Debois Project

A Lot of this is an absolute mess. Not many Comments. Just figured I should post it anyways.

1 Database load and setup

Used a local postgressql database to fit full data in memory. This code is mostly just importing it into the database, loading it, etc.

# Load Database
conn <- 
    dbConnect(
        drv = Postgres(),
        user = 'lizsql', 
        password = 'lizsql', 
        host = "localhost",
        port = "5432",
        dbname = "postgres"
    )
debois_1900 <- tbl(conn, in_schema('public', 'debois_1900'))
acs_2019_5yr <- tbl(conn, in_schema('public', 'acs_2019_5yr_v2'))
# Reads into Postgres. Replace variable and table names for each dataset. 
# Had to use postgres as full 1900 census would not fit in memory. 
cps_ddi_file <- "usa_00009.xml"
cps_data_file <- "usa_00009.dat"
# Add data to tables in chunks
ddi <- read_ipums_ddi(cps_ddi_file)
read_ipums_micro_chunked(
  ddi,
  data_file = cps_data_file,
  readr::SideEffectChunkCallback$new(function(x, pos) {
    if (pos == 1) {
      dbWriteTable(conn, "acs_2019_5yr_v2", x)
    } else {
      dbWriteTable(conn, "acs_2019_5yr_v2", x, row.names = FALSE, append = TRUE)
    }
  }),
  chunk_size = 30000,
  verbose = FALSE
)
s
f <- debois_1900 |> 
    filter(STATEFIP == 13, RACE == 2) |> 
    count(BPL) |> 
    ipums_collect(ddi)

f2 <- debois_1900 |> 
    filter(BPL == 13, RACE == 2) |> 
    count(STATEFIP) |> 
    ipums_collect(ddi)

2 Migration Chart

This is very messy. But basically involved filtering out various parts of the dataset and then creating the different figures.

migration_to_georgia <- f |> mutate(region = labelled::to_factor(BPL), FIPS = labelled::remove_labels(BPL)) |> select(region, FIPS, n)
saveRDS(migration_to_georgia, file = "migration_to_georgia")
migration_from_georgia <- f2 |> mutate(region = labelled::to_factor(STATEFIP), FIPS = labelled::remove_labels(STATEFIP)) |> 
    select(region, FIPS, n)
#saveRDS(migration_from_georgia, file = 'migration_from_georgia')
fixed_numbers <-
    migration_from_georgia %>% filter(FIPS < 60) %>% mutate(region = tolower(region)) %>% filter(region != 'district of columbia', FIPS != 13) %>% mutate(n = as.numeric(n)) %>% select(region, n)
states_map <- map_data('state')
total_map <- left_join(states_map, fixed_numbers, by = 'region')
state_name <-
    data.frame(
        abb = state.abb,
        region = tolower(state.name),
        x = state.center$x,
        y = state.center$y
    ) |> filter(abb != 'HI', abb != 'AK') |>
    left_join(fixed_numbers) #,
                                           #           TRUE ~ n)) 
from_ga <- ggplot(total_map, aes(long, lat, group = group)) +
    #    annotation_map_tile("stamenwatercolor") +
    geom_polygon(aes(fill = n), color = "white") +
    scale_fill_viridis_c(option = "C",
                         trans = 'log',
                         direction = -1) + geom_shadowtext(data = state_name,
                                                           aes(
                                                               x = x,
                                                               y = y,
                                                               label = ifelse(abb == 'GA', "GA\n ", paste0(abb,'\n', ifelse(is.na(n), 0, n))),
                                                               group = 1
                                                           ),
                                                           size = 2) +
    #  annotation_scale() +
 #   theme_void() +
    theme(axis.line=element_blank(),axis.text.x=element_blank(),
          axis.text.y=element_blank(),axis.ticks=element_blank(),
          axis.title.x=element_blank(), legend.position = 'none',
          axis.title.y=element_blank(),
          panel.background=element_blank(),panel.border=element_blank(),panel.grid.major=element_blank(),
          panel.grid.minor=element_blank(),plot.background=element_blank()) +
     labs(
        color = 'Population',
        title = 'Populated Migrated from Georgia',
        subtitle = 'Population born in Georgia by current state of residence (if living outside Georgia)'
    ) 
   # theme(plot.title = element_text(hjust = 0.5))
#theme(legend.position="none")
from_ga
ggsave(
    'from_ga.png',
    from_ga,
    width = 2560,
    height = 1440,
    units = c('px')
)


fixed_numbers <-
    migration_to_georgia %>% filter(FIPS < 60) %>% mutate(region = tolower(region)) %>% filter(region != 'district of columbia', FIPS != 13) %>% mutate(n = as.numeric(n)) %>% select(region, n)
states_map <- map_data('state')
total_map <- left_join(states_map, fixed_numbers, by = 'region')
state_name <-
    data.frame(
        abb = state.abb,
        region = tolower(state.name),
        x = state.center$x,
        y = state.center$y
    ) |> filter(abb != 'HI', abb != 'AK') |>
    left_join(fixed_numbers)# %>% mutate(n = case_when(abb == 'GA' ~ 958984,
                             #                         TRUE ~ n))
to_ga <- ggplot(total_map, aes(long, lat, group = group)) +
    #    annotation_map_tile("stamenwatercolor") +
    geom_polygon(aes(fill = n), color = "white") +
    scale_fill_viridis_c(option = "C",
                         trans = 'log',
                         direction = -1) + geom_shadowtext(data = state_name,
                                                           aes(
                                                               x = x,
                                                               y = y,
                                                               label =  ifelse(abb == 'GA', "GA\n ", paste0(abb,'\n', ifelse(is.na(n), 0, n))),
                                                               group = 1
                                                           ),
                                                           size = 2) +
    #  annotation_scale() +
   # theme_void() +
    #theme(plot.title = element_text(hjust = 0.5)) + 
    labs(
        color = 'Population',
        title = 'Population Migrated to Georgia', 
        subtitle = 'Number of current Georgia residents by place of birth (if born outside georgia)'
    ) +
      theme(axis.line=element_blank(),axis.text.x=element_blank(),
          axis.text.y=element_blank(),axis.ticks=element_blank(),
          axis.title.x=element_blank(),
          axis.title.y=element_blank(), legend.position = 'none',
          panel.background=element_blank(),panel.border=element_blank(),panel.grid.major=element_blank(),
          panel.grid.minor=element_blank(),plot.background=element_blank())
        #  plot.margin = margin())
#theme(legend.position="none")
to_ga
ggsave(
    'to_ga.png',
    to_ga,
    width = 2560,
    height = 1440,
    units = c('px')
)

patchwork = to_ga / from_ga
patchwork <- patchwork + 
    plot_annotation(
    theme = theme(legend.position = 'none',
                  plot.title = element_text(size = 20),
                  plot.margin = margin(t = 25, b = 25, l = 25, r = 25)),
    title = 'Migration of African Americans to and from Georgia, 1900',
    subtitle = 'Residents of Georgia born in another state, and residents of other states born in Georgia\n ',
    caption = 'Created by Elizabeth Goodwin using the full 1900 Census, IPUMS USA'
    # subtitle = 'These 3 plots will reveal yet-untold secrets about our beloved data-set',
    #   caption = 'Disclaimer: None of these plots are insightful',
  #  tag_levels = c('A', '1'),
  #  tag_prefix = 'Fig. ',
 #   tag_sep = '.',
  #  tag_suffix = ':'
)  
patchwork

filename = 'lot-11931-no-08-GOODWIN.pdf'
filenamepng = 'lot-11931-no-08-GOODWIN.png'
ggsave(filename, 
       plot = patchwork,
       dpi = 300,
       height = 11,
       width = 8.5
       )

3 Marital Status Figure

density <- acs_2019_5yr |> 
    filter(RACE == 1) |> 
    mutate(
        age_bucket = case_when(
            
            AGE < 16 ~ "0-15",
            AGE < 21 ~ "15-20",
            AGE < 26 ~ "20-25",
            AGE < 31 ~ "25-30",
            AGE < 36 ~ "30-35",
            AGE < 46 ~ "35-45",
            AGE < 56 ~ "45-55",
            AGE < 66 ~ "55-65",
            AGE < 76 ~ "65-75",
            AGE < 89 ~ "Over 75",
            TRUE ~ 'other'
        ), 
        Marital_Status = case_when(
            MARST < 3 ~ 'Married', 
            MARST < 5 ~ 'Separated/\nDivorced', 
            MARST == 5 ~ "Widowed", 
            MARST == 6 ~ "Single"
        )
    ) |> 
    count(SEX, age_bucket, Marital_Status) |> 
    ipums_collect(ddi) |> 
    filter(age_bucket != 'other') |> 
    add_count(SEX, age_bucket, wt = n, name = 'total') |> 
    mutate(pct = 100*n / total) |> 
    mutate(SEX = case_when(SEX == 1 ~ 'Male', TRUE ~ "Female")) |> 
    mutate(Marital_Status = factor(Marital_Status, levels = rev(c('Single', 'Married', "Separated/\nDivorced", 'Widowed'))))
to_swap = rev(c("#9A8A76", "#db735c", "#EFA86E","#555555" ))
male <-
    ggplot((density |> filter(SEX == 'Male')),
           aes(x = age_bucket, y = as.numeric(pct), fill = Marital_Status)) +
    geom_bar(stat = "identity", width = 1, color = 'black', size = .3) + 
    coord_flip() + 
    
    labs(subtitle = 'Male', 
         y = element_blank(), 
  fill = "Status",
         x = "Age (Years)") + 
  #  hrbrthemes::theme_ipsum_ps() + 
    theme(legend.position = 'bottom'
  #      plot.subtitle = element_text(hjust = 0.5)
          ) + 
    geom_shadowtext(aes(label = ifelse(round(pct) > 3, paste0(round(pct), "%"), "")), size = 2.8,position = position_stack(vjust = .5)) + 
    scale_y_reverse(limits=c(101,0), labels = scales::percent_format(scale = 1), expand = expansion(mult = c(.05,.025))) +
    scale_fill_manual(values = to_swap)
    

female <-
    ggplot((density |> filter(SEX == 'Female')),
           aes(
               x = age_bucket,
               y = as.numeric(pct),
               fill = Marital_Status
           )) +
    geom_bar(stat = "identity", width = 1, color = 'black', size = .3) + 
    coord_flip() + 

 

    labs(subtitle = 'Female',
  fill = "Status",
  y = element_blank()
        ) + 
  #  hrbrthemes::theme_ipsum_ps() + 
    
  geom_shadowtext(aes(label = ifelse(round(pct) > 3, paste0(round(pct), "%"), "")), size = 2.8,position = position_stack(vjust = .5)) + 
    scale_y_continuous(labels = scales::percent_format(scale = 1),  expand = expansion(mult = c(.025,0.05))) +

  coord_flip() + #+ coord_flip() +  scale_y_reverse(limits=c(100,-100))+
    
  theme(
        legend.position = 'none',
        axis.title.y = element_blank(),
        axis.text.y = element_blank(),
        axis.ticks.y = element_blank(),
        axis.line.y = element_blank(),
     #   plot.subtitle = element_text(hjust = 0.5),
     plot.margin = margin(l = 0)
    )  + scale_fill_manual(values = to_swap)


combined <- male + female & theme(legend.position = "right", legend.text=element_text(size=8))  
combined <- combined + plot_layout(guides = "collect") + plot_annotation(
  title = 'Marital Status of African Americans',
  subtitle = 'By Age and Sex, 2015-2019',
  caption = element_text('Made by Elizabeth Goodwin\n Source: 2015-2019 ACS, IPUMS USA', size = 8)) +
  plot_annotation(theme = theme(plot.margin = margin(r = 15, l = 15, t = 20, b = 20, unit = 'pt')))

combined
ggsave('lot-11931-no-53-GOODWIN.pdf',combined, dpi = 400, height = 5.83, width = 9)
#ggsave('lot-11931-no-53-GOODWIN.png',combined, dpi = 400, height = 5.83, width = 9)

4 Employment Figure

acs_occ_pct <- acs_2019_5yr %>% count(OCC2010, RACE, wt = PERWT) |> add_count(OCC2010, wt = n, name = 'total') |>  mutate(pct = 100*n/total) |> ipums_collect(ddi)
acs_occ <- acs_occ_pct |> 
    mutate(OCC2010 = as.numeric(OCC2010),  
    occ = case_when(
        ((OCC2010 >= 10) & (OCC2010 <= 430)) ~ 'Management, Business, Science, and Arts',
        ((OCC2010 >= 500 ) & (OCC2010 <= 730)) ~ 'Business Operations Specialists',
        ((OCC2010 >= 800) & (OCC2010 <= 950)) ~ 'Financial Specialists',
        ((OCC2010 >= 1000) & (OCC2010 <= 1240)) ~ 'Computer and Mathematical',
        ((OCC2010 >= 1300) & (OCC2010 <= 1540)) ~ 'Architecture and Engineering',
        ((OCC2010 >= 1550) & (OCC2010 <= 1560)) ~ 'Technicians',
        ((OCC2010 >= 1600) & (OCC2010 <= 1980)) ~ 'Life, Physical, and Social Science',
        ((OCC2010 >= 2000) & (OCC2010 <= 2060)) ~ 'Community and Social Services',
        ((OCC2010 >= 2100) & (OCC2010 <= 2150)) ~ 'Legal',
        ((OCC2010 >= 2200) & (OCC2010 <= 2550)) ~ 'Education, Training, and Library',
        ((OCC2010 >= 2600) & (OCC2010 <= 2920)) ~ 'Arts, Design, Entertainment, Sports, and Media',
        ((OCC2010 >= 3000) & (OCC2010 <= 3540)) ~ 'Healthcare Practitioners and Technicians',
        ((OCC2010 >= 3600) & (OCC2010 <= 3650)) ~ 'Healthcare Support',
        ((OCC2010 >= 3700) & (OCC2010 <= 3950)) ~ 'Protective Service',
        ((OCC2010 >= 4000) & (OCC2010 <= 4150)) ~ 'Food Preparation and Serving',
        ((OCC2010 >= 4200) & (OCC2010 <= 4250)) ~ 'Building and Grounds Cleaning and Maintenance',
        ((OCC2010 >= 4300) & (OCC2010 <= 4650)) ~ 'Personal Care and Service',
        ((OCC2010 >= 4700) & (OCC2010 <= 4965)) ~ 'Sales and Related',
        ((OCC2010 >= 5000) & (OCC2010 <= 5940)) ~ 'Office and Administrative Support',
        ((OCC2010 >= 6005) & (OCC2010 <= 6130)) ~ 'Farming, Fishing, and Forestry',
        ((OCC2010 >= 6200) & (OCC2010 <= 6765)) ~ 'Construction',
        ((OCC2010 >= 6800) & (OCC2010 <= 6940)) ~ 'Extraction',
        ((OCC2010 >= 7000) & (OCC2010 <= 7630)) ~ 'Installation, Maintenance, and Repair',
        ((OCC2010 >= 7700) & (OCC2010 <= 8965)) ~ 'Production',
        ((OCC2010 >= 9000) & (OCC2010 <= 9750)) ~ 'Transportation and Material Moving',
        ((OCC2010 >= 9800) & (OCC2010 <= 9830)) ~ 'Military Specific',
        ((OCC2010 >= 9920) & (OCC2010 <= 9920)) ~ 'Unemployed for 5+ years or Never Worked',
        TRUE ~ 'Other'),
    race = case_when(RACE == 1 ~ 'White', RACE == 2 ~ 'Black', TRUE ~ 'Other')
    ) |>
    ungroup() |> 
    select(occ, race, n, total, pct) |> 
    count(occ, race, wt = n) |> 
    add_count(occ, wt = n, name = 'total') |> 
    mutate(pct = 100*n/total) |> 
    filter(race != 'Other') |> 
    select(occ, race, pct, n) |>  
    pivot_wider(names_from = race, values_from = c(pct,n)) |> 
    mutate(avg_pct_black = weighted.mean(pct_Black, n_Black),
           diff_from_mean = pct_Black - avg_pct_black,
           occ = fct_reorder(occ, diff_from_mean),
           tot = sum(n_Black, n_White),
           ci = 196 * sqrt(((n_Black / tot) * (1 - (n_Black / tot))) / tot))
acs_occ_fig <- acs_occ %>% 
    ggplot(aes(x = pct_Black, y = occ, color = diff_from_mean)) +
    geom_point(size = 3) + 
    geom_vline(aes(xintercept = avg_pct_black), linetype = 2) + 
    scale_color_viridis() + 
    theme(legend.position = 'none',
           plot.title.position = "plot", 
    plot.caption.position = "plot",
    plot.margin = margin(r=25, l=25, t=25, b=10)
    ) + 
    labs(
        title = 'Percent African American by Employment Sector', 
        subtitle = 'Grouped by overall Employment Category. Dotted line is overall percent of population',
        x = "Percent African American",
        y = "Employment Sector",
        color = 'Difference from overall percent'
        
    ) 
acs_occ_fig
acs_occ_2 <- acs_occ_pct |> 
    mutate(occ = labelled::to_character(OCC2010),  
           #race = labelled::to_factor(RACE)
           race = case_when(RACE == 1 ~ 'White', RACE == 2 ~ 'Black', TRUE ~ 'Other')
    ) |>
    ungroup() |> 
    mutate(
        occ = case_when(occ == 'Postal Service Mail Sorters, Processors, and Processing Machine Operators' ~ "Postal Service Mail Sorters and Processors",
                        occ == "Farmers, Ranchers, and Other Agricultural Managers" ~ "Farmers and Ranchers",
                        occ == "Security Guards and Gaming Surveillance Officers" ~ "Security Guards",
                        TRUE ~ occ)) |> 
    select(occ, race, n, total, pct) |> 
    count(occ, race, wt = n) |> 
    add_count(occ, wt = n, name = 'total') |> 
    mutate(pct = 100*n/total) |> 
    filter(race != 'Other') |> 
    #add_count(race, wt = n, name = 'test') |> 
    #  filter(race < 3) |> 
    #  mutate(race = case_when(RACE == 1 ~ 'White', TRUE ~ 'Black'))|> 
    select(occ, race, pct, n) |>  
    pivot_wider(names_from = race, values_from = c(pct,n)) |> 
    mutate(avg_pct_black = weighted.mean(pct_Black, n_Black),
           diff_from_mean = pct_Black - avg_pct_black,
           occ = fct_reorder(occ, diff_from_mean),
           tot = sum(n_Black, n_White),
           ci = 196 * sqrt(((n_Black / tot) * (1 - (n_Black / tot))) / tot)) %>% mutate(type = case_when(diff_from_mean < 0 ~ 'Low', TRUE ~ 'High')) |> group_by(type) %>% 
    slice_min(desc(abs(diff_from_mean)), n= 8) %>%
    ungroup()

acs_occ_fig_2 <- acs_occ_2 %>% 
    ggplot(aes(x = pct_Black, y = occ, color = diff_from_mean)) +
    geom_point(size = 3) + 
    geom_vline(aes(xintercept = avg_pct_black), linetype = 2) + 
    scale_color_viridis() + 
    theme(legend.position = 'none',
           plot.title.position = "plot", # NEW parameter. Apply for subtitle too.
    plot.caption.position = "plot",
    plot.margin = margin(r=25, l=25, t=25, b=25)
    ) + 
    labs(
        title = 'Top 8 Highest and Lowest Jobs by African American representation', 
        subtitle = 'Grouped by specific employment classification, not overall sector',
        x = "Percent African American",
        y = "Employment Role",
        color = 'Difference from overall percent'
        
    ) + facet_free(type ~ .)
acs_occ_fig_2#+ coord_flip()
combined_occ <- acs_occ_fig / acs_occ_fig_2 + plot_layout(heights = c(1.5,1)) + plot_annotation(theme = theme(legend.position = 'none', plot.margin = margin(b = 10)), caption = 'Made by Elizabeth Goodwin | 2010 OCCSCORE, 2015-2019 ACS, IPUMS USA')
ggsave('original-GOODWIN.pdf', plot = combined_occ, dpi = 400, height = 10, width = 8)
#ggsave('original-GOODWIN.png', plot = combined_occ, dpi = 400, height = 10, width = 8)
LS0tCnRpdGxlOiAnRGVib2lzIFByb2plY3QnCmF1dGhvcnNzOiBFbGl6YWJldGggR29vZHdpbgpkYXRlOiAyMDIyLTA5LTIzCm91dHB1dDoKICBybWRmb3JtYXRzOjpyb2JvYm9vazoKICMgICBmaWdfY2FwdGlvbjogdHJ1ZQojICAgIGxpZ2h0Ym94OiB0cnVlCiAjICAgZ2FsbGVyeTogdHJ1ZQogICAgc2VsZl9jb250YWluZWQ6IHRydWUKICAjICBkZl9wcmludDogcGFnZWQKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIG51bWJlcl9zZWN0aW9uczogVFJVRQogICAgdG9jX2RlcHRoOiA1CiAgIyAgY29kZV9mb2xkaW5nOiBoaWRlIAogICAgdXNlX2Jvb2tkb3duOiB0cnVlCiAgICAjICAgI3BkZi1lbmdpbmU6CiAgICAgICAjICAgICBwZGZsYXRleAogICMgcm1kZm9ybWF0czo6cm9ib2Jvb2s6CiAgIyAgIGZpZ19jYXB0aW9uOiB0cnVlCiAgIyAgIGxpZ2h0Ym94OiB0cnVlCiAgIyAgIGdhbGxlcnk6IHRydWUKICAjICAgc2VsZl9jb250YWluZWQ6IHRydWUKICAjICAgZGZfcHJpbnQ6IHBhZ2VkCiAgIyAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAjICAgbnVtYmVyX3NlY3Rpb25zOiBUUlVFCiAgIyAgIHRvY19kZXB0aDogNQogICMgICBjb2RlX2ZvbGRpbmc6IGhpZGUgCiAgIyAgIHVzZV9ib29rZG93bjogdHJ1ZQojZW1iZWQtcmVzb3VyY2VzOiB0cnVlCgpmb250c2l6ZTogMTJwdAplZGl0b3Jfb3B0aW9uczogCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGNvbnNvbGUKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KHRhYi50b3BjYXB0aW9uID0gVCwgZnRfZG9fYXV0b2ZpdCA9IFQsIGZ0LmFsaWduID0gImxlZnQiLCBmaWcuaGVpZ2h0ID0gMTAsIGZpZy53aWR0aCA9IDEyLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSkKCiNzZXR3ZCgiL1VzZXJzL2xpei9Eb2N1bWVudHMvUHJvamVjdHMvIikKCiMgTW9zdCBvZiB0aGVzZSBwYWNrYWdlcyBhcmUgbm90IG5lZWRlZCBhdCBhbGwsIEkganVzdCBrZWVwIGEgYmlnIGltcG9ydCBsaXN0IHNvIEkgaGF2ZSBldmVyeXRoaW5nIEkgd291bGQgZXZlciBuZWVkCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KG1hZ3JpdHRyKQpsaWJyYXJ5KGhhdmVuKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZ2dmb3J0aWZ5KQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KHNqbGFiZWxsZWQpCmxpYnJhcnkoZ2dyZXBlbCkKbGlicmFyeShzY2FsZXMpCmxpYnJhcnkoZ2dwdWJyKQpsaWJyYXJ5KHZpcmlkaXMpCmxpYnJhcnkoaHRtbHRvb2xzKQpsaWJyYXJ5KEhtaXNjKQpsaWJyYXJ5KHNoYWRvd3RleHQpCmxpYnJhcnkoaHJicnRoZW1lcykKbGlicmFyeShSUG9zdGdyZXMpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShnZ3NwYXRpYWwpCmxpYnJhcnkocGF0Y2h3b3JrKQpsaWJyYXJ5KHNjaWNvKQpsaWJyYXJ5KHVzbWFwKQpsaWJyYXJ5KGRicGx5cikKbGlicmFyeShEQkkpCmxpYnJhcnkoZ2d0aGVtcikKbGlicmFyeShmb3JtYXRSKQpsaWJyYXJ5KGlwdW1zcikKZ2d0aGVtcihwYWxldHRlID0gJ2R1c3QnLCB0eXBlID0gJ291dGVyJykKYGBgCkEgTG90IG9mIHRoaXMgaXMgYW4gYWJzb2x1dGUgbWVzcy4gTm90IG1hbnkgQ29tbWVudHMuIEp1c3QgZmlndXJlZCBJIHNob3VsZCBwb3N0IGl0IGFueXdheXMuIAoKIyBEYXRhYmFzZSBsb2FkIGFuZCBzZXR1cCAKClVzZWQgYSBsb2NhbCBwb3N0Z3Jlc3NxbCBkYXRhYmFzZSB0byBmaXQgZnVsbCBkYXRhIGluIG1lbW9yeS4gVGhpcyBjb2RlIGlzIG1vc3RseSBqdXN0IGltcG9ydGluZyBpdCBpbnRvIHRoZSBkYXRhYmFzZSwgbG9hZGluZyBpdCwgZXRjLiAKCmBgYHtyIGV2YWwgPSBGfQojIExvYWQgRGF0YWJhc2UKY29ubiA8LSAKICAgIGRiQ29ubmVjdCgKICAgICAgICBkcnYgPSBQb3N0Z3JlcygpLAogICAgICAgIHVzZXIgPSAnbGl6c3FsJywgCiAgICAgICAgcGFzc3dvcmQgPSAnbGl6c3FsJywgCiAgICAgICAgaG9zdCA9ICJsb2NhbGhvc3QiLAogICAgICAgIHBvcnQgPSAiNTQzMiIsCiAgICAgICAgZGJuYW1lID0gInBvc3RncmVzIgogICAgKQpgYGAKCmBgYHtyIGV2YWwgPSBGfQpkZWJvaXNfMTkwMCA8LSB0YmwoY29ubiwgaW5fc2NoZW1hKCdwdWJsaWMnLCAnZGVib2lzXzE5MDAnKSkKYWNzXzIwMTlfNXlyIDwtIHRibChjb25uLCBpbl9zY2hlbWEoJ3B1YmxpYycsICdhY3NfMjAxOV81eXJfdjInKSkKYGBgCmBgYHtyIGV2YWwgPSBGfQojIFJlYWRzIGludG8gUG9zdGdyZXMuIFJlcGxhY2UgdmFyaWFibGUgYW5kIHRhYmxlIG5hbWVzIGZvciBlYWNoIGRhdGFzZXQuIAojIEhhZCB0byB1c2UgcG9zdGdyZXMgYXMgZnVsbCAxOTAwIGNlbnN1cyB3b3VsZCBub3QgZml0IGluIG1lbW9yeS4gCmNwc19kZGlfZmlsZSA8LSAidXNhXzAwMDA5LnhtbCIKY3BzX2RhdGFfZmlsZSA8LSAidXNhXzAwMDA5LmRhdCIKIyBBZGQgZGF0YSB0byB0YWJsZXMgaW4gY2h1bmtzCmRkaSA8LSByZWFkX2lwdW1zX2RkaShjcHNfZGRpX2ZpbGUpCnJlYWRfaXB1bXNfbWljcm9fY2h1bmtlZCgKICBkZGksCiAgZGF0YV9maWxlID0gY3BzX2RhdGFfZmlsZSwKICByZWFkcjo6U2lkZUVmZmVjdENodW5rQ2FsbGJhY2skbmV3KGZ1bmN0aW9uKHgsIHBvcykgewogICAgaWYgKHBvcyA9PSAxKSB7CiAgICAgIGRiV3JpdGVUYWJsZShjb25uLCAiYWNzXzIwMTlfNXlyX3YyIiwgeCkKICAgIH0gZWxzZSB7CiAgICAgIGRiV3JpdGVUYWJsZShjb25uLCAiYWNzXzIwMTlfNXlyX3YyIiwgeCwgcm93Lm5hbWVzID0gRkFMU0UsIGFwcGVuZCA9IFRSVUUpCiAgICB9CiAgfSksCiAgY2h1bmtfc2l6ZSA9IDMwMDAwLAogIHZlcmJvc2UgPSBGQUxTRQopCnMKYGBgCgpgYGB7ciBldmFsID0gRn0KZiA8LSBkZWJvaXNfMTkwMCB8PiAKICAgIGZpbHRlcihTVEFURUZJUCA9PSAxMywgUkFDRSA9PSAyKSB8PiAKICAgIGNvdW50KEJQTCkgfD4gCiAgICBpcHVtc19jb2xsZWN0KGRkaSkKCmYyIDwtIGRlYm9pc18xOTAwIHw+IAogICAgZmlsdGVyKEJQTCA9PSAxMywgUkFDRSA9PSAyKSB8PiAKICAgIGNvdW50KFNUQVRFRklQKSB8PiAKICAgIGlwdW1zX2NvbGxlY3QoZGRpKQpgYGAKCiMgTWlncmF0aW9uIENoYXJ0ClRoaXMgaXMgdmVyeSBtZXNzeS4gQnV0IGJhc2ljYWxseSBpbnZvbHZlZCBmaWx0ZXJpbmcgb3V0IHZhcmlvdXMgcGFydHMgb2YgdGhlIGRhdGFzZXQgYW5kIHRoZW4gY3JlYXRpbmcgdGhlIGRpZmZlcmVudCBmaWd1cmVzLiAKCmBgYHtyIGV2YWwgPSBGfQptaWdyYXRpb25fdG9fZ2VvcmdpYSA8LSBmIHw+IG11dGF0ZShyZWdpb24gPSBsYWJlbGxlZDo6dG9fZmFjdG9yKEJQTCksIEZJUFMgPSBsYWJlbGxlZDo6cmVtb3ZlX2xhYmVscyhCUEwpKSB8PiBzZWxlY3QocmVnaW9uLCBGSVBTLCBuKQpzYXZlUkRTKG1pZ3JhdGlvbl90b19nZW9yZ2lhLCBmaWxlID0gIm1pZ3JhdGlvbl90b19nZW9yZ2lhIikKbWlncmF0aW9uX2Zyb21fZ2VvcmdpYSA8LSBmMiB8PiBtdXRhdGUocmVnaW9uID0gbGFiZWxsZWQ6OnRvX2ZhY3RvcihTVEFURUZJUCksIEZJUFMgPSBsYWJlbGxlZDo6cmVtb3ZlX2xhYmVscyhTVEFURUZJUCkpIHw+IAogICAgc2VsZWN0KHJlZ2lvbiwgRklQUywgbikKI3NhdmVSRFMobWlncmF0aW9uX2Zyb21fZ2VvcmdpYSwgZmlsZSA9ICdtaWdyYXRpb25fZnJvbV9nZW9yZ2lhJykKYGBgCgpgYGB7ciBldmFsID0gRn0KZml4ZWRfbnVtYmVycyA8LQogICAgbWlncmF0aW9uX2Zyb21fZ2VvcmdpYSAlPiUgZmlsdGVyKEZJUFMgPCA2MCkgJT4lIG11dGF0ZShyZWdpb24gPSB0b2xvd2VyKHJlZ2lvbikpICU+JSBmaWx0ZXIocmVnaW9uICE9ICdkaXN0cmljdCBvZiBjb2x1bWJpYScsIEZJUFMgIT0gMTMpICU+JSBtdXRhdGUobiA9IGFzLm51bWVyaWMobikpICU+JSBzZWxlY3QocmVnaW9uLCBuKQpzdGF0ZXNfbWFwIDwtIG1hcF9kYXRhKCdzdGF0ZScpCnRvdGFsX21hcCA8LSBsZWZ0X2pvaW4oc3RhdGVzX21hcCwgZml4ZWRfbnVtYmVycywgYnkgPSAncmVnaW9uJykKc3RhdGVfbmFtZSA8LQogICAgZGF0YS5mcmFtZSgKICAgICAgICBhYmIgPSBzdGF0ZS5hYmIsCiAgICAgICAgcmVnaW9uID0gdG9sb3dlcihzdGF0ZS5uYW1lKSwKICAgICAgICB4ID0gc3RhdGUuY2VudGVyJHgsCiAgICAgICAgeSA9IHN0YXRlLmNlbnRlciR5CiAgICApIHw+IGZpbHRlcihhYmIgIT0gJ0hJJywgYWJiICE9ICdBSycpIHw+CiAgICBsZWZ0X2pvaW4oZml4ZWRfbnVtYmVycykgIywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgICAgICAgICAgIFRSVUUgfiBuKSkgCmZyb21fZ2EgPC0gZ2dwbG90KHRvdGFsX21hcCwgYWVzKGxvbmcsIGxhdCwgZ3JvdXAgPSBncm91cCkpICsKICAgICMgICAgYW5ub3RhdGlvbl9tYXBfdGlsZSgic3RhbWVud2F0ZXJjb2xvciIpICsKICAgIGdlb21fcG9seWdvbihhZXMoZmlsbCA9IG4pLCBjb2xvciA9ICJ3aGl0ZSIpICsKICAgIHNjYWxlX2ZpbGxfdmlyaWRpc19jKG9wdGlvbiA9ICJDIiwKICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zID0gJ2xvZycsCiAgICAgICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAtMSkgKyBnZW9tX3NoYWRvd3RleHQoZGF0YSA9IHN0YXRlX25hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWVzKAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0geCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IHksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gaWZlbHNlKGFiYiA9PSAnR0EnLCAiR0FcbiAiLCBwYXN0ZTAoYWJiLCdcbicsIGlmZWxzZShpcy5uYShuKSwgMCwgbikpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSAxCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gMikgKwogICAgIyAgYW5ub3RhdGlvbl9zY2FsZSgpICsKICMgICB0aGVtZV92b2lkKCkgKwogICAgdGhlbWUoYXhpcy5saW5lPWVsZW1lbnRfYmxhbmsoKSxheGlzLnRleHQueD1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X2JsYW5rKCksYXhpcy50aWNrcz1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpLCBsZWdlbmQucG9zaXRpb24gPSAnbm9uZScsCiAgICAgICAgICBheGlzLnRpdGxlLnk9ZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgcGFuZWwuYmFja2dyb3VuZD1lbGVtZW50X2JsYW5rKCkscGFuZWwuYm9yZGVyPWVsZW1lbnRfYmxhbmsoKSxwYW5lbC5ncmlkLm1ham9yPWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIHBhbmVsLmdyaWQubWlub3I9ZWxlbWVudF9ibGFuaygpLHBsb3QuYmFja2dyb3VuZD1lbGVtZW50X2JsYW5rKCkpICsKICAgICBsYWJzKAogICAgICAgIGNvbG9yID0gJ1BvcHVsYXRpb24nLAogICAgICAgIHRpdGxlID0gJ1BvcHVsYXRlZCBNaWdyYXRlZCBmcm9tIEdlb3JnaWEnLAogICAgICAgIHN1YnRpdGxlID0gJ1BvcHVsYXRpb24gYm9ybiBpbiBHZW9yZ2lhIGJ5IGN1cnJlbnQgc3RhdGUgb2YgcmVzaWRlbmNlIChpZiBsaXZpbmcgb3V0c2lkZSBHZW9yZ2lhKScKICAgICkgCiAgICMgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpCiN0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKQpmcm9tX2dhCmdnc2F2ZSgKICAgICdmcm9tX2dhLnBuZycsCiAgICBmcm9tX2dhLAogICAgd2lkdGggPSAyNTYwLAogICAgaGVpZ2h0ID0gMTQ0MCwKICAgIHVuaXRzID0gYygncHgnKQopCgoKZml4ZWRfbnVtYmVycyA8LQogICAgbWlncmF0aW9uX3RvX2dlb3JnaWEgJT4lIGZpbHRlcihGSVBTIDwgNjApICU+JSBtdXRhdGUocmVnaW9uID0gdG9sb3dlcihyZWdpb24pKSAlPiUgZmlsdGVyKHJlZ2lvbiAhPSAnZGlzdHJpY3Qgb2YgY29sdW1iaWEnLCBGSVBTICE9IDEzKSAlPiUgbXV0YXRlKG4gPSBhcy5udW1lcmljKG4pKSAlPiUgc2VsZWN0KHJlZ2lvbiwgbikKc3RhdGVzX21hcCA8LSBtYXBfZGF0YSgnc3RhdGUnKQp0b3RhbF9tYXAgPC0gbGVmdF9qb2luKHN0YXRlc19tYXAsIGZpeGVkX251bWJlcnMsIGJ5ID0gJ3JlZ2lvbicpCnN0YXRlX25hbWUgPC0KICAgIGRhdGEuZnJhbWUoCiAgICAgICAgYWJiID0gc3RhdGUuYWJiLAogICAgICAgIHJlZ2lvbiA9IHRvbG93ZXIoc3RhdGUubmFtZSksCiAgICAgICAgeCA9IHN0YXRlLmNlbnRlciR4LAogICAgICAgIHkgPSBzdGF0ZS5jZW50ZXIkeQogICAgKSB8PiBmaWx0ZXIoYWJiICE9ICdISScsIGFiYiAhPSAnQUsnKSB8PgogICAgbGVmdF9qb2luKGZpeGVkX251bWJlcnMpIyAlPiUgbXV0YXRlKG4gPSBjYXNlX3doZW4oYWJiID09ICdHQScgfiA5NTg5ODQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gbikpCnRvX2dhIDwtIGdncGxvdCh0b3RhbF9tYXAsIGFlcyhsb25nLCBsYXQsIGdyb3VwID0gZ3JvdXApKSArCiAgICAjICAgIGFubm90YXRpb25fbWFwX3RpbGUoInN0YW1lbndhdGVyY29sb3IiKSArCiAgICBnZW9tX3BvbHlnb24oYWVzKGZpbGwgPSBuKSwgY29sb3IgPSAid2hpdGUiKSArCiAgICBzY2FsZV9maWxsX3ZpcmlkaXNfYyhvcHRpb24gPSAiQyIsCiAgICAgICAgICAgICAgICAgICAgICAgICB0cmFucyA9ICdsb2cnLAogICAgICAgICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gLTEpICsgZ2VvbV9zaGFkb3d0ZXh0KGRhdGEgPSBzdGF0ZV9uYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFlcygKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9IHgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSB5LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9ICBpZmVsc2UoYWJiID09ICdHQScsICJHQVxuICIsIHBhc3RlMChhYmIsJ1xuJywgaWZlbHNlKGlzLm5hKG4pLCAwLCBuKSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cCA9IDEKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAyKSArCiAgICAjICBhbm5vdGF0aW9uX3NjYWxlKCkgKwogICAjIHRoZW1lX3ZvaWQoKSArCiAgICAjdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsgCiAgICBsYWJzKAogICAgICAgIGNvbG9yID0gJ1BvcHVsYXRpb24nLAogICAgICAgIHRpdGxlID0gJ1BvcHVsYXRpb24gTWlncmF0ZWQgdG8gR2VvcmdpYScsIAogICAgICAgIHN1YnRpdGxlID0gJ051bWJlciBvZiBjdXJyZW50IEdlb3JnaWEgcmVzaWRlbnRzIGJ5IHBsYWNlIG9mIGJpcnRoIChpZiBib3JuIG91dHNpZGUgZ2VvcmdpYSknCiAgICApICsKICAgICAgdGhlbWUoYXhpcy5saW5lPWVsZW1lbnRfYmxhbmsoKSxheGlzLnRleHQueD1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X2JsYW5rKCksYXhpcy50aWNrcz1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgYXhpcy50aXRsZS55PWVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLnBvc2l0aW9uID0gJ25vbmUnLAogICAgICAgICAgcGFuZWwuYmFja2dyb3VuZD1lbGVtZW50X2JsYW5rKCkscGFuZWwuYm9yZGVyPWVsZW1lbnRfYmxhbmsoKSxwYW5lbC5ncmlkLm1ham9yPWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIHBhbmVsLmdyaWQubWlub3I9ZWxlbWVudF9ibGFuaygpLHBsb3QuYmFja2dyb3VuZD1lbGVtZW50X2JsYW5rKCkpCiAgICAgICAgIyAgcGxvdC5tYXJnaW4gPSBtYXJnaW4oKSkKI3RoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpCnRvX2dhCmdnc2F2ZSgKICAgICd0b19nYS5wbmcnLAogICAgdG9fZ2EsCiAgICB3aWR0aCA9IDI1NjAsCiAgICBoZWlnaHQgPSAxNDQwLAogICAgdW5pdHMgPSBjKCdweCcpCikKCnBhdGNod29yayA9IHRvX2dhIC8gZnJvbV9nYQpwYXRjaHdvcmsgPC0gcGF0Y2h3b3JrICsgCiAgICBwbG90X2Fubm90YXRpb24oCiAgICB0aGVtZSA9IHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICdub25lJywKICAgICAgICAgICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApLAogICAgICAgICAgICAgICAgICBwbG90Lm1hcmdpbiA9IG1hcmdpbih0ID0gMjUsIGIgPSAyNSwgbCA9IDI1LCByID0gMjUpKSwKICAgIHRpdGxlID0gJ01pZ3JhdGlvbiBvZiBBZnJpY2FuIEFtZXJpY2FucyB0byBhbmQgZnJvbSBHZW9yZ2lhLCAxOTAwJywKICAgIHN1YnRpdGxlID0gJ1Jlc2lkZW50cyBvZiBHZW9yZ2lhIGJvcm4gaW4gYW5vdGhlciBzdGF0ZSwgYW5kIHJlc2lkZW50cyBvZiBvdGhlciBzdGF0ZXMgYm9ybiBpbiBHZW9yZ2lhXG4gJywKICAgIGNhcHRpb24gPSAnQ3JlYXRlZCBieSBFbGl6YWJldGggR29vZHdpbiB1c2luZyB0aGUgZnVsbCAxOTAwIENlbnN1cywgSVBVTVMgVVNBJwogICAgIyBzdWJ0aXRsZSA9ICdUaGVzZSAzIHBsb3RzIHdpbGwgcmV2ZWFsIHlldC11bnRvbGQgc2VjcmV0cyBhYm91dCBvdXIgYmVsb3ZlZCBkYXRhLXNldCcsCiAgICAjICAgY2FwdGlvbiA9ICdEaXNjbGFpbWVyOiBOb25lIG9mIHRoZXNlIHBsb3RzIGFyZSBpbnNpZ2h0ZnVsJywKICAjICB0YWdfbGV2ZWxzID0gYygnQScsICcxJyksCiAgIyAgdGFnX3ByZWZpeCA9ICdGaWcuICcsCiAjICAgdGFnX3NlcCA9ICcuJywKICAjICB0YWdfc3VmZml4ID0gJzonCikgIApwYXRjaHdvcmsKCmZpbGVuYW1lID0gJ2xvdC0xMTkzMS1uby0wOC1HT09EV0lOLnBkZicKZmlsZW5hbWVwbmcgPSAnbG90LTExOTMxLW5vLTA4LUdPT0RXSU4ucG5nJwpnZ3NhdmUoZmlsZW5hbWUsIAogICAgICAgcGxvdCA9IHBhdGNod29yaywKICAgICAgIGRwaSA9IDMwMCwKICAgICAgIGhlaWdodCA9IDExLAogICAgICAgd2lkdGggPSA4LjUKICAgICAgICkKCmBgYAoKIyBNYXJpdGFsIFN0YXR1cyBGaWd1cmUKCmBgYHtyIGV2YWwgPSBGfQpkZW5zaXR5IDwtIGFjc18yMDE5XzV5ciB8PiAKICAgIGZpbHRlcihSQUNFID09IDEpIHw+IAogICAgbXV0YXRlKAogICAgICAgIGFnZV9idWNrZXQgPSBjYXNlX3doZW4oCiAgICAgICAgICAgIAogICAgICAgICAgICBBR0UgPCAxNiB+ICIwLTE1IiwKICAgICAgICAgICAgQUdFIDwgMjEgfiAiMTUtMjAiLAogICAgICAgICAgICBBR0UgPCAyNiB+ICIyMC0yNSIsCiAgICAgICAgICAgIEFHRSA8IDMxIH4gIjI1LTMwIiwKICAgICAgICAgICAgQUdFIDwgMzYgfiAiMzAtMzUiLAogICAgICAgICAgICBBR0UgPCA0NiB+ICIzNS00NSIsCiAgICAgICAgICAgIEFHRSA8IDU2IH4gIjQ1LTU1IiwKICAgICAgICAgICAgQUdFIDwgNjYgfiAiNTUtNjUiLAogICAgICAgICAgICBBR0UgPCA3NiB+ICI2NS03NSIsCiAgICAgICAgICAgIEFHRSA8IDg5IH4gIk92ZXIgNzUiLAogICAgICAgICAgICBUUlVFIH4gJ290aGVyJwogICAgICAgICksIAogICAgICAgIE1hcml0YWxfU3RhdHVzID0gY2FzZV93aGVuKAogICAgICAgICAgICBNQVJTVCA8IDMgfiAnTWFycmllZCcsIAogICAgICAgICAgICBNQVJTVCA8IDUgfiAnU2VwYXJhdGVkL1xuRGl2b3JjZWQnLCAKICAgICAgICAgICAgTUFSU1QgPT0gNSB+ICJXaWRvd2VkIiwgCiAgICAgICAgICAgIE1BUlNUID09IDYgfiAiU2luZ2xlIgogICAgICAgICkKICAgICkgfD4gCiAgICBjb3VudChTRVgsIGFnZV9idWNrZXQsIE1hcml0YWxfU3RhdHVzKSB8PiAKICAgIGlwdW1zX2NvbGxlY3QoZGRpKSB8PiAKICAgIGZpbHRlcihhZ2VfYnVja2V0ICE9ICdvdGhlcicpIHw+IAogICAgYWRkX2NvdW50KFNFWCwgYWdlX2J1Y2tldCwgd3QgPSBuLCBuYW1lID0gJ3RvdGFsJykgfD4gCiAgICBtdXRhdGUocGN0ID0gMTAwKm4gLyB0b3RhbCkgfD4gCiAgICBtdXRhdGUoU0VYID0gY2FzZV93aGVuKFNFWCA9PSAxIH4gJ01hbGUnLCBUUlVFIH4gIkZlbWFsZSIpKSB8PiAKICAgIG11dGF0ZShNYXJpdGFsX1N0YXR1cyA9IGZhY3RvcihNYXJpdGFsX1N0YXR1cywgbGV2ZWxzID0gcmV2KGMoJ1NpbmdsZScsICdNYXJyaWVkJywgIlNlcGFyYXRlZC9cbkRpdm9yY2VkIiwgJ1dpZG93ZWQnKSkpKQpgYGAKCmBgYHtyIGV2YWwgPSBGfQp0b19zd2FwID0gcmV2KGMoIiM5QThBNzYiLCAiI2RiNzM1YyIsICIjRUZBODZFIiwiIzU1NTU1NSIgKSkKbWFsZSA8LQogICAgZ2dwbG90KChkZW5zaXR5IHw+IGZpbHRlcihTRVggPT0gJ01hbGUnKSksCiAgICAgICAgICAgYWVzKHggPSBhZ2VfYnVja2V0LCB5ID0gYXMubnVtZXJpYyhwY3QpLCBmaWxsID0gTWFyaXRhbF9TdGF0dXMpKSArCiAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5Iiwgd2lkdGggPSAxLCBjb2xvciA9ICdibGFjaycsIHNpemUgPSAuMykgKyAKICAgIGNvb3JkX2ZsaXAoKSArIAogICAgCiAgICBsYWJzKHN1YnRpdGxlID0gJ01hbGUnLCAKICAgICAgICAgeSA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgZmlsbCA9ICJTdGF0dXMiLAogICAgICAgICB4ID0gIkFnZSAoWWVhcnMpIikgKyAKICAjICBocmJydGhlbWVzOjp0aGVtZV9pcHN1bV9wcygpICsgCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAnYm90dG9tJwogICMgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KQogICAgICAgICAgKSArIAogICAgZ2VvbV9zaGFkb3d0ZXh0KGFlcyhsYWJlbCA9IGlmZWxzZShyb3VuZChwY3QpID4gMywgcGFzdGUwKHJvdW5kKHBjdCksICIlIiksICIiKSksIHNpemUgPSAyLjgscG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayh2anVzdCA9IC41KSkgKyAKICAgIHNjYWxlX3lfcmV2ZXJzZShsaW1pdHM9YygxMDEsMCksIGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoc2NhbGUgPSAxKSwgZXhwYW5kID0gZXhwYW5zaW9uKG11bHQgPSBjKC4wNSwuMDI1KSkpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHRvX3N3YXApCiAgICAKCmZlbWFsZSA8LQogICAgZ2dwbG90KChkZW5zaXR5IHw+IGZpbHRlcihTRVggPT0gJ0ZlbWFsZScpKSwKICAgICAgICAgICBhZXMoCiAgICAgICAgICAgICAgIHggPSBhZ2VfYnVja2V0LAogICAgICAgICAgICAgICB5ID0gYXMubnVtZXJpYyhwY3QpLAogICAgICAgICAgICAgICBmaWxsID0gTWFyaXRhbF9TdGF0dXMKICAgICAgICAgICApKSArCiAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5Iiwgd2lkdGggPSAxLCBjb2xvciA9ICdibGFjaycsIHNpemUgPSAuMykgKyAKICAgIGNvb3JkX2ZsaXAoKSArIAoKIAoKICAgIGxhYnMoc3VidGl0bGUgPSAnRmVtYWxlJywKICBmaWxsID0gIlN0YXR1cyIsCiAgeSA9IGVsZW1lbnRfYmxhbmsoKQogICAgICAgICkgKyAKICAjICBocmJydGhlbWVzOjp0aGVtZV9pcHN1bV9wcygpICsgCiAgICAKICBnZW9tX3NoYWRvd3RleHQoYWVzKGxhYmVsID0gaWZlbHNlKHJvdW5kKHBjdCkgPiAzLCBwYXN0ZTAocm91bmQocGN0KSwgIiUiKSwgIiIpKSwgc2l6ZSA9IDIuOCxwb3NpdGlvbiA9IHBvc2l0aW9uX3N0YWNrKHZqdXN0ID0gLjUpKSArIAogICAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoc2NhbGUgPSAxKSwgIGV4cGFuZCA9IGV4cGFuc2lvbihtdWx0ID0gYyguMDI1LDAuMDUpKSkgKwoKICBjb29yZF9mbGlwKCkgKyAjKyBjb29yZF9mbGlwKCkgKyAgc2NhbGVfeV9yZXZlcnNlKGxpbWl0cz1jKDEwMCwtMTAwKSkrCiAgICAKICB0aGVtZSgKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAnbm9uZScsCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLmxpbmUueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAjICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksCiAgICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4obCA9IDApCiAgICApICArIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHRvX3N3YXApCgoKY29tYmluZWQgPC0gbWFsZSArIGZlbWFsZSAmIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsIGxlZ2VuZC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTgpKSAgCmNvbWJpbmVkIDwtIGNvbWJpbmVkICsgcGxvdF9sYXlvdXQoZ3VpZGVzID0gImNvbGxlY3QiKSArIHBsb3RfYW5ub3RhdGlvbigKICB0aXRsZSA9ICdNYXJpdGFsIFN0YXR1cyBvZiBBZnJpY2FuIEFtZXJpY2FucycsCiAgc3VidGl0bGUgPSAnQnkgQWdlIGFuZCBTZXgsIDIwMTUtMjAxOScsCiAgY2FwdGlvbiA9IGVsZW1lbnRfdGV4dCgnTWFkZSBieSBFbGl6YWJldGggR29vZHdpblxuIFNvdXJjZTogMjAxNS0yMDE5IEFDUywgSVBVTVMgVVNBJywgc2l6ZSA9IDgpKSArCiAgcGxvdF9hbm5vdGF0aW9uKHRoZW1lID0gdGhlbWUocGxvdC5tYXJnaW4gPSBtYXJnaW4ociA9IDE1LCBsID0gMTUsIHQgPSAyMCwgYiA9IDIwLCB1bml0ID0gJ3B0JykpKQoKY29tYmluZWQKZ2dzYXZlKCdsb3QtMTE5MzEtbm8tNTMtR09PRFdJTi5wZGYnLGNvbWJpbmVkLCBkcGkgPSA0MDAsIGhlaWdodCA9IDUuODMsIHdpZHRoID0gOSkKI2dnc2F2ZSgnbG90LTExOTMxLW5vLTUzLUdPT0RXSU4ucG5nJyxjb21iaW5lZCwgZHBpID0gNDAwLCBoZWlnaHQgPSA1LjgzLCB3aWR0aCA9IDkpCmBgYAoKIyBFbXBsb3ltZW50IEZpZ3VyZSAKCmBgYHtyIGV2YWwgPSBGfQphY3Nfb2NjX3BjdCA8LSBhY3NfMjAxOV81eXIgJT4lIGNvdW50KE9DQzIwMTAsIFJBQ0UsIHd0ID0gUEVSV1QpIHw+IGFkZF9jb3VudChPQ0MyMDEwLCB3dCA9IG4sIG5hbWUgPSAndG90YWwnKSB8PiAgbXV0YXRlKHBjdCA9IDEwMCpuL3RvdGFsKSB8PiBpcHVtc19jb2xsZWN0KGRkaSkKYGBgCgpgYGB7ciBldmFsID0gRn0KCmFjc19vY2MgPC0gYWNzX29jY19wY3QgfD4gCiAgICBtdXRhdGUoT0NDMjAxMCA9IGFzLm51bWVyaWMoT0NDMjAxMCksICAKICAgIG9jYyA9IGNhc2Vfd2hlbigKICAgICAgICAoKE9DQzIwMTAgPj0gMTApICYgKE9DQzIwMTAgPD0gNDMwKSkgfiAnTWFuYWdlbWVudCwgQnVzaW5lc3MsIFNjaWVuY2UsIGFuZCBBcnRzJywKICAgICAgICAoKE9DQzIwMTAgPj0gNTAwICkgJiAoT0NDMjAxMCA8PSA3MzApKSB+ICdCdXNpbmVzcyBPcGVyYXRpb25zIFNwZWNpYWxpc3RzJywKICAgICAgICAoKE9DQzIwMTAgPj0gODAwKSAmIChPQ0MyMDEwIDw9IDk1MCkpIH4gJ0ZpbmFuY2lhbCBTcGVjaWFsaXN0cycsCiAgICAgICAgKChPQ0MyMDEwID49IDEwMDApICYgKE9DQzIwMTAgPD0gMTI0MCkpIH4gJ0NvbXB1dGVyIGFuZCBNYXRoZW1hdGljYWwnLAogICAgICAgICgoT0NDMjAxMCA+PSAxMzAwKSAmIChPQ0MyMDEwIDw9IDE1NDApKSB+ICdBcmNoaXRlY3R1cmUgYW5kIEVuZ2luZWVyaW5nJywKICAgICAgICAoKE9DQzIwMTAgPj0gMTU1MCkgJiAoT0NDMjAxMCA8PSAxNTYwKSkgfiAnVGVjaG5pY2lhbnMnLAogICAgICAgICgoT0NDMjAxMCA+PSAxNjAwKSAmIChPQ0MyMDEwIDw9IDE5ODApKSB+ICdMaWZlLCBQaHlzaWNhbCwgYW5kIFNvY2lhbCBTY2llbmNlJywKICAgICAgICAoKE9DQzIwMTAgPj0gMjAwMCkgJiAoT0NDMjAxMCA8PSAyMDYwKSkgfiAnQ29tbXVuaXR5IGFuZCBTb2NpYWwgU2VydmljZXMnLAogICAgICAgICgoT0NDMjAxMCA+PSAyMTAwKSAmIChPQ0MyMDEwIDw9IDIxNTApKSB+ICdMZWdhbCcsCiAgICAgICAgKChPQ0MyMDEwID49IDIyMDApICYgKE9DQzIwMTAgPD0gMjU1MCkpIH4gJ0VkdWNhdGlvbiwgVHJhaW5pbmcsIGFuZCBMaWJyYXJ5JywKICAgICAgICAoKE9DQzIwMTAgPj0gMjYwMCkgJiAoT0NDMjAxMCA8PSAyOTIwKSkgfiAnQXJ0cywgRGVzaWduLCBFbnRlcnRhaW5tZW50LCBTcG9ydHMsIGFuZCBNZWRpYScsCiAgICAgICAgKChPQ0MyMDEwID49IDMwMDApICYgKE9DQzIwMTAgPD0gMzU0MCkpIH4gJ0hlYWx0aGNhcmUgUHJhY3RpdGlvbmVycyBhbmQgVGVjaG5pY2lhbnMnLAogICAgICAgICgoT0NDMjAxMCA+PSAzNjAwKSAmIChPQ0MyMDEwIDw9IDM2NTApKSB+ICdIZWFsdGhjYXJlIFN1cHBvcnQnLAogICAgICAgICgoT0NDMjAxMCA+PSAzNzAwKSAmIChPQ0MyMDEwIDw9IDM5NTApKSB+ICdQcm90ZWN0aXZlIFNlcnZpY2UnLAogICAgICAgICgoT0NDMjAxMCA+PSA0MDAwKSAmIChPQ0MyMDEwIDw9IDQxNTApKSB+ICdGb29kIFByZXBhcmF0aW9uIGFuZCBTZXJ2aW5nJywKICAgICAgICAoKE9DQzIwMTAgPj0gNDIwMCkgJiAoT0NDMjAxMCA8PSA0MjUwKSkgfiAnQnVpbGRpbmcgYW5kIEdyb3VuZHMgQ2xlYW5pbmcgYW5kIE1haW50ZW5hbmNlJywKICAgICAgICAoKE9DQzIwMTAgPj0gNDMwMCkgJiAoT0NDMjAxMCA8PSA0NjUwKSkgfiAnUGVyc29uYWwgQ2FyZSBhbmQgU2VydmljZScsCiAgICAgICAgKChPQ0MyMDEwID49IDQ3MDApICYgKE9DQzIwMTAgPD0gNDk2NSkpIH4gJ1NhbGVzIGFuZCBSZWxhdGVkJywKICAgICAgICAoKE9DQzIwMTAgPj0gNTAwMCkgJiAoT0NDMjAxMCA8PSA1OTQwKSkgfiAnT2ZmaWNlIGFuZCBBZG1pbmlzdHJhdGl2ZSBTdXBwb3J0JywKICAgICAgICAoKE9DQzIwMTAgPj0gNjAwNSkgJiAoT0NDMjAxMCA8PSA2MTMwKSkgfiAnRmFybWluZywgRmlzaGluZywgYW5kIEZvcmVzdHJ5JywKICAgICAgICAoKE9DQzIwMTAgPj0gNjIwMCkgJiAoT0NDMjAxMCA8PSA2NzY1KSkgfiAnQ29uc3RydWN0aW9uJywKICAgICAgICAoKE9DQzIwMTAgPj0gNjgwMCkgJiAoT0NDMjAxMCA8PSA2OTQwKSkgfiAnRXh0cmFjdGlvbicsCiAgICAgICAgKChPQ0MyMDEwID49IDcwMDApICYgKE9DQzIwMTAgPD0gNzYzMCkpIH4gJ0luc3RhbGxhdGlvbiwgTWFpbnRlbmFuY2UsIGFuZCBSZXBhaXInLAogICAgICAgICgoT0NDMjAxMCA+PSA3NzAwKSAmIChPQ0MyMDEwIDw9IDg5NjUpKSB+ICdQcm9kdWN0aW9uJywKICAgICAgICAoKE9DQzIwMTAgPj0gOTAwMCkgJiAoT0NDMjAxMCA8PSA5NzUwKSkgfiAnVHJhbnNwb3J0YXRpb24gYW5kIE1hdGVyaWFsIE1vdmluZycsCiAgICAgICAgKChPQ0MyMDEwID49IDk4MDApICYgKE9DQzIwMTAgPD0gOTgzMCkpIH4gJ01pbGl0YXJ5IFNwZWNpZmljJywKICAgICAgICAoKE9DQzIwMTAgPj0gOTkyMCkgJiAoT0NDMjAxMCA8PSA5OTIwKSkgfiAnVW5lbXBsb3llZCBmb3IgNSsgeWVhcnMgb3IgTmV2ZXIgV29ya2VkJywKICAgICAgICBUUlVFIH4gJ090aGVyJyksCiAgICByYWNlID0gY2FzZV93aGVuKFJBQ0UgPT0gMSB+ICdXaGl0ZScsIFJBQ0UgPT0gMiB+ICdCbGFjaycsIFRSVUUgfiAnT3RoZXInKQogICAgKSB8PgogICAgdW5ncm91cCgpIHw+IAogICAgc2VsZWN0KG9jYywgcmFjZSwgbiwgdG90YWwsIHBjdCkgfD4gCiAgICBjb3VudChvY2MsIHJhY2UsIHd0ID0gbikgfD4gCiAgICBhZGRfY291bnQob2NjLCB3dCA9IG4sIG5hbWUgPSAndG90YWwnKSB8PiAKICAgIG11dGF0ZShwY3QgPSAxMDAqbi90b3RhbCkgfD4gCiAgICBmaWx0ZXIocmFjZSAhPSAnT3RoZXInKSB8PiAKICAgIHNlbGVjdChvY2MsIHJhY2UsIHBjdCwgbikgfD4gIAogICAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHJhY2UsIHZhbHVlc19mcm9tID0gYyhwY3QsbikpIHw+IAogICAgbXV0YXRlKGF2Z19wY3RfYmxhY2sgPSB3ZWlnaHRlZC5tZWFuKHBjdF9CbGFjaywgbl9CbGFjayksCiAgICAgICAgICAgZGlmZl9mcm9tX21lYW4gPSBwY3RfQmxhY2sgLSBhdmdfcGN0X2JsYWNrLAogICAgICAgICAgIG9jYyA9IGZjdF9yZW9yZGVyKG9jYywgZGlmZl9mcm9tX21lYW4pLAogICAgICAgICAgIHRvdCA9IHN1bShuX0JsYWNrLCBuX1doaXRlKSwKICAgICAgICAgICBjaSA9IDE5NiAqIHNxcnQoKChuX0JsYWNrIC8gdG90KSAqICgxIC0gKG5fQmxhY2sgLyB0b3QpKSkgLyB0b3QpKQpgYGAKYGBge3IgZXZhbCA9IEZ9CmFjc19vY2NfZmlnIDwtIGFjc19vY2MgJT4lIAogICAgZ2dwbG90KGFlcyh4ID0gcGN0X0JsYWNrLCB5ID0gb2NjLCBjb2xvciA9IGRpZmZfZnJvbV9tZWFuKSkgKwogICAgZ2VvbV9wb2ludChzaXplID0gMykgKyAKICAgIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQgPSBhdmdfcGN0X2JsYWNrKSwgbGluZXR5cGUgPSAyKSArIAogICAgc2NhbGVfY29sb3JfdmlyaWRpcygpICsgCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAnbm9uZScsCiAgICAgICAgICAgcGxvdC50aXRsZS5wb3NpdGlvbiA9ICJwbG90IiwgCiAgICBwbG90LmNhcHRpb24ucG9zaXRpb24gPSAicGxvdCIsCiAgICBwbG90Lm1hcmdpbiA9IG1hcmdpbihyPTI1LCBsPTI1LCB0PTI1LCBiPTEwKQogICAgKSArIAogICAgbGFicygKICAgICAgICB0aXRsZSA9ICdQZXJjZW50IEFmcmljYW4gQW1lcmljYW4gYnkgRW1wbG95bWVudCBTZWN0b3InLCAKICAgICAgICBzdWJ0aXRsZSA9ICdHcm91cGVkIGJ5IG92ZXJhbGwgRW1wbG95bWVudCBDYXRlZ29yeS4gRG90dGVkIGxpbmUgaXMgb3ZlcmFsbCBwZXJjZW50IG9mIHBvcHVsYXRpb24nLAogICAgICAgIHggPSAiUGVyY2VudCBBZnJpY2FuIEFtZXJpY2FuIiwKICAgICAgICB5ID0gIkVtcGxveW1lbnQgU2VjdG9yIiwKICAgICAgICBjb2xvciA9ICdEaWZmZXJlbmNlIGZyb20gb3ZlcmFsbCBwZXJjZW50JwogICAgICAgIAogICAgKSAKYWNzX29jY19maWcKYGBgCmBgYHtyIGV2YWwgPSBGfQphY3Nfb2NjXzIgPC0gYWNzX29jY19wY3QgfD4gCiAgICBtdXRhdGUob2NjID0gbGFiZWxsZWQ6OnRvX2NoYXJhY3RlcihPQ0MyMDEwKSwgIAogICAgICAgICAgICNyYWNlID0gbGFiZWxsZWQ6OnRvX2ZhY3RvcihSQUNFKQogICAgICAgICAgIHJhY2UgPSBjYXNlX3doZW4oUkFDRSA9PSAxIH4gJ1doaXRlJywgUkFDRSA9PSAyIH4gJ0JsYWNrJywgVFJVRSB+ICdPdGhlcicpCiAgICApIHw+CiAgICB1bmdyb3VwKCkgfD4gCiAgICBtdXRhdGUoCiAgICAgICAgb2NjID0gY2FzZV93aGVuKG9jYyA9PSAnUG9zdGFsIFNlcnZpY2UgTWFpbCBTb3J0ZXJzLCBQcm9jZXNzb3JzLCBhbmQgUHJvY2Vzc2luZyBNYWNoaW5lIE9wZXJhdG9ycycgfiAiUG9zdGFsIFNlcnZpY2UgTWFpbCBTb3J0ZXJzIGFuZCBQcm9jZXNzb3JzIiwKICAgICAgICAgICAgICAgICAgICAgICAgb2NjID09ICJGYXJtZXJzLCBSYW5jaGVycywgYW5kIE90aGVyIEFncmljdWx0dXJhbCBNYW5hZ2VycyIgfiAiRmFybWVycyBhbmQgUmFuY2hlcnMiLAogICAgICAgICAgICAgICAgICAgICAgICBvY2MgPT0gIlNlY3VyaXR5IEd1YXJkcyBhbmQgR2FtaW5nIFN1cnZlaWxsYW5jZSBPZmZpY2VycyIgfiAiU2VjdXJpdHkgR3VhcmRzIiwKICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IG9jYykpIHw+IAogICAgc2VsZWN0KG9jYywgcmFjZSwgbiwgdG90YWwsIHBjdCkgfD4gCiAgICBjb3VudChvY2MsIHJhY2UsIHd0ID0gbikgfD4gCiAgICBhZGRfY291bnQob2NjLCB3dCA9IG4sIG5hbWUgPSAndG90YWwnKSB8PiAKICAgIG11dGF0ZShwY3QgPSAxMDAqbi90b3RhbCkgfD4gCiAgICBmaWx0ZXIocmFjZSAhPSAnT3RoZXInKSB8PiAKICAgICNhZGRfY291bnQocmFjZSwgd3QgPSBuLCBuYW1lID0gJ3Rlc3QnKSB8PiAKICAgICMgIGZpbHRlcihyYWNlIDwgMykgfD4gCiAgICAjICBtdXRhdGUocmFjZSA9IGNhc2Vfd2hlbihSQUNFID09IDEgfiAnV2hpdGUnLCBUUlVFIH4gJ0JsYWNrJykpfD4gCiAgICBzZWxlY3Qob2NjLCByYWNlLCBwY3QsIG4pIHw+ICAKICAgIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSByYWNlLCB2YWx1ZXNfZnJvbSA9IGMocGN0LG4pKSB8PiAKICAgIG11dGF0ZShhdmdfcGN0X2JsYWNrID0gd2VpZ2h0ZWQubWVhbihwY3RfQmxhY2ssIG5fQmxhY2spLAogICAgICAgICAgIGRpZmZfZnJvbV9tZWFuID0gcGN0X0JsYWNrIC0gYXZnX3BjdF9ibGFjaywKICAgICAgICAgICBvY2MgPSBmY3RfcmVvcmRlcihvY2MsIGRpZmZfZnJvbV9tZWFuKSwKICAgICAgICAgICB0b3QgPSBzdW0obl9CbGFjaywgbl9XaGl0ZSksCiAgICAgICAgICAgY2kgPSAxOTYgKiBzcXJ0KCgobl9CbGFjayAvIHRvdCkgKiAoMSAtIChuX0JsYWNrIC8gdG90KSkpIC8gdG90KSkgJT4lIG11dGF0ZSh0eXBlID0gY2FzZV93aGVuKGRpZmZfZnJvbV9tZWFuIDwgMCB+ICdMb3cnLCBUUlVFIH4gJ0hpZ2gnKSkgfD4gZ3JvdXBfYnkodHlwZSkgJT4lIAogICAgc2xpY2VfbWluKGRlc2MoYWJzKGRpZmZfZnJvbV9tZWFuKSksIG49IDgpICU+JQogICAgdW5ncm91cCgpCgphY3Nfb2NjX2ZpZ18yIDwtIGFjc19vY2NfMiAlPiUgCiAgICBnZ3Bsb3QoYWVzKHggPSBwY3RfQmxhY2ssIHkgPSBvY2MsIGNvbG9yID0gZGlmZl9mcm9tX21lYW4pKSArCiAgICBnZW9tX3BvaW50KHNpemUgPSAzKSArIAogICAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdCA9IGF2Z19wY3RfYmxhY2spLCBsaW5ldHlwZSA9IDIpICsgCiAgICBzY2FsZV9jb2xvcl92aXJpZGlzKCkgKyAKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICdub25lJywKICAgICAgICAgICBwbG90LnRpdGxlLnBvc2l0aW9uID0gInBsb3QiLCAjIE5FVyBwYXJhbWV0ZXIuIEFwcGx5IGZvciBzdWJ0aXRsZSB0b28uCiAgICBwbG90LmNhcHRpb24ucG9zaXRpb24gPSAicGxvdCIsCiAgICBwbG90Lm1hcmdpbiA9IG1hcmdpbihyPTI1LCBsPTI1LCB0PTI1LCBiPTI1KQogICAgKSArIAogICAgbGFicygKICAgICAgICB0aXRsZSA9ICdUb3AgOCBIaWdoZXN0IGFuZCBMb3dlc3QgSm9icyBieSBBZnJpY2FuIEFtZXJpY2FuIHJlcHJlc2VudGF0aW9uJywgCiAgICAgICAgc3VidGl0bGUgPSAnR3JvdXBlZCBieSBzcGVjaWZpYyBlbXBsb3ltZW50IGNsYXNzaWZpY2F0aW9uLCBub3Qgb3ZlcmFsbCBzZWN0b3InLAogICAgICAgIHggPSAiUGVyY2VudCBBZnJpY2FuIEFtZXJpY2FuIiwKICAgICAgICB5ID0gIkVtcGxveW1lbnQgUm9sZSIsCiAgICAgICAgY29sb3IgPSAnRGlmZmVyZW5jZSBmcm9tIG92ZXJhbGwgcGVyY2VudCcKICAgICAgICAKICAgICkgKyBmYWNldF9mcmVlKHR5cGUgfiAuKQphY3Nfb2NjX2ZpZ18yIysgY29vcmRfZmxpcCgpCmBgYApgYGB7ciBldmFsID0gRn0KY29tYmluZWRfb2NjIDwtIGFjc19vY2NfZmlnIC8gYWNzX29jY19maWdfMiArIHBsb3RfbGF5b3V0KGhlaWdodHMgPSBjKDEuNSwxKSkgKyBwbG90X2Fubm90YXRpb24odGhlbWUgPSB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAnbm9uZScsIHBsb3QubWFyZ2luID0gbWFyZ2luKGIgPSAxMCkpLCBjYXB0aW9uID0gJ01hZGUgYnkgRWxpemFiZXRoIEdvb2R3aW4gfCAyMDEwIE9DQ1NDT1JFLCAyMDE1LTIwMTkgQUNTLCBJUFVNUyBVU0EnKQpnZ3NhdmUoJ29yaWdpbmFsLUdPT0RXSU4ucGRmJywgcGxvdCA9IGNvbWJpbmVkX29jYywgZHBpID0gNDAwLCBoZWlnaHQgPSAxMCwgd2lkdGggPSA4KQojZ2dzYXZlKCdvcmlnaW5hbC1HT09EV0lOLnBuZycsIHBsb3QgPSBjb21iaW5lZF9vY2MsIGRwaSA9IDQwMCwgaGVpZ2h0ID0gMTAsIHdpZHRoID0gOCkKYGBgCgo=