library(estimatr) # robust standard errors
library(patchwork) # arrrange plots
library(sf) # plot maps and gespatial tools
library(tidyverse)
ggplot2::theme_set(theme_void())
crs_deu <- "+proj=lcc +lat_1=48 +lat_2=53 +lat_0=51 +lon_0=10" # LCC Germany parameters
Source
The Federal Returning Officer ("Der Bundeswahlleiter): Bundestag election 2017
- results constituencies
- © The Federal Returning Officer, Wiesbaden 2017
- geometric data of constituencies
- © Der Bundeswahlleiter, Statistisches Bundesamt, Wiesbaden 2016, Wahlkreiskarte für die Wahl zum 19. Deutschen Bundestag, Basis of the geological information © Geobasis-DE / BKG (2016)
bw_raw <- read_csv("data/btw-2017-party.csv")
bw_tier1 <- bw_raw %>% filter(level == "district", votes_type == "Erststimmen")
bw_tier2 <- bw_raw %>% filter(level == "district", votes_type == "Zweitstimmen")
mp_raw <-
read_delim("data/btw17_gewaehlte_utf8.csv", delim = ";", skip = 6) %>%
janitor::clean_names()
mp <-
mp_raw %>%
filter(gewahlt_stimmenart == "E") %>%
mutate(
sex = str_replace(geschlecht, "w", "f"),
region = if_else(gewahlt_land %in% c("BB", "MV", "SN", "ST", "TH"), "east", "west"), # "BE"
region = factor(region) %>% fct_relevel("west")
) %>%
select(
state = gewahlt_land,
region,
district_name = gewahlt_wahlkreis_bez,
wkr_nr = gewahlt_wahlkreis_nr,
party = partei_kurz_bez,
sex
)
wk_shp <-
read_rds("data/btw17-districts-geometry.rds") %>%
left_join(mp %>% distinct(wkr_nr, region))
wk_ctr <- read_rds("data/btw17-districts-centroid.rds")
Votes
Results
party votes share federal level
- candidate tier (first tier) — “Erststimmen”
- party tier (second tier) — (“Zweitstimmen”)
bw_raw %>%
filter(level == "federal") %>%
mutate(party = if_else(party %in% c("CDU", "CSU"), "CDU/CSU", party)) %>%
group_by(votes_type, party) %>%
summarise(share = sum(share) %>% round(1)) %>%
pivot_wider(names_from = votes_type, values_from = share)
Party votes
pl_dt <-
wk_shp %>%
select(wkr_nr, geometry) %>%
right_join(bw_tier2) %>%
mutate(party = if_else(party %in% c("CDU", "CSU"), "CDU/CSU", party)) %>%
group_by(party) %>%
mutate(share_diff = share - mean(share))
party tier (“Zweitstimmen”) vote share electoral districts
pl1 <-
ggplot() +
geom_sf(data = pl_dt, aes(fill = share), lwd = 0.05) +
scale_fill_viridis_c(option = "magma", direction = -1) +
coord_sf(crs = crs_deu) +
facet_wrap(vars(party))
pl1

difference (+/-) of votes share party district from national average votes share party
pl2 <-
ggplot() +
geom_sf(data = pl_dt, aes(fill = share_diff), lwd = 0.05) +
scale_fill_gradient2(name = "+/-") +
coord_sf(crs = crs_deu) +
facet_wrap(vars(party))
pl2
ggsave("z-btw17-vote-share.png", pl1 / pl2, width = 5, height = 7)

Candidate votes
candidate tier (“Erststimmen”) vote share by party
- A — plurality vote winning party
- B — sum of candidate votes share difference by ideology
- right — AfD, CDU, CSU, FDP
- left — DIE LINKE, GRÜNE, SPD
- I – votes share plurality winner
- II – votes share difference top 2 results
party_scale <- c("#decbe4", "#b3cde3", "#ccebc5", "#ffffcc", "#fed9a6", "#fbb4ae")
ideo_share <-
bw_tier1 %>%
group_by(wkr_nr, ideology) %>%
summarise(share = sum(share)) %>%
pivot_wider(names_from = ideology, values_from = share) %>%
mutate(rl_diff = right - left)
pl_dt <-
wk_shp %>%
select(wkr_nr, geometry) %>%
inner_join(ideo_share) %>%
inner_join(mp %>% select(wkr_nr, party))
pl1 <-
ggplot() +
geom_sf(data = pl_dt, aes(fill = party), lwd = 0.05) +
coord_sf(crs = crs_deu) +
scale_fill_manual(values = party_scale)
# print(pl1)
pl2 <-
ggplot() +
geom_sf(data = pl_dt, aes(fill = rl_diff), lwd = 0.05) +
coord_sf(crs = crs_deu) +
scale_fill_gradient2(name = "right +/-")
# print(pl2)
pl1 + pl2 + plot_annotation(tag_levels = "A")

diff_1_2 <-
bw_tier1 %>%
arrange(wkr_nr, desc(share)) %>%
group_by(wkr_nr) %>%
filter(row_number() %in% c(1, 2)) %>%
summarise(
top_2_diff = max(share) - min(share),
share = max(share)
)
pl_dt <-
wk_shp %>%
select(wkr_nr, geometry) %>%
inner_join(diff_1_2)
pl1 <-
ggplot() +
geom_sf(data = pl_dt, aes(fill = share), lwd = 0.05) +
coord_sf(crs = crs_deu) +
scale_fill_viridis_c(option = "cividis", direction = -1)
# print(pl1)
pl2 <-
ggplot() +
geom_sf(data = pl_dt, aes(fill = top_2_diff), lwd = 0.05) +
coord_sf(crs = crs_deu) +
scale_fill_viridis_c(option = "magma", direction = -1)
# print(pl2)
pl1 + pl2 + plot_annotation(tag_levels = "I")

Female MPs
Maps
plurality winner candidate (first) tier vote by party and sex
Germany
scale_sex <- c("red", "blue")
pl_dt_shp <- wk_shp %>% left_join(mp)
pl_dt_ctr <- wk_ctr %>% left_join(mp)
ggplot() +
geom_sf(data = pl_dt_shp, aes(fill = party), lwd = 0.1) +
# scale_fill_brewer(type = "qual", palette = 4) +
scale_fill_manual(values = party_scale) +
geom_sf(data = pl_dt_ctr, aes(shape = sex, colour = sex), alpha = 0.9) +
coord_sf(crs = crs_deu) +
scale_colour_manual(values = scale_sex)

NRW and Berlin
plot_state <- function(state_select, party_scale_select) {
pl_dt_shp_re <- pl_dt_shp %>% filter(state == state_select)
pl_dt_ctr_re <- pl_dt_ctr %>% filter(state == state_select)
ggplot() +
geom_sf(data = pl_dt_shp_re, aes(fill = party), lwd = 0.2) +
scale_fill_manual(values = party_scale_select) +
geom_sf(data = pl_dt_ctr_re, aes(shape = sex, colour = sex), size = 2) +
scale_colour_manual(values = scale_sex) +
guides(colour = FALSE, fill = FALSE, shape = FALSE)
}
pl1 <- plot_state("NW", party_scale[c(2, 6)])
pl2 <- plot_state("BE", party_scale[c(2, 4, 5, 6)])
# plot_state("HH", party_scale[c(2, 6)])
pl1 + pl2 + plot_layout(widths = c(55, 45))

Descriptives
number (n) of districts won by party and sex (f – female, m – male)
Party
count_party <-
mp %>%
count(party, sex) %>%
pivot_wider(names_from = sex, values_from = n) %>%
replace(is.na(.), 0) %>%
mutate(share_f = round(100 * f / (m + f)))
count_party %>% arrange(share_f)
mp %>%
count(party) %>%
mutate(share = round(100 * n / sum(n))) %>%
arrange(desc(share))
States
count_state <-
mp %>%
left_join(wk_shp %>% select(wkr_nr, state_name = land_name)) %>%
count(state_name, sex) %>%
pivot_wider(names_from = sex, values_from = n) %>%
mutate(share_f = round(100 * f / (m + f)))
count_state %>% arrange(share_f)
Models
- area_km2 — size of district as square length (root of area)
- coord_y — north/south position (latitude)
- left_share — share of left parties (SPD, Linke, Grüne)
- region – western or eastern (former GDR) state
library(broom)
library(ggeffects)
mo_dt <-
pl_dt_shp %>%
left_join(ideo_share) %>%
mutate(
female = if_else(sex == "f", 1, 0),
left_share = left
)
Female first-tier winners
Logit model to predict female winners of candidate (first) tier vote
mo_glm <- glm(female ~ area_km2 + coord_y + left_share, data = mo_dt, family = "binomial")
tidy(mo_glm) %>% mutate(across(where(is.numeric), round, 2))
pl1 <- ggpredict(mo_glm, terms = "area_km2 [all]") %>% plot(add.data = TRUE, show.title = FALSE)
pl2 <- ggpredict(mo_glm, terms = "coord_y [all]") %>% plot(add.data = TRUE, show.title = FALSE)
pl1 + pl2

Left vote-share
Linear model of left parties (SPD, Linke, Grüne) vote share
mo_lm <- lm_robust(left_share ~ area_km2*region + coord_y*region, data = mo_dt)
tidy(mo_lm) %>% mutate(across(where(is.numeric), round, 2))
pl1 <- ggpredict(mo_lm, c("area_km2", "region")) %>% plot(add.data = TRUE, show.title = FALSE)
pl2 <- ggpredict(mo_lm, terms = c("coord_y", "region")) %>% plot(add.data = TRUE, show.title = FALSE)
pl1 + pl2

Party vote-share
Linear model of party vote share
mo_dt2 <-
bw_tier2 %>%
mutate(party = if_else(party %in% c("CDU", "CSU"), "CDU/CSU", party)) %>%
# mutate(party = fct_relevel(party, "CDU")) %>%
left_join(wk_shp)
mo_lm2 <- lm_robust(share ~ party*area_km2*region, data = mo_dt2)
# tidy(mo_lm2) %>% mutate(across(where(is.numeric), round, 2))
ggpredict(mo_lm2, terms = c( "area_km2", "region", "party")) %>%
plot(add.data = TRUE, show.title = FALSE)

LS0tCnRpdGxlOiAiR2VybWFueSBkaXN0cmljdCBNUHMiCmF1dGhvcjogIkhvbGdlciBEb2VyaW5nIC0tLSBkb2VyaW5nQHVuaS1icmVtZW4uZGUiCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVkICVCICVZLCAlSDolTScpYCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwogIGh0bWxfZG9jdW1lbnQ6CiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwogICAgZGZfcHJpbnQ6IHBhZ2VkCi0tLQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPiA8IS0tIC50YWJsZSB7IHdpZHRoOiBhdXRvIH0gLS0tPiA8L3N0eWxlPgoKYGBge3Igb3B0aW9ucywgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfa25pdCRzZXQoCiAgZ2xvYmFsLnBhciA9IFRSVUUsCiAgIyByZXN1bHRzID0gImhpZGUiLAogIG1lc3NhZ2UgPSBGQUxTRSwKICB3YXJuaW5nID0gRkFMU0UsCiAgcGFja2FnZS5zdGFydHVwLm1lc3NhZ2UgPSBGQUxTRQogICkKCm9wdGlvbnMoCiAgcmVhZHIubnVtX2NvbHVtbnMgPSAwLAogIGtuaXRyLmthYmxlLk5BID0gIiIsCiAgd2lkdGggPSAxMDAsCiAgdGlkeXZlcnNlLnF1aWV0ID0gVFJVRQopCmBgYAoKYGBge3IsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkoZXN0aW1hdHIpICAgIyByb2J1c3Qgc3RhbmRhcmQgZXJyb3JzCmxpYnJhcnkocGF0Y2h3b3JrKSAgIyBhcnJyYW5nZSBwbG90cwpsaWJyYXJ5KHNmKSAgICAgICAgICMgcGxvdCBtYXBzIGFuZCBnZXNwYXRpYWwgdG9vbHMKbGlicmFyeSh0aWR5dmVyc2UpCgpnZ3Bsb3QyOjp0aGVtZV9zZXQodGhlbWVfdm9pZCgpKQoKY3JzX2RldSA8LSAiK3Byb2o9bGNjICtsYXRfMT00OCArbGF0XzI9NTMgK2xhdF8wPTUxICtsb25fMD0xMCIgICMgTENDIEdlcm1hbnkgcGFyYW1ldGVycwpgYGAKCgojIFNvdXJjZQoKVGhlIEZlZGVyYWwgUmV0dXJuaW5nIE9mZmljZXIgKCJEZXIgQnVuZGVzd2FobGxlaXRlcik6IEJ1bmRlc3RhZyBlbGVjdGlvbiAyMDE3IAoKKyBbcmVzdWx0c10oaHR0cHM6Ly93d3cuYnVuZGVzd2FobGxlaXRlci5kZS9lbi9idW5kZXN0YWdzd2FobGVuLzIwMTcvZXJnZWJuaXNzZS5odG1sKSBjb25zdGl0dWVuY2llcwogICsgwqkgVGhlIEZlZGVyYWwgUmV0dXJuaW5nIE9mZmljZXIsIFdpZXNiYWRlbiAyMDE3CisgW2dlb21ldHJpYyBkYXRhXShodHRwczovL3d3dy5idW5kZXN3YWhsbGVpdGVyLmRlL2VuL2J1bmRlc3RhZ3N3YWhsZW4vMjAxNy93YWhsa3JlaXNlaW50ZWlsdW5nL2Rvd25sb2Fkcy5odG1sKSBvZiBjb25zdGl0dWVuY2llcwogICsgwqkgRGVyIEJ1bmRlc3dhaGxsZWl0ZXIsIFN0YXRpc3Rpc2NoZXMgQnVuZGVzYW10LCBXaWVzYmFkZW4gMjAxNiwgV2FobGtyZWlza2FydGUgZsO8ciBkaWUgV2FobCB6dW0gMTkuIERldXRzY2hlbiBCdW5kZXN0YWcsIEJhc2lzIG9mIHRoZSBnZW9sb2dpY2FsIGluZm9ybWF0aW9uIMKpIEdlb2Jhc2lzLURFIC8gQktHICgyMDE2KQoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmJ3X3JhdyA8LSByZWFkX2NzdigiZGF0YS9idHctMjAxNy1wYXJ0eS5jc3YiKQoKYndfdGllcjEgPC0gYndfcmF3ICU+JSBmaWx0ZXIobGV2ZWwgPT0gImRpc3RyaWN0Iiwgdm90ZXNfdHlwZSA9PSAiRXJzdHN0aW1tZW4iKQpid190aWVyMiA8LSBid19yYXcgJT4lIGZpbHRlcihsZXZlbCA9PSAiZGlzdHJpY3QiLCB2b3Rlc190eXBlID09ICJad2VpdHN0aW1tZW4iKQoKbXBfcmF3IDwtIAogIHJlYWRfZGVsaW0oImRhdGEvYnR3MTdfZ2V3YWVobHRlX3V0ZjguY3N2IiwgZGVsaW0gPSAiOyIsIHNraXAgPSA2KSAlPiUgCiAgamFuaXRvcjo6Y2xlYW5fbmFtZXMoKQoKbXAgPC0gCiAgbXBfcmF3ICU+JSAKICBmaWx0ZXIoZ2V3YWhsdF9zdGltbWVuYXJ0ID09ICJFIikgJT4lIAogIG11dGF0ZSgKICAgIHNleCA9IHN0cl9yZXBsYWNlKGdlc2NobGVjaHQsICJ3IiwgImYiKSwKICAgIHJlZ2lvbiA9IGlmX2Vsc2UoZ2V3YWhsdF9sYW5kICVpbiUgYygiQkIiLCAiTVYiLCAiU04iLCAiU1QiLCAiVEgiKSwgImVhc3QiLCAid2VzdCIpLCAgIyAiQkUiCiAgICByZWdpb24gPSBmYWN0b3IocmVnaW9uKSAlPiUgZmN0X3JlbGV2ZWwoIndlc3QiKQogICAgKSAlPiUgCiAgc2VsZWN0KAogICAgc3RhdGUgPSBnZXdhaGx0X2xhbmQsCiAgICByZWdpb24sCiAgICBkaXN0cmljdF9uYW1lID0gZ2V3YWhsdF93YWhsa3JlaXNfYmV6LAogICAgd2tyX25yID0gZ2V3YWhsdF93YWhsa3JlaXNfbnIsCiAgICBwYXJ0eSA9IHBhcnRlaV9rdXJ6X2JleiwKICAgIHNleAogICAgKQoKd2tfc2hwIDwtIAogIHJlYWRfcmRzKCJkYXRhL2J0dzE3LWRpc3RyaWN0cy1nZW9tZXRyeS5yZHMiKSAlPiUgCiAgICAgIGxlZnRfam9pbihtcCAlPiUgZGlzdGluY3Qod2tyX25yLCByZWdpb24pKQp3a19jdHIgPC0gcmVhZF9yZHMoImRhdGEvYnR3MTctZGlzdHJpY3RzLWNlbnRyb2lkLnJkcyIpCmBgYAoKIyBWb3RlcwoKIyMgUmVzdWx0cwoKcGFydHkgdm90ZXMgc2hhcmUgZmVkZXJhbCBsZXZlbAoKKyBjYW5kaWRhdGUgdGllciAoZmlyc3QgdGllcikg4oCUICJFcnN0c3RpbW1lbiIKKyBwYXJ0eSB0aWVyIChzZWNvbmQgdGllcikg4oCUICgiWndlaXRzdGltbWVuIikKCmBgYHtyLCBtZXNzYWdlPUZBTFNFfQpid19yYXcgJT4lCiAgZmlsdGVyKGxldmVsID09ICJmZWRlcmFsIikgJT4lIAogIG11dGF0ZShwYXJ0eSA9IGlmX2Vsc2UocGFydHkgJWluJSBjKCJDRFUiLCAiQ1NVIiksICJDRFUvQ1NVIiwgcGFydHkpKSAlPiUgCiAgZ3JvdXBfYnkodm90ZXNfdHlwZSwgcGFydHkpICU+JSAKICBzdW1tYXJpc2Uoc2hhcmUgPSBzdW0oc2hhcmUpICU+JSByb3VuZCgxKSkgJT4lIAogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSB2b3Rlc190eXBlLCB2YWx1ZXNfZnJvbSA9IHNoYXJlKQpgYGAKCiMjIFBhcnR5IHZvdGVzCgpgYGB7ciwgbWVzc2FnZT1GQUxTRX0KcGxfZHQgPC0gCiAgd2tfc2hwICU+JSAKICBzZWxlY3Qod2tyX25yLCBnZW9tZXRyeSkgJT4lIAogIHJpZ2h0X2pvaW4oYndfdGllcjIpICU+JSAKICBtdXRhdGUocGFydHkgPSBpZl9lbHNlKHBhcnR5ICVpbiUgYygiQ0RVIiwgIkNTVSIpLCAiQ0RVL0NTVSIsIHBhcnR5KSkgJT4lIAogIGdyb3VwX2J5KHBhcnR5KSAlPiUgCiAgbXV0YXRlKHNoYXJlX2RpZmYgPSBzaGFyZSAtIG1lYW4oc2hhcmUpKQpgYGAKCl9fcGFydHkgdGllcl9fICgiWndlaXRzdGltbWVuIikgdm90ZSBzaGFyZSBlbGVjdG9yYWwgZGlzdHJpY3RzIAoKYGBge3J9CnBsMSA8LSAKICBnZ3Bsb3QoKSArIAogIGdlb21fc2YoZGF0YSA9IHBsX2R0LCBhZXMoZmlsbCA9IHNoYXJlKSwgbHdkID0gMC4wNSkgKwogIHNjYWxlX2ZpbGxfdmlyaWRpc19jKG9wdGlvbiA9ICJtYWdtYSIsIGRpcmVjdGlvbiA9IC0xKSArCiAgY29vcmRfc2YoY3JzID0gY3JzX2RldSkgKwogIGZhY2V0X3dyYXAodmFycyhwYXJ0eSkpCnBsMQpgYGAKCl9fZGlmZmVyZW5jZSAoKy8tKV9fIG9mIHZvdGVzIHNoYXJlIHBhcnR5IF9fZGlzdHJpY3RfXyBmcm9tIF9fbmF0aW9uYWwgYXZlcmFnZV9fIHZvdGVzIHNoYXJlIHBhcnR5CgpgYGB7cn0KcGwyIDwtIAogIGdncGxvdCgpICsgCiAgZ2VvbV9zZihkYXRhID0gcGxfZHQsIGFlcyhmaWxsID0gc2hhcmVfZGlmZiksIGx3ZCA9IDAuMDUpICsKICBzY2FsZV9maWxsX2dyYWRpZW50MihuYW1lID0gIisvLSIpICsKICBjb29yZF9zZihjcnMgPSBjcnNfZGV1KSArCiAgZmFjZXRfd3JhcCh2YXJzKHBhcnR5KSkKcGwyCgpnZ3NhdmUoInotYnR3MTctdm90ZS1zaGFyZS5wbmciLCBwbDEgLyBwbDIsIHdpZHRoID0gNSwgaGVpZ2h0ID0gNykKYGBgCgojIyBDYW5kaWRhdGUgdm90ZXMKCl9fY2FuZGlkYXRlIHRpZXJfXyAoIkVyc3RzdGltbWVuIikgdm90ZSBzaGFyZSBieSBwYXJ0eQoKKyBBIC0tLSBwbHVyYWxpdHkgdm90ZSBfX3dpbm5pbmcgcGFydHlfXworIEIgLS0tIHN1bSBvZiBjYW5kaWRhdGUgdm90ZXMgc2hhcmUgX19kaWZmZXJlbmNlX18gYnkgX19pZGVvbG9neV9fCiAgKyByaWdodCAtLS0gQWZELCBDRFUsIENTVSwgRkRQCiAgKyBsZWZ0IC0tLSBESUUgTElOS0UsIEdSw5xORSwgU1BECisgSSAtLSB2b3RlcyBzaGFyZSBfX3BsdXJhbGl0eSB3aW5uZXJfXworIElJIC0tIHZvdGVzIHNoYXJlIF9fZGlmZmVyZW5jZSB0b3AgMl9fIHJlc3VsdHMKCgpgYGB7ciwgbWVzc2FnZT1GQUxTRX0KcGFydHlfc2NhbGUgPC0gYygiI2RlY2JlNCIsICIjYjNjZGUzIiwgIiNjY2ViYzUiLCAiI2ZmZmZjYyIsICIjZmVkOWE2IiwgIiNmYmI0YWUiKQoKaWRlb19zaGFyZSA8LSAKICBid190aWVyMSAlPiUgCiAgZ3JvdXBfYnkod2tyX25yLCBpZGVvbG9neSkgJT4lIAogIHN1bW1hcmlzZShzaGFyZSA9IHN1bShzaGFyZSkpICU+JSAKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gaWRlb2xvZ3ksIHZhbHVlc19mcm9tID0gc2hhcmUpICU+JSAKICBtdXRhdGUocmxfZGlmZiA9IHJpZ2h0IC0gbGVmdCkKCnBsX2R0IDwtIAogIHdrX3NocCAlPiUgCiAgc2VsZWN0KHdrcl9uciwgZ2VvbWV0cnkpICU+JSAKICBpbm5lcl9qb2luKGlkZW9fc2hhcmUpICU+JSAKICBpbm5lcl9qb2luKG1wICU+JSBzZWxlY3Qod2tyX25yLCBwYXJ0eSkpCgpwbDEgPC0gCiAgZ2dwbG90KCkgKyAKICBnZW9tX3NmKGRhdGEgPSBwbF9kdCwgYWVzKGZpbGwgPSBwYXJ0eSksIGx3ZCA9IDAuMDUpICsKICBjb29yZF9zZihjcnMgPSBjcnNfZGV1KSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gcGFydHlfc2NhbGUpCiMgcHJpbnQocGwxKQoKcGwyIDwtIAogIGdncGxvdCgpICsgCiAgZ2VvbV9zZihkYXRhID0gcGxfZHQsIGFlcyhmaWxsID0gcmxfZGlmZiksIGx3ZCA9IDAuMDUpICsKICBjb29yZF9zZihjcnMgPSBjcnNfZGV1KSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudDIobmFtZSA9ICJyaWdodCArLy0iKQojIHByaW50KHBsMikKCnBsMSArIHBsMiArIHBsb3RfYW5ub3RhdGlvbih0YWdfbGV2ZWxzID0gIkEiKQpgYGAKCmBgYHtyLCBtZXNzYWdlPUZBTFNFfQpkaWZmXzFfMiA8LSAKICBid190aWVyMSAlPiUgCiAgYXJyYW5nZSh3a3JfbnIsIGRlc2Moc2hhcmUpKSAlPiUgCiAgZ3JvdXBfYnkod2tyX25yKSAlPiUgCiAgZmlsdGVyKHJvd19udW1iZXIoKSAlaW4lIGMoMSwgMikpICU+JSAKICBzdW1tYXJpc2UoCiAgICB0b3BfMl9kaWZmID0gbWF4KHNoYXJlKSAtIG1pbihzaGFyZSksCiAgICBzaGFyZSA9IG1heChzaGFyZSkKICApCgpwbF9kdCA8LSAKICB3a19zaHAgJT4lIAogIHNlbGVjdCh3a3JfbnIsIGdlb21ldHJ5KSAlPiUgCiAgaW5uZXJfam9pbihkaWZmXzFfMikKCnBsMSA8LSAKICBnZ3Bsb3QoKSArIAogIGdlb21fc2YoZGF0YSA9IHBsX2R0LCBhZXMoZmlsbCA9IHNoYXJlKSwgbHdkID0gMC4wNSkgKwogIGNvb3JkX3NmKGNycyA9IGNyc19kZXUpICsKICBzY2FsZV9maWxsX3ZpcmlkaXNfYyhvcHRpb24gPSAiY2l2aWRpcyIsIGRpcmVjdGlvbiA9IC0xKQojIHByaW50KHBsMSkKCnBsMiA8LSAKICBnZ3Bsb3QoKSArIAogIGdlb21fc2YoZGF0YSA9IHBsX2R0LCBhZXMoZmlsbCA9IHRvcF8yX2RpZmYpLCBsd2QgPSAwLjA1KSArCiAgY29vcmRfc2YoY3JzID0gY3JzX2RldSkgKwogIHNjYWxlX2ZpbGxfdmlyaWRpc19jKG9wdGlvbiA9ICJtYWdtYSIsIGRpcmVjdGlvbiA9IC0xKQojIHByaW50KHBsMikKCnBsMSArIHBsMiArIHBsb3RfYW5ub3RhdGlvbih0YWdfbGV2ZWxzID0gIkkiKQpgYGAKCiMgRmVtYWxlIE1QcwoKIyMgTWFwcwoKcGx1cmFsaXR5IHdpbm5lciBjYW5kaWRhdGUgKGZpcnN0KSB0aWVyIHZvdGUgYnkgcGFydHkgYW5kIHNleAoKIyMjIEdlcm1hbnkKCmBgYHtyLCBtZXNzYWdlPUZBTFNFfQpzY2FsZV9zZXggPC0gYygicmVkIiwgImJsdWUiKQoKcGxfZHRfc2hwIDwtIHdrX3NocCAlPiUgbGVmdF9qb2luKG1wKQpwbF9kdF9jdHIgPC0gd2tfY3RyICU+JSBsZWZ0X2pvaW4obXApCgpnZ3Bsb3QoKSArIAogIGdlb21fc2YoZGF0YSA9IHBsX2R0X3NocCwgYWVzKGZpbGwgPSBwYXJ0eSksIGx3ZCA9IDAuMSkgKwogICMgc2NhbGVfZmlsbF9icmV3ZXIodHlwZSA9ICJxdWFsIiwgcGFsZXR0ZSA9IDQpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBwYXJ0eV9zY2FsZSkgKwogIGdlb21fc2YoZGF0YSA9IHBsX2R0X2N0ciwgYWVzKHNoYXBlID0gc2V4LCBjb2xvdXIgPSBzZXgpLCBhbHBoYSA9IDAuOSkgKwogIGNvb3JkX3NmKGNycyA9IGNyc19kZXUpICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IHNjYWxlX3NleCkKYGBgCgojIyMgTlJXIGFuZCBCZXJsaW4KCmBgYHtyfQpwbG90X3N0YXRlIDwtIGZ1bmN0aW9uKHN0YXRlX3NlbGVjdCwgcGFydHlfc2NhbGVfc2VsZWN0KSB7CiAgcGxfZHRfc2hwX3JlIDwtIHBsX2R0X3NocCAlPiUgZmlsdGVyKHN0YXRlID09IHN0YXRlX3NlbGVjdCkKICBwbF9kdF9jdHJfcmUgPC0gcGxfZHRfY3RyICU+JSBmaWx0ZXIoc3RhdGUgPT0gc3RhdGVfc2VsZWN0KQogIAogIGdncGxvdCgpICsgCiAgICBnZW9tX3NmKGRhdGEgPSBwbF9kdF9zaHBfcmUsIGFlcyhmaWxsID0gcGFydHkpLCBsd2QgPSAwLjIpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHBhcnR5X3NjYWxlX3NlbGVjdCkgKwogICAgZ2VvbV9zZihkYXRhID0gcGxfZHRfY3RyX3JlLCBhZXMoc2hhcGUgPSBzZXgsIGNvbG91ciA9IHNleCksIHNpemUgPSAyKSArCiAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IHNjYWxlX3NleCkgKwogICAgZ3VpZGVzKGNvbG91ciA9IEZBTFNFLCBmaWxsID0gRkFMU0UsIHNoYXBlID0gRkFMU0UpCn0KCnBsMSA8LSBwbG90X3N0YXRlKCJOVyIsIHBhcnR5X3NjYWxlW2MoMiwgNildKQpwbDIgPC0gcGxvdF9zdGF0ZSgiQkUiLCBwYXJ0eV9zY2FsZVtjKDIsIDQsIDUsIDYpXSkKIyBwbG90X3N0YXRlKCJISCIsIHBhcnR5X3NjYWxlW2MoMiwgNildKQpwbDEgKyBwbDIgKyBwbG90X2xheW91dCh3aWR0aHMgPSBjKDU1LCA0NSkpCmBgYAoKCiMjIERlc2NyaXB0aXZlcwoKbnVtYmVyIChuKSBvZiBkaXN0cmljdHMgd29uIGJ5IHBhcnR5IGFuZCBzZXggKGYgLS0gZmVtYWxlLCBtIC0tIG1hbGUpCgojIyMgUGFydHkKCmBgYHtyfQpjb3VudF9wYXJ0eSA8LSAKICBtcCAlPiUgCiAgY291bnQocGFydHksIHNleCkgJT4lIAogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBzZXgsIHZhbHVlc19mcm9tID0gbikgJT4lIAogIHJlcGxhY2UoaXMubmEoLiksIDApICU+JSAKICBtdXRhdGUoc2hhcmVfZiA9IHJvdW5kKDEwMCAqIGYgLyAobSArIGYpKSkKCmNvdW50X3BhcnR5ICU+JSBhcnJhbmdlKHNoYXJlX2YpCmBgYAoKYGBge3J9Cm1wICU+JSAKICBjb3VudChwYXJ0eSkgJT4lIAogIG11dGF0ZShzaGFyZSA9IHJvdW5kKDEwMCAqIG4gLyBzdW0obikpKSAlPiUgCiAgYXJyYW5nZShkZXNjKHNoYXJlKSkKYGBgCgoKIyMjIFN0YXRlcwoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHJvd3MucHJpbnQ9MjB9CmNvdW50X3N0YXRlIDwtIAogIG1wICU+JSAKICBsZWZ0X2pvaW4od2tfc2hwICU+JSBzZWxlY3Qod2tyX25yLCBzdGF0ZV9uYW1lID0gbGFuZF9uYW1lKSkgJT4lIAogIGNvdW50KHN0YXRlX25hbWUsIHNleCkgJT4lIAogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBzZXgsIHZhbHVlc19mcm9tID0gbikgJT4lIAogIG11dGF0ZShzaGFyZV9mID0gcm91bmQoMTAwICogZiAvIChtICsgZikpKQoKY291bnRfc3RhdGUgJT4lIGFycmFuZ2Uoc2hhcmVfZikKYGBgCgojIE1vZGVscwoKKyBhcmVhX2ttMiAtLS0gc2l6ZSBvZiBkaXN0cmljdCBhcyBzcXVhcmUgbGVuZ3RoIChyb290IG9mIGFyZWEpCisgY29vcmRfeSAtLS0gbm9ydGgvc291dGggcG9zaXRpb24gKGxhdGl0dWRlKQorIGxlZnRfc2hhcmUgLS0tIHNoYXJlIG9mIGxlZnQgcGFydGllcyAoU1BELCBMaW5rZSwgR3LDvG5lKQorIHJlZ2lvbiAtLSB3ZXN0ZXJuIG9yIGVhc3Rlcm4gKGZvcm1lciBHRFIpIHN0YXRlCgpgYGB7ciwgbWVzc2FnZT1GQUxTRX0KbGlicmFyeShicm9vbSkKbGlicmFyeShnZ2VmZmVjdHMpCgptb19kdCA8LSAgCiAgcGxfZHRfc2hwICU+JSAKICBsZWZ0X2pvaW4oaWRlb19zaGFyZSkgJT4lIAogIG11dGF0ZSgKICAgIGZlbWFsZSA9IGlmX2Vsc2Uoc2V4ID09ICJmIiwgMSwgMCksCiAgICBsZWZ0X3NoYXJlID0gbGVmdAogICAgKQpgYGAKCiMjIEZlbWFsZSBmaXJzdC10aWVyIHdpbm5lcnMKCkxvZ2l0IG1vZGVsIHRvIHByZWRpY3QgZmVtYWxlIHdpbm5lcnMgb2YgY2FuZGlkYXRlIChmaXJzdCkgdGllciB2b3RlCgpgYGB7ciwgd2FybmluZz1GQUxTRX0KbW9fZ2xtIDwtIGdsbShmZW1hbGUgfiBhcmVhX2ttMiArIGNvb3JkX3kgKyBsZWZ0X3NoYXJlLCBkYXRhID0gbW9fZHQsIGZhbWlseSA9ICJiaW5vbWlhbCIpCgp0aWR5KG1vX2dsbSkgJT4lIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYyksIHJvdW5kLCAyKSkKCnBsMSA8LSBnZ3ByZWRpY3QobW9fZ2xtLCB0ZXJtcyA9ICJhcmVhX2ttMiBbYWxsXSIpICU+JSBwbG90KGFkZC5kYXRhID0gVFJVRSwgc2hvdy50aXRsZSA9IEZBTFNFKQpwbDIgPC0gZ2dwcmVkaWN0KG1vX2dsbSwgdGVybXMgPSAiY29vcmRfeSBbYWxsXSIpICU+JSBwbG90KGFkZC5kYXRhID0gVFJVRSwgc2hvdy50aXRsZSA9IEZBTFNFKQpwbDEgKyBwbDIKYGBgCiMjIExlZnQgdm90ZS1zaGFyZQoKTGluZWFyIG1vZGVsIG9mIGxlZnQgcGFydGllcyAoU1BELCBMaW5rZSwgR3LDvG5lKSB2b3RlIHNoYXJlCgpgYGB7ciwgd2FybmluZz1GQUxTRX0KbW9fbG0gPC0gbG1fcm9idXN0KGxlZnRfc2hhcmUgfiBhcmVhX2ttMipyZWdpb24gKyBjb29yZF95KnJlZ2lvbiwgZGF0YSA9IG1vX2R0KQoKdGlkeShtb19sbSkgJT4lIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYyksIHJvdW5kLCAyKSkKCnBsMSA8LSBnZ3ByZWRpY3QobW9fbG0sIGMoImFyZWFfa20yIiwgInJlZ2lvbiIpKSAlPiUgcGxvdChhZGQuZGF0YSA9IFRSVUUsIHNob3cudGl0bGUgPSBGQUxTRSkKcGwyIDwtIGdncHJlZGljdChtb19sbSwgdGVybXMgPSBjKCJjb29yZF95IiwgInJlZ2lvbiIpKSAlPiUgcGxvdChhZGQuZGF0YSA9IFRSVUUsIHNob3cudGl0bGUgPSBGQUxTRSkKcGwxICsgcGwyCmBgYAoKIyMgUGFydHkgdm90ZS1zaGFyZQoKTGluZWFyIG1vZGVsIG9mIHBhcnR5IHZvdGUgc2hhcmUKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9Cm1vX2R0MiA8LSAgCiAgYndfdGllcjIgJT4lIAogIG11dGF0ZShwYXJ0eSA9IGlmX2Vsc2UocGFydHkgJWluJSBjKCJDRFUiLCAiQ1NVIiksICJDRFUvQ1NVIiwgcGFydHkpKSAlPiUgCiAgIyBtdXRhdGUocGFydHkgPSBmY3RfcmVsZXZlbChwYXJ0eSwgIkNEVSIpKSAlPiUgCiAgbGVmdF9qb2luKHdrX3NocCkKCm1vX2xtMiA8LSBsbV9yb2J1c3Qoc2hhcmUgfiBwYXJ0eSphcmVhX2ttMipyZWdpb24sIGRhdGEgPSBtb19kdDIpCgojIHRpZHkobW9fbG0yKSAlPiUgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSwgcm91bmQsIDIpKQoKZ2dwcmVkaWN0KG1vX2xtMiwgdGVybXMgPSBjKCAiYXJlYV9rbTIiLCAicmVnaW9uIiwgInBhcnR5IikpICU+JSAKICBwbG90KGFkZC5kYXRhID0gVFJVRSwgc2hvdy50aXRsZSA9IEZBTFNFKQpgYGAK