data source




Start to crawl

library(xml2)
library(XML)
library(dplyr)
library(RSelenium)

load("data/rawdata.rdata")

load

# load("data/creatorInfo.rdata")
# load("data/projectInfo.rdata")
# load("data/updateInfo.rdata")
# load("data/supportInfo.rdata")

Creator Information

creator_info = Reduce(rbind, Map(function(x){

  # x = creator_id[14]
  url = paste0("https://www.kickstarter.com/profile/", x, "/about")
  # url = "https://www.kickstarter.com/profile/795368464/about"
  doc = read_html(url)
  
  ## biography
  xpath = '//*[(@id = "content")]//p'
  bio = paste0("",xml_text(xml_find_all(doc, xpath)))
  bio = gsub("\n", "", bio[2])      # 去除換行及前後空白
  bio = gsub("^\\s|\\s$", "", bio)
  if(is.na(bio)) bio=NA
  
  ## websites
  xpath = '//*[(@id = "content")]//a'
  websites = paste0("",xml_attr(xml_find_all(doc, xpath), "href"))
  websites = gsub("\n", "", websites)      # 去除換行及前後空白
  websites = gsub("^\\s|\\s$", "", websites)
  
  webs = "" 
  webs = paste(websites, collapse = ', ') # 把所有網址連接在一起

  ## backed project count
  xpath = '//span[@class="backed"]'
  backed = xml_text(xml_find_all(doc, xpath)) %>% regmatches(., regexpr("[[:digit:]]", .)) %>% trimws
  if(length(backed)==0) backed=NA
  
  ## created project count
  xpath = '//span[@class="count"]'
  created = xml_text(xml_find_all(doc, xpath)[1]) %>% regmatches(., regexpr("[[:digit:]]", .)) %>% trimws
  if(length(created)==0) created=NA
  
  # 存成data frame
  df = data.frame(cid = x, 
                  biography = bio, 
                  websites = webs, 
                  backed = backed,
                  created = created)
}, creator_id))

# View(creator_info)

save(creator_info, file="data/creatorInfo.rdata")
"done"

project information

iter = 0
project_info = Reduce(rbind, Map(function(x){
  
  # x="https://www.kickstarter.com/projects/1870476470/tomb-of-horror-vol-2-horror-anthology?ref=category_newest"
  
  iter = iter+1
  doc = read_html(x)
  
  ## updates count
  xpath = '//*[contains(concat( " ", @class, " " ), concat( " ", "project-nav__link--updates", " " ))]//*[contains(concat( " ", @class, " " ), concat( " ", "count", " " ))]'
  upd_cnt = xml_text(xml_find_all(doc, xpath)) %>% as.numeric
  
  ## comments count 
  xpath = '//*[contains(concat( " ", @class, " " ), concat( " ", "project-nav__link--comments", " " ))]'
  cmt_cnt = xml_find_all(doc, xpath) %>% 
    xml_text %>% 
    regmatches(., regexpr("[[:digit:]]", .)) %>%
    trimws %>%
    as.numeric
  
  ## project image
  xpath='//img[contains(concat( " ", @class, " " ), concat( " ", "aspect-ratio--object", " " ))]'
  img_src = doc %>% xml_find_all(xpath) %>% xml_attr("src")
  if(length(img_src)==0) img_src=NA
  
  ## Description
  xpath='//*[contains(concat( " ", @class, " " ), concat( " ", "description-container", " " ))]'
  desc = doc %>% 
    xml_find_all(xpath) %>% 
    xml_text %>% 
    sub("\\sLearn about accountability on Kickstarter","",.) %>%    # 去除最下面的贅字
    sub("\\sQuestions about this project\\?","",.) %>% 
    sub("Check out the FAQ","",.) %>% 
    sub("\\sReport this project to Kickstarter","",.) %>% 
    trimws
  
  ### Risks and challenges
  desc_risksAndChallenges = desc %>% regmatches(., regexpr("Risks and challenges[[:space:]].*", .)) %>%
    sub("Risks and challenges","",.) %>% trimws
  if(length(desc_risksAndChallenges)==0) desc_risksAndChallenges=NA
  ### About
  desc_about = desc %>% 
    regmatches(., regexpr("About[[:space:]].*", .)) %>%
    sub("About","",.) %>% trimws
  Erroresult<- tryCatch(                  # 如果沒有Risks and challenges
    {
      desc_about = desc_about %>% sub(regmatches(., regexpr("Risks and challenges[[:space:]].*", .)),"",.) %>% trimws  
    }, warning = function(war) {
      print(paste("MY_WARNING:  ",war))
    }, error = function(err) {
      print(paste("MY_ERROR:  ",err))
    })
  
  ### pictures in description //example[124] or [126]
  pic_src = doc %>% xml_find_all(xpath) %>% xml_find_all('//img[@class="fit"]') %>% xml_attr("src")
  pic_srcs = "" 
  pic_srcs = paste(pic_src, collapse = ', ') # 把所有網址連接在一起
  pic_cnt = length(pic_src) %>% as.numeric
  if(pic_cnt==0) pic_srcs=NA

  ## support
  xpath = '//*[contains(concat( " ", @class, " " ), concat( " ", "pledge-selectable-sidebar", " " ))]'
  supports = doc %>% xml_find_all(xpath)
  sup_cnt = length(supports) %>% as.numeric
  
  ## Hidden Project
  Erroresult<- tryCatch(
    {
      xpath = '//*[(@id = "hidden_project")]'
      isHidden = xml_find_all(doc, xpath)
      if(length(isHidden)!=0){
        upd_cnt = NA
        cmt_cnt = NA
        img_src = NA
        desc = NA
        desc_about = NA
        desc_risksAndChallenges = NA
        pic_cnt = NA
        pic_srcs = NA
        sup_cnt = NA
      }
    }, warning = function(war) {
      print(paste("MY_WARNING:  ",war))
    }, error = function(err) {
      print(paste("MY_ERROR:  ",err))
    })

  # 存成data frame
  df = data.frame(
    purl = x,
    upd_cnt = upd_cnt,
    cmt_cnt = cmt_cnt,
    img_src = img_src,
    desc = desc,
    desc_about = desc_about,
    desc_risksAndChallenges = desc_risksAndChallenges,
    pic_cnt = pic_cnt,
    pic_srcs = pic_srcs,
    sup_cnt = sup_cnt
  )
}, project_url))

# View(project_info)

save(project_info, file="data/projectInfo.rdata")
"done"

update posts

upates = sapply(project_url,function(x){
  
  # print(x)
  upd=data.frame()
  # x = project_url[405]
  
  xpath = '//*[contains(concat( " ", @class, " " ), concat( " ", "project-nav__link--updates", " " ))]//*[contains(concat( " ", @class, " " ), concat( " ", "count", " " ))]'
  doc = read_html(x)
  upd_cnt = xml_text(xml_find_all(doc, xpath)) %>% as.numeric
  
  ## Hidden Project
  Erroresult<- tryCatch(
    {
      xpath = '//*[(@id = "hidden_project")]'
      isHidden = xml_find_all(doc, xpath)
      if(length(isHidden)!=0){
        upd_date = NA
        upd_title = NA
        upd_content = NA
        upd_cnt = 0
      }
    }, warning = function(war) {
      print(paste("MY_WARNING:  ",war))
    }, error = function(err) {
      print(paste("MY_ERROR hidden project:  ",err))
    })
  
  if(upd_cnt!=0){
    
    url = x %>% sub(".ref=.*","",.) %>% paste0("/updates")
    doc = read_html(url)
    
    xpath = '//*[contains(concat( " ", @class, " " ), concat( " ", "hover-target", " " ))]'
    upPosts = xml_find_all(doc, xpath)
    
    upPosts_date = upPosts %>% 
      xml_text %>% 
      regmatches(., regexpr("[[:upper:]][[:lower:]]* [[:digit:]]{1,2}, [[:digit:]]{4}", .)) %>% 
      trimws %>% as.character
      # strptime("%B %d, %Y") 
    
    upPosts_title = upPosts %>% 
      xml_find_all('//*[contains(concat( " ", @class, " " ), concat( " ", "grid-post__title", " " ))]') %>% 
      xml_text %>% trimws
    
    upPosts_content = upPosts %>% 
      xml_find_all('//div[@class = "grid-post__content"]') %>% 
      xml_text %>% trimws
    if(length(upPosts_content)==0){
      upPosts_content = NA
    }
    
    # 有些upd沒有content只有title
    if(length(upPosts_content)!=length(upPosts_title)){
      for(i in 1:(length(upPosts_title) - length(upPosts_content)) ){
        upPosts_content = append(upPosts_content, "")
      }
    }
    
    
    # 存成data frame
    upd = data.frame(
        purl = x,
        upd_date = upPosts_date,
        upd_title = upPosts_title,
        upd_content = upPosts_content
      )
    
    # insert data to DB
    updDB$insert(upd)
    
  } # end if 
})
updates = Reduce(rbind, lapply(project_url,function(x){
  
  # print(x)
  iter = iter+1
  upd=data.frame()

  # x = project_url[405]
  
  xpath = '//*[contains(concat( " ", @class, " " ), concat( " ", "project-nav__link--updates", " " ))]//*[contains(concat( " ", @class, " " ), concat( " ", "count", " " ))]'
  doc = read_html(x)
  upd_cnt = xml_text(xml_find_all(doc, xpath)) %>% as.numeric
  
  ## Hidden Project
  Erroresult<- tryCatch(
    {
      xpath = '//*[(@id = "hidden_project")]'
      isHidden = xml_find_all(doc, xpath)
      if(length(isHidden)!=0){
        upd_date = NA
        upd_title = NA
        upd_content = NA
        upd_cnt = 0
      }
    }, warning = function(war) {
      print(paste("MY_WARNING:  ",war))
    }, error = function(err) {
      print(paste("MY_ERROR hidden project:  ",err))
    })
  
  if(upd_cnt!=0){
    
    url = x %>% sub(".ref=.*","",.) %>% paste0("/updates")
    doc = read_html(url)
    
    xpath = '//*[contains(concat( " ", @class, " " ), concat( " ", "hover-target", " " ))]'
    upPosts = xml_find_all(doc, xpath)
    
    upPosts_date = upPosts %>% 
      xml_text %>% 
      regmatches(., regexpr("[[:upper:]][[:lower:]]* [[:digit:]]{1,2}, [[:digit:]]{4}", .)) %>% 
      trimws %>% as.character
      # strptime("%B %d, %Y") 
    
    upPosts_title = upPosts %>% 
      xml_find_all('//*[contains(concat( " ", @class, " " ), concat( " ", "grid-post__title", " " ))]') %>% 
      xml_text %>% trimws
    
    upPosts_content = upPosts %>% 
      xml_find_all('//div[@class = "grid-post__content"]') %>% 
      xml_text %>% trimws
    if(length(upPosts_content)==0){
      upPosts_content = NA
    }
    
    # 有些upd沒有content只有title
    if(length(upPosts_content)!=length(upPosts_title)){
      for(i in 1:(length(upPosts_title) - length(upPosts_content)) ){
        upPosts_content = append(upPosts_content, "")
      }
    }
    
    
    # 存成data frame
    
    upd = data.frame(
        purl = x,
        upd_date = upPosts_date,
        upd_title = upPosts_title,
        upd_content = upPosts_content
      )
  } # end if 
  
  return(upd)
}))

# View(updates)
save(updates, file="data/updateInfo.rdata")
"done"

supports

supports = Reduce(rbind, lapply(project_url,function(x){
  
  # print(x)
  sup = data.frame()
  # x = project_url[1321]
    
  doc = read_html(x)
  xpath = '//*[contains(concat( " ", @class, " " ), concat( " ", "pledge-selectable-sidebar", " " ))]'
  supports = doc %>% xml_find_all(xpath)
  sup_cnt = length(supports) %>% as.numeric
  
  ## Hidden Project
  Erroresult<- tryCatch(
    {
      xpath = '//*[(@id = "hidden_project")]'
      isHidden = xml_find_all(doc, xpath)
      
      if(length(isHidden)!=0){
        sup_amounts = NA
        sup_desc = NA
        sup_extraInfo = NA
        sup_baker = NA
        sup_cnt=0
      }
    }, warning = function(war) {
      print(paste("MY_WARNING:  ",war))
    }, error = function(err) {
      print(paste("MY_ERROR hidden project:  ",err))
    })
  
  if(sup_cnt!=0){
      
    sup_amounts = supports %>% 
      xml_find_all('//h2[@class="pledge__amount"]') %>% 
      xml_text %>% trimws
    sup_desc = supports %>% 
      xml_find_all('//div[@class="pledge__reward-description pledge__reward-description--expanded"]') %>% 
      xml_text %>% trimws
    sup_extraInfo = supports %>% 
      xml_find_all('//div[@class="pledge__extra-info"]') %>% 
      xml_text %>% trimws
    sup_baker = supports %>% 
      xml_find_all('//*[contains(concat( " ", @class, " " ), concat( " ", "pledge__backer-count", " " ))]') %>% 
      xml_text %>% regmatches(., regexpr("[[:digit:]]+", .)) %>% as.numeric
      
    # 存成data frame
    sup = data.frame(
        purl = x,
        sup_amounts = sup_amounts,
        sup_desc = sup_desc,
        sup_extraInfo = sup_extraInfo,
        sup_baker = sup_baker
      )
    } # end if 
    
    return(sup)
  }))

# View(supports)
save(supports, file="data/supportInfo.rdata")
"done"



creator biography可讀性

# ra_bio = with(all_bio, readability(bio, url))
# ra_bio
# summary(ra_bio)
LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQo8YnI+DQpbZGF0YSBzb3VyY2VdKGh0dHBzOi8vd2Vicm9ib3RzLmlvL2tpY2tzdGFydGVyLWRhdGFzZXRzLykgDQoNCi0tLQ0KPGJyPiA8YnI+IDxocj4NCiMjIGNvbm5lY3QgdG8gTW9uZ29EQg0KYGBge3J9DQojIGluc3RhbGwucGFja2FnZXMoIlJ0b29scyIpDQojIGluc3RhbGwucGFja2FnZXMoImRldnRvb2xzIikNCiMgbGlicmFyeShkZXZ0b29scykNCiMgaW5zdGFsbC5wYWNrYWdlcygickphdmEiKQ0KIyBTeXMuc2V0ZW52KEpBVkFfSE9NRT0iQzovUHJvZ3JhbSBGaWxlcy9KYXZhL2pkay0xMS4wLjEvIikNCiMgbGlicmFyeShySmF2YSkNCiMgaW5zdGFsbC5wYWNrYWdlcygiUk1vbmdvIikNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoUk1vbmdvKQ0KbW9uZ28gPSBtb25nb0RiQ29ubmVjdCgiS2lja3N0YXJ0ZXIiKQ0KZGJTaG93Q29sbGVjdGlvbnMobW9uZ28pDQpxdWVyeSA8LSBkYkdldFF1ZXJ5KG1vbmdvLCAncmF3ZGF0YScsICIiKQ0KDQojIOaKimNyZWF0b3JfaW5mb+i9iWpzb27lho3lrZjpgLLljrsNCmxpYnJhcnkocmpzb24pDQpjcnRfanNvbiA9IHRvSlNPTihjcmVhdG9yX2luZm9bMSxdKQ0KDQojIGluc2VydCBkYXRhIGluIG1vbmdvDQpvdXRwdXQgPC0gZGJJbnNlcnREb2N1bWVudChtb25nbywgInRlc3RfZGF0YSIsIGNydF9qc29uKSAgDQpvdXRwdXQgPC0gZGJHZXRRdWVyeShtb25nbywgJ3Jhd2RhdGEnLCAne30nKQ0Kb3V0cHV0DQoNCg0KIyBkYkRpc2Nvbm5lY3QobW9uZ28pDQpgYGANCg0KbW9uZ29saXRlDQpgYGB7cn0NCmxpYnJhcnkoIm1vbmdvbGl0ZSIpDQpyYXdkYXRhREIgPSBtb25nbyhjb2xsZWN0aW9uID0gInJhd2RhdGEiLCBkYiA9ICJLaWNrc3RhcnRlciIpICMgY3JlYXRlIGNvbm5lY3Rpb24sIGRhdGFiYXNlIGFuZCBjb2xsZWN0aW9uDQpyYXdkYXRhREIkY291bnQNCmBgYA0KDQoNCi0tLQ0KPGJyPiA8YnI+IDxocj4NCiMjIFN0YXJ0IHRvIGNyYXdsDQpgYGB7ciBtZXNzYWdlPUZBTFNFfQ0KbGlicmFyeSh4bWwyKQ0KbGlicmFyeShYTUwpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShSU2VsZW5pdW0pDQoNCmxvYWQoImRhdGEvcmF3ZGF0YS5yZGF0YSIpDQpgYGANCg0KDQojIyMjIGxvYWQNCmBgYHtyfQ0KIyBsb2FkKCJkYXRhL2NyZWF0b3JJbmZvLnJkYXRhIikNCiMgbG9hZCgiZGF0YS9wcm9qZWN0SW5mby5yZGF0YSIpDQojIGxvYWQoImRhdGEvdXBkYXRlSW5mby5yZGF0YSIpDQojIGxvYWQoImRhdGEvc3VwcG9ydEluZm8ucmRhdGEiKQ0KYGBgDQoNCiMjIyBDcmVhdG9yIEluZm9ybWF0aW9uDQoNCmBgYHtyfQ0KY3JlYXRvcl9pbmZvID0gUmVkdWNlKHJiaW5kLCBNYXAoZnVuY3Rpb24oeCl7DQoNCiAgIyB4ID0gY3JlYXRvcl9pZFsxNF0NCiAgdXJsID0gcGFzdGUwKCJodHRwczovL3d3dy5raWNrc3RhcnRlci5jb20vcHJvZmlsZS8iLCB4LCAiL2Fib3V0IikNCiAgIyB1cmwgPSAiaHR0cHM6Ly93d3cua2lja3N0YXJ0ZXIuY29tL3Byb2ZpbGUvNzk1MzY4NDY0L2Fib3V0Ig0KICBkb2MgPSByZWFkX2h0bWwodXJsKQ0KICANCiAgIyMgYmlvZ3JhcGh5DQogIHhwYXRoID0gJy8vKlsoQGlkID0gImNvbnRlbnQiKV0vL3AnDQogIGJpbyA9IHBhc3RlMCgiIix4bWxfdGV4dCh4bWxfZmluZF9hbGwoZG9jLCB4cGF0aCkpKQ0KICBiaW8gPSBnc3ViKCJcbiIsICIiLCBiaW9bMl0pICAgICAgIyDljrvpmaTmj5vooYzlj4rliY3lvoznqbrnmb0NCiAgYmlvID0gZ3N1YigiXlxcc3xcXHMkIiwgIiIsIGJpbykNCiAgaWYoaXMubmEoYmlvKSkgYmlvPU5BDQogIA0KICAjIyB3ZWJzaXRlcw0KICB4cGF0aCA9ICcvLypbKEBpZCA9ICJjb250ZW50IildLy9hJw0KICB3ZWJzaXRlcyA9IHBhc3RlMCgiIix4bWxfYXR0cih4bWxfZmluZF9hbGwoZG9jLCB4cGF0aCksICJocmVmIikpDQogIHdlYnNpdGVzID0gZ3N1YigiXG4iLCAiIiwgd2Vic2l0ZXMpICAgICAgIyDljrvpmaTmj5vooYzlj4rliY3lvoznqbrnmb0NCiAgd2Vic2l0ZXMgPSBnc3ViKCJeXFxzfFxccyQiLCAiIiwgd2Vic2l0ZXMpDQogIA0KICB3ZWJzID0gIiIgDQogIHdlYnMgPSBwYXN0ZSh3ZWJzaXRlcywgY29sbGFwc2UgPSAnLCAnKSAjIOaKiuaJgOaciee2suWdgOmAo+aOpeWcqOS4gOi1tw0KDQogICMjIGJhY2tlZCBwcm9qZWN0IGNvdW50DQogIHhwYXRoID0gJy8vc3BhbltAY2xhc3M9ImJhY2tlZCJdJw0KICBiYWNrZWQgPSB4bWxfdGV4dCh4bWxfZmluZF9hbGwoZG9jLCB4cGF0aCkpICU+JSByZWdtYXRjaGVzKC4sIHJlZ2V4cHIoIltbOmRpZ2l0Ol1dIiwgLikpICU+JSB0cmltd3MNCiAgaWYobGVuZ3RoKGJhY2tlZCk9PTApIGJhY2tlZD1OQQ0KICANCiAgIyMgY3JlYXRlZCBwcm9qZWN0IGNvdW50DQogIHhwYXRoID0gJy8vc3BhbltAY2xhc3M9ImNvdW50Il0nDQogIGNyZWF0ZWQgPSB4bWxfdGV4dCh4bWxfZmluZF9hbGwoZG9jLCB4cGF0aClbMV0pICU+JSByZWdtYXRjaGVzKC4sIHJlZ2V4cHIoIltbOmRpZ2l0Ol1dIiwgLikpICU+JSB0cmltd3MNCiAgaWYobGVuZ3RoKGNyZWF0ZWQpPT0wKSBjcmVhdGVkPU5BDQogIA0KICAjIOWtmOaIkGRhdGEgZnJhbWUNCiAgZGYgPSBkYXRhLmZyYW1lKGNpZCA9IHgsIA0KICAgICAgICAgICAgICAgICAgYmlvZ3JhcGh5ID0gYmlvLCANCiAgICAgICAgICAgICAgICAgIHdlYnNpdGVzID0gd2VicywgDQogICAgICAgICAgICAgICAgICBiYWNrZWQgPSBiYWNrZWQsDQogICAgICAgICAgICAgICAgICBjcmVhdGVkID0gY3JlYXRlZCkNCn0sIGNyZWF0b3JfaWQpKQ0KDQojIFZpZXcoY3JlYXRvcl9pbmZvKQ0KDQpzYXZlKGNyZWF0b3JfaW5mbywgZmlsZT0iZGF0YS9jcmVhdG9ySW5mby5yZGF0YSIpDQoiZG9uZSINCmBgYA0KDQoNCiMjIyBwcm9qZWN0IGluZm9ybWF0aW9uDQpgYGB7cn0NCml0ZXIgPSAwDQpwcm9qZWN0X2luZm8gPSBSZWR1Y2UocmJpbmQsIE1hcChmdW5jdGlvbih4KXsNCiAgDQogICMgeD0iaHR0cHM6Ly93d3cua2lja3N0YXJ0ZXIuY29tL3Byb2plY3RzLzE4NzA0NzY0NzAvdG9tYi1vZi1ob3Jyb3Itdm9sLTItaG9ycm9yLWFudGhvbG9neT9yZWY9Y2F0ZWdvcnlfbmV3ZXN0Ig0KICANCiAgaXRlciA9IGl0ZXIrMQ0KICBkb2MgPSByZWFkX2h0bWwoeCkNCiAgDQogICMjIHVwZGF0ZXMgY291bnQNCiAgeHBhdGggPSAnLy8qW2NvbnRhaW5zKGNvbmNhdCggIiAiLCBAY2xhc3MsICIgIiApLCBjb25jYXQoICIgIiwgInByb2plY3QtbmF2X19saW5rLS11cGRhdGVzIiwgIiAiICkpXS8vKltjb250YWlucyhjb25jYXQoICIgIiwgQGNsYXNzLCAiICIgKSwgY29uY2F0KCAiICIsICJjb3VudCIsICIgIiApKV0nDQogIHVwZF9jbnQgPSB4bWxfdGV4dCh4bWxfZmluZF9hbGwoZG9jLCB4cGF0aCkpICU+JSBhcy5udW1lcmljDQogIA0KICAjIyBjb21tZW50cyBjb3VudCANCiAgeHBhdGggPSAnLy8qW2NvbnRhaW5zKGNvbmNhdCggIiAiLCBAY2xhc3MsICIgIiApLCBjb25jYXQoICIgIiwgInByb2plY3QtbmF2X19saW5rLS1jb21tZW50cyIsICIgIiApKV0nDQogIGNtdF9jbnQgPSB4bWxfZmluZF9hbGwoZG9jLCB4cGF0aCkgJT4lIA0KICAgIHhtbF90ZXh0ICU+JSANCiAgICByZWdtYXRjaGVzKC4sIHJlZ2V4cHIoIltbOmRpZ2l0Ol1dIiwgLikpICU+JQ0KICAgIHRyaW13cyAlPiUNCiAgICBhcy5udW1lcmljDQogIA0KICAjIyBwcm9qZWN0IGltYWdlDQogIHhwYXRoPScvL2ltZ1tjb250YWlucyhjb25jYXQoICIgIiwgQGNsYXNzLCAiICIgKSwgY29uY2F0KCAiICIsICJhc3BlY3QtcmF0aW8tLW9iamVjdCIsICIgIiApKV0nDQogIGltZ19zcmMgPSBkb2MgJT4lIHhtbF9maW5kX2FsbCh4cGF0aCkgJT4lIHhtbF9hdHRyKCJzcmMiKQ0KICBpZihsZW5ndGgoaW1nX3NyYyk9PTApIGltZ19zcmM9TkENCiAgDQogICMjIERlc2NyaXB0aW9uDQogIHhwYXRoPScvLypbY29udGFpbnMoY29uY2F0KCAiICIsIEBjbGFzcywgIiAiICksIGNvbmNhdCggIiAiLCAiZGVzY3JpcHRpb24tY29udGFpbmVyIiwgIiAiICkpXScNCiAgZGVzYyA9IGRvYyAlPiUgDQogICAgeG1sX2ZpbmRfYWxsKHhwYXRoKSAlPiUgDQogICAgeG1sX3RleHQgJT4lIA0KICAgIHN1YigiXFxzTGVhcm4gYWJvdXQgYWNjb3VudGFiaWxpdHkgb24gS2lja3N0YXJ0ZXIiLCIiLC4pICU+JSAgICAjIOWOu+mZpOacgOS4i+mdoueahOi0heWtlw0KICAgIHN1YigiXFxzUXVlc3Rpb25zIGFib3V0IHRoaXMgcHJvamVjdFxcPyIsIiIsLikgJT4lIA0KICAgIHN1YigiQ2hlY2sgb3V0IHRoZSBGQVEiLCIiLC4pICU+JSANCiAgICBzdWIoIlxcc1JlcG9ydCB0aGlzIHByb2plY3QgdG8gS2lja3N0YXJ0ZXIiLCIiLC4pICU+JSANCiAgICB0cmltd3MNCiAgDQogICMjIyBSaXNrcyBhbmQgY2hhbGxlbmdlcw0KICBkZXNjX3Jpc2tzQW5kQ2hhbGxlbmdlcyA9IGRlc2MgJT4lIHJlZ21hdGNoZXMoLiwgcmVnZXhwcigiUmlza3MgYW5kIGNoYWxsZW5nZXNbWzpzcGFjZTpdXS4qIiwgLikpICU+JQ0KICAgIHN1YigiUmlza3MgYW5kIGNoYWxsZW5nZXMiLCIiLC4pICU+JSB0cmltd3MNCiAgaWYobGVuZ3RoKGRlc2Nfcmlza3NBbmRDaGFsbGVuZ2VzKT09MCkgZGVzY19yaXNrc0FuZENoYWxsZW5nZXM9TkENCiAgIyMjIEFib3V0DQogIGRlc2NfYWJvdXQgPSBkZXNjICU+JSANCiAgICByZWdtYXRjaGVzKC4sIHJlZ2V4cHIoIkFib3V0W1s6c3BhY2U6XV0uKiIsIC4pKSAlPiUNCiAgICBzdWIoIkFib3V0IiwiIiwuKSAlPiUgdHJpbXdzDQogIEVycm9yZXN1bHQ8LSB0cnlDYXRjaCggICAgICAgICAgICAgICAgICAjIOWmguaenOaykuaciVJpc2tzIGFuZCBjaGFsbGVuZ2VzDQogICAgew0KICAgICAgZGVzY19hYm91dCA9IGRlc2NfYWJvdXQgJT4lIHN1YihyZWdtYXRjaGVzKC4sIHJlZ2V4cHIoIlJpc2tzIGFuZCBjaGFsbGVuZ2VzW1s6c3BhY2U6XV0uKiIsIC4pKSwiIiwuKSAlPiUgdHJpbXdzICANCiAgICB9LCB3YXJuaW5nID0gZnVuY3Rpb24od2FyKSB7DQogICAgICBwcmludChwYXN0ZSgiTVlfV0FSTklORzogICIsd2FyKSkNCiAgICB9LCBlcnJvciA9IGZ1bmN0aW9uKGVycikgew0KICAgICAgcHJpbnQocGFzdGUoIk1ZX0VSUk9SOiAgIixlcnIpKQ0KICAgIH0pDQogIA0KICAjIyMgcGljdHVyZXMgaW4gZGVzY3JpcHRpb24gLy9leGFtcGxlWzEyNF0gb3IgWzEyNl0NCiAgcGljX3NyYyA9IGRvYyAlPiUgeG1sX2ZpbmRfYWxsKHhwYXRoKSAlPiUgeG1sX2ZpbmRfYWxsKCcvL2ltZ1tAY2xhc3M9ImZpdCJdJykgJT4lIHhtbF9hdHRyKCJzcmMiKQ0KICBwaWNfc3JjcyA9ICIiIA0KICBwaWNfc3JjcyA9IHBhc3RlKHBpY19zcmMsIGNvbGxhcHNlID0gJywgJykgIyDmiormiYDmnInntrLlnYDpgKPmjqXlnKjkuIDotbcNCiAgcGljX2NudCA9IGxlbmd0aChwaWNfc3JjKSAlPiUgYXMubnVtZXJpYw0KICBpZihwaWNfY250PT0wKSBwaWNfc3Jjcz1OQQ0KDQogICMjIHN1cHBvcnQNCiAgeHBhdGggPSAnLy8qW2NvbnRhaW5zKGNvbmNhdCggIiAiLCBAY2xhc3MsICIgIiApLCBjb25jYXQoICIgIiwgInBsZWRnZS1zZWxlY3RhYmxlLXNpZGViYXIiLCAiICIgKSldJw0KICBzdXBwb3J0cyA9IGRvYyAlPiUgeG1sX2ZpbmRfYWxsKHhwYXRoKQ0KICBzdXBfY250ID0gbGVuZ3RoKHN1cHBvcnRzKSAlPiUgYXMubnVtZXJpYw0KICANCiAgIyMgSGlkZGVuIFByb2plY3QNCiAgRXJyb3Jlc3VsdDwtIHRyeUNhdGNoKA0KICAgIHsNCiAgICAgIHhwYXRoID0gJy8vKlsoQGlkID0gImhpZGRlbl9wcm9qZWN0IildJw0KICAgICAgaXNIaWRkZW4gPSB4bWxfZmluZF9hbGwoZG9jLCB4cGF0aCkNCiAgICAgIGlmKGxlbmd0aChpc0hpZGRlbikhPTApew0KICAgICAgICB1cGRfY250ID0gTkENCiAgICAgICAgY210X2NudCA9IE5BDQogICAgICAgIGltZ19zcmMgPSBOQQ0KICAgICAgICBkZXNjID0gTkENCiAgICAgICAgZGVzY19hYm91dCA9IE5BDQogICAgICAgIGRlc2Nfcmlza3NBbmRDaGFsbGVuZ2VzID0gTkENCiAgICAgICAgcGljX2NudCA9IE5BDQogICAgICAgIHBpY19zcmNzID0gTkENCiAgICAgICAgc3VwX2NudCA9IE5BDQogICAgICB9DQogICAgfSwgd2FybmluZyA9IGZ1bmN0aW9uKHdhcikgew0KICAgICAgcHJpbnQocGFzdGUoIk1ZX1dBUk5JTkc6ICAiLHdhcikpDQogICAgfSwgZXJyb3IgPSBmdW5jdGlvbihlcnIpIHsNCiAgICAgIHByaW50KHBhc3RlKCJNWV9FUlJPUjogICIsZXJyKSkNCiAgICB9KQ0KDQogICMg5a2Y5oiQZGF0YSBmcmFtZQ0KICBkZiA9IGRhdGEuZnJhbWUoDQogICAgcHVybCA9IHgsDQogICAgdXBkX2NudCA9IHVwZF9jbnQsDQogICAgY210X2NudCA9IGNtdF9jbnQsDQogICAgaW1nX3NyYyA9IGltZ19zcmMsDQogICAgZGVzYyA9IGRlc2MsDQogICAgZGVzY19hYm91dCA9IGRlc2NfYWJvdXQsDQogICAgZGVzY19yaXNrc0FuZENoYWxsZW5nZXMgPSBkZXNjX3Jpc2tzQW5kQ2hhbGxlbmdlcywNCiAgICBwaWNfY250ID0gcGljX2NudCwNCiAgICBwaWNfc3JjcyA9IHBpY19zcmNzLA0KICAgIHN1cF9jbnQgPSBzdXBfY250DQogICkNCn0sIHByb2plY3RfdXJsKSkNCg0KIyBWaWV3KHByb2plY3RfaW5mbykNCg0Kc2F2ZShwcm9qZWN0X2luZm8sIGZpbGU9ImRhdGEvcHJvamVjdEluZm8ucmRhdGEiKQ0KImRvbmUiDQpgYGANCg0KIyMjIyB1cGRhdGUgcG9zdHMNCg0KYGBge3J9DQp1cGREQiA9IG1vbmdvKGNvbGxlY3Rpb24gPSAidXBkYXRlcyIsIGRiID0gIktpY2tzdGFydGVyIikgIyBjcmVhdGUgY29ubmVjdGlvbiwgZGF0YWJhc2UgYW5kIGNvbGxlY3Rpb24NCnVwZERCJGNvdW50KCkNCmBgYA0KDQpgYGB7cn0NCnVwYXRlcyA9IHNhcHBseShwcm9qZWN0X3VybCxmdW5jdGlvbih4KXsNCiAgDQogICMgcHJpbnQoeCkNCiAgdXBkPWRhdGEuZnJhbWUoKQ0KICAjIHggPSBwcm9qZWN0X3VybFs0MDVdDQogIA0KICB4cGF0aCA9ICcvLypbY29udGFpbnMoY29uY2F0KCAiICIsIEBjbGFzcywgIiAiICksIGNvbmNhdCggIiAiLCAicHJvamVjdC1uYXZfX2xpbmstLXVwZGF0ZXMiLCAiICIgKSldLy8qW2NvbnRhaW5zKGNvbmNhdCggIiAiLCBAY2xhc3MsICIgIiApLCBjb25jYXQoICIgIiwgImNvdW50IiwgIiAiICkpXScNCiAgZG9jID0gcmVhZF9odG1sKHgpDQogIHVwZF9jbnQgPSB4bWxfdGV4dCh4bWxfZmluZF9hbGwoZG9jLCB4cGF0aCkpICU+JSBhcy5udW1lcmljDQogIA0KICAjIyBIaWRkZW4gUHJvamVjdA0KICBFcnJvcmVzdWx0PC0gdHJ5Q2F0Y2goDQogICAgew0KICAgICAgeHBhdGggPSAnLy8qWyhAaWQgPSAiaGlkZGVuX3Byb2plY3QiKV0nDQogICAgICBpc0hpZGRlbiA9IHhtbF9maW5kX2FsbChkb2MsIHhwYXRoKQ0KICAgICAgaWYobGVuZ3RoKGlzSGlkZGVuKSE9MCl7DQogICAgICAgIHVwZF9kYXRlID0gTkENCiAgICAgICAgdXBkX3RpdGxlID0gTkENCiAgICAgICAgdXBkX2NvbnRlbnQgPSBOQQ0KICAgICAgICB1cGRfY250ID0gMA0KICAgICAgfQ0KICAgIH0sIHdhcm5pbmcgPSBmdW5jdGlvbih3YXIpIHsNCiAgICAgIHByaW50KHBhc3RlKCJNWV9XQVJOSU5HOiAgIix3YXIpKQ0KICAgIH0sIGVycm9yID0gZnVuY3Rpb24oZXJyKSB7DQogICAgICBwcmludChwYXN0ZSgiTVlfRVJST1IgaGlkZGVuIHByb2plY3Q6ICAiLGVycikpDQogICAgfSkNCiAgDQogIGlmKHVwZF9jbnQhPTApew0KICAgIA0KICAgIHVybCA9IHggJT4lIHN1YigiLnJlZj0uKiIsIiIsLikgJT4lIHBhc3RlMCgiL3VwZGF0ZXMiKQ0KICAgIGRvYyA9IHJlYWRfaHRtbCh1cmwpDQogICAgDQogICAgeHBhdGggPSAnLy8qW2NvbnRhaW5zKGNvbmNhdCggIiAiLCBAY2xhc3MsICIgIiApLCBjb25jYXQoICIgIiwgImhvdmVyLXRhcmdldCIsICIgIiApKV0nDQogICAgdXBQb3N0cyA9IHhtbF9maW5kX2FsbChkb2MsIHhwYXRoKQ0KICAgIA0KICAgIHVwUG9zdHNfZGF0ZSA9IHVwUG9zdHMgJT4lIA0KICAgICAgeG1sX3RleHQgJT4lIA0KICAgICAgcmVnbWF0Y2hlcyguLCByZWdleHByKCJbWzp1cHBlcjpdXVtbOmxvd2VyOl1dKiBbWzpkaWdpdDpdXXsxLDJ9LCBbWzpkaWdpdDpdXXs0fSIsIC4pKSAlPiUgDQogICAgICB0cmltd3MgJT4lIGFzLmNoYXJhY3Rlcg0KICAgICAgIyBzdHJwdGltZSgiJUIgJWQsICVZIikgDQogICAgDQogICAgdXBQb3N0c190aXRsZSA9IHVwUG9zdHMgJT4lIA0KICAgICAgeG1sX2ZpbmRfYWxsKCcvLypbY29udGFpbnMoY29uY2F0KCAiICIsIEBjbGFzcywgIiAiICksIGNvbmNhdCggIiAiLCAiZ3JpZC1wb3N0X190aXRsZSIsICIgIiApKV0nKSAlPiUgDQogICAgICB4bWxfdGV4dCAlPiUgdHJpbXdzDQogICAgDQogICAgdXBQb3N0c19jb250ZW50ID0gdXBQb3N0cyAlPiUgDQogICAgICB4bWxfZmluZF9hbGwoJy8vZGl2W0BjbGFzcyA9ICJncmlkLXBvc3RfX2NvbnRlbnQiXScpICU+JSANCiAgICAgIHhtbF90ZXh0ICU+JSB0cmltd3MNCiAgICBpZihsZW5ndGgodXBQb3N0c19jb250ZW50KT09MCl7DQogICAgICB1cFBvc3RzX2NvbnRlbnQgPSBOQQ0KICAgIH0NCiAgICANCiAgICAjIOacieS6m3VwZOaykuaciWNvbnRlbnTlj6rmnIl0aXRsZQ0KICAgIGlmKGxlbmd0aCh1cFBvc3RzX2NvbnRlbnQpIT1sZW5ndGgodXBQb3N0c190aXRsZSkpew0KICAgICAgZm9yKGkgaW4gMToobGVuZ3RoKHVwUG9zdHNfdGl0bGUpIC0gbGVuZ3RoKHVwUG9zdHNfY29udGVudCkpICl7DQogICAgICAgIHVwUG9zdHNfY29udGVudCA9IGFwcGVuZCh1cFBvc3RzX2NvbnRlbnQsICIiKQ0KICAgICAgfQ0KICAgIH0NCiAgICANCiAgICANCiAgICAjIOWtmOaIkGRhdGEgZnJhbWUNCiAgICB1cGQgPSBkYXRhLmZyYW1lKA0KICAgICAgICBwdXJsID0geCwNCiAgICAgICAgdXBkX2RhdGUgPSB1cFBvc3RzX2RhdGUsDQogICAgICAgIHVwZF90aXRsZSA9IHVwUG9zdHNfdGl0bGUsDQogICAgICAgIHVwZF9jb250ZW50ID0gdXBQb3N0c19jb250ZW50DQogICAgICApDQogICAgDQogICAgIyBpbnNlcnQgZGF0YSB0byBEQg0KICAgIHVwZERCJGluc2VydCh1cGQpDQogICAgDQogIH0gIyBlbmQgaWYgDQp9KQ0KYGBgDQoNCg0KYGBge3J9DQp1cGRhdGVzID0gUmVkdWNlKHJiaW5kLCBsYXBwbHkocHJvamVjdF91cmwsZnVuY3Rpb24oeCl7DQogIA0KICAjIHByaW50KHgpDQogIGl0ZXIgPSBpdGVyKzENCiAgdXBkPWRhdGEuZnJhbWUoKQ0KDQogICMgeCA9IHByb2plY3RfdXJsWzQwNV0NCiAgDQogIHhwYXRoID0gJy8vKltjb250YWlucyhjb25jYXQoICIgIiwgQGNsYXNzLCAiICIgKSwgY29uY2F0KCAiICIsICJwcm9qZWN0LW5hdl9fbGluay0tdXBkYXRlcyIsICIgIiApKV0vLypbY29udGFpbnMoY29uY2F0KCAiICIsIEBjbGFzcywgIiAiICksIGNvbmNhdCggIiAiLCAiY291bnQiLCAiICIgKSldJw0KICBkb2MgPSByZWFkX2h0bWwoeCkNCiAgdXBkX2NudCA9IHhtbF90ZXh0KHhtbF9maW5kX2FsbChkb2MsIHhwYXRoKSkgJT4lIGFzLm51bWVyaWMNCiAgDQogICMjIEhpZGRlbiBQcm9qZWN0DQogIEVycm9yZXN1bHQ8LSB0cnlDYXRjaCgNCiAgICB7DQogICAgICB4cGF0aCA9ICcvLypbKEBpZCA9ICJoaWRkZW5fcHJvamVjdCIpXScNCiAgICAgIGlzSGlkZGVuID0geG1sX2ZpbmRfYWxsKGRvYywgeHBhdGgpDQogICAgICBpZihsZW5ndGgoaXNIaWRkZW4pIT0wKXsNCiAgICAgICAgdXBkX2RhdGUgPSBOQQ0KICAgICAgICB1cGRfdGl0bGUgPSBOQQ0KICAgICAgICB1cGRfY29udGVudCA9IE5BDQogICAgICAgIHVwZF9jbnQgPSAwDQogICAgICB9DQogICAgfSwgd2FybmluZyA9IGZ1bmN0aW9uKHdhcikgew0KICAgICAgcHJpbnQocGFzdGUoIk1ZX1dBUk5JTkc6ICAiLHdhcikpDQogICAgfSwgZXJyb3IgPSBmdW5jdGlvbihlcnIpIHsNCiAgICAgIHByaW50KHBhc3RlKCJNWV9FUlJPUiBoaWRkZW4gcHJvamVjdDogICIsZXJyKSkNCiAgICB9KQ0KICANCiAgaWYodXBkX2NudCE9MCl7DQogICAgDQogICAgdXJsID0geCAlPiUgc3ViKCIucmVmPS4qIiwiIiwuKSAlPiUgcGFzdGUwKCIvdXBkYXRlcyIpDQogICAgZG9jID0gcmVhZF9odG1sKHVybCkNCiAgICANCiAgICB4cGF0aCA9ICcvLypbY29udGFpbnMoY29uY2F0KCAiICIsIEBjbGFzcywgIiAiICksIGNvbmNhdCggIiAiLCAiaG92ZXItdGFyZ2V0IiwgIiAiICkpXScNCiAgICB1cFBvc3RzID0geG1sX2ZpbmRfYWxsKGRvYywgeHBhdGgpDQogICAgDQogICAgdXBQb3N0c19kYXRlID0gdXBQb3N0cyAlPiUgDQogICAgICB4bWxfdGV4dCAlPiUgDQogICAgICByZWdtYXRjaGVzKC4sIHJlZ2V4cHIoIltbOnVwcGVyOl1dW1s6bG93ZXI6XV0qIFtbOmRpZ2l0Ol1dezEsMn0sIFtbOmRpZ2l0Ol1dezR9IiwgLikpICU+JSANCiAgICAgIHRyaW13cyAlPiUgYXMuY2hhcmFjdGVyDQogICAgICAjIHN0cnB0aW1lKCIlQiAlZCwgJVkiKSANCiAgICANCiAgICB1cFBvc3RzX3RpdGxlID0gdXBQb3N0cyAlPiUgDQogICAgICB4bWxfZmluZF9hbGwoJy8vKltjb250YWlucyhjb25jYXQoICIgIiwgQGNsYXNzLCAiICIgKSwgY29uY2F0KCAiICIsICJncmlkLXBvc3RfX3RpdGxlIiwgIiAiICkpXScpICU+JSANCiAgICAgIHhtbF90ZXh0ICU+JSB0cmltd3MNCiAgICANCiAgICB1cFBvc3RzX2NvbnRlbnQgPSB1cFBvc3RzICU+JSANCiAgICAgIHhtbF9maW5kX2FsbCgnLy9kaXZbQGNsYXNzID0gImdyaWQtcG9zdF9fY29udGVudCJdJykgJT4lIA0KICAgICAgeG1sX3RleHQgJT4lIHRyaW13cw0KICAgIGlmKGxlbmd0aCh1cFBvc3RzX2NvbnRlbnQpPT0wKXsNCiAgICAgIHVwUG9zdHNfY29udGVudCA9IE5BDQogICAgfQ0KICAgIA0KICAgICMg5pyJ5LqbdXBk5rKS5pyJY29udGVudOWPquaciXRpdGxlDQogICAgaWYobGVuZ3RoKHVwUG9zdHNfY29udGVudCkhPWxlbmd0aCh1cFBvc3RzX3RpdGxlKSl7DQogICAgICBmb3IoaSBpbiAxOihsZW5ndGgodXBQb3N0c190aXRsZSkgLSBsZW5ndGgodXBQb3N0c19jb250ZW50KSkgKXsNCiAgICAgICAgdXBQb3N0c19jb250ZW50ID0gYXBwZW5kKHVwUG9zdHNfY29udGVudCwgIiIpDQogICAgICB9DQogICAgfQ0KICAgIA0KICAgIA0KICAgICMg5a2Y5oiQZGF0YSBmcmFtZQ0KICAgIA0KICAgIHVwZCA9IGRhdGEuZnJhbWUoDQogICAgICAgIHB1cmwgPSB4LA0KICAgICAgICB1cGRfZGF0ZSA9IHVwUG9zdHNfZGF0ZSwNCiAgICAgICAgdXBkX3RpdGxlID0gdXBQb3N0c190aXRsZSwNCiAgICAgICAgdXBkX2NvbnRlbnQgPSB1cFBvc3RzX2NvbnRlbnQNCiAgICAgICkNCiAgfSAjIGVuZCBpZiANCiAgDQogIHJldHVybih1cGQpDQp9KSkNCg0KIyBWaWV3KHVwZGF0ZXMpDQpzYXZlKHVwZGF0ZXMsIGZpbGU9ImRhdGEvdXBkYXRlSW5mby5yZGF0YSIpDQoiZG9uZSINCmBgYA0KDQoNCiMjIyBzdXBwb3J0cw0KDQpgYGB7cn0NCnN1cHBvcnRzID0gUmVkdWNlKHJiaW5kLCBsYXBwbHkocHJvamVjdF91cmwsZnVuY3Rpb24oeCl7DQogIA0KICAjIHByaW50KHgpDQogIHN1cCA9IGRhdGEuZnJhbWUoKQ0KICAjIHggPSBwcm9qZWN0X3VybFsxMzIxXQ0KICAgIA0KICBkb2MgPSByZWFkX2h0bWwoeCkNCiAgeHBhdGggPSAnLy8qW2NvbnRhaW5zKGNvbmNhdCggIiAiLCBAY2xhc3MsICIgIiApLCBjb25jYXQoICIgIiwgInBsZWRnZS1zZWxlY3RhYmxlLXNpZGViYXIiLCAiICIgKSldJw0KICBzdXBwb3J0cyA9IGRvYyAlPiUgeG1sX2ZpbmRfYWxsKHhwYXRoKQ0KICBzdXBfY250ID0gbGVuZ3RoKHN1cHBvcnRzKSAlPiUgYXMubnVtZXJpYw0KICANCiAgIyMgSGlkZGVuIFByb2plY3QNCiAgRXJyb3Jlc3VsdDwtIHRyeUNhdGNoKA0KICAgIHsNCiAgICAgIHhwYXRoID0gJy8vKlsoQGlkID0gImhpZGRlbl9wcm9qZWN0IildJw0KICAgICAgaXNIaWRkZW4gPSB4bWxfZmluZF9hbGwoZG9jLCB4cGF0aCkNCiAgICAgIA0KICAgICAgaWYobGVuZ3RoKGlzSGlkZGVuKSE9MCl7DQogICAgICAgIHN1cF9hbW91bnRzID0gTkENCiAgICAgICAgc3VwX2Rlc2MgPSBOQQ0KICAgICAgICBzdXBfZXh0cmFJbmZvID0gTkENCiAgICAgICAgc3VwX2Jha2VyID0gTkENCiAgICAgICAgc3VwX2NudD0wDQogICAgICB9DQogICAgfSwgd2FybmluZyA9IGZ1bmN0aW9uKHdhcikgew0KICAgICAgcHJpbnQocGFzdGUoIk1ZX1dBUk5JTkc6ICAiLHdhcikpDQogICAgfSwgZXJyb3IgPSBmdW5jdGlvbihlcnIpIHsNCiAgICAgIHByaW50KHBhc3RlKCJNWV9FUlJPUiBoaWRkZW4gcHJvamVjdDogICIsZXJyKSkNCiAgICB9KQ0KICANCiAgaWYoc3VwX2NudCE9MCl7DQogICAgICANCiAgICBzdXBfYW1vdW50cyA9IHN1cHBvcnRzICU+JSANCiAgICAgIHhtbF9maW5kX2FsbCgnLy9oMltAY2xhc3M9InBsZWRnZV9fYW1vdW50Il0nKSAlPiUgDQogICAgICB4bWxfdGV4dCAlPiUgdHJpbXdzDQogICAgc3VwX2Rlc2MgPSBzdXBwb3J0cyAlPiUgDQogICAgICB4bWxfZmluZF9hbGwoJy8vZGl2W0BjbGFzcz0icGxlZGdlX19yZXdhcmQtZGVzY3JpcHRpb24gcGxlZGdlX19yZXdhcmQtZGVzY3JpcHRpb24tLWV4cGFuZGVkIl0nKSAlPiUgDQogICAgICB4bWxfdGV4dCAlPiUgdHJpbXdzDQogICAgc3VwX2V4dHJhSW5mbyA9IHN1cHBvcnRzICU+JSANCiAgICAgIHhtbF9maW5kX2FsbCgnLy9kaXZbQGNsYXNzPSJwbGVkZ2VfX2V4dHJhLWluZm8iXScpICU+JSANCiAgICAgIHhtbF90ZXh0ICU+JSB0cmltd3MNCiAgICBzdXBfYmFrZXIgPSBzdXBwb3J0cyAlPiUgDQogICAgICB4bWxfZmluZF9hbGwoJy8vKltjb250YWlucyhjb25jYXQoICIgIiwgQGNsYXNzLCAiICIgKSwgY29uY2F0KCAiICIsICJwbGVkZ2VfX2JhY2tlci1jb3VudCIsICIgIiApKV0nKSAlPiUgDQogICAgICB4bWxfdGV4dCAlPiUgcmVnbWF0Y2hlcyguLCByZWdleHByKCJbWzpkaWdpdDpdXSsiLCAuKSkgJT4lIGFzLm51bWVyaWMNCiAgICAgIA0KICAgICMg5a2Y5oiQZGF0YSBmcmFtZQ0KICAgIHN1cCA9IGRhdGEuZnJhbWUoDQogICAgICAgIHB1cmwgPSB4LA0KICAgICAgICBzdXBfYW1vdW50cyA9IHN1cF9hbW91bnRzLA0KICAgICAgICBzdXBfZGVzYyA9IHN1cF9kZXNjLA0KICAgICAgICBzdXBfZXh0cmFJbmZvID0gc3VwX2V4dHJhSW5mbywNCiAgICAgICAgc3VwX2Jha2VyID0gc3VwX2Jha2VyDQogICAgICApDQogICAgfSAjIGVuZCBpZiANCiAgICANCiAgICByZXR1cm4oc3VwKQ0KICB9KSkNCg0KIyBWaWV3KHN1cHBvcnRzKQ0Kc2F2ZShzdXBwb3J0cywgZmlsZT0iZGF0YS9zdXBwb3J0SW5mby5yZGF0YSIpDQoiZG9uZSINCmBgYA0KDQoNCg0KDQoNCi0tLQ0KPGJyPiA8YnI+IDxocj4NCg0KIyMgUlNlbGVuaXVtDQpgYGB7ciBpbmNsdWRlPUZBTFNFfQ0KIyBzdGFydCBhIGNocm9tZSBicm93c2VyDQpyRCA8LSByc0RyaXZlcigpDQpyZW1EciA8LSByRFtbImNsaWVudCJdXQ0KYGBgDQoNCiMjIyBjb21tZW50IGluZm9ybWF0aW9uDQpgYGB7cn0NCml0ZXI9MA0KY29tbWVudHMgPSBSZWR1Y2UocmJpbmQsIE1hcChmdW5jdGlvbih4KXsNCiAgDQogICMgcHJpbnQoeCkgDQogICMgeCA9ICJodHRwczovL3d3dy5raWNrc3RhcnRlci5jb20vcHJvamVjdHMvMjc5MzA3MjUvcGV0cmlmaWVkLWZvcmVzdC1uYXRpb25hbC1wYXJrLXJlc2lkZW5jeT9yZWY9Y2F0ZWdvcnlfbmV3ZXN0Ig0KICAjIHVybCA9ICJodHRwczovL3d3dy5raWNrc3RhcnRlci5jb20vcHJvamVjdHMvamVzemlrYS9hbnViaXMtZWd5cHRpYW4tbXl0aG9sb2d5LWFydC1wcmludHMtbWFrZS0xMDAvY29tbWVudHMiDQogIA0KICBpdGVyPWl0ZXIrMQ0KICB1cmwgPSB4ICU+JSBzdWIoIi5yZWY9LioiLCIiLC4pICU+JSBwYXN0ZTAoIi9jb21tZW50cyIpDQogIHJlbURyJG5hdmlnYXRlKHVybCkNCiAgDQogICMjIFJTZWxlbml1bQ0KICB3ZWJFbGVtIDwtIHJlbURyJGZpbmRFbGVtZW50cyh1c2luZyA9ICd4cGF0aCcsICcvLypbY29udGFpbnMoY29uY2F0KCAiICIsIEBjbGFzcywgIiAiICksIGNvbmNhdCggIiAiLCAicDIiLCAiICIgKSkgYW5kIGNvbnRhaW5zKGNvbmNhdCggIiAiLCBAY2xhc3MsICIgIiApLCBjb25jYXQoICIgIiwgIm1iMyIsICIgIiApKV0nKQ0KICANCiAgY210X2F1dGhvcj1OQQ0KICBjbXRfY29udGVudD1OQQ0KICANCiAgRXJyb3Jlc3VsdDwtIHRyeUNhdGNoKHsNCiAgICBjbXRzID0gd2ViRWxlbVtbMV1dJGZpbmRDaGlsZEVsZW1lbnRzKHVzaW5nID0gInRhZyBuYW1lIiwgdmFsdWUgPSAibGkiKQ0KICAgIGNtdF9hdXRob3IgPSBjbXRzW1sxXV0kZmluZENoaWxkRWxlbWVudHModXNpbmcgPSAieHBhdGgiLCB2YWx1ZSA9ICIvL3NwYW5bQGNsYXNzPSdtcjInXSIpICU+JSANCiAgICAgIGxhcHBseSguLCBmdW5jdGlvbih4KXt4JGdldEVsZW1lbnRUZXh0KCl9KSAlPiUgDQogICAgICB1bmxpc3QNCiAgICBjbXRfY29udGVudCA9IGxhcHBseShjbXRzLCBGVU4gPSBmdW5jdGlvbih4KXsNCiAgICAgIHgkZmluZENoaWxkRWxlbWVudHModXNpbmcgPSAidGFnIG5hbWUiLCB2YWx1ZSA9ICJwIikgJT4lIA0KICAgICAgICBsYXBwbHkoLiwgZnVuY3Rpb24oeCl7eCRnZXRFbGVtZW50VGV4dCgpfSkgJT4lIA0KICAgICAgICB1bmxpc3QgJT4lIA0KICAgICAgICBwYXN0ZSguLCBjb2xsYXBzZSA9ICdcbicpDQogICAgfSkNCiAgICBjbXRfY29udGVudCA9IGNtdF9jb250ZW50ICU+JSB1bmxpc3QNCiAgICBjbXRfY29udGVudCA9IGNtdF9jb250ZW50WyFjbXRfY29udGVudCA9PSAiVGhpcyBwZXJzb24gaGFzIGNhbmNlbGVkIHRoZWlyIHBsZWRnZS4gU2hvdyB0aGUgY29tbWVudC4iXQ0KICAgIA0KICB9LCB3YXJuaW5nID0gZnVuY3Rpb24od2FyKSB7DQogICAgcHJpbnQocGFzdGUoIk1ZX1dBUk5JTkc6ICAiLHdhcikpDQogIH0sIGVycm9yID0gZnVuY3Rpb24oZXJyKSB7DQogICAgcHJpbnQocGFzdGUoIk1ZX0VSUk9SOiAgIixlcnIpKTsNCiAgfSkNCiAgDQogICMg5a2Y5oiQZGF0YSBmcmFtZQ0KICBpZihsZW5ndGgoY210X2F1dGhvcikhPTApew0KICAgIGRmID0gZGF0YS5mcmFtZSgNCiAgICAgIHVybD0geCwNCiAgICAgIGNtdF9hdXRob3IgPSBjbXRfYXV0aG9yLA0KICAgICAgY210X2NvbnRlbnQgPSBjbXRfY29udGVudA0KICAgICkNCiAgfQ0KICANCn0sIHByb2plY3RfdXJsKSkgIA0KDQojIHNhdmUNCnNhdmUoY29tbWVudHMsImRhdGEvY29tbWVudHNJbmZvLnJkYXRhIikNCiJkb25lIg0KYGBgDQoNCg0KIyMjIFByb2plY3QgTWFpbiBWaWRlbw0KDQoqKiBjb21wbGV0ZSAqKg0KYGBge3J9DQppdGVyPTANCnByb2pfdmlkID0gZGF0YS5mcmFtZSgpDQpwcm9qX3ZpZCA9IFJlZHVjZShyYmluZCwgTWFwKGZ1bmN0aW9uKHgpew0KDQogICMgcHJpbnQoeCkNCiAgIyB4ID0gcHJvamVjdF91cmxbMTQxXQ0KICBpdGVyID0gaXRlcisxDQogIHJlbURyJG5hdmlnYXRlKHgpDQogIA0KICAjIFJTZWxlbml1bQ0KICB3ZWJFbGVtcyA8LSByZW1EciRmaW5kRWxlbWVudHModXNpbmcgPSAnY2xhc3MnLCAiYm9yZGVyLW1lZGl1bSIpDQogIHdlYkVsZW1zQ2xhc3NlcyA8LSBsYXBwbHkod2ViRWxlbXMsIGZ1bmN0aW9uKHgpe3gkZ2V0RWxlbWVudEF0dHJpYnV0ZSgiY2xhc3MiKX0pICU+JSB1bmxpc3QNCiAgDQogIEVycm9yZXN1bHQ8LSB0cnlDYXRjaCh7DQogICAgDQogICAgdmlkX3NyYyA8LSBjKCIiKQ0KICANCiAgICAjIGNsaWNraW5nIHBsYXkgYnV0dG9uIGxldCB2aWRlbyBwbGF5DQogICAgd2ViRWxlbSA8LSB3ZWJFbGVtc1tbd2hpY2god2ViRWxlbXNDbGFzc2VzID09ICJtLWF1dG8gdzIwcCBoMjBwIHcxNXAtbWQgaDE1cC1tZCBwMSBwMi1tZCBiZy1ncmVlbi03MDAgYm9yZGVyIGJvcmRlci13aGl0ZSBib3JkZXItbWVkaXVtIildXQ0KICAgIHdlYkVsZW0kY2xpY2tFbGVtZW50KCkNCiAgICANCiAgICAjIGdldCBzb3VyY2UNCiAgICB3ZWJFbGVtcyA8LSByZW1EciRmaW5kRWxlbWVudHModXNpbmcgPSAneHBhdGgnLCAiLy9zb3VyY2UiKQ0KICAgIHZpZF9zcmMgPC0gc2FwcGx5KHdlYkVsZW1zLCBmdW5jdGlvbih4KXt4JGdldEVsZW1lbnRBdHRyaWJ1dGUoInNyYyIpfSlbMV0gJT4lIGFzLmNoYXJhY3Rlcg0KICAgIA0KICB9LCB3YXJuaW5nID0gZnVuY3Rpb24od2FyKSB7DQogICAgcHJpbnQocGFzdGUoIk1ZX1dBUk5JTkc6ICAiLHdhcikpDQogIH0sIGVycm9yID0gZnVuY3Rpb24oZXJyKSB7DQogICAgcHJpbnQocGFzdGUoIk1ZX0VSUk9SOiAgIixlcnIpKTsNCiAgfSkNCg0KICANCiAgIyDlrZjmiJBkYXRhIGZyYW1lDQogIGRmID0gZGF0YS5mcmFtZSh1cmw9IHgsIHNyYyA9IHZpZF9zcmMpDQogIA0KfSwgcHJvamVjdF91cmwpKQ0KDQojIFZpZXcocHJval92aWQpDQoNCiMgc2F2ZQ0Kc2F2ZShwcm9qX3ZpZCwgImRhdGEvdmlkZW9JbmZvLnJkYXRhIikNCiJkb25lIg0KYGBgDQoNCiMjIyMg6Zec5o6JU2VsZW5pdW0gU2VydmVyDQpgYGB7cn0NCnJlbURyJGNsb3NlKCkNCg0KIyBzdG9wIHRoZSBzZWxlbml1bSBzZXJ2ZXINCnJEW1sic2VydmVyIl1dJHN0b3AoKSANCmBgYA0KDQoNCg0KIyMjIGNvbGxhYm9yYXRvciANCioqbm90IGNvbXBsZXRlKioNCmBgYHtyfQ0KDQp4ID0gcHJvamVjdF91cmxbMTE4XQ0KeCA9ICdodHRwczovL3d3dy5raWNrc3RhcnRlci5jb20vcHJvamVjdHMvMTk3MTM4NjExNi9saXR0bGUtbWlzcy1zdW1vP3JlZj1kaXNjb3ZlcnknDQp4ID0gJ2h0dHBzOi8vd3d3LmtpY2tzdGFydGVyLmNvbS9wcm9qZWN0cy9iZWVoaXZlYm9va3MvaS13aWxsLWxpdmUtZm9yZXZlci1wYXBlcmNyYWZ0LWNvbWljcy1ieS1tYWVsbGUtZG8/cmVmPWRpc2NvdmVyeScNCiAgIyDpgLLlhaXlsIjmoYjpoIHpnaINCiAgcmVtRHIkbmF2aWdhdGUoeCkNCiAgDQogICMg6YCy5YWlY3JlYXRvcuWwj3BhZ2UNCiAgd2ViRWxlbXMgPC0gcmVtRHIkZmluZEVsZW1lbnRzKHVzaW5nID0gJ2NsYXNzJywgImZsZXgtbm9zaHJpbmsiKQ0KICB3ZWJFbGVtc0NsYXNzZXMgPC0gdW5saXN0KGxhcHBseSh3ZWJFbGVtcywgZnVuY3Rpb24oeCl7eCRnZXRFbGVtZW50QXR0cmlidXRlKCJjbGFzcyIpfSkpDQogIEVycm9yZXN1bHQ8LSB0cnlDYXRjaCh7DQogICAgd2ViRWxlbSA8LSB3ZWJFbGVtc1tbd2hpY2god2ViRWxlbXNDbGFzc2VzID09ICJ3NCB3Ny1tZCBtYjItbWQgcG9pbnRlciBmbGV4LW5vc2hyaW5rIGtleWJvYXJkLWZvY3VzYWJsZSIpWzJdXV0NCiAgICB3ZWJFbGVtJGNsaWNrRWxlbWVudCgpDQogIH0sIHdhcm5pbmcgPSBmdW5jdGlvbih3YXIpIHsNCiAgICBwcmludChwYXN0ZSgiTVlfV0FSTklORzogICIsd2FyKSkNCiAgfSwgZXJyb3IgPSBmdW5jdGlvbihlcnIpIHsNCiAgICB3ZWJFbGVtIDwtIHdlYkVsZW1zW1t3aGljaCh3ZWJFbGVtc0NsYXNzZXMgPT0gInc0IHc3LW1kIG1iMi1tZCBwb2ludGVyIGZsZXgtbm9zaHJpbmsga2V5Ym9hcmQtZm9jdXNhYmxlIilbMV1dXQ0KICAgIHdlYkVsZW0kY2xpY2tFbGVtZW50KCkNCiAgICBwcmludChwYXN0ZSgiTVlfRVJST1I6ICAiLGVycikpDQogfSkNCiAgDQogIHdlYkVsZW1zID0gcmVtRHIkZmluZEVsZW1lbnRzKHVzaW5nPSd4cGF0aCcsICcvL2g0JykNCiAgd2ViRWxlbXNDbGFzc2VzIDwtIHVubGlzdChsYXBwbHkod2ViRWxlbXMsIGZ1bmN0aW9uKHgpe3gkZ2V0RWxlbWVudEF0dHJpYnV0ZSgiY2xhc3MiKX0pKQ0KICB3ZWJFbGVtIDwtIHdlYkVsZW1zW3doaWNoKHdlYkVsZW1zQ2xhc3NlcyA9PSAibXQwIG1iMyB0eXBlLTE4IildDQogIHdlYkVsZW0kZ2V0RWxlbWVudFRleHQNCiAgDQpgYGANCg0KDQojIyMgY3JlYXRvciBzbWFsbCBwYWdlDQoNCioqIG5vdCBjb21wbGV0ZSAqKg0KYGBge3J9DQpwcm9qVVJMX2RmID0gZGF0YS5mcmFtZSgpDQpwcm9qVVJMX2RmID0gUmVkdWNlKHJiaW5kLCBNYXAoZnVuY3Rpb24oeCl7DQoNCiAgeCA9IHByb2plY3RfdXJsWzExOF0NCiAgIyDpgLLlhaXlsIjmoYjpoIHpnaINCiAgcmVtRHIkbmF2aWdhdGUoeCkNCiAgDQogICMg6YCy5YWlY3JlYXRvcuWwj3BhZ2UNCiAgd2ViRWxlbXMgPC0gcmVtRHIkZmluZEVsZW1lbnRzKHVzaW5nID0gJ2NsYXNzJywgImZsZXgtbm9zaHJpbmsiKQ0KICB3ZWJFbGVtc0NsYXNzZXMgPC0gdW5saXN0KGxhcHBseSh3ZWJFbGVtcywgZnVuY3Rpb24oeCl7eCRnZXRFbGVtZW50QXR0cmlidXRlKCJjbGFzcyIpfSkpDQogIEVycm9yZXN1bHQ8LSB0cnlDYXRjaCh7DQogICAgd2ViRWxlbSA8LSB3ZWJFbGVtc1tbd2hpY2god2ViRWxlbXNDbGFzc2VzID09ICJ3NCB3Ny1tZCBtYjItbWQgcG9pbnRlciBmbGV4LW5vc2hyaW5rIGtleWJvYXJkLWZvY3VzYWJsZSIpWzJdXV0NCiAgICB3ZWJFbGVtJGNsaWNrRWxlbWVudCgpDQogIH0sIHdhcm5pbmcgPSBmdW5jdGlvbih3YXIpIHsNCiAgICBwcmludChwYXN0ZSgiTVlfV0FSTklORzogICIsd2FyKSkNCiAgfSwgZXJyb3IgPSBmdW5jdGlvbihlcnIpIHsNCiAgICB3ZWJFbGVtIDwtIHdlYkVsZW1zW1t3aGljaCh3ZWJFbGVtc0NsYXNzZXMgPT0gInc0IHc3LW1kIG1iMi1tZCBwb2ludGVyIGZsZXgtbm9zaHJpbmsga2V5Ym9hcmQtZm9jdXNhYmxlIilbMV1dXQ0KICAgIHdlYkVsZW0kY2xpY2tFbGVtZW50KCkNCiAgICBwcmludChwYXN0ZSgiTVlfRVJST1I6ICAiLGVycikpDQogfSkNCiAgDQogICMjIGxhc3QgbG9naW4gZGF0ZQ0KDQogICMjIGZhY2Vib29rIGNvbm5lY3QNCiAgIyB1c2UgdGhpcyBwcm9qZWN0ICENCiAgIyBodHRwczovL3d3dy5raWNrc3RhcnRlci5jb20vcHJvamVjdHMvMTg3MDQ3NjQ3MC90b21iLW9mLWhvcnJvci12b2wtMi1ob3Jyb3ItYW50aG9sb2d5P3JlZj1jYXRlZ29yeV9uZXdlc3QNCiAgDQogIA0KICAjIyBDb2xsYWJvcmF0b3JzIG9uIHRoaXMgcHJvamVjdA0KICANCiAgDQogIA0KICAjIOWtmOaIkGRhdGEgZnJhbWUNCiAgZGYgPSBkYXRhLmZyYW1lKHVybD0geCwgZGVzY3JpcHRpb24gPSBkZXNjLCB0ZXh0ID0gdGV4dCkNCg0KfSwgcHJvamVjdF91cmxbMTo1XSkpDQpgYGANCg0KIyMjIyDpl5zmjolTZWxlbml1bSBTZXJ2ZXINCmBgYHtyfQ0KcmVtRHIkY2xvc2UoKQ0KDQojIHN0b3AgdGhlIHNlbGVuaXVtIHNlcnZlcg0KckRbWyJzZXJ2ZXIiXV0kc3RvcCgpIA0KYGBgDQoNCg0KLS0tDQo8YnI+IDxicj4gPGhyPg0KDQojIyMgY3JlYXRvciBiaW9ncmFwaHnlj6/oroDmgKcNCmBgYHtyfQ0KIyByYV9iaW8gPSB3aXRoKGFsbF9iaW8sIHJlYWRhYmlsaXR5KGJpbywgdXJsKSkNCiMgcmFfYmlvDQojIHN1bW1hcnkocmFfYmlvKQ0KYGBg