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)
The median municipality has 66.84% of its EAV from Residential Class 2 Properties. Total EAV includes frozen EAV & TIF increments, and all exempt EAV.

The median municipality has 66.84% of its EAV from Residential Class 2 Properties. Total EAV includes frozen EAV & TIF increments, and all exempt EAV.

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% ")
Median value for single-family EAV is 20.76%.Median value for single-family EAV is 20.76%.

Median value for single-family EAV is 20.76%.

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)
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 1/5th of their residential EAV due to exemptions. 20.85% of Single-family home EAV is not taxed and transferred to other tax payers.

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 1/5th of their residential EAV due to exemptions. 20.85% of Single-family home EAV is not taxed and transferred to other tax payers.

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