Document set-up

1.) Import data and format data

library(tidyverse)
library(lubridate)
library(DT)
library(stringr)

'%!in%' <- function(x,y)!('%in%'(x,y))

# Set working directory to file location
setwd("~/Documents/GitHub/2020-10-campaign-contributions/workspace")

#import candidates from primary and general
candidates <- read_csv('data/candidates.csv')
#candidates not on ballot
not_on_ballot <- read_csv('committees_not_on_ballot.csv')
# import 2020 contributions from individuals to state races.
contributions.raw <- read_csv('data/all_contributions_2020.csv')
  
# convert names to snake_case
colnames(contributions.raw) <- gsub(' ', '_', tolower(colnames(contributions.raw)))

contributions.noParty <- contributions.raw %>% 
    mutate(contribution_date = as.Date(contribution_date, format='%m/%d/%Y') )  %>% 
    # removes records where office is NA, leaving only contributions to committees supporting candidates
    # removes candidate laons
    filter(
      !is.na(office),
      contribution_type != 'Candidate Loan'
    )


# join party data from candidate list
contributions <- left_join(
  contributions.noParty %>% 
    filter(
      receiving_committee %!in% not_on_ballot$committee
    ) %>% 
    mutate(
      committeeJoin = gsub(' ','', receiving_committee)
    ),
  candidates %>% 
    select(committee, party, ballotName, inGeneral) %>% 
    mutate(
      committeeJoin = gsub(' ','', committee)
    ),
  by = 'committeeJoin'
) %>% 
  filter(!is.na(party)) %>%
  select(-filing_period) %>% 
  distinct()
# original      17,704
# not on ballot 17,311
# no party join 17,117
# distinct      15,873











contributions.individuals <- contributions %>% 
  filter(
      contributor_type %in% c('Individual', "Total of Contributions not exceeding $100"),
      contribution_type %in% c("Check", "Electronic Fund Transfer", "Credit Card", "Cash", "Total of Contributions not exceeding $100")
    )

Data overview

key value
contributions all non-candidate-loan contributions to any candidate committee (where
is.na(Office)
& contribution_type != 'Candidate Loan' )
contributions.individuals direct monetary contributions from individuals to any candidate committee (where
contribution_type %in% c("Check", "Electronic Fund Transfer", "Credit Card", "Cash", "Total of Contributions not exceeding $100")
& is.na(Office)
& contributor_type == 'Individual'
)
candidates all candidates in the Delaware primary and general elections
contributions.raw all contributions to any committee

Questions

Total

How much money has been contributed total?

What groups or individuals are the top donors to each party?

`summarise()` regrouping output by 'contributor_name' (override with `.groups` argument)

What groups or people donated to candidates from both parties?

`summarise()` ungrouping output (override with `.groups` argument)

Contributions where contributor_name contains “Police”

Individuals

How much money has been contributed by individuals total?

How much money has been contributed by individuals to each party

contributions.individuals %>% 
  group_by(party) %>% 
  summarise(total = sum(contribution_amount)) %>% 
  datatable(options = list(pageLength = 10))
`summarise()` ungrouping output (override with `.groups` argument)

Who the top donors among individuals?

contributions.individuals %>% 
  group_by(contributor_name) %>% 
  summarise(total = sum(contribution_amount)) %>% 
  arrange(desc(total)) %>% 
  datatable(options = list(pageLength = 10))
`summarise()` ungrouping output (override with `.groups` argument)

Who the top donors by party among individuals?

contributions.individuals %>% 
  group_by(contributor_name, party) %>% 
  summarise(total = sum(contribution_amount)) %>% 
  arrange(desc(total)) %>% 
  datatable(options = list(pageLength = 10))
`summarise()` regrouping output by 'contributor_name' (override with `.groups` argument)

How much money has been contributed to each office (primary and general) by individuals?

contributions.individuals %>% 
  group_by(office, party) %>% 
  summarise(total = sum(contribution_amount)) %>% 
  arrange(desc(total)) %>% 
  datatable(options = list(pageLength = 10))
`summarise()` regrouping output by 'office' (override with `.groups` argument)

How much money has been contributed to each candidate by individuals?

contributions.individuals %>% 
  group_by(ballotName, party) %>% 
  summarise(total = sum(contribution_amount)) %>% 
  arrange(desc(total)) %>% 
  datatable(options = list(pageLength = 10))
`summarise()` regrouping output by 'ballotName' (override with `.groups` argument)

How much money has been contributed to each general election candidate by individuals?

contributions.individuals %>%
  filter(inGeneral == 1) %>% 
  group_by(ballotName) %>% 
  summarise(total = sum(contribution_amount)) %>% 
  arrange(desc(total)) %>% 
  datatable(options = list(pageLength = 10))
`summarise()` ungrouping output (override with `.groups` argument)

How many people donated to multiple candidates?


contributions.individuals %>% 
  select(
    contributor_name, committee
  ) %>% 
  distinct() %>% 
  group_by(contributor_name) %>%
  summarise(numCandidates = n()) %>% 
  ungroup() %>% 
  group_by(numCandidates) %>% 
  summarise(group_count = n()) %>% 
  datatable(options = list(pageLength = 10))
`summarise()` ungrouping output (override with `.groups` argument)
`summarise()` ungrouping output (override with `.groups` argument)

How many people donated to candidates from both parties?

contributions.individuals %>% 
  select(
    contributor_name, party 
  ) %>% 
  distinct() %>% 
  group_by(contributor_name) %>%
  summarise(numParties = n()) %>% 
  ungroup() %>% 
  group_by(numParties) %>% 
  summarise(group_count = n()) %>% 
  datatable(options = list(pageLength = 10))
`summarise()` ungrouping output (override with `.groups` argument)
`summarise()` ungrouping output (override with `.groups` argument)

How much money John Carney and Julianne Murray received in donations from individuals

`summarise()` ungrouping output (override with `.groups` argument)

How much money John Carney and Julianne Murray received in donations from PACS, business groups, labor uniions, and non-profit organizations

`summarise()` ungrouping output (override with `.groups` argument)

John Carney and Julianne Murray donations from PACS, business groups, labor uniions, and non-profit organizations broken down

`summarise()` regrouping output by 'receiving_committee' (override with `.groups` argument)

How much money John Carney and Julianne Murray received in donations from individuals, PACS, business groups, labor uniions, and non-profit organizations (This is everything except Candidate Committee, Self (Candidate), Political Committee, , and Dem or Rep National Sub-Committees)

`summarise()` ungrouping output (override with `.groups` argument)

How much did legislative candidates receive?

contributions %>% 
  filter(
    str_detect(office, 'State'),
    contribution_type %in% c("Check", "Electronic Fund Transfer", "Credit Card", "Cash", "Total of Contributions not exceeding $100")
  ) %>% 
  select(
    contributor_name,
    contributor_type,
    contribution_type,
    contribution_amount,
    ballotName
  ) %>% 
  mutate(
    contributor_type_group = case_when(
      contributor_type %in% c("Individual","Total of Contributions not exceeding $100") ~ 'individual',
      contributor_type == 'Candidate Committee' ~ 'Candidate Committee',
      contributor_type %in% outside_groups ~ 'outside group',
      contributor_type == 'Self (Candidate)' ~ 'self',
      TRUE ~ 'other'
    )
  ) %>% 
  group_by(
    ballotName,
    contributor_type_group
  ) %>% 
  summarise(
    total = round(sum(contribution_amount), 0)
  ) %>%
  pivot_wider(
    id_cols = ballotName,
    names_from = contributor_type_group,
    values_from = total
  ) %>%
  mutate(
    total = round(sum(c(individual, `Candidate Committee`, `outside group`, other, self), na.rm=T), 0)
  ) %>% 
  arrange(desc(total)) %>% 
  datatable(options = list(pageLength = 10))
`summarise()` regrouping output by 'ballotName' (override with `.groups` argument)
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyMjIERvY3VtZW50IHNldC11cAoKIyMjIyAxLikgSW1wb3J0IGRhdGEgYW5kIGZvcm1hdCBkYXRhCmBgYHtyIGVjaG8gPSBULCByZXN1bHRzID0gJ2hpZGUnfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShsdWJyaWRhdGUpCmxpYnJhcnkoRFQpCmxpYnJhcnkoc3RyaW5ncikKCiclIWluJScgPC0gZnVuY3Rpb24oeCx5KSEoJyVpbiUnKHgseSkpCgojIFNldCB3b3JraW5nIGRpcmVjdG9yeSB0byBmaWxlIGxvY2F0aW9uCnNldHdkKCJ+L0RvY3VtZW50cy9HaXRIdWIvMjAyMC0xMC1jYW1wYWlnbi1jb250cmlidXRpb25zL3dvcmtzcGFjZSIpCgojaW1wb3J0IGNhbmRpZGF0ZXMgZnJvbSBwcmltYXJ5IGFuZCBnZW5lcmFsCmNhbmRpZGF0ZXMgPC0gcmVhZF9jc3YoJ2RhdGEvY2FuZGlkYXRlcy5jc3YnKQoKI2NhbmRpZGF0ZXMgbm90IG9uIGJhbGxvdApub3Rfb25fYmFsbG90IDwtIHJlYWRfY3N2KCdjb21taXR0ZWVzX25vdF9vbl9iYWxsb3QuY3N2JykKCgojIGltcG9ydCAyMDIwIGNvbnRyaWJ1dGlvbnMgZnJvbSBpbmRpdmlkdWFscyB0byBzdGF0ZSByYWNlcy4KY29udHJpYnV0aW9ucy5yYXcgPC0gcmVhZF9jc3YoJ2RhdGEvYWxsX2NvbnRyaWJ1dGlvbnNfMjAyMC5jc3YnKQogIAojIGNvbnZlcnQgbmFtZXMgdG8gc25ha2VfY2FzZQpjb2xuYW1lcyhjb250cmlidXRpb25zLnJhdykgPC0gZ3N1YignICcsICdfJywgdG9sb3dlcihjb2xuYW1lcyhjb250cmlidXRpb25zLnJhdykpKQoKY29udHJpYnV0aW9ucy5ub1BhcnR5IDwtIGNvbnRyaWJ1dGlvbnMucmF3ICU+JSAKICAgIG11dGF0ZShjb250cmlidXRpb25fZGF0ZSA9IGFzLkRhdGUoY29udHJpYnV0aW9uX2RhdGUsIGZvcm1hdD0nJW0vJWQvJVknKSApICAlPiUgCiAgICAjIHJlbW92ZXMgcmVjb3JkcyB3aGVyZSBvZmZpY2UgaXMgTkEsIGxlYXZpbmcgb25seSBjb250cmlidXRpb25zIHRvIGNvbW1pdHRlZXMgc3VwcG9ydGluZyBjYW5kaWRhdGVzCiAgICAjIHJlbW92ZXMgY2FuZGlkYXRlIGxhb25zCiAgICBmaWx0ZXIoCiAgICAgICFpcy5uYShvZmZpY2UpLAogICAgICBjb250cmlidXRpb25fdHlwZSAhPSAnQ2FuZGlkYXRlIExvYW4nCiAgICApCgoKIyBqb2luIHBhcnR5IGRhdGEgZnJvbSBjYW5kaWRhdGUgbGlzdApjb250cmlidXRpb25zIDwtIGxlZnRfam9pbigKICBjb250cmlidXRpb25zLm5vUGFydHkgJT4lIAogICAgZmlsdGVyKAogICAgICByZWNlaXZpbmdfY29tbWl0dGVlICUhaW4lIG5vdF9vbl9iYWxsb3QkY29tbWl0dGVlCiAgICApICU+JSAKICAgIG11dGF0ZSgKICAgICAgY29tbWl0dGVlSm9pbiA9IGdzdWIoJyAnLCcnLCByZWNlaXZpbmdfY29tbWl0dGVlKQogICAgKSwKICBjYW5kaWRhdGVzICU+JSAKICAgIHNlbGVjdChjb21taXR0ZWUsIHBhcnR5LCBiYWxsb3ROYW1lLCBpbkdlbmVyYWwpICU+JSAKICAgIG11dGF0ZSgKICAgICAgY29tbWl0dGVlSm9pbiA9IGdzdWIoJyAnLCcnLCBjb21taXR0ZWUpCiAgICApLAogIGJ5ID0gJ2NvbW1pdHRlZUpvaW4nCikgJT4lIAogIGZpbHRlcighaXMubmEocGFydHkpKSAlPiUKICBzZWxlY3QoLWZpbGluZ19wZXJpb2QpICU+JSAKICBkaXN0aW5jdCgpCiMgb3JpZ2luYWwgICAgICAxNyw3MDQKIyBub3Qgb24gYmFsbG90IDE3LDMxMQojIG5vIHBhcnR5IGpvaW4gMTcsMTE3CiMgZGlzdGluY3QgICAgICAxNSw4NzMKCgoKCgoKCgoKCgpjb250cmlidXRpb25zLmluZGl2aWR1YWxzIDwtIGNvbnRyaWJ1dGlvbnMgJT4lIAogIGZpbHRlcigKICAgICAgY29udHJpYnV0b3JfdHlwZSAlaW4lIGMoJ0luZGl2aWR1YWwnLCAiVG90YWwgb2YgQ29udHJpYnV0aW9ucyBub3QgZXhjZWVkaW5nICQxMDAiKSwKICAgICAgY29udHJpYnV0aW9uX3R5cGUgJWluJSBjKCJDaGVjayIsICJFbGVjdHJvbmljIEZ1bmQgVHJhbnNmZXIiLCAiQ3JlZGl0IENhcmQiLCAiQ2FzaCIsICJUb3RhbCBvZiBDb250cmlidXRpb25zIG5vdCBleGNlZWRpbmcgJDEwMCIpCiAgICApCgpgYGAKCgoqKioKCgojIyMgRGF0YSBvdmVydmlldwoKCnwga2V5ICAgICAgICAgICB8IHZhbHVlICB8CnwtLS0tLS0tLS0tLS0tLS18LS0tLS0tLS18CnwgKipjb250cmlidXRpb25zKiogICAgICB8IGFsbCBub24tY2FuZGlkYXRlLWxvYW4gY29udHJpYnV0aW9ucyB0byBhbnkgY2FuZGlkYXRlIGNvbW1pdHRlZSAod2hlcmUgPGJyLz5gaXMubmEoT2ZmaWNlKWA8YnIvPmAmIGNvbnRyaWJ1dGlvbl90eXBlICE9ICdDYW5kaWRhdGUgTG9hbidgICkgfAp8ICoqY29udHJpYnV0aW9ucy5pbmRpdmlkdWFscyoqICAgICAgfCBkaXJlY3QgbW9uZXRhcnkgY29udHJpYnV0aW9ucyBmcm9tIGluZGl2aWR1YWxzIHRvIGFueSBjYW5kaWRhdGUgY29tbWl0dGVlICh3aGVyZSA8YnIvPmBjb250cmlidXRpb25fdHlwZSAlaW4lIGMoIkNoZWNrIiwgIkVsZWN0cm9uaWMgRnVuZCBUcmFuc2ZlciIsICJDcmVkaXQgQ2FyZCIsICJDYXNoIiwgIlRvdGFsIG9mIENvbnRyaWJ1dGlvbnMgbm90IGV4Y2VlZGluZyAkMTAwIilgPGJyPmAmIGlzLm5hKE9mZmljZSlgPGJyPmAmIGNvbnRyaWJ1dG9yX3R5cGUgPT0gJ0luZGl2aWR1YWwnYDxicj4gKSB8CnwgY2FuZGlkYXRlcyB8IGFsbCBjYW5kaWRhdGVzIGluIHRoZSBEZWxhd2FyZSBwcmltYXJ5IGFuZCBnZW5lcmFsIGVsZWN0aW9ucyB8CnwgY29udHJpYnV0aW9ucy5yYXcgICAgICB8IGFsbCBjb250cmlidXRpb25zIHRvIGFueSBjb21taXR0ZWUgfAoKCiAKCgpgYGB7ciBlY2hvPUZBTFNFLCBpbmNsdWRlPUZBTFNFLCByZXN1bHRzID0gJ2hpZGUnfQpjb250cmlidXRpb25zLmluZGl2aWR1YWxzICU+JQogIGdyb3VwX2J5KAogICAgY29udHJpYnV0aW9uX2RhdGUKICApICU+JSAKICBzdW1tYXJpc2UodG90YWwgPSBzdW0oY29udHJpYnV0aW9uX2Ftb3VudCkpICU+JSAKICBnZ3Bsb3QoCiAgICBhZXMoeCA9IGNvbnRyaWJ1dGlvbl9kYXRlLCB5PXRvdGFsKQogICkgKwogIGdlb21fY29sKCkgKwogIGxhYnModGl0bGU9J0RhaWx5IGNvbnRyaWJ1dGlvbnMsIGFsbCBjYW5kaWRhdGVzJykKCmBgYAoKCmBgYHtyIGVjaG89RkFMU0UsIGluY2x1ZGU9RkFMU0UsIHJlc3VsdHMgPSAnaGlkZSd9Cgpjb250cmlidXRpb25zLmluZGl2aWR1YWxzICU+JSAKICBncm91cF9ieSgKICAgIHBhcnR5LAogICAgY29udHJpYnV0aW9uX2RhdGUKICApICU+JQogIHN1bW1hcmlzZSh0b3RhbCA9IHN1bShjb250cmlidXRpb25fYW1vdW50KSkgJT4lCiAgbXV0YXRlKGN1bV90b3RhbCA9IGN1bXN1bSh0b3RhbCkpICU+JSAKICBnZ3Bsb3QoCiAgICBhZXMoeCA9IGNvbnRyaWJ1dGlvbl9kYXRlLCB5PWN1bV90b3RhbCwgY29sb3I9cGFydHkpCiAgKSArCiAgZ2VvbV9saW5lKCkgKwogIGxhYnModGl0bGU9J0N1bXVsYXRpdmUgY29udHJpYnV0aW9ucywgYnkgcGFydHknKQoKYGBgCgoKCioqKgoKIyMgUXVlc3Rpb25zCgojIyMgKlRvdGFsKgoKIyMjIEhvdyBtdWNoIG1vbmV5IGhhcyBiZWVuIGNvbnRyaWJ1dGVkIHRvdGFsPwpgYGB7ciBlY2hvPUZBTFNFfQpjb250cmlidXRpb25zICU+JSAKICBzdW1tYXJpc2UodG90YWwgPSBzdW0oY29udHJpYnV0aW9uX2Ftb3VudCkpCmBgYAoKIyMjIFdoYXQgZ3JvdXBzIG9yIGluZGl2aWR1YWxzIGFyZSB0aGUgdG9wIGRvbm9ycyB0byBlYWNoIHBhcnR5PwoKYGBge3IgZWNobz1GQUxTRX0KY29udHJpYnV0aW9ucyAlPiUgCiAgZmlsdGVyKGNvbnRyaWJ1dG9yX25hbWUgIT0gJ1RvdGFsIG9mIENvbnRyaWJ1dGlvbnMgbm90IGV4Y2VlZGluZyAkMTAwJykgJT4lIAogIGdyb3VwX2J5KGNvbnRyaWJ1dG9yX25hbWUsIHBhcnR5KSAlPiUgCiAgc3VtbWFyaXNlKHRvdGFsID0gc3VtKGNvbnRyaWJ1dGlvbl9hbW91bnQpKSAlPiUgCiAgYXJyYW5nZShkZXNjKHRvdGFsKSkgJT4lIAogIGRhdGF0YWJsZShvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gMTApKQpgYGAKCgojIyMgV2hhdCBncm91cHMgb3IgcGVvcGxlIGRvbmF0ZWQgdG8gY2FuZGlkYXRlcyBmcm9tIGJvdGggcGFydGllcz8KCmBgYHtyIGVjaG89RkFMU0V9CmNvbnRyaWJ1dGlvbnMgJT4lCiAgZmlsdGVyKGNvbnRyaWJ1dG9yX25hbWUgIT0gJ1RvdGFsIG9mIENvbnRyaWJ1dGlvbnMgbm90IGV4Y2VlZGluZyAkMTAwJykgJT4lIAogIHNlbGVjdCgKICAgIGNvbnRyaWJ1dG9yX25hbWUsIHBhcnR5CiAgKSAlPiUgCiAgZGlzdGluY3QoKSAlPiUgCiAgZ3JvdXBfYnkoY29udHJpYnV0b3JfbmFtZSkgJT4lCiAgc3VtbWFyaXNlKG51bVBhcnRpZXMgPSBuKCkpICU+JSAKICBmaWx0ZXIoIG51bVBhcnRpZXMgPiAxKSAlPiUgCiAgYXJyYW5nZShkZXNjKG51bVBhcnRpZXMpKSAlPiUgCiAgZGF0YXRhYmxlKG9wdGlvbnMgPSBsaXN0KHBhZ2VMZW5ndGggPSAxMCkpCgpgYGAKCgoKIyMjIENvbnRyaWJ1dGlvbnMgd2hlcmUgYGNvbnRyaWJ1dG9yX25hbWVgIGNvbnRhaW5zICJQb2xpY2UiCmBgYHtyIGVjaG89RkFMU0V9CmNvbnRyaWJ1dGlvbnMgJT4lIAogIGZpbHRlcihncmVwbCgiUG9saWNlIiwgY29udHJpYnV0b3JfbmFtZSwgaWdub3JlLmNhc2U9VFJVRSkpICU+JSAKICBkYXRhdGFibGUob3B0aW9ucyA9IGxpc3QocGFnZUxlbmd0aCA9IDEwKSkKICAKYGBgCgoKCiMjIyAqSW5kaXZpZHVhbHMqCgojIyMgSG93IG11Y2ggbW9uZXkgaGFzIGJlZW4gY29udHJpYnV0ZWQgYnkgaW5kaXZpZHVhbHMgdG90YWw/CmBgYHtyIGVjaG89RkFMU0V9CmNvbnRyaWJ1dGlvbnMuaW5kaXZpZHVhbHMgJT4lIAogIHN1bW1hcmlzZSh0b3RhbCA9IHN1bShjb250cmlidXRpb25fYW1vdW50KSkKYGBgCgojIyMgSG93IG11Y2ggbW9uZXkgaGFzIGJlZW4gY29udHJpYnV0ZWQgYnkgaW5kaXZpZHVhbHMgdG8gZWFjaCBwYXJ0eQpgYGB7cn0KY29udHJpYnV0aW9ucy5pbmRpdmlkdWFscyAlPiUgCiAgZ3JvdXBfYnkocGFydHkpICU+JSAKICBzdW1tYXJpc2UodG90YWwgPSBzdW0oY29udHJpYnV0aW9uX2Ftb3VudCkpICU+JSAKICBkYXRhdGFibGUob3B0aW9ucyA9IGxpc3QocGFnZUxlbmd0aCA9IDEwKSkKYGBgCgojIyMgV2hvIHRoZSB0b3AgZG9ub3JzIGFtb25nIGluZGl2aWR1YWxzPwoKYGBge3J9CmNvbnRyaWJ1dGlvbnMuaW5kaXZpZHVhbHMgJT4lIAogIGdyb3VwX2J5KGNvbnRyaWJ1dG9yX25hbWUpICU+JSAKICBzdW1tYXJpc2UodG90YWwgPSBzdW0oY29udHJpYnV0aW9uX2Ftb3VudCkpICU+JSAKICBhcnJhbmdlKGRlc2ModG90YWwpKSAlPiUgCiAgZGF0YXRhYmxlKG9wdGlvbnMgPSBsaXN0KHBhZ2VMZW5ndGggPSAxMCkpCmBgYAoKIyMjIFdobyB0aGUgdG9wIGRvbm9ycyBieSBwYXJ0eSBhbW9uZyBpbmRpdmlkdWFscz8KCmBgYHtyfQpjb250cmlidXRpb25zLmluZGl2aWR1YWxzICU+JSAKICBncm91cF9ieShjb250cmlidXRvcl9uYW1lLCBwYXJ0eSkgJT4lIAogIHN1bW1hcmlzZSh0b3RhbCA9IHN1bShjb250cmlidXRpb25fYW1vdW50KSkgJT4lIAogIGFycmFuZ2UoZGVzYyh0b3RhbCkpICU+JSAKICBkYXRhdGFibGUob3B0aW9ucyA9IGxpc3QocGFnZUxlbmd0aCA9IDEwKSkKYGBgCgojIyMgSG93IG11Y2ggbW9uZXkgaGFzIGJlZW4gY29udHJpYnV0ZWQgdG8gZWFjaCBvZmZpY2UgKHByaW1hcnkgYW5kIGdlbmVyYWwpIGJ5IGluZGl2aWR1YWxzPwpgYGB7cn0KY29udHJpYnV0aW9ucy5pbmRpdmlkdWFscyAlPiUgCiAgZ3JvdXBfYnkob2ZmaWNlLCBwYXJ0eSkgJT4lIAogIHN1bW1hcmlzZSh0b3RhbCA9IHN1bShjb250cmlidXRpb25fYW1vdW50KSkgJT4lIAogIGFycmFuZ2UoZGVzYyh0b3RhbCkpICU+JSAKICBkYXRhdGFibGUob3B0aW9ucyA9IGxpc3QocGFnZUxlbmd0aCA9IDEwKSkKYGBgCgojIyMgSG93IG11Y2ggbW9uZXkgaGFzIGJlZW4gY29udHJpYnV0ZWQgdG8gZWFjaCBjYW5kaWRhdGUgYnkgaW5kaXZpZHVhbHM/CmBgYHtyfQpjb250cmlidXRpb25zLmluZGl2aWR1YWxzICU+JSAKICBncm91cF9ieShiYWxsb3ROYW1lLCBwYXJ0eSkgJT4lIAogIHN1bW1hcmlzZSh0b3RhbCA9IHN1bShjb250cmlidXRpb25fYW1vdW50KSkgJT4lIAogIGFycmFuZ2UoZGVzYyh0b3RhbCkpICU+JSAKICBkYXRhdGFibGUob3B0aW9ucyA9IGxpc3QocGFnZUxlbmd0aCA9IDEwKSkKYGBgCgoKIyMjIEhvdyBtdWNoIG1vbmV5IGhhcyBiZWVuIGNvbnRyaWJ1dGVkIHRvIGVhY2ggZ2VuZXJhbCBlbGVjdGlvbiBjYW5kaWRhdGUgYnkgaW5kaXZpZHVhbHM/CmBgYHtyfQpjb250cmlidXRpb25zLmluZGl2aWR1YWxzICU+JQogIGZpbHRlcihpbkdlbmVyYWwgPT0gMSkgJT4lIAogIGdyb3VwX2J5KGJhbGxvdE5hbWUpICU+JSAKICBzdW1tYXJpc2UodG90YWwgPSBzdW0oY29udHJpYnV0aW9uX2Ftb3VudCkpICU+JSAKICBhcnJhbmdlKGRlc2ModG90YWwpKSAlPiUgCiAgZGF0YXRhYmxlKG9wdGlvbnMgPSBsaXN0KHBhZ2VMZW5ndGggPSAxMCkpCmBgYAojIyMgSG93IG1hbnkgcGVvcGxlIGRvbmF0ZWQgdG8gbXVsdGlwbGUgY2FuZGlkYXRlcz8KYGBge3J9Cgpjb250cmlidXRpb25zLmluZGl2aWR1YWxzICU+JSAKICBzZWxlY3QoCiAgICBjb250cmlidXRvcl9uYW1lLCBjb21taXR0ZWUKICApICU+JSAKICBkaXN0aW5jdCgpICU+JSAKICBncm91cF9ieShjb250cmlidXRvcl9uYW1lKSAlPiUKICBzdW1tYXJpc2UobnVtQ2FuZGlkYXRlcyA9IG4oKSkgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgZ3JvdXBfYnkobnVtQ2FuZGlkYXRlcykgJT4lIAogIHN1bW1hcmlzZShncm91cF9jb3VudCA9IG4oKSkgJT4lIAogIGRhdGF0YWJsZShvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gMTApKQoKCmBgYAoKCiMjIyBIb3cgbWFueSBwZW9wbGUgZG9uYXRlZCB0byBjYW5kaWRhdGVzIGZyb20gYm90aCBwYXJ0aWVzPwoKYGBge3J9CmNvbnRyaWJ1dGlvbnMuaW5kaXZpZHVhbHMgJT4lIAogIHNlbGVjdCgKICAgIGNvbnRyaWJ1dG9yX25hbWUsIHBhcnR5IAogICkgJT4lIAogIGRpc3RpbmN0KCkgJT4lIAogIGdyb3VwX2J5KGNvbnRyaWJ1dG9yX25hbWUpICU+JQogIHN1bW1hcmlzZShudW1QYXJ0aWVzID0gbigpKSAlPiUgCiAgdW5ncm91cCgpICU+JSAKICBncm91cF9ieShudW1QYXJ0aWVzKSAlPiUgCiAgc3VtbWFyaXNlKGdyb3VwX2NvdW50ID0gbigpKSAlPiUgCiAgZGF0YXRhYmxlKG9wdGlvbnMgPSBsaXN0KHBhZ2VMZW5ndGggPSAxMCkpCgpgYGAKCgoqKioKCmBgYHtyIGluY2x1ZGU9RkFMU0V9CgpvdXRzaWRlX2dyb3VwcyA8LSBjKCJPdXQtb2YtU3RhdGUgb3IgRmVkZXJhbCBDb21taXR0ZWUiLCJJbmRpdmlkdWFsIiwgIkJ1c2luZXNzL0dyb3VwL09yZ2FuaXphdGlvbiIsICJQb2xpdGljYWwgQWN0aW9uIENvbW1pdHRlZSIsICJMYWJvciBVbmlvbiIsICJOb24tUHJvZml0IE9yZ2FuaXphdGlvbiIpCgpjYXJuZXlfbXVycmF5X2dyb3VwIDwtIGNvbnRyaWJ1dGlvbnMgJT4lIAogIGZpbHRlcigKICAgICAgY29udHJpYnV0aW9uX3R5cGUgJWluJSBjKCJDaGVjayIsICJFbGVjdHJvbmljIEZ1bmQgVHJhbnNmZXIiLCAiQ3JlZGl0IENhcmQiLCAiQ2FzaCIsICJUb3RhbCBvZiBDb250cmlidXRpb25zIG5vdCBleGNlZWRpbmcgJDEwMCIpLAogICAgICBjb250cmlidXRvcl90eXBlICVpbiUgb3V0c2lkZV9ncm91cHMsCiAgICAgIHJlY2VpdmluZ19jb21taXR0ZWUgJWluJSBjKCdGcmllbmRzIGZvciBKb2huIENhcm5leScsICdNdXJyYXkgZm9yIERlbGF3YXJlJykKICAgICAgIyBjb250cmlidXRpb25fdHlwZSAlaW4lIGMoIkNoZWNrIiwgIkVsZWN0cm9uaWMgRnVuZCBUcmFuc2ZlciIsICJDcmVkaXQgQ2FyZCIsICJDYXNoIiwgIlRvdGFsIG9mIENvbnRyaWJ1dGlvbnMgbm90IGV4Y2VlZGluZyAkMTAwIikKICAgICkKYGBgCgoKCiMjIyBIb3cgbXVjaCBtb25leSBKb2huIENhcm5leSBhbmQgSnVsaWFubmUgTXVycmF5IHJlY2VpdmVkIGluIGRvbmF0aW9ucyBmcm9tIGluZGl2aWR1YWxzCmBgYHtyIGVjaG89RkFMU0V9CmNhcm5leV9tdXJyYXlfZ3JvdXAgJT4lCiAgZmlsdGVyKGNvbnRyaWJ1dG9yX3R5cGUgJWluJSBjKCJJbmRpdmlkdWFsIiwiVG90YWwgb2YgQ29udHJpYnV0aW9ucyBub3QgZXhjZWVkaW5nICQxMDAiKSkgJT4lIAogIGdyb3VwX2J5KHJlY2VpdmluZ19jb21taXR0ZWUpICU+JSAKICBzdW1tYXJpc2UodG90YWwgPSBzdW0oY29udHJpYnV0aW9uX2Ftb3VudCkgKQpgYGAKCiMjIyBIb3cgbXVjaCBtb25leSBKb2huIENhcm5leSBhbmQgSnVsaWFubmUgTXVycmF5IHJlY2VpdmVkIGluIGRvbmF0aW9ucyBmcm9tIFBBQ1MsIGJ1c2luZXNzIGdyb3VwcywgbGFib3IgdW5paW9ucywgYW5kIG5vbi1wcm9maXQgb3JnYW5pemF0aW9ucwpgYGB7ciBlY2hvPUZBTFNFfQpjYXJuZXlfbXVycmF5X2dyb3VwICU+JQogIGZpbHRlcihjb250cmlidXRvcl90eXBlICUhaW4lIGMoIkluZGl2aWR1YWwiLCJUb3RhbCBvZiBDb250cmlidXRpb25zIG5vdCBleGNlZWRpbmcgJDEwMCIpKSAlPiUgCiAgZ3JvdXBfYnkocmVjZWl2aW5nX2NvbW1pdHRlZSkgJT4lIAogIHN1bW1hcmlzZSh0b3RhbCA9IHN1bShjb250cmlidXRpb25fYW1vdW50KSApCmBgYAoKIyMjIEpvaG4gQ2FybmV5IGFuZCBKdWxpYW5uZSBNdXJyYXkgZG9uYXRpb25zIGZyb20gUEFDUywgYnVzaW5lc3MgZ3JvdXBzLCBsYWJvciB1bmlpb25zLCBhbmQgbm9uLXByb2ZpdCBvcmdhbml6YXRpb25zIGJyb2tlbiBkb3duCmBgYHtyIGVjaG89RkFMU0V9CmNhcm5leV9tdXJyYXlfZ3JvdXAgJT4lCiAgZmlsdGVyKGNvbnRyaWJ1dG9yX3R5cGUgJSFpbiUgYygiSW5kaXZpZHVhbCIsIlRvdGFsIG9mIENvbnRyaWJ1dGlvbnMgbm90IGV4Y2VlZGluZyAkMTAwIikpICU+JSAKICBncm91cF9ieShyZWNlaXZpbmdfY29tbWl0dGVlLCBjb250cmlidXRvcl9uYW1lKSAlPiUgCiAgc3VtbWFyaXNlKHRvdGFsID0gc3VtKGNvbnRyaWJ1dGlvbl9hbW91bnQpICkgJT4lIAogIGFycmFuZ2UoZGVzYyh0b3RhbCkpICU+JSAKICBkYXRhdGFibGUob3B0aW9ucyA9IGxpc3QocGFnZUxlbmd0aCA9IDEwKSkKYGBgCgoKIyMjIEhvdyBtdWNoIG1vbmV5IEpvaG4gQ2FybmV5IGFuZCBKdWxpYW5uZSBNdXJyYXkgcmVjZWl2ZWQgaW4gZG9uYXRpb25zIGZyb20gaW5kaXZpZHVhbHMsIFBBQ1MsIGJ1c2luZXNzIGdyb3VwcywgbGFib3IgdW5paW9ucywgYW5kIG5vbi1wcm9maXQgb3JnYW5pemF0aW9ucyAoVGhpcyBpcyBldmVyeXRoaW5nIGV4Y2VwdCBDYW5kaWRhdGUgQ29tbWl0dGVlLCBTZWxmIChDYW5kaWRhdGUpLCBQb2xpdGljYWwgQ29tbWl0dGVlLCAsIGFuZCBEZW0gb3IgUmVwIE5hdGlvbmFsIFN1Yi1Db21taXR0ZWVzKQpgYGB7ciBlY2hvPUZBTFNFfQpjYXJuZXlfbXVycmF5X2dyb3VwICU+JQogIGdyb3VwX2J5KHJlY2VpdmluZ19jb21taXR0ZWUpICU+JSAKICBzdW1tYXJpc2UodG90YWwgPSBzdW0oY29udHJpYnV0aW9uX2Ftb3VudCkgKQpgYGAKCgoKKioqCiMjIyBIb3cgbXVjaCBkaWQgbGVnaXNsYXRpdmUgY2FuZGlkYXRlcyByZWNlaXZlPwoKYGBge3J9Cgpjb250cmlidXRpb25zICU+JSAKICBmaWx0ZXIoCiAgICBzdHJfZGV0ZWN0KG9mZmljZSwgJ1N0YXRlJyksCiAgICBjb250cmlidXRpb25fdHlwZSAlaW4lIGMoIkNoZWNrIiwgIkVsZWN0cm9uaWMgRnVuZCBUcmFuc2ZlciIsICJDcmVkaXQgQ2FyZCIsICJDYXNoIiwgIlRvdGFsIG9mIENvbnRyaWJ1dGlvbnMgbm90IGV4Y2VlZGluZyAkMTAwIikKICApICU+JSAKICBzZWxlY3QoCiAgICBjb250cmlidXRvcl9uYW1lLAogICAgY29udHJpYnV0b3JfdHlwZSwKICAgIGNvbnRyaWJ1dGlvbl90eXBlLAogICAgY29udHJpYnV0aW9uX2Ftb3VudCwKICAgIGJhbGxvdE5hbWUKICApICU+JSAKICBtdXRhdGUoCiAgICBjb250cmlidXRvcl90eXBlX2dyb3VwID0gY2FzZV93aGVuKAogICAgICBjb250cmlidXRvcl90eXBlICVpbiUgYygiSW5kaXZpZHVhbCIsIlRvdGFsIG9mIENvbnRyaWJ1dGlvbnMgbm90IGV4Y2VlZGluZyAkMTAwIikgfiAnaW5kaXZpZHVhbCcsCiAgICAgIGNvbnRyaWJ1dG9yX3R5cGUgPT0gJ0NhbmRpZGF0ZSBDb21taXR0ZWUnIH4gJ0NhbmRpZGF0ZSBDb21taXR0ZWUnLAogICAgICBjb250cmlidXRvcl90eXBlICVpbiUgb3V0c2lkZV9ncm91cHMgfiAnb3V0c2lkZSBncm91cCcsCiAgICAgIGNvbnRyaWJ1dG9yX3R5cGUgPT0gJ1NlbGYgKENhbmRpZGF0ZSknIH4gJ3NlbGYnLAogICAgICBUUlVFIH4gJ290aGVyJwogICAgKQogICkgJT4lIAogIGdyb3VwX2J5KAogICAgYmFsbG90TmFtZSwKICAgIGNvbnRyaWJ1dG9yX3R5cGVfZ3JvdXAKICApICU+JSAKICBzdW1tYXJpc2UoCiAgICB0b3RhbCA9IHJvdW5kKHN1bShjb250cmlidXRpb25fYW1vdW50KSwgMCkKICApICU+JQogIHBpdm90X3dpZGVyKAogICAgaWRfY29scyA9IGJhbGxvdE5hbWUsCiAgICBuYW1lc19mcm9tID0gY29udHJpYnV0b3JfdHlwZV9ncm91cCwKICAgIHZhbHVlc19mcm9tID0gdG90YWwKICApICU+JQogIG11dGF0ZSgKICAgIHRvdGFsID0gcm91bmQoc3VtKGMoaW5kaXZpZHVhbCwgYENhbmRpZGF0ZSBDb21taXR0ZWVgLCBgb3V0c2lkZSBncm91cGAsIG90aGVyLCBzZWxmKSwgbmEucm09VCksIDApCiAgKSAlPiUgCiAgYXJyYW5nZShkZXNjKHRvdGFsKSkgJT4lIAogIGRhdGF0YWJsZShvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gMTApKQoKCmBgYAoKCgo=