Replication Steps: Get Pin and Tax Bill Data

  1. Run file 1_Get_All_Pin_Bills.Rmd to replicate pulling the 2021 bills.
  2. Run file 2_....Rmd to get summed values to various levels of analysis (parcel, taxcode–class, taxcode–majorclass, etc.). This file also creates the current composite tax rates for each tax code.
  3. Run file 3_Exemption_Details.rmd to pull all exemption (and amount per type of exemption) for every pin in Cook County.
    • Using the pin data from ptaxsim, I calculate the eav of all properties, exempt EAV, the current tax base, and tax base 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

  4. Run file 4_Taxbill_Hypotheticals.rmd to ….

Necessary files for replication code include:

  • a property class table with major property classes and other property class variables. Download from Github here
  • file of Municipality names formatted in various ways (all caps, sentence case, shortened, etc.) to match different files when joining. Download from Github here.

There are 1,864,594 pins in Cook County in 2021. There are 1,825,816 in incorporated areas within Cook County (referred to as “Municipalities” in this document).

Exemptions per Property Class in Municipalities

# use exemptions in tax codes to summarize EAV. 
# exemption values came from `pin` data table in ptaxsim.
# More accurate that calculating it from revenue collected.tax rate in tax bill data

exemptions_by_class_per_TC <- read_csv("3_Exemption_Details_output-Cook_Exemps_byClassandTaxcode.csv") %>%
  mutate(tax_code_num = as.character(tax_code_num),
         class_code = as.character(class_code)) %>%
  
  left_join(class_dict, by = "class_code") %>%
  left_join(muni_tax_codes, by = c("tax_code_num") ) %>%
  
  # drops all Class 0 properties (Railroad property, tax exempt)
  filter(class_code != "0") %>%
  
  left_join(muni_agency_names) %>%
  left_join(nicknames, by = c("agency_name" = "agency_name")) %>%
  # 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),
         grouped_classes = ifelse(class_1dig %in% c("2"), "Class 2", NA),
         grouped_classes = ifelse(class_1dig %in% c("3", "9"), "Class 3", grouped_classes),
         grouped_classes = ifelse(is.na(grouped_classes), "Other Classes", grouped_classes)
  )



muni_totals <-  exemptions_by_class_per_TC %>% 
  group_by(clean_name, agency_name) %>% 
 #  filter(!is.na(clean_name)) %>%
  summarize(muni_av = sum(av),
            muni_eav = sum(eav))

table2 <- exemptions_by_class_per_TC %>% 
  group_by(clean_name, agency_name, grouped_classes) %>%
  summarize(av = sum(av),
            eav = sum(eav)) %>% 
  ungroup() %>%
  left_join(muni_totals) %>%
  filter(!is.na(clean_name))%>%
  mutate(perc_class2 = ifelse(grouped_classes == "Class 2", eav/muni_eav, 0),
         perc_class3 = ifelse(grouped_classes == "Class 3", eav/muni_eav, 0),
         perc_other = ifelse(grouped_classes == "Other Classes", eav/muni_eav, 0)) %>%
  group_by(clean_name, agency_name) %>%
  mutate(
         perc_res = perc_class2 + perc_class3)


table2 %>% ungroup() %>% select(-c(agency_name, muni_av, muni_eav))

Fix table below later!

munitotals <- exemptions_by_class_per_TC %>% 
  mutate(is_chicago = ifelse(clean_name == "Chicago", 1, 0)) %>%
  filter(tax_code_num %in% muni_tax_codes$tax_code_num)%>%
  group_by(is_chicago) %>%
  summarize(av = sum(av, na.rm = TRUE),
            eav=sum(eav, na.rm=TRUE),
            total_exempt_eav = sum(exe_homeowner + exe_senior + exe_freeze + exe_longtime_homeowner + 
                         exe_disabled + exe_vet_returning + exe_vet_dis + exe_abate, na.rm=TRUE),
            homeowners_exemption = sum(exe_homeowner, na.rm=TRUE),
            senior_exemption = sum(exe_senior, na.rm=TRUE),
            freeze_exemption = sum(exe_freeze, na.rm=TRUE),
                        pin_count = n()) %>%
  pivot_longer(cols = av:pin_count, names_to = "Variables", values_to = "Municipality Totals")

## only unincorporated aareas
cooktotals<-exemptions_by_class_per_TC %>% 
  mutate(is_chicago = ifelse(clean_name == "Chicago", 1, 0)) %>%
  filter(tax_code_num %in% cook_tax_codes$tax_code_num)%>%
  group_by(is_chicago) %>%
  summarize(av = sum(av, na.rm = TRUE),
            eav=sum(eav, na.rm=TRUE),
            total_exempt_eav = sum(exe_homeowner + exe_senior + exe_freeze + exe_longtime_homeowner + 
                         exe_disabled + exe_vet_returning + exe_vet_dis + exe_abate, na.rm=TRUE),
            homeowners_exemption = sum(exe_homeowner, na.rm=TRUE),
            senior_exemption = sum(exe_senior, na.rm=TRUE),
            freeze_exemption = sum(exe_freeze, na.rm=TRUE),
                        pin_count = n()) %>%
  pivot_longer(cols = av:pin_count, names_to = "Variables", values_to = "Cook County Totals") %>%
  mutate(is_chicago = ifelse(is.na(is_chicago), 0, is_chicago))

unincorporatedareas<-exemptions_by_class_per_TC %>% 
  mutate(is_chicago = ifelse(clean_name == "Chicago", 1, 0)) %>%
 filter(!tax_code_num %in% muni_tax_codes$tax_code_num)%>%
  group_by(is_chicago) %>%
  summarize(av = sum(av, na.rm = TRUE),
            eav=sum(eav, na.rm=TRUE),
            total_exempt_eav = sum(exe_homeowner + exe_senior + exe_freeze + exe_longtime_homeowner + 
                         exe_disabled + exe_vet_returning + exe_vet_dis + exe_abate, na.rm=TRUE),
            homeowners_exemption = sum(exe_homeowner, na.rm=TRUE),
            senior_exemption = sum(exe_senior, na.rm=TRUE),
            freeze_exemption = sum(exe_freeze, na.rm=TRUE),
                        pin_count = n()) %>%
  pivot_longer(cols = av:pin_count, names_to = "Variables", values_to = "Unincorporated Totals") %>%
  mutate(is_chicago = ifelse(is.na(is_chicago), 0, is_chicago))


cookandmunitotals <- left_join(cooktotals, munitotals) 
cookandmunitotals %>% left_join(unincorporatedareas)

There was $209,502,768,986 EAV in Cook County during 2021 when including all property types.

tif_table <- exemptions_by_class_per_TC %>% 
  group_by(clean_name, agency_name, in_TIF, grouped_classes) %>%
  summarize(av = sum(av),
            eav = sum(eav)) %>% 
  ungroup() %>%
  left_join(muni_totals) %>% 
  pivot_wider(id_cols = c(clean_name, agency_name, muni_av, muni_eav), 
              names_from = c(in_TIF, grouped_classes), 
              values_from = eav)

# tif_table %>% 
#   select(clean_name:muni_eav, `1_Other Classes`, `0_Other Classes`) %>% 
#   rename(nonres_inTIF = `1_Other Classes`, 
#          nonres_outsideTIF = `0_Other Classes`) %>%
#   mutate(pct_nonres_inTIF = round(nonres_inTIF/muni_eav, digit=6),
#          pct_nonres_outsideTIF = round(nonres_outsideTIF/muni_eav, digit=6),
#          pct_nonres_inTIF = ifelse(is.na(pct_nonres_inTIF), 0, pct_nonres_inTIF),
#          pct_nonres_outsideTIF = ifelse(is.na(pct_nonres_outsideTIF), 0, pct_nonres_outsideTIF))

tif_table %>% 
  select(clean_name:muni_eav, `1_Class 2`, `0_Class 2`) %>% 
  rename(res_inTIF = `1_Class 2`, 
         res_outsideTIF = `0_Class 2`) %>%
  mutate(pct_res_inTIF = round(res_inTIF/muni_eav, digit=6),
         pct_res_outsideTIF = round(res_outsideTIF/muni_eav, digit=6),
         pct_res_inTIF = ifelse(is.na(pct_res_inTIF), 0, pct_res_inTIF),
         pct_res_outsideTIF = ifelse(is.na(pct_res_outsideTIF), 0, pct_res_outsideTIF)) %>% select(-agency_name) %>% filter(clean_name %in% c("Park Forest", "Dolton","Hillside", "Riverside","Chicago", "Westchester", "Markham", "Winnetka", "Rosemont"))

Muni EAV represents all EAV in the municipality and includes TIF increments and tax exempt property. It is the summed eav of all pins from the pin PTAXSIM data table.

Out of all of Chicago’s EAV, 9.9% of its EAV is residential properties inside of TIFs. 42.8% of Chicago’s total EAV comes from Residential properties outside of TIFs.

Winnetka has all of its residential EAV outside of a TIF and nearly all of their EAV is from residential properties.

pivottable <- table2 %>% 
  pivot_wider(id_cols = c(clean_name, agency_name, muni_av, muni_eav), 
              names_from = grouped_classes, values_from = eav) %>%   
  mutate(agency_name = ifelse(agency_name == "TOWN CICERO", "CITY OF CICERO", agency_name) )

pivottable %>% select(-agency_name)
pivot_table <- pivottable %>%   
  mutate(perc_class2 = `Class 2`/muni_eav,
         perc_class3 = `Class 3`/muni_eav,
         perc_other = `Other Classes`/muni_eav,

         perc_nonres = (perc_class3 + perc_other),
         perc_residential = perc_class2) %>% 
  mutate_all( ~coalesce(.,0))

#pivot_table %>% ungroup() %>% select(-agency_name) %>% arrange(desc(perc_residential)) %>% select(clean_name, perc_residential, everything())

pivot_table %>% ungroup()  %>% select(-agency_name) %>% select(clean_name, perc_class2, perc_class3, perc_residential, everything())%>% arrange(desc(perc_class2))
#pivot_table %>% ungroup()  %>% select(-agency_name)%>% arrange(desc(perc_class3)) %>% select(clean_name, perc_class3, everything())

#write_csv(pivot_table, "3_exemption_details_output-residential_percent_August14.csv")

pivot_table %>% filter(clean_name %in% c("Park Forest","Markham",  "Dolton", "Hillside", "Riverside", "Chicago", "Westchester", "Winnetka", "Rosemont")) %>% ungroup() %>% select(-agency_name) %>% select(clean_name, `Class 2`:perc_residential, muni_eav, muni_av)
# sum of all Class 2 property EAV
class2_EAV <- table2 %>% ungroup() %>% filter(grouped_classes == "Class 2") %>% summarize(residential_eav = sum(eav))

There is $120,948,512,294 in Class 2 Residential EAV in Cook County

File 3_exemption_details_output-residential_percent.csv has the percent of EAV before exemptions but does NOT alter EAV that is in TIFs. TIFs are essentially ignored in this file. This amount of Taxable Residential EAV vs Residential EAV is quite different for some municipalities.

On average, Municipalities have 3% of their EAV from Class 3 Multi-Family Properties.

On average, Municipalities have 63% of their EAV from Class 2 Residential properties. This property class includes single-family homes, condos, and residential apartments.

Now examine the taxable base for each Muni. The Taxable Base is the EAV that is taxable for the municipality and has TIF increments and exemptions subtracted from the original residential EAV.

grouped_exemptions <- exemptions_by_class_per_TC %>% 
   # group_by(agency_name, major_class_code, major_class_type, ResidentialProps, PropType) %>%
  group_by(clean_name, grouped_classes, 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 == "Residential") %>% 
  mutate(pct_PropType = eav / muni_EAV_includesTIF)# %>% select()

pct_property_types %>% ungroup() %>% select(-agency_name) %>% select(Municipality = clean_name, PropertyClass = grouped_classes, pct_PropType, everything())
pct_property_types %>% ungroup() %>% select(-agency_name)  %>% filter(clean_name %in% c("Park Forest", "Dolton","Hillside", "Riverside","Chicago", "Westchester", "Markham", "Winnetka", "Rosemont"))

Percent Residential is the Residential EAV (Class 2 properties) outside of TIFs / Municipality EAV outside of TIFs.

grouped_exemptions <- exemptions_by_class_per_TC %>% 
   group_by(clean_name, major_class_code, major_class_type, agency_name) %>%
  #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())
  

# 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() 



## Percent Residential is the same as percent that is Class == 2. 
## Percent residential does not include Multi-family property class 3 or 9.
perc_residential <- left_join(grouped_exemptions, muni_eav) %>% 
  filter(major_class_code == "2") %>% 
  mutate(percent_residential = eav / muni_EAV_includesTIF)# %>% select()
# 119 municipalities remain. Some munis do not have residential eav and are dropped.

# 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 %>% arrange(desc(percent_residential)) %>% 
  select(-c(major_class_code, major_class_type, agency_name)) %>%  # drop these and reorder
  select(clean_name, percent_residential, everything())
perc_residential %>% 
 # group_by(ResidentialProps)%>%
    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_residential)) + 
  geom_sf(aes(geometry = geometry), color = "black") + 
  labs(title = "Residential EAV /  Total EAV", 
  caption = "Residential Property includes 200 level property classes.
       The median municipality has 67% of its EAV from Class 2 Properties.") +
    theme_void() + 
  theme(axis.ticks = element_blank(), axis.text = element_blank())+# +#+
    scale_fill_steps2(
    high = "darkblue", low = "black", 
    mid = "beige", #  guide = "legend",
      midpoint = median(perc_residential$percent_residential),
           na.value = NA,   
                       n.breaks = 6,
  show.limits=TRUE,
                        name = "% Residential",
  labels = scales::percent)

Taxable Base & Land Use

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"))   %>% filter(!agency_num %in% cross_county_lines)



taxcodes_current %>% 
  left_join(muni_agency_names) %>%
  left_join(nicknames, by = c("agency_name" = "agency_name")) %>% 
  filter(clean_name %in% c("Park Forest","Markham",  "Dolton", "Hillside", "Riverside", "Chicago", "Westchester", "Winnetka")) %>% ungroup() %>% select(-c(agency_name, Column1, `Most recent reassessed`, shpfile_name, short_name,agency_number,))

Composite Tax Rates

Current_Taxrates <- taxcodes_current %>% 
  filter(!agency_num %in% cross_county_lines) %>%
  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))

Current_Taxrates %>%  filter(clean_name %in% c("Park Forest","Markham",  "Dolton", "Hillside", "Riverside", "Chicago", "Westchester", "Winnetka", "Rosemont")) %>% select(-agency_name)
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, major_class_code, 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()

land_use %>% filter(clean_name %in% c( "Dolton", "Chicago", "Winnetka")) %>% select(-agency_name)
# made in Excel originally

Current_Taxrates %>%  filter(clean_name %in% c("Park Forest","Dolton", "Hillside", "Riverside", "Chicago", "Winnetka", "Rosemont")) %>% select(clean_name, tax_rate_current, taxrate_new) %>% pivot_longer(cols = c(tax_rate_current,taxrate_new), names_to = "names", values_to = "values")  %>%
  ggplot(aes(x = clean_name, y = values, fill = names)) +
  geom_col(position = "dodge" ) + theme_classic() + labs(x="", y = "Composite Tax Rate")

Current_Taxrates %>%  filter(clean_name %in% c("Markham", "Chicago", "Westchester", "Winnetka")) %>% select(clean_name, tax_rate_current, taxrate_new) %>% pivot_longer(cols = c(tax_rate_current,taxrate_new), names_to = "names", values_to = "values")  %>%
  ggplot(aes(x = clean_name, y = values, fill = names)) +
  geom_col(position = "dodge" ) + theme_classic() + labs(x="", y = "Composite Tax Rate")

Percent of Residential EAV that is tax exempt

For this document, residential EAV includes Class 2 properties only. Residential property can be in and outside of a TIF. Any EAV greater than the frozen EAV within a TIF becomes TIF revenue when it is taxed. We try to only include the frozen EAV and non-TIF EAV in our residential calculations.

exemptions_to_class2EAV_ratios <- perc_residential %>% 
  mutate(exemptEAV_pctof_resEAV = exempt_EAV/eav,
         exemptEAV_pctof_totalEAV = exempt_EAV / muni_EAV_includesTIF,
         exemptEAV_pctof_taxbase_current = exempt_EAV / tax_base_current,
         exemptEAV_pctof_taxbase_noexemps = exempt_EAV / tax_base_noexemps,
         nontif_ratio = exempt_EAV / tax_base_noexemps) %>% 
  select(agency_name, clean_name, exemptEAV_pctof_resEAV, nontif_ratio, everything()) %>% 
  arrange(nontif_ratio)

exemptions_to_class2EAV_ratios %>%
    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 = 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",  mid = "beige",
                      # limits = c(0,.8),
                       n.breaks = 7, show.limits=TRUE,
                       na.value = NA,
                    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) ) %>%
  full_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", mid="beige",
                    #colors = c("white", "darkblue"), 
                    # limits = c(0),
                    midpoint = median(exemptions_to_class2EAV_ratios$nontif_ratio),
                    n.breaks = 5, 
                    na.value = NA,
                    show.limits=TRUE,
                    name = "% Residential EAV \nthat is exempt", label = scales::percent) + 
  labs( caption = "Median value is 20.0% ")


exemptions_to_class2EAV_ratios %>%
  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 = 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",mid ="beige",
                    #colors = c("white", "darkblue"), 
                    # limits = c(0),
                    midpoint = median(exemptions_to_class2EAV_ratios$nontif_ratio),
                    n.breaks = 7, 
                    na.value = NA,
                    show.limits=TRUE,
                    name = "% Residential EAV \nthat is exempt", label = scales::percent) + 
  labs( caption = "Median value is 20.0% ")

exemptions_to_class2EAV_ratios %>%  filter(nontif_ratio<.6) %>%
    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 = 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",mid ="beige",
                    #  colors = c("white", "darkblue"), 
                    limits = c(0,.4),
                    na.value = NA,
                    midpoint = median(exemptions_to_class2EAV_ratios$nontif_ratio),
                    n.breaks = 5, show.limits=TRUE,
                    name = "% Residential EAV \nthat is tax exempt", label = scales::percent)


exemptions_to_class2EAV_ratios %>%  filter(nontif_ratio<.6) %>%
  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 = 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",mid ="beige",
                    #  colors = c("white", "darkblue"), 
                    limits = c(0,.4),
                    na.value = NA,
                    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.

In Cook County there is $101,682,352,077 in Class 2 Residential Property EAV.

There is $117,315,679,587 in Class 2 Residential Property EAV before all exemptions.

The Total EAV for Cook County $212,180,626,672. Total EAV includes TIF increment and exempt EAV.

The current taxable EAV for Cook County $175,237,018,872.

The hypothetical taxable EAV for Cook County $190,887,516,430.

Burden Shift

burden_table <- pct_property_types %>%
  filter(!is.na(clean_name)) %>%
  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.


burden_table %>% 
  arrange(desc(burden_change)) %>% 
  select(clean_name, burden_change, everything()) %>%
  mutate(burden_change = round(burden_change*100, digits = 2)) %>%
  select(-agency_name)
# Current Burden:

munis_3property_types <- burden_shift %>%
    filter(!agency_name %in% cross_county_lines) %>%
# 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, grouped_classes) %>%
  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 <- munis_3property_types %>% 
    mutate(burden_current = ifelse(is.na(burden_current), 0, burden_current)) %>%

  pivot_wider( id_cols = clean_name , names_from = "grouped_classes", values_from = "burden_current", names_prefix="Current - ", values_fill = 0 ) %>% 
  select(clean_name, `Current - Class 2`, everything()) %>%
  arrange(-`Current - Class 2`)

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 <- munis_3property_types %>% 
  mutate(burden_noexemps = ifelse(is.na(burden_noexemps), 0, burden_noexemps)) %>%
  pivot_wider( id_cols = clean_name , names_from = "grouped_classes", 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

burden_3groups_currentandhypothetial<- left_join(proptypes3_current, proptypes3_noexemps)
burden_3groups_currentandhypothetial
props_wide <- munis_3property_types %>%
  pivot_wider(id_cols = clean_name , 
               names_from = "grouped_classes", 
               values_from = "burden_change", values_fill = 0) %>% 
  select(clean_name, `Class 2`, everything()) %>%
  arrange(desc(`Class 2`) )

props_wide[2:4] <- sapply(props_wide[2:4], function(x) scales::percent(x, accuracy=.01))
props_wide
props_wide %>%  filter(clean_name %in% c("Markham", "Chicago", "Westchester", "Winnetka"))
burden_table  %>%  filter(clean_name %in% c("Markham", "Chicago", "Westchester", "Winnetka"))%>% select(clean_name, burden_current:burden_change) %>% pivot_longer(cols = c(burden_current, burden_noexemps), names_to = "names", values_to = "values")  %>%
  ggplot(aes(x = clean_name, y = values, fill = names)) +
  geom_col(position = "dodge" ) + theme_classic() + labs(x="", y="Share of Levy Paid by Class 2", title = "Current and Hypothetial Tax Burden")

# as a dot graph ## 

cross_county_lines <- c("030440000",
"030585000", "030890000", "030320000", "031280000","030080000", "030560000", "031120000", "030280000", "030340000","030150000","030050000", "030180000","030500000","031210000")

cross_county_lines <- muni_agency_names %>% filter(agency_num %in%cross_county_lines) %>% left_join(nicknames, by = "agency_name")

order <- burden_shift %>% 
  ungroup %>% as_tibble() %>%
  #  filter(ResidentialProps == "Residential") %>%
  filter(grouped_classes == "Class 2") %>%
  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


# median burden c hange is 0.45
# current median burden is 65.5% of the levy

burden_shift %>% 
  filter(!clean_name %in% cross_county_lines$clean_name)%>%
  filter(grouped_classes == "Class 2") %>%
  filter(burden_current > 0.938 |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 = 65.5, linetype = 3)+
  geom_line(aes(group = clean_name))+ 
  geom_hline(yintercept = 5.5, linetype = 2)+
  geom_hline(yintercept = 13.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 Class 2 Residential Tax Burden", 
       subtitle = "Ordered by Current Tax Burden",
  x = "Share of Levy (%)", y = "" , 
  caption = "Dotted line represents median Class 2 burden (65.5% of the levy). Residential Tax Burden is the 
  share of the property tax collected that was paid for by property owners with Class 2 properties.") +
    geom_label(label = "Class 2 pays small share of \nlevy; very little residential", x=32, y = 16, label.size = 1, size = 3)+
    geom_label(label = "Class 2 pays median share of \nlevy (65%), mix of land use", x=42, y = 9.5, label.size = 1, size = 3) +
    geom_label(label = "Class 2 pays nearly all of levy, \nhighly residential", x=70, y = 3, label.size = 1,size = 3)

Hypothetical Median Tax Bill without Exemptions

#bill_change_3groups <- read_csv( "4_Taxbill_Hypotheticals-taxbill_change_20230814.csv")

#bill_change_3groups %>% select(Municipality = clean_name, bill_change, everything()) 


tax_bill_change <- read_csv("4_Taxbill_Hypotheticals-taxbill_change_foreachPropClass_perMuni.csv")

Composite Tax Rates

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*100)) + 
  geom_sf(aes(geometry = geometry), color = "black") +  
  theme_void() + 
  theme(axis.ticks = element_blank(), axis.text = element_blank())+
  
  scale_fill_steps2(high = "darkblue", low = "black", mid = "lightblue",
                    n=7, 
                    midpoint = median(Current_Taxrates$taxrate_change*100),
                 #   midpoint = 0.01388, 
                 guide = "legend",
                    show.limits=TRUE,
                    nice.breaks=TRUE,
                    na.value = NA,
                   # labels = scales::percent,
                    name = "Percentage Point \nDifference")+
  labs(title = "Change in Composite Tax Rate if all Exemptions are Eliminated")

ggsave("AWM_compositetaxrate_change.png", limitsize = FALSE, width = 8, height = 4, units = "in")
Current_Taxrates_perTC <- taxcodes_current %>% 
  left_join(muni_agency_names, by = "agency_num") %>%
  left_join(nicknames, by = c("agency_name" = "agency_name")) %>%
  filter(!agency_num %in% cross_county_lines) %>%
  group_by(clean_name, agency_name, tax_code, pins_in_class) %>%
  
  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, tax_code, everything()) %>% 
  arrange(desc(tax_rate_current))

Current_Taxrates_perTC
Current_Taxrates_perTC %>% left_join(nicknames) %>%
  group_by(Triad) %>% 
  filter( Triad == "South") %>% summarize(taxrate_new = mean(taxrate_new, na.rm=TRUE),
                                          taxrate_current = mean(tax_rate_current, na.rm=TRUE)) %>%
  mutate(taxrate_change = taxrate_new-taxrate_current)
Current_Taxrates_perTC %>% left_join(nicknames) %>% group_by(Triad) %>% 
  filter( Triad == "North") %>% summarize(taxrate_change = mean(taxrate_change, na.rm=TRUE))

Bring in the composite tax rates for all tax codes.

Current_Taxrates2 <- read_csv("2_taxcode_taxrates.csv") %>% 
  mutate(tax_code = as.character(tax_code))

land_use2 <- 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, major_class_code, 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()

land_use2

Using similarily Assessed Value properties

nicknames <- readxl::read_excel("muni_shortnames.xlsx")

class_dict <- read_csv("class_dict.csv")

taxcode_taxrates <- read_csv("2_taxcode_taxrates.csv")


DoltonChicago <- read_csv("Cholton_taxbills.csv") %>% 
  arrange(av) %>%     
  left_join(taxcode_taxrates) %>%
    mutate(propclass_1dig = str_sub(class, 1, 1))

library(kableExtra)
# DoltonChicago %>% 
#   group_by(agency_num, tax_code) %>% 
#   summarize(max_comprate = max(tax_rate_current),
#             min_comprate = min(tax_rate_current)) %>% arrange(-max_comprate)

DoltonChicago %>% group_by(agency_num) %>% 
  summarize(max_comprate = max(tax_rate_current, na.rm=TRUE),
            mean_comprate = mean(tax_rate_current, na.rm=TRUE),
            min_comprate = min(tax_rate_current, na.rm=TRUE)) %>% arrange(-mean_comprate)
DoltonChicago %>% filter(agency_num == "030310000") %>%
  group_by(agency_num, class) %>% 
  summarize(max_comprate = max(tax_rate_current, na.rm=TRUE),
            mean_comprate = mean(tax_rate_current, na.rm=TRUE),
            min_comprate = min(tax_rate_current, na.rm=TRUE),
            pin_count = n(),
            av = mean(av),
            eav = mean(eav),
            tax_amt_post_exe = mean(tax_amt_post_exe),
            tax_amt_exe = mean(tax_amt_exe),
            tax_amt_pre_exe = mean(tax_amt_pre_exe)) %>% 
  arrange(-pin_count) %>% head() %>% kbl()
agency_num class max_comprate mean_comprate min_comprate pin_count av eav tax_amt_post_exe tax_amt_exe tax_amt_pre_exe
030310000 203 0.2792 0.2517 0.2294 3609 8462 25409 3971.1 2352 6323
030310000 234 0.2792 0.2437 0.2294 2374 11826 35510 5704.2 2925 8629
030310000 202 0.2792 0.2637 0.2294 990 4834 14514 2225.9 1615 3839
030310000 211 0.2792 0.2556 0.2294 286 14033 42138 9064.8 1371 10436
030310000 100 0.2792 0.2578 0.2294 221 6530 19607 5015.1 0 5015
030310000 299 0.2792 0.2618 0.2294 221 2607 7829 665.2 1384 2050
DoltonChicago %>% filter(agency_num == "030210000") %>%
  group_by(agency_num, class) %>% 
  summarize(max_comprate = max(tax_rate_current, na.rm=TRUE),
            mean_comprate = mean(tax_rate_current, na.rm=TRUE),
            min_comprate = min(tax_rate_current, na.rm=TRUE),
            pin_count = n(),
            av = mean(av),
            eav = mean(eav),
            tax_amt_post_exe = mean(tax_amt_post_exe),
            tax_amt_exe = mean(tax_amt_exe),
            tax_amt_pre_exe = mean(tax_amt_pre_exe)) %>% 
  arrange(-pin_count) %>% head() %>% kbl()
agency_num class max_comprate mean_comprate min_comprate pin_count av eav tax_amt_post_exe tax_amt_exe tax_amt_pre_exe
030210000 299 0.0844 0.0671 0.067 286419 25845 77606 4880 333.9 5214
030210000 203 0.0824 0.0671 0.067 134808 21964 65951 3504 917.9 4422
030210000 211 0.0908 0.0671 0.067 120872 36681 110143 6529 858.2 7387
030210000 202 0.0824 0.0671 0.067 55917 16139 48460 2488 761.6 3250
030210000 205 0.0908 0.0671 0.067 36918 30049 90229 5194 856.2 6051
030210000 100 0.0908 0.0671 0.067 32109 6198 18610 1255 0.0 1255
DoltonChicago %>% 
  filter(class == "203") %>% 
  arrange(av)%>%
  group_by(agency_num, class) %>%
  summarize(medianbill = median(total_billed),
            meanbill = mean(total_billed),
            medianAV = median(av),
            meanAV = mean(av),
            )%>% 
 # pivot_longer(medianbill:meanAV, names_to = "Stats", values_to = "Values")  %>%
  kbl(caption= "Chicago and Dolton, Class 203, Measures of the Middle", digits=0, booktabs = T) %>%   
  kable_styling(full_width = T)
Chicago and Dolton, Class 203, Measures of the Middle
agency_num class medianbill meanbill medianAV meanAV
030210000 203 3151 3504 20000 21964
030310000 203 4152 3971 8874 8462
DoltonChicago %>% 
  filter(class == "205") %>% 
  group_by(agency_num, class) %>%
  summarize(medianbill = median(total_billed),
            meanbill = mean(total_billed),
            medianAV = median(av),
            meanAV = mean(av),
            )%>% 
 # pivot_longer(medianbill:meanAV, names_to = "Stats", values_to = "Values")  %>%
  kbl(caption= "Chicago and Dolton, Class 205, Measures of the Middle", digits=0, booktabs = T) %>%   
  kable_styling(full_width = T)
Chicago and Dolton, Class 205, Measures of the Middle
agency_num class medianbill meanbill medianAV meanAV
030210000 205 4168 5194 25000 30049
030310000 205 3515 4006 6980 7834
DoltonChicago %>% 
  filter(class == "211") %>% 
  group_by(agency_num, class) %>%
  summarize(medianbill = median(total_billed),
            meanbill = mean(total_billed),
            medianAV = median(av),
            meanAV = mean(av),
            )%>% 
 # pivot_longer(medianbill:meanAV, names_to = "Stats", values_to = "Values")  %>%
  kbl(caption= "Chicago and Dolton, Class 211, Measures of the Middle", digits=0, booktabs = T) %>%   
  kable_styling(full_width = T)
Chicago and Dolton, Class 211, Measures of the Middle
agency_num class medianbill meanbill medianAV meanAV
030210000 211 4640 6529 28000 36681
030310000 211 8878 9065 15192 14033
DoltonChicago %>% 
  filter(class == "234") %>% 
  group_by(agency_num, class) %>%
  summarize(medianbill = median(total_billed),
            meanbill = mean(total_billed),
            medianAV = median(av),
            meanAV = mean(av),
            )%>% 
 # pivot_longer(medianbill:meanAV, names_to = "Stats", values_to = "Values")  %>%
  kbl(caption= "Chicago and Dolton, Class 234, Measures of the Middle", digits=0, booktabs = T) %>%   
  kable_styling(full_width = T)
Chicago and Dolton, Class 234, Measures of the Middle
agency_num class medianbill meanbill medianAV meanAV
030210000 234 2420 2953 15999 18781
030310000 234 6043 5704 11990 11826

Chicago has 655 tax codes in its borders and Dolton has 13 tax codes in its borders.

Max composite tax rate in a tax code in Chicago is 9.1% and minimum composite tax rate is 6.7%. Chicago has 665 tax codes.

Max composite tax rate in a tax code in Dolton is 27.9% and minimum composite tax rate is 22.9%. Dolton has 13 tax codes.

Class 203

One story residence, any age, 1,000 to 1,800 sq. ft.

DoltonChicago %>% 
  filter(agency_num == "030210000" ) %>% #& class == "203" & between(av,9950,10050)) %>% 
  group_by(tax_code) %>% 
  summarize(count = n(),            
            avg_current_comprate = mean(tax_rate_current, na.rm=TRUE)
  ) %>% arrange(-avg_current_comprate) %>% head()
DoltonChicago %>% 
  filter(agency_num == "030310000") %>% # & class == "203" & between(av, 9950, 10050)) %>%
  group_by(tax_code) %>%
  summarize(count = n(),
            avg_current_comprate = mean(tax_rate_current, na.rm=TRUE)
  ) %>% arrange(-avg_current_comprate) %>% head()

If holding the levy constant and acknowledging the change in tax rates that would occur from having additional taxable EAV within the taxing jurisdictions….

For property class 203 PINs with assessed values between $9,000 and $11,000, the average change in tax bill would be $75 more in Chicago and $205 more in Dolton compared to their current tax bills ($1475 and $4312 respectively).

The “average” property tax payer would think they are saving $624 in Chicago and $2708 in Dolton due to exemptions. This number appears on their taxbill and calculated by the full EAV * current tax rate and does NOT consider the change in tax rate that would occur if levies are held constant and all EAV became taxable.

Chi3 <- DoltonChicago %>% 
  filter(agency_num == "030210000" & class == "203" & between(av,9000,11000)) %>%
    summarize(              
    comp_taxrate = mean(tax_code_rate, na.rm=TRUE),
    bill_current = mean(tax_amt_post_exe, na.rm=TRUE),
    bill_hyp = mean(eav*taxrate_new, na.rm=TRUE),
    bill_change = bill_hyp - bill_current,
    tax_amt_post_exe = mean(tax_amt_post_exe),
    tax_amt_exe = mean(tax_amt_exe),
    tax_amt_pre_exe = mean(tax_amt_pre_exe),
    pin_count = n(),
    av = mean(av), 
    eav = mean(eav)
  ) %>% 
  pivot_longer(cols = comp_taxrate:eav, names_to = "Stats", values_to = "Values")

Dol3 <- DoltonChicago %>% 
  filter(agency_num == "030310000" & class == "203" & between(av, 9000, 11000)) %>%
    summarize(              
    comp_taxrate = mean(tax_code_rate, na.rm=TRUE),
    bill_current = mean(tax_amt_post_exe, na.rm=TRUE),
    bill_hyp = mean(eav*taxrate_new, na.rm=TRUE),
    bill_change = bill_hyp - bill_current,
    tax_amt_post_exe = mean(tax_amt_post_exe),
    tax_amt_exe = mean(tax_amt_exe, na.rm=TRUE),
    tax_amt_pre_exe = mean(tax_amt_pre_exe, na.rm=TRUE),
    pin_count = n(),
    av = mean(av), 
    eav = mean(eav)
  ) %>% 
    pivot_longer(cols = comp_taxrate:eav, names_to = "Stats", values_to = "Values")

both_dt <- cbind(Chi3, Dol3)


kbl(both_dt, booktabs = T, digits = 0, 
    caption = "Property Class 203 Comparison, AV ~ $10,000 (9000-11000 range)") %>%
  kable_styling(full_width = T)%>%
add_header_above(c("Chicago" = 2, "Dolton" = 2))
Property Class 203 Comparison, AV ~ $10,000 (9000-11000 range)
Chicago
Dolton
Stats Values Stats Values
comp_taxrate 7 comp_taxrate 24
bill_current 1475 bill_current 4312
bill_hyp 1550 bill_hyp 4517
bill_change 74 bill_change 205
tax_amt_post_exe 1475 tax_amt_post_exe 4312
tax_amt_exe 624 tax_amt_exe 2708
tax_amt_pre_exe 2099 tax_amt_pre_exe 7020
pin_count 4801 pin_count 1466
av 10424 av 9769
eav 31301 eav 29333

Changing the range of PINs included in the calculation alters the “Median Property Statistic”

If holding the levy constant and acknowledging the change in tax rates that would occur from having additional taxable EAV within the taxing jurisdictions….

For property class 203 PINs with assessed values between $8,000 and $12,000, the average change in tax bill would be $98 more in Chicago and $55 more in Dolton compared to their current tax bills ($1513 and $4342 respectively).

Chi3 <- DoltonChicago %>% 
  filter(agency_num == "030210000" & class == "203" & between(av,8000,12000)) %>%
    summarize(              
    comp_taxrate = mean(tax_code_rate, na.rm=TRUE),
    bill_current = mean(tax_amt_post_exe, na.rm=TRUE),
    bill_hyp = mean(eav*taxrate_new, na.rm=TRUE),
    bill_change = bill_hyp - bill_current,
    tax_amt_post_exe = mean(tax_amt_post_exe),
    tax_amt_exe = mean(tax_amt_exe, na.rm=TRUE),
    tax_amt_pre_exe = mean(tax_amt_pre_exe, na.rm=TRUE),
    pin_count = n(),
    av = mean(av), 
    eav = mean(eav)
  ) %>% 
  pivot_longer(cols = comp_taxrate:eav, names_to = "Stats", values_to = "Values")

# Chicago only has 2 pins that are similar to Dolton's median pin (which had a lot of matches)
Dol3 <- DoltonChicago %>% 
  filter(agency_num == "030310000" & class == "203" & between(av, 8000, 12000)) %>%
    summarize(              
    comp_taxrate = mean(tax_code_rate, na.rm=TRUE),
    bill_current = mean(tax_amt_post_exe, na.rm=TRUE),
    bill_hyp = mean(eav*taxrate_new, na.rm=TRUE),
    bill_change = bill_hyp - bill_current,
    tax_amt_post_exe = mean(tax_amt_post_exe),
    tax_amt_exe = mean(tax_amt_exe, na.rm=TRUE),
    tax_amt_pre_exe = mean(tax_amt_pre_exe, na.rm=TRUE),
    pin_count = n(),
    av = mean(av), 
    eav = mean(eav)
  ) %>% 
    pivot_longer(cols = comp_taxrate:eav, names_to = "Stats", values_to = "Values")

both_dt <- cbind(Chi3, Dol3)


kbl(both_dt, booktabs = T, digits = 0, 
    caption = "Property Major Class 2 Comparison, AV ~ $10,000 (AV range $8000-$12000)") %>%
  kable_styling(full_width = T)%>%
add_header_above(c("Chicago Class 203, 8K-12K Property Stats" = 2, "Dolton Class 203, 8L-12K AV Property Stats" = 2))
Property Major Class 2 Comparison, AV ~ $10,000 (AV range $8000-$12000)
Chicago Class 203, 8K-12K Property Stats
Dolton Class 203, 8L-12K AV Property Stats
Stats Values Stats Values
comp_taxrate 7 comp_taxrate 24
bill_current 1513 bill_current 4342
bill_hyp 1611 bill_hyp 4396
bill_change 98 bill_change 55
tax_amt_post_exe 1513 tax_amt_post_exe 4342
tax_amt_exe 676 tax_amt_exe 2519
tax_amt_pre_exe 2190 tax_amt_pre_exe 6860
pin_count 10480 pin_count 2541
av 10871 av 9380
eav 32643 eav 28166

Major Class 2

Average and median tax bills and assessed values are calculated below for ALL property class types within the the broader “Residential” property class type (property classes that have the first digit “2”, or Major Class Type 2)

The median AV is used to select a range of pins (based on their AV) to calculate the average current bill, hypothetical bill, and hypothetical change in tax bill for a “median property”.

This is done because some properties receive multiple exemptions while others receive none. Using the literal median pin can skew the summary statistics of that specific pin receives no exemptions or multiple exemptions. The average for the range of “median PINs” is created to smooth out the variation within the observations.

DoltonChicago %>% 
  filter(propclass_1dig == "2") %>% 
  arrange(av) %>%
  group_by(agency_num) %>%
  summarize(medianbill = median(total_billed),
            meanbill = mean(total_billed),
            medianAV = median(av),
            meanAV = mean(av),
            pin_count = n()
            )%>% 
 # pivot_longer(medianbill:meanAV, names_to = "Stats", values_to = "Values")  %>%
  kbl(caption= "Chicago and Dolton, Major Class 2, Measures of the Middle", digits=0, booktabs = T) %>%   
  kable_styling(full_width = T)
Chicago and Dolton, Major Class 2, Measures of the Middle
agency_num medianbill meanbill medianAV meanAV pin_count
030210000 3619 5244 21119 29123 732952
030310000 4304 4364 9132 8929 8275
# 
# DoltonChicago %>% 
#   filter(propclass_1dig == "3") %>% 
#   arrange(av) %>%
#   group_by(agency_num) %>%
#   summarize(medianbill = median(total_billed),
#             meanbill = mean(total_billed),
#             medianAV = median(av),
#             meanAV = mean(av),
#             pin_count = n()
#             )%>% 
#  # pivot_longer(medianbill:meanAV, names_to = "Stats", values_to = "Values")  %>%
#   kbl(caption= "Chicago and Dolton, Major Class 3, Measures of the Middle", digits=0, booktabs = T) %>%   
#   kable_styling(full_width = T)

If holding the levy constant and acknowledging the change in tax rates that would occur from having additional taxable EAV within the taxing jurisdictions, Chicago’s hypothetical tax bill would be $1570 (an $14 increase from $1556) and Dolton’s would be $4610 (a $30 increase from $4580).

On average, residents would think they “saved” $501 in Chicago and $2588 in Dolton (based on tax_amt_exe which also shows up on their tax bill based on the “naive” pre-tax exemption tax bill amount on the tax bill). The amount saved per person will depend on how many exemptions they qualified for in the first place. This is a rough average for all types of exemptions and includes those that received no exemptions and multiiple exemptions.

Values were calculated by selecting pins with AVs between $9000 and $11,000 and then calculating the average current bill, change in bill, and other statistics seen in the table. Pin count tells you the number of pins that were included in the AV range used for the “median property.”

Chi3 <- DoltonChicago %>% 
  filter(agency_num == "030210000" & propclass_1dig == "2" & between(av,9000,11000)) %>%
    summarize(              
    comp_taxrate = mean(tax_code_rate, na.rm=TRUE),
    bill_current = mean(tax_amt_post_exe, na.rm=TRUE),
    bill_hyp = mean(eav*taxrate_new, na.rm=TRUE),
    bill_change = bill_hyp - bill_current,
    tax_amt_post_exe = mean(tax_amt_post_exe),
    tax_amt_exe = mean(tax_amt_exe, na.rm=TRUE),
    tax_amt_pre_exe = mean(tax_amt_pre_exe, na.rm=TRUE),
    pin_count = n(),
    av = mean(av), 
    eav = mean(eav)
  ) %>% 
  pivot_longer(cols = comp_taxrate:eav, names_to = "Stats", values_to = "Values")

# Chicago only has 2 pins that are similar to Dolton's median pin (which had a lot of matches)
Dol3 <- DoltonChicago %>% 
  filter(agency_num == "030310000" & propclass_1dig == "2" & between(av, 9000, 11000)) %>%
    summarize(              
    comp_taxrate = mean(tax_code_rate, na.rm=TRUE),
    bill_current = mean(tax_amt_post_exe, na.rm=TRUE),
    bill_hyp = mean(eav*taxrate_new, na.rm=TRUE),
    bill_change = bill_hyp - bill_current,
    tax_amt_post_exe = mean(tax_amt_post_exe),
    tax_amt_exe = mean(tax_amt_exe, na.rm=TRUE),
    tax_amt_pre_exe = mean(tax_amt_pre_exe, na.rm=TRUE),
    pin_count = n(),
    av = mean(av), 
    eav = mean(eav)
  ) %>% 
    pivot_longer(cols = comp_taxrate:eav, names_to = "Stats", values_to = "Values")

both_dt <- cbind(Chi3, Dol3)


kbl(both_dt, booktabs = T, digits = 0, 
    caption = "Property Major Class 2 Comparison, AV ~ $10,000 (AV range $9000-$11000)") %>%
  kable_styling(full_width = T)%>%
add_header_above(c("Chicago" = 2, "Dolton" = 2))
Property Major Class 2 Comparison, AV ~ $10,000 (AV range $9000-$11000)
Chicago
Dolton
Stats Values Stats Values
comp_taxrate 7 comp_taxrate 24
bill_current 1556 bill_current 4580
bill_hyp 1570 bill_hyp 4610
bill_change 14 bill_change 30
tax_amt_post_exe 1556 tax_amt_post_exe 4580
tax_amt_exe 501 tax_amt_exe 2588
tax_amt_pre_exe 2057 tax_amt_pre_exe 7168
pin_count 34215 pin_count 1823
av 10199 av 9869
eav 30623 eav 29635
Chi3 <- DoltonChicago %>% 
  filter(agency_num == "030210000" & propclass_1dig == "2" & between(av,8000,12000)) %>%
    summarize(              
    comp_taxrate = mean(tax_code_rate, na.rm=TRUE),
    bill_current = mean(tax_amt_post_exe, na.rm=TRUE),
    bill_hyp = mean(eav*taxrate_new, na.rm=TRUE),
    bill_change = bill_hyp - bill_current,
    tax_amt_post_exe = mean(tax_amt_post_exe),
    tax_amt_exe = mean(tax_amt_exe, na.rm=TRUE),
    tax_amt_pre_exe = mean(tax_amt_pre_exe, na.rm=TRUE),
    pin_count = n(),
    av = mean(av), 
    eav = mean(eav)
  ) %>% 
  pivot_longer(cols = comp_taxrate:eav, names_to = "Stats", values_to = "Values")

# Chicago only has 2 pins that are similar to Dolton's median pin (which had a lot of matches)
Dol3 <- DoltonChicago %>% 
  filter(agency_num == "030310000" & propclass_1dig == "2" & between(av, 8000, 12000)) %>%
    summarize(              
    comp_taxrate = mean(tax_code_rate, na.rm=TRUE),
    bill_current = mean(tax_amt_post_exe, na.rm=TRUE),
    bill_hyp = mean(eav*taxrate_new, na.rm=TRUE),
    bill_change = bill_hyp - bill_current,
    tax_amt_post_exe = mean(tax_amt_post_exe),
    tax_amt_exe = mean(tax_amt_exe, na.rm=TRUE),
    tax_amt_pre_exe = mean(tax_amt_pre_exe, na.rm=TRUE),
    pin_count = n(),
    av = mean(av), 
    eav = mean(eav)
  ) %>% 
    pivot_longer(cols = comp_taxrate:eav, names_to = "Stats", values_to = "Values")

both_dt <- cbind(Chi3, Dol3)


kbl(both_dt, booktabs = T, digits = 0, 
    caption = "Property Major Class 2 Comparison, AV ~ $10,000 (AV range $8000-$12000)") %>%
  kable_styling(full_width = T)%>%
add_header_above(c("Chicago" = 2, "Dolton" = 2))
Property Major Class 2 Comparison, AV ~ $10,000 (AV range $8000-$12000)
Chicago
Dolton
Stats Values Stats Values
comp_taxrate 7 comp_taxrate 25
bill_current 1579 bill_current 4796
bill_hyp 1592 bill_hyp 4698
bill_change 13 bill_change -99
tax_amt_post_exe 1579 tax_amt_post_exe 4796
tax_amt_exe 504 tax_amt_exe 2539
tax_amt_pre_exe 2083 tax_amt_pre_exe 7335
pin_count 62480 pin_count 3885
av 10329 av 9943
eav 31015 eav 29855

If holding the levy constant and acknowledging the change in tax rates that would occur from having additional taxable EAV within the taxing jurisdictions, Chicago’s hypothetical tax bill would be $1592 (an $13 increase from $1579) and Dolton’s would be $4598 (a $99 DECREASE from $4596).

Values were calculated by selecting pins with AVs between $8000 and $12,000 and then calculating the average current bill, change in bill, and other statistics seen in the table. Pin count tells you the number of pins that were included in the AV range used for the “median property.”

Increasing the number of pins included in the measurement of “average bill” and “average bill change” completely changed the results for Dolton. Using the “median” value must be done super carefully.

If we “removed” only homeowners exemptions or only senior exemptions, then the median statistic would be more reliable… potentially.

Class 205

Two or more story residence, over 62 years, up to 2,200 sq. ft

Chi3 <- DoltonChicago %>% 
  filter(agency_num == "030210000" & class == "205" & between(av,8000,12000)) %>%
    summarize(              
    comp_taxrate = mean(tax_code_rate, na.rm=TRUE),
    bill_current = mean(tax_amt_post_exe, na.rm=TRUE),
    bill_hyp = mean(eav*taxrate_new, na.rm=TRUE),
    bill_change = bill_hyp - bill_current,
    tax_amt_post_exe = mean(tax_amt_post_exe),
    tax_amt_exe = mean(tax_amt_exe, na.rm=TRUE),
    tax_amt_pre_exe = mean(tax_amt_pre_exe, na.rm=TRUE),
    pin_count = n(),
    av = mean(av), 
    eav = mean(eav)
  ) %>% 
  pivot_longer(cols = comp_taxrate:eav, names_to = "Stats", values_to = "Values")


Dol3 <- DoltonChicago %>% 
  filter(agency_num == "030310000" & class == "205" & between(av, 8000, 12000)) %>%
    summarize(              
    comp_taxrate = mean(tax_code_rate, na.rm=TRUE),
    bill_current = mean(tax_amt_post_exe, na.rm=TRUE),
    bill_hyp = mean(eav*taxrate_new, na.rm=TRUE),
    bill_change = bill_hyp - bill_current,
    tax_amt_post_exe = mean(tax_amt_post_exe),
    tax_amt_exe = mean(tax_amt_exe, na.rm=TRUE),
    tax_amt_pre_exe = mean(tax_amt_pre_exe, na.rm=TRUE),
    pin_count = n(),
    av = mean(av), 
    eav = mean(eav)
  )  %>% 
    pivot_longer(cols = comp_taxrate:eav, names_to = "Stats", values_to = "Values")

both_dt <- cbind(Chi3, Dol3)


kbl(both_dt, booktabs = T, digits = 0, 
    caption = "Property Class 205 Comparison, AV ~ $10,000 (8000 to 12000 AV range)") %>%
  kable_styling(full_width = T)%>%
add_header_above(c("Chicago" = 2, "Dolton" = 2))
Property Class 205 Comparison, AV ~ $10,000 (8000 to 12000 AV range)
Chicago
Dolton
Stats Values Stats Values
comp_taxrate 7 comp_taxrate 27
bill_current 1503 bill_current 5147
bill_hyp 1530 bill_hyp 4755
bill_change 27 bill_change -392
tax_amt_post_exe 1503 tax_amt_post_exe 5147
tax_amt_exe 622 tax_amt_exe 2353
tax_amt_pre_exe 2124 tax_amt_pre_exe 7500
pin_count 2832 pin_count 55
av 10544 av 9427
eav 31660 eav 28305

Class 211

Two to six residential apartments, any age.

Chi3 <- DoltonChicago %>% 
  filter(agency_num == "030210000" & class == "211" & between(av,17000,19000)) %>%
    summarize(              
    comp_taxrate = mean(tax_code_rate, na.rm=TRUE),
    bill_current = mean(tax_amt_post_exe, na.rm=TRUE),
    bill_hyp = mean(eav*taxrate_new, na.rm=TRUE),
    bill_change = bill_hyp - bill_current,
    tax_amt_post_exe = mean(tax_amt_post_exe),
    tax_amt_exe = mean(tax_amt_exe, na.rm=TRUE),
    tax_amt_pre_exe = mean(tax_amt_pre_exe, na.rm=TRUE),
    pin_count = n(),
    av = mean(av), 
    eav = mean(eav)
  ) %>% 
  pivot_longer(cols = comp_taxrate:eav, names_to = "Stats", values_to = "Values")


Dol3 <- DoltonChicago %>% 
  filter(agency_num == "030310000" & class == "211" & between(av, 17000, 19000)) %>%
    summarize(              
    comp_taxrate = mean(tax_code_rate, na.rm=TRUE),
    bill_current = mean(tax_amt_post_exe, na.rm=TRUE),
    bill_hyp = mean(eav*taxrate_new, na.rm=TRUE),
    bill_change = bill_hyp - bill_current,
    tax_amt_post_exe = mean(tax_amt_post_exe),
    tax_amt_exe = mean(tax_amt_exe, na.rm=TRUE),
    tax_amt_pre_exe = mean(tax_amt_pre_exe, na.rm=TRUE),
    pin_count = n(),
    av = mean(av), 
    eav = mean(eav)
  ) %>% 
    pivot_longer(cols = comp_taxrate:eav, names_to = "Stats", values_to = "Values")

both_dt <- cbind(Chi3, Dol3)


kbl(both_dt, booktabs = T, digits = 0, 
    caption = "Property Class 211 Comparison, AV ~ $18,000") %>%
  kable_styling(full_width = T)%>%
add_header_above(c("Chicago" = 2, "Dolton" = 2))
Property Class 211 Comparison, AV ~ $18,000
Chicago
Dolton
Stats Values Stats Values
comp_taxrate 7 comp_taxrate 24
bill_current 3040 bill_current 11459
bill_hyp 2782 bill_hyp 8211
bill_change -258 bill_change -3249
tax_amt_post_exe 3040 tax_amt_post_exe 11459
tax_amt_exe 628 tax_amt_exe 1231
tax_amt_pre_exe 3668 tax_amt_pre_exe 12690
pin_count 6747 pin_count 54
av 18217 av 17707
eav 54701 eav 53170

Class 234

Split level residence, with a lower level below grade, all ages, all sizes

Chi3 <- DoltonChicago %>% 
  filter(agency_num == "030210000" & class == "234" & between(av,12000,13000)) %>%
    summarize(              
    comp_taxrate = mean(tax_code_rate, na.rm=TRUE),
    bill_current = mean(tax_amt_post_exe, na.rm=TRUE),
    bill_hyp = mean(eav*taxrate_new, na.rm=TRUE),
    bill_change = bill_hyp - bill_current,
    tax_amt_post_exe = mean(tax_amt_post_exe),
    tax_amt_exe = mean(tax_amt_exe, na.rm=TRUE),
    tax_amt_pre_exe = mean(tax_amt_pre_exe, na.rm=TRUE),
    pin_count = n(),
    av = mean(av), 
    eav = mean(eav)
  ) %>% 
  pivot_longer(cols = comp_taxrate:eav, names_to = "Stats", values_to = "Values")


Dol3 <- DoltonChicago %>% 
  filter(agency_num == "030310000" & class == "234" & between(av, 12450, 12750)) %>%
    summarize(              
    comp_taxrate = mean(tax_code_rate, na.rm=TRUE),
    bill_current = mean(tax_amt_post_exe, na.rm=TRUE),
    bill_hyp = mean(eav*taxrate_new, na.rm=TRUE),
    bill_change = bill_hyp - bill_current,
    tax_amt_post_exe = mean(tax_amt_post_exe),
    tax_amt_exe = mean(tax_amt_exe, na.rm=TRUE),
    tax_amt_pre_exe = mean(tax_amt_pre_exe, na.rm=TRUE),
    pin_count = n(),
    av = mean(av), 
    eav = mean(eav)) %>% 
    pivot_longer(cols = comp_taxrate:eav, names_to = "Stats", values_to = "Values")

both_dt <- cbind(Chi3, Dol3)


kbl(both_dt, booktabs = T, digits = 0, 
    caption = "Property Class 234 Comparison, AV ~ $12,500") %>%
  kable_styling(full_width = T)%>%
add_header_above(c("Chicago" = 2, "Dolton" = 2))
Property Class 234 Comparison, AV ~ $12,500
Chicago
Dolton
Stats Values Stats Values
comp_taxrate 7 comp_taxrate 24
bill_current 1763 bill_current 5944
bill_hyp 1824 bill_hyp 5861
bill_change 61 bill_change -82
tax_amt_post_exe 1763 tax_amt_post_exe 5944
tax_amt_exe 779 tax_amt_exe 3176
tax_amt_pre_exe 2542 tax_amt_pre_exe 9120
pin_count 591 pin_count 215
av 12613 av 12606
eav 37872 eav 37851

“Cost” of Exemptions

# TC_bills_current has the summed taxbill information that comes from the tax_bill() command in ptaxsim
TC_bills_current <- read_csv("2_Summed_Bills_by_Taxcode_and_Class.csv") %>% 
  #filter(class == "205") %>%
  mutate(tax_code = as.character(tax_code),
         class = as.character(class))

class_dict$class_code <- as.character(class_dict$class_code)
 
#muni_tax_codes %>% select(tax_code_num, tax_code_rate, agency_num)
TC_bills_current <- left_join(TC_bills_current, muni_tax_codes,
                      by = c("tax_code" = "tax_code_num")) 

TC_bills_current <- TC_bills_current %>% left_join(muni_agency_names) %>% left_join(nicknames) %>% select(-c(shpfile_name, Column1, `Most recent reassessed`, short_name, minor_type, agency_name, agency_number))

TC_bills_current
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) 
    ) %>%
  full_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,
  na.value=NA,
                    n =6,
                       name = "Revenue Shifted \nfrom Exemptions",
         labels = scales::dollar
)+
 
  labs(title = "Dollars passed from Class 2 Residential properties to others \ndue to current exemptions",    
         caption = "There was $460 million in exempt EAV in Chicago.")

ggsave("cook_nochicago.png")
# Class 2 only
class2_perc <- exemptions_by_class_per_TC %>% 
  filter(class_code >=200 & class_code <=299) %>%
  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 <- 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%")
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")
tax_bill_change %>% 
 # filter(major_class_code == "2") %>% 
  filter(class_code >=200 & class_code <= 299) %>%
  filter(class_code != "0") %>%
   mutate(class_code = as.character(class_code)) %>%
  left_join(nicknames) %>%
  filter(Triad == "South") %>%
  summarize(cost_increasedbills = sum(bill_change, na.rm=TRUE))
TC_bills_current %>%  filter(class != "0") %>%
 summarize(cost_exemps = scales::dollar(sum(tax_amt_exe)),
                               composite_rate = mean(tax_code_rate)) 
TC_bills_current  %>% 
  filter(class != "0") %>%
  group_by(Triad) %>% 
  summarize(cost_exemps = scales::dollar(sum(tax_amt_exe)),
            composite_rate = mean(tax_code_rate)
                                                    ) 
# TC_bills_current %>% group_by(Triad) %>% 

Covering all changes in tax bills in the South triad would cost $218,678,328.

Paying for all tax bills that experienced a 15% increase from the elimination of exemptions or had a $0 taxbill would cost $825,963,411.

tax_bill_change %>% ungroup() %>%
  filter(class_code == "203") %>%
   mutate(class_code = as.character(class_code)) %>%
  left_join(nicknames)
tax_bill_change %>% ungroup() %>%
  filter(class_code == "203") %>%
    filter(clean_name %in% c("Park Forest","Markham",  "Dolton", "Hillside", "Riverside", "Chicago", "Westchester", "Winnetka")) %>%
   mutate(class_code = as.character(class_code)) %>%
  left_join(nicknames)%>%
group_by(Triad, clean_name)

Other Exemption Scenarios

Taxable Base in Scenarios

exemptions <- read_csv("3_Exemption_Details_output-all_cook_pin_exemptions_2021_actual.csv") 
# head(exemptions)


exemptions <- exemptions %>% 
  select(pin, av, eav_original = eav, class_code, tax_code_num, major_class_code, exe_homeowner:exe_abate) %>%
  
  mutate(exe_vet_dis = exe_vet_dis_lt50 + exe_vet_dis_50_69 + exe_vet_dis_ge70,
         total_exempt_eav = exe_homeowner + exe_senior + exe_freeze + exe_longtime_homeowner + 
           exe_disabled + exe_vet_returning + exe_vet_dis + exe_abate,
         has_homeown = ifelse(exe_homeowner > 0, 1, 0),
         has_senior = ifelse(exe_senior > 0, 1, 0),
         has_freeze = ifelse(exe_freeze > 0, 1, 0),
         
         has_seniorexemps = ifelse(exe_senior > 0 & exe_freeze > 0, 1, 0),
         has_disability = ifelse(exe_disabled > 0, 1, 0),
         has_vetreturn = ifelse(exe_vet_returning > 0, 1, 0), 
         
         has_any_exemps = ifelse(total_exempt_eav > 0, 1, 0),
         has_multi_exemps = ifelse(has_senior + has_freeze + has_homeown + has_disability + has_vetreturn > 1, 1, 0)) %>% 
  
  mutate(tax_code_num = as.character(tax_code_num))%>%
  left_join(muni_tax_codes) %>% 
  left_join(muni_agency_names) %>% 
  left_join(nicknames)

# head(exemptions)

#table(exemptions$has_any_exemps)
#table(exemptions$has_seniorexemps)
#table(exemptions$has_multi_exemps)

has_exemptions_pins <-  exemptions %>% 
  filter(has_any_exemps == 1)

# head(has_exemptions_pins)

has_exemptions_pins %>% 
  summarize(
    av = sum(av, na.rm = TRUE),
    EAV_beforeExemptsOrTIF=sum(eav_original, na.rm=TRUE),
    total_exempt_eav = sum(exe_homeowner + exe_senior + exe_freeze + exe_longtime_homeowner + 
                             exe_disabled + exe_vet_returning + exe_vet_dis + exe_abate, na.rm=TRUE),
    homeowners_exemption = sum(exe_homeowner),
    senior_exemption = sum(exe_senior, na.rm=TRUE),
    freeze_exemption = sum(exe_freeze, na.rm=TRUE),
    other_exemptions = sum(exe_vet_dis + exe_disabled + exe_longtime_homeowner + exe_vet_returning + exe_abate))  
muni_exempt_eav <- has_exemptions_pins %>% 
  group_by(clean_name, agency_num) %>%
  summarize(
    av_hasexemps = sum(av, na.rm = TRUE),
    eav_original_hasexemps=sum(eav_original, na.rm=TRUE),
    total_exempt_eav = sum(exe_homeowner + exe_senior + exe_freeze + exe_longtime_homeowner + 
                             exe_disabled + exe_vet_returning + exe_vet_dis + exe_abate, na.rm=TRUE),
    homeowners_exemption = sum(exe_homeowner),
    senior_exemption = sum(exe_senior, na.rm=TRUE),
    freeze_exemption = sum(exe_freeze, na.rm=TRUE),
    other_exemptions = sum(exe_vet_dis + exe_disabled + exe_longtime_homeowner + exe_vet_returning + exe_abate), 
    #pin_count_hasexemptions = n(),
    PC_has_exe = n() # has at least one exemption associated with the pin
    ) 


# muni_exempt_eav %>% select(-agency_num)

muni_C2_has_exe_eav <- has_exemptions_pins %>%
  group_by(clean_name, agency_num) %>%
  filter(major_class_code == "2") %>%
  summarize(
    av_hasexemps = sum(av, na.rm = TRUE),
    eav_original_hasexemps=sum(eav_original, na.rm=TRUE),
    total_exempt_eav = sum(exe_homeowner + exe_senior + exe_freeze + exe_longtime_homeowner +
                             exe_disabled + exe_vet_returning + exe_vet_dis + exe_abate, na.rm=TRUE),
    homeowners_exemption = sum(exe_homeowner),
    senior_exemption = sum(exe_senior, na.rm=TRUE),
    freeze_exemption = sum(exe_freeze, na.rm=TRUE),
    other_exemptions = sum(exe_vet_dis + exe_disabled + exe_longtime_homeowner + exe_vet_returning + exe_abate),
    PC_C2_has_exe = n()
    )


muni_singfamres_has_homeowners_exemps <- has_exemptions_pins %>% 
  filter(class_code > 199 & class_code < 211) %>%
  filter(exe_homeowner > 0) %>%
  group_by(clean_name, agency_num) %>%
  summarize(
    av_singfam_has_homeownexemps = sum(av, na.rm = TRUE),
    eav_original_sing_fam_has_homeownexemps=sum(eav_original, na.rm=TRUE),
    total_exempt_eav_singfam_has_homeown = sum(exe_homeowner + exe_senior + exe_freeze + exe_longtime_homeowner + exe_disabled + exe_vet_returning + exe_vet_dis + exe_abate, na.rm=TRUE),
    homeowners_exemption_singfam = sum(exe_homeowner),
    #pin_count_singfam_has_homeownerexemptions = n(),
    PC_SF_has_HOexe = n() # has Homeowner exemption and is within Class range specified
  ) 

Over 10 billion in EAV is not taxed due to the general homeowners exemption. 2.63 billion is not taxed due to senior exemptions. 3.2 billion in EAV is not taxed due to F

  • 1,029,799 pins have at least one exemption in 2021.
  • 350,126 pins have multiple exemptions in 2021.
  • 151,642 pins have the senior exemption, senior freeze exemption, or both of those exemptions.
munitotals <- exemptions %>%
  filter(tax_code_num %in% muni_tax_codes$tax_code_num)%>%
  group_by(clean_name, agency_num) %>%
  summarize(muni_av = sum(av, na.rm = TRUE),
            muni_eav_original=sum(eav_original, na.rm=TRUE),
            total_exempt_eav = sum(exe_homeowner + exe_senior + exe_freeze + exe_longtime_homeowner + 
                                     exe_disabled + exe_vet_returning + exe_vet_dis + exe_abate, na.rm=TRUE),
            homeowners_exemption = sum(exe_homeowner),
            senior_exemption = sum(exe_senior, na.rm=TRUE),
            freeze_exemption = sum(exe_freeze, na.rm=TRUE),
            PC_allPINs_muni = n() # number of pins within each municipality
            ) 

# munitotals %>% select(-agency_num)


muni_residentialtotals <- exemptions %>%
  filter(tax_code_num %in% muni_tax_codes$tax_code_num)%>%
  filter(major_class_code == "2") %>% 
  group_by(clean_name, agency_num) %>%
  summarize(muni_residential_av = sum(av, na.rm = TRUE),
            muni_residential_eav_original=sum(eav_original, na.rm=TRUE),
            total_residential_exempt_eav = sum(exe_homeowner + exe_senior + exe_freeze + exe_longtime_homeowner + 
                                                 exe_disabled + exe_vet_returning + exe_vet_dis + exe_abate, na.rm=TRUE),
            PC_C2_muni = n() # number of PINs that are Class 2 Residential 
            ) 

#muni_residentialtotals %>% select(-agency_num)


# Should I add the other "single family" property classes??  ## 
muni_singfam_residentialtotals <- exemptions %>%
  filter(tax_code_num %in% muni_tax_codes$tax_code_num)%>%
  filter(class_code > 199 & class_code < 211) %>% 
  group_by(clean_name, agency_num) %>%
  summarize(muni_singfam_residential_av = sum(av, na.rm = TRUE),
            muni_singfam_residential_eav_original=sum(eav_original, na.rm=TRUE),
           # total "single-family" residential exempt eav
            SF_res_exe_EAV_muni = sum(exe_homeowner + exe_senior + exe_freeze + exe_longtime_homeowner + 
                                      exe_disabled + exe_vet_returning + exe_vet_dis + exe_abate, na.rm=TRUE),
            PC_SF_Res = n() 
           ) 

#muni_singfam_residentialtotals %>% select(-agency_num)

merged <- munitotals %>% 
  select(clean_name, agency_num, muni_av, muni_eav_original, PC_allPINs_muni) %>% 
  left_join(muni_exempt_eav) %>% 
  left_join(muni_residentialtotals) %>%
  left_join(muni_singfam_residentialtotals) %>%
  left_join(muni_C2_has_exe_eav) %>%
  left_join(muni_singfamres_has_homeowners_exemps) %>%
  mutate(pct_ofSF_pins_w_HOexe = PC_SF_has_HOexe / PC_SF_Res,
        # pct_SF_pins_w_exemps = pin_count_has_homeownerexemptions / pin_count_singfam_residential,
        # pct_pins_w_exemps = pin_count_hasexemptions / pin_count,
        pct_ofallpins_w_exe = PC_has_exe / PC_allPINs_muni, #       pins with exemptions / all pins in a muni

         pct_C2_w_exemps = PC_C2_has_exe / PC_C2_muni, # 
         #pct_singfam_pins_w_exemps = pin_count_hasexemptions / pin_count_singfam_residential,
      #   pct_singfam_pins_w_exemps = pin_count_has_homeownerexemptions / pin_count_singfam_residential
    ) %>%
  
  select(clean_name, pct_ofSF_pins_w_HOexe, pct_ofallpins_w_exe, pct_C2_w_exemps, 
         PC_has_exe, PC_C2_muni, PC_allPINs_muni, everything())

merged

Bring in tax bills to calculate the muni levy for each municipality from final_tax_to_dist variable.

TC_bills_current <- read_csv("2_Summed_Bills_by_Taxcode_and_Class.csv") %>% 
  mutate(tax_code = as.character(tax_code),
         class = as.character(class))

class_dict$class_code <- as.character(class_dict$class_code)
 

taxcodes_current <- left_join(TC_bills_current, muni_tax_codes, 
                      by = c("tax_code" = "tax_code_num")) 

MuniLevy <- taxcodes_current %>% 
  left_join(muni_agency_names, by = "agency_num") %>%
  left_join(nicknames, by = c("agency_name" = "agency_name")) %>%
  #filter(!agency_num %in% cross_county_lines) %>%
  group_by(clean_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))


merged <- merged %>% left_join(MuniLevy)
scenario_taxrates <- merged %>% 
  mutate(scenario1_taxable_eav = Total_EAV - TIF_increment_EAV - Exempt_EAV + homeowners_exemption,
         scenario2_taxable_eav = Total_EAV - TIF_increment_EAV - Exempt_EAV + (senior_exemption + freeze_exemption ),
                  scenario_noexemptions_taxable_eav = Total_EAV - Exempt_EAV) %>%
  mutate(taxrate_scen1 = MuniLevy / scenario1_taxable_eav,
         taxrate_scen2 = MuniLevy / scenario2_taxable_eav,
         tax_rate_current = MuniLevy/nonTIF_EAV_post_exemps,
         taxrate_noexemps = MuniLevy /(Total_EAV - TIF_increment_EAV  ),
         taxrate_noTIFs = MuniLevy / (Total_EAV - Exempt_EAV),
         taxrate_noTIFs_orExemps = MuniLevy / Total_EAV)  %>%
  select(clean_name, MuniLevy, taxrate_scen1, taxrate_scen2, tax_rate_current, taxrate_noexemps, taxrate_noTIFs, taxrate_noTIFs_orExemps, scenario1_taxable_eav, scenario2_taxable_eav)

scenario_taxrates
merged %>% 
  filter(clean_name %in% c("Park Forest","Markham",  "Dolton", "Hillside", "Riverside", "Chicago", "Westchester", "Winnetka", "Rosemont")) %>%
  mutate(scenario1_taxable_eav = Total_EAV - TIF_increment_EAV - Exempt_EAV + homeowners_exemption,
         scenario2_taxable_eav = Total_EAV - TIF_increment_EAV - Exempt_EAV + (senior_exemption + freeze_exemption ),
         scenario_noexemptions_taxable_eav = Total_EAV - Exempt_EAV) %>%
  mutate(taxrate_scen1 = MuniLevy / scenario1_taxable_eav,
         taxrate_scen2 = MuniLevy / scenario2_taxable_eav,
         tax_rate_current = MuniLevy/nonTIF_EAV_post_exemps,
         taxrate_noexemps = MuniLevy /(Total_EAV - TIF_increment_EAV  ),
         taxrate_noTIFs = MuniLevy / (Total_EAV - Exempt_EAV),
         taxrate_noTIFs_orExemps = MuniLevy / Total_EAV)  %>%
  select(clean_name, MuniLevy, taxrate_scen1, taxrate_scen2, tax_rate_current, taxrate_noexemps, scenario1_taxable_eav, scenario2_taxable_eav, scenario_noexemptions_taxable_eav, Total_EAV, taxrate_noTIFs, taxrate_noTIFs_orExemps)

Scenario 1 is removing homeowners exemptions. Scenario 2 is removing the two senior exemptions.

Burden Share for Scenarios

Calculate Class 2 Burden –> Calculate the amount of taxable EAV in the Municipality (for each scenario) and multiply it by the new composite tax rate (for each scenario).

Burden Share = Taxable EAV within Property Class * Composite tax rate

Composite Tax Rate = (Municipal Levy / Taxable EAV )

Class2_EAV_scenarios <- exemptions %>% 
  filter(class_code >= 200 & class_code <= 300) %>% 
  filter(tax_code_num %in% muni_tax_codes$tax_code_num)%>%
  group_by(clean_name) %>%
  summarize(Class2_av = sum(av, na.rm = TRUE),
            Class2_eav_original=sum(eav_original, na.rm=TRUE),
            Class2_total_exempt_eav = sum(exe_homeowner + exe_senior + exe_freeze + exe_longtime_homeowner + 
                                     exe_disabled + exe_vet_returning + exe_vet_dis + exe_abate, na.rm=TRUE),
            Class2_homeowners_exemption = sum(exe_homeowner),
            Class2_senior_exemption = sum(exe_senior, na.rm=TRUE),
            Class2_freeze_exemption = sum(exe_freeze, na.rm=TRUE),
            Class2_PC_permuni = n() # number of pins within each municipality
            ) 
Class2_EAV_scenarios
Class2_TIF_EAV <-  taxcodes_current %>% 
  filter(class >=200 & class <=300) %>%
  left_join(muni_agency_names, by = "agency_num") %>%
  left_join(nicknames, by = c("agency_name" = "agency_name")) %>%
  filter(!agency_num %in% cross_county_lines) %>%
  group_by(clean_name) %>%
  summarize(Class2_DistrictRev = sum(final_tax_to_dist, na.rm = TRUE), # amount billed by munis with current exemptions in place
            Class2_nonTIF_EAV_post_exemps = sum(final_tax_to_dist/(tax_code_rate/100), na.rm = TRUE),
            Class2_TIF_increment_EAV = sum(final_tax_to_tif/(tax_code_rate/100), na.rm=TRUE),  
            Class2_Exempt_EAV = sum(tax_amt_exe/(tax_code_rate/100), na.rm=TRUE), 
            Class2_Total_EAV = sum((tax_amt_exe+final_tax_to_dist+final_tax_to_tif)/(tax_code_rate/100), na.rm = TRUE))

Class2_TIF_EAV
Class2_merged <- Class2_TIF_EAV %>% 
  left_join(Class2_EAV_scenarios) %>%
  left_join(MuniLevy)


Class2_Scenario_burdenshift <- Class2_merged %>% 
  left_join(scenario_taxrates) %>%
  mutate(Class2_scenario1_taxable_eav = Class2_Total_EAV - Class2_TIF_increment_EAV - Exempt_EAV +  Class2_homeowners_exemption,
        Class2_scenario2_taxable_eav = Class2_Total_EAV - Class2_TIF_increment_EAV - Exempt_EAV +  (Class2_senior_exemption + Class2_freeze_exemption )) %>%
  
  mutate(burden_C2_scen1 = (Class2_scenario1_taxable_eav * taxrate_scen1)/ MuniLevy,
         burden_C2_scen2 = (Class2_scenario2_taxable_eav * taxrate_scen2) / MuniLevy,
         burden_C2_current = Class2_nonTIF_EAV_post_exemps * tax_rate_current/ MuniLevy,
         burden_C2_noexemps = ( (Class2_Total_EAV - Class2_TIF_increment_EAV)*taxrate_noexemps ) / MuniLevy,
         burden_C2_noTIF_orExemps = (Class2_Total_EAV * taxrate_noTIFs_orExemps ) / MuniLevy,
         burden_C2_noTIFs =  ((Class2_Total_EAV - Class2_Exempt_EAV) * taxrate_noTIFs ) / MuniLevy) #  %>%
 # select(clean_name, MuniLevy, taxrate_scen1, taxrate_scen2, tax_rate_current, taxrate_noexemps, scenario1_taxable_eav, scenario2_taxable_eav)

Class2_Scenario_burdenshift %>% 
  select(clean_name, burden_C2_scen1:burden_C2_noTIFs)  %>% 
  filter(clean_name %in% c("Park Forest","Markham",  "Dolton", "Hillside", "Riverside", "Chicago", "Westchester", "Winnetka", "Rosemont"))

Appendix: All code for this report.

Exporting data into Excel

library(openxlsx)

dataset_names <- list('Cook County Totals' = total_exemptions,
                      'Incorp Exemp Totals' = muni_totals,
                      'Muni Level Exemp Tot' = exemptype_totals_permuni,
                      'EAV in and out of TIF' = tif_table,
                      'Percent Residential' = perc_residential,
                      'Tax Base by Class' = grouped_exemptions,
                      'CurrentandHyp Tax Burden'= munis_3property_types,
                      'Burden Shift, 3 PropClasses' = props_wide,
                      'Full Burden Shift Table'= burden_shift, # has essentially all variables used to make the smaller, more specific tables
                      'Exemps by Class, All Tax Codes' = exemptions_by_class_per_TC,
                      'Exempt Residential EAV' = exemptions_to_class2EAV_ratios,
                      'Tax Code Tax Rates'= taxcodes_current,
                  #    'Tax Bill Change, All PropClass' = tax_bill_change, # uses the actual median value for the statistic. Not my favorite way to calculate this statistic
                    #  'Tax Bill Change, 3 MajorClasses' = bill_change_3groups, # uses the actual median value for the statistic. Not my favorite way to calculate this statistic

                      'Muni TaxCodeXClass Bill Sums' = TC_bills_current, # uses the actual median value for the statistic. Not my favorite way to calculate this statistic
                      'Composite tax rates' = Current_Taxrates
)

write.xlsx(dataset_names, file = 'UIC_CMAP_exemptionWhitepaper.xlsx')
knitr::opts_chunk$set(echo = TRUE, warning = FALSE, message = FALSE)


library(tidyverse)
library(DBI)
library(data.table)
library(ggspatial)
library(gstat)
library(here)
library(httr)
library(jsonlite)
library(ptaxsim)
library(sf)
library(stars)
library(glue)
library(ggpattern)

# Create the DB connection with the default name expected by PTAXSIM functions
ptaxsim_db_conn <- DBI::dbConnect(RSQLite::SQLite(), "./ptaxsim.db/ptaxsim-2021.0.4.db")


options(digits=4, scipen = 999)

library(sf)
library(jsonlite)
library(httr)
library(NatParksPalettes)

# link to the API output as a JSON file
muni_shp <- read_sf("https://gis.cookcountyil.gov/traditional/rest/services/politicalBoundary/MapServer/2/query?outFields=*&where=1%3D1&f=geojson")

cook_shp <- read_sf("https://gis.cookcountyil.gov/traditional/rest/services/plss/MapServer/1/query?outFields=*&where=1%3D1&f=geojson")



#muni_shp <- read_json("muni_shp.json")
nicknames <- readxl::read_excel("muni_shortnames.xlsx")

class_dict <- read_csv("class_dict_expanded.csv") %>% 
  mutate(class_code = as.character(class_code))


cross_county_lines <- c("030440000", "030585000", "030890000", "030320000", "031280000","030080000", "030560000", "031120000", "030280000", "030340000","030150000","030050000", "030180000","030500000","031210000")



# `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. tax_bill() uses this table for the taxable EAV that is used to  calculate the tax rates in the tax bills. For simulations, you must alter the taxable EAV or levy or other variables and then tell tax_bill() function to use the modified agency data table for simulated tax bills.
# 



# has EAV values, extensions by agency_num
agency_dt <- DBI::dbGetQuery(
  ptaxsim_db_conn,
  "SELECT *
  FROM agency
  WHERE year = 2021
  "
)


cook_agency_names <- DBI::dbGetQuery(
  ptaxsim_db_conn,
  "SELECT DISTINCT agency_num, agency_name
  FROM agency_info
  "
)

 


# has all tax codes and the taxing agency that taxes them. Tax code rates and agency rates. 
cook_tax_codes <- DBI::dbGetQuery(
  ptaxsim_db_conn,
  glue_sql("
  SELECT*
  FROM tax_code
  WHERE agency_num IN ({cook_agency_names$agency_num*})
  AND year = 2021
  ",
  .con = ptaxsim_db_conn
  )
)


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_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
  )
)  
  

# 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
  )
)


tif_distrib <- DBI::dbGetQuery(
  ptaxsim_db_conn, 
  glue_sql("
  SELECT *
  FROM tif_distribution
  WHERE tax_code_num IN ({cook_tax_codes$tax_code_num*})
  AND year = 2021
  ",
  .con = ptaxsim_db_conn
  )
) %>% mutate(tax_code_num = as.character(tax_code_num))


exemptions_by_class_per_TC <- read_csv("3_Exemption_Details_output-Cook_Exemps_byClassandTaxcode.csv") 


cooktotals <- exemptions_by_class_per_TC %>% 
  summarize(av = sum(av, na.rm = TRUE),
            eav=sum(eav, na.rm=TRUE),
            total_exempt_eav = sum(exe_homeowner + exe_senior + exe_freeze + exe_longtime_homeowner + 
                         exe_disabled + exe_vet_returning + exe_vet_dis + exe_abate, na.rm=TRUE),
            homeowners_exemption = sum(exe_homeowner),
            senior_exemption = sum(exe_senior, na.rm=TRUE),
            freeze_exemption = sum(exe_freeze, na.rm=TRUE),
                        pin_count = n()) %>%
  pivot_longer(cols = av:pin_count, names_to = "Variables", values_to = "Cook County Totals")

munitotals <- exemptions_by_class_per_TC %>% 
  filter(tax_code_num %in% muni_tax_codes$tax_code_num)%>%
  summarize(av = sum(av, na.rm = TRUE),
            eav=sum(eav, na.rm=TRUE),
            total_exempt_eav = sum(exe_homeowner + exe_senior + exe_freeze + exe_longtime_homeowner + 
                         exe_disabled + exe_vet_returning + exe_vet_dis + exe_abate, na.rm=TRUE),
            homeowners_exemption = sum(exe_homeowner),
            senior_exemption = sum(exe_senior, na.rm=TRUE),
            freeze_exemption = sum(exe_freeze, na.rm=TRUE),
                        pin_count = n()) %>%
  pivot_longer(cols = av:pin_count, names_to = "Variables", values_to = "Municipality Totals")


total_exemptions <- left_join(cooktotals, munitotals)
total_exemptions

exemptype_totals_permuni <- exemptions_by_class_per_TC %>% 
  mutate(tax_code_num = as.character(tax_code_num)) %>%
  left_join(muni_tax_codes) %>%
  left_join(muni_agency_names) %>%
  filter(tax_code_num %in% muni_tax_codes$tax_code_num)%>%
  group_by(agency_num, agency_name) %>%
  summarize(av = sum(av, na.rm = TRUE),
            eav=sum(eav, na.rm=TRUE),
            total_exempt_eav_inMuni = sum(exe_homeowner + exe_senior + exe_freeze + exe_longtime_homeowner + 
                         exe_disabled + exe_vet_returning + exe_vet_dis + exe_abate, na.rm=TRUE),
            exe_homeowner = sum(exe_homeowner, na.rm=TRUE),
            exe_senior = sum(exe_senior, na.rm=TRUE),
            exe_freeze = sum(exe_freeze, na.rm=TRUE),
            exe_longtime_homeowner = sum(exe_longtime_homeowner, na.rm=TRUE),
            exe_disabled = sum(exe_disabled, na.rm=TRUE),
            exe_vet_returning = sum(exe_vet_returning, na.rm=TRUE),
            exe_vet_dis = sum(exe_vet_dis, na.rm=TRUE),
            exe_abate = sum(exe_abate, na.rm=TRUE),
            muni_pin_count = n())

exemptions_by_class_per_TC %>%
  summarize(exe_homeowner = sum(exe_homeowner, na.rm=TRUE),
            exe_senior = sum(exe_senior, na.rm=TRUE),
            exe_freeze = sum(exe_freeze, na.rm=TRUE),
            exe_longtime_homeowner = sum(exe_longtime_homeowner, na.rm=TRUE),
            exe_disabled = sum(exe_disabled, na.rm=TRUE),
            exe_vet_returning = sum(exe_vet_returning, na.rm=TRUE),
            exe_vet_dis = sum(exe_vet_dis),
            exe_abate = sum(exe_abate, na.rm=TRUE)) %>%
  pivot_longer(cols = exe_homeowner:exe_abate, names_to = "exemption_type", values_to = "amount")




# exemptions_by_class_per_TC %>% 
#   summarize(
#             exe_homeowner = sum(exe_homeowner, na.rm=TRUE),
#             exe_senior = sum(exe_senior, na.rm=TRUE),
#             exe_freeze = sum(exe_freeze, na.rm=TRUE),
#             exe_longtime_homeowner = sum(exe_longtime_homeowner, na.rm=TRUE),
#             exe_disabled = sum(exe_disabled, na.rm=TRUE),
#             exe_vet_returning = sum(exe_vet_returning, na.rm=TRUE),
#             exe_vet_dis = sum(exe_vet_dis),
#             exe_abate = sum(exe_abate, na.rm=TRUE),
#             ) %>%
#   pivot_longer(cols = exe_homeowner:exe_abate, names_to = "exemption_type", values_to = "amount") %>%
#   ggplot() +
#   geom_bar(aes(x=amount, y=exemption_type), stat = "identity") + theme_classic() +
#   theme(legend.position = "bottom")+
#   labs(y="",x="", title = "Amount of Exempt EAV due to each Exemption Type")+
#     scale_x_continuous(labels = scales::dollar)



exemptions_by_class_per_TC %>% 
  mutate(class_code = as.character(class_code)) %>%
    left_join(class_dict, by = "class_code") %>%
  group_by(Alea_cat) %>%
  summarize(av = sum(av, na.rm = TRUE),
            eav=sum(eav, na.rm=TRUE),
            exe_homeowner = sum(exe_homeowner, na.rm=TRUE),
            exe_senior = sum(exe_senior, na.rm=TRUE),
            exe_freeze = sum(exe_freeze, na.rm=TRUE),
            exe_longtime_homeowner = sum(exe_longtime_homeowner, na.rm=TRUE),
            exe_disabled = sum(exe_disabled, na.rm=TRUE),
            exe_vet_returning = sum(exe_vet_returning, na.rm=TRUE),
            exe_vet_dis = sum(exe_vet_dis),
            exe_abate = sum(exe_abate, na.rm=TRUE),
            pin_count = n()) %>%
  pivot_longer(cols = exe_homeowner:exe_abate, names_to = "exemption_type", values_to = "amount") %>%
  ggplot() +
  geom_bar(aes(x=amount, y=exemption_type, fill = Alea_cat), stat = "identity") + theme_classic() + 
    theme(legend.position = "bottom")+
labs(y="",x="", title = "Amount of Exempt EAV due to each Exemption Type", subtitle = "Alea's categories")+
  scale_x_continuous(labels = scales::dollar)


exemptions_by_class_per_TC %>% 
  mutate(class_code = as.character(class_code)) %>%
    left_join(class_dict, by = "class_code") %>%
  group_by(Alea_cat) %>%
  summarize(av = sum(av, na.rm = TRUE),
            eav=sum(eav, na.rm=TRUE),
            exe_homeowner = sum(exe_homeowner, na.rm=TRUE),
            exe_senior = sum(exe_senior, na.rm=TRUE),
            exe_freeze = sum(exe_freeze, na.rm=TRUE),
            exe_longtime_homeowner = sum(exe_longtime_homeowner, na.rm=TRUE),
            exe_disabled = sum(exe_disabled, na.rm=TRUE),
            exe_vet_returning = sum(exe_vet_returning, na.rm=TRUE),
            exe_vet_dis = sum(exe_vet_dis),
            exe_abate = sum(exe_abate, na.rm=TRUE),
            pin_count = n()) %>%
  pivot_longer(cols = exe_homeowner:exe_abate, names_to = "class_type", values_to = "amount") %>%
  ggplot() +
  geom_bar(aes(x=amount, y=Alea_cat, fill = class_type), stat = "identity") + theme_classic() + 
    theme(legend.position = "bottom")+
labs(y="",x="", title = "Amount of Exempt EAV due to each Exemption Type", subtitle = "Alea's categories")+
  scale_x_continuous(labels = scales::dollar)

exemptions_by_class_per_TC %>% 
  mutate(class_code = as.character(class_code)) %>%
    left_join(class_dict, by = "class_code") %>%
  group_by(major_class_type) %>%
 #   filter(major_class_type == "Residential") %>%

  summarize(av = sum(av, na.rm = TRUE),
            eav=sum(eav, na.rm=TRUE),
            exe_homeowner = sum(exe_homeowner, na.rm=TRUE),
            exe_senior = sum(exe_senior, na.rm=TRUE),
            exe_freeze = sum(exe_freeze, na.rm=TRUE),
            exe_longtime_homeowner = sum(exe_longtime_homeowner, na.rm=TRUE),
            exe_disabled = sum(exe_disabled, na.rm=TRUE),
            exe_vet_returning = sum(exe_vet_returning, na.rm=TRUE),
            exe_vet_dis = sum(exe_vet_dis),
            exe_abate = sum(exe_abate, na.rm=TRUE),
            pin_count = n()) %>%
  pivot_longer(cols = exe_homeowner:exe_abate, names_to = "class_type", values_to = "amount") %>%
  ggplot() +
  geom_bar(aes(x=amount, y = major_class_type, fill = class_type), stat = "identity") + theme_classic() +
  labs( y = "", title = "Exempt EAV within each Major Property Class", subtitle = "Major Class Types") +   theme(legend.position = "bottom")+
  scale_x_continuous(labels = scales::dollar)
# use exemptions in tax codes to summarize EAV. 
# exemption values came from `pin` data table in ptaxsim.
# More accurate that calculating it from revenue collected.tax rate in tax bill data

exemptions_by_class_per_TC <- read_csv("3_Exemption_Details_output-Cook_Exemps_byClassandTaxcode.csv") %>%
  mutate(tax_code_num = as.character(tax_code_num),
         class_code = as.character(class_code)) %>%
  
  left_join(class_dict, by = "class_code") %>%
  left_join(muni_tax_codes, by = c("tax_code_num") ) %>%
  
  # drops all Class 0 properties (Railroad property, tax exempt)
  filter(class_code != "0") %>%
  
  left_join(muni_agency_names) %>%
  left_join(nicknames, by = c("agency_name" = "agency_name")) %>%
  # 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),
         grouped_classes = ifelse(class_1dig %in% c("2"), "Class 2", NA),
         grouped_classes = ifelse(class_1dig %in% c("3", "9"), "Class 3", grouped_classes),
         grouped_classes = ifelse(is.na(grouped_classes), "Other Classes", grouped_classes)
  )



muni_totals <-  exemptions_by_class_per_TC %>% 
  group_by(clean_name, agency_name) %>% 
 #  filter(!is.na(clean_name)) %>%
  summarize(muni_av = sum(av),
            muni_eav = sum(eav))

table2 <- exemptions_by_class_per_TC %>% 
  group_by(clean_name, agency_name, grouped_classes) %>%
  summarize(av = sum(av),
            eav = sum(eav)) %>% 
  ungroup() %>%
  left_join(muni_totals) %>%
  filter(!is.na(clean_name))%>%
  mutate(perc_class2 = ifelse(grouped_classes == "Class 2", eav/muni_eav, 0),
         perc_class3 = ifelse(grouped_classes == "Class 3", eav/muni_eav, 0),
         perc_other = ifelse(grouped_classes == "Other Classes", eav/muni_eav, 0)) %>%
  group_by(clean_name, agency_name) %>%
  mutate(
         perc_res = perc_class2 + perc_class3)


table2 %>% ungroup() %>% select(-c(agency_name, muni_av, muni_eav))
munitotals <- exemptions_by_class_per_TC %>% 
  mutate(is_chicago = ifelse(clean_name == "Chicago", 1, 0)) %>%
  filter(tax_code_num %in% muni_tax_codes$tax_code_num)%>%
  group_by(is_chicago) %>%
  summarize(av = sum(av, na.rm = TRUE),
            eav=sum(eav, na.rm=TRUE),
            total_exempt_eav = sum(exe_homeowner + exe_senior + exe_freeze + exe_longtime_homeowner + 
                         exe_disabled + exe_vet_returning + exe_vet_dis + exe_abate, na.rm=TRUE),
            homeowners_exemption = sum(exe_homeowner, na.rm=TRUE),
            senior_exemption = sum(exe_senior, na.rm=TRUE),
            freeze_exemption = sum(exe_freeze, na.rm=TRUE),
                        pin_count = n()) %>%
  pivot_longer(cols = av:pin_count, names_to = "Variables", values_to = "Municipality Totals")

## only unincorporated aareas
cooktotals<-exemptions_by_class_per_TC %>% 
  mutate(is_chicago = ifelse(clean_name == "Chicago", 1, 0)) %>%
  filter(tax_code_num %in% cook_tax_codes$tax_code_num)%>%
  group_by(is_chicago) %>%
  summarize(av = sum(av, na.rm = TRUE),
            eav=sum(eav, na.rm=TRUE),
            total_exempt_eav = sum(exe_homeowner + exe_senior + exe_freeze + exe_longtime_homeowner + 
                         exe_disabled + exe_vet_returning + exe_vet_dis + exe_abate, na.rm=TRUE),
            homeowners_exemption = sum(exe_homeowner, na.rm=TRUE),
            senior_exemption = sum(exe_senior, na.rm=TRUE),
            freeze_exemption = sum(exe_freeze, na.rm=TRUE),
                        pin_count = n()) %>%
  pivot_longer(cols = av:pin_count, names_to = "Variables", values_to = "Cook County Totals") %>%
  mutate(is_chicago = ifelse(is.na(is_chicago), 0, is_chicago))

unincorporatedareas<-exemptions_by_class_per_TC %>% 
  mutate(is_chicago = ifelse(clean_name == "Chicago", 1, 0)) %>%
 filter(!tax_code_num %in% muni_tax_codes$tax_code_num)%>%
  group_by(is_chicago) %>%
  summarize(av = sum(av, na.rm = TRUE),
            eav=sum(eav, na.rm=TRUE),
            total_exempt_eav = sum(exe_homeowner + exe_senior + exe_freeze + exe_longtime_homeowner + 
                         exe_disabled + exe_vet_returning + exe_vet_dis + exe_abate, na.rm=TRUE),
            homeowners_exemption = sum(exe_homeowner, na.rm=TRUE),
            senior_exemption = sum(exe_senior, na.rm=TRUE),
            freeze_exemption = sum(exe_freeze, na.rm=TRUE),
                        pin_count = n()) %>%
  pivot_longer(cols = av:pin_count, names_to = "Variables", values_to = "Unincorporated Totals") %>%
  mutate(is_chicago = ifelse(is.na(is_chicago), 0, is_chicago))


cookandmunitotals <- left_join(cooktotals, munitotals) 
cookandmunitotals %>% left_join(unincorporatedareas)
tif_table <- exemptions_by_class_per_TC %>% 
  group_by(clean_name, agency_name, in_TIF, grouped_classes) %>%
  summarize(av = sum(av),
            eav = sum(eav)) %>% 
  ungroup() %>%
  left_join(muni_totals) %>% 
  pivot_wider(id_cols = c(clean_name, agency_name, muni_av, muni_eav), 
              names_from = c(in_TIF, grouped_classes), 
              values_from = eav)

# tif_table %>% 
#   select(clean_name:muni_eav, `1_Other Classes`, `0_Other Classes`) %>% 
#   rename(nonres_inTIF = `1_Other Classes`, 
#          nonres_outsideTIF = `0_Other Classes`) %>%
#   mutate(pct_nonres_inTIF = round(nonres_inTIF/muni_eav, digit=6),
#          pct_nonres_outsideTIF = round(nonres_outsideTIF/muni_eav, digit=6),
#          pct_nonres_inTIF = ifelse(is.na(pct_nonres_inTIF), 0, pct_nonres_inTIF),
#          pct_nonres_outsideTIF = ifelse(is.na(pct_nonres_outsideTIF), 0, pct_nonres_outsideTIF))

tif_table %>% 
  select(clean_name:muni_eav, `1_Class 2`, `0_Class 2`) %>% 
  rename(res_inTIF = `1_Class 2`, 
         res_outsideTIF = `0_Class 2`) %>%
  mutate(pct_res_inTIF = round(res_inTIF/muni_eav, digit=6),
         pct_res_outsideTIF = round(res_outsideTIF/muni_eav, digit=6),
         pct_res_inTIF = ifelse(is.na(pct_res_inTIF), 0, pct_res_inTIF),
         pct_res_outsideTIF = ifelse(is.na(pct_res_outsideTIF), 0, pct_res_outsideTIF)) %>% select(-agency_name) %>% filter(clean_name %in% c("Park Forest", "Dolton","Hillside", "Riverside","Chicago", "Westchester", "Markham", "Winnetka", "Rosemont"))

pivottable <- table2 %>% 
  pivot_wider(id_cols = c(clean_name, agency_name, muni_av, muni_eav), 
              names_from = grouped_classes, values_from = eav) %>%   
  mutate(agency_name = ifelse(agency_name == "TOWN CICERO", "CITY OF CICERO", agency_name) )

pivottable %>% select(-agency_name)

pivot_table <- pivottable %>%   
  mutate(perc_class2 = `Class 2`/muni_eav,
         perc_class3 = `Class 3`/muni_eav,
         perc_other = `Other Classes`/muni_eav,

         perc_nonres = (perc_class3 + perc_other),
         perc_residential = perc_class2) %>% 
  mutate_all( ~coalesce(.,0))

#pivot_table %>% ungroup() %>% select(-agency_name) %>% arrange(desc(perc_residential)) %>% select(clean_name, perc_residential, everything())

pivot_table %>% ungroup()  %>% select(-agency_name) %>% select(clean_name, perc_class2, perc_class3, perc_residential, everything())%>% arrange(desc(perc_class2))

#pivot_table %>% ungroup()  %>% select(-agency_name)%>% arrange(desc(perc_class3)) %>% select(clean_name, perc_class3, everything())

#write_csv(pivot_table, "3_exemption_details_output-residential_percent_August14.csv")

pivot_table %>% filter(clean_name %in% c("Park Forest","Markham",  "Dolton", "Hillside", "Riverside", "Chicago", "Westchester", "Winnetka", "Rosemont")) %>% ungroup() %>% select(-agency_name) %>% select(clean_name, `Class 2`:perc_residential, muni_eav, muni_av)
# sum of all Class 2 property EAV
class2_EAV <- table2 %>% ungroup() %>% filter(grouped_classes == "Class 2") %>% summarize(residential_eav = sum(eav))


Cook_layer <- ggplot(data = cook_shp, aes(geometry = geometry)) + 
  geom_sf_pattern() + theme_void()


pivot_table %>%
  full_join(muni_shp, by = c("agency_name" = "AGENCY_DESC")) %>% 

  ggplot(aes(fill = perc_class2)) + 
  geom_sf(aes(geometry = geometry), color = "black") + 
  labs(title = "Class 2 Properties EAV / Muni EAV", 
  caption = "67.6 % of EAV is from Class 2 Properties in the median municipality") +
  theme_void() + 
  theme(axis.ticks = element_blank(), axis.text = element_blank())+# +#+
  scale_fill_steps2(
     high =   "#2EEA8C", low = "#20223E", mid = "#F9ECE8",

 #   high = "darkgreen", low = "red",
    midpoint = median(pivot_table$perc_class2, na.rm = TRUE),

   nice.breaks = FALSE,
  #  show.limits=TRUE,
  na.value = "white",
    name = "% Class 2",
    labels = scales::percent
  )

pivot_table %>%
  full_join(muni_shp, by = c("agency_name" = "AGENCY_DESC")) %>% 
  ggplot(aes(fill = (perc_other))) + 
  geom_sf(aes(geometry = geometry), color = "black") + 
    labs(title = "Non-residential Property EAV /  Total EAV in Municipality", 
  caption = "Nonresidential includes all proeprty classes besides 2 & 3. 
  33.7% of EAV is from classes besides 2 & 3 in the median municipality.") +
  theme_void() + 
  theme(axis.ticks = element_blank(), axis.text = element_blank())+
  scale_fill_steps2(
  #  high =  "#E88C23", low = "#426737", mid ="#FAF3CE",
 low =   "#2EEA8C", high = "#20223E", mid = "#F9ECE8",
   midpoint = median(pivot_table$perc_other, na.rm = TRUE),
    nice.breaks = FALSE,
    show.limits=TRUE,
  na.value = NA,
    name = "% Non-Class 2 or 3",
    labels = scales::percent
  )



pivot_table %>%
    filter(clean_name != "University Park") %>%
  full_join(muni_shp, by = c("agency_name" = "AGENCY_DESC")) %>% 
  ggplot(aes(fill = perc_class3)) + 
  geom_sf(aes(geometry = geometry), color = "black") + 
  labs(title = "Class 3 Properties EAV / Muni EAV", 
  caption = "1.9% of EAV is from Class 3 properties in the median municipality. 
  Municipalities have a wide range of Class 3 percent makeup.") +
  theme_void() + 
  theme(axis.ticks = element_blank(), axis.text = element_blank())+# +#+
  scale_fill_steps2(
    #high = "darkblue", low = "orange",
     high =   "#2EEA8C", low = "#20223E",   mid = "#F9ECE8",
    midpoint = 
      median(pivot_table$perc_class3, na.rm = TRUE),
   #nice.breaks = FALSE,
   # show.limits=TRUE,
  na.value =  NA,
    name = "% Class 3",
    labels = scales::percent
  )

grouped_exemptions <- exemptions_by_class_per_TC %>% 
   # group_by(agency_name, major_class_code, major_class_type, ResidentialProps, PropType) %>%
  group_by(clean_name, grouped_classes, 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 == "Residential") %>% 
  mutate(pct_PropType = eav / muni_EAV_includesTIF)# %>% select()

pct_property_types %>% ungroup() %>% select(-agency_name) %>% select(Municipality = clean_name, PropertyClass = grouped_classes, pct_PropType, everything())

pct_property_types %>% ungroup() %>% select(-agency_name)  %>% filter(clean_name %in% c("Park Forest", "Dolton","Hillside", "Riverside","Chicago", "Westchester", "Markham", "Winnetka", "Rosemont"))

grouped_exemptions2 <- exemptions_by_class_per_TC %>% 
   # group_by(agency_name, major_class_code, major_class_type, ResidentialProps, PropType) %>%
  group_by(clean_name, grouped_classes, major_class_code, 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_types2 <- left_join(grouped_exemptions, muni_eav) %>% 
  #filter(ResidentialProps == "Residential") %>% 
  mutate(pct_PropType = eav / muni_EAV_includesTIF)
pct_property_types2
grouped_exemptions <- exemptions_by_class_per_TC %>% 
   group_by(clean_name, major_class_code, major_class_type, agency_name) %>%
  #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())
  

# 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() 



## Percent Residential is the same as percent that is Class == 2. 
## Percent residential does not include Multi-family property class 3 or 9.
perc_residential <- left_join(grouped_exemptions, muni_eav) %>% 
  filter(major_class_code == "2") %>% 
  mutate(percent_residential = eav / muni_EAV_includesTIF)# %>% select()
# 119 municipalities remain. Some munis do not have residential eav and are dropped.

# 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 %>% arrange(desc(percent_residential)) %>% 
  select(-c(major_class_code, major_class_type, agency_name)) %>%  # drop these and reorder
  select(clean_name, percent_residential, everything())


perc_residential %>% 
 # group_by(ResidentialProps)%>%
    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_residential)) + 
  geom_sf(aes(geometry = geometry), color = "black") + 
  labs(title = "Residential EAV /  Total EAV", 
  caption = "Residential Property includes 200 level property classes.
       The median municipality has 67% of its EAV from Class 2 Properties.") +
    theme_void() + 
  theme(axis.ticks = element_blank(), axis.text = element_blank())+# +#+
    scale_fill_steps2(
    high = "darkblue", low = "black", 
    mid = "beige", #  guide = "legend",
      midpoint = median(perc_residential$percent_residential),
           na.value = NA,   
                       n.breaks = 6,
  show.limits=TRUE,
                        name = "% Residential",
  labels = scales::percent)
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"))   %>% filter(!agency_num %in% cross_county_lines)



taxcodes_current %>% 
  left_join(muni_agency_names) %>%
  left_join(nicknames, by = c("agency_name" = "agency_name")) %>% 
  filter(clean_name %in% c("Park Forest","Markham",  "Dolton", "Hillside", "Riverside", "Chicago", "Westchester", "Winnetka")) %>% ungroup() %>% select(-c(agency_name, Column1, `Most recent reassessed`, shpfile_name, short_name,agency_number,))

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) %>% filter(class >= 800 &  class <= 900) %>% 
  group_by(clean_name) %>% distinct(clean_name)
Current_Taxrates <- taxcodes_current %>% 
  filter(!agency_num %in% cross_county_lines) %>%
  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))

Current_Taxrates %>%  filter(clean_name %in% c("Park Forest","Markham",  "Dolton", "Hillside", "Riverside", "Chicago", "Westchester", "Winnetka", "Rosemont")) %>% select(-agency_name)


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, major_class_code, 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()

land_use %>% filter(clean_name %in% c( "Dolton", "Chicago", "Winnetka")) %>% select(-agency_name)


# made in Excel originally

Current_Taxrates %>%  filter(clean_name %in% c("Park Forest","Dolton", "Hillside", "Riverside", "Chicago", "Winnetka", "Rosemont")) %>% select(clean_name, tax_rate_current, taxrate_new) %>% pivot_longer(cols = c(tax_rate_current,taxrate_new), names_to = "names", values_to = "values")  %>%
  ggplot(aes(x = clean_name, y = values, fill = names)) +
  geom_col(position = "dodge" ) + theme_classic() + labs(x="", y = "Composite Tax Rate")


Current_Taxrates %>%  filter(clean_name %in% c("Markham", "Chicago", "Westchester", "Winnetka")) %>% select(clean_name, tax_rate_current, taxrate_new) %>% pivot_longer(cols = c(tax_rate_current,taxrate_new), names_to = "names", values_to = "values")  %>%
  ggplot(aes(x = clean_name, y = values, fill = names)) +
  geom_col(position = "dodge" ) + theme_classic() + labs(x="", y = "Composite Tax Rate")

# 
# burden_shift %>% 
#   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 = "Variable", values_to = "Median Value")


Current_Taxrates %>% 
    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 = 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 = "plum4", low = "#008080",# mid = "lavenderblush2",
    midpoint = median(Current_Taxrates$tax_rate_current), #  midpoint = 0.123,
    #breaks = breaks_sd,
    limits = c(0,.45),
    show.limits=TRUE,
    na.value = NA,
    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.1%. 
         Highest composite tax rate is in Park Forest (41.4%.)
       Lowest composite tax rate is in Chicago (6.7%).")

Current_Taxrates %>% 
      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 = taxrate_new)) + 
  theme_void() + 
  theme(axis.ticks = element_blank(), axis.text = element_blank())+
  scale_fill_steps2(
    high = "plum4", low = "#008080",
    limits = c(0,.45),
    midpoint = median(Current_Taxrates$taxrate_new),  # midpoint = .1052,
    nice.breaks=FALSE,
    show.limits=TRUE,
    na.value=NA,
    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 = NA,
    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")
exemptions_to_class2EAV_ratios <- perc_residential %>% 
  mutate(exemptEAV_pctof_resEAV = exempt_EAV/eav,
         exemptEAV_pctof_totalEAV = exempt_EAV / muni_EAV_includesTIF,
         exemptEAV_pctof_taxbase_current = exempt_EAV / tax_base_current,
         exemptEAV_pctof_taxbase_noexemps = exempt_EAV / tax_base_noexemps,
         nontif_ratio = exempt_EAV / tax_base_noexemps) %>% 
  select(agency_name, clean_name, exemptEAV_pctof_resEAV, nontif_ratio, everything()) %>% 
  arrange(nontif_ratio)

exemptions_to_class2EAV_ratios %>%
    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 = 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",  mid = "beige",
                      # limits = c(0,.8),
                       n.breaks = 7, show.limits=TRUE,
                       na.value = NA,
                    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) ) %>%
  full_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", mid="beige",
                    #colors = c("white", "darkblue"), 
                    # limits = c(0),
                    midpoint = median(exemptions_to_class2EAV_ratios$nontif_ratio),
                    n.breaks = 5, 
                    na.value = NA,
                    show.limits=TRUE,
                    name = "% Residential EAV \nthat is exempt", label = scales::percent) + 
  labs( caption = "Median value is 20.0% ")


exemptions_to_class2EAV_ratios %>%
  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 = 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",mid ="beige",
                    #colors = c("white", "darkblue"), 
                    # limits = c(0),
                    midpoint = median(exemptions_to_class2EAV_ratios$nontif_ratio),
                    n.breaks = 7, 
                    na.value = NA,
                    show.limits=TRUE,
                    name = "% Residential EAV \nthat is exempt", label = scales::percent) + 
  labs( caption = "Median value is 20.0% ")
exemptions_to_class2EAV_ratios %>%  filter(nontif_ratio<.6) %>%
    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 = 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",mid ="beige",
                    #  colors = c("white", "darkblue"), 
                    limits = c(0,.4),
                    na.value = NA,
                    midpoint = median(exemptions_to_class2EAV_ratios$nontif_ratio),
                    n.breaks = 5, show.limits=TRUE,
                    name = "% Residential EAV \nthat is tax exempt", label = scales::percent)


exemptions_to_class2EAV_ratios %>%  filter(nontif_ratio<.6) %>%
  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 = 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",mid ="beige",
                    #  colors = c("white", "darkblue"), 
                    limits = c(0,.4),
                    na.value = NA,
                    midpoint = median(exemptions_to_class2EAV_ratios$nontif_ratio),
                    n.breaks = 7, show.limits=TRUE,
                    name = "% Residential EAV \nthat is tax exempt", label = scales::percent)
burden_table <- pct_property_types %>%
  filter(!is.na(clean_name)) %>%
  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.


burden_table %>% 
  arrange(desc(burden_change)) %>% 
  select(clean_name, burden_change, everything()) %>%
  mutate(burden_change = round(burden_change*100, digits = 2)) %>%
  select(-agency_name)

# Current Burden:

munis_3property_types <- burden_shift %>%
    filter(!agency_name %in% cross_county_lines) %>%
# 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, grouped_classes) %>%
  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 <- munis_3property_types %>% 
    mutate(burden_current = ifelse(is.na(burden_current), 0, burden_current)) %>%

  pivot_wider( id_cols = clean_name , names_from = "grouped_classes", values_from = "burden_current", names_prefix="Current - ", values_fill = 0 ) %>% 
  select(clean_name, `Current - Class 2`, everything()) %>%
  arrange(-`Current - Class 2`)

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 <- munis_3property_types %>% 
  mutate(burden_noexemps = ifelse(is.na(burden_noexemps), 0, burden_noexemps)) %>%
  pivot_wider( id_cols = clean_name , names_from = "grouped_classes", 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

burden_3groups_currentandhypothetial<- left_join(proptypes3_current, proptypes3_noexemps)
burden_3groups_currentandhypothetial

props_wide <- munis_3property_types %>%
  pivot_wider(id_cols = clean_name , 
               names_from = "grouped_classes", 
               values_from = "burden_change", values_fill = 0) %>% 
  select(clean_name, `Class 2`, everything()) %>%
  arrange(desc(`Class 2`) )

props_wide[2:4] <- sapply(props_wide[2:4], function(x) scales::percent(x, accuracy=.01))
props_wide
props_wide %>%  filter(clean_name %in% c("Markham", "Chicago", "Westchester", "Winnetka"))
burden_table  %>%  filter(clean_name %in% c("Markham", "Chicago", "Westchester", "Winnetka"))%>% select(clean_name, burden_current:burden_change) %>% pivot_longer(cols = c(burden_current, burden_noexemps), names_to = "names", values_to = "values")  %>%
  ggplot(aes(x = clean_name, y = values, fill = names)) +
  geom_col(position = "dodge" ) + theme_classic() + labs(x="", y="Share of Levy Paid by Class 2", title = "Current and Hypothetial Tax Burden")
# as a dot graph ## 

cross_county_lines <- c("030440000",
"030585000", "030890000", "030320000", "031280000","030080000", "030560000", "031120000", "030280000", "030340000","030150000","030050000", "030180000","030500000","031210000")

cross_county_lines <- muni_agency_names %>% filter(agency_num %in%cross_county_lines) %>% left_join(nicknames, by = "agency_name")

order <- burden_shift %>% 
  ungroup %>% as_tibble() %>%
  #  filter(ResidentialProps == "Residential") %>%
  filter(grouped_classes == "Class 2") %>%
  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


# median burden c hange is 0.45
# current median burden is 65.5% of the levy

burden_shift %>% 
  filter(!clean_name %in% cross_county_lines$clean_name)%>%
  filter(grouped_classes == "Class 2") %>%
  filter(burden_current > 0.938 |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 = 65.5, linetype = 3)+
  geom_line(aes(group = clean_name))+ 
  geom_hline(yintercept = 5.5, linetype = 2)+
  geom_hline(yintercept = 13.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 Class 2 Residential Tax Burden", 
       subtitle = "Ordered by Current Tax Burden",
  x = "Share of Levy (%)", y = "" , 
  caption = "Dotted line represents median Class 2 burden (65.5% of the levy). Residential Tax Burden is the 
  share of the property tax collected that was paid for by property owners with Class 2 properties.") +
    geom_label(label = "Class 2 pays small share of \nlevy; very little residential", x=32, y = 16, label.size = 1, size = 3)+
    geom_label(label = "Class 2 pays median share of \nlevy (65%), mix of land use", x=42, y = 9.5, label.size = 1, size = 3) +
    geom_label(label = "Class 2 pays nearly all of levy, \nhighly residential", x=70, y = 3, label.size = 1,size = 3)
#bill_change_3groups <- read_csv( "4_Taxbill_Hypotheticals-taxbill_change_20230814.csv")

#bill_change_3groups %>% select(Municipality = clean_name, bill_change, everything()) 


tax_bill_change <- read_csv("4_Taxbill_Hypotheticals-taxbill_change_foreachPropClass_perMuni.csv")

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*100)) + 
  geom_sf(aes(geometry = geometry), color = "black") +  
  theme_void() + 
  theme(axis.ticks = element_blank(), axis.text = element_blank())+
  
  scale_fill_steps2(high = "darkblue", low = "black", mid = "lightblue",
                    n=7, 
                    midpoint = median(Current_Taxrates$taxrate_change*100),
                 #   midpoint = 0.01388, 
                 guide = "legend",
                    show.limits=TRUE,
                    nice.breaks=TRUE,
                    na.value = NA,
                   # labels = scales::percent,
                    name = "Percentage Point \nDifference")+
  labs(title = "Change in Composite Tax Rate if all Exemptions are Eliminated")

ggsave("AWM_compositetaxrate_change.png", limitsize = FALSE, width = 8, height = 4, units = "in")
# # all of unincorporated cook totals: includes all land in cook county
# taxcodes_current %>% 
#   left_join(muni_agency_names, by = "agency_num") %>%
#   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)) %>%
#   pivot_longer(cols = MuniLevy:taxrate_change) %>%
#   mutate(value = round(value, digits = 0))


# all of incorporated cook totals; Munis only
taxcodes_current %>% 
  left_join(muni_agency_names, by = "agency_num") %>%
  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 = round(MuniLevy/nonTIF_EAV_post_exemps,2),
         nonTIF_EAV_pre_exemps = round(nonTIF_EAV_post_exemps + Exempt_EAV),
         taxrate_new = round(MuniLevy/nonTIF_EAV_pre_exemps,2),
         taxrate_change = round(tax_rate_current-taxrate_new, 2) )%>% 
 # select(clean_name, taxrate_change, tax_rate_current, taxrate_new, everything()) %>% 
  arrange(desc(tax_rate_current)) %>%
  pivot_longer(cols = MuniLevy:taxrate_change) %>%
  mutate(value = value)
Current_Taxrates_perTC <- taxcodes_current %>% 
  left_join(muni_agency_names, by = "agency_num") %>%
  left_join(nicknames, by = c("agency_name" = "agency_name")) %>%
  filter(!agency_num %in% cross_county_lines) %>%
  group_by(clean_name, agency_name, tax_code, pins_in_class) %>%
  
  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, tax_code, everything()) %>% 
  arrange(desc(tax_rate_current))

Current_Taxrates_perTC

Current_Taxrates_perTC %>% left_join(nicknames) %>%
  group_by(Triad) %>% 
  filter( Triad == "South") %>% summarize(taxrate_new = mean(taxrate_new, na.rm=TRUE),
                                          taxrate_current = mean(tax_rate_current, na.rm=TRUE)) %>%
  mutate(taxrate_change = taxrate_new-taxrate_current)

Current_Taxrates_perTC %>% left_join(nicknames) %>% group_by(Triad) %>% 
  filter( Triad == "North") %>% summarize(taxrate_change = mean(taxrate_change, na.rm=TRUE))

Current_Taxrates_perTC %>% 
  mutate(is_chicago = ifelse(clean_name == "Chicago", 1,0)) %>%
  group_by(is_chicago) %>%
  summarize(average_taxableEAV_current = mean(nonTIF_EAV_post_exemps/pins_in_class, na.rm=TRUE),
         average_taxableEAV_hyp = mean(nonTIF_EAV_pre_exemps/pins_in_class, na.rm=TRUE),
         average_taxableEAV_hyp_noTIFS = mean(Total_EAV/pins_in_class, na.rm=TRUE),
         average_taxbill_current = mean(tax_rate_current*average_taxableEAV_current, na.rm=TRUE),
         average_taxbill_hyp = mean(taxrate_new*average_taxableEAV_hyp, na.rm=TRUE)) %>%
  pivot_longer(cols = average_taxableEAV_current:average_taxbill_hyp)

Current_Taxrates_perTC %>% 
  mutate(is_chicago = ifelse(clean_name == "Chicago", 1,0)) %>%
  group_by(is_chicago) %>%
  summarize(rev_billed = sum(MuniLevy, na.rm=TRUE)) #%>% # made from final_tax_to_dist variable
         # average_taxableEAV_hyp = mean(nonTIF_EAV_pre_exemps/pins_in_class, na.rm=TRUE),
         # average_taxableEAV_hyp_noTIFS = mean(Total_EAV/pins_in_class, na.rm=TRUE),
         # average_taxbill_current = mean(tax_rate_current*average_taxableEAV_current, na.rm=TRUE),
         # average_taxbill_hyp = mean(taxrate_new*average_taxableEAV_hyp, na.rm=TRUE)) %>%
  #pivot_longer(cols = average_taxableEAV_current:average_taxbill_hyp)



Current_Taxrates_perTC %>% 
mutate(is_chicago = ifelse(clean_name == "Chicago", 1,0)) %>%
  group_by(is_chicago) %>%
  summarize(tif_rev = sum(tax_rate_current * TIF_increment_EAV, na.rm=TRUE),
            rev_billed = sum(tax_rate_current * nonTIF_EAV_post_exemps, na.rm=TRUE),
            all_rev = sum(tax_rate_current* (nonTIF_EAV_post_exemps + TIF_increment_EAV), na.rm=TRUE))
# 14,990,945,440 Revenue Collected (does not include TIF revenue) 
# 16,539,762,290 Revenue Collected (including TIF revenue)
Current_Taxrates2 <- read_csv("2_taxcode_taxrates.csv") %>% 
  mutate(tax_code = as.character(tax_code))

land_use2 <- 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, major_class_code, 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()

land_use2


nicknames <- readxl::read_excel("muni_shortnames.xlsx")

class_dict <- read_csv("class_dict.csv")

taxcode_taxrates <- read_csv("2_taxcode_taxrates.csv")


DoltonChicago <- read_csv("Cholton_taxbills.csv") %>% 
  arrange(av) %>%     
  left_join(taxcode_taxrates) %>%
    mutate(propclass_1dig = str_sub(class, 1, 1))

library(kableExtra)
# DoltonChicago %>% 
#   group_by(agency_num, tax_code) %>% 
#   summarize(max_comprate = max(tax_rate_current),
#             min_comprate = min(tax_rate_current)) %>% arrange(-max_comprate)

DoltonChicago %>% group_by(agency_num) %>% 
  summarize(max_comprate = max(tax_rate_current, na.rm=TRUE),
            mean_comprate = mean(tax_rate_current, na.rm=TRUE),
            min_comprate = min(tax_rate_current, na.rm=TRUE)) %>% arrange(-mean_comprate)

DoltonChicago %>% filter(agency_num == "030310000") %>%
  group_by(agency_num, class) %>% 
  summarize(max_comprate = max(tax_rate_current, na.rm=TRUE),
            mean_comprate = mean(tax_rate_current, na.rm=TRUE),
            min_comprate = min(tax_rate_current, na.rm=TRUE),
            pin_count = n(),
            av = mean(av),
            eav = mean(eav),
            tax_amt_post_exe = mean(tax_amt_post_exe),
            tax_amt_exe = mean(tax_amt_exe),
            tax_amt_pre_exe = mean(tax_amt_pre_exe)) %>% 
  arrange(-pin_count) %>% head() %>% kbl()

DoltonChicago %>% filter(agency_num == "030210000") %>%
  group_by(agency_num, class) %>% 
  summarize(max_comprate = max(tax_rate_current, na.rm=TRUE),
            mean_comprate = mean(tax_rate_current, na.rm=TRUE),
            min_comprate = min(tax_rate_current, na.rm=TRUE),
            pin_count = n(),
            av = mean(av),
            eav = mean(eav),
            tax_amt_post_exe = mean(tax_amt_post_exe),
            tax_amt_exe = mean(tax_amt_exe),
            tax_amt_pre_exe = mean(tax_amt_pre_exe)) %>% 
  arrange(-pin_count) %>% head() %>% kbl()

DoltonChicago %>% 
  filter(class == "203") %>% 
  arrange(av)%>%
  group_by(agency_num, class) %>%
  summarize(medianbill = median(total_billed),
            meanbill = mean(total_billed),
            medianAV = median(av),
            meanAV = mean(av),
            )%>% 
 # pivot_longer(medianbill:meanAV, names_to = "Stats", values_to = "Values")  %>%
  kbl(caption= "Chicago and Dolton, Class 203, Measures of the Middle", digits=0, booktabs = T) %>%   
  kable_styling(full_width = T)



DoltonChicago %>% 
  filter(class == "205") %>% 
  group_by(agency_num, class) %>%
  summarize(medianbill = median(total_billed),
            meanbill = mean(total_billed),
            medianAV = median(av),
            meanAV = mean(av),
            )%>% 
 # pivot_longer(medianbill:meanAV, names_to = "Stats", values_to = "Values")  %>%
  kbl(caption= "Chicago and Dolton, Class 205, Measures of the Middle", digits=0, booktabs = T) %>%   
  kable_styling(full_width = T)

DoltonChicago %>% 
  filter(class == "211") %>% 
  group_by(agency_num, class) %>%
  summarize(medianbill = median(total_billed),
            meanbill = mean(total_billed),
            medianAV = median(av),
            meanAV = mean(av),
            )%>% 
 # pivot_longer(medianbill:meanAV, names_to = "Stats", values_to = "Values")  %>%
  kbl(caption= "Chicago and Dolton, Class 211, Measures of the Middle", digits=0, booktabs = T) %>%   
  kable_styling(full_width = T)

DoltonChicago %>% 
  filter(class == "234") %>% 
  group_by(agency_num, class) %>%
  summarize(medianbill = median(total_billed),
            meanbill = mean(total_billed),
            medianAV = median(av),
            meanAV = mean(av),
            )%>% 
 # pivot_longer(medianbill:meanAV, names_to = "Stats", values_to = "Values")  %>%
  kbl(caption= "Chicago and Dolton, Class 234, Measures of the Middle", digits=0, booktabs = T) %>%   
  kable_styling(full_width = T)


DoltonChicago %>% 
  filter(agency_num == "030210000" ) %>% #& class == "203" & between(av,9950,10050)) %>% 
  group_by(tax_code) %>% 
  summarize(count = n(),            
            avg_current_comprate = mean(tax_rate_current, na.rm=TRUE)
  ) %>% arrange(-avg_current_comprate) %>% head()

DoltonChicago %>% 
  filter(agency_num == "030310000") %>% # & class == "203" & between(av, 9950, 10050)) %>%
  group_by(tax_code) %>%
  summarize(count = n(),
            avg_current_comprate = mean(tax_rate_current, na.rm=TRUE)
  ) %>% arrange(-avg_current_comprate) %>% head()
Chi3 <- DoltonChicago %>% 
  filter(agency_num == "030210000" & class == "203" & between(av,9000,11000)) %>%
    summarize(              
    comp_taxrate = mean(tax_code_rate, na.rm=TRUE),
    bill_current = mean(tax_amt_post_exe, na.rm=TRUE),
    bill_hyp = mean(eav*taxrate_new, na.rm=TRUE),
    bill_change = bill_hyp - bill_current,
    tax_amt_post_exe = mean(tax_amt_post_exe),
    tax_amt_exe = mean(tax_amt_exe),
    tax_amt_pre_exe = mean(tax_amt_pre_exe),
    pin_count = n(),
    av = mean(av), 
    eav = mean(eav)
  ) %>% 
  pivot_longer(cols = comp_taxrate:eav, names_to = "Stats", values_to = "Values")

Dol3 <- DoltonChicago %>% 
  filter(agency_num == "030310000" & class == "203" & between(av, 9000, 11000)) %>%
    summarize(              
    comp_taxrate = mean(tax_code_rate, na.rm=TRUE),
    bill_current = mean(tax_amt_post_exe, na.rm=TRUE),
    bill_hyp = mean(eav*taxrate_new, na.rm=TRUE),
    bill_change = bill_hyp - bill_current,
    tax_amt_post_exe = mean(tax_amt_post_exe),
    tax_amt_exe = mean(tax_amt_exe, na.rm=TRUE),
    tax_amt_pre_exe = mean(tax_amt_pre_exe, na.rm=TRUE),
    pin_count = n(),
    av = mean(av), 
    eav = mean(eav)
  ) %>% 
    pivot_longer(cols = comp_taxrate:eav, names_to = "Stats", values_to = "Values")

both_dt <- cbind(Chi3, Dol3)


kbl(both_dt, booktabs = T, digits = 0, 
    caption = "Property Class 203 Comparison, AV ~ $10,000 (9000-11000 range)") %>%
  kable_styling(full_width = T)%>%
add_header_above(c("Chicago" = 2, "Dolton" = 2))
Chi3 <- DoltonChicago %>% 
  filter(agency_num == "030210000" & class == "203" & between(av,8000,12000)) %>%
    summarize(              
    comp_taxrate = mean(tax_code_rate, na.rm=TRUE),
    bill_current = mean(tax_amt_post_exe, na.rm=TRUE),
    bill_hyp = mean(eav*taxrate_new, na.rm=TRUE),
    bill_change = bill_hyp - bill_current,
    tax_amt_post_exe = mean(tax_amt_post_exe),
    tax_amt_exe = mean(tax_amt_exe, na.rm=TRUE),
    tax_amt_pre_exe = mean(tax_amt_pre_exe, na.rm=TRUE),
    pin_count = n(),
    av = mean(av), 
    eav = mean(eav)
  ) %>% 
  pivot_longer(cols = comp_taxrate:eav, names_to = "Stats", values_to = "Values")

# Chicago only has 2 pins that are similar to Dolton's median pin (which had a lot of matches)
Dol3 <- DoltonChicago %>% 
  filter(agency_num == "030310000" & class == "203" & between(av, 8000, 12000)) %>%
    summarize(              
    comp_taxrate = mean(tax_code_rate, na.rm=TRUE),
    bill_current = mean(tax_amt_post_exe, na.rm=TRUE),
    bill_hyp = mean(eav*taxrate_new, na.rm=TRUE),
    bill_change = bill_hyp - bill_current,
    tax_amt_post_exe = mean(tax_amt_post_exe),
    tax_amt_exe = mean(tax_amt_exe, na.rm=TRUE),
    tax_amt_pre_exe = mean(tax_amt_pre_exe, na.rm=TRUE),
    pin_count = n(),
    av = mean(av), 
    eav = mean(eav)
  ) %>% 
    pivot_longer(cols = comp_taxrate:eav, names_to = "Stats", values_to = "Values")

both_dt <- cbind(Chi3, Dol3)


kbl(both_dt, booktabs = T, digits = 0, 
    caption = "Property Major Class 2 Comparison, AV ~ $10,000 (AV range $8000-$12000)") %>%
  kable_styling(full_width = T)%>%
add_header_above(c("Chicago Class 203, 8K-12K Property Stats" = 2, "Dolton Class 203, 8L-12K AV Property Stats" = 2))
DoltonChicago %>% 
  filter(propclass_1dig == "2") %>% 
  arrange(av) %>%
  group_by(agency_num) %>%
  summarize(medianbill = median(total_billed),
            meanbill = mean(total_billed),
            medianAV = median(av),
            meanAV = mean(av),
            pin_count = n()
            )%>% 
 # pivot_longer(medianbill:meanAV, names_to = "Stats", values_to = "Values")  %>%
  kbl(caption= "Chicago and Dolton, Major Class 2, Measures of the Middle", digits=0, booktabs = T) %>%   
  kable_styling(full_width = T)

# 
# DoltonChicago %>% 
#   filter(propclass_1dig == "3") %>% 
#   arrange(av) %>%
#   group_by(agency_num) %>%
#   summarize(medianbill = median(total_billed),
#             meanbill = mean(total_billed),
#             medianAV = median(av),
#             meanAV = mean(av),
#             pin_count = n()
#             )%>% 
#  # pivot_longer(medianbill:meanAV, names_to = "Stats", values_to = "Values")  %>%
#   kbl(caption= "Chicago and Dolton, Major Class 3, Measures of the Middle", digits=0, booktabs = T) %>%   
#   kable_styling(full_width = T)
Chi3 <- DoltonChicago %>% 
  filter(agency_num == "030210000" & propclass_1dig == "2" & between(av,9000,11000)) %>%
    summarize(              
    comp_taxrate = mean(tax_code_rate, na.rm=TRUE),
    bill_current = mean(tax_amt_post_exe, na.rm=TRUE),
    bill_hyp = mean(eav*taxrate_new, na.rm=TRUE),
    bill_change = bill_hyp - bill_current,
    tax_amt_post_exe = mean(tax_amt_post_exe),
    tax_amt_exe = mean(tax_amt_exe, na.rm=TRUE),
    tax_amt_pre_exe = mean(tax_amt_pre_exe, na.rm=TRUE),
    pin_count = n(),
    av = mean(av), 
    eav = mean(eav)
  ) %>% 
  pivot_longer(cols = comp_taxrate:eav, names_to = "Stats", values_to = "Values")

# Chicago only has 2 pins that are similar to Dolton's median pin (which had a lot of matches)
Dol3 <- DoltonChicago %>% 
  filter(agency_num == "030310000" & propclass_1dig == "2" & between(av, 9000, 11000)) %>%
    summarize(              
    comp_taxrate = mean(tax_code_rate, na.rm=TRUE),
    bill_current = mean(tax_amt_post_exe, na.rm=TRUE),
    bill_hyp = mean(eav*taxrate_new, na.rm=TRUE),
    bill_change = bill_hyp - bill_current,
    tax_amt_post_exe = mean(tax_amt_post_exe),
    tax_amt_exe = mean(tax_amt_exe, na.rm=TRUE),
    tax_amt_pre_exe = mean(tax_amt_pre_exe, na.rm=TRUE),
    pin_count = n(),
    av = mean(av), 
    eav = mean(eav)
  ) %>% 
    pivot_longer(cols = comp_taxrate:eav, names_to = "Stats", values_to = "Values")

both_dt <- cbind(Chi3, Dol3)


kbl(both_dt, booktabs = T, digits = 0, 
    caption = "Property Major Class 2 Comparison, AV ~ $10,000 (AV range $9000-$11000)") %>%
  kable_styling(full_width = T)%>%
add_header_above(c("Chicago" = 2, "Dolton" = 2))
Chi3 <- DoltonChicago %>% 
  filter(agency_num == "030210000" & propclass_1dig == "2" & between(av,8000,12000)) %>%
    summarize(              
    comp_taxrate = mean(tax_code_rate, na.rm=TRUE),
    bill_current = mean(tax_amt_post_exe, na.rm=TRUE),
    bill_hyp = mean(eav*taxrate_new, na.rm=TRUE),
    bill_change = bill_hyp - bill_current,
    tax_amt_post_exe = mean(tax_amt_post_exe),
    tax_amt_exe = mean(tax_amt_exe, na.rm=TRUE),
    tax_amt_pre_exe = mean(tax_amt_pre_exe, na.rm=TRUE),
    pin_count = n(),
    av = mean(av), 
    eav = mean(eav)
  ) %>% 
  pivot_longer(cols = comp_taxrate:eav, names_to = "Stats", values_to = "Values")

# Chicago only has 2 pins that are similar to Dolton's median pin (which had a lot of matches)
Dol3 <- DoltonChicago %>% 
  filter(agency_num == "030310000" & propclass_1dig == "2" & between(av, 8000, 12000)) %>%
    summarize(              
    comp_taxrate = mean(tax_code_rate, na.rm=TRUE),
    bill_current = mean(tax_amt_post_exe, na.rm=TRUE),
    bill_hyp = mean(eav*taxrate_new, na.rm=TRUE),
    bill_change = bill_hyp - bill_current,
    tax_amt_post_exe = mean(tax_amt_post_exe),
    tax_amt_exe = mean(tax_amt_exe, na.rm=TRUE),
    tax_amt_pre_exe = mean(tax_amt_pre_exe, na.rm=TRUE),
    pin_count = n(),
    av = mean(av), 
    eav = mean(eav)
  ) %>% 
    pivot_longer(cols = comp_taxrate:eav, names_to = "Stats", values_to = "Values")

both_dt <- cbind(Chi3, Dol3)


kbl(both_dt, booktabs = T, digits = 0, 
    caption = "Property Major Class 2 Comparison, AV ~ $10,000 (AV range $8000-$12000)") %>%
  kable_styling(full_width = T)%>%
add_header_above(c("Chicago" = 2, "Dolton" = 2))
Chi3 <- DoltonChicago %>% 
  filter(agency_num == "030210000" & class == "205" & between(av,8000,12000)) %>%
    summarize(              
    comp_taxrate = mean(tax_code_rate, na.rm=TRUE),
    bill_current = mean(tax_amt_post_exe, na.rm=TRUE),
    bill_hyp = mean(eav*taxrate_new, na.rm=TRUE),
    bill_change = bill_hyp - bill_current,
    tax_amt_post_exe = mean(tax_amt_post_exe),
    tax_amt_exe = mean(tax_amt_exe, na.rm=TRUE),
    tax_amt_pre_exe = mean(tax_amt_pre_exe, na.rm=TRUE),
    pin_count = n(),
    av = mean(av), 
    eav = mean(eav)
  ) %>% 
  pivot_longer(cols = comp_taxrate:eav, names_to = "Stats", values_to = "Values")


Dol3 <- DoltonChicago %>% 
  filter(agency_num == "030310000" & class == "205" & between(av, 8000, 12000)) %>%
    summarize(              
    comp_taxrate = mean(tax_code_rate, na.rm=TRUE),
    bill_current = mean(tax_amt_post_exe, na.rm=TRUE),
    bill_hyp = mean(eav*taxrate_new, na.rm=TRUE),
    bill_change = bill_hyp - bill_current,
    tax_amt_post_exe = mean(tax_amt_post_exe),
    tax_amt_exe = mean(tax_amt_exe, na.rm=TRUE),
    tax_amt_pre_exe = mean(tax_amt_pre_exe, na.rm=TRUE),
    pin_count = n(),
    av = mean(av), 
    eav = mean(eav)
  )  %>% 
    pivot_longer(cols = comp_taxrate:eav, names_to = "Stats", values_to = "Values")

both_dt <- cbind(Chi3, Dol3)


kbl(both_dt, booktabs = T, digits = 0, 
    caption = "Property Class 205 Comparison, AV ~ $10,000 (8000 to 12000 AV range)") %>%
  kable_styling(full_width = T)%>%
add_header_above(c("Chicago" = 2, "Dolton" = 2))
Chi3 <- DoltonChicago %>% 
  filter(agency_num == "030210000" & class == "211" & between(av,17000,19000)) %>%
    summarize(              
    comp_taxrate = mean(tax_code_rate, na.rm=TRUE),
    bill_current = mean(tax_amt_post_exe, na.rm=TRUE),
    bill_hyp = mean(eav*taxrate_new, na.rm=TRUE),
    bill_change = bill_hyp - bill_current,
    tax_amt_post_exe = mean(tax_amt_post_exe),
    tax_amt_exe = mean(tax_amt_exe, na.rm=TRUE),
    tax_amt_pre_exe = mean(tax_amt_pre_exe, na.rm=TRUE),
    pin_count = n(),
    av = mean(av), 
    eav = mean(eav)
  ) %>% 
  pivot_longer(cols = comp_taxrate:eav, names_to = "Stats", values_to = "Values")


Dol3 <- DoltonChicago %>% 
  filter(agency_num == "030310000" & class == "211" & between(av, 17000, 19000)) %>%
    summarize(              
    comp_taxrate = mean(tax_code_rate, na.rm=TRUE),
    bill_current = mean(tax_amt_post_exe, na.rm=TRUE),
    bill_hyp = mean(eav*taxrate_new, na.rm=TRUE),
    bill_change = bill_hyp - bill_current,
    tax_amt_post_exe = mean(tax_amt_post_exe),
    tax_amt_exe = mean(tax_amt_exe, na.rm=TRUE),
    tax_amt_pre_exe = mean(tax_amt_pre_exe, na.rm=TRUE),
    pin_count = n(),
    av = mean(av), 
    eav = mean(eav)
  ) %>% 
    pivot_longer(cols = comp_taxrate:eav, names_to = "Stats", values_to = "Values")

both_dt <- cbind(Chi3, Dol3)


kbl(both_dt, booktabs = T, digits = 0, 
    caption = "Property Class 211 Comparison, AV ~ $18,000") %>%
  kable_styling(full_width = T)%>%
add_header_above(c("Chicago" = 2, "Dolton" = 2))
Chi3 <- DoltonChicago %>% 
  filter(agency_num == "030210000" & class == "234" & between(av,12000,13000)) %>%
    summarize(              
    comp_taxrate = mean(tax_code_rate, na.rm=TRUE),
    bill_current = mean(tax_amt_post_exe, na.rm=TRUE),
    bill_hyp = mean(eav*taxrate_new, na.rm=TRUE),
    bill_change = bill_hyp - bill_current,
    tax_amt_post_exe = mean(tax_amt_post_exe),
    tax_amt_exe = mean(tax_amt_exe, na.rm=TRUE),
    tax_amt_pre_exe = mean(tax_amt_pre_exe, na.rm=TRUE),
    pin_count = n(),
    av = mean(av), 
    eav = mean(eav)
  ) %>% 
  pivot_longer(cols = comp_taxrate:eav, names_to = "Stats", values_to = "Values")


Dol3 <- DoltonChicago %>% 
  filter(agency_num == "030310000" & class == "234" & between(av, 12450, 12750)) %>%
    summarize(              
    comp_taxrate = mean(tax_code_rate, na.rm=TRUE),
    bill_current = mean(tax_amt_post_exe, na.rm=TRUE),
    bill_hyp = mean(eav*taxrate_new, na.rm=TRUE),
    bill_change = bill_hyp - bill_current,
    tax_amt_post_exe = mean(tax_amt_post_exe),
    tax_amt_exe = mean(tax_amt_exe, na.rm=TRUE),
    tax_amt_pre_exe = mean(tax_amt_pre_exe, na.rm=TRUE),
    pin_count = n(),
    av = mean(av), 
    eav = mean(eav)) %>% 
    pivot_longer(cols = comp_taxrate:eav, names_to = "Stats", values_to = "Values")

both_dt <- cbind(Chi3, Dol3)


kbl(both_dt, booktabs = T, digits = 0, 
    caption = "Property Class 234 Comparison, AV ~ $12,500") %>%
  kable_styling(full_width = T)%>%
add_header_above(c("Chicago" = 2, "Dolton" = 2))
# TC_bills_current has the summed taxbill information that comes from the tax_bill() command in ptaxsim
TC_bills_current <- read_csv("2_Summed_Bills_by_Taxcode_and_Class.csv") %>% 
  #filter(class == "205") %>%
  mutate(tax_code = as.character(tax_code),
         class = as.character(class))

class_dict$class_code <- as.character(class_dict$class_code)
 
#muni_tax_codes %>% select(tax_code_num, tax_code_rate, agency_num)
TC_bills_current <- left_join(TC_bills_current, muni_tax_codes,
                      by = c("tax_code" = "tax_code_num")) 

TC_bills_current <- TC_bills_current %>% left_join(muni_agency_names) %>% left_join(nicknames) %>% select(-c(shpfile_name, Column1, `Most recent reassessed`, short_name, minor_type, agency_name, agency_number))

TC_bills_current

TC_bills_current %>%  
 # left_join(muni_agency_names, by = "agency_num") %>%
 # left_join(nicknames, by = c("agency_name" = "agency_name")) %>%
  filter(!agency_num %in% cross_county_lines) %>%
 # group_by(clean_name, agency_name) %>%
  summarize(MuniLevy = round(sum(final_tax_to_dist, na.rm = TRUE), digits = 0), # amount billed by munis with current exemptions in place
            nonTIF_EAV_post_exemps = round(sum(final_tax_to_dist/(tax_code_rate/100), na.rm = TRUE), 0),
            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 = round(MuniLevy/nonTIF_EAV_post_exemps,4),
         nonTIF_EAV_pre_exemps = round(nonTIF_EAV_post_exemps + Exempt_EAV),
         taxrate_new = round(MuniLevy/nonTIF_EAV_pre_exemps,4),
         taxrate_change = round(tax_rate_current-taxrate_new, 4) )%>% 
 # select(clean_name, taxrate_change, tax_rate_current, taxrate_new, everything()) %>% 
  arrange(desc(tax_rate_current)) %>%
  pivot_longer(cols = MuniLevy:taxrate_change) %>%
  mutate(value = value)

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) 
    ) %>%
  full_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,
  na.value=NA,
                    n =6,
                       name = "Revenue Shifted \nfrom Exemptions",
         labels = scales::dollar
)+
 
  labs(title = "Dollars passed from Class 2 Residential properties to others \ndue to current exemptions",    
         caption = "There was $460 million in exempt EAV in Chicago.")

ggsave("cook_nochicago.png")
# Class 2 only
class2_perc <- exemptions_by_class_per_TC %>% 
  filter(class_code >=200 & class_code <=299) %>%
  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 <- 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%")
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")

tax_bill_change %>% 
 # filter(major_class_code == "2") %>% 
  filter(class_code >=200 & class_code <= 299) %>%
  filter(class_code != "0") %>%
   mutate(class_code = as.character(class_code)) %>%
  left_join(nicknames) %>%
  filter(Triad == "South") %>%
  summarize(cost_increasedbills = sum(bill_change, na.rm=TRUE))


TC_bills_current %>%  filter(class != "0") %>%
 summarize(cost_exemps = scales::dollar(sum(tax_amt_exe)),
                               composite_rate = mean(tax_code_rate)) 


TC_bills_current  %>% 
  filter(class != "0") %>%
  group_by(Triad) %>% 
  summarize(cost_exemps = scales::dollar(sum(tax_amt_exe)),
            composite_rate = mean(tax_code_rate)
                                                    ) 

# TC_bills_current %>% group_by(Triad) %>% 
tax_bill_change %>% ungroup() %>%
  filter(class_code == "203") %>%
   mutate(class_code = as.character(class_code)) %>%
  left_join(nicknames)


tax_bill_change %>% ungroup() %>%
  filter(class_code == "203") %>%
    filter(clean_name %in% c("Park Forest","Markham",  "Dolton", "Hillside", "Riverside", "Chicago", "Westchester", "Winnetka")) %>%
   mutate(class_code = as.character(class_code)) %>%
  left_join(nicknames)%>%
group_by(Triad, clean_name)
exemptions <- read_csv("3_Exemption_Details_output-all_cook_pin_exemptions_2021_actual.csv") 
# head(exemptions)


exemptions <- exemptions %>% 
  select(pin, av, eav_original = eav, class_code, tax_code_num, major_class_code, exe_homeowner:exe_abate) %>%
  
  mutate(exe_vet_dis = exe_vet_dis_lt50 + exe_vet_dis_50_69 + exe_vet_dis_ge70,
         total_exempt_eav = exe_homeowner + exe_senior + exe_freeze + exe_longtime_homeowner + 
           exe_disabled + exe_vet_returning + exe_vet_dis + exe_abate,
         has_homeown = ifelse(exe_homeowner > 0, 1, 0),
         has_senior = ifelse(exe_senior > 0, 1, 0),
         has_freeze = ifelse(exe_freeze > 0, 1, 0),
         
         has_seniorexemps = ifelse(exe_senior > 0 & exe_freeze > 0, 1, 0),
         has_disability = ifelse(exe_disabled > 0, 1, 0),
         has_vetreturn = ifelse(exe_vet_returning > 0, 1, 0), 
         
         has_any_exemps = ifelse(total_exempt_eav > 0, 1, 0),
         has_multi_exemps = ifelse(has_senior + has_freeze + has_homeown + has_disability + has_vetreturn > 1, 1, 0)) %>% 
  
  mutate(tax_code_num = as.character(tax_code_num))%>%
  left_join(muni_tax_codes) %>% 
  left_join(muni_agency_names) %>% 
  left_join(nicknames)

# head(exemptions)

#table(exemptions$has_any_exemps)
#table(exemptions$has_seniorexemps)
#table(exemptions$has_multi_exemps)

has_exemptions_pins <-  exemptions %>% 
  filter(has_any_exemps == 1)

# head(has_exemptions_pins)

has_exemptions_pins %>% 
  summarize(
    av = sum(av, na.rm = TRUE),
    EAV_beforeExemptsOrTIF=sum(eav_original, na.rm=TRUE),
    total_exempt_eav = sum(exe_homeowner + exe_senior + exe_freeze + exe_longtime_homeowner + 
                             exe_disabled + exe_vet_returning + exe_vet_dis + exe_abate, na.rm=TRUE),
    homeowners_exemption = sum(exe_homeowner),
    senior_exemption = sum(exe_senior, na.rm=TRUE),
    freeze_exemption = sum(exe_freeze, na.rm=TRUE),
    other_exemptions = sum(exe_vet_dis + exe_disabled + exe_longtime_homeowner + exe_vet_returning + exe_abate))  


muni_exempt_eav <- has_exemptions_pins %>% 
  group_by(clean_name, agency_num) %>%
  summarize(
    av_hasexemps = sum(av, na.rm = TRUE),
    eav_original_hasexemps=sum(eav_original, na.rm=TRUE),
    total_exempt_eav = sum(exe_homeowner + exe_senior + exe_freeze + exe_longtime_homeowner + 
                             exe_disabled + exe_vet_returning + exe_vet_dis + exe_abate, na.rm=TRUE),
    homeowners_exemption = sum(exe_homeowner),
    senior_exemption = sum(exe_senior, na.rm=TRUE),
    freeze_exemption = sum(exe_freeze, na.rm=TRUE),
    other_exemptions = sum(exe_vet_dis + exe_disabled + exe_longtime_homeowner + exe_vet_returning + exe_abate), 
    #pin_count_hasexemptions = n(),
    PC_has_exe = n() # has at least one exemption associated with the pin
    ) 


# muni_exempt_eav %>% select(-agency_num)

muni_C2_has_exe_eav <- has_exemptions_pins %>%
  group_by(clean_name, agency_num) %>%
  filter(major_class_code == "2") %>%
  summarize(
    av_hasexemps = sum(av, na.rm = TRUE),
    eav_original_hasexemps=sum(eav_original, na.rm=TRUE),
    total_exempt_eav = sum(exe_homeowner + exe_senior + exe_freeze + exe_longtime_homeowner +
                             exe_disabled + exe_vet_returning + exe_vet_dis + exe_abate, na.rm=TRUE),
    homeowners_exemption = sum(exe_homeowner),
    senior_exemption = sum(exe_senior, na.rm=TRUE),
    freeze_exemption = sum(exe_freeze, na.rm=TRUE),
    other_exemptions = sum(exe_vet_dis + exe_disabled + exe_longtime_homeowner + exe_vet_returning + exe_abate),
    PC_C2_has_exe = n()
    )


muni_singfamres_has_homeowners_exemps <- has_exemptions_pins %>% 
  filter(class_code > 199 & class_code < 211) %>%
  filter(exe_homeowner > 0) %>%
  group_by(clean_name, agency_num) %>%
  summarize(
    av_singfam_has_homeownexemps = sum(av, na.rm = TRUE),
    eav_original_sing_fam_has_homeownexemps=sum(eav_original, na.rm=TRUE),
    total_exempt_eav_singfam_has_homeown = sum(exe_homeowner + exe_senior + exe_freeze + exe_longtime_homeowner + exe_disabled + exe_vet_returning + exe_vet_dis + exe_abate, na.rm=TRUE),
    homeowners_exemption_singfam = sum(exe_homeowner),
    #pin_count_singfam_has_homeownerexemptions = n(),
    PC_SF_has_HOexe = n() # has Homeowner exemption and is within Class range specified
  ) 

munitotals <- exemptions %>%
  filter(tax_code_num %in% muni_tax_codes$tax_code_num)%>%
  group_by(clean_name, agency_num) %>%
  summarize(muni_av = sum(av, na.rm = TRUE),
            muni_eav_original=sum(eav_original, na.rm=TRUE),
            total_exempt_eav = sum(exe_homeowner + exe_senior + exe_freeze + exe_longtime_homeowner + 
                                     exe_disabled + exe_vet_returning + exe_vet_dis + exe_abate, na.rm=TRUE),
            homeowners_exemption = sum(exe_homeowner),
            senior_exemption = sum(exe_senior, na.rm=TRUE),
            freeze_exemption = sum(exe_freeze, na.rm=TRUE),
            PC_allPINs_muni = n() # number of pins within each municipality
            ) 

# munitotals %>% select(-agency_num)


muni_residentialtotals <- exemptions %>%
  filter(tax_code_num %in% muni_tax_codes$tax_code_num)%>%
  filter(major_class_code == "2") %>% 
  group_by(clean_name, agency_num) %>%
  summarize(muni_residential_av = sum(av, na.rm = TRUE),
            muni_residential_eav_original=sum(eav_original, na.rm=TRUE),
            total_residential_exempt_eav = sum(exe_homeowner + exe_senior + exe_freeze + exe_longtime_homeowner + 
                                                 exe_disabled + exe_vet_returning + exe_vet_dis + exe_abate, na.rm=TRUE),
            PC_C2_muni = n() # number of PINs that are Class 2 Residential 
            ) 

#muni_residentialtotals %>% select(-agency_num)


# Should I add the other "single family" property classes??  ## 
muni_singfam_residentialtotals <- exemptions %>%
  filter(tax_code_num %in% muni_tax_codes$tax_code_num)%>%
  filter(class_code > 199 & class_code < 211) %>% 
  group_by(clean_name, agency_num) %>%
  summarize(muni_singfam_residential_av = sum(av, na.rm = TRUE),
            muni_singfam_residential_eav_original=sum(eav_original, na.rm=TRUE),
           # total "single-family" residential exempt eav
            SF_res_exe_EAV_muni = sum(exe_homeowner + exe_senior + exe_freeze + exe_longtime_homeowner + 
                                      exe_disabled + exe_vet_returning + exe_vet_dis + exe_abate, na.rm=TRUE),
            PC_SF_Res = n() 
           ) 

#muni_singfam_residentialtotals %>% select(-agency_num)

merged <- munitotals %>% 
  select(clean_name, agency_num, muni_av, muni_eav_original, PC_allPINs_muni) %>% 
  left_join(muni_exempt_eav) %>% 
  left_join(muni_residentialtotals) %>%
  left_join(muni_singfam_residentialtotals) %>%
  left_join(muni_C2_has_exe_eav) %>%
  left_join(muni_singfamres_has_homeowners_exemps) %>%
  mutate(pct_ofSF_pins_w_HOexe = PC_SF_has_HOexe / PC_SF_Res,
        # pct_SF_pins_w_exemps = pin_count_has_homeownerexemptions / pin_count_singfam_residential,
        # pct_pins_w_exemps = pin_count_hasexemptions / pin_count,
        pct_ofallpins_w_exe = PC_has_exe / PC_allPINs_muni, #       pins with exemptions / all pins in a muni

         pct_C2_w_exemps = PC_C2_has_exe / PC_C2_muni, # 
         #pct_singfam_pins_w_exemps = pin_count_hasexemptions / pin_count_singfam_residential,
      #   pct_singfam_pins_w_exemps = pin_count_has_homeownerexemptions / pin_count_singfam_residential
    ) %>%
  
  select(clean_name, pct_ofSF_pins_w_HOexe, pct_ofallpins_w_exe, pct_C2_w_exemps, 
         PC_has_exe, PC_C2_muni, PC_allPINs_muni, everything())

merged
TC_bills_current <- read_csv("2_Summed_Bills_by_Taxcode_and_Class.csv") %>% 
  mutate(tax_code = as.character(tax_code),
         class = as.character(class))

class_dict$class_code <- as.character(class_dict$class_code)
 

taxcodes_current <- left_join(TC_bills_current, muni_tax_codes, 
                      by = c("tax_code" = "tax_code_num")) 

MuniLevy <- taxcodes_current %>% 
  left_join(muni_agency_names, by = "agency_num") %>%
  left_join(nicknames, by = c("agency_name" = "agency_name")) %>%
  #filter(!agency_num %in% cross_county_lines) %>%
  group_by(clean_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))


merged <- merged %>% left_join(MuniLevy)
scenario_taxrates <- merged %>% 
  mutate(scenario1_taxable_eav = Total_EAV - TIF_increment_EAV - Exempt_EAV + homeowners_exemption,
         scenario2_taxable_eav = Total_EAV - TIF_increment_EAV - Exempt_EAV + (senior_exemption + freeze_exemption ),
                  scenario_noexemptions_taxable_eav = Total_EAV - Exempt_EAV) %>%
  mutate(taxrate_scen1 = MuniLevy / scenario1_taxable_eav,
         taxrate_scen2 = MuniLevy / scenario2_taxable_eav,
         tax_rate_current = MuniLevy/nonTIF_EAV_post_exemps,
         taxrate_noexemps = MuniLevy /(Total_EAV - TIF_increment_EAV  ),
         taxrate_noTIFs = MuniLevy / (Total_EAV - Exempt_EAV),
         taxrate_noTIFs_orExemps = MuniLevy / Total_EAV)  %>%
  select(clean_name, MuniLevy, taxrate_scen1, taxrate_scen2, tax_rate_current, taxrate_noexemps, taxrate_noTIFs, taxrate_noTIFs_orExemps, scenario1_taxable_eav, scenario2_taxable_eav)

scenario_taxrates


merged %>% 
  filter(clean_name %in% c("Park Forest","Markham",  "Dolton", "Hillside", "Riverside", "Chicago", "Westchester", "Winnetka", "Rosemont")) %>%
  mutate(scenario1_taxable_eav = Total_EAV - TIF_increment_EAV - Exempt_EAV + homeowners_exemption,
         scenario2_taxable_eav = Total_EAV - TIF_increment_EAV - Exempt_EAV + (senior_exemption + freeze_exemption ),
         scenario_noexemptions_taxable_eav = Total_EAV - Exempt_EAV) %>%
  mutate(taxrate_scen1 = MuniLevy / scenario1_taxable_eav,
         taxrate_scen2 = MuniLevy / scenario2_taxable_eav,
         tax_rate_current = MuniLevy/nonTIF_EAV_post_exemps,
         taxrate_noexemps = MuniLevy /(Total_EAV - TIF_increment_EAV  ),
         taxrate_noTIFs = MuniLevy / (Total_EAV - Exempt_EAV),
         taxrate_noTIFs_orExemps = MuniLevy / Total_EAV)  %>%
  select(clean_name, MuniLevy, taxrate_scen1, taxrate_scen2, tax_rate_current, taxrate_noexemps, scenario1_taxable_eav, scenario2_taxable_eav, scenario_noexemptions_taxable_eav, Total_EAV, taxrate_noTIFs, taxrate_noTIFs_orExemps)

Class2_EAV_scenarios <- exemptions %>% 
  filter(class_code >= 200 & class_code <= 300) %>% 
  filter(tax_code_num %in% muni_tax_codes$tax_code_num)%>%
  group_by(clean_name) %>%
  summarize(Class2_av = sum(av, na.rm = TRUE),
            Class2_eav_original=sum(eav_original, na.rm=TRUE),
            Class2_total_exempt_eav = sum(exe_homeowner + exe_senior + exe_freeze + exe_longtime_homeowner + 
                                     exe_disabled + exe_vet_returning + exe_vet_dis + exe_abate, na.rm=TRUE),
            Class2_homeowners_exemption = sum(exe_homeowner),
            Class2_senior_exemption = sum(exe_senior, na.rm=TRUE),
            Class2_freeze_exemption = sum(exe_freeze, na.rm=TRUE),
            Class2_PC_permuni = n() # number of pins within each municipality
            ) 
Class2_EAV_scenarios


Class2_TIF_EAV <-  taxcodes_current %>% 
  filter(class >=200 & class <=300) %>%
  left_join(muni_agency_names, by = "agency_num") %>%
  left_join(nicknames, by = c("agency_name" = "agency_name")) %>%
  filter(!agency_num %in% cross_county_lines) %>%
  group_by(clean_name) %>%
  summarize(Class2_DistrictRev = sum(final_tax_to_dist, na.rm = TRUE), # amount billed by munis with current exemptions in place
            Class2_nonTIF_EAV_post_exemps = sum(final_tax_to_dist/(tax_code_rate/100), na.rm = TRUE),
            Class2_TIF_increment_EAV = sum(final_tax_to_tif/(tax_code_rate/100), na.rm=TRUE),  
            Class2_Exempt_EAV = sum(tax_amt_exe/(tax_code_rate/100), na.rm=TRUE), 
            Class2_Total_EAV = sum((tax_amt_exe+final_tax_to_dist+final_tax_to_tif)/(tax_code_rate/100), na.rm = TRUE))

Class2_TIF_EAV


Class2_merged <- Class2_TIF_EAV %>% 
  left_join(Class2_EAV_scenarios) %>%
  left_join(MuniLevy)


Class2_Scenario_burdenshift <- Class2_merged %>% 
  left_join(scenario_taxrates) %>%
  mutate(Class2_scenario1_taxable_eav = Class2_Total_EAV - Class2_TIF_increment_EAV - Exempt_EAV +  Class2_homeowners_exemption,
        Class2_scenario2_taxable_eav = Class2_Total_EAV - Class2_TIF_increment_EAV - Exempt_EAV +  (Class2_senior_exemption + Class2_freeze_exemption )) %>%
  
  mutate(burden_C2_scen1 = (Class2_scenario1_taxable_eav * taxrate_scen1)/ MuniLevy,
         burden_C2_scen2 = (Class2_scenario2_taxable_eav * taxrate_scen2) / MuniLevy,
         burden_C2_current = Class2_nonTIF_EAV_post_exemps * tax_rate_current/ MuniLevy,
         burden_C2_noexemps = ( (Class2_Total_EAV - Class2_TIF_increment_EAV)*taxrate_noexemps ) / MuniLevy,
         burden_C2_noTIF_orExemps = (Class2_Total_EAV * taxrate_noTIFs_orExemps ) / MuniLevy,
         burden_C2_noTIFs =  ((Class2_Total_EAV - Class2_Exempt_EAV) * taxrate_noTIFs ) / MuniLevy) #  %>%
 # select(clean_name, MuniLevy, taxrate_scen1, taxrate_scen2, tax_rate_current, taxrate_noexemps, scenario1_taxable_eav, scenario2_taxable_eav)

Class2_Scenario_burdenshift %>% 
  select(clean_name, burden_C2_scen1:burden_C2_noTIFs)  %>% 
  filter(clean_name %in% c("Park Forest","Markham",  "Dolton", "Hillside", "Riverside", "Chicago", "Westchester", "Winnetka", "Rosemont"))
library(openxlsx)

dataset_names <- list('Cook County Totals' = total_exemptions,
                      'Incorp Exemp Totals' = muni_totals,
                      'Muni Level Exemp Tot' = exemptype_totals_permuni,
                      'EAV in and out of TIF' = tif_table,
                      'Percent Residential' = perc_residential,
                      'Tax Base by Class' = grouped_exemptions,
                      'CurrentandHyp Tax Burden'= munis_3property_types,
                      'Burden Shift, 3 PropClasses' = props_wide,
                      'Full Burden Shift Table'= burden_shift, # has essentially all variables used to make the smaller, more specific tables
                      'Exemps by Class, All Tax Codes' = exemptions_by_class_per_TC,
                      'Exempt Residential EAV' = exemptions_to_class2EAV_ratios,
                      'Tax Code Tax Rates'= taxcodes_current,
                  #    'Tax Bill Change, All PropClass' = tax_bill_change, # uses the actual median value for the statistic. Not my favorite way to calculate this statistic
                    #  'Tax Bill Change, 3 MajorClasses' = bill_change_3groups, # uses the actual median value for the statistic. Not my favorite way to calculate this statistic

                      'Muni TaxCodeXClass Bill Sums' = TC_bills_current, # uses the actual median value for the statistic. Not my favorite way to calculate this statistic
                      'Composite tax rates' = Current_Taxrates
)

write.xlsx(dataset_names, file = 'UIC_CMAP_exemptionWhitepaper.xlsx')
LS0tDQp0aXRsZTogIlVJQy1DTUFQIFByb3BlcnR5IFRheCBFeGVtcHRpb25zIFJlcG9ydCINCmF1dGhvcjogIkFsZWEgV2lsYnVyIg0KZGF0ZTogImByIFN5cy5EYXRlKClgIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0OiB5ZXMNCiAgICBkZl9wcmludDogcGFnZWQNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQotLS0NCg0KKipSZXBsaWNhdGlvbiBTdGVwczogR2V0IFBpbiBhbmQgVGF4IEJpbGwgRGF0YSoqDQoNCjEuICBSdW4gZmlsZSBgMV9HZXRfQWxsX1Bpbl9CaWxscy5SbWRgIHRvIHJlcGxpY2F0ZSBwdWxsaW5nIHRoZSAyMDIxIGJpbGxzLg0KMi4gIFJ1biBmaWxlIGAyXy4uLi5SbWRgIHRvIGdldCBzdW1tZWQgdmFsdWVzIHRvIHZhcmlvdXMgbGV2ZWxzIG9mIGFuYWx5c2lzIChwYXJjZWwsIHRheGNvZGUtLWNsYXNzLCB0YXhjb2RlLS1tYWpvcmNsYXNzLCBldGMuKS4gVGhpcyBmaWxlIGFsc28gY3JlYXRlcyB0aGUgY3VycmVudCBjb21wb3NpdGUgdGF4IHJhdGVzIGZvciBlYWNoIHRheCBjb2RlLg0KMy4gIFJ1biBmaWxlIGAzX0V4ZW1wdGlvbl9EZXRhaWxzLnJtZGAgdG8gcHVsbCBhbGwgZXhlbXB0aW9uIChhbmQgYW1vdW50IHBlciB0eXBlIG9mIGV4ZW1wdGlvbikgZm9yIGV2ZXJ5IHBpbiBpbiBDb29rIENvdW50eS4NCiAgICAtICAgVXNpbmcgdGhlIHBpbiBkYXRhIGZyb20gcHRheHNpbSwgSSBjYWxjdWxhdGUgdGhlIGVhdiBvZiBhbGwgcHJvcGVydGllcywgZXhlbXB0IEVBViwgdGhlIGN1cnJlbnQgdGF4IGJhc2UsIGFuZCB0YXggYmFzZSBpZiB0aGVyZSB3ZXJlIG5vdCBleGVtcHRpb25zDQogICAgICAgIC0gICBleGVtcHQgRUFWIChzdW1tZWQgZnJvbSBhbGwgZXhlbXB0aW9uIHR5cGVzKQ0KDQogICAgICAgIC0gICBjdXJyZW50IHRheGJhc2UgKHVzaW5nIHRoZSBgdGlmX2Rpc3RyaWJgIHRhYmxlIGFuZCBwZXJjZW50IG9mIHRheGNvZGUgcmV2IHRoYXQgZ29lcyB0byB0aGUgdGlmKS4gSWYgYSB0YXhjb2RlIGlzIGEgVElGIHRheGNvZGUsIHRoZW4gZG8gKEVBVi1leGVtcHQgRUFWKSBcKiAoMS0lcmV2IHRoYXQgZ29lcyB0byBUSUYpLiBJZiB0aGUgdGF4IGNvZGUgaXMgbm90IGEgVElGIHRheCBjb2RlLCB0aGVuIHVzZSB0aGUgRUFWLWV4ZW1wdCBFQVYuDQoNCiAgICAgICAgLSAgIHRheCBiYXNlIHdpdGhvdXQgZXhlbXB0aW9uczogSWYgYSB0YXhjb2RlIGlzIGEgVElGIHRheGNvZGUsIHRoZW4gZG8gRUFWIFwqICgxLSVyZXYgdGhhdCBnb2VzIHRvIFRJRikuIElmIHRoZSB0YXggY29kZSBpcyBub3QgYSBUSUYgdGF4IGNvZGUsIHRoZW4gdXNlIHRoZSBlYXYNCjQuICBSdW4gZmlsZSBgNF9UYXhiaWxsX0h5cG90aGV0aWNhbHMucm1kYCB0byAuLi4uDQoNCk5lY2Vzc2FyeSBmaWxlcyBmb3IgcmVwbGljYXRpb24gY29kZSBpbmNsdWRlOg0KDQotICAgYSBwcm9wZXJ0eSBjbGFzcyB0YWJsZSB3aXRoIG1ham9yIHByb3BlcnR5IGNsYXNzZXMgYW5kIG90aGVyIHByb3BlcnR5IGNsYXNzIHZhcmlhYmxlcy4gW0Rvd25sb2FkIGZyb20gR2l0aHViIGhlcmVdKGh0dHBzOi8vZ2l0aHViLmNvbS9BbGVhV00vQ29va0NvdW50eS1Qcm9wZXJ0eVRheGVzL2Jsb2IvbWFpbi9jbGFzc19kaWN0X2V4cGFuZGVkLmNzdikNCi0gICBmaWxlIG9mIE11bmljaXBhbGl0eSBuYW1lcyBmb3JtYXR0ZWQgaW4gdmFyaW91cyB3YXlzIChhbGwgY2Fwcywgc2VudGVuY2UgY2FzZSwgc2hvcnRlbmVkLCBldGMuKSB0byBtYXRjaCBkaWZmZXJlbnQgZmlsZXMgd2hlbiBqb2luaW5nLiBbRG93bmxvYWQgZnJvbSBHaXRodWIgaGVyZV0oaHR0cHM6Ly9naXRodWIuY29tL0FsZWFXTS9Db29rQ291bnR5LVByb3BlcnR5VGF4ZXMvYmxvYi9tYWluL2NsYXNzX2RpY3RfZXhwYW5kZWQuY3N2KS4NCg0KYGBge3Igc2V0dXAsIGVjaG8gPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFKQ0KDQoNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShEQkkpDQpsaWJyYXJ5KGRhdGEudGFibGUpDQpsaWJyYXJ5KGdnc3BhdGlhbCkNCmxpYnJhcnkoZ3N0YXQpDQpsaWJyYXJ5KGhlcmUpDQpsaWJyYXJ5KGh0dHIpDQpsaWJyYXJ5KGpzb25saXRlKQ0KbGlicmFyeShwdGF4c2ltKQ0KbGlicmFyeShzZikNCmxpYnJhcnkoc3RhcnMpDQpsaWJyYXJ5KGdsdWUpDQpsaWJyYXJ5KGdncGF0dGVybikNCg0KIyBDcmVhdGUgdGhlIERCIGNvbm5lY3Rpb24gd2l0aCB0aGUgZGVmYXVsdCBuYW1lIGV4cGVjdGVkIGJ5IFBUQVhTSU0gZnVuY3Rpb25zDQpwdGF4c2ltX2RiX2Nvbm4gPC0gREJJOjpkYkNvbm5lY3QoUlNRTGl0ZTo6U1FMaXRlKCksICIuL3B0YXhzaW0uZGIvcHRheHNpbS0yMDIxLjAuNC5kYiIpDQoNCg0Kb3B0aW9ucyhkaWdpdHM9NCwgc2NpcGVuID0gOTk5KQ0KDQpsaWJyYXJ5KHNmKQ0KbGlicmFyeShqc29ubGl0ZSkNCmxpYnJhcnkoaHR0cikNCmxpYnJhcnkoTmF0UGFya3NQYWxldHRlcykNCg0KIyBsaW5rIHRvIHRoZSBBUEkgb3V0cHV0IGFzIGEgSlNPTiBmaWxlDQptdW5pX3NocCA8LSByZWFkX3NmKCJodHRwczovL2dpcy5jb29rY291bnR5aWwuZ292L3RyYWRpdGlvbmFsL3Jlc3Qvc2VydmljZXMvcG9saXRpY2FsQm91bmRhcnkvTWFwU2VydmVyLzIvcXVlcnk/b3V0RmllbGRzPSomd2hlcmU9MSUzRDEmZj1nZW9qc29uIikNCg0KY29va19zaHAgPC0gcmVhZF9zZigiaHR0cHM6Ly9naXMuY29va2NvdW50eWlsLmdvdi90cmFkaXRpb25hbC9yZXN0L3NlcnZpY2VzL3Bsc3MvTWFwU2VydmVyLzEvcXVlcnk/b3V0RmllbGRzPSomd2hlcmU9MSUzRDEmZj1nZW9qc29uIikNCg0KDQoNCiNtdW5pX3NocCA8LSByZWFkX2pzb24oIm11bmlfc2hwLmpzb24iKQ0Kbmlja25hbWVzIDwtIHJlYWR4bDo6cmVhZF9leGNlbCgibXVuaV9zaG9ydG5hbWVzLnhsc3giKQ0KDQpjbGFzc19kaWN0IDwtIHJlYWRfY3N2KCJjbGFzc19kaWN0X2V4cGFuZGVkLmNzdiIpICU+JSANCiAgbXV0YXRlKGNsYXNzX2NvZGUgPSBhcy5jaGFyYWN0ZXIoY2xhc3NfY29kZSkpDQoNCg0KY3Jvc3NfY291bnR5X2xpbmVzIDwtIGMoIjAzMDQ0MDAwMCIsICIwMzA1ODUwMDAiLCAiMDMwODkwMDAwIiwgIjAzMDMyMDAwMCIsICIwMzEyODAwMDAiLCIwMzAwODAwMDAiLCAiMDMwNTYwMDAwIiwgIjAzMTEyMDAwMCIsICIwMzAyODAwMDAiLCAiMDMwMzQwMDAwIiwiMDMwMTUwMDAwIiwiMDMwMDUwMDAwIiwgIjAzMDE4MDAwMCIsIjAzMDUwMDAwMCIsIjAzMTIxMDAwMCIpDQpgYGANCg0KYGBge3IgZWNobz1GQUxTRX0NCg0KDQoNCiMgYGFnZW5jeV9kdGAgaGFzIGFsbCB0YXhpbmcgYWdlbmNpZXMgKGJ1dCBub3QgVElGcykgdGhhdCBleGlzdGVkIGVhY2ggeWVhciBhbmQgaW5jbHVkZXMgdGhlaXIgdG90YWwgdGF4YWJsZSBiYXNlIChjdHlfY29va19lYXYpLCB0aGVpciBsZXZ5LCB0YXhpbmcgcmF0ZSwgYmluYXJ5IHZhcmlhYmxlcyBmb3IgaWYgYSBtdW5pY2lwYWxpdHkgaXMgaG9tZSBydWxlIG9yIG5vdCwgYXMgd2VsbCBhcyBtYW55IG90aGVyIHZhcmlhYmxlcy4gdGF4X2JpbGwoKSB1c2VzIHRoaXMgdGFibGUgZm9yIHRoZSB0YXhhYmxlIEVBViB0aGF0IGlzIHVzZWQgdG8gIGNhbGN1bGF0ZSB0aGUgdGF4IHJhdGVzIGluIHRoZSB0YXggYmlsbHMuIEZvciBzaW11bGF0aW9ucywgeW91IG11c3QgYWx0ZXIgdGhlIHRheGFibGUgRUFWIG9yIGxldnkgb3Igb3RoZXIgdmFyaWFibGVzIGFuZCB0aGVuIHRlbGwgdGF4X2JpbGwoKSBmdW5jdGlvbiB0byB1c2UgdGhlIG1vZGlmaWVkIGFnZW5jeSBkYXRhIHRhYmxlIGZvciBzaW11bGF0ZWQgdGF4IGJpbGxzLg0KIyANCg0KDQoNCiMgaGFzIEVBViB2YWx1ZXMsIGV4dGVuc2lvbnMgYnkgYWdlbmN5X251bQ0KYWdlbmN5X2R0IDwtIERCSTo6ZGJHZXRRdWVyeSgNCiAgcHRheHNpbV9kYl9jb25uLA0KICAiU0VMRUNUICoNCiAgRlJPTSBhZ2VuY3kNCiAgV0hFUkUgeWVhciA9IDIwMjENCiAgIg0KKQ0KDQoNCmNvb2tfYWdlbmN5X25hbWVzIDwtIERCSTo6ZGJHZXRRdWVyeSgNCiAgcHRheHNpbV9kYl9jb25uLA0KICAiU0VMRUNUIERJU1RJTkNUIGFnZW5jeV9udW0sIGFnZW5jeV9uYW1lDQogIEZST00gYWdlbmN5X2luZm8NCiAgIg0KKQ0KDQogDQoNCg0KIyBoYXMgYWxsIHRheCBjb2RlcyBhbmQgdGhlIHRheGluZyBhZ2VuY3kgdGhhdCB0YXhlcyB0aGVtLiBUYXggY29kZSByYXRlcyBhbmQgYWdlbmN5IHJhdGVzLiANCmNvb2tfdGF4X2NvZGVzIDwtIERCSTo6ZGJHZXRRdWVyeSgNCiAgcHRheHNpbV9kYl9jb25uLA0KICBnbHVlX3NxbCgiDQogIFNFTEVDVCoNCiAgRlJPTSB0YXhfY29kZQ0KICBXSEVSRSBhZ2VuY3lfbnVtIElOICh7Y29va19hZ2VuY3lfbmFtZXMkYWdlbmN5X251bSp9KQ0KICBBTkQgeWVhciA9IDIwMjENCiAgIiwNCiAgLmNvbiA9IHB0YXhzaW1fZGJfY29ubg0KICApDQopDQoNCg0KbXVuaV9hZ2VuY3lfbmFtZXMgPC0gREJJOjpkYkdldFF1ZXJ5KA0KICBwdGF4c2ltX2RiX2Nvbm4sDQogICJTRUxFQ1QgRElTVElOQ1QgYWdlbmN5X251bSwgYWdlbmN5X25hbWUsIG1pbm9yX3R5cGUNCiAgRlJPTSBhZ2VuY3lfaW5mbw0KICBXSEVSRSBtaW5vcl90eXBlID0gJ01VTkknDQogIE9SIGFnZW5jeV9udW0gPSAnMDIwMDYwMDAwJyAgDQoNCiAgIg0KKQ0KDQptdW5pX3RheF9jb2RlcyA8LSBEQkk6OmRiR2V0UXVlcnkoDQogIHB0YXhzaW1fZGJfY29ubiwNCiAgZ2x1ZV9zcWwoIg0KICBTRUxFQ1QqDQogIEZST00gdGF4X2NvZGUNCiAgV0hFUkUgYWdlbmN5X251bSBJTiAoe211bmlfYWdlbmN5X25hbWVzJGFnZW5jeV9udW0qfSkNCiAgQU5EIHllYXIgPSAyMDIxDQogICIsDQogIC5jb24gPSBwdGF4c2ltX2RiX2Nvbm4NCiAgKQ0KKSAgDQogIA0KDQojIEFnZW5jeSBudW1iZXIgYW5kIGFnZW5jeSBuYW1lIGZvciBhbGwgVElGcw0KVElGX2FnZW5jaWVzIDwtIERCSTo6ZGJHZXRRdWVyeSgNCiAgcHRheHNpbV9kYl9jb25uLA0KICAiU0VMRUNUIERJU1RJTkNUIGFnZW5jeV9udW0sIGFnZW5jeV9uYW1lLCBtYWpvcl90eXBlLCBtaW5vcl90eXBlDQogIEZST00gYWdlbmN5X2luZm8NCiAgV0hFUkUgbWlub3JfdHlwZSA9ICdUSUYnDQogICINCikNCg0KdW5pcXVlX3RpZl90YXhjb2RlcyA8LSBEQkk6OmRiR2V0UXVlcnkoDQogIHB0YXhzaW1fZGJfY29ubiwgDQogIGdsdWVfc3FsKCINCiAgU0VMRUNUIERJU1RJTkNUIHRheF9jb2RlX251bQ0KICBGUk9NIHRheF9jb2RlDQogIFdIRVJFIGFnZW5jeV9udW0gSU4gKHtUSUZfYWdlbmNpZXMkYWdlbmN5X251bSp9KQ0KICBBTkQgeWVhciA9IDIwMjENCiAgIiwNCiAgLmNvbiA9IHB0YXhzaW1fZGJfY29ubg0KICApDQopDQoNCg0KdGlmX2Rpc3RyaWIgPC0gREJJOjpkYkdldFF1ZXJ5KA0KICBwdGF4c2ltX2RiX2Nvbm4sIA0KICBnbHVlX3NxbCgiDQogIFNFTEVDVCAqDQogIEZST00gdGlmX2Rpc3RyaWJ1dGlvbg0KICBXSEVSRSB0YXhfY29kZV9udW0gSU4gKHtjb29rX3RheF9jb2RlcyR0YXhfY29kZV9udW0qfSkNCiAgQU5EIHllYXIgPSAyMDIxDQogICIsDQogIC5jb24gPSBwdGF4c2ltX2RiX2Nvbm4NCiAgKQ0KKSAlPiUgbXV0YXRlKHRheF9jb2RlX251bSA9IGFzLmNoYXJhY3Rlcih0YXhfY29kZV9udW0pKQ0KDQoNCmBgYA0KDQpUaGVyZSBhcmUgMSw4NjQsNTk0IHBpbnMgaW4gQ29vayBDb3VudHkgaW4gMjAyMS4gVGhlcmUgYXJlIDEsODI1LDgxNiBpbiBpbmNvcnBvcmF0ZWQgYXJlYXMgd2l0aGluIENvb2sgQ291bnR5IChyZWZlcnJlZCB0byBhcyAiTXVuaWNpcGFsaXRpZXMiIGluIHRoaXMgZG9jdW1lbnQpLg0KDQoNCiMgRXhlbXB0aW9ucyBwZXIgUHJvcGVydHkgQ2xhc3MgaW4gTXVuaWNpcGFsaXRpZXMNCg0KYGBge3IgY29va3RvdGFscywgZWNobz1GQUxTRX0NCmV4ZW1wdGlvbnNfYnlfY2xhc3NfcGVyX1RDIDwtIHJlYWRfY3N2KCIzX0V4ZW1wdGlvbl9EZXRhaWxzX291dHB1dC1Db29rX0V4ZW1wc19ieUNsYXNzYW5kVGF4Y29kZS5jc3YiKSANCg0KDQpjb29rdG90YWxzIDwtIGV4ZW1wdGlvbnNfYnlfY2xhc3NfcGVyX1RDICU+JSANCiAgc3VtbWFyaXplKGF2ID0gc3VtKGF2LCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgZWF2PXN1bShlYXYsIG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgdG90YWxfZXhlbXB0X2VhdiA9IHN1bShleGVfaG9tZW93bmVyICsgZXhlX3NlbmlvciArIGV4ZV9mcmVlemUgKyBleGVfbG9uZ3RpbWVfaG9tZW93bmVyICsgDQogICAgICAgICAgICAgICAgICAgICAgICAgZXhlX2Rpc2FibGVkICsgZXhlX3ZldF9yZXR1cm5pbmcgKyBleGVfdmV0X2RpcyArIGV4ZV9hYmF0ZSwgbmEucm09VFJVRSksDQogICAgICAgICAgICBob21lb3duZXJzX2V4ZW1wdGlvbiA9IHN1bShleGVfaG9tZW93bmVyKSwNCiAgICAgICAgICAgIHNlbmlvcl9leGVtcHRpb24gPSBzdW0oZXhlX3NlbmlvciwgbmEucm09VFJVRSksDQogICAgICAgICAgICBmcmVlemVfZXhlbXB0aW9uID0gc3VtKGV4ZV9mcmVlemUsIG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgICAgICAgICAgICAgcGluX2NvdW50ID0gbigpKSAlPiUNCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBhdjpwaW5fY291bnQsIG5hbWVzX3RvID0gIlZhcmlhYmxlcyIsIHZhbHVlc190byA9ICJDb29rIENvdW50eSBUb3RhbHMiKQ0KDQptdW5pdG90YWxzIDwtIGV4ZW1wdGlvbnNfYnlfY2xhc3NfcGVyX1RDICU+JSANCiAgZmlsdGVyKHRheF9jb2RlX251bSAlaW4lIG11bmlfdGF4X2NvZGVzJHRheF9jb2RlX251bSklPiUNCiAgc3VtbWFyaXplKGF2ID0gc3VtKGF2LCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgZWF2PXN1bShlYXYsIG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgdG90YWxfZXhlbXB0X2VhdiA9IHN1bShleGVfaG9tZW93bmVyICsgZXhlX3NlbmlvciArIGV4ZV9mcmVlemUgKyBleGVfbG9uZ3RpbWVfaG9tZW93bmVyICsgDQogICAgICAgICAgICAgICAgICAgICAgICAgZXhlX2Rpc2FibGVkICsgZXhlX3ZldF9yZXR1cm5pbmcgKyBleGVfdmV0X2RpcyArIGV4ZV9hYmF0ZSwgbmEucm09VFJVRSksDQogICAgICAgICAgICBob21lb3duZXJzX2V4ZW1wdGlvbiA9IHN1bShleGVfaG9tZW93bmVyKSwNCiAgICAgICAgICAgIHNlbmlvcl9leGVtcHRpb24gPSBzdW0oZXhlX3NlbmlvciwgbmEucm09VFJVRSksDQogICAgICAgICAgICBmcmVlemVfZXhlbXB0aW9uID0gc3VtKGV4ZV9mcmVlemUsIG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgICAgICAgICAgICAgcGluX2NvdW50ID0gbigpKSAlPiUNCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBhdjpwaW5fY291bnQsIG5hbWVzX3RvID0gIlZhcmlhYmxlcyIsIHZhbHVlc190byA9ICJNdW5pY2lwYWxpdHkgVG90YWxzIikNCg0KDQp0b3RhbF9leGVtcHRpb25zIDwtIGxlZnRfam9pbihjb29rdG90YWxzLCBtdW5pdG90YWxzKQ0KdG90YWxfZXhlbXB0aW9ucw0KYGBgDQoNCmBgYHtyIGV4ZW1wdGlvbnR5cGUtcGVybXVuaSwgaW5jbHVkZSA9IEZBTFNFfQ0KDQpleGVtcHR5cGVfdG90YWxzX3Blcm11bmkgPC0gZXhlbXB0aW9uc19ieV9jbGFzc19wZXJfVEMgJT4lIA0KICBtdXRhdGUodGF4X2NvZGVfbnVtID0gYXMuY2hhcmFjdGVyKHRheF9jb2RlX251bSkpICU+JQ0KICBsZWZ0X2pvaW4obXVuaV90YXhfY29kZXMpICU+JQ0KICBsZWZ0X2pvaW4obXVuaV9hZ2VuY3lfbmFtZXMpICU+JQ0KICBmaWx0ZXIodGF4X2NvZGVfbnVtICVpbiUgbXVuaV90YXhfY29kZXMkdGF4X2NvZGVfbnVtKSU+JQ0KICBncm91cF9ieShhZ2VuY3lfbnVtLCBhZ2VuY3lfbmFtZSkgJT4lDQogIHN1bW1hcml6ZShhdiA9IHN1bShhdiwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgICAgIGVhdj1zdW0oZWF2LCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIHRvdGFsX2V4ZW1wdF9lYXZfaW5NdW5pID0gc3VtKGV4ZV9ob21lb3duZXIgKyBleGVfc2VuaW9yICsgZXhlX2ZyZWV6ZSArIGV4ZV9sb25ndGltZV9ob21lb3duZXIgKyANCiAgICAgICAgICAgICAgICAgICAgICAgICBleGVfZGlzYWJsZWQgKyBleGVfdmV0X3JldHVybmluZyArIGV4ZV92ZXRfZGlzICsgZXhlX2FiYXRlLCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIGV4ZV9ob21lb3duZXIgPSBzdW0oZXhlX2hvbWVvd25lciwgbmEucm09VFJVRSksDQogICAgICAgICAgICBleGVfc2VuaW9yID0gc3VtKGV4ZV9zZW5pb3IsIG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgZXhlX2ZyZWV6ZSA9IHN1bShleGVfZnJlZXplLCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIGV4ZV9sb25ndGltZV9ob21lb3duZXIgPSBzdW0oZXhlX2xvbmd0aW1lX2hvbWVvd25lciwgbmEucm09VFJVRSksDQogICAgICAgICAgICBleGVfZGlzYWJsZWQgPSBzdW0oZXhlX2Rpc2FibGVkLCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIGV4ZV92ZXRfcmV0dXJuaW5nID0gc3VtKGV4ZV92ZXRfcmV0dXJuaW5nLCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIGV4ZV92ZXRfZGlzID0gc3VtKGV4ZV92ZXRfZGlzLCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIGV4ZV9hYmF0ZSA9IHN1bShleGVfYWJhdGUsIG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgbXVuaV9waW5fY291bnQgPSBuKCkpDQoNCmBgYA0KDQoNCmBgYHtyIGdyYXBocywgZWNobz1GQUxTRX0NCmV4ZW1wdGlvbnNfYnlfY2xhc3NfcGVyX1RDICU+JQ0KICBzdW1tYXJpemUoZXhlX2hvbWVvd25lciA9IHN1bShleGVfaG9tZW93bmVyLCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIGV4ZV9zZW5pb3IgPSBzdW0oZXhlX3NlbmlvciwgbmEucm09VFJVRSksDQogICAgICAgICAgICBleGVfZnJlZXplID0gc3VtKGV4ZV9mcmVlemUsIG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgZXhlX2xvbmd0aW1lX2hvbWVvd25lciA9IHN1bShleGVfbG9uZ3RpbWVfaG9tZW93bmVyLCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIGV4ZV9kaXNhYmxlZCA9IHN1bShleGVfZGlzYWJsZWQsIG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgZXhlX3ZldF9yZXR1cm5pbmcgPSBzdW0oZXhlX3ZldF9yZXR1cm5pbmcsIG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgZXhlX3ZldF9kaXMgPSBzdW0oZXhlX3ZldF9kaXMpLA0KICAgICAgICAgICAgZXhlX2FiYXRlID0gc3VtKGV4ZV9hYmF0ZSwgbmEucm09VFJVRSkpICU+JQ0KICBwaXZvdF9sb25nZXIoY29scyA9IGV4ZV9ob21lb3duZXI6ZXhlX2FiYXRlLCBuYW1lc190byA9ICJleGVtcHRpb25fdHlwZSIsIHZhbHVlc190byA9ICJhbW91bnQiKQ0KDQoNCg0KDQojIGV4ZW1wdGlvbnNfYnlfY2xhc3NfcGVyX1RDICU+JSANCiMgICBzdW1tYXJpemUoDQojICAgICAgICAgICAgIGV4ZV9ob21lb3duZXIgPSBzdW0oZXhlX2hvbWVvd25lciwgbmEucm09VFJVRSksDQojICAgICAgICAgICAgIGV4ZV9zZW5pb3IgPSBzdW0oZXhlX3NlbmlvciwgbmEucm09VFJVRSksDQojICAgICAgICAgICAgIGV4ZV9mcmVlemUgPSBzdW0oZXhlX2ZyZWV6ZSwgbmEucm09VFJVRSksDQojICAgICAgICAgICAgIGV4ZV9sb25ndGltZV9ob21lb3duZXIgPSBzdW0oZXhlX2xvbmd0aW1lX2hvbWVvd25lciwgbmEucm09VFJVRSksDQojICAgICAgICAgICAgIGV4ZV9kaXNhYmxlZCA9IHN1bShleGVfZGlzYWJsZWQsIG5hLnJtPVRSVUUpLA0KIyAgICAgICAgICAgICBleGVfdmV0X3JldHVybmluZyA9IHN1bShleGVfdmV0X3JldHVybmluZywgbmEucm09VFJVRSksDQojICAgICAgICAgICAgIGV4ZV92ZXRfZGlzID0gc3VtKGV4ZV92ZXRfZGlzKSwNCiMgICAgICAgICAgICAgZXhlX2FiYXRlID0gc3VtKGV4ZV9hYmF0ZSwgbmEucm09VFJVRSksDQojICAgICAgICAgICAgICkgJT4lDQojICAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBleGVfaG9tZW93bmVyOmV4ZV9hYmF0ZSwgbmFtZXNfdG8gPSAiZXhlbXB0aW9uX3R5cGUiLCB2YWx1ZXNfdG8gPSAiYW1vdW50IikgJT4lDQojICAgZ2dwbG90KCkgKw0KIyAgIGdlb21fYmFyKGFlcyh4PWFtb3VudCwgeT1leGVtcHRpb25fdHlwZSksIHN0YXQgPSAiaWRlbnRpdHkiKSArIHRoZW1lX2NsYXNzaWMoKSArDQojICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpKw0KIyAgIGxhYnMoeT0iIix4PSIiLCB0aXRsZSA9ICJBbW91bnQgb2YgRXhlbXB0IEVBViBkdWUgdG8gZWFjaCBFeGVtcHRpb24gVHlwZSIpKw0KIyAgICAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6ZG9sbGFyKQ0KDQoNCg0KZXhlbXB0aW9uc19ieV9jbGFzc19wZXJfVEMgJT4lIA0KICBtdXRhdGUoY2xhc3NfY29kZSA9IGFzLmNoYXJhY3RlcihjbGFzc19jb2RlKSkgJT4lDQogICAgbGVmdF9qb2luKGNsYXNzX2RpY3QsIGJ5ID0gImNsYXNzX2NvZGUiKSAlPiUNCiAgZ3JvdXBfYnkoQWxlYV9jYXQpICU+JQ0KICBzdW1tYXJpemUoYXYgPSBzdW0oYXYsIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgICBlYXY9c3VtKGVhdiwgbmEucm09VFJVRSksDQogICAgICAgICAgICBleGVfaG9tZW93bmVyID0gc3VtKGV4ZV9ob21lb3duZXIsIG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgZXhlX3NlbmlvciA9IHN1bShleGVfc2VuaW9yLCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIGV4ZV9mcmVlemUgPSBzdW0oZXhlX2ZyZWV6ZSwgbmEucm09VFJVRSksDQogICAgICAgICAgICBleGVfbG9uZ3RpbWVfaG9tZW93bmVyID0gc3VtKGV4ZV9sb25ndGltZV9ob21lb3duZXIsIG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgZXhlX2Rpc2FibGVkID0gc3VtKGV4ZV9kaXNhYmxlZCwgbmEucm09VFJVRSksDQogICAgICAgICAgICBleGVfdmV0X3JldHVybmluZyA9IHN1bShleGVfdmV0X3JldHVybmluZywgbmEucm09VFJVRSksDQogICAgICAgICAgICBleGVfdmV0X2RpcyA9IHN1bShleGVfdmV0X2RpcyksDQogICAgICAgICAgICBleGVfYWJhdGUgPSBzdW0oZXhlX2FiYXRlLCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIHBpbl9jb3VudCA9IG4oKSkgJT4lDQogIHBpdm90X2xvbmdlcihjb2xzID0gZXhlX2hvbWVvd25lcjpleGVfYWJhdGUsIG5hbWVzX3RvID0gImV4ZW1wdGlvbl90eXBlIiwgdmFsdWVzX3RvID0gImFtb3VudCIpICU+JQ0KICBnZ3Bsb3QoKSArDQogIGdlb21fYmFyKGFlcyh4PWFtb3VudCwgeT1leGVtcHRpb25fdHlwZSwgZmlsbCA9IEFsZWFfY2F0KSwgc3RhdCA9ICJpZGVudGl0eSIpICsgdGhlbWVfY2xhc3NpYygpICsgDQogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpKw0KbGFicyh5PSIiLHg9IiIsIHRpdGxlID0gIkFtb3VudCBvZiBFeGVtcHQgRUFWIGR1ZSB0byBlYWNoIEV4ZW1wdGlvbiBUeXBlIiwgc3VidGl0bGUgPSAiQWxlYSdzIGNhdGVnb3JpZXMiKSsNCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6ZG9sbGFyKQ0KDQoNCmV4ZW1wdGlvbnNfYnlfY2xhc3NfcGVyX1RDICU+JSANCiAgbXV0YXRlKGNsYXNzX2NvZGUgPSBhcy5jaGFyYWN0ZXIoY2xhc3NfY29kZSkpICU+JQ0KICAgIGxlZnRfam9pbihjbGFzc19kaWN0LCBieSA9ICJjbGFzc19jb2RlIikgJT4lDQogIGdyb3VwX2J5KEFsZWFfY2F0KSAlPiUNCiAgc3VtbWFyaXplKGF2ID0gc3VtKGF2LCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgZWF2PXN1bShlYXYsIG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgZXhlX2hvbWVvd25lciA9IHN1bShleGVfaG9tZW93bmVyLCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIGV4ZV9zZW5pb3IgPSBzdW0oZXhlX3NlbmlvciwgbmEucm09VFJVRSksDQogICAgICAgICAgICBleGVfZnJlZXplID0gc3VtKGV4ZV9mcmVlemUsIG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgZXhlX2xvbmd0aW1lX2hvbWVvd25lciA9IHN1bShleGVfbG9uZ3RpbWVfaG9tZW93bmVyLCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIGV4ZV9kaXNhYmxlZCA9IHN1bShleGVfZGlzYWJsZWQsIG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgZXhlX3ZldF9yZXR1cm5pbmcgPSBzdW0oZXhlX3ZldF9yZXR1cm5pbmcsIG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgZXhlX3ZldF9kaXMgPSBzdW0oZXhlX3ZldF9kaXMpLA0KICAgICAgICAgICAgZXhlX2FiYXRlID0gc3VtKGV4ZV9hYmF0ZSwgbmEucm09VFJVRSksDQogICAgICAgICAgICBwaW5fY291bnQgPSBuKCkpICU+JQ0KICBwaXZvdF9sb25nZXIoY29scyA9IGV4ZV9ob21lb3duZXI6ZXhlX2FiYXRlLCBuYW1lc190byA9ICJjbGFzc190eXBlIiwgdmFsdWVzX3RvID0gImFtb3VudCIpICU+JQ0KICBnZ3Bsb3QoKSArDQogIGdlb21fYmFyKGFlcyh4PWFtb3VudCwgeT1BbGVhX2NhdCwgZmlsbCA9IGNsYXNzX3R5cGUpLCBzdGF0ID0gImlkZW50aXR5IikgKyB0aGVtZV9jbGFzc2ljKCkgKyANCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikrDQpsYWJzKHk9IiIseD0iIiwgdGl0bGUgPSAiQW1vdW50IG9mIEV4ZW1wdCBFQVYgZHVlIHRvIGVhY2ggRXhlbXB0aW9uIFR5cGUiLCBzdWJ0aXRsZSA9ICJBbGVhJ3MgY2F0ZWdvcmllcyIpKw0KICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpkb2xsYXIpDQoNCmV4ZW1wdGlvbnNfYnlfY2xhc3NfcGVyX1RDICU+JSANCiAgbXV0YXRlKGNsYXNzX2NvZGUgPSBhcy5jaGFyYWN0ZXIoY2xhc3NfY29kZSkpICU+JQ0KICAgIGxlZnRfam9pbihjbGFzc19kaWN0LCBieSA9ICJjbGFzc19jb2RlIikgJT4lDQogIGdyb3VwX2J5KG1ham9yX2NsYXNzX3R5cGUpICU+JQ0KICMgICBmaWx0ZXIobWFqb3JfY2xhc3NfdHlwZSA9PSAiUmVzaWRlbnRpYWwiKSAlPiUNCg0KICBzdW1tYXJpemUoYXYgPSBzdW0oYXYsIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgICBlYXY9c3VtKGVhdiwgbmEucm09VFJVRSksDQogICAgICAgICAgICBleGVfaG9tZW93bmVyID0gc3VtKGV4ZV9ob21lb3duZXIsIG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgZXhlX3NlbmlvciA9IHN1bShleGVfc2VuaW9yLCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIGV4ZV9mcmVlemUgPSBzdW0oZXhlX2ZyZWV6ZSwgbmEucm09VFJVRSksDQogICAgICAgICAgICBleGVfbG9uZ3RpbWVfaG9tZW93bmVyID0gc3VtKGV4ZV9sb25ndGltZV9ob21lb3duZXIsIG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgZXhlX2Rpc2FibGVkID0gc3VtKGV4ZV9kaXNhYmxlZCwgbmEucm09VFJVRSksDQogICAgICAgICAgICBleGVfdmV0X3JldHVybmluZyA9IHN1bShleGVfdmV0X3JldHVybmluZywgbmEucm09VFJVRSksDQogICAgICAgICAgICBleGVfdmV0X2RpcyA9IHN1bShleGVfdmV0X2RpcyksDQogICAgICAgICAgICBleGVfYWJhdGUgPSBzdW0oZXhlX2FiYXRlLCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIHBpbl9jb3VudCA9IG4oKSkgJT4lDQogIHBpdm90X2xvbmdlcihjb2xzID0gZXhlX2hvbWVvd25lcjpleGVfYWJhdGUsIG5hbWVzX3RvID0gImNsYXNzX3R5cGUiLCB2YWx1ZXNfdG8gPSAiYW1vdW50IikgJT4lDQogIGdncGxvdCgpICsNCiAgZ2VvbV9iYXIoYWVzKHg9YW1vdW50LCB5ID0gbWFqb3JfY2xhc3NfdHlwZSwgZmlsbCA9IGNsYXNzX3R5cGUpLCBzdGF0ID0gImlkZW50aXR5IikgKyB0aGVtZV9jbGFzc2ljKCkgKw0KICBsYWJzKCB5ID0gIiIsIHRpdGxlID0gIkV4ZW1wdCBFQVYgd2l0aGluIGVhY2ggTWFqb3IgUHJvcGVydHkgQ2xhc3MiLCBzdWJ0aXRsZSA9ICJNYWpvciBDbGFzcyBUeXBlcyIpICsgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikrDQogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OmRvbGxhcikNCmBgYA0KDQoNCmBgYHtyfQ0KIyB1c2UgZXhlbXB0aW9ucyBpbiB0YXggY29kZXMgdG8gc3VtbWFyaXplIEVBVi4gDQojIGV4ZW1wdGlvbiB2YWx1ZXMgY2FtZSBmcm9tIGBwaW5gIGRhdGEgdGFibGUgaW4gcHRheHNpbS4NCiMgTW9yZSBhY2N1cmF0ZSB0aGF0IGNhbGN1bGF0aW5nIGl0IGZyb20gcmV2ZW51ZSBjb2xsZWN0ZWQudGF4IHJhdGUgaW4gdGF4IGJpbGwgZGF0YQ0KDQpleGVtcHRpb25zX2J5X2NsYXNzX3Blcl9UQyA8LSByZWFkX2NzdigiM19FeGVtcHRpb25fRGV0YWlsc19vdXRwdXQtQ29va19FeGVtcHNfYnlDbGFzc2FuZFRheGNvZGUuY3N2IikgJT4lDQogIG11dGF0ZSh0YXhfY29kZV9udW0gPSBhcy5jaGFyYWN0ZXIodGF4X2NvZGVfbnVtKSwNCiAgICAgICAgIGNsYXNzX2NvZGUgPSBhcy5jaGFyYWN0ZXIoY2xhc3NfY29kZSkpICU+JQ0KICANCiAgbGVmdF9qb2luKGNsYXNzX2RpY3QsIGJ5ID0gImNsYXNzX2NvZGUiKSAlPiUNCiAgbGVmdF9qb2luKG11bmlfdGF4X2NvZGVzLCBieSA9IGMoInRheF9jb2RlX251bSIpICkgJT4lDQogIA0KICAjIGRyb3BzIGFsbCBDbGFzcyAwIHByb3BlcnRpZXMgKFJhaWxyb2FkIHByb3BlcnR5LCB0YXggZXhlbXB0KQ0KICBmaWx0ZXIoY2xhc3NfY29kZSAhPSAiMCIpICU+JQ0KICANCiAgbGVmdF9qb2luKG11bmlfYWdlbmN5X25hbWVzKSAlPiUNCiAgbGVmdF9qb2luKG5pY2tuYW1lcywgYnkgPSBjKCJhZ2VuY3lfbmFtZSIgPSAiYWdlbmN5X25hbWUiKSkgJT4lDQogICMgbWVyZ2Ugd2l0aCBUSUYgZGlzdHJpYiB0YWJsZSB0byBjYWxjdWxhdGUgdGhlIHBlcmNlbnQgb2YgdGhlIEVBViB0aGF0IGdvZXMgdG8gdGhlIFRJRiB2cyB0aGUgZGlzdHJpY3QNCiAgbGVmdF9qb2luKHRpZl9kaXN0cmliLCBieT1jKCJ0YXhfY29kZV9udW0iLCAieWVhciIsICJ0YXhfY29kZV9yYXRlIikpICU+JQ0KICANCiAgbXV0YXRlKGV4ZW1wdF9FQVYgPSAoZXhlX2hvbWVvd25lciArIGV4ZV9zZW5pb3IgKyBleGVfZnJlZXplICsgZXhlX2xvbmd0aW1lX2hvbWVvd25lciArIA0KICAgICAgICAgICAgICAgICAgICAgICAgIGV4ZV9kaXNhYmxlZCArIGV4ZV92ZXRfcmV0dXJuaW5nICsgZXhlX3ZldF9kaXMgKyBleGVfYWJhdGUpICwNCiAgICAgICAgIGluX1RJRiA9IGlmZWxzZSh0YXhfY29kZV9udW0gJWluJSB1bmlxdWVfdGlmX3RheGNvZGVzJHRheF9jb2RlX251bSwgMSwgMCksDQogICAgICAgICB0YXhfYmFzZV9jdXJyZW50ID0gaWZlbHNlKGluX1RJRj09MSwgKGVhdi1leGVtcHRfRUFWKSooMS10YXhfY29kZV9kaXN0cmlidXRpb25fcGN0LzEwMCksIGVhdi1leGVtcHRfRUFWKSwNCiAgICAgICAgIHRheF9iYXNlX25vZXhlbXBzID0gaWZlbHNlKGluX1RJRj09MSwgKGVhdikqKDEtdGF4X2NvZGVfZGlzdHJpYnV0aW9uX3BjdC8xMDApLCBlYXYpLA0KICAgICAgICAgZ3JvdXBlZF9jbGFzc2VzID0gaWZlbHNlKGNsYXNzXzFkaWcgJWluJSBjKCIyIiksICJDbGFzcyAyIiwgTkEpLA0KICAgICAgICAgZ3JvdXBlZF9jbGFzc2VzID0gaWZlbHNlKGNsYXNzXzFkaWcgJWluJSBjKCIzIiwgIjkiKSwgIkNsYXNzIDMiLCBncm91cGVkX2NsYXNzZXMpLA0KICAgICAgICAgZ3JvdXBlZF9jbGFzc2VzID0gaWZlbHNlKGlzLm5hKGdyb3VwZWRfY2xhc3NlcyksICJPdGhlciBDbGFzc2VzIiwgZ3JvdXBlZF9jbGFzc2VzKQ0KICApDQoNCg0KDQptdW5pX3RvdGFscyA8LSAgZXhlbXB0aW9uc19ieV9jbGFzc19wZXJfVEMgJT4lIA0KICBncm91cF9ieShjbGVhbl9uYW1lLCBhZ2VuY3lfbmFtZSkgJT4lIA0KICMgIGZpbHRlcighaXMubmEoY2xlYW5fbmFtZSkpICU+JQ0KICBzdW1tYXJpemUobXVuaV9hdiA9IHN1bShhdiksDQogICAgICAgICAgICBtdW5pX2VhdiA9IHN1bShlYXYpKQ0KDQp0YWJsZTIgPC0gZXhlbXB0aW9uc19ieV9jbGFzc19wZXJfVEMgJT4lIA0KICBncm91cF9ieShjbGVhbl9uYW1lLCBhZ2VuY3lfbmFtZSwgZ3JvdXBlZF9jbGFzc2VzKSAlPiUNCiAgc3VtbWFyaXplKGF2ID0gc3VtKGF2KSwNCiAgICAgICAgICAgIGVhdiA9IHN1bShlYXYpKSAlPiUgDQogIHVuZ3JvdXAoKSAlPiUNCiAgbGVmdF9qb2luKG11bmlfdG90YWxzKSAlPiUNCiAgZmlsdGVyKCFpcy5uYShjbGVhbl9uYW1lKSklPiUNCiAgbXV0YXRlKHBlcmNfY2xhc3MyID0gaWZlbHNlKGdyb3VwZWRfY2xhc3NlcyA9PSAiQ2xhc3MgMiIsIGVhdi9tdW5pX2VhdiwgMCksDQogICAgICAgICBwZXJjX2NsYXNzMyA9IGlmZWxzZShncm91cGVkX2NsYXNzZXMgPT0gIkNsYXNzIDMiLCBlYXYvbXVuaV9lYXYsIDApLA0KICAgICAgICAgcGVyY19vdGhlciA9IGlmZWxzZShncm91cGVkX2NsYXNzZXMgPT0gIk90aGVyIENsYXNzZXMiLCBlYXYvbXVuaV9lYXYsIDApKSAlPiUNCiAgZ3JvdXBfYnkoY2xlYW5fbmFtZSwgYWdlbmN5X25hbWUpICU+JQ0KICBtdXRhdGUoDQogICAgICAgICBwZXJjX3JlcyA9IHBlcmNfY2xhc3MyICsgcGVyY19jbGFzczMpDQoNCg0KdGFibGUyICU+JSB1bmdyb3VwKCkgJT4lIHNlbGVjdCgtYyhhZ2VuY3lfbmFtZSwgbXVuaV9hdiwgbXVuaV9lYXYpKQ0KYGBgDQoNCj4gRml4ICB0YWJsZSBiZWxvdyBsYXRlciEgDQoNCmBgYHtyfQ0KbXVuaXRvdGFscyA8LSBleGVtcHRpb25zX2J5X2NsYXNzX3Blcl9UQyAlPiUgDQogIG11dGF0ZShpc19jaGljYWdvID0gaWZlbHNlKGNsZWFuX25hbWUgPT0gIkNoaWNhZ28iLCAxLCAwKSkgJT4lDQogIGZpbHRlcih0YXhfY29kZV9udW0gJWluJSBtdW5pX3RheF9jb2RlcyR0YXhfY29kZV9udW0pJT4lDQogIGdyb3VwX2J5KGlzX2NoaWNhZ28pICU+JQ0KICBzdW1tYXJpemUoYXYgPSBzdW0oYXYsIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgICBlYXY9c3VtKGVhdiwgbmEucm09VFJVRSksDQogICAgICAgICAgICB0b3RhbF9leGVtcHRfZWF2ID0gc3VtKGV4ZV9ob21lb3duZXIgKyBleGVfc2VuaW9yICsgZXhlX2ZyZWV6ZSArIGV4ZV9sb25ndGltZV9ob21lb3duZXIgKyANCiAgICAgICAgICAgICAgICAgICAgICAgICBleGVfZGlzYWJsZWQgKyBleGVfdmV0X3JldHVybmluZyArIGV4ZV92ZXRfZGlzICsgZXhlX2FiYXRlLCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIGhvbWVvd25lcnNfZXhlbXB0aW9uID0gc3VtKGV4ZV9ob21lb3duZXIsIG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgc2VuaW9yX2V4ZW1wdGlvbiA9IHN1bShleGVfc2VuaW9yLCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIGZyZWV6ZV9leGVtcHRpb24gPSBzdW0oZXhlX2ZyZWV6ZSwgbmEucm09VFJVRSksDQogICAgICAgICAgICAgICAgICAgICAgICBwaW5fY291bnQgPSBuKCkpICU+JQ0KICBwaXZvdF9sb25nZXIoY29scyA9IGF2OnBpbl9jb3VudCwgbmFtZXNfdG8gPSAiVmFyaWFibGVzIiwgdmFsdWVzX3RvID0gIk11bmljaXBhbGl0eSBUb3RhbHMiKQ0KDQojIyBvbmx5IHVuaW5jb3Jwb3JhdGVkIGFhcmVhcw0KY29va3RvdGFsczwtZXhlbXB0aW9uc19ieV9jbGFzc19wZXJfVEMgJT4lIA0KICBtdXRhdGUoaXNfY2hpY2FnbyA9IGlmZWxzZShjbGVhbl9uYW1lID09ICJDaGljYWdvIiwgMSwgMCkpICU+JQ0KICBmaWx0ZXIodGF4X2NvZGVfbnVtICVpbiUgY29va190YXhfY29kZXMkdGF4X2NvZGVfbnVtKSU+JQ0KICBncm91cF9ieShpc19jaGljYWdvKSAlPiUNCiAgc3VtbWFyaXplKGF2ID0gc3VtKGF2LCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgZWF2PXN1bShlYXYsIG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgdG90YWxfZXhlbXB0X2VhdiA9IHN1bShleGVfaG9tZW93bmVyICsgZXhlX3NlbmlvciArIGV4ZV9mcmVlemUgKyBleGVfbG9uZ3RpbWVfaG9tZW93bmVyICsgDQogICAgICAgICAgICAgICAgICAgICAgICAgZXhlX2Rpc2FibGVkICsgZXhlX3ZldF9yZXR1cm5pbmcgKyBleGVfdmV0X2RpcyArIGV4ZV9hYmF0ZSwgbmEucm09VFJVRSksDQogICAgICAgICAgICBob21lb3duZXJzX2V4ZW1wdGlvbiA9IHN1bShleGVfaG9tZW93bmVyLCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIHNlbmlvcl9leGVtcHRpb24gPSBzdW0oZXhlX3NlbmlvciwgbmEucm09VFJVRSksDQogICAgICAgICAgICBmcmVlemVfZXhlbXB0aW9uID0gc3VtKGV4ZV9mcmVlemUsIG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgICAgICAgICAgICAgcGluX2NvdW50ID0gbigpKSAlPiUNCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBhdjpwaW5fY291bnQsIG5hbWVzX3RvID0gIlZhcmlhYmxlcyIsIHZhbHVlc190byA9ICJDb29rIENvdW50eSBUb3RhbHMiKSAlPiUNCiAgbXV0YXRlKGlzX2NoaWNhZ28gPSBpZmVsc2UoaXMubmEoaXNfY2hpY2FnbyksIDAsIGlzX2NoaWNhZ28pKQ0KDQp1bmluY29ycG9yYXRlZGFyZWFzPC1leGVtcHRpb25zX2J5X2NsYXNzX3Blcl9UQyAlPiUgDQogIG11dGF0ZShpc19jaGljYWdvID0gaWZlbHNlKGNsZWFuX25hbWUgPT0gIkNoaWNhZ28iLCAxLCAwKSkgJT4lDQogZmlsdGVyKCF0YXhfY29kZV9udW0gJWluJSBtdW5pX3RheF9jb2RlcyR0YXhfY29kZV9udW0pJT4lDQogIGdyb3VwX2J5KGlzX2NoaWNhZ28pICU+JQ0KICBzdW1tYXJpemUoYXYgPSBzdW0oYXYsIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgICBlYXY9c3VtKGVhdiwgbmEucm09VFJVRSksDQogICAgICAgICAgICB0b3RhbF9leGVtcHRfZWF2ID0gc3VtKGV4ZV9ob21lb3duZXIgKyBleGVfc2VuaW9yICsgZXhlX2ZyZWV6ZSArIGV4ZV9sb25ndGltZV9ob21lb3duZXIgKyANCiAgICAgICAgICAgICAgICAgICAgICAgICBleGVfZGlzYWJsZWQgKyBleGVfdmV0X3JldHVybmluZyArIGV4ZV92ZXRfZGlzICsgZXhlX2FiYXRlLCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIGhvbWVvd25lcnNfZXhlbXB0aW9uID0gc3VtKGV4ZV9ob21lb3duZXIsIG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgc2VuaW9yX2V4ZW1wdGlvbiA9IHN1bShleGVfc2VuaW9yLCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIGZyZWV6ZV9leGVtcHRpb24gPSBzdW0oZXhlX2ZyZWV6ZSwgbmEucm09VFJVRSksDQogICAgICAgICAgICAgICAgICAgICAgICBwaW5fY291bnQgPSBuKCkpICU+JQ0KICBwaXZvdF9sb25nZXIoY29scyA9IGF2OnBpbl9jb3VudCwgbmFtZXNfdG8gPSAiVmFyaWFibGVzIiwgdmFsdWVzX3RvID0gIlVuaW5jb3Jwb3JhdGVkIFRvdGFscyIpICU+JQ0KICBtdXRhdGUoaXNfY2hpY2FnbyA9IGlmZWxzZShpcy5uYShpc19jaGljYWdvKSwgMCwgaXNfY2hpY2FnbykpDQoNCg0KY29va2FuZG11bml0b3RhbHMgPC0gbGVmdF9qb2luKGNvb2t0b3RhbHMsIG11bml0b3RhbHMpIA0KY29va2FuZG11bml0b3RhbHMgJT4lIGxlZnRfam9pbih1bmluY29ycG9yYXRlZGFyZWFzKQ0KYGBgDQoNClRoZXJlIHdhcyBgciBzY2FsZXM6OmRvbGxhcihzdW0odGFibGUyJGVhdikpYCBFQVYgaW4gQ29vayBDb3VudHkgZHVyaW5nIDIwMjEgd2hlbiBpbmNsdWRpbmcgYWxsIHByb3BlcnR5IHR5cGVzLg0KDQpgYGB7cn0NCnRpZl90YWJsZSA8LSBleGVtcHRpb25zX2J5X2NsYXNzX3Blcl9UQyAlPiUgDQogIGdyb3VwX2J5KGNsZWFuX25hbWUsIGFnZW5jeV9uYW1lLCBpbl9USUYsIGdyb3VwZWRfY2xhc3NlcykgJT4lDQogIHN1bW1hcml6ZShhdiA9IHN1bShhdiksDQogICAgICAgICAgICBlYXYgPSBzdW0oZWF2KSkgJT4lIA0KICB1bmdyb3VwKCkgJT4lDQogIGxlZnRfam9pbihtdW5pX3RvdGFscykgJT4lIA0KICBwaXZvdF93aWRlcihpZF9jb2xzID0gYyhjbGVhbl9uYW1lLCBhZ2VuY3lfbmFtZSwgbXVuaV9hdiwgbXVuaV9lYXYpLCANCiAgICAgICAgICAgICAgbmFtZXNfZnJvbSA9IGMoaW5fVElGLCBncm91cGVkX2NsYXNzZXMpLCANCiAgICAgICAgICAgICAgdmFsdWVzX2Zyb20gPSBlYXYpDQoNCiMgdGlmX3RhYmxlICU+JSANCiMgICBzZWxlY3QoY2xlYW5fbmFtZTptdW5pX2VhdiwgYDFfT3RoZXIgQ2xhc3Nlc2AsIGAwX090aGVyIENsYXNzZXNgKSAlPiUgDQojICAgcmVuYW1lKG5vbnJlc19pblRJRiA9IGAxX090aGVyIENsYXNzZXNgLCANCiMgICAgICAgICAgbm9ucmVzX291dHNpZGVUSUYgPSBgMF9PdGhlciBDbGFzc2VzYCkgJT4lDQojICAgbXV0YXRlKHBjdF9ub25yZXNfaW5USUYgPSByb3VuZChub25yZXNfaW5USUYvbXVuaV9lYXYsIGRpZ2l0PTYpLA0KIyAgICAgICAgICBwY3Rfbm9ucmVzX291dHNpZGVUSUYgPSByb3VuZChub25yZXNfb3V0c2lkZVRJRi9tdW5pX2VhdiwgZGlnaXQ9NiksDQojICAgICAgICAgIHBjdF9ub25yZXNfaW5USUYgPSBpZmVsc2UoaXMubmEocGN0X25vbnJlc19pblRJRiksIDAsIHBjdF9ub25yZXNfaW5USUYpLA0KIyAgICAgICAgICBwY3Rfbm9ucmVzX291dHNpZGVUSUYgPSBpZmVsc2UoaXMubmEocGN0X25vbnJlc19vdXRzaWRlVElGKSwgMCwgcGN0X25vbnJlc19vdXRzaWRlVElGKSkNCg0KdGlmX3RhYmxlICU+JSANCiAgc2VsZWN0KGNsZWFuX25hbWU6bXVuaV9lYXYsIGAxX0NsYXNzIDJgLCBgMF9DbGFzcyAyYCkgJT4lIA0KICByZW5hbWUocmVzX2luVElGID0gYDFfQ2xhc3MgMmAsIA0KICAgICAgICAgcmVzX291dHNpZGVUSUYgPSBgMF9DbGFzcyAyYCkgJT4lDQogIG11dGF0ZShwY3RfcmVzX2luVElGID0gcm91bmQocmVzX2luVElGL211bmlfZWF2LCBkaWdpdD02KSwNCiAgICAgICAgIHBjdF9yZXNfb3V0c2lkZVRJRiA9IHJvdW5kKHJlc19vdXRzaWRlVElGL211bmlfZWF2LCBkaWdpdD02KSwNCiAgICAgICAgIHBjdF9yZXNfaW5USUYgPSBpZmVsc2UoaXMubmEocGN0X3Jlc19pblRJRiksIDAsIHBjdF9yZXNfaW5USUYpLA0KICAgICAgICAgcGN0X3Jlc19vdXRzaWRlVElGID0gaWZlbHNlKGlzLm5hKHBjdF9yZXNfb3V0c2lkZVRJRiksIDAsIHBjdF9yZXNfb3V0c2lkZVRJRikpICU+JSBzZWxlY3QoLWFnZW5jeV9uYW1lKSAlPiUgZmlsdGVyKGNsZWFuX25hbWUgJWluJSBjKCJQYXJrIEZvcmVzdCIsICJEb2x0b24iLCJIaWxsc2lkZSIsICJSaXZlcnNpZGUiLCJDaGljYWdvIiwgIldlc3RjaGVzdGVyIiwgIk1hcmtoYW0iLCAiV2lubmV0a2EiLCAiUm9zZW1vbnQiKSkNCg0KYGBgDQoNCk11bmkgRUFWIHJlcHJlc2VudHMgYWxsIEVBViBpbiB0aGUgbXVuaWNpcGFsaXR5IGFuZCBpbmNsdWRlcyBUSUYgaW5jcmVtZW50cyBhbmQgdGF4IGV4ZW1wdCBwcm9wZXJ0eS4gSXQgaXMgdGhlIHN1bW1lZCBlYXYgb2YgYWxsIHBpbnMgZnJvbSB0aGUgYHBpbmAgUFRBWFNJTSBkYXRhIHRhYmxlLg0KDQoNCk91dCBvZiBhbGwgb2YgQ2hpY2FnbydzIEVBViwgOS45JSBvZiBpdHMgRUFWIGlzIHJlc2lkZW50aWFsIHByb3BlcnRpZXMgaW5zaWRlIG9mIFRJRnMuIDQyLjglIG9mIENoaWNhZ28ncyB0b3RhbCBFQVYgY29tZXMgZnJvbSBSZXNpZGVudGlhbCBwcm9wZXJ0aWVzIG91dHNpZGUgb2YgVElGcy4NCg0KV2lubmV0a2EgaGFzIGFsbCBvZiBpdHMgcmVzaWRlbnRpYWwgRUFWIG91dHNpZGUgb2YgYSBUSUYgYW5kIG5lYXJseSBhbGwgb2YgdGhlaXIgRUFWIGlzIGZyb20gcmVzaWRlbnRpYWwgcHJvcGVydGllcy4gDQoNCmBgYHtyfQ0KcGl2b3R0YWJsZSA8LSB0YWJsZTIgJT4lIA0KICBwaXZvdF93aWRlcihpZF9jb2xzID0gYyhjbGVhbl9uYW1lLCBhZ2VuY3lfbmFtZSwgbXVuaV9hdiwgbXVuaV9lYXYpLCANCiAgICAgICAgICAgICAgbmFtZXNfZnJvbSA9IGdyb3VwZWRfY2xhc3NlcywgdmFsdWVzX2Zyb20gPSBlYXYpICU+JSAgIA0KICBtdXRhdGUoYWdlbmN5X25hbWUgPSBpZmVsc2UoYWdlbmN5X25hbWUgPT0gIlRPV04gQ0lDRVJPIiwgIkNJVFkgT0YgQ0lDRVJPIiwgYWdlbmN5X25hbWUpICkNCg0KcGl2b3R0YWJsZSAlPiUgc2VsZWN0KC1hZ2VuY3lfbmFtZSkNCg0KcGl2b3RfdGFibGUgPC0gcGl2b3R0YWJsZSAlPiUgICANCiAgbXV0YXRlKHBlcmNfY2xhc3MyID0gYENsYXNzIDJgL211bmlfZWF2LA0KICAgICAgICAgcGVyY19jbGFzczMgPSBgQ2xhc3MgM2AvbXVuaV9lYXYsDQogICAgICAgICBwZXJjX290aGVyID0gYE90aGVyIENsYXNzZXNgL211bmlfZWF2LA0KDQogICAgICAgICBwZXJjX25vbnJlcyA9IChwZXJjX2NsYXNzMyArIHBlcmNfb3RoZXIpLA0KICAgICAgICAgcGVyY19yZXNpZGVudGlhbCA9IHBlcmNfY2xhc3MyKSAlPiUgDQogIG11dGF0ZV9hbGwoIH5jb2FsZXNjZSguLDApKQ0KDQojcGl2b3RfdGFibGUgJT4lIHVuZ3JvdXAoKSAlPiUgc2VsZWN0KC1hZ2VuY3lfbmFtZSkgJT4lIGFycmFuZ2UoZGVzYyhwZXJjX3Jlc2lkZW50aWFsKSkgJT4lIHNlbGVjdChjbGVhbl9uYW1lLCBwZXJjX3Jlc2lkZW50aWFsLCBldmVyeXRoaW5nKCkpDQoNCnBpdm90X3RhYmxlICU+JSB1bmdyb3VwKCkgICU+JSBzZWxlY3QoLWFnZW5jeV9uYW1lKSAlPiUgc2VsZWN0KGNsZWFuX25hbWUsIHBlcmNfY2xhc3MyLCBwZXJjX2NsYXNzMywgcGVyY19yZXNpZGVudGlhbCwgZXZlcnl0aGluZygpKSU+JSBhcnJhbmdlKGRlc2MocGVyY19jbGFzczIpKQ0KDQojcGl2b3RfdGFibGUgJT4lIHVuZ3JvdXAoKSAgJT4lIHNlbGVjdCgtYWdlbmN5X25hbWUpJT4lIGFycmFuZ2UoZGVzYyhwZXJjX2NsYXNzMykpICU+JSBzZWxlY3QoY2xlYW5fbmFtZSwgcGVyY19jbGFzczMsIGV2ZXJ5dGhpbmcoKSkNCg0KI3dyaXRlX2NzdihwaXZvdF90YWJsZSwgIjNfZXhlbXB0aW9uX2RldGFpbHNfb3V0cHV0LXJlc2lkZW50aWFsX3BlcmNlbnRfQXVndXN0MTQuY3N2IikNCg0KcGl2b3RfdGFibGUgJT4lIGZpbHRlcihjbGVhbl9uYW1lICVpbiUgYygiUGFyayBGb3Jlc3QiLCJNYXJraGFtIiwgICJEb2x0b24iLCAiSGlsbHNpZGUiLCAiUml2ZXJzaWRlIiwgIkNoaWNhZ28iLCAiV2VzdGNoZXN0ZXIiLCAiV2lubmV0a2EiLCAiUm9zZW1vbnQiKSkgJT4lIHVuZ3JvdXAoKSAlPiUgc2VsZWN0KC1hZ2VuY3lfbmFtZSkgJT4lIHNlbGVjdChjbGVhbl9uYW1lLCBgQ2xhc3MgMmA6cGVyY19yZXNpZGVudGlhbCwgbXVuaV9lYXYsIG11bmlfYXYpDQpgYGANCg0KYGBge3J9DQojIHN1bSBvZiBhbGwgQ2xhc3MgMiBwcm9wZXJ0eSBFQVYNCmNsYXNzMl9FQVYgPC0gdGFibGUyICU+JSB1bmdyb3VwKCkgJT4lIGZpbHRlcihncm91cGVkX2NsYXNzZXMgPT0gIkNsYXNzIDIiKSAlPiUgc3VtbWFyaXplKHJlc2lkZW50aWFsX2VhdiA9IHN1bShlYXYpKQ0KDQpgYGANCg0KVGhlcmUgaXMgYHIgc2NhbGVzOjpkb2xsYXIoYXMubnVtZXJpYyhjbGFzczJfRUFWKSlgIGluIENsYXNzIDIgUmVzaWRlbnRpYWwgRUFWIGluIENvb2sgQ291bnR5DQoNCj4gRmlsZSBgM19leGVtcHRpb25fZGV0YWlsc19vdXRwdXQtcmVzaWRlbnRpYWxfcGVyY2VudC5jc3ZgIGhhcyB0aGUgcGVyY2VudCBvZiBFQVYgYmVmb3JlIGV4ZW1wdGlvbnMgYnV0IGRvZXMgTk9UIGFsdGVyIEVBViB0aGF0IGlzIGluIFRJRnMuIFRJRnMgYXJlIGVzc2VudGlhbGx5IGlnbm9yZWQgaW4gdGhpcyBmaWxlLiBUaGlzIGFtb3VudCBvZiBUYXhhYmxlIFJlc2lkZW50aWFsIEVBViB2cyBSZXNpZGVudGlhbCBFQVYgaXMgcXVpdGUgZGlmZmVyZW50IGZvciBzb21lIG11bmljaXBhbGl0aWVzLg0KDQoNCmBgYHtyIGVjaG89RkFMU0V9DQoNCkNvb2tfbGF5ZXIgPC0gZ2dwbG90KGRhdGEgPSBjb29rX3NocCwgYWVzKGdlb21ldHJ5ID0gZ2VvbWV0cnkpKSArIA0KICBnZW9tX3NmX3BhdHRlcm4oKSArIHRoZW1lX3ZvaWQoKQ0KDQoNCnBpdm90X3RhYmxlICU+JQ0KICBmdWxsX2pvaW4obXVuaV9zaHAsIGJ5ID0gYygiYWdlbmN5X25hbWUiID0gIkFHRU5DWV9ERVNDIikpICU+JSANCg0KICBnZ3Bsb3QoYWVzKGZpbGwgPSBwZXJjX2NsYXNzMikpICsgDQogIGdlb21fc2YoYWVzKGdlb21ldHJ5ID0gZ2VvbWV0cnkpLCBjb2xvciA9ICJibGFjayIpICsgDQogIGxhYnModGl0bGUgPSAiQ2xhc3MgMiBQcm9wZXJ0aWVzIEVBViAvIE11bmkgRUFWIiwgDQogIGNhcHRpb24gPSAiNjcuNiAlIG9mIEVBViBpcyBmcm9tIENsYXNzIDIgUHJvcGVydGllcyBpbiB0aGUgbWVkaWFuIG11bmljaXBhbGl0eSIpICsNCiAgdGhlbWVfdm9pZCgpICsgDQogIHRoZW1lKGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSkrIyArIysNCiAgc2NhbGVfZmlsbF9zdGVwczIoDQogICAgIGhpZ2ggPSAgICIjMkVFQThDIiwgbG93ID0gIiMyMDIyM0UiLCBtaWQgPSAiI0Y5RUNFOCIsDQoNCiAjICAgaGlnaCA9ICJkYXJrZ3JlZW4iLCBsb3cgPSAicmVkIiwNCiAgICBtaWRwb2ludCA9IG1lZGlhbihwaXZvdF90YWJsZSRwZXJjX2NsYXNzMiwgbmEucm0gPSBUUlVFKSwNCg0KICAgbmljZS5icmVha3MgPSBGQUxTRSwNCiAgIyAgc2hvdy5saW1pdHM9VFJVRSwNCiAgbmEudmFsdWUgPSAid2hpdGUiLA0KICAgIG5hbWUgPSAiJSBDbGFzcyAyIiwNCiAgICBsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQNCiAgKQ0KDQpwaXZvdF90YWJsZSAlPiUNCiAgZnVsbF9qb2luKG11bmlfc2hwLCBieSA9IGMoImFnZW5jeV9uYW1lIiA9ICJBR0VOQ1lfREVTQyIpKSAlPiUgDQogIGdncGxvdChhZXMoZmlsbCA9IChwZXJjX290aGVyKSkpICsgDQogIGdlb21fc2YoYWVzKGdlb21ldHJ5ID0gZ2VvbWV0cnkpLCBjb2xvciA9ICJibGFjayIpICsgDQogICAgbGFicyh0aXRsZSA9ICJOb24tcmVzaWRlbnRpYWwgUHJvcGVydHkgRUFWIC8gIFRvdGFsIEVBViBpbiBNdW5pY2lwYWxpdHkiLCANCiAgY2FwdGlvbiA9ICJOb25yZXNpZGVudGlhbCBpbmNsdWRlcyBhbGwgcHJvZXBydHkgY2xhc3NlcyBiZXNpZGVzIDIgJiAzLiANCiAgMzMuNyUgb2YgRUFWIGlzIGZyb20gY2xhc3NlcyBiZXNpZGVzIDIgJiAzIGluIHRoZSBtZWRpYW4gbXVuaWNpcGFsaXR5LiIpICsNCiAgdGhlbWVfdm9pZCgpICsgDQogIHRoZW1lKGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSkrDQogIHNjYWxlX2ZpbGxfc3RlcHMyKA0KICAjICBoaWdoID0gICIjRTg4QzIzIiwgbG93ID0gIiM0MjY3MzciLCBtaWQgPSIjRkFGM0NFIiwNCiBsb3cgPSAgICIjMkVFQThDIiwgaGlnaCA9ICIjMjAyMjNFIiwgbWlkID0gIiNGOUVDRTgiLA0KICAgbWlkcG9pbnQgPSBtZWRpYW4ocGl2b3RfdGFibGUkcGVyY19vdGhlciwgbmEucm0gPSBUUlVFKSwNCiAgICBuaWNlLmJyZWFrcyA9IEZBTFNFLA0KICAgIHNob3cubGltaXRzPVRSVUUsDQogIG5hLnZhbHVlID0gTkEsDQogICAgbmFtZSA9ICIlIE5vbi1DbGFzcyAyIG9yIDMiLA0KICAgIGxhYmVscyA9IHNjYWxlczo6cGVyY2VudA0KICApDQoNCg0KDQpwaXZvdF90YWJsZSAlPiUNCiAgICBmaWx0ZXIoY2xlYW5fbmFtZSAhPSAiVW5pdmVyc2l0eSBQYXJrIikgJT4lDQogIGZ1bGxfam9pbihtdW5pX3NocCwgYnkgPSBjKCJhZ2VuY3lfbmFtZSIgPSAiQUdFTkNZX0RFU0MiKSkgJT4lIA0KICBnZ3Bsb3QoYWVzKGZpbGwgPSBwZXJjX2NsYXNzMykpICsgDQogIGdlb21fc2YoYWVzKGdlb21ldHJ5ID0gZ2VvbWV0cnkpLCBjb2xvciA9ICJibGFjayIpICsgDQogIGxhYnModGl0bGUgPSAiQ2xhc3MgMyBQcm9wZXJ0aWVzIEVBViAvIE11bmkgRUFWIiwgDQogIGNhcHRpb24gPSAiMS45JSBvZiBFQVYgaXMgZnJvbSBDbGFzcyAzIHByb3BlcnRpZXMgaW4gdGhlIG1lZGlhbiBtdW5pY2lwYWxpdHkuIA0KICBNdW5pY2lwYWxpdGllcyBoYXZlIGEgd2lkZSByYW5nZSBvZiBDbGFzcyAzIHBlcmNlbnQgbWFrZXVwLiIpICsNCiAgdGhlbWVfdm9pZCgpICsgDQogIHRoZW1lKGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSkrIyArIysNCiAgc2NhbGVfZmlsbF9zdGVwczIoDQogICAgI2hpZ2ggPSAiZGFya2JsdWUiLCBsb3cgPSAib3JhbmdlIiwNCiAgICAgaGlnaCA9ICAgIiMyRUVBOEMiLCBsb3cgPSAiIzIwMjIzRSIsICAgbWlkID0gIiNGOUVDRTgiLA0KICAgIG1pZHBvaW50ID0gDQogICAgICBtZWRpYW4ocGl2b3RfdGFibGUkcGVyY19jbGFzczMsIG5hLnJtID0gVFJVRSksDQogICAjbmljZS5icmVha3MgPSBGQUxTRSwNCiAgICMgc2hvdy5saW1pdHM9VFJVRSwNCiAgbmEudmFsdWUgPSAgTkEsDQogICAgbmFtZSA9ICIlIENsYXNzIDMiLA0KICAgIGxhYmVscyA9IHNjYWxlczo6cGVyY2VudA0KICApDQpgYGANCg0KT24gYXZlcmFnZSwgTXVuaWNpcGFsaXRpZXMgaGF2ZSBgciBzY2FsZXM6OnBlcmNlbnQobWVhbihwaXZvdF90YWJsZSRwZXJjX2NsYXNzMywgbmEucm09VFJVRSkpYCBvZiB0aGVpciBFQVYgZnJvbSBDbGFzcyAzIE11bHRpLUZhbWlseSBQcm9wZXJ0aWVzLg0KDQpPbiBhdmVyYWdlLCBNdW5pY2lwYWxpdGllcyBoYXZlIGByIHNjYWxlczo6cGVyY2VudChtZWFuKHBpdm90X3RhYmxlJHBlcmNfY2xhc3MyLCBuYS5ybT1UUlVFKSlgIG9mIHRoZWlyIEVBViBmcm9tIENsYXNzIDIgUmVzaWRlbnRpYWwgcHJvcGVydGllcy4gVGhpcyBwcm9wZXJ0eSBjbGFzcyBpbmNsdWRlcyBzaW5nbGUtZmFtaWx5IGhvbWVzLCBjb25kb3MsIGFuZCByZXNpZGVudGlhbCBhcGFydG1lbnRzLg0KDQpOb3cgZXhhbWluZSB0aGUgdGF4YWJsZSBiYXNlIGZvciBlYWNoIE11bmkuIFRoZSBUYXhhYmxlIEJhc2UgaXMgdGhlIEVBViB0aGF0IGlzIHRheGFibGUgZm9yIHRoZSBtdW5pY2lwYWxpdHkgYW5kIGhhcyBUSUYgaW5jcmVtZW50cyBhbmQgZXhlbXB0aW9ucyBzdWJ0cmFjdGVkIGZyb20gdGhlIG9yaWdpbmFsIHJlc2lkZW50aWFsIEVBVi4NCg0KYGBge3J9DQoNCmdyb3VwZWRfZXhlbXB0aW9ucyA8LSBleGVtcHRpb25zX2J5X2NsYXNzX3Blcl9UQyAlPiUgDQogICAjIGdyb3VwX2J5KGFnZW5jeV9uYW1lLCBtYWpvcl9jbGFzc19jb2RlLCBtYWpvcl9jbGFzc190eXBlLCBSZXNpZGVudGlhbFByb3BzLCBQcm9wVHlwZSkgJT4lDQogIGdyb3VwX2J5KGNsZWFuX25hbWUsIGdyb3VwZWRfY2xhc3NlcywgYWdlbmN5X25hbWUpICU+JQ0KICBzdW1tYXJpemUoZWF2ID0gc3VtKGVhdiksDQogICAgICAgICAgIGV4ZW1wdF9FQVYgPSBzdW0oZXhlbXB0X0VBViwgZXhlX2FiYXRlLCBuYS5ybT1UUlVFKSwNCiAgICAgICAgIHRheF9iYXNlX2N1cnJlbnQgPSBzdW0odGF4X2Jhc2VfY3VycmVudCwgbmEucm09VFJVRSksDQogICAgICAgICB0YXhfYmFzZV9ub2V4ZW1wcyA9IHN1bSh0YXhfYmFzZV9ub2V4ZW1wcywgbmEucm09VFJVRSkpICU+JSB1bmdyb3VwKCkNCiAgDQoNCiMgY2FsY3VsYXRlIHRvdGFscyB3aXRoIE9OTFkgRUFWIG91dHNpZGUgb2YgVElGcw0KbXVuaV9lYXYgPC0gZ3JvdXBlZF9leGVtcHRpb25zICU+JSAgDQogIGdyb3VwX2J5KGNsZWFuX25hbWUsIGFnZW5jeV9uYW1lKSAlPiUgDQogIHN1bW1hcml6ZShtdW5pX0VBVl9pbmNsdWRlc1RJRiA9IHN1bShlYXYpLCAjIGFsbCBFQVYgaW4gdGhlIG11bmljaXBhbGl0eSB0aGF0IGV4aXN0cw0KICAgICAgICAgICAgbXVuaV90YXhfYmFzZV9jdXJyZW50PXN1bSh0YXhfYmFzZV9jdXJyZW50KSwgIyB0YXhhYmxlIEVBViBiYXNlZCBvbiBjdXJyZW50IGV4ZW1wdGlvbnMNCiAgICAgICAgICAgIG11bmlfdGF4X2Jhc2Vfbm9leGVtcHMgPSBzdW0odGF4X2Jhc2Vfbm9leGVtcHMpKSAlPiUgICMgdGF4YWJsZSBFQVYgcHJlLWV4ZW1wdGlvbnMNCiAgdW5ncm91cCgpIA0KDQpwY3RfcHJvcGVydHlfdHlwZXMgPC0gbGVmdF9qb2luKGdyb3VwZWRfZXhlbXB0aW9ucywgbXVuaV9lYXYpICU+JSANCiAgI2ZpbHRlcihSZXNpZGVudGlhbFByb3BzID09ICJSZXNpZGVudGlhbCIpICU+JSANCiAgbXV0YXRlKHBjdF9Qcm9wVHlwZSA9IGVhdiAvIG11bmlfRUFWX2luY2x1ZGVzVElGKSMgJT4lIHNlbGVjdCgpDQoNCnBjdF9wcm9wZXJ0eV90eXBlcyAlPiUgdW5ncm91cCgpICU+JSBzZWxlY3QoLWFnZW5jeV9uYW1lKSAlPiUgc2VsZWN0KE11bmljaXBhbGl0eSA9IGNsZWFuX25hbWUsIFByb3BlcnR5Q2xhc3MgPSBncm91cGVkX2NsYXNzZXMsIHBjdF9Qcm9wVHlwZSwgZXZlcnl0aGluZygpKQ0KDQpwY3RfcHJvcGVydHlfdHlwZXMgJT4lIHVuZ3JvdXAoKSAlPiUgc2VsZWN0KC1hZ2VuY3lfbmFtZSkgICU+JSBmaWx0ZXIoY2xlYW5fbmFtZSAlaW4lIGMoIlBhcmsgRm9yZXN0IiwgIkRvbHRvbiIsIkhpbGxzaWRlIiwgIlJpdmVyc2lkZSIsIkNoaWNhZ28iLCAiV2VzdGNoZXN0ZXIiLCAiTWFya2hhbSIsICJXaW5uZXRrYSIsICJSb3NlbW9udCIpKQ0KDQpgYGANCmBgYHtyIGV2YWw9RkFMU0UsaW5jbHVkZT1GQUxTRX0NCmdyb3VwZWRfZXhlbXB0aW9uczIgPC0gZXhlbXB0aW9uc19ieV9jbGFzc19wZXJfVEMgJT4lIA0KICAgIyBncm91cF9ieShhZ2VuY3lfbmFtZSwgbWFqb3JfY2xhc3NfY29kZSwgbWFqb3JfY2xhc3NfdHlwZSwgUmVzaWRlbnRpYWxQcm9wcywgUHJvcFR5cGUpICU+JQ0KICBncm91cF9ieShjbGVhbl9uYW1lLCBncm91cGVkX2NsYXNzZXMsIG1ham9yX2NsYXNzX2NvZGUsIGFnZW5jeV9uYW1lKSAlPiUNCiAgc3VtbWFyaXplKGVhdiA9IHN1bShlYXYpLA0KICAgICAgICAgICBleGVtcHRfRUFWID0gc3VtKGV4ZW1wdF9FQVYsIGV4ZV9hYmF0ZSwgbmEucm09VFJVRSksDQogICAgICAgICB0YXhfYmFzZV9jdXJyZW50ID0gc3VtKHRheF9iYXNlX2N1cnJlbnQsIG5hLnJtPVRSVUUpLA0KICAgICAgICAgdGF4X2Jhc2Vfbm9leGVtcHMgPSBzdW0odGF4X2Jhc2Vfbm9leGVtcHMsIG5hLnJtPVRSVUUpKSAlPiUgdW5ncm91cCgpDQogIA0KDQojIGNhbGN1bGF0ZSB0b3RhbHMgd2l0aCBPTkxZIEVBViBvdXRzaWRlIG9mIFRJRnMNCm11bmlfZWF2IDwtIGdyb3VwZWRfZXhlbXB0aW9ucyAlPiUgIA0KICBncm91cF9ieShjbGVhbl9uYW1lLCBhZ2VuY3lfbmFtZSkgJT4lIA0KICBzdW1tYXJpemUobXVuaV9FQVZfaW5jbHVkZXNUSUYgPSBzdW0oZWF2KSwgIyBhbGwgRUFWIGluIHRoZSBtdW5pY2lwYWxpdHkgdGhhdCBleGlzdHMNCiAgICAgICAgICAgIG11bmlfdGF4X2Jhc2VfY3VycmVudD1zdW0odGF4X2Jhc2VfY3VycmVudCksICMgdGF4YWJsZSBFQVYgYmFzZWQgb24gY3VycmVudCBleGVtcHRpb25zDQogICAgICAgICAgICBtdW5pX3RheF9iYXNlX25vZXhlbXBzID0gc3VtKHRheF9iYXNlX25vZXhlbXBzKSkgJT4lICAjIHRheGFibGUgRUFWIHByZS1leGVtcHRpb25zDQogIHVuZ3JvdXAoKSANCg0KcGN0X3Byb3BlcnR5X3R5cGVzMiA8LSBsZWZ0X2pvaW4oZ3JvdXBlZF9leGVtcHRpb25zLCBtdW5pX2VhdikgJT4lIA0KICAjZmlsdGVyKFJlc2lkZW50aWFsUHJvcHMgPT0gIlJlc2lkZW50aWFsIikgJT4lIA0KICBtdXRhdGUocGN0X1Byb3BUeXBlID0gZWF2IC8gbXVuaV9FQVZfaW5jbHVkZXNUSUYpDQpwY3RfcHJvcGVydHlfdHlwZXMyDQpgYGANCg0KUGVyY2VudCBSZXNpZGVudGlhbCBpcyB0aGUgUmVzaWRlbnRpYWwgRUFWIChDbGFzcyAyIHByb3BlcnRpZXMpIG91dHNpZGUgb2YgVElGcyAvIE11bmljaXBhbGl0eSBFQVYgb3V0c2lkZSBvZiBUSUZzLg0KDQpgYGB7cn0NCmdyb3VwZWRfZXhlbXB0aW9ucyA8LSBleGVtcHRpb25zX2J5X2NsYXNzX3Blcl9UQyAlPiUgDQogICBncm91cF9ieShjbGVhbl9uYW1lLCBtYWpvcl9jbGFzc19jb2RlLCBtYWpvcl9jbGFzc190eXBlLCBhZ2VuY3lfbmFtZSkgJT4lDQogICNncm91cF9ieShjbGVhbl9uYW1lLCBSZXNpZGVudGlhbFByb3BzLCBhZ2VuY3lfbmFtZSwgYWdlbmN5X251bS54KSAlPiUNCiAgc3VtbWFyaXplKGVhdiA9IHN1bShlYXYpLA0KICAgICAgICAgICBleGVtcHRfRUFWID0gc3VtKGV4ZW1wdF9FQVYsIGV4ZV9hYmF0ZSwgbmEucm09VFJVRSksDQogICAgICAgICB0YXhfYmFzZV9jdXJyZW50ID0gc3VtKHRheF9iYXNlX2N1cnJlbnQsIG5hLnJtPVRSVUUpLA0KICAgICAgICAgdGF4X2Jhc2Vfbm9leGVtcHMgPSBzdW0odGF4X2Jhc2Vfbm9leGVtcHMsIG5hLnJtPVRSVUUpKSAlPiUgDQogIHVuZ3JvdXAoKSAlPiUgDQogIHNlbGVjdChjbGVhbl9uYW1lLCBlYXYsIGV4ZW1wdF9FQVYsIGV2ZXJ5dGhpbmcoKSkNCiAgDQoNCiMgY2FsY3VsYXRlIHRvdGFscyB3aXRoIE9OTFkgRUFWIG91dHNpZGUgb2YgVElGcw0KbXVuaV9lYXYgPC0gZ3JvdXBlZF9leGVtcHRpb25zICU+JSAgDQogIGdyb3VwX2J5KGNsZWFuX25hbWUsIGFnZW5jeV9uYW1lKSAlPiUNCiAgc3VtbWFyaXplKG11bmlfRUFWX2luY2x1ZGVzVElGID0gc3VtKGVhdiksICMgYWxsIEVBViBpbiB0aGUgbXVuaWNpcGFsaXR5IHRoYXQgZXhpc3RzDQogICAgICAgICAgICBtdW5pX3RheF9iYXNlX2N1cnJlbnQ9c3VtKHRheF9iYXNlX2N1cnJlbnQpLCAjIHRheGFibGUgRUFWIGJhc2VkIG9uIGN1cnJlbnQgZXhlbXB0aW9ucw0KICAgICAgICAgICAgbXVuaV90YXhfYmFzZV9ub2V4ZW1wcyA9IHN1bSh0YXhfYmFzZV9ub2V4ZW1wcykpICU+JSAgIyB0YXhhYmxlIEVBViBwcmUtZXhlbXB0aW9ucw0KICB1bmdyb3VwKCkgDQoNCg0KDQojIyBQZXJjZW50IFJlc2lkZW50aWFsIGlzIHRoZSBzYW1lIGFzIHBlcmNlbnQgdGhhdCBpcyBDbGFzcyA9PSAyLiANCiMjIFBlcmNlbnQgcmVzaWRlbnRpYWwgZG9lcyBub3QgaW5jbHVkZSBNdWx0aS1mYW1pbHkgcHJvcGVydHkgY2xhc3MgMyBvciA5Lg0KcGVyY19yZXNpZGVudGlhbCA8LSBsZWZ0X2pvaW4oZ3JvdXBlZF9leGVtcHRpb25zLCBtdW5pX2VhdikgJT4lIA0KICBmaWx0ZXIobWFqb3JfY2xhc3NfY29kZSA9PSAiMiIpICU+JSANCiAgbXV0YXRlKHBlcmNlbnRfcmVzaWRlbnRpYWwgPSBlYXYgLyBtdW5pX0VBVl9pbmNsdWRlc1RJRikjICU+JSBzZWxlY3QoKQ0KIyAxMTkgbXVuaWNpcGFsaXRpZXMgcmVtYWluLiBTb21lIG11bmlzIGRvIG5vdCBoYXZlIHJlc2lkZW50aWFsIGVhdiBhbmQgYXJlIGRyb3BwZWQuDQoNCiMgaW4gdGhpcyBzdGFnZSwgQmVuc2VudmlsbGUsIEVhc3QgRHVuZGVlLCBhbmQgSG9tZXIgR2xlbiB3ZXJlIGRyb3BwZWQuIFRoaXMgaXMgZmluZSBiZWNhdXNlIEkgd2FzIGdvaW5nIHRvIGRyb3AgdGhlbSBsYXRlciBhbnl3YXlzLiBUaGV5IGRvbid0IGhhdmUgcmVzaWRlbnRpYWwgRUFWIHdpdGhpbiBDb29rIENvdW50eS4NCg0KcGVyY19yZXNpZGVudGlhbCAlPiUgYXJyYW5nZShkZXNjKHBlcmNlbnRfcmVzaWRlbnRpYWwpKSAlPiUgDQogIHNlbGVjdCgtYyhtYWpvcl9jbGFzc19jb2RlLCBtYWpvcl9jbGFzc190eXBlLCBhZ2VuY3lfbmFtZSkpICU+JSAgIyBkcm9wIHRoZXNlIGFuZCByZW9yZGVyDQogIHNlbGVjdChjbGVhbl9uYW1lLCBwZXJjZW50X3Jlc2lkZW50aWFsLCBldmVyeXRoaW5nKCkpDQoNCg0KcGVyY19yZXNpZGVudGlhbCAlPiUgDQogIyBncm91cF9ieShSZXNpZGVudGlhbFByb3BzKSU+JQ0KICAgIG11dGF0ZShhZ2VuY3lfbmFtZSA9IGlmZWxzZShhZ2VuY3lfbmFtZSA9PSAiVE9XTiBDSUNFUk8iLCAiQ0lUWSBPRiBDSUNFUk8iLCBhZ2VuY3lfbmFtZSkgKSAlPiUNCiAgZnVsbF9qb2luKG11bmlfc2hwLCBieSA9IGMoImFnZW5jeV9uYW1lIiA9ICJBR0VOQ1lfREVTQyIpKSAlPiUNCiAgZ2dwbG90KGFlcyhmaWxsID0gcGVyY2VudF9yZXNpZGVudGlhbCkpICsgDQogIGdlb21fc2YoYWVzKGdlb21ldHJ5ID0gZ2VvbWV0cnkpLCBjb2xvciA9ICJibGFjayIpICsgDQogIGxhYnModGl0bGUgPSAiUmVzaWRlbnRpYWwgRUFWIC8gIFRvdGFsIEVBViIsIA0KICBjYXB0aW9uID0gIlJlc2lkZW50aWFsIFByb3BlcnR5IGluY2x1ZGVzIDIwMCBsZXZlbCBwcm9wZXJ0eSBjbGFzc2VzLg0KICAgICAgIFRoZSBtZWRpYW4gbXVuaWNpcGFsaXR5IGhhcyA2NyUgb2YgaXRzIEVBViBmcm9tIENsYXNzIDIgUHJvcGVydGllcy4iKSArDQogICAgdGhlbWVfdm9pZCgpICsgDQogIHRoZW1lKGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSkrIyArIysNCiAgICBzY2FsZV9maWxsX3N0ZXBzMigNCiAgICBoaWdoID0gImRhcmtibHVlIiwgbG93ID0gImJsYWNrIiwgDQogICAgbWlkID0gImJlaWdlIiwgIyAgZ3VpZGUgPSAibGVnZW5kIiwNCiAgICAgIG1pZHBvaW50ID0gbWVkaWFuKHBlcmNfcmVzaWRlbnRpYWwkcGVyY2VudF9yZXNpZGVudGlhbCksDQogICAgICAgICAgIG5hLnZhbHVlID0gTkEsICAgDQogICAgICAgICAgICAgICAgICAgICAgIG4uYnJlYWtzID0gNiwNCiAgc2hvdy5saW1pdHM9VFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiJSBSZXNpZGVudGlhbCIsDQogIGxhYmVscyA9IHNjYWxlczo6cGVyY2VudCkNCmBgYA0KDQojIFRheGFibGUgQmFzZSAmIExhbmQgVXNlDQoNCmBgYHtyfQ0KVENfYmlsbHNfY3VycmVudCA8LSByZWFkX2NzdigiMl9TdW1tZWRfQmlsbHNfYnlfVGF4Y29kZV9hbmRfQ2xhc3MuY3N2IikgJT4lIA0KICBmaWx0ZXIoY2xhc3MgIT0gIjAiKSAlPiUgDQogIG11dGF0ZSh0YXhfY29kZSA9IGFzLmNoYXJhY3Rlcih0YXhfY29kZSksDQogICAgICAgICBjbGFzcyA9IGFzLmNoYXJhY3RlcihjbGFzcykpDQoNCmNsYXNzX2RpY3QkY2xhc3NfY29kZSA8LSBhcy5jaGFyYWN0ZXIoY2xhc3NfZGljdCRjbGFzc19jb2RlKQ0KIA0KDQp0YXhjb2Rlc19jdXJyZW50IDwtIGZ1bGxfam9pbihUQ19iaWxsc19jdXJyZW50LCBtdW5pX3RheF9jb2RlcywgDQogICAgICAgICAgICAgICAgICAgICAgYnkgPSBjKCJ0YXhfY29kZSIgPSAidGF4X2NvZGVfbnVtIikpICAgJT4lIGZpbHRlcighYWdlbmN5X251bSAlaW4lIGNyb3NzX2NvdW50eV9saW5lcykNCg0KDQoNCnRheGNvZGVzX2N1cnJlbnQgJT4lIA0KICBsZWZ0X2pvaW4obXVuaV9hZ2VuY3lfbmFtZXMpICU+JQ0KICBsZWZ0X2pvaW4obmlja25hbWVzLCBieSA9IGMoImFnZW5jeV9uYW1lIiA9ICJhZ2VuY3lfbmFtZSIpKSAlPiUgDQogIGZpbHRlcihjbGVhbl9uYW1lICVpbiUgYygiUGFyayBGb3Jlc3QiLCJNYXJraGFtIiwgICJEb2x0b24iLCAiSGlsbHNpZGUiLCAiUml2ZXJzaWRlIiwgIkNoaWNhZ28iLCAiV2VzdGNoZXN0ZXIiLCAiV2lubmV0a2EiKSkgJT4lIHVuZ3JvdXAoKSAlPiUgc2VsZWN0KC1jKGFnZW5jeV9uYW1lLCBDb2x1bW4xLCBgTW9zdCByZWNlbnQgcmVhc3Nlc3NlZGAsIHNocGZpbGVfbmFtZSwgc2hvcnRfbmFtZSxhZ2VuY3lfbnVtYmVyLCkpDQpgYGANCmBgYHtyIG11bmlzd2l0aGNsYXNzOCwgaW5jbHVkZSA9IEZBTFNFLCBldmFsPUZBTFNFfQ0KDQp0YXhjb2Rlc19jdXJyZW50ICU+JSANCiAgbGVmdF9qb2luKG11bmlfYWdlbmN5X25hbWVzKSAlPiUNCiAgbGVmdF9qb2luKG5pY2tuYW1lcywgYnkgPSBjKCJhZ2VuY3lfbmFtZSIgPSAiYWdlbmN5X25hbWUiKSkgJT4lDQogICNmaWx0ZXIoIWFnZW5jeV9udW0gJWluJSBjcm9zc19jb3VudHlfbGluZXMpICU+JQ0KICBncm91cF9ieShjbGVhbl9uYW1lLCBhZ2VuY3lfbmFtZSkgJT4lIGZpbHRlcihjbGFzcyA+PSA4MDAgJiAgY2xhc3MgPD0gOTAwKSAlPiUgDQogIGdyb3VwX2J5KGNsZWFuX25hbWUpICU+JSBkaXN0aW5jdChjbGVhbl9uYW1lKQ0KYGBgDQoNCiMjIENvbXBvc2l0ZSBUYXggUmF0ZXMNCg0KYGBge3J9DQpDdXJyZW50X1RheHJhdGVzIDwtIHRheGNvZGVzX2N1cnJlbnQgJT4lIA0KICBmaWx0ZXIoIWFnZW5jeV9udW0gJWluJSBjcm9zc19jb3VudHlfbGluZXMpICU+JQ0KICBsZWZ0X2pvaW4obXVuaV9hZ2VuY3lfbmFtZXMpICU+JQ0KICBsZWZ0X2pvaW4obmlja25hbWVzLCBieSA9IGMoImFnZW5jeV9uYW1lIiA9ICJhZ2VuY3lfbmFtZSIpKSAlPiUNCiAgI2ZpbHRlcighYWdlbmN5X251bSAlaW4lIGNyb3NzX2NvdW50eV9saW5lcykgJT4lDQogIGdyb3VwX2J5KGNsZWFuX25hbWUsIGFnZW5jeV9uYW1lKSAlPiUNCiAgc3VtbWFyaXplKE11bmlMZXZ5ID0gc3VtKGZpbmFsX3RheF90b19kaXN0LCBuYS5ybSA9IFRSVUUpLCAjIGFtb3VudCBiaWxsZWQgYnkgbXVuaXMgd2l0aCBjdXJyZW50IGV4ZW1wdGlvbnMgaW4gcGxhY2UNCiAgICAgICAgICAgIG5vblRJRl9FQVZfcG9zdF9leGVtcHMgPSBzdW0oZmluYWxfdGF4X3RvX2Rpc3QvKHRheF9jb2RlX3JhdGUvMTAwKSwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgICAgIFRJRl9pbmNyZW1lbnRfRUFWID0gc3VtKGZpbmFsX3RheF90b190aWYvKHRheF9jb2RlX3JhdGUvMTAwKSwgbmEucm09VFJVRSksICANCiAgICAgICAgICAgIEV4ZW1wdF9FQVYgPSBzdW0odGF4X2FtdF9leGUvKHRheF9jb2RlX3JhdGUvMTAwKSwgbmEucm09VFJVRSksIA0KICAgICAgICAgICAgVG90YWxfRUFWID0gc3VtKCh0YXhfYW10X2V4ZStmaW5hbF90YXhfdG9fZGlzdCtmaW5hbF90YXhfdG9fdGlmKS8odGF4X2NvZGVfcmF0ZS8xMDApLCBuYS5ybSA9IFRSVUUpKSAlPiUNCg0KICBtdXRhdGUodGF4X3JhdGVfY3VycmVudCA9IE11bmlMZXZ5L25vblRJRl9FQVZfcG9zdF9leGVtcHMsDQogICAgICAgICBub25USUZfRUFWX3ByZV9leGVtcHMgPSBub25USUZfRUFWX3Bvc3RfZXhlbXBzICsgRXhlbXB0X0VBViwNCiAgICAgICAgIHRheHJhdGVfbmV3ID0gTXVuaUxldnkvbm9uVElGX0VBVl9wcmVfZXhlbXBzLA0KICAgICAgICAgdGF4cmF0ZV9jaGFuZ2UgPSB0YXhfcmF0ZV9jdXJyZW50LXRheHJhdGVfbmV3KSAlPiUgDQogIHNlbGVjdChjbGVhbl9uYW1lLCB0YXhyYXRlX2NoYW5nZSwgdGF4X3JhdGVfY3VycmVudCwgdGF4cmF0ZV9uZXcsIGV2ZXJ5dGhpbmcoKSkgJT4lIA0KICBhcnJhbmdlKGRlc2ModGF4X3JhdGVfY3VycmVudCkpDQoNCkN1cnJlbnRfVGF4cmF0ZXMgJT4lICBmaWx0ZXIoY2xlYW5fbmFtZSAlaW4lIGMoIlBhcmsgRm9yZXN0IiwiTWFya2hhbSIsICAiRG9sdG9uIiwgIkhpbGxzaWRlIiwgIlJpdmVyc2lkZSIsICJDaGljYWdvIiwgIldlc3RjaGVzdGVyIiwgIldpbm5ldGthIiwgIlJvc2Vtb250IikpICU+JSBzZWxlY3QoLWFnZW5jeV9uYW1lKQ0KDQoNCmxhbmRfdXNlIDwtIHRheGNvZGVzX2N1cnJlbnQgJT4lIA0KICBsZWZ0X2pvaW4obXVuaV9hZ2VuY3lfbmFtZXMpICU+JSANCiAgbGVmdF9qb2luKEN1cnJlbnRfVGF4cmF0ZXMpICU+JQ0KICBsZWZ0X2pvaW4oY2xhc3NfZGljdCwgYnkgPSBjKCJjbGFzcyIgPSAiY2xhc3NfY29kZSIpKSAlPiUNCiAgDQojICBtdXRhdGUoY2xhc3NfMWRpZyA9IHN0cl9zdWIoY2xhc3MsIDEsIDEpLA0KIyAgICBSZXNpZGVudGlhbFByb3BzID0gaWZlbHNlKGNsYXNzXzFkaWcgJWluJSBjKCIyIiwgIjMiLCAiOSIpLCAiUmVzaWRlbnRpYWwiLCAiTm9uLVJlc2lkZW50aWFsIikpICU+JQ0KICAjICAgICAgICBQcm9wVHlwZSA9IGNhc2Vfd2hlbigNCiAgIyAgICAgICAgICBtYWpvcl9jbGFzc19jb2RlICVpbiUgYygiMyIsIjkiKSB+ICJNdWx0aS1GYW1pbHkiLA0KICAjICAgICAgICAgIG1ham9yX2NsYXNzX2NvZGUgPT0gIjIiIH4gIlNpbmdsZS1GYW1pbHkiLA0KICAjICAgICAgICAgIFRSVUUgfiAiQ29tbWVyY2lhbC1JbmR1c3RyaWFsIikpICU+JQ0KICBncm91cF9ieShjbGVhbl9uYW1lLCBtYWpvcl9jbGFzc19jb2RlLCBhZ2VuY3lfbnVtLCB0YXhfcmF0ZV9jdXJyZW50LCB0YXhyYXRlX25ldywgdGF4cmF0ZV9jaGFuZ2UsIGFnZW5jeV9uYW1lKSAlPiUgDQogIA0KICAjIEFsbCBvZiB0aGUgdmFsdWVzIGNhbGN1bGF0ZWQgYmVsb3cgYXJlIEFGVEVSIGV4ZW1wdGlvbnMgaGF2ZSBiZWVuIHJlbW92ZWQNCiAgc3VtbWFyaXplKHRheHJldl9mcm9tX3Byb3B0eXBlID0gc3VtKGZpbmFsX3RheF90b19kaXN0LCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgbm9uVElGX0VBViA9IHN1bShmaW5hbF90YXhfdG9fZGlzdC8odGF4X2NvZGVfcmF0ZS8xMDApLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgVElGX2luY3JlbWVudF9FQVYgPSBzdW0oZmluYWxfdGF4X3RvX3RpZi8odGF4X2NvZGVfcmF0ZS8xMDApLCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIEV4ZW1wdF9FQVYgPSBzdW0odGF4X2FtdF9leGUvKHRheF9jb2RlX3JhdGUvMTAwKSwgbmEucm09VFJVRSksDQogICAgICAgICAgICBUb3RhbF9FQVYgPSBzdW0oKHRheF9hbXRfZXhlK2ZpbmFsX3RheF90b19kaXN0K2ZpbmFsX3RheF90b190aWYpLyh0YXhfY29kZV9yYXRlLzEwMCksIG5hLnJtID0gVFJVRSkgKSAlPiUgdW5ncm91cCgpDQoNCmxhbmRfdXNlICU+JSBmaWx0ZXIoY2xlYW5fbmFtZSAlaW4lIGMoICJEb2x0b24iLCAiQ2hpY2FnbyIsICJXaW5uZXRrYSIpKSAlPiUgc2VsZWN0KC1hZ2VuY3lfbmFtZSkNCg0KDQpgYGANCg0KDQpgYGB7ciBGaWd1cmUtQVdNMX0NCiMgbWFkZSBpbiBFeGNlbCBvcmlnaW5hbGx5DQoNCkN1cnJlbnRfVGF4cmF0ZXMgJT4lICBmaWx0ZXIoY2xlYW5fbmFtZSAlaW4lIGMoIlBhcmsgRm9yZXN0IiwiRG9sdG9uIiwgIkhpbGxzaWRlIiwgIlJpdmVyc2lkZSIsICJDaGljYWdvIiwgIldpbm5ldGthIiwgIlJvc2Vtb250IikpICU+JSBzZWxlY3QoY2xlYW5fbmFtZSwgdGF4X3JhdGVfY3VycmVudCwgdGF4cmF0ZV9uZXcpICU+JSBwaXZvdF9sb25nZXIoY29scyA9IGModGF4X3JhdGVfY3VycmVudCx0YXhyYXRlX25ldyksIG5hbWVzX3RvID0gIm5hbWVzIiwgdmFsdWVzX3RvID0gInZhbHVlcyIpICAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gY2xlYW5fbmFtZSwgeSA9IHZhbHVlcywgZmlsbCA9IG5hbWVzKSkgKw0KICBnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZSIgKSArIHRoZW1lX2NsYXNzaWMoKSArIGxhYnMoeD0iIiwgeSA9ICJDb21wb3NpdGUgVGF4IFJhdGUiKQ0KDQoNCkN1cnJlbnRfVGF4cmF0ZXMgJT4lICBmaWx0ZXIoY2xlYW5fbmFtZSAlaW4lIGMoIk1hcmtoYW0iLCAiQ2hpY2FnbyIsICJXZXN0Y2hlc3RlciIsICJXaW5uZXRrYSIpKSAlPiUgc2VsZWN0KGNsZWFuX25hbWUsIHRheF9yYXRlX2N1cnJlbnQsIHRheHJhdGVfbmV3KSAlPiUgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKHRheF9yYXRlX2N1cnJlbnQsdGF4cmF0ZV9uZXcpLCBuYW1lc190byA9ICJuYW1lcyIsIHZhbHVlc190byA9ICJ2YWx1ZXMiKSAgJT4lDQogIGdncGxvdChhZXMoeCA9IGNsZWFuX25hbWUsIHkgPSB2YWx1ZXMsIGZpbGwgPSBuYW1lcykpICsNCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAiZG9kZ2UiICkgKyB0aGVtZV9jbGFzc2ljKCkgKyBsYWJzKHg9IiIsIHkgPSAiQ29tcG9zaXRlIFRheCBSYXRlIikNCg0KYGBgDQoNCmBgYHtyIHJlc3VsdHM9J2hvbGQnLCBvdXQud2lkdGg9ICI1MCUiLCBlY2hvPUZBTFNFfQ0KIyANCiMgYnVyZGVuX3NoaWZ0ICU+JSANCiMgICBmaWx0ZXIobWFqb3JfY2xhc3NfY29kZSA9PSAyKSAlPiUNCiMgICBzdW1tYXJpemUobWVkaWFuX2N1cnJlbnRidXJkZW4gPSBtZWRpYW4oYnVyZGVuX2N1cnJlbnQpLA0KIyAgICAgICAgICAgICBtZWRpYW5fbmV3X2J1cmRlbiA9IG1lZGlhbihidXJkZW5fbm9leGVtcHMpLA0KIyAgICAgICAgICAgICBtZWRpYW5fYnVyZGVuY2hhbmdlID0gbWVkaWFuKGJ1cmRlbl9jaGFuZ2UpLA0KIyAgICAgICAgICAgICBtZWRpYW5fY3VycmVudHRheHJhdGUgPSBtZWRpYW4odGF4X3JhdGVfY3VycmVudCksDQojICAgICAgICAgICAgIG1lZGlhbl90YXhyYXRlY2hhbmdlID0gbWVkaWFuKHRheHJhdGVfY2hhbmdlKSwNCiMgICAgICAgICAgICAgbWVkaWFuX3RheHJhdGVuZXcgPSBtZWRpYW4odGF4cmF0ZV9uZXcpKSAlPiUgDQojICAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBldmVyeXRoaW5nKCksIG5hbWVzX3RvID0gIlZhcmlhYmxlIiwgdmFsdWVzX3RvID0gIk1lZGlhbiBWYWx1ZSIpDQoNCg0KQ3VycmVudF9UYXhyYXRlcyAlPiUgDQogICAgbXV0YXRlKGFnZW5jeV9uYW1lID0gaWZlbHNlKGFnZW5jeV9uYW1lID09ICJUT1dOIENJQ0VSTyIsICJDSVRZIE9GIENJQ0VSTyIsIGFnZW5jeV9uYW1lKSANCiAgICApICU+JQ0KICBmdWxsX2pvaW4obXVuaV9zaHAsIGJ5ID0gYygiYWdlbmN5X25hbWUiID0gIkFHRU5DWV9ERVNDIikpICU+JQ0KICANCiAgZ2dwbG90KGFlcyhmaWxsID0gdGF4X3JhdGVfY3VycmVudCkpICsNCiAgZ2VvbV9zZihhZXMoZ2VvbWV0cnkgPSBnZW9tZXRyeSksIGNvbG9yID0gImJsYWNrIikgKyANCiAgdGhlbWVfdm9pZCgpICsgDQogIHRoZW1lKGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSkrDQogIHNjYWxlX2ZpbGxfc3RlcHMyKCNjb2xvcnMgPSBjb2xvcnMsDQogICAgaGlnaCA9ICJwbHVtNCIsIGxvdyA9ICIjMDA4MDgwIiwjIG1pZCA9ICJsYXZlbmRlcmJsdXNoMiIsDQogICAgbWlkcG9pbnQgPSBtZWRpYW4oQ3VycmVudF9UYXhyYXRlcyR0YXhfcmF0ZV9jdXJyZW50KSwgIyAgbWlkcG9pbnQgPSAwLjEyMywNCiAgICAjYnJlYWtzID0gYnJlYWtzX3NkLA0KICAgIGxpbWl0cyA9IGMoMCwuNDUpLA0KICAgIHNob3cubGltaXRzPVRSVUUsDQogICAgbmEudmFsdWUgPSBOQSwNCiAgICBuaWNlLmJyZWFrcz1GQUxTRSwNCiAgICBuID02LA0KICAgIG5hbWUgPSAiVGF4IFJhdGUiLA0KICAgIGxhYmVsID0gc2NhbGVzOjpwZXJjZW50ICkrDQogIA0KICBsYWJzKHRpdGxlID0gIkN1cnJlbnQgY29tcG9zaXRlIHRheCByYXRlcyIgLCAgICANCiAgICAgICBjYXB0aW9uID0gIlRoZSBjdXJyZW50IG1lZGlhbiBjb21wb3NpdGUgdGF4IHJhdGUgaXMgMTIuMSUuIA0KICAgICAgICAgSGlnaGVzdCBjb21wb3NpdGUgdGF4IHJhdGUgaXMgaW4gUGFyayBGb3Jlc3QgKDQxLjQlLikNCiAgICAgICBMb3dlc3QgY29tcG9zaXRlIHRheCByYXRlIGlzIGluIENoaWNhZ28gKDYuNyUpLiIpDQoNCkN1cnJlbnRfVGF4cmF0ZXMgJT4lIA0KICAgICAgbXV0YXRlKGFnZW5jeV9uYW1lID0gaWZlbHNlKGFnZW5jeV9uYW1lID09ICJUT1dOIENJQ0VSTyIsICJDSVRZIE9GIENJQ0VSTyIsIGFnZW5jeV9uYW1lKSANCiAgICApICU+JQ0KICBmdWxsX2pvaW4obXVuaV9zaHAsIGJ5ID0gYygiYWdlbmN5X25hbWUiID0gIkFHRU5DWV9ERVNDIikpICU+JQ0KICBnZ3Bsb3QoYWVzKGZpbGwgPSB0YXhyYXRlX25ldykpICsgDQogIHRoZW1lX3ZvaWQoKSArIA0KICB0aGVtZShheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCkpKw0KICBzY2FsZV9maWxsX3N0ZXBzMigNCiAgICBoaWdoID0gInBsdW00IiwgbG93ID0gIiMwMDgwODAiLA0KICAgIGxpbWl0cyA9IGMoMCwuNDUpLA0KICAgIG1pZHBvaW50ID0gbWVkaWFuKEN1cnJlbnRfVGF4cmF0ZXMkdGF4cmF0ZV9uZXcpLCAgIyBtaWRwb2ludCA9IC4xMDUyLA0KICAgIG5pY2UuYnJlYWtzPUZBTFNFLA0KICAgIHNob3cubGltaXRzPVRSVUUsDQogICAgbmEudmFsdWU9TkEsDQogICAgbj02LA0KICAgIG5hbWUgPSAiVGF4IFJhdGUiLCBsYWJlbCA9IHNjYWxlczo6cGVyY2VudCkrDQogIGdlb21fc2YoYWVzKGdlb21ldHJ5ID0gZ2VvbWV0cnkpLCBjb2xvciA9ICJibGFjayIpICsgIA0KICBsYWJzKHRpdGxlID0gIk5ldyBjb21wb3NpdGUgdGF4IHJhdGVzIGlmIGV4ZW1wdGlvbnMgd2VyZSBlbGltaW5hdGVkIiAsICAgIA0KICAgICAgIGNhcHRpb24gPSAiVGhlIG5ldyBtZWRpYW4gY29tcG9zaXRlIHRheCByYXRlIHdvdWxkIGJlIGFwcHJveGltYXRlbHkgMTAuNSUgDQogICAgICAgaWYgZXhlbXB0aW9ucyB3ZXJlIHJlbW92ZWQuIikNCmBgYA0KDQpgYGB7ciBGaWd1cmUtQVdNMiwgZWNobz1GQUxTRX0NCkN1cnJlbnRfVGF4cmF0ZXMgJT4lIA0KICBtdXRhdGUoYWdlbmN5X25hbWUgPSBpZmVsc2UoYWdlbmN5X25hbWUgPT0gIlRPV04gQ0lDRVJPIiwgIkNJVFkgT0YgQ0lDRVJPIiwgYWdlbmN5X25hbWUpICkgJT4lDQogICMgZmlsdGVyKGNsZWFuX25hbWUgIT0gIlBhcmsgRm9yZXN0IikgJT4lDQogIGZ1bGxfam9pbihtdW5pX3NocCwgYnkgPSBjKCJhZ2VuY3lfbmFtZSIgPSAiQUdFTkNZX0RFU0MiKSkgJT4lDQogIGdncGxvdChhZXMoZmlsbCA9IHRheHJhdGVfY2hhbmdlKSkgKyANCiAgZ2VvbV9zZihhZXMoZ2VvbWV0cnkgPSBnZW9tZXRyeSksIGNvbG9yID0gImJsYWNrIikgKyAgDQogIHRoZW1lX3ZvaWQoKSArIA0KICB0aGVtZShheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCkpKw0KICANCiAgc2NhbGVfZmlsbF9zdGVwczIoaGlnaCA9ICJibHVlIiwgbG93ID0gImJsYWNrIiwNCiAgICBuPTYsICNtaWRwb2ludCA9IDAuMDEzODgsIA0KICAgIHNob3cubGltaXRzPVRSVUUsDQogICAgbmljZS5icmVha3M9RkFMU0UsDQogICAgbmEudmFsdWUgPSBOQSwNCiAgICBsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQsDQogICAgbmFtZSA9ICJQZXJjZW50YWdlIFBvaW50IFxuRGlmZmVyZW5jZSIpKw0KICBsYWJzKHRpdGxlID0gIkNoYW5nZSBpbiBDb21wb3NpdGUgVGF4IFJhdGUgaWYgRXhlbXB0aW9ucyBhcmUgUmVtb3ZlZCIsDQogICAgICAgY2FwdGlvbiA9ICJUaGUgbWVkaWFuIGNoYW5nZSBpbiBjb21wb3NpdGUgdGF4IHJhdGUgaXMgMS40MyBwZXJjZW50YWdlIHBvaW50cyIpDQpgYGANCg0KIyMgUGVyY2VudCBvZiBSZXNpZGVudGlhbCBFQVYgdGhhdCBpcyB0YXggZXhlbXB0DQoNCkZvciB0aGlzIGRvY3VtZW50LCByZXNpZGVudGlhbCBFQVYgaW5jbHVkZXMgQ2xhc3MgMiBwcm9wZXJ0aWVzIG9ubHkuIFJlc2lkZW50aWFsIHByb3BlcnR5IGNhbiBiZSBpbiBhbmQgb3V0c2lkZSBvZiBhIFRJRi4gQW55IEVBViBncmVhdGVyIHRoYW4gdGhlIGZyb3plbiBFQVYgd2l0aGluIGEgVElGIGJlY29tZXMgVElGIHJldmVudWUgd2hlbiBpdCBpcyB0YXhlZC4gIFdlIHRyeSB0byBvbmx5IGluY2x1ZGUgdGhlIGZyb3plbiBFQVYgYW5kIG5vbi1USUYgRUFWIGluIG91ciByZXNpZGVudGlhbCBjYWxjdWxhdGlvbnMuIA0KDQpgYGB7cn0NCmV4ZW1wdGlvbnNfdG9fY2xhc3MyRUFWX3JhdGlvcyA8LSBwZXJjX3Jlc2lkZW50aWFsICU+JSANCiAgbXV0YXRlKGV4ZW1wdEVBVl9wY3RvZl9yZXNFQVYgPSBleGVtcHRfRUFWL2VhdiwNCiAgICAgICAgIGV4ZW1wdEVBVl9wY3RvZl90b3RhbEVBViA9IGV4ZW1wdF9FQVYgLyBtdW5pX0VBVl9pbmNsdWRlc1RJRiwNCiAgICAgICAgIGV4ZW1wdEVBVl9wY3RvZl90YXhiYXNlX2N1cnJlbnQgPSBleGVtcHRfRUFWIC8gdGF4X2Jhc2VfY3VycmVudCwNCiAgICAgICAgIGV4ZW1wdEVBVl9wY3RvZl90YXhiYXNlX25vZXhlbXBzID0gZXhlbXB0X0VBViAvIHRheF9iYXNlX25vZXhlbXBzLA0KICAgICAgICAgbm9udGlmX3JhdGlvID0gZXhlbXB0X0VBViAvIHRheF9iYXNlX25vZXhlbXBzKSAlPiUgDQogIHNlbGVjdChhZ2VuY3lfbmFtZSwgY2xlYW5fbmFtZSwgZXhlbXB0RUFWX3BjdG9mX3Jlc0VBViwgbm9udGlmX3JhdGlvLCBldmVyeXRoaW5nKCkpICU+JSANCiAgYXJyYW5nZShub250aWZfcmF0aW8pDQoNCmV4ZW1wdGlvbnNfdG9fY2xhc3MyRUFWX3JhdGlvcyAlPiUNCiAgICBtdXRhdGUoYWdlbmN5X25hbWUgPSBpZmVsc2UoYWdlbmN5X25hbWUgPT0gIlRPV04gQ0lDRVJPIiwgIkNJVFkgT0YgQ0lDRVJPIiwgYWdlbmN5X25hbWUpICkgJT4lDQogZnVsbF9qb2luKG11bmlfc2hwLCBieSA9IGMoImFnZW5jeV9uYW1lIiA9ICJBR0VOQ1lfREVTQyIpKSAlPiUNCiAgZ2dwbG90KGFlcyhmaWxsID0gZXhlbXB0RUFWX3BjdG9mX3Jlc0VBVikpICsgDQogIGdlb21fc2YoYWVzKGdlb21ldHJ5ID0gZ2VvbWV0cnkpLCBjb2xvciA9ICJibGFjayIpICsgdGhlbWVfdm9pZCgpKyANCiAgbGFicyh0aXRsZSA9ICJFeGVtcHRpb25zIC8gUmVzaWRlbnRpYWwgRUFWIChpbiBhbmQgb3V0IG9mIFRJRnMpIikgKw0KICAgIHRoZW1lX3ZvaWQoKSArIA0KICB0aGVtZShheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCkpKw0KICAgc2NhbGVfZmlsbF9zdGVwczIoaGlnaCA9ICJkYXJrYmx1ZSIsIGxvdyA9ICJibGFjayIsICBtaWQgPSAiYmVpZ2UiLA0KICAgICAgICAgICAgICAgICAgICAgICMgbGltaXRzID0gYygwLC44KSwNCiAgICAgICAgICAgICAgICAgICAgICAgbi5icmVha3MgPSA3LCBzaG93LmxpbWl0cz1UUlVFLA0KICAgICAgICAgICAgICAgICAgICAgICBuYS52YWx1ZSA9IE5BLA0KICAgICAgICAgICAgICAgICAgICBuaWNlLmJyZWFrcyA9IEZBTFNFLA0KICAgICAgICAgICAgICAgICAgICBtaWRwb2ludCA9IG1lZGlhbihleGVtcHRpb25zX3RvX2NsYXNzMkVBVl9yYXRpb3MkZXhlbXB0RUFWX3BjdG9mX3Jlc0VBViksDQogICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gIiUgUmVzaWRlbnRpYWwgRUFWIFxudGhhdCBpcyBleGVtcHQiLCBsYWJlbCA9IHNjYWxlczo6cGVyY2VudCkNCmBgYA0KDQpgYGB7ciwgZmlnLnNob3c9J2hvbGQnLCBvdXQud2lkdGg9IjUwJSJ9DQpleGVtcHRpb25zX3RvX2NsYXNzMkVBVl9yYXRpb3MgJT4lDQogIG11dGF0ZShhZ2VuY3lfbmFtZSA9IGlmZWxzZShhZ2VuY3lfbmFtZSA9PSAiVE9XTiBDSUNFUk8iLCAiQ0lUWSBPRiBDSUNFUk8iLCBhZ2VuY3lfbmFtZSkgKSAlPiUNCiAgZnVsbF9qb2luKG11bmlfc2hwLCBieSA9IGMoImFnZW5jeV9uYW1lIiA9ICJBR0VOQ1lfREVTQyIpKSAlPiUNCiAgZ2dwbG90KGFlcyhmaWxsID0gbm9udGlmX3JhdGlvKSkgKyANCiAgZ2VvbV9zZihhZXMoZ2VvbWV0cnkgPSBnZW9tZXRyeSksIGNvbG9yID0gImJsYWNrIikgKyB0aGVtZV92b2lkKCkrIA0KICBsYWJzKHRpdGxlID0gIk5vbi1USUYgRUFWIG9ubHk6IEhvbWVzdGVhZCBFeGVtcHRpb25zIC8gUmVzaWRlbnRpYWwgRUFWIiwgY2FwdGlvbiA9ICJWaWxsYWdlIG9mIFBob2VuaXggc2tld3MgZ3JhcGguIERyb3BwZWQgaW4gbWFwIGJlbG93IikgKw0KICB0aGVtZV92b2lkKCkgKyANCiAgdGhlbWUoYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpKSsNCiAgc2NhbGVfZmlsbF9zdGVwczIoaGlnaCA9ICJkYXJrYmx1ZSIsIGxvdyA9ICJibGFjayIsIG1pZD0iYmVpZ2UiLA0KICAgICAgICAgICAgICAgICAgICAjY29sb3JzID0gYygid2hpdGUiLCAiZGFya2JsdWUiKSwgDQogICAgICAgICAgICAgICAgICAgICMgbGltaXRzID0gYygwKSwNCiAgICAgICAgICAgICAgICAgICAgbWlkcG9pbnQgPSBtZWRpYW4oZXhlbXB0aW9uc190b19jbGFzczJFQVZfcmF0aW9zJG5vbnRpZl9yYXRpbyksDQogICAgICAgICAgICAgICAgICAgIG4uYnJlYWtzID0gNSwgDQogICAgICAgICAgICAgICAgICAgIG5hLnZhbHVlID0gTkEsDQogICAgICAgICAgICAgICAgICAgIHNob3cubGltaXRzPVRSVUUsDQogICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiJSBSZXNpZGVudGlhbCBFQVYgXG50aGF0IGlzIGV4ZW1wdCIsIGxhYmVsID0gc2NhbGVzOjpwZXJjZW50KSArIA0KICBsYWJzKCBjYXB0aW9uID0gIk1lZGlhbiB2YWx1ZSBpcyAyMC4wJSAiKQ0KDQoNCmV4ZW1wdGlvbnNfdG9fY2xhc3MyRUFWX3JhdGlvcyAlPiUNCiAgbXV0YXRlKGFnZW5jeV9uYW1lID0gaWZlbHNlKGFnZW5jeV9uYW1lID09ICJUT1dOIENJQ0VSTyIsICJDSVRZIE9GIENJQ0VSTyIsIGFnZW5jeV9uYW1lKSApICU+JQ0KICBmdWxsX2pvaW4obXVuaV9zaHAsIGJ5ID0gYygiYWdlbmN5X25hbWUiID0gIkFHRU5DWV9ERVNDIikpICU+JQ0KICBnZ3Bsb3QoYWVzKGZpbGwgPSBub250aWZfcmF0aW8pKSArIA0KICBnZW9tX3NmKGFlcyhnZW9tZXRyeSA9IGdlb21ldHJ5KSwgY29sb3IgPSAiYmxhY2siKSArIHRoZW1lX3ZvaWQoKSsgDQogIGxhYnModGl0bGUgPSAiTm9uLVRJRiBFQVYgb25seTogSG9tZXN0ZWFkIEV4ZW1wdGlvbnMgLyBSZXNpZGVudGlhbCBFQVYiLCBjYXB0aW9uID0gIlZpbGxhZ2Ugb2YgUGhvZW5peCBza2V3cyBncmFwaC4gRHJvcHBlZCBpbiBtYXAgYmVsb3ciKSArDQogIHRoZW1lX3ZvaWQoKSArIA0KICB0aGVtZShheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCkpKw0KICBzY2FsZV9maWxsX3N0ZXBzMihoaWdoID0gImRhcmtibHVlIiwgbG93ID0gImJsYWNrIixtaWQgPSJiZWlnZSIsDQogICAgICAgICAgICAgICAgICAgICNjb2xvcnMgPSBjKCJ3aGl0ZSIsICJkYXJrYmx1ZSIpLCANCiAgICAgICAgICAgICAgICAgICAgIyBsaW1pdHMgPSBjKDApLA0KICAgICAgICAgICAgICAgICAgICBtaWRwb2ludCA9IG1lZGlhbihleGVtcHRpb25zX3RvX2NsYXNzMkVBVl9yYXRpb3Mkbm9udGlmX3JhdGlvKSwNCiAgICAgICAgICAgICAgICAgICAgbi5icmVha3MgPSA3LCANCiAgICAgICAgICAgICAgICAgICAgbmEudmFsdWUgPSBOQSwNCiAgICAgICAgICAgICAgICAgICAgc2hvdy5saW1pdHM9VFJVRSwNCiAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICIlIFJlc2lkZW50aWFsIEVBViBcbnRoYXQgaXMgZXhlbXB0IiwgbGFiZWwgPSBzY2FsZXM6OnBlcmNlbnQpICsgDQogIGxhYnMoIGNhcHRpb24gPSAiTWVkaWFuIHZhbHVlIGlzIDIwLjAlICIpDQpgYGANCg0KYGBge3IgLCBmaWcuc2hvdz0naG9sZCcsIG91dC53aWR0aD0iNTAlIn0NCmV4ZW1wdGlvbnNfdG9fY2xhc3MyRUFWX3JhdGlvcyAlPiUgIGZpbHRlcihub250aWZfcmF0aW88LjYpICU+JQ0KICAgIG11dGF0ZShhZ2VuY3lfbmFtZSA9IGlmZWxzZShhZ2VuY3lfbmFtZSA9PSAiVE9XTiBDSUNFUk8iLCAiQ0lUWSBPRiBDSUNFUk8iLCBhZ2VuY3lfbmFtZSkgKSAlPiUNCiAgZnVsbF9qb2luKG11bmlfc2hwLCBieSA9IGMoImFnZW5jeV9uYW1lIiA9ICJBR0VOQ1lfREVTQyIpKSAlPiUNCiAgZ2dwbG90KGFlcyhmaWxsID0gbm9udGlmX3JhdGlvKSkgKyANCiAgZ2VvbV9zZihhZXMoZ2VvbWV0cnkgPSBnZW9tZXRyeSksIGNvbG9yID0gImJsYWNrIikgKyB0aGVtZV92b2lkKCkrIA0KICBsYWJzKHRpdGxlID0gIlBlcmNlbnQgb2YgUmVzaWRlbnRpYWwgRUFWIHRoYXQgaXMgVGF4IEV4ZW1wdCIsIA0KICAgICAgIHN1YnRpdGxlID0gIiUgb2YgTm9uLVRJRiBSZXNpZGVudGlhbCBFQVYgb25seTogXG5Ib21lc3RlYWQgRXhlbXB0aW9ucyAvIFJlc2lkZW50aWFsIEVBViIsIA0KICAgICAgIGNhcHRpb24gPSAiIikgKw0KICB0aGVtZV92b2lkKCkgKyANCiAgdGhlbWUoYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpKSsNCiAgc2NhbGVfZmlsbF9zdGVwczIoaGlnaCA9ICJkYXJrYmx1ZSIsIGxvdyA9ICJibGFjayIsbWlkID0iYmVpZ2UiLA0KICAgICAgICAgICAgICAgICAgICAjICBjb2xvcnMgPSBjKCJ3aGl0ZSIsICJkYXJrYmx1ZSIpLCANCiAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygwLC40KSwNCiAgICAgICAgICAgICAgICAgICAgbmEudmFsdWUgPSBOQSwNCiAgICAgICAgICAgICAgICAgICAgbWlkcG9pbnQgPSBtZWRpYW4oZXhlbXB0aW9uc190b19jbGFzczJFQVZfcmF0aW9zJG5vbnRpZl9yYXRpbyksDQogICAgICAgICAgICAgICAgICAgIG4uYnJlYWtzID0gNSwgc2hvdy5saW1pdHM9VFJVRSwNCiAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICIlIFJlc2lkZW50aWFsIEVBViBcbnRoYXQgaXMgdGF4IGV4ZW1wdCIsIGxhYmVsID0gc2NhbGVzOjpwZXJjZW50KQ0KDQoNCmV4ZW1wdGlvbnNfdG9fY2xhc3MyRUFWX3JhdGlvcyAlPiUgIGZpbHRlcihub250aWZfcmF0aW88LjYpICU+JQ0KICBtdXRhdGUoYWdlbmN5X25hbWUgPSBpZmVsc2UoYWdlbmN5X25hbWUgPT0gIlRPV04gQ0lDRVJPIiwgIkNJVFkgT0YgQ0lDRVJPIiwgYWdlbmN5X25hbWUpICkgJT4lDQogIGZ1bGxfam9pbihtdW5pX3NocCwgYnkgPSBjKCJhZ2VuY3lfbmFtZSIgPSAiQUdFTkNZX0RFU0MiKSkgJT4lDQogIGdncGxvdChhZXMoZmlsbCA9IG5vbnRpZl9yYXRpbykpICsgDQogIGdlb21fc2YoYWVzKGdlb21ldHJ5ID0gZ2VvbWV0cnkpLCBjb2xvciA9ICJibGFjayIpICsgdGhlbWVfdm9pZCgpKyANCiAgbGFicyh0aXRsZSA9ICJQZXJjZW50IG9mIFJlc2lkZW50aWFsIEVBViB0aGF0IGlzIFRheCBFeGVtcHQiLCANCiAgICAgICBzdWJ0aXRsZSA9ICIlIG9mIE5vbi1USUYgUmVzaWRlbnRpYWwgRUFWIG9ubHk6IFxuSG9tZXN0ZWFkIEV4ZW1wdGlvbnMgLyBSZXNpZGVudGlhbCBFQVYiLCANCiAgICAgICBjYXB0aW9uID0gIiIpICsNCiAgdGhlbWVfdm9pZCgpICsgDQogIHRoZW1lKGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSkrDQogIHNjYWxlX2ZpbGxfc3RlcHMyKGhpZ2ggPSAiZGFya2JsdWUiLCBsb3cgPSAiYmxhY2siLG1pZCA9ImJlaWdlIiwNCiAgICAgICAgICAgICAgICAgICAgIyAgY29sb3JzID0gYygid2hpdGUiLCAiZGFya2JsdWUiKSwgDQogICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoMCwuNCksDQogICAgICAgICAgICAgICAgICAgIG5hLnZhbHVlID0gTkEsDQogICAgICAgICAgICAgICAgICAgIG1pZHBvaW50ID0gbWVkaWFuKGV4ZW1wdGlvbnNfdG9fY2xhc3MyRUFWX3JhdGlvcyRub250aWZfcmF0aW8pLA0KICAgICAgICAgICAgICAgICAgICBuLmJyZWFrcyA9IDcsIHNob3cubGltaXRzPVRSVUUsDQogICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiJSBSZXNpZGVudGlhbCBFQVYgXG50aGF0IGlzIHRheCBleGVtcHQiLCBsYWJlbCA9IHNjYWxlczo6cGVyY2VudCkNCmBgYA0KDQpEcm9wcyBWaWxsYWdlIG9mIFBob2VuaXggYmVjYXVzZSBpdCBza2V3cyBtYXAgY29sb3JzICg3OCUgb2YgdGhlaXIgcmVzaWRlbnRpYWwgRUFWIGlzIHRheCBleGVtcHQpLiBNZWRpYW4gbXVuaWNpcGFsaXR5IGNhbiBub3QgZ2V0IHRheCByZXZlbnVlIGZyb20gMS81dGggb2YgdGhlaXIgcmVzaWRlbnRpYWwgRUFWIGR1ZSB0byBleGVtcHRpb25zLiAyMC44NSUgb2YgU2luZ2xlLWZhbWlseSBob21lIEVBViBpcyBub3QgdGF4ZWQgYW5kIHRyYW5zZmVycmVkIHRvIG90aGVyIHRheCBwYXllcnMuDQoNCkluIENvb2sgQ291bnR5IHRoZXJlIGlzIGByIHNjYWxlczo6ZG9sbGFyKHN1bShwZXJjX3Jlc2lkZW50aWFsJHRheF9iYXNlX2N1cnJlbnQpKWAgaW4gQ2xhc3MgMiBSZXNpZGVudGlhbCBQcm9wZXJ0eSBFQVYuDQoNClRoZXJlIGlzIGByIHNjYWxlczo6ZG9sbGFyKHN1bShwZXJjX3Jlc2lkZW50aWFsJHRheF9iYXNlX25vZXhlbXBzKSlgIGluIENsYXNzIDIgUmVzaWRlbnRpYWwgUHJvcGVydHkgRUFWIGJlZm9yZSBhbGwgZXhlbXB0aW9ucy4NCg0KVGhlIFRvdGFsIEVBViBmb3IgQ29vayBDb3VudHkgYHIgc2NhbGVzOjpkb2xsYXIoc3VtKHBlcmNfcmVzaWRlbnRpYWwkbXVuaV9FQVZfaW5jbHVkZXNUSUYpKWAuIFRvdGFsIEVBViBpbmNsdWRlcyBUSUYgaW5jcmVtZW50IGFuZCBleGVtcHQgRUFWLg0KDQpUaGUgY3VycmVudCB0YXhhYmxlIEVBViBmb3IgQ29vayBDb3VudHkgYHIgc2NhbGVzOjpkb2xsYXIoc3VtKHBlcmNfcmVzaWRlbnRpYWwkbXVuaV90YXhfYmFzZV9jdXJyZW50KSlgLg0KDQpUaGUgaHlwb3RoZXRpY2FsIHRheGFibGUgRUFWIGZvciBDb29rIENvdW50eSBgciBzY2FsZXM6OmRvbGxhcihzdW0ocGVyY19yZXNpZGVudGlhbCRtdW5pX3RheF9iYXNlX25vZXhlbXBzKSlgLg0KDQoNCiMgQnVyZGVuIFNoaWZ0DQoNCmBgYHtyfQ0KYnVyZGVuX3RhYmxlIDwtIHBjdF9wcm9wZXJ0eV90eXBlcyAlPiUNCiAgZmlsdGVyKCFpcy5uYShjbGVhbl9uYW1lKSkgJT4lDQogIGxlZnRfam9pbihDdXJyZW50X1RheHJhdGVzLCBieSA9IGMoImFnZW5jeV9uYW1lIiwgImNsZWFuX25hbWUiKSkgJT4lDQogIG11dGF0ZShyZXZfY29sbGVjdGVkX2N1cnJlbnQgPSB0YXhfYmFzZV9jdXJyZW50ICogdGF4X3JhdGVfY3VycmVudCwNCiAgICAgICAgIHJldl9jb2xsZWN0ZWRfbmV3ID0gdGF4X2Jhc2Vfbm9leGVtcHMqdGF4cmF0ZV9uZXcsDQogICAgICAgICBidXJkZW5fY3VycmVudCA9IHJldl9jb2xsZWN0ZWRfY3VycmVudC9NdW5pTGV2eSwNCiAgICAgICAgIGJ1cmRlbl9ub2V4ZW1wcyA9IHJldl9jb2xsZWN0ZWRfbmV3L011bmlMZXZ5LA0KICAgICAgICAgYnVyZGVuX2NoYW5nZSA9IGJ1cmRlbl9ub2V4ZW1wcy0gYnVyZGVuX2N1cnJlbnQsDQogICAgICAgICBidXJkZW5fbm9leGVtcHMgPSBpZmVsc2UoYnVyZGVuX25vZXhlbXBzID4xLCAxLCBidXJkZW5fbm9leGVtcHMpKSAlPiUNCiAgbXV0YXRlKGJ1cmRlbl9jdXJyZW50ID0gaWZlbHNlKGlzLm5hKGJ1cmRlbl9jdXJyZW50KSwgMCwgYnVyZGVuX2N1cnJlbnQpLA0KICAgICAgICAgYnVyZGVuX25vZXhlbXBzID0gaWZlbHNlKGlzLm5hKGJ1cmRlbl9ub2V4ZW1wcyksIDAsIGJ1cmRlbl9ub2V4ZW1wcykpICU+JQ0KICBtdXRhdGUoYnVyZGVuX25vZXhlbXBzID0gaWZlbHNlKGJ1cmRlbl9ub2V4ZW1wcz4xLCAxLCBidXJkZW5fbm9leGVtcHMpLA0KICAgICAgICAgYnVyZGVuX2N1cnJlbnQgPSBpZmVsc2UoYnVyZGVuX2N1cnJlbnQ+MSwgMSwgYnVyZGVuX2N1cnJlbnQpKSAlPiUNCiAgbXV0YXRlKGFnZW5jeV9uYW1lID0gaWZlbHNlKGFnZW5jeV9uYW1lID09ICJUT1dOIENJQ0VSTyIsICJDSVRZIE9GIENJQ0VSTyIsIGFnZW5jeV9uYW1lKSApDQoNCg0KYnVyZGVuX3NoaWZ0IDwtIGJ1cmRlbl90YWJsZSAjIG9ubHkgdG8gbm90IGNoYW5nZSBjb2RlIGJlbG93IGluIGdyYXBocy4NCg0KDQpidXJkZW5fdGFibGUgJT4lIA0KICBhcnJhbmdlKGRlc2MoYnVyZGVuX2NoYW5nZSkpICU+JSANCiAgc2VsZWN0KGNsZWFuX25hbWUsIGJ1cmRlbl9jaGFuZ2UsIGV2ZXJ5dGhpbmcoKSkgJT4lDQogIG11dGF0ZShidXJkZW5fY2hhbmdlID0gcm91bmQoYnVyZGVuX2NoYW5nZSoxMDAsIGRpZ2l0cyA9IDIpKSAlPiUNCiAgc2VsZWN0KC1hZ2VuY3lfbmFtZSkNCg0KIyBDdXJyZW50IEJ1cmRlbjoNCg0KbXVuaXNfM3Byb3BlcnR5X3R5cGVzIDwtIGJ1cmRlbl9zaGlmdCAlPiUNCiAgICBmaWx0ZXIoIWFnZW5jeV9uYW1lICVpbiUgY3Jvc3NfY291bnR5X2xpbmVzKSAlPiUNCiMgbXV0YXRlKA0KICAgICAjICAgICAgIGJ1cmRlbl9ub2V4ZW1wcyA9IGlmZWxzZShpcy5uYShidXJkZW5fbm9leGVtcHMpLCAwLCBidXJkZW5fbm9leGVtcHMpKSAlPiUNCiAgIyAgICBtdXRhdGUoYnVyZGVuX2N1cnJlbnQgPSBpZmVsc2UoYnVyZGVuX2N1cnJlbnQ+MSwgMSwgYnVyZGVuX2N1cnJlbnQpKSAlPiUNCiAgdW5ncm91cCgpICU+JSANCiAgZ3JvdXBfYnkoYWdlbmN5X25hbWUsIGNsZWFuX25hbWUsIGdyb3VwZWRfY2xhc3NlcykgJT4lDQogIHN1bW1hcml6ZSgjZmluYWxfdGF4X3RvX2Rpc3QgPSBzdW0oZmluYWxfdGF4X3RvX2Rpc3QsIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgICBidXJkZW5fY3VycmVudCA9IHN1bShidXJkZW5fY3VycmVudCwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgICAgIGJ1cmRlbl9ub2V4ZW1wcyA9IHN1bShidXJkZW5fbm9leGVtcHMsIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgICBidXJkZW5fY2hhbmdlID0gc3VtKGJ1cmRlbl9jaGFuZ2UsIG5hLnJtID0gVFJVRSkpIA0KDQojd3JpdGUuY3N2KG11bmlzXzNwcm9wZXJ0eV90eXBlcywgIjFfdXNlbWV0YWJsZS5jc3YiKQ0KDQpwcm9wdHlwZXMzX2N1cnJlbnQgPC0gbXVuaXNfM3Byb3BlcnR5X3R5cGVzICU+JSANCiAgICBtdXRhdGUoYnVyZGVuX2N1cnJlbnQgPSBpZmVsc2UoaXMubmEoYnVyZGVuX2N1cnJlbnQpLCAwLCBidXJkZW5fY3VycmVudCkpICU+JQ0KDQogIHBpdm90X3dpZGVyKCBpZF9jb2xzID0gY2xlYW5fbmFtZSAsIG5hbWVzX2Zyb20gPSAiZ3JvdXBlZF9jbGFzc2VzIiwgdmFsdWVzX2Zyb20gPSAiYnVyZGVuX2N1cnJlbnQiLCBuYW1lc19wcmVmaXg9IkN1cnJlbnQgLSAiLCB2YWx1ZXNfZmlsbCA9IDAgKSAlPiUgDQogIHNlbGVjdChjbGVhbl9uYW1lLCBgQ3VycmVudCAtIENsYXNzIDJgLCBldmVyeXRoaW5nKCkpICU+JQ0KICBhcnJhbmdlKC1gQ3VycmVudCAtIENsYXNzIDJgKQ0KDQpwcm9wdHlwZXMzX2N1cnJlbnRbMjo0XSA8LSBzYXBwbHkocHJvcHR5cGVzM19jdXJyZW50WzI6NF0sIGZ1bmN0aW9uKHgpIHNjYWxlczo6cGVyY2VudCh4LCBhY2N1cmFjeT0uMDEpICkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQojcHJvcHR5cGVzM19jdXJyZW50DQoNCg0KIyBfX1RheCBCdXJkZW4gaWYgdGhlcmUgd2VyZSBubyBleGVtcHRpb25zOl9fDQoNCnByb3B0eXBlczNfbm9leGVtcHMgPC0gbXVuaXNfM3Byb3BlcnR5X3R5cGVzICU+JSANCiAgbXV0YXRlKGJ1cmRlbl9ub2V4ZW1wcyA9IGlmZWxzZShpcy5uYShidXJkZW5fbm9leGVtcHMpLCAwLCBidXJkZW5fbm9leGVtcHMpKSAlPiUNCiAgcGl2b3Rfd2lkZXIoIGlkX2NvbHMgPSBjbGVhbl9uYW1lICwgbmFtZXNfZnJvbSA9ICJncm91cGVkX2NsYXNzZXMiLCB2YWx1ZXNfZnJvbSA9ICJidXJkZW5fbm9leGVtcHMiLCANCiAgICAgICAgICAgICAgIG5hbWVzX3ByZWZpeCA9ICJXL08gRXhlbXB0aW9ucyAtICIsIHZhbHVlc19maWxsID0gMCkgIA0KcHJvcHR5cGVzM19ub2V4ZW1wc1syOjRdIDwtIHNhcHBseShwcm9wdHlwZXMzX25vZXhlbXBzWzI6NF0sIGZ1bmN0aW9uKHgpIHNjYWxlczo6cGVyY2VudCh4LCBhY2N1cmFjeT0uMDEpKQ0KI3Byb3B0eXBlczNfbm9leGVtcHMNCg0KYnVyZGVuXzNncm91cHNfY3VycmVudGFuZGh5cG90aGV0aWFsPC0gbGVmdF9qb2luKHByb3B0eXBlczNfY3VycmVudCwgcHJvcHR5cGVzM19ub2V4ZW1wcykNCmJ1cmRlbl8zZ3JvdXBzX2N1cnJlbnRhbmRoeXBvdGhldGlhbA0KDQpwcm9wc193aWRlIDwtIG11bmlzXzNwcm9wZXJ0eV90eXBlcyAlPiUNCiAgcGl2b3Rfd2lkZXIoaWRfY29scyA9IGNsZWFuX25hbWUgLCANCiAgICAgICAgICAgICAgIG5hbWVzX2Zyb20gPSAiZ3JvdXBlZF9jbGFzc2VzIiwgDQogICAgICAgICAgICAgICB2YWx1ZXNfZnJvbSA9ICJidXJkZW5fY2hhbmdlIiwgdmFsdWVzX2ZpbGwgPSAwKSAlPiUgDQogIHNlbGVjdChjbGVhbl9uYW1lLCBgQ2xhc3MgMmAsIGV2ZXJ5dGhpbmcoKSkgJT4lDQogIGFycmFuZ2UoZGVzYyhgQ2xhc3MgMmApICkNCg0KcHJvcHNfd2lkZVsyOjRdIDwtIHNhcHBseShwcm9wc193aWRlWzI6NF0sIGZ1bmN0aW9uKHgpIHNjYWxlczo6cGVyY2VudCh4LCBhY2N1cmFjeT0uMDEpKQ0KcHJvcHNfd2lkZQ0KYGBgDQoNCg0KDQpgYGB7ciBGaWd1cmUtQVdNLWRpcmVjdGluZGlyZWN0fQ0KcHJvcHNfd2lkZSAlPiUgIGZpbHRlcihjbGVhbl9uYW1lICVpbiUgYygiTWFya2hhbSIsICJDaGljYWdvIiwgIldlc3RjaGVzdGVyIiwgIldpbm5ldGthIikpDQpidXJkZW5fdGFibGUgICU+JSAgZmlsdGVyKGNsZWFuX25hbWUgJWluJSBjKCJNYXJraGFtIiwgIkNoaWNhZ28iLCAiV2VzdGNoZXN0ZXIiLCAiV2lubmV0a2EiKSklPiUgc2VsZWN0KGNsZWFuX25hbWUsIGJ1cmRlbl9jdXJyZW50OmJ1cmRlbl9jaGFuZ2UpICU+JSBwaXZvdF9sb25nZXIoY29scyA9IGMoYnVyZGVuX2N1cnJlbnQsIGJ1cmRlbl9ub2V4ZW1wcyksIG5hbWVzX3RvID0gIm5hbWVzIiwgdmFsdWVzX3RvID0gInZhbHVlcyIpICAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gY2xlYW5fbmFtZSwgeSA9IHZhbHVlcywgZmlsbCA9IG5hbWVzKSkgKw0KICBnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZSIgKSArIHRoZW1lX2NsYXNzaWMoKSArIGxhYnMoeD0iIiwgeT0iU2hhcmUgb2YgTGV2eSBQYWlkIGJ5IENsYXNzIDIiLCB0aXRsZSA9ICJDdXJyZW50IGFuZCBIeXBvdGhldGlhbCBUYXggQnVyZGVuIikNCmBgYA0KDQpgYGB7ciBGaWd1cmUtQVdNMy10YXhidXJkZW4tZG90Z3JhcGh9DQojIGFzIGEgZG90IGdyYXBoICMjIA0KDQpjcm9zc19jb3VudHlfbGluZXMgPC0gYygiMDMwNDQwMDAwIiwNCiIwMzA1ODUwMDAiLCAiMDMwODkwMDAwIiwgIjAzMDMyMDAwMCIsICIwMzEyODAwMDAiLCIwMzAwODAwMDAiLCAiMDMwNTYwMDAwIiwgIjAzMTEyMDAwMCIsICIwMzAyODAwMDAiLCAiMDMwMzQwMDAwIiwiMDMwMTUwMDAwIiwiMDMwMDUwMDAwIiwgIjAzMDE4MDAwMCIsIjAzMDUwMDAwMCIsIjAzMTIxMDAwMCIpDQoNCmNyb3NzX2NvdW50eV9saW5lcyA8LSBtdW5pX2FnZW5jeV9uYW1lcyAlPiUgZmlsdGVyKGFnZW5jeV9udW0gJWluJWNyb3NzX2NvdW50eV9saW5lcykgJT4lIGxlZnRfam9pbihuaWNrbmFtZXMsIGJ5ID0gImFnZW5jeV9uYW1lIikNCg0Kb3JkZXIgPC0gYnVyZGVuX3NoaWZ0ICU+JSANCiAgdW5ncm91cCAlPiUgYXNfdGliYmxlKCkgJT4lDQogICMgIGZpbHRlcihSZXNpZGVudGlhbFByb3BzID09ICJSZXNpZGVudGlhbCIpICU+JQ0KICBmaWx0ZXIoZ3JvdXBlZF9jbGFzc2VzID09ICJDbGFzcyAyIikgJT4lDQogIHNlbGVjdChhZ2VuY3lfbmFtZSwgY2xlYW5fbmFtZSwgYnVyZGVuX2N1cnJlbnQsIGJ1cmRlbl9jaGFuZ2UpDQoNCg0KDQojIGJ1cmRlcl9zaGlmdF9vcmRlcmVkIDwtICBidXJkZW5fc2hpZnQgJT4lIA0KIyAgIHVuZ3JvdXAoKSAlPiUgDQojICAgc2VsZWN0KGFnZW5jeV9uYW1lLCBjdXJyZW50X2J1cmRlbiwgbm9fZXhlbXB0aW9uc19idXJkZW4pICU+JSAgICANCiMgICBwaXZvdF9sb25nZXIoYygiY3VycmVudF9idXJkZW4iLCAibm9fZXhlbXB0aW9uc19idXJkZW4iKSwgDQojICAgICAgICAgICAgICAgIG5hbWVzX3RvID0gInR5cGUiLCB2YWx1ZXNfdG8gPSAicGN0X2J1cmRlbiIpICU+JSANCiMgICBsZWZ0X2pvaW4ob3JkZXIpDQoNCiMgbG9vayBhdCBvbmVzIHRoYXQgY2hhbmdlZCB0aGUgbW9zdA0KDQoNCiMgbWVkaWFuIGJ1cmRlbiBjIGhhbmdlIGlzIDAuNDUNCiMgY3VycmVudCBtZWRpYW4gYnVyZGVuIGlzIDY1LjUlIG9mIHRoZSBsZXZ5DQoNCmJ1cmRlbl9zaGlmdCAlPiUgDQogIGZpbHRlcighY2xlYW5fbmFtZSAlaW4lIGNyb3NzX2NvdW50eV9saW5lcyRjbGVhbl9uYW1lKSU+JQ0KICBmaWx0ZXIoZ3JvdXBlZF9jbGFzc2VzID09ICJDbGFzcyAyIikgJT4lDQogIGZpbHRlcihidXJkZW5fY3VycmVudCA+IDAuOTM4IHxidXJkZW5fY3VycmVudCA8IC4xNyB8DQogICAgICAgICAgICggKGJ1cmRlbl9jdXJyZW50IDwgbWVkaWFuKGJ1cmRlbl9jdXJyZW50KSArIDAuMDEgKSYgKGJ1cmRlbl9jdXJyZW50ID4gbWVkaWFuKGJ1cmRlbl9jdXJyZW50KSAtIDAuMDEpKSApJT4lIA0KICB1bmdyb3VwKCkgJT4lIA0KICBzZWxlY3QoYWdlbmN5X25hbWUsIGNsZWFuX25hbWUsIGJ1cmRlbl9jdXJyZW50LCBidXJkZW5fbm9leGVtcHMsICBidXJkZW5fY2hhbmdlKSAlPiUgDQogIGFycmFuZ2UoYnVyZGVuX2NoYW5nZSkgJT4lDQogIG11dGF0ZSggDQogICAgYnVyZGVuX25vZXhlbXBzID0gaWZlbHNlKGJ1cmRlbl9ub2V4ZW1wcyA+IDEsIDEsIGJ1cmRlbl9ub2V4ZW1wcykpICU+JQ0KICBwaXZvdF9sb25nZXIoYygiYnVyZGVuX2N1cnJlbnQiLCAiYnVyZGVuX25vZXhlbXBzIiksIA0KICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAidHlwZSIsIHZhbHVlc190byA9ICJwY3RfYnVyZGVuIikgJT4lIA0KICBpbm5lcl9qb2luKG9yZGVyKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gcGN0X2J1cmRlbioxMDAsIA0KICAgICAgICAgICAgIHk9IHJlb3JkZXIoY2xlYW5fbmFtZSwgLWJ1cmRlbl9jdXJyZW50KSkpKw0KICAjIHk9IHJlb3JkZXIoY2xlYW5fbmFtZSwgYnVyZGVuX2N1cnJlbnQpKSkrDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDY1LjUsIGxpbmV0eXBlID0gMykrDQogIGdlb21fbGluZShhZXMoZ3JvdXAgPSBjbGVhbl9uYW1lKSkrIA0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSA1LjUsIGxpbmV0eXBlID0gMikrDQogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDEzLjUsIGxpbmV0eXBlID0gMikrDQogIGdlb21fcG9pbnQoYWVzKGNvbG9yPXR5cGUpLCBzaXplPTMgKSsNCg0KICB0aGVtZV9taW5pbWFsKCkgKyANCiAgdGhlbWUoI2xlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgDQogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLA0KICAgIHBsb3QudGl0bGUucG9zaXRpb24gPSAicGxvdCIsDQogICAgIyAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD0ndHJhbnNwYXJlbnQnKSwgI3RyYW5zcGFyZW50IHBhbmVsIGJnDQogICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9J3RyYW5zcGFyZW50JywgY29sb3I9TkEpICN0cmFuc3BhcmVudCBwbG90IGJnDQogICkrDQogIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlPSJQYWlyZWQiLCBsYWJlbHMgPSBjKCJDdXJyZW50IEJ1cmRlbiIsICJCdXJkZW4gaWYgXG5ObyBFeGVtcHRpb25zIiApLCBkaXJlY3Rpb24gPSAxKSsNCg0KICANCiAgbGFicyh0aXRsZSA9ICJDaGFuZ2UgaW4gQ2xhc3MgMiBSZXNpZGVudGlhbCBUYXggQnVyZGVuIiwgDQogICAgICAgc3VidGl0bGUgPSAiT3JkZXJlZCBieSBDdXJyZW50IFRheCBCdXJkZW4iLA0KICB4ID0gIlNoYXJlIG9mIExldnkgKCUpIiwgeSA9ICIiICwgDQogIGNhcHRpb24gPSAiRG90dGVkIGxpbmUgcmVwcmVzZW50cyBtZWRpYW4gQ2xhc3MgMiBidXJkZW4gKDY1LjUlIG9mIHRoZSBsZXZ5KS4gUmVzaWRlbnRpYWwgVGF4IEJ1cmRlbiBpcyB0aGUgDQogIHNoYXJlIG9mIHRoZSBwcm9wZXJ0eSB0YXggY29sbGVjdGVkIHRoYXQgd2FzIHBhaWQgZm9yIGJ5IHByb3BlcnR5IG93bmVycyB3aXRoIENsYXNzIDIgcHJvcGVydGllcy4iKSArDQogICAgZ2VvbV9sYWJlbChsYWJlbCA9ICJDbGFzcyAyIHBheXMgc21hbGwgc2hhcmUgb2YgXG5sZXZ5OyB2ZXJ5IGxpdHRsZSByZXNpZGVudGlhbCIsIHg9MzIsIHkgPSAxNiwgbGFiZWwuc2l6ZSA9IDEsIHNpemUgPSAzKSsNCiAgICBnZW9tX2xhYmVsKGxhYmVsID0gIkNsYXNzIDIgcGF5cyBtZWRpYW4gc2hhcmUgb2YgXG5sZXZ5ICg2NSUpLCBtaXggb2YgbGFuZCB1c2UiLCB4PTQyLCB5ID0gOS41LCBsYWJlbC5zaXplID0gMSwgc2l6ZSA9IDMpICsNCiAgICBnZW9tX2xhYmVsKGxhYmVsID0gIkNsYXNzIDIgcGF5cyBuZWFybHkgYWxsIG9mIGxldnksIFxuaGlnaGx5IHJlc2lkZW50aWFsIiwgeD03MCwgeSA9IDMsIGxhYmVsLnNpemUgPSAxLHNpemUgPSAzKQ0KYGBgDQoNCg0KIyBIeXBvdGhldGljYWwgTWVkaWFuIFRheCBCaWxsIHdpdGhvdXQgRXhlbXB0aW9ucw0KDQpgYGB7cn0NCiNiaWxsX2NoYW5nZV8zZ3JvdXBzIDwtIHJlYWRfY3N2KCAiNF9UYXhiaWxsX0h5cG90aGV0aWNhbHMtdGF4YmlsbF9jaGFuZ2VfMjAyMzA4MTQuY3N2IikNCg0KI2JpbGxfY2hhbmdlXzNncm91cHMgJT4lIHNlbGVjdChNdW5pY2lwYWxpdHkgPSBjbGVhbl9uYW1lLCBiaWxsX2NoYW5nZSwgZXZlcnl0aGluZygpKSANCg0KDQp0YXhfYmlsbF9jaGFuZ2UgPC0gcmVhZF9jc3YoIjRfVGF4YmlsbF9IeXBvdGhldGljYWxzLXRheGJpbGxfY2hhbmdlX2ZvcmVhY2hQcm9wQ2xhc3NfcGVyTXVuaS5jc3YiKQ0KDQpgYGANCg0KDQojIyBDb21wb3NpdGUgVGF4IFJhdGVzDQoNCmBgYHtyfQ0KQ3VycmVudF9UYXhyYXRlcyAlPiUgDQogIG11dGF0ZShhZ2VuY3lfbmFtZSA9IGlmZWxzZShhZ2VuY3lfbmFtZSA9PSAiVE9XTiBDSUNFUk8iLCAiQ0lUWSBPRiBDSUNFUk8iLCBhZ2VuY3lfbmFtZSkgKSAlPiUNCiAgIyBmaWx0ZXIoY2xlYW5fbmFtZSAhPSAiUGFyayBGb3Jlc3QiKSAlPiUNCiAgZnVsbF9qb2luKG11bmlfc2hwLCBieSA9IGMoImFnZW5jeV9uYW1lIiA9ICJBR0VOQ1lfREVTQyIpKSAlPiUNCiAgZ2dwbG90KGFlcyhmaWxsID0gdGF4cmF0ZV9jaGFuZ2UqMTAwKSkgKyANCiAgZ2VvbV9zZihhZXMoZ2VvbWV0cnkgPSBnZW9tZXRyeSksIGNvbG9yID0gImJsYWNrIikgKyAgDQogIHRoZW1lX3ZvaWQoKSArIA0KICB0aGVtZShheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCkpKw0KICANCiAgc2NhbGVfZmlsbF9zdGVwczIoaGlnaCA9ICJkYXJrYmx1ZSIsIGxvdyA9ICJibGFjayIsIG1pZCA9ICJsaWdodGJsdWUiLA0KICAgICAgICAgICAgICAgICAgICBuPTcsIA0KICAgICAgICAgICAgICAgICAgICBtaWRwb2ludCA9IG1lZGlhbihDdXJyZW50X1RheHJhdGVzJHRheHJhdGVfY2hhbmdlKjEwMCksDQogICAgICAgICAgICAgICAgICMgICBtaWRwb2ludCA9IDAuMDEzODgsIA0KICAgICAgICAgICAgICAgICBndWlkZSA9ICJsZWdlbmQiLA0KICAgICAgICAgICAgICAgICAgICBzaG93LmxpbWl0cz1UUlVFLA0KICAgICAgICAgICAgICAgICAgICBuaWNlLmJyZWFrcz1UUlVFLA0KICAgICAgICAgICAgICAgICAgICBuYS52YWx1ZSA9IE5BLA0KICAgICAgICAgICAgICAgICAgICMgbGFiZWxzID0gc2NhbGVzOjpwZXJjZW50LA0KICAgICAgICAgICAgICAgICAgICBuYW1lID0gIlBlcmNlbnRhZ2UgUG9pbnQgXG5EaWZmZXJlbmNlIikrDQogIGxhYnModGl0bGUgPSAiQ2hhbmdlIGluIENvbXBvc2l0ZSBUYXggUmF0ZSBpZiBhbGwgRXhlbXB0aW9ucyBhcmUgRWxpbWluYXRlZCIpDQoNCmdnc2F2ZSgiQVdNX2NvbXBvc2l0ZXRheHJhdGVfY2hhbmdlLnBuZyIsIGxpbWl0c2l6ZSA9IEZBTFNFLCB3aWR0aCA9IDgsIGhlaWdodCA9IDQsIHVuaXRzID0gImluIikNCmBgYA0KDQpgYGB7ciBpbmNsdWRlID0gRkFMU0V9DQojICMgYWxsIG9mIHVuaW5jb3Jwb3JhdGVkIGNvb2sgdG90YWxzOiBpbmNsdWRlcyBhbGwgbGFuZCBpbiBjb29rIGNvdW50eQ0KIyB0YXhjb2Rlc19jdXJyZW50ICU+JSANCiMgICBsZWZ0X2pvaW4obXVuaV9hZ2VuY3lfbmFtZXMsIGJ5ID0gImFnZW5jeV9udW0iKSAlPiUNCiMgICBsZWZ0X2pvaW4obmlja25hbWVzLCBieSA9IGMoImFnZW5jeV9uYW1lIiA9ICJhZ2VuY3lfbmFtZSIpKSAlPiUNCiMgICAjZmlsdGVyKCFhZ2VuY3lfbnVtICVpbiUgY3Jvc3NfY291bnR5X2xpbmVzKSAlPiUNCiMgICMgZ3JvdXBfYnkoY2xlYW5fbmFtZSwgYWdlbmN5X25hbWUpICU+JQ0KIyAgIHN1bW1hcml6ZShNdW5pTGV2eSA9IHN1bShmaW5hbF90YXhfdG9fZGlzdCwgbmEucm0gPSBUUlVFKSwgIyBhbW91bnQgYmlsbGVkIGJ5IG11bmlzIHdpdGggY3VycmVudCBleGVtcHRpb25zIGluIHBsYWNlDQojICAgICAgICAgICAgIG5vblRJRl9FQVZfcG9zdF9leGVtcHMgPSBzdW0oZmluYWxfdGF4X3RvX2Rpc3QvKHRheF9jb2RlX3JhdGUvMTAwKSwgbmEucm0gPSBUUlVFKSwNCiMgICAgICAgICAgICAgVElGX2luY3JlbWVudF9FQVYgPSBzdW0oZmluYWxfdGF4X3RvX3RpZi8odGF4X2NvZGVfcmF0ZS8xMDApLCBuYS5ybT1UUlVFKSwgIA0KIyAgICAgICAgICAgICBFeGVtcHRfRUFWID0gc3VtKHRheF9hbXRfZXhlLyh0YXhfY29kZV9yYXRlLzEwMCksIG5hLnJtPVRSVUUpLCANCiMgICAgICAgICAgICAgVG90YWxfRUFWID0gc3VtKCh0YXhfYW10X2V4ZStmaW5hbF90YXhfdG9fZGlzdCtmaW5hbF90YXhfdG9fdGlmKS8odGF4X2NvZGVfcmF0ZS8xMDApLCBuYS5ybSA9IFRSVUUpKSAlPiUNCiMgDQojICAgbXV0YXRlKHRheF9yYXRlX2N1cnJlbnQgPSBNdW5pTGV2eS9ub25USUZfRUFWX3Bvc3RfZXhlbXBzLA0KIyAgICAgICAgICBub25USUZfRUFWX3ByZV9leGVtcHMgPSBub25USUZfRUFWX3Bvc3RfZXhlbXBzICsgRXhlbXB0X0VBViwNCiMgICAgICAgICAgdGF4cmF0ZV9uZXcgPSBNdW5pTGV2eS9ub25USUZfRUFWX3ByZV9leGVtcHMsDQojICAgICAgICAgIHRheHJhdGVfY2hhbmdlID0gdGF4X3JhdGVfY3VycmVudC10YXhyYXRlX25ldykgJT4lIA0KIyAgIyBzZWxlY3QoY2xlYW5fbmFtZSwgdGF4cmF0ZV9jaGFuZ2UsIHRheF9yYXRlX2N1cnJlbnQsIHRheHJhdGVfbmV3LCBldmVyeXRoaW5nKCkpICU+JSANCiMgICBhcnJhbmdlKGRlc2ModGF4X3JhdGVfY3VycmVudCkpICU+JQ0KIyAgIHBpdm90X2xvbmdlcihjb2xzID0gTXVuaUxldnk6dGF4cmF0ZV9jaGFuZ2UpICU+JQ0KIyAgIG11dGF0ZSh2YWx1ZSA9IHJvdW5kKHZhbHVlLCBkaWdpdHMgPSAwKSkNCg0KDQojIGFsbCBvZiBpbmNvcnBvcmF0ZWQgY29vayB0b3RhbHM7IE11bmlzIG9ubHkNCnRheGNvZGVzX2N1cnJlbnQgJT4lIA0KICBsZWZ0X2pvaW4obXVuaV9hZ2VuY3lfbmFtZXMsIGJ5ID0gImFnZW5jeV9udW0iKSAlPiUNCiAgbGVmdF9qb2luKG5pY2tuYW1lcywgYnkgPSBjKCJhZ2VuY3lfbmFtZSIgPSAiYWdlbmN5X25hbWUiKSkgJT4lDQogIGZpbHRlcighYWdlbmN5X251bSAlaW4lIGNyb3NzX2NvdW50eV9saW5lcykgJT4lDQogIyBncm91cF9ieShjbGVhbl9uYW1lLCBhZ2VuY3lfbmFtZSkgJT4lDQogIHN1bW1hcml6ZShNdW5pTGV2eSA9IHN1bShmaW5hbF90YXhfdG9fZGlzdCwgbmEucm0gPSBUUlVFKSwgIyBhbW91bnQgYmlsbGVkIGJ5IG11bmlzIHdpdGggY3VycmVudCBleGVtcHRpb25zIGluIHBsYWNlDQogICAgICAgICAgICBub25USUZfRUFWX3Bvc3RfZXhlbXBzID0gc3VtKGZpbmFsX3RheF90b19kaXN0Lyh0YXhfY29kZV9yYXRlLzEwMCksIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgICBUSUZfaW5jcmVtZW50X0VBViA9IHN1bShmaW5hbF90YXhfdG9fdGlmLyh0YXhfY29kZV9yYXRlLzEwMCksIG5hLnJtPVRSVUUpLCAgDQogICAgICAgICAgICBFeGVtcHRfRUFWID0gc3VtKHRheF9hbXRfZXhlLyh0YXhfY29kZV9yYXRlLzEwMCksIG5hLnJtPVRSVUUpLCANCiAgICAgICAgICAgIFRvdGFsX0VBViA9IHN1bSgodGF4X2FtdF9leGUrZmluYWxfdGF4X3RvX2Rpc3QrZmluYWxfdGF4X3RvX3RpZikvKHRheF9jb2RlX3JhdGUvMTAwKSwgbmEucm0gPSBUUlVFKSkgJT4lDQoNCiAgbXV0YXRlKHRheF9yYXRlX2N1cnJlbnQgPSByb3VuZChNdW5pTGV2eS9ub25USUZfRUFWX3Bvc3RfZXhlbXBzLDIpLA0KICAgICAgICAgbm9uVElGX0VBVl9wcmVfZXhlbXBzID0gcm91bmQobm9uVElGX0VBVl9wb3N0X2V4ZW1wcyArIEV4ZW1wdF9FQVYpLA0KICAgICAgICAgdGF4cmF0ZV9uZXcgPSByb3VuZChNdW5pTGV2eS9ub25USUZfRUFWX3ByZV9leGVtcHMsMiksDQogICAgICAgICB0YXhyYXRlX2NoYW5nZSA9IHJvdW5kKHRheF9yYXRlX2N1cnJlbnQtdGF4cmF0ZV9uZXcsIDIpICklPiUgDQogIyBzZWxlY3QoY2xlYW5fbmFtZSwgdGF4cmF0ZV9jaGFuZ2UsIHRheF9yYXRlX2N1cnJlbnQsIHRheHJhdGVfbmV3LCBldmVyeXRoaW5nKCkpICU+JSANCiAgYXJyYW5nZShkZXNjKHRheF9yYXRlX2N1cnJlbnQpKSAlPiUNCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBNdW5pTGV2eTp0YXhyYXRlX2NoYW5nZSkgJT4lDQogIG11dGF0ZSh2YWx1ZSA9IHZhbHVlKQ0KYGBgDQoNCg0KYGBge3IgfQ0KQ3VycmVudF9UYXhyYXRlc19wZXJUQyA8LSB0YXhjb2Rlc19jdXJyZW50ICU+JSANCiAgbGVmdF9qb2luKG11bmlfYWdlbmN5X25hbWVzLCBieSA9ICJhZ2VuY3lfbnVtIikgJT4lDQogIGxlZnRfam9pbihuaWNrbmFtZXMsIGJ5ID0gYygiYWdlbmN5X25hbWUiID0gImFnZW5jeV9uYW1lIikpICU+JQ0KICBmaWx0ZXIoIWFnZW5jeV9udW0gJWluJSBjcm9zc19jb3VudHlfbGluZXMpICU+JQ0KICBncm91cF9ieShjbGVhbl9uYW1lLCBhZ2VuY3lfbmFtZSwgdGF4X2NvZGUsIHBpbnNfaW5fY2xhc3MpICU+JQ0KICANCiAgc3VtbWFyaXplKE11bmlMZXZ5ID0gc3VtKGZpbmFsX3RheF90b19kaXN0LCBuYS5ybSA9IFRSVUUpLCAjIGFtb3VudCBiaWxsZWQgYnkgbXVuaXMgd2l0aCBjdXJyZW50IGV4ZW1wdGlvbnMgaW4gcGxhY2UNCiAgICAgICAgICAgIG5vblRJRl9FQVZfcG9zdF9leGVtcHMgPSBzdW0oZmluYWxfdGF4X3RvX2Rpc3QvKHRheF9jb2RlX3JhdGUvMTAwKSwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgICAgIFRJRl9pbmNyZW1lbnRfRUFWID0gc3VtKGZpbmFsX3RheF90b190aWYvKHRheF9jb2RlX3JhdGUvMTAwKSwgbmEucm09VFJVRSksICANCiAgICAgICAgICAgIEV4ZW1wdF9FQVYgPSBzdW0odGF4X2FtdF9leGUvKHRheF9jb2RlX3JhdGUvMTAwKSwgbmEucm09VFJVRSksIA0KICAgICAgICAgICAgVG90YWxfRUFWID0gc3VtKCh0YXhfYW10X2V4ZStmaW5hbF90YXhfdG9fZGlzdCtmaW5hbF90YXhfdG9fdGlmKS8odGF4X2NvZGVfcmF0ZS8xMDApLCBuYS5ybSA9IFRSVUUpKSAlPiUNCg0KICBtdXRhdGUodGF4X3JhdGVfY3VycmVudCA9IE11bmlMZXZ5L25vblRJRl9FQVZfcG9zdF9leGVtcHMsDQogICAgICAgICBub25USUZfRUFWX3ByZV9leGVtcHMgPSBub25USUZfRUFWX3Bvc3RfZXhlbXBzICsgRXhlbXB0X0VBViwNCiAgICAgICAgIHRheHJhdGVfbmV3ID0gTXVuaUxldnkvbm9uVElGX0VBVl9wcmVfZXhlbXBzLA0KICAgICAgICAgdGF4cmF0ZV9jaGFuZ2UgPSB0YXhfcmF0ZV9jdXJyZW50LXRheHJhdGVfbmV3KSAlPiUgDQogc2VsZWN0KGNsZWFuX25hbWUsIHRheHJhdGVfY2hhbmdlLCB0YXhfcmF0ZV9jdXJyZW50LCB0YXhyYXRlX25ldywgdGF4X2NvZGUsIGV2ZXJ5dGhpbmcoKSkgJT4lIA0KICBhcnJhbmdlKGRlc2ModGF4X3JhdGVfY3VycmVudCkpDQoNCkN1cnJlbnRfVGF4cmF0ZXNfcGVyVEMNCg0KYGBgDQpgYGB7cn0NCkN1cnJlbnRfVGF4cmF0ZXNfcGVyVEMgJT4lIGxlZnRfam9pbihuaWNrbmFtZXMpICU+JQ0KICBncm91cF9ieShUcmlhZCkgJT4lIA0KICBmaWx0ZXIoIFRyaWFkID09ICJTb3V0aCIpICU+JSBzdW1tYXJpemUodGF4cmF0ZV9uZXcgPSBtZWFuKHRheHJhdGVfbmV3LCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRheHJhdGVfY3VycmVudCA9IG1lYW4odGF4X3JhdGVfY3VycmVudCwgbmEucm09VFJVRSkpICU+JQ0KICBtdXRhdGUodGF4cmF0ZV9jaGFuZ2UgPSB0YXhyYXRlX25ldy10YXhyYXRlX2N1cnJlbnQpDQoNCkN1cnJlbnRfVGF4cmF0ZXNfcGVyVEMgJT4lIGxlZnRfam9pbihuaWNrbmFtZXMpICU+JSBncm91cF9ieShUcmlhZCkgJT4lIA0KICBmaWx0ZXIoIFRyaWFkID09ICJOb3J0aCIpICU+JSBzdW1tYXJpemUodGF4cmF0ZV9jaGFuZ2UgPSBtZWFuKHRheHJhdGVfY2hhbmdlLCBuYS5ybT1UUlVFKSkNCmBgYA0KDQpgYGB7ciBpbmNsdWRlPUZBTFNFfQ0KDQpDdXJyZW50X1RheHJhdGVzX3BlclRDICU+JSANCiAgbXV0YXRlKGlzX2NoaWNhZ28gPSBpZmVsc2UoY2xlYW5fbmFtZSA9PSAiQ2hpY2FnbyIsIDEsMCkpICU+JQ0KICBncm91cF9ieShpc19jaGljYWdvKSAlPiUNCiAgc3VtbWFyaXplKGF2ZXJhZ2VfdGF4YWJsZUVBVl9jdXJyZW50ID0gbWVhbihub25USUZfRUFWX3Bvc3RfZXhlbXBzL3BpbnNfaW5fY2xhc3MsIG5hLnJtPVRSVUUpLA0KICAgICAgICAgYXZlcmFnZV90YXhhYmxlRUFWX2h5cCA9IG1lYW4obm9uVElGX0VBVl9wcmVfZXhlbXBzL3BpbnNfaW5fY2xhc3MsIG5hLnJtPVRSVUUpLA0KICAgICAgICAgYXZlcmFnZV90YXhhYmxlRUFWX2h5cF9ub1RJRlMgPSBtZWFuKFRvdGFsX0VBVi9waW5zX2luX2NsYXNzLCBuYS5ybT1UUlVFKSwNCiAgICAgICAgIGF2ZXJhZ2VfdGF4YmlsbF9jdXJyZW50ID0gbWVhbih0YXhfcmF0ZV9jdXJyZW50KmF2ZXJhZ2VfdGF4YWJsZUVBVl9jdXJyZW50LCBuYS5ybT1UUlVFKSwNCiAgICAgICAgIGF2ZXJhZ2VfdGF4YmlsbF9oeXAgPSBtZWFuKHRheHJhdGVfbmV3KmF2ZXJhZ2VfdGF4YWJsZUVBVl9oeXAsIG5hLnJtPVRSVUUpKSAlPiUNCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBhdmVyYWdlX3RheGFibGVFQVZfY3VycmVudDphdmVyYWdlX3RheGJpbGxfaHlwKQ0KDQpDdXJyZW50X1RheHJhdGVzX3BlclRDICU+JSANCiAgbXV0YXRlKGlzX2NoaWNhZ28gPSBpZmVsc2UoY2xlYW5fbmFtZSA9PSAiQ2hpY2FnbyIsIDEsMCkpICU+JQ0KICBncm91cF9ieShpc19jaGljYWdvKSAlPiUNCiAgc3VtbWFyaXplKHJldl9iaWxsZWQgPSBzdW0oTXVuaUxldnksIG5hLnJtPVRSVUUpKSAjJT4lICMgbWFkZSBmcm9tIGZpbmFsX3RheF90b19kaXN0IHZhcmlhYmxlDQogICAgICAgICAjIGF2ZXJhZ2VfdGF4YWJsZUVBVl9oeXAgPSBtZWFuKG5vblRJRl9FQVZfcHJlX2V4ZW1wcy9waW5zX2luX2NsYXNzLCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICMgYXZlcmFnZV90YXhhYmxlRUFWX2h5cF9ub1RJRlMgPSBtZWFuKFRvdGFsX0VBVi9waW5zX2luX2NsYXNzLCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICMgYXZlcmFnZV90YXhiaWxsX2N1cnJlbnQgPSBtZWFuKHRheF9yYXRlX2N1cnJlbnQqYXZlcmFnZV90YXhhYmxlRUFWX2N1cnJlbnQsIG5hLnJtPVRSVUUpLA0KICAgICAgICAgIyBhdmVyYWdlX3RheGJpbGxfaHlwID0gbWVhbih0YXhyYXRlX25ldyphdmVyYWdlX3RheGFibGVFQVZfaHlwLCBuYS5ybT1UUlVFKSkgJT4lDQogICNwaXZvdF9sb25nZXIoY29scyA9IGF2ZXJhZ2VfdGF4YWJsZUVBVl9jdXJyZW50OmF2ZXJhZ2VfdGF4YmlsbF9oeXApDQoNCg0KDQpDdXJyZW50X1RheHJhdGVzX3BlclRDICU+JSANCm11dGF0ZShpc19jaGljYWdvID0gaWZlbHNlKGNsZWFuX25hbWUgPT0gIkNoaWNhZ28iLCAxLDApKSAlPiUNCiAgZ3JvdXBfYnkoaXNfY2hpY2FnbykgJT4lDQogIHN1bW1hcml6ZSh0aWZfcmV2ID0gc3VtKHRheF9yYXRlX2N1cnJlbnQgKiBUSUZfaW5jcmVtZW50X0VBViwgbmEucm09VFJVRSksDQogICAgICAgICAgICByZXZfYmlsbGVkID0gc3VtKHRheF9yYXRlX2N1cnJlbnQgKiBub25USUZfRUFWX3Bvc3RfZXhlbXBzLCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIGFsbF9yZXYgPSBzdW0odGF4X3JhdGVfY3VycmVudCogKG5vblRJRl9FQVZfcG9zdF9leGVtcHMgKyBUSUZfaW5jcmVtZW50X0VBViksIG5hLnJtPVRSVUUpKQ0KIyAxNCw5OTAsOTQ1LDQ0MCBSZXZlbnVlIENvbGxlY3RlZCAoZG9lcyBub3QgaW5jbHVkZSBUSUYgcmV2ZW51ZSkgDQojIDE2LDUzOSw3NjIsMjkwIFJldmVudWUgQ29sbGVjdGVkIChpbmNsdWRpbmcgVElGIHJldmVudWUpDQpgYGANCg0KQnJpbmcgaW4gdGhlIGNvbXBvc2l0ZSB0YXggcmF0ZXMgZm9yIGFsbCB0YXggY29kZXMuDQoNCmBgYHtyIH0NCkN1cnJlbnRfVGF4cmF0ZXMyIDwtIHJlYWRfY3N2KCIyX3RheGNvZGVfdGF4cmF0ZXMuY3N2IikgJT4lIA0KICBtdXRhdGUodGF4X2NvZGUgPSBhcy5jaGFyYWN0ZXIodGF4X2NvZGUpKQ0KDQpsYW5kX3VzZTIgPC0gdGF4Y29kZXNfY3VycmVudCAlPiUgDQogIGxlZnRfam9pbihtdW5pX2FnZW5jeV9uYW1lcykgJT4lIA0KICBsZWZ0X2pvaW4oQ3VycmVudF9UYXhyYXRlcykgJT4lDQogIGxlZnRfam9pbihjbGFzc19kaWN0LCBieSA9IGMoImNsYXNzIiA9ICJjbGFzc19jb2RlIikpICU+JQ0KICANCiMgIG11dGF0ZShjbGFzc18xZGlnID0gc3RyX3N1YihjbGFzcywgMSwgMSksDQojICAgIFJlc2lkZW50aWFsUHJvcHMgPSBpZmVsc2UoY2xhc3NfMWRpZyAlaW4lIGMoIjIiLCAiMyIsICI5IiksICJSZXNpZGVudGlhbCIsICJOb24tUmVzaWRlbnRpYWwiKSkgJT4lDQogICMgICAgICAgIFByb3BUeXBlID0gY2FzZV93aGVuKA0KICAjICAgICAgICAgIG1ham9yX2NsYXNzX2NvZGUgJWluJSBjKCIzIiwiOSIpIH4gIk11bHRpLUZhbWlseSIsDQogICMgICAgICAgICAgbWFqb3JfY2xhc3NfY29kZSA9PSAiMiIgfiAiU2luZ2xlLUZhbWlseSIsDQogICMgICAgICAgICAgVFJVRSB+ICJDb21tZXJjaWFsLUluZHVzdHJpYWwiKSkgJT4lDQogIGdyb3VwX2J5KGNsZWFuX25hbWUsIG1ham9yX2NsYXNzX2NvZGUsIGFnZW5jeV9udW0sIHRheF9yYXRlX2N1cnJlbnQsIHRheHJhdGVfbmV3LCB0YXhyYXRlX2NoYW5nZSwgYWdlbmN5X25hbWUpICU+JSANCiAgDQogICMgQWxsIG9mIHRoZSB2YWx1ZXMgY2FsY3VsYXRlZCBiZWxvdyBhcmUgQUZURVIgZXhlbXB0aW9ucyBoYXZlIGJlZW4gcmVtb3ZlZA0KICBzdW1tYXJpemUodGF4cmV2X2Zyb21fcHJvcHR5cGUgPSBzdW0oZmluYWxfdGF4X3RvX2Rpc3QsIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgICBub25USUZfRUFWID0gc3VtKGZpbmFsX3RheF90b19kaXN0Lyh0YXhfY29kZV9yYXRlLzEwMCksIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgICBUSUZfaW5jcmVtZW50X0VBViA9IHN1bShmaW5hbF90YXhfdG9fdGlmLyh0YXhfY29kZV9yYXRlLzEwMCksIG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgRXhlbXB0X0VBViA9IHN1bSh0YXhfYW10X2V4ZS8odGF4X2NvZGVfcmF0ZS8xMDApLCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIFRvdGFsX0VBViA9IHN1bSgodGF4X2FtdF9leGUrZmluYWxfdGF4X3RvX2Rpc3QrZmluYWxfdGF4X3RvX3RpZikvKHRheF9jb2RlX3JhdGUvMTAwKSwgbmEucm0gPSBUUlVFKSApICU+JSB1bmdyb3VwKCkNCg0KbGFuZF91c2UyDQoNCg0KYGBgDQoNCg0KIyMgVXNpbmcgc2ltaWxhcmlseSBBc3Nlc3NlZCBWYWx1ZSBwcm9wZXJ0aWVzIA0KDQpgYGB7cn0NCm5pY2tuYW1lcyA8LSByZWFkeGw6OnJlYWRfZXhjZWwoIm11bmlfc2hvcnRuYW1lcy54bHN4IikNCg0KY2xhc3NfZGljdCA8LSByZWFkX2NzdigiY2xhc3NfZGljdC5jc3YiKQ0KDQp0YXhjb2RlX3RheHJhdGVzIDwtIHJlYWRfY3N2KCIyX3RheGNvZGVfdGF4cmF0ZXMuY3N2IikNCg0KDQpEb2x0b25DaGljYWdvIDwtIHJlYWRfY3N2KCJDaG9sdG9uX3RheGJpbGxzLmNzdiIpICU+JSANCiAgYXJyYW5nZShhdikgJT4lICAgICANCiAgbGVmdF9qb2luKHRheGNvZGVfdGF4cmF0ZXMpICU+JQ0KICAgIG11dGF0ZShwcm9wY2xhc3NfMWRpZyA9IHN0cl9zdWIoY2xhc3MsIDEsIDEpKQ0KDQpsaWJyYXJ5KGthYmxlRXh0cmEpDQpgYGANCg0KYGBge3J9DQojIERvbHRvbkNoaWNhZ28gJT4lIA0KIyAgIGdyb3VwX2J5KGFnZW5jeV9udW0sIHRheF9jb2RlKSAlPiUgDQojICAgc3VtbWFyaXplKG1heF9jb21wcmF0ZSA9IG1heCh0YXhfcmF0ZV9jdXJyZW50KSwNCiMgICAgICAgICAgICAgbWluX2NvbXByYXRlID0gbWluKHRheF9yYXRlX2N1cnJlbnQpKSAlPiUgYXJyYW5nZSgtbWF4X2NvbXByYXRlKQ0KDQpEb2x0b25DaGljYWdvICU+JSBncm91cF9ieShhZ2VuY3lfbnVtKSAlPiUgDQogIHN1bW1hcml6ZShtYXhfY29tcHJhdGUgPSBtYXgodGF4X3JhdGVfY3VycmVudCwgbmEucm09VFJVRSksDQogICAgICAgICAgICBtZWFuX2NvbXByYXRlID0gbWVhbih0YXhfcmF0ZV9jdXJyZW50LCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIG1pbl9jb21wcmF0ZSA9IG1pbih0YXhfcmF0ZV9jdXJyZW50LCBuYS5ybT1UUlVFKSkgJT4lIGFycmFuZ2UoLW1lYW5fY29tcHJhdGUpDQoNCkRvbHRvbkNoaWNhZ28gJT4lIGZpbHRlcihhZ2VuY3lfbnVtID09ICIwMzAzMTAwMDAiKSAlPiUNCiAgZ3JvdXBfYnkoYWdlbmN5X251bSwgY2xhc3MpICU+JSANCiAgc3VtbWFyaXplKG1heF9jb21wcmF0ZSA9IG1heCh0YXhfcmF0ZV9jdXJyZW50LCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIG1lYW5fY29tcHJhdGUgPSBtZWFuKHRheF9yYXRlX2N1cnJlbnQsIG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgbWluX2NvbXByYXRlID0gbWluKHRheF9yYXRlX2N1cnJlbnQsIG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgcGluX2NvdW50ID0gbigpLA0KICAgICAgICAgICAgYXYgPSBtZWFuKGF2KSwNCiAgICAgICAgICAgIGVhdiA9IG1lYW4oZWF2KSwNCiAgICAgICAgICAgIHRheF9hbXRfcG9zdF9leGUgPSBtZWFuKHRheF9hbXRfcG9zdF9leGUpLA0KICAgICAgICAgICAgdGF4X2FtdF9leGUgPSBtZWFuKHRheF9hbXRfZXhlKSwNCiAgICAgICAgICAgIHRheF9hbXRfcHJlX2V4ZSA9IG1lYW4odGF4X2FtdF9wcmVfZXhlKSkgJT4lIA0KICBhcnJhbmdlKC1waW5fY291bnQpICU+JSBoZWFkKCkgJT4lIGtibCgpDQoNCkRvbHRvbkNoaWNhZ28gJT4lIGZpbHRlcihhZ2VuY3lfbnVtID09ICIwMzAyMTAwMDAiKSAlPiUNCiAgZ3JvdXBfYnkoYWdlbmN5X251bSwgY2xhc3MpICU+JSANCiAgc3VtbWFyaXplKG1heF9jb21wcmF0ZSA9IG1heCh0YXhfcmF0ZV9jdXJyZW50LCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIG1lYW5fY29tcHJhdGUgPSBtZWFuKHRheF9yYXRlX2N1cnJlbnQsIG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgbWluX2NvbXByYXRlID0gbWluKHRheF9yYXRlX2N1cnJlbnQsIG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgcGluX2NvdW50ID0gbigpLA0KICAgICAgICAgICAgYXYgPSBtZWFuKGF2KSwNCiAgICAgICAgICAgIGVhdiA9IG1lYW4oZWF2KSwNCiAgICAgICAgICAgIHRheF9hbXRfcG9zdF9leGUgPSBtZWFuKHRheF9hbXRfcG9zdF9leGUpLA0KICAgICAgICAgICAgdGF4X2FtdF9leGUgPSBtZWFuKHRheF9hbXRfZXhlKSwNCiAgICAgICAgICAgIHRheF9hbXRfcHJlX2V4ZSA9IG1lYW4odGF4X2FtdF9wcmVfZXhlKSkgJT4lIA0KICBhcnJhbmdlKC1waW5fY291bnQpICU+JSBoZWFkKCkgJT4lIGtibCgpDQpgYGAgDQoNCg0KDQpgYGB7cn0NCg0KRG9sdG9uQ2hpY2FnbyAlPiUgDQogIGZpbHRlcihjbGFzcyA9PSAiMjAzIikgJT4lIA0KICBhcnJhbmdlKGF2KSU+JQ0KICBncm91cF9ieShhZ2VuY3lfbnVtLCBjbGFzcykgJT4lDQogIHN1bW1hcml6ZShtZWRpYW5iaWxsID0gbWVkaWFuKHRvdGFsX2JpbGxlZCksDQogICAgICAgICAgICBtZWFuYmlsbCA9IG1lYW4odG90YWxfYmlsbGVkKSwNCiAgICAgICAgICAgIG1lZGlhbkFWID0gbWVkaWFuKGF2KSwNCiAgICAgICAgICAgIG1lYW5BViA9IG1lYW4oYXYpLA0KICAgICAgICAgICAgKSU+JSANCiAjIHBpdm90X2xvbmdlcihtZWRpYW5iaWxsOm1lYW5BViwgbmFtZXNfdG8gPSAiU3RhdHMiLCB2YWx1ZXNfdG8gPSAiVmFsdWVzIikgICU+JQ0KICBrYmwoY2FwdGlvbj0gIkNoaWNhZ28gYW5kIERvbHRvbiwgQ2xhc3MgMjAzLCBNZWFzdXJlcyBvZiB0aGUgTWlkZGxlIiwgZGlnaXRzPTAsIGJvb2t0YWJzID0gVCkgJT4lICAgDQogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IFQpDQoNCg0KDQpEb2x0b25DaGljYWdvICU+JSANCiAgZmlsdGVyKGNsYXNzID09ICIyMDUiKSAlPiUgDQogIGdyb3VwX2J5KGFnZW5jeV9udW0sIGNsYXNzKSAlPiUNCiAgc3VtbWFyaXplKG1lZGlhbmJpbGwgPSBtZWRpYW4odG90YWxfYmlsbGVkKSwNCiAgICAgICAgICAgIG1lYW5iaWxsID0gbWVhbih0b3RhbF9iaWxsZWQpLA0KICAgICAgICAgICAgbWVkaWFuQVYgPSBtZWRpYW4oYXYpLA0KICAgICAgICAgICAgbWVhbkFWID0gbWVhbihhdiksDQogICAgICAgICAgICApJT4lIA0KICMgcGl2b3RfbG9uZ2VyKG1lZGlhbmJpbGw6bWVhbkFWLCBuYW1lc190byA9ICJTdGF0cyIsIHZhbHVlc190byA9ICJWYWx1ZXMiKSAgJT4lDQogIGtibChjYXB0aW9uPSAiQ2hpY2FnbyBhbmQgRG9sdG9uLCBDbGFzcyAyMDUsIE1lYXN1cmVzIG9mIHRoZSBNaWRkbGUiLCBkaWdpdHM9MCwgYm9va3RhYnMgPSBUKSAlPiUgICANCiAga2FibGVfc3R5bGluZyhmdWxsX3dpZHRoID0gVCkNCg0KRG9sdG9uQ2hpY2FnbyAlPiUgDQogIGZpbHRlcihjbGFzcyA9PSAiMjExIikgJT4lIA0KICBncm91cF9ieShhZ2VuY3lfbnVtLCBjbGFzcykgJT4lDQogIHN1bW1hcml6ZShtZWRpYW5iaWxsID0gbWVkaWFuKHRvdGFsX2JpbGxlZCksDQogICAgICAgICAgICBtZWFuYmlsbCA9IG1lYW4odG90YWxfYmlsbGVkKSwNCiAgICAgICAgICAgIG1lZGlhbkFWID0gbWVkaWFuKGF2KSwNCiAgICAgICAgICAgIG1lYW5BViA9IG1lYW4oYXYpLA0KICAgICAgICAgICAgKSU+JSANCiAjIHBpdm90X2xvbmdlcihtZWRpYW5iaWxsOm1lYW5BViwgbmFtZXNfdG8gPSAiU3RhdHMiLCB2YWx1ZXNfdG8gPSAiVmFsdWVzIikgICU+JQ0KICBrYmwoY2FwdGlvbj0gIkNoaWNhZ28gYW5kIERvbHRvbiwgQ2xhc3MgMjExLCBNZWFzdXJlcyBvZiB0aGUgTWlkZGxlIiwgZGlnaXRzPTAsIGJvb2t0YWJzID0gVCkgJT4lICAgDQogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IFQpDQoNCkRvbHRvbkNoaWNhZ28gJT4lIA0KICBmaWx0ZXIoY2xhc3MgPT0gIjIzNCIpICU+JSANCiAgZ3JvdXBfYnkoYWdlbmN5X251bSwgY2xhc3MpICU+JQ0KICBzdW1tYXJpemUobWVkaWFuYmlsbCA9IG1lZGlhbih0b3RhbF9iaWxsZWQpLA0KICAgICAgICAgICAgbWVhbmJpbGwgPSBtZWFuKHRvdGFsX2JpbGxlZCksDQogICAgICAgICAgICBtZWRpYW5BViA9IG1lZGlhbihhdiksDQogICAgICAgICAgICBtZWFuQVYgPSBtZWFuKGF2KSwNCiAgICAgICAgICAgICklPiUgDQogIyBwaXZvdF9sb25nZXIobWVkaWFuYmlsbDptZWFuQVYsIG5hbWVzX3RvID0gIlN0YXRzIiwgdmFsdWVzX3RvID0gIlZhbHVlcyIpICAlPiUNCiAga2JsKGNhcHRpb249ICJDaGljYWdvIGFuZCBEb2x0b24sIENsYXNzIDIzNCwgTWVhc3VyZXMgb2YgdGhlIE1pZGRsZSIsIGRpZ2l0cz0wLCBib29rdGFicyA9IFQpICU+JSAgIA0KICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBUKQ0KDQoNCmBgYA0KDQpDaGljYWdvIGhhcyA2NTUgdGF4IGNvZGVzIGluIGl0cyBib3JkZXJzIGFuZCBEb2x0b24gaGFzIDEzIHRheCBjb2RlcyBpbiBpdHMgYm9yZGVycy4gDQoNCg0KPiBNYXggY29tcG9zaXRlIHRheCByYXRlIGluIGEgdGF4IGNvZGUgaW4gQ2hpY2FnbyBpcyA5LjElIGFuZCBtaW5pbXVtIGNvbXBvc2l0ZSB0YXggcmF0ZSBpcyA2LjclLiBDaGljYWdvIGhhcyA2NjUgdGF4IGNvZGVzLiANCg0KPiBNYXggY29tcG9zaXRlIHRheCByYXRlIGluIGEgdGF4IGNvZGUgaW4gRG9sdG9uIGlzIDI3LjklIGFuZCBtaW5pbXVtIGNvbXBvc2l0ZSB0YXggcmF0ZSBpcyAyMi45JS4gRG9sdG9uIGhhcyAxMyB0YXggY29kZXMuIA0KDQoNCg0KIyMjIENsYXNzIDIwMw0KDQpPbmUgc3RvcnkgcmVzaWRlbmNlLCBhbnkgYWdlLCAxLDAwMCB0byAxLDgwMCBzcS4gZnQuDQoNCg0KYGBge3J9DQpEb2x0b25DaGljYWdvICU+JSANCiAgZmlsdGVyKGFnZW5jeV9udW0gPT0gIjAzMDIxMDAwMCIgKSAlPiUgIyYgY2xhc3MgPT0gIjIwMyIgJiBiZXR3ZWVuKGF2LDk5NTAsMTAwNTApKSAlPiUgDQogIGdyb3VwX2J5KHRheF9jb2RlKSAlPiUgDQogIHN1bW1hcml6ZShjb3VudCA9IG4oKSwgICAgICAgICAgICANCiAgICAgICAgICAgIGF2Z19jdXJyZW50X2NvbXByYXRlID0gbWVhbih0YXhfcmF0ZV9jdXJyZW50LCBuYS5ybT1UUlVFKQ0KICApICU+JSBhcnJhbmdlKC1hdmdfY3VycmVudF9jb21wcmF0ZSkgJT4lIGhlYWQoKQ0KDQpEb2x0b25DaGljYWdvICU+JSANCiAgZmlsdGVyKGFnZW5jeV9udW0gPT0gIjAzMDMxMDAwMCIpICU+JSAjICYgY2xhc3MgPT0gIjIwMyIgJiBiZXR3ZWVuKGF2LCA5OTUwLCAxMDA1MCkpICU+JQ0KICBncm91cF9ieSh0YXhfY29kZSkgJT4lDQogIHN1bW1hcml6ZShjb3VudCA9IG4oKSwNCiAgICAgICAgICAgIGF2Z19jdXJyZW50X2NvbXByYXRlID0gbWVhbih0YXhfcmF0ZV9jdXJyZW50LCBuYS5ybT1UUlVFKQ0KICApICU+JSBhcnJhbmdlKC1hdmdfY3VycmVudF9jb21wcmF0ZSkgJT4lIGhlYWQoKQ0KYGBgDQoNCg0KSWYgaG9sZGluZyB0aGUgbGV2eSBjb25zdGFudCBhbmQgYWNrbm93bGVkZ2luZyB0aGUgY2hhbmdlIGluIHRheCByYXRlcyB0aGF0IHdvdWxkIG9jY3VyIGZyb20gaGF2aW5nIGFkZGl0aW9uYWwgdGF4YWJsZSBFQVYgd2l0aGluIHRoZSB0YXhpbmcganVyaXNkaWN0aW9ucy4uLi4NCg0KRm9yIHByb3BlcnR5IGNsYXNzIDIwMyBQSU5zIHdpdGggYXNzZXNzZWQgdmFsdWVzIGJldHdlZW4gXCQ5LDAwMCBhbmQgXCQxMSwwMDAsIHRoZSBhdmVyYWdlIGNoYW5nZSBpbiB0YXggYmlsbCB3b3VsZCBiZSBcJDc1IG1vcmUgaW4gQ2hpY2FnbyBhbmQgXCQyMDUgbW9yZSBpbiBEb2x0b24gY29tcGFyZWQgdG8gdGhlaXIgY3VycmVudCB0YXggYmlsbHMgKFwkMTQ3NSBhbmQgJDQzMTIgcmVzcGVjdGl2ZWx5KS4gDQoNClRoZSAiYXZlcmFnZSIgcHJvcGVydHkgdGF4IHBheWVyIHdvdWxkIHRoaW5rIHRoZXkgYXJlIHNhdmluZyBcJDYyNCBpbiBDaGljYWdvIGFuZCAkMjcwOCBpbiBEb2x0b24gZHVlIHRvIGV4ZW1wdGlvbnMuIFRoaXMgbnVtYmVyIGFwcGVhcnMgb24gdGhlaXIgdGF4YmlsbCBhbmQgY2FsY3VsYXRlZCBieSB0aGUgZnVsbCBFQVYgKiBjdXJyZW50IHRheCByYXRlIGFuZCBkb2VzIE5PVCBjb25zaWRlciB0aGUgY2hhbmdlIGluIHRheCByYXRlIHRoYXQgd291bGQgb2NjdXIgaWYgbGV2aWVzIGFyZSBoZWxkIGNvbnN0YW50IGFuZCBhbGwgRUFWIGJlY2FtZSB0YXhhYmxlLiANCg0KDQpgYGB7cn0NCkNoaTMgPC0gRG9sdG9uQ2hpY2FnbyAlPiUgDQogIGZpbHRlcihhZ2VuY3lfbnVtID09ICIwMzAyMTAwMDAiICYgY2xhc3MgPT0gIjIwMyIgJiBiZXR3ZWVuKGF2LDkwMDAsMTEwMDApKSAlPiUNCiAgICBzdW1tYXJpemUoICAgICAgICAgICAgICANCiAgICBjb21wX3RheHJhdGUgPSBtZWFuKHRheF9jb2RlX3JhdGUsIG5hLnJtPVRSVUUpLA0KICAgIGJpbGxfY3VycmVudCA9IG1lYW4odGF4X2FtdF9wb3N0X2V4ZSwgbmEucm09VFJVRSksDQogICAgYmlsbF9oeXAgPSBtZWFuKGVhdip0YXhyYXRlX25ldywgbmEucm09VFJVRSksDQogICAgYmlsbF9jaGFuZ2UgPSBiaWxsX2h5cCAtIGJpbGxfY3VycmVudCwNCiAgICB0YXhfYW10X3Bvc3RfZXhlID0gbWVhbih0YXhfYW10X3Bvc3RfZXhlKSwNCiAgICB0YXhfYW10X2V4ZSA9IG1lYW4odGF4X2FtdF9leGUpLA0KICAgIHRheF9hbXRfcHJlX2V4ZSA9IG1lYW4odGF4X2FtdF9wcmVfZXhlKSwNCiAgICBwaW5fY291bnQgPSBuKCksDQogICAgYXYgPSBtZWFuKGF2KSwgDQogICAgZWF2ID0gbWVhbihlYXYpDQogICkgJT4lIA0KICBwaXZvdF9sb25nZXIoY29scyA9IGNvbXBfdGF4cmF0ZTplYXYsIG5hbWVzX3RvID0gIlN0YXRzIiwgdmFsdWVzX3RvID0gIlZhbHVlcyIpDQoNCkRvbDMgPC0gRG9sdG9uQ2hpY2FnbyAlPiUgDQogIGZpbHRlcihhZ2VuY3lfbnVtID09ICIwMzAzMTAwMDAiICYgY2xhc3MgPT0gIjIwMyIgJiBiZXR3ZWVuKGF2LCA5MDAwLCAxMTAwMCkpICU+JQ0KICAgIHN1bW1hcml6ZSggICAgICAgICAgICAgIA0KICAgIGNvbXBfdGF4cmF0ZSA9IG1lYW4odGF4X2NvZGVfcmF0ZSwgbmEucm09VFJVRSksDQogICAgYmlsbF9jdXJyZW50ID0gbWVhbih0YXhfYW10X3Bvc3RfZXhlLCBuYS5ybT1UUlVFKSwNCiAgICBiaWxsX2h5cCA9IG1lYW4oZWF2KnRheHJhdGVfbmV3LCBuYS5ybT1UUlVFKSwNCiAgICBiaWxsX2NoYW5nZSA9IGJpbGxfaHlwIC0gYmlsbF9jdXJyZW50LA0KICAgIHRheF9hbXRfcG9zdF9leGUgPSBtZWFuKHRheF9hbXRfcG9zdF9leGUpLA0KICAgIHRheF9hbXRfZXhlID0gbWVhbih0YXhfYW10X2V4ZSwgbmEucm09VFJVRSksDQogICAgdGF4X2FtdF9wcmVfZXhlID0gbWVhbih0YXhfYW10X3ByZV9leGUsIG5hLnJtPVRSVUUpLA0KICAgIHBpbl9jb3VudCA9IG4oKSwNCiAgICBhdiA9IG1lYW4oYXYpLCANCiAgICBlYXYgPSBtZWFuKGVhdikNCiAgKSAlPiUgDQogICAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjb21wX3RheHJhdGU6ZWF2LCBuYW1lc190byA9ICJTdGF0cyIsIHZhbHVlc190byA9ICJWYWx1ZXMiKQ0KDQpib3RoX2R0IDwtIGNiaW5kKENoaTMsIERvbDMpDQoNCg0Ka2JsKGJvdGhfZHQsIGJvb2t0YWJzID0gVCwgZGlnaXRzID0gMCwgDQogICAgY2FwdGlvbiA9ICJQcm9wZXJ0eSBDbGFzcyAyMDMgQ29tcGFyaXNvbiwgQVYgfiAkMTAsMDAwICg5MDAwLTExMDAwIHJhbmdlKSIpICU+JQ0KICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBUKSU+JQ0KYWRkX2hlYWRlcl9hYm92ZShjKCJDaGljYWdvIiA9IDIsICJEb2x0b24iID0gMikpDQpgYGANCg0KDQo+IENoYW5naW5nIHRoZSByYW5nZSBvZiBQSU5zIGluY2x1ZGVkIGluIHRoZSBjYWxjdWxhdGlvbiBhbHRlcnMgdGhlICJNZWRpYW4gUHJvcGVydHkgU3RhdGlzdGljIiANCg0KSWYgaG9sZGluZyB0aGUgbGV2eSBjb25zdGFudCBhbmQgYWNrbm93bGVkZ2luZyB0aGUgY2hhbmdlIGluIHRheCByYXRlcyB0aGF0IHdvdWxkIG9jY3VyIGZyb20gaGF2aW5nIGFkZGl0aW9uYWwgdGF4YWJsZSBFQVYgd2l0aGluIHRoZSB0YXhpbmcganVyaXNkaWN0aW9ucy4uLi4NCg0KRm9yIHByb3BlcnR5IGNsYXNzIDIwMyBQSU5zIHdpdGggYXNzZXNzZWQgdmFsdWVzIGJldHdlZW4gXCQ4LDAwMCBhbmQgXCQxMiwwMDAsIHRoZSBhdmVyYWdlIGNoYW5nZSBpbiB0YXggYmlsbCB3b3VsZCBiZSBcJDk4IG1vcmUgaW4gQ2hpY2FnbyBhbmQgXCQ1NSBtb3JlIGluIERvbHRvbiBjb21wYXJlZCB0byB0aGVpciBjdXJyZW50IHRheCBiaWxscyAoXCQxNTEzIGFuZCAkNDM0MiByZXNwZWN0aXZlbHkpLiANCg0KYGBge3J9DQpDaGkzIDwtIERvbHRvbkNoaWNhZ28gJT4lIA0KICBmaWx0ZXIoYWdlbmN5X251bSA9PSAiMDMwMjEwMDAwIiAmIGNsYXNzID09ICIyMDMiICYgYmV0d2Vlbihhdiw4MDAwLDEyMDAwKSkgJT4lDQogICAgc3VtbWFyaXplKCAgICAgICAgICAgICAgDQogICAgY29tcF90YXhyYXRlID0gbWVhbih0YXhfY29kZV9yYXRlLCBuYS5ybT1UUlVFKSwNCiAgICBiaWxsX2N1cnJlbnQgPSBtZWFuKHRheF9hbXRfcG9zdF9leGUsIG5hLnJtPVRSVUUpLA0KICAgIGJpbGxfaHlwID0gbWVhbihlYXYqdGF4cmF0ZV9uZXcsIG5hLnJtPVRSVUUpLA0KICAgIGJpbGxfY2hhbmdlID0gYmlsbF9oeXAgLSBiaWxsX2N1cnJlbnQsDQogICAgdGF4X2FtdF9wb3N0X2V4ZSA9IG1lYW4odGF4X2FtdF9wb3N0X2V4ZSksDQogICAgdGF4X2FtdF9leGUgPSBtZWFuKHRheF9hbXRfZXhlLCBuYS5ybT1UUlVFKSwNCiAgICB0YXhfYW10X3ByZV9leGUgPSBtZWFuKHRheF9hbXRfcHJlX2V4ZSwgbmEucm09VFJVRSksDQogICAgcGluX2NvdW50ID0gbigpLA0KICAgIGF2ID0gbWVhbihhdiksIA0KICAgIGVhdiA9IG1lYW4oZWF2KQ0KICApICU+JSANCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjb21wX3RheHJhdGU6ZWF2LCBuYW1lc190byA9ICJTdGF0cyIsIHZhbHVlc190byA9ICJWYWx1ZXMiKQ0KDQojIENoaWNhZ28gb25seSBoYXMgMiBwaW5zIHRoYXQgYXJlIHNpbWlsYXIgdG8gRG9sdG9uJ3MgbWVkaWFuIHBpbiAod2hpY2ggaGFkIGEgbG90IG9mIG1hdGNoZXMpDQpEb2wzIDwtIERvbHRvbkNoaWNhZ28gJT4lIA0KICBmaWx0ZXIoYWdlbmN5X251bSA9PSAiMDMwMzEwMDAwIiAmIGNsYXNzID09ICIyMDMiICYgYmV0d2VlbihhdiwgODAwMCwgMTIwMDApKSAlPiUNCiAgICBzdW1tYXJpemUoICAgICAgICAgICAgICANCiAgICBjb21wX3RheHJhdGUgPSBtZWFuKHRheF9jb2RlX3JhdGUsIG5hLnJtPVRSVUUpLA0KICAgIGJpbGxfY3VycmVudCA9IG1lYW4odGF4X2FtdF9wb3N0X2V4ZSwgbmEucm09VFJVRSksDQogICAgYmlsbF9oeXAgPSBtZWFuKGVhdip0YXhyYXRlX25ldywgbmEucm09VFJVRSksDQogICAgYmlsbF9jaGFuZ2UgPSBiaWxsX2h5cCAtIGJpbGxfY3VycmVudCwNCiAgICB0YXhfYW10X3Bvc3RfZXhlID0gbWVhbih0YXhfYW10X3Bvc3RfZXhlKSwNCiAgICB0YXhfYW10X2V4ZSA9IG1lYW4odGF4X2FtdF9leGUsIG5hLnJtPVRSVUUpLA0KICAgIHRheF9hbXRfcHJlX2V4ZSA9IG1lYW4odGF4X2FtdF9wcmVfZXhlLCBuYS5ybT1UUlVFKSwNCiAgICBwaW5fY291bnQgPSBuKCksDQogICAgYXYgPSBtZWFuKGF2KSwgDQogICAgZWF2ID0gbWVhbihlYXYpDQogICkgJT4lIA0KICAgIHBpdm90X2xvbmdlcihjb2xzID0gY29tcF90YXhyYXRlOmVhdiwgbmFtZXNfdG8gPSAiU3RhdHMiLCB2YWx1ZXNfdG8gPSAiVmFsdWVzIikNCg0KYm90aF9kdCA8LSBjYmluZChDaGkzLCBEb2wzKQ0KDQoNCmtibChib3RoX2R0LCBib29rdGFicyA9IFQsIGRpZ2l0cyA9IDAsIA0KICAgIGNhcHRpb24gPSAiUHJvcGVydHkgTWFqb3IgQ2xhc3MgMiBDb21wYXJpc29uLCBBViB+ICQxMCwwMDAgKEFWIHJhbmdlICQ4MDAwLSQxMjAwMCkiKSAlPiUNCiAga2FibGVfc3R5bGluZyhmdWxsX3dpZHRoID0gVCklPiUNCmFkZF9oZWFkZXJfYWJvdmUoYygiQ2hpY2FnbyBDbGFzcyAyMDMsIDhLLTEySyBQcm9wZXJ0eSBTdGF0cyIgPSAyLCAiRG9sdG9uIENsYXNzIDIwMywgOEwtMTJLIEFWIFByb3BlcnR5IFN0YXRzIiA9IDIpKQ0KYGBgDQoNCg0KDQojIyMgTWFqb3IgQ2xhc3MgMg0KDQpBdmVyYWdlIGFuZCBtZWRpYW4gdGF4IGJpbGxzIGFuZCBhc3Nlc3NlZCB2YWx1ZXMgYXJlIGNhbGN1bGF0ZWQgYmVsb3cgZm9yIEFMTCBwcm9wZXJ0eSBjbGFzcyB0eXBlcyB3aXRoaW4gdGhlIHRoZSBicm9hZGVyICJSZXNpZGVudGlhbCIgcHJvcGVydHkgY2xhc3MgdHlwZSAocHJvcGVydHkgY2xhc3NlcyB0aGF0IGhhdmUgdGhlIGZpcnN0IGRpZ2l0ICIyIiwgb3IgTWFqb3IgQ2xhc3MgVHlwZSAyKQ0KDQpUaGUgbWVkaWFuIEFWICBpcyB1c2VkIHRvIHNlbGVjdCBhIHJhbmdlIG9mIHBpbnMgKGJhc2VkIG9uIHRoZWlyIEFWKSB0byBjYWxjdWxhdGUgdGhlIGF2ZXJhZ2UgY3VycmVudCBiaWxsLCBoeXBvdGhldGljYWwgYmlsbCwgYW5kIGh5cG90aGV0aWNhbCBjaGFuZ2UgaW4gdGF4IGJpbGwgZm9yIGEgIm1lZGlhbiBwcm9wZXJ0eSIuIA0KDQpUaGlzIGlzIGRvbmUgYmVjYXVzZSBzb21lIHByb3BlcnRpZXMgcmVjZWl2ZSBtdWx0aXBsZSBleGVtcHRpb25zIHdoaWxlIG90aGVycyByZWNlaXZlIG5vbmUuIFVzaW5nIHRoZSBsaXRlcmFsIG1lZGlhbiBwaW4gY2FuIHNrZXcgdGhlIHN1bW1hcnkgc3RhdGlzdGljcyBvZiB0aGF0IHNwZWNpZmljIHBpbiByZWNlaXZlcyBubyBleGVtcHRpb25zIG9yIG11bHRpcGxlIGV4ZW1wdGlvbnMuIFRoZSBhdmVyYWdlIGZvciB0aGUgcmFuZ2Ugb2YgIm1lZGlhbiBQSU5zIiBpcyBjcmVhdGVkIHRvIHNtb290aCBvdXQgdGhlIHZhcmlhdGlvbiB3aXRoaW4gdGhlIG9ic2VydmF0aW9ucy4gDQoNCmBgYHtyfQ0KRG9sdG9uQ2hpY2FnbyAlPiUgDQogIGZpbHRlcihwcm9wY2xhc3NfMWRpZyA9PSAiMiIpICU+JSANCiAgYXJyYW5nZShhdikgJT4lDQogIGdyb3VwX2J5KGFnZW5jeV9udW0pICU+JQ0KICBzdW1tYXJpemUobWVkaWFuYmlsbCA9IG1lZGlhbih0b3RhbF9iaWxsZWQpLA0KICAgICAgICAgICAgbWVhbmJpbGwgPSBtZWFuKHRvdGFsX2JpbGxlZCksDQogICAgICAgICAgICBtZWRpYW5BViA9IG1lZGlhbihhdiksDQogICAgICAgICAgICBtZWFuQVYgPSBtZWFuKGF2KSwNCiAgICAgICAgICAgIHBpbl9jb3VudCA9IG4oKQ0KICAgICAgICAgICAgKSU+JSANCiAjIHBpdm90X2xvbmdlcihtZWRpYW5iaWxsOm1lYW5BViwgbmFtZXNfdG8gPSAiU3RhdHMiLCB2YWx1ZXNfdG8gPSAiVmFsdWVzIikgICU+JQ0KICBrYmwoY2FwdGlvbj0gIkNoaWNhZ28gYW5kIERvbHRvbiwgTWFqb3IgQ2xhc3MgMiwgTWVhc3VyZXMgb2YgdGhlIE1pZGRsZSIsIGRpZ2l0cz0wLCBib29rdGFicyA9IFQpICU+JSAgIA0KICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBUKQ0KDQojIA0KIyBEb2x0b25DaGljYWdvICU+JSANCiMgICBmaWx0ZXIocHJvcGNsYXNzXzFkaWcgPT0gIjMiKSAlPiUgDQojICAgYXJyYW5nZShhdikgJT4lDQojICAgZ3JvdXBfYnkoYWdlbmN5X251bSkgJT4lDQojICAgc3VtbWFyaXplKG1lZGlhbmJpbGwgPSBtZWRpYW4odG90YWxfYmlsbGVkKSwNCiMgICAgICAgICAgICAgbWVhbmJpbGwgPSBtZWFuKHRvdGFsX2JpbGxlZCksDQojICAgICAgICAgICAgIG1lZGlhbkFWID0gbWVkaWFuKGF2KSwNCiMgICAgICAgICAgICAgbWVhbkFWID0gbWVhbihhdiksDQojICAgICAgICAgICAgIHBpbl9jb3VudCA9IG4oKQ0KIyAgICAgICAgICAgICApJT4lIA0KIyAgIyBwaXZvdF9sb25nZXIobWVkaWFuYmlsbDptZWFuQVYsIG5hbWVzX3RvID0gIlN0YXRzIiwgdmFsdWVzX3RvID0gIlZhbHVlcyIpICAlPiUNCiMgICBrYmwoY2FwdGlvbj0gIkNoaWNhZ28gYW5kIERvbHRvbiwgTWFqb3IgQ2xhc3MgMywgTWVhc3VyZXMgb2YgdGhlIE1pZGRsZSIsIGRpZ2l0cz0wLCBib29rdGFicyA9IFQpICU+JSAgIA0KIyAgIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IFQpDQpgYGANCg0KSWYgaG9sZGluZyB0aGUgbGV2eSBjb25zdGFudCBhbmQgYWNrbm93bGVkZ2luZyB0aGUgY2hhbmdlIGluIHRheCByYXRlcyB0aGF0IHdvdWxkIG9jY3VyIGZyb20gaGF2aW5nIGFkZGl0aW9uYWwgdGF4YWJsZSBFQVYgd2l0aGluIHRoZSB0YXhpbmcganVyaXNkaWN0aW9ucywgQ2hpY2FnbydzIGh5cG90aGV0aWNhbCB0YXggYmlsbCB3b3VsZCBiZSBcJDE1NzAgKGFuIFwkMTQgaW5jcmVhc2UgZnJvbSBcJDE1NTYpIGFuZCBEb2x0b24ncyB3b3VsZCBiZSBcJDQ2MTAgKGEgXCQzMCBpbmNyZWFzZSBmcm9tICQ0NTgwKS4gICANCg0KT24gYXZlcmFnZSwgcmVzaWRlbnRzIHdvdWxkIHRoaW5rIHRoZXkgInNhdmVkIiBcJDUwMSBpbiBDaGljYWdvIGFuZCBcJDI1ODggaW4gRG9sdG9uIChiYXNlZCBvbiB0YXhfYW10X2V4ZSB3aGljaCBhbHNvIHNob3dzIHVwIG9uIHRoZWlyIHRheCBiaWxsIGJhc2VkIG9uIHRoZSAibmFpdmUiIHByZS10YXggZXhlbXB0aW9uIHRheCBiaWxsIGFtb3VudCBvbiB0aGUgdGF4IGJpbGwpLiBUaGUgYW1vdW50IHNhdmVkIHBlciBwZXJzb24gd2lsbCBkZXBlbmQgb24gaG93IG1hbnkgZXhlbXB0aW9ucyB0aGV5IHF1YWxpZmllZCBmb3IgaW4gdGhlIGZpcnN0IHBsYWNlLiBUaGlzIGlzIGEgcm91Z2ggYXZlcmFnZSBmb3IgYWxsIHR5cGVzIG9mIGV4ZW1wdGlvbnMgYW5kIGluY2x1ZGVzIHRob3NlIHRoYXQgcmVjZWl2ZWQgbm8gZXhlbXB0aW9ucyBhbmQgbXVsdGlpcGxlIGV4ZW1wdGlvbnMuIA0KDQpWYWx1ZXMgd2VyZSBjYWxjdWxhdGVkIGJ5IHNlbGVjdGluZyBwaW5zIHdpdGggQVZzIGJldHdlZW4gXCQ5MDAwIGFuZCAkMTEsMDAwIGFuZCB0aGVuIGNhbGN1bGF0aW5nIHRoZSBhdmVyYWdlIGN1cnJlbnQgYmlsbCwgY2hhbmdlIGluIGJpbGwsIGFuZCBvdGhlciBzdGF0aXN0aWNzIHNlZW4gaW4gdGhlIHRhYmxlLiBQaW4gY291bnQgdGVsbHMgeW91IHRoZSBudW1iZXIgb2YgcGlucyB0aGF0IHdlcmUgaW5jbHVkZWQgaW4gdGhlIEFWIHJhbmdlIHVzZWQgZm9yIHRoZSAibWVkaWFuIHByb3BlcnR5LiINCg0KYGBge3J9DQpDaGkzIDwtIERvbHRvbkNoaWNhZ28gJT4lIA0KICBmaWx0ZXIoYWdlbmN5X251bSA9PSAiMDMwMjEwMDAwIiAmIHByb3BjbGFzc18xZGlnID09ICIyIiAmIGJldHdlZW4oYXYsOTAwMCwxMTAwMCkpICU+JQ0KICAgIHN1bW1hcml6ZSggICAgICAgICAgICAgIA0KICAgIGNvbXBfdGF4cmF0ZSA9IG1lYW4odGF4X2NvZGVfcmF0ZSwgbmEucm09VFJVRSksDQogICAgYmlsbF9jdXJyZW50ID0gbWVhbih0YXhfYW10X3Bvc3RfZXhlLCBuYS5ybT1UUlVFKSwNCiAgICBiaWxsX2h5cCA9IG1lYW4oZWF2KnRheHJhdGVfbmV3LCBuYS5ybT1UUlVFKSwNCiAgICBiaWxsX2NoYW5nZSA9IGJpbGxfaHlwIC0gYmlsbF9jdXJyZW50LA0KICAgIHRheF9hbXRfcG9zdF9leGUgPSBtZWFuKHRheF9hbXRfcG9zdF9leGUpLA0KICAgIHRheF9hbXRfZXhlID0gbWVhbih0YXhfYW10X2V4ZSwgbmEucm09VFJVRSksDQogICAgdGF4X2FtdF9wcmVfZXhlID0gbWVhbih0YXhfYW10X3ByZV9leGUsIG5hLnJtPVRSVUUpLA0KICAgIHBpbl9jb3VudCA9IG4oKSwNCiAgICBhdiA9IG1lYW4oYXYpLCANCiAgICBlYXYgPSBtZWFuKGVhdikNCiAgKSAlPiUgDQogIHBpdm90X2xvbmdlcihjb2xzID0gY29tcF90YXhyYXRlOmVhdiwgbmFtZXNfdG8gPSAiU3RhdHMiLCB2YWx1ZXNfdG8gPSAiVmFsdWVzIikNCg0KIyBDaGljYWdvIG9ubHkgaGFzIDIgcGlucyB0aGF0IGFyZSBzaW1pbGFyIHRvIERvbHRvbidzIG1lZGlhbiBwaW4gKHdoaWNoIGhhZCBhIGxvdCBvZiBtYXRjaGVzKQ0KRG9sMyA8LSBEb2x0b25DaGljYWdvICU+JSANCiAgZmlsdGVyKGFnZW5jeV9udW0gPT0gIjAzMDMxMDAwMCIgJiBwcm9wY2xhc3NfMWRpZyA9PSAiMiIgJiBiZXR3ZWVuKGF2LCA5MDAwLCAxMTAwMCkpICU+JQ0KICAgIHN1bW1hcml6ZSggICAgICAgICAgICAgIA0KICAgIGNvbXBfdGF4cmF0ZSA9IG1lYW4odGF4X2NvZGVfcmF0ZSwgbmEucm09VFJVRSksDQogICAgYmlsbF9jdXJyZW50ID0gbWVhbih0YXhfYW10X3Bvc3RfZXhlLCBuYS5ybT1UUlVFKSwNCiAgICBiaWxsX2h5cCA9IG1lYW4oZWF2KnRheHJhdGVfbmV3LCBuYS5ybT1UUlVFKSwNCiAgICBiaWxsX2NoYW5nZSA9IGJpbGxfaHlwIC0gYmlsbF9jdXJyZW50LA0KICAgIHRheF9hbXRfcG9zdF9leGUgPSBtZWFuKHRheF9hbXRfcG9zdF9leGUpLA0KICAgIHRheF9hbXRfZXhlID0gbWVhbih0YXhfYW10X2V4ZSwgbmEucm09VFJVRSksDQogICAgdGF4X2FtdF9wcmVfZXhlID0gbWVhbih0YXhfYW10X3ByZV9leGUsIG5hLnJtPVRSVUUpLA0KICAgIHBpbl9jb3VudCA9IG4oKSwNCiAgICBhdiA9IG1lYW4oYXYpLCANCiAgICBlYXYgPSBtZWFuKGVhdikNCiAgKSAlPiUgDQogICAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjb21wX3RheHJhdGU6ZWF2LCBuYW1lc190byA9ICJTdGF0cyIsIHZhbHVlc190byA9ICJWYWx1ZXMiKQ0KDQpib3RoX2R0IDwtIGNiaW5kKENoaTMsIERvbDMpDQoNCg0Ka2JsKGJvdGhfZHQsIGJvb2t0YWJzID0gVCwgZGlnaXRzID0gMCwgDQogICAgY2FwdGlvbiA9ICJQcm9wZXJ0eSBNYWpvciBDbGFzcyAyIENvbXBhcmlzb24sIEFWIH4gJDEwLDAwMCAoQVYgcmFuZ2UgJDkwMDAtJDExMDAwKSIpICU+JQ0KICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBUKSU+JQ0KYWRkX2hlYWRlcl9hYm92ZShjKCJDaGljYWdvIiA9IDIsICJEb2x0b24iID0gMikpDQpgYGANCg0KDQpgYGB7cn0NCkNoaTMgPC0gRG9sdG9uQ2hpY2FnbyAlPiUgDQogIGZpbHRlcihhZ2VuY3lfbnVtID09ICIwMzAyMTAwMDAiICYgcHJvcGNsYXNzXzFkaWcgPT0gIjIiICYgYmV0d2Vlbihhdiw4MDAwLDEyMDAwKSkgJT4lDQogICAgc3VtbWFyaXplKCAgICAgICAgICAgICAgDQogICAgY29tcF90YXhyYXRlID0gbWVhbih0YXhfY29kZV9yYXRlLCBuYS5ybT1UUlVFKSwNCiAgICBiaWxsX2N1cnJlbnQgPSBtZWFuKHRheF9hbXRfcG9zdF9leGUsIG5hLnJtPVRSVUUpLA0KICAgIGJpbGxfaHlwID0gbWVhbihlYXYqdGF4cmF0ZV9uZXcsIG5hLnJtPVRSVUUpLA0KICAgIGJpbGxfY2hhbmdlID0gYmlsbF9oeXAgLSBiaWxsX2N1cnJlbnQsDQogICAgdGF4X2FtdF9wb3N0X2V4ZSA9IG1lYW4odGF4X2FtdF9wb3N0X2V4ZSksDQogICAgdGF4X2FtdF9leGUgPSBtZWFuKHRheF9hbXRfZXhlLCBuYS5ybT1UUlVFKSwNCiAgICB0YXhfYW10X3ByZV9leGUgPSBtZWFuKHRheF9hbXRfcHJlX2V4ZSwgbmEucm09VFJVRSksDQogICAgcGluX2NvdW50ID0gbigpLA0KICAgIGF2ID0gbWVhbihhdiksIA0KICAgIGVhdiA9IG1lYW4oZWF2KQ0KICApICU+JSANCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjb21wX3RheHJhdGU6ZWF2LCBuYW1lc190byA9ICJTdGF0cyIsIHZhbHVlc190byA9ICJWYWx1ZXMiKQ0KDQojIENoaWNhZ28gb25seSBoYXMgMiBwaW5zIHRoYXQgYXJlIHNpbWlsYXIgdG8gRG9sdG9uJ3MgbWVkaWFuIHBpbiAod2hpY2ggaGFkIGEgbG90IG9mIG1hdGNoZXMpDQpEb2wzIDwtIERvbHRvbkNoaWNhZ28gJT4lIA0KICBmaWx0ZXIoYWdlbmN5X251bSA9PSAiMDMwMzEwMDAwIiAmIHByb3BjbGFzc18xZGlnID09ICIyIiAmIGJldHdlZW4oYXYsIDgwMDAsIDEyMDAwKSkgJT4lDQogICAgc3VtbWFyaXplKCAgICAgICAgICAgICAgDQogICAgY29tcF90YXhyYXRlID0gbWVhbih0YXhfY29kZV9yYXRlLCBuYS5ybT1UUlVFKSwNCiAgICBiaWxsX2N1cnJlbnQgPSBtZWFuKHRheF9hbXRfcG9zdF9leGUsIG5hLnJtPVRSVUUpLA0KICAgIGJpbGxfaHlwID0gbWVhbihlYXYqdGF4cmF0ZV9uZXcsIG5hLnJtPVRSVUUpLA0KICAgIGJpbGxfY2hhbmdlID0gYmlsbF9oeXAgLSBiaWxsX2N1cnJlbnQsDQogICAgdGF4X2FtdF9wb3N0X2V4ZSA9IG1lYW4odGF4X2FtdF9wb3N0X2V4ZSksDQogICAgdGF4X2FtdF9leGUgPSBtZWFuKHRheF9hbXRfZXhlLCBuYS5ybT1UUlVFKSwNCiAgICB0YXhfYW10X3ByZV9leGUgPSBtZWFuKHRheF9hbXRfcHJlX2V4ZSwgbmEucm09VFJVRSksDQogICAgcGluX2NvdW50ID0gbigpLA0KICAgIGF2ID0gbWVhbihhdiksIA0KICAgIGVhdiA9IG1lYW4oZWF2KQ0KICApICU+JSANCiAgICBwaXZvdF9sb25nZXIoY29scyA9IGNvbXBfdGF4cmF0ZTplYXYsIG5hbWVzX3RvID0gIlN0YXRzIiwgdmFsdWVzX3RvID0gIlZhbHVlcyIpDQoNCmJvdGhfZHQgPC0gY2JpbmQoQ2hpMywgRG9sMykNCg0KDQprYmwoYm90aF9kdCwgYm9va3RhYnMgPSBULCBkaWdpdHMgPSAwLCANCiAgICBjYXB0aW9uID0gIlByb3BlcnR5IE1ham9yIENsYXNzIDIgQ29tcGFyaXNvbiwgQVYgfiAkMTAsMDAwIChBViByYW5nZSAkODAwMC0kMTIwMDApIikgJT4lDQogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IFQpJT4lDQphZGRfaGVhZGVyX2Fib3ZlKGMoIkNoaWNhZ28iID0gMiwgIkRvbHRvbiIgPSAyKSkNCmBgYA0KSWYgaG9sZGluZyB0aGUgbGV2eSBjb25zdGFudCBhbmQgYWNrbm93bGVkZ2luZyB0aGUgY2hhbmdlIGluIHRheCByYXRlcyB0aGF0IHdvdWxkIG9jY3VyIGZyb20gaGF2aW5nIGFkZGl0aW9uYWwgdGF4YWJsZSBFQVYgd2l0aGluIHRoZSB0YXhpbmcganVyaXNkaWN0aW9ucywgQ2hpY2FnbydzIGh5cG90aGV0aWNhbCB0YXggYmlsbCB3b3VsZCBiZSBcJDE1OTIgKGFuIFwkMTMgaW5jcmVhc2UgZnJvbSBcJDE1NzkpIGFuZCBEb2x0b24ncyB3b3VsZCBiZSBcJDQ1OTggKGEgXCQ5OSBERUNSRUFTRSBmcm9tICQ0NTk2KS4gICANCg0KVmFsdWVzIHdlcmUgY2FsY3VsYXRlZCBieSBzZWxlY3RpbmcgcGlucyB3aXRoIEFWcyBiZXR3ZWVuIFwkODAwMCBhbmQgJDEyLDAwMCBhbmQgdGhlbiBjYWxjdWxhdGluZyB0aGUgYXZlcmFnZSBjdXJyZW50IGJpbGwsIGNoYW5nZSBpbiBiaWxsLCBhbmQgb3RoZXIgc3RhdGlzdGljcyBzZWVuIGluIHRoZSB0YWJsZS4gUGluIGNvdW50IHRlbGxzIHlvdSB0aGUgbnVtYmVyIG9mIHBpbnMgdGhhdCB3ZXJlIGluY2x1ZGVkIGluIHRoZSBBViByYW5nZSB1c2VkIGZvciB0aGUgIm1lZGlhbiBwcm9wZXJ0eS4iDQoNCg0KPiBJbmNyZWFzaW5nIHRoZSBudW1iZXIgb2YgcGlucyBpbmNsdWRlZCBpbiB0aGUgbWVhc3VyZW1lbnQgb2YgImF2ZXJhZ2UgYmlsbCIgYW5kICJhdmVyYWdlIGJpbGwgY2hhbmdlIiBjb21wbGV0ZWx5IGNoYW5nZWQgdGhlIHJlc3VsdHMgZm9yIERvbHRvbi4gVXNpbmcgdGhlICJtZWRpYW4iIHZhbHVlIG11c3QgYmUgZG9uZSBzdXBlciBjYXJlZnVsbHkuIA0KDQo+IElmIHdlICJyZW1vdmVkIiBvbmx5IGhvbWVvd25lcnMgZXhlbXB0aW9ucyBvciBvbmx5IHNlbmlvciBleGVtcHRpb25zLCB0aGVuIHRoZSBtZWRpYW4gc3RhdGlzdGljIHdvdWxkIGJlIG1vcmUgcmVsaWFibGUuLi4gcG90ZW50aWFsbHkuIA0KDQoNCg0KIyMjIENsYXNzIDIwNQ0KDQpUd28gb3IgbW9yZSBzdG9yeSByZXNpZGVuY2UsIG92ZXIgNjIgeWVhcnMsIHVwIHRvIDIsMjAwIHNxLiBmdA0KDQoNCmBgYHtyfQ0KQ2hpMyA8LSBEb2x0b25DaGljYWdvICU+JSANCiAgZmlsdGVyKGFnZW5jeV9udW0gPT0gIjAzMDIxMDAwMCIgJiBjbGFzcyA9PSAiMjA1IiAmIGJldHdlZW4oYXYsODAwMCwxMjAwMCkpICU+JQ0KICAgIHN1bW1hcml6ZSggICAgICAgICAgICAgIA0KICAgIGNvbXBfdGF4cmF0ZSA9IG1lYW4odGF4X2NvZGVfcmF0ZSwgbmEucm09VFJVRSksDQogICAgYmlsbF9jdXJyZW50ID0gbWVhbih0YXhfYW10X3Bvc3RfZXhlLCBuYS5ybT1UUlVFKSwNCiAgICBiaWxsX2h5cCA9IG1lYW4oZWF2KnRheHJhdGVfbmV3LCBuYS5ybT1UUlVFKSwNCiAgICBiaWxsX2NoYW5nZSA9IGJpbGxfaHlwIC0gYmlsbF9jdXJyZW50LA0KICAgIHRheF9hbXRfcG9zdF9leGUgPSBtZWFuKHRheF9hbXRfcG9zdF9leGUpLA0KICAgIHRheF9hbXRfZXhlID0gbWVhbih0YXhfYW10X2V4ZSwgbmEucm09VFJVRSksDQogICAgdGF4X2FtdF9wcmVfZXhlID0gbWVhbih0YXhfYW10X3ByZV9leGUsIG5hLnJtPVRSVUUpLA0KICAgIHBpbl9jb3VudCA9IG4oKSwNCiAgICBhdiA9IG1lYW4oYXYpLCANCiAgICBlYXYgPSBtZWFuKGVhdikNCiAgKSAlPiUgDQogIHBpdm90X2xvbmdlcihjb2xzID0gY29tcF90YXhyYXRlOmVhdiwgbmFtZXNfdG8gPSAiU3RhdHMiLCB2YWx1ZXNfdG8gPSAiVmFsdWVzIikNCg0KDQpEb2wzIDwtIERvbHRvbkNoaWNhZ28gJT4lIA0KICBmaWx0ZXIoYWdlbmN5X251bSA9PSAiMDMwMzEwMDAwIiAmIGNsYXNzID09ICIyMDUiICYgYmV0d2VlbihhdiwgODAwMCwgMTIwMDApKSAlPiUNCiAgICBzdW1tYXJpemUoICAgICAgICAgICAgICANCiAgICBjb21wX3RheHJhdGUgPSBtZWFuKHRheF9jb2RlX3JhdGUsIG5hLnJtPVRSVUUpLA0KICAgIGJpbGxfY3VycmVudCA9IG1lYW4odGF4X2FtdF9wb3N0X2V4ZSwgbmEucm09VFJVRSksDQogICAgYmlsbF9oeXAgPSBtZWFuKGVhdip0YXhyYXRlX25ldywgbmEucm09VFJVRSksDQogICAgYmlsbF9jaGFuZ2UgPSBiaWxsX2h5cCAtIGJpbGxfY3VycmVudCwNCiAgICB0YXhfYW10X3Bvc3RfZXhlID0gbWVhbih0YXhfYW10X3Bvc3RfZXhlKSwNCiAgICB0YXhfYW10X2V4ZSA9IG1lYW4odGF4X2FtdF9leGUsIG5hLnJtPVRSVUUpLA0KICAgIHRheF9hbXRfcHJlX2V4ZSA9IG1lYW4odGF4X2FtdF9wcmVfZXhlLCBuYS5ybT1UUlVFKSwNCiAgICBwaW5fY291bnQgPSBuKCksDQogICAgYXYgPSBtZWFuKGF2KSwgDQogICAgZWF2ID0gbWVhbihlYXYpDQogICkgICU+JSANCiAgICBwaXZvdF9sb25nZXIoY29scyA9IGNvbXBfdGF4cmF0ZTplYXYsIG5hbWVzX3RvID0gIlN0YXRzIiwgdmFsdWVzX3RvID0gIlZhbHVlcyIpDQoNCmJvdGhfZHQgPC0gY2JpbmQoQ2hpMywgRG9sMykNCg0KDQprYmwoYm90aF9kdCwgYm9va3RhYnMgPSBULCBkaWdpdHMgPSAwLCANCiAgICBjYXB0aW9uID0gIlByb3BlcnR5IENsYXNzIDIwNSBDb21wYXJpc29uLCBBViB+ICQxMCwwMDAgKDgwMDAgdG8gMTIwMDAgQVYgcmFuZ2UpIikgJT4lDQogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IFQpJT4lDQphZGRfaGVhZGVyX2Fib3ZlKGMoIkNoaWNhZ28iID0gMiwgIkRvbHRvbiIgPSAyKSkNCmBgYA0KDQoNCiMjIyBDbGFzcyAyMTENCg0KVHdvIHRvIHNpeCByZXNpZGVudGlhbCBhcGFydG1lbnRzLCBhbnkgYWdlLg0KDQoNCmBgYHtyfQ0KQ2hpMyA8LSBEb2x0b25DaGljYWdvICU+JSANCiAgZmlsdGVyKGFnZW5jeV9udW0gPT0gIjAzMDIxMDAwMCIgJiBjbGFzcyA9PSAiMjExIiAmIGJldHdlZW4oYXYsMTcwMDAsMTkwMDApKSAlPiUNCiAgICBzdW1tYXJpemUoICAgICAgICAgICAgICANCiAgICBjb21wX3RheHJhdGUgPSBtZWFuKHRheF9jb2RlX3JhdGUsIG5hLnJtPVRSVUUpLA0KICAgIGJpbGxfY3VycmVudCA9IG1lYW4odGF4X2FtdF9wb3N0X2V4ZSwgbmEucm09VFJVRSksDQogICAgYmlsbF9oeXAgPSBtZWFuKGVhdip0YXhyYXRlX25ldywgbmEucm09VFJVRSksDQogICAgYmlsbF9jaGFuZ2UgPSBiaWxsX2h5cCAtIGJpbGxfY3VycmVudCwNCiAgICB0YXhfYW10X3Bvc3RfZXhlID0gbWVhbih0YXhfYW10X3Bvc3RfZXhlKSwNCiAgICB0YXhfYW10X2V4ZSA9IG1lYW4odGF4X2FtdF9leGUsIG5hLnJtPVRSVUUpLA0KICAgIHRheF9hbXRfcHJlX2V4ZSA9IG1lYW4odGF4X2FtdF9wcmVfZXhlLCBuYS5ybT1UUlVFKSwNCiAgICBwaW5fY291bnQgPSBuKCksDQogICAgYXYgPSBtZWFuKGF2KSwgDQogICAgZWF2ID0gbWVhbihlYXYpDQogICkgJT4lIA0KICBwaXZvdF9sb25nZXIoY29scyA9IGNvbXBfdGF4cmF0ZTplYXYsIG5hbWVzX3RvID0gIlN0YXRzIiwgdmFsdWVzX3RvID0gIlZhbHVlcyIpDQoNCg0KRG9sMyA8LSBEb2x0b25DaGljYWdvICU+JSANCiAgZmlsdGVyKGFnZW5jeV9udW0gPT0gIjAzMDMxMDAwMCIgJiBjbGFzcyA9PSAiMjExIiAmIGJldHdlZW4oYXYsIDE3MDAwLCAxOTAwMCkpICU+JQ0KICAgIHN1bW1hcml6ZSggICAgICAgICAgICAgIA0KICAgIGNvbXBfdGF4cmF0ZSA9IG1lYW4odGF4X2NvZGVfcmF0ZSwgbmEucm09VFJVRSksDQogICAgYmlsbF9jdXJyZW50ID0gbWVhbih0YXhfYW10X3Bvc3RfZXhlLCBuYS5ybT1UUlVFKSwNCiAgICBiaWxsX2h5cCA9IG1lYW4oZWF2KnRheHJhdGVfbmV3LCBuYS5ybT1UUlVFKSwNCiAgICBiaWxsX2NoYW5nZSA9IGJpbGxfaHlwIC0gYmlsbF9jdXJyZW50LA0KICAgIHRheF9hbXRfcG9zdF9leGUgPSBtZWFuKHRheF9hbXRfcG9zdF9leGUpLA0KICAgIHRheF9hbXRfZXhlID0gbWVhbih0YXhfYW10X2V4ZSwgbmEucm09VFJVRSksDQogICAgdGF4X2FtdF9wcmVfZXhlID0gbWVhbih0YXhfYW10X3ByZV9leGUsIG5hLnJtPVRSVUUpLA0KICAgIHBpbl9jb3VudCA9IG4oKSwNCiAgICBhdiA9IG1lYW4oYXYpLCANCiAgICBlYXYgPSBtZWFuKGVhdikNCiAgKSAlPiUgDQogICAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjb21wX3RheHJhdGU6ZWF2LCBuYW1lc190byA9ICJTdGF0cyIsIHZhbHVlc190byA9ICJWYWx1ZXMiKQ0KDQpib3RoX2R0IDwtIGNiaW5kKENoaTMsIERvbDMpDQoNCg0Ka2JsKGJvdGhfZHQsIGJvb2t0YWJzID0gVCwgZGlnaXRzID0gMCwgDQogICAgY2FwdGlvbiA9ICJQcm9wZXJ0eSBDbGFzcyAyMTEgQ29tcGFyaXNvbiwgQVYgfiAkMTgsMDAwIikgJT4lDQogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IFQpJT4lDQphZGRfaGVhZGVyX2Fib3ZlKGMoIkNoaWNhZ28iID0gMiwgIkRvbHRvbiIgPSAyKSkNCmBgYA0KDQoNCg0KIyMjIENsYXNzIDIzNA0KDQpTcGxpdCBsZXZlbCByZXNpZGVuY2UsIHdpdGggYSBsb3dlciBsZXZlbCBiZWxvdyBncmFkZSwgYWxsIGFnZXMsIGFsbCBzaXplcw0KDQoNCmBgYHtyfQ0KQ2hpMyA8LSBEb2x0b25DaGljYWdvICU+JSANCiAgZmlsdGVyKGFnZW5jeV9udW0gPT0gIjAzMDIxMDAwMCIgJiBjbGFzcyA9PSAiMjM0IiAmIGJldHdlZW4oYXYsMTIwMDAsMTMwMDApKSAlPiUNCiAgICBzdW1tYXJpemUoICAgICAgICAgICAgICANCiAgICBjb21wX3RheHJhdGUgPSBtZWFuKHRheF9jb2RlX3JhdGUsIG5hLnJtPVRSVUUpLA0KICAgIGJpbGxfY3VycmVudCA9IG1lYW4odGF4X2FtdF9wb3N0X2V4ZSwgbmEucm09VFJVRSksDQogICAgYmlsbF9oeXAgPSBtZWFuKGVhdip0YXhyYXRlX25ldywgbmEucm09VFJVRSksDQogICAgYmlsbF9jaGFuZ2UgPSBiaWxsX2h5cCAtIGJpbGxfY3VycmVudCwNCiAgICB0YXhfYW10X3Bvc3RfZXhlID0gbWVhbih0YXhfYW10X3Bvc3RfZXhlKSwNCiAgICB0YXhfYW10X2V4ZSA9IG1lYW4odGF4X2FtdF9leGUsIG5hLnJtPVRSVUUpLA0KICAgIHRheF9hbXRfcHJlX2V4ZSA9IG1lYW4odGF4X2FtdF9wcmVfZXhlLCBuYS5ybT1UUlVFKSwNCiAgICBwaW5fY291bnQgPSBuKCksDQogICAgYXYgPSBtZWFuKGF2KSwgDQogICAgZWF2ID0gbWVhbihlYXYpDQogICkgJT4lIA0KICBwaXZvdF9sb25nZXIoY29scyA9IGNvbXBfdGF4cmF0ZTplYXYsIG5hbWVzX3RvID0gIlN0YXRzIiwgdmFsdWVzX3RvID0gIlZhbHVlcyIpDQoNCg0KRG9sMyA8LSBEb2x0b25DaGljYWdvICU+JSANCiAgZmlsdGVyKGFnZW5jeV9udW0gPT0gIjAzMDMxMDAwMCIgJiBjbGFzcyA9PSAiMjM0IiAmIGJldHdlZW4oYXYsIDEyNDUwLCAxMjc1MCkpICU+JQ0KICAgIHN1bW1hcml6ZSggICAgICAgICAgICAgIA0KICAgIGNvbXBfdGF4cmF0ZSA9IG1lYW4odGF4X2NvZGVfcmF0ZSwgbmEucm09VFJVRSksDQogICAgYmlsbF9jdXJyZW50ID0gbWVhbih0YXhfYW10X3Bvc3RfZXhlLCBuYS5ybT1UUlVFKSwNCiAgICBiaWxsX2h5cCA9IG1lYW4oZWF2KnRheHJhdGVfbmV3LCBuYS5ybT1UUlVFKSwNCiAgICBiaWxsX2NoYW5nZSA9IGJpbGxfaHlwIC0gYmlsbF9jdXJyZW50LA0KICAgIHRheF9hbXRfcG9zdF9leGUgPSBtZWFuKHRheF9hbXRfcG9zdF9leGUpLA0KICAgIHRheF9hbXRfZXhlID0gbWVhbih0YXhfYW10X2V4ZSwgbmEucm09VFJVRSksDQogICAgdGF4X2FtdF9wcmVfZXhlID0gbWVhbih0YXhfYW10X3ByZV9leGUsIG5hLnJtPVRSVUUpLA0KICAgIHBpbl9jb3VudCA9IG4oKSwNCiAgICBhdiA9IG1lYW4oYXYpLCANCiAgICBlYXYgPSBtZWFuKGVhdikpICU+JSANCiAgICBwaXZvdF9sb25nZXIoY29scyA9IGNvbXBfdGF4cmF0ZTplYXYsIG5hbWVzX3RvID0gIlN0YXRzIiwgdmFsdWVzX3RvID0gIlZhbHVlcyIpDQoNCmJvdGhfZHQgPC0gY2JpbmQoQ2hpMywgRG9sMykNCg0KDQprYmwoYm90aF9kdCwgYm9va3RhYnMgPSBULCBkaWdpdHMgPSAwLCANCiAgICBjYXB0aW9uID0gIlByb3BlcnR5IENsYXNzIDIzNCBDb21wYXJpc29uLCBBViB+ICQxMiw1MDAiKSAlPiUNCiAga2FibGVfc3R5bGluZyhmdWxsX3dpZHRoID0gVCklPiUNCmFkZF9oZWFkZXJfYWJvdmUoYygiQ2hpY2FnbyIgPSAyLCAiRG9sdG9uIiA9IDIpKQ0KYGBgDQoNCg0KDQoNCg0KIyAiQ29zdCIgb2YgRXhlbXB0aW9ucw0KDQoNCmBgYHtyfQ0KIyBUQ19iaWxsc19jdXJyZW50IGhhcyB0aGUgc3VtbWVkIHRheGJpbGwgaW5mb3JtYXRpb24gdGhhdCBjb21lcyBmcm9tIHRoZSB0YXhfYmlsbCgpIGNvbW1hbmQgaW4gcHRheHNpbQ0KVENfYmlsbHNfY3VycmVudCA8LSByZWFkX2NzdigiMl9TdW1tZWRfQmlsbHNfYnlfVGF4Y29kZV9hbmRfQ2xhc3MuY3N2IikgJT4lIA0KICAjZmlsdGVyKGNsYXNzID09ICIyMDUiKSAlPiUNCiAgbXV0YXRlKHRheF9jb2RlID0gYXMuY2hhcmFjdGVyKHRheF9jb2RlKSwNCiAgICAgICAgIGNsYXNzID0gYXMuY2hhcmFjdGVyKGNsYXNzKSkNCg0KY2xhc3NfZGljdCRjbGFzc19jb2RlIDwtIGFzLmNoYXJhY3RlcihjbGFzc19kaWN0JGNsYXNzX2NvZGUpDQogDQojbXVuaV90YXhfY29kZXMgJT4lIHNlbGVjdCh0YXhfY29kZV9udW0sIHRheF9jb2RlX3JhdGUsIGFnZW5jeV9udW0pDQpUQ19iaWxsc19jdXJyZW50IDwtIGxlZnRfam9pbihUQ19iaWxsc19jdXJyZW50LCBtdW5pX3RheF9jb2RlcywNCiAgICAgICAgICAgICAgICAgICAgICBieSA9IGMoInRheF9jb2RlIiA9ICJ0YXhfY29kZV9udW0iKSkgDQoNClRDX2JpbGxzX2N1cnJlbnQgPC0gVENfYmlsbHNfY3VycmVudCAlPiUgbGVmdF9qb2luKG11bmlfYWdlbmN5X25hbWVzKSAlPiUgbGVmdF9qb2luKG5pY2tuYW1lcykgJT4lIHNlbGVjdCgtYyhzaHBmaWxlX25hbWUsIENvbHVtbjEsIGBNb3N0IHJlY2VudCByZWFzc2Vzc2VkYCwgc2hvcnRfbmFtZSwgbWlub3JfdHlwZSwgYWdlbmN5X25hbWUsIGFnZW5jeV9udW1iZXIpKQ0KDQpUQ19iaWxsc19jdXJyZW50DQpgYGANCg0KDQpgYGB7ciBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQ0KDQpUQ19iaWxsc19jdXJyZW50ICU+JSAgDQogIyBsZWZ0X2pvaW4obXVuaV9hZ2VuY3lfbmFtZXMsIGJ5ID0gImFnZW5jeV9udW0iKSAlPiUNCiAjIGxlZnRfam9pbihuaWNrbmFtZXMsIGJ5ID0gYygiYWdlbmN5X25hbWUiID0gImFnZW5jeV9uYW1lIikpICU+JQ0KICBmaWx0ZXIoIWFnZW5jeV9udW0gJWluJSBjcm9zc19jb3VudHlfbGluZXMpICU+JQ0KICMgZ3JvdXBfYnkoY2xlYW5fbmFtZSwgYWdlbmN5X25hbWUpICU+JQ0KICBzdW1tYXJpemUoTXVuaUxldnkgPSByb3VuZChzdW0oZmluYWxfdGF4X3RvX2Rpc3QsIG5hLnJtID0gVFJVRSksIGRpZ2l0cyA9IDApLCAjIGFtb3VudCBiaWxsZWQgYnkgbXVuaXMgd2l0aCBjdXJyZW50IGV4ZW1wdGlvbnMgaW4gcGxhY2UNCiAgICAgICAgICAgIG5vblRJRl9FQVZfcG9zdF9leGVtcHMgPSByb3VuZChzdW0oZmluYWxfdGF4X3RvX2Rpc3QvKHRheF9jb2RlX3JhdGUvMTAwKSwgbmEucm0gPSBUUlVFKSwgMCksDQogICAgICAgICAgICBUSUZfaW5jcmVtZW50X0VBViA9IHN1bShmaW5hbF90YXhfdG9fdGlmLyh0YXhfY29kZV9yYXRlLzEwMCksIG5hLnJtPVRSVUUpLCAgDQogICAgICAgICAgICBFeGVtcHRfRUFWID0gc3VtKHRheF9hbXRfZXhlLyh0YXhfY29kZV9yYXRlLzEwMCksIG5hLnJtPVRSVUUpLCANCiAgICAgICAgICAgIFRvdGFsX0VBViA9IHN1bSgodGF4X2FtdF9leGUrZmluYWxfdGF4X3RvX2Rpc3QrZmluYWxfdGF4X3RvX3RpZikvKHRheF9jb2RlX3JhdGUvMTAwKSwgbmEucm0gPSBUUlVFKSkgJT4lDQoNCiAgbXV0YXRlKHRheF9yYXRlX2N1cnJlbnQgPSByb3VuZChNdW5pTGV2eS9ub25USUZfRUFWX3Bvc3RfZXhlbXBzLDQpLA0KICAgICAgICAgbm9uVElGX0VBVl9wcmVfZXhlbXBzID0gcm91bmQobm9uVElGX0VBVl9wb3N0X2V4ZW1wcyArIEV4ZW1wdF9FQVYpLA0KICAgICAgICAgdGF4cmF0ZV9uZXcgPSByb3VuZChNdW5pTGV2eS9ub25USUZfRUFWX3ByZV9leGVtcHMsNCksDQogICAgICAgICB0YXhyYXRlX2NoYW5nZSA9IHJvdW5kKHRheF9yYXRlX2N1cnJlbnQtdGF4cmF0ZV9uZXcsIDQpICklPiUgDQogIyBzZWxlY3QoY2xlYW5fbmFtZSwgdGF4cmF0ZV9jaGFuZ2UsIHRheF9yYXRlX2N1cnJlbnQsIHRheHJhdGVfbmV3LCBldmVyeXRoaW5nKCkpICU+JSANCiAgYXJyYW5nZShkZXNjKHRheF9yYXRlX2N1cnJlbnQpKSAlPiUNCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBNdW5pTGV2eTp0YXhyYXRlX2NoYW5nZSkgJT4lDQogIG11dGF0ZSh2YWx1ZSA9IHZhbHVlKQ0KDQpgYGANCg0KDQpgYGB7cn0NCkN1cnJlbnRfVGF4cmF0ZXMgJT4lIA0KICBmaWx0ZXIoY2xlYW5fbmFtZSAhPSAiQ2hpY2FnbyIpICU+JQ0KICBtdXRhdGUodHJhbnNmZXJlZF90YXhlcyA9IHRheF9yYXRlX2N1cnJlbnQqRXhlbXB0X0VBVikgJT4lIA0KICAgIG11dGF0ZShhZ2VuY3lfbmFtZSA9IGlmZWxzZShhZ2VuY3lfbmFtZSA9PSAiVE9XTiBDSUNFUk8iLCAiQ0lUWSBPRiBDSUNFUk8iLCBhZ2VuY3lfbmFtZSkgDQogICAgKSAlPiUNCiAgZnVsbF9qb2luKG11bmlfc2hwLCBieSA9IGMoImFnZW5jeV9uYW1lIiA9ICJBR0VOQ1lfREVTQyIpKSAlPiUNCg0KICAgIGdncGxvdChhZXMoZmlsbCA9IHRyYW5zZmVyZWRfdGF4ZXMpKSArDQogICAgZ2VvbV9zZihhZXMoZ2VvbWV0cnkgPSBnZW9tZXRyeSksIGNvbG9yID0gImJsYWNrIikgKw0KICB0aGVtZV92b2lkKCkgKyANCiAgdGhlbWUoYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpKSsNCnNjYWxlX2ZpbGxfc3RlcHMyKA0KICAgIGhpZ2ggPSAiIzQyMDQyMCIsIGxvdyA9ICJibGFjayIsDQogICMgbWlkcG9pbnQgPSBtZWRpYW4odHJhbnNmZXJlZF90YXhlcyksDQogICAgICAgICAgICAgICAgICAgc2hvdy5saW1pdHM9VFJVRSwNCiAgbmljZS5icmVha3M9RkFMU0UsDQogIG5hLnZhbHVlPU5BLA0KICAgICAgICAgICAgICAgICAgICBuID02LA0KICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gIlJldmVudWUgU2hpZnRlZCBcbmZyb20gRXhlbXB0aW9ucyIsDQogICAgICAgICBsYWJlbHMgPSBzY2FsZXM6OmRvbGxhcg0KKSsNCiANCiAgbGFicyh0aXRsZSA9ICJEb2xsYXJzIHBhc3NlZCBmcm9tIENsYXNzIDIgUmVzaWRlbnRpYWwgcHJvcGVydGllcyB0byBvdGhlcnMgXG5kdWUgdG8gY3VycmVudCBleGVtcHRpb25zIiwgICAgDQogICAgICAgICBjYXB0aW9uID0gIlRoZXJlIHdhcyAkNDYwIG1pbGxpb24gaW4gZXhlbXB0IEVBViBpbiBDaGljYWdvLiIpDQoNCmdnc2F2ZSgiY29va19ub2NoaWNhZ28ucG5nIikNCmBgYA0KDQpgYGB7ciBldmFsID0gRkFMU0V9DQojIENsYXNzIDIgb25seQ0KY2xhc3MyX3BlcmMgPC0gZXhlbXB0aW9uc19ieV9jbGFzc19wZXJfVEMgJT4lIA0KICBmaWx0ZXIoY2xhc3NfY29kZSA+PTIwMCAmIGNsYXNzX2NvZGUgPD0yOTkpICU+JQ0KICBncm91cF9ieShjbGVhbl9uYW1lLCBtYWpvcl9jbGFzc19jb2RlLCBhZ2VuY3lfbmFtZSwgYWdlbmN5X251bS54KSAlPiUNCiAgc3VtbWFyaXplKGVhdiA9IHN1bShlYXYpLA0KICAgICAgICAgICBleGVtcHRfRUFWID0gc3VtKGV4ZW1wdF9FQVYsIGV4ZV9hYmF0ZSwgbmEucm09VFJVRSksDQogICAgICAgICB0YXhfYmFzZV9jdXJyZW50ID0gc3VtKHRheF9iYXNlX2N1cnJlbnQsIG5hLnJtPVRSVUUpLA0KICAgICAgICAgdGF4X2Jhc2Vfbm9leGVtcHMgPSBzdW0odGF4X2Jhc2Vfbm9leGVtcHMsIG5hLnJtPVRSVUUpKSAlPiUgDQogIGxlZnRfam9pbihtdW5pX2VhdikgJT4lDQogIG11dGF0ZShwZXJjX2NsYXNzMl90b3RhbEVBViA9IGVhdiAvIG11bmlfRUFWX2luY2x1ZGVzVElGKSAlPiUgICAgDQogIG11dGF0ZShhZ2VuY3lfbmFtZSA9IGlmZWxzZShhZ2VuY3lfbmFtZSA9PSAiVE9XTiBDSUNFUk8iLCAiQ0lUWSBPRiBDSUNFUk8iLCBhZ2VuY3lfbmFtZSkgKQ0KDQoNCg0KDQpjbGFzczJfcGVyYyA8LSBjbGFzczJfcGVyYyAlPiUgICBtdXRhdGUocGVyY2VudF9leGVtcHQgPSBleGVtcHRfRUFWL211bmlfdGF4X2Jhc2Vfbm9leGVtcHMpIA0KDQoNCmNsYXNzMl9wZXJjICU+JSANCiAgICBtdXRhdGUoYWdlbmN5X25hbWUgPSBpZmVsc2UoYWdlbmN5X25hbWUgPT0gIlRPV04gQ0lDRVJPIiwgIkNJVFkgT0YgQ0lDRVJPIiwgYWdlbmN5X25hbWUpIA0KICAgICkgJT4lDQogIGxlZnRfam9pbihtdW5pX3NocCwgYnkgPSBjKCJhZ2VuY3lfbmFtZSIgPSAiQUdFTkNZX0RFU0MiKSkgJT4lDQoNCiAgICBnZ3Bsb3QoYWVzKGZpbGwgPSBwZXJjZW50X2V4ZW1wdCkpICsNCiAgICBnZW9tX3NmKGFlcyhnZW9tZXRyeSA9IGdlb21ldHJ5KSwgY29sb3IgPSAiYmxhY2siKSArIA0KICAgICAgdGhlbWVfdm9pZCgpICsgDQogIHRoZW1lKGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSkrDQpzY2FsZV9maWxsX3N0ZXBzMigNCiAgICBoaWdoID0gIiM0MjA0MjAiLCBsb3cgPSAiYmxhY2siLA0KICAgbWlkcG9pbnQgPSBtZWRpYW4oY2xhc3MyX3BlcmMkcGVyY2VudF9leGVtcHQpLA0KICAgICAgICAgICAgICAgICAgIHNob3cubGltaXRzPVRSVUUsDQogIG5pY2UuYnJlYWtzPUZBTFNFLA0KICAgICAgICAgICAgICAgICAgICBuID02LA0KICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gIlBlcmNlbnQgRXhlbXB0IiwNCiAgICAgICAgIGxhYmVscyA9IHNjYWxlczo6cGVyY2VudA0KKSMrDQogDQojICBsYWJzKHRpdGxlID0gIlBlcmNlbnQgb2YgcHJlLWV4ZW1wdGlvbiB0YXhhYmxlIGJhc2UgdGhhdCBpcyB0YXggZXhlbXB0IiwgICAgDQogIyAgICAgICAgY2FwdGlvbiA9ICJUb3RhbCBFQVYgaW5jbHVkZXMgdGhlIHByZS1leGVtcHRpb24gVGF4YWJsZSBCYXNlLiANCiAjICAgICAgVElGIGluY3JlbWVudCBFQVYgaXMgbm90IGluY2x1ZGVkIGluIHRoZSB0b3RhbCBFQVYgaW4gdGhpcyBpbWFnZS4NCiAjICAgICAgTWVkaWFuIHZhbHVlIGlzIDEyLjQzJSIpDQpgYGANCg0KYGBge3IgZXZhbD1GQUxTRX0NCmNsYXNzMl9wZXJjIDwtIGNsYXNzMl9wZXJjICU+JSAgbXV0YXRlKHBlcmNlbnRfZXhlbXB0ID0gZXhlbXB0X0VBVi9tdW5pX0VBVl9pbmNsdWRlc1RJRikgDQoNCmNsYXNzMl9wZXJjJT4lDQogICAgbXV0YXRlKGFnZW5jeV9uYW1lID0gaWZlbHNlKGFnZW5jeV9uYW1lID09ICJUT1dOIENJQ0VSTyIsICJDSVRZIE9GIENJQ0VSTyIsIGFnZW5jeV9uYW1lKSANCiAgICApICU+JQ0KICBsZWZ0X2pvaW4obXVuaV9zaHAsIGJ5ID0gYygiYWdlbmN5X25hbWUiID0gIkFHRU5DWV9ERVNDIikpICU+JQ0KDQogICAgZ2dwbG90KGFlcyhmaWxsID0gcGVyY2VudF9leGVtcHQpKSArDQogICAgZ2VvbV9zZihhZXMoZ2VvbWV0cnkgPSBnZW9tZXRyeSksIGNvbG9yID0gImJsYWNrIikgKyANCiAgICAgIHRoZW1lX3ZvaWQoKSArIA0KICB0aGVtZShheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCkpKw0Kc2NhbGVfZmlsbF9zdGVwczIoDQogICAgaGlnaCA9ICIjNDIwNDIwIiwgbG93ID0gImJsYWNrIiwNCiBtaWRwb2ludCA9IG1lZGlhbihjbGFzczJfcGVyYyRwZXJjZW50X2V4ZW1wdCksDQogICAgICAgICAgICAgICAgICAgc2hvdy5saW1pdHM9VFJVRSwNCiAgbmljZS5icmVha3M9RkFMU0UsDQogICAgICAgICAgICAgICAgICAgIG4gPTYsDQogICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiUGVyY2VudCBFeGVtcHQiLA0KICAgICAgICAgbGFiZWxzID0gc2NhbGVzOjpwZXJjZW50DQopKw0KIA0KICBsYWJzKHRpdGxlID0gIlBlcmNlbnQgRXhlbXB0OiAgRXhlbXB0IEVBViAvIEFsbCBFQVYgaW4gTXVuaWNpcGFsaXR5IikNCmBgYA0KDQpgYGB7cn0NCg0KdGF4X2JpbGxfY2hhbmdlICU+JSANCiAjIGZpbHRlcihtYWpvcl9jbGFzc19jb2RlID09ICIyIikgJT4lIA0KICBmaWx0ZXIoY2xhc3NfY29kZSA+PTIwMCAmIGNsYXNzX2NvZGUgPD0gMjk5KSAlPiUNCiAgZmlsdGVyKGNsYXNzX2NvZGUgIT0gIjAiKSAlPiUNCiAgIG11dGF0ZShjbGFzc19jb2RlID0gYXMuY2hhcmFjdGVyKGNsYXNzX2NvZGUpKSAlPiUNCiAgbGVmdF9qb2luKG5pY2tuYW1lcykgJT4lDQogIGZpbHRlcihUcmlhZCA9PSAiU291dGgiKSAlPiUNCiAgc3VtbWFyaXplKGNvc3RfaW5jcmVhc2VkYmlsbHMgPSBzdW0oYmlsbF9jaGFuZ2UsIG5hLnJtPVRSVUUpKQ0KDQoNClRDX2JpbGxzX2N1cnJlbnQgJT4lICBmaWx0ZXIoY2xhc3MgIT0gIjAiKSAlPiUNCiBzdW1tYXJpemUoY29zdF9leGVtcHMgPSBzY2FsZXM6OmRvbGxhcihzdW0odGF4X2FtdF9leGUpKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21wb3NpdGVfcmF0ZSA9IG1lYW4odGF4X2NvZGVfcmF0ZSkpIA0KDQoNClRDX2JpbGxzX2N1cnJlbnQgICU+JSANCiAgZmlsdGVyKGNsYXNzICE9ICIwIikgJT4lDQogIGdyb3VwX2J5KFRyaWFkKSAlPiUgDQogIHN1bW1hcml6ZShjb3N0X2V4ZW1wcyA9IHNjYWxlczo6ZG9sbGFyKHN1bSh0YXhfYW10X2V4ZSkpLA0KICAgICAgICAgICAgY29tcG9zaXRlX3JhdGUgPSBtZWFuKHRheF9jb2RlX3JhdGUpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSANCg0KIyBUQ19iaWxsc19jdXJyZW50ICU+JSBncm91cF9ieShUcmlhZCkgJT4lIA0KYGBgDQoNCn5+Q292ZXJpbmcgYWxsIGNoYW5nZXMgaW4gdGF4IGJpbGxzIGluIHRoZSBTb3V0aCB0cmlhZCB3b3VsZCBjb3N0IFwkMjE4LDY3OCwzMjgufn4NCg0Kfn5QYXlpbmcgZm9yIGFsbCB0YXggYmlsbHMgdGhhdCBleHBlcmllbmNlZCBhIDE1JSBpbmNyZWFzZSBmcm9tIHRoZSBlbGltaW5hdGlvbiBvZiBleGVtcHRpb25zIG9yIGhhZCBhIFwkMCB0YXhiaWxsIHdvdWxkIGNvc3QgXCQ4MjUsOTYzLDQxMS5+fg0KDQpgYGB7cn0NCnRheF9iaWxsX2NoYW5nZSAlPiUgdW5ncm91cCgpICU+JQ0KICBmaWx0ZXIoY2xhc3NfY29kZSA9PSAiMjAzIikgJT4lDQogICBtdXRhdGUoY2xhc3NfY29kZSA9IGFzLmNoYXJhY3RlcihjbGFzc19jb2RlKSkgJT4lDQogIGxlZnRfam9pbihuaWNrbmFtZXMpDQoNCg0KdGF4X2JpbGxfY2hhbmdlICU+JSB1bmdyb3VwKCkgJT4lDQogIGZpbHRlcihjbGFzc19jb2RlID09ICIyMDMiKSAlPiUNCiAgICBmaWx0ZXIoY2xlYW5fbmFtZSAlaW4lIGMoIlBhcmsgRm9yZXN0IiwiTWFya2hhbSIsICAiRG9sdG9uIiwgIkhpbGxzaWRlIiwgIlJpdmVyc2lkZSIsICJDaGljYWdvIiwgIldlc3RjaGVzdGVyIiwgIldpbm5ldGthIikpICU+JQ0KICAgbXV0YXRlKGNsYXNzX2NvZGUgPSBhcy5jaGFyYWN0ZXIoY2xhc3NfY29kZSkpICU+JQ0KICBsZWZ0X2pvaW4obmlja25hbWVzKSU+JQ0KZ3JvdXBfYnkoVHJpYWQsIGNsZWFuX25hbWUpDQpgYGANCg0KIyMgT3RoZXIgRXhlbXB0aW9uIFNjZW5hcmlvcw0KDQojIyMgVGF4YWJsZSBCYXNlIGluIFNjZW5hcmlvcw0KDQpgYGB7cn0NCmV4ZW1wdGlvbnMgPC0gcmVhZF9jc3YoIjNfRXhlbXB0aW9uX0RldGFpbHNfb3V0cHV0LWFsbF9jb29rX3Bpbl9leGVtcHRpb25zXzIwMjFfYWN0dWFsLmNzdiIpIA0KIyBoZWFkKGV4ZW1wdGlvbnMpDQoNCg0KZXhlbXB0aW9ucyA8LSBleGVtcHRpb25zICU+JSANCiAgc2VsZWN0KHBpbiwgYXYsIGVhdl9vcmlnaW5hbCA9IGVhdiwgY2xhc3NfY29kZSwgdGF4X2NvZGVfbnVtLCBtYWpvcl9jbGFzc19jb2RlLCBleGVfaG9tZW93bmVyOmV4ZV9hYmF0ZSkgJT4lDQogIA0KICBtdXRhdGUoZXhlX3ZldF9kaXMgPSBleGVfdmV0X2Rpc19sdDUwICsgZXhlX3ZldF9kaXNfNTBfNjkgKyBleGVfdmV0X2Rpc19nZTcwLA0KICAgICAgICAgdG90YWxfZXhlbXB0X2VhdiA9IGV4ZV9ob21lb3duZXIgKyBleGVfc2VuaW9yICsgZXhlX2ZyZWV6ZSArIGV4ZV9sb25ndGltZV9ob21lb3duZXIgKyANCiAgICAgICAgICAgZXhlX2Rpc2FibGVkICsgZXhlX3ZldF9yZXR1cm5pbmcgKyBleGVfdmV0X2RpcyArIGV4ZV9hYmF0ZSwNCiAgICAgICAgIGhhc19ob21lb3duID0gaWZlbHNlKGV4ZV9ob21lb3duZXIgPiAwLCAxLCAwKSwNCiAgICAgICAgIGhhc19zZW5pb3IgPSBpZmVsc2UoZXhlX3NlbmlvciA+IDAsIDEsIDApLA0KICAgICAgICAgaGFzX2ZyZWV6ZSA9IGlmZWxzZShleGVfZnJlZXplID4gMCwgMSwgMCksDQogICAgICAgICANCiAgICAgICAgIGhhc19zZW5pb3JleGVtcHMgPSBpZmVsc2UoZXhlX3NlbmlvciA+IDAgJiBleGVfZnJlZXplID4gMCwgMSwgMCksDQogICAgICAgICBoYXNfZGlzYWJpbGl0eSA9IGlmZWxzZShleGVfZGlzYWJsZWQgPiAwLCAxLCAwKSwNCiAgICAgICAgIGhhc192ZXRyZXR1cm4gPSBpZmVsc2UoZXhlX3ZldF9yZXR1cm5pbmcgPiAwLCAxLCAwKSwgDQogICAgICAgICANCiAgICAgICAgIGhhc19hbnlfZXhlbXBzID0gaWZlbHNlKHRvdGFsX2V4ZW1wdF9lYXYgPiAwLCAxLCAwKSwNCiAgICAgICAgIGhhc19tdWx0aV9leGVtcHMgPSBpZmVsc2UoaGFzX3NlbmlvciArIGhhc19mcmVlemUgKyBoYXNfaG9tZW93biArIGhhc19kaXNhYmlsaXR5ICsgaGFzX3ZldHJldHVybiA+IDEsIDEsIDApKSAlPiUgDQogIA0KICBtdXRhdGUodGF4X2NvZGVfbnVtID0gYXMuY2hhcmFjdGVyKHRheF9jb2RlX251bSkpJT4lDQogIGxlZnRfam9pbihtdW5pX3RheF9jb2RlcykgJT4lIA0KICBsZWZ0X2pvaW4obXVuaV9hZ2VuY3lfbmFtZXMpICU+JSANCiAgbGVmdF9qb2luKG5pY2tuYW1lcykNCg0KIyBoZWFkKGV4ZW1wdGlvbnMpDQoNCiN0YWJsZShleGVtcHRpb25zJGhhc19hbnlfZXhlbXBzKQ0KI3RhYmxlKGV4ZW1wdGlvbnMkaGFzX3NlbmlvcmV4ZW1wcykNCiN0YWJsZShleGVtcHRpb25zJGhhc19tdWx0aV9leGVtcHMpDQoNCmhhc19leGVtcHRpb25zX3BpbnMgPC0gIGV4ZW1wdGlvbnMgJT4lIA0KICBmaWx0ZXIoaGFzX2FueV9leGVtcHMgPT0gMSkNCg0KIyBoZWFkKGhhc19leGVtcHRpb25zX3BpbnMpDQoNCmhhc19leGVtcHRpb25zX3BpbnMgJT4lIA0KICBzdW1tYXJpemUoDQogICAgYXYgPSBzdW0oYXYsIG5hLnJtID0gVFJVRSksDQogICAgRUFWX2JlZm9yZUV4ZW1wdHNPclRJRj1zdW0oZWF2X29yaWdpbmFsLCBuYS5ybT1UUlVFKSwNCiAgICB0b3RhbF9leGVtcHRfZWF2ID0gc3VtKGV4ZV9ob21lb3duZXIgKyBleGVfc2VuaW9yICsgZXhlX2ZyZWV6ZSArIGV4ZV9sb25ndGltZV9ob21lb3duZXIgKyANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhlX2Rpc2FibGVkICsgZXhlX3ZldF9yZXR1cm5pbmcgKyBleGVfdmV0X2RpcyArIGV4ZV9hYmF0ZSwgbmEucm09VFJVRSksDQogICAgaG9tZW93bmVyc19leGVtcHRpb24gPSBzdW0oZXhlX2hvbWVvd25lciksDQogICAgc2VuaW9yX2V4ZW1wdGlvbiA9IHN1bShleGVfc2VuaW9yLCBuYS5ybT1UUlVFKSwNCiAgICBmcmVlemVfZXhlbXB0aW9uID0gc3VtKGV4ZV9mcmVlemUsIG5hLnJtPVRSVUUpLA0KICAgIG90aGVyX2V4ZW1wdGlvbnMgPSBzdW0oZXhlX3ZldF9kaXMgKyBleGVfZGlzYWJsZWQgKyBleGVfbG9uZ3RpbWVfaG9tZW93bmVyICsgZXhlX3ZldF9yZXR1cm5pbmcgKyBleGVfYWJhdGUpKSAgDQoNCg0KbXVuaV9leGVtcHRfZWF2IDwtIGhhc19leGVtcHRpb25zX3BpbnMgJT4lIA0KICBncm91cF9ieShjbGVhbl9uYW1lLCBhZ2VuY3lfbnVtKSAlPiUNCiAgc3VtbWFyaXplKA0KICAgIGF2X2hhc2V4ZW1wcyA9IHN1bShhdiwgbmEucm0gPSBUUlVFKSwNCiAgICBlYXZfb3JpZ2luYWxfaGFzZXhlbXBzPXN1bShlYXZfb3JpZ2luYWwsIG5hLnJtPVRSVUUpLA0KICAgIHRvdGFsX2V4ZW1wdF9lYXYgPSBzdW0oZXhlX2hvbWVvd25lciArIGV4ZV9zZW5pb3IgKyBleGVfZnJlZXplICsgZXhlX2xvbmd0aW1lX2hvbWVvd25lciArIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleGVfZGlzYWJsZWQgKyBleGVfdmV0X3JldHVybmluZyArIGV4ZV92ZXRfZGlzICsgZXhlX2FiYXRlLCBuYS5ybT1UUlVFKSwNCiAgICBob21lb3duZXJzX2V4ZW1wdGlvbiA9IHN1bShleGVfaG9tZW93bmVyKSwNCiAgICBzZW5pb3JfZXhlbXB0aW9uID0gc3VtKGV4ZV9zZW5pb3IsIG5hLnJtPVRSVUUpLA0KICAgIGZyZWV6ZV9leGVtcHRpb24gPSBzdW0oZXhlX2ZyZWV6ZSwgbmEucm09VFJVRSksDQogICAgb3RoZXJfZXhlbXB0aW9ucyA9IHN1bShleGVfdmV0X2RpcyArIGV4ZV9kaXNhYmxlZCArIGV4ZV9sb25ndGltZV9ob21lb3duZXIgKyBleGVfdmV0X3JldHVybmluZyArIGV4ZV9hYmF0ZSksIA0KICAgICNwaW5fY291bnRfaGFzZXhlbXB0aW9ucyA9IG4oKSwNCiAgICBQQ19oYXNfZXhlID0gbigpICMgaGFzIGF0IGxlYXN0IG9uZSBleGVtcHRpb24gYXNzb2NpYXRlZCB3aXRoIHRoZSBwaW4NCiAgICApIA0KDQoNCiMgbXVuaV9leGVtcHRfZWF2ICU+JSBzZWxlY3QoLWFnZW5jeV9udW0pDQoNCm11bmlfQzJfaGFzX2V4ZV9lYXYgPC0gaGFzX2V4ZW1wdGlvbnNfcGlucyAlPiUNCiAgZ3JvdXBfYnkoY2xlYW5fbmFtZSwgYWdlbmN5X251bSkgJT4lDQogIGZpbHRlcihtYWpvcl9jbGFzc19jb2RlID09ICIyIikgJT4lDQogIHN1bW1hcml6ZSgNCiAgICBhdl9oYXNleGVtcHMgPSBzdW0oYXYsIG5hLnJtID0gVFJVRSksDQogICAgZWF2X29yaWdpbmFsX2hhc2V4ZW1wcz1zdW0oZWF2X29yaWdpbmFsLCBuYS5ybT1UUlVFKSwNCiAgICB0b3RhbF9leGVtcHRfZWF2ID0gc3VtKGV4ZV9ob21lb3duZXIgKyBleGVfc2VuaW9yICsgZXhlX2ZyZWV6ZSArIGV4ZV9sb25ndGltZV9ob21lb3duZXIgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleGVfZGlzYWJsZWQgKyBleGVfdmV0X3JldHVybmluZyArIGV4ZV92ZXRfZGlzICsgZXhlX2FiYXRlLCBuYS5ybT1UUlVFKSwNCiAgICBob21lb3duZXJzX2V4ZW1wdGlvbiA9IHN1bShleGVfaG9tZW93bmVyKSwNCiAgICBzZW5pb3JfZXhlbXB0aW9uID0gc3VtKGV4ZV9zZW5pb3IsIG5hLnJtPVRSVUUpLA0KICAgIGZyZWV6ZV9leGVtcHRpb24gPSBzdW0oZXhlX2ZyZWV6ZSwgbmEucm09VFJVRSksDQogICAgb3RoZXJfZXhlbXB0aW9ucyA9IHN1bShleGVfdmV0X2RpcyArIGV4ZV9kaXNhYmxlZCArIGV4ZV9sb25ndGltZV9ob21lb3duZXIgKyBleGVfdmV0X3JldHVybmluZyArIGV4ZV9hYmF0ZSksDQogICAgUENfQzJfaGFzX2V4ZSA9IG4oKQ0KICAgICkNCg0KDQptdW5pX3NpbmdmYW1yZXNfaGFzX2hvbWVvd25lcnNfZXhlbXBzIDwtIGhhc19leGVtcHRpb25zX3BpbnMgJT4lIA0KICBmaWx0ZXIoY2xhc3NfY29kZSA+IDE5OSAmIGNsYXNzX2NvZGUgPCAyMTEpICU+JQ0KICBmaWx0ZXIoZXhlX2hvbWVvd25lciA+IDApICU+JQ0KICBncm91cF9ieShjbGVhbl9uYW1lLCBhZ2VuY3lfbnVtKSAlPiUNCiAgc3VtbWFyaXplKA0KICAgIGF2X3NpbmdmYW1faGFzX2hvbWVvd25leGVtcHMgPSBzdW0oYXYsIG5hLnJtID0gVFJVRSksDQogICAgZWF2X29yaWdpbmFsX3NpbmdfZmFtX2hhc19ob21lb3duZXhlbXBzPXN1bShlYXZfb3JpZ2luYWwsIG5hLnJtPVRSVUUpLA0KICAgIHRvdGFsX2V4ZW1wdF9lYXZfc2luZ2ZhbV9oYXNfaG9tZW93biA9IHN1bShleGVfaG9tZW93bmVyICsgZXhlX3NlbmlvciArIGV4ZV9mcmVlemUgKyBleGVfbG9uZ3RpbWVfaG9tZW93bmVyICsgZXhlX2Rpc2FibGVkICsgZXhlX3ZldF9yZXR1cm5pbmcgKyBleGVfdmV0X2RpcyArIGV4ZV9hYmF0ZSwgbmEucm09VFJVRSksDQogICAgaG9tZW93bmVyc19leGVtcHRpb25fc2luZ2ZhbSA9IHN1bShleGVfaG9tZW93bmVyKSwNCiAgICAjcGluX2NvdW50X3NpbmdmYW1faGFzX2hvbWVvd25lcmV4ZW1wdGlvbnMgPSBuKCksDQogICAgUENfU0ZfaGFzX0hPZXhlID0gbigpICMgaGFzIEhvbWVvd25lciBleGVtcHRpb24gYW5kIGlzIHdpdGhpbiBDbGFzcyByYW5nZSBzcGVjaWZpZWQNCiAgKSANCg0KYGBgDQoNCk92ZXIgMTAgYmlsbGlvbiBpbiBFQVYgaXMgbm90IHRheGVkIGR1ZSB0byB0aGUgZ2VuZXJhbCBob21lb3duZXJzIGV4ZW1wdGlvbi4gMi42MyBiaWxsaW9uIGlzIG5vdCB0YXhlZCBkdWUgdG8gc2VuaW9yIGV4ZW1wdGlvbnMuIDMuMiBiaWxsaW9uIGluIEVBViBpcyBub3QgdGF4ZWQgZHVlIHRvIEYNCg0KLSAxLDAyOSw3OTkgcGlucyBoYXZlIGF0IGxlYXN0IG9uZSBleGVtcHRpb24gaW4gMjAyMS4gIA0KLSAzNTAsMTI2IHBpbnMgaGF2ZSBtdWx0aXBsZSBleGVtcHRpb25zIGluIDIwMjEuICANCi0gMTUxLDY0MiBwaW5zIGhhdmUgdGhlIHNlbmlvciBleGVtcHRpb24sIHNlbmlvciBmcmVlemUgZXhlbXB0aW9uLCBvciBib3RoIG9mIHRob3NlIGV4ZW1wdGlvbnMuICAgIA0KDQoNCmBgYHtyfQ0KbXVuaXRvdGFscyA8LSBleGVtcHRpb25zICU+JQ0KICBmaWx0ZXIodGF4X2NvZGVfbnVtICVpbiUgbXVuaV90YXhfY29kZXMkdGF4X2NvZGVfbnVtKSU+JQ0KICBncm91cF9ieShjbGVhbl9uYW1lLCBhZ2VuY3lfbnVtKSAlPiUNCiAgc3VtbWFyaXplKG11bmlfYXYgPSBzdW0oYXYsIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgICBtdW5pX2Vhdl9vcmlnaW5hbD1zdW0oZWF2X29yaWdpbmFsLCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIHRvdGFsX2V4ZW1wdF9lYXYgPSBzdW0oZXhlX2hvbWVvd25lciArIGV4ZV9zZW5pb3IgKyBleGVfZnJlZXplICsgZXhlX2xvbmd0aW1lX2hvbWVvd25lciArIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4ZV9kaXNhYmxlZCArIGV4ZV92ZXRfcmV0dXJuaW5nICsgZXhlX3ZldF9kaXMgKyBleGVfYWJhdGUsIG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgaG9tZW93bmVyc19leGVtcHRpb24gPSBzdW0oZXhlX2hvbWVvd25lciksDQogICAgICAgICAgICBzZW5pb3JfZXhlbXB0aW9uID0gc3VtKGV4ZV9zZW5pb3IsIG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgZnJlZXplX2V4ZW1wdGlvbiA9IHN1bShleGVfZnJlZXplLCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIFBDX2FsbFBJTnNfbXVuaSA9IG4oKSAjIG51bWJlciBvZiBwaW5zIHdpdGhpbiBlYWNoIG11bmljaXBhbGl0eQ0KICAgICAgICAgICAgKSANCg0KIyBtdW5pdG90YWxzICU+JSBzZWxlY3QoLWFnZW5jeV9udW0pDQoNCg0KbXVuaV9yZXNpZGVudGlhbHRvdGFscyA8LSBleGVtcHRpb25zICU+JQ0KICBmaWx0ZXIodGF4X2NvZGVfbnVtICVpbiUgbXVuaV90YXhfY29kZXMkdGF4X2NvZGVfbnVtKSU+JQ0KICBmaWx0ZXIobWFqb3JfY2xhc3NfY29kZSA9PSAiMiIpICU+JSANCiAgZ3JvdXBfYnkoY2xlYW5fbmFtZSwgYWdlbmN5X251bSkgJT4lDQogIHN1bW1hcml6ZShtdW5pX3Jlc2lkZW50aWFsX2F2ID0gc3VtKGF2LCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgbXVuaV9yZXNpZGVudGlhbF9lYXZfb3JpZ2luYWw9c3VtKGVhdl9vcmlnaW5hbCwgbmEucm09VFJVRSksDQogICAgICAgICAgICB0b3RhbF9yZXNpZGVudGlhbF9leGVtcHRfZWF2ID0gc3VtKGV4ZV9ob21lb3duZXIgKyBleGVfc2VuaW9yICsgZXhlX2ZyZWV6ZSArIGV4ZV9sb25ndGltZV9ob21lb3duZXIgKyANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleGVfZGlzYWJsZWQgKyBleGVfdmV0X3JldHVybmluZyArIGV4ZV92ZXRfZGlzICsgZXhlX2FiYXRlLCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIFBDX0MyX211bmkgPSBuKCkgIyBudW1iZXIgb2YgUElOcyB0aGF0IGFyZSBDbGFzcyAyIFJlc2lkZW50aWFsIA0KICAgICAgICAgICAgKSANCg0KI211bmlfcmVzaWRlbnRpYWx0b3RhbHMgJT4lIHNlbGVjdCgtYWdlbmN5X251bSkNCg0KDQojIFNob3VsZCBJIGFkZCB0aGUgb3RoZXIgInNpbmdsZSBmYW1pbHkiIHByb3BlcnR5IGNsYXNzZXM/PyAgIyMgDQptdW5pX3NpbmdmYW1fcmVzaWRlbnRpYWx0b3RhbHMgPC0gZXhlbXB0aW9ucyAlPiUNCiAgZmlsdGVyKHRheF9jb2RlX251bSAlaW4lIG11bmlfdGF4X2NvZGVzJHRheF9jb2RlX251bSklPiUNCiAgZmlsdGVyKGNsYXNzX2NvZGUgPiAxOTkgJiBjbGFzc19jb2RlIDwgMjExKSAlPiUgDQogIGdyb3VwX2J5KGNsZWFuX25hbWUsIGFnZW5jeV9udW0pICU+JQ0KICBzdW1tYXJpemUobXVuaV9zaW5nZmFtX3Jlc2lkZW50aWFsX2F2ID0gc3VtKGF2LCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgbXVuaV9zaW5nZmFtX3Jlc2lkZW50aWFsX2Vhdl9vcmlnaW5hbD1zdW0oZWF2X29yaWdpbmFsLCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIyB0b3RhbCAic2luZ2xlLWZhbWlseSIgcmVzaWRlbnRpYWwgZXhlbXB0IGVhdg0KICAgICAgICAgICAgU0ZfcmVzX2V4ZV9FQVZfbXVuaSA9IHN1bShleGVfaG9tZW93bmVyICsgZXhlX3NlbmlvciArIGV4ZV9mcmVlemUgKyBleGVfbG9uZ3RpbWVfaG9tZW93bmVyICsgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4ZV9kaXNhYmxlZCArIGV4ZV92ZXRfcmV0dXJuaW5nICsgZXhlX3ZldF9kaXMgKyBleGVfYWJhdGUsIG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgUENfU0ZfUmVzID0gbigpIA0KICAgICAgICAgICApIA0KDQojbXVuaV9zaW5nZmFtX3Jlc2lkZW50aWFsdG90YWxzICU+JSBzZWxlY3QoLWFnZW5jeV9udW0pDQoNCm1lcmdlZCA8LSBtdW5pdG90YWxzICU+JSANCiAgc2VsZWN0KGNsZWFuX25hbWUsIGFnZW5jeV9udW0sIG11bmlfYXYsIG11bmlfZWF2X29yaWdpbmFsLCBQQ19hbGxQSU5zX211bmkpICU+JSANCiAgbGVmdF9qb2luKG11bmlfZXhlbXB0X2VhdikgJT4lIA0KICBsZWZ0X2pvaW4obXVuaV9yZXNpZGVudGlhbHRvdGFscykgJT4lDQogIGxlZnRfam9pbihtdW5pX3NpbmdmYW1fcmVzaWRlbnRpYWx0b3RhbHMpICU+JQ0KICBsZWZ0X2pvaW4obXVuaV9DMl9oYXNfZXhlX2VhdikgJT4lDQogIGxlZnRfam9pbihtdW5pX3NpbmdmYW1yZXNfaGFzX2hvbWVvd25lcnNfZXhlbXBzKSAlPiUNCiAgbXV0YXRlKHBjdF9vZlNGX3BpbnNfd19IT2V4ZSA9IFBDX1NGX2hhc19IT2V4ZSAvIFBDX1NGX1JlcywNCiAgICAgICAgIyBwY3RfU0ZfcGluc193X2V4ZW1wcyA9IHBpbl9jb3VudF9oYXNfaG9tZW93bmVyZXhlbXB0aW9ucyAvIHBpbl9jb3VudF9zaW5nZmFtX3Jlc2lkZW50aWFsLA0KICAgICAgICAjIHBjdF9waW5zX3dfZXhlbXBzID0gcGluX2NvdW50X2hhc2V4ZW1wdGlvbnMgLyBwaW5fY291bnQsDQogICAgICAgIHBjdF9vZmFsbHBpbnNfd19leGUgPSBQQ19oYXNfZXhlIC8gUENfYWxsUElOc19tdW5pLCAjICAgICAgIHBpbnMgd2l0aCBleGVtcHRpb25zIC8gYWxsIHBpbnMgaW4gYSBtdW5pDQoNCiAgICAgICAgIHBjdF9DMl93X2V4ZW1wcyA9IFBDX0MyX2hhc19leGUgLyBQQ19DMl9tdW5pLCAjIA0KICAgICAgICAgI3BjdF9zaW5nZmFtX3BpbnNfd19leGVtcHMgPSBwaW5fY291bnRfaGFzZXhlbXB0aW9ucyAvIHBpbl9jb3VudF9zaW5nZmFtX3Jlc2lkZW50aWFsLA0KICAgICAgIyAgIHBjdF9zaW5nZmFtX3BpbnNfd19leGVtcHMgPSBwaW5fY291bnRfaGFzX2hvbWVvd25lcmV4ZW1wdGlvbnMgLyBwaW5fY291bnRfc2luZ2ZhbV9yZXNpZGVudGlhbA0KICAgICkgJT4lDQogIA0KICBzZWxlY3QoY2xlYW5fbmFtZSwgcGN0X29mU0ZfcGluc193X0hPZXhlLCBwY3Rfb2ZhbGxwaW5zX3dfZXhlLCBwY3RfQzJfd19leGVtcHMsIA0KICAgICAgICAgUENfaGFzX2V4ZSwgUENfQzJfbXVuaSwgUENfYWxsUElOc19tdW5pLCBldmVyeXRoaW5nKCkpDQoNCm1lcmdlZA0KYGBgDQoNCj4gQnJpbmcgaW4gdGF4IGJpbGxzIHRvIGNhbGN1bGF0ZSB0aGUgbXVuaSBsZXZ5IGZvciBlYWNoIG11bmljaXBhbGl0eSBmcm9tIGZpbmFsX3RheF90b19kaXN0IHZhcmlhYmxlLg0KDQpgYGB7cn0NClRDX2JpbGxzX2N1cnJlbnQgPC0gcmVhZF9jc3YoIjJfU3VtbWVkX0JpbGxzX2J5X1RheGNvZGVfYW5kX0NsYXNzLmNzdiIpICU+JSANCiAgbXV0YXRlKHRheF9jb2RlID0gYXMuY2hhcmFjdGVyKHRheF9jb2RlKSwNCiAgICAgICAgIGNsYXNzID0gYXMuY2hhcmFjdGVyKGNsYXNzKSkNCg0KY2xhc3NfZGljdCRjbGFzc19jb2RlIDwtIGFzLmNoYXJhY3RlcihjbGFzc19kaWN0JGNsYXNzX2NvZGUpDQogDQoNCnRheGNvZGVzX2N1cnJlbnQgPC0gbGVmdF9qb2luKFRDX2JpbGxzX2N1cnJlbnQsIG11bmlfdGF4X2NvZGVzLCANCiAgICAgICAgICAgICAgICAgICAgICBieSA9IGMoInRheF9jb2RlIiA9ICJ0YXhfY29kZV9udW0iKSkgDQoNCk11bmlMZXZ5IDwtIHRheGNvZGVzX2N1cnJlbnQgJT4lIA0KICBsZWZ0X2pvaW4obXVuaV9hZ2VuY3lfbmFtZXMsIGJ5ID0gImFnZW5jeV9udW0iKSAlPiUNCiAgbGVmdF9qb2luKG5pY2tuYW1lcywgYnkgPSBjKCJhZ2VuY3lfbmFtZSIgPSAiYWdlbmN5X25hbWUiKSkgJT4lDQogICNmaWx0ZXIoIWFnZW5jeV9udW0gJWluJSBjcm9zc19jb3VudHlfbGluZXMpICU+JQ0KICBncm91cF9ieShjbGVhbl9uYW1lKSAlPiUNCiAgDQogIHN1bW1hcml6ZShNdW5pTGV2eSA9IHN1bShmaW5hbF90YXhfdG9fZGlzdCwgbmEucm0gPSBUUlVFKSwgIyBhbW91bnQgYmlsbGVkIGJ5IG11bmlzIHdpdGggY3VycmVudCBleGVtcHRpb25zIGluIHBsYWNlDQogICAgICAgICAgICBub25USUZfRUFWX3Bvc3RfZXhlbXBzID0gc3VtKGZpbmFsX3RheF90b19kaXN0Lyh0YXhfY29kZV9yYXRlLzEwMCksIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgICBUSUZfaW5jcmVtZW50X0VBViA9IHN1bShmaW5hbF90YXhfdG9fdGlmLyh0YXhfY29kZV9yYXRlLzEwMCksIG5hLnJtPVRSVUUpLCAgDQogICAgICAgICAgICBFeGVtcHRfRUFWID0gc3VtKHRheF9hbXRfZXhlLyh0YXhfY29kZV9yYXRlLzEwMCksIG5hLnJtPVRSVUUpLCANCiAgICAgICAgICAgIFRvdGFsX0VBViA9IHN1bSgodGF4X2FtdF9leGUrZmluYWxfdGF4X3RvX2Rpc3QrZmluYWxfdGF4X3RvX3RpZikvKHRheF9jb2RlX3JhdGUvMTAwKSwgbmEucm0gPSBUUlVFKSkNCg0KDQptZXJnZWQgPC0gbWVyZ2VkICU+JSBsZWZ0X2pvaW4oTXVuaUxldnkpDQpgYGANCg0KDQoNCmBgYHtyfQ0Kc2NlbmFyaW9fdGF4cmF0ZXMgPC0gbWVyZ2VkICU+JSANCiAgbXV0YXRlKHNjZW5hcmlvMV90YXhhYmxlX2VhdiA9IFRvdGFsX0VBViAtIFRJRl9pbmNyZW1lbnRfRUFWIC0gRXhlbXB0X0VBViArIGhvbWVvd25lcnNfZXhlbXB0aW9uLA0KICAgICAgICAgc2NlbmFyaW8yX3RheGFibGVfZWF2ID0gVG90YWxfRUFWIC0gVElGX2luY3JlbWVudF9FQVYgLSBFeGVtcHRfRUFWICsgKHNlbmlvcl9leGVtcHRpb24gKyBmcmVlemVfZXhlbXB0aW9uICksDQogICAgICAgICAgICAgICAgICBzY2VuYXJpb19ub2V4ZW1wdGlvbnNfdGF4YWJsZV9lYXYgPSBUb3RhbF9FQVYgLSBFeGVtcHRfRUFWKSAlPiUNCiAgbXV0YXRlKHRheHJhdGVfc2NlbjEgPSBNdW5pTGV2eSAvIHNjZW5hcmlvMV90YXhhYmxlX2VhdiwNCiAgICAgICAgIHRheHJhdGVfc2NlbjIgPSBNdW5pTGV2eSAvIHNjZW5hcmlvMl90YXhhYmxlX2VhdiwNCiAgICAgICAgIHRheF9yYXRlX2N1cnJlbnQgPSBNdW5pTGV2eS9ub25USUZfRUFWX3Bvc3RfZXhlbXBzLA0KICAgICAgICAgdGF4cmF0ZV9ub2V4ZW1wcyA9IE11bmlMZXZ5IC8oVG90YWxfRUFWIC0gVElGX2luY3JlbWVudF9FQVYgICksDQogICAgICAgICB0YXhyYXRlX25vVElGcyA9IE11bmlMZXZ5IC8gKFRvdGFsX0VBViAtIEV4ZW1wdF9FQVYpLA0KICAgICAgICAgdGF4cmF0ZV9ub1RJRnNfb3JFeGVtcHMgPSBNdW5pTGV2eSAvIFRvdGFsX0VBVikgICU+JQ0KICBzZWxlY3QoY2xlYW5fbmFtZSwgTXVuaUxldnksIHRheHJhdGVfc2NlbjEsIHRheHJhdGVfc2NlbjIsIHRheF9yYXRlX2N1cnJlbnQsIHRheHJhdGVfbm9leGVtcHMsIHRheHJhdGVfbm9USUZzLCB0YXhyYXRlX25vVElGc19vckV4ZW1wcywgc2NlbmFyaW8xX3RheGFibGVfZWF2LCBzY2VuYXJpbzJfdGF4YWJsZV9lYXYpDQoNCnNjZW5hcmlvX3RheHJhdGVzDQoNCg0KbWVyZ2VkICU+JSANCiAgZmlsdGVyKGNsZWFuX25hbWUgJWluJSBjKCJQYXJrIEZvcmVzdCIsIk1hcmtoYW0iLCAgIkRvbHRvbiIsICJIaWxsc2lkZSIsICJSaXZlcnNpZGUiLCAiQ2hpY2FnbyIsICJXZXN0Y2hlc3RlciIsICJXaW5uZXRrYSIsICJSb3NlbW9udCIpKSAlPiUNCiAgbXV0YXRlKHNjZW5hcmlvMV90YXhhYmxlX2VhdiA9IFRvdGFsX0VBViAtIFRJRl9pbmNyZW1lbnRfRUFWIC0gRXhlbXB0X0VBViArIGhvbWVvd25lcnNfZXhlbXB0aW9uLA0KICAgICAgICAgc2NlbmFyaW8yX3RheGFibGVfZWF2ID0gVG90YWxfRUFWIC0gVElGX2luY3JlbWVudF9FQVYgLSBFeGVtcHRfRUFWICsgKHNlbmlvcl9leGVtcHRpb24gKyBmcmVlemVfZXhlbXB0aW9uICksDQogICAgICAgICBzY2VuYXJpb19ub2V4ZW1wdGlvbnNfdGF4YWJsZV9lYXYgPSBUb3RhbF9FQVYgLSBFeGVtcHRfRUFWKSAlPiUNCiAgbXV0YXRlKHRheHJhdGVfc2NlbjEgPSBNdW5pTGV2eSAvIHNjZW5hcmlvMV90YXhhYmxlX2VhdiwNCiAgICAgICAgIHRheHJhdGVfc2NlbjIgPSBNdW5pTGV2eSAvIHNjZW5hcmlvMl90YXhhYmxlX2VhdiwNCiAgICAgICAgIHRheF9yYXRlX2N1cnJlbnQgPSBNdW5pTGV2eS9ub25USUZfRUFWX3Bvc3RfZXhlbXBzLA0KICAgICAgICAgdGF4cmF0ZV9ub2V4ZW1wcyA9IE11bmlMZXZ5IC8oVG90YWxfRUFWIC0gVElGX2luY3JlbWVudF9FQVYgICksDQogICAgICAgICB0YXhyYXRlX25vVElGcyA9IE11bmlMZXZ5IC8gKFRvdGFsX0VBViAtIEV4ZW1wdF9FQVYpLA0KICAgICAgICAgdGF4cmF0ZV9ub1RJRnNfb3JFeGVtcHMgPSBNdW5pTGV2eSAvIFRvdGFsX0VBVikgICU+JQ0KICBzZWxlY3QoY2xlYW5fbmFtZSwgTXVuaUxldnksIHRheHJhdGVfc2NlbjEsIHRheHJhdGVfc2NlbjIsIHRheF9yYXRlX2N1cnJlbnQsIHRheHJhdGVfbm9leGVtcHMsIHNjZW5hcmlvMV90YXhhYmxlX2Vhdiwgc2NlbmFyaW8yX3RheGFibGVfZWF2LCBzY2VuYXJpb19ub2V4ZW1wdGlvbnNfdGF4YWJsZV9lYXYsIFRvdGFsX0VBViwgdGF4cmF0ZV9ub1RJRnMsIHRheHJhdGVfbm9USUZzX29yRXhlbXBzKQ0KDQpgYGANCg0KPiBTY2VuYXJpbyAxIGlzIHJlbW92aW5nIGhvbWVvd25lcnMgZXhlbXB0aW9ucy4gU2NlbmFyaW8gMiBpcyByZW1vdmluZyB0aGUgdHdvIHNlbmlvciBleGVtcHRpb25zLiANCg0KDQoNCg0KIyMjIEJ1cmRlbiBTaGFyZSBmb3IgU2NlbmFyaW9zDQoNCg0KQ2FsY3VsYXRlIENsYXNzIDIgQnVyZGVuIC0tPiBDYWxjdWxhdGUgdGhlIGFtb3VudCBvZiB0YXhhYmxlIEVBViBpbiB0aGUgTXVuaWNpcGFsaXR5IChmb3IgZWFjaCBzY2VuYXJpbykgYW5kIG11bHRpcGx5IGl0IGJ5IHRoZSBuZXcgY29tcG9zaXRlIHRheCByYXRlIChmb3IgZWFjaCBzY2VuYXJpbykuDQoNCg0KQnVyZGVuIFNoYXJlICA9IFRheGFibGUgRUFWIHdpdGhpbiBQcm9wZXJ0eSBDbGFzcyAqIENvbXBvc2l0ZSB0YXggcmF0ZSANCg0KQ29tcG9zaXRlIFRheCBSYXRlID0gKE11bmljaXBhbCBMZXZ5IC8gVGF4YWJsZSBFQVYgKQ0KDQoNCg0KYGBge3J9DQpDbGFzczJfRUFWX3NjZW5hcmlvcyA8LSBleGVtcHRpb25zICU+JSANCiAgZmlsdGVyKGNsYXNzX2NvZGUgPj0gMjAwICYgY2xhc3NfY29kZSA8PSAzMDApICU+JSANCiAgZmlsdGVyKHRheF9jb2RlX251bSAlaW4lIG11bmlfdGF4X2NvZGVzJHRheF9jb2RlX251bSklPiUNCiAgZ3JvdXBfYnkoY2xlYW5fbmFtZSkgJT4lDQogIHN1bW1hcml6ZShDbGFzczJfYXYgPSBzdW0oYXYsIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgICBDbGFzczJfZWF2X29yaWdpbmFsPXN1bShlYXZfb3JpZ2luYWwsIG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgQ2xhc3MyX3RvdGFsX2V4ZW1wdF9lYXYgPSBzdW0oZXhlX2hvbWVvd25lciArIGV4ZV9zZW5pb3IgKyBleGVfZnJlZXplICsgZXhlX2xvbmd0aW1lX2hvbWVvd25lciArIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4ZV9kaXNhYmxlZCArIGV4ZV92ZXRfcmV0dXJuaW5nICsgZXhlX3ZldF9kaXMgKyBleGVfYWJhdGUsIG5hLnJtPVRSVUUpLA0KICAgICAgICAgICAgQ2xhc3MyX2hvbWVvd25lcnNfZXhlbXB0aW9uID0gc3VtKGV4ZV9ob21lb3duZXIpLA0KICAgICAgICAgICAgQ2xhc3MyX3Nlbmlvcl9leGVtcHRpb24gPSBzdW0oZXhlX3NlbmlvciwgbmEucm09VFJVRSksDQogICAgICAgICAgICBDbGFzczJfZnJlZXplX2V4ZW1wdGlvbiA9IHN1bShleGVfZnJlZXplLCBuYS5ybT1UUlVFKSwNCiAgICAgICAgICAgIENsYXNzMl9QQ19wZXJtdW5pID0gbigpICMgbnVtYmVyIG9mIHBpbnMgd2l0aGluIGVhY2ggbXVuaWNpcGFsaXR5DQogICAgICAgICAgICApIA0KQ2xhc3MyX0VBVl9zY2VuYXJpb3MNCg0KDQpDbGFzczJfVElGX0VBViA8LSAgdGF4Y29kZXNfY3VycmVudCAlPiUgDQogIGZpbHRlcihjbGFzcyA+PTIwMCAmIGNsYXNzIDw9MzAwKSAlPiUNCiAgbGVmdF9qb2luKG11bmlfYWdlbmN5X25hbWVzLCBieSA9ICJhZ2VuY3lfbnVtIikgJT4lDQogIGxlZnRfam9pbihuaWNrbmFtZXMsIGJ5ID0gYygiYWdlbmN5X25hbWUiID0gImFnZW5jeV9uYW1lIikpICU+JQ0KICBmaWx0ZXIoIWFnZW5jeV9udW0gJWluJSBjcm9zc19jb3VudHlfbGluZXMpICU+JQ0KICBncm91cF9ieShjbGVhbl9uYW1lKSAlPiUNCiAgc3VtbWFyaXplKENsYXNzMl9EaXN0cmljdFJldiA9IHN1bShmaW5hbF90YXhfdG9fZGlzdCwgbmEucm0gPSBUUlVFKSwgIyBhbW91bnQgYmlsbGVkIGJ5IG11bmlzIHdpdGggY3VycmVudCBleGVtcHRpb25zIGluIHBsYWNlDQogICAgICAgICAgICBDbGFzczJfbm9uVElGX0VBVl9wb3N0X2V4ZW1wcyA9IHN1bShmaW5hbF90YXhfdG9fZGlzdC8odGF4X2NvZGVfcmF0ZS8xMDApLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgQ2xhc3MyX1RJRl9pbmNyZW1lbnRfRUFWID0gc3VtKGZpbmFsX3RheF90b190aWYvKHRheF9jb2RlX3JhdGUvMTAwKSwgbmEucm09VFJVRSksICANCiAgICAgICAgICAgIENsYXNzMl9FeGVtcHRfRUFWID0gc3VtKHRheF9hbXRfZXhlLyh0YXhfY29kZV9yYXRlLzEwMCksIG5hLnJtPVRSVUUpLCANCiAgICAgICAgICAgIENsYXNzMl9Ub3RhbF9FQVYgPSBzdW0oKHRheF9hbXRfZXhlK2ZpbmFsX3RheF90b19kaXN0K2ZpbmFsX3RheF90b190aWYpLyh0YXhfY29kZV9yYXRlLzEwMCksIG5hLnJtID0gVFJVRSkpDQoNCkNsYXNzMl9USUZfRUFWDQoNCg0KQ2xhc3MyX21lcmdlZCA8LSBDbGFzczJfVElGX0VBViAlPiUgDQogIGxlZnRfam9pbihDbGFzczJfRUFWX3NjZW5hcmlvcykgJT4lDQogIGxlZnRfam9pbihNdW5pTGV2eSkNCg0KDQpDbGFzczJfU2NlbmFyaW9fYnVyZGVuc2hpZnQgPC0gQ2xhc3MyX21lcmdlZCAlPiUgDQogIGxlZnRfam9pbihzY2VuYXJpb190YXhyYXRlcykgJT4lDQogIG11dGF0ZShDbGFzczJfc2NlbmFyaW8xX3RheGFibGVfZWF2ID0gQ2xhc3MyX1RvdGFsX0VBViAtIENsYXNzMl9USUZfaW5jcmVtZW50X0VBViAtIEV4ZW1wdF9FQVYgKyAgQ2xhc3MyX2hvbWVvd25lcnNfZXhlbXB0aW9uLA0KICAgICAgICBDbGFzczJfc2NlbmFyaW8yX3RheGFibGVfZWF2ID0gQ2xhc3MyX1RvdGFsX0VBViAtIENsYXNzMl9USUZfaW5jcmVtZW50X0VBViAtIEV4ZW1wdF9FQVYgKyAgKENsYXNzMl9zZW5pb3JfZXhlbXB0aW9uICsgQ2xhc3MyX2ZyZWV6ZV9leGVtcHRpb24gKSkgJT4lDQogIA0KICBtdXRhdGUoYnVyZGVuX0MyX3NjZW4xID0gKENsYXNzMl9zY2VuYXJpbzFfdGF4YWJsZV9lYXYgKiB0YXhyYXRlX3NjZW4xKS8gTXVuaUxldnksDQogICAgICAgICBidXJkZW5fQzJfc2NlbjIgPSAoQ2xhc3MyX3NjZW5hcmlvMl90YXhhYmxlX2VhdiAqIHRheHJhdGVfc2NlbjIpIC8gTXVuaUxldnksDQogICAgICAgICBidXJkZW5fQzJfY3VycmVudCA9IENsYXNzMl9ub25USUZfRUFWX3Bvc3RfZXhlbXBzICogdGF4X3JhdGVfY3VycmVudC8gTXVuaUxldnksDQogICAgICAgICBidXJkZW5fQzJfbm9leGVtcHMgPSAoIChDbGFzczJfVG90YWxfRUFWIC0gQ2xhc3MyX1RJRl9pbmNyZW1lbnRfRUFWKSp0YXhyYXRlX25vZXhlbXBzICkgLyBNdW5pTGV2eSwNCiAgICAgICAgIGJ1cmRlbl9DMl9ub1RJRl9vckV4ZW1wcyA9IChDbGFzczJfVG90YWxfRUFWICogdGF4cmF0ZV9ub1RJRnNfb3JFeGVtcHMgKSAvIE11bmlMZXZ5LA0KICAgICAgICAgYnVyZGVuX0MyX25vVElGcyA9ICAoKENsYXNzMl9Ub3RhbF9FQVYgLSBDbGFzczJfRXhlbXB0X0VBVikgKiB0YXhyYXRlX25vVElGcyApIC8gTXVuaUxldnkpICMgICU+JQ0KICMgc2VsZWN0KGNsZWFuX25hbWUsIE11bmlMZXZ5LCB0YXhyYXRlX3NjZW4xLCB0YXhyYXRlX3NjZW4yLCB0YXhfcmF0ZV9jdXJyZW50LCB0YXhyYXRlX25vZXhlbXBzLCBzY2VuYXJpbzFfdGF4YWJsZV9lYXYsIHNjZW5hcmlvMl90YXhhYmxlX2VhdikNCg0KQ2xhc3MyX1NjZW5hcmlvX2J1cmRlbnNoaWZ0ICU+JSANCiAgc2VsZWN0KGNsZWFuX25hbWUsIGJ1cmRlbl9DMl9zY2VuMTpidXJkZW5fQzJfbm9USUZzKSAgJT4lIA0KICBmaWx0ZXIoY2xlYW5fbmFtZSAlaW4lIGMoIlBhcmsgRm9yZXN0IiwiTWFya2hhbSIsICAiRG9sdG9uIiwgIkhpbGxzaWRlIiwgIlJpdmVyc2lkZSIsICJDaGljYWdvIiwgIldlc3RjaGVzdGVyIiwgIldpbm5ldGthIiwgIlJvc2Vtb250IikpDQpgYGANCg0KDQoNCg0KDQojIEFwcGVuZGl4OiBBbGwgY29kZSBmb3IgdGhpcyByZXBvcnQuDQoNCiMjIEV4cG9ydGluZyBkYXRhIGludG8gRXhjZWwgDQoNCmBgYHtyfQ0KbGlicmFyeShvcGVueGxzeCkNCg0KZGF0YXNldF9uYW1lcyA8LSBsaXN0KCdDb29rIENvdW50eSBUb3RhbHMnID0gdG90YWxfZXhlbXB0aW9ucywNCiAgICAgICAgICAgICAgICAgICAgICAnSW5jb3JwIEV4ZW1wIFRvdGFscycgPSBtdW5pX3RvdGFscywNCiAgICAgICAgICAgICAgICAgICAgICAnTXVuaSBMZXZlbCBFeGVtcCBUb3QnID0gZXhlbXB0eXBlX3RvdGFsc19wZXJtdW5pLA0KICAgICAgICAgICAgICAgICAgICAgICdFQVYgaW4gYW5kIG91dCBvZiBUSUYnID0gdGlmX3RhYmxlLA0KICAgICAgICAgICAgICAgICAgICAgICdQZXJjZW50IFJlc2lkZW50aWFsJyA9IHBlcmNfcmVzaWRlbnRpYWwsDQogICAgICAgICAgICAgICAgICAgICAgJ1RheCBCYXNlIGJ5IENsYXNzJyA9IGdyb3VwZWRfZXhlbXB0aW9ucywNCiAgICAgICAgICAgICAgICAgICAgICAnQ3VycmVudGFuZEh5cCBUYXggQnVyZGVuJz0gbXVuaXNfM3Byb3BlcnR5X3R5cGVzLA0KICAgICAgICAgICAgICAgICAgICAgICdCdXJkZW4gU2hpZnQsIDMgUHJvcENsYXNzZXMnID0gcHJvcHNfd2lkZSwNCiAgICAgICAgICAgICAgICAgICAgICAnRnVsbCBCdXJkZW4gU2hpZnQgVGFibGUnPSBidXJkZW5fc2hpZnQsICMgaGFzIGVzc2VudGlhbGx5IGFsbCB2YXJpYWJsZXMgdXNlZCB0byBtYWtlIHRoZSBzbWFsbGVyLCBtb3JlIHNwZWNpZmljIHRhYmxlcw0KICAgICAgICAgICAgICAgICAgICAgICdFeGVtcHMgYnkgQ2xhc3MsIEFsbCBUYXggQ29kZXMnID0gZXhlbXB0aW9uc19ieV9jbGFzc19wZXJfVEMsDQogICAgICAgICAgICAgICAgICAgICAgJ0V4ZW1wdCBSZXNpZGVudGlhbCBFQVYnID0gZXhlbXB0aW9uc190b19jbGFzczJFQVZfcmF0aW9zLA0KICAgICAgICAgICAgICAgICAgICAgICdUYXggQ29kZSBUYXggUmF0ZXMnPSB0YXhjb2Rlc19jdXJyZW50LA0KICAgICAgICAgICAgICAgICAgIyAgICAnVGF4IEJpbGwgQ2hhbmdlLCBBbGwgUHJvcENsYXNzJyA9IHRheF9iaWxsX2NoYW5nZSwgIyB1c2VzIHRoZSBhY3R1YWwgbWVkaWFuIHZhbHVlIGZvciB0aGUgc3RhdGlzdGljLiBOb3QgbXkgZmF2b3JpdGUgd2F5IHRvIGNhbGN1bGF0ZSB0aGlzIHN0YXRpc3RpYw0KICAgICAgICAgICAgICAgICAgICAjICAnVGF4IEJpbGwgQ2hhbmdlLCAzIE1ham9yQ2xhc3NlcycgPSBiaWxsX2NoYW5nZV8zZ3JvdXBzLCAjIHVzZXMgdGhlIGFjdHVhbCBtZWRpYW4gdmFsdWUgZm9yIHRoZSBzdGF0aXN0aWMuIE5vdCBteSBmYXZvcml0ZSB3YXkgdG8gY2FsY3VsYXRlIHRoaXMgc3RhdGlzdGljDQoNCiAgICAgICAgICAgICAgICAgICAgICAnTXVuaSBUYXhDb2RlWENsYXNzIEJpbGwgU3VtcycgPSBUQ19iaWxsc19jdXJyZW50LCAjIHVzZXMgdGhlIGFjdHVhbCBtZWRpYW4gdmFsdWUgZm9yIHRoZSBzdGF0aXN0aWMuIE5vdCBteSBmYXZvcml0ZSB3YXkgdG8gY2FsY3VsYXRlIHRoaXMgc3RhdGlzdGljDQogICAgICAgICAgICAgICAgICAgICAgJ0NvbXBvc2l0ZSB0YXggcmF0ZXMnID0gQ3VycmVudF9UYXhyYXRlcw0KKQ0KDQp3cml0ZS54bHN4KGRhdGFzZXRfbmFtZXMsIGZpbGUgPSAnVUlDX0NNQVBfZXhlbXB0aW9uV2hpdGVwYXBlci54bHN4JykNCmBgYA0KDQoNCg0KYGBge3IgcmVmLmxhYmVsPWtuaXRyOjphbGxfbGFiZWxzKCksIGVjaG89VFJVRSwgZXZhbD1GQUxTRX0NCg0KYGBgDQo=