library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(tidyr)
library(readr)
library(readxl)
library(httr)
library(purrr)
library(stringi)
library(tibble)
# library(gt)
# library(gtsummary)
source('utils.R')

Download data

github_link <- 'https://raw.githubusercontent.com/covidclinical/Phase1.1AggregateDataPerSite/master/'
demo_link <- paste0(github_link, 'Demographics_persite_fakeID.csv')
diag_link <- paste0(github_link, 'Diagnoses_persite_fakeID.csv')

temp_file_1 <- temp_file_2 <- tempfile(fileext = ".csv")
req <- GET(demo_link, 
          # authenticate using GITHUB_PAT
           authenticate(Sys.getenv("GITHUB_PAT"), ""),
          # write result to disk
           write_disk(path = temp_file_1))
demo_all <- read_csv(temp_file_1)
unlink(temp_file_1)

req <- GET(diag_link, 
           authenticate(Sys.getenv("GITHUB_PAT"), ""),
           write_disk(path = temp_file_2))
diag_all <- read_csv(temp_file_2)
unlink(temp_file_2)

Notes: - num_patients_ever_severe_icd1: number of patients having the icd code and ever being severe - num_patients_never_severe_icd1: number of patients having the icd code and never being severe - num_patients_ever_severe_icd0: number of patients not having the icd code and ever being severe - num_patients_never_severe_icd0: number of patients not having the icd code and never being severe

Read in local files

site_country <- read_csv('data/SiteID_Map_Non_Pediatric_3digit_toshare.csv') %>% 
  select(- Peds.only) %>% 
  mutate(Country = case_when(
    Country == 'USA' ~ Country,
    TRUE ~ stringr::str_to_title(Country)))
## 
## ── Column specification ────────────────────────────────────────────────────────
## cols(
##   Country = col_character(),
##   SiteID.new = col_character(),
##   Peds.only = col_character()
## )
neuro_icds_10 <- read_excel('data/2020-09-10_neuro-icd10.xlsx') %>% 
  rename('icd' = `ICD-10`)

neuro_icds_9 <- readxl::read_excel('data/neuroicd10to9withdescript.xlsx') %>% 
  left_join(neuro_icds_10 %>% select(`Neurological Disease Category`, icd), 
            by = c('ICD10_CODE' = 'icd')) %>% 
  # select(- c(ICD9_CODE, ICD9_DESCRIPTION, ICD10_CODE)) %>% 
  rename('icd' = ICD9_THREE_DIGIT) %>% 
  filter(!is.na(icd)) %>% # ignore ICD10 code G46 and G65 not mapped to any ICD_9 code
  {.}

neuro_icds_9 %>% 
  distinct(icd, ICD10_CODE) %>% 
  count(icd) %>%
  filter(n > 1)
## # A tibble: 4 x 2
##   icd       n
##   <chr> <int>
## 1 437       2
## 2 780       3
## 3 781       3
## 4 V41       2

`

Manual grouping of four ICD-9 codes

For the two codes with non-specific description (780 and 781), we can include (in the Methods, Figure legend or supplementary material) the descriptions of all subcodes for each. See link here http://dbmi-ncats-test01.dbmi.pitt.edu/webclient/: no login required, and also the link below each code. I added the disease groups in parentheses for these four codes. The only group that is not consistent with the grouping based on ICD10 codes is vision/smell/taste. (For ICD10 codes, we separate vision and neuropathy, the latter of which includes smell and taste). V41 Problems with special senses and other special functions (vision/smell/taste) 437 Other and ill-defined cerebrovascular disease (vascular) 780 General symptoms (Other) https://icd.codes/icd9cm/780 781 Symptoms involving nervous and musculoskeletal systems (Other) https://icd.codes/icd9cm/781

phecode_icd9 <- read_csv('data/phecode_icd9_rolled.csv') %>% 
  select(icd = ICD9, icd9_desc = `ICD9 String`)
## 
## ── Column specification ────────────────────────────────────────────────────────
## cols(
##   ICD9 = col_character(),
##   `ICD9 String` = col_character(),
##   PheCode = col_character(),
##   Phenotype = col_character(),
##   `Excl. Phecodes` = col_character(),
##   `Excl. Phenotypes` = col_character(),
##   Rollup = col_double(),
##   Leaf = col_double()
## )
neuro_icds_9 <- neuro_icds_9 %>% 
  left_join(phecode_icd9, by = 'icd')

neuro_icds_9 %>% filter(icd %in% c('V41', '780', '781', '437'))
## # A tibble: 19 x 7
##    icd   ICD9_CODE ICD9_DESCRIPTION ICD10_CODE ICD10_DESCRIPTI… `Neurological D…
##    <chr> <chr>     <chr>            <chr>      <chr>            <chr>           
##  1 437   437.7     Transient globa… G45        Transient cereb… Vascular        
##  2 780   780.79    Other malaise a… G93        Other disorders… Other           
##  3 V41   V41.0     Problems with s… H54        Blindness and l… Vision          
##  4 437   437.0     Cerebral athero… I67        Other cerebrova… Vascular        
##  5 437   437.1     Other generaliz… I67        Other cerebrova… Vascular        
##  6 437   437.2     Hypertensive en… I67        Other cerebrova… Vascular        
##  7 437   437.3     Cerebral aneury… I67        Other cerebrova… Vascular        
##  8 437   437.4     Cerebral arteri… I67        Other cerebrova… Vascular        
##  9 437   437.5     Moyamoya disease I67        Other cerebrova… Vascular        
## 10 437   437.6     Nonpyogenic thr… I67        Other cerebrova… Vascular        
## 11 437   437.8     Other ill-defin… I67        Other cerebrova… Vascular        
## 12 437   437.9     Unspecified cer… I67        Other cerebrova… Vascular        
## 13 781   781.3     Lack of coordin… R27        Other lack of c… Coordination    
## 14 780   780.93    Memory loss      R41        Other symptoms … Consciousness   
## 15 780   780.97    Altered mental … R41        Other symptoms … Consciousness   
## 16 781   781.8     Neurologic negl… R41        Other symptoms … Consciousness   
## 17 780   780.4     Dizziness and g… R42        Dizziness and g… Dizziness       
## 18 781   781.1     Disturbances of… R43        Disturbances of… Neuropathy      
## 19 V41   V41.5     Problems with s… R43        Disturbances of… Neuropathy      
## # … with 1 more variable: icd9_desc <chr>
neuro_icds_9 <- neuro_icds_9 %>% 
  within(., icd9_desc[icd == 'V41'] <- 'Problems with special senses and other special functions') %>% 
  within(., `Neurological Disease Category`[icd == 'V41'] <- 'Vision/smell/taste') %>%
  within(., icd9_desc[icd == '781'] <- 'Symptoms involving nervous and musculoskeletal systems') %>% 
  within(., `Neurological Disease Category`[icd == '781'] <- 'Neuropathy') %>% # and Consciousness
  within(., icd9_desc[icd == '437'] <- 'Other and ill-defined cerebrovascular disease') %>%
  within(., icd9_desc[icd == '780'] <- 'General symptoms') %>%
  within(., `Neurological Disease Category`[icd == '780'] <- 'Other') %>%
  distinct() %>% 
  select(`Neurological Disease Category`, icd, icd9_desc) %>% 
  distinct() %>% 
  arrange(icd)

neuro_icds_9 %>% 
  write_csv('results/icd9_tab.csv')

Notes:

“-99” indicate masked small numbers (for obfuscation) and “-999” indicate missing, mismatches, not applicable, etc.

Descriptive statistics

Diagnoses_persite_fakeID.csv has 45 unique siteid’s. Demographics_persite_fakeID.csv has 45 unique siteid’s.

Mold data frames

demo_ana <- demo_all %>% 
  filter(race == 'all', age_group == 'all', sex == 'all') %>% 
  # left_join(site_to_country, by = 'siteid') %>% 
  select(- c(sex, age_group, race)) %>% 
  bind_rows(# Compute patients_all for SITE734 manually
    demo_all %>% 
      filter(siteid == 'SITE734', race == 'all', age_group == 'all') %>% 
      group_by(siteid) %>% 
      summarise(across(c(num_patients_all, num_patients_ever_severe), .fns = sum),
                .groups = 'drop')
  ) %>% 
  mutate(num_patients_never_severe = num_patients_all - num_patients_ever_severe)


split_patient_type <- function(x) {
  temp <- strsplit(sub('(^[^_]+_[^_]+)_(.*)$', '\\1 \\2', stri_reverse(x)), ' ')
  map(temp, stri_reverse)
}

diag_ana <- diag_all %>% 
  mutate(
    num_patients_never_severe_before_admission = num_patients_all_before_admission - num_patients_ever_severe_before_admission,
    num_patients_never_severe_since_admission = num_patients_all_since_admission - num_patients_ever_severe_since_admission,
  ) %>% 
  pivot_longer(cols = starts_with('num'), names_to = 'patient_type', values_to = 'count') %>% 
  bind_cols(
    split_patient_type(.[['patient_type']]) %>% 
      do.call(rbind, .) %>% 
      as.data.frame() %>% 
      `colnames<-`(c('time', 'severe'))
  ) %>% 
  mutate(severe = recode(severe, 
                         num_patients_all = 'num_patients_icd',
                         num_patients_ever_severe= 'num_patients_ever_severe_icd1',
                         num_patients_never_severe= 'num_patients_never_severe_icd1'),
         time = recode(time,
                       before_admission = 'Before admission',
                       since_admission = 'After admission')) %>% 
  rename('icd' = icd_code_3chars) %>% 
  select(- patient_type) %>% 
  drop_na() %>% 
  left_join(site_country, by = c('siteid' = 'SiteID.new')) %>% 
  {.}

diag_icd_10 <- diag_ana %>% 
  filter(icd_version == 10) %>%
  select(- icd_version) %>% 
  pivot_wider(names_from = severe, values_from = count) %>%
  right_join(neuro_icds_10, by = 'icd') %>% 
  distinct() %>% 
  left_join(demo_ana, by = 'siteid') %>% 
  mutate(full_icd = paste0(`ICD-10 Description`, ' (', icd, ')'),
         num_patients_never_severe_icd0 = num_patients_never_severe - num_patients_never_severe_icd1,
         num_patients_ever_severe_icd0 = num_patients_ever_severe - num_patients_ever_severe_icd1,
  ) %>%
  drop_na(num_patients_icd) %>% 
  {.}

diag_icd_9 <- diag_ana %>% 
  filter(icd_version == 9) %>%
  select(- icd_version) %>% 
  pivot_wider(names_from = severe, values_from = count) %>%
  right_join(neuro_icds_9, by = 'icd') %>% 
  distinct() %>% 
  left_join(demo_ana, by = 'siteid') %>% 
  mutate(full_icd = paste0(icd9_desc, ' (', icd, ')'),
         num_patients_never_severe_icd0 = num_patients_never_severe - num_patients_never_severe_icd1,
         num_patients_ever_severe_icd0 = num_patients_ever_severe - num_patients_ever_severe_icd1,
  ) %>%
  drop_na(num_patients_icd) %>% 
  {.}

40 sites with icd-10 code. 11 sites have icd-9.

country_sum_icd10 <- diag_icd_10 %>% 
  select(siteid, Country, num_patients_all) %>% 
  distinct() %>% 
  group_by(Country) %>% 
  summarise(all_pats_country = sum(num_patients_all), .groups = 'drop')

country_sum_icd9 <- diag_icd_9 %>% 
  select(siteid, Country, num_patients_all) %>% 
  distinct() %>% 
  group_by(Country) %>% 
  summarise(all_pats_country = sum(num_patients_all), .groups = 'drop')

diag_icd_10 <- diag_icd_10 %>% 
  merge(country_sum_icd10, by = 'Country')

diag_icd_9 <- diag_icd_9 %>% 
  merge(country_sum_icd9, by = 'Country')

Write data out to .Rdata

save(demo_ana, diag_icd_10, diag_icd_9, file = 'data/processed-data.Rdata')

Quality checks

Check if ‘all’ equals to sum of the rest

age_group_check <- demo_all %>% 
  filter(sex == 'all', race == 'all', age_group != 'all') %>% 
  group_by(siteid) %>% 
  summarise(age_group_sum = sum(num_patients_all), .groups = 'drop') %>% 
  right_join(demo_ana) %>% 
  mutate(mismatches = num_patients_all - age_group_sum) %>% 
  # filter(abs(mismatches) != 0) %>% 
  select(-contains('severe')) %>% 
  arrange(desc(abs(mismatches))) %>% 
  {.}
## Joining, by = "siteid"
race_check <- demo_all %>% 
  filter(sex == 'all', race != 'all', age_group == 'all') %>% 
  group_by(siteid) %>% 
  summarise(race_sum = sum(num_patients_all), .groups = 'drop') %>% 
  right_join(demo_ana) %>% 
  mutate(mismatches = num_patients_all - race_sum) %>% 
  # filter(abs(mismatches) != 0) %>% 
  select(-contains('severe')) %>% 
  arrange(desc(abs(mismatches))) %>% 
  {.}
## Joining, by = "siteid"
sex_check <- demo_all %>% 
  filter(race == 'all', sex != 'all', age_group == 'all') %>% 
  group_by(siteid) %>% 
  summarise(sex_sum = sum(num_patients_all), .groups = 'drop') %>% 
  right_join(demo_ana) %>% 
  mutate(mismatches = num_patients_all - sex_sum) %>% 
  # filter(mismatches != 0) %>% 
  select(-contains('severe')) %>% 
  arrange(desc(abs(mismatches))) %>% 
  {.}
## Joining, by = "siteid"
demo_check <- demo_ana %>% 
  mutate(perc_severe = num_patients_ever_severe/num_patients_all)

write_csv(race_check, 'data/race_check.csv')
write_csv(sex_check, 'data/sex_check.csv')
write_csv(age_group_check, 'data/age_group_check.csv')

Generate characteristics table

sum_sum <- sym(paste('N =', sum(demo_ana$num_patients_all)))
sites_no_age <- demo_all %>% 
  filter(siteid %in% (age_group_check %>% filter(is.na(age_group_sum)) %>% pull(siteid)), 
         age_group != 'all', sex != 'all', race != 'all') %>% 
  group_by(siteid, age_group) %>% 
  summarise(size = sum(num_patients_all), .groups = 'drop') 

age_group_desc <- demo_all %>% 
  filter(sex == 'all', race == 'all', age_group != 'all') %>% 
  group_by(age_group, siteid) %>% 
  summarise(size = sum(num_patients_all, na.rm = T), .groups = 'drop') %>% 
  bind_rows(sites_no_age) %>% 
  pivot_wider(names_from = age_group, values_from = size, values_fill = list(size = 0)) %>% 
  mutate(sum_age_cols = rowSums(.[, -1])) %>% 
  right_join(age_group_check) %>% 
  replace(is.na(.), 0) %>% 
  mutate(unknown_other = other + num_patients_all - sum_age_cols) %>% 
  {.}
## Joining, by = "siteid"
age_comp <- age_group_desc  %>% 
  column_to_rownames('siteid') %>% 
  rename('80to100' = `80plus`) %>% 
  select(contains('to')) %>% 
  apply(., 1, cumsum) %>% 
  t()
median_age(age_comp[2,])
## [1] 67.94007
age_med_df <- data.frame(median_age = apply(age_comp, 1, median_age)) %>% 
  rownames_to_column('siteid')

age_group_desc <- age_group_desc %>% 
  left_join(age_med_df)
## Joining, by = "siteid"
sites_no_race <- demo_all %>% 
  filter(siteid %in% (race_check %>% filter(is.na(race_sum)) %>% pull(siteid)), 
  age_group != 'all', sex != 'all', race != 'all') %>% 
  group_by(siteid, race) %>% 
  summarise(size = sum(num_patients_all), .groups = 'drop') 

sites_no_race %>% 
  left_join(site_country, by = c('siteid' = 'SiteID.new'))
## # A tibble: 10 x 4
##    siteid  race             size Country  
##    <chr>   <chr>           <dbl> <chr>    
##  1 SITE116 asian             160 Singapore
##  2 SITE116 other             105 Singapore
##  3 SITE116 white              13 Singapore
##  4 SITE185 other              78 Germany  
##  5 SITE434 black               0 Italy    
##  6 SITE434 hispanic_latino     0 Italy    
##  7 SITE434 other             587 Italy    
##  8 SITE434 white               0 Italy    
##  9 SITE926 other             945 Italy    
## 10 SITE974 white              62 Italy
race_desc <- demo_all %>% 
  filter(sex == 'all', race != 'all', age_group == 'all') %>% 
  group_by(race, siteid) %>% 
  summarise(size = sum(num_patients_all, na.rm = T), .groups = 'drop') %>% 
  bind_rows(sites_no_race) %>% 
  pivot_wider(names_from = race, values_from = size, values_fill = list(size = 0)) %>% 
  mutate(sum_race_cols = rowSums(.[, -1])) %>% 
  right_join(race_check) %>% 
  replace(is.na(.), 0) %>% 
  mutate(unknown_other_race = other + num_patients_all - sum_race_cols) %>% 
  {.}
## Joining, by = "siteid"
sex_desc <- demo_all %>% 
  filter(sex != 'all', race == 'all', age_group == 'all') %>% 
  group_by(sex, siteid) %>% 
  summarise(size = sum(num_patients_all, na.rm = T), .groups = 'drop') %>% 
  pivot_wider(names_from = sex, values_from = size, values_fill = list(size = 0)) %>% 
  mutate(sum_sex_cols = rowSums(.[, -1])) %>% 
  right_join(sex_check) %>% 
  replace(is.na(.), 0) %>% 
  mutate(unknown_other = other + num_patients_all - sex_sum) %>% 
  {.}
## Joining, by = "siteid"
# race_desc <- demo_all %>%
#   filter(sex == 'all', race != 'all', age_group == 'all') %>% 
#   group_by(race, siteid) %>% 
#   summarise(size = sum(num_patients_all, na.rm = T), .groups = 'drop') %>% 
#   pivot_wider(names_from = race, values_from = size, values_fill = list(size = 0)) %>% 
#   mutate(sum_race_cols = rowSums(.[, -1])) %>% 
#   right_join(race_check) %>% 
#   replace(is.na(.), 0) %>% 
#   mutate(unknown_other_race = other + num_patients_all - race_sum) %>% 
#   {.}

demo_desc <- left_join(sex_desc, age_group_desc, by = 'siteid', suffix = c("_sex", "_age_group")) %>% 
  left_join(race_desc, by = 'siteid') %>% 
  # Reduce(function(...) left_join(..., by = 'siteid', , '_race')), 
  #                   list(, race_desc), ) %>% 
  select(- c(contains('um'), contains('mismatches'))) %>% 
  right_join(demo_ana, ., by = 'siteid') %>% 
  left_join(site_country, by = c('siteid' = 'SiteID.new')) %>% 
  select(siteid, Country, everything())


demo_perc <- demo_desc %>% 
  # mutate(across(- contains('num'), ~ .x/.data$num_patients_all))
  mutate_at(vars(- num_patients_all, - siteid, - Country, - median_age),
            list(~ round(. / .data$num_patients_all * 100, 1)))

demo_desc %>% write_csv('results/demo_prelim.csv')
demo_perc %>% write_csv('results/demo_perc_prelim.csv')
# some NAs are because there are just not a row for with that value
sex_age <- demo_all %>% 
  filter(age_group != 'all', sex != 'all', race != 'all') %>% 
  group_by(siteid, age_group, sex) %>% 
  summarise(size = sum(num_patients_all), .groups = 'drop') %>% 
  pivot_wider(names_from = c(sex, age_group), values_from = size, values_fill = list(size = 0)) %>% 
  mutate(sum_age_cols = rowSums(.[, -1])) %>% 
  right_join(age_group_check) %>% 
  replace(is.na(.), 0) %>% 
  mutate(unknown_other = female_other + male_other + other_other + num_patients_all - sum_age_cols) %>% 
  select(- c(contains('um'), contains('mismatches'))) %>% 
  right_join(demo_ana, ., by = 'siteid') %>% 
  left_join(site_country, by = c('siteid' = 'SiteID.new')) %>% 
  select(siteid, Country, everything()) %>% 
  {.}
## Joining, by = "siteid"
# sex_desc <- demo_all %>% 
#   filter(sex != 'all', race == 'all', age_group == 'all') %>% 
#   group_by(sex) %>% 
#   summarise(!!sum_sum := sum(num_patients_all), .groups = 'drop') %>% 
#   mutate(category = 'Sex') %>% 
#   rename('Characteristics' = sex)
# 
# race_desc <- demo_all %>% 
#   filter(sex == 'all', race != 'all', age_group == 'all') %>% 
#   group_by(race) %>% 
#   summarise(!!sum_sum := sum(num_patients_all), .groups = 'drop') %>% 
#   mutate(category = 'Race/Ethnicity') %>% 
#   rename('Characteristics' = race)
# 
# bind_rows(age_group_desc, sex_desc, race_desc) %>% 
#   group_by(category) %>% 
#   gt() %>% 
#   tab_footnote(
#     footnote = "Obfuscation at each site may affect the total counts.",
#     locations = cells_column_labels(
#       columns = 2)
#   ) %>% 
#   {.}

Check NAs:

na_diag <- diag_ana %>% 
  select(siteid, icd, contains('num')) %>% 
  filter(rowSums(is.na(.)) > 0)
# va_vec <- c("VA1", "VA10", "VA12", "VA15", "VA16", "VA17", "VA19", "VA2", "VA20", "VA21", "VA22", "VA23", "VA4", "VA5", "VA6", "VA7", "VA8", "VA9")
# sites <- c("APHP", "ASSTPAVIA", "BIDMC", "C2WF", "FRBDX", "H12O", "HPG23", "ICSM1", "KUMC", "MCWCTSI", "MGB", "MUSC", "NUH", "NWU", "POLIMI", "RIVHS", "SLHN", "UCLA", "UKER", "UKFR", "UKY", "UMICH", "UMM", "UNICZ", "UPenn", "UPITT", "UTSW", "VA")
# 
# obfuscation_df <- googlesheets4::read_sheet(
#   # 'https://docs.google.com/spreadsheets/d/1VhtKIbzEOeGFG1Iw27D_gq_l3eJpKn0LiJr_f_hFdwc/edit?ts=5ec17a70#gid=0',
#   'https://docs.google.com/spreadsheets/d/1Xl9juDBXt86P3xQtsoTaBl2zPl1BIiAG9DI3Rotyqp8/edit#gid=212461777',
#   skip = 1,
#   col_names = c('SLHN', 'site_name', 'contact_name', 'contact_email', 'city', 'country',
#                 'low_count_threshold', 'small_count_rows_deleted', 'blur_range', 'notes',
#                 'irb_statement')) %>%
#   filter(SLHN != 'FICHOS') %>%
#   mutate(low_count_threshold = low_count_threshold %>%
#            replace(low_count_threshold == '<=10', '<11') %>%
#            replace(low_count_threshold == '<=5', '<6'))
# 
# library(ggplot2)

# obfuscation_df %>%
#   ggplot(aes(x = low_count_threshold)) +
#   geom_bar()
# obfus_1 <- obfuscation_df %>%
#   filter(SLHN %in% sites)
# table(obfus_1$low_count_threshold)
# sum(table(obfus_1$low_count_threshold))
LS0tCnRpdGxlOiAiUmVhZCBpbiBhbmQgcHJvY2VzcyBkYXRhIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRoZW1lOiBsdW1lbgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IGZhbHNlCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICBoaWdobGlnaHQ6IHRhbmdvCmtuaXQ6IChmdW5jdGlvbihpbnB1dEZpbGUsIGVuY29kaW5nKSB7CiAgcm1hcmtkb3duOjpyZW5kZXIoaW5wdXRGaWxlLCBlbmNvZGluZyA9IGVuY29kaW5nLCBvdXRwdXRfZGlyID0gImRvY3MiKSB9KQotLS0KCmBgYHtyfQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KHJlYWRyKQpsaWJyYXJ5KHJlYWR4bCkKbGlicmFyeShodHRyKQpsaWJyYXJ5KHB1cnJyKQpsaWJyYXJ5KHN0cmluZ2kpCmxpYnJhcnkodGliYmxlKQojIGxpYnJhcnkoZ3QpCiMgbGlicmFyeShndHN1bW1hcnkpCnNvdXJjZSgndXRpbHMuUicpCmBgYAoKIyMgRG93bmxvYWQgZGF0YQoKYGBge3IgbWVzc2FnZT1GQUxTRX0KZ2l0aHViX2xpbmsgPC0gJ2h0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9jb3ZpZGNsaW5pY2FsL1BoYXNlMS4xQWdncmVnYXRlRGF0YVBlclNpdGUvbWFzdGVyLycKZGVtb19saW5rIDwtIHBhc3RlMChnaXRodWJfbGluaywgJ0RlbW9ncmFwaGljc19wZXJzaXRlX2Zha2VJRC5jc3YnKQpkaWFnX2xpbmsgPC0gcGFzdGUwKGdpdGh1Yl9saW5rLCAnRGlhZ25vc2VzX3BlcnNpdGVfZmFrZUlELmNzdicpCgp0ZW1wX2ZpbGVfMSA8LSB0ZW1wX2ZpbGVfMiA8LSB0ZW1wZmlsZShmaWxlZXh0ID0gIi5jc3YiKQpyZXEgPC0gR0VUKGRlbW9fbGluaywgCiAgICAgICAgICAjIGF1dGhlbnRpY2F0ZSB1c2luZyBHSVRIVUJfUEFUCiAgICAgICAgICAgYXV0aGVudGljYXRlKFN5cy5nZXRlbnYoIkdJVEhVQl9QQVQiKSwgIiIpLAogICAgICAgICAgIyB3cml0ZSByZXN1bHQgdG8gZGlzawogICAgICAgICAgIHdyaXRlX2Rpc2socGF0aCA9IHRlbXBfZmlsZV8xKSkKZGVtb19hbGwgPC0gcmVhZF9jc3YodGVtcF9maWxlXzEpCnVubGluayh0ZW1wX2ZpbGVfMSkKCnJlcSA8LSBHRVQoZGlhZ19saW5rLCAKICAgICAgICAgICBhdXRoZW50aWNhdGUoU3lzLmdldGVudigiR0lUSFVCX1BBVCIpLCAiIiksCiAgICAgICAgICAgd3JpdGVfZGlzayhwYXRoID0gdGVtcF9maWxlXzIpKQpkaWFnX2FsbCA8LSByZWFkX2Nzdih0ZW1wX2ZpbGVfMikKdW5saW5rKHRlbXBfZmlsZV8yKQpgYGAKCk5vdGVzOgotIGBudW1fcGF0aWVudHNfZXZlcl9zZXZlcmVfaWNkMWA6IG51bWJlciBvZiBwYXRpZW50cyBoYXZpbmcgdGhlIGljZCBjb2RlIGFuZCBldmVyIGJlaW5nIHNldmVyZQotIGBudW1fcGF0aWVudHNfbmV2ZXJfc2V2ZXJlX2ljZDFgOiBudW1iZXIgb2YgcGF0aWVudHMgaGF2aW5nIHRoZSBpY2QgY29kZSBhbmQgbmV2ZXIgYmVpbmcgc2V2ZXJlCi0gYG51bV9wYXRpZW50c19ldmVyX3NldmVyZV9pY2QwYDogbnVtYmVyIG9mIHBhdGllbnRzIG5vdCBoYXZpbmcgdGhlIGljZCBjb2RlIGFuZCBldmVyIGJlaW5nIHNldmVyZQotIGBudW1fcGF0aWVudHNfbmV2ZXJfc2V2ZXJlX2ljZDBgOiBudW1iZXIgb2YgcGF0aWVudHMgbm90IGhhdmluZyB0aGUgaWNkIGNvZGUgYW5kIG5ldmVyIGJlaW5nIHNldmVyZQoKIyMgUmVhZCBpbiBsb2NhbCBmaWxlcwoKYGBge3J9CnNpdGVfY291bnRyeSA8LSByZWFkX2NzdignZGF0YS9TaXRlSURfTWFwX05vbl9QZWRpYXRyaWNfM2RpZ2l0X3Rvc2hhcmUuY3N2JykgJT4lIAogIHNlbGVjdCgtIFBlZHMub25seSkgJT4lIAogIG11dGF0ZShDb3VudHJ5ID0gY2FzZV93aGVuKAogICAgQ291bnRyeSA9PSAnVVNBJyB+IENvdW50cnksCiAgICBUUlVFIH4gc3RyaW5ncjo6c3RyX3RvX3RpdGxlKENvdW50cnkpKSkKYGBgCgo8IS0tIFR3byByb3dzIGhhdmUgY291bnRyeSBTSU5HQVBPUkVfU1BBSU4gYmVjYXVzZSB0aGVyZSBpcyBvbmx5IG9uZSBzaXRlIGluIGVhY2ggb25lIG9mIHRoZSBjb3VudHJpZXMuIC0tPgo8IS0tIElmIHRoaXMgd2VyZSBub3QgY29tYmluZWQ6IGRhdGEgY291bGQgYmUga25vd24gdGhlIHNwZWNpZmljIHNpdGUuIC0tPgoKPCEtLSBTSVRFNjYwIHdhcyBtYXBwZWQgdG8gYm90aCBVUyBhbmQgRnJhbmNlPyAtLT4KPCEtLSBTSVRFMzA5IHdhcyBtYXBwZWQgdG8gYm90aCBVUyBhbmQgSXRhbHk/IC0tPgpgYGB7cn0KbmV1cm9faWNkc18xMCA8LSByZWFkX2V4Y2VsKCdkYXRhLzIwMjAtMDktMTBfbmV1cm8taWNkMTAueGxzeCcpICU+JSAKICByZW5hbWUoJ2ljZCcgPSBgSUNELTEwYCkKCm5ldXJvX2ljZHNfOSA8LSByZWFkeGw6OnJlYWRfZXhjZWwoJ2RhdGEvbmV1cm9pY2QxMHRvOXdpdGhkZXNjcmlwdC54bHN4JykgJT4lIAogIGxlZnRfam9pbihuZXVyb19pY2RzXzEwICU+JSBzZWxlY3QoYE5ldXJvbG9naWNhbCBEaXNlYXNlIENhdGVnb3J5YCwgaWNkKSwgCiAgICAgICAgICAgIGJ5ID0gYygnSUNEMTBfQ09ERScgPSAnaWNkJykpICU+JSAKICAjIHNlbGVjdCgtIGMoSUNEOV9DT0RFLCBJQ0Q5X0RFU0NSSVBUSU9OLCBJQ0QxMF9DT0RFKSkgJT4lIAogIHJlbmFtZSgnaWNkJyA9IElDRDlfVEhSRUVfRElHSVQpICU+JSAKICBmaWx0ZXIoIWlzLm5hKGljZCkpICU+JSAjIGlnbm9yZSBJQ0QxMCBjb2RlIEc0NiBhbmQgRzY1IG5vdCBtYXBwZWQgdG8gYW55IElDRF85IGNvZGUKICB7Ln0KCm5ldXJvX2ljZHNfOSAlPiUgCiAgZGlzdGluY3QoaWNkLCBJQ0QxMF9DT0RFKSAlPiUgCiAgY291bnQoaWNkKSAlPiUKICBmaWx0ZXIobiA+IDEpCmBgYApgCgoKIyMgTWFudWFsIGdyb3VwaW5nIG9mIGZvdXIgSUNELTkgY29kZXMKCkZvciB0aGUgdHdvIGNvZGVzIHdpdGggbm9uLXNwZWNpZmljIGRlc2NyaXB0aW9uICg3ODAgYW5kIDc4MSksIHdlIGNhbiBpbmNsdWRlIChpbiB0aGUgTWV0aG9kcywgRmlndXJlIGxlZ2VuZCBvciBzdXBwbGVtZW50YXJ5IG1hdGVyaWFsKSB0aGUgZGVzY3JpcHRpb25zIG9mIGFsbCBzdWJjb2RlcyBmb3IgZWFjaC4KU2VlIGxpbmsgaGVyZSA8aHR0cDovL2RibWktbmNhdHMtdGVzdDAxLmRibWkucGl0dC5lZHUvd2ViY2xpZW50Lz46IG5vIGxvZ2luIHJlcXVpcmVkLCBhbmQgYWxzbyB0aGUgbGluayBiZWxvdyBlYWNoIGNvZGUuCkkgYWRkZWQgdGhlIGRpc2Vhc2UgZ3JvdXBzIGluIHBhcmVudGhlc2VzIGZvciB0aGVzZSBmb3VyIGNvZGVzLgpUaGUgb25seSBncm91cCB0aGF0IGlzIG5vdCBjb25zaXN0ZW50IHdpdGggdGhlIGdyb3VwaW5nIGJhc2VkIG9uIElDRDEwIGNvZGVzIGlzIHZpc2lvbi9zbWVsbC90YXN0ZS4KKEZvciBJQ0QxMCBjb2Rlcywgd2Ugc2VwYXJhdGUgdmlzaW9uIGFuZCBuZXVyb3BhdGh5LCB0aGUgbGF0dGVyIG9mIHdoaWNoIGluY2x1ZGVzIHNtZWxsIGFuZCB0YXN0ZSkuClY0MSBQcm9ibGVtcyB3aXRoIHNwZWNpYWwgc2Vuc2VzIGFuZCBvdGhlciBzcGVjaWFsIGZ1bmN0aW9ucyAodmlzaW9uL3NtZWxsL3Rhc3RlKQo0MzcgT3RoZXIgYW5kIGlsbC1kZWZpbmVkIGNlcmVicm92YXNjdWxhciBkaXNlYXNlICh2YXNjdWxhcikKNzgwIEdlbmVyYWwgc3ltcHRvbXMgKE90aGVyKQpodHRwczovL2ljZC5jb2Rlcy9pY2Q5Y20vNzgwCjc4MSBTeW1wdG9tcyBpbnZvbHZpbmcgbmVydm91cyBhbmQgbXVzY3Vsb3NrZWxldGFsIHN5c3RlbXMgKE90aGVyKQpodHRwczovL2ljZC5jb2Rlcy9pY2Q5Y20vNzgxCgoKYGBge3J9CnBoZWNvZGVfaWNkOSA8LSByZWFkX2NzdignZGF0YS9waGVjb2RlX2ljZDlfcm9sbGVkLmNzdicpICU+JSAKICBzZWxlY3QoaWNkID0gSUNEOSwgaWNkOV9kZXNjID0gYElDRDkgU3RyaW5nYCkKCm5ldXJvX2ljZHNfOSA8LSBuZXVyb19pY2RzXzkgJT4lIAogIGxlZnRfam9pbihwaGVjb2RlX2ljZDksIGJ5ID0gJ2ljZCcpCgpuZXVyb19pY2RzXzkgJT4lIGZpbHRlcihpY2QgJWluJSBjKCdWNDEnLCAnNzgwJywgJzc4MScsICc0MzcnKSkKCm5ldXJvX2ljZHNfOSA8LSBuZXVyb19pY2RzXzkgJT4lIAogIHdpdGhpbiguLCBpY2Q5X2Rlc2NbaWNkID09ICdWNDEnXSA8LSAnUHJvYmxlbXMgd2l0aCBzcGVjaWFsIHNlbnNlcyBhbmQgb3RoZXIgc3BlY2lhbCBmdW5jdGlvbnMnKSAlPiUgCiAgd2l0aGluKC4sIGBOZXVyb2xvZ2ljYWwgRGlzZWFzZSBDYXRlZ29yeWBbaWNkID09ICdWNDEnXSA8LSAnVmlzaW9uL3NtZWxsL3Rhc3RlJykgJT4lCiAgd2l0aGluKC4sIGljZDlfZGVzY1tpY2QgPT0gJzc4MSddIDwtICdTeW1wdG9tcyBpbnZvbHZpbmcgbmVydm91cyBhbmQgbXVzY3Vsb3NrZWxldGFsIHN5c3RlbXMnKSAlPiUgCiAgd2l0aGluKC4sIGBOZXVyb2xvZ2ljYWwgRGlzZWFzZSBDYXRlZ29yeWBbaWNkID09ICc3ODEnXSA8LSAnTmV1cm9wYXRoeScpICU+JSAjIGFuZCBDb25zY2lvdXNuZXNzCiAgd2l0aGluKC4sIGljZDlfZGVzY1tpY2QgPT0gJzQzNyddIDwtICdPdGhlciBhbmQgaWxsLWRlZmluZWQgY2VyZWJyb3Zhc2N1bGFyIGRpc2Vhc2UnKSAlPiUKICB3aXRoaW4oLiwgaWNkOV9kZXNjW2ljZCA9PSAnNzgwJ10gPC0gJ0dlbmVyYWwgc3ltcHRvbXMnKSAlPiUKICB3aXRoaW4oLiwgYE5ldXJvbG9naWNhbCBEaXNlYXNlIENhdGVnb3J5YFtpY2QgPT0gJzc4MCddIDwtICdPdGhlcicpICU+JQogIGRpc3RpbmN0KCkgJT4lIAogIHNlbGVjdChgTmV1cm9sb2dpY2FsIERpc2Vhc2UgQ2F0ZWdvcnlgLCBpY2QsIGljZDlfZGVzYykgJT4lIAogIGRpc3RpbmN0KCkgJT4lIAogIGFycmFuZ2UoaWNkKQoKbmV1cm9faWNkc185ICU+JSAKICB3cml0ZV9jc3YoJ3Jlc3VsdHMvaWNkOV90YWIuY3N2JykKYGBgCgpOb3RlczogCgrigJwtOTnigJ0gaW5kaWNhdGUgbWFza2VkIHNtYWxsIG51bWJlcnMgKGZvciBvYmZ1c2NhdGlvbikgYW5kIOKAnC05OTkiIGluZGljYXRlIG1pc3NpbmcsIG1pc21hdGNoZXMsIG5vdCBhcHBsaWNhYmxlLCBldGMuCgojIERlc2NyaXB0aXZlIHN0YXRpc3RpY3MKCmBEaWFnbm9zZXNfcGVyc2l0ZV9mYWtlSUQuY3N2YCBoYXMgYHIgbGVuZ3RoKHVuaXF1ZShkaWFnX2FsbCRzaXRlaWQpKWAgdW5pcXVlIHNpdGVpZCdzLgpgRGVtb2dyYXBoaWNzX3BlcnNpdGVfZmFrZUlELmNzdmAgaGFzIGByIGxlbmd0aCh1bmlxdWUoZGVtb19hbGwkc2l0ZWlkKSlgIHVuaXF1ZSBzaXRlaWQncy4KCgojIE1vbGQgZGF0YSBmcmFtZXMKCmBgYHtyfQpkZW1vX2FuYSA8LSBkZW1vX2FsbCAlPiUgCiAgZmlsdGVyKHJhY2UgPT0gJ2FsbCcsIGFnZV9ncm91cCA9PSAnYWxsJywgc2V4ID09ICdhbGwnKSAlPiUgCiAgIyBsZWZ0X2pvaW4oc2l0ZV90b19jb3VudHJ5LCBieSA9ICdzaXRlaWQnKSAlPiUgCiAgc2VsZWN0KC0gYyhzZXgsIGFnZV9ncm91cCwgcmFjZSkpICU+JSAKICBiaW5kX3Jvd3MoIyBDb21wdXRlIHBhdGllbnRzX2FsbCBmb3IgU0lURTczNCBtYW51YWxseQogICAgZGVtb19hbGwgJT4lIAogICAgICBmaWx0ZXIoc2l0ZWlkID09ICdTSVRFNzM0JywgcmFjZSA9PSAnYWxsJywgYWdlX2dyb3VwID09ICdhbGwnKSAlPiUgCiAgICAgIGdyb3VwX2J5KHNpdGVpZCkgJT4lIAogICAgICBzdW1tYXJpc2UoYWNyb3NzKGMobnVtX3BhdGllbnRzX2FsbCwgbnVtX3BhdGllbnRzX2V2ZXJfc2V2ZXJlKSwgLmZucyA9IHN1bSksCiAgICAgICAgICAgICAgICAuZ3JvdXBzID0gJ2Ryb3AnKQogICkgJT4lIAogIG11dGF0ZShudW1fcGF0aWVudHNfbmV2ZXJfc2V2ZXJlID0gbnVtX3BhdGllbnRzX2FsbCAtIG51bV9wYXRpZW50c19ldmVyX3NldmVyZSkKCgpzcGxpdF9wYXRpZW50X3R5cGUgPC0gZnVuY3Rpb24oeCkgewogIHRlbXAgPC0gc3Ryc3BsaXQoc3ViKCcoXlteX10rX1teX10rKV8oLiopJCcsICdcXDEgXFwyJywgc3RyaV9yZXZlcnNlKHgpKSwgJyAnKQogIG1hcCh0ZW1wLCBzdHJpX3JldmVyc2UpCn0KCmRpYWdfYW5hIDwtIGRpYWdfYWxsICU+JSAKICBtdXRhdGUoCiAgICBudW1fcGF0aWVudHNfbmV2ZXJfc2V2ZXJlX2JlZm9yZV9hZG1pc3Npb24gPSBudW1fcGF0aWVudHNfYWxsX2JlZm9yZV9hZG1pc3Npb24gLSBudW1fcGF0aWVudHNfZXZlcl9zZXZlcmVfYmVmb3JlX2FkbWlzc2lvbiwKICAgIG51bV9wYXRpZW50c19uZXZlcl9zZXZlcmVfc2luY2VfYWRtaXNzaW9uID0gbnVtX3BhdGllbnRzX2FsbF9zaW5jZV9hZG1pc3Npb24gLSBudW1fcGF0aWVudHNfZXZlcl9zZXZlcmVfc2luY2VfYWRtaXNzaW9uLAogICkgJT4lIAogIHBpdm90X2xvbmdlcihjb2xzID0gc3RhcnRzX3dpdGgoJ251bScpLCBuYW1lc190byA9ICdwYXRpZW50X3R5cGUnLCB2YWx1ZXNfdG8gPSAnY291bnQnKSAlPiUgCiAgYmluZF9jb2xzKAogICAgc3BsaXRfcGF0aWVudF90eXBlKC5bWydwYXRpZW50X3R5cGUnXV0pICU+JSAKICAgICAgZG8uY2FsbChyYmluZCwgLikgJT4lIAogICAgICBhcy5kYXRhLmZyYW1lKCkgJT4lIAogICAgICBgY29sbmFtZXM8LWAoYygndGltZScsICdzZXZlcmUnKSkKICApICU+JSAKICBtdXRhdGUoc2V2ZXJlID0gcmVjb2RlKHNldmVyZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBudW1fcGF0aWVudHNfYWxsID0gJ251bV9wYXRpZW50c19pY2QnLAogICAgICAgICAgICAgICAgICAgICAgICAgbnVtX3BhdGllbnRzX2V2ZXJfc2V2ZXJlPSAnbnVtX3BhdGllbnRzX2V2ZXJfc2V2ZXJlX2ljZDEnLAogICAgICAgICAgICAgICAgICAgICAgICAgbnVtX3BhdGllbnRzX25ldmVyX3NldmVyZT0gJ251bV9wYXRpZW50c19uZXZlcl9zZXZlcmVfaWNkMScpLAogICAgICAgICB0aW1lID0gcmVjb2RlKHRpbWUsCiAgICAgICAgICAgICAgICAgICAgICAgYmVmb3JlX2FkbWlzc2lvbiA9ICdCZWZvcmUgYWRtaXNzaW9uJywKICAgICAgICAgICAgICAgICAgICAgICBzaW5jZV9hZG1pc3Npb24gPSAnQWZ0ZXIgYWRtaXNzaW9uJykpICU+JSAKICByZW5hbWUoJ2ljZCcgPSBpY2RfY29kZV8zY2hhcnMpICU+JSAKICBzZWxlY3QoLSBwYXRpZW50X3R5cGUpICU+JSAKICBkcm9wX25hKCkgJT4lIAogIGxlZnRfam9pbihzaXRlX2NvdW50cnksIGJ5ID0gYygnc2l0ZWlkJyA9ICdTaXRlSUQubmV3JykpICU+JSAKICB7Ln0KCmRpYWdfaWNkXzEwIDwtIGRpYWdfYW5hICU+JSAKICBmaWx0ZXIoaWNkX3ZlcnNpb24gPT0gMTApICU+JQogIHNlbGVjdCgtIGljZF92ZXJzaW9uKSAlPiUgCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHNldmVyZSwgdmFsdWVzX2Zyb20gPSBjb3VudCkgJT4lCiAgcmlnaHRfam9pbihuZXVyb19pY2RzXzEwLCBieSA9ICdpY2QnKSAlPiUgCiAgZGlzdGluY3QoKSAlPiUgCiAgbGVmdF9qb2luKGRlbW9fYW5hLCBieSA9ICdzaXRlaWQnKSAlPiUgCiAgbXV0YXRlKGZ1bGxfaWNkID0gcGFzdGUwKGBJQ0QtMTAgRGVzY3JpcHRpb25gLCAnICgnLCBpY2QsICcpJyksCiAgICAgICAgIG51bV9wYXRpZW50c19uZXZlcl9zZXZlcmVfaWNkMCA9IG51bV9wYXRpZW50c19uZXZlcl9zZXZlcmUgLSBudW1fcGF0aWVudHNfbmV2ZXJfc2V2ZXJlX2ljZDEsCiAgICAgICAgIG51bV9wYXRpZW50c19ldmVyX3NldmVyZV9pY2QwID0gbnVtX3BhdGllbnRzX2V2ZXJfc2V2ZXJlIC0gbnVtX3BhdGllbnRzX2V2ZXJfc2V2ZXJlX2ljZDEsCiAgKSAlPiUKICBkcm9wX25hKG51bV9wYXRpZW50c19pY2QpICU+JSAKICB7Ln0KCmRpYWdfaWNkXzkgPC0gZGlhZ19hbmEgJT4lIAogIGZpbHRlcihpY2RfdmVyc2lvbiA9PSA5KSAlPiUKICBzZWxlY3QoLSBpY2RfdmVyc2lvbikgJT4lIAogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBzZXZlcmUsIHZhbHVlc19mcm9tID0gY291bnQpICU+JQogIHJpZ2h0X2pvaW4obmV1cm9faWNkc185LCBieSA9ICdpY2QnKSAlPiUgCiAgZGlzdGluY3QoKSAlPiUgCiAgbGVmdF9qb2luKGRlbW9fYW5hLCBieSA9ICdzaXRlaWQnKSAlPiUgCiAgbXV0YXRlKGZ1bGxfaWNkID0gcGFzdGUwKGljZDlfZGVzYywgJyAoJywgaWNkLCAnKScpLAogICAgICAgICBudW1fcGF0aWVudHNfbmV2ZXJfc2V2ZXJlX2ljZDAgPSBudW1fcGF0aWVudHNfbmV2ZXJfc2V2ZXJlIC0gbnVtX3BhdGllbnRzX25ldmVyX3NldmVyZV9pY2QxLAogICAgICAgICBudW1fcGF0aWVudHNfZXZlcl9zZXZlcmVfaWNkMCA9IG51bV9wYXRpZW50c19ldmVyX3NldmVyZSAtIG51bV9wYXRpZW50c19ldmVyX3NldmVyZV9pY2QxLAogICkgJT4lCiAgZHJvcF9uYShudW1fcGF0aWVudHNfaWNkKSAlPiUgCiAgey59CmBgYAoKYHIgbGVuZ3RoKHVuaXF1ZShkaWFnX2ljZF8xMCRzaXRlaWQpKWAgc2l0ZXMgd2l0aCBpY2QtMTAgY29kZS4gCmByIGxlbmd0aCh1bmlxdWUoZGlhZ19pY2RfOSRzaXRlaWQpKWAgc2l0ZXMgaGF2ZSBpY2QtOS4KCmBgYHtyfQpjb3VudHJ5X3N1bV9pY2QxMCA8LSBkaWFnX2ljZF8xMCAlPiUgCiAgc2VsZWN0KHNpdGVpZCwgQ291bnRyeSwgbnVtX3BhdGllbnRzX2FsbCkgJT4lIAogIGRpc3RpbmN0KCkgJT4lIAogIGdyb3VwX2J5KENvdW50cnkpICU+JSAKICBzdW1tYXJpc2UoYWxsX3BhdHNfY291bnRyeSA9IHN1bShudW1fcGF0aWVudHNfYWxsKSwgLmdyb3VwcyA9ICdkcm9wJykKCmNvdW50cnlfc3VtX2ljZDkgPC0gZGlhZ19pY2RfOSAlPiUgCiAgc2VsZWN0KHNpdGVpZCwgQ291bnRyeSwgbnVtX3BhdGllbnRzX2FsbCkgJT4lIAogIGRpc3RpbmN0KCkgJT4lIAogIGdyb3VwX2J5KENvdW50cnkpICU+JSAKICBzdW1tYXJpc2UoYWxsX3BhdHNfY291bnRyeSA9IHN1bShudW1fcGF0aWVudHNfYWxsKSwgLmdyb3VwcyA9ICdkcm9wJykKCmRpYWdfaWNkXzEwIDwtIGRpYWdfaWNkXzEwICU+JSAKICBtZXJnZShjb3VudHJ5X3N1bV9pY2QxMCwgYnkgPSAnQ291bnRyeScpCgpkaWFnX2ljZF85IDwtIGRpYWdfaWNkXzkgJT4lIAogIG1lcmdlKGNvdW50cnlfc3VtX2ljZDksIGJ5ID0gJ0NvdW50cnknKQpgYGAKCiMgV3JpdGUgZGF0YSBvdXQgdG8gLlJkYXRhCgpgYGB7cn0Kc2F2ZShkZW1vX2FuYSwgZGlhZ19pY2RfMTAsIGRpYWdfaWNkXzksIGZpbGUgPSAnZGF0YS9wcm9jZXNzZWQtZGF0YS5SZGF0YScpCmBgYAoKIyBRdWFsaXR5IGNoZWNrcwoKIyMgQ2hlY2sgaWYgJ2FsbCcgZXF1YWxzIHRvIHN1bSBvZiB0aGUgcmVzdApgYGB7cn0KYWdlX2dyb3VwX2NoZWNrIDwtIGRlbW9fYWxsICU+JSAKICBmaWx0ZXIoc2V4ID09ICdhbGwnLCByYWNlID09ICdhbGwnLCBhZ2VfZ3JvdXAgIT0gJ2FsbCcpICU+JSAKICBncm91cF9ieShzaXRlaWQpICU+JSAKICBzdW1tYXJpc2UoYWdlX2dyb3VwX3N1bSA9IHN1bShudW1fcGF0aWVudHNfYWxsKSwgLmdyb3VwcyA9ICdkcm9wJykgJT4lIAogIHJpZ2h0X2pvaW4oZGVtb19hbmEpICU+JSAKICBtdXRhdGUobWlzbWF0Y2hlcyA9IG51bV9wYXRpZW50c19hbGwgLSBhZ2VfZ3JvdXBfc3VtKSAlPiUgCiAgIyBmaWx0ZXIoYWJzKG1pc21hdGNoZXMpICE9IDApICU+JSAKICBzZWxlY3QoLWNvbnRhaW5zKCdzZXZlcmUnKSkgJT4lIAogIGFycmFuZ2UoZGVzYyhhYnMobWlzbWF0Y2hlcykpKSAlPiUgCiAgey59CgpyYWNlX2NoZWNrIDwtIGRlbW9fYWxsICU+JSAKICBmaWx0ZXIoc2V4ID09ICdhbGwnLCByYWNlICE9ICdhbGwnLCBhZ2VfZ3JvdXAgPT0gJ2FsbCcpICU+JSAKICBncm91cF9ieShzaXRlaWQpICU+JSAKICBzdW1tYXJpc2UocmFjZV9zdW0gPSBzdW0obnVtX3BhdGllbnRzX2FsbCksIC5ncm91cHMgPSAnZHJvcCcpICU+JSAKICByaWdodF9qb2luKGRlbW9fYW5hKSAlPiUgCiAgbXV0YXRlKG1pc21hdGNoZXMgPSBudW1fcGF0aWVudHNfYWxsIC0gcmFjZV9zdW0pICU+JSAKICAjIGZpbHRlcihhYnMobWlzbWF0Y2hlcykgIT0gMCkgJT4lIAogIHNlbGVjdCgtY29udGFpbnMoJ3NldmVyZScpKSAlPiUgCiAgYXJyYW5nZShkZXNjKGFicyhtaXNtYXRjaGVzKSkpICU+JSAKICB7Ln0KCnNleF9jaGVjayA8LSBkZW1vX2FsbCAlPiUgCiAgZmlsdGVyKHJhY2UgPT0gJ2FsbCcsIHNleCAhPSAnYWxsJywgYWdlX2dyb3VwID09ICdhbGwnKSAlPiUgCiAgZ3JvdXBfYnkoc2l0ZWlkKSAlPiUgCiAgc3VtbWFyaXNlKHNleF9zdW0gPSBzdW0obnVtX3BhdGllbnRzX2FsbCksIC5ncm91cHMgPSAnZHJvcCcpICU+JSAKICByaWdodF9qb2luKGRlbW9fYW5hKSAlPiUgCiAgbXV0YXRlKG1pc21hdGNoZXMgPSBudW1fcGF0aWVudHNfYWxsIC0gc2V4X3N1bSkgJT4lIAogICMgZmlsdGVyKG1pc21hdGNoZXMgIT0gMCkgJT4lIAogIHNlbGVjdCgtY29udGFpbnMoJ3NldmVyZScpKSAlPiUgCiAgYXJyYW5nZShkZXNjKGFicyhtaXNtYXRjaGVzKSkpICU+JSAKICB7Ln0KCmRlbW9fY2hlY2sgPC0gZGVtb19hbmEgJT4lIAogIG11dGF0ZShwZXJjX3NldmVyZSA9IG51bV9wYXRpZW50c19ldmVyX3NldmVyZS9udW1fcGF0aWVudHNfYWxsKQoKd3JpdGVfY3N2KHJhY2VfY2hlY2ssICdkYXRhL3JhY2VfY2hlY2suY3N2JykKd3JpdGVfY3N2KHNleF9jaGVjaywgJ2RhdGEvc2V4X2NoZWNrLmNzdicpCndyaXRlX2NzdihhZ2VfZ3JvdXBfY2hlY2ssICdkYXRhL2FnZV9ncm91cF9jaGVjay5jc3YnKQpgYGAKCiMjIEdlbmVyYXRlIGNoYXJhY3RlcmlzdGljcyB0YWJsZQoKYGBge3J9CnN1bV9zdW0gPC0gc3ltKHBhc3RlKCdOID0nLCBzdW0oZGVtb19hbmEkbnVtX3BhdGllbnRzX2FsbCkpKQpgYGAKCmBgYHtyfQpzaXRlc19ub19hZ2UgPC0gZGVtb19hbGwgJT4lIAogIGZpbHRlcihzaXRlaWQgJWluJSAoYWdlX2dyb3VwX2NoZWNrICU+JSBmaWx0ZXIoaXMubmEoYWdlX2dyb3VwX3N1bSkpICU+JSBwdWxsKHNpdGVpZCkpLCAKICAgICAgICAgYWdlX2dyb3VwICE9ICdhbGwnLCBzZXggIT0gJ2FsbCcsIHJhY2UgIT0gJ2FsbCcpICU+JSAKICBncm91cF9ieShzaXRlaWQsIGFnZV9ncm91cCkgJT4lIAogIHN1bW1hcmlzZShzaXplID0gc3VtKG51bV9wYXRpZW50c19hbGwpLCAuZ3JvdXBzID0gJ2Ryb3AnKSAKCmFnZV9ncm91cF9kZXNjIDwtIGRlbW9fYWxsICU+JSAKICBmaWx0ZXIoc2V4ID09ICdhbGwnLCByYWNlID09ICdhbGwnLCBhZ2VfZ3JvdXAgIT0gJ2FsbCcpICU+JSAKICBncm91cF9ieShhZ2VfZ3JvdXAsIHNpdGVpZCkgJT4lIAogIHN1bW1hcmlzZShzaXplID0gc3VtKG51bV9wYXRpZW50c19hbGwsIG5hLnJtID0gVCksIC5ncm91cHMgPSAnZHJvcCcpICU+JSAKICBiaW5kX3Jvd3Moc2l0ZXNfbm9fYWdlKSAlPiUgCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGFnZV9ncm91cCwgdmFsdWVzX2Zyb20gPSBzaXplLCB2YWx1ZXNfZmlsbCA9IGxpc3Qoc2l6ZSA9IDApKSAlPiUgCiAgbXV0YXRlKHN1bV9hZ2VfY29scyA9IHJvd1N1bXMoLlssIC0xXSkpICU+JSAKICByaWdodF9qb2luKGFnZV9ncm91cF9jaGVjaykgJT4lIAogIHJlcGxhY2UoaXMubmEoLiksIDApICU+JSAKICBtdXRhdGUodW5rbm93bl9vdGhlciA9IG90aGVyICsgbnVtX3BhdGllbnRzX2FsbCAtIHN1bV9hZ2VfY29scykgJT4lIAogIHsufQoKYWdlX2NvbXAgPC0gYWdlX2dyb3VwX2Rlc2MgICU+JSAKICBjb2x1bW5fdG9fcm93bmFtZXMoJ3NpdGVpZCcpICU+JSAKICByZW5hbWUoJzgwdG8xMDAnID0gYDgwcGx1c2ApICU+JSAKICBzZWxlY3QoY29udGFpbnMoJ3RvJykpICU+JSAKICBhcHBseSguLCAxLCBjdW1zdW0pICU+JSAKICB0KCkKbWVkaWFuX2FnZShhZ2VfY29tcFsyLF0pCmFnZV9tZWRfZGYgPC0gZGF0YS5mcmFtZShtZWRpYW5fYWdlID0gYXBwbHkoYWdlX2NvbXAsIDEsIG1lZGlhbl9hZ2UpKSAlPiUgCiAgcm93bmFtZXNfdG9fY29sdW1uKCdzaXRlaWQnKQoKYWdlX2dyb3VwX2Rlc2MgPC0gYWdlX2dyb3VwX2Rlc2MgJT4lIAogIGxlZnRfam9pbihhZ2VfbWVkX2RmKQpgYGAKCmBgYHtyfQpzaXRlc19ub19yYWNlIDwtIGRlbW9fYWxsICU+JSAKICBmaWx0ZXIoc2l0ZWlkICVpbiUgKHJhY2VfY2hlY2sgJT4lIGZpbHRlcihpcy5uYShyYWNlX3N1bSkpICU+JSBwdWxsKHNpdGVpZCkpLCAKICBhZ2VfZ3JvdXAgIT0gJ2FsbCcsIHNleCAhPSAnYWxsJywgcmFjZSAhPSAnYWxsJykgJT4lIAogIGdyb3VwX2J5KHNpdGVpZCwgcmFjZSkgJT4lIAogIHN1bW1hcmlzZShzaXplID0gc3VtKG51bV9wYXRpZW50c19hbGwpLCAuZ3JvdXBzID0gJ2Ryb3AnKSAKCnNpdGVzX25vX3JhY2UgJT4lIAogIGxlZnRfam9pbihzaXRlX2NvdW50cnksIGJ5ID0gYygnc2l0ZWlkJyA9ICdTaXRlSUQubmV3JykpCgpyYWNlX2Rlc2MgPC0gZGVtb19hbGwgJT4lIAogIGZpbHRlcihzZXggPT0gJ2FsbCcsIHJhY2UgIT0gJ2FsbCcsIGFnZV9ncm91cCA9PSAnYWxsJykgJT4lIAogIGdyb3VwX2J5KHJhY2UsIHNpdGVpZCkgJT4lIAogIHN1bW1hcmlzZShzaXplID0gc3VtKG51bV9wYXRpZW50c19hbGwsIG5hLnJtID0gVCksIC5ncm91cHMgPSAnZHJvcCcpICU+JSAKICBiaW5kX3Jvd3Moc2l0ZXNfbm9fcmFjZSkgJT4lIAogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSByYWNlLCB2YWx1ZXNfZnJvbSA9IHNpemUsIHZhbHVlc19maWxsID0gbGlzdChzaXplID0gMCkpICU+JSAKICBtdXRhdGUoc3VtX3JhY2VfY29scyA9IHJvd1N1bXMoLlssIC0xXSkpICU+JSAKICByaWdodF9qb2luKHJhY2VfY2hlY2spICU+JSAKICByZXBsYWNlKGlzLm5hKC4pLCAwKSAlPiUgCiAgbXV0YXRlKHVua25vd25fb3RoZXJfcmFjZSA9IG90aGVyICsgbnVtX3BhdGllbnRzX2FsbCAtIHN1bV9yYWNlX2NvbHMpICU+JSAKICB7Ln0KYGBgCgoKYGBge3J9CnNleF9kZXNjIDwtIGRlbW9fYWxsICU+JSAKICBmaWx0ZXIoc2V4ICE9ICdhbGwnLCByYWNlID09ICdhbGwnLCBhZ2VfZ3JvdXAgPT0gJ2FsbCcpICU+JSAKICBncm91cF9ieShzZXgsIHNpdGVpZCkgJT4lIAogIHN1bW1hcmlzZShzaXplID0gc3VtKG51bV9wYXRpZW50c19hbGwsIG5hLnJtID0gVCksIC5ncm91cHMgPSAnZHJvcCcpICU+JSAKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gc2V4LCB2YWx1ZXNfZnJvbSA9IHNpemUsIHZhbHVlc19maWxsID0gbGlzdChzaXplID0gMCkpICU+JSAKICBtdXRhdGUoc3VtX3NleF9jb2xzID0gcm93U3VtcyguWywgLTFdKSkgJT4lIAogIHJpZ2h0X2pvaW4oc2V4X2NoZWNrKSAlPiUgCiAgcmVwbGFjZShpcy5uYSguKSwgMCkgJT4lIAogIG11dGF0ZSh1bmtub3duX290aGVyID0gb3RoZXIgKyBudW1fcGF0aWVudHNfYWxsIC0gc2V4X3N1bSkgJT4lIAogIHsufQoKIyByYWNlX2Rlc2MgPC0gZGVtb19hbGwgJT4lCiMgICBmaWx0ZXIoc2V4ID09ICdhbGwnLCByYWNlICE9ICdhbGwnLCBhZ2VfZ3JvdXAgPT0gJ2FsbCcpICU+JSAKIyAgIGdyb3VwX2J5KHJhY2UsIHNpdGVpZCkgJT4lIAojICAgc3VtbWFyaXNlKHNpemUgPSBzdW0obnVtX3BhdGllbnRzX2FsbCwgbmEucm0gPSBUKSwgLmdyb3VwcyA9ICdkcm9wJykgJT4lIAojICAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHJhY2UsIHZhbHVlc19mcm9tID0gc2l6ZSwgdmFsdWVzX2ZpbGwgPSBsaXN0KHNpemUgPSAwKSkgJT4lIAojICAgbXV0YXRlKHN1bV9yYWNlX2NvbHMgPSByb3dTdW1zKC5bLCAtMV0pKSAlPiUgCiMgICByaWdodF9qb2luKHJhY2VfY2hlY2spICU+JSAKIyAgIHJlcGxhY2UoaXMubmEoLiksIDApICU+JSAKIyAgIG11dGF0ZSh1bmtub3duX290aGVyX3JhY2UgPSBvdGhlciArIG51bV9wYXRpZW50c19hbGwgLSByYWNlX3N1bSkgJT4lIAojICAgey59CgpkZW1vX2Rlc2MgPC0gbGVmdF9qb2luKHNleF9kZXNjLCBhZ2VfZ3JvdXBfZGVzYywgYnkgPSAnc2l0ZWlkJywgc3VmZml4ID0gYygiX3NleCIsICJfYWdlX2dyb3VwIikpICU+JSAKICBsZWZ0X2pvaW4ocmFjZV9kZXNjLCBieSA9ICdzaXRlaWQnKSAlPiUgCiAgIyBSZWR1Y2UoZnVuY3Rpb24oLi4uKSBsZWZ0X2pvaW4oLi4uLCBieSA9ICdzaXRlaWQnLCAsICdfcmFjZScpKSwgCiAgIyAgICAgICAgICAgICAgICAgICBsaXN0KCwgcmFjZV9kZXNjKSwgKSAlPiUgCiAgc2VsZWN0KC0gYyhjb250YWlucygndW0nKSwgY29udGFpbnMoJ21pc21hdGNoZXMnKSkpICU+JSAKICByaWdodF9qb2luKGRlbW9fYW5hLCAuLCBieSA9ICdzaXRlaWQnKSAlPiUgCiAgbGVmdF9qb2luKHNpdGVfY291bnRyeSwgYnkgPSBjKCdzaXRlaWQnID0gJ1NpdGVJRC5uZXcnKSkgJT4lIAogIHNlbGVjdChzaXRlaWQsIENvdW50cnksIGV2ZXJ5dGhpbmcoKSkKCgpkZW1vX3BlcmMgPC0gZGVtb19kZXNjICU+JSAKICAjIG11dGF0ZShhY3Jvc3MoLSBjb250YWlucygnbnVtJyksIH4gLngvLmRhdGEkbnVtX3BhdGllbnRzX2FsbCkpCiAgbXV0YXRlX2F0KHZhcnMoLSBudW1fcGF0aWVudHNfYWxsLCAtIHNpdGVpZCwgLSBDb3VudHJ5LCAtIG1lZGlhbl9hZ2UpLAogICAgICAgICAgICBsaXN0KH4gcm91bmQoLiAvIC5kYXRhJG51bV9wYXRpZW50c19hbGwgKiAxMDAsIDEpKSkKCmRlbW9fZGVzYyAlPiUgd3JpdGVfY3N2KCdyZXN1bHRzL2RlbW9fcHJlbGltLmNzdicpCmRlbW9fcGVyYyAlPiUgd3JpdGVfY3N2KCdyZXN1bHRzL2RlbW9fcGVyY19wcmVsaW0uY3N2JykKIyBzb21lIE5BcyBhcmUgYmVjYXVzZSB0aGVyZSBhcmUganVzdCBub3QgYSByb3cgZm9yIHdpdGggdGhhdCB2YWx1ZQpgYGAKCgpgYGB7cn0Kc2V4X2FnZSA8LSBkZW1vX2FsbCAlPiUgCiAgZmlsdGVyKGFnZV9ncm91cCAhPSAnYWxsJywgc2V4ICE9ICdhbGwnLCByYWNlICE9ICdhbGwnKSAlPiUgCiAgZ3JvdXBfYnkoc2l0ZWlkLCBhZ2VfZ3JvdXAsIHNleCkgJT4lIAogIHN1bW1hcmlzZShzaXplID0gc3VtKG51bV9wYXRpZW50c19hbGwpLCAuZ3JvdXBzID0gJ2Ryb3AnKSAlPiUgCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGMoc2V4LCBhZ2VfZ3JvdXApLCB2YWx1ZXNfZnJvbSA9IHNpemUsIHZhbHVlc19maWxsID0gbGlzdChzaXplID0gMCkpICU+JSAKICBtdXRhdGUoc3VtX2FnZV9jb2xzID0gcm93U3VtcyguWywgLTFdKSkgJT4lIAogIHJpZ2h0X2pvaW4oYWdlX2dyb3VwX2NoZWNrKSAlPiUgCiAgcmVwbGFjZShpcy5uYSguKSwgMCkgJT4lIAogIG11dGF0ZSh1bmtub3duX290aGVyID0gZmVtYWxlX290aGVyICsgbWFsZV9vdGhlciArIG90aGVyX290aGVyICsgbnVtX3BhdGllbnRzX2FsbCAtIHN1bV9hZ2VfY29scykgJT4lIAogIHNlbGVjdCgtIGMoY29udGFpbnMoJ3VtJyksIGNvbnRhaW5zKCdtaXNtYXRjaGVzJykpKSAlPiUgCiAgcmlnaHRfam9pbihkZW1vX2FuYSwgLiwgYnkgPSAnc2l0ZWlkJykgJT4lIAogIGxlZnRfam9pbihzaXRlX2NvdW50cnksIGJ5ID0gYygnc2l0ZWlkJyA9ICdTaXRlSUQubmV3JykpICU+JSAKICBzZWxlY3Qoc2l0ZWlkLCBDb3VudHJ5LCBldmVyeXRoaW5nKCkpICU+JSAKICB7Ln0KYGBgCgoKYGBge3J9CiMgc2V4X2Rlc2MgPC0gZGVtb19hbGwgJT4lIAojICAgZmlsdGVyKHNleCAhPSAnYWxsJywgcmFjZSA9PSAnYWxsJywgYWdlX2dyb3VwID09ICdhbGwnKSAlPiUgCiMgICBncm91cF9ieShzZXgpICU+JSAKIyAgIHN1bW1hcmlzZSghIXN1bV9zdW0gOj0gc3VtKG51bV9wYXRpZW50c19hbGwpLCAuZ3JvdXBzID0gJ2Ryb3AnKSAlPiUgCiMgICBtdXRhdGUoY2F0ZWdvcnkgPSAnU2V4JykgJT4lIAojICAgcmVuYW1lKCdDaGFyYWN0ZXJpc3RpY3MnID0gc2V4KQojIAojIHJhY2VfZGVzYyA8LSBkZW1vX2FsbCAlPiUgCiMgICBmaWx0ZXIoc2V4ID09ICdhbGwnLCByYWNlICE9ICdhbGwnLCBhZ2VfZ3JvdXAgPT0gJ2FsbCcpICU+JSAKIyAgIGdyb3VwX2J5KHJhY2UpICU+JSAKIyAgIHN1bW1hcmlzZSghIXN1bV9zdW0gOj0gc3VtKG51bV9wYXRpZW50c19hbGwpLCAuZ3JvdXBzID0gJ2Ryb3AnKSAlPiUgCiMgICBtdXRhdGUoY2F0ZWdvcnkgPSAnUmFjZS9FdGhuaWNpdHknKSAlPiUgCiMgICByZW5hbWUoJ0NoYXJhY3RlcmlzdGljcycgPSByYWNlKQojIAojIGJpbmRfcm93cyhhZ2VfZ3JvdXBfZGVzYywgc2V4X2Rlc2MsIHJhY2VfZGVzYykgJT4lIAojICAgZ3JvdXBfYnkoY2F0ZWdvcnkpICU+JSAKIyAgIGd0KCkgJT4lIAojICAgdGFiX2Zvb3Rub3RlKAojICAgICBmb290bm90ZSA9ICJPYmZ1c2NhdGlvbiBhdCBlYWNoIHNpdGUgbWF5IGFmZmVjdCB0aGUgdG90YWwgY291bnRzLiIsCiMgICAgIGxvY2F0aW9ucyA9IGNlbGxzX2NvbHVtbl9sYWJlbHMoCiMgICAgICAgY29sdW1ucyA9IDIpCiMgICApICU+JSAKIyAgIHsufQpgYGAKCgpDaGVjayBOQXM6CmBgYHtyfQpuYV9kaWFnIDwtIGRpYWdfYW5hICU+JSAKICBzZWxlY3Qoc2l0ZWlkLCBpY2QsIGNvbnRhaW5zKCdudW0nKSkgJT4lIAogIGZpbHRlcihyb3dTdW1zKGlzLm5hKC4pKSA+IDApCmBgYAoKPCEtLSAjIE1vcmUgcXVhbGl0eSBjaGVjazogLS0+CgpgYGB7ciBpbmNsdWRlPUZBTFNFLCBldmFsPUZBTFNFfQojIGNoZWNrX2FsbCA8LSBkZW1vX2FsbCAlPiUgCiMgICBmaWx0ZXIocmFjZSA9PSAnYWxsJykgCgojIGNoZWNrIHdoZXRoZXIgdGhlIHJvd3Mgd2l0aCByYWNlID0gYWxsIGFyZSBhY3R1YWwgc3VtIG9mIHRoZSByZXN0CiMgY2hlY2tfcmFjZSA8LSBkZW1vX2FsbCAlPiUKIyAgIGZpbHRlcihyYWNlICE9ICdhbGwnKSAlPiUKIyAgIGdyb3VwX2J5KHNpdGVpZCwgc2V4LCBhZ2VfZ3JvdXApICU+JQojICAgc3VtbWFyaXNlKG51bV9wYXRpZW50c19zdW0gPSBzdW0obnVtX3BhdGllbnRzX2FsbCkpICU+JQojICAgbGVmdF9qb2luKGNoZWNrX2FsbCkKCgojIGNoZWNrX25hIDwtIGNoZWNrX3JhY2UgJT4lIAojICAgZmlsdGVyKGlzLm5hKG51bV9wYXRpZW50c19hbGwpKSAlPiUgCiMgICBwdWxsKHNpdGVpZCkgJT4lIAojICAgdW5pcXVlKCkKCiMgbGVuZ3RoKHVuaXF1ZShkaWFnX2FsbCRzaXRlaWQpKQpjaGVja19kaWFnIDwtIGRpYWdfYWxsICU+JSAKICBmaWx0ZXIoIWlzLm5hKG51bV9wYXRpZW50c19ldmVyX3NldmVyZV9pY2QxKSkgJT4lIAogIG11dGF0ZShudW1fcGF0aWVudHNfaWNkID0gbnVtX3BhdGllbnRzX2V2ZXJfc2V2ZXJlX2ljZDEgKyBudW1fcGF0aWVudHNfbmV2ZXJfc2V2ZXJlX2ljZDEsCiAgICAgICAgIGljZCA9IGdzdWIoJ2ljZDonLCAnJywgaWNkKSkgJT4lIAogIGdyb3VwX2J5KHNpdGVpZCkgJT4lCiAgc3VtbWFyaXNlKG1heF9pY2RfcGF0c19hbGwgPSBtYXgobnVtX3BhdGllbnRzX2ljZCwgbmEucm0gPSBUKSwgLmdyb3VwcyA9ICdkcm9wJykgJT4lCiAgbGVmdF9qb2luKGRlbW9fYW5hKQoKY2hlY2tfZGlhZyAlPiUgCiAgZmlsdGVyKG1heF9pY2RfcGF0c19hbGwgPiBudW1fcGF0aWVudHNfYWxsKQpgYGAKCgpgYGB7ciBpbmNsdWRlPUZBTFNFLCBldmFsPUZBTFNFfQojIGNvdW50cnlfcGF0cyA8LSBkZW1vX2FuYSAlPiUKIyAgIGdyb3VwX2J5KENvdW50cnkpICU+JQojICAgc3VtbWFyaXNlKHRvdGFsX3BhdGllbnRzX3Blcl9jb3VudHJ5ID0gc3VtKG51bV9wYXRpZW50c19hbGwpLCAuZ3JvdXBzID0gJ2Ryb3AnKQoKIyBkb3RfZGF0IDwtIGRpYWdfYW5hICU+JQojICAgZ3JvdXBfYnkoc2l0ZWlkLCB0aW1lLCBpY2QpICU+JQojICAgc3VtbWFyaXNlKHBhdHNfdGltZV9pY2RfY3RyeSA9IHN1bShudW1fcGF0aWVudHNfaWNkKSwgLmdyb3VwcyA9ICdkcm9wJykgJT4lCiMgICBsZWZ0X2pvaW4oc2l0ZV9wYXRzLCBieSA9ICdzaXRlaWQnKSAlPiUKIyAgIG11dGF0ZShwZXJjZW50X3BhdHMgPSBwYXRzX3RpbWVfaWNkX2N0cnkvbnVtX3BhdGllbnRzX2FsbCkKIyAKIyBkb3RfZGF0ICU+JQojICAgZ2dwbG90KGFlcyh5ID0gZm9yY2F0czo6ZmN0X3Jlb3JkZXIoaWNkLCBwZXJjZW50X3BhdHMpLCB4ID0gcGVyY2VudF9wYXRzLCBncm91cCA9IGljZCkpICsKIyAgICAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSB0aW1lKSkgKwojICAgICBnZW9tX2xpbmUoKSArCiMgICAgIGZhY2V0X2dyaWQocm93cyA9IHZhcnMoc2l0ZWlkKSkgKwojICAgIyBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDEsIDAuMSksIGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoYWNjdXJhY3kgPSAxKSkgKwojICAgc2NhbGVfY29sb3JfY2FydG9fZChwYWxldHRlID0gNCkgKwojICAgbGFicyh4ID0gTlVMTCwgeSA9ICdQZXJjZW50IHBhdGllbnRzJykKICAgIApgYGAKCgpgYGB7cn0KIyB2YV92ZWMgPC0gYygiVkExIiwgIlZBMTAiLCAiVkExMiIsICJWQTE1IiwgIlZBMTYiLCAiVkExNyIsICJWQTE5IiwgIlZBMiIsICJWQTIwIiwgIlZBMjEiLCAiVkEyMiIsICJWQTIzIiwgIlZBNCIsICJWQTUiLCAiVkE2IiwgIlZBNyIsICJWQTgiLCAiVkE5IikKIyBzaXRlcyA8LSBjKCJBUEhQIiwgIkFTU1RQQVZJQSIsICJCSURNQyIsICJDMldGIiwgIkZSQkRYIiwgIkgxMk8iLCAiSFBHMjMiLCAiSUNTTTEiLCAiS1VNQyIsICJNQ1dDVFNJIiwgIk1HQiIsICJNVVNDIiwgIk5VSCIsICJOV1UiLCAiUE9MSU1JIiwgIlJJVkhTIiwgIlNMSE4iLCAiVUNMQSIsICJVS0VSIiwgIlVLRlIiLCAiVUtZIiwgIlVNSUNIIiwgIlVNTSIsICJVTklDWiIsICJVUGVubiIsICJVUElUVCIsICJVVFNXIiwgIlZBIikKIyAKIyBvYmZ1c2NhdGlvbl9kZiA8LSBnb29nbGVzaGVldHM0OjpyZWFkX3NoZWV0KAojICAgIyAnaHR0cHM6Ly9kb2NzLmdvb2dsZS5jb20vc3ByZWFkc2hlZXRzL2QvMVZodEtJYnpFT2VHRkcxSXcyN0RfZ3FfbDNlSnBLbjBMaUpyX2ZfaEZkd2MvZWRpdD90cz01ZWMxN2E3MCNnaWQ9MCcsCiMgICAnaHR0cHM6Ly9kb2NzLmdvb2dsZS5jb20vc3ByZWFkc2hlZXRzL2QvMVhsOWp1REJYdDg2UDN4UXRzb1RhQmwyelBsMUJJaUFHOURJM1JvdHlxcDgvZWRpdCNnaWQ9MjEyNDYxNzc3JywKIyAgIHNraXAgPSAxLAojICAgY29sX25hbWVzID0gYygnU0xITicsICdzaXRlX25hbWUnLCAnY29udGFjdF9uYW1lJywgJ2NvbnRhY3RfZW1haWwnLCAnY2l0eScsICdjb3VudHJ5JywKIyAgICAgICAgICAgICAgICAgJ2xvd19jb3VudF90aHJlc2hvbGQnLCAnc21hbGxfY291bnRfcm93c19kZWxldGVkJywgJ2JsdXJfcmFuZ2UnLCAnbm90ZXMnLAojICAgICAgICAgICAgICAgICAnaXJiX3N0YXRlbWVudCcpKSAlPiUKIyAgIGZpbHRlcihTTEhOICE9ICdGSUNIT1MnKSAlPiUKIyAgIG11dGF0ZShsb3dfY291bnRfdGhyZXNob2xkID0gbG93X2NvdW50X3RocmVzaG9sZCAlPiUKIyAgICAgICAgICAgIHJlcGxhY2UobG93X2NvdW50X3RocmVzaG9sZCA9PSAnPD0xMCcsICc8MTEnKSAlPiUKIyAgICAgICAgICAgIHJlcGxhY2UobG93X2NvdW50X3RocmVzaG9sZCA9PSAnPD01JywgJzw2JykpCiMgCiMgbGlicmFyeShnZ3Bsb3QyKQoKIyBvYmZ1c2NhdGlvbl9kZiAlPiUKIyAgIGdncGxvdChhZXMoeCA9IGxvd19jb3VudF90aHJlc2hvbGQpKSArCiMgICBnZW9tX2JhcigpCmBgYAoKYGBge3J9CiMgb2JmdXNfMSA8LSBvYmZ1c2NhdGlvbl9kZiAlPiUKIyAgIGZpbHRlcihTTEhOICVpbiUgc2l0ZXMpCiMgdGFibGUob2JmdXNfMSRsb3dfY291bnRfdGhyZXNob2xkKQojIHN1bSh0YWJsZShvYmZ1c18xJGxvd19jb3VudF90aHJlc2hvbGQpKQpgYGAKCg==