getting started
#start with clean workspace
rm(list=ls())
getwd()
packages
library(data.table)
library(tidyverse)
require(xml2)
require(rvest)
require(devtools)
require(scholar)
require(stringi)
Scholar
“https://scholar.google.nl/scholar/citations?view_op=search_authors&mauthors=jochem+tolsma&hl=en&oi=ao”
https://scholar.google.nl/citations?view_op=search_authors&mauthors=lonneke+van
den berg&hl=en&oi=ao
get_scholar_resp(“https://scholar.google.nl/citations?view_op=search_authors&mauthors=lonneke+van
den berg&hl=en&oi=ao”)
get_scholar_resp(“https://scholar.google.nl/citations?view_op=search_authors&mauthors=lonneke+van+den+berg&hl=en&oi=ao”)
fixing a bug in the
get_scholar_id function.
get_scholar_id_fix <- function (last_name = "", first_name = "", affiliation = NA)
{
if (!any(nzchar(c(first_name, last_name))))
stop("At least one of first and last name must be specified!")
site <- getOption("scholar_site")
url <- paste0(site, "/citations?view_op=search_authors&mauthors=",
first_name, "+", last_name, "&hl=en&oi=ao")
page <- get_scholar_resp(url)
if (is.null(page))
return(NA)
aa <- httr::content(page, as = "text")
# added by Bas Hofstra: bugfix for IDs that have a dash ("-")
ids <- substring(aa, regexpr(";user=", aa))
ids <- substr(ids, 1, 19) # error prone, but unsure how to solve otherwise
# if (nchar(stringr::str_extract_all(string = aa, pattern = ";user=[[:alnum:]]+[[:punct:]]")[[1]][1]) < 18) {
# ids <- stringr::str_extract_all(string = aa, pattern = ";user=[[:alnum:]]+[[:punct:]]+[[:alnum:]]+[[:punct:]]")
# } else {
# ids <- stringr::str_extract_all(string = aa, pattern = ";user=[[:alnum:]]+[[:punct:]]")
# }
if (length(unlist(ids)) == 0) {
message("No Scholar ID found.")
return(NA)
}
ids <- ids %>% unlist %>% gsub(";user=|[[:punct:]]$", "",
.) %>% unique
if (length(ids) > 1) {
profiles <- lapply(ids, scholar::get_profile)
if (is.na(affiliation)) {
x_profile <- profiles[[1]]
warning("Selecting first out of ", length(profiles),
" candidate matches.")
}
else {
which_profile <- sapply(profiles, function(x) {
stringr::str_count(string = x$affiliation, pattern = stringr::coll(affiliation,
ignore_case = TRUE))
})
if (all(which_profile == 0)) {
warning("No researcher found at the indicated affiliation.")
return(NA)
}
else {
x_profile <- profiles[[which(which_profile !=
0)]]
}
}
}
else {
x_profile <- scholar::get_profile(id = ids)
}
return(x_profile$id)
}
scholars id.
Don’t forget to check manually if everything is okay.
We make an important decisson here. we remove staff members without
scholar ids. perhaps a bit strange for our RSiena analysis later. I
mean, we can include isolates
YOU MAY NEED TO ADD AN TRYCATCH TO THIS LOOP AS WELL TO AVOID TIME
OUT ERRORS, SEE THE NEXT LOOP BELOW
load("names_df_v20221006.RData")
cs_df <- names_df
cs_df$gs_id <- "" #don't make it empty everytime you run scrape!
cs_df$affiliation[cs_df$affiliation=="RU"] <- "Radboud University"
cs_df$affiliation[cs_df$affiliation=="UU"] <- "Utrecht University"
cs_df$last_name3 <- str_replace_all(cs_df$last_name, " ", "+")
time <- .1 # I placed the waiting time outside the loop
i <- 1 # Our loop iterator is now a variable. This means I can change it within a while loop. Using a for loop you cant change your iterator in the loop itself.
while (i <= nrow(cs_df)) {
print(i)
Sys.sleep(time)
if (cs_df[i,c("gs_id")]!="") {
i <- i + 1
next
}
tryCatch({
if (cs_df[i,c("gs_id")]=="") {
cs_df[i,c("gs_id")] <- get_scholar_id_fix(last_name = cs_df[i, c("last_name3")], first_name = cs_df[i, c("first_name")],affiliation = cs_df[i,c("affiliation")])
i <- i + 1
time <- 1 #reset time if succesfull
}
},
warning = function(w) {
cat("WARNING:", conditionMessage(w), "\n") #WARNING message
cs_df[i,c("gs_id")] <<- ""
i <<- i + 1
time <<- .1 #reset time if succesfull
},
error=function(e){
err <- conditionMessage(e)
if (stringr::str_detect(err, "Google is rate limiting you")) {
time <<- min(time + 100, 3600*2)
cat("Error:", conditionMessage(e), "\n") #ERROR message
cat("sleep time:", time, "\n")
cat("ik zit in loop", i)
} else {
cat("ERROR :", conditionMessage(e), "\n") # continue on error, but print the error
i <<- i + 1
time <<- .1 #reset time if succesfull
}
})
}
let us repeat without affiliation.
scholartemp <- cs_df
save(scholartemp, file="./data/scholartemp_v20221006.RData")
rm(scholartemp)
rm(names_df)
publications and
profiles
cs_df <- cs_df[!cs_df$gs_id == "", ]
cs_df <- cs_df[!is.na(cs_df$gs_id), ]
soc_list_profiles <- list() # first we create an empty list that we then fill up with the for loop
soc_list_publications <- list()
time <- .1 # I placed the waiting time outside the loop
i <- 1 # Our loop iterator is now a variable. This means I can change it within a while loop. Using a for loop you cant change your iterator in the loop itself.
while (i <= nrow(cs_df)) {
print(i)
Sys.sleep(time)
tryCatch({
soc_list_profiles[[i]] <- get_profile(cs_df[i, c("gs_id")])
soc_list_publications[[i]] <- get_publications(cs_df[i, c("gs_id")])
soc_list_publications[[i]][, c("gs_id")] <- cs_df[i, c("gs_id")]
i <- i + 1
time <- .1
},
warning = function(w) {
cat("WARNING:", conditionMessage(w), "\n")
i <<- i + 1
},
error =function(e) {
time <<- min(time + 100, 3600*2)
cat("Error:", conditionMessage(e), "\n")
cat("sleep time:", time, "\n")
cat("ik zit in loop", i)
})
}
cs_df_publications <- names_df_publications <- bind_rows(soc_list_publications)
cs_list_profiles <- names_list_profiles <- soc_list_profiles
save(names_df_publications, file="./data/names_df_publications_v20221006.RData")
save(names_list_profiles, file= "./data/names_list_profiles_v20221006.RData")
put the info of the
profiles in our data set of staff members cs_df
cs_profiles_df <- list()
for (i in 1:length(cs_list_profiles)) {
# soc_profiles_df[[i]] <- data.frame(t(unlist(soc_list_profiles[[i]][1:8]))) #some annyoing
# data handling
if (!is.null(cs_list_profiles[[i]])) {
cs_profiles_df[[i]] <- unlist(cs_list_profiles[[i]][1:8])
cs_profiles_df[[i]] <- data.frame(cs_profiles_df[[i]])
cs_profiles_df[[i]] <- t(cs_profiles_df[[i]])
row.names(cs_profiles_df[[i]]) <- NULL
cs_profiles_df[[i]] <- data.frame(cs_profiles_df[[i]])
}
}
let op we hebben dus duplicates. mensen staan zowel bij computer
science als bij data science.
cs_profiles_df2 <- bind_rows(cs_profiles_df)
names(cs_profiles_df2)[1] <- "gs_id"
#cs_df <- names_df_copy[!names_df_copy$gs_id=="",]
length(cs_df$id)
duplicated(cs_df$gs_id)
cs_df[order(cs_df$gs_id),]
cs_df2 <- data.frame(cbind(cs_df, cs_profiles_df2) )
names_df <- cs_df2
save(names_df, file="./data/names_df2_v20220106.RData")
citation history
cs_df <- cs_df2
# get citation history of a scholar
cs_staff_cit <- list()
time <- .1 # I placed the waiting time outside the loop
i <- 1 # Our loop iterator is now a variable. This means I can change it within a while loop. Using a for loop you cant change your iterator in the loop itself.
while (i <= nrow(cs_df)) {
print(i)
Sys.sleep(time)
tryCatch({
cs_staff_cit[[i]] <- get_citation_history(cs_df[i, c("gs_id")])
if (nrow(cs_staff_cit[[i]]) > 0) {
cs_staff_cit[[i]][, c("gs_id")] <- cs_df[i, c("gs_id")] # again attach the gs_id as third column
}
i <- i + 1
time <- .1
},
warning = function(w) {
cat("WARNING:", conditionMessage(w), "\n") #WARNING message
i <<- i + 1}, #BUT WE DO WANT TO CONTINUE. NOTE THE DOUBLE << THIS IS BECAUSE I WANT TO CHANGE A VARIABLE WHICH EXISTS OUTSIDE THE WARNING FUNCTION
error =function(e) {
time <<- min(time + 10, 3600*2)
cat("Error:", conditionMessage(e), "\n") #ERROR message
cat("sleep time:", time, "\n")
cat("ik zit in loop", i)
#AFTER THE NEW SLEEP TIME, WE TRY AGAIN, WE THEREFORE DO NOT UPDATE i. ideally you also want to have some break option. And maybe you also want to save your data when you hit a time out error.
})
}
names_staff_cit <- bind_rows(cs_staff_cit)
save(names_staff_cit, file="./data/names_staff_cit_v20221006.RData")
LS0tDQp0aXRsZTogIjQuIFNjaG9sYXIiDQphdXRob3I6ICJieTogTmluYSBCcmFudGVuIg0KYmlibGlvZ3JhcGh5OiByZWZlcmVuY2VzLmJpYg0KLS0tDQoNCg0KDQpgYGB7ciwgaW5zdGFsbCByZW1vdGVseSwgZ2xvYmFsc2V0dGluZ3MsIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHJlc3VsdHM9J2hpZGUnLCBldmFsPUZBTFNFfQ0KaW5zdGFsbC5wYWNrYWdlcygicmVtb3RlcyIpDQpyZW1vdGVzOjppbnN0YWxsX2dpdGh1Yigicmxlc3VyL2tsaXBweSIpDQpgYGAgDQoNCmBgYHtyLCBnbG9iYWxzZXR0aW5ncywgZWNobz1GQUxTRSwgd2FybmluZz1GQUxTRSwgcmVzdWx0cz0naGlkZSd9DQpsaWJyYXJ5KGtuaXRyKQ0KbGlicmFyeShyZ2wpDQoNCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkNCm9wdHNfY2h1bmskc2V0KHRpZHkub3B0cz1saXN0KHdpZHRoLmN1dG9mZj0xMDApLHRpZHk9VFJVRSwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UsY29tbWVudCA9ICIjPiIsIGNhY2hlPVRSVUUsIGNsYXNzLnNvdXJjZT1jKCJ0ZXN0IiksIGNsYXNzLm91dHB1dD1jKCJ0ZXN0MiIpKQ0Kb3B0aW9ucyh3aWR0aCA9IDEwMCkNCnJnbDo6c2V0dXBLbml0cigpDQoNCg0KDQpjb2xvcml6ZSA8LSBmdW5jdGlvbih4LCBjb2xvcikge3NwcmludGYoIjxzcGFuIHN0eWxlPSdjb2xvcjogJXM7Jz4lczwvc3Bhbj4iLCBjb2xvciwgeCkgfQ0KDQpgYGANCg0KYGBge3Iga2xpcHB5LCBlY2hvPUZBTFNFLCBpbmNsdWRlPVRSVUV9DQprbGlwcHk6OmtsaXBweShwb3NpdGlvbiA9IGMoJ3RvcCcsICdyaWdodCcpKQ0KI2tsaXBweTo6a2xpcHB5KGNvbG9yID0gJ2RhcmtyZWQnKQ0KI2tsaXBweTo6a2xpcHB5KHRvb2x0aXBfbWVzc2FnZSA9ICdDbGljayB0byBjb3B5JywgdG9vbHRpcF9zdWNjZXNzID0gJ0RvbmUnKQ0KYGBgDQoNCg0KIyBnZXR0aW5nIHN0YXJ0ZWQNCg0KYGBge3IsIGV2YWw9RkFMU0V9DQojc3RhcnQgd2l0aCBjbGVhbiB3b3Jrc3BhY2UgDQpybShsaXN0PWxzKCkpDQpnZXR3ZCgpDQpgYGANCg0KIyBwYWNrYWdlcw0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCmxpYnJhcnkoZGF0YS50YWJsZSkgDQpsaWJyYXJ5KHRpZHl2ZXJzZSkgDQpyZXF1aXJlKHhtbDIpDQpyZXF1aXJlKHJ2ZXN0KQ0KcmVxdWlyZShkZXZ0b29scykNCnJlcXVpcmUoc2Nob2xhcikNCnJlcXVpcmUoc3RyaW5naSkNCg0KYGBgDQoNCiMgU2Nob2xhciAgDQoNCiJodHRwczovL3NjaG9sYXIuZ29vZ2xlLm5sL3NjaG9sYXIvY2l0YXRpb25zP3ZpZXdfb3A9c2VhcmNoX2F1dGhvcnMmbWF1dGhvcnM9am9jaGVtK3RvbHNtYSZobD1lbiZvaT1hbyINCg0KaHR0cHM6Ly9zY2hvbGFyLmdvb2dsZS5ubC9jaXRhdGlvbnM/dmlld19vcD1zZWFyY2hfYXV0aG9ycyZtYXV0aG9ycz1sb25uZWtlK3ZhbiBkZW4gYmVyZyZobD1lbiZvaT1hbw0KDQpnZXRfc2Nob2xhcl9yZXNwKCJodHRwczovL3NjaG9sYXIuZ29vZ2xlLm5sL2NpdGF0aW9ucz92aWV3X29wPXNlYXJjaF9hdXRob3JzJm1hdXRob3JzPWxvbm5la2UrdmFuIGRlbiBiZXJnJmhsPWVuJm9pPWFvIikNCg0KZ2V0X3NjaG9sYXJfcmVzcCgiaHR0cHM6Ly9zY2hvbGFyLmdvb2dsZS5ubC9jaXRhdGlvbnM/dmlld19vcD1zZWFyY2hfYXV0aG9ycyZtYXV0aG9ycz1sb25uZWtlK3ZhbitkZW4rYmVyZyZobD1lbiZvaT1hbyIpDQoNCiMjIGZpeGluZyBhIGJ1ZyBpbiB0aGUgZ2V0X3NjaG9sYXJfaWQgZnVuY3Rpb24uIA0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCg0KZ2V0X3NjaG9sYXJfaWRfZml4IDwtIGZ1bmN0aW9uIChsYXN0X25hbWUgPSAiIiwgZmlyc3RfbmFtZSA9ICIiLCBhZmZpbGlhdGlvbiA9IE5BKQ0Kew0KICBpZiAoIWFueShuemNoYXIoYyhmaXJzdF9uYW1lLCBsYXN0X25hbWUpKSkpDQogICAgc3RvcCgiQXQgbGVhc3Qgb25lIG9mIGZpcnN0IGFuZCBsYXN0IG5hbWUgbXVzdCBiZSBzcGVjaWZpZWQhIikNCiAgc2l0ZSA8LSBnZXRPcHRpb24oInNjaG9sYXJfc2l0ZSIpDQogIHVybCA8LSBwYXN0ZTAoc2l0ZSwgIi9jaXRhdGlvbnM/dmlld19vcD1zZWFyY2hfYXV0aG9ycyZtYXV0aG9ycz0iLA0KICAgICAgICAgICAgICAgIGZpcnN0X25hbWUsICIrIiwgbGFzdF9uYW1lLCAiJmhsPWVuJm9pPWFvIikNCiAgcGFnZSA8LSBnZXRfc2Nob2xhcl9yZXNwKHVybCkNCiAgaWYgKGlzLm51bGwocGFnZSkpDQogICAgcmV0dXJuKE5BKQ0KICBhYSA8LSBodHRyOjpjb250ZW50KHBhZ2UsIGFzID0gInRleHQiKQ0KICAjIGFkZGVkIGJ5IEJhcyBIb2ZzdHJhOiBidWdmaXggZm9yIElEcyB0aGF0IGhhdmUgYSBkYXNoICgiLSIpDQogIGlkcyA8LSBzdWJzdHJpbmcoYWEsIHJlZ2V4cHIoIjt1c2VyPSIsIGFhKSkNCiAgaWRzIDwtIHN1YnN0cihpZHMsIDEsIDE5KSAjIGVycm9yIHByb25lLCBidXQgdW5zdXJlIGhvdyB0byBzb2x2ZSBvdGhlcndpc2UNCiAgIyBpZiAobmNoYXIoc3RyaW5ncjo6c3RyX2V4dHJhY3RfYWxsKHN0cmluZyA9IGFhLCBwYXR0ZXJuID0gIjt1c2VyPVtbOmFsbnVtOl1dK1tbOnB1bmN0Ol1dIilbWzFdXVsxXSkgPCAxOCkgew0KICAjICAgaWRzIDwtIHN0cmluZ3I6OnN0cl9leHRyYWN0X2FsbChzdHJpbmcgPSBhYSwgcGF0dGVybiA9ICI7dXNlcj1bWzphbG51bTpdXStbWzpwdW5jdDpdXStbWzphbG51bTpdXStbWzpwdW5jdDpdXSIpDQogICMgfSBlbHNlIHsNCiAgIyAgIGlkcyA8LSBzdHJpbmdyOjpzdHJfZXh0cmFjdF9hbGwoc3RyaW5nID0gYWEsIHBhdHRlcm4gPSAiO3VzZXI9W1s6YWxudW06XV0rW1s6cHVuY3Q6XV0iKQ0KICAjIH0NCiAgaWYgKGxlbmd0aCh1bmxpc3QoaWRzKSkgPT0gMCkgew0KICAgIG1lc3NhZ2UoIk5vIFNjaG9sYXIgSUQgZm91bmQuIikNCiAgICByZXR1cm4oTkEpDQogIH0NCiAgaWRzIDwtIGlkcyAlPiUgdW5saXN0ICU+JSBnc3ViKCI7dXNlcj18W1s6cHVuY3Q6XV0kIiwgIiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuKSAlPiUgdW5pcXVlDQogIGlmIChsZW5ndGgoaWRzKSA+IDEpIHsNCiAgICBwcm9maWxlcyA8LSBsYXBwbHkoaWRzLCBzY2hvbGFyOjpnZXRfcHJvZmlsZSkNCiAgICBpZiAoaXMubmEoYWZmaWxpYXRpb24pKSB7DQogICAgICB4X3Byb2ZpbGUgPC0gcHJvZmlsZXNbWzFdXQ0KICAgICAgd2FybmluZygiU2VsZWN0aW5nIGZpcnN0IG91dCBvZiAiLCBsZW5ndGgocHJvZmlsZXMpLA0KICAgICAgICAgICAgICAiIGNhbmRpZGF0ZSBtYXRjaGVzLiIpDQogICAgfQ0KICAgIGVsc2Ugew0KICAgICAgd2hpY2hfcHJvZmlsZSA8LSBzYXBwbHkocHJvZmlsZXMsIGZ1bmN0aW9uKHgpIHsNCiAgICAgICAgc3RyaW5ncjo6c3RyX2NvdW50KHN0cmluZyA9IHgkYWZmaWxpYXRpb24sIHBhdHRlcm4gPSBzdHJpbmdyOjpjb2xsKGFmZmlsaWF0aW9uLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWdub3JlX2Nhc2UgPSBUUlVFKSkNCiAgICAgIH0pDQogICAgICBpZiAoYWxsKHdoaWNoX3Byb2ZpbGUgPT0gMCkpIHsNCiAgICAgICAgd2FybmluZygiTm8gcmVzZWFyY2hlciBmb3VuZCBhdCB0aGUgaW5kaWNhdGVkIGFmZmlsaWF0aW9uLiIpDQogICAgICAgIHJldHVybihOQSkNCiAgICAgIH0NCiAgICAgIGVsc2Ugew0KICAgICAgICB4X3Byb2ZpbGUgPC0gcHJvZmlsZXNbW3doaWNoKHdoaWNoX3Byb2ZpbGUgIT0NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDApXV0NCiAgICAgIH0NCiAgICB9DQogIH0NCiAgZWxzZSB7DQogICAgeF9wcm9maWxlIDwtIHNjaG9sYXI6OmdldF9wcm9maWxlKGlkID0gaWRzKQ0KICB9DQogIHJldHVybih4X3Byb2ZpbGUkaWQpDQp9DQpgYGANCg0KIyMgc2Nob2xhcnMgaWQuIA0KDQpEb24ndCBmb3JnZXQgdG8gY2hlY2sgbWFudWFsbHkgaWYgZXZlcnl0aGluZyBpcyBva2F5LiANCg0KV2UgbWFrZSBhbiBpbXBvcnRhbnQgZGVjaXNzb24gaGVyZS4gd2UgcmVtb3ZlIHN0YWZmIG1lbWJlcnMgd2l0aG91dCBzY2hvbGFyIGlkcy4gcGVyaGFwcyBhIGJpdCBzdHJhbmdlIGZvciBvdXIgUlNpZW5hIGFuYWx5c2lzIGxhdGVyLiBJIG1lYW4sIHdlIGNhbiBpbmNsdWRlIGlzb2xhdGVzDQoNCllPVSBNQVkgTkVFRCBUTyBBREQgQU4gVFJZQ0FUQ0ggVE8gVEhJUyBMT09QIEFTIFdFTEwgVE8gQVZPSUQgVElNRSBPVVQgRVJST1JTLCBTRUUgVEhFIE5FWFQgTE9PUCBCRUxPVw0KYGBge3IsIGV2YWw9RkFMU0V9DQpsb2FkKCJuYW1lc19kZl92MjAyMjEwMDYuUkRhdGEiKSANCmNzX2RmIDwtIG5hbWVzX2RmDQpjc19kZiRnc19pZCA8LSAiIiAjZG9uJ3QgbWFrZSBpdCBlbXB0eSBldmVyeXRpbWUgeW91IHJ1biBzY3JhcGUhIA0KY3NfZGYkYWZmaWxpYXRpb25bY3NfZGYkYWZmaWxpYXRpb249PSJSVSJdIDwtICJSYWRib3VkIFVuaXZlcnNpdHkiDQpjc19kZiRhZmZpbGlhdGlvbltjc19kZiRhZmZpbGlhdGlvbj09IlVVIl0gPC0gIlV0cmVjaHQgVW5pdmVyc2l0eSINCmNzX2RmJGxhc3RfbmFtZTMgPC0gc3RyX3JlcGxhY2VfYWxsKGNzX2RmJGxhc3RfbmFtZSwgIiAiLCAiKyIpICANCg0KYGBgDQoNCg0KYGBge3IsIGV2YWw9RkFMU0V9DQp0aW1lIDwtIC4xICMgSSBwbGFjZWQgdGhlIHdhaXRpbmcgdGltZSBvdXRzaWRlIHRoZSBsb29wDQppIDwtIDEgIyBPdXIgbG9vcCBpdGVyYXRvciBpcyBub3cgYSB2YXJpYWJsZS4gVGhpcyBtZWFucyBJIGNhbiBjaGFuZ2UgaXQgd2l0aGluIGEgd2hpbGUgbG9vcC4gVXNpbmcgYSBmb3IgbG9vcCB5b3UgY2FudCBjaGFuZ2UgeW91ciBpdGVyYXRvciBpbiB0aGUgbG9vcCBpdHNlbGYuDQpgYGANCg0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCndoaWxlIChpIDw9IG5yb3coY3NfZGYpKSB7DQogIHByaW50KGkpDQogIFN5cy5zbGVlcCh0aW1lKQ0KICBpZiAoY3NfZGZbaSxjKCJnc19pZCIpXSE9IiIpIHsNCiAgICBpIDwtIGkgKyAxDQogICAgbmV4dA0KICB9DQogIHRyeUNhdGNoKHsNCiAgICAgaWYgKGNzX2RmW2ksYygiZ3NfaWQiKV09PSIiKSB7DQogICAgICAgY3NfZGZbaSxjKCJnc19pZCIpXSA8LSBnZXRfc2Nob2xhcl9pZF9maXgobGFzdF9uYW1lID0gY3NfZGZbaSwgYygibGFzdF9uYW1lMyIpXSwgZmlyc3RfbmFtZSA9IGNzX2RmW2ksIGMoImZpcnN0X25hbWUiKV0sYWZmaWxpYXRpb24gPSBjc19kZltpLGMoImFmZmlsaWF0aW9uIildKQ0KICAgICAgaSA8LSBpICsgMQ0KICAgICAgdGltZSA8LSAxICNyZXNldCB0aW1lIGlmIHN1Y2Nlc2Z1bGwgDQogICAgIH0NCiAgICB9LCANCiAgICB3YXJuaW5nID0gZnVuY3Rpb24odykgew0KICAgICAgICBjYXQoIldBUk5JTkc6IiwgY29uZGl0aW9uTWVzc2FnZSh3KSwgIlxuIikgI1dBUk5JTkcgbWVzc2FnZQ0KICAgICAgICBjc19kZltpLGMoImdzX2lkIildIDw8LSAiIg0KICAgICAgICBpIDw8LSBpICsgMQ0KICAgICAgICB0aW1lIDw8LSAuMSAjcmVzZXQgdGltZSBpZiBzdWNjZXNmdWxsIA0KICAgICAgICB9LCANCiAgICBlcnJvcj1mdW5jdGlvbihlKXsNCiAgICAgIGVyciA8LSBjb25kaXRpb25NZXNzYWdlKGUpDQogICAgICBpZiAoc3RyaW5ncjo6c3RyX2RldGVjdChlcnIsICJHb29nbGUgaXMgcmF0ZSBsaW1pdGluZyB5b3UiKSkgew0KICAgICAgICB0aW1lIDw8LSBtaW4odGltZSArIDEwMCwgMzYwMCoyKQ0KICAgICAgICBjYXQoIkVycm9yOiIsIGNvbmRpdGlvbk1lc3NhZ2UoZSksICJcbiIpICNFUlJPUiBtZXNzYWdlDQogICAgICAgIGNhdCgic2xlZXAgdGltZToiLCB0aW1lLCAgIlxuIikNCiAgICAgICAgY2F0KCJpayB6aXQgaW4gbG9vcCIsIGkpDQogICAgICB9IGVsc2Ugew0KICAgICAgICBjYXQoIkVSUk9SIDoiLCBjb25kaXRpb25NZXNzYWdlKGUpLCAiXG4iKSAjIGNvbnRpbnVlIG9uIGVycm9yLCBidXQgcHJpbnQgdGhlIGVycm9yDQogICAgICAgIGkgPDwtIGkgKyAxDQogICAgICAgIHRpbWUgPDwtIC4xICNyZXNldCB0aW1lIGlmIHN1Y2Nlc2Z1bGwgDQogICAgICAgIH0NCiAgICAgIH0pDQp9DQpgYGANCg0KbGV0IHVzIHJlcGVhdCB3aXRob3V0IGFmZmlsaWF0aW9uLiANCg0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCnNjaG9sYXJ0ZW1wIDwtIGNzX2RmDQpzYXZlKHNjaG9sYXJ0ZW1wLCBmaWxlPSIuL2RhdGEvc2Nob2xhcnRlbXBfdjIwMjIxMDA2LlJEYXRhIikNCnJtKHNjaG9sYXJ0ZW1wKQ0Kcm0obmFtZXNfZGYpDQoNCmBgYA0KDQoNCg0KDQojIHB1YmxpY2F0aW9ucyBhbmQgcHJvZmlsZXMNCg0KYGBge3IsIGV2YWw9RkFMU0V9DQpjc19kZiA8LSBjc19kZlshY3NfZGYkZ3NfaWQgPT0gIiIsIF0gDQpjc19kZiA8LSBjc19kZlshaXMubmEoY3NfZGYkZ3NfaWQpLCBdIA0KDQpgYGANCg0KDQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0Kc29jX2xpc3RfcHJvZmlsZXMgPC0gbGlzdCgpICAjIGZpcnN0IHdlIGNyZWF0ZSBhbiBlbXB0eSBsaXN0IHRoYXQgd2UgdGhlbiBmaWxsIHVwIHdpdGggdGhlIGZvciBsb29wDQpzb2NfbGlzdF9wdWJsaWNhdGlvbnMgPC0gbGlzdCgpDQpgYGANCg0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCnRpbWUgPC0gLjEgIyBJIHBsYWNlZCB0aGUgd2FpdGluZyB0aW1lIG91dHNpZGUgdGhlIGxvb3ANCmkgPC0gMSAjIE91ciBsb29wIGl0ZXJhdG9yIGlzIG5vdyBhIHZhcmlhYmxlLiBUaGlzIG1lYW5zIEkgY2FuIGNoYW5nZSBpdCB3aXRoaW4gYSB3aGlsZSBsb29wLiBVc2luZyBhIGZvciBsb29wIHlvdSBjYW50IGNoYW5nZSB5b3VyIGl0ZXJhdG9yIGluIHRoZSBsb29wIGl0c2VsZi4NCmBgYA0KDQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0Kd2hpbGUgKGkgPD0gbnJvdyhjc19kZikpIHsNCiAgICBwcmludChpKQ0KICAgIFN5cy5zbGVlcCh0aW1lKQ0KDQogICAgdHJ5Q2F0Y2goew0KICAgIHNvY19saXN0X3Byb2ZpbGVzW1tpXV0gPC0gZ2V0X3Byb2ZpbGUoY3NfZGZbaSwgYygiZ3NfaWQiKV0pIA0KICAgIHNvY19saXN0X3B1YmxpY2F0aW9uc1tbaV1dIDwtIGdldF9wdWJsaWNhdGlvbnMoY3NfZGZbaSwgYygiZ3NfaWQiKV0pDQogICAgc29jX2xpc3RfcHVibGljYXRpb25zW1tpXV1bLCBjKCJnc19pZCIpXSA8LSBjc19kZltpLCBjKCJnc19pZCIpXSAgDQogICAgaSA8LSBpICsgMSANCiAgICB0aW1lIDwtIC4xDQogICAgfSwNCiAgICANCiAgICAgIHdhcm5pbmcgPSBmdW5jdGlvbih3KSB7DQogICAgICAgIGNhdCgiV0FSTklORzoiLCBjb25kaXRpb25NZXNzYWdlKHcpLCAiXG4iKSANCiAgICAgICAgaSA8PC0gaSArIDENCiAgICAgICAgfSwgDQogICAgDQogICAgICBlcnJvciA9ZnVuY3Rpb24oZSkgew0KICAgICAgICB0aW1lIDw8LSBtaW4odGltZSArIDEwMCwgMzYwMCoyKQ0KICAgICAgICBjYXQoIkVycm9yOiIsIGNvbmRpdGlvbk1lc3NhZ2UoZSksICJcbiIpIA0KICAgICAgICBjYXQoInNsZWVwIHRpbWU6IiwgdGltZSwgICJcbiIpDQogICAgICAgIGNhdCgiaWsgeml0IGluIGxvb3AiLCBpKQ0KICAgICAgfSkNCn0NCmBgYA0KDQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KY3NfZGZfcHVibGljYXRpb25zIDwtIG5hbWVzX2RmX3B1YmxpY2F0aW9ucyA8LSBiaW5kX3Jvd3Moc29jX2xpc3RfcHVibGljYXRpb25zKQ0KY3NfbGlzdF9wcm9maWxlcyA8LSBuYW1lc19saXN0X3Byb2ZpbGVzIDwtIHNvY19saXN0X3Byb2ZpbGVzDQpgYGANCg0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCnNhdmUobmFtZXNfZGZfcHVibGljYXRpb25zLCBmaWxlPSIuL2RhdGEvbmFtZXNfZGZfcHVibGljYXRpb25zX3YyMDIyMTAwNi5SRGF0YSIpDQpzYXZlKG5hbWVzX2xpc3RfcHJvZmlsZXMsIGZpbGU9ICIuL2RhdGEvbmFtZXNfbGlzdF9wcm9maWxlc192MjAyMjEwMDYuUkRhdGEiKQ0KDQpgYGANCg0KDQoNCiMjIHB1dCB0aGUgaW5mbyBvZiB0aGUgcHJvZmlsZXMgaW4gb3VyIGRhdGEgc2V0IG9mIHN0YWZmIG1lbWJlcnMgY3NfZGYNCg0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCmNzX3Byb2ZpbGVzX2RmIDwtIGxpc3QoKQ0KDQoNCmZvciAoaSBpbiAxOmxlbmd0aChjc19saXN0X3Byb2ZpbGVzKSkgew0KICAgICMgc29jX3Byb2ZpbGVzX2RmW1tpXV0gPC0gZGF0YS5mcmFtZSh0KHVubGlzdChzb2NfbGlzdF9wcm9maWxlc1tbaV1dWzE6OF0pKSkgI3NvbWUgYW5ueW9pbmcNCiAgICAjIGRhdGEgaGFuZGxpbmcNCiAgaWYgKCFpcy5udWxsKGNzX2xpc3RfcHJvZmlsZXNbW2ldXSkpIHsNCiAgICBjc19wcm9maWxlc19kZltbaV1dIDwtIHVubGlzdChjc19saXN0X3Byb2ZpbGVzW1tpXV1bMTo4XSkNCiAgICBjc19wcm9maWxlc19kZltbaV1dIDwtIGRhdGEuZnJhbWUoY3NfcHJvZmlsZXNfZGZbW2ldXSkNCiAgICBjc19wcm9maWxlc19kZltbaV1dIDwtIHQoY3NfcHJvZmlsZXNfZGZbW2ldXSkNCiAgICByb3cubmFtZXMoY3NfcHJvZmlsZXNfZGZbW2ldXSkgPC0gTlVMTA0KICAgIGNzX3Byb2ZpbGVzX2RmW1tpXV0gPC0gZGF0YS5mcmFtZShjc19wcm9maWxlc19kZltbaV1dKQ0KICB9DQp9DQpgYGANCg0KbGV0IG9wIHdlIGhlYmJlbiBkdXMgZHVwbGljYXRlcy4gbWVuc2VuIHN0YWFuIHpvd2VsIGJpaiBjb21wdXRlciBzY2llbmNlIGFscyBiaWogZGF0YSBzY2llbmNlLiANCmBgYHtyLCBldmFsPUZBTFNFfQ0KY3NfcHJvZmlsZXNfZGYyIDwtIGJpbmRfcm93cyhjc19wcm9maWxlc19kZikNCg0KbmFtZXMoY3NfcHJvZmlsZXNfZGYyKVsxXSA8LSAiZ3NfaWQiDQojY3NfZGYgPC0gbmFtZXNfZGZfY29weVshbmFtZXNfZGZfY29weSRnc19pZD09IiIsXQ0KbGVuZ3RoKGNzX2RmJGlkKQ0KZHVwbGljYXRlZChjc19kZiRnc19pZCkNCmNzX2RmW29yZGVyKGNzX2RmJGdzX2lkKSxdDQpjc19kZjIgPC0gZGF0YS5mcmFtZShjYmluZChjc19kZiwgY3NfcHJvZmlsZXNfZGYyKSApDQpuYW1lc19kZiA8LSBjc19kZjINCg0KYGBgDQoNCg0KYGBge3IsIGV2YWw9RkFMU0V9DQoNCnNhdmUobmFtZXNfZGYsIGZpbGU9Ii4vZGF0YS9uYW1lc19kZjJfdjIwMjIwMTA2LlJEYXRhIikNCg0KYGBgDQoNCg0KIyBjaXRhdGlvbiBoaXN0b3J5DQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KY3NfZGYgPC0gY3NfZGYyDQpgYGANCg0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCiMgZ2V0IGNpdGF0aW9uIGhpc3Rvcnkgb2YgYSBzY2hvbGFyDQpjc19zdGFmZl9jaXQgPC0gbGlzdCgpDQpgYGANCg0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCnRpbWUgPC0gLjEgIyBJIHBsYWNlZCB0aGUgd2FpdGluZyB0aW1lIG91dHNpZGUgdGhlIGxvb3ANCmkgPC0gMSAjIE91ciBsb29wIGl0ZXJhdG9yIGlzIG5vdyBhIHZhcmlhYmxlLiBUaGlzIG1lYW5zIEkgY2FuIGNoYW5nZSBpdCB3aXRoaW4gYSB3aGlsZSBsb29wLiBVc2luZyBhIGZvciBsb29wIHlvdSBjYW50IGNoYW5nZSB5b3VyIGl0ZXJhdG9yIGluIHRoZSBsb29wIGl0c2VsZi4NCmBgYA0KDQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0Kd2hpbGUgKGkgPD0gbnJvdyhjc19kZikpIHsNCiAgICBwcmludChpKQ0KICAgIFN5cy5zbGVlcCh0aW1lKQ0KDQogICAgdHJ5Q2F0Y2goew0KICAgICAgY3Nfc3RhZmZfY2l0W1tpXV0gPC0gZ2V0X2NpdGF0aW9uX2hpc3RvcnkoY3NfZGZbaSwgYygiZ3NfaWQiKV0pDQogICAgICAgIGlmIChucm93KGNzX3N0YWZmX2NpdFtbaV1dKSA+IDApIHsNCiAgICAgICAgICBjc19zdGFmZl9jaXRbW2ldXVssIGMoImdzX2lkIildIDwtIGNzX2RmW2ksIGMoImdzX2lkIildICAjIGFnYWluIGF0dGFjaCB0aGUgZ3NfaWQgYXMgdGhpcmQgY29sdW1uDQogICAgICAgIH0NCiAgICBpIDwtIGkgKyAxDQogICAgdGltZSA8LSAuMQ0KICAgIH0sDQogICAgICB3YXJuaW5nID0gZnVuY3Rpb24odykgew0KICAgICAgICBjYXQoIldBUk5JTkc6IiwgY29uZGl0aW9uTWVzc2FnZSh3KSwgIlxuIikgI1dBUk5JTkcgbWVzc2FnZQ0KICAgICAgICBpIDw8LSBpICsgMX0sICNCVVQgV0UgRE8gV0FOVCBUTyBDT05USU5VRS4gTk9URSBUSEUgRE9VQkxFIDw8IFRISVMgSVMgQkVDQVVTRSBJIFdBTlQgVE8gQ0hBTkdFIEEgVkFSSUFCTEUgV0hJQ0ggRVhJU1RTIE9VVFNJREUgVEhFIFdBUk5JTkcgRlVOQ1RJT04NCiAgICAgIGVycm9yID1mdW5jdGlvbihlKSB7DQogICAgICAgIHRpbWUgPDwtIG1pbih0aW1lICsgMTAsIDM2MDAqMikNCiAgICAgICAgY2F0KCJFcnJvcjoiLCBjb25kaXRpb25NZXNzYWdlKGUpLCAiXG4iKSAjRVJST1IgbWVzc2FnZQ0KICAgICAgICBjYXQoInNsZWVwIHRpbWU6IiwgdGltZSwgICJcbiIpDQogICAgICAgIGNhdCgiaWsgeml0IGluIGxvb3AiLCBpKQ0KICAgICAgICAjQUZURVIgVEhFIE5FVyBTTEVFUCBUSU1FLCBXRSBUUlkgQUdBSU4sIFdFIFRIRVJFRk9SRSBETyBOT1QgVVBEQVRFIGkuIGlkZWFsbHkgeW91IGFsc28gd2FudCB0byBoYXZlIHNvbWUgYnJlYWsgb3B0aW9uLiBBbmQgbWF5YmUgeW91IGFsc28gd2FudCB0byBzYXZlIHlvdXIgZGF0YSB3aGVuIHlvdSBoaXQgYSB0aW1lIG91dCBlcnJvci4gDQogICAgICB9KQ0KDQogICAgDQp9DQpuYW1lc19zdGFmZl9jaXQgPC0gYmluZF9yb3dzKGNzX3N0YWZmX2NpdCkNCg0KYGBgDQoNCg0KYGBge3IsIGV2YWw9RkFMU0V9DQpzYXZlKG5hbWVzX3N0YWZmX2NpdCwgZmlsZT0iLi9kYXRhL25hbWVzX3N0YWZmX2NpdF92MjAyMjEwMDYuUkRhdGEiKQ0KDQpgYGANCg0K