Experimental
conditions
# pick one configuration that likely leads to an unpopular norm, and explore multiple 'seeds':
run_one_seed <- function(
i,
base_seed = 1253281123,
params = list(s = 15, e = 10, w = 40, z = 50, lambda1 = 5, lambda2 = 1.8),
# tweak network
k_min = 2,
k_max = 9,
alpha = 2.1,
rho = 0.4,
r = -0.1,
# retrieve network
return_network = FALSE
) {
# derived seed for this run
seed_i <- base_seed + i
set.seed(seed_i)
# --- network creation ---
degseq <- fdegseq(
n = 10,
alpha = alpha,
k_min = k_min,
k_max = k_max,
dist = "log-normal", #use log-normal
seed = seed_i
)
network <- sample_degseq(degseq, method = "vl")
V(network)$role <- sample(
c(rep("trendsetter", 2), rep("conformist", 8))
)
rewired_network <- frewire_r(network, r, verbose = FALSE, max_iter = 1e5)
final_network <- fswap_rho(rewired_network, rho, verbose = FALSE, max_iter = 1e4)
# --- stats ---
stats <- list(
run = i,
seed = seed_i,
num_nodes = vcount(final_network),
num_edges = ecount(final_network),
avg_degree = mean(degree(final_network)),
sd_degree = sd(degree(final_network)),
net_density = edge_density(final_network),
net_diameter = diameter(final_network, directed = FALSE, unconnected = TRUE),
avg_path_len = average.path.length(final_network, directed = FALSE),
clust_coeff = transitivity(final_network, type = "global"),
assort_deg = assortativity_degree(final_network),
deg_trait_cor = fdegtraitcor(final_network)$cor,
components = components(final_network)$no
)
fplot_graph(final_network, layout = layout_with_fr(final_network))
# --- initial actions ---
V(final_network)$action <- ifelse(V(final_network)$role == "trendsetter", 1, 0)
# --- deterministic simulation ---
sim_det <- fabm(
network = final_network,
params = params,
max_rounds = 50,
mi_threshold = 0.49,
choice_rule = "deterministic",
plot = TRUE,
histories = TRUE
)
# generate the gif for the current network
gif_filename <- paste0("./figures/animation_network_", seed_i, ".gif")
gif_path <- fnetworkgif(final_network, sim_det$decision_history, rounds = sim_det$equilibrium$round, output_dir = "./figures")
# rename the gif to match the naming pattern
file.rename(gif_path, gif_filename)
if (!is.null(sim_det$plot)) {
print(sim_det$plot)
}
# --- probabilistic simulation ---
sim_prob <- fabm(
network = final_network,
params = params,
max_rounds = 100,
mi_threshold = 0.49,
choice_rule = "probabilistic",
stable_window = 8, # the length of the window of adoption values
required_stable_rounds = 20, # number of windows needed to declare equilibrium
plot = TRUE
)
if (!is.null(sim_prob$plot)) {
print(sim_prob$plot)
}
result <- list(
segregation_det = sim_det$equilibrium$segregation,
segregation_prob = sim_prob$equilibrium$segregation,
stats = stats
)
if (return_network) {
result$network <- final_network
}
result
}
####
run_one_sw <- function(
i,
base_seed = 1253281123,
model = "watts-strogatz",
beta = 0,
nei = 3,
clique_size = 5,
pmin = 0.1,
params = list(s = 15, e = 10, w = 40, z = 50, lambda1 = 5, lambda2 = 1.8),
# retrieve network
return_network = FALSE
) {
# derived seed for this run
seed_i <- base_seed + i
set.seed(seed_i)
if (model == "watts-strogatz") {
network <- sample_smallworld(dim = 1, size = 10, nei = 3, p = beta) }
else if (model == "caveman") {
network <- simulate_caveman(n = 10, clique_size = clique_size)
}
V(network)$role <- sample(
c(rep("trendsetter", 2), rep("conformist", 8))
)
final_network <- network
# --- stats ---
stats <- list(
run = i,
seed = seed_i,
num_nodes = vcount(final_network),
num_edges = ecount(final_network),
avg_degree = mean(degree(final_network)),
sd_degree = sd(degree(final_network)),
net_density = edge_density(final_network),
net_diameter = diameter(final_network, directed = FALSE, unconnected = TRUE),
avg_path_len = average.path.length(final_network, directed = FALSE),
clust_coeff = transitivity(final_network, type = "global"),
assort_deg = assortativity_degree(final_network),
deg_trait_cor = fdegtraitcor(final_network)$cor,
components = components(final_network)$no
)
stats_df <- data.frame(
Metric = names(stats),
Value = unlist(stats),
row.names = NULL
)
#print(stats_df)
fplot_graph(final_network, layout = layout.kamada.kawai(final_network))
# --- initial actions ---
V(final_network)$action <- ifelse(V(final_network)$role == "trendsetter", 1, 0)
# --- deterministic simulation ---
sim_det <- fabm(
network = final_network,
params = params,
max_rounds = 50,
mi_threshold = 0.49,
choice_rule = "deterministic",
plot = TRUE,
histories = TRUE
)
# generate the gif for the current network
gif_filename <- paste0("./figures/animation_network_", seed_i, ".gif")
gif_path <- fnetworkgif(final_network, sim_det$decision_history, rounds = sim_det$equilibrium$round, output_dir = "./figures")
# rename the gif to match the naming pattern
file.rename(gif_path, gif_filename)
if (!is.null(sim_det$plot)) {
print(sim_det$plot)
}
# --- probabilistic simulation ---
sim_prob <- fabm(
network = final_network,
params = params,
max_rounds = 100,
mi_threshold = 0.49,
choice_rule = "probabilistic",
stable_window = 8, # the length of the window of adoption values
required_stable_rounds = 20, # number of windows needed to declare equilibrium
plot = TRUE
)
if (!is.null(sim_prob$plot)) {
print(sim_prob$plot)
}
result <- list(
segregation_det = sim_det$equilibrium$segregation,
segregation_prob = sim_prob$equilibrium$segregation,
stats = stats
)
if (return_network) {
result$network <- final_network
}
result
}
test <- run_one_seed(1, k_min = 2, k_max = 9, alpha = 2.1, rho = 0.7, r = -0.1, return_network = TRUE)



base = 1253281123
seed = base + 1
# use this as the network structure for an otree session:
# cbind(degree(test$network),V(test$network)$role)
# convert to adjacency matrix
adj_matrix <- as.matrix(as_adjacency_matrix(test$network))
# get roles
role_vector <- ifelse(V(test$network)$role == "trendsetter", 1, 0)
# create a list to store the network data
net <- list(adj_matrix = adj_matrix, role_vector = role_vector)
# save the list as a JSON file
write_json(net, "network_test_n10.json")
# random
test <- run_one_sw(i = 15, beta = 1, pmin = 0.15, return_network = TRUE)



# fplot_graph(test$network)
# use this as the network structure for an otree session:
# cbind(degree(test$network),V(test$network)$role)
# convert to adjacency matrix
adj_matrix <- as.matrix(as_adjacency_matrix(test$network))
# get roles
role_vector <- ifelse(V(test$network)$role == "trendsetter", 1, 0)
# create a list to store the network data
net <- list(adj_matrix = adj_matrix, role_vector = role_vector)
# save the list as a JSON file
write_json(net, "network_test_n10_random.json")
LS0tDQp0aXRsZTogIkV4cGVyaW1lbnQiDQpiaWJsaW9ncmFwaHk6IHJlZmVyZW5jZXMuYmliDQpsaW5rLWNpdGF0aW9uczogdHJ1ZQ0KZGF0ZTogIkxhc3QgY29tcGlsZWQgb24gYHIgZm9ybWF0KFN5cy50aW1lKCksICclZC0lbS0lWScpYCINCm91dHB1dDogDQogIGh0bWxfZG9jdW1lbnQ6DQogICAgc2VsZl9jb250YWluZWQ6IHRydWUNCiAgICBjc3M6IHR3ZWFrcy5jc3MNCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZmxvYXQ6IHRydWUNCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUNCiAgICB0b2NfZGVwdGg6IDQNCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCi0tLQ0KDQpgYGB7ciwgZ2xvYmFsc2V0dGluZ3MsIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHJlc3VsdHM9J2hpZGUnLCBtZXNzYWdlPUZBTFNFfQ0KbGlicmFyeShrbml0cikNCmxpYnJhcnkodGlkeXZlcnNlKQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0Kb3B0c19jaHVuayRzZXQodGlkeS5vcHRzPWxpc3Qod2lkdGguY3V0b2ZmPTEwMCksdGlkeT1UUlVFLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSxjb21tZW50ID0gIiM+IiwgY2FjaGU9VFJVRSwgY2xhc3Muc291cmNlPWMoInRlc3QiKSwgY2xhc3Mub3V0cHV0PWMoInRlc3QzIikpDQpvcHRpb25zKHdpZHRoID0gMTAwKQ0KcmdsOjpzZXR1cEtuaXRyKCkNCg0KY29sb3JpemUgPC0gZnVuY3Rpb24oeCwgY29sb3IpIHtzcHJpbnRmKCI8c3BhbiBzdHlsZT0nY29sb3I6ICVzOyc+JXM8L3NwYW4+IiwgY29sb3IsIHgpIH0NCmBgYA0KDQpgYGB7ciBrbGlwcHksIGVjaG89RkFMU0UsIGluY2x1ZGU9VFJVRX0NCmtsaXBweTo6a2xpcHB5KHBvc2l0aW9uID0gYygndG9wJywgJ3JpZ2h0JykpDQoja2xpcHB5OjprbGlwcHkoY29sb3IgPSAnZGFya3JlZCcpDQoja2xpcHB5OjprbGlwcHkodG9vbHRpcF9tZXNzYWdlID0gJ0NsaWNrIHRvIGNvcHknLCB0b29sdGlwX3N1Y2Nlc3MgPSAnRG9uZScpDQpgYGANCg0KLS0tDQoNCiMgR2V0dGluZyBzdGFydGVkDQoNClRvIGNvcHkgdGhlIGNvZGUsIGNsaWNrIHRoZSBidXR0b24gaW4gdGhlIHVwcGVyIHJpZ2h0IGNvcm5lciBvZiB0aGUgY29kZS1jaHVua3MuDQoNCiMjIGNsZWFuIHVwDQoNCmBgYHtyLCBjbGVhbl91cCwgcmVzdWx0cz0naGlkZSd9DQpybShsaXN0PWxzKCkpDQpnYygpDQpgYGANCg0KPGJyPg0KDQojIyBjdXN0b20gZnVuY3Rpb25zDQoNCldlIGRlZmluZWQgYSBudW1iZXIgY3VzdG9tIGZ1bmN0aW9ucywgYXQgYHIgeGZ1bjo6ZW1iZWRfZmlsZSgiLi9jdXN0b21fZnVuY3Rpb25zLlIiKWAuDQoNCmBgYHtyLCBjdXN0b21fZnVuY3Rpb25zfQ0Kc291cmNlKCIuL2N1c3RvbV9mdW5jdGlvbnMuUiIpDQpgYGANCg0KPGJyPg0KDQojIyBuZWNlc3NhcnkgcGFja2FnZXMNCg0KLSBgdGlkeXZlcnNlYDogZGF0YSB3cmFuZ2xpbmcNCi0gYGlncmFwaGA6IGdlbmVyYXRlIGFuZCB2aXN1YWxpemUgZ3JhcGhzDQotIGBwYXJhbGxlbGA6IHBhcmFsbGVsIGNvbXB1dGluZyB0byBzcGVlZCB1cCBzaW11bGF0aW9uDQotIGBmb3JlYWNoYDogbG9vcGluZyBpbiBwYXJhbGxlbA0KLSBgZG9QYXJhbGxlbGA6IHBhcmFsbGVsIGJhY2tlbmQgZm9yIGBmb3JlYWNoYA0KLSBgZ2dwbG90MmA6IGRhdGEgdmlzdWFsaXphdGlvbg0KLSBgZ2doNHhgOiBoYWNrcyBmb3IgYGdncGxvdDJgDQotIGBnZ3B1YnJgOiBtYWtlIHZpc3VhbGl6YXRpb25zIHB1YmxpY2F0aW9uLXJlYWR5DQoNCmBgYHtyLCBwYWNrYWdlc30NCnBhY2thZ2VzID0gYygidGlkeXZlcnNlIiwgImlncmFwaCIsICJnZ3Bsb3QyIiwgInBhcmFsbGVsIiwgImRvUGFyYWxsZWwiLCAiZm9yZWFjaCIsICJnZ2g0eCIsICJnZ3B1YnIiLCAicGxvdGx5IiwgIlJDb2xvckJyZXdlciIsICJncmlkIiwgImdyaWRFeHRyYSIsICJwYXRjaHdvcmsiLCAiZ2dwbG90aWZ5IiwgImdncmFwaCIsICJnZ2FuaW1hdGUiLCAiUkNvbG9yQnJld2VyIiwNCiAgICAiZ2d0ZXh0IiwgIm1hZ2ljayIsICJqc29ubGl0ZSIpDQoNCmludmlzaWJsZShmcGFja2FnZS5jaGVjayhwYWNrYWdlcykpDQpybShwYWNrYWdlcykNCmBgYA0KDQotLS0NCg0KIyBFeHBlcmltZW50YWwgY29uZGl0aW9ucw0KDQoNCmBgYHtyLCBlY2hvPVRSVUUsIGZpZy5zaG93PSdob2xkJywgZmlnLmtlZXA9J2FsbCcsIG1lc3NhZ2U9RkFMU0UsIGZpZy5oZWlnaHQ9NX0NCiMgcGljayBvbmUgY29uZmlndXJhdGlvbiB0aGF0IGxpa2VseSBsZWFkcyB0byBhbiB1bnBvcHVsYXIgbm9ybSwgYW5kIGV4cGxvcmUgbXVsdGlwbGUgJ3NlZWRzJzoNCnJ1bl9vbmVfc2VlZCA8LSBmdW5jdGlvbigNCiAgaSwNCiAgYmFzZV9zZWVkID0gMTI1MzI4MTEyMywNCiAgcGFyYW1zID0gbGlzdChzID0gMTUsIGUgPSAxMCwgdyA9IDQwLCB6ID0gNTAsIGxhbWJkYTEgPSA1LCBsYW1iZGEyID0gMS44KSwNCiAgDQogICMgdHdlYWsgbmV0d29yaw0KICBrX21pbiA9IDIsIA0KICBrX21heCA9IDksDQogIGFscGhhID0gMi4xLA0KICByaG8gPSAwLjQsDQogIHIgPSAtMC4xLA0KICANCiAgIyByZXRyaWV2ZSBuZXR3b3JrDQogIHJldHVybl9uZXR3b3JrID0gRkFMU0UNCiAgDQopIHsNCiAgIyBkZXJpdmVkIHNlZWQgZm9yIHRoaXMgcnVuDQogIHNlZWRfaSA8LSBiYXNlX3NlZWQgKyBpDQogIHNldC5zZWVkKHNlZWRfaSkNCg0KICAjIC0tLSBuZXR3b3JrIGNyZWF0aW9uIC0tLQ0KICBkZWdzZXEgPC0gZmRlZ3NlcSgNCiAgICBuICAgICAgPSAxMCwNCiAgICBhbHBoYSAgPSBhbHBoYSwNCiAgICBrX21pbiAgPSBrX21pbiwNCiAgICBrX21heCAgPSBrX21heCwNCiAgICBkaXN0ICAgPSAibG9nLW5vcm1hbCIsICN1c2UgbG9nLW5vcm1hbCANCiAgICBzZWVkICAgPSBzZWVkX2kNCiAgKQ0KDQogIG5ldHdvcmsgPC0gc2FtcGxlX2RlZ3NlcShkZWdzZXEsIG1ldGhvZCA9ICJ2bCIpDQogIA0KICBWKG5ldHdvcmspJHJvbGUgPC0gc2FtcGxlKA0KICAgIGMocmVwKCJ0cmVuZHNldHRlciIsIDIpLCByZXAoImNvbmZvcm1pc3QiLCA4KSkNCiAgKQ0KICANCg0KICByZXdpcmVkX25ldHdvcmsgPC0gZnJld2lyZV9yKG5ldHdvcmssIHIsIHZlcmJvc2UgPSBGQUxTRSwgbWF4X2l0ZXIgPSAxZTUpDQogIGZpbmFsX25ldHdvcmsgICA8LSBmc3dhcF9yaG8ocmV3aXJlZF9uZXR3b3JrLCByaG8sIHZlcmJvc2UgPSBGQUxTRSwgbWF4X2l0ZXIgPSAxZTQpDQogIA0KICAjIC0tLSBzdGF0cyAtLS0NCiAgc3RhdHMgPC0gbGlzdCgNCiAgICBydW4gICAgICAgICAgID0gaSwNCiAgICBzZWVkICAgICAgICAgID0gc2VlZF9pLA0KICAgIG51bV9ub2RlcyAgICAgPSB2Y291bnQoZmluYWxfbmV0d29yayksDQogICAgbnVtX2VkZ2VzICAgICA9IGVjb3VudChmaW5hbF9uZXR3b3JrKSwNCiAgICBhdmdfZGVncmVlICAgID0gbWVhbihkZWdyZWUoZmluYWxfbmV0d29yaykpLA0KICAgIHNkX2RlZ3JlZSAgICAgPSBzZChkZWdyZWUoZmluYWxfbmV0d29yaykpLA0KICAgIG5ldF9kZW5zaXR5ICAgPSBlZGdlX2RlbnNpdHkoZmluYWxfbmV0d29yayksDQogICAgbmV0X2RpYW1ldGVyICA9IGRpYW1ldGVyKGZpbmFsX25ldHdvcmssIGRpcmVjdGVkID0gRkFMU0UsIHVuY29ubmVjdGVkID0gVFJVRSksDQogICAgYXZnX3BhdGhfbGVuICA9IGF2ZXJhZ2UucGF0aC5sZW5ndGgoZmluYWxfbmV0d29yaywgZGlyZWN0ZWQgPSBGQUxTRSksDQogICAgY2x1c3RfY29lZmYgICA9IHRyYW5zaXRpdml0eShmaW5hbF9uZXR3b3JrLCB0eXBlID0gImdsb2JhbCIpLA0KICAgIGFzc29ydF9kZWcgICAgPSBhc3NvcnRhdGl2aXR5X2RlZ3JlZShmaW5hbF9uZXR3b3JrKSwNCiAgICBkZWdfdHJhaXRfY29yID0gZmRlZ3RyYWl0Y29yKGZpbmFsX25ldHdvcmspJGNvciwNCiAgICBjb21wb25lbnRzICAgID0gY29tcG9uZW50cyhmaW5hbF9uZXR3b3JrKSRubw0KICApDQogIA0KICBmcGxvdF9ncmFwaChmaW5hbF9uZXR3b3JrLCBsYXlvdXQgPSBsYXlvdXRfd2l0aF9mcihmaW5hbF9uZXR3b3JrKSkgDQogIA0KICANCiAgIyAtLS0gaW5pdGlhbCBhY3Rpb25zIC0tLQ0KICBWKGZpbmFsX25ldHdvcmspJGFjdGlvbiA8LSBpZmVsc2UoVihmaW5hbF9uZXR3b3JrKSRyb2xlID09ICJ0cmVuZHNldHRlciIsIDEsIDApDQogIA0KICAjIC0tLSBkZXRlcm1pbmlzdGljIHNpbXVsYXRpb24gLS0tDQogIHNpbV9kZXQgPC0gZmFibSgNCiAgICBuZXR3b3JrICAgICAgPSBmaW5hbF9uZXR3b3JrLA0KICAgIHBhcmFtcyAgICAgICA9IHBhcmFtcywNCiAgICBtYXhfcm91bmRzICAgPSA1MCwNCiAgICBtaV90aHJlc2hvbGQgPSAwLjQ5LA0KICAgIGNob2ljZV9ydWxlICA9ICJkZXRlcm1pbmlzdGljIiwNCiAgICBwbG90ICAgICAgICAgPSBUUlVFLA0KICAgIGhpc3RvcmllcyAgICA9IFRSVUUNCiAgKQ0KICANCiAgIyBnZW5lcmF0ZSB0aGUgZ2lmIGZvciB0aGUgY3VycmVudCBuZXR3b3JrDQogIGdpZl9maWxlbmFtZSA8LSBwYXN0ZTAoIi4vZmlndXJlcy9hbmltYXRpb25fbmV0d29ya18iLCBzZWVkX2ksICIuZ2lmIikNCiAgZ2lmX3BhdGggPC0gZm5ldHdvcmtnaWYoZmluYWxfbmV0d29yaywgc2ltX2RldCRkZWNpc2lvbl9oaXN0b3J5LCByb3VuZHMgPSBzaW1fZGV0JGVxdWlsaWJyaXVtJHJvdW5kLCBvdXRwdXRfZGlyID0gIi4vZmlndXJlcyIpDQogICMgcmVuYW1lIHRoZSBnaWYgdG8gbWF0Y2ggdGhlIG5hbWluZyBwYXR0ZXJuDQogIGZpbGUucmVuYW1lKGdpZl9wYXRoLCBnaWZfZmlsZW5hbWUpDQoNCiAgaWYgKCFpcy5udWxsKHNpbV9kZXQkcGxvdCkpIHsNCiAgICBwcmludChzaW1fZGV0JHBsb3QpDQogIH0NCiAgDQogICMgLS0tIHByb2JhYmlsaXN0aWMgc2ltdWxhdGlvbiAtLS0NCiAgc2ltX3Byb2IgPC0gZmFibSgNCiAgICBuZXR3b3JrICAgICAgICAgICAgICAgID0gZmluYWxfbmV0d29yaywNCiAgICBwYXJhbXMgICAgICAgICAgICAgICAgID0gcGFyYW1zLA0KICAgIG1heF9yb3VuZHMgICAgICAgICAgICAgPSAxMDAsDQogICAgbWlfdGhyZXNob2xkICAgICAgICAgICA9IDAuNDksDQogICAgY2hvaWNlX3J1bGUgICAgICAgICAgICA9ICJwcm9iYWJpbGlzdGljIiwNCiAgICBzdGFibGVfd2luZG93ICAgICAgICAgID0gOCwgICAjIHRoZSBsZW5ndGggb2YgdGhlIHdpbmRvdyBvZiBhZG9wdGlvbiB2YWx1ZXMNCiAgICByZXF1aXJlZF9zdGFibGVfcm91bmRzID0gMjAsICMgbnVtYmVyIG9mIHdpbmRvd3MgbmVlZGVkIHRvIGRlY2xhcmUgZXF1aWxpYnJpdW0NCiAgICBwbG90ICAgICAgICAgICAgICAgICAgID0gVFJVRQ0KICApDQogIGlmICghaXMubnVsbChzaW1fcHJvYiRwbG90KSkgew0KICAgIHByaW50KHNpbV9wcm9iJHBsb3QpDQogIH0NCiAgDQogICByZXN1bHQgPC0gbGlzdCgNCiAgICBzZWdyZWdhdGlvbl9kZXQgID0gc2ltX2RldCRlcXVpbGlicml1bSRzZWdyZWdhdGlvbiwNCiAgICBzZWdyZWdhdGlvbl9wcm9iID0gc2ltX3Byb2IkZXF1aWxpYnJpdW0kc2VncmVnYXRpb24sDQogICAgc3RhdHMgICAgICAgICAgICA9IHN0YXRzDQogICkNCiAgDQogIGlmIChyZXR1cm5fbmV0d29yaykgew0KICAgIHJlc3VsdCRuZXR3b3JrIDwtIGZpbmFsX25ldHdvcmsNCiAgfQ0KICANCiAgcmVzdWx0DQp9DQoNCiMjIyMNCg0KcnVuX29uZV9zdyA8LSBmdW5jdGlvbigNCiAgaSwNCiAgYmFzZV9zZWVkID0gMTI1MzI4MTEyMywNCiAgbW9kZWwgPSAid2F0dHMtc3Ryb2dhdHoiLA0KICBiZXRhID0gMCwNCiAgbmVpID0gMywNCiAgY2xpcXVlX3NpemUgPSA1LA0KICBwbWluID0gMC4xLA0KICANCiAgcGFyYW1zID0gbGlzdChzID0gMTUsIGUgPSAxMCwgdyA9IDQwLCB6ID0gNTAsIGxhbWJkYTEgPSA1LCBsYW1iZGEyID0gMS44KSwNCiAgDQogICMgcmV0cmlldmUgbmV0d29yaw0KICByZXR1cm5fbmV0d29yayA9IEZBTFNFDQogIA0KKSB7DQogICMgZGVyaXZlZCBzZWVkIGZvciB0aGlzIHJ1bg0KICBzZWVkX2kgPC0gYmFzZV9zZWVkICsgaQ0KICBzZXQuc2VlZChzZWVkX2kpDQoNCiAgaWYgKG1vZGVsID09ICJ3YXR0cy1zdHJvZ2F0eiIpIHsNCiAgICBuZXR3b3JrIDwtIHNhbXBsZV9zbWFsbHdvcmxkKGRpbSA9IDEsIHNpemUgPSAxMCwgbmVpID0gMywgcCA9IGJldGEpIH0NCiAgZWxzZSBpZiAobW9kZWwgPT0gImNhdmVtYW4iKSB7DQogICAgbmV0d29yayA8LSBzaW11bGF0ZV9jYXZlbWFuKG4gPSAxMCwgY2xpcXVlX3NpemUgPSBjbGlxdWVfc2l6ZSkgDQogIH0NCg0KICBWKG5ldHdvcmspJHJvbGUgPC0gc2FtcGxlKA0KICAgIGMocmVwKCJ0cmVuZHNldHRlciIsIDIpLCByZXAoImNvbmZvcm1pc3QiLCA4KSkNCiAgKQ0KICANCiAgDQogIGZpbmFsX25ldHdvcmsgPC0gbmV0d29yaw0KDQogIA0KICAjIC0tLSBzdGF0cyAtLS0NCiAgc3RhdHMgPC0gbGlzdCgNCiAgICBydW4gICAgICAgICAgID0gaSwNCiAgICBzZWVkICAgICAgICAgID0gc2VlZF9pLA0KICAgIG51bV9ub2RlcyAgICAgPSB2Y291bnQoZmluYWxfbmV0d29yayksDQogICAgbnVtX2VkZ2VzICAgICA9IGVjb3VudChmaW5hbF9uZXR3b3JrKSwNCiAgICBhdmdfZGVncmVlICAgID0gbWVhbihkZWdyZWUoZmluYWxfbmV0d29yaykpLA0KICAgIHNkX2RlZ3JlZSAgICAgPSBzZChkZWdyZWUoZmluYWxfbmV0d29yaykpLA0KICAgIG5ldF9kZW5zaXR5ICAgPSBlZGdlX2RlbnNpdHkoZmluYWxfbmV0d29yayksDQogICAgbmV0X2RpYW1ldGVyICA9IGRpYW1ldGVyKGZpbmFsX25ldHdvcmssIGRpcmVjdGVkID0gRkFMU0UsIHVuY29ubmVjdGVkID0gVFJVRSksDQogICAgYXZnX3BhdGhfbGVuICA9IGF2ZXJhZ2UucGF0aC5sZW5ndGgoZmluYWxfbmV0d29yaywgZGlyZWN0ZWQgPSBGQUxTRSksDQogICAgY2x1c3RfY29lZmYgICA9IHRyYW5zaXRpdml0eShmaW5hbF9uZXR3b3JrLCB0eXBlID0gImdsb2JhbCIpLA0KICAgIGFzc29ydF9kZWcgICAgPSBhc3NvcnRhdGl2aXR5X2RlZ3JlZShmaW5hbF9uZXR3b3JrKSwNCiAgICBkZWdfdHJhaXRfY29yID0gZmRlZ3RyYWl0Y29yKGZpbmFsX25ldHdvcmspJGNvciwNCiAgICBjb21wb25lbnRzICAgID0gY29tcG9uZW50cyhmaW5hbF9uZXR3b3JrKSRubw0KICApDQogIA0KICBzdGF0c19kZiA8LSBkYXRhLmZyYW1lKA0KICAgIE1ldHJpYyA9IG5hbWVzKHN0YXRzKSwNCiAgICBWYWx1ZSAgPSB1bmxpc3Qoc3RhdHMpLA0KICAgIHJvdy5uYW1lcyA9IE5VTEwNCiAgKQ0KICANCiAgI3ByaW50KHN0YXRzX2RmKQ0KICBmcGxvdF9ncmFwaChmaW5hbF9uZXR3b3JrLCBsYXlvdXQgPSBsYXlvdXQua2FtYWRhLmthd2FpKGZpbmFsX25ldHdvcmspKQ0KICANCg0KICAjIC0tLSBpbml0aWFsIGFjdGlvbnMgLS0tDQogIFYoZmluYWxfbmV0d29yaykkYWN0aW9uIDwtIGlmZWxzZShWKGZpbmFsX25ldHdvcmspJHJvbGUgPT0gInRyZW5kc2V0dGVyIiwgMSwgMCkNCiAgDQogICMgLS0tIGRldGVybWluaXN0aWMgc2ltdWxhdGlvbiAtLS0NCiAgc2ltX2RldCA8LSBmYWJtKA0KICAgIG5ldHdvcmsgICAgICA9IGZpbmFsX25ldHdvcmssDQogICAgcGFyYW1zICAgICAgID0gcGFyYW1zLA0KICAgIG1heF9yb3VuZHMgICA9IDUwLA0KICAgIG1pX3RocmVzaG9sZCA9IDAuNDksDQogICAgY2hvaWNlX3J1bGUgID0gImRldGVybWluaXN0aWMiLA0KICAgIHBsb3QgICAgICAgICA9IFRSVUUsDQogICAgaGlzdG9yaWVzICAgID0gVFJVRQ0KICApDQoNCiAgIyBnZW5lcmF0ZSB0aGUgZ2lmIGZvciB0aGUgY3VycmVudCBuZXR3b3JrDQogIGdpZl9maWxlbmFtZSA8LSBwYXN0ZTAoIi4vZmlndXJlcy9hbmltYXRpb25fbmV0d29ya18iLCBzZWVkX2ksICIuZ2lmIikNCiAgZ2lmX3BhdGggPC0gZm5ldHdvcmtnaWYoZmluYWxfbmV0d29yaywgc2ltX2RldCRkZWNpc2lvbl9oaXN0b3J5LCByb3VuZHMgPSBzaW1fZGV0JGVxdWlsaWJyaXVtJHJvdW5kLCBvdXRwdXRfZGlyID0gIi4vZmlndXJlcyIpDQogICMgcmVuYW1lIHRoZSBnaWYgdG8gbWF0Y2ggdGhlIG5hbWluZyBwYXR0ZXJuDQogIGZpbGUucmVuYW1lKGdpZl9wYXRoLCBnaWZfZmlsZW5hbWUpDQogIA0KICANCiAgaWYgKCFpcy5udWxsKHNpbV9kZXQkcGxvdCkpIHsNCiAgICBwcmludChzaW1fZGV0JHBsb3QpDQogIH0NCiAgDQogICMgLS0tIHByb2JhYmlsaXN0aWMgc2ltdWxhdGlvbiAtLS0NCiAgc2ltX3Byb2IgPC0gZmFibSgNCiAgICBuZXR3b3JrICAgICAgICAgICAgICAgID0gZmluYWxfbmV0d29yaywNCiAgICBwYXJhbXMgICAgICAgICAgICAgICAgID0gcGFyYW1zLA0KICAgIG1heF9yb3VuZHMgICAgICAgICAgICAgPSAxMDAsDQogICAgbWlfdGhyZXNob2xkICAgICAgICAgICA9IDAuNDksDQogICAgY2hvaWNlX3J1bGUgICAgICAgICAgICA9ICJwcm9iYWJpbGlzdGljIiwNCiAgICBzdGFibGVfd2luZG93ICAgICAgICAgID0gOCwgICAjIHRoZSBsZW5ndGggb2YgdGhlIHdpbmRvdyBvZiBhZG9wdGlvbiB2YWx1ZXMNCiAgICByZXF1aXJlZF9zdGFibGVfcm91bmRzID0gMjAsICMgbnVtYmVyIG9mIHdpbmRvd3MgbmVlZGVkIHRvIGRlY2xhcmUgZXF1aWxpYnJpdW0NCiAgICBwbG90ICAgICAgICAgICAgICAgICAgID0gVFJVRQ0KICApDQogIGlmICghaXMubnVsbChzaW1fcHJvYiRwbG90KSkgew0KICAgIHByaW50KHNpbV9wcm9iJHBsb3QpDQogIH0NCiAgDQogIA0KICByZXN1bHQgPC0gbGlzdCgNCiAgICBzZWdyZWdhdGlvbl9kZXQgID0gc2ltX2RldCRlcXVpbGlicml1bSRzZWdyZWdhdGlvbiwNCiAgICBzZWdyZWdhdGlvbl9wcm9iID0gc2ltX3Byb2IkZXF1aWxpYnJpdW0kc2VncmVnYXRpb24sDQogICAgc3RhdHMgICAgICAgICAgICA9IHN0YXRzDQogICkNCiAgDQogIGlmIChyZXR1cm5fbmV0d29yaykgew0KICAgIHJlc3VsdCRuZXR3b3JrIDwtIGZpbmFsX25ldHdvcmsNCiAgfQ0KICANCiAgcmVzdWx0DQp9DQpgYGANCg0KDQpgYGB7cn0NCnRlc3QgPC0gcnVuX29uZV9zZWVkKDEsIGtfbWluID0gMiwga19tYXggPSA5LCBhbHBoYSA9IDIuMSwgcmhvID0gMC43LCByID0gLTAuMSwgcmV0dXJuX25ldHdvcmsgPSBUUlVFKQ0KDQpiYXNlID0gMTI1MzI4MTEyMw0Kc2VlZCA9IGJhc2UgKyAxDQpgYGAgDQoNCmBgYHtyLCBldmFsID0gRkFMU0V9DQojIHVzZSB0aGlzIGFzIHRoZSBuZXR3b3JrIHN0cnVjdHVyZSBmb3IgYW4gb3RyZWUgc2Vzc2lvbjoNCiNjYmluZChkZWdyZWUodGVzdCRuZXR3b3JrKSxWKHRlc3QkbmV0d29yaykkcm9sZSkNCg0KIyBjb252ZXJ0IHRvIGFkamFjZW5jeSBtYXRyaXgNCmFkal9tYXRyaXggPC0gYXMubWF0cml4KGFzX2FkamFjZW5jeV9tYXRyaXgodGVzdCRuZXR3b3JrKSkNCg0KI2dldCByb2xlcw0Kcm9sZV92ZWN0b3IgPC0gaWZlbHNlKFYodGVzdCRuZXR3b3JrKSRyb2xlID09ICJ0cmVuZHNldHRlciIsMSwwKQ0KIyBjcmVhdGUgYSBsaXN0IHRvIHN0b3JlIHRoZSBuZXR3b3JrIGRhdGENCm5ldCA8LSBsaXN0KGFkal9tYXRyaXggPSBhZGpfbWF0cml4LCByb2xlX3ZlY3RvciA9IHJvbGVfdmVjdG9yKQ0KIyBzYXZlIHRoZSBsaXN0IGFzIGEgSlNPTiBmaWxlDQp3cml0ZV9qc29uKG5ldCwgIm5ldHdvcmtfdGVzdF9uMTAuanNvbiIpDQpgYGANCg0KDQpgYGB7cn0NCiNyYW5kb20NCnRlc3QgPC0gcnVuX29uZV9zdyhpPTE1LCBiZXRhPTEsIHBtaW49LjE1LCByZXR1cm5fbmV0d29yayA9IFRSVUUgKQ0KI2ZwbG90X2dyYXBoKHRlc3QkbmV0d29yaykNCmBgYA0KYGBge3IsZXZhbD1GQUxTRX0NCiMgdXNlIHRoaXMgYXMgdGhlIG5ldHdvcmsgc3RydWN0dXJlIGZvciBhbiBvdHJlZSBzZXNzaW9uOg0KI2NiaW5kKGRlZ3JlZSh0ZXN0JG5ldHdvcmspLFYodGVzdCRuZXR3b3JrKSRyb2xlKQ0KDQojIGNvbnZlcnQgdG8gYWRqYWNlbmN5IG1hdHJpeA0KYWRqX21hdHJpeCA8LSBhcy5tYXRyaXgoYXNfYWRqYWNlbmN5X21hdHJpeCh0ZXN0JG5ldHdvcmspKQ0KDQojZ2V0IHJvbGVzDQpyb2xlX3ZlY3RvciA8LSBpZmVsc2UoVih0ZXN0JG5ldHdvcmspJHJvbGUgPT0gInRyZW5kc2V0dGVyIiwxLDApDQojIGNyZWF0ZSBhIGxpc3QgdG8gc3RvcmUgdGhlIG5ldHdvcmsgZGF0YQ0KbmV0IDwtIGxpc3QoYWRqX21hdHJpeCA9IGFkal9tYXRyaXgsIHJvbGVfdmVjdG9yID0gcm9sZV92ZWN0b3IpDQojIHNhdmUgdGhlIGxpc3QgYXMgYSBKU09OIGZpbGUNCndyaXRlX2pzb24obmV0LCAibmV0d29ya190ZXN0X24xMF9yYW5kb20uanNvbiIpDQpgYGANCg==