Overview

Load Libraries

options(scipen = 999)
library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
-- Attaching packages --------------------------------------------------------------------------------------------------------------------- tidyverse 1.3.0 --
v ggplot2 3.3.3     v purrr   0.3.4
v tibble  3.0.4     v dplyr   1.0.2
v tidyr   1.1.2     v stringr 1.4.0
v readr   1.4.0     v forcats 0.5.0
-- Conflicts ------------------------------------------------------------------------------------------------------------------------ tidyverse_conflicts() --
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()

Load data

boston  <- read_csv("boston_2020.csv")

-- Column specification --------------------------------------------------------------------------------------------------------------------------------------
cols(
  .default = col_character(),
  PID = col_double(),
  AV_TOTAL = col_double(),
  LAND_SF = col_double(),
  YR_BUILT = col_double(),
  YR_REMOD = col_double(),
  LIVING_AREA = col_double(),
  NUM_FLOORS = col_double(),
  STRUCTURE_CLASS = col_logical(),
  R_TOTAL_RMS = col_double(),
  R_BDRMS = col_double(),
  R_FULL_BTH = col_double(),
  R_HALF_BTH = col_double(),
  R_FPLACE = col_double()
)
i Use `spec()` for the full column specifications.
zips    <- read_csv("boston_zips.csv")

-- Column specification --------------------------------------------------------------------------------------------------------------------------------------
cols(
  ZIP = col_character(),
  Population = col_double(),
  Pop_Density = col_double(),
  Median_Income = col_double(),
  City_State = col_character()
)
truecar <- read_csv("true_car_prices_50k.csv")

-- Column specification --------------------------------------------------------------------------------------------------------------------------------------
cols(
  vin = col_character(),
  make = col_character(),
  model = col_character(),
  year = col_double(),
  price = col_double(),
  mileage = col_double(),
  city = col_character(),
  state = col_character(),
  region = col_character(),
  population = col_double(),
  lat = col_double(),
  lng = col_double()
)

Top N Frequency

framework for our function, here we want to create working code of what we want our function to do.

  1. we want to create a top 20 frequency per character column
  2. we want to plot the frequency
freq <- truecar %>%
  group_by(make) %>%
  summarise(n = n()) %>%
  mutate(pct = n/sum(n)) %>%
  arrange(desc(n)) %>%
  top_n(20,n)
`summarise()` ungrouping output (override with `.groups` argument)
print(freq)

freq %>%
  ggplot(aes(reorder(make,n),n)) +
  geom_col() +
  coord_flip() +
  labs(title = "Frequency Analysis",
       y = "count",
       x = "category")

Next wrap code in a function

like this.

freq_function <- function(){
  # frequency analysis of true car by make 
  freq <- truecar %>%
    group_by(make) %>%
    summarise(n = n()) %>%
    mutate(pct = n/sum(n)) %>%
    arrange(desc(n)) %>%
    top_n(20,n)
  
  print(freq)
  
  freq %>%
    ggplot(aes(reorder(make,n),n)) +
    geom_col() +
    coord_flip() +
    labs(title = "Frequency Analysis",
         y = "count",
         x = "category")
}

freq_function()

Parameterize your function

add the argument data and replace truecar with the argument


freq_function <- function(data){
  # frequency analysis of true car by make 
  freq <- data %>%
    group_by(make) %>%
    summarise(n = n()) %>%
    mutate(pct = n/sum(n)) %>%
    arrange(desc(n)) %>%
    top_n(20,n)
  
  print(freq)
  
  freq %>%
    ggplot(aes(reorder(make,n),n)) +
    geom_col() +
    coord_flip() +
    labs(title = "Frequency Analysis",
         y = "count",
         x = "category")
}

freq_function(truecar)
`summarise()` ungrouping output (override with `.groups` argument)

Next replace column

you want to pass it a column to perform frequency analysis of to do this you need to tell R that the string passed is in fact a column. to do this we use !!as.name(“string”) this tells R that the string is a column name

  1. add an argument column to your function
  2. repalce make with !!as.name(column)
  3. test with make, model, year, city, state
freq_function <- function(data, column){
  # frequency analysis of true car by make 
  freq <- data %>%
    group_by(!!as.name(column)) %>%
    summarise(n = n()) %>%
    mutate(pct = n/sum(n)) %>%
    arrange(desc(n)) %>%
    top_n(20,n)
  
  print(freq)
  
  freq %>%
    ggplot(aes(reorder(!!as.name(column),n),n)) +
    geom_col() +
    coord_flip() +
    labs(title = "Frequency Analysis",
         subtitle = column,
         y = "count",
         x = "category")
}
freq_function(truecar, "make")
`summarise()` ungrouping output (override with `.groups` argument)

freq_function(truecar, "model")
`summarise()` ungrouping output (override with `.groups` argument)

freq_function(truecar, "year")
`summarise()` ungrouping output (override with `.groups` argument)

freq_function(truecar, "city")
`summarise()` ungrouping output (override with `.groups` argument)

freq_function(truecar, "state")
`summarise()` ungrouping output (override with `.groups` argument)

Function 1 GET_STATS

get_stats(dataframe, column)

your challenge is to add the mean, min, max, and column name to the table returned by the function call.

get_stats <- function(dataframe, column){
  dataframe %>%
    summarise(n = n(),
              n_distinct = n_distinct(!!as.name(column)),
              n_miss = sum(is.na(!!as.name(column))),
              mean = mean(!!as.name(column)),
              min = min(!!as.name(column)),
              max = max(!!as.name(column))) %>%
    mutate( column = column)
  
              # add mean, min, max 
               # %>%
    # add a column name ~ mutate(column = column)
}

get_stats(boston,"AV_TOTAL")
get_stats(boston, "LIVING_AREA")
get_stats(truecar, "price")
get_stats(truecar, "mileage")

Function 2 get_chart(dataframe, group_by_column, mean_column)

group_by_column <- "ZIPCODE"
mean_column <- "AV_TOTAL"
dataset <- boston 

get_chart <- function(dataframe, group_by_column, mean_column){
  res <- dataframe %>%
    group_by(!!as.name(group_by_column)) %>%
    summarise(mean = mean(!!as.name(mean_column))) # change this 
  
  res %>% ggplot(aes(reorder(!!as.name(group_by_column), mean), mean)) +
    geom_col() +
    labs(title = paste("mean ",mean_column, " by ", group_by_column),
         x = "ZIPCODE", 
         y = "Mean AV_TOTAL", # fix this 
         caption = "Dataset: Boston")
}

group_by_column2 <- "R_BLDG_STYL"
mean_column2 <- "LIVING_AREA"
dataset <- boston 

get_chart2 <- function(dataframe, group_by_column2, mean_column2){
  res <- dataframe %>%
    group_by(!!as.name(group_by_column2)) %>%
    summarise(mean = mean(!!as.name(mean_column2))) # change this 
  
  res %>% ggplot(aes(reorder(!!as.name(group_by_column2), mean), mean)) +
    geom_col() +
    theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
    labs(title = paste("mean ",mean_column2, " by ", group_by_column2),
         x = "R_BLDG_STYL", 
         y = "Mean LIVING_AREA", # fix this 
         caption = "Dataset: Boston")
}

group_by_column3 <- "make"
mean_column3 <- "price"
dataset <- truecar 

get_chart3 <- function(dataframe, group_by_column3, mean_column3){
  res <- dataframe %>%
    group_by(!!as.name(group_by_column3)) %>%
    summarise(mean = mean(!!as.name(mean_column3))) # change this 
  
  res %>% ggplot(aes(reorder(!!as.name(group_by_column3), mean), mean)) +
    geom_col() +
    theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
    labs(title = paste("mean ",mean_column3, " by ", group_by_column3),
         x = "make", 
         y = "Mean price", # fix this 
         caption = "Dataset: truecar")
}

group_by_column4 <- "make"
mean_column4 <- "mileage"
dataset <- truecar 

get_chart4 <- function(dataframe, group_by_column4, mean_column4){
  res <- dataframe %>%
    group_by(!!as.name(group_by_column4)) %>%
    summarise(mean = mean(!!as.name(mean_column4))) # change this 
  
  res %>% ggplot(aes(reorder(!!as.name(group_by_column4), mean), mean)) +
    geom_col() +
    theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
    labs(title = paste("mean ",mean_column4, " by ", group_by_column4),
         x = "make", 
         y = "Mean mileage", # fix this 
         caption = "Dataset: truecar")
}

get_chart(boston, "ZIPCODE", "AV_TOTAL")
`summarise()` ungrouping output (override with `.groups` argument)

get_chart2(boston, "R_BLDG_STYL", "LIVING_AREA")
`summarise()` ungrouping output (override with `.groups` argument)

get_chart3(truecar, "make", "price")
`summarise()` ungrouping output (override with `.groups` argument)

get_chart4(truecar, "make", "mileage")
`summarise()` ungrouping output (override with `.groups` argument)

LS0tDQp0aXRsZTogIkZyZXEgT3V0ISINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQojIE92ZXJ2aWV3IA0KDQoNCg0KIyMgTG9hZCBMaWJyYXJpZXMNCg0KYGBge3J9DQpvcHRpb25zKHNjaXBlbiA9IDk5OSkNCmxpYnJhcnkodGlkeXZlcnNlKQ0KYGBgDQoNCiMjIExvYWQgZGF0YSANCg0KYGBge3J9DQpib3N0b24gIDwtIHJlYWRfY3N2KCJib3N0b25fMjAyMC5jc3YiKQ0KemlwcyAgICA8LSByZWFkX2NzdigiYm9zdG9uX3ppcHMuY3N2IikNCnRydWVjYXIgPC0gcmVhZF9jc3YoInRydWVfY2FyX3ByaWNlc181MGsuY3N2IikNCmBgYA0KDQojIyBUb3AgTiBGcmVxdWVuY3kNCg0KZnJhbWV3b3JrIGZvciBvdXIgZnVuY3Rpb24sIGhlcmUgd2Ugd2FudCB0byBjcmVhdGUgd29ya2luZyBjb2RlIG9mIHdoYXQgd2Ugd2FudCBvdXIgZnVuY3Rpb24gdG8gZG8uIA0KDQoxLiB3ZSB3YW50IHRvIGNyZWF0ZSBhIHRvcCAyMCBmcmVxdWVuY3kgcGVyIGNoYXJhY3RlciBjb2x1bW4NCjIuIHdlIHdhbnQgdG8gcGxvdCB0aGUgZnJlcXVlbmN5IA0KDQoNCmBgYHtyfQ0KZnJlcSA8LSB0cnVlY2FyICU+JQ0KICBncm91cF9ieShtYWtlKSAlPiUNCiAgc3VtbWFyaXNlKG4gPSBuKCkpICU+JQ0KICBtdXRhdGUocGN0ID0gbi9zdW0obikpICU+JQ0KICBhcnJhbmdlKGRlc2MobikpICU+JQ0KICB0b3BfbigyMCxuKQ0KDQpwcmludChmcmVxKQ0KDQpmcmVxICU+JQ0KICBnZ3Bsb3QoYWVzKHJlb3JkZXIobWFrZSxuKSxuKSkgKw0KICBnZW9tX2NvbCgpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgbGFicyh0aXRsZSA9ICJGcmVxdWVuY3kgQW5hbHlzaXMiLA0KICAgICAgIHkgPSAiY291bnQiLA0KICAgICAgIHggPSAiY2F0ZWdvcnkiKQ0KDQpgYGANCg0KIyMgTmV4dCB3cmFwIGNvZGUgaW4gYSBmdW5jdGlvbg0KDQpsaWtlIHRoaXMuDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFfQ0KZnJlcV9mdW5jdGlvbiA8LSBmdW5jdGlvbigpew0KICAjIGZyZXF1ZW5jeSBhbmFseXNpcyBvZiB0cnVlIGNhciBieSBtYWtlIA0KICBmcmVxIDwtIHRydWVjYXIgJT4lDQogICAgZ3JvdXBfYnkobWFrZSkgJT4lDQogICAgc3VtbWFyaXNlKG4gPSBuKCkpICU+JQ0KICAgIG11dGF0ZShwY3QgPSBuL3N1bShuKSkgJT4lDQogICAgYXJyYW5nZShkZXNjKG4pKSAlPiUNCiAgICB0b3BfbigyMCxuKQ0KICANCiAgcHJpbnQoZnJlcSkNCiAgDQogIGZyZXEgJT4lDQogICAgZ2dwbG90KGFlcyhyZW9yZGVyKG1ha2UsbiksbikpICsNCiAgICBnZW9tX2NvbCgpICsNCiAgICBjb29yZF9mbGlwKCkgKw0KICAgIGxhYnModGl0bGUgPSAiRnJlcXVlbmN5IEFuYWx5c2lzIiwNCiAgICAgICAgIHkgPSAiY291bnQiLA0KICAgICAgICAgeCA9ICJjYXRlZ29yeSIpDQp9DQoNCmZyZXFfZnVuY3Rpb24oKQ0KYGBgDQoNCiMjIFBhcmFtZXRlcml6ZSB5b3VyIGZ1bmN0aW9uDQoNCmFkZCB0aGUgYXJndW1lbnQgZGF0YSBhbmQgcmVwbGFjZSB0cnVlY2FyIHdpdGggdGhlIGFyZ3VtZW50IA0KDQpgYGB7cn0NCg0KZnJlcV9mdW5jdGlvbiA8LSBmdW5jdGlvbihkYXRhKXsNCiAgIyBmcmVxdWVuY3kgYW5hbHlzaXMgb2YgdHJ1ZSBjYXIgYnkgbWFrZSANCiAgZnJlcSA8LSBkYXRhICU+JQ0KICAgIGdyb3VwX2J5KG1ha2UpICU+JQ0KICAgIHN1bW1hcmlzZShuID0gbigpKSAlPiUNCiAgICBtdXRhdGUocGN0ID0gbi9zdW0obikpICU+JQ0KICAgIGFycmFuZ2UoZGVzYyhuKSkgJT4lDQogICAgdG9wX24oMjAsbikNCiAgDQogIHByaW50KGZyZXEpDQogIA0KICBmcmVxICU+JQ0KICAgIGdncGxvdChhZXMocmVvcmRlcihtYWtlLG4pLG4pKSArDQogICAgZ2VvbV9jb2woKSArDQogICAgY29vcmRfZmxpcCgpICsNCiAgICBsYWJzKHRpdGxlID0gIkZyZXF1ZW5jeSBBbmFseXNpcyIsDQogICAgICAgICB5ID0gImNvdW50IiwNCiAgICAgICAgIHggPSAiY2F0ZWdvcnkiKQ0KfQ0KDQpmcmVxX2Z1bmN0aW9uKHRydWVjYXIpDQoNCmBgYA0KDQojIyMgTmV4dCByZXBsYWNlIGNvbHVtbiANCg0KeW91IHdhbnQgdG8gcGFzcyBpdCBhIGNvbHVtbiB0byBwZXJmb3JtIGZyZXF1ZW5jeSBhbmFseXNpcyBvZiB0byBkbyB0aGlzIHlvdSBuZWVkIHRvIHRlbGwgUiANCnRoYXQgdGhlIHN0cmluZyBwYXNzZWQgaXMgaW4gZmFjdCBhIGNvbHVtbi4gdG8gZG8gdGhpcyB3ZSB1c2UgISFhcy5uYW1lKCJzdHJpbmciKSB0aGlzIHRlbGxzIFIgdGhhdCB0aGUgc3RyaW5nIGlzIGEgY29sdW1uIG5hbWUgDQoNCjEuIGFkZCBhbiBhcmd1bWVudCBjb2x1bW4gdG8geW91ciBmdW5jdGlvbg0KMi4gcmVwYWxjZSBtYWtlIHdpdGggISFhcy5uYW1lKGNvbHVtbikNCjMuIHRlc3Qgd2l0aCBtYWtlLCBtb2RlbCwgeWVhciwgY2l0eSwgc3RhdGUgDQoNCmBgYHtyfQ0KZnJlcV9mdW5jdGlvbiA8LSBmdW5jdGlvbihkYXRhLCBjb2x1bW4pew0KICAjIGZyZXF1ZW5jeSBhbmFseXNpcyBvZiB0cnVlIGNhciBieSBtYWtlIA0KICBmcmVxIDwtIGRhdGEgJT4lDQogICAgZ3JvdXBfYnkoISFhcy5uYW1lKGNvbHVtbikpICU+JQ0KICAgIHN1bW1hcmlzZShuID0gbigpKSAlPiUNCiAgICBtdXRhdGUocGN0ID0gbi9zdW0obikpICU+JQ0KICAgIGFycmFuZ2UoZGVzYyhuKSkgJT4lDQogICAgdG9wX24oMjAsbikNCiAgDQogIHByaW50KGZyZXEpDQogIA0KICBmcmVxICU+JQ0KICAgIGdncGxvdChhZXMocmVvcmRlcighIWFzLm5hbWUoY29sdW1uKSxuKSxuKSkgKw0KICAgIGdlb21fY29sKCkgKw0KICAgIGNvb3JkX2ZsaXAoKSArDQogICAgbGFicyh0aXRsZSA9ICJGcmVxdWVuY3kgQW5hbHlzaXMiLA0KICAgICAgICAgc3VidGl0bGUgPSBjb2x1bW4sDQogICAgICAgICB5ID0gImNvdW50IiwNCiAgICAgICAgIHggPSAiY2F0ZWdvcnkiKQ0KfQ0KZnJlcV9mdW5jdGlvbih0cnVlY2FyLCAibWFrZSIpDQpmcmVxX2Z1bmN0aW9uKHRydWVjYXIsICJtb2RlbCIpDQpmcmVxX2Z1bmN0aW9uKHRydWVjYXIsICJ5ZWFyIikNCmZyZXFfZnVuY3Rpb24odHJ1ZWNhciwgImNpdHkiKQ0KZnJlcV9mdW5jdGlvbih0cnVlY2FyLCAic3RhdGUiKQ0KDQpgYGANCg0KIyBGdW5jdGlvbiAxIEdFVF9TVEFUUyANCg0KIyMgZ2V0X3N0YXRzKGRhdGFmcmFtZSwgY29sdW1uKQ0KeW91ciBjaGFsbGVuZ2UgaXMgdG8gYWRkIHRoZSBtZWFuLCBtaW4sIG1heCwgYW5kIGNvbHVtbiBuYW1lIHRvIHRoZSB0YWJsZSByZXR1cm5lZCBieSB0aGUgZnVuY3Rpb24gY2FsbC4gDQoNCmBgYHtyfQ0KZ2V0X3N0YXRzIDwtIGZ1bmN0aW9uKGRhdGFmcmFtZSwgY29sdW1uKXsNCiAgZGF0YWZyYW1lICU+JQ0KICAgIHN1bW1hcmlzZShuID0gbigpLA0KICAgICAgICAgICAgICBuX2Rpc3RpbmN0ID0gbl9kaXN0aW5jdCghIWFzLm5hbWUoY29sdW1uKSksDQogICAgICAgICAgICAgIG5fbWlzcyA9IHN1bShpcy5uYSghIWFzLm5hbWUoY29sdW1uKSkpLA0KICAgICAgICAgICAgICBtZWFuID0gbWVhbighIWFzLm5hbWUoY29sdW1uKSksDQogICAgICAgICAgICAgIG1pbiA9IG1pbighIWFzLm5hbWUoY29sdW1uKSksDQogICAgICAgICAgICAgIG1heCA9IG1heCghIWFzLm5hbWUoY29sdW1uKSkpICU+JQ0KICAgIG11dGF0ZSggY29sdW1uID0gY29sdW1uKQ0KICANCiAgICAgICAgICAgICAgIyBhZGQgbWVhbiwgbWluLCBtYXggDQogICAgICAgICAgICAgICAjICU+JQ0KICAgICMgYWRkIGEgY29sdW1uIG5hbWUgfiBtdXRhdGUoY29sdW1uID0gY29sdW1uKQ0KfQ0KDQpnZXRfc3RhdHMoYm9zdG9uLCJBVl9UT1RBTCIpDQpnZXRfc3RhdHMoYm9zdG9uLCAiTElWSU5HX0FSRUEiKQ0KZ2V0X3N0YXRzKHRydWVjYXIsICJwcmljZSIpDQpnZXRfc3RhdHModHJ1ZWNhciwgIm1pbGVhZ2UiKQ0KYGBgDQoNCiMgRnVuY3Rpb24gMiBnZXRfY2hhcnQoZGF0YWZyYW1lLCBncm91cF9ieV9jb2x1bW4sIG1lYW5fY29sdW1uKQ0KDQpgYGB7cn0NCmdyb3VwX2J5X2NvbHVtbiA8LSAiWklQQ09ERSINCm1lYW5fY29sdW1uIDwtICJBVl9UT1RBTCINCmRhdGFzZXQgPC0gYm9zdG9uIA0KDQpnZXRfY2hhcnQgPC0gZnVuY3Rpb24oZGF0YWZyYW1lLCBncm91cF9ieV9jb2x1bW4sIG1lYW5fY29sdW1uKXsNCiAgcmVzIDwtIGRhdGFmcmFtZSAlPiUNCiAgICBncm91cF9ieSghIWFzLm5hbWUoZ3JvdXBfYnlfY29sdW1uKSkgJT4lDQogICAgc3VtbWFyaXNlKG1lYW4gPSBtZWFuKCEhYXMubmFtZShtZWFuX2NvbHVtbikpKSAjIGNoYW5nZSB0aGlzIA0KICANCiAgcmVzICU+JSBnZ3Bsb3QoYWVzKHJlb3JkZXIoISFhcy5uYW1lKGdyb3VwX2J5X2NvbHVtbiksIG1lYW4pLCBtZWFuKSkgKw0KICAgIGdlb21fY29sKCkgKw0KICAgIGxhYnModGl0bGUgPSBwYXN0ZSgibWVhbiAiLG1lYW5fY29sdW1uLCAiIGJ5ICIsIGdyb3VwX2J5X2NvbHVtbiksDQogICAgICAgICB4ID0gIlpJUENPREUiLCANCiAgICAgICAgIHkgPSAiTWVhbiBBVl9UT1RBTCIsICMgZml4IHRoaXMgDQogICAgICAgICBjYXB0aW9uID0gIkRhdGFzZXQ6IEJvc3RvbiIpDQp9DQoNCmdyb3VwX2J5X2NvbHVtbjIgPC0gIlJfQkxER19TVFlMIg0KbWVhbl9jb2x1bW4yIDwtICJMSVZJTkdfQVJFQSINCmRhdGFzZXQgPC0gYm9zdG9uIA0KDQpnZXRfY2hhcnQyIDwtIGZ1bmN0aW9uKGRhdGFmcmFtZSwgZ3JvdXBfYnlfY29sdW1uMiwgbWVhbl9jb2x1bW4yKXsNCiAgcmVzIDwtIGRhdGFmcmFtZSAlPiUNCiAgICBncm91cF9ieSghIWFzLm5hbWUoZ3JvdXBfYnlfY29sdW1uMikpICU+JQ0KICAgIHN1bW1hcmlzZShtZWFuID0gbWVhbighIWFzLm5hbWUobWVhbl9jb2x1bW4yKSkpICMgY2hhbmdlIHRoaXMgDQogIA0KICByZXMgJT4lIGdncGxvdChhZXMocmVvcmRlcighIWFzLm5hbWUoZ3JvdXBfYnlfY29sdW1uMiksIG1lYW4pLCBtZWFuKSkgKw0KICAgIGdlb21fY29sKCkgKw0KICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICsNCiAgICBsYWJzKHRpdGxlID0gcGFzdGUoIm1lYW4gIixtZWFuX2NvbHVtbjIsICIgYnkgIiwgZ3JvdXBfYnlfY29sdW1uMiksDQogICAgICAgICB4ID0gIlJfQkxER19TVFlMIiwgDQogICAgICAgICB5ID0gIk1lYW4gTElWSU5HX0FSRUEiLCAjIGZpeCB0aGlzIA0KICAgICAgICAgY2FwdGlvbiA9ICJEYXRhc2V0OiBCb3N0b24iKQ0KfQ0KDQpncm91cF9ieV9jb2x1bW4zIDwtICJtYWtlIg0KbWVhbl9jb2x1bW4zIDwtICJwcmljZSINCmRhdGFzZXQgPC0gdHJ1ZWNhciANCg0KZ2V0X2NoYXJ0MyA8LSBmdW5jdGlvbihkYXRhZnJhbWUsIGdyb3VwX2J5X2NvbHVtbjMsIG1lYW5fY29sdW1uMyl7DQogIHJlcyA8LSBkYXRhZnJhbWUgJT4lDQogICAgZ3JvdXBfYnkoISFhcy5uYW1lKGdyb3VwX2J5X2NvbHVtbjMpKSAlPiUNCiAgICBzdW1tYXJpc2UobWVhbiA9IG1lYW4oISFhcy5uYW1lKG1lYW5fY29sdW1uMykpKSAjIGNoYW5nZSB0aGlzIA0KICANCiAgcmVzICU+JSBnZ3Bsb3QoYWVzKHJlb3JkZXIoISFhcy5uYW1lKGdyb3VwX2J5X2NvbHVtbjMpLCBtZWFuKSwgbWVhbikpICsNCiAgICBnZW9tX2NvbCgpICsNCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKSArDQogICAgbGFicyh0aXRsZSA9IHBhc3RlKCJtZWFuICIsbWVhbl9jb2x1bW4zLCAiIGJ5ICIsIGdyb3VwX2J5X2NvbHVtbjMpLA0KICAgICAgICAgeCA9ICJtYWtlIiwgDQogICAgICAgICB5ID0gIk1lYW4gcHJpY2UiLCAjIGZpeCB0aGlzIA0KICAgICAgICAgY2FwdGlvbiA9ICJEYXRhc2V0OiB0cnVlY2FyIikNCn0NCg0KZ3JvdXBfYnlfY29sdW1uNCA8LSAibWFrZSINCm1lYW5fY29sdW1uNCA8LSAibWlsZWFnZSINCmRhdGFzZXQgPC0gdHJ1ZWNhciANCg0KZ2V0X2NoYXJ0NCA8LSBmdW5jdGlvbihkYXRhZnJhbWUsIGdyb3VwX2J5X2NvbHVtbjQsIG1lYW5fY29sdW1uNCl7DQogIHJlcyA8LSBkYXRhZnJhbWUgJT4lDQogICAgZ3JvdXBfYnkoISFhcy5uYW1lKGdyb3VwX2J5X2NvbHVtbjQpKSAlPiUNCiAgICBzdW1tYXJpc2UobWVhbiA9IG1lYW4oISFhcy5uYW1lKG1lYW5fY29sdW1uNCkpKSAjIGNoYW5nZSB0aGlzIA0KICANCiAgcmVzICU+JSBnZ3Bsb3QoYWVzKHJlb3JkZXIoISFhcy5uYW1lKGdyb3VwX2J5X2NvbHVtbjQpLCBtZWFuKSwgbWVhbikpICsNCiAgICBnZW9tX2NvbCgpICsNCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKSArDQogICAgbGFicyh0aXRsZSA9IHBhc3RlKCJtZWFuICIsbWVhbl9jb2x1bW40LCAiIGJ5ICIsIGdyb3VwX2J5X2NvbHVtbjQpLA0KICAgICAgICAgeCA9ICJtYWtlIiwgDQogICAgICAgICB5ID0gIk1lYW4gbWlsZWFnZSIsICMgZml4IHRoaXMgDQogICAgICAgICBjYXB0aW9uID0gIkRhdGFzZXQ6IHRydWVjYXIiKQ0KfQ0KDQpnZXRfY2hhcnQoYm9zdG9uLCAiWklQQ09ERSIsICJBVl9UT1RBTCIpDQpnZXRfY2hhcnQyKGJvc3RvbiwgIlJfQkxER19TVFlMIiwgIkxJVklOR19BUkVBIikNCmdldF9jaGFydDModHJ1ZWNhciwgIm1ha2UiLCAicHJpY2UiKQ0KZ2V0X2NoYXJ0NCh0cnVlY2FyLCAibWFrZSIsICJtaWxlYWdlIikNCg0KYGBgDQoNCg==