1 Getting started

To copy the code, click the button in the upper right corner of the code-chunks.

1.1 clean up

rm(list = ls())
gc()


1.2 custom functions

We defined a number custom functions, at Download custom_functions.R.

source("./custom_functions.R")


1.3 necessary packages

  • tidyverse: data wrangling
  • igraph: generate and visualize graphs
  • parallel: parallel computing to speed up simulation
  • foreach: looping in parallel
  • doParallel: parallel backend for foreach
  • ggplot2: data visualization
  • ggh4x: hacks for ggplot2
  • ggpubr: make visualizations publication-ready
packages = c("tidyverse", "igraph", "ggplot2", "parallel", "doParallel", "foreach", "ggh4x", "ggpubr",
    "plotly")
invisible(fpackage.check(packages))
rm(packages)

2 Simulation

Set up parameter space:

  1. Scale-free networks using the configuration model (e.g., Newman et al., 2001).
  2. Small-world networks using the Watts-Strogatz (1998) model.
# full factorial design
n <- 100
conf <- expand.grid(group_size = n, minority_prop = c(0.05, 0.1, 0.15), min_deg = c(2), max_deg = c(2 *
    (sqrt(n)), n - 1), dist = c("power-law", "log-normal"), alpha = c(2.1, 2.5, 3), r_kk = seq(-0.4,
    0.1, length.out = 6), rho_kx = seq(0, 0.5, length.out = 6), influence = c("strong", "weak"), choice_rule = c("deterministic",
    "probabilistic"))

# apply filters; we don't need to simulate the whole parameter space for weak influence...
conf <- conf %>%
    filter(!(influence == "weak" & minority_prop == 0.05)) %>%
    filter(!(influence == "weak" & minority_prop > 0.05 & (rho_kx < 0.2 | r_kk > -0.2)))

# parameter space 2: 'small-world' networks using WS-model
ws <- expand.grid(group_size = n, min_deg = c(3, 4), minority_prop = c(0.05, 0.1, 0.15), p = c(0.01,
    0.05, 0.1, 0.25, 1), r_kk = seq(-0.4, 0.1, length.out = 6), rho_kx = seq(0, 0.5, length.out = 6),
    influence = c("weak", "strong"), choice_rule = c("deterministic", "probabilistic"))

# apply filters; we don't need to simulate the whole parameter space for weak influence...
ws <- ws %>%
    filter(!(influence == "weak" & minority_prop == 0.05)) %>%
    filter(!(influence == "weak" & (rho_kx < 0.2 | r_kk > -0.2)))

# also, we don't manipulate degree-trait correlation and disassortativity when the network is
# nearly regular
ws <- ws %>%
    filter(!(p <= 0.05 & (rho_kx != 0 | r_kk != 0)))

fshowdf(fdesign(conf), caption = "Configuration model design space")
Configuration model design space
parameter n_levels levels
group_size 1 100
minority_prop 3 0.05, 0.1, 0.15
min_deg 1 2
max_deg 2 20, 99
dist 2 power-law, log-normal
alpha 3 2.1, 2.5, 3
r_kk 6 -0.4, -0.3, -0.2, -0.1, 0, 0.1
rho_kx 6 0, 0.1, 0.2, 0.3, 0.4, 0.5
influence 2 strong, weak
choice_rule 2 deterministic, probabilistic
fshowdf(fdesign(ws), caption = "Watts-Strogatz model design space")
Watts-Strogatz model design space
parameter n_levels levels
group_size 1 100
min_deg 2 3, 4
minority_prop 3 0.05, 0.1, 0.15
p 5 0.01, 0.05, 0.1, 0.25, 1
r_kk 6 -0.4, -0.3, -0.2, -0.1, 0, 0.1
rho_kx 6 0, 0.1, 0.2, 0.3, 0.4, 0.5
influence 2 weak, strong
choice_rule 2 deterministic, probabilistic


Simulate norm evolution across N seeds for all target networks:

2.1 Configuration model

# first a test:

# 1 create a network generate degree sequence
degseq <- fdegseq(n = 50, alpha = 2.5, k_min = 2, k_max = 25, dist = "power-law", seed = 123)

# construct network from degree sequence
network <- sample_degseq(degseq, method = "vl")

# assign roles to nodes
min_prop = 0.2
V(network)$role <- sample(c(rep("trendsetter", floor(50 * min_prop)), rep("conformist", 50 - floor(50 *
    min_prop))))

# simulate

fabm(network = network, params = list(s = 15, e = 10, w = 40, z = 50, lambda1 = 5, lambda2 = 1.8), max_rounds = 50,
    mi_threshold = 0.49, choice_rule = "deterministic")
# number of seeds
nIter = 3

# set up parallel backend to increase efficiency
ncores <- detectCores() - 1 
cl <- makeCluster(ncores)
registerDoParallel(cl)

# make folder to store simulations in
if (!dir.exists("./sims")) dir.create("./sims")

# parallel processing using foreach
system.time({
  foreach(i = 1:nrow(conf), .combine = 'c', .packages = c("igraph", "tidyverse")) %dopar% {
    
    cfg <- conf[i, ] # get configuration from full factorial
    results <- list()  # temporary storage for all iterations of this config
    
    for (iter in 1:nIter) {
      seed <- 123 + iter 
      set.seed(seed)
      
      results[[iter]] <- tryCatch({
        
        # generate degree sequence
        degseq <- fdegseq(n = cfg$group_size, 
                          alpha = cfg$alpha, 
                          k_min = cfg$min_deg, 
                          k_max = cfg$max_deg, 
                          dist = cfg$dist, 
                          seed = seed)
 
        # construct network
        network <- sample_degseq(degseq, method = "vl")
      
        # assign roles
        V(network)$role <- sample(
          c(
            rep("trendsetter", floor(cfg$group_size * cfg$minority_prop)),
            rep("conformist", cfg$group_size - floor(cfg$group_size * cfg$minority_prop))
          )
        )
        #fplot_graph(network)
      
        # rewire and swap
        rewired_network <- frewire_r(network, cfg$r_kk, verbose = FALSE, max_iter = 1e5)
        final_network <- fswap_rho(rewired_network, cfg$rho_kx, verbose = FALSE, max_iter = 1e4)
        actual_r <- assortativity_degree(rewired_network)
        final_rho <- fdegtraitcor(final_network)$cor
      
        # set initial action
        V(final_network)$action <- ifelse(V(final_network)$role == "trendsetter", 1, 0)
      
        # calculate global majority illusion
        # get threshold based on influence strength
        thresh <- ifelse(cfg$influence=="strong", .49, .50)
        mi <- fcalculate_majority_illusion(final_network, threshold = thresh)
      
        params <- if (cfg$influence == "strong") {
          list(s = 15, e = 10, w = 40, z = 50, lambda1 = 5, lambda2 = 1.8)
        } else {
          list(s = 15, e = 10, w = 40, z = 50, lambda1 = 3, lambda2 = 1.8)
        }
      
        # run simulation
        sim <- fabm(
          network = final_network,
          params = params,
          max_rounds = 50,
          mi_threshold = thresh,
          choice_rule = cfg$choice_rule
        )
        
        # package result
        list(
          config_id = i,
          dist = cfg$dist,
          alpha = cfg$alpha,
          target_r = cfg$r_kk,
          actual_r = actual_r,
          target_rho = cfg$rho_kx,
          actual_rho = final_rho,
          mi = mi,
          seed = seed,
          choice_rule = cfg$choice_rule,
          influence = cfg$influence,
          min_deg = cfg$min_deg,
          max_deg = cfg$max_deg,
          minority_prop = cfg$minority_prop,
          sim = list(
            outcomes = sim$outcomes,
            equilibrium = sim$equilibrium
          )
        )
        }, error = function(e) {
        message(sprintf("Iteration %d failed for config %d: %s", iter, i, e$message))
        NULL
      })
    }
    
    results <- Filter(Negate(is.null), results)
    
    # save all iterations for this configuration as a single file
    saveRDS(results, file = paste0("./sims/results_config_", i, ".rds"))
  }
})
#for 3168 confs and 50 iterations, about 18 hours.

# now load in the results
results_dir <- "./sims/"
files <- list.files(results_dir, pattern = "^results_config_\\d+\\.rds$", full.names = TRUE)

# to a long dataframe
all_results <- foreach(file = files, .combine = bind_rows, .packages = c("tibble", "dplyr")) %dopar% {
  config_results <- readRDS(file)
  summaries <- lapply(config_results, function(res) {
    eq <- res$sim$equilibrium
    seg <- res$sim$segregation
    tibble(
      config_id = res$config_id,
      alpha = res$alpha,
      dist = res$dist,
      target_r = res$target_r,
      actual_r = res$actual_r,
      target_rho = res$target_rho,
      actual_rho = res$actual_rho,
      mi = res$mi,
      influence = res$influence,
      choice_rule = res$choice_rule,
      minority_prop = res$minority_prop,
      min_deg = res$min_deg,
      max_deg = res$max_deg,
      seed = res$seed,
      reached_equilibrium = eq$reached,
      rounds_to_equilibrium = eq$round,
      final_adoption_rate = eq$prop_follow_trend,
      beh_assort = eq$segregation$r_behavior,
      L1CC_share = eq$segregation$L1CC_share
      
    )
  })
  
  bind_rows(summaries)
}

# stop cluster
stopCluster(cl)

# order by config_id
data <- all_results[order(all_results$config_id), ]

# and save the  dataframe
fsave(data, "sims_conf.Rda")


2.2 Watts-Strogatz model

#if (!dir.exists("./sims2")) dir.create("./sims2")

system.time({
  foreach(i = 1:10, .combine = 'c', .packages = c("igraph", "tidyverse")) %dopar% {
    
    cfg <- ws[i, ] # get configuration from full factorial
    results <- list()  # temporary storage for all iterations of this config
    
    for (iter in 1:nIter) {
      seed <- 123 + iter 
      set.seed(seed)
      
      results[[iter]] <- tryCatch({
        
        # construct network
        network <- sample_smallworld(dim = 1, size = cfg$group_size, nei = cfg$min_deg, p = cfg$p)
        
        # remove isolates that may arise due to rewiring
        isolates <- which(degree(network)==0)
        if (length(isolates) > 0) {
          network <- delete_vertices(network, isolates)
        }
        
        new_n <- vcount(network)
        
        # assign roles
        V(network)$role <- sample(
          c(
            rep("trendsetter", floor(new_n * cfg$minority_prop)),
            rep("conformist", new_n - floor(new_n * cfg$minority_prop))
          )
        )

        # rewire and swap
        rewired_network <- frewire_r(network, cfg$r_kk, verbose = TRUE, max_iter = 1e5)
        final_network <- fswap_rho(rewired_network, cfg$rho_kx, verbose = FALSE, max_iter = 1e4)
        actual_r <- assortativity_degree(rewired_network)
        final_rho <- fdegtraitcor(final_network)$cor
        
        # set initial action
        V(final_network)$action <- ifelse(V(final_network)$role == "trendsetter", 1, 0)
        
        #fplot_graph(final_network)
        
        # calculate global majority illusion
        # get threshold based on influence strength
        thresh <- ifelse(cfg$influence=="strong", .49, .50)
        mi <- fcalculate_majority_illusion(final_network, threshold = thresh)
        
        params <- if (cfg$influence == "strong") {
          list(s = 15, e = 10, w = 40, z = 50, lambda1 = 5, lambda2 = 1.8)
        } else {
          list(s = 15, e = 10, w = 40, z = 50, lambda1 = 3, lambda2 = 1.8)
        }
        
        # run simulation
        sim <- fabm(
          network = final_network,
          params = params,
          max_rounds = 50,
          mi_threshold = thresh,
          choice_rule = cfg$choice_rule
        )
        
        # package result
        list(
          config_id = i,
          min_deg = cfg$min_deg,
          p = cfg$p,
          target_r = cfg$r_kk,
          actual_r = actual_r,
          target_rho = cfg$rho_kx,
          actual_rho = final_rho,
          mi = mi,
          seed = seed,
          choice_rule = cfg$choice_rule,
          influence = cfg$influence,
          group_size = new_n,
          minority_prop = cfg$minority_prop,
          sim = list(
            outcomes = sim$outcomes,
            equilibrium = sim$equilibrium
          )
          
        )
      }, error = function(e) {
        message(sprintf("Iteration %d failed for config %d: %s", iter, i, e$message))
        NULL
      })
    }
    
    results <- Filter(Negate(is.null), results)
    
    # save all iterations for this configuration as a single file
    saveRDS(results, file = paste0("./sims2/results_config_", i, ".rds"))
  }
})

# now load in the results
results_dir <- "./sims2/"
files <- list.files(results_dir, pattern = "^results_config_\\d+\\.rds$", full.names = TRUE)

# to a long dataframe
all_results <- foreach(file = files, .combine = bind_rows, .packages = c("tibble", "dplyr")) %dopar% {
  config_results <- readRDS(file)
  summaries <- lapply(config_results, function(res) {
    eq <- res$sim$equilibrium
    
    tibble(
      config_id = res$config_id,
      size = res$group_size,
      min_deg = res$min_deg,
      p = res$p,
      target_r = res$target_r,
      actual_r = res$actual_r,
      target_rho = res$target_rho,
      actual_rho = res$actual_rho,
      mi = res$mi,
      minority_prop = res$minority_prop,
      influence = res$influence,
      choice_rule = res$choice_rule,
      seed = res$seed,
      reached_equilibrium = eq$reached,
      rounds_to_equilibrium = eq$round,
      final_adoption_rate = eq$prop_follow_trend,
      beh_assort = eq$segregation$r_behavior,
      L1CC_share = eq$segregation$L1CC_share
    )
  })
  
  bind_rows(summaries)
}

stopCluster(cl)

# order by config_id
data <- all_results[order(all_results$config_id), ]

#fix(data)
fsave(data, "sims_sw.Rda")

3 Results

We use a heatmap to visualize the probability with which each target network configuration drives negative equilibrium, across seeds.

3.1 Configuration model

# import data
today = "20250627"  # date on which the data was saved
data <- fload(paste0("./data/processed/", today, "sims_conf.Rda"))
# str(data)

# define equilibrium definition depends on deterministic/stochastic choice-rule:
data$unpop <- NA
data$unpop[data$choice_rule == "deterministic"] <- ifelse(data$final_adoption_rate[data$choice_rule ==
    "deterministic"] == 1, 1, 0)  # full adoption

# for stochastic choice-rule, use alternative definition: where proportion taking up B >= p +
# (1-p)(1-e)
data$unpop[data$choice_rule == "probabilistic"] <- ifelse(data$final_adoption_rate[data$choice_rule ==
    "probabilistic"] >= data$minority_prop[data$choice_rule == "probabilistic"] + (1 - data$minority_prop[data$choice_rule ==
    "probabilistic"]) * (1 - 0.1), 1, 0)

3.1.1 strong influence

3.1.1.1 truncated

# make plots: 1 determinstic (main)
fwrapper(data = data, choice_rule = "deterministic", influence = "strong", kmin = 2, kmax = 2 * sqrt(n),
    minority_props = c(0.05, 0.1, 0.15))

# ggsave('./figures/det_strong_trunc.png', height=4, width = 14)

# 2 stochastic
fwrapper(data = data, choice_rule = "probabilistic", influence = "strong", kmin = 2, kmax = 2 * sqrt(n),
    minority_props = c(0.05, 0.1, 0.15))

# ggsave('./figures/stoch_strong_trunc.png', height=4, width = 14)

3.1.1.2 untruncated

fwrapper(data = data, choice_rule = "deterministic", influence = "strong", kmin = 2, kmax = n - 1, minority_props = c(0.05,
    0.1, 0.15))

# ggsave('./figures/det_strong_untrunc.png', height=4, width = 14)

fwrapper(data = data, choice_rule = "probabilistic", influence = "strong", kmin = 2, kmax = n - 1, minority_props = c(0.05,
    0.1, 0.15))

# ggsave('./figures/stoch_strong_untrunc.png', height=4, width = 14)

3.1.2 weak influence

3.1.2.1 truncated

# make plots: 1 determinstic (main)
fwrapper(data = data, choice_rule = "deterministic", influence = "weak", kmin = 2, kmax = 2 * sqrt(n),
    minority_props = c(0.1, 0.15))

# 2 stochastic
fwrapper(data = data, choice_rule = "probabilistic", influence = "weak", kmin = 2, kmax = 2 * sqrt(n),
    minority_props = c(0.1, 0.15))

3.1.2.2 untruncated

fwrapper(data = data, choice_rule = "deterministic", influence = "weak", kmin = 2, kmax = n - 1, minority_props = c(0.1,
    0.15))

fwrapper(data = data, choice_rule = "probabilistic", influence = "strong", kmin = 2, kmax = n - 1, minority_props = c(0.1,
    0.15))


3.2 Watts-Strogatz model

# import data
today = "20250627"  # date on which the data was saved
data <- fload(paste0("./data/processed/", today, "sims_sw.Rda"))
# str(data)

# define equilibrium definition depends on deterministic/stochastic choice-rule:
data$unpop <- NA
data$unpop[data$choice_rule == "deterministic"] <- ifelse(data$final_adoption_rate[data$choice_rule ==
    "deterministic"] == 1, 1, 0)  # full adoption

# for stochastic choice-rule, use alternative definition: where proportion taking up B >= p +
# (1-p)(1-e)
data$unpop[data$choice_rule == "probabilistic"] <- ifelse(data$final_adoption_rate[data$choice_rule ==
    "probabilistic"] >= data$minority_prop[data$choice_rule == "probabilistic"] + (1 - data$minority_prop[data$choice_rule ==
    "probabilistic"]) * (1 - 0.1), 1, 0)

3.2.1 strong influence

# make plots: 1 determinstic (main)
fwrapper(data = data, fplot = fcreate_heatmap_sw, choice_rule = "deterministic", influence = "strong",
    minority_props = c(0.05, 0.1, 0.15))

# ggsave('./figures/det_strong_sw.png', height=4, width = 18)

# stochastic
fwrapper(data = data, fplot = fcreate_heatmap_sw, choice_rule = "probabilistic", influence = "strong",
    minority_props = c(0.05, 0.1, 0.15))

# =ggsave('./figures/stoch_strong_sw.png', height=4, width = 18)

3.2.2 weak influence

fwrapper(data = data, fplot = fcreate_heatmap_sw, choice_rule = "deterministic", influence = "weak",
    minority_props = c(0.1, 0.15))

# ggsave('./figures/det_weak_sw.png', height=4, width = 14)

fwrapper(data = data, fplot = fcreate_heatmap_sw, choice_rule = "probabilistic", influence = "weak",
    minority_props = c(0.1, 0.15))

# ggsave('./figures/stoch_weak_sw.png', height=4, width = 14)


explore clustering (auto-correlation) of norms in the network; that is, dyadic similarity (behavioral assortativity). but beyond that ‘pocketing’ (e.g., largest component size/share); or segregation at distance-1 and distance-k>1 or distance decay.

# all_results$beh_assort plot(all_results$beh_assort, all_results$p)

References

Newman, M. E. J., S. H. Strogatz, and D. J. Watts. 2001. “Random Graphs with Arbitrary Degree Distributions and Their Applications.” Physical Review E 64 (2): 026118. https://doi.org/10.1103/PhysRevE.64.026118.
Watts, Duncan J., and Steven H. Strogatz. 1998. “Collective Dynamics of ‘Small-World’ Networks.” Nature 393 (6684): 440–42. https://www.nature.com/articles/30918/figu-.
LS0tDQp0aXRsZTogIlRoZW9yZXRpY2FsIG1vZGVsIg0KYmlibGlvZ3JhcGh5OiByZWZlcmVuY2VzLmJpYg0KbGluay1jaXRhdGlvbnM6IHRydWUNCmRhdGU6ICJMYXN0IGNvbXBpbGVkIG9uIGByIGZvcm1hdChTeXMudGltZSgpLCAnJWQtJW0tJVknKWAiDQpvdXRwdXQ6IA0KICBodG1sX2RvY3VtZW50Og0KICAgIHNlbGZfY29udGFpbmVkOiB0cnVlDQogICAgY3NzOiB0d2Vha3MuY3NzDQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlDQogICAgdG9jX2RlcHRoOiA0DQogICAgY29kZV9mb2xkaW5nOiBzaG93DQogICAgY29kZV9kb3dubG9hZDogeWVzDQotLS0NCg0KYGBge3IsIGdsb2JhbHNldHRpbmdzLCBlY2hvPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCByZXN1bHRzPSdoaWRlJywgbWVzc2FnZT1GQUxTRX0NCmxpYnJhcnkoa25pdHIpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkNCm9wdHNfY2h1bmskc2V0KHRpZHkub3B0cz1saXN0KHdpZHRoLmN1dG9mZj0xMDApLHRpZHk9VFJVRSwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UsY29tbWVudCA9ICIjPiIsIGNhY2hlPVRSVUUsIGNsYXNzLnNvdXJjZT1jKCJ0ZXN0IiksIGNsYXNzLm91dHB1dD1jKCJ0ZXN0MyIpKQ0Kb3B0aW9ucyh3aWR0aCA9IDEwMCkNCnJnbDo6c2V0dXBLbml0cigpDQoNCmNvbG9yaXplIDwtIGZ1bmN0aW9uKHgsIGNvbG9yKSB7c3ByaW50ZigiPHNwYW4gc3R5bGU9J2NvbG9yOiAlczsnPiVzPC9zcGFuPiIsIGNvbG9yLCB4KSB9DQpgYGANCg0KYGBge3Iga2xpcHB5LCBlY2hvPUZBTFNFLCBpbmNsdWRlPVRSVUV9DQprbGlwcHk6OmtsaXBweShwb3NpdGlvbiA9IGMoJ3RvcCcsICdyaWdodCcpKQ0KI2tsaXBweTo6a2xpcHB5KGNvbG9yID0gJ2RhcmtyZWQnKQ0KI2tsaXBweTo6a2xpcHB5KHRvb2x0aXBfbWVzc2FnZSA9ICdDbGljayB0byBjb3B5JywgdG9vbHRpcF9zdWNjZXNzID0gJ0RvbmUnKQ0KYGBgDQoNCi0tLQ0KDQojIEdldHRpbmcgc3RhcnRlZA0KDQpUbyBjb3B5IHRoZSBjb2RlLCBjbGljayB0aGUgYnV0dG9uIGluIHRoZSB1cHBlciByaWdodCBjb3JuZXIgb2YgdGhlIGNvZGUtY2h1bmtzLg0KDQojIyBjbGVhbiB1cA0KDQpgYGB7ciwgY2xlYW5fdXAsIHJlc3VsdHM9J2hpZGUnfQ0Kcm0obGlzdD1scygpKQ0KZ2MoKQ0KYGBgDQoNCjxicj4NCg0KIyMgY3VzdG9tIGZ1bmN0aW9ucw0KDQpXZSBkZWZpbmVkIGEgbnVtYmVyIGN1c3RvbSBmdW5jdGlvbnMsIGF0IGByIHhmdW46OmVtYmVkX2ZpbGUoIi4vY3VzdG9tX2Z1bmN0aW9ucy5SIilgLg0KDQpgYGB7ciwgY3VzdG9tX2Z1bmN0aW9uc30NCnNvdXJjZSgiLi9jdXN0b21fZnVuY3Rpb25zLlIiKQ0KYGBgDQoNCjxicj4NCg0KIyMgbmVjZXNzYXJ5IHBhY2thZ2VzDQoNCi0gYHRpZHl2ZXJzZWA6IGRhdGEgd3JhbmdsaW5nDQotIGBpZ3JhcGhgOiBnZW5lcmF0ZSBhbmQgdmlzdWFsaXplIGdyYXBocw0KLSBgcGFyYWxsZWxgOiBwYXJhbGxlbCBjb21wdXRpbmcgdG8gc3BlZWQgdXAgc2ltdWxhdGlvbg0KLSBgZm9yZWFjaGA6IGxvb3BpbmcgaW4gcGFyYWxsZWwNCi0gYGRvUGFyYWxsZWxgOiBwYXJhbGxlbCBiYWNrZW5kIGZvciBgZm9yZWFjaGANCi0gYGdncGxvdDJgOiBkYXRhIHZpc3VhbGl6YXRpb24NCi0gYGdnaDR4YDogaGFja3MgZm9yIGBnZ3Bsb3QyYA0KLSBgZ2dwdWJyYDogbWFrZSB2aXN1YWxpemF0aW9ucyBwdWJsaWNhdGlvbi1yZWFkeQ0KDQpgYGB7ciwgcGFja2FnZXN9DQpwYWNrYWdlcyA9IGMoInRpZHl2ZXJzZSIsICJpZ3JhcGgiLCAiZ2dwbG90MiIsICJwYXJhbGxlbCIsICJkb1BhcmFsbGVsIiwgImZvcmVhY2giLCAiZ2doNHgiLCAiZ2dwdWJyIiwgInBsb3RseSIpDQppbnZpc2libGUoZnBhY2thZ2UuY2hlY2socGFja2FnZXMpKQ0Kcm0ocGFja2FnZXMpDQpgYGANCg0KLS0tDQoNCiMgU2ltdWxhdGlvbg0KDQpTZXQgdXAgcGFyYW1ldGVyIHNwYWNlOg0KDQoxLiBTY2FsZS1mcmVlIG5ldHdvcmtzIHVzaW5nIHRoZSBjb25maWd1cmF0aW9uIG1vZGVsIFtlLmcuLCBOZXdtYW4gZXQgYWwuLCAtQG5ld21hbl9yYW5kb21fMjAwMV0uDQoyLiBTbWFsbC13b3JsZCBuZXR3b3JrcyB1c2luZyB0aGUgV2F0dHMtU3Ryb2dhdHogWy1Ad2F0dHNfY29sbGVjdGl2ZV8xOTk4XSBtb2RlbC4NCg0KYGBge3IsIGNsYXNzLnNvdXJjZT0nZm9sZC1oaWRlJ30NCiMgZnVsbCBmYWN0b3JpYWwgZGVzaWduDQpuIDwtIDEwMCANCmNvbmYgPC0gZXhwYW5kLmdyaWQoDQogIGdyb3VwX3NpemUgPSBuLA0KICBtaW5vcml0eV9wcm9wID0gYygwLjA1LCAwLjEsIDAuMTUpLA0KICBtaW5fZGVnID0gYygyKSwNCiAgbWF4X2RlZyA9IGMoMiooc3FydChuKSksIG4tMSksDQogIGRpc3QgPSBjKCJwb3dlci1sYXciLCAibG9nLW5vcm1hbCIpLA0KICBhbHBoYSA9IGMoMi4xLCAyLjUsIDMpLA0KICByX2trID0gc2VxKC0wLjQsIDAuMSwgbGVuZ3RoLm91dCA9IDYpLCANCiAgcmhvX2t4ID0gc2VxKDAsIDAuNSwgbGVuZ3RoLm91dCA9IDYpLCANCiAgaW5mbHVlbmNlID0gYygic3Ryb25nIiwgIndlYWsiKSwNCiAgY2hvaWNlX3J1bGUgPSBjKCJkZXRlcm1pbmlzdGljIiwgInByb2JhYmlsaXN0aWMiKQ0KKQ0KDQojYXBwbHkgZmlsdGVyczsgd2UgZG9uJ3QgbmVlZCB0byBzaW11bGF0ZSB0aGUgd2hvbGUgcGFyYW1ldGVyIHNwYWNlIGZvciB3ZWFrIGluZmx1ZW5jZS4uLg0KY29uZiA8LSBjb25mICU+JQ0KICBmaWx0ZXIoIShpbmZsdWVuY2UgPT0gIndlYWsiICYgbWlub3JpdHlfcHJvcCA9PSAwLjA1KSkgJT4lDQogIGZpbHRlcighKGluZmx1ZW5jZSA9PSAid2VhayIgJiBtaW5vcml0eV9wcm9wID4gMC4wNSAmIChyaG9fa3ggPCAwLjIgfCByX2trID4gLTAuMikpKQ0KDQojIHBhcmFtZXRlciBzcGFjZSAyOiAnc21hbGwtd29ybGQnIG5ldHdvcmtzIHVzaW5nIFdTLW1vZGVsDQp3cyA8LSBleHBhbmQuZ3JpZCgNCiAgZ3JvdXBfc2l6ZSA9IG4sDQogIG1pbl9kZWcgPSBjKDMsIDQpLA0KICBtaW5vcml0eV9wcm9wID0gYygwLjA1LCAwLjEwLCAwLjE1KSwNCiAgcCA9IGMoMC4wMSwgMC4wNSwgMC4xMCwgMC4yNSwgIDEpLA0KICByX2trID0gc2VxKC0wLjQsIDAuMSwgbGVuZ3RoLm91dCA9IDYpLA0KICByaG9fa3ggPSBzZXEoMCwgMC41LCBsZW5ndGgub3V0ID0gNiksDQogIGluZmx1ZW5jZSA9IGMoIndlYWsiLCAic3Ryb25nIiksDQogIGNob2ljZV9ydWxlID0gYygiZGV0ZXJtaW5pc3RpYyIsICJwcm9iYWJpbGlzdGljIikNCikNCg0KI2FwcGx5IGZpbHRlcnM7IHdlIGRvbid0IG5lZWQgdG8gc2ltdWxhdGUgdGhlIHdob2xlIHBhcmFtZXRlciBzcGFjZSBmb3Igd2VhayBpbmZsdWVuY2UuLi4NCndzIDwtIHdzICU+JQ0KICBmaWx0ZXIoIShpbmZsdWVuY2UgPT0gIndlYWsiICYgbWlub3JpdHlfcHJvcCA9PSAwLjA1KSkgJT4lDQogIGZpbHRlcighKGluZmx1ZW5jZSA9PSAid2VhayIgJiAocmhvX2t4IDwgMC4yIHwgcl9rayA+IC0wLjIpKSkNCg0KI2Fsc28sIHdlIGRvbid0IG1hbmlwdWxhdGUgZGVncmVlLXRyYWl0IGNvcnJlbGF0aW9uIGFuZCBkaXNhc3NvcnRhdGl2aXR5IHdoZW4gdGhlIG5ldHdvcmsgaXMgbmVhcmx5IHJlZ3VsYXINCndzIDwtIHdzICU+JQ0KICBmaWx0ZXIoIShwIDw9IDAuMDUgJiAocmhvX2t4ICE9IDAgfCByX2trICE9IDApKSkNCg0KZnNob3dkZihmZGVzaWduKGNvbmYpLCBjYXB0aW9uID0gIkNvbmZpZ3VyYXRpb24gbW9kZWwgZGVzaWduIHNwYWNlIikNCmZzaG93ZGYoZmRlc2lnbih3cyksIGNhcHRpb24gPSAiV2F0dHMtU3Ryb2dhdHogbW9kZWwgZGVzaWduIHNwYWNlIikNCmBgYA0KDQo8YnI+DQoNClNpbXVsYXRlIG5vcm0gZXZvbHV0aW9uIGFjcm9zcyBOIHNlZWRzIGZvciBhbGwgdGFyZ2V0IG5ldHdvcmtzOg0KDQojIyBDb25maWd1cmF0aW9uIG1vZGVsDQoNCmBgYHtyLCBldmFsID0gRkFMU0V9DQojZmlyc3QgYSB0ZXN0Og0KDQojMSBjcmVhdGUgYSBuZXR3b3JrDQojIGdlbmVyYXRlIGRlZ3JlZSBzZXF1ZW5jZQ0KZGVnc2VxIDwtIGZkZWdzZXEobiA9IDUwLCANCiAgICAgICAgICAgICAgICAgIGFscGhhID0gMi41LCANCiAgICAgICAgICAgICAgICAgIGtfbWluID0gMiwgDQogICAgICAgICAgICAgICAgICBrX21heCA9IDI1LCANCiAgICAgICAgICAgICAgICAgIGRpc3QgPSAicG93ZXItbGF3IiwgDQogICAgICAgICAgICAgICAgICBzZWVkID0gMTIzKQ0KDQojIGNvbnN0cnVjdCBuZXR3b3JrIGZyb20gZGVncmVlIHNlcXVlbmNlDQpuZXR3b3JrIDwtIHNhbXBsZV9kZWdzZXEoZGVnc2VxLCBtZXRob2QgPSAidmwiKQ0KDQojIGFzc2lnbiByb2xlcyB0byBub2Rlcw0KbWluX3Byb3AgPSAuMg0KVihuZXR3b3JrKSRyb2xlIDwtIHNhbXBsZSgNCiAgYygNCiAgICByZXAoInRyZW5kc2V0dGVyIiwgZmxvb3IoNTAgKiBtaW5fcHJvcCkpLA0KICAgIHJlcCgiY29uZm9ybWlzdCIsIDUwIC0gZmxvb3IoNTAgKiBtaW5fcHJvcCkpDQogICAgKQ0KICApDQoNCiMgc2ltdWxhdGUNCg0KZmFibSgNCiAgbmV0d29yayA9IG5ldHdvcmssDQogIHBhcmFtcyA9IGxpc3Qocz0xNSwgZT0xMCwgdz00MCwgej01MCwgbGFtYmRhMT01LCBsYW1iZGEyPTEuOCksDQogIG1heF9yb3VuZHMgPSA1MCwNCiAgbWlfdGhyZXNob2xkID0gLjQ5LA0KICBjaG9pY2VfcnVsZSA9ICJkZXRlcm1pbmlzdGljIg0KICApDQoNCiAgICAgIA0KICAgDQpgYGANCg0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCiMgbnVtYmVyIG9mIHNlZWRzDQpuSXRlciA9IDMNCg0KIyBzZXQgdXAgcGFyYWxsZWwgYmFja2VuZCB0byBpbmNyZWFzZSBlZmZpY2llbmN5DQpuY29yZXMgPC0gZGV0ZWN0Q29yZXMoKSAtIDEgDQpjbCA8LSBtYWtlQ2x1c3RlcihuY29yZXMpDQpyZWdpc3RlckRvUGFyYWxsZWwoY2wpDQoNCiMgbWFrZSBmb2xkZXIgdG8gc3RvcmUgc2ltdWxhdGlvbnMgaW4NCmlmICghZGlyLmV4aXN0cygiLi9zaW1zIikpIGRpci5jcmVhdGUoIi4vc2ltcyIpDQoNCiMgcGFyYWxsZWwgcHJvY2Vzc2luZyB1c2luZyBmb3JlYWNoDQpzeXN0ZW0udGltZSh7DQogIGZvcmVhY2goaSA9IDE6bnJvdyhjb25mKSwgLmNvbWJpbmUgPSAnYycsIC5wYWNrYWdlcyA9IGMoImlncmFwaCIsICJ0aWR5dmVyc2UiKSkgJWRvcGFyJSB7DQogICAgDQogICAgY2ZnIDwtIGNvbmZbaSwgXSAjIGdldCBjb25maWd1cmF0aW9uIGZyb20gZnVsbCBmYWN0b3JpYWwNCiAgICByZXN1bHRzIDwtIGxpc3QoKSAgIyB0ZW1wb3Jhcnkgc3RvcmFnZSBmb3IgYWxsIGl0ZXJhdGlvbnMgb2YgdGhpcyBjb25maWcNCiAgICANCiAgICBmb3IgKGl0ZXIgaW4gMTpuSXRlcikgew0KICAgICAgc2VlZCA8LSAxMjMgKyBpdGVyIA0KICAgICAgc2V0LnNlZWQoc2VlZCkNCiAgICAgIA0KICAgICAgcmVzdWx0c1tbaXRlcl1dIDwtIHRyeUNhdGNoKHsNCiAgICAgICAgDQogICAgICAgICMgZ2VuZXJhdGUgZGVncmVlIHNlcXVlbmNlDQogICAgICAgIGRlZ3NlcSA8LSBmZGVnc2VxKG4gPSBjZmckZ3JvdXBfc2l6ZSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gY2ZnJGFscGhhLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAga19taW4gPSBjZmckbWluX2RlZywgDQogICAgICAgICAgICAgICAgICAgICAgICAgIGtfbWF4ID0gY2ZnJG1heF9kZWcsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICBkaXN0ID0gY2ZnJGRpc3QsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICBzZWVkID0gc2VlZCkNCiANCiAgICAgICAgIyBjb25zdHJ1Y3QgbmV0d29yaw0KICAgICAgICBuZXR3b3JrIDwtIHNhbXBsZV9kZWdzZXEoZGVnc2VxLCBtZXRob2QgPSAidmwiKQ0KICAgICAgDQogICAgICAgICMgYXNzaWduIHJvbGVzDQogICAgICAgIFYobmV0d29yaykkcm9sZSA8LSBzYW1wbGUoDQogICAgICAgICAgYygNCiAgICAgICAgICAgIHJlcCgidHJlbmRzZXR0ZXIiLCBmbG9vcihjZmckZ3JvdXBfc2l6ZSAqIGNmZyRtaW5vcml0eV9wcm9wKSksDQogICAgICAgICAgICByZXAoImNvbmZvcm1pc3QiLCBjZmckZ3JvdXBfc2l6ZSAtIGZsb29yKGNmZyRncm91cF9zaXplICogY2ZnJG1pbm9yaXR5X3Byb3ApKQ0KICAgICAgICAgICkNCiAgICAgICAgKQ0KICAgICAgICAjZnBsb3RfZ3JhcGgobmV0d29yaykNCiAgICAgIA0KICAgICAgICAjIHJld2lyZSBhbmQgc3dhcA0KICAgICAgICByZXdpcmVkX25ldHdvcmsgPC0gZnJld2lyZV9yKG5ldHdvcmssIGNmZyRyX2trLCB2ZXJib3NlID0gRkFMU0UsIG1heF9pdGVyID0gMWU1KQ0KICAgICAgICBmaW5hbF9uZXR3b3JrIDwtIGZzd2FwX3JobyhyZXdpcmVkX25ldHdvcmssIGNmZyRyaG9fa3gsIHZlcmJvc2UgPSBGQUxTRSwgbWF4X2l0ZXIgPSAxZTQpDQogICAgICAgIGFjdHVhbF9yIDwtIGFzc29ydGF0aXZpdHlfZGVncmVlKHJld2lyZWRfbmV0d29yaykNCiAgICAgICAgZmluYWxfcmhvIDwtIGZkZWd0cmFpdGNvcihmaW5hbF9uZXR3b3JrKSRjb3INCiAgICAgIA0KICAgICAgICAjIHNldCBpbml0aWFsIGFjdGlvbg0KICAgICAgICBWKGZpbmFsX25ldHdvcmspJGFjdGlvbiA8LSBpZmVsc2UoVihmaW5hbF9uZXR3b3JrKSRyb2xlID09ICJ0cmVuZHNldHRlciIsIDEsIDApDQogICAgICANCiAgICAgICAgIyBjYWxjdWxhdGUgZ2xvYmFsIG1ham9yaXR5IGlsbHVzaW9uDQogICAgICAgICMgZ2V0IHRocmVzaG9sZCBiYXNlZCBvbiBpbmZsdWVuY2Ugc3RyZW5ndGgNCiAgICAgICAgdGhyZXNoIDwtIGlmZWxzZShjZmckaW5mbHVlbmNlPT0ic3Ryb25nIiwgLjQ5LCAuNTApDQogICAgICAgIG1pIDwtIGZjYWxjdWxhdGVfbWFqb3JpdHlfaWxsdXNpb24oZmluYWxfbmV0d29yaywgdGhyZXNob2xkID0gdGhyZXNoKQ0KICAgICAgDQogICAgICAgIHBhcmFtcyA8LSBpZiAoY2ZnJGluZmx1ZW5jZSA9PSAic3Ryb25nIikgew0KICAgICAgICAgIGxpc3QocyA9IDE1LCBlID0gMTAsIHcgPSA0MCwgeiA9IDUwLCBsYW1iZGExID0gNSwgbGFtYmRhMiA9IDEuOCkNCiAgICAgICAgfSBlbHNlIHsNCiAgICAgICAgICBsaXN0KHMgPSAxNSwgZSA9IDEwLCB3ID0gNDAsIHogPSA1MCwgbGFtYmRhMSA9IDMsIGxhbWJkYTIgPSAxLjgpDQogICAgICAgIH0NCiAgICAgIA0KICAgICAgICAjIHJ1biBzaW11bGF0aW9uDQogICAgICAgIHNpbSA8LSBmYWJtKA0KICAgICAgICAgIG5ldHdvcmsgPSBmaW5hbF9uZXR3b3JrLA0KICAgICAgICAgIHBhcmFtcyA9IHBhcmFtcywNCiAgICAgICAgICBtYXhfcm91bmRzID0gNTAsDQogICAgICAgICAgbWlfdGhyZXNob2xkID0gdGhyZXNoLA0KICAgICAgICAgIGNob2ljZV9ydWxlID0gY2ZnJGNob2ljZV9ydWxlDQogICAgICAgICkNCiAgICAgICAgDQogICAgICAgICMgcGFja2FnZSByZXN1bHQNCiAgICAgICAgbGlzdCgNCiAgICAgICAgICBjb25maWdfaWQgPSBpLA0KICAgICAgICAgIGRpc3QgPSBjZmckZGlzdCwNCiAgICAgICAgICBhbHBoYSA9IGNmZyRhbHBoYSwNCiAgICAgICAgICB0YXJnZXRfciA9IGNmZyRyX2trLA0KICAgICAgICAgIGFjdHVhbF9yID0gYWN0dWFsX3IsDQogICAgICAgICAgdGFyZ2V0X3JobyA9IGNmZyRyaG9fa3gsDQogICAgICAgICAgYWN0dWFsX3JobyA9IGZpbmFsX3JobywNCiAgICAgICAgICBtaSA9IG1pLA0KICAgICAgICAgIHNlZWQgPSBzZWVkLA0KICAgICAgICAgIGNob2ljZV9ydWxlID0gY2ZnJGNob2ljZV9ydWxlLA0KICAgICAgICAgIGluZmx1ZW5jZSA9IGNmZyRpbmZsdWVuY2UsDQogICAgICAgICAgbWluX2RlZyA9IGNmZyRtaW5fZGVnLA0KICAgICAgICAgIG1heF9kZWcgPSBjZmckbWF4X2RlZywNCiAgICAgICAgICBtaW5vcml0eV9wcm9wID0gY2ZnJG1pbm9yaXR5X3Byb3AsDQogICAgICAgICAgc2ltID0gbGlzdCgNCiAgICAgICAgICAgIG91dGNvbWVzID0gc2ltJG91dGNvbWVzLA0KICAgICAgICAgICAgZXF1aWxpYnJpdW0gPSBzaW0kZXF1aWxpYnJpdW0NCiAgICAgICAgICApDQogICAgICAgICkNCiAgICAgICAgfSwgZXJyb3IgPSBmdW5jdGlvbihlKSB7DQogICAgICAgIG1lc3NhZ2Uoc3ByaW50ZigiSXRlcmF0aW9uICVkIGZhaWxlZCBmb3IgY29uZmlnICVkOiAlcyIsIGl0ZXIsIGksIGUkbWVzc2FnZSkpDQogICAgICAgIE5VTEwNCiAgICAgIH0pDQogICAgfQ0KICAgIA0KICAgIHJlc3VsdHMgPC0gRmlsdGVyKE5lZ2F0ZShpcy5udWxsKSwgcmVzdWx0cykNCiAgICANCiAgICAjIHNhdmUgYWxsIGl0ZXJhdGlvbnMgZm9yIHRoaXMgY29uZmlndXJhdGlvbiBhcyBhIHNpbmdsZSBmaWxlDQogICAgc2F2ZVJEUyhyZXN1bHRzLCBmaWxlID0gcGFzdGUwKCIuL3NpbXMvcmVzdWx0c19jb25maWdfIiwgaSwgIi5yZHMiKSkNCiAgfQ0KfSkNCiNmb3IgMzE2OCBjb25mcyBhbmQgNTAgaXRlcmF0aW9ucywgYWJvdXQgMTggaG91cnMuDQoNCiMgbm93IGxvYWQgaW4gdGhlIHJlc3VsdHMNCnJlc3VsdHNfZGlyIDwtICIuL3NpbXMvIg0KZmlsZXMgPC0gbGlzdC5maWxlcyhyZXN1bHRzX2RpciwgcGF0dGVybiA9ICJecmVzdWx0c19jb25maWdfXFxkK1xcLnJkcyQiLCBmdWxsLm5hbWVzID0gVFJVRSkNCg0KIyB0byBhIGxvbmcgZGF0YWZyYW1lDQphbGxfcmVzdWx0cyA8LSBmb3JlYWNoKGZpbGUgPSBmaWxlcywgLmNvbWJpbmUgPSBiaW5kX3Jvd3MsIC5wYWNrYWdlcyA9IGMoInRpYmJsZSIsICJkcGx5ciIpKSAlZG9wYXIlIHsNCiAgY29uZmlnX3Jlc3VsdHMgPC0gcmVhZFJEUyhmaWxlKQ0KICBzdW1tYXJpZXMgPC0gbGFwcGx5KGNvbmZpZ19yZXN1bHRzLCBmdW5jdGlvbihyZXMpIHsNCiAgICBlcSA8LSByZXMkc2ltJGVxdWlsaWJyaXVtDQogICAgc2VnIDwtIHJlcyRzaW0kc2VncmVnYXRpb24NCiAgICB0aWJibGUoDQogICAgICBjb25maWdfaWQgPSByZXMkY29uZmlnX2lkLA0KICAgICAgYWxwaGEgPSByZXMkYWxwaGEsDQogICAgICBkaXN0ID0gcmVzJGRpc3QsDQogICAgICB0YXJnZXRfciA9IHJlcyR0YXJnZXRfciwNCiAgICAgIGFjdHVhbF9yID0gcmVzJGFjdHVhbF9yLA0KICAgICAgdGFyZ2V0X3JobyA9IHJlcyR0YXJnZXRfcmhvLA0KICAgICAgYWN0dWFsX3JobyA9IHJlcyRhY3R1YWxfcmhvLA0KICAgICAgbWkgPSByZXMkbWksDQogICAgICBpbmZsdWVuY2UgPSByZXMkaW5mbHVlbmNlLA0KICAgICAgY2hvaWNlX3J1bGUgPSByZXMkY2hvaWNlX3J1bGUsDQogICAgICBtaW5vcml0eV9wcm9wID0gcmVzJG1pbm9yaXR5X3Byb3AsDQogICAgICBtaW5fZGVnID0gcmVzJG1pbl9kZWcsDQogICAgICBtYXhfZGVnID0gcmVzJG1heF9kZWcsDQogICAgICBzZWVkID0gcmVzJHNlZWQsDQogICAgICByZWFjaGVkX2VxdWlsaWJyaXVtID0gZXEkcmVhY2hlZCwNCiAgICAgIHJvdW5kc190b19lcXVpbGlicml1bSA9IGVxJHJvdW5kLA0KICAgICAgZmluYWxfYWRvcHRpb25fcmF0ZSA9IGVxJHByb3BfZm9sbG93X3RyZW5kLA0KICAgICAgYmVoX2Fzc29ydCA9IGVxJHNlZ3JlZ2F0aW9uJHJfYmVoYXZpb3IsDQogICAgICBMMUNDX3NoYXJlID0gZXEkc2VncmVnYXRpb24kTDFDQ19zaGFyZQ0KICAgICAgDQogICAgKQ0KICB9KQ0KICANCiAgYmluZF9yb3dzKHN1bW1hcmllcykNCn0NCg0KIyBzdG9wIGNsdXN0ZXINCnN0b3BDbHVzdGVyKGNsKQ0KDQojIG9yZGVyIGJ5IGNvbmZpZ19pZA0KZGF0YSA8LSBhbGxfcmVzdWx0c1tvcmRlcihhbGxfcmVzdWx0cyRjb25maWdfaWQpLCBdDQoNCiMgYW5kIHNhdmUgdGhlICBkYXRhZnJhbWUNCmZzYXZlKGRhdGEsICJzaW1zX2NvbmYuUmRhIikNCmBgYA0KDQo8YnI+DQoNCiMjIFdhdHRzLVN0cm9nYXR6IG1vZGVsDQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KI2lmICghZGlyLmV4aXN0cygiLi9zaW1zMiIpKSBkaXIuY3JlYXRlKCIuL3NpbXMyIikNCg0Kc3lzdGVtLnRpbWUoew0KICBmb3JlYWNoKGkgPSAxOjEwLCAuY29tYmluZSA9ICdjJywgLnBhY2thZ2VzID0gYygiaWdyYXBoIiwgInRpZHl2ZXJzZSIpKSAlZG9wYXIlIHsNCiAgICANCiAgICBjZmcgPC0gd3NbaSwgXSAjIGdldCBjb25maWd1cmF0aW9uIGZyb20gZnVsbCBmYWN0b3JpYWwNCiAgICByZXN1bHRzIDwtIGxpc3QoKSAgIyB0ZW1wb3Jhcnkgc3RvcmFnZSBmb3IgYWxsIGl0ZXJhdGlvbnMgb2YgdGhpcyBjb25maWcNCiAgICANCiAgICBmb3IgKGl0ZXIgaW4gMTpuSXRlcikgew0KICAgICAgc2VlZCA8LSAxMjMgKyBpdGVyIA0KICAgICAgc2V0LnNlZWQoc2VlZCkNCiAgICAgIA0KICAgICAgcmVzdWx0c1tbaXRlcl1dIDwtIHRyeUNhdGNoKHsNCiAgICAgICAgDQogICAgICAgICMgY29uc3RydWN0IG5ldHdvcmsNCiAgICAgICAgbmV0d29yayA8LSBzYW1wbGVfc21hbGx3b3JsZChkaW0gPSAxLCBzaXplID0gY2ZnJGdyb3VwX3NpemUsIG5laSA9IGNmZyRtaW5fZGVnLCBwID0gY2ZnJHApDQogICAgICAgIA0KICAgICAgICAjIHJlbW92ZSBpc29sYXRlcyB0aGF0IG1heSBhcmlzZSBkdWUgdG8gcmV3aXJpbmcNCiAgICAgICAgaXNvbGF0ZXMgPC0gd2hpY2goZGVncmVlKG5ldHdvcmspPT0wKQ0KICAgICAgICBpZiAobGVuZ3RoKGlzb2xhdGVzKSA+IDApIHsNCiAgICAgICAgICBuZXR3b3JrIDwtIGRlbGV0ZV92ZXJ0aWNlcyhuZXR3b3JrLCBpc29sYXRlcykNCiAgICAgICAgfQ0KICAgICAgICANCiAgICAgICAgbmV3X24gPC0gdmNvdW50KG5ldHdvcmspDQogICAgICAgIA0KICAgICAgICAjIGFzc2lnbiByb2xlcw0KICAgICAgICBWKG5ldHdvcmspJHJvbGUgPC0gc2FtcGxlKA0KICAgICAgICAgIGMoDQogICAgICAgICAgICByZXAoInRyZW5kc2V0dGVyIiwgZmxvb3IobmV3X24gKiBjZmckbWlub3JpdHlfcHJvcCkpLA0KICAgICAgICAgICAgcmVwKCJjb25mb3JtaXN0IiwgbmV3X24gLSBmbG9vcihuZXdfbiAqIGNmZyRtaW5vcml0eV9wcm9wKSkNCiAgICAgICAgICApDQogICAgICAgICkNCg0KICAgICAgICAjIHJld2lyZSBhbmQgc3dhcA0KICAgICAgICByZXdpcmVkX25ldHdvcmsgPC0gZnJld2lyZV9yKG5ldHdvcmssIGNmZyRyX2trLCB2ZXJib3NlID0gVFJVRSwgbWF4X2l0ZXIgPSAxZTUpDQogICAgICAgIGZpbmFsX25ldHdvcmsgPC0gZnN3YXBfcmhvKHJld2lyZWRfbmV0d29yaywgY2ZnJHJob19reCwgdmVyYm9zZSA9IEZBTFNFLCBtYXhfaXRlciA9IDFlNCkNCiAgICAgICAgYWN0dWFsX3IgPC0gYXNzb3J0YXRpdml0eV9kZWdyZWUocmV3aXJlZF9uZXR3b3JrKQ0KICAgICAgICBmaW5hbF9yaG8gPC0gZmRlZ3RyYWl0Y29yKGZpbmFsX25ldHdvcmspJGNvcg0KICAgICAgICANCiAgICAgICAgIyBzZXQgaW5pdGlhbCBhY3Rpb24NCiAgICAgICAgVihmaW5hbF9uZXR3b3JrKSRhY3Rpb24gPC0gaWZlbHNlKFYoZmluYWxfbmV0d29yaykkcm9sZSA9PSAidHJlbmRzZXR0ZXIiLCAxLCAwKQ0KICAgICAgICANCiAgICAgICAgI2ZwbG90X2dyYXBoKGZpbmFsX25ldHdvcmspDQogICAgICAgIA0KICAgICAgICAjIGNhbGN1bGF0ZSBnbG9iYWwgbWFqb3JpdHkgaWxsdXNpb24NCiAgICAgICAgIyBnZXQgdGhyZXNob2xkIGJhc2VkIG9uIGluZmx1ZW5jZSBzdHJlbmd0aA0KICAgICAgICB0aHJlc2ggPC0gaWZlbHNlKGNmZyRpbmZsdWVuY2U9PSJzdHJvbmciLCAuNDksIC41MCkNCiAgICAgICAgbWkgPC0gZmNhbGN1bGF0ZV9tYWpvcml0eV9pbGx1c2lvbihmaW5hbF9uZXR3b3JrLCB0aHJlc2hvbGQgPSB0aHJlc2gpDQogICAgICAgIA0KICAgICAgICBwYXJhbXMgPC0gaWYgKGNmZyRpbmZsdWVuY2UgPT0gInN0cm9uZyIpIHsNCiAgICAgICAgICBsaXN0KHMgPSAxNSwgZSA9IDEwLCB3ID0gNDAsIHogPSA1MCwgbGFtYmRhMSA9IDUsIGxhbWJkYTIgPSAxLjgpDQogICAgICAgIH0gZWxzZSB7DQogICAgICAgICAgbGlzdChzID0gMTUsIGUgPSAxMCwgdyA9IDQwLCB6ID0gNTAsIGxhbWJkYTEgPSAzLCBsYW1iZGEyID0gMS44KQ0KICAgICAgICB9DQogICAgICAgIA0KICAgICAgICAjIHJ1biBzaW11bGF0aW9uDQogICAgICAgIHNpbSA8LSBmYWJtKA0KICAgICAgICAgIG5ldHdvcmsgPSBmaW5hbF9uZXR3b3JrLA0KICAgICAgICAgIHBhcmFtcyA9IHBhcmFtcywNCiAgICAgICAgICBtYXhfcm91bmRzID0gNTAsDQogICAgICAgICAgbWlfdGhyZXNob2xkID0gdGhyZXNoLA0KICAgICAgICAgIGNob2ljZV9ydWxlID0gY2ZnJGNob2ljZV9ydWxlDQogICAgICAgICkNCiAgICAgICAgDQogICAgICAgICMgcGFja2FnZSByZXN1bHQNCiAgICAgICAgbGlzdCgNCiAgICAgICAgICBjb25maWdfaWQgPSBpLA0KICAgICAgICAgIG1pbl9kZWcgPSBjZmckbWluX2RlZywNCiAgICAgICAgICBwID0gY2ZnJHAsDQogICAgICAgICAgdGFyZ2V0X3IgPSBjZmckcl9raywNCiAgICAgICAgICBhY3R1YWxfciA9IGFjdHVhbF9yLA0KICAgICAgICAgIHRhcmdldF9yaG8gPSBjZmckcmhvX2t4LA0KICAgICAgICAgIGFjdHVhbF9yaG8gPSBmaW5hbF9yaG8sDQogICAgICAgICAgbWkgPSBtaSwNCiAgICAgICAgICBzZWVkID0gc2VlZCwNCiAgICAgICAgICBjaG9pY2VfcnVsZSA9IGNmZyRjaG9pY2VfcnVsZSwNCiAgICAgICAgICBpbmZsdWVuY2UgPSBjZmckaW5mbHVlbmNlLA0KICAgICAgICAgIGdyb3VwX3NpemUgPSBuZXdfbiwNCiAgICAgICAgICBtaW5vcml0eV9wcm9wID0gY2ZnJG1pbm9yaXR5X3Byb3AsDQogICAgICAgICAgc2ltID0gbGlzdCgNCiAgICAgICAgICAgIG91dGNvbWVzID0gc2ltJG91dGNvbWVzLA0KICAgICAgICAgICAgZXF1aWxpYnJpdW0gPSBzaW0kZXF1aWxpYnJpdW0NCiAgICAgICAgICApDQogICAgICAgICAgDQogICAgICAgICkNCiAgICAgIH0sIGVycm9yID0gZnVuY3Rpb24oZSkgew0KICAgICAgICBtZXNzYWdlKHNwcmludGYoIkl0ZXJhdGlvbiAlZCBmYWlsZWQgZm9yIGNvbmZpZyAlZDogJXMiLCBpdGVyLCBpLCBlJG1lc3NhZ2UpKQ0KICAgICAgICBOVUxMDQogICAgICB9KQ0KICAgIH0NCiAgICANCiAgICByZXN1bHRzIDwtIEZpbHRlcihOZWdhdGUoaXMubnVsbCksIHJlc3VsdHMpDQogICAgDQogICAgIyBzYXZlIGFsbCBpdGVyYXRpb25zIGZvciB0aGlzIGNvbmZpZ3VyYXRpb24gYXMgYSBzaW5nbGUgZmlsZQ0KICAgIHNhdmVSRFMocmVzdWx0cywgZmlsZSA9IHBhc3RlMCgiLi9zaW1zMi9yZXN1bHRzX2NvbmZpZ18iLCBpLCAiLnJkcyIpKQ0KICB9DQp9KQ0KDQojIG5vdyBsb2FkIGluIHRoZSByZXN1bHRzDQpyZXN1bHRzX2RpciA8LSAiLi9zaW1zMi8iDQpmaWxlcyA8LSBsaXN0LmZpbGVzKHJlc3VsdHNfZGlyLCBwYXR0ZXJuID0gIl5yZXN1bHRzX2NvbmZpZ19cXGQrXFwucmRzJCIsIGZ1bGwubmFtZXMgPSBUUlVFKQ0KDQojIHRvIGEgbG9uZyBkYXRhZnJhbWUNCmFsbF9yZXN1bHRzIDwtIGZvcmVhY2goZmlsZSA9IGZpbGVzLCAuY29tYmluZSA9IGJpbmRfcm93cywgLnBhY2thZ2VzID0gYygidGliYmxlIiwgImRwbHlyIikpICVkb3BhciUgew0KICBjb25maWdfcmVzdWx0cyA8LSByZWFkUkRTKGZpbGUpDQogIHN1bW1hcmllcyA8LSBsYXBwbHkoY29uZmlnX3Jlc3VsdHMsIGZ1bmN0aW9uKHJlcykgew0KICAgIGVxIDwtIHJlcyRzaW0kZXF1aWxpYnJpdW0NCiAgICANCiAgICB0aWJibGUoDQogICAgICBjb25maWdfaWQgPSByZXMkY29uZmlnX2lkLA0KICAgICAgc2l6ZSA9IHJlcyRncm91cF9zaXplLA0KICAgICAgbWluX2RlZyA9IHJlcyRtaW5fZGVnLA0KICAgICAgcCA9IHJlcyRwLA0KICAgICAgdGFyZ2V0X3IgPSByZXMkdGFyZ2V0X3IsDQogICAgICBhY3R1YWxfciA9IHJlcyRhY3R1YWxfciwNCiAgICAgIHRhcmdldF9yaG8gPSByZXMkdGFyZ2V0X3JobywNCiAgICAgIGFjdHVhbF9yaG8gPSByZXMkYWN0dWFsX3JobywNCiAgICAgIG1pID0gcmVzJG1pLA0KICAgICAgbWlub3JpdHlfcHJvcCA9IHJlcyRtaW5vcml0eV9wcm9wLA0KICAgICAgaW5mbHVlbmNlID0gcmVzJGluZmx1ZW5jZSwNCiAgICAgIGNob2ljZV9ydWxlID0gcmVzJGNob2ljZV9ydWxlLA0KICAgICAgc2VlZCA9IHJlcyRzZWVkLA0KICAgICAgcmVhY2hlZF9lcXVpbGlicml1bSA9IGVxJHJlYWNoZWQsDQogICAgICByb3VuZHNfdG9fZXF1aWxpYnJpdW0gPSBlcSRyb3VuZCwNCiAgICAgIGZpbmFsX2Fkb3B0aW9uX3JhdGUgPSBlcSRwcm9wX2ZvbGxvd190cmVuZCwNCiAgICAgIGJlaF9hc3NvcnQgPSBlcSRzZWdyZWdhdGlvbiRyX2JlaGF2aW9yLA0KICAgICAgTDFDQ19zaGFyZSA9IGVxJHNlZ3JlZ2F0aW9uJEwxQ0Nfc2hhcmUNCiAgICApDQogIH0pDQogIA0KICBiaW5kX3Jvd3Moc3VtbWFyaWVzKQ0KfQ0KDQpzdG9wQ2x1c3RlcihjbCkNCg0KIyBvcmRlciBieSBjb25maWdfaWQNCmRhdGEgPC0gYWxsX3Jlc3VsdHNbb3JkZXIoYWxsX3Jlc3VsdHMkY29uZmlnX2lkKSwgXQ0KDQojZml4KGRhdGEpDQpmc2F2ZShkYXRhLCAic2ltc19zdy5SZGEiKQ0KYGBgIA0KDQotLS0tDQoNCiMgUmVzdWx0cw0KDQpXZSB1c2UgYSBoZWF0bWFwIHRvIHZpc3VhbGl6ZSB0aGUgcHJvYmFiaWxpdHkgd2l0aCB3aGljaCBlYWNoIHRhcmdldCBuZXR3b3JrIGNvbmZpZ3VyYXRpb24gZHJpdmVzIG5lZ2F0aXZlIGVxdWlsaWJyaXVtLCBhY3Jvc3Mgc2VlZHMuDQoNCiMjIENvbmZpZ3VyYXRpb24gbW9kZWwgey50YWJzZXQgLnRhYnNldC1mYWRlfQ0KDQpgYGB7cn0NCiMgaW1wb3J0IGRhdGENCnRvZGF5ID0gIjIwMjUwNjI3IiAjIGRhdGUgb24gd2hpY2ggdGhlIGRhdGEgd2FzIHNhdmVkDQpkYXRhIDwtIGZsb2FkKHBhc3RlMCgiLi9kYXRhL3Byb2Nlc3NlZC8iLCB0b2RheSwgInNpbXNfY29uZi5SZGEiKSkNCiNzdHIoZGF0YSkNCg0KIyBkZWZpbmUgZXF1aWxpYnJpdW0NCiMgZGVmaW5pdGlvbiBkZXBlbmRzIG9uIGRldGVybWluaXN0aWMvc3RvY2hhc3RpYyBjaG9pY2UtcnVsZToNCmRhdGEkdW5wb3AgPC0gTkENCmRhdGEkdW5wb3BbZGF0YSRjaG9pY2VfcnVsZT09ImRldGVybWluaXN0aWMiXSA8LSBpZmVsc2UoDQogIGRhdGEkZmluYWxfYWRvcHRpb25fcmF0ZVtkYXRhJGNob2ljZV9ydWxlPT0iZGV0ZXJtaW5pc3RpYyJdID09IDEgLCAxLCAwKSAjIGZ1bGwgYWRvcHRpb24NCg0KI2ZvciBzdG9jaGFzdGljIGNob2ljZS1ydWxlLCB1c2UgYWx0ZXJuYXRpdmUgZGVmaW5pdGlvbjoNCiN3aGVyZSBwcm9wb3J0aW9uIHRha2luZyB1cCBCID49IHAgKyAoMS1wKSgxLWUpDQpkYXRhJHVucG9wW2RhdGEkY2hvaWNlX3J1bGUgPT0gInByb2JhYmlsaXN0aWMiXSA8LSBpZmVsc2UoZGF0YSRmaW5hbF9hZG9wdGlvbl9yYXRlW2RhdGEkY2hvaWNlX3J1bGUgPT0gInByb2JhYmlsaXN0aWMiXSA+PSBkYXRhJG1pbm9yaXR5X3Byb3BbZGF0YSRjaG9pY2VfcnVsZSA9PSAicHJvYmFiaWxpc3RpYyJdICsgKDEtZGF0YSRtaW5vcml0eV9wcm9wW2RhdGEkY2hvaWNlX3J1bGUgPT0gInByb2JhYmlsaXN0aWMiXSkqKDEtLjEwKSwgMSwgMCkNCmBgYA0KDQojIyMgc3Ryb25nIGluZmx1ZW5jZSB7LnRhYnNldCAudGFic2V0LWZhZGV9DQoNCiMjIyMgdHJ1bmNhdGVkDQoNCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9NCwgY2xhc3Muc291cmNlID0gJ2ZvbGQtaGlkZScgfQ0KI21ha2UgcGxvdHM6DQojMSBkZXRlcm1pbnN0aWMgKG1haW4pDQpmd3JhcHBlcihkYXRhID0gZGF0YSwNCiAgICAgICAgIGNob2ljZV9ydWxlID0gImRldGVybWluaXN0aWMiLA0KICAgICAgICAgaW5mbHVlbmNlID0gInN0cm9uZyIsDQogICAgICAgICBrbWluID0gMiwNCiAgICAgICAgIGttYXggPSAyKnNxcnQobiksDQogICAgICAgICBtaW5vcml0eV9wcm9wcyA9IGMoMC4wNSwgMC4xMCwgMC4xNSkpDQojZ2dzYXZlKCIuL2ZpZ3VyZXMvZGV0X3N0cm9uZ190cnVuYy5wbmciLCBoZWlnaHQ9NCwgd2lkdGggPSAxNCkNCg0KIyAyIHN0b2NoYXN0aWMNCmZ3cmFwcGVyKGRhdGEgPSBkYXRhLA0KICAgICAgICAgY2hvaWNlX3J1bGUgPSAicHJvYmFiaWxpc3RpYyIsDQogICAgICAgICBpbmZsdWVuY2UgPSAic3Ryb25nIiwNCiAgICAgICAgIGttaW4gPSAyLA0KICAgICAgICAga21heCA9IDIqc3FydChuKSwNCiAgICAgICAgIG1pbm9yaXR5X3Byb3BzID0gYygwLjA1LCAwLjEwLCAwLjE1KSkNCiNnZ3NhdmUoIi4vZmlndXJlcy9zdG9jaF9zdHJvbmdfdHJ1bmMucG5nIiwgaGVpZ2h0PTQsIHdpZHRoID0gMTQpDQpgYGAgIA0KDQojIyMjIHVudHJ1bmNhdGVkDQoNCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9NCwgY2xhc3Muc291cmNlID0gJ2ZvbGQtaGlkZScgfQ0KZndyYXBwZXIoZGF0YSA9IGRhdGEsDQogICAgICAgICBjaG9pY2VfcnVsZSA9ICJkZXRlcm1pbmlzdGljIiwNCiAgICAgICAgIGluZmx1ZW5jZSA9ICJzdHJvbmciLA0KICAgICAgICAga21pbiA9IDIsDQogICAgICAgICBrbWF4ID0gbi0xLA0KICAgICAgICAgbWlub3JpdHlfcHJvcHMgPSBjKDAuMDUsIDAuMTAsIDAuMTUpKQ0KI2dnc2F2ZSgiLi9maWd1cmVzL2RldF9zdHJvbmdfdW50cnVuYy5wbmciLCBoZWlnaHQ9NCwgd2lkdGggPSAxNCkNCg0KZndyYXBwZXIoZGF0YSA9IGRhdGEsDQogICAgICAgICBjaG9pY2VfcnVsZSA9ICJwcm9iYWJpbGlzdGljIiwNCiAgICAgICAgIGluZmx1ZW5jZSA9ICJzdHJvbmciLA0KICAgICAgICAga21pbiA9IDIsDQogICAgICAgICBrbWF4ID0gbi0xLA0KICAgICAgICAgbWlub3JpdHlfcHJvcHMgPSBjKDAuMDUsIDAuMTAsIDAuMTUpKQ0KI2dnc2F2ZSgiLi9maWd1cmVzL3N0b2NoX3N0cm9uZ191bnRydW5jLnBuZyIsIGhlaWdodD00LCB3aWR0aCA9IDE0KQ0KYGBgDQoNCiMjIyB3ZWFrIGluZmx1ZW5jZSB7LnRhYnNldCAudGFic2V0LWZhZGV9DQoNCiMjIyMgdHJ1bmNhdGVkDQoNCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9NCwgY2xhc3Muc291cmNlID0gJ2ZvbGQtaGlkZScgfQ0KI21ha2UgcGxvdHM6DQojMSBkZXRlcm1pbnN0aWMgKG1haW4pDQpmd3JhcHBlcihkYXRhID0gZGF0YSwNCiAgICAgICAgIGNob2ljZV9ydWxlID0gImRldGVybWluaXN0aWMiLA0KICAgICAgICAgaW5mbHVlbmNlID0gIndlYWsiLA0KICAgICAgICAga21pbiA9IDIsDQogICAgICAgICBrbWF4ID0gMipzcXJ0KG4pLA0KICAgICAgICAgbWlub3JpdHlfcHJvcHMgPSBjKDAuMTAsIDAuMTUpKQ0KDQojIDIgc3RvY2hhc3RpYw0KZndyYXBwZXIoZGF0YSA9IGRhdGEsDQogICAgICAgICBjaG9pY2VfcnVsZSA9ICJwcm9iYWJpbGlzdGljIiwNCiAgICAgICAgIGluZmx1ZW5jZSA9ICJ3ZWFrIiwNCiAgICAgICAgIGttaW4gPSAyLA0KICAgICAgICAga21heCA9IDIqc3FydChuKSwNCiAgICAgICAgIG1pbm9yaXR5X3Byb3BzID0gYygwLjEwLCAwLjE1KSkNCmBgYCAgDQoNCiMjIyMgdW50cnVuY2F0ZWQNCg0KYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD00LCBjbGFzcy5zb3VyY2UgPSAnZm9sZC1oaWRlJyB9DQpmd3JhcHBlcihkYXRhID0gZGF0YSwNCiAgICAgICAgIGNob2ljZV9ydWxlID0gImRldGVybWluaXN0aWMiLA0KICAgICAgICAgaW5mbHVlbmNlID0gIndlYWsiLA0KICAgICAgICAga21pbiA9IDIsDQogICAgICAgICBrbWF4ID0gbi0xLA0KICAgICAgICAgbWlub3JpdHlfcHJvcHMgPSBjKDAuMTAsIDAuMTUpKQ0KDQpmd3JhcHBlcihkYXRhID0gZGF0YSwNCiAgICAgICAgIGNob2ljZV9ydWxlID0gInByb2JhYmlsaXN0aWMiLA0KICAgICAgICAgaW5mbHVlbmNlID0gInN0cm9uZyIsDQogICAgICAgICBrbWluID0gMiwNCiAgICAgICAgIGttYXggPSBuLTEsDQogICAgICAgICBtaW5vcml0eV9wcm9wcyA9IGMoIDAuMTAsIDAuMTUpKQ0KYGBgDQoNCiMjIyB7LnVubGlzdGVkIC51bm51bWJlcmVkfQ0KDQoNCjwhLS0tDQoNCmBgYHtyfQ0KIyMgaWRlbnRpZnksIGFjcm9zcyB0aGUgZGF0YWZyYW1lLCB0aGUgY29uZmlndXJhdGlvbnMgKCsgc2VlZHMpIHRoYXQgZHJvdmUgbmVnYXRpdmUgZXF1aWxpYnJpdW0gaW4gYm90aCBjaG9pY2UgbW9kZWxzLg0KDQojc3RyKGRhdGEpDQojIGNyZWF0ZSB0aGUgY29uZmlnLXNlZWQgY29tYmkNCmRmIDwtIGRhdGEgJT4lDQogIG11dGF0ZShJRCA9IHBhc3RlKGNvbmZpZ19pZCwgc2VlZCwgc2VwID0gIl8iKSkNCg0KIyBmaWx0ZXIgYnkgcnVsZQ0KZGZfZGV0IDwtIGRmICU+JSBmaWx0ZXIoY2hvaWNlX3J1bGUgPT0gImRldGVybWluaXN0aWMiKQ0KZGZfcHJvYiA8LSBkZiAlPiUgZmlsdGVyKGNob2ljZV9ydWxlID09ICJwcm9iYWJpbGlzdGljIikNCmRmX3Byb2IkSUQgPC0gZGZfZGV0JElEICMgaWRzIGFyZSBzYW1lICh0YWtlIGNob2ljZS1ydWxlIG91dCBvZiB0aGUgZXF1YXRpb24pIA0KDQojIGdldCBjb21tb24gSURzIHdoZXJlIHVucG9wID09IDEgaW4gYm90aA0KZGV0X3VucG9wX2lkcyA8LSBkZl9kZXQgJT4lIGZpbHRlcih1bnBvcCA9PSAxKSAlPiUgcHVsbChJRCkNCnByb2JfdW5wb3BfaWRzIDwtIGRmX3Byb2IgJT4lIGZpbHRlcih1bnBvcCA9PSAxKSAlPiUgcHVsbChJRCkNCmJvdGhfcnVsZXNfaWRzIDwtIGludGVyc2VjdChkZXRfdW5wb3BfaWRzLCBwcm9iX3VucG9wX2lkcykNCg0KIyBmaWx0ZXIgdGhlIG9yaWdpbmFsIGRmIGJ5IHRoZXNlIElEcw0KZGZfY29tbW9uIDwtIGRmICU+JQ0KICBmaWx0ZXIoSUQgJWluJSBib3RoX3J1bGVzX2lkcykNCg0KIyBuZXN0IGJ5IGNvbmZpZ19pZA0KcmVzdWx0IDwtIGRmX2NvbW1vbiAlPiUNCiAgc2VsZWN0KGNvbmZpZ19pZCwgc2VlZCkNCnBsb3QodGFibGUocmVzdWx0JGNvbmZpZ19pZCkpDQpgYGANCg0KLS0+IA0KDQo8YnI+DQoNCg0KIyMgV2F0dHMtU3Ryb2dhdHogbW9kZWwgey50YWJzZXQgLnRhYnNldC1mYWRlfQ0KDQpgYGB7cn0NCiMgaW1wb3J0IGRhdGENCnRvZGF5ID0gIjIwMjUwNjI3IiAjIGRhdGUgb24gd2hpY2ggdGhlIGRhdGEgd2FzIHNhdmVkDQpkYXRhIDwtIGZsb2FkKHBhc3RlMCgiLi9kYXRhL3Byb2Nlc3NlZC8iLCB0b2RheSwgInNpbXNfc3cuUmRhIikpDQojc3RyKGRhdGEpDQoNCiMgZGVmaW5lIGVxdWlsaWJyaXVtDQojIGRlZmluaXRpb24gZGVwZW5kcyBvbiBkZXRlcm1pbmlzdGljL3N0b2NoYXN0aWMgY2hvaWNlLXJ1bGU6DQpkYXRhJHVucG9wIDwtIE5BDQpkYXRhJHVucG9wW2RhdGEkY2hvaWNlX3J1bGU9PSJkZXRlcm1pbmlzdGljIl0gPC0gaWZlbHNlKA0KICBkYXRhJGZpbmFsX2Fkb3B0aW9uX3JhdGVbZGF0YSRjaG9pY2VfcnVsZT09ImRldGVybWluaXN0aWMiXSA9PSAxICwgMSwgMCkgIyBmdWxsIGFkb3B0aW9uDQoNCiNmb3Igc3RvY2hhc3RpYyBjaG9pY2UtcnVsZSwgdXNlIGFsdGVybmF0aXZlIGRlZmluaXRpb246DQojd2hlcmUgcHJvcG9ydGlvbiB0YWtpbmcgdXAgQiA+PSBwICsgKDEtcCkoMS1lKQ0KZGF0YSR1bnBvcFtkYXRhJGNob2ljZV9ydWxlID09ICJwcm9iYWJpbGlzdGljIl0gPC0gaWZlbHNlKGRhdGEkZmluYWxfYWRvcHRpb25fcmF0ZVtkYXRhJGNob2ljZV9ydWxlID09ICJwcm9iYWJpbGlzdGljIl0gPj0gZGF0YSRtaW5vcml0eV9wcm9wW2RhdGEkY2hvaWNlX3J1bGUgPT0gInByb2JhYmlsaXN0aWMiXSArICgxLWRhdGEkbWlub3JpdHlfcHJvcFtkYXRhJGNob2ljZV9ydWxlID09ICJwcm9iYWJpbGlzdGljIl0pKigxLS4xMCksIDEsIDApDQpgYGANCg0KIyMjIHN0cm9uZyBpbmZsdWVuY2UNCg0KYGBge3IsIGZpZy53aWR0aD0xOCwgZmlnLmhlaWdodD00LCBjbGFzcy5zb3VyY2UgPSAnZm9sZC1oaWRlJyB9DQojbWFrZSBwbG90czoNCiMxIGRldGVybWluc3RpYyAobWFpbikNCmZ3cmFwcGVyKGRhdGEgPSBkYXRhLA0KICAgICAgICAgZnBsb3QgPSBmY3JlYXRlX2hlYXRtYXBfc3csDQogICAgICAgICBjaG9pY2VfcnVsZSA9ICJkZXRlcm1pbmlzdGljIiwNCiAgICAgICAgIGluZmx1ZW5jZSA9ICJzdHJvbmciLA0KICAgICAgICAgbWlub3JpdHlfcHJvcHMgPSBjKCAwLjA1LCAwLjEwLCAwLjE1KSkNCg0KI2dnc2F2ZSgiLi9maWd1cmVzL2RldF9zdHJvbmdfc3cucG5nIiwgaGVpZ2h0PTQsIHdpZHRoID0gMTgpDQoNCiMgc3RvY2hhc3RpYw0KZndyYXBwZXIoZGF0YSA9IGRhdGEsDQogICAgICAgICBmcGxvdCA9IGZjcmVhdGVfaGVhdG1hcF9zdywNCiAgICAgICAgIGNob2ljZV9ydWxlID0gInByb2JhYmlsaXN0aWMiLA0KICAgICAgICAgaW5mbHVlbmNlID0gInN0cm9uZyIsDQogICAgICAgICBtaW5vcml0eV9wcm9wcyA9IGMoIDAuMDUsIDAuMTAsIDAuMTUpKQ0KIz1nZ3NhdmUoIi4vZmlndXJlcy9zdG9jaF9zdHJvbmdfc3cucG5nIiwgaGVpZ2h0PTQsIHdpZHRoID0gMTgpDQpgYGANCg0KDQojIyMgd2VhayBpbmZsdWVuY2UNCg0KYGBge3IsIGZpZy53aWR0aD0xNiwgZmlnLmhlaWdodD00LjUsIGNsYXNzLnNvdXJjZSA9ICdmb2xkLWhpZGUnIH0NCmZ3cmFwcGVyKGRhdGEgPSBkYXRhLA0KICAgICAgICAgZnBsb3QgPSBmY3JlYXRlX2hlYXRtYXBfc3csDQogICAgICAgICBjaG9pY2VfcnVsZSA9ICJkZXRlcm1pbmlzdGljIiwNCiAgICAgICAgIGluZmx1ZW5jZSA9ICJ3ZWFrIiwNCiAgICAgICAgIG1pbm9yaXR5X3Byb3BzID0gYyggMC4xMCwgMC4xNSkpDQojZ2dzYXZlKCIuL2ZpZ3VyZXMvZGV0X3dlYWtfc3cucG5nIiwgaGVpZ2h0PTQsIHdpZHRoID0gMTQpDQoNCmZ3cmFwcGVyKGRhdGEgPSBkYXRhLA0KICAgICAgICAgZnBsb3QgPSBmY3JlYXRlX2hlYXRtYXBfc3csDQogICAgICAgICBjaG9pY2VfcnVsZSA9ICJwcm9iYWJpbGlzdGljIiwNCiAgICAgICAgIGluZmx1ZW5jZSA9ICJ3ZWFrIiwNCiAgICAgICAgIG1pbm9yaXR5X3Byb3BzID0gYyggMC4xMCwgMC4xNSkpDQojZ2dzYXZlKCIuL2ZpZ3VyZXMvc3RvY2hfd2Vha19zdy5wbmciLCBoZWlnaHQ9NCwgd2lkdGggPSAxNCkNCmBgYCANCg0KIyMgey51bmxpc3RlZCAudW5udW1iZXJlZH0NCg0KPGJyPg0KDQpleHBsb3JlIGNsdXN0ZXJpbmcgKGF1dG8tY29ycmVsYXRpb24pIG9mIG5vcm1zIGluIHRoZSBuZXR3b3JrOw0KdGhhdCBpcywgZHlhZGljIHNpbWlsYXJpdHkgKGJlaGF2aW9yYWwgYXNzb3J0YXRpdml0eSkuIGJ1dCBiZXlvbmQgdGhhdCAncG9ja2V0aW5nJyAoZS5nLiwgbGFyZ2VzdCBjb21wb25lbnQgc2l6ZS9zaGFyZSk7IG9yIHNlZ3JlZ2F0aW9uIGF0IGRpc3RhbmNlLTEgYW5kIGRpc3RhbmNlLWs+MSBvciBkaXN0YW5jZSBkZWNheS4NCg0KYGBge3J9DQojYWxsX3Jlc3VsdHMkYmVoX2Fzc29ydA0KI3Bsb3QoYWxsX3Jlc3VsdHMkYmVoX2Fzc29ydCwgYWxsX3Jlc3VsdHMkcCkNCmBgYA0KDQoNCi0tLQ0KDQojIFJlZmVyZW5jZXM=


Copyright © Rob Franken