library(tidyverse)
── Attaching packages ─────────────────────────────────────────────────────────────────────────────────────── tidyverse 1.3.0 ──
✓ ggplot2 3.2.1     ✓ purrr   0.3.3
✓ tibble  2.1.3     ✓ dplyr   0.8.4
✓ tidyr   1.0.2     ✓ stringr 1.4.0
✓ readr   1.3.1     ✓ forcats 0.4.0
── Conflicts ────────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
x dplyr::filter()  masks stats::filter()
x purrr::flatten() masks rtweet::flatten()
x dplyr::lag()     masks stats::lag()
library(DT)
library(trendyy)                # Package to access google search data
library(lubridate)               # Handles dates and times

Attaching package: ‘lubridate’

The following object is masked from ‘package:base’:

    date

The theory is that what people search for reveals their interests in a way that might be more honest than a survey.

There is a friendly web interface to google trends here: https://trends.google.com/

To start, let’s see how people search for the word “flu” with trendy(), and then glimpse() it.

flu <- trendy("flu")

flu %>% 
  get_interest() %>% 
  glimpse()
Observations: 260
Variables: 7
$ date     <dttm> 2015-03-01, 2015-03-08, 2015-03-15, 2015-03-22, 2015-03-29, 2015-04-05, 2015-04-12, 2015-04-19, 2015-04-26,…
$ hits     <int> 34, 25, 21, 17, 16, 18, 17, 16, 13, 13, 12, 12, 11, 13, 11, 10, 9, 9, 9, 9, 9, 9, 9, 10, 10, 11, 12, 14, 16,…
$ geo      <chr> "world", "world", "world", "world", "world", "world", "world", "world", "world", "world", "world", "world", …
$ time     <chr> "today+5-y", "today+5-y", "today+5-y", "today+5-y", "today+5-y", "today+5-y", "today+5-y", "today+5-y", "tod…
$ keyword  <chr> "flu", "flu", "flu", "flu", "flu", "flu", "flu", "flu", "flu", "flu", "flu", "flu", "flu", "flu", "flu", "fl…
$ gprop    <chr> "web", "web", "web", "web", "web", "web", "web", "web", "web", "web", "web", "web", "web", "web", "web", "we…
$ category <chr> "All categories", "All categories", "All categories", "All categories", "All categories", "All categories", …
flu %>% 
  get_interest() %>% 
  datatable()

graph it

flu %>%
  get_interest() %>% 
  ggplot(aes(x = date, y = hits)) +
  geom_line() +
  theme_minimal() +
  labs(title = "hits on flue")

To improve the graph, use theme_minimal and include a title:

flu %>%
  get_interest() %>% 
  ggplot(aes(x = date, y = hits)) +
  geom_line() +
  theme_minimal() +
  labs(title = "google search hits on 'flu'")

We might want to look at repeating seasonsal trends, collapsing across different years. Here’s how to do that:

  1. Create a new variable by extracting the month from the date variable with the lubridate package’s month() function.
  2. Use group_by() on the new month variable to collect the months together.
  3. Get the mean number of search hits for each month.

In addition, I used a datatable with a pageLength option set to 12, and formatRound() to round the 2nd column to 2 digits.

flu %>%
  get_interest() %>% 
  mutate(month = month(date)) %>%         # Create a new variable called month
  group_by(month) %>%                     # Combine the months across different weeks and years
  summarize(hits_per_month = mean(hits)) %>%         # Get average number of searches per month
  datatable(options = list(pageLength = 12)) %>% 
  formatRound(2, 1)

NA

Instead of sending that to a table, we can send it to a graph. We use x = month and y = hits_per_month. The last line scale_x_discrete(limits = c(1:12)) isn’t necessary, but it ensures that the number for every month shows on the x-axis.

flu %>%
  get_interest() %>% 
  mutate(month = month(date)) %>%            # Create a new variable called month
  group_by(month) %>%                        # Combine months across weeks and years
  summarize(hits_per_month = mean(hits)) %>%      # Average number of searches for each month
  ggplot(aes(x = month, y = hits_per_month)) +    # graph it
  geom_line() +
  scale_x_discrete(limits = c(1:12))

Locations

Limit to US, and over a specific time period.

flu_US <- trendy("flu", geo = "US", from = "2015-06-01", to = "2019-06-01")

Now we can look at different regions within the US. Regions are states.

flu_US %>%
  get_interest_region() %>% 
  datatable()

NA

DMA stands for Designated Market Area, and roughly corresponds to cities, and represents a single television market. Pipe flu_US into get_interest_dma() and then into datatable() in a chunk below:

flu_US %>%
  get_interest_dma() %>%
  datatable()

Flu season in Australia occurs at a different time from the US, so it might be interesting to compare search rates. In geo, you can put both “US” and “AU” inside the parentheses of c().

flu_countries <- trendy("flu", geo = c("US", "AU"), from = "2015-01-01", to = "2020-01-01")

Create another ggplot line graph, but this time add color = geo, which will show different colored lines for the US and Australia.

Pipe flu_countries to get_interest to a ggplot, with x = date, y = hits, color = geo. Make it a line graph. Do that below:

flu_countries %>%
  get_interest() %>%
  ggplot(aes(x = date, y = hits, color = geo)) +
  geom_line()

NA
NA

To summarize by month like we did before, just add geo to month inside group_by(), and then add color = geo inside ggplot(aes()).

flu_countries %>%
  get_interest() %>% 
  mutate(month = month(date)) %>%          
  group_by(month, geo) %>%                              
  summarize(hits_per_month = mean(hits)) %>%           
  ggplot(aes(x = month, y = hits_per_month, color = geo)) +       
  geom_line() +
  scale_x_discrete(limits = c(1:12)) +
  theme_minimal() +
  labs(title = "Internet searches for 'flu' over time, by country")

Multiple keywords

We can also search for multiple keywords. Since depression may have some seasonality, let’s compare flu and depression.

flu_depression <- trendy(c("flu", "depression"), geo = "US")

Graph it as above with a line graph, but this time use color = keyword to have different colored lines for the two search terms. Pipe flu_depression to get_interest() to ggplot, with x = date, y = hits, color = keyword.

flu_depression %>%
  get_interest() %>% 
  ggplot(aes(x = date, y = hits, color = keyword)) +
  geom_line()

NA
NA

Now graph it by month, as above for AU and US. Start with flu_depression, pipe that to get_interest(), and then use the model for AU vs. US above, but to see the different keyword plots, use group_by(month, keyword), and use color = keyword in the ggplot. Select an appropriate title.

flu_depression %>%
  get_interest() %>% 
  mutate(month = month(date)) %>%          
  group_by(month, keyword) %>%                              
  summarize(hits_per_month = mean(hits)) %>%           
  ggplot(aes(x = month, y = hits_per_month, color = keyword)) +       
  geom_line() +
  scale_x_discrete(limits = c(1:12)) +
  theme_minimal() +
  labs(title = "Internet searches for 'flu' and 'depression")

Searching specific google properties

You can specify a particular google site to look at with gprop =. Valid options are “web” (default), “news”, “images”, “froogle”, and “youtube”.

depression_videos <- trendy("how to treat depression", gprop = "youtube")

Graph searches by month:

depression_videos %>%
  get_interest() %>% 
  mutate(month = month(date)) %>%          
  group_by(month) %>%                              
  summarize(hits_per_month = mean(hits)) %>%           
  ggplot(aes(x = month, y = hits_per_month)) +       
  geom_line() +
  scale_x_discrete(limits = c(1:12)) +
  theme_minimal() +
  labs(title = "Youtube searches for 'how to treat depression' by month")

Assignment: Look up “psychologist” with trendyy.

psy <- trendy("psychologist")

psy %>% 
  get_interest() %>% 
  glimpse()
Observations: 260
Variables: 7
$ date     <dttm> 2015-03-01, 2015-03-08, 2015-03-15, 2015-03-22, 2015-03-29, 2015-04-05, 2015-04-12, 2015-04-19, 2015-04-26,…
$ hits     <int> 68, 67, 66, 67, 61, 63, 66, 66, 65, 66, 66, 65, 61, 62, 62, 60, 61, 58, 58, 61, 63, 61, 61, 64, 66, 73, 74, …
$ geo      <chr> "world", "world", "world", "world", "world", "world", "world", "world", "world", "world", "world", "world", …
$ time     <chr> "today+5-y", "today+5-y", "today+5-y", "today+5-y", "today+5-y", "today+5-y", "today+5-y", "today+5-y", "tod…
$ keyword  <chr> "psychologist", "psychologist", "psychologist", "psychologist", "psychologist", "psychologist", "psychologis…
$ gprop    <chr> "web", "web", "web", "web", "web", "web", "web", "web", "web", "web", "web", "web", "web", "web", "web", "we…
$ category <chr> "All categories", "All categories", "All categories", "All categories", "All categories", "All categories", …
  1. Create a graph of interest in it over time.
psy %>% 
  get_interest() %>% 
  datatable()
  1. Create a graph of monthly interest in it.

psy %>%
  get_interest() %>% 
  mutate(month = month(date)) %>%            # Create a new variable called month
  group_by(month) %>%                        # Combine months across weeks and years
  summarize(hits_per_month = mean(hits)) %>%      # Average number of searches for each month
  ggplot(aes(x = month, y = hits_per_month)) +    # graph it
  geom_line() +
  scale_x_discrete(limits = c(1:12))

psy_US <- trendy("psychologist", geo = "US", from = "2015-06-01", to = "2019-06-01")
psy_US %>%
  get_interest_region() %>% 
  datatable()

NA
  1. Create a datatable of interest by DMA.

  2. Compare US vs. Canadian (CA) interest in psychologist by month, and create a line graph.

psy_countries <- trendy("psychologist", geo = c("US", "AU"), from = "2015-01-01", to = "2020-01-01")
psy_countries %>%
  get_interest() %>% 
  mutate(month = month(date)) %>%          
  group_by(month, geo) %>%                              
  summarize(hits_per_month = mean(hits)) %>%           
  ggplot(aes(x = month, y = hits_per_month, color = geo)) +       
  geom_line() +
  scale_x_discrete(limits = c(1:12)) +
  theme_minimal() +
  labs(title = "Internet searches for 'psychologist' over time, by country")

  1. Compare interest in psychologist to psychiatrist over time, and create a line graph.
psy_psych <- trendy(c("psychologist", "psychiatrist"), geo = "US")
psy_psych %>%
  get_interest() %>% 
  mutate(month = month(date)) %>%          
  group_by(month, keyword) %>%                              
  summarize(hits_per_month = mean(hits)) %>%           
  ggplot(aes(x = month, y = hits_per_month, color = keyword)) +       
  geom_line() +
  scale_x_discrete(limits = c(1:12)) +
  theme_minimal() +
  labs(title = "Internet searches for 'psychologist' and 'Psychiatrist")

  1. Compare interest in psychologist to psychiatrist in google images over time, and create a line graph.

We can also search for multiple keywords. Since depression may have some seasonality, let’s compare flu and depression.

verses <- trendy(c("psychologist", "psychiatrist"), geo = "US")

Graph it as above with a line graph, but this time use color = keyword to have different colored lines for the two search terms. Pipe flu_depression to get_interest() to ggplot, with x = date, y = hits, color = keyword.

verses %>%
  get_interest() %>% 
  ggplot(aes(x = date, y = hits, color = keyword)) +
  geom_line()

NA
NA

``` 7. Annotate the document and publish it to rpubs.com.

LS0tCnRpdGxlOiAiR29vZ2xlIHRyZW5kcyIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQpgYGB7cn0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoRFQpCmxpYnJhcnkodHJlbmR5eSkgICAgICAgICAgICAgICAgIyBQYWNrYWdlIHRvIGFjY2VzcyBnb29nbGUgc2VhcmNoIGRhdGEKbGlicmFyeShsdWJyaWRhdGUpICAgICAgICAgICAgICAgIyBIYW5kbGVzIGRhdGVzIGFuZCB0aW1lcwpgYGAKCgoKVGhlIHRoZW9yeSBpcyB0aGF0IHdoYXQgcGVvcGxlIHNlYXJjaCBmb3IgcmV2ZWFscyB0aGVpciBpbnRlcmVzdHMgaW4gYSB3YXkgdGhhdCBtaWdodCBiZSBtb3JlIGhvbmVzdCB0aGFuIGEgc3VydmV5LiAgCgpUaGVyZSBpcyBhIGZyaWVuZGx5IHdlYiBpbnRlcmZhY2UgdG8gZ29vZ2xlIHRyZW5kcyBoZXJlOiBodHRwczovL3RyZW5kcy5nb29nbGUuY29tLwoKVG8gc3RhcnQsIGxldCdzIHNlZSBob3cgcGVvcGxlIHNlYXJjaCBmb3IgdGhlIHdvcmQgImZsdSIgd2l0aCB0cmVuZHkoKSwgYW5kIHRoZW4gZ2xpbXBzZSgpIGl0LgoKCmBgYHtyfQpmbHUgPC0gdHJlbmR5KCJmbHUiKQoKZmx1ICU+JSAKICBnZXRfaW50ZXJlc3QoKSAlPiUgCiAgZ2xpbXBzZSgpCmBgYAoKCmBgYHtyfQpmbHUgJT4lIAogIGdldF9pbnRlcmVzdCgpICU+JSAKICBkYXRhdGFibGUoKQpgYGAKCgpncmFwaCBpdApgYGB7cn0KZmx1ICU+JQogIGdldF9pbnRlcmVzdCgpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBkYXRlLCB5ID0gaGl0cykpICsKICBnZW9tX2xpbmUoKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKHRpdGxlID0gImdvb2dsZSBzZWFyY2ggaGl0cyBvbiAnZmx1JyIpCmBgYAoKVG8gaW1wcm92ZSB0aGUgZ3JhcGgsIHVzZSB0aGVtZV9taW5pbWFsIGFuZCBpbmNsdWRlIGEgdGl0bGU6CmBgYHtyfQpmbHUgJT4lCiAgZ2V0X2ludGVyZXN0KCkgJT4lIAogIGdncGxvdChhZXMoeCA9IGRhdGUsIHkgPSBoaXRzKSkgKwogIGdlb21fbGluZSgpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnModGl0bGUgPSAiZ29vZ2xlIHNlYXJjaCBoaXRzIG9uICdmbHUnIikKYGBgCgoKCgoKCldlIG1pZ2h0IHdhbnQgdG8gbG9vayBhdCByZXBlYXRpbmcgc2Vhc29uc2FsIHRyZW5kcywgY29sbGFwc2luZyBhY3Jvc3MgZGlmZmVyZW50IHllYXJzLiBIZXJlJ3MgaG93IHRvIGRvIHRoYXQ6IAoKMS4gQ3JlYXRlIGEgbmV3IHZhcmlhYmxlIGJ5IGV4dHJhY3RpbmcgdGhlIG1vbnRoIGZyb20gdGhlIGRhdGUgdmFyaWFibGUgd2l0aCB0aGUgbHVicmlkYXRlIHBhY2thZ2UncyBtb250aCgpIGZ1bmN0aW9uLiAgCjIuIFVzZSBncm91cF9ieSgpIG9uIHRoZSBuZXcgbW9udGggdmFyaWFibGUgdG8gY29sbGVjdCB0aGUgbW9udGhzIHRvZ2V0aGVyLiAgCjMuIEdldCB0aGUgbWVhbiBudW1iZXIgb2Ygc2VhcmNoIGhpdHMgZm9yIGVhY2ggbW9udGguICAKCkluIGFkZGl0aW9uLCBJIHVzZWQgYSBkYXRhdGFibGUgd2l0aCBhIHBhZ2VMZW5ndGggb3B0aW9uIHNldCB0byAxMiwgYW5kIGZvcm1hdFJvdW5kKCkgdG8gcm91bmQgdGhlIDJuZCBjb2x1bW4gdG8gMiBkaWdpdHMuCgpgYGB7cn0KZmx1ICU+JQogIGdldF9pbnRlcmVzdCgpICU+JSAKICBtdXRhdGUobW9udGggPSBtb250aChkYXRlKSkgJT4lICAgICAgICAgIyBDcmVhdGUgYSBuZXcgdmFyaWFibGUgY2FsbGVkIG1vbnRoCiAgZ3JvdXBfYnkobW9udGgpICU+JSAgICAgICAgICAgICAgICAgICAgICMgQ29tYmluZSB0aGUgbW9udGhzIGFjcm9zcyBkaWZmZXJlbnQgd2Vla3MgYW5kIHllYXJzCiAgc3VtbWFyaXplKGhpdHNfcGVyX21vbnRoID0gbWVhbihoaXRzKSkgJT4lICAgICAgICAgIyBHZXQgYXZlcmFnZSBudW1iZXIgb2Ygc2VhcmNoZXMgcGVyIG1vbnRoCiAgZGF0YXRhYmxlKG9wdGlvbnMgPSBsaXN0KHBhZ2VMZW5ndGggPSAxMikpICU+JSAKICBmb3JtYXRSb3VuZCgyLCAxKQoKYGBgCgoKSW5zdGVhZCBvZiBzZW5kaW5nIHRoYXQgdG8gYSB0YWJsZSwgd2UgY2FuIHNlbmQgaXQgdG8gYSBncmFwaC4gV2UgdXNlIHggPSBtb250aCBhbmQgeSA9IGhpdHNfcGVyX21vbnRoLiBUaGUgbGFzdCBsaW5lIHNjYWxlX3hfZGlzY3JldGUobGltaXRzID0gYygxOjEyKSkgaXNuJ3QgbmVjZXNzYXJ5LCBidXQgaXQgZW5zdXJlcyB0aGF0IHRoZSBudW1iZXIgZm9yIGV2ZXJ5IG1vbnRoIHNob3dzIG9uIHRoZSB4LWF4aXMuCgpgYGB7cn0KZmx1ICU+JQogIGdldF9pbnRlcmVzdCgpICU+JSAKICBtdXRhdGUobW9udGggPSBtb250aChkYXRlKSkgJT4lICAgICAgICAgICAgIyBDcmVhdGUgYSBuZXcgdmFyaWFibGUgY2FsbGVkIG1vbnRoCiAgZ3JvdXBfYnkobW9udGgpICU+JSAgICAgICAgICAgICAgICAgICAgICAgICMgQ29tYmluZSBtb250aHMgYWNyb3NzIHdlZWtzIGFuZCB5ZWFycwogIHN1bW1hcml6ZShoaXRzX3Blcl9tb250aCA9IG1lYW4oaGl0cykpICU+JSAgICAgICMgQXZlcmFnZSBudW1iZXIgb2Ygc2VhcmNoZXMgZm9yIGVhY2ggbW9udGgKICBnZ3Bsb3QoYWVzKHggPSBtb250aCwgeSA9IGhpdHNfcGVyX21vbnRoKSkgKyAgICAjIGdyYXBoIGl0CiAgZ2VvbV9saW5lKCkgKwogIHNjYWxlX3hfZGlzY3JldGUobGltaXRzID0gYygxOjEyKSkKCmBgYAoKCgoKCiMjIyBMb2NhdGlvbnMKCkxpbWl0IHRvIFVTLCBhbmQgb3ZlciBhIHNwZWNpZmljIHRpbWUgcGVyaW9kLgoKCmBgYHtyfQpmbHVfVVMgPC0gdHJlbmR5KCJmbHUiLCBnZW8gPSAiVVMiLCBmcm9tID0gIjIwMTUtMDYtMDEiLCB0byA9ICIyMDE5LTA2LTAxIikKYGBgCgoKCgpOb3cgd2UgY2FuIGxvb2sgYXQgZGlmZmVyZW50IHJlZ2lvbnMgd2l0aGluIHRoZSBVUy4gUmVnaW9ucyBhcmUgc3RhdGVzLgoKYGBge3J9CmZsdV9VUyAlPiUKICBnZXRfaW50ZXJlc3RfcmVnaW9uKCkgJT4lIAogIGRhdGF0YWJsZSgpCgpgYGAKCgoKRE1BIHN0YW5kcyBmb3IgRGVzaWduYXRlZCBNYXJrZXQgQXJlYSwgYW5kIHJvdWdobHkgY29ycmVzcG9uZHMgdG8gY2l0aWVzLCBhbmQgcmVwcmVzZW50cyBhIHNpbmdsZSB0ZWxldmlzaW9uIG1hcmtldC4gUGlwZSBmbHVfVVMgaW50byBnZXRfaW50ZXJlc3RfZG1hKCkgYW5kIHRoZW4gaW50byBkYXRhdGFibGUoKSBpbiBhIGNodW5rIGJlbG93OgoKYGBge3J9CmZsdV9VUyAlPiUKICBnZXRfaW50ZXJlc3RfZG1hKCkgJT4lCiAgZGF0YXRhYmxlKCkKYGBgCgoKCgoKCkZsdSBzZWFzb24gaW4gQXVzdHJhbGlhIG9jY3VycyBhdCBhIGRpZmZlcmVudCB0aW1lIGZyb20gdGhlIFVTLCBzbyBpdCBtaWdodCBiZSBpbnRlcmVzdGluZyB0byBjb21wYXJlIHNlYXJjaCByYXRlcy4gSW4gZ2VvLCB5b3UgY2FuIHB1dCBib3RoICJVUyIgYW5kICJBVSIgaW5zaWRlIHRoZSBwYXJlbnRoZXNlcyBvZiBjKCkuCgpgYGB7cn0KZmx1X2NvdW50cmllcyA8LSB0cmVuZHkoImZsdSIsIGdlbyA9IGMoIlVTIiwgIkFVIiksIGZyb20gPSAiMjAxNS0wMS0wMSIsIHRvID0gIjIwMjAtMDEtMDEiKQpgYGAKCgpDcmVhdGUgYW5vdGhlciBnZ3Bsb3QgbGluZSBncmFwaCwgYnV0IHRoaXMgdGltZSBhZGQgY29sb3IgPSBnZW8sIHdoaWNoIHdpbGwgc2hvdyBkaWZmZXJlbnQgY29sb3JlZCBsaW5lcyBmb3IgdGhlIFVTIGFuZCBBdXN0cmFsaWEuCgpQaXBlIGZsdV9jb3VudHJpZXMgdG8gZ2V0X2ludGVyZXN0IHRvIGEgZ2dwbG90LCB3aXRoIHggPSBkYXRlLCB5ID0gaGl0cywgY29sb3IgPSBnZW8uIE1ha2UgaXQgYSBsaW5lIGdyYXBoLiBEbyB0aGF0IGJlbG93OgoKYGBge3J9CmZsdV9jb3VudHJpZXMgJT4lCiAgZ2V0X2ludGVyZXN0KCkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gZGF0ZSwgeSA9IGhpdHMsIGNvbG9yID0gZ2VvKSkgKwogIGdlb21fbGluZSgpCgoKYGBgCgoKCgoKCgpUbyBzdW1tYXJpemUgYnkgbW9udGggbGlrZSB3ZSBkaWQgYmVmb3JlLCBqdXN0IGFkZCBnZW8gdG8gbW9udGggaW5zaWRlIGdyb3VwX2J5KCksIGFuZCB0aGVuIGFkZCBjb2xvciA9IGdlbyBpbnNpZGUgZ2dwbG90KGFlcygpKS4KCmBgYHtyfQpmbHVfY291bnRyaWVzICU+JQogIGdldF9pbnRlcmVzdCgpICU+JSAKICBtdXRhdGUobW9udGggPSBtb250aChkYXRlKSkgJT4lICAgICAgICAgIAogIGdyb3VwX2J5KG1vbnRoLCBnZW8pICU+JSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogIHN1bW1hcml6ZShoaXRzX3Blcl9tb250aCA9IG1lYW4oaGl0cykpICU+JSAgICAgICAgICAgCiAgZ2dwbG90KGFlcyh4ID0gbW9udGgsIHkgPSBoaXRzX3Blcl9tb250aCwgY29sb3IgPSBnZW8pKSArICAgICAgIAogIGdlb21fbGluZSgpICsKICBzY2FsZV94X2Rpc2NyZXRlKGxpbWl0cyA9IGMoMToxMikpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnModGl0bGUgPSAiSW50ZXJuZXQgc2VhcmNoZXMgZm9yICdmbHUnIG92ZXIgdGltZSwgYnkgY291bnRyeSIpCgpgYGAKCgojIyMgTXVsdGlwbGUga2V5d29yZHMKCldlIGNhbiBhbHNvIHNlYXJjaCBmb3IgbXVsdGlwbGUga2V5d29yZHMuIFNpbmNlIGRlcHJlc3Npb24gbWF5IGhhdmUgc29tZSBzZWFzb25hbGl0eSwgbGV0J3MgY29tcGFyZSBmbHUgYW5kIGRlcHJlc3Npb24uCgpgYGB7cn0KZmx1X2RlcHJlc3Npb24gPC0gdHJlbmR5KGMoImZsdSIsICJkZXByZXNzaW9uIiksIGdlbyA9ICJVUyIpCmBgYAoKCkdyYXBoIGl0IGFzIGFib3ZlIHdpdGggYSBsaW5lIGdyYXBoLCBidXQgdGhpcyB0aW1lIHVzZSBjb2xvciA9IGtleXdvcmQgdG8gaGF2ZSBkaWZmZXJlbnQgY29sb3JlZCBsaW5lcyBmb3IgdGhlIHR3byBzZWFyY2ggdGVybXMuIFBpcGUgZmx1X2RlcHJlc3Npb24gdG8gZ2V0X2ludGVyZXN0KCkgdG8gZ2dwbG90LCB3aXRoIHggPSBkYXRlLCB5ID0gaGl0cywgY29sb3IgPSBrZXl3b3JkLgpgYGB7cn0KZmx1X2RlcHJlc3Npb24gJT4lCiAgZ2V0X2ludGVyZXN0KCkgJT4lIAogIGdncGxvdChhZXMoeCA9IGRhdGUsIHkgPSBoaXRzLCBjb2xvciA9IGtleXdvcmQpKSArCiAgZ2VvbV9saW5lKCkKICAKCmBgYAoKCgoKCgoKCk5vdyBncmFwaCBpdCBieSBtb250aCwgYXMgYWJvdmUgZm9yIEFVIGFuZCBVUy4gU3RhcnQgd2l0aCBmbHVfZGVwcmVzc2lvbiwgcGlwZSB0aGF0IHRvIGdldF9pbnRlcmVzdCgpLCBhbmQgdGhlbiB1c2UgdGhlIG1vZGVsIGZvciBBVSB2cy4gVVMgYWJvdmUsIGJ1dCB0byBzZWUgdGhlIGRpZmZlcmVudCBrZXl3b3JkIHBsb3RzLCB1c2UgZ3JvdXBfYnkobW9udGgsIGtleXdvcmQpLCBhbmQgdXNlIGNvbG9yID0ga2V5d29yZCBpbiB0aGUgZ2dwbG90LiBTZWxlY3QgYW4gYXBwcm9wcmlhdGUgdGl0bGUuCgpgYGB7cn0KZmx1X2RlcHJlc3Npb24gJT4lCiAgZ2V0X2ludGVyZXN0KCkgJT4lIAogIG11dGF0ZShtb250aCA9IG1vbnRoKGRhdGUpKSAlPiUgICAgICAgICAgCiAgZ3JvdXBfYnkobW9udGgsIGtleXdvcmQpICU+JSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogIHN1bW1hcml6ZShoaXRzX3Blcl9tb250aCA9IG1lYW4oaGl0cykpICU+JSAgICAgICAgICAgCiAgZ2dwbG90KGFlcyh4ID0gbW9udGgsIHkgPSBoaXRzX3Blcl9tb250aCwgY29sb3IgPSBrZXl3b3JkKSkgKyAgICAgICAKICBnZW9tX2xpbmUoKSArCiAgc2NhbGVfeF9kaXNjcmV0ZShsaW1pdHMgPSBjKDE6MTIpKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKHRpdGxlID0gIkludGVybmV0IHNlYXJjaGVzIGZvciAnZmx1JyBhbmQgJ2RlcHJlc3Npb24iKQoKYGBgCgoKCgoKIyMjIFNlYXJjaGluZyBzcGVjaWZpYyBnb29nbGUgcHJvcGVydGllcwoKWW91IGNhbiBzcGVjaWZ5IGEgcGFydGljdWxhciBnb29nbGUgc2l0ZSB0byBsb29rIGF0IHdpdGggZ3Byb3AgPS4gVmFsaWQgb3B0aW9ucyBhcmUgIndlYiIgKGRlZmF1bHQpLCAibmV3cyIsICJpbWFnZXMiLCAiZnJvb2dsZSIsIGFuZCAieW91dHViZSIuCgpgYGB7cn0KZGVwcmVzc2lvbl92aWRlb3MgPC0gdHJlbmR5KCJob3cgdG8gdHJlYXQgZGVwcmVzc2lvbiIsIGdwcm9wID0gInlvdXR1YmUiKQpgYGAKCgoKR3JhcGggc2VhcmNoZXMgYnkgbW9udGg6CgpgYGB7cn0KZGVwcmVzc2lvbl92aWRlb3MgJT4lCiAgZ2V0X2ludGVyZXN0KCkgJT4lIAogIG11dGF0ZShtb250aCA9IG1vbnRoKGRhdGUpKSAlPiUgICAgICAgICAgCiAgZ3JvdXBfYnkobW9udGgpICU+JSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogIHN1bW1hcml6ZShoaXRzX3Blcl9tb250aCA9IG1lYW4oaGl0cykpICU+JSAgICAgICAgICAgCiAgZ2dwbG90KGFlcyh4ID0gbW9udGgsIHkgPSBoaXRzX3Blcl9tb250aCkpICsgICAgICAgCiAgZ2VvbV9saW5lKCkgKwogIHNjYWxlX3hfZGlzY3JldGUobGltaXRzID0gYygxOjEyKSkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgbGFicyh0aXRsZSA9ICJZb3V0dWJlIHNlYXJjaGVzIGZvciAnaG93IHRvIHRyZWF0IGRlcHJlc3Npb24nIGJ5IG1vbnRoIikKCmBgYAoKCgoKCgoKCkFzc2lnbm1lbnQ6IExvb2sgdXAgInBzeWNob2xvZ2lzdCIgd2l0aCB0cmVuZHl5LgpgYGB7cn0KcHN5IDwtIHRyZW5keSgicHN5Y2hvbG9naXN0IikKCnBzeSAlPiUgCiAgZ2V0X2ludGVyZXN0KCkgJT4lIAogIGdsaW1wc2UoKQpgYGAKMS4gQ3JlYXRlIGEgZ3JhcGggb2YgaW50ZXJlc3QgaW4gaXQgb3ZlciB0aW1lLgpgYGB7cn0KcHN5ICU+JSAKICBnZXRfaW50ZXJlc3QoKSAlPiUgCiAgZGF0YXRhYmxlKCkKYGBgCgoyLiBDcmVhdGUgYSBncmFwaCBvZiBtb250aGx5IGludGVyZXN0IGluIGl0LgpgYGB7cn0KCnBzeSAlPiUKICBnZXRfaW50ZXJlc3QoKSAlPiUgCiAgbXV0YXRlKG1vbnRoID0gbW9udGgoZGF0ZSkpICU+JSAgICAgICAgICAgICMgQ3JlYXRlIGEgbmV3IHZhcmlhYmxlIGNhbGxlZCBtb250aAogIGdyb3VwX2J5KG1vbnRoKSAlPiUgICAgICAgICAgICAgICAgICAgICAgICAjIENvbWJpbmUgbW9udGhzIGFjcm9zcyB3ZWVrcyBhbmQgeWVhcnMKICBzdW1tYXJpemUoaGl0c19wZXJfbW9udGggPSBtZWFuKGhpdHMpKSAlPiUgICAgICAjIEF2ZXJhZ2UgbnVtYmVyIG9mIHNlYXJjaGVzIGZvciBlYWNoIG1vbnRoCiAgZ2dwbG90KGFlcyh4ID0gbW9udGgsIHkgPSBoaXRzX3Blcl9tb250aCkpICsgICAgIyBncmFwaCBpdAogIGdlb21fbGluZSgpICsKICBzY2FsZV94X2Rpc2NyZXRlKGxpbWl0cyA9IGMoMToxMikpCmBgYAoKYGBge3J9CnBzeV9VUyA8LSB0cmVuZHkoInBzeWNob2xvZ2lzdCIsIGdlbyA9ICJVUyIsIGZyb20gPSAiMjAxNS0wNi0wMSIsIHRvID0gIjIwMTktMDYtMDEiKQpwc3lfVVMgJT4lCiAgZ2V0X2ludGVyZXN0X3JlZ2lvbigpICU+JSAKICBkYXRhdGFibGUoKQoKYGBgCgozLiBDcmVhdGUgYSBkYXRhdGFibGUgb2YgaW50ZXJlc3QgYnkgRE1BLgoKCjQuIENvbXBhcmUgVVMgdnMuIENhbmFkaWFuIChDQSkgaW50ZXJlc3QgaW4gcHN5Y2hvbG9naXN0IGJ5IG1vbnRoLCBhbmQgY3JlYXRlIGEgbGluZSBncmFwaC4KYGBge3J9CnBzeV9jb3VudHJpZXMgPC0gdHJlbmR5KCJwc3ljaG9sb2dpc3QiLCBnZW8gPSBjKCJVUyIsICJBVSIpLCBmcm9tID0gIjIwMTUtMDEtMDEiLCB0byA9ICIyMDIwLTAxLTAxIikKYGBgCgpgYGB7cn0KcHN5X2NvdW50cmllcyAlPiUKICBnZXRfaW50ZXJlc3QoKSAlPiUgCiAgbXV0YXRlKG1vbnRoID0gbW9udGgoZGF0ZSkpICU+JSAgICAgICAgICAKICBncm91cF9ieShtb250aCwgZ2VvKSAlPiUgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICBzdW1tYXJpemUoaGl0c19wZXJfbW9udGggPSBtZWFuKGhpdHMpKSAlPiUgICAgICAgICAgIAogIGdncGxvdChhZXMoeCA9IG1vbnRoLCB5ID0gaGl0c19wZXJfbW9udGgsIGNvbG9yID0gZ2VvKSkgKyAgICAgICAKICBnZW9tX2xpbmUoKSArCiAgc2NhbGVfeF9kaXNjcmV0ZShsaW1pdHMgPSBjKDE6MTIpKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKHRpdGxlID0gIkludGVybmV0IHNlYXJjaGVzIGZvciAncHN5Y2hvbG9naXN0JyBvdmVyIHRpbWUsIGJ5IGNvdW50cnkiKQpgYGAKNS4gQ29tcGFyZSBpbnRlcmVzdCBpbiBwc3ljaG9sb2dpc3QgdG8gcHN5Y2hpYXRyaXN0IG92ZXIgdGltZSwgYW5kIGNyZWF0ZSBhIGxpbmUgZ3JhcGguICAKYGBge3J9CnBzeV9wc3ljaCA8LSB0cmVuZHkoYygicHN5Y2hvbG9naXN0IiwgInBzeWNoaWF0cmlzdCIpLCBnZW8gPSAiVVMiKQpgYGAKCmBgYHtyfQpwc3lfcHN5Y2ggJT4lCiAgZ2V0X2ludGVyZXN0KCkgJT4lIAogIG11dGF0ZShtb250aCA9IG1vbnRoKGRhdGUpKSAlPiUgICAgICAgICAgCiAgZ3JvdXBfYnkobW9udGgsIGtleXdvcmQpICU+JSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogIHN1bW1hcml6ZShoaXRzX3Blcl9tb250aCA9IG1lYW4oaGl0cykpICU+JSAgICAgICAgICAgCiAgZ2dwbG90KGFlcyh4ID0gbW9udGgsIHkgPSBoaXRzX3Blcl9tb250aCwgY29sb3IgPSBrZXl3b3JkKSkgKyAgICAgICAKICBnZW9tX2xpbmUoKSArCiAgc2NhbGVfeF9kaXNjcmV0ZShsaW1pdHMgPSBjKDE6MTIpKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKHRpdGxlID0gIkludGVybmV0IHNlYXJjaGVzIGZvciAncHN5Y2hvbG9naXN0JyBhbmQgJ1BzeWNoaWF0cmlzdCIpCgpgYGAKCgoKNi4gQ29tcGFyZSBpbnRlcmVzdCBpbiBwc3ljaG9sb2dpc3QgdG8gcHN5Y2hpYXRyaXN0IGluIGdvb2dsZSBpbWFnZXMgb3ZlciB0aW1lLCBhbmQgY3JlYXRlIGEgbGluZSBncmFwaC4KCldlIGNhbiBhbHNvIHNlYXJjaCBmb3IgbXVsdGlwbGUga2V5d29yZHMuIFNpbmNlIGRlcHJlc3Npb24gbWF5IGhhdmUgc29tZSBzZWFzb25hbGl0eSwgbGV0J3MgY29tcGFyZSBmbHUgYW5kIGRlcHJlc3Npb24uCgpgYGB7cn0KdmVyc2VzIDwtIHRyZW5keShjKCJwc3ljaG9sb2dpc3QiLCAicHN5Y2hpYXRyaXN0IiksIGdlbyA9ICJVUyIpCmBgYAoKCkdyYXBoIGl0IGFzIGFib3ZlIHdpdGggYSBsaW5lIGdyYXBoLCBidXQgdGhpcyB0aW1lIHVzZSBjb2xvciA9IGtleXdvcmQgdG8gaGF2ZSBkaWZmZXJlbnQgY29sb3JlZCBsaW5lcyBmb3IgdGhlIHR3byBzZWFyY2ggdGVybXMuIFBpcGUgZmx1X2RlcHJlc3Npb24gdG8gZ2V0X2ludGVyZXN0KCkgdG8gZ2dwbG90LCB3aXRoIHggPSBkYXRlLCB5ID0gaGl0cywgY29sb3IgPSBrZXl3b3JkLgpgYGB7cn0KdmVyc2VzICU+JQogIGdldF9pbnRlcmVzdCgpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBkYXRlLCB5ID0gaGl0cywgY29sb3IgPSBrZXl3b3JkKSkgKwogIGdlb21fbGluZSgpCiAgCgpgYGAKYGBgCjcuIEFubm90YXRlIHRoZSBkb2N1bWVudCBhbmQgcHVibGlzaCBpdCB0byBycHVicy5jb20uCgo=