Aim: to explore how consequential influence effects are for the running behavior (here, frequency) across clubs.

I reduced the data to only two time-points. Initial effect values are set based on the estimated model parameters of tables 2 and 3 of the manuscript.

I specify additional models: 1) with no peer influence effects whatsoever; 2) with only indegree effect on behavior; 3) with only upward assimilation (avAttHigher); 4) with only downward assimilation (avAttLower).

only 100 simulations were run, but this can be adjusted in the script!



Getting started

clean up

rm (list = ls( ))
#gc()


general custom functions

  • fpackage.check: Check if packages are installed (and install if not) in R (source)
  • fload.R: function to load R-objects under new names.
fpackage.check <- function(packages) {
    lapply(packages, FUN = function(x) {
        if (!require(x, character.only = TRUE)) {
            install.packages(x, dependencies = TRUE)
            library(x, character.only = TRUE)
        }
    })
}

fload.R  <- function(fileName){
  load(fileName)
  get(ls()[ls() != "fileName"])
}

necessary packages

  • RSiena: SIENA as ABM
  • sna
  • lattice: for plotting
  • RColorBrewer: color palettes
packages = c("RSiena", "sna", "lattice", "RColorBrewer")

fpackage.check(packages)


load club data

Load the club list, to set up our starting networks

load("clubdata.RData")


The following scripts makes for all clubs boxplots illustrating how average running behavior values differ across different simulation models.

Models:

  • model 5
  • no_inf
  • only indegree
  • only avAttLower
  • only avAttHigher

simulation models

plotL <- list() # list to store plots in

for (c in 1:length(clubdata)) {

  # pick club

  club <- clubdata[[c]]
  
  # we reduce the data to only two time points
  kudonet <- sienaDependent(club$kudo[,,1:2], allowOnly = FALSE)
  freq_run <- sienaDependent(club$freq_run[,,1:2], type = "behavior", allowOnly = FALSE) 
  time_run <- sienaDependent(club$time_run[,,1:2], type = "behavior", allowOnly = FALSE) 
  
  # covariates
  # changing covariates not possible with only 2 waves, so we make other activity a constant
  freq_other <- coCovar(club$freq_other[, ,1])
  time_other <- coCovar(club$time_other[, ,1])
  gender <- coCovar(ifelse(club$male == 1, 1, 2))
  
  # create a RSiena data object for both models: frequency and volume
  mydata <- sienaDataCreate(kudonet, freq_run, freq_other, gender)
  mydata2<- sienaDataCreate(kudonet, time_run, time_other, gender)
  
  # load in the sienaFit object list, containing estimated parameters
  # for the frequency and volume model
  load(paste0("test/sienaFit/sienaFit_club", c, ".RData")) # freq.
  ans <- sienaFit[[5]] # get object for main model (m5)
  load(paste0("test/sienaFit/duration/sienaFit_club", c, ".RData")) # vol.
  ans2 <- sienaFit[[5]]
  
  # make effects object
  myeff <- getEffects(mydata)
  myeff2 <- getEffects(mydata2)
  # set initial values of basic effects for simulations based on estimated model
  myeff$initialValue[myeff$include==T] <- ans$theta[c(1,12,13,28,39,40)]
  myeff2$initialValue[myeff2$include==T] <- ans2$theta[c(1,12,13,28,39,40)]
  
  # include extra effects and set initial value
  # frequency model
  {
    myeff <- setEffect(myeff, gwespFF, name = "kudonet", initialValue = ans$theta[which(ans$effects$shortName=="gwespFF")])
    myeff <- setEffect(myeff, outActSqrt, name = "kudonet", initialValue = ans$theta[which(ans$effects$shortName=="outActSqrt")])
    myeff <- setEffect(myeff, inPopSqrt, name = "kudonet", initialValue = ans$theta[which(ans$effects$shortName=="inPopSqrt")])
    myeff <- setEffect(myeff, outPopSqrt, name = "kudonet", initialValue = ans$theta[which(ans$effects$shortName=="outPopSqrt")])
    myeff <- setEffect(myeff, reciAct, name = "kudonet", initialValue = ans$theta[which(ans$effects$shortName=="reciAct")])
    myeff <- setEffect(myeff, outIso, name = "kudonet", initialValue = ans$theta[which(ans$effects$shortName=="outIso")])
    myeff <- includeInteraction(myeff, recip, gwespFF, parameter = 69, name = "kudonet")
    (eff1 <- myeff[myeff$include, ]$effect1[10])
    (eff2 <- myeff[myeff$include, ]$effect2[10])
    myeff <- setEffect(myeff, unspInt, effect1 = eff1, effect2 = eff2, initialValue = ans$theta[which(ans$effects$shortName=="unspInt")])
    myeff <- setEffect(myeff, higher, name = "kudonet", interaction1 = "freq_run", initialValue = ans$theta[which(ans$effects$shortName=="higher")])
    myeff <- setEffect(myeff, egoX, name = "kudonet", interaction1 = "gender", initialValue = ans$theta[which(ans$effects$shortName=="egoX" & ans$effects$interaction1=="gender")])
    myeff <- setEffect(myeff, altX, name = "kudonet", interaction1 = "gender", initialValue = ans$theta[which(ans$effects$shortName=="altX" & ans$effects$interaction1=="gender")])
    myeff <- setEffect(myeff, sameX, name = "kudonet", interaction1 = "gender", initialValue = ans$theta[which(ans$effects$shortName=="sameX"& ans$effects$interaction1=="gender")])
    myeff <- setEffect(myeff, effFrom, name = "freq_run", interaction1 = "freq_other", initialValue = ans$theta[which(ans$effects$shortName=="effFrom" & ans$effects$interaction1=="freq_other")])
    myeff <- setEffect(myeff, effFrom, name = "freq_run", interaction1 = "gender", initialValue = ans$theta[which(ans$effects$shortName=="effFrom" & ans$effects$interaction1=="gender")])
    myeff <- setEffect(myeff, indeg, name = "freq_run", interaction1 = "kudonet", initialValue = ans$theta[which(ans$effects$shortName=="indeg")])
    myeff <- setEffect(myeff, avAttHigher, name = "freq_run", interaction1 = "kudonet", initialValue = ans$theta[which(ans$effects$shortName=="avAttHigher")])
    myeff <- setEffect(myeff, avAttLower, name = "freq_run", interaction1 = "kudonet", initialValue = ans$theta[which(ans$effects$shortName=="avAttLower")])
  }
  
  # volume model
  {
    myeff2 <- setEffect(myeff2, gwespFF, name = "kudonet", initialValue = ans2$theta[which(ans2$effects$shortName=="gwespFF")])
    myeff2 <- setEffect(myeff2, outActSqrt, name = "kudonet", initialValue = ans2$theta[which(ans2$effects$shortName=="outActSqrt")])
    myeff2 <- setEffect(myeff2, inPopSqrt, name = "kudonet", initialValue = ans2$theta[which(ans2$effects$shortName=="inPopSqrt")])
    myeff2 <- setEffect(myeff2, outPopSqrt, name = "kudonet", initialValue = ans2$theta[which(ans2$effects$shortName=="outPopSqrt")])
    myeff2 <- setEffect(myeff2, reciAct, name = "kudonet", initialValue = ans2$theta[which(ans2$effects$shortName=="reciAct")])
    myeff2 <- setEffect(myeff2, outIso, name = "kudonet", initialValue = ans2$theta[which(ans2$effects$shortName=="outIso")])
    myeff2 <- includeInteraction(myeff2, recip, gwespFF, parameter = 69, name = "kudonet")
    (eff1 <- myeff2[myeff2$include, ]$effect1[10])
    (eff2 <- myeff2[myeff2$include, ]$effect2[10])
    myeff2 <- setEffect(myeff2, unspInt, effect1 = eff1, effect2 = eff2, initialValue = ans2$theta[which(ans2$effects$shortName=="unspInt")])
    myeff2 <- setEffect(myeff2, higher, name = "kudonet", interaction1 = "time_run", initialValue = ans2$theta[which(ans2$effects$shortName=="higher")])
    myeff2 <- setEffect(myeff2, egoX, name = "kudonet", interaction1 = "gender", initialValue = ans2$theta[which(ans2$effects$shortName=="egoX" & ans2$effects$interaction1=="gender")])
    myeff2 <- setEffect(myeff2, altX, name = "kudonet", interaction1 = "gender", initialValue = ans2$theta[which(ans2$effects$shortName=="altX" & ans2$effects$interaction1=="gender")])
    myeff2 <- setEffect(myeff2, sameX, name = "kudonet", interaction1 = "gender", initialValue = ans2$theta[which(ans2$effects$shortName=="sameX"& ans2$effects$interaction1=="gender")])
    myeff2 <- setEffect(myeff2, effFrom, name = "time_run", interaction1 = "time_other", initialValue = ans2$theta[which(ans2$effects$shortName=="effFrom" & ans2$effects$interaction1=="time_other")])
    myeff2 <- setEffect(myeff2, effFrom, name = "time_run", interaction1 = "gender", initialValue = ans2$theta[which(ans2$effects$shortName=="effFrom" & ans2$effects$interaction1=="gender")])
    myeff2 <- setEffect(myeff2, indeg, name = "time_run", interaction1 = "kudonet", initialValue = ans2$theta[which(ans2$effects$shortName=="indeg")])
    myeff2 <- setEffect(myeff2, avAttHigher, name = "time_run", interaction1 = "kudonet", initialValue = ans2$theta[which(ans2$effects$shortName=="avAttHigher")])
    myeff2 <- setEffect(myeff2, avAttLower, name = "time_run", interaction1 = "kudonet", initialValue = ans2$theta[which(ans2$effects$shortName=="avAttLower")])
  }
  
  # fix effects at this value
  myeff$fix[myeff$include==T] <- TRUE 
  myeff2$fix[myeff2$include==T] <- TRUE 
  
  # I also specify models with no social influences, 
  myeff_noinf <- setEffect(myeff, avAttHigher, name = "freq_run", interaction1 = "kudonet", initialValue = 0, fix = TRUE)
  myeff_noinf <- setEffect(myeff_noinf, avAttLower, name = "freq_run", interaction1 = "kudonet", initialValue = 0, fix = TRUE)
  myeff_noinf <- setEffect(myeff_noinf, indeg, name = "freq_run", interaction1 = "kudonet", initialValue = 0, fix = TRUE)
  
  myeff2_noinf <- setEffect(myeff2, avAttHigher, name = "time_run", interaction1 = "kudonet", initialValue = 0, fix = TRUE)
  myeff2_noinf <- setEffect(myeff2_noinf, avAttLower, name = "time_run", interaction1 = "kudonet", initialValue = 0, fix = TRUE)
  myeff2_noinf <- setEffect(myeff2_noinf, indeg, name = "time_run", interaction1 = "kudonet", initialValue = 0, fix = TRUE)
  
  # only indegree
  myeff_indeg <- setEffect(myeff_noinf, indeg, name = "freq_run", interaction1 = "kudonet", initialValue = ans$theta[which(ans$effects$shortName=="indeg")], fix=TRUE)
  
  myeff2_indeg <- setEffect(myeff2_noinf, indeg, name = "time_run", interaction1 = "kudonet", initialValue = ans2$theta[which(ans2$effects$shortName=="indeg")], fix=TRUE)
  
  # only upward assimilation,
  myeff_nolow <- setEffect(myeff_noinf, avAttHigher, name = "freq_run", interaction1 = "kudonet", initialValue = ans$theta[which(ans$effects$shortName=="avAttHigher")], fix=TRUE)
  
  myeff2_nolow <- setEffect(myeff2_noinf, avAttHigher, name = "time_run", interaction1 = "kudonet", initialValue = ans2$theta[which(ans2$effects$shortName=="avAttHigher")], fix=TRUE)
  
  # and only downward assimilation
  myeff_nohigh <- setEffect(myeff_noinf, avAttLower, name = "freq_run", interaction1 = "kudonet", initialValue = ans$theta[which(ans$effects$shortName=="avAttLower")], fix=TRUE)
  
  myeff2_nohigh <- setEffect(myeff2_noinf, avAttLower, name = "time_run", interaction1 = "kudonet", initialValue = ans2$theta[which(ans2$effects$shortName=="avAttLower")], fix=TRUE)
  
  # set up the simulation settings
  nIter <- 100 # number of iterations
  sim_model <- sienaAlgorithmCreate(
    projname = 'simulation',
    cond = FALSE,
    useStdInits = FALSE, nsub = 0,
    n3 = nIter, 
    seed=242452, # seed for replication
    simOnly = TRUE)
  
  # I will extract the mean running frequency / volume values from the simulation runs
  # make vectors to store means
  meanSimO_freq <- meanSimO_vol <- rep(0, nIter)
  meanSim_noinf_freq <- meanSim_noinf_vol <- rep(0, nIter)
  meanSim_indeg_freq <- meanSim_indeg_vol <- rep(0, nIter)
  meanSim_nolow_freq <- meanSim_nolow_vol <- rep(0, nIter)
  meanSim_nohigh_freq <- meanSim_nohigh_vol <- rep(0, nIter)
  
  # simulation using estimated parameters
  sim_ans <- siena07(sim_model,          # simulation settings
                     data = mydata,      # data
                     effects = myeff,    # defined effects and set parameters
                     returnDeps = TRUE,  # return simulated networks and behaviors
                     returnChains = TRUE,# return sequences of micro-steps
                     batch = TRUE)
  sim_ans2 <- siena07(sim_model,         
                      data = mydata2,      
                      effects = myeff2,    
                      returnDeps = TRUE,  
                      returnChains = TRUE,
                      batch = TRUE)
  
  sim_ans_noinf <- siena07(sim_model,         
                           data = mydata,     
                           effects = myeff_noinf,   
                           returnDeps = TRUE, 
                           returnChains = TRUE,
                           batch = TRUE)
  sim_ans2_noinf <- siena07(sim_model,         
                            data = mydata2,     
                            effects = myeff2_noinf,   
                            returnDeps = TRUE, 
                            returnChains = TRUE,
                            batch = TRUE)
  
  sim_ans_indeg <- siena07(sim_model,         
                           data = mydata,     
                           effects = myeff_indeg,   
                           returnDeps = TRUE, 
                           returnChains = TRUE,
                           batch = TRUE)
  sim_ans2_indeg <- siena07(sim_model,         
                            data = mydata2,     
                            effects = myeff2_indeg,   
                            returnDeps = TRUE, 
                            returnChains = TRUE,
                            batch = TRUE)
  
  sim_ans_nolow <- siena07(sim_model,         
                           data = mydata,     
                           effects = myeff_nolow,   
                           returnDeps = TRUE, 
                           returnChains = TRUE,
                           batch = TRUE)
  sim_ans2_nolow <- siena07(sim_model,         
                            data = mydata2,     
                            effects = myeff2_nolow,   
                            returnDeps = TRUE, 
                            returnChains = TRUE,
                            batch = TRUE)
  
  sim_ans_nohigh <- siena07(sim_model,         
                            data = mydata,     
                            effects = myeff_nohigh,   
                            returnDeps = TRUE, 
                            returnChains = TRUE,
                            batch = TRUE)
  sim_ans2_nohigh <- siena07(sim_model,         
                             data = mydata2,     
                             effects = myeff2_nohigh,   
                             returnDeps = TRUE, 
                             returnChains = TRUE,
                             batch = TRUE)
  
  # extract mean behavior values from simulation runs
  for (i in 1:nIter) {
    meanSimO_freq[i] <- mean(sim_ans$sims[[i]][[1]]$freq_run[[1]])
    meanSimO_vol[i] <- mean(sim_ans2$sims[[i]][[1]]$time_run[[1]])
    meanSim_noinf_freq[i] <- mean(sim_ans_noinf$sims[[i]][[1]]$freq_run[[1]])
    meanSim_noinf_vol[i] <- mean(sim_ans2_noinf$sims[[i]][[1]]$time_run[[1]])
    meanSim_indeg_freq[i] <- mean(sim_ans_indeg$sims[[i]][[1]]$freq_run[[1]])
    meanSim_indeg_vol[i] <- mean(sim_ans2_indeg$sims[[i]][[1]]$time_run[[1]])
    meanSim_nolow_freq[i] <- mean(sim_ans_nolow$sims[[i]][[1]]$freq_run[[1]])
    meanSim_nolow_vol[i] <- mean(sim_ans2_nolow$sims[[i]][[1]]$time_run[[1]])
    meanSim_nohigh_freq[i] <- mean(sim_ans_nohigh$sims[[i]][[1]]$freq_run[[1]])
    meanSim_nohigh_vol[i] <- mean(sim_ans2_nohigh$sims[[i]][[1]]$time_run[[1]])
  }
  #str(sim_ans$sims[[1]]) # numbering is as follows: nIter, group number, DV, period number
  
  # also store observed mean at t2
  meanObs_freq <- mean(club$freq_run[,,2], na.rm = TRUE)
  meanObs_vol <- mean(club$time_run[,,2], na.rm = TRUE)
  
  #  make a layout for the plots
  #dev.off()
  #plot(rnorm(50), rnorm(50))
  l <- layout(matrix(c(1, 2), # sim_vol
                     nrow = 2,
                     ncol = 1,
                     byrow = TRUE))
  #layout.show(l)
  
  # make data for plotting
  plot_data_freq <- rbind(
    data.frame(cond="Observed", mean = meanSimO_freq),
    data.frame(cond="No_inf", mean = meanSim_noinf_freq),
    data.frame(cond="Indeg", mean = meanSim_indeg_freq),
    data.frame(cond="No_avAttL", mean = meanSim_nolow_freq),
    data.frame(cond="No_avAttH", mean = meanSim_nohigh_freq)
  )
  plot_data_vol <- rbind(
    data.frame(cond="Observed", mean = meanSimO_vol),
    data.frame(cond="No_inf", mean = meanSim_noinf_vol),
    data.frame(cond="Indeg", mean = meanSim_indeg_vol),
    data.frame(cond="No_avAttL", mean = meanSim_nolow_vol),
    data.frame(cond="No_avAttH", mean = meanSim_nohigh_vol)
  )
  
  # reorder conditions
  plot_data_freq$cond <- factor(plot_data_freq$cond, levels=c("Observed", "No_inf", "Indeg", "No_avAttL", "No_avAttH"))
  plot_data_vol$cond <- factor(plot_data_vol$cond, levels=c("Observed", "No_inf", "Indeg", "No_avAttL", "No_avAttH"))
  color <- brewer.pal(5, "Set3") # get colors for boxplots
  {
    boxplot(mean ~ cond, data = plot_data_freq, main = paste("Simulation results across", nIter, "iterations"),
            xlab = "Simulation", ylab = "Average running frequency", col = color)
    #abline(h=meanObs_freq, col = "brown") # add the observed mean running at t2
  }
  {
    boxplot(mean ~ cond, data = plot_data_vol, main = paste("Simulation results across", nIter, "iterations"),
            xlab = "Simulation model", ylab = "Average running volume", col = color)
    #abline(h=meanObs_freq, col = "brown") # add the observed mean running at t2
  }
  
  # record the plot and put it in the list
  plotL[[c]] <- recordPlot()

}


Plots

club 1

club 2

club 3

club 4

club 5

LS0tDQp0aXRsZTogIlNBT00gYXMgQUJNIg0KZGF0ZTogIkxhc3QgY29tcGlsZWQgb24gYHIgZm9ybWF0KFN5cy50aW1lKCksICclQiwgJVknKWAiDQpiaWJsaW9ncmFwaHk6IHJlZmVyZW5jZXMuYmliDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgY3NzOiB0d2Vha3MuY3NzDQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgY29sbGFwc2VkOiBmYWxzZQ0KICAgIG51bWJlcl9zZWN0aW9uczogZmFsc2UNCiAgICB0b2NfZGVwdGg6IDENCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCi0tLQ0KICANCmBgYHtyLCBnbG9iYWxzZXR0aW5ncywgZWNobz1GQUxTRSwgd2FybmluZz1GQUxTRSwgcmVzdWx0cz0naGlkZSd9DQpsaWJyYXJ5KGtuaXRyKQ0KbGlicmFyeShSU2llbmEpDQpsaWJyYXJ5KGdncGxvdDIpDQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpDQpvcHRzX2NodW5rJHNldCh0aWR5Lm9wdHM9bGlzdCh3aWR0aC5jdXRvZmY9MTAwKSx0aWR5PVRSVUUsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFLGNvbW1lbnQgPSAiIz4iLCBjYWNoZT1UUlVFLCBjbGFzcy5zb3VyY2U9YygidGVzdCIpLCBjbGFzcy5vdXRwdXQ9YygidGVzdDIiKSkNCm9wdGlvbnMod2lkdGggPSAxMDApDQpyZ2w6OnNldHVwS25pdHIoKQ0KDQpjb2xvcml6ZSA8LSBmdW5jdGlvbih4LCBjb2xvcikge3NwcmludGYoIjxzcGFuIHN0eWxlPSdjb2xvcjogJXM7Jz4lczwvc3Bhbj4iLCBjb2xvciwgeCkgfQ0KDQpgYGANCg0KYGBge3Iga2xpcHB5LCBlY2hvPUZBTFNFLCBpbmNsdWRlPVRSVUV9DQprbGlwcHk6OmtsaXBweShwb3NpdGlvbiA9IGMoJ3RvcCcsICdyaWdodCcpKQ0KI2tsaXBweTo6a2xpcHB5KGNvbG9yID0gJ2RhcmtyZWQnKQ0KI2tsaXBweTo6a2xpcHB5KHRvb2x0aXBfbWVzc2FnZSA9ICdDbGljayB0byBjb3B5JywgdG9vbHRpcF9zdWNjZXNzID0gJ0RvbmUnKQ0KYGBgDQoNCg0KDQotLS0NCiAgDQpBaW06IHRvIGV4cGxvcmUgaG93IGNvbnNlcXVlbnRpYWwgaW5mbHVlbmNlIGVmZmVjdHMgYXJlIGZvciB0aGUgcnVubmluZyBiZWhhdmlvciAoaGVyZSwgZnJlcXVlbmN5KSBhY3Jvc3MgY2x1YnMuDQoNCkkgcmVkdWNlZCB0aGUgZGF0YSB0byBvbmx5IHR3byB0aW1lLXBvaW50cy4gSW5pdGlhbCBlZmZlY3QgdmFsdWVzIGFyZSBzZXQgYmFzZWQgb24gdGhlIGVzdGltYXRlZCBtb2RlbCBwYXJhbWV0ZXJzIG9mIHRhYmxlcyAyIGFuZCAzIG9mIHRoZSBtYW51c2NyaXB0Lg0KDQpJIHNwZWNpZnkgYWRkaXRpb25hbCBtb2RlbHM6IDEpIHdpdGggbm8gcGVlciBpbmZsdWVuY2UgZWZmZWN0cyB3aGF0c29ldmVyOyAyKSB3aXRoIG9ubHkgaW5kZWdyZWUgZWZmZWN0IG9uIGJlaGF2aW9yOyAzKSB3aXRoIG9ubHkgdXB3YXJkIGFzc2ltaWxhdGlvbiAoYXZBdHRIaWdoZXIpOyA0KSB3aXRoIG9ubHkgZG93bndhcmQgYXNzaW1pbGF0aW9uIChhdkF0dExvd2VyKS4NCg0KDQpgciBjb2xvcml6ZSgib25seSAxMDAgc2ltdWxhdGlvbnMgd2VyZSBydW4sIGJ1dCB0aGlzIGNhbiBiZSBhZGp1c3RlZCBpbiB0aGUgc2NyaXB0ISIsICJyZWQiKWANCg0KLS0tLQ0KDQo8YnI+DQoNCiMgR2V0dGluZyBzdGFydGVkDQoNCiMjIGNsZWFuIHVwDQoNCmBgYHtyLCBhdHRyLm91dHB1dD0nc3R5bGU9Im1heC1oZWlnaHQ6IDIwMHB4OyInfQ0KDQpybSAobGlzdCA9IGxzKCApKQ0KI2djKCkNCmBgYA0KDQo8YnI+DQoNCiMjIGdlbmVyYWwgY3VzdG9tIGZ1bmN0aW9ucw0KDQotIGBmcGFja2FnZS5jaGVja2A6IENoZWNrIGlmIHBhY2thZ2VzIGFyZSBpbnN0YWxsZWQgKGFuZCBpbnN0YWxsIGlmIG5vdCkgaW4gUiAoW3NvdXJjZV0oaHR0cHM6Ly92YmFsaWdhLmdpdGh1Yi5pby92ZXJpZnktdGhhdC1yLXBhY2thZ2VzLWFyZS1pbnN0YWxsZWQtYW5kLWxvYWRlZC8pKQ0KLSBgZmxvYWQuUmA6IGZ1bmN0aW9uIHRvIGxvYWQgUi1vYmplY3RzIHVuZGVyIG5ldyBuYW1lcy4NCg0KYGBge3IsIHJlc3VsdHM9J2hpZGUnLCBldmFsPUZBTFNFfQ0KDQpmcGFja2FnZS5jaGVjayA8LSBmdW5jdGlvbihwYWNrYWdlcykgew0KICAgIGxhcHBseShwYWNrYWdlcywgRlVOID0gZnVuY3Rpb24oeCkgew0KICAgICAgICBpZiAoIXJlcXVpcmUoeCwgY2hhcmFjdGVyLm9ubHkgPSBUUlVFKSkgew0KICAgICAgICAgICAgaW5zdGFsbC5wYWNrYWdlcyh4LCBkZXBlbmRlbmNpZXMgPSBUUlVFKQ0KICAgICAgICAgICAgbGlicmFyeSh4LCBjaGFyYWN0ZXIub25seSA9IFRSVUUpDQogICAgICAgIH0NCiAgICB9KQ0KfQ0KDQpmbG9hZC5SICA8LSBmdW5jdGlvbihmaWxlTmFtZSl7DQogIGxvYWQoZmlsZU5hbWUpDQogIGdldChscygpW2xzKCkgIT0gImZpbGVOYW1lIl0pDQp9DQoNCmBgYA0KDQoNCiMjIG5lY2Vzc2FyeSBwYWNrYWdlcw0KDQotIGBSU2llbmFgOiBTSUVOQSBhcyBBQk0NCi0gYHNuYWANCi0gYGxhdHRpY2VgOiBmb3IgcGxvdHRpbmcNCi0gYFJDb2xvckJyZXdlcmA6IGNvbG9yIHBhbGV0dGVzDQoNCg0KYGBge3IgcGFja2FnZXMsIGV2YWw9RkFMU0V9DQoNCnBhY2thZ2VzID0gYygiUlNpZW5hIiwgInNuYSIsICJsYXR0aWNlIiwgIlJDb2xvckJyZXdlciIpDQoNCmZwYWNrYWdlLmNoZWNrKHBhY2thZ2VzKQ0KYGBgDQoNCjxicj4NCg0KIyMgbG9hZCBjbHViIGRhdGENCg0KDQpMb2FkIHRoZSBjbHViIGxpc3QsIHRvIHNldCB1cCBvdXIgc3RhcnRpbmcgbmV0d29ya3MNCmBgYHtyIGV2YWw9Rn0NCmxvYWQoImNsdWJkYXRhLlJEYXRhIikNCmBgYA0KDQoNCjxicj4NCg0KVGhlIGZvbGxvd2luZyBzY3JpcHRzIG1ha2VzIGZvciBhbGwgY2x1YnMgYm94cGxvdHMgaWxsdXN0cmF0aW5nIGhvdyBhdmVyYWdlIHJ1bm5pbmcgYmVoYXZpb3IgdmFsdWVzIGRpZmZlciBhY3Jvc3MgZGlmZmVyZW50IHNpbXVsYXRpb24gbW9kZWxzLg0KDQoqKk1vZGVscyoqOg0KDQotIG1vZGVsIDUNCi0gbm9faW5mDQotIG9ubHkgaW5kZWdyZWUNCi0gb25seSBhdkF0dExvd2VyDQotIG9ubHkgYXZBdHRIaWdoZXINCg0KDQojICBzaW11bGF0aW9uIG1vZGVscw0KYGBge3IsIGV2YWw9Rn0NCnBsb3RMIDwtIGxpc3QoKSAjIGxpc3QgdG8gc3RvcmUgcGxvdHMgaW4NCg0KZm9yIChjIGluIDE6bGVuZ3RoKGNsdWJkYXRhKSkgew0KDQogICMgcGljayBjbHViDQoNCiAgY2x1YiA8LSBjbHViZGF0YVtbY11dDQogIA0KICAjIHdlIHJlZHVjZSB0aGUgZGF0YSB0byBvbmx5IHR3byB0aW1lIHBvaW50cw0KICBrdWRvbmV0IDwtIHNpZW5hRGVwZW5kZW50KGNsdWIka3Vkb1ssLDE6Ml0sIGFsbG93T25seSA9IEZBTFNFKQ0KICBmcmVxX3J1biA8LSBzaWVuYURlcGVuZGVudChjbHViJGZyZXFfcnVuWywsMToyXSwgdHlwZSA9ICJiZWhhdmlvciIsIGFsbG93T25seSA9IEZBTFNFKSANCiAgdGltZV9ydW4gPC0gc2llbmFEZXBlbmRlbnQoY2x1YiR0aW1lX3J1blssLDE6Ml0sIHR5cGUgPSAiYmVoYXZpb3IiLCBhbGxvd09ubHkgPSBGQUxTRSkgDQogIA0KICAjIGNvdmFyaWF0ZXMNCiAgIyBjaGFuZ2luZyBjb3ZhcmlhdGVzIG5vdCBwb3NzaWJsZSB3aXRoIG9ubHkgMiB3YXZlcywgc28gd2UgbWFrZSBvdGhlciBhY3Rpdml0eSBhIGNvbnN0YW50DQogIGZyZXFfb3RoZXIgPC0gY29Db3ZhcihjbHViJGZyZXFfb3RoZXJbLCAsMV0pDQogIHRpbWVfb3RoZXIgPC0gY29Db3ZhcihjbHViJHRpbWVfb3RoZXJbLCAsMV0pDQogIGdlbmRlciA8LSBjb0NvdmFyKGlmZWxzZShjbHViJG1hbGUgPT0gMSwgMSwgMikpDQogIA0KICAjIGNyZWF0ZSBhIFJTaWVuYSBkYXRhIG9iamVjdCBmb3IgYm90aCBtb2RlbHM6IGZyZXF1ZW5jeSBhbmQgdm9sdW1lDQogIG15ZGF0YSA8LSBzaWVuYURhdGFDcmVhdGUoa3Vkb25ldCwgZnJlcV9ydW4sIGZyZXFfb3RoZXIsIGdlbmRlcikNCiAgbXlkYXRhMjwtIHNpZW5hRGF0YUNyZWF0ZShrdWRvbmV0LCB0aW1lX3J1biwgdGltZV9vdGhlciwgZ2VuZGVyKQ0KICANCiAgIyBsb2FkIGluIHRoZSBzaWVuYUZpdCBvYmplY3QgbGlzdCwgY29udGFpbmluZyBlc3RpbWF0ZWQgcGFyYW1ldGVycw0KICAjIGZvciB0aGUgZnJlcXVlbmN5IGFuZCB2b2x1bWUgbW9kZWwNCiAgbG9hZChwYXN0ZTAoInRlc3Qvc2llbmFGaXQvc2llbmFGaXRfY2x1YiIsIGMsICIuUkRhdGEiKSkgIyBmcmVxLg0KICBhbnMgPC0gc2llbmFGaXRbWzVdXSAjIGdldCBvYmplY3QgZm9yIG1haW4gbW9kZWwgKG01KQ0KICBsb2FkKHBhc3RlMCgidGVzdC9zaWVuYUZpdC9kdXJhdGlvbi9zaWVuYUZpdF9jbHViIiwgYywgIi5SRGF0YSIpKSAjIHZvbC4NCiAgYW5zMiA8LSBzaWVuYUZpdFtbNV1dDQogIA0KICAjIG1ha2UgZWZmZWN0cyBvYmplY3QNCiAgbXllZmYgPC0gZ2V0RWZmZWN0cyhteWRhdGEpDQogIG15ZWZmMiA8LSBnZXRFZmZlY3RzKG15ZGF0YTIpDQogICMgc2V0IGluaXRpYWwgdmFsdWVzIG9mIGJhc2ljIGVmZmVjdHMgZm9yIHNpbXVsYXRpb25zIGJhc2VkIG9uIGVzdGltYXRlZCBtb2RlbA0KICBteWVmZiRpbml0aWFsVmFsdWVbbXllZmYkaW5jbHVkZT09VF0gPC0gYW5zJHRoZXRhW2MoMSwxMiwxMywyOCwzOSw0MCldDQogIG15ZWZmMiRpbml0aWFsVmFsdWVbbXllZmYyJGluY2x1ZGU9PVRdIDwtIGFuczIkdGhldGFbYygxLDEyLDEzLDI4LDM5LDQwKV0NCiAgDQogICMgaW5jbHVkZSBleHRyYSBlZmZlY3RzIGFuZCBzZXQgaW5pdGlhbCB2YWx1ZQ0KICAjIGZyZXF1ZW5jeSBtb2RlbA0KICB7DQogICAgbXllZmYgPC0gc2V0RWZmZWN0KG15ZWZmLCBnd2VzcEZGLCBuYW1lID0gImt1ZG9uZXQiLCBpbml0aWFsVmFsdWUgPSBhbnMkdGhldGFbd2hpY2goYW5zJGVmZmVjdHMkc2hvcnROYW1lPT0iZ3dlc3BGRiIpXSkNCiAgICBteWVmZiA8LSBzZXRFZmZlY3QobXllZmYsIG91dEFjdFNxcnQsIG5hbWUgPSAia3Vkb25ldCIsIGluaXRpYWxWYWx1ZSA9IGFucyR0aGV0YVt3aGljaChhbnMkZWZmZWN0cyRzaG9ydE5hbWU9PSJvdXRBY3RTcXJ0IildKQ0KICAgIG15ZWZmIDwtIHNldEVmZmVjdChteWVmZiwgaW5Qb3BTcXJ0LCBuYW1lID0gImt1ZG9uZXQiLCBpbml0aWFsVmFsdWUgPSBhbnMkdGhldGFbd2hpY2goYW5zJGVmZmVjdHMkc2hvcnROYW1lPT0iaW5Qb3BTcXJ0IildKQ0KICAgIG15ZWZmIDwtIHNldEVmZmVjdChteWVmZiwgb3V0UG9wU3FydCwgbmFtZSA9ICJrdWRvbmV0IiwgaW5pdGlhbFZhbHVlID0gYW5zJHRoZXRhW3doaWNoKGFucyRlZmZlY3RzJHNob3J0TmFtZT09Im91dFBvcFNxcnQiKV0pDQogICAgbXllZmYgPC0gc2V0RWZmZWN0KG15ZWZmLCByZWNpQWN0LCBuYW1lID0gImt1ZG9uZXQiLCBpbml0aWFsVmFsdWUgPSBhbnMkdGhldGFbd2hpY2goYW5zJGVmZmVjdHMkc2hvcnROYW1lPT0icmVjaUFjdCIpXSkNCiAgICBteWVmZiA8LSBzZXRFZmZlY3QobXllZmYsIG91dElzbywgbmFtZSA9ICJrdWRvbmV0IiwgaW5pdGlhbFZhbHVlID0gYW5zJHRoZXRhW3doaWNoKGFucyRlZmZlY3RzJHNob3J0TmFtZT09Im91dElzbyIpXSkNCiAgICBteWVmZiA8LSBpbmNsdWRlSW50ZXJhY3Rpb24obXllZmYsIHJlY2lwLCBnd2VzcEZGLCBwYXJhbWV0ZXIgPSA2OSwgbmFtZSA9ICJrdWRvbmV0IikNCiAgICAoZWZmMSA8LSBteWVmZltteWVmZiRpbmNsdWRlLCBdJGVmZmVjdDFbMTBdKQ0KICAgIChlZmYyIDwtIG15ZWZmW215ZWZmJGluY2x1ZGUsIF0kZWZmZWN0MlsxMF0pDQogICAgbXllZmYgPC0gc2V0RWZmZWN0KG15ZWZmLCB1bnNwSW50LCBlZmZlY3QxID0gZWZmMSwgZWZmZWN0MiA9IGVmZjIsIGluaXRpYWxWYWx1ZSA9IGFucyR0aGV0YVt3aGljaChhbnMkZWZmZWN0cyRzaG9ydE5hbWU9PSJ1bnNwSW50IildKQ0KICAgIG15ZWZmIDwtIHNldEVmZmVjdChteWVmZiwgaGlnaGVyLCBuYW1lID0gImt1ZG9uZXQiLCBpbnRlcmFjdGlvbjEgPSAiZnJlcV9ydW4iLCBpbml0aWFsVmFsdWUgPSBhbnMkdGhldGFbd2hpY2goYW5zJGVmZmVjdHMkc2hvcnROYW1lPT0iaGlnaGVyIildKQ0KICAgIG15ZWZmIDwtIHNldEVmZmVjdChteWVmZiwgZWdvWCwgbmFtZSA9ICJrdWRvbmV0IiwgaW50ZXJhY3Rpb24xID0gImdlbmRlciIsIGluaXRpYWxWYWx1ZSA9IGFucyR0aGV0YVt3aGljaChhbnMkZWZmZWN0cyRzaG9ydE5hbWU9PSJlZ29YIiAmIGFucyRlZmZlY3RzJGludGVyYWN0aW9uMT09ImdlbmRlciIpXSkNCiAgICBteWVmZiA8LSBzZXRFZmZlY3QobXllZmYsIGFsdFgsIG5hbWUgPSAia3Vkb25ldCIsIGludGVyYWN0aW9uMSA9ICJnZW5kZXIiLCBpbml0aWFsVmFsdWUgPSBhbnMkdGhldGFbd2hpY2goYW5zJGVmZmVjdHMkc2hvcnROYW1lPT0iYWx0WCIgJiBhbnMkZWZmZWN0cyRpbnRlcmFjdGlvbjE9PSJnZW5kZXIiKV0pDQogICAgbXllZmYgPC0gc2V0RWZmZWN0KG15ZWZmLCBzYW1lWCwgbmFtZSA9ICJrdWRvbmV0IiwgaW50ZXJhY3Rpb24xID0gImdlbmRlciIsIGluaXRpYWxWYWx1ZSA9IGFucyR0aGV0YVt3aGljaChhbnMkZWZmZWN0cyRzaG9ydE5hbWU9PSJzYW1lWCImIGFucyRlZmZlY3RzJGludGVyYWN0aW9uMT09ImdlbmRlciIpXSkNCiAgICBteWVmZiA8LSBzZXRFZmZlY3QobXllZmYsIGVmZkZyb20sIG5hbWUgPSAiZnJlcV9ydW4iLCBpbnRlcmFjdGlvbjEgPSAiZnJlcV9vdGhlciIsIGluaXRpYWxWYWx1ZSA9IGFucyR0aGV0YVt3aGljaChhbnMkZWZmZWN0cyRzaG9ydE5hbWU9PSJlZmZGcm9tIiAmIGFucyRlZmZlY3RzJGludGVyYWN0aW9uMT09ImZyZXFfb3RoZXIiKV0pDQogICAgbXllZmYgPC0gc2V0RWZmZWN0KG15ZWZmLCBlZmZGcm9tLCBuYW1lID0gImZyZXFfcnVuIiwgaW50ZXJhY3Rpb24xID0gImdlbmRlciIsIGluaXRpYWxWYWx1ZSA9IGFucyR0aGV0YVt3aGljaChhbnMkZWZmZWN0cyRzaG9ydE5hbWU9PSJlZmZGcm9tIiAmIGFucyRlZmZlY3RzJGludGVyYWN0aW9uMT09ImdlbmRlciIpXSkNCiAgICBteWVmZiA8LSBzZXRFZmZlY3QobXllZmYsIGluZGVnLCBuYW1lID0gImZyZXFfcnVuIiwgaW50ZXJhY3Rpb24xID0gImt1ZG9uZXQiLCBpbml0aWFsVmFsdWUgPSBhbnMkdGhldGFbd2hpY2goYW5zJGVmZmVjdHMkc2hvcnROYW1lPT0iaW5kZWciKV0pDQogICAgbXllZmYgPC0gc2V0RWZmZWN0KG15ZWZmLCBhdkF0dEhpZ2hlciwgbmFtZSA9ICJmcmVxX3J1biIsIGludGVyYWN0aW9uMSA9ICJrdWRvbmV0IiwgaW5pdGlhbFZhbHVlID0gYW5zJHRoZXRhW3doaWNoKGFucyRlZmZlY3RzJHNob3J0TmFtZT09ImF2QXR0SGlnaGVyIildKQ0KICAgIG15ZWZmIDwtIHNldEVmZmVjdChteWVmZiwgYXZBdHRMb3dlciwgbmFtZSA9ICJmcmVxX3J1biIsIGludGVyYWN0aW9uMSA9ICJrdWRvbmV0IiwgaW5pdGlhbFZhbHVlID0gYW5zJHRoZXRhW3doaWNoKGFucyRlZmZlY3RzJHNob3J0TmFtZT09ImF2QXR0TG93ZXIiKV0pDQogIH0NCiAgDQogICMgdm9sdW1lIG1vZGVsDQogIHsNCiAgICBteWVmZjIgPC0gc2V0RWZmZWN0KG15ZWZmMiwgZ3dlc3BGRiwgbmFtZSA9ICJrdWRvbmV0IiwgaW5pdGlhbFZhbHVlID0gYW5zMiR0aGV0YVt3aGljaChhbnMyJGVmZmVjdHMkc2hvcnROYW1lPT0iZ3dlc3BGRiIpXSkNCiAgICBteWVmZjIgPC0gc2V0RWZmZWN0KG15ZWZmMiwgb3V0QWN0U3FydCwgbmFtZSA9ICJrdWRvbmV0IiwgaW5pdGlhbFZhbHVlID0gYW5zMiR0aGV0YVt3aGljaChhbnMyJGVmZmVjdHMkc2hvcnROYW1lPT0ib3V0QWN0U3FydCIpXSkNCiAgICBteWVmZjIgPC0gc2V0RWZmZWN0KG15ZWZmMiwgaW5Qb3BTcXJ0LCBuYW1lID0gImt1ZG9uZXQiLCBpbml0aWFsVmFsdWUgPSBhbnMyJHRoZXRhW3doaWNoKGFuczIkZWZmZWN0cyRzaG9ydE5hbWU9PSJpblBvcFNxcnQiKV0pDQogICAgbXllZmYyIDwtIHNldEVmZmVjdChteWVmZjIsIG91dFBvcFNxcnQsIG5hbWUgPSAia3Vkb25ldCIsIGluaXRpYWxWYWx1ZSA9IGFuczIkdGhldGFbd2hpY2goYW5zMiRlZmZlY3RzJHNob3J0TmFtZT09Im91dFBvcFNxcnQiKV0pDQogICAgbXllZmYyIDwtIHNldEVmZmVjdChteWVmZjIsIHJlY2lBY3QsIG5hbWUgPSAia3Vkb25ldCIsIGluaXRpYWxWYWx1ZSA9IGFuczIkdGhldGFbd2hpY2goYW5zMiRlZmZlY3RzJHNob3J0TmFtZT09InJlY2lBY3QiKV0pDQogICAgbXllZmYyIDwtIHNldEVmZmVjdChteWVmZjIsIG91dElzbywgbmFtZSA9ICJrdWRvbmV0IiwgaW5pdGlhbFZhbHVlID0gYW5zMiR0aGV0YVt3aGljaChhbnMyJGVmZmVjdHMkc2hvcnROYW1lPT0ib3V0SXNvIildKQ0KICAgIG15ZWZmMiA8LSBpbmNsdWRlSW50ZXJhY3Rpb24obXllZmYyLCByZWNpcCwgZ3dlc3BGRiwgcGFyYW1ldGVyID0gNjksIG5hbWUgPSAia3Vkb25ldCIpDQogICAgKGVmZjEgPC0gbXllZmYyW215ZWZmMiRpbmNsdWRlLCBdJGVmZmVjdDFbMTBdKQ0KICAgIChlZmYyIDwtIG15ZWZmMltteWVmZjIkaW5jbHVkZSwgXSRlZmZlY3QyWzEwXSkNCiAgICBteWVmZjIgPC0gc2V0RWZmZWN0KG15ZWZmMiwgdW5zcEludCwgZWZmZWN0MSA9IGVmZjEsIGVmZmVjdDIgPSBlZmYyLCBpbml0aWFsVmFsdWUgPSBhbnMyJHRoZXRhW3doaWNoKGFuczIkZWZmZWN0cyRzaG9ydE5hbWU9PSJ1bnNwSW50IildKQ0KICAgIG15ZWZmMiA8LSBzZXRFZmZlY3QobXllZmYyLCBoaWdoZXIsIG5hbWUgPSAia3Vkb25ldCIsIGludGVyYWN0aW9uMSA9ICJ0aW1lX3J1biIsIGluaXRpYWxWYWx1ZSA9IGFuczIkdGhldGFbd2hpY2goYW5zMiRlZmZlY3RzJHNob3J0TmFtZT09ImhpZ2hlciIpXSkNCiAgICBteWVmZjIgPC0gc2V0RWZmZWN0KG15ZWZmMiwgZWdvWCwgbmFtZSA9ICJrdWRvbmV0IiwgaW50ZXJhY3Rpb24xID0gImdlbmRlciIsIGluaXRpYWxWYWx1ZSA9IGFuczIkdGhldGFbd2hpY2goYW5zMiRlZmZlY3RzJHNob3J0TmFtZT09ImVnb1giICYgYW5zMiRlZmZlY3RzJGludGVyYWN0aW9uMT09ImdlbmRlciIpXSkNCiAgICBteWVmZjIgPC0gc2V0RWZmZWN0KG15ZWZmMiwgYWx0WCwgbmFtZSA9ICJrdWRvbmV0IiwgaW50ZXJhY3Rpb24xID0gImdlbmRlciIsIGluaXRpYWxWYWx1ZSA9IGFuczIkdGhldGFbd2hpY2goYW5zMiRlZmZlY3RzJHNob3J0TmFtZT09ImFsdFgiICYgYW5zMiRlZmZlY3RzJGludGVyYWN0aW9uMT09ImdlbmRlciIpXSkNCiAgICBteWVmZjIgPC0gc2V0RWZmZWN0KG15ZWZmMiwgc2FtZVgsIG5hbWUgPSAia3Vkb25ldCIsIGludGVyYWN0aW9uMSA9ICJnZW5kZXIiLCBpbml0aWFsVmFsdWUgPSBhbnMyJHRoZXRhW3doaWNoKGFuczIkZWZmZWN0cyRzaG9ydE5hbWU9PSJzYW1lWCImIGFuczIkZWZmZWN0cyRpbnRlcmFjdGlvbjE9PSJnZW5kZXIiKV0pDQogICAgbXllZmYyIDwtIHNldEVmZmVjdChteWVmZjIsIGVmZkZyb20sIG5hbWUgPSAidGltZV9ydW4iLCBpbnRlcmFjdGlvbjEgPSAidGltZV9vdGhlciIsIGluaXRpYWxWYWx1ZSA9IGFuczIkdGhldGFbd2hpY2goYW5zMiRlZmZlY3RzJHNob3J0TmFtZT09ImVmZkZyb20iICYgYW5zMiRlZmZlY3RzJGludGVyYWN0aW9uMT09InRpbWVfb3RoZXIiKV0pDQogICAgbXllZmYyIDwtIHNldEVmZmVjdChteWVmZjIsIGVmZkZyb20sIG5hbWUgPSAidGltZV9ydW4iLCBpbnRlcmFjdGlvbjEgPSAiZ2VuZGVyIiwgaW5pdGlhbFZhbHVlID0gYW5zMiR0aGV0YVt3aGljaChhbnMyJGVmZmVjdHMkc2hvcnROYW1lPT0iZWZmRnJvbSIgJiBhbnMyJGVmZmVjdHMkaW50ZXJhY3Rpb24xPT0iZ2VuZGVyIildKQ0KICAgIG15ZWZmMiA8LSBzZXRFZmZlY3QobXllZmYyLCBpbmRlZywgbmFtZSA9ICJ0aW1lX3J1biIsIGludGVyYWN0aW9uMSA9ICJrdWRvbmV0IiwgaW5pdGlhbFZhbHVlID0gYW5zMiR0aGV0YVt3aGljaChhbnMyJGVmZmVjdHMkc2hvcnROYW1lPT0iaW5kZWciKV0pDQogICAgbXllZmYyIDwtIHNldEVmZmVjdChteWVmZjIsIGF2QXR0SGlnaGVyLCBuYW1lID0gInRpbWVfcnVuIiwgaW50ZXJhY3Rpb24xID0gImt1ZG9uZXQiLCBpbml0aWFsVmFsdWUgPSBhbnMyJHRoZXRhW3doaWNoKGFuczIkZWZmZWN0cyRzaG9ydE5hbWU9PSJhdkF0dEhpZ2hlciIpXSkNCiAgICBteWVmZjIgPC0gc2V0RWZmZWN0KG15ZWZmMiwgYXZBdHRMb3dlciwgbmFtZSA9ICJ0aW1lX3J1biIsIGludGVyYWN0aW9uMSA9ICJrdWRvbmV0IiwgaW5pdGlhbFZhbHVlID0gYW5zMiR0aGV0YVt3aGljaChhbnMyJGVmZmVjdHMkc2hvcnROYW1lPT0iYXZBdHRMb3dlciIpXSkNCiAgfQ0KICANCiAgIyBmaXggZWZmZWN0cyBhdCB0aGlzIHZhbHVlDQogIG15ZWZmJGZpeFtteWVmZiRpbmNsdWRlPT1UXSA8LSBUUlVFIA0KICBteWVmZjIkZml4W215ZWZmMiRpbmNsdWRlPT1UXSA8LSBUUlVFIA0KICANCiAgIyBJIGFsc28gc3BlY2lmeSBtb2RlbHMgd2l0aCBubyBzb2NpYWwgaW5mbHVlbmNlcywgDQogIG15ZWZmX25vaW5mIDwtIHNldEVmZmVjdChteWVmZiwgYXZBdHRIaWdoZXIsIG5hbWUgPSAiZnJlcV9ydW4iLCBpbnRlcmFjdGlvbjEgPSAia3Vkb25ldCIsIGluaXRpYWxWYWx1ZSA9IDAsIGZpeCA9IFRSVUUpDQogIG15ZWZmX25vaW5mIDwtIHNldEVmZmVjdChteWVmZl9ub2luZiwgYXZBdHRMb3dlciwgbmFtZSA9ICJmcmVxX3J1biIsIGludGVyYWN0aW9uMSA9ICJrdWRvbmV0IiwgaW5pdGlhbFZhbHVlID0gMCwgZml4ID0gVFJVRSkNCiAgbXllZmZfbm9pbmYgPC0gc2V0RWZmZWN0KG15ZWZmX25vaW5mLCBpbmRlZywgbmFtZSA9ICJmcmVxX3J1biIsIGludGVyYWN0aW9uMSA9ICJrdWRvbmV0IiwgaW5pdGlhbFZhbHVlID0gMCwgZml4ID0gVFJVRSkNCiAgDQogIG15ZWZmMl9ub2luZiA8LSBzZXRFZmZlY3QobXllZmYyLCBhdkF0dEhpZ2hlciwgbmFtZSA9ICJ0aW1lX3J1biIsIGludGVyYWN0aW9uMSA9ICJrdWRvbmV0IiwgaW5pdGlhbFZhbHVlID0gMCwgZml4ID0gVFJVRSkNCiAgbXllZmYyX25vaW5mIDwtIHNldEVmZmVjdChteWVmZjJfbm9pbmYsIGF2QXR0TG93ZXIsIG5hbWUgPSAidGltZV9ydW4iLCBpbnRlcmFjdGlvbjEgPSAia3Vkb25ldCIsIGluaXRpYWxWYWx1ZSA9IDAsIGZpeCA9IFRSVUUpDQogIG15ZWZmMl9ub2luZiA8LSBzZXRFZmZlY3QobXllZmYyX25vaW5mLCBpbmRlZywgbmFtZSA9ICJ0aW1lX3J1biIsIGludGVyYWN0aW9uMSA9ICJrdWRvbmV0IiwgaW5pdGlhbFZhbHVlID0gMCwgZml4ID0gVFJVRSkNCiAgDQogICMgb25seSBpbmRlZ3JlZQ0KICBteWVmZl9pbmRlZyA8LSBzZXRFZmZlY3QobXllZmZfbm9pbmYsIGluZGVnLCBuYW1lID0gImZyZXFfcnVuIiwgaW50ZXJhY3Rpb24xID0gImt1ZG9uZXQiLCBpbml0aWFsVmFsdWUgPSBhbnMkdGhldGFbd2hpY2goYW5zJGVmZmVjdHMkc2hvcnROYW1lPT0iaW5kZWciKV0sIGZpeD1UUlVFKQ0KICANCiAgbXllZmYyX2luZGVnIDwtIHNldEVmZmVjdChteWVmZjJfbm9pbmYsIGluZGVnLCBuYW1lID0gInRpbWVfcnVuIiwgaW50ZXJhY3Rpb24xID0gImt1ZG9uZXQiLCBpbml0aWFsVmFsdWUgPSBhbnMyJHRoZXRhW3doaWNoKGFuczIkZWZmZWN0cyRzaG9ydE5hbWU9PSJpbmRlZyIpXSwgZml4PVRSVUUpDQogIA0KICAjIG9ubHkgdXB3YXJkIGFzc2ltaWxhdGlvbiwNCiAgbXllZmZfbm9sb3cgPC0gc2V0RWZmZWN0KG15ZWZmX25vaW5mLCBhdkF0dEhpZ2hlciwgbmFtZSA9ICJmcmVxX3J1biIsIGludGVyYWN0aW9uMSA9ICJrdWRvbmV0IiwgaW5pdGlhbFZhbHVlID0gYW5zJHRoZXRhW3doaWNoKGFucyRlZmZlY3RzJHNob3J0TmFtZT09ImF2QXR0SGlnaGVyIildLCBmaXg9VFJVRSkNCiAgDQogIG15ZWZmMl9ub2xvdyA8LSBzZXRFZmZlY3QobXllZmYyX25vaW5mLCBhdkF0dEhpZ2hlciwgbmFtZSA9ICJ0aW1lX3J1biIsIGludGVyYWN0aW9uMSA9ICJrdWRvbmV0IiwgaW5pdGlhbFZhbHVlID0gYW5zMiR0aGV0YVt3aGljaChhbnMyJGVmZmVjdHMkc2hvcnROYW1lPT0iYXZBdHRIaWdoZXIiKV0sIGZpeD1UUlVFKQ0KICANCiAgIyBhbmQgb25seSBkb3dud2FyZCBhc3NpbWlsYXRpb24NCiAgbXllZmZfbm9oaWdoIDwtIHNldEVmZmVjdChteWVmZl9ub2luZiwgYXZBdHRMb3dlciwgbmFtZSA9ICJmcmVxX3J1biIsIGludGVyYWN0aW9uMSA9ICJrdWRvbmV0IiwgaW5pdGlhbFZhbHVlID0gYW5zJHRoZXRhW3doaWNoKGFucyRlZmZlY3RzJHNob3J0TmFtZT09ImF2QXR0TG93ZXIiKV0sIGZpeD1UUlVFKQ0KICANCiAgbXllZmYyX25vaGlnaCA8LSBzZXRFZmZlY3QobXllZmYyX25vaW5mLCBhdkF0dExvd2VyLCBuYW1lID0gInRpbWVfcnVuIiwgaW50ZXJhY3Rpb24xID0gImt1ZG9uZXQiLCBpbml0aWFsVmFsdWUgPSBhbnMyJHRoZXRhW3doaWNoKGFuczIkZWZmZWN0cyRzaG9ydE5hbWU9PSJhdkF0dExvd2VyIildLCBmaXg9VFJVRSkNCiAgDQogICMgc2V0IHVwIHRoZSBzaW11bGF0aW9uIHNldHRpbmdzDQogIG5JdGVyIDwtIDEwMCAjIG51bWJlciBvZiBpdGVyYXRpb25zDQogIHNpbV9tb2RlbCA8LSBzaWVuYUFsZ29yaXRobUNyZWF0ZSgNCiAgICBwcm9qbmFtZSA9ICdzaW11bGF0aW9uJywNCiAgICBjb25kID0gRkFMU0UsDQogICAgdXNlU3RkSW5pdHMgPSBGQUxTRSwgbnN1YiA9IDAsDQogICAgbjMgPSBuSXRlciwgDQogICAgc2VlZD0yNDI0NTIsICMgc2VlZCBmb3IgcmVwbGljYXRpb24NCiAgICBzaW1Pbmx5ID0gVFJVRSkNCiAgDQogICMgSSB3aWxsIGV4dHJhY3QgdGhlIG1lYW4gcnVubmluZyBmcmVxdWVuY3kgLyB2b2x1bWUgdmFsdWVzIGZyb20gdGhlIHNpbXVsYXRpb24gcnVucw0KICAjIG1ha2UgdmVjdG9ycyB0byBzdG9yZSBtZWFucw0KICBtZWFuU2ltT19mcmVxIDwtIG1lYW5TaW1PX3ZvbCA8LSByZXAoMCwgbkl0ZXIpDQogIG1lYW5TaW1fbm9pbmZfZnJlcSA8LSBtZWFuU2ltX25vaW5mX3ZvbCA8LSByZXAoMCwgbkl0ZXIpDQogIG1lYW5TaW1faW5kZWdfZnJlcSA8LSBtZWFuU2ltX2luZGVnX3ZvbCA8LSByZXAoMCwgbkl0ZXIpDQogIG1lYW5TaW1fbm9sb3dfZnJlcSA8LSBtZWFuU2ltX25vbG93X3ZvbCA8LSByZXAoMCwgbkl0ZXIpDQogIG1lYW5TaW1fbm9oaWdoX2ZyZXEgPC0gbWVhblNpbV9ub2hpZ2hfdm9sIDwtIHJlcCgwLCBuSXRlcikNCiAgDQogICMgc2ltdWxhdGlvbiB1c2luZyBlc3RpbWF0ZWQgcGFyYW1ldGVycw0KICBzaW1fYW5zIDwtIHNpZW5hMDcoc2ltX21vZGVsLCAgICAgICAgICAjIHNpbXVsYXRpb24gc2V0dGluZ3MNCiAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBteWRhdGEsICAgICAgIyBkYXRhDQogICAgICAgICAgICAgICAgICAgICBlZmZlY3RzID0gbXllZmYsICAgICMgZGVmaW5lZCBlZmZlY3RzIGFuZCBzZXQgcGFyYW1ldGVycw0KICAgICAgICAgICAgICAgICAgICAgcmV0dXJuRGVwcyA9IFRSVUUsICAjIHJldHVybiBzaW11bGF0ZWQgbmV0d29ya3MgYW5kIGJlaGF2aW9ycw0KICAgICAgICAgICAgICAgICAgICAgcmV0dXJuQ2hhaW5zID0gVFJVRSwjIHJldHVybiBzZXF1ZW5jZXMgb2YgbWljcm8tc3RlcHMNCiAgICAgICAgICAgICAgICAgICAgIGJhdGNoID0gVFJVRSkNCiAgc2ltX2FuczIgPC0gc2llbmEwNyhzaW1fbW9kZWwsICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IG15ZGF0YTIsICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgZWZmZWN0cyA9IG15ZWZmMiwgICAgDQogICAgICAgICAgICAgICAgICAgICAgcmV0dXJuRGVwcyA9IFRSVUUsICANCiAgICAgICAgICAgICAgICAgICAgICByZXR1cm5DaGFpbnMgPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgICAgIGJhdGNoID0gVFJVRSkNCiAgDQogIHNpbV9hbnNfbm9pbmYgPC0gc2llbmEwNyhzaW1fbW9kZWwsICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gbXlkYXRhLCAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICBlZmZlY3RzID0gbXllZmZfbm9pbmYsICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm5EZXBzID0gVFJVRSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm5DaGFpbnMgPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgYmF0Y2ggPSBUUlVFKQ0KICBzaW1fYW5zMl9ub2luZiA8LSBzaWVuYTA3KHNpbV9tb2RlbCwgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gbXlkYXRhMiwgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVmZmVjdHMgPSBteWVmZjJfbm9pbmYsICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuRGVwcyA9IFRSVUUsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybkNoYWlucyA9IFRSVUUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgYmF0Y2ggPSBUUlVFKQ0KICANCiAgc2ltX2Fuc19pbmRlZyA8LSBzaWVuYTA3KHNpbV9tb2RlbCwgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBteWRhdGEsICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGVmZmVjdHMgPSBteWVmZl9pbmRlZywgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybkRlcHMgPSBUUlVFLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybkNoYWlucyA9IFRSVUUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBiYXRjaCA9IFRSVUUpDQogIHNpbV9hbnMyX2luZGVnIDwtIHNpZW5hMDcoc2ltX21vZGVsLCAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBteWRhdGEyLCAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgZWZmZWN0cyA9IG15ZWZmMl9pbmRlZywgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm5EZXBzID0gVFJVRSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuQ2hhaW5zID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYXRjaCA9IFRSVUUpDQogIA0KICBzaW1fYW5zX25vbG93IDwtIHNpZW5hMDcoc2ltX21vZGVsLCAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IG15ZGF0YSwgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgZWZmZWN0cyA9IG15ZWZmX25vbG93LCAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuRGVwcyA9IFRSVUUsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuQ2hhaW5zID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhdGNoID0gVFJVRSkNCiAgc2ltX2FuczJfbm9sb3cgPC0gc2llbmEwNyhzaW1fbW9kZWwsICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IG15ZGF0YTIsICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlZmZlY3RzID0gbXllZmYyX25vbG93LCAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybkRlcHMgPSBUUlVFLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm5DaGFpbnMgPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhdGNoID0gVFJVRSkNCiAgDQogIHNpbV9hbnNfbm9oaWdoIDwtIHNpZW5hMDcoc2ltX21vZGVsLCAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBteWRhdGEsICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlZmZlY3RzID0gbXllZmZfbm9oaWdoLCAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybkRlcHMgPSBUUlVFLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm5DaGFpbnMgPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhdGNoID0gVFJVRSkNCiAgc2ltX2FuczJfbm9oaWdoIDwtIHNpZW5hMDcoc2ltX21vZGVsLCAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gbXlkYXRhMiwgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlZmZlY3RzID0gbXllZmYyX25vaGlnaCwgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuRGVwcyA9IFRSVUUsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm5DaGFpbnMgPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYXRjaCA9IFRSVUUpDQogIA0KICAjIGV4dHJhY3QgbWVhbiBiZWhhdmlvciB2YWx1ZXMgZnJvbSBzaW11bGF0aW9uIHJ1bnMNCiAgZm9yIChpIGluIDE6bkl0ZXIpIHsNCiAgICBtZWFuU2ltT19mcmVxW2ldIDwtIG1lYW4oc2ltX2FucyRzaW1zW1tpXV1bWzFdXSRmcmVxX3J1bltbMV1dKQ0KICAgIG1lYW5TaW1PX3ZvbFtpXSA8LSBtZWFuKHNpbV9hbnMyJHNpbXNbW2ldXVtbMV1dJHRpbWVfcnVuW1sxXV0pDQogICAgbWVhblNpbV9ub2luZl9mcmVxW2ldIDwtIG1lYW4oc2ltX2Fuc19ub2luZiRzaW1zW1tpXV1bWzFdXSRmcmVxX3J1bltbMV1dKQ0KICAgIG1lYW5TaW1fbm9pbmZfdm9sW2ldIDwtIG1lYW4oc2ltX2FuczJfbm9pbmYkc2ltc1tbaV1dW1sxXV0kdGltZV9ydW5bWzFdXSkNCiAgICBtZWFuU2ltX2luZGVnX2ZyZXFbaV0gPC0gbWVhbihzaW1fYW5zX2luZGVnJHNpbXNbW2ldXVtbMV1dJGZyZXFfcnVuW1sxXV0pDQogICAgbWVhblNpbV9pbmRlZ192b2xbaV0gPC0gbWVhbihzaW1fYW5zMl9pbmRlZyRzaW1zW1tpXV1bWzFdXSR0aW1lX3J1bltbMV1dKQ0KICAgIG1lYW5TaW1fbm9sb3dfZnJlcVtpXSA8LSBtZWFuKHNpbV9hbnNfbm9sb3ckc2ltc1tbaV1dW1sxXV0kZnJlcV9ydW5bWzFdXSkNCiAgICBtZWFuU2ltX25vbG93X3ZvbFtpXSA8LSBtZWFuKHNpbV9hbnMyX25vbG93JHNpbXNbW2ldXVtbMV1dJHRpbWVfcnVuW1sxXV0pDQogICAgbWVhblNpbV9ub2hpZ2hfZnJlcVtpXSA8LSBtZWFuKHNpbV9hbnNfbm9oaWdoJHNpbXNbW2ldXVtbMV1dJGZyZXFfcnVuW1sxXV0pDQogICAgbWVhblNpbV9ub2hpZ2hfdm9sW2ldIDwtIG1lYW4oc2ltX2FuczJfbm9oaWdoJHNpbXNbW2ldXVtbMV1dJHRpbWVfcnVuW1sxXV0pDQogIH0NCiAgI3N0cihzaW1fYW5zJHNpbXNbWzFdXSkgIyBudW1iZXJpbmcgaXMgYXMgZm9sbG93czogbkl0ZXIsIGdyb3VwIG51bWJlciwgRFYsIHBlcmlvZCBudW1iZXINCiAgDQogICMgYWxzbyBzdG9yZSBvYnNlcnZlZCBtZWFuIGF0IHQyDQogIG1lYW5PYnNfZnJlcSA8LSBtZWFuKGNsdWIkZnJlcV9ydW5bLCwyXSwgbmEucm0gPSBUUlVFKQ0KICBtZWFuT2JzX3ZvbCA8LSBtZWFuKGNsdWIkdGltZV9ydW5bLCwyXSwgbmEucm0gPSBUUlVFKQ0KICANCiAgIyAgbWFrZSBhIGxheW91dCBmb3IgdGhlIHBsb3RzDQogICNkZXYub2ZmKCkNCiAgI3Bsb3Qocm5vcm0oNTApLCBybm9ybSg1MCkpDQogIGwgPC0gbGF5b3V0KG1hdHJpeChjKDEsIDIpLCAjIHNpbV92b2wNCiAgICAgICAgICAgICAgICAgICAgIG5yb3cgPSAyLA0KICAgICAgICAgICAgICAgICAgICAgbmNvbCA9IDEsDQogICAgICAgICAgICAgICAgICAgICBieXJvdyA9IFRSVUUpKQ0KICAjbGF5b3V0LnNob3cobCkNCiAgDQogICMgbWFrZSBkYXRhIGZvciBwbG90dGluZw0KICBwbG90X2RhdGFfZnJlcSA8LSByYmluZCgNCiAgICBkYXRhLmZyYW1lKGNvbmQ9Ik9ic2VydmVkIiwgbWVhbiA9IG1lYW5TaW1PX2ZyZXEpLA0KICAgIGRhdGEuZnJhbWUoY29uZD0iTm9faW5mIiwgbWVhbiA9IG1lYW5TaW1fbm9pbmZfZnJlcSksDQogICAgZGF0YS5mcmFtZShjb25kPSJJbmRlZyIsIG1lYW4gPSBtZWFuU2ltX2luZGVnX2ZyZXEpLA0KICAgIGRhdGEuZnJhbWUoY29uZD0iTm9fYXZBdHRMIiwgbWVhbiA9IG1lYW5TaW1fbm9sb3dfZnJlcSksDQogICAgZGF0YS5mcmFtZShjb25kPSJOb19hdkF0dEgiLCBtZWFuID0gbWVhblNpbV9ub2hpZ2hfZnJlcSkNCiAgKQ0KICBwbG90X2RhdGFfdm9sIDwtIHJiaW5kKA0KICAgIGRhdGEuZnJhbWUoY29uZD0iT2JzZXJ2ZWQiLCBtZWFuID0gbWVhblNpbU9fdm9sKSwNCiAgICBkYXRhLmZyYW1lKGNvbmQ9Ik5vX2luZiIsIG1lYW4gPSBtZWFuU2ltX25vaW5mX3ZvbCksDQogICAgZGF0YS5mcmFtZShjb25kPSJJbmRlZyIsIG1lYW4gPSBtZWFuU2ltX2luZGVnX3ZvbCksDQogICAgZGF0YS5mcmFtZShjb25kPSJOb19hdkF0dEwiLCBtZWFuID0gbWVhblNpbV9ub2xvd192b2wpLA0KICAgIGRhdGEuZnJhbWUoY29uZD0iTm9fYXZBdHRIIiwgbWVhbiA9IG1lYW5TaW1fbm9oaWdoX3ZvbCkNCiAgKQ0KICANCiAgIyByZW9yZGVyIGNvbmRpdGlvbnMNCiAgcGxvdF9kYXRhX2ZyZXEkY29uZCA8LSBmYWN0b3IocGxvdF9kYXRhX2ZyZXEkY29uZCwgbGV2ZWxzPWMoIk9ic2VydmVkIiwgIk5vX2luZiIsICJJbmRlZyIsICJOb19hdkF0dEwiLCAiTm9fYXZBdHRIIikpDQogIHBsb3RfZGF0YV92b2wkY29uZCA8LSBmYWN0b3IocGxvdF9kYXRhX3ZvbCRjb25kLCBsZXZlbHM9YygiT2JzZXJ2ZWQiLCAiTm9faW5mIiwgIkluZGVnIiwgIk5vX2F2QXR0TCIsICJOb19hdkF0dEgiKSkNCiAgY29sb3IgPC0gYnJld2VyLnBhbCg1LCAiU2V0MyIpICMgZ2V0IGNvbG9ycyBmb3IgYm94cGxvdHMNCiAgew0KICAgIGJveHBsb3QobWVhbiB+IGNvbmQsIGRhdGEgPSBwbG90X2RhdGFfZnJlcSwgbWFpbiA9IHBhc3RlKCJTaW11bGF0aW9uIHJlc3VsdHMgYWNyb3NzIiwgbkl0ZXIsICJpdGVyYXRpb25zIiksDQogICAgICAgICAgICB4bGFiID0gIlNpbXVsYXRpb24iLCB5bGFiID0gIkF2ZXJhZ2UgcnVubmluZyBmcmVxdWVuY3kiLCBjb2wgPSBjb2xvcikNCiAgICAjYWJsaW5lKGg9bWVhbk9ic19mcmVxLCBjb2wgPSAiYnJvd24iKSAjIGFkZCB0aGUgb2JzZXJ2ZWQgbWVhbiBydW5uaW5nIGF0IHQyDQogIH0NCiAgew0KICAgIGJveHBsb3QobWVhbiB+IGNvbmQsIGRhdGEgPSBwbG90X2RhdGFfdm9sLCBtYWluID0gcGFzdGUoIlNpbXVsYXRpb24gcmVzdWx0cyBhY3Jvc3MiLCBuSXRlciwgIml0ZXJhdGlvbnMiKSwNCiAgICAgICAgICAgIHhsYWIgPSAiU2ltdWxhdGlvbiBtb2RlbCIsIHlsYWIgPSAiQXZlcmFnZSBydW5uaW5nIHZvbHVtZSIsIGNvbCA9IGNvbG9yKQ0KICAgICNhYmxpbmUoaD1tZWFuT2JzX2ZyZXEsIGNvbCA9ICJicm93biIpICMgYWRkIHRoZSBvYnNlcnZlZCBtZWFuIHJ1bm5pbmcgYXQgdDINCiAgfQ0KICANCiAgIyByZWNvcmQgdGhlIHBsb3QgYW5kIHB1dCBpdCBpbiB0aGUgbGlzdA0KICBwbG90TFtbY11dIDwtIHJlY29yZFBsb3QoKQ0KDQp9DQoNCmBgYCAgDQoNCg0KPCEtLSAgIyMjDQogIA0KICAjIEkgZXhhbWluZSB0aGUgcnVubmluZyBmcmVxdWVuY3kgY2hhbmdlcyBpbiBncmVhdGVyIGRldGFpbA0KICBuX2FjdG9ycyA8LSBjbHViJG5ldHNpemUNCiAgDQogIFpzNSA8LSBhcnJheShOQSwgZGltPWMobl9hY3RvcnMsMSkpDQogIFpiNSA8LSBhcnJheSAoMCwgZGltPWMobkl0ZXIsMSkpDQogIGZvciAoaSBpbiAxOiBuSXRlcikgew0KICAgIGZvciAoaiBpbiAxOm5fYWN0b3JzKSB7DQogICAgICAjIHNpbXVsYXRlZCBiZWhhdmlvciBvZiBhY3RvciBqIGluIGl0ZXJhdGlvbiBpDQogICAgICBaczVbaiwxXSA8LSBzaW1fYW5zJHNpbXNbW2ldXVtbMV1dJGZyZXFfcnVuW1sxXV1bW2pdXSANCiAgICB9DQogICAgIyBtZWFuIHNpbXVsYXRlZCBiZWhhdmlvciBvdmVyIGFjdG9ycyBpbiBpdGVyYXRpb24gaQ0KICAgIFpiNVtpXSA8LWNvbFN1bXMoWnM1LCBuYS5ybT1UKS9uX2FjdG9ycw0KICB9DQogIA0KICAjY29sTWVhbnMoY2JpbmQoY2x1YiRmcmVxX3J1blssLDE6Ml0pKSAjIG9ic2VydmVkIG1lYW5zIGF0IHQxIGFuZCB0Mg0KICAjY29sTWVhbnMoWmI1KSAgIyBhdmVyYWdlIG1lYW4gc2ltdWxhdGVkIGJlaGF2aW9yIHZhbHVlDQogICNtZWFuKCBzaW1fYW5zJHNpbXNbW25JdGVyXV1bWzFdXSRmcmVxX3J1bltbMV1dICkjIG1lYW4gb2YgbGFzdCBzaW11bGF0aW9uIHJ1bg0KICANCiAgDQogICMgSSBwbG90IHRoZSBtZWFuIHNpbXVsYXRlZCBydW5uaW5nIGZyZXF1ZW5jeSBvdmVyIHRpbWUgDQogICMgZXh0cmFjdCBtZWFuIHJ1bm5pbmcgZm9yIGFsbCBjaGFpbnMsIHdpdGggbmV0d29yayBjaGFuZ2Ugb3Bwb3J0dW5pdGllcyBpbmNsdWRlZA0KICBzaW1DaGFuZ2VzIDwtIHJlcCgwLCBuSXRlcikNCiAgZm9yIChpIGluIDE6IG5JdGVyKSB7c2ltQ2hhbmdlc1tpXSA8LSBsZW5ndGgoc2ltX2FucyRjaGFpbltbaV1dW1sxXV1bWzFdXSkgfQ0KICBtYXhDaGFuZ2VzIDwtIG1heChzaW1DaGFuZ2VzKQ0KICANCiAgc2VxcyA8LSBtYXRyaXgoWmI1LCBucj0gbkl0ZXIsIG5jPW1heENoYW5nZXMrMSkgICMgZmlsbCBtYXRyaXggd2l0aCBmaW5hbCBtZWFuDQogIHNlcXNbLDFdIDwtIG1lYW4oY2x1YiRmcmVxX3J1blssLDFdKSAgICMgc2V0IHQxIG1lYW4gdG8gb2JzZXJ2ZWQgbGV2ZWwNCiAgZm9yIChpIGluIDE6IG5JdGVyKSB7DQogICAgZGF0Q2hhaW4gPC0gdChtYXRyaXgodW5saXN0KHNpbV9hbnMkY2hhaW5bW2ldXVtbMV1dW1sxXV0pLCBuYz1sZW5ndGgoc2ltX2FucyRjaGFpbltbaV1dW1sxXV1bWzFdXSkpKSANCiAgICBmb3IgKGogaW4gMTogc2ltQ2hhbmdlc1tpXSkgew0KICAgICAgaWYgKGRhdENoYWluW2osMl09PSIwIikgeyANCiAgICAgICAgc2Vxc1tpLGorMV0gPC0gc2Vxc1tpLGpdDQogICAgICB9DQogICAgICBpZiAoZGF0Q2hhaW5baiwyXT09IjEiKSB7IA0KICAgICAgICBzZXFzW2ksaisxXSA8LSBzZXFzW2ksal0gKyAoYXMubnVtZXJpYyhkYXRDaGFpbltqLDZdKS9uX2FjdG9ycykNCiAgICAgIH0NCiAgICB9DQogIH0NCiAgIyBwbG90IG11bHRpcGxlIGl0ZXJhdGlvbnMgdXNpbmcgbG9lc3MgY3VydmVzDQogIG1pY3JvcyA8LSAxOmRpbShzZXFzKVsyXQ0KICBsbzEgPC0gbG9lc3Moc2Vxc1sxLF0gfiBtaWNyb3MpDQogIGwxIDwtIHByZWRpY3QobG8xLCBtaWNyb3MpDQogIA0KICAjIHNldCB5bGltOyBzbyBpdCBpcyBjb25zaXN0ZW50IGFjcm9zcyBwbG90cw0KICB5bWluIDwtIHBseXI6OnJvdW5kX2FueShtaW4oc2VxcywgbmEucm09VFJVRSksIC41LCBmPWZsb29yKQ0KICB5bWF4IDwtIHBseXI6OnJvdW5kX2FueShtYXgoc2VxcywgbmEucm09VFJVRSksIC41LCBmPWNlaWxpbmcpDQogIA0KICBwbG90KHg9MTpkaW0oc2VxcylbMl0sIHk9c2Vxc1sxLF0sIHlsaW09Yyh5bWluLHltYXgpLHR5cGU9ImwiLCANCiAgICAgICB5bGFiPSdBdmVyYWdlIHJ1bm5pbmcgZnJlcXVlbmN5JywgeGxhYj0nTWljcm8tc3RlcCcsIGNvbD0nd2hpdGUnLA0KICAgICAgIG1haW49J01lYW4gcnVubmluZyBvdmVyIHRpbWU6DQogICAgIGZ1bGwgbW9kZWwnKQkNCiAgZm9yIChpIGluIDE6MjUpIHsNCiAgICBsaW5lcyh4PW1pY3JvcywgeT1wcmVkaWN0KGxvZXNzKHNlcXNbaSxdIH4gbWljcm9zKSwgbWljcm9zKSwgY29sPWNvbG9ycygpW2kqMTBdKQ0KICB9DQogIA0KICAjIGRvIHRoZSBzYW1lIGZvciB0aGUgbW9kZWwgd2l0aCBubyBwZWVyIGluZmx1ZW5jZSB3aGF0c29ldmVyLiANCiAgZm9yIChpIGluIDE6IG5JdGVyKSB7DQogICAgZm9yIChqIGluIDE6bl9hY3RvcnMpIHsNCiAgICAgICMgc2ltdWxhdGVkIGJlaGF2aW9yIG9mIGFjdG9yIGogaW4gaXRlcmF0aW9uIGkNCiAgICAgIFpzNVtqLDFdIDwtIHNpbV9hbnNfbm9pbmYkc2ltc1tbaV1dW1sxXV0kZnJlcV9ydW5bWzFdXVtbal1dIA0KICAgIH0NCiAgICAjIG1lYW4gc2ltdWxhdGVkIGJlaGF2aW9yIG92ZXIgYWN0b3JzIGluIGl0ZXJhdGlvbiBpDQogICAgWmI1W2ldIDwtY29sU3VtcyhaczUsIG5hLnJtPVQpL25fYWN0b3JzDQogIH0NCiAgZm9yIChpIGluIDE6IG5JdGVyKSB7DQogICAgZGF0Q2hhaW4gPC0gdChtYXRyaXgodW5saXN0KHNpbV9hbnNfbm9pbmYkY2hhaW5bW2ldXVtbMV1dW1sxXV0pLCBuYz1sZW5ndGgoc2ltX2Fuc19ub2luZiRjaGFpbltbaV1dW1sxXV1bWzFdXSkpKSANCiAgICBmb3IgKGogaW4gMTogc2ltQ2hhbmdlc1tpXSkgew0KICAgICAgaWYgKGRhdENoYWluW2osMl09PSIwIikgeyANCiAgICAgICAgc2Vxc1tpLGorMV0gPC0gc2Vxc1tpLGpdDQogICAgICB9DQogICAgICBpZiAoZGF0Q2hhaW5baiwyXT09IjEiKSB7IA0KICAgICAgICBzZXFzW2ksaisxXSA8LSBzZXFzW2ksal0gKyAoYXMubnVtZXJpYyhkYXRDaGFpbltqLDZdKS9uX2FjdG9ycykNCiAgICAgIH0NCiAgICB9DQogIH0NCiAgbWljcm9zIDwtIDE6ZGltKHNlcXMpWzJdDQogIGxvMSA8LSBsb2VzcyhzZXFzWzEsXSB+IG1pY3JvcykNCiAgbDEgPC0gcHJlZGljdChsbzEsIG1pY3JvcykNCiAgDQogIHBsb3QoeD0xOmRpbShzZXFzKVsyXSwgeT1zZXFzWzEsXSwgeWxpbT1jKHltaW4seW1heCksdHlwZT0ibCIsIA0KICAgICAgIHlsYWI9J0F2ZXJhZ2UgcnVubmluZyBmcmVxdWVuY3knLCB4bGFiPSdNaWNyby1zdGVwJywgY29sPSd3aGl0ZScsDQogICAgICAgbWFpbj0nTWVhbiBydW5uaW5nIG92ZXIgdGltZToNCiAgICAgbm8gaW5mbHVlbmNlJykJDQogIGZvciAoaSBpbiAxOjI1KSB7DQogICAgbGluZXMoeD1taWNyb3MsIHk9cHJlZGljdChsb2VzcyhzZXFzW2ksXSB+IG1pY3JvcyksIG1pY3JvcyksIGNvbD1jb2xvcnMoKVtpKjEwXSkNCiAgfQ0KICANCiAgIyBubyBkb3dud2FyZCBhc3NpbWlsYXRpb24uIA0KICBmb3IgKGkgaW4gMTogbkl0ZXIpIHsNCiAgICBmb3IgKGogaW4gMTpuX2FjdG9ycykgew0KICAgICAgIyBzaW11bGF0ZWQgYmVoYXZpb3Igb2YgYWN0b3IgaiBpbiBpdGVyYXRpb24gaQ0KICAgICAgWnM1W2osMV0gPC0gc2ltX2Fuc19ub2xvdyRzaW1zW1tpXV1bWzFdXSRmcmVxX3J1bltbMV1dW1tqXV0gDQogICAgfQ0KICAgICMgbWVhbiBzaW11bGF0ZWQgYmVoYXZpb3Igb3ZlciBhY3RvcnMgaW4gaXRlcmF0aW9uIGkNCiAgICBaYjVbaV0gPC1jb2xTdW1zKFpzNSwgbmEucm09VCkvbl9hY3RvcnMNCiAgfQ0KICANCiAgZm9yIChpIGluIDE6IG5JdGVyKSB7DQogICAgZGF0Q2hhaW4gPC0gdChtYXRyaXgodW5saXN0KHNpbV9hbnNfbm9sb3ckY2hhaW5bW2ldXVtbMV1dW1sxXV0pLCBuYz1sZW5ndGgoc2ltX2Fuc19ub2xvdyRjaGFpbltbaV1dW1sxXV1bWzFdXSkpKSANCiAgICBmb3IgKGogaW4gMTogc2ltQ2hhbmdlc1tpXSkgew0KICAgICAgaWYgKGRhdENoYWluW2osMl09PSIwIikgeyANCiAgICAgICAgc2Vxc1tpLGorMV0gPC0gc2Vxc1tpLGpdDQogICAgICB9DQogICAgICBpZiAoZGF0Q2hhaW5baiwyXT09IjEiKSB7IA0KICAgICAgICBzZXFzW2ksaisxXSA8LSBzZXFzW2ksal0gKyAoYXMubnVtZXJpYyhkYXRDaGFpbltqLDZdKS9uX2FjdG9ycykNCiAgICAgIH0NCiAgICB9DQogIH0NCiAgbWljcm9zIDwtIDE6ZGltKHNlcXMpWzJdDQogIGxvMSA8LSBsb2VzcyhzZXFzWzEsXSB+IG1pY3JvcykNCiAgbDEgPC0gcHJlZGljdChsbzEsIG1pY3JvcykNCiAgDQogIHBsb3QoeD0xOmRpbShzZXFzKVsyXSwgeT1zZXFzWzEsXSwgeWxpbT1jKHltaW4seW1heCksdHlwZT0ibCIsIA0KICAgICAgIHlsYWI9J0F2ZXJhZ2UgcnVubmluZyBmcmVxdWVuY3knLCB4bGFiPSdNaWNyby1zdGVwJywgY29sPSd3aGl0ZScsDQogICAgICAgbWFpbj0nTWVhbiBydW5uaW5nIG92ZXIgdGltZToNCiAgICAgbm8gYXZBdHRMb3dlcicpCQ0KICBmb3IgKGkgaW4gMToyNSkgew0KICAgIGxpbmVzKHg9bWljcm9zLCB5PXByZWRpY3QobG9lc3Moc2Vxc1tpLF0gfiBtaWNyb3MpLCBtaWNyb3MpLCBjb2w9Y29sb3JzKClbaSoxMF0pDQogIH0NCiAgDQogICMgbm8gdXB3YXJkIGFzc2ltaWxhdGlvbi4gDQogIGZvciAoaSBpbiAxOiBuSXRlcikgew0KICAgIGZvciAoaiBpbiAxOm5fYWN0b3JzKSB7DQogICAgICAjIHNpbXVsYXRlZCBiZWhhdmlvciBvZiBhY3RvciBqIGluIGl0ZXJhdGlvbiBpDQogICAgICBaczVbaiwxXSA8LSBzaW1fYW5zX25vaGlnaCRzaW1zW1tpXV1bWzFdXSRmcmVxX3J1bltbMV1dW1tqXV0gDQogICAgfQ0KICAgICMgbWVhbiBzaW11bGF0ZWQgYmVoYXZpb3Igb3ZlciBhY3RvcnMgaW4gaXRlcmF0aW9uIGkNCiAgICBaYjVbaV0gPC1jb2xTdW1zKFpzNSwgbmEucm09VCkvbl9hY3RvcnMNCiAgfQ0KICANCiAgZm9yIChpIGluIDE6IG5JdGVyKSB7DQogICAgZGF0Q2hhaW4gPC0gdChtYXRyaXgodW5saXN0KHNpbV9hbnNfbm9oaWdoJGNoYWluW1tpXV1bWzFdXVtbMV1dKSwgbmM9bGVuZ3RoKHNpbV9hbnNfbm9oaWdoJGNoYWluW1tpXV1bWzFdXVtbMV1dKSkpIA0KICAgIGZvciAoaiBpbiAxOiBzaW1DaGFuZ2VzW2ldKSB7DQogICAgICBpZiAoZGF0Q2hhaW5baiwyXT09IjAiKSB7IA0KICAgICAgICBzZXFzW2ksaisxXSA8LSBzZXFzW2ksal0NCiAgICAgIH0NCiAgICAgIGlmIChkYXRDaGFpbltqLDJdPT0iMSIpIHsgDQogICAgICAgIHNlcXNbaSxqKzFdIDwtIHNlcXNbaSxqXSArIChhcy5udW1lcmljKGRhdENoYWluW2osNl0pL25fYWN0b3JzKQ0KICAgICAgfQ0KICAgIH0NCiAgfQ0KICBtaWNyb3MgPC0gMTpkaW0oc2VxcylbMl0NCiAgbG8xIDwtIGxvZXNzKHNlcXNbMSxdIH4gbWljcm9zKQ0KICBsMSA8LSBwcmVkaWN0KGxvMSwgbWljcm9zKQ0KICANCiAgcGxvdCh4PTE6ZGltKHNlcXMpWzJdLCB5PXNlcXNbMSxdLCB5bGltPWMoeW1pbix5bWF4KSx0eXBlPSJsIiwgDQogICAgICAgeWxhYj0nQXZlcmFnZSBydW5uaW5nIGZyZXF1ZW5jeScsIHhsYWI9J01pY3JvLXN0ZXAnLCBjb2w9J3doaXRlJywNCiAgICAgICBtYWluPSdNZWFuIHJ1bm5pbmcgb3ZlciB0aW1lOg0KICAgICBubyBhdkF0dEhpZ2hlcicpCQ0KICBmb3IgKGkgaW4gMToyNSkgew0KICAgIGxpbmVzKHg9bWljcm9zLCB5PXByZWRpY3QobG9lc3Moc2Vxc1tpLF0gfiBtaWNyb3MpLCBtaWNyb3MpLCBjb2w9Y29sb3JzKClbaSoxMF0pDQogIH0NCiAgDQogICNzYXZlIHRoZSBwbG90IHRvIHRoZSBsaXN0DQogIHBsb3RMW1tjXV0gPC0gcmVjb3JkUGxvdCgpDQoNCn0NCg0KDQotLT4NCg0KDQo8YnI+DQoNCiMgUGxvdHMgey50YWJzZXQgLnRhYnNldC1mYWRlfQ0KDQojIyBjbHViIDENCg0KIVtdKGFibV9wbG90X2NsdWIxLnBuZykNCg0KIyMgY2x1YiAyDQoNCiFbXShhYm1fcGxvdF9jbHViMi5wbmcpDQoNCiMjIGNsdWIgMw0KDQohW10oYWJtX3Bsb3RfY2x1YjMucG5nKQ0KDQojIyBjbHViIDQNCg0KIVtdKGFibV9wbG90X2NsdWI0LnBuZykNCg0KIyMgY2x1YiA1DQoNCiFbXShhYm1fcGxvdF9jbHViNS5wbmcpDQoNCiMgey19DQo=


Copyright © 2021 Rob Franken