Honorees
keynotes %>%
pull(conference) %>%
table()
## .
## ISCB Fellow ISMB RECOMB
## 75 167 170
There are 412 entries and 290 unique names in the ISCB cohort.
Names sorted by the number of honors:
keynotes %>%
count(fore_name, last_name) %>%
arrange(desc(n)) %>%
DT::datatable()
Number of keynote speakers/fellows across years:
keynotes %>%
select(year, conference) %>%
count(year, conference) %>%
ggplot(aes(x = year(year), y = n, color = conference)) +
geom_point() +
geom_line(alpha = 0.5) +
coord_cartesian(ylim = c(0, 13)) +
scale_x_continuous(breaks = seq(1995, 2019, 5)) +
scale_y_continuous(breaks = seq(0, 14, 2)) +
scale_color_viridis_d() +
labs(x = 'Year', y = 'Number of keynote speakers/fellows')
Authors
Total number of last authors: 176110.
10 journals with the most computational biology articles:
corr_authors %>%
mutate(publication_date = ymd(publication_date, truncated = 2)) %>%
select(publication_date, journal) %>%
filter(journal %in% large_jours$journal) %>%
ggplot(aes(x = publication_date, fill = forcats::fct_infreq(journal))) +
geom_histogram(size = 0, bins = 27) +
scale_fill_brewer(palette = 'Set3') +
theme(legend.position = c(0.2, 0.7)) +
labs(x = NULL, y = NULL) +
scale_x_date(
labels = scales::date_format("%Y"),
breaks = as.Date(c('2000-01-01', '2010-01-01', '2019-01-01')),
limits = c(as.Date('1993-01-01'), as.Date('2019-12-31'))) +
# geom_text(data = jours, aes(x = x, y = y, label = label), color = 'grey10') +
NULL
## Warning: Removed 20 rows containing missing values (geom_bar).
nucleic_acids <- corr_authors %>% filter(grepl('Nucleic Acids Res', journal))
table(nucleic_acids$journal)
##
## Nucleic Acids Res Nucleic Acids Res Suppl
## 3419 5
Gender analysis
gender_df <- read_tsv('data/gender/genderize.tsv')
##
## ── Column specification ──────────────────────────────────────────
## cols(
## fore_name_simple = col_character(),
## n_authors = col_double(),
## genderize_sample_size = col_double(),
## query_date = col_date(format = ""),
## probability_male = col_double()
## )
pubmed_gender_pmids <- corr_authors %>%
left_join(gender_df, by = 'fore_name_simple')
iscb_gender_df <- keynotes %>%
left_join(gender_df, by = 'fore_name_simple')
pubmed_gender_pmids %>%
mutate(genderized = ifelse(is.na(probability_male), 'NOT genderized', 'Genderized')) %>%
ggplot(aes(year(year), fill = genderized)) +
geom_bar() +
scale_fill_viridis_d() +
theme(legend.position = c(0.2, 0.8)) +
ylab('Number of full names')
gender_check <- pubmed_gender_pmids %>%
mutate(got_gender = case_when(
is.na(probability_male) ~ 'Gender not predicted',
TRUE ~ 'Gender predicted'))
pred_all <- pubmed_gender_pmids %>%
count(is.na(probability_male))
dash_df <- pubmed_gender_pmids %>%
filter(is.na(probability_male) & !is.na(fore_name_simple)) %>%
mutate(dashed_name = grepl('-', fore_name_simple)) %>%
count(dashed_name)
pred_before_2002 <- gender_check %>%
filter(year(year) < 2002) %>%
count(is.na(probability_male), is.na(fore_name_simple))
1014 last authors with empty fore name field (i.e., missing metadata). 12512 authors with no fore_name_simple
.
In total, 153655 authors had gender prediction and 22515 didn’t. 11498 authors with fore name that is NA once simplified (i.e., initials only). Among 10003 authors with fore name but no predictions, ~ 42% has a dash.
Before 2002, 35 authors had gender predictions, 2566 didn’t have gender predictions because of these authors only have initials for fore names.
Mean probability of selecting Asian among these names:
pubmed_gender_pmids %>%
filter(is.na(probability_male) & !is.na(fore_name_simple)) %>%
rename('surname' = last_name_simple) %>%
predict_race(surname.only = T, impute.missing = F) %>%
pull(pred.asi) %>%
mean(na.rm = T)
## [1] "Proceeding with surname-only predictions..."
## Warning in merge_surnames(voter.file, impute.missing =
## impute.missing): 1305 surnames were not matched.
## [1] 0.8174599
Honorees that didn’t receive a gender prediction: Chung-I Wu.
In summary, the NA predictions mostly include initials only, hyphenated names and perhaps names with accent marks.
US race analysis
pubmed_aff_pmids <- corr_authors %>%
tidyr::separate_rows(countries, sep = ',') %>%
filter(countries == 'US') # looking at only US affiliation
keynotes_us <- keynotes %>%
tidyr::separate_rows(afflcountries, sep = '\\|') %>%
filter(afflcountries == 'United States')
pubmed_race_pmids <- pubmed_aff_pmids %>%
rename('surname' = last_name_simple) %>%
predict_race(surname.only = T, impute.missing = F)
## [1] "Proceeding with surname-only predictions..."
iscb_us_race <- keynotes_us %>%
rename('surname' = last_name_simple) %>%
predict_race(surname.only = T, impute.missing = F)
## [1] "Proceeding with surname-only predictions..."
Number of honorees affiliated with the US: 239.
Number of last authors affiliated with the US: 27410.
Number of authors with no race prediction: 5166 (of which 6 did not have a surname).
Number of honorees with no race prediction: 45 (of which 0 did not have a surname).
pubmed_race_pmids %>%
mutate(race_pred = ifelse(is.na(pred.whi), 'Race NOT predicted', 'Race predicted')) %>%
ggplot(aes(year(year), fill = fct_rev(race_pred))) +
geom_bar() +
scale_fill_viridis_d() +
theme(legend.position = c(0.2, 0.8)) +
ylab('Number of full names')
Name origin analysis
region_levels <- paste(c('Celtic/English', 'European', 'East Asian', 'Hispanic', 'South Asian', 'Arabic', 'Hebrew', 'African', 'Nordic', 'Greek'), 'names')
pubmed_nat_pmids <- corr_authors %>%
left_join(nationalize_df, by = c('fore_name', 'last_name'))
pubmed_nat_df <- pubmed_nat_pmids %>%
group_by(pmid, journal, publication_date, year) %>%
summarise_at(vars(African:SouthAsian), mean, na.rm = T) %>%
ungroup()
iscb_nat_df <- keynotes %>%
left_join(nationalize_df, by = c('fore_name', 'last_name'))
set.seed(0)
top_names <- map_dfc(
nationalize_df %>%
select(African:SouthAsian) %>%
colnames(),
function(x) {
nationalize_df %>%
filter((!!sym(x)) > 0.9) %>%
sample_n(6) %>%
select(full_name) %>%
rename(!!x := full_name)
})
top_names %>%
pivot_longer(everything(), names_to = 'region', values_to = 'names') %>%
recode_region() %>%
group_by(region) %>%
summarise(names = paste(names, collapse = ', '), .groups = 'drop') %>%
arrange(factor(region, levels = region_levels)) %>%
DT::datatable() %>%
# write_tsv('data/names/example_name_origin.tsv') %>%
{.}
## Warning: Problem with `mutate()` input `region`.
## ℹ Unknown levels in `f`: OtherCategories
## ℹ Input `region` is `fct_recode(...)`.
## Warning: Unknown levels in `f`: OtherCategories
pubmed_nat_pmids %>% count(!is.na(African), is.na(fore_name_simple.x))
## # A tibble: 2 x 3
## `!is.na(African)` `is.na(fore_name_simple.x)` n
## <lgl> <lgl> <int>
## 1 FALSE TRUE 12512
## 2 TRUE FALSE 163598
0 ISCB speakers did not have nationality predictions. 12512 pubmed full names not nationalized. 12512 of these don’t have fore_name_simple. (See earlier conclusion in Gender analysis.)
pubmed_nat_df %>%
mutate(nationalized = ifelse(is.na(African), 'NOT nationalized', 'Nationalized')) %>%
ggplot(aes(year(year), fill = nationalized)) +
geom_bar() +
scale_fill_viridis_d() +
theme(legend.position = c(0.2, 0.8)) +
ylab('Number of full names')
Affiliation analysis
corr_authors %>%
mutate(affi_country_found = ifelse(is.na(countries), 'Country NOT found', 'Country found')) %>%
ggplot(aes(year(year), fill = affi_country_found)) +
geom_bar(position = 'stack') +
scale_fill_viridis_d() +
theme(legend.position = c(0.2, 0.8)) +
ylab('Number of full names')
corr_authors %>%
ggplot(aes(x = adjusted_citations)) +
geom_density()
corr_authors %>%
mutate(affi_country_found = ifelse(
is.na(countries), 'Country NOT found', 'Country found'),
has_pmcid = ifelse(is.na(pmcid), 'No PMCID', 'Has PMCID')) %>%
count(affi_country_found, has_pmcid)
## # A tibble: 4 x 3
## affi_country_found has_pmcid n
## <chr> <chr> <int>
## 1 Country found Has PMCID 44165
## 2 Country found No PMCID 39972
## 3 Country NOT found Has PMCID 37424
## 4 Country NOT found No PMCID 54549
Due to the lack of metadata, our method couldn’t extract countries for most articles before 2014. Even though many of these articles have PMCIDs, the affiliations were not mapped to authors in PMC metadata and thus couldn’t be parsed. However, unlike the other analyses where we considered “year” as a covariate, we calculated the enrichment by gathering data from all the years together. Therefore, we leave all the data in as is.
US name origin analysis
pubmed_nat_pmids <- corr_authors %>%
separate_rows(countries, sep = ',') %>%
filter(countries == 'US') %>%
left_join(nationalize_df, by = c('fore_name', 'last_name'))
pubmed_nat_df <- pubmed_nat_pmids %>%
group_by(pmid, journal, publication_date, year) %>%
summarise_at(vars(African:SouthAsian), mean, na.rm = T) %>%
ungroup()
iscb_nat_df <- keynotes %>%
separate_rows(afflcountries, sep = '\\|') %>%
filter(afflcountries == 'United States') %>%
left_join(nationalize_df, by = c('fore_name', 'last_name'))
0 US-affiliated ISCB speakers did not have nationality predictions. pubmed_nat_pmids %>% filter(is.na(African)) %>% nrow()
US-affiliated authors did not have nationality predictions. 1205 of these don’t have fore_name_simple. (See earlier conclusion in Gender analysis.)
pubmed_nat_df %>%
mutate(nationalized = ifelse(is.na(African), 'NOT nationalized', 'Nationalized')) %>%
ggplot(aes(year(year), fill = nationalized)) +
geom_bar() +
scale_fill_viridis_d() +
theme(legend.position = c(0.2, 0.8)) +
ylab('Number of US-affiliated full names')
LS0tCnRpdGxlOiAiU3VtbWFyeSBzdGF0aXN0aWNzIGFuZCBtaXNzaW5nIGRhdGEgYW5hbHlzaXMiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdGhlbWU6IGZsYXRseQogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIGhpZ2hsaWdodDogdGFuZ28Ka25pdDogKGZ1bmN0aW9uKGlucHV0RmlsZSwgZW5jb2RpbmcpIHsKICBybWFya2Rvd246OnJlbmRlcihpbnB1dEZpbGUsIGVuY29kaW5nID0gZW5jb2RpbmcsIG91dHB1dF9kaXIgPSAiZG9jcyIpIH0pCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGx1YnJpZGF0ZSkKbGlicmFyeShybmF0dXJhbGVhcnRoKQpsaWJyYXJ5KHdydSkKc291cmNlKCd1dGlscy9yLXV0aWxzLlInKQp0aGVtZV9zZXQodGhlbWVfYncoKSArIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkpCmBgYAoKIyMgR2VuZXJhbCBkYXRhIHJlYWQtaW4KCmBgYHtyfQpsb2FkKCdSZGF0YS9yYXdzLlJkYXRhJykKYGBgCiMjIEhvbm9yZWVzCgotIE51bWJlciBvZiBob25vcmVlcyB1cCB1bnRpbCAyMDE5OiBgciBucm93KGtleW5vdGVzKWAuCgotIFRocmVlIHR5cGVzIG9mIGhvbm9yZWVzOgpgYGB7cn0Ka2V5bm90ZXMgJT4lIAogIHB1bGwoY29uZmVyZW5jZSkgJT4lIAogIHRhYmxlKCkKYGBgCgpUaGVyZSBhcmUgYHIgbnJvdyhrZXlub3RlcylgIGVudHJpZXMgYW5kIGByIGtleW5vdGVzICU+JSBkaXN0aW5jdChmb3JlX25hbWUsIGxhc3RfbmFtZSkgJT4lIG5yb3coKWAgdW5pcXVlIG5hbWVzIGluIHRoZSBJU0NCIGNvaG9ydC4KCk5hbWVzIHNvcnRlZCBieSB0aGUgbnVtYmVyIG9mIGhvbm9yczoKYGBge3J9CmtleW5vdGVzICU+JSAKICBjb3VudChmb3JlX25hbWUsIGxhc3RfbmFtZSkgJT4lIAogIGFycmFuZ2UoZGVzYyhuKSkgJT4lIAogIERUOjpkYXRhdGFibGUoKQpgYGAKCk51bWJlciBvZiBrZXlub3RlIHNwZWFrZXJzL2ZlbGxvd3MgYWNyb3NzIHllYXJzOgoKYGBge3J9CmtleW5vdGVzICU+JQogIHNlbGVjdCh5ZWFyLCBjb25mZXJlbmNlKSAlPiUgCiAgY291bnQoeWVhciwgY29uZmVyZW5jZSkgJT4lIAogIGdncGxvdChhZXMoeCA9IHllYXIoeWVhciksIHkgPSBuLCBjb2xvciA9IGNvbmZlcmVuY2UpKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX2xpbmUoYWxwaGEgPSAwLjUpICsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoMCwgMTMpKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgxOTk1LCAyMDE5LCA1KSkgKwogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgMTQsIDIpKSArCiAgc2NhbGVfY29sb3JfdmlyaWRpc19kKCkgKwogIGxhYnMoeCA9ICdZZWFyJywgeSA9ICdOdW1iZXIgb2Yga2V5bm90ZSBzcGVha2Vycy9mZWxsb3dzJykKYGBgCgoKIyMgQXV0aG9ycwpUb3RhbCBudW1iZXIgb2YgbGFzdCBhdXRob3JzOiBgciBucm93KGNvcnJfYXV0aG9ycylgLgoKMTAgam91cm5hbHMgd2l0aCB0aGUgbW9zdCBjb21wdXRhdGlvbmFsIGJpb2xvZ3kgYXJ0aWNsZXM6CgpgYGB7cn0KY29ycl9hdXRob3JzICU+JSAKICBtdXRhdGUocHVibGljYXRpb25fZGF0ZSA9IHltZChwdWJsaWNhdGlvbl9kYXRlLCB0cnVuY2F0ZWQgPSAyKSkgJT4lIAogIHNlbGVjdChwdWJsaWNhdGlvbl9kYXRlLCBqb3VybmFsKSAlPiUgCiAgZmlsdGVyKGpvdXJuYWwgJWluJSBsYXJnZV9qb3VycyRqb3VybmFsKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gcHVibGljYXRpb25fZGF0ZSwgZmlsbCA9IGZvcmNhdHM6OmZjdF9pbmZyZXEoam91cm5hbCkpKSArCiAgZ2VvbV9oaXN0b2dyYW0oc2l6ZSA9IDAsIGJpbnMgPSAyNykgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAnU2V0MycpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKDAuMiwgMC43KSkgKwogIGxhYnMoeCA9IE5VTEwsIHkgPSBOVUxMKSArCnNjYWxlX3hfZGF0ZSgKICAgIGxhYmVscyA9IHNjYWxlczo6ZGF0ZV9mb3JtYXQoIiVZIiksCiAgICBicmVha3MgPSBhcy5EYXRlKGMoJzIwMDAtMDEtMDEnLCAnMjAxMC0wMS0wMScsICcyMDE5LTAxLTAxJykpLAogICAgbGltaXRzID0gYyhhcy5EYXRlKCcxOTkzLTAxLTAxJyksIGFzLkRhdGUoJzIwMTktMTItMzEnKSkpICsgCiAgIyBnZW9tX3RleHQoZGF0YSA9IGpvdXJzLCBhZXMoeCA9IHgsIHkgPSB5LCBsYWJlbCA9IGxhYmVsKSwgY29sb3IgPSAnZ3JleTEwJykgKwogIE5VTEwKYGBgCgpgYGB7cn0KbnVjbGVpY19hY2lkcyA8LSBjb3JyX2F1dGhvcnMgJT4lIGZpbHRlcihncmVwbCgnTnVjbGVpYyBBY2lkcyBSZXMnLCBqb3VybmFsKSkKdGFibGUobnVjbGVpY19hY2lkcyRqb3VybmFsKQpgYGAKCmBgYHtyIGluY2x1ZGUgPSBGLCBldmFsID0gRn0KIyBIb3cgbXVjaCBkaWQgSVNDQiBob25vcmVlcyBwdWJsaXNoIGluIHRoZXNlIGpvdXJuYWxzIGFzIGxhc3QgYXV0aG9ycz8KCm5fcHVicyA8LSBrZXlub3RlcyAlPiUgCiAgZGlzdGluY3QoZm9yZV9uYW1lX3NpbXBsZSwgbGFzdF9uYW1lX3NpbXBsZSkgJT4lIAogICMgbGVmdF9qb2luKG5hdF90b19yZWcsIGJ5ID0gYygnYWZmbGNvdW50cmllcycgPSAnY291bnRyeV9uYW1lJykpICU+JSAKICBsZWZ0X2pvaW4oY29ycl9hdXRob3JzLCBieSA9IGMoJ2ZvcmVfbmFtZV9zaW1wbGUnLCAnbGFzdF9uYW1lX3NpbXBsZScpKSAlPiUgCiAgZ3JvdXBfYnkoZm9yZV9uYW1lX3NpbXBsZSwgbGFzdF9uYW1lX3NpbXBsZSkgJT4lIAogIHN1bW1hcmlzZShudW1fcHVicyA9IHN1bSghaXMubmEocG1pZCkpLCAuZ3JvdXBzID0gJ2Ryb3AnKQpuX3B1YnMkbnVtX3B1YnMgJT4lIHN1bSgpCiMgbl9wdWJzICU+JSAKIyAgIGdncGxvdCgpICsKIyAgIGdlb21fYmFyKGFlcyh4ID0gbnVtX3B1YnMpKQpgYGAKCiMjIEdlbmRlciBhbmFseXNpcwoKYGBge3J9CmdlbmRlcl9kZiA8LSByZWFkX3RzdignZGF0YS9nZW5kZXIvZ2VuZGVyaXplLnRzdicpCgpwdWJtZWRfZ2VuZGVyX3BtaWRzIDwtIGNvcnJfYXV0aG9ycyAlPiUKICBsZWZ0X2pvaW4oZ2VuZGVyX2RmLCBieSA9ICdmb3JlX25hbWVfc2ltcGxlJykKCmlzY2JfZ2VuZGVyX2RmIDwtIGtleW5vdGVzICU+JSAKICBsZWZ0X2pvaW4oZ2VuZGVyX2RmLCBieSA9ICdmb3JlX25hbWVfc2ltcGxlJykKYGBgCgpgYGB7cn0KcHVibWVkX2dlbmRlcl9wbWlkcyAlPiUgCiAgbXV0YXRlKGdlbmRlcml6ZWQgPSBpZmVsc2UoaXMubmEocHJvYmFiaWxpdHlfbWFsZSksICdOT1QgZ2VuZGVyaXplZCcsICdHZW5kZXJpemVkJykpICU+JSAKICBnZ3Bsb3QoYWVzKHllYXIoeWVhciksIGZpbGwgPSBnZW5kZXJpemVkKSkgKwogIGdlb21fYmFyKCkgKwogIHNjYWxlX2ZpbGxfdmlyaWRpc19kKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC4yLCAwLjgpKSArCiAgeWxhYignTnVtYmVyIG9mIGZ1bGwgbmFtZXMnKQpgYGAKCiAgCmBgYHtyfQpnZW5kZXJfY2hlY2sgPC0gcHVibWVkX2dlbmRlcl9wbWlkcyAlPiUKICBtdXRhdGUoZ290X2dlbmRlciA9IGNhc2Vfd2hlbigKICAgIGlzLm5hKHByb2JhYmlsaXR5X21hbGUpIH4gJ0dlbmRlciBub3QgcHJlZGljdGVkJywKICAgIFRSVUUgfiAnR2VuZGVyIHByZWRpY3RlZCcpKQoKcHJlZF9hbGwgPC0gcHVibWVkX2dlbmRlcl9wbWlkcyAlPiUgCiAgY291bnQoaXMubmEocHJvYmFiaWxpdHlfbWFsZSkpCgpkYXNoX2RmIDwtIHB1Ym1lZF9nZW5kZXJfcG1pZHMgJT4lIAogIGZpbHRlcihpcy5uYShwcm9iYWJpbGl0eV9tYWxlKSAmICFpcy5uYShmb3JlX25hbWVfc2ltcGxlKSkgJT4lIAogIG11dGF0ZShkYXNoZWRfbmFtZSA9IGdyZXBsKCctJywgZm9yZV9uYW1lX3NpbXBsZSkpICU+JSAKICBjb3VudChkYXNoZWRfbmFtZSkKCnByZWRfYmVmb3JlXzIwMDIgPC0gZ2VuZGVyX2NoZWNrICU+JSAKICBmaWx0ZXIoeWVhcih5ZWFyKSA8IDIwMDIpICU+JQogIGNvdW50KGlzLm5hKHByb2JhYmlsaXR5X21hbGUpLCBpcy5uYShmb3JlX25hbWVfc2ltcGxlKSkKCmBgYAoKYHIgcHVibWVkX2dlbmRlcl9wbWlkcyAlPiUgZmlsdGVyKGlzLm5hKGZvcmVfbmFtZSkpICU+JSBucm93KClgIGxhc3QgYXV0aG9ycyB3aXRoIGVtcHR5IGZvcmUgbmFtZSBmaWVsZCAoaS5lLiwgbWlzc2luZyBtZXRhZGF0YSkuCmByIHB1Ym1lZF9nZW5kZXJfcG1pZHMgJT4lIGZpbHRlcihpcy5uYShmb3JlX25hbWVfc2ltcGxlKSkgJT4lIG5yb3coKWAgYXV0aG9ycyB3aXRoIG5vIGBmb3JlX25hbWVfc2ltcGxlYC4KCkluIHRvdGFsLCBgciBwcmVkX2FsbFsxLCAnbiddYCBhdXRob3JzIGhhZCBnZW5kZXIgcHJlZGljdGlvbiBhbmQgYHIgcHJlZF9hbGxbMiwgJ24nXWAgZGlkbid0LgpgciBwdWJtZWRfZ2VuZGVyX3BtaWRzICU+JSBmaWx0ZXIoIWlzLm5hKGZvcmVfbmFtZSkmaXMubmEoZm9yZV9uYW1lX3NpbXBsZSkpICU+JSBucm93KClgIGF1dGhvcnMgd2l0aCBmb3JlIG5hbWUgdGhhdCBpcyBOQSBvbmNlIHNpbXBsaWZpZWQgKGkuZS4sIGluaXRpYWxzIG9ubHkpLgpBbW9uZyBgciBzdW0oZGFzaF9kZiRuKWAgYXV0aG9ycyB3aXRoIGZvcmUgbmFtZSBidXQgbm8gcHJlZGljdGlvbnMsIH4gYHIgcm91bmQoZGFzaF9kZiRuWzFdL3N1bShkYXNoX2RmJG4pKjEwMClgJSBoYXMgYSBkYXNoLgoKQmVmb3JlIDIwMDIsIGByIHByZWRfYmVmb3JlXzIwMDJbMSwgJ24nXWAgYXV0aG9ycyBoYWQgZ2VuZGVyIHByZWRpY3Rpb25zLCBgciBwcmVkX2JlZm9yZV8yMDAyWzIsICduJ11gIGRpZG4ndCBoYXZlIGdlbmRlciBwcmVkaWN0aW9ucyBiZWNhdXNlIG9mIHRoZXNlIGF1dGhvcnMgb25seSBoYXZlIGluaXRpYWxzIGZvciBmb3JlIG5hbWVzLgoKCk1lYW4gcHJvYmFiaWxpdHkgb2Ygc2VsZWN0aW5nIEFzaWFuIGFtb25nIHRoZXNlIG5hbWVzOgpgYGB7cn0KcHVibWVkX2dlbmRlcl9wbWlkcyAlPiUgCiAgZmlsdGVyKGlzLm5hKHByb2JhYmlsaXR5X21hbGUpICYgIWlzLm5hKGZvcmVfbmFtZV9zaW1wbGUpKSAlPiUgCiAgcmVuYW1lKCdzdXJuYW1lJyA9IGxhc3RfbmFtZV9zaW1wbGUpICU+JSAKICBwcmVkaWN0X3JhY2Uoc3VybmFtZS5vbmx5ID0gVCwgaW1wdXRlLm1pc3NpbmcgPSBGKSAlPiUgCiAgcHVsbChwcmVkLmFzaSkgJT4lIAogIG1lYW4obmEucm0gPSBUKQpgYGAKCkhvbm9yZWVzIHRoYXQgZGlkbid0IHJlY2VpdmUgYSBnZW5kZXIgcHJlZGljdGlvbjogYHIgaXNjYl9nZW5kZXJfZGYgJT4lIGZpbHRlcihpcy5uYShwcm9iYWJpbGl0eV9tYWxlKSkgJT4lIHB1bGwoZnVsbF9uYW1lKWAuCgoqKkluIHN1bW1hcnksIHRoZSBOQSBwcmVkaWN0aW9ucyBtb3N0bHkgaW5jbHVkZSBpbml0aWFscyBvbmx5LCBoeXBoZW5hdGVkIG5hbWVzIGFuZCBwZXJoYXBzIG5hbWVzIHdpdGggYWNjZW50IG1hcmtzLioqCgoKIyMgVVMgcmFjZSBhbmFseXNpcwoKYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KcHVibWVkX2FmZl9wbWlkcyA8LSBjb3JyX2F1dGhvcnMgJT4lIAogIHRpZHlyOjpzZXBhcmF0ZV9yb3dzKGNvdW50cmllcywgc2VwID0gJywnKSAlPiUgCiAgZmlsdGVyKGNvdW50cmllcyA9PSAnVVMnKSAjIGxvb2tpbmcgYXQgb25seSBVUyBhZmZpbGlhdGlvbgoKa2V5bm90ZXNfdXMgPC0ga2V5bm90ZXMgJT4lIAogIHRpZHlyOjpzZXBhcmF0ZV9yb3dzKGFmZmxjb3VudHJpZXMsIHNlcCA9ICdcXHwnKSAlPiUgCiAgZmlsdGVyKGFmZmxjb3VudHJpZXMgPT0gJ1VuaXRlZCBTdGF0ZXMnKSAKCnB1Ym1lZF9yYWNlX3BtaWRzIDwtIHB1Ym1lZF9hZmZfcG1pZHMgJT4lCiAgcmVuYW1lKCdzdXJuYW1lJyA9IGxhc3RfbmFtZV9zaW1wbGUpICU+JSAKICBwcmVkaWN0X3JhY2Uoc3VybmFtZS5vbmx5ID0gVCwgaW1wdXRlLm1pc3NpbmcgPSBGKQoKaXNjYl91c19yYWNlIDwtIGtleW5vdGVzX3VzICU+JSAKICByZW5hbWUoJ3N1cm5hbWUnID0gbGFzdF9uYW1lX3NpbXBsZSkgJT4lCiAgcHJlZGljdF9yYWNlKHN1cm5hbWUub25seSA9IFQsIGltcHV0ZS5taXNzaW5nID0gRikKICAKYGBgCgotIE51bWJlciBvZiBob25vcmVlcyBhZmZpbGlhdGVkIHdpdGggdGhlIFVTOiBgciBucm93KGtleW5vdGVzX3VzKWAuCgotIE51bWJlciBvZiBsYXN0IGF1dGhvcnMgYWZmaWxpYXRlZCB3aXRoIHRoZSBVUzogYHIgbnJvdyhwdWJtZWRfYWZmX3BtaWRzKWAuCgotIE51bWJlciBvZiBhdXRob3JzIHdpdGggbm8gcmFjZSBwcmVkaWN0aW9uOiBgciBzdW0oaXMubmEocHVibWVkX3JhY2VfcG1pZHMkcHJlZC53aGkpKWAgKG9mIHdoaWNoIGByIHN1bShpcy5uYShwdWJtZWRfcmFjZV9wbWlkcyRzdXJuYW1lKSlgIGRpZCBub3QgaGF2ZSBhIHN1cm5hbWUpLgoKLSBOdW1iZXIgb2YgaG9ub3JlZXMgd2l0aCBubyByYWNlIHByZWRpY3Rpb246IGByIHN1bShpcy5uYShpc2NiX3VzX3JhY2UkcHJlZC53aGkpKWAgKG9mIHdoaWNoIGByIHN1bShpcy5uYShpc2NiX3VzX3JhY2Ukc3VybmFtZSkpYCBkaWQgbm90IGhhdmUgYSBzdXJuYW1lKS4KCmBgYHtyfQpwdWJtZWRfcmFjZV9wbWlkcyAlPiUgCiAgbXV0YXRlKHJhY2VfcHJlZCA9IGlmZWxzZShpcy5uYShwcmVkLndoaSksICdSYWNlIE5PVCBwcmVkaWN0ZWQnLCAnUmFjZSBwcmVkaWN0ZWQnKSkgJT4lIAogIGdncGxvdChhZXMoeWVhcih5ZWFyKSwgZmlsbCA9IGZjdF9yZXYocmFjZV9wcmVkKSkpICsKICBnZW9tX2JhcigpICsKICBzY2FsZV9maWxsX3ZpcmlkaXNfZCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKDAuMiwgMC44KSkgKwogIHlsYWIoJ051bWJlciBvZiBmdWxsIG5hbWVzJykKYGBgCgoKIyMgTmFtZSBvcmlnaW4gYW5hbHlzaXMKCmBgYHtyfQpyZWdpb25fbGV2ZWxzIDwtIHBhc3RlKGMoJ0NlbHRpYy9FbmdsaXNoJywgJ0V1cm9wZWFuJywgJ0Vhc3QgQXNpYW4nLCAnSGlzcGFuaWMnLCAnU291dGggQXNpYW4nLCAnQXJhYmljJywgJ0hlYnJldycsICdBZnJpY2FuJywgJ05vcmRpYycsICdHcmVlaycpLCAnbmFtZXMnKQoKcHVibWVkX25hdF9wbWlkcyA8LSBjb3JyX2F1dGhvcnMgJT4lCiAgbGVmdF9qb2luKG5hdGlvbmFsaXplX2RmLCBieSA9IGMoJ2ZvcmVfbmFtZScsICdsYXN0X25hbWUnKSkKCnB1Ym1lZF9uYXRfZGYgPC0gcHVibWVkX25hdF9wbWlkcyAlPiUgCiAgZ3JvdXBfYnkocG1pZCwgam91cm5hbCwgcHVibGljYXRpb25fZGF0ZSwgeWVhcikgJT4lCiAgc3VtbWFyaXNlX2F0KHZhcnMoQWZyaWNhbjpTb3V0aEFzaWFuKSwgbWVhbiwgbmEucm0gPSBUKSAlPiUKICB1bmdyb3VwKCkKCmlzY2JfbmF0X2RmIDwtIGtleW5vdGVzICU+JQogIGxlZnRfam9pbihuYXRpb25hbGl6ZV9kZiwgYnkgPSBjKCdmb3JlX25hbWUnLCAnbGFzdF9uYW1lJykpCgpgYGAKCmBgYHtyfQpzZXQuc2VlZCgwKQoKdG9wX25hbWVzIDwtIG1hcF9kZmMoCiAgbmF0aW9uYWxpemVfZGYgJT4lIAogICAgc2VsZWN0KEFmcmljYW46U291dGhBc2lhbikgJT4lIAogICAgY29sbmFtZXMoKSwgCiAgZnVuY3Rpb24oeCkgewogICAgbmF0aW9uYWxpemVfZGYgJT4lCiAgICAgIGZpbHRlcigoISFzeW0oeCkpID4gMC45KSAlPiUKICAgICAgc2FtcGxlX24oNikgJT4lCiAgICAgIHNlbGVjdChmdWxsX25hbWUpICU+JQogICAgICByZW5hbWUoISF4IDo9IGZ1bGxfbmFtZSkKICB9KQoKdG9wX25hbWVzICU+JSAKICBwaXZvdF9sb25nZXIoZXZlcnl0aGluZygpLCBuYW1lc190byA9ICdyZWdpb24nLCB2YWx1ZXNfdG8gPSAnbmFtZXMnKSAlPiUgCiAgcmVjb2RlX3JlZ2lvbigpICU+JSAKICBncm91cF9ieShyZWdpb24pICU+JSAKICBzdW1tYXJpc2UobmFtZXMgPSBwYXN0ZShuYW1lcywgY29sbGFwc2UgPSAnLCAnKSwgLmdyb3VwcyA9ICdkcm9wJykgJT4lIAogIGFycmFuZ2UoZmFjdG9yKHJlZ2lvbiwgbGV2ZWxzID0gcmVnaW9uX2xldmVscykpICU+JQogIERUOjpkYXRhdGFibGUoKSAlPiUgCiAgIyB3cml0ZV90c3YoJ2RhdGEvbmFtZXMvZXhhbXBsZV9uYW1lX29yaWdpbi50c3YnKSAlPiUgCiAgey59CgogcHVibWVkX25hdF9wbWlkcyAlPiUgY291bnQoIWlzLm5hKEFmcmljYW4pLCBpcy5uYShmb3JlX25hbWVfc2ltcGxlLngpKQpgYGAKCmByIGlzY2JfbmF0X2RmICU+JSBmaWx0ZXIoaXMubmEoQWZyaWNhbikpICU+JSBucm93KClgIElTQ0Igc3BlYWtlcnMgZGlkIG5vdCBoYXZlIG5hdGlvbmFsaXR5IHByZWRpY3Rpb25zLgpgciBwdWJtZWRfbmF0X3BtaWRzICU+JSBmaWx0ZXIoaXMubmEoQWZyaWNhbikpICU+JSBucm93KClgIHB1Ym1lZCBmdWxsIG5hbWVzIG5vdCBuYXRpb25hbGl6ZWQuCmByIHB1Ym1lZF9uYXRfcG1pZHMgJT4lIGZpbHRlcihpcy5uYShBZnJpY2FuKSZpcy5uYShmb3JlX25hbWVfc2ltcGxlLngpKSAlPiUgbnJvdygpYCBvZiB0aGVzZSBkb24ndCBoYXZlIGZvcmVfbmFtZV9zaW1wbGUuCihTZWUgZWFybGllciBjb25jbHVzaW9uIGluIEdlbmRlciBhbmFseXNpcy4pCgpgYGB7cn0KcHVibWVkX25hdF9kZiAlPiUgCiAgbXV0YXRlKG5hdGlvbmFsaXplZCA9IGlmZWxzZShpcy5uYShBZnJpY2FuKSwgJ05PVCBuYXRpb25hbGl6ZWQnLCAnTmF0aW9uYWxpemVkJykpICU+JSAKICBnZ3Bsb3QoYWVzKHllYXIoeWVhciksIGZpbGwgPSBuYXRpb25hbGl6ZWQpKSArCiAgZ2VvbV9iYXIoKSArCiAgc2NhbGVfZmlsbF92aXJpZGlzX2QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gYygwLjIsIDAuOCkpICsKICB5bGFiKCdOdW1iZXIgb2YgZnVsbCBuYW1lcycpCmBgYAoKIyMgQWZmaWxpYXRpb24gYW5hbHlzaXMKCmBgYHtyfQpjb3JyX2F1dGhvcnMgJT4lIAogIG11dGF0ZShhZmZpX2NvdW50cnlfZm91bmQgPSBpZmVsc2UoaXMubmEoY291bnRyaWVzKSwgJ0NvdW50cnkgTk9UIGZvdW5kJywgJ0NvdW50cnkgZm91bmQnKSkgJT4lIAogIGdncGxvdChhZXMoeWVhcih5ZWFyKSwgZmlsbCA9IGFmZmlfY291bnRyeV9mb3VuZCkpICsKICBnZW9tX2Jhcihwb3NpdGlvbiA9ICdzdGFjaycpICsKICBzY2FsZV9maWxsX3ZpcmlkaXNfZCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKDAuMiwgMC44KSkgKwogIHlsYWIoJ051bWJlciBvZiBmdWxsIG5hbWVzJykKCmNvcnJfYXV0aG9ycyAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gYWRqdXN0ZWRfY2l0YXRpb25zKSkgKwogIGdlb21fZGVuc2l0eSgpCgpjb3JyX2F1dGhvcnMgJT4lIAogIG11dGF0ZShhZmZpX2NvdW50cnlfZm91bmQgPSBpZmVsc2UoCiAgICBpcy5uYShjb3VudHJpZXMpLCAnQ291bnRyeSBOT1QgZm91bmQnLCAnQ291bnRyeSBmb3VuZCcpLAogICAgICAgICBoYXNfcG1jaWQgPSBpZmVsc2UoaXMubmEocG1jaWQpLCAnTm8gUE1DSUQnLCAnSGFzIFBNQ0lEJykpICU+JSAKICBjb3VudChhZmZpX2NvdW50cnlfZm91bmQsIGhhc19wbWNpZCkKYGBgCgpEdWUgdG8gdGhlIGxhY2sgb2YgbWV0YWRhdGEsIG91ciBtZXRob2QgY291bGRuJ3QgZXh0cmFjdCBjb3VudHJpZXMgZm9yIG1vc3QgYXJ0aWNsZXMgYmVmb3JlIDIwMTQuCkV2ZW4gdGhvdWdoIG1hbnkgb2YgdGhlc2UgYXJ0aWNsZXMgaGF2ZSBQTUNJRHMsIHRoZSBhZmZpbGlhdGlvbnMgd2VyZSBub3QgbWFwcGVkIHRvIGF1dGhvcnMgaW4gUE1DIG1ldGFkYXRhIGFuZCB0aHVzIGNvdWxkbid0IGJlIHBhcnNlZC4KSG93ZXZlciwgdW5saWtlIHRoZSBvdGhlciBhbmFseXNlcyB3aGVyZSB3ZSBjb25zaWRlcmVkICJ5ZWFyIiBhcyBhIGNvdmFyaWF0ZSwgd2UgY2FsY3VsYXRlZCB0aGUgZW5yaWNobWVudCBieSBnYXRoZXJpbmcgZGF0YSBmcm9tIGFsbCB0aGUgeWVhcnMgdG9nZXRoZXIuClRoZXJlZm9yZSwgd2UgbGVhdmUgYWxsIHRoZSBkYXRhIGluIGFzIGlzLgoKIyMgVVMgbmFtZSBvcmlnaW4gYW5hbHlzaXMKCmBgYHtyfQpwdWJtZWRfbmF0X3BtaWRzIDwtIGNvcnJfYXV0aG9ycyAlPiUKICBzZXBhcmF0ZV9yb3dzKGNvdW50cmllcywgc2VwID0gJywnKSAlPiUgCiAgZmlsdGVyKGNvdW50cmllcyA9PSAnVVMnKSAlPiUgCiAgbGVmdF9qb2luKG5hdGlvbmFsaXplX2RmLCBieSA9IGMoJ2ZvcmVfbmFtZScsICdsYXN0X25hbWUnKSkKCnB1Ym1lZF9uYXRfZGYgPC0gcHVibWVkX25hdF9wbWlkcyAlPiUgCiAgZ3JvdXBfYnkocG1pZCwgam91cm5hbCwgcHVibGljYXRpb25fZGF0ZSwgeWVhcikgJT4lCiAgc3VtbWFyaXNlX2F0KHZhcnMoQWZyaWNhbjpTb3V0aEFzaWFuKSwgbWVhbiwgbmEucm0gPSBUKSAlPiUKICB1bmdyb3VwKCkKCmlzY2JfbmF0X2RmIDwtIGtleW5vdGVzICU+JQogIHNlcGFyYXRlX3Jvd3MoYWZmbGNvdW50cmllcywgc2VwID0gJ1xcfCcpICU+JSAKICBmaWx0ZXIoYWZmbGNvdW50cmllcyA9PSAnVW5pdGVkIFN0YXRlcycpICU+JSAKICBsZWZ0X2pvaW4obmF0aW9uYWxpemVfZGYsIGJ5ID0gYygnZm9yZV9uYW1lJywgJ2xhc3RfbmFtZScpKQpgYGAKCmByIGlzY2JfbmF0X2RmICU+JSBmaWx0ZXIoaXMubmEoQWZyaWNhbikpICU+JSBucm93KClgIFVTLWFmZmlsaWF0ZWQgSVNDQiBzcGVha2VycyBkaWQgbm90IGhhdmUgbmF0aW9uYWxpdHkgcHJlZGljdGlvbnMuCmBwdWJtZWRfbmF0X3BtaWRzICU+JSBmaWx0ZXIoaXMubmEoQWZyaWNhbikpICU+JSBucm93KClgIFVTLWFmZmlsaWF0ZWQgYXV0aG9ycyBkaWQgbm90IGhhdmUgbmF0aW9uYWxpdHkgcHJlZGljdGlvbnMuCmByIHB1Ym1lZF9uYXRfcG1pZHMgJT4lIGZpbHRlcihpcy5uYShBZnJpY2FuKSZpcy5uYShmb3JlX25hbWVfc2ltcGxlLngpKSAlPiUgbnJvdygpYCBvZiB0aGVzZSBkb24ndCBoYXZlIGZvcmVfbmFtZV9zaW1wbGUuCihTZWUgZWFybGllciBjb25jbHVzaW9uIGluIEdlbmRlciBhbmFseXNpcy4pCgoKYGBge3J9CnB1Ym1lZF9uYXRfZGYgJT4lIAogIG11dGF0ZShuYXRpb25hbGl6ZWQgPSBpZmVsc2UoaXMubmEoQWZyaWNhbiksICdOT1QgbmF0aW9uYWxpemVkJywgJ05hdGlvbmFsaXplZCcpKSAlPiUgCiAgZ2dwbG90KGFlcyh5ZWFyKHllYXIpLCBmaWxsID0gbmF0aW9uYWxpemVkKSkgKwogIGdlb21fYmFyKCkgKwogIHNjYWxlX2ZpbGxfdmlyaWRpc19kKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC4yLCAwLjgpKSArCiAgeWxhYignTnVtYmVyIG9mIFVTLWFmZmlsaWF0ZWQgZnVsbCBuYW1lcycpCmBgYAoKCgoK