Scrape names &
collabs
#########################################
# Title: Webscraping in R
# Author: Bas Hofstra
# Version: 29-07-2021
#########################################
#start with clean workspace
rm(list=ls())
# install.packages("data.table")
library(data.table) # mainly for faster data handling
library(tidyverse) # I assume you already installed this one!
# install.packages("httr") # we don't need this for now
# require(httr)
#install.packages("xml2")
require(xml2)
#install.packages("rvest")
require(rvest)
#install.packages("devtools")
require(devtools)
# Note we're doing something different here. We're installing a *latest* version directly from GitHub
# This is because the released version of this packages contains some errors!
#devtools::install_github("jkeirstead/scholar")
require(scholar)
#define workdirectory, note the double *backslashes* if you're on windows
# setwd("/yourpathhere)"
# Let's first get the staff page read_html is a function that simply extracts html webpages and
# puts them in xml format
data_staff <- read_html("https://www.cs.ru.nl/das/staff/index.html")
head(data_staff)
class(data_staff)
The website of the data science department looks different. It turns
out that the names, emails and pictures are written as javascript, so
this is not possible to scrape how we learnt it. After a lot of googling
and trying, the following script seemed to work.
#Here I need to install the extra package V8 which is able to read java data.
#Loading both the required libraries
#library(rvest)
#install.packages("V8")
library(V8)
#URL with js-rendered content to be scraped
link <- 'https://www.cs.ru.nl/das/staff/index.html'
#Read the html page content and extract all javascript codes that are inside a list
#The names are stored after the bit of html that ends with javascript.
namesjs <- read_html(link) %>% html_nodes('script') %>% html_text()
# Create a new v8 context
ct <- v8()
#This part gave me an error, something about undefined is not found. However, I saw that some data was stored in namesjs (the javascript names) already. So I moved on to the next chunk.
#parse the html content from the js output and print it as text
read_html(ct$eval(gsub('document.write', namesjs))) %>%
html_text()
#This is to clear the data a little bit more.
data_staff <- namesjs %>%
gsub("[\n\t]", "", .) %>%
stringr::str_trim() %>%
gsub("\\s+", " ", .) %>%
strsplit(" ") %>%
unlist()
#Then I made data_staff (based on the javascript names) a dataframe.
data_staff <- as.data.frame(data_staff)
#Now I only have one column and everything is stored underneath each other. Now I have to see how I can make that normal-looking data. The first 15 can be just deleted as these were almost empty columns.
data_staff <- data_staff[-c (1:15), , drop=FALSE]
#Now I can look whether there are certain patterns I detect in the data. Now I also have all the email-adresses stored and I don't need those.
data_staff1 <- data_staff[!grepl("@|jpg|png", data_staff$data_staff), ]
data_staff1 <- as.data.frame(data_staff1)
data_staff <- data_staff1[c(1:160), , drop=FALSE]
All the above code didn’t help me, so I had to just put the names in
a dataframe.
#Okay for the sake of time I have to create a dataframe with their names by hand. (h for handcoded). I wont include guest researchers as they may not have Radboud as affiliation and for sociology those are excluded as well.
first_name <- c("tom", "djoerd", "martha", "david", "elena", "arjen", "nico", "theo", "johannes", "tom", "perry", "faegheh", "twan", "harrie", "marieke", "gabriel", "parisa", "yuliya", "gijs", "inge", "jacopo", "ankur", "zaheer", "roel", "franka", "kai", "koen", "mirthe", "luc", "emma", "negin", "hideaki", "chris", "alex", "norman", "simone", "zhuoran","konrad", "marvin", "gido", "bob", "shabaz", "wieske", "yao", "nik", "ivan", "feri", "errol", "zhengyu")
last_name <- c("heskes", "hiemstra", "larson", "van leeuwen", "marchiori", "de vries", "karssemeijer", "van der weide", "textor", "claassen", "groot", "hasibi", "van laarhoven", "oosterhuis", "de vries", "bucur", "naseri", "shapovalova", "van tulder", "wortel", "acquarelli", "ankan", "babar", "bouman", "buytenhuijs", "chen", "dercksen", "van diepen", "evers", "gerritse", "ghasemitaheri", "joko", "kamphuis", "kolmus", "knyazev", "lederer", "liu", "mielke", "oeben", "schoenmacker", "stienen", "sultan", "de swart", "tong", "vaessen", "veul", "wijayanto", "zalmijn", "zhao")
data_staffh <- data.frame(first_name, last_name)
# set affiliation to radboud, comes in handy for querying google scholar
data_staffh$affiliation <- "radboud university"
#require(scholar)
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)
}
# Look throught get_scholar_id_fix(last_name, first_name, affiliation)
# if we can find google scholar profiles of sociology staff!
#Turns out 17 people data science do not have a google scholar id. Leaves us with 32 people.
data_staffh$gs_id <- ""
for (i in 1:nrow(data_staffh)) {
print(i)
time <- runif(1, 0, 1)
Sys.sleep(time)
tryCatch({
data_staffh[i,c("gs_id")] <- get_scholar_id_fix(last_name = data_staffh[i, c("last_name")], # so search on last_name of staff (third column)
first_name = data_staffh[i, c("first_name")], # search on first_name of staff (fourth column)
affiliation = data_staffh[i,c("affiliation")]) # search on affiliation of each staff (fifth column)
}, error=function(e){cat("ERROR :", conditionMessage(e), "\n")}) # continue on error, but print the error
}
# remove those without pubs from the df
data_staffh <- data_staffh[!data_staffh$gs_id == "", ]
data_staffh
data_list_profiles <- list() # first we create an empty list that we then fill up with the for loop
data_list_publications <- list()
for (i in 1:nrow(data_staffh)) {
print(i)
time <- runif(1, 0, 1)
Sys.sleep(time)
# note how you call different elements in a list '[[]]', fill in the i-th element
data_list_profiles[[i]] <- get_profile(data_staffh[i, c("gs_id")]) # Note how we call row i (remember how to call rows in a DF/Matrix) and then the associated scholar id
data_list_publications[[i]] <- get_publications(data_staffh[i, c("gs_id")])
data_list_publications[[i]][, c("gs_id")] <- data_staffh[i, c("gs_id")] # note that we again attach an id
# so both functions here call the entire profile and pubs for an author, based on google
# scholar ids
}
# Notice how fast the data blow up! The 34 RU sociology scholars publish ~3000 papers
data_df_publications <- bind_rows(data_list_publications)
data_profiles_df <- list()
for (i in 1:length(data_list_profiles)) {
# soc_profiles_df[[i]] <- data.frame(t(unlist(soc_list_profiles[[i]][1:8]))) #some annyoing
# data handling
data_profiles_df[[i]] <- unlist(data_list_profiles[[i]][1:8])
data_profiles_df[[i]] <- data.frame(data_profiles_df[[i]])
data_profiles_df[[i]] <- data.frame(t(data_profiles_df[[i]]))
}
data_profiles_df <- bind_rows(data_profiles_df)
data_df <- left_join(data_staffh, data_profiles_df, by = c(gs_id = "id")) # merge data with soc_df
data_df # notice all the new information we were able to get from the scholar profiles!
# get citation history of a scholar
data_staff_cit <- list()
for (i in 1:nrow(datadef_df)) {
data_staff_cit[[i]] <- get_citation_history(datadef_df[i, c("gs_id")])
if (nrow(data_staff_cit[[i]]) > 0) {
data_staff_cit[[i]][, c("gs_id")] <- datadef_df[i, c("gs_id")] # again attach the gs_id as third column
}
}
data_staff_cit <- bind_rows(data_staff_cit)
colnames(data_staff_cit)[3] <- "gs_id"
save(data_staff_cit, file="/Users/anuschka/Documents/labjournal/data/data_staff_cit.RData")
require(rvest)
require(xml2)
require(tidyverse)
# function to get collaborators and names from GS profiles
fcollabs <- function(gsid, lookforcollabs) {
htmlpage1 <- read_html(paste0("https://scholar.google.nl/citations?user=", gsid, "&hl=en")) # so we paste the google scholar id
profilename <- htmlpage1 %>% html_nodes(xpath = "//*/div[@id='gsc_prf_in']") %>% html_text() # we extract the profile name of that google scholar page
profilecollabs1 <- as.data.frame(0) # empty df necessary for later
profilecollabs2 <- as.data.frame(0) # empty df necessary for later
if (lookforcollabs == 1) { # so if you want to look for collabs, set function to 1
htmlpage2 <- read_html(paste0("https://scholar.google.com/citations?view_op=list_colleagues&hl=en&user=", gsid)) # so we paste the google scholar id
profilecollabs1 <- htmlpage2 %>% html_nodes(css="h3") %>% html_text() # get names
profilecollabs1 <- as.data.frame(profilecollabs1)
profilecollabs2 <- htmlpage2 %>% html_nodes("a") %>% html_attr("href") # get the link
profilecollabs2 <- profilecollabs2[seq_along(profilecollabs2) %% 2 > 0]
profilecollabs2 <- substring(profilecollabs2, 23)
}
if (nrow(profilecollabs1)>1) { # if there ARE collabs
profilecollabs1 <- as.data.frame(profilecollabs1) # we want to...
profilecollabs2 <- as.data.frame(profilecollabs2)
profilecollabs1[,c("coauth_id")] <- profilecollabs2[,1]
profilecollabs1[,c("gs_id")] <- gsid #... add gs_ids of focal GS profile
profilecollabs1[,c("name")] <- profilename #...and the the profile name of GS profile attached
names(profilecollabs1)[1] <- "coauth"
} else {
profilecollabs1 <- as.data.frame(cbind(gsid, profilename)) # if NOT looking for collabs...
names(profilecollabs1) <- c("gs_id", "name") #...we only attach gs_id and profilename
}
return(profilecollabs1)
}
save(data_df, file = "addfiles\\data_df.RData")
# first the soc collaborators note how we already build a function (fcollabs()) for you you need to
# input a google scholar id and a 1 (if you want to find collabs) or 0 (only extracting names)
# fcollabs --> you can check it out if you're interested
data_collabs <- list()
for (i in 1:nrow(data_df)) {
time <- runif(1, 0, 1)
Sys.sleep(time)
data_collabs[[i]] <- fcollabs(data_df[i, c("gs_id")], 1)
}
data_collabs <- bind_rows(data_collabs) # bind rows, get the unique ones!
data_collabs_unique <- unique(data_collabs[, "coauth_id"]) # so 229 unique collaborators for RU staff?
data_collabs_unique <- data_collabs_unique[!is.na(data_collabs_unique)]
save(data_collabs, file = "addfiles\\data_df_collabs1.RData") # you notice this takes a while, so we save the data here.
# then the names of those collaborators plus THEIR collaborators understand that we don't have
# names of them yet from the code above?
collabsdata_1deep <- list()
for (i in 1:length(data_collabs_unique)) {
time <- runif(1, 0, 3)
Sys.sleep(time)
if (!data_collabs_unique[i] %in% data_df$gs_id) {
collabsdata_1deep[[i]] <- fcollabs(data_collabs_unique[i], 1)
}
}
collabsdata_1deep <- bind_rows(collabsdata_1deep)
collabsdata_1deep_unique <- unique(collabsdata_1deep[, 2])
collabsdata_1deep_unique <- collabsdata_1deep_unique[!is.na(collabsdata_1deep_unique)]
save(collabsdata_1deep, file = "addfiles\\data_collabs2.RData") # you notice this takes a while, so we save the data here.
fgender <- function(firstname_df, me, file=NULL) {
####################################
# Author: Bas Hofstra, Anne Maaike Mulders, Jochem Tolsma
# DAte: 13-10-2021, last edit: 22-09-2022
# Tasks: - assign gender baed on name
# - Adapted from Rense Corten code April 2021
####################################
#Input:
# - firstname_df: a data.frame with a column named firstname and gender!
# - me: a character vector introducing yourself: e.g. "J Tolsma, Radboud University"
# - file: location and name of file to be saved.
#------------------------------------------------------------------------------------
# Load required packages
if (!require("tidyverse", character.only = TRUE)) {
install.packages("tidyverse", dependencies = TRUE)
library(tidyverse, character.only = TRUE)
}
if (!require("rvest", character.only = TRUE)) {
install.packages("rvest", dependencies = TRUE)
library(rvest, character.only = TRUE)
}
if (!require("polite", character.only = TRUE)) {
install.packages("polite", dependencies = TRUE)
library(polite, character.only = TRUE)
}
# make links to scrape
firstname_df$name_url <- paste0("https://www.meertens.knaw.nl/nvb/naam/is/", firstname_df[, c("firstname")])
#------------------------------------------------------------------------------------
### 2: introduce to server ###
# Introduce myself to the server
session <- bow("https://www.meertens.knaw.nl/nvb/naam/is", user_agent = me , delay = 1)
#------------------------------------------------------------------------------------
### 3: make function to get table from ###
fnames <- function(link){
name_session <-nod(session, path = link)
name_page <- scrape(name_session)
return(name_page)
}
name_list <- list()
table_list <- list()
for (i in 1:nrow(firstname_df)) {
print(i)
if (!(is.na(firstname_df$gender))) next
name_list[[i]] <- fnames(firstname_df[i, c("name_url")])
# extract name frequency table and gender info
if (length(name_list[[i]] %>% html_table())>0) {
table_list[[i]] <- name_list[[i]] %>% html_table()
table_list[[i]][[1]][table_list[[i]][[1]]=="--"] <- "0"
if (as.numeric(table_list[[i]][[1]]$X3[2]) > as.numeric(table_list[[i]][[1]]$X3[6])) {
firstname_df$gender[i] <- "male" } else {
firstname_df$gender[i] <- "female"
}
}
if (!is.null(file)) (save(firstname_df, file=file))
}
return(firstname_df)
}
data_df %>% mutate(firstname=first_name) -> data_df
data_df$gender <- NA
#GIVES ERROR
data_df$firstname
data_df <- fgender(data_df, me="Jochem Tolsma, RU/RUG", file="tempgender_data_d2.RData")
save(cs_df, file="cs_df_s2b.RData") #genderized last.
Ethnicity
data_df %>% mutate(lastname=last_name) -> data_df
lastname_df <- data_df
#voorvoegsels correct zetten voor scraper
voorvoegsels <- c("'t ", "d' ", "de ", "de la ", "den ", "del ", "der ", "des ", "el ", "el- ", "in 't ", "la ", "le ", "les ", "op den ", "ten ", "ter ", "tes ", "van ", "van 't ", "van de " , "van der ", "van den ", "von der ", "op den ", "ul ")
for (i in 1: length(lastname_df$lastname)) {
if (sum(str_detect(lastname_df$lastname[i], voorvoegsels))>0) {
last <- as.character(str_split(lastname_df$lastname[i], pattern=" ", simplify = TRUE))
last <- last[length(last)]
first <- as.character(unlist(strsplit(lastname_df$lastname[i], split=last, fixed=TRUE)))
lastname_df$lastname[i] <- paste(last, ", ", first, sep="")
}
}
#dubbele namen verwijderen. let op dubbele namen met voorvoegsel worden niet gecleaned. TO DO
for (i in 1: length(lastname_df$lastname)) {
if (!sum(str_detect(lastname_df$lastname[i], voorvoegsels))>0) {
lastname_df$lastname[i] <- as.character(str_split(lastname_df$lastname[i], pattern=" ", n = 2, simplify = TRUE)[,1])
lastname_df$lastname[i] <- as.character(str_split(lastname_df$lastname[i], pattern="-", n = 2, simplify = TRUE)[,1])
}
}
lastname_df$lastname<- trimws(lastname_df$lastname, which = c("right"), whitespace = "[ \t\r\n]")
lastname_df$lastname <- str_replace_all(lastname_df$lastname, " ", "%20") #html links houden niet van spaties.
lastname_df$np <- ""
# Load required packages
if (!require("tidyverse", character.only = TRUE)) {
install.packages("tidyverse", dependencies = TRUE)
library(tidyverse, character.only = TRUE)
}
if (!require("rvest", character.only = TRUE)) {
install.packages("rvest", dependencies = TRUE)
library(rvest, character.only = TRUE)
}
# if (!require("polite", character.only = TRUE)) {
# install.packages("polite", dependencies = TRUE)
# library(polite, character.only = TRUE)
# }
#
# if (!require("xml2", character.only = TRUE)) {
# install.packages("xml2", dependencies = TRUE)
# library(polite, character.only = TRUE)
# }
hier maken we de links voor de website.
# creating URLs: origin
lastname_df$name_origin <- ifelse((lastname_df$np==""),
paste0("https://www.cbgfamilienamen.nl/nfb/detail_naam.php?gba_naam=",
stringr::str_to_title(lastname_df[, c("lastname")]),
"&gba_naam=",
stringr::str_to_title(lastname_df[, c("lastname")]),
"&nfd_naam=",
stringr::str_to_title(lastname_df[, c("lastname")]),
"&info=analyse+en+verklaring&operator=eq&taal="),
paste0("https://www.cbgfamilienamen.nl/nfb/detail_naam.php?gba_naam=",
lastname_df[, c("np2")],
stringr::str_to_title(lastname_df[, c("lastname")]),
"&gba_naam=",
lastname_df[, c("np2")],
stringr::str_to_title(lastname_df[, c("lastname")]),
"&nfd_naam=",
stringr::str_to_title(lastname_df[, c("lastname")]),
"%2C+",
lastname_df[, c("np")],
"&info=analyse+en+verklaring&operator=eq&taal="))
hier slaan we alles op
name_originl <- list()
table_originl <- list()
time <- 0.1
LS0tCnRpdGxlOiAiV2Vic2NyYXBpbmcgRGF0YSBTY2llbmNlIgphdXRob3I6ICJBbnVzY2hrYSBQZWVsZW4iCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OiBodG1sX2RvY3VtZW50Ci0tLQoKCmBgYHtyIHdhcm5pbmc9RkFMU0UsIGdsb2JhbHNldHRpbmdzLCBlY2hvPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30KbGlicmFyeShrbml0cikKCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkKb3B0c19jaHVuayRzZXQodGlkeS5vcHRzPWxpc3Qod2lkdGguY3V0b2ZmPTEwMCksdGlkeT1UUlVFLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSxjb21tZW50ID0gIiM+IiwgY2FjaGU9VFJVRSwgY2xhc3Muc291cmNlPWMoInRlc3QiKSwgY2xhc3Mub3V0cHV0PWMoInRlc3QyIikpCm9wdGlvbnMod2lkdGggPSAxMDApCnJnbDo6c2V0dXBLbml0cigpCgoKCmNvbG9yaXplIDwtIGZ1bmN0aW9uKHgsIGNvbG9yKSB7c3ByaW50ZigiPHNwYW4gc3R5bGU9J2NvbG9yOiAlczsnPiVzPC9zcGFuPiIsIGNvbG9yLCB4KSB9CmBgYAoKYGBge3Iga2xpcHB5LCBlY2hvPUZBTFNFLCBpbmNsdWRlPVRSVUV9CmtsaXBweTo6a2xpcHB5KHBvc2l0aW9uID0gYygndG9wJywgJ3JpZ2h0JykpCiNrbGlwcHk6OmtsaXBweShjb2xvciA9ICdkYXJrcmVkJykKI2tsaXBweTo6a2xpcHB5KHRvb2x0aXBfbWVzc2FnZSA9ICdDbGljayB0byBjb3B5JywgdG9vbHRpcF9zdWNjZXNzID0gJ0RvbmUnKQpgYGAKCiMgU2NyYXBlIG5hbWVzICYgY29sbGFicwpgYGB7ciwgZXZhbD1GQUxTRX0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBUaXRsZTogICAgV2Vic2NyYXBpbmcgaW4gUgojIEF1dGhvcjogICBCYXMgSG9mc3RyYQojIFZlcnNpb246ICAyOS0wNy0yMDIxCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgojc3RhcnQgd2l0aCBjbGVhbiB3b3Jrc3BhY2UgCnJtKGxpc3Q9bHMoKSkKCiMgaW5zdGFsbC5wYWNrYWdlcygiZGF0YS50YWJsZSIpIApsaWJyYXJ5KGRhdGEudGFibGUpICMgbWFpbmx5IGZvciBmYXN0ZXIgZGF0YSBoYW5kbGluZwpsaWJyYXJ5KHRpZHl2ZXJzZSkgIyBJIGFzc3VtZSB5b3UgYWxyZWFkeSBpbnN0YWxsZWQgdGhpcyBvbmUhCiMgaW5zdGFsbC5wYWNrYWdlcygiaHR0ciIpICMgd2UgZG9uJ3QgbmVlZCB0aGlzIGZvciBub3cKIyByZXF1aXJlKGh0dHIpCiNpbnN0YWxsLnBhY2thZ2VzKCJ4bWwyIikKcmVxdWlyZSh4bWwyKQojaW5zdGFsbC5wYWNrYWdlcygicnZlc3QiKQpyZXF1aXJlKHJ2ZXN0KQojaW5zdGFsbC5wYWNrYWdlcygiZGV2dG9vbHMiKQpyZXF1aXJlKGRldnRvb2xzKQojIE5vdGUgd2UncmUgZG9pbmcgc29tZXRoaW5nIGRpZmZlcmVudCBoZXJlLiBXZSdyZSBpbnN0YWxsaW5nIGEgKmxhdGVzdCogdmVyc2lvbiBkaXJlY3RseSBmcm9tIEdpdEh1YgojIFRoaXMgaXMgYmVjYXVzZSB0aGUgcmVsZWFzZWQgdmVyc2lvbiBvZiB0aGlzIHBhY2thZ2VzIGNvbnRhaW5zIHNvbWUgZXJyb3JzIQojZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJqa2VpcnN0ZWFkL3NjaG9sYXIiKSAKCgpyZXF1aXJlKHNjaG9sYXIpCgojZGVmaW5lIHdvcmtkaXJlY3RvcnksIG5vdGUgdGhlIGRvdWJsZSAqYmFja3NsYXNoZXMqIGlmIHlvdSdyZSBvbiB3aW5kb3dzCiMgc2V0d2QoIi95b3VycGF0aGhlcmUpIgpgYGAKCgpgYGB7ciwgZXZhbD1GQUxTRX0KIyBMZXQncyBmaXJzdCBnZXQgdGhlIHN0YWZmIHBhZ2UgcmVhZF9odG1sIGlzIGEgZnVuY3Rpb24gdGhhdCBzaW1wbHkgZXh0cmFjdHMgaHRtbCB3ZWJwYWdlcyBhbmQKIyBwdXRzIHRoZW0gaW4geG1sIGZvcm1hdApkYXRhX3N0YWZmIDwtIHJlYWRfaHRtbCgiaHR0cHM6Ly93d3cuY3MucnUubmwvZGFzL3N0YWZmL2luZGV4Lmh0bWwiKQoKaGVhZChkYXRhX3N0YWZmKQoKY2xhc3MoZGF0YV9zdGFmZikKYGBgCgpUaGUgd2Vic2l0ZSBvZiB0aGUgZGF0YSBzY2llbmNlIGRlcGFydG1lbnQgbG9va3MgZGlmZmVyZW50LiBJdCB0dXJucyBvdXQgdGhhdCB0aGUgbmFtZXMsIGVtYWlscyBhbmQgcGljdHVyZXMgYXJlIHdyaXR0ZW4gYXMgamF2YXNjcmlwdCwgc28gdGhpcyBpcyBub3QgcG9zc2libGUgdG8gc2NyYXBlIGhvdyB3ZSBsZWFybnQgaXQuIEFmdGVyIGEgbG90IG9mIGdvb2dsaW5nIGFuZCB0cnlpbmcsIHRoZSBmb2xsb3dpbmcgc2NyaXB0IHNlZW1lZCB0byB3b3JrLiAKCmBgYHtyLCBldmFsPUZBTFNFfQojSGVyZSBJIG5lZWQgdG8gaW5zdGFsbCB0aGUgZXh0cmEgcGFja2FnZSBWOCB3aGljaCBpcyBhYmxlIHRvIHJlYWQgamF2YSBkYXRhLiAKI0xvYWRpbmcgYm90aCB0aGUgcmVxdWlyZWQgbGlicmFyaWVzCiNsaWJyYXJ5KHJ2ZXN0KQojaW5zdGFsbC5wYWNrYWdlcygiVjgiKQpsaWJyYXJ5KFY4KQpgYGAKCmBgYHtyLCBldmFsPUZBTFNFfQojVVJMIHdpdGgganMtcmVuZGVyZWQgY29udGVudCB0byBiZSBzY3JhcGVkCmxpbmsgPC0gJ2h0dHBzOi8vd3d3LmNzLnJ1Lm5sL2Rhcy9zdGFmZi9pbmRleC5odG1sJwoKI1JlYWQgdGhlIGh0bWwgcGFnZSBjb250ZW50IGFuZCBleHRyYWN0IGFsbCBqYXZhc2NyaXB0IGNvZGVzIHRoYXQgYXJlIGluc2lkZSBhIGxpc3QKI1RoZSBuYW1lcyBhcmUgc3RvcmVkIGFmdGVyIHRoZSBiaXQgb2YgaHRtbCB0aGF0IGVuZHMgd2l0aCBqYXZhc2NyaXB0LgpuYW1lc2pzIDwtIHJlYWRfaHRtbChsaW5rKSAgJT4lIGh0bWxfbm9kZXMoJ3NjcmlwdCcpICU+JSBodG1sX3RleHQoKQoKIyBDcmVhdGUgYSBuZXcgdjggY29udGV4dApjdCA8LSB2OCgpCmBgYAoKCmBgYHtyLCBldmFsPUZBTFNFfQojVGhpcyBwYXJ0IGdhdmUgbWUgYW4gZXJyb3IsIHNvbWV0aGluZyBhYm91dCB1bmRlZmluZWQgaXMgbm90IGZvdW5kLiBIb3dldmVyLCBJIHNhdyB0aGF0IHNvbWUgZGF0YSB3YXMgc3RvcmVkIGluIG5hbWVzanMgKHRoZSBqYXZhc2NyaXB0IG5hbWVzKSBhbHJlYWR5LiBTbyBJIG1vdmVkIG9uIHRvIHRoZSBuZXh0IGNodW5rLiAKI3BhcnNlIHRoZSBodG1sIGNvbnRlbnQgZnJvbSB0aGUganMgb3V0cHV0IGFuZCBwcmludCBpdCBhcyB0ZXh0CnJlYWRfaHRtbChjdCRldmFsKGdzdWIoJ2RvY3VtZW50LndyaXRlJywgbmFtZXNqcykpKSAlPiUgCiBodG1sX3RleHQoKQpgYGAKCmBgYHtyLCBldmFsPUZBTFNFfQojVGhpcyBpcyB0byBjbGVhciB0aGUgZGF0YSBhIGxpdHRsZSBiaXQgbW9yZS4gCmRhdGFfc3RhZmYgPC0gbmFtZXNqcyAlPiUgCmdzdWIoIltcblx0XSIsICIiLCAuKSAlPiUKc3RyaW5ncjo6c3RyX3RyaW0oKSAlPiUKZ3N1YigiXFxzKyIsICIgIiwgLikgJT4lCnN0cnNwbGl0KCIgIikgJT4lIAp1bmxpc3QoKQoKYGBgCgpgYGB7ciwgZXZhbD1GQUxTRX0KI1RoZW4gSSBtYWRlIGRhdGFfc3RhZmYgKGJhc2VkIG9uIHRoZSBqYXZhc2NyaXB0IG5hbWVzKSBhIGRhdGFmcmFtZS4gCmRhdGFfc3RhZmYgPC0gYXMuZGF0YS5mcmFtZShkYXRhX3N0YWZmKQoKI05vdyBJIG9ubHkgaGF2ZSBvbmUgY29sdW1uIGFuZCBldmVyeXRoaW5nIGlzIHN0b3JlZCB1bmRlcm5lYXRoIGVhY2ggb3RoZXIuIE5vdyBJIGhhdmUgdG8gc2VlIGhvdyBJIGNhbiBtYWtlIHRoYXQgbm9ybWFsLWxvb2tpbmcgZGF0YS4gVGhlIGZpcnN0IDE1IGNhbiBiZSBqdXN0IGRlbGV0ZWQgYXMgdGhlc2Ugd2VyZSBhbG1vc3QgZW1wdHkgY29sdW1ucy4gCmRhdGFfc3RhZmYgPC0gZGF0YV9zdGFmZlstYyAoMToxNSksICwgZHJvcD1GQUxTRV0KCiNOb3cgSSBjYW4gbG9vayB3aGV0aGVyIHRoZXJlIGFyZSBjZXJ0YWluIHBhdHRlcm5zIEkgZGV0ZWN0IGluIHRoZSBkYXRhLiBOb3cgSSBhbHNvIGhhdmUgYWxsIHRoZSBlbWFpbC1hZHJlc3NlcyBzdG9yZWQgYW5kIEkgZG9uJ3QgbmVlZCB0aG9zZS4gCmRhdGFfc3RhZmYxIDwtIGRhdGFfc3RhZmZbIWdyZXBsKCJAfGpwZ3xwbmciLCBkYXRhX3N0YWZmJGRhdGFfc3RhZmYpLCBdCmRhdGFfc3RhZmYxIDwtIGFzLmRhdGEuZnJhbWUoZGF0YV9zdGFmZjEpCmRhdGFfc3RhZmYgPC0gZGF0YV9zdGFmZjFbYygxOjE2MCksICwgZHJvcD1GQUxTRV0KCgpgYGAKCkFsbCB0aGUgYWJvdmUgY29kZSBkaWRuJ3QgaGVscCBtZSwgc28gSSBoYWQgdG8ganVzdCBwdXQgdGhlIG5hbWVzIGluIGEgZGF0YWZyYW1lLiAKCmBgYHtyLCBldmFsPUZBTFNFfQojT2theSBmb3IgdGhlIHNha2Ugb2YgdGltZSBJIGhhdmUgdG8gY3JlYXRlIGEgZGF0YWZyYW1lIHdpdGggdGhlaXIgbmFtZXMgYnkgaGFuZC4gKGggZm9yIGhhbmRjb2RlZCkuIEkgd29udCBpbmNsdWRlIGd1ZXN0IHJlc2VhcmNoZXJzIGFzIHRoZXkgbWF5IG5vdCBoYXZlIFJhZGJvdWQgYXMgYWZmaWxpYXRpb24gYW5kIGZvciBzb2Npb2xvZ3kgdGhvc2UgYXJlIGV4Y2x1ZGVkIGFzIHdlbGwuCmZpcnN0X25hbWUgPC0gYygidG9tIiwgImRqb2VyZCIsICJtYXJ0aGEiLCAiZGF2aWQiLCAiZWxlbmEiLCAiYXJqZW4iLCAibmljbyIsICJ0aGVvIiwgImpvaGFubmVzIiwgInRvbSIsICJwZXJyeSIsICJmYWVnaGVoIiwgInR3YW4iLCAiaGFycmllIiwgIm1hcmlla2UiLCAiZ2FicmllbCIsICJwYXJpc2EiLCAieXVsaXlhIiwgImdpanMiLCAiaW5nZSIsICJqYWNvcG8iLCAiYW5rdXIiLCAiemFoZWVyIiwgInJvZWwiLCAiZnJhbmthIiwgImthaSIsICJrb2VuIiwgIm1pcnRoZSIsICJsdWMiLCAiZW1tYSIsICJuZWdpbiIsICJoaWRlYWtpIiwgImNocmlzIiwgImFsZXgiLCAibm9ybWFuIiwgInNpbW9uZSIsICJ6aHVvcmFuIiwia29ucmFkIiwgIm1hcnZpbiIsICJnaWRvIiwgImJvYiIsICJzaGFiYXoiLCAid2llc2tlIiwgInlhbyIsICJuaWsiLCAiaXZhbiIsICJmZXJpIiwgImVycm9sIiwgInpoZW5neXUiKQpsYXN0X25hbWUgPC0gYygiaGVza2VzIiwgImhpZW1zdHJhIiwgImxhcnNvbiIsICJ2YW4gbGVldXdlbiIsICJtYXJjaGlvcmkiLCAiZGUgdnJpZXMiLCAia2Fyc3NlbWVpamVyIiwgInZhbiBkZXIgd2VpZGUiLCAidGV4dG9yIiwgImNsYWFzc2VuIiwgImdyb290IiwgImhhc2liaSIsICJ2YW4gbGFhcmhvdmVuIiwgIm9vc3Rlcmh1aXMiLCAiZGUgdnJpZXMiLCAiYnVjdXIiLCAibmFzZXJpIiwgInNoYXBvdmFsb3ZhIiwgInZhbiB0dWxkZXIiLCAid29ydGVsIiwgImFjcXVhcmVsbGkiLCAiYW5rYW4iLCAiYmFiYXIiLCAiYm91bWFuIiwgImJ1eXRlbmh1aWpzIiwgImNoZW4iLCAiZGVyY2tzZW4iLCAidmFuIGRpZXBlbiIsICJldmVycyIsICJnZXJyaXRzZSIsICJnaGFzZW1pdGFoZXJpIiwgImpva28iLCAia2FtcGh1aXMiLCAia29sbXVzIiwgImtueWF6ZXYiLCAibGVkZXJlciIsICJsaXUiLCAibWllbGtlIiwgIm9lYmVuIiwgInNjaG9lbm1hY2tlciIsICJzdGllbmVuIiwgInN1bHRhbiIsICJkZSBzd2FydCIsICJ0b25nIiwgInZhZXNzZW4iLCAidmV1bCIsICJ3aWpheWFudG8iLCAiemFsbWlqbiIsICJ6aGFvIikKZGF0YV9zdGFmZmggPC0gZGF0YS5mcmFtZShmaXJzdF9uYW1lLCBsYXN0X25hbWUpCmBgYAoKCmBgYHtyLCBldmFsPUZBTFNFfQojIHNldCBhZmZpbGlhdGlvbiB0byByYWRib3VkLCBjb21lcyBpbiBoYW5keSBmb3IgcXVlcnlpbmcgZ29vZ2xlIHNjaG9sYXIKZGF0YV9zdGFmZmgkYWZmaWxpYXRpb24gPC0gInJhZGJvdWQgdW5pdmVyc2l0eSIKYGBgCgoKYGBge3IsIGV2YWw9RkFMU0V9CiNyZXF1aXJlKHNjaG9sYXIpCmdldF9zY2hvbGFyX2lkX2ZpeCA8LSBmdW5jdGlvbiAobGFzdF9uYW1lID0gIiIsIGZpcnN0X25hbWUgPSAiIiwgYWZmaWxpYXRpb24gPSBOQSkKewogIGlmICghYW55KG56Y2hhcihjKGZpcnN0X25hbWUsIGxhc3RfbmFtZSkpKSkKICAgIHN0b3AoIkF0IGxlYXN0IG9uZSBvZiBmaXJzdCBhbmQgbGFzdCBuYW1lIG11c3QgYmUgc3BlY2lmaWVkISIpCiAgc2l0ZSA8LSBnZXRPcHRpb24oInNjaG9sYXJfc2l0ZSIpCiAgdXJsIDwtIHBhc3RlMChzaXRlLCAiL2NpdGF0aW9ucz92aWV3X29wPXNlYXJjaF9hdXRob3JzJm1hdXRob3JzPSIsCiAgICAgICAgICAgICAgICBmaXJzdF9uYW1lLCAiKyIsIGxhc3RfbmFtZSwgIiZobD1lbiZvaT1hbyIpCiAgcGFnZSA8LSBnZXRfc2Nob2xhcl9yZXNwKHVybCkKICBpZiAoaXMubnVsbChwYWdlKSkKICAgIHJldHVybihOQSkKICBhYSA8LSBodHRyOjpjb250ZW50KHBhZ2UsIGFzID0gInRleHQiKQogICMgYWRkZWQgYnkgQmFzIEhvZnN0cmE6IGJ1Z2ZpeCBmb3IgSURzIHRoYXQgaGF2ZSBhIGRhc2ggKCItIikKICBpZHMgPC0gc3Vic3RyaW5nKGFhLCByZWdleHByKCI7dXNlcj0iLCBhYSkpCiAgaWRzIDwtIHN1YnN0cihpZHMsIDEsIDE5KSAjIGVycm9yIHByb25lLCBidXQgdW5zdXJlIGhvdyB0byBzb2x2ZSBvdGhlcndpc2UKICAjIGlmIChuY2hhcihzdHJpbmdyOjpzdHJfZXh0cmFjdF9hbGwoc3RyaW5nID0gYWEsIHBhdHRlcm4gPSAiO3VzZXI9W1s6YWxudW06XV0rW1s6cHVuY3Q6XV0iKVtbMV1dWzFdKSA8IDE4KSB7CiAgIyAgIGlkcyA8LSBzdHJpbmdyOjpzdHJfZXh0cmFjdF9hbGwoc3RyaW5nID0gYWEsIHBhdHRlcm4gPSAiO3VzZXI9W1s6YWxudW06XV0rW1s6cHVuY3Q6XV0rW1s6YWxudW06XV0rW1s6cHVuY3Q6XV0iKQogICMgfSBlbHNlIHsKICAjICAgaWRzIDwtIHN0cmluZ3I6OnN0cl9leHRyYWN0X2FsbChzdHJpbmcgPSBhYSwgcGF0dGVybiA9ICI7dXNlcj1bWzphbG51bTpdXStbWzpwdW5jdDpdXSIpCiAgIyB9CiAgaWYgKGxlbmd0aCh1bmxpc3QoaWRzKSkgPT0gMCkgewogICAgbWVzc2FnZSgiTm8gU2Nob2xhciBJRCBmb3VuZC4iKQogICAgcmV0dXJuKE5BKQogIH0KICBpZHMgPC0gaWRzICU+JSB1bmxpc3QgJT4lIGdzdWIoIjt1c2VyPXxbWzpwdW5jdDpdXSQiLCAiIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLikgJT4lIHVuaXF1ZQogIGlmIChsZW5ndGgoaWRzKSA+IDEpIHsKICAgIHByb2ZpbGVzIDwtIGxhcHBseShpZHMsIHNjaG9sYXI6OmdldF9wcm9maWxlKQogICAgaWYgKGlzLm5hKGFmZmlsaWF0aW9uKSkgewogICAgICB4X3Byb2ZpbGUgPC0gcHJvZmlsZXNbWzFdXQogICAgICB3YXJuaW5nKCJTZWxlY3RpbmcgZmlyc3Qgb3V0IG9mICIsIGxlbmd0aChwcm9maWxlcyksCiAgICAgICAgICAgICAgIiBjYW5kaWRhdGUgbWF0Y2hlcy4iKQogICAgfQogICAgZWxzZSB7CiAgICAgIHdoaWNoX3Byb2ZpbGUgPC0gc2FwcGx5KHByb2ZpbGVzLCBmdW5jdGlvbih4KSB7CiAgICAgICAgc3RyaW5ncjo6c3RyX2NvdW50KHN0cmluZyA9IHgkYWZmaWxpYXRpb24sIHBhdHRlcm4gPSBzdHJpbmdyOjpjb2xsKGFmZmlsaWF0aW9uLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZ25vcmVfY2FzZSA9IFRSVUUpKQogICAgICB9KQogICAgICBpZiAoYWxsKHdoaWNoX3Byb2ZpbGUgPT0gMCkpIHsKICAgICAgICB3YXJuaW5nKCJObyByZXNlYXJjaGVyIGZvdW5kIGF0IHRoZSBpbmRpY2F0ZWQgYWZmaWxpYXRpb24uIikKICAgICAgICByZXR1cm4oTkEpCiAgICAgIH0KICAgICAgZWxzZSB7CiAgICAgICAgeF9wcm9maWxlIDwtIHByb2ZpbGVzW1t3aGljaCh3aGljaF9wcm9maWxlICE9CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDApXV0KICAgICAgfQogICAgfQogIH0KICBlbHNlIHsKICAgIHhfcHJvZmlsZSA8LSBzY2hvbGFyOjpnZXRfcHJvZmlsZShpZCA9IGlkcykKICB9CiAgcmV0dXJuKHhfcHJvZmlsZSRpZCkKfQpgYGAKCgpgYGB7ciwgZXZhbD1GQUxTRX0KIyBMb29rIHRocm91Z2h0IGdldF9zY2hvbGFyX2lkX2ZpeChsYXN0X25hbWUsIGZpcnN0X25hbWUsIGFmZmlsaWF0aW9uKSAKIyBpZiB3ZSBjYW4gZmluZCBnb29nbGUgc2Nob2xhciBwcm9maWxlcyBvZiBzb2Npb2xvZ3kgc3RhZmYhCiNUdXJucyBvdXQgMTcgcGVvcGxlIGRhdGEgc2NpZW5jZSBkbyBub3QgaGF2ZSBhIGdvb2dsZSBzY2hvbGFyIGlkLiBMZWF2ZXMgdXMgd2l0aCAzMiBwZW9wbGUuIApkYXRhX3N0YWZmaCRnc19pZCA8LSAiIgpmb3IgKGkgaW4gMTpucm93KGRhdGFfc3RhZmZoKSkgewogIHByaW50KGkpCiAgdGltZSA8LSBydW5pZigxLCAwLCAxKQogIFN5cy5zbGVlcCh0aW1lKQogIAogIHRyeUNhdGNoKHsKICAgICBkYXRhX3N0YWZmaFtpLGMoImdzX2lkIildIDwtIGdldF9zY2hvbGFyX2lkX2ZpeChsYXN0X25hbWUgPSBkYXRhX3N0YWZmaFtpLCBjKCJsYXN0X25hbWUiKV0sICMgc28gc2VhcmNoIG9uIGxhc3RfbmFtZSBvZiBzdGFmZiAodGhpcmQgY29sdW1uKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaXJzdF9uYW1lID0gZGF0YV9zdGFmZmhbaSwgYygiZmlyc3RfbmFtZSIpXSwgICMgc2VhcmNoIG9uIGZpcnN0X25hbWUgb2Ygc3RhZmYgKGZvdXJ0aCBjb2x1bW4pCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFmZmlsaWF0aW9uID0gZGF0YV9zdGFmZmhbaSxjKCJhZmZpbGlhdGlvbiIpXSkgIyBzZWFyY2ggb24gYWZmaWxpYXRpb24gb2YgZWFjaCBzdGFmZiAoZmlmdGggY29sdW1uKQogICAgfSwgZXJyb3I9ZnVuY3Rpb24oZSl7Y2F0KCJFUlJPUiA6IiwgY29uZGl0aW9uTWVzc2FnZShlKSwgIlxuIil9KSAjIGNvbnRpbnVlIG9uIGVycm9yLCBidXQgcHJpbnQgdGhlIGVycm9yCiAgfQojIHJlbW92ZSB0aG9zZSB3aXRob3V0IHB1YnMgZnJvbSB0aGUgZGYKZGF0YV9zdGFmZmggPC0gZGF0YV9zdGFmZmhbIWRhdGFfc3RhZmZoJGdzX2lkID09ICIiLCBdCmRhdGFfc3RhZmZoCmBgYAoKCmBgYHtyLCBldmFsPUZBTFNFfQpkYXRhX2xpc3RfcHJvZmlsZXMgPC0gbGlzdCgpICAjIGZpcnN0IHdlIGNyZWF0ZSBhbiBlbXB0eSBsaXN0IHRoYXQgd2UgdGhlbiBmaWxsIHVwIHdpdGggdGhlIGZvciBsb29wCmRhdGFfbGlzdF9wdWJsaWNhdGlvbnMgPC0gbGlzdCgpCmZvciAoaSBpbiAxOm5yb3coZGF0YV9zdGFmZmgpKSB7CiAgICBwcmludChpKQogICAgdGltZSA8LSBydW5pZigxLCAwLCAxKQogICAgU3lzLnNsZWVwKHRpbWUpCiAgICAjIG5vdGUgaG93IHlvdSBjYWxsIGRpZmZlcmVudCBlbGVtZW50cyBpbiBhIGxpc3QgJ1tbXV0nLCBmaWxsIGluIHRoZSBpLXRoIGVsZW1lbnQKICAgIGRhdGFfbGlzdF9wcm9maWxlc1tbaV1dIDwtIGdldF9wcm9maWxlKGRhdGFfc3RhZmZoW2ksIGMoImdzX2lkIildKSAgIyBOb3RlIGhvdyB3ZSBjYWxsIHJvdyBpIChyZW1lbWJlciBob3cgdG8gY2FsbCByb3dzIGluIGEgREYvTWF0cml4KSBhbmQgdGhlbiB0aGUgYXNzb2NpYXRlZCBzY2hvbGFyIGlkCiAgICBkYXRhX2xpc3RfcHVibGljYXRpb25zW1tpXV0gPC0gZ2V0X3B1YmxpY2F0aW9ucyhkYXRhX3N0YWZmaFtpLCBjKCJnc19pZCIpXSkKICAgIGRhdGFfbGlzdF9wdWJsaWNhdGlvbnNbW2ldXVssIGMoImdzX2lkIildIDwtIGRhdGFfc3RhZmZoW2ksIGMoImdzX2lkIildICAjIG5vdGUgdGhhdCB3ZSBhZ2FpbiBhdHRhY2ggYW4gaWQKICAgICMgc28gYm90aCBmdW5jdGlvbnMgaGVyZSBjYWxsIHRoZSBlbnRpcmUgcHJvZmlsZSBhbmQgcHVicyBmb3IgYW4gYXV0aG9yLCBiYXNlZCBvbiBnb29nbGUKICAgICMgc2Nob2xhciBpZHMKfQojIE5vdGljZSBob3cgZmFzdCB0aGUgZGF0YSBibG93IHVwISBUaGUgMzQgUlUgc29jaW9sb2d5IHNjaG9sYXJzIHB1Ymxpc2ggfjMwMDAgcGFwZXJzCmRhdGFfZGZfcHVibGljYXRpb25zIDwtIGJpbmRfcm93cyhkYXRhX2xpc3RfcHVibGljYXRpb25zKQpgYGAKCmBgYHtyLCBldmFsPUZBTFNFfQpkYXRhX3Byb2ZpbGVzX2RmIDwtIGxpc3QoKQpmb3IgKGkgaW4gMTpsZW5ndGgoZGF0YV9saXN0X3Byb2ZpbGVzKSkgewogICAgIyBzb2NfcHJvZmlsZXNfZGZbW2ldXSA8LSBkYXRhLmZyYW1lKHQodW5saXN0KHNvY19saXN0X3Byb2ZpbGVzW1tpXV1bMTo4XSkpKSAjc29tZSBhbm55b2luZwogICAgIyBkYXRhIGhhbmRsaW5nCiAgICBkYXRhX3Byb2ZpbGVzX2RmW1tpXV0gPC0gdW5saXN0KGRhdGFfbGlzdF9wcm9maWxlc1tbaV1dWzE6OF0pCiAgICBkYXRhX3Byb2ZpbGVzX2RmW1tpXV0gPC0gZGF0YS5mcmFtZShkYXRhX3Byb2ZpbGVzX2RmW1tpXV0pCiAgICBkYXRhX3Byb2ZpbGVzX2RmW1tpXV0gPC0gZGF0YS5mcmFtZSh0KGRhdGFfcHJvZmlsZXNfZGZbW2ldXSkpCn0KZGF0YV9wcm9maWxlc19kZiA8LSBiaW5kX3Jvd3MoZGF0YV9wcm9maWxlc19kZikKZGF0YV9kZiA8LSBsZWZ0X2pvaW4oZGF0YV9zdGFmZmgsIGRhdGFfcHJvZmlsZXNfZGYsIGJ5ID0gYyhnc19pZCA9ICJpZCIpKSAgIyBtZXJnZSBkYXRhIHdpdGggc29jX2RmCmRhdGFfZGYgICMgbm90aWNlIGFsbCB0aGUgbmV3IGluZm9ybWF0aW9uIHdlIHdlcmUgYWJsZSB0byBnZXQgZnJvbSB0aGUgc2Nob2xhciBwcm9maWxlcyEKYGBgCgpgYGB7ciwgZXZhbD1GQUxTRX0KIyBnZXQgY2l0YXRpb24gaGlzdG9yeSBvZiBhIHNjaG9sYXIKZGF0YV9zdGFmZl9jaXQgPC0gbGlzdCgpCmZvciAoaSBpbiAxOm5yb3coZGF0YWRlZl9kZikpIHsKICAgIGRhdGFfc3RhZmZfY2l0W1tpXV0gPC0gZ2V0X2NpdGF0aW9uX2hpc3RvcnkoZGF0YWRlZl9kZltpLCBjKCJnc19pZCIpXSkKICAgIGlmIChucm93KGRhdGFfc3RhZmZfY2l0W1tpXV0pID4gMCkgewogICAgICAgIGRhdGFfc3RhZmZfY2l0W1tpXV1bLCBjKCJnc19pZCIpXSA8LSBkYXRhZGVmX2RmW2ksIGMoImdzX2lkIildICAjIGFnYWluIGF0dGFjaCB0aGUgZ3NfaWQgYXMgdGhpcmQgY29sdW1uCiAgICB9Cn0KZGF0YV9zdGFmZl9jaXQgPC0gYmluZF9yb3dzKGRhdGFfc3RhZmZfY2l0KQpjb2xuYW1lcyhkYXRhX3N0YWZmX2NpdClbM10gPC0gImdzX2lkIgpgYGAKCmBgYHtyLCBldmFsPUZBTFNFfQpzYXZlKGRhdGFfc3RhZmZfY2l0LCBmaWxlPSIvVXNlcnMvYW51c2Noa2EvRG9jdW1lbnRzL2xhYmpvdXJuYWwvZGF0YS9kYXRhX3N0YWZmX2NpdC5SRGF0YSIpCmBgYAoKCmBgYHtyLCBldmFsPUZBTFNFfQpyZXF1aXJlKHJ2ZXN0KQpyZXF1aXJlKHhtbDIpCnJlcXVpcmUodGlkeXZlcnNlKQojIGZ1bmN0aW9uIHRvIGdldCBjb2xsYWJvcmF0b3JzIGFuZCBuYW1lcyBmcm9tIEdTIHByb2ZpbGVzCmZjb2xsYWJzIDwtIGZ1bmN0aW9uKGdzaWQsIGxvb2tmb3Jjb2xsYWJzKSB7CiAgaHRtbHBhZ2UxIDwtIHJlYWRfaHRtbChwYXN0ZTAoImh0dHBzOi8vc2Nob2xhci5nb29nbGUubmwvY2l0YXRpb25zP3VzZXI9IiwgZ3NpZCwgIiZobD1lbiIpKSAjIHNvIHdlIHBhc3RlIHRoZSBnb29nbGUgc2Nob2xhciBpZAogIHByb2ZpbGVuYW1lIDwtIGh0bWxwYWdlMSAlPiUgaHRtbF9ub2Rlcyh4cGF0aCA9ICIvLyovZGl2W0BpZD0nZ3NjX3ByZl9pbiddIikgJT4lIGh0bWxfdGV4dCgpICMgd2UgZXh0cmFjdCB0aGUgcHJvZmlsZSBuYW1lIG9mIHRoYXQgZ29vZ2xlIHNjaG9sYXIgcGFnZQogIHByb2ZpbGVjb2xsYWJzMSA8LSBhcy5kYXRhLmZyYW1lKDApICMgZW1wdHkgZGYgbmVjZXNzYXJ5IGZvciBsYXRlcgogIHByb2ZpbGVjb2xsYWJzMiA8LSBhcy5kYXRhLmZyYW1lKDApICMgZW1wdHkgZGYgbmVjZXNzYXJ5IGZvciBsYXRlcgogIGlmIChsb29rZm9yY29sbGFicyA9PSAxKSB7ICMgc28gaWYgeW91IHdhbnQgdG8gbG9vayBmb3IgY29sbGFicywgc2V0IGZ1bmN0aW9uIHRvIDEKICAgIGh0bWxwYWdlMiA8LSByZWFkX2h0bWwocGFzdGUwKCJodHRwczovL3NjaG9sYXIuZ29vZ2xlLmNvbS9jaXRhdGlvbnM/dmlld19vcD1saXN0X2NvbGxlYWd1ZXMmaGw9ZW4mdXNlcj0iLCBnc2lkKSkgIyBzbyB3ZSBwYXN0ZSB0aGUgZ29vZ2xlIHNjaG9sYXIgaWQKICAgIHByb2ZpbGVjb2xsYWJzMSA8LSAgaHRtbHBhZ2UyICU+JSBodG1sX25vZGVzKGNzcz0iaDMiKSAlPiUgaHRtbF90ZXh0KCkgIyBnZXQgbmFtZXMKICAgIHByb2ZpbGVjb2xsYWJzMSA8LSAgYXMuZGF0YS5mcmFtZShwcm9maWxlY29sbGFiczEpCiAgICBwcm9maWxlY29sbGFiczIgPC0gaHRtbHBhZ2UyICU+JSBodG1sX25vZGVzKCJhIikgJT4lIGh0bWxfYXR0cigiaHJlZiIpICMgZ2V0IHRoZSBsaW5rCiAgICBwcm9maWxlY29sbGFiczIgPC0gcHJvZmlsZWNvbGxhYnMyW3NlcV9hbG9uZyhwcm9maWxlY29sbGFiczIpICUlIDIgPiAwXQogICAgcHJvZmlsZWNvbGxhYnMyIDwtIHN1YnN0cmluZyhwcm9maWxlY29sbGFiczIsIDIzKQogIH0KICBpZiAobnJvdyhwcm9maWxlY29sbGFiczEpPjEpIHsgIyBpZiB0aGVyZSBBUkUgY29sbGFicwogICAgcHJvZmlsZWNvbGxhYnMxIDwtIGFzLmRhdGEuZnJhbWUocHJvZmlsZWNvbGxhYnMxKSAjIHdlIHdhbnQgdG8uLi4KICAgIHByb2ZpbGVjb2xsYWJzMiA8LSAgYXMuZGF0YS5mcmFtZShwcm9maWxlY29sbGFiczIpCiAgICBwcm9maWxlY29sbGFiczFbLGMoImNvYXV0aF9pZCIpXSA8LSBwcm9maWxlY29sbGFiczJbLDFdCiAgICBwcm9maWxlY29sbGFiczFbLGMoImdzX2lkIildIDwtIGdzaWQgIy4uLiBhZGQgZ3NfaWRzIG9mIGZvY2FsIEdTIHByb2ZpbGUKICAgIHByb2ZpbGVjb2xsYWJzMVssYygibmFtZSIpXSA8LSBwcm9maWxlbmFtZSAjLi4uYW5kIHRoZSB0aGUgcHJvZmlsZSBuYW1lIG9mIEdTIHByb2ZpbGUgYXR0YWNoZWQKICAgIG5hbWVzKHByb2ZpbGVjb2xsYWJzMSlbMV0gPC0gImNvYXV0aCIKICB9IGVsc2UgewogICAgcHJvZmlsZWNvbGxhYnMxIDwtIGFzLmRhdGEuZnJhbWUoY2JpbmQoZ3NpZCwgcHJvZmlsZW5hbWUpKSAjIGlmIE5PVCBsb29raW5nIGZvciBjb2xsYWJzLi4uCiAgICBuYW1lcyhwcm9maWxlY29sbGFiczEpIDwtIGMoImdzX2lkIiwgIm5hbWUiKSAjLi4ud2Ugb25seSBhdHRhY2ggZ3NfaWQgYW5kIHByb2ZpbGVuYW1lCiAgfQogIHJldHVybihwcm9maWxlY29sbGFiczEpCn0KYGBgCgpgYGB7ciwgZXZhbD1GQUxTRX0Kc2F2ZShkYXRhX2RmLCBmaWxlID0gImFkZGZpbGVzXFxkYXRhX2RmLlJEYXRhIikgCmBgYAoKCmBgYHtyLCBldmFsPUZBTFNFfQojIGZpcnN0IHRoZSBzb2MgY29sbGFib3JhdG9ycyBub3RlIGhvdyB3ZSBhbHJlYWR5IGJ1aWxkIGEgZnVuY3Rpb24gKGZjb2xsYWJzKCkpIGZvciB5b3UgeW91IG5lZWQgdG8KIyBpbnB1dCBhIGdvb2dsZSBzY2hvbGFyIGlkIGFuZCBhIDEgKGlmIHlvdSB3YW50IHRvIGZpbmQgY29sbGFicykgb3IgMCAob25seSBleHRyYWN0aW5nIG5hbWVzKQojIGZjb2xsYWJzIC0tPiB5b3UgY2FuIGNoZWNrIGl0IG91dCBpZiB5b3UncmUgaW50ZXJlc3RlZApkYXRhX2NvbGxhYnMgPC0gbGlzdCgpCmZvciAoaSBpbiAxOm5yb3coZGF0YV9kZikpIHsKICAgIHRpbWUgPC0gcnVuaWYoMSwgMCwgMSkKICAgIFN5cy5zbGVlcCh0aW1lKQogICAgZGF0YV9jb2xsYWJzW1tpXV0gPC0gZmNvbGxhYnMoZGF0YV9kZltpLCBjKCJnc19pZCIpXSwgMSkKfQpkYXRhX2NvbGxhYnMgPC0gYmluZF9yb3dzKGRhdGFfY29sbGFicykgICMgYmluZCByb3dzLCBnZXQgdGhlIHVuaXF1ZSBvbmVzIQpkYXRhX2NvbGxhYnNfdW5pcXVlIDwtIHVuaXF1ZShkYXRhX2NvbGxhYnNbLCAiY29hdXRoX2lkIl0pICAjIHNvIDIyOSB1bmlxdWUgY29sbGFib3JhdG9ycyBmb3IgUlUgc3RhZmY/CmRhdGFfY29sbGFic191bmlxdWUgPC0gZGF0YV9jb2xsYWJzX3VuaXF1ZVshaXMubmEoZGF0YV9jb2xsYWJzX3VuaXF1ZSldCnNhdmUoZGF0YV9jb2xsYWJzLCBmaWxlID0gImFkZGZpbGVzXFxkYXRhX2RmX2NvbGxhYnMxLlJEYXRhIikgICMgeW91IG5vdGljZSB0aGlzIHRha2VzIGEgd2hpbGUsIHNvIHdlIHNhdmUgdGhlIGRhdGEgaGVyZS4KYGBgCgpgYGB7ciwgZXZhbD1GQUxTRX0KIyB0aGVuIHRoZSBuYW1lcyBvZiB0aG9zZSBjb2xsYWJvcmF0b3JzIHBsdXMgVEhFSVIgY29sbGFib3JhdG9ycyB1bmRlcnN0YW5kIHRoYXQgd2UgZG9uJ3QgaGF2ZQojIG5hbWVzIG9mIHRoZW0geWV0IGZyb20gdGhlIGNvZGUgYWJvdmU/CmNvbGxhYnNkYXRhXzFkZWVwIDwtIGxpc3QoKQpmb3IgKGkgaW4gMTpsZW5ndGgoZGF0YV9jb2xsYWJzX3VuaXF1ZSkpIHsKICAgIHRpbWUgPC0gcnVuaWYoMSwgMCwgMykKICAgIFN5cy5zbGVlcCh0aW1lKQogICAgaWYgKCFkYXRhX2NvbGxhYnNfdW5pcXVlW2ldICVpbiUgZGF0YV9kZiRnc19pZCkgewogICAgICAgIGNvbGxhYnNkYXRhXzFkZWVwW1tpXV0gPC0gZmNvbGxhYnMoZGF0YV9jb2xsYWJzX3VuaXF1ZVtpXSwgMSkKICAgIH0KfQpjb2xsYWJzZGF0YV8xZGVlcCA8LSBiaW5kX3Jvd3MoY29sbGFic2RhdGFfMWRlZXApCmNvbGxhYnNkYXRhXzFkZWVwX3VuaXF1ZSA8LSB1bmlxdWUoY29sbGFic2RhdGFfMWRlZXBbLCAyXSkKY29sbGFic2RhdGFfMWRlZXBfdW5pcXVlIDwtIGNvbGxhYnNkYXRhXzFkZWVwX3VuaXF1ZVshaXMubmEoY29sbGFic2RhdGFfMWRlZXBfdW5pcXVlKV0Kc2F2ZShjb2xsYWJzZGF0YV8xZGVlcCwgZmlsZSA9ICJhZGRmaWxlc1xcZGF0YV9jb2xsYWJzMi5SRGF0YSIpICAjIHlvdSBub3RpY2UgdGhpcyB0YWtlcyBhIHdoaWxlLCBzbyB3ZSBzYXZlIHRoZSBkYXRhIGhlcmUuCmBgYAoKCmBgYHtyLCBldmFsPUZBTFNFfQpmZ2VuZGVyIDwtIGZ1bmN0aW9uKGZpcnN0bmFtZV9kZiwgbWUsIGZpbGU9TlVMTCkgewoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgQXV0aG9yOiBCYXMgSG9mc3RyYSwgQW5uZSBNYWFpa2UgTXVsZGVycywgSm9jaGVtIFRvbHNtYQojIERBdGU6ICAgMTMtMTAtMjAyMSwgbGFzdCBlZGl0OiAyMi0wOS0yMDIyCiMgVGFza3M6ICAtIGFzc2lnbiBnZW5kZXIgYmFlZCBvbiBuYW1lCiMgICAgICAgICAtIEFkYXB0ZWQgZnJvbSBSZW5zZSBDb3J0ZW4gY29kZSBBcHJpbCAyMDIxCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKCiNJbnB1dDogCiMgIC0gZmlyc3RuYW1lX2RmOiBhIGRhdGEuZnJhbWUgd2l0aCBhIGNvbHVtbiBuYW1lZCBmaXJzdG5hbWUgIGFuZCBnZW5kZXIhCiMgIC0gbWU6IGEgY2hhcmFjdGVyIHZlY3RvciBpbnRyb2R1Y2luZyB5b3Vyc2VsZjogZS5nLiAiSiBUb2xzbWEsIFJhZGJvdWQgVW5pdmVyc2l0eSIKIyAgLSBmaWxlOiBsb2NhdGlvbiBhbmQgbmFtZSBvZiBmaWxlIHRvIGJlIHNhdmVkLiAKICAKIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIExvYWQgcmVxdWlyZWQgcGFja2FnZXMKCmlmICghcmVxdWlyZSgidGlkeXZlcnNlIiwgY2hhcmFjdGVyLm9ubHkgPSBUUlVFKSkgewogIGluc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIsIGRlcGVuZGVuY2llcyA9IFRSVUUpCiAgbGlicmFyeSh0aWR5dmVyc2UsIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkKfQoKaWYgKCFyZXF1aXJlKCJydmVzdCIsIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkpIHsKICBpbnN0YWxsLnBhY2thZ2VzKCJydmVzdCIsIGRlcGVuZGVuY2llcyA9IFRSVUUpCiAgbGlicmFyeShydmVzdCwgY2hhcmFjdGVyLm9ubHkgPSBUUlVFKQp9CgppZiAoIXJlcXVpcmUoInBvbGl0ZSIsIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkpIHsKICBpbnN0YWxsLnBhY2thZ2VzKCJwb2xpdGUiLCBkZXBlbmRlbmNpZXMgPSBUUlVFKQogIGxpYnJhcnkocG9saXRlLCBjaGFyYWN0ZXIub25seSA9IFRSVUUpCn0KCgoKIyBtYWtlIGxpbmtzIHRvIHNjcmFwZQpmaXJzdG5hbWVfZGYkbmFtZV91cmwgPC0gcGFzdGUwKCJodHRwczovL3d3dy5tZWVydGVucy5rbmF3Lm5sL252Yi9uYWFtL2lzLyIsIGZpcnN0bmFtZV9kZlssIGMoImZpcnN0bmFtZSIpXSkKCgoKIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIyMgMjogaW50cm9kdWNlIHRvIHNlcnZlciAjIyMKCiMgSW50cm9kdWNlIG15c2VsZiB0byB0aGUgc2VydmVyCnNlc3Npb24gPC0gYm93KCJodHRwczovL3d3dy5tZWVydGVucy5rbmF3Lm5sL252Yi9uYWFtL2lzIiwgdXNlcl9hZ2VudCA9IG1lICwgZGVsYXkgPSAxKQoKCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyMjIDM6IG1ha2UgZnVuY3Rpb24gdG8gZ2V0IHRhYmxlIGZyb20gIyMjCiAgZm5hbWVzIDwtIGZ1bmN0aW9uKGxpbmspeyAKICAgIG5hbWVfc2Vzc2lvbiA8LW5vZChzZXNzaW9uLCBwYXRoID0gbGluaykKICAgIG5hbWVfcGFnZSA8LSBzY3JhcGUobmFtZV9zZXNzaW9uKSAKICAgIHJldHVybihuYW1lX3BhZ2UpCiAgfQogIApuYW1lX2xpc3QgPC0gbGlzdCgpCnRhYmxlX2xpc3QgPC0gbGlzdCgpCgoKICBmb3IgKGkgaW4gMTpucm93KGZpcnN0bmFtZV9kZikpIHsKICAgIHByaW50KGkpCiAgICBpZiAoIShpcy5uYShmaXJzdG5hbWVfZGYkZ2VuZGVyKSkpIG5leHQKICAgIG5hbWVfbGlzdFtbaV1dIDwtIGZuYW1lcyhmaXJzdG5hbWVfZGZbaSwgYygibmFtZV91cmwiKV0pCiAgICAjIGV4dHJhY3QgbmFtZSBmcmVxdWVuY3kgdGFibGUgYW5kIGdlbmRlciBpbmZvCiAgICBpZiAobGVuZ3RoKG5hbWVfbGlzdFtbaV1dICU+JSBodG1sX3RhYmxlKCkpPjApIHsKICAgICAgCiAgICAgIHRhYmxlX2xpc3RbW2ldXSA8LSBuYW1lX2xpc3RbW2ldXSAlPiUgaHRtbF90YWJsZSgpCiAgICAgIHRhYmxlX2xpc3RbW2ldXVtbMV1dW3RhYmxlX2xpc3RbW2ldXVtbMV1dPT0iLS0iXSA8LSAiMCIKICAgICAgaWYgKGFzLm51bWVyaWModGFibGVfbGlzdFtbaV1dW1sxXV0kWDNbMl0pID4gYXMubnVtZXJpYyh0YWJsZV9saXN0W1tpXV1bWzFdXSRYM1s2XSkpIHsKICAgICAgICBmaXJzdG5hbWVfZGYkZ2VuZGVyW2ldIDwtICJtYWxlIiB9IGVsc2UgewogICAgICAgICAgZmlyc3RuYW1lX2RmJGdlbmRlcltpXSA8LSAiZmVtYWxlIgogICAgICAgIH0KICAgIH0KICAgIGlmICghaXMubnVsbChmaWxlKSkgKHNhdmUoZmlyc3RuYW1lX2RmLCBmaWxlPWZpbGUpKQogICAgCiAgICB9CiAgcmV0dXJuKGZpcnN0bmFtZV9kZikKfQpgYGAKCmBgYHtyLCBldmFsPUZBTFNFfQpkYXRhX2RmICU+JSBtdXRhdGUoZmlyc3RuYW1lPWZpcnN0X25hbWUpIC0+IGRhdGFfZGYKZGF0YV9kZiRnZW5kZXIgPC0gTkEKYGBgCgoKYGBge3IsIGV2YWw9RkFMU0V9CiNHSVZFUyBFUlJPUgpkYXRhX2RmJGZpcnN0bmFtZQpkYXRhX2RmIDwtIGZnZW5kZXIoZGF0YV9kZiwgbWU9IkpvY2hlbSBUb2xzbWEsIFJVL1JVRyIsIGZpbGU9InRlbXBnZW5kZXJfZGF0YV9kMi5SRGF0YSIpCgpgYGAKCmBgYHtyLCBldmFsPUZBTFNFfQpzYXZlKGNzX2RmLCBmaWxlPSJjc19kZl9zMmIuUkRhdGEiKSAjZ2VuZGVyaXplZCBsYXN0LiAKYGBgCgoKIyBFdGhuaWNpdHkgCgpgYGB7ciwgZXZhbD1GQUxTRX0KZGF0YV9kZiAlPiUgbXV0YXRlKGxhc3RuYW1lPWxhc3RfbmFtZSkgLT4gZGF0YV9kZgpsYXN0bmFtZV9kZiA8LSBkYXRhX2RmCmBgYAoKCmBgYHtyLCBldmFsPUZBTFNFfQojdm9vcnZvZWdzZWxzIGNvcnJlY3QgemV0dGVuIHZvb3Igc2NyYXBlcgp2b29ydm9lZ3NlbHMgPC0gYygiJ3QgIiwgImQnICIsICJkZSAiLCAiZGUgbGEgIiwgImRlbiAiLCAiZGVsICIsICJkZXIgIiwgImRlcyAiLCAiZWwgIiwgImVsLSAiLCAiaW4gJ3QgIiwgImxhICIsICJsZSAiLCAibGVzICIsICJvcCBkZW4gIiwgInRlbiAiLCAidGVyICIsICJ0ZXMgIiwgInZhbiAiLCAidmFuICd0ICIsICJ2YW4gZGUgIiAsICJ2YW4gZGVyICIsICJ2YW4gZGVuICIsICJ2b24gZGVyICIsICJvcCBkZW4gIiwgInVsICIpIAoKZm9yIChpIGluIDE6IGxlbmd0aChsYXN0bmFtZV9kZiRsYXN0bmFtZSkpIHsKICBpZiAoc3VtKHN0cl9kZXRlY3QobGFzdG5hbWVfZGYkbGFzdG5hbWVbaV0sIHZvb3J2b2Vnc2VscykpPjApIHsKICAgIGxhc3QgPC0gIGFzLmNoYXJhY3RlcihzdHJfc3BsaXQobGFzdG5hbWVfZGYkbGFzdG5hbWVbaV0sIHBhdHRlcm49IiAiLCBzaW1wbGlmeSA9IFRSVUUpKQogICAgbGFzdCA8LSBsYXN0W2xlbmd0aChsYXN0KV0KICAgIGZpcnN0IDwtIGFzLmNoYXJhY3Rlcih1bmxpc3Qoc3Ryc3BsaXQobGFzdG5hbWVfZGYkbGFzdG5hbWVbaV0sIHNwbGl0PWxhc3QsIGZpeGVkPVRSVUUpKSkKICAgIGxhc3RuYW1lX2RmJGxhc3RuYW1lW2ldIDwtIHBhc3RlKGxhc3QsICIsICIsIGZpcnN0LCBzZXA9IiIpCiAgfQp9CgojZHViYmVsZSBuYW1lbiB2ZXJ3aWpkZXJlbi4gbGV0IG9wIGR1YmJlbGUgbmFtZW4gbWV0IHZvb3J2b2Vnc2VsIHdvcmRlbiBuaWV0IGdlY2xlYW5lZC4gVE8gRE8gCmZvciAoaSBpbiAxOiBsZW5ndGgobGFzdG5hbWVfZGYkbGFzdG5hbWUpKSB7CiAgaWYgKCFzdW0oc3RyX2RldGVjdChsYXN0bmFtZV9kZiRsYXN0bmFtZVtpXSwgdm9vcnZvZWdzZWxzKSk+MCkgewogICAgbGFzdG5hbWVfZGYkbGFzdG5hbWVbaV0gPC0gYXMuY2hhcmFjdGVyKHN0cl9zcGxpdChsYXN0bmFtZV9kZiRsYXN0bmFtZVtpXSwgcGF0dGVybj0iICIsIG4gPSAyLCBzaW1wbGlmeSA9IFRSVUUpWywxXSkKICAgIGxhc3RuYW1lX2RmJGxhc3RuYW1lW2ldIDwtIGFzLmNoYXJhY3RlcihzdHJfc3BsaXQobGFzdG5hbWVfZGYkbGFzdG5hbWVbaV0sIHBhdHRlcm49Ii0iLCBuID0gMiwgc2ltcGxpZnkgPSBUUlVFKVssMV0pCiAgfQp9CgpsYXN0bmFtZV9kZiRsYXN0bmFtZTwtIHRyaW13cyhsYXN0bmFtZV9kZiRsYXN0bmFtZSwgd2hpY2ggPSBjKCJyaWdodCIpLCB3aGl0ZXNwYWNlID0gIlsgXHRcclxuXSIpCmxhc3RuYW1lX2RmJGxhc3RuYW1lIDwtIHN0cl9yZXBsYWNlX2FsbChsYXN0bmFtZV9kZiRsYXN0bmFtZSwgIiAiLCAiJTIwIikgI2h0bWwgbGlua3MgaG91ZGVuIG5pZXQgdmFuIHNwYXRpZXMuIAoKbGFzdG5hbWVfZGYkbnAgPC0gIiIKYGBgCgoKYGBge3IsIGV2YWw9RkFMU0V9CiMgTG9hZCByZXF1aXJlZCBwYWNrYWdlcwoKaWYgKCFyZXF1aXJlKCJ0aWR5dmVyc2UiLCBjaGFyYWN0ZXIub25seSA9IFRSVUUpKSB7CiAgaW5zdGFsbC5wYWNrYWdlcygidGlkeXZlcnNlIiwgZGVwZW5kZW5jaWVzID0gVFJVRSkKICBsaWJyYXJ5KHRpZHl2ZXJzZSwgY2hhcmFjdGVyLm9ubHkgPSBUUlVFKQp9CgppZiAoIXJlcXVpcmUoInJ2ZXN0IiwgY2hhcmFjdGVyLm9ubHkgPSBUUlVFKSkgewogIGluc3RhbGwucGFja2FnZXMoInJ2ZXN0IiwgZGVwZW5kZW5jaWVzID0gVFJVRSkKICBsaWJyYXJ5KHJ2ZXN0LCBjaGFyYWN0ZXIub25seSA9IFRSVUUpCn0KCiMgaWYgKCFyZXF1aXJlKCJwb2xpdGUiLCBjaGFyYWN0ZXIub25seSA9IFRSVUUpKSB7CiMgICBpbnN0YWxsLnBhY2thZ2VzKCJwb2xpdGUiLCBkZXBlbmRlbmNpZXMgPSBUUlVFKQojICAgbGlicmFyeShwb2xpdGUsIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkKIyB9CiMgICAKIyBpZiAoIXJlcXVpcmUoInhtbDIiLCBjaGFyYWN0ZXIub25seSA9IFRSVUUpKSB7CiMgICBpbnN0YWxsLnBhY2thZ2VzKCJ4bWwyIiwgZGVwZW5kZW5jaWVzID0gVFJVRSkKIyAgIGxpYnJhcnkocG9saXRlLCBjaGFyYWN0ZXIub25seSA9IFRSVUUpCiMgfQpgYGAKCmhpZXIgbWFrZW4gd2UgZGUgbGlua3Mgdm9vciBkZSB3ZWJzaXRlLiAKYGBge3IsIGV2YWw9RkFMU0V9CiMgY3JlYXRpbmcgVVJMczogb3JpZ2luCmxhc3RuYW1lX2RmJG5hbWVfb3JpZ2luIDwtIGlmZWxzZSgobGFzdG5hbWVfZGYkbnA9PSIiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZTAoImh0dHBzOi8vd3d3LmNiZ2ZhbWlsaWVuYW1lbi5ubC9uZmIvZGV0YWlsX25hYW0ucGhwP2diYV9uYWFtPSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cmluZ3I6OnN0cl90b190aXRsZShsYXN0bmFtZV9kZlssIGMoImxhc3RuYW1lIildKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICImZ2JhX25hYW09IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyaW5ncjo6c3RyX3RvX3RpdGxlKGxhc3RuYW1lX2RmWywgYygibGFzdG5hbWUiKV0pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiJm5mZF9uYWFtPSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cmluZ3I6OnN0cl90b190aXRsZShsYXN0bmFtZV9kZlssIGMoImxhc3RuYW1lIildKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICImaW5mbz1hbmFseXNlK2VuK3ZlcmtsYXJpbmcmb3BlcmF0b3I9ZXEmdGFhbD0iKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUwKCJodHRwczovL3d3dy5jYmdmYW1pbGllbmFtZW4ubmwvbmZiL2RldGFpbF9uYWFtLnBocD9nYmFfbmFhbT0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYXN0bmFtZV9kZlssIGMoIm5wMiIpXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyaW5ncjo6c3RyX3RvX3RpdGxlKGxhc3RuYW1lX2RmWywgYygibGFzdG5hbWUiKV0pLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiZnYmFfbmFhbT0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYXN0bmFtZV9kZlssIGMoIm5wMiIpXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyaW5ncjo6c3RyX3RvX3RpdGxlKGxhc3RuYW1lX2RmWywgYygibGFzdG5hbWUiKV0pLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiZuZmRfbmFhbT0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJpbmdyOjpzdHJfdG9fdGl0bGUobGFzdG5hbWVfZGZbLCBjKCJsYXN0bmFtZSIpXSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIlMkMrIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFzdG5hbWVfZGZbLCBjKCJucCIpXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiZpbmZvPWFuYWx5c2UrZW4rdmVya2xhcmluZyZvcGVyYXRvcj1lcSZ0YWFsPSIpKQpgYGAKCmhpZXIgc2xhYW4gd2UgYWxsZXMgb3AKYGBge3IsIGV2YWw9RkFMU0V9Cm5hbWVfb3JpZ2lubCA8LSBsaXN0KCkKdGFibGVfb3JpZ2lubCA8LSBsaXN0KCkKdGltZSA8LSAwLjEKYGBgCgojIGNydWNpY2FsIHNjcmFwZSBsb29wCmtvbSB2b29ybG9waWcgZ2VlbiBmb3V0ZW4gdGVnZW4sIHRvY2ggYWxsZXMgYWx2YXN0IGluIGVlbiB0cnljYXRjaCBnZXpldC4gCmxldCBvcCBkYXQgaWsgbmlldCBuZXRqZXMgc2NyYXBlLiBkdXMgem9uZGVyIGZ1bmN0aWUgJ3BvbGl0ZScgZ2V6aWVuIGRlIGtsZWluZSBhYW50YWxsZW4gaW4gb256ZSBjdXJzdXMsIG1hZyBkYXQgd21iIHdlbC4gCmBgYHtyLCBldmFsPUZBTFNFfQoKZm9yIChpIGluIDE6bnJvdyhsYXN0bmFtZV9kZikpIHsKICBwcmludChpKQogIFN5cy5zbGVlcCh0aW1lKQogIHRyeUNhdGNoKHsgCiAgICBuYW1lX29yaWdpbmxbW2ldXSAgPC0gcmVhZF9odG1sKGxhc3RuYW1lX2RmW2ksIGMoIm5hbWVfb3JpZ2luIildKQogICAgdGFibGVfb3JpZ2lubFtbaV1dIDwtIG5hbWVfb3JpZ2lubFtbaV1dICU+JSBodG1sX3RhYmxlKCkKICB9LCAKICAgIHdhcm5pbmcgPSBmdW5jdGlvbih3KSB7CiAgICAgICAgY2F0KCJXQVJOSU5HOiIsIGNvbmRpdGlvbk1lc3NhZ2UodyksICJcbiIpICNXQVJOSU5HIG1lc3NhZ2UKICAgIH0sCiAgICBlcnJvcj1mdW5jdGlvbihlKXsKICAgICAgZXJyIDwtIGNvbmRpdGlvbk1lc3NhZ2UoZSkKICAgICAgY2F0KCJFcnJvcjoiLCBjb25kaXRpb25NZXNzYWdlKGUpLCAiXG4iKSAjRVJST1IgbWVzc2FnZQogICAgfSAgCiAgKQp9CmBgYAoKZW4gdmFuYWYgaGllciBpcyBoZXQgZWlnZW5saWprIGFsbGVlbiBtYWFyIG9wc2Nob25lbi4gCmBgYHtyLGV2YWw9RkFMU0V9Cm9yaWdpbl90eHQgPC0gbGlzdCgpCmZvciAoaSBpbiAxOmxlbmd0aChuYW1lX29yaWdpbmwpKSB7CiAgICBvcmlnaW5fdHh0IFtbaV1dIDwtIG5hbWVfb3JpZ2lubFtbaV1dICU+JSBodG1sX3RleHQoKSAlPiUgYXMuY2hhcmFjdGVyKCkKfQoKYGBgCgoKYGBge3IsIGV2YWw9RkFMU0V9CiMgR2V0IG91dCB0aGUgcmVsZXZhbnQgb3JpZ2luIGluZm9ybWF0aW9uIGZyb20gdGhlIHhtbCBsaXN0cwpvcmlnaW5fbG4gPC0gbGlzdCgpCgpmb3IgKGkgaW4gMTpsZW5ndGgobmFtZV9vcmlnaW5sKSkgewogIG9yaWdpbl9sbltbaV1dIDwtIG5hbWVfb3JpZ2lubFtbaV1dICU+JSBodG1sX25vZGVzKCJkaXYiKSAlPiUgcnZlc3Q6Omh0bWxfdGV4dCgpCiAgb3JpZ2luX2xuW1tpXV0gPC0gb3JpZ2luX2xuW1tpXV1bWzNdXQp9CgojIFJlbW92ZSBtZXNzCmZvciAoaSBpbiAxOmxlbmd0aChvcmlnaW5fbG4pKSB7CiAgb3JpZ2luX2xuW1tpXV0gPC0gZ3N1YigiXFx0IiwgIiAiLCBvcmlnaW5fbG5bW2ldXSkKICBvcmlnaW5fbG5bW2ldXSA8LSBnc3ViKCJcXG4iLCAiICIsIG9yaWdpbl9sbltbaV1dKQp9CgojIEZsYXR0ZW4gbmVzdGVkIHN0cnVjdHVyZSBvZiB0aGUgb3JpZ2luIGluZm9ybWF0aW9uCiNvcmlnaW5fbG4gPC0gcmJpbmQoZmxhdHRlbihvcmlnaW5fbG4pKQoKYGBgCgoKYGBge3IgZXh0cmFjdGluZy12ZXJrbGFyaW5nLWtlbm1lcmtlbiwgZXZhbD1GQUxTRX0KCiMgRGV0YWNoaW5nIHRoZSBuYW1lcyBhbmQgb3JpZ2luIGluZm8gZm9yIGVhc2llciBkYXRhIGhhbmRsaW5nCm9yaWdpbiA8LSB1bmxpc3Qob3JpZ2luX2xuKQoKCgpvcmlnaW4gPC0gc3RyX2V4dHJhY3RfYWxsKG9yaWdpbiwgInZhcmlhbnRlbiguKj8pwqkiKQoKIyBPcmlnaW4gaW5mb3JtYXRpb24gaXMgdXN1YWxseSBtZW50aW9uZWQgYWZ0ZXIgInZlcmtsYXJpbmciIG9yICJrZW5tZXJrZW4iCm9yaWdpbiA8LSBzdHJfcmVtb3ZlX2FsbChvcmlnaW4sICJ2YXJpYW50ZW4iKQpvcmlnaW4gPC0gc3RyX3JlbW92ZV9hbGwob3JpZ2luLCAiQ0JHIEJyb25uZW4iKQpvcmlnaW4gPC0gc3RyX3JlbW92ZV9hbGwob3JpZ2luLCAiY2F0YWxvZ3VzIikKb3JpZ2luIDwtIHN0cl9yZW1vdmVfYWxsKG9yaWdpbiwgIsKpIikKCgp2ZXJrbGFyaW5nIDwtIHN0cl9yZW1vdmVfYWxsKG9yaWdpbiwgImtlbm1lcmtlbjooLio/KSQiKQprZW5tZXJrZW4gPC0gc3RyX2V4dHJhY3RfYWxsKG9yaWdpbiwgImtlbm1lcmtlbjooLio/KSQiKQprZW5tZXJrZW4gPC0gc3RyX3JlbW92ZV9hbGwoa2VubWVya2VuLCAic3BlY2lmaWVrZSBjb21wb25lbnRlbjooLio/KSQiKQpzYyA8LSBzdHJfZXh0cmFjdF9hbGwob3JpZ2luLCAic3BlY2lmaWVrZSBjb21wb25lbnRlbjooLio/KSQiKSAjIE5vdCBkaXJlY3RseSByZWxldmFudCB0byB1cywgYnV0IGRvZXMgbWVhbiB0aGF0IHRoZSBuYW1lIGhhcyBhIHdlYnBhZ2UKCgojIE1ha2UgaW50byBhIG5lYXQgZGF0YWZyYW1lIHdpdGggdGhlIG5hbWVzIGF0dGFjaGVkCnZlcmtsYXJpbmcgPC0gdHJpbXdzKHZlcmtsYXJpbmcsIHdoaWNoID0gImJvdGgiKQprZW5tZXJrZW4gPC0gdHJpbXdzKGtlbm1lcmtlbiwgd2hpY2ggPSAiYm90aCIpCnNjIDwtIHRyaW13cyhzYywgd2hpY2ggPSAiYm90aCIpCnZrIDwtIGRhdGEuZnJhbWUoZGF0YV9kZiRsYXN0bmFtZSwgdmVya2xhcmluZywga2VubWVya2VuLCBzYykKCgpgYGAKCgoKIyBTZXBhcmF0aW5nIG5hbWVzIHdpdGggRHV0Y2ggJiB1bmtub3duIG9yaWdpbgpOZXh0LCB3ZSBpZGVudGlmeSB0aG9zZSBuYW1lcyBmb3Igd2hpY2ggbm8gYWRkaXRpb25hbCBpbmZvcm1hdGlvbiB3YXMgZm91bmQuIFRoaXMgaXMgaW1wb3J0YW50IHRvIGRpc3Rpbmd1aXNoIER1dGNoIG5hbWVzIGZyb20gbmFtZXMgd2l0aCB1bmtub3duIG9yaWdpbnMuCgotIER1dGNoIG5hbWVzOiBubyBsYWJlbCBpbmRpY2F0aW5nIHRoYXQgdGhlIG5hbWUgaXMgRHV0Y2gsIGJ1dCBzb21lIG90aGVyIGluZm9ybWF0aW9uIGF2YWlsYWJsZSBvbiBuYW1lIG9yaWdpbgotIFVua25vd24gbmFtZXM6IHdlYiBwYWdlIGNhbm5vdCBiZSBmb3VuZCwgc28gb3JpZ2luIGluZm9ybWF0aW9uIGlzIGVtcHR5LiAKCmBgYHtyIG9yaWdpbi11bmtub3duLCBldmFsPUZBTFNFfQoKIyBJZGVudGlmeSBsYXN0IG5hbWVzIHRoYXQgY291bGQgbm90IGJlIGZvdW5kCnZrIDwtIHZrICU+JQogIG11dGF0ZSh2ZXJrbGFyaW5nID0gaWZlbHNlKHZlcmtsYXJpbmc9PSIiLCAwLCB2ZXJrbGFyaW5nKSwgCiAgICAgICAgIGtlbm1lcmtlbiA9IGlmZWxzZShrZW5tZXJrZW49PSJjaGFyYWN0ZXIoMCkiLCAwLCBrZW5tZXJrZW4pLAogICAgICAgICBzYyA9IGlmZWxzZShzYz09ImNoYXJhY3RlcigwKSIsIDAsIHNjKSwKICAgICAgICAgbm9faW5mbyA9IG5jaGFyKHZlcmtsYXJpbmcpICsgbmNoYXIoa2VubWVya2VuKSArIG5jaGFyKHNjKSkKCnZrIDwtIHZrICU+JQogIG11dGF0ZShub19pbmZvID0gaWZlbHNlKG5vX2luZm89PTMsIDEsIDApLCAKICAgICAgICAgdmVya2xhcmluZyA9IGlmZWxzZSh2ZXJrbGFyaW5nPT0wLCBOQSwgdmVya2xhcmluZyksCiAgICAgICAgIGtlbm1lcmtlbiA9IGlmZWxzZShrZW5tZXJrZW49PTAsIE5BLCBrZW5tZXJrZW4pKQojIElmIHRoZXJlIGlzIG5vIHRleHQgaW4gdmVya2xhcmluZyBvciBrZW5tZXJrZW4sIHRoZSBuYW1lIGNvdWxkIG5vdCBiZSBmb3VuZCBpbiB0aGUgZGF0YWJhc2VzLiAKYGBgCgoKIyBFeHRyYWN0aW5nIHNwZWNpZmljIG9yaWdpbiBpbmZvcm1hdGlvbgpUaGVyZSBhcmUgdGhyZWUgbWFpbiB3YXlzIHRvIGdldCBpbmZvcm1hdGlvbiBhYm91dCB0aGUgb3JpZ2luIG9mIGxhc3QgbmFtZXM6CgoxKSBVbmRlciAia2VubWVya2VuIiwgbGFzdCBuYW1lcyBhcmUgYXNzaWduZWQgY2xpY2thYmxlIHRhZ3MuIFRoZXNlIHRhZ3MgaW5jbHVkZSB1bnNwZWNpZmllZCBmb3JlaWduIG5hbWUgdGFncyAoImFuZGVyZSB0YWFsIiksIGFzIHdlbGwgYXMgc3BlY2lmaWMgZm9yZWlnbiBvcmlnaW5zIG9mIHRoZSBuYW1lICgiRnJhbnNlIG5hYW0iLCAiSW5kaXNjaGUgbmFhbSIpLgotPiBvcmlnaW4xICsgb3JpZ2luNAoKMikgU2V2ZXJhbCBuYW1lcyBoYXZlIG1vcmUgZXh0ZW5zaXZlbHkgd3JpdHRlbiBvdXQgc3RvcmllcyBiZWhpbmQgdGhlIG5hbWUsIHVuZGVyICJ2ZXJrbGFyaW5nIi4gQSBudW1iZXIgb2YgbmFtZXMgY29udGFpbiBkZXRhaWxlZCAoZWl0aGVyIGNvdW50cnktbGV2ZWwgb3IgcmVnaW9uYWwpIG9yaWdpbnMsIHVzdWFsbHkgaW4gdGhlIGZvcm0gb2YgIkRlIG5hYW0gW3h5el0gaXMgYWZrb21zdGlnIHVpdCBbY291bnRyeV0iLiAKLT4gb3JpZ2luMiAKCjMpIFNvbWUgbmFtZXMgaGF2ZSBvcmlnaW4gaW5mb3JtYXRpb24gdW5kZXIgInZlcmtsYXJpbmciIGluIHRoZSBmb3JtIG9mIHRoZSBsaW5ndWlzdGljIG9yaWdpbnMgb2YgdGhlIG5hbWUuIFRoaXMgY2FuIGJlIGNvdW50cnkgc3BlY2lmaWMgKGUuZy4gQ2hpbmVzZSBuYW1lKSwgYnV0IGl0IGNhbiBhbHNvIGFwcGx5IHRvIG11bHRpcGxlIGNvdW50cmllcyB3aGVuIHRoZSBsYW5ndWFnZSBpcyBzcG9rZW4gaW4gbW9yZSB0aGFuIDEgY291bnRyaWVzIChlLmcuIFNwYW5pc2ggbmFtZSkuIAotPiBvcmlnaW4zIAoKYGBge3IgY291bnRyaWVzLWV4dHJhY3QsIGV2YWw9RkFMU0V9CgojIFN0ZXAgMTogZXh0cmFjdGluZyBvcmlnaW4gdGFncyBmcm9tIGtlbm1lcmtlbgp2ayA8LSB2ayAlPiUKICBtdXRhdGUob3JpZ2luMSA9IHN0cl9leHRyYWN0KGtlbm1lcmtlbiwgIls6dXBwZXI6XShbOmxvd2VyOl17Mix9KSBuYWFtIikpCgojIE5vdGU6IHNvbWV0aW1lcyBtdWx0aXBsZSBvcmlnaW5zIGFyZSBtZW50aW9uZWQuIEN1cnJlbnRseSwgSSBvbmx5IGV4dHJhY3QgdGhlIGZpcnN0IG9uZS4gT3RoZXJ3aXNlLCB3ZSBzaG91bGQgdXNlIHN0cl9leHRyYWN0X2FsbC4gCgoKCiMgU3RlcCAyOiBleHRyYWN0aW5nIG9yaWdpbiBpbmZvIGZyb20gdmVya2xhcmluZyAKdmsgPC0gdmsgJT4lCiAgbXV0YXRlKG9yaWdpbjIgPSBpZmVsc2UoYXMubnVtZXJpYyhzdHJfZGV0ZWN0KHZlcmtsYXJpbmcsICJhZmtvbXN0aWcgdWl0IikpID09IDEsIAogICAgICAgICBzdHJfcmVtb3ZlKHZlcmtsYXJpbmcsICIuKmFma29tc3RpZyB1aXQiKSwgTkEpKQoKCiMgU3RlcCAzOiBleHRyYWN0aW5nIGFkZGl0aW9uYWwgb3JpZ2luIGluZm8gZnJvbSB2ZXJrbGFyaW5nCnZrIDwtIHZrICU+JQogIG11dGF0ZShvcmlnaW4zID0gc3RyX2V4dHJhY3QodmVya2xhcmluZywgIls6dXBwZXI6XShbOmxvd2VyOl17Mix9KSAoYWNodGVyKT8oZmFtaWxpZSk/KGJlcm9lcHMpP25hYW0iKSkKCgoKIyBGaW5hbGx5LCB3ZSBjbGVhbiB1cCB0aGUgb3JpZ2luIGluZm9ybWF0aW9uIGV4dHJhY3RlZCBhYm92ZQoKIyBPcmlnaW4xOiBhbHJlYWR5IG5lYXQKdmskb3JpZ2luMSA8LSBzdHJfcmVtb3ZlKHZrJG9yaWdpbjEsICJKb29kc2UgbmFhbSIpICMgY2FuIGJlIER1dGNoICYgbm9uLUR1dGNoCgojIE9yaWdpbjI6IG1lc3N5CnZrJG9yaWdpbjIgPC0gc3RyX3JlbW92ZSh2ayRvcmlnaW4yLCAiXFwuLioiKSAjIHJlbW92ZSBleHRyYSBpbmZvIGluIHRoZSBmb2xsb3dpbmcgc2VudGVuY2UgCnZrJG9yaWdpbjIgPC0gc3RyX3JlbW92ZSh2ayRvcmlnaW4yLCAiXFw7LioiKSAjIHJlbW92ZSBleHRyYSBpbmZvIGluIHRoZSBmb2xsb3dpbmcgc2VudGVuY2UgCnZrJG9yaWdpbjIgPC0gc3RyX3JlbW92ZSh2ayRvcmlnaW4yLCAiXFwoLioiKSAjIHJlbW92ZSBleHRyYSBpbmZvIGluIHRoZSBmb2xsb3dpbmcgc2VudGVuY2UgCgoKdmskZHBnIDwtIGFzLm51bWVyaWMoc3RyX2RldGVjdCh2ayRvcmlnaW4yLCAiKGRvcnApfChwbGFhdHMpfChnZW1lZW50ZSl8KGdyYWFmc2NoYXApfChzdGFkKXwoZGVlbCl8KEZyaWVzbGFuZCkiKSkgIyBvcmlnaW4gaW5mbyB0b28gcmVnaW9uYWwgCnZrIDwtIHZrICU+JSBtdXRhdGUob3JpZ2luMiA9IGlmZWxzZSgoZHBnPT0xKSwgTkEsIG9yaWdpbjIpKSAjIHJlbW92aW5nIHJlZ2lvbmFsIG9yaWdpbiBpbmZvCnZrIDwtIHN1YnNldCh2aywgc2VsZWN0ID0gLWRwZykgIyByZW1vdmluZyBpbnRlcm1lZGlhdGUgdmFyaWFibGUKCiMgU29tZXRpbWVzLCB0aGVyZSB3ZXJlIG11bHRpcGxlIGNvdW50cmllcyBtZW50aW9uZWQuIFRha2Ugb25seSB0aGUgZmlyc3Q6CnZrJG9yaWdpbjIgPC0gc3RyX3JlbW92ZSh2ayRvcmlnaW4yLCAiXFwsLioiKSAjIE9ubHkgZmlyc3QKdmskb3JpZ2luMiA8LSBzdHJfcmVtb3ZlKHZrJG9yaWdpbjIsICJcXHMoZW4pLioiKSAjIE9ubHkgZmlyc3QgCnZrJG9yaWdpbjIgPC0gc3RyX3JlbW92ZSh2ayRvcmlnaW4yLCAiXFxzKG9mKS4qIikgIyBPbmx5IGZpcnN0IAoKCiMgT3JpZ2luMzogcHJldHR5IG5lYXQKdmskb3JpZ2luMyA8LSBzdHJfcmVtb3ZlKHZrJG9yaWdpbjMsICJEKGkpP2UoemUpPyAoZmFtaWxpZSk/KGFjaHRlcik/KGJlcm9lcHMpP25hYW0iKSAjIHNsaXBwZWQgdGhyb3VnaCB0aGUgcmVnZXgKdmskb3JpZ2luMyA8LSBzdHJfcmVtb3ZlKHZrJG9yaWdpbjMsICJFZW4gKGZhbWlsaWUpPyhhY2h0ZXIpPyhiZXJvZXBzKT9uYWFtIikgIyBzbGlwcGVkIHRocm91Z2ggdGhlIHJlZ2V4CnZrJG9yaWdpbjMgPC0gc3RyX3JlbW92ZSh2ayRvcmlnaW4zLCAiWmlqbiAoZmFtaWxpZSk/KGFjaHRlcik/KGJlcm9lcHMpP25hYW0iKSAjIHNsaXBwZWQgdGhyb3VnaCB0aGUgcmVnZXgKdmskb3JpZ2luMyA8LSBzdHJfcmVtb3ZlKHZrJG9yaWdpbjMsICJBbHMgKGZhbWlsaWUpPyhhY2h0ZXIpPyhiZXJvZXBzKT9uYWFtIikgIyBzbGlwcGVkIHRocm91Z2ggdGhlIHJlZ2V4CnZrJG9yaWdpbjMgPC0gc3RyX3JlbW92ZSh2ayRvcmlnaW4zLCAiSm9vZHNlIChmYW1pbGllKT8oYWNodGVyKT9uYWFtIikKdmskb3JpZ2luMyA8LSBzdHJfcmVtb3ZlKHZrJG9yaWdpbjMsICJCaWpiZWxzZSAoZmFtaWxpZSk/KGFjaHRlcik/bmFhbSIpCgoKIyBTZXR0aW5nIGVtcHR5IG9yaWdpbiB2YXJpYWJsZXMgdG8gTkEgKER1dGNoIG9yIHVuZm91bmQgZm9yZWlnbikKdmsgPC0gdmsgJT4lCiAgbXV0YXRlKG9yaWdpbjEgPSBhcy5jaGFyYWN0ZXIoaWZlbHNlKG9yaWdpbjE9PSIifG9yaWdpbjE9PSJjaGFyYWN0ZXIoMCkiLCBOQSwgb3JpZ2luMSkpLAogICAgICAgICBvcmlnaW4yID0gYXMuY2hhcmFjdGVyKGlmZWxzZShvcmlnaW4yPT0iInxvcmlnaW4yPT0iY2hhcmFjdGVyKDApIiwgTkEsIG9yaWdpbjIpKSwKICAgICAgICAgb3JpZ2luMyA9IGFzLmNoYXJhY3RlcihpZmVsc2Uob3JpZ2luMz09IiJ8b3JpZ2luMz09ImNoYXJhY3RlcigwKSIsIE5BLCBvcmlnaW4zKSkpCgoKCiMgRmluYWxseSwgdGhlIHRhZyAiYW5kZXJlIHRhYWwiIHdhcyB1c2VkIHRvIGRpc3Rpbmd1aXNoIGZvcmVpZ24gbmFtZXMgb2YgdW5rbm93biBvcmlnaW4gZnJvbSBrbm93biBEdXRjaCBuYW1lcy4gCnZrIDwtIHZrICU+JQogIG11dGF0ZShvcmlnaW40ID0gaWZlbHNlKChhcy5udW1lcmljKHN0cl9kZXRlY3Qoa2VubWVya2VuLCAiYW5kZXJlIHRhYWwiKSk9PTEpLCAibm9uLUR1dGNoIiwgTkEpKQoKCmBgYAoKSWsgem91IGFsbGVzIHdhYXIgYG5vX2luZm9gIG9wIDEgc3RhYXQgb2Ygd2FhciBgb3JpZ2luNGAgb3AgIm5vbi1EdXRjaCIgc3RhYXQgY29kZXJlbiBhbHMgYnVpdGVubGFuZHMhIAoKYGBge3IsIGV2YWw9RkFMU0V9CnNhdmUodmssIGZpbGU9InZrX2RhdGEuUkRhdGEiKQpgYGAKCiMgTWFraW5nIFJTaWVuYSBmcmFtZQoKSSBzZWUgdGhhdCBpIGRvbnQgaGF2ZSB0aGUgZGF0YSBzYXZlZCBmb3IgdGhlIHB1YmxpY2F0aW9ucyBmcm9tIGRhdGEgc2NpZW5jZSwgYnV0IEkgZG8gbm90IGhhdmUgdGltZSB0byBmaXggdGhhdCBub3cuIFNvIEkgd2lsbCBzdGFydCBpbiBjbGFzcyAKIyBuZXR3b3JrIGJhc2VkIG9uIHB1YmxpY2F0aW9ucwoKTkFUVVJBTExZLCBUSElTIElTIEpVU1QgQU4gRVhBTVBMRS4gZk9SIHJTSUVOQSwgWU9VIE5FRUQgQVQgTEVBU1QgMyBORVRXT1JLUy4gdEhVUyBZT1UgSEFWRSBUTyBUV0VBSyBUSEUgUEVSSU9EIEFTIFlPVSBERUVNIEZJVC4gCgpgYGB7ciwgZXZhbD1GQUxTRX0KbGlicmFyeShzdHJpbmdyKQoKI2VtcHR5IGFkamFjZW5jeSBtYXRyaXggZm9yIHRoZSB5ZWFycyAyMDAxLTIwMTAKbmV0d29yazIwMTBfMjAxMiA8LSBtYXRyaXgoTkEsIG5yb3c9bnJvdyhzb2NfZGYpLCBuY29sPW5yb3coc29jX2RmKSkKbmV0d29yazIwMTNfMjAxNSA8LSBtYXRyaXgoTkEsIG5yb3c9bnJvdyhzb2NfZGYpLCBuY29sPW5yb3coc29jX2RmKSkKbmV0d29yazIwMTZfMjAxOCA8LSBtYXRyaXgoTkEsIG5yb3c9bnJvdyhzb2NfZGYpLCBuY29sPW5yb3coc29jX2RmKSkKbmV0d29yazIwMTlfMjAyMSA8LSBtYXRyaXgoTkEsIG5yb3c9bnJvdyhzb2NfZGYpLCBuY29sPW5yb3coc29jX2RmKSkKCgojc2VsZWN0IHB1YmxpY2F0aW9ucyBvZiB0aGUgY29ycmVzcG9uZGluZyB0aW1lIGVyYQpwdWJzX3NlbCA8LSBzb2NfZGZfcHVibGljYXRpb25zICU+JQogICAgICAgICAgICAgIG11dGF0ZShhdXRob3IgPSB0b2xvd2VyKGF1dGhvcikpICU+JQogICAgICAgICAgICAgIGZpbHRlcih5ZWFyPj0yMDEwICYgeWVhcjw9MjAxMikKI2ZpbGwgdGhlIG1hdHJpeApmb3IgKGVnbyBpbiAxOiBucm93KHNvY19kZikpIHsKICBuYW1lX2VnbyA8LSBzb2NfZGYkbGFzdF9uYW1lW2Vnb10gI3doaWNoIGVnbz8gCiAgcHVic19zZWwyIDwtIHB1YnNfc2VsW3N0cl9kZXRlY3QocHVic19zZWwkYXV0aG9yLCBuYW1lX2VnbyksXSAjcHVibGljYXRpb25zIG9mIGVnbwogIGZvciAoYWx0ZXIgaW4gMTpucm93KHNvY19kZikpewogICAgbmFtZV9hbHRlciA8LSBzb2NfZGYkbGFzdF9uYW1lW2FsdGVyXSAjd2hpY2ggYWx0ZXI/IAogICAgbmV0d29yazIwMTBfMjAxMltlZ28sYWx0ZXJdIDwtIGFzLm51bWVyaWMoc3VtKHN0cl9kZXRlY3QocHVic19zZWwyJGF1dGhvciwgbmFtZV9hbHRlcikpID4gMSkgICNkaWQgYWx0ZXIgcHVibGlzaCB3aXRoIGVnbwogIH0KfQoKI3NlbGVjdCBwdWJsaWNhdGlvbnMgb2YgdGhlIGNvcnJlc3BvbmRpbmcgdGltZSBlcmEKcHVic19zZWwgPC0gc29jX2RmX3B1YmxpY2F0aW9ucyAlPiUKICAgICAgICAgICAgICBtdXRhdGUoYXV0aG9yID0gdG9sb3dlcihhdXRob3IpKSAlPiUKICAgICAgICAgICAgICBmaWx0ZXIoeWVhcj49MjAxMyAmIHllYXI8PTIwMTUpCiNmaWxsIHRoZSBtYXRyaXgKZm9yIChlZ28gaW4gMTogbnJvdyhzb2NfZGYpKSB7CiAgbmFtZV9lZ28gPC0gc29jX2RmJGxhc3RfbmFtZVtlZ29dICN3aGljaCBlZ28/IAogIHB1YnNfc2VsMiA8LSBwdWJzX3NlbFtzdHJfZGV0ZWN0KHB1YnNfc2VsJGF1dGhvciwgbmFtZV9lZ28pLF0gI3B1YmxpY2F0aW9ucyBvZiBlZ28KICBmb3IgKGFsdGVyIGluIDE6bnJvdyhzb2NfZGYpKXsKICAgIG5hbWVfYWx0ZXIgPC0gc29jX2RmJGxhc3RfbmFtZVthbHRlcl0gI3doaWNoIGFsdGVyPyAKICAgIG5ldHdvcmsyMDEzXzIwMTVbZWdvLGFsdGVyXSA8LSBhcy5udW1lcmljKHN1bShzdHJfZGV0ZWN0KHB1YnNfc2VsMiRhdXRob3IsIG5hbWVfYWx0ZXIpKSA+IDEpICNkaWQgYWx0ZXIgcHVibGlzaCB3aXRoIGVnbwogIH0KfQoKI3NlbGVjdCBwdWJsaWNhdGlvbnMgb2YgdGhlIGNvcnJlc3BvbmRpbmcgdGltZSBlcmEKcHVic19zZWwgPC0gc29jX2RmX3B1YmxpY2F0aW9ucyAlPiUKICAgICAgICAgICAgICBtdXRhdGUoYXV0aG9yID0gdG9sb3dlcihhdXRob3IpKSAlPiUKICAgICAgICAgICAgICBmaWx0ZXIoeWVhcj49MjAxNiAmIHllYXI8PTIwMTgpCiNmaWxsIHRoZSBtYXRyaXgKZm9yIChlZ28gaW4gMTogbnJvdyhzb2NfZGYpKSB7CiAgbmFtZV9lZ28gPC0gc29jX2RmJGxhc3RfbmFtZVtlZ29dICN3aGljaCBlZ28/IAogIHB1YnNfc2VsMiA8LSBwdWJzX3NlbFtzdHJfZGV0ZWN0KHB1YnNfc2VsJGF1dGhvciwgbmFtZV9lZ28pLF0gI3B1YmxpY2F0aW9ucyBvZiBlZ28KICBmb3IgKGFsdGVyIGluIDE6bnJvdyhzb2NfZGYpKXsKICAgIG5hbWVfYWx0ZXIgPC0gc29jX2RmJGxhc3RfbmFtZVthbHRlcl0gI3doaWNoIGFsdGVyPyAKICAgIG5ldHdvcmsyMDE2XzIwMThbZWdvLGFsdGVyXSA8LSBhcy5udW1lcmljKHN1bShzdHJfZGV0ZWN0KHB1YnNfc2VsMiRhdXRob3IsIG5hbWVfYWx0ZXIpKSA+IDEpICNkaWQgYWx0ZXIgcHVibGlzaCB3aXRoIGVnbwogIH0KfQoKI3NlbGVjdCBwdWJsaWNhdGlvbnMgb2YgdGhlIGNvcnJlc3BvbmRpbmcgdGltZSBlcmEKcHVic19zZWwgPC0gc29jX2RmX3B1YmxpY2F0aW9ucyAlPiUKICAgICAgICAgICAgICBtdXRhdGUoYXV0aG9yID0gdG9sb3dlcihhdXRob3IpKSAlPiUKICAgICAgICAgICAgICBmaWx0ZXIoeWVhcj49MjAxOSAmIHllYXI8PTIwMjEpCiNmaWxsIHRoZSBtYXRyaXgKZm9yIChlZ28gaW4gMTogbnJvdyhzb2NfZGYpKSB7CiAgbmFtZV9lZ28gPC0gc29jX2RmJGxhc3RfbmFtZVtlZ29dICN3aGljaCBlZ28/IAogIHB1YnNfc2VsMiA8LSBwdWJzX3NlbFtzdHJfZGV0ZWN0KHB1YnNfc2VsJGF1dGhvciwgbmFtZV9lZ28pLF0gI3B1YmxpY2F0aW9ucyBvZiBlZ28KICBmb3IgKGFsdGVyIGluIDE6bnJvdyhzb2NfZGYpKXsKICAgIG5hbWVfYWx0ZXIgPC0gc29jX2RmJGxhc3RfbmFtZVthbHRlcl0gI3doaWNoIGFsdGVyPyAKICAgIG5ldHdvcmsyMDE5XzIwMjFbZWdvLGFsdGVyXSA8LSBhcy5udW1lcmljKHN1bShzdHJfZGV0ZWN0KHB1YnNfc2VsMiRhdXRob3IsIG5hbWVfYWx0ZXIpKSA+IDEpICNkaWQgYWx0ZXIgcHVibGlzaCB3aXRoIGVnbwogIH0KfQoKYyhkaW0obmV0d29yazIwMTBfMjAxMiksNCkKbmV0X2FycmF5IDwtIGFycmF5KGRhdGEgPSBjKG5ldHdvcmsyMDEwXzIwMTIsIG5ldHdvcmsyMDEzXzIwMTUsIG5ldHdvcmsyMDE2XzIwMTgsIG5ldHdvcmsyMDE5XzIwMjEpLCBkaW09YyhkaW0obmV0d29yazIwMTBfMjAxMiksNCkpCgpuZXRfYXJyYXlbMSwxLDFdCmBgYAoKCmBgYHtyLCBldmFsPUZBTFNFfQpzYXZlKG5ldF9hcnJheSwgZmlsZT0ic29jX25ldF9hcnJheS5SRGF0YSIpCmBgYAoKCg==