Setup

knitr::opts_knit$set(root.dir = here::here())
library(tidyverse)
library(here)
library(jsonlite)
library(assertthat)
library(irr)
pak::pkg_install("hsci-r/gghsci")
library(gghsci)
library(ggbeeswarm)
library(gt)
renv::snapshot()
sorensen <- function(x,y){
    assert_that(is.character(x))
    assert_that(is.character(y))
    index <- 
        2*(length(intersect(x,y)))/(2*(length(intersect(x,y)))+
                                        length(setdiff(x,y))+
                                        length(setdiff(y,x)))
    return(index)
}
sorensen_dist <- function(x,y) {
  return(1-sorensen(x,y))
}

Data loading

AP loading

clarity_bound <- 0.75
quick_bound_centile <- 3
slow_bound_centile <- 7
short_bound_centile <- 3
long_bound_centile <- 7

raw_data <- list.files(here("data/final_annotations"),full.names=T) %>%
  setNames(.,str_replace(basename(.),"annotointi_(.*)\\.csv$","\\1")) %>% 
  map_dfr(~read_csv(.,show_col_types=F),.id="name") %>%
  replace_na(list(theme="not alcohol policy")) %>%
  mutate(document_id=as.numeric(factor(text))) %>%
  group_by(name) %>%
  mutate(lead_time_centile=ntile(lead_time,10),lead_time_quartile=ntile(lead_time,4)) %>%
  ungroup() %>%
  mutate(speed_type=case_when(
    lead_time_centile>=slow_bound_centile ~ "slow",
    lead_time_centile<=quick_bound_centile ~ "quick",
    T ~ "in-between"
  )) %>% 
  mutate(whole_article=is.na(answer)) %>%
  mutate(part_length=map_if(answer,~!is.na(.),~fromJSON(.),.else=~list())) %>%
  mutate(part_length=map(part_length,~.$end-.$start)) %>% 
  mutate(part_length=map_dbl(part_length,~reduce(.,~.x+.y,.init=0))) %>%
  group_by(text)%>%
  mutate(annotations=n()) %>%
  ungroup() %>%
  extract(text,into=c("url"),regex = "^([^ ]*)") %>%
  rename(annotation_document_id=document_id)

md <- bind_rows(
  read_csv(here("data/df_joined_individual.csv")),
  read_csv(here("data/df_joined_interannotator.csv"))
  ) %>%
  mutate(content_length_centile=ntile(nr_characters,10),content_length_quartile=ntile(nr_characters,4)) %>%
  mutate(length_type=case_when(
    content_length_centile<=short_bound_centile ~ "short",
    content_length_centile>=long_bound_centile ~ "long",
    T ~ "in-between"
  ))
New names:
• `` -> `...1`
Rows: 1500 Columns: 25
── Column specification ──────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr  (15): text, url, section, document_id, title, author, subsection, media, subject, genre, ...
dbl   (8): ...1, score, sentences, nr_characters, nr_tokens, paragraphs, document_parts, urgency
dttm  (2): time_created, time_modified

ℹ 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.
New names:
• `` -> `...1`
Rows: 100 Columns: 25
── Column specification ──────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr  (15): text, url, section, document_id, title, author, subsection, media, subject, genre, ...
dbl   (8): ...1, score, sentences, nr_characters, nr_tokens, paragraphs, document_parts, urgency
dttm  (2): time_created, time_modified

ℹ 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.
raw_data <- raw_data %>% 
  inner_join(md)
Joining, by = "url"
assert_that(nrow(md)==1600)
[1] TRUE
assert_that(nrow(raw_data)==5500)
[1] TRUE
dl <- bind_rows(
  raw_data %>% filter(str_sub(theme,1,1)!='{') %>% mutate(multiple=F),
  raw_data %>% filter(str_sub(theme,1,1)=='{') %>%
    mutate(theme=map(theme,~fromJSON(.) %>% as.data.frame())) %>% 
    unnest(theme) %>% 
    rename(theme=choices)
  )
New names:
• `...1` -> `...18`
New names:
• `...1` -> `...18`
d <- dl %>% 
  group_by(across(-theme)) %>% 
  arrange(theme) %>%
  summarize(theme=str_c(theme,collapse="|"),.groups="drop") %>% 
  group_by(text,theme) %>% 
  mutate(theme_annotations=n()) %>% 
  group_by(text,speed_type) %>% 
  mutate(speed_type_annotations=n()) %>% 
  group_by(text,whole_article) %>%
  mutate(whole_article_annotations=n()) %>%
  group_by(text) %>% 
  arrange(desc(theme_annotations),theme) %>% 
  mutate(theme_annotation_proportion=theme_annotations/n()) %>% 
  mutate(majority_theme=str_flatten(na.omit(unique(if_else(theme_annotations==max(theme_annotations),theme,NA_character_))),collapse="|"),majority_theme_annotations=first(theme_annotations),majority_theme_proportion=first(theme_annotations)/n()) %>%
  arrange(desc(speed_type_annotations),speed_type) %>% 
  mutate(speed_type_annotation_proportion=speed_type_annotations/n()) %>% 
  mutate(majority_speed_type=str_flatten(na.omit(unique(if_else(speed_type_annotations==max(speed_type_annotations),speed_type,NA_character_))),collapse="|"),majority_speed_type_annotations=first(speed_type_annotations),majority_speed_type_proportion=first(speed_type_annotations)/n()) %>%
  arrange(desc(whole_article_annotations),whole_article) %>% 
  mutate(whole_article_annotation_proportion=whole_article_annotations/n()) %>% 
  mutate(majority_whole_article=str_flatten(na.omit(unique(if_else(whole_article_annotations==max(whole_article_annotations),whole_article,NA))),collapse="|"),majority_whole_article_annotations=first(whole_article_annotations),majority_whole_article_proportion=first(whole_article_annotations)/n()) %>%
  ungroup() %>%
  mutate(
    decision_type=if_else(theme==majority_theme,"assent","dissent"),
    clarity=if_else(majority_theme_proportion>=clarity_bound,"clear","unclear")
  )

assert_that(nrow(d)==5500)
[1] TRUE
bd <- d %>% 
  mutate(theme=if_else(theme=="not alcohol policy",theme,"alcohol policy"))
bd <- bd %>% 
  group_by(text,theme) %>% 
  mutate(n=n()) %>% 
  group_by(text) %>% 
  arrange(desc(n),theme) %>% 
  mutate(prop=n/n()) %>% 
  mutate(majority_theme=str_flatten(na.omit(unique(if_else(n==max(n),theme,NA_character_))),collapse="|"),majority_theme_n=first(n),majority_theme_proportion=first(n)/n()) %>%
  ungroup() %>%
  mutate(
    decision_type=if_else(theme==majority_theme,"assent","dissent"),
    clarity=if_else(majority_theme_proportion>=clarity_bound,"clear","unclear")
  )

bmd <- md %>%
  inner_join(bd %>% distinct(url,annotations,majority_theme,majority_theme_annotations,majority_theme_proportion,clarity,majority_speed_type,majority_speed_type_annotations,majority_speed_type_proportion,majority_whole_article))
Joining, by = "url"
assert_that(nrow(bmd)==1600)
[1] TRUE
md <- md %>% 
  inner_join(d %>% distinct(url,annotations,majority_theme,majority_theme_annotations,majority_theme_proportion,clarity,majority_speed_type,majority_speed_type_annotations,majority_speed_type_proportion,majority_whole_article))
Joining, by = "url"
assert_that(nrow(md)==1600)
[1] TRUE

MV loading

mvd <- list.files(here("data/mv_annotations/"),full.names=T) %>%
  setNames(.,str_replace(basename(.),"annotator_(.*)\\.csv$","\\1")) %>% 
  map_dfr(~read_csv(.,show_col_types=F),.id="name") %>%
  replace_na(list(sentiment="empty")) %>%
  filter(sentiment!="empty") %>%
  mutate(document_id=as.numeric(factor(text))) %>%
  group_by(name) %>%
  mutate(lead_time_centile=ntile(lead_time,10),lead_time_quartile=ntile(lead_time,4)) %>%
  ungroup() %>%
  mutate(speed_type=case_when(
    lead_time_centile>=slow_bound_centile ~ "slow",
    lead_time_centile<=quick_bound_centile ~ "quick",
    T ~ "in-between"
  )) %>% 
  group_by(text,sentiment) %>% 
  mutate(sentiment_annotations=n()) %>% 
  group_by(text,speed_type) %>% 
  mutate(speed_type_annotations=n()) %>% 
  group_by(text) %>% 
  arrange(desc(sentiment_annotations)) %>% 
  mutate(sentiment_annotation_proportion=sentiment_annotations/n()) %>% 
  mutate(majority_sentiment=first(sentiment),majority_sentiment_annotations=first(sentiment_annotations),majority_sentiment_proportion=first(sentiment_annotations)/n()) %>%
  arrange(desc(speed_type_annotations),speed_type) %>% 
  mutate(speed_type_annotation_proportion=speed_type_annotations/n()) %>% 
  mutate(majority_speed_type=str_flatten(na.omit(unique(if_else(speed_type_annotations==max(speed_type_annotations),speed_type,NA_character_))),collapse="|"),majority_speed_type_annotations=first(speed_type_annotations),majority_speed_type_proportion=first(speed_type_annotations)/n()) %>%
  ungroup() %>%
  mutate(
    decision_type=if_else(sentiment==majority_sentiment,"assent","dissent"),
    clarity=if_else(majority_sentiment_proportion>=clarity_bound,"clear","unclear")
  )

mvmd <- read_csv(here("data/MV_data_final_links.csv"),col_select=c("content","link")) %>% 
  mutate(content_length=str_length(content)) %>%
  mutate(content_length_centile=ntile(content_length,10),content_length_quartile=ntile(content_length,4))  %>%
  mutate(length_type=case_when(
    content_length_centile<=short_bound_centile ~ "short",
    content_length_centile>=long_bound_centile ~ "long",
    T ~ "in-between"
  )) %>% rename(text=link)
New names:
• `` -> `...1`
Rows: 997 Columns: 2
── Column specification ──────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (2): content, link

ℹ 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.
mvd <- mvd %>% inner_join(mvmd)
Joining, by = "text"
mvmd <- mvmd %>% inner_join(mvd %>% distinct(text,majority_sentiment,majority_sentiment_annotations,majority_sentiment_proportion,clarity,majority_speed_type,majority_speed_type_annotations,majority_speed_type_proportion))
Joining, by = "text"
assert_that(nrow(mvmd)==98)
[1] TRUE

Binary alcohol policy analyses

Majority theme proportions

N Proportion
not alcohol policy 936 58.50%
alcohol policy 660 41.25%
alcohol policy|not alcohol policy 4 0.25%

60/40 split between not AP and AP is a pretty even base.

Decision clarity by majority theme

N Proportion
alcohol policy
clear 445 67.42%
unclear 215 32.58%
not alcohol policy
clear 757 80.88%
unclear 179 19.12%

There are proportionally more clear decisions for not alcohol policy than there are for alcohol policy -> it is easier to say that something is not AP than to say that something is AP.

Theme, clarity and speed type cross investigation

There is a subset of articles where it is quick to decide that they are not AP.

Theme, clarity and whole/part investigation

When an article deals only partially with alcohol, it is more likely to not be an alcohol policy article. It is harder to clearly decide whether an article not dealing completely with alcohol is AP or not as compared to an article wholly dealing with alcohol.

Theme, clarity, speed type and length cross investigation

Unsurprisingly, longer articles take longer to decide upon. Short non-AP articles are particularly easy to categorize clearly, but there is also the potential for error here, as evidenced by the high number of “unclear” quick selections in the short articles.

Alcohol policy annotator analyses

Time to decide by annotator

Very clearly different task time profiles between annotators.

Agreement matrix between annotators

p <- scales::percent_format(accuracy=1)
bd %>% 
  full_join(bd,by=c("text")) %>%
  mutate(agree=theme.x==theme.y) %>%
  group_by(name.x,name.y) %>%
  summarize(agree=sum(agree),pagree=sum(agree)/n(),.groups="drop") %>%
  ggplot(aes(x=name.x,y=name.y,fill=pagree)) +
  geom_raster() +
  theme_hsci() +
  scale_fill_viridis_c(labels=scales::percent_format(accuracy=1)) +
  geom_text(aes(label=p(pagree))) +
  labs(fill="Agreement") +
  xlab("Annotator 1") +
  ylab("Annotator 2")

Kaisa stands out as an annotator with lower agreement to the majority of other annotators, except interestingly Sonja and Susanna.

Proportion of annotators indicating the majority viewpoint

Time taken to annotate by annotator and clarity

Almost all annotators are likely to spend more time on “problematic” articles, here proxied by their clarity(=the amount of general agreement wrt them). -> the annotators are doing a good job, and most errors should not be caused by carelessness but by actual decision differences and ambiguities in guidelines.

Annotation time difference based on agreement between annotator pairs

At the same time, there is also clearly an effect visible where difference in annotation time explains agreement, so there is also an attentiveness component to the disagreements.

Heuristics for testing whether outlier annotator should be removed

kripp.alpha(bd %>% 
              pivot_wider(id_cols=name,names_from=document_id,values_from=theme) %>%
              select(-name) %>% 
              as.matrix,
            method="nominal")
Warning in kripp.alpha(bd %>% pivot_wider(id_cols = name, names_from = document_id,  :
  NAs introduced by coercion
 Krippendorff's alpha

 Subjects = 1600 
   Raters = 10 
    alpha = 0.657 
kripp.alpha(bd %>% 
              filter(name!="Kaisa") %>%
              pivot_wider(id_cols=name,names_from=document_id,values_from=theme) %>%
              select(-name) %>% 
              as.matrix,
            method="nominal")
Warning in kripp.alpha(bd %>% filter(name != "Kaisa") %>% pivot_wider(id_cols = name,  :
  NAs introduced by coercion
 Krippendorff's alpha

 Subjects = 1600 
   Raters = 9 
    alpha = 0.688 

MV analyses

Majority sentiment proportions

N Proportion
Sisällön kopiointi valtamediasta 69 70.41%
Oman narratiivin rakentaminen lähdeviitteiden avulla 24 24.49%
Journalistisen median kritiikki 5 5.10%

70% of this data is copying from mainstream media. 24 articles is probably enough to analyse the developing of one’s own narrative, but there are really too few “criticism of mainstream media” articles to draw conclusions from.

Decision clarity by majority sentiment

N Proportion
Journalistisen median kritiikki
clear 4 80.00%
unclear 1 20.00%
Oman narratiivin rakentaminen lähdeviitteiden avulla
clear 16 66.67%
unclear 8 33.33%
Sisällön kopiointi valtamediasta
clear 66 95.65%
unclear 3 4.35%

Identifying the copying of material from mainstream media seems quite clear, as opposed to whether something is building their own narrative.

The confusion matrix between annotation pairs tells a bit more:

Here, it seems that it is hard to draw boundaries between the development of one’s own narrative and both journalistic critique as well as copying.

Sentiment, clarity and speed type cross investigation

Again, too few critique articles to draw conclusions from. Otherwise, seems that the only clear category identified quickly is a subset of articles copying content from mainstream media. Even for clear cases of building one’s own narrative, decisions take long to reach.

Theme, clarity, speed type and length cross investigation

Here even more categories lack data to base decisions on. What we can see is that copying can be relatively quickly identified in all length categories, and that own narrative articles are often long and slow to parse.

MV annotator analyses

Again, we have two different annotator profiles evident.

Agreement matrix between annotators

No clear outlier annotators appear in this task:

Proportion of annotators indicating the majority viewpoint

Time taken to annotate by annotator and whether all annotators agree

Here again, annotators are likely to spend more time on “problematic” articles, here proxied by their clarity(=the amount of general agreement wrt them). An interesting exception is the own narrative category, where unclear decisions may have been due to making them in haste.

Annotation time difference based on agreement between annotator pairs

Again, there is also clearly an effect visible where difference in annotation time explains agreement.

Categorical data is here a bit sparse to draw conclusions, but may further point to attentiveness differences in explaining disagreement on the boundaries of the own narrative category. Similarly, because the critique category requires picking up on individual sentence ques, time taken may explain some of the difference for that category.

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiAKICBodG1sX25vdGVib29rOgogICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgICB0b2M6IHRydWUKLS0tCgojIFNldHVwCgpgYGB7ciBzZXR1cH0Ka25pdHI6Om9wdHNfa25pdCRzZXQocm9vdC5kaXIgPSBoZXJlOjpoZXJlKCkpCmBgYAoKYGBge3IscmVzdWx0cz0naGlkZSd9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGhlcmUpCmxpYnJhcnkoanNvbmxpdGUpCmxpYnJhcnkoYXNzZXJ0dGhhdCkKbGlicmFyeShpcnIpCnBhazo6cGtnX2luc3RhbGwoImhzY2ktci9nZ2hzY2kiKQpsaWJyYXJ5KGdnaHNjaSkKbGlicmFyeShnZ2JlZXN3YXJtKQpsaWJyYXJ5KGd0KQpyZW52OjpzbmFwc2hvdCgpCmBgYAoKYGBge3J9CnNvcmVuc2VuIDwtIGZ1bmN0aW9uKHgseSl7CiAgICBhc3NlcnRfdGhhdChpcy5jaGFyYWN0ZXIoeCkpCiAgICBhc3NlcnRfdGhhdChpcy5jaGFyYWN0ZXIoeSkpCiAgICBpbmRleCA8LSAKICAgICAgICAyKihsZW5ndGgoaW50ZXJzZWN0KHgseSkpKS8oMioobGVuZ3RoKGludGVyc2VjdCh4LHkpKSkrCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZW5ndGgoc2V0ZGlmZih4LHkpKSsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlbmd0aChzZXRkaWZmKHkseCkpKQogICAgcmV0dXJuKGluZGV4KQp9CnNvcmVuc2VuX2Rpc3QgPC0gZnVuY3Rpb24oeCx5KSB7CiAgcmV0dXJuKDEtc29yZW5zZW4oeCx5KSkKfQpgYGAKCiMgRGF0YSBsb2FkaW5nCgojIyBBUCBsb2FkaW5nCgpgYGB7cn0KY2xhcml0eV9ib3VuZCA8LSAwLjc1CnF1aWNrX2JvdW5kX2NlbnRpbGUgPC0gMwpzbG93X2JvdW5kX2NlbnRpbGUgPC0gNwpzaG9ydF9ib3VuZF9jZW50aWxlIDwtIDMKbG9uZ19ib3VuZF9jZW50aWxlIDwtIDcKCnJhd19kYXRhIDwtIGxpc3QuZmlsZXMoaGVyZSgiZGF0YS9maW5hbF9hbm5vdGF0aW9ucyIpLGZ1bGwubmFtZXM9VCkgJT4lCiAgc2V0TmFtZXMoLixzdHJfcmVwbGFjZShiYXNlbmFtZSguKSwiYW5ub3RvaW50aV8oLiopXFwuY3N2JCIsIlxcMSIpKSAlPiUgCiAgbWFwX2Rmcih+cmVhZF9jc3YoLixzaG93X2NvbF90eXBlcz1GKSwuaWQ9Im5hbWUiKSAlPiUKICByZXBsYWNlX25hKGxpc3QodGhlbWU9Im5vdCBhbGNvaG9sIHBvbGljeSIpKSAlPiUKICBtdXRhdGUoZG9jdW1lbnRfaWQ9YXMubnVtZXJpYyhmYWN0b3IodGV4dCkpKSAlPiUKICBncm91cF9ieShuYW1lKSAlPiUKICBtdXRhdGUobGVhZF90aW1lX2NlbnRpbGU9bnRpbGUobGVhZF90aW1lLDEwKSxsZWFkX3RpbWVfcXVhcnRpbGU9bnRpbGUobGVhZF90aW1lLDQpKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKHNwZWVkX3R5cGU9Y2FzZV93aGVuKAogICAgbGVhZF90aW1lX2NlbnRpbGU+PXNsb3dfYm91bmRfY2VudGlsZSB+ICJzbG93IiwKICAgIGxlYWRfdGltZV9jZW50aWxlPD1xdWlja19ib3VuZF9jZW50aWxlIH4gInF1aWNrIiwKICAgIFQgfiAiaW4tYmV0d2VlbiIKICApKSAlPiUgCiAgbXV0YXRlKHdob2xlX2FydGljbGU9aXMubmEoYW5zd2VyKSkgJT4lCiAgbXV0YXRlKHBhcnRfbGVuZ3RoPW1hcF9pZihhbnN3ZXIsfiFpcy5uYSguKSx+ZnJvbUpTT04oLiksLmVsc2U9fmxpc3QoKSkpICU+JQogIG11dGF0ZShwYXJ0X2xlbmd0aD1tYXAocGFydF9sZW5ndGgsfi4kZW5kLS4kc3RhcnQpKSAlPiUgCiAgbXV0YXRlKHBhcnRfbGVuZ3RoPW1hcF9kYmwocGFydF9sZW5ndGgsfnJlZHVjZSguLH4ueCsueSwuaW5pdD0wKSkpICU+JQogIGdyb3VwX2J5KHRleHQpJT4lCiAgbXV0YXRlKGFubm90YXRpb25zPW4oKSkgJT4lCiAgdW5ncm91cCgpICU+JQogIGV4dHJhY3QodGV4dCxpbnRvPWMoInVybCIpLHJlZ2V4ID0gIl4oW14gXSopIikgJT4lCiAgcmVuYW1lKGFubm90YXRpb25fZG9jdW1lbnRfaWQ9ZG9jdW1lbnRfaWQpCgptZCA8LSBiaW5kX3Jvd3MoCiAgcmVhZF9jc3YoaGVyZSgiZGF0YS9kZl9qb2luZWRfaW5kaXZpZHVhbC5jc3YiKSksCiAgcmVhZF9jc3YoaGVyZSgiZGF0YS9kZl9qb2luZWRfaW50ZXJhbm5vdGF0b3IuY3N2IikpCiAgKSAlPiUKICBtdXRhdGUoY29udGVudF9sZW5ndGhfY2VudGlsZT1udGlsZShucl9jaGFyYWN0ZXJzLDEwKSxjb250ZW50X2xlbmd0aF9xdWFydGlsZT1udGlsZShucl9jaGFyYWN0ZXJzLDQpKSAlPiUKICBtdXRhdGUobGVuZ3RoX3R5cGU9Y2FzZV93aGVuKAogICAgY29udGVudF9sZW5ndGhfY2VudGlsZTw9c2hvcnRfYm91bmRfY2VudGlsZSB+ICJzaG9ydCIsCiAgICBjb250ZW50X2xlbmd0aF9jZW50aWxlPj1sb25nX2JvdW5kX2NlbnRpbGUgfiAibG9uZyIsCiAgICBUIH4gImluLWJldHdlZW4iCiAgKSkKCnJhd19kYXRhIDwtIHJhd19kYXRhICU+JSAKICBpbm5lcl9qb2luKG1kKQoKYXNzZXJ0X3RoYXQobnJvdyhtZCk9PTE2MDApCmFzc2VydF90aGF0KG5yb3cocmF3X2RhdGEpPT01NTAwKQoKZGwgPC0gYmluZF9yb3dzKAogIHJhd19kYXRhICU+JSBmaWx0ZXIoc3RyX3N1Yih0aGVtZSwxLDEpIT0neycpICU+JSBtdXRhdGUobXVsdGlwbGU9RiksCiAgcmF3X2RhdGEgJT4lIGZpbHRlcihzdHJfc3ViKHRoZW1lLDEsMSk9PSd7JykgJT4lCiAgICBtdXRhdGUodGhlbWU9bWFwKHRoZW1lLH5mcm9tSlNPTiguKSAlPiUgYXMuZGF0YS5mcmFtZSgpKSkgJT4lIAogICAgdW5uZXN0KHRoZW1lKSAlPiUgCiAgICByZW5hbWUodGhlbWU9Y2hvaWNlcykKICApCgpkIDwtIGRsICU+JSAKICBncm91cF9ieShhY3Jvc3MoLXRoZW1lKSkgJT4lIAogIGFycmFuZ2UodGhlbWUpICU+JQogIHN1bW1hcml6ZSh0aGVtZT1zdHJfYyh0aGVtZSxjb2xsYXBzZT0ifCIpLC5ncm91cHM9ImRyb3AiKSAlPiUgCiAgZ3JvdXBfYnkodGV4dCx0aGVtZSkgJT4lIAogIG11dGF0ZSh0aGVtZV9hbm5vdGF0aW9ucz1uKCkpICU+JSAKICBncm91cF9ieSh0ZXh0LHNwZWVkX3R5cGUpICU+JSAKICBtdXRhdGUoc3BlZWRfdHlwZV9hbm5vdGF0aW9ucz1uKCkpICU+JSAKICBncm91cF9ieSh0ZXh0LHdob2xlX2FydGljbGUpICU+JQogIG11dGF0ZSh3aG9sZV9hcnRpY2xlX2Fubm90YXRpb25zPW4oKSkgJT4lCiAgZ3JvdXBfYnkodGV4dCkgJT4lIAogIGFycmFuZ2UoZGVzYyh0aGVtZV9hbm5vdGF0aW9ucyksdGhlbWUpICU+JSAKICBtdXRhdGUodGhlbWVfYW5ub3RhdGlvbl9wcm9wb3J0aW9uPXRoZW1lX2Fubm90YXRpb25zL24oKSkgJT4lIAogIG11dGF0ZShtYWpvcml0eV90aGVtZT1zdHJfZmxhdHRlbihuYS5vbWl0KHVuaXF1ZShpZl9lbHNlKHRoZW1lX2Fubm90YXRpb25zPT1tYXgodGhlbWVfYW5ub3RhdGlvbnMpLHRoZW1lLE5BX2NoYXJhY3Rlcl8pKSksY29sbGFwc2U9InwiKSxtYWpvcml0eV90aGVtZV9hbm5vdGF0aW9ucz1maXJzdCh0aGVtZV9hbm5vdGF0aW9ucyksbWFqb3JpdHlfdGhlbWVfcHJvcG9ydGlvbj1maXJzdCh0aGVtZV9hbm5vdGF0aW9ucykvbigpKSAlPiUKICBhcnJhbmdlKGRlc2Moc3BlZWRfdHlwZV9hbm5vdGF0aW9ucyksc3BlZWRfdHlwZSkgJT4lIAogIG11dGF0ZShzcGVlZF90eXBlX2Fubm90YXRpb25fcHJvcG9ydGlvbj1zcGVlZF90eXBlX2Fubm90YXRpb25zL24oKSkgJT4lIAogIG11dGF0ZShtYWpvcml0eV9zcGVlZF90eXBlPXN0cl9mbGF0dGVuKG5hLm9taXQodW5pcXVlKGlmX2Vsc2Uoc3BlZWRfdHlwZV9hbm5vdGF0aW9ucz09bWF4KHNwZWVkX3R5cGVfYW5ub3RhdGlvbnMpLHNwZWVkX3R5cGUsTkFfY2hhcmFjdGVyXykpKSxjb2xsYXBzZT0ifCIpLG1ham9yaXR5X3NwZWVkX3R5cGVfYW5ub3RhdGlvbnM9Zmlyc3Qoc3BlZWRfdHlwZV9hbm5vdGF0aW9ucyksbWFqb3JpdHlfc3BlZWRfdHlwZV9wcm9wb3J0aW9uPWZpcnN0KHNwZWVkX3R5cGVfYW5ub3RhdGlvbnMpL24oKSkgJT4lCiAgYXJyYW5nZShkZXNjKHdob2xlX2FydGljbGVfYW5ub3RhdGlvbnMpLHdob2xlX2FydGljbGUpICU+JSAKICBtdXRhdGUod2hvbGVfYXJ0aWNsZV9hbm5vdGF0aW9uX3Byb3BvcnRpb249d2hvbGVfYXJ0aWNsZV9hbm5vdGF0aW9ucy9uKCkpICU+JSAKICBtdXRhdGUobWFqb3JpdHlfd2hvbGVfYXJ0aWNsZT1zdHJfZmxhdHRlbihuYS5vbWl0KHVuaXF1ZShpZl9lbHNlKHdob2xlX2FydGljbGVfYW5ub3RhdGlvbnM9PW1heCh3aG9sZV9hcnRpY2xlX2Fubm90YXRpb25zKSx3aG9sZV9hcnRpY2xlLE5BKSkpLGNvbGxhcHNlPSJ8IiksbWFqb3JpdHlfd2hvbGVfYXJ0aWNsZV9hbm5vdGF0aW9ucz1maXJzdCh3aG9sZV9hcnRpY2xlX2Fubm90YXRpb25zKSxtYWpvcml0eV93aG9sZV9hcnRpY2xlX3Byb3BvcnRpb249Zmlyc3Qod2hvbGVfYXJ0aWNsZV9hbm5vdGF0aW9ucykvbigpKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKAogICAgZGVjaXNpb25fdHlwZT1pZl9lbHNlKHRoZW1lPT1tYWpvcml0eV90aGVtZSwiYXNzZW50IiwiZGlzc2VudCIpLAogICAgY2xhcml0eT1pZl9lbHNlKG1ham9yaXR5X3RoZW1lX3Byb3BvcnRpb24+PWNsYXJpdHlfYm91bmQsImNsZWFyIiwidW5jbGVhciIpCiAgKQoKYXNzZXJ0X3RoYXQobnJvdyhkKT09NTUwMCkKCmJkIDwtIGQgJT4lIAogIG11dGF0ZSh0aGVtZT1pZl9lbHNlKHRoZW1lPT0ibm90IGFsY29ob2wgcG9saWN5Iix0aGVtZSwiYWxjb2hvbCBwb2xpY3kiKSkKYmQgPC0gYmQgJT4lIAogIGdyb3VwX2J5KHRleHQsdGhlbWUpICU+JSAKICBtdXRhdGUobj1uKCkpICU+JSAKICBncm91cF9ieSh0ZXh0KSAlPiUgCiAgYXJyYW5nZShkZXNjKG4pLHRoZW1lKSAlPiUgCiAgbXV0YXRlKHByb3A9bi9uKCkpICU+JSAKICBtdXRhdGUobWFqb3JpdHlfdGhlbWU9c3RyX2ZsYXR0ZW4obmEub21pdCh1bmlxdWUoaWZfZWxzZShuPT1tYXgobiksdGhlbWUsTkFfY2hhcmFjdGVyXykpKSxjb2xsYXBzZT0ifCIpLG1ham9yaXR5X3RoZW1lX249Zmlyc3QobiksbWFqb3JpdHlfdGhlbWVfcHJvcG9ydGlvbj1maXJzdChuKS9uKCkpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBtdXRhdGUoCiAgICBkZWNpc2lvbl90eXBlPWlmX2Vsc2UodGhlbWU9PW1ham9yaXR5X3RoZW1lLCJhc3NlbnQiLCJkaXNzZW50IiksCiAgICBjbGFyaXR5PWlmX2Vsc2UobWFqb3JpdHlfdGhlbWVfcHJvcG9ydGlvbj49Y2xhcml0eV9ib3VuZCwiY2xlYXIiLCJ1bmNsZWFyIikKICApCgpibWQgPC0gbWQgJT4lCiAgaW5uZXJfam9pbihiZCAlPiUgZGlzdGluY3QodXJsLGFubm90YXRpb25zLG1ham9yaXR5X3RoZW1lLG1ham9yaXR5X3RoZW1lX2Fubm90YXRpb25zLG1ham9yaXR5X3RoZW1lX3Byb3BvcnRpb24sY2xhcml0eSxtYWpvcml0eV9zcGVlZF90eXBlLG1ham9yaXR5X3NwZWVkX3R5cGVfYW5ub3RhdGlvbnMsbWFqb3JpdHlfc3BlZWRfdHlwZV9wcm9wb3J0aW9uLG1ham9yaXR5X3dob2xlX2FydGljbGUpKQoKYXNzZXJ0X3RoYXQobnJvdyhibWQpPT0xNjAwKQoKbWQgPC0gbWQgJT4lIAogIGlubmVyX2pvaW4oZCAlPiUgZGlzdGluY3QodXJsLGFubm90YXRpb25zLG1ham9yaXR5X3RoZW1lLG1ham9yaXR5X3RoZW1lX2Fubm90YXRpb25zLG1ham9yaXR5X3RoZW1lX3Byb3BvcnRpb24sY2xhcml0eSxtYWpvcml0eV9zcGVlZF90eXBlLG1ham9yaXR5X3NwZWVkX3R5cGVfYW5ub3RhdGlvbnMsbWFqb3JpdHlfc3BlZWRfdHlwZV9wcm9wb3J0aW9uLG1ham9yaXR5X3dob2xlX2FydGljbGUpKQoKYXNzZXJ0X3RoYXQobnJvdyhtZCk9PTE2MDApCgpgYGAKCiMjIE1WIGxvYWRpbmcKCmBgYHtyfQptdmQgPC0gbGlzdC5maWxlcyhoZXJlKCJkYXRhL212X2Fubm90YXRpb25zLyIpLGZ1bGwubmFtZXM9VCkgJT4lCiAgc2V0TmFtZXMoLixzdHJfcmVwbGFjZShiYXNlbmFtZSguKSwiYW5ub3RhdG9yXyguKilcXC5jc3YkIiwiXFwxIikpICU+JSAKICBtYXBfZGZyKH5yZWFkX2NzdiguLHNob3dfY29sX3R5cGVzPUYpLC5pZD0ibmFtZSIpICU+JQogIHJlcGxhY2VfbmEobGlzdChzZW50aW1lbnQ9ImVtcHR5IikpICU+JQogIGZpbHRlcihzZW50aW1lbnQhPSJlbXB0eSIpICU+JQogIG11dGF0ZShkb2N1bWVudF9pZD1hcy5udW1lcmljKGZhY3Rvcih0ZXh0KSkpICU+JQogIGdyb3VwX2J5KG5hbWUpICU+JQogIG11dGF0ZShsZWFkX3RpbWVfY2VudGlsZT1udGlsZShsZWFkX3RpbWUsMTApLGxlYWRfdGltZV9xdWFydGlsZT1udGlsZShsZWFkX3RpbWUsNCkpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBtdXRhdGUoc3BlZWRfdHlwZT1jYXNlX3doZW4oCiAgICBsZWFkX3RpbWVfY2VudGlsZT49c2xvd19ib3VuZF9jZW50aWxlIH4gInNsb3ciLAogICAgbGVhZF90aW1lX2NlbnRpbGU8PXF1aWNrX2JvdW5kX2NlbnRpbGUgfiAicXVpY2siLAogICAgVCB+ICJpbi1iZXR3ZWVuIgogICkpICU+JSAKICBncm91cF9ieSh0ZXh0LHNlbnRpbWVudCkgJT4lIAogIG11dGF0ZShzZW50aW1lbnRfYW5ub3RhdGlvbnM9bigpKSAlPiUgCiAgZ3JvdXBfYnkodGV4dCxzcGVlZF90eXBlKSAlPiUgCiAgbXV0YXRlKHNwZWVkX3R5cGVfYW5ub3RhdGlvbnM9bigpKSAlPiUgCiAgZ3JvdXBfYnkodGV4dCkgJT4lIAogIGFycmFuZ2UoZGVzYyhzZW50aW1lbnRfYW5ub3RhdGlvbnMpKSAlPiUgCiAgbXV0YXRlKHNlbnRpbWVudF9hbm5vdGF0aW9uX3Byb3BvcnRpb249c2VudGltZW50X2Fubm90YXRpb25zL24oKSkgJT4lIAogIG11dGF0ZShtYWpvcml0eV9zZW50aW1lbnQ9Zmlyc3Qoc2VudGltZW50KSxtYWpvcml0eV9zZW50aW1lbnRfYW5ub3RhdGlvbnM9Zmlyc3Qoc2VudGltZW50X2Fubm90YXRpb25zKSxtYWpvcml0eV9zZW50aW1lbnRfcHJvcG9ydGlvbj1maXJzdChzZW50aW1lbnRfYW5ub3RhdGlvbnMpL24oKSkgJT4lCiAgYXJyYW5nZShkZXNjKHNwZWVkX3R5cGVfYW5ub3RhdGlvbnMpLHNwZWVkX3R5cGUpICU+JSAKICBtdXRhdGUoc3BlZWRfdHlwZV9hbm5vdGF0aW9uX3Byb3BvcnRpb249c3BlZWRfdHlwZV9hbm5vdGF0aW9ucy9uKCkpICU+JSAKICBtdXRhdGUobWFqb3JpdHlfc3BlZWRfdHlwZT1zdHJfZmxhdHRlbihuYS5vbWl0KHVuaXF1ZShpZl9lbHNlKHNwZWVkX3R5cGVfYW5ub3RhdGlvbnM9PW1heChzcGVlZF90eXBlX2Fubm90YXRpb25zKSxzcGVlZF90eXBlLE5BX2NoYXJhY3Rlcl8pKSksY29sbGFwc2U9InwiKSxtYWpvcml0eV9zcGVlZF90eXBlX2Fubm90YXRpb25zPWZpcnN0KHNwZWVkX3R5cGVfYW5ub3RhdGlvbnMpLG1ham9yaXR5X3NwZWVkX3R5cGVfcHJvcG9ydGlvbj1maXJzdChzcGVlZF90eXBlX2Fubm90YXRpb25zKS9uKCkpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBtdXRhdGUoCiAgICBkZWNpc2lvbl90eXBlPWlmX2Vsc2Uoc2VudGltZW50PT1tYWpvcml0eV9zZW50aW1lbnQsImFzc2VudCIsImRpc3NlbnQiKSwKICAgIGNsYXJpdHk9aWZfZWxzZShtYWpvcml0eV9zZW50aW1lbnRfcHJvcG9ydGlvbj49Y2xhcml0eV9ib3VuZCwiY2xlYXIiLCJ1bmNsZWFyIikKICApCgptdm1kIDwtIHJlYWRfY3N2KGhlcmUoImRhdGEvTVZfZGF0YV9maW5hbF9saW5rcy5jc3YiKSxjb2xfc2VsZWN0PWMoImNvbnRlbnQiLCJsaW5rIikpICU+JSAKICBtdXRhdGUoY29udGVudF9sZW5ndGg9c3RyX2xlbmd0aChjb250ZW50KSkgJT4lCiAgbXV0YXRlKGNvbnRlbnRfbGVuZ3RoX2NlbnRpbGU9bnRpbGUoY29udGVudF9sZW5ndGgsMTApLGNvbnRlbnRfbGVuZ3RoX3F1YXJ0aWxlPW50aWxlKGNvbnRlbnRfbGVuZ3RoLDQpKSAgJT4lCiAgbXV0YXRlKGxlbmd0aF90eXBlPWNhc2Vfd2hlbigKICAgIGNvbnRlbnRfbGVuZ3RoX2NlbnRpbGU8PXNob3J0X2JvdW5kX2NlbnRpbGUgfiAic2hvcnQiLAogICAgY29udGVudF9sZW5ndGhfY2VudGlsZT49bG9uZ19ib3VuZF9jZW50aWxlIH4gImxvbmciLAogICAgVCB+ICJpbi1iZXR3ZWVuIgogICkpICU+JSByZW5hbWUodGV4dD1saW5rKQoKbXZkIDwtIG12ZCAlPiUgaW5uZXJfam9pbihtdm1kKQoKbXZtZCA8LSBtdm1kICU+JSBpbm5lcl9qb2luKG12ZCAlPiUgZGlzdGluY3QodGV4dCxtYWpvcml0eV9zZW50aW1lbnQsbWFqb3JpdHlfc2VudGltZW50X2Fubm90YXRpb25zLG1ham9yaXR5X3NlbnRpbWVudF9wcm9wb3J0aW9uLGNsYXJpdHksbWFqb3JpdHlfc3BlZWRfdHlwZSxtYWpvcml0eV9zcGVlZF90eXBlX2Fubm90YXRpb25zLG1ham9yaXR5X3NwZWVkX3R5cGVfcHJvcG9ydGlvbikpCgphc3NlcnRfdGhhdChucm93KG12bWQpPT05OCkKYGBgCgojIEJpbmFyeSBhbGNvaG9sIHBvbGljeSBhbmFseXNlcwoKIyMgTWFqb3JpdHkgdGhlbWUgcHJvcG9ydGlvbnMKCmBgYHtyfQpibWQgJT4lIAogIGNvdW50KG1ham9yaXR5X3RoZW1lKSAlPiUKICBtdXRhdGUobWFqb3JpdHlfdGhlbWVfcHJvcG9ydGlvbj1uL3N1bShuKSkgJT4lCiAgYXJyYW5nZShkZXNjKG4pKSAlPiUKICBndChyb3duYW1lX2NvbD0ibWFqb3JpdHlfdGhlbWUiKSAlPiUKICBjb2xzX2xhYmVsKG49Ik4iLG1ham9yaXR5X3RoZW1lX3Byb3BvcnRpb249IlByb3BvcnRpb24iKSAlPiUKICBmbXRfcGVyY2VudChjb2x1bW5zID0gYyhtYWpvcml0eV90aGVtZV9wcm9wb3J0aW9uKSkKYGBgCgo2MC80MCBzcGxpdCBiZXR3ZWVuIG5vdCBBUCBhbmQgQVAgaXMgYSBwcmV0dHkgZXZlbiBiYXNlLgoKIyMgRGVjaXNpb24gY2xhcml0eSBieSBtYWpvcml0eSB0aGVtZQoKYGBge3J9CmJtZCAlPiUgCiAgY291bnQobWFqb3JpdHlfdGhlbWUsY2xhcml0eSkgJT4lCiAgZmlsdGVyKG1ham9yaXR5X3RoZW1lIT0iYWxjb2hvbCBwb2xpY3l8bm90IGFsY29ob2wgcG9saWN5IikgJT4lCiAgZ3JvdXBfYnkobWFqb3JpdHlfdGhlbWUpICU+JQogIG11dGF0ZShtYWpvcml0eV90aGVtZV9wcm9wb3J0aW9uPW4vc3VtKG4pKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgYXJyYW5nZShtYWpvcml0eV90aGVtZSxjbGFyaXR5KSAlPiUKICBndChncm91cG5hbWVfY29sPSJtYWpvcml0eV90aGVtZSIscm93bmFtZV9jb2w9ImNsYXJpdHkiKSAlPiUKICBjb2xzX2xhYmVsKG49Ik4iLG1ham9yaXR5X3RoZW1lX3Byb3BvcnRpb249IlByb3BvcnRpb24iKSAlPiUKICBmbXRfcGVyY2VudChjb2x1bW5zID0gYyhtYWpvcml0eV90aGVtZV9wcm9wb3J0aW9uKSkgIApgYGAKClRoZXJlIGFyZSBwcm9wb3J0aW9uYWxseSBtb3JlIGNsZWFyIGRlY2lzaW9ucyBmb3Igbm90IGFsY29ob2wgcG9saWN5IHRoYW4gdGhlcmUgYXJlIGZvciBhbGNvaG9sIHBvbGljeSAtPiBpdCBpcyBlYXNpZXIgdG8gc2F5IHRoYXQgc29tZXRoaW5nIGlzIG5vdCBBUCB0aGFuIHRvIHNheSB0aGF0IHNvbWV0aGluZyBpcyBBUC4KCiMjIFRoZW1lLCBjbGFyaXR5IGFuZCBzcGVlZCB0eXBlIGNyb3NzIGludmVzdGlnYXRpb24KCmBgYHtyfQpibWQgJT4lIAogIG11dGF0ZShtYWpvcml0eV9zcGVlZF90eXBlPWZjdF9sdW1wX24obWFqb3JpdHlfc3BlZWRfdHlwZSw0KSkgJT4lCiAgY291bnQobWFqb3JpdHlfdGhlbWUsY2xhcml0eSxtYWpvcml0eV9zcGVlZF90eXBlKSAlPiUKICBncm91cF9ieShtYWpvcml0eV90aGVtZSxjbGFyaXR5KSAlPiUKICBtdXRhdGUobWFqb3JpdHlfc3BlZWRfdHlwZV9wcm9wb3J0aW9uPW4vc3VtKG4pKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgZmlsdGVyKG1ham9yaXR5X3RoZW1lIT0iYWxjb2hvbCBwb2xpY3l8bm90IGFsY29ob2wgcG9saWN5IikgJT4lCiAgZ2dwbG90KGFlcyh4PWNsYXJpdHksZmlsbD1tYWpvcml0eV9zcGVlZF90eXBlLHk9bWFqb3JpdHlfc3BlZWRfdHlwZV9wcm9wb3J0aW9uKSkgKwogIGdlb21fY29sKCkgKwogIHRoZW1lX2hzY2lfZGlzY3JldGUoKSArIAogIGZhY2V0X3dyYXAofm1ham9yaXR5X3RoZW1lKQpgYGAKClRoZXJlIGlzIGEgc3Vic2V0IG9mIGFydGljbGVzIHdoZXJlIGl0IGlzIHF1aWNrIHRvIGRlY2lkZSB0aGF0IHRoZXkgYXJlIG5vdCBBUC4KCiMjIFRoZW1lLCBjbGFyaXR5IGFuZCB3aG9sZS9wYXJ0IGludmVzdGlnYXRpb24KCmBgYHtyfQpibWQgJT4lIAogIGNvdW50KG1ham9yaXR5X3RoZW1lLGNsYXJpdHksbWFqb3JpdHlfd2hvbGVfYXJ0aWNsZSkgJT4lCiAgZmlsdGVyKG1ham9yaXR5X3dob2xlX2FydGljbGUhPSJGQUxTRXxUUlVFIikgJT4lCiAgZ3JvdXBfYnkobWFqb3JpdHlfdGhlbWUsY2xhcml0eSkgJT4lCiAgbXV0YXRlKG1ham9yaXR5X3dob2xlX2FydGljbGVfcHJvcG9ydGlvbj1uL3N1bShuKSkgJT4lCiAgdW5ncm91cCgpICU+JQogIGZpbHRlcihtYWpvcml0eV90aGVtZSE9ImFsY29ob2wgcG9saWN5fG5vdCBhbGNvaG9sIHBvbGljeSIpICU+JQogIGdncGxvdChhZXMoeD1jbGFyaXR5LGZpbGw9bWFqb3JpdHlfd2hvbGVfYXJ0aWNsZSx5PW1ham9yaXR5X3dob2xlX2FydGljbGVfcHJvcG9ydGlvbikpICsKICBnZW9tX2NvbCgpICsKICB0aGVtZV9oc2NpX2Rpc2NyZXRlKCkgKyAKICBmYWNldF93cmFwKH5tYWpvcml0eV90aGVtZSkKYGBgCgpXaGVuIGFuIGFydGljbGUgZGVhbHMgb25seSBwYXJ0aWFsbHkgd2l0aCBhbGNvaG9sLCBpdCBpcyBtb3JlIGxpa2VseSB0byBub3QgYmUgYW4gYWxjb2hvbCBwb2xpY3kgYXJ0aWNsZS4gSXQgaXMgaGFyZGVyIHRvIGNsZWFybHkgZGVjaWRlIHdoZXRoZXIgYW4gYXJ0aWNsZSBub3QgZGVhbGluZyBjb21wbGV0ZWx5IHdpdGggYWxjb2hvbCBpcyBBUCBvciBub3QgYXMgY29tcGFyZWQgdG8gYW4gYXJ0aWNsZSB3aG9sbHkgZGVhbGluZyB3aXRoIGFsY29ob2wuCgojIyBUaGVtZSwgY2xhcml0eSwgc3BlZWQgdHlwZSBhbmQgbGVuZ3RoIGNyb3NzIGludmVzdGlnYXRpb24KCmBgYHtyfQpibWQgJT4lIAogIG11dGF0ZShtYWpvcml0eV9zcGVlZF90eXBlPWZjdF9sdW1wX24obWFqb3JpdHlfc3BlZWRfdHlwZSw0KSkgJT4lCiAgY291bnQobWFqb3JpdHlfdGhlbWUsY2xhcml0eSxtYWpvcml0eV9zcGVlZF90eXBlLGNvbnRlbnRfbGVuZ3RoX3F1YXJ0aWxlKSAlPiUKICBncm91cF9ieShtYWpvcml0eV90aGVtZSxjbGFyaXR5LGNvbnRlbnRfbGVuZ3RoX3F1YXJ0aWxlKSAlPiUKICBtdXRhdGUobWFqb3JpdHlfc3BlZWRfdHlwZV9wcm9wb3J0aW9uPW4vc3VtKG4pKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgZmlsdGVyKG1ham9yaXR5X3RoZW1lIT0iYWxjb2hvbCBwb2xpY3l8bm90IGFsY29ob2wgcG9saWN5IikgJT4lCiAgZ2dwbG90KGFlcyh4PWNsYXJpdHksZmlsbD1tYWpvcml0eV9zcGVlZF90eXBlLHk9bWFqb3JpdHlfc3BlZWRfdHlwZV9wcm9wb3J0aW9uKSkgKwogIGdlb21fY29sKCkgKwogIHRoZW1lX2hzY2lfZGlzY3JldGUoKSArIAogIGZhY2V0X2dyaWQobWFqb3JpdHlfdGhlbWV+Y29udGVudF9sZW5ndGhfcXVhcnRpbGUpCmBgYAoKVW5zdXJwcmlzaW5nbHksIGxvbmdlciBhcnRpY2xlcyB0YWtlIGxvbmdlciB0byBkZWNpZGUgdXBvbi4gU2hvcnQgbm9uLUFQIGFydGljbGVzIGFyZSBwYXJ0aWN1bGFybHkgZWFzeSB0byBjYXRlZ29yaXplIGNsZWFybHksIGJ1dCB0aGVyZSBpcyBhbHNvIHRoZSBwb3RlbnRpYWwgZm9yIGVycm9yIGhlcmUsIGFzIGV2aWRlbmNlZCBieSB0aGUgaGlnaCBudW1iZXIgb2YgInVuY2xlYXIiIHF1aWNrIHNlbGVjdGlvbnMgaW4gdGhlIHNob3J0IGFydGljbGVzLgoKIyBBbGNvaG9sIHBvbGljeSBhbm5vdGF0b3IgYW5hbHlzZXMKCiMjIFRpbWUgdG8gZGVjaWRlIGJ5IGFubm90YXRvcgoKYGBge3J9CmRsICU+JSBnZ3Bsb3QoYWVzKHg9bmFtZSx5PWxlYWRfdGltZS82MCxjb2xvcj10aGVtZSkpICsgCiAgZ2VvbV9xdWFzaXJhbmRvbShzaXplPTAuNSxzaG93LmxlZ2VuZD1GKSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW09YygwLDUpKSArCiAgdGhlbWVfaHNjaV9kaXNjcmV0ZSgpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgwLDUsYnk9MSkpICsKICB4bGFiKCJBbm5vdGF0b3IiKSArCiAgeWxhYigiVGltZSB0byBkZWNpZGUgKG1pbnV0ZXMpIikKYGBgCgpWZXJ5IGNsZWFybHkgZGlmZmVyZW50IHRhc2sgdGltZSBwcm9maWxlcyBiZXR3ZWVuIGFubm90YXRvcnMuCgojIyBBZ3JlZW1lbnQgbWF0cml4IGJldHdlZW4gYW5ub3RhdG9ycwoKYGBge3J9CnAgPC0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdChhY2N1cmFjeT0xKQpiZCAlPiUgCiAgZnVsbF9qb2luKGJkLGJ5PWMoInRleHQiKSkgJT4lCiAgbXV0YXRlKGFncmVlPXRoZW1lLng9PXRoZW1lLnkpICU+JQogIGdyb3VwX2J5KG5hbWUueCxuYW1lLnkpICU+JQogIHN1bW1hcml6ZShhZ3JlZT1zdW0oYWdyZWUpLHBhZ3JlZT1zdW0oYWdyZWUpL24oKSwuZ3JvdXBzPSJkcm9wIikgJT4lCiAgZ2dwbG90KGFlcyh4PW5hbWUueCx5PW5hbWUueSxmaWxsPXBhZ3JlZSkpICsKICBnZW9tX3Jhc3RlcigpICsKICB0aGVtZV9oc2NpKCkgKwogIHNjYWxlX2ZpbGxfdmlyaWRpc19jKGxhYmVscz1zY2FsZXM6OnBlcmNlbnRfZm9ybWF0KGFjY3VyYWN5PTEpKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1wKHBhZ3JlZSkpKSArCiAgbGFicyhmaWxsPSJBZ3JlZW1lbnQiKSArCiAgeGxhYigiQW5ub3RhdG9yIDEiKSArCiAgeWxhYigiQW5ub3RhdG9yIDIiKQpgYGAKCkthaXNhIHN0YW5kcyBvdXQgYXMgYW4gYW5ub3RhdG9yIHdpdGggbG93ZXIgYWdyZWVtZW50IHRvIHRoZSBtYWpvcml0eSBvZiBvdGhlciBhbm5vdGF0b3JzLCBleGNlcHQgaW50ZXJlc3RpbmdseSBTb25qYSBhbmQgU3VzYW5uYS4KCiMjIFByb3BvcnRpb24gb2YgYW5ub3RhdG9ycyBpbmRpY2F0aW5nIHRoZSBtYWpvcml0eSB2aWV3cG9pbnQKCmBgYHtyfQpibWQgJT4lIAogIGdncGxvdChhZXMoeD1tYWpvcml0eV90aGVtZV9wcm9wb3J0aW9uKSkgKwogIGdlb21fYmFyKCkgKyAKICB0aGVtZV9oc2NpX2Rpc2NyZXRlKCkgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHM9c2NhbGVzOjpwZXJjZW50X2Zvcm1hdChhY2N1cmFjeT0xKSkgKwogIHhsYWIoIlByb3BvcnRpb24gb2YgYW5ub3RhdG9ycyBpbmRpY2F0aW5nIHRoZSBtYWpvcml0eSB2aWV3cG9pbnQiKSArCiAgeWxhYigiTnVtYmVyIG9mIGFydGljbGVzIikgKwogIGZhY2V0X3dyYXAofmFubm90YXRpb25zLHNjYWxlcz0iZnJlZSIpCmBgYAoKIyMgVGltZSB0YWtlbiB0byBhbm5vdGF0ZSBieSBhbm5vdGF0b3IgYW5kIGNsYXJpdHkKCmBgYHtyLGZpZy53aWR0aD0xMH0KYmQgJT4lCiAgZ2dwbG90KGFlcyh4PW5hbWUseT1sZWFkX3RpbWUvNjAsY29sb3I9Y2xhcml0eSkpICsgCiAgZ2VvbV9ib3hwbG90KHNpemU9MC41KSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW09YygwLDUpKSArCiAgdGhlbWVfaHNjaV9kaXNjcmV0ZSgpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgwLDUsYnk9MSkpICsKICB4bGFiKCJBbm5vdGF0b3IiKSArCiAgbGFicyhjb2xvcj0iQ2xhcml0eSIpICsKICB5bGFiKCJUaW1lIHRvIGRlY2lkZSAobWludXRlcykiKSArIAogIGZhY2V0X2dyaWQoYW5ub3RhdGlvbnN+dGhlbWUsc2NhbGVzPSJmcmVlIikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0iYm90dG9tIikKICAKYGBgCgpBbG1vc3QgYWxsIGFubm90YXRvcnMgYXJlIGxpa2VseSB0byBzcGVuZCBtb3JlIHRpbWUgb24gInByb2JsZW1hdGljIiBhcnRpY2xlcywgaGVyZSBwcm94aWVkIGJ5IHRoZWlyIGNsYXJpdHkoPXRoZSBhbW91bnQgb2YgZ2VuZXJhbCBhZ3JlZW1lbnQgd3J0IHRoZW0pLiAtPiB0aGUgYW5ub3RhdG9ycyBhcmUgZG9pbmcgYSBnb29kIGpvYiwgYW5kIG1vc3QgZXJyb3JzIHNob3VsZCBub3QgYmUgY2F1c2VkIGJ5IGNhcmVsZXNzbmVzcyBidXQgYnkgYWN0dWFsIGRlY2lzaW9uIGRpZmZlcmVuY2VzIGFuZCBhbWJpZ3VpdGllcyBpbiBndWlkZWxpbmVzLgoKIyMgQW5ub3RhdGlvbiB0aW1lIGRpZmZlcmVuY2UgYmFzZWQgb24gYWdyZWVtZW50IGJldHdlZW4gYW5ub3RhdG9yIHBhaXJzCgpgYGB7cn0KYmQgJT4lIAogIGZ1bGxfam9pbihiZCxieT1jKCJ0ZXh0IikpICU+JQogIG11dGF0ZShhZ3JlZT10aGVtZS54PT10aGVtZS55LHRkaWZmPWFicyhsZWFkX3RpbWVfY2VudGlsZS54LWxlYWRfdGltZV9jZW50aWxlLnkpKSAlPiUKICBnZ3Bsb3QoYWVzKHg9YWdyZWUseT10ZGlmZikpICsKICBnZW9tX2JveHBsb3QoKSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW09YygwLDUpKSArCiAgdGhlbWVfaHNjaV9kaXNjcmV0ZSgpICsKICB4bGFiKCJBZ3JlZW1lbnQgYmV0d2VlbiBhbm5vdGF0b3JzIikgKwogIHlsYWIoIkRpZmZlcmVuY2UgaW4gYW5ub3RhdGlvbiB0aW1lIGNlbnRpbGUiKQpgYGAKCkF0IHRoZSBzYW1lIHRpbWUsIHRoZXJlIGlzIGFsc28gY2xlYXJseSBhbiBlZmZlY3QgdmlzaWJsZSB3aGVyZSBkaWZmZXJlbmNlIGluIGFubm90YXRpb24gdGltZSBleHBsYWlucyBhZ3JlZW1lbnQsIHNvIHRoZXJlIGlzIGFsc28gYW4gYXR0ZW50aXZlbmVzcyBjb21wb25lbnQgdG8gdGhlIGRpc2FncmVlbWVudHMuCgojIyBIZXVyaXN0aWNzIGZvciB0ZXN0aW5nIHdoZXRoZXIgb3V0bGllciBhbm5vdGF0b3Igc2hvdWxkIGJlIHJlbW92ZWQKCmBgYHtyfQprcmlwcC5hbHBoYShiZCAlPiUgCiAgICAgICAgICAgICAgcGl2b3Rfd2lkZXIoaWRfY29scz1uYW1lLG5hbWVzX2Zyb209ZG9jdW1lbnRfaWQsdmFsdWVzX2Zyb209dGhlbWUpICU+JQogICAgICAgICAgICAgIHNlbGVjdCgtbmFtZSkgJT4lIAogICAgICAgICAgICAgIGFzLm1hdHJpeCwKICAgICAgICAgICAgbWV0aG9kPSJub21pbmFsIikKa3JpcHAuYWxwaGEoYmQgJT4lIAogICAgICAgICAgICAgIGZpbHRlcihuYW1lIT0iS2Fpc2EiKSAlPiUKICAgICAgICAgICAgICBwaXZvdF93aWRlcihpZF9jb2xzPW5hbWUsbmFtZXNfZnJvbT1kb2N1bWVudF9pZCx2YWx1ZXNfZnJvbT10aGVtZSkgJT4lCiAgICAgICAgICAgICAgc2VsZWN0KC1uYW1lKSAlPiUgCiAgICAgICAgICAgICAgYXMubWF0cml4LAogICAgICAgICAgICBtZXRob2Q9Im5vbWluYWwiKQpgYGAKCiMgTVYgYW5hbHlzZXMKCiMjIE1ham9yaXR5IHNlbnRpbWVudCBwcm9wb3J0aW9ucwoKYGBge3J9Cm12bWQgJT4lIAogIGNvdW50KG1ham9yaXR5X3NlbnRpbWVudCkgJT4lCiAgbXV0YXRlKG1ham9yaXR5X3NlbnRpbWVudF9wcm9wb3J0aW9uPW4vc3VtKG4pKSAlPiUKICBhcnJhbmdlKGRlc2MobikpICU+JQogIGd0KHJvd25hbWVfY29sPSJtYWpvcml0eV9zZW50aW1lbnQiKSAlPiUKICBjb2xzX2xhYmVsKG49Ik4iLG1ham9yaXR5X3NlbnRpbWVudF9wcm9wb3J0aW9uPSJQcm9wb3J0aW9uIikgJT4lCiAgZm10X3BlcmNlbnQoY29sdW1ucyA9IGMobWFqb3JpdHlfc2VudGltZW50X3Byb3BvcnRpb24pKQpgYGAKCjcwJSBvZiB0aGlzIGRhdGEgaXMgY29weWluZyBmcm9tIG1haW5zdHJlYW0gbWVkaWEuIDI0IGFydGljbGVzIGlzIHByb2JhYmx5IGVub3VnaCB0byBhbmFseXNlIHRoZSBkZXZlbG9waW5nIG9mIG9uZSdzIG93biBuYXJyYXRpdmUsIGJ1dCB0aGVyZSBhcmUgcmVhbGx5IHRvbyBmZXcgImNyaXRpY2lzbSBvZiBtYWluc3RyZWFtIG1lZGlhIiBhcnRpY2xlcyB0byBkcmF3IGNvbmNsdXNpb25zIGZyb20uCgojIyBEZWNpc2lvbiBjbGFyaXR5IGJ5IG1ham9yaXR5IHNlbnRpbWVudAoKYGBge3J9Cm12bWQgJT4lIAogIGNvdW50KG1ham9yaXR5X3NlbnRpbWVudCxjbGFyaXR5KSAlPiUKICBncm91cF9ieShtYWpvcml0eV9zZW50aW1lbnQpICU+JQogIG11dGF0ZShtYWpvcml0eV9zZW50aW1lbnRfcHJvcG9ydGlvbj1uL3N1bShuKSkgJT4lCiAgdW5ncm91cCgpICU+JQogIGFycmFuZ2UobWFqb3JpdHlfc2VudGltZW50LGNsYXJpdHkpICU+JQogIGd0KGdyb3VwbmFtZV9jb2w9Im1ham9yaXR5X3NlbnRpbWVudCIscm93bmFtZV9jb2w9ImNsYXJpdHkiKSAlPiUKICBjb2xzX2xhYmVsKG49Ik4iLG1ham9yaXR5X3NlbnRpbWVudF9wcm9wb3J0aW9uPSJQcm9wb3J0aW9uIikgJT4lCiAgZm10X3BlcmNlbnQoY29sdW1ucyA9IGMobWFqb3JpdHlfc2VudGltZW50X3Byb3BvcnRpb24pKSAgICAKYGBgCgpJZGVudGlmeWluZyB0aGUgY29weWluZyBvZiBtYXRlcmlhbCBmcm9tIG1haW5zdHJlYW0gbWVkaWEgc2VlbXMgcXVpdGUgY2xlYXIsIGFzIG9wcG9zZWQgdG8gd2hldGhlciBzb21ldGhpbmcgaXMgYnVpbGRpbmcgdGhlaXIgb3duIG5hcnJhdGl2ZS4KClRoZSBjb25mdXNpb24gbWF0cml4IGJldHdlZW4gYW5ub3RhdGlvbiBwYWlycyB0ZWxscyBhIGJpdCBtb3JlOgpgYGB7cn0KbXZkICU+JSAKICBmdWxsX2pvaW4obXZkLGJ5PWMoInRleHQiKSkgJT4lCiAgZmlsdGVyKG5hbWUueCE9bmFtZS55KSAlPiUKICBjb3VudChzZW50aW1lbnQueCxzZW50aW1lbnQueSkgJT4lCiAgbXV0YXRlKHNlbnRpbWVudC54PXN0cl90cnVuYyhzZW50aW1lbnQueCwxMCkpICU+JQogIGdncGxvdChhZXMoeD1zZW50aW1lbnQueCx5PXNlbnRpbWVudC55LGZpbGw9bikpICsKICBnZW9tX3Jhc3RlcigpICsKICB0aGVtZV9oc2NpX2NvbnRpbnVvdXMoKSArCiAgZ2VvbV9sYWJlbChhZXMobGFiZWw9biksZmlsbD0id2hpdGUiKSArCiAgbGFicyhmaWxsPSJBbm5vdGF0aW9uIHBhaXJzIikgKwogIHhsYWIoIkFubm90YXRpb24gMiIpICsKICB5bGFiKCJBbm5vdGF0aW9uIDEiKSArIAogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdD0xKSkKYGBgCgpIZXJlLCBpdCBzZWVtcyB0aGF0IGl0IGlzIGhhcmQgdG8gZHJhdyBib3VuZGFyaWVzIGJldHdlZW4gdGhlIGRldmVsb3BtZW50IG9mIG9uZSdzIG93biBuYXJyYXRpdmUgYW5kIGJvdGggam91cm5hbGlzdGljIGNyaXRpcXVlIGFzIHdlbGwgYXMgY29weWluZy4gCgojIyBTZW50aW1lbnQsIGNsYXJpdHkgYW5kIHNwZWVkIHR5cGUgY3Jvc3MgaW52ZXN0aWdhdGlvbgoKYGBge3J9Cm12bWQgJT4lIAogIG11dGF0ZShtYWpvcml0eV9zcGVlZF90eXBlPWZjdF9sdW1wX24obWFqb3JpdHlfc3BlZWRfdHlwZSw0KSkgJT4lCiAgY291bnQobWFqb3JpdHlfc2VudGltZW50LGNsYXJpdHksbWFqb3JpdHlfc3BlZWRfdHlwZSkgJT4lCiAgZ3JvdXBfYnkobWFqb3JpdHlfc2VudGltZW50LGNsYXJpdHkpICU+JQogIG11dGF0ZShtYWpvcml0eV9zcGVlZF90eXBlX3Byb3BvcnRpb249bi9zdW0obikpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBnZ3Bsb3QoYWVzKHg9Y2xhcml0eSxmaWxsPW1ham9yaXR5X3NwZWVkX3R5cGUseT1tYWpvcml0eV9zcGVlZF90eXBlX3Byb3BvcnRpb24pKSArCiAgZ2VvbV9jb2woKSArCiAgZ2VvbV9sYWJlbChhZXMobGFiZWw9bikscG9zaXRpb249cG9zaXRpb25fc3RhY2sodmp1c3Q9MC41KSkgKwogIHRoZW1lX2hzY2lfZGlzY3JldGUoKSArIAogIGZhY2V0X3dyYXAofm1ham9yaXR5X3NlbnRpbWVudCkKYGBgCgpBZ2FpbiwgdG9vIGZldyBjcml0aXF1ZSBhcnRpY2xlcyB0byBkcmF3IGNvbmNsdXNpb25zIGZyb20uIE90aGVyd2lzZSwgc2VlbXMgdGhhdCB0aGUgb25seSBjbGVhciBjYXRlZ29yeSBpZGVudGlmaWVkIHF1aWNrbHkgaXMgYSBzdWJzZXQgb2YgYXJ0aWNsZXMgY29weWluZyBjb250ZW50IGZyb20gbWFpbnN0cmVhbSBtZWRpYS4gRXZlbiBmb3IgY2xlYXIgY2FzZXMgb2YgYnVpbGRpbmcgb25lJ3Mgb3duIG5hcnJhdGl2ZSwgZGVjaXNpb25zIHRha2UgbG9uZyB0byByZWFjaC4KCiMjIFRoZW1lLCBjbGFyaXR5LCBzcGVlZCB0eXBlIGFuZCBsZW5ndGggY3Jvc3MgaW52ZXN0aWdhdGlvbgoKYGBge3J9Cm12bWQgJT4lIAogIG11dGF0ZShtYWpvcml0eV9zcGVlZF90eXBlPWZjdF9sdW1wX24obWFqb3JpdHlfc3BlZWRfdHlwZSw0KSkgJT4lCiAgY291bnQobWFqb3JpdHlfc2VudGltZW50LGNsYXJpdHksbWFqb3JpdHlfc3BlZWRfdHlwZSxjb250ZW50X2xlbmd0aF9xdWFydGlsZSkgJT4lCiAgZ3JvdXBfYnkobWFqb3JpdHlfc2VudGltZW50LGNsYXJpdHksY29udGVudF9sZW5ndGhfcXVhcnRpbGUpICU+JQogIG11dGF0ZShtYWpvcml0eV9zcGVlZF90eXBlX3Byb3BvcnRpb249bi9zdW0obikpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBnZ3Bsb3QoYWVzKHg9Y2xhcml0eSxmaWxsPW1ham9yaXR5X3NwZWVkX3R5cGUseT1tYWpvcml0eV9zcGVlZF90eXBlX3Byb3BvcnRpb24pKSArCiAgZ2VvbV9jb2woKSArCiAgZ2VvbV9sYWJlbChhZXMobGFiZWw9bikscG9zaXRpb249cG9zaXRpb25fc3RhY2sodmp1c3Q9MC41KSkgKwogIHRoZW1lX2hzY2lfZGlzY3JldGUoKSArIAogIGZhY2V0X2dyaWQobWFqb3JpdHlfc2VudGltZW50fmNvbnRlbnRfbGVuZ3RoX3F1YXJ0aWxlKQpgYGAKCkhlcmUgZXZlbiBtb3JlIGNhdGVnb3JpZXMgbGFjayBkYXRhIHRvIGJhc2UgZGVjaXNpb25zIG9uLiBXaGF0IHdlIGNhbiBzZWUgaXMgdGhhdCBjb3B5aW5nIGNhbiBiZSByZWxhdGl2ZWx5IHF1aWNrbHkgaWRlbnRpZmllZCBpbiBhbGwgbGVuZ3RoIGNhdGVnb3JpZXMsIGFuZCB0aGF0IG93biBuYXJyYXRpdmUgYXJ0aWNsZXMgYXJlIG9mdGVuIGxvbmcgYW5kIHNsb3cgdG8gcGFyc2UuCgojIE1WIGFubm90YXRvciBhbmFseXNlcwoKYGBge3J9Cm12ZCAlPiUgZ2dwbG90KGFlcyh4PW5hbWUseT1sZWFkX3RpbWUvNjAsY29sb3I9c2VudGltZW50KSkgKyAKICBnZW9tX3F1YXNpcmFuZG9tKHNpemU9MC41LHNob3cubGVnZW5kPUYpICsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKDAsNSkpICsKICB0aGVtZV9oc2NpX2Rpc2NyZXRlKCkgKwogIHNjYWxlX3lfY29udGludW91cyhicmVha3M9c2VxKDAsNSxieT0xKSkgKwogIHhsYWIoIkFubm90YXRvciIpICsKICB5bGFiKCJUaW1lIHRvIGRlY2lkZSAobWludXRlcykiKQpgYGAKCkFnYWluLCB3ZSBoYXZlIHR3byBkaWZmZXJlbnQgYW5ub3RhdG9yIHByb2ZpbGVzIGV2aWRlbnQuCgojIyBBZ3JlZW1lbnQgbWF0cml4IGJldHdlZW4gYW5ub3RhdG9ycwoKTm8gY2xlYXIgb3V0bGllciBhbm5vdGF0b3JzIGFwcGVhciBpbiB0aGlzIHRhc2s6CgpgYGB7cn0KcCA8LSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KGFjY3VyYWN5PTEpCm12ZCAlPiUgCiAgZnVsbF9qb2luKG12ZCxieT1jKCJ0ZXh0IikpICU+JQogIG11dGF0ZShhZ3JlZT1zZW50aW1lbnQueD09c2VudGltZW50LnkpICU+JQogIGdyb3VwX2J5KG5hbWUueCxuYW1lLnkpICU+JQogIHN1bW1hcml6ZShhZ3JlZT1zdW0oYWdyZWUpLHBhZ3JlZT1zdW0oYWdyZWUpL24oKSwuZ3JvdXBzPSJkcm9wIikgJT4lCiAgZ2dwbG90KGFlcyh4PW5hbWUueCx5PW5hbWUueSxmaWxsPXBhZ3JlZSkpICsKICBnZW9tX3Jhc3RlcigpICsKICB0aGVtZV9oc2NpKCkgKwogIHNjYWxlX2ZpbGxfdmlyaWRpc19jKGxhYmVscz1zY2FsZXM6OnBlcmNlbnRfZm9ybWF0KGFjY3VyYWN5PTEpKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1wKHBhZ3JlZSkpKSArCiAgbGFicyhmaWxsPSJBZ3JlZW1lbnQiKSArCiAgeGxhYigiQW5ub3RhdG9yIDEiKSArCiAgeWxhYigiQW5ub3RhdG9yIDIiKQpgYGAKCiMjIFByb3BvcnRpb24gb2YgYW5ub3RhdG9ycyBpbmRpY2F0aW5nIHRoZSBtYWpvcml0eSB2aWV3cG9pbnQKCmBgYHtyfQptdm1kICU+JSAKICBnZ3Bsb3QoYWVzKHg9bWFqb3JpdHlfc2VudGltZW50X3Byb3BvcnRpb24pKSArCiAgZ2VvbV9iYXIoKSArIAogIHRoZW1lX2hzY2lfZGlzY3JldGUoKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscz1zY2FsZXM6OnBlcmNlbnRfZm9ybWF0KGFjY3VyYWN5PTEpKSArCiAgeGxhYigiUHJvcG9ydGlvbiBvZiBhbm5vdGF0b3JzIGluZGljYXRpbmcgdGhlIG1ham9yaXR5IHZpZXdwb2ludCIpICsKICB5bGFiKCJOdW1iZXIgb2YgYXJ0aWNsZXMiKSAKYGBgCgojIyBUaW1lIHRha2VuIHRvIGFubm90YXRlIGJ5IGFubm90YXRvciBhbmQgd2hldGhlciBhbGwgYW5ub3RhdG9ycyBhZ3JlZQoKYGBge3IsZmlnLndpZHRoPTEwfQptdmQgJT4lCiAgZ2dwbG90KGFlcyh4PW5hbWUseT1sZWFkX3RpbWUvNjAsY29sb3I9Y2xhcml0eSkpICsgCiAgZ2VvbV9ib3hwbG90KHNpemU9MC41KSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW09YygwLDUpKSArCiAgdGhlbWVfaHNjaV9kaXNjcmV0ZSgpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgwLDUsYnk9MSkpICsKICB4bGFiKCJBbm5vdGF0b3IiKSArCiAgbGFicyhjb2xvcj0iQ2xhcml0eSIpICsKICB5bGFiKCJUaW1lIHRvIGRlY2lkZSAobWludXRlcykiKSArIAogIGZhY2V0X3dyYXAofnNlbnRpbWVudCxzY2FsZXM9ImZyZWUiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJib3R0b20iKQogIApgYGAKSGVyZSBhZ2FpbiwgYW5ub3RhdG9ycyBhcmUgbGlrZWx5IHRvIHNwZW5kIG1vcmUgdGltZSBvbiAicHJvYmxlbWF0aWMiIGFydGljbGVzLCBoZXJlIHByb3hpZWQgYnkgdGhlaXIgY2xhcml0eSg9dGhlIGFtb3VudCBvZiBnZW5lcmFsIGFncmVlbWVudCB3cnQgdGhlbSkuIEFuIGludGVyZXN0aW5nIGV4Y2VwdGlvbiBpcyB0aGUgb3duIG5hcnJhdGl2ZSBjYXRlZ29yeSwgd2hlcmUgdW5jbGVhciBkZWNpc2lvbnMgbWF5IGhhdmUgYmVlbiBkdWUgdG8gbWFraW5nIHRoZW0gaW4gaGFzdGUuCgojIyBBbm5vdGF0aW9uIHRpbWUgZGlmZmVyZW5jZSBiYXNlZCBvbiBhZ3JlZW1lbnQgYmV0d2VlbiBhbm5vdGF0b3IgcGFpcnMKCmBgYHtyfQptdmQgJT4lIAogIGZ1bGxfam9pbihtdmQsYnk9YygidGV4dCIpKSAlPiUKICBtdXRhdGUoYWdyZWU9c2VudGltZW50Lng9PXNlbnRpbWVudC55LHRkaWZmPWFicyhsZWFkX3RpbWVfY2VudGlsZS54LWxlYWRfdGltZV9jZW50aWxlLnkpKSAlPiUKICBnZ3Bsb3QoYWVzKHg9YWdyZWUseT10ZGlmZikpICsKICBnZW9tX2JveHBsb3QoKSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW09YygwLDUpKSArCiAgdGhlbWVfaHNjaV9kaXNjcmV0ZSgpICsKICB4bGFiKCJBZ3JlZW1lbnQgYmV0d2VlbiBhbm5vdGF0b3JzIikgKwogIHlsYWIoIkRpZmZlcmVuY2UgaW4gYW5ub3RhdGlvbiBzcGVlZCBjZW50aWxlcyIpCmBgYAoKQWdhaW4sIHRoZXJlIGlzIGFsc28gY2xlYXJseSBhbiBlZmZlY3QgdmlzaWJsZSB3aGVyZSBkaWZmZXJlbmNlIGluIGFubm90YXRpb24gdGltZSBleHBsYWlucyBhZ3JlZW1lbnQuCgpgYGB7cn0KbXZkICU+JSAKICBmdWxsX2pvaW4obXZkLGJ5PWMoInRleHQiLCJtYWpvcml0eV9zZW50aW1lbnQiKSkgJT4lCiAgbXV0YXRlKGFncmVlPXNlbnRpbWVudC54PT1zZW50aW1lbnQueSx0ZGlmZj1hYnMobGVhZF90aW1lX2NlbnRpbGUueC1sZWFkX3RpbWVfY2VudGlsZS55KSkgJT4lCiAgZ2dwbG90KGFlcyh4PWFncmVlLHk9dGRpZmYsY29sb3I9bWFqb3JpdHlfc2VudGltZW50KSkgKwogIGdlb21fYm94cGxvdCgpICsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKDAsNSkpICsKICB0aGVtZV9oc2NpX2Rpc2NyZXRlKCkgKwogIHhsYWIoIkFncmVlbWVudCBiZXR3ZWVuIGFubm90YXRvcnMiKSArCiAgeWxhYigiRGlmZmVyZW5jZSBpbiBhbm5vdGF0aW9uIHNwZWVkIGNlbnRpbGVzIikKYGBgCgpDYXRlZ29yaWNhbCBkYXRhIGlzIGhlcmUgYSBiaXQgc3BhcnNlIHRvIGRyYXcgY29uY2x1c2lvbnMsIGJ1dCBtYXkgZnVydGhlciBwb2ludCB0byBhdHRlbnRpdmVuZXNzIGRpZmZlcmVuY2VzIGluIGV4cGxhaW5pbmcgZGlzYWdyZWVtZW50IG9uIHRoZSBib3VuZGFyaWVzIG9mIHRoZSBvd24gbmFycmF0aXZlIGNhdGVnb3J5LiBTaW1pbGFybHksIGJlY2F1c2UgdGhlIGNyaXRpcXVlIGNhdGVnb3J5IHJlcXVpcmVzIHBpY2tpbmcgdXAgb24gaW5kaXZpZHVhbCBzZW50ZW5jZSBxdWVzLCB0aW1lIHRha2VuIG1heSBleHBsYWluIHNvbWUgb2YgdGhlIGRpZmZlcmVuY2UgZm9yIHRoYXQgY2F0ZWdvcnku