Introduction

This year Kaggle is launching the second annual Data Science Survey Challenge, where we will be awarding a prize pool of $30,000 to notebook authors who tell a rich story about a subset of the data science and machine learning community. Data and other information you can download here.

Some Insights

R Codes

# Clear workspace: 
rm(list = ls())

# Load package and data: 
library(tidyverse)
df_raw <- read_csv("multiple_choice_responses.csv")

# Rename for all columns: 
df_raw %>% 
  slice(1) %>% 
  as.vector() -> all_columns

str_replace_all(all_columns, " ", "_") -> new_names

df_raw %>% slice(-1) -> df_raw

names(df_raw) <- new_names


#-------------------------------------
#  Fact 1: Woman in DS/ML Community
#-------------------------------------

# Select two columns: 

df_raw %>% 
  select(c(3, 5)) %>% 
  rename(gender = `What_is_your_gender?_-_Selected_Choice`, nation = `In_which_country_do_you_currently_reside?`) -> df_gender_nation

# Top 19 nations + Vietnam by nunber of DS/ML: 

df_gender_nation %>% 
  group_by(nation) %>% 
  count() %>% 
  arrange(-n) %>% 
  ungroup() %>% 
  slice(1:19) %>% 
  pull(nation) -> top_19_nations

c(top_19_nations, "Viet Nam") -> top19_vietnam

# Relabel for some countries: 

df_gender_nation %>% 
  filter(nation %in% top19_vietnam, gender %in% c("Male", "Female")) %>% 
  mutate(nation = case_when(str_detect(nation, "United States") ~ "United States", 
                            str_detect(nation, "Kingdom") ~ "United Kingdom", 
                            TRUE ~ nation)) -> df_gender_20nations

df_gender_20nations %>% 
  group_by(gender, nation) %>% 
  count() %>% 
  ungroup() -> df1

# Calculate female rate: 

df1 %>% 
  spread(key = "gender", value = "n") %>% 
  mutate(rate = Female / (Female + Male)) %>% 
  arrange(rate) %>% 
  mutate(label = round(100*rate, 1)) %>% 
  mutate(label = as.character(label)) %>% 
  mutate(label = case_when(!str_detect(label, "\\.") ~ paste0(label, ".0"), TRUE ~ label)) %>% 
  mutate(label = paste0(label, "%")) %>% 
  mutate(nation = factor(nation, levels = nation)) -> df_rate

# Re-arrange order by female rate: 

df1 %>% 
  mutate(nation = factor(nation, levels = df_rate$nation)) -> df1_ordered


# Prepare for data visualization: 

library(extrafont)

my_colors <- c("#2E74C0", "#CB454A") # Set color. 

my_font <- "Roboto Condensed" # Set font. 

my_caption <- "Source: 2019 Kaggle ML & DS Survey" # Fix caption. 

# Fuction for creating our theme: 

my_theme <- function(...) {
  theme_minimal() + 
    theme(text = element_text(family = my_font)) + 
    theme(plot.margin = unit(rep(0.7, 4), "cm")) + 
    theme(plot.background = element_rect(fill = "#EFF2F4", color = NA)) + 
    theme(plot.title = element_text(size = 19)) + 
    theme(plot.subtitle = element_text(size = 11.7, color = "grey30")) + 
    theme(plot.caption = element_text(size = 10, color = "grey30")) + 
    theme(axis.text.x = element_text(size = 10.5, color = "grey20")) + 
    theme(axis.text.y = element_text(size = 10.5, color = "grey20")) 
  
}

# Graph presents fact 1: 

df1_ordered %>% 
  full_join(df_rate, by = "nation") %>% 
  ggplot(aes(x = nation, y = n, fill = gender)) + 
  geom_col(position = "fill") + 
  coord_flip() + 
  geom_text(aes(x = nation, y = 0.97, label = label), size = 3.8, color = "white", family = my_font) + 
  scale_fill_manual(name = "", values = c(Male = my_colors[1], Female = my_colors[2]), labels = c("Female", "Male")) + 
  scale_y_continuous(labels = paste0(seq(0, 100, 25), "%"), expand = c(0, 0)) + 
  my_theme() + 
  theme(legend.position = "top") + 
  guides(fill = guide_legend(reverse = TRUE)) + 
  theme(panel.grid.major.y = element_blank(), panel.grid.minor.x = element_blank()) + 
  theme(legend.key.height = unit(0.15, "mm"), legend.key.width = unit(5, "mm")) + 
  labs(x = NULL, y = NULL, 
       title = "Fact 1: Women in Machine Learning and Data Science Comunity", 
       subtitle = "There’s still a significant gender gap for data scientists, with 84% of users identifying as males.\nThe United States has a slightly smaller gender gap at 79%, while Japan has a slightly higher one at 90%.", 
       caption = my_caption)


#--------------------------------
#  Fact 2: Age group by gender
#--------------------------------

df_raw %>% 
  group_by(`What_is_your_age_(#_years)?`, `What_is_your_gender?_-_Selected_Choice`) %>% 
  count() %>% 
  ungroup() -> df_age_gender

names(df_age_gender) <- c("age_group", "gender", "n")

df_age_gender %>% 
  filter(gender %in% c("Male", "Female")) -> df_age_gender

df_age_gender$age_group %>% unique() -> age_groups

df_age_gender %>% 
  mutate(age_group = factor(age_group, levels = age_groups)) %>% 
  mutate(n = as.numeric(n)) %>% 
  mutate(n_new = case_when(gender == "Male" ~ -1*n, TRUE ~ n)) -> df_age_gender

df_age_gender %>% 
  ggplot(aes(age_group, n_new, fill = gender)) + 
  geom_col() + 
  coord_flip() + 
  my_theme() + 
  scale_fill_manual(name = "", values = c(Male = my_colors[1], Female = my_colors[2]), labels = c("Female", "Male")) + 
  theme(legend.position = "top") + 
  guides(fill = guide_legend(reverse = TRUE)) + 
  theme(panel.grid.major.y = element_blank(), panel.grid.minor.x = element_blank()) + 
  theme(legend.key.height = unit(0.15, "mm"), legend.key.width = unit(5, "mm")) + 
  scale_y_continuous(breaks = seq(-4000, 1000, 500), labels = c(seq(4000, 500, -500), seq(0, 1000, 500))) + 
  theme(panel.grid.major.x = element_line(color = "grey50", linetype = "dotted")) + 
  labs(x = NULL, y = NULL, 
       title = "Fact 2: Age Distribution by Gender", 
       subtitle = "Millennials dominate data science, with 25-29 year olds being the most common age group.", 
       caption = my_caption)

#----------------------------------------------------
#      Fact 3: Popular Platforms for learing DS
#----------------------------------------------------

df_raw %>% 
  select(contains("On_which_platforms_have_you_begun_or_completed_data_science_courses")) %>% 
  gather(question, platform) %>% 
  filter(!is.na(platform)) %>% 
  group_by(platform) %>% 
  count() %>% 
  arrange(-n) %>% 
  ungroup() %>% 
  filter(platform != "-1") %>% 
  slice(1:12) -> df_platform

df_platform %>% pull(platform) -> top12_platform

df_raw %>% 
  select(3, contains("On_which_platforms_have_you_begun_or_completed_data_science_courses")) %>% 
  gather(question, platform, -`What_is_your_gender?_-_Selected_Choice`) %>% 
  filter(!is.na(platform)) -> gender_platforms

names(gender_platforms) <- c("gender", "question", "platform")

gender_platforms %>% 
  filter(platform %in% top12_platform) %>% 
  filter(gender %in% c("Male", "Female")) %>% 
  group_by(gender, platform) %>% 
  count() %>% 
  ungroup() %>% 
  mutate(platform = case_when(str_detect(platform, "Univer") ~ "University", 
                              str_detect(platform, "Kaggle") ~ "Kaggle", 
                              str_detect(platform, "Link") ~ "Linkin", 
                              TRUE ~ platform)) -> gender_platforms_count


df_platform %>% 
  mutate(platform = case_when(str_detect(platform, "Univer") ~ "University", 
                              str_detect(platform, "Kaggle") ~ "Kaggle", 
                              str_detect(platform, "Link") ~ "Linkin", 
                              TRUE ~ platform)) -> df_platform


gender_platforms_count %>% 
  mutate(platform = factor(platform, levels = df_platform$platform)) %>% 
  mutate(n = as.numeric(n)) %>% 
  mutate(n_new = case_when(gender == "Male" ~ -1*n, TRUE ~ n)) %>%  
  ggplot(aes(platform, n_new, fill = gender)) + 
  geom_col() + 
  coord_flip() + 
  my_theme() + 
  scale_fill_manual(name = "", values = c(Male = my_colors[1], Female = my_colors[2]), labels = c("Female", "Male")) + 
  theme(legend.position = "top") + 
  guides(fill = guide_legend(reverse = TRUE)) + 
  theme(panel.grid.major.y = element_blank(), panel.grid.minor.x = element_blank()) + 
  theme(legend.key.height = unit(0.15, "mm"), legend.key.width = unit(5, "mm")) + 
  scale_y_continuous(breaks = seq(-7500, 1500, 500), labels = c(seq(7500, 0, -500), seq(500, 1500, 500))) + 
  theme(panel.grid.major.x = element_line(color = "grey50", linetype = "dotted")) + 
  labs(x = NULL, y = NULL, 
       title = "Fact 3: Top Sources for Learning Data Science Skills/Courses", 
       subtitle = "Coursera, Kaggle and Udemy are the most popular sources for learning Data Science.", 
       caption = my_caption)
LS0tDQp0aXRsZTogJzIwMTkgS2FnZ2xlIE1MICYgRFMgU3VydmV5IChQYXJ0IDEpJw0KYXV0aG9yOiAnQXV0aG9yOiBOZ3V5ZW4gQ2hpIER1bmcnDQpzdWJ0aXRsZTogIkRhaWx5IEdyYXBoIFNlcmllcyINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDogDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgICMgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgaGlnaGxpZ2h0OiB6ZW5idXJuDQogICAgIyBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIHRoZW1lOiAiZmxhdGx5Ig0KICAgIHRvYzogVFJVRQ0KICAgIHRvY19mbG9hdDogVFJVRQ0KLS0tDQoNCmBgYHtyIHNldHVwLGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFLCBjYWNoZSA9IFRSVUUpDQoNCmBgYA0KDQoNCiMgSW50cm9kdWN0aW9uDQoNClRoaXMgeWVhciBLYWdnbGUgaXMgbGF1bmNoaW5nIHRoZSBzZWNvbmQgYW5udWFsIERhdGEgU2NpZW5jZSBTdXJ2ZXkgQ2hhbGxlbmdlLCB3aGVyZSB3ZSB3aWxsIGJlIGF3YXJkaW5nIGEgcHJpemUgcG9vbCBvZiAkMzAsMDAwIHRvIG5vdGVib29rIGF1dGhvcnMgd2hvIHRlbGwgYSByaWNoIHN0b3J5IGFib3V0IGEgc3Vic2V0IG9mIHRoZSBkYXRhIHNjaWVuY2UgYW5kIG1hY2hpbmUgbGVhcm5pbmcgY29tbXVuaXR5LiBEYXRhIGFuZCBvdGhlciBpbmZvcm1hdGlvbiB5b3UgY2FuIGRvd25sb2FkIFtoZXJlXShodHRwczovL3d3dy5rYWdnbGUuY29tL2Mva2FnZ2xlLXN1cnZleS0yMDE5KS4gDQoNCiMgU29tZSBJbnNpZ2h0cyANCg0KIVtdKEM6XFxVc2Vyc1xcQWRtaW5cXERvY3VtZW50c1xca2FnZ2xlMS5qcGcpDQohW10oQzpcXFVzZXJzXFxBZG1pblxcRG9jdW1lbnRzXFxrYWdnbGUyLmpwZykNCiFbXShDOlxcVXNlcnNcXEFkbWluXFxEb2N1bWVudHNcXGthZ2dsZTMuanBnKQ0KDQojIFIgQ29kZXMNCg0KYGBge3IsIGV2YWw9RkFMU0V9DQoNCiMgQ2xlYXIgd29ya3NwYWNlOiANCnJtKGxpc3QgPSBscygpKQ0KDQojIExvYWQgcGFja2FnZSBhbmQgZGF0YTogDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmRmX3JhdyA8LSByZWFkX2NzdigibXVsdGlwbGVfY2hvaWNlX3Jlc3BvbnNlcy5jc3YiKQ0KDQojIFJlbmFtZSBmb3IgYWxsIGNvbHVtbnM6IA0KZGZfcmF3ICU+JSANCiAgc2xpY2UoMSkgJT4lIA0KICBhcy52ZWN0b3IoKSAtPiBhbGxfY29sdW1ucw0KDQpzdHJfcmVwbGFjZV9hbGwoYWxsX2NvbHVtbnMsICIgIiwgIl8iKSAtPiBuZXdfbmFtZXMNCg0KZGZfcmF3ICU+JSBzbGljZSgtMSkgLT4gZGZfcmF3DQoNCm5hbWVzKGRmX3JhdykgPC0gbmV3X25hbWVzDQoNCg0KIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgIEZhY3QgMTogV29tYW4gaW4gRFMvTUwgQ29tbXVuaXR5DQojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQojIFNlbGVjdCB0d28gY29sdW1uczogDQoNCmRmX3JhdyAlPiUgDQogIHNlbGVjdChjKDMsIDUpKSAlPiUgDQogIHJlbmFtZShnZW5kZXIgPSBgV2hhdF9pc195b3VyX2dlbmRlcj9fLV9TZWxlY3RlZF9DaG9pY2VgLCBuYXRpb24gPSBgSW5fd2hpY2hfY291bnRyeV9kb195b3VfY3VycmVudGx5X3Jlc2lkZT9gKSAtPiBkZl9nZW5kZXJfbmF0aW9uDQoNCiMgVG9wIDE5IG5hdGlvbnMgKyBWaWV0bmFtIGJ5IG51bmJlciBvZiBEUy9NTDogDQoNCmRmX2dlbmRlcl9uYXRpb24gJT4lIA0KICBncm91cF9ieShuYXRpb24pICU+JSANCiAgY291bnQoKSAlPiUgDQogIGFycmFuZ2UoLW4pICU+JSANCiAgdW5ncm91cCgpICU+JSANCiAgc2xpY2UoMToxOSkgJT4lIA0KICBwdWxsKG5hdGlvbikgLT4gdG9wXzE5X25hdGlvbnMNCg0KYyh0b3BfMTlfbmF0aW9ucywgIlZpZXQgTmFtIikgLT4gdG9wMTlfdmlldG5hbQ0KDQojIFJlbGFiZWwgZm9yIHNvbWUgY291bnRyaWVzOiANCg0KZGZfZ2VuZGVyX25hdGlvbiAlPiUgDQogIGZpbHRlcihuYXRpb24gJWluJSB0b3AxOV92aWV0bmFtLCBnZW5kZXIgJWluJSBjKCJNYWxlIiwgIkZlbWFsZSIpKSAlPiUgDQogIG11dGF0ZShuYXRpb24gPSBjYXNlX3doZW4oc3RyX2RldGVjdChuYXRpb24sICJVbml0ZWQgU3RhdGVzIikgfiAiVW5pdGVkIFN0YXRlcyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cl9kZXRlY3QobmF0aW9uLCAiS2luZ2RvbSIpIH4gIlVuaXRlZCBLaW5nZG9tIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IG5hdGlvbikpIC0+IGRmX2dlbmRlcl8yMG5hdGlvbnMNCg0KZGZfZ2VuZGVyXzIwbmF0aW9ucyAlPiUgDQogIGdyb3VwX2J5KGdlbmRlciwgbmF0aW9uKSAlPiUgDQogIGNvdW50KCkgJT4lIA0KICB1bmdyb3VwKCkgLT4gZGYxDQoNCiMgQ2FsY3VsYXRlIGZlbWFsZSByYXRlOiANCg0KZGYxICU+JSANCiAgc3ByZWFkKGtleSA9ICJnZW5kZXIiLCB2YWx1ZSA9ICJuIikgJT4lIA0KICBtdXRhdGUocmF0ZSA9IEZlbWFsZSAvIChGZW1hbGUgKyBNYWxlKSkgJT4lIA0KICBhcnJhbmdlKHJhdGUpICU+JSANCiAgbXV0YXRlKGxhYmVsID0gcm91bmQoMTAwKnJhdGUsIDEpKSAlPiUgDQogIG11dGF0ZShsYWJlbCA9IGFzLmNoYXJhY3RlcihsYWJlbCkpICU+JSANCiAgbXV0YXRlKGxhYmVsID0gY2FzZV93aGVuKCFzdHJfZGV0ZWN0KGxhYmVsLCAiXFwuIikgfiBwYXN0ZTAobGFiZWwsICIuMCIpLCBUUlVFIH4gbGFiZWwpKSAlPiUgDQogIG11dGF0ZShsYWJlbCA9IHBhc3RlMChsYWJlbCwgIiUiKSkgJT4lIA0KICBtdXRhdGUobmF0aW9uID0gZmFjdG9yKG5hdGlvbiwgbGV2ZWxzID0gbmF0aW9uKSkgLT4gZGZfcmF0ZQ0KDQojIFJlLWFycmFuZ2Ugb3JkZXIgYnkgZmVtYWxlIHJhdGU6IA0KDQpkZjEgJT4lIA0KICBtdXRhdGUobmF0aW9uID0gZmFjdG9yKG5hdGlvbiwgbGV2ZWxzID0gZGZfcmF0ZSRuYXRpb24pKSAtPiBkZjFfb3JkZXJlZA0KDQoNCiMgUHJlcGFyZSBmb3IgZGF0YSB2aXN1YWxpemF0aW9uOiANCg0KbGlicmFyeShleHRyYWZvbnQpDQoNCm15X2NvbG9ycyA8LSBjKCIjMkU3NEMwIiwgIiNDQjQ1NEEiKSAjIFNldCBjb2xvci4gDQoNCm15X2ZvbnQgPC0gIlJvYm90byBDb25kZW5zZWQiICMgU2V0IGZvbnQuIA0KDQpteV9jYXB0aW9uIDwtICJTb3VyY2U6IDIwMTkgS2FnZ2xlIE1MICYgRFMgU3VydmV5IiAjIEZpeCBjYXB0aW9uLiANCg0KIyBGdWN0aW9uIGZvciBjcmVhdGluZyBvdXIgdGhlbWU6IA0KDQpteV90aGVtZSA8LSBmdW5jdGlvbiguLi4pIHsNCiAgdGhlbWVfbWluaW1hbCgpICsgDQogICAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSBteV9mb250KSkgKyANCiAgICB0aGVtZShwbG90Lm1hcmdpbiA9IHVuaXQocmVwKDAuNywgNCksICJjbSIpKSArIA0KICAgIHRoZW1lKHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIiNFRkYyRjQiLCBjb2xvciA9IE5BKSkgKyANCiAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOSkpICsgDQogICAgdGhlbWUocGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTEuNywgY29sb3IgPSAiZ3JleTMwIikpICsgDQogICAgdGhlbWUocGxvdC5jYXB0aW9uID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCwgY29sb3IgPSAiZ3JleTMwIikpICsgDQogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwLjUsIGNvbG9yID0gImdyZXkyMCIpKSArIA0KICAgIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMC41LCBjb2xvciA9ICJncmV5MjAiKSkgDQogIA0KfQ0KDQojIEdyYXBoIHByZXNlbnRzIGZhY3QgMTogDQoNCmRmMV9vcmRlcmVkICU+JSANCiAgZnVsbF9qb2luKGRmX3JhdGUsIGJ5ID0gIm5hdGlvbiIpICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gbmF0aW9uLCB5ID0gbiwgZmlsbCA9IGdlbmRlcikpICsgDQogIGdlb21fY29sKHBvc2l0aW9uID0gImZpbGwiKSArIA0KICBjb29yZF9mbGlwKCkgKyANCiAgZ2VvbV90ZXh0KGFlcyh4ID0gbmF0aW9uLCB5ID0gMC45NywgbGFiZWwgPSBsYWJlbCksIHNpemUgPSAzLjgsIGNvbG9yID0gIndoaXRlIiwgZmFtaWx5ID0gbXlfZm9udCkgKyANCiAgc2NhbGVfZmlsbF9tYW51YWwobmFtZSA9ICIiLCB2YWx1ZXMgPSBjKE1hbGUgPSBteV9jb2xvcnNbMV0sIEZlbWFsZSA9IG15X2NvbG9yc1syXSksIGxhYmVscyA9IGMoIkZlbWFsZSIsICJNYWxlIikpICsgDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBwYXN0ZTAoc2VxKDAsIDEwMCwgMjUpLCAiJSIpLCBleHBhbmQgPSBjKDAsIDApKSArIA0KICBteV90aGVtZSgpICsgDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKSArIA0KICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZChyZXZlcnNlID0gVFJVRSkpICsgDQogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKSwgcGFuZWwuZ3JpZC5taW5vci54ID0gZWxlbWVudF9ibGFuaygpKSArIA0KICB0aGVtZShsZWdlbmQua2V5LmhlaWdodCA9IHVuaXQoMC4xNSwgIm1tIiksIGxlZ2VuZC5rZXkud2lkdGggPSB1bml0KDUsICJtbSIpKSArIA0KICBsYWJzKHggPSBOVUxMLCB5ID0gTlVMTCwgDQogICAgICAgdGl0bGUgPSAiRmFjdCAxOiBXb21lbiBpbiBNYWNoaW5lIExlYXJuaW5nIGFuZCBEYXRhIFNjaWVuY2UgQ29tdW5pdHkiLCANCiAgICAgICBzdWJ0aXRsZSA9ICJUaGVyZeKAmXMgc3RpbGwgYSBzaWduaWZpY2FudCBnZW5kZXIgZ2FwIGZvciBkYXRhIHNjaWVudGlzdHMsIHdpdGggODQlIG9mIHVzZXJzIGlkZW50aWZ5aW5nIGFzIG1hbGVzLlxuVGhlIFVuaXRlZCBTdGF0ZXMgaGFzIGEgc2xpZ2h0bHkgc21hbGxlciBnZW5kZXIgZ2FwIGF0IDc5JSwgd2hpbGUgSmFwYW4gaGFzIGEgc2xpZ2h0bHkgaGlnaGVyIG9uZSBhdCA5MCUuIiwgDQogICAgICAgY2FwdGlvbiA9IG15X2NhcHRpb24pDQoNCg0KIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojICBGYWN0IDI6IEFnZSBncm91cCBieSBnZW5kZXINCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQpkZl9yYXcgJT4lIA0KICBncm91cF9ieShgV2hhdF9pc195b3VyX2FnZV8oI195ZWFycyk/YCwgYFdoYXRfaXNfeW91cl9nZW5kZXI/Xy1fU2VsZWN0ZWRfQ2hvaWNlYCkgJT4lIA0KICBjb3VudCgpICU+JSANCiAgdW5ncm91cCgpIC0+IGRmX2FnZV9nZW5kZXINCg0KbmFtZXMoZGZfYWdlX2dlbmRlcikgPC0gYygiYWdlX2dyb3VwIiwgImdlbmRlciIsICJuIikNCg0KZGZfYWdlX2dlbmRlciAlPiUgDQogIGZpbHRlcihnZW5kZXIgJWluJSBjKCJNYWxlIiwgIkZlbWFsZSIpKSAtPiBkZl9hZ2VfZ2VuZGVyDQoNCmRmX2FnZV9nZW5kZXIkYWdlX2dyb3VwICU+JSB1bmlxdWUoKSAtPiBhZ2VfZ3JvdXBzDQoNCmRmX2FnZV9nZW5kZXIgJT4lIA0KICBtdXRhdGUoYWdlX2dyb3VwID0gZmFjdG9yKGFnZV9ncm91cCwgbGV2ZWxzID0gYWdlX2dyb3VwcykpICU+JSANCiAgbXV0YXRlKG4gPSBhcy5udW1lcmljKG4pKSAlPiUgDQogIG11dGF0ZShuX25ldyA9IGNhc2Vfd2hlbihnZW5kZXIgPT0gIk1hbGUiIH4gLTEqbiwgVFJVRSB+IG4pKSAtPiBkZl9hZ2VfZ2VuZGVyDQoNCmRmX2FnZV9nZW5kZXIgJT4lIA0KICBnZ3Bsb3QoYWVzKGFnZV9ncm91cCwgbl9uZXcsIGZpbGwgPSBnZW5kZXIpKSArIA0KICBnZW9tX2NvbCgpICsgDQogIGNvb3JkX2ZsaXAoKSArIA0KICBteV90aGVtZSgpICsgDQogIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWUgPSAiIiwgdmFsdWVzID0gYyhNYWxlID0gbXlfY29sb3JzWzFdLCBGZW1hbGUgPSBteV9jb2xvcnNbMl0pLCBsYWJlbHMgPSBjKCJGZW1hbGUiLCAiTWFsZSIpKSArIA0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikgKyANCiAgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQocmV2ZXJzZSA9IFRSVUUpKSArIA0KICB0aGVtZShwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2JsYW5rKCksIHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSkgKyANCiAgdGhlbWUobGVnZW5kLmtleS5oZWlnaHQgPSB1bml0KDAuMTUsICJtbSIpLCBsZWdlbmQua2V5LndpZHRoID0gdW5pdCg1LCAibW0iKSkgKyANCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgtNDAwMCwgMTAwMCwgNTAwKSwgbGFiZWxzID0gYyhzZXEoNDAwMCwgNTAwLCAtNTAwKSwgc2VxKDAsIDEwMDAsIDUwMCkpKSArIA0KICB0aGVtZShwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2xpbmUoY29sb3IgPSAiZ3JleTUwIiwgbGluZXR5cGUgPSAiZG90dGVkIikpICsgDQogIGxhYnMoeCA9IE5VTEwsIHkgPSBOVUxMLCANCiAgICAgICB0aXRsZSA9ICJGYWN0IDI6IEFnZSBEaXN0cmlidXRpb24gYnkgR2VuZGVyIiwgDQogICAgICAgc3VidGl0bGUgPSAiTWlsbGVubmlhbHMgZG9taW5hdGUgZGF0YSBzY2llbmNlLCB3aXRoIDI1LTI5IHllYXIgb2xkcyBiZWluZyB0aGUgbW9zdCBjb21tb24gYWdlIGdyb3VwLiIsIA0KICAgICAgIGNhcHRpb24gPSBteV9jYXB0aW9uKQ0KDQojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyAgICAgIEZhY3QgMzogUG9wdWxhciBQbGF0Zm9ybXMgZm9yIGxlYXJpbmcgRFMNCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCmRmX3JhdyAlPiUgDQogIHNlbGVjdChjb250YWlucygiT25fd2hpY2hfcGxhdGZvcm1zX2hhdmVfeW91X2JlZ3VuX29yX2NvbXBsZXRlZF9kYXRhX3NjaWVuY2VfY291cnNlcyIpKSAlPiUgDQogIGdhdGhlcihxdWVzdGlvbiwgcGxhdGZvcm0pICU+JSANCiAgZmlsdGVyKCFpcy5uYShwbGF0Zm9ybSkpICU+JSANCiAgZ3JvdXBfYnkocGxhdGZvcm0pICU+JSANCiAgY291bnQoKSAlPiUgDQogIGFycmFuZ2UoLW4pICU+JSANCiAgdW5ncm91cCgpICU+JSANCiAgZmlsdGVyKHBsYXRmb3JtICE9ICItMSIpICU+JSANCiAgc2xpY2UoMToxMikgLT4gZGZfcGxhdGZvcm0NCg0KZGZfcGxhdGZvcm0gJT4lIHB1bGwocGxhdGZvcm0pIC0+IHRvcDEyX3BsYXRmb3JtDQoNCmRmX3JhdyAlPiUgDQogIHNlbGVjdCgzLCBjb250YWlucygiT25fd2hpY2hfcGxhdGZvcm1zX2hhdmVfeW91X2JlZ3VuX29yX2NvbXBsZXRlZF9kYXRhX3NjaWVuY2VfY291cnNlcyIpKSAlPiUgDQogIGdhdGhlcihxdWVzdGlvbiwgcGxhdGZvcm0sIC1gV2hhdF9pc195b3VyX2dlbmRlcj9fLV9TZWxlY3RlZF9DaG9pY2VgKSAlPiUgDQogIGZpbHRlcighaXMubmEocGxhdGZvcm0pKSAtPiBnZW5kZXJfcGxhdGZvcm1zDQoNCm5hbWVzKGdlbmRlcl9wbGF0Zm9ybXMpIDwtIGMoImdlbmRlciIsICJxdWVzdGlvbiIsICJwbGF0Zm9ybSIpDQoNCmdlbmRlcl9wbGF0Zm9ybXMgJT4lIA0KICBmaWx0ZXIocGxhdGZvcm0gJWluJSB0b3AxMl9wbGF0Zm9ybSkgJT4lIA0KICBmaWx0ZXIoZ2VuZGVyICVpbiUgYygiTWFsZSIsICJGZW1hbGUiKSkgJT4lIA0KICBncm91cF9ieShnZW5kZXIsIHBsYXRmb3JtKSAlPiUgDQogIGNvdW50KCkgJT4lIA0KICB1bmdyb3VwKCkgJT4lIA0KICBtdXRhdGUocGxhdGZvcm0gPSBjYXNlX3doZW4oc3RyX2RldGVjdChwbGF0Zm9ybSwgIlVuaXZlciIpIH4gIlVuaXZlcnNpdHkiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cl9kZXRlY3QocGxhdGZvcm0sICJLYWdnbGUiKSB+ICJLYWdnbGUiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cl9kZXRlY3QocGxhdGZvcm0sICJMaW5rIikgfiAiTGlua2luIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gcGxhdGZvcm0pKSAtPiBnZW5kZXJfcGxhdGZvcm1zX2NvdW50DQoNCg0KZGZfcGxhdGZvcm0gJT4lIA0KICBtdXRhdGUocGxhdGZvcm0gPSBjYXNlX3doZW4oc3RyX2RldGVjdChwbGF0Zm9ybSwgIlVuaXZlciIpIH4gIlVuaXZlcnNpdHkiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cl9kZXRlY3QocGxhdGZvcm0sICJLYWdnbGUiKSB+ICJLYWdnbGUiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cl9kZXRlY3QocGxhdGZvcm0sICJMaW5rIikgfiAiTGlua2luIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gcGxhdGZvcm0pKSAtPiBkZl9wbGF0Zm9ybQ0KDQoNCmdlbmRlcl9wbGF0Zm9ybXNfY291bnQgJT4lIA0KICBtdXRhdGUocGxhdGZvcm0gPSBmYWN0b3IocGxhdGZvcm0sIGxldmVscyA9IGRmX3BsYXRmb3JtJHBsYXRmb3JtKSkgJT4lIA0KICBtdXRhdGUobiA9IGFzLm51bWVyaWMobikpICU+JSANCiAgbXV0YXRlKG5fbmV3ID0gY2FzZV93aGVuKGdlbmRlciA9PSAiTWFsZSIgfiAtMSpuLCBUUlVFIH4gbikpICU+JSAgDQogIGdncGxvdChhZXMocGxhdGZvcm0sIG5fbmV3LCBmaWxsID0gZ2VuZGVyKSkgKyANCiAgZ2VvbV9jb2woKSArIA0KICBjb29yZF9mbGlwKCkgKyANCiAgbXlfdGhlbWUoKSArIA0KICBzY2FsZV9maWxsX21hbnVhbChuYW1lID0gIiIsIHZhbHVlcyA9IGMoTWFsZSA9IG15X2NvbG9yc1sxXSwgRmVtYWxlID0gbXlfY29sb3JzWzJdKSwgbGFiZWxzID0gYygiRmVtYWxlIiwgIk1hbGUiKSkgKyANCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpICsgDQogIGd1aWRlcyhmaWxsID0gZ3VpZGVfbGVnZW5kKHJldmVyc2UgPSBUUlVFKSkgKyANCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9ibGFuaygpLCBwYW5lbC5ncmlkLm1pbm9yLnggPSBlbGVtZW50X2JsYW5rKCkpICsgDQogIHRoZW1lKGxlZ2VuZC5rZXkuaGVpZ2h0ID0gdW5pdCgwLjE1LCAibW0iKSwgbGVnZW5kLmtleS53aWR0aCA9IHVuaXQoNSwgIm1tIikpICsgDQogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoLTc1MDAsIDE1MDAsIDUwMCksIGxhYmVscyA9IGMoc2VxKDc1MDAsIDAsIC01MDApLCBzZXEoNTAwLCAxNTAwLCA1MDApKSkgKyANCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9saW5lKGNvbG9yID0gImdyZXk1MCIsIGxpbmV0eXBlID0gImRvdHRlZCIpKSArIA0KICBsYWJzKHggPSBOVUxMLCB5ID0gTlVMTCwgDQogICAgICAgdGl0bGUgPSAiRmFjdCAzOiBUb3AgU291cmNlcyBmb3IgTGVhcm5pbmcgRGF0YSBTY2llbmNlIFNraWxscy9Db3Vyc2VzIiwgDQogICAgICAgc3VidGl0bGUgPSAiQ291cnNlcmEsIEthZ2dsZSBhbmQgVWRlbXkgYXJlIHRoZSBtb3N0IHBvcHVsYXIgc291cmNlcyBmb3IgbGVhcm5pbmcgRGF0YSBTY2llbmNlLiIsIA0KICAgICAgIGNhcHRpb24gPSBteV9jYXB0aW9uKQ0KDQpgYGANCg0KDQo=