library(tidyverse)
library(broom)
library(plotly)
library(tidycensus)      # gets census data that we can use to create maps
library(sf)              # helper package for mapping
Linking to GEOS 3.9.1, GDAL 3.4.0, PROJ 8.1.1; sf_use_s2() is TRUE
library(leaflet)         # interactive mapping package
library(trendyy)
library(usdata)          # this package has a conversion utility for state abbreviations to full names

Assignment

  1. Pick one of these and create a choropleth map with leaflet.
census_api_key("686d80e4f7ee63c3023fcefac14d068f56cc4d19", install = TRUE)
Error: A CENSUS_API_KEY already exists. You can overwrite it with the argument overwrite=TRUE

I first entered my census api key.

smokers <- read_csv("Cig_smoking_percent.csv")
Rows: 52 Columns: 5
── Column specification ────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (1): State
dbl (3): Cig_percent, Low_Confidence_Limit, High_Confidence_Limit

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

I then read in the excel data for Cigarette Smokers

states_leaflet <- get_acs(geography = "state",       
                  variables = "cig_percent",          
                  geometry = TRUE)                   
Getting data from the 2016-2020 5-year ACS
Downloading feature geometry from the Census website.  To cache shapefiles for use in future sessions, set `options(tigris_use_cache = TRUE)`.
Error: Your API call has errors.  The API message returned is error: error: unknown variable 'cig_percentE'.

I used the code above to obtain state population and map data from the census bureau.


nicorette_colors <- colorNumeric(palette = "viridis", domain = nicorette_data$Cig_percent)

states_leaflet %>% 
  rename(location = NAME) %>% 
  inner_join(nicorette_data) %>% 
  leaflet() %>% 
  addTiles() %>%
  addPolygons(weight = 1,
              fillColor = ~nicorette_colors(Cig_percent), 
              label = ~paste0(location, ", Cig Percent = ", Cig_percent),
              highlight = highlightOptions(weight = 2)) %>% 
  setView(-95, 40, zoom = 4) %>% 
  addLegend(pal = nicorette_colors, values = ~Cig_percent)
Joining, by = "location"
Warning: sf layer has inconsistent datum (+proj=longlat +datum=NAD83 +no_defs).
Need '+proj=longlat +datum=WGS84'

Lastly, I created a chloropleth map using leaflet to show the percent of cigarette smokers among US states that you can hover over to display the information.

  1. Choose a google search term or phrase that is relevant to your chosen CDC data, and create a choropleth of that as well.
nicorette <- trendy("nicorette", 
                   geo = "US", 
                   from = "2020-01-01", to = "2021-01-01")


nicorette_states <- nicorette %>%
  get_interest_region()

nicorette_states

I chose the Google search term nicorette because I felt it would be closely related to populations of smokers as most would probably like to quit the habit at some point or another.

nicorette_colors <- colorNumeric(palette = "viridis", domain = nicorette_states$hits)

states_leaflet %>% 
  rename(location = NAME) %>% 
  inner_join(nicorette_states) %>% 
  leaflet() %>% 
  addTiles() %>%
  addPolygons(weight = 1,
              fillColor = ~nicorette_colors(hits), 
              label = ~paste0(location, ", Search volume for nicorette = ", hits),
              highlight = highlightOptions(weight = 2)) %>% 
  setView(-95, 40, zoom = 4) %>% 
  addLegend(pal = nicorette_colors, values = ~hits)
Joining, by = "location"
Warning: sf layer has inconsistent datum (+proj=longlat +datum=NAD83 +no_defs).
Need '+proj=longlat +datum=WGS84'

I used the code above to create a choloropleth map for search hits for nicorette in the US. Vermont had the highest rate of hits followed by New York.

  1. Do a linear model relating the CDC data to the good search term, and create a plotly scatterplot of the relationship.
smokers <- read_csv("Cig_smoking_percent.csv")
Rows: 52 Columns: 5
── Column specification ────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (1): State
dbl (3): Cig_percent, Low_Confidence_Limit, High_Confidence_Limit

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
glimpse(smokers)
Rows: 52
Columns: 5
$ State                 <chr> "AL", "AK", "AZ", "AR", "CA", "CO", "CT", "DE", "DC", "FL", "GA", "HI", "ID", "IL", "IN", "IA", "KS"…
$ Cig_percent           <dbl> 19.2, 19.1, 14.0, 22.7, 11.2, 14.5, 12.2, 16.5, 13.8, 14.5, 16.1, 13.4, 14.7, 15.5, 21.1, 16.6, 17.2…
$ Low_Confidence_Limit  <dbl> 17.9, 16.9, 12.7, 20.9, 10.4, 13.6, 11.3, 15.1, 12.3, 13.4, 15.1, 12.3, 13.0, 14.2, 19.8, 15.7, 16.2…
$ High_Confidence_Limit <dbl> 20.5, 21.3, 15.3, 24.5, 12.0, 15.4, 13.1, 17.9, 15.3, 15.6, 17.1, 14.5, 16.4, 16.8, 22.4, 17.5, 18.2…
$ Sample_Size           <dbl> 6347, 2698, 7758, 5177, 11118, 8188, 10276, 5011, 4137, 14589, 8783, 7566, 3594, 5128, 7269, 8842, 1…
glimpse(nicorette_states)
Rows: 51
Columns: 5
$ location <chr> "Vermont", "New York", "New Hampshire", "Rhode Island", "Kentucky", "Oregon", "Pennsylvania", "North Carolina", "…
$ hits     <int> 100, 69, 52, 51, 51, 47, 47, 46, 45, 45, 44, 44, 44, 44, 43, 43, 42, 42, 42, 41, 41, 40, 40, 40, 39, 39, 38, 37, …
$ keyword  <chr> "nicorette", "nicorette", "nicorette", "nicorette", "nicorette", "nicorette", "nicorette", "nicorette", "nicorett…
$ geo      <chr> "US", "US", "US", "US", "US", "US", "US", "US", "US", "US", "US", "US", "US", "US", "US", "US", "US", "US", "US",…
$ gprop    <chr> "web", "web", "web", "web", "web", "web", "web", "web", "web", "web", "web", "web", "web", "web", "web", "web", "…
nicorette_states %>%
  mutate(State = state2abbr(location)) %>%
  inner_join(smokers)
Joining, by = "State"
nicorette_data <- nicorette_states %>% 
  mutate(State = state2abbr(location)) %>% 
  inner_join(smokers)
Joining, by = "State"
nicorette_model <- lm(Cig_percent ~ hits, data = nicorette_data)

glance(nicorette_model)
nicorette_data %>% 
  drop_na() %>% 
  plot_ly(x = ~hits, 
          y = ~Cig_percent,
          hoverinfo = "text", 
          text = ~paste("State: ", location, "<br>", "'Nicorette' search rate: ", hits, "<br>", "Cig smoking percent: ", Cig_percent)) %>% 
  add_markers(showlegend = F) %>% 
  add_lines(y = ~fitted(nicorette_model)) %>% 
  layout(title = "Relationship between google searches for 'nicorette' and smoking percent rates, by state",
   xaxis = list(title = "Google search hits for 'nicorette'"),
   yaxis = list(title = "State smoking rate"))
NA

According to the statistical analysis for the relationship between Google search hits for nicorette, and smoking percent rate data, the relationship is not statistically significant (p = .42)

  1. Choose a second google search term or phrase that is relevant to your chosen CDC data and create a choropleth map.
tobacco <- trendy("tobacco", 
                   geo = "US", 
                   from = "2020-01-01", to = "2021-01-01")


tobacco_states <- tobacco %>%
  get_interest_region()

tobacco_states
tobacco_colors <- colorNumeric(palette = "viridis", domain = tobacco_states$hits)

states_leaflet %>% 
  rename(location = NAME) %>% 
  inner_join(tobacco_states) %>% 
  leaflet() %>% 
  addTiles() %>%
  addPolygons(weight = 1,
              fillColor = ~tobacco_colors(hits), 
              label = ~paste0(location, ", Search volume for tobacco = ", hits),
              highlight = highlightOptions(weight = 2)) %>% 
  setView(-95, 40, zoom = 4) %>% 
  addLegend(pal = tobacco_colors, values = ~hits)
Joining, by = "location"
Warning: sf layer has inconsistent datum (+proj=longlat +datum=NAD83 +no_defs).
Need '+proj=longlat +datum=WGS84'

The second term related to cigarette smokers that I searched for was ‘tobacco.’ I used trendy and the code above to create a chloropleth map for search hits for tobacco. The lighter states show a higher search rate, the darker purple states show a lower volume.

  1. Do the linear model and plotly graph between your second term and the CDC data.
smokers <- read_csv("Cig_smoking_percent.csv")
Rows: 52 Columns: 5
── Column specification ────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (1): State
dbl (3): Cig_percent, Low_Confidence_Limit, High_Confidence_Limit

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
glimpse(smokers)
Rows: 52
Columns: 5
$ State                 <chr> "AL", "AK", "AZ", "AR", "CA", "CO", "CT", "DE", "DC", "FL", "GA", "HI", "ID", "IL", "IN", "IA", "KS"…
$ Cig_percent           <dbl> 19.2, 19.1, 14.0, 22.7, 11.2, 14.5, 12.2, 16.5, 13.8, 14.5, 16.1, 13.4, 14.7, 15.5, 21.1, 16.6, 17.2…
$ Low_Confidence_Limit  <dbl> 17.9, 16.9, 12.7, 20.9, 10.4, 13.6, 11.3, 15.1, 12.3, 13.4, 15.1, 12.3, 13.0, 14.2, 19.8, 15.7, 16.2…
$ High_Confidence_Limit <dbl> 20.5, 21.3, 15.3, 24.5, 12.0, 15.4, 13.1, 17.9, 15.3, 15.6, 17.1, 14.5, 16.4, 16.8, 22.4, 17.5, 18.2…
$ Sample_Size           <dbl> 6347, 2698, 7758, 5177, 11118, 8188, 10276, 5011, 4137, 14589, 8783, 7566, 3594, 5128, 7269, 8842, 1…
glimpse(tobacco_states)
Rows: 51
Columns: 5
$ location <chr> "Minnesota", "Arkansas", "North Carolina", "Virginia", "Tennessee", "Kentucky", "West Virginia", "Michigan", "Mar…
$ hits     <int> 100, 99, 92, 78, 70, 69, 63, 61, 58, 57, 56, 55, 55, 54, 53, 53, 52, 52, 51, 51, 51, 50, 48, 48, 48, 45, 44, 42, …
$ keyword  <chr> "tobacco", "tobacco", "tobacco", "tobacco", "tobacco", "tobacco", "tobacco", "tobacco", "tobacco", "tobacco", "to…
$ geo      <chr> "US", "US", "US", "US", "US", "US", "US", "US", "US", "US", "US", "US", "US", "US", "US", "US", "US", "US", "US",…
$ gprop    <chr> "web", "web", "web", "web", "web", "web", "web", "web", "web", "web", "web", "web", "web", "web", "web", "web", "…
tobacco_states %>%
  mutate(State = state2abbr(location)) %>%
  inner_join(smokers)
Joining, by = "State"
tobacco_data <- tobacco_states %>% 
  mutate(State = state2abbr(location)) %>% 
  inner_join(smokers)
Joining, by = "State"
tobacco_model <- lm(Cig_percent ~ hits, data = tobacco_data)

glance(tobacco_model)
tobacco_data %>% 
  drop_na() %>% 
  plot_ly(x = ~hits, 
          y = ~Cig_percent,
          hoverinfo = "text", 
          text = ~paste("State: ", location, "<br>", "'Tobacco' search rate: ", hits, "<br>", "Cig smoking percent: ", Cig_percent)) %>% 
  add_markers(showlegend = F) %>% 
  add_lines(y = ~fitted(tobacco_model)) %>% 
  layout(title = "Relationship between google searches for 'tobacco' and smoking percent rates, by state",
   xaxis = list(title = "Google search hits for 'tobacco'"),
   yaxis = list(title = "State smoking rate"))
NA

According to the statistical analysis done above, Google searches for ‘tobacco,’ and cigarette smoking percentage by state do have a statistically significant relationship (p=.0001). There is a positive linear correlation between searches for tobacco and percentage of cigarette smokers. The more searches for tobacco on the web, the higher percentage of smokers in that state.

LS0tCnRpdGxlOiAiQ2hvcm9wbGV0aCBtYXBzIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgoKCgoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGJyb29tKQpsaWJyYXJ5KHBsb3RseSkKbGlicmFyeSh0aWR5Y2Vuc3VzKSAgICAgICMgZ2V0cyBjZW5zdXMgZGF0YSB0aGF0IHdlIGNhbiB1c2UgdG8gY3JlYXRlIG1hcHMKbGlicmFyeShzZikgICAgICAgICAgICAgICMgaGVscGVyIHBhY2thZ2UgZm9yIG1hcHBpbmcKbGlicmFyeShsZWFmbGV0KSAgICAgICAgICMgaW50ZXJhY3RpdmUgbWFwcGluZyBwYWNrYWdlCmxpYnJhcnkodHJlbmR5eSkKbGlicmFyeSh1c2RhdGEpICAgICAgICAgICMgdGhpcyBwYWNrYWdlIGhhcyBhIGNvbnZlcnNpb24gdXRpbGl0eSBmb3Igc3RhdGUgYWJicmV2aWF0aW9ucyB0byBmdWxsIG5hbWVzCmBgYAoKCkFzc2lnbm1lbnQKCgoxLiBQaWNrIG9uZSBvZiB0aGVzZSBhbmQgY3JlYXRlIGEgY2hvcm9wbGV0aCBtYXAgd2l0aCBsZWFmbGV0LgpgYGB7cn0KY2Vuc3VzX2FwaV9rZXkoKQpgYGAKSSBmaXJzdCBlbnRlcmVkIG15IGNlbnN1cyBhcGkga2V5LgoKYGBge3J9CnNtb2tlcnMgPC0gcmVhZF9jc3YoIkNpZ19zbW9raW5nX3BlcmNlbnQuY3N2IikKYGBgCgpJIHRoZW4gcmVhZCBpbiB0aGUgZXhjZWwgZGF0YSBmb3IgQ2lnYXJldHRlIFNtb2tlcnMKCmBgYHtyfQpzdGF0ZXNfbGVhZmxldCA8LSBnZXRfYWNzKGdlb2dyYXBoeSA9ICJzdGF0ZSIsICAgICAgIAogICAgICAgICAgICAgICAgICB2YXJpYWJsZXMgPSAiQjAxMDAzXzAwMSIsICAgICAgICAgIAogICAgICAgICAgICAgICAgICBnZW9tZXRyeSA9IFRSVUUpICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgc2hpZnRfZ2VvID0gVCAgICAgICAgICAgICAgICAgICAgCgpgYGAKCkkgdXNlZCB0aGUgY29kZSBhYm92ZSB0byBvYnRhaW4gc3RhdGUgcG9wdWxhdGlvbiBhbmQgbWFwIGRhdGEgZnJvbSB0aGUgY2Vuc3VzIGJ1cmVhdS4KCmBgYHtyfQoKbmljb3JldHRlX2NvbG9ycyA8LSBjb2xvck51bWVyaWMocGFsZXR0ZSA9ICJ2aXJpZGlzIiwgZG9tYWluID0gbmljb3JldHRlX2RhdGEkQ2lnX3BlcmNlbnQpCgpzdGF0ZXNfbGVhZmxldCAlPiUgCiAgcmVuYW1lKGxvY2F0aW9uID0gTkFNRSkgJT4lIAogIGlubmVyX2pvaW4obmljb3JldHRlX2RhdGEpICU+JSAKICBsZWFmbGV0KCkgJT4lIAogIGFkZFRpbGVzKCkgJT4lCiAgYWRkUG9seWdvbnMod2VpZ2h0ID0gMSwKICAgICAgICAgICAgICBmaWxsQ29sb3IgPSB+bmljb3JldHRlX2NvbG9ycyhDaWdfcGVyY2VudCksIAogICAgICAgICAgICAgIGxhYmVsID0gfnBhc3RlMChsb2NhdGlvbiwgIiwgQ2lnIFBlcmNlbnQgPSAiLCBDaWdfcGVyY2VudCksCiAgICAgICAgICAgICAgaGlnaGxpZ2h0ID0gaGlnaGxpZ2h0T3B0aW9ucyh3ZWlnaHQgPSAyKSkgJT4lIAogIHNldFZpZXcoLTk1LCA0MCwgem9vbSA9IDQpICU+JSAKICBhZGRMZWdlbmQocGFsID0gbmljb3JldHRlX2NvbG9ycywgdmFsdWVzID0gfkNpZ19wZXJjZW50KQpgYGAKCgoKTGFzdGx5LCBJIGNyZWF0ZWQgYSBjaGxvcm9wbGV0aCBtYXAgdXNpbmcgbGVhZmxldCB0byBzaG93IHRoZSBwZXJjZW50IG9mIGNpZ2FyZXR0ZSBzbW9rZXJzIGFtb25nIFVTIHN0YXRlcyB0aGF0IHlvdSBjYW4gaG92ZXIgb3ZlciB0byBkaXNwbGF5IHRoZSBpbmZvcm1hdGlvbi4KCgoyLiBDaG9vc2UgYSBnb29nbGUgc2VhcmNoIHRlcm0gb3IgcGhyYXNlIHRoYXQgaXMgcmVsZXZhbnQgdG8geW91ciBjaG9zZW4gQ0RDIGRhdGEsIGFuZCBjcmVhdGUgYSBjaG9yb3BsZXRoIG9mIHRoYXQgYXMgd2VsbC4KCmBgYHtyfQpuaWNvcmV0dGUgPC0gdHJlbmR5KCJuaWNvcmV0dGUiLCAKICAgICAgICAgICAgICAgICAgIGdlbyA9ICJVUyIsIAogICAgICAgICAgICAgICAgICAgZnJvbSA9ICIyMDIwLTAxLTAxIiwgdG8gPSAiMjAyMS0wMS0wMSIpCgoKbmljb3JldHRlX3N0YXRlcyA8LSBuaWNvcmV0dGUgJT4lCiAgZ2V0X2ludGVyZXN0X3JlZ2lvbigpCgpuaWNvcmV0dGVfc3RhdGVzCmBgYAoKSSBjaG9zZSB0aGUgR29vZ2xlIHNlYXJjaCB0ZXJtIG5pY29yZXR0ZSBiZWNhdXNlIEkgZmVsdCBpdCB3b3VsZCBiZSBjbG9zZWx5IHJlbGF0ZWQgdG8gcG9wdWxhdGlvbnMgb2Ygc21va2VycyBhcyBtb3N0IHdvdWxkIHByb2JhYmx5IGxpa2UgdG8gcXVpdCB0aGUgaGFiaXQgYXQgc29tZSBwb2ludCBvciBhbm90aGVyLiAKCmBgYHtyfQpuaWNvcmV0dGVfY29sb3JzIDwtIGNvbG9yTnVtZXJpYyhwYWxldHRlID0gInZpcmlkaXMiLCBkb21haW4gPSBuaWNvcmV0dGVfc3RhdGVzJGhpdHMpCgpzdGF0ZXNfbGVhZmxldCAlPiUgCiAgcmVuYW1lKGxvY2F0aW9uID0gTkFNRSkgJT4lIAogIGlubmVyX2pvaW4obmljb3JldHRlX3N0YXRlcykgJT4lIAogIGxlYWZsZXQoKSAlPiUgCiAgYWRkVGlsZXMoKSAlPiUKICBhZGRQb2x5Z29ucyh3ZWlnaHQgPSAxLAogICAgICAgICAgICAgIGZpbGxDb2xvciA9IH5uaWNvcmV0dGVfY29sb3JzKGhpdHMpLCAKICAgICAgICAgICAgICBsYWJlbCA9IH5wYXN0ZTAobG9jYXRpb24sICIsIFNlYXJjaCB2b2x1bWUgZm9yIG5pY29yZXR0ZSA9ICIsIGhpdHMpLAogICAgICAgICAgICAgIGhpZ2hsaWdodCA9IGhpZ2hsaWdodE9wdGlvbnMod2VpZ2h0ID0gMikpICU+JSAKICBzZXRWaWV3KC05NSwgNDAsIHpvb20gPSA0KSAlPiUgCiAgYWRkTGVnZW5kKHBhbCA9IG5pY29yZXR0ZV9jb2xvcnMsIHZhbHVlcyA9IH5oaXRzKQpgYGAKCkkgdXNlZCB0aGUgY29kZSBhYm92ZSB0byBjcmVhdGUgYSBjaG9sb3JvcGxldGggbWFwIGZvciBzZWFyY2ggaGl0cyBmb3Igbmljb3JldHRlIGluIHRoZSBVUy4gVmVybW9udCBoYWQgdGhlIGhpZ2hlc3QgcmF0ZSBvZiBoaXRzIGZvbGxvd2VkIGJ5IE5ldyBZb3JrLgoKCgozLiBEbyBhIGxpbmVhciBtb2RlbCByZWxhdGluZyB0aGUgQ0RDIGRhdGEgdG8gdGhlIGdvb2Qgc2VhcmNoIHRlcm0sIGFuZCBjcmVhdGUgYSBwbG90bHkgc2NhdHRlcnBsb3Qgb2YgdGhlIHJlbGF0aW9uc2hpcC4KCmBgYHtyfQpzbW9rZXJzIDwtIHJlYWRfY3N2KCJDaWdfc21va2luZ19wZXJjZW50LmNzdiIpCmBgYAoKYGBge3J9CmdsaW1wc2Uoc21va2VycykKZ2xpbXBzZShuaWNvcmV0dGVfc3RhdGVzKQpgYGAKYGBge3J9Cm5pY29yZXR0ZV9zdGF0ZXMgJT4lCiAgbXV0YXRlKFN0YXRlID0gc3RhdGUyYWJicihsb2NhdGlvbikpICU+JQogIGlubmVyX2pvaW4oc21va2VycykKYGBgCmBgYHtyfQpuaWNvcmV0dGVfZGF0YSA8LSBuaWNvcmV0dGVfc3RhdGVzICU+JSAKICBtdXRhdGUoU3RhdGUgPSBzdGF0ZTJhYmJyKGxvY2F0aW9uKSkgJT4lIAogIGlubmVyX2pvaW4oc21va2VycykKYGBgCgpgYGB7cn0Kbmljb3JldHRlX21vZGVsIDwtIGxtKENpZ19wZXJjZW50IH4gaGl0cywgZGF0YSA9IG5pY29yZXR0ZV9kYXRhKQoKZ2xhbmNlKG5pY29yZXR0ZV9tb2RlbCkKYGBgCgoKYGBge3J9Cm5pY29yZXR0ZV9kYXRhICU+JSAKICBkcm9wX25hKCkgJT4lIAogIHBsb3RfbHkoeCA9IH5oaXRzLCAKICAgICAgICAgIHkgPSB+Q2lnX3BlcmNlbnQsCiAgICAgICAgICBob3ZlcmluZm8gPSAidGV4dCIsIAogICAgICAgICAgdGV4dCA9IH5wYXN0ZSgiU3RhdGU6ICIsIGxvY2F0aW9uLCAiPGJyPiIsICInTmljb3JldHRlJyBzZWFyY2ggcmF0ZTogIiwgaGl0cywgIjxicj4iLCAiQ2lnIHNtb2tpbmcgcGVyY2VudDogIiwgQ2lnX3BlcmNlbnQpKSAlPiUgCiAgYWRkX21hcmtlcnMoc2hvd2xlZ2VuZCA9IEYpICU+JSAKICBhZGRfbGluZXMoeSA9IH5maXR0ZWQobmljb3JldHRlX21vZGVsKSkgJT4lIAogIGxheW91dCh0aXRsZSA9ICJSZWxhdGlvbnNoaXAgYmV0d2VlbiBnb29nbGUgc2VhcmNoZXMgZm9yICduaWNvcmV0dGUnIGFuZCBzbW9raW5nIHBlcmNlbnQgcmF0ZXMsIGJ5IHN0YXRlIiwKICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gIkdvb2dsZSBzZWFyY2ggaGl0cyBmb3IgJ25pY29yZXR0ZSciKSwKICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gIlN0YXRlIHNtb2tpbmcgcmF0ZSIpKQoKYGBgCkFjY29yZGluZyB0byB0aGUgc3RhdGlzdGljYWwgYW5hbHlzaXMgZm9yIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBHb29nbGUgc2VhcmNoIGhpdHMgZm9yIG5pY29yZXR0ZSwgYW5kIHNtb2tpbmcgcGVyY2VudCByYXRlIGRhdGEsIHRoZSByZWxhdGlvbnNoaXAgaXMgbm90IHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgKCpwKiA9IC40MikKCjQuIENob29zZSBhIHNlY29uZCBnb29nbGUgc2VhcmNoIHRlcm0gb3IgcGhyYXNlIHRoYXQgaXMgcmVsZXZhbnQgdG8geW91ciBjaG9zZW4gQ0RDIGRhdGEgYW5kIGNyZWF0ZSBhIGNob3JvcGxldGggbWFwLgoKYGBge3J9CnRvYmFjY28gPC0gdHJlbmR5KCJ0b2JhY2NvIiwgCiAgICAgICAgICAgICAgICAgICBnZW8gPSAiVVMiLCAKICAgICAgICAgICAgICAgICAgIGZyb20gPSAiMjAyMC0wMS0wMSIsIHRvID0gIjIwMjEtMDEtMDEiKQoKCnRvYmFjY29fc3RhdGVzIDwtIHRvYmFjY28gJT4lCiAgZ2V0X2ludGVyZXN0X3JlZ2lvbigpCgp0b2JhY2NvX3N0YXRlcwpgYGAKYGBge3J9CnRvYmFjY29fY29sb3JzIDwtIGNvbG9yTnVtZXJpYyhwYWxldHRlID0gInZpcmlkaXMiLCBkb21haW4gPSB0b2JhY2NvX3N0YXRlcyRoaXRzKQoKc3RhdGVzX2xlYWZsZXQgJT4lIAogIHJlbmFtZShsb2NhdGlvbiA9IE5BTUUpICU+JSAKICBpbm5lcl9qb2luKHRvYmFjY29fc3RhdGVzKSAlPiUgCiAgbGVhZmxldCgpICU+JSAKICBhZGRUaWxlcygpICU+JQogIGFkZFBvbHlnb25zKHdlaWdodCA9IDEsCiAgICAgICAgICAgICAgZmlsbENvbG9yID0gfnRvYmFjY29fY29sb3JzKGhpdHMpLCAKICAgICAgICAgICAgICBsYWJlbCA9IH5wYXN0ZTAobG9jYXRpb24sICIsIFNlYXJjaCB2b2x1bWUgZm9yIHRvYmFjY28gPSAiLCBoaXRzKSwKICAgICAgICAgICAgICBoaWdobGlnaHQgPSBoaWdobGlnaHRPcHRpb25zKHdlaWdodCA9IDIpKSAlPiUgCiAgc2V0VmlldygtOTUsIDQwLCB6b29tID0gNCkgJT4lIAogIGFkZExlZ2VuZChwYWwgPSB0b2JhY2NvX2NvbG9ycywgdmFsdWVzID0gfmhpdHMpCmBgYAoKVGhlIHNlY29uZCB0ZXJtIHJlbGF0ZWQgdG8gY2lnYXJldHRlIHNtb2tlcnMgdGhhdCBJIHNlYXJjaGVkIGZvciB3YXMgJ3RvYmFjY28uJyBJIHVzZWQgdHJlbmR5IGFuZCB0aGUgY29kZSBhYm92ZSB0byBjcmVhdGUgYSBjaGxvcm9wbGV0aCBtYXAgZm9yIHNlYXJjaCBoaXRzIGZvciB0b2JhY2NvLiBUaGUgbGlnaHRlciBzdGF0ZXMgc2hvdyBhIGhpZ2hlciBzZWFyY2ggcmF0ZSwgdGhlIGRhcmtlciBwdXJwbGUgc3RhdGVzIHNob3cgYSBsb3dlciB2b2x1bWUuCgo1LiBEbyB0aGUgbGluZWFyIG1vZGVsIGFuZCBwbG90bHkgZ3JhcGggYmV0d2VlbiB5b3VyIHNlY29uZCB0ZXJtIGFuZCB0aGUgQ0RDIGRhdGEuCgoKYGBge3J9CnNtb2tlcnMgPC0gcmVhZF9jc3YoIkNpZ19zbW9raW5nX3BlcmNlbnQuY3N2IikKYGBgCmBgYHtyfQpnbGltcHNlKHNtb2tlcnMpCmdsaW1wc2UodG9iYWNjb19zdGF0ZXMpCmBgYApgYGB7cn0KdG9iYWNjb19zdGF0ZXMgJT4lCiAgbXV0YXRlKFN0YXRlID0gc3RhdGUyYWJicihsb2NhdGlvbikpICU+JQogIGlubmVyX2pvaW4oc21va2VycykKYGBgCmBgYHtyfQp0b2JhY2NvX2RhdGEgPC0gdG9iYWNjb19zdGF0ZXMgJT4lIAogIG11dGF0ZShTdGF0ZSA9IHN0YXRlMmFiYnIobG9jYXRpb24pKSAlPiUgCiAgaW5uZXJfam9pbihzbW9rZXJzKQpgYGAKCmBgYHtyfQp0b2JhY2NvX21vZGVsIDwtIGxtKENpZ19wZXJjZW50IH4gaGl0cywgZGF0YSA9IHRvYmFjY29fZGF0YSkKCmdsYW5jZSh0b2JhY2NvX21vZGVsKQpgYGAKCmBgYHtyfQp0b2JhY2NvX2RhdGEgJT4lIAogIGRyb3BfbmEoKSAlPiUgCiAgcGxvdF9seSh4ID0gfmhpdHMsIAogICAgICAgICAgeSA9IH5DaWdfcGVyY2VudCwKICAgICAgICAgIGhvdmVyaW5mbyA9ICJ0ZXh0IiwgCiAgICAgICAgICB0ZXh0ID0gfnBhc3RlKCJTdGF0ZTogIiwgbG9jYXRpb24sICI8YnI+IiwgIidUb2JhY2NvJyBzZWFyY2ggcmF0ZTogIiwgaGl0cywgIjxicj4iLCAiQ2lnIHNtb2tpbmcgcGVyY2VudDogIiwgQ2lnX3BlcmNlbnQpKSAlPiUgCiAgYWRkX21hcmtlcnMoc2hvd2xlZ2VuZCA9IEYpICU+JSAKICBhZGRfbGluZXMoeSA9IH5maXR0ZWQodG9iYWNjb19tb2RlbCkpICU+JSAKICBsYXlvdXQodGl0bGUgPSAiUmVsYXRpb25zaGlwIGJldHdlZW4gZ29vZ2xlIHNlYXJjaGVzIGZvciAndG9iYWNjbycgYW5kIHNtb2tpbmcgcGVyY2VudCByYXRlcywgYnkgc3RhdGUiLAogICB4YXhpcyA9IGxpc3QodGl0bGUgPSAiR29vZ2xlIHNlYXJjaCBoaXRzIGZvciAndG9iYWNjbyciKSwKICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gIlN0YXRlIHNtb2tpbmcgcmF0ZSIpKQoKYGBgCgpBY2NvcmRpbmcgdG8gdGhlIHN0YXRpc3RpY2FsIGFuYWx5c2lzIGRvbmUgYWJvdmUsIEdvb2dsZSBzZWFyY2hlcyBmb3IgJ3RvYmFjY28sJyBhbmQgY2lnYXJldHRlIHNtb2tpbmcgcGVyY2VudGFnZSBieSBzdGF0ZSBkbyBoYXZlIGEgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCByZWxhdGlvbnNoaXAgKCpwKj0uMDAwMSkuIFRoZXJlIGlzIGEgcG9zaXRpdmUgbGluZWFyIGNvcnJlbGF0aW9uIGJldHdlZW4gc2VhcmNoZXMgZm9yIHRvYmFjY28gYW5kIHBlcmNlbnRhZ2Ugb2YgY2lnYXJldHRlIHNtb2tlcnMuIFRoZSBtb3JlIHNlYXJjaGVzIGZvciB0b2JhY2NvIG9uIHRoZSB3ZWIsIHRoZSBoaWdoZXIgcGVyY2VudGFnZSBvZiBzbW9rZXJzIGluIHRoYXQgc3RhdGUuICAK