Import

APA PsycTests

records_wide <- readRDS("../sober_rubric/raw_data/preprocessed_records.rds")

records_wide %>% group_by(Name)  %>% filter(n()>1) %>% ungroup() %>% summarise(n_distinct(Name), n())
## # A tibble: 1 × 2
##   `n_distinct(Name)` `n()`
##                <int> <int>
## 1               1237  3043
records_wide$first_construct <- str_trim(str_replace_all(str_to_lower(records_wide$first_construct), "[:space:]+", " "))

First EBSCO scrape of APA PsycInfo

psycinfo <- read_tsv('../sober_rubric/raw_data/merged_table_all.tsv') %>% 
  # this tsv can be found in "Scraping-EBSCO-Host\data\merged tables"
#  mutate(Name = toTitleCase(Name)) %>% 
  rename(usage_count = "Hit Count") %>% 
  group_by(Name, Year) %>% 
  summarise(usage_count = sum(usage_count))
## Rows: 309223 Columns: 5
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: "\t"
## chr (2): Name, Journal
## dbl (3): Hit Count, Year, number of search results
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
## `summarise()` has grouped output by 'Name'. You can override using the `.groups` argument.

Second EBSCO scrape of APA PsycInfo

overview <- readr::read_tsv("../sober_rubric/raw_data/20230617_ebsco_scrape_clean_overview_table_1.tsv")
## Rows: 71692 Columns: 4
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: "\t"
## chr (1): DOI
## dbl (3): first_pub_year, last_pub_year, Hits
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
byyear <- readr::read_tsv("../sober_rubric/raw_data/20230617_ebsco_scrape_table_years_1.tsv")
## Rows: 218142 Columns: 3
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: "\t"
## chr (1): DOI
## dbl (2): Year, Hits
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
n_distinct(byyear$DOI)
## [1] 31145
overview %>% filter(is.na(Hits)) %>% nrow()
## [1] 40574
nrow(overview)
## [1] 71692
overview %>% filter(Hits >= 1) %>% nrow()
## [1] 31118
one_hit_wonders <- overview %>% filter(Hits == 1) %>% 
  mutate(Year = first_pub_year)

nrow(one_hit_wonders)
## [1] 13280
# for some few, the call was repeated by year for some reason
# one_hit_wonders %>% select(DOI, first_pub_year) %>% inner_join(byyear, by = "DOI") %>% arrange(DOI)

byyear <- byyear %>% anti_join(one_hit_wonders, by = "DOI")

all <- one_hit_wonders %>% 
  select(DOI, Year, Hits) %>% 
  bind_rows(byyear) %>% 
  left_join(overview %>% rename(total_hits = Hits), by = "DOI")

n_distinct(all$DOI)
## [1] 31145
all %>% filter(Hits > 0) %>% filter(Year < first_pub_year | Year > last_pub_year) %>% nrow()
## [1] 0
all %>% group_by(total_hits, DOI) %>% summarise(hits_by_year = sum(Hits, na.rm = T)) %>% filter(hits_by_year > total_hits) %>% ungroup() %>% select(DOI, everything()) %>% mutate(diff = hits_by_year - total_hits) %>% nrow()
## `summarise()` has grouped output by 'total_hits'. You can override using the
## `.groups` argument.
## [1] 0
# all %>% group_by(total_hits, DOI) %>% summarise(hits_by_year = sum(usage_count, na.rm = T)) %>% filter(hits_by_year < total_hits) %>% select(DOI, everything()) %>% mutate(diff = hits_by_year - total_hits) %>%  View()
all %>% group_by(total_hits, DOI) %>% summarise(hits_by_year = sum(Hits, na.rm = T)) %>% filter(hits_by_year == total_hits) %>% nrow()
## `summarise()` has grouped output by 'total_hits'. You can override using the
## `.groups` argument.
## [1] 31118
all %>% group_by(DOI) %>% summarise(hits_by_year = sum(Hits, na.rm = T)) %>% filter(hits_by_year == 0)
## # A tibble: 27 × 2
##    DOI                hits_by_year
##    <chr>                     <dbl>
##  1 10.1037/t00747-000            0
##  2 10.1037/t00875-000            0
##  3 10.1037/t00878-000            0
##  4 10.1037/t00879-000            0
##  5 10.1037/t02477-000            0
##  6 10.1037/t02488-000            0
##  7 10.1037/t04670-000            0
##  8 10.1037/t04771-000            0
##  9 10.1037/t04776-000            0
## 10 10.1037/t04779-000            0
## # ℹ 17 more rows
all %>% group_by(total_hits, DOI) %>% summarise(hits_by_year = sum(Hits, na.rm = T)) %>% filter(is.na(total_hits)) %>% pull(hits_by_year) %>% table()
## `summarise()` has grouped output by 'total_hits'. You can override using the
## `.groups` argument.
## .
##  0 
## 27
psyctests_info <- records_wide %>% 
  select(DOI, TestYear, Name, first_construct, 
         original_test_DOI, original_DOI_combined, 
         test_type, ConstructList, subdiscipline_1, subdiscipline_2, 
         classification_1, classification_2, instrument_type_broad, 
         InstrumentType,
         number_of_factors_subscales, Name_base) %>%
  distinct() %>% 
  inner_join(all, by = c("DOI" = "DOI"), multiple = "all") %>% 
  rename(usage_count = "Hits")


write_rds(psyctests_info, "../sober_rubric/raw_data/psyctests_info.rds")

2016 changes in standards

test_data <- records_wide %>%
  filter(TestYear <= 2022) %>%
    rowwise() %>%
    mutate(Methodology = length(MethodologyList) >0) %>%
    mutate(AdministrationMethod = length(AdministrationMethodList) >0) %>%
    mutate(PopulationGroup = length(PopulationGroupList) >0) %>%
    mutate(AgeGroup = length(AgeGroupList) >0) %>%
    group_by(TestYear) %>%
    summarise(Reliability = mean(Reliability!="No reliability indicated."),
              FactorAnalysis = mean(FactorAnalysis!="No factor analysis indicated."),
              # Unidimensional = mean(FactorAnalysis=="This is a unidimensional measure."),
              FactorsAndSubscales = mean(!is.na(FactorsAndSubscales)),
              Validity = mean(Validity!="No validity indicated."),
              Format = mean(!is.na(Format)),
              # Fee = mean(Fee == "Yes"),
              Methodology = mean(Methodology),
              AdministrationMethod = mean(AdministrationMethod),
              # AgeGroup = mean(AgeGroup),
              # PopulationGroup = mean(PopulationGroup),
              TestItems = mean(TestItemsAvailable == "Yes")) %>%
    pivot_longer(-TestYear)
test_data %>%
  ggplot(aes(TestYear, value, color = name)) +
  geom_vline(xintercept = 2016, linetype = 'dashed') +
  geom_line() +
  scale_x_continuous("Publication year in APA PsycTests",
                     limits = c(1993, 2030),
                     breaks = seq(1993, 2022, by = 1),
                     labels = c(1993, "", "", "", "", 1998, "", "", "", "", 2003, "", "", "", "", 2008, "", "", "", "", 2013, "", "", "", "", 2018, "", "", "", "2022"),
                     expand = expansion(add = c(0, 1.2))) +
  scale_color_brewer(type = "qual", guide = "none", palette = 2) +
  geom_text_repel(
    data = test_data %>% drop_na() %>% group_by(name) %>% filter(TestYear == max(TestYear, na.rm = T)),
    aes(label = name),
    segment.color = 'grey',
    xlim = c(2022, 2033),
    box.padding = 0.1,
    # point.padding = 0.6,
    nudge_x = 1.2,
    # nudge_y = 0,
    force = 0.5,
    hjust = 0,
    direction="y",
    na.rm = TRUE
  ) +
  ylab("PsycTests contains information about...") +
  theme(panel.grid.minor.y = element_blank(),
        panel.grid.minor.x = element_blank(),
        plot.title.position = "plot",
        plot.title = element_text(face="bold"),
        legend.position = "none")
## Warning: Removed 696 rows containing missing values or values outside the scale range
## (`geom_line()`).

ggsave("figures/changed_standards_2016.pdf", width = 8, height = 4)
## Warning: Removed 696 rows containing missing values or values outside the scale range
## (`geom_line()`).
ggsave("figures/changed_standards_2016.png", width = 8, height = 4)
## Warning: Removed 696 rows containing missing values or values outside the scale range
## (`geom_line()`).
records_wide %>% 
  group_by(TestYear) %>% 
  summarise(number_of_test_items = mean(number_of_test_items, na.rm = T)) %>% 
  filter(TestYear >= 1993, TestYear <= 2022) %>% 
ggplot(aes(TestYear, number_of_test_items)) + 
  geom_vline(xintercept = 2016, linetype = 'dashed') +
  geom_line() +
  scale_x_continuous("Publication year in APA PsycTests",
                     limits = c(1993, NA), 
                     breaks = seq(1993, 2022, by = 1),
                     labels = c(1993, "", "", "", "", 1998, "", "", "", "", 2003, "", "", "", "", 2008, "", "", "", "", 2013, "", "", "", "", 2018, "", "", "", "2022")) +
  theme(panel.grid.minor.y = element_blank(),
        panel.grid.minor.x = element_blank(),
        plot.title.position = "plot",
        plot.title = element_text(face="bold"),
        legend.position = "none") +
  xlab("Publication year in APA PsycTests") +
  ylab("Number of items in measure")

records_wide %>% 
  filter(TestYear >= 1993, TestYear <= 2022) %>% 
ggplot(aes(TestYear, number_of_factors_subscales)) + 
  geom_vline(xintercept = 2016, linetype = 'dashed') +
  geom_pointrange(stat = 'summary', fun.data = 'mean_se') +
  xlim(1993, 2022) +
  xlab("Publication year in APA PsycTests") +
  ylab("Number of factors/subscales")
## Warning: Removed 54780 rows containing non-finite outside the scale range
## (`stat_summary()`).

records_wide %>% 
  group_by(InstrumentType, TestYear) %>% 
  summarise(tests = n()) %>% 
  group_by(TestYear) %>% 
  mutate(tests = tests/sum(tests, na.rm = T)) %>% 
  arrange(TestYear) %>% 
  filter(TestYear >= 1993, TestYear <= 2022) %>% 
  # mutate(tests = cumsum(tests)) %>% 
  ggplot(aes(TestYear, tests, color = InstrumentType)) + 
  geom_vline(xintercept = 2016, linetype = 'dashed') +
  scale_color_viridis_d() +
  geom_line() +
  xlim(1993, 2022) +
  xlab("Publication year in APA PsycTests") +
  ylab("Proportion of instrument type")
## `summarise()` has grouped output by 'InstrumentType'. You can override using
## the `.groups` argument.
## Warning: Removed 29 rows containing missing values or values outside the scale range
## (`geom_line()`).

records_wide %>% 
  # filter(instrument_type_broad !=)
  group_by(instrument_type_broad, TestYear) %>% 
  summarise(tests = n()) %>% 
  group_by(TestYear) %>% 
  mutate(tests = tests/sum(tests, na.rm = T)) %>% 
  arrange(TestYear) %>% 
  filter(TestYear >= 1993, TestYear <= 2022) %>% 
  # mutate(tests = cumsum(tests)) %>% 
  ggplot(aes(TestYear, tests, color = instrument_type_broad)) + 
  geom_vline(xintercept = 2016, linetype = 'dashed') +
  geom_line() +
  xlim(1993, 2022) +
  xlab("Publication year in APA PsycTests") +
  ylab("Proportion of instrument type")
## `summarise()` has grouped output by 'instrument_type_broad'. You can override
## using the `.groups` argument.

records_wide %>% 
  filter(instrument_type_broad != "questionnaire") %>% 
  group_by(InstrumentType, TestYear) %>% 
  summarise(tests = n()) %>% 
  group_by(TestYear) %>% 
  mutate(tests = tests/sum(tests, na.rm = T)) %>% 
  arrange(TestYear) %>% 
  filter(TestYear >= 1993, TestYear <= 2022) %>% 
  # mutate(tests = cumsum(tests)) %>% 
  ggplot(aes(TestYear, tests, color = InstrumentType)) + 
  geom_vline(xintercept = 2016, linetype = 'dashed') +
  geom_line() +
  xlim(1993, 2022) +
  xlab("Publication year in APA PsycTests") +
  ylab("Proportion of instrument type") +
  ggtitle("Without questionnaires")
## `summarise()` has grouped output by 'InstrumentType'. You can override using
## the `.groups` argument.

psyctests_info %>% group_by(DOI, TestYear) %>% 
  summarise(used = sum(usage_count, na.rm = T)) %>% 
  full_join(records_wide %>% select(DOI, TestYear)) %>% 
  mutate(used = coalesce(used, 0)) %>% 
  filter(TestYear >= 1993, TestYear <= 2022) %>% 
  group_by(TestYear) %>% 
  summarise(never_reused = mean(used == 0),
            used_once = mean(used == 1),
            used_twice = mean(used == 2),
            used_thrice = mean(used == 3),
            used_more_10 = mean(used > 9)) %>% 
  pivot_longer(-TestYear) %>% 
  ggplot(aes(TestYear, value, color = name)) + 
  geom_vline(xintercept = 2016, linetype = 'dashed') +
  geom_line() +
  xlim(1993, 2022) +
  xlab("Publication year in APA PsycTests") +
  ylab("Frequency")
## `summarise()` has grouped output by 'DOI'. You can override using the `.groups`
## argument.
## Joining with `by = join_by(DOI, TestYear)`

New measures by publication year

count_all <- records_wide %>% 
  group_by(TestYear) %>% 
  summarise(tests = n()) %>% 
  arrange(TestYear)

count_orig <- records_wide %>% 
  filter(test_type == "Original") %>% 
  group_by(TestYear) %>% 
  summarise(tests = n()) %>% 
  arrange(TestYear)

count_base <- records_wide %>% 
  arrange(TestYear) %>% 
  distinct(Name_base, .keep_all = T) %>% 
  group_by(TestYear) %>% 
  summarise(tests = n_distinct(DOI))

count_construct <- records_wide %>% 
  arrange(TestYear) %>% 
  distinct(first_construct, .keep_all = T) %>% 
  group_by(TestYear) %>% 
  summarise(tests = n_distinct(first_construct)) %>% 
  arrange(TestYear)

counts <- bind_rows(
  "novel constructs" = count_construct,
  "novel measures" = count_orig,
  "with translations\n and revisions" = count_all,
  .id = "origin"
  ) %>% 
  rename(Year = TestYear) %>% 
  filter(Year <= 2022)


ggplot(counts, aes(Year, tests, color = origin)) + 
  geom_line() +
  geom_vline(xintercept = 2016, linetype = 'dashed') +
  scale_y_continuous("Number of measures/constructs published") +
  scale_x_continuous("Publication year in APA PsycTests",
                     limits = c(1993, 2030), 
                     breaks = seq(1993, 2022, by = 1),
                     labels = c(1993, "", "", "", "", 1998, "", "", "", "", 2003, "", "", "", "", 2008, "", "", "", "", 2013, "", "", "", "", 2018, "", "", "", "2022")) +
  scale_color_brewer(type = "qual", guide = "none", palette = 2) +
  # ggrepel::geom_text_repel(
  #   aes(label = str_replace(subdiscipline, " Psychology", "")), data = entropy_by_year %>% filter(Year == max(Year, na.rm = T)),
  #   size = 4, hjust = 1,
  #   ) +
  geom_text_repel(data = counts %>% drop_na() %>% group_by(origin) %>% filter(Year == max(Year, na.rm = T)),
                  aes(label = paste0(" ", origin)),
                  segment.curvature = -0.1,
                  segment.square = TRUE,
                  lineheight = .9,
                  # segment.color = 'grey',
                  box.padding = 0.1,
                  point.padding = 0.6,
                  nudge_x = 1.5,
                  nudge_y = -15,
                  force = 1,
                  hjust = 0,
                  direction="y",
                  na.rm = F) +
   theme(panel.grid.minor.y = element_blank(),
        panel.grid.minor.x = element_blank(),
        plot.title.position = "plot",
        plot.title = element_text(face="bold"),
        legend.position = "none")
## Warning: Removed 250 rows containing missing values or values outside the scale range
## (`geom_line()`).

ggsave("figures/counts.pdf", width = 8, height = 4)
## Warning: Removed 250 rows containing missing values or values outside the scale range
## (`geom_line()`).
ggsave("figures/counts.png", width = 8, height = 4)
## Warning: Removed 250 rows containing missing values or values outside the scale range
## (`geom_line()`).

Cumulative number of measures and constructs

cumsum_all <- records_wide %>% 
  group_by(TestYear) %>% 
  summarise(tests = n()) %>% 
  arrange(TestYear) %>% 
  mutate(tests = cumsum(tests)) 

cumsum_orig <- records_wide %>% 
  filter(test_type == "Original") %>% 
  group_by(TestYear) %>% 
  summarise(tests = n()) %>% 
  arrange(TestYear) %>% 
  mutate(tests = cumsum(tests)) 

cumsum_base <- records_wide %>% 
  arrange(TestYear) %>% 
  distinct(Name_base, .keep_all = T) %>% 
  group_by(TestYear) %>% 
  summarise(tests = n_distinct(DOI)) %>% 
  mutate(tests = cumsum(tests)) 

cumsum_construct <- records_wide %>% 
  arrange(TestYear) %>% 
  distinct(first_construct, .keep_all = T) %>% 
  group_by(TestYear) %>% 
  summarise(tests = n_distinct(DOI)) %>% 
  arrange(TestYear) %>% 
  mutate(tests = cumsum(tests)) 

cumsums <- bind_rows(
  "novel constructs" = cumsum_construct,
  "novel measures" = cumsum_orig,
  "with translations\n and revisions" = cumsum_all,
  .id = "origin"
  ) %>% 
  rename(Year = TestYear) %>% 
  filter(Year <= 2022)


ggplot(cumsums, aes(Year, tests, color = origin)) + 
  geom_line() +
  geom_vline(xintercept = 2016, linetype = 'dashed') +
  scale_y_continuous("Cumulative number of measures") +
  scale_x_continuous("Publication year in APA PsycTests",
                     limits = c(1993, 2030), 
                     breaks = seq(1993,2022, by = 1),
                     labels = c(1993, "", "", "", "", 1998, "", "", "", "", 2003, "", "", "", "", 2008, "", "", "", "", 2013, "", "", "", "", 2018, "", "", "", "2022"),
                     expand = expansion(add = c(0, 1))) +
  scale_color_brewer(type = "qual", guide = "none", palette = 2) +
  # ggrepel::geom_text_repel(
  #   aes(label = str_replace(subdiscipline, " Psychology", "")), data = entropy_by_year %>% filter(Year == max(Year, na.rm = T)),
  #   size = 4, hjust = 1,
  #   )  +
  geom_text_repel(data = cumsums %>% drop_na() %>% group_by(origin) %>% filter(Year == max(Year, na.rm = T)),
                  aes(label = paste0(" ", origin, "\n (n = ", tests, ")")),
                  segment.square = TRUE,
                  lineheight = .9,
                  segment.color = 'grey',
                  nudge_x = 1.2,
                  hjust = 0,
                  na.rm = TRUE) +
   # theme_minimal(base_size = 13) +
   theme(panel.grid.minor.y = element_blank(),
        panel.grid.minor.x = element_blank(),
        plot.title.position = "plot",
        plot.title = element_text(face="bold"),
        legend.position = "none")  +
    guides(
    x = guide_axis(cap = "both"), # Cap both ends
  )
## Warning: Removed 250 rows containing missing values or values outside the scale range
## (`geom_line()`).

ggsave("figures/cumsums.pdf", width = 8, height = 4)
## Warning: Removed 250 rows containing missing values or values outside the scale range
## (`geom_line()`).
ggsave("figures/cumsums.png", width = 8, height = 4)
## Warning: Removed 250 rows containing missing values or values outside the scale range
## (`geom_line()`).

By subdiscipline

cumsum_all <- records_wide %>% 
  group_by(subdiscipline_1, TestYear) %>% 
  summarise(tests = n()) %>% 
  arrange(TestYear) %>% 
  mutate(tests = cumsum(tests)) 
## `summarise()` has grouped output by 'subdiscipline_1'. You can override using
## the `.groups` argument.
cumsum_orig <- records_wide %>% 
  filter(test_type == "Original") %>% 
  group_by(subdiscipline_1, TestYear) %>% 
  summarise(tests = n()) %>% 
  arrange(TestYear) %>% 
  mutate(tests = cumsum(tests)) 
## `summarise()` has grouped output by 'subdiscipline_1'. You can override using
## the `.groups` argument.
cumsum_base <- records_wide %>% 
  arrange(TestYear) %>% 
  distinct(Name_base, .keep_all = T) %>% 
  group_by(subdiscipline_1, TestYear) %>% 
  summarise(tests = n_distinct(DOI)) %>% 
  mutate(tests = cumsum(tests)) 
## `summarise()` has grouped output by 'subdiscipline_1'. You can override using
## the `.groups` argument.
cumsum_construct <- records_wide %>% 
  arrange(TestYear) %>% 
  distinct(first_construct, .keep_all = T) %>% 
  group_by(subdiscipline_1, TestYear) %>% 
  summarise(tests = n_distinct(DOI)) %>% 
  arrange(TestYear) %>% 
  mutate(tests = cumsum(tests)) 
## `summarise()` has grouped output by 'subdiscipline_1'. You can override using
## the `.groups` argument.
cumsums <- bind_rows(
  "constructs" = cumsum_construct,
  "measures" = cumsum_orig,
  "with translations & revisions" = cumsum_all,
  .id = "origin"
  ) %>% 
  rename(Year = TestYear) %>% 
  filter(Year <= 2022)

cumsums$origin <- factor(cumsums$origin, levels = c("with translations & revisions", "constructs", "measures"))
my_colors <- c("with translations & revisions" = "#7570B3",
               "constructs" = "#1B9E77", 
               "measures" = "#D95F02") 

ggplot(cumsums, aes(Year, tests, color = origin)) + 
  geom_line() +
  facet_wrap(~ subdiscipline_1, scales = "free_y", ncol = 2) + 
  scale_y_continuous("Cumulative number of measures") +
  scale_x_continuous("Publication year in APA PsycTests",
                     limits = c(1993, 2022), 
                     breaks = seq(1993, 2022, by = 1),
                     labels = c(1993, "", "", "", "", 1998, "", "", "", "", 2003, "", "", "", "", 2008, "", "", "", "", 2013, "", "", "", "", 2018, "", "", "", "2022")) +
  scale_color_manual(values = my_colors, guide = guide_legend(title = NULL)) +
  theme_minimal(base_size = 13) +
  theme(panel.grid.minor.y = element_blank(),
        panel.grid.minor.x = element_blank(),
        plot.title.position = "plot",
        plot.title = element_text(face="bold"),
        legend.position = c(0.58, 0.08),
        legend.justification = c(0, 0),
        legend.box.just = "right",
        legend.text = element_text(size = 11))
## Warning: A numeric `legend.position` argument in `theme()` was deprecated in ggplot2
## 3.5.0.
## ℹ Please use the `legend.position.inside` argument of `theme()` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## Warning: Removed 189 rows containing missing values or values outside the scale range
## (`geom_line()`).

ggsave("figures/cumsums_subdiscipline.pdf", width = 8, height = 7)
## Warning: Removed 189 rows containing missing values or values outside the scale range
## (`geom_line()`).
ggsave("figures/cumsums_subdiscipline.png", width = 8, height = 7)
## Warning: Removed 189 rows containing missing values or values outside the scale range
## (`geom_line()`).

Tests by usage frequency

test_frequency <- psyctests_info %>% 
  mutate(Test = if_else(test_type == "Original", DOI, original_test_DOI)) %>% 
  drop_na(Test) %>% 
  # filter(TestYear >= 1990) %>%
  filter(between(Year, 1993, 2022)) %>%
  group_by(Test) %>% 
  summarise(n = sum(usage_count, na.rm = T)) %>% 
  arrange(n)

test_frequency <- records_wide %>% 
  filter(test_type == "Original", TestYear <= 2022) %>% 
  select(Test = DOI) %>% 
  full_join(test_frequency) %>% 
  mutate(n = coalesce(n, 0.5))
## Joining with `by = join_by(Test)`
test_frequency <- test_frequency %>% 
  group_by(n) %>% 
  summarise(count = n()) %>% 
  ungroup() %>% 
  mutate(percent = count/sum(count))

freq_plot <- ggplot(test_frequency, aes(n, count)) + 
  geom_bar(width = 0.1, fill = colors["novel"], stat = "identity") +
  # facet_wrap(~ subdiscipline_1, scales = "free_y") + 
  # scale_y_sqrt("Number of measures", breaks = c(0, 100, 400, 1000, 2000, 4000, 6000, 10000), limits = c(0, 11500)) +
  scale_y_continuous("Number of measures") +
  scale_x_log10("Usages recorded in APA PsycInfo 1993-2022",
                breaks = c(0.5, 1, 2, 5, 10, 100, 1000, 25000),
               labels = c(0, 1, 2, 5, 10, 100, 1000, 25000)) +
  
  geom_text(aes(label = if_else(n <= 2, sprintf("%.0f%%", percent*100), ""),
                x = n, y = count + 700)) +

  # scale_x_sqrt(breaks = c(0, 1, 2, 3, 4, 5, 10, 20, 40, 50), labels = c(0, 1, 2, 3, 4, 5, 10, 20, 40, "50+")) +
  # geom_text_repel(aes(x = n, label = first_acronym, y = y), 
  #                 data =
  #                   test_frequency %>% group_by(subdiscipline_1) %>% filter(row_number() > (n() - 10) ) %>% left_join(records_wide %>% select(Test = DOI, first_acronym)) %>% 
  #                   mutate(first_acronym = if_else(first_acronym == "HRSD", "HAM-D",
  #                                                  first_acronym)) %>% 
    # mutate(y = 20 + 50*(1+n()-row_number())),
    #               size = 3.3, force = 5, force_pull   = 0, max.time = 1, 
    #               max.overlaps = Inf,
    #               segment.color = "lightgray",
    #               segment.curvature = 1,
    #               hjust = 1,
    #               nudge_y = 10,
    #               direction = "y"
    # ) +
  theme_minimal(base_size = 13) +
  theme(panel.grid.minor.y = element_blank(),
        panel.grid.minor.x = element_blank(),
        plot.title.position = "plot",
        plot.title = element_text(face="bold"),
        legend.position = "none")
freq_plot
## Warning: `position_stack()` requires non-overlapping x intervals.

ggsave("figures/frequency_across.pdf", width = 8, height = 4)
## Warning: `position_stack()` requires non-overlapping x intervals.
ggsave("figures/frequency_across.png", width = 8, height = 4)
## Warning: `position_stack()` requires non-overlapping x intervals.
test_frequency <- test_frequency %>% 
  filter(n >= 1) %>% 
  mutate(percent = count/sum(count))

freq_plot <- ggplot(test_frequency, aes(n, count)) + 
  geom_bar(width = 0.1, fill = colors["novel"], stat = "identity") +
  # scale_y_sqrt("Number of measures", breaks = c(0, 100, 400, 1000, 2000, 4000, 6000, 10000), limits = c(0, 11500)) +
  scale_y_continuous("Number of measures") +
  scale_x_log10("Usages recorded in APA PsycInfo 1993-2022",
                breaks = c(1, 2, 5, 10, 100, 1000, 25000),
               labels = c(1, 2, 5, 10, 100, 1000, 25000)) +
  
  geom_text(aes(label = if_else(n <= 2, sprintf("%.0f%%", percent*100), ""),
                x = n, y = count + 700)) +

  # scale_x_sqrt(breaks = c(0, 1, 2, 3, 4, 5, 10, 20, 40, 50), labels = c(0, 1, 2, 3, 4, 5, 10, 20, 40, "50+")) +
  # geom_text_repel(aes(x = n, label = first_acronym, y = y), 
  #                 data =
  #                   test_frequency %>% group_by(subdiscipline_1) %>% filter(row_number() > (n() - 10) ) %>% left_join(records_wide %>% select(Test = DOI, first_acronym)) %>% 
  #                   mutate(first_acronym = if_else(first_acronym == "HRSD", "HAM-D",
  #                                                  first_acronym)) %>% 
    # mutate(y = 20 + 50*(1+n()-row_number())),
    #               size = 3.3, force = 5, force_pull   = 0, max.time = 1, 
    #               max.overlaps = Inf,
    #               segment.color = "lightgray",
    #               segment.curvature = 1,
    #               hjust = 1,
    #               nudge_y = 10,
    #               direction = "y"
    # ) +
  theme_minimal(base_size = 13) +
  theme(panel.grid.minor.y = element_blank(),
        panel.grid.minor.x = element_blank(),
        plot.title.position = "plot",
        plot.title = element_text(face="bold"),
        legend.position = "none")
freq_plot
## Warning: `position_stack()` requires non-overlapping x intervals.

ggsave("figures/frequency_across_no0.pdf", width = 8, height = 4)
## Warning: `position_stack()` requires non-overlapping x intervals.
ggsave("figures/frequency_across_no0.png", width = 8, height = 4)
## Warning: `position_stack()` requires non-overlapping x intervals.
test_frequency <- psyctests_info %>% 
  mutate(Test = if_else(test_type == "Original", DOI, original_test_DOI)) %>% 
  drop_na(Test) %>% 
  # filter(TestYear >= 1990) %>%
  filter(between(Year, 1993, 2022)) %>%
  group_by(subdiscipline_1, Test) %>% 
  summarise(n = sum(usage_count, na.rm = T)) %>% 
  arrange(n)
## `summarise()` has grouped output by 'subdiscipline_1'. You can override using
## the `.groups` argument.
test_frequency <- records_wide %>% 
  filter(test_type == "Original", TestYear <= 2022) %>% 
  select(subdiscipline_1, Test = DOI) %>% 
  full_join(test_frequency) %>% 
  mutate(n = coalesce(n, 0.5))
## Joining with `by = join_by(subdiscipline_1, Test)`
test_frequency <- test_frequency %>% 
  # mutate(n = if_else(n >= 1000, 1000, n)) %>% 
  mutate(subdiscipline_1 = str_replace(subdiscipline_1, " Psychology", "")) %>% 
  group_by(subdiscipline_1, n) %>% 
  summarise(count = n()) %>% 
  group_by(subdiscipline_1) %>% 
  mutate(percent = count/sum(count))
## `summarise()` has grouped output by 'subdiscipline_1'. You can override using
## the `.groups` argument.
freq_plot <- ggplot(test_frequency, aes(n, count)) + 
  geom_bar(width = 0.1, fill = colors["novel"], stat = "identity") +
  facet_wrap(~ subdiscipline_1, scales = "free_y") + 
  # scale_y_sqrt("Number of measures", breaks = c(0, 100, 400, 1000, 2000, 4000, 6000, 10000), limits = c(0, 11500)) +
  scale_y_continuous("Number of measures", expand = expansion(c(0, 0.1))) +
  scale_x_log10("Usages recorded in APA PsycInfo 1993-2022",
                breaks = c(0.5, 1, 2, 10, 100, 1000, 25000),
               labels = c(0, 1, 2, 10, 100, 1000, 25000)) +
  
  geom_text(aes(label = if_else(n <= 2, sprintf("%.0f%%", percent*100), ""),
                x = n, y = count ), size = 3, vjust = -0.4, hjust = 0.4) +

  # scale_x_sqrt(breaks = c(0, 1, 2, 3, 4, 5, 10, 20, 40, 50), labels = c(0, 1, 2, 3, 4, 5, 10, 20, 40, "50+")) +
  # geom_text_repel(aes(x = n, label = first_acronym, y = y), 
  #                 data =
  #                   test_frequency %>% group_by(subdiscipline_1) %>% filter(row_number() > (n() - 10) ) %>% left_join(records_wide %>% select(Test = DOI, first_acronym)) %>% 
  #                   mutate(first_acronym = if_else(first_acronym == "HRSD", "HAM-D",
  #                                                  first_acronym)) %>% 
    # mutate(y = 20 + 50*(1+n()-row_number())),
    #               size = 3.3, force = 5, force_pull   = 0, max.time = 1, 
    #               max.overlaps = Inf,
    #               segment.color = "lightgray",
    #               segment.curvature = 1,
    #               hjust = 1,
    #               nudge_y = 10,
    #               direction = "y"
    # ) +
  theme(panel.grid.minor.y = element_blank(),
        panel.grid.minor.x = element_blank(),
        plot.title.position = "plot",
        plot.title = element_text(face="bold"),
        legend.position = "none")

freq_plot
## Warning: `position_stack()` requires non-overlapping x intervals.
## `position_stack()` requires non-overlapping x intervals.
## `position_stack()` requires non-overlapping x intervals.
## `position_stack()` requires non-overlapping x intervals.
## `position_stack()` requires non-overlapping x intervals.

ggsave("figures/frequency.pdf", width = 8, height = 4)
## Warning: `position_stack()` requires non-overlapping x intervals.
## `position_stack()` requires non-overlapping x intervals.
## `position_stack()` requires non-overlapping x intervals.
## `position_stack()` requires non-overlapping x intervals.
## `position_stack()` requires non-overlapping x intervals.
ggsave("figures/frequency.png", width = 8, height = 4)
## Warning: `position_stack()` requires non-overlapping x intervals.
## `position_stack()` requires non-overlapping x intervals.
## `position_stack()` requires non-overlapping x intervals.
## `position_stack()` requires non-overlapping x intervals.
## `position_stack()` requires non-overlapping x intervals.
test_frequency <- test_frequency %>% 
  filter(n >= 1) %>% 
  group_by(subdiscipline_1) %>% 
  mutate(percent = count/sum(count))

freq_plot <- ggplot(test_frequency, aes(n, count)) + 
  geom_bar(width = 0.1, fill = colors["novel"], stat = "identity") +
  facet_wrap(~ subdiscipline_1, scales = "free_y") + 
  # scale_y_sqrt("Number of measures", breaks = c(0, 100, 400, 1000, 2000, 4000, 6000, 10000), limits = c(0, 11500)) +
    scale_y_continuous("Number of measures", expand = expansion(c(0, 0.1))) +
  scale_x_log10("Usages recorded in APA PsycInfo 1993-2022",
                breaks = c(1, 2, 5, 10, 100, 1000, 25000),
               labels = c(1, 2, 5, 10, 100, 1000, 25000)) +
  
  geom_text(aes(label = if_else(n <= 2, sprintf("%.0f%%", percent*100), ""),
                x = n, y = count ), size = 3, vjust = -0.11, hjust = 0.4) +

  # scale_x_sqrt(breaks = c(0, 1, 2, 3, 4, 5, 10, 20, 40, 50), labels = c(0, 1, 2, 3, 4, 5, 10, 20, 40, "50+")) +
  # geom_text_repel(aes(x = n, label = first_acronym, y = y), 
  #                 data =
  #                   test_frequency %>% group_by(subdiscipline_1) %>% filter(row_number() > (n() - 10) ) %>% left_join(records_wide %>% select(Test = DOI, first_acronym)) %>% 
  #                   mutate(first_acronym = if_else(first_acronym == "HRSD", "HAM-D",
  #                                                  first_acronym)) %>% 
    # mutate(y = 20 + 50*(1+n()-row_number())),
    #               size = 3.3, force = 5, force_pull   = 0, max.time = 1, 
    #               max.overlaps = Inf,
    #               segment.color = "lightgray",
    #               segment.curvature = 1,
    #               hjust = 1,
    #               nudge_y = 10,
    #               direction = "y"
    # ) +
  theme(panel.grid.minor.y = element_blank(),
        panel.grid.minor.x = element_blank(),
        plot.title.position = "plot",
        plot.title = element_text(face="bold"),
        legend.position = "none")
freq_plot
## Warning: `position_stack()` requires non-overlapping x intervals.
## `position_stack()` requires non-overlapping x intervals.
## `position_stack()` requires non-overlapping x intervals.
## `position_stack()` requires non-overlapping x intervals.
## `position_stack()` requires non-overlapping x intervals.

ggsave("figures/frequency_no0.pdf", width = 8, height = 4)
## Warning: `position_stack()` requires non-overlapping x intervals.
## `position_stack()` requires non-overlapping x intervals.
## `position_stack()` requires non-overlapping x intervals.
## `position_stack()` requires non-overlapping x intervals.
## `position_stack()` requires non-overlapping x intervals.

By instrument type

usage_by_year_instrument_type <- psyctests_info %>% 
  filter(between(Year, 1993, 2022)) %>% 
  group_by(instrument_type_broad, Year, Test = DOI) %>% 
  summarise(n = sum(usage_count, na.rm = T)) %>% 
  group_by(instrument_type_broad) %>% 
  mutate(n_tests = n_distinct(Test)) %>% 
  group_by(instrument_type_broad, n_tests, Year) %>% 
  summarise(n = sum(n),
            diff_tests = n()) %>% 
  ungroup()
## `summarise()` has grouped output by 'instrument_type_broad', 'Year'. You can
## override using the `.groups` argument.
## `summarise()` has grouped output by 'instrument_type_broad', 'n_tests'. You can
## override using the `.groups` argument.
usage_by_year_instrument_type %>% 
  ggplot(., aes(Year, n, color = instrument_type_broad)) +
  geom_line(size = 0.7) +
  scale_y_continuous("Times tests were coded in PsycInfo") +
  scale_x_continuous(limits = c(1993, 2030), breaks = c(1993, 1998, 2003, 2008, 2013, 2018, 2022)) +
  scale_color_brewer(type = "qual", guide = "none", palette = 2) +
  # ggrepel::geom_text_repel(
  #   aes(label = str_replace(subdiscipline, " Psychology", "")), data = entropy_by_year %>% filter(Year == max(Year, na.rm = T)),
  #   size = 4, hjust = 1,
  #   ) + 
  geom_text_repel(aes(label = gsub("^.*$", " ", instrument_type_broad)), # This will force the correct position of the link's right end.
                  data = usage_by_year_instrument_type %>% filter(Year == max(Year, na.rm = T)),
                  segment.curvature = -0.1,
                  segment.square = TRUE,
                  segment.color = 'grey',
                  box.padding = 0.1,
                  point.padding = 0.6,
                  nudge_x = 0.15,
                  nudge_y = 0.05,
                  force = 0.5,
                  hjust = 0,
                  direction="y",
                  na.rm = TRUE
  ) +
  geom_text_repel(data = usage_by_year_instrument_type %>% filter(Year == max(Year, na.rm = T)),
                  aes(label = paste0("  ",str_replace(instrument_type_broad, " Psychology", ""), " (n=", n_tests, ")")),
                  segment.alpha = 0, ## This will 'hide' the link
                  segment.curvature = -0.1,
                  segment.square = TRUE,
                  # segment.color = 'grey',
                  box.padding = 0.1,
                  point.padding = 0.6,
                  nudge_x = 0.15,
                  nudge_y = 0.05,
                  force = 0.5,
                  hjust = 0,
                  direction="y",
                  na.rm = TRUE)+
  theme_minimal(base_size = 13) +
   theme(panel.grid.minor.y = element_blank(),
        panel.grid.minor.x = element_blank(),
        plot.title.position = "plot",
        plot.title = element_text(face="bold"),
        legend.position = "none")
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## Warning: Removed 30 rows containing missing values or values outside the scale range
## (`geom_line()`).

ggsave("figures/usage_by_year_instrument_type.pdf", width = 10, height = 4)
## Warning: Removed 30 rows containing missing values or values outside the scale range
## (`geom_line()`).
ggsave("figures/usage_by_year_instrument_type.png", width = 10, height = 4)
## Warning: Removed 30 rows containing missing values or values outside the scale range
## (`geom_line()`).
usage_by_year_instrument_type <- psyctests_info %>% 
  filter(between(Year, 1993, 2022)) %>% 
  group_by(InstrumentType, Year, Test = DOI) %>% 
  summarise(n = sum(usage_count, na.rm = T)) %>% 
  group_by(InstrumentType) %>% 
  mutate(n_tests = n_distinct(Test)) %>% 
  group_by(InstrumentType, n_tests, Year) %>% 
  summarise(n = sum(n),
            diff_tests = n()) %>% 
  ungroup()
## `summarise()` has grouped output by 'InstrumentType', 'Year'. You can override
## using the `.groups` argument.
## `summarise()` has grouped output by 'InstrumentType', 'n_tests'. You can
## override using the `.groups` argument.
usage_by_year_instrument_type %>% 
  ggplot(., aes(Year, n, color = InstrumentType)) +
  geom_line(size = 0.7) +
  scale_y_continuous("Times tests were coded in PsycInfo") +
  scale_x_continuous(limits = c(1993, 2035), breaks = c(1993, 1998, 2003, 2008, 2013, 2018, 2022)) +
  scale_color_discrete() +
  # ggrepel::geom_text_repel(
  #   aes(label = str_replace(subdiscipline, " Psychology", "")), data = entropy_by_year %>% filter(Year == max(Year, na.rm = T)),
  #   size = 4, hjust = 1,
  #   ) + 
  geom_text_repel(aes(label = gsub("^.*$", " ", InstrumentType)), # This will force the correct position of the link's right end.
                  data = usage_by_year_instrument_type %>% filter(Year == max(Year, na.rm = T)),
                  segment.curvature = -0.1,
                  segment.square = TRUE,
                  segment.color = 'grey',
                  box.padding = 0.1,
                  point.padding = 0.6,
                  nudge_x = 0.15,
                  nudge_y = 0.05,
                  force = 0.5,
                  hjust = 0,
                  direction="y",
                  na.rm = TRUE
  ) +
  geom_text_repel(data = usage_by_year_instrument_type %>% filter(Year == max(Year, na.rm = T)),
                  aes(label = paste0("  ",str_replace(InstrumentType, " Psychology", ""), " (n=", n_tests, ")")),
                  segment.alpha = 0, ## This will 'hide' the link
                  segment.curvature = -0.1,
                  segment.square = TRUE,
                  # segment.color = 'grey',
                  box.padding = 0.1,
                  point.padding = 0.6,
                  nudge_x = 0.15,
                  nudge_y = 0.05,
                  force = 0.5,
                  hjust = 0,
                  direction="y",
                  na.rm = TRUE)+
  theme_minimal(base_size = 13) +
   theme(panel.grid.minor.y = element_blank(),
        panel.grid.minor.x = element_blank(),
        plot.title.position = "plot",
        plot.title = element_text(face="bold"),
        legend.position = "none")
## Warning: ggrepel: 11 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps
## Warning: ggrepel: 12 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps

ggsave("figures/usage_by_year_instrument_type_narrow.pdf", width = 14, height = 10)
## Warning: ggrepel: 7 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps
## Warning: ggrepel: 9 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps
ggsave("figures/usage_by_year_instrument_type_narrow.png", width = 14, height = 10)
## Warning: ggrepel: 7 unlabeled data points (too many overlaps). Consider increasing max.overlaps
## ggrepel: 9 unlabeled data points (too many overlaps). Consider increasing max.overlaps

Entropy

Entropy by year

byorig_entropy_by_year <- psyctests_info %>% 
  filter(between(Year, 1993, 2022)) %>% 
  mutate(Test = if_else(test_type == "Original", DOI, original_test_DOI)) %>% 
  drop_na(Test) %>% 
  group_by(Year, Test) %>% 
  summarise(n = sum(usage_count, na.rm = T)) %>% 
  ungroup() %>% 
  mutate(n_tests = n_distinct(Test)) %>% 
  group_by(n_tests, Year) %>% 
  filter(n > 0) %>% 
  summarise(entropy = entropy(n),
            norm_entropy = calc_norm_entropy(n),
            n = sum(n),
            diff_tests = n()) %>% 
  ungroup()
## `summarise()` has grouped output by 'Year'. You can override using the
## `.groups` argument.
## `summarise()` has grouped output by 'n_tests'. You can override using the
## `.groups` argument.
# what's the point of mutate(n_tests = n_distinct(Test))? just to check?


byconstruct_entropy_by_year <- psyctests_info %>% 
  filter(between(Year, 1993, 2022)) %>% 
  drop_na(first_construct) %>% 
  group_by(Year, Test = first_construct) %>% 
  summarise(n = sum(usage_count, na.rm = T)) %>% 
  ungroup() %>% 
  mutate(n_tests = n_distinct(Test)) %>% 
  group_by(n_tests, Year) %>% 
  filter(n > 0) %>% 
  summarise(entropy = entropy(n),,
            norm_entropy = calc_norm_entropy(n),
            n = sum(n),
            diff_tests = n()) %>% 
  ungroup()
## `summarise()` has grouped output by 'Year'. You can override using the
## `.groups` argument.
## `summarise()` has grouped output by 'n_tests'. You can override using the
## `.groups` argument.
all_entropy_by_year <- psyctests_info %>% 
  filter(between(Year, 1993, 2022)) %>% 
  drop_na(DOI) %>% 
  group_by(Year, Test = DOI) %>% 
  summarise(n = sum(usage_count, na.rm = T)) %>% 
  ungroup() %>% 
  mutate(n_tests = n_distinct(Test)) %>% 
  group_by(n_tests, Year) %>% 
  filter(n > 0) %>% 
  summarise(entropy = entropy(n),,
            norm_entropy = calc_norm_entropy(n),
            n = sum(n),
            diff_tests = n()) %>% 
  ungroup()
## `summarise()` has grouped output by 'Year'. You can override using the
## `.groups` argument.
## `summarise()` has grouped output by 'n_tests'. You can override using the
## `.groups` argument.
original_entropy_by_year <- psyctests_info %>% 
  filter(between(Year, 1993, 2022)) %>% 
  filter(test_type == "Original") %>% 
  group_by(Year, Test = DOI) %>% 
  summarise(n = sum(usage_count, na.rm = T)) %>% 
  ungroup() %>% 
  mutate(n_tests = n_distinct(Test)) %>% 
  group_by(n_tests, Year) %>% 
  filter(n > 0) %>% 
  summarise(entropy = entropy(n),,
            norm_entropy = calc_norm_entropy(n),
            n = sum(n),
            diff_tests = n()) %>% 
  ungroup()
## `summarise()` has grouped output by 'Year'. You can override using the
## `.groups` argument.
## `summarise()` has grouped output by 'n_tests'. You can override using the
## `.groups` argument.
entropy_by_year <- bind_rows(# "all tests" = all_entropy_by_year,
                             "measures" = original_entropy_by_year,
                             "with translations\n and revisions" = byorig_entropy_by_year,
                             # "by name base" = bybase_entropy_by_year,
                             "constructs" = byconstruct_entropy_by_year,
                             .id = "version")


entropy_by_year %>% 
  ggplot(., aes(Year, norm_entropy, color = version)) +
  geom_line(size = 0.7) +
  scale_y_continuous("Normalized Shannon Entropy", limits = c(0, 1), labels = scales::percent) +
  # geom_line(aes(y = log(n)), color = 'red') +
  scale_x_continuous("Usage year as coded in APA PsycInfo", limits = c(1993, 2030), 
                     breaks = seq(1993, 2022, by = 1),
                     labels = c(1993, "", "", "", "", 1998, "", "", "", "", 2003, "", "", "", "", 2008, "", "", "", "", 2013, "", "", "", "", 2018, "", "", "", "2022")) +
  scale_color_brewer(type = "qual", guide = "none", palette = 2) +
  geom_vline(xintercept = 2016, linetype = 'dashed') +
  # ggrepel::geom_text_repel(
  #   aes(label = str_replace(subdiscipline, " Psychology", "")), data = entropy_by_year %>% filter(Year == max(Year, na.rm = T)),
  #   size = 4, hjust = 1,
  #   ) + 
  geom_text_repel(data = entropy_by_year %>% drop_na() %>% group_by(version) %>% filter(Year == max(Year, na.rm = T)),
                  aes(label = paste0(" ",version)), # "\n (n = ", n_tests, ")"
                  segment.curvature = -0.5,
                  segment.square = TRUE,
                  segment.color = 'grey', 
                  xlim = c(2023, 2030),
                  nudge_x = 1.14,
                  lineheight = .9,
                  hjust = 0,
                  direction="y",
                  na.rm = TRUE) +
  theme_minimal(base_size = 13) +
   theme(
        panel.grid.minor.y = element_blank(),
        panel.grid.minor.x = element_blank(),
        plot.title.position = "plot",
        plot.title = element_text(face="bold"),
        legend.position = "none")

ggsave("figures/entropy.pdf", width = 8, height = 4)
ggsave("figures/entropy.png", width = 8, height = 4)

by subdiscipline

all measures

entropy_by_year <- psyctests_info %>% 
  filter(between(Year, 1993, 2022)) %>% 
  group_by(subdiscipline_1, Year, Test = DOI) %>% 
  summarise(n = sum(usage_count, na.rm = T)) %>% 
  group_by(subdiscipline_1) %>% 
  mutate(n_tests = n_distinct(Test)) %>% 
  group_by(subdiscipline_1, n_tests, Year) %>% 
  filter(n > 0) %>% 
  summarise(entropy = entropy(n),,
            norm_entropy = calc_norm_entropy(n),
            n = sum(n),
            diff_tests = n()) %>% 
  ungroup()
## `summarise()` has grouped output by 'subdiscipline_1', 'Year'. You can override
## using the `.groups` argument.
## `summarise()` has grouped output by 'subdiscipline_1', 'n_tests'. You can
## override using the `.groups` argument.
entropy_by_year %>% 
  ggplot(., aes(Year, norm_entropy, color = subdiscipline_1)) +
  geom_line(size = 0.7) +
  scale_y_continuous("Normalized Shannon Entropy\n(with revisions and translations)", limits = c(0, 1), labels = scales::percent) +
  # geom_line(aes(y = log(n)), color = 'red') +
  scale_x_continuous("Usage year as coded in APA PsycInfo", limits = c(1993, 2033), 
                     breaks = seq(1993,2022, by = 1),
                     labels = c(1993, "", "", "", "", 1998, "", "", "", "", 2003, "", "", "", "", 2008, "", "", "", "", 2013, "", "", "", "", 2018, "", "", "", "2022"),
                     expand = expansion(add = c(0, 14))) +
  scale_color_brewer(type = "qual", guide = "none", palette = 2) +
  # ggtitle(str_c(n_distinct(tests_by_year$Test), " measures tracked in PsycInfo")) +
 # geom_text_repel(aes(label = gsub("^.*$", " ", subdiscipline_1)), # This will force the correct position of the link's right end.
 #                  data = entropy_by_year %>% drop_na() %>% group_by(subdiscipline_1) %>% filter(Year == max(Year, na.rm = T)),
 #                  segment.curvature = -0.1,
 #                  segment.square = TRUE,
 #                  segment.color = 'grey',
 #                  box.padding = 0.1,
 #                  point.padding = 0.6,
 #                  max.overlaps = Inf,
 #                  nudge_x = 1.3,
 #                  # nudge_y = 0,
 #                  force = 20,
 #                  hjust = 0,
 #                  direction="y",
 #                  na.rm = TRUE
 #  ) +  
  geom_text_repel(data = entropy_by_year %>% drop_na() %>% group_by(subdiscipline_1) %>% filter(Year == max(Year, na.rm = T)),
                  aes(label = paste0("  ",str_replace(subdiscipline_1, " Psychology", ""), " (n=", n_tests, ")")),
                  # segment.alpha = 0, ## This will 'hide' the link
                  segment.curvature = -0.1,
                  segment.square = TRUE,
                  segment.color = 'grey',
                  box.padding = 0.1,
                  max.overlaps = Inf,
                  point.padding = 0.6,
                  xlim = c(2022, NA),
                  nudge_x = 2,
                  # nudge_y = 0.0,
                  force = 5,
                  hjust = 0,
                  direction="y",
                  na.rm = F) +
  theme_minimal(base_size = 13) +
   theme(panel.grid.minor.y = element_blank(),
        panel.grid.minor.x = element_blank(),
        plot.title.position = "plot",
        plot.title = element_text(face="bold"),
        legend.position = "none") +
    coord_cartesian(clip = "off")

ggsave("figures/entropy_subdiscipline_all.pdf", width = 8, height = 4)
ggsave("figures/entropy_subdiscipline_all.png", width = 8, height = 4)

original measures

entropy_by_year <- psyctests_info %>% 
  filter(between(Year, 1993, 2022)) %>% 
  mutate(Test = if_else(test_type == "Original", DOI, original_test_DOI)) %>% 
  drop_na(Test) %>% 
  group_by(subdiscipline_1, Year, Test) %>% 
  summarise(n = sum(usage_count, na.rm = T)) %>% 
  group_by(subdiscipline_1) %>% 
  mutate(n_tests = n_distinct(Test)) %>% 
  group_by(subdiscipline_1, n_tests, Year) %>% 
  filter(n > 0) %>% 
  summarise(entropy = entropy(n),,
            norm_entropy = calc_norm_entropy(n),
            n = sum(n),
            diff_tests = n()) %>% 
  ungroup()
## `summarise()` has grouped output by 'subdiscipline_1', 'Year'. You can override
## using the `.groups` argument.
## `summarise()` has grouped output by 'subdiscipline_1', 'n_tests'. You can
## override using the `.groups` argument.
entropy_by_year %>% 
  ggplot(., aes(Year, norm_entropy, color = subdiscipline_1)) +
  geom_line(size = 0.7) +
  scale_y_continuous("Normalized Shannon Entropy\n(novel measures)", limits = c(0, 1), labels = scales::percent) +
  # geom_line(aes(y = log(n)), color = 'red') +
  scale_x_continuous("Usage year as coded in APA PsycInfo", limits = c(1993, 2030), 
                     breaks = seq(1993, 2022, by = 1),
                     labels = c(1993, "", "", "", "", 1998, "", "", "", "", 2003, "", "", "", "", 2008, "", "", "", "", 2013, "", "", "", "", 2018, "", "", "", "2022"),
                     expand = expansion(add = c(0, 17))) +
  scale_color_brewer(type = "qual", guide = "none", palette = 2) +
  # ggtitle(str_c(n_distinct(tests_by_year$Test), " measures tracked in PsycInfo")) +
 # geom_text_repel(aes(label = gsub("^.*$", " ", subdiscipline_1)), # This will force the correct position of the link's right end.
 #                  data = entropy_by_year %>% drop_na() %>% group_by(subdiscipline_1) %>% filter(Year == max(Year, na.rm = T)),
 #                  segment.curvature = -0.1,
 #                  segment.square = TRUE,
 #                  segment.color = 'grey',
 #                  box.padding = 0.1,
 #                  point.padding = 0.6,
 #                  max.overlaps = Inf,
 #                  nudge_x = 1.3,
 #                  # nudge_y = 0,
 #                  force = 20,
 #                  hjust = 0,
 #                  direction="y",
 #                  na.rm = TRUE
 #  ) +  
  geom_text_repel(data = entropy_by_year %>% drop_na() %>% group_by(subdiscipline_1) %>% filter(Year == max(Year, na.rm = T)),
                  aes(label = paste0("  ",str_replace(subdiscipline_1, " Psychology", ""), " (n=", n_tests, ")")),
                  # segment.alpha = 0, ## This will 'hide' the link
                  segment.curvature = -0.1,
                  segment.square = TRUE,
                  segment.color = 'grey',
                  box.padding = 0.1,
                  max.overlaps = Inf,
                  point.padding = 0.6,
                  xlim = c(2022, NA),
                  nudge_x = 2,
                  # nudge_y = 0.0,
                  force = 5,
                  hjust = 0,
                  direction="y",
                  na.rm = F)  +
   theme(panel.grid.minor.y = element_blank(),
        panel.grid.minor.x = element_blank(),
        plot.title.position = "plot",
        plot.title = element_text(face="bold"),
        legend.position = "none") +
    coord_cartesian(clip = "off")

ggsave("figures/entropy_subdiscipline_orig.pdf", width = 8, height = 4)
ggsave("figures/entropy_subdiscipline_orig.png", width = 8, height = 4)

constructs

entropy_by_year <- psyctests_info %>% 
  filter(between(Year, 1993, 2022)) %>% 
  group_by(subdiscipline_1, Year, Test = first_construct) %>% 
  summarise(n = sum(usage_count, na.rm = T)) %>% 
  group_by(subdiscipline_1) %>% 
  mutate(n_tests = n_distinct(Test)) %>% 
  group_by(subdiscipline_1, n_tests, Year) %>% 
  filter(n > 0) %>% 
  summarise(entropy = entropy(n),,
            norm_entropy = calc_norm_entropy(n),
            n = sum(n),
            diff_tests = n()) %>% 
  ungroup()
## `summarise()` has grouped output by 'subdiscipline_1', 'Year'. You can override
## using the `.groups` argument.
## `summarise()` has grouped output by 'subdiscipline_1', 'n_tests'. You can
## override using the `.groups` argument.
entropy_by_year %>% 
  ggplot(., aes(Year, norm_entropy, color = subdiscipline_1)) +
  geom_line(size = 0.7) +
  scale_y_continuous("Normalized Shannon Entropy (constructs)", limits = c(0, 1), labels = scales::percent) +
  # geom_line(aes(y = log(n)), color = 'red') +
  scale_x_continuous("Usage year as coded in APA PsycInfo", limits = c(1993, 2038), 
                     breaks = seq(1993, 2022, by = 1),
                     labels = c(1993, "", "", "", "", 1998, "", "", "", "", 2003, "", "", "", "", 2008, "", "", "", "", 2013, "", "", "", "", 2018, "", "", "", "2022"),
                     expand = expansion(add = c(0, 10))) +
  scale_color_brewer(type = "qual", guide = "none", palette = 2) +
  # ggtitle(str_c(n_distinct(tests_by_year$Test), " measures tracked in PsycInfo")) +
  # ggrepel::geom_text_repel(
  #   aes(label = str_replace(subdiscipline, " Psychology", "")), data = entropy_by_year %>% filter(Year == max(Year, na.rm = T)),
  #   size = 4, hjust = 1,
  #   ) + 
  geom_text_repel(data = entropy_by_year %>% drop_na() %>% group_by(subdiscipline_1) %>% filter(Year == max(Year, na.rm = T)),
                  aes(label = paste0("  ",str_replace(subdiscipline_1, " Psychology", ""), " (n=", n_tests, ")")),
                  # segment.alpha = 0, ## This will 'hide' the link
                  segment.curvature = -0.1,
                  segment.square = TRUE,
                  segment.color = 'grey',
                  box.padding = 0.1,
                  max.overlaps = Inf,
                  point.padding = 0.6,
                  xlim = c(2022, NA),
                  nudge_x = 2,
                  # nudge_y = 0.0,
                  force = 5,
                  hjust = 0,
                  direction="y",
                  na.rm = F) +
   theme(panel.grid.minor.y = element_blank(),
        panel.grid.minor.x = element_blank(),
        plot.title.position = "plot",
        plot.title = element_text(face="bold"),
        legend.position = "none")

ggsave("figures/entropy_subdiscipline_constructs.pdf", width = 8, height = 4)
ggsave("figures/entropy_subdiscipline_constructs.png", width = 8, height = 4)

By instrument type

entropy_by_year <- psyctests_info %>% 
  filter(between(Year, 1993, 2022)) %>% 
  group_by(instrument_type_broad, Year, Test = DOI) %>% 
  summarise(n = sum(usage_count, na.rm = T)) %>% 
  group_by(instrument_type_broad) %>% 
  mutate(n_tests = n_distinct(Test)) %>% 
  group_by(instrument_type_broad, n_tests, Year) %>% 
  filter(n > 0) %>% 
  summarise(entropy = entropy(n),
            norm_entropy = calc_norm_entropy(n),
            n = sum(n),
            diff_tests = n()) %>% 
  ungroup()
## `summarise()` has grouped output by 'instrument_type_broad', 'Year'. You can
## override using the `.groups` argument.
## `summarise()` has grouped output by 'instrument_type_broad', 'n_tests'. You can
## override using the `.groups` argument.
entropy_by_year %>% 
  ggplot(., aes(Year, norm_entropy, color = instrument_type_broad)) +
  geom_line(size = 0.7) +
  scale_y_continuous("Normalized Shannon Entropy", limits = c(0, 1), labels = scales::percent) +
  # geom_line(aes(y = log(n)), color = 'red') +
  scale_x_continuous(limits = c(1993, 2027), breaks = c(1993, 1998, 2003, 2008, 2013, 2018, 2022)) +
  scale_color_brewer(type = "qual", guide = "none", palette = 3) +
  # ggrepel::geom_text_repel(
  #   aes(label = str_replace(subdiscipline, " Psychology", "")), data = entropy_by_year %>% filter(Year == max(Year, na.rm = T)),
  #   size = 4, hjust = 1,
  #   ) + 
  geom_text_repel(aes(label = gsub("^.*$", " ", instrument_type_broad)), # This will force the correct position of the link's right end.
                  data = entropy_by_year %>% filter(Year == max(Year, na.rm = T)),
                  segment.curvature = -0.1,
                  segment.square = TRUE,
                  segment.color = 'grey',
                  box.padding = 0.1,
                  point.padding = 0.6,
                  nudge_x = 0.15,
                  nudge_y = 0.05,
                  force = 0.5,
                  hjust = 0,
                  direction="y",
                  na.rm = TRUE
  ) +
  geom_text_repel(data = entropy_by_year %>% filter(Year == max(Year, na.rm = T)),
                  aes(label = paste0("  ",str_replace(instrument_type_broad, " Psychology", ""), " (n=", n_tests, ")")),
                  segment.alpha = 0, ## This will 'hide' the link
                  segment.curvature = -0.1,
                  segment.square = TRUE,
                  # segment.color = 'grey',
                  box.padding = 0.1,
                  point.padding = 0.6,
                  nudge_x = 0.15,
                  nudge_y = 0.05,
                  force = 0.5,
                  hjust = 0,
                  direction="y",
                  na.rm = TRUE)+
  theme_minimal(base_size = 13) +
   theme(panel.grid.minor.y = element_blank(),
        panel.grid.minor.x = element_blank(),
        plot.title.position = "plot",
        plot.title = element_text(face="bold"),
        legend.position = "none")
## Warning: Removed 31 rows containing missing values or values outside the scale range
## (`geom_line()`).

Lorenz curves

test_frequency <- psyctests_info %>% 
  mutate(Test = if_else(test_type == "Original", DOI, original_test_DOI)) %>% 
  drop_na(Test) %>% 
  # filter(TestYear >= 1990) %>%
  filter(between(Year, 1993, 2022)) %>%
  group_by(subdiscipline_1, Test) %>% 
  summarise(n = sum(usage_count, na.rm = T)) %>% 
  arrange(n) %>% 
  mutate(decile = Hmisc::cut2(n, g = 10)) %>% 
  mutate(cumsum = cumsum(n),
         sum = sum(n))
## `summarise()` has grouped output by 'subdiscipline_1'. You can override using
## the `.groups` argument.
# 
# test_frequency %>% 
#     group_by(subdiscipline_1, decile) %>% 
#     summarise(share = sum(n)/first(sum),
#               median_n = median(n),
#               n_measures = n()) %>% 
#   View()


ggplot(test_frequency, aes(n)) +
  stat_lorenz(desc = F) +
  coord_fixed() +
  geom_abline(linetype = "dashed") +
      theme_minimal() +
    hrbrthemes::scale_x_percent("Cumulative percentage of measures") +
    hrbrthemes::scale_y_percent("Cumulative percentage of measure market share") #+

#    hrbrthemes::theme_ipsum_rc()

ggplot(test_frequency, aes(n, color = subdiscipline_1)) +
  stat_lorenz(desc = F) +
  coord_fixed() +
  geom_abline(linetype = "dashed") +
      theme_minimal() +
    hrbrthemes::scale_x_percent("Cumulative percentage of measures") +
    hrbrthemes::scale_y_percent("Cumulative percentage of measure market share")

Survival

aggregate stats

constructs <- psyctests_info %>% 
     # filter(between(first_pub_year, 1950, 2015)) %>%
     unnest(ConstructList) %>% 
     rowwise() %>% 
     mutate(construct = unlist(ConstructList)) %>% 
     select(-ConstructList) %>% 
     filter(between(Year, 1993, 2022)) %>% 
     drop_na(construct) %>% 
     mutate(survival = last_pub_year - first_pub_year,
            survived_five = if_else(survival >= 5, T, F),
            survived_ten = if_else(survival >= 10, T, F)) %>%
     distinct(construct, .keep_all = TRUE)

mean(constructs$survival, na.rm = T)
## [1] 6.120457
sd(constructs$survival, na.rm = T)
## [1] 8.788988
median(constructs$survival, na.rm = T)
## [1] 2
max(constructs$survival, na.rm = T)
## [1] 122
min(constructs$survival, na.rm = T)
## [1] 0
measures <- psyctests_info %>% 
     filter(between(Year, 1993, 2022))  %>% 
     mutate(survival = last_pub_year - first_pub_year,
            survived_five = if_else(survival >= 5, T, F),
            survived_ten = if_else(survival >= 10, T, F)) %>%
     distinct(DOI, .keep_all = TRUE)

mean(measures$survival, na.rm = T)
## [1] 6.046785
sd(measures$survival, na.rm = T)
## [1] 8.743927
median(measures$survival, na.rm = T)
## [1] 2
max(measures$survival, na.rm = T)
## [1] 122
min(measures$survival, na.rm = T)
## [1] 0

cumulative sum

all constructs

cumsum_construct <- constructs %>% 
  arrange(TestYear) %>% 
  group_by(TestYear) %>% 
  summarise(constructs = n_distinct(DOI)) %>% 
  arrange(TestYear) %>% 
  mutate(constructs = cumsum(constructs)) 

cumsum_construct_survived_5 <- constructs %>% 
  filter(survived_five == T) %>% 
  arrange(TestYear) %>% 
  group_by(TestYear) %>% 
  summarise(constructs = n_distinct(DOI)) %>% 
  arrange(TestYear) %>% 
  mutate(constructs = cumsum(constructs)) 
  
cumsum_construct_survived_10 <- constructs %>% 
  filter(survived_ten == T) %>% 
  arrange(TestYear) %>% 
  group_by(TestYear) %>% 
  summarise(constructs = n_distinct(DOI)) %>% 
  arrange(TestYear) %>% 
  mutate(constructs = cumsum(constructs)) 



cumsums <- bind_rows(
  "all constructs" = cumsum_construct,
  "constructs in use\n for => 5 years" = cumsum_construct_survived_5,
  "constructs in use\n for => 10 years" = cumsum_construct_survived_10,
  .id = "origin"
  ) %>% 
  rename(Year = TestYear) %>% 
  filter(Year <= 2022)


ggplot(cumsums, aes(Year, constructs, color = origin)) + 
  geom_line() +
  geom_vline(xintercept = 2016, linetype = 'dashed') +
  scale_y_continuous("Cumulative number of constructs") +
  scale_x_continuous("Publication year in APA PsycTests",
                     limits = c(1993, 2030), 
                     breaks = seq(1993,2022, by = 1),
                     labels = c(1993, "", "", "", "", 1998, "", "", "", "", 2003, "", "", "", "", 2008, "", "", "", "", 2013, "", "", "", "", 2018, "", "", "", "2022"),
                     expand = expansion(add = c(0, 1))) +
  scale_color_brewer(type = "qual", guide = "none", palette = 2) +
  # ggrepel::geom_text_repel(
  #   aes(label = str_replace(subdiscipline, " Psychology", "")), data = entropy_by_year %>% filter(Year == max(Year, na.rm = T)),
  #   size = 4, hjust = 1,
  #   )  +
  geom_text_repel(data = cumsums %>% drop_na() %>% group_by(origin) %>% filter(Year == max(Year, na.rm = T)),
                  aes(label = paste0(" ", origin, "\n (n = ", constructs, ")")),
                  segment.square = TRUE,
                  lineheight = .9,
                  segment.color = 'grey',
                  nudge_x = 1.2,
                  hjust = 0,
                  na.rm = TRUE)+
   # theme_minimal(base_size = 13) +
   theme(panel.grid.minor.y = element_blank(),
        panel.grid.minor.x = element_blank(),
        plot.title.position = "plot",
        plot.title = element_text(face="bold"),
        legend.position = "none")  +
    guides(
    x = guide_axis(cap = "both"), # Cap both ends
  )
## Warning: Removed 187 rows containing missing values or values outside the scale range
## (`geom_line()`).

ggsave("figures/cumsums_survival_all.pdf", width = 8, height = 4)
## Warning: Removed 187 rows containing missing values or values outside the scale range
## (`geom_line()`).
ggsave("figures/cumsums_survival_all.png", width = 8, height = 4)
## Warning: Removed 187 rows containing missing values or values outside the scale range
## (`geom_line()`).

first constructs

first_constructs <- constructs %>%
  distinct(first_construct, .keep_all = TRUE)


cumsum_construct <- first_constructs %>% 
  arrange(TestYear) %>% 
  group_by(TestYear) %>% 
  summarise(constructs = n_distinct(DOI)) %>% 
  arrange(TestYear) %>% 
  mutate(constructs = cumsum(constructs)) 

cumsum_construct_survived_5 <- first_constructs %>% 
  filter(survived_five == T) %>% 
  arrange(TestYear) %>% 
  group_by(TestYear) %>% 
  summarise(constructs = n_distinct(DOI)) %>% 
  arrange(TestYear) %>% 
  mutate(constructs = cumsum(constructs)) 
  
cumsum_construct_survived_10 <- first_constructs %>% 
  filter(survived_ten == T) %>% 
  arrange(TestYear) %>% 
  group_by(TestYear) %>% 
  summarise(constructs = n_distinct(DOI)) %>% 
  arrange(TestYear) %>% 
  mutate(constructs = cumsum(constructs)) 



cumsums <- bind_rows(
  "all constructs" = cumsum_construct,
  "constructs in use\n for => 5 years" = cumsum_construct_survived_5,
  "constructs in use\n for => 10 years" = cumsum_construct_survived_10,
  .id = "origin"
  ) %>% 
  rename(Year = TestYear) %>% 
  filter(Year <= 2022)


ggplot(cumsums, aes(Year, constructs, color = origin)) + 
  geom_line() +
  geom_vline(xintercept = 2016, linetype = 'dashed') +
  scale_y_continuous("Cumulative number of constructs") +
  scale_x_continuous("Publication year in APA PsycTests",
                     limits = c(1993, 2030), 
                     breaks = seq(1993,2022, by = 1),
                     labels = c(1993, "", "", "", "", 1998, "", "", "", "", 2003, "", "", "", "", 2008, "", "", "", "", 2013, "", "", "", "", 2018, "", "", "", "2022"),
                     expand = expansion(add = c(0, 1))) +
  scale_color_brewer(type = "qual", guide = "none", palette = 2) +
  # ggrepel::geom_text_repel(
  #   aes(label = str_replace(subdiscipline, " Psychology", "")), data = entropy_by_year %>% filter(Year == max(Year, na.rm = T)),
  #   size = 4, hjust = 1,
  #   )  +
  geom_text_repel(data = cumsums %>% drop_na() %>% group_by(origin) %>% filter(Year == max(Year, na.rm = T)),
                  aes(label = paste0(" ", origin, "\n (n = ", constructs, ")")),
                  segment.square = TRUE,
                  lineheight = .9,
                  segment.color = 'grey',
                  nudge_x = 1.2,
                  hjust = 0,
                  na.rm = TRUE)+
   # theme_minimal(base_size = 13) +
   theme(panel.grid.minor.y = element_blank(),
        panel.grid.minor.x = element_blank(),
        plot.title.position = "plot",
        plot.title = element_text(face="bold"),
        legend.position = "none")  +
    guides(
    x = guide_axis(cap = "both"), # Cap both ends
  )
## Warning: Removed 187 rows containing missing values or values outside the scale range
## (`geom_line()`).

ggsave("figures/cumsums_survival_first.pdf", width = 8, height = 4)
## Warning: Removed 187 rows containing missing values or values outside the scale range
## (`geom_line()`).
ggsave("figures/cumsums_survival_first.png", width = 8, height = 4)
## Warning: Removed 187 rows containing missing values or values outside the scale range
## (`geom_line()`).

measures

cumsum_all <- measures %>% 
  group_by(TestYear) %>% 
  summarise(tests = n()) %>% 
  arrange(TestYear) %>% 
  mutate(tests = cumsum(tests)) 

cumsum_5 <- measures %>% 
  filter(survived_five == T) %>% 
  group_by(TestYear) %>% 
  summarise(tests = n()) %>% 
  arrange(TestYear) %>% 
  mutate(tests = cumsum(tests)) 

cumsum_10 <- measures %>% 
  filter(survived_ten == T) %>% 
  arrange(TestYear) %>% 
  distinct(Name_base, .keep_all = T) %>% 
  group_by(TestYear) %>% 
  summarise(tests = n_distinct(DOI)) %>% 
  mutate(tests = cumsum(tests)) 

cumsums <- bind_rows(
  "all measures" = cumsum_all,
  "measures in use\n for => 5 years" = cumsum_5,
  "measures in use\n for => 10 years" = cumsum_10,
  .id = "origin"
  ) %>% 
  rename(Year = TestYear) %>% 
  filter(Year <= 2022)


ggplot(cumsums, aes(Year, tests, color = origin)) + 
  geom_line() +
  geom_vline(xintercept = 2016, linetype = 'dashed') +
  scale_y_continuous("Cumulative number of measures") +
  scale_x_continuous("Publication year in APA PsycTests",
                     limits = c(1993, 2030), 
                     breaks = seq(1993,2022, by = 1),
                     labels = c(1993, "", "", "", "", 1998, "", "", "", "", 2003, "", "", "", "", 2008, "", "", "", "", 2013, "", "", "", "", 2018, "", "", "", "2022"),
                     expand = expansion(add = c(0, 1))) +
  scale_color_brewer(type = "qual", guide = "none", palette = 2) +
  # ggrepel::geom_text_repel(
  #   aes(label = str_replace(subdiscipline, " Psychology", "")), data = entropy_by_year %>% filter(Year == max(Year, na.rm = T)),
  #   size = 4, hjust = 1,
  #   )  +
  geom_text_repel(data = cumsums %>% drop_na() %>% group_by(origin) %>% filter(Year == max(Year, na.rm = T)),
                  aes(label = paste0(" ", origin, "\n (n = ", tests, ")")),
                  segment.square = TRUE,
                  lineheight = .9,
                  segment.color = 'grey',
                  nudge_x = 1.2,
                  hjust = 0,
                  na.rm = TRUE) +
   # theme_minimal(base_size = 13) +
   theme(panel.grid.minor.y = element_blank(),
        panel.grid.minor.x = element_blank(),
        plot.title.position = "plot",
        plot.title = element_text(face="bold"),
        legend.position = "none")  +
    guides(
    x = guide_axis(cap = "both"), # Cap both ends
  )
## Warning: Removed 220 rows containing missing values or values outside the scale range
## (`geom_line()`).

ggsave("figures/cumsums_survival_measures.pdf", width = 8, height = 4)
## Warning: Removed 220 rows containing missing values or values outside the scale range
## (`geom_line()`).
ggsave("figures/cumsums_survival_measures.png", width = 8, height = 4)
## Warning: Removed 220 rows containing missing values or values outside the scale range
## (`geom_line()`).

by first use in PsycInfo instead of publication year in PsycTests

cumsum_construct <- constructs %>% 
  arrange(first_pub_year) %>% 
  group_by(first_pub_year) %>% 
  summarise(constructs = n_distinct(DOI)) %>% 
  arrange(first_pub_year) %>% 
  mutate(constructs = cumsum(constructs)) 

cumsum_construct_survived_5 <- constructs %>% 
  filter(survived_five == T) %>% 
  arrange(first_pub_year) %>% 
  group_by(first_pub_year) %>% 
  summarise(constructs = n_distinct(DOI)) %>% 
  arrange(first_pub_year) %>% 
  mutate(constructs = cumsum(constructs)) 
  
cumsum_construct_survived_10 <- constructs %>% 
  filter(survived_ten == T) %>% 
  arrange(first_pub_year) %>% 
  group_by(first_pub_year) %>% 
  summarise(constructs = n_distinct(DOI)) %>% 
  arrange(first_pub_year) %>% 
  mutate(constructs = cumsum(constructs)) 



cumsums <- bind_rows(
  "all constructs" = cumsum_construct,
  "constructs in use\n for => 5 years" = cumsum_construct_survived_5,
  "constructs in use\n for => 10 years" = cumsum_construct_survived_10,
  .id = "origin"
  ) %>% 
  rename(Year = first_pub_year) %>% 
  filter(Year <= 2022)


ggplot(cumsums, aes(Year, constructs, color = origin)) + 
  geom_line() +
  geom_vline(xintercept = 2016, linetype = 'dashed') +
  scale_y_continuous("Cumulative number of constructs") +
  scale_x_continuous("First usage logged in PsycInfo",
                     limits = c(1993, 2030), 
                     breaks = seq(1993,2022, by = 1),
                     labels = c(1993, "", "", "", "", 1998, "", "", "", "", 2003, "", "", "", "", 2008, "", "", "", "", 2013, "", "", "", "", 2018, "", "", "", "2022"),
                     expand = expansion(add = c(0, 1))) +
  scale_color_brewer(type = "qual", guide = "none", palette = 2) +
  # ggrepel::geom_text_repel(
  #   aes(label = str_replace(subdiscipline, " Psychology", "")), data = entropy_by_year %>% filter(Year == max(Year, na.rm = T)),
  #   size = 4, hjust = 1,
  #   )  +
  geom_text_repel(data = cumsums %>% drop_na() %>% group_by(origin) %>% filter(Year == max(Year, na.rm = T)),
                  aes(label = paste0(" ", origin, "\n (n = ", constructs, ")")),
                  segment.square = TRUE,
                  lineheight = .9,
                  segment.color = 'grey',
                  nudge_x = 1.2,
                  hjust = 0,
                  na.rm = TRUE)+
   # theme_minimal(base_size = 13) +
   theme(panel.grid.minor.y = element_blank(),
        panel.grid.minor.x = element_blank(),
        plot.title.position = "plot",
        plot.title = element_text(face="bold"),
        legend.position = "none")  +
    guides(
    x = guide_axis(cap = "both"), # Cap both ends
  )
## Warning: Removed 186 rows containing missing values or values outside the scale range
## (`geom_line()`).

by last use in PsycInfo instead of publication year in PsycTests

cumsum_construct <- constructs %>% 
  arrange(last_pub_year) %>% 
  group_by(last_pub_year) %>% 
  summarise(constructs = n_distinct(DOI)) %>% 
  arrange(last_pub_year) %>% 
  mutate(constructs = cumsum(constructs)) 

cumsum_construct_survived_5 <- constructs %>% 
  filter(survived_five == T) %>% 
  arrange(last_pub_year) %>% 
  group_by(last_pub_year) %>% 
  summarise(constructs = n_distinct(DOI)) %>% 
  arrange(last_pub_year) %>% 
  mutate(constructs = cumsum(constructs)) 
  
cumsum_construct_survived_10 <- constructs %>% 
  filter(survived_ten == T) %>% 
  arrange(last_pub_year) %>% 
  group_by(last_pub_year) %>% 
  summarise(constructs = n_distinct(DOI)) %>% 
  arrange(last_pub_year) %>% 
  mutate(constructs = cumsum(constructs)) 



cumsums <- bind_rows(
  "all constructs" = cumsum_construct,
  "constructs in use\n for => 5 years" = cumsum_construct_survived_5,
  "constructs in use\n for => 10 years" = cumsum_construct_survived_10,
  .id = "origin"
  ) %>% 
  rename(Year = last_pub_year) %>% 
  filter(Year <= 2022)


ggplot(cumsums, aes(Year, constructs, color = origin)) + 
  geom_line() +
  geom_vline(xintercept = 2016, linetype = 'dashed') +
  scale_y_continuous("Cumulative number of constructs") +
  scale_x_continuous("Last usage logged in PsycInfo",
                     limits = c(1993, 2030), 
                     breaks = seq(1993,2022, by = 1),
                     labels = c(1993, "", "", "", "", 1998, "", "", "", "", 2003, "", "", "", "", 2008, "", "", "", "", 2013, "", "", "", "", 2018, "", "", "", "2022"),
                     expand = expansion(add = c(0, 1))) +
  scale_color_brewer(type = "qual", guide = "none", palette = 2) +
  # ggrepel::geom_text_repel(
  #   aes(label = str_replace(subdiscipline, " Psychology", "")), data = entropy_by_year %>% filter(Year == max(Year, na.rm = T)),
  #   size = 4, hjust = 1,
  #   )  +
  geom_text_repel(data = cumsums %>% drop_na() %>% group_by(origin) %>% filter(Year == max(Year, na.rm = T)),
                  aes(label = paste0(" ", origin, "\n (n = ", constructs, ")")),
                  segment.square = TRUE,
                  lineheight = .9,
                  segment.color = 'grey',
                  nudge_x = 1.2,
                  hjust = 0,
                  na.rm = TRUE)+
   # theme_minimal(base_size = 13) +
   theme(panel.grid.minor.y = element_blank(),
        panel.grid.minor.x = element_blank(),
        plot.title.position = "plot",
        plot.title = element_text(face="bold"),
        legend.position = "none")  +
    guides(
    x = guide_axis(cap = "both"), # Cap both ends
  )

counts

count_construct <- constructs %>% 
  arrange(TestYear) %>%
  group_by(TestYear) %>% 
  summarise(tests = n_distinct(construct)) %>% 
  arrange(TestYear)

count_construct_5 <- constructs %>% 
  filter(survived_five == T) %>% 
  arrange(TestYear) %>%
  group_by(TestYear) %>% 
  summarise(tests = n_distinct(construct)) %>% 
  arrange(TestYear)

count_construct_10 <- constructs %>% 
  filter(survived_ten == T) %>% 
  arrange(TestYear) %>%
  group_by(TestYear) %>% 
  summarise(tests = n_distinct(construct)) %>% 
  arrange(TestYear)

counts <- bind_rows(
  "all constructs" = count_construct,
  "constructs in use\n for => 5 years" = count_construct_5,
  "constructs in use\n for => 10 years" = count_construct_10,
  .id = "origin"
  ) %>% 
  rename(Year = TestYear) %>% 
  filter(Year <= 2022)



ggplot(counts, aes(Year, tests, color = origin)) + 
  geom_line() +
  geom_vline(xintercept = 2016, linetype = 'dashed') +
  scale_y_continuous("Number of constructs") +
  scale_x_continuous("Publication year in APA PsycTests",
                     limits = c(1993, 2030), 
                     breaks = seq(1993, 2022, by = 1),
                     labels = c(1993, "", "", "", "", 1998, "", "", "", "", 2003, "", "", "", "", 2008, "", "", "", "", 2013, "", "", "", "", 2018, "", "", "", "2022")) +
  scale_color_brewer(type = "qual", guide = "none", palette = 2) +
  # ggrepel::geom_text_repel(
  #   aes(label = str_replace(subdiscipline, " Psychology", "")), data = entropy_by_year %>% filter(Year == max(Year, na.rm = T)),
  #   size = 4, hjust = 1,
  #   ) +
  geom_text_repel(data = counts %>% drop_na() %>% group_by(origin) %>% filter(Year == max(Year, na.rm = T)),
                  aes(label = paste0(" ", origin)),
                  segment.curvature = -0.1,
                  segment.square = TRUE,
                  lineheight = .9,
                  # segment.color = 'grey',
                  box.padding = 0.1,
                  point.padding = 0.6,
                  nudge_x = 1.5,
                  nudge_y = -15,
                  force = 1,
                  hjust = 0,
                  direction="y",
                  na.rm = F) +
   theme(panel.grid.minor.y = element_blank(),
        panel.grid.minor.x = element_blank(),
        plot.title.position = "plot",
        plot.title = element_text(face="bold"),
        legend.position = "none")
## Warning: Removed 187 rows containing missing values or values outside the scale range
## (`geom_line()`).

ggsave("figures/counts_survival.pdf", width = 8, height = 4)
## Warning: Removed 187 rows containing missing values or values outside the scale range
## (`geom_line()`).
ggsave("figures/counts_survival.png", width = 8, height = 4)
## Warning: Removed 187 rows containing missing values or values outside the scale range
## (`geom_line()`).

Robustness checks

all_constructs_over_time <- records_wide %>% select(subdiscipline_1, DOI, TestYear, ConstructList) %>% 
    unnest(ConstructList) %>% 
    rowwise() %>% 
    mutate(construct = unlist(ConstructList)) %>% 
  select(-ConstructList)

cumsum_all_constructs <- all_constructs_over_time %>% 
  arrange(TestYear) %>% 
  distinct(construct, .keep_all = T) %>% 
  group_by(TestYear) %>% 
  summarise(constructs = n_distinct(construct)) %>% 
  arrange(TestYear) %>% 
  mutate(constructs = cumsum(constructs)) 


cumsum_construct <- records_wide %>% 
  arrange(TestYear) %>% 
  distinct(first_construct, .keep_all = T) %>% 
  group_by(TestYear) %>% 
  summarise(constructs = n_distinct(first_construct)) %>% 
  arrange(TestYear) %>% 
  mutate(constructs = cumsum(constructs))

cumsums <- bind_rows(
  "first constructs" = cumsum_construct,
  "all constructs" = cumsum_all_constructs,
  .id = "origin"
  ) %>% 
  rename(Year = TestYear) %>% 
  filter(Year <= 2022)


ggplot(cumsums, aes(Year, constructs, color = origin)) + 
  geom_line() +
  scale_y_continuous("Cumulative number of constructs") +
  scale_x_continuous("Publication year in APA PsycTests",
                     limits = c(1993, 2027), 
                     breaks = seq(1993, 2022, by = 1),
                     labels = c(1993, "", "", "", "", 1998, "", "", "", "", 2003, "", "", "", "", 2008, "", "", "", "", 2013, "", "", "", "", 2018, "", "", "", "2022")) +
  scale_color_brewer(type = "qual", guide = "none", palette = 2) +
  # ggrepel::geom_text_repel(
  #   aes(label = str_replace(subdiscipline, " Psychology", "")), data = entropy_by_year %>% filter(Year == max(Year, na.rm = T)),
  #   size = 4, hjust = 1,
  #   ) + 
  geom_text_repel(data = cumsums %>% drop_na() %>% group_by(origin) %>% filter(Year == max(Year, na.rm = T)),
                  aes(label = paste0(" ", origin, "\n (n = ", constructs, ")")),
                  segment.square = TRUE,
                  lineheight = .9,
                  segment.color = 'grey',
                  nudge_x = 1.2,
                  hjust = 0,
                  na.rm = TRUE)
## Warning: Removed 170 rows containing missing values or values outside the scale range
## (`geom_line()`).

ggsave("figures/cumsum_all_vs_first.pdf", width = 8, height = 4)
## Warning: Removed 170 rows containing missing values or values outside the scale range
## (`geom_line()`).
ggsave("figures/cumsum_all_vs_first.png", width = 8, height = 4)
## Warning: Removed 170 rows containing missing values or values outside the scale range
## (`geom_line()`).

All or first constructs

For some 20% of tests, two or more constructs were coded. In most plots, we simply use the first construct for each test.

records_wide <- records_wide %>% 
  rowwise() %>% 
  mutate(constructs_n = length(ConstructList)) %>% 
  ungroup()

table(records_wide$constructs_n)
## 
##     1     2     3     4     5     6     7     8     9    10    12    15    16 
## 56645 12421  2134   326    85    37    13    14     3     3     3     1     1 
##    17    21    22    23    25 
##     1     1     1     1     2
round(prop.table(table(records_wide$constructs_n)),2)
## 
##    1    2    3    4    5    6    7    8    9   10   12   15   16   17   21   22 
## 0.79 0.17 0.03 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 
##   23   25 
## 0.00 0.00
ggplot(records_wide, aes(constructs_n)) + 
  geom_bar()

Expanding the entropy calculation to all coded constructs makes little difference.

all_constructs_over_time <- psyctests_info %>% select(subdiscipline_1, DOI, TestYear, Year, ConstructList, usage_count) %>% 
    unnest(ConstructList) %>% 
    rowwise() %>% 
    mutate(construct = unlist(ConstructList)) %>% 
  select(-ConstructList)

entropy_all_constructs <- all_constructs_over_time %>% 
  filter(between(Year, 1993, 2022)) %>% 
  drop_na(construct) %>% 
  group_by(Year, construct) %>% 
  summarise(n = sum(usage_count, na.rm = T)) %>% 
  ungroup() %>% 
  mutate(n_tests = n_distinct(construct)) %>% 
  group_by(n_tests, Year) %>% 
  filter(n > 0) %>% 
  summarise(entropy = entropy(n),,
            norm_entropy = calc_norm_entropy(n),
            n = sum(n),
            diff_tests = n()) %>% 
  ungroup()
## `summarise()` has grouped output by 'Year'. You can override using the
## `.groups` argument.
## `summarise()` has grouped output by 'n_tests'. You can override using the
## `.groups` argument.
byconstruct_entropy_by_year <- psyctests_info %>% 
  filter(between(Year, 1993, 2022)) %>% 
  drop_na(first_construct) %>% 
  group_by(Year, Test = first_construct) %>% 
  summarise(n = sum(usage_count, na.rm = T)) %>% 
  ungroup() %>% 
  mutate(n_tests = n_distinct(Test)) %>% 
  group_by(n_tests, Year) %>% 
  filter(n > 0) %>% 
  summarise(entropy = entropy(n),,
            norm_entropy = calc_norm_entropy(n),
            n = sum(n),
            diff_tests = n()) %>% 
  ungroup()
## `summarise()` has grouped output by 'Year'. You can override using the
## `.groups` argument.
## `summarise()` has grouped output by 'n_tests'. You can override using the
## `.groups` argument.
entropy_by_year <- bind_rows(# "all tests" = all_entropy_by_year,
                             "all constructs" = entropy_all_constructs,
                             # "by name base" = bybase_entropy_by_year,
                             "first constructs" = byconstruct_entropy_by_year,
                             .id = "version")

entropy_by_year %>% 
  ggplot(., aes(Year, norm_entropy, color = version)) +
  geom_line(size = 0.7) +
  scale_y_continuous("Normalized Shannon Entropy", limits = c(0, 1), labels = scales::percent) +
  # geom_line(aes(y = log(n)), color = 'red') +
  scale_x_continuous("Usage year as coded in APA PsycInfo", limits = c(1993, 2027), 
                     breaks = seq(1993, 2022, by = 1),
                     labels = c(1993, "", "", "", "", 1998, "", "", "", "", 2003, "", "", "", "", 2008, "", "", "", "", 2013, "", "", "", "", 2018, "", "", "", "2022")) +

  scale_color_brewer(type = "qual", guide = "none", palette = 2) +
  # ggrepel::geom_text_repel(
  #   aes(label = str_replace(subdiscipline, " Psychology", "")), data = entropy_by_year %>% filter(Year == max(Year, na.rm = T)),
  #   size = 4, hjust = 1,
  #   ) + 
  geom_text_repel(data = entropy_by_year %>% drop_na() %>% group_by(version) %>% filter(Year == max(Year, na.rm = T)),
                  aes(label = paste0(" ",version)), # "\n (n = ", n_tests, ")"
                  segment.curvature = -0.5,
                  segment.square = TRUE,
                  segment.color = 'grey', 
                  xlim = c(2023, 2030),
                  nudge_x = 1.14,
                  lineheight = .9,
                  hjust = 0,
                  direction="y",
                  na.rm = TRUE) +
  theme_minimal(base_size = 13) +
   theme(panel.grid.minor.y = element_blank(),
        panel.grid.minor.x = element_blank(),
        plot.title.position = "plot",
        plot.title = element_text(face="bold"),
        legend.position = "none")

ggsave("figures/entropy_all_vs_first.pdf", width = 8, height = 4)
ggsave("figures/entropy_all_vs_first.png", width = 8, height = 4)

Unbiased estimators of Shannon entropy

Does not make much of a difference.

byorig_entropy_by_year <- psyctests_info %>% 
  filter(between(Year, 1993, 2022)) %>% 
  mutate(Test = if_else(test_type == "Original", DOI, original_test_DOI)) %>% 
  drop_na(Test) %>% 
  group_by(Year, Test) %>% 
  summarise(n = sum(usage_count, na.rm = T)) %>% 
  ungroup() %>% 
  mutate(n_tests = n_distinct(Test)) %>% 
  group_by(n_tests, Year) %>% 
  filter(n > 0) %>% 
  summarise(norm_entropy = calc_norm_entropy(n),
            norm_entropy_MM = entropy(n, method = "MM") / log(n()),
            n = sum(n),
            diff_tests = n()) %>% 
  ungroup()
## `summarise()` has grouped output by 'Year'. You can override using the
## `.groups` argument.
## `summarise()` has grouped output by 'n_tests'. You can override using the
## `.groups` argument.
1 - (byorig_entropy_by_year$n_tests[1]/ records_wide %>% filter(between(TestYear, 1993, 2022)) %>% 
       mutate(Test = if_else(test_type == "Original", DOI, original_test_DOI)) %>% 
       summarise(n_distinct(Test)))
## # A tibble: 1 × 1
##   `n_distinct(Test)`
##                <dbl>
## 1              0.552
byconstruct_entropy_by_year <- psyctests_info %>% 
  filter(between(Year, 1993, 2022)) %>% 
  drop_na(first_construct) %>% 
  group_by(Year, Test = first_construct) %>% 
  summarise(n = sum(usage_count, na.rm = T)) %>% 
  ungroup() %>% 
  mutate(n_tests = n_distinct(Test)) %>% 
  group_by(n_tests, Year) %>% 
  filter(n > 0) %>% 
  summarise(norm_entropy = calc_norm_entropy(n),
            norm_entropy_MM = entropy(n, method = "MM") / log(n()),
            n = sum(n),
            diff_tests = n()) %>% 
  ungroup()
## `summarise()` has grouped output by 'Year'. You can override using the
## `.groups` argument.
## `summarise()` has grouped output by 'n_tests'. You can override using the
## `.groups` argument.
all_entropy_by_year <- psyctests_info %>% 
  filter(between(Year, 1993, 2022)) %>% 
  drop_na(DOI) %>% 
  group_by(Year, Test = DOI) %>% 
  summarise(n = sum(usage_count, na.rm = T)) %>% 
  ungroup() %>% 
  mutate(n_tests = n_distinct(Test)) %>% 
  group_by(n_tests, Year) %>% 
  filter(n > 0) %>% 
  summarise(norm_entropy = calc_norm_entropy(n),
            norm_entropy_MM = entropy(n, method = "MM") / log(n()),
            n = sum(n),
            diff_tests = n()) %>% 
  ungroup()
## `summarise()` has grouped output by 'Year'. You can override using the
## `.groups` argument.
## `summarise()` has grouped output by 'n_tests'. You can override using the
## `.groups` argument.
original_entropy_by_year <- psyctests_info %>% 
  filter(between(Year, 1993, 2022)) %>% 
  filter(test_type == "Original") %>% 
  group_by(Year, Test = DOI) %>% 
  summarise(n = sum(usage_count, na.rm = T)) %>% 
  ungroup() %>% 
  mutate(n_tests = n_distinct(Test)) %>% 
  group_by(n_tests, Year) %>% 
  filter(n > 0) %>% 
  summarise(norm_entropy = calc_norm_entropy(n),
            norm_entropy_MM = entropy(n, method = "MM") / log(n()),
            n = sum(n),
            diff_tests = n()) %>% 
  ungroup()
## `summarise()` has grouped output by 'Year'. You can override using the
## `.groups` argument.
## `summarise()` has grouped output by 'n_tests'. You can override using the
## `.groups` argument.
entropy_by_year <- bind_rows(# "all tests" = all_entropy_by_year,
  "measures" = original_entropy_by_year,
  "with translations\n and revisions" = byorig_entropy_by_year,
  # "by name base" = bybase_entropy_by_year,
  "constructs" = byconstruct_entropy_by_year,
  .id = "version")


plot_entropy <- entropy_by_year %>% 
  ggplot(., aes(Year, norm_entropy, color = version)) +
  geom_line(size = 0.7, linetype = "dashed") +
  geom_line(aes(y = norm_entropy_MM), size = 0.7) +
  scale_y_continuous("Normalized Shannon Entropy", limits = c(0, 1), labels = scales::percent) +
  # geom_line(aes(y = log(n)), color = 'red') +
  scale_x_continuous("Usage year as coded in APA PsycInfo", limits = c(1993, 2027), 
                     breaks = seq(1993, 2022, by = 1),
                     labels = c(1993, "", "", "", "", 1998, "", "", "", "", 2003, "", "", "", "", 2008, "", "", "", "", 2013, "", "", "", "", 2018, "", "", "", "2022")) +
  # ggtitle(str_c(n_distinct(tests_by_year$Test), " measures tracked in PsycInfo")) +
  # annotate("text", x = 1993, y = 1, label = "- each used once", 
  #       size = 3.3, vjust = 0.3, hjust = 0.05) +
  # annotate("text", x = 1993, y = 0, label = "- all used one", 
  #       size = 3.3,  vjust = 0.3, hjust = 0.05) +
  
  scale_color_brewer(type = "qual", guide = "none", palette = 2) +
  # ggrepel::geom_text_repel(
  #   aes(label = str_replace(subdiscipline, " Psychology", "")), data = entropy_by_year %>% filter(Year == max(Year, na.rm = T)),
  #   size = 4, hjust = 1,
  #   ) + 
  geom_text_repel(aes(label = str_replace_all(version, "[a-z=0-9/() ]+", " ")), # This will force the correct position of the link's right end.
                  data = entropy_by_year %>% drop_na() %>% group_by(version) %>% filter(Year == max(Year, na.rm = T)),
                  segment.curvature = -0.1,
                  segment.square = TRUE,
                  lineheight = .9,
                  segment.color = 'grey',
                  box.padding = 0.1,
                  point.padding = 0.6,
                  nudge_x = 1.15,
                  nudge_y = 0.03,
                  force = 0.9,
                  hjust = 0,
                  direction="y",
                  size = 3.3,
                  na.rm = TRUE) +
  geom_text_repel(data = entropy_by_year %>% drop_na() %>% group_by(version) %>% filter(Year == max(Year, na.rm = T)),
                  aes(label = paste0(" ",version)), # "\n (n = ", n_tests, ")"
                  segment.alpha = 0, ## This will 'hide' the link
                  segment.curvature = -0.1,
                  segment.square = TRUE,
                  # segment.color = 'grey',
                  box.padding = 0.1,
                  point.padding = 0.6,
                  nudge_x = 1.15,
                  nudge_y = 0.0,
                  lineheight = .9,
                  force = 0.9,
                  size = 3.3,
                  hjust = 0,
                  direction="y",
                  na.rm = TRUE) +
  theme_minimal(base_size = 13) +
  theme(panel.grid.minor.y = element_blank(),
        panel.grid.minor.x = element_blank(),
        plot.title.position = "plot",
        plot.title = element_text(face="bold"),
        legend.position = "none")
plot_entropy

Entropy by classificaiton

entropy_by_class <- psyctests_info %>% 
  group_by(classification_1, DOI) %>% 
  summarise(n = sum(usage_count, na.rm = T),
            parent = case_when(
                    n > 50 ~ "",
                    n > 20 ~ "used 21-50 times",
                    n > 5 ~ "used 6-20 times",
                    TRUE ~ "used 1-5 times")) %>% 
  group_by(classification_1) %>% 
  # filter(n > 0) %>% 
  summarise(
    entropy = entropy(n),
    norm_entropy = calc_norm_entropy(n)) %>% 
  arrange(norm_entropy)
## `summarise()` has grouped output by 'classification_1'. You can override using
## the `.groups` argument.
kable(entropy_by_class)
classification_1 entropy norm_entropy
Military Personnel, Adjustment, and Training 2.383022 0.4815393
Anxiety and Depression 3.193979 0.4847495
Aptitude and Achievement 2.316471 0.5135321
Neuropsychological Assessment 3.279933 0.5288051
Intelligence 2.257675 0.5350566
General Assessment Tools 2.473627 0.5371412
Functional Status and Adaptive Behavior 3.530552 0.5868450
Trauma, Stress, and Coping 4.183437 0.5982308
Emotional States, Emotional Responses, and Motivation 4.248094 0.6077965
Mental Health/Illness Related Assessment 4.840355 0.6092446
Addiction, Gambling, and Substance Abuse/Use 4.368824 0.6220855
Cognitive Processes, Memory, and Decision Making 4.430633 0.6357767
Sports, Recreation, and Leisure 3.819379 0.6452859
Treatment, Rehabilitation, and Therapeutic Processes 5.157328 0.6514703
Legal and Forensic Evaluation 3.839622 0.6557771
Personality 5.270944 0.6880603
Development and Aging 5.170306 0.7010938
Physical Health/Illness Related Assessment 5.519613 0.7074794
Perceptual, Motor, and Sensory Processing 4.027230 0.7094247
Attitudes, Interests, Values, and Expectancies 4.964110 0.7109935
Communication, Language, and Verbal Processing 4.017755 0.7210416
Family Relationships and Parenting 5.284498 0.7324078
Sex, Gender Roles, and Sexual Behavior 4.922535 0.7417984
Social, Group, and Interpersonal Relationships 5.558756 0.7492815
Religious and Political Beliefs 4.667158 0.7656319
Consumer Behavior, Marketing, and Advertising 4.587740 0.7679755
Culture, Racial, and Ethnic Identity 4.787330 0.7693485
Human Factors and Environmental Engineering 4.212094 0.7776987
Human-Computer Interaction 4.726558 0.7843782
Organizational, Occupational, and Career Development 6.103051 0.7895549
Education, Teaching, and Student Characteristics 6.281884 0.7986947

Entropy by instrument type

psyctests_info %>% 
  group_by(instrument_type_broad, DOI) %>% 
  summarise(n = sum(usage_count, na.rm = T),
            parent = case_when(
                    n > 50 ~ "",
                    n > 20 ~ "used 21-50 times",
                    n > 5 ~ "used 6-20 times",
                    TRUE ~ "used 1-5 times")) %>% 
  group_by(instrument_type_broad) %>% 
  filter(n > 0) %>% 
  summarise(
    entropy = entropy(n),
    norm_entropy = calc_norm_entropy(n)) %>% 
  arrange(norm_entropy) %>% 
  kable()
## `summarise()` has grouped output by 'instrument_type_broad'. You can override
## using the `.groups` argument.
instrument_type_broad entropy norm_entropy
other-rating 4.454314 0.6201748
task 4.041814 0.6228520
NA 3.717207 0.6283096
test 4.704202 0.6359652
questionnaire 7.207948 0.7060498

Tests by exact same name

same_name_tests <- records_wide %>% group_by(name_psycinfo) %>% filter(n_distinct(DOI) > 1) %>% summarise(n = n())
nrow(same_name_tests)
## [1] 1230
mean(same_name_tests$n)
## [1] 2.44878
same_name_tests %>% arrange(desc(n)) %>% head(20)
## # A tibble: 20 × 2
##    name_psycinfo                                n
##    <chr>                                    <int>
##  1 theory of planned behavior questionnaire    18
##  2 job satisfaction scale                      15
##  3 self-efficacy scale                         11
##  4 self-control scale                          10
##  5 behavioral intentions measure                9
##  6 parental involvement scale                   9
##  7 procedural justice scale                     9
##  8 social distance scale                        9
##  9 marital satisfaction measure                 8
## 10 perceived behavioral control measure         8
## 11 religiosity measure                          8
## 12 religiosity scale                            8
## 13 social capital measure                       8
## 14 social support scale                         8
## 15 victimization measure                        8
## 16 attribution questionnaire                    7
## 17 delinquency measure                          7
## 18 fear of crime scale                          7
## 19 food frequency questionnaire                 7
## 20 life satisfaction scale                      7
LS0tDQp0aXRsZTogIkNvbnN0cnVjdCBwcm9saWZlcmF0aW9uIg0KYXV0aG9yOiAiUnViZW4gQXJzbGFuIg0KZGF0ZTogImByIFN5cy5EYXRlKClgIg0Kb3V0cHV0OiANCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZmxvYXQ6IHRydWUNCiAgICBjb2RlX2ZvbGRpbmc6ICJoaWRlIg0KZWRpdG9yX29wdGlvbnM6IA0KICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIGVycm9yID0gVCwgd2FybmluZyA9IFQsIG1lc3NhZ2UgPSBULCBmaWcud2lkdGggPSA4LCBmaWcuaGVpZ2h0ID0gNCkNCg0KbGlicmFyeShncm91bmRob2cpDQpncm91bmRob2cubGlicmFyeShjKCJ0aWR5dmVyc2UiLCAiZW50cm9weSIsICJnZ3JlcGVsIiwgImNvd3Bsb3QiLCAia25pdHIiLCAicmVhZHIiLA0KICAgICAgICAgICAgICAgICAgICAiUkNvbG9yQnJld2VyIiwgInBsb3RseSIsICJnZ2xvcmVueiIsICJyaW8iLCAiaHJicnRoZW1lcyIpLCANCiAgICAgICAgICAgICAgICAgIGRhdGUgPSAiMjAyNC0wMi0yNCIpDQp0aGVtZV9zZXQodGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxMykpDQoNCmNvbG9ycyA8LSBSQ29sb3JCcmV3ZXI6OmJyZXdlci5wYWwoMywgbmFtZSA9ICJEYXJrMiIpDQpuYW1lcyhjb2xvcnMpIDwtIGMoImFsbCIsICJub3ZlbCIsICJjb25zdHJ1Y3RzIikNCg0KY2FsY19ub3JtX2VudHJvcHkgPC0gZnVuY3Rpb24obikgew0KICBuIDwtIG5bbj4wXQ0KICBlbnRyb3B5OjplbnRyb3B5KG4pL2xvZyhsZW5ndGgobikpDQp9DQpgYGANCg0KDQo8ZGV0YWlscz48c3VtbWFyeT5JbXBvcnQ8L3N1bW1hcnk+DQpBUEEgUHN5Y1Rlc3RzDQoNCmBgYHtyfQ0KcmVjb3Jkc193aWRlIDwtIHJlYWRSRFMoIi4uL3NvYmVyX3J1YnJpYy9yYXdfZGF0YS9wcmVwcm9jZXNzZWRfcmVjb3Jkcy5yZHMiKQ0KDQpyZWNvcmRzX3dpZGUgJT4lIGdyb3VwX2J5KE5hbWUpICAlPiUgZmlsdGVyKG4oKT4xKSAlPiUgdW5ncm91cCgpICU+JSBzdW1tYXJpc2Uobl9kaXN0aW5jdChOYW1lKSwgbigpKQ0KDQpyZWNvcmRzX3dpZGUkZmlyc3RfY29uc3RydWN0IDwtIHN0cl90cmltKHN0cl9yZXBsYWNlX2FsbChzdHJfdG9fbG93ZXIocmVjb3Jkc193aWRlJGZpcnN0X2NvbnN0cnVjdCksICJbOnNwYWNlOl0rIiwgIiAiKSkNCmBgYA0KDQpGaXJzdCBFQlNDTyBzY3JhcGUgb2YgQVBBIFBzeWNJbmZvDQpgYGB7cn0NCnBzeWNpbmZvIDwtIHJlYWRfdHN2KCcuLi9zb2Jlcl9ydWJyaWMvcmF3X2RhdGEvbWVyZ2VkX3RhYmxlX2FsbC50c3YnKSAlPiUgDQogICMgdGhpcyB0c3YgY2FuIGJlIGZvdW5kIGluICJTY3JhcGluZy1FQlNDTy1Ib3N0XGRhdGFcbWVyZ2VkIHRhYmxlcyINCiMgIG11dGF0ZShOYW1lID0gdG9UaXRsZUNhc2UoTmFtZSkpICU+JSANCiAgcmVuYW1lKHVzYWdlX2NvdW50ID0gIkhpdCBDb3VudCIpICU+JSANCiAgZ3JvdXBfYnkoTmFtZSwgWWVhcikgJT4lIA0KICBzdW1tYXJpc2UodXNhZ2VfY291bnQgPSBzdW0odXNhZ2VfY291bnQpKQ0KYGBgDQoNCg0KU2Vjb25kIEVCU0NPIHNjcmFwZSBvZiBBUEEgUHN5Y0luZm8NCmBgYHtyfQ0Kb3ZlcnZpZXcgPC0gcmVhZHI6OnJlYWRfdHN2KCIuLi9zb2Jlcl9ydWJyaWMvcmF3X2RhdGEvMjAyMzA2MTdfZWJzY29fc2NyYXBlX2NsZWFuX292ZXJ2aWV3X3RhYmxlXzEudHN2IikNCmJ5eWVhciA8LSByZWFkcjo6cmVhZF90c3YoIi4uL3NvYmVyX3J1YnJpYy9yYXdfZGF0YS8yMDIzMDYxN19lYnNjb19zY3JhcGVfdGFibGVfeWVhcnNfMS50c3YiKQ0Kbl9kaXN0aW5jdChieXllYXIkRE9JKQ0KDQpvdmVydmlldyAlPiUgZmlsdGVyKGlzLm5hKEhpdHMpKSAlPiUgbnJvdygpDQpucm93KG92ZXJ2aWV3KQ0Kb3ZlcnZpZXcgJT4lIGZpbHRlcihIaXRzID49IDEpICU+JSBucm93KCkNCg0Kb25lX2hpdF93b25kZXJzIDwtIG92ZXJ2aWV3ICU+JSBmaWx0ZXIoSGl0cyA9PSAxKSAlPiUgDQogIG11dGF0ZShZZWFyID0gZmlyc3RfcHViX3llYXIpDQoNCm5yb3cob25lX2hpdF93b25kZXJzKQ0KIyBmb3Igc29tZSBmZXcsIHRoZSBjYWxsIHdhcyByZXBlYXRlZCBieSB5ZWFyIGZvciBzb21lIHJlYXNvbg0KIyBvbmVfaGl0X3dvbmRlcnMgJT4lIHNlbGVjdChET0ksIGZpcnN0X3B1Yl95ZWFyKSAlPiUgaW5uZXJfam9pbihieXllYXIsIGJ5ID0gIkRPSSIpICU+JSBhcnJhbmdlKERPSSkNCg0KYnl5ZWFyIDwtIGJ5eWVhciAlPiUgYW50aV9qb2luKG9uZV9oaXRfd29uZGVycywgYnkgPSAiRE9JIikNCg0KYWxsIDwtIG9uZV9oaXRfd29uZGVycyAlPiUgDQogIHNlbGVjdChET0ksIFllYXIsIEhpdHMpICU+JSANCiAgYmluZF9yb3dzKGJ5eWVhcikgJT4lIA0KICBsZWZ0X2pvaW4ob3ZlcnZpZXcgJT4lIHJlbmFtZSh0b3RhbF9oaXRzID0gSGl0cyksIGJ5ID0gIkRPSSIpDQoNCm5fZGlzdGluY3QoYWxsJERPSSkNCmFsbCAlPiUgZmlsdGVyKEhpdHMgPiAwKSAlPiUgZmlsdGVyKFllYXIgPCBmaXJzdF9wdWJfeWVhciB8IFllYXIgPiBsYXN0X3B1Yl95ZWFyKSAlPiUgbnJvdygpDQphbGwgJT4lIGdyb3VwX2J5KHRvdGFsX2hpdHMsIERPSSkgJT4lIHN1bW1hcmlzZShoaXRzX2J5X3llYXIgPSBzdW0oSGl0cywgbmEucm0gPSBUKSkgJT4lIGZpbHRlcihoaXRzX2J5X3llYXIgPiB0b3RhbF9oaXRzKSAlPiUgdW5ncm91cCgpICU+JSBzZWxlY3QoRE9JLCBldmVyeXRoaW5nKCkpICU+JSBtdXRhdGUoZGlmZiA9IGhpdHNfYnlfeWVhciAtIHRvdGFsX2hpdHMpICU+JSBucm93KCkNCiMgYWxsICU+JSBncm91cF9ieSh0b3RhbF9oaXRzLCBET0kpICU+JSBzdW1tYXJpc2UoaGl0c19ieV95ZWFyID0gc3VtKHVzYWdlX2NvdW50LCBuYS5ybSA9IFQpKSAlPiUgZmlsdGVyKGhpdHNfYnlfeWVhciA8IHRvdGFsX2hpdHMpICU+JSBzZWxlY3QoRE9JLCBldmVyeXRoaW5nKCkpICU+JSBtdXRhdGUoZGlmZiA9IGhpdHNfYnlfeWVhciAtIHRvdGFsX2hpdHMpICU+JSAgVmlldygpDQphbGwgJT4lIGdyb3VwX2J5KHRvdGFsX2hpdHMsIERPSSkgJT4lIHN1bW1hcmlzZShoaXRzX2J5X3llYXIgPSBzdW0oSGl0cywgbmEucm0gPSBUKSkgJT4lIGZpbHRlcihoaXRzX2J5X3llYXIgPT0gdG90YWxfaGl0cykgJT4lIG5yb3coKQ0KYWxsICU+JSBncm91cF9ieShET0kpICU+JSBzdW1tYXJpc2UoaGl0c19ieV95ZWFyID0gc3VtKEhpdHMsIG5hLnJtID0gVCkpICU+JSBmaWx0ZXIoaGl0c19ieV95ZWFyID09IDApDQphbGwgJT4lIGdyb3VwX2J5KHRvdGFsX2hpdHMsIERPSSkgJT4lIHN1bW1hcmlzZShoaXRzX2J5X3llYXIgPSBzdW0oSGl0cywgbmEucm0gPSBUKSkgJT4lIGZpbHRlcihpcy5uYSh0b3RhbF9oaXRzKSkgJT4lIHB1bGwoaGl0c19ieV95ZWFyKSAlPiUgdGFibGUoKQ0KDQpwc3ljdGVzdHNfaW5mbyA8LSByZWNvcmRzX3dpZGUgJT4lIA0KICBzZWxlY3QoRE9JLCBUZXN0WWVhciwgTmFtZSwgZmlyc3RfY29uc3RydWN0LCANCiAgICAgICAgIG9yaWdpbmFsX3Rlc3RfRE9JLCBvcmlnaW5hbF9ET0lfY29tYmluZWQsIA0KICAgICAgICAgdGVzdF90eXBlLCBDb25zdHJ1Y3RMaXN0LCBzdWJkaXNjaXBsaW5lXzEsIHN1YmRpc2NpcGxpbmVfMiwgDQogICAgICAgICBjbGFzc2lmaWNhdGlvbl8xLCBjbGFzc2lmaWNhdGlvbl8yLCBpbnN0cnVtZW50X3R5cGVfYnJvYWQsIA0KICAgICAgICAgSW5zdHJ1bWVudFR5cGUsDQogICAgICAgICBudW1iZXJfb2ZfZmFjdG9yc19zdWJzY2FsZXMsIE5hbWVfYmFzZSkgJT4lDQogIGRpc3RpbmN0KCkgJT4lIA0KICBpbm5lcl9qb2luKGFsbCwgYnkgPSBjKCJET0kiID0gIkRPSSIpLCBtdWx0aXBsZSA9ICJhbGwiKSAlPiUgDQogIHJlbmFtZSh1c2FnZV9jb3VudCA9ICJIaXRzIikNCg0KDQp3cml0ZV9yZHMocHN5Y3Rlc3RzX2luZm8sICIuLi9zb2Jlcl9ydWJyaWMvcmF3X2RhdGEvcHN5Y3Rlc3RzX2luZm8ucmRzIikNCmBgYA0KDQo8L2RldGFpbHM+DQoNCiMgMjAxNiBjaGFuZ2VzIGluIHN0YW5kYXJkcw0KYGBge3J9DQp0ZXN0X2RhdGEgPC0gcmVjb3Jkc193aWRlICU+JQ0KICBmaWx0ZXIoVGVzdFllYXIgPD0gMjAyMikgJT4lDQogICAgcm93d2lzZSgpICU+JQ0KICAgIG11dGF0ZShNZXRob2RvbG9neSA9IGxlbmd0aChNZXRob2RvbG9neUxpc3QpID4wKSAlPiUNCiAgICBtdXRhdGUoQWRtaW5pc3RyYXRpb25NZXRob2QgPSBsZW5ndGgoQWRtaW5pc3RyYXRpb25NZXRob2RMaXN0KSA+MCkgJT4lDQogICAgbXV0YXRlKFBvcHVsYXRpb25Hcm91cCA9IGxlbmd0aChQb3B1bGF0aW9uR3JvdXBMaXN0KSA+MCkgJT4lDQogICAgbXV0YXRlKEFnZUdyb3VwID0gbGVuZ3RoKEFnZUdyb3VwTGlzdCkgPjApICU+JQ0KICAgIGdyb3VwX2J5KFRlc3RZZWFyKSAlPiUNCiAgICBzdW1tYXJpc2UoUmVsaWFiaWxpdHkgPSBtZWFuKFJlbGlhYmlsaXR5IT0iTm8gcmVsaWFiaWxpdHkgaW5kaWNhdGVkLiIpLA0KICAgICAgICAgICAgICBGYWN0b3JBbmFseXNpcyA9IG1lYW4oRmFjdG9yQW5hbHlzaXMhPSJObyBmYWN0b3IgYW5hbHlzaXMgaW5kaWNhdGVkLiIpLA0KICAgICAgICAgICAgICAjIFVuaWRpbWVuc2lvbmFsID0gbWVhbihGYWN0b3JBbmFseXNpcz09IlRoaXMgaXMgYSB1bmlkaW1lbnNpb25hbCBtZWFzdXJlLiIpLA0KICAgICAgICAgICAgICBGYWN0b3JzQW5kU3Vic2NhbGVzID0gbWVhbighaXMubmEoRmFjdG9yc0FuZFN1YnNjYWxlcykpLA0KICAgICAgICAgICAgICBWYWxpZGl0eSA9IG1lYW4oVmFsaWRpdHkhPSJObyB2YWxpZGl0eSBpbmRpY2F0ZWQuIiksDQogICAgICAgICAgICAgIEZvcm1hdCA9IG1lYW4oIWlzLm5hKEZvcm1hdCkpLA0KICAgICAgICAgICAgICAjIEZlZSA9IG1lYW4oRmVlID09ICJZZXMiKSwNCiAgICAgICAgICAgICAgTWV0aG9kb2xvZ3kgPSBtZWFuKE1ldGhvZG9sb2d5KSwNCiAgICAgICAgICAgICAgQWRtaW5pc3RyYXRpb25NZXRob2QgPSBtZWFuKEFkbWluaXN0cmF0aW9uTWV0aG9kKSwNCiAgICAgICAgICAgICAgIyBBZ2VHcm91cCA9IG1lYW4oQWdlR3JvdXApLA0KICAgICAgICAgICAgICAjIFBvcHVsYXRpb25Hcm91cCA9IG1lYW4oUG9wdWxhdGlvbkdyb3VwKSwNCiAgICAgICAgICAgICAgVGVzdEl0ZW1zID0gbWVhbihUZXN0SXRlbXNBdmFpbGFibGUgPT0gIlllcyIpKSAlPiUNCiAgICBwaXZvdF9sb25nZXIoLVRlc3RZZWFyKQ0KdGVzdF9kYXRhICU+JQ0KICBnZ3Bsb3QoYWVzKFRlc3RZZWFyLCB2YWx1ZSwgY29sb3IgPSBuYW1lKSkgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAyMDE2LCBsaW5ldHlwZSA9ICdkYXNoZWQnKSArDQogIGdlb21fbGluZSgpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKCJQdWJsaWNhdGlvbiB5ZWFyIGluIEFQQSBQc3ljVGVzdHMiLA0KICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygxOTkzLCAyMDMwKSwNCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNlcSgxOTkzLCAyMDIyLCBieSA9IDEpLA0KICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygxOTkzLCAiIiwgIiIsICIiLCAiIiwgMTk5OCwgIiIsICIiLCAiIiwgIiIsIDIwMDMsICIiLCAiIiwgIiIsICIiLCAyMDA4LCAiIiwgIiIsICIiLCAiIiwgMjAxMywgIiIsICIiLCAiIiwgIiIsIDIwMTgsICIiLCAiIiwgIiIsICIyMDIyIiksDQogICAgICAgICAgICAgICAgICAgICBleHBhbmQgPSBleHBhbnNpb24oYWRkID0gYygwLCAxLjIpKSkgKw0KICBzY2FsZV9jb2xvcl9icmV3ZXIodHlwZSA9ICJxdWFsIiwgZ3VpZGUgPSAibm9uZSIsIHBhbGV0dGUgPSAyKSArDQogIGdlb21fdGV4dF9yZXBlbCgNCiAgICBkYXRhID0gdGVzdF9kYXRhICU+JSBkcm9wX25hKCkgJT4lIGdyb3VwX2J5KG5hbWUpICU+JSBmaWx0ZXIoVGVzdFllYXIgPT0gbWF4KFRlc3RZZWFyLCBuYS5ybSA9IFQpKSwNCiAgICBhZXMobGFiZWwgPSBuYW1lKSwNCiAgICBzZWdtZW50LmNvbG9yID0gJ2dyZXknLA0KICAgIHhsaW0gPSBjKDIwMjIsIDIwMzMpLA0KICAgIGJveC5wYWRkaW5nID0gMC4xLA0KICAgICMgcG9pbnQucGFkZGluZyA9IDAuNiwNCiAgICBudWRnZV94ID0gMS4yLA0KICAgICMgbnVkZ2VfeSA9IDAsDQogICAgZm9yY2UgPSAwLjUsDQogICAgaGp1c3QgPSAwLA0KICAgIGRpcmVjdGlvbj0ieSIsDQogICAgbmEucm0gPSBUUlVFDQogICkgKw0KICB5bGFiKCJQc3ljVGVzdHMgY29udGFpbnMgaW5mb3JtYXRpb24gYWJvdXQuLi4iKSArDQogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vci54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwbG90LnRpdGxlLnBvc2l0aW9uID0gInBsb3QiLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2U9ImJvbGQiKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KZ2dzYXZlKCJmaWd1cmVzL2NoYW5nZWRfc3RhbmRhcmRzXzIwMTYucGRmIiwgd2lkdGggPSA4LCBoZWlnaHQgPSA0KQ0KZ2dzYXZlKCJmaWd1cmVzL2NoYW5nZWRfc3RhbmRhcmRzXzIwMTYucG5nIiwgd2lkdGggPSA4LCBoZWlnaHQgPSA0KQ0KYGBgDQoNCg0KYGBge3J9DQpyZWNvcmRzX3dpZGUgJT4lIA0KICBncm91cF9ieShUZXN0WWVhcikgJT4lIA0KICBzdW1tYXJpc2UobnVtYmVyX29mX3Rlc3RfaXRlbXMgPSBtZWFuKG51bWJlcl9vZl90ZXN0X2l0ZW1zLCBuYS5ybSA9IFQpKSAlPiUgDQogIGZpbHRlcihUZXN0WWVhciA+PSAxOTkzLCBUZXN0WWVhciA8PSAyMDIyKSAlPiUgDQpnZ3Bsb3QoYWVzKFRlc3RZZWFyLCBudW1iZXJfb2ZfdGVzdF9pdGVtcykpICsgDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDIwMTYsIGxpbmV0eXBlID0gJ2Rhc2hlZCcpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoIlB1YmxpY2F0aW9uIHllYXIgaW4gQVBBIFBzeWNUZXN0cyIsDQogICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKDE5OTMsIE5BKSwgDQogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzZXEoMTk5MywgMjAyMiwgYnkgPSAxKSwNCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoMTk5MywgIiIsICIiLCAiIiwgIiIsIDE5OTgsICIiLCAiIiwgIiIsICIiLCAyMDAzLCAiIiwgIiIsICIiLCAiIiwgMjAwOCwgIiIsICIiLCAiIiwgIiIsIDIwMTMsICIiLCAiIiwgIiIsICIiLCAyMDE4LCAiIiwgIiIsICIiLCAiMjAyMiIpKSArDQogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vci54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwbG90LnRpdGxlLnBvc2l0aW9uID0gInBsb3QiLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2U9ImJvbGQiKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArDQogIHhsYWIoIlB1YmxpY2F0aW9uIHllYXIgaW4gQVBBIFBzeWNUZXN0cyIpICsNCiAgeWxhYigiTnVtYmVyIG9mIGl0ZW1zIGluIG1lYXN1cmUiKQ0KYGBgDQoNCg0KYGBge3J9DQpyZWNvcmRzX3dpZGUgJT4lIA0KICBmaWx0ZXIoVGVzdFllYXIgPj0gMTk5MywgVGVzdFllYXIgPD0gMjAyMikgJT4lIA0KZ2dwbG90KGFlcyhUZXN0WWVhciwgbnVtYmVyX29mX2ZhY3RvcnNfc3Vic2NhbGVzKSkgKyANCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMjAxNiwgbGluZXR5cGUgPSAnZGFzaGVkJykgKw0KICBnZW9tX3BvaW50cmFuZ2Uoc3RhdCA9ICdzdW1tYXJ5JywgZnVuLmRhdGEgPSAnbWVhbl9zZScpICsNCiAgeGxpbSgxOTkzLCAyMDIyKSArDQogIHhsYWIoIlB1YmxpY2F0aW9uIHllYXIgaW4gQVBBIFBzeWNUZXN0cyIpICsNCiAgeWxhYigiTnVtYmVyIG9mIGZhY3RvcnMvc3Vic2NhbGVzIikNCmBgYA0KDQoNCmBgYHtyfQ0KcmVjb3Jkc193aWRlICU+JSANCiAgZ3JvdXBfYnkoSW5zdHJ1bWVudFR5cGUsIFRlc3RZZWFyKSAlPiUgDQogIHN1bW1hcmlzZSh0ZXN0cyA9IG4oKSkgJT4lIA0KICBncm91cF9ieShUZXN0WWVhcikgJT4lIA0KICBtdXRhdGUodGVzdHMgPSB0ZXN0cy9zdW0odGVzdHMsIG5hLnJtID0gVCkpICU+JSANCiAgYXJyYW5nZShUZXN0WWVhcikgJT4lIA0KICBmaWx0ZXIoVGVzdFllYXIgPj0gMTk5MywgVGVzdFllYXIgPD0gMjAyMikgJT4lIA0KICAjIG11dGF0ZSh0ZXN0cyA9IGN1bXN1bSh0ZXN0cykpICU+JSANCiAgZ2dwbG90KGFlcyhUZXN0WWVhciwgdGVzdHMsIGNvbG9yID0gSW5zdHJ1bWVudFR5cGUpKSArIA0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAyMDE2LCBsaW5ldHlwZSA9ICdkYXNoZWQnKSArDQogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfZCgpICsNCiAgZ2VvbV9saW5lKCkgKw0KICB4bGltKDE5OTMsIDIwMjIpICsNCiAgeGxhYigiUHVibGljYXRpb24geWVhciBpbiBBUEEgUHN5Y1Rlc3RzIikgKw0KICB5bGFiKCJQcm9wb3J0aW9uIG9mIGluc3RydW1lbnQgdHlwZSIpDQpgYGANCg0KDQpgYGB7cn0NCnJlY29yZHNfd2lkZSAlPiUgDQogICMgZmlsdGVyKGluc3RydW1lbnRfdHlwZV9icm9hZCAhPSkNCiAgZ3JvdXBfYnkoaW5zdHJ1bWVudF90eXBlX2Jyb2FkLCBUZXN0WWVhcikgJT4lIA0KICBzdW1tYXJpc2UodGVzdHMgPSBuKCkpICU+JSANCiAgZ3JvdXBfYnkoVGVzdFllYXIpICU+JSANCiAgbXV0YXRlKHRlc3RzID0gdGVzdHMvc3VtKHRlc3RzLCBuYS5ybSA9IFQpKSAlPiUgDQogIGFycmFuZ2UoVGVzdFllYXIpICU+JSANCiAgZmlsdGVyKFRlc3RZZWFyID49IDE5OTMsIFRlc3RZZWFyIDw9IDIwMjIpICU+JSANCiAgIyBtdXRhdGUodGVzdHMgPSBjdW1zdW0odGVzdHMpKSAlPiUgDQogIGdncGxvdChhZXMoVGVzdFllYXIsIHRlc3RzLCBjb2xvciA9IGluc3RydW1lbnRfdHlwZV9icm9hZCkpICsgDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDIwMTYsIGxpbmV0eXBlID0gJ2Rhc2hlZCcpICsNCiAgZ2VvbV9saW5lKCkgKw0KICB4bGltKDE5OTMsIDIwMjIpICsNCiAgeGxhYigiUHVibGljYXRpb24geWVhciBpbiBBUEEgUHN5Y1Rlc3RzIikgKw0KICB5bGFiKCJQcm9wb3J0aW9uIG9mIGluc3RydW1lbnQgdHlwZSIpDQpgYGANCg0KDQpgYGB7cn0NCnJlY29yZHNfd2lkZSAlPiUgDQogIGZpbHRlcihpbnN0cnVtZW50X3R5cGVfYnJvYWQgIT0gInF1ZXN0aW9ubmFpcmUiKSAlPiUgDQogIGdyb3VwX2J5KEluc3RydW1lbnRUeXBlLCBUZXN0WWVhcikgJT4lIA0KICBzdW1tYXJpc2UodGVzdHMgPSBuKCkpICU+JSANCiAgZ3JvdXBfYnkoVGVzdFllYXIpICU+JSANCiAgbXV0YXRlKHRlc3RzID0gdGVzdHMvc3VtKHRlc3RzLCBuYS5ybSA9IFQpKSAlPiUgDQogIGFycmFuZ2UoVGVzdFllYXIpICU+JSANCiAgZmlsdGVyKFRlc3RZZWFyID49IDE5OTMsIFRlc3RZZWFyIDw9IDIwMjIpICU+JSANCiAgIyBtdXRhdGUodGVzdHMgPSBjdW1zdW0odGVzdHMpKSAlPiUgDQogIGdncGxvdChhZXMoVGVzdFllYXIsIHRlc3RzLCBjb2xvciA9IEluc3RydW1lbnRUeXBlKSkgKyANCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMjAxNiwgbGluZXR5cGUgPSAnZGFzaGVkJykgKw0KICBnZW9tX2xpbmUoKSArDQogIHhsaW0oMTk5MywgMjAyMikgKw0KICB4bGFiKCJQdWJsaWNhdGlvbiB5ZWFyIGluIEFQQSBQc3ljVGVzdHMiKSArDQogIHlsYWIoIlByb3BvcnRpb24gb2YgaW5zdHJ1bWVudCB0eXBlIikgKw0KICBnZ3RpdGxlKCJXaXRob3V0IHF1ZXN0aW9ubmFpcmVzIikNCmBgYA0KDQoNCmBgYHtyfQ0KcHN5Y3Rlc3RzX2luZm8gJT4lIGdyb3VwX2J5KERPSSwgVGVzdFllYXIpICU+JSANCiAgc3VtbWFyaXNlKHVzZWQgPSBzdW0odXNhZ2VfY291bnQsIG5hLnJtID0gVCkpICU+JSANCiAgZnVsbF9qb2luKHJlY29yZHNfd2lkZSAlPiUgc2VsZWN0KERPSSwgVGVzdFllYXIpKSAlPiUgDQogIG11dGF0ZSh1c2VkID0gY29hbGVzY2UodXNlZCwgMCkpICU+JSANCiAgZmlsdGVyKFRlc3RZZWFyID49IDE5OTMsIFRlc3RZZWFyIDw9IDIwMjIpICU+JSANCiAgZ3JvdXBfYnkoVGVzdFllYXIpICU+JSANCiAgc3VtbWFyaXNlKG5ldmVyX3JldXNlZCA9IG1lYW4odXNlZCA9PSAwKSwNCiAgICAgICAgICAgIHVzZWRfb25jZSA9IG1lYW4odXNlZCA9PSAxKSwNCiAgICAgICAgICAgIHVzZWRfdHdpY2UgPSBtZWFuKHVzZWQgPT0gMiksDQogICAgICAgICAgICB1c2VkX3RocmljZSA9IG1lYW4odXNlZCA9PSAzKSwNCiAgICAgICAgICAgIHVzZWRfbW9yZV8xMCA9IG1lYW4odXNlZCA+IDkpKSAlPiUgDQogIHBpdm90X2xvbmdlcigtVGVzdFllYXIpICU+JSANCiAgZ2dwbG90KGFlcyhUZXN0WWVhciwgdmFsdWUsIGNvbG9yID0gbmFtZSkpICsgDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDIwMTYsIGxpbmV0eXBlID0gJ2Rhc2hlZCcpICsNCiAgZ2VvbV9saW5lKCkgKw0KICB4bGltKDE5OTMsIDIwMjIpICsNCiAgeGxhYigiUHVibGljYXRpb24geWVhciBpbiBBUEEgUHN5Y1Rlc3RzIikgKw0KICB5bGFiKCJGcmVxdWVuY3kiKQ0KYGBgDQoNCiMgTmV3IG1lYXN1cmVzIGJ5IHB1YmxpY2F0aW9uIHllYXINCmBgYHtyfQ0KY291bnRfYWxsIDwtIHJlY29yZHNfd2lkZSAlPiUgDQogIGdyb3VwX2J5KFRlc3RZZWFyKSAlPiUgDQogIHN1bW1hcmlzZSh0ZXN0cyA9IG4oKSkgJT4lIA0KICBhcnJhbmdlKFRlc3RZZWFyKQ0KDQpjb3VudF9vcmlnIDwtIHJlY29yZHNfd2lkZSAlPiUgDQogIGZpbHRlcih0ZXN0X3R5cGUgPT0gIk9yaWdpbmFsIikgJT4lIA0KICBncm91cF9ieShUZXN0WWVhcikgJT4lIA0KICBzdW1tYXJpc2UodGVzdHMgPSBuKCkpICU+JSANCiAgYXJyYW5nZShUZXN0WWVhcikNCg0KY291bnRfYmFzZSA8LSByZWNvcmRzX3dpZGUgJT4lIA0KICBhcnJhbmdlKFRlc3RZZWFyKSAlPiUgDQogIGRpc3RpbmN0KE5hbWVfYmFzZSwgLmtlZXBfYWxsID0gVCkgJT4lIA0KICBncm91cF9ieShUZXN0WWVhcikgJT4lIA0KICBzdW1tYXJpc2UodGVzdHMgPSBuX2Rpc3RpbmN0KERPSSkpDQoNCmNvdW50X2NvbnN0cnVjdCA8LSByZWNvcmRzX3dpZGUgJT4lIA0KICBhcnJhbmdlKFRlc3RZZWFyKSAlPiUgDQogIGRpc3RpbmN0KGZpcnN0X2NvbnN0cnVjdCwgLmtlZXBfYWxsID0gVCkgJT4lIA0KICBncm91cF9ieShUZXN0WWVhcikgJT4lIA0KICBzdW1tYXJpc2UodGVzdHMgPSBuX2Rpc3RpbmN0KGZpcnN0X2NvbnN0cnVjdCkpICU+JSANCiAgYXJyYW5nZShUZXN0WWVhcikNCg0KY291bnRzIDwtIGJpbmRfcm93cygNCiAgIm5vdmVsIGNvbnN0cnVjdHMiID0gY291bnRfY29uc3RydWN0LA0KICAibm92ZWwgbWVhc3VyZXMiID0gY291bnRfb3JpZywNCiAgIndpdGggdHJhbnNsYXRpb25zXG4gYW5kIHJldmlzaW9ucyIgPSBjb3VudF9hbGwsDQogIC5pZCA9ICJvcmlnaW4iDQogICkgJT4lIA0KICByZW5hbWUoWWVhciA9IFRlc3RZZWFyKSAlPiUgDQogIGZpbHRlcihZZWFyIDw9IDIwMjIpDQoNCg0KZ2dwbG90KGNvdW50cywgYWVzKFllYXIsIHRlc3RzLCBjb2xvciA9IG9yaWdpbikpICsgDQogIGdlb21fbGluZSgpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMjAxNiwgbGluZXR5cGUgPSAnZGFzaGVkJykgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoIk51bWJlciBvZiBtZWFzdXJlcy9jb25zdHJ1Y3RzIHB1Ymxpc2hlZCIpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKCJQdWJsaWNhdGlvbiB5ZWFyIGluIEFQQSBQc3ljVGVzdHMiLA0KICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygxOTkzLCAyMDMwKSwgDQogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzZXEoMTk5MywgMjAyMiwgYnkgPSAxKSwNCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoMTk5MywgIiIsICIiLCAiIiwgIiIsIDE5OTgsICIiLCAiIiwgIiIsICIiLCAyMDAzLCAiIiwgIiIsICIiLCAiIiwgMjAwOCwgIiIsICIiLCAiIiwgIiIsIDIwMTMsICIiLCAiIiwgIiIsICIiLCAyMDE4LCAiIiwgIiIsICIiLCAiMjAyMiIpKSArDQogIHNjYWxlX2NvbG9yX2JyZXdlcih0eXBlID0gInF1YWwiLCBndWlkZSA9ICJub25lIiwgcGFsZXR0ZSA9IDIpICsNCiAgIyBnZ3JlcGVsOjpnZW9tX3RleHRfcmVwZWwoDQogICMgICBhZXMobGFiZWwgPSBzdHJfcmVwbGFjZShzdWJkaXNjaXBsaW5lLCAiIFBzeWNob2xvZ3kiLCAiIikpLCBkYXRhID0gZW50cm9weV9ieV95ZWFyICU+JSBmaWx0ZXIoWWVhciA9PSBtYXgoWWVhciwgbmEucm0gPSBUKSksDQogICMgICBzaXplID0gNCwgaGp1c3QgPSAxLA0KICAjICAgKSArDQogIGdlb21fdGV4dF9yZXBlbChkYXRhID0gY291bnRzICU+JSBkcm9wX25hKCkgJT4lIGdyb3VwX2J5KG9yaWdpbikgJT4lIGZpbHRlcihZZWFyID09IG1heChZZWFyLCBuYS5ybSA9IFQpKSwNCiAgICAgICAgICAgICAgICAgIGFlcyhsYWJlbCA9IHBhc3RlMCgiICIsIG9yaWdpbikpLA0KICAgICAgICAgICAgICAgICAgc2VnbWVudC5jdXJ2YXR1cmUgPSAtMC4xLA0KICAgICAgICAgICAgICAgICAgc2VnbWVudC5zcXVhcmUgPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgbGluZWhlaWdodCA9IC45LA0KICAgICAgICAgICAgICAgICAgIyBzZWdtZW50LmNvbG9yID0gJ2dyZXknLA0KICAgICAgICAgICAgICAgICAgYm94LnBhZGRpbmcgPSAwLjEsDQogICAgICAgICAgICAgICAgICBwb2ludC5wYWRkaW5nID0gMC42LA0KICAgICAgICAgICAgICAgICAgbnVkZ2VfeCA9IDEuNSwNCiAgICAgICAgICAgICAgICAgIG51ZGdlX3kgPSAtMTUsDQogICAgICAgICAgICAgICAgICBmb3JjZSA9IDEsDQogICAgICAgICAgICAgICAgICBoanVzdCA9IDAsDQogICAgICAgICAgICAgICAgICBkaXJlY3Rpb249InkiLA0KICAgICAgICAgICAgICAgICAgbmEucm0gPSBGKSArDQogICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yLnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGxvdC50aXRsZS5wb3NpdGlvbiA9ICJwbG90IiwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlPSJib2xkIiksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCg0KZ2dzYXZlKCJmaWd1cmVzL2NvdW50cy5wZGYiLCB3aWR0aCA9IDgsIGhlaWdodCA9IDQpDQpnZ3NhdmUoImZpZ3VyZXMvY291bnRzLnBuZyIsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNCkNCmBgYA0KDQoNCg0KIyBDdW11bGF0aXZlIG51bWJlciBvZiBtZWFzdXJlcyBhbmQgY29uc3RydWN0cw0KYGBge3J9DQpjdW1zdW1fYWxsIDwtIHJlY29yZHNfd2lkZSAlPiUgDQogIGdyb3VwX2J5KFRlc3RZZWFyKSAlPiUgDQogIHN1bW1hcmlzZSh0ZXN0cyA9IG4oKSkgJT4lIA0KICBhcnJhbmdlKFRlc3RZZWFyKSAlPiUgDQogIG11dGF0ZSh0ZXN0cyA9IGN1bXN1bSh0ZXN0cykpIA0KDQpjdW1zdW1fb3JpZyA8LSByZWNvcmRzX3dpZGUgJT4lIA0KICBmaWx0ZXIodGVzdF90eXBlID09ICJPcmlnaW5hbCIpICU+JSANCiAgZ3JvdXBfYnkoVGVzdFllYXIpICU+JSANCiAgc3VtbWFyaXNlKHRlc3RzID0gbigpKSAlPiUgDQogIGFycmFuZ2UoVGVzdFllYXIpICU+JSANCiAgbXV0YXRlKHRlc3RzID0gY3Vtc3VtKHRlc3RzKSkgDQoNCmN1bXN1bV9iYXNlIDwtIHJlY29yZHNfd2lkZSAlPiUgDQogIGFycmFuZ2UoVGVzdFllYXIpICU+JSANCiAgZGlzdGluY3QoTmFtZV9iYXNlLCAua2VlcF9hbGwgPSBUKSAlPiUgDQogIGdyb3VwX2J5KFRlc3RZZWFyKSAlPiUgDQogIHN1bW1hcmlzZSh0ZXN0cyA9IG5fZGlzdGluY3QoRE9JKSkgJT4lIA0KICBtdXRhdGUodGVzdHMgPSBjdW1zdW0odGVzdHMpKSANCg0KY3Vtc3VtX2NvbnN0cnVjdCA8LSByZWNvcmRzX3dpZGUgJT4lIA0KICBhcnJhbmdlKFRlc3RZZWFyKSAlPiUgDQogIGRpc3RpbmN0KGZpcnN0X2NvbnN0cnVjdCwgLmtlZXBfYWxsID0gVCkgJT4lIA0KICBncm91cF9ieShUZXN0WWVhcikgJT4lIA0KICBzdW1tYXJpc2UodGVzdHMgPSBuX2Rpc3RpbmN0KERPSSkpICU+JSANCiAgYXJyYW5nZShUZXN0WWVhcikgJT4lIA0KICBtdXRhdGUodGVzdHMgPSBjdW1zdW0odGVzdHMpKSANCg0KY3Vtc3VtcyA8LSBiaW5kX3Jvd3MoDQogICJub3ZlbCBjb25zdHJ1Y3RzIiA9IGN1bXN1bV9jb25zdHJ1Y3QsDQogICJub3ZlbCBtZWFzdXJlcyIgPSBjdW1zdW1fb3JpZywNCiAgIndpdGggdHJhbnNsYXRpb25zXG4gYW5kIHJldmlzaW9ucyIgPSBjdW1zdW1fYWxsLA0KICAuaWQgPSAib3JpZ2luIg0KICApICU+JSANCiAgcmVuYW1lKFllYXIgPSBUZXN0WWVhcikgJT4lIA0KICBmaWx0ZXIoWWVhciA8PSAyMDIyKQ0KDQoNCmdncGxvdChjdW1zdW1zLCBhZXMoWWVhciwgdGVzdHMsIGNvbG9yID0gb3JpZ2luKSkgKyANCiAgZ2VvbV9saW5lKCkgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAyMDE2LCBsaW5ldHlwZSA9ICdkYXNoZWQnKSArDQogIHNjYWxlX3lfY29udGludW91cygiQ3VtdWxhdGl2ZSBudW1iZXIgb2YgbWVhc3VyZXMiKSArDQogIHNjYWxlX3hfY29udGludW91cygiUHVibGljYXRpb24geWVhciBpbiBBUEEgUHN5Y1Rlc3RzIiwNCiAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoMTk5MywgMjAzMCksIA0KICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc2VxKDE5OTMsMjAyMiwgYnkgPSAxKSwNCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoMTk5MywgIiIsICIiLCAiIiwgIiIsIDE5OTgsICIiLCAiIiwgIiIsICIiLCAyMDAzLCAiIiwgIiIsICIiLCAiIiwgMjAwOCwgIiIsICIiLCAiIiwgIiIsIDIwMTMsICIiLCAiIiwgIiIsICIiLCAyMDE4LCAiIiwgIiIsICIiLCAiMjAyMiIpLA0KICAgICAgICAgICAgICAgICAgICAgZXhwYW5kID0gZXhwYW5zaW9uKGFkZCA9IGMoMCwgMSkpKSArDQogIHNjYWxlX2NvbG9yX2JyZXdlcih0eXBlID0gInF1YWwiLCBndWlkZSA9ICJub25lIiwgcGFsZXR0ZSA9IDIpICsNCiAgIyBnZ3JlcGVsOjpnZW9tX3RleHRfcmVwZWwoDQogICMgICBhZXMobGFiZWwgPSBzdHJfcmVwbGFjZShzdWJkaXNjaXBsaW5lLCAiIFBzeWNob2xvZ3kiLCAiIikpLCBkYXRhID0gZW50cm9weV9ieV95ZWFyICU+JSBmaWx0ZXIoWWVhciA9PSBtYXgoWWVhciwgbmEucm0gPSBUKSksDQogICMgICBzaXplID0gNCwgaGp1c3QgPSAxLA0KICAjICAgKSAgKw0KICBnZW9tX3RleHRfcmVwZWwoZGF0YSA9IGN1bXN1bXMgJT4lIGRyb3BfbmEoKSAlPiUgZ3JvdXBfYnkob3JpZ2luKSAlPiUgZmlsdGVyKFllYXIgPT0gbWF4KFllYXIsIG5hLnJtID0gVCkpLA0KICAgICAgICAgICAgICAgICAgYWVzKGxhYmVsID0gcGFzdGUwKCIgIiwgb3JpZ2luLCAiXG4gKG4gPSAiLCB0ZXN0cywgIikiKSksDQogICAgICAgICAgICAgICAgICBzZWdtZW50LnNxdWFyZSA9IFRSVUUsDQogICAgICAgICAgICAgICAgICBsaW5laGVpZ2h0ID0gLjksDQogICAgICAgICAgICAgICAgICBzZWdtZW50LmNvbG9yID0gJ2dyZXknLA0KICAgICAgICAgICAgICAgICAgbnVkZ2VfeCA9IDEuMiwNCiAgICAgICAgICAgICAgICAgIGhqdXN0ID0gMCwNCiAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRSkgKw0KICAgIyB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDEzKSArDQogICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yLnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGxvdC50aXRsZS5wb3NpdGlvbiA9ICJwbG90IiwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlPSJib2xkIiksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgICsNCiAgICBndWlkZXMoDQogICAgeCA9IGd1aWRlX2F4aXMoY2FwID0gImJvdGgiKSwgIyBDYXAgYm90aCBlbmRzDQogICkNCmdnc2F2ZSgiZmlndXJlcy9jdW1zdW1zLnBkZiIsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNCkNCmdnc2F2ZSgiZmlndXJlcy9jdW1zdW1zLnBuZyIsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNCkNCmBgYA0KDQojIyBCeSBzdWJkaXNjaXBsaW5lDQpgYGB7ciBmaWcud2lkdGg9OCxmaWcuaGVpZ2h0PTd9DQpjdW1zdW1fYWxsIDwtIHJlY29yZHNfd2lkZSAlPiUgDQogIGdyb3VwX2J5KHN1YmRpc2NpcGxpbmVfMSwgVGVzdFllYXIpICU+JSANCiAgc3VtbWFyaXNlKHRlc3RzID0gbigpKSAlPiUgDQogIGFycmFuZ2UoVGVzdFllYXIpICU+JSANCiAgbXV0YXRlKHRlc3RzID0gY3Vtc3VtKHRlc3RzKSkgDQoNCg0KY3Vtc3VtX29yaWcgPC0gcmVjb3Jkc193aWRlICU+JSANCiAgZmlsdGVyKHRlc3RfdHlwZSA9PSAiT3JpZ2luYWwiKSAlPiUgDQogIGdyb3VwX2J5KHN1YmRpc2NpcGxpbmVfMSwgVGVzdFllYXIpICU+JSANCiAgc3VtbWFyaXNlKHRlc3RzID0gbigpKSAlPiUgDQogIGFycmFuZ2UoVGVzdFllYXIpICU+JSANCiAgbXV0YXRlKHRlc3RzID0gY3Vtc3VtKHRlc3RzKSkgDQoNCmN1bXN1bV9iYXNlIDwtIHJlY29yZHNfd2lkZSAlPiUgDQogIGFycmFuZ2UoVGVzdFllYXIpICU+JSANCiAgZGlzdGluY3QoTmFtZV9iYXNlLCAua2VlcF9hbGwgPSBUKSAlPiUgDQogIGdyb3VwX2J5KHN1YmRpc2NpcGxpbmVfMSwgVGVzdFllYXIpICU+JSANCiAgc3VtbWFyaXNlKHRlc3RzID0gbl9kaXN0aW5jdChET0kpKSAlPiUgDQogIG11dGF0ZSh0ZXN0cyA9IGN1bXN1bSh0ZXN0cykpIA0KDQpjdW1zdW1fY29uc3RydWN0IDwtIHJlY29yZHNfd2lkZSAlPiUgDQogIGFycmFuZ2UoVGVzdFllYXIpICU+JSANCiAgZGlzdGluY3QoZmlyc3RfY29uc3RydWN0LCAua2VlcF9hbGwgPSBUKSAlPiUgDQogIGdyb3VwX2J5KHN1YmRpc2NpcGxpbmVfMSwgVGVzdFllYXIpICU+JSANCiAgc3VtbWFyaXNlKHRlc3RzID0gbl9kaXN0aW5jdChET0kpKSAlPiUgDQogIGFycmFuZ2UoVGVzdFllYXIpICU+JSANCiAgbXV0YXRlKHRlc3RzID0gY3Vtc3VtKHRlc3RzKSkgDQoNCmN1bXN1bXMgPC0gYmluZF9yb3dzKA0KICAiY29uc3RydWN0cyIgPSBjdW1zdW1fY29uc3RydWN0LA0KICAibWVhc3VyZXMiID0gY3Vtc3VtX29yaWcsDQogICJ3aXRoIHRyYW5zbGF0aW9ucyAmIHJldmlzaW9ucyIgPSBjdW1zdW1fYWxsLA0KICAuaWQgPSAib3JpZ2luIg0KICApICU+JSANCiAgcmVuYW1lKFllYXIgPSBUZXN0WWVhcikgJT4lIA0KICBmaWx0ZXIoWWVhciA8PSAyMDIyKQ0KDQpjdW1zdW1zJG9yaWdpbiA8LSBmYWN0b3IoY3Vtc3VtcyRvcmlnaW4sIGxldmVscyA9IGMoIndpdGggdHJhbnNsYXRpb25zICYgcmV2aXNpb25zIiwgImNvbnN0cnVjdHMiLCAibWVhc3VyZXMiKSkNCm15X2NvbG9ycyA8LSBjKCJ3aXRoIHRyYW5zbGF0aW9ucyAmIHJldmlzaW9ucyIgPSAiIzc1NzBCMyIsDQogICAgICAgICAgICAgICAiY29uc3RydWN0cyIgPSAiIzFCOUU3NyIsIA0KICAgICAgICAgICAgICAgIm1lYXN1cmVzIiA9ICIjRDk1RjAyIikgDQoNCmdncGxvdChjdW1zdW1zLCBhZXMoWWVhciwgdGVzdHMsIGNvbG9yID0gb3JpZ2luKSkgKyANCiAgZ2VvbV9saW5lKCkgKw0KICBmYWNldF93cmFwKH4gc3ViZGlzY2lwbGluZV8xLCBzY2FsZXMgPSAiZnJlZV95IiwgbmNvbCA9IDIpICsgDQogIHNjYWxlX3lfY29udGludW91cygiQ3VtdWxhdGl2ZSBudW1iZXIgb2YgbWVhc3VyZXMiKSArDQogIHNjYWxlX3hfY29udGludW91cygiUHVibGljYXRpb24geWVhciBpbiBBUEEgUHN5Y1Rlc3RzIiwNCiAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoMTk5MywgMjAyMiksIA0KICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc2VxKDE5OTMsIDIwMjIsIGJ5ID0gMSksDQogICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKDE5OTMsICIiLCAiIiwgIiIsICIiLCAxOTk4LCAiIiwgIiIsICIiLCAiIiwgMjAwMywgIiIsICIiLCAiIiwgIiIsIDIwMDgsICIiLCAiIiwgIiIsICIiLCAyMDEzLCAiIiwgIiIsICIiLCAiIiwgMjAxOCwgIiIsICIiLCAiIiwgIjIwMjIiKSkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gbXlfY29sb3JzLCBndWlkZSA9IGd1aWRlX2xlZ2VuZCh0aXRsZSA9IE5VTEwpKSArDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTMpICsNCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vci55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5ncmlkLm1pbm9yLnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBsb3QudGl0bGUucG9zaXRpb24gPSAicGxvdCIsDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZT0iYm9sZCIpLA0KICAgICAgICBsZWdlbmQucG9zaXRpb24gPSBjKDAuNTgsIDAuMDgpLA0KICAgICAgICBsZWdlbmQuanVzdGlmaWNhdGlvbiA9IGMoMCwgMCksDQogICAgICAgIGxlZ2VuZC5ib3guanVzdCA9ICJyaWdodCIsDQogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMSkpDQoNCg0KDQpnZ3NhdmUoImZpZ3VyZXMvY3Vtc3Vtc19zdWJkaXNjaXBsaW5lLnBkZiIsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNykNCmdnc2F2ZSgiZmlndXJlcy9jdW1zdW1zX3N1YmRpc2NpcGxpbmUucG5nIiwgd2lkdGggPSA4LCBoZWlnaHQgPSA3KQ0KYGBgDQoNCg0KIyBUZXN0cyBieSB1c2FnZSBmcmVxdWVuY3kNCmBgYHtyfQ0KdGVzdF9mcmVxdWVuY3kgPC0gcHN5Y3Rlc3RzX2luZm8gJT4lIA0KICBtdXRhdGUoVGVzdCA9IGlmX2Vsc2UodGVzdF90eXBlID09ICJPcmlnaW5hbCIsIERPSSwgb3JpZ2luYWxfdGVzdF9ET0kpKSAlPiUgDQogIGRyb3BfbmEoVGVzdCkgJT4lIA0KICAjIGZpbHRlcihUZXN0WWVhciA+PSAxOTkwKSAlPiUNCiAgZmlsdGVyKGJldHdlZW4oWWVhciwgMTk5MywgMjAyMikpICU+JQ0KICBncm91cF9ieShUZXN0KSAlPiUgDQogIHN1bW1hcmlzZShuID0gc3VtKHVzYWdlX2NvdW50LCBuYS5ybSA9IFQpKSAlPiUgDQogIGFycmFuZ2UobikNCg0KdGVzdF9mcmVxdWVuY3kgPC0gcmVjb3Jkc193aWRlICU+JSANCiAgZmlsdGVyKHRlc3RfdHlwZSA9PSAiT3JpZ2luYWwiLCBUZXN0WWVhciA8PSAyMDIyKSAlPiUgDQogIHNlbGVjdChUZXN0ID0gRE9JKSAlPiUgDQogIGZ1bGxfam9pbih0ZXN0X2ZyZXF1ZW5jeSkgJT4lIA0KICBtdXRhdGUobiA9IGNvYWxlc2NlKG4sIDAuNSkpDQoNCnRlc3RfZnJlcXVlbmN5IDwtIHRlc3RfZnJlcXVlbmN5ICU+JSANCiAgZ3JvdXBfYnkobikgJT4lIA0KICBzdW1tYXJpc2UoY291bnQgPSBuKCkpICU+JSANCiAgdW5ncm91cCgpICU+JSANCiAgbXV0YXRlKHBlcmNlbnQgPSBjb3VudC9zdW0oY291bnQpKQ0KDQpmcmVxX3Bsb3QgPC0gZ2dwbG90KHRlc3RfZnJlcXVlbmN5LCBhZXMobiwgY291bnQpKSArIA0KICBnZW9tX2Jhcih3aWR0aCA9IDAuMSwgZmlsbCA9IGNvbG9yc1sibm92ZWwiXSwgc3RhdCA9ICJpZGVudGl0eSIpICsNCiAgIyBmYWNldF93cmFwKH4gc3ViZGlzY2lwbGluZV8xLCBzY2FsZXMgPSAiZnJlZV95IikgKyANCiAgIyBzY2FsZV95X3NxcnQoIk51bWJlciBvZiBtZWFzdXJlcyIsIGJyZWFrcyA9IGMoMCwgMTAwLCA0MDAsIDEwMDAsIDIwMDAsIDQwMDAsIDYwMDAsIDEwMDAwKSwgbGltaXRzID0gYygwLCAxMTUwMCkpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKCJOdW1iZXIgb2YgbWVhc3VyZXMiKSArDQogIHNjYWxlX3hfbG9nMTAoIlVzYWdlcyByZWNvcmRlZCBpbiBBUEEgUHN5Y0luZm8gMTk5My0yMDIyIiwNCiAgICAgICAgICAgICAgICBicmVha3MgPSBjKDAuNSwgMSwgMiwgNSwgMTAsIDEwMCwgMTAwMCwgMjUwMDApLA0KICAgICAgICAgICAgICAgbGFiZWxzID0gYygwLCAxLCAyLCA1LCAxMCwgMTAwLCAxMDAwLCAyNTAwMCkpICsNCiAgDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBpZl9lbHNlKG4gPD0gMiwgc3ByaW50ZigiJS4wZiUlIiwgcGVyY2VudCoxMDApLCAiIiksDQogICAgICAgICAgICAgICAgeCA9IG4sIHkgPSBjb3VudCArIDcwMCkpICsNCg0KICAjIHNjYWxlX3hfc3FydChicmVha3MgPSBjKDAsIDEsIDIsIDMsIDQsIDUsIDEwLCAyMCwgNDAsIDUwKSwgbGFiZWxzID0gYygwLCAxLCAyLCAzLCA0LCA1LCAxMCwgMjAsIDQwLCAiNTArIikpICsNCiAgIyBnZW9tX3RleHRfcmVwZWwoYWVzKHggPSBuLCBsYWJlbCA9IGZpcnN0X2Fjcm9ueW0sIHkgPSB5KSwgDQogICMgICAgICAgICAgICAgICAgIGRhdGEgPQ0KICAjICAgICAgICAgICAgICAgICAgIHRlc3RfZnJlcXVlbmN5ICU+JSBncm91cF9ieShzdWJkaXNjaXBsaW5lXzEpICU+JSBmaWx0ZXIocm93X251bWJlcigpID4gKG4oKSAtIDEwKSApICU+JSBsZWZ0X2pvaW4ocmVjb3Jkc193aWRlICU+JSBzZWxlY3QoVGVzdCA9IERPSSwgZmlyc3RfYWNyb255bSkpICU+JSANCiAgIyAgICAgICAgICAgICAgICAgICBtdXRhdGUoZmlyc3RfYWNyb255bSA9IGlmX2Vsc2UoZmlyc3RfYWNyb255bSA9PSAiSFJTRCIsICJIQU0tRCIsDQogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpcnN0X2Fjcm9ueW0pKSAlPiUgDQogICAgIyBtdXRhdGUoeSA9IDIwICsgNTAqKDErbigpLXJvd19udW1iZXIoKSkpLA0KICAgICMgICAgICAgICAgICAgICBzaXplID0gMy4zLCBmb3JjZSA9IDUsIGZvcmNlX3B1bGwJPSAwLCBtYXgudGltZSA9IDEsIA0KICAgICMgICAgICAgICAgICAgICBtYXgub3ZlcmxhcHMgPSBJbmYsDQogICAgIyAgICAgICAgICAgICAgIHNlZ21lbnQuY29sb3IgPSAibGlnaHRncmF5IiwNCiAgICAjICAgICAgICAgICAgICAgc2VnbWVudC5jdXJ2YXR1cmUgPSAxLA0KICAgICMgICAgICAgICAgICAgICBoanVzdCA9IDEsDQogICAgIyAgICAgICAgICAgICAgIG51ZGdlX3kgPSAxMCwNCiAgICAjICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gInkiDQogICAgIyApICsNCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxMykgKw0KICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yLnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGxvdC50aXRsZS5wb3NpdGlvbiA9ICJwbG90IiwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlPSJib2xkIiksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCmZyZXFfcGxvdA0KZ2dzYXZlKCJmaWd1cmVzL2ZyZXF1ZW5jeV9hY3Jvc3MucGRmIiwgd2lkdGggPSA4LCBoZWlnaHQgPSA0KQ0KZ2dzYXZlKCJmaWd1cmVzL2ZyZXF1ZW5jeV9hY3Jvc3MucG5nIiwgd2lkdGggPSA4LCBoZWlnaHQgPSA0KQ0KDQp0ZXN0X2ZyZXF1ZW5jeSA8LSB0ZXN0X2ZyZXF1ZW5jeSAlPiUgDQogIGZpbHRlcihuID49IDEpICU+JSANCiAgbXV0YXRlKHBlcmNlbnQgPSBjb3VudC9zdW0oY291bnQpKQ0KDQpmcmVxX3Bsb3QgPC0gZ2dwbG90KHRlc3RfZnJlcXVlbmN5LCBhZXMobiwgY291bnQpKSArIA0KICBnZW9tX2Jhcih3aWR0aCA9IDAuMSwgZmlsbCA9IGNvbG9yc1sibm92ZWwiXSwgc3RhdCA9ICJpZGVudGl0eSIpICsNCiAgIyBzY2FsZV95X3NxcnQoIk51bWJlciBvZiBtZWFzdXJlcyIsIGJyZWFrcyA9IGMoMCwgMTAwLCA0MDAsIDEwMDAsIDIwMDAsIDQwMDAsIDYwMDAsIDEwMDAwKSwgbGltaXRzID0gYygwLCAxMTUwMCkpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKCJOdW1iZXIgb2YgbWVhc3VyZXMiKSArDQogIHNjYWxlX3hfbG9nMTAoIlVzYWdlcyByZWNvcmRlZCBpbiBBUEEgUHN5Y0luZm8gMTk5My0yMDIyIiwNCiAgICAgICAgICAgICAgICBicmVha3MgPSBjKDEsIDIsIDUsIDEwLCAxMDAsIDEwMDAsIDI1MDAwKSwNCiAgICAgICAgICAgICAgIGxhYmVscyA9IGMoMSwgMiwgNSwgMTAsIDEwMCwgMTAwMCwgMjUwMDApKSArDQogIA0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gaWZfZWxzZShuIDw9IDIsIHNwcmludGYoIiUuMGYlJSIsIHBlcmNlbnQqMTAwKSwgIiIpLA0KICAgICAgICAgICAgICAgIHggPSBuLCB5ID0gY291bnQgKyA3MDApKSArDQoNCiAgIyBzY2FsZV94X3NxcnQoYnJlYWtzID0gYygwLCAxLCAyLCAzLCA0LCA1LCAxMCwgMjAsIDQwLCA1MCksIGxhYmVscyA9IGMoMCwgMSwgMiwgMywgNCwgNSwgMTAsIDIwLCA0MCwgIjUwKyIpKSArDQogICMgZ2VvbV90ZXh0X3JlcGVsKGFlcyh4ID0gbiwgbGFiZWwgPSBmaXJzdF9hY3JvbnltLCB5ID0geSksIA0KICAjICAgICAgICAgICAgICAgICBkYXRhID0NCiAgIyAgICAgICAgICAgICAgICAgICB0ZXN0X2ZyZXF1ZW5jeSAlPiUgZ3JvdXBfYnkoc3ViZGlzY2lwbGluZV8xKSAlPiUgZmlsdGVyKHJvd19udW1iZXIoKSA+IChuKCkgLSAxMCkgKSAlPiUgbGVmdF9qb2luKHJlY29yZHNfd2lkZSAlPiUgc2VsZWN0KFRlc3QgPSBET0ksIGZpcnN0X2Fjcm9ueW0pKSAlPiUgDQogICMgICAgICAgICAgICAgICAgICAgbXV0YXRlKGZpcnN0X2Fjcm9ueW0gPSBpZl9lbHNlKGZpcnN0X2Fjcm9ueW0gPT0gIkhSU0QiLCAiSEFNLUQiLA0KICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaXJzdF9hY3JvbnltKSkgJT4lIA0KICAgICMgbXV0YXRlKHkgPSAyMCArIDUwKigxK24oKS1yb3dfbnVtYmVyKCkpKSwNCiAgICAjICAgICAgICAgICAgICAgc2l6ZSA9IDMuMywgZm9yY2UgPSA1LCBmb3JjZV9wdWxsCT0gMCwgbWF4LnRpbWUgPSAxLCANCiAgICAjICAgICAgICAgICAgICAgbWF4Lm92ZXJsYXBzID0gSW5mLA0KICAgICMgICAgICAgICAgICAgICBzZWdtZW50LmNvbG9yID0gImxpZ2h0Z3JheSIsDQogICAgIyAgICAgICAgICAgICAgIHNlZ21lbnQuY3VydmF0dXJlID0gMSwNCiAgICAjICAgICAgICAgICAgICAgaGp1c3QgPSAxLA0KICAgICMgICAgICAgICAgICAgICBudWRnZV95ID0gMTAsDQogICAgIyAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9ICJ5Ig0KICAgICMgKSArDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTMpICsNCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vci55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5ncmlkLm1pbm9yLnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBsb3QudGl0bGUucG9zaXRpb24gPSAicGxvdCIsDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZT0iYm9sZCIpLA0KICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQpmcmVxX3Bsb3QNCmdnc2F2ZSgiZmlndXJlcy9mcmVxdWVuY3lfYWNyb3NzX25vMC5wZGYiLCB3aWR0aCA9IDgsIGhlaWdodCA9IDQpDQpnZ3NhdmUoImZpZ3VyZXMvZnJlcXVlbmN5X2Fjcm9zc19ubzAucG5nIiwgd2lkdGggPSA4LCBoZWlnaHQgPSA0KQ0KYGBgDQoNCmBgYHtyfQ0KdGVzdF9mcmVxdWVuY3kgPC0gcHN5Y3Rlc3RzX2luZm8gJT4lIA0KICBtdXRhdGUoVGVzdCA9IGlmX2Vsc2UodGVzdF90eXBlID09ICJPcmlnaW5hbCIsIERPSSwgb3JpZ2luYWxfdGVzdF9ET0kpKSAlPiUgDQogIGRyb3BfbmEoVGVzdCkgJT4lIA0KICAjIGZpbHRlcihUZXN0WWVhciA+PSAxOTkwKSAlPiUNCiAgZmlsdGVyKGJldHdlZW4oWWVhciwgMTk5MywgMjAyMikpICU+JQ0KICBncm91cF9ieShzdWJkaXNjaXBsaW5lXzEsIFRlc3QpICU+JSANCiAgc3VtbWFyaXNlKG4gPSBzdW0odXNhZ2VfY291bnQsIG5hLnJtID0gVCkpICU+JSANCiAgYXJyYW5nZShuKQ0KDQp0ZXN0X2ZyZXF1ZW5jeSA8LSByZWNvcmRzX3dpZGUgJT4lIA0KICBmaWx0ZXIodGVzdF90eXBlID09ICJPcmlnaW5hbCIsIFRlc3RZZWFyIDw9IDIwMjIpICU+JSANCiAgc2VsZWN0KHN1YmRpc2NpcGxpbmVfMSwgVGVzdCA9IERPSSkgJT4lIA0KICBmdWxsX2pvaW4odGVzdF9mcmVxdWVuY3kpICU+JSANCiAgbXV0YXRlKG4gPSBjb2FsZXNjZShuLCAwLjUpKQ0KDQp0ZXN0X2ZyZXF1ZW5jeSA8LSB0ZXN0X2ZyZXF1ZW5jeSAlPiUgDQogICMgbXV0YXRlKG4gPSBpZl9lbHNlKG4gPj0gMTAwMCwgMTAwMCwgbikpICU+JSANCiAgbXV0YXRlKHN1YmRpc2NpcGxpbmVfMSA9IHN0cl9yZXBsYWNlKHN1YmRpc2NpcGxpbmVfMSwgIiBQc3ljaG9sb2d5IiwgIiIpKSAlPiUgDQogIGdyb3VwX2J5KHN1YmRpc2NpcGxpbmVfMSwgbikgJT4lIA0KICBzdW1tYXJpc2UoY291bnQgPSBuKCkpICU+JSANCiAgZ3JvdXBfYnkoc3ViZGlzY2lwbGluZV8xKSAlPiUgDQogIG11dGF0ZShwZXJjZW50ID0gY291bnQvc3VtKGNvdW50KSkNCg0KZnJlcV9wbG90IDwtIGdncGxvdCh0ZXN0X2ZyZXF1ZW5jeSwgYWVzKG4sIGNvdW50KSkgKyANCiAgZ2VvbV9iYXIod2lkdGggPSAwLjEsIGZpbGwgPSBjb2xvcnNbIm5vdmVsIl0sIHN0YXQgPSAiaWRlbnRpdHkiKSArDQogIGZhY2V0X3dyYXAofiBzdWJkaXNjaXBsaW5lXzEsIHNjYWxlcyA9ICJmcmVlX3kiKSArIA0KICAjIHNjYWxlX3lfc3FydCgiTnVtYmVyIG9mIG1lYXN1cmVzIiwgYnJlYWtzID0gYygwLCAxMDAsIDQwMCwgMTAwMCwgMjAwMCwgNDAwMCwgNjAwMCwgMTAwMDApLCBsaW1pdHMgPSBjKDAsIDExNTAwKSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoIk51bWJlciBvZiBtZWFzdXJlcyIsIGV4cGFuZCA9IGV4cGFuc2lvbihjKDAsIDAuMSkpKSArDQogIHNjYWxlX3hfbG9nMTAoIlVzYWdlcyByZWNvcmRlZCBpbiBBUEEgUHN5Y0luZm8gMTk5My0yMDIyIiwNCiAgICAgICAgICAgICAgICBicmVha3MgPSBjKDAuNSwgMSwgMiwgMTAsIDEwMCwgMTAwMCwgMjUwMDApLA0KICAgICAgICAgICAgICAgbGFiZWxzID0gYygwLCAxLCAyLCAxMCwgMTAwLCAxMDAwLCAyNTAwMCkpICsNCiAgDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBpZl9lbHNlKG4gPD0gMiwgc3ByaW50ZigiJS4wZiUlIiwgcGVyY2VudCoxMDApLCAiIiksDQogICAgICAgICAgICAgICAgeCA9IG4sIHkgPSBjb3VudCApLCBzaXplID0gMywgdmp1c3QgPSAtMC40LCBoanVzdCA9IDAuNCkgKw0KDQogICMgc2NhbGVfeF9zcXJ0KGJyZWFrcyA9IGMoMCwgMSwgMiwgMywgNCwgNSwgMTAsIDIwLCA0MCwgNTApLCBsYWJlbHMgPSBjKDAsIDEsIDIsIDMsIDQsIDUsIDEwLCAyMCwgNDAsICI1MCsiKSkgKw0KICAjIGdlb21fdGV4dF9yZXBlbChhZXMoeCA9IG4sIGxhYmVsID0gZmlyc3RfYWNyb255bSwgeSA9IHkpLCANCiAgIyAgICAgICAgICAgICAgICAgZGF0YSA9DQogICMgICAgICAgICAgICAgICAgICAgdGVzdF9mcmVxdWVuY3kgJT4lIGdyb3VwX2J5KHN1YmRpc2NpcGxpbmVfMSkgJT4lIGZpbHRlcihyb3dfbnVtYmVyKCkgPiAobigpIC0gMTApICkgJT4lIGxlZnRfam9pbihyZWNvcmRzX3dpZGUgJT4lIHNlbGVjdChUZXN0ID0gRE9JLCBmaXJzdF9hY3JvbnltKSkgJT4lIA0KICAjICAgICAgICAgICAgICAgICAgIG11dGF0ZShmaXJzdF9hY3JvbnltID0gaWZfZWxzZShmaXJzdF9hY3JvbnltID09ICJIUlNEIiwgIkhBTS1EIiwNCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlyc3RfYWNyb255bSkpICU+JSANCiAgICAjIG11dGF0ZSh5ID0gMjAgKyA1MCooMStuKCktcm93X251bWJlcigpKSksDQogICAgIyAgICAgICAgICAgICAgIHNpemUgPSAzLjMsIGZvcmNlID0gNSwgZm9yY2VfcHVsbAk9IDAsIG1heC50aW1lID0gMSwgDQogICAgIyAgICAgICAgICAgICAgIG1heC5vdmVybGFwcyA9IEluZiwNCiAgICAjICAgICAgICAgICAgICAgc2VnbWVudC5jb2xvciA9ICJsaWdodGdyYXkiLA0KICAgICMgICAgICAgICAgICAgICBzZWdtZW50LmN1cnZhdHVyZSA9IDEsDQogICAgIyAgICAgICAgICAgICAgIGhqdXN0ID0gMSwNCiAgICAjICAgICAgICAgICAgICAgbnVkZ2VfeSA9IDEwLA0KICAgICMgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAieSINCiAgICAjICkgKw0KICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yLnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGxvdC50aXRsZS5wb3NpdGlvbiA9ICJwbG90IiwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlPSJib2xkIiksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCg0KZnJlcV9wbG90DQpnZ3NhdmUoImZpZ3VyZXMvZnJlcXVlbmN5LnBkZiIsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNCkNCmdnc2F2ZSgiZmlndXJlcy9mcmVxdWVuY3kucG5nIiwgd2lkdGggPSA4LCBoZWlnaHQgPSA0KQ0KDQp0ZXN0X2ZyZXF1ZW5jeSA8LSB0ZXN0X2ZyZXF1ZW5jeSAlPiUgDQogIGZpbHRlcihuID49IDEpICU+JSANCiAgZ3JvdXBfYnkoc3ViZGlzY2lwbGluZV8xKSAlPiUgDQogIG11dGF0ZShwZXJjZW50ID0gY291bnQvc3VtKGNvdW50KSkNCg0KZnJlcV9wbG90IDwtIGdncGxvdCh0ZXN0X2ZyZXF1ZW5jeSwgYWVzKG4sIGNvdW50KSkgKyANCiAgZ2VvbV9iYXIod2lkdGggPSAwLjEsIGZpbGwgPSBjb2xvcnNbIm5vdmVsIl0sIHN0YXQgPSAiaWRlbnRpdHkiKSArDQogIGZhY2V0X3dyYXAofiBzdWJkaXNjaXBsaW5lXzEsIHNjYWxlcyA9ICJmcmVlX3kiKSArIA0KICAjIHNjYWxlX3lfc3FydCgiTnVtYmVyIG9mIG1lYXN1cmVzIiwgYnJlYWtzID0gYygwLCAxMDAsIDQwMCwgMTAwMCwgMjAwMCwgNDAwMCwgNjAwMCwgMTAwMDApLCBsaW1pdHMgPSBjKDAsIDExNTAwKSkgKw0KICAgIHNjYWxlX3lfY29udGludW91cygiTnVtYmVyIG9mIG1lYXN1cmVzIiwgZXhwYW5kID0gZXhwYW5zaW9uKGMoMCwgMC4xKSkpICsNCiAgc2NhbGVfeF9sb2cxMCgiVXNhZ2VzIHJlY29yZGVkIGluIEFQQSBQc3ljSW5mbyAxOTkzLTIwMjIiLA0KICAgICAgICAgICAgICAgIGJyZWFrcyA9IGMoMSwgMiwgNSwgMTAsIDEwMCwgMTAwMCwgMjUwMDApLA0KICAgICAgICAgICAgICAgbGFiZWxzID0gYygxLCAyLCA1LCAxMCwgMTAwLCAxMDAwLCAyNTAwMCkpICsNCiAgDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBpZl9lbHNlKG4gPD0gMiwgc3ByaW50ZigiJS4wZiUlIiwgcGVyY2VudCoxMDApLCAiIiksDQogICAgICAgICAgICAgICAgeCA9IG4sIHkgPSBjb3VudCApLCBzaXplID0gMywgdmp1c3QgPSAtMC4xMSwgaGp1c3QgPSAwLjQpICsNCg0KICAjIHNjYWxlX3hfc3FydChicmVha3MgPSBjKDAsIDEsIDIsIDMsIDQsIDUsIDEwLCAyMCwgNDAsIDUwKSwgbGFiZWxzID0gYygwLCAxLCAyLCAzLCA0LCA1LCAxMCwgMjAsIDQwLCAiNTArIikpICsNCiAgIyBnZW9tX3RleHRfcmVwZWwoYWVzKHggPSBuLCBsYWJlbCA9IGZpcnN0X2Fjcm9ueW0sIHkgPSB5KSwgDQogICMgICAgICAgICAgICAgICAgIGRhdGEgPQ0KICAjICAgICAgICAgICAgICAgICAgIHRlc3RfZnJlcXVlbmN5ICU+JSBncm91cF9ieShzdWJkaXNjaXBsaW5lXzEpICU+JSBmaWx0ZXIocm93X251bWJlcigpID4gKG4oKSAtIDEwKSApICU+JSBsZWZ0X2pvaW4ocmVjb3Jkc193aWRlICU+JSBzZWxlY3QoVGVzdCA9IERPSSwgZmlyc3RfYWNyb255bSkpICU+JSANCiAgIyAgICAgICAgICAgICAgICAgICBtdXRhdGUoZmlyc3RfYWNyb255bSA9IGlmX2Vsc2UoZmlyc3RfYWNyb255bSA9PSAiSFJTRCIsICJIQU0tRCIsDQogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpcnN0X2Fjcm9ueW0pKSAlPiUgDQogICAgIyBtdXRhdGUoeSA9IDIwICsgNTAqKDErbigpLXJvd19udW1iZXIoKSkpLA0KICAgICMgICAgICAgICAgICAgICBzaXplID0gMy4zLCBmb3JjZSA9IDUsIGZvcmNlX3B1bGwJPSAwLCBtYXgudGltZSA9IDEsIA0KICAgICMgICAgICAgICAgICAgICBtYXgub3ZlcmxhcHMgPSBJbmYsDQogICAgIyAgICAgICAgICAgICAgIHNlZ21lbnQuY29sb3IgPSAibGlnaHRncmF5IiwNCiAgICAjICAgICAgICAgICAgICAgc2VnbWVudC5jdXJ2YXR1cmUgPSAxLA0KICAgICMgICAgICAgICAgICAgICBoanVzdCA9IDEsDQogICAgIyAgICAgICAgICAgICAgIG51ZGdlX3kgPSAxMCwNCiAgICAjICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gInkiDQogICAgIyApICsNCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vci55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5ncmlkLm1pbm9yLnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBsb3QudGl0bGUucG9zaXRpb24gPSAicGxvdCIsDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZT0iYm9sZCIpLA0KICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQpmcmVxX3Bsb3QNCmdnc2F2ZSgiZmlndXJlcy9mcmVxdWVuY3lfbm8wLnBkZiIsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNCkNCmBgYA0KDQojIyBCeSBpbnN0cnVtZW50IHR5cGUNCmBgYHtyfQ0KdXNhZ2VfYnlfeWVhcl9pbnN0cnVtZW50X3R5cGUgPC0gcHN5Y3Rlc3RzX2luZm8gJT4lIA0KICBmaWx0ZXIoYmV0d2VlbihZZWFyLCAxOTkzLCAyMDIyKSkgJT4lIA0KICBncm91cF9ieShpbnN0cnVtZW50X3R5cGVfYnJvYWQsIFllYXIsIFRlc3QgPSBET0kpICU+JSANCiAgc3VtbWFyaXNlKG4gPSBzdW0odXNhZ2VfY291bnQsIG5hLnJtID0gVCkpICU+JSANCiAgZ3JvdXBfYnkoaW5zdHJ1bWVudF90eXBlX2Jyb2FkKSAlPiUgDQogIG11dGF0ZShuX3Rlc3RzID0gbl9kaXN0aW5jdChUZXN0KSkgJT4lIA0KICBncm91cF9ieShpbnN0cnVtZW50X3R5cGVfYnJvYWQsIG5fdGVzdHMsIFllYXIpICU+JSANCiAgc3VtbWFyaXNlKG4gPSBzdW0obiksDQogICAgICAgICAgICBkaWZmX3Rlc3RzID0gbigpKSAlPiUgDQogIHVuZ3JvdXAoKQ0KDQoNCg0KdXNhZ2VfYnlfeWVhcl9pbnN0cnVtZW50X3R5cGUgJT4lIA0KICBnZ3Bsb3QoLiwgYWVzKFllYXIsIG4sIGNvbG9yID0gaW5zdHJ1bWVudF90eXBlX2Jyb2FkKSkgKw0KICBnZW9tX2xpbmUoc2l6ZSA9IDAuNykgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoIlRpbWVzIHRlc3RzIHdlcmUgY29kZWQgaW4gUHN5Y0luZm8iKSArDQogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDE5OTMsIDIwMzApLCBicmVha3MgPSBjKDE5OTMsIDE5OTgsIDIwMDMsIDIwMDgsIDIwMTMsIDIwMTgsIDIwMjIpKSArDQogIHNjYWxlX2NvbG9yX2JyZXdlcih0eXBlID0gInF1YWwiLCBndWlkZSA9ICJub25lIiwgcGFsZXR0ZSA9IDIpICsNCiAgIyBnZ3JlcGVsOjpnZW9tX3RleHRfcmVwZWwoDQogICMgICBhZXMobGFiZWwgPSBzdHJfcmVwbGFjZShzdWJkaXNjaXBsaW5lLCAiIFBzeWNob2xvZ3kiLCAiIikpLCBkYXRhID0gZW50cm9weV9ieV95ZWFyICU+JSBmaWx0ZXIoWWVhciA9PSBtYXgoWWVhciwgbmEucm0gPSBUKSksDQogICMgICBzaXplID0gNCwgaGp1c3QgPSAxLA0KICAjICAgKSArIA0KICBnZW9tX3RleHRfcmVwZWwoYWVzKGxhYmVsID0gZ3N1YigiXi4qJCIsICIgIiwgaW5zdHJ1bWVudF90eXBlX2Jyb2FkKSksICMgVGhpcyB3aWxsIGZvcmNlIHRoZSBjb3JyZWN0IHBvc2l0aW9uIG9mIHRoZSBsaW5rJ3MgcmlnaHQgZW5kLg0KICAgICAgICAgICAgICAgICAgZGF0YSA9IHVzYWdlX2J5X3llYXJfaW5zdHJ1bWVudF90eXBlICU+JSBmaWx0ZXIoWWVhciA9PSBtYXgoWWVhciwgbmEucm0gPSBUKSksDQogICAgICAgICAgICAgICAgICBzZWdtZW50LmN1cnZhdHVyZSA9IC0wLjEsDQogICAgICAgICAgICAgICAgICBzZWdtZW50LnNxdWFyZSA9IFRSVUUsDQogICAgICAgICAgICAgICAgICBzZWdtZW50LmNvbG9yID0gJ2dyZXknLA0KICAgICAgICAgICAgICAgICAgYm94LnBhZGRpbmcgPSAwLjEsDQogICAgICAgICAgICAgICAgICBwb2ludC5wYWRkaW5nID0gMC42LA0KICAgICAgICAgICAgICAgICAgbnVkZ2VfeCA9IDAuMTUsDQogICAgICAgICAgICAgICAgICBudWRnZV95ID0gMC4wNSwNCiAgICAgICAgICAgICAgICAgIGZvcmNlID0gMC41LA0KICAgICAgICAgICAgICAgICAgaGp1c3QgPSAwLA0KICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uPSJ5IiwNCiAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRQ0KICApICsNCiAgZ2VvbV90ZXh0X3JlcGVsKGRhdGEgPSB1c2FnZV9ieV95ZWFyX2luc3RydW1lbnRfdHlwZSAlPiUgZmlsdGVyKFllYXIgPT0gbWF4KFllYXIsIG5hLnJtID0gVCkpLA0KICAgICAgICAgICAgICAgICAgYWVzKGxhYmVsID0gcGFzdGUwKCIgICIsc3RyX3JlcGxhY2UoaW5zdHJ1bWVudF90eXBlX2Jyb2FkLCAiIFBzeWNob2xvZ3kiLCAiIiksICIgKG49Iiwgbl90ZXN0cywgIikiKSksDQogICAgICAgICAgICAgICAgICBzZWdtZW50LmFscGhhID0gMCwgIyMgVGhpcyB3aWxsICdoaWRlJyB0aGUgbGluaw0KICAgICAgICAgICAgICAgICAgc2VnbWVudC5jdXJ2YXR1cmUgPSAtMC4xLA0KICAgICAgICAgICAgICAgICAgc2VnbWVudC5zcXVhcmUgPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgIyBzZWdtZW50LmNvbG9yID0gJ2dyZXknLA0KICAgICAgICAgICAgICAgICAgYm94LnBhZGRpbmcgPSAwLjEsDQogICAgICAgICAgICAgICAgICBwb2ludC5wYWRkaW5nID0gMC42LA0KICAgICAgICAgICAgICAgICAgbnVkZ2VfeCA9IDAuMTUsDQogICAgICAgICAgICAgICAgICBudWRnZV95ID0gMC4wNSwNCiAgICAgICAgICAgICAgICAgIGZvcmNlID0gMC41LA0KICAgICAgICAgICAgICAgICAgaGp1c3QgPSAwLA0KICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uPSJ5IiwNCiAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRSkrDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTMpICsNCiAgIHRoZW1lKHBhbmVsLmdyaWQubWlub3IueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vci54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwbG90LnRpdGxlLnBvc2l0aW9uID0gInBsb3QiLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2U9ImJvbGQiKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KZ2dzYXZlKCJmaWd1cmVzL3VzYWdlX2J5X3llYXJfaW5zdHJ1bWVudF90eXBlLnBkZiIsIHdpZHRoID0gMTAsIGhlaWdodCA9IDQpDQpnZ3NhdmUoImZpZ3VyZXMvdXNhZ2VfYnlfeWVhcl9pbnN0cnVtZW50X3R5cGUucG5nIiwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNCkNCmBgYA0KDQpgYGB7cn0NCnVzYWdlX2J5X3llYXJfaW5zdHJ1bWVudF90eXBlIDwtIHBzeWN0ZXN0c19pbmZvICU+JSANCiAgZmlsdGVyKGJldHdlZW4oWWVhciwgMTk5MywgMjAyMikpICU+JSANCiAgZ3JvdXBfYnkoSW5zdHJ1bWVudFR5cGUsIFllYXIsIFRlc3QgPSBET0kpICU+JSANCiAgc3VtbWFyaXNlKG4gPSBzdW0odXNhZ2VfY291bnQsIG5hLnJtID0gVCkpICU+JSANCiAgZ3JvdXBfYnkoSW5zdHJ1bWVudFR5cGUpICU+JSANCiAgbXV0YXRlKG5fdGVzdHMgPSBuX2Rpc3RpbmN0KFRlc3QpKSAlPiUgDQogIGdyb3VwX2J5KEluc3RydW1lbnRUeXBlLCBuX3Rlc3RzLCBZZWFyKSAlPiUgDQogIHN1bW1hcmlzZShuID0gc3VtKG4pLA0KICAgICAgICAgICAgZGlmZl90ZXN0cyA9IG4oKSkgJT4lIA0KICB1bmdyb3VwKCkNCg0KDQoNCnVzYWdlX2J5X3llYXJfaW5zdHJ1bWVudF90eXBlICU+JSANCiAgZ2dwbG90KC4sIGFlcyhZZWFyLCBuLCBjb2xvciA9IEluc3RydW1lbnRUeXBlKSkgKw0KICBnZW9tX2xpbmUoc2l6ZSA9IDAuNykgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoIlRpbWVzIHRlc3RzIHdlcmUgY29kZWQgaW4gUHN5Y0luZm8iKSArDQogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDE5OTMsIDIwMzUpLCBicmVha3MgPSBjKDE5OTMsIDE5OTgsIDIwMDMsIDIwMDgsIDIwMTMsIDIwMTgsIDIwMjIpKSArDQogIHNjYWxlX2NvbG9yX2Rpc2NyZXRlKCkgKw0KICAjIGdncmVwZWw6Omdlb21fdGV4dF9yZXBlbCgNCiAgIyAgIGFlcyhsYWJlbCA9IHN0cl9yZXBsYWNlKHN1YmRpc2NpcGxpbmUsICIgUHN5Y2hvbG9neSIsICIiKSksIGRhdGEgPSBlbnRyb3B5X2J5X3llYXIgJT4lIGZpbHRlcihZZWFyID09IG1heChZZWFyLCBuYS5ybSA9IFQpKSwNCiAgIyAgIHNpemUgPSA0LCBoanVzdCA9IDEsDQogICMgICApICsgDQogIGdlb21fdGV4dF9yZXBlbChhZXMobGFiZWwgPSBnc3ViKCJeLiokIiwgIiAiLCBJbnN0cnVtZW50VHlwZSkpLCAjIFRoaXMgd2lsbCBmb3JjZSB0aGUgY29ycmVjdCBwb3NpdGlvbiBvZiB0aGUgbGluaydzIHJpZ2h0IGVuZC4NCiAgICAgICAgICAgICAgICAgIGRhdGEgPSB1c2FnZV9ieV95ZWFyX2luc3RydW1lbnRfdHlwZSAlPiUgZmlsdGVyKFllYXIgPT0gbWF4KFllYXIsIG5hLnJtID0gVCkpLA0KICAgICAgICAgICAgICAgICAgc2VnbWVudC5jdXJ2YXR1cmUgPSAtMC4xLA0KICAgICAgICAgICAgICAgICAgc2VnbWVudC5zcXVhcmUgPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgc2VnbWVudC5jb2xvciA9ICdncmV5JywNCiAgICAgICAgICAgICAgICAgIGJveC5wYWRkaW5nID0gMC4xLA0KICAgICAgICAgICAgICAgICAgcG9pbnQucGFkZGluZyA9IDAuNiwNCiAgICAgICAgICAgICAgICAgIG51ZGdlX3ggPSAwLjE1LA0KICAgICAgICAgICAgICAgICAgbnVkZ2VfeSA9IDAuMDUsDQogICAgICAgICAgICAgICAgICBmb3JjZSA9IDAuNSwNCiAgICAgICAgICAgICAgICAgIGhqdXN0ID0gMCwNCiAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbj0ieSIsDQogICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUNCiAgKSArDQogIGdlb21fdGV4dF9yZXBlbChkYXRhID0gdXNhZ2VfYnlfeWVhcl9pbnN0cnVtZW50X3R5cGUgJT4lIGZpbHRlcihZZWFyID09IG1heChZZWFyLCBuYS5ybSA9IFQpKSwNCiAgICAgICAgICAgICAgICAgIGFlcyhsYWJlbCA9IHBhc3RlMCgiICAiLHN0cl9yZXBsYWNlKEluc3RydW1lbnRUeXBlLCAiIFBzeWNob2xvZ3kiLCAiIiksICIgKG49Iiwgbl90ZXN0cywgIikiKSksDQogICAgICAgICAgICAgICAgICBzZWdtZW50LmFscGhhID0gMCwgIyMgVGhpcyB3aWxsICdoaWRlJyB0aGUgbGluaw0KICAgICAgICAgICAgICAgICAgc2VnbWVudC5jdXJ2YXR1cmUgPSAtMC4xLA0KICAgICAgICAgICAgICAgICAgc2VnbWVudC5zcXVhcmUgPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgIyBzZWdtZW50LmNvbG9yID0gJ2dyZXknLA0KICAgICAgICAgICAgICAgICAgYm94LnBhZGRpbmcgPSAwLjEsDQogICAgICAgICAgICAgICAgICBwb2ludC5wYWRkaW5nID0gMC42LA0KICAgICAgICAgICAgICAgICAgbnVkZ2VfeCA9IDAuMTUsDQogICAgICAgICAgICAgICAgICBudWRnZV95ID0gMC4wNSwNCiAgICAgICAgICAgICAgICAgIGZvcmNlID0gMC41LA0KICAgICAgICAgICAgICAgICAgaGp1c3QgPSAwLA0KICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uPSJ5IiwNCiAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRSkrDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTMpICsNCiAgIHRoZW1lKHBhbmVsLmdyaWQubWlub3IueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vci54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwbG90LnRpdGxlLnBvc2l0aW9uID0gInBsb3QiLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2U9ImJvbGQiKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KZ2dzYXZlKCJmaWd1cmVzL3VzYWdlX2J5X3llYXJfaW5zdHJ1bWVudF90eXBlX25hcnJvdy5wZGYiLCB3aWR0aCA9IDE0LCBoZWlnaHQgPSAxMCkNCmdnc2F2ZSgiZmlndXJlcy91c2FnZV9ieV95ZWFyX2luc3RydW1lbnRfdHlwZV9uYXJyb3cucG5nIiwgd2lkdGggPSAxNCwgaGVpZ2h0ID0gMTApDQpgYGANCg0KIyBFbnRyb3B5DQoNCiMjIEVudHJvcHkgYnkgeWVhcg0KYGBge3J9DQpieW9yaWdfZW50cm9weV9ieV95ZWFyIDwtIHBzeWN0ZXN0c19pbmZvICU+JSANCiAgZmlsdGVyKGJldHdlZW4oWWVhciwgMTk5MywgMjAyMikpICU+JSANCiAgbXV0YXRlKFRlc3QgPSBpZl9lbHNlKHRlc3RfdHlwZSA9PSAiT3JpZ2luYWwiLCBET0ksIG9yaWdpbmFsX3Rlc3RfRE9JKSkgJT4lIA0KICBkcm9wX25hKFRlc3QpICU+JSANCiAgZ3JvdXBfYnkoWWVhciwgVGVzdCkgJT4lIA0KICBzdW1tYXJpc2UobiA9IHN1bSh1c2FnZV9jb3VudCwgbmEucm0gPSBUKSkgJT4lIA0KICB1bmdyb3VwKCkgJT4lIA0KICBtdXRhdGUobl90ZXN0cyA9IG5fZGlzdGluY3QoVGVzdCkpICU+JSANCiAgZ3JvdXBfYnkobl90ZXN0cywgWWVhcikgJT4lIA0KICBmaWx0ZXIobiA+IDApICU+JSANCiAgc3VtbWFyaXNlKGVudHJvcHkgPSBlbnRyb3B5KG4pLA0KICAgICAgICAgICAgbm9ybV9lbnRyb3B5ID0gY2FsY19ub3JtX2VudHJvcHkobiksDQogICAgICAgICAgICBuID0gc3VtKG4pLA0KICAgICAgICAgICAgZGlmZl90ZXN0cyA9IG4oKSkgJT4lIA0KICB1bmdyb3VwKCkNCiMgd2hhdCdzIHRoZSBwb2ludCBvZiBtdXRhdGUobl90ZXN0cyA9IG5fZGlzdGluY3QoVGVzdCkpPyBqdXN0IHRvIGNoZWNrPw0KDQoNCmJ5Y29uc3RydWN0X2VudHJvcHlfYnlfeWVhciA8LSBwc3ljdGVzdHNfaW5mbyAlPiUgDQogIGZpbHRlcihiZXR3ZWVuKFllYXIsIDE5OTMsIDIwMjIpKSAlPiUgDQogIGRyb3BfbmEoZmlyc3RfY29uc3RydWN0KSAlPiUgDQogIGdyb3VwX2J5KFllYXIsIFRlc3QgPSBmaXJzdF9jb25zdHJ1Y3QpICU+JSANCiAgc3VtbWFyaXNlKG4gPSBzdW0odXNhZ2VfY291bnQsIG5hLnJtID0gVCkpICU+JSANCiAgdW5ncm91cCgpICU+JSANCiAgbXV0YXRlKG5fdGVzdHMgPSBuX2Rpc3RpbmN0KFRlc3QpKSAlPiUgDQogIGdyb3VwX2J5KG5fdGVzdHMsIFllYXIpICU+JSANCiAgZmlsdGVyKG4gPiAwKSAlPiUgDQogIHN1bW1hcmlzZShlbnRyb3B5ID0gZW50cm9weShuKSwsDQogICAgICAgICAgICBub3JtX2VudHJvcHkgPSBjYWxjX25vcm1fZW50cm9weShuKSwNCiAgICAgICAgICAgIG4gPSBzdW0obiksDQogICAgICAgICAgICBkaWZmX3Rlc3RzID0gbigpKSAlPiUgDQogIHVuZ3JvdXAoKQ0KDQphbGxfZW50cm9weV9ieV95ZWFyIDwtIHBzeWN0ZXN0c19pbmZvICU+JSANCiAgZmlsdGVyKGJldHdlZW4oWWVhciwgMTk5MywgMjAyMikpICU+JSANCiAgZHJvcF9uYShET0kpICU+JSANCiAgZ3JvdXBfYnkoWWVhciwgVGVzdCA9IERPSSkgJT4lIA0KICBzdW1tYXJpc2UobiA9IHN1bSh1c2FnZV9jb3VudCwgbmEucm0gPSBUKSkgJT4lIA0KICB1bmdyb3VwKCkgJT4lIA0KICBtdXRhdGUobl90ZXN0cyA9IG5fZGlzdGluY3QoVGVzdCkpICU+JSANCiAgZ3JvdXBfYnkobl90ZXN0cywgWWVhcikgJT4lIA0KICBmaWx0ZXIobiA+IDApICU+JSANCiAgc3VtbWFyaXNlKGVudHJvcHkgPSBlbnRyb3B5KG4pLCwNCiAgICAgICAgICAgIG5vcm1fZW50cm9weSA9IGNhbGNfbm9ybV9lbnRyb3B5KG4pLA0KICAgICAgICAgICAgbiA9IHN1bShuKSwNCiAgICAgICAgICAgIGRpZmZfdGVzdHMgPSBuKCkpICU+JSANCiAgdW5ncm91cCgpDQoNCm9yaWdpbmFsX2VudHJvcHlfYnlfeWVhciA8LSBwc3ljdGVzdHNfaW5mbyAlPiUgDQogIGZpbHRlcihiZXR3ZWVuKFllYXIsIDE5OTMsIDIwMjIpKSAlPiUgDQogIGZpbHRlcih0ZXN0X3R5cGUgPT0gIk9yaWdpbmFsIikgJT4lIA0KICBncm91cF9ieShZZWFyLCBUZXN0ID0gRE9JKSAlPiUgDQogIHN1bW1hcmlzZShuID0gc3VtKHVzYWdlX2NvdW50LCBuYS5ybSA9IFQpKSAlPiUgDQogIHVuZ3JvdXAoKSAlPiUgDQogIG11dGF0ZShuX3Rlc3RzID0gbl9kaXN0aW5jdChUZXN0KSkgJT4lIA0KICBncm91cF9ieShuX3Rlc3RzLCBZZWFyKSAlPiUgDQogIGZpbHRlcihuID4gMCkgJT4lIA0KICBzdW1tYXJpc2UoZW50cm9weSA9IGVudHJvcHkobiksLA0KICAgICAgICAgICAgbm9ybV9lbnRyb3B5ID0gY2FsY19ub3JtX2VudHJvcHkobiksDQogICAgICAgICAgICBuID0gc3VtKG4pLA0KICAgICAgICAgICAgZGlmZl90ZXN0cyA9IG4oKSkgJT4lIA0KICB1bmdyb3VwKCkNCg0KZW50cm9weV9ieV95ZWFyIDwtIGJpbmRfcm93cygjICJhbGwgdGVzdHMiID0gYWxsX2VudHJvcHlfYnlfeWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIm1lYXN1cmVzIiA9IG9yaWdpbmFsX2VudHJvcHlfYnlfeWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIndpdGggdHJhbnNsYXRpb25zXG4gYW5kIHJldmlzaW9ucyIgPSBieW9yaWdfZW50cm9weV9ieV95ZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjICJieSBuYW1lIGJhc2UiID0gYnliYXNlX2VudHJvcHlfYnlfeWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvbnN0cnVjdHMiID0gYnljb25zdHJ1Y3RfZW50cm9weV9ieV95ZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuaWQgPSAidmVyc2lvbiIpDQoNCg0KZW50cm9weV9ieV95ZWFyICU+JSANCiAgZ2dwbG90KC4sIGFlcyhZZWFyLCBub3JtX2VudHJvcHksIGNvbG9yID0gdmVyc2lvbikpICsNCiAgZ2VvbV9saW5lKHNpemUgPSAwLjcpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKCJOb3JtYWxpemVkIFNoYW5ub24gRW50cm9weSIsIGxpbWl0cyA9IGMoMCwgMSksIGxhYmVscyA9IHNjYWxlczo6cGVyY2VudCkgKw0KICAjIGdlb21fbGluZShhZXMoeSA9IGxvZyhuKSksIGNvbG9yID0gJ3JlZCcpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKCJVc2FnZSB5ZWFyIGFzIGNvZGVkIGluIEFQQSBQc3ljSW5mbyIsIGxpbWl0cyA9IGMoMTk5MywgMjAzMCksIA0KICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc2VxKDE5OTMsIDIwMjIsIGJ5ID0gMSksDQogICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKDE5OTMsICIiLCAiIiwgIiIsICIiLCAxOTk4LCAiIiwgIiIsICIiLCAiIiwgMjAwMywgIiIsICIiLCAiIiwgIiIsIDIwMDgsICIiLCAiIiwgIiIsICIiLCAyMDEzLCAiIiwgIiIsICIiLCAiIiwgMjAxOCwgIiIsICIiLCAiIiwgIjIwMjIiKSkgKw0KICBzY2FsZV9jb2xvcl9icmV3ZXIodHlwZSA9ICJxdWFsIiwgZ3VpZGUgPSAibm9uZSIsIHBhbGV0dGUgPSAyKSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDIwMTYsIGxpbmV0eXBlID0gJ2Rhc2hlZCcpICsNCiAgIyBnZ3JlcGVsOjpnZW9tX3RleHRfcmVwZWwoDQogICMgICBhZXMobGFiZWwgPSBzdHJfcmVwbGFjZShzdWJkaXNjaXBsaW5lLCAiIFBzeWNob2xvZ3kiLCAiIikpLCBkYXRhID0gZW50cm9weV9ieV95ZWFyICU+JSBmaWx0ZXIoWWVhciA9PSBtYXgoWWVhciwgbmEucm0gPSBUKSksDQogICMgICBzaXplID0gNCwgaGp1c3QgPSAxLA0KICAjICAgKSArIA0KICBnZW9tX3RleHRfcmVwZWwoZGF0YSA9IGVudHJvcHlfYnlfeWVhciAlPiUgZHJvcF9uYSgpICU+JSBncm91cF9ieSh2ZXJzaW9uKSAlPiUgZmlsdGVyKFllYXIgPT0gbWF4KFllYXIsIG5hLnJtID0gVCkpLA0KICAgICAgICAgICAgICAgICAgYWVzKGxhYmVsID0gcGFzdGUwKCIgIix2ZXJzaW9uKSksICMgIlxuIChuID0gIiwgbl90ZXN0cywgIikiDQogICAgICAgICAgICAgICAgICBzZWdtZW50LmN1cnZhdHVyZSA9IC0wLjUsDQogICAgICAgICAgICAgICAgICBzZWdtZW50LnNxdWFyZSA9IFRSVUUsDQogICAgICAgICAgICAgICAgICBzZWdtZW50LmNvbG9yID0gJ2dyZXknLCANCiAgICAgICAgICAgICAgICAgIHhsaW0gPSBjKDIwMjMsIDIwMzApLA0KICAgICAgICAgICAgICAgICAgbnVkZ2VfeCA9IDEuMTQsDQogICAgICAgICAgICAgICAgICBsaW5laGVpZ2h0ID0gLjksDQogICAgICAgICAgICAgICAgICBoanVzdCA9IDAsDQogICAgICAgICAgICAgICAgICBkaXJlY3Rpb249InkiLA0KICAgICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFKSArDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTMpICsNCiAgIHRoZW1lKA0KICAgICAgICBwYW5lbC5ncmlkLm1pbm9yLnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGxvdC50aXRsZS5wb3NpdGlvbiA9ICJwbG90IiwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlPSJib2xkIiksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCg0KZ2dzYXZlKCJmaWd1cmVzL2VudHJvcHkucGRmIiwgd2lkdGggPSA4LCBoZWlnaHQgPSA0KQ0KZ2dzYXZlKCJmaWd1cmVzL2VudHJvcHkucG5nIiwgd2lkdGggPSA4LCBoZWlnaHQgPSA0KQ0KYGBgDQoNCg0KIyMgYnkgc3ViZGlzY2lwbGluZQ0KDQojIyMgYWxsIG1lYXN1cmVzDQpgYGB7ciBmaWcud2lkdGg9OCxmaWcuaGVpZ2h0PTR9DQplbnRyb3B5X2J5X3llYXIgPC0gcHN5Y3Rlc3RzX2luZm8gJT4lIA0KICBmaWx0ZXIoYmV0d2VlbihZZWFyLCAxOTkzLCAyMDIyKSkgJT4lIA0KICBncm91cF9ieShzdWJkaXNjaXBsaW5lXzEsIFllYXIsIFRlc3QgPSBET0kpICU+JSANCiAgc3VtbWFyaXNlKG4gPSBzdW0odXNhZ2VfY291bnQsIG5hLnJtID0gVCkpICU+JSANCiAgZ3JvdXBfYnkoc3ViZGlzY2lwbGluZV8xKSAlPiUgDQogIG11dGF0ZShuX3Rlc3RzID0gbl9kaXN0aW5jdChUZXN0KSkgJT4lIA0KICBncm91cF9ieShzdWJkaXNjaXBsaW5lXzEsIG5fdGVzdHMsIFllYXIpICU+JSANCiAgZmlsdGVyKG4gPiAwKSAlPiUgDQogIHN1bW1hcmlzZShlbnRyb3B5ID0gZW50cm9weShuKSwsDQogICAgICAgICAgICBub3JtX2VudHJvcHkgPSBjYWxjX25vcm1fZW50cm9weShuKSwNCiAgICAgICAgICAgIG4gPSBzdW0obiksDQogICAgICAgICAgICBkaWZmX3Rlc3RzID0gbigpKSAlPiUgDQogIHVuZ3JvdXAoKQ0KDQoNCmVudHJvcHlfYnlfeWVhciAlPiUgDQogIGdncGxvdCguLCBhZXMoWWVhciwgbm9ybV9lbnRyb3B5LCBjb2xvciA9IHN1YmRpc2NpcGxpbmVfMSkpICsNCiAgZ2VvbV9saW5lKHNpemUgPSAwLjcpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKCJOb3JtYWxpemVkIFNoYW5ub24gRW50cm9weVxuKHdpdGggcmV2aXNpb25zIGFuZCB0cmFuc2xhdGlvbnMpIiwgbGltaXRzID0gYygwLCAxKSwgbGFiZWxzID0gc2NhbGVzOjpwZXJjZW50KSArDQogICMgZ2VvbV9saW5lKGFlcyh5ID0gbG9nKG4pKSwgY29sb3IgPSAncmVkJykgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoIlVzYWdlIHllYXIgYXMgY29kZWQgaW4gQVBBIFBzeWNJbmZvIiwgbGltaXRzID0gYygxOTkzLCAyMDMzKSwgDQogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzZXEoMTk5MywyMDIyLCBieSA9IDEpLA0KICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygxOTkzLCAiIiwgIiIsICIiLCAiIiwgMTk5OCwgIiIsICIiLCAiIiwgIiIsIDIwMDMsICIiLCAiIiwgIiIsICIiLCAyMDA4LCAiIiwgIiIsICIiLCAiIiwgMjAxMywgIiIsICIiLCAiIiwgIiIsIDIwMTgsICIiLCAiIiwgIiIsICIyMDIyIiksDQogICAgICAgICAgICAgICAgICAgICBleHBhbmQgPSBleHBhbnNpb24oYWRkID0gYygwLCAxNCkpKSArDQogIHNjYWxlX2NvbG9yX2JyZXdlcih0eXBlID0gInF1YWwiLCBndWlkZSA9ICJub25lIiwgcGFsZXR0ZSA9IDIpICsNCiAgIyBnZ3RpdGxlKHN0cl9jKG5fZGlzdGluY3QodGVzdHNfYnlfeWVhciRUZXN0KSwgIiBtZWFzdXJlcyB0cmFja2VkIGluIFBzeWNJbmZvIikpICsNCiAjIGdlb21fdGV4dF9yZXBlbChhZXMobGFiZWwgPSBnc3ViKCJeLiokIiwgIiAiLCBzdWJkaXNjaXBsaW5lXzEpKSwgIyBUaGlzIHdpbGwgZm9yY2UgdGhlIGNvcnJlY3QgcG9zaXRpb24gb2YgdGhlIGxpbmsncyByaWdodCBlbmQuDQogIyAgICAgICAgICAgICAgICAgIGRhdGEgPSBlbnRyb3B5X2J5X3llYXIgJT4lIGRyb3BfbmEoKSAlPiUgZ3JvdXBfYnkoc3ViZGlzY2lwbGluZV8xKSAlPiUgZmlsdGVyKFllYXIgPT0gbWF4KFllYXIsIG5hLnJtID0gVCkpLA0KICMgICAgICAgICAgICAgICAgICBzZWdtZW50LmN1cnZhdHVyZSA9IC0wLjEsDQogIyAgICAgICAgICAgICAgICAgIHNlZ21lbnQuc3F1YXJlID0gVFJVRSwNCiAjICAgICAgICAgICAgICAgICAgc2VnbWVudC5jb2xvciA9ICdncmV5JywNCiAjICAgICAgICAgICAgICAgICAgYm94LnBhZGRpbmcgPSAwLjEsDQogIyAgICAgICAgICAgICAgICAgIHBvaW50LnBhZGRpbmcgPSAwLjYsDQogIyAgICAgICAgICAgICAgICAgIG1heC5vdmVybGFwcyA9IEluZiwNCiAjICAgICAgICAgICAgICAgICAgbnVkZ2VfeCA9IDEuMywNCiAjICAgICAgICAgICAgICAgICAgIyBudWRnZV95ID0gMCwNCiAjICAgICAgICAgICAgICAgICAgZm9yY2UgPSAyMCwNCiAjICAgICAgICAgICAgICAgICAgaGp1c3QgPSAwLA0KICMgICAgICAgICAgICAgICAgICBkaXJlY3Rpb249InkiLA0KICMgICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUNCiAjICApICsgIA0KICBnZW9tX3RleHRfcmVwZWwoZGF0YSA9IGVudHJvcHlfYnlfeWVhciAlPiUgZHJvcF9uYSgpICU+JSBncm91cF9ieShzdWJkaXNjaXBsaW5lXzEpICU+JSBmaWx0ZXIoWWVhciA9PSBtYXgoWWVhciwgbmEucm0gPSBUKSksDQogICAgICAgICAgICAgICAgICBhZXMobGFiZWwgPSBwYXN0ZTAoIiAgIixzdHJfcmVwbGFjZShzdWJkaXNjaXBsaW5lXzEsICIgUHN5Y2hvbG9neSIsICIiKSwgIiAobj0iLCBuX3Rlc3RzLCAiKSIpKSwNCiAgICAgICAgICAgICAgICAgICMgc2VnbWVudC5hbHBoYSA9IDAsICMjIFRoaXMgd2lsbCAnaGlkZScgdGhlIGxpbmsNCiAgICAgICAgICAgICAgICAgIHNlZ21lbnQuY3VydmF0dXJlID0gLTAuMSwNCiAgICAgICAgICAgICAgICAgIHNlZ21lbnQuc3F1YXJlID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgIHNlZ21lbnQuY29sb3IgPSAnZ3JleScsDQogICAgICAgICAgICAgICAgICBib3gucGFkZGluZyA9IDAuMSwNCiAgICAgICAgICAgICAgICAgIG1heC5vdmVybGFwcyA9IEluZiwNCiAgICAgICAgICAgICAgICAgIHBvaW50LnBhZGRpbmcgPSAwLjYsDQogICAgICAgICAgICAgICAgICB4bGltID0gYygyMDIyLCBOQSksDQogICAgICAgICAgICAgICAgICBudWRnZV94ID0gMiwNCiAgICAgICAgICAgICAgICAgICMgbnVkZ2VfeSA9IDAuMCwNCiAgICAgICAgICAgICAgICAgIGZvcmNlID0gNSwNCiAgICAgICAgICAgICAgICAgIGhqdXN0ID0gMCwNCiAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbj0ieSIsDQogICAgICAgICAgICAgICAgICBuYS5ybSA9IEYpICsNCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxMykgKw0KICAgdGhlbWUocGFuZWwuZ3JpZC5taW5vci55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5ncmlkLm1pbm9yLnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBsb3QudGl0bGUucG9zaXRpb24gPSAicGxvdCIsDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZT0iYm9sZCIpLA0KICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsNCiAgICBjb29yZF9jYXJ0ZXNpYW4oY2xpcCA9ICJvZmYiKQ0KZ2dzYXZlKCJmaWd1cmVzL2VudHJvcHlfc3ViZGlzY2lwbGluZV9hbGwucGRmIiwgd2lkdGggPSA4LCBoZWlnaHQgPSA0KQ0KZ2dzYXZlKCJmaWd1cmVzL2VudHJvcHlfc3ViZGlzY2lwbGluZV9hbGwucG5nIiwgd2lkdGggPSA4LCBoZWlnaHQgPSA0KQ0KYGBgDQoNCiMjIyBvcmlnaW5hbCBtZWFzdXJlcw0KYGBge3IgZmlnLndpZHRoPTgsZmlnLmhlaWdodD00fQ0KZW50cm9weV9ieV95ZWFyIDwtIHBzeWN0ZXN0c19pbmZvICU+JSANCiAgZmlsdGVyKGJldHdlZW4oWWVhciwgMTk5MywgMjAyMikpICU+JSANCiAgbXV0YXRlKFRlc3QgPSBpZl9lbHNlKHRlc3RfdHlwZSA9PSAiT3JpZ2luYWwiLCBET0ksIG9yaWdpbmFsX3Rlc3RfRE9JKSkgJT4lIA0KICBkcm9wX25hKFRlc3QpICU+JSANCiAgZ3JvdXBfYnkoc3ViZGlzY2lwbGluZV8xLCBZZWFyLCBUZXN0KSAlPiUgDQogIHN1bW1hcmlzZShuID0gc3VtKHVzYWdlX2NvdW50LCBuYS5ybSA9IFQpKSAlPiUgDQogIGdyb3VwX2J5KHN1YmRpc2NpcGxpbmVfMSkgJT4lIA0KICBtdXRhdGUobl90ZXN0cyA9IG5fZGlzdGluY3QoVGVzdCkpICU+JSANCiAgZ3JvdXBfYnkoc3ViZGlzY2lwbGluZV8xLCBuX3Rlc3RzLCBZZWFyKSAlPiUgDQogIGZpbHRlcihuID4gMCkgJT4lIA0KICBzdW1tYXJpc2UoZW50cm9weSA9IGVudHJvcHkobiksLA0KICAgICAgICAgICAgbm9ybV9lbnRyb3B5ID0gY2FsY19ub3JtX2VudHJvcHkobiksDQogICAgICAgICAgICBuID0gc3VtKG4pLA0KICAgICAgICAgICAgZGlmZl90ZXN0cyA9IG4oKSkgJT4lIA0KICB1bmdyb3VwKCkNCg0KDQplbnRyb3B5X2J5X3llYXIgJT4lIA0KICBnZ3Bsb3QoLiwgYWVzKFllYXIsIG5vcm1fZW50cm9weSwgY29sb3IgPSBzdWJkaXNjaXBsaW5lXzEpKSArDQogIGdlb21fbGluZShzaXplID0gMC43KSArDQogIHNjYWxlX3lfY29udGludW91cygiTm9ybWFsaXplZCBTaGFubm9uIEVudHJvcHlcbihub3ZlbCBtZWFzdXJlcykiLCBsaW1pdHMgPSBjKDAsIDEpLCBsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQpICsNCiAgIyBnZW9tX2xpbmUoYWVzKHkgPSBsb2cobikpLCBjb2xvciA9ICdyZWQnKSArDQogIHNjYWxlX3hfY29udGludW91cygiVXNhZ2UgeWVhciBhcyBjb2RlZCBpbiBBUEEgUHN5Y0luZm8iLCBsaW1pdHMgPSBjKDE5OTMsIDIwMzApLCANCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNlcSgxOTkzLCAyMDIyLCBieSA9IDEpLA0KICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygxOTkzLCAiIiwgIiIsICIiLCAiIiwgMTk5OCwgIiIsICIiLCAiIiwgIiIsIDIwMDMsICIiLCAiIiwgIiIsICIiLCAyMDA4LCAiIiwgIiIsICIiLCAiIiwgMjAxMywgIiIsICIiLCAiIiwgIiIsIDIwMTgsICIiLCAiIiwgIiIsICIyMDIyIiksDQogICAgICAgICAgICAgICAgICAgICBleHBhbmQgPSBleHBhbnNpb24oYWRkID0gYygwLCAxNykpKSArDQogIHNjYWxlX2NvbG9yX2JyZXdlcih0eXBlID0gInF1YWwiLCBndWlkZSA9ICJub25lIiwgcGFsZXR0ZSA9IDIpICsNCiAgIyBnZ3RpdGxlKHN0cl9jKG5fZGlzdGluY3QodGVzdHNfYnlfeWVhciRUZXN0KSwgIiBtZWFzdXJlcyB0cmFja2VkIGluIFBzeWNJbmZvIikpICsNCiAjIGdlb21fdGV4dF9yZXBlbChhZXMobGFiZWwgPSBnc3ViKCJeLiokIiwgIiAiLCBzdWJkaXNjaXBsaW5lXzEpKSwgIyBUaGlzIHdpbGwgZm9yY2UgdGhlIGNvcnJlY3QgcG9zaXRpb24gb2YgdGhlIGxpbmsncyByaWdodCBlbmQuDQogIyAgICAgICAgICAgICAgICAgIGRhdGEgPSBlbnRyb3B5X2J5X3llYXIgJT4lIGRyb3BfbmEoKSAlPiUgZ3JvdXBfYnkoc3ViZGlzY2lwbGluZV8xKSAlPiUgZmlsdGVyKFllYXIgPT0gbWF4KFllYXIsIG5hLnJtID0gVCkpLA0KICMgICAgICAgICAgICAgICAgICBzZWdtZW50LmN1cnZhdHVyZSA9IC0wLjEsDQogIyAgICAgICAgICAgICAgICAgIHNlZ21lbnQuc3F1YXJlID0gVFJVRSwNCiAjICAgICAgICAgICAgICAgICAgc2VnbWVudC5jb2xvciA9ICdncmV5JywNCiAjICAgICAgICAgICAgICAgICAgYm94LnBhZGRpbmcgPSAwLjEsDQogIyAgICAgICAgICAgICAgICAgIHBvaW50LnBhZGRpbmcgPSAwLjYsDQogIyAgICAgICAgICAgICAgICAgIG1heC5vdmVybGFwcyA9IEluZiwNCiAjICAgICAgICAgICAgICAgICAgbnVkZ2VfeCA9IDEuMywNCiAjICAgICAgICAgICAgICAgICAgIyBudWRnZV95ID0gMCwNCiAjICAgICAgICAgICAgICAgICAgZm9yY2UgPSAyMCwNCiAjICAgICAgICAgICAgICAgICAgaGp1c3QgPSAwLA0KICMgICAgICAgICAgICAgICAgICBkaXJlY3Rpb249InkiLA0KICMgICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUNCiAjICApICsgIA0KICBnZW9tX3RleHRfcmVwZWwoZGF0YSA9IGVudHJvcHlfYnlfeWVhciAlPiUgZHJvcF9uYSgpICU+JSBncm91cF9ieShzdWJkaXNjaXBsaW5lXzEpICU+JSBmaWx0ZXIoWWVhciA9PSBtYXgoWWVhciwgbmEucm0gPSBUKSksDQogICAgICAgICAgICAgICAgICBhZXMobGFiZWwgPSBwYXN0ZTAoIiAgIixzdHJfcmVwbGFjZShzdWJkaXNjaXBsaW5lXzEsICIgUHN5Y2hvbG9neSIsICIiKSwgIiAobj0iLCBuX3Rlc3RzLCAiKSIpKSwNCiAgICAgICAgICAgICAgICAgICMgc2VnbWVudC5hbHBoYSA9IDAsICMjIFRoaXMgd2lsbCAnaGlkZScgdGhlIGxpbmsNCiAgICAgICAgICAgICAgICAgIHNlZ21lbnQuY3VydmF0dXJlID0gLTAuMSwNCiAgICAgICAgICAgICAgICAgIHNlZ21lbnQuc3F1YXJlID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgIHNlZ21lbnQuY29sb3IgPSAnZ3JleScsDQogICAgICAgICAgICAgICAgICBib3gucGFkZGluZyA9IDAuMSwNCiAgICAgICAgICAgICAgICAgIG1heC5vdmVybGFwcyA9IEluZiwNCiAgICAgICAgICAgICAgICAgIHBvaW50LnBhZGRpbmcgPSAwLjYsDQogICAgICAgICAgICAgICAgICB4bGltID0gYygyMDIyLCBOQSksDQogICAgICAgICAgICAgICAgICBudWRnZV94ID0gMiwNCiAgICAgICAgICAgICAgICAgICMgbnVkZ2VfeSA9IDAuMCwNCiAgICAgICAgICAgICAgICAgIGZvcmNlID0gNSwNCiAgICAgICAgICAgICAgICAgIGhqdXN0ID0gMCwNCiAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbj0ieSIsDQogICAgICAgICAgICAgICAgICBuYS5ybSA9IEYpICArDQogICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yLnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGxvdC50aXRsZS5wb3NpdGlvbiA9ICJwbG90IiwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlPSJib2xkIiksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKw0KICAgIGNvb3JkX2NhcnRlc2lhbihjbGlwID0gIm9mZiIpDQpnZ3NhdmUoImZpZ3VyZXMvZW50cm9weV9zdWJkaXNjaXBsaW5lX29yaWcucGRmIiwgd2lkdGggPSA4LCBoZWlnaHQgPSA0KQ0KZ2dzYXZlKCJmaWd1cmVzL2VudHJvcHlfc3ViZGlzY2lwbGluZV9vcmlnLnBuZyIsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNCkNCmBgYA0KIyMjIGNvbnN0cnVjdHMNCmBgYHtyfQ0KZW50cm9weV9ieV95ZWFyIDwtIHBzeWN0ZXN0c19pbmZvICU+JSANCiAgZmlsdGVyKGJldHdlZW4oWWVhciwgMTk5MywgMjAyMikpICU+JSANCiAgZ3JvdXBfYnkoc3ViZGlzY2lwbGluZV8xLCBZZWFyLCBUZXN0ID0gZmlyc3RfY29uc3RydWN0KSAlPiUgDQogIHN1bW1hcmlzZShuID0gc3VtKHVzYWdlX2NvdW50LCBuYS5ybSA9IFQpKSAlPiUgDQogIGdyb3VwX2J5KHN1YmRpc2NpcGxpbmVfMSkgJT4lIA0KICBtdXRhdGUobl90ZXN0cyA9IG5fZGlzdGluY3QoVGVzdCkpICU+JSANCiAgZ3JvdXBfYnkoc3ViZGlzY2lwbGluZV8xLCBuX3Rlc3RzLCBZZWFyKSAlPiUgDQogIGZpbHRlcihuID4gMCkgJT4lIA0KICBzdW1tYXJpc2UoZW50cm9weSA9IGVudHJvcHkobiksLA0KICAgICAgICAgICAgbm9ybV9lbnRyb3B5ID0gY2FsY19ub3JtX2VudHJvcHkobiksDQogICAgICAgICAgICBuID0gc3VtKG4pLA0KICAgICAgICAgICAgZGlmZl90ZXN0cyA9IG4oKSkgJT4lIA0KICB1bmdyb3VwKCkNCg0KDQplbnRyb3B5X2J5X3llYXIgJT4lIA0KICBnZ3Bsb3QoLiwgYWVzKFllYXIsIG5vcm1fZW50cm9weSwgY29sb3IgPSBzdWJkaXNjaXBsaW5lXzEpKSArDQogIGdlb21fbGluZShzaXplID0gMC43KSArDQogIHNjYWxlX3lfY29udGludW91cygiTm9ybWFsaXplZCBTaGFubm9uIEVudHJvcHkgKGNvbnN0cnVjdHMpIiwgbGltaXRzID0gYygwLCAxKSwgbGFiZWxzID0gc2NhbGVzOjpwZXJjZW50KSArDQogICMgZ2VvbV9saW5lKGFlcyh5ID0gbG9nKG4pKSwgY29sb3IgPSAncmVkJykgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoIlVzYWdlIHllYXIgYXMgY29kZWQgaW4gQVBBIFBzeWNJbmZvIiwgbGltaXRzID0gYygxOTkzLCAyMDM4KSwgDQogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzZXEoMTk5MywgMjAyMiwgYnkgPSAxKSwNCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoMTk5MywgIiIsICIiLCAiIiwgIiIsIDE5OTgsICIiLCAiIiwgIiIsICIiLCAyMDAzLCAiIiwgIiIsICIiLCAiIiwgMjAwOCwgIiIsICIiLCAiIiwgIiIsIDIwMTMsICIiLCAiIiwgIiIsICIiLCAyMDE4LCAiIiwgIiIsICIiLCAiMjAyMiIpLA0KICAgICAgICAgICAgICAgICAgICAgZXhwYW5kID0gZXhwYW5zaW9uKGFkZCA9IGMoMCwgMTApKSkgKw0KICBzY2FsZV9jb2xvcl9icmV3ZXIodHlwZSA9ICJxdWFsIiwgZ3VpZGUgPSAibm9uZSIsIHBhbGV0dGUgPSAyKSArDQogICMgZ2d0aXRsZShzdHJfYyhuX2Rpc3RpbmN0KHRlc3RzX2J5X3llYXIkVGVzdCksICIgbWVhc3VyZXMgdHJhY2tlZCBpbiBQc3ljSW5mbyIpKSArDQogICMgZ2dyZXBlbDo6Z2VvbV90ZXh0X3JlcGVsKA0KICAjICAgYWVzKGxhYmVsID0gc3RyX3JlcGxhY2Uoc3ViZGlzY2lwbGluZSwgIiBQc3ljaG9sb2d5IiwgIiIpKSwgZGF0YSA9IGVudHJvcHlfYnlfeWVhciAlPiUgZmlsdGVyKFllYXIgPT0gbWF4KFllYXIsIG5hLnJtID0gVCkpLA0KICAjICAgc2l6ZSA9IDQsIGhqdXN0ID0gMSwNCiAgIyAgICkgKyANCiAgZ2VvbV90ZXh0X3JlcGVsKGRhdGEgPSBlbnRyb3B5X2J5X3llYXIgJT4lIGRyb3BfbmEoKSAlPiUgZ3JvdXBfYnkoc3ViZGlzY2lwbGluZV8xKSAlPiUgZmlsdGVyKFllYXIgPT0gbWF4KFllYXIsIG5hLnJtID0gVCkpLA0KICAgICAgICAgICAgICAgICAgYWVzKGxhYmVsID0gcGFzdGUwKCIgICIsc3RyX3JlcGxhY2Uoc3ViZGlzY2lwbGluZV8xLCAiIFBzeWNob2xvZ3kiLCAiIiksICIgKG49Iiwgbl90ZXN0cywgIikiKSksDQogICAgICAgICAgICAgICAgICAjIHNlZ21lbnQuYWxwaGEgPSAwLCAjIyBUaGlzIHdpbGwgJ2hpZGUnIHRoZSBsaW5rDQogICAgICAgICAgICAgICAgICBzZWdtZW50LmN1cnZhdHVyZSA9IC0wLjEsDQogICAgICAgICAgICAgICAgICBzZWdtZW50LnNxdWFyZSA9IFRSVUUsDQogICAgICAgICAgICAgICAgICBzZWdtZW50LmNvbG9yID0gJ2dyZXknLA0KICAgICAgICAgICAgICAgICAgYm94LnBhZGRpbmcgPSAwLjEsDQogICAgICAgICAgICAgICAgICBtYXgub3ZlcmxhcHMgPSBJbmYsDQogICAgICAgICAgICAgICAgICBwb2ludC5wYWRkaW5nID0gMC42LA0KICAgICAgICAgICAgICAgICAgeGxpbSA9IGMoMjAyMiwgTkEpLA0KICAgICAgICAgICAgICAgICAgbnVkZ2VfeCA9IDIsDQogICAgICAgICAgICAgICAgICAjIG51ZGdlX3kgPSAwLjAsDQogICAgICAgICAgICAgICAgICBmb3JjZSA9IDUsDQogICAgICAgICAgICAgICAgICBoanVzdCA9IDAsDQogICAgICAgICAgICAgICAgICBkaXJlY3Rpb249InkiLA0KICAgICAgICAgICAgICAgICAgbmEucm0gPSBGKSArDQogICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yLnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGxvdC50aXRsZS5wb3NpdGlvbiA9ICJwbG90IiwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlPSJib2xkIiksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCmdnc2F2ZSgiZmlndXJlcy9lbnRyb3B5X3N1YmRpc2NpcGxpbmVfY29uc3RydWN0cy5wZGYiLCB3aWR0aCA9IDgsIGhlaWdodCA9IDQpDQpnZ3NhdmUoImZpZ3VyZXMvZW50cm9weV9zdWJkaXNjaXBsaW5lX2NvbnN0cnVjdHMucG5nIiwgd2lkdGggPSA4LCBoZWlnaHQgPSA0KQ0KYGBgDQoNCiMjIyBCeSBpbnN0cnVtZW50IHR5cGUNCmBgYHtyfQ0KZW50cm9weV9ieV95ZWFyIDwtIHBzeWN0ZXN0c19pbmZvICU+JSANCiAgZmlsdGVyKGJldHdlZW4oWWVhciwgMTk5MywgMjAyMikpICU+JSANCiAgZ3JvdXBfYnkoaW5zdHJ1bWVudF90eXBlX2Jyb2FkLCBZZWFyLCBUZXN0ID0gRE9JKSAlPiUgDQogIHN1bW1hcmlzZShuID0gc3VtKHVzYWdlX2NvdW50LCBuYS5ybSA9IFQpKSAlPiUgDQogIGdyb3VwX2J5KGluc3RydW1lbnRfdHlwZV9icm9hZCkgJT4lIA0KICBtdXRhdGUobl90ZXN0cyA9IG5fZGlzdGluY3QoVGVzdCkpICU+JSANCiAgZ3JvdXBfYnkoaW5zdHJ1bWVudF90eXBlX2Jyb2FkLCBuX3Rlc3RzLCBZZWFyKSAlPiUgDQogIGZpbHRlcihuID4gMCkgJT4lIA0KICBzdW1tYXJpc2UoZW50cm9weSA9IGVudHJvcHkobiksDQogICAgICAgICAgICBub3JtX2VudHJvcHkgPSBjYWxjX25vcm1fZW50cm9weShuKSwNCiAgICAgICAgICAgIG4gPSBzdW0obiksDQogICAgICAgICAgICBkaWZmX3Rlc3RzID0gbigpKSAlPiUgDQogIHVuZ3JvdXAoKQ0KDQoNCg0KZW50cm9weV9ieV95ZWFyICU+JSANCiAgZ2dwbG90KC4sIGFlcyhZZWFyLCBub3JtX2VudHJvcHksIGNvbG9yID0gaW5zdHJ1bWVudF90eXBlX2Jyb2FkKSkgKw0KICBnZW9tX2xpbmUoc2l6ZSA9IDAuNykgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoIk5vcm1hbGl6ZWQgU2hhbm5vbiBFbnRyb3B5IiwgbGltaXRzID0gYygwLCAxKSwgbGFiZWxzID0gc2NhbGVzOjpwZXJjZW50KSArDQogICMgZ2VvbV9saW5lKGFlcyh5ID0gbG9nKG4pKSwgY29sb3IgPSAncmVkJykgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygxOTkzLCAyMDI3KSwgYnJlYWtzID0gYygxOTkzLCAxOTk4LCAyMDAzLCAyMDA4LCAyMDEzLCAyMDE4LCAyMDIyKSkgKw0KICBzY2FsZV9jb2xvcl9icmV3ZXIodHlwZSA9ICJxdWFsIiwgZ3VpZGUgPSAibm9uZSIsIHBhbGV0dGUgPSAzKSArDQogICMgZ2dyZXBlbDo6Z2VvbV90ZXh0X3JlcGVsKA0KICAjICAgYWVzKGxhYmVsID0gc3RyX3JlcGxhY2Uoc3ViZGlzY2lwbGluZSwgIiBQc3ljaG9sb2d5IiwgIiIpKSwgZGF0YSA9IGVudHJvcHlfYnlfeWVhciAlPiUgZmlsdGVyKFllYXIgPT0gbWF4KFllYXIsIG5hLnJtID0gVCkpLA0KICAjICAgc2l6ZSA9IDQsIGhqdXN0ID0gMSwNCiAgIyAgICkgKyANCiAgZ2VvbV90ZXh0X3JlcGVsKGFlcyhsYWJlbCA9IGdzdWIoIl4uKiQiLCAiICIsIGluc3RydW1lbnRfdHlwZV9icm9hZCkpLCAjIFRoaXMgd2lsbCBmb3JjZSB0aGUgY29ycmVjdCBwb3NpdGlvbiBvZiB0aGUgbGluaydzIHJpZ2h0IGVuZC4NCiAgICAgICAgICAgICAgICAgIGRhdGEgPSBlbnRyb3B5X2J5X3llYXIgJT4lIGZpbHRlcihZZWFyID09IG1heChZZWFyLCBuYS5ybSA9IFQpKSwNCiAgICAgICAgICAgICAgICAgIHNlZ21lbnQuY3VydmF0dXJlID0gLTAuMSwNCiAgICAgICAgICAgICAgICAgIHNlZ21lbnQuc3F1YXJlID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgIHNlZ21lbnQuY29sb3IgPSAnZ3JleScsDQogICAgICAgICAgICAgICAgICBib3gucGFkZGluZyA9IDAuMSwNCiAgICAgICAgICAgICAgICAgIHBvaW50LnBhZGRpbmcgPSAwLjYsDQogICAgICAgICAgICAgICAgICBudWRnZV94ID0gMC4xNSwNCiAgICAgICAgICAgICAgICAgIG51ZGdlX3kgPSAwLjA1LA0KICAgICAgICAgICAgICAgICAgZm9yY2UgPSAwLjUsDQogICAgICAgICAgICAgICAgICBoanVzdCA9IDAsDQogICAgICAgICAgICAgICAgICBkaXJlY3Rpb249InkiLA0KICAgICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFDQogICkgKw0KICBnZW9tX3RleHRfcmVwZWwoZGF0YSA9IGVudHJvcHlfYnlfeWVhciAlPiUgZmlsdGVyKFllYXIgPT0gbWF4KFllYXIsIG5hLnJtID0gVCkpLA0KICAgICAgICAgICAgICAgICAgYWVzKGxhYmVsID0gcGFzdGUwKCIgICIsc3RyX3JlcGxhY2UoaW5zdHJ1bWVudF90eXBlX2Jyb2FkLCAiIFBzeWNob2xvZ3kiLCAiIiksICIgKG49Iiwgbl90ZXN0cywgIikiKSksDQogICAgICAgICAgICAgICAgICBzZWdtZW50LmFscGhhID0gMCwgIyMgVGhpcyB3aWxsICdoaWRlJyB0aGUgbGluaw0KICAgICAgICAgICAgICAgICAgc2VnbWVudC5jdXJ2YXR1cmUgPSAtMC4xLA0KICAgICAgICAgICAgICAgICAgc2VnbWVudC5zcXVhcmUgPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgIyBzZWdtZW50LmNvbG9yID0gJ2dyZXknLA0KICAgICAgICAgICAgICAgICAgYm94LnBhZGRpbmcgPSAwLjEsDQogICAgICAgICAgICAgICAgICBwb2ludC5wYWRkaW5nID0gMC42LA0KICAgICAgICAgICAgICAgICAgbnVkZ2VfeCA9IDAuMTUsDQogICAgICAgICAgICAgICAgICBudWRnZV95ID0gMC4wNSwNCiAgICAgICAgICAgICAgICAgIGZvcmNlID0gMC41LA0KICAgICAgICAgICAgICAgICAgaGp1c3QgPSAwLA0KICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uPSJ5IiwNCiAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRSkrDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTMpICsNCiAgIHRoZW1lKHBhbmVsLmdyaWQubWlub3IueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vci54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwbG90LnRpdGxlLnBvc2l0aW9uID0gInBsb3QiLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2U9ImJvbGQiKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KYGBgDQoNCg0KIyMgTG9yZW56IGN1cnZlcw0KYGBge3J9DQp0ZXN0X2ZyZXF1ZW5jeSA8LSBwc3ljdGVzdHNfaW5mbyAlPiUgDQogIG11dGF0ZShUZXN0ID0gaWZfZWxzZSh0ZXN0X3R5cGUgPT0gIk9yaWdpbmFsIiwgRE9JLCBvcmlnaW5hbF90ZXN0X0RPSSkpICU+JSANCiAgZHJvcF9uYShUZXN0KSAlPiUgDQogICMgZmlsdGVyKFRlc3RZZWFyID49IDE5OTApICU+JQ0KICBmaWx0ZXIoYmV0d2VlbihZZWFyLCAxOTkzLCAyMDIyKSkgJT4lDQogIGdyb3VwX2J5KHN1YmRpc2NpcGxpbmVfMSwgVGVzdCkgJT4lIA0KICBzdW1tYXJpc2UobiA9IHN1bSh1c2FnZV9jb3VudCwgbmEucm0gPSBUKSkgJT4lIA0KICBhcnJhbmdlKG4pICU+JSANCiAgbXV0YXRlKGRlY2lsZSA9IEhtaXNjOjpjdXQyKG4sIGcgPSAxMCkpICU+JSANCiAgbXV0YXRlKGN1bXN1bSA9IGN1bXN1bShuKSwNCiAgICAgICAgIHN1bSA9IHN1bShuKSkNCiMgDQojIHRlc3RfZnJlcXVlbmN5ICU+JSANCiMgICAgIGdyb3VwX2J5KHN1YmRpc2NpcGxpbmVfMSwgZGVjaWxlKSAlPiUgDQojICAgICBzdW1tYXJpc2Uoc2hhcmUgPSBzdW0obikvZmlyc3Qoc3VtKSwNCiMgICAgICAgICAgICAgICBtZWRpYW5fbiA9IG1lZGlhbihuKSwNCiMgICAgICAgICAgICAgICBuX21lYXN1cmVzID0gbigpKSAlPiUgDQojICAgVmlldygpDQoNCg0KZ2dwbG90KHRlc3RfZnJlcXVlbmN5LCBhZXMobikpICsNCiAgc3RhdF9sb3JlbnooZGVzYyA9IEYpICsNCiAgY29vcmRfZml4ZWQoKSArDQogIGdlb21fYWJsaW5lKGxpbmV0eXBlID0gImRhc2hlZCIpICsNCiAgICAgIHRoZW1lX21pbmltYWwoKSArDQogICAgaHJicnRoZW1lczo6c2NhbGVfeF9wZXJjZW50KCJDdW11bGF0aXZlIHBlcmNlbnRhZ2Ugb2YgbWVhc3VyZXMiKSArDQogICAgaHJicnRoZW1lczo6c2NhbGVfeV9wZXJjZW50KCJDdW11bGF0aXZlIHBlcmNlbnRhZ2Ugb2YgbWVhc3VyZSBtYXJrZXQgc2hhcmUiKSAjKw0KIyAgICBocmJydGhlbWVzOjp0aGVtZV9pcHN1bV9yYygpDQoNCmdncGxvdCh0ZXN0X2ZyZXF1ZW5jeSwgYWVzKG4sIGNvbG9yID0gc3ViZGlzY2lwbGluZV8xKSkgKw0KICBzdGF0X2xvcmVueihkZXNjID0gRikgKw0KICBjb29yZF9maXhlZCgpICsNCiAgZ2VvbV9hYmxpbmUobGluZXR5cGUgPSAiZGFzaGVkIikgKw0KICAgICAgdGhlbWVfbWluaW1hbCgpICsNCiAgICBocmJydGhlbWVzOjpzY2FsZV94X3BlcmNlbnQoIkN1bXVsYXRpdmUgcGVyY2VudGFnZSBvZiBtZWFzdXJlcyIpICsNCiAgICBocmJydGhlbWVzOjpzY2FsZV95X3BlcmNlbnQoIkN1bXVsYXRpdmUgcGVyY2VudGFnZSBvZiBtZWFzdXJlIG1hcmtldCBzaGFyZSIpDQpgYGANCg0KIyBTdXJ2aXZhbA0KDQojIyBhZ2dyZWdhdGUgc3RhdHMNCmBgYHtyfQ0KDQpjb25zdHJ1Y3RzIDwtIHBzeWN0ZXN0c19pbmZvICU+JSANCiAgICAgIyBmaWx0ZXIoYmV0d2VlbihmaXJzdF9wdWJfeWVhciwgMTk1MCwgMjAxNSkpICU+JQ0KICAgICB1bm5lc3QoQ29uc3RydWN0TGlzdCkgJT4lIA0KICAgICByb3d3aXNlKCkgJT4lIA0KICAgICBtdXRhdGUoY29uc3RydWN0ID0gdW5saXN0KENvbnN0cnVjdExpc3QpKSAlPiUgDQogICAgIHNlbGVjdCgtQ29uc3RydWN0TGlzdCkgJT4lIA0KICAgICBmaWx0ZXIoYmV0d2VlbihZZWFyLCAxOTkzLCAyMDIyKSkgJT4lIA0KICAgICBkcm9wX25hKGNvbnN0cnVjdCkgJT4lIA0KICAgICBtdXRhdGUoc3Vydml2YWwgPSBsYXN0X3B1Yl95ZWFyIC0gZmlyc3RfcHViX3llYXIsDQogICAgICAgICAgICBzdXJ2aXZlZF9maXZlID0gaWZfZWxzZShzdXJ2aXZhbCA+PSA1LCBULCBGKSwNCiAgICAgICAgICAgIHN1cnZpdmVkX3RlbiA9IGlmX2Vsc2Uoc3Vydml2YWwgPj0gMTAsIFQsIEYpKSAlPiUNCiAgICAgZGlzdGluY3QoY29uc3RydWN0LCAua2VlcF9hbGwgPSBUUlVFKQ0KDQptZWFuKGNvbnN0cnVjdHMkc3Vydml2YWwsIG5hLnJtID0gVCkNCnNkKGNvbnN0cnVjdHMkc3Vydml2YWwsIG5hLnJtID0gVCkNCm1lZGlhbihjb25zdHJ1Y3RzJHN1cnZpdmFsLCBuYS5ybSA9IFQpDQptYXgoY29uc3RydWN0cyRzdXJ2aXZhbCwgbmEucm0gPSBUKQ0KbWluKGNvbnN0cnVjdHMkc3Vydml2YWwsIG5hLnJtID0gVCkNCmBgYA0KDQpgYGB7cn0NCg0KbWVhc3VyZXMgPC0gcHN5Y3Rlc3RzX2luZm8gJT4lIA0KICAgICBmaWx0ZXIoYmV0d2VlbihZZWFyLCAxOTkzLCAyMDIyKSkgICU+JSANCiAgICAgbXV0YXRlKHN1cnZpdmFsID0gbGFzdF9wdWJfeWVhciAtIGZpcnN0X3B1Yl95ZWFyLA0KICAgICAgICAgICAgc3Vydml2ZWRfZml2ZSA9IGlmX2Vsc2Uoc3Vydml2YWwgPj0gNSwgVCwgRiksDQogICAgICAgICAgICBzdXJ2aXZlZF90ZW4gPSBpZl9lbHNlKHN1cnZpdmFsID49IDEwLCBULCBGKSkgJT4lDQogICAgIGRpc3RpbmN0KERPSSwgLmtlZXBfYWxsID0gVFJVRSkNCg0KbWVhbihtZWFzdXJlcyRzdXJ2aXZhbCwgbmEucm0gPSBUKQ0Kc2QobWVhc3VyZXMkc3Vydml2YWwsIG5hLnJtID0gVCkNCm1lZGlhbihtZWFzdXJlcyRzdXJ2aXZhbCwgbmEucm0gPSBUKQ0KbWF4KG1lYXN1cmVzJHN1cnZpdmFsLCBuYS5ybSA9IFQpDQptaW4obWVhc3VyZXMkc3Vydml2YWwsIG5hLnJtID0gVCkNCmBgYA0KDQoNCiMjIGN1bXVsYXRpdmUgc3VtIA0KIyMjIGFsbCBjb25zdHJ1Y3RzDQpgYGB7cn0NCmN1bXN1bV9jb25zdHJ1Y3QgPC0gY29uc3RydWN0cyAlPiUgDQogIGFycmFuZ2UoVGVzdFllYXIpICU+JSANCiAgZ3JvdXBfYnkoVGVzdFllYXIpICU+JSANCiAgc3VtbWFyaXNlKGNvbnN0cnVjdHMgPSBuX2Rpc3RpbmN0KERPSSkpICU+JSANCiAgYXJyYW5nZShUZXN0WWVhcikgJT4lIA0KICBtdXRhdGUoY29uc3RydWN0cyA9IGN1bXN1bShjb25zdHJ1Y3RzKSkgDQoNCmN1bXN1bV9jb25zdHJ1Y3Rfc3Vydml2ZWRfNSA8LSBjb25zdHJ1Y3RzICU+JSANCiAgZmlsdGVyKHN1cnZpdmVkX2ZpdmUgPT0gVCkgJT4lIA0KICBhcnJhbmdlKFRlc3RZZWFyKSAlPiUgDQogIGdyb3VwX2J5KFRlc3RZZWFyKSAlPiUgDQogIHN1bW1hcmlzZShjb25zdHJ1Y3RzID0gbl9kaXN0aW5jdChET0kpKSAlPiUgDQogIGFycmFuZ2UoVGVzdFllYXIpICU+JSANCiAgbXV0YXRlKGNvbnN0cnVjdHMgPSBjdW1zdW0oY29uc3RydWN0cykpIA0KICANCmN1bXN1bV9jb25zdHJ1Y3Rfc3Vydml2ZWRfMTAgPC0gY29uc3RydWN0cyAlPiUgDQogIGZpbHRlcihzdXJ2aXZlZF90ZW4gPT0gVCkgJT4lIA0KICBhcnJhbmdlKFRlc3RZZWFyKSAlPiUgDQogIGdyb3VwX2J5KFRlc3RZZWFyKSAlPiUgDQogIHN1bW1hcmlzZShjb25zdHJ1Y3RzID0gbl9kaXN0aW5jdChET0kpKSAlPiUgDQogIGFycmFuZ2UoVGVzdFllYXIpICU+JSANCiAgbXV0YXRlKGNvbnN0cnVjdHMgPSBjdW1zdW0oY29uc3RydWN0cykpIA0KDQoNCg0KY3Vtc3VtcyA8LSBiaW5kX3Jvd3MoDQogICJhbGwgY29uc3RydWN0cyIgPSBjdW1zdW1fY29uc3RydWN0LA0KICAiY29uc3RydWN0cyBpbiB1c2VcbiBmb3IgPT4gNSB5ZWFycyIgPSBjdW1zdW1fY29uc3RydWN0X3N1cnZpdmVkXzUsDQogICJjb25zdHJ1Y3RzIGluIHVzZVxuIGZvciA9PiAxMCB5ZWFycyIgPSBjdW1zdW1fY29uc3RydWN0X3N1cnZpdmVkXzEwLA0KICAuaWQgPSAib3JpZ2luIg0KICApICU+JSANCiAgcmVuYW1lKFllYXIgPSBUZXN0WWVhcikgJT4lIA0KICBmaWx0ZXIoWWVhciA8PSAyMDIyKQ0KDQoNCmdncGxvdChjdW1zdW1zLCBhZXMoWWVhciwgY29uc3RydWN0cywgY29sb3IgPSBvcmlnaW4pKSArIA0KICBnZW9tX2xpbmUoKSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDIwMTYsIGxpbmV0eXBlID0gJ2Rhc2hlZCcpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKCJDdW11bGF0aXZlIG51bWJlciBvZiBjb25zdHJ1Y3RzIikgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoIlB1YmxpY2F0aW9uIHllYXIgaW4gQVBBIFBzeWNUZXN0cyIsDQogICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKDE5OTMsIDIwMzApLCANCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNlcSgxOTkzLDIwMjIsIGJ5ID0gMSksDQogICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKDE5OTMsICIiLCAiIiwgIiIsICIiLCAxOTk4LCAiIiwgIiIsICIiLCAiIiwgMjAwMywgIiIsICIiLCAiIiwgIiIsIDIwMDgsICIiLCAiIiwgIiIsICIiLCAyMDEzLCAiIiwgIiIsICIiLCAiIiwgMjAxOCwgIiIsICIiLCAiIiwgIjIwMjIiKSwNCiAgICAgICAgICAgICAgICAgICAgIGV4cGFuZCA9IGV4cGFuc2lvbihhZGQgPSBjKDAsIDEpKSkgKw0KICBzY2FsZV9jb2xvcl9icmV3ZXIodHlwZSA9ICJxdWFsIiwgZ3VpZGUgPSAibm9uZSIsIHBhbGV0dGUgPSAyKSArDQogICMgZ2dyZXBlbDo6Z2VvbV90ZXh0X3JlcGVsKA0KICAjICAgYWVzKGxhYmVsID0gc3RyX3JlcGxhY2Uoc3ViZGlzY2lwbGluZSwgIiBQc3ljaG9sb2d5IiwgIiIpKSwgZGF0YSA9IGVudHJvcHlfYnlfeWVhciAlPiUgZmlsdGVyKFllYXIgPT0gbWF4KFllYXIsIG5hLnJtID0gVCkpLA0KICAjICAgc2l6ZSA9IDQsIGhqdXN0ID0gMSwNCiAgIyAgICkgICsNCiAgZ2VvbV90ZXh0X3JlcGVsKGRhdGEgPSBjdW1zdW1zICU+JSBkcm9wX25hKCkgJT4lIGdyb3VwX2J5KG9yaWdpbikgJT4lIGZpbHRlcihZZWFyID09IG1heChZZWFyLCBuYS5ybSA9IFQpKSwNCiAgICAgICAgICAgICAgICAgIGFlcyhsYWJlbCA9IHBhc3RlMCgiICIsIG9yaWdpbiwgIlxuIChuID0gIiwgY29uc3RydWN0cywgIikiKSksDQogICAgICAgICAgICAgICAgICBzZWdtZW50LnNxdWFyZSA9IFRSVUUsDQogICAgICAgICAgICAgICAgICBsaW5laGVpZ2h0ID0gLjksDQogICAgICAgICAgICAgICAgICBzZWdtZW50LmNvbG9yID0gJ2dyZXknLA0KICAgICAgICAgICAgICAgICAgbnVkZ2VfeCA9IDEuMiwNCiAgICAgICAgICAgICAgICAgIGhqdXN0ID0gMCwNCiAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRSkrDQogICAjIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTMpICsNCiAgIHRoZW1lKHBhbmVsLmdyaWQubWlub3IueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vci54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwbG90LnRpdGxlLnBvc2l0aW9uID0gInBsb3QiLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2U9ImJvbGQiKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSAgKw0KICAgIGd1aWRlcygNCiAgICB4ID0gZ3VpZGVfYXhpcyhjYXAgPSAiYm90aCIpLCAjIENhcCBib3RoIGVuZHMNCiAgKQ0KDQpnZ3NhdmUoImZpZ3VyZXMvY3Vtc3Vtc19zdXJ2aXZhbF9hbGwucGRmIiwgd2lkdGggPSA4LCBoZWlnaHQgPSA0KQ0KZ2dzYXZlKCJmaWd1cmVzL2N1bXN1bXNfc3Vydml2YWxfYWxsLnBuZyIsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNCkNCmBgYA0KDQojIyMgZmlyc3QgY29uc3RydWN0cw0KYGBge3J9DQpmaXJzdF9jb25zdHJ1Y3RzIDwtIGNvbnN0cnVjdHMgJT4lDQogIGRpc3RpbmN0KGZpcnN0X2NvbnN0cnVjdCwgLmtlZXBfYWxsID0gVFJVRSkNCg0KDQpjdW1zdW1fY29uc3RydWN0IDwtIGZpcnN0X2NvbnN0cnVjdHMgJT4lIA0KICBhcnJhbmdlKFRlc3RZZWFyKSAlPiUgDQogIGdyb3VwX2J5KFRlc3RZZWFyKSAlPiUgDQogIHN1bW1hcmlzZShjb25zdHJ1Y3RzID0gbl9kaXN0aW5jdChET0kpKSAlPiUgDQogIGFycmFuZ2UoVGVzdFllYXIpICU+JSANCiAgbXV0YXRlKGNvbnN0cnVjdHMgPSBjdW1zdW0oY29uc3RydWN0cykpIA0KDQpjdW1zdW1fY29uc3RydWN0X3N1cnZpdmVkXzUgPC0gZmlyc3RfY29uc3RydWN0cyAlPiUgDQogIGZpbHRlcihzdXJ2aXZlZF9maXZlID09IFQpICU+JSANCiAgYXJyYW5nZShUZXN0WWVhcikgJT4lIA0KICBncm91cF9ieShUZXN0WWVhcikgJT4lIA0KICBzdW1tYXJpc2UoY29uc3RydWN0cyA9IG5fZGlzdGluY3QoRE9JKSkgJT4lIA0KICBhcnJhbmdlKFRlc3RZZWFyKSAlPiUgDQogIG11dGF0ZShjb25zdHJ1Y3RzID0gY3Vtc3VtKGNvbnN0cnVjdHMpKSANCiAgDQpjdW1zdW1fY29uc3RydWN0X3N1cnZpdmVkXzEwIDwtIGZpcnN0X2NvbnN0cnVjdHMgJT4lIA0KICBmaWx0ZXIoc3Vydml2ZWRfdGVuID09IFQpICU+JSANCiAgYXJyYW5nZShUZXN0WWVhcikgJT4lIA0KICBncm91cF9ieShUZXN0WWVhcikgJT4lIA0KICBzdW1tYXJpc2UoY29uc3RydWN0cyA9IG5fZGlzdGluY3QoRE9JKSkgJT4lIA0KICBhcnJhbmdlKFRlc3RZZWFyKSAlPiUgDQogIG11dGF0ZShjb25zdHJ1Y3RzID0gY3Vtc3VtKGNvbnN0cnVjdHMpKSANCg0KDQoNCmN1bXN1bXMgPC0gYmluZF9yb3dzKA0KICAiYWxsIGNvbnN0cnVjdHMiID0gY3Vtc3VtX2NvbnN0cnVjdCwNCiAgImNvbnN0cnVjdHMgaW4gdXNlXG4gZm9yID0+IDUgeWVhcnMiID0gY3Vtc3VtX2NvbnN0cnVjdF9zdXJ2aXZlZF81LA0KICAiY29uc3RydWN0cyBpbiB1c2VcbiBmb3IgPT4gMTAgeWVhcnMiID0gY3Vtc3VtX2NvbnN0cnVjdF9zdXJ2aXZlZF8xMCwNCiAgLmlkID0gIm9yaWdpbiINCiAgKSAlPiUgDQogIHJlbmFtZShZZWFyID0gVGVzdFllYXIpICU+JSANCiAgZmlsdGVyKFllYXIgPD0gMjAyMikNCg0KDQpnZ3Bsb3QoY3Vtc3VtcywgYWVzKFllYXIsIGNvbnN0cnVjdHMsIGNvbG9yID0gb3JpZ2luKSkgKyANCiAgZ2VvbV9saW5lKCkgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAyMDE2LCBsaW5ldHlwZSA9ICdkYXNoZWQnKSArDQogIHNjYWxlX3lfY29udGludW91cygiQ3VtdWxhdGl2ZSBudW1iZXIgb2YgY29uc3RydWN0cyIpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKCJQdWJsaWNhdGlvbiB5ZWFyIGluIEFQQSBQc3ljVGVzdHMiLA0KICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygxOTkzLCAyMDMwKSwgDQogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzZXEoMTk5MywyMDIyLCBieSA9IDEpLA0KICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygxOTkzLCAiIiwgIiIsICIiLCAiIiwgMTk5OCwgIiIsICIiLCAiIiwgIiIsIDIwMDMsICIiLCAiIiwgIiIsICIiLCAyMDA4LCAiIiwgIiIsICIiLCAiIiwgMjAxMywgIiIsICIiLCAiIiwgIiIsIDIwMTgsICIiLCAiIiwgIiIsICIyMDIyIiksDQogICAgICAgICAgICAgICAgICAgICBleHBhbmQgPSBleHBhbnNpb24oYWRkID0gYygwLCAxKSkpICsNCiAgc2NhbGVfY29sb3JfYnJld2VyKHR5cGUgPSAicXVhbCIsIGd1aWRlID0gIm5vbmUiLCBwYWxldHRlID0gMikgKw0KICAjIGdncmVwZWw6Omdlb21fdGV4dF9yZXBlbCgNCiAgIyAgIGFlcyhsYWJlbCA9IHN0cl9yZXBsYWNlKHN1YmRpc2NpcGxpbmUsICIgUHN5Y2hvbG9neSIsICIiKSksIGRhdGEgPSBlbnRyb3B5X2J5X3llYXIgJT4lIGZpbHRlcihZZWFyID09IG1heChZZWFyLCBuYS5ybSA9IFQpKSwNCiAgIyAgIHNpemUgPSA0LCBoanVzdCA9IDEsDQogICMgICApICArDQogIGdlb21fdGV4dF9yZXBlbChkYXRhID0gY3Vtc3VtcyAlPiUgZHJvcF9uYSgpICU+JSBncm91cF9ieShvcmlnaW4pICU+JSBmaWx0ZXIoWWVhciA9PSBtYXgoWWVhciwgbmEucm0gPSBUKSksDQogICAgICAgICAgICAgICAgICBhZXMobGFiZWwgPSBwYXN0ZTAoIiAiLCBvcmlnaW4sICJcbiAobiA9ICIsIGNvbnN0cnVjdHMsICIpIikpLA0KICAgICAgICAgICAgICAgICAgc2VnbWVudC5zcXVhcmUgPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgbGluZWhlaWdodCA9IC45LA0KICAgICAgICAgICAgICAgICAgc2VnbWVudC5jb2xvciA9ICdncmV5JywNCiAgICAgICAgICAgICAgICAgIG51ZGdlX3ggPSAxLjIsDQogICAgICAgICAgICAgICAgICBoanVzdCA9IDAsDQogICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUpKw0KICAgIyB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDEzKSArDQogICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yLnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGxvdC50aXRsZS5wb3NpdGlvbiA9ICJwbG90IiwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlPSJib2xkIiksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgICsNCiAgICBndWlkZXMoDQogICAgeCA9IGd1aWRlX2F4aXMoY2FwID0gImJvdGgiKSwgIyBDYXAgYm90aCBlbmRzDQogICkNCg0KZ2dzYXZlKCJmaWd1cmVzL2N1bXN1bXNfc3Vydml2YWxfZmlyc3QucGRmIiwgd2lkdGggPSA4LCBoZWlnaHQgPSA0KQ0KZ2dzYXZlKCJmaWd1cmVzL2N1bXN1bXNfc3Vydml2YWxfZmlyc3QucG5nIiwgd2lkdGggPSA4LCBoZWlnaHQgPSA0KQ0KYGBgDQoNCiMjIyBtZWFzdXJlcw0KYGBge3J9DQpjdW1zdW1fYWxsIDwtIG1lYXN1cmVzICU+JSANCiAgZ3JvdXBfYnkoVGVzdFllYXIpICU+JSANCiAgc3VtbWFyaXNlKHRlc3RzID0gbigpKSAlPiUgDQogIGFycmFuZ2UoVGVzdFllYXIpICU+JSANCiAgbXV0YXRlKHRlc3RzID0gY3Vtc3VtKHRlc3RzKSkgDQoNCmN1bXN1bV81IDwtIG1lYXN1cmVzICU+JSANCiAgZmlsdGVyKHN1cnZpdmVkX2ZpdmUgPT0gVCkgJT4lIA0KICBncm91cF9ieShUZXN0WWVhcikgJT4lIA0KICBzdW1tYXJpc2UodGVzdHMgPSBuKCkpICU+JSANCiAgYXJyYW5nZShUZXN0WWVhcikgJT4lIA0KICBtdXRhdGUodGVzdHMgPSBjdW1zdW0odGVzdHMpKSANCg0KY3Vtc3VtXzEwIDwtIG1lYXN1cmVzICU+JSANCiAgZmlsdGVyKHN1cnZpdmVkX3RlbiA9PSBUKSAlPiUgDQogIGFycmFuZ2UoVGVzdFllYXIpICU+JSANCiAgZGlzdGluY3QoTmFtZV9iYXNlLCAua2VlcF9hbGwgPSBUKSAlPiUgDQogIGdyb3VwX2J5KFRlc3RZZWFyKSAlPiUgDQogIHN1bW1hcmlzZSh0ZXN0cyA9IG5fZGlzdGluY3QoRE9JKSkgJT4lIA0KICBtdXRhdGUodGVzdHMgPSBjdW1zdW0odGVzdHMpKSANCg0KY3Vtc3VtcyA8LSBiaW5kX3Jvd3MoDQogICJhbGwgbWVhc3VyZXMiID0gY3Vtc3VtX2FsbCwNCiAgIm1lYXN1cmVzIGluIHVzZVxuIGZvciA9PiA1IHllYXJzIiA9IGN1bXN1bV81LA0KICAibWVhc3VyZXMgaW4gdXNlXG4gZm9yID0+IDEwIHllYXJzIiA9IGN1bXN1bV8xMCwNCiAgLmlkID0gIm9yaWdpbiINCiAgKSAlPiUgDQogIHJlbmFtZShZZWFyID0gVGVzdFllYXIpICU+JSANCiAgZmlsdGVyKFllYXIgPD0gMjAyMikNCg0KDQpnZ3Bsb3QoY3Vtc3VtcywgYWVzKFllYXIsIHRlc3RzLCBjb2xvciA9IG9yaWdpbikpICsgDQogIGdlb21fbGluZSgpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMjAxNiwgbGluZXR5cGUgPSAnZGFzaGVkJykgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoIkN1bXVsYXRpdmUgbnVtYmVyIG9mIG1lYXN1cmVzIikgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoIlB1YmxpY2F0aW9uIHllYXIgaW4gQVBBIFBzeWNUZXN0cyIsDQogICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKDE5OTMsIDIwMzApLCANCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNlcSgxOTkzLDIwMjIsIGJ5ID0gMSksDQogICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKDE5OTMsICIiLCAiIiwgIiIsICIiLCAxOTk4LCAiIiwgIiIsICIiLCAiIiwgMjAwMywgIiIsICIiLCAiIiwgIiIsIDIwMDgsICIiLCAiIiwgIiIsICIiLCAyMDEzLCAiIiwgIiIsICIiLCAiIiwgMjAxOCwgIiIsICIiLCAiIiwgIjIwMjIiKSwNCiAgICAgICAgICAgICAgICAgICAgIGV4cGFuZCA9IGV4cGFuc2lvbihhZGQgPSBjKDAsIDEpKSkgKw0KICBzY2FsZV9jb2xvcl9icmV3ZXIodHlwZSA9ICJxdWFsIiwgZ3VpZGUgPSAibm9uZSIsIHBhbGV0dGUgPSAyKSArDQogICMgZ2dyZXBlbDo6Z2VvbV90ZXh0X3JlcGVsKA0KICAjICAgYWVzKGxhYmVsID0gc3RyX3JlcGxhY2Uoc3ViZGlzY2lwbGluZSwgIiBQc3ljaG9sb2d5IiwgIiIpKSwgZGF0YSA9IGVudHJvcHlfYnlfeWVhciAlPiUgZmlsdGVyKFllYXIgPT0gbWF4KFllYXIsIG5hLnJtID0gVCkpLA0KICAjICAgc2l6ZSA9IDQsIGhqdXN0ID0gMSwNCiAgIyAgICkgICsNCiAgZ2VvbV90ZXh0X3JlcGVsKGRhdGEgPSBjdW1zdW1zICU+JSBkcm9wX25hKCkgJT4lIGdyb3VwX2J5KG9yaWdpbikgJT4lIGZpbHRlcihZZWFyID09IG1heChZZWFyLCBuYS5ybSA9IFQpKSwNCiAgICAgICAgICAgICAgICAgIGFlcyhsYWJlbCA9IHBhc3RlMCgiICIsIG9yaWdpbiwgIlxuIChuID0gIiwgdGVzdHMsICIpIikpLA0KICAgICAgICAgICAgICAgICAgc2VnbWVudC5zcXVhcmUgPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgbGluZWhlaWdodCA9IC45LA0KICAgICAgICAgICAgICAgICAgc2VnbWVudC5jb2xvciA9ICdncmV5JywNCiAgICAgICAgICAgICAgICAgIG51ZGdlX3ggPSAxLjIsDQogICAgICAgICAgICAgICAgICBoanVzdCA9IDAsDQogICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUpICsNCiAgICMgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxMykgKw0KICAgdGhlbWUocGFuZWwuZ3JpZC5taW5vci55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5ncmlkLm1pbm9yLnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBsb3QudGl0bGUucG9zaXRpb24gPSAicGxvdCIsDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZT0iYm9sZCIpLA0KICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICArDQogICAgZ3VpZGVzKA0KICAgIHggPSBndWlkZV9heGlzKGNhcCA9ICJib3RoIiksICMgQ2FwIGJvdGggZW5kcw0KICApDQpnZ3NhdmUoImZpZ3VyZXMvY3Vtc3Vtc19zdXJ2aXZhbF9tZWFzdXJlcy5wZGYiLCB3aWR0aCA9IDgsIGhlaWdodCA9IDQpDQpnZ3NhdmUoImZpZ3VyZXMvY3Vtc3Vtc19zdXJ2aXZhbF9tZWFzdXJlcy5wbmciLCB3aWR0aCA9IDgsIGhlaWdodCA9IDQpDQpgYGANCg0KDQojIyMgYnkgZmlyc3QgdXNlIGluIFBzeWNJbmZvIGluc3RlYWQgb2YgcHVibGljYXRpb24geWVhciBpbiBQc3ljVGVzdHMNCmBgYHtyfQ0KY3Vtc3VtX2NvbnN0cnVjdCA8LSBjb25zdHJ1Y3RzICU+JSANCiAgYXJyYW5nZShmaXJzdF9wdWJfeWVhcikgJT4lIA0KICBncm91cF9ieShmaXJzdF9wdWJfeWVhcikgJT4lIA0KICBzdW1tYXJpc2UoY29uc3RydWN0cyA9IG5fZGlzdGluY3QoRE9JKSkgJT4lIA0KICBhcnJhbmdlKGZpcnN0X3B1Yl95ZWFyKSAlPiUgDQogIG11dGF0ZShjb25zdHJ1Y3RzID0gY3Vtc3VtKGNvbnN0cnVjdHMpKSANCg0KY3Vtc3VtX2NvbnN0cnVjdF9zdXJ2aXZlZF81IDwtIGNvbnN0cnVjdHMgJT4lIA0KICBmaWx0ZXIoc3Vydml2ZWRfZml2ZSA9PSBUKSAlPiUgDQogIGFycmFuZ2UoZmlyc3RfcHViX3llYXIpICU+JSANCiAgZ3JvdXBfYnkoZmlyc3RfcHViX3llYXIpICU+JSANCiAgc3VtbWFyaXNlKGNvbnN0cnVjdHMgPSBuX2Rpc3RpbmN0KERPSSkpICU+JSANCiAgYXJyYW5nZShmaXJzdF9wdWJfeWVhcikgJT4lIA0KICBtdXRhdGUoY29uc3RydWN0cyA9IGN1bXN1bShjb25zdHJ1Y3RzKSkgDQogIA0KY3Vtc3VtX2NvbnN0cnVjdF9zdXJ2aXZlZF8xMCA8LSBjb25zdHJ1Y3RzICU+JSANCiAgZmlsdGVyKHN1cnZpdmVkX3RlbiA9PSBUKSAlPiUgDQogIGFycmFuZ2UoZmlyc3RfcHViX3llYXIpICU+JSANCiAgZ3JvdXBfYnkoZmlyc3RfcHViX3llYXIpICU+JSANCiAgc3VtbWFyaXNlKGNvbnN0cnVjdHMgPSBuX2Rpc3RpbmN0KERPSSkpICU+JSANCiAgYXJyYW5nZShmaXJzdF9wdWJfeWVhcikgJT4lIA0KICBtdXRhdGUoY29uc3RydWN0cyA9IGN1bXN1bShjb25zdHJ1Y3RzKSkgDQoNCg0KDQpjdW1zdW1zIDwtIGJpbmRfcm93cygNCiAgImFsbCBjb25zdHJ1Y3RzIiA9IGN1bXN1bV9jb25zdHJ1Y3QsDQogICJjb25zdHJ1Y3RzIGluIHVzZVxuIGZvciA9PiA1IHllYXJzIiA9IGN1bXN1bV9jb25zdHJ1Y3Rfc3Vydml2ZWRfNSwNCiAgImNvbnN0cnVjdHMgaW4gdXNlXG4gZm9yID0+IDEwIHllYXJzIiA9IGN1bXN1bV9jb25zdHJ1Y3Rfc3Vydml2ZWRfMTAsDQogIC5pZCA9ICJvcmlnaW4iDQogICkgJT4lIA0KICByZW5hbWUoWWVhciA9IGZpcnN0X3B1Yl95ZWFyKSAlPiUgDQogIGZpbHRlcihZZWFyIDw9IDIwMjIpDQoNCg0KZ2dwbG90KGN1bXN1bXMsIGFlcyhZZWFyLCBjb25zdHJ1Y3RzLCBjb2xvciA9IG9yaWdpbikpICsgDQogIGdlb21fbGluZSgpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMjAxNiwgbGluZXR5cGUgPSAnZGFzaGVkJykgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoIkN1bXVsYXRpdmUgbnVtYmVyIG9mIGNvbnN0cnVjdHMiKSArDQogIHNjYWxlX3hfY29udGludW91cygiRmlyc3QgdXNhZ2UgbG9nZ2VkIGluIFBzeWNJbmZvIiwNCiAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoMTk5MywgMjAzMCksIA0KICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc2VxKDE5OTMsMjAyMiwgYnkgPSAxKSwNCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoMTk5MywgIiIsICIiLCAiIiwgIiIsIDE5OTgsICIiLCAiIiwgIiIsICIiLCAyMDAzLCAiIiwgIiIsICIiLCAiIiwgMjAwOCwgIiIsICIiLCAiIiwgIiIsIDIwMTMsICIiLCAiIiwgIiIsICIiLCAyMDE4LCAiIiwgIiIsICIiLCAiMjAyMiIpLA0KICAgICAgICAgICAgICAgICAgICAgZXhwYW5kID0gZXhwYW5zaW9uKGFkZCA9IGMoMCwgMSkpKSArDQogIHNjYWxlX2NvbG9yX2JyZXdlcih0eXBlID0gInF1YWwiLCBndWlkZSA9ICJub25lIiwgcGFsZXR0ZSA9IDIpICsNCiAgIyBnZ3JlcGVsOjpnZW9tX3RleHRfcmVwZWwoDQogICMgICBhZXMobGFiZWwgPSBzdHJfcmVwbGFjZShzdWJkaXNjaXBsaW5lLCAiIFBzeWNob2xvZ3kiLCAiIikpLCBkYXRhID0gZW50cm9weV9ieV95ZWFyICU+JSBmaWx0ZXIoWWVhciA9PSBtYXgoWWVhciwgbmEucm0gPSBUKSksDQogICMgICBzaXplID0gNCwgaGp1c3QgPSAxLA0KICAjICAgKSAgKw0KICBnZW9tX3RleHRfcmVwZWwoZGF0YSA9IGN1bXN1bXMgJT4lIGRyb3BfbmEoKSAlPiUgZ3JvdXBfYnkob3JpZ2luKSAlPiUgZmlsdGVyKFllYXIgPT0gbWF4KFllYXIsIG5hLnJtID0gVCkpLA0KICAgICAgICAgICAgICAgICAgYWVzKGxhYmVsID0gcGFzdGUwKCIgIiwgb3JpZ2luLCAiXG4gKG4gPSAiLCBjb25zdHJ1Y3RzLCAiKSIpKSwNCiAgICAgICAgICAgICAgICAgIHNlZ21lbnQuc3F1YXJlID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgIGxpbmVoZWlnaHQgPSAuOSwNCiAgICAgICAgICAgICAgICAgIHNlZ21lbnQuY29sb3IgPSAnZ3JleScsDQogICAgICAgICAgICAgICAgICBudWRnZV94ID0gMS4yLA0KICAgICAgICAgICAgICAgICAgaGp1c3QgPSAwLA0KICAgICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFKSsNCiAgICMgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxMykgKw0KICAgdGhlbWUocGFuZWwuZ3JpZC5taW5vci55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5ncmlkLm1pbm9yLnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBsb3QudGl0bGUucG9zaXRpb24gPSAicGxvdCIsDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZT0iYm9sZCIpLA0KICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICArDQogICAgZ3VpZGVzKA0KICAgIHggPSBndWlkZV9heGlzKGNhcCA9ICJib3RoIiksICMgQ2FwIGJvdGggZW5kcw0KICApDQpgYGANCg0KIyMjIGJ5IGxhc3QgdXNlIGluIFBzeWNJbmZvIGluc3RlYWQgb2YgcHVibGljYXRpb24geWVhciBpbiBQc3ljVGVzdHMNCg0KYGBge3J9DQpjdW1zdW1fY29uc3RydWN0IDwtIGNvbnN0cnVjdHMgJT4lIA0KICBhcnJhbmdlKGxhc3RfcHViX3llYXIpICU+JSANCiAgZ3JvdXBfYnkobGFzdF9wdWJfeWVhcikgJT4lIA0KICBzdW1tYXJpc2UoY29uc3RydWN0cyA9IG5fZGlzdGluY3QoRE9JKSkgJT4lIA0KICBhcnJhbmdlKGxhc3RfcHViX3llYXIpICU+JSANCiAgbXV0YXRlKGNvbnN0cnVjdHMgPSBjdW1zdW0oY29uc3RydWN0cykpIA0KDQpjdW1zdW1fY29uc3RydWN0X3N1cnZpdmVkXzUgPC0gY29uc3RydWN0cyAlPiUgDQogIGZpbHRlcihzdXJ2aXZlZF9maXZlID09IFQpICU+JSANCiAgYXJyYW5nZShsYXN0X3B1Yl95ZWFyKSAlPiUgDQogIGdyb3VwX2J5KGxhc3RfcHViX3llYXIpICU+JSANCiAgc3VtbWFyaXNlKGNvbnN0cnVjdHMgPSBuX2Rpc3RpbmN0KERPSSkpICU+JSANCiAgYXJyYW5nZShsYXN0X3B1Yl95ZWFyKSAlPiUgDQogIG11dGF0ZShjb25zdHJ1Y3RzID0gY3Vtc3VtKGNvbnN0cnVjdHMpKSANCiAgDQpjdW1zdW1fY29uc3RydWN0X3N1cnZpdmVkXzEwIDwtIGNvbnN0cnVjdHMgJT4lIA0KICBmaWx0ZXIoc3Vydml2ZWRfdGVuID09IFQpICU+JSANCiAgYXJyYW5nZShsYXN0X3B1Yl95ZWFyKSAlPiUgDQogIGdyb3VwX2J5KGxhc3RfcHViX3llYXIpICU+JSANCiAgc3VtbWFyaXNlKGNvbnN0cnVjdHMgPSBuX2Rpc3RpbmN0KERPSSkpICU+JSANCiAgYXJyYW5nZShsYXN0X3B1Yl95ZWFyKSAlPiUgDQogIG11dGF0ZShjb25zdHJ1Y3RzID0gY3Vtc3VtKGNvbnN0cnVjdHMpKSANCg0KDQoNCmN1bXN1bXMgPC0gYmluZF9yb3dzKA0KICAiYWxsIGNvbnN0cnVjdHMiID0gY3Vtc3VtX2NvbnN0cnVjdCwNCiAgImNvbnN0cnVjdHMgaW4gdXNlXG4gZm9yID0+IDUgeWVhcnMiID0gY3Vtc3VtX2NvbnN0cnVjdF9zdXJ2aXZlZF81LA0KICAiY29uc3RydWN0cyBpbiB1c2VcbiBmb3IgPT4gMTAgeWVhcnMiID0gY3Vtc3VtX2NvbnN0cnVjdF9zdXJ2aXZlZF8xMCwNCiAgLmlkID0gIm9yaWdpbiINCiAgKSAlPiUgDQogIHJlbmFtZShZZWFyID0gbGFzdF9wdWJfeWVhcikgJT4lIA0KICBmaWx0ZXIoWWVhciA8PSAyMDIyKQ0KDQoNCmdncGxvdChjdW1zdW1zLCBhZXMoWWVhciwgY29uc3RydWN0cywgY29sb3IgPSBvcmlnaW4pKSArIA0KICBnZW9tX2xpbmUoKSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDIwMTYsIGxpbmV0eXBlID0gJ2Rhc2hlZCcpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKCJDdW11bGF0aXZlIG51bWJlciBvZiBjb25zdHJ1Y3RzIikgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoIkxhc3QgdXNhZ2UgbG9nZ2VkIGluIFBzeWNJbmZvIiwNCiAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoMTk5MywgMjAzMCksIA0KICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc2VxKDE5OTMsMjAyMiwgYnkgPSAxKSwNCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoMTk5MywgIiIsICIiLCAiIiwgIiIsIDE5OTgsICIiLCAiIiwgIiIsICIiLCAyMDAzLCAiIiwgIiIsICIiLCAiIiwgMjAwOCwgIiIsICIiLCAiIiwgIiIsIDIwMTMsICIiLCAiIiwgIiIsICIiLCAyMDE4LCAiIiwgIiIsICIiLCAiMjAyMiIpLA0KICAgICAgICAgICAgICAgICAgICAgZXhwYW5kID0gZXhwYW5zaW9uKGFkZCA9IGMoMCwgMSkpKSArDQogIHNjYWxlX2NvbG9yX2JyZXdlcih0eXBlID0gInF1YWwiLCBndWlkZSA9ICJub25lIiwgcGFsZXR0ZSA9IDIpICsNCiAgIyBnZ3JlcGVsOjpnZW9tX3RleHRfcmVwZWwoDQogICMgICBhZXMobGFiZWwgPSBzdHJfcmVwbGFjZShzdWJkaXNjaXBsaW5lLCAiIFBzeWNob2xvZ3kiLCAiIikpLCBkYXRhID0gZW50cm9weV9ieV95ZWFyICU+JSBmaWx0ZXIoWWVhciA9PSBtYXgoWWVhciwgbmEucm0gPSBUKSksDQogICMgICBzaXplID0gNCwgaGp1c3QgPSAxLA0KICAjICAgKSAgKw0KICBnZW9tX3RleHRfcmVwZWwoZGF0YSA9IGN1bXN1bXMgJT4lIGRyb3BfbmEoKSAlPiUgZ3JvdXBfYnkob3JpZ2luKSAlPiUgZmlsdGVyKFllYXIgPT0gbWF4KFllYXIsIG5hLnJtID0gVCkpLA0KICAgICAgICAgICAgICAgICAgYWVzKGxhYmVsID0gcGFzdGUwKCIgIiwgb3JpZ2luLCAiXG4gKG4gPSAiLCBjb25zdHJ1Y3RzLCAiKSIpKSwNCiAgICAgICAgICAgICAgICAgIHNlZ21lbnQuc3F1YXJlID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgIGxpbmVoZWlnaHQgPSAuOSwNCiAgICAgICAgICAgICAgICAgIHNlZ21lbnQuY29sb3IgPSAnZ3JleScsDQogICAgICAgICAgICAgICAgICBudWRnZV94ID0gMS4yLA0KICAgICAgICAgICAgICAgICAgaGp1c3QgPSAwLA0KICAgICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFKSsNCiAgICMgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxMykgKw0KICAgdGhlbWUocGFuZWwuZ3JpZC5taW5vci55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5ncmlkLm1pbm9yLnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBsb3QudGl0bGUucG9zaXRpb24gPSAicGxvdCIsDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZT0iYm9sZCIpLA0KICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICArDQogICAgZ3VpZGVzKA0KICAgIHggPSBndWlkZV9heGlzKGNhcCA9ICJib3RoIiksICMgQ2FwIGJvdGggZW5kcw0KICApDQpgYGANCg0KDQojIyBjb3VudHMNCmBgYHtyfQ0KDQpjb3VudF9jb25zdHJ1Y3QgPC0gY29uc3RydWN0cyAlPiUgDQogIGFycmFuZ2UoVGVzdFllYXIpICU+JQ0KICBncm91cF9ieShUZXN0WWVhcikgJT4lIA0KICBzdW1tYXJpc2UodGVzdHMgPSBuX2Rpc3RpbmN0KGNvbnN0cnVjdCkpICU+JSANCiAgYXJyYW5nZShUZXN0WWVhcikNCg0KY291bnRfY29uc3RydWN0XzUgPC0gY29uc3RydWN0cyAlPiUgDQogIGZpbHRlcihzdXJ2aXZlZF9maXZlID09IFQpICU+JSANCiAgYXJyYW5nZShUZXN0WWVhcikgJT4lDQogIGdyb3VwX2J5KFRlc3RZZWFyKSAlPiUgDQogIHN1bW1hcmlzZSh0ZXN0cyA9IG5fZGlzdGluY3QoY29uc3RydWN0KSkgJT4lIA0KICBhcnJhbmdlKFRlc3RZZWFyKQ0KDQpjb3VudF9jb25zdHJ1Y3RfMTAgPC0gY29uc3RydWN0cyAlPiUgDQogIGZpbHRlcihzdXJ2aXZlZF90ZW4gPT0gVCkgJT4lIA0KICBhcnJhbmdlKFRlc3RZZWFyKSAlPiUNCiAgZ3JvdXBfYnkoVGVzdFllYXIpICU+JSANCiAgc3VtbWFyaXNlKHRlc3RzID0gbl9kaXN0aW5jdChjb25zdHJ1Y3QpKSAlPiUgDQogIGFycmFuZ2UoVGVzdFllYXIpDQoNCmNvdW50cyA8LSBiaW5kX3Jvd3MoDQogICJhbGwgY29uc3RydWN0cyIgPSBjb3VudF9jb25zdHJ1Y3QsDQogICJjb25zdHJ1Y3RzIGluIHVzZVxuIGZvciA9PiA1IHllYXJzIiA9IGNvdW50X2NvbnN0cnVjdF81LA0KICAiY29uc3RydWN0cyBpbiB1c2VcbiBmb3IgPT4gMTAgeWVhcnMiID0gY291bnRfY29uc3RydWN0XzEwLA0KICAuaWQgPSAib3JpZ2luIg0KICApICU+JSANCiAgcmVuYW1lKFllYXIgPSBUZXN0WWVhcikgJT4lIA0KICBmaWx0ZXIoWWVhciA8PSAyMDIyKQ0KDQoNCg0KZ2dwbG90KGNvdW50cywgYWVzKFllYXIsIHRlc3RzLCBjb2xvciA9IG9yaWdpbikpICsgDQogIGdlb21fbGluZSgpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMjAxNiwgbGluZXR5cGUgPSAnZGFzaGVkJykgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoIk51bWJlciBvZiBjb25zdHJ1Y3RzIikgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoIlB1YmxpY2F0aW9uIHllYXIgaW4gQVBBIFBzeWNUZXN0cyIsDQogICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKDE5OTMsIDIwMzApLCANCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNlcSgxOTkzLCAyMDIyLCBieSA9IDEpLA0KICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygxOTkzLCAiIiwgIiIsICIiLCAiIiwgMTk5OCwgIiIsICIiLCAiIiwgIiIsIDIwMDMsICIiLCAiIiwgIiIsICIiLCAyMDA4LCAiIiwgIiIsICIiLCAiIiwgMjAxMywgIiIsICIiLCAiIiwgIiIsIDIwMTgsICIiLCAiIiwgIiIsICIyMDIyIikpICsNCiAgc2NhbGVfY29sb3JfYnJld2VyKHR5cGUgPSAicXVhbCIsIGd1aWRlID0gIm5vbmUiLCBwYWxldHRlID0gMikgKw0KICAjIGdncmVwZWw6Omdlb21fdGV4dF9yZXBlbCgNCiAgIyAgIGFlcyhsYWJlbCA9IHN0cl9yZXBsYWNlKHN1YmRpc2NpcGxpbmUsICIgUHN5Y2hvbG9neSIsICIiKSksIGRhdGEgPSBlbnRyb3B5X2J5X3llYXIgJT4lIGZpbHRlcihZZWFyID09IG1heChZZWFyLCBuYS5ybSA9IFQpKSwNCiAgIyAgIHNpemUgPSA0LCBoanVzdCA9IDEsDQogICMgICApICsNCiAgZ2VvbV90ZXh0X3JlcGVsKGRhdGEgPSBjb3VudHMgJT4lIGRyb3BfbmEoKSAlPiUgZ3JvdXBfYnkob3JpZ2luKSAlPiUgZmlsdGVyKFllYXIgPT0gbWF4KFllYXIsIG5hLnJtID0gVCkpLA0KICAgICAgICAgICAgICAgICAgYWVzKGxhYmVsID0gcGFzdGUwKCIgIiwgb3JpZ2luKSksDQogICAgICAgICAgICAgICAgICBzZWdtZW50LmN1cnZhdHVyZSA9IC0wLjEsDQogICAgICAgICAgICAgICAgICBzZWdtZW50LnNxdWFyZSA9IFRSVUUsDQogICAgICAgICAgICAgICAgICBsaW5laGVpZ2h0ID0gLjksDQogICAgICAgICAgICAgICAgICAjIHNlZ21lbnQuY29sb3IgPSAnZ3JleScsDQogICAgICAgICAgICAgICAgICBib3gucGFkZGluZyA9IDAuMSwNCiAgICAgICAgICAgICAgICAgIHBvaW50LnBhZGRpbmcgPSAwLjYsDQogICAgICAgICAgICAgICAgICBudWRnZV94ID0gMS41LA0KICAgICAgICAgICAgICAgICAgbnVkZ2VfeSA9IC0xNSwNCiAgICAgICAgICAgICAgICAgIGZvcmNlID0gMSwNCiAgICAgICAgICAgICAgICAgIGhqdXN0ID0gMCwNCiAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbj0ieSIsDQogICAgICAgICAgICAgICAgICBuYS5ybSA9IEYpICsNCiAgIHRoZW1lKHBhbmVsLmdyaWQubWlub3IueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vci54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwbG90LnRpdGxlLnBvc2l0aW9uID0gInBsb3QiLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2U9ImJvbGQiKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KDQpnZ3NhdmUoImZpZ3VyZXMvY291bnRzX3N1cnZpdmFsLnBkZiIsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNCkNCmdnc2F2ZSgiZmlndXJlcy9jb3VudHNfc3Vydml2YWwucG5nIiwgd2lkdGggPSA4LCBoZWlnaHQgPSA0KQ0KYGBgDQoNCg0KDQoNCg0KDQoNCiMgUm9idXN0bmVzcyBjaGVja3MNCmBgYHtyfQ0KYWxsX2NvbnN0cnVjdHNfb3Zlcl90aW1lIDwtIHJlY29yZHNfd2lkZSAlPiUgc2VsZWN0KHN1YmRpc2NpcGxpbmVfMSwgRE9JLCBUZXN0WWVhciwgQ29uc3RydWN0TGlzdCkgJT4lIA0KICAgIHVubmVzdChDb25zdHJ1Y3RMaXN0KSAlPiUgDQogICAgcm93d2lzZSgpICU+JSANCiAgICBtdXRhdGUoY29uc3RydWN0ID0gdW5saXN0KENvbnN0cnVjdExpc3QpKSAlPiUgDQogIHNlbGVjdCgtQ29uc3RydWN0TGlzdCkNCg0KY3Vtc3VtX2FsbF9jb25zdHJ1Y3RzIDwtIGFsbF9jb25zdHJ1Y3RzX292ZXJfdGltZSAlPiUgDQogIGFycmFuZ2UoVGVzdFllYXIpICU+JSANCiAgZGlzdGluY3QoY29uc3RydWN0LCAua2VlcF9hbGwgPSBUKSAlPiUgDQogIGdyb3VwX2J5KFRlc3RZZWFyKSAlPiUgDQogIHN1bW1hcmlzZShjb25zdHJ1Y3RzID0gbl9kaXN0aW5jdChjb25zdHJ1Y3QpKSAlPiUgDQogIGFycmFuZ2UoVGVzdFllYXIpICU+JSANCiAgbXV0YXRlKGNvbnN0cnVjdHMgPSBjdW1zdW0oY29uc3RydWN0cykpIA0KDQoNCmN1bXN1bV9jb25zdHJ1Y3QgPC0gcmVjb3Jkc193aWRlICU+JSANCiAgYXJyYW5nZShUZXN0WWVhcikgJT4lIA0KICBkaXN0aW5jdChmaXJzdF9jb25zdHJ1Y3QsIC5rZWVwX2FsbCA9IFQpICU+JSANCiAgZ3JvdXBfYnkoVGVzdFllYXIpICU+JSANCiAgc3VtbWFyaXNlKGNvbnN0cnVjdHMgPSBuX2Rpc3RpbmN0KGZpcnN0X2NvbnN0cnVjdCkpICU+JSANCiAgYXJyYW5nZShUZXN0WWVhcikgJT4lIA0KICBtdXRhdGUoY29uc3RydWN0cyA9IGN1bXN1bShjb25zdHJ1Y3RzKSkNCg0KY3Vtc3VtcyA8LSBiaW5kX3Jvd3MoDQogICJmaXJzdCBjb25zdHJ1Y3RzIiA9IGN1bXN1bV9jb25zdHJ1Y3QsDQogICJhbGwgY29uc3RydWN0cyIgPSBjdW1zdW1fYWxsX2NvbnN0cnVjdHMsDQogIC5pZCA9ICJvcmlnaW4iDQogICkgJT4lIA0KICByZW5hbWUoWWVhciA9IFRlc3RZZWFyKSAlPiUgDQogIGZpbHRlcihZZWFyIDw9IDIwMjIpDQoNCg0KZ2dwbG90KGN1bXN1bXMsIGFlcyhZZWFyLCBjb25zdHJ1Y3RzLCBjb2xvciA9IG9yaWdpbikpICsgDQogIGdlb21fbGluZSgpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKCJDdW11bGF0aXZlIG51bWJlciBvZiBjb25zdHJ1Y3RzIikgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoIlB1YmxpY2F0aW9uIHllYXIgaW4gQVBBIFBzeWNUZXN0cyIsDQogICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKDE5OTMsIDIwMjcpLCANCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNlcSgxOTkzLCAyMDIyLCBieSA9IDEpLA0KICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygxOTkzLCAiIiwgIiIsICIiLCAiIiwgMTk5OCwgIiIsICIiLCAiIiwgIiIsIDIwMDMsICIiLCAiIiwgIiIsICIiLCAyMDA4LCAiIiwgIiIsICIiLCAiIiwgMjAxMywgIiIsICIiLCAiIiwgIiIsIDIwMTgsICIiLCAiIiwgIiIsICIyMDIyIikpICsNCiAgc2NhbGVfY29sb3JfYnJld2VyKHR5cGUgPSAicXVhbCIsIGd1aWRlID0gIm5vbmUiLCBwYWxldHRlID0gMikgKw0KICAjIGdncmVwZWw6Omdlb21fdGV4dF9yZXBlbCgNCiAgIyAgIGFlcyhsYWJlbCA9IHN0cl9yZXBsYWNlKHN1YmRpc2NpcGxpbmUsICIgUHN5Y2hvbG9neSIsICIiKSksIGRhdGEgPSBlbnRyb3B5X2J5X3llYXIgJT4lIGZpbHRlcihZZWFyID09IG1heChZZWFyLCBuYS5ybSA9IFQpKSwNCiAgIyAgIHNpemUgPSA0LCBoanVzdCA9IDEsDQogICMgICApICsgDQogIGdlb21fdGV4dF9yZXBlbChkYXRhID0gY3Vtc3VtcyAlPiUgZHJvcF9uYSgpICU+JSBncm91cF9ieShvcmlnaW4pICU+JSBmaWx0ZXIoWWVhciA9PSBtYXgoWWVhciwgbmEucm0gPSBUKSksDQogICAgICAgICAgICAgICAgICBhZXMobGFiZWwgPSBwYXN0ZTAoIiAiLCBvcmlnaW4sICJcbiAobiA9ICIsIGNvbnN0cnVjdHMsICIpIikpLA0KICAgICAgICAgICAgICAgICAgc2VnbWVudC5zcXVhcmUgPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgbGluZWhlaWdodCA9IC45LA0KICAgICAgICAgICAgICAgICAgc2VnbWVudC5jb2xvciA9ICdncmV5JywNCiAgICAgICAgICAgICAgICAgIG51ZGdlX3ggPSAxLjIsDQogICAgICAgICAgICAgICAgICBoanVzdCA9IDAsDQogICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUpDQoNCmdnc2F2ZSgiZmlndXJlcy9jdW1zdW1fYWxsX3ZzX2ZpcnN0LnBkZiIsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNCkNCmdnc2F2ZSgiZmlndXJlcy9jdW1zdW1fYWxsX3ZzX2ZpcnN0LnBuZyIsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNCkNCmBgYA0KDQojIyBBbGwgb3IgZmlyc3QgY29uc3RydWN0cw0KDQpGb3Igc29tZSAyMCUgb2YgdGVzdHMsIHR3byBvciBtb3JlIGNvbnN0cnVjdHMgd2VyZSBjb2RlZC4gSW4gbW9zdCBwbG90cywgd2Ugc2ltcGx5IHVzZQ0KdGhlIGZpcnN0IGNvbnN0cnVjdCBmb3IgZWFjaCB0ZXN0Lg0KYGBge3J9DQpyZWNvcmRzX3dpZGUgPC0gcmVjb3Jkc193aWRlICU+JSANCiAgcm93d2lzZSgpICU+JSANCiAgbXV0YXRlKGNvbnN0cnVjdHNfbiA9IGxlbmd0aChDb25zdHJ1Y3RMaXN0KSkgJT4lIA0KICB1bmdyb3VwKCkNCg0KdGFibGUocmVjb3Jkc193aWRlJGNvbnN0cnVjdHNfbikNCnJvdW5kKHByb3AudGFibGUodGFibGUocmVjb3Jkc193aWRlJGNvbnN0cnVjdHNfbikpLDIpDQoNCmdncGxvdChyZWNvcmRzX3dpZGUsIGFlcyhjb25zdHJ1Y3RzX24pKSArIA0KICBnZW9tX2JhcigpDQpgYGANCg0KDQpFeHBhbmRpbmcgdGhlIGVudHJvcHkgY2FsY3VsYXRpb24gdG8gYWxsIGNvZGVkIGNvbnN0cnVjdHMgbWFrZXMgbGl0dGxlIGRpZmZlcmVuY2UuDQoNCmBgYHtyfQ0KYWxsX2NvbnN0cnVjdHNfb3Zlcl90aW1lIDwtIHBzeWN0ZXN0c19pbmZvICU+JSBzZWxlY3Qoc3ViZGlzY2lwbGluZV8xLCBET0ksIFRlc3RZZWFyLCBZZWFyLCBDb25zdHJ1Y3RMaXN0LCB1c2FnZV9jb3VudCkgJT4lIA0KICAgIHVubmVzdChDb25zdHJ1Y3RMaXN0KSAlPiUgDQogICAgcm93d2lzZSgpICU+JSANCiAgICBtdXRhdGUoY29uc3RydWN0ID0gdW5saXN0KENvbnN0cnVjdExpc3QpKSAlPiUgDQogIHNlbGVjdCgtQ29uc3RydWN0TGlzdCkNCg0KZW50cm9weV9hbGxfY29uc3RydWN0cyA8LSBhbGxfY29uc3RydWN0c19vdmVyX3RpbWUgJT4lIA0KICBmaWx0ZXIoYmV0d2VlbihZZWFyLCAxOTkzLCAyMDIyKSkgJT4lIA0KICBkcm9wX25hKGNvbnN0cnVjdCkgJT4lIA0KICBncm91cF9ieShZZWFyLCBjb25zdHJ1Y3QpICU+JSANCiAgc3VtbWFyaXNlKG4gPSBzdW0odXNhZ2VfY291bnQsIG5hLnJtID0gVCkpICU+JSANCiAgdW5ncm91cCgpICU+JSANCiAgbXV0YXRlKG5fdGVzdHMgPSBuX2Rpc3RpbmN0KGNvbnN0cnVjdCkpICU+JSANCiAgZ3JvdXBfYnkobl90ZXN0cywgWWVhcikgJT4lIA0KICBmaWx0ZXIobiA+IDApICU+JSANCiAgc3VtbWFyaXNlKGVudHJvcHkgPSBlbnRyb3B5KG4pLCwNCiAgICAgICAgICAgIG5vcm1fZW50cm9weSA9IGNhbGNfbm9ybV9lbnRyb3B5KG4pLA0KICAgICAgICAgICAgbiA9IHN1bShuKSwNCiAgICAgICAgICAgIGRpZmZfdGVzdHMgPSBuKCkpICU+JSANCiAgdW5ncm91cCgpDQoNCmJ5Y29uc3RydWN0X2VudHJvcHlfYnlfeWVhciA8LSBwc3ljdGVzdHNfaW5mbyAlPiUgDQogIGZpbHRlcihiZXR3ZWVuKFllYXIsIDE5OTMsIDIwMjIpKSAlPiUgDQogIGRyb3BfbmEoZmlyc3RfY29uc3RydWN0KSAlPiUgDQogIGdyb3VwX2J5KFllYXIsIFRlc3QgPSBmaXJzdF9jb25zdHJ1Y3QpICU+JSANCiAgc3VtbWFyaXNlKG4gPSBzdW0odXNhZ2VfY291bnQsIG5hLnJtID0gVCkpICU+JSANCiAgdW5ncm91cCgpICU+JSANCiAgbXV0YXRlKG5fdGVzdHMgPSBuX2Rpc3RpbmN0KFRlc3QpKSAlPiUgDQogIGdyb3VwX2J5KG5fdGVzdHMsIFllYXIpICU+JSANCiAgZmlsdGVyKG4gPiAwKSAlPiUgDQogIHN1bW1hcmlzZShlbnRyb3B5ID0gZW50cm9weShuKSwsDQogICAgICAgICAgICBub3JtX2VudHJvcHkgPSBjYWxjX25vcm1fZW50cm9weShuKSwNCiAgICAgICAgICAgIG4gPSBzdW0obiksDQogICAgICAgICAgICBkaWZmX3Rlc3RzID0gbigpKSAlPiUgDQogIHVuZ3JvdXAoKQ0KDQplbnRyb3B5X2J5X3llYXIgPC0gYmluZF9yb3dzKCMgImFsbCB0ZXN0cyIgPSBhbGxfZW50cm9weV9ieV95ZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYWxsIGNvbnN0cnVjdHMiID0gZW50cm9weV9hbGxfY29uc3RydWN0cywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyAiYnkgbmFtZSBiYXNlIiA9IGJ5YmFzZV9lbnRyb3B5X2J5X3llYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJmaXJzdCBjb25zdHJ1Y3RzIiA9IGJ5Y29uc3RydWN0X2VudHJvcHlfYnlfeWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLmlkID0gInZlcnNpb24iKQ0KDQplbnRyb3B5X2J5X3llYXIgJT4lIA0KICBnZ3Bsb3QoLiwgYWVzKFllYXIsIG5vcm1fZW50cm9weSwgY29sb3IgPSB2ZXJzaW9uKSkgKw0KICBnZW9tX2xpbmUoc2l6ZSA9IDAuNykgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoIk5vcm1hbGl6ZWQgU2hhbm5vbiBFbnRyb3B5IiwgbGltaXRzID0gYygwLCAxKSwgbGFiZWxzID0gc2NhbGVzOjpwZXJjZW50KSArDQogICMgZ2VvbV9saW5lKGFlcyh5ID0gbG9nKG4pKSwgY29sb3IgPSAncmVkJykgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoIlVzYWdlIHllYXIgYXMgY29kZWQgaW4gQVBBIFBzeWNJbmZvIiwgbGltaXRzID0gYygxOTkzLCAyMDI3KSwgDQogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzZXEoMTk5MywgMjAyMiwgYnkgPSAxKSwNCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoMTk5MywgIiIsICIiLCAiIiwgIiIsIDE5OTgsICIiLCAiIiwgIiIsICIiLCAyMDAzLCAiIiwgIiIsICIiLCAiIiwgMjAwOCwgIiIsICIiLCAiIiwgIiIsIDIwMTMsICIiLCAiIiwgIiIsICIiLCAyMDE4LCAiIiwgIiIsICIiLCAiMjAyMiIpKSArDQoNCiAgc2NhbGVfY29sb3JfYnJld2VyKHR5cGUgPSAicXVhbCIsIGd1aWRlID0gIm5vbmUiLCBwYWxldHRlID0gMikgKw0KICAjIGdncmVwZWw6Omdlb21fdGV4dF9yZXBlbCgNCiAgIyAgIGFlcyhsYWJlbCA9IHN0cl9yZXBsYWNlKHN1YmRpc2NpcGxpbmUsICIgUHN5Y2hvbG9neSIsICIiKSksIGRhdGEgPSBlbnRyb3B5X2J5X3llYXIgJT4lIGZpbHRlcihZZWFyID09IG1heChZZWFyLCBuYS5ybSA9IFQpKSwNCiAgIyAgIHNpemUgPSA0LCBoanVzdCA9IDEsDQogICMgICApICsgDQogIGdlb21fdGV4dF9yZXBlbChkYXRhID0gZW50cm9weV9ieV95ZWFyICU+JSBkcm9wX25hKCkgJT4lIGdyb3VwX2J5KHZlcnNpb24pICU+JSBmaWx0ZXIoWWVhciA9PSBtYXgoWWVhciwgbmEucm0gPSBUKSksDQogICAgICAgICAgICAgICAgICBhZXMobGFiZWwgPSBwYXN0ZTAoIiAiLHZlcnNpb24pKSwgIyAiXG4gKG4gPSAiLCBuX3Rlc3RzLCAiKSINCiAgICAgICAgICAgICAgICAgIHNlZ21lbnQuY3VydmF0dXJlID0gLTAuNSwNCiAgICAgICAgICAgICAgICAgIHNlZ21lbnQuc3F1YXJlID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgIHNlZ21lbnQuY29sb3IgPSAnZ3JleScsIA0KICAgICAgICAgICAgICAgICAgeGxpbSA9IGMoMjAyMywgMjAzMCksDQogICAgICAgICAgICAgICAgICBudWRnZV94ID0gMS4xNCwNCiAgICAgICAgICAgICAgICAgIGxpbmVoZWlnaHQgPSAuOSwNCiAgICAgICAgICAgICAgICAgIGhqdXN0ID0gMCwNCiAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbj0ieSIsDQogICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUpICsNCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxMykgKw0KICAgdGhlbWUocGFuZWwuZ3JpZC5taW5vci55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5ncmlkLm1pbm9yLnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBsb3QudGl0bGUucG9zaXRpb24gPSAicGxvdCIsDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZT0iYm9sZCIpLA0KICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQoNCg0KZ2dzYXZlKCJmaWd1cmVzL2VudHJvcHlfYWxsX3ZzX2ZpcnN0LnBkZiIsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNCkNCmdnc2F2ZSgiZmlndXJlcy9lbnRyb3B5X2FsbF92c19maXJzdC5wbmciLCB3aWR0aCA9IDgsIGhlaWdodCA9IDQpDQpgYGANCg0KIyMgVW5iaWFzZWQgZXN0aW1hdG9ycyBvZiBTaGFubm9uIGVudHJvcHkNCkRvZXMgbm90IG1ha2UgbXVjaCBvZiBhIGRpZmZlcmVuY2UuDQpgYGB7cn0NCmJ5b3JpZ19lbnRyb3B5X2J5X3llYXIgPC0gcHN5Y3Rlc3RzX2luZm8gJT4lIA0KICBmaWx0ZXIoYmV0d2VlbihZZWFyLCAxOTkzLCAyMDIyKSkgJT4lIA0KICBtdXRhdGUoVGVzdCA9IGlmX2Vsc2UodGVzdF90eXBlID09ICJPcmlnaW5hbCIsIERPSSwgb3JpZ2luYWxfdGVzdF9ET0kpKSAlPiUgDQogIGRyb3BfbmEoVGVzdCkgJT4lIA0KICBncm91cF9ieShZZWFyLCBUZXN0KSAlPiUgDQogIHN1bW1hcmlzZShuID0gc3VtKHVzYWdlX2NvdW50LCBuYS5ybSA9IFQpKSAlPiUgDQogIHVuZ3JvdXAoKSAlPiUgDQogIG11dGF0ZShuX3Rlc3RzID0gbl9kaXN0aW5jdChUZXN0KSkgJT4lIA0KICBncm91cF9ieShuX3Rlc3RzLCBZZWFyKSAlPiUgDQogIGZpbHRlcihuID4gMCkgJT4lIA0KICBzdW1tYXJpc2Uobm9ybV9lbnRyb3B5ID0gY2FsY19ub3JtX2VudHJvcHkobiksDQogICAgICAgICAgICBub3JtX2VudHJvcHlfTU0gPSBlbnRyb3B5KG4sIG1ldGhvZCA9ICJNTSIpIC8gbG9nKG4oKSksDQogICAgICAgICAgICBuID0gc3VtKG4pLA0KICAgICAgICAgICAgZGlmZl90ZXN0cyA9IG4oKSkgJT4lIA0KICB1bmdyb3VwKCkNCg0KMSAtIChieW9yaWdfZW50cm9weV9ieV95ZWFyJG5fdGVzdHNbMV0vIHJlY29yZHNfd2lkZSAlPiUgZmlsdGVyKGJldHdlZW4oVGVzdFllYXIsIDE5OTMsIDIwMjIpKSAlPiUgDQogICAgICAgbXV0YXRlKFRlc3QgPSBpZl9lbHNlKHRlc3RfdHlwZSA9PSAiT3JpZ2luYWwiLCBET0ksIG9yaWdpbmFsX3Rlc3RfRE9JKSkgJT4lIA0KICAgICAgIHN1bW1hcmlzZShuX2Rpc3RpbmN0KFRlc3QpKSkNCg0KDQpieWNvbnN0cnVjdF9lbnRyb3B5X2J5X3llYXIgPC0gcHN5Y3Rlc3RzX2luZm8gJT4lIA0KICBmaWx0ZXIoYmV0d2VlbihZZWFyLCAxOTkzLCAyMDIyKSkgJT4lIA0KICBkcm9wX25hKGZpcnN0X2NvbnN0cnVjdCkgJT4lIA0KICBncm91cF9ieShZZWFyLCBUZXN0ID0gZmlyc3RfY29uc3RydWN0KSAlPiUgDQogIHN1bW1hcmlzZShuID0gc3VtKHVzYWdlX2NvdW50LCBuYS5ybSA9IFQpKSAlPiUgDQogIHVuZ3JvdXAoKSAlPiUgDQogIG11dGF0ZShuX3Rlc3RzID0gbl9kaXN0aW5jdChUZXN0KSkgJT4lIA0KICBncm91cF9ieShuX3Rlc3RzLCBZZWFyKSAlPiUgDQogIGZpbHRlcihuID4gMCkgJT4lIA0KICBzdW1tYXJpc2Uobm9ybV9lbnRyb3B5ID0gY2FsY19ub3JtX2VudHJvcHkobiksDQogICAgICAgICAgICBub3JtX2VudHJvcHlfTU0gPSBlbnRyb3B5KG4sIG1ldGhvZCA9ICJNTSIpIC8gbG9nKG4oKSksDQogICAgICAgICAgICBuID0gc3VtKG4pLA0KICAgICAgICAgICAgZGlmZl90ZXN0cyA9IG4oKSkgJT4lIA0KICB1bmdyb3VwKCkNCg0KYWxsX2VudHJvcHlfYnlfeWVhciA8LSBwc3ljdGVzdHNfaW5mbyAlPiUgDQogIGZpbHRlcihiZXR3ZWVuKFllYXIsIDE5OTMsIDIwMjIpKSAlPiUgDQogIGRyb3BfbmEoRE9JKSAlPiUgDQogIGdyb3VwX2J5KFllYXIsIFRlc3QgPSBET0kpICU+JSANCiAgc3VtbWFyaXNlKG4gPSBzdW0odXNhZ2VfY291bnQsIG5hLnJtID0gVCkpICU+JSANCiAgdW5ncm91cCgpICU+JSANCiAgbXV0YXRlKG5fdGVzdHMgPSBuX2Rpc3RpbmN0KFRlc3QpKSAlPiUgDQogIGdyb3VwX2J5KG5fdGVzdHMsIFllYXIpICU+JSANCiAgZmlsdGVyKG4gPiAwKSAlPiUgDQogIHN1bW1hcmlzZShub3JtX2VudHJvcHkgPSBjYWxjX25vcm1fZW50cm9weShuKSwNCiAgICAgICAgICAgIG5vcm1fZW50cm9weV9NTSA9IGVudHJvcHkobiwgbWV0aG9kID0gIk1NIikgLyBsb2cobigpKSwNCiAgICAgICAgICAgIG4gPSBzdW0obiksDQogICAgICAgICAgICBkaWZmX3Rlc3RzID0gbigpKSAlPiUgDQogIHVuZ3JvdXAoKQ0KDQpvcmlnaW5hbF9lbnRyb3B5X2J5X3llYXIgPC0gcHN5Y3Rlc3RzX2luZm8gJT4lIA0KICBmaWx0ZXIoYmV0d2VlbihZZWFyLCAxOTkzLCAyMDIyKSkgJT4lIA0KICBmaWx0ZXIodGVzdF90eXBlID09ICJPcmlnaW5hbCIpICU+JSANCiAgZ3JvdXBfYnkoWWVhciwgVGVzdCA9IERPSSkgJT4lIA0KICBzdW1tYXJpc2UobiA9IHN1bSh1c2FnZV9jb3VudCwgbmEucm0gPSBUKSkgJT4lIA0KICB1bmdyb3VwKCkgJT4lIA0KICBtdXRhdGUobl90ZXN0cyA9IG5fZGlzdGluY3QoVGVzdCkpICU+JSANCiAgZ3JvdXBfYnkobl90ZXN0cywgWWVhcikgJT4lIA0KICBmaWx0ZXIobiA+IDApICU+JSANCiAgc3VtbWFyaXNlKG5vcm1fZW50cm9weSA9IGNhbGNfbm9ybV9lbnRyb3B5KG4pLA0KICAgICAgICAgICAgbm9ybV9lbnRyb3B5X01NID0gZW50cm9weShuLCBtZXRob2QgPSAiTU0iKSAvIGxvZyhuKCkpLA0KICAgICAgICAgICAgbiA9IHN1bShuKSwNCiAgICAgICAgICAgIGRpZmZfdGVzdHMgPSBuKCkpICU+JSANCiAgdW5ncm91cCgpDQoNCmVudHJvcHlfYnlfeWVhciA8LSBiaW5kX3Jvd3MoIyAiYWxsIHRlc3RzIiA9IGFsbF9lbnRyb3B5X2J5X3llYXIsDQogICJtZWFzdXJlcyIgPSBvcmlnaW5hbF9lbnRyb3B5X2J5X3llYXIsDQogICJ3aXRoIHRyYW5zbGF0aW9uc1xuIGFuZCByZXZpc2lvbnMiID0gYnlvcmlnX2VudHJvcHlfYnlfeWVhciwNCiAgIyAiYnkgbmFtZSBiYXNlIiA9IGJ5YmFzZV9lbnRyb3B5X2J5X3llYXIsDQogICJjb25zdHJ1Y3RzIiA9IGJ5Y29uc3RydWN0X2VudHJvcHlfYnlfeWVhciwNCiAgLmlkID0gInZlcnNpb24iKQ0KDQoNCnBsb3RfZW50cm9weSA8LSBlbnRyb3B5X2J5X3llYXIgJT4lIA0KICBnZ3Bsb3QoLiwgYWVzKFllYXIsIG5vcm1fZW50cm9weSwgY29sb3IgPSB2ZXJzaW9uKSkgKw0KICBnZW9tX2xpbmUoc2l6ZSA9IDAuNywgbGluZXR5cGUgPSAiZGFzaGVkIikgKw0KICBnZW9tX2xpbmUoYWVzKHkgPSBub3JtX2VudHJvcHlfTU0pLCBzaXplID0gMC43KSArDQogIHNjYWxlX3lfY29udGludW91cygiTm9ybWFsaXplZCBTaGFubm9uIEVudHJvcHkiLCBsaW1pdHMgPSBjKDAsIDEpLCBsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQpICsNCiAgIyBnZW9tX2xpbmUoYWVzKHkgPSBsb2cobikpLCBjb2xvciA9ICdyZWQnKSArDQogIHNjYWxlX3hfY29udGludW91cygiVXNhZ2UgeWVhciBhcyBjb2RlZCBpbiBBUEEgUHN5Y0luZm8iLCBsaW1pdHMgPSBjKDE5OTMsIDIwMjcpLCANCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNlcSgxOTkzLCAyMDIyLCBieSA9IDEpLA0KICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygxOTkzLCAiIiwgIiIsICIiLCAiIiwgMTk5OCwgIiIsICIiLCAiIiwgIiIsIDIwMDMsICIiLCAiIiwgIiIsICIiLCAyMDA4LCAiIiwgIiIsICIiLCAiIiwgMjAxMywgIiIsICIiLCAiIiwgIiIsIDIwMTgsICIiLCAiIiwgIiIsICIyMDIyIikpICsNCiAgIyBnZ3RpdGxlKHN0cl9jKG5fZGlzdGluY3QodGVzdHNfYnlfeWVhciRUZXN0KSwgIiBtZWFzdXJlcyB0cmFja2VkIGluIFBzeWNJbmZvIikpICsNCiAgIyBhbm5vdGF0ZSgidGV4dCIsIHggPSAxOTkzLCB5ID0gMSwgbGFiZWwgPSAiLSBlYWNoIHVzZWQgb25jZSIsIA0KICAjICAgICAgIHNpemUgPSAzLjMsIHZqdXN0ID0gMC4zLCBoanVzdCA9IDAuMDUpICsNCiAgIyBhbm5vdGF0ZSgidGV4dCIsIHggPSAxOTkzLCB5ID0gMCwgbGFiZWwgPSAiLSBhbGwgdXNlZCBvbmUiLCANCiAgIyAgICAgICBzaXplID0gMy4zLCAgdmp1c3QgPSAwLjMsIGhqdXN0ID0gMC4wNSkgKw0KICANCiAgc2NhbGVfY29sb3JfYnJld2VyKHR5cGUgPSAicXVhbCIsIGd1aWRlID0gIm5vbmUiLCBwYWxldHRlID0gMikgKw0KICAjIGdncmVwZWw6Omdlb21fdGV4dF9yZXBlbCgNCiAgIyAgIGFlcyhsYWJlbCA9IHN0cl9yZXBsYWNlKHN1YmRpc2NpcGxpbmUsICIgUHN5Y2hvbG9neSIsICIiKSksIGRhdGEgPSBlbnRyb3B5X2J5X3llYXIgJT4lIGZpbHRlcihZZWFyID09IG1heChZZWFyLCBuYS5ybSA9IFQpKSwNCiAgIyAgIHNpemUgPSA0LCBoanVzdCA9IDEsDQogICMgICApICsgDQogIGdlb21fdGV4dF9yZXBlbChhZXMobGFiZWwgPSBzdHJfcmVwbGFjZV9hbGwodmVyc2lvbiwgIlthLXo9MC05LygpIF0rIiwgIiAiKSksICMgVGhpcyB3aWxsIGZvcmNlIHRoZSBjb3JyZWN0IHBvc2l0aW9uIG9mIHRoZSBsaW5rJ3MgcmlnaHQgZW5kLg0KICAgICAgICAgICAgICAgICAgZGF0YSA9IGVudHJvcHlfYnlfeWVhciAlPiUgZHJvcF9uYSgpICU+JSBncm91cF9ieSh2ZXJzaW9uKSAlPiUgZmlsdGVyKFllYXIgPT0gbWF4KFllYXIsIG5hLnJtID0gVCkpLA0KICAgICAgICAgICAgICAgICAgc2VnbWVudC5jdXJ2YXR1cmUgPSAtMC4xLA0KICAgICAgICAgICAgICAgICAgc2VnbWVudC5zcXVhcmUgPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgbGluZWhlaWdodCA9IC45LA0KICAgICAgICAgICAgICAgICAgc2VnbWVudC5jb2xvciA9ICdncmV5JywNCiAgICAgICAgICAgICAgICAgIGJveC5wYWRkaW5nID0gMC4xLA0KICAgICAgICAgICAgICAgICAgcG9pbnQucGFkZGluZyA9IDAuNiwNCiAgICAgICAgICAgICAgICAgIG51ZGdlX3ggPSAxLjE1LA0KICAgICAgICAgICAgICAgICAgbnVkZ2VfeSA9IDAuMDMsDQogICAgICAgICAgICAgICAgICBmb3JjZSA9IDAuOSwNCiAgICAgICAgICAgICAgICAgIGhqdXN0ID0gMCwNCiAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbj0ieSIsDQogICAgICAgICAgICAgICAgICBzaXplID0gMy4zLA0KICAgICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFKSArDQogIGdlb21fdGV4dF9yZXBlbChkYXRhID0gZW50cm9weV9ieV95ZWFyICU+JSBkcm9wX25hKCkgJT4lIGdyb3VwX2J5KHZlcnNpb24pICU+JSBmaWx0ZXIoWWVhciA9PSBtYXgoWWVhciwgbmEucm0gPSBUKSksDQogICAgICAgICAgICAgICAgICBhZXMobGFiZWwgPSBwYXN0ZTAoIiAiLHZlcnNpb24pKSwgIyAiXG4gKG4gPSAiLCBuX3Rlc3RzLCAiKSINCiAgICAgICAgICAgICAgICAgIHNlZ21lbnQuYWxwaGEgPSAwLCAjIyBUaGlzIHdpbGwgJ2hpZGUnIHRoZSBsaW5rDQogICAgICAgICAgICAgICAgICBzZWdtZW50LmN1cnZhdHVyZSA9IC0wLjEsDQogICAgICAgICAgICAgICAgICBzZWdtZW50LnNxdWFyZSA9IFRSVUUsDQogICAgICAgICAgICAgICAgICAjIHNlZ21lbnQuY29sb3IgPSAnZ3JleScsDQogICAgICAgICAgICAgICAgICBib3gucGFkZGluZyA9IDAuMSwNCiAgICAgICAgICAgICAgICAgIHBvaW50LnBhZGRpbmcgPSAwLjYsDQogICAgICAgICAgICAgICAgICBudWRnZV94ID0gMS4xNSwNCiAgICAgICAgICAgICAgICAgIG51ZGdlX3kgPSAwLjAsDQogICAgICAgICAgICAgICAgICBsaW5laGVpZ2h0ID0gLjksDQogICAgICAgICAgICAgICAgICBmb3JjZSA9IDAuOSwNCiAgICAgICAgICAgICAgICAgIHNpemUgPSAzLjMsDQogICAgICAgICAgICAgICAgICBoanVzdCA9IDAsDQogICAgICAgICAgICAgICAgICBkaXJlY3Rpb249InkiLA0KICAgICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFKSArDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTMpICsNCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vci55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5ncmlkLm1pbm9yLnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBsb3QudGl0bGUucG9zaXRpb24gPSAicGxvdCIsDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZT0iYm9sZCIpLA0KICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQpwbG90X2VudHJvcHkNCmBgYA0KDQojIyBFbnRyb3B5IGJ5IGNsYXNzaWZpY2FpdG9uDQpgYGB7cn0NCmVudHJvcHlfYnlfY2xhc3MgPC0gcHN5Y3Rlc3RzX2luZm8gJT4lIA0KICBncm91cF9ieShjbGFzc2lmaWNhdGlvbl8xLCBET0kpICU+JSANCiAgc3VtbWFyaXNlKG4gPSBzdW0odXNhZ2VfY291bnQsIG5hLnJtID0gVCksDQogICAgICAgICAgICBwYXJlbnQgPSBjYXNlX3doZW4oDQogICAgICAgICAgICAgICAgICAgIG4gPiA1MCB+ICIiLA0KICAgICAgICAgICAgICAgICAgICBuID4gMjAgfiAidXNlZCAyMS01MCB0aW1lcyIsDQogICAgICAgICAgICAgICAgICAgIG4gPiA1IH4gInVzZWQgNi0yMCB0aW1lcyIsDQogICAgICAgICAgICAgICAgICAgIFRSVUUgfiAidXNlZCAxLTUgdGltZXMiKSkgJT4lIA0KICBncm91cF9ieShjbGFzc2lmaWNhdGlvbl8xKSAlPiUgDQogICMgZmlsdGVyKG4gPiAwKSAlPiUgDQogIHN1bW1hcmlzZSgNCiAgICBlbnRyb3B5ID0gZW50cm9weShuKSwNCiAgICBub3JtX2VudHJvcHkgPSBjYWxjX25vcm1fZW50cm9weShuKSkgJT4lIA0KICBhcnJhbmdlKG5vcm1fZW50cm9weSkNCg0Ka2FibGUoZW50cm9weV9ieV9jbGFzcykNCmBgYA0KDQojIyBFbnRyb3B5IGJ5IGluc3RydW1lbnQgdHlwZQ0KYGBge3J9DQpwc3ljdGVzdHNfaW5mbyAlPiUgDQogIGdyb3VwX2J5KGluc3RydW1lbnRfdHlwZV9icm9hZCwgRE9JKSAlPiUgDQogIHN1bW1hcmlzZShuID0gc3VtKHVzYWdlX2NvdW50LCBuYS5ybSA9IFQpLA0KICAgICAgICAgICAgcGFyZW50ID0gY2FzZV93aGVuKA0KICAgICAgICAgICAgICAgICAgICBuID4gNTAgfiAiIiwNCiAgICAgICAgICAgICAgICAgICAgbiA+IDIwIH4gInVzZWQgMjEtNTAgdGltZXMiLA0KICAgICAgICAgICAgICAgICAgICBuID4gNSB+ICJ1c2VkIDYtMjAgdGltZXMiLA0KICAgICAgICAgICAgICAgICAgICBUUlVFIH4gInVzZWQgMS01IHRpbWVzIikpICU+JSANCiAgZ3JvdXBfYnkoaW5zdHJ1bWVudF90eXBlX2Jyb2FkKSAlPiUgDQogIGZpbHRlcihuID4gMCkgJT4lIA0KICBzdW1tYXJpc2UoDQogICAgZW50cm9weSA9IGVudHJvcHkobiksDQogICAgbm9ybV9lbnRyb3B5ID0gY2FsY19ub3JtX2VudHJvcHkobikpICU+JSANCiAgYXJyYW5nZShub3JtX2VudHJvcHkpICU+JSANCiAga2FibGUoKQ0KYGBgDQoNCiMgVGVzdHMgYnkgZXhhY3Qgc2FtZSBuYW1lDQpgYGB7cn0NCnNhbWVfbmFtZV90ZXN0cyA8LSByZWNvcmRzX3dpZGUgJT4lIGdyb3VwX2J5KG5hbWVfcHN5Y2luZm8pICU+JSBmaWx0ZXIobl9kaXN0aW5jdChET0kpID4gMSkgJT4lIHN1bW1hcmlzZShuID0gbigpKQ0KbnJvdyhzYW1lX25hbWVfdGVzdHMpDQptZWFuKHNhbWVfbmFtZV90ZXN0cyRuKQ0Kc2FtZV9uYW1lX3Rlc3RzICU+JSBhcnJhbmdlKGRlc2MobikpICU+JSBoZWFkKDIwKQ0KYGBgDQoNCg==