Introduction
With the upcoming 2024 United States presidential election
approaching, analysts are consistently searching for metrics to predict
the outcomes accurately and early. While individual voter motivations
are varied and nuanced, a review of the common economic measures in
relation to county election results of the past can potentially provide
insight into the trends of the future. In order to review these
potential trends, the following data was utilized for analysis:
While these datasets include a litany of information, the areas of
focus in this exploratory data analysis are the impacts of county level
unemployment rate for the current election year, county level poverty
rate for the year prior to the current election year, higher education
rate for the four years prior to the current election year. To note,
years prior to the current election year are utilized due to data
availability and the impact of previous year’s socioeconomic conditions
on the current voter’s opinions. The focus of this exploratory data
analysis centers around analyzing potential correlations and predictive
values as related to the 2020 presidential election only.
Relevant Note
All data preparation code is copied in the appendix as well as
included in line with the report, visualization code is only included in
line with the report. To view any of the code in line with each location
it is used in the report, select the Show
buttons on the
right hand side of the page.
Data Preparation
Prior to any data visualization and analysis, all datasets were
loaded into RStudio (v2024.09.0 Build 375) to prepare unique relaional
datasets. A unique identifier of FIPS Code
was utilized
across all four (4) datasets, as well as to link the relevant geoJSON
data for county mapping.
Create Relational
Datasets
Presidential
Election Data (2020 or most recent year available)
The raw presidential election data was obtained from from the
publicly available
MIT
Election Lab Data Set: County Presidential Election Returns
2000-2020.
Election data was read into RStudio as election_raw
and
cleaned utilizing the following steps to create the relational dataset
election
:
- Data was grouped by the county
FIPS code
- Data was sorted by descending
Year
- Data was filtered by political
Party
for only
Democrat
and Republican
as the analysis
focuses on the potential impacts on county presidential election
winners. No other parties have ever won the presidency and thus were
omitted.
- To note: blank values were not omitted
- Unnecessary variables were removed
- Data was filtered for
2020
or the
most recent year with available data
if 2020 was not
available
A searchable preview of the relational dataset election
is available in the data table below.
##read in the election data as election_raw
election_raw <- read.csv('https://raw.githubusercontent.com/nlepera/sta551/refs/heads/main/HW01/data/countypresidential_election_2000-2020.csv')
##clean the election data
election <- election_raw %>%
group_by(county_fips) %>% ##group by county FIPS code
arrange (desc(year)) %>% ##sort by descending year
filter (party == "DEMOCRAT" | party == "REPUBLICAN") %>% ##filter for only dem & rep
subset(, -c(state_po, office, version, mode)) %>% ##remove unnecessary columns
slice (1:2) %>% ##pull top 2 values for each group (county_fips sorted by desc year) pulling both dem & rep for each county at max year available
arrange (desc(candidatevotes)) %>% ##re filter to sort by group, with highest candidate votes on top
slice (1) %>% ##only keep value for highest candidate votes (winner) per county
rename (FIPS = county_fips) ## set ID name for outer join
DT::datatable(election)
Unemployment Data
(2020 or most recent year available)
The raw unemployment data was obtained from from the publicly
available
USDA
Economic Research Service County-level Dataset: Unemployment.
Unemployment data was read into RStudio as unemploy_raw
and cleaned utilizing the following steps to create the relational
dataset unemploy
:
- Data was filtered for text containing the string
Unemployment
in the Attribute
variable data
values to remove other unnecessary data types.
- In order to extract the year from the
Attribute
values,
a new column was created by extracting the last four (4) characters of
the Attribute
values.
- Data was grouped by the county
FIPS code
- Data was sorted by descending
Year
- Data was filtered for
2020
or the
most recent year with available data
if 2020 was not
available
- Unnecessary variables were removed
A searchable preview of the relational dataset unemploy
is available in the data table below.
## read in the unemployment data as unemploy_raw
unemploy_raw <- read.csv('https://raw.githubusercontent.com/nlepera/sta551/refs/heads/main/HW01/data/Unemployment.csv')
## clean the unemployment data
unemploy <- unemploy_raw %>%
filter (grepl('Unemployment', Attribute)) %>% #use dplyr package to use filter(grepl()) to filter for string of text to select only the unemployment rate values
mutate (year = str_sub(Attribute, -4)) %>% ##create a new column using mutate and stringr to create a new column from the last 4 values of the attribute column, to extract the year (str_sub -> stringr_subset)
group_by (FIPS_Code) %>% ##group by FIPS code before sorting to get max year
arrange (desc(year)) %>% ## sort descending year to put max available at the top
slice(1) %>% ##slice top value to keep only max year for each FIPS code
subset (, c(FIPS_Code, Value)) %>% ##remove unnecessary columns
rename ("Unemployment_Rate (%)" = Value, FIPS = FIPS_Code) ##rename column to reflect unemployment rate & set ID name for outer join
DT::datatable(unemploy)
Poverty Data
(2019)
The raw poverty data was obtained from from the publicly available
USDA
Economic Research Service County-level Dataset: Poverty.
Poverty data was read into RStudio as poverty_raw
and
cleaned utilizing the following steps to create the relational dataset
poverty
:
- Data was filtered for text containing the string
PCTPOVALL_2019
in the Attribute
variable data
values to remove other unnecessary data types.
- Unnecessary variables were removed
A searchable preview of the relational dataset unemploy
is available in the data table below.
## read in the poverty data as poverty_raw
poverty_raw <- read.csv('https://raw.githubusercontent.com/nlepera/sta551/refs/heads/main/HW01/data/PovertyEstimates.csv')
##clean the poverty data
poverty <- poverty_raw %>%
filter (Attribute == "PCTPOVALL_2019") %>% ##Filter for 2019 poverty values
subset (, c(FIPStxt, Value)) %>% ##remove unneccessary columns
rename ("Poverty_Rate (%)" = Value, FIPS = FIPStxt) ##rename Value column to Poverty_Rate (%) and set ID name for outer join
DT::datatable(poverty)
Education Data
(2015 - 2019)
The raw education data was obtained from from the publicly available
USDA
Economic Research Service County-level Dataset: Education.
Unemployment data was read into RStudio as edu_raw
and
cleaned utilizing the following steps to create the relational dataset
edu
:
- Unnecessary variables were removed
- Columns were renamed to truncated values for ease of use:
No_HS
= # of persons in the county with less than a
high school diploma
HS
= # of persons in the county with a high school
diploma only
AS_SomeCol
= # of persons in the county with either
some college credit or an Associate’s Degree
BS_More
= # of persons in the county with a Bachelor’s
Degree or higher
- Data cleaned to remove commas from numbers and convert from
character to numeric values
A searchable preview of the relational dataset unemploy
is available in the data table below.
## read in the unemployment data as edu_raw
edu_raw <- read.csv('https://nlepera.github.io/sta551/HW01/data/Education.csv', stringsAsFactors = FALSE)
#clean education data
edu <- edu_raw %>%
subset (, c(FIPS.Code, Less.than.a.high.school.diploma..2015.19, High.school.diploma.only..2015.19, Some.college.or.associate.s.degree..2015.19, Bachelor.s.degree.or.higher..2015.19)) %>% ##remove irrelevant columns
rename ( "No_HS" = Less.than.a.high.school.diploma..2015.19, "HS" = High.school.diploma.only..2015.19, "AS_SomeCol" = Some.college.or.associate.s.degree..2015.19, "BS_More" = Bachelor.s.degree.or.higher..2015.19, FIPS = FIPS.Code) ##rename for ease and set ID name for outer join
edu$No_HS = gsub(',', '', edu$No_HS) ##remove commas from number with commas saved as charachters
edu$HS = gsub(',', '', edu$HS)
edu$AS_SomeCol = gsub(',', '', edu$AS_SomeCol)
edu$BS_More = gsub(',', '', edu$BS_More)
edu$No_HS = as.numeric(edu$No_HS) ##transform to numeric to aggregate
edu$HS = as.numeric(edu$HS)
edu$AS_SomeCol = as.numeric(edu$AS_SomeCol)
edu$BS_More = as.numeric(edu$BS_More)
DT::datatable(edu)
Merge Relational
Datasets & Aggregate data
Merge the
relational datasets using county FIPS codes
Once all four (4) relational datasets (edu
,
election
, poverty
, and unemploy
)
were created, a new dataset named all.data
was created by
completing multiple full join functions. All datasets were merged using
the county FIPS
code as the unique identifier conserved
across all datasets.
##merge election data & education data as election.education
election.education <- full_join (
x = election,
y = edu,
by = "FIPS",
keep = FALSE
)
##merge election.education & poverty data as election.education.poverty
election.education.poverty <- full_join(
x = election.education,
y = poverty,
by = "FIPS",
keep = FALSE
)
##merge election.education.poverty & unemployment data as all.data
all.data <- full_join (
x = election.education.poverty,
y = unemploy,
by = "FIPS",
keep = FALSE
)
Aggregate the
Education Data into % Higher Ed
As the educational data provided for each county consisted of the
total number of persons in each county that received each of the four
tiers of education, the data was aggregated to allow for cleaner
analysis and comparison. In order to aggregate the educational data, the
four education variables (No_HS
, HS
,
AS_SomeCol
, & BS_More
) were aggregated to
create a new variable Higher_Ed_Percent
to measure the
percentage of the population surveyed that completed either some college
credit, an Associate’s Degree, a Bachelor’s Degree, or additional
graduate level degrees.
This higher education metric was created as a measure of the average
socioeconomic status of the counties being analyzed.
all.data <- all.data %>%
filter(FIPS != 0) %>% ##filter out values with no associated county or state name
filter(FIPS != 1000) %>%
mutate (Higher_Ed_Percent = (((`AS_SomeCol` + `BS_More`)/(`No_HS`+ `HS` + `AS_SomeCol` + `BS_More`))*100)) ##% of pop with higher ed.
Visualizing and
Analyzing the Data
Mapping the full
data
For an initial visualization of the data as a whole, the
all.data
dataset was mapped by county utilizing an
interactive leaflet map. Due to the size of the dataset and number of
counties, color specific data is not visible until the map is zoomed in
to the appropriate county level. Until zoomed in the color scale (green
to red) represents the number of counties nested in that group until the
map is zoomed in further. Once fully zoomed in the color of the
unnumbered circles (red and blue) represent the winning party
(Republican and Democrat respectively) in each county for the 2020
presidential election.
county_data_raw <- sf::read_sf("https://raw.githubusercontent.com/plotly/datasets/master/geojson-counties-fips.json") ##pull in map of FIPS codes
FIPSconvert_raw <- sf::read_sf("https://nlepera.github.io/sta551/HW01/data/fips2geocode.csv") ##pull in key of FIPS codes to lat/long
county_data <- county_data_raw %>% #clean county data to list FIPS as numeric & match name to key for join
mutate (id = as.numeric(as.character(id))) %>%
rename (FIPS = id)
FIPSconvert <- FIPSconvert_raw %>%
mutate (fips = as.numeric(as.character(fips)), lon = as.numeric(as.character(lon)), lat = as.numeric(as.character(lat))) %>%
rename (FIPS = fips, Longitude = lon, Latitude = lat)
all.data.join <- full_join(
x = all.data,
y = FIPSconvert,
by = "FIPS",
keep = FALSE
) %>%
ungroup()
Interactive Map of County Data
pal <- colorFactor(c("blue", "red"), domain = c("REPUBLICAN", "DEMOCRAT"))
title <- "
<style>
.custom-title {
color: white;
padding: 0px;
border-radius: 0px;
text-align: right;
}
</style>
Election Results, Education Rates, Unemployment Rates & Poverty Rates
<br>Zoom in to view each county individually
<br>Select a county's circle to view full data"
leaflet() %>%
setView(lng=-98.5795, lat=39.8283, zoom = 4) %>% ##set view to mid US
addProviderTiles(providers$CartoDB.DarkMatter) %>% ##set map to dark mode
addControl(html = title,
position = "topright",
className = "custom-title") %>%
addPolygons(data = county_data, ##add FIPS polygons
color = "yellow",
fill = FALSE,
weight = 0.25) %>%
addCircleMarkers(data = all.data.join,
color = ~pal(party),
radius = 20,
fillOpacity = 0.5,
popup = ~popupTable(all.data),
clusterOptions = markerClusterOptions(maxClusterRadius = 50))
Plot variable
distribution
Before completing any data analysis the distribution of the three
numeric variables of interest was reviewed, controlling for the the
winning party (Republican or Democrat) in each county for the 2020
presidential election.
Both unemployment and higher education rates appear to have normal
distributions while poverty rates appear to have closer to a gamma
distribution. A greater frequency of counties with democratic candidate
winners was seen for all three (3) variables in question.
ggplot (all.data, aes(x = `Unemployment_Rate (%)`, fill = `party`)) +
geom_histogram(inherit.aes = TRUE, color = "black") +
ggtitle ("Distribution of Unemployment Rates by County Election Winner") +
xlab ("County Unemployment Rate (x)
[% of County Pop.]") +
ylab ("Counties W/ Unemployment Rate = x") +
scale_fill_manual(values = c("blue", "red")) +
theme(legend.position = c(0.8, 0.8))

ggplot (all.data, aes(x = `Poverty_Rate (%)`, fill = `party`)) +
geom_histogram(inherit.aes = TRUE, color = "black") +
ggtitle ("Distribution of Poverty Rates by County Election Winner") +
xlab ("County Poverty Rate (x)
[% of County Pop.]") +
ylab ("Counties W/ Poverty Rate = x") +
scale_fill_manual(values = c("blue", "red")) +
theme(legend.position = c(0.8, 0.8), height = "200px")

ggplot (all.data, aes(x = `Higher_Ed_Percent`, fill = `party`)) +
geom_histogram(inherit.aes = TRUE, color = "black") +
ggtitle ("Distribution of Higher Education Rates by County Election Winner") +
xlab ("County Higher Ed. Rate (x)
[% of County Pop.] ") +
ylab ("Counties W/ Higher Ed. Rate = x") +
scale_fill_manual(values = c("blue", "red")) +
theme(legend.position = c(0.8, 0.8))

Plot Relationship
Between Numeric Variables
To determine the potential relationships between the three numeric
variables of interest (Unemployment Rate
,
Poverty Rate
, and Higher Education Rate
) were
plotted against each other and reviewed utilizing a basic linear
regression model for the normally distributed data and a GLM gamma
regresion model for the gamma distributed data.
ggplot(data = all.data, aes(x =all.data$`Unemployment_Rate (%)`, y=all.data$`Poverty_Rate (%)`, color=`party`)) +
geom_point(alpha = 0.25) +
ggtitle ("Unemployment Rates vs. Poverty Rates by Election Winning Party") +
xlab ("County Unemployment Rate [% of County Pop.] (x)") +
ylab ("County Poverty Rate [% of County Pop.] (y)") +
scale_color_manual(values = c("blue", "red")) +
stat_smooth(method = lm, se=FALSE, size = 0.1)

pov_unem <- lm(`Poverty_Rate (%)`~`Unemployment_Rate (%)` , data = all.data)
summary(pov_unem)
Call:
lm(formula = `Poverty_Rate (%)` ~ `Unemployment_Rate (%)`, data = all.data)
Residuals:
Min 1Q Median 3Q Max
-21.355 -3.713 -0.826 2.871 34.731
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 9.40945 0.30570 30.78 <2e-16 ***
`Unemployment_Rate (%)` 0.74165 0.04289 17.29 <2e-16 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 5.519 on 3189 degrees of freedom
(128 observations deleted due to missingness)
Multiple R-squared: 0.08572, Adjusted R-squared: 0.08544
F-statistic: 299 on 1 and 3189 DF, p-value: < 2.2e-16
ggplot(data = all.data, aes(x =all.data$`Higher_Ed_Percent`, y=all.data$`Poverty_Rate (%)`, color=`party`)) +
geom_point(alpha = 0.25) +
ggtitle ("Percent of Population w/ Higher Education vs.
Poverty Rates by Election Winning Party") +
xlab ("County Higher Ed. Rate [% of County Pop.] (x)") +
ylab ("County Poverty Rate [% of County Pop.] (y)") +
scale_color_manual(values = c("blue", "red")) +
stat_smooth(method = glm, se=FALSE, size = 0.1)

highed_pov <- glm(`Higher_Ed_Percent`~`Poverty_Rate (%)`, data = all.data)
summary(highed_pov)
Call:
glm(formula = Higher_Ed_Percent ~ `Poverty_Rate (%)`, data = all.data)
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 68.37787 0.41629 164.26 <2e-16 ***
`Poverty_Rate (%)` -1.07151 0.02681 -39.97 <2e-16 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
(Dispersion parameter for gaussian family taken to be 76.33665)
Null deviance: 365417 on 3190 degrees of freedom
Residual deviance: 243438 on 3189 degrees of freedom
(128 observations deleted due to missingness)
AIC: 22893
Number of Fisher Scoring iterations: 2
ggplot(data = all.data, aes(x =all.data$`Higher_Ed_Percent`, y=all.data$`Unemployment_Rate (%)`, color=`party`)) +
geom_point(alpha = 0.25) +
ggtitle ("Percent of Population w/ Higher Education vs.
Unemployment Rates by Election Winning Party") +
xlab ("County Higher Ed. Rate [% of County Pop.] (x)") +
ylab ("County Unemployment Rate [% of County Pop.] (y)") +
scale_color_manual(values = c("blue", "red")) +
stat_smooth(method = lm, se=FALSE, size = 0.1)

highed_unem <- lm(`Higher_Ed_Percent`~`Unemployment_Rate (%)`, data = all.data)
summary(highed_unem)
Call:
lm(formula = Higher_Ed_Percent ~ `Unemployment_Rate (%)`, data = all.data)
Residuals:
Min 1Q Median 3Q Max
-47.747 -7.579 -0.476 6.880 36.109
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 59.02069 0.56472 104.51 <2e-16 ***
`Unemployment_Rate (%)` -0.92418 0.07816 -11.82 <2e-16 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 10.51 on 3268 degrees of freedom
(49 observations deleted due to missingness)
Multiple R-squared: 0.04102, Adjusted R-squared: 0.04073
F-statistic: 139.8 on 1 and 3268 DF, p-value: < 2.2e-16
Conclusions
While all three investigated potential correlations indicated a high
level of statistic significance with p values well below 0.05, both the
Unemployment Rates vs. Poverty Rates by Election Winning Party
and
Percent of Population w/ Higher Education vs. Unemployment Rates by Election Winning Party
models illustrated a poor fit with very low R squared values. The
Percent of Population w/ Higher Education vs. Poverty Rates by Election Winning Party
also illustrated a poor fit but had the highest r squared value
indicating reduced variance in this model. No clustering was noted along
the party variables.
Overall a correlation between unemployment rates, poverty rates,
higher education rates, and county winning party was not
illustrated.
Code
##read in the election data as election_raw
election_raw <- read.csv('https://raw.githubusercontent.com/nlepera/sta551/refs/heads/main/HW01/data/countypresidential_election_2000-2020.csv')
##clean the election data
election <- election_raw %>%
group_by(county_fips) %>% ##group by county FIPS code
arrange (desc(year)) %>% ##sort by descending year
filter (party == "DEMOCRAT" | party == "REPUBLICAN") %>% ##filter for only dem & rep
subset(, -c(state_po, office, version, mode)) %>% ##remove unnecessary columns
slice (1:2) %>% ##pull top 2 values for each group (county_fips sorted by desc year) pulling both dem & rep for each county at max year available
arrange (desc(candidatevotes)) %>% ##re filter to sort by group, with highest candidate votes on top
slice (1) %>% ##only keep value for highest candidate votes (winner) per county
rename (FIPS = county_fips) ## set ID name for outer join
DT::datatable(election)
## read in the unemployment data as unemploy_raw
unemploy_raw <- read.csv('https://raw.githubusercontent.com/nlepera/sta551/refs/heads/main/HW01/data/Unemployment.csv')
## clean the unemployment data
unemploy <- unemploy_raw %>%
filter (grepl('Unemployment', Attribute)) %>% #use dplyr package to use filter(grepl()) to filter for string of text to select only the unemployment rate values
mutate (year = str_sub(Attribute, -4)) %>% ##create a new column using mutate and stringr to create a new column from the last 4 values of the attribute column, to extract the year (str_sub -> stringr_subset)
group_by (FIPS_Code) %>% ##group by FIPS code before sorting to get max year
arrange (desc(year)) %>% ## sort descending year to put max available at the top
slice(1) %>% ##slice top value to keep only max year for each FIPS code
subset (, c(FIPS_Code, Value)) %>% ##remove unnecessary columns
rename ("Unemployment_Rate (%)" = Value, FIPS = FIPS_Code) ##rename column to reflect unemployment rate & set ID name for outer join
DT::datatable(unemploy)
## read in the poverty data as poverty_raw
poverty_raw <- read.csv('https://raw.githubusercontent.com/nlepera/sta551/refs/heads/main/HW01/data/PovertyEstimates.csv')
##clean the poverty data
poverty <- poverty_raw %>%
filter (Attribute == "PCTPOVALL_2019") %>% ##Filter for 2019 poverty values
subset (, c(FIPStxt, Value)) %>% ##remove unneccessary columns
rename ("Poverty_Rate (%)" = Value, FIPS = FIPStxt) ##rename Value column to Poverty_Rate (%) and set ID name for outer join
DT::datatable(poverty)
## read in the unemployment data as edu_raw
edu_raw <- read.csv('https://nlepera.github.io/sta551/HW01/data/Education.csv', stringsAsFactors = FALSE)
#clean education data
edu <- edu_raw %>%
subset (, c(FIPS.Code, Less.than.a.high.school.diploma..2015.19, High.school.diploma.only..2015.19, Some.college.or.associate.s.degree..2015.19, Bachelor.s.degree.or.higher..2015.19)) %>% ##remove irrelevant columns
rename ( "No_HS" = Less.than.a.high.school.diploma..2015.19, "HS" = High.school.diploma.only..2015.19, "AS_SomeCol" = Some.college.or.associate.s.degree..2015.19, "BS_More" = Bachelor.s.degree.or.higher..2015.19, FIPS = FIPS.Code) ##rename for ease and set ID name for outer join
edu$No_HS = gsub(',', '', edu$No_HS) ##remove commas from number with commas saved as charachters
edu$HS = gsub(',', '', edu$HS)
edu$AS_SomeCol = gsub(',', '', edu$AS_SomeCol)
edu$BS_More = gsub(',', '', edu$BS_More)
edu$No_HS = as.numeric(edu$No_HS) ##transform to numeric to aggregate
edu$HS = as.numeric(edu$HS)
edu$AS_SomeCol = as.numeric(edu$AS_SomeCol)
edu$BS_More = as.numeric(edu$BS_More)
DT::datatable(edu)
##merge election data & education data as election.education
election.education <- full_join (
x = election,
y = edu,
by = "FIPS",
keep = FALSE
)
##merge election.education & poverty data as election.education.poverty
election.education.poverty <- full_join(
x = election.education,
y = poverty,
by = "FIPS",
keep = FALSE
)
##merge election.education.poverty & unemployment data as all.data
all.data <- full_join (
x = election.education.poverty,
y = unemploy,
by = "FIPS",
keep = FALSE
)
all.data <- all.data %>%
filter(FIPS != 0) %>% ##filter out values with no associated county or state name
filter(FIPS != 1000) %>%
mutate (Higher_Ed_Percent = (((`AS_SomeCol` + `BS_More`)/(`No_HS`+ `HS` + `AS_SomeCol` + `BS_More`))*100)) ##% of pop with higher ed.
county_data_raw <- sf::read_sf("https://raw.githubusercontent.com/plotly/datasets/master/geojson-counties-fips.json") ##pull in map of FIPS codes
FIPSconvert_raw <- sf::read_sf("https://nlepera.github.io/sta551/HW01/data/fips2geocode.csv") ##pull in key of FIPS codes to lat/long
county_data <- county_data_raw %>% #clean county data to list FIPS as numeric & match name to key for join
mutate (id = as.numeric(as.character(id))) %>%
rename (FIPS = id)
FIPSconvert <- FIPSconvert_raw %>%
mutate (fips = as.numeric(as.character(fips)), lon = as.numeric(as.character(lon)), lat = as.numeric(as.character(lat))) %>%
rename (FIPS = fips, Longitude = lon, Latitude = lat)
all.data.join <- full_join(
x = all.data,
y = FIPSconvert,
by = "FIPS",
keep = FALSE
) %>%
ungroup()
LS0tDQp0aXRsZTogIlByZXNpZGVudGlhbCBGaXRuZXNzIFRlc3Q6PGltZyBzcmM9XCJodHRwczovL25sZXBlcmEuZ2l0aHViLmlvL3N0YTU1MS9IVzAxL2ltZy9wZW5ndWluX2N1dGUucG5nXCIgc3R5bGU9XCJmbG9hdDogcmlnaHQ7IHdpZHRoOiAxMiVcIi8+Ig0Kc3VidGl0bGU6ICJUaGUgSW1wYWN0IG9mIExvY2FsIEVkdWNhdGlvbiwgUG92ZXJ0eSwgYW5kIFVuZW1wbG95bWVudCBSYXRlcyBvbiBDb3VudHkgUHJlc2lkZW50YWwgRWxlY3Rpb24gUmVzdWx0cyINCmF1dGhvcjogDQotIG5hbWU6IE5hdGFsaWUgTGVQZXJhDQogIGFmZmlsaWF0aW9uOiBXZXN0IENoZXN0ZXIgVW5pdmVyc2l0eSB8IFNUQTUxMSAtIEhXIDAxDQpkYXRlOiAiMjUgU2VwIDIwMjQiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6IA0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiAyDQogICAgdG9jX2Zsb2F0OiB5ZXMNCiAgICB0b2NfY29sbGFwc2U6IHllcw0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgc21vb3RoX3Njcm9sbDogdHJ1ZQ0KICAgIHRoZW1lOiByZWFkYWJsZQ0KLS0tDQoNCmBgYHtjc3MgZWNobyA9IEZBTFNFfQ0KaDEudGl0bGUgeyAgLyogVGl0bGUgLSBmb250IHNwZWNpZmljYXRpb25zIG9mIHRoZSByZXBvcnQgdGl0bGUgKi8NCiAgZm9udC13ZWlnaHQ6Ym9sZDsNCiAgY29sb3I6IGRhcmttYWdlbnRhIDsNCn0NCmgxLnN1YnRpdGxlIHsgIC8qIFRpdGxlIC0gZm9udCBzcGVjaWZpY2F0aW9ucyBvZiB0aGUgcmVwb3J0IHRpdGxlICovDQogIGZvbnQtd2VpZ2h0OmJvbGQ7DQogIGNvbG9yOiBkYXJrbWFnZW50YSA7DQp9DQpoNC5hdXRob3IgeyAvKiBIZWFkZXIgNCAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgZm9yIGF1dGhvcnMgICovDQogIGZvbnQtZmFtaWx5OiBzeXN0ZW0tdWk7DQogIGNvbG9yOiBuYXZ5Ow0KfQ0KaDQuZGF0ZSB7IC8qIEhlYWRlciA0IC0gZm9udCBzcGVjaWZpY2F0aW9ucyBmb3IgdGhlIGRhdGUgICovDQogIGZvbnQtZmFtaWx5OiBzeXN0ZW0tdWk7DQogIGNvbG9yOiBuYXZ5Ow0KfQ0KaDEgeyAvKiBIZWFkZXIgMSAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgZm9yIGxldmVsIDEgc2VjdGlvbiB0aXRsZSAgKi8NCiAgICBmb250LXdlaWdodDpib2xkOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQpoMiB7IC8qIEhlYWRlciAyIC0gZm9udCBzcGVjaWZpY2F0aW9ucyBmb3IgbGV2ZWwgMiBzZWN0aW9uIHRpdGxlICovDQogICAgZm9udC13ZWlnaHQ6Ym9sZDsNCiAgICBjb2xvcjogbmF2eTsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQpoMyB7IC8qIEhlYWRlciAzIC0gZm9udCBzcGVjaWZpY2F0aW9ucyBvZiBsZXZlbCAzIHNlY3Rpb24gdGl0bGUgICovDQogICAgZm9udC13ZWlnaHQ6Ym9sZDsNCiAgICBjb2xvcjogbmF2eTsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQpoNCB7IC8qIEhlYWRlciA0IC0gZm9udCBzcGVjaWZpY2F0aW9ucyBvZiBsZXZlbCA0IHNlY3Rpb24gdGl0bGUgICovDQogICAgY29sb3I6IGRhcmtyZWQ7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KYm9keSB7IGJhY2tncm91bmQtY29sb3I6d2hpdGU7IH0NCg0KLmhpZ2hsaWdodG1lIHsgYmFja2dyb3VuZC1jb2xvcjp5ZWxsb3c7IH0NCg0KcCB7IGJhY2tncm91bmQtY29sb3I6d2hpdGU7IH0NCmg1IHsNCiAgY29sb3I6IHdoaXRlOw0KfQ0KDQpgYGANCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQppZiAoIXJlcXVpcmUoImRwbHlyIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJkcGx5ciIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJkcGx5ciIpDQp9DQoNCmlmICghcmVxdWlyZSgic3RyaW5nciIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygic3RyaW5nciIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJzdHJpbmdyIikNCn0NCg0KaWYgKCFyZXF1aXJlKCJwbG90bHkiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoInBsb3RseSIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJwbG90bHkiKQ0KfQ0KDQppZiAoIXJlcXVpcmUoImxlYWZsZXQiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImxlYWZsZXQiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgibGVhZmxldCIpDQp9DQoNCmlmICghcmVxdWlyZSgiY3Jvc3N0YWxrIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJjcm9zc3RhbGsiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgiY3Jvc3N0YWxrIikNCn0NCg0KDQppZiAoIXJlcXVpcmUoInJqc29uIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJyanNvbiIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJyanNvbiIpDQp9DQppZiAoIXJlcXVpcmUoInRpZ3JpcyIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygidGlncmlzIikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoInRpZ3JpcyIpDQp9DQppZiAoIXJlcXVpcmUoInJhc3RlciIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygicmFzdGVyIikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoInJhc3RlciIpDQp9DQppZiAoIXJlcXVpcmUoImxlYWZwb3AiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImxlYWZwb3AiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgibGVhZnBvcCIpDQp9DQppZiAoIXJlcXVpcmUoImdncmlkZ2VzIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJnZ3JpZGdlcyIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJnZ3JpZGdlcyIpDQp9DQppZiAoIXJlcXVpcmUoImNvd3Bsb3QiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImNvd3Bsb3QiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgiY293cGxvdCIpDQp9DQoNCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgd2FybmluZyA9IEZBTFNFLCAgIA0KICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdCA9IFRSVUUsICAgDQogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFLA0KICAgICAgICAgICAgICAgICAgICAgIGNvbW1lbnQgPSBOQSkNCg0Kb3B0aW9ucyhEVC5vcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gNSwgc2Nyb2xsWCA9IFRSVUUpKQ0KYGBgDQo8YnI+DQoNCiMgSW50cm9kdWN0aW9uDQoNCldpdGggdGhlIHVwY29taW5nIDIwMjQgVW5pdGVkIFN0YXRlcyBwcmVzaWRlbnRpYWwgZWxlY3Rpb24gYXBwcm9hY2hpbmcsIGFuYWx5c3RzIGFyZSBjb25zaXN0ZW50bHkgc2VhcmNoaW5nIGZvciBtZXRyaWNzIHRvIHByZWRpY3QgdGhlIG91dGNvbWVzIGFjY3VyYXRlbHkgYW5kIGVhcmx5LiAgV2hpbGUgaW5kaXZpZHVhbCB2b3RlciBtb3RpdmF0aW9ucyBhcmUgdmFyaWVkIGFuZCBudWFuY2VkLCBhIHJldmlldyBvZiB0aGUgY29tbW9uIGVjb25vbWljIG1lYXN1cmVzIGluIHJlbGF0aW9uIHRvIGNvdW50eSBlbGVjdGlvbiByZXN1bHRzIG9mIHRoZSBwYXN0IGNhbiBwb3RlbnRpYWxseSBwcm92aWRlIGluc2lnaHQgaW50byB0aGUgdHJlbmRzIG9mIHRoZSBmdXR1cmUuICAgSW4gb3JkZXIgdG8gcmV2aWV3IHRoZXNlIHBvdGVudGlhbCB0cmVuZHMsIHRoZSBmb2xsb3dpbmcgZGF0YSB3YXMgdXRpbGl6ZWQgZm9yIGFuYWx5c2lzOg0KDQotIFByZXNpZGVudGlhbCBFbGVjdGlvbiBEYXRhLCBvYnRhaW5lZCBmcm9tIHRoZSBwdWJsaWNseSBhdmFpbGFibGUgPGEgaHJlZj0iaHR0cHM6Ly9lbGVjdGlvbmxhYi5taXQuZWR1L2RhdGEiPk1JVCBFbGVjdGlvbiBMYWIgRGF0YSBTZXRzPC9hPg0KLSBQZXIgQ291bnR5IFVuZW1wbG95bWVudCBEYXRhLCBvYnRhaW5lZCBmcm9tIHRoZSBwdWJsaWNseSBhdmFpbGFibGUgPGEgaHJlZj0iaHR0cHM6Ly93d3cuZXJzLnVzZGEuZ292L2RhdGEtcHJvZHVjdHMvY291bnR5LWxldmVsLWRhdGEtc2V0cy8iPlVTREEgRWNvbm9taWMgUmVzZWFyY2ggU2VydmljZSBDb3VudHktbGV2ZWwgZGF0YXNldHM8L2E+DQotIFBlciBDb3VudHkgUG92ZXJ0eSBEYXRhLCBvYnRhaW5lZCBmcm9tIHRoZSBwdWJsaWNseSBhdmFpbGFibGUgPGEgaHJlZj0iaHR0cHM6Ly93d3cuZXJzLnVzZGEuZ292L2RhdGEtcHJvZHVjdHMvY291bnR5LWxldmVsLWRhdGEtc2V0cy8iPlVTREEgRWNvbm9taWMgUmVzZWFyY2ggU2VydmljZSBDb3VudHktbGV2ZWwgZGF0YXNldHM8L2E+DQotIFBlciBDb3VudHkgRWR1Y2F0aW9uIERhdGEsIG9idGFpbmVkIGZyb20gdGhlIHB1YmxpY2x5IGF2YWlsYWJsZSA8YSBocmVmPSJodHRwczovL3d3dy5lcnMudXNkYS5nb3YvZGF0YS1wcm9kdWN0cy9jb3VudHktbGV2ZWwtZGF0YS1zZXRzLyI+VVNEQSBFY29ub21pYyBSZXNlYXJjaCBTZXJ2aWNlIENvdW50eS1sZXZlbCBkYXRhc2V0czwvYT4NCg0KDQpXaGlsZSB0aGVzZSBkYXRhc2V0cyBpbmNsdWRlIGEgbGl0YW55IG9mIGluZm9ybWF0aW9uLCB0aGUgYXJlYXMgb2YgZm9jdXMgaW4gdGhpcyBleHBsb3JhdG9yeSBkYXRhIGFuYWx5c2lzIGFyZSB0aGUgaW1wYWN0cyBvZiBjb3VudHkgbGV2ZWwgdW5lbXBsb3ltZW50IHJhdGUgZm9yIHRoZSBjdXJyZW50IGVsZWN0aW9uIHllYXIsIGNvdW50eSBsZXZlbCBwb3ZlcnR5IHJhdGUgZm9yIHRoZSB5ZWFyIHByaW9yIHRvIHRoZSBjdXJyZW50IGVsZWN0aW9uIHllYXIsIGhpZ2hlciBlZHVjYXRpb24gcmF0ZSBmb3IgdGhlIGZvdXIgeWVhcnMgcHJpb3IgdG8gdGhlIGN1cnJlbnQgZWxlY3Rpb24geWVhci4gIFRvIG5vdGUsIHllYXJzIHByaW9yIHRvIHRoZSBjdXJyZW50IGVsZWN0aW9uIHllYXIgYXJlIHV0aWxpemVkIGR1ZSB0byBkYXRhIGF2YWlsYWJpbGl0eSBhbmQgdGhlIGltcGFjdCBvZiBwcmV2aW91cyB5ZWFyJ3Mgc29jaW9lY29ub21pYyBjb25kaXRpb25zIG9uIHRoZSBjdXJyZW50IHZvdGVyJ3Mgb3BpbmlvbnMuICBUaGUgZm9jdXMgb2YgdGhpcyBleHBsb3JhdG9yeSBkYXRhIGFuYWx5c2lzIGNlbnRlcnMgYXJvdW5kIGFuYWx5emluZyBwb3RlbnRpYWwgY29ycmVsYXRpb25zIGFuZCBwcmVkaWN0aXZlIHZhbHVlcyBhcyByZWxhdGVkIHRvIHRoZSAyMDIwIHByZXNpZGVudGlhbCBlbGVjdGlvbiBvbmx5LiANCg0KPGg0PlJlbGV2YW50IE5vdGU8L2g0Pg0KQWxsIGRhdGEgcHJlcGFyYXRpb24gY29kZSBpcyBjb3BpZWQgaW4gdGhlIGFwcGVuZGl4IGFzIHdlbGwgYXMgaW5jbHVkZWQgaW4gbGluZSB3aXRoIHRoZSByZXBvcnQsIHZpc3VhbGl6YXRpb24gY29kZSBpcyBvbmx5IGluY2x1ZGVkIGluIGxpbmUgd2l0aCB0aGUgcmVwb3J0LiBUbyB2aWV3IGFueSBvZiB0aGUgY29kZSBpbiBsaW5lIHdpdGggZWFjaCBsb2NhdGlvbiBpdCBpcyB1c2VkIGluIHRoZSByZXBvcnQsIHNlbGVjdCB0aGUgYFNob3dgIGJ1dHRvbnMgb24gdGhlIHJpZ2h0IGhhbmQgc2lkZSBvZiB0aGUgcGFnZS4NCg0KIyBEYXRhIFByZXBhcmF0aW9uDQoNClByaW9yIHRvIGFueSBkYXRhIHZpc3VhbGl6YXRpb24gYW5kIGFuYWx5c2lzLCBhbGwgZGF0YXNldHMgd2VyZSBsb2FkZWQgaW50byBSU3R1ZGlvICh2MjAyNC4wOS4wIEJ1aWxkIDM3NSkgdG8gcHJlcGFyZSB1bmlxdWUgcmVsYWlvbmFsIGRhdGFzZXRzLiAgQSB1bmlxdWUgaWRlbnRpZmllciBvZiBgRklQUyBDb2RlYCB3YXMgdXRpbGl6ZWQgYWNyb3NzIGFsbCBmb3VyICg0KSBkYXRhc2V0cywgYXMgd2VsbCBhcyB0byBsaW5rIHRoZSByZWxldmFudCBnZW9KU09OIGRhdGEgZm9yIGNvdW50eSBtYXBwaW5nLiANCg0KIyMgQ3JlYXRlIFJlbGF0aW9uYWwgRGF0YXNldHMNCg0KIyMjIFByZXNpZGVudGlhbCBFbGVjdGlvbiBEYXRhICgyMDIwIG9yIG1vc3QgcmVjZW50IHllYXIgYXZhaWxhYmxlKQ0KDQpUaGUgcmF3IHByZXNpZGVudGlhbCBlbGVjdGlvbiBkYXRhIHdhcyBvYnRhaW5lZCBmcm9tIGZyb20gdGhlIHB1YmxpY2x5IGF2YWlsYWJsZSA8YSBocmVmPSJodHRwczovL2RhdGF2ZXJzZS5oYXJ2YXJkLmVkdS9kYXRhc2V0LnhodG1sP3BlcnNpc3RlbnRJZD1kb2k6MTAuNzkxMC9EVk4vVk9RQ0hRIj5NSVQgRWxlY3Rpb24gTGFiIERhdGEgU2V0OiBDb3VudHkgUHJlc2lkZW50aWFsIEVsZWN0aW9uIFJldHVybnMgMjAwMC0yMDIwPC9hPi4gDQoNCkVsZWN0aW9uIGRhdGEgd2FzIHJlYWQgaW50byBSU3R1ZGlvIGFzIGBlbGVjdGlvbl9yYXdgIGFuZCBjbGVhbmVkIHV0aWxpemluZyB0aGUgZm9sbG93aW5nIHN0ZXBzIHRvIGNyZWF0ZSB0aGUgcmVsYXRpb25hbCBkYXRhc2V0IGBlbGVjdGlvbmA6DQoNCi0gRGF0YSB3YXMgZ3JvdXBlZCBieSB0aGUgY291bnR5IGBGSVBTIGNvZGVgDQotIERhdGEgd2FzIHNvcnRlZCBieSBkZXNjZW5kaW5nIGBZZWFyYA0KLSBEYXRhIHdhcyBmaWx0ZXJlZCBieSBwb2xpdGljYWwgYFBhcnR5YCBmb3Igb25seSBgRGVtb2NyYXRgIGFuZCBgUmVwdWJsaWNhbmAgYXMgdGhlIGFuYWx5c2lzIGZvY3VzZXMgb24gdGhlIHBvdGVudGlhbCBpbXBhY3RzIG9uIGNvdW50eSBwcmVzaWRlbnRpYWwgZWxlY3Rpb24gd2lubmVycy4gIE5vIG90aGVyIHBhcnRpZXMgaGF2ZSBldmVyIHdvbiB0aGUgcHJlc2lkZW5jeSBhbmQgdGh1cyB3ZXJlIG9taXR0ZWQuICANCiAgLSBUbyBub3RlOiBibGFuayB2YWx1ZXMgd2VyZSBub3Qgb21pdHRlZA0KLSBVbm5lY2Vzc2FyeSB2YXJpYWJsZXMgd2VyZSByZW1vdmVkDQotIERhdGEgd2FzIGZpbHRlcmVkIGZvciBgMjAyMGAgb3IgdGhlIGBtb3N0IHJlY2VudCB5ZWFyIHdpdGggYXZhaWxhYmxlIGRhdGFgIGlmIDIwMjAgd2FzIG5vdCBhdmFpbGFibGUNCg0KQSBzZWFyY2hhYmxlIHByZXZpZXcgb2YgdGhlIHJlbGF0aW9uYWwgZGF0YXNldCBgZWxlY3Rpb25gIGlzIGF2YWlsYWJsZSBpbiB0aGUgZGF0YSB0YWJsZSBiZWxvdy4gIA0KDQpgYGB7cn0NCiMjcmVhZCBpbiB0aGUgZWxlY3Rpb24gZGF0YSBhcyBlbGVjdGlvbl9yYXcNCg0KZWxlY3Rpb25fcmF3IDwtIHJlYWQuY3N2KCdodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vbmxlcGVyYS9zdGE1NTEvcmVmcy9oZWFkcy9tYWluL0hXMDEvZGF0YS9jb3VudHlwcmVzaWRlbnRpYWxfZWxlY3Rpb25fMjAwMC0yMDIwLmNzdicpDQoNCiMjY2xlYW4gdGhlIGVsZWN0aW9uIGRhdGEgDQoNCmVsZWN0aW9uIDwtIGVsZWN0aW9uX3JhdyAlPiUgDQogIGdyb3VwX2J5KGNvdW50eV9maXBzKSAlPiUgICAjI2dyb3VwIGJ5IGNvdW50eSBGSVBTIGNvZGUNCiAgYXJyYW5nZSAoZGVzYyh5ZWFyKSkgJT4lICAgICMjc29ydCBieSBkZXNjZW5kaW5nIHllYXINCiAgZmlsdGVyIChwYXJ0eSA9PSAiREVNT0NSQVQiIHwgcGFydHkgPT0gIlJFUFVCTElDQU4iKSAlPiUgICAgIyNmaWx0ZXIgZm9yIG9ubHkgZGVtICYgcmVwDQogIHN1YnNldCgsIC1jKHN0YXRlX3BvLCBvZmZpY2UsIHZlcnNpb24sIG1vZGUpKSAlPiUgICAjI3JlbW92ZSB1bm5lY2Vzc2FyeSBjb2x1bW5zDQogIHNsaWNlICgxOjIpICU+JSAgICMjcHVsbCB0b3AgMiB2YWx1ZXMgZm9yIGVhY2ggZ3JvdXAgKGNvdW50eV9maXBzIHNvcnRlZCBieSBkZXNjIHllYXIpIHB1bGxpbmcgYm90aCBkZW0gJiByZXAgZm9yIGVhY2ggY291bnR5IGF0IG1heCB5ZWFyIGF2YWlsYWJsZQ0KICBhcnJhbmdlIChkZXNjKGNhbmRpZGF0ZXZvdGVzKSkgJT4lICAgICMjcmUgZmlsdGVyIHRvIHNvcnQgYnkgZ3JvdXAsIHdpdGggaGlnaGVzdCBjYW5kaWRhdGUgdm90ZXMgb24gdG9wDQogIHNsaWNlICgxKSAlPiUgICAgIyNvbmx5IGtlZXAgdmFsdWUgZm9yIGhpZ2hlc3QgY2FuZGlkYXRlIHZvdGVzICh3aW5uZXIpIHBlciBjb3VudHkNCiAgcmVuYW1lIChGSVBTID0gY291bnR5X2ZpcHMpICAgIyMgc2V0IElEIG5hbWUgZm9yIG91dGVyIGpvaW4NCiAgDQpEVDo6ZGF0YXRhYmxlKGVsZWN0aW9uKQ0KYGBgDQoNCiMjIyBVbmVtcGxveW1lbnQgRGF0YSAoMjAyMCBvciBtb3N0IHJlY2VudCB5ZWFyIGF2YWlsYWJsZSkNClRoZSByYXcgdW5lbXBsb3ltZW50IGRhdGEgd2FzIG9idGFpbmVkIGZyb20gZnJvbSB0aGUgcHVibGljbHkgYXZhaWxhYmxlIDxhIGhyZWY9Imh0dHBzOi8vd3d3LmVycy51c2RhLmdvdi9kYXRhLXByb2R1Y3RzL2NvdW50eS1sZXZlbC1kYXRhLXNldHMvIj5VU0RBIEVjb25vbWljIFJlc2VhcmNoIFNlcnZpY2UgQ291bnR5LWxldmVsIERhdGFzZXQ6IFVuZW1wbG95bWVudDwvYT4uIA0KDQpVbmVtcGxveW1lbnQgZGF0YSB3YXMgcmVhZCBpbnRvIFJTdHVkaW8gYXMgYHVuZW1wbG95X3Jhd2AgYW5kIGNsZWFuZWQgdXRpbGl6aW5nIHRoZSBmb2xsb3dpbmcgc3RlcHMgdG8gY3JlYXRlIHRoZSByZWxhdGlvbmFsIGRhdGFzZXQgYHVuZW1wbG95YDoNCg0KLSBEYXRhIHdhcyBmaWx0ZXJlZCBmb3IgdGV4dCBjb250YWluaW5nIHRoZSBzdHJpbmcgYFVuZW1wbG95bWVudGAgaW4gdGhlIGBBdHRyaWJ1dGVgIHZhcmlhYmxlIGRhdGEgdmFsdWVzIHRvIHJlbW92ZSBvdGhlciB1bm5lY2Vzc2FyeSBkYXRhIHR5cGVzLg0KLSBJbiBvcmRlciB0byBleHRyYWN0IHRoZSB5ZWFyIGZyb20gdGhlIGBBdHRyaWJ1dGVgIHZhbHVlcywgYSBuZXcgY29sdW1uIHdhcyBjcmVhdGVkIGJ5IGV4dHJhY3RpbmcgdGhlIGxhc3QgZm91ciAoNCkgY2hhcmFjdGVycyBvZiB0aGUgYEF0dHJpYnV0ZWAgdmFsdWVzLg0KLSBEYXRhIHdhcyBncm91cGVkIGJ5IHRoZSBjb3VudHkgYEZJUFMgY29kZWANCi0gRGF0YSB3YXMgc29ydGVkIGJ5IGRlc2NlbmRpbmcgYFllYXJgDQotIERhdGEgd2FzIGZpbHRlcmVkIGZvciBgMjAyMGAgb3IgdGhlIGBtb3N0IHJlY2VudCB5ZWFyIHdpdGggYXZhaWxhYmxlIGRhdGFgIGlmIDIwMjAgd2FzIG5vdCBhdmFpbGFibGUNCi0gVW5uZWNlc3NhcnkgdmFyaWFibGVzIHdlcmUgcmVtb3ZlZA0KDQpBIHNlYXJjaGFibGUgcHJldmlldyBvZiB0aGUgcmVsYXRpb25hbCBkYXRhc2V0IGB1bmVtcGxveWAgaXMgYXZhaWxhYmxlIGluIHRoZSBkYXRhIHRhYmxlIGJlbG93LiAgDQoNCmBgYHtyfQ0KIyMgcmVhZCBpbiB0aGUgdW5lbXBsb3ltZW50IGRhdGEgYXMgdW5lbXBsb3lfcmF3DQoNCnVuZW1wbG95X3JhdyA8LSByZWFkLmNzdignaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL25sZXBlcmEvc3RhNTUxL3JlZnMvaGVhZHMvbWFpbi9IVzAxL2RhdGEvVW5lbXBsb3ltZW50LmNzdicpDQoNCiMjIGNsZWFuIHRoZSB1bmVtcGxveW1lbnQgZGF0YQ0KdW5lbXBsb3kgPC0gdW5lbXBsb3lfcmF3ICU+JSANCiAgZmlsdGVyIChncmVwbCgnVW5lbXBsb3ltZW50JywgQXR0cmlidXRlKSkgJT4lICAgI3VzZSBkcGx5ciBwYWNrYWdlIHRvIHVzZSBmaWx0ZXIoZ3JlcGwoKSkgdG8gZmlsdGVyIGZvciBzdHJpbmcgb2YgdGV4dCB0byBzZWxlY3Qgb25seSB0aGUgdW5lbXBsb3ltZW50IHJhdGUgdmFsdWVzDQogIG11dGF0ZSAoeWVhciA9IHN0cl9zdWIoQXR0cmlidXRlLCAtNCkpICU+JSAgIyNjcmVhdGUgYSBuZXcgY29sdW1uIHVzaW5nIG11dGF0ZSBhbmQgc3RyaW5nciB0byBjcmVhdGUgYSBuZXcgY29sdW1uIGZyb20gdGhlIGxhc3QgNCB2YWx1ZXMgb2YgdGhlIGF0dHJpYnV0ZSBjb2x1bW4sIHRvIGV4dHJhY3QgdGhlIHllYXIgKHN0cl9zdWIgLT4gc3RyaW5ncl9zdWJzZXQpDQogIGdyb3VwX2J5IChGSVBTX0NvZGUpICU+JSAgIyNncm91cCBieSBGSVBTIGNvZGUgYmVmb3JlIHNvcnRpbmcgdG8gZ2V0IG1heCB5ZWFyDQogIGFycmFuZ2UgKGRlc2MoeWVhcikpICU+JSAgIyMgc29ydCBkZXNjZW5kaW5nIHllYXIgdG8gcHV0IG1heCBhdmFpbGFibGUgYXQgdGhlIHRvcA0KICBzbGljZSgxKSAlPiUgICAjI3NsaWNlIHRvcCB2YWx1ZSB0byBrZWVwIG9ubHkgbWF4IHllYXIgZm9yIGVhY2ggRklQUyBjb2RlDQogIHN1YnNldCAoLCBjKEZJUFNfQ29kZSwgVmFsdWUpKSAlPiUgICAjI3JlbW92ZSB1bm5lY2Vzc2FyeSBjb2x1bW5zDQogIHJlbmFtZSAoIlVuZW1wbG95bWVudF9SYXRlICglKSIgPSBWYWx1ZSwgRklQUyA9IEZJUFNfQ29kZSkgICAgIyNyZW5hbWUgY29sdW1uIHRvIHJlZmxlY3QgdW5lbXBsb3ltZW50IHJhdGUgJiBzZXQgSUQgbmFtZSBmb3Igb3V0ZXIgam9pbg0KDQpEVDo6ZGF0YXRhYmxlKHVuZW1wbG95KQ0KICANCmBgYA0KDQojIyMgUG92ZXJ0eSBEYXRhICgyMDE5KQ0KVGhlIHJhdyBwb3ZlcnR5IGRhdGEgd2FzIG9idGFpbmVkIGZyb20gZnJvbSB0aGUgcHVibGljbHkgYXZhaWxhYmxlIDxhIGhyZWY9Imh0dHBzOi8vd3d3LmVycy51c2RhLmdvdi9kYXRhLXByb2R1Y3RzL2NvdW50eS1sZXZlbC1kYXRhLXNldHMvIj5VU0RBIEVjb25vbWljIFJlc2VhcmNoIFNlcnZpY2UgQ291bnR5LWxldmVsIERhdGFzZXQ6IFBvdmVydHk8L2E+LiANCg0KUG92ZXJ0eSBkYXRhIHdhcyByZWFkIGludG8gUlN0dWRpbyBhcyBgcG92ZXJ0eV9yYXdgIGFuZCBjbGVhbmVkIHV0aWxpemluZyB0aGUgZm9sbG93aW5nIHN0ZXBzIHRvIGNyZWF0ZSB0aGUgcmVsYXRpb25hbCBkYXRhc2V0IGBwb3ZlcnR5YDoNCg0KLSBEYXRhIHdhcyBmaWx0ZXJlZCBmb3IgdGV4dCBjb250YWluaW5nIHRoZSBzdHJpbmcgYFBDVFBPVkFMTF8yMDE5YCBpbiB0aGUgYEF0dHJpYnV0ZWAgdmFyaWFibGUgZGF0YSB2YWx1ZXMgdG8gcmVtb3ZlIG90aGVyIHVubmVjZXNzYXJ5IGRhdGEgdHlwZXMuDQotIFVubmVjZXNzYXJ5IHZhcmlhYmxlcyB3ZXJlIHJlbW92ZWQNCg0KQSBzZWFyY2hhYmxlIHByZXZpZXcgb2YgdGhlIHJlbGF0aW9uYWwgZGF0YXNldCBgdW5lbXBsb3lgIGlzIGF2YWlsYWJsZSBpbiB0aGUgZGF0YSB0YWJsZSBiZWxvdy4NCg0KYGBge3J9DQojIyByZWFkIGluIHRoZSBwb3ZlcnR5IGRhdGEgYXMgcG92ZXJ0eV9yYXcNCg0KcG92ZXJ0eV9yYXcgPC0gcmVhZC5jc3YoJ2h0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9ubGVwZXJhL3N0YTU1MS9yZWZzL2hlYWRzL21haW4vSFcwMS9kYXRhL1BvdmVydHlFc3RpbWF0ZXMuY3N2JykNCg0KIyNjbGVhbiB0aGUgcG92ZXJ0eSBkYXRhDQpwb3ZlcnR5IDwtIHBvdmVydHlfcmF3ICU+JSANCiAgZmlsdGVyIChBdHRyaWJ1dGUgPT0gIlBDVFBPVkFMTF8yMDE5IikgJT4lICAjI0ZpbHRlciBmb3IgMjAxOSBwb3ZlcnR5IHZhbHVlcw0KICBzdWJzZXQgKCwgYyhGSVBTdHh0LCBWYWx1ZSkpICU+JSAgIyNyZW1vdmUgdW5uZWNjZXNzYXJ5IGNvbHVtbnMNCiAgcmVuYW1lICgiUG92ZXJ0eV9SYXRlICglKSIgPSBWYWx1ZSwgRklQUyA9IEZJUFN0eHQpICAgIyNyZW5hbWUgVmFsdWUgY29sdW1uIHRvIFBvdmVydHlfUmF0ZSAoJSkgYW5kIHNldCBJRCBuYW1lIGZvciBvdXRlciBqb2luDQoNCkRUOjpkYXRhdGFibGUocG92ZXJ0eSkNCmBgYA0KDQojIyMgRWR1Y2F0aW9uIERhdGEgKDIwMTUgLSAyMDE5KQ0KVGhlIHJhdyBlZHVjYXRpb24gZGF0YSB3YXMgb2J0YWluZWQgZnJvbSBmcm9tIHRoZSBwdWJsaWNseSBhdmFpbGFibGUgPGEgaHJlZj0iaHR0cHM6Ly93d3cuZXJzLnVzZGEuZ292L2RhdGEtcHJvZHVjdHMvY291bnR5LWxldmVsLWRhdGEtc2V0cy8iPlVTREEgRWNvbm9taWMgUmVzZWFyY2ggU2VydmljZSBDb3VudHktbGV2ZWwgRGF0YXNldDogRWR1Y2F0aW9uPC9hPi4gDQoNClVuZW1wbG95bWVudCBkYXRhIHdhcyByZWFkIGludG8gUlN0dWRpbyBhcyBgZWR1X3Jhd2AgYW5kIGNsZWFuZWQgdXRpbGl6aW5nIHRoZSBmb2xsb3dpbmcgc3RlcHMgdG8gY3JlYXRlIHRoZSByZWxhdGlvbmFsIGRhdGFzZXQgYGVkdWA6DQoNCi0gVW5uZWNlc3NhcnkgdmFyaWFibGVzIHdlcmUgcmVtb3ZlZA0KLSBDb2x1bW5zIHdlcmUgcmVuYW1lZCB0byB0cnVuY2F0ZWQgdmFsdWVzIGZvciBlYXNlIG9mIHVzZToNCiAgLSBgTm9fSFNgID0gIyBvZiBwZXJzb25zIGluIHRoZSBjb3VudHkgd2l0aCBsZXNzIHRoYW4gYSBoaWdoIHNjaG9vbCBkaXBsb21hDQogIC0gYEhTYCA9ICMgb2YgcGVyc29ucyBpbiB0aGUgY291bnR5IHdpdGggYSBoaWdoIHNjaG9vbCBkaXBsb21hIG9ubHkNCiAgLSBgQVNfU29tZUNvbGAgPSAjIG9mIHBlcnNvbnMgaW4gdGhlIGNvdW50eSB3aXRoIGVpdGhlciBzb21lIGNvbGxlZ2UgY3JlZGl0IG9yIGFuIEFzc29jaWF0ZSdzIERlZ3JlZQ0KICAtIGBCU19Nb3JlYCA9ICMgb2YgcGVyc29ucyBpbiB0aGUgY291bnR5IHdpdGggYSBCYWNoZWxvcidzIERlZ3JlZSBvciBoaWdoZXINCi0gRGF0YSBjbGVhbmVkIHRvIHJlbW92ZSBjb21tYXMgZnJvbSBudW1iZXJzIGFuZCBjb252ZXJ0IGZyb20gY2hhcmFjdGVyIHRvIG51bWVyaWMgdmFsdWVzDQoNCg0KQSBzZWFyY2hhYmxlIHByZXZpZXcgb2YgdGhlIHJlbGF0aW9uYWwgZGF0YXNldCBgdW5lbXBsb3lgIGlzIGF2YWlsYWJsZSBpbiB0aGUgZGF0YSB0YWJsZSBiZWxvdy4NCg0KDQpgYGB7cn0NCiMjIHJlYWQgaW4gdGhlIHVuZW1wbG95bWVudCBkYXRhIGFzIGVkdV9yYXcNCg0KZWR1X3JhdyA8LSByZWFkLmNzdignaHR0cHM6Ly9ubGVwZXJhLmdpdGh1Yi5pby9zdGE1NTEvSFcwMS9kYXRhL0VkdWNhdGlvbi5jc3YnLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQoNCg0KI2NsZWFuIGVkdWNhdGlvbiBkYXRhDQplZHUgPC0gZWR1X3JhdyAlPiUgDQogIHN1YnNldCAoLCBjKEZJUFMuQ29kZSwgTGVzcy50aGFuLmEuaGlnaC5zY2hvb2wuZGlwbG9tYS4uMjAxNS4xOSwgSGlnaC5zY2hvb2wuZGlwbG9tYS5vbmx5Li4yMDE1LjE5LCBTb21lLmNvbGxlZ2Uub3IuYXNzb2NpYXRlLnMuZGVncmVlLi4yMDE1LjE5LAlCYWNoZWxvci5zLmRlZ3JlZS5vci5oaWdoZXIuLjIwMTUuMTkpKSAlPiUgICMjcmVtb3ZlIGlycmVsZXZhbnQgY29sdW1ucw0KICByZW5hbWUgKCAiTm9fSFMiID0gTGVzcy50aGFuLmEuaGlnaC5zY2hvb2wuZGlwbG9tYS4uMjAxNS4xOSwgIkhTIiA9IEhpZ2guc2Nob29sLmRpcGxvbWEub25seS4uMjAxNS4xOSwgIkFTX1NvbWVDb2wiID0gU29tZS5jb2xsZWdlLm9yLmFzc29jaWF0ZS5zLmRlZ3JlZS4uMjAxNS4xOSwJIkJTX01vcmUiID0gQmFjaGVsb3Iucy5kZWdyZWUub3IuaGlnaGVyLi4yMDE1LjE5LCBGSVBTID0gRklQUy5Db2RlKSAgIyNyZW5hbWUgZm9yIGVhc2UgYW5kIHNldCBJRCBuYW1lIGZvciBvdXRlciBqb2luDQplZHUkTm9fSFMgPSBnc3ViKCcsJywgJycsIGVkdSROb19IUykgIyNyZW1vdmUgY29tbWFzIGZyb20gbnVtYmVyIHdpdGggY29tbWFzIHNhdmVkIGFzIGNoYXJhY2h0ZXJzDQplZHUkSFMgPSBnc3ViKCcsJywgJycsIGVkdSRIUykNCmVkdSRBU19Tb21lQ29sID0gZ3N1YignLCcsICcnLCBlZHUkQVNfU29tZUNvbCkNCmVkdSRCU19Nb3JlID0gZ3N1YignLCcsICcnLCBlZHUkQlNfTW9yZSkNCmVkdSROb19IUyA9IGFzLm51bWVyaWMoZWR1JE5vX0hTKSAgIyN0cmFuc2Zvcm0gdG8gbnVtZXJpYyB0byBhZ2dyZWdhdGUNCmVkdSRIUyA9IGFzLm51bWVyaWMoZWR1JEhTKQ0KZWR1JEFTX1NvbWVDb2wgPSBhcy5udW1lcmljKGVkdSRBU19Tb21lQ29sKQ0KZWR1JEJTX01vcmUgPSBhcy5udW1lcmljKGVkdSRCU19Nb3JlKQ0KICANCkRUOjpkYXRhdGFibGUoZWR1KQ0KYGBgDQojIyBNZXJnZSBSZWxhdGlvbmFsIERhdGFzZXRzICYgQWdncmVnYXRlIGRhdGENCg0KIyMjIE1lcmdlIHRoZSByZWxhdGlvbmFsIGRhdGFzZXRzIHVzaW5nIGNvdW50eSBGSVBTIGNvZGVzDQoNCk9uY2UgYWxsIGZvdXIgKDQpIHJlbGF0aW9uYWwgZGF0YXNldHMgKGBlZHVgLCBgZWxlY3Rpb25gLCBgcG92ZXJ0eWAsIGFuZCBgdW5lbXBsb3lgKSB3ZXJlIGNyZWF0ZWQsIGEgbmV3IGRhdGFzZXQgbmFtZWQgYGFsbC5kYXRhYCB3YXMgY3JlYXRlZCBieSBjb21wbGV0aW5nIG11bHRpcGxlIGZ1bGwgam9pbiBmdW5jdGlvbnMuICBBbGwgZGF0YXNldHMgd2VyZSBtZXJnZWQgdXNpbmcgdGhlIGNvdW50eSBgRklQU2AgY29kZSBhcyB0aGUgdW5pcXVlIGlkZW50aWZpZXIgY29uc2VydmVkIGFjcm9zcyBhbGwgZGF0YXNldHMuIA0KDQpgYGB7cn0NCiMjbWVyZ2UgZWxlY3Rpb24gZGF0YSAmIGVkdWNhdGlvbiBkYXRhIGFzIGVsZWN0aW9uLmVkdWNhdGlvbiANCmVsZWN0aW9uLmVkdWNhdGlvbiA8LSBmdWxsX2pvaW4gKA0KICB4ID0gZWxlY3Rpb24sDQogIHkgPSBlZHUsDQogIGJ5ID0gIkZJUFMiLA0KICBrZWVwID0gRkFMU0UNCikNCg0KDQojI21lcmdlIGVsZWN0aW9uLmVkdWNhdGlvbiAmIHBvdmVydHkgZGF0YSBhcyBlbGVjdGlvbi5lZHVjYXRpb24ucG92ZXJ0eQ0KZWxlY3Rpb24uZWR1Y2F0aW9uLnBvdmVydHkgPC0gZnVsbF9qb2luKA0KICB4ID0gZWxlY3Rpb24uZWR1Y2F0aW9uLA0KICB5ID0gcG92ZXJ0eSwNCiAgYnkgPSAiRklQUyIsDQogIGtlZXAgPSBGQUxTRQ0KKQ0KDQojI21lcmdlIGVsZWN0aW9uLmVkdWNhdGlvbi5wb3ZlcnR5ICYgdW5lbXBsb3ltZW50IGRhdGEgYXMgYWxsLmRhdGENCmFsbC5kYXRhIDwtIGZ1bGxfam9pbiAoDQogIHggPSBlbGVjdGlvbi5lZHVjYXRpb24ucG92ZXJ0eSwNCiAgeSA9IHVuZW1wbG95LA0KICBieSA9ICJGSVBTIiwNCiAga2VlcCA9IEZBTFNFDQopDQoNCg0KYGBgDQoNCiMjIyBBZ2dyZWdhdGUgdGhlIEVkdWNhdGlvbiBEYXRhIGludG8gJSBIaWdoZXIgRWQNCg0KQXMgdGhlIGVkdWNhdGlvbmFsIGRhdGEgcHJvdmlkZWQgZm9yIGVhY2ggY291bnR5IGNvbnNpc3RlZCBvZiB0aGUgdG90YWwgbnVtYmVyIG9mIHBlcnNvbnMgaW4gZWFjaCBjb3VudHkgdGhhdCByZWNlaXZlZCBlYWNoIG9mIHRoZSBmb3VyIHRpZXJzIG9mIGVkdWNhdGlvbiwgdGhlIGRhdGEgd2FzIGFnZ3JlZ2F0ZWQgdG8gYWxsb3cgZm9yIGNsZWFuZXIgYW5hbHlzaXMgYW5kIGNvbXBhcmlzb24uICBJbiBvcmRlciB0byBhZ2dyZWdhdGUgdGhlIGVkdWNhdGlvbmFsIGRhdGEsIHRoZSBmb3VyIGVkdWNhdGlvbiB2YXJpYWJsZXMgKGBOb19IU2AsIGBIU2AsIGBBU19Tb21lQ29sYCwgJiBgQlNfTW9yZWApIHdlcmUgYWdncmVnYXRlZCB0byBjcmVhdGUgYSBuZXcgdmFyaWFibGUgYEhpZ2hlcl9FZF9QZXJjZW50YCB0byBtZWFzdXJlIHRoZSBwZXJjZW50YWdlIG9mIHRoZSBwb3B1bGF0aW9uIHN1cnZleWVkIHRoYXQgY29tcGxldGVkIGVpdGhlciBzb21lIGNvbGxlZ2UgY3JlZGl0LCBhbiBBc3NvY2lhdGUncyBEZWdyZWUsIGEgQmFjaGVsb3IncyBEZWdyZWUsIG9yIGFkZGl0aW9uYWwgZ3JhZHVhdGUgbGV2ZWwgZGVncmVlcy4gIA0KDQpUaGlzIGhpZ2hlciBlZHVjYXRpb24gbWV0cmljIHdhcyBjcmVhdGVkIGFzIGEgbWVhc3VyZSBvZiB0aGUgYXZlcmFnZSBzb2Npb2Vjb25vbWljIHN0YXR1cyBvZiB0aGUgY291bnRpZXMgYmVpbmcgYW5hbHl6ZWQuDQoNCmBgYHtyfQ0KYWxsLmRhdGEgPC0gYWxsLmRhdGEgICU+JSANCiAgZmlsdGVyKEZJUFMgIT0gMCkgJT4lICMjZmlsdGVyIG91dCB2YWx1ZXMgd2l0aCBubyBhc3NvY2lhdGVkIGNvdW50eSBvciBzdGF0ZSBuYW1lDQogIGZpbHRlcihGSVBTICE9IDEwMDApICU+JSANCiAgbXV0YXRlIChIaWdoZXJfRWRfUGVyY2VudCA9ICgoKGBBU19Tb21lQ29sYCArIGBCU19Nb3JlYCkvKGBOb19IU2ArIGBIU2AgKyBgQVNfU29tZUNvbGAgKyBgQlNfTW9yZWApKSoxMDApKSAgIyMlIG9mIHBvcCB3aXRoIGhpZ2hlciBlZC4NCg0KYGBgDQoNCiMgVmlzdWFsaXppbmcgYW5kIEFuYWx5emluZyB0aGUgRGF0YQ0KDQojIyBNYXBwaW5nIHRoZSBmdWxsIGRhdGENCg0KRm9yIGFuIGluaXRpYWwgdmlzdWFsaXphdGlvbiBvZiB0aGUgZGF0YSBhcyBhIHdob2xlLCB0aGUgYGFsbC5kYXRhYCBkYXRhc2V0IHdhcyBtYXBwZWQgYnkgY291bnR5IHV0aWxpemluZyBhbiBpbnRlcmFjdGl2ZSBsZWFmbGV0IG1hcC4gIER1ZSB0byB0aGUgc2l6ZSBvZiB0aGUgZGF0YXNldCBhbmQgbnVtYmVyIG9mIGNvdW50aWVzLCBjb2xvciBzcGVjaWZpYyBkYXRhIGlzIG5vdCB2aXNpYmxlIHVudGlsIHRoZSBtYXAgaXMgem9vbWVkIGluIHRvIHRoZSBhcHByb3ByaWF0ZSBjb3VudHkgbGV2ZWwuICBVbnRpbCB6b29tZWQgaW4gdGhlIGNvbG9yIHNjYWxlIChncmVlbiB0byByZWQpIHJlcHJlc2VudHMgdGhlIG51bWJlciBvZiBjb3VudGllcyBuZXN0ZWQgaW4gdGhhdCBncm91cCB1bnRpbCB0aGUgbWFwIGlzIHpvb21lZCBpbiBmdXJ0aGVyLiAgT25jZSBmdWxseSB6b29tZWQgaW4gdGhlIGNvbG9yIG9mIHRoZSA8Yj51bm51bWJlcmVkIGNpcmNsZXM8L2I+IChyZWQgYW5kIGJsdWUpIHJlcHJlc2VudCB0aGUgd2lubmluZyBwYXJ0eSAoUmVwdWJsaWNhbiBhbmQgRGVtb2NyYXQgcmVzcGVjdGl2ZWx5KSBpbiBlYWNoIGNvdW50eSBmb3IgdGhlIDIwMjAgcHJlc2lkZW50aWFsIGVsZWN0aW9uLg0KDQpgYGB7cn0NCg0KY291bnR5X2RhdGFfcmF3IDwtIHNmOjpyZWFkX3NmKCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vcGxvdGx5L2RhdGFzZXRzL21hc3Rlci9nZW9qc29uLWNvdW50aWVzLWZpcHMuanNvbiIpICMjcHVsbCBpbiBtYXAgb2YgRklQUyBjb2RlcyANCg0KRklQU2NvbnZlcnRfcmF3IDwtIHNmOjpyZWFkX3NmKCJodHRwczovL25sZXBlcmEuZ2l0aHViLmlvL3N0YTU1MS9IVzAxL2RhdGEvZmlwczJnZW9jb2RlLmNzdiIpICMjcHVsbCBpbiBrZXkgb2YgRklQUyBjb2RlcyB0byBsYXQvbG9uZw0KDQpjb3VudHlfZGF0YSA8LSBjb3VudHlfZGF0YV9yYXcgJT4lICAjY2xlYW4gY291bnR5IGRhdGEgdG8gbGlzdCBGSVBTIGFzIG51bWVyaWMgJiBtYXRjaCBuYW1lIHRvIGtleSBmb3Igam9pbg0KICBtdXRhdGUgKGlkID0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoaWQpKSkgJT4lIA0KICByZW5hbWUgKEZJUFMgPSBpZCkNCg0KRklQU2NvbnZlcnQgPC0gRklQU2NvbnZlcnRfcmF3ICU+JSAgDQogIG11dGF0ZSAoZmlwcyA9IGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGZpcHMpKSwgbG9uID0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIobG9uKSksIGxhdCA9IGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGxhdCkpKSAlPiUgDQogIHJlbmFtZSAoRklQUyA9IGZpcHMsIExvbmdpdHVkZSA9IGxvbiwgTGF0aXR1ZGUgPSBsYXQpDQoNCmFsbC5kYXRhLmpvaW4gPC0gZnVsbF9qb2luKA0KICB4ID0gYWxsLmRhdGEsDQogIHkgPSBGSVBTY29udmVydCwNCiAgYnkgPSAiRklQUyIsDQogIGtlZXAgPSBGQUxTRQ0KKSAlPiUgDQogIHVuZ3JvdXAoKQ0KYGBgDQoNCjxoMj4gSW50ZXJhY3RpdmUgTWFwIG9mIENvdW50eSBEYXRhIDwvaDI+DQoNCmBgYHtyfQ0KcGFsIDwtIGNvbG9yRmFjdG9yKGMoImJsdWUiLCAicmVkIiksIGRvbWFpbiA9IGMoIlJFUFVCTElDQU4iLCAiREVNT0NSQVQiKSkNCg0KdGl0bGUgPC0gIg0KPHN0eWxlPg0KICAuY3VzdG9tLXRpdGxlIHsNCiAgICBjb2xvcjogd2hpdGU7DQogICAgcGFkZGluZzogMHB4Ow0KICAgIGJvcmRlci1yYWRpdXM6IDBweDsNCiAgICB0ZXh0LWFsaWduOiByaWdodDsNCiAgfQ0KPC9zdHlsZT4NCkVsZWN0aW9uIFJlc3VsdHMsIEVkdWNhdGlvbiBSYXRlcywgVW5lbXBsb3ltZW50IFJhdGVzICYgUG92ZXJ0eSBSYXRlcw0KPGJyPlpvb20gaW4gdG8gdmlldyBlYWNoIGNvdW50eSBpbmRpdmlkdWFsbHkNCjxicj5TZWxlY3QgYSBjb3VudHkncyBjaXJjbGUgdG8gdmlldyBmdWxsIGRhdGEiDQoNCmxlYWZsZXQoKSAlPiUgDQogIHNldFZpZXcobG5nPS05OC41Nzk1LCBsYXQ9MzkuODI4Mywgem9vbSA9IDQpICU+JSAjI3NldCB2aWV3IHRvIG1pZCBVUw0KICBhZGRQcm92aWRlclRpbGVzKHByb3ZpZGVycyRDYXJ0b0RCLkRhcmtNYXR0ZXIpICU+JSAgIyNzZXQgbWFwIHRvIGRhcmsgbW9kZQ0KICBhZGRDb250cm9sKGh0bWwgPSB0aXRsZSwgDQogICAgICAgICAgICAgcG9zaXRpb24gPSAidG9wcmlnaHQiLCANCiAgICAgICAgICAgICBjbGFzc05hbWUgPSAiY3VzdG9tLXRpdGxlIikgJT4lIA0KICBhZGRQb2x5Z29ucyhkYXRhID0gY291bnR5X2RhdGEsICAjI2FkZCBGSVBTIHBvbHlnb25zDQogICAgICAgICAgICAgIGNvbG9yID0gInllbGxvdyIsDQogICAgICAgICAgICAgIGZpbGwgPSBGQUxTRSwNCiAgICAgICAgICAgICAgd2VpZ2h0ID0gMC4yNSkgJT4lIA0KICBhZGRDaXJjbGVNYXJrZXJzKGRhdGEgPSBhbGwuZGF0YS5qb2luLA0KICAgICAgICAgICAgICAgICAgIGNvbG9yID0gfnBhbChwYXJ0eSksDQogICAgICAgICAgICAgICAgICAgcmFkaXVzID0gMjAsDQogICAgICAgICAgICAgICAgICAgZmlsbE9wYWNpdHkgPSAwLjUsDQogICAgICAgICAgICAgICAgICAgcG9wdXAgPSB+cG9wdXBUYWJsZShhbGwuZGF0YSksDQogICAgICAgICAgICAgICAgICAgY2x1c3Rlck9wdGlvbnMgPSBtYXJrZXJDbHVzdGVyT3B0aW9ucyhtYXhDbHVzdGVyUmFkaXVzID0gNTApKQ0KICANCiAgDQpgYGANCg0KIyMgUGxvdCB2YXJpYWJsZSBkaXN0cmlidXRpb24NCg0KQmVmb3JlIGNvbXBsZXRpbmcgYW55IGRhdGEgYW5hbHlzaXMgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgdGhyZWUgbnVtZXJpYyB2YXJpYWJsZXMgb2YgaW50ZXJlc3Qgd2FzIHJldmlld2VkLCBjb250cm9sbGluZyBmb3IgdGhlIHRoZSB3aW5uaW5nIHBhcnR5IChSZXB1YmxpY2FuIG9yIERlbW9jcmF0KSBpbiBlYWNoIGNvdW50eSBmb3IgdGhlIDIwMjAgcHJlc2lkZW50aWFsIGVsZWN0aW9uLg0KDQpCb3RoIHVuZW1wbG95bWVudCBhbmQgaGlnaGVyIGVkdWNhdGlvbiByYXRlcyBhcHBlYXIgdG8gaGF2ZSBub3JtYWwgZGlzdHJpYnV0aW9ucyB3aGlsZSBwb3ZlcnR5IHJhdGVzIGFwcGVhciB0byBoYXZlIGNsb3NlciB0byBhIGdhbW1hIGRpc3RyaWJ1dGlvbi4gIEEgZ3JlYXRlciBmcmVxdWVuY3kgb2YgY291bnRpZXMgd2l0aCBkZW1vY3JhdGljIGNhbmRpZGF0ZSB3aW5uZXJzIHdhcyBzZWVuIGZvciBhbGwgdGhyZWUgKDMpIHZhcmlhYmxlcyBpbiBxdWVzdGlvbi4gDQpgYGB7cn0NCg0KZ2dwbG90IChhbGwuZGF0YSwgYWVzKHggPSBgVW5lbXBsb3ltZW50X1JhdGUgKCUpYCwgZmlsbCA9IGBwYXJ0eWApKSArDQogIGdlb21faGlzdG9ncmFtKGluaGVyaXQuYWVzID0gVFJVRSwgY29sb3IgPSAiYmxhY2siKSArDQogIGdndGl0bGUgKCJEaXN0cmlidXRpb24gb2YgVW5lbXBsb3ltZW50IFJhdGVzIGJ5IENvdW50eSBFbGVjdGlvbiBXaW5uZXIiKSArDQogIHhsYWIgKCJDb3VudHkgVW5lbXBsb3ltZW50IFJhdGUgKHgpDQogICAgICAgIFslIG9mIENvdW50eSBQb3AuXSIpICsgDQogIHlsYWIgKCJDb3VudGllcyBXLyBVbmVtcGxveW1lbnQgUmF0ZSA9IHgiKSAgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJibHVlIiwgInJlZCIpKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC44LCAwLjgpKQ0KDQpnZ3Bsb3QgKGFsbC5kYXRhLCBhZXMoeCA9IGBQb3ZlcnR5X1JhdGUgKCUpYCwgZmlsbCA9IGBwYXJ0eWApKSArDQogIGdlb21faGlzdG9ncmFtKGluaGVyaXQuYWVzID0gVFJVRSwgY29sb3IgPSAiYmxhY2siKSArIA0KICBnZ3RpdGxlICgiRGlzdHJpYnV0aW9uIG9mIFBvdmVydHkgUmF0ZXMgYnkgQ291bnR5IEVsZWN0aW9uIFdpbm5lciIpICsgDQogIHhsYWIgKCJDb3VudHkgUG92ZXJ0eSBSYXRlICh4KQ0KICAgICAgICBbJSBvZiBDb3VudHkgUG9wLl0iKSArDQogIHlsYWIgKCJDb3VudGllcyBXLyBQb3ZlcnR5IFJhdGUgPSB4IikgICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiYmx1ZSIsICJyZWQiKSkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKDAuOCwgMC44KSwgaGVpZ2h0ID0gIjIwMHB4IikNCg0KZ2dwbG90IChhbGwuZGF0YSwgYWVzKHggPSBgSGlnaGVyX0VkX1BlcmNlbnRgLCBmaWxsID0gYHBhcnR5YCkpICsgDQogIGdlb21faGlzdG9ncmFtKGluaGVyaXQuYWVzID0gVFJVRSwgY29sb3IgPSAiYmxhY2siKSArIA0KICBnZ3RpdGxlICgiRGlzdHJpYnV0aW9uIG9mIEhpZ2hlciBFZHVjYXRpb24gUmF0ZXMgYnkgQ291bnR5IEVsZWN0aW9uIFdpbm5lciIpICsgDQogIHhsYWIgKCJDb3VudHkgSGlnaGVyIEVkLiBSYXRlICh4KQ0KICAgICAgICBbJSBvZiBDb3VudHkgUG9wLl0gIikgKyANCiAgeWxhYiAoIkNvdW50aWVzIFcvIEhpZ2hlciBFZC4gUmF0ZSA9IHgiKSAgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJibHVlIiwgInJlZCIpKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC44LCAwLjgpKQ0KDQpgYGANCg0KIyMgUGxvdCBSZWxhdGlvbnNoaXAgQmV0d2VlbiBOdW1lcmljIFZhcmlhYmxlcw0KDQpUbyBkZXRlcm1pbmUgdGhlIHBvdGVudGlhbCByZWxhdGlvbnNoaXBzIGJldHdlZW4gdGhlIHRocmVlIG51bWVyaWMgdmFyaWFibGVzIG9mIGludGVyZXN0IChgVW5lbXBsb3ltZW50IFJhdGVgLCBgUG92ZXJ0eSBSYXRlYCwgYW5kIGBIaWdoZXIgRWR1Y2F0aW9uIFJhdGVgKSB3ZXJlIHBsb3R0ZWQgYWdhaW5zdCBlYWNoIG90aGVyIGFuZCByZXZpZXdlZCB1dGlsaXppbmcgYSBiYXNpYyBsaW5lYXIgcmVncmVzc2lvbiBtb2RlbCBmb3IgdGhlIG5vcm1hbGx5IGRpc3RyaWJ1dGVkIGRhdGEgYW5kIGEgR0xNIGdhbW1hIHJlZ3Jlc2lvbiBtb2RlbCBmb3IgdGhlIGdhbW1hIGRpc3RyaWJ1dGVkIGRhdGEuDQpgYGB7cn0NCmdncGxvdChkYXRhID0gYWxsLmRhdGEsIGFlcyh4ID1hbGwuZGF0YSRgVW5lbXBsb3ltZW50X1JhdGUgKCUpYCwgeT1hbGwuZGF0YSRgUG92ZXJ0eV9SYXRlICglKWAsIGNvbG9yPWBwYXJ0eWApKSArDQogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjI1KSArDQogICAgZ2d0aXRsZSAoIlVuZW1wbG95bWVudCBSYXRlcyB2cy4gUG92ZXJ0eSBSYXRlcyBieSBFbGVjdGlvbiBXaW5uaW5nIFBhcnR5IikgKyANCiAgICB4bGFiICgiQ291bnR5IFVuZW1wbG95bWVudCBSYXRlIFslIG9mIENvdW50eSBQb3AuXSAoeCkiKSArIA0KICAgIHlsYWIgKCJDb3VudHkgUG92ZXJ0eSBSYXRlIFslIG9mIENvdW50eSBQb3AuXSAoeSkiKSAgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiYmx1ZSIsICJyZWQiKSkgKw0KICBzdGF0X3Ntb290aChtZXRob2QgPSBsbSwgc2U9RkFMU0UsIHNpemUgPSAwLjEpIA0KDQpgYGANCg0KYGBge3J9DQpwb3ZfdW5lbSA8LSBsbShgUG92ZXJ0eV9SYXRlICglKWB+YFVuZW1wbG95bWVudF9SYXRlICglKWAgLCBkYXRhID0gYWxsLmRhdGEpDQpzdW1tYXJ5KHBvdl91bmVtKQ0KDQpgYGANCg0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IGFsbC5kYXRhLCBhZXMoeCA9YWxsLmRhdGEkYEhpZ2hlcl9FZF9QZXJjZW50YCwgeT1hbGwuZGF0YSRgUG92ZXJ0eV9SYXRlICglKWAsIGNvbG9yPWBwYXJ0eWApKSArDQogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjI1KSArDQogICAgZ2d0aXRsZSAoIlBlcmNlbnQgb2YgUG9wdWxhdGlvbiB3LyBIaWdoZXIgRWR1Y2F0aW9uIHZzLg0KICAgICAgICAgICAgIFBvdmVydHkgUmF0ZXMgYnkgRWxlY3Rpb24gV2lubmluZyBQYXJ0eSIpICsgDQogICAgeGxhYiAoIkNvdW50eSBIaWdoZXIgRWQuIFJhdGUgWyUgb2YgQ291bnR5IFBvcC5dICh4KSIpICsgDQogICAgeWxhYiAoIkNvdW50eSBQb3ZlcnR5IFJhdGUgWyUgb2YgQ291bnR5IFBvcC5dICh5KSIpICArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJibHVlIiwgInJlZCIpKSArDQogIHN0YXRfc21vb3RoKG1ldGhvZCA9IGdsbSwgc2U9RkFMU0UsIHNpemUgPSAwLjEpIA0KDQpgYGANCg0KYGBge3J9DQpoaWdoZWRfcG92IDwtIGdsbShgSGlnaGVyX0VkX1BlcmNlbnRgfmBQb3ZlcnR5X1JhdGUgKCUpYCwgZGF0YSA9IGFsbC5kYXRhKQ0Kc3VtbWFyeShoaWdoZWRfcG92KQ0KDQpgYGANCg0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IGFsbC5kYXRhLCBhZXMoeCA9YWxsLmRhdGEkYEhpZ2hlcl9FZF9QZXJjZW50YCwgeT1hbGwuZGF0YSRgVW5lbXBsb3ltZW50X1JhdGUgKCUpYCwgY29sb3I9YHBhcnR5YCkpICsNCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMjUpICsNCiAgICBnZ3RpdGxlICgiUGVyY2VudCBvZiBQb3B1bGF0aW9uIHcvIEhpZ2hlciBFZHVjYXRpb24gdnMuDQogICAgICAgICAgICAgVW5lbXBsb3ltZW50IFJhdGVzIGJ5IEVsZWN0aW9uIFdpbm5pbmcgUGFydHkiKSArIA0KICAgIHhsYWIgKCJDb3VudHkgSGlnaGVyIEVkLiBSYXRlIFslIG9mIENvdW50eSBQb3AuXSAoeCkiKSArIA0KICAgIHlsYWIgKCJDb3VudHkgVW5lbXBsb3ltZW50IFJhdGUgWyUgb2YgQ291bnR5IFBvcC5dICh5KSIpICArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJibHVlIiwgInJlZCIpKSArDQogIHN0YXRfc21vb3RoKG1ldGhvZCA9IGxtLCBzZT1GQUxTRSwgc2l6ZSA9IDAuMSkgDQoNCmBgYA0KDQpgYGB7cn0NCmhpZ2hlZF91bmVtIDwtIGxtKGBIaWdoZXJfRWRfUGVyY2VudGB+YFVuZW1wbG95bWVudF9SYXRlICglKWAsIGRhdGEgPSBhbGwuZGF0YSkNCnN1bW1hcnkoaGlnaGVkX3VuZW0pDQoNCmBgYA0KDQojIENvbmNsdXNpb25zDQoNCldoaWxlIGFsbCB0aHJlZSBpbnZlc3RpZ2F0ZWQgcG90ZW50aWFsIGNvcnJlbGF0aW9ucyBpbmRpY2F0ZWQgYSBoaWdoIGxldmVsIG9mIHN0YXRpc3RpYyBzaWduaWZpY2FuY2Ugd2l0aCBwIHZhbHVlcyB3ZWxsIGJlbG93IDAuMDUsIGJvdGggdGhlIGBVbmVtcGxveW1lbnQgUmF0ZXMgdnMuIFBvdmVydHkgUmF0ZXMgYnkgRWxlY3Rpb24gV2lubmluZyBQYXJ0eWAgYW5kIGBQZXJjZW50IG9mIFBvcHVsYXRpb24gdy8gSGlnaGVyIEVkdWNhdGlvbiB2cy4gVW5lbXBsb3ltZW50IFJhdGVzIGJ5IEVsZWN0aW9uIFdpbm5pbmcgUGFydHlgIG1vZGVscyBpbGx1c3RyYXRlZCBhIHBvb3IgZml0IHdpdGggdmVyeSBsb3cgUiBzcXVhcmVkIHZhbHVlcy4gIFRoZSBgUGVyY2VudCBvZiBQb3B1bGF0aW9uIHcvIEhpZ2hlciBFZHVjYXRpb24gdnMuIFBvdmVydHkgUmF0ZXMgYnkgRWxlY3Rpb24gV2lubmluZyBQYXJ0eWAgYWxzbyBpbGx1c3RyYXRlZCBhIHBvb3IgZml0IGJ1dCBoYWQgdGhlIGhpZ2hlc3QgciBzcXVhcmVkIHZhbHVlIGluZGljYXRpbmcgcmVkdWNlZCB2YXJpYW5jZSBpbiB0aGlzIG1vZGVsLiBObyBjbHVzdGVyaW5nIHdhcyBub3RlZCBhbG9uZyB0aGUgcGFydHkgdmFyaWFibGVzLiANCg0KT3ZlcmFsbCBhIGNvcnJlbGF0aW9uIGJldHdlZW4gdW5lbXBsb3ltZW50IHJhdGVzLCBwb3ZlcnR5IHJhdGVzLCBoaWdoZXIgZWR1Y2F0aW9uIHJhdGVzLCBhbmQgY291bnR5IHdpbm5pbmcgcGFydHkgd2FzIG5vdCBpbGx1c3RyYXRlZC4gDQoNCiMgQ29kZQ0KDQpgYGANCg0KIyNyZWFkIGluIHRoZSBlbGVjdGlvbiBkYXRhIGFzIGVsZWN0aW9uX3Jhdw0KDQplbGVjdGlvbl9yYXcgPC0gcmVhZC5jc3YoJ2h0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9ubGVwZXJhL3N0YTU1MS9yZWZzL2hlYWRzL21haW4vSFcwMS9kYXRhL2NvdW50eXByZXNpZGVudGlhbF9lbGVjdGlvbl8yMDAwLTIwMjAuY3N2JykNCg0KIyNjbGVhbiB0aGUgZWxlY3Rpb24gZGF0YSANCg0KZWxlY3Rpb24gPC0gZWxlY3Rpb25fcmF3ICU+JSANCiAgZ3JvdXBfYnkoY291bnR5X2ZpcHMpICU+JSAgICMjZ3JvdXAgYnkgY291bnR5IEZJUFMgY29kZQ0KICBhcnJhbmdlIChkZXNjKHllYXIpKSAlPiUgICAgIyNzb3J0IGJ5IGRlc2NlbmRpbmcgeWVhcg0KICBmaWx0ZXIgKHBhcnR5ID09ICJERU1PQ1JBVCIgfCBwYXJ0eSA9PSAiUkVQVUJMSUNBTiIpICU+JSAgICAjI2ZpbHRlciBmb3Igb25seSBkZW0gJiByZXANCiAgc3Vic2V0KCwgLWMoc3RhdGVfcG8sIG9mZmljZSwgdmVyc2lvbiwgbW9kZSkpICU+JSAgICMjcmVtb3ZlIHVubmVjZXNzYXJ5IGNvbHVtbnMNCiAgc2xpY2UgKDE6MikgJT4lICAgIyNwdWxsIHRvcCAyIHZhbHVlcyBmb3IgZWFjaCBncm91cCAoY291bnR5X2ZpcHMgc29ydGVkIGJ5IGRlc2MgeWVhcikgcHVsbGluZyBib3RoIGRlbSAmIHJlcCBmb3IgZWFjaCBjb3VudHkgYXQgbWF4IHllYXIgYXZhaWxhYmxlDQogIGFycmFuZ2UgKGRlc2MoY2FuZGlkYXRldm90ZXMpKSAlPiUgICAgIyNyZSBmaWx0ZXIgdG8gc29ydCBieSBncm91cCwgd2l0aCBoaWdoZXN0IGNhbmRpZGF0ZSB2b3RlcyBvbiB0b3ANCiAgc2xpY2UgKDEpICU+JSAgICAjI29ubHkga2VlcCB2YWx1ZSBmb3IgaGlnaGVzdCBjYW5kaWRhdGUgdm90ZXMgKHdpbm5lcikgcGVyIGNvdW50eQ0KICByZW5hbWUgKEZJUFMgPSBjb3VudHlfZmlwcykgICAjIyBzZXQgSUQgbmFtZSBmb3Igb3V0ZXIgam9pbg0KICANCkRUOjpkYXRhdGFibGUoZWxlY3Rpb24pDQoNCiMjIHJlYWQgaW4gdGhlIHVuZW1wbG95bWVudCBkYXRhIGFzIHVuZW1wbG95X3Jhdw0KDQp1bmVtcGxveV9yYXcgPC0gcmVhZC5jc3YoJ2h0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9ubGVwZXJhL3N0YTU1MS9yZWZzL2hlYWRzL21haW4vSFcwMS9kYXRhL1VuZW1wbG95bWVudC5jc3YnKQ0KDQojIyBjbGVhbiB0aGUgdW5lbXBsb3ltZW50IGRhdGENCnVuZW1wbG95IDwtIHVuZW1wbG95X3JhdyAlPiUgDQogIGZpbHRlciAoZ3JlcGwoJ1VuZW1wbG95bWVudCcsIEF0dHJpYnV0ZSkpICU+JSAgICN1c2UgZHBseXIgcGFja2FnZSB0byB1c2UgZmlsdGVyKGdyZXBsKCkpIHRvIGZpbHRlciBmb3Igc3RyaW5nIG9mIHRleHQgdG8gc2VsZWN0IG9ubHkgdGhlIHVuZW1wbG95bWVudCByYXRlIHZhbHVlcw0KICBtdXRhdGUgKHllYXIgPSBzdHJfc3ViKEF0dHJpYnV0ZSwgLTQpKSAlPiUgICMjY3JlYXRlIGEgbmV3IGNvbHVtbiB1c2luZyBtdXRhdGUgYW5kIHN0cmluZ3IgdG8gY3JlYXRlIGEgbmV3IGNvbHVtbiBmcm9tIHRoZSBsYXN0IDQgdmFsdWVzIG9mIHRoZSBhdHRyaWJ1dGUgY29sdW1uLCB0byBleHRyYWN0IHRoZSB5ZWFyIChzdHJfc3ViIC0+IHN0cmluZ3Jfc3Vic2V0KQ0KICBncm91cF9ieSAoRklQU19Db2RlKSAlPiUgICMjZ3JvdXAgYnkgRklQUyBjb2RlIGJlZm9yZSBzb3J0aW5nIHRvIGdldCBtYXggeWVhcg0KICBhcnJhbmdlIChkZXNjKHllYXIpKSAlPiUgICMjIHNvcnQgZGVzY2VuZGluZyB5ZWFyIHRvIHB1dCBtYXggYXZhaWxhYmxlIGF0IHRoZSB0b3ANCiAgc2xpY2UoMSkgJT4lICAgIyNzbGljZSB0b3AgdmFsdWUgdG8ga2VlcCBvbmx5IG1heCB5ZWFyIGZvciBlYWNoIEZJUFMgY29kZQ0KICBzdWJzZXQgKCwgYyhGSVBTX0NvZGUsIFZhbHVlKSkgJT4lICAgIyNyZW1vdmUgdW5uZWNlc3NhcnkgY29sdW1ucw0KICByZW5hbWUgKCJVbmVtcGxveW1lbnRfUmF0ZSAoJSkiID0gVmFsdWUsIEZJUFMgPSBGSVBTX0NvZGUpICAgICMjcmVuYW1lIGNvbHVtbiB0byByZWZsZWN0IHVuZW1wbG95bWVudCByYXRlICYgc2V0IElEIG5hbWUgZm9yIG91dGVyIGpvaW4NCg0KRFQ6OmRhdGF0YWJsZSh1bmVtcGxveSkNCg0KIyMgcmVhZCBpbiB0aGUgcG92ZXJ0eSBkYXRhIGFzIHBvdmVydHlfcmF3DQoNCnBvdmVydHlfcmF3IDwtIHJlYWQuY3N2KCdodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vbmxlcGVyYS9zdGE1NTEvcmVmcy9oZWFkcy9tYWluL0hXMDEvZGF0YS9Qb3ZlcnR5RXN0aW1hdGVzLmNzdicpDQoNCiMjY2xlYW4gdGhlIHBvdmVydHkgZGF0YQ0KcG92ZXJ0eSA8LSBwb3ZlcnR5X3JhdyAlPiUgDQogIGZpbHRlciAoQXR0cmlidXRlID09ICJQQ1RQT1ZBTExfMjAxOSIpICU+JSAgIyNGaWx0ZXIgZm9yIDIwMTkgcG92ZXJ0eSB2YWx1ZXMNCiAgc3Vic2V0ICgsIGMoRklQU3R4dCwgVmFsdWUpKSAlPiUgICMjcmVtb3ZlIHVubmVjY2Vzc2FyeSBjb2x1bW5zDQogIHJlbmFtZSAoIlBvdmVydHlfUmF0ZSAoJSkiID0gVmFsdWUsIEZJUFMgPSBGSVBTdHh0KSAgICMjcmVuYW1lIFZhbHVlIGNvbHVtbiB0byBQb3ZlcnR5X1JhdGUgKCUpIGFuZCBzZXQgSUQgbmFtZSBmb3Igb3V0ZXIgam9pbg0KDQpEVDo6ZGF0YXRhYmxlKHBvdmVydHkpDQoNCiMjIHJlYWQgaW4gdGhlIHVuZW1wbG95bWVudCBkYXRhIGFzIGVkdV9yYXcNCg0KZWR1X3JhdyA8LSByZWFkLmNzdignaHR0cHM6Ly9ubGVwZXJhLmdpdGh1Yi5pby9zdGE1NTEvSFcwMS9kYXRhL0VkdWNhdGlvbi5jc3YnLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQoNCg0KI2NsZWFuIGVkdWNhdGlvbiBkYXRhDQplZHUgPC0gZWR1X3JhdyAlPiUgDQogIHN1YnNldCAoLCBjKEZJUFMuQ29kZSwgTGVzcy50aGFuLmEuaGlnaC5zY2hvb2wuZGlwbG9tYS4uMjAxNS4xOSwgSGlnaC5zY2hvb2wuZGlwbG9tYS5vbmx5Li4yMDE1LjE5LCBTb21lLmNvbGxlZ2Uub3IuYXNzb2NpYXRlLnMuZGVncmVlLi4yMDE1LjE5LAlCYWNoZWxvci5zLmRlZ3JlZS5vci5oaWdoZXIuLjIwMTUuMTkpKSAlPiUgICMjcmVtb3ZlIGlycmVsZXZhbnQgY29sdW1ucw0KICByZW5hbWUgKCAiTm9fSFMiID0gTGVzcy50aGFuLmEuaGlnaC5zY2hvb2wuZGlwbG9tYS4uMjAxNS4xOSwgIkhTIiA9IEhpZ2guc2Nob29sLmRpcGxvbWEub25seS4uMjAxNS4xOSwgIkFTX1NvbWVDb2wiID0gU29tZS5jb2xsZWdlLm9yLmFzc29jaWF0ZS5zLmRlZ3JlZS4uMjAxNS4xOSwJIkJTX01vcmUiID0gQmFjaGVsb3Iucy5kZWdyZWUub3IuaGlnaGVyLi4yMDE1LjE5LCBGSVBTID0gRklQUy5Db2RlKSAgIyNyZW5hbWUgZm9yIGVhc2UgYW5kIHNldCBJRCBuYW1lIGZvciBvdXRlciBqb2luDQplZHUkTm9fSFMgPSBnc3ViKCcsJywgJycsIGVkdSROb19IUykgIyNyZW1vdmUgY29tbWFzIGZyb20gbnVtYmVyIHdpdGggY29tbWFzIHNhdmVkIGFzIGNoYXJhY2h0ZXJzDQplZHUkSFMgPSBnc3ViKCcsJywgJycsIGVkdSRIUykNCmVkdSRBU19Tb21lQ29sID0gZ3N1YignLCcsICcnLCBlZHUkQVNfU29tZUNvbCkNCmVkdSRCU19Nb3JlID0gZ3N1YignLCcsICcnLCBlZHUkQlNfTW9yZSkNCmVkdSROb19IUyA9IGFzLm51bWVyaWMoZWR1JE5vX0hTKSAgIyN0cmFuc2Zvcm0gdG8gbnVtZXJpYyB0byBhZ2dyZWdhdGUNCmVkdSRIUyA9IGFzLm51bWVyaWMoZWR1JEhTKQ0KZWR1JEFTX1NvbWVDb2wgPSBhcy5udW1lcmljKGVkdSRBU19Tb21lQ29sKQ0KZWR1JEJTX01vcmUgPSBhcy5udW1lcmljKGVkdSRCU19Nb3JlKQ0KICANCkRUOjpkYXRhdGFibGUoZWR1KQ0KDQojI21lcmdlIGVsZWN0aW9uIGRhdGEgJiBlZHVjYXRpb24gZGF0YSBhcyBlbGVjdGlvbi5lZHVjYXRpb24gDQplbGVjdGlvbi5lZHVjYXRpb24gPC0gZnVsbF9qb2luICgNCiAgeCA9IGVsZWN0aW9uLA0KICB5ID0gZWR1LA0KICBieSA9ICJGSVBTIiwNCiAga2VlcCA9IEZBTFNFDQopDQoNCg0KIyNtZXJnZSBlbGVjdGlvbi5lZHVjYXRpb24gJiBwb3ZlcnR5IGRhdGEgYXMgZWxlY3Rpb24uZWR1Y2F0aW9uLnBvdmVydHkNCmVsZWN0aW9uLmVkdWNhdGlvbi5wb3ZlcnR5IDwtIGZ1bGxfam9pbigNCiAgeCA9IGVsZWN0aW9uLmVkdWNhdGlvbiwNCiAgeSA9IHBvdmVydHksDQogIGJ5ID0gIkZJUFMiLA0KICBrZWVwID0gRkFMU0UNCikNCg0KIyNtZXJnZSBlbGVjdGlvbi5lZHVjYXRpb24ucG92ZXJ0eSAmIHVuZW1wbG95bWVudCBkYXRhIGFzIGFsbC5kYXRhDQphbGwuZGF0YSA8LSBmdWxsX2pvaW4gKA0KICB4ID0gZWxlY3Rpb24uZWR1Y2F0aW9uLnBvdmVydHksDQogIHkgPSB1bmVtcGxveSwNCiAgYnkgPSAiRklQUyIsDQogIGtlZXAgPSBGQUxTRQ0KKQ0KDQphbGwuZGF0YSA8LSBhbGwuZGF0YSAgJT4lIA0KICBmaWx0ZXIoRklQUyAhPSAwKSAlPiUgIyNmaWx0ZXIgb3V0IHZhbHVlcyB3aXRoIG5vIGFzc29jaWF0ZWQgY291bnR5IG9yIHN0YXRlIG5hbWUNCiAgZmlsdGVyKEZJUFMgIT0gMTAwMCkgJT4lIA0KICBtdXRhdGUgKEhpZ2hlcl9FZF9QZXJjZW50ID0gKCgoYEFTX1NvbWVDb2xgICsgYEJTX01vcmVgKS8oYE5vX0hTYCsgYEhTYCArIGBBU19Tb21lQ29sYCArIGBCU19Nb3JlYCkpKjEwMCkpICAjIyUgb2YgcG9wIHdpdGggaGlnaGVyIGVkLg0KDQpjb3VudHlfZGF0YV9yYXcgPC0gc2Y6OnJlYWRfc2YoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9wbG90bHkvZGF0YXNldHMvbWFzdGVyL2dlb2pzb24tY291bnRpZXMtZmlwcy5qc29uIikgIyNwdWxsIGluIG1hcCBvZiBGSVBTIGNvZGVzIA0KDQpGSVBTY29udmVydF9yYXcgPC0gc2Y6OnJlYWRfc2YoImh0dHBzOi8vbmxlcGVyYS5naXRodWIuaW8vc3RhNTUxL0hXMDEvZGF0YS9maXBzMmdlb2NvZGUuY3N2IikgIyNwdWxsIGluIGtleSBvZiBGSVBTIGNvZGVzIHRvIGxhdC9sb25nDQoNCmNvdW50eV9kYXRhIDwtIGNvdW50eV9kYXRhX3JhdyAlPiUgICNjbGVhbiBjb3VudHkgZGF0YSB0byBsaXN0IEZJUFMgYXMgbnVtZXJpYyAmIG1hdGNoIG5hbWUgdG8ga2V5IGZvciBqb2luDQogIG11dGF0ZSAoaWQgPSBhcy5udW1lcmljKGFzLmNoYXJhY3RlcihpZCkpKSAlPiUgDQogIHJlbmFtZSAoRklQUyA9IGlkKQ0KDQpGSVBTY29udmVydCA8LSBGSVBTY29udmVydF9yYXcgJT4lICANCiAgbXV0YXRlIChmaXBzID0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoZmlwcykpLCBsb24gPSBhcy5udW1lcmljKGFzLmNoYXJhY3Rlcihsb24pKSwgbGF0ID0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIobGF0KSkpICU+JSANCiAgcmVuYW1lIChGSVBTID0gZmlwcywgTG9uZ2l0dWRlID0gbG9uLCBMYXRpdHVkZSA9IGxhdCkNCg0KYWxsLmRhdGEuam9pbiA8LSBmdWxsX2pvaW4oDQogIHggPSBhbGwuZGF0YSwNCiAgeSA9IEZJUFNjb252ZXJ0LA0KICBieSA9ICJGSVBTIiwNCiAga2VlcCA9IEZBTFNFDQopICU+JSANCiAgdW5ncm91cCgpDQoNCmBgYA0KDQo=