Antibiotics and food in the American press: A text mining study.
Antoine Bridier-Nahmias\(\dagger\), Estera Badau\(\dagger\), Pi Nyvall Collen ,Antoine Andremont, Jocelyne Arquembourg

\(\dagger\): These authors contributed equally to this work

Corpus constitution

The articles have been searched upon the Factiva database, based on key words and expressions used in conjunction. Terms and expressions researched were the following:

antibiotic resistance, antimicrobial resistance, 
antibiotic free or antibiotic-free, antibiotics and food, 
antibiotics and farming, antibiotics and resistant, antibiotics and salmonella, 
salmonella and resistant, salmonella and outbreak, 
antibiotics and campylobacter and resistant, antibiotics and routine, 
antibiotics and routinely, antibiotics and One Health;
(antibio* near3 food) or (antibio* near3 farm*) or (antibio* near3 salmonell*) 
or (antibio* near3 campylobacter*) or (antibio* near3 animal*) or 
(antibio* near3 feed)

Data loading

The corpus is consituted by articles saved in independent pdf files.

Data Processing

Information scrapping and cleaning

We will now fuse the articles and their respective informations in a dataframe, and then we will remove the headers and footers. This operation is noisy because of the inconsistency in the footer formatting.

We are ready to unite everything in one data.frame, beforehand we’ll just add a unique id for each article.

The tokenzation can now take place. We can use multiple ngrams size, we will start with 1grams first i.e: words.

Counting and more

Let’s first extract some figures about the whole corpus

Publication chronology

Parsed with column specification:
cols(
  date = col_date(format = ""),
  full_event = col_character(),
  event_label = col_character()
)
longer object length is not a multiple of shorter object length

Counts and TF-IDF

We will compute the following:

  • corpus_length: the total number of documents in the corpus
  • article_length: the total number of words in each article
  • n_article: the count of each word in each article
  • word_in_n: for each word, how many articles contain it
  • n_tot: total count of each word
  • n_journal: total count of each word by journal
suppressMessages(
  my_stop_words <-
    read_table(
      file = "../data/my_stop_words.txt",
      col_names = "stop_word"
    )
)
corpus_tfidf_full <-
  corpus_1_grams_unfiltered %>%
  # filter(id %in% c(30:100,400:500) ) %>%
  # filter(id %in% c(517) ) %>%
  
  # clean dataset
  mutate(word = str_to_lower(string = word)) %>% 
  mutate(word = str_replace_all(string = word, pattern = "([[:alpha:]]*)\\.([[:alpha:]]*)", replacement = "\\1\\2")) %>%
  mutate(word = str_replace_all(string = word, pattern = "'s$", replacement = "")) %>%
  # mutate(word = str_replace_all(string = word, pattern = "[^a-z]", replacement = "")) %>%
  filter(!(str_detect(string = word, pattern = "washpostcom"))) %>% # Tokenization splits on @ !!!!!!!
  filter(word != "") %>% 
  filter(nchar(word) > 1) %>% 
  filter(!str_detect(string = word, pattern = "^[0-9]|[[:punct:]]+$")) %>%
  
  # lemmatization (better than stemming) and last filtering
  mutate(stem = stem_words(word)) %>%
  filter(!word %in% my_stop_words$stop_word) %>% 
  
  # total number of articles
  mutate(corpus_length = length(unique(id) )) %>%  
  
  # total word in article
  group_by(id) %>%
  mutate(article_length = n()) %>%
  
  # count of each word by article
  group_by(id, stem) %>% 
  mutate(n_article = n()) %>% 
  
  # word count
  group_by(stem) %>% 
  mutate(n_total = n()) %>% 
  group_by(stem, journal) %>% 
  mutate(n_journal = n()) %>% 
  ungroup() %>%
  # compute tf-idf
  
  mutate(tf = n_article / article_length) %>% # text frequency
  group_by(stem) %>% 
  mutate(word_in_n = length(unique(id))) %>% 
  mutate(idf = log(corpus_length / word_in_n) ) %>% # inverse document frequency
  mutate(tf_idf = tf * idf) %>% 
  ungroup() %>% 
  
  # Choose a representant for each stem, the most common term could be the best
  group_by(stem) %>%
  mutate(ori_word = word) %>%
  group_by(ori_word) %>% 
  mutate(n_ori = n()) %>%
  arrange(desc(n_ori)) %>%
  group_by(stem) %>% 
  mutate(word = word[1]) %>%
  select(-n_ori) %>% 
  ungroup()
# write_delim(x = corpus_tfidf_full, path = "../output/corpus_tfidf_full.tsv", delim = "\t", col_names = TRUE)
# corpus_tfidf_full <- 
#   read_delim(file = "../output/corpus_tfidf_full.tsv", delim = "\t", col_names = TRUE)
corpus_tfidf <-
  corpus_tfidf_full %>% 
  # reduce
  group_by(id, word) %>%
  slice(1) %>% 
  ungroup() %>%
  
  # filter out  words with tf-idf == 0
  filter(tf_idf > 0) %>% 
  identity()
corpus_tfidf %>% 
  filter(!(word %in% stop_words$word)) %>%
  filter(n_total >= 50) %>% 
  arrange(desc(n_total)) %>% 
  group_by(word, journal) %>% 
  slice(1) %>%
  select(word, journal, pub_date, n_total, n_journal) %>%
  arrange(desc(n_total)) %>% 
  datatable(caption = "Words appearing at least 50 times", filter = "top") %>% 
  identity()

Word count evolution through time

Analyzes

GLM

What are the term that could discriminate between an article from the WP and the NYT?

   user  system elapsed 
 13.482   0.293  13.802 

Contextual analysis

Syntagma curation

In the next section, we will concentrate on counting manually curated terms or expressions (syntagmas) They will be presented in a named list containing all the terms considered equivalent. We will then extract all the sentences in which they occur and analyse their context (in general and across time).

$antibiotic_resistance
[1] "antibiotic resistance"     "antibiotic-resistance"     "resistant to antibiotics"  "resistance to antibiotics"

$antibiotic_free
[1] "antibiotic free"     "antibiotic-free"     "antibioticsfree"     "free of antibiotics"

$routine_use
[1] "routine use"    "routinely used"

$judicious_use
[1] "judicious use"

$responsible_use
[1] "responsible use"

$prudent_use
[1] "prudent use"

$indiscriminate_use
[1] "indiscriminate use"

$food_borne
[1] "food borne" "food-borne"

The first step is to divide the corpus in sentences.
Remark unnest_tokens(token = "sentences") clearly fails whenever it encounters an abbreviation containing a dot.

corpus_sentences <-
  corpus_txt %>% 
  # Each article has to be re-concatenated
  group_by(id) %>% 
  # filter(id %in% 1:5) %>%
  mutate(article = paste(text, collapse = " ")) %>%
  select(-text) %>% 
  distinct() %>%
  ungroup() %>% 
# Could/should be done in one pass with a list of terms!
  mutate(article = str_replace_all(string = article, pattern = regex(pattern = "dr\\.", ignore_case = TRUE), replacement = "dr")) %>%
  mutate(article = str_replace_all(string = article, pattern = regex(pattern = "prof\\.", ignore_case = TRUE), replacement = "prof")) %>%
  mutate(article = str_replace_all(string = article, pattern = regex(pattern = "mr\\.", ignore_case = TRUE), replacement = "mr")) %>%
  mutate(article = str_replace_all(string = article, pattern = regex(pattern = "ms\\.", ignore_case = TRUE), replacement = "ms")) %>%
  mutate(article = str_replace_all(string = article, pattern = regex(pattern = "mrs\\.", ignore_case = TRUE), replacement = "mrs")) %>%
  mutate(article = str_replace_all(string = article, pattern = regex(pattern = "st\\.", ignore_case = TRUE), replacement = "st")) %>%
  mutate(article = str_replace_all(string = article, pattern = regex(pattern = "rep\\.", ignore_case = TRUE), replacement = "rep")) %>%
  mutate(article = str_replace_all(string = article, pattern = regex(pattern = "u\\.s\\.", ignore_case = TRUE), replacement = "usa")) %>%
  mutate(article = str_replace_all(string = article, pattern = regex(pattern = "f\\.d\\.a\\.", ignore_case = TRUE), replacement = "fda")) %>%
  mutate(article = str_replace_all(string = article, pattern = regex(pattern = "gov\\.", ignore_case = TRUE), replacement = "gov")) %>%
  mutate(article = str_replace_all(string = article, pattern = regex(pattern = "sen\\.", ignore_case = TRUE), replacement = "sen")) %>%
  mutate(article = str_replace_all(string = article, pattern = regex(pattern = "( .{1})\\.", ignore_case = TRUE), replacement = "\\1")) %>%
  unnest_tokens(output = "sentence", 
                input = article, 
                token = "sentences", 
                to_lower = TRUE) %>%
  mutate(length = nchar(sentence)) %>%
  select(length, everything()) %>% 
  ungroup() %>% 
  identity()
# Diagnose problems with abbreviations (Mr. Dr. etc)
end_sentences_corpus <-
  corpus_sentences %>%
  filter(str_detect(string = sentence, pattern = "^[[:alnum:]]{1,5}\\.$")) %>%
  group_by(sentence) %>%
  summarize(n = n()) %>%
  ungroup() %>%
  mutate(n_char = nchar(sentence)) %>%
  arrange(desc(n))

We can now try to isolate sentences containing our terms of interest.


      antibiotic free antibiotic resistance            food borne    indiscriminate use         judicious use           prudent use 
                  125                   299                   119                    16                    14                     7 
      responsible use           routine use 
                    1                    53 
                       
                        The New York Times The Washington Post
  antibiotic free                       88                  37
  antibiotic resistance                165                 134
  food borne                            55                  64
  indiscriminate use                    13                   3
  judicious use                          9                   5
  prudent use                            6                   1
  responsible use                        1                   0
  routine use                           38                  15

On this new dataframe, we can count the occurence of each word in the sentence context of each syntagma, overall and divided by journal:

Grouping rowwise data frame strips rowwise natureGrouping rowwise data frame strips rowwise nature

Figures printing and saving

Packages loading

─ Session info ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

─ Packages ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
 package        * version date       lib source        
 askpass          1.1     2019-01-13 [1] CRAN (R 3.6.0)
 assertthat       0.2.1   2019-03-21 [1] CRAN (R 3.6.0)
 backports        1.1.4   2019-04-10 [1] CRAN (R 3.6.0)
 base64enc        0.1-3   2015-07-28 [1] CRAN (R 3.6.0)
 broom            0.5.2   2019-04-07 [1] CRAN (R 3.6.0)
 callr            3.2.0   2019-03-15 [1] CRAN (R 3.6.0)
 cli              1.1.0   2019-03-19 [1] CRAN (R 3.6.0)
 codetools        0.2-16  2018-12-24 [2] CRAN (R 3.6.0)
 colorspace       1.4-1   2019-03-18 [1] CRAN (R 3.6.0)
 cowplot        * 0.9.4   2019-01-08 [1] CRAN (R 3.6.0)
 crayon           1.3.4   2017-09-16 [1] CRAN (R 3.6.0)
 crosstalk        1.0.0   2016-12-21 [1] CRAN (R 3.6.0)
 data.table       1.12.2  2019-04-07 [1] CRAN (R 3.6.0)
 desc             1.2.0   2018-05-01 [1] CRAN (R 3.6.0)
 devtools         2.0.2   2019-04-08 [1] CRAN (R 3.6.0)
 digest           0.6.18  2018-10-10 [1] CRAN (R 3.6.0)
 dplyr          * 0.8.0.1 2019-02-15 [1] CRAN (R 3.6.0)
 DT             * 0.5     2018-11-05 [1] CRAN (R 3.6.0)
 evaluate         0.13    2019-02-12 [1] CRAN (R 3.6.0)
 foreach        * 1.4.4   2017-12-12 [1] CRAN (R 3.6.0)
 fs               1.2.7   2019-03-19 [1] CRAN (R 3.6.0)
 generics         0.0.2   2018-11-29 [1] CRAN (R 3.6.0)
 ggplot2        * 3.1.1   2019-04-07 [1] CRAN (R 3.6.0)
 ggrepel          0.8.0   2018-05-09 [1] CRAN (R 3.6.0)
 glmnet         * 2.0-16  2018-04-02 [1] CRAN (R 3.6.0)
 glue             1.3.1   2019-03-12 [1] CRAN (R 3.6.0)
 gtable           0.3.0   2019-03-25 [1] CRAN (R 3.6.0)
 hms              0.4.2   2018-03-10 [1] CRAN (R 3.6.0)
 htmltools        0.3.6   2017-04-28 [1] CRAN (R 3.6.0)
 htmlwidgets      1.3     2018-09-30 [1] CRAN (R 3.6.0)
 httpuv           1.5.1   2019-04-05 [1] CRAN (R 3.6.0)
 iterators        1.0.10  2018-07-13 [1] CRAN (R 3.6.0)
 janeaustenr      0.1.5   2017-06-10 [1] CRAN (R 3.6.0)
 jsonlite         1.6     2018-12-07 [1] CRAN (R 3.6.0)
 knitr            1.22    2019-03-08 [1] CRAN (R 3.6.0)
 koRpus         * 0.11-5  2018-10-28 [1] CRAN (R 3.6.0)
 koRpus.lang.en * 0.1-2   2018-03-21 [1] CRAN (R 3.6.0)
 labeling         0.3     2014-08-23 [1] CRAN (R 3.6.0)
 later            0.8.0   2019-02-11 [1] CRAN (R 3.6.0)
 lattice          0.20-38 2018-11-04 [2] CRAN (R 3.6.0)
 lazyeval         0.2.2   2019-03-15 [1] CRAN (R 3.6.0)
 lubridate      * 1.7.4   2018-04-11 [1] CRAN (R 3.6.0)
 magrittr         1.5     2014-11-22 [1] CRAN (R 3.6.0)
 Matrix         * 1.2-17  2019-03-22 [2] CRAN (R 3.6.0)
 memoise          1.1.0   2017-04-21 [1] CRAN (R 3.6.0)
 mime             0.6     2018-10-05 [1] CRAN (R 3.6.0)
 munsell          0.5.0   2018-06-12 [1] CRAN (R 3.6.0)
 nlme             3.1-139 2019-04-09 [2] CRAN (R 3.6.0)
 pdftools       * 2.2     2019-03-10 [1] CRAN (R 3.6.0)
 pillar           1.3.1   2018-12-15 [1] CRAN (R 3.6.0)
 pkgbuild         1.0.3   2019-03-20 [1] CRAN (R 3.6.0)
 pkgconfig        2.0.2   2018-08-16 [1] CRAN (R 3.6.0)
 pkgload          1.0.2   2018-10-29 [1] CRAN (R 3.6.0)
 plyr             1.8.4   2016-06-08 [1] CRAN (R 3.6.0)
 prettyunits      1.0.2   2015-07-13 [1] CRAN (R 3.6.0)
 processx         3.3.0   2019-03-10 [1] CRAN (R 3.6.0)
 promises         1.0.1   2018-04-13 [1] CRAN (R 3.6.0)
 ps               1.3.0   2018-12-21 [1] CRAN (R 3.6.0)
 purrr            0.3.2   2019-03-15 [1] CRAN (R 3.6.0)
 qpdf             1.1     2019-03-07 [1] CRAN (R 3.6.0)
 R6               2.4.0   2019-02-14 [1] CRAN (R 3.6.0)
 Rcpp             1.0.1   2019-03-17 [1] CRAN (R 3.6.0)
 readr          * 1.3.1   2018-12-21 [1] CRAN (R 3.6.0)
 remotes          2.0.4   2019-04-10 [1] CRAN (R 3.6.0)
 rlang            0.3.4   2019-04-07 [1] CRAN (R 3.6.0)
 rmarkdown        1.12    2019-03-14 [1] CRAN (R 3.6.0)
 rprojroot        1.3-2   2018-01-03 [1] CRAN (R 3.6.0)
 rstudioapi       0.10    2019-03-19 [1] CRAN (R 3.6.0)
 scales           1.0.0   2018-08-09 [1] CRAN (R 3.6.0)
 sessioninfo      1.1.1   2018-11-05 [1] CRAN (R 3.6.0)
 shiny            1.3.2   2019-04-22 [1] CRAN (R 3.6.0)
 SnowballC        0.6.0   2019-01-15 [1] CRAN (R 3.6.0)
 stringi          1.4.3   2019-03-12 [1] CRAN (R 3.6.0)
 stringr        * 1.4.0   2019-02-10 [1] CRAN (R 3.6.0)
 sylly          * 0.1-5   2018-07-29 [1] CRAN (R 3.6.0)
 sylly.en         0.1-3   2018-03-19 [1] CRAN (R 3.6.0)
 textstem       * 0.1.4   2018-04-09 [1] CRAN (R 3.6.0)
 tibble           2.1.1   2019-03-16 [1] CRAN (R 3.6.0)
 tidyr          * 0.8.3   2019-03-01 [1] CRAN (R 3.6.0)
 tidyselect       0.2.5   2018-10-11 [1] CRAN (R 3.6.0)
 tidytext       * 0.2.0   2018-10-17 [1] CRAN (R 3.6.0)
 tokenizers       0.2.1   2018-03-29 [1] CRAN (R 3.6.0)
 usethis          1.5.0   2019-04-07 [1] CRAN (R 3.6.0)
 withr            2.1.2   2018-03-15 [1] CRAN (R 3.6.0)
 xfun             0.6     2019-04-02 [1] CRAN (R 3.6.0)
 xtable           1.8-4   2019-04-21 [1] CRAN (R 3.6.0)
 yaml             2.2.0   2018-07-25 [1] CRAN (R 3.6.0)

[1] /home/abn/R/x86_64-pc-linux-gnu-library/3.6
[2] /usr/lib/R/library
LS0tCnRpdGxlOiAiQW50aWJpb3RpY3MgYW5kIGZvb2QgaW4gdGhlIEFtZXJpY2FuIHByZXNzOiBBIHRleHQgbWluaW5nIHN0dWR5LiIKYXV0aG9yOiAiYW50b2luZS5icmlkaWVyLW5haG1pYXNAaW5zZXJtLmZyIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazogCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogZmFsc2UKICAgIHRvY19kZXB0aDogMwogICAgdGhlbWU6ICJmbGF0bHkiCiAgICBoaWdobGlnaHQ6ICJweWdtZW50cyIKLS0tCgoqQW50aWJpb3RpY3MgYW5kIGZvb2QgaW4gdGhlIEFtZXJpY2FuIHByZXNzOiBBIHRleHQgbWluaW5nIHN0dWR5LiogIAo8c21hbGw+QW50b2luZSBCcmlkaWVyLU5haG1pYXMkXGRhZ2dlciQsIEVzdGVyYSBCYWRhdSRcZGFnZ2VyJCwgUGkgTnl2YWxsIENvbGxlbgosQW50b2luZSBBbmRyZW1vbnQsIEpvY2VseW5lIEFycXVlbWJvdXJnPC9zbWFsbD4KCgo8c21hbGw+JFxkYWdnZXIkOiBUaGVzZSBhdXRob3JzIGNvbnRyaWJ1dGVkIGVxdWFsbHkgdG8gdGhpcyB3b3JrPC9zbWFsbD4KCiMgQ29ycHVzIGNvbnN0aXR1dGlvbgpUaGUgYXJ0aWNsZXMgaGF2ZSBiZWVuIHNlYXJjaGVkIHVwb24gdGhlIEZhY3RpdmEgZGF0YWJhc2UsIGJhc2VkIG9uIGtleSB3b3JkcyAKYW5kIGV4cHJlc3Npb25zIHVzZWQgaW4gY29uanVuY3Rpb24uIFRlcm1zIGFuZCBleHByZXNzaW9ucyByZXNlYXJjaGVkIHdlcmUgdGhlIApmb2xsb3dpbmc6IApgYGAKYW50aWJpb3RpYyByZXNpc3RhbmNlLCBhbnRpbWljcm9iaWFsIHJlc2lzdGFuY2UsIAphbnRpYmlvdGljIGZyZWUgb3IgYW50aWJpb3RpYy1mcmVlLCBhbnRpYmlvdGljcyBhbmQgZm9vZCwgCmFudGliaW90aWNzIGFuZCBmYXJtaW5nLCBhbnRpYmlvdGljcyBhbmQgcmVzaXN0YW50LCBhbnRpYmlvdGljcyBhbmQgc2FsbW9uZWxsYSwgCnNhbG1vbmVsbGEgYW5kIHJlc2lzdGFudCwgc2FsbW9uZWxsYSBhbmQgb3V0YnJlYWssIAphbnRpYmlvdGljcyBhbmQgY2FtcHlsb2JhY3RlciBhbmQgcmVzaXN0YW50LCBhbnRpYmlvdGljcyBhbmQgcm91dGluZSwgCmFudGliaW90aWNzIGFuZCByb3V0aW5lbHksIGFudGliaW90aWNzIGFuZCBPbmUgSGVhbHRoOwooYW50aWJpbyogbmVhcjMgZm9vZCkgb3IgKGFudGliaW8qIG5lYXIzIGZhcm0qKSBvciAoYW50aWJpbyogbmVhcjMgc2FsbW9uZWxsKikgCm9yIChhbnRpYmlvKiBuZWFyMyBjYW1weWxvYmFjdGVyKikgb3IgKGFudGliaW8qIG5lYXIzIGFuaW1hbCopIG9yIAooYW50aWJpbyogbmVhcjMgZmVlZCkKYGBgCgojIERhdGEgbG9hZGluZwpUaGUgY29ycHVzIGlzIGNvbnNpdHV0ZWQgYnkgYXJ0aWNsZXMgc2F2ZWQgaW4gaW5kZXBlbmRlbnQgcGRmIGZpbGVzLgpgYGB7ciBjb3JwdXNfbG9hZGluZ30KIyBsaXN0IHBkZiBmaWxlcwpwZGZfbGlzdCA8LQogIGxpc3QuZmlsZXMocGF0aCA9ICIuLi9kYXRhL2NvcnB1cy8iLCBwYXR0ZXJuID0gIl4uKnBkZiQiLCBmdWxsLm5hbWVzID0gVFJVRSwgcmVjdXJzaXZlID0gVFJVRSkKCiMgc2NyYXAgdGhlaXIgdGV4dCBjb250ZW50CnBkZl90eHQgPC0KICBsYXBwbHkoWCA9IHBkZl9saXN0LCBGVU4gPSBmdW5jdGlvbih4KSBwYXN0ZTAocGRmX3RleHQoeCksIGNvbGxhcHNlID0gIlxuIiApKQoKIyBzcGxpdCB0aGVtIG92ZXIgZWFjaCBuZXdsaW5lCnBkZl9zcGxpdCA8LQogIHNhcHBseShYID0gcGRmX3R4dCwgZnVuY3Rpb24oeCkgc3RyX3NwbGl0KHN0cmluZyA9IHVubGlzdCh4KSwgcGF0dGVybiA9ICJcbiIpKQoKIyBlbGltaW5hdGluZyBsZWFkaW5nIHNwYWNlcyBpbiBlYWNoIGxpbmUKcGRmX3NwbGl0X3N0cnAgPC0KICBsYXBwbHkoWCA9IHBkZl9zcGxpdCwgZnVuY3Rpb24oeCkgc3RyX3JlcGxhY2Uoc3RyaW5nID0geCwgcGF0dGVybiA9ICJeW1s6c3BhY2U6XV0rIiwgcmVwbGFjZW1lbnQgPSAiIikpCmBgYAoKIyBEYXRhIFByb2Nlc3NpbmcKCiMjIEluZm9ybWF0aW9uIHNjcmFwcGluZyBhbmQgY2xlYW5pbmcKYGBge3IgcGFyc2luZ19pbmZvfQojIFRoaXMgZnVuY3Rpb24gd2lsbCB0YWtlIGNhcmUgb2YgdGhlIHBhcnNpbmcKZ29nb19nYWRnZXRvX2dldF9pbmZvIDwtIGZ1bmN0aW9uKHRleHRfdmVjdG9yKXsKICAjIEhEIGlzIHRoZSB0aXRsZSB0YWcKICB0aXRsZSA8LSBnc3ViKHBhdHRlcm4gPSAiSEQoLiopIiwgcmVwbGFjZW1lbnQgPSAiXFwxIiwKICAgICAgICAgICAgICAgIHggPSBncmVwKHBhdHRlcm4gPSAiXkhELioiLCB4ID0gdGV4dF92ZWN0b3IsIHZhbHVlID0gVFJVRSkpCiAgdGl0bGUgPC0gc3RyX3JlbW92ZV9hbGwoc3RyaW5nID0gdGl0bGUsIHBhdHRlcm4gPSAiXiAqIikKICAjIEJZIGlzIHRoZSBhdXRob3IgdGFnCiAgYXV0aG9yIDwtIGdzdWIocGF0dGVybiA9ICIoPzpCWXxCeSkoLiopIiwgcmVwbGFjZW1lbnQgPSAiXFwxIiwKICAgICAgICAgICAgICAgICB4ID0gZ3JlcChwYXR0ZXJuID0gIl4oPzpCWXxCeSkuKiIsIHggPSB0ZXh0X3ZlY3RvciwgdmFsdWUgPSBUUlVFKSkKICBhdXRob3IgPC0gaWZlbHNlKHRlc3QgPSBsZW5ndGgoYXV0aG9yKSA9PSAwLCB5ZXMgPSAiIiwgbm8gPSBhdXRob3IpCiAgCiAgIyBTTiBpcyB0aGUgam91cm5hbCB0YWcKICBqb3VybmFsIDwtIGdzdWIocGF0dGVybiA9ICJTTiguKikiLCByZXBsYWNlbWVudCA9ICJcXDEiLAogICAgICAgICAgICAgICAgICB4ID0gZ3JlcChwYXR0ZXJuID0gIl5TTi4qIiwgeCA9IHRleHRfdmVjdG9yLCB2YWx1ZSA9IFRSVUUpKQogIGpvdXJuYWwgPC0gaWZlbHNlKHRlc3QgPSBsZW5ndGgoam91cm5hbCkgPT0gMCwgeWVzID0gIiIsIG5vID0gam91cm5hbCkKICBqb3VybmFsIDwtIHN0cl9yZXBsYWNlKGpvdXJuYWwsICJeICsiLCAiIikKICAKICAjIFBEIGlzIHRoZSBwdWJsaWNhdGlvbiBkYXRlIHRhZwogIHB1Yl9kYXRlIDwtIGdzdWIocGF0dGVybiA9ICJQRCguKikiLCByZXBsYWNlbWVudCA9ICJcXDEiLAogICAgICAgICAgICAgICAgICAgeCA9IGdyZXAocGF0dGVybiA9ICJeUEQuKiIsIHggPSB0ZXh0X3ZlY3RvciwgdmFsdWUgPSBUUlVFKSkKICBwdWJfZGF0ZSA8LSBpZmVsc2UodGVzdCA9IGxlbmd0aChwdWJfZGF0ZSkgPT0gMCwgeWVzID0gIiIsIG5vID0gcHViX2RhdGUpCiAgcHViX2RhdGUgPC0gZ3N1YihwYXR0ZXJuID0gImFvdCIsIHJlcGxhY2VtZW50ID0gImF1Z3VzdCIsIHggPSBwdWJfZGF0ZSkKICBwdWJfZGF0ZSA8LSBkbXkocHViX2RhdGUpCiAgCiAgIyBvdXRwdXQgaXMgYSB0aWJibGUgd2l0aCBhbGwgdGhlIGluZm9ybWF0aW9ucwogIGFydGljbGVfaW5mbyA8LSB0aWJibGUodGl0bGUgPSB0aXRsZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhdXRob3IgPSBhdXRob3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgam91cm5hbCA9IGpvdXJuYWwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHViX2RhdGUgPSBwdWJfZGF0ZSkKICByZXR1cm4oYXJ0aWNsZV9pbmZvKQp9CgojIGV4dHJhY3QgaW5mb3JtYXRpb25zIG9mIGVhY2ggYXJ0aWNsZSB3LyBnb2dvX2dhZGdldG9fZ2V0X2luZm8KcGRmX2luZm8gPC0KICBsYXBwbHkoWCA9IHBkZl9zcGxpdF9zdHJwLCBGVU4gPSBnb2dvX2dhZGdldG9fZ2V0X2luZm8pCmBgYAoKV2Ugd2lsbCBub3cgZnVzZSB0aGUgYXJ0aWNsZXMgYW5kIHRoZWlyIHJlc3BlY3RpdmUgaW5mb3JtYXRpb25zIGluIGEgZGF0YWZyYW1lLCAKYW5kIHRoZW4gd2Ugd2lsbCByZW1vdmUgdGhlIGhlYWRlcnMgYW5kIGZvb3RlcnMuClRoaXMgb3BlcmF0aW9uIGlzIG5vaXN5IGJlY2F1c2Ugb2YgdGhlIGluY29uc2lzdGVuY3kgaW4gdGhlIGZvb3RlciBmb3JtYXR0aW5nLgpgYGB7ciBhZGRpbmdfaW5mb30KIyBtYWtpbmcgYSBkYXRhLmZyYW1lIHdpdGggdGhlIGluZm8gYW5kIHRoZSB0ZXh0CnBkZl90eHRfaW5mbyA8LSBsaXN0KCkKZm9yIChpIGluIDE6bGVuZ3RoKHBkZl9zcGxpdF9zdHJwKSkgewogIHBkZl90eHRfaW5mb1tbaV1dIDwtIAogICAgY2JpbmQuZGF0YS5mcmFtZShwZGZfaW5mb1tbaV1dLCAKICAgICAgICAgICAgICAgICAgICAgdGV4dCA9IGFzLmNoYXJhY3RlcihwZGZfc3BsaXRfc3RycFtbaV1dKSwgCiAgICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKfQoKIyBSZW1vdmluZyBoZWFkZXIgYW5kIGZvb3RlciBpbiBlYWNoIGRhdGFmcmFtZQojIFRoZSBmb290ZXIgaXMgaW5jb25zaXN0ZW50IGFjcm9zcyBhcnRpY2xlIGFuZCAKIyBtYW55IGRpZmZlcmVudCBsaW5lcyBhcmUgbmVlZGVkIHRvIHB1cmdlIGl0IG91dAojIGNoZWNrIGZvciBhIHN0cmluZyA6IHN1bSh1bmxpc3QobGFwcGx5KHBkZl90eHRfaW5mbywgZnVuY3Rpb24oeCkgc3RyX2RldGVjdChzdHJpbmcgPSB4JHRleHQsIHBhdHRlcm4gPSAiXkxQIikpKSkKYmVoZWFkX2FuZF9iZWZvb3QgPC0gZnVuY3Rpb24oZGZfaW4pewogIGRmX291dCA8LQogICAgZGZfaW4gJT4lCiAgICBmaWx0ZXIoY3Vtc3VtKHN0cl9kZXRlY3QodGV4dCwgcGF0dGVybiA9ICJeTFAiKSkgPj0gMSkgJT4lCiAgICBmaWx0ZXIoY3Vtc3VtKHN0cl9kZXRlY3QodGV4dCwgcGF0dGVybiA9ICJeTlMiKSApIDwgMSkgJT4lCiAgICBmaWx0ZXIoY3Vtc3VtKHN0cl9kZXRlY3QodGV4dCwgcGF0dGVybiA9ICJeSWxsdXN0cmF0aW9uczoiKSApIDwgMSkgJT4lCiAgICBmaWx0ZXIoY3Vtc3VtKHN0cl9kZXRlY3QodGV4dCwgcGF0dGVybiA9ICJeQVJUIikgKSA8IDEpICU+JQogICAgZmlsdGVyKGN1bXN1bShzdHJfZGV0ZWN0KHRleHQsIHBhdHRlcm4gPSAiXkNUIikgKSA8IDEpICU+JQogICAgZmlsdGVyKGN1bXN1bShzdHJfZGV0ZWN0KHRleHQsIHBhdHRlcm4gPSAiXklQRCIpICkgPCAxKSAlPiUKICAgIGZpbHRlcihjdW1zdW0oc3RyX2RldGVjdCh0ZXh0LCBwYXR0ZXJuID0gIl4uKlxcfC4qXFx8LioiKSkgPCAxKSAlPiUKICAgIGZpbHRlcihjdW1zdW0oc3RyX2RldGVjdCh0ZXh0LCBwYXR0ZXJuID0gIl5BTiAiKSkgPCAxKSAlPiUgCiAgICBmaWx0ZXIoY3Vtc3VtKHN0cl9kZXRlY3QodGV4dCwgcGF0dGVybiA9ICJeUkYgIikpIDwgMSkgJT4lIAogICAgZmlsdGVyKGN1bXN1bShzdHJfZGV0ZWN0KHRleHQsIHBhdHRlcm4gPSAiXkNPICIpKSA8IDEpICU+JQogICAgZmlsdGVyKCFzdHJfZGV0ZWN0KHRleHQsIHBhdHRlcm4gPSAiRmFjdGl2YSIpKSAlPiUKICAgIGZpbHRlcighc3RyX2RldGVjdCh0ZXh0LCBwYXR0ZXJuID0gIl5URCQiKSkgJT4lCiAgICBmaWx0ZXIoIXN0cl9kZXRlY3QodGV4dCwgcGF0dGVybiA9ICJeTFAkIikpICU+JQogICAgZmlsdGVyKCFzdHJfZGV0ZWN0KHRleHQsIHBhdHRlcm4gPSAiXiQiKSkgJT4lIAogICAgaWRlbnRpdHkoKQogIHJldHVybihkZl9vdXQpCn0KCnR4dF9jbGVhbiA8LQogIGxhcHBseShYID0gcGRmX3R4dF9pbmZvLCAKICAgICAgICAgRlVOID0gYmVoZWFkX2FuZF9iZWZvb3QpCmBgYAoKV2UgYXJlIHJlYWR5IHRvIHVuaXRlIGV2ZXJ5dGhpbmcgaW4gb25lIGRhdGEuZnJhbWUsIGJlZm9yZWhhbmQgd2UnbGwganVzdCBhZGQgYSAKdW5pcXVlIGlkIGZvciBlYWNoIGFydGljbGUuCmBgYHtyIHVuaXRlfQojIGJlZm9yZSB1bml0aW5nIHRoZW0sIGVhY2ggYXJ0aWNsZSBuZWVkcyB0byByZWNlaXZlIGEgdW5pcXVlIElECmZvciAoaSBpbiAxOmxlbmd0aCh0eHRfY2xlYW4pKSB7CiAgdHh0X2NsZWFuW1tpXV0gPC0gY2JpbmQuZGF0YS5mcmFtZSh0eHRfY2xlYW5bW2ldXSwgaWQgPSBpKQogIHR4dF9jbGVhbltbaV1dJHRleHRbMV0gPC0gcGFzdGUodHh0X2NsZWFuW1tpXV0kdGl0bGVbMV0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHh0X2NsZWFuW1tpXV0kdGV4dFsxXSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXAgPSAiICIpCn0KCiMgdW5pdGluZyBldmVyeXRoaW5nIGludG8gYSBiaWcgZGF0YWZyYW1lCmNvcnB1c190eHQgPC0KICBkby5jYWxsKHJiaW5kLCB0eHRfY2xlYW4pCgpgYGAKClRoZSB0b2tlbnphdGlvbiBjYW4gbm93IHRha2UgcGxhY2UuIFdlIGNhbiB1c2UgbXVsdGlwbGUgbmdyYW1zIHNpemUsIHdlIHdpbGwgCnN0YXJ0IHdpdGggMWdyYW1zIGZpcnN0ICppLmUqOiB3b3Jkcy4gIApgYGB7ciAxX2dyYW1zfQpjb3JwdXNfMV9ncmFtc191bmZpbHRlcmVkIDwtIAogIHVubmVzdF90b2tlbnModGJsID0gY29ycHVzX3R4dCwgCiAgICAgICAgICAgICAgICBvdXRwdXQgPSAid29yZCIsIAogICAgICAgICAgICAgICAgaW5wdXQgPSAidGV4dCIsIAogICAgICAgICAgICAgICAgdG9rZW4gPSAibmdyYW1zIiwgCiAgICAgICAgICAgICAgICBuID0gMSkKYGBgCgojIENvdW50aW5nIGFuZCBtb3JlCkxldCdzIGZpcnN0IGV4dHJhY3Qgc29tZSBmaWd1cmVzIGFib3V0IHRoZSB3aG9sZSBjb3JwdXMKYGBge3IgZ2xvYmFsX2ZpZ3VyZXMsIHJlc3VsdHMgPSBGQUxTRX0KYXJ0aWNsYSA8LQogIGxlbmd0aCh1bmlxdWUoY29ycHVzXzFfZ3JhbXNfdW5maWx0ZXJlZCRpZCkpCgphcnRpY2xhX2J5X2pvdXJuYWwgPC0KICBjb3JwdXNfMV9ncmFtc191bmZpbHRlcmVkICU+JQogIGdyb3VwX2J5KGpvdXJuYWwpICU+JQogIHN1bW1hcml6ZShuID0gbl9kaXN0aW5jdChpZCkpCgp3b3JkYSA8LSAKICBmb3JtYXQobnJvdyhjb3JwdXNfMV9ncmFtc191bmZpbHRlcmVkKSwgYmlnLm1hcmsgPSAiLCIpCgp3b3JkYV91bmlxIDwtCiAgZm9ybWF0KGxlbmd0aCh1bmlxdWUoY29ycHVzXzFfZ3JhbXNfdW5maWx0ZXJlZCR3b3JkKSksIGJpZy5tYXJrID0gIiwiKQoKd29yZGFfYnlfam91cm5hbCA8LQogIGNvcnB1c18xX2dyYW1zX3VuZmlsdGVyZWQgJT4lCiAgZ3JvdXBfYnkoam91cm5hbCkgJT4lIGNvdW50KCkKCndvcmRhX3VuaXFfYnlfam91cm5hbCA8LQogIGNvcnB1c18xX2dyYW1zX3VuZmlsdGVyZWQgJT4lCiAgZ3JvdXBfYnkoam91cm5hbCkgJT4lCiAgc3VtbWFyaXplKG4gPSBuX2Rpc3RpbmN0KHdvcmQpKQoKIyBhcnRpY2xhO2FydGljbGFfYnlfam91cm5hbDt3b3JkYTt3b3JkYV91bmlxOyB3b3JkYV9ieV9qb3VybmFsO3dvcmRhX3VuaXFfYnlfam91cm5hbApgYGAKCi0gVGhlIHRvdGFsIG51bWJlciBvZiBhcnRpY2xlczoKLSBvdmVyYWxsOiBgciBhcnRpY2xhYAotIGJ5IGpvdXJuYWw6IGByIGFydGljbGFfYnlfam91cm5hbGAKCi0gVGhlIHRvdGFsIG51bWJlciBvZiB3b3JkcyBpbiB0aGUgY29ycHVzCi0gb3ZlcmFsbDogYHIgd29yZGFgCi0gYnkgam91cm5hbDogYHIgd29yZGFfYnlfam91cm5hbGAKCi0gVGhlIHRvdGFsIG51bWJlciBvZiBkaXN0aW5jdCB3b3JkcyBpbiB0aGUgY29ycHVzCi0gb3ZlcmFsbDogYHIgd29yZGFfdW5pcWAKLSBieSBqb3VybmFsOiBgciB3b3JkYV91bmlxX2J5X2pvdXJuYWxgCgojIyBQdWJsaWNhdGlvbiBjaHJvbm9sb2d5CmBgYHtyIHB1Yl9jaHJvbm8sIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTE1LCBmaWcuYXNwPTAuNX0KdGltZWxpbmVfZXZlbnRzIDwtIHJlYWRfZGVsaW0oIi4uL2RhdGEvdGltZWxpbmVfZXZlbnRzLnRzdiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiXHQiLCBlc2NhcGVfZG91YmxlID0gRkFMU0UsIHRyaW1fd3MgPSBUUlVFLCBjb21tZW50ID0gIiMiKQoKdGltZWxpbmVfZXZlbnRzIDwtCiAgdGltZWxpbmVfZXZlbnRzICU+JQogIG11dGF0ZShldmVudF9sYWJlbCA9IHN0cl9yZXBsYWNlX2FsbChzdHJpbmcgPSBldmVudF9sYWJlbCwgcGF0dGVybiA9ICJYWFgiLCByZXBsYWNlbWVudCA9ICJcbiIpKSAlPiUKICBtdXRhdGUoZGF0ZSA9IHltZChkYXRlKSkgJT4lCiAgbXV0YXRlKGRhdGVfbGFiID0gcGFzdGUobW9udGgoZGF0ZSwgbGFiZWwgPSBUUlVFLCBhYmJyID0gVFJVRSwgbG9jYWxlID0gImVuX1VTLnV0ZjgiKSwgeWVhcihkYXRlKSkpICU+JQogIG11dGF0ZShldmVudF9sYWJlbCA9IHBhc3RlMChldmVudF9sYWJlbCwiXG4iLCBkYXRlX2xhYikpICU+JSAKICBtdXRhdGUoeXBvcyA9IDAuMSwgeXBvcyA9IHlwb3MgKiBjKDEsIC0xKSkgJT4lICAjIGluIG9yZGVyIHRvIGFwcGVhciBhYm92ZSBvciB1bmRlciB0aGUgdGltZWxpbmUKICBtdXRhdGUoeWRhdGUgPSB5cG9zKjAuNSkKCmFydGljbGVfaGlzdF9kb2RnZSA8LQogIGNvcnB1c18xX2dyYW1zX3VuZmlsdGVyZWQgJT4lCiAgdW5ncm91cCgpICU+JQogIHNlbGVjdChpZCwgcHViX2RhdGUsIGpvdXJuYWwpICU+JQogIGdyb3VwX2J5KGlkKSAlPiUKICBzbGljZSgxKSAlPiUKICBtdXRhdGUoeWVhciA9IHltZChwYXN0ZTAoeWVhcihwdWJfZGF0ZSksIjAxIiwiMDEiKSkpICU+JQogIGdyb3VwX2J5KHllYXIsIGpvdXJuYWwpICU+JQogIG11dGF0ZShjb3VudCA9IG4oKSkgJT4lCiAgc2xpY2UoMSkKCmhpc3RvIDwtCiAgZ2dwbG90KGRhdGEgPSBhcnRpY2xlX2hpc3RfZG9kZ2UpICsKICBnZW9tX2NvbChtYXBwaW5nID0gYWVzKHggPSB5ZWFyLCB5ID0gY291bnQsIGZpbGwgPSBqb3VybmFsKSwgCiAgICAgICAgICAgcG9zaXRpb24gPSAiZG9kZ2UiLCBhbHBoYSA9IDAuOCwgY29sb3VyID0gImJsYWNrIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKGFscGhhKCJibGFjayIsIDAuMSksIGFscGhhKCJibGFjayIsIDAuMSkpKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygic3RlZWxibHVlIiwgInZpb2xldHJlZDMiKSkgKwogIHNjYWxlX3hfZGF0ZShicmVha3MgPSBzZXEoZnJvbSA9IHltZCgiMTk4MC8wMS8wMSIpLCB0byA9IHltZCgiMjAxNS8wMS8wMSIpLCBieSA9ICI1IHllYXJzIiksCiAgICAgICAgICAgICAgIGRhdGVfbGFiZWxzID0gIiVZIiwKICAgICAgICAgICAgICAgbWlub3JfYnJlYWtzID0gd2FpdmVyKCksCiAgICAgICAgICAgICAgIGRhdGVfbWlub3JfYnJlYWtzID0gIjEgeWVhcnMiLAogICAgICAgICAgICAgICBsaW1pdHMgPSBjKHltZCgiMTk3OS8wMS8wMSIpLHltZCgiMjAxNy8wMS8wMSIpKSkgKyAKICBiYWNrZ3JvdW5kX2dyaWQobWFqb3IgPSAieHkiLCAKICAgICAgICAgICAgICAgICAgbWlub3IgPSAieHkiLCAKICAgICAgICAgICAgICAgICAgY29sb3VyLm1ham9yID0gcmdiKHJlZCA9IDAuNSxncmVlbiA9IDAuNSxibHVlID0gMC41LCBhbHBoYSA9IDAuNSksCiAgICAgICAgICAgICAgICAgIGNvbG91ci5taW5vciA9IHJnYihyZWQgPSAwLjUsZ3JlZW4gPSAwLjUsYmx1ZSA9IDAuNSwgYWxwaGEgPSAwLjEpKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIsCiAgICAgICAgbGVnZW5kLmRpcmVjdGlvbiA9ICJob3Jpem9udGFsIikKaGlzdG8KCnRpbWVsaW5lIDwtIAogIGdncGxvdChkYXRhID0gdGltZWxpbmVfZXZlbnRzKSArCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkYXRlLCB5ID0geXBvcykpICsKICBnZW9tX3NlZ21lbnQobWFwcGluZyA9IGFlcyh4ZW5kID0gZGF0ZSwgeCA9IGRhdGUsIHkgPSB5cG9zLCB5ZW5kID0gMCkpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBjb2xvciA9ICJibGFjayIsIHNpemUgPSAwLjMpICsgIyB0aW1lbGluZSBpdHNlbGYKICBnZ3JlcGVsOjpnZW9tX2xhYmVsX3JlcGVsKG1hcHBpbmcgPSBhZXMoeCA9IGRhdGUsIHkgPSB5cG9zLCBsYWJlbCA9IGV2ZW50X2xhYmVsKSwgaW5oZXJpdC5hZXMgPSBGQUxTRSkgKwogICMgZ2dyZXBlbDo6Z2VvbV9sYWJlbF9yZXBlbChtYXBwaW5nID0gYWVzKHggPSBkYXRlLCB5ID0geWRhdGUsIGxhYmVsID0gZGF0ZV9sYWIsIGFuZ2xlID0gMjUpLCBwb2ludC5wYWRkaW5nID0gMCwgaW5oZXJpdC5hZXMgPSBGQUxTRSkgKwogIHNjYWxlX3hfZGF0ZShicmVha3MgPSBzZXEoZnJvbSA9IHltZCgiMTk4MC8wMS8wMSIpLCB0byA9IHltZCgiMjAxNS8wMS8wMSIpLCBieSA9ICI1IHllYXJzIiksCiAgICAgICAgICAgICAgIGRhdGVfbGFiZWxzID0gIiVZIiwKICAgICAgICAgICAgICAgbWlub3JfYnJlYWtzID0gd2FpdmVyKCksCiAgICAgICAgICAgICAgIGRhdGVfbWlub3JfYnJlYWtzID0gIjEgeWVhcnMiLAogICAgICAgICAgICAgICBsaW1pdHMgPSBjKHltZCgiMTk3OS8wMS8wMSIpLHltZCgiMjAxNy8wMS8wMSIpKSkgKyAKICB0aGVtZShheGlzLmxpbmUueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy5saW5lLnggPSBlbGVtZW50X2JsYW5rKCkKICAgICAgICAgICkKdGltZWxpbmUKCmBgYAoKIyMgQ291bnRzIGFuZCBURi1JREYKV2Ugd2lsbCBjb21wdXRlIHRoZSBmb2xsb3dpbmc6CgotICpjb3JwdXNfbGVuZ3RoKjogdGhlIHRvdGFsIG51bWJlciBvZiBkb2N1bWVudHMgaW4gdGhlIGNvcnB1cwotICphcnRpY2xlX2xlbmd0aCo6IHRoZSB0b3RhbCBudW1iZXIgb2Ygd29yZHMgaW4gZWFjaCBhcnRpY2xlCi0gKm5fYXJ0aWNsZSo6IHRoZSBjb3VudCBvZiBlYWNoIHdvcmQgaW4gZWFjaCBhcnRpY2xlCi0gKndvcmRfaW5fbio6IGZvciBlYWNoIHdvcmQsIGhvdyBtYW55IGFydGljbGVzIGNvbnRhaW4gaXQKLSAqbl90b3QqOiB0b3RhbCBjb3VudCBvZiBlYWNoIHdvcmQKLSAqbl9qb3VybmFsKjogdG90YWwgY291bnQgb2YgZWFjaCB3b3JkIGJ5IGpvdXJuYWwKYGBge3IgdGZpZGZfYnlfYXJ0aWNsZX0Kc3VwcHJlc3NNZXNzYWdlcygKICBteV9zdG9wX3dvcmRzIDwtCiAgICByZWFkX3RhYmxlKAogICAgICBmaWxlID0gIi4uL2RhdGEvbXlfc3RvcF93b3Jkcy50eHQiLAogICAgICBjb2xfbmFtZXMgPSAic3RvcF93b3JkIgogICAgKQopCmNvcnB1c190ZmlkZl9mdWxsIDwtCiAgY29ycHVzXzFfZ3JhbXNfdW5maWx0ZXJlZCAlPiUKICAjIGZpbHRlcihpZCAlaW4lIGMoMzA6MTAwLDQwMDo1MDApICkgJT4lCiAgIyBmaWx0ZXIoaWQgJWluJSBjKDUxNykgKSAlPiUKICAKICAjIGNsZWFuIGRhdGFzZXQKICBtdXRhdGUod29yZCA9IHN0cl90b19sb3dlcihzdHJpbmcgPSB3b3JkKSkgJT4lIAogIG11dGF0ZSh3b3JkID0gc3RyX3JlcGxhY2VfYWxsKHN0cmluZyA9IHdvcmQsIHBhdHRlcm4gPSAiKFtbOmFscGhhOl1dKilcXC4oW1s6YWxwaGE6XV0qKSIsIHJlcGxhY2VtZW50ID0gIlxcMVxcMiIpKSAlPiUKICBtdXRhdGUod29yZCA9IHN0cl9yZXBsYWNlX2FsbChzdHJpbmcgPSB3b3JkLCBwYXR0ZXJuID0gIidzJCIsIHJlcGxhY2VtZW50ID0gIiIpKSAlPiUKICAjIG11dGF0ZSh3b3JkID0gc3RyX3JlcGxhY2VfYWxsKHN0cmluZyA9IHdvcmQsIHBhdHRlcm4gPSAiW15hLXpdIiwgcmVwbGFjZW1lbnQgPSAiIikpICU+JQogIGZpbHRlcighKHN0cl9kZXRlY3Qoc3RyaW5nID0gd29yZCwgcGF0dGVybiA9ICJ3YXNocG9zdGNvbSIpKSkgJT4lICMgVG9rZW5pemF0aW9uIHNwbGl0cyBvbiBAICEhISEhISEKICBmaWx0ZXIod29yZCAhPSAiIikgJT4lIAogIGZpbHRlcihuY2hhcih3b3JkKSA+IDEpICU+JSAKICBmaWx0ZXIoIXN0cl9kZXRlY3Qoc3RyaW5nID0gd29yZCwgcGF0dGVybiA9ICJeWzAtOV18W1s6cHVuY3Q6XV0rJCIpKSAlPiUKICAKICAjIGxlbW1hdGl6YXRpb24gKGJldHRlciB0aGFuIHN0ZW1taW5nKSBhbmQgbGFzdCBmaWx0ZXJpbmcKICBtdXRhdGUoc3RlbSA9IHN0ZW1fd29yZHMod29yZCkpICU+JQogIGZpbHRlcighd29yZCAlaW4lIG15X3N0b3Bfd29yZHMkc3RvcF93b3JkKSAlPiUgCiAgCiAgIyB0b3RhbCBudW1iZXIgb2YgYXJ0aWNsZXMKICBtdXRhdGUoY29ycHVzX2xlbmd0aCA9IGxlbmd0aCh1bmlxdWUoaWQpICkpICU+JSAgCiAgCiAgIyB0b3RhbCB3b3JkIGluIGFydGljbGUKICBncm91cF9ieShpZCkgJT4lCiAgbXV0YXRlKGFydGljbGVfbGVuZ3RoID0gbigpKSAlPiUKICAKICAjIGNvdW50IG9mIGVhY2ggd29yZCBieSBhcnRpY2xlCiAgZ3JvdXBfYnkoaWQsIHN0ZW0pICU+JSAKICBtdXRhdGUobl9hcnRpY2xlID0gbigpKSAlPiUgCiAgCiAgIyB3b3JkIGNvdW50CiAgZ3JvdXBfYnkoc3RlbSkgJT4lIAogIG11dGF0ZShuX3RvdGFsID0gbigpKSAlPiUgCiAgZ3JvdXBfYnkoc3RlbSwgam91cm5hbCkgJT4lIAogIG11dGF0ZShuX2pvdXJuYWwgPSBuKCkpICU+JSAKICB1bmdyb3VwKCkgJT4lCiAgIyBjb21wdXRlIHRmLWlkZgogIAogIG11dGF0ZSh0ZiA9IG5fYXJ0aWNsZSAvIGFydGljbGVfbGVuZ3RoKSAlPiUgIyB0ZXh0IGZyZXF1ZW5jeQogIGdyb3VwX2J5KHN0ZW0pICU+JSAKICBtdXRhdGUod29yZF9pbl9uID0gbGVuZ3RoKHVuaXF1ZShpZCkpKSAlPiUgCiAgbXV0YXRlKGlkZiA9IGxvZyhjb3JwdXNfbGVuZ3RoIC8gd29yZF9pbl9uKSApICU+JSAjIGludmVyc2UgZG9jdW1lbnQgZnJlcXVlbmN5CiAgbXV0YXRlKHRmX2lkZiA9IHRmICogaWRmKSAlPiUgCiAgdW5ncm91cCgpICU+JSAKICAKICAjIENob29zZSBhIHJlcHJlc2VudGFudCBmb3IgZWFjaCBzdGVtLCB0aGUgbW9zdCBjb21tb24gdGVybSBjb3VsZCBiZSB0aGUgYmVzdAogIGdyb3VwX2J5KHN0ZW0pICU+JQogIG11dGF0ZShvcmlfd29yZCA9IHdvcmQpICU+JQogIGdyb3VwX2J5KG9yaV93b3JkKSAlPiUgCiAgbXV0YXRlKG5fb3JpID0gbigpKSAlPiUKICBhcnJhbmdlKGRlc2Mobl9vcmkpKSAlPiUKICBncm91cF9ieShzdGVtKSAlPiUgCiAgbXV0YXRlKHdvcmQgPSB3b3JkWzFdKSAlPiUKICBzZWxlY3QoLW5fb3JpKSAlPiUgCiAgdW5ncm91cCgpCgojIHdyaXRlX2RlbGltKHggPSBjb3JwdXNfdGZpZGZfZnVsbCwgcGF0aCA9ICIuLi9vdXRwdXQvY29ycHVzX3RmaWRmX2Z1bGwudHN2IiwgZGVsaW0gPSAiXHQiLCBjb2xfbmFtZXMgPSBUUlVFKQojIGNvcnB1c190ZmlkZl9mdWxsIDwtIAojICAgcmVhZF9kZWxpbShmaWxlID0gIi4uL291dHB1dC9jb3JwdXNfdGZpZGZfZnVsbC50c3YiLCBkZWxpbSA9ICJcdCIsIGNvbF9uYW1lcyA9IFRSVUUpCgpjb3JwdXNfdGZpZGYgPC0KICBjb3JwdXNfdGZpZGZfZnVsbCAlPiUgCiAgIyByZWR1Y2UKICBncm91cF9ieShpZCwgd29yZCkgJT4lCiAgc2xpY2UoMSkgJT4lIAogIHVuZ3JvdXAoKSAlPiUKICAKICAjIGZpbHRlciBvdXQgIHdvcmRzIHdpdGggdGYtaWRmID09IDAKICBmaWx0ZXIodGZfaWRmID4gMCkgJT4lIAogIGlkZW50aXR5KCkKCmNvcnB1c190ZmlkZiAlPiUgCiAgZmlsdGVyKCEod29yZCAlaW4lIHN0b3Bfd29yZHMkd29yZCkpICU+JQogIGZpbHRlcihuX3RvdGFsID49IDUwKSAlPiUgCiAgYXJyYW5nZShkZXNjKG5fdG90YWwpKSAlPiUgCiAgZ3JvdXBfYnkod29yZCwgam91cm5hbCkgJT4lIAogIHNsaWNlKDEpICU+JQogIHNlbGVjdCh3b3JkLCBqb3VybmFsLCBwdWJfZGF0ZSwgbl90b3RhbCwgbl9qb3VybmFsKSAlPiUKICBhcnJhbmdlKGRlc2Mobl90b3RhbCkpICU+JSAKICBkYXRhdGFibGUoY2FwdGlvbiA9ICJXb3JkcyBhcHBlYXJpbmcgYXQgbGVhc3QgNTAgdGltZXMiLCBmaWx0ZXIgPSAidG9wIikgJT4lIAogIGlkZW50aXR5KCkKYGBgCgojIyBXb3JkIGNvdW50IGV2b2x1dGlvbiB0aHJvdWdoIHRpbWUKYGBge3Igd29yZHNfdGltZSwgZmlnLndpZHRoID0gMTUsIGZpZy5oZWlnaHQ9IDM1fQpjb3JwdXNfeWVhciA8LQogIGNvcnB1c190ZmlkZl9mdWxsICU+JQogICMgRmlsdGVyIG91dCBhIHdvcmQgaWYgb25lIG1lbWJlciBvZiB0aGUgZmFtaWx5IChvcmlfd29yZCkgaXMgYSBzdG9wd29yZAogIGdyb3VwX2J5KHdvcmQpICU+JSAKICBtdXRhdGUoaXNfc3RvcCA9IGlmZWxzZSh0ZXN0ID0gc3VtKG9yaV93b3JkICVpbiUgc3RvcF93b3JkcyR3b3JkKSA+PSAxLCB5ZXMgPSBUUlVFLCBubyA9IEZBTFNFKSkgJT4lCiAgZmlsdGVyKCFpc19zdG9wKSAlPiUgCiAgbXV0YXRlKGlzX3N0b3AgPSBOVUxMKSAlPiUgCiAgdW5ncm91cCgpICU+JSAKICBmaWx0ZXIobl90b3RhbCA+IDM1MCkgJT4lCiAgbXV0YXRlKHllYXIgPSB5ZWFyKHB1Yl9kYXRlKSkgJT4lCiAgZ3JvdXBfYnkod29yZCwgeWVhciwgam91cm5hbCkgJT4lCiAgbXV0YXRlKG5feWVhciA9IG4oKSkgJT4lCiAgc2xpY2UoMSkgJT4lCiAgdW5ncm91cCgpICU+JQogIG11dGF0ZSh3b3JkID0gcmVvcmRlcih3b3JkLCBkZXNjKG5fdG90YWwpKSkjIENvbnZlcnNpb24gdG8gZmFjdG9yIGZvciBvcmRlcmluZyBpbiB0aGUgZmFjZXRfd3JhcHBpbmcgb2YgdGhlIHBsb3QKCm15X2xhYmVsbGVyIDwtCiAgdW5pcXVlKHBhc3RlMChjb3JwdXNfeWVhciR3b3JkLCAiKCIsY29ycHVzX3llYXIkbl90b3RhbCwiKSIpKQpuYW1lcyhteV9sYWJlbGxlcikgPC0gdW5pcXVlKGNvcnB1c195ZWFyJHdvcmQpCgp3b3JkX3RpbWVfcGxvdCA8LQogIGdncGxvdChjb3JwdXNfeWVhcikgKwogIGdlb21fbGluZShtYXBwaW5nID0gYWVzKHggPSBwdWJfZGF0ZSwgeSA9IG5feWVhciwgY29sb3VyID0gam91cm5hbCkpICsKICB5bGFiKCJjb3VudCIpICsKICAgIHhsYWIoIlllYXIiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoInN0ZWVsYmx1ZSIsICJ2aW9sZXRyZWQzIikpICsKICBzY2FsZV94X2RhdGUoYnJlYWtzID0gc2VxKGZyb20gPSB5bWQoIjE5ODAvMDEvMDEiKSwgdG8gPSB5bWQoIjIwMTUvMDEvMDEiKSwgYnkgPSAiNSB5ZWFycyIpLAogICAgICAgICAgICAgICBkYXRlX2xhYmVscyA9ICIlWSIsCiAgICAgICAgICAgICAgIG1pbm9yX2JyZWFrcyA9IHdhaXZlcigpLAogICAgICAgICAgICAgICBkYXRlX21pbm9yX2JyZWFrcyA9ICIxIHllYXJzIiwKICAgICAgICAgICAgICAgbGltaXRzID0gYyh5bWQoIjE5NzkvMDEvMDEiKSx5bWQoIjIwMTcvMDEvMDEiKSkpICsgIyAxIHllYXIgYmVmb3JlIGJlY2F1c2UgZG9kZ2UgbmVlZHMgYSBiaXQgb2Ygc3BhY2UgYXBwYXJlbnRseQogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLCBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpKSArCiAgZmFjZXRfd3JhcCh+d29yZCwgbmNvbCA9IDMsIGxhYmVsbGVyID0gYXNfbGFiZWxsZXIobXlfbGFiZWxsZXIpLCBzY2FsZXMgPSAiZnJlZSIpCiMgZ2dkcmF3KCkgKyBkcmF3X3Bsb3Qod29yZF90aW1lX3Bsb3QpICsgZ2dzYXZlKGZpbGVuYW1lID0gIi4uL291dHB1dC93b3Jkc190aW1lLnBkZiIsIHdpZHRoID0gMzAsIGhlaWdodCA9IDkwLCB1bml0cyA9ICJjbSIpCndvcmRfdGltZV9wbG90CgojIEZvciB0aGUgcGFwZXIKc2VsZWN0ZWRfd29yZF90aW1lX3Bsb3QgPC0KICBjb3JwdXNfeWVhciAlPiUKICBmaWx0ZXIoc3RyX2RldGVjdChzdHJpbmcgPSB3b3JkLCBwYXR0ZXJuID0gIl5hbnRpYmlvdGljcyR8XmZhcm0kfF5pbmR1c3RyeSQiKSkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fbGluZShtYXBwaW5nID0gYWVzKHggPSBwdWJfZGF0ZSwgeSA9IG5feWVhciwgY29sb3VyID0gam91cm5hbCkpICsKICB5bGFiKCJjb3VudCIpICsKICB4bGFiKCJZZWFyIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJzdGVlbGJsdWUiLCAidmlvbGV0cmVkMyIpLCAKICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBndWlkZV9sZWdlbmQodGl0bGUgPSBOVUxMKSkgKwogIHNjYWxlX3hfZGF0ZShicmVha3MgPSBzZXEoZnJvbSA9IHltZCgiMTk4MC8wMS8wMSIpLCB0byA9IHltZCgiMjAxNS8wMS8wMSIpLCBieSA9ICI1IHllYXJzIiksCiAgICAgICAgICAgICAgIGRhdGVfbGFiZWxzID0gIiVZIiwKICAgICAgICAgICAgICAgbWlub3JfYnJlYWtzID0gd2FpdmVyKCksCiAgICAgICAgICAgICAgIGRhdGVfbWlub3JfYnJlYWtzID0gIjEgeWVhcnMiLAogICAgICAgICAgICAgICBsaW1pdHMgPSBjKHltZCgiMTk3OS8wMS8wMSIpLHltZCgiMjAxNy8wMS8wMSIpKSkgKyAjIDEgeWVhciBiZWZvcmUgYmVjYXVzZSBkb2RnZSBuZWVkcyBhIGJpdCBvZiBzcGFjZSBhcHBhcmVudGx5CiAgdGhlbWVfYncoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIsIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMikpICsKICBmYWNldF93cmFwKH53b3JkLCBuY29sID0gMSwgbGFiZWxsZXIgPSBhc19sYWJlbGxlcihteV9sYWJlbGxlciksIHNjYWxlcyA9ICJmcmVlIikKYGBgCmBgYHtyfQpzZWxlY3RlZF93b3JkX3RpbWVfcGxvdApgYGAKCgojIEFuYWx5emVzCiMjIEdMTQpXaGF0IGFyZSB0aGUgdGVybSB0aGF0IGNvdWxkIGRpc2NyaW1pbmF0ZSBiZXR3ZWVuIGFuIGFydGljbGUgZnJvbSB0aGUgV1AgYW5kIHRoZSBOWVQ/CmBgYHtyIGdsbV9kYXRhfQpjb3JwdXNfZ2xtX3dpZGUgPC0KICBjb3JwdXNfdGZpZGYgJT4lIAogIHNlbGVjdCh3b3JkLCBpZCwgam91cm5hbCwgdGZfaWRmKSAlPiUgCiAgbXV0YXRlKGlkX2pvdXJuYWwgPSBqb3VybmFsLCBqb3VybmFsID0gTlVMTCkgJT4lICMgam91cm5hbCBpcyBhIHdvcmQgcHJlc2VudCBpbiB0aGUgY29ycHVzIAogIHNwcmVhZChrZXkgPSB3b3JkLCB2YWx1ZSA9IHRmX2lkZikgJT4lIAogIGJhc2U6OnJlcGxhY2UoeCA9IC4sIGxpc3QgPSBpcy5uYSguKSwgdmFsdWVzID0gMCkgJT4lCiAgdW5ncm91cCgpICU+JSAKICBzZWxlY3QoLWlkKSAlPiUgCiAgbXV0YXRlKGlkX2pvdXJuYWwgPSBhcy5mYWN0b3IoaWRfam91cm5hbCkpICU+JSAKICB1bmdyb3VwKCkgJT4lIAogIGlkZW50aXR5KCkKCnN0YW5kYXJkaXplX2NsYXNzaWMgPC0gCiAgZnVuY3Rpb24oeCkgcmV0dXJuKCh4IC0gbWVhbih4KSkgLyBzZCh4KSkKc3RhbmRhcmRpemVfZ2VsbWFuIDwtIAogIGZ1bmN0aW9uKHgpIHJldHVybih4IC0gbWVhbih4KSAvIDIgKiBzZCh4KSkgIyBzdHJhbmdlLCBzZWUgaHR0cHM6Ly9hbmRyZXdnZWxtYW4uY29tLzIwMDkvMDcvMTEvd2hlbl90b19zdGFuZGFyLwoKc3RhbmRhcmRpemVkX3RmX2lkZiA8LSAjIGNvcnB1c19nbG1fd2lkZVssIC0xXQogIGFwcGx5KFggPSBhcy5tYXRyaXgoY29ycHVzX2dsbV93aWRlWyAsLTFdKSwgCiAgICAgICAgTUFSR0lOID0gMiwgIAogICAgICAgICBGVU4gPSBzdGFuZGFyZGl6ZV9jbGFzc2ljKQoKcmVzcG9uc2VfdmFyIDwtIAogIGNvcnB1c19nbG1fd2lkZSRpZF9qb3VybmFsCnJlc3BvbnNlX3Zhcl9ib29sIDwtIAogIGlmZWxzZSh0ZXN0ID0gcmVzcG9uc2VfdmFyID09ICJUaGUgV2FzaGluZ3RvbiBQb3N0IiwgCiAgICAgICAgIHllcyA9IFRSVUUsIAogICAgICAgICBubyA9IEZBTFNFKQoKYGBgCgpgYGB7ciBnbG1fY2FsY30Kc2V0LnNlZWQoYygxMiwxMCwyMDE4LDE4LDIwKSkgIyBjdi5nbG1uZXQgaGFzIGEgcmFuZG9tIHBhcnQKc3lzdGVtLnRpbWUoCmNvcnB1c19sYXNzbyA8LSAKICBjdi5nbG1uZXQoeCA9IHN0YW5kYXJkaXplZF90Zl9pZGYsIAogICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSByZXNwb25zZV92YXJfYm9vbCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gImJpbm9taWFsIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgbmZvbGRzID0gMTAsIAogICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUubWVhc3VyZSA9ICJhdWMiLCAjIGNvdWxkIGJlICJhdWMiIG9yICJjbGFzcyIKICAgICAgICAgICAgICAgICAgICAgICAgICBpbnRlcmNlcHQgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuNSkKKQpwbG90KGNvcnB1c19sYXNzbykKCndvcmRhX2xhc3NvIDwtIAogIGRpbW5hbWVzKGNvZWYoY29ycHVzX2xhc3NvKSlbWzFdXQoKYmV0YV9kZiA8LSAKICBkYXRhLmZyYW1lKHdvcmQgPSB3b3JkYV9sYXNzbyxiZXRhX2NvZWYgPSBhcy52ZWN0b3IoY29lZi5jdi5nbG1uZXQoY29ycHVzX2xhc3NvLCBjb3JwdXNfbGFzc28kbGFtYmRhLm1pbikpKSAlPiUgCiAgZmlsdGVyKGJldGFfY29lZiAhPSAwKSAlPiUKICBhcnJhbmdlKGRlc2MoYmV0YV9jb2VmKSkgJT4lIAogIG11dGF0ZShwID0gZXhwKChiZXRhX2NvZWYpKSAvICgxICsgZXhwKChiZXRhX2NvZWYpKSkgKSAlPiUgCiAgbXV0YXRlKGxhYl9iZXRhX2NvZWYgPSAoc2lnbmlmKGJldGFfY29lZiwgMikpKSAlPiUgCiAgaWRlbnRpdHkoKQpiZXRhX2RmIAoKCnRpbG9zIDwtCiAgZ2dwbG90KGRhdGEgPSBiZXRhX2RmLCBtYXBwaW5nID0gYWVzKHggPSBmYWN0b3IoMCksIHkgPSByZW9yZGVyKHdvcmQsIGJldGFfY29lZikpKSArCiAgZ2VvbV90aWxlKGFlcyhmaWxsID0gYmV0YV9jb2VmKSkgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSB3b3JkKSkgKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnQyKGxvdyA9ICJzdGVlbGJsdWUiLAogICAgICAgICAgICAgICAgICAgICAgIG1pZCA9ICJ3aGl0ZSIsIAogICAgICAgICAgICAgICAgICAgICAgIGhpZ2ggPSAidmlvbGV0cmVkMyIsIAogICAgICAgICAgICAgICAgICAgICAgIG1pZHBvaW50ID0gMCwgCiAgICAgICAgICAgICAgICAgICAgICAgc3BhY2UgPSAiTGFiIiwgCiAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gYyhtYXgoYmV0YV9kZiRiZXRhX2NvZWYpLCBtaW4oYmV0YV9kZiRiZXRhX2NvZWYpKSwKICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJXUCIsICJOWVQiKSApICsKICBzY2FsZV95X2Rpc2NyZXRlKGxhYmVscyA9IChzb3J0KGJldGFfZGYkbGFiX2JldGFfY29lZiwgZGVjcmVhc2luZyA9IEZBTFNFKSkgKSArCiAgZ2d0aXRsZSgiIikgKwogIHhsYWIoIndvcmQiKSArCiAgeWxhYigiYmV0YSBjb2VmZmljaWVudCBmcm9tIHRoZSBzdGFuZGFyZGl6ZWQgbG9naXN0aWMgcmVncmVzc2lvbiIpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIHRoZW1lKGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dCgpLCAKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKQogICAgICAgICkgKwogIGdlb21fYmxhbmsoKQp0aWxvcwoKIyBwcmVkb3MgPC0gCiMgICBwcmVkaWN0LmN2LmdsbW5ldChvYmplY3QgPSBjb3JwdXNfbGFzc28sIAojICAgICAgICAgICAgICAgICAgICAgbmV3eCA9IHN0YW5kYXJkaXplZF90Zl9pZGYsIAojICAgICAgICAgICAgICAgICAgICAgcyA9ICJsYW1iZGEubWluIiwgCiMgICAgICAgICAgICAgICAgICAgICB0eXBlID0gImNsYXNzIikKIyB0YWJsZShwcmVkb3MgPT0gcmVzcG9uc2VfdmFyX2Jvb2wpCmBgYAoKIyMgQ29udGV4dHVhbCBhbmFseXNpcwojIyMgU3ludGFnbWEgY3VyYXRpb24KSW4gdGhlIG5leHQgc2VjdGlvbiwgd2Ugd2lsbCBjb25jZW50cmF0ZSBvbiBjb3VudGluZyBtYW51YWxseSBjdXJhdGVkIHRlcm1zIG9yIGV4cHJlc3Npb25zIChzeW50YWdtYXMpClRoZXkgd2lsbCBiZSBwcmVzZW50ZWQgaW4gYSBuYW1lZCBsaXN0IGNvbnRhaW5pbmcgYWxsIHRoZSB0ZXJtcyBjb25zaWRlcmVkIGVxdWl2YWxlbnQuIFdlIHdpbGwgdGhlbiBleHRyYWN0IGFsbCB0aGUgc2VudGVuY2VzIGluIHdoaWNoIHRoZXkgb2NjdXIgYW5kIGFuYWx5c2UgdGhlaXIgY29udGV4dCAoaW4gZ2VuZXJhbCBhbmQgYWNyb3NzIHRpbWUpLgpgYGB7ciBjdXJhdGVkX3N5bnRhZ21hfQpjdXJhdGVkX3N5bnRhZ21hIDwtIAogIGxpc3QoCiAgICAiYW50aWJpb3RpY19yZXNpc3RhbmNlIiA9IAogICAgICBjKCJhbnRpYmlvdGljIHJlc2lzdGFuY2UiLCAiYW50aWJpb3RpYy1yZXNpc3RhbmNlIiwgInJlc2lzdGFudCB0byBhbnRpYmlvdGljcyIsICJyZXNpc3RhbmNlIHRvIGFudGliaW90aWNzIiksCiAgICAiYW50aWJpb3RpY19mcmVlIiA9IAogICAgICBjKCJhbnRpYmlvdGljIGZyZWUiLCAiYW50aWJpb3RpYy1mcmVlIiwgImFudGliaW90aWNzZnJlZSIsICJmcmVlIG9mIGFudGliaW90aWNzIiksCiAgICAicm91dGluZV91c2UiID0gCiAgICAgIGMoInJvdXRpbmUgdXNlIiwgInJvdXRpbmVseSB1c2VkIiksCiAgICAianVkaWNpb3VzX3VzZSIgPSAKICAgICAgYygianVkaWNpb3VzIHVzZSIpLAogICAgInJlc3BvbnNpYmxlX3VzZSIgPSAKICAgICAgYygicmVzcG9uc2libGUgdXNlIiksCiAgICAicHJ1ZGVudF91c2UiID0gCiAgICAgIGMoInBydWRlbnQgdXNlIiksCiAgICAiaW5kaXNjcmltaW5hdGVfdXNlIiA9IAogICAgICBjKCJpbmRpc2NyaW1pbmF0ZSB1c2UiKSwKICAgICJmb29kX2Jvcm5lIiA9IAogICAgICBjKCJmb29kIGJvcm5lIiwgImZvb2QtYm9ybmUiKQogICkKY3VyYXRlZF9zeW50YWdtYQpgYGAKClRoZSBmaXJzdCBzdGVwIGlzIHRvIGRpdmlkZSB0aGUgY29ycHVzIGluIHNlbnRlbmNlcy4gIApSZW1hcmsgYHVubmVzdF90b2tlbnModG9rZW4gPSAic2VudGVuY2VzIilgIGNsZWFybHkgZmFpbHMgd2hlbmV2ZXIgaXQgZW5jb3VudGVycyBhbiBhYmJyZXZpYXRpb24gY29udGFpbmluZyBhIGRvdC4KYGBge3IgY29ycHVzX3NlbnRlbmNlc30KY29ycHVzX3NlbnRlbmNlcyA8LQogIGNvcnB1c190eHQgJT4lIAogICMgRWFjaCBhcnRpY2xlIGhhcyB0byBiZSByZS1jb25jYXRlbmF0ZWQKICBncm91cF9ieShpZCkgJT4lIAogICMgZmlsdGVyKGlkICVpbiUgMTo1KSAlPiUKICBtdXRhdGUoYXJ0aWNsZSA9IHBhc3RlKHRleHQsIGNvbGxhcHNlID0gIiAiKSkgJT4lCiAgc2VsZWN0KC10ZXh0KSAlPiUgCiAgZGlzdGluY3QoKSAlPiUKICB1bmdyb3VwKCkgJT4lIAojIENvdWxkL3Nob3VsZCBiZSBkb25lIGluIG9uZSBwYXNzIHdpdGggYSBsaXN0IG9mIHRlcm1zIQogIG11dGF0ZShhcnRpY2xlID0gc3RyX3JlcGxhY2VfYWxsKHN0cmluZyA9IGFydGljbGUsIHBhdHRlcm4gPSByZWdleChwYXR0ZXJuID0gImRyXFwuIiwgaWdub3JlX2Nhc2UgPSBUUlVFKSwgcmVwbGFjZW1lbnQgPSAiZHIiKSkgJT4lCiAgbXV0YXRlKGFydGljbGUgPSBzdHJfcmVwbGFjZV9hbGwoc3RyaW5nID0gYXJ0aWNsZSwgcGF0dGVybiA9IHJlZ2V4KHBhdHRlcm4gPSAicHJvZlxcLiIsIGlnbm9yZV9jYXNlID0gVFJVRSksIHJlcGxhY2VtZW50ID0gInByb2YiKSkgJT4lCiAgbXV0YXRlKGFydGljbGUgPSBzdHJfcmVwbGFjZV9hbGwoc3RyaW5nID0gYXJ0aWNsZSwgcGF0dGVybiA9IHJlZ2V4KHBhdHRlcm4gPSAibXJcXC4iLCBpZ25vcmVfY2FzZSA9IFRSVUUpLCByZXBsYWNlbWVudCA9ICJtciIpKSAlPiUKICBtdXRhdGUoYXJ0aWNsZSA9IHN0cl9yZXBsYWNlX2FsbChzdHJpbmcgPSBhcnRpY2xlLCBwYXR0ZXJuID0gcmVnZXgocGF0dGVybiA9ICJtc1xcLiIsIGlnbm9yZV9jYXNlID0gVFJVRSksIHJlcGxhY2VtZW50ID0gIm1zIikpICU+JQogIG11dGF0ZShhcnRpY2xlID0gc3RyX3JlcGxhY2VfYWxsKHN0cmluZyA9IGFydGljbGUsIHBhdHRlcm4gPSByZWdleChwYXR0ZXJuID0gIm1yc1xcLiIsIGlnbm9yZV9jYXNlID0gVFJVRSksIHJlcGxhY2VtZW50ID0gIm1ycyIpKSAlPiUKICBtdXRhdGUoYXJ0aWNsZSA9IHN0cl9yZXBsYWNlX2FsbChzdHJpbmcgPSBhcnRpY2xlLCBwYXR0ZXJuID0gcmVnZXgocGF0dGVybiA9ICJzdFxcLiIsIGlnbm9yZV9jYXNlID0gVFJVRSksIHJlcGxhY2VtZW50ID0gInN0IikpICU+JQogIG11dGF0ZShhcnRpY2xlID0gc3RyX3JlcGxhY2VfYWxsKHN0cmluZyA9IGFydGljbGUsIHBhdHRlcm4gPSByZWdleChwYXR0ZXJuID0gInJlcFxcLiIsIGlnbm9yZV9jYXNlID0gVFJVRSksIHJlcGxhY2VtZW50ID0gInJlcCIpKSAlPiUKICBtdXRhdGUoYXJ0aWNsZSA9IHN0cl9yZXBsYWNlX2FsbChzdHJpbmcgPSBhcnRpY2xlLCBwYXR0ZXJuID0gcmVnZXgocGF0dGVybiA9ICJ1XFwuc1xcLiIsIGlnbm9yZV9jYXNlID0gVFJVRSksIHJlcGxhY2VtZW50ID0gInVzYSIpKSAlPiUKICBtdXRhdGUoYXJ0aWNsZSA9IHN0cl9yZXBsYWNlX2FsbChzdHJpbmcgPSBhcnRpY2xlLCBwYXR0ZXJuID0gcmVnZXgocGF0dGVybiA9ICJmXFwuZFxcLmFcXC4iLCBpZ25vcmVfY2FzZSA9IFRSVUUpLCByZXBsYWNlbWVudCA9ICJmZGEiKSkgJT4lCiAgbXV0YXRlKGFydGljbGUgPSBzdHJfcmVwbGFjZV9hbGwoc3RyaW5nID0gYXJ0aWNsZSwgcGF0dGVybiA9IHJlZ2V4KHBhdHRlcm4gPSAiZ292XFwuIiwgaWdub3JlX2Nhc2UgPSBUUlVFKSwgcmVwbGFjZW1lbnQgPSAiZ292IikpICU+JQogIG11dGF0ZShhcnRpY2xlID0gc3RyX3JlcGxhY2VfYWxsKHN0cmluZyA9IGFydGljbGUsIHBhdHRlcm4gPSByZWdleChwYXR0ZXJuID0gInNlblxcLiIsIGlnbm9yZV9jYXNlID0gVFJVRSksIHJlcGxhY2VtZW50ID0gInNlbiIpKSAlPiUKICBtdXRhdGUoYXJ0aWNsZSA9IHN0cl9yZXBsYWNlX2FsbChzdHJpbmcgPSBhcnRpY2xlLCBwYXR0ZXJuID0gcmVnZXgocGF0dGVybiA9ICIoIC57MX0pXFwuIiwgaWdub3JlX2Nhc2UgPSBUUlVFKSwgcmVwbGFjZW1lbnQgPSAiXFwxIikpICU+JQogIHVubmVzdF90b2tlbnMob3V0cHV0ID0gInNlbnRlbmNlIiwgCiAgICAgICAgICAgICAgICBpbnB1dCA9IGFydGljbGUsIAogICAgICAgICAgICAgICAgdG9rZW4gPSAic2VudGVuY2VzIiwgCiAgICAgICAgICAgICAgICB0b19sb3dlciA9IFRSVUUpICU+JQogIG11dGF0ZShsZW5ndGggPSBuY2hhcihzZW50ZW5jZSkpICU+JQogIHNlbGVjdChsZW5ndGgsIGV2ZXJ5dGhpbmcoKSkgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgaWRlbnRpdHkoKQoKCgojIERpYWdub3NlIHByb2JsZW1zIHdpdGggYWJicmV2aWF0aW9ucyAoTXIuIERyLiBldGMpCmVuZF9zZW50ZW5jZXNfY29ycHVzIDwtCiAgY29ycHVzX3NlbnRlbmNlcyAlPiUKICBmaWx0ZXIoc3RyX2RldGVjdChzdHJpbmcgPSBzZW50ZW5jZSwgcGF0dGVybiA9ICJeW1s6YWxudW06XV17MSw1fVxcLiQiKSkgJT4lCiAgZ3JvdXBfYnkoc2VudGVuY2UpICU+JQogIHN1bW1hcml6ZShuID0gbigpKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKG5fY2hhciA9IG5jaGFyKHNlbnRlbmNlKSkgJT4lCiAgYXJyYW5nZShkZXNjKG4pKQpgYGAKCldlIGNhbiBub3cgdHJ5IHRvIGlzb2xhdGUgc2VudGVuY2VzIGNvbnRhaW5pbmcgb3VyIHRlcm1zIG9mIGludGVyZXN0LgpgYGB7cn0KY29ycHVzX3N5bnRhZ21hX3NlbnRlbmNlIDwtCiAgbGFwcGx5KFggPSBjdXJhdGVkX3N5bnRhZ21hLCBGVU4gPSBmdW5jdGlvbihzeW50YWdtYSl7CiAgICBjb3JwdXNfc2VudGVuY2VzICU+JQogICAgICByb3d3aXNlKCkgJT4lCiAgICAgIG11dGF0ZShzeW50YWdtdXMgPSBpZmVsc2UodGVzdCA9IHN1bShzdHJfZGV0ZWN0KHN0cmluZyA9IHNlbnRlbmNlLCBwYXR0ZXJuID0gc3ludGFnbWEpKSA+IDAsIHllcyA9IHN5bnRhZ21hLCBubyA9IE5BKSkgJT4lCiAgICAgIGZpbHRlcighaXMubmEoc3ludGFnbXVzKSkKICB9KQoKY29ycHVzX3N5bnRhZ21hX3NlbnRlbmNlIDwtCiAgZG8uY2FsbCh3aGF0ID0gcmJpbmQsIGFyZ3MgPSBjb3JwdXNfc3ludGFnbWFfc2VudGVuY2UpCnRhYmxlKGNvcnB1c19zeW50YWdtYV9zZW50ZW5jZSRzeW50YWdtdXMpCnRhYmxlKGNvcnB1c19zeW50YWdtYV9zZW50ZW5jZSRzeW50YWdtdXMsIGNvcnB1c19zeW50YWdtYV9zZW50ZW5jZSRqb3VybmFsKQpgYGAKCk9uIHRoaXMgbmV3IGRhdGFmcmFtZSwgd2UgY2FuIGNvdW50IHRoZSBvY2N1cmVuY2Ugb2YgZWFjaCB3b3JkIGluIHRoZSBzZW50ZW5jZSBjb250ZXh0IG9mIGVhY2gKc3ludGFnbWEsIG92ZXJhbGwgYW5kIGRpdmlkZWQgYnkgam91cm5hbDoKCmBgYHtyfQpjb3JwdXNfc3ludGFnbWFfd29yZCA8LQogIGNvcnB1c19zeW50YWdtYV9zZW50ZW5jZSAlPiUKICB1bm5lc3RfdG9rZW5zKG91dHB1dCA9ICJ3b3JkIiwgaW5wdXQgPSBzZW50ZW5jZSwgdG9rZW4gPSAibmdyYW1zIiwgbiA9IDEpICU+JQogIGZpbHRlcighKHdvcmQgJWluJSBzdG9wX3dvcmRzJHdvcmQpKSAlPiUKICBmaWx0ZXIoaXMubmEoc3RyX21hdGNoKHN0cmluZyA9IHdvcmQsIHBhdHRlcm4gPSAiWzAtOV0iKSkpICU+JSAjIG5vIG1hdGNoIGluIHN0cl9tYXRjaCgpIHJldHVybnMgTkEKICBtdXRhdGUod29yZCA9IHN0cl9yZXBsYWNlX2FsbChzdHJpbmcgPSB3b3JkLCBwYXR0ZXJuID0gIlxcLiIsIHJlcGxhY2VtZW50ID0gIiIpKSAlPiUKICBtdXRhdGUod29yZCA9IHN0cl9yZXBsYWNlX2FsbChzdHJpbmcgPSB3b3JkLCBwYXR0ZXJuID0gIiguKikncyIsIHJlcGxhY2VtZW50ID0gIlxcMSIpKSAlPiUKICBtdXRhdGUoc3RlbSA9IHN0ZW1fd29yZHMod29yZCkpICU+JQogIAogICMgQ2hvb3NlIGEgcmVwcmVzZW50YW50IGZvciBlYWNoIHN0ZW0sIHRoZSBtb3N0IGNvbW1vbiB0ZXJtIGNvdWxkIGJlIHRoZSBiZXN0CiAgZ3JvdXBfYnkoc3RlbSkgJT4lCiAgbXV0YXRlKG9yaV93b3JkID0gd29yZCkgJT4lCiAgZ3JvdXBfYnkob3JpX3dvcmQpICU+JSAKICBtdXRhdGUobl9vcmkgPSBuKCkpICU+JQogIGFycmFuZ2UoZGVzYyhuX29yaSkpICU+JQogIGdyb3VwX2J5KHN0ZW0pICU+JSAKICBtdXRhdGUod29yZCA9IHdvcmRbMV0pICU+JQogIHNlbGVjdCgtbl9vcmkpICU+JSAKICB1bmdyb3VwKCkgJT4lIAogIAogIGdyb3VwX2J5KHN5bnRhZ211cywgc3RlbSkgJT4lCiAgbXV0YXRlKG5fdG90YWwgPSBuKCkpICU+JQogIGdyb3VwX2J5KHN5bnRhZ211cywgam91cm5hbCwgc3RlbSkgJT4lCiAgbXV0YXRlKG5fam91cm5hbCA9IG4oKSkgJT4lCiAgc2xpY2UoMSkgJT4lCiAgdW5ncm91cCgpICU+JSAKICBzZWxlY3Qoc3ludGFnbXVzLCB3b3JkLCBqb3VybmFsLCBuX2pvdXJuYWwsIG5fdG90YWwpICU+JQogIGFycmFuZ2UoZGVzYyhuX3RvdGFsKSkgJT4lCiAgaWRlbnRpdHkoKQpjb3JwdXNfc3ludGFnbWFfd29yZCAlPiUgCiAgICBkYXRhdGFibGUoZmlsdGVyID0gInRvcCIsIHJvd25hbWVzID0gRkFMU0UsIG9wdGlvbnMgPSBsaXN0KHBhZ2VMZW5ndGggPSAxMCkpCmBgYAoKCgoKCkZpZ3VyZXMgcHJpbnRpbmcgYW5kIHNhdmluZwpgYGB7ciBmaWdfcHJpbnQsIGVjaG8gPSBGQUxTRSwgcmVzdWx0cyA9IEZBTFNFfQojIHBsb3RfZ3JpZChoaXN0bywgc2VsZWN0ZWRfd29yZF90aW1lX3Bsb3QsIG5jb2wgPSAxLCBsYWJlbHMgPSBjKCJBIiwgIkIiKSkgKwojICAgIGdnc2F2ZShmaWxlbmFtZSA9ICIuLi9vdXRwdXQvZmlnMS5zdmciLCB3aWR0aCA9IDIwLCBoZWlnaHQgPSAzMCwgdW5pdHMgPSAiY20iKQoKIyBnZ3NhdmUocGxvdCA9IHRpbWVsaW5lLCBmaWxlbmFtZSA9ICIuLi9vdXRwdXQvdGltZWxpbmUuc3ZnIiwgd2lkdGggPSAyMCwgaGVpZ2h0ID0gMTApCiMgZ2dzYXZlKHBsb3QgPSB0aWxvcywgZmlsZW5hbWUgPSAiLi4vb3V0cHV0L2ZpZ18yXy5zdmciLCB3aWR0aCA9IDE1LCBoZWlnaHQgPSAyMCwgdW5pdHMgPSAiY20iKQpzYXZlX3Bsb3QoZmlsZW5hbWUgPSAiLi4vb3V0cHV0L3dvcmRfdXNhZ2UucGRmIiwgcGxvdCA9IHNlbGVjdGVkX3dvcmRfdGltZV9wbG90LCBiYXNlX2FzcGVjdF9yYXRpbyA9IDEuMiwgYmFzZV9oZWlnaHQgPSA1KQpzYXZlX3Bsb3QoZmlsZW5hbWUgPSAiLi4vb3V0cHV0L2JldGEucGRmIiwgcGxvdCA9IHRpbG9zLCBiYXNlX2FzcGVjdF9yYXRpbyA9IDAuOCwgYmFzZV9oZWlnaHQgPSA0KQpgYGAKCgoKCgpQYWNrYWdlcyBsb2FkaW5nCmBgYHtyIHNldHVwLCBlY2hvID0gRkFMU0UsbWVzc2FnZSA9IEZBTFNFfQp1c2VkX3Bja2dzIDwtIGMoInJlYWRyIiwgCiAgICAgICAgICAgICAgICAicGRmdG9vbHMiLAogICAgICAgICAgICAgICAgImRwbHlyIiwgCiAgICAgICAgICAgICAgICAidGlkeXIiLCAKICAgICAgICAgICAgICAgICJzdHJpbmdyIiwKICAgICAgICAgICAgICAgICJsdWJyaWRhdGUiLAogICAgICAgICAgICAgICAgInRpZHl0ZXh0IiwKICAgICAgICAgICAgICAgICJnZ3Bsb3QyIiwgCiAgICAgICAgICAgICAgICAiY293cGxvdCIsCiAgICAgICAgICAgICAgICAidGV4dHN0ZW0iLAogICAgICAgICAgICAgICAgIkRUIiwKICAgICAgICAgICAgICAgICJnbG1uZXQiKQoKbXlfcGFja2FnZXMgPC0gZnVuY3Rpb24ocGFja2FnZXMsIGluc3RhbGxfcGFja2FnZXMgPSBGQUxTRSl7CiAgdXNlZF9wY2tncyA8LSBwYWNrYWdlcwogIGZvciAocGFja3VzIGluIHVzZWRfcGNrZ3MpIHsKICAgIHBhY2t1cyA8LSBhcy5jaGFyYWN0ZXIocGFja3VzKQogICAgcGNrZ19wcmVzZW50IDwtIAogICAgICByZXF1aXJlKHBhY2t1cywgCiAgICAgICAgICAgICAgY2hhcmFjdGVyLm9ubHkgPSBUUlVFLCAKICAgICAgICAgICAgICBxdWlldGx5ID0gVFJVRSkKICAgIGlmIChwY2tnX3ByZXNlbnQpIHsKICAgICAgbGlicmFyeShwYWNrdXMsIAogICAgICAgICAgICAgIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkKICAgIH0gCiAgICBlbHNlIHsKICAgICAgcHJpbnQocGFzdGUwKCJQYWNrYWdlOiAiLHBhY2t1cywgIiBub3QgZm91bmQiKSkKICAgICAgaWYgKGluc3RhbGxfcGFja2FnZXMpIGluc3RhbGwucGFja2FnZXMocGFja3VzKQogICAgfQogIH0KfQoKbXlfcGFja2FnZXMocGFja2FnZXMgPSB1c2VkX3Bja2dzLCBpbnN0YWxsX3BhY2thZ2VzID0gVCkKZGV2dG9vbHM6OnNlc3Npb25faW5mbygpCmBgYA==