Vietnam War Casualties

Estimates of casualties of the Vietnam War vary widely. Estimates include both civilian and military deaths in North and South Vietnam, Laos, and Cambodia.

The war persisted from 1955 to 1975 and most of the fighting took place in South Vietnam; accordingly it suffered the most casualties. The war also spilled over into the neighboring countries of Cambodia and Laos which also endured casualties from aerial and ground fighting.

Civilian deaths caused by both sides amounted to a significant percentage of total deaths. Civilian deaths were partly caused by assassinations, massacres and terror tactics. Civilian deaths were also caused by mortar and artillery, extensive aerial bombing and the use of firepower in military operations conducted in heavily populated areas. Some 365,000 Vietnamese civilians are estimated by one source to have died as a result of the war during the period of American involvement.

A number of incidents occurred during the war in which civilians were deliberately targeted or killed. The best-known are the Massacre at Huế and the My Lai massacre.

According to The Virtual Wall Vietnam Veterans Memorial, the number of U.S casualties during Vietnam War was 58,226.

Collecting Data for 58,226 US Deaths

In this section I present R codes for collecting detailed data (first name, last name, gender, death date, category, birth date, service number, rank, death location, and other information) for 58,226 US Deaths during Vietnam War.

# https://www.honorstates.org/index.php?page=wars&war=Vietnam+Conflict&do=states
# https://laahgp.genealogyvillage.com/MilitaryIndex/vietnam-war-causalities.html
# https://www.jstor.org/stable/2137774?seq=1#page_scan_tab_contents
# https://www.nwitimes.com/the-region-fallen-of-the-vietnam-war/table_1f7fde93-a183-5f1c-ae69-ccac4fdebb5e.html
# http://www.vietnammemorial.com/vietnam-memorial-list-of-heroes.html
# Korean https://www.vvmf.org/Wall-of-Faces/?fbclid=IwAR3JJi8fPklR5QtfRHGfN0oxaDjf4uuHmHFDxulYqICS1aBuzjJIrEmKIqs


# Load some R packages and clear workspace:

rm(list = ls())
library(rvest)
library(xml2)
library(tidyverse)

#=============================================
#    Stage 1:  Get links for all soldiers
#=============================================


get_panel_link <- function(url) {
  
  # Create an html document from the url: 
  webpage <- xml2::read_html(url)
  
  # Extract the URLs: 
  url_ <- webpage %>%
    rvest::html_nodes("a") %>%
    rvest::html_attr("href")
  
  # Extract the link text: 
  link_ <- webpage %>%
    rvest::html_nodes("a") %>%
    rvest::html_text()
  return(data_frame(link = link_, url = url_))
}


all_panels <- "http://www.virtualwall.org/iPanels.htm"
panel_links <- get_panel_link(all_panels)


# All suffixes: 

all_suffix <- panel_links$url[str_detect(panel_links$url, "iPanels/ipan")] %>% na.omit()
all_suffix <- str_sub(all_suffix, start = 2, end = str_count(all_suffix))
all_names_InPanel <- paste0("http://www.virtualwall.org", all_suffix)


# All soldier links: 

get_link_for_soldiers <- function(panel_selected) {
  
  soldier_suffix <- get_panel_link(panel_selected)
  
  soldier_suffix %>% 
    filter(!str_detect(url, "misspelledname")) %>% 
    filter(!str_detect(url, "noscriptIndexMenu")) %>% 
    filter(!str_detect(url, "index")) %>% 
    filter(!str_detect(url, "ipan")) %>% 
    mutate(url = paste0("http://www.VirtualWall.org", str_sub(url, start = 3, end = str_count(url)))) %>% 
    rename(name = link, link_for_soldier = url) %>% 
    return()
  
}


lapply(all_names_InPanel, get_link_for_soldiers) -> link_soldiers_list
do.call("bind_rows", link_soldiers_list) -> df_link_soldiers

df_link_soldiers %>% 
  filter(!duplicated(link_for_soldier)) -> df_link_soldiers


# Save our data: 

write.csv(df_link_soldiers, "df_link_soldiers.csv", row.names = FALSE)

#=============================================
#    Stage 2:  Get data for all soldiers
#=============================================

# Function for collecting all from a soldier: 

collect_all_DataSoldier <- function(my_link) {
  
  pg <- read_html(my_link)
  
  html_text(pg, trim = TRUE) %>% 
    str_split("\\\n", simplify = TRUE) %>% 
    as.character() %>% 
    str_squish() %>% 
    .[3:27] -> m
  
  
  m %>% 
    str_split("\\/", simplify = TRUE) %>% 
    data.frame() %>% 
    mutate_all(as.character) -> df
  
  
  df_date <- df %>% 
    slice(c(17:19)) %>% 
    mutate(my_date = paste0(X1, X2, X3)) %>% 
    select(my_date, X5)
  
  t(df_date %>% select(my_date)) %>% 
    as.data.frame() -> df_date_soldier
  
  names(df_date_soldier) <- c("birth", "start", "cas_date")
  

  df_remain <- df %>% 
    slice(-c(17:19)) %>% 
    select(X1, X3)
  
  t(df_remain %>% select(X1)) %>% 
    as.data.frame() -> df
  
  
  names(df) <- c(df_remain$X3[1:2], "notKnown", "Grade_at_loss", df_remain$X3[5:22])   
  all_data_soldier <- bind_cols(df, df_date_soldier)
  return(all_data_soldier %>% mutate(link = my_link))
  
}

get_SoldierData <- function(link_selected) {
  return(tryCatch(collect_all_DataSoldier(link_selected), error = function(e) {NULL}))
}


# Use this function: 

df_link_soldiers <- read_csv("df_link_soldiers.csv")
soldier_links <- df_link_soldiers$link_for_soldier
lapply(soldier_links, get_SoldierData) -> all_data_list
save(all_data_list, file = "all_data_list.RData")

do.call("bind_rows", all_data_list) %>% 
  select(-V1) -> all_data_df

# Save our data: 
write.csv(all_data_df, "all_us_deaths_in_Vietnam_war.csv", row.names = FALSE)

US Fatal Deaths by Military Rank

#==================================================
#  Stage 3: Data-preprocessing and visualization
#==================================================

library(tidyverse)

# Import data: 
all_data_df <- read_csv("C:\\Users\\Zbook\\Documents\\all_us_deaths_in_Vietnam_war.csv")

all_data_df %>% 
  select(1:26) -> df_USdeaths


library(hrbrthemes)
library(scales)
my_colors <- c("#3E606F")
my_font <- "Roboto Condensed"


my_cleanText1 <- function(x) {
  str_replace_all(x, "[^A-Za-z]", " ") %>% 
    str_squish() %>% 
    return()
}



df_USdeaths %>% 
  mutate(Rank = my_cleanText1(Rank)) %>% 
  group_by(Rank) %>% 
  count() %>% 
  ungroup() %>% 
  top_n(20, n) %>% 
  arrange(n) %>% 
  mutate(Rank = factor(Rank, levels = Rank)) %>% 
  mutate(label = comma_format()(n)) -> deaths_byRank

deaths_byRank %>% 
  ggplot(aes(Rank, n)) + 
  geom_col(width = 0.8, fill = "firebrick", color = "firebrick") + 
  coord_flip() + 
  theme_ft_rc() + 
  scale_y_continuous(expand = c(0.015, 0)) + 
  theme(panel.grid = element_blank()) + 
  theme(axis.text.x = element_blank()) + 
  theme(axis.text.y = element_text(color = "white", size = 14, family = my_font)) + 
  theme(plot.margin = unit(c(1.2, 1.2, 1.2, 1.2), "cm")) + 
  geom_text(aes(label = label), hjust = -0.2, color = "white", size = 5, family = my_font) + 
  geom_text(data = deaths_byRank %>% slice(which.max(n)), aes(label = label), hjust = 1.1, color = "white", size = 5, family = my_font) + 
  theme(plot.title = element_text(size = 23)) + 
  theme(plot.subtitle = element_text(size = 14, color = "grey90")) + 
  theme(plot.caption = element_text(size = 12, face = "italic")) + 
  labs(x = NULL, y = NULL, 
       title = "Figure 1: US Fatal Deaths by Military Rank", 
       subtitle = "Note: For top 20 by number of deaths.", 
       caption = "Data Source: http://www.virtualwall.org")

US Fatal Deaths by Location

df_USdeaths %>% 
  mutate(location = my_cleanText1(location)) %>% 
  mutate(location1 = case_when(str_detect(location, "North Vietnam") ~ paste0("X Province", location), 
                               str_detect(location, "Cambodia") ~ paste0("Cambodia Province", location), 
                               str_detect(location, "Laos") ~ paste0("Laos Province", location), 
                               str_detect(location, "Thailand") ~ paste0("Thailand Province", location), 
                               str_detect(location, "China") ~ paste0("China Province", location), 
                               str_detect(location, "not reported") ~ paste0("Unknown Province", location), 
                               TRUE ~ location)) -> df_USdeaths_location1


df_USdeaths_location1 %>% 
  filter(str_detect(location1, "Province")) %>% 
  pull(location1) %>% 
  str_split("Province", simplify = TRUE) %>% 
  as.data.frame() %>% 
  mutate_all(as.character) %>% 
  mutate_all(str_squish) %>% 
  rename(Province = V1) %>% 
  mutate(Province = case_when(str_detect(Province, "X") ~ "North Vietnam", TRUE ~ Province)) %>% 
  group_by(Province) %>% 
  count() %>% 
  ungroup() %>% 
  arrange(n) %>% 
  mutate(Province = factor(Province, levels = Province)) %>% 
  mutate(bar_color = case_when(str_detect(Province, "North Vietnam") ~ my_colors, 
                               str_detect(Province, "Laos") ~ my_colors,
                               str_detect(Province, "Cambodia") ~ my_colors, 
                               str_detect(Province, "Thailand") ~ my_colors, 
                               TRUE ~ "firebrick")) %>% 
  mutate(label = comma_format()(n)) -> df_death_byProvince



df_death_byProvince %>% 
  ggplot(aes(Province, n)) + 
  geom_col(width = 0.8, fill = "firebrick", color = "firebrick") + 
  coord_flip() + 
  theme_ft_rc() + 
  scale_y_continuous(expand = c(0.01, 0)) + 
  theme(panel.grid = element_blank()) + 
  theme(axis.text.x = element_blank()) + 
  theme(axis.text.y = element_text(color = "white", size = 11, family = my_font)) + 
  theme(plot.margin = unit(c(1.2, 1.2, 1.2, 1.2), "cm")) + 
  geom_text(data = df_death_byProvince %>% slice(1:45), aes(label = label), hjust = -0.2, color = "white", size = 3.5, family = my_font) + 
  geom_text(data = df_death_byProvince %>% slice(46:48), aes(label = label), hjust = 1.1, color = "white", size = 3.5, family = my_font) + 
  theme(plot.title = element_text(size = 23)) + 
  theme(plot.subtitle = element_text(size = 14, color = "grey90")) + 
  theme(plot.caption = element_text(size = 12, face = "italic")) + 
  labs(x = NULL, y = NULL, 
       title = "Figure 2: US Fatal Deaths by Location", 
       subtitle = "Note: Unverified Locations are labelled as Unknown.", 
       caption = "Data Source: http://www.virtualwall.org")

Reflections Of My Life

The changing

Of sunlight to moonlight

Reflections of my life

Oh how they fill my eyes

The greetings

Of people in trouble

Reflections of my life

Oh how they fill my eyes

All my sorrows

Sad tomorrows

Take me back to my own home

All my cryings

Feel I’m dying, dying

Take me back to my own home

I’m changing, arranging

I’m changing, I’m changing everything

Oh, everything around me

The world is a bad place

A bad place, a terrible place to live

Oh, but I don’t wanna die

All my sorrows

Sad tomorrows

Take me back to my own home

All my cryings

Feel I’m dying, dying

Take me back to my own home

All my sorrows

Sad tomorrows

Take me back to my own home

All my cryings…

To Be Continued

LS0tDQp0aXRsZTogIlVTIE1pbGl0YXJ5IEZhdGFsIENhc3VhbHRpZXMgRHVyaW5nIHRoZSBWaWV0bmFtIFdhciINCnN1YnRpdGxlOiAiRGFpbHkgR3JhcGggU2VyaWVzIg0KYXV0aG9yOiAiTmd1eWVuIENoaSBEdW5nIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGhpZ2hsaWdodDogemVuYnVybg0KICAgIHRoZW1lOiBmbGF0bHkNCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDogeWVzDQogIHdvcmRfZG9jdW1lbnQ6DQogICAgdG9jOiB5ZXMNCi0tLQ0KDQpgYGB7ciBzZXR1cCxpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSwgZmlnLnJldGluYT0yKQ0KYGBgDQoNCg0KIVtdKEM6XFxVc2Vyc1xcWmJvb2tcXERlc2t0b3BcXHBpY1xcd2FyMTEuanBnKQ0KDQojIFZpZXRuYW0gV2FyIENhc3VhbHRpZXMNCg0KDQpFc3RpbWF0ZXMgb2YgY2FzdWFsdGllcyBvZiB0aGUgVmlldG5hbSBXYXIgdmFyeSB3aWRlbHkuIEVzdGltYXRlcyBpbmNsdWRlIGJvdGggY2l2aWxpYW4gYW5kIG1pbGl0YXJ5IGRlYXRocyBpbiBOb3J0aCBhbmQgU291dGggVmlldG5hbSwgTGFvcywgYW5kIENhbWJvZGlhLg0KDQpUaGUgd2FyIHBlcnNpc3RlZCBmcm9tIDE5NTUgdG8gMTk3NSBhbmQgbW9zdCBvZiB0aGUgZmlnaHRpbmcgdG9vayBwbGFjZSBpbiBTb3V0aCBWaWV0bmFtOyBhY2NvcmRpbmdseSBpdCBzdWZmZXJlZCB0aGUgbW9zdCBjYXN1YWx0aWVzLiBUaGUgd2FyIGFsc28gc3BpbGxlZCBvdmVyIGludG8gdGhlIG5laWdoYm9yaW5nIGNvdW50cmllcyBvZiBDYW1ib2RpYSBhbmQgTGFvcyB3aGljaCBhbHNvIGVuZHVyZWQgY2FzdWFsdGllcyBmcm9tIGFlcmlhbCBhbmQgZ3JvdW5kIGZpZ2h0aW5nLg0KDQpDaXZpbGlhbiBkZWF0aHMgY2F1c2VkIGJ5IGJvdGggc2lkZXMgYW1vdW50ZWQgdG8gYSBzaWduaWZpY2FudCBwZXJjZW50YWdlIG9mIHRvdGFsIGRlYXRocy4gQ2l2aWxpYW4gZGVhdGhzIHdlcmUgcGFydGx5IGNhdXNlZCBieSBhc3Nhc3NpbmF0aW9ucywgbWFzc2FjcmVzIGFuZCB0ZXJyb3IgdGFjdGljcy4gQ2l2aWxpYW4gZGVhdGhzIHdlcmUgYWxzbyBjYXVzZWQgYnkgbW9ydGFyIGFuZCBhcnRpbGxlcnksIGV4dGVuc2l2ZSBhZXJpYWwgYm9tYmluZyBhbmQgdGhlIHVzZSBvZiBmaXJlcG93ZXIgaW4gbWlsaXRhcnkgb3BlcmF0aW9ucyBjb25kdWN0ZWQgaW4gaGVhdmlseSBwb3B1bGF0ZWQgYXJlYXMuIFNvbWUgMzY1LDAwMCBWaWV0bmFtZXNlIGNpdmlsaWFucyBhcmUgZXN0aW1hdGVkIGJ5IG9uZSBzb3VyY2UgdG8gaGF2ZSBkaWVkIGFzIGEgcmVzdWx0IG9mIHRoZSB3YXIgZHVyaW5nIHRoZSBwZXJpb2Qgb2YgQW1lcmljYW4gaW52b2x2ZW1lbnQuDQoNCkEgbnVtYmVyIG9mIGluY2lkZW50cyBvY2N1cnJlZCBkdXJpbmcgdGhlIHdhciBpbiB3aGljaCBjaXZpbGlhbnMgd2VyZSBkZWxpYmVyYXRlbHkgdGFyZ2V0ZWQgb3Iga2lsbGVkLiBUaGUgYmVzdC1rbm93biBhcmUgdGhlIE1hc3NhY3JlIGF0IEh14bq/IGFuZCB0aGUgTXkgTGFpIG1hc3NhY3JlLg0KDQpBY2NvcmRpbmcgdG8gW1RoZSBWaXJ0dWFsIFdhbGwgVmlldG5hbSBWZXRlcmFucyBNZW1vcmlhbF0oaHR0cDovL3d3dy52aXJ0dWFsd2FsbC5vcmcvKSwgdGhlIG51bWJlciBvZiBVLlMgY2FzdWFsdGllcyBkdXJpbmcgVmlldG5hbSBXYXIgd2FzIDU4LDIyNi4gDQoNCiMgQ29sbGVjdGluZyBEYXRhIGZvciA1OCwyMjYgVVMgRGVhdGhzDQoNCkluIHRoaXMgc2VjdGlvbiBJIHByZXNlbnQgUiBjb2RlcyBmb3IgY29sbGVjdGluZyBkZXRhaWxlZCBkYXRhIChmaXJzdCBuYW1lLCBsYXN0IG5hbWUsIGdlbmRlciwgZGVhdGggZGF0ZSwgY2F0ZWdvcnksIGJpcnRoIGRhdGUsIHNlcnZpY2UgbnVtYmVyLCByYW5rLCBkZWF0aCBsb2NhdGlvbiwgYW5kIG90aGVyIGluZm9ybWF0aW9uKSBmb3IgNTgsMjI2IFVTIERlYXRocyBkdXJpbmcgVmlldG5hbSBXYXIuIA0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCg0KIyBodHRwczovL3d3dy5ob25vcnN0YXRlcy5vcmcvaW5kZXgucGhwP3BhZ2U9d2FycyZ3YXI9VmlldG5hbStDb25mbGljdCZkbz1zdGF0ZXMNCiMgaHR0cHM6Ly9sYWFoZ3AuZ2VuZWFsb2d5dmlsbGFnZS5jb20vTWlsaXRhcnlJbmRleC92aWV0bmFtLXdhci1jYXVzYWxpdGllcy5odG1sDQojIGh0dHBzOi8vd3d3LmpzdG9yLm9yZy9zdGFibGUvMjEzNzc3ND9zZXE9MSNwYWdlX3NjYW5fdGFiX2NvbnRlbnRzDQojIGh0dHBzOi8vd3d3Lm53aXRpbWVzLmNvbS90aGUtcmVnaW9uLWZhbGxlbi1vZi10aGUtdmlldG5hbS13YXIvdGFibGVfMWY3ZmRlOTMtYTE4My01ZjFjLWFlNjktY2NhYzRmZGViYjVlLmh0bWwNCiMgaHR0cDovL3d3dy52aWV0bmFtbWVtb3JpYWwuY29tL3ZpZXRuYW0tbWVtb3JpYWwtbGlzdC1vZi1oZXJvZXMuaHRtbA0KIyBLb3JlYW4gaHR0cHM6Ly93d3cudnZtZi5vcmcvV2FsbC1vZi1GYWNlcy8/ZmJjbGlkPUl3QVIzSkppOGZQa2xSNVF0ZlJIR2ZOMG94YURqZjR1dUhtSEZEeHVsWXFJQ1MxYUJ1empKSXJFbUtJcXMNCg0KDQojIExvYWQgc29tZSBSIHBhY2thZ2VzIGFuZCBjbGVhciB3b3Jrc3BhY2U6DQoNCnJtKGxpc3QgPSBscygpKQ0KbGlicmFyeShydmVzdCkNCmxpYnJhcnkoeG1sMikNCmxpYnJhcnkodGlkeXZlcnNlKQ0KDQojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojICAgIFN0YWdlIDE6ICBHZXQgbGlua3MgZm9yIGFsbCBzb2xkaWVycw0KIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KDQoNCmdldF9wYW5lbF9saW5rIDwtIGZ1bmN0aW9uKHVybCkgew0KICANCiAgIyBDcmVhdGUgYW4gaHRtbCBkb2N1bWVudCBmcm9tIHRoZSB1cmw6IA0KICB3ZWJwYWdlIDwtIHhtbDI6OnJlYWRfaHRtbCh1cmwpDQogIA0KICAjIEV4dHJhY3QgdGhlIFVSTHM6IA0KICB1cmxfIDwtIHdlYnBhZ2UgJT4lDQogICAgcnZlc3Q6Omh0bWxfbm9kZXMoImEiKSAlPiUNCiAgICBydmVzdDo6aHRtbF9hdHRyKCJocmVmIikNCiAgDQogICMgRXh0cmFjdCB0aGUgbGluayB0ZXh0OiANCiAgbGlua18gPC0gd2VicGFnZSAlPiUNCiAgICBydmVzdDo6aHRtbF9ub2RlcygiYSIpICU+JQ0KICAgIHJ2ZXN0OjpodG1sX3RleHQoKQ0KICByZXR1cm4oZGF0YV9mcmFtZShsaW5rID0gbGlua18sIHVybCA9IHVybF8pKQ0KfQ0KDQoNCmFsbF9wYW5lbHMgPC0gImh0dHA6Ly93d3cudmlydHVhbHdhbGwub3JnL2lQYW5lbHMuaHRtIg0KcGFuZWxfbGlua3MgPC0gZ2V0X3BhbmVsX2xpbmsoYWxsX3BhbmVscykNCg0KDQojIEFsbCBzdWZmaXhlczogDQoNCmFsbF9zdWZmaXggPC0gcGFuZWxfbGlua3MkdXJsW3N0cl9kZXRlY3QocGFuZWxfbGlua3MkdXJsLCAiaVBhbmVscy9pcGFuIildICU+JSBuYS5vbWl0KCkNCmFsbF9zdWZmaXggPC0gc3RyX3N1YihhbGxfc3VmZml4LCBzdGFydCA9IDIsIGVuZCA9IHN0cl9jb3VudChhbGxfc3VmZml4KSkNCmFsbF9uYW1lc19JblBhbmVsIDwtIHBhc3RlMCgiaHR0cDovL3d3dy52aXJ0dWFsd2FsbC5vcmciLCBhbGxfc3VmZml4KQ0KDQoNCiMgQWxsIHNvbGRpZXIgbGlua3M6IA0KDQpnZXRfbGlua19mb3Jfc29sZGllcnMgPC0gZnVuY3Rpb24ocGFuZWxfc2VsZWN0ZWQpIHsNCiAgDQogIHNvbGRpZXJfc3VmZml4IDwtIGdldF9wYW5lbF9saW5rKHBhbmVsX3NlbGVjdGVkKQ0KICANCiAgc29sZGllcl9zdWZmaXggJT4lIA0KICAgIGZpbHRlcighc3RyX2RldGVjdCh1cmwsICJtaXNzcGVsbGVkbmFtZSIpKSAlPiUgDQogICAgZmlsdGVyKCFzdHJfZGV0ZWN0KHVybCwgIm5vc2NyaXB0SW5kZXhNZW51IikpICU+JSANCiAgICBmaWx0ZXIoIXN0cl9kZXRlY3QodXJsLCAiaW5kZXgiKSkgJT4lIA0KICAgIGZpbHRlcighc3RyX2RldGVjdCh1cmwsICJpcGFuIikpICU+JSANCiAgICBtdXRhdGUodXJsID0gcGFzdGUwKCJodHRwOi8vd3d3LlZpcnR1YWxXYWxsLm9yZyIsIHN0cl9zdWIodXJsLCBzdGFydCA9IDMsIGVuZCA9IHN0cl9jb3VudCh1cmwpKSkpICU+JSANCiAgICByZW5hbWUobmFtZSA9IGxpbmssIGxpbmtfZm9yX3NvbGRpZXIgPSB1cmwpICU+JSANCiAgICByZXR1cm4oKQ0KICANCn0NCg0KDQpsYXBwbHkoYWxsX25hbWVzX0luUGFuZWwsIGdldF9saW5rX2Zvcl9zb2xkaWVycykgLT4gbGlua19zb2xkaWVyc19saXN0DQpkby5jYWxsKCJiaW5kX3Jvd3MiLCBsaW5rX3NvbGRpZXJzX2xpc3QpIC0+IGRmX2xpbmtfc29sZGllcnMNCg0KZGZfbGlua19zb2xkaWVycyAlPiUgDQogIGZpbHRlcighZHVwbGljYXRlZChsaW5rX2Zvcl9zb2xkaWVyKSkgLT4gZGZfbGlua19zb2xkaWVycw0KDQoNCiMgU2F2ZSBvdXIgZGF0YTogDQoNCndyaXRlLmNzdihkZl9saW5rX3NvbGRpZXJzLCAiZGZfbGlua19zb2xkaWVycy5jc3YiLCByb3cubmFtZXMgPSBGQUxTRSkNCg0KIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KIyAgICBTdGFnZSAyOiAgR2V0IGRhdGEgZm9yIGFsbCBzb2xkaWVycw0KIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KDQojIEZ1bmN0aW9uIGZvciBjb2xsZWN0aW5nIGFsbCBmcm9tIGEgc29sZGllcjogDQoNCmNvbGxlY3RfYWxsX0RhdGFTb2xkaWVyIDwtIGZ1bmN0aW9uKG15X2xpbmspIHsNCiAgDQogIHBnIDwtIHJlYWRfaHRtbChteV9saW5rKQ0KICANCiAgaHRtbF90ZXh0KHBnLCB0cmltID0gVFJVRSkgJT4lIA0KICAgIHN0cl9zcGxpdCgiXFxcbiIsIHNpbXBsaWZ5ID0gVFJVRSkgJT4lIA0KICAgIGFzLmNoYXJhY3RlcigpICU+JSANCiAgICBzdHJfc3F1aXNoKCkgJT4lIA0KICAgIC5bMzoyN10gLT4gbQ0KICANCiAgDQogIG0gJT4lIA0KICAgIHN0cl9zcGxpdCgiXFwvIiwgc2ltcGxpZnkgPSBUUlVFKSAlPiUgDQogICAgZGF0YS5mcmFtZSgpICU+JSANCiAgICBtdXRhdGVfYWxsKGFzLmNoYXJhY3RlcikgLT4gZGYNCiAgDQogIA0KICBkZl9kYXRlIDwtIGRmICU+JSANCiAgICBzbGljZShjKDE3OjE5KSkgJT4lIA0KICAgIG11dGF0ZShteV9kYXRlID0gcGFzdGUwKFgxLCBYMiwgWDMpKSAlPiUgDQogICAgc2VsZWN0KG15X2RhdGUsIFg1KQ0KICANCiAgdChkZl9kYXRlICU+JSBzZWxlY3QobXlfZGF0ZSkpICU+JSANCiAgICBhcy5kYXRhLmZyYW1lKCkgLT4gZGZfZGF0ZV9zb2xkaWVyDQogIA0KICBuYW1lcyhkZl9kYXRlX3NvbGRpZXIpIDwtIGMoImJpcnRoIiwgInN0YXJ0IiwgImNhc19kYXRlIikNCiAgDQoNCiAgZGZfcmVtYWluIDwtIGRmICU+JSANCiAgICBzbGljZSgtYygxNzoxOSkpICU+JSANCiAgICBzZWxlY3QoWDEsIFgzKQ0KICANCiAgdChkZl9yZW1haW4gJT4lIHNlbGVjdChYMSkpICU+JSANCiAgICBhcy5kYXRhLmZyYW1lKCkgLT4gZGYNCiAgDQogIA0KICBuYW1lcyhkZikgPC0gYyhkZl9yZW1haW4kWDNbMToyXSwgIm5vdEtub3duIiwgIkdyYWRlX2F0X2xvc3MiLCBkZl9yZW1haW4kWDNbNToyMl0pICAgDQogIGFsbF9kYXRhX3NvbGRpZXIgPC0gYmluZF9jb2xzKGRmLCBkZl9kYXRlX3NvbGRpZXIpDQogIHJldHVybihhbGxfZGF0YV9zb2xkaWVyICU+JSBtdXRhdGUobGluayA9IG15X2xpbmspKQ0KICANCn0NCg0KZ2V0X1NvbGRpZXJEYXRhIDwtIGZ1bmN0aW9uKGxpbmtfc2VsZWN0ZWQpIHsNCiAgcmV0dXJuKHRyeUNhdGNoKGNvbGxlY3RfYWxsX0RhdGFTb2xkaWVyKGxpbmtfc2VsZWN0ZWQpLCBlcnJvciA9IGZ1bmN0aW9uKGUpIHtOVUxMfSkpDQp9DQoNCg0KIyBVc2UgdGhpcyBmdW5jdGlvbjogDQoNCmRmX2xpbmtfc29sZGllcnMgPC0gcmVhZF9jc3YoImRmX2xpbmtfc29sZGllcnMuY3N2IikNCnNvbGRpZXJfbGlua3MgPC0gZGZfbGlua19zb2xkaWVycyRsaW5rX2Zvcl9zb2xkaWVyDQpsYXBwbHkoc29sZGllcl9saW5rcywgZ2V0X1NvbGRpZXJEYXRhKSAtPiBhbGxfZGF0YV9saXN0DQpzYXZlKGFsbF9kYXRhX2xpc3QsIGZpbGUgPSAiYWxsX2RhdGFfbGlzdC5SRGF0YSIpDQoNCmRvLmNhbGwoImJpbmRfcm93cyIsIGFsbF9kYXRhX2xpc3QpICU+JSANCiAgc2VsZWN0KC1WMSkgLT4gYWxsX2RhdGFfZGYNCg0KIyBTYXZlIG91ciBkYXRhOiANCndyaXRlLmNzdihhbGxfZGF0YV9kZiwgImFsbF91c19kZWF0aHNfaW5fVmlldG5hbV93YXIuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpDQpgYGANCg0KIyBVUyBGYXRhbCBEZWF0aHMgYnkgTWlsaXRhcnkgUmFuaw0KDQohW10oQzpcXFVzZXJzXFxaYm9va1xcRGVza3RvcFxccGljXFx3MS5qcGcpDQoNCg0KYGBge3IsIGV2YWw9RkFMU0V9DQojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCiMgIFN0YWdlIDM6IERhdGEtcHJlcHJvY2Vzc2luZyBhbmQgdmlzdWFsaXphdGlvbg0KIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQoNCmxpYnJhcnkodGlkeXZlcnNlKQ0KDQojIEltcG9ydCBkYXRhOiANCmFsbF9kYXRhX2RmIDwtIHJlYWRfY3N2KCJDOlxcVXNlcnNcXFpib29rXFxEb2N1bWVudHNcXGFsbF91c19kZWF0aHNfaW5fVmlldG5hbV93YXIuY3N2IikNCg0KYWxsX2RhdGFfZGYgJT4lIA0KICBzZWxlY3QoMToyNikgLT4gZGZfVVNkZWF0aHMNCg0KDQpsaWJyYXJ5KGhyYnJ0aGVtZXMpDQpsaWJyYXJ5KHNjYWxlcykNCm15X2NvbG9ycyA8LSBjKCIjM0U2MDZGIikNCm15X2ZvbnQgPC0gIlJvYm90byBDb25kZW5zZWQiDQoNCg0KbXlfY2xlYW5UZXh0MSA8LSBmdW5jdGlvbih4KSB7DQogIHN0cl9yZXBsYWNlX2FsbCh4LCAiW15BLVphLXpdIiwgIiAiKSAlPiUgDQogICAgc3RyX3NxdWlzaCgpICU+JSANCiAgICByZXR1cm4oKQ0KfQ0KDQoNCg0KZGZfVVNkZWF0aHMgJT4lIA0KICBtdXRhdGUoUmFuayA9IG15X2NsZWFuVGV4dDEoUmFuaykpICU+JSANCiAgZ3JvdXBfYnkoUmFuaykgJT4lIA0KICBjb3VudCgpICU+JSANCiAgdW5ncm91cCgpICU+JSANCiAgdG9wX24oMjAsIG4pICU+JSANCiAgYXJyYW5nZShuKSAlPiUgDQogIG11dGF0ZShSYW5rID0gZmFjdG9yKFJhbmssIGxldmVscyA9IFJhbmspKSAlPiUgDQogIG11dGF0ZShsYWJlbCA9IGNvbW1hX2Zvcm1hdCgpKG4pKSAtPiBkZWF0aHNfYnlSYW5rDQoNCmRlYXRoc19ieVJhbmsgJT4lIA0KICBnZ3Bsb3QoYWVzKFJhbmssIG4pKSArIA0KICBnZW9tX2NvbCh3aWR0aCA9IDAuOCwgZmlsbCA9ICJmaXJlYnJpY2siLCBjb2xvciA9ICJmaXJlYnJpY2siKSArIA0KICBjb29yZF9mbGlwKCkgKyANCiAgdGhlbWVfZnRfcmMoKSArIA0KICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLjAxNSwgMCkpICsgDQogIHRoZW1lKHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCkpICsgDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKSArIA0KICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChjb2xvciA9ICJ3aGl0ZSIsIHNpemUgPSAxNCwgZmFtaWx5ID0gbXlfZm9udCkpICsgDQogIHRoZW1lKHBsb3QubWFyZ2luID0gdW5pdChjKDEuMiwgMS4yLCAxLjIsIDEuMiksICJjbSIpKSArIA0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gbGFiZWwpLCBoanVzdCA9IC0wLjIsIGNvbG9yID0gIndoaXRlIiwgc2l6ZSA9IDUsIGZhbWlseSA9IG15X2ZvbnQpICsgDQogIGdlb21fdGV4dChkYXRhID0gZGVhdGhzX2J5UmFuayAlPiUgc2xpY2Uod2hpY2gubWF4KG4pKSwgYWVzKGxhYmVsID0gbGFiZWwpLCBoanVzdCA9IDEuMSwgY29sb3IgPSAid2hpdGUiLCBzaXplID0gNSwgZmFtaWx5ID0gbXlfZm9udCkgKyANCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjMpKSArIA0KICB0aGVtZShwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgY29sb3IgPSAiZ3JleTkwIikpICsgDQogIHRoZW1lKHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGZhY2UgPSAiaXRhbGljIikpICsgDQogIGxhYnMoeCA9IE5VTEwsIHkgPSBOVUxMLCANCiAgICAgICB0aXRsZSA9ICJGaWd1cmUgMTogVVMgRmF0YWwgRGVhdGhzIGJ5IE1pbGl0YXJ5IFJhbmsiLCANCiAgICAgICBzdWJ0aXRsZSA9ICJOb3RlOiBGb3IgdG9wIDIwIGJ5IG51bWJlciBvZiBkZWF0aHMuIiwgDQogICAgICAgY2FwdGlvbiA9ICJEYXRhIFNvdXJjZTogaHR0cDovL3d3dy52aXJ0dWFsd2FsbC5vcmciKQ0KDQoNCmBgYA0KDQojIFVTIEZhdGFsIERlYXRocyBieSBMb2NhdGlvbg0KDQohW10oQzpcXFVzZXJzXFxaYm9va1xcRGVza3RvcFxccGljXFx3Mi5qcGcpDQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KZGZfVVNkZWF0aHMgJT4lIA0KICBtdXRhdGUobG9jYXRpb24gPSBteV9jbGVhblRleHQxKGxvY2F0aW9uKSkgJT4lIA0KICBtdXRhdGUobG9jYXRpb24xID0gY2FzZV93aGVuKHN0cl9kZXRlY3QobG9jYXRpb24sICJOb3J0aCBWaWV0bmFtIikgfiBwYXN0ZTAoIlggUHJvdmluY2UiLCBsb2NhdGlvbiksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cl9kZXRlY3QobG9jYXRpb24sICJDYW1ib2RpYSIpIH4gcGFzdGUwKCJDYW1ib2RpYSBQcm92aW5jZSIsIGxvY2F0aW9uKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyX2RldGVjdChsb2NhdGlvbiwgIkxhb3MiKSB+IHBhc3RlMCgiTGFvcyBQcm92aW5jZSIsIGxvY2F0aW9uKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyX2RldGVjdChsb2NhdGlvbiwgIlRoYWlsYW5kIikgfiBwYXN0ZTAoIlRoYWlsYW5kIFByb3ZpbmNlIiwgbG9jYXRpb24pLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJfZGV0ZWN0KGxvY2F0aW9uLCAiQ2hpbmEiKSB+IHBhc3RlMCgiQ2hpbmEgUHJvdmluY2UiLCBsb2NhdGlvbiksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cl9kZXRlY3QobG9jYXRpb24sICJub3QgcmVwb3J0ZWQiKSB+IHBhc3RlMCgiVW5rbm93biBQcm92aW5jZSIsIGxvY2F0aW9uKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IGxvY2F0aW9uKSkgLT4gZGZfVVNkZWF0aHNfbG9jYXRpb24xDQoNCg0KZGZfVVNkZWF0aHNfbG9jYXRpb24xICU+JSANCiAgZmlsdGVyKHN0cl9kZXRlY3QobG9jYXRpb24xLCAiUHJvdmluY2UiKSkgJT4lIA0KICBwdWxsKGxvY2F0aW9uMSkgJT4lIA0KICBzdHJfc3BsaXQoIlByb3ZpbmNlIiwgc2ltcGxpZnkgPSBUUlVFKSAlPiUgDQogIGFzLmRhdGEuZnJhbWUoKSAlPiUgDQogIG11dGF0ZV9hbGwoYXMuY2hhcmFjdGVyKSAlPiUgDQogIG11dGF0ZV9hbGwoc3RyX3NxdWlzaCkgJT4lIA0KICByZW5hbWUoUHJvdmluY2UgPSBWMSkgJT4lIA0KICBtdXRhdGUoUHJvdmluY2UgPSBjYXNlX3doZW4oc3RyX2RldGVjdChQcm92aW5jZSwgIlgiKSB+ICJOb3J0aCBWaWV0bmFtIiwgVFJVRSB+IFByb3ZpbmNlKSkgJT4lIA0KICBncm91cF9ieShQcm92aW5jZSkgJT4lIA0KICBjb3VudCgpICU+JSANCiAgdW5ncm91cCgpICU+JSANCiAgYXJyYW5nZShuKSAlPiUgDQogIG11dGF0ZShQcm92aW5jZSA9IGZhY3RvcihQcm92aW5jZSwgbGV2ZWxzID0gUHJvdmluY2UpKSAlPiUgDQogIG11dGF0ZShiYXJfY29sb3IgPSBjYXNlX3doZW4oc3RyX2RldGVjdChQcm92aW5jZSwgIk5vcnRoIFZpZXRuYW0iKSB+IG15X2NvbG9ycywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyX2RldGVjdChQcm92aW5jZSwgIkxhb3MiKSB+IG15X2NvbG9ycywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJfZGV0ZWN0KFByb3ZpbmNlLCAiQ2FtYm9kaWEiKSB+IG15X2NvbG9ycywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyX2RldGVjdChQcm92aW5jZSwgIlRoYWlsYW5kIikgfiBteV9jb2xvcnMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAiZmlyZWJyaWNrIikpICU+JSANCiAgbXV0YXRlKGxhYmVsID0gY29tbWFfZm9ybWF0KCkobikpIC0+IGRmX2RlYXRoX2J5UHJvdmluY2UNCg0KDQoNCmRmX2RlYXRoX2J5UHJvdmluY2UgJT4lIA0KICBnZ3Bsb3QoYWVzKFByb3ZpbmNlLCBuKSkgKyANCiAgZ2VvbV9jb2wod2lkdGggPSAwLjgsIGZpbGwgPSAiZmlyZWJyaWNrIiwgY29sb3IgPSAiZmlyZWJyaWNrIikgKyANCiAgY29vcmRfZmxpcCgpICsgDQogIHRoZW1lX2Z0X3JjKCkgKyANCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMC4wMSwgMCkpICsgDQogIHRoZW1lKHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCkpICsgDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKSArIA0KICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChjb2xvciA9ICJ3aGl0ZSIsIHNpemUgPSAxMSwgZmFtaWx5ID0gbXlfZm9udCkpICsgDQogIHRoZW1lKHBsb3QubWFyZ2luID0gdW5pdChjKDEuMiwgMS4yLCAxLjIsIDEuMiksICJjbSIpKSArIA0KICBnZW9tX3RleHQoZGF0YSA9IGRmX2RlYXRoX2J5UHJvdmluY2UgJT4lIHNsaWNlKDE6NDUpLCBhZXMobGFiZWwgPSBsYWJlbCksIGhqdXN0ID0gLTAuMiwgY29sb3IgPSAid2hpdGUiLCBzaXplID0gMy41LCBmYW1pbHkgPSBteV9mb250KSArIA0KICBnZW9tX3RleHQoZGF0YSA9IGRmX2RlYXRoX2J5UHJvdmluY2UgJT4lIHNsaWNlKDQ2OjQ4KSwgYWVzKGxhYmVsID0gbGFiZWwpLCBoanVzdCA9IDEuMSwgY29sb3IgPSAid2hpdGUiLCBzaXplID0gMy41LCBmYW1pbHkgPSBteV9mb250KSArIA0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMykpICsgDQogIHRoZW1lKHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LCBjb2xvciA9ICJncmV5OTAiKSkgKyANCiAgdGhlbWUocGxvdC5jYXB0aW9uID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJpdGFsaWMiKSkgKyANCiAgbGFicyh4ID0gTlVMTCwgeSA9IE5VTEwsIA0KICAgICAgIHRpdGxlID0gIkZpZ3VyZSAyOiBVUyBGYXRhbCBEZWF0aHMgYnkgTG9jYXRpb24iLCANCiAgICAgICBzdWJ0aXRsZSA9ICJOb3RlOiBVbnZlcmlmaWVkIExvY2F0aW9ucyBhcmUgbGFiZWxsZWQgYXMgVW5rbm93bi4iLCANCiAgICAgICBjYXB0aW9uID0gIkRhdGEgU291cmNlOiBodHRwOi8vd3d3LnZpcnR1YWx3YWxsLm9yZyIpDQoNCg0KYGBgDQoNCiMgUmVmbGVjdGlvbnMgT2YgTXkgTGlmZQ0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCmxpYnJhcnkodmVtYmVkcikNCmVtYmVkX3VybCgiaHR0cHM6Ly93d3cueW91dHViZS5jb20vd2F0Y2g/dj1fMWxJQU5SSk5iQSIpDQpgYGANCg0KVGhlIGNoYW5naW5nDQoNCk9mIHN1bmxpZ2h0IHRvIG1vb25saWdodA0KDQpSZWZsZWN0aW9ucyBvZiBteSBsaWZlDQoNCk9oIGhvdyB0aGV5IGZpbGwgbXkgZXllcw0KDQpUaGUgZ3JlZXRpbmdzDQoNCk9mIHBlb3BsZSBpbiB0cm91YmxlDQoNClJlZmxlY3Rpb25zIG9mIG15IGxpZmUNCg0KT2ggaG93IHRoZXkgZmlsbCBteSBleWVzDQoNCkFsbCBteSBzb3Jyb3dzDQoNClNhZCB0b21vcnJvd3MNCg0KVGFrZSBtZSBiYWNrIHRvIG15IG93biBob21lDQoNCkFsbCBteSBjcnlpbmdzDQoNCkZlZWwgSSdtIGR5aW5nLCBkeWluZw0KDQpUYWtlIG1lIGJhY2sgdG8gbXkgb3duIGhvbWUNCg0KSSdtIGNoYW5naW5nLCBhcnJhbmdpbmcNCg0KSSdtIGNoYW5naW5nLCBJJ20gY2hhbmdpbmcgZXZlcnl0aGluZw0KDQpPaCwgZXZlcnl0aGluZyBhcm91bmQgbWUNCg0KVGhlIHdvcmxkIGlzIGEgYmFkIHBsYWNlDQoNCkEgYmFkIHBsYWNlLCBhIHRlcnJpYmxlIHBsYWNlIHRvIGxpdmUNCg0KT2gsIGJ1dCBJIGRvbid0IHdhbm5hIGRpZQ0KDQpBbGwgbXkgc29ycm93cw0KDQpTYWQgdG9tb3Jyb3dzDQoNClRha2UgbWUgYmFjayB0byBteSBvd24gaG9tZQ0KDQpBbGwgbXkgY3J5aW5ncw0KDQpGZWVsIEknbSBkeWluZywgZHlpbmcNCg0KVGFrZSBtZSBiYWNrIHRvIG15IG93biBob21lDQoNCkFsbCBteSBzb3Jyb3dzDQoNClNhZCB0b21vcnJvd3MNCg0KVGFrZSBtZSBiYWNrIHRvIG15IG93biBob21lDQoNCkFsbCBteSBjcnlpbmdzLi4uDQoNCiMgVG8gQmUgQ29udGludWVkDQoNCg0K