Data visualization exercise

This notebook uses TidyTuesday 2021/week4 Kenya Census data containing gender, crops and households indicators of the 2019 Kenya Population and Housing Census, from rKenyaCensus courtesy of Shelmith Kariuki.

Load libaries

library(tidyverse)
library(janitor)
library(waffle)
library(ggsci)
library(ggpubr)
library(scales)

Import data

gender <- readr::read_csv('https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2021/2021-01-19/gender.csv')
crops <- readr::read_csv('https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2021/2021-01-19/crops.csv')
households <- readr::read_csv('https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2021/2021-01-19/households.csv')

Clean and merge data

# clean names
crops_df = crops %>% clean_names()
households_df = households %>% clean_names()
gender_df = gender %>% clean_names()

# change county names to upper for joining
households_df$county <- sapply(households_df$county, toupper)
gender_df$county <- sapply(gender_df$county, toupper)

# recode factors for joining
gender_df = gender_df %>% mutate_at(vars(county), ~recode_factor(.,"TOTAL" = "KENYA"))
crops_df <- crops_df %>% rename(county = sub_county) 

# remove white space in county
crops_df$county <- gsub('\\s+', '', crops_df$county)
households_df$county <- gsub('\\s+', '', households_df$county)
gender_df$county <- gsub('\\s+', '', gender_df$county)

# rename NAIROBI to NAIROBICITY in crops_df
crops_df = crops_df %>% mutate_at(vars(county), ~recode_factor(.,"NAIROBI" = "NAIROBICITY"))

# merge three dataframe
data = list(crops_df, households_df, gender_df) %>% 
  reduce(full_join, by = "county")
dim(data)
[1] 48 18

Visualise missing data

# plot
data %>% summarise(across(everything(), ~mean(!is.na(.)))) %>% 
  gather() %>%
  mutate(key= fct_reorder(key, value)) %>%
  ggplot(aes(key, value)) +
  geom_point(size=3, color="#006d77") +
  geom_segment( aes(x=key, xend=key, y=0, yend=value)) + 
  geom_text(aes(label= percent(value)),
            nudge_y=0.07, size=3) + 
  scale_y_continuous(labels= scales::percent) + 
  theme_minimal() +
  theme(
    panel.grid.major.x = element_blank(),
    panel.grid.minor.x = element_blank(),
    panel.grid.major.y = element_blank(),
    legend.position="none"
  ) +
  theme(axis.text.x=element_blank()) +
  labs(x="", y="% of data present") + 
  coord_flip()

Distribution of Households Growing Permanent Crops by Type and County

crops_df2 <- crops_df %>% mutate_if(is.factor, function(x) tolower(as.character(x)))
crops_df2$county = str_to_title(crops_df2$county)

k_crops = crops_df2 %>% filter(county=="Kenya") 
k_crops_key = k_crops %>% gather("farming":"khat_miraa", key="crop_type",value="households") %>% mutate(households_mil = round((households/1000000),2))
ggdotchart(k_crops_key, x = "crop_type", y = "households_mil",
           color = c("#457b9d"), # Custom color palette
           sorting = "descending",                       # Sort value in descending order
           rotate = TRUE,                                # Rotate vertically
           dot.size = 8,                                 # Large dot size
           label = round(k_crops_key$households_mil,1),
           font.label = list(color = "white", size = 9, 
                             vjust = 0.5),
           ggtheme = theme_pubr()                        # ggplot2 theme
           )+
  theme_cleveland() +                                     # Add dashed grids
    labs(y="Number of households (in millions)", caption= "Data from rKenyaCensus", title="Distribution of Households Growing Permanent Crops by Type", subtitle="2019 Kenya Population and Housing Census")

Crops: Coffee vs Tea

# prepare data
ct_key = crops_df2 %>% select(county, coffee, tea) %>% gather(crop_type, households, 2:3) %>% filter(!is.na(households)) %>% filter(county!="Kenya") 
ct_key = ct_key %>% group_by(county) %>% mutate(households_total = sum(households)) %>% ungroup() %>% arrange(desc(households_total))

# plot
ggplot(ct_key, aes(households, reorder(county,households_total))) +
  geom_line(aes(group = county)) +
  geom_point(aes(color = crop_type)) + 
  theme_minimal() + 
  scale_color_d3() + 
  labs(y="County",
       x="Number of households",
       color="", 
       title= "Coffee vs. Tea ", 
       subtitle="Number of farming households in Kenya by County",
       caption= "Data from rKenyaCensus")

Crops: Cashew Nut vs. Coconut

# prepare data
mc_key = crops_df2 %>% select(county, cashew_nut, coconut) %>% gather(crop_type, households, 2:3) %>% filter(!is.na(households)) %>% filter(county!="Kenya") 
mc_key = mc_key %>% group_by(county) %>% mutate(households_total = sum(households)) %>% ungroup() %>% arrange(desc(households_total))

right_label <- mc_key %>%
        group_by(county) %>%
        arrange(desc(households)) %>%
        slice(1)

left_label <- mc_key %>%
        group_by(county) %>%
        arrange(desc(households)) %>%
        slice(2)

# plot
ggplot(mc_key, aes(households, reorder(county,households_total))) +
  geom_line(aes(group = county)) +
  geom_point(aes(color = crop_type), size=3) + 
  geom_text(data = right_label, aes(color = crop_type, label = round(households, 0)),
                  size = 3, hjust = -.5) +
  geom_text(data = left_label, aes(color = crop_type, label = round(households, 0)),
                  size = 3, hjust = 1.5) +
  theme_minimal() + 
  theme(legend.position = "bottom") +
  scale_color_nejm() + 
  scale_x_continuous(limits = c(-5000, 50000)) + 
  labs(y="County",
       x="Number of households",
       color="", 
       title= "Cashew nut vs. Coconut ", 
       subtitle="Number of farming households in Kenya by County",
       caption= "Data from rKenyaCensus")

Crops: Cashew Nut vs. Coconut

# waffle plot
# cashew nut
cas_df = crops_df2 %>% select(county, cashew_nut) %>% filter(!is.na(cashew_nut)) %>% arrange(desc(cashew_nut))
cas_df = cas_df[-1,] #remove first row

cas_vec = c(`KILIFI (27940)`=27940, `KWALE (22803) `=22803, `LAMU (8085) `=8085,
    `TANA RIVER (1691) `=1691, `MOMBASA (602) `=602, `TAITA/TAVETA (543) `=543)
    
p1 = waffle(cas_vec/500, rows=8, size=0.6,
      colors=c("#e85d04", "#264653", "#e9c46a","#00509d", "#90be6d", "#9e2a2b"),
      title="Households Growing Cashew Nut by Counties of Kenya",
      xlab="1 square = 500 households, data from rKenyaCensus", pad=7) 
p1 = p1 + theme(plot.title = element_text(size = 12))

# coconut
coco_df = crops_df %>% select(county, coconut) %>% filter(!is.na(coconut)) %>% arrange(desc(coconut))
coco_df = coco_df[-1,] #remove first row
coco_vec = c(`KILIFI (47561)`=47561, `KWALE (31954) `=31954, `LAMU (5017) `=5017,
    `TAITA/TAVETA  (2504) `=2504, `TANA RIVER (2228) `=2228, `MOMBASA (1688) `=1688)
    
p2 = waffle(coco_vec/500, rows=8, size=0.6,
            colors=c("#e85d04", "#264653", "#e9c46a","#9e2a2b", "#00509d", "#90be6d"),
            title="Households Growing Coconut by Counties of Kenya",
            xlab="1 square = 500 households, data from rKenyaCensus")
p2 = p2 + theme(plot.title = element_text(size = 12))

# plot
iron(p1,p2)

Avocados

avo_df = crops_df2 %>% dplyr::select(county, avocado, farming) %>% filter(!is.na(avocado)) %>% mutate(ratio = round((avocado/farming),4))

avo_df %>% ggplot(aes(reorder(county,ratio), ratio)) + geom_point(color="#606c38",size=2.5) + coord_flip() + 
  scale_y_continuous(labels = scales::percent, limits=c(0, 0.45)) +
  theme_minimal() +
  theme(
    panel.grid.minor.x = element_blank()) +
  labs(x="",y="", title="Avocados from Kenya", subtitle="Percentage of county's farming households farming avocados", caption="Data from rKenyaCensus")

Avocados (map)

library(Hmisc)
library(sf)
library(colorspace)
library(ggrepel)
library(viridis)
library(rKenyaCensus)

  k_shp <- rKenyaCensus::KenyaCounties_SHP
# clean
clean_county <- function(X) {
    X %>%
      tolower %>%
      str_replace_all("[^[:alpha:]]+", "") %>%
      str_replace_all(fixed("city"), "")
}

households = households %>% mutate(County = clean_county(County))
crops = crops %>% mutate(County = clean_county(SubCounty))
gender = gender %>% mutate(County = clean_county(County))

k_shp %>%
    as("sf") %>%
    dplyr::select(-Population) %>%
    mutate(County = clean_county(County)) %>%
    inner_join(households, by="County") %>%
    inner_join(gender, by="County") %>%
    inner_join(crops, by="County") ->
    k_data


# centroids
k_data$centroids <- st_transform(k_data) %>% 
    st_centroid() %>% 
    st_transform(., '+proj=longlat +ellps=GRS80 +no_defs') %>%
    st_geometry()

# centriods as dataframe
k_data_2 <- k_data %>% st_centroid() %>%  
    as_Spatial() %>%                
    as.data.frame()
# select four countries to label 
topavo <- subset(k_data_2, Avocado>50000)
topavo$County <- capitalize(topavo$County)
topavo[, c("County", "coords.x1", "coords.x2")]
topavo$County[topavo$County=="Muranga"] <- "Murang'a"
ggplot(k_data) + 
    geom_sf(aes(fill=Avocado), color="black") +
   geom_text_repel(data = topavo, aes(x = coords.x1, y = coords.x2, label = County), 
                   size=8, color="firebrick4", 
                             #  bungoma  / kakamega / kisii / muranga
                   nudge_x = c(-100000,   -250000,  +5000, -50000), 
                   nudge_y = c(+100000, -250000, -200000, -400000) ) +
   labs(title = "KENYA: Population growing/farming avocados by county", 
        subtitle="",
        fill="",
        caption="Data from rKenyaCencus") +
  scale_fill_continuous_sequential(palette = "Greens") +
   theme_void() + 
   theme(legend.position = "left",
         legend.text=element_text(size=16),
         text = element_text(color="black"),
         plot.caption  = element_text(size = 14, hjust=.5), 
         plot.title    = element_text(size = 32, hjust=0), 
         plot.subtitle = element_text(size = 24, hjust=0, color="gray30"), 
         plot.margin=unit(c(0.5, 0, 0.5, 0),"cm") )

Clustering household data by county

# libraries
library(factoextra)
library(ggthemes)
# prepare data 
cdf<-as.data.frame(households) #change class
rownames(cdf)<-households$County
cdf<-cdf[,-1] # drop first col
cdf<-cdf[-1,] # drop national data

# scale
cdf_scaled = scale(cdf)
head(cdf_scaled)
            Population NumberOfHouseholds AverageHouseholdSize
mombasa      0.2719883          0.5119992           -1.2801769
kwale       -0.2126755         -0.3634175            0.8686915
kilifi       0.6366411          0.1709959            0.6424948
tanariver   -1.0063075         -0.8109828            0.4162981
lamu        -1.2583862         -0.9401290           -0.6015869
taitataveta -0.9756191         -0.6907594           -0.8277836
# check optimal clusters using elbow plot
fviz_nbclust(cdf, kmeans, method = "wss")

# K means with 4 clusters
set.seed(123)
k4 = kmeans(cdf, 4,nstart=25)

# plot
fviz_cluster(k4, data = cdf)+theme_fivethirtyeight()+theme(rect = element_rect(fill = "White",linetype = 0, colour = NA))+labs(title="Cluster of Counties in Kenya based on Household",caption="Data from rKenyaCensus")

LS0tCnRpdGxlOiAiS2VueWEgQ2Vuc3VzIgpkYXRlOiAiMDEvMjAyMSIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyMgRGF0YSB2aXN1YWxpemF0aW9uIGV4ZXJjaXNlIAoKVGhpcyBub3RlYm9vayB1c2VzIFtUaWR5VHVlc2RheV0oaHR0cHM6Ly9naXRodWIuY29tL3Jmb3JkYXRhc2NpZW5jZS90aWR5dHVlc2RheSkgMjAyMS93ZWVrNCBbS2VueWEgQ2Vuc3VzXShodHRwczovL2dpdGh1Yi5jb20vcmZvcmRhdGFzY2llbmNlL3RpZHl0dWVzZGF5L2Jsb2IvbWFzdGVyL2RhdGEvMjAyMS8yMDIxLTAxLTE5L3JlYWRtZS5tZCkgZGF0YSBjb250YWluaW5nIGdlbmRlciwgY3JvcHMgYW5kIGhvdXNlaG9sZHMgaW5kaWNhdG9ycyBvZiB0aGUgMjAxOSBLZW55YSBQb3B1bGF0aW9uIGFuZCBIb3VzaW5nIENlbnN1cywgZnJvbSBbcktlbnlhQ2Vuc3VzXShodHRwczovL2dpdGh1Yi5jb20vU2hlbG1pdGgtS2FyaXVraS9yS2VueWFDZW5zdXMpIGNvdXJ0ZXN5IG9mIFNoZWxtaXRoIEthcml1a2kuIAoKCiMjIyBMb2FkIGxpYmFyaWVzCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShqYW5pdG9yKQpsaWJyYXJ5KHdhZmZsZSkKbGlicmFyeShnZ3NjaSkKbGlicmFyeShnZ3B1YnIpCmxpYnJhcnkoc2NhbGVzKQpgYGAKCiMjIyBJbXBvcnQgZGF0YQpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZ2VuZGVyIDwtIHJlYWRyOjpyZWFkX2NzdignaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3Jmb3JkYXRhc2NpZW5jZS90aWR5dHVlc2RheS9tYXN0ZXIvZGF0YS8yMDIxLzIwMjEtMDEtMTkvZ2VuZGVyLmNzdicpCmNyb3BzIDwtIHJlYWRyOjpyZWFkX2NzdignaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3Jmb3JkYXRhc2NpZW5jZS90aWR5dHVlc2RheS9tYXN0ZXIvZGF0YS8yMDIxLzIwMjEtMDEtMTkvY3JvcHMuY3N2JykKaG91c2Vob2xkcyA8LSByZWFkcjo6cmVhZF9jc3YoJ2h0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9yZm9yZGF0YXNjaWVuY2UvdGlkeXR1ZXNkYXkvbWFzdGVyL2RhdGEvMjAyMS8yMDIxLTAxLTE5L2hvdXNlaG9sZHMuY3N2JykKYGBgCgoKIyMjIENsZWFuIGFuZCBtZXJnZSBkYXRhIApgYGB7cn0KIyBjbGVhbiBuYW1lcwpjcm9wc19kZiA9IGNyb3BzICU+JSBjbGVhbl9uYW1lcygpCmhvdXNlaG9sZHNfZGYgPSBob3VzZWhvbGRzICU+JSBjbGVhbl9uYW1lcygpCmdlbmRlcl9kZiA9IGdlbmRlciAlPiUgY2xlYW5fbmFtZXMoKQoKIyBjaGFuZ2UgY291bnR5IG5hbWVzIHRvIHVwcGVyIGZvciBqb2luaW5nCmhvdXNlaG9sZHNfZGYkY291bnR5IDwtIHNhcHBseShob3VzZWhvbGRzX2RmJGNvdW50eSwgdG91cHBlcikKZ2VuZGVyX2RmJGNvdW50eSA8LSBzYXBwbHkoZ2VuZGVyX2RmJGNvdW50eSwgdG91cHBlcikKCiMgcmVjb2RlIGZhY3RvcnMgZm9yIGpvaW5pbmcKZ2VuZGVyX2RmID0gZ2VuZGVyX2RmICU+JSBtdXRhdGVfYXQodmFycyhjb3VudHkpLCB+cmVjb2RlX2ZhY3RvciguLCJUT1RBTCIgPSAiS0VOWUEiKSkKY3JvcHNfZGYgPC0gY3JvcHNfZGYgJT4lIHJlbmFtZShjb3VudHkgPSBzdWJfY291bnR5KSAKCiMgcmVtb3ZlIHdoaXRlIHNwYWNlIGluIGNvdW50eQpjcm9wc19kZiRjb3VudHkgPC0gZ3N1YignXFxzKycsICcnLCBjcm9wc19kZiRjb3VudHkpCmhvdXNlaG9sZHNfZGYkY291bnR5IDwtIGdzdWIoJ1xccysnLCAnJywgaG91c2Vob2xkc19kZiRjb3VudHkpCmdlbmRlcl9kZiRjb3VudHkgPC0gZ3N1YignXFxzKycsICcnLCBnZW5kZXJfZGYkY291bnR5KQoKIyByZW5hbWUgTkFJUk9CSSB0byBOQUlST0JJQ0lUWSBpbiBjcm9wc19kZgpjcm9wc19kZiA9IGNyb3BzX2RmICU+JSBtdXRhdGVfYXQodmFycyhjb3VudHkpLCB+cmVjb2RlX2ZhY3RvciguLCJOQUlST0JJIiA9ICJOQUlST0JJQ0lUWSIpKQoKIyBtZXJnZSB0aHJlZSBkYXRhZnJhbWUKZGF0YSA9IGxpc3QoY3JvcHNfZGYsIGhvdXNlaG9sZHNfZGYsIGdlbmRlcl9kZikgJT4lIAogIHJlZHVjZShmdWxsX2pvaW4sIGJ5ID0gImNvdW50eSIpCmRpbShkYXRhKQpgYGAKCiMjIyBWaXN1YWxpc2UgbWlzc2luZyBkYXRhCiogcmVmZXJlbmNlOiBbQGpvc2h5YW1fXShodHRwczovL3R3aXR0ZXIuY29tL2pvc2h5YW1fL3N0YXR1cy8xMzUxMjgxNjYxMjUwMzk2MTYwL3Bob3RvLzEpCmBgYHtyfQojIHBsb3QKZGF0YSAlPiUgc3VtbWFyaXNlKGFjcm9zcyhldmVyeXRoaW5nKCksIH5tZWFuKCFpcy5uYSguKSkpKSAlPiUgCiAgZ2F0aGVyKCkgJT4lCiAgbXV0YXRlKGtleT0gZmN0X3Jlb3JkZXIoa2V5LCB2YWx1ZSkpICU+JQogIGdncGxvdChhZXMoa2V5LCB2YWx1ZSkpICsKICBnZW9tX3BvaW50KHNpemU9MywgY29sb3I9IiMwMDZkNzciKSArCiAgZ2VvbV9zZWdtZW50KCBhZXMoeD1rZXksIHhlbmQ9a2V5LCB5PTAsIHllbmQ9dmFsdWUpKSArIAogIGdlb21fdGV4dChhZXMobGFiZWw9IHBlcmNlbnQodmFsdWUpKSwKICAgICAgICAgICAgbnVkZ2VfeT0wLjA3LCBzaXplPTMpICsgCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscz0gc2NhbGVzOjpwZXJjZW50KSArIAogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoCiAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBwYW5lbC5ncmlkLm1pbm9yLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICBsZWdlbmQucG9zaXRpb249Im5vbmUiCiAgKSArCiAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpKSArCiAgbGFicyh4PSIiLCB5PSIlIG9mIGRhdGEgcHJlc2VudCIpICsgCiAgY29vcmRfZmxpcCgpCmBgYAoKIyMjIERpc3RyaWJ1dGlvbiBvZiBIb3VzZWhvbGRzIEdyb3dpbmcgUGVybWFuZW50IENyb3BzIGJ5IFR5cGUgYW5kIENvdW50eSAKCmBgYHtyfQpjcm9wc19kZjIgPC0gY3JvcHNfZGYgJT4lIG11dGF0ZV9pZihpcy5mYWN0b3IsIGZ1bmN0aW9uKHgpIHRvbG93ZXIoYXMuY2hhcmFjdGVyKHgpKSkKY3JvcHNfZGYyJGNvdW50eSA9IHN0cl90b190aXRsZShjcm9wc19kZjIkY291bnR5KQoKa19jcm9wcyA9IGNyb3BzX2RmMiAlPiUgZmlsdGVyKGNvdW50eT09IktlbnlhIikgCmtfY3JvcHNfa2V5ID0ga19jcm9wcyAlPiUgZ2F0aGVyKCJmYXJtaW5nIjoia2hhdF9taXJhYSIsIGtleT0iY3JvcF90eXBlIix2YWx1ZT0iaG91c2Vob2xkcyIpICU+JSBtdXRhdGUoaG91c2Vob2xkc19taWwgPSByb3VuZCgoaG91c2Vob2xkcy8xMDAwMDAwKSwyKSkKYGBgCgpgYGB7cn0KZ2dkb3RjaGFydChrX2Nyb3BzX2tleSwgeCA9ICJjcm9wX3R5cGUiLCB5ID0gImhvdXNlaG9sZHNfbWlsIiwKICAgICAgICAgICBjb2xvciA9IGMoIiM0NTdiOWQiKSwgIyBDdXN0b20gY29sb3IgcGFsZXR0ZQogICAgICAgICAgIHNvcnRpbmcgPSAiZGVzY2VuZGluZyIsICAgICAgICAgICAgICAgICAgICAgICAjIFNvcnQgdmFsdWUgaW4gZGVzY2VuZGluZyBvcmRlcgogICAgICAgICAgIHJvdGF0ZSA9IFRSVUUsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIFJvdGF0ZSB2ZXJ0aWNhbGx5CiAgICAgICAgICAgZG90LnNpemUgPSA4LCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgTGFyZ2UgZG90IHNpemUKICAgICAgICAgICBsYWJlbCA9IHJvdW5kKGtfY3JvcHNfa2V5JGhvdXNlaG9sZHNfbWlsLDEpLAogICAgICAgICAgIGZvbnQubGFiZWwgPSBsaXN0KGNvbG9yID0gIndoaXRlIiwgc2l6ZSA9IDksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZqdXN0ID0gMC41KSwKICAgICAgICAgICBnZ3RoZW1lID0gdGhlbWVfcHVicigpICAgICAgICAgICAgICAgICAgICAgICAgIyBnZ3Bsb3QyIHRoZW1lCiAgICAgICAgICAgKSsKICB0aGVtZV9jbGV2ZWxhbmQoKSArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgQWRkIGRhc2hlZCBncmlkcwogICAgbGFicyh5PSJOdW1iZXIgb2YgaG91c2Vob2xkcyAoaW4gbWlsbGlvbnMpIiwgY2FwdGlvbj0gIkRhdGEgZnJvbSByS2VueWFDZW5zdXMiLCB0aXRsZT0iRGlzdHJpYnV0aW9uIG9mIEhvdXNlaG9sZHMgR3Jvd2luZyBQZXJtYW5lbnQgQ3JvcHMgYnkgVHlwZSIsIHN1YnRpdGxlPSIyMDE5IEtlbnlhIFBvcHVsYXRpb24gYW5kIEhvdXNpbmcgQ2Vuc3VzIikKYGBgCgojIyMgQ3JvcHM6IENvZmZlZSB2cyBUZWEgCiogSW5zcGlyZWQgYnk6IFtpenpfbTJdKGh0dHBzOi8vdHdpdHRlci5jb20vaXp6X20yL3N0YXR1cy8xMzUxNjE1NDM4Nzk1NTA5NzYyL3Bob3RvLzEpCmBgYHtyfQojIHByZXBhcmUgZGF0YQpjdF9rZXkgPSBjcm9wc19kZjIgJT4lIHNlbGVjdChjb3VudHksIGNvZmZlZSwgdGVhKSAlPiUgZ2F0aGVyKGNyb3BfdHlwZSwgaG91c2Vob2xkcywgMjozKSAlPiUgZmlsdGVyKCFpcy5uYShob3VzZWhvbGRzKSkgJT4lIGZpbHRlcihjb3VudHkhPSJLZW55YSIpIApjdF9rZXkgPSBjdF9rZXkgJT4lIGdyb3VwX2J5KGNvdW50eSkgJT4lIG11dGF0ZShob3VzZWhvbGRzX3RvdGFsID0gc3VtKGhvdXNlaG9sZHMpKSAlPiUgdW5ncm91cCgpICU+JSBhcnJhbmdlKGRlc2MoaG91c2Vob2xkc190b3RhbCkpCgojIHBsb3QKZ2dwbG90KGN0X2tleSwgYWVzKGhvdXNlaG9sZHMsIHJlb3JkZXIoY291bnR5LGhvdXNlaG9sZHNfdG90YWwpKSkgKwogIGdlb21fbGluZShhZXMoZ3JvdXAgPSBjb3VudHkpKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBjcm9wX3R5cGUpKSArIAogIHRoZW1lX21pbmltYWwoKSArIAogIHNjYWxlX2NvbG9yX2QzKCkgKyAKICBsYWJzKHk9IkNvdW50eSIsCiAgICAgICB4PSJOdW1iZXIgb2YgaG91c2Vob2xkcyIsCiAgICAgICBjb2xvcj0iIiwgCiAgICAgICB0aXRsZT0gIkNvZmZlZSB2cy4gVGVhICIsIAogICAgICAgc3VidGl0bGU9Ik51bWJlciBvZiBmYXJtaW5nIGhvdXNlaG9sZHMgaW4gS2VueWEgYnkgQ291bnR5IiwKICAgICAgIGNhcHRpb249ICJEYXRhIGZyb20gcktlbnlhQ2Vuc3VzIikKYGBgCgoKIyMjIENyb3BzOiBDYXNoZXcgTnV0IHZzLiBDb2NvbnV0IApgYGB7cn0KIyBwcmVwYXJlIGRhdGEKbWNfa2V5ID0gY3JvcHNfZGYyICU+JSBzZWxlY3QoY291bnR5LCBjYXNoZXdfbnV0LCBjb2NvbnV0KSAlPiUgZ2F0aGVyKGNyb3BfdHlwZSwgaG91c2Vob2xkcywgMjozKSAlPiUgZmlsdGVyKCFpcy5uYShob3VzZWhvbGRzKSkgJT4lIGZpbHRlcihjb3VudHkhPSJLZW55YSIpIAptY19rZXkgPSBtY19rZXkgJT4lIGdyb3VwX2J5KGNvdW50eSkgJT4lIG11dGF0ZShob3VzZWhvbGRzX3RvdGFsID0gc3VtKGhvdXNlaG9sZHMpKSAlPiUgdW5ncm91cCgpICU+JSBhcnJhbmdlKGRlc2MoaG91c2Vob2xkc190b3RhbCkpCgpyaWdodF9sYWJlbCA8LSBtY19rZXkgJT4lCiAgICAgICAgZ3JvdXBfYnkoY291bnR5KSAlPiUKICAgICAgICBhcnJhbmdlKGRlc2MoaG91c2Vob2xkcykpICU+JQogICAgICAgIHNsaWNlKDEpCgpsZWZ0X2xhYmVsIDwtIG1jX2tleSAlPiUKICAgICAgICBncm91cF9ieShjb3VudHkpICU+JQogICAgICAgIGFycmFuZ2UoZGVzYyhob3VzZWhvbGRzKSkgJT4lCiAgICAgICAgc2xpY2UoMikKCiMgcGxvdApnZ3Bsb3QobWNfa2V5LCBhZXMoaG91c2Vob2xkcywgcmVvcmRlcihjb3VudHksaG91c2Vob2xkc190b3RhbCkpKSArCiAgZ2VvbV9saW5lKGFlcyhncm91cCA9IGNvdW50eSkpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGNyb3BfdHlwZSksIHNpemU9MykgKyAKICBnZW9tX3RleHQoZGF0YSA9IHJpZ2h0X2xhYmVsLCBhZXMoY29sb3IgPSBjcm9wX3R5cGUsIGxhYmVsID0gcm91bmQoaG91c2Vob2xkcywgMCkpLAogICAgICAgICAgICAgICAgICBzaXplID0gMywgaGp1c3QgPSAtLjUpICsKICBnZW9tX3RleHQoZGF0YSA9IGxlZnRfbGFiZWwsIGFlcyhjb2xvciA9IGNyb3BfdHlwZSwgbGFiZWwgPSByb3VuZChob3VzZWhvbGRzLCAwKSksCiAgICAgICAgICAgICAgICAgIHNpemUgPSAzLCBoanVzdCA9IDEuNSkgKwogIHRoZW1lX21pbmltYWwoKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArCiAgc2NhbGVfY29sb3JfbmVqbSgpICsgCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoLTUwMDAsIDUwMDAwKSkgKyAKICBsYWJzKHk9IkNvdW50eSIsCiAgICAgICB4PSJOdW1iZXIgb2YgaG91c2Vob2xkcyIsCiAgICAgICBjb2xvcj0iIiwgCiAgICAgICB0aXRsZT0gIkNhc2hldyBudXQgdnMuIENvY29udXQgIiwgCiAgICAgICBzdWJ0aXRsZT0iTnVtYmVyIG9mIGZhcm1pbmcgaG91c2Vob2xkcyBpbiBLZW55YSBieSBDb3VudHkiLAogICAgICAgY2FwdGlvbj0gIkRhdGEgZnJvbSByS2VueWFDZW5zdXMiKQpgYGAKCiMjIyBDcm9wczogQ2FzaGV3IE51dCB2cy4gQ29jb251dCAKYGBge3J9CiMgd2FmZmxlIHBsb3QKIyBjYXNoZXcgbnV0CmNhc19kZiA9IGNyb3BzX2RmMiAlPiUgc2VsZWN0KGNvdW50eSwgY2FzaGV3X251dCkgJT4lIGZpbHRlcighaXMubmEoY2FzaGV3X251dCkpICU+JSBhcnJhbmdlKGRlc2MoY2FzaGV3X251dCkpCmNhc19kZiA9IGNhc19kZlstMSxdICNyZW1vdmUgZmlyc3Qgcm93CgpjYXNfdmVjID0gYyhgS0lMSUZJICgyNzk0MClgPTI3OTQwLCBgS1dBTEUgKDIyODAzKSBgPTIyODAzLCBgTEFNVSAoODA4NSkgYD04MDg1LAoJYFRBTkEgUklWRVIgKDE2OTEpIGA9MTY5MSwgYE1PTUJBU0EgKDYwMikgYD02MDIsIGBUQUlUQS9UQVZFVEEgKDU0MykgYD01NDMpCgkKcDEgPSB3YWZmbGUoY2FzX3ZlYy81MDAsIHJvd3M9OCwgc2l6ZT0wLjYsCiAgICAgIGNvbG9ycz1jKCIjZTg1ZDA0IiwgIiMyNjQ2NTMiLCAiI2U5YzQ2YSIsIiMwMDUwOWQiLCAiIzkwYmU2ZCIsICIjOWUyYTJiIiksCiAgICAgIHRpdGxlPSJIb3VzZWhvbGRzIEdyb3dpbmcgQ2FzaGV3IE51dCBieSBDb3VudGllcyBvZiBLZW55YSIsCiAgICAgIHhsYWI9IjEgc3F1YXJlID0gNTAwIGhvdXNlaG9sZHMsIGRhdGEgZnJvbSByS2VueWFDZW5zdXMiLCBwYWQ9NykgCnAxID0gcDEgKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMikpCgojIGNvY29udXQKY29jb19kZiA9IGNyb3BzX2RmICU+JSBzZWxlY3QoY291bnR5LCBjb2NvbnV0KSAlPiUgZmlsdGVyKCFpcy5uYShjb2NvbnV0KSkgJT4lIGFycmFuZ2UoZGVzYyhjb2NvbnV0KSkKY29jb19kZiA9IGNvY29fZGZbLTEsXSAjcmVtb3ZlIGZpcnN0IHJvdwpjb2NvX3ZlYyA9IGMoYEtJTElGSSAoNDc1NjEpYD00NzU2MSwgYEtXQUxFICgzMTk1NCkgYD0zMTk1NCwgYExBTVUgKDUwMTcpIGA9NTAxNywKCWBUQUlUQS9UQVZFVEEgICgyNTA0KSBgPTI1MDQsIGBUQU5BIFJJVkVSICgyMjI4KSBgPTIyMjgsIGBNT01CQVNBICgxNjg4KSBgPTE2ODgpCgkKcDIgPSB3YWZmbGUoY29jb192ZWMvNTAwLCByb3dzPTgsIHNpemU9MC42LAogICAgICAgICAgICBjb2xvcnM9YygiI2U4NWQwNCIsICIjMjY0NjUzIiwgIiNlOWM0NmEiLCIjOWUyYTJiIiwgIiMwMDUwOWQiLCAiIzkwYmU2ZCIpLAogICAgICAgICAgICB0aXRsZT0iSG91c2Vob2xkcyBHcm93aW5nIENvY29udXQgYnkgQ291bnRpZXMgb2YgS2VueWEiLAogICAgICAgICAgICB4bGFiPSIxIHNxdWFyZSA9IDUwMCBob3VzZWhvbGRzLCBkYXRhIGZyb20gcktlbnlhQ2Vuc3VzIikKcDIgPSBwMiArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSkKCiMgcGxvdAppcm9uKHAxLHAyKQpgYGAKCgojIyMgQXZvY2Fkb3MgCiogSW5zcGlyZWQgYnkgW0BhZHJpYWFhYWFhYW5dKGh0dHBzOi8vdHdpdHRlci5jb20vYWRyaWFhYWFhYWFuL3N0YXR1cy8xMzUxNjY1NjI4MDEzMzU1MDA4L3Bob3RvLzEpCgpgYGB7cn0KYXZvX2RmID0gY3JvcHNfZGYyICU+JSBkcGx5cjo6c2VsZWN0KGNvdW50eSwgYXZvY2FkbywgZmFybWluZykgJT4lIGZpbHRlcighaXMubmEoYXZvY2FkbykpICU+JSBtdXRhdGUocmF0aW8gPSByb3VuZCgoYXZvY2Fkby9mYXJtaW5nKSw0KSkKCmF2b19kZiAlPiUgZ2dwbG90KGFlcyhyZW9yZGVyKGNvdW50eSxyYXRpbyksIHJhdGlvKSkgKyBnZW9tX3BvaW50KGNvbG9yPSIjNjA2YzM4IixzaXplPTIuNSkgKyBjb29yZF9mbGlwKCkgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50LCBsaW1pdHM9YygwLCAwLjQ1KSkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoCiAgICBwYW5lbC5ncmlkLm1pbm9yLnggPSBlbGVtZW50X2JsYW5rKCkpICsKICBsYWJzKHg9IiIseT0iIiwgdGl0bGU9IkF2b2NhZG9zIGZyb20gS2VueWEiLCBzdWJ0aXRsZT0iUGVyY2VudGFnZSBvZiBjb3VudHkncyBmYXJtaW5nIGhvdXNlaG9sZHMgZmFybWluZyBhdm9jYWRvcyIsIGNhcHRpb249IkRhdGEgZnJvbSByS2VueWFDZW5zdXMiKQpgYGAKCiMjIyBBdm9jYWRvcyAobWFwKQoqIHJlZmVyZW5jZTogW0tlbnlhIFggQ29mZmVlIGJ5IEBweXl4eG9dKGh0dHBzOi8vdHdpdHRlci5jb20vcHl5eHhvL3N0YXR1cy8xMzUxNTY4MDQ1NzE0NjQ1MDAwL3Bob3RvLzEpCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpsaWJyYXJ5KEhtaXNjKQpsaWJyYXJ5KHNmKQpsaWJyYXJ5KGNvbG9yc3BhY2UpCmxpYnJhcnkoZ2dyZXBlbCkKbGlicmFyeShSQ29sb3JCcmV3ZXIpCmxpYnJhcnkocktlbnlhQ2Vuc3VzKQoKICBrX3NocCA8LSByS2VueWFDZW5zdXM6OktlbnlhQ291bnRpZXNfU0hQCmBgYAoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgY2xlYW4KY2xlYW5fY291bnR5IDwtIGZ1bmN0aW9uKFgpIHsKICAgIFggJT4lCiAgICAgIHRvbG93ZXIgJT4lCiAgICAgIHN0cl9yZXBsYWNlX2FsbCgiW15bOmFscGhhOl1dKyIsICIiKSAlPiUKICAgICAgc3RyX3JlcGxhY2VfYWxsKGZpeGVkKCJjaXR5IiksICIiKQp9Cgpob3VzZWhvbGRzID0gaG91c2Vob2xkcyAlPiUgbXV0YXRlKENvdW50eSA9IGNsZWFuX2NvdW50eShDb3VudHkpKQpjcm9wcyA9IGNyb3BzICU+JSBtdXRhdGUoQ291bnR5ID0gY2xlYW5fY291bnR5KFN1YkNvdW50eSkpCmdlbmRlciA9IGdlbmRlciAlPiUgbXV0YXRlKENvdW50eSA9IGNsZWFuX2NvdW50eShDb3VudHkpKQoKa19zaHAgJT4lCiAgICBhcygic2YiKSAlPiUKICAgIGRwbHlyOjpzZWxlY3QoLVBvcHVsYXRpb24pICU+JQogICAgbXV0YXRlKENvdW50eSA9IGNsZWFuX2NvdW50eShDb3VudHkpKSAlPiUKICAgIGlubmVyX2pvaW4oaG91c2Vob2xkcywgYnk9IkNvdW50eSIpICU+JQogICAgaW5uZXJfam9pbihnZW5kZXIsIGJ5PSJDb3VudHkiKSAlPiUKICAgIGlubmVyX2pvaW4oY3JvcHMsIGJ5PSJDb3VudHkiKSAtPgogICAga19kYXRhCgoKIyBjZW50cm9pZHMKa19kYXRhJGNlbnRyb2lkcyA8LSBzdF90cmFuc2Zvcm0oa19kYXRhKSAlPiUgCiAgICBzdF9jZW50cm9pZCgpICU+JSAKICAgIHN0X3RyYW5zZm9ybSguLCAnK3Byb2o9bG9uZ2xhdCArZWxscHM9R1JTODAgK25vX2RlZnMnKSAlPiUKICAgIHN0X2dlb21ldHJ5KCkKCiMgY2VudHJpb2RzIGFzIGRhdGFmcmFtZQprX2RhdGFfMiA8LSBrX2RhdGEgJT4lIHN0X2NlbnRyb2lkKCkgJT4lICAKICAgIGFzX1NwYXRpYWwoKSAlPiUgICAgICAgICAgICAgICAgCiAgICBhcy5kYXRhLmZyYW1lKCkKYGBgCgpgYGB7cn0KIyBzZWxlY3QgZm91ciBjb3VudHJpZXMgdG8gbGFiZWwgCnRvcGF2byA8LSBzdWJzZXQoa19kYXRhXzIsIEF2b2NhZG8+NTAwMDApCnRvcGF2byRDb3VudHkgPC0gY2FwaXRhbGl6ZSh0b3Bhdm8kQ291bnR5KQp0b3Bhdm9bLCBjKCJDb3VudHkiLCAiY29vcmRzLngxIiwgImNvb3Jkcy54MiIpXQp0b3Bhdm8kQ291bnR5W3RvcGF2byRDb3VudHk9PSJNdXJhbmdhIl0gPC0gIk11cmFuZydhIgpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0PTksIGZpZy53aWR0aD0xNn0KZ2dwbG90KGtfZGF0YSkgKyAKICAgIGdlb21fc2YoYWVzKGZpbGw9QXZvY2FkbyksIGNvbG9yPSJibGFjayIpICsKICAgZ2VvbV90ZXh0X3JlcGVsKGRhdGEgPSB0b3Bhdm8sIGFlcyh4ID0gY29vcmRzLngxLCB5ID0gY29vcmRzLngyLCBsYWJlbCA9IENvdW50eSksIAogICAgICAgICAgICAgICAgICAgc2l6ZT04LCBjb2xvcj0iZmlyZWJyaWNrNCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgIGJ1bmdvbWEgIC8ga2FrYW1lZ2EgLyBraXNpaSAvIG11cmFuZ2EKICAgICAgICAgICAgICAgICAgIG51ZGdlX3ggPSBjKC0xMDAwMDAsICAgLTI1MDAwMCwgICs1MDAwLCAtNTAwMDApLCAKICAgICAgICAgICAgICAgICAgIG51ZGdlX3kgPSBjKCsxMDAwMDAsIC0yNTAwMDAsIC0yMDAwMDAsIC00MDAwMDApICkgKwogICBsYWJzKHRpdGxlID0gIktFTllBOiBQb3B1bGF0aW9uIGdyb3dpbmcvZmFybWluZyBhdm9jYWRvcyBieSBjb3VudHkiLCAKICAgICAgICBzdWJ0aXRsZT0iIiwKICAgICAgICBmaWxsPSIiLAogICAgICAgIGNhcHRpb249IkRhdGEgZnJvbSByS2VueWFDZW5jdXMiKSArCiAgc2NhbGVfZmlsbF9jb250aW51b3VzX3NlcXVlbnRpYWwocGFsZXR0ZSA9ICJHcmVlbnMiKSArCiAgIHRoZW1lX3ZvaWQoKSArIAogICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibGVmdCIsCiAgICAgICAgIGxlZ2VuZC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTE2KSwKICAgICAgICAgdGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvcj0iYmxhY2siKSwKICAgICAgICAgcGxvdC5jYXB0aW9uICA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIGhqdXN0PS41KSwgCiAgICAgICAgIHBsb3QudGl0bGUgICAgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDMyLCBoanVzdD0wKSwgCiAgICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDI0LCBoanVzdD0wLCBjb2xvcj0iZ3JheTMwIiksIAogICAgICAgICBwbG90Lm1hcmdpbj11bml0KGMoMC41LCAwLCAwLjUsIDApLCJjbSIpICkKYGBgCgoKIyMjIENsdXN0ZXJpbmcgaG91c2Vob2xkIGRhdGEgYnkgY291bnR5CiogUmVmZXJlbmNlOiBbQE96YW5jYW5PemRlbWlyXShodHRwczovL3R3aXR0ZXIuY29tL096YW5jYW5PemRlbWlyL3N0YXR1cy8xMzUxNzk0MDYyNjI2NTc4NDMyL3Bob3RvLzEpCgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBsaWJyYXJpZXMKbGlicmFyeShmYWN0b2V4dHJhKQpsaWJyYXJ5KGdndGhlbWVzKQpgYGAKCmBgYHtyfQojIHByZXBhcmUgZGF0YSAKY2RmPC1hcy5kYXRhLmZyYW1lKGhvdXNlaG9sZHMpICNjaGFuZ2UgY2xhc3MKcm93bmFtZXMoY2RmKTwtaG91c2Vob2xkcyRDb3VudHkKY2RmPC1jZGZbLC0xXSAjIGRyb3AgZmlyc3QgY29sCmNkZjwtY2RmWy0xLF0gIyBkcm9wIG5hdGlvbmFsIGRhdGEKCiMgc2NhbGUKY2RmX3NjYWxlZCA9IHNjYWxlKGNkZikKaGVhZChjZGZfc2NhbGVkKQpgYGAKCgpgYGB7cn0KIyBjaGVjayBvcHRpbWFsIGNsdXN0ZXJzIHVzaW5nIGVsYm93IHBsb3QKZnZpel9uYmNsdXN0KGNkZiwga21lYW5zLCBtZXRob2QgPSAid3NzIikgIzQgY2x1c3RlcnMKYGBgCgpgYGB7ciwgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9N30KIyBLIG1lYW5zIHdpdGggNCBjbHVzdGVycwpzZXQuc2VlZCgxMjMpCms0ID0ga21lYW5zKGNkZiwgNCxuc3RhcnQ9MjUpCgojIHBsb3QKZnZpel9jbHVzdGVyKGs0LCBkYXRhID0gY2RmKSt0aGVtZV9maXZldGhpcnR5ZWlnaHQoKSt0aGVtZShyZWN0ID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiV2hpdGUiLGxpbmV0eXBlID0gMCwgY29sb3VyID0gTkEpKStsYWJzKHRpdGxlPSJDbHVzdGVyIG9mIENvdW50aWVzIGluIEtlbnlhIGJhc2VkIG9uIEhvdXNlaG9sZCIsY2FwdGlvbj0iRGF0YSBmcm9tIHJLZW55YUNlbnN1cyIpCmBgYAoK