clubdata.RData
In the following scripts a list containing the (anonymized) data of
all clubs is made (clubdata.RData).
Our primary network variable is the Kudos-network. A tie i ->
j exists if ego i award at least 1 Kudos to alter j.
For the behavioral data we include information on the
frequency (i.e., in times per week) and volume (i.e.,
in hours per week) of running activities. We included activity
(frequency and volume) in other sports (e.g., cycling and swimming) as a
time-varying covariate.
# club string represents the club ID
club_str <- c("clubid1", "clubid2", "clubid3", "clubid4" ,"clubid5")
# the following script reads the data of the clubs from the folder for each club, stores them in a list, and saves it in an object in the last function call of this script.
for (i in (1: length(club_str))) {
club_id <- club_str[i]
# read the data from the club
clubdata <- read.csv(paste("clubs/", club_id, "/", "egoData_extended.csv", sep = ""), row.names = NULL,
sep = ",")
# saving club size
size <- length(clubdata[, "gender"])
# the number of months that we want to add as waves
n_waves <- 12
# let's load the friendship/following network
friend_data <- as.matrix(read.csv(paste("clubs/", club_id, "/", "socialnetwork.csv", sep = ""), row.names = NULL,
sep = ","))
# remove the first column (represents index made in the csv)
friend_data <- friend_data[, 2:ncol(friend_data)]
# and anonymize the user id, with our id-maker function
fakeid <- fidmaker(nrow(friend_data)) # generate random id
colnames(friend_data) <- fakeid # anonymizing users
# let's load the kudos network
path <- paste("clubs/", club_id, "/", "kudos", sep = "") # create path
{
kudo_w1 <- as.matrix(read.csv(paste(path, "1-2019.csv", sep = ""), row.names = NULL, sep = ","))
kudo_w1 <- kudo_w1[, 2:ncol(kudo_w1)]
kudo_w2 <- as.matrix(read.csv(paste(path, "2-2019.csv", sep = ""), row.names = NULL, sep = ","))
kudo_w2 <- kudo_w2[, 2:ncol(kudo_w2)]
kudo_w3 <- as.matrix(read.csv(paste(path, "3-2019.csv", sep = ""), row.names = NULL, sep = ","))
kudo_w3 <- kudo_w3[, 2:ncol(kudo_w3)]
kudo_w4 <- as.matrix(read.csv(paste(path, "4-2019.csv", sep = ""), row.names = NULL, sep = ","))
kudo_w4 <- kudo_w4[, 2:ncol(kudo_w4)]
kudo_w5 <- as.matrix(read.csv(paste(path, "5-2019.csv", sep = ""), row.names = NULL, sep = ","))
kudo_w5 <- kudo_w5[, 2:ncol(kudo_w5)]
kudo_w6 <- as.matrix(read.csv(paste(path, "6-2019.csv", sep = ""), row.names = NULL, sep = ","))
kudo_w6 <- kudo_w6[, 2:ncol(kudo_w6)]
kudo_w7 <- as.matrix(read.csv(paste(path, "7-2019.csv", sep = ""), row.names = NULL, sep = ","))
kudo_w7 <- kudo_w7[, 2:ncol(kudo_w7)]
kudo_w8 <- as.matrix(read.csv(paste(path, "8-2019.csv", sep = ""), row.names = NULL, sep = ","))
kudo_w8 <- kudo_w8[, 2:ncol(kudo_w8)]
kudo_w9 <- as.matrix(read.csv(paste(path, "9-2019.csv", sep = ""), row.names = NULL, sep = ","))
kudo_w9 <- kudo_w9[, 2:ncol(kudo_w9)]
kudo_w10 <- as.matrix(read.csv(paste(path, "10-2019.csv", sep = ""), row.names = NULL, sep = ","))
kudo_w10 <- kudo_w10[, 2:ncol(kudo_w10)]
kudo_w11 <- as.matrix(read.csv(paste(path, "11-2019.csv", sep = ""), row.names = NULL, sep = ","))
kudo_w11 <- kudo_w11[, 2:ncol(kudo_w11)]
kudo_w12 <- as.matrix(read.csv(paste(path, "12-2019.csv", sep = ""), row.names = NULL, sep = ","))
kudo_w12 <- kudo_w12[, 2:ncol(kudo_w12)]
}
kudos <- array(c(kudo_w1, kudo_w2, kudo_w3, kudo_w4, kudo_w5, kudo_w6, kudo_w7, kudo_w8, kudo_w9,
kudo_w10, kudo_w11, kudo_w12), dim = c(size, size, n_waves)) #Kudos matrix
kudo_data <- ifelse(kudos > 0, 1, 0) #if at least 1 Kudo is send, tie exists
# running time (in hours per week)
time_run <- array(c(clubdata[, "time_run_1.2019"], clubdata[, "time_run_2.2019"], clubdata[, "time_run_3.2019"],
clubdata[, "time_run_4.2019"], clubdata[, "time_run_5.2019"], clubdata[, "time_run_6.2019"],
clubdata[, "time_run_7.2019"], clubdata[, "time_run_8.2019"], clubdata[, "time_run_9.2019"],
clubdata[, "time_run_10.2019"], clubdata[, "time_run_11.2019"], clubdata[, "time_run_12.2019"]),
dim = c(size, 1, n_waves)) # minutes per month
time_run_h <- time_run/60 # hours per month
# time_run_30 <- time_run_h * 2 # half hours
time <- ceiling(time_run_h/4) # per week
# provide some descriptives
# time %>% # absolute table() time %>% # proportionate table() %>%
# prop.table() %>% round(3) cumprop <- time %>% # cumulative proportions table() %>%
# prop.table() %>% round(3) %>% cumsum() print(cumprop) 1-cumprop # the percentage of all
# values that is higher than the particular value
# our idea was to cap running time of at 7+ hours per week. this resulted in rather smooth
# (right-skewed) distribution of values for most clubs except for club 5, where 7+ hours
# category was highly populated over time. We added 2 extra categories (capped of at 9+
# hours); this resulted in a rather smooth distribution for this club.
if (club_id == "clubid5") {
time_run_temp <- ifelse(time > 9, 9, time)
} else {
time_run_temp <- ifelse(time > 7, 7, time)
}
# running frequency (times per week)
freq_run <- array(c(clubdata[, "X.run_1.2019"], clubdata[, "X.run_2.2019"], clubdata[, "X.run_3.2019"],
clubdata[, "X.run_4.2019"], clubdata[, "X.run_5.2019"], clubdata[, "X.run_6.2019"], clubdata[,
"X.run_7.2019"], clubdata[, "X.run_8.2019"], clubdata[, "X.run_9.2019"], clubdata[, "X.run_10.2019"],
clubdata[, "X.run_11.2019"], clubdata[, "X.run_12.2019"]), dim = c(size, 1, n_waves)) # frequencies per month
frequencies <- ceiling(freq_run/4) # per week
freq_run_temp <- ifelse(frequencies > 7, 7, frequencies) # cap off at 7 times per week
# we deal with composition change: actors joining the Strava club over time (we assume no leavers);
# node set was determined at t12; from there, we 'scraped backward' in time;
# down below, we count the number of waves, from t1 onward, that actors scored 0 on all DVs
# that is, where the sum of number of kudos in- and out-ties (network activity), frequency and volume (behavior activity), equals 0.
# this number +1 is the wave in which actors are assumed to have joined
# our model will then assume that entries of joiners happen at the midpoint of the unobserved time period between this and the subsequent wave.
sum_dv <- matrix(NA, nr=size, nc=n_waves)
for (i in 1:size) {
for (j in 1:n_waves) {
sum_dv[i,j] <- sum( c( # sum of
kudo_data[i,,j], # number of out-ties of actor i at time j
kudo_data[,i,j], # number of in-ties of actor i at time j
freq_run_temp[i,,j], # running frequency of i at j
time_run_temp[i,,j] # running volume of i at j
))
}
}
t <- rep(1, size) # starting entry t=1
for ( i in 1:size) {
for( j in 1:n_waves) {
# if sum = 0 for actor i in wave j,
# increment the entry period t with 1
if(sum_dv[i,j] == 0) {
t[i] = t[i] + 1
}
# if sum > 0, break the loop
if(sum_dv[i,j] > 0) {
break
}
}
}
# entry-waves cannot surpass 12:
t[which(t>12)] <- 12
# actors that join at t=12, cannot be included into the estimation;
# they are structural zero;
# we exclude the rows (i) and columns (j) corresponding to these actors
# from the kudos matrices
# we also remove these actors' elements from the running variable objects.
# first, identify these actors (get their index)
x <- which(t==12)
# make new arrays to store entries of actors, excluding structural zeros
kudo_data.nm <- array(NA, dim = c(size - length(x),
size - length(x),
n_waves))
freq_run_temp.nm <- array(NA, dim = c(size - length(x), 1, n_waves))
time_run_temp.nm <- array(NA, dim = c(size - length(x), 1, n_waves))
# fill arrays
for (i in 1:n_waves) {
kudo_data.nm[,,i] <- subset(kudo_data[,,i], select = -x)[-x, ]
freq_run_temp.nm[,,i] <- freq_run_temp[,,i][-x]
time_run_temp.nm[,,i] <- time_run_temp[,,i][-x]
}
# and adjust network size accordingly
size.nm <- size - length(x)
# create a list for the times of composition change
# see 4.3.3 of RSIENA manual
comp <- rep(list(NA), size.nm)
for (i in 1:size.nm) {
comp[[i]] <- c(t[-x][i],n_waves)
}
# RSiena GOF functions do not combine properly with the method of joiners and leavers
# But if we use NA codes for the tie variables of absent actors, sienaGOF will work properly.
# get time of joining for each actor:
t_j <- t[which(t!=12)]
# for actors that are partially absent, set entries in the kudos-matrix to NA,
# for those waves they are absent, i.e., waves 1 : (t_j-1)
for ( i in which(t_j>1)) { # for actors that join later
for (j in 1:n_waves) { # for all waves
if(t_j[i]>j) { # if their time of joining comes after the current wave
kudo_data.nm[i,,j] <- NA # set their out-degree entries to NA
kudo_data.nm[,i,j] <- NA # but also their in-degree entries
freq_run_temp.nm[i,1,j] <- NA # and their behaviors
time_run_temp.nm[i,1,j] <- NA
}g
}
}
# let's load other activity data (e.g., cycling, swimming) time
time_ride <- array(c(clubdata[, "time_ride_1.2019"], clubdata[, "time_ride_2.2019"], clubdata[, "time_ride_3.2019"],
clubdata[, "time_ride_4.2019"], clubdata[, "time_ride_5.2019"], clubdata[, "time_ride_6.2019"],
clubdata[, "time_ride_7.2019"], clubdata[, "time_ride_8.2019"], clubdata[, "time_ride_9.2019"],
clubdata[, "time_ride_10.2019"], clubdata[, "time_ride_11.2019"], clubdata[, "time_ride_12.2019"]),
dim = c(size, 1, n_waves))
time_other <- array(c(clubdata[, "time_other_1.2019"], clubdata[, "time_other_2.2019"], clubdata[,
"time_other_3.2019"], clubdata[, "time_other_4.2019"], clubdata[, "time_other_5.2019"], clubdata[,
"time_other_6.2019"], clubdata[, "time_other_7.2019"], clubdata[, "time_other_8.2019"], clubdata[,
"time_other_12.2019"]), dim = c(size, 1, n_waves))
time_other <- time_ride + time_other # minutes per month
time_other_h <- time_other/60 # hours per month
# time_other_h <- time_other_h * 2 # half hours
time <- ceiling(time_other_h/4) #per week
time_other_temp <- ifelse(time > 7, 7, time) # cap off at 7 hours per week
#table(time_other_temp)
# frequency
freq_ride <- array(c(clubdata[, "X.ride_1.2019"], clubdata[, "X.ride_2.2019"], clubdata[, "X.ride_3.2019"],
clubdata[, "X.ride_4.2019"], clubdata[, "X.ride_5.2019"], clubdata[, "X.ride_6.2019"], clubdata[,
"X.ride_7.2019"], clubdata[, "X.ride_8.2019"], clubdata[, "X.ride_9.2019"], clubdata[, "X.ride_10.2019"],
clubdata[, "X.ride_11.2019"], clubdata[, "X.ride_12.2019"]), dim = c(size, 1, n_waves))
freq_other <- array(c(clubdata[, "X.other_1.2019"], clubdata[, "X.other_2.2019"], clubdata[, "X.other_3.2019"],
clubdata[, "X.other_4.2019"], clubdata[, "X.other_5.2019"], clubdata[, "X.other_6.2019"], clubdata[,
"X.other_7.2019"], clubdata[, "X.other_8.2019"], clubdata[, "X.other_9.2019"], clubdata[,
"X.other_10.2019"], clubdata[, "X.other_11.2019"], clubdata[, "X.other_12.2019"]), dim = c(size,
1, n_waves))
freq_other <- freq_ride + freq_other
frequencies <- ceiling(freq_other/4)
freq_other_temp <- ifelse(frequencies > 7, 7, frequencies)
# and again, exclude the structural zeros:
freq_other_temp.nm <- array(NA, dim = c(size.nm, 1, n_waves))
time_other_temp.nm <- array(NA, dim = c(size.nm, 1, n_waves))
for (i in 1:n_waves) {
freq_other_temp.nm[,,i] <- freq_other_temp[,,i][-x]
time_other_temp.nm[,,i] <- time_other_temp[,,i][-x]
}
# separating male/female/other
male <- ifelse(clubdata[, "gender"][-x] == "M", 1,0)
female <- ifelse(clubdata[, "gender"][-x] == "F", 1, 0)
other <- ifelse(clubdata[, "gender"][-x] == "O", 1, 0)
# specify months of winter in case we want to use it as a varying covariate starts with
# december
winter <- rep(c(1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0), size.nm)
winter <- matrix(winter, nr = size.nm, nc = n_waves, byrow = TRUE)
# in case we want to condition on the first activity recorded by users:
st_yr <- clubdata[,'start_date_year']
st_yr <- st_yr[-x] #exclude NAs
start_year <- ifelse(st_yr <= 2011, 1,
ifelse(st_yr == 2012, 2,
ifelse(st_yr == 2013, 3,
ifelse(st_yr == 2014, 4,
ifelse(st_yr == 2015, 5,
ifelse(st_yr == 2016, 6,
ifelse(st_yr == 2017, 7,
ifelse(st_yr == 2018, 8,
9))))))))
#hist(start_year)
# create a list containing all the read club data for the current club
club <- list(friendship = friend_data, kudo = kudo_data.nm, freq_run = freq_run_temp.nm, time_run = time_run_temp.nm,
freq_other = freq_other_temp.nm, time_other = time_other_temp.nm, winter = winter, male = male, female = female,
other = other, netsize = size.nm, composition = comp, novice=start_year)
# save the club object
save(club, file = paste("clubs/", "club", club_id, ".RData", sep = ""))
}
####################################################
# Now that we have saved the clubdata for all clubs, let's combine them in one list
# first clean the working directory, except our club string; we still need that one.
# and our function fload.R
rm(list = setdiff(ls(), c("club_str", "fload.R")))
# load in the separate club-objects
club1 <- fload.R(paste("clubs", "/", "club", club_str[1], ".RData", sep=""))
club2 <- fload.R(paste("clubs", "/", "club", club_str[2], ".RData", sep=""))
club3 <- fload.R(paste("clubs", "/", "club", club_str[3], ".RData", sep=""))
club4 <- fload.R(paste("clubs", "/", "club", club_str[4], ".RData", sep=""))
club5 <- fload.R(paste("clubs", "/", "club", club_str[5], ".RData", sep=""))
# and make a list containing all the clubdata
clubdata <- list(club1, club2, club3, club4, club5)
# save the output
save(clubdata, file = "clubs/clubdata.RData")
LS0tDQp0aXRsZTogIkRhdGEgcHJlcGFyYXRpb24iDQpiaWJsaW9ncmFwaHk6IHJlZmVyZW5jZXMuYmliDQpkYXRlOiAiTGFzdCBjb21waWxlZCBvbiBgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVCLCAlWScpYCINCm91dHB1dDogDQogIGh0bWxfZG9jdW1lbnQ6DQogICAgY3NzOiB0d2Vha3MuY3NzDQogICAgdG9jOiAgdHJ1ZQ0KICAgIHRvY19mbG9hdDogdHJ1ZQ0KICAgIG51bWJlcl9zZWN0aW9uczogZmFsc2UNCiAgICB0b2NfZGVwdGg6IDENCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCi0tLQ0KDQpgYGB7ciwgZ2xvYmFsc2V0dGluZ3MsIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHJlc3VsdHM9J2hpZGUnfQ0KbGlicmFyeShrbml0cikNCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkNCm9wdHNfY2h1bmskc2V0KHRpZHkub3B0cz1saXN0KHdpZHRoLmN1dG9mZj0xMDApLHRpZHk9VFJVRSwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UsY29tbWVudCA9ICIjPiIsIGNhY2hlPVRSVUUsIGNsYXNzLnNvdXJjZT1jKCJ0ZXN0IiksIGNsYXNzLm91dHB1dD1jKCJ0ZXN0MiIpKQ0Kb3B0aW9ucyh3aWR0aCA9IDEwMCkNCnJnbDo6c2V0dXBLbml0cigpDQoNCg0KY29sb3JpemUgPC0gZnVuY3Rpb24oeCwgY29sb3IpIHtzcHJpbnRmKCI8c3BhbiBzdHlsZT0nY29sb3I6ICVzOyc+JXM8L3NwYW4+IiwgY29sb3IsIHgpIH0NCmBgYA0KDQoNCmBgYHtyIGtsaXBweSwgZWNobz1GQUxTRSwgaW5jbHVkZT1UUlVFfQ0Ka2xpcHB5OjprbGlwcHkocG9zaXRpb24gPSBjKCd0b3AnLCAncmlnaHQnKSkNCiNrbGlwcHk6OmtsaXBweShjb2xvciA9ICdkYXJrcmVkJykNCiNrbGlwcHk6OmtsaXBweSh0b29sdGlwX21lc3NhZ2UgPSAnQ2xpY2sgdG8gY29weScsIHRvb2x0aXBfc3VjY2VzcyA9ICdEb25lJykNCmBgYA0KDQoNCi0tLSAgDQoNCiMgR2V0dGluZyBzdGFydGVkDQoNCg0KIyMgY2xlYW4gdXANCg0KYGBge3IsIHJlc3VsdHM9J2hpZGUnfQ0Kcm0obGlzdD1scygpKQ0KYGBgDQoNCjxicj4NCg0KIyMgZ2VuZXJhbCBjdXN0b20gZnVuY3Rpb25zDQoNCi0gYGZwYWNrYWdlLmNoZWNrYDogQ2hlY2sgaWYgcGFja2FnZXMgYXJlIGluc3RhbGxlZCAoYW5kIGluc3RhbGwgaWYgbm90KSBpbiBSIChbc291cmNlXShodHRwczovL3ZiYWxpZ2EuZ2l0aHViLmlvL3ZlcmlmeS10aGF0LXItcGFja2FnZXMtYXJlLWluc3RhbGxlZC1hbmQtbG9hZGVkLykpDQotIGBmbG9hZC5SYDogZnVuY3Rpb24gdG8gbG9hZCBSLW9iamVjdHMgdW5kZXIgbmV3IG5hbWVzLg0KLSBgZmlkbWFrZXJgOiBjcmVhdGluZyBtb2NrIElEcw0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCg0KZnBhY2thZ2UuY2hlY2sgPC0gZnVuY3Rpb24ocGFja2FnZXMpIHsNCiAgICBsYXBwbHkocGFja2FnZXMsIEZVTiA9IGZ1bmN0aW9uKHgpIHsNCiAgICAgICAgaWYgKCFyZXF1aXJlKHgsIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkpIHsNCiAgICAgICAgICAgIGluc3RhbGwucGFja2FnZXMoeCwgZGVwZW5kZW5jaWVzID0gVFJVRSkNCiAgICAgICAgICAgIGxpYnJhcnkoeCwgY2hhcmFjdGVyLm9ubHkgPSBUUlVFKQ0KICAgICAgICB9DQogICAgfSkNCn0NCg0KZmxvYWQuUiAgPC0gZnVuY3Rpb24oZmlsZU5hbWUpew0KICBsb2FkKGZpbGVOYW1lKQ0KICBnZXQobHMoKVtscygpICE9ICJmaWxlTmFtZSJdKQ0KfQ0KDQpmaWRtYWtlciA8LSBmdW5jdGlvbih4KSB7DQogICAgbWF4LnZhbCA9IHggKiAxZSswNQ0KICAgIGNvdW50IDwtIG5jaGFyKGFzLmNoYXJhY3RlcihtYXgudmFsKSkgICMgZmluZCBvdXQgaG93IG1hbnkgJ251bWJlcnMnIGVhY2ggaWQgd2lsbCBoYXZlIGFmdGVyIHRoZSBsZXR0ZXINCiAgICBzaXplIDwtIHBhc3RlKCIlMCIsIGNvdW50LCAiZCIsIHNlcCA9ICIiKSAgIyBzZXQgdGhlIHZhcmlhYmxlIHRvIGJlIGZlZCBpbnRvICdzcHJpbnRmJyB0byBlbnN1cmUgd2UgaGF2ZSBsZWFkaW5nIDAncw0KICAgIGxldHMgPC0gdG91cHBlcihzYW1wbGUobGV0dGVycywgeCwgcmVwbGFjZSA9IFQpKSAgIyByYW5kb21pemluZyB0aGUgbGV0dGVycyANCiAgICBudW1zIDwtIHNwcmludGYoc2l6ZSwgc2FtcGxlKDE6bWF4LnZhbClbMTp4XSkgICMgcmFuZG9taXppbmcgdGhlIG51bWJlcnMsIGFuZCBlbnN1cmluZyB0aGV5IGFsbCBoYXZlIHRoZSBzYW1lIG51bWJlciBvZiBjaGFyYWN0ZXJzDQogICAgaWRzIDwtIHBhc3RlKGxldHMsIG51bXMsIHNlcCA9ICIiKSAgIyBqb2luaW5nIHRoZW0gdG9nZXRoZXINCiAgICByZXR1cm4oaWRzKQ0KICB9DQoNCmBgYA0KDQo8YnI+DQoNCiMjIG5lY2Vzc2FyeSBwYWNrYWdlcw0KDQotIGBSU2llbmFgOiBjcmVhdGluZyBSU2llbmEgZGF0YSBvYmplY3RzDQotIGBkcGx5cmA6IHBhY2thZ2UgZm9yIGRhdGEgd3JhbmdsaW5nDQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KcGFja2FnZXMgPSBjKCJSU2llbmEiLCAiZHBseXIiKQ0KZnBhY2thZ2UuY2hlY2socGFja2FnZXMpDQpgYGANCg0KPGJyPg0KLS0tLQ0KDQojIGNsdWJkYXRhLlJEYXRhDQoNCkluIHRoZSBmb2xsb3dpbmcgc2NyaXB0cyBhIGxpc3QgY29udGFpbmluZyB0aGUgKGFub255bWl6ZWQpIGRhdGEgb2YgYWxsIGNsdWJzIGlzIG1hZGUgKGNsdWJkYXRhLlJEYXRhKS4NCg0KKiBPdXIgcHJpbWFyeSBuZXR3b3JrIHZhcmlhYmxlIGlzIHRoZSBLdWRvcy1uZXR3b3JrLiBBIHRpZSBpIC0+IGogZXhpc3RzIGlmIGVnbyBpIGF3YXJkIGF0IGxlYXN0IDEgS3Vkb3MgdG8gYWx0ZXIgai4NCg0KKiBGb3IgdGhlIGJlaGF2aW9yYWwgZGF0YSB3ZSBpbmNsdWRlIGluZm9ybWF0aW9uIG9uIHRoZSAqZnJlcXVlbmN5KiAoaS5lLiwgaW4gdGltZXMgcGVyIHdlZWspIGFuZCAqdm9sdW1lKiAoaS5lLiwgaW4gaG91cnMgcGVyIHdlZWspIG9mIHJ1bm5pbmcgYWN0aXZpdGllcy4gV2UgaW5jbHVkZWQgYWN0aXZpdHkgKGZyZXF1ZW5jeSBhbmQgdm9sdW1lKSBpbiBvdGhlciBzcG9ydHMgKGUuZy4sIGN5Y2xpbmcgYW5kIHN3aW1taW5nKSBhcyBhIHRpbWUtdmFyeWluZyBjb3ZhcmlhdGUuDQoNCg0KYGBge3IgY2x1YnMsIGV2YWw9RkFMU0V9DQoNCiMgY2x1YiBzdHJpbmcgcmVwcmVzZW50cyB0aGUgY2x1YiBJRA0KY2x1Yl9zdHIgPC0gYygiY2x1YmlkMSIsICJjbHViaWQyIiwgImNsdWJpZDMiLCAiY2x1YmlkNCIgLCJjbHViaWQ1IikgDQoNCiMgdGhlIGZvbGxvd2luZyBzY3JpcHQgcmVhZHMgdGhlIGRhdGEgb2YgdGhlIGNsdWJzIGZyb20gdGhlIGZvbGRlciBmb3IgZWFjaCBjbHViLCBzdG9yZXMgdGhlbSBpbiBhIGxpc3QsIGFuZCBzYXZlcyBpdCBpbiBhbiBvYmplY3QgaW4gdGhlIGxhc3QgZnVuY3Rpb24gY2FsbCBvZiB0aGlzIHNjcmlwdC4gDQoNCg0KZm9yIChpIGluICgxOiBsZW5ndGgoY2x1Yl9zdHIpKSkgew0KICANCiAgY2x1Yl9pZCA8LSBjbHViX3N0cltpXQ0KICANCiAgIyByZWFkIHRoZSBkYXRhIGZyb20gdGhlIGNsdWINCiAgY2x1YmRhdGEgPC0gcmVhZC5jc3YocGFzdGUoImNsdWJzLyIsIGNsdWJfaWQsICIvIiwgImVnb0RhdGFfZXh0ZW5kZWQuY3N2Iiwgc2VwID0gIiIpLCByb3cubmFtZXMgPSBOVUxMLA0KICAgICAgICAgICAgICAgICAgICAgICBzZXAgPSAiLCIpDQogICMgc2F2aW5nIGNsdWIgc2l6ZQ0KICBzaXplIDwtIGxlbmd0aChjbHViZGF0YVssICJnZW5kZXIiXSkNCiAgIyB0aGUgbnVtYmVyIG9mIG1vbnRocyB0aGF0IHdlIHdhbnQgdG8gYWRkIGFzIHdhdmVzDQogIG5fd2F2ZXMgPC0gMTINCiAgDQogICMgbGV0J3MgbG9hZCB0aGUgZnJpZW5kc2hpcC9mb2xsb3dpbmcgbmV0d29yaw0KICBmcmllbmRfZGF0YSA8LSBhcy5tYXRyaXgocmVhZC5jc3YocGFzdGUoImNsdWJzLyIsIGNsdWJfaWQsICIvIiwgInNvY2lhbG5ldHdvcmsuY3N2Iiwgc2VwID0gIiIpLCByb3cubmFtZXMgPSBOVUxMLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VwID0gIiwiKSkNCiAgIyByZW1vdmUgdGhlIGZpcnN0IGNvbHVtbiAocmVwcmVzZW50cyBpbmRleCBtYWRlIGluIHRoZSBjc3YpDQogIGZyaWVuZF9kYXRhIDwtIGZyaWVuZF9kYXRhWywgMjpuY29sKGZyaWVuZF9kYXRhKV0NCiAgDQogICMgYW5kIGFub255bWl6ZSB0aGUgdXNlciBpZCwgd2l0aCBvdXIgaWQtbWFrZXIgZnVuY3Rpb24NCiAgDQogIGZha2VpZCA8LSBmaWRtYWtlcihucm93KGZyaWVuZF9kYXRhKSkgICMgZ2VuZXJhdGUgcmFuZG9tIGlkDQogIGNvbG5hbWVzKGZyaWVuZF9kYXRhKSA8LSBmYWtlaWQgICMgYW5vbnltaXppbmcgdXNlcnMNCiAgDQogICMgbGV0J3MgbG9hZCB0aGUga3Vkb3MgbmV0d29yaw0KICBwYXRoIDwtIHBhc3RlKCJjbHVicy8iLCBjbHViX2lkLCAiLyIsICJrdWRvcyIsIHNlcCA9ICIiKSAgIyBjcmVhdGUgcGF0aA0KICB7DQogICAga3Vkb193MSA8LSBhcy5tYXRyaXgocmVhZC5jc3YocGFzdGUocGF0aCwgIjEtMjAxOS5jc3YiLCBzZXAgPSAiIiksIHJvdy5uYW1lcyA9IE5VTEwsIHNlcCA9ICIsIikpDQogICAga3Vkb193MSA8LSBrdWRvX3cxWywgMjpuY29sKGt1ZG9fdzEpXQ0KICAgIGt1ZG9fdzIgPC0gYXMubWF0cml4KHJlYWQuY3N2KHBhc3RlKHBhdGgsICIyLTIwMTkuY3N2Iiwgc2VwID0gIiIpLCByb3cubmFtZXMgPSBOVUxMLCBzZXAgPSAiLCIpKQ0KICAgIGt1ZG9fdzIgPC0ga3Vkb193MlssIDI6bmNvbChrdWRvX3cyKV0NCiAgICBrdWRvX3czIDwtIGFzLm1hdHJpeChyZWFkLmNzdihwYXN0ZShwYXRoLCAiMy0yMDE5LmNzdiIsIHNlcCA9ICIiKSwgcm93Lm5hbWVzID0gTlVMTCwgc2VwID0gIiwiKSkNCiAgICBrdWRvX3czIDwtIGt1ZG9fdzNbLCAyOm5jb2woa3Vkb193MyldDQogICAga3Vkb193NCA8LSBhcy5tYXRyaXgocmVhZC5jc3YocGFzdGUocGF0aCwgIjQtMjAxOS5jc3YiLCBzZXAgPSAiIiksIHJvdy5uYW1lcyA9IE5VTEwsIHNlcCA9ICIsIikpDQogICAga3Vkb193NCA8LSBrdWRvX3c0WywgMjpuY29sKGt1ZG9fdzQpXQ0KICAgIGt1ZG9fdzUgPC0gYXMubWF0cml4KHJlYWQuY3N2KHBhc3RlKHBhdGgsICI1LTIwMTkuY3N2Iiwgc2VwID0gIiIpLCByb3cubmFtZXMgPSBOVUxMLCBzZXAgPSAiLCIpKQ0KICAgIGt1ZG9fdzUgPC0ga3Vkb193NVssIDI6bmNvbChrdWRvX3c1KV0NCiAgICBrdWRvX3c2IDwtIGFzLm1hdHJpeChyZWFkLmNzdihwYXN0ZShwYXRoLCAiNi0yMDE5LmNzdiIsIHNlcCA9ICIiKSwgcm93Lm5hbWVzID0gTlVMTCwgc2VwID0gIiwiKSkNCiAgICBrdWRvX3c2IDwtIGt1ZG9fdzZbLCAyOm5jb2woa3Vkb193NildDQogICAga3Vkb193NyA8LSBhcy5tYXRyaXgocmVhZC5jc3YocGFzdGUocGF0aCwgIjctMjAxOS5jc3YiLCBzZXAgPSAiIiksIHJvdy5uYW1lcyA9IE5VTEwsIHNlcCA9ICIsIikpDQogICAga3Vkb193NyA8LSBrdWRvX3c3WywgMjpuY29sKGt1ZG9fdzcpXQ0KICAgIGt1ZG9fdzggPC0gYXMubWF0cml4KHJlYWQuY3N2KHBhc3RlKHBhdGgsICI4LTIwMTkuY3N2Iiwgc2VwID0gIiIpLCByb3cubmFtZXMgPSBOVUxMLCBzZXAgPSAiLCIpKQ0KICAgIGt1ZG9fdzggPC0ga3Vkb193OFssIDI6bmNvbChrdWRvX3c4KV0NCiAgICBrdWRvX3c5IDwtIGFzLm1hdHJpeChyZWFkLmNzdihwYXN0ZShwYXRoLCAiOS0yMDE5LmNzdiIsIHNlcCA9ICIiKSwgcm93Lm5hbWVzID0gTlVMTCwgc2VwID0gIiwiKSkNCiAgICBrdWRvX3c5IDwtIGt1ZG9fdzlbLCAyOm5jb2woa3Vkb193OSldDQogICAga3Vkb193MTAgPC0gYXMubWF0cml4KHJlYWQuY3N2KHBhc3RlKHBhdGgsICIxMC0yMDE5LmNzdiIsIHNlcCA9ICIiKSwgcm93Lm5hbWVzID0gTlVMTCwgc2VwID0gIiwiKSkNCiAgICBrdWRvX3cxMCA8LSBrdWRvX3cxMFssIDI6bmNvbChrdWRvX3cxMCldDQogICAga3Vkb193MTEgPC0gYXMubWF0cml4KHJlYWQuY3N2KHBhc3RlKHBhdGgsICIxMS0yMDE5LmNzdiIsIHNlcCA9ICIiKSwgcm93Lm5hbWVzID0gTlVMTCwgc2VwID0gIiwiKSkNCiAgICBrdWRvX3cxMSA8LSBrdWRvX3cxMVssIDI6bmNvbChrdWRvX3cxMSldDQogICAga3Vkb193MTIgPC0gYXMubWF0cml4KHJlYWQuY3N2KHBhc3RlKHBhdGgsICIxMi0yMDE5LmNzdiIsIHNlcCA9ICIiKSwgcm93Lm5hbWVzID0gTlVMTCwgc2VwID0gIiwiKSkNCiAgICBrdWRvX3cxMiA8LSBrdWRvX3cxMlssIDI6bmNvbChrdWRvX3cxMildDQogIH0NCiAga3Vkb3MgPC0gYXJyYXkoYyhrdWRvX3cxLCBrdWRvX3cyLCBrdWRvX3czLCBrdWRvX3c0LCBrdWRvX3c1LCBrdWRvX3c2LCBrdWRvX3c3LCBrdWRvX3c4LCBrdWRvX3c5LA0KICAgICAgICAgICAgICAgICAgIGt1ZG9fdzEwLCBrdWRvX3cxMSwga3Vkb193MTIpLCBkaW0gPSBjKHNpemUsIHNpemUsIG5fd2F2ZXMpKSAgI0t1ZG9zIG1hdHJpeA0KICANCiAga3Vkb19kYXRhIDwtIGlmZWxzZShrdWRvcyA+IDAsIDEsIDApICAjaWYgYXQgbGVhc3QgMSBLdWRvIGlzIHNlbmQsIHRpZSBleGlzdHMNCiAgDQogICMgcnVubmluZyB0aW1lIChpbiBob3VycyBwZXIgd2VlaykNCiAgdGltZV9ydW4gPC0gYXJyYXkoYyhjbHViZGF0YVssICJ0aW1lX3J1bl8xLjIwMTkiXSwgY2x1YmRhdGFbLCAidGltZV9ydW5fMi4yMDE5Il0sIGNsdWJkYXRhWywgInRpbWVfcnVuXzMuMjAxOSJdLA0KICAgICAgICAgICAgICAgICAgICAgIGNsdWJkYXRhWywgInRpbWVfcnVuXzQuMjAxOSJdLCBjbHViZGF0YVssICJ0aW1lX3J1bl81LjIwMTkiXSwgY2x1YmRhdGFbLCAidGltZV9ydW5fNi4yMDE5Il0sDQogICAgICAgICAgICAgICAgICAgICAgY2x1YmRhdGFbLCAidGltZV9ydW5fNy4yMDE5Il0sIGNsdWJkYXRhWywgInRpbWVfcnVuXzguMjAxOSJdLCBjbHViZGF0YVssICJ0aW1lX3J1bl85LjIwMTkiXSwNCiAgICAgICAgICAgICAgICAgICAgICBjbHViZGF0YVssICJ0aW1lX3J1bl8xMC4yMDE5Il0sIGNsdWJkYXRhWywgInRpbWVfcnVuXzExLjIwMTkiXSwgY2x1YmRhdGFbLCAidGltZV9ydW5fMTIuMjAxOSJdKSwNCiAgICAgICAgICAgICAgICAgICAgZGltID0gYyhzaXplLCAxLCBuX3dhdmVzKSkgICMgbWludXRlcyBwZXIgbW9udGgNCiAgdGltZV9ydW5faCA8LSB0aW1lX3J1bi82MCAgIyBob3VycyBwZXIgbW9udGgNCiAgIyB0aW1lX3J1bl8zMCA8LSB0aW1lX3J1bl9oICogMiAjIGhhbGYgaG91cnMNCiAgdGltZSA8LSBjZWlsaW5nKHRpbWVfcnVuX2gvNCkgICMgcGVyIHdlZWsNCiAgDQogICMgcHJvdmlkZSBzb21lIGRlc2NyaXB0aXZlcyANCiAgIyB0aW1lICU+JSAjIGFic29sdXRlIHRhYmxlKCkgdGltZSAlPiUgIyBwcm9wb3J0aW9uYXRlIHRhYmxlKCkgJT4lDQogICMgcHJvcC50YWJsZSgpICU+JSByb3VuZCgzKSBjdW1wcm9wIDwtIHRpbWUgJT4lICMgY3VtdWxhdGl2ZSBwcm9wb3J0aW9ucyB0YWJsZSgpICU+JQ0KICAjIHByb3AudGFibGUoKSAlPiUgcm91bmQoMykgJT4lIGN1bXN1bSgpIHByaW50KGN1bXByb3ApIDEtY3VtcHJvcCAjIHRoZSBwZXJjZW50YWdlIG9mIGFsbA0KICAjIHZhbHVlcyB0aGF0IGlzIGhpZ2hlciB0aGFuIHRoZSBwYXJ0aWN1bGFyIHZhbHVlDQogIA0KICAjIG91ciBpZGVhIHdhcyB0byBjYXAgcnVubmluZyB0aW1lIG9mIGF0IDcrIGhvdXJzIHBlciB3ZWVrLiAgdGhpcyByZXN1bHRlZCBpbiByYXRoZXIgc21vb3RoDQogICMgKHJpZ2h0LXNrZXdlZCkgZGlzdHJpYnV0aW9uIG9mIHZhbHVlcyBmb3IgbW9zdCBjbHVicyBleGNlcHQgZm9yIGNsdWIgNSwgd2hlcmUgNysgaG91cnMNCiAgIyBjYXRlZ29yeSB3YXMgaGlnaGx5IHBvcHVsYXRlZCBvdmVyIHRpbWUuICBXZSBhZGRlZCAyIGV4dHJhIGNhdGVnb3JpZXMgKGNhcHBlZCBvZiBhdCA5Kw0KICAjIGhvdXJzKTsgdGhpcyByZXN1bHRlZCBpbiBhIHJhdGhlciBzbW9vdGggZGlzdHJpYnV0aW9uIGZvciB0aGlzIGNsdWIuDQogIA0KICBpZiAoY2x1Yl9pZCA9PSAiY2x1YmlkNSIpIHsNCiAgICB0aW1lX3J1bl90ZW1wIDwtIGlmZWxzZSh0aW1lID4gOSwgOSwgdGltZSkNCiAgfSBlbHNlIHsNCiAgICB0aW1lX3J1bl90ZW1wIDwtIGlmZWxzZSh0aW1lID4gNywgNywgdGltZSkNCiAgfQ0KICANCiAgIyBydW5uaW5nIGZyZXF1ZW5jeSAodGltZXMgcGVyIHdlZWspDQogIGZyZXFfcnVuIDwtIGFycmF5KGMoY2x1YmRhdGFbLCAiWC5ydW5fMS4yMDE5Il0sIGNsdWJkYXRhWywgIlgucnVuXzIuMjAxOSJdLCBjbHViZGF0YVssICJYLnJ1bl8zLjIwMTkiXSwNCiAgICAgICAgICAgICAgICAgICAgICBjbHViZGF0YVssICJYLnJ1bl80LjIwMTkiXSwgY2x1YmRhdGFbLCAiWC5ydW5fNS4yMDE5Il0sIGNsdWJkYXRhWywgIlgucnVuXzYuMjAxOSJdLCBjbHViZGF0YVssDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlgucnVuXzcuMjAxOSJdLCBjbHViZGF0YVssICJYLnJ1bl84LjIwMTkiXSwgY2x1YmRhdGFbLCAiWC5ydW5fOS4yMDE5Il0sIGNsdWJkYXRhWywgIlgucnVuXzEwLjIwMTkiXSwNCiAgICAgICAgICAgICAgICAgICAgICBjbHViZGF0YVssICJYLnJ1bl8xMS4yMDE5Il0sIGNsdWJkYXRhWywgIlgucnVuXzEyLjIwMTkiXSksIGRpbSA9IGMoc2l6ZSwgMSwgbl93YXZlcykpICAjIGZyZXF1ZW5jaWVzIHBlciBtb250aA0KICBmcmVxdWVuY2llcyA8LSBjZWlsaW5nKGZyZXFfcnVuLzQpICAjIHBlciB3ZWVrDQogIGZyZXFfcnVuX3RlbXAgPC0gaWZlbHNlKGZyZXF1ZW5jaWVzID4gNywgNywgZnJlcXVlbmNpZXMpICAjIGNhcCBvZmYgYXQgNyB0aW1lcyBwZXIgd2Vlaw0KICANCg0KICAjIHdlIGRlYWwgd2l0aCBjb21wb3NpdGlvbiBjaGFuZ2U6IGFjdG9ycyBqb2luaW5nIHRoZSBTdHJhdmEgY2x1YiBvdmVyIHRpbWUgKHdlIGFzc3VtZSBubyBsZWF2ZXJzKTsNCiAgIyBub2RlIHNldCB3YXMgZGV0ZXJtaW5lZCBhdCB0MTI7IGZyb20gdGhlcmUsIHdlICdzY3JhcGVkIGJhY2t3YXJkJyBpbiB0aW1lOw0KICAjIGRvd24gYmVsb3csIHdlIGNvdW50IHRoZSBudW1iZXIgb2Ygd2F2ZXMsIGZyb20gdDEgb253YXJkLCB0aGF0IGFjdG9ycyBzY29yZWQgMCBvbiBhbGwgRFZzIA0KICAjIHRoYXQgaXMsIHdoZXJlIHRoZSBzdW0gb2YgbnVtYmVyIG9mIGt1ZG9zIGluLSBhbmQgb3V0LXRpZXMgKG5ldHdvcmsgYWN0aXZpdHkpLCBmcmVxdWVuY3kgYW5kIHZvbHVtZSAoYmVoYXZpb3IgYWN0aXZpdHkpLCBlcXVhbHMgMC4NCiAgIyB0aGlzIG51bWJlciArMSBpcyB0aGUgd2F2ZSBpbiB3aGljaCBhY3RvcnMgYXJlIGFzc3VtZWQgdG8gaGF2ZSBqb2luZWQgDQogICMgb3VyIG1vZGVsIHdpbGwgdGhlbiBhc3N1bWUgdGhhdCBlbnRyaWVzIG9mIGpvaW5lcnMgaGFwcGVuIGF0IHRoZSBtaWRwb2ludCBvZiB0aGUgdW5vYnNlcnZlZCB0aW1lIHBlcmlvZCBiZXR3ZWVuIHRoaXMgYW5kIHRoZSBzdWJzZXF1ZW50IHdhdmUuDQogIA0KICBzdW1fZHYgPC0gbWF0cml4KE5BLCBucj1zaXplLCBuYz1uX3dhdmVzKQ0KICANCiAgZm9yIChpIGluIDE6c2l6ZSkgew0KICAgIGZvciAoaiBpbiAxOm5fd2F2ZXMpIHsNCiAgICAgIHN1bV9kdltpLGpdIDwtIHN1bSggYyggIyBzdW0gb2YNCiAgICAgICAga3Vkb19kYXRhW2ksLGpdLCAgICAgIyBudW1iZXIgb2Ygb3V0LXRpZXMgb2YgYWN0b3IgaSBhdCB0aW1lIGoNCiAgICAgICAga3Vkb19kYXRhWyxpLGpdLCAgICAgIyBudW1iZXIgb2YgaW4tdGllcyBvZiBhY3RvciBpIGF0IHRpbWUgag0KICAgICAgICBmcmVxX3J1bl90ZW1wW2ksLGpdLCAjIHJ1bm5pbmcgZnJlcXVlbmN5IG9mIGkgYXQgag0KICAgICAgICB0aW1lX3J1bl90ZW1wW2ksLGpdICAjIHJ1bm5pbmcgdm9sdW1lIG9mIGkgYXQgag0KICAgICAgKSkNCiAgICB9DQogIH0NCg0KICB0IDwtIHJlcCgxLCBzaXplKSAjIHN0YXJ0aW5nIGVudHJ5IHQ9MQ0KICBmb3IgKCBpIGluIDE6c2l6ZSkgew0KICAgIGZvciggaiBpbiAxOm5fd2F2ZXMpIHsNCiAgICAgIA0KICAgICAgIyBpZiBzdW0gPSAwIGZvciBhY3RvciBpIGluIHdhdmUgaiwgDQogICAgICAjIGluY3JlbWVudCB0aGUgZW50cnkgcGVyaW9kIHQgd2l0aCAxDQogICAgICBpZihzdW1fZHZbaSxqXSA9PSAwKSB7DQogICAgICAgIHRbaV0gPSB0W2ldICsgMQ0KICAgICAgfQ0KICAgICAgIyBpZiBzdW0gPiAwLCBicmVhayB0aGUgbG9vcA0KICAgICAgaWYoc3VtX2R2W2ksal0gPiAwKSB7DQogICAgICAgIGJyZWFrDQogICAgICB9DQogICAgfQ0KICB9DQogICMgZW50cnktd2F2ZXMgY2Fubm90IHN1cnBhc3MgMTI6DQogIHRbd2hpY2godD4xMildIDwtIDEyDQogIA0KICAjIGFjdG9ycyB0aGF0IGpvaW4gYXQgdD0xMiwgY2Fubm90IGJlIGluY2x1ZGVkIGludG8gdGhlIGVzdGltYXRpb247DQogICMgdGhleSBhcmUgc3RydWN0dXJhbCB6ZXJvOw0KICAjIHdlIGV4Y2x1ZGUgdGhlIHJvd3MgKGkpIGFuZCBjb2x1bW5zIChqKSBjb3JyZXNwb25kaW5nIHRvIHRoZXNlIGFjdG9ycw0KICAjIGZyb20gdGhlIGt1ZG9zIG1hdHJpY2VzDQogICMgd2UgYWxzbyByZW1vdmUgdGhlc2UgYWN0b3JzJyBlbGVtZW50cyBmcm9tIHRoZSBydW5uaW5nIHZhcmlhYmxlIG9iamVjdHMuDQogIA0KICAjIGZpcnN0LCBpZGVudGlmeSB0aGVzZSBhY3RvcnMgKGdldCB0aGVpciBpbmRleCkNCiAgeCA8LSB3aGljaCh0PT0xMikNCiAgDQogICMgbWFrZSBuZXcgYXJyYXlzIHRvIHN0b3JlIGVudHJpZXMgb2YgYWN0b3JzLCBleGNsdWRpbmcgc3RydWN0dXJhbCB6ZXJvcw0KICBrdWRvX2RhdGEubm0gPC0gYXJyYXkoTkEsIGRpbSA9IGMoc2l6ZSAtIGxlbmd0aCh4KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgLSBsZW5ndGgoeCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuX3dhdmVzKSkNCiAgZnJlcV9ydW5fdGVtcC5ubSA8LSBhcnJheShOQSwgZGltID0gYyhzaXplIC0gbGVuZ3RoKHgpLCAxLCBuX3dhdmVzKSkNCiAgdGltZV9ydW5fdGVtcC5ubSA8LSBhcnJheShOQSwgZGltID0gYyhzaXplIC0gbGVuZ3RoKHgpLCAxLCBuX3dhdmVzKSkNCiAgDQogICMgZmlsbCBhcnJheXMgIA0KICBmb3IgKGkgaW4gMTpuX3dhdmVzKSB7DQogICAga3Vkb19kYXRhLm5tWywsaV0gPC0gc3Vic2V0KGt1ZG9fZGF0YVssLGldLCBzZWxlY3QgPSAteClbLXgsIF0NCiAgICBmcmVxX3J1bl90ZW1wLm5tWywsaV0gPC0gZnJlcV9ydW5fdGVtcFssLGldWy14XQ0KICAgIHRpbWVfcnVuX3RlbXAubm1bLCxpXSA8LSB0aW1lX3J1bl90ZW1wWywsaV1bLXhdDQogIH0NCiAgDQogICMgYW5kIGFkanVzdCBuZXR3b3JrIHNpemUgYWNjb3JkaW5nbHkNCiAgc2l6ZS5ubSA8LSBzaXplIC0gbGVuZ3RoKHgpDQoNCg0KICAjIGNyZWF0ZSBhIGxpc3QgZm9yIHRoZSB0aW1lcyBvZiBjb21wb3NpdGlvbiBjaGFuZ2UNCiAgIyBzZWUgNC4zLjMgb2YgUlNJRU5BIG1hbnVhbA0KICBjb21wIDwtIHJlcChsaXN0KE5BKSwgc2l6ZS5ubSkNCiAgZm9yIChpIGluIDE6c2l6ZS5ubSkgew0KICAgIGNvbXBbW2ldXSA8LSBjKHRbLXhdW2ldLG5fd2F2ZXMpDQogIH0NCiAgDQogICMgUlNpZW5hIEdPRiBmdW5jdGlvbnMgZG8gbm90IGNvbWJpbmUgcHJvcGVybHkgd2l0aCB0aGUgbWV0aG9kIG9mIGpvaW5lcnMgYW5kIGxlYXZlcnMNCiAgIyBCdXQgaWYgd2UgdXNlIE5BIGNvZGVzIGZvciB0aGUgdGllIHZhcmlhYmxlcyBvZiBhYnNlbnQgYWN0b3JzLCBzaWVuYUdPRiB3aWxsIHdvcmsgcHJvcGVybHkuDQoNCiAgIyBnZXQgdGltZSBvZiBqb2luaW5nIGZvciBlYWNoIGFjdG9yOg0KICB0X2ogPC0gdFt3aGljaCh0IT0xMildIA0KICANCiAgIyBmb3IgYWN0b3JzIHRoYXQgYXJlIHBhcnRpYWxseSBhYnNlbnQsIHNldCBlbnRyaWVzIGluIHRoZSBrdWRvcy1tYXRyaXggdG8gTkEsIA0KICAjIGZvciB0aG9zZSB3YXZlcyB0aGV5IGFyZSBhYnNlbnQsIGkuZS4sIHdhdmVzIDEgOiAodF9qLTEpDQogIGZvciAoIGkgaW4gd2hpY2godF9qPjEpKSB7ICAgICAjIGZvciBhY3RvcnMgdGhhdCBqb2luIGxhdGVyDQogICAgZm9yIChqIGluIDE6bl93YXZlcykgeyAgICAgICAjIGZvciBhbGwgd2F2ZXMNCiAgICAgIGlmKHRfaltpXT5qKSB7ICAgICAgICAgICAgICMgaWYgdGhlaXIgdGltZSBvZiBqb2luaW5nIGNvbWVzIGFmdGVyIHRoZSBjdXJyZW50IHdhdmUNCiAgICAgICAga3Vkb19kYXRhLm5tW2ksLGpdIDwtIE5BICMgc2V0IHRoZWlyIG91dC1kZWdyZWUgZW50cmllcyB0byBOQQ0KICAgICAgICBrdWRvX2RhdGEubm1bLGksal0gPC0gTkEgIyBidXQgYWxzbyB0aGVpciBpbi1kZWdyZWUgZW50cmllcw0KICAgICAgICBmcmVxX3J1bl90ZW1wLm5tW2ksMSxqXSA8LSBOQSAjIGFuZCB0aGVpciBiZWhhdmlvcnMNCiAgICAgICAgdGltZV9ydW5fdGVtcC5ubVtpLDEsal0gPC0gTkENCiAgICAgIH1nDQogICAgfQ0KICB9DQoNCiAgIyAgbGV0J3MgbG9hZCBvdGhlciBhY3Rpdml0eSBkYXRhIChlLmcuLCBjeWNsaW5nLCBzd2ltbWluZykgdGltZQ0KICB0aW1lX3JpZGUgPC0gYXJyYXkoYyhjbHViZGF0YVssICJ0aW1lX3JpZGVfMS4yMDE5Il0sIGNsdWJkYXRhWywgInRpbWVfcmlkZV8yLjIwMTkiXSwgY2x1YmRhdGFbLCAidGltZV9yaWRlXzMuMjAxOSJdLA0KICAgICAgICAgICAgICAgICAgICAgICBjbHViZGF0YVssICJ0aW1lX3JpZGVfNC4yMDE5Il0sIGNsdWJkYXRhWywgInRpbWVfcmlkZV81LjIwMTkiXSwgY2x1YmRhdGFbLCAidGltZV9yaWRlXzYuMjAxOSJdLA0KICAgICAgICAgICAgICAgICAgICAgICBjbHViZGF0YVssICJ0aW1lX3JpZGVfNy4yMDE5Il0sIGNsdWJkYXRhWywgInRpbWVfcmlkZV84LjIwMTkiXSwgY2x1YmRhdGFbLCAidGltZV9yaWRlXzkuMjAxOSJdLA0KICAgICAgICAgICAgICAgICAgICAgICBjbHViZGF0YVssICJ0aW1lX3JpZGVfMTAuMjAxOSJdLCBjbHViZGF0YVssICJ0aW1lX3JpZGVfMTEuMjAxOSJdLCBjbHViZGF0YVssICJ0aW1lX3JpZGVfMTIuMjAxOSJdKSwNCiAgICAgICAgICAgICAgICAgICAgIGRpbSA9IGMoc2l6ZSwgMSwgbl93YXZlcykpDQogIHRpbWVfb3RoZXIgPC0gYXJyYXkoYyhjbHViZGF0YVssICJ0aW1lX290aGVyXzEuMjAxOSJdLCBjbHViZGF0YVssICJ0aW1lX290aGVyXzIuMjAxOSJdLCBjbHViZGF0YVssDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAidGltZV9vdGhlcl8zLjIwMTkiXSwgY2x1YmRhdGFbLCAidGltZV9vdGhlcl80LjIwMTkiXSwgY2x1YmRhdGFbLCAidGltZV9vdGhlcl81LjIwMTkiXSwgY2x1YmRhdGFbLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ0aW1lX290aGVyXzYuMjAxOSJdLCBjbHViZGF0YVssICJ0aW1lX290aGVyXzcuMjAxOSJdLCBjbHViZGF0YVssICJ0aW1lX290aGVyXzguMjAxOSJdLCBjbHViZGF0YVssDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ0aW1lX290aGVyXzEyLjIwMTkiXSksIGRpbSA9IGMoc2l6ZSwgMSwgbl93YXZlcykpDQoNCiAgdGltZV9vdGhlciA8LSB0aW1lX3JpZGUgKyB0aW1lX290aGVyICAjIG1pbnV0ZXMgcGVyIG1vbnRoDQogIHRpbWVfb3RoZXJfaCA8LSB0aW1lX290aGVyLzYwICAjIGhvdXJzIHBlciBtb250aA0KICAjIHRpbWVfb3RoZXJfaCA8LSB0aW1lX290aGVyX2ggKiAyICMgaGFsZiBob3Vycw0KICB0aW1lIDwtIGNlaWxpbmcodGltZV9vdGhlcl9oLzQpICAjcGVyIHdlZWsNCiAgdGltZV9vdGhlcl90ZW1wIDwtIGlmZWxzZSh0aW1lID4gNywgNywgdGltZSkgICMgY2FwIG9mZiBhdCA3IGhvdXJzIHBlciB3ZWVrDQogICN0YWJsZSh0aW1lX290aGVyX3RlbXApDQogIA0KICAjIGZyZXF1ZW5jeQ0KICBmcmVxX3JpZGUgPC0gYXJyYXkoYyhjbHViZGF0YVssICJYLnJpZGVfMS4yMDE5Il0sIGNsdWJkYXRhWywgIlgucmlkZV8yLjIwMTkiXSwgY2x1YmRhdGFbLCAiWC5yaWRlXzMuMjAxOSJdLA0KICAgICAgICAgICAgICAgICAgICAgICBjbHViZGF0YVssICJYLnJpZGVfNC4yMDE5Il0sIGNsdWJkYXRhWywgIlgucmlkZV81LjIwMTkiXSwgY2x1YmRhdGFbLCAiWC5yaWRlXzYuMjAxOSJdLCBjbHViZGF0YVssDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJYLnJpZGVfNy4yMDE5Il0sIGNsdWJkYXRhWywgIlgucmlkZV84LjIwMTkiXSwgY2x1YmRhdGFbLCAiWC5yaWRlXzkuMjAxOSJdLCBjbHViZGF0YVssICJYLnJpZGVfMTAuMjAxOSJdLA0KICAgICAgICAgICAgICAgICAgICAgICBjbHViZGF0YVssICJYLnJpZGVfMTEuMjAxOSJdLCBjbHViZGF0YVssICJYLnJpZGVfMTIuMjAxOSJdKSwgZGltID0gYyhzaXplLCAxLCBuX3dhdmVzKSkNCiAgZnJlcV9vdGhlciA8LSBhcnJheShjKGNsdWJkYXRhWywgIlgub3RoZXJfMS4yMDE5Il0sIGNsdWJkYXRhWywgIlgub3RoZXJfMi4yMDE5Il0sIGNsdWJkYXRhWywgIlgub3RoZXJfMy4yMDE5Il0sDQogICAgICAgICAgICAgICAgICAgICAgICBjbHViZGF0YVssICJYLm90aGVyXzQuMjAxOSJdLCBjbHViZGF0YVssICJYLm90aGVyXzUuMjAxOSJdLCBjbHViZGF0YVssICJYLm90aGVyXzYuMjAxOSJdLCBjbHViZGF0YVssDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiWC5vdGhlcl83LjIwMTkiXSwgY2x1YmRhdGFbLCAiWC5vdGhlcl84LjIwMTkiXSwgY2x1YmRhdGFbLCAiWC5vdGhlcl85LjIwMTkiXSwgY2x1YmRhdGFbLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJYLm90aGVyXzEwLjIwMTkiXSwgY2x1YmRhdGFbLCAiWC5vdGhlcl8xMS4yMDE5Il0sIGNsdWJkYXRhWywgIlgub3RoZXJfMTIuMjAxOSJdKSwgZGltID0gYyhzaXplLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxLCBuX3dhdmVzKSkNCiAgDQogIGZyZXFfb3RoZXIgPC0gZnJlcV9yaWRlICsgZnJlcV9vdGhlcg0KICBmcmVxdWVuY2llcyA8LSBjZWlsaW5nKGZyZXFfb3RoZXIvNCkNCiAgZnJlcV9vdGhlcl90ZW1wIDwtIGlmZWxzZShmcmVxdWVuY2llcyA+IDcsIDcsIGZyZXF1ZW5jaWVzKQ0KICANCiAgIyBhbmQgYWdhaW4sIGV4Y2x1ZGUgdGhlIHN0cnVjdHVyYWwgemVyb3M6DQogIGZyZXFfb3RoZXJfdGVtcC5ubSA8LSBhcnJheShOQSwgZGltID0gYyhzaXplLm5tLCAxLCBuX3dhdmVzKSkNCiAgdGltZV9vdGhlcl90ZW1wLm5tIDwtIGFycmF5KE5BLCBkaW0gPSBjKHNpemUubm0sIDEsIG5fd2F2ZXMpKQ0KICBmb3IgKGkgaW4gMTpuX3dhdmVzKSB7DQogICAgZnJlcV9vdGhlcl90ZW1wLm5tWywsaV0gPC0gZnJlcV9vdGhlcl90ZW1wWywsaV1bLXhdDQogICAgdGltZV9vdGhlcl90ZW1wLm5tWywsaV0gPC0gdGltZV9vdGhlcl90ZW1wWywsaV1bLXhdDQogIH0NCiAgDQogICMgc2VwYXJhdGluZyBtYWxlL2ZlbWFsZS9vdGhlcg0KICANCiAgbWFsZSA8LSBpZmVsc2UoY2x1YmRhdGFbLCAiZ2VuZGVyIl1bLXhdID09ICJNIiwgMSwwKQ0KICBmZW1hbGUgPC0gaWZlbHNlKGNsdWJkYXRhWywgImdlbmRlciJdWy14XSA9PSAiRiIsIDEsIDApDQogIG90aGVyIDwtIGlmZWxzZShjbHViZGF0YVssICJnZW5kZXIiXVsteF0gPT0gIk8iLCAxLCAwKQ0KICANCiAgIyBzcGVjaWZ5IG1vbnRocyBvZiB3aW50ZXIgaW4gY2FzZSB3ZSB3YW50IHRvIHVzZSBpdCBhcyBhIHZhcnlpbmcgY292YXJpYXRlIHN0YXJ0cyB3aXRoDQogICMgZGVjZW1iZXINCiAgd2ludGVyIDwtIHJlcChjKDEsIDEsIDEsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDApLCBzaXplLm5tKQ0KICB3aW50ZXIgPC0gbWF0cml4KHdpbnRlciwgbnIgPSBzaXplLm5tLCBuYyA9IG5fd2F2ZXMsIGJ5cm93ID0gVFJVRSkNCiAgDQogICMgaW4gY2FzZSB3ZSB3YW50IHRvIGNvbmRpdGlvbiBvbiB0aGUgZmlyc3QgYWN0aXZpdHkgcmVjb3JkZWQgYnkgdXNlcnM6DQogIHN0X3lyIDwtIGNsdWJkYXRhWywnc3RhcnRfZGF0ZV95ZWFyJ10NCiAgc3RfeXIgPC0gc3RfeXJbLXhdICNleGNsdWRlIE5Bcw0KICANCiAgc3RhcnRfeWVhciA8LSBpZmVsc2Uoc3RfeXIgPD0gMjAxMSwgMSwgDQogICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShzdF95ciA9PSAyMDEyLCAyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHN0X3lyID09IDIwMTMsIDMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHN0X3lyID09IDIwMTQsIDQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShzdF95ciA9PSAyMDE1LCA1LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHN0X3lyID09IDIwMTYsIDYsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHN0X3lyID09IDIwMTcsIDcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShzdF95ciA9PSAyMDE4LCA4LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgOSkpKSkpKSkpDQogICNoaXN0KHN0YXJ0X3llYXIpDQogIA0KICAjIGNyZWF0ZSBhIGxpc3QgY29udGFpbmluZyBhbGwgdGhlIHJlYWQgY2x1YiBkYXRhIGZvciB0aGUgY3VycmVudCBjbHViDQogIGNsdWIgPC0gbGlzdChmcmllbmRzaGlwID0gZnJpZW5kX2RhdGEsIGt1ZG8gPSBrdWRvX2RhdGEubm0sIGZyZXFfcnVuID0gZnJlcV9ydW5fdGVtcC5ubSwgdGltZV9ydW4gPSB0aW1lX3J1bl90ZW1wLm5tLA0KICAgICAgICAgICAgICAgZnJlcV9vdGhlciA9IGZyZXFfb3RoZXJfdGVtcC5ubSwgdGltZV9vdGhlciA9IHRpbWVfb3RoZXJfdGVtcC5ubSwgd2ludGVyID0gd2ludGVyLCBtYWxlID0gbWFsZSwgZmVtYWxlID0gZmVtYWxlLA0KICAgICAgICAgICAgICAgb3RoZXIgPSBvdGhlciwgbmV0c2l6ZSA9IHNpemUubm0sIGNvbXBvc2l0aW9uID0gY29tcCwgbm92aWNlPXN0YXJ0X3llYXIpDQogIA0KICANCiAgIyBzYXZlIHRoZSBjbHViIG9iamVjdA0KICBzYXZlKGNsdWIsIGZpbGUgPSBwYXN0ZSgiY2x1YnMvIiwgImNsdWIiLCBjbHViX2lkLCAiLlJEYXRhIiwgc2VwID0gIiIpKQ0KICANCn0NCg0KDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQoNCiMgTm93IHRoYXQgd2UgaGF2ZSBzYXZlZCB0aGUgY2x1YmRhdGEgZm9yIGFsbCBjbHVicywgbGV0J3MgY29tYmluZSB0aGVtIGluIG9uZSBsaXN0DQoNCiMgZmlyc3QgY2xlYW4gdGhlIHdvcmtpbmcgZGlyZWN0b3J5LCBleGNlcHQgb3VyIGNsdWIgc3RyaW5nOyB3ZSBzdGlsbCBuZWVkIHRoYXQgb25lLg0KIyBhbmQgb3VyIGZ1bmN0aW9uIGZsb2FkLlINCnJtKGxpc3QgPSBzZXRkaWZmKGxzKCksIGMoImNsdWJfc3RyIiwgImZsb2FkLlIiKSkpDQoNCg0KIyBsb2FkIGluIHRoZSBzZXBhcmF0ZSBjbHViLW9iamVjdHMNCmNsdWIxIDwtIGZsb2FkLlIocGFzdGUoImNsdWJzIiwgIi8iLCAiY2x1YiIsIGNsdWJfc3RyWzFdLCAiLlJEYXRhIiwgc2VwPSIiKSkNCmNsdWIyIDwtIGZsb2FkLlIocGFzdGUoImNsdWJzIiwgIi8iLCAiY2x1YiIsIGNsdWJfc3RyWzJdLCAiLlJEYXRhIiwgc2VwPSIiKSkNCmNsdWIzIDwtIGZsb2FkLlIocGFzdGUoImNsdWJzIiwgIi8iLCAiY2x1YiIsIGNsdWJfc3RyWzNdLCAiLlJEYXRhIiwgc2VwPSIiKSkNCmNsdWI0IDwtIGZsb2FkLlIocGFzdGUoImNsdWJzIiwgIi8iLCAiY2x1YiIsIGNsdWJfc3RyWzRdLCAiLlJEYXRhIiwgc2VwPSIiKSkNCmNsdWI1IDwtIGZsb2FkLlIocGFzdGUoImNsdWJzIiwgIi8iLCAiY2x1YiIsIGNsdWJfc3RyWzVdLCAiLlJEYXRhIiwgc2VwPSIiKSkNCg0KIyBhbmQgbWFrZSBhIGxpc3QgY29udGFpbmluZyBhbGwgdGhlIGNsdWJkYXRhDQpjbHViZGF0YSA8LSBsaXN0KGNsdWIxLCBjbHViMiwgY2x1YjMsIGNsdWI0LCBjbHViNSkNCg0KIyBzYXZlIHRoZSBvdXRwdXQNCnNhdmUoY2x1YmRhdGEsIGZpbGUgPSAiY2x1YnMvY2x1YmRhdGEuUkRhdGEiKQ0KDQoNCmBgYCANCg0KLS0tICANCg0KIyBjbHViZGF0YV9yc2llbmEuUkRhdGENCg0KVGhlIGZvbGxvd2luZyBzY3JpcHQgY3JlYXRlcyBhIGxpc3QgY29udGFpbmluZyBSU2llbmEgb2JqZWN0cyBmb3IgYWxsIGNsdWJzLiANCldlIGNyZWF0ZSBhIGxpc3QgY29udGFpbmluZyBSU2llbmEgb2JqZWN0cyB3aXRoIHJ1bm5pbmcgZnJlcXVlbmN5IGFzIHRoZSBiZWhhdmlvciB2YXJpYWJsZSAoY2x1YmRhdGFfcnNpZW5hX2ZyZXEuUkRhdGEpIGFuZCBydW5uaW5nIHZvbHVtZSAoY2x1YmRhdGFfcnNpZW5hX3ZvbC5SRGF0YSkuIA0KDQpOb3RlOiBpbiBzb21lIGdyb3VwcywgZGVwZW5kZW50IHZhcmlhYmxlcyAoZWl0aGVyIHRoZSBrdWRvcy1uZXR3b3JrIG9yIHJ1bm5pbmcgYmVoYXZpb3JzKSBvbmx5IGhhdmUgdXB3YXJkIG9yIGRvd253YXJkIGNoYW5nZXMgaW4gcGFydGljdWxhciBwZXJpb2RzLiBXZSBsaWZ0IFJTaWVuYSdzIGF1dG9tYXRpYyByZXN0cmljdGlvbiB0byAgZm9sbG93IHRoaXMgcGF0dGVybiBpbiB0aGUgc2ltdWxhdGlvbnMsIGJ5IHVzaW5nICcqYWxsb3dPbmx5KiA9IEZBTFNFJy4gVGhpcyBtdXN0IGJlIGRvbmUgZm9yIHRoZSBzdWJzZXF1ZW50IG1ldGEtYW5hbHlzaXMuDQoNCmBgYHtyIGV2YWw9RkFMU0V9DQojIGNsZWFuIHRoZSB3b3JraW5nIGVudmlyb25tZW50IA0Kcm0gKGxpc3QgPSBscyggKSkNCg0KIyBsb2FkIHRoZSBjbHViZGF0YQ0KbG9hZCgiY2x1YnMvY2x1YmRhdGEuUkRhdGEiKQ0Kc3RyKGNsdWJkYXRhKSAjIGluc3BlY3Qgc3RydWN0dXJlDQojIGNsdWJkYXRhIGlzIGEgbGlzdCBvZiA1IGxpc3RzLCANCiMgd2l0aCBlYWNoIG9mIHRoZXNlIGxpc3RzIGNvbnRhaW5pbmcgZGF0YSBvZiB0aGUgY29ycmVzcG9uZGluZyBjbHViLg0KDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQoNCg0KY2x1YmRhdGFfcnNpZW5hX2ZyZXEgPC0gbGlzdCgpDQpjbHViZGF0YV9yc2llbmFfdm9sIDwtIGxpc3QoKQ0KDQoNCmZvciAoaSBpbiAxOjUpIHsgDQogIGNsdWIgPC0gY2x1YmRhdGFbW2ldXQ0KICAjIHNwZWNpZnkgdGhlIHJvbGVzIG9mIHZhcmlhYmxlcw0KICBuYW1lcyhjbHViKQ0KICANCiAgIyBBOiBuZXR3b3JrIHZhcmlhYmxlcw0KICBrdWRvbmV0IDwtIHNpZW5hRGVwZW5kZW50KGNsdWIka3VkbywgYWxsb3dPbmx5ID0gRkFMU0UpICAjYXQgbGVhc3Qgb25lIEt1ZG8NCiAgDQogICMgQjogYmVoYXZpb3JhbCB2YXJpYWJsZXMNCiAgdGltZV9ydW4gPC0gc2llbmFEZXBlbmRlbnQoY2x1YiR0aW1lX3J1biwgdHlwZT0gImJlaGF2aW9yIiwgYWxsb3dPbmx5ID0gRkFMU0UpDQogIGZyZXFfcnVuIDwtIHNpZW5hRGVwZW5kZW50KGNsdWIkZnJlcV9ydW4sIHR5cGU9ICJiZWhhdmlvciIsIGFsbG93T25seSA9IEZBTFNFKQ0KICANCiAgdGltZV9vdGhlciA8LSB2YXJDb3ZhcihjbHViJHRpbWVfb3RoZXJbLCxdKQ0KICBmcmVxX290aGVyIDwtIHZhckNvdmFyKGNsdWIkZnJlcV9vdGhlclssLF0pDQoNCiAgIyBDOiBjb3ZhcmlhdGVzDQogIHdpbnRlciA8LSB2YXJDb3ZhcihjbHViJHdpbnRlcikNCiAgZ2VuZGVyIDwtIE5BICN3ZSBkaWNob3RvbWl6ZSBnZW5kZXIgYXMgYmluYXJ5IChtZW4gdnMuIHdvbWVuIGFuZCBvdGhlcikNCiAgZ2VuZGVyIDwtIGlmZWxzZShjbHViJG1hbGUgPT0gMSwgMSwgZ2VuZGVyKQ0KICBnZW5kZXIgPC0gaWZlbHNlKGNsdWIkZmVtYWxlID09IDEsIDIsIGdlbmRlcikNCiAgZ2VuZGVyIDwtIGlmZWxzZShjbHViJG90aGVyID09IDEsIDIsIGdlbmRlcikNCiAgZ2VuZGVyIDwtIGNvQ292YXIoZ2VuZGVyKQ0KICBub3ZpY2UgPC0gY29Db3ZhcihjbHViJG5vdmljZSkNCiAgDQogIA0KICAjIEQ6IGNvbXBvc2l0aW9uIGNoYW5nZSAoam9pbmVycykNCiAgam9pbmVycyA8LSBzaWVuYUNvbXBvc2l0aW9uQ2hhbmdlKGNsdWIkY29tcG9zaXRpb24pDQogIA0KICAjIG5vdyBjb21iaW5lIHRoZSBkZXBlbmRlbnQgYW5kIGluZGVwZW5kZW50IHZhcmlhYmxlcyBpbiBhIGRhdGEgb2JqZWN0DQogIG15ZGF0YSA8LSBzaWVuYURhdGFDcmVhdGUoa3Vkb25ldCwgZnJlcV9ydW4sIHRpbWVfb3RoZXIsIGZyZXFfb3RoZXIsIGdlbmRlciwgd2ludGVyLCBqb2luZXJzLCBub3ZpY2UpDQogIG15ZGF0YTIgPC0gc2llbmFEYXRhQ3JlYXRlKGt1ZG9uZXQsIHRpbWVfcnVuLCB0aW1lX290aGVyLCBmcmVxX290aGVyLCBnZW5kZXIsIHdpbnRlciwgam9pbmVycywgbm92aWNlKQ0KDQogICMgdGhpcyBmaW5pc2hlcyB0aGUgZGF0YSBzcGVjaWZpY2F0aW9uDQogIGNsdWJkYXRhX3JzaWVuYV9mcmVxW1tpXV0gPC0gbXlkYXRhDQogIGNsdWJkYXRhX3JzaWVuYV92b2xbW2ldXSA8LSBteWRhdGEyDQp9IA0KDQoNCiNjbGVhbiBlbnZpcm9ubWVudA0Kcm0obGlzdCA9IHNldGRpZmYobHMoKSwgYygiY2x1YmRhdGFfcnNpZW5hX2ZyZXEiLCAiY2x1YmRhdGFfcnNpZW5hX3ZvbCIpKSkNCg0KIyBzYXZlIHRoZSBvdXRwdXQNCnNhdmUoY2x1YmRhdGFfcnNpZW5hX2ZyZXEsIGZpbGUgPSAiY2x1YnMvY2x1YmRhdGFfcnNpZW5hX2ZyZXEuUkRhdGEiKQ0Kc2F2ZShjbHViZGF0YV9yc2llbmFfdm9sLCBmaWxlID0gImNsdWJzL2NsdWJkYXRhX3JzaWVuYV92b2wuUkRhdGEiKQ0KYGBgDQoNCg0KDQotLS0NCg0K