1 Required Packages

# checking to see if the pacman package is installed + installing it if needed
if(require(pacman)==FALSE) install.packages("pacman")
pacman::p_load(tidyverse,
               rvest,
               lubridate, # to fix the date
               magrittr)

2 Scraping the Miami University Found and Impounded Property Listing

When you click on Found and Impounded Property Listing on the Property - Lost, Found, Impounded Page, you will be taken to a Google Doc containing a table of lost and found items.

Please scrape the table and print it out. Your code should be self-contained in the code chunk below.

read_html("https://docs.google.com/spreadsheets/d/e/2PACX-1vQ3uk9AJOMODxS9fUgX_4vnEMj-Di7ulkTXWzPUmaHvHbaII63xmKmRu3VaBvOXrwQhtkOUlL9fxLMB/pubhtml?gid=1104208671&single=true") %>%
  # select html elements we want (the only table)
  html_elements("table") %>%
  html_table() -> lost_and_found
lost_and_found=lost_and_found[[1]]
lost_and_found
## # A tibble: 60 x 5
##       `` ``                                                    ``    ``    ``   
##    <int> <chr>                                                 <chr> <chr> <chr>
##  1     1 "Date Found / Impounded / Turned into MU Police Dept" "Ite~ "Gen~ "Loc~
##  2    NA ""                                                    ""    ""    ""   
##  3     2 "11/24/2021"                                          "Wal~ "Wal~ "Law~
##  4     3 "11/29/2021"                                          "Key~ "Key~ "Arm~
##  5     4 "12/1/2021"                                           "Ele~ "Air~ "Arm~
##  6     5 "12/1/2021"                                           "Key~ "Key~ "Arm~
##  7     6 "12/7/2021"                                           "Cre~ "Cre~ "Arm~
##  8     7 "12/1/2021"                                           "Ele~ "Air~ "Arm~
##  9     8 "12/8/2021"                                           "Cre~ "Cre~ "Rec~
## 10     9 "12/10/2021"                                          "Wal~ "Wal~ "101~
## # ... with 50 more rows
colnames(lost_and_found) = lost_and_found[1, ] # rename columns after the first row
lost_and_found[-1, ] -> lost_and_found
lost_and_found #CHECKING TO SEE IF ROW REMOVED
## # A tibble: 59 x 5
##      `1` `Date Found / Impou~` `Item Category` `General Descr~` `Location Found`
##    <int> <chr>                 <chr>           <chr>            <chr>           
##  1    NA ""                    ""              ""               ""              
##  2     2 "11/24/2021"          "Wallet/Purses" "Wallet"         "Laws Hall"     
##  3     3 "11/29/2021"          "Keys"          "Keys"           "Armstrong"     
##  4     4 "12/1/2021"           "Electronics"   "Airpods"        "Armstrong"     
##  5     5 "12/1/2021"           "Keys"          "Keys"           "Armstrong"     
##  6     6 "12/7/2021"           "Credit Card"   "Credit Card"    "Armstrong"     
##  7     7 "12/1/2021"           "Electronics"   "Airpods"        "Armstrong"     
##  8     8 "12/8/2021"           "Credit Card"   "Credit Card"    "Rec Center"    
##  9     9 "12/10/2021"          "Wallet/Purses" "Wallet"         "101 McGuffey"  
## 10    10 "12/15/2021"          "Other misc it~ "Wheel"          "Unknown"       
## # ... with 49 more rows
lost_and_found[-1, ] -> lost_and_found
lost_and_found #CHECKING TO SEE IF ROW REMOVED
## # A tibble: 58 x 5
##      `1` `Date Found / Impou~` `Item Category` `General Descr~` `Location Found`
##    <int> <chr>                 <chr>           <chr>            <chr>           
##  1     2 11/24/2021            Wallet/Purses   Wallet           Laws Hall       
##  2     3 11/29/2021            Keys            Keys             Armstrong       
##  3     4 12/1/2021             Electronics     Airpods          Armstrong       
##  4     5 12/1/2021             Keys            Keys             Armstrong       
##  5     6 12/7/2021             Credit Card     Credit Card      Armstrong       
##  6     7 12/1/2021             Electronics     Airpods          Armstrong       
##  7     8 12/8/2021             Credit Card     Credit Card      Rec Center      
##  8     9 12/10/2021            Wallet/Purses   Wallet           101 McGuffey    
##  9    10 12/15/2021            Other misc ite~ Wheel            Unknown         
## 10    11 12/16/2021            Wallet/Purses   Wallet           Unknown         
## # ... with 48 more rows
lost_and_found[ ,-1] -> lost_and_found
lost_and_found #CHECKING TO SEE IF COLUMN REMOVED
## # A tibble: 58 x 4
##    `Date Found / Impounded /~` `Item Category` `General Descr~` `Location Found`
##    <chr>                       <chr>           <chr>            <chr>           
##  1 11/24/2021                  Wallet/Purses   Wallet           Laws Hall       
##  2 11/29/2021                  Keys            Keys             Armstrong       
##  3 12/1/2021                   Electronics     Airpods          Armstrong       
##  4 12/1/2021                   Keys            Keys             Armstrong       
##  5 12/7/2021                   Credit Card     Credit Card      Armstrong       
##  6 12/1/2021                   Electronics     Airpods          Armstrong       
##  7 12/8/2021                   Credit Card     Credit Card      Rec Center      
##  8 12/10/2021                  Wallet/Purses   Wallet           101 McGuffey    
##  9 12/15/2021                  Other misc ite~ Wheel            Unknown         
## 10 12/16/2021                  Wallet/Purses   Wallet           Unknown         
## # ... with 48 more rows

3 Create a Table of all FSB Departmental Faculty/Staff

Currently, the Farmer School of Business has the following academic departments: - Accountancy
- Economics - Entrepreneurship
- Finance - Information Systems & Analytics
- Marketing
- Management

Using the code chunk below, please write code that will produce and print a single tibble containing information on ALL departments and the following variables: (a) department name, (b) faculty/staff’s name, (c) faculty/staff’s position, and (d) faculty/staff’s website

depts = c('Accountancy','Economics','Entrepreneurship', 'Finance', 'ISA', 'Marketing', 'Management')
base_url1 = 'https://www.miamioh.edu/fsb/academics/'
base_url2 = '/about/faculty-staff/index.html'
staff_complete = tibble()

for (i in 1:length(depts)){
  url = paste0(base_url1,depts[i],base_url2) 
  read_html(url) -> htmldata
  
  htmldata %>%
    html_elements(css = "td:nth-child(1)") %>%
    html_text2() -> staff_dept
  
  htmldata %>%
    html_elements(css = "strong > a") %>%
    html_text2() -> staff_name
  
  htmldata %>%
    html_elements(css = "i") %>%
    html_text(trim = TRUE) -> staff_position
  
  htmldata %>%
    html_elements(css = "strong > a") %>%
    html_attr('href') -> staff_website
  
  staff = tibble(staff_dept, staff_name, staff_position, staff_website)
  
  staff_complete = rbind(staff_complete, staff)
}

staff_complete
## # A tibble: 188 x 4
##    staff_dept  staff_name           staff_position                 staff_website
##    <chr>       <chr>                <chr>                          <chr>        
##  1 Accountancy Dr. Brian Ballou     EY Professor of Accountancy, ~ http://miami~
##  2 Accountancy Dr. William Brink    Associate Professor            http://miami~
##  3 Accountancy Dr. Po-Chang Chen    Endres Associate Professor Fe~ http://miami~
##  4 Accountancy Dr. Timothy Eaton    Professor                      http://miami~
##  5 Accountancy Dr. Jan Eighme       Teaching Professor             http://miami~
##  6 Accountancy Dr. Anne Farrell     PricewaterhouseCoopers Profes~ http://miami~
##  7 Accountancy Dr. Michele Frank    Assistant Professor            http://miami~
##  8 Accountancy Mrs. Deborah Gentry  Administrative Assistant       http://miami~
##  9 Accountancy Dr. Jonathan Grenier Professor &Miami PRIME Direct~ http://miami~
## 10 Accountancy Dr. Dan Heitger      Deloitte Professor &William I~ http://miami~
## # ... with 178 more rows

4 Netflix Ratings on IMDb

The most popular listings on Netflix are rated and reviews on ImDb. Based on this webpage and its following pages, please create a tibble that contains the following:

  • Title:
  • Years:
  • Age classification:
  • Duration:
  • Genres:
  • IMDb Rating:
  • 1-2 Sentence Summary:
  • Stars:
  • Votes:

Your tibble should contain a variable for the 9 items above for each of the 50 titles found on the page.

Netflix_Ratings = read_html("https://www.imdb.com/search/title/?companies=co0144901")

#Create Titles Variable
Netflix_Ratings %>% html_elements(css = "div.lister-list > div.lister-item.mode-advanced 
                                  > div.lister-item-content > h3.lister-item-header > a") %>%
  html_text() -> Netflix_titles

#Create Variable for movie years
Netflix_Ratings %>%
  html_elements(css='span.lister-item-year.text-muted.unbold') %>%
  html_text()-> Netflix_years


#Create Variable for Age Classification
Netflix_Ratings %>% html_elements("span.certificate") %>%
  html_text() ->
  Netflix_Age_Classification

# Create Variable for duration
Netflix_Ratings %>% 
  html_elements(css = "span.runtime") %>%
  html_text(trim = TRUE) -> Netflix_duration

# Create Variable for Genre's
Netflix_Ratings %>% 
  html_elements(css = "span.genre") %>%
  html_text(trim = TRUE) -> Netflix_genre

# Create Variable for rate
Netflix_Ratings %>% 
  html_elements(css = "div.inline-block.ratings-imdb-rating") %>%
  html_text(trim = TRUE) -> Netflix_rate

# Create Variable for 1-2 sentence summary
Netflix_Ratings %>%
  html_elements(css='div.lister-item-content > p:nth-child(4)') %>%
  html_text(trim = TRUE) -> Netflix_summary

Netflix_Ratings %>%
  html_elements(css='div.lister-item-content > p:nth-child(5)') %>%
  html_text(trim = TRUE) -> Netflix_stars

# Create vote variable and fix where there is a lack of votes
first_vote ='div:nth-child('
second_vote = ') > div.lister-item-content > p.sort-num_votes-visible > span:nth-child(2)'
Netflix_votes = tibble()

for (i in 1:50) {
  cssurl = paste0(first_vote,toString(i),second_vote)
  Netflix_Ratings %>%
    html_elements(css=cssurl) %>%
    html_text(trim = TRUE) -> vote
  if (length(vote) == 0){
    vote = "N/A"
  }
  
  Netflix_votes = rbind(Netflix_votes,vote)
}


# Combine all variables for a tibble
IMDB_Movies = tibble(Netflix_titles, Netflix_Age_Classification, Netflix_genre, Netflix_summary, Netflix_years, Netflix_votes)

IMDB_Movies
## # A tibble: 50 x 6
##    Netflix_titles   Netflix_Age_Cla~ Netflix_genre Netflix_summary Netflix_years
##    <chr>            <chr>            <chr>         <chr>           <chr>        
##  1 Attack on Titan  TV-MA            Animation, A~ After his home~ (2013–2022)  
##  2 The Power of th~ R                Drama, Roman~ Charismatic ra~ (2021)       
##  3 Ozark            TV-MA            Crime, Drama~ A financial ad~ (2017–2022)  
##  4 The Woman in th~ TV-MA            Comedy, Crim~ When a handsom~ (2022)       
##  5 Sweet Magnolias  TV-14            Drama, Roman~ Three South Ca~ (2020– )     
##  6 The Tinder Swin~ TV-MA            Documentary,~ Posing as a we~ (2022)       
##  7 All of Us Are D~ TV-MA            Action, Dram~ A high school ~ (2022– )     
##  8 Inventing Anna   TV-MA            Drama         A journalist w~ (2022)       
##  9 Murderville      TV-MA            Comedy, Crim~ Eccentric dete~ (2022– )     
## 10 Demon Slayer: K~ TV-MA            Animation, A~ A family is at~ (2019– )     
## # ... with 40 more rows, and 1 more variable: X.324.249. <chr>

5 Top 300 Netflix Ratings

Expand on the previous example to capture the top 300 titles on Netflix (i.e., the information across six pages).

## For this question, we excludedthe variables that experienced missing values. 
## Our final tibble includes, Titles, Genre, Summary, and Years

# Create lists for less problematic variables we may use in final tibble
Netflix_titles = list()
Netflix_years = list()
Netflix_Age_Classification = list()
Netflix_genre = list()
Netflix_Summary = list()

Netflix_Ratings = read_html("https://www.imdb.com/search/title/?companies=co0144901")

#Create Titles Variable
Netflix_Ratings %>% html_elements(css = "div.lister-list > div.lister-item.mode-advanced 
                                  > div.lister-item-content > h3.lister-item-header > a") %>%
  html_text() -> Netflix_titles

#Create Variable for movie years
Netflix_Ratings %>%
  html_elements(css='span.lister-item-year.text-muted.unbold') %>%
  html_text()-> Netflix_years


#Create Variable for Age Classification
Netflix_Ratings %>% html_elements("span.certificate") %>%
  html_text(trim = TRUE) -> Netflix_Age_Classification

# --- Commenting out the variables that are missing values ---
# Create Variable for duration
#Netflix_Ratings %>% 
 # html_elements(css = "span.runtime") %>%
  #html_text(trim = TRUE) -> Netflix_duration

# Create Variable for Genre's
Netflix_Ratings %>% 
  html_elements(css = "span.genre") %>%
  html_text(trim = TRUE) -> Netflix_genre

# --- Commenting out the variables that are missing values ---
# Create Variable for rate
#Netflix_Ratings %>% 
 # html_elements(css = "div.inline-block.ratings-imdb-rating") %>%
  #html_text(trim = TRUE) -> Netflix_rate

# Create Variable for 1-2 sentence summary
Netflix_Ratings %>%
  html_elements(css='div.lister-item-content > p:nth-child(4)') %>%
  html_text(trim = TRUE) -> Netflix_summary

# --- Commenting out the variables that are missing values ---
#Netflix_Ratings %>%
 # html_elements(css='div.lister-item-content > p:nth-child(5)') %>%
  #html_text(trim = TRUE) -> Netflix_stars

# Now begin contructing the for loop that will run through each page
all_pages = list(51, 101, 151, 201, 251)
base_url = "https://www.imdb.com/search/title/?companies=co0144901&start="
end_url = "&ref_=adv_nxt"

for (i in all_pages) {
  Netflix_Ratings = paste0(base_url, i, end_url)
  
  Netflix_Ratings %>%
    read_html() %>%
    html_elements(css='h3 > a') %>%
    html_text()-> Title
  Netflix_titles = append(Netflix_titles,Title)
  
  
  Netflix_Ratings %>%
    read_html() %>%
    html_elements(css='span.lister-item-year.text-muted.unbold') %>%
    html_text()-> Year
  Netflix_years = append(Netflix_years,Year)
  
  
  
  Netflix_Ratings %>%
    read_html() %>%
    html_elements(css='span.genre') %>%
    html_text(trim = TRUE) -> Genre
  Netflix_genre = append(Netflix_genre,Genre)
  
  
  Netflix_Ratings %>%
    read_html() %>%
    html_elements(css='div.lister-item-content > p:nth-child(4)') %>%
    html_text(trim = TRUE) -> Summary
  Netflix_summary = append(Netflix_summary,Summary)
  
  vote1 ='div:nth-child('
  vote2 = ') > div.lister-item-content > p.sort-num_votes-visible > span:nth-child(2)'
  Netflix_votes = tibble()
  
  
  Netflix_Ratings %>%
    read_html() %>%
    html_elements(css='span.certificate') %>%
    html_text(trim = TRUE) -> AgeClass
  Netflix_Age_Classification = append(Netflix_Age_Classification,AgeClass)
  
  
}  

imdb = tibble(Netflix_titles, Netflix_genre, Netflix_summary, Netflix_years)

imdb
## # A tibble: 300 x 4
##    Netflix_titles                 Netflix_genre    Netflix_summary Netflix_years
##    <chr>                          <chr>            <chr>           <chr>        
##  1 Attack on Titan                Animation, Acti~ After his home~ (2013–2022)  
##  2 The Power of the Dog           Drama, Romance,~ Charismatic ra~ (2021)       
##  3 Ozark                          Crime, Drama, T~ A financial ad~ (2017–2022)  
##  4 The Woman in the House         Comedy, Crime, ~ When a handsom~ (2022)       
##  5 Sweet Magnolias                Drama, Romance   Three South Ca~ (2020– )     
##  6 The Tinder Swindler            Documentary, Cr~ Posing as a we~ (2022)       
##  7 All of Us Are Dead             Action, Drama, ~ A high school ~ (2022– )     
##  8 Inventing Anna                 Drama            A journalist w~ (2022)       
##  9 Murderville                    Comedy, Crime, ~ Eccentric dete~ (2022– )     
## 10 Demon Slayer: Kimetsu no Yaiba Animation, Acti~ A family is at~ (2019– )     
## # ... with 290 more rows

6 Yelp Reviews for Patterson Cafe

In assignment 02, I shared with you an RDS file containing four variables and all the reviews that were performed on Patterson Cafe on Yelp. Use what you have learned in class to potentially recreate the same results.

# --- Utilizing robots.txt to see if we are allowed to scrape page ---
# at www.yelp.com/robots.txt, it states, “Disallow: /biz/*destination=*” which prevents us from scraping the yelp page for Patterson’s as it follows that same path. Below is the code we worked on prior to learning this information. The trouble we encountered converting the stars into a score may be explained by the fact that they are considered images upon inspection of the html. 


patterson_reviews = read_html("https://www.yelp.com/biz/pattersons-cafe-oxford") 

reviews = tibble()

for(page_result in seq(from = 1, to = 90, by = 10)) {
  link = paste0("https://www.yelp.com/biz/pattersons-cafe-oxford?start=", page_result,
                "90"
  )
  patterson_reviews = read_html("https://www.yelp.com/biz/pattersons-cafe-oxford")
  
  #create reviewer
  patterson_reviews %>% html_elements(css = ".css-1iikwpv .css-1422juy") %>%
    html_text2() -> reviewer
  reviewer
  str(reviewer)
  
  #create review date
  patterson_reviews %>% html_elements(css = ".margin-b1-5__09f24__NHcQi .css-1e4fdj9") %>%
    html_text2() -> review_date
  review_date
  str(review_date)
  
  #create score 
  patterson_reviews %>% html_elements(css = ".margin-b1-5__09f24__NHcQi .overflow--hidden__09f24___ayzG") %>%
    html_text2() -> score
  score
  str(score)
  
  # create comments
  patterson_reviews %>% html_elements(css = ".comment__09f24__gu0rG .raw__09f24__T4Ezm") %>%
    html_text2() -> comments
  comments
  str(comments)
  
  
}
##  chr [1:10] "Dana M." "Melanie U." "Ken N." "Landon C." "Missy H." ...
##  chr [1:10] "11/30/2021" "7/21/2021" "9/24/2020" "7/22/2021" "10/24/2021" ...
##  chr [1:10] "" "" "" "" "" "" "" "" "" ""
##  chr [1:10] "Fabulous gluten free Monte Cristi. Huge pancakes aabd large portions of spaghetti like home fries." ...
##  chr [1:10] "Dana M." "Melanie U." "Ken N." "Landon C." "Missy H." ...
##  chr [1:10] "11/30/2021" "7/21/2021" "9/24/2020" "7/22/2021" "10/24/2021" ...
##  chr [1:10] "" "" "" "" "" "" "" "" "" ""
##  chr [1:10] "Fabulous gluten free Monte Cristi. Huge pancakes aabd large portions of spaghetti like home fries." ...
##  chr(0) 
##  chr(0) 
##  chr(0) 
##  chr(0) 
##  chr [1:10] "Dana M." "Melanie U." "Ken N." "Landon C." "Missy H." ...
##  chr [1:10] "11/30/2021" "7/21/2021" "9/24/2020" "7/22/2021" "10/24/2021" ...
##  chr [1:10] "" "" "" "" "" "" "" "" "" ""
##  chr [1:10] "Fabulous gluten free Monte Cristi. Huge pancakes aabd large portions of spaghetti like home fries." ...
##  chr [1:10] "Dana M." "Melanie U." "Ken N." "Landon C." "Missy H." ...
##  chr [1:10] "11/30/2021" "7/21/2021" "9/24/2020" "7/22/2021" "10/24/2021" ...
##  chr [1:10] "" "" "" "" "" "" "" "" "" ""
##  chr [1:10] "Fabulous gluten free Monte Cristi. Huge pancakes aabd large portions of spaghetti like home fries." ...
##  chr [1:10] "Dana M." "Melanie U." "Ken N." "Landon C." "Missy H." ...
##  chr [1:10] "11/30/2021" "7/21/2021" "9/24/2020" "7/22/2021" "10/24/2021" ...
##  chr [1:10] "" "" "" "" "" "" "" "" "" ""
##  chr [1:10] "Fabulous gluten free Monte Cristi. Huge pancakes aabd large portions of spaghetti like home fries." ...
##  chr [1:10] "Dana M." "Melanie U." "Ken N." "Landon C." "Missy H." ...
##  chr [1:10] "11/30/2021" "7/21/2021" "9/24/2020" "7/22/2021" "10/24/2021" ...
##  chr [1:10] "" "" "" "" "" "" "" "" "" ""
##  chr [1:10] "Fabulous gluten free Monte Cristi. Huge pancakes aabd large portions of spaghetti like home fries." ...
##  chr [1:10] "Dana M." "Melanie U." "Ken N." "Landon C." "Missy H." ...
##  chr [1:10] "11/30/2021" "7/21/2021" "9/24/2020" "7/22/2021" "10/24/2021" ...
##  chr [1:10] "" "" "" "" "" "" "" "" "" ""
##  chr [1:10] "Fabulous gluten free Monte Cristi. Huge pancakes aabd large portions of spaghetti like home fries." ...
##  chr [1:10] "Dana M." "Melanie U." "Ken N." "Landon C." "Missy H." ...
##  chr [1:10] "11/30/2021" "7/21/2021" "9/24/2020" "7/22/2021" "10/24/2021" ...
##  chr [1:10] "" "" "" "" "" "" "" "" "" ""
##  chr [1:10] "Fabulous gluten free Monte Cristi. Huge pancakes aabd large portions of spaghetti like home fries." ...
review = tibble(reviewer, review_date, score, comments)
LS0tDQp0aXRsZTogIkxhYiAxOiBTY3JhcGluZyBXZWIgUGFnZXMiDQphdXRob3I6DQogIC0gbmFtZTogIk1pa2F5bGEgQWxjb3JuIF5bRW1haWw6IGFsY29ybm1wQG1pYW1pb2guZWR1XSINCiAgICBhZmZpbGlhdGlvbjogRmFybWVyIFNjaG9vbCBvZiBCdXNpbmVzcywgTWlhbWkgVW5pdmVyc2l0eQ0KICAtIG5hbWU6ICJQYW5vcyBEYXZheWlvcyBeW0VtYWlsOiBkYXZheWlwZEBtaWFtaW9oLmVkdV0iDQogICAgYWZmaWxpYXRpb246IEZhcm1lciBTY2hvb2wgb2YgQnVzaW5lc3MsIE1pYW1pIFVuaXZlcnNpdHkNCiAgLSBuYW1lOiAiS3lsZSBIZW5jaCBeW0VtYWlsOiBoZW5jaGttQG1pYW1pb2guZWR1XSINCiAgICBhZmZpbGlhdGlvbjogRmFybWVyIFNjaG9vbCBvZiBCdXNpbmVzcywgTWlhbWkgVW5pdmVyc2l0eQ0KZGF0ZTogIlNwcmluZyAyMDIyIg0Kb3V0cHV0OiANCiAgaHRtbF9kb2N1bWVudDoNCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cNCiAgICBjb2RlX2Rvd25sb2FkOiBUUlVFDQogICAgbnVtYmVyX3NlY3Rpb25zOiBUUlVFDQogICAgcGFnZWRfZGY6IFRSVUUNCiAgICB0b2M6IFRSVUUNCiAgICB0b2NfZmxvYXQ6IFRSVUUNCiAgICB0aGVtZTogcmVhZGFibGUNCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICB3YXJuaW5nID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFLA0KICAgICAgICAgICAgICAgICAgICAgIHByb2dyZXNzID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZSA9IFRSVUUsDQogICAgICAgICAgICAgICAgICAgICAgY2FjaGUgPSBUUlVFKQ0KYGBgDQoNCg0KLS0tDQoNCiMgUmVxdWlyZWQgUGFja2FnZXMNCmBgYHtyIHBhY2thZ2VzfQ0KIyBjaGVja2luZyB0byBzZWUgaWYgdGhlIHBhY21hbiBwYWNrYWdlIGlzIGluc3RhbGxlZCArIGluc3RhbGxpbmcgaXQgaWYgbmVlZGVkDQppZihyZXF1aXJlKHBhY21hbik9PUZBTFNFKSBpbnN0YWxsLnBhY2thZ2VzKCJwYWNtYW4iKQ0KcGFjbWFuOjpwX2xvYWQodGlkeXZlcnNlLA0KICAgICAgICAgICAgICAgcnZlc3QsDQogICAgICAgICAgICAgICBsdWJyaWRhdGUsICMgdG8gZml4IHRoZSBkYXRlDQogICAgICAgICAgICAgICBtYWdyaXR0cikNCg0KYGBgDQoNCg0KLS0tDQoNCiMgU2NyYXBpbmcgdGhlIE1pYW1pIFVuaXZlcnNpdHkgRm91bmQgYW5kIEltcG91bmRlZCBQcm9wZXJ0eSBMaXN0aW5nDQoNCldoZW4geW91IGNsaWNrIG9uIFtGb3VuZCBhbmQgSW1wb3VuZGVkIFByb3BlcnR5IExpc3RpbmddKGh0dHBzOi8vZG9jcy5nb29nbGUuY29tL3NwcmVhZHNoZWV0cy9kL2UvMlBBQ1gtMXZRM3VrOUFKT01PRHhTOWZVZ1hfNHZuRU1qLURpN3Vsa1RYV3pQVW1hSHZIYmFJSTYzeG1LbVJ1M1ZhQnZPWHJ3UWh0a09VbEw5ZnhMTUIvcHViaHRtbD9naWQ9MTEwNDIwODY3MSZzaW5nbGU9dHJ1ZSkgb24gdGhlIFtQcm9wZXJ0eSAtIExvc3QsIEZvdW5kLCBJbXBvdW5kZWQgUGFnZV0oaHR0cHM6Ly93d3cubWlhbWlvaC5lZHUvcG9saWNlL3NlcnZpY2VzL3Byb3BlcnR5bG9zdGZvdW5kaW1wb3VuZGVkL2luZGV4Lmh0bWwpLCB5b3Ugd2lsbCBiZSB0YWtlbiB0byBhIEdvb2dsZSBEb2MgY29udGFpbmluZyBhIHRhYmxlIG9mIGxvc3QgYW5kIGZvdW5kIGl0ZW1zLiANCg0KKipQbGVhc2Ugc2NyYXBlIHRoZSB0YWJsZSBhbmQgcHJpbnQgaXQgb3V0LioqIFlvdXIgY29kZSBzaG91bGQgYmUgc2VsZi1jb250YWluZWQgaW4gdGhlIGNvZGUgY2h1bmsgYmVsb3cuDQoNCmBgYHtyIG11X2xvc3RfYW5kX2ZvdW5kfQ0KcmVhZF9odG1sKCJodHRwczovL2RvY3MuZ29vZ2xlLmNvbS9zcHJlYWRzaGVldHMvZC9lLzJQQUNYLTF2UTN1azlBSk9NT0R4UzlmVWdYXzR2bkVNai1EaTd1bGtUWFd6UFVtYUh2SGJhSUk2M3htS21SdTNWYUJ2T1hyd1FodGtPVWxMOWZ4TE1CL3B1Ymh0bWw/Z2lkPTExMDQyMDg2NzEmc2luZ2xlPXRydWUiKSAlPiUNCiAgIyBzZWxlY3QgaHRtbCBlbGVtZW50cyB3ZSB3YW50ICh0aGUgb25seSB0YWJsZSkNCiAgaHRtbF9lbGVtZW50cygidGFibGUiKSAlPiUNCiAgaHRtbF90YWJsZSgpIC0+IGxvc3RfYW5kX2ZvdW5kDQpsb3N0X2FuZF9mb3VuZD1sb3N0X2FuZF9mb3VuZFtbMV1dDQpsb3N0X2FuZF9mb3VuZA0KDQpjb2xuYW1lcyhsb3N0X2FuZF9mb3VuZCkgPSBsb3N0X2FuZF9mb3VuZFsxLCBdICMgcmVuYW1lIGNvbHVtbnMgYWZ0ZXIgdGhlIGZpcnN0IHJvdw0KbG9zdF9hbmRfZm91bmRbLTEsIF0gLT4gbG9zdF9hbmRfZm91bmQNCmxvc3RfYW5kX2ZvdW5kICNDSEVDS0lORyBUTyBTRUUgSUYgUk9XIFJFTU9WRUQNCmxvc3RfYW5kX2ZvdW5kWy0xLCBdIC0+IGxvc3RfYW5kX2ZvdW5kDQpsb3N0X2FuZF9mb3VuZCAjQ0hFQ0tJTkcgVE8gU0VFIElGIFJPVyBSRU1PVkVEDQpsb3N0X2FuZF9mb3VuZFsgLC0xXSAtPiBsb3N0X2FuZF9mb3VuZA0KbG9zdF9hbmRfZm91bmQgI0NIRUNLSU5HIFRPIFNFRSBJRiBDT0xVTU4gUkVNT1ZFRA0KYGBgDQoNCg0KLS0tDQoNCiMgQ3JlYXRlIGEgVGFibGUgb2YgYWxsIEZTQiBEZXBhcnRtZW50YWwgRmFjdWx0eS9TdGFmZg0KDQpDdXJyZW50bHksIHRoZSBGYXJtZXIgU2Nob29sIG9mIEJ1c2luZXNzIGhhcyB0aGUgZm9sbG93aW5nIGFjYWRlbWljIGRlcGFydG1lbnRzOg0KLSBbQWNjb3VudGFuY3ldKGh0dHBzOi8vd3d3Lm1pYW1pb2guZWR1L2ZzYi9hY2FkZW1pY3MvYWNjb3VudGFuY3kvYWJvdXQvZmFjdWx0eS1zdGFmZi9pbmRleC5odG1sKSAgDQotIFtFY29ub21pY3NdKGh0dHBzOi8vd3d3Lm1pYW1pb2guZWR1L2ZzYi9hY2FkZW1pY3MvZWNvbm9taWNzL2Fib3V0L2ZhY3VsdHktc3RhZmYvaW5kZXguaHRtbCkgDQotIFtFbnRyZXByZW5ldXJzaGlwXShodHRwczovL3d3dy5taWFtaW9oLmVkdS9mc2IvYWNhZGVtaWNzL2VudHJlcHJlbmV1cnNoaXAvYWJvdXQvZmFjdWx0eS1zdGFmZi9pbmRleC5odG1sKSAgDQotIFtGaW5hbmNlXShodHRwczovL3d3dy5taWFtaW9oLmVkdS9mc2IvYWNhZGVtaWNzL2ZpbmFuY2UvYWJvdXQvZmFjdWx0eS1zdGFmZi9pbmRleC5odG1sKQ0KLSBbSW5mb3JtYXRpb24gU3lzdGVtcyAmIEFuYWx5dGljc10oaHR0cHM6Ly93d3cubWlhbWlvaC5lZHUvZnNiL2FjYWRlbWljcy9pc2EvYWJvdXQvZmFjdWx0eS1zdGFmZi9pbmRleC5odG1sKSAgDQotIFtNYXJrZXRpbmddKGh0dHBzOi8vd3d3Lm1pYW1pb2guZWR1L2ZzYi9hY2FkZW1pY3MvbWFya2V0aW5nL2Fib3V0L2ZhY3VsdHktc3RhZmYvaW5kZXguaHRtbCkgIA0KLSBbTWFuYWdlbWVudF0oaHR0cHM6Ly93d3cubWlhbWlvaC5lZHUvZnNiL2FjYWRlbWljcy9tYW5hZ2VtZW50L2Fib3V0L2ZhY3VsdHktc3RhZmYvaW5kZXguaHRtbCkgIA0KDQpVc2luZyB0aGUgY29kZSBjaHVuayBiZWxvdywgcGxlYXNlIHdyaXRlIGNvZGUgdGhhdCB3aWxsIHByb2R1Y2UgYW5kIHByaW50IGEgKipzaW5nbGUgdGliYmxlIGNvbnRhaW5pbmcgaW5mb3JtYXRpb24gb24gQUxMIGRlcGFydG1lbnRzIGFuZCB0aGUgZm9sbG93aW5nIHZhcmlhYmxlczoqKiAoYSkgZGVwYXJ0bWVudCBuYW1lLCAoYikgZmFjdWx0eS9zdGFmZidzIG5hbWUsIChjKSBmYWN1bHR5L3N0YWZmJ3MgcG9zaXRpb24sIGFuZCAoZCkgZmFjdWx0eS9zdGFmZidzIHdlYnNpdGUNCg0KYGBge3IgZnNiX2ZhY3VsdHlfc3RhZmZ9DQpkZXB0cyA9IGMoJ0FjY291bnRhbmN5JywnRWNvbm9taWNzJywnRW50cmVwcmVuZXVyc2hpcCcsICdGaW5hbmNlJywgJ0lTQScsICdNYXJrZXRpbmcnLCAnTWFuYWdlbWVudCcpDQpiYXNlX3VybDEgPSAnaHR0cHM6Ly93d3cubWlhbWlvaC5lZHUvZnNiL2FjYWRlbWljcy8nDQpiYXNlX3VybDIgPSAnL2Fib3V0L2ZhY3VsdHktc3RhZmYvaW5kZXguaHRtbCcNCnN0YWZmX2NvbXBsZXRlID0gdGliYmxlKCkNCg0KZm9yIChpIGluIDE6bGVuZ3RoKGRlcHRzKSl7DQogIHVybCA9IHBhc3RlMChiYXNlX3VybDEsZGVwdHNbaV0sYmFzZV91cmwyKSANCiAgcmVhZF9odG1sKHVybCkgLT4gaHRtbGRhdGENCiAgDQogIGh0bWxkYXRhICU+JQ0KICAgIGh0bWxfZWxlbWVudHMoY3NzID0gInRkOm50aC1jaGlsZCgxKSIpICU+JQ0KICAgIGh0bWxfdGV4dDIoKSAtPiBzdGFmZl9kZXB0DQogIA0KICBodG1sZGF0YSAlPiUNCiAgICBodG1sX2VsZW1lbnRzKGNzcyA9ICJzdHJvbmcgPiBhIikgJT4lDQogICAgaHRtbF90ZXh0MigpIC0+IHN0YWZmX25hbWUNCiAgDQogIGh0bWxkYXRhICU+JQ0KICAgIGh0bWxfZWxlbWVudHMoY3NzID0gImkiKSAlPiUNCiAgICBodG1sX3RleHQodHJpbSA9IFRSVUUpIC0+IHN0YWZmX3Bvc2l0aW9uDQogIA0KICBodG1sZGF0YSAlPiUNCiAgICBodG1sX2VsZW1lbnRzKGNzcyA9ICJzdHJvbmcgPiBhIikgJT4lDQogICAgaHRtbF9hdHRyKCdocmVmJykgLT4gc3RhZmZfd2Vic2l0ZQ0KICANCiAgc3RhZmYgPSB0aWJibGUoc3RhZmZfZGVwdCwgc3RhZmZfbmFtZSwgc3RhZmZfcG9zaXRpb24sIHN0YWZmX3dlYnNpdGUpDQogIA0KICBzdGFmZl9jb21wbGV0ZSA9IHJiaW5kKHN0YWZmX2NvbXBsZXRlLCBzdGFmZikNCn0NCg0Kc3RhZmZfY29tcGxldGUNCmBgYA0KDQoNCi0tLQ0KDQojIE5ldGZsaXggUmF0aW5ncyBvbiBJTURiDQoNClRoZSBtb3N0IHBvcHVsYXIgbGlzdGluZ3Mgb24gTmV0ZmxpeCBhcmUgcmF0ZWQgYW5kIHJldmlld3Mgb24gW0ltRGJdKGh0dHBzOi8vd3d3LmltZGIuY29tL3NlYXJjaC90aXRsZS8/Y29tcGFuaWVzPWNvMDE0NDkwMSkuIEJhc2VkIG9uIHRoaXMgd2VicGFnZSBhbmQgaXRzIGZvbGxvd2luZyBwYWdlcywgcGxlYXNlIGNyZWF0ZSBhICoqdGliYmxlKiogdGhhdCBjb250YWlucyB0aGUgZm9sbG93aW5nOg0KDQotICpUaXRsZToqICANCi0gKlllYXJzOioNCi0gKkFnZSBjbGFzc2lmaWNhdGlvbjoqDQotICpEdXJhdGlvbjoqDQotICpHZW5yZXM6Kg0KLSAqSU1EYiBSYXRpbmc6Kg0KLSAqMS0yIFNlbnRlbmNlIFN1bW1hcnk6Kg0KLSAqU3RhcnM6Kg0KLSAqVm90ZXM6Kg0KDQoqKllvdXIgdGliYmxlIHNob3VsZCBjb250YWluIGEgdmFyaWFibGUgZm9yIHRoZSA5IGl0ZW1zIGFib3ZlIGZvciBlYWNoIG9mIHRoZSA1MCB0aXRsZXMgZm91bmQgb24gdGhlIHBhZ2UuKiogDQoNCmBgYHtyIG5ldGZsaXhfaW1kYl9wMX0NCk5ldGZsaXhfUmF0aW5ncyA9IHJlYWRfaHRtbCgiaHR0cHM6Ly93d3cuaW1kYi5jb20vc2VhcmNoL3RpdGxlLz9jb21wYW5pZXM9Y28wMTQ0OTAxIikNCg0KI0NyZWF0ZSBUaXRsZXMgVmFyaWFibGUNCk5ldGZsaXhfUmF0aW5ncyAlPiUgaHRtbF9lbGVtZW50cyhjc3MgPSAiZGl2Lmxpc3Rlci1saXN0ID4gZGl2Lmxpc3Rlci1pdGVtLm1vZGUtYWR2YW5jZWQgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPiBkaXYubGlzdGVyLWl0ZW0tY29udGVudCA+IGgzLmxpc3Rlci1pdGVtLWhlYWRlciA+IGEiKSAlPiUNCiAgaHRtbF90ZXh0KCkgLT4gTmV0ZmxpeF90aXRsZXMNCg0KI0NyZWF0ZSBWYXJpYWJsZSBmb3IgbW92aWUgeWVhcnMNCk5ldGZsaXhfUmF0aW5ncyAlPiUNCiAgaHRtbF9lbGVtZW50cyhjc3M9J3NwYW4ubGlzdGVyLWl0ZW0teWVhci50ZXh0LW11dGVkLnVuYm9sZCcpICU+JQ0KICBodG1sX3RleHQoKS0+IE5ldGZsaXhfeWVhcnMNCg0KDQojQ3JlYXRlIFZhcmlhYmxlIGZvciBBZ2UgQ2xhc3NpZmljYXRpb24NCk5ldGZsaXhfUmF0aW5ncyAlPiUgaHRtbF9lbGVtZW50cygic3Bhbi5jZXJ0aWZpY2F0ZSIpICU+JQ0KICBodG1sX3RleHQoKSAtPg0KICBOZXRmbGl4X0FnZV9DbGFzc2lmaWNhdGlvbg0KDQojIENyZWF0ZSBWYXJpYWJsZSBmb3IgZHVyYXRpb24NCk5ldGZsaXhfUmF0aW5ncyAlPiUgDQogIGh0bWxfZWxlbWVudHMoY3NzID0gInNwYW4ucnVudGltZSIpICU+JQ0KICBodG1sX3RleHQodHJpbSA9IFRSVUUpIC0+IE5ldGZsaXhfZHVyYXRpb24NCg0KIyBDcmVhdGUgVmFyaWFibGUgZm9yIEdlbnJlJ3MNCk5ldGZsaXhfUmF0aW5ncyAlPiUgDQogIGh0bWxfZWxlbWVudHMoY3NzID0gInNwYW4uZ2VucmUiKSAlPiUNCiAgaHRtbF90ZXh0KHRyaW0gPSBUUlVFKSAtPiBOZXRmbGl4X2dlbnJlDQoNCiMgQ3JlYXRlIFZhcmlhYmxlIGZvciByYXRlDQpOZXRmbGl4X1JhdGluZ3MgJT4lIA0KICBodG1sX2VsZW1lbnRzKGNzcyA9ICJkaXYuaW5saW5lLWJsb2NrLnJhdGluZ3MtaW1kYi1yYXRpbmciKSAlPiUNCiAgaHRtbF90ZXh0KHRyaW0gPSBUUlVFKSAtPiBOZXRmbGl4X3JhdGUNCg0KIyBDcmVhdGUgVmFyaWFibGUgZm9yIDEtMiBzZW50ZW5jZSBzdW1tYXJ5DQpOZXRmbGl4X1JhdGluZ3MgJT4lDQogIGh0bWxfZWxlbWVudHMoY3NzPSdkaXYubGlzdGVyLWl0ZW0tY29udGVudCA+IHA6bnRoLWNoaWxkKDQpJykgJT4lDQogIGh0bWxfdGV4dCh0cmltID0gVFJVRSkgLT4gTmV0ZmxpeF9zdW1tYXJ5DQoNCk5ldGZsaXhfUmF0aW5ncyAlPiUNCiAgaHRtbF9lbGVtZW50cyhjc3M9J2Rpdi5saXN0ZXItaXRlbS1jb250ZW50ID4gcDpudGgtY2hpbGQoNSknKSAlPiUNCiAgaHRtbF90ZXh0KHRyaW0gPSBUUlVFKSAtPiBOZXRmbGl4X3N0YXJzDQoNCiMgQ3JlYXRlIHZvdGUgdmFyaWFibGUgYW5kIGZpeCB3aGVyZSB0aGVyZSBpcyBhIGxhY2sgb2Ygdm90ZXMNCmZpcnN0X3ZvdGUgPSdkaXY6bnRoLWNoaWxkKCcNCnNlY29uZF92b3RlID0gJykgPiBkaXYubGlzdGVyLWl0ZW0tY29udGVudCA+IHAuc29ydC1udW1fdm90ZXMtdmlzaWJsZSA+IHNwYW46bnRoLWNoaWxkKDIpJw0KTmV0ZmxpeF92b3RlcyA9IHRpYmJsZSgpDQoNCmZvciAoaSBpbiAxOjUwKSB7DQogIGNzc3VybCA9IHBhc3RlMChmaXJzdF92b3RlLHRvU3RyaW5nKGkpLHNlY29uZF92b3RlKQ0KICBOZXRmbGl4X1JhdGluZ3MgJT4lDQogICAgaHRtbF9lbGVtZW50cyhjc3M9Y3NzdXJsKSAlPiUNCiAgICBodG1sX3RleHQodHJpbSA9IFRSVUUpIC0+IHZvdGUNCiAgaWYgKGxlbmd0aCh2b3RlKSA9PSAwKXsNCiAgICB2b3RlID0gIk4vQSINCiAgfQ0KICANCiAgTmV0ZmxpeF92b3RlcyA9IHJiaW5kKE5ldGZsaXhfdm90ZXMsdm90ZSkNCn0NCg0KDQojIENvbWJpbmUgYWxsIHZhcmlhYmxlcyBmb3IgYSB0aWJibGUNCklNREJfTW92aWVzID0gdGliYmxlKE5ldGZsaXhfdGl0bGVzLCBOZXRmbGl4X0FnZV9DbGFzc2lmaWNhdGlvbiwgTmV0ZmxpeF9nZW5yZSwgTmV0ZmxpeF9zdW1tYXJ5LCBOZXRmbGl4X3llYXJzLCBOZXRmbGl4X3ZvdGVzKQ0KDQpJTURCX01vdmllcw0KYGBgDQoNCi0tLQ0KDQojIFRvcCAzMDAgTmV0ZmxpeCBSYXRpbmdzIA0KDQpFeHBhbmQgb24gdGhlIHByZXZpb3VzIGV4YW1wbGUgdG8gY2FwdHVyZSB0aGUgdG9wICoqMzAwKiogdGl0bGVzIG9uIE5ldGZsaXggKGkuZS4sIHRoZSBpbmZvcm1hdGlvbiBhY3Jvc3Mgc2l4IHBhZ2VzKS4NCg0KYGBge3IgbmV0ZmxpeF9pbWRiX3AyfQ0KIyMgRm9yIHRoaXMgcXVlc3Rpb24sIHdlIGV4Y2x1ZGVkdGhlIHZhcmlhYmxlcyB0aGF0IGV4cGVyaWVuY2VkIG1pc3NpbmcgdmFsdWVzLiANCiMjIE91ciBmaW5hbCB0aWJibGUgaW5jbHVkZXMsIFRpdGxlcywgR2VucmUsIFN1bW1hcnksIGFuZCBZZWFycw0KDQojIENyZWF0ZSBsaXN0cyBmb3IgbGVzcyBwcm9ibGVtYXRpYyB2YXJpYWJsZXMgd2UgbWF5IHVzZSBpbiBmaW5hbCB0aWJibGUNCk5ldGZsaXhfdGl0bGVzID0gbGlzdCgpDQpOZXRmbGl4X3llYXJzID0gbGlzdCgpDQpOZXRmbGl4X0FnZV9DbGFzc2lmaWNhdGlvbiA9IGxpc3QoKQ0KTmV0ZmxpeF9nZW5yZSA9IGxpc3QoKQ0KTmV0ZmxpeF9TdW1tYXJ5ID0gbGlzdCgpDQoNCk5ldGZsaXhfUmF0aW5ncyA9IHJlYWRfaHRtbCgiaHR0cHM6Ly93d3cuaW1kYi5jb20vc2VhcmNoL3RpdGxlLz9jb21wYW5pZXM9Y28wMTQ0OTAxIikNCg0KI0NyZWF0ZSBUaXRsZXMgVmFyaWFibGUNCk5ldGZsaXhfUmF0aW5ncyAlPiUgaHRtbF9lbGVtZW50cyhjc3MgPSAiZGl2Lmxpc3Rlci1saXN0ID4gZGl2Lmxpc3Rlci1pdGVtLm1vZGUtYWR2YW5jZWQgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPiBkaXYubGlzdGVyLWl0ZW0tY29udGVudCA+IGgzLmxpc3Rlci1pdGVtLWhlYWRlciA+IGEiKSAlPiUNCiAgaHRtbF90ZXh0KCkgLT4gTmV0ZmxpeF90aXRsZXMNCg0KI0NyZWF0ZSBWYXJpYWJsZSBmb3IgbW92aWUgeWVhcnMNCk5ldGZsaXhfUmF0aW5ncyAlPiUNCiAgaHRtbF9lbGVtZW50cyhjc3M9J3NwYW4ubGlzdGVyLWl0ZW0teWVhci50ZXh0LW11dGVkLnVuYm9sZCcpICU+JQ0KICBodG1sX3RleHQoKS0+IE5ldGZsaXhfeWVhcnMNCg0KDQojQ3JlYXRlIFZhcmlhYmxlIGZvciBBZ2UgQ2xhc3NpZmljYXRpb24NCk5ldGZsaXhfUmF0aW5ncyAlPiUgaHRtbF9lbGVtZW50cygic3Bhbi5jZXJ0aWZpY2F0ZSIpICU+JQ0KICBodG1sX3RleHQodHJpbSA9IFRSVUUpIC0+IE5ldGZsaXhfQWdlX0NsYXNzaWZpY2F0aW9uDQoNCiMgLS0tIENvbW1lbnRpbmcgb3V0IHRoZSB2YXJpYWJsZXMgdGhhdCBhcmUgbWlzc2luZyB2YWx1ZXMgLS0tDQojIENyZWF0ZSBWYXJpYWJsZSBmb3IgZHVyYXRpb24NCiNOZXRmbGl4X1JhdGluZ3MgJT4lIA0KICMgaHRtbF9lbGVtZW50cyhjc3MgPSAic3Bhbi5ydW50aW1lIikgJT4lDQogICNodG1sX3RleHQodHJpbSA9IFRSVUUpIC0+IE5ldGZsaXhfZHVyYXRpb24NCg0KIyBDcmVhdGUgVmFyaWFibGUgZm9yIEdlbnJlJ3MNCk5ldGZsaXhfUmF0aW5ncyAlPiUgDQogIGh0bWxfZWxlbWVudHMoY3NzID0gInNwYW4uZ2VucmUiKSAlPiUNCiAgaHRtbF90ZXh0KHRyaW0gPSBUUlVFKSAtPiBOZXRmbGl4X2dlbnJlDQoNCiMgLS0tIENvbW1lbnRpbmcgb3V0IHRoZSB2YXJpYWJsZXMgdGhhdCBhcmUgbWlzc2luZyB2YWx1ZXMgLS0tDQojIENyZWF0ZSBWYXJpYWJsZSBmb3IgcmF0ZQ0KI05ldGZsaXhfUmF0aW5ncyAlPiUgDQogIyBodG1sX2VsZW1lbnRzKGNzcyA9ICJkaXYuaW5saW5lLWJsb2NrLnJhdGluZ3MtaW1kYi1yYXRpbmciKSAlPiUNCiAgI2h0bWxfdGV4dCh0cmltID0gVFJVRSkgLT4gTmV0ZmxpeF9yYXRlDQoNCiMgQ3JlYXRlIFZhcmlhYmxlIGZvciAxLTIgc2VudGVuY2Ugc3VtbWFyeQ0KTmV0ZmxpeF9SYXRpbmdzICU+JQ0KICBodG1sX2VsZW1lbnRzKGNzcz0nZGl2Lmxpc3Rlci1pdGVtLWNvbnRlbnQgPiBwOm50aC1jaGlsZCg0KScpICU+JQ0KICBodG1sX3RleHQodHJpbSA9IFRSVUUpIC0+IE5ldGZsaXhfc3VtbWFyeQ0KDQojIC0tLSBDb21tZW50aW5nIG91dCB0aGUgdmFyaWFibGVzIHRoYXQgYXJlIG1pc3NpbmcgdmFsdWVzIC0tLQ0KI05ldGZsaXhfUmF0aW5ncyAlPiUNCiAjIGh0bWxfZWxlbWVudHMoY3NzPSdkaXYubGlzdGVyLWl0ZW0tY29udGVudCA+IHA6bnRoLWNoaWxkKDUpJykgJT4lDQogICNodG1sX3RleHQodHJpbSA9IFRSVUUpIC0+IE5ldGZsaXhfc3RhcnMNCg0KIyBOb3cgYmVnaW4gY29udHJ1Y3RpbmcgdGhlIGZvciBsb29wIHRoYXQgd2lsbCBydW4gdGhyb3VnaCBlYWNoIHBhZ2UNCmFsbF9wYWdlcyA9IGxpc3QoNTEsIDEwMSwgMTUxLCAyMDEsIDI1MSkNCmJhc2VfdXJsID0gImh0dHBzOi8vd3d3LmltZGIuY29tL3NlYXJjaC90aXRsZS8/Y29tcGFuaWVzPWNvMDE0NDkwMSZzdGFydD0iDQplbmRfdXJsID0gIiZyZWZfPWFkdl9ueHQiDQoNCmZvciAoaSBpbiBhbGxfcGFnZXMpIHsNCiAgTmV0ZmxpeF9SYXRpbmdzID0gcGFzdGUwKGJhc2VfdXJsLCBpLCBlbmRfdXJsKQ0KICANCiAgTmV0ZmxpeF9SYXRpbmdzICU+JQ0KICAgIHJlYWRfaHRtbCgpICU+JQ0KICAgIGh0bWxfZWxlbWVudHMoY3NzPSdoMyA+IGEnKSAlPiUNCiAgICBodG1sX3RleHQoKS0+IFRpdGxlDQogIE5ldGZsaXhfdGl0bGVzID0gYXBwZW5kKE5ldGZsaXhfdGl0bGVzLFRpdGxlKQ0KICANCiAgDQogIE5ldGZsaXhfUmF0aW5ncyAlPiUNCiAgICByZWFkX2h0bWwoKSAlPiUNCiAgICBodG1sX2VsZW1lbnRzKGNzcz0nc3Bhbi5saXN0ZXItaXRlbS15ZWFyLnRleHQtbXV0ZWQudW5ib2xkJykgJT4lDQogICAgaHRtbF90ZXh0KCktPiBZZWFyDQogIE5ldGZsaXhfeWVhcnMgPSBhcHBlbmQoTmV0ZmxpeF95ZWFycyxZZWFyKQ0KICANCiAgDQogIA0KICBOZXRmbGl4X1JhdGluZ3MgJT4lDQogICAgcmVhZF9odG1sKCkgJT4lDQogICAgaHRtbF9lbGVtZW50cyhjc3M9J3NwYW4uZ2VucmUnKSAlPiUNCiAgICBodG1sX3RleHQodHJpbSA9IFRSVUUpIC0+IEdlbnJlDQogIE5ldGZsaXhfZ2VucmUgPSBhcHBlbmQoTmV0ZmxpeF9nZW5yZSxHZW5yZSkNCiAgDQogIA0KICBOZXRmbGl4X1JhdGluZ3MgJT4lDQogICAgcmVhZF9odG1sKCkgJT4lDQogICAgaHRtbF9lbGVtZW50cyhjc3M9J2Rpdi5saXN0ZXItaXRlbS1jb250ZW50ID4gcDpudGgtY2hpbGQoNCknKSAlPiUNCiAgICBodG1sX3RleHQodHJpbSA9IFRSVUUpIC0+IFN1bW1hcnkNCiAgTmV0ZmxpeF9zdW1tYXJ5ID0gYXBwZW5kKE5ldGZsaXhfc3VtbWFyeSxTdW1tYXJ5KQ0KICANCiAgdm90ZTEgPSdkaXY6bnRoLWNoaWxkKCcNCiAgdm90ZTIgPSAnKSA+IGRpdi5saXN0ZXItaXRlbS1jb250ZW50ID4gcC5zb3J0LW51bV92b3Rlcy12aXNpYmxlID4gc3BhbjpudGgtY2hpbGQoMiknDQogIE5ldGZsaXhfdm90ZXMgPSB0aWJibGUoKQ0KICANCiAgDQogIE5ldGZsaXhfUmF0aW5ncyAlPiUNCiAgICByZWFkX2h0bWwoKSAlPiUNCiAgICBodG1sX2VsZW1lbnRzKGNzcz0nc3Bhbi5jZXJ0aWZpY2F0ZScpICU+JQ0KICAgIGh0bWxfdGV4dCh0cmltID0gVFJVRSkgLT4gQWdlQ2xhc3MNCiAgTmV0ZmxpeF9BZ2VfQ2xhc3NpZmljYXRpb24gPSBhcHBlbmQoTmV0ZmxpeF9BZ2VfQ2xhc3NpZmljYXRpb24sQWdlQ2xhc3MpDQogIA0KICANCn0gIA0KDQppbWRiID0gdGliYmxlKE5ldGZsaXhfdGl0bGVzLCBOZXRmbGl4X2dlbnJlLCBOZXRmbGl4X3N1bW1hcnksIE5ldGZsaXhfeWVhcnMpDQoNCmltZGINCmBgYA0KDQoNCi0tLQ0KDQojIFllbHAgUmV2aWV3cyBmb3IgUGF0dGVyc29uIENhZmUNCkluIGFzc2lnbm1lbnQgMDIsIEkgc2hhcmVkIHdpdGggeW91IGFuIFJEUyBmaWxlIGNvbnRhaW5pbmcgZm91ciB2YXJpYWJsZXMgYW5kIGFsbCB0aGUgcmV2aWV3cyB0aGF0IHdlcmUgcGVyZm9ybWVkIG9uIFtQYXR0ZXJzb24gQ2FmZSBvbiBZZWxwXShodHRwczovL3d3dy55ZWxwLmNvbS9iaXovcGF0dGVyc29ucy1jYWZlLW94Zm9yZCkuIFVzZSB3aGF0IHlvdSBoYXZlIGxlYXJuZWQgaW4gY2xhc3MgdG8gcG90ZW50aWFsbHkgcmVjcmVhdGUgdGhlIHNhbWUgcmVzdWx0cy4NCg0KYGBge3IgeWVscF9yZXZpZXdzfQ0KIyAtLS0gVXRpbGl6aW5nIHJvYm90cy50eHQgdG8gc2VlIGlmIHdlIGFyZSBhbGxvd2VkIHRvIHNjcmFwZSBwYWdlIC0tLQ0KIyBhdCB3d3cueWVscC5jb20vcm9ib3RzLnR4dCwgaXQgc3RhdGVzLCDigJxEaXNhbGxvdzogL2Jpei8qZGVzdGluYXRpb249KuKAnSB3aGljaCBwcmV2ZW50cyB1cyBmcm9tIHNjcmFwaW5nIHRoZSB5ZWxwIHBhZ2UgZm9yIFBhdHRlcnNvbuKAmXMgYXMgaXQgZm9sbG93cyB0aGF0IHNhbWUgcGF0aC4gQmVsb3cgaXMgdGhlIGNvZGUgd2Ugd29ya2VkIG9uIHByaW9yIHRvIGxlYXJuaW5nIHRoaXMgaW5mb3JtYXRpb24uIFRoZSB0cm91YmxlIHdlIGVuY291bnRlcmVkIGNvbnZlcnRpbmcgdGhlIHN0YXJzIGludG8gYSBzY29yZSBtYXkgYmUgZXhwbGFpbmVkIGJ5IHRoZSBmYWN0IHRoYXQgdGhleSBhcmUgY29uc2lkZXJlZCBpbWFnZXMgdXBvbiBpbnNwZWN0aW9uIG9mIHRoZSBodG1sLiANCg0KDQpwYXR0ZXJzb25fcmV2aWV3cyA9IHJlYWRfaHRtbCgiaHR0cHM6Ly93d3cueWVscC5jb20vYml6L3BhdHRlcnNvbnMtY2FmZS1veGZvcmQiKSANCg0KcmV2aWV3cyA9IHRpYmJsZSgpDQoNCmZvcihwYWdlX3Jlc3VsdCBpbiBzZXEoZnJvbSA9IDEsIHRvID0gOTAsIGJ5ID0gMTApKSB7DQogIGxpbmsgPSBwYXN0ZTAoImh0dHBzOi8vd3d3LnllbHAuY29tL2Jpei9wYXR0ZXJzb25zLWNhZmUtb3hmb3JkP3N0YXJ0PSIsIHBhZ2VfcmVzdWx0LA0KICAgICAgICAgICAgICAgICI5MCINCiAgKQ0KICBwYXR0ZXJzb25fcmV2aWV3cyA9IHJlYWRfaHRtbCgiaHR0cHM6Ly93d3cueWVscC5jb20vYml6L3BhdHRlcnNvbnMtY2FmZS1veGZvcmQiKQ0KICANCiAgI2NyZWF0ZSByZXZpZXdlcg0KICBwYXR0ZXJzb25fcmV2aWV3cyAlPiUgaHRtbF9lbGVtZW50cyhjc3MgPSAiLmNzcy0xaWlrd3B2IC5jc3MtMTQyMmp1eSIpICU+JQ0KICAgIGh0bWxfdGV4dDIoKSAtPiByZXZpZXdlcg0KICByZXZpZXdlcg0KICBzdHIocmV2aWV3ZXIpDQogIA0KICAjY3JlYXRlIHJldmlldyBkYXRlDQogIHBhdHRlcnNvbl9yZXZpZXdzICU+JSBodG1sX2VsZW1lbnRzKGNzcyA9ICIubWFyZ2luLWIxLTVfXzA5ZjI0X19OSGNRaSAuY3NzLTFlNGZkajkiKSAlPiUNCiAgICBodG1sX3RleHQyKCkgLT4gcmV2aWV3X2RhdGUNCiAgcmV2aWV3X2RhdGUNCiAgc3RyKHJldmlld19kYXRlKQ0KICANCiAgI2NyZWF0ZSBzY29yZSANCiAgcGF0dGVyc29uX3Jldmlld3MgJT4lIGh0bWxfZWxlbWVudHMoY3NzID0gIi5tYXJnaW4tYjEtNV9fMDlmMjRfX05IY1FpIC5vdmVyZmxvdy0taGlkZGVuX18wOWYyNF9fX2F5ekciKSAlPiUNCiAgICBodG1sX3RleHQyKCkgLT4gc2NvcmUNCiAgc2NvcmUNCiAgc3RyKHNjb3JlKQ0KICANCiAgIyBjcmVhdGUgY29tbWVudHMNCiAgcGF0dGVyc29uX3Jldmlld3MgJT4lIGh0bWxfZWxlbWVudHMoY3NzID0gIi5jb21tZW50X18wOWYyNF9fZ3UwckcgLnJhd19fMDlmMjRfX1Q0RXptIikgJT4lDQogICAgaHRtbF90ZXh0MigpIC0+IGNvbW1lbnRzDQogIGNvbW1lbnRzDQogIHN0cihjb21tZW50cykNCiAgDQogIA0KfQ0KDQpyZXZpZXcgPSB0aWJibGUocmV2aWV3ZXIsIHJldmlld19kYXRlLCBzY29yZSwgY29tbWVudHMpDQoNCmBgYA0KDQo=