Setup

# loading libraries --
library(tidyverse)
library(rvest)
library(robotstxt)
library(calendar)
library(lubridate)
library(here)

Checking if we can scrape the page

Check the page’s terms of service first, and then verify with {robotstxt}

get_robotstxt("https://global.rstudio.com/student/all_events")
Event: on_not_foundEvent: on_file_type_mismatchEvent: on_suspect_content
[robots.txt]
--------------------------------------

# robots.txt overwrite by: on_suspect_content

User-agent: *
Allow: /



[events]
--------------------------------------

requested:   https://global.rstudio.com/student/all_events/robots.txt 
downloaded:  https://global.rstudio.com/student/all_events/robots.txt 

$on_not_found
$on_not_found$status_code
[1] 404


$on_file_type_mismatch
$on_file_type_mismatch$content_type
[1] "text/html; charset=utf-8"


$on_suspect_content
$on_suspect_content$parsable
[1] FALSE

$on_suspect_content$content_suspect
[1] TRUE


[attributes]
--------------------------------------

problems, cached, request, class

Getting the html

Good to check if you can do it in one page, and then if it works, scale.

html_1 <- read_html("https://global.rstudio.com/student/all_events?page=1")

Extracting information from tags

# event title --
title_1 <- html_1 %>%
  html_nodes(".session__name") %>%
  html_text() # specifies what format we want

# double check if the information you want was saved --
title_1
 [1] "Maintaining the house the tidyverse built - Session 1"                                                        
 [2] "Q&A: Hadley Wickham - Session 1"                                                                              
 [3] "Accessible Data Science Beyond Visual Models: Non-Visual Interactions with R and RStudio Packages - Session 1"
 [4] "Always look on the bright side of plots - Session 1"                                                          
 [5] "Bringing the Tidyverse to Python with Siuba - Session 1"                                                      
 [6] "A New Paradigm for Multifigure, Coordinate-Based Plotting in R - Session 1"                                   
 [7] "R & Python: Going Steady - Session 1"                                                                         
 [8] "Starting an R Book Club: Cooking Up Friendships in Isolation - Session 1"                                     
 [9] "Discussion: Learning 1 - Session 1"                                                                           
[10] "Discussion: Visualisation 1 - Session 1"                                                                      
[11] "Discussion: Language interop 1 - Session 1"                                                                   
[12] "Art Lessons: One Year as RStudio’s Artist-in-Residence - Session 1"                                           
[13] "Using pins with Python and JavaScript - Session 1"                                                            
[14] "Trial and Error in Data Viz at the ACLU - Session 1"                                                          
[15] "Racial Equity Dashboard: Unpacking Systemic Inequity - Session 1"                                             
[16] "The dynamic duo: SQL & R - Session 1"                                                                         
[17] "Aesthetically automated figure production - Session 1"                                                        
[18] "Your R is My R too:  Reflections on creating the Mi-R community - Session 1"                                  
[19] "An easy and friendly way to build your multilingual website - Session 1"                                      
[20] "Making .pot-ery with R: Translations in R Packages - Session 1"                                               
[21] "Discussion: Visualisation 2 - Session 1"                                                                      
[22] "Discussion: Language interop 2 - Session 1"                                                                   
[23] "Discussion: Learning 2 - Session 1"                                                                           
[24] "Reporting on and visualising the pandemic - Session 1"                                                        
# dates --
datetime_1 <- html_1 %>%
  html_nodes(".session__dates.session__dates--index") %>%
  html_text()

datetime_1
 [1] "Thursday, Jan 21, 2021 at 11:00 AM to 11:33 AM EST"
 [2] "Thursday, Jan 21, 2021 at 11:33 AM to 12:18 PM EST"
 [3] "Thursday, Jan 21, 2021 at  1:00 PM to 1:19 PM EST" 
 [4] "Thursday, Jan 21, 2021 at  1:00 PM to 1:21 PM EST" 
 [5] "Thursday, Jan 21, 2021 at  1:00 PM to 1:20 PM EST" 
 [6] "Thursday, Jan 21, 2021 at  1:19 PM to 1:33 PM EST" 
 [7] "Thursday, Jan 21, 2021 at  1:19 PM to 1:34 PM EST" 
 [8] "Thursday, Jan 21, 2021 at  1:21 PM to 1:28 PM EST" 
 [9] "Thursday, Jan 21, 2021 at  1:29 PM to 1:59 PM EST" 
[10] "Thursday, Jan 21, 2021 at  1:33 PM to 1:59 PM EST" 
[11] "Thursday, Jan 21, 2021 at  1:34 PM to 1:59 PM EST" 
[12] "Thursday, Jan 21, 2021 at  2:00 PM to 2:19 PM EST" 
[13] "Thursday, Jan 21, 2021 at  2:00 PM to 2:19 PM EST" 
[14] "Thursday, Jan 21, 2021 at  2:00 PM to 2:16 PM EST" 
[15] "Thursday, Jan 21, 2021 at  2:16 PM to 2:20 PM EST" 
[16] "Thursday, Jan 21, 2021 at  2:19 PM to 2:36 PM EST" 
[17] "Thursday, Jan 21, 2021 at  2:19 PM to 2:39 PM EST" 
[18] "Thursday, Jan 21, 2021 at  2:20 PM to 2:24 PM EST" 
[19] "Thursday, Jan 21, 2021 at  2:25 PM to 2:30 PM EST" 
[20] "Thursday, Jan 21, 2021 at  2:30 PM to 2:34 PM EST" 
[21] "Thursday, Jan 21, 2021 at  2:35 PM to 2:59 PM EST" 
[22] "Thursday, Jan 21, 2021 at  2:37 PM to 2:59 PM EST" 
[23] "Thursday, Jan 21, 2021 at  2:38 PM to 2:58 PM EST" 
[24] "Thursday, Jan 21, 2021 at  3:00 PM to 3:50 PM EST" 

Creating scraping functions

# scraping event titles --
get_titles <- name <- function(page_number) {
  Sys.sleep(2)
  
  link <- paste0("https://global.rstudio.com/student/all_events?page=", page_number)
  
  read_html(link) %>%
  html_nodes(".session__name") %>%
  html_text()  
}

# scraping event dates and times --
get_dates <- name <- function(page_number) {
  Sys.sleep(2)
  
  link <- paste0("https://global.rstudio.com/student/all_events?page=", page_number)
  
  read_html(link) %>%
  html_nodes(".session__dates.session__dates--index") %>%
  html_text()  
}

Testing the function

get_titles(3)
 [1] "Discussion: Modelling 2 - Session 1"                                                                    
 [2] "Your Public Garden - Session 1"                                                                         
 [3] "Q&A: Vicki Boykis - Session 1"                                                                          
 [4] "Introducing xrprof: A New Way to Profile R - Session 1"                                                 
 [5] "The Opioid Files: Turning big pharmacy data over to the public - Session 1"                             
 [6] "Not The App We Deserve. The App We Need: Putting a GMP Shiny App into Production - Session 1"           
 [7] "plumber + future: Async Web APIs - Session 1"                                                           
 [8] "rKenyaCensus Package - Session 1"                                                                       
 [9] "How we made the switch: a case study on automating a complex report. - Session 1"                       
[10] "Making Shiny apps faster with caching - Session 1"                                                      
[11] "Discussion: Data for good 1 - Session 1"                                                                
[12] "Discussion: Programming 1 - Session 1"                                                                  
[13] "Discussion: Organisational tooling 1 - Session 1"                                                       
[14] "Humanitarian Data Science with R - Session 1"                                                           
[15] "Bigger Data With Ease Using Apache Arrow - Session 1"                                                   
[16] "From Zero to Hero: Best practices for setting up Rstudio Team in the Cloud - Session 1"                 
[17] "How reproducible am I? A retrospective on a year of commercial data science projects in R - Session 1"  
[18] "Cognitive speed: How the Tidyverse helped the British Red Cross respond quickly to COVID-19 - Session 1"
[19] "Easy larger-than-RAM data manipulation with {disk.frame} - Session 1"                                   
[20] "Lifelong Learning with R Weekly - Session 1"                                                            
[21] "xaringan Playground: Using xaringan to learn web development - Session 1"                               
[22] "Custom theming in Shiny & R Markdown with bslib & thematic - Session 1"                                 
[23] "parsermd - parsing R Markdown for fun and profit - Session 1"                                           
[24] "How Content Makes the Data Go 'Round - Session 1"                                                       

Iterating with the function

This step will try out the get_titles() function on pages 2, 3, 4

map(2:4, get_titles)
[[1]]
 [1] "Q&A: John Burn-Murdoch - Session 1"                                                                                   
 [2] "oRganization: How to make internal R packages part of your team - Session 1"                                          
 [3] "Making the jump from learning to applying: R training and documentation for different levels of expertise - Session 1"
 [4] "What's new in tidymodels? - Session 1"                                                                                
 [5] "Using R to Up Your Experimentation Game - Session 1"                                                                  
 [6] "You're Already Ready: Zen and the Art of R Package Development - Session 1"                                           
 [7] "On programming, teaching, and building interactive tutorials with learnr:: - Session 1"                               
 [8] "Discussion: Modelling 1 - Session 1"                                                                                  
 [9] "Discussion: Package dev 1 - Session 1"                                                                                
[10] "Discussion: Teaching 1 - Session 1"                                                                                   
[11] "Fairness and Data Science: Failures, Factors, and Futures - Session 1"                                                
[12] "Monitoring health and impact of open-source projects - Session 1"                                                     
[13] "Feedback at scale - Session 1"                                                                                        
[14] "Make a package - Make some friends - Session 1"                                                                       
[15] "How to do things with words: learning to program in R with a \"communicative approach\" - Session 1"                  
[16] "tidymodels/stacks, Or, In Preparation for Pesto: A Grammar for Stacked Ensemble Modeling - Session 1"                 
[17] "Using formr to create R-powered surveys with individualized feedback - Session 1"                                     
[18] "Using Guided Simulation Exercises to Teach Data Science with R - Session 1"                                           
[19] "Towards an integrated {verse}: lessons learned developing a library of validated packages - Session 1"                
[20] "How I became a Data Composer – examples of simulated datasets that bring value to a data-driven company - Session 1"  
[21] "The Power of Great Datasets - Session 1"                                                                              
[22] "Discussion: Teaching 2 - Session 1"                                                                                   
[23] "Categorical Embeddings: New Ways to Simplify Complex Data - Session 1"                                                
[24] "Discussion: Package dev 2 - Session 1"                                                                                

[[2]]
 [1] "Discussion: Modelling 2 - Session 1"                                                                    
 [2] "Your Public Garden - Session 1"                                                                         
 [3] "Q&A: Vicki Boykis - Session 1"                                                                          
 [4] "Introducing xrprof: A New Way to Profile R - Session 1"                                                 
 [5] "The Opioid Files: Turning big pharmacy data over to the public - Session 1"                             
 [6] "Not The App We Deserve. The App We Need: Putting a GMP Shiny App into Production - Session 1"           
 [7] "plumber + future: Async Web APIs - Session 1"                                                           
 [8] "rKenyaCensus Package - Session 1"                                                                       
 [9] "How we made the switch: a case study on automating a complex report. - Session 1"                       
[10] "Making Shiny apps faster with caching - Session 1"                                                      
[11] "Discussion: Data for good 1 - Session 1"                                                                
[12] "Discussion: Programming 1 - Session 1"                                                                  
[13] "Discussion: Organisational tooling 1 - Session 1"                                                       
[14] "Humanitarian Data Science with R - Session 1"                                                           
[15] "Bigger Data With Ease Using Apache Arrow - Session 1"                                                   
[16] "From Zero to Hero: Best practices for setting up Rstudio Team in the Cloud - Session 1"                 
[17] "How reproducible am I? A retrospective on a year of commercial data science projects in R - Session 1"  
[18] "Cognitive speed: How the Tidyverse helped the British Red Cross respond quickly to COVID-19 - Session 1"
[19] "Easy larger-than-RAM data manipulation with {disk.frame} - Session 1"                                   
[20] "Lifelong Learning with R Weekly - Session 1"                                                            
[21] "xaringan Playground: Using xaringan to learn web development - Session 1"                               
[22] "Custom theming in Shiny & R Markdown with bslib & thematic - Session 1"                                 
[23] "parsermd - parsing R Markdown for fun and profit - Session 1"                                           
[24] "How Content Makes the Data Go 'Round - Session 1"                                                       

[[3]]
 [1] "Discussion: Data for good 2 - Session 1"                                                                      
 [2] "Designing Randomized Studies using Shiny - Session 1"                                                         
 [3] "Discussion: Organisational tooling 2 - Session 1"                                                             
 [4] "Discussion: Programming 2 - Session 1"                                                                        
 [5] "Maintaining the house the tidyverse built - Session 2"                                                        
 [6] "Q&A: Hadley Wickham - Session 2"                                                                              
 [7] "Accessible Data Science Beyond Visual Models: Non-Visual Interactions with R and RStudio Packages - Session 2"
 [8] "Always look on the bright side of plots - Session 2"                                                          
 [9] "Bringing the Tidyverse to Python with Siuba - Session 2"                                                      
[10] "A New Paradigm for Multifigure, Coordinate-Based Plotting in R - Session 2"                                   
[11] "R & Python: Going Steady - Session 2"                                                                         
[12] "Starting an R Book Club: Cooking Up Friendships in Isolation - Session 2"                                     
[13] "Discussion: Learning 1 - Session 2"                                                                           
[14] "Discussion: Visualisation 1 - Session 2"                                                                      
[15] "Discussion: Language interop 1 - Session 2"                                                                   
[16] "Art Lessons: One Year as RStudio’s Artist-in-Residence - Session 2"                                           
[17] "Using pins with Python and JavaScript - Session 2"                                                            
[18] "Trial and Error in Data Viz at the ACLU - Session 2"                                                          
[19] "Racial Equity Dashboard: Unpacking Systemic Inequity - Session 2"                                             
[20] "The dynamic duo: SQL & R - Session 2"                                                                         
[21] "Aesthetically automated figure production - Session 2"                                                        
[22] "Your R is My R too:  Reflections on creating the Mi-R community - Session 2"                                  
[23] "An easy and friendly way to build your multilingual website - Session 2"                                      
[24] "Making .pot-ery with R: Translations in R Packages - Session 2"                                               
# then check with the website to see if it matches

Scraping all the pages

# titles --
titles_all <- map(1:7, get_titles) %>%
  unlist()

# dates --
dates_all <- map(1:7, get_dates) %>%
  unlist()
# creating tibble from scrapes --
schedule <- 
  tibble(event_name = titles_all,
         date_time = dates_all)

schedule

Cleaning the date-time column

# defining string patterns --
str_at <- "\\s+at\\s+"
str_to <- "\\s+to\\s+"
str_EST <- " EST"
str_day <- "\\w+\\,\\s+"

# wrangling the date-time strings --
schedule_new_times <-
schedule %>%
  mutate(date = str_replace_all(date_time, pattern = str_to, "-"),
         date = str_replace_all(date, str_EST, "")) %>%
  tidyr::separate(date, sep = str_at, c("day_date", "time")) %>%
  mutate(date = str_replace(day_date, pattern = str_day, ""),
         date = lubridate::mdy(date, tz = "US/Eastern")) %>%
  mutate(date_time_new = str_c(date, time, sep = " ")) %>%
  tidyr::separate(time, sep = "-", c("start_time", "end_time"))

Parsing the date-time

# wrangling the dates and times --
schedule_new <-
schedule_new_times %>%
  mutate(start_datetime = str_c(date, start_time, sep = " "),
         end_datetime = str_c(date, end_time, sep = " ")) %>%
  mutate(across(c(start_datetime, end_datetime), 
                ~lubridate::ymd_hm(.x, tz = "US/Eastern"))) %>%
  select(-c(date_time, day_date, date_time_new))

# writing to CSV and RDS files --
write_csv(schedule_new, 
          here("schedule-files", "schedule_new_EST.csv"))
saveRDS(schedule_new, 
        here("schedule-files", "schedule_new_EST.Rds"))

Select your timezone and convert to local time

timezone <- Sys.timezone()

schedule_new_timezone <- schedule_new %>%
  mutate(start_datetime = lubridate::with_tz(start_datetime, tzone = timezone),
         end_datetime = lubridate::with_tz(end_datetime, tzone = timezone))

# writing to CSV and RDS files --
write_csv(schedule_new_timezone, 
          here("schedule-files", "schedule_new_localtz.csv"))
saveRDS(schedule_new_timezone, 
        here("schedule-files", "schedule_new_localtz.Rds"))
  

Creating an .ics object

# creating a function --
make_calendar <- function(event) {
  event_subset <- schedule_new_timezone[event, ]
  
  calendar_event <-
  calendar::ic_event(start_time = event_subset$start_datetime,
                     end_time = event_subset$end_datetime,
                     summary = event_subset$event_name)
  
  return(calendar_event)
}

number_events <- length(schedule_new_timezone$event_name)

# creating ics objects for all events --
events_all <- map(1:number_events, make_calendar) %>% 
  bind_rows()

# writing to .ics file --
calendar::ic_write(events_all,
                   here("calendar-files-ics", "all_events_localtime.ics"))

Saving as an R script

knitr::purl("rstudio-global-2021-calendar.Rmd")


processing file: rstudio-global-2021-calendar.Rmd

  |                                                                        
  |                                                                  |   0%
  |                                                                        
  |..                                                                |   3%
  |                                                                        
  |.....                                                             |   7%
  |                                                                        
  |.......                                                           |  10%
  |                                                                        
  |.........                                                         |  14%
  |                                                                        
  |...........                                                       |  17%
  |                                                                        
  |..............                                                    |  21%
  |                                                                        
  |................                                                  |  24%
  |                                                                        
  |..................                                                |  28%
  |                                                                        
  |....................                                              |  31%
  |                                                                        
  |.......................                                           |  34%
  |                                                                        
  |.........................                                         |  38%
  |                                                                        
  |...........................                                       |  41%
  |                                                                        
  |..............................                                    |  45%
  |                                                                        
  |................................                                  |  48%
  |                                                                        
  |..................................                                |  52%
  |                                                                        
  |....................................                              |  55%
  |                                                                        
  |.......................................                           |  59%
  |                                                                        
  |.........................................                         |  62%
  |                                                                        
  |...........................................                       |  66%
  |                                                                        
  |..............................................                    |  69%
  |                                                                        
  |................................................                  |  72%
  |                                                                        
  |..................................................                |  76%
  |                                                                        
  |....................................................              |  79%
  |                                                                        
  |.......................................................           |  83%
  |                                                                        
  |.........................................................         |  86%
  |                                                                        
  |...........................................................       |  90%
  |                                                                        
  |.............................................................     |  93%
  |                                                                        
  |................................................................  |  97%
  |                                                                        
  |..................................................................| 100%
output file: rstudio-global-2021-calendar.R
[1] "rstudio-global-2021-calendar.R"
LS0tCnRpdGxlOiAiU2NyYXBlLVlvdXItT3duIENhbGVuZGFyIgpzdWJ0aXRsZTogIltyc3R1ZGlvOjpnbG9iYWwoMjAyMSkgb25saW5lIHNjaGVkdWxlXShodHRwczovL2dsb2JhbC5yc3R1ZGlvLmNvbS9zdHVkZW50L2FsbF9ldmVudHMpIgphdXRob3I6IFNpbHZpYSBDYW5lbMOzbiwgTmF0YWxpYSBNb3JhbmRlaXJhICYgUGFvIENvcnJhbGVzCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazoKICAgIHRoZW1lOiBmbGF0bHkKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBoaWdobGlnaHQ6IHB5Z21lbnRzCiAgY29kZV9kb3dubG9hZDogdHJ1ZQotLS0KCiMgU2V0dXAKCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQojIGxvYWRpbmcgbGlicmFyaWVzIC0tCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHJ2ZXN0KQpsaWJyYXJ5KHJvYm90c3R4dCkKbGlicmFyeShjYWxlbmRhcikKbGlicmFyeShsdWJyaWRhdGUpCmxpYnJhcnkoaGVyZSkKYGBgCgojIENoZWNraW5nIGlmIHdlIGNhbiBzY3JhcGUgdGhlIHBhZ2UKCkNoZWNrIHRoZSBwYWdlJ3MgdGVybXMgb2Ygc2VydmljZSBmaXJzdCwgYW5kIHRoZW4gdmVyaWZ5IHdpdGggYHtyb2JvdHN0eHR9YAoKYGBge3J9CmdldF9yb2JvdHN0eHQoImh0dHBzOi8vZ2xvYmFsLnJzdHVkaW8uY29tL3N0dWRlbnQvYWxsX2V2ZW50cyIpCmBgYAoKIyBHZXR0aW5nIHRoZSBodG1sCgpHb29kIHRvIGNoZWNrIGlmIHlvdSBjYW4gZG8gaXQgaW4gb25lIHBhZ2UsIGFuZCBfdGhlbl8gaWYgaXQgd29ya3MsIHNjYWxlLgoKYGBge3J9Cmh0bWxfMSA8LSByZWFkX2h0bWwoImh0dHBzOi8vZ2xvYmFsLnJzdHVkaW8uY29tL3N0dWRlbnQvYWxsX2V2ZW50cz9wYWdlPTEiKQpgYGAKCiMgRXh0cmFjdGluZyBpbmZvcm1hdGlvbiBmcm9tIHRhZ3MKCmBgYHtyfQojIGV2ZW50IHRpdGxlIC0tCnRpdGxlXzEgPC0gaHRtbF8xICU+JQogIGh0bWxfbm9kZXMoIi5zZXNzaW9uX19uYW1lIikgJT4lCiAgaHRtbF90ZXh0KCkgIyBzcGVjaWZpZXMgd2hhdCBmb3JtYXQgd2Ugd2FudAoKIyBkb3VibGUgY2hlY2sgaWYgdGhlIGluZm9ybWF0aW9uIHlvdSB3YW50IHdhcyBzYXZlZCAtLQp0aXRsZV8xCgojIGRhdGVzIC0tCmRhdGV0aW1lXzEgPC0gaHRtbF8xICU+JQogIGh0bWxfbm9kZXMoIi5zZXNzaW9uX19kYXRlcy5zZXNzaW9uX19kYXRlcy0taW5kZXgiKSAlPiUKICBodG1sX3RleHQoKQoKZGF0ZXRpbWVfMQpgYGAKCiMgQ3JlYXRpbmcgc2NyYXBpbmcgZnVuY3Rpb25zCgpgYGB7cn0KIyBzY3JhcGluZyBldmVudCB0aXRsZXMgLS0KZ2V0X3RpdGxlcyA8LSBuYW1lIDwtIGZ1bmN0aW9uKHBhZ2VfbnVtYmVyKSB7CiAgU3lzLnNsZWVwKDIpCiAgCiAgbGluayA8LSBwYXN0ZTAoImh0dHBzOi8vZ2xvYmFsLnJzdHVkaW8uY29tL3N0dWRlbnQvYWxsX2V2ZW50cz9wYWdlPSIsIHBhZ2VfbnVtYmVyKQogIAogIHJlYWRfaHRtbChsaW5rKSAlPiUKICBodG1sX25vZGVzKCIuc2Vzc2lvbl9fbmFtZSIpICU+JQogIGh0bWxfdGV4dCgpICAKfQoKIyBzY3JhcGluZyBldmVudCBkYXRlcyBhbmQgdGltZXMgLS0KZ2V0X2RhdGVzIDwtIG5hbWUgPC0gZnVuY3Rpb24ocGFnZV9udW1iZXIpIHsKICBTeXMuc2xlZXAoMikKICAKICBsaW5rIDwtIHBhc3RlMCgiaHR0cHM6Ly9nbG9iYWwucnN0dWRpby5jb20vc3R1ZGVudC9hbGxfZXZlbnRzP3BhZ2U9IiwgcGFnZV9udW1iZXIpCiAgCiAgcmVhZF9odG1sKGxpbmspICU+JQogIGh0bWxfbm9kZXMoIi5zZXNzaW9uX19kYXRlcy5zZXNzaW9uX19kYXRlcy0taW5kZXgiKSAlPiUKICBodG1sX3RleHQoKSAgCn0KYGBgCgojIFRlc3RpbmcgdGhlIGZ1bmN0aW9uCgpgYGB7cn0KZ2V0X3RpdGxlcygzKQpgYGAKCiMgSXRlcmF0aW5nIHdpdGggdGhlIGZ1bmN0aW9uCgpUaGlzIHN0ZXAgd2lsbCB0cnkgb3V0IHRoZSBgZ2V0X3RpdGxlcygpYCBmdW5jdGlvbiBvbiBwYWdlcyAyLCAzLCA0CgpgYGB7cn0KbWFwKDI6NCwgZ2V0X3RpdGxlcykKCiMgdGhlbiBjaGVjayB3aXRoIHRoZSB3ZWJzaXRlIHRvIHNlZSBpZiBpdCBtYXRjaGVzCmBgYAoKIyBTY3JhcGluZyBhbGwgdGhlIHBhZ2VzCgpgYGB7cn0KIyB0aXRsZXMgLS0KdGl0bGVzX2FsbCA8LSBtYXAoMTo3LCBnZXRfdGl0bGVzKSAlPiUKICB1bmxpc3QoKQoKIyBkYXRlcyAtLQpkYXRlc19hbGwgPC0gbWFwKDE6NywgZ2V0X2RhdGVzKSAlPiUKICB1bmxpc3QoKQpgYGAKCgpgYGB7cn0KIyBjcmVhdGluZyB0aWJibGUgZnJvbSBzY3JhcGVzIC0tCnNjaGVkdWxlIDwtIAogIHRpYmJsZShldmVudF9uYW1lID0gdGl0bGVzX2FsbCwKICAgICAgICAgZGF0ZV90aW1lID0gZGF0ZXNfYWxsKQoKc2NoZWR1bGUKYGBgCgojIENsZWFuaW5nIHRoZSBkYXRlLXRpbWUgY29sdW1uCgpgYGB7cn0KIyBkZWZpbmluZyBzdHJpbmcgcGF0dGVybnMgLS0Kc3RyX2F0IDwtICJcXHMrYXRcXHMrIgpzdHJfdG8gPC0gIlxccyt0b1xccysiCnN0cl9FU1QgPC0gIiBFU1QiCnN0cl9kYXkgPC0gIlxcdytcXCxcXHMrIgoKIyB3cmFuZ2xpbmcgdGhlIGRhdGUtdGltZSBzdHJpbmdzIC0tCnNjaGVkdWxlX25ld190aW1lcyA8LQpzY2hlZHVsZSAlPiUKICBtdXRhdGUoZGF0ZSA9IHN0cl9yZXBsYWNlX2FsbChkYXRlX3RpbWUsIHBhdHRlcm4gPSBzdHJfdG8sICItIiksCiAgICAgICAgIGRhdGUgPSBzdHJfcmVwbGFjZV9hbGwoZGF0ZSwgc3RyX0VTVCwgIiIpKSAlPiUKICB0aWR5cjo6c2VwYXJhdGUoZGF0ZSwgc2VwID0gc3RyX2F0LCBjKCJkYXlfZGF0ZSIsICJ0aW1lIikpICU+JQogIG11dGF0ZShkYXRlID0gc3RyX3JlcGxhY2UoZGF5X2RhdGUsIHBhdHRlcm4gPSBzdHJfZGF5LCAiIiksCiAgICAgICAgIGRhdGUgPSBsdWJyaWRhdGU6Om1keShkYXRlLCB0eiA9ICJVUy9FYXN0ZXJuIikpICU+JQogIG11dGF0ZShkYXRlX3RpbWVfbmV3ID0gc3RyX2MoZGF0ZSwgdGltZSwgc2VwID0gIiAiKSkgJT4lCiAgdGlkeXI6OnNlcGFyYXRlKHRpbWUsIHNlcCA9ICItIiwgYygic3RhcnRfdGltZSIsICJlbmRfdGltZSIpKQpgYGAKCgojIFBhcnNpbmcgdGhlIGRhdGUtdGltZQoKYGBge3J9CiMgd3JhbmdsaW5nIHRoZSBkYXRlcyBhbmQgdGltZXMgLS0Kc2NoZWR1bGVfbmV3IDwtCnNjaGVkdWxlX25ld190aW1lcyAlPiUKICBtdXRhdGUoc3RhcnRfZGF0ZXRpbWUgPSBzdHJfYyhkYXRlLCBzdGFydF90aW1lLCBzZXAgPSAiICIpLAogICAgICAgICBlbmRfZGF0ZXRpbWUgPSBzdHJfYyhkYXRlLCBlbmRfdGltZSwgc2VwID0gIiAiKSkgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKHN0YXJ0X2RhdGV0aW1lLCBlbmRfZGF0ZXRpbWUpLCAKICAgICAgICAgICAgICAgIH5sdWJyaWRhdGU6OnltZF9obSgueCwgdHogPSAiVVMvRWFzdGVybiIpKSkgJT4lCiAgc2VsZWN0KC1jKGRhdGVfdGltZSwgZGF5X2RhdGUsIGRhdGVfdGltZV9uZXcpKQoKIyB3cml0aW5nIHRvIENTViBhbmQgUkRTIGZpbGVzIC0tCndyaXRlX2NzdihzY2hlZHVsZV9uZXcsIAogICAgICAgICAgaGVyZSgic2NoZWR1bGUtZmlsZXMiLCAic2NoZWR1bGVfbmV3X0VTVC5jc3YiKSkKc2F2ZVJEUyhzY2hlZHVsZV9uZXcsIAogICAgICAgIGhlcmUoInNjaGVkdWxlLWZpbGVzIiwgInNjaGVkdWxlX25ld19FU1QuUmRzIikpCmBgYAoKIyBTZWxlY3QgeW91ciB0aW1lem9uZSBhbmQgY29udmVydCB0byBsb2NhbCB0aW1lCmBgYHtyfQp0aW1lem9uZSA8LSBTeXMudGltZXpvbmUoKQoKc2NoZWR1bGVfbmV3X3RpbWV6b25lIDwtIHNjaGVkdWxlX25ldyAlPiUKICBtdXRhdGUoc3RhcnRfZGF0ZXRpbWUgPSBsdWJyaWRhdGU6OndpdGhfdHooc3RhcnRfZGF0ZXRpbWUsIHR6b25lID0gdGltZXpvbmUpLAogICAgICAgICBlbmRfZGF0ZXRpbWUgPSBsdWJyaWRhdGU6OndpdGhfdHooZW5kX2RhdGV0aW1lLCB0em9uZSA9IHRpbWV6b25lKSkKCiMgd3JpdGluZyB0byBDU1YgYW5kIFJEUyBmaWxlcyAtLQp3cml0ZV9jc3Yoc2NoZWR1bGVfbmV3X3RpbWV6b25lLCAKICAgICAgICAgIGhlcmUoInNjaGVkdWxlLWZpbGVzIiwgInNjaGVkdWxlX25ld19sb2NhbHR6LmNzdiIpKQpzYXZlUkRTKHNjaGVkdWxlX25ld190aW1lem9uZSwgCiAgICAgICAgaGVyZSgic2NoZWR1bGUtZmlsZXMiLCAic2NoZWR1bGVfbmV3X2xvY2FsdHouUmRzIikpCiAgCmBgYAoKCiMgQ3JlYXRpbmcgYW4gLmljcyBvYmplY3QKCmBgYHtyfQojIGNyZWF0aW5nIGEgZnVuY3Rpb24gLS0KbWFrZV9jYWxlbmRhciA8LSBmdW5jdGlvbihldmVudCkgewogIGV2ZW50X3N1YnNldCA8LSBzY2hlZHVsZV9uZXdfdGltZXpvbmVbZXZlbnQsIF0KICAKICBjYWxlbmRhcl9ldmVudCA8LQogIGNhbGVuZGFyOjppY19ldmVudChzdGFydF90aW1lID0gZXZlbnRfc3Vic2V0JHN0YXJ0X2RhdGV0aW1lLAogICAgICAgICAgICAgICAgICAgICBlbmRfdGltZSA9IGV2ZW50X3N1YnNldCRlbmRfZGF0ZXRpbWUsCiAgICAgICAgICAgICAgICAgICAgIHN1bW1hcnkgPSBldmVudF9zdWJzZXQkZXZlbnRfbmFtZSkKICAKICByZXR1cm4oY2FsZW5kYXJfZXZlbnQpCn0KCm51bWJlcl9ldmVudHMgPC0gbGVuZ3RoKHNjaGVkdWxlX25ld190aW1lem9uZSRldmVudF9uYW1lKQoKIyBjcmVhdGluZyBpY3Mgb2JqZWN0cyBmb3IgYWxsIGV2ZW50cyAtLQpldmVudHNfYWxsIDwtIG1hcCgxOm51bWJlcl9ldmVudHMsIG1ha2VfY2FsZW5kYXIpICU+JSAKICBiaW5kX3Jvd3MoKQoKIyB3cml0aW5nIHRvIC5pY3MgZmlsZSAtLQpjYWxlbmRhcjo6aWNfd3JpdGUoZXZlbnRzX2FsbCwKICAgICAgICAgICAgICAgICAgIGhlcmUoImNhbGVuZGFyLWZpbGVzLWljcyIsICJhbGxfZXZlbnRzX2xvY2FsdGltZS5pY3MiKSkKYGBgCgojIFNhdmluZyBhcyBhbiBSIHNjcmlwdAoKYGBge3IsIHdhcm5pbmc9RkFMU0V9CmtuaXRyOjpwdXJsKCJyc3R1ZGlvLWdsb2JhbC0yMDIxLWNhbGVuZGFyLlJtZCIpCmBgYAoK