Getting Data
Data Prep
Pull all agency names that exist, then use agency numbers associated
with MUNI types to pull only the muni_agency_names
object.
There are 946 unique taxing agencies that existed in 2021.
# has EAV values, extensions by agency_num
agency_dt <- DBI::dbGetQuery(
ptaxsim_db_conn,
"SELECT *
FROM agency
WHERE year = 2021
"
)
# grabs all unique muni names. Would be needed if creating a loop for calculating all munis
# municipality names and their agency number
muni_agency_names <- DBI::dbGetQuery(
ptaxsim_db_conn,
"SELECT DISTINCT agency_num, agency_name, minor_type
FROM agency_info
WHERE minor_type = 'MUNI'
OR agency_num = '020060000'
"
)
muni_agency_names <- muni_agency_names %>%
mutate(first6 = str_sub(agency_num,1,6),
first5 = str_sub(agency_num,1,5)) %>%
select(-minor_type)
#Makes a list of ALL taxing agencies, including TIFs, SSAs, etc.
# all agency names, numbers, and types
# includes TIF and non-TIF agencies
all_taxing_agencies <- DBI::dbGetQuery(
ptaxsim_db_conn,
"SELECT agency_num, agency_name, major_type, minor_type
FROM agency_info
"
) %>%
mutate(first6 = str_sub(agency_num,1,6),
first5 = str_sub(agency_num,1,5))
muni_agency_nums<- all_taxing_agencies %>%
filter(minor_type %in% c("MUNI") |
agency_num == "020060000") %>%
select(agency_num)
muni_tax_codes <- DBI::dbGetQuery(
ptaxsim_db_conn,
glue_sql("
SELECT*
FROM tax_code
WHERE agency_num IN ({muni_agency_names$agency_num*})
AND year = 2021
",
.con = ptaxsim_db_conn
)
)# %>% select(-agency_rate)
# Agency number and agency name for all TIFs
TIF_agencies <- DBI::dbGetQuery(
ptaxsim_db_conn,
"SELECT DISTINCT agency_num, agency_name, major_type, minor_type
FROM agency_info
WHERE minor_type = 'TIF'
"
)
unique_tif_taxcodes <- DBI::dbGetQuery(
ptaxsim_db_conn,
glue_sql("
SELECT DISTINCT tax_code_num
FROM tax_code
WHERE agency_num IN ({TIF_agencies$agency_num*})
AND year = 2021
",
.con = ptaxsim_db_conn
)
)
## Read in summarized tax code level data for exemptions and taxbills.
taxbills_by_Class_per_TC <- #read_csv("taxbills_inMunis_perTC.csv") %>%
read_csv("2_Summed_Bills_by_Taxcode_and_Class.csv") %>%
mutate(tax_code = as.character(tax_code))
# get rid of rpm variables, tax_amt_exe,pre and post exemption variables,
exemptions_by_class_per_TC <- #read_csv("all_exemptions_by_TC.csv") %>%
read_csv("3_Exemptions_Details_output-ClassTaxcodeExemps.csv") %>%
mutate(tax_code_num = as.character(tax_code_num))
tif_distrib <- DBI::dbGetQuery(
ptaxsim_db_conn,
glue_sql("
SELECT *
FROM tif_distribution
WHERE tax_code_num IN ({muni_tax_codes$tax_code_num*})
AND year = 2021
",
.con = ptaxsim_db_conn
)
) %>% mutate(tax_code_num = as.character(tax_code_num))
all_taxing_agencies <- all_taxing_agencies %>%
left_join(muni_agency_names, by = c("first5", "first6")) %>%
rename(muni_name = agency_name.y,
muni_num = agency_num.y,
agency_name = agency_name.x,
agency_num = agency_num.x)
## Add agency names since those weren't included originally in the table:
# all_taxing_agencies <- all_taxing_agencies %>%
# left_join(muni_agency_names, by = c("first5", "first6")) %>%
# rename(muni_name = agency_name.y,
# muni_num = agency_num.y,
# agency_name = agency_name.x,
# agency_num = agency_num.x)
#
# combine taxing agency names and agency type to data table that has eav and extension values
agency_data <- right_join(agency_dt, all_taxing_agencies) %>%
# get rid of unneeded columns to make table outputs smaller
select(-c(cty_dupage_eav:cty_livingston_eav, lim_numerator, lim_denominator)) %>% # drop some of the unused variables
arrange(agency_num)
This table is used for the municipality levy in later
calculations.
agency_dt has all taxing agencies (but not TIFs) that
existed each year and includes their total taxable base (cty_cook_eav),
their levy, taxing rate, binary variables for if a municipality is home
rule or not, as well as many other variables. Also currently doesn’t
have agency_names to go with the agency numbers. That will be merged in
shortly.
There are 1,878 taxing agencies. When grouped by minor_type, there
are 133 muni agencies, 639 tif agencies, 30 townships, etc.
Everything depends on the tax codes.
Using the agency numbers for each municipality, I pull all tax codes
that have an agency_num included in the muni_agency_names object. By
narrowing the agencies down to just Municipality types, this prevents
duplicate tax_codes from being pulled.
There are 3774 tax codes within Cook County that are taxed by
Municipalities. There are 4228 unique tax codes in Cook County in
2021.
Drop municipalities where most of the EAV is outside of Cook
County:
cross_county_lines <- c("030440000",
"030585000", "030890000", "030320000", "031280000","030080000", "030560000", "031120000", "030280000", "030340000","030150000","030050000", "030180000","030500000","031210000"
)
# Frankfort, Homer Glenn, Oak Brook are below 1% in Cook County
# East Dundee, University Park, Bensenville, Hinsdale, Roeelle, Deerfield are below 15% in Cook County
# Above 50%: buffalo grove, bertlette, burr ridge, hanover park, steger,
# tinley park, barrington hills and barrington, and park forest
# ALL border crossers:
#cross_county_lines <- c("030030000", "030040000", "030050000", "030080000","030150000","030180000", "030280000", "030320000","030340000", "030440000","030500000", "030560000", "030585000", "030890000", "031000000","031120000","031210000","031270000", "031280000")
# Municipalities | Triad | agency_num
#
# CITY OF ELGIN North 30340000
# VILLAGE OF BARRINGTON North 30030000
# VILLAGE OF BARRINGTON HILLS North 30040000
# VILLAGE OF BARTLETT North 30050000
# VILLAGE OF BENSENVILLE NA 30080000
# VILLAGE OF BUFFALO GROVE North 30150000
# VILLAGE OF BURR RIDGE South 30180000
# VILLAGE OF DEERFIELD NA 30280000
# VILLAGE OF EAST DUNDEE NA 30320000
# VILLAGE OF FRANKFORT NA 30440000
# VILLAGE OF HANOVER PARK North 30500000
# VILLAGE OF HINSDALE South 30560000
# VILLAGE OF HOMER GLEN NA 30585000
# VILLAGE OF OAK BROOK NA 30890000
# VILLAGE OF PARK FOREST South 31000000
# VILLAGE OF ROSELLE North 31120000
# VILLAGE OF STEGER South 31210000
# VILLAGE OF TINLEY PARK South 31270000
# VILLAGE OF UNIVERSITY PARK NA 31280000
Proportion of Residential Land in
Municipalities
using the pin data from ptaxsim, I calculate the eav of all
properties, exempt EAV, the current taxbase, and taxbase if there were
not exemptions
exempt EAV (summed from all exemption types)
current taxbase (using the tif_distrib table and
percent of taxcode rev that goes to the tif). If a taxcode is a TIF
taxcode, then do (EAV-exempt EAV) * (1-%rev that goes to TIF). If the
tax code is not a TIF tax code, then use the EAV-exempt EAV.
tax base without exemptions: If a taxcode is a TIF taxcode, then
do EAV * (1-%rev that goes to TIF). If the tax code is not a TIF tax
code, then use the eav
Joining problem: in muni_agency_names, Cicero is called
“TOWN CICERO”, in map shapefile it is called “CITY OF CICERO”.
class_dict <- read_csv("class_dict_expanded.csv")
# use exemptions in tax codes to summarize EAV.
# More accurate that calculating it from revenue collected.tax rate in tax bill data
exemptions_by_class_per_TC <- read_csv("3_Exemptions_Details_output-ClassTaxcodeExemps.csv") %>%
filter(class_code != "0") %>%
left_join(class_dict) %>%
mutate(tax_code_num = as.character(tax_code_num)) %>%
left_join(muni_tax_codes) %>%
full_join(muni_agency_names) %>%
left_join(nicknames, by = c("agency_name" = "agency_name")) %>%
filter(!agency_num %in% cross_county_lines) %>%
# merge with TIF distrib table to calculate the percent of the EAV that goes to the TIF vs the district
left_join(tif_distrib, by=c("tax_code_num", "year", "tax_code_rate")) %>%
mutate(exempt_EAV = (exe_homeowner + exe_senior + exe_freeze + exe_longtime_homeowner +
exe_disabled + exe_vet_returning + exe_vet_dis + exe_abate) ,
in_TIF = ifelse(tax_code_num %in% unique_tif_taxcodes$tax_code_num, 1, 0),
tax_base_current = ifelse(in_TIF==1, (eav-exempt_EAV)*(1-tax_code_distribution_pct/100), eav-exempt_EAV),
tax_base_noexemps = ifelse(in_TIF==1, (eav)*(1-tax_code_distribution_pct/100), eav),
ResidentialProps = ifelse(major_class_code %in% c("2", "3", "9"), "Residential", "Commercial"))
#,
#
# PropType = case_when(
# major_class_code %in% c("3","9") ~ "Multi-Family",
# major_class_code == "2" ~ "Single-Family",
# TRUE~ "Commercial-Industrial")
Exemptions within each municipality:
Percent Residential is the Residential EAV outside of TIFs /
Municipality EAV outside of TIFs.
grouped_exemptions <- exemptions_by_class_per_TC %>%
# group_by(agency_name, major_class_code, major_class_type, ResidentialProps, PropType) %>%
group_by(clean_name, ResidentialProps, agency_name, agency_num.x) %>%
summarize(eav = sum(eav),
exempt_EAV = sum(exempt_EAV, exe_abate, na.rm=TRUE),
tax_base_current = sum(tax_base_current, na.rm=TRUE),
tax_base_noexemps = sum(tax_base_noexemps, na.rm=TRUE)) %>% ungroup() %>% select(clean_name, eav, exempt_EAV, everything())
grouped_exemptions
# calculate totals with ONLY EAV outside of TIFs
muni_eav <- grouped_exemptions %>%
group_by(clean_name, agency_name, agency_num.x) %>%
summarize(muni_EAV_includesTIF = sum(eav), # all EAV in the municipality that exists
muni_tax_base_current=sum(tax_base_current), # taxable EAV based on current exemptions
muni_tax_base_noexemps = sum(tax_base_noexemps)) %>% # taxable EAV pre-exemptions
ungroup()
perc_residential <- full_join(grouped_exemptions, muni_eav) %>%
filter(ResidentialProps == "Residential") %>%
mutate(percent_residential = eav / muni_EAV_includesTIF)# %>% select()
# in this stage, Bensenville, East Dundee, and Homer Glen were dropped. This is fine because I was going to drop them later anyways. They don't have residential EAV within Cook County.
perc_residential
library(ggpattern)
Residential (Only Class 2)
In Cook County there is $118,936,418,533 in Class 2 Residential
Property EAV. Note: Class 2 properties include single-family detached
homes, condos, and some rental buildings.
# Class 2 only
class2_perc <- exemptions_by_class_per_TC %>%
filter(major_class_code == 2) %>%
group_by(clean_name, major_class_code, agency_name, agency_num.x) %>%
summarize(eav = sum(eav),
exempt_EAV = sum(exempt_EAV, exe_abate, na.rm=TRUE),
tax_base_current = sum(tax_base_current, na.rm=TRUE),
tax_base_noexemps = sum(tax_base_noexemps, na.rm=TRUE)) %>%
left_join(muni_eav) %>%
mutate(perc_class2_totalEAV = eav / muni_EAV_includesTIF) %>%
mutate(agency_name = ifelse(agency_name == "TOWN CICERO", "CITY OF CICERO", agency_name) )
class2_perc %>%
full_join(muni_shp, by = c("agency_name" = "AGENCY_DESC")) %>%
ggplot(aes(fill = perc_class2_totalEAV)) +
geom_sf(aes(geometry = geometry), color = "black") +
labs(title = "Class 2 Property EAV / Total EAV in Municipality",
caption = "") +
theme_void() +
theme(axis.ticks = element_blank(), axis.text = element_blank())+# +#+
scale_fill_steps2(
high = "darkblue", low = "black",
midpoint = median(class2_perc$perc_class2_totalEAV),
# breaks = breaks_sd, # tried to do breaks based on standard deviation but map does that in an easier way by setting the midpoint.
na.value = "white",
nice.breaks = FALSE,
show.limits=TRUE,
name = "% Residential",
labels = scales::percent)
Cook_layer <- ggplot(data = cook_shp,aes(geometry = geometry)) +
geom_sf_pattern() + theme_void()
class2_perc %>%
full_join(muni_shp, by = c("agency_name" = "AGENCY_DESC")) %>%
ggplot() +
geom_sf_pattern(data = cook_shp, aes(geometry = geometry), pattern_alpha = 0.1,
pattern_scale = .5,
pattern_angle = 45, pattern_fill = NA,
#pattern_density = .5,
pattern_spacing = .02
) +
geom_sf(aes(geometry = geometry, fill = perc_class2_totalEAV), color = "black") +
labs(title = "Class 2 Property EAV / Total EAV in Municipality",
caption = "") +
theme_void() +
theme(axis.ticks = element_blank(), axis.text = element_blank())+# +#+
scale_fill_steps2(
high = "darkblue", low = "maroon",
midpoint = median(class2_perc$perc_class2_totalEAV),
# breaks = breaks_sd, # tried to do breaks based on standard deviation but map does that in an easier way by setting the midpoint.
na.value = NA,
nice.breaks = FALSE,
show.limits=TRUE,
name = "% Residential",
labels = scales::percent)

Percent of Class 2 EAV that is tax exempt: Exempt EAV /
Residential EAV
exemptions_to_class2EAV_ratios <- class2_perc %>%
mutate(exemptEAV_pctof_resEAV = exempt_EAV/eav,
nontif_ratio = exempt_EAV / tax_base_noexemps) %>%
select(agency_name, clean_name, exemptEAV_pctof_resEAV, nontif_ratio) %>%
arrange(nontif_ratio)
exemptions_to_class2EAV_ratios %>%
mutate(agency_name = ifelse(agency_name == "TOWN CICERO", "CITY OF CICERO", agency_name) ) %>%
left_join(muni_shp, by = c("agency_name" = "AGENCY_DESC")) %>%
ggplot(aes(fill = exemptEAV_pctof_resEAV)) +
geom_sf(aes(geometry = geometry), color = "black") + theme_void()+
labs(title = "Exemptions / Residential EAV (in and out of TIFs)") +
theme_void() +
theme(axis.ticks = element_blank(), axis.text = element_blank())+
scale_fill_steps2(high = "darkblue", low = "black",
# limits = c(0,.8),
n.breaks = 7, show.limits=TRUE,
nice.breaks = FALSE,
midpoint = median(exemptions_to_class2EAV_ratios$exemptEAV_pctof_resEAV),
name = "% Residential EAV \nthat is exempt", label = scales::percent)
exemptions_to_class2EAV_ratios %>%
mutate(agency_name = ifelse(agency_name == "TOWN CICERO", "CITY OF CICERO", agency_name) ) %>%
left_join(muni_shp, by = c("agency_name" = "AGENCY_DESC")) %>%
ggplot(aes(fill = nontif_ratio)) +
geom_sf(aes(geometry = geometry), color = "black") + theme_void()+
labs(title = "Non-TIF EAV only: Homestead Exemptions / Residential EAV", caption = "Village of Phoenix skews graph. Dropped in map below") +
theme_void() +
theme(axis.ticks = element_blank(), axis.text = element_blank())+
scale_fill_steps2(high = "darkblue", low = "black",
#colors = c("white", "darkblue"),
# limits = c(0),
midpoint = median(exemptions_to_class2EAV_ratios$nontif_ratio),
n.breaks = 7,
show.limits=TRUE,
name = "% Residential EAV \nthat is exempt", label = scales::percent) +
labs( caption = "Median value is 20.85% ")
exemptions_to_class2EAV_ratios %>% filter(nontif_ratio<.6) %>%
mutate(agency_name = ifelse(agency_name == "TOWN CICERO", "CITY OF CICERO", agency_name) ) %>%
left_join(muni_shp, by = c("agency_name" = "AGENCY_DESC")) %>%
ggplot(aes(fill = nontif_ratio)) +
geom_sf(aes(geometry = geometry), color = "black") + theme_void()+
labs(title = "Percent of Residential EAV that is Tax Exempt",
subtitle = "% of Non-TIF Residential EAV only: \nHomestead Exemptions / Residential EAV",
caption = "") +
theme_void() +
theme(axis.ticks = element_blank(), axis.text = element_blank())+
scale_fill_steps2(high = "darkblue", low = "black",
# colors = c("white", "darkblue"),
limits = c(0,.4),
midpoint = median(exemptions_to_class2EAV_ratios$nontif_ratio),
n.breaks = 7, show.limits=TRUE,
name = "% Residential EAV \nthat is tax exempt", label = scales::percent)
Residential (Class 2, 3, & 9)
The median amount of EAV from residentical parcels is 70%.
variable <- perc_residential$percent_residential
breaks_sd = c(
(median(variable)-2.5*sd(variable)),
(median(variable)-1.5*sd(variable)),
median(variable)-.5*sd(variable),
median(variable),
median(variable)+.5*sd(variable),
median(variable)+1.5*sd(variable),
median(variable)+2.5*sd(variable))
# class 2, 3, 9 combined
perc_residential %>%
group_by(ResidentialProps)%>%
mutate(agency_name = ifelse(agency_name == "TOWN CICERO", "CITY OF CICERO", agency_name) ) %>%
left_join(muni_shp, by = c("agency_name" = "AGENCY_DESC")) %>%
ggplot(aes(fill = percent_residential)) +
geom_sf(aes(geometry = geometry), color = "black") +
labs(title = "Residential EAV / Total EAV", caption = "The median municipality has 70.4% of its EAV from Residential Class 2, 3, & 9 Properties") +
theme_classic() +
theme(axis.ticks = element_blank(), axis.text = element_blank())+# +#+
scale_fill_steps2(
high = "darkblue", low = "black", # guide = "legend",
midpoint = median(perc_residential$percent_residential),
breaks = breaks_sd,
# n.breaks = 6,
show.limits=TRUE,
name = "% Residential",
labels = scales::percent)

exemptions_to_resEAV_ratios <- grouped_exemptions %>%
filter(ResidentialProps == "Residential") %>%
mutate(exemptEAV_pctof_resEAV = exempt_EAV/eav,
nontif_ratio = exempt_EAV / tax_base_noexemps) %>%
select(agency_name, clean_name, exemptEAV_pctof_resEAV, nontif_ratio) %>%
arrange(nontif_ratio)
exemptions_to_resEAV_ratios %>%
mutate(agency_name = ifelse(agency_name == "TOWN CICERO", "CITY OF CICERO", agency_name) ) %>%
left_join(muni_shp, by = c("agency_name" = "AGENCY_DESC")) %>%
ggplot(aes(fill = exemptEAV_pctof_resEAV)) +
geom_sf(aes(geometry = geometry), color = "black") + theme_void()+
labs(title = "Exemptions / Residential EAV (in and out of TIFs)") +
theme_classic() +
theme(axis.ticks = element_blank(), axis.text = element_blank())+
scale_fill_steps2(high = "maroon", low = "black",
# limits = c(0,.8),
n.breaks = 7, show.limits=TRUE,
nice.breaks = FALSE,
midpoint = median(exemptions_to_resEAV_ratios$exemptEAV_pctof_resEAV),
name = "% Residential EAV \nthat is exempt", label = scales::percent) + labs(caption = "Median value is 19.5%.
Nearly 20% of Residential EAV is tax exempt in the median municipality. ")

exemptions_to_resEAV_ratios %>%
mutate(agency_name = ifelse(agency_name == "TOWN CICERO", "CITY OF CICERO", agency_name) ) %>%
left_join(muni_shp, by = c("agency_name" = "AGENCY_DESC")) %>%
ggplot(aes(fill = nontif_ratio)) +
geom_sf(aes(geometry = geometry), color = "black") + theme_void()+
labs(title = "Non-TIF EAV only: Homestead Exemptions / Residential EAV", caption = "Village of Phoenix skews graph. Dropped in map below") +
theme_void() +
theme(axis.ticks = element_blank(), axis.text = element_blank())+
scale_fill_steps2(high = "maroon", low = "black",
#colors = c("white", "darkblue"),
limits = c(0,.8),
midpoint = median(exemptions_to_resEAV_ratios$nontif_ratio),
n.breaks = 7, show.limits=TRUE,
name = "% Residential EAV \nthat is exempt", label = scales::percent) + labs( caption = "Median value is 19.77% ")

exemptions_to_resEAV_ratios %>%
filter(nontif_ratio<.5) %>%
mutate(agency_name = ifelse(agency_name == "TOWN CICERO", "CITY OF CICERO", agency_name) ) %>%
left_join(muni_shp, by = c("agency_name" = "AGENCY_DESC")) %>%
ggplot(aes(fill = nontif_ratio)) +
geom_sf(aes(geometry = geometry), color = "black") + theme_void()+
labs(title = "Percent of Residential EAV that is Tax Exempt",
subtitle = "% of Non-TIF Residential EAV only: \nHomestead Exemptions / Residential EAV",
caption = "Residential includes Class 2, 3, and 9.
Drops Village of Phoenix because it skews map colors (78% of their residential EAV is tax exempt).
Median municipality can not get tax revenue from 19.77% of their residential EAV due to exemptions.") +
theme_void() +
theme(axis.ticks = element_blank(), axis.text = element_blank())+
scale_fill_steps2(high = "maroon", low = "black",
# colors = c("white", "darkblue"),
# limits = c(0,.4),
midpoint = median(exemptions_to_resEAV_ratios$nontif_ratio),
# n.breaks = 7,
show.limits=TRUE,
name = "% Residential EAV \nthat is exempt", label = scales::percent)

exemptions_to_resEAV_ratios %>% arrange(desc(nontif_ratio))
Residential (Owner Occupied)
Municipality total EAV excludes TIF increment EAV. Frozen base EAV is
included.
grouped_exemptions <- exemptions_by_class_per_TC %>%
left_join(class_dict) %>%
group_by(clean_name, Alea_cat, agency_name, agency_num.x) %>%
summarize(eav = sum(eav),
exempt_EAV = sum(exempt_EAV, exe_abate, na.rm=TRUE),
tax_base_current = sum(tax_base_current, na.rm=TRUE),
tax_base_noexemps = sum(tax_base_noexemps, na.rm=TRUE)) %>% ungroup() %>%
select(clean_name, eav, exempt_EAV, everything())
grouped_exemptions
# calculate totals with ONLY EAV outside of TIFs
muni_eav <- grouped_exemptions %>%
group_by(clean_name, agency_name, agency_num.x) %>%
summarize(muni_EAV_includesTIF = sum(eav), # all EAV in the municipality that exists
muni_tax_base_current=sum(tax_base_current), # taxable EAV based on current exemptions
muni_tax_base_noexemps = sum(tax_base_noexemps)) %>% # taxable EAV pre-exemptions
ungroup()
perc_residential <- full_join(grouped_exemptions, muni_eav) %>%
# filter(ResidentialProps == "Residential") %>%
filter(Alea_cat == "Owner Occupied") %>%
mutate(percent_owned = eav / muni_EAV_includesTIF)# %>% select()
# in this stage, Bensenville, East Dundee, and Homer Glen were dropped. This is fine because I was going to drop them later anyways. They don't have residential EAV within Cook County.
perc_residential
The median municipality has 63% of their EAV in the form of owner
occupied properties.
While this is very similar to the percentage calculated using only
Class 2 residential properties. There are some municipalities that
experience large changes due to the change in categorization of Owner
occupied vs rental compared to Class 2 or multi-family vs single-family
properties.
variable <- perc_residential$percent_owned
breaks_sd = c(
(median(variable)-2.5*sd(variable)),
(median(variable)-1.5*sd(variable)),
median(variable)-.5*sd(variable),
median(variable),
median(variable)+.5*sd(variable),
median(variable)+1.5*sd(variable),
median(variable)+2.5*sd(variable))
perc_residential %>%
filter(Alea_cat == "Owner Occupied")%>%
mutate(agency_name = ifelse(agency_name == "TOWN CICERO", "CITY OF CICERO", agency_name) ) %>%
full_join(muni_shp, by = c("agency_name" = "AGENCY_DESC")) %>%
ggplot(aes(fill = percent_owned)) +
geom_sf(aes(geometry = geometry), color = "black") +
labs(title = "Owner Occupied EAV / Total EAV",
# caption = "The median municipality has 70.4% of its EAV from Residential Class 2, 3, & 9 Properties"
) +
theme_classic() +
theme(axis.ticks = element_blank(), axis.text = element_blank()) +
scale_fill_steps2(
high = "darkblue", low = "black", # guide = "legend",
midpoint = median(perc_residential$percent_owned, na.rm = TRUE),
#breaks = breaks_sd,
# n.breaks = 6,
show.limits=TRUE,
name = "% Owner Occupied",
na.value = "beige",
labels = scales::percent
)

exemptions_to_resEAV_ratios <- grouped_exemptions %>%
mutate(ResidentialProps = ifelse(Alea_cat %in% c("Rental", "Owner Occupied", "Other Residential"), "Residential", "Non-residential")) %>%
filter(ResidentialProps == "Residential") %>%
mutate(exemptEAV_pctof_resEAV = exempt_EAV/eav,
nontif_ratio = exempt_EAV / tax_base_noexemps) %>%
select(agency_name, clean_name, exemptEAV_pctof_resEAV, nontif_ratio) %>%
arrange(nontif_ratio)
exemptions_to_resEAV_ratios %>%
mutate(agency_name = ifelse(agency_name == "TOWN CICERO", "CITY OF CICERO", agency_name) ) %>%
left_join(muni_shp, by = c("agency_name" = "AGENCY_DESC")) %>%
ggplot(aes(fill = exemptEAV_pctof_resEAV)) +
geom_sf(aes(geometry = geometry), color = "black") + theme_void()+
labs(title = "Exemptions / Residential EAV (in and out of TIFs)") +
theme_classic() +
theme(axis.ticks = element_blank(), axis.text = element_blank())+
scale_fill_steps2(high = "maroon", low = "black",
n.breaks = 7, show.limits=TRUE,
nice.breaks = FALSE,
midpoint = median(exemptions_to_resEAV_ratios$exemptEAV_pctof_resEAV),
name = "% Residential EAV \nthat is exempt", label = scales::percent) + labs(caption = "Median value is 19.18%.
Nearly 19.2% of Owner Occuppied EAV is tax exempt in the median municipality. ")

exemptions_to_resEAV_ratios %>%
filter(nontif_ratio<.5) %>%
mutate(agency_name = ifelse(agency_name == "TOWN CICERO", "CITY OF CICERO", agency_name) ) %>%
left_join(muni_shp, by = c("agency_name" = "AGENCY_DESC")) %>%
ggplot(aes(fill = nontif_ratio)) +
geom_sf(aes(geometry = geometry), color = "black") + theme_void()+
labs(title = "Percent of Owner Occupied EAV that is Tax Exempt",
subtitle = "% of Non-TIF Owner Occupied EAV only: \nHomestead Exemptions / Residential EAV",
caption = "Drops Village of Phoenix because it skews map colors (78% of their residential EAV is tax exempt).
Median municipality can not get tax revenue from 19.29% of their residential EAV due to exemptions.") +
theme_void() +
theme(axis.ticks = element_blank(), axis.text = element_blank())+
scale_fill_steps2(high = "maroon", low = "black",
midpoint = median(exemptions_to_resEAV_ratios$nontif_ratio),
show.limits=TRUE,
name = "% Owner Occupied EAV \nthat is exempt", label = scales::percent)

exemptions_to_resEAV_ratios %>% arrange(desc(nontif_ratio))
Taxable Base and Muni Land Use
Tax base in the tables above are the total EAV outside of TIF
areas.
TC_bills_current <- read_csv("2_Summed_Bills_by_Taxcode_and_Class.csv") %>%
filter(class != "0") %>%
mutate(tax_code = as.character(tax_code),
class = as.character(class))
class_dict$class_code <- as.character(class_dict$class_code)
taxcodes_current <- full_join(TC_bills_current, muni_tax_codes,
by = c("tax_code" = "tax_code_num"))
Current_Taxrates <- taxcodes_current %>%
left_join(muni_agency_names) %>%
left_join(nicknames, by = c("agency_name" = "agency_name")) %>%
filter(!agency_num %in% cross_county_lines) %>%
group_by(clean_name, agency_name) %>%
summarize(MuniLevy = sum(final_tax_to_dist, na.rm = TRUE), # amount billed by munis with current exemptions in place
nonTIF_EAV_post_exemps = sum(final_tax_to_dist/(tax_code_rate/100), na.rm = TRUE),
TIF_increment_EAV = sum(final_tax_to_tif/(tax_code_rate/100), na.rm=TRUE),
Exempt_EAV = sum(tax_amt_exe/(tax_code_rate/100), na.rm=TRUE),
Total_EAV = sum((tax_amt_exe+final_tax_to_dist+final_tax_to_tif)/(tax_code_rate/100), na.rm = TRUE)) %>%
mutate(tax_rate_current = MuniLevy/nonTIF_EAV_post_exemps,
nonTIF_EAV_pre_exemps = nonTIF_EAV_post_exemps + Exempt_EAV,
taxrate_new = MuniLevy/nonTIF_EAV_pre_exemps,
taxrate_change = tax_rate_current-taxrate_new) %>%
select(clean_name, taxrate_change, tax_rate_current, taxrate_new, everything()) %>%
arrange(desc(tax_rate_current))
land_use <- taxcodes_current %>%
left_join(muni_agency_names) %>%
left_join(Current_Taxrates) %>%
left_join(class_dict, by = c("class" = "class_code")) %>%
mutate(class_1dig = str_sub(class, 1, 1),
ResidentialProps = ifelse(class_1dig %in% c("2", "3", "9"), "Residential", "Non-Residential")) %>%
# PropType = case_when(
# major_class_code %in% c("3","9") ~ "Multi-Family",
# major_class_code == "2" ~ "Single-Family",
# TRUE ~ "Commercial-Industrial")) %>%
group_by(clean_name, Alea_cat, agency_num, tax_rate_current, taxrate_new, taxrate_change, agency_name) %>%
# All of the values calculated below are AFTER exemptions have been removed
summarize(taxrev_from_proptype = sum(final_tax_to_dist, na.rm = TRUE),
nonTIF_EAV = sum(final_tax_to_dist/(tax_code_rate/100), na.rm = TRUE),
TIF_increment_EAV = sum(final_tax_to_tif/(tax_code_rate/100), na.rm=TRUE),
Exempt_EAV = sum(tax_amt_exe/(tax_code_rate/100), na.rm=TRUE),
Total_EAV = sum((tax_amt_exe+final_tax_to_dist+final_tax_to_tif)/(tax_code_rate/100), na.rm = TRUE) ) %>% ungroup()
Current_Taxrates
Current composite tax rates for each municipality are above. Table
also includes the new tax rate if there were no exemptions, the levy
(aka amount collected by the municipality from final_tax_to_dist
variable), EAV outside of TIFs, amount of exempt EAV, and additional
variables.
Below: Take EAV values within each property type, join it with muni
level EAV values, and calculate …
grouped_exemptions <- exemptions_by_class_per_TC %>%
# group_by(agency_name, major_class_code, major_class_type, ResidentialProps, PropType) %>%
group_by(clean_name, Alea_cat, agency_name) %>%
summarize(eav = sum(eav),
exempt_EAV = sum(exempt_EAV, exe_abate, na.rm=TRUE),
tax_base_current = sum(tax_base_current, na.rm=TRUE),
tax_base_noexemps = sum(tax_base_noexemps, na.rm=TRUE)) %>% ungroup()
# calculate totals with ONLY EAV outside of TIFs
muni_eav <- grouped_exemptions %>%
group_by(clean_name, agency_name) %>%
summarize(muni_EAV_includesTIF = sum(eav), # all EAV in the municipality that exists
muni_tax_base_current=sum(tax_base_current), # taxable EAV based on current exemptions
muni_tax_base_noexemps = sum(tax_base_noexemps)) %>% # taxable EAV pre-exemptions
ungroup()
pct_property_types <- left_join(grouped_exemptions, muni_eav) %>%
# filter(ResidentialProps == "Alea_cat") %>%
mutate(pct_PropType = eav / muni_EAV_includesTIF)# %>% select()
pct_property_types
burden_table <- pct_property_types %>%
left_join(Current_Taxrates, by = c("agency_name", "clean_name")) %>%
mutate(rev_collected_current = tax_base_current * tax_rate_current,
rev_collected_new = tax_base_noexemps*taxrate_new,
burden_current = rev_collected_current/MuniLevy,
burden_noexemps = rev_collected_new/MuniLevy,
burden_change = burden_noexemps- burden_current,
burden_noexemps = ifelse(burden_noexemps >1, 1, burden_noexemps)) %>%
mutate(burden_current = ifelse(is.na(burden_current), 0, burden_current),
burden_noexemps = ifelse(is.na(burden_noexemps), 0, burden_noexemps)) %>%
mutate(burden_noexemps = ifelse(burden_noexemps>1, 1, burden_noexemps),
burden_current = ifelse(burden_current>1, 1, burden_current)) %>%
mutate(agency_name = ifelse(agency_name == "TOWN CICERO", "CITY OF CICERO", agency_name) )
burden_shift <- burden_table # only to not change code below in graphs.
Composite Tax Rate Change
The tax rate shown is the composite tax rate for the Municipality.
The composite tax rate is the aggregate of the tax rate for each taxing
agency X the EAV within the taxing jurisdiction. This was calculated at
a tax code level first and then added together for all taxcodes taxed by
a municipal taxing agency.
6 Highest and 6 lowest tax rates. View the extremes on both sides
library(kableExtra)
Current_Taxrates %>% filter(tax_rate_current > 0.25 ) %>% select( -agency_name) %>%
kbl(caption = "Highest Composite Tax Rates" , row.names=FALSE) %>%
kable_classic()
Highest Composite Tax Rates
|
clean_name
|
taxrate_change
|
tax_rate_current
|
taxrate_new
|
MuniLevy
|
nonTIF_EAV_post_exemps
|
TIF_increment_EAV
|
Exempt_EAV
|
Total_EAV
|
nonTIF_EAV_pre_exemps
|
|
Park Forest
|
0.1445
|
0.4136
|
0.2691
|
37786878
|
91359693
|
7860014
|
49058933
|
148278640
|
140418626
|
|
Riverdale
|
0.0677
|
0.3065
|
0.2389
|
29466293
|
96122768
|
0
|
27234709
|
123357478
|
123357478
|
|
Phoenix
|
0.1362
|
0.2981
|
0.1619
|
1611282
|
5405017
|
3879516
|
4548727
|
13833260
|
9953744
|
|
Harvey
|
0.0507
|
0.2726
|
0.2220
|
54729654
|
200734513
|
9158437
|
45848694
|
255741644
|
246583207
|
|
Markham
|
0.0619
|
0.2652
|
0.2032
|
31891600
|
120271847
|
15224108
|
36651935
|
172147890
|
156923782
|
|
Calumet City
|
0.0583
|
0.2606
|
0.2023
|
92759714
|
355895328
|
9193252
|
102654888
|
467743468
|
458550216
|
Current_Taxrates %>% filter( tax_rate_current < 0.08) %>% select( -agency_name) %>%
kbl(caption = "Lowest Composite Tax Rates" , row.names=FALSE) %>%
kable_classic()
Lowest Composite Tax Rates
|
clean_name
|
taxrate_change
|
tax_rate_current
|
taxrate_new
|
MuniLevy
|
nonTIF_EAV_post_exemps
|
TIF_increment_EAV
|
Exempt_EAV
|
Total_EAV
|
nonTIF_EAV_pre_exemps
|
|
Countryside
|
0.0054
|
0.0790
|
0.0737
|
26921653
|
340570898
|
8300179
|
24803814
|
373674890
|
365374711
|
|
Lemont
|
0.0072
|
0.0784
|
0.0712
|
56597990
|
722097359
|
11370587
|
72740257
|
806208203
|
794837616
|
|
Chicago
|
0.0044
|
0.0673
|
0.0629
|
6536952735
|
97124833788
|
17702266790
|
6839135241
|
121666235819
|
103963969029
|
#quantile(Current_Taxrates$tax_rate_current )
#sd(Current_Taxrates$tax_rate_current)
The current composite tax rate for the median municipality is 12%
Current_Taxrates %>%
mutate(agency_name = ifelse(agency_name == "TOWN CICERO", "CITY OF CICERO", agency_name)
) %>%
# filter(major_class_code == 2) %>% # all property types have same composite tax rate
left_join(muni_shp, by = c("agency_name" = "AGENCY_DESC")) %>%
ggplot(aes(fill = tax_rate_current)) +
geom_sf(aes(geometry = geometry), color = "black") +
theme_void() +
theme(axis.ticks = element_blank(), axis.text = element_blank())+
scale_fill_steps2(#colors = colors,
high = "#420420", low = "black",
midpoint = median(Current_Taxrates$tax_rate_current), # midpoint = 0.123,
#breaks = breaks_sd,
limits = c(0,.45),
show.limits=TRUE,
nice.breaks=FALSE,
n =6,
name = "Tax Rate",
label = scales::percent )+
labs(title = "Current composite tax rates" ,
caption = "The current median composite tax rate is 12.3%.
Highest composite tax rate is in Park Forest (41.4%.)
Lowest composite tax rate is in Chicago (6.7%).")

# median
burden_shift %>%
filter(Alea_cat == "Owner Occupied") %>%
#filter(major_class_code == 2) %>%
summarize(median_currentburden = median(burden_current),
median_new_burden = median(burden_noexemps),
median_burdenchange = median(burden_change),
median_currenttaxrate = median(tax_rate_current),
median_taxratechange = median(taxrate_change),
median_taxratenew = median(taxrate_new)) %>%
pivot_longer(cols = everything(), names_to = "Stat", values_to = "Value")
burden_shift %>%
filter(Alea_cat == "Rental") %>%
#filter(major_class_code == 2) %>%
summarize(median_currentburden = median(burden_current),
median_new_burden = median(burden_noexemps),
median_burdenchange = median(burden_change),
median_currenttaxrate = median(tax_rate_current),
median_taxratechange = median(taxrate_change),
median_taxratenew = median(taxrate_new)) %>%
pivot_longer(cols = everything(), names_to = "Stat", values_to = "Value")
Current_Taxrates %>%
mutate(agency_name = ifelse(agency_name == "TOWN CICERO", "CITY OF CICERO", agency_name)
) %>%
left_join(muni_shp, by = c("agency_name" = "AGENCY_DESC")) %>%
ggplot(aes(fill = taxrate_new)) +
theme_void() +
theme(axis.ticks = element_blank(), axis.text = element_blank())+
scale_fill_steps2(
high = "#420420", low = "#008080",
limits = c(0,.45),
midpoint = median(Current_Taxrates$taxrate_new), # midpoint = .1052,
nice.breaks=FALSE,
show.limits=TRUE,
n=6,
name = "Tax Rate", label = scales::percent)+
geom_sf(aes(geometry = geometry), color = "black") +
labs(title = "New composite tax rates if exemptions were eliminated" ,
caption = "The new median composite tax rate would be approximately 10.5%
if exemptions were removed.")

Current_Taxrates %>%
mutate(agency_name = ifelse(agency_name == "TOWN CICERO", "CITY OF CICERO", agency_name) ) %>%
# filter(clean_name != "Park Forest") %>%
full_join(muni_shp, by = c("agency_name" = "AGENCY_DESC")) %>%
ggplot(aes(fill = taxrate_change)) +
geom_sf(aes(geometry = geometry), color = "black") +
theme_void() +
theme(axis.ticks = element_blank(), axis.text = element_blank())+
scale_fill_steps2(high = "blue", low = "black",
n=6, midpoint = 0.01388,
show.limits=TRUE,
nice.breaks=FALSE,
na.value = "lightgray",
labels = scales::percent,
name = "Percentage Point \nDifference")+
labs(title = "Change in Composite Tax Rate if Exemptions are Removed",
caption = "The median change in composite tax rate is 1.43 percentage points")

# as a dot graph ##
order <- burden_shift %>%
as_tibble() %>%
summarize(agency_name = unique(agency_name),
clean_name = unique(clean_name),
tax_rate_current = unique(tax_rate_current),
taxrate_new = unique(taxrate_new)) %>%
arrange(tax_rate_current) %>%
select(agency_name, clean_name, tax_rate_current)
head(order)
# look at ones that changed the most
burden_shift %>%
# filter(tax_rate_current < (median(tax_rate_current))+0.002 & tax_rate_current > (median(tax_rate_current))-0.002 |
# (tax_rate_current > 0.25 | tax_rate_current < 0.08 )) %>%
# (tax_rate_current < (median(tax_rate_current))+0.005 & tax_rate_current > (median(tax_rate_current))-0.005 )) %>%
#filter(PropType == "Single-Family") %>%
filter(Alea_cat == "Owner Occupied") %>%
ungroup() %>%
select(clean_name, tax_rate_current, taxrate_new, agency_name) %>%
pivot_longer(c("tax_rate_current", "taxrate_new"),
names_to = "type", values_to = "tax_rate") %>%
left_join(order) %>%
ggplot(aes(x = tax_rate*100, y= reorder(clean_name, tax_rate_current)))+
geom_line(aes(group = clean_name))+
geom_hline(yintercept = 3.5, linetype = 2)+
geom_hline(yintercept = 13.5, linetype = 2) +
geom_point(aes(color=type), size=3 )+
theme_minimal() +
theme(
legend.title = element_blank(),
plot.title.position = "plot",
# panel.background = element_rect(fill='transparent'), #transparent panel bg
plot.background = element_rect(fill='transparent', color=NA) #transparent plot bg
)+
scale_color_brewer(palette="Paired", labels = c("Exemptions", "No Exemptions"), direction = 1)+
labs(title = "Difference in Composite Tax Rate if there were No Exemptions",
subtitle = "Ordered by Current Composite Tax Rate", x = "Composite Tax Rate (%)", y = "" ,
caption = "For the highest, median, and lowest municipality composite tax rates ")

# ordered by change in tax rate if exemptions were removed.
# as a dot graph ##
order <- burden_shift %>%
as_tibble() %>%
group_by(agency_name, clean_name) %>%
summarize(tax_rate_current = median(tax_rate_current),
taxrate_new = median(taxrate_new),
taxrate_change = median(taxrate_change)) %>%
arrange(taxrate_change)
median(order$taxrate_change) # median rate change is 1.388 percentage points
## [1] 0.01388
#head(order)
#tail(order)
burden_shift %>%
filter(taxrate_change < 0.0027 |taxrate_change > 0.06 |
taxrate_change < (median(taxrate_change))+0.0007 & taxrate_change > (median(taxrate_change))-0.00075
) %>%
filter(Alea_cat == "Owner Occupied") %>%
# filter(PropType == "Single-Family") %>%
ungroup() %>%
select(clean_name, tax_rate_current, taxrate_new, agency_name) %>%
pivot_longer(c("tax_rate_current", "taxrate_new"),
names_to = "type", values_to = "tax_rate") %>%
left_join(order) %>%
ggplot(aes(x = tax_rate*100, y= reorder(clean_name, taxrate_change)))+
geom_line(aes(group = clean_name))+
geom_point(aes(color=type), size=3 )+
geom_hline(yintercept = 10.5, linetype =2)+
geom_hline(yintercept = 5.5, linetype =2)+
theme_minimal() +
theme(
legend.title = element_blank(),
plot.title.position = "plot",
legend.position = "none",
# panel.background = element_rect(fill='transparent'), #transparent panel bg
plot.background = element_rect(fill='transparent', color=NA) #transparent plot bg
)+
scale_color_brewer(palette="Paired", labels = c("Exemptions", "No Exemptions"), direction = 1)+
labs(title = "Difference in Composite Tax Rate if there were No Exemptions",
subtitle = "Ordered by Change in Tax Rate: Highest, Median, and Smallest Differences",
caption = "Median change is 1.38 percentage points",
x = "Composite Tax Rate (%)", y = "" )

ggsave("Composite_Rate_Change.png", width = 6, height = 4, units = "in")
Owner Occupied Properties Burden Shift
Change in Tax Burden for Owner Occupied Properties. Includes class 2
properties that are not rental properties:
burden_shift %>%
mutate(burden_current = ifelse(burden_current>1, 1, burden_current)) %>%
filter(Alea_cat == "Owner Occupied") %>%
#filter(major_class_code == 2) %>%
mutate(agency_name = ifelse(agency_name == "TOWN CICERO", "CITY OF CICERO", agency_name) ) %>%
left_join(muni_shp, by = c("agency_name" = "AGENCY_DESC")) %>%
ggplot(aes(fill = burden_current)) +
geom_sf(aes(geometry = geometry), color = "black") +
theme_classic() +
theme(axis.ticks = element_blank(), axis.text = element_blank())+
scale_fill_steps2(
# high = "#00e304" , low = "#00cfd4",
high = "#420420", low = "#008080",
# high = "#00a8ff" , low = "#ff4800",
nice.breaks=FALSE,
show.limits=TRUE,
n.breaks = 6,
midpoint = 0.597,
# guide = "legend",
name = "Current Burden \n(with Exemptions)", labels = scales::percent
)+
labs(title = "Current share of property tax burden",
subtitle = "for Owner Occupied Property Types",
caption = "The median municipality gets 59.7% of its property tax revenue
from Class 2 properties that are owner occupied in the current tax system.")
burden_shift %>%
mutate(agency_name = ifelse(agency_name == "TOWN CICERO", "CITY OF CICERO", agency_name) ) %>%
# filter(major_class_code == 2) %>%
filter(Alea_cat == "Owner Occupied") %>%
left_join(muni_shp, by = c("agency_name" = "AGENCY_DESC")) %>%
ggplot(aes(fill = burden_noexemps)) +
geom_sf(aes(geometry = geometry), color = "black") +
theme_classic( ) +
theme(axis.ticks = element_blank(), axis.text = element_blank())+
scale_fill_steps2(
# high = "#00e304" , low = "#00cfd4",
# colors = c("#ffffcc","#a1dab4" ,"#41b6c4","#2c7fb8", "#253494"),
high = "#420420", low = "#008080",
# high = "#253494" , low = "#3b3c36" ,
nice.breaks=FALSE,
show.limits=TRUE,
n.breaks = 6,
midpoint = 0.65,
name = "Burden without \nExemptions", labels = scales::percent) +
labs(title = "New share of property tax burden", subtitle = "for Owner occupied properties", caption =
"Without exemptions, municipalities would get a larger share of
their revenue from owner occupied properties.
Owner occupied properties includes condos and single-family homes.")


burden_shift %>% #filter(clean_name != "Phoenix") %>%
filter(Alea_cat == "Owner Occupied") %>%
# filter(major_class_code == 2) %>%
mutate(agency_name = ifelse(agency_name == "TOWN CICERO", "CITY OF CICERO", agency_name) ) %>%
mutate(burden_change = ifelse(burden_change<0,0, burden_change))%>%
# burden_change = ifelse(burden_change>1,1, burden_change))%>%
left_join(muni_shp, by = c("agency_name" = "AGENCY_DESC")) %>%
ggplot(aes(fill = (burden_change*100)) )+
geom_sf(aes(geometry = geometry), color = "black") + theme_void()+
labs(title = "Change in Tax Burden: Owner occupied properties",
caption = "The median shift from owner occupied properties to other property types
due to current exemptions is worth approximately 4.5% of a municipality's levy.") +
theme_classic() +
theme(axis.ticks = element_blank(), axis.text = element_blank())+
scale_fill_steps2(
high = "#420420", low = "#008080",
nice.breaks=FALSE,
show.limits=TRUE,# n.breaks = 5,
midpoint = 4.7, # median(burden_shift$burden_change*100),
name = "Change in Burden \n Pct Points")

Change median vertical line and the horizontal lines. Refilter the
top, medium, and lowest values
burden_shift %>% #filter(PropType == "Single-Family")%>%
filter(Alea_cat == "Owner Occupied") %>%
summarize(median_change = median(burden_change), # 4.74 percentage points.
median_current = median(burden_current), #60%
median_noexemps = median(burden_noexemps)) # 66%
# as a dot graph ##
order <- burden_shift %>%
ungroup %>% as_tibble() %>%
# filter(ResidentialProps == "Residential") %>%
# filter(PropType == "Single-Family") %>%
filter(Alea_cat == "Owner Occupied") %>%
select(agency_name, clean_name, burden_current, burden_change)
# burder_shift_ordered <- burden_shift %>%
# ungroup() %>%
# select(agency_name, current_burden, no_exemptions_burden) %>%
# pivot_longer(c("current_burden", "no_exemptions_burden"),
# names_to = "type", values_to = "pct_burden") %>%
# left_join(order)
# look at ones that changed the most
burden_shift %>% filter(Alea_cat == "Owner Occupied") %>%
arrange(burden_current)
burden_shift %>%
filter(Alea_cat == "Owner Occupied") %>%
filter(clean_name != "Hoffman Estates") %>% # only because 6 were between the median range and I only wanted 5 in the graph
filter(burden_current > 0.931 |burden_current < .17 |
( (burden_current < median(burden_current) + 0.01 )& (burden_current > median(burden_current) - 0.01)) )%>%
ungroup() %>%
select(agency_name, clean_name, burden_current, burden_noexemps, burden_change) %>%
arrange(burden_change) %>%
mutate(
burden_noexemps = ifelse(burden_noexemps > 1, 1, burden_noexemps)) %>%
pivot_longer(c("burden_current", "burden_noexemps"),
names_to = "type", values_to = "pct_burden") %>%
inner_join(order) %>%
ggplot(aes(x = pct_burden*100,
y= reorder(clean_name, -burden_current)))+
# y= reorder(clean_name, burden_current)))+
geom_vline(xintercept = 59.7, linetype = 3)+
geom_line(aes(group = clean_name))+
geom_hline(yintercept = 5.5, linetype = 2)+
geom_hline(yintercept = 10.5, linetype = 2)+
geom_point(aes(color=type), size=3 )+
theme_minimal() +
theme(#legend.position = "none",
legend.title = element_blank(),
plot.title.position = "plot",
# panel.background = element_rect(fill='transparent'), #transparent panel bg
plot.background = element_rect(fill='transparent', color=NA) #transparent plot bg
)+
scale_color_brewer(palette="Paired", labels = c("Current Burden", "Burden if \nNo Exemptions" ), direction = 1)+
labs(title = "Change in Owner Occupied Tax Burden",
subtitle = "Ordered by Current Tax Burden",
x = "Share of Levy (%)", y = "" ,
caption = "Dotted line represents current tax burden (59.7% of the municpality's levy) in the median municipality.
Residential Tax Burden is the share of the property tax collected that was paid for by residential
property owners. Includes condos and detached homes. Does not include classes described as 'rentals'.") +
geom_label(label = "Home owners pay small share of \nlevy; very little residential", x=35, y = 12.5, label.size = 1, size = 3)+
geom_label(label = "Home owners pay median share of \nlevy (59.7%), mix of land use", x=30, y = 7.5, label.size = 1, size = 3) +
geom_label(label = "Home owners pay nearly all of levy, \nhighly residential", x=70, y = 3, label.size = 1,size = 3)

### Change in Burden
burden_shift %>%
ungroup() %>%
filter(Alea_cat == "Owner Occupied") %>%
# filter(PropType == "Single-Family") %>%
# filter(burden_change > 0.3 | burden_change < .01) %>%
select(agency_name, clean_name, burden_current, burden_noexemps,
burden_change) %>%
mutate(
burden_current = ifelse(burden_current > 1, 1, burden_current)) %>%
pivot_longer(c("burden_current", "burden_noexemps"),
names_to = "type", values_to = "pct_burden") %>%
inner_join(order) %>%
ggplot(aes(x = pct_burden, y= reorder(clean_name, -burden_current)))+
geom_line(aes(group = clean_name))+
geom_point(aes(color=type), size=3 )+
theme_minimal() +
theme(#legend.position = "none",
legend.title = element_blank(),
plot.title.position = "plot",
# panel.background = element_rect(fill='transparent'), #transparent panel bg
plot.background = element_rect(fill='transparent', color=NA) #transparent plot bg
)+
scale_color_brewer(palette="Paired", labels = c("Current Burden","Burden if \nNo Exemptions"), direction = 1)+
labs(title = "Change in Owner Occupied Property Tax Burden",
x = "Share of Levy (%)", y = "" ,
caption = "Tax Burden is the Share of the property tax collected that was paid for by
home owners in property classes 2.")

burden_shift %>%
ungroup() %>%
filter(Alea_cat == "Owner Occupied") %>%
# filter(PropType == "Single-Family") %>%
filter(burden_noexemps > 0.2 | burden_noexemps < .001) %>%
select(agency_name, clean_name, burden_current, burden_noexemps,
burden_change) %>%
mutate(
burden_current = ifelse(burden_current > 1, 1, burden_current)) %>%
pivot_longer(c("burden_current", "burden_noexemps"),
names_to = "type", values_to = "pct_burden") %>%
inner_join(order) %>%
ggplot(aes(x = pct_burden, y= reorder(clean_name, burden_change)))+
geom_line(aes(group = clean_name))+
geom_point(aes(color=type), size=3 )+
theme_minimal() +
theme(#legend.position = "none",
legend.title = element_blank(),
plot.title.position = "plot",
# panel.background = element_rect(fill='transparent'), #transparent panel bg
plot.background = element_rect(fill='transparent', color=NA) #transparent plot bg
)+
scale_color_brewer(palette="Paired", labels = c( "Current Burden","Burden if \nNo Exemptions"), direction = 1)+
labs(title = "Change in Owner Occupied Class 2 Residential Tax Burden",
x = "Share of Levy (%)", y = "" ,
caption = "Tax Burden is the Share of the property tax collected that was paid for by
home owners in property classes 2.")

burden_shift %>% ungroup() %>% #filter(PropType == "Single-Family") %>%
filter(Alea_cat == "Owner Occupied") %>%
arrange(burden_change) %>% head()
burden_shift %>%
ungroup() %>%
filter(Alea_cat == "Owner Occupied") %>%
# filter(PropType == "Single-Family") %>%
filter(clean_name != "Phoenix") %>%
filter(clean_name %in% c("Schaumburg", "Elk Grove Village", "Westchester", "Palos Hills", "Orland Hills") |
# filter(clean_name %in% c("Hometown", "Burbank", "Schaumburg", "Elk Grove Village", "Westchester") |
burden_change > 0.11 |burden_change < .003 ) %>%
#| ( (burden_change < median(burden_change) + 0.001 )& (burden_change > median(burden_change) - 0.001)) ) %>%
select(agency_name, clean_name, burden_current, burden_noexemps,
burden_change) %>%
pivot_longer(c("burden_current", "burden_noexemps"),
names_to = "type", values_to = "pct_burden") %>%
inner_join(order) %>%
ggplot(aes(x = pct_burden*100, y= reorder(clean_name, burden_change*100)))+
geom_line(aes(group = clean_name))+
geom_hline(yintercept = 5.5, linetype = 2)+
geom_hline(yintercept = 10.5, linetype = 2)+
geom_point(aes(color=type), size=3 )+
theme_minimal() +
theme(legend.position = "none",
legend.title = element_blank(),
plot.title.position = "plot",
# panel.background = element_rect(fill='transparent'), #transparent panel bg
plot.background = element_rect(fill='transparent', color=NA) #transparent plot bg
)+
scale_color_brewer(palette="Paired", labels = c( "Current Burden","Burden if \nNo Exemptions"), direction = 1)+
labs(title = "Change in Residential Tax Burden (Owner Occupied only)",
x = "Share of Levy (%)", y = "" )

ggsave("residential_tax_burden_change.png", width = 6, height = 4, units = "in")
Summary table of Burden Shift: Grouped Property Categories
Same data that is used above but property types are combined into 4
categories:
- Owner Occupied (Most of Class 2 Properties. Classes with “rental” in
the description were included with Renter properties.)
- Renters (Class 3 & 9 and some of Class 2)
- Commercial (splits class 5, 6, 7, and 8. Commercial/Industrial,
incentive and nonprofit classes based on property class
descriptions)
- Industrial (splits class 5, 6, 7, and 8. Commercial/Industrial,
incentive and nonprofit classes based on property class
descriptions)
- Other?: Vacant Land.
- Railroad land is dropped from calculations and tables. Not
taxed.
# Current Burden:
munis_3property_types <- burden_shift %>%# mutate(
# burden_noexemps = ifelse(is.na(burden_noexemps), 0, burden_noexemps)) %>%
# mutate(burden_current = ifelse(burden_current>1, 1, burden_current)) %>%
ungroup() %>%
group_by(agency_name, clean_name, Alea_cat) %>%
summarize(#final_tax_to_dist = sum(final_tax_to_dist, na.rm = TRUE),
burden_current = sum(burden_current, na.rm = TRUE),
burden_noexemps = sum(burden_noexemps, na.rm = TRUE),
burden_change = sum(burden_change, na.rm = TRUE))
#write.csv(munis_3property_types, "1_usemetable.csv")
proptypes3_current <- burden_shift %>%
mutate(burden_current = ifelse(is.na(burden_current), 0, burden_current)) %>%
pivot_wider( id_cols = clean_name , names_from = "Alea_cat", values_from = "burden_current",names_prefix="Current - ", values_fill = 0 ) %>%
select(clean_name, everything())
proptypes3_current[2:4] <- sapply(proptypes3_current[2:4], function(x) scales::percent(x, accuracy=.01) )
proptypes3_current
# __Tax Burden if there were no exemptions:__
proptypes3_noexemps <- burden_shift %>%
mutate(burden_noexemps = ifelse(is.na(burden_noexemps), 0, burden_noexemps)) %>%
pivot_wider( id_cols = clean_name , names_from = "Alea_cat", values_from = "burden_noexemps", names_prefix = "W/O Exemptions - ", values_fill = 0)
proptypes3_noexemps[2:4] <- sapply(proptypes3_noexemps[2:4], function(x) scales::percent(x, accuracy=.01))
proptypes3_noexemps
Change in Share of Burden if there were no
exemptions:
# burden_shift %>% ungroup() %>%
# group_by(agency_name, PropType) %>%
# summarize(district_rev_collected = sum(district_rev_collected),
# current_burden = sum(current_burden),
# no_exemptions_burden = sum(no_exemptions_burden))
props_wide <- burden_shift %>%
filter(!is.na(Alea_cat))%>%
pivot_wider(id_cols = clean_name ,
names_from = "Alea_cat",
values_from = "burden_change", values_fill = 0) %>%
select(clean_name, everything()) %>%
arrange(desc(`Owner Occupied`) )
props_wide[2:7] <- sapply(props_wide[2:7], function(x) scales::percent(x, accuracy=.001))
props_wide
proptypes3_comparisontable<- left_join(proptypes3_current, proptypes3_noexemps, by = "clean_name")
proptypes3_comparisontable
write_csv(proptypes3_comparisontable, "OwnerOccupied_ComparisonTable.csv")
proptypes3_burdenchange <- burden_shift %>%
filter(!is.na(Alea_cat))%>%
mutate(burden_noexemps = ifelse(is.na(burden_change), 0, burden_change)) %>%
pivot_wider( id_cols = clean_name , names_from = "Alea_cat", values_from = "burden_change", values_fill = 0) %>%
arrange(desc(`Owner Occupied`))
proptypes3_burdenchange[2:4] <- sapply(proptypes3_burdenchange[2:4], function(x) scales::percent(x, accuracy=.01))
proptypes3_burdenchange
#proptypes3_burdenchange %>% write_csv("burden_change_august6.csv")
Cook County “Cost” Values
“Multiplies the EAV exempted for all Cook County
municipalities by their consolidated tax rates in each
municipality”
Do this by taxcode and actual tax code tax rate. Much more
accurate.
taxcodes_current %>%
summarize(forgone_rev = sum(tax_amt_exe, na.rm = TRUE),
exempt_EAV = sum(tax_amt_exe/(tax_code_rate/100), na.rm = TRUE)
)
There is $15,770,910,176 of EAV that is exempt from property
taxes.
$1.5 Billion of potential revenue is transferred to other
taxpayers due to current exemptions.
Current_Taxrates %>%
mutate(transfered_taxes = tax_rate_current*Exempt_EAV) %>%
mutate(agency_name = ifelse(agency_name == "TOWN CICERO", "CITY OF CICERO", agency_name)
) %>%
left_join(muni_shp, by = c("agency_name" = "AGENCY_DESC")) %>%
ggplot(aes(fill = transfered_taxes)) +
geom_sf(aes(geometry = geometry), color = "black") +
theme_void() +
theme(axis.ticks = element_blank(), axis.text = element_blank())+
scale_fill_steps2(
high = "#420420", low = "black",
# midpoint = median(transfered_taxes),
show.limits=TRUE,
nice.breaks=FALSE,
n =6,
name = "",
labels = scales::dollar
)+
labs(title = "Dollars passed from Class 2 properties to others \ndue to current exemptions")
Current_Taxrates %>%
filter(clean_name != "Chicago") %>%
mutate(transfered_taxes = tax_rate_current*Exempt_EAV) %>%
mutate(agency_name = ifelse(agency_name == "TOWN CICERO", "CITY OF CICERO", agency_name)
) %>%
left_join(muni_shp, by = c("agency_name" = "AGENCY_DESC")) %>%
ggplot(aes(fill = transfered_taxes)) +
geom_sf(aes(geometry = geometry), color = "black") +
theme_void() +
theme(axis.ticks = element_blank(), axis.text = element_blank())+
scale_fill_steps2(
high = "#420420", low = "black",
# midpoint = median(transfered_taxes),
show.limits=TRUE,
nice.breaks=FALSE,
n =6,
name = "",
labels = scales::dollar
)+
labs(title = "Dollars passed from Class 2 Residential properties to others \ndue to current exemptions",
caption = "Ignores Chicago (over $460K) to highlight other municipalities")
ggsave("cook_nochicago.png")


class2_perc <- class2_perc %>% mutate(percent_exempt = exempt_EAV/muni_EAV_includesTIF)
class2_perc%>%
mutate(agency_name = ifelse(agency_name == "TOWN CICERO", "CITY OF CICERO", agency_name)
) %>%
left_join(muni_shp, by = c("agency_name" = "AGENCY_DESC")) %>%
ggplot(aes(fill = percent_exempt)) +
geom_sf(aes(geometry = geometry), color = "black") +
theme_void() +
theme(axis.ticks = element_blank(), axis.text = element_blank())+
scale_fill_steps2(
high = "#420420", low = "black",
midpoint = median(class2_perc$percent_exempt),
show.limits=TRUE,
nice.breaks=FALSE,
n =6,
name = "Percent Exempt",
labels = scales::percent
)+
labs(title = "Percent Exempt: Exempt EAV / All EAV in Municipality")
class2_perc <- class2_perc %>% mutate(percent_exempt = exempt_EAV/muni_tax_base_noexemps)
class2_perc %>%
mutate(agency_name = ifelse(agency_name == "TOWN CICERO", "CITY OF CICERO", agency_name)
) %>%
left_join(muni_shp, by = c("agency_name" = "AGENCY_DESC")) %>%
ggplot(aes(fill = percent_exempt)) +
geom_sf(aes(geometry = geometry), color = "black") +
theme_void() +
theme(axis.ticks = element_blank(), axis.text = element_blank())+
scale_fill_steps2(
high = "#420420", low = "black",
midpoint = median(class2_perc$percent_exempt),
show.limits=TRUE,
nice.breaks=FALSE,
n =6,
name = "Percent Exempt",
labels = scales::percent
)+
labs(title = "Percent of pre-exemption taxable base that is tax exempt",
caption = "Total EAV includes the pre-exemption Taxable Base.
TIF increment EAV is not included in the total EAV in this image.
Median value is 12.43%")


Current_Taxrates <- Current_Taxrates %>%
mutate(Exempt_percent = Exempt_EAV/Total_EAV)
median(Current_Taxrates$Exempt_percent)
## [1] 0.1245
Current_Taxrates%>%
mutate(agency_name = ifelse(agency_name == "TOWN CICERO", "CITY OF CICERO", agency_name)
) %>%
left_join(muni_shp, by = c("agency_name" = "AGENCY_DESC")) %>%
ggplot(aes(fill = Exempt_percent)) +
geom_sf(aes(geometry = geometry), color = "black") +
theme_void() +
theme(axis.ticks = element_blank(), axis.text = element_blank())+
scale_fill_steps2(
high = "#420420", low = "black",
midpoint = median(Current_Taxrates$Exempt_percent),
show.limits=TRUE,
nice.breaks=FALSE,
n =6,
name = "Percent Exempt",
labels = scales::percent)+
labs(title = "Percent of Total EAV that is Tax Exempt",
caption = "Total EAV includes all EAV in and out of TIFs.
Median value is 13.1%. ")

“Takes the median tax rate increase as a result of exemptions
(1.4%) and multiplies that by the total residential EAV in Cook
County”
taxcodes_current %>%
filter(year == 2021) %>%
group_by(major_class_type, major_class_code) %>%
summarize(eav = sum(tax_amt_pre_exe/(tax_code_rate/100), na.rm=TRUE)) %>% arrange(desc(eav))
120944941944 * 0.01388 # 1693229187
There is $120,944,941,944 of Residential EAV in Cook
County.
$1,678,715,794 is Residential EAV * average increase in municipal
taxrate.
“And then we should [show] how/why if levy is fixed,
exemptions increase the tax rate and/or shift the tax
burden.”
- Once the amount of money that is needed is determined, then the tax
rate is determined based off of that.
- Levy doesn’t change, so if you are decreasing the amount of taxable
EAV, then the tax rate must go up to collect the same amount of
money.
- maybe draw a diagram for a municipality as an example on a
slide?
“We might also want to take a closer look at either our 6
case study municipalities or those municipalities most affected by
exemptions (Park Forest, Phoenix, Calumet Park, Riverdale) to get some
effects for the owner of the average or median value home.”
Locations with the highest percent of their potentially taxable EAV
(non-TIF increment EAV) that is tax-exempt:
Phoenix Park Forest Markham Calumet Park
Thornton
Harvey
Burnham Dolton
Almost exact same list of locations as largest tax rate change.
Exporting data to Excel file
library(openxlsx)
dataset_names <- list(
'Land Use' = perc_residential,
'Burden Table' = burden_table,
# 'EAVoutsideTIFs' = EAV_outside_TIFS_byClass,
'Composite Tax Rates' = Current_Taxrates,
'MuniEAV' = muni_eav, #included as columns in Burden Table too
# 'ResidentialEAV' = table_ResidentialEAV, # doesn't exist?
# 'Burden with Exemps' = burden_with_exemptions,
# 'Burden without Exemps' = burden_noexemps,
'Burden Shift-3PropTypes' = proptypes3_burdenchange,
'3 Property Types'= munis_3property_types,
# 'TaxcodeData-NoExemptions'=taxcodes_noexemps,
'TaxcodeData-Current' = taxcodes_current)
write.xlsx(dataset_names, file = 'data_for_slides_filteredMunis.xlsx')
LS0tDQp0aXRsZTogIk1hcHBpbmcgUHJvcGVydHkgVGF4IEJ1cmRlbiBTaGlmdCBkdWUgdG8gRXhlbXB0aW9ucyINCnN1YnRpdGxlOiAiQ29vayBDb3VudHkgTXVuaWNpcGFsaXRpZXMgKHdpdGggPjUwJSBFQVYgd2l0aGluIENvb2sgQ291bnR5KSINCmF1dGhvcjogIkFsZWEgV2lsYnVyIg0KZGF0ZTogImByIFN5cy5EYXRlKClgIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0OiB5ZXMNCiAgICBkZl9wcmludDogcGFnZWQNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQotLS0NCg0KIyBHZXR0aW5nIERhdGENCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFKQ0KDQoNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShEQkkpDQpsaWJyYXJ5KGRhdGEudGFibGUpDQpsaWJyYXJ5KGdnc3BhdGlhbCkNCmxpYnJhcnkoZ3N0YXQpDQpsaWJyYXJ5KGhlcmUpDQpsaWJyYXJ5KGh0dHIpDQpsaWJyYXJ5KGpzb25saXRlKQ0KbGlicmFyeShwdGF4c2ltKQ0KbGlicmFyeShzZikNCmxpYnJhcnkoc3RhcnMpDQpsaWJyYXJ5KGdsdWUpDQoNCiMgQ3JlYXRlIHRoZSBEQiBjb25uZWN0aW9uIHdpdGggdGhlIGRlZmF1bHQgbmFtZSBleHBlY3RlZCBieSBQVEFYU0lNIGZ1bmN0aW9ucw0KcHRheHNpbV9kYl9jb25uIDwtIERCSTo6ZGJDb25uZWN0KFJTUUxpdGU6OlNRTGl0ZSgpLCAiLi9wdGF4c2ltLmRiL3B0YXhzaW0tMjAyMS4wLjQuZGIiKQ0KDQoNCm9wdGlvbnMoZGlnaXRzPTQsIHNjaXBlbiA9IDk5OSkNCg0KbGlicmFyeShzZikNCmxpYnJhcnkoanNvbmxpdGUpDQpsaWJyYXJ5KGh0dHIpDQoNCiMgbGluayB0byB0aGUgQVBJIG91dHB1dCBhcyBhIEpTT04gZmlsZQ0KbXVuaV9zaHAgPC0gcmVhZF9zZigiaHR0cHM6Ly9naXMuY29va2NvdW50eWlsLmdvdi90cmFkaXRpb25hbC9yZXN0L3NlcnZpY2VzL3BvbGl0aWNhbEJvdW5kYXJ5L01hcFNlcnZlci8yL3F1ZXJ5P291dEZpZWxkcz0qJndoZXJlPTElM0QxJmY9Z2VvanNvbiIpDQoNCmNvb2tfc2hwIDwtIHJlYWRfc2YoImh0dHBzOi8vZ2lzLmNvb2tjb3VudHlpbC5nb3YvdHJhZGl0aW9uYWwvcmVzdC9zZXJ2aWNlcy9wbHNzL01hcFNlcnZlci8xL3F1ZXJ5P291dEZpZWxkcz0qJndoZXJlPTElM0QxJmY9Z2VvanNvbiIpDQoNCiNtdW5pX3NocCA8LSByZWFkX2pzb24oIm11bmlfc2hwLmpzb24iKQ0Kbmlja25hbWVzIDwtIHJlYWR4bDo6cmVhZF9leGNlbCgibXVuaV9zaG9ydG5hbWVzLnhsc3giKQ0KDQoNCg0KYGBgDQoNCioqRGF0YSBQcmVwKioNCg0KUHVsbCBhbGwgYWdlbmN5IG5hbWVzIHRoYXQgZXhpc3QsIHRoZW4gdXNlIGFnZW5jeSBudW1iZXJzIGFzc29jaWF0ZWQgd2l0aCBNVU5JIHR5cGVzIHRvIHB1bGwgb25seSB0aGUgYG11bmlfYWdlbmN5X25hbWVzYCBvYmplY3QuDQoNClRoZXJlIGFyZSA5NDYgdW5pcXVlIHRheGluZyBhZ2VuY2llcyB0aGF0IGV4aXN0ZWQgaW4gMjAyMS4NCg0KYGBge3IgYWdlbmN5LWR0fQ0KIyBoYXMgRUFWIHZhbHVlcywgZXh0ZW5zaW9ucyBieSBhZ2VuY3lfbnVtDQphZ2VuY3lfZHQgPC0gREJJOjpkYkdldFF1ZXJ5KA0KICBwdGF4c2ltX2RiX2Nvbm4sDQogICJTRUxFQ1QgKg0KICBGUk9NIGFnZW5jeQ0KICBXSEVSRSB5ZWFyID0gMjAyMQ0KICAiDQopDQoNCiMgZ3JhYnMgYWxsIHVuaXF1ZSBtdW5pIG5hbWVzLiBXb3VsZCBiZSBuZWVkZWQgaWYgY3JlYXRpbmcgYSBsb29wIGZvciBjYWxjdWxhdGluZyBhbGwgbXVuaXMNCiMgbXVuaWNpcGFsaXR5IG5hbWVzIGFuZCB0aGVpciBhZ2VuY3kgbnVtYmVyDQptdW5pX2FnZW5jeV9uYW1lcyA8LSBEQkk6OmRiR2V0UXVlcnkoDQogIHB0YXhzaW1fZGJfY29ubiwNCiAgIlNFTEVDVCBESVNUSU5DVCBhZ2VuY3lfbnVtLCBhZ2VuY3lfbmFtZSwgbWlub3JfdHlwZQ0KICBGUk9NIGFnZW5jeV9pbmZvDQogIFdIRVJFIG1pbm9yX3R5cGUgPSAnTVVOSScNCiAgT1IgYWdlbmN5X251bSA9ICcwMjAwNjAwMDAnICANCg0KICAiDQopDQoNCm11bmlfYWdlbmN5X25hbWVzIDwtIG11bmlfYWdlbmN5X25hbWVzICU+JSANCiAgICBtdXRhdGUoZmlyc3Q2ID0gc3RyX3N1YihhZ2VuY3lfbnVtLDEsNiksDQogICAgICAgICBmaXJzdDUgPSBzdHJfc3ViKGFnZW5jeV9udW0sMSw1KSkgJT4lIA0KICBzZWxlY3QoLW1pbm9yX3R5cGUpDQoNCg0KDQojTWFrZXMgYSBsaXN0IG9mIEFMTCB0YXhpbmcgYWdlbmNpZXMsIGluY2x1ZGluZyBUSUZzLCBTU0FzLCBldGMuDQoNCiMgYWxsIGFnZW5jeSBuYW1lcywgbnVtYmVycywgYW5kIHR5cGVzDQojIGluY2x1ZGVzIFRJRiBhbmQgbm9uLVRJRiBhZ2VuY2llcw0KYWxsX3RheGluZ19hZ2VuY2llcyA8LSBEQkk6OmRiR2V0UXVlcnkoDQogIHB0YXhzaW1fZGJfY29ubiwNCiAgIlNFTEVDVCBhZ2VuY3lfbnVtLCBhZ2VuY3lfbmFtZSwgbWFqb3JfdHlwZSwgbWlub3JfdHlwZQ0KICBGUk9NIGFnZW5jeV9pbmZvDQogICINCikgJT4lDQogIG11dGF0ZShmaXJzdDYgPSBzdHJfc3ViKGFnZW5jeV9udW0sMSw2KSwNCiAgICAgICAgIGZpcnN0NSA9IHN0cl9zdWIoYWdlbmN5X251bSwxLDUpKQ0KDQoNCm11bmlfYWdlbmN5X251bXM8LSBhbGxfdGF4aW5nX2FnZW5jaWVzICU+JSANCiAgZmlsdGVyKG1pbm9yX3R5cGUgJWluJSBjKCJNVU5JIikgfCANCiAgICAgICAgICAgYWdlbmN5X251bSA9PSAiMDIwMDYwMDAwIikgJT4lDQogICBzZWxlY3QoYWdlbmN5X251bSkNCg0KbXVuaV90YXhfY29kZXMgPC0gREJJOjpkYkdldFF1ZXJ5KA0KICBwdGF4c2ltX2RiX2Nvbm4sDQogIGdsdWVfc3FsKCINCiAgU0VMRUNUKg0KICBGUk9NIHRheF9jb2RlDQogIFdIRVJFIGFnZW5jeV9udW0gSU4gKHttdW5pX2FnZW5jeV9uYW1lcyRhZ2VuY3lfbnVtKn0pDQogIEFORCB5ZWFyID0gMjAyMQ0KICAiLA0KICAuY29uID0gcHRheHNpbV9kYl9jb25uDQogICkNCikjICU+JSBzZWxlY3QoLWFnZW5jeV9yYXRlKQ0KDQojIEFnZW5jeSBudW1iZXIgYW5kIGFnZW5jeSBuYW1lIGZvciBhbGwgVElGcw0KVElGX2FnZW5jaWVzIDwtIERCSTo6ZGJHZXRRdWVyeSgNCiAgcHRheHNpbV9kYl9jb25uLA0KICAiU0VMRUNUIERJU1RJTkNUIGFnZW5jeV9udW0sIGFnZW5jeV9uYW1lLCBtYWpvcl90eXBlLCBtaW5vcl90eXBlDQogIEZST00gYWdlbmN5X2luZm8NCiAgV0hFUkUgbWlub3JfdHlwZSA9ICdUSUYnDQogICINCikNCg0KdW5pcXVlX3RpZl90YXhjb2RlcyA8LSBEQkk6OmRiR2V0UXVlcnkoDQogIHB0YXhzaW1fZGJfY29ubiwgDQogIGdsdWVfc3FsKCINCiAgU0VMRUNUIERJU1RJTkNUIHRheF9jb2RlX251bQ0KICBGUk9NIHRheF9jb2RlDQogIFdIRVJFIGFnZW5jeV9udW0gSU4gKHtUSUZfYWdlbmNpZXMkYWdlbmN5X251bSp9KQ0KICBBTkQgeWVhciA9IDIwMjENCiAgIiwNCiAgLmNvbiA9IHB0YXhzaW1fZGJfY29ubg0KICApDQopDQoNCg0KDQojIyBSZWFkIGluIHN1bW1hcml6ZWQgdGF4IGNvZGUgbGV2ZWwgZGF0YSBmb3IgZXhlbXB0aW9ucyBhbmQgdGF4YmlsbHMuDQoNCnRheGJpbGxzX2J5X0NsYXNzX3Blcl9UQyA8LSAjcmVhZF9jc3YoInRheGJpbGxzX2luTXVuaXNfcGVyVEMuY3N2IikgICU+JSANCiAgcmVhZF9jc3YoIjJfU3VtbWVkX0JpbGxzX2J5X1RheGNvZGVfYW5kX0NsYXNzLmNzdiIpICU+JQ0KICBtdXRhdGUodGF4X2NvZGUgPSBhcy5jaGFyYWN0ZXIodGF4X2NvZGUpKSANCg0KDQojIGdldCByaWQgb2YgcnBtIHZhcmlhYmxlcywgdGF4X2FtdF9leGUscHJlIGFuZCBwb3N0IGV4ZW1wdGlvbiB2YXJpYWJsZXMsDQpleGVtcHRpb25zX2J5X2NsYXNzX3Blcl9UQyA8LSAjcmVhZF9jc3YoImFsbF9leGVtcHRpb25zX2J5X1RDLmNzdiIpICU+JQ0KICByZWFkX2NzdigiM19FeGVtcHRpb25zX0RldGFpbHNfb3V0cHV0LUNsYXNzVGF4Y29kZUV4ZW1wcy5jc3YiKSAlPiUNCiAgICBtdXRhdGUodGF4X2NvZGVfbnVtID0gYXMuY2hhcmFjdGVyKHRheF9jb2RlX251bSkpDQoNCnRpZl9kaXN0cmliIDwtIERCSTo6ZGJHZXRRdWVyeSgNCiAgcHRheHNpbV9kYl9jb25uLCANCiAgZ2x1ZV9zcWwoIg0KICBTRUxFQ1QgKg0KICBGUk9NIHRpZl9kaXN0cmlidXRpb24NCiAgV0hFUkUgdGF4X2NvZGVfbnVtIElOICh7bXVuaV90YXhfY29kZXMkdGF4X2NvZGVfbnVtKn0pDQogIEFORCB5ZWFyID0gMjAyMQ0KICAiLA0KICAuY29uID0gcHRheHNpbV9kYl9jb25uDQogICkNCikgJT4lIG11dGF0ZSh0YXhfY29kZV9udW0gPSBhcy5jaGFyYWN0ZXIodGF4X2NvZGVfbnVtKSkNCg0KDQoNCmFsbF90YXhpbmdfYWdlbmNpZXMgPC0gYWxsX3RheGluZ19hZ2VuY2llcyAlPiUgDQogIGxlZnRfam9pbihtdW5pX2FnZW5jeV9uYW1lcywgYnkgPSBjKCJmaXJzdDUiLCAiZmlyc3Q2IikpICU+JSANCiAgcmVuYW1lKG11bmlfbmFtZSA9ICBhZ2VuY3lfbmFtZS55LA0KICAgICAgICBtdW5pX251bSA9IGFnZW5jeV9udW0ueSwNCiAgICAgICAgYWdlbmN5X25hbWUgPSBhZ2VuY3lfbmFtZS54LA0KICAgICAgICBhZ2VuY3lfbnVtID0gYWdlbmN5X251bS54KQ0KDQoNCg0KDQoNCg0KIyMgQWRkIGFnZW5jeSBuYW1lcyBzaW5jZSB0aG9zZSB3ZXJlbid0IGluY2x1ZGVkIG9yaWdpbmFsbHkgaW4gdGhlIHRhYmxlOg0KDQojIGFsbF90YXhpbmdfYWdlbmNpZXMgPC0gYWxsX3RheGluZ19hZ2VuY2llcyAlPiUgDQojICAgbGVmdF9qb2luKG11bmlfYWdlbmN5X25hbWVzLCBieSA9IGMoImZpcnN0NSIsICJmaXJzdDYiKSkgJT4lIA0KIyAgIHJlbmFtZShtdW5pX25hbWUgPSAgYWdlbmN5X25hbWUueSwNCiMgICAgICAgICBtdW5pX251bSA9IGFnZW5jeV9udW0ueSwNCiMgICAgICAgICBhZ2VuY3lfbmFtZSA9IGFnZW5jeV9uYW1lLngsDQojICAgICAgICAgYWdlbmN5X251bSA9IGFnZW5jeV9udW0ueCkNCiMgDQoNCg0KIyBjb21iaW5lIHRheGluZyBhZ2VuY3kgbmFtZXMgYW5kIGFnZW5jeSB0eXBlIHRvIGRhdGEgdGFibGUgdGhhdCBoYXMgZWF2IGFuZCBleHRlbnNpb24gdmFsdWVzDQphZ2VuY3lfZGF0YSA8LSByaWdodF9qb2luKGFnZW5jeV9kdCwgYWxsX3RheGluZ19hZ2VuY2llcykgJT4lIA0KICAjIGdldCByaWQgb2YgdW5uZWVkZWQgY29sdW1ucyB0byBtYWtlIHRhYmxlIG91dHB1dHMgc21hbGxlcg0KICBzZWxlY3QoLWMoY3R5X2R1cGFnZV9lYXY6Y3R5X2xpdmluZ3N0b25fZWF2LCBsaW1fbnVtZXJhdG9yLCBsaW1fZGVub21pbmF0b3IpKSAlPiUgIyBkcm9wIHNvbWUgb2YgdGhlIHVudXNlZCB2YXJpYWJsZXMNCiAgYXJyYW5nZShhZ2VuY3lfbnVtKQ0KYGBgDQoNClRoaXMgdGFibGUgaXMgdXNlZCBmb3IgdGhlIG11bmljaXBhbGl0eSBsZXZ5IGluIGxhdGVyIGNhbGN1bGF0aW9ucy4NCg0KYGFnZW5jeV9kdGAgaGFzIGFsbCB0YXhpbmcgYWdlbmNpZXMgKGJ1dCBub3QgVElGcykgdGhhdCBleGlzdGVkIGVhY2ggeWVhciBhbmQgaW5jbHVkZXMgdGhlaXIgdG90YWwgdGF4YWJsZSBiYXNlIChjdHlfY29va19lYXYpLCB0aGVpciBsZXZ5LCB0YXhpbmcgcmF0ZSwgYmluYXJ5IHZhcmlhYmxlcyBmb3IgaWYgYSBtdW5pY2lwYWxpdHkgaXMgaG9tZSBydWxlIG9yIG5vdCwgYXMgd2VsbCBhcyBtYW55IG90aGVyIHZhcmlhYmxlcy4gQWxzbyBjdXJyZW50bHkgZG9lc24ndCBoYXZlIGFnZW5jeV9uYW1lcyB0byBnbyB3aXRoIHRoZSBhZ2VuY3kgbnVtYmVycy4gVGhhdCB3aWxsIGJlIG1lcmdlZCBpbiBzaG9ydGx5Lg0KDQpUaGVyZSBhcmUgMSw4NzggdGF4aW5nIGFnZW5jaWVzLiBXaGVuIGdyb3VwZWQgYnkgbWlub3JfdHlwZSwgdGhlcmUgYXJlIDEzMyBtdW5pIGFnZW5jaWVzLCA2MzkgdGlmIGFnZW5jaWVzLCAzMCB0b3duc2hpcHMsIGV0Yy4NCg0KPiBFdmVyeXRoaW5nIGRlcGVuZHMgb24gdGhlIHRheCBjb2Rlcy4NCg0KVXNpbmcgdGhlIGFnZW5jeSBudW1iZXJzIGZvciBlYWNoIG11bmljaXBhbGl0eSwgSSBwdWxsIGFsbCB0YXggY29kZXMgdGhhdCBoYXZlIGFuIGFnZW5jeV9udW0gaW5jbHVkZWQgaW4gdGhlIG11bmlfYWdlbmN5X25hbWVzIG9iamVjdC4gQnkgbmFycm93aW5nIHRoZSBhZ2VuY2llcyBkb3duIHRvIGp1c3QgTXVuaWNpcGFsaXR5IHR5cGVzLCB0aGlzIHByZXZlbnRzIGR1cGxpY2F0ZSB0YXhfY29kZXMgZnJvbSBiZWluZyBwdWxsZWQuDQoNClRoZXJlIGFyZSAzNzc0IHRheCBjb2RlcyB3aXRoaW4gQ29vayBDb3VudHkgdGhhdCBhcmUgdGF4ZWQgYnkgTXVuaWNpcGFsaXRpZXMuIFRoZXJlIGFyZSA0MjI4IHVuaXF1ZSB0YXggY29kZXMgaW4gQ29vayBDb3VudHkgaW4gMjAyMS4NCg0KRHJvcCBtdW5pY2lwYWxpdGllcyB3aGVyZSBtb3N0IG9mIHRoZSBFQVYgaXMgb3V0c2lkZSBvZiBDb29rIENvdW50eToNCg0KYGBge3J9DQpjcm9zc19jb3VudHlfbGluZXMgPC0gYygiMDMwNDQwMDAwIiwNCiIwMzA1ODUwMDAiLCAiMDMwODkwMDAwIiwgIjAzMDMyMDAwMCIsICIwMzEyODAwMDAiLCIwMzAwODAwMDAiLCAiMDMwNTYwMDAwIiwgIjAzMTEyMDAwMCIsICIwMzAyODAwMDAiLCAiMDMwMzQwMDAwIiwiMDMwMTUwMDAwIiwiMDMwMDUwMDAwIiwgIjAzMDE4MDAwMCIsIjAzMDUwMDAwMCIsIjAzMTIxMDAwMCINCikNCg0KIyBGcmFua2ZvcnQsIEhvbWVyIEdsZW5uLCBPYWsgQnJvb2sgYXJlIGJlbG93IDElIGluIENvb2sgQ291bnR5DQojIEVhc3QgRHVuZGVlLCBVbml2ZXJzaXR5IFBhcmssIEJlbnNlbnZpbGxlLCBIaW5zZGFsZSwgUm9lZWxsZSwgRGVlcmZpZWxkIGFyZSBiZWxvdyAxNSUgaW4gQ29vayBDb3VudHkNCg0KIyBBYm92ZSA1MCU6ICBidWZmYWxvIGdyb3ZlLCBiZXJ0bGV0dGUsIGJ1cnIgcmlkZ2UsIGhhbm92ZXIgcGFyaywgc3RlZ2VyLCANCiMgdGlubGV5IHBhcmssIGJhcnJpbmd0b24gaGlsbHMgYW5kIGJhcnJpbmd0b24sIGFuZCBwYXJrIGZvcmVzdCANCg0KIyBBTEwgYm9yZGVyIGNyb3NzZXJzOg0KI2Nyb3NzX2NvdW50eV9saW5lcyA8LSBjKCIwMzAwMzAwMDAiLCAiMDMwMDQwMDAwIiwgIjAzMDA1MDAwMCIsICIwMzAwODAwMDAiLCIwMzAxNTAwMDAiLCIwMzAxODAwMDAiLCAiMDMwMjgwMDAwIiwgIjAzMDMyMDAwMCIsIjAzMDM0MDAwMCIsICIwMzA0NDAwMDAiLCIwMzA1MDAwMDAiLCAiMDMwNTYwMDAwIiwgIjAzMDU4NTAwMCIsICIwMzA4OTAwMDAiLCAgIjAzMTAwMDAwMCIsIjAzMTEyMDAwMCIsIjAzMTIxMDAwMCIsIjAzMTI3MDAwMCIsICIwMzEyODAwMDAiKQ0KDQoNCiMgTXVuaWNpcGFsaXRpZXMgfCBUcmlhZCB8IGFnZW5jeV9udW0gDQojIA0KIyBDSVRZIE9GIEVMR0lOIE5vcnRoICAgMzAzNDAwMDAgIA0KIyBWSUxMQUdFIE9GIEJBUlJJTkdUT04gTm9ydGggICAzMDAzMDAwMCAgDQojIFZJTExBR0UgT0YgQkFSUklOR1RPTiBISUxMUyAgIE5vcnRoICAgMzAwNDAwMDAgIA0KIyBWSUxMQUdFIE9GIEJBUlRMRVRUICAgTm9ydGggICAzMDA1MDAwMCAgDQojIFZJTExBR0UgT0YgQkVOU0VOVklMTEUgICAgTkEgIDMwMDgwMDAwICANCiMgVklMTEFHRSBPRiBCVUZGQUxPIEdST1ZFICBOb3J0aCAgIDMwMTUwMDAwICANCiMgVklMTEFHRSBPRiBCVVJSIFJJREdFIFNvdXRoICAgMzAxODAwMDAgIA0KIyBWSUxMQUdFIE9GIERFRVJGSUVMRCAgTkEgIDMwMjgwMDAwICANCiMgVklMTEFHRSBPRiBFQVNUIERVTkRFRSAgICBOQSAgMzAzMjAwMDAgIA0KIyBWSUxMQUdFIE9GIEZSQU5LRk9SVCAgTkEgIDMwNDQwMDAwICANCiMgVklMTEFHRSBPRiBIQU5PVkVSIFBBUksgICBOb3J0aCAgIDMwNTAwMDAwICANCiMgVklMTEFHRSBPRiBISU5TREFMRSAgIFNvdXRoICAgMzA1NjAwMDAgIA0KIyBWSUxMQUdFIE9GIEhPTUVSIEdMRU4gTkEgIDMwNTg1MDAwICANCiMgVklMTEFHRSBPRiBPQUsgQlJPT0sgIE5BICAzMDg5MDAwMCAgDQojIFZJTExBR0UgT0YgUEFSSyBGT1JFU1QgICAgU291dGggICAzMTAwMDAwMCAgDQojIFZJTExBR0UgT0YgUk9TRUxMRSAgICBOb3J0aCAgIDMxMTIwMDAwICANCiMgVklMTEFHRSBPRiBTVEVHRVIgU291dGggICAzMTIxMDAwMCAgDQojIFZJTExBR0UgT0YgVElOTEVZIFBBUksgICAgU291dGggICAzMTI3MDAwMCAgDQojIFZJTExBR0UgT0YgVU5JVkVSU0lUWSBQQVJLICAgIE5BICAzMTI4MDAwMCAgDQpgYGANCg0KIyBQcm9wb3J0aW9uIG9mIFJlc2lkZW50aWFsIExhbmQgaW4gTXVuaWNpcGFsaXRpZXMgey50YWJzZXQgLnRhYnNldC1waWxsc30NCg0KdXNpbmcgdGhlIHBpbiBkYXRhIGZyb20gcHRheHNpbSwgSSBjYWxjdWxhdGUgdGhlIGVhdiBvZiBhbGwgcHJvcGVydGllcywgZXhlbXB0IEVBViwgdGhlIGN1cnJlbnQgdGF4YmFzZSwgYW5kIHRheGJhc2UgaWYgdGhlcmUgd2VyZSBub3QgZXhlbXB0aW9ucw0KDQotICAgZXhlbXB0IEVBViAoc3VtbWVkIGZyb20gYWxsIGV4ZW1wdGlvbiB0eXBlcykNCg0KLSAgIGN1cnJlbnQgdGF4YmFzZSAodXNpbmcgdGhlIGB0aWZfZGlzdHJpYmAgdGFibGUgYW5kIHBlcmNlbnQgb2YgdGF4Y29kZSByZXYgdGhhdCBnb2VzIHRvIHRoZSB0aWYpLiBJZiBhIHRheGNvZGUgaXMgYSBUSUYgdGF4Y29kZSwgdGhlbiBkbyAoRUFWLWV4ZW1wdCBFQVYpIFwqICgxLSVyZXYgdGhhdCBnb2VzIHRvIFRJRikuIElmIHRoZSB0YXggY29kZSBpcyBub3QgYSBUSUYgdGF4IGNvZGUsIHRoZW4gdXNlIHRoZSBFQVYtZXhlbXB0IEVBVi4NCg0KLSAgIHRheCBiYXNlIHdpdGhvdXQgZXhlbXB0aW9uczogSWYgYSB0YXhjb2RlIGlzIGEgVElGIHRheGNvZGUsIHRoZW4gZG8gRUFWIFwqICgxLSVyZXYgdGhhdCBnb2VzIHRvIFRJRikuIElmIHRoZSB0YXggY29kZSBpcyBub3QgYSBUSUYgdGF4IGNvZGUsIHRoZW4gdXNlIHRoZSBlYXYNCg0KPiBKb2luaW5nIHByb2JsZW06IGluIGBtdW5pX2FnZW5jeV9uYW1lc2AsIENpY2VybyBpcyBjYWxsZWQgIlRPV04gQ0lDRVJPIiwgaW4gbWFwIHNoYXBlZmlsZSBpdCBpcyBjYWxsZWQgIkNJVFkgT0YgQ0lDRVJPIi4NCg0KYGBge3J9DQpjbGFzc19kaWN0IDwtIHJlYWRfY3N2KCJjbGFzc19kaWN0X2V4cGFuZGVkLmNzdiIpDQoNCiMgdXNlIGV4ZW1wdGlvbnMgaW4gdGF4IGNvZGVzIHRvIHN1bW1hcml6ZSBFQVYuIA0KIyBNb3JlIGFjY3VyYXRlIHRoYXQgY2FsY3VsYXRpbmcgaXQgZnJvbSByZXZlbnVlIGNvbGxlY3RlZC50YXggcmF0ZSBpbiB0YXggYmlsbCBkYXRhDQpleGVtcHRpb25zX2J5X2NsYXNzX3Blcl9UQyA8LSByZWFkX2NzdigiM19FeGVtcHRpb25zX0RldGFpbHNfb3V0cHV0LUNsYXNzVGF4Y29kZUV4ZW1wcy5jc3YiKSAlPiUgDQogIGZpbHRlcihjbGFzc19jb2RlICE9ICIwIikgJT4lDQogIGxlZnRfam9pbihjbGFzc19kaWN0KSAlPiUNCiAgbXV0YXRlKHRheF9jb2RlX251bSA9IGFzLmNoYXJhY3Rlcih0YXhfY29kZV9udW0pKSAlPiUNCiAgbGVmdF9qb2luKG11bmlfdGF4X2NvZGVzKSAlPiUNCiAgZnVsbF9qb2luKG11bmlfYWdlbmN5X25hbWVzKSAlPiUNCiAgbGVmdF9qb2luKG5pY2tuYW1lcywgYnkgPSBjKCJhZ2VuY3lfbmFtZSIgPSAiYWdlbmN5X25hbWUiKSkgJT4lDQogIGZpbHRlcighYWdlbmN5X251bSAlaW4lIGNyb3NzX2NvdW50eV9saW5lcykgJT4lDQogIA0KICAjIG1lcmdlIHdpdGggVElGIGRpc3RyaWIgdGFibGUgdG8gY2FsY3VsYXRlIHRoZSBwZXJjZW50IG9mIHRoZSBFQVYgdGhhdCBnb2VzIHRvIHRoZSBUSUYgdnMgdGhlIGRpc3RyaWN0DQogIGxlZnRfam9pbih0aWZfZGlzdHJpYiwgYnk9YygidGF4X2NvZGVfbnVtIiwgInllYXIiLCAidGF4X2NvZGVfcmF0ZSIpKSAlPiUNCiAgbXV0YXRlKGV4ZW1wdF9FQVYgPSAoZXhlX2hvbWVvd25lciArIGV4ZV9zZW5pb3IgKyBleGVfZnJlZXplICsgZXhlX2xvbmd0aW1lX2hvbWVvd25lciArIA0KICAgICAgICAgZXhlX2Rpc2FibGVkICsgZXhlX3ZldF9yZXR1cm5pbmcgKyBleGVfdmV0X2RpcyArIGV4ZV9hYmF0ZSkgLA0KICAgICAgICAgaW5fVElGID0gaWZlbHNlKHRheF9jb2RlX251bSAlaW4lIHVuaXF1ZV90aWZfdGF4Y29kZXMkdGF4X2NvZGVfbnVtLCAxLCAwKSwNCiAgICAgICAgIHRheF9iYXNlX2N1cnJlbnQgPSBpZmVsc2UoaW5fVElGPT0xLCAoZWF2LWV4ZW1wdF9FQVYpKigxLXRheF9jb2RlX2Rpc3RyaWJ1dGlvbl9wY3QvMTAwKSwgZWF2LWV4ZW1wdF9FQVYpLA0KICAgICAgICAgdGF4X2Jhc2Vfbm9leGVtcHMgPSBpZmVsc2UoaW5fVElGPT0xLCAoZWF2KSooMS10YXhfY29kZV9kaXN0cmlidXRpb25fcGN0LzEwMCksIGVhdiksDQogICAgICAgICBSZXNpZGVudGlhbFByb3BzID0gaWZlbHNlKG1ham9yX2NsYXNzX2NvZGUgJWluJSBjKCIyIiwgIjMiLCAiOSIpLCAiUmVzaWRlbnRpYWwiLCAiQ29tbWVyY2lhbCIpKSANCiMsDQogICAgICAgICAjIA0KICAgICAgICAgIyBQcm9wVHlwZSA9IGNhc2Vfd2hlbigNCiAgICAgICAgICMgICBtYWpvcl9jbGFzc19jb2RlICVpbiUgYygiMyIsIjkiKSB+ICJNdWx0aS1GYW1pbHkiLA0KICAgICAgICAgIyAgIG1ham9yX2NsYXNzX2NvZGUgPT0gIjIiIH4gIlNpbmdsZS1GYW1pbHkiLA0KICAgICAgICAgIyAgIFRSVUV+ICJDb21tZXJjaWFsLUluZHVzdHJpYWwiKQ0KICAgICAgICAgDQpgYGANCg0KX19FeGVtcHRpb25zIHdpdGhpbiBlYWNoIG11bmljaXBhbGl0eTpfXw0KDQoNClBlcmNlbnQgUmVzaWRlbnRpYWwgaXMgdGhlIFJlc2lkZW50aWFsIEVBViBvdXRzaWRlIG9mIFRJRnMgLyBNdW5pY2lwYWxpdHkgRUFWIG91dHNpZGUgb2YgVElGcy4NCg0KDQpgYGB7cn0NCmdyb3VwZWRfZXhlbXB0aW9ucyA8LSBleGVtcHRpb25zX2J5X2NsYXNzX3Blcl9UQyAlPiUgDQogICAjIGdyb3VwX2J5KGFnZW5jeV9uYW1lLCBtYWpvcl9jbGFzc19jb2RlLCBtYWpvcl9jbGFzc190eXBlLCBSZXNpZGVudGlhbFByb3BzLCBQcm9wVHlwZSkgJT4lDQogIGdyb3VwX2J5KGNsZWFuX25hbWUsIFJlc2lkZW50aWFsUHJvcHMsIGFnZW5jeV9uYW1lLCBhZ2VuY3lfbnVtLngpICU+JQ0KICBzdW1tYXJpemUoZWF2ID0gc3VtKGVhdiksDQogICAgICAgICAgIGV4ZW1wdF9FQVYgPSBzdW0oZXhlbXB0X0VBViwgZXhlX2FiYXRlLCBuYS5ybT1UUlVFKSwNCiAgICAgICAgIHRheF9iYXNlX2N1cnJlbnQgPSBzdW0odGF4X2Jhc2VfY3VycmVudCwgbmEucm09VFJVRSksDQogICAgICAgICB0YXhfYmFzZV9ub2V4ZW1wcyA9IHN1bSh0YXhfYmFzZV9ub2V4ZW1wcywgbmEucm09VFJVRSkpICU+JSB1bmdyb3VwKCkgJT4lIHNlbGVjdChjbGVhbl9uYW1lLCBlYXYsIGV4ZW1wdF9FQVYsIGV2ZXJ5dGhpbmcoKSkNCiAgDQpncm91cGVkX2V4ZW1wdGlvbnMgDQoNCiMgY2FsY3VsYXRlIHRvdGFscyB3aXRoIE9OTFkgRUFWIG91dHNpZGUgb2YgVElGcw0KbXVuaV9lYXYgPC0gZ3JvdXBlZF9leGVtcHRpb25zICU+JSAgDQogIGdyb3VwX2J5KGNsZWFuX25hbWUsIGFnZW5jeV9uYW1lLCBhZ2VuY3lfbnVtLngpICU+JSANCiAgc3VtbWFyaXplKG11bmlfRUFWX2luY2x1ZGVzVElGID0gc3VtKGVhdiksICMgYWxsIEVBViBpbiB0aGUgbXVuaWNpcGFsaXR5IHRoYXQgZXhpc3RzDQogICAgICAgICAgICBtdW5pX3RheF9iYXNlX2N1cnJlbnQ9c3VtKHRheF9iYXNlX2N1cnJlbnQpLCAjIHRheGFibGUgRUFWIGJhc2VkIG9uIGN1cnJlbnQgZXhlbXB0aW9ucw0KICAgICAgICAgICAgbXVuaV90YXhfYmFzZV9ub2V4ZW1wcyA9IHN1bSh0YXhfYmFzZV9ub2V4ZW1wcykpICU+JSAgIyB0YXhhYmxlIEVBViBwcmUtZXhlbXB0aW9ucw0KICB1bmdyb3VwKCkgDQoNCnBlcmNfcmVzaWRlbnRpYWwgPC0gZnVsbF9qb2luKGdyb3VwZWRfZXhlbXB0aW9ucywgbXVuaV9lYXYpICU+JSANCiAgZmlsdGVyKFJlc2lkZW50aWFsUHJvcHMgPT0gIlJlc2lkZW50aWFsIikgJT4lIA0KICANCiAgbXV0YXRlKHBlcmNlbnRfcmVzaWRlbnRpYWwgPSBlYXYgLyBtdW5pX0VBVl9pbmNsdWRlc1RJRikjICU+JSBzZWxlY3QoKQ0KDQoNCiMgaW4gdGhpcyBzdGFnZSwgQmVuc2VudmlsbGUsIEVhc3QgRHVuZGVlLCBhbmQgSG9tZXIgR2xlbiB3ZXJlIGRyb3BwZWQuIFRoaXMgaXMgZmluZSBiZWNhdXNlIEkgd2FzIGdvaW5nIHRvIGRyb3AgdGhlbSBsYXRlciBhbnl3YXlzLiBUaGV5IGRvbid0IGhhdmUgcmVzaWRlbnRpYWwgRUFWIHdpdGhpbiBDb29rIENvdW50eS4NCg0KcGVyY19yZXNpZGVudGlhbA0KDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KGdncGF0dGVybikNCmBgYA0KDQoNCiMjIFJlc2lkZW50aWFsIChPbmx5IENsYXNzIDIpDQoNCmBgYHtyIGluY2x1ZGUgPSBGQUxTRX0NCmNvb2tfZWF2IDwtIGV4ZW1wdGlvbnNfYnlfY2xhc3NfcGVyX1RDICU+JSBmaWx0ZXIobWFqb3JfY2xhc3NfY29kZSA9PSAyKSAlPiUgc3VtbWFyaXplKGVhdiA9IHN1bShlYXYsbmEucm09VFJVRSkpDQpgYGANCg0KSW4gQ29vayBDb3VudHkgdGhlcmUgaXMgYHIgc2NhbGVzOjpkb2xsYXIoY29va19lYXYkZWF2KWAgaW4gQ2xhc3MgMiBSZXNpZGVudGlhbCBQcm9wZXJ0eSBFQVYuIE5vdGU6IENsYXNzIDIgcHJvcGVydGllcyBpbmNsdWRlIHNpbmdsZS1mYW1pbHkgZGV0YWNoZWQgaG9tZXMsIGNvbmRvcywgYW5kIHNvbWUgcmVudGFsIGJ1aWxkaW5ncy4gDQoNCmBgYHtyIGZpZy5jYXA9IlRoZSBtZWRpYW4gbXVuaWNpcGFsaXR5IGhhcyA2Ni44NCUgb2YgaXRzIEVBViBmcm9tIFJlc2lkZW50aWFsIENsYXNzIDIgUHJvcGVydGllcy4gVG90YWwgRUFWIGluY2x1ZGVzIGZyb3plbiBFQVYgJiBUSUYgaW5jcmVtZW50cywgYW5kIGFsbCBleGVtcHQgRUFWLiJ9DQoNCg0KIyBDbGFzcyAyIG9ubHkNCmNsYXNzMl9wZXJjIDwtIGV4ZW1wdGlvbnNfYnlfY2xhc3NfcGVyX1RDICU+JSANCiAgICBmaWx0ZXIobWFqb3JfY2xhc3NfY29kZSA9PSAyKSAlPiUNCiAgZ3JvdXBfYnkoY2xlYW5fbmFtZSwgbWFqb3JfY2xhc3NfY29kZSwgYWdlbmN5X25hbWUsIGFnZW5jeV9udW0ueCkgJT4lDQogIHN1bW1hcml6ZShlYXYgPSBzdW0oZWF2KSwNCiAgICAgICAgICAgZXhlbXB0X0VBViA9IHN1bShleGVtcHRfRUFWLCBleGVfYWJhdGUsIG5hLnJtPVRSVUUpLA0KICAgICAgICAgdGF4X2Jhc2VfY3VycmVudCA9IHN1bSh0YXhfYmFzZV9jdXJyZW50LCBuYS5ybT1UUlVFKSwNCiAgICAgICAgIHRheF9iYXNlX25vZXhlbXBzID0gc3VtKHRheF9iYXNlX25vZXhlbXBzLCBuYS5ybT1UUlVFKSkgJT4lIA0KICBsZWZ0X2pvaW4obXVuaV9lYXYpICU+JQ0KICBtdXRhdGUocGVyY19jbGFzczJfdG90YWxFQVYgPSBlYXYgLyBtdW5pX0VBVl9pbmNsdWRlc1RJRikgJT4lICAgIA0KICBtdXRhdGUoYWdlbmN5X25hbWUgPSBpZmVsc2UoYWdlbmN5X25hbWUgPT0gIlRPV04gQ0lDRVJPIiwgIkNJVFkgT0YgQ0lDRVJPIiwgYWdlbmN5X25hbWUpICkNCg0KDQoNCmNsYXNzMl9wZXJjICU+JQ0KICBmdWxsX2pvaW4obXVuaV9zaHAsIGJ5ID0gYygiYWdlbmN5X25hbWUiID0gIkFHRU5DWV9ERVNDIikpICU+JQ0KICBnZ3Bsb3QoYWVzKGZpbGwgPSBwZXJjX2NsYXNzMl90b3RhbEVBVikpICsgDQogIGdlb21fc2YoYWVzKGdlb21ldHJ5ID0gZ2VvbWV0cnkpLCBjb2xvciA9ICJibGFjayIpICsgDQogIGxhYnModGl0bGUgPSAiQ2xhc3MgMiBQcm9wZXJ0eSBFQVYgLyAgVG90YWwgRUFWIGluIE11bmljaXBhbGl0eSIsIA0KICBjYXB0aW9uID0gIiIpICsNCiAgdGhlbWVfdm9pZCgpICsgDQogIHRoZW1lKGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSkrIyArIysNCiAgc2NhbGVfZmlsbF9zdGVwczIoDQogICAgaGlnaCA9ICJkYXJrYmx1ZSIsIGxvdyA9ICJibGFjayIsDQogICAgbWlkcG9pbnQgPSBtZWRpYW4oY2xhc3MyX3BlcmMkcGVyY19jbGFzczJfdG90YWxFQVYpLA0KICAjICBicmVha3MgPSBicmVha3Nfc2QsICAjIHRyaWVkIHRvIGRvIGJyZWFrcyBiYXNlZCBvbiBzdGFuZGFyZCBkZXZpYXRpb24gYnV0IG1hcCBkb2VzIHRoYXQgaW4gYW4gZWFzaWVyIHdheSBieSBzZXR0aW5nIHRoZSBtaWRwb2ludC4NCiAgbmEudmFsdWUgPSAid2hpdGUiLA0KICAgIG5pY2UuYnJlYWtzID0gRkFMU0UsDQogICAgc2hvdy5saW1pdHM9VFJVRSwNCiAgICBuYW1lID0gIiUgUmVzaWRlbnRpYWwiLA0KICAgIGxhYmVscyA9IHNjYWxlczo6cGVyY2VudCkNCmBgYA0KDQoNCg0KYGBge3J9DQpDb29rX2xheWVyIDwtIGdncGxvdChkYXRhID0gY29va19zaHAsYWVzKGdlb21ldHJ5ID0gZ2VvbWV0cnkpKSArIA0KICBnZW9tX3NmX3BhdHRlcm4oKSArIHRoZW1lX3ZvaWQoKQ0KDQoNCmNsYXNzMl9wZXJjICU+JQ0KICBmdWxsX2pvaW4obXVuaV9zaHAsIGJ5ID0gYygiYWdlbmN5X25hbWUiID0gIkFHRU5DWV9ERVNDIikpICU+JQ0KICBnZ3Bsb3QoKSArIA0KICBnZW9tX3NmX3BhdHRlcm4oZGF0YSA9IGNvb2tfc2hwLCBhZXMoZ2VvbWV0cnkgPSBnZW9tZXRyeSksICBwYXR0ZXJuX2FscGhhID0gMC4xLCANCiAgICAgICAgICAgICAgICAgcGF0dGVybl9zY2FsZSA9IC41LCANCiAgICAgICAgICAgICAgICAgIHBhdHRlcm5fYW5nbGUgPSA0NSwgcGF0dGVybl9maWxsID0gTkEsIA0KICAgICAgICAgICAgICAjcGF0dGVybl9kZW5zaXR5ID0gLjUsIA0KICAgICAgICAgICAgICBwYXR0ZXJuX3NwYWNpbmcgPSAuMDINCiAgICAgICAgICAgICAgICAgICkgKyANCiAgZ2VvbV9zZihhZXMoZ2VvbWV0cnkgPSBnZW9tZXRyeSwgZmlsbCA9IHBlcmNfY2xhc3MyX3RvdGFsRUFWKSwgY29sb3IgPSAiYmxhY2siKSArIA0KICBsYWJzKHRpdGxlID0gIkNsYXNzIDIgUHJvcGVydHkgRUFWIC8gIFRvdGFsIEVBViBpbiBNdW5pY2lwYWxpdHkiLCANCiAgY2FwdGlvbiA9ICIiKSArDQogIHRoZW1lX3ZvaWQoKSArIA0KICB0aGVtZShheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCkpKyMgKyMrDQogIHNjYWxlX2ZpbGxfc3RlcHMyKA0KICAgIGhpZ2ggPSAiZGFya2JsdWUiLCBsb3cgPSAibWFyb29uIiwNCiAgICBtaWRwb2ludCA9IG1lZGlhbihjbGFzczJfcGVyYyRwZXJjX2NsYXNzMl90b3RhbEVBViksDQogICMgIGJyZWFrcyA9IGJyZWFrc19zZCwgICMgdHJpZWQgdG8gZG8gYnJlYWtzIGJhc2VkIG9uIHN0YW5kYXJkIGRldmlhdGlvbiBidXQgbWFwIGRvZXMgdGhhdCBpbiBhbiBlYXNpZXIgd2F5IGJ5IHNldHRpbmcgdGhlIG1pZHBvaW50Lg0KICBuYS52YWx1ZSA9IE5BLA0KICAgIG5pY2UuYnJlYWtzID0gRkFMU0UsDQogICAgc2hvdy5saW1pdHM9VFJVRSwNCiAgICBuYW1lID0gIiUgUmVzaWRlbnRpYWwiLA0KICAgIGxhYmVscyA9IHNjYWxlczo6cGVyY2VudCkNCmBgYA0KDQpfX1BlcmNlbnQgb2YgQ2xhc3MgMiBFQVYgdGhhdCBpcyB0YXggZXhlbXB0OiBFeGVtcHQgRUFWIC8gUmVzaWRlbnRpYWwgRUFWX18NCg0KYGBge3IgZmlnLmNhcD0gIk1lZGlhbiB2YWx1ZSBmb3Igc2luZ2xlLWZhbWlseSBFQVYgaXMgMjAuNzYlLiIsIGZpZy5zaG93PSJob2xkIiwgb3V0LndpZHRoID0gIjUwJSJ9DQoNCmV4ZW1wdGlvbnNfdG9fY2xhc3MyRUFWX3JhdGlvcyA8LSBjbGFzczJfcGVyYyAlPiUgDQogIG11dGF0ZShleGVtcHRFQVZfcGN0b2ZfcmVzRUFWID0gZXhlbXB0X0VBVi9lYXYsDQogICAgICAgICBub250aWZfcmF0aW8gPSBleGVtcHRfRUFWIC8gdGF4X2Jhc2Vfbm9leGVtcHMpICU+JSANCiAgc2VsZWN0KGFnZW5jeV9uYW1lLCBjbGVhbl9uYW1lLCBleGVtcHRFQVZfcGN0b2ZfcmVzRUFWLCBub250aWZfcmF0aW8pICU+JSANCiAgYXJyYW5nZShub250aWZfcmF0aW8pDQoNCmV4ZW1wdGlvbnNfdG9fY2xhc3MyRUFWX3JhdGlvcyAlPiUNCiAgICBtdXRhdGUoYWdlbmN5X25hbWUgPSBpZmVsc2UoYWdlbmN5X25hbWUgPT0gIlRPV04gQ0lDRVJPIiwgIkNJVFkgT0YgQ0lDRVJPIiwgYWdlbmN5X25hbWUpICkgJT4lDQogbGVmdF9qb2luKG11bmlfc2hwLCBieSA9IGMoImFnZW5jeV9uYW1lIiA9ICJBR0VOQ1lfREVTQyIpKSAlPiUNCiAgZ2dwbG90KGFlcyhmaWxsID0gZXhlbXB0RUFWX3BjdG9mX3Jlc0VBVikpICsgDQogIGdlb21fc2YoYWVzKGdlb21ldHJ5ID0gZ2VvbWV0cnkpLCBjb2xvciA9ICJibGFjayIpICsgdGhlbWVfdm9pZCgpKyANCiAgbGFicyh0aXRsZSA9ICJFeGVtcHRpb25zIC8gUmVzaWRlbnRpYWwgRUFWIChpbiBhbmQgb3V0IG9mIFRJRnMpIikgKw0KICAgIHRoZW1lX3ZvaWQoKSArIA0KICB0aGVtZShheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCkpKw0KICAgc2NhbGVfZmlsbF9zdGVwczIoaGlnaCA9ICJkYXJrYmx1ZSIsIGxvdyA9ICJibGFjayIsIA0KICAgICAgICAgICAgICAgICAgICAgICMgbGltaXRzID0gYygwLC44KSwNCiAgICAgICAgICAgICAgICAgICAgICAgbi5icmVha3MgPSA3LCBzaG93LmxpbWl0cz1UUlVFLA0KICAgICAgICAgICAgICAgICAgICBuaWNlLmJyZWFrcyA9IEZBTFNFLA0KICAgICAgICAgICAgICAgICAgICBtaWRwb2ludCA9IG1lZGlhbihleGVtcHRpb25zX3RvX2NsYXNzMkVBVl9yYXRpb3MkZXhlbXB0RUFWX3BjdG9mX3Jlc0VBViksDQogICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gIiUgUmVzaWRlbnRpYWwgRUFWIFxudGhhdCBpcyBleGVtcHQiLCBsYWJlbCA9IHNjYWxlczo6cGVyY2VudCkNCg0KDQpleGVtcHRpb25zX3RvX2NsYXNzMkVBVl9yYXRpb3MgJT4lDQogICAgbXV0YXRlKGFnZW5jeV9uYW1lID0gaWZlbHNlKGFnZW5jeV9uYW1lID09ICJUT1dOIENJQ0VSTyIsICJDSVRZIE9GIENJQ0VSTyIsIGFnZW5jeV9uYW1lKSApICU+JQ0KICBsZWZ0X2pvaW4obXVuaV9zaHAsIGJ5ID0gYygiYWdlbmN5X25hbWUiID0gIkFHRU5DWV9ERVNDIikpICU+JQ0KICBnZ3Bsb3QoYWVzKGZpbGwgPSBub250aWZfcmF0aW8pKSArIA0KICBnZW9tX3NmKGFlcyhnZW9tZXRyeSA9IGdlb21ldHJ5KSwgY29sb3IgPSAiYmxhY2siKSArIHRoZW1lX3ZvaWQoKSsgDQogIGxhYnModGl0bGUgPSAiTm9uLVRJRiBFQVYgb25seTogSG9tZXN0ZWFkIEV4ZW1wdGlvbnMgLyBSZXNpZGVudGlhbCBFQVYiLCBjYXB0aW9uID0gIlZpbGxhZ2Ugb2YgUGhvZW5peCBza2V3cyBncmFwaC4gRHJvcHBlZCBpbiBtYXAgYmVsb3ciKSArDQogICAgdGhlbWVfdm9pZCgpICsgDQogIHRoZW1lKGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSkrDQogICBzY2FsZV9maWxsX3N0ZXBzMihoaWdoID0gImRhcmtibHVlIiwgbG93ID0gImJsYWNrIiwNCiAgICAgI2NvbG9ycyA9IGMoIndoaXRlIiwgImRhcmtibHVlIiksIA0KICAgICAgICAgICAgICAgICAgICAgICMgbGltaXRzID0gYygwKSwNCiAgICAgICAgICAgICAgICAgICAgbWlkcG9pbnQgPSBtZWRpYW4oZXhlbXB0aW9uc190b19jbGFzczJFQVZfcmF0aW9zJG5vbnRpZl9yYXRpbyksDQogICAgICAgICAgICAgICAgICAgICAgIG4uYnJlYWtzID0gNywgDQogICAgIHNob3cubGltaXRzPVRSVUUsDQogICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gIiUgUmVzaWRlbnRpYWwgRUFWIFxudGhhdCBpcyBleGVtcHQiLCBsYWJlbCA9IHNjYWxlczo6cGVyY2VudCkgKyANCiAgbGFicyggY2FwdGlvbiA9ICJNZWRpYW4gdmFsdWUgaXMgMjAuODUlICIpDQpgYGANCg0KDQpgYGB7ciBmaWcuY2FwPSJEcm9wcyBWaWxsYWdlIG9mIFBob2VuaXggYmVjYXVzZSBpdCBza2V3cyBtYXAgY29sb3JzICg3OCUgb2YgdGhlaXIgcmVzaWRlbnRpYWwgRUFWIGlzIHRheCBleGVtcHQpLiBNZWRpYW4gbXVuaWNpcGFsaXR5IGNhbiBub3QgZ2V0IHRheCByZXZlbnVlIGZyb20gMS81dGggb2YgdGhlaXIgcmVzaWRlbnRpYWwgRUFWIGR1ZSB0byBleGVtcHRpb25zLiAyMC44NSUgb2YgU2luZ2xlLWZhbWlseSBob21lIEVBViBpcyBub3QgdGF4ZWQgYW5kIHRyYW5zZmVycmVkIHRvIG90aGVyIHRheCBwYXllcnMuIn0NCiAgDQpleGVtcHRpb25zX3RvX2NsYXNzMkVBVl9yYXRpb3MgJT4lICBmaWx0ZXIobm9udGlmX3JhdGlvPC42KSAlPiUNCiAgICBtdXRhdGUoYWdlbmN5X25hbWUgPSBpZmVsc2UoYWdlbmN5X25hbWUgPT0gIlRPV04gQ0lDRVJPIiwgIkNJVFkgT0YgQ0lDRVJPIiwgYWdlbmN5X25hbWUpICkgJT4lDQogIGxlZnRfam9pbihtdW5pX3NocCwgYnkgPSBjKCJhZ2VuY3lfbmFtZSIgPSAiQUdFTkNZX0RFU0MiKSkgJT4lDQogIGdncGxvdChhZXMoZmlsbCA9IG5vbnRpZl9yYXRpbykpICsgDQogIGdlb21fc2YoYWVzKGdlb21ldHJ5ID0gZ2VvbWV0cnkpLCBjb2xvciA9ICJibGFjayIpICsgdGhlbWVfdm9pZCgpKyANCiAgbGFicyh0aXRsZSA9ICJQZXJjZW50IG9mIFJlc2lkZW50aWFsIEVBViB0aGF0IGlzIFRheCBFeGVtcHQiLCANCiAgc3VidGl0bGUgPSAiJSBvZiBOb24tVElGIFJlc2lkZW50aWFsIEVBViBvbmx5OiBcbkhvbWVzdGVhZCBFeGVtcHRpb25zIC8gUmVzaWRlbnRpYWwgRUFWIiwgDQogIGNhcHRpb24gPSAiIikgKw0KICAgIHRoZW1lX3ZvaWQoKSArIA0KICB0aGVtZShheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCkpKw0KICAgc2NhbGVfZmlsbF9zdGVwczIoaGlnaCA9ICJkYXJrYmx1ZSIsIGxvdyA9ICJibGFjayIsDQogICAjICBjb2xvcnMgPSBjKCJ3aGl0ZSIsICJkYXJrYmx1ZSIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygwLC40KSwNCiAgIG1pZHBvaW50ID0gbWVkaWFuKGV4ZW1wdGlvbnNfdG9fY2xhc3MyRUFWX3JhdGlvcyRub250aWZfcmF0aW8pLA0KICAgICAgICAgICAgICAgICAgICAgICBuLmJyZWFrcyA9IDcsIHNob3cubGltaXRzPVRSVUUsDQogICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gIiUgUmVzaWRlbnRpYWwgRUFWIFxudGhhdCBpcyB0YXggZXhlbXB0IiwgbGFiZWwgPSBzY2FsZXM6OnBlcmNlbnQpDQpgYGANCg0KDQojIyBSZXNpZGVudGlhbCAoQ2xhc3MgMiwgMywgJiA5KQ0KDQoNClRoZSBtZWRpYW4gYW1vdW50IG9mIEVBViBmcm9tIHJlc2lkZW50aWNhbCBwYXJjZWxzIGlzIGByIHNjYWxlczo6cGVyY2VudChtZWRpYW4ocGVyY19yZXNpZGVudGlhbCRwZXJjZW50X3Jlc2lkZW50aWFsKSlgLg0KDQpgYGB7cn0NCnZhcmlhYmxlIDwtIHBlcmNfcmVzaWRlbnRpYWwkcGVyY2VudF9yZXNpZGVudGlhbA0KDQpicmVha3Nfc2QgPSBjKA0KICAobWVkaWFuKHZhcmlhYmxlKS0yLjUqc2QodmFyaWFibGUpKSwNCiAgKG1lZGlhbih2YXJpYWJsZSktMS41KnNkKHZhcmlhYmxlKSksDQogIG1lZGlhbih2YXJpYWJsZSktLjUqc2QodmFyaWFibGUpLA0KICBtZWRpYW4odmFyaWFibGUpLA0KICBtZWRpYW4odmFyaWFibGUpKy41KnNkKHZhcmlhYmxlKSwNCiAgbWVkaWFuKHZhcmlhYmxlKSsxLjUqc2QodmFyaWFibGUpLA0KICBtZWRpYW4odmFyaWFibGUpKzIuNSpzZCh2YXJpYWJsZSkpDQoNCg0KDQojIGNsYXNzIDIsIDMsIDkgY29tYmluZWQNCnBlcmNfcmVzaWRlbnRpYWwgJT4lIA0KICBncm91cF9ieShSZXNpZGVudGlhbFByb3BzKSU+JQ0KICAgIG11dGF0ZShhZ2VuY3lfbmFtZSA9IGlmZWxzZShhZ2VuY3lfbmFtZSA9PSAiVE9XTiBDSUNFUk8iLCAiQ0lUWSBPRiBDSUNFUk8iLCBhZ2VuY3lfbmFtZSkgKSAlPiUNCiAgbGVmdF9qb2luKG11bmlfc2hwLCBieSA9IGMoImFnZW5jeV9uYW1lIiA9ICJBR0VOQ1lfREVTQyIpKSAlPiUNCiAgZ2dwbG90KGFlcyhmaWxsID0gcGVyY2VudF9yZXNpZGVudGlhbCkpICsgDQogIGdlb21fc2YoYWVzKGdlb21ldHJ5ID0gZ2VvbWV0cnkpLCBjb2xvciA9ICJibGFjayIpICsgDQogIGxhYnModGl0bGUgPSAiUmVzaWRlbnRpYWwgRUFWIC8gIFRvdGFsIEVBViIsIGNhcHRpb24gPSAiVGhlIG1lZGlhbiBtdW5pY2lwYWxpdHkgaGFzIDcwLjQlIG9mIGl0cyBFQVYgZnJvbSBSZXNpZGVudGlhbCBDbGFzcyAyLCAzLCAmIDkgUHJvcGVydGllcyIpICsNCiAgICB0aGVtZV9jbGFzc2ljKCkgKyANCiAgdGhlbWUoYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpKSsjICsjKw0KICAgIHNjYWxlX2ZpbGxfc3RlcHMyKA0KICAgIGhpZ2ggPSAiZGFya2JsdWUiLCBsb3cgPSAiYmxhY2siLCAgIyAgZ3VpZGUgPSAibGVnZW5kIiwNCiAgICAgIG1pZHBvaW50ID0gbWVkaWFuKHBlcmNfcmVzaWRlbnRpYWwkcGVyY2VudF9yZXNpZGVudGlhbCksDQogICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gYnJlYWtzX3NkLA0KICAjICAgICAgICAgICAgICAgICAgICAgIG4uYnJlYWtzID0gNiwNCiAgc2hvdy5saW1pdHM9VFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiJSBSZXNpZGVudGlhbCIsDQogIGxhYmVscyA9IHNjYWxlczo6cGVyY2VudCkNCmBgYA0KDQpgYGB7cn0NCg0KZXhlbXB0aW9uc190b19yZXNFQVZfcmF0aW9zIDwtIGdyb3VwZWRfZXhlbXB0aW9ucyAlPiUgDQogIGZpbHRlcihSZXNpZGVudGlhbFByb3BzID09ICJSZXNpZGVudGlhbCIpICU+JSANCiAgbXV0YXRlKGV4ZW1wdEVBVl9wY3RvZl9yZXNFQVYgPSBleGVtcHRfRUFWL2VhdiwNCiAgICAgICAgIG5vbnRpZl9yYXRpbyA9IGV4ZW1wdF9FQVYgLyB0YXhfYmFzZV9ub2V4ZW1wcykgJT4lIA0KICBzZWxlY3QoYWdlbmN5X25hbWUsIGNsZWFuX25hbWUsIGV4ZW1wdEVBVl9wY3RvZl9yZXNFQVYsIG5vbnRpZl9yYXRpbykgJT4lIA0KICBhcnJhbmdlKG5vbnRpZl9yYXRpbykNCg0KZXhlbXB0aW9uc190b19yZXNFQVZfcmF0aW9zICU+JQ0KICAgIG11dGF0ZShhZ2VuY3lfbmFtZSA9IGlmZWxzZShhZ2VuY3lfbmFtZSA9PSAiVE9XTiBDSUNFUk8iLCAiQ0lUWSBPRiBDSUNFUk8iLCBhZ2VuY3lfbmFtZSkgKSAlPiUNCiBsZWZ0X2pvaW4obXVuaV9zaHAsIGJ5ID0gYygiYWdlbmN5X25hbWUiID0gIkFHRU5DWV9ERVNDIikpICU+JQ0KICBnZ3Bsb3QoYWVzKGZpbGwgPSBleGVtcHRFQVZfcGN0b2ZfcmVzRUFWKSkgKyANCiAgZ2VvbV9zZihhZXMoZ2VvbWV0cnkgPSBnZW9tZXRyeSksIGNvbG9yID0gImJsYWNrIikgKyB0aGVtZV92b2lkKCkrIA0KICBsYWJzKHRpdGxlID0gIkV4ZW1wdGlvbnMgLyBSZXNpZGVudGlhbCBFQVYgKGluIGFuZCBvdXQgb2YgVElGcykiKSArDQogICAgdGhlbWVfY2xhc3NpYygpICsgDQogIHRoZW1lKGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSkrDQogICBzY2FsZV9maWxsX3N0ZXBzMihoaWdoID0gIm1hcm9vbiIsIGxvdyA9ICJibGFjayIsIA0KICAgICAgICAgICAgICAgICAgICAgICMgbGltaXRzID0gYygwLC44KSwNCiAgICAgICAgICAgICAgICAgICAgICAgbi5icmVha3MgPSA3LCBzaG93LmxpbWl0cz1UUlVFLA0KICAgICAgICAgICAgICAgICAgICBuaWNlLmJyZWFrcyA9IEZBTFNFLA0KICAgICAgICAgICAgICAgICAgICBtaWRwb2ludCA9IG1lZGlhbihleGVtcHRpb25zX3RvX3Jlc0VBVl9yYXRpb3MkZXhlbXB0RUFWX3BjdG9mX3Jlc0VBViksDQogICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gIiUgUmVzaWRlbnRpYWwgRUFWIFxudGhhdCBpcyBleGVtcHQiLCBsYWJlbCA9IHNjYWxlczo6cGVyY2VudCkgKyBsYWJzKGNhcHRpb24gPSAiTWVkaWFuIHZhbHVlIGlzIDE5LjUlLiANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTmVhcmx5IDIwJSBvZiBSZXNpZGVudGlhbCBFQVYgaXMgdGF4IGV4ZW1wdCBpbiB0aGUgbWVkaWFuIG11bmljaXBhbGl0eS4gIikNCg0KZXhlbXB0aW9uc190b19yZXNFQVZfcmF0aW9zICU+JQ0KICAgIG11dGF0ZShhZ2VuY3lfbmFtZSA9IGlmZWxzZShhZ2VuY3lfbmFtZSA9PSAiVE9XTiBDSUNFUk8iLCAiQ0lUWSBPRiBDSUNFUk8iLCBhZ2VuY3lfbmFtZSkgKSAlPiUNCiAgbGVmdF9qb2luKG11bmlfc2hwLCBieSA9IGMoImFnZW5jeV9uYW1lIiA9ICJBR0VOQ1lfREVTQyIpKSAlPiUNCiAgZ2dwbG90KGFlcyhmaWxsID0gbm9udGlmX3JhdGlvKSkgKyANCiAgZ2VvbV9zZihhZXMoZ2VvbWV0cnkgPSBnZW9tZXRyeSksIGNvbG9yID0gImJsYWNrIikgKyB0aGVtZV92b2lkKCkrIA0KICBsYWJzKHRpdGxlID0gIk5vbi1USUYgRUFWIG9ubHk6IEhvbWVzdGVhZCBFeGVtcHRpb25zIC8gUmVzaWRlbnRpYWwgRUFWIiwgY2FwdGlvbiA9ICJWaWxsYWdlIG9mIFBob2VuaXggc2tld3MgZ3JhcGguIERyb3BwZWQgaW4gbWFwIGJlbG93IikgKw0KICAgIHRoZW1lX3ZvaWQoKSArIA0KICB0aGVtZShheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCkpKw0KICAgc2NhbGVfZmlsbF9zdGVwczIoaGlnaCA9ICJtYXJvb24iLCBsb3cgPSAiYmxhY2siLA0KICAgICAjY29sb3JzID0gYygid2hpdGUiLCAiZGFya2JsdWUiKSwgDQogICAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoMCwuOCksDQogICAgICAgICAgICAgICAgICAgIG1pZHBvaW50ID0gbWVkaWFuKGV4ZW1wdGlvbnNfdG9fcmVzRUFWX3JhdGlvcyRub250aWZfcmF0aW8pLA0KICAgICAgICAgICAgICAgICAgICAgICBuLmJyZWFrcyA9IDcsIHNob3cubGltaXRzPVRSVUUsDQogICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gIiUgUmVzaWRlbnRpYWwgRUFWIFxudGhhdCBpcyBleGVtcHQiLCBsYWJlbCA9IHNjYWxlczo6cGVyY2VudCkgKyBsYWJzKCBjYXB0aW9uID0gIk1lZGlhbiB2YWx1ZSBpcyAxOS43NyUgIikNCg0KZXhlbXB0aW9uc190b19yZXNFQVZfcmF0aW9zICU+JSANCiAgZmlsdGVyKG5vbnRpZl9yYXRpbzwuNSkgJT4lDQogICAgbXV0YXRlKGFnZW5jeV9uYW1lID0gaWZlbHNlKGFnZW5jeV9uYW1lID09ICJUT1dOIENJQ0VSTyIsICJDSVRZIE9GIENJQ0VSTyIsIGFnZW5jeV9uYW1lKSApICU+JQ0KICBsZWZ0X2pvaW4obXVuaV9zaHAsIGJ5ID0gYygiYWdlbmN5X25hbWUiID0gIkFHRU5DWV9ERVNDIikpICU+JQ0KICBnZ3Bsb3QoYWVzKGZpbGwgPSBub250aWZfcmF0aW8pKSArIA0KICBnZW9tX3NmKGFlcyhnZW9tZXRyeSA9IGdlb21ldHJ5KSwgY29sb3IgPSAiYmxhY2siKSArIHRoZW1lX3ZvaWQoKSsgDQogIGxhYnModGl0bGUgPSAiUGVyY2VudCBvZiBSZXNpZGVudGlhbCBFQVYgdGhhdCBpcyBUYXggRXhlbXB0IiwgDQogIHN1YnRpdGxlID0gIiUgb2YgTm9uLVRJRiBSZXNpZGVudGlhbCBFQVYgb25seTogXG5Ib21lc3RlYWQgRXhlbXB0aW9ucyAvIFJlc2lkZW50aWFsIEVBViIsIA0KICBjYXB0aW9uID0gIlJlc2lkZW50aWFsIGluY2x1ZGVzIENsYXNzIDIsIDMsIGFuZCA5Lg0KICBEcm9wcyBWaWxsYWdlIG9mIFBob2VuaXggYmVjYXVzZSBpdCBza2V3cyBtYXAgY29sb3JzICg3OCUgb2YgdGhlaXIgcmVzaWRlbnRpYWwgRUFWIGlzIHRheCBleGVtcHQpLiANCiAgTWVkaWFuIG11bmljaXBhbGl0eSBjYW4gbm90IGdldCB0YXggcmV2ZW51ZSBmcm9tIDE5Ljc3JSBvZiB0aGVpciByZXNpZGVudGlhbCBFQVYgZHVlIHRvIGV4ZW1wdGlvbnMuIikgKw0KICAgIHRoZW1lX3ZvaWQoKSArIA0KICB0aGVtZShheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCkpKw0KICAgc2NhbGVfZmlsbF9zdGVwczIoaGlnaCA9ICJtYXJvb24iLCBsb3cgPSAiYmxhY2siLA0KICAgIyAgY29sb3JzID0gYygid2hpdGUiLCAiZGFya2JsdWUiKSwgDQogICAgICAgICAgICAgICAgICAgICAgIyBsaW1pdHMgPSBjKDAsLjQpLA0KICAgbWlkcG9pbnQgPSBtZWRpYW4oZXhlbXB0aW9uc190b19yZXNFQVZfcmF0aW9zJG5vbnRpZl9yYXRpbyksDQogICAgICAgICAgICAgICAgICAgICAjICBuLmJyZWFrcyA9IDcsIA0KICAgc2hvdy5saW1pdHM9VFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiJSBSZXNpZGVudGlhbCBFQVYgXG50aGF0IGlzIGV4ZW1wdCIsIGxhYmVsID0gc2NhbGVzOjpwZXJjZW50KQ0KYGBgDQoNCmBgYHtyfQ0KZXhlbXB0aW9uc190b19yZXNFQVZfcmF0aW9zICU+JSBhcnJhbmdlKGRlc2Mobm9udGlmX3JhdGlvKSkNCmBgYA0KDQoNCiMjIFJlc2lkZW50aWFsIChPd25lciBPY2N1cGllZCkNCg0KTXVuaWNpcGFsaXR5IHRvdGFsIEVBViBleGNsdWRlcyBUSUYgaW5jcmVtZW50IEVBVi4gRnJvemVuIGJhc2UgRUFWIGlzIGluY2x1ZGVkLg0KDQpgYGB7cn0NCmdyb3VwZWRfZXhlbXB0aW9ucyA8LSBleGVtcHRpb25zX2J5X2NsYXNzX3Blcl9UQyAlPiUgDQpsZWZ0X2pvaW4oY2xhc3NfZGljdCkgJT4lDQogIGdyb3VwX2J5KGNsZWFuX25hbWUsIEFsZWFfY2F0LCBhZ2VuY3lfbmFtZSwgYWdlbmN5X251bS54KSAlPiUNCiAgc3VtbWFyaXplKGVhdiA9IHN1bShlYXYpLA0KICAgICAgICAgICBleGVtcHRfRUFWID0gc3VtKGV4ZW1wdF9FQVYsIGV4ZV9hYmF0ZSwgbmEucm09VFJVRSksDQogICAgICAgICB0YXhfYmFzZV9jdXJyZW50ID0gc3VtKHRheF9iYXNlX2N1cnJlbnQsIG5hLnJtPVRSVUUpLA0KICAgICAgICAgdGF4X2Jhc2Vfbm9leGVtcHMgPSBzdW0odGF4X2Jhc2Vfbm9leGVtcHMsIG5hLnJtPVRSVUUpKSAlPiUgdW5ncm91cCgpICU+JSANCiAgc2VsZWN0KGNsZWFuX25hbWUsIGVhdiwgZXhlbXB0X0VBViwgZXZlcnl0aGluZygpKQ0KICANCmdyb3VwZWRfZXhlbXB0aW9ucyANCg0KIyBjYWxjdWxhdGUgdG90YWxzIHdpdGggT05MWSBFQVYgb3V0c2lkZSBvZiBUSUZzDQptdW5pX2VhdiA8LSBncm91cGVkX2V4ZW1wdGlvbnMgJT4lICANCiAgZ3JvdXBfYnkoY2xlYW5fbmFtZSwgYWdlbmN5X25hbWUsIGFnZW5jeV9udW0ueCkgJT4lIA0KICBzdW1tYXJpemUobXVuaV9FQVZfaW5jbHVkZXNUSUYgPSBzdW0oZWF2KSwgIyBhbGwgRUFWIGluIHRoZSBtdW5pY2lwYWxpdHkgdGhhdCBleGlzdHMNCiAgICAgICAgICAgIG11bmlfdGF4X2Jhc2VfY3VycmVudD1zdW0odGF4X2Jhc2VfY3VycmVudCksICMgdGF4YWJsZSBFQVYgYmFzZWQgb24gY3VycmVudCBleGVtcHRpb25zDQogICAgICAgICAgICBtdW5pX3RheF9iYXNlX25vZXhlbXBzID0gc3VtKHRheF9iYXNlX25vZXhlbXBzKSkgJT4lICAjIHRheGFibGUgRUFWIHByZS1leGVtcHRpb25zDQogIHVuZ3JvdXAoKSANCg0KcGVyY19yZXNpZGVudGlhbCA8LSBmdWxsX2pvaW4oZ3JvdXBlZF9leGVtcHRpb25zLCBtdW5pX2VhdikgJT4lIA0KICMgZmlsdGVyKFJlc2lkZW50aWFsUHJvcHMgPT0gIlJlc2lkZW50aWFsIikgJT4lIA0KICBmaWx0ZXIoQWxlYV9jYXQgPT0gIk93bmVyIE9jY3VwaWVkIikgJT4lIA0KICBtdXRhdGUocGVyY2VudF9vd25lZCA9IGVhdiAvIG11bmlfRUFWX2luY2x1ZGVzVElGKSMgJT4lIHNlbGVjdCgpDQoNCg0KIyBpbiB0aGlzIHN0YWdlLCBCZW5zZW52aWxsZSwgRWFzdCBEdW5kZWUsIGFuZCBIb21lciBHbGVuIHdlcmUgZHJvcHBlZC4gVGhpcyBpcyBmaW5lIGJlY2F1c2UgSSB3YXMgZ29pbmcgdG8gZHJvcCB0aGVtIGxhdGVyIGFueXdheXMuIFRoZXkgZG9uJ3QgaGF2ZSByZXNpZGVudGlhbCBFQVYgd2l0aGluIENvb2sgQ291bnR5Lg0KDQpwZXJjX3Jlc2lkZW50aWFsDQoNCmBgYA0KDQoNClRoZSBtZWRpYW4gbXVuaWNpcGFsaXR5IGhhcyBgciBzY2FsZXM6OnBlcmNlbnQobWVkaWFuKHBlcmNfcmVzaWRlbnRpYWwkcGVyY2VudF9vd25lZCkpYCBvZiB0aGVpciBFQVYgaW4gdGhlIGZvcm0gb2Ygb3duZXIgb2NjdXBpZWQgcHJvcGVydGllcy4NCg0KV2hpbGUgdGhpcyBpcyB2ZXJ5IHNpbWlsYXIgdG8gdGhlIHBlcmNlbnRhZ2UgY2FsY3VsYXRlZCB1c2luZyBvbmx5IENsYXNzIDIgcmVzaWRlbnRpYWwgcHJvcGVydGllcy4gVGhlcmUgYXJlIHNvbWUgbXVuaWNpcGFsaXRpZXMgdGhhdCBleHBlcmllbmNlIGxhcmdlIGNoYW5nZXMgZHVlIHRvIHRoZSBjaGFuZ2UgaW4gY2F0ZWdvcml6YXRpb24gb2YgT3duZXIgb2NjdXBpZWQgdnMgcmVudGFsIGNvbXBhcmVkIHRvIENsYXNzIDIgb3IgbXVsdGktZmFtaWx5IHZzIHNpbmdsZS1mYW1pbHkgcHJvcGVydGllcy4NCg0KDQpgYGB7cn0NCnZhcmlhYmxlIDwtIHBlcmNfcmVzaWRlbnRpYWwkcGVyY2VudF9vd25lZA0KDQpicmVha3Nfc2QgPSBjKA0KICAobWVkaWFuKHZhcmlhYmxlKS0yLjUqc2QodmFyaWFibGUpKSwNCiAgKG1lZGlhbih2YXJpYWJsZSktMS41KnNkKHZhcmlhYmxlKSksDQogIG1lZGlhbih2YXJpYWJsZSktLjUqc2QodmFyaWFibGUpLA0KICBtZWRpYW4odmFyaWFibGUpLA0KICBtZWRpYW4odmFyaWFibGUpKy41KnNkKHZhcmlhYmxlKSwNCiAgbWVkaWFuKHZhcmlhYmxlKSsxLjUqc2QodmFyaWFibGUpLA0KICBtZWRpYW4odmFyaWFibGUpKzIuNSpzZCh2YXJpYWJsZSkpDQoNCg0KDQpwZXJjX3Jlc2lkZW50aWFsICU+JSANCiAgZmlsdGVyKEFsZWFfY2F0ID09ICJPd25lciBPY2N1cGllZCIpJT4lDQogIG11dGF0ZShhZ2VuY3lfbmFtZSA9IGlmZWxzZShhZ2VuY3lfbmFtZSA9PSAiVE9XTiBDSUNFUk8iLCAiQ0lUWSBPRiBDSUNFUk8iLCBhZ2VuY3lfbmFtZSkgKSAlPiUNCiAgZnVsbF9qb2luKG11bmlfc2hwLCBieSA9IGMoImFnZW5jeV9uYW1lIiA9ICJBR0VOQ1lfREVTQyIpKSAlPiUNCiAgZ2dwbG90KGFlcyhmaWxsID0gcGVyY2VudF9vd25lZCkpICsgDQogIGdlb21fc2YoYWVzKGdlb21ldHJ5ID0gZ2VvbWV0cnkpLCBjb2xvciA9ICJibGFjayIpICsgDQogIGxhYnModGl0bGUgPSAiT3duZXIgT2NjdXBpZWQgRUFWIC8gIFRvdGFsIEVBViIsIA0KICAgICAgIyBjYXB0aW9uID0gIlRoZSBtZWRpYW4gbXVuaWNpcGFsaXR5IGhhcyA3MC40JSBvZiBpdHMgRUFWIGZyb20gUmVzaWRlbnRpYWwgQ2xhc3MgMiwgMywgJiA5IFByb3BlcnRpZXMiDQogICAgICAgKSArDQogICAgdGhlbWVfY2xhc3NpYygpICsgDQogIHRoZW1lKGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSkgKw0KICAgIHNjYWxlX2ZpbGxfc3RlcHMyKA0KICAgIGhpZ2ggPSAiZGFya2JsdWUiLCBsb3cgPSAiYmxhY2siLCAgIyAgZ3VpZGUgPSAibGVnZW5kIiwNCiAgICBtaWRwb2ludCA9IG1lZGlhbihwZXJjX3Jlc2lkZW50aWFsJHBlcmNlbnRfb3duZWQsIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgICAgICAgICAgICAgI2JyZWFrcyA9IGJyZWFrc19zZCwNCiAgIyAgICAgICAgICAgICAgICAgICAgICBuLmJyZWFrcyA9IDYsDQogIHNob3cubGltaXRzPVRSVUUsDQogICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gIiUgT3duZXIgT2NjdXBpZWQiLA0KICBuYS52YWx1ZSA9ICJiZWlnZSIsDQogIGxhYmVscyA9IHNjYWxlczo6cGVyY2VudA0KICApDQpgYGANCg0KYGBge3J9DQpleGVtcHRpb25zX3RvX3Jlc0VBVl9yYXRpb3MgPC0gZ3JvdXBlZF9leGVtcHRpb25zICU+JSANCiAgbXV0YXRlKFJlc2lkZW50aWFsUHJvcHMgPSBpZmVsc2UoQWxlYV9jYXQgJWluJSBjKCJSZW50YWwiLCAiT3duZXIgT2NjdXBpZWQiLCAiT3RoZXIgUmVzaWRlbnRpYWwiKSwgIlJlc2lkZW50aWFsIiwgIk5vbi1yZXNpZGVudGlhbCIpKSAlPiUNCiAgZmlsdGVyKFJlc2lkZW50aWFsUHJvcHMgPT0gIlJlc2lkZW50aWFsIikgJT4lIA0KICBtdXRhdGUoZXhlbXB0RUFWX3BjdG9mX3Jlc0VBViA9IGV4ZW1wdF9FQVYvZWF2LA0KICAgICAgICAgbm9udGlmX3JhdGlvID0gZXhlbXB0X0VBViAvIHRheF9iYXNlX25vZXhlbXBzKSAlPiUgDQogIHNlbGVjdChhZ2VuY3lfbmFtZSwgY2xlYW5fbmFtZSwgZXhlbXB0RUFWX3BjdG9mX3Jlc0VBViwgbm9udGlmX3JhdGlvKSAlPiUgDQogIGFycmFuZ2Uobm9udGlmX3JhdGlvKQ0KDQpleGVtcHRpb25zX3RvX3Jlc0VBVl9yYXRpb3MgJT4lDQogICAgbXV0YXRlKGFnZW5jeV9uYW1lID0gaWZlbHNlKGFnZW5jeV9uYW1lID09ICJUT1dOIENJQ0VSTyIsICJDSVRZIE9GIENJQ0VSTyIsIGFnZW5jeV9uYW1lKSApICU+JQ0KIGxlZnRfam9pbihtdW5pX3NocCwgYnkgPSBjKCJhZ2VuY3lfbmFtZSIgPSAiQUdFTkNZX0RFU0MiKSkgJT4lDQogIGdncGxvdChhZXMoZmlsbCA9IGV4ZW1wdEVBVl9wY3RvZl9yZXNFQVYpKSArIA0KICBnZW9tX3NmKGFlcyhnZW9tZXRyeSA9IGdlb21ldHJ5KSwgY29sb3IgPSAiYmxhY2siKSArIHRoZW1lX3ZvaWQoKSsgDQogIGxhYnModGl0bGUgPSAiRXhlbXB0aW9ucyAvIFJlc2lkZW50aWFsIEVBViAoaW4gYW5kIG91dCBvZiBUSUZzKSIpICsNCiAgICB0aGVtZV9jbGFzc2ljKCkgKyANCiAgdGhlbWUoYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpKSsNCiAgIHNjYWxlX2ZpbGxfc3RlcHMyKGhpZ2ggPSAibWFyb29uIiwgbG93ID0gImJsYWNrIiwgDQogICAgICAgICAgICAgICAgICAgICAgIG4uYnJlYWtzID0gNywgc2hvdy5saW1pdHM9VFJVRSwNCiAgICAgICAgICAgICAgICAgICAgbmljZS5icmVha3MgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgbWlkcG9pbnQgPSBtZWRpYW4oZXhlbXB0aW9uc190b19yZXNFQVZfcmF0aW9zJGV4ZW1wdEVBVl9wY3RvZl9yZXNFQVYpLA0KICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICIlIFJlc2lkZW50aWFsIEVBViBcbnRoYXQgaXMgZXhlbXB0IiwgbGFiZWwgPSBzY2FsZXM6OnBlcmNlbnQpICsgbGFicyhjYXB0aW9uID0gIk1lZGlhbiB2YWx1ZSBpcyAxOS4xOCUuIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOZWFybHkgMTkuMiUgb2YgT3duZXIgT2NjdXBwaWVkIEVBViBpcyB0YXggZXhlbXB0IGluIHRoZSBtZWRpYW4gbXVuaWNpcGFsaXR5LiAiKQ0KYGBgDQoNCg0KYGBge3IgaW5jbHVkZT1GQUxTRX0NCmV4ZW1wdGlvbnNfdG9fcmVzRUFWX3JhdGlvcyAlPiUNCiAgICBtdXRhdGUoYWdlbmN5X25hbWUgPSBpZmVsc2UoYWdlbmN5X25hbWUgPT0gIlRPV04gQ0lDRVJPIiwgIkNJVFkgT0YgQ0lDRVJPIiwgYWdlbmN5X25hbWUpICkgJT4lDQogIGxlZnRfam9pbihtdW5pX3NocCwgYnkgPSBjKCJhZ2VuY3lfbmFtZSIgPSAiQUdFTkNZX0RFU0MiKSkgJT4lDQogIGdncGxvdChhZXMoZmlsbCA9IG5vbnRpZl9yYXRpbykpICsgDQogIGdlb21fc2YoYWVzKGdlb21ldHJ5ID0gZ2VvbWV0cnkpLCBjb2xvciA9ICJibGFjayIpICsgdGhlbWVfdm9pZCgpKyANCiAgbGFicyh0aXRsZSA9ICJOb24tVElGIEVBViBvbmx5OiBIb21lc3RlYWQgRXhlbXB0aW9ucyAvIFJlc2lkZW50aWFsIEVBViIsIGNhcHRpb24gPSAiVmlsbGFnZSBvZiBQaG9lbml4IHNrZXdzIGdyYXBoLiBEcm9wcGVkIGluIG1hcCBiZWxvdyIpICsNCiAgICB0aGVtZV92b2lkKCkgKyANCiAgdGhlbWUoYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpKSsNCiAgIHNjYWxlX2ZpbGxfc3RlcHMyKGhpZ2ggPSAibWFyb29uIiwgbG93ID0gImJsYWNrIiwNCiAgICAgI2NvbG9ycyA9IGMoIndoaXRlIiwgImRhcmtibHVlIiksIA0KICAgICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKDAsLjgpLA0KICAgICAgICAgICAgICAgICAgICBtaWRwb2ludCA9IG1lZGlhbihleGVtcHRpb25zX3RvX3Jlc0VBVl9yYXRpb3Mkbm9udGlmX3JhdGlvKSwNCiAgICAgICAgICAgICAgICAgICAgICAgbi5icmVha3MgPSA3LCBzaG93LmxpbWl0cz1UUlVFLA0KICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICIlIG9mIEVBViBmcm9tIE93bmVyIE9jY3VwaWVkIFByb3BlcnRpZXMgXG50aGF0IGlzIHRheCBleGVtcHQiLCBsYWJlbCA9IHNjYWxlczo6cGVyY2VudCkgKyBsYWJzKCBjYXB0aW9uID0gIk1lZGlhbiB2YWx1ZSBpcyAxOS4yOSUuIFRJRiBpbmNyZW1lbnQgRUFWIGV4Y2x1ZGVkIGZyb20gY2FsY3VsYXRpb25zLiIpDQpgYGANCg0KDQpgYGB7ciB9DQpleGVtcHRpb25zX3RvX3Jlc0VBVl9yYXRpb3MgJT4lIA0KICBmaWx0ZXIobm9udGlmX3JhdGlvPC41KSAlPiUNCiAgICBtdXRhdGUoYWdlbmN5X25hbWUgPSBpZmVsc2UoYWdlbmN5X25hbWUgPT0gIlRPV04gQ0lDRVJPIiwgIkNJVFkgT0YgQ0lDRVJPIiwgYWdlbmN5X25hbWUpICkgJT4lDQogIGxlZnRfam9pbihtdW5pX3NocCwgYnkgPSBjKCJhZ2VuY3lfbmFtZSIgPSAiQUdFTkNZX0RFU0MiKSkgJT4lDQogIGdncGxvdChhZXMoZmlsbCA9IG5vbnRpZl9yYXRpbykpICsgDQogIGdlb21fc2YoYWVzKGdlb21ldHJ5ID0gZ2VvbWV0cnkpLCBjb2xvciA9ICJibGFjayIpICsgdGhlbWVfdm9pZCgpKyANCiAgbGFicyh0aXRsZSA9ICJQZXJjZW50IG9mIE93bmVyIE9jY3VwaWVkIEVBViB0aGF0IGlzIFRheCBFeGVtcHQiLCANCiAgc3VidGl0bGUgPSAiJSBvZiBOb24tVElGIE93bmVyIE9jY3VwaWVkIEVBViBvbmx5OiBcbkhvbWVzdGVhZCBFeGVtcHRpb25zIC8gUmVzaWRlbnRpYWwgRUFWIiwgDQogIGNhcHRpb24gPSAiRHJvcHMgVmlsbGFnZSBvZiBQaG9lbml4IGJlY2F1c2UgaXQgc2tld3MgbWFwIGNvbG9ycyAoNzglIG9mIHRoZWlyIHJlc2lkZW50aWFsIEVBViBpcyB0YXggZXhlbXB0KS4gDQogIE1lZGlhbiBtdW5pY2lwYWxpdHkgY2FuIG5vdCBnZXQgdGF4IHJldmVudWUgZnJvbSAxOS4yOSUgb2YgdGhlaXIgcmVzaWRlbnRpYWwgRUFWIGR1ZSB0byBleGVtcHRpb25zLiIpICsNCiAgICB0aGVtZV92b2lkKCkgKyANCiAgdGhlbWUoYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpKSsNCiAgIHNjYWxlX2ZpbGxfc3RlcHMyKGhpZ2ggPSAibWFyb29uIiwgbG93ID0gImJsYWNrIiwNCiAgIG1pZHBvaW50ID0gbWVkaWFuKGV4ZW1wdGlvbnNfdG9fcmVzRUFWX3JhdGlvcyRub250aWZfcmF0aW8pLA0KICAgc2hvdy5saW1pdHM9VFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiJSBPd25lciBPY2N1cGllZCBFQVYgXG50aGF0IGlzIGV4ZW1wdCIsIGxhYmVsID0gc2NhbGVzOjpwZXJjZW50KQ0KYGBgDQoNCmBgYHtyfQ0KZXhlbXB0aW9uc190b19yZXNFQVZfcmF0aW9zICU+JSBhcnJhbmdlKGRlc2Mobm9udGlmX3JhdGlvKSkNCmBgYA0KDQoNCg0KIyBUYXhhYmxlIEJhc2UgYW5kIE11bmkgTGFuZCBVc2UNCg0KVGF4IGJhc2UgaW4gdGhlIHRhYmxlcyBhYm92ZSBhcmUgdGhlIHRvdGFsIEVBViBvdXRzaWRlIG9mIFRJRiBhcmVhcy4NCg0KYGBge3J9DQpUQ19iaWxsc19jdXJyZW50IDwtIHJlYWRfY3N2KCIyX1N1bW1lZF9CaWxsc19ieV9UYXhjb2RlX2FuZF9DbGFzcy5jc3YiKSAlPiUgDQogIGZpbHRlcihjbGFzcyAhPSAiMCIpICU+JSANCiAgbXV0YXRlKHRheF9jb2RlID0gYXMuY2hhcmFjdGVyKHRheF9jb2RlKSwNCiAgICAgICAgIGNsYXNzID0gYXMuY2hhcmFjdGVyKGNsYXNzKSkNCg0KY2xhc3NfZGljdCRjbGFzc19jb2RlIDwtIGFzLmNoYXJhY3RlcihjbGFzc19kaWN0JGNsYXNzX2NvZGUpDQogDQoNCnRheGNvZGVzX2N1cnJlbnQgPC0gZnVsbF9qb2luKFRDX2JpbGxzX2N1cnJlbnQsIG11bmlfdGF4X2NvZGVzLCANCiAgICAgICAgICAgICAgICAgICAgICBieSA9IGMoInRheF9jb2RlIiA9ICJ0YXhfY29kZV9udW0iKSkgDQoNCkN1cnJlbnRfVGF4cmF0ZXMgPC0gdGF4Y29kZXNfY3VycmVudCAlPiUgDQogIGxlZnRfam9pbihtdW5pX2FnZW5jeV9uYW1lcykgJT4lDQogIGxlZnRfam9pbihuaWNrbmFtZXMsIGJ5ID0gYygiYWdlbmN5X25hbWUiID0gImFnZW5jeV9uYW1lIikpICU+JQ0KICBmaWx0ZXIoIWFnZW5jeV9udW0gJWluJSBjcm9zc19jb3VudHlfbGluZXMpICU+JQ0KICBncm91cF9ieShjbGVhbl9uYW1lLCBhZ2VuY3lfbmFtZSkgJT4lDQogIHN1bW1hcml6ZShNdW5pTGV2eSA9IHN1bShmaW5hbF90YXhfdG9fZGlzdCwgbmEucm0gPSBUUlVFKSwgIyBhbW91bnQgYmlsbGVkIGJ5IG11bmlzIHdpdGggY3VycmVudCBleGVtcHRpb25zIGluIHBsYWNlDQogICAgICAgICAgICBub25USUZfRUFWX3Bvc3RfZXhlbXBzID0gc3VtKGZpbmFsX3RheF90b19kaXN0Lyh0YXhfY29kZV9yYXRlLzEwMCksIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgICBUSUZfaW5jcmVtZW50X0VBViA9IHN1bShmaW5hbF90YXhfdG9fdGlmLyh0YXhfY29kZV9yYXRlLzEwMCksIG5hLnJtPVRSVUUpLCAgDQogICAgICAgICAgICBFeGVtcHRfRUFWID0gc3VtKHRheF9hbXRfZXhlLyh0YXhfY29kZV9yYXRlLzEwMCksIG5hLnJtPVRSVUUpLCANCiAgICAgICAgICAgIFRvdGFsX0VBViA9IHN1bSgodGF4X2FtdF9leGUrZmluYWxfdGF4X3RvX2Rpc3QrZmluYWxfdGF4X3RvX3RpZikvKHRheF9jb2RlX3JhdGUvMTAwKSwgbmEucm0gPSBUUlVFKSkgJT4lDQoNCiAgbXV0YXRlKHRheF9yYXRlX2N1cnJlbnQgPSBNdW5pTGV2eS9ub25USUZfRUFWX3Bvc3RfZXhlbXBzLA0KICAgICAgICAgbm9uVElGX0VBVl9wcmVfZXhlbXBzID0gbm9uVElGX0VBVl9wb3N0X2V4ZW1wcyArIEV4ZW1wdF9FQVYsDQogICAgICAgICB0YXhyYXRlX25ldyA9IE11bmlMZXZ5L25vblRJRl9FQVZfcHJlX2V4ZW1wcywNCiAgICAgICAgIHRheHJhdGVfY2hhbmdlID0gdGF4X3JhdGVfY3VycmVudC10YXhyYXRlX25ldykgJT4lIA0KICBzZWxlY3QoY2xlYW5fbmFtZSwgdGF4cmF0ZV9jaGFuZ2UsIHRheF9yYXRlX2N1cnJlbnQsIHRheHJhdGVfbmV3LCBldmVyeXRoaW5nKCkpICU+JSANCiAgYXJyYW5nZShkZXNjKHRheF9yYXRlX2N1cnJlbnQpKQ0KDQpsYW5kX3VzZSA8LSB0YXhjb2Rlc19jdXJyZW50ICU+JSANCiAgbGVmdF9qb2luKG11bmlfYWdlbmN5X25hbWVzKSAlPiUgDQogIGxlZnRfam9pbihDdXJyZW50X1RheHJhdGVzKSAlPiUNCiAgICBsZWZ0X2pvaW4oY2xhc3NfZGljdCwgYnkgPSBjKCJjbGFzcyIgPSAiY2xhc3NfY29kZSIpKSAlPiUNCg0KICBtdXRhdGUoY2xhc3NfMWRpZyA9IHN0cl9zdWIoY2xhc3MsIDEsIDEpLA0KICAgIFJlc2lkZW50aWFsUHJvcHMgPSBpZmVsc2UoY2xhc3NfMWRpZyAlaW4lIGMoIjIiLCAiMyIsICI5IiksICJSZXNpZGVudGlhbCIsICJOb24tUmVzaWRlbnRpYWwiKSkgJT4lDQogICMgICAgICAgIFByb3BUeXBlID0gY2FzZV93aGVuKA0KICAjICAgICAgICAgIG1ham9yX2NsYXNzX2NvZGUgJWluJSBjKCIzIiwiOSIpIH4gIk11bHRpLUZhbWlseSIsDQogICMgICAgICAgICAgbWFqb3JfY2xhc3NfY29kZSA9PSAiMiIgfiAiU2luZ2xlLUZhbWlseSIsDQogICMgICAgICAgICAgVFJVRSB+ICJDb21tZXJjaWFsLUluZHVzdHJpYWwiKSkgJT4lDQogIGdyb3VwX2J5KGNsZWFuX25hbWUsIEFsZWFfY2F0LCBhZ2VuY3lfbnVtLCB0YXhfcmF0ZV9jdXJyZW50LCB0YXhyYXRlX25ldywgdGF4cmF0ZV9jaGFuZ2UsIGFnZW5jeV9uYW1lKSAlPiUgDQogIA0KICAjIEFsbCBvZiB0aGUgdmFsdWVzIGNhbGN1bGF0ZWQgYmVsb3cgYXJlIEFGVEVSIGV4ZW1wdGlvbnMgaGF2ZSBiZWVuIHJlbW92ZWQNCiAgc3VtbWFyaXplKHRheHJldl9mcm9tX3Byb3B0eXBlID0gc3VtKGZpbmFsX3RheF90b19kaXN0LCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgbm9uVElGX0VBViA9IHN1bShmaW5hbF90YXhfdG9fZGlzdC8odGF4X2NvZGVfcmF0ZS8xMDApLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgVElGX2luY3JlbWVudF9FQVYgPSBzdW0oZmluYWxfdGF4X3RvX3RpZi8odGF4X2NvZGVfcmF0ZS8xMDApLCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIEV4ZW1wdF9FQVYgPSBzdW0odGF4X2FtdF9leGUvKHRheF9jb2RlX3JhdGUvMTAwKSwgbmEucm09VFJVRSksDQogICAgICAgICAgICBUb3RhbF9FQVYgPSBzdW0oKHRheF9hbXRfZXhlK2ZpbmFsX3RheF90b19kaXN0K2ZpbmFsX3RheF90b190aWYpLyh0YXhfY29kZV9yYXRlLzEwMCksIG5hLnJtID0gVFJVRSkgKSAlPiUgdW5ncm91cCgpDQoNCkN1cnJlbnRfVGF4cmF0ZXMNCmBgYA0KDQpDdXJyZW50IGNvbXBvc2l0ZSB0YXggcmF0ZXMgZm9yIGVhY2ggbXVuaWNpcGFsaXR5IGFyZSBhYm92ZS4gVGFibGUgYWxzbyBpbmNsdWRlcyB0aGUgbmV3IHRheCByYXRlIGlmIHRoZXJlIHdlcmUgbm8gZXhlbXB0aW9ucywgdGhlIGxldnkgKGFrYSBhbW91bnQgY29sbGVjdGVkIGJ5IHRoZSBtdW5pY2lwYWxpdHkgZnJvbSBmaW5hbF90YXhfdG9fZGlzdCB2YXJpYWJsZSksIEVBViBvdXRzaWRlIG9mIFRJRnMsIGFtb3VudCBvZiBleGVtcHQgRUFWLCBhbmQgYWRkaXRpb25hbCB2YXJpYWJsZXMuDQoNCkJlbG93OiBUYWtlIEVBViB2YWx1ZXMgd2l0aGluIGVhY2ggcHJvcGVydHkgdHlwZSwgam9pbiBpdCB3aXRoIG11bmkgbGV2ZWwgRUFWIHZhbHVlcywgYW5kIGNhbGN1bGF0ZSAuLi4NCg0KYGBge3J9DQoNCmdyb3VwZWRfZXhlbXB0aW9ucyA8LSBleGVtcHRpb25zX2J5X2NsYXNzX3Blcl9UQyAlPiUgDQogICAjIGdyb3VwX2J5KGFnZW5jeV9uYW1lLCBtYWpvcl9jbGFzc19jb2RlLCBtYWpvcl9jbGFzc190eXBlLCBSZXNpZGVudGlhbFByb3BzLCBQcm9wVHlwZSkgJT4lDQogIGdyb3VwX2J5KGNsZWFuX25hbWUsIEFsZWFfY2F0LCBhZ2VuY3lfbmFtZSkgJT4lDQogIHN1bW1hcml6ZShlYXYgPSBzdW0oZWF2KSwNCiAgICAgICAgICAgZXhlbXB0X0VBViA9IHN1bShleGVtcHRfRUFWLCBleGVfYWJhdGUsIG5hLnJtPVRSVUUpLA0KICAgICAgICAgdGF4X2Jhc2VfY3VycmVudCA9IHN1bSh0YXhfYmFzZV9jdXJyZW50LCBuYS5ybT1UUlVFKSwNCiAgICAgICAgIHRheF9iYXNlX25vZXhlbXBzID0gc3VtKHRheF9iYXNlX25vZXhlbXBzLCBuYS5ybT1UUlVFKSkgJT4lIHVuZ3JvdXAoKQ0KICANCg0KIyBjYWxjdWxhdGUgdG90YWxzIHdpdGggT05MWSBFQVYgb3V0c2lkZSBvZiBUSUZzDQptdW5pX2VhdiA8LSBncm91cGVkX2V4ZW1wdGlvbnMgJT4lICANCiAgZ3JvdXBfYnkoY2xlYW5fbmFtZSwgYWdlbmN5X25hbWUpICU+JSANCiAgc3VtbWFyaXplKG11bmlfRUFWX2luY2x1ZGVzVElGID0gc3VtKGVhdiksICMgYWxsIEVBViBpbiB0aGUgbXVuaWNpcGFsaXR5IHRoYXQgZXhpc3RzDQogICAgICAgICAgICBtdW5pX3RheF9iYXNlX2N1cnJlbnQ9c3VtKHRheF9iYXNlX2N1cnJlbnQpLCAjIHRheGFibGUgRUFWIGJhc2VkIG9uIGN1cnJlbnQgZXhlbXB0aW9ucw0KICAgICAgICAgICAgbXVuaV90YXhfYmFzZV9ub2V4ZW1wcyA9IHN1bSh0YXhfYmFzZV9ub2V4ZW1wcykpICU+JSAgIyB0YXhhYmxlIEVBViBwcmUtZXhlbXB0aW9ucw0KICB1bmdyb3VwKCkgDQoNCnBjdF9wcm9wZXJ0eV90eXBlcyA8LSBsZWZ0X2pvaW4oZ3JvdXBlZF9leGVtcHRpb25zLCBtdW5pX2VhdikgJT4lIA0KICMgZmlsdGVyKFJlc2lkZW50aWFsUHJvcHMgPT0gIkFsZWFfY2F0IikgJT4lIA0KICBtdXRhdGUocGN0X1Byb3BUeXBlID0gZWF2IC8gbXVuaV9FQVZfaW5jbHVkZXNUSUYpIyAlPiUgc2VsZWN0KCkNCg0KcGN0X3Byb3BlcnR5X3R5cGVzDQoNCg0KYnVyZGVuX3RhYmxlIDwtIHBjdF9wcm9wZXJ0eV90eXBlcyAlPiUgDQogIGxlZnRfam9pbihDdXJyZW50X1RheHJhdGVzLCBieSA9IGMoImFnZW5jeV9uYW1lIiwgImNsZWFuX25hbWUiKSkgJT4lDQogIG11dGF0ZShyZXZfY29sbGVjdGVkX2N1cnJlbnQgPSB0YXhfYmFzZV9jdXJyZW50ICogdGF4X3JhdGVfY3VycmVudCwNCiAgICAgICAgIHJldl9jb2xsZWN0ZWRfbmV3ID0gdGF4X2Jhc2Vfbm9leGVtcHMqdGF4cmF0ZV9uZXcsDQogICAgICAgICBidXJkZW5fY3VycmVudCA9IHJldl9jb2xsZWN0ZWRfY3VycmVudC9NdW5pTGV2eSwNCiAgICAgICAgIGJ1cmRlbl9ub2V4ZW1wcyA9IHJldl9jb2xsZWN0ZWRfbmV3L011bmlMZXZ5LCANCiAgICAgICAgIGJ1cmRlbl9jaGFuZ2UgPSBidXJkZW5fbm9leGVtcHMtIGJ1cmRlbl9jdXJyZW50LA0KICAgICAgICAgYnVyZGVuX25vZXhlbXBzID0gaWZlbHNlKGJ1cmRlbl9ub2V4ZW1wcyA+MSwgMSwgYnVyZGVuX25vZXhlbXBzKSkgJT4lDQogIG11dGF0ZShidXJkZW5fY3VycmVudCA9IGlmZWxzZShpcy5uYShidXJkZW5fY3VycmVudCksIDAsIGJ1cmRlbl9jdXJyZW50KSwNCiAgICAgICAgIGJ1cmRlbl9ub2V4ZW1wcyA9IGlmZWxzZShpcy5uYShidXJkZW5fbm9leGVtcHMpLCAwLCBidXJkZW5fbm9leGVtcHMpKSAlPiUNCiAgbXV0YXRlKGJ1cmRlbl9ub2V4ZW1wcyA9IGlmZWxzZShidXJkZW5fbm9leGVtcHM+MSwgMSwgYnVyZGVuX25vZXhlbXBzKSwNCiAgICAgICAgIGJ1cmRlbl9jdXJyZW50ID0gaWZlbHNlKGJ1cmRlbl9jdXJyZW50PjEsIDEsIGJ1cmRlbl9jdXJyZW50KSkgJT4lDQogIG11dGF0ZShhZ2VuY3lfbmFtZSA9IGlmZWxzZShhZ2VuY3lfbmFtZSA9PSAiVE9XTiBDSUNFUk8iLCAiQ0lUWSBPRiBDSUNFUk8iLCBhZ2VuY3lfbmFtZSkgKQ0KDQoNCmJ1cmRlbl9zaGlmdCA8LSBidXJkZW5fdGFibGUgIyBvbmx5IHRvIG5vdCBjaGFuZ2UgY29kZSBiZWxvdyBpbiBncmFwaHMuIA0KYGBgDQoNCg0KIyBDb21wb3NpdGUgVGF4IFJhdGUgQ2hhbmdlDQoNClRoZSB0YXggcmF0ZSBzaG93biBpcyB0aGUgY29tcG9zaXRlIHRheCByYXRlIGZvciB0aGUgTXVuaWNpcGFsaXR5LiBUaGUgY29tcG9zaXRlIHRheCByYXRlIGlzIHRoZSBhZ2dyZWdhdGUgb2YgdGhlIHRheCByYXRlIGZvciBlYWNoIHRheGluZyBhZ2VuY3kgWCB0aGUgRUFWIHdpdGhpbiB0aGUgdGF4aW5nIGp1cmlzZGljdGlvbi4gVGhpcyB3YXMgY2FsY3VsYXRlZCBhdCBhIHRheCBjb2RlIGxldmVsIGZpcnN0IGFuZCB0aGVuIGFkZGVkIHRvZ2V0aGVyIGZvciBhbGwgdGF4Y29kZXMgdGF4ZWQgYnkgYSBtdW5pY2lwYWwgdGF4aW5nIGFnZW5jeS4NCg0KNiBIaWdoZXN0IGFuZCA2IGxvd2VzdCB0YXggcmF0ZXMuIFZpZXcgdGhlIGV4dHJlbWVzIG9uIGJvdGggc2lkZXMNCg0KYGBge3J9DQpsaWJyYXJ5KGthYmxlRXh0cmEpDQpDdXJyZW50X1RheHJhdGVzICU+JSAgZmlsdGVyKHRheF9yYXRlX2N1cnJlbnQgPiAwLjI1ICkgJT4lIHNlbGVjdCggLWFnZW5jeV9uYW1lKSAlPiUNCiAga2JsKGNhcHRpb24gPSAiSGlnaGVzdCBDb21wb3NpdGUgVGF4IFJhdGVzIiAsIHJvdy5uYW1lcz1GQUxTRSkgJT4lIA0KICAgICBrYWJsZV9jbGFzc2ljKCkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KQ3VycmVudF9UYXhyYXRlcyAlPiUgIGZpbHRlciggdGF4X3JhdGVfY3VycmVudCA8IDAuMDgpICAlPiUgICBzZWxlY3QoIC1hZ2VuY3lfbmFtZSkgJT4lDQogIGtibChjYXB0aW9uID0gIkxvd2VzdCBDb21wb3NpdGUgVGF4IFJhdGVzIiAsIHJvdy5uYW1lcz1GQUxTRSkgJT4lIA0KICAgICBrYWJsZV9jbGFzc2ljKCkNCg0KI3F1YW50aWxlKEN1cnJlbnRfVGF4cmF0ZXMkdGF4X3JhdGVfY3VycmVudCApDQoNCiNzZChDdXJyZW50X1RheHJhdGVzJHRheF9yYXRlX2N1cnJlbnQpDQoNCmBgYA0KDQpUaGUgY3VycmVudCBjb21wb3NpdGUgdGF4IHJhdGUgZm9yIHRoZSBtZWRpYW4gbXVuaWNpcGFsaXR5IGlzIGByIHNjYWxlczo6cGVyY2VudChtZWRpYW4oQ3VycmVudF9UYXhyYXRlcyR0YXhfcmF0ZV9jdXJyZW50ICkpYA0KDQoNCmBgYHtyfQ0KQ3VycmVudF9UYXhyYXRlcyAlPiUgDQogICAgbXV0YXRlKGFnZW5jeV9uYW1lID0gaWZlbHNlKGFnZW5jeV9uYW1lID09ICJUT1dOIENJQ0VSTyIsICJDSVRZIE9GIENJQ0VSTyIsIGFnZW5jeV9uYW1lKSANCiAgICApICU+JQ0KICAjICBmaWx0ZXIobWFqb3JfY2xhc3NfY29kZSA9PSAyKSAlPiUgIyBhbGwgcHJvcGVydHkgdHlwZXMgaGF2ZSBzYW1lIGNvbXBvc2l0ZSB0YXggcmF0ZQ0KICBsZWZ0X2pvaW4obXVuaV9zaHAsIGJ5ID0gYygiYWdlbmN5X25hbWUiID0gIkFHRU5DWV9ERVNDIikpICU+JQ0KICANCiAgZ2dwbG90KGFlcyhmaWxsID0gdGF4X3JhdGVfY3VycmVudCkpICsNCiAgZ2VvbV9zZihhZXMoZ2VvbWV0cnkgPSBnZW9tZXRyeSksIGNvbG9yID0gImJsYWNrIikgKyANCiAgdGhlbWVfdm9pZCgpICsgDQogIHRoZW1lKGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSkrDQogIHNjYWxlX2ZpbGxfc3RlcHMyKCNjb2xvcnMgPSBjb2xvcnMsDQogICAgaGlnaCA9ICIjNDIwNDIwIiwgbG93ID0gImJsYWNrIiwNCiAgICBtaWRwb2ludCA9IG1lZGlhbihDdXJyZW50X1RheHJhdGVzJHRheF9yYXRlX2N1cnJlbnQpLCAjICBtaWRwb2ludCA9IDAuMTIzLA0KICAgICNicmVha3MgPSBicmVha3Nfc2QsDQogICAgbGltaXRzID0gYygwLC40NSksDQogICAgc2hvdy5saW1pdHM9VFJVRSwNCiAgICBuaWNlLmJyZWFrcz1GQUxTRSwNCiAgICBuID02LA0KICAgIG5hbWUgPSAiVGF4IFJhdGUiLA0KICAgIGxhYmVsID0gc2NhbGVzOjpwZXJjZW50ICkrDQogIA0KICBsYWJzKHRpdGxlID0gIkN1cnJlbnQgY29tcG9zaXRlIHRheCByYXRlcyIgLCAgICANCiAgICAgICBjYXB0aW9uID0gIlRoZSBjdXJyZW50IG1lZGlhbiBjb21wb3NpdGUgdGF4IHJhdGUgaXMgMTIuMyUuIA0KICAgICAgICAgSGlnaGVzdCBjb21wb3NpdGUgdGF4IHJhdGUgaXMgaW4gUGFyayBGb3Jlc3QgKDQxLjQlLikNCiAgICAgICBMb3dlc3QgY29tcG9zaXRlIHRheCByYXRlIGlzIGluIENoaWNhZ28gKDYuNyUpLiIpDQoNCmBgYA0KDQpgYGB7cn0NCiMgbWVkaWFuIA0KYnVyZGVuX3NoaWZ0ICU+JSANCiAgZmlsdGVyKEFsZWFfY2F0ID09ICJPd25lciBPY2N1cGllZCIpICU+JQ0KICAjZmlsdGVyKG1ham9yX2NsYXNzX2NvZGUgPT0gMikgJT4lDQogIHN1bW1hcml6ZShtZWRpYW5fY3VycmVudGJ1cmRlbiA9IG1lZGlhbihidXJkZW5fY3VycmVudCksDQogICAgICAgICAgICBtZWRpYW5fbmV3X2J1cmRlbiA9IG1lZGlhbihidXJkZW5fbm9leGVtcHMpLA0KICAgICAgICAgICAgbWVkaWFuX2J1cmRlbmNoYW5nZSA9IG1lZGlhbihidXJkZW5fY2hhbmdlKSwNCiAgICAgICAgICAgIG1lZGlhbl9jdXJyZW50dGF4cmF0ZSA9IG1lZGlhbih0YXhfcmF0ZV9jdXJyZW50KSwNCiAgICAgICAgICAgIG1lZGlhbl90YXhyYXRlY2hhbmdlID0gbWVkaWFuKHRheHJhdGVfY2hhbmdlKSwNCiAgICAgICAgICAgIG1lZGlhbl90YXhyYXRlbmV3ID0gbWVkaWFuKHRheHJhdGVfbmV3KSkgJT4lIA0KICBwaXZvdF9sb25nZXIoY29scyA9IGV2ZXJ5dGhpbmcoKSwgbmFtZXNfdG8gPSAiU3RhdCIsIHZhbHVlc190byA9ICJWYWx1ZSIpDQoNCmJ1cmRlbl9zaGlmdCAlPiUgDQogIGZpbHRlcihBbGVhX2NhdCA9PSAiUmVudGFsIikgJT4lDQogICNmaWx0ZXIobWFqb3JfY2xhc3NfY29kZSA9PSAyKSAlPiUNCiAgc3VtbWFyaXplKG1lZGlhbl9jdXJyZW50YnVyZGVuID0gbWVkaWFuKGJ1cmRlbl9jdXJyZW50KSwNCiAgICAgICAgICAgIG1lZGlhbl9uZXdfYnVyZGVuID0gbWVkaWFuKGJ1cmRlbl9ub2V4ZW1wcyksDQogICAgICAgICAgICBtZWRpYW5fYnVyZGVuY2hhbmdlID0gbWVkaWFuKGJ1cmRlbl9jaGFuZ2UpLA0KICAgICAgICAgICAgbWVkaWFuX2N1cnJlbnR0YXhyYXRlID0gbWVkaWFuKHRheF9yYXRlX2N1cnJlbnQpLA0KICAgICAgICAgICAgbWVkaWFuX3RheHJhdGVjaGFuZ2UgPSBtZWRpYW4odGF4cmF0ZV9jaGFuZ2UpLA0KICAgICAgICAgICAgbWVkaWFuX3RheHJhdGVuZXcgPSBtZWRpYW4odGF4cmF0ZV9uZXcpKSAlPiUgDQogIHBpdm90X2xvbmdlcihjb2xzID0gZXZlcnl0aGluZygpLCBuYW1lc190byA9ICJTdGF0IiwgdmFsdWVzX3RvID0gIlZhbHVlIikNCmBgYA0KDQpgYGB7cn0NCkN1cnJlbnRfVGF4cmF0ZXMgJT4lIA0KICAgICAgbXV0YXRlKGFnZW5jeV9uYW1lID0gaWZlbHNlKGFnZW5jeV9uYW1lID09ICJUT1dOIENJQ0VSTyIsICJDSVRZIE9GIENJQ0VSTyIsIGFnZW5jeV9uYW1lKSANCiAgICApICU+JQ0KICBsZWZ0X2pvaW4obXVuaV9zaHAsIGJ5ID0gYygiYWdlbmN5X25hbWUiID0gIkFHRU5DWV9ERVNDIikpICU+JQ0KICBnZ3Bsb3QoYWVzKGZpbGwgPSB0YXhyYXRlX25ldykpICsgDQogIHRoZW1lX3ZvaWQoKSArIA0KICB0aGVtZShheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCkpKw0KICBzY2FsZV9maWxsX3N0ZXBzMigNCiAgICBoaWdoID0gIiM0MjA0MjAiLCBsb3cgPSAiIzAwODA4MCIsDQogICAgbGltaXRzID0gYygwLC40NSksDQogICAgbWlkcG9pbnQgPSBtZWRpYW4oQ3VycmVudF9UYXhyYXRlcyR0YXhyYXRlX25ldyksICAjIG1pZHBvaW50ID0gLjEwNTIsDQogICAgbmljZS5icmVha3M9RkFMU0UsDQogICAgc2hvdy5saW1pdHM9VFJVRSwNCiAgICBuPTYsDQogICAgbmFtZSA9ICJUYXggUmF0ZSIsIGxhYmVsID0gc2NhbGVzOjpwZXJjZW50KSsNCiAgZ2VvbV9zZihhZXMoZ2VvbWV0cnkgPSBnZW9tZXRyeSksIGNvbG9yID0gImJsYWNrIikgKyAgDQogIGxhYnModGl0bGUgPSAiTmV3IGNvbXBvc2l0ZSB0YXggcmF0ZXMgaWYgZXhlbXB0aW9ucyB3ZXJlIGVsaW1pbmF0ZWQiICwgICAgDQogICAgICAgY2FwdGlvbiA9ICJUaGUgbmV3IG1lZGlhbiBjb21wb3NpdGUgdGF4IHJhdGUgd291bGQgYmUgYXBwcm94aW1hdGVseSAxMC41JSANCiAgICAgICBpZiBleGVtcHRpb25zIHdlcmUgcmVtb3ZlZC4iKQ0KYGBgDQoNCg0KYGBge3J9DQoNCg0KQ3VycmVudF9UYXhyYXRlcyAlPiUgDQogIG11dGF0ZShhZ2VuY3lfbmFtZSA9IGlmZWxzZShhZ2VuY3lfbmFtZSA9PSAiVE9XTiBDSUNFUk8iLCAiQ0lUWSBPRiBDSUNFUk8iLCBhZ2VuY3lfbmFtZSkgKSAlPiUNCiAgIyBmaWx0ZXIoY2xlYW5fbmFtZSAhPSAiUGFyayBGb3Jlc3QiKSAlPiUNCiAgZnVsbF9qb2luKG11bmlfc2hwLCBieSA9IGMoImFnZW5jeV9uYW1lIiA9ICJBR0VOQ1lfREVTQyIpKSAlPiUNCiAgZ2dwbG90KGFlcyhmaWxsID0gdGF4cmF0ZV9jaGFuZ2UpKSArIA0KICBnZW9tX3NmKGFlcyhnZW9tZXRyeSA9IGdlb21ldHJ5KSwgY29sb3IgPSAiYmxhY2siKSArICANCiAgdGhlbWVfdm9pZCgpICsgDQogIHRoZW1lKGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSkrDQogIA0KICBzY2FsZV9maWxsX3N0ZXBzMihoaWdoID0gImJsdWUiLCBsb3cgPSAiYmxhY2siLA0KICAgIG49NiwgbWlkcG9pbnQgPSAwLjAxMzg4LCANCiAgICBzaG93LmxpbWl0cz1UUlVFLA0KICAgIG5pY2UuYnJlYWtzPUZBTFNFLA0KICAgIG5hLnZhbHVlID0gImxpZ2h0Z3JheSIsDQogICAgbGFiZWxzID0gc2NhbGVzOjpwZXJjZW50LA0KICAgIG5hbWUgPSAiUGVyY2VudGFnZSBQb2ludCBcbkRpZmZlcmVuY2UiKSsNCiAgbGFicyh0aXRsZSA9ICJDaGFuZ2UgaW4gQ29tcG9zaXRlIFRheCBSYXRlIGlmIEV4ZW1wdGlvbnMgYXJlIFJlbW92ZWQiLA0KICAgICAgIGNhcHRpb24gPSAiVGhlIG1lZGlhbiBjaGFuZ2UgaW4gY29tcG9zaXRlIHRheCByYXRlIGlzIDEuNDMgcGVyY2VudGFnZSBwb2ludHMiKQ0KYGBgDQoNCmBgYHtyfQ0KIyBhcyBhIGRvdCBncmFwaCAjIyANCg0Kb3JkZXIgPC0gYnVyZGVuX3NoaWZ0ICU+JSAgDQogIGFzX3RpYmJsZSgpICU+JSANCiAgc3VtbWFyaXplKGFnZW5jeV9uYW1lID0gdW5pcXVlKGFnZW5jeV9uYW1lKSwgDQogICAgICAgICAgICBjbGVhbl9uYW1lID0gdW5pcXVlKGNsZWFuX25hbWUpLCANCiAgICAgICAgICAgIHRheF9yYXRlX2N1cnJlbnQgPSB1bmlxdWUodGF4X3JhdGVfY3VycmVudCksIA0KICAgICAgICAgICAgdGF4cmF0ZV9uZXcgPSB1bmlxdWUodGF4cmF0ZV9uZXcpKSAlPiUgDQogIGFycmFuZ2UodGF4X3JhdGVfY3VycmVudCkgJT4lDQogIHNlbGVjdChhZ2VuY3lfbmFtZSwgY2xlYW5fbmFtZSwgdGF4X3JhdGVfY3VycmVudCkNCg0KaGVhZChvcmRlcikNCg0KIyBsb29rIGF0IG9uZXMgdGhhdCBjaGFuZ2VkIHRoZSBtb3N0DQpidXJkZW5fc2hpZnQgJT4lIA0KICAjIGZpbHRlcih0YXhfcmF0ZV9jdXJyZW50IDwgKG1lZGlhbih0YXhfcmF0ZV9jdXJyZW50KSkrMC4wMDIgJiB0YXhfcmF0ZV9jdXJyZW50ID4gKG1lZGlhbih0YXhfcmF0ZV9jdXJyZW50KSktMC4wMDIgfA0KICAjICAodGF4X3JhdGVfY3VycmVudCA+IDAuMjUgfCB0YXhfcmF0ZV9jdXJyZW50IDwgMC4wOCApKSAlPiUNCiAgIyAgICAgICAgICAodGF4X3JhdGVfY3VycmVudCA8IChtZWRpYW4odGF4X3JhdGVfY3VycmVudCkpKzAuMDA1ICYgdGF4X3JhdGVfY3VycmVudCA+IChtZWRpYW4odGF4X3JhdGVfY3VycmVudCkpLTAuMDA1ICkpICU+JSANCiAgI2ZpbHRlcihQcm9wVHlwZSA9PSAiU2luZ2xlLUZhbWlseSIpICU+JQ0KICBmaWx0ZXIoQWxlYV9jYXQgPT0gIk93bmVyIE9jY3VwaWVkIikgJT4lDQogIHVuZ3JvdXAoKSAlPiUgDQogIHNlbGVjdChjbGVhbl9uYW1lLCB0YXhfcmF0ZV9jdXJyZW50LCB0YXhyYXRlX25ldywgYWdlbmN5X25hbWUpICU+JSANCiAgcGl2b3RfbG9uZ2VyKGMoInRheF9yYXRlX2N1cnJlbnQiLCAidGF4cmF0ZV9uZXciKSwgDQogICAgICAgICAgICAgICBuYW1lc190byA9ICJ0eXBlIiwgdmFsdWVzX3RvID0gInRheF9yYXRlIikgJT4lIA0KICBsZWZ0X2pvaW4ob3JkZXIpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSB0YXhfcmF0ZSoxMDAsIHk9IHJlb3JkZXIoY2xlYW5fbmFtZSwgdGF4X3JhdGVfY3VycmVudCkpKSsNCg0KICBnZW9tX2xpbmUoYWVzKGdyb3VwID0gY2xlYW5fbmFtZSkpKyANCiAgICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDMuNSwgbGluZXR5cGUgPSAyKSsNCiAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAxMy41LCBsaW5ldHlwZSA9IDIpICsNCiAgIGdlb21fcG9pbnQoYWVzKGNvbG9yPXR5cGUpLCBzaXplPTMgKSsNCiAgdGhlbWVfbWluaW1hbCgpICsgDQogIHRoZW1lKCANCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgICAgICBwbG90LnRpdGxlLnBvc2l0aW9uID0gInBsb3QiLA0KICAgICAjICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsPSd0cmFuc3BhcmVudCcpLCAjdHJhbnNwYXJlbnQgcGFuZWwgYmcNCiAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD0ndHJhbnNwYXJlbnQnLCBjb2xvcj1OQSkgI3RyYW5zcGFyZW50IHBsb3QgYmcNCiAgICkrDQogICAgICAgIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlPSJQYWlyZWQiLCBsYWJlbHMgPSBjKCJFeGVtcHRpb25zIiwgIk5vIEV4ZW1wdGlvbnMiKSwgZGlyZWN0aW9uID0gMSkrDQoNCiAgbGFicyh0aXRsZSA9ICJEaWZmZXJlbmNlIGluIENvbXBvc2l0ZSBUYXggUmF0ZSBpZiB0aGVyZSB3ZXJlIE5vIEV4ZW1wdGlvbnMiLA0KICAgICAgIHN1YnRpdGxlID0gIk9yZGVyZWQgYnkgQ3VycmVudCBDb21wb3NpdGUgVGF4IFJhdGUiLCB4ID0gIkNvbXBvc2l0ZSBUYXggUmF0ZSAoJSkiLCB5ID0gIiIgLCANCiAgICAgICBjYXB0aW9uID0gIkZvciB0aGUgaGlnaGVzdCwgbWVkaWFuLCBhbmQgbG93ZXN0IG11bmljaXBhbGl0eSBjb21wb3NpdGUgdGF4IHJhdGVzICIpDQpgYGANCg0KYGBge3J9DQojIG9yZGVyZWQgYnkgY2hhbmdlIGluIHRheCByYXRlIGlmIGV4ZW1wdGlvbnMgd2VyZSByZW1vdmVkLg0KIyBhcyBhIGRvdCBncmFwaCAjIyANCg0Kb3JkZXIgPC0gYnVyZGVuX3NoaWZ0ICU+JSANCiAgYXNfdGliYmxlKCkgJT4lDQogIGdyb3VwX2J5KGFnZW5jeV9uYW1lLCBjbGVhbl9uYW1lKSAlPiUNCiAgICBzdW1tYXJpemUodGF4X3JhdGVfY3VycmVudCA9IG1lZGlhbih0YXhfcmF0ZV9jdXJyZW50KSwgDQogICAgICAgICAgICB0YXhyYXRlX25ldyA9IG1lZGlhbih0YXhyYXRlX25ldyksDQogICAgICAgICAgICB0YXhyYXRlX2NoYW5nZSA9IG1lZGlhbih0YXhyYXRlX2NoYW5nZSkpICU+JQ0KICBhcnJhbmdlKHRheHJhdGVfY2hhbmdlKQ0KDQptZWRpYW4ob3JkZXIkdGF4cmF0ZV9jaGFuZ2UpICMgbWVkaWFuIHJhdGUgY2hhbmdlIGlzIDEuMzg4IHBlcmNlbnRhZ2UgcG9pbnRzDQojaGVhZChvcmRlcikNCiN0YWlsKG9yZGVyKQ0KDQpidXJkZW5fc2hpZnQgJT4lICANCiAgZmlsdGVyKHRheHJhdGVfY2hhbmdlIDwgMC4wMDI3IHx0YXhyYXRlX2NoYW5nZSA+IDAuMDYgIHwNCiAgICAgICAgICAgdGF4cmF0ZV9jaGFuZ2UgPCAobWVkaWFuKHRheHJhdGVfY2hhbmdlKSkrMC4wMDA3ICYgdGF4cmF0ZV9jaGFuZ2UgPiAobWVkaWFuKHRheHJhdGVfY2hhbmdlKSktMC4wMDA3NQ0KICAgICAgICAgKSAlPiUgDQogICAgZmlsdGVyKEFsZWFfY2F0ID09ICJPd25lciBPY2N1cGllZCIpICU+JQ0KDQogIyBmaWx0ZXIoUHJvcFR5cGUgPT0gIlNpbmdsZS1GYW1pbHkiKSAlPiUNCiAgdW5ncm91cCgpICU+JSANCiAgc2VsZWN0KGNsZWFuX25hbWUsIHRheF9yYXRlX2N1cnJlbnQsIHRheHJhdGVfbmV3LCBhZ2VuY3lfbmFtZSkgJT4lIA0KICBwaXZvdF9sb25nZXIoYygidGF4X3JhdGVfY3VycmVudCIsICJ0YXhyYXRlX25ldyIpLCANCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gInR5cGUiLCB2YWx1ZXNfdG8gPSAidGF4X3JhdGUiKSAlPiUgDQogIGxlZnRfam9pbihvcmRlcikgJT4lDQogIGdncGxvdChhZXMoeCA9IHRheF9yYXRlKjEwMCwgeT0gcmVvcmRlcihjbGVhbl9uYW1lLCB0YXhyYXRlX2NoYW5nZSkpKSsNCiAgZ2VvbV9saW5lKGFlcyhncm91cCA9IGNsZWFuX25hbWUpKSsgDQogICBnZW9tX3BvaW50KGFlcyhjb2xvcj10eXBlKSwgc2l6ZT0zICkrDQogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDEwLjUsIGxpbmV0eXBlID0yKSsNCiAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSA1LjUsIGxpbmV0eXBlID0yKSsNCiAgdGhlbWVfbWluaW1hbCgpICsgDQogIHRoZW1lKCANCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgICAgICBwbG90LnRpdGxlLnBvc2l0aW9uID0gInBsb3QiLA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICAgIyAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD0ndHJhbnNwYXJlbnQnKSwgI3RyYW5zcGFyZW50IHBhbmVsIGJnDQogICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9J3RyYW5zcGFyZW50JywgY29sb3I9TkEpICN0cmFuc3BhcmVudCBwbG90IGJnDQogICApKw0KICAgICAgICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZT0iUGFpcmVkIiwgbGFiZWxzID0gYygiRXhlbXB0aW9ucyIsICJObyBFeGVtcHRpb25zIiksIGRpcmVjdGlvbiA9IDEpKw0KDQogIGxhYnModGl0bGUgPSAiRGlmZmVyZW5jZSBpbiBDb21wb3NpdGUgVGF4IFJhdGUgaWYgdGhlcmUgd2VyZSBObyBFeGVtcHRpb25zIiwgDQogICAgICAgc3VidGl0bGUgPSAiT3JkZXJlZCBieSBDaGFuZ2UgaW4gVGF4IFJhdGU6IEhpZ2hlc3QsIE1lZGlhbiwgYW5kIFNtYWxsZXN0IERpZmZlcmVuY2VzIiwNCiAgICAgICBjYXB0aW9uID0gIk1lZGlhbiBjaGFuZ2UgaXMgMS4zOCBwZXJjZW50YWdlIHBvaW50cyIsDQogICAgICAgeCA9ICJDb21wb3NpdGUgVGF4IFJhdGUgKCUpIiwgeSA9ICIiICkNCg0KZ2dzYXZlKCJDb21wb3NpdGVfUmF0ZV9DaGFuZ2UucG5nIiwgd2lkdGggPSA2LCBoZWlnaHQgPSA0LCB1bml0cyA9ICJpbiIpDQpgYGANCg0KDQojIE93bmVyIE9jY3VwaWVkIFByb3BlcnRpZXMgQnVyZGVuIFNoaWZ0DQoNCkNoYW5nZSBpbiBUYXggQnVyZGVuIGZvciBPd25lciBPY2N1cGllZCBQcm9wZXJ0aWVzLiBJbmNsdWRlcyBjbGFzcyAyIHByb3BlcnRpZXMgdGhhdCBhcmUgbm90IHJlbnRhbCBwcm9wZXJ0aWVzOg0KDQpgYGB7ciBmaWcuc2hvdz0naG9sZCcsIG91dC53aWR0aD0iNTAlIn0NCmJ1cmRlbl9zaGlmdCAlPiUNCiAgICAgIG11dGF0ZShidXJkZW5fY3VycmVudCA9IGlmZWxzZShidXJkZW5fY3VycmVudD4xLCAxLCBidXJkZW5fY3VycmVudCkpICU+JQ0KICBmaWx0ZXIoQWxlYV9jYXQgPT0gIk93bmVyIE9jY3VwaWVkIikgJT4lDQogICAgICAjZmlsdGVyKG1ham9yX2NsYXNzX2NvZGUgPT0gMikgJT4lDQogIG11dGF0ZShhZ2VuY3lfbmFtZSA9IGlmZWxzZShhZ2VuY3lfbmFtZSA9PSAiVE9XTiBDSUNFUk8iLCAiQ0lUWSBPRiBDSUNFUk8iLCBhZ2VuY3lfbmFtZSkgKSAlPiUNCiAgbGVmdF9qb2luKG11bmlfc2hwLCBieSA9IGMoImFnZW5jeV9uYW1lIiA9ICJBR0VOQ1lfREVTQyIpKSAlPiUNCg0KICBnZ3Bsb3QoYWVzKGZpbGwgPSBidXJkZW5fY3VycmVudCkpICsgDQogIGdlb21fc2YoYWVzKGdlb21ldHJ5ID0gZ2VvbWV0cnkpLCBjb2xvciA9ICJibGFjayIpICsgDQogIHRoZW1lX2NsYXNzaWMoKSArIA0KICB0aGVtZShheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCkpKw0KICAgc2NhbGVfZmlsbF9zdGVwczIoDQogICAjIGhpZ2ggPSAiIzAwZTMwNCIgLCBsb3cgPSAiIzAwY2ZkNCIsDQogICAgIGhpZ2ggPSAiIzQyMDQyMCIsIGxvdyA9ICIjMDA4MDgwIiwNCiAgICMgIGhpZ2ggPSAiIzAwYThmZiIgLCBsb3cgPSAiI2ZmNDgwMCIsDQogICAgIG5pY2UuYnJlYWtzPUZBTFNFLA0KICAgICAgICAgICAgICAgICAgICAgICAgc2hvdy5saW1pdHM9VFJVRSwgDQogICBuLmJyZWFrcyA9IDYsDQogICAgICAgICAgICAgICAgICAgICBtaWRwb2ludCA9IDAuNTk3LA0KICAjIGd1aWRlID0gImxlZ2VuZCIsDQogICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gIkN1cnJlbnQgQnVyZGVuIFxuKHdpdGggRXhlbXB0aW9ucykiLCBsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQNCiAgICAgICAgICAgICAgICAgICAgKSsNCiAgbGFicyh0aXRsZSA9ICJDdXJyZW50IHNoYXJlIG9mIHByb3BlcnR5IHRheCBidXJkZW4iLCANCiAgICAgICBzdWJ0aXRsZSA9ICJmb3IgIE93bmVyIE9jY3VwaWVkIFByb3BlcnR5IFR5cGVzIiwgDQogICAgICAgY2FwdGlvbiA9ICJUaGUgbWVkaWFuIG11bmljaXBhbGl0eSBnZXRzIDU5LjclIG9mIGl0cyBwcm9wZXJ0eSB0YXggcmV2ZW51ZSANCiAgICAgICBmcm9tIENsYXNzIDIgcHJvcGVydGllcyB0aGF0IGFyZSBvd25lciBvY2N1cGllZCBpbiB0aGUgY3VycmVudCB0YXggc3lzdGVtLiIpDQoNCmJ1cmRlbl9zaGlmdCAlPiUgDQogICAgbXV0YXRlKGFnZW5jeV9uYW1lID0gaWZlbHNlKGFnZW5jeV9uYW1lID09ICJUT1dOIENJQ0VSTyIsICJDSVRZIE9GIENJQ0VSTyIsIGFnZW5jeV9uYW1lKSApICU+JQ0KICAgICMgIGZpbHRlcihtYWpvcl9jbGFzc19jb2RlID09IDIpICU+JQ0KICBmaWx0ZXIoQWxlYV9jYXQgPT0gIk93bmVyIE9jY3VwaWVkIikgJT4lDQoNCiAgbGVmdF9qb2luKG11bmlfc2hwLCBieSA9IGMoImFnZW5jeV9uYW1lIiA9ICJBR0VOQ1lfREVTQyIpKSAlPiUNCg0KICBnZ3Bsb3QoYWVzKGZpbGwgPSBidXJkZW5fbm9leGVtcHMpKSArIA0KICBnZW9tX3NmKGFlcyhnZW9tZXRyeSA9IGdlb21ldHJ5KSwgY29sb3IgPSAiYmxhY2siKSArICAgICANCiAgdGhlbWVfY2xhc3NpYyggKSArIA0KICB0aGVtZShheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCkpKw0KDQogICAgIHNjYWxlX2ZpbGxfc3RlcHMyKA0KICAgICAgIyAgaGlnaCA9ICIjMDBlMzA0IiAsIGxvdyA9ICIjMDBjZmQ0IiwNCiAgICAgIyBjb2xvcnMgPSBjKCIjZmZmZmNjIiwiI2ExZGFiNCIgLCIjNDFiNmM0IiwiIzJjN2ZiOCIsICIjMjUzNDk0IiksDQogICAgICBoaWdoID0gIiM0MjA0MjAiLCBsb3cgPSAiIzAwODA4MCIsDQogICMgICBoaWdoID0gIiMyNTM0OTQiICwgbG93ID0gIiMzYjNjMzYiICwNCiAgICAgbmljZS5icmVha3M9RkFMU0UsDQogICAgICAgICAgICAgICAgICAgICAgICBzaG93LmxpbWl0cz1UUlVFLCANCiAgIG4uYnJlYWtzID0gNiwNCiAgICAgICAgICAgICAgICAgICAgIG1pZHBvaW50ID0gMC42NSwNCiAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiQnVyZGVuIHdpdGhvdXQgXG5FeGVtcHRpb25zIiwgbGFiZWxzID0gc2NhbGVzOjpwZXJjZW50KSArDQogbGFicyh0aXRsZSA9ICJOZXcgc2hhcmUgb2YgcHJvcGVydHkgdGF4IGJ1cmRlbiIsIHN1YnRpdGxlID0gImZvciBPd25lciBvY2N1cGllZCBwcm9wZXJ0aWVzIiwgY2FwdGlvbiA9DQogICAgICAiV2l0aG91dCBleGVtcHRpb25zLCBtdW5pY2lwYWxpdGllcyB3b3VsZCBnZXQgYSBsYXJnZXIgc2hhcmUgb2YgDQogICAgICB0aGVpciByZXZlbnVlIGZyb20gb3duZXIgb2NjdXBpZWQgcHJvcGVydGllcy4NCiAgICAgIE93bmVyIG9jY3VwaWVkIHByb3BlcnRpZXMgaW5jbHVkZXMgY29uZG9zIGFuZCBzaW5nbGUtZmFtaWx5IGhvbWVzLiIpDQpgYGANCg0KYGBge3J9DQpidXJkZW5fc2hpZnQgJT4lICNmaWx0ZXIoY2xlYW5fbmFtZSAhPSAiUGhvZW5peCIpICU+JQ0KICAgIGZpbHRlcihBbGVhX2NhdCA9PSAiT3duZXIgT2NjdXBpZWQiKSAlPiUNCg0KICMgZmlsdGVyKG1ham9yX2NsYXNzX2NvZGUgPT0gMikgJT4lDQogICAgbXV0YXRlKGFnZW5jeV9uYW1lID0gaWZlbHNlKGFnZW5jeV9uYW1lID09ICJUT1dOIENJQ0VSTyIsICJDSVRZIE9GIENJQ0VSTyIsIGFnZW5jeV9uYW1lKSApICU+JQ0KICBtdXRhdGUoYnVyZGVuX2NoYW5nZSA9IGlmZWxzZShidXJkZW5fY2hhbmdlPDAsMCwgYnVyZGVuX2NoYW5nZSkpJT4lDQogICAgICMgICAgYnVyZGVuX2NoYW5nZSA9IGlmZWxzZShidXJkZW5fY2hhbmdlPjEsMSwgYnVyZGVuX2NoYW5nZSkpJT4lDQogIGxlZnRfam9pbihtdW5pX3NocCwgYnkgPSBjKCJhZ2VuY3lfbmFtZSIgPSAiQUdFTkNZX0RFU0MiKSkgJT4lDQogIGdncGxvdChhZXMoZmlsbCA9IChidXJkZW5fY2hhbmdlKjEwMCkpICkrIA0KICBnZW9tX3NmKGFlcyhnZW9tZXRyeSA9IGdlb21ldHJ5KSwgY29sb3IgPSAiYmxhY2siKSArIHRoZW1lX3ZvaWQoKSsgDQogIGxhYnModGl0bGUgPSAiQ2hhbmdlIGluIFRheCBCdXJkZW46IE93bmVyIG9jY3VwaWVkIHByb3BlcnRpZXMiLCANCiAgICAgICBjYXB0aW9uID0gIlRoZSBtZWRpYW4gc2hpZnQgZnJvbSBvd25lciBvY2N1cGllZCBwcm9wZXJ0aWVzIHRvIG90aGVyIHByb3BlcnR5IHR5cGVzDQogICAgICAgZHVlIHRvIGN1cnJlbnQgZXhlbXB0aW9ucyBpcyB3b3J0aCBhcHByb3hpbWF0ZWx5IDQuNSUgb2YgYSBtdW5pY2lwYWxpdHkncyBsZXZ5LiIpICsNCiAgICB0aGVtZV9jbGFzc2ljKCkgKyANCiAgdGhlbWUoYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpKSsNCiAgIHNjYWxlX2ZpbGxfc3RlcHMyKA0KICAgICBoaWdoID0gIiM0MjA0MjAiLCBsb3cgPSAiIzAwODA4MCIsDQogICAgIG5pY2UuYnJlYWtzPUZBTFNFLA0KICAgICBzaG93LmxpbWl0cz1UUlVFLCMgbi5icmVha3MgPSA1LA0KICAgICAgICAgICAgICAgICAgICAgbWlkcG9pbnQgPSA0LjcsICMgbWVkaWFuKGJ1cmRlbl9zaGlmdCRidXJkZW5fY2hhbmdlKjEwMCksDQogICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gIkNoYW5nZSBpbiBCdXJkZW4gXG4gUGN0IFBvaW50cyIpDQoNCmBgYA0KDQo+IENoYW5nZSBtZWRpYW4gdmVydGljYWwgbGluZSBhbmQgdGhlIGhvcml6b250YWwgbGluZXMuIFJlZmlsdGVyIHRoZSB0b3AsIG1lZGl1bSwgYW5kIGxvd2VzdCB2YWx1ZXMNCg0KYGBge3J9DQoNCg0KYnVyZGVuX3NoaWZ0ICU+JSAjZmlsdGVyKFByb3BUeXBlID09ICJTaW5nbGUtRmFtaWx5IiklPiUNCiAgICBmaWx0ZXIoQWxlYV9jYXQgPT0gIk93bmVyIE9jY3VwaWVkIikgJT4lDQoNCnN1bW1hcml6ZShtZWRpYW5fY2hhbmdlID0gbWVkaWFuKGJ1cmRlbl9jaGFuZ2UpLCAjIDQuNzQgcGVyY2VudGFnZSBwb2ludHMuDQogICAgICAgICAgbWVkaWFuX2N1cnJlbnQgPSBtZWRpYW4oYnVyZGVuX2N1cnJlbnQpLCAjNjAlDQogICAgICAgICAgbWVkaWFuX25vZXhlbXBzID0gbWVkaWFuKGJ1cmRlbl9ub2V4ZW1wcykpICMgNjYlDQojIGFzIGEgZG90IGdyYXBoICMjIA0KDQoNCm9yZGVyIDwtIGJ1cmRlbl9zaGlmdCAlPiUgDQogIHVuZ3JvdXAgJT4lIGFzX3RpYmJsZSgpICU+JQ0KICAjICBmaWx0ZXIoUmVzaWRlbnRpYWxQcm9wcyA9PSAiUmVzaWRlbnRpYWwiKSAlPiUNCiMgIGZpbHRlcihQcm9wVHlwZSA9PSAiU2luZ2xlLUZhbWlseSIpICU+JQ0KICAgIGZpbHRlcihBbGVhX2NhdCA9PSAiT3duZXIgT2NjdXBpZWQiKSAlPiUNCg0KICBzZWxlY3QoYWdlbmN5X25hbWUsIGNsZWFuX25hbWUsIGJ1cmRlbl9jdXJyZW50LCBidXJkZW5fY2hhbmdlKQ0KDQoNCg0KIyBidXJkZXJfc2hpZnRfb3JkZXJlZCA8LSAgYnVyZGVuX3NoaWZ0ICU+JSANCiMgICB1bmdyb3VwKCkgJT4lIA0KIyAgIHNlbGVjdChhZ2VuY3lfbmFtZSwgY3VycmVudF9idXJkZW4sIG5vX2V4ZW1wdGlvbnNfYnVyZGVuKSAlPiUgICAgDQojICAgcGl2b3RfbG9uZ2VyKGMoImN1cnJlbnRfYnVyZGVuIiwgIm5vX2V4ZW1wdGlvbnNfYnVyZGVuIiksIA0KIyAgICAgICAgICAgICAgICBuYW1lc190byA9ICJ0eXBlIiwgdmFsdWVzX3RvID0gInBjdF9idXJkZW4iKSAlPiUgDQojICAgbGVmdF9qb2luKG9yZGVyKQ0KDQojIGxvb2sgYXQgb25lcyB0aGF0IGNoYW5nZWQgdGhlIG1vc3QNCg0KYnVyZGVuX3NoaWZ0ICU+JSAgICAgZmlsdGVyKEFsZWFfY2F0ID09ICJPd25lciBPY2N1cGllZCIpICU+JQ0KIGFycmFuZ2UoYnVyZGVuX2N1cnJlbnQpDQoNCmJ1cmRlbl9zaGlmdCAlPiUgDQogICAgZmlsdGVyKEFsZWFfY2F0ID09ICJPd25lciBPY2N1cGllZCIpICU+JQ0KICBmaWx0ZXIoY2xlYW5fbmFtZSAhPSAiSG9mZm1hbiBFc3RhdGVzIikgJT4lICMgb25seSBiZWNhdXNlIDYgd2VyZSBiZXR3ZWVuIHRoZSBtZWRpYW4gcmFuZ2UgYW5kIEkgb25seSB3YW50ZWQgNSBpbiB0aGUgZ3JhcGgNCiAgIGZpbHRlcihidXJkZW5fY3VycmVudCA+IDAuOTMxIHxidXJkZW5fY3VycmVudCA8IC4xNyB8DQogICAgICAgICAgICAoIChidXJkZW5fY3VycmVudCA8IG1lZGlhbihidXJkZW5fY3VycmVudCkgKyAwLjAxICkmIChidXJkZW5fY3VycmVudCA+IG1lZGlhbihidXJkZW5fY3VycmVudCkgLSAwLjAxKSkgKSU+JSANCiAgdW5ncm91cCgpICU+JSANCiAgc2VsZWN0KGFnZW5jeV9uYW1lLCBjbGVhbl9uYW1lLCBidXJkZW5fY3VycmVudCwgYnVyZGVuX25vZXhlbXBzLCAgYnVyZGVuX2NoYW5nZSkgJT4lIA0KICBhcnJhbmdlKGJ1cmRlbl9jaGFuZ2UpICU+JQ0KICBtdXRhdGUoIA0KICAgIGJ1cmRlbl9ub2V4ZW1wcyA9IGlmZWxzZShidXJkZW5fbm9leGVtcHMgPiAxLCAxLCBidXJkZW5fbm9leGVtcHMpKSAlPiUNCiAgcGl2b3RfbG9uZ2VyKGMoImJ1cmRlbl9jdXJyZW50IiwgImJ1cmRlbl9ub2V4ZW1wcyIpLCANCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gInR5cGUiLCB2YWx1ZXNfdG8gPSAicGN0X2J1cmRlbiIpICU+JSANCiAgaW5uZXJfam9pbihvcmRlcikgJT4lDQogIGdncGxvdChhZXMoeCA9IHBjdF9idXJkZW4qMTAwLCANCiAgICAgICAgICAgICB5PSByZW9yZGVyKGNsZWFuX25hbWUsIC1idXJkZW5fY3VycmVudCkpKSsNCiAgIyB5PSByZW9yZGVyKGNsZWFuX25hbWUsIGJ1cmRlbl9jdXJyZW50KSkpKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSA1OS43LCBsaW5ldHlwZSA9IDMpKw0KICBnZW9tX2xpbmUoYWVzKGdyb3VwID0gY2xlYW5fbmFtZSkpKyANCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gNS41LCBsaW5ldHlwZSA9IDIpKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAxMC41LCBsaW5ldHlwZSA9IDIpKw0KICBnZW9tX3BvaW50KGFlcyhjb2xvcj10eXBlKSwgc2l6ZT0zICkrDQoNCiAgdGhlbWVfbWluaW1hbCgpICsgDQogIHRoZW1lKCNsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIA0KICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBwbG90LnRpdGxlLnBvc2l0aW9uID0gInBsb3QiLA0KICAgICMgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9J3RyYW5zcGFyZW50JyksICN0cmFuc3BhcmVudCBwYW5lbCBiZw0KICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsPSd0cmFuc3BhcmVudCcsIGNvbG9yPU5BKSAjdHJhbnNwYXJlbnQgcGxvdCBiZw0KICApKw0KICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZT0iUGFpcmVkIiwgbGFiZWxzID0gYygiQ3VycmVudCBCdXJkZW4iLCAiQnVyZGVuIGlmIFxuTm8gRXhlbXB0aW9ucyIgKSwgZGlyZWN0aW9uID0gMSkrDQoNCiAgDQogIGxhYnModGl0bGUgPSAiQ2hhbmdlIGluIE93bmVyIE9jY3VwaWVkIFRheCBCdXJkZW4iLCANCiAgICAgICBzdWJ0aXRsZSA9ICJPcmRlcmVkIGJ5IEN1cnJlbnQgVGF4IEJ1cmRlbiIsDQogIHggPSAiU2hhcmUgb2YgTGV2eSAoJSkiLCB5ID0gIiIgLCANCiAgY2FwdGlvbiA9ICJEb3R0ZWQgbGluZSByZXByZXNlbnRzIGN1cnJlbnQgdGF4IGJ1cmRlbiAoNTkuNyUgb2YgdGhlIG11bmljcGFsaXR5J3MgbGV2eSkgaW4gdGhlIG1lZGlhbiBtdW5pY2lwYWxpdHkuIA0KICBSZXNpZGVudGlhbCBUYXggQnVyZGVuIGlzIHRoZSBzaGFyZSBvZiB0aGUgcHJvcGVydHkgdGF4IGNvbGxlY3RlZCB0aGF0IHdhcyBwYWlkIGZvciBieSByZXNpZGVudGlhbCANCiAgcHJvcGVydHkgb3duZXJzLiBJbmNsdWRlcyBjb25kb3MgYW5kIGRldGFjaGVkIGhvbWVzLiBEb2VzIG5vdCBpbmNsdWRlIGNsYXNzZXMgZGVzY3JpYmVkIGFzICdyZW50YWxzJy4iKSArDQogICAgZ2VvbV9sYWJlbChsYWJlbCA9ICJIb21lIG93bmVycyBwYXkgc21hbGwgc2hhcmUgb2YgXG5sZXZ5OyB2ZXJ5IGxpdHRsZSByZXNpZGVudGlhbCIsIHg9MzUsIHkgPSAxMi41LCBsYWJlbC5zaXplID0gMSwgc2l6ZSA9IDMpKw0KICAgIGdlb21fbGFiZWwobGFiZWwgPSAiSG9tZSBvd25lcnMgcGF5IG1lZGlhbiBzaGFyZSBvZiBcbmxldnkgKDU5LjclKSwgbWl4IG9mIGxhbmQgdXNlIiwgeD0zMCwgeSA9IDcuNSwgbGFiZWwuc2l6ZSA9IDEsIHNpemUgPSAzKSArDQogICAgZ2VvbV9sYWJlbChsYWJlbCA9ICJIb21lIG93bmVycyBwYXkgbmVhcmx5IGFsbCBvZiBsZXZ5LCBcbmhpZ2hseSByZXNpZGVudGlhbCIsIHg9NzAsIHkgPSAzLCBsYWJlbC5zaXplID0gMSxzaXplID0gMykNCg0KYGBgDQoNCmBgYHtyfQ0KIyMjIENoYW5nZSBpbiBCdXJkZW4NCmJ1cmRlbl9zaGlmdCAlPiUgICAgDQogIHVuZ3JvdXAoKSAlPiUgDQogICAgZmlsdGVyKEFsZWFfY2F0ID09ICJPd25lciBPY2N1cGllZCIpICU+JQ0KDQogICAjIGZpbHRlcihQcm9wVHlwZSA9PSAiU2luZ2xlLUZhbWlseSIpICU+JQ0KICAgIyBmaWx0ZXIoYnVyZGVuX2NoYW5nZSA+IDAuMyB8IGJ1cmRlbl9jaGFuZ2UgPCAuMDEpICU+JSANCg0KICBzZWxlY3QoYWdlbmN5X25hbWUsIGNsZWFuX25hbWUsIGJ1cmRlbl9jdXJyZW50LCBidXJkZW5fbm9leGVtcHMsDQogICAgICAgICBidXJkZW5fY2hhbmdlKSAlPiUgDQogIG11dGF0ZSgNCiAgICAgICAgIGJ1cmRlbl9jdXJyZW50ID0gaWZlbHNlKGJ1cmRlbl9jdXJyZW50ID4gMSwgMSwgYnVyZGVuX2N1cnJlbnQpKSAlPiUNCiAgcGl2b3RfbG9uZ2VyKGMoImJ1cmRlbl9jdXJyZW50IiwgImJ1cmRlbl9ub2V4ZW1wcyIpLA0KICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAidHlwZSIsIHZhbHVlc190byA9ICJwY3RfYnVyZGVuIikgJT4lDQogIGlubmVyX2pvaW4ob3JkZXIpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBwY3RfYnVyZGVuLCB5PSByZW9yZGVyKGNsZWFuX25hbWUsIC1idXJkZW5fY3VycmVudCkpKSsNCiAgZ2VvbV9saW5lKGFlcyhncm91cCA9IGNsZWFuX25hbWUpKSsgDQogICBnZW9tX3BvaW50KGFlcyhjb2xvcj10eXBlKSwgc2l6ZT0zICkrDQogIHRoZW1lX21pbmltYWwoKSArIA0KICB0aGVtZSgjbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCANCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgICAgICBwbG90LnRpdGxlLnBvc2l0aW9uID0gInBsb3QiLA0KICAgICAjICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsPSd0cmFuc3BhcmVudCcpLCAjdHJhbnNwYXJlbnQgcGFuZWwgYmcNCiAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD0ndHJhbnNwYXJlbnQnLCBjb2xvcj1OQSkgI3RyYW5zcGFyZW50IHBsb3QgYmcNCiAgICkrDQogICAgICAgIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlPSJQYWlyZWQiLCBsYWJlbHMgPSBjKCJDdXJyZW50IEJ1cmRlbiIsIkJ1cmRlbiBpZiBcbk5vIEV4ZW1wdGlvbnMiKSwgZGlyZWN0aW9uID0gMSkrDQoNCiAgbGFicyh0aXRsZSA9ICJDaGFuZ2UgaW4gT3duZXIgT2NjdXBpZWQgUHJvcGVydHkgVGF4IEJ1cmRlbiIsIA0KICB4ID0gIlNoYXJlIG9mIExldnkgKCUpIiwgeSA9ICIiICwgDQogIGNhcHRpb24gPSAiVGF4IEJ1cmRlbiBpcyB0aGUgU2hhcmUgb2YgdGhlIHByb3BlcnR5IHRheCBjb2xsZWN0ZWQgdGhhdCB3YXMgcGFpZCBmb3IgYnkgDQogICAgIGhvbWUgb3duZXJzIGluIHByb3BlcnR5IGNsYXNzZXMgMi4iKQ0KDQoNCg0KYnVyZGVuX3NoaWZ0ICU+JSAgICANCiAgdW5ncm91cCgpICU+JSANCiAgICBmaWx0ZXIoQWxlYV9jYXQgPT0gIk93bmVyIE9jY3VwaWVkIikgJT4lDQoNCiAgIyAgZmlsdGVyKFByb3BUeXBlID09ICJTaW5nbGUtRmFtaWx5IikgJT4lDQogICAgZmlsdGVyKGJ1cmRlbl9ub2V4ZW1wcyA+IDAuMiB8IGJ1cmRlbl9ub2V4ZW1wcyA8IC4wMDEpICU+JSANCg0KICBzZWxlY3QoYWdlbmN5X25hbWUsIGNsZWFuX25hbWUsIGJ1cmRlbl9jdXJyZW50LCBidXJkZW5fbm9leGVtcHMsDQogICAgICAgICBidXJkZW5fY2hhbmdlKSAlPiUgDQogIG11dGF0ZSgNCiAgICAgICAgIGJ1cmRlbl9jdXJyZW50ID0gaWZlbHNlKGJ1cmRlbl9jdXJyZW50ID4gMSwgMSwgYnVyZGVuX2N1cnJlbnQpKSAlPiUNCiAgcGl2b3RfbG9uZ2VyKGMoImJ1cmRlbl9jdXJyZW50IiwgImJ1cmRlbl9ub2V4ZW1wcyIpLA0KICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAidHlwZSIsIHZhbHVlc190byA9ICJwY3RfYnVyZGVuIikgJT4lDQogIGlubmVyX2pvaW4ob3JkZXIpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBwY3RfYnVyZGVuLCB5PSByZW9yZGVyKGNsZWFuX25hbWUsIGJ1cmRlbl9jaGFuZ2UpKSkrDQogIGdlb21fbGluZShhZXMoZ3JvdXAgPSBjbGVhbl9uYW1lKSkrIA0KICAgZ2VvbV9wb2ludChhZXMoY29sb3I9dHlwZSksIHNpemU9MyApKw0KICB0aGVtZV9taW5pbWFsKCkgKyANCiAgdGhlbWUoI2xlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgDQogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgICAgICAgcGxvdC50aXRsZS5wb3NpdGlvbiA9ICJwbG90IiwNCiAgICAgIyAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD0ndHJhbnNwYXJlbnQnKSwgI3RyYW5zcGFyZW50IHBhbmVsIGJnDQogICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9J3RyYW5zcGFyZW50JywgY29sb3I9TkEpICN0cmFuc3BhcmVudCBwbG90IGJnDQogICApKw0KICAgICAgICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZT0iUGFpcmVkIiwgbGFiZWxzID0gYyggIkN1cnJlbnQgQnVyZGVuIiwiQnVyZGVuIGlmIFxuTm8gRXhlbXB0aW9ucyIpLCBkaXJlY3Rpb24gPSAxKSsNCg0KICBsYWJzKHRpdGxlID0gIkNoYW5nZSBpbiBPd25lciBPY2N1cGllZCBDbGFzcyAyIFJlc2lkZW50aWFsIFRheCBCdXJkZW4iLCANCiAgeCA9ICJTaGFyZSBvZiBMZXZ5ICglKSIsIHkgPSAiIiAsIA0KICBjYXB0aW9uID0gIlRheCBCdXJkZW4gaXMgdGhlIFNoYXJlIG9mIHRoZSBwcm9wZXJ0eSB0YXggY29sbGVjdGVkIHRoYXQgd2FzIHBhaWQgZm9yIGJ5IA0KICAgIGhvbWUgb3duZXJzIGluIHByb3BlcnR5IGNsYXNzZXMgMi4iKQ0KYGBgDQoNCmBgYHtyfQ0KYnVyZGVuX3NoaWZ0ICU+JSB1bmdyb3VwKCkgJT4lICNmaWx0ZXIoUHJvcFR5cGUgPT0gIlNpbmdsZS1GYW1pbHkiKSAlPiUNCiAgICBmaWx0ZXIoQWxlYV9jYXQgPT0gIk93bmVyIE9jY3VwaWVkIikgJT4lDQoNCmFycmFuZ2UoYnVyZGVuX2NoYW5nZSkgJT4lIGhlYWQoKQ0KDQoNCmJ1cmRlbl9zaGlmdCAlPiUgICAgDQogIHVuZ3JvdXAoKSAlPiUgDQogICAgZmlsdGVyKEFsZWFfY2F0ID09ICJPd25lciBPY2N1cGllZCIpICU+JQ0KDQogICAjIGZpbHRlcihQcm9wVHlwZSA9PSAiU2luZ2xlLUZhbWlseSIpICU+JQ0KICBmaWx0ZXIoY2xlYW5fbmFtZSAhPSAiUGhvZW5peCIpICU+JQ0KICBmaWx0ZXIoY2xlYW5fbmFtZSAlaW4lIGMoIlNjaGF1bWJ1cmciLCAiRWxrIEdyb3ZlIFZpbGxhZ2UiLCAiV2VzdGNoZXN0ZXIiLCAiUGFsb3MgSGlsbHMiLCAiT3JsYW5kIEhpbGxzIikgfA0KICMgZmlsdGVyKGNsZWFuX25hbWUgJWluJSBjKCJIb21ldG93biIsICJCdXJiYW5rIiwgIlNjaGF1bWJ1cmciLCAiRWxrIEdyb3ZlIFZpbGxhZ2UiLCAiV2VzdGNoZXN0ZXIiKSB8IA0KICAgICAgICAgICBidXJkZW5fY2hhbmdlID4gMC4xMSB8YnVyZGVuX2NoYW5nZSA8IC4wMDMgKSAlPiUNCiAgICAgICAgICN8ICAoIChidXJkZW5fY2hhbmdlIDwgbWVkaWFuKGJ1cmRlbl9jaGFuZ2UpICsgMC4wMDEgKSYgKGJ1cmRlbl9jaGFuZ2UgPiBtZWRpYW4oYnVyZGVuX2NoYW5nZSkgLSAwLjAwMSkpICkgJT4lIA0KICBzZWxlY3QoYWdlbmN5X25hbWUsIGNsZWFuX25hbWUsIGJ1cmRlbl9jdXJyZW50LCBidXJkZW5fbm9leGVtcHMsDQogICAgICAgICBidXJkZW5fY2hhbmdlKSAlPiUgDQogIHBpdm90X2xvbmdlcihjKCJidXJkZW5fY3VycmVudCIsICJidXJkZW5fbm9leGVtcHMiKSwNCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gInR5cGUiLCB2YWx1ZXNfdG8gPSAicGN0X2J1cmRlbiIpICU+JQ0KICBpbm5lcl9qb2luKG9yZGVyKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gcGN0X2J1cmRlbioxMDAsIHk9IHJlb3JkZXIoY2xlYW5fbmFtZSwgYnVyZGVuX2NoYW5nZSoxMDApKSkrDQogIGdlb21fbGluZShhZXMoZ3JvdXAgPSBjbGVhbl9uYW1lKSkrIA0KICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDUuNSwgbGluZXR5cGUgPSAyKSsNCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMTAuNSwgbGluZXR5cGUgPSAyKSsNCiAgIGdlb21fcG9pbnQoYWVzKGNvbG9yPXR5cGUpLCBzaXplPTMgKSsNCiAgdGhlbWVfbWluaW1hbCgpICsgDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgDQogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgICAgICAgcGxvdC50aXRsZS5wb3NpdGlvbiA9ICJwbG90IiwNCiAgICAgIyAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD0ndHJhbnNwYXJlbnQnKSwgI3RyYW5zcGFyZW50IHBhbmVsIGJnDQogICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9J3RyYW5zcGFyZW50JywgY29sb3I9TkEpICN0cmFuc3BhcmVudCBwbG90IGJnDQogICApKw0KICAgICAgICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZT0iUGFpcmVkIiwgbGFiZWxzID0gYyggIkN1cnJlbnQgQnVyZGVuIiwiQnVyZGVuIGlmIFxuTm8gRXhlbXB0aW9ucyIpLCBkaXJlY3Rpb24gPSAxKSsNCg0KICBsYWJzKHRpdGxlID0gIkNoYW5nZSBpbiBSZXNpZGVudGlhbCBUYXggQnVyZGVuIChPd25lciBPY2N1cGllZCBvbmx5KSIsIA0KICB4ID0gIlNoYXJlIG9mIExldnkgKCUpIiwgeSA9ICIiICkNCg0KZ2dzYXZlKCJyZXNpZGVudGlhbF90YXhfYnVyZGVuX2NoYW5nZS5wbmciLCB3aWR0aCA9IDYsIGhlaWdodCA9IDQsIHVuaXRzID0gImluIikNCmBgYA0KDQoNCg0KDQojIFN1bW1hcnkgdGFibGUgb2YgQnVyZGVuIFNoaWZ0OiBHcm91cGVkIFByb3BlcnR5IENhdGVnb3JpZXMNCg0KU2FtZSBkYXRhIHRoYXQgaXMgdXNlZCBhYm92ZSBidXQgcHJvcGVydHkgdHlwZXMgYXJlIGNvbWJpbmVkIGludG8gNCBjYXRlZ29yaWVzOg0KDQotIE93bmVyIE9jY3VwaWVkICAoTW9zdCBvZiBDbGFzcyAyIFByb3BlcnRpZXMuIENsYXNzZXMgd2l0aCAicmVudGFsIiBpbiB0aGUgZGVzY3JpcHRpb24gd2VyZSBpbmNsdWRlZCB3aXRoIFJlbnRlciBwcm9wZXJ0aWVzLikgICAgDQotIFJlbnRlcnMgKENsYXNzIDMgJiA5IGFuZCBzb21lIG9mIENsYXNzIDIpICANCi0gQ29tbWVyY2lhbCAoc3BsaXRzIGNsYXNzIDUsIDYsIDcsIGFuZCA4LiBDb21tZXJjaWFsL0luZHVzdHJpYWwsIGluY2VudGl2ZSBhbmQgbm9ucHJvZml0IGNsYXNzZXMgYmFzZWQgb24gcHJvcGVydHkgY2xhc3MgZGVzY3JpcHRpb25zKQ0KLSBJbmR1c3RyaWFsIChzcGxpdHMgY2xhc3MgNSwgNiwgNywgYW5kIDguIENvbW1lcmNpYWwvSW5kdXN0cmlhbCwgaW5jZW50aXZlIGFuZCBub25wcm9maXQgY2xhc3NlcyBiYXNlZCBvbiBwcm9wZXJ0eSBjbGFzcyBkZXNjcmlwdGlvbnMpDQotIE90aGVyPzogVmFjYW50IExhbmQuDQogIC0gUmFpbHJvYWQgbGFuZCBpcyBkcm9wcGVkIGZyb20gY2FsY3VsYXRpb25zIGFuZCB0YWJsZXMuIE5vdCB0YXhlZC4gICANCg0KYGBge3J9DQojIEN1cnJlbnQgQnVyZGVuOg0KDQptdW5pc18zcHJvcGVydHlfdHlwZXMgPC0gYnVyZGVuX3NoaWZ0ICU+JSMgbXV0YXRlKA0KICAgICAjICAgICAgIGJ1cmRlbl9ub2V4ZW1wcyA9IGlmZWxzZShpcy5uYShidXJkZW5fbm9leGVtcHMpLCAwLCBidXJkZW5fbm9leGVtcHMpKSAlPiUNCiAgIyAgICBtdXRhdGUoYnVyZGVuX2N1cnJlbnQgPSBpZmVsc2UoYnVyZGVuX2N1cnJlbnQ+MSwgMSwgYnVyZGVuX2N1cnJlbnQpKSAlPiUNCiAgdW5ncm91cCgpICU+JSANCiAgZ3JvdXBfYnkoYWdlbmN5X25hbWUsIGNsZWFuX25hbWUsIEFsZWFfY2F0KSAlPiUNCiAgc3VtbWFyaXplKCNmaW5hbF90YXhfdG9fZGlzdCA9IHN1bShmaW5hbF90YXhfdG9fZGlzdCwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgICAgIGJ1cmRlbl9jdXJyZW50ID0gc3VtKGJ1cmRlbl9jdXJyZW50LCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgYnVyZGVuX25vZXhlbXBzID0gc3VtKGJ1cmRlbl9ub2V4ZW1wcywgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgICAgIGJ1cmRlbl9jaGFuZ2UgPSBzdW0oYnVyZGVuX2NoYW5nZSwgbmEucm0gPSBUUlVFKSkgDQoNCiN3cml0ZS5jc3YobXVuaXNfM3Byb3BlcnR5X3R5cGVzLCAiMV91c2VtZXRhYmxlLmNzdiIpDQoNCnByb3B0eXBlczNfY3VycmVudCA8LSBidXJkZW5fc2hpZnQgJT4lIA0KICAgIG11dGF0ZShidXJkZW5fY3VycmVudCA9IGlmZWxzZShpcy5uYShidXJkZW5fY3VycmVudCksIDAsIGJ1cmRlbl9jdXJyZW50KSkgJT4lDQoNCiAgcGl2b3Rfd2lkZXIoIGlkX2NvbHMgPSBjbGVhbl9uYW1lICwgbmFtZXNfZnJvbSA9ICJBbGVhX2NhdCIsIHZhbHVlc19mcm9tID0gImJ1cmRlbl9jdXJyZW50IixuYW1lc19wcmVmaXg9IkN1cnJlbnQgLSAiLCB2YWx1ZXNfZmlsbCA9IDAgKSAlPiUgDQogIHNlbGVjdChjbGVhbl9uYW1lLCAgZXZlcnl0aGluZygpKSANCg0KcHJvcHR5cGVzM19jdXJyZW50WzI6NF0gPC0gc2FwcGx5KHByb3B0eXBlczNfY3VycmVudFsyOjRdLCBmdW5jdGlvbih4KSBzY2FsZXM6OnBlcmNlbnQoeCwgYWNjdXJhY3k9LjAxKSApDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KcHJvcHR5cGVzM19jdXJyZW50DQpgYGANCg0KYGBge3J9DQojIF9fVGF4IEJ1cmRlbiBpZiB0aGVyZSB3ZXJlIG5vIGV4ZW1wdGlvbnM6X18NCg0KcHJvcHR5cGVzM19ub2V4ZW1wcyA8LSBidXJkZW5fc2hpZnQgJT4lIA0KICBtdXRhdGUoYnVyZGVuX25vZXhlbXBzID0gaWZlbHNlKGlzLm5hKGJ1cmRlbl9ub2V4ZW1wcyksIDAsIGJ1cmRlbl9ub2V4ZW1wcykpICU+JQ0KICBwaXZvdF93aWRlciggaWRfY29scyA9IGNsZWFuX25hbWUgLCBuYW1lc19mcm9tID0gIkFsZWFfY2F0IiwgdmFsdWVzX2Zyb20gPSAiYnVyZGVuX25vZXhlbXBzIiwgbmFtZXNfcHJlZml4ID0gIlcvTyBFeGVtcHRpb25zIC0gIiwgdmFsdWVzX2ZpbGwgPSAwKSAgDQpwcm9wdHlwZXMzX25vZXhlbXBzWzI6NF0gPC0gc2FwcGx5KHByb3B0eXBlczNfbm9leGVtcHNbMjo0XSwgZnVuY3Rpb24oeCkgc2NhbGVzOjpwZXJjZW50KHgsIGFjY3VyYWN5PS4wMSkpDQpwcm9wdHlwZXMzX25vZXhlbXBzDQpgYGANCg0KKipDaGFuZ2UgaW4gU2hhcmUgb2YgQnVyZGVuIGlmIHRoZXJlIHdlcmUgbm8gZXhlbXB0aW9uczoqKg0KDQpgYGB7cn0NCiMgYnVyZGVuX3NoaWZ0ICU+JSB1bmdyb3VwKCkgJT4lIA0KIyAgIGdyb3VwX2J5KGFnZW5jeV9uYW1lLCBQcm9wVHlwZSkgJT4lDQojICAgc3VtbWFyaXplKGRpc3RyaWN0X3Jldl9jb2xsZWN0ZWQgPSBzdW0oZGlzdHJpY3RfcmV2X2NvbGxlY3RlZCksDQojICAgICAgICAgICAgIGN1cnJlbnRfYnVyZGVuID0gc3VtKGN1cnJlbnRfYnVyZGVuKSwNCiMgICAgICAgICAgICAgbm9fZXhlbXB0aW9uc19idXJkZW4gPSBzdW0obm9fZXhlbXB0aW9uc19idXJkZW4pKSANCg0KcHJvcHNfd2lkZSA8LSBidXJkZW5fc2hpZnQgJT4lDQogIGZpbHRlcighaXMubmEoQWxlYV9jYXQpKSU+JQ0KICBwaXZvdF93aWRlcihpZF9jb2xzID0gY2xlYW5fbmFtZSAsIA0KICAgICAgICAgICAgICAgbmFtZXNfZnJvbSA9ICJBbGVhX2NhdCIsIA0KICAgICAgICAgICAgICAgdmFsdWVzX2Zyb20gPSAiYnVyZGVuX2NoYW5nZSIsIHZhbHVlc19maWxsID0gMCkgJT4lIA0KICBzZWxlY3QoY2xlYW5fbmFtZSwgZXZlcnl0aGluZygpKSAlPiUNCiAgYXJyYW5nZShkZXNjKGBPd25lciBPY2N1cGllZGApICkNCg0KcHJvcHNfd2lkZVsyOjddIDwtIHNhcHBseShwcm9wc193aWRlWzI6N10sIGZ1bmN0aW9uKHgpIHNjYWxlczo6cGVyY2VudCh4LCBhY2N1cmFjeT0uMDAxKSkNCnByb3BzX3dpZGUNCg0KDQpwcm9wdHlwZXMzX2NvbXBhcmlzb250YWJsZTwtIGxlZnRfam9pbihwcm9wdHlwZXMzX2N1cnJlbnQsIHByb3B0eXBlczNfbm9leGVtcHMsIGJ5ID0gImNsZWFuX25hbWUiKSANCnByb3B0eXBlczNfY29tcGFyaXNvbnRhYmxlDQoNCndyaXRlX2Nzdihwcm9wdHlwZXMzX2NvbXBhcmlzb250YWJsZSwgIk93bmVyT2NjdXBpZWRfQ29tcGFyaXNvblRhYmxlLmNzdiIpDQoNCmBgYA0KDQpgYGB7cn0NCnByb3B0eXBlczNfYnVyZGVuY2hhbmdlIDwtIGJ1cmRlbl9zaGlmdCAlPiUgDQogIGZpbHRlcighaXMubmEoQWxlYV9jYXQpKSU+JQ0KICBtdXRhdGUoYnVyZGVuX25vZXhlbXBzID0gaWZlbHNlKGlzLm5hKGJ1cmRlbl9jaGFuZ2UpLCAwLCBidXJkZW5fY2hhbmdlKSkgJT4lDQogIHBpdm90X3dpZGVyKCBpZF9jb2xzID0gY2xlYW5fbmFtZSAsIG5hbWVzX2Zyb20gPSAiQWxlYV9jYXQiLCB2YWx1ZXNfZnJvbSA9ICJidXJkZW5fY2hhbmdlIiwgdmFsdWVzX2ZpbGwgPSAwKSAlPiUNCiAgYXJyYW5nZShkZXNjKGBPd25lciBPY2N1cGllZGApKQ0KDQpwcm9wdHlwZXMzX2J1cmRlbmNoYW5nZVsyOjRdIDwtIHNhcHBseShwcm9wdHlwZXMzX2J1cmRlbmNoYW5nZVsyOjRdLCBmdW5jdGlvbih4KSBzY2FsZXM6OnBlcmNlbnQoeCwgYWNjdXJhY3k9LjAxKSkNCnByb3B0eXBlczNfYnVyZGVuY2hhbmdlDQoNCiNwcm9wdHlwZXMzX2J1cmRlbmNoYW5nZSAlPiUgd3JpdGVfY3N2KCJidXJkZW5fY2hhbmdlX2F1Z3VzdDYuY3N2IikNCg0KYGBgDQoNCiMgQ29vayBDb3VudHkgIkNvc3QiIFZhbHVlcw0KDQoqKiJNdWx0aXBsaWVzIHRoZSBFQVYgZXhlbXB0ZWQgZm9yIGFsbCBDb29rIENvdW50eSBtdW5pY2lwYWxpdGllcyBieSB0aGVpciBjb25zb2xpZGF0ZWQgdGF4IHJhdGVzIGluIGVhY2ggbXVuaWNpcGFsaXR5IioqDQoNCj4gRG8gdGhpcyBieSB0YXhjb2RlIGFuZCBhY3R1YWwgdGF4IGNvZGUgdGF4IHJhdGUuIE11Y2ggbW9yZSBhY2N1cmF0ZS4NCg0KYGBge3J9DQp0YXhjb2Rlc19jdXJyZW50ICU+JSANCiAgc3VtbWFyaXplKGZvcmdvbmVfcmV2ID0gc3VtKHRheF9hbXRfZXhlLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgZXhlbXB0X0VBViA9IHN1bSh0YXhfYW10X2V4ZS8odGF4X2NvZGVfcmF0ZS8xMDApLCBuYS5ybSA9IFRSVUUpDQogICkNCmBgYA0KDQotICAgVGhlcmUgaXMgXCQxNSw3NzAsOTEwLDE3NiBvZiBFQVYgdGhhdCBpcyBleGVtcHQgZnJvbSBwcm9wZXJ0eSB0YXhlcy4NCg0KLSAgIFwkMS41IEJpbGxpb24gb2YgcG90ZW50aWFsIHJldmVudWUgaXMgdHJhbnNmZXJyZWQgdG8gb3RoZXIgdGF4cGF5ZXJzIGR1ZSB0byBjdXJyZW50IGV4ZW1wdGlvbnMuDQoNCmBgYHtyIGZpZy5zaG93PSdob2xkJywgb3V0LndpZHRoPSI1MCUifQ0KQ3VycmVudF9UYXhyYXRlcyAlPiUgDQogIG11dGF0ZSh0cmFuc2ZlcmVkX3RheGVzID0gdGF4X3JhdGVfY3VycmVudCpFeGVtcHRfRUFWKSAlPiUgDQogICAgbXV0YXRlKGFnZW5jeV9uYW1lID0gaWZlbHNlKGFnZW5jeV9uYW1lID09ICJUT1dOIENJQ0VSTyIsICJDSVRZIE9GIENJQ0VSTyIsIGFnZW5jeV9uYW1lKSANCiAgICApICU+JQ0KICBsZWZ0X2pvaW4obXVuaV9zaHAsIGJ5ID0gYygiYWdlbmN5X25hbWUiID0gIkFHRU5DWV9ERVNDIikpICU+JQ0KDQogIGdncGxvdChhZXMoZmlsbCA9IHRyYW5zZmVyZWRfdGF4ZXMpKSArDQogIGdlb21fc2YoYWVzKGdlb21ldHJ5ID0gZ2VvbWV0cnkpLCBjb2xvciA9ICJibGFjayIpICsgDQogIHRoZW1lX3ZvaWQoKSArIA0KICB0aGVtZShheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCkpKw0KICBzY2FsZV9maWxsX3N0ZXBzMigNCiAgICBoaWdoID0gIiM0MjA0MjAiLCBsb3cgPSAiYmxhY2siLA0KICAgICMgbWlkcG9pbnQgPSBtZWRpYW4odHJhbnNmZXJlZF90YXhlcyksDQogICAgc2hvdy5saW1pdHM9VFJVRSwNCiAgICBuaWNlLmJyZWFrcz1GQUxTRSwNCiAgICBuID02LA0KICAgIG5hbWUgPSAiIiwNCiAgICBsYWJlbHMgPSBzY2FsZXM6OmRvbGxhcg0KICApKw0KICANCiAgbGFicyh0aXRsZSA9ICJEb2xsYXJzIHBhc3NlZCBmcm9tIENsYXNzIDIgcHJvcGVydGllcyB0byBvdGhlcnMgXG5kdWUgdG8gY3VycmVudCBleGVtcHRpb25zIikNCg0KQ3VycmVudF9UYXhyYXRlcyAlPiUgDQogIGZpbHRlcihjbGVhbl9uYW1lICE9ICJDaGljYWdvIikgJT4lDQogIG11dGF0ZSh0cmFuc2ZlcmVkX3RheGVzID0gdGF4X3JhdGVfY3VycmVudCpFeGVtcHRfRUFWKSAlPiUgDQogICAgbXV0YXRlKGFnZW5jeV9uYW1lID0gaWZlbHNlKGFnZW5jeV9uYW1lID09ICJUT1dOIENJQ0VSTyIsICJDSVRZIE9GIENJQ0VSTyIsIGFnZW5jeV9uYW1lKSANCiAgICApICU+JQ0KICBsZWZ0X2pvaW4obXVuaV9zaHAsIGJ5ID0gYygiYWdlbmN5X25hbWUiID0gIkFHRU5DWV9ERVNDIikpICU+JQ0KDQogICAgZ2dwbG90KGFlcyhmaWxsID0gdHJhbnNmZXJlZF90YXhlcykpICsNCiAgICBnZW9tX3NmKGFlcyhnZW9tZXRyeSA9IGdlb21ldHJ5KSwgY29sb3IgPSAiYmxhY2siKSArDQogIHRoZW1lX3ZvaWQoKSArIA0KICB0aGVtZShheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCkpKw0Kc2NhbGVfZmlsbF9zdGVwczIoDQogICAgaGlnaCA9ICIjNDIwNDIwIiwgbG93ID0gImJsYWNrIiwNCiAgIyBtaWRwb2ludCA9IG1lZGlhbih0cmFuc2ZlcmVkX3RheGVzKSwNCiAgICAgICAgICAgICAgICAgICBzaG93LmxpbWl0cz1UUlVFLA0KICBuaWNlLmJyZWFrcz1GQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgbiA9NiwNCiAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICIiLA0KICAgICAgICAgbGFiZWxzID0gc2NhbGVzOjpkb2xsYXINCikrDQogDQogIGxhYnModGl0bGUgPSAiRG9sbGFycyBwYXNzZWQgZnJvbSBDbGFzcyAyIFJlc2lkZW50aWFsIHByb3BlcnRpZXMgdG8gb3RoZXJzIFxuZHVlIHRvIGN1cnJlbnQgZXhlbXB0aW9ucyIsICAgIA0KICAgICAgICAgY2FwdGlvbiA9ICJJZ25vcmVzIENoaWNhZ28gKG92ZXIgJDQ2MEspIHRvIGhpZ2hsaWdodCBvdGhlciBtdW5pY2lwYWxpdGllcyIpDQpnZ3NhdmUoImNvb2tfbm9jaGljYWdvLnBuZyIpDQpgYGANCg0KYGBge3IgaW5jbHVkZT1GQUxTRX0NCmNoaWNhZ28gPC0gQ3VycmVudF9UYXhyYXRlcyAlPiUgDQogIGZpbHRlcihjbGVhbl9uYW1lID09ICJDaGljYWdvIikgJT4lDQogIG11dGF0ZSh0cmFuc2ZlcmVkX3RheGVzID0gdGF4X3JhdGVfY3VycmVudCpFeGVtcHRfRUFWKSAlPiUgDQogICAgbXV0YXRlKGFnZW5jeV9uYW1lID0gaWZlbHNlKGFnZW5jeV9uYW1lID09ICJUT1dOIENJQ0VSTyIsICJDSVRZIE9GIENJQ0VSTyIsIGFnZW5jeV9uYW1lKSANCiAgICApICU+JQ0KICBsZWZ0X2pvaW4obXVuaV9zaHAsIGJ5ID0gYygiYWdlbmN5X25hbWUiID0gIkFHRU5DWV9ERVNDIikpICU+JQ0KDQogICAgZ2dwbG90KGFlcyhmaWxsID0gdHJhbnNmZXJlZF90YXhlcyksICkgKw0KICAgIGdlb21fc2YoYWVzKGdlb21ldHJ5ID0gZ2VvbWV0cnkpLCBmaWxsID0iIzFBNUU3RCIsIGNvbG9yID0gImJsYWNrIikgKyANCiAgICAgIHRoZW1lX3ZvaWQoKSArIA0KICB0aGVtZShheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCksIGxlZ2VuZC5wb3NpdGlvbiAgPSAibm9uZSIpDQoNCmNoaWNhZ28NCmdnc2F2ZSgiY2hpY2Fnby5wbmciKQ0KDQpDdXJyZW50X1RheHJhdGVzICU+JSANCiAgZmlsdGVyKGNsZWFuX25hbWUgIT0gIkNoaWNhZ28iKSAlPiUNCiAgbXV0YXRlKHRyYW5zZmVyZWRfdGF4ZXMgPSB0YXhfcmF0ZV9jdXJyZW50KkV4ZW1wdF9FQVYpICU+JSANCiAgICBtdXRhdGUoYWdlbmN5X25hbWUgPSBpZmVsc2UoYWdlbmN5X25hbWUgPT0gIlRPV04gQ0lDRVJPIiwgIkNJVFkgT0YgQ0lDRVJPIiwgYWdlbmN5X25hbWUpIA0KICAgICkgJT4lDQogIGZ1bGxfam9pbihtdW5pX3NocCwgYnkgPSBjKCJhZ2VuY3lfbmFtZSIgPSAiQUdFTkNZX0RFU0MiKSkgJT4lDQoNCiAgICBnZ3Bsb3QoYWVzKGZpbGwgPSB0cmFuc2ZlcmVkX3RheGVzKSkgKw0KICAgIGdlb21fc2YoYWVzKGdlb21ldHJ5ID0gZ2VvbWV0cnkpLCBjb2xvciA9ICJibGFjayIpICsNCiAgdGhlbWVfdm9pZCgpICsgDQogIHRoZW1lKGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSkrDQpzY2FsZV9maWxsX3N0ZXBzMigNCiAgICBoaWdoID0gIiM0MjA0MjAiLCBsb3cgPSAiYmxhY2siLA0KICAjIG1pZHBvaW50ID0gbWVkaWFuKHRyYW5zZmVyZWRfdGF4ZXMpLA0KICAgICAgICAgICAgICAgICAgIHNob3cubGltaXRzPVRSVUUsDQogIG5pY2UuYnJlYWtzPUZBTFNFLA0KICBuYS52YWx1ZSA9ICJkYXJrYmx1ZSIsDQogICAgICAgICAgICAgICAgICAgIG4gPTYsDQogICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiIiwNCiAgICAgICAgIGxhYmVscyA9IHNjYWxlczo6ZG9sbGFyDQopDQoNCmdnc2F2ZSgiY29va19ub2NoaWNhZ28ucG5nIikNCmBgYA0KDQoNCg0KYGBge3IgZmlnLnNob3c9J2hvbGQnLCBvdXQud2lkdGg9IjUwJSJ9DQpjbGFzczJfcGVyYyA8LSBjbGFzczJfcGVyYyAlPiUgIG11dGF0ZShwZXJjZW50X2V4ZW1wdCA9IGV4ZW1wdF9FQVYvbXVuaV9FQVZfaW5jbHVkZXNUSUYpIA0KDQpjbGFzczJfcGVyYyU+JQ0KICAgIG11dGF0ZShhZ2VuY3lfbmFtZSA9IGlmZWxzZShhZ2VuY3lfbmFtZSA9PSAiVE9XTiBDSUNFUk8iLCAiQ0lUWSBPRiBDSUNFUk8iLCBhZ2VuY3lfbmFtZSkgDQogICAgKSAlPiUNCiAgbGVmdF9qb2luKG11bmlfc2hwLCBieSA9IGMoImFnZW5jeV9uYW1lIiA9ICJBR0VOQ1lfREVTQyIpKSAlPiUNCg0KICAgIGdncGxvdChhZXMoZmlsbCA9IHBlcmNlbnRfZXhlbXB0KSkgKw0KICAgIGdlb21fc2YoYWVzKGdlb21ldHJ5ID0gZ2VvbWV0cnkpLCBjb2xvciA9ICJibGFjayIpICsgDQogICAgICB0aGVtZV92b2lkKCkgKyANCiAgdGhlbWUoYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpKSsNCnNjYWxlX2ZpbGxfc3RlcHMyKA0KICAgIGhpZ2ggPSAiIzQyMDQyMCIsIGxvdyA9ICJibGFjayIsDQogbWlkcG9pbnQgPSBtZWRpYW4oY2xhc3MyX3BlcmMkcGVyY2VudF9leGVtcHQpLA0KICAgICAgICAgICAgICAgICAgIHNob3cubGltaXRzPVRSVUUsDQogIG5pY2UuYnJlYWtzPUZBTFNFLA0KICAgICAgICAgICAgICAgICAgICBuID02LA0KICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gIlBlcmNlbnQgRXhlbXB0IiwNCiAgICAgICAgIGxhYmVscyA9IHNjYWxlczo6cGVyY2VudA0KKSsNCiANCiAgbGFicyh0aXRsZSA9ICJQZXJjZW50IEV4ZW1wdDogIEV4ZW1wdCBFQVYgLyBBbGwgRUFWIGluIE11bmljaXBhbGl0eSIpDQoNCg0KDQoNCg0KY2xhc3MyX3BlcmMgPC0gY2xhc3MyX3BlcmMgJT4lICAgbXV0YXRlKHBlcmNlbnRfZXhlbXB0ID0gZXhlbXB0X0VBVi9tdW5pX3RheF9iYXNlX25vZXhlbXBzKSANCg0KY2xhc3MyX3BlcmMgJT4lIA0KICAgIG11dGF0ZShhZ2VuY3lfbmFtZSA9IGlmZWxzZShhZ2VuY3lfbmFtZSA9PSAiVE9XTiBDSUNFUk8iLCAiQ0lUWSBPRiBDSUNFUk8iLCBhZ2VuY3lfbmFtZSkgDQogICAgKSAlPiUNCiAgbGVmdF9qb2luKG11bmlfc2hwLCBieSA9IGMoImFnZW5jeV9uYW1lIiA9ICJBR0VOQ1lfREVTQyIpKSAlPiUNCg0KICAgIGdncGxvdChhZXMoZmlsbCA9IHBlcmNlbnRfZXhlbXB0KSkgKw0KICAgIGdlb21fc2YoYWVzKGdlb21ldHJ5ID0gZ2VvbWV0cnkpLCBjb2xvciA9ICJibGFjayIpICsgDQogICAgICB0aGVtZV92b2lkKCkgKyANCiAgdGhlbWUoYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpKSsNCnNjYWxlX2ZpbGxfc3RlcHMyKA0KICAgIGhpZ2ggPSAiIzQyMDQyMCIsIGxvdyA9ICJibGFjayIsDQogICBtaWRwb2ludCA9IG1lZGlhbihjbGFzczJfcGVyYyRwZXJjZW50X2V4ZW1wdCksDQogICAgICAgICAgICAgICAgICAgc2hvdy5saW1pdHM9VFJVRSwNCiAgbmljZS5icmVha3M9RkFMU0UsDQogICAgICAgICAgICAgICAgICAgIG4gPTYsDQogICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiUGVyY2VudCBFeGVtcHQiLA0KICAgICAgICAgbGFiZWxzID0gc2NhbGVzOjpwZXJjZW50DQopKw0KIA0KICBsYWJzKHRpdGxlID0gIlBlcmNlbnQgb2YgcHJlLWV4ZW1wdGlvbiB0YXhhYmxlIGJhc2UgdGhhdCBpcyB0YXggZXhlbXB0IiwgICAgDQogICAgICAgICBjYXB0aW9uID0gIlRvdGFsIEVBViBpbmNsdWRlcyB0aGUgcHJlLWV4ZW1wdGlvbiBUYXhhYmxlIEJhc2UuIA0KICAgICAgIFRJRiBpbmNyZW1lbnQgRUFWIGlzIG5vdCBpbmNsdWRlZCBpbiB0aGUgdG90YWwgRUFWIGluIHRoaXMgaW1hZ2UuDQogICAgICAgTWVkaWFuIHZhbHVlIGlzIDEyLjQzJSIpDQpgYGANCg0KYGBge3J9DQpDdXJyZW50X1RheHJhdGVzIDwtIEN1cnJlbnRfVGF4cmF0ZXMgJT4lIA0KICBtdXRhdGUoRXhlbXB0X3BlcmNlbnQgPSBFeGVtcHRfRUFWL1RvdGFsX0VBVikgDQoNCm1lZGlhbihDdXJyZW50X1RheHJhdGVzJEV4ZW1wdF9wZXJjZW50KQ0KDQpDdXJyZW50X1RheHJhdGVzJT4lIA0KICBtdXRhdGUoYWdlbmN5X25hbWUgPSBpZmVsc2UoYWdlbmN5X25hbWUgPT0gIlRPV04gQ0lDRVJPIiwgIkNJVFkgT0YgQ0lDRVJPIiwgYWdlbmN5X25hbWUpIA0KICApICU+JQ0KICBsZWZ0X2pvaW4obXVuaV9zaHAsIGJ5ID0gYygiYWdlbmN5X25hbWUiID0gIkFHRU5DWV9ERVNDIikpICU+JQ0KICANCiAgZ2dwbG90KGFlcyhmaWxsID0gRXhlbXB0X3BlcmNlbnQpKSArDQogIGdlb21fc2YoYWVzKGdlb21ldHJ5ID0gZ2VvbWV0cnkpLCBjb2xvciA9ICJibGFjayIpICsgDQogIHRoZW1lX3ZvaWQoKSArIA0KICB0aGVtZShheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCkpKw0KICBzY2FsZV9maWxsX3N0ZXBzMigNCiAgICBoaWdoID0gIiM0MjA0MjAiLCBsb3cgPSAiYmxhY2siLA0KICAgIG1pZHBvaW50ID0gbWVkaWFuKEN1cnJlbnRfVGF4cmF0ZXMkRXhlbXB0X3BlcmNlbnQpLA0KICAgIHNob3cubGltaXRzPVRSVUUsDQogICAgbmljZS5icmVha3M9RkFMU0UsDQogICAgbiA9NiwNCiAgICBuYW1lID0gIlBlcmNlbnQgRXhlbXB0IiwNCiAgICBsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQpKw0KDQogIGxhYnModGl0bGUgPSAiUGVyY2VudCBvZiBUb3RhbCBFQVYgdGhhdCBpcyBUYXggRXhlbXB0IiwgICAgDQogICAgICAgY2FwdGlvbiA9ICJUb3RhbCBFQVYgaW5jbHVkZXMgYWxsIEVBViBpbiBhbmQgb3V0IG9mIFRJRnMuDQogICAgICAgTWVkaWFuIHZhbHVlIGlzIDEzLjElLiAiKQ0KDQoNCmBgYA0KDQoNCioqIlRha2VzIHRoZSBtZWRpYW4gdGF4IHJhdGUgaW5jcmVhc2UgYXMgYSByZXN1bHQgb2YgZXhlbXB0aW9ucyAoMS40JSkgYW5kIG11bHRpcGxpZXMgdGhhdCBieSB0aGUgdG90YWwgcmVzaWRlbnRpYWwgRUFWIGluIENvb2sgQ291bnR5IioqDQoNCmBgYHtyIGV2YWw9RkFMU0V9DQp0YXhjb2Rlc19jdXJyZW50ICU+JQ0KICBmaWx0ZXIoeWVhciA9PSAyMDIxKSAlPiUNCiAgZ3JvdXBfYnkobWFqb3JfY2xhc3NfdHlwZSwgbWFqb3JfY2xhc3NfY29kZSkgJT4lDQogIHN1bW1hcml6ZShlYXYgPSBzdW0odGF4X2FtdF9wcmVfZXhlLyh0YXhfY29kZV9yYXRlLzEwMCksIG5hLnJtPVRSVUUpKSAlPiUgYXJyYW5nZShkZXNjKGVhdikpDQoNCjEyMDk0NDk0MTk0NCAqIDAuMDEzODggIyAxNjkzMjI5MTg3DQpgYGANCg0KLSAgIFRoZXJlIGlzIFwkMTIwLDk0NCw5NDEsOTQ0IG9mIFJlc2lkZW50aWFsIEVBViBpbiBDb29rIENvdW50eS4NCg0KLSAgIFwkMSw2NzgsNzE1LDc5NCBpcyBSZXNpZGVudGlhbCBFQVYgXCogYXZlcmFnZSBpbmNyZWFzZSBpbiBtdW5pY2lwYWwgdGF4cmF0ZS4NCg0KKioiQW5kIHRoZW4gd2Ugc2hvdWxkIFtzaG93XSBob3cvd2h5IGlmIGxldnkgaXMgZml4ZWQsIGV4ZW1wdGlvbnMgaW5jcmVhc2UgdGhlIHRheCByYXRlIGFuZC9vciBzaGlmdCB0aGUgdGF4IGJ1cmRlbi4iKioNCg0KLSAgIE9uY2UgdGhlIGFtb3VudCBvZiBtb25leSB0aGF0IGlzIG5lZWRlZCBpcyBkZXRlcm1pbmVkLCB0aGVuIHRoZSB0YXggcmF0ZSBpcyBkZXRlcm1pbmVkIGJhc2VkIG9mZiBvZiB0aGF0Lg0KICAgIC0gICBMZXZ5IGRvZXNuJ3QgY2hhbmdlLCBzbyBpZiB5b3UgYXJlIGRlY3JlYXNpbmcgdGhlIGFtb3VudCBvZiB0YXhhYmxlIEVBViwgdGhlbiB0aGUgdGF4IHJhdGUgbXVzdCBnbyB1cCB0byBjb2xsZWN0IHRoZSBzYW1lIGFtb3VudCBvZiBtb25leS5cDQogICAgLSAgIG1heWJlIGRyYXcgYSBkaWFncmFtIGZvciBhIG11bmljaXBhbGl0eSBhcyBhbiBleGFtcGxlIG9uIGEgc2xpZGU/DQoNCioqIldlIG1pZ2h0IGFsc28gd2FudCB0byB0YWtlIGEgY2xvc2VyIGxvb2sgYXQgZWl0aGVyIG91ciA2IGNhc2Ugc3R1ZHkgbXVuaWNpcGFsaXRpZXMgb3IgdGhvc2UgbXVuaWNpcGFsaXRpZXMgbW9zdCBhZmZlY3RlZCBieSBleGVtcHRpb25zIChQYXJrIEZvcmVzdCwgUGhvZW5peCwgQ2FsdW1ldCBQYXJrLCBSaXZlcmRhbGUpIHRvIGdldCBzb21lIGVmZmVjdHMgZm9yIHRoZSBvd25lciBvZiB0aGUgYXZlcmFnZSBvciBtZWRpYW4gdmFsdWUgaG9tZS4iKioNCg0KDQpMb2NhdGlvbnMgd2l0aCB0aGUgaGlnaGVzdCBwZXJjZW50IG9mIHRoZWlyIHBvdGVudGlhbGx5IHRheGFibGUgRUFWIChub24tVElGIGluY3JlbWVudCBFQVYpIHRoYXQgaXMgdGF4LWV4ZW1wdDoNCg0KUGhvZW5peCBQYXJrIEZvcmVzdCBNYXJraGFtIENhbHVtZXQgUGFya1wNClRob3JudG9uXA0KSGFydmV5XA0KQnVybmhhbSBEb2x0b24NCg0KQWxtb3N0IGV4YWN0IHNhbWUgbGlzdCBvZiBsb2NhdGlvbnMgYXMgbGFyZ2VzdCB0YXggcmF0ZSBjaGFuZ2UuDQoNCg0KDQoNCl9fRXhwb3J0aW5nIGRhdGEgdG8gRXhjZWwgZmlsZV9fDQoNCmBgYHtyIGV2YWw9RkFMU0V9DQpsaWJyYXJ5KG9wZW54bHN4KQ0KDQpkYXRhc2V0X25hbWVzIDwtIGxpc3QoDQogICdMYW5kIFVzZScgPSBwZXJjX3Jlc2lkZW50aWFsLA0KICAnQnVyZGVuIFRhYmxlJyA9IGJ1cmRlbl90YWJsZSwNCiAgIyAnRUFWb3V0c2lkZVRJRnMnID0gRUFWX291dHNpZGVfVElGU19ieUNsYXNzLA0KICANCiAgJ0NvbXBvc2l0ZSBUYXggUmF0ZXMnID0gQ3VycmVudF9UYXhyYXRlcywNCiAgJ011bmlFQVYnID0gbXVuaV9lYXYsICNpbmNsdWRlZCBhcyBjb2x1bW5zIGluIEJ1cmRlbiBUYWJsZSB0b28NCiAjICAnUmVzaWRlbnRpYWxFQVYnID0gdGFibGVfUmVzaWRlbnRpYWxFQVYsICAjIGRvZXNuJ3QgZXhpc3Q/DQogICMgJ0J1cmRlbiB3aXRoIEV4ZW1wcycgPSBidXJkZW5fd2l0aF9leGVtcHRpb25zLA0KICAjICdCdXJkZW4gd2l0aG91dCBFeGVtcHMnID0gYnVyZGVuX25vZXhlbXBzLA0KICAnQnVyZGVuIFNoaWZ0LTNQcm9wVHlwZXMnID0gcHJvcHR5cGVzM19idXJkZW5jaGFuZ2UsDQogICczIFByb3BlcnR5IFR5cGVzJz0gbXVuaXNfM3Byb3BlcnR5X3R5cGVzLA0KIyAgJ1RheGNvZGVEYXRhLU5vRXhlbXB0aW9ucyc9dGF4Y29kZXNfbm9leGVtcHMsDQogICdUYXhjb2RlRGF0YS1DdXJyZW50JyA9IHRheGNvZGVzX2N1cnJlbnQpDQoNCndyaXRlLnhsc3goZGF0YXNldF9uYW1lcywgZmlsZSA9ICdkYXRhX2Zvcl9zbGlkZXNfZmlsdGVyZWRNdW5pcy54bHN4JykNCmBgYA0K