Mini case 1: Simple visualisation using ggplot2

In this section, I will combine both data wrangling and data visualisation.

# packages installations

my_packages <- c("tidyverse", "ggthemes", "ggplot2", "extrafont", "stringr")

install.packages(my_packages, repos = "http://cran.rstudio.com")
## package 'tidyverse' successfully unpacked and MD5 sums checked
## package 'ggthemes' successfully unpacked and MD5 sums checked
## package 'ggplot2' successfully unpacked and MD5 sums checked
## package 'extrafont' successfully unpacked and MD5 sums checked
## package 'stringr' successfully unpacked and MD5 sums checked
## 
## The downloaded binary packages are in
##  C:\Users\mlcl.local\AppData\Local\Temp\Rtmp6h8gw0\downloaded_packages
# Load some packages for scrapping data and data manipulation: 

rm(list = ls())
x <- c("rvest", "tidyverse", "magrittr")

lapply(x, library, character.only = TRUE)
## [[1]]
## [1] "rvest"     "xml2"      "stats"     "graphics"  "grDevices" "utils"    
## [7] "datasets"  "methods"   "base"     
## 
## [[2]]
##  [1] "forcats"   "stringr"   "dplyr"     "purrr"     "readr"    
##  [6] "tidyr"     "tibble"    "ggplot2"   "tidyverse" "rvest"    
## [11] "xml2"      "stats"     "graphics"  "grDevices" "utils"    
## [16] "datasets"  "methods"   "base"     
## 
## [[3]]
##  [1] "magrittr"  "forcats"   "stringr"   "dplyr"     "purrr"    
##  [6] "readr"     "tidyr"     "tibble"    "ggplot2"   "tidyverse"
## [11] "rvest"     "xml2"      "stats"     "graphics"  "grDevices"
## [16] "utils"     "datasets"  "methods"   "base"
# Loading data from the internet

link1 <- "https://college.harvard.edu/admissions/admissions-statistics"

field <- read_html("https://college.harvard.edu/admissions/admissions-statistics") %>% 
  html_table(fill = TRUE) %>% 
  .[[4]]

head(field)
##   Intended field of concentration      
## 1                      Humanities 14.5%
## 2                 Social Sciences 23.8%
## 3             Biological Sciences 20.5%
## 4               Physical Sciences  7.6%
## 5                     Engineering 11.7%
## 6                Computer Science  8.4%

This data doesn’t look clean enough.

# Re-names for variables

names(field) <- c("field", "rate")
head(field)
##                 field  rate
## 1          Humanities 14.5%
## 2     Social Sciences 23.8%
## 3 Biological Sciences 20.5%
## 4   Physical Sciences  7.6%
## 5         Engineering 11.7%
## 6    Computer Science  8.4%
# Extract "%" out

library(stringr)

# Creat my own function to pull out any strings rather than number

get_num <- function(x) {
  x %>% 
    str_replace_all("[^0-9]" , "") %>% 
    as.numeric() %>% 
    return()
}

field %<>% mutate(rate = get_num(rate) / 10)

head(field)
##                 field rate
## 1          Humanities 14.5
## 2     Social Sciences 23.8
## 3 Biological Sciences 20.5
## 4   Physical Sciences  7.6
## 5         Engineering 11.7
## 6    Computer Science  8.4

Now it’s time to visualize data!!!

A draft

theme_set(theme_minimal())

field %>% 
  ggplot(aes(field, rate)) + 
  geom_col()

It looks boring, Let’s add more colours!

Gradual adjustment:

library(ggthemes)


p <- field %>% 
  ggplot(aes(reorder(field, rate), rate, fill = field)) + 
  geom_col(show.legend = FALSE) + 
  coord_flip() + 
  labs(x = NULL, 
       y = NULL, 
       title = "Number of Students by Fields at Harvard University", 
       subtitle = "Created by Jenny Nguyen", 
       caption = "Data Source: https://college.harvard.edu/admissions/admissions-statistics") 


p

# I want to use the conomist theme, then,,,

p + 
  theme_economist(horizontal = FALSE) + 
  scale_fill_economist()

p + 
  theme_wsj()

# If I Want to add statistical numbers


p + 
  geom_text(aes(label = rate), hjust = 1.2, color = "white", size = 5)

## And add "% symbol"
p + 
  geom_text(aes(label = paste(rate, "%", sep = " ")), hjust = 1.1, color = "white", size = 5) + 
  theme(axis.title.x = element_blank(),
        axis.text.x = element_blank(),
        axis.ticks.x = element_blank()) -> p1
p1

## Use the economist theme
p1 + 
  theme_economist(horizontal = FALSE) + 
  scale_fill_economist() + 
  theme(axis.title.x = element_blank(),
        axis.text.x = element_blank(),
        axis.ticks.x = element_blank())

## Now, if I want to highlight one field over 8? 

field %>% 
  ggplot(aes(reorder(field, rate), rate)) + 
  geom_col(show.legend = FALSE, fill = c("#27408B")) + 
  geom_col(data = field %>% filter(field %in% c( "Humanities")), fill = "red") + 
  coord_flip() + 
  labs(x = NULL, 
       y = NULL, 
       title = "Number of Students by Fields at Harvard University", 
       subtitle = "Created by Jenny Nguyen", 
       caption = "Data Source: https://college.harvard.edu/admissions/admissions-statistics")

Mini case 2: Population Pyramids of Australia from 1995 to 2017

# A function for collecting population data: 

get_population <- function(countryCode_selected, year_selected) {
  
  base_url <- "https://www.census.gov/data-tools/demo/idb/region.php?N=%20Results%20&T=10&A=separate&RT=0&Y="
  link <- paste0(paste0(paste0(base_url, year_selected), "&R=-1&C="), countryCode_selected)
  
  link %>% 
    read_html() -> html_content  
  
  html_content %>% 
    html_table(fill = TRUE) %>% 
    .[[1]] -> pop_df
  
  names(pop_df) <- str_replace_all(names(pop_df), " ", "_")
  
  country_name <- html_content %>% 
    html_nodes('.query_source a') %>% 
    html_text() 
  
  if (length(country_name) == 2) {
    country_name <- country_name[2]
  }
  
  
  final_df <- pop_df %>% 
    select(-Year, -Age, -contains("Percent"), -Sex_Ratio) %>% 
    mutate_all(function(x) {str_replace_all(x, "[^0-9]", "") %>% as.numeric()}) %>% 
    mutate(Year = pop_df$Year, Country = country_name[1], Age = pop_df$Age) %>% 
    select(Year, Country, Age, everything()) %>% 
    mutate(Percent_Both_Sexes = Both_Sexes_Population / Both_Sexes_Population[1], 
           Percent_Male = Male_Population / Male_Population[1], 
           Percent_Female = Female_Population / Female_Population[1], 
           Sex_Ratio = Male_Population / Female_Population, 
           Age = case_when(Age == "0-4" ~ "00-04", Age == "5-9" ~ "05-09", TRUE ~ Age))
  
  return(final_df)
  
}

A Draft Plot

#==============
#   Style 1
#==============

# Use above function for Australia in 2016: 

au_2016_pop <- get_population("AS", 2016) 

head(au_2016_pop)
##   Year   Country   Age Both_Sexes_Population Male_Population
## 1 2016 Australia Total              22992654        11529136
## 2 2016 Australia 00-04               1376790          706537
## 3 2016 Australia 05-09               1369540          702678
## 4 2016 Australia 10-14               1356536          696218
## 5 2016 Australia 15-19               1403667          720507
## 6 2016 Australia 20-24               1576666          808486
##   Female_Population Percent_Both_Sexes Percent_Male Percent_Female
## 1          11463518         1.00000000   1.00000000     1.00000000
## 2            670253         0.05987956   0.06128274     0.05846835
## 3            666862         0.05956424   0.06094802     0.05817254
## 4            660318         0.05899867   0.06038770     0.05760169
## 5            683160         0.06104850   0.06249445     0.05959427
## 6            768180         0.06857260   0.07012546     0.06701084
##   Sex_Ratio
## 1  1.005724
## 2  1.054135
## 3  1.053708
## 4  1.054368
## 5  1.054668
## 6  1.052469
# Make a draft plot: 

theme_set(theme_minimal())

au_2016_pop %>% 
  slice(-c(1, 21:22)) %>% 
  select(Age, Male_Population, Female_Population) %>% 
  mutate(Male_Population = -1*Male_Population) %>% 
  gather(Gender, Value, -Age) %>% 
  ggplot(aes(Age, Value, fill = Gender)) + 
  geom_col(position = "stack") + 
  coord_flip() + 
  theme(legend.position = "top") + 
  scale_y_continuous(breaks = seq(-1000000, 1000000, 200000), 
                     limits = c(-1000000, 1000000), 
                     labels = c(paste0(seq(10, 0, -2), ""), paste0(1:5, "")))

This graph looks okay but not charming. We can make some improvements for making a more beautiful one by changing colours, adjusting axeses, adding titile and subtitles…

# Get more data from 1995 to 2017

total_df <- bind_rows(get_population("AS", 2017) %>% 
                        slice(-c(1, 20:22)) %>% 
                        select(Year, Age, Male_Population, Female_Population) %>% 
                        mutate(Female_Population = -1*Female_Population) %>% 
                        gather(Gender, Value, -Age, -Year), 
                      get_population("AS", 2005) %>% 
                        slice(-c(1, 20:22)) %>% 
                        select(Year, Age, Male_Population, Female_Population) %>% 
                        mutate(Female_Population = -1*Female_Population) %>% 
                        gather(Gender, Value, -Age, -Year), 
                      get_population("AS", 2000) %>% 
                        slice(-c(1, 20:22)) %>% 
                        select(Year, Age, Male_Population, Female_Population) %>% 
                        mutate(Female_Population = -1*Female_Population) %>% 
                        gather(Gender, Value, -Age, -Year), 
                      get_population("AS", 1995) %>% 
                        slice(-c(1, 20:22)) %>% 
                        select(Year, Age, Male_Population, Female_Population) %>% 
                        mutate(Female_Population = -1*Female_Population) %>% 
                        gather(Gender, Value, -Age, -Year))
# See the first 6 obs
head(total_df)
##   Year   Age          Gender  Value
## 1 2017 00-04 Male_Population 711818
## 2 2017 05-09 Male_Population 706653
## 3 2017 10-14 Male_Population 703668
## 4 2017 15-19 Male_Population 718381
## 5 2017 20-24 Male_Population 805987
## 6 2017 25-29 Male_Population 851478
# See the last 6 obs
tail(total_df)
##     Year   Age            Gender   Value
## 139 1995 60-64 Female_Population -345753
## 140 1995 65-69 Female_Population -349981
## 141 1995 70-74 Female_Population -319157
## 142 1995 75-79 Female_Population -239631
## 143 1995 80-84 Female_Population -174500
## 144 1995 85-89 Female_Population  -92423

The final plot

library(extrafont)


# Make final plot: 


total_df %>% 
  ggplot(aes(x = Age, color = Gender))+
  geom_linerange(data = total_df %>% filter(Gender == "Male_Population"), 
                 aes(ymin = -0.35, ymax = -0.35 + Value), 
                 size = 3.5, alpha = 0.8) +
  geom_linerange(data = total_df %>% filter(Gender != "Male_Population"), 
                 aes(ymin = 0.35, ymax = 0.35 + Value), 
                 size = 3.5, alpha = 0.8) + 
  geom_label(aes(x = Age, y = 0, label = Age), inherit.aes = TRUE, 
             family = "OfficinaSansITC", size = 4, label.padding = unit(0, "lines"), 
             label.size = 0, label.r = unit(0.0, "lines"), fill = "#f5f5f2", 
             alpha = 1, color = "gray20") + 
  coord_flip() + 
  facet_wrap( ~ Year) + 
  labs(x = NULL, y = NULL, 
       title = "Population Pyramids of Australia from 1995 to 2017",
       subtitle = "A population pyramid illustrates the age-sex structure of a country's population and may provide insights\nabout political and social stability, as well as economic development. Countries with young populations\nneed to invest more in schools, while countries with older populations need to invest more in the health sector.",
       caption = "Data Source: https://www.census.gov") + 
  scale_y_continuous(breaks = seq(-1000000, 1000000, 200000), 
                     limits = c(-1000000, 1000000), 
                     labels = c(paste0(seq(10, 0, -2), ""), paste0(1:5, ""))) + 
  scale_color_manual(name = "", values = c(Female_Population = "#3E606F", Male_Population = "#8C3F4D"), 
                     labels = c("Male", "Female")) + 
  
  theme(panel.grid.major.y = element_blank()) + 
  
  theme(plot.title = element_text(face = "bold", size = 24, family = "OfficinaSansITC", margin = margin(b = 9), hjust = 0, color = "grey20")) + 
  theme(plot.subtitle = element_text(size =12, margin = margin(b = 20), hjust = 0, family = "OfficinaSansITC", color = "grey30")) + 
  theme(plot.caption = element_text(size = 13, color = "grey50", family = "OfficinaSansITC")) + 
  
  
  theme(axis.text.y = element_blank()) + 
  theme(axis.text.x = element_text(size = 12, color = "grey20", family = "OfficinaSansITC", face = "bold")) + 
  
  theme(plot.background = element_rect(fill = "#EFF2F4", color = NA)) + 
  theme(panel.grid.major.x = element_line(linetype = "dotted", size = 0.2, color = "grey40")) + 
  theme(plot.margin = unit(c(1, 1, 1, 1), "cm")) + 
  theme(legend.position = "top") + 
  theme(legend.text = element_text(size = 10, face = "bold", color = "grey20")) + 
  theme(legend.text.align = 1) + 
  theme(strip.text = element_text(color = "grey20", size = 14, face = "bold", hjust = 0.026, family = "OfficinaSansITC")) 

LS0tDQp0aXRsZTogIkRhdGEgVmlzdWFsaXNhdGlvbiINCmF1dGhvcjogIkplbm55IE5ndXllbiINCmRhdGU6ICIyMSBOb3ZlbWJlciAyMDE4Ig0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50OiANCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgIyBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBoaWdobGlnaHQ6IHB5Z21lbnRzDQogICAgIyBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIHRoZW1lOiAiam91cm5hbCINCiAgICB0b2M6IFRSVUUNCiAgICB0b2NfZmxvYXQ6IFRSVUUNCi0tLQ0KDQpgYGB7ciBzZXR1cCxpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSkNCmBgYA0KDQoNCiMjIE1pbmkgY2FzZSAxOiBTaW1wbGUgdmlzdWFsaXNhdGlvbiB1c2luZyBnZ3Bsb3QyDQoNCkluIHRoaXMgc2VjdGlvbiwgSSB3aWxsIGNvbWJpbmUgYm90aCBkYXRhIHdyYW5nbGluZyBhbmQgZGF0YSB2aXN1YWxpc2F0aW9uLg0KDQpgYGB7ciBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQoNCiMgcGFja2FnZXMgaW5zdGFsbGF0aW9ucw0KDQpteV9wYWNrYWdlcyA8LSBjKCJ0aWR5dmVyc2UiLCAiZ2d0aGVtZXMiLCAiZ2dwbG90MiIsICJleHRyYWZvbnQiLCAic3RyaW5nciIpDQoNCmluc3RhbGwucGFja2FnZXMobXlfcGFja2FnZXMsIHJlcG9zID0gImh0dHA6Ly9jcmFuLnJzdHVkaW8uY29tIikNCg0KDQpgYGANCg0KDQpgYGB7ciBlY2hvPVRSVUUsIHdhcm5pbmc9RkFMU0V9DQojIExvYWQgc29tZSBwYWNrYWdlcyBmb3Igc2NyYXBwaW5nIGRhdGEgYW5kIGRhdGEgbWFuaXB1bGF0aW9uOiANCg0Kcm0obGlzdCA9IGxzKCkpDQp4IDwtIGMoInJ2ZXN0IiwgInRpZHl2ZXJzZSIsICJtYWdyaXR0ciIpDQoNCmxhcHBseSh4LCBsaWJyYXJ5LCBjaGFyYWN0ZXIub25seSA9IFRSVUUpDQpgYGANCg0KDQoNCmBgYHtyfQ0KIyBMb2FkaW5nIGRhdGEgZnJvbSB0aGUgaW50ZXJuZXQNCg0KbGluazEgPC0gImh0dHBzOi8vY29sbGVnZS5oYXJ2YXJkLmVkdS9hZG1pc3Npb25zL2FkbWlzc2lvbnMtc3RhdGlzdGljcyINCg0KZmllbGQgPC0gcmVhZF9odG1sKCJodHRwczovL2NvbGxlZ2UuaGFydmFyZC5lZHUvYWRtaXNzaW9ucy9hZG1pc3Npb25zLXN0YXRpc3RpY3MiKSAlPiUgDQogIGh0bWxfdGFibGUoZmlsbCA9IFRSVUUpICU+JSANCiAgLltbNF1dDQoNCmhlYWQoZmllbGQpDQpgYGANCg0KVGhpcyBkYXRhIGRvZXNuJ3QgbG9vayBjbGVhbiBlbm91Z2guIA0KDQpgYGB7cn0NCiMgUmUtbmFtZXMgZm9yIHZhcmlhYmxlcw0KDQpuYW1lcyhmaWVsZCkgPC0gYygiZmllbGQiLCAicmF0ZSIpDQpoZWFkKGZpZWxkKQ0KYGBgDQoNCmBgYHtyfQ0KIyBFeHRyYWN0ICIlIiBvdXQNCg0KbGlicmFyeShzdHJpbmdyKQ0KDQojIENyZWF0IG15IG93biBmdW5jdGlvbiB0byBwdWxsIG91dCBhbnkgc3RyaW5ncyByYXRoZXIgdGhhbiBudW1iZXINCg0KZ2V0X251bSA8LSBmdW5jdGlvbih4KSB7DQogIHggJT4lIA0KICAgIHN0cl9yZXBsYWNlX2FsbCgiW14wLTldIiAsICIiKSAlPiUgDQogICAgYXMubnVtZXJpYygpICU+JSANCiAgICByZXR1cm4oKQ0KfQ0KDQpmaWVsZCAlPD4lIG11dGF0ZShyYXRlID0gZ2V0X251bShyYXRlKSAvIDEwKQ0KDQpoZWFkKGZpZWxkKQ0KDQpgYGANCg0KTm93IGl0J3MgdGltZSB0byB2aXN1YWxpemUgZGF0YSEhIQ0KDQoNCiMjIyBBIGRyYWZ0DQoNCmBgYHtyfQ0KdGhlbWVfc2V0KHRoZW1lX21pbmltYWwoKSkNCg0KZmllbGQgJT4lIA0KICBnZ3Bsb3QoYWVzKGZpZWxkLCByYXRlKSkgKyANCiAgZ2VvbV9jb2woKQ0KDQpgYGANCg0KDQpJdCBsb29rcyBib3JpbmcsIExldCdzIGFkZCBtb3JlIGNvbG91cnMhDQoNCiMjIyBHcmFkdWFsIGFkanVzdG1lbnQ6DQoNCmBgYHtyIHdhcm5pbmc9RkFMU0V9DQpsaWJyYXJ5KGdndGhlbWVzKQ0KDQoNCnAgPC0gZmllbGQgJT4lIA0KICBnZ3Bsb3QoYWVzKHJlb3JkZXIoZmllbGQsIHJhdGUpLCByYXRlLCBmaWxsID0gZmllbGQpKSArIA0KICBnZW9tX2NvbChzaG93LmxlZ2VuZCA9IEZBTFNFKSArIA0KICBjb29yZF9mbGlwKCkgKyANCiAgbGFicyh4ID0gTlVMTCwgDQogICAgICAgeSA9IE5VTEwsIA0KICAgICAgIHRpdGxlID0gIk51bWJlciBvZiBTdHVkZW50cyBieSBGaWVsZHMgYXQgSGFydmFyZCBVbml2ZXJzaXR5IiwgDQogICAgICAgc3VidGl0bGUgPSAiQ3JlYXRlZCBieSBKZW5ueSBOZ3V5ZW4iLCANCiAgICAgICBjYXB0aW9uID0gIkRhdGEgU291cmNlOiBodHRwczovL2NvbGxlZ2UuaGFydmFyZC5lZHUvYWRtaXNzaW9ucy9hZG1pc3Npb25zLXN0YXRpc3RpY3MiKSANCg0KDQpwDQoNCmBgYA0KDQoNCmBgYHtyfQ0KIyBJIHdhbnQgdG8gdXNlIHRoZSBjb25vbWlzdCB0aGVtZSwgdGhlbiwsLA0KDQpwICsgDQogIHRoZW1lX2Vjb25vbWlzdChob3Jpem9udGFsID0gRkFMU0UpICsgDQogIHNjYWxlX2ZpbGxfZWNvbm9taXN0KCkNCg0KYGBgDQoNCmBgYHtyIGVjaG89VFJVRSwgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTE4LCB3YXJuaW5nPUZBTFNFfQ0KcCArIA0KICB0aGVtZV93c2ooKQ0KYGBgDQoNCg0KYGBge3IgZWNobz1UUlVFfQ0KIyBJZiBJIFdhbnQgdG8gYWRkIHN0YXRpc3RpY2FsIG51bWJlcnMNCg0KDQpwICsgDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSByYXRlKSwgaGp1c3QgPSAxLjIsIGNvbG9yID0gIndoaXRlIiwgc2l6ZSA9IDUpDQoNCg0KDQoNCmBgYA0KDQpgYGB7ciBlY2hvPVRSVUV9DQoNCiMjIEFuZCBhZGQgIiUgc3ltYm9sIg0KcCArIA0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGFzdGUocmF0ZSwgIiUiLCBzZXAgPSAiICIpKSwgaGp1c3QgPSAxLjEsIGNvbG9yID0gIndoaXRlIiwgc2l6ZSA9IDUpICsgDQogIHRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSkgLT4gcDENCnAxDQpgYGANCg0KDQpgYGB7ciBlY2hvPVRSVUV9DQoNCiMjIFVzZSB0aGUgZWNvbm9taXN0IHRoZW1lDQpwMSArIA0KICB0aGVtZV9lY29ub21pc3QoaG9yaXpvbnRhbCA9IEZBTFNFKSArIA0KICBzY2FsZV9maWxsX2Vjb25vbWlzdCgpICsgDQogIHRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSkNCg0KYGBgDQoNCmBgYHtyIGVjaG89VFJVRX0NCiMjIE5vdywgaWYgSSB3YW50IHRvIGhpZ2hsaWdodCBvbmUgZmllbGQgb3ZlciA4PyANCg0KZmllbGQgJT4lIA0KICBnZ3Bsb3QoYWVzKHJlb3JkZXIoZmllbGQsIHJhdGUpLCByYXRlKSkgKyANCiAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGQUxTRSwgZmlsbCA9IGMoIiMyNzQwOEIiKSkgKyANCiAgZ2VvbV9jb2woZGF0YSA9IGZpZWxkICU+JSBmaWx0ZXIoZmllbGQgJWluJSBjKCAiSHVtYW5pdGllcyIpKSwgZmlsbCA9ICJyZWQiKSArIA0KICBjb29yZF9mbGlwKCkgKyANCiAgbGFicyh4ID0gTlVMTCwgDQogICAgICAgeSA9IE5VTEwsIA0KICAgICAgIHRpdGxlID0gIk51bWJlciBvZiBTdHVkZW50cyBieSBGaWVsZHMgYXQgSGFydmFyZCBVbml2ZXJzaXR5IiwgDQogICAgICAgc3VidGl0bGUgPSAiQ3JlYXRlZCBieSBKZW5ueSBOZ3V5ZW4iLCANCiAgICAgICBjYXB0aW9uID0gIkRhdGEgU291cmNlOiBodHRwczovL2NvbGxlZ2UuaGFydmFyZC5lZHUvYWRtaXNzaW9ucy9hZG1pc3Npb25zLXN0YXRpc3RpY3MiKQ0KICANCg0KDQoNCmBgYA0KDQoNCiMjIE1pbmkgY2FzZSAyOiBQb3B1bGF0aW9uIFB5cmFtaWRzIG9mIEF1c3RyYWxpYSBmcm9tIDE5OTUgdG8gMjAxNw0KDQpgYGB7ciBlY2hvPVRSVUV9DQojIEEgZnVuY3Rpb24gZm9yIGNvbGxlY3RpbmcgcG9wdWxhdGlvbiBkYXRhOiANCg0KZ2V0X3BvcHVsYXRpb24gPC0gZnVuY3Rpb24oY291bnRyeUNvZGVfc2VsZWN0ZWQsIHllYXJfc2VsZWN0ZWQpIHsNCiAgDQogIGJhc2VfdXJsIDwtICJodHRwczovL3d3dy5jZW5zdXMuZ292L2RhdGEtdG9vbHMvZGVtby9pZGIvcmVnaW9uLnBocD9OPSUyMFJlc3VsdHMlMjAmVD0xMCZBPXNlcGFyYXRlJlJUPTAmWT0iDQogIGxpbmsgPC0gcGFzdGUwKHBhc3RlMChwYXN0ZTAoYmFzZV91cmwsIHllYXJfc2VsZWN0ZWQpLCAiJlI9LTEmQz0iKSwgY291bnRyeUNvZGVfc2VsZWN0ZWQpDQogIA0KICBsaW5rICU+JSANCiAgICByZWFkX2h0bWwoKSAtPiBodG1sX2NvbnRlbnQgIA0KICANCiAgaHRtbF9jb250ZW50ICU+JSANCiAgICBodG1sX3RhYmxlKGZpbGwgPSBUUlVFKSAlPiUgDQogICAgLltbMV1dIC0+IHBvcF9kZg0KICANCiAgbmFtZXMocG9wX2RmKSA8LSBzdHJfcmVwbGFjZV9hbGwobmFtZXMocG9wX2RmKSwgIiAiLCAiXyIpDQogIA0KICBjb3VudHJ5X25hbWUgPC0gaHRtbF9jb250ZW50ICU+JSANCiAgICBodG1sX25vZGVzKCcucXVlcnlfc291cmNlIGEnKSAlPiUgDQogICAgaHRtbF90ZXh0KCkgDQogIA0KICBpZiAobGVuZ3RoKGNvdW50cnlfbmFtZSkgPT0gMikgew0KICAgIGNvdW50cnlfbmFtZSA8LSBjb3VudHJ5X25hbWVbMl0NCiAgfQ0KICANCiAgDQogIGZpbmFsX2RmIDwtIHBvcF9kZiAlPiUgDQogICAgc2VsZWN0KC1ZZWFyLCAtQWdlLCAtY29udGFpbnMoIlBlcmNlbnQiKSwgLVNleF9SYXRpbykgJT4lIA0KICAgIG11dGF0ZV9hbGwoZnVuY3Rpb24oeCkge3N0cl9yZXBsYWNlX2FsbCh4LCAiW14wLTldIiwgIiIpICU+JSBhcy5udW1lcmljKCl9KSAlPiUgDQogICAgbXV0YXRlKFllYXIgPSBwb3BfZGYkWWVhciwgQ291bnRyeSA9IGNvdW50cnlfbmFtZVsxXSwgQWdlID0gcG9wX2RmJEFnZSkgJT4lIA0KICAgIHNlbGVjdChZZWFyLCBDb3VudHJ5LCBBZ2UsIGV2ZXJ5dGhpbmcoKSkgJT4lIA0KICAgIG11dGF0ZShQZXJjZW50X0JvdGhfU2V4ZXMgPSBCb3RoX1NleGVzX1BvcHVsYXRpb24gLyBCb3RoX1NleGVzX1BvcHVsYXRpb25bMV0sIA0KICAgICAgICAgICBQZXJjZW50X01hbGUgPSBNYWxlX1BvcHVsYXRpb24gLyBNYWxlX1BvcHVsYXRpb25bMV0sIA0KICAgICAgICAgICBQZXJjZW50X0ZlbWFsZSA9IEZlbWFsZV9Qb3B1bGF0aW9uIC8gRmVtYWxlX1BvcHVsYXRpb25bMV0sIA0KICAgICAgICAgICBTZXhfUmF0aW8gPSBNYWxlX1BvcHVsYXRpb24gLyBGZW1hbGVfUG9wdWxhdGlvbiwgDQogICAgICAgICAgIEFnZSA9IGNhc2Vfd2hlbihBZ2UgPT0gIjAtNCIgfiAiMDAtMDQiLCBBZ2UgPT0gIjUtOSIgfiAiMDUtMDkiLCBUUlVFIH4gQWdlKSkNCiAgDQogIHJldHVybihmaW5hbF9kZikNCiAgDQp9DQoNCmBgYA0KDQoNCiMjIyBBIERyYWZ0IFBsb3QNCg0KYGBge3IgZWNobz1UUlVFfQ0KIz09PT09PT09PT09PT09DQojICAgU3R5bGUgMQ0KIz09PT09PT09PT09PT09DQoNCiMgVXNlIGFib3ZlIGZ1bmN0aW9uIGZvciBBdXN0cmFsaWEgaW4gMjAxNjogDQoNCmF1XzIwMTZfcG9wIDwtIGdldF9wb3B1bGF0aW9uKCJBUyIsIDIwMTYpIA0KDQpoZWFkKGF1XzIwMTZfcG9wKQ0KYGBgDQoNCg0KYGBge3IgZWNobz1UUlVFfQ0KDQojIE1ha2UgYSBkcmFmdCBwbG90OiANCg0KdGhlbWVfc2V0KHRoZW1lX21pbmltYWwoKSkNCg0KYXVfMjAxNl9wb3AgJT4lIA0KICBzbGljZSgtYygxLCAyMToyMikpICU+JSANCiAgc2VsZWN0KEFnZSwgTWFsZV9Qb3B1bGF0aW9uLCBGZW1hbGVfUG9wdWxhdGlvbikgJT4lIA0KICBtdXRhdGUoTWFsZV9Qb3B1bGF0aW9uID0gLTEqTWFsZV9Qb3B1bGF0aW9uKSAlPiUgDQogIGdhdGhlcihHZW5kZXIsIFZhbHVlLCAtQWdlKSAlPiUgDQogIGdncGxvdChhZXMoQWdlLCBWYWx1ZSwgZmlsbCA9IEdlbmRlcikpICsgDQogIGdlb21fY29sKHBvc2l0aW9uID0gInN0YWNrIikgKyANCiAgY29vcmRfZmxpcCgpICsgDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKSArIA0KICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKC0xMDAwMDAwLCAxMDAwMDAwLCAyMDAwMDApLCANCiAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoLTEwMDAwMDAsIDEwMDAwMDApLCANCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMocGFzdGUwKHNlcSgxMCwgMCwgLTIpLCAiIiksIHBhc3RlMCgxOjUsICIiKSkpDQoNCg0KDQpgYGANCg0KVGhpcyBncmFwaCBsb29rcyBva2F5IGJ1dCBub3QgY2hhcm1pbmcuIFdlIGNhbiBtYWtlIHNvbWUgaW1wcm92ZW1lbnRzIGZvciBtYWtpbmcgYSBtb3JlIGJlYXV0aWZ1bCBvbmUgYnkgY2hhbmdpbmcgY29sb3VycywgYWRqdXN0aW5nIGF4ZXNlcywgYWRkaW5nIHRpdGlsZSBhbmQgc3VidGl0bGVzLi4uDQoNCg0KYGBge3IgZWNobz1UUlVFfQ0KIyBHZXQgbW9yZSBkYXRhIGZyb20gMTk5NSB0byAyMDE3DQoNCnRvdGFsX2RmIDwtIGJpbmRfcm93cyhnZXRfcG9wdWxhdGlvbigiQVMiLCAyMDE3KSAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgICBzbGljZSgtYygxLCAyMDoyMikpICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdChZZWFyLCBBZ2UsIE1hbGVfUG9wdWxhdGlvbiwgRmVtYWxlX1BvcHVsYXRpb24pICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShGZW1hbGVfUG9wdWxhdGlvbiA9IC0xKkZlbWFsZV9Qb3B1bGF0aW9uKSAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgICBnYXRoZXIoR2VuZGVyLCBWYWx1ZSwgLUFnZSwgLVllYXIpLCANCiAgICAgICAgICAgICAgICAgICAgICBnZXRfcG9wdWxhdGlvbigiQVMiLCAyMDA1KSAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgICBzbGljZSgtYygxLCAyMDoyMikpICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdChZZWFyLCBBZ2UsIE1hbGVfUG9wdWxhdGlvbiwgRmVtYWxlX1BvcHVsYXRpb24pICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShGZW1hbGVfUG9wdWxhdGlvbiA9IC0xKkZlbWFsZV9Qb3B1bGF0aW9uKSAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgICBnYXRoZXIoR2VuZGVyLCBWYWx1ZSwgLUFnZSwgLVllYXIpLCANCiAgICAgICAgICAgICAgICAgICAgICBnZXRfcG9wdWxhdGlvbigiQVMiLCAyMDAwKSAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgICBzbGljZSgtYygxLCAyMDoyMikpICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdChZZWFyLCBBZ2UsIE1hbGVfUG9wdWxhdGlvbiwgRmVtYWxlX1BvcHVsYXRpb24pICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShGZW1hbGVfUG9wdWxhdGlvbiA9IC0xKkZlbWFsZV9Qb3B1bGF0aW9uKSAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgICBnYXRoZXIoR2VuZGVyLCBWYWx1ZSwgLUFnZSwgLVllYXIpLCANCiAgICAgICAgICAgICAgICAgICAgICBnZXRfcG9wdWxhdGlvbigiQVMiLCAxOTk1KSAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgICBzbGljZSgtYygxLCAyMDoyMikpICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdChZZWFyLCBBZ2UsIE1hbGVfUG9wdWxhdGlvbiwgRmVtYWxlX1BvcHVsYXRpb24pICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShGZW1hbGVfUG9wdWxhdGlvbiA9IC0xKkZlbWFsZV9Qb3B1bGF0aW9uKSAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgICBnYXRoZXIoR2VuZGVyLCBWYWx1ZSwgLUFnZSwgLVllYXIpKQ0KDQoNCmBgYA0KDQoNCmBgYHtyIGVjaG89VFJVRX0NCiMgU2VlIHRoZSBmaXJzdCA2IG9icw0KaGVhZCh0b3RhbF9kZikNCmBgYA0KDQpgYGB7cn0NCiMgU2VlIHRoZSBsYXN0IDYgb2JzDQp0YWlsKHRvdGFsX2RmKQ0KYGBgDQoNCg0KIyMjIFRoZSBmaW5hbCBwbG90DQoNCmBgYHtyIGVjaG89VFJVRSwgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTEwLCB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeShleHRyYWZvbnQpDQoNCg0KIyBNYWtlIGZpbmFsIHBsb3Q6IA0KDQoNCnRvdGFsX2RmICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gQWdlLCBjb2xvciA9IEdlbmRlcikpKw0KICBnZW9tX2xpbmVyYW5nZShkYXRhID0gdG90YWxfZGYgJT4lIGZpbHRlcihHZW5kZXIgPT0gIk1hbGVfUG9wdWxhdGlvbiIpLCANCiAgICAgICAgICAgICAgICAgYWVzKHltaW4gPSAtMC4zNSwgeW1heCA9IC0wLjM1ICsgVmFsdWUpLCANCiAgICAgICAgICAgICAgICAgc2l6ZSA9IDMuNSwgYWxwaGEgPSAwLjgpICsNCiAgZ2VvbV9saW5lcmFuZ2UoZGF0YSA9IHRvdGFsX2RmICU+JSBmaWx0ZXIoR2VuZGVyICE9ICJNYWxlX1BvcHVsYXRpb24iKSwgDQogICAgICAgICAgICAgICAgIGFlcyh5bWluID0gMC4zNSwgeW1heCA9IDAuMzUgKyBWYWx1ZSksIA0KICAgICAgICAgICAgICAgICBzaXplID0gMy41LCBhbHBoYSA9IDAuOCkgKyANCiAgZ2VvbV9sYWJlbChhZXMoeCA9IEFnZSwgeSA9IDAsIGxhYmVsID0gQWdlKSwgaW5oZXJpdC5hZXMgPSBUUlVFLCANCiAgICAgICAgICAgICBmYW1pbHkgPSAiT2ZmaWNpbmFTYW5zSVRDIiwgc2l6ZSA9IDQsIGxhYmVsLnBhZGRpbmcgPSB1bml0KDAsICJsaW5lcyIpLCANCiAgICAgICAgICAgICBsYWJlbC5zaXplID0gMCwgbGFiZWwuciA9IHVuaXQoMC4wLCAibGluZXMiKSwgZmlsbCA9ICIjZjVmNWYyIiwgDQogICAgICAgICAgICAgYWxwaGEgPSAxLCBjb2xvciA9ICJncmF5MjAiKSArIA0KICBjb29yZF9mbGlwKCkgKyANCiAgZmFjZXRfd3JhcCggfiBZZWFyKSArIA0KICBsYWJzKHggPSBOVUxMLCB5ID0gTlVMTCwgDQogICAgICAgdGl0bGUgPSAiUG9wdWxhdGlvbiBQeXJhbWlkcyBvZiBBdXN0cmFsaWEgZnJvbSAxOTk1IHRvIDIwMTciLA0KICAgICAgIHN1YnRpdGxlID0gIkEgcG9wdWxhdGlvbiBweXJhbWlkIGlsbHVzdHJhdGVzIHRoZSBhZ2Utc2V4IHN0cnVjdHVyZSBvZiBhIGNvdW50cnkncyBwb3B1bGF0aW9uIGFuZCBtYXkgcHJvdmlkZSBpbnNpZ2h0c1xuYWJvdXQgcG9saXRpY2FsIGFuZCBzb2NpYWwgc3RhYmlsaXR5LCBhcyB3ZWxsIGFzIGVjb25vbWljIGRldmVsb3BtZW50LiBDb3VudHJpZXMgd2l0aCB5b3VuZyBwb3B1bGF0aW9uc1xubmVlZCB0byBpbnZlc3QgbW9yZSBpbiBzY2hvb2xzLCB3aGlsZSBjb3VudHJpZXMgd2l0aCBvbGRlciBwb3B1bGF0aW9ucyBuZWVkIHRvIGludmVzdCBtb3JlIGluIHRoZSBoZWFsdGggc2VjdG9yLiIsDQogICAgICAgY2FwdGlvbiA9ICJEYXRhIFNvdXJjZTogaHR0cHM6Ly93d3cuY2Vuc3VzLmdvdiIpICsgDQogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoLTEwMDAwMDAsIDEwMDAwMDAsIDIwMDAwMCksIA0KICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygtMTAwMDAwMCwgMTAwMDAwMCksIA0KICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYyhwYXN0ZTAoc2VxKDEwLCAwLCAtMiksICIiKSwgcGFzdGUwKDE6NSwgIiIpKSkgKyANCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWUgPSAiIiwgdmFsdWVzID0gYyhGZW1hbGVfUG9wdWxhdGlvbiA9ICIjM0U2MDZGIiwgTWFsZV9Qb3B1bGF0aW9uID0gIiM4QzNGNEQiKSwgDQogICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJNYWxlIiwgIkZlbWFsZSIpKSArIA0KICANCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9ibGFuaygpKSArIA0KICANCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMjQsIGZhbWlseSA9ICJPZmZpY2luYVNhbnNJVEMiLCBtYXJnaW4gPSBtYXJnaW4oYiA9IDkpLCBoanVzdCA9IDAsIGNvbG9yID0gImdyZXkyMCIpKSArIA0KICB0aGVtZShwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPTEyLCBtYXJnaW4gPSBtYXJnaW4oYiA9IDIwKSwgaGp1c3QgPSAwLCBmYW1pbHkgPSAiT2ZmaWNpbmFTYW5zSVRDIiwgY29sb3IgPSAiZ3JleTMwIikpICsgDQogIHRoZW1lKHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfdGV4dChzaXplID0gMTMsIGNvbG9yID0gImdyZXk1MCIsIGZhbWlseSA9ICJPZmZpY2luYVNhbnNJVEMiKSkgKyANCiAgDQogIA0KICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSkgKyANCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBjb2xvciA9ICJncmV5MjAiLCBmYW1pbHkgPSAiT2ZmaWNpbmFTYW5zSVRDIiwgZmFjZSA9ICJib2xkIikpICsgDQogIA0KICB0aGVtZShwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICIjRUZGMkY0IiwgY29sb3IgPSBOQSkpICsgDQogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfbGluZShsaW5ldHlwZSA9ICJkb3R0ZWQiLCBzaXplID0gMC4yLCBjb2xvciA9ICJncmV5NDAiKSkgKyANCiAgdGhlbWUocGxvdC5tYXJnaW4gPSB1bml0KGMoMSwgMSwgMSwgMSksICJjbSIpKSArIA0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikgKyANCiAgdGhlbWUobGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwLCBmYWNlID0gImJvbGQiLCBjb2xvciA9ICJncmV5MjAiKSkgKyANCiAgdGhlbWUobGVnZW5kLnRleHQuYWxpZ24gPSAxKSArIA0KICB0aGVtZShzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG9yID0gImdyZXkyMCIsIHNpemUgPSAxNCwgZmFjZSA9ICJib2xkIiwgaGp1c3QgPSAwLjAyNiwgZmFtaWx5ID0gIk9mZmljaW5hU2Fuc0lUQyIpKSANCg0KDQpgYGANCg0K