Note: For now, this is all based on the BHL version of the simulation with landscape_fitness_linked as the outcome variable. That can all be changed, though.


Constraint importance

Here we use a random forest to determine variable importance. We don’t need to include all the interactions (e.g. create_network + select + create_network * select, etc.) because random forests inherently pick those up.

According to Liz Dinsdale:

The mean decrease in Gini coefficient is a measure of how each variable contributes to the homogeneity of the nodes and leaves in the resulting random forest. Each time a particular variable is used to split a node, the Gini coefficient for the child nodes are calculated and compared to that of the original node. The Gini coefficient is a measure of homogeneity from 0 (homogeneous) to 1 (heterogeneous). The changes in Gini are summed for each variable and normalized at the end of the calculation. Variables that result in nodes with higher purity have a higher decrease in Gini coefficient.

Basically, the higher the decrease in impurity, the more important the variable in explaining the outcome.

constraint IncNodePurity
select 748.6
compete 453.9
catastrophe 33.86
create_network 16.69
disperse 2.953
selectfor_d 0.6772

Power of different combinations of constraints

THIS IS MAGICAL.

# Create columns for every combination of constraint in the data (e.g. select &
# disperse, select & disperse & create_network) 
#
# By the inimitable Vincent Arel-Bundock
make_combinations <- function(df, m = 5) {
  com <- colnames(df)[2:ncol(df)] %>%
    combn(m) %>%
    as_tibble()
  out <- com %>%
    map(~ df[.]) %>%
    map(~ rowSums(.) == ncol(.)) %>%
    setNames(map(com, paste, collapse = " + ")) %>%
    as_tibble()
  return(out)
}

# Select just the run number and *_constraint TRUE/FALSE columns
constraint_combinations <- sim_results %>%
  select(runnum, ends_with("_constraint")) %>% 
  # Shrink names by removing "_constraint"
  rename_at(vars(ends_with("constraint")), 
            list(~str_replace_all(., "_constraint", "")))

# Find all combinations of variables (m = number of items in combination; m = 2
# means pairs, m = 3 means triplets, etc.)
all_constraint_combos <- map(2:6, ~make_combinations(constraint_combinations, m = .)) %>% 
  bind_cols(constraint_combinations, .)

# Select the outcome variables we care about (for now just
# landscape_fitness_linked) and join the constraint combinations
constraint_combo_outcomes <- sim_results %>%
  select(runnum, n_constraints, landscape_fitness_linked) %>% 
  right_join(all_constraint_combos, by = "runnum")

# Don't double count rows. If a row has two constraints like select and
# disperse, it'll also have select + disperse set to TRUE. If that's the case,
# we don't want to include it in just select or just disperse
constraint_combo_outcomes_nested <- constraint_combo_outcomes %>% 
  select(-n_constraints) %>% 
  # Make long
  gather(constraint_combo, value, -c(runnum, landscape_fitness_linked)) %>% 
  # Count how many constraints there are within each row based on + signs
  mutate(n = str_count(constraint_combo, "\\+") + 1) %>%
  # Only keep rows where the constraint is turned on
  filter(value == TRUE) %>%
  # Nest all the constraint combinations within each row
  group_by(runnum) %>% 
  nest()

# Only keep the values where n == max(n) for that row
constraint_combo_outcomes_filtered <- constraint_combo_outcomes_nested %>% 
  mutate(filtered = data %>% map(~filter(., n == max(.$n)))) %>% 
  select(-data) %>% 
  unnest(filtered)

# This omitted all the rows where n_constraints == 0, so add those back in
no_constraints <- constraint_combo_outcomes %>% 
  filter(n_constraints == 0) %>% 
  mutate(constraint_combo = "No constraints", n = 0) %>% 
  select(runnum, landscape_fitness_linked, constraint_combo, n)

constraint_combo_outcomes_done <- bind_rows(constraint_combo_outcomes_filtered,
                                            no_constraints) %>% 
  select(-value)

LS0tCnRpdGxlOiAiRmFuY2llciBhbmFseXNpcyIKYXV0aG9yOiAiU3RldmVuIEwuIFBlY2sgYW5kIEFuZHJldyBIZWlzcyIKZGF0ZTogIkxhc3QgcnVuOiBgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVCICVlLCAlWScpYCIKb3V0cHV0OiAKICBodG1sX2RvY3VtZW50OgogICAgY29kZV9mb2xkaW5nOiBoaWRlCmVkaXRvcl9vcHRpb25zOiAKICBjaHVua19vdXRwdXRfdHlwZTogY29uc29sZQotLS0KCioqTm90ZToqKiBGb3Igbm93LCB0aGlzIGlzIGFsbCBiYXNlZCBvbiB0aGUgYEJITGAgdmVyc2lvbiBvZiB0aGUgc2ltdWxhdGlvbiB3aXRoIGBsYW5kc2NhcGVfZml0bmVzc19saW5rZWRgIGFzIHRoZSBvdXRjb21lIHZhcmlhYmxlLiBUaGF0IGNhbiBhbGwgYmUgY2hhbmdlZCwgdGhvdWdoLgoKLS0tCgpgYGB7ciBsb2FkLWxpYnJhcmllcy1kYXRhLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShyYW5kb21Gb3Jlc3QpCmxpYnJhcnkoZ2dyaWRnZXMpCmxpYnJhcnkoZ2dzdGFuY2UpCmxpYnJhcnkocGFuZGVyKQpsaWJyYXJ5KGhlcmUpCgojIExvYWQgZGV0YWlscyBhYm91dCBjb25zdHJhaW50cwpjb25zdHJhaW50cyA8LSByZWFkX3JkcyhoZXJlKCJkYXRhIiwgImRlcml2ZWRfZGF0YSIsICJjb25zdHJhaW50cy5yZHMiKSkKCmNvbnN0cmFpbnRfbGV2ZWxzIDwtIGNvbnN0cmFpbnRzICU+JQogIG11dGF0ZShjb25zdHJhaW50X2NsZWFuID0gZmN0X2lub3JkZXIoY29uc3RyYWludF9jbGVhbikpICU+JQogIG11dGF0ZShsZXZlbHMgPSBtYXAobGV2ZWxzX2NsZWFuLCBuYW1lcykpICU+JQogIHVubmVzdChsZXZlbHMpICU+JQogIG11dGF0ZShsZXZlbHMgPSBmY3RfaW5vcmRlcihsZXZlbHMpKQoKIyBMb2FkIHNpbXVsYXRpb24gZGF0YQojIFRPRE86IFN3aXRjaCBiYWNrIHRvIGZ1bGwgQkxTLnJkcyBhbmQgQkhMLnJkcwpCSEwgPC0gcmVhZF9yZHMoaGVyZSgiZGF0YSIsICJkZXJpdmVkX2RhdGEiLCAiQkhMX3NtYWxsLnJkcyIpKQoKc2ltX3Jlc3VsdHMgPC0gQkhMICU+JQogICMgTWFrZSBuZXcgY29sdW1ucyB3aXRoICJfY29uc3RyYWludCIgc3VmZml4IHRoYXQgc2hvdyBpZiBjb25zdHJhaW50IGlzIFQvRgogICMgaW5zdGVhZCBvZiB1c2luZyB0aGUgbGFiZWwuIGUuZy4gIlNlbGVjdGlvbiIgYmVjb21lcyBUUlVFLCAiTm8gc2VsZWN0aW9uIgogICMgYmVjb21lcyBGQUxTRQogIG11dGF0ZV9hdCh2YXJzKG9uZV9vZihjb25zdHJhaW50cyRjb25zdHJhaW50KSksCiAgICAgICAgICAgIGxpc3QoY29uc3RyYWludCA9IH5hcy5sb2dpY2FsKC1hcy5pbnRlZ2VyKC4pICsgMkwpKSkgJT4lCiAgIyBDb3VudCBob3cgbWFueSBvZiB0aGUgY29uc3RyYWludHMgYXJlIFRSVUUgaW4gZWFjaCByb3cKICBtdXRhdGUobl9jb25zdHJhaW50cyA9IHJlZHVjZShzZWxlY3QoLiwgZW5kc193aXRoKCJfY29uc3RyYWludCIpKSwgYCtgKSkgJT4lCiAgIyBNYWtlIGEgZmFjdG9yIHZlcnNpb24gb2YgdGhlIGNvbnN0cmFpbnQgY291bnQgZm9yIHBsb3R0aW5nCiAgbXV0YXRlKG5fY29uc3RyYWludHNfZiA9IGFzLmZhY3RvcihuX2NvbnN0cmFpbnRzKSkKYGBgCgoKIyBBdmVyYWdlIGZpdG5lc3MgYXMgbnVtYmVyIG9mIGNvbnN0cmFpbnRzIGluY3JlYXNlCgojIyBQb2ludHMKClRoYW5vcyBhcHBhcmVudGx5IHNuYXBwZWQgdGhpcyBwbG90LgoKYGBge3IgcGxvdC1maXRuZXNzLWNvbnN0cmFpbnRzLXBvaW50cywgZmlnLndpZHRoPTYsIGZpZy5oZWlnaHQ9NC41fQpnZ3Bsb3Qoc2ltX3Jlc3VsdHMsIAogICAgICAgYWVzKHggPSBuX2NvbnN0cmFpbnRzX2YsIHkgPSBsYW5kc2NhcGVfZml0bmVzc19saW5rZWQpKSArCiAgZ2VvbV9wb2ludChzaXplID0gMC41LCBhbHBoYSA9IDAuMywgcG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXIoc2VlZCA9IDEyMzQpKSArCiAgc2NhbGVfeV9yZXZlcnNlKCkgKwogIGxhYnMoeCA9ICJOdW1iZXIgb2YgY29uc3RyYWludHMiLAogICAgICAgeSA9ICJMYW5kc2NhcGUgZml0bmVzcywgbGlua2VkIikgKwogIHRoZW1lX2J3KCkKYGBgCgojIyBSaWRnZXMKCmBgYHtyIHBsb3QtZml0bmVzcy1jb25zdHJhaW50cy1yaWRnZXMsIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTQuNSwgbWVzc2FnZT1GQUxTRX0KZ2dwbG90KHNpbV9yZXN1bHRzLCAKICAgICAgIGFlcyh4ID0gbGFuZHNjYXBlX2ZpdG5lc3NfbGlua2VkLCB5ID0gZmN0X3JldihuX2NvbnN0cmFpbnRzX2YpKSkgKwogIGdlb21fZGVuc2l0eV9yaWRnZXMocmVsX21pbl9oZWlnaHQgPSAwLjAwNSkgKwogIHNjYWxlX3hfcmV2ZXJzZSgpICsKICBsYWJzKHggPSAiTGFuZHNjYXBlIGZpdG5lc3MsIGxpbmtlZCIsCiAgICAgICB5ID0gIk51bWJlciBvZiBjb25zdHJhaW50cyIpICsKICB0aGVtZV9idygpCmBgYAoKIyMgVmlvbGlucwoKYGBge3IgcGxvdC1maXRuZXNzLWNvbnN0cmFpbnRzLXZpb2xpbiwgZmlnLndpZHRoPTYsIGZpZy5oZWlnaHQ9NC41fQpnZ3Bsb3Qoc2ltX3Jlc3VsdHMsIGFlcyh4ID0gbl9jb25zdHJhaW50c19mLCB5ID0gbGFuZHNjYXBlX2ZpdG5lc3NfbGlua2VkKSkgKwogIGdlb21fdmlvbGluKHNpemUgPSAwLjI1LCBmaWxsID0gImdyZXk3MCIpICsKICBzdGF0X3N1bW1hcnkoZ2VvbSA9ICJwb2ludCIsIGZ1bi55ID0gIm1lYW4iLAogICAgICAgICAgICAgICBzaXplID0gMiwgcGNoID0gMjEsIGZpbGwgPSAiYmxhY2siLCBjb2xvciA9ICJ3aGl0ZSIpICsKICBzY2FsZV95X3JldmVyc2UoKSArCiAgbGFicyh4ID0gIk51bWJlciBvZiBjb25zdHJhaW50cyIsCiAgICAgICB5ID0gIkxhbmRzY2FwZSBmaXRuZXNzLCBsaW5rZWQiLAogICAgICAgY2FwdGlvbiA9ICJQb2ludCA9IG1lYW4gdmFsdWUiKSArCiAgdGhlbWVfYncoKQpgYGAKCiMjIEJveHBsb3RzCgpgYGB7ciBwbG90LWZpdG5lc3MtY29uc3RyYWludHMtYm94cGxvdCwgZmlnLndpZHRoPTYsIGZpZy5oZWlnaHQ9NC41fQpnZ3Bsb3Qoc2ltX3Jlc3VsdHMsIGFlcyh4ID0gbl9jb25zdHJhaW50c19mLCB5ID0gbGFuZHNjYXBlX2ZpdG5lc3NfbGlua2VkKSkgKwogIGdlb21fYm94cGxvdCgpICsKICBzdGF0X3N1bW1hcnkoZ2VvbSA9ICJwb2ludCIsIGZ1bi55ID0gIm1lYW4iLAogICAgICAgICAgICAgICBzaXplID0gMiwgcGNoID0gMjEsIGZpbGwgPSAiYmxhY2siLCBjb2xvciA9ICJ3aGl0ZSIpICsKICBzY2FsZV95X3JldmVyc2UoKSArCiAgbGFicyh4ID0gIk51bWJlciBvZiBjb25zdHJhaW50cyIsCiAgICAgICB5ID0gIkxhbmRzY2FwZSBmaXRuZXNzLCBsaW5rZWQiLAogICAgICAgY2FwdGlvbiA9ICJQb2ludCA9IG1lYW4gdmFsdWUiKSArCiAgdGhlbWVfYncoKQpgYGAKCgojIENvbnN0cmFpbnQgaW1wb3J0YW5jZQoKSGVyZSB3ZSB1c2UgYSByYW5kb20gZm9yZXN0IHRvIGRldGVybWluZSB2YXJpYWJsZSBpbXBvcnRhbmNlLiBXZSBkb24ndCBuZWVkIHRvIGluY2x1ZGUgYWxsIHRoZSBpbnRlcmFjdGlvbnMgKGUuZy4gYGNyZWF0ZV9uZXR3b3JrICsgc2VsZWN0ICsgY3JlYXRlX25ldHdvcmsgKiBzZWxlY3RgLCBldGMuKSBiZWNhdXNlIFtyYW5kb20gZm9yZXN0cyBpbmhlcmVudGx5IHBpY2sgdGhvc2UgdXBdKGh0dHBzOi8vc3RhdHMuc3RhY2tleGNoYW5nZS5jb20vYS8xNTc2NzQvMzAyNSkuCgpgYGB7ciByZi1ydW4tbW9kZWxzLCBjYWNoZT1UUlVFfQojIFRoaXMgdGFrZXMgYSBjb3VwbGUgbWludXRlcyB0byBydW4KZm9yZXN0X21vZGVsIDwtIAogIHJhbmRvbUZvcmVzdChsYW5kc2NhcGVfZml0bmVzc19saW5rZWQgfgogICAgICAgICAgICAgICAgIGNyZWF0ZV9uZXR3b3JrICsgc2VsZWN0ICsgZGlzcGVyc2UgKyAKICAgICAgICAgICAgICAgICBjb21wZXRlICsgc2VsZWN0Zm9yX2QgKyBjYXRhc3Ryb3BoZSwKICAgICAgICAgICAgICAgZGF0YSA9IHNpbV9yZXN1bHRzKQpgYGAKCkFjY29yZGluZyB0byBbTGl6IERpbnNkYWxlXShodHRwczovL2RpbnNkYWxlbGFiLnNkc3UuZWR1L21ldGFnLnN0YXRzL2NvZGUvcmFuZG9tZm9yZXN0Lmh0bWwpOgoKPiBUaGUgbWVhbiBkZWNyZWFzZSBpbiBHaW5pIGNvZWZmaWNpZW50IGlzIGEgbWVhc3VyZSBvZiBob3cgZWFjaCB2YXJpYWJsZSBjb250cmlidXRlcyB0byB0aGUgaG9tb2dlbmVpdHkgb2YgdGhlIG5vZGVzIGFuZCBsZWF2ZXMgaW4gdGhlIHJlc3VsdGluZyByYW5kb20gZm9yZXN0LiBFYWNoIHRpbWUgYSBwYXJ0aWN1bGFyIHZhcmlhYmxlIGlzIHVzZWQgdG8gc3BsaXQgYSBub2RlLCB0aGUgR2luaSBjb2VmZmljaWVudCBmb3IgdGhlIGNoaWxkIG5vZGVzIGFyZSBjYWxjdWxhdGVkIGFuZCBjb21wYXJlZCB0byB0aGF0IG9mIHRoZSBvcmlnaW5hbCBub2RlLiBUaGUgR2luaSBjb2VmZmljaWVudCBpcyBhIG1lYXN1cmUgb2YgaG9tb2dlbmVpdHkgZnJvbSAwIChob21vZ2VuZW91cykgdG8gMSAoaGV0ZXJvZ2VuZW91cykuIFRoZSBjaGFuZ2VzIGluIEdpbmkgYXJlIHN1bW1lZCBmb3IgZWFjaCB2YXJpYWJsZSBhbmQgbm9ybWFsaXplZCBhdCB0aGUgZW5kIG9mIHRoZSBjYWxjdWxhdGlvbi4gVmFyaWFibGVzIHRoYXQgcmVzdWx0IGluIG5vZGVzIHdpdGggaGlnaGVyIHB1cml0eSBoYXZlIGEgaGlnaGVyIGRlY3JlYXNlIGluIEdpbmkgY29lZmZpY2llbnQuCgpCYXNpY2FsbHksIHRoZSBoaWdoZXIgdGhlIGRlY3JlYXNlIGluIGltcHVyaXR5LCB0aGUgbW9yZSBpbXBvcnRhbnQgdGhlIHZhcmlhYmxlIGluIGV4cGxhaW5pbmcgdGhlIG91dGNvbWUuCgpgYGB7ciBjb25zdHJhaW50LWltcG9ydGFuY2UtdGJsLCByZXN1bHRzPSJhc2lzIn0KY29uc3RyYWludF9pbXBvcnRhbmNlIDwtIGltcG9ydGFuY2UoZm9yZXN0X21vZGVsKSAlPiUgCiAgZGF0YS5mcmFtZSgpICU+JSAKICByb3duYW1lc190b19jb2x1bW4odmFyID0gImNvbnN0cmFpbnQiKSAlPiUgCiAgYXJyYW5nZShkZXNjKEluY05vZGVQdXJpdHkpKSAlPiUgCiAgbXV0YXRlKGNvbnN0cmFpbnQgPSBmY3RfaW5vcmRlcihjb25zdHJhaW50KSkKCmNvbnN0cmFpbnRfaW1wb3J0YW5jZSAlPiUgCiAgbXV0YXRlKGNvbnN0cmFpbnQgPSBwYXN0ZTAoImAiLCBjb25zdHJhaW50LCAiYCIpKSAlPiUgCiAgcGFuZG9jLnRhYmxlKGp1c3RpZnkgPSAibGMiKQpgYGAKCmBgYHtyIGNvbnN0cmFpbnQtaW1wb3J0YW5jZS1wbG90LCBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD00LjV9CmdncGxvdChjb25zdHJhaW50X2ltcG9ydGFuY2UsIAogICAgICAgYWVzKHggPSBJbmNOb2RlUHVyaXR5LCB5ID0gZmN0X3Jldihjb25zdHJhaW50KSkpICsKICBnZW9tX3BvaW50cmFuZ2VoKGFlcyh4bWluID0gMCwgeG1heCA9IEluY05vZGVQdXJpdHkpKSArCiAgbGFicyh4ID0gIk1lYW4gZGVjcmVhc2UgaW4gbm9kZSBpbXB1cml0eSAoR2luaSkiLAogICAgICAgeSA9IE5VTEwpICsKICB0aGVtZV9idygpCmBgYAoKCiMgUG93ZXIgb2YgZGlmZmVyZW50IGNvbWJpbmF0aW9ucyBvZiBjb25zdHJhaW50cwoKVEhJUyBJUyBNQUdJQ0FMLgoKYGBge3IgZmluZC12YWx1ZXMtYXQtYWxsLWNvbWJpbmF0aW9ucywgY2FjaGU9VFJVRSwgd2FybmluZz1GQUxTRX0KIyBDcmVhdGUgY29sdW1ucyBmb3IgZXZlcnkgY29tYmluYXRpb24gb2YgY29uc3RyYWludCBpbiB0aGUgZGF0YSAoZS5nLiBzZWxlY3QgJgojIGRpc3BlcnNlLCBzZWxlY3QgJiBkaXNwZXJzZSAmIGNyZWF0ZV9uZXR3b3JrKSAKIwojIEJ5IHRoZSBpbmltaXRhYmxlIFZpbmNlbnQgQXJlbC1CdW5kb2NrCm1ha2VfY29tYmluYXRpb25zIDwtIGZ1bmN0aW9uKGRmLCBtID0gNSkgewogIGNvbSA8LSBjb2xuYW1lcyhkZilbMjpuY29sKGRmKV0gJT4lCiAgICBjb21ibihtKSAlPiUKICAgIGFzX3RpYmJsZSgpCiAgb3V0IDwtIGNvbSAlPiUKICAgIG1hcCh+IGRmWy5dKSAlPiUKICAgIG1hcCh+IHJvd1N1bXMoLikgPT0gbmNvbCguKSkgJT4lCiAgICBzZXROYW1lcyhtYXAoY29tLCBwYXN0ZSwgY29sbGFwc2UgPSAiICsgIikpICU+JQogICAgYXNfdGliYmxlKCkKICByZXR1cm4ob3V0KQp9CgojIFNlbGVjdCBqdXN0IHRoZSBydW4gbnVtYmVyIGFuZCAqX2NvbnN0cmFpbnQgVFJVRS9GQUxTRSBjb2x1bW5zCmNvbnN0cmFpbnRfY29tYmluYXRpb25zIDwtIHNpbV9yZXN1bHRzICU+JQogIHNlbGVjdChydW5udW0sIGVuZHNfd2l0aCgiX2NvbnN0cmFpbnQiKSkgJT4lIAogICMgU2hyaW5rIG5hbWVzIGJ5IHJlbW92aW5nICJfY29uc3RyYWludCIKICByZW5hbWVfYXQodmFycyhlbmRzX3dpdGgoImNvbnN0cmFpbnQiKSksIAogICAgICAgICAgICBsaXN0KH5zdHJfcmVwbGFjZV9hbGwoLiwgIl9jb25zdHJhaW50IiwgIiIpKSkKCiMgRmluZCBhbGwgY29tYmluYXRpb25zIG9mIHZhcmlhYmxlcyAobSA9IG51bWJlciBvZiBpdGVtcyBpbiBjb21iaW5hdGlvbjsgbSA9IDIKIyBtZWFucyBwYWlycywgbSA9IDMgbWVhbnMgdHJpcGxldHMsIGV0Yy4pCmFsbF9jb25zdHJhaW50X2NvbWJvcyA8LSBtYXAoMjo2LCB+bWFrZV9jb21iaW5hdGlvbnMoY29uc3RyYWludF9jb21iaW5hdGlvbnMsIG0gPSAuKSkgJT4lIAogIGJpbmRfY29scyhjb25zdHJhaW50X2NvbWJpbmF0aW9ucywgLikKCiMgU2VsZWN0IHRoZSBvdXRjb21lIHZhcmlhYmxlcyB3ZSBjYXJlIGFib3V0IChmb3Igbm93IGp1c3QKIyBsYW5kc2NhcGVfZml0bmVzc19saW5rZWQpIGFuZCBqb2luIHRoZSBjb25zdHJhaW50IGNvbWJpbmF0aW9ucwpjb25zdHJhaW50X2NvbWJvX291dGNvbWVzIDwtIHNpbV9yZXN1bHRzICU+JQogIHNlbGVjdChydW5udW0sIG5fY29uc3RyYWludHMsIGxhbmRzY2FwZV9maXRuZXNzX2xpbmtlZCkgJT4lIAogIHJpZ2h0X2pvaW4oYWxsX2NvbnN0cmFpbnRfY29tYm9zLCBieSA9ICJydW5udW0iKQoKIyBEb24ndCBkb3VibGUgY291bnQgcm93cy4gSWYgYSByb3cgaGFzIHR3byBjb25zdHJhaW50cyBsaWtlIHNlbGVjdCBhbmQKIyBkaXNwZXJzZSwgaXQnbGwgYWxzbyBoYXZlIHNlbGVjdCArIGRpc3BlcnNlIHNldCB0byBUUlVFLiBJZiB0aGF0J3MgdGhlIGNhc2UsCiMgd2UgZG9uJ3Qgd2FudCB0byBpbmNsdWRlIGl0IGluIGp1c3Qgc2VsZWN0IG9yIGp1c3QgZGlzcGVyc2UKY29uc3RyYWludF9jb21ib19vdXRjb21lc19uZXN0ZWQgPC0gY29uc3RyYWludF9jb21ib19vdXRjb21lcyAlPiUgCiAgc2VsZWN0KC1uX2NvbnN0cmFpbnRzKSAlPiUgCiAgIyBNYWtlIGxvbmcKICBnYXRoZXIoY29uc3RyYWludF9jb21ibywgdmFsdWUsIC1jKHJ1bm51bSwgbGFuZHNjYXBlX2ZpdG5lc3NfbGlua2VkKSkgJT4lIAogICMgQ291bnQgaG93IG1hbnkgY29uc3RyYWludHMgdGhlcmUgYXJlIHdpdGhpbiBlYWNoIHJvdyBiYXNlZCBvbiArIHNpZ25zCiAgbXV0YXRlKG4gPSBzdHJfY291bnQoY29uc3RyYWludF9jb21ibywgIlxcKyIpICsgMSkgJT4lCiAgIyBPbmx5IGtlZXAgcm93cyB3aGVyZSB0aGUgY29uc3RyYWludCBpcyB0dXJuZWQgb24KICBmaWx0ZXIodmFsdWUgPT0gVFJVRSkgJT4lCiAgIyBOZXN0IGFsbCB0aGUgY29uc3RyYWludCBjb21iaW5hdGlvbnMgd2l0aGluIGVhY2ggcm93CiAgZ3JvdXBfYnkocnVubnVtKSAlPiUgCiAgbmVzdCgpCgojIE9ubHkga2VlcCB0aGUgdmFsdWVzIHdoZXJlIG4gPT0gbWF4KG4pIGZvciB0aGF0IHJvdwpjb25zdHJhaW50X2NvbWJvX291dGNvbWVzX2ZpbHRlcmVkIDwtIGNvbnN0cmFpbnRfY29tYm9fb3V0Y29tZXNfbmVzdGVkICU+JSAKICBtdXRhdGUoZmlsdGVyZWQgPSBkYXRhICU+JSBtYXAofmZpbHRlciguLCBuID09IG1heCguJG4pKSkpICU+JSAKICBzZWxlY3QoLWRhdGEpICU+JSAKICB1bm5lc3QoZmlsdGVyZWQpCgojIFRoaXMgb21pdHRlZCBhbGwgdGhlIHJvd3Mgd2hlcmUgbl9jb25zdHJhaW50cyA9PSAwLCBzbyBhZGQgdGhvc2UgYmFjayBpbgpub19jb25zdHJhaW50cyA8LSBjb25zdHJhaW50X2NvbWJvX291dGNvbWVzICU+JSAKICBmaWx0ZXIobl9jb25zdHJhaW50cyA9PSAwKSAlPiUgCiAgbXV0YXRlKGNvbnN0cmFpbnRfY29tYm8gPSAiTm8gY29uc3RyYWludHMiLCBuID0gMCkgJT4lIAogIHNlbGVjdChydW5udW0sIGxhbmRzY2FwZV9maXRuZXNzX2xpbmtlZCwgY29uc3RyYWludF9jb21ibywgbikKCmNvbnN0cmFpbnRfY29tYm9fb3V0Y29tZXNfZG9uZSA8LSBiaW5kX3Jvd3MoY29uc3RyYWludF9jb21ib19vdXRjb21lc19maWx0ZXJlZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub19jb25zdHJhaW50cykgJT4lIAogIHNlbGVjdCgtdmFsdWUpCmBgYAoKYGBge3IgcGxvdC1maXRuZXNzLWFsbC1jb21ib3MsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTEwfQpuX2NvbnN0cmFpbnRzX2NvbWJvcyA8LSBjb25zdHJhaW50X2NvbWJvX291dGNvbWVzX2RvbmUgJT4lCiAgZ3JvdXBfYnkoY29uc3RyYWludF9jb21ibywgbikgJT4lCiAgc3VtbWFyaXplKGF2ZyA9IG1lYW4obGFuZHNjYXBlX2ZpdG5lc3NfbGlua2VkKSkgJT4lIAogIGFycmFuZ2UoZGVzYyhuKSwgZGVzYyhhdmcpKSAlPiUgCiAgdW5ncm91cCgpICU+JSAKICBtdXRhdGUoY29uc3RyYWludF9jb21ibyA9IGZjdF9pbm9yZGVyKGNvbnN0cmFpbnRfY29tYm8pKQoKZ2dwbG90KG5fY29uc3RyYWludHNfY29tYm9zLAogICAgICAgYWVzKHggPSBhdmcsIHkgPSBjb25zdHJhaW50X2NvbWJvKSkgKwogIGdlb21fcG9pbnRyYW5nZWgoYWVzKHhtaW4gPSAwLCB4bWF4ID0gYXZnKSkgKyAKICBsYWJzKHggPSAiQXZlcmFnZSBsYW5kc2NhcGUgZml0bmVzcywgbGlua2VkIiwKICAgICAgIHkgPSBOVUxMKSArCiAgZmFjZXRfZ3JpZChyb3dzID0gdmFycyhuKSwKICAgICAgICAgICAgIHNjYWxlcyA9ICJmcmVlIiwgc3BhY2UgPSAiZnJlZSIpICsgCiAgdGhlbWVfYncoKQpgYGAK