Intro

This is the script that scrapes and assembles the data used by the package. While both the script and the data are included, this script has a very high chance of breaking, given the likelihood of websites or URLs changing, locales differing, etc. If you’d like to assemble the data differently or are just curious how it was assembled, though, this script will be of use.

A function to refresh data is not included in the package because this script is depends on web structures that may vary, requires a lot of dependencies (see below) and is irrelevant to the use of the package. If you do choose to run it, keep in mind that it scrapes a lot of sources; please be curteous and don’t re-scrape more times than necessary. Due to the number and size of sources, it will take a while to run, anyway, and so is probably best run by chunk. While structured as an RMarkdown notebook for ease of documentation and structure, the HTML file it knits is not useful and is thus not included.

Setup

Packages required:

Aside from rvest and tidyverse, most could be fairly easily refactored into an alternative.

library(rvest)
Loading required package: xml2
library(tidyverse)
+ ggplot2 2.2.1.9000        Date: 2017-07-06
+ tibble  1.3.3                R: 3.4.0
+ tidyr   0.6.3.9000         GUI: RStudio 1.0.143
+ readr   1.1.1.9000      Locale: en_US.UTF-8
+ purrr   0.2.2.9000          TZ: America/New_York
+ dplyr   0.7.1.9000      
+ stringr 1.2.0.9000      
Conflicts --------------------------------------------------------------------
* filter(),  from dplyr, masks stats::filter()
* lag(),     from dplyr, masks stats::lag()

Scraping

CIA World Factbook

# CIA World Factbook country names
country_names <- 'https://www.cia.gov/library/publications/the-world-factbook/fields/2142.html' %>%
    read_html() %>%
    html_nodes('table tr[id]') %>%
    { setNames(map(., html_nodes, 'td'), toupper(html_attr(., 'id'))) } %>%
    map_df(~data_frame(
        country = html_text(.x[1]),
        key = map(.x[2], html_nodes, css = 'strong') %>% map(html_text),
        value = map(.x[2], html_nodes, xpath = 'text()') %>%
            map(html_text, trim = TRUE) %>%
            map(discard, `==`, '')
    ), .id = 'gec') %>%
    unnest() %>%
    mutate(key = gsub(':\\s+$|`', '', key),
           key = gsub('etymolgy', 'etymology', key),
           key = gsub('official|Papiamentu', 'local', key),
           key = gsub('English', 'conventional', key),
           key = ifelse(country == 'Curacao',
                        gsub('Dutch', 'conventional', key),
                        gsub('Dutch', 'local', key)),
           country = ifelse(gec == 'AS', 'Australia', country)) %>%
    spread(key, value) %>% 
    mutate(abbreviation = ifelse(country == 'Australia', NA, abbreviation))
# CIA World Factbook country codes
country_codes <- 'https://www.cia.gov/library/publications/the-world-factbook/appendix/appendix-d.html' %>%
    read_html() %>%
    html_nodes('ul#GetAppendix_D li') %>%
    map(html_nodes, css = 'td') %>%
    map(html_text, trim = TRUE) %>%
    map(~.[c(-3, -10)]) %>%
    transpose() %>%
    simplify_all() %>%
    setNames(c('country', 'gec', 'iso2c', 'iso3c', 'iso3n', 'stanag', 'tld', 'comment')) %>%
    as_data_frame() %>%
    mutate_all(na_if, y = '-') %>%
    mutate(comment = na_if(comment, ''))

National Geospatial-Intelligence Agency

# http://geonames.nga.mil/gns/html/countrycodes.html
# http://geonames.nga.mil/gns/html/docs/GENC_ED3U5_GEC_XWALK.xlsx
genc <- rio::import('http://geonames.nga.mil/gns/html/docs/GENC_ED3U5_GEC_XWALK.xlsx', 
                    skip = 2, setclass = 'tbl_df', na = '--') %>% 
    modify(na_if, '[None]')

Wikipedia

# Wikipedia country codes
w <- 'https://en.wikipedia.org/wiki/Category:Lists_of_country_codes' %>%
    read_html() %>%
    html_nodes('a[title*="Country codes:"]') %>%
    html_attr('href') %>%
    paste0('https://en.wikipedia.org', .) %>%
    map(read_html) %>%
    map(html_nodes, 'h2 + table') %>%
    modify_depth(2, html_nodes, 'td') %>%
    map(map_df, ~list(
        key = map(.x, html_nodes, xpath = 'a|text()') %>%
            map(html_text) %>%
            map_chr(paste, collapse = '') %>%
            trimws(),
        value = html_nodes(.x, 'p') %>% html_text()
    ), .id = 'row') %>%
    map_df(spread, key, value) %>%
    select(-row) %>%
    mutate_all(na_if, y = '—') %>% modify(na_if, '-') %>%
    modify(~gsub('\\n', ', ', .x)) %>%
    setNames(c('tld', 'calling', 'mcc', 'gec', 'gs1_gtin', 'icao_aircraft', 'icao_airport', 'ioc', 'iso2c', 'iso3c', 'iso3n', 'itu_callsign', 'itu', 'itu_maritime', 'license_plate', 'marc', 'stanag', 'nato2c', 'undp', 'wmo'))
# # Wikipedia FIFA codes - unused
# fifa <- 'https://en.wikipedia.org/wiki/List_of_FIFA_country_codes' %>%
#     read_html() %>%
#     html_nodes('table.wikitable') %>%
#     map(html_table, fill = TRUE) %>%
#     .[-7:-9] %>%    # remove obsolete codes tables
#     reduce(full_join) %>%
#     mutate(FIFA = coalesce(Code, FIFA)) %>%
#     select(-Code, -Confederation) %>%
#     mutate_all(funs(gsub('\\[.*\\]', '', .))) %>% mutate_all(na_if, y = '') %>%
#     setNames(tolower(names(.))) %>% rename(iso3c = iso)

ITU

Unused except for corrections of Wikipedia innacuracies.

itu <- 'https://www.itu.int/online/mm/scripts/gensel8' %>% 
    read_html() %>% 
    html_node('table') %>% 
    html_table(header = TRUE) %>% 
    select(-5) %>% 
    set_names(c('en_iso', 'itu_region', 'itu', 'tld')) %>% 
    mutate(tld = tolower(tld))

UN ISO regions

unstats <- 'https://unstats.un.org/unsd/methodology/m49/overview/' %>% 
    read_html() %>% 
    html_nodes('table') %>% 
    map_df(~html_table(.x, header = TRUE) %>% 
               mutate(language = tolower(sub('downloadTable', '', 
                                             html_attr(.x, 'id'))))) %>% 
    tbl_df()

OKFN

okfn <- read_csv('https://github.com/datasets/country-codes/raw/master/data/country-codes.csv')

Unicode CLDR

# http://unicode.org/copyright.html
# http://unicode.org/repos/cldr/trunk/unicode-license.txt
# modern
langs_modern <- 'https://github.com/unicode-cldr/cldr-localenames-modern/tree/master/main' %>%
    read_html() %>%
    html_nodes('.content span a') %>% html_text()
unicode_modern <- langs_modern %>%
    set_names(
        paste0('https://github.com/unicode-cldr/cldr-localenames-modern/raw/master/main/',
               ., '/territories.json'),
        .) %>%
    map(jsonlite::fromJSON) %>%
    map(c(1, 1, 2, 1)) %>%
    simplify_all() %>%
    map2(names(.),
         ~set_names(data_frame(names(.x), .x),
                    c('code', .y))) %>%
    reduce(full_join, by = 'code')
# # unused
# lang_codes <- 'https://github.com/unicode-cldr/cldr-localenames-modern/raw/master/main/en-US-POSIX/languages.json' %>%
#     jsonlite::fromJSON() %>%
#     map(c(1,2,1)) %>% .[[1]] %>%
#     simplify()
# 
# lang_code_df <- data_frame(language = lang_codes,
#                            code = names(lang_codes))
unicode_codes <- 'https://github.com/unicode-cldr/cldr-core/raw/master/supplemental/codeMappings.json' %>% 
    jsonlite::fromJSON() %>% 
    .[[1]] %>% .[[2]] %>% 
    bind_rows(.id = 'iso2c') %>% 
    set_names(c('iso2c', 'iso3n', 'iso3c', 'gec', 'tld')) %>% 
    select(-tld) %>% 
    mutate(iso3c = coalesce(iso3c, iso2c), 
           iso2c = ifelse(nchar(iso2c) > 2, NA, iso2c))

Cleaning

countrycode_data_c <- codelist %>% 
    mutate(iso2c = ifelse(genc2c == 'XK', 'XK', iso2c)) %>% 
df <- countrycode::countrycode_data %>%  select(iso2c, matches('regex')) %>% 
    drop_na(iso2c) %>%
    janitor::clean_names() %>% 
    set_names(sub('country_name_', '', names(.)))
Error in codelist %>% mutate(iso2c = ifelse(genc2c == "XK", "XK", iso2c)) %>%  : 
  could not find function "%>%<-"

Joining

cia <- full_join(country_codes_c %>% drop_na(gec), country_names_c)
Joining, by = "gec"
usg <- full_join(genc_c %>% drop_na(gec), cia, by = 'gec') %>%
    mutate(iso3c = coalesce(iso3c.x, iso3c.y),
           iso2c = coalesce(iso2c.x, iso2c.y),
           iso3n = coalesce(iso3n.x, iso3n.y)) %>%
    select(-matches('\\.'))
               # Sacrifice Channel Islands for Sark
ok_un <- okfn_c %>% slice(-1) %>% full_join(unstats_c)
Joining, by = "iso3c"
us_ok_un <- full_join(ok_un, usg, by = 'iso3n') %>%
    mutate(iso3c = coalesce(iso3c.x, iso3c.y),
           iso2c = coalesce(iso2c.x, iso2c.y),
           gec = coalesce(gec.x, gec.y),
           tld = coalesce(tld.x, tld.y)) %>%
    select(-matches('\\.'))
us_ok_un_w <- full_join(us_ok_un, w_c, by = 'iso2c') %>%
    mutate(iso3c = coalesce(iso3c.x, iso3c.y),
           iso3n = coalesce(iso3n.x, iso3n.y),
           gec = coalesce(gec.x, gec.y),
           marc = coalesce(marc.x, marc.y),
           # wmo = coalesce(wmo.x, wmo.y),    # w/okfn codes differ, and no official list to verify
           calling = coalesce(calling.x, calling.y),
           ioc = coalesce(ioc.x, ioc.y),
           stanag = coalesce(stanag.x, stanag.y),
           tld = coalesce(tld.x, tld.y)) %>%
    select(-matches('\\.'))
unicode <- unicode_codes %>% 
    drop_na(iso2c) %>% 
    right_join(unicode_modern_c, by = 'iso2c') %>% 
    mutate(iso3n = coalesce(iso3n.x, iso3n.y)) %>% 
    select(-matches('\\.')) %>% 
    mutate(iso3n = case_when(iso2c == 'CP' ~ '905',
                             iso2c == 'DG' ~ '908',
                             iso2c == 'XK' ~ '901',
                             TRUE ~ iso3n),
           iso3c = ifelse(iso2c == 'XK', NA, iso3c))
countries <- full_join(unicode, us_ok_un_w, by = c('iso3n', 'iso2c', 'alt')) %>% 
    mutate(iso3c = coalesce(iso3c.x, iso3c.y), 
           gec = coalesce(gec.x, gec.y)) %>% 
    select(-matches('\\.'))
countries <- left_join(countries, countrycode_data_c)
Joining, by = "iso2c"
# check code duplication
us_ok_un_w %>% names() %>% 
    map_int(~ countries %>% 
                filter(is.na(alt)) %>% 
                group_by_(.dots = .x) %>% 
                filter(n() > 1) %>% 
                select(gec, en, iso3c, iso2c, iso3n) %>% 
                .[!is.na(.[[.x]]),] %>% 
                nrow()) %>% 
    set_names(names(us_ok_un_w))
Adding missing grouping variables: `en_iso`
Adding missing grouping variables: `fr_iso`
Adding missing grouping variables: `fifa`
Adding missing grouping variables: `gaul`
Adding missing grouping variables: `iso4217_3c`
Adding missing grouping variables: `iso4217_name`
Adding missing grouping variables: `iso4217_3n`
Adding missing grouping variables: `is_independent`
Adding missing grouping variables: `capital`
Adding missing grouping variables: `continent`
Adding missing grouping variables: `edgar`
Adding missing grouping variables: `un_region_code`
Adding missing grouping variables: `un_subregion_code`
Adding missing grouping variables: `un_intermediate_region_code`
Adding missing grouping variables: `m49`
Adding missing grouping variables: `ldc`
Adding missing grouping variables: `lldc`
Adding missing grouping variables: `sids`
Adding missing grouping variables: `is_developed`
Adding missing grouping variables: `ar_un`
Adding missing grouping variables: `ar_un_intermediate_region`
Adding missing grouping variables: `ar_un_region`
Adding missing grouping variables: `ar_un_subregion`
Adding missing grouping variables: `en_un`
Adding missing grouping variables: `en_un_intermediate_region`
Adding missing grouping variables: `en_un_region`
Adding missing grouping variables: `en_un_subregion`
Adding missing grouping variables: `es_un`
Adding missing grouping variables: `es_un_intermediate_region`
Adding missing grouping variables: `es_un_region`
Adding missing grouping variables: `es_un_subregion`
Adding missing grouping variables: `fr_un`
Adding missing grouping variables: `fr_un_intermediate_region`
Adding missing grouping variables: `fr_un_region`
Adding missing grouping variables: `fr_un_subregion`
Adding missing grouping variables: `ru_un`
Adding missing grouping variables: `ru_un_intermediate_region`
Adding missing grouping variables: `ru_un_region`
Adding missing grouping variables: `ru_un_subregion`
Adding missing grouping variables: `zh_un`
Adding missing grouping variables: `zh_un_intermediate_region`
Adding missing grouping variables: `zh_un_region`
Adding missing grouping variables: `zh_un_subregion`
Adding missing grouping variables: `en_cia_abbreviation`
Adding missing grouping variables: `alt`
Adding missing grouping variables: `en_cia`
Adding missing grouping variables: `en_cia_local`
Adding missing grouping variables: `mcc`
Adding missing grouping variables: `icao_aircraft`
Adding missing grouping variables: `icao_airport`
Adding missing grouping variables: `itu_callsign`
Adding missing grouping variables: `itu`
Adding missing grouping variables: `itu_maritime`
Adding missing grouping variables: `license_plate`
Adding missing grouping variables: `nato2c`
Adding missing grouping variables: `undp`
Adding missing grouping variables: `marc`
Adding missing grouping variables: `calling`
Adding missing grouping variables: `ioc`
Adding missing grouping variables: `stanag`
Adding missing grouping variables: `tld`
                     en_iso                      fr_iso 
                          0                           0 
                       fifa                        gaul 
                          0                           0 
                 iso4217_3c                iso4217_name 
                        104                         104 
                 iso4217_3n              is_independent 
                        104                         245 
                    capital                   continent 
                          2                         208 
                      edgar              un_region_code 
                          0                         248 
          un_subregion_code un_intermediate_region_code 
                        248                         108 
                        m49                         ldc 
                          0                         249 
                       lldc                        sids 
                        249                         249 
               is_developed                       ar_un 
                        248                           0 
  ar_un_intermediate_region                ar_un_region 
                        108                         248 
            ar_un_subregion                       en_un 
                        248                           0 
  en_un_intermediate_region                en_un_region 
                        108                         248 
            en_un_subregion                       es_un 
                        248                           0 
  es_un_intermediate_region                es_un_region 
                        108                         248 
            es_un_subregion                       fr_un 
                        248                           0 
  fr_un_intermediate_region                fr_un_region 
                        108                         248 
            fr_un_subregion                       ru_un 
                        248                           0 
  ru_un_intermediate_region                ru_un_region 
                        108                         248 
            ru_un_subregion                       zh_un 
                        248                           0 
  zh_un_intermediate_region                zh_un_region 
                        108                         248 
            zh_un_subregion         en_cia_abbreviation 
                        248                           0 
                        alt                      en_cia 
                          0                           0 
               en_cia_local                       iso2c 
                          0                           0 
                        mcc               icao_aircraft 
                         20                          39 
               icao_airport                itu_callsign 
                         25                           3 
                        itu                itu_maritime 
                          0                           0 
              license_plate                      nato2c 
                          9                           0 
                       undp                       iso3c 
                          0                           0 
                      iso3n                         gec 
                          0                           0 
                       marc                     calling 
                          3                          32 
                        ioc                      stanag 
                          0                          22 
                        tld 
                          5 

Documenting

countries_colnames <- names(countries)
codes <- data_frame(column = countries_colnames, 
                 code = gsub('_', '-', column)) %>% 
    mutate(expansion = map(code, safely(NLP::parse_IETF_language_tag), expand = TRUE), 
           expansion = map(expansion, c(1, 1)), 
           expansion = map(expansion, ~if(length(.x) == 0) {c(Language = NA_character_)} else .x), 
           expansion = map(expansion, map_df, ~suppressWarnings(na_if(toString(na.omit(.x)), ''))), 
           expansion = map(expansion, ~set_names(.x, sub('=.*', '', names(.x))))) %>% 
    unnest() %>% 
    mutate(Language = case_when(column == 'alt' ~ NA_character_,
                                column == 'mcc' ~ NA_character_,
                                column == 'tld' ~ NA_character_,
                                TRUE ~ Language),
           Variant = ifelse(column == 'en_us_posix', 'POSIX', Variant),
           Variant = ifelse(grepl('_iso', column), 'ISO', Variant),
           Variant = ifelse(grepl('_cia', column), 'CIA World Factbook', Variant),
           Extension = ifelse(grepl('_cia_', column), 
                              sub('en_cia_', '', column), Extension),
           name = case_when(
               column == 'iso2c' ~ 'ISO 3166-1 Alpha-2 code',
               column == 'iso3c' ~ 'ISO 3166-1 Alpha-3 code',
               column == 'iso3n' ~ 'ISO 3166-1 numeric code',
               column == 'en_iso' ~ 'ISO English name',
               column == 'fr_iso' ~ 'ISO French name',
               column == 'gec' ~ 'Geopolitical Entities and Codes',
               column == 'fifa' ~ 'FIFA (Fédération Internationale de Football Association) code',
               column == 'gaul' ~ 'Global Administrative Unit Layers from the Food and Agriculture Organization (FAO) code',
               column == 'iso4217_3c' ~ 'ISO 4217 3-character currency code',
               column == 'iso4217_name' ~ 'ISO 4217 currency name',
               column == 'iso4217_3n' ~ 'ISO 4217 numeric currency code',
               column == 'is_independent' ~ 'Country sovereignty status from the CIA World Factbook',
               column == 'capital' ~ 'Capital city',
               column == 'edgar' ~ 'EDGAR country code from the SEC',
               column == 'en_cia' ~ 'Country names from the CIA World Factbook',
               column == 'en_cia_local' ~ 'Local country names from the CIA World Factbook',
               column == 'en_cia_abbreviation' ~ 'Commonly used country abbreviations from the CIA World Factbook.',
               column == 'mcc' ~ 'International Telecommunication Union (ITU) Telecommunication Standardization Sector (ITU-T) E.212 Mobile Country Code',
               column == 'itu_callsign' ~ 'International Telecommunication Union (ITU) callsign prefixes for radio and television stations',
               column == 'itu' ~ 'International Telecommunication Union (ITU) 1-3 character country code',
               column == 'itu_maritime' ~ 'International Telecommunication Union (ITU) Maritime Identification Digits',
               column == 'license_plate' ~ 'Motor vehicle licence plate country code',
               column == 'stanag' ~ 'North Atlantic Treaty Organization (NATO/OTAN) STANAG 1059 Letter Codes for Geographical Entities',
               column == 'nato2c' ~ 'North Atlantic Treaty Organization (NATO/OTAN) 2-letter code.',
               column == 'undp' ~ 'United Nations Development Programme (UNDP) country code',
               column == 'marc' ~ 'MAchine-Readable Cataloging (MARC) codes from the US Library of Congress',
               column == 'calling' ~ 'International Telecommunication Union (ITU) Telecommunication Standardization Sector (ITU-T) E.164 international telephone calling code',
               column == 'ioc' ~ 'International Olympic Committee country code',
               column == 'tld' ~ 'Internet Assigned Numbers Authority (IANA) country code top-level domain',
               column == 'm49' ~ 'United Nations Statistics Division (UNSD) M.49 area code',
               column == 'ldc' ~ 'United Nations (UN) Least Developed Countries',
               column == 'lldc' ~ 'United Nations (UN) Land Locked Developing Countries',
               column == 'sids' ~ 'United Nations (UN) Small Island Developing States',
               column == 'is_developed' ~ 'United Nations (UN) development status',
               grepl('_un', column) ~ 'United Nations (UN) Geoscheme region name',
               TRUE ~ NA_character_
           ),
           notes = case_when(
               column == 'gec' ~ 'Formerly FIPS Pub 10-4, which was withdrawn by NIST in 2008. Maintained until 2014 by the National Geospatial-Intelligence Agency (NGA), after which it was frozen and superceded by GENC, the US government profile of ISO 3166.',
               column == 'en_iso' ~ 'Does not include Taiwan, which is not a member of the UN. A few use uncommon offical forms, including North and South Korea and Bolivia.',
               column == 'fr_iso' ~ 'Does not include Taiwan, which is not a member of the UN. A few use uncommon offical forms, including North and South Korea and Bolivia.',
               column == 'en_cia' ~ 'Many short and long forms. Uses "Burma" instead of "Myanmar".',
               column == 'en_cia_local' ~ 'Many short and long forms. Includes alternatives inline. Transliterates to Latin script.',
               column == 'en_cia_abbreviation' ~ 'Only included where commonly used. Includes alternatives inline.',
               column == 'mcc' ~ 'Includes ranges.',
               column == 'itu_callsign' ~ 'Includes ranges.',
               column == 'itu_maritime' ~ 'Includes ranges.',
               column == 'nato2c' ~ 'Officially deprecated in favor of STANAG 1059 (see "stanag").',
               column == 'tld' ~ 'Includes leading period.',
               grepl('_un_region', column) ~ 'Continent',
               grepl('regex', column) ~ 'Regex used for `parse_country`.',
               TRUE ~ NA_character_
           )) %>% 
    janitor::clean_names() %>% 
    arrange(column) %>% 
    select(1:2, 8:9, 3:7)

Saving

# to avoid ASCII CRAN warning
codes <- codes %>% modify(stringi::stri_trans_general, 'Latin-ASCII')
devtools::use_data(countries, countries_colnames, 
                   internal = TRUE, overwrite = TRUE)
Saving countries, countries_colnames as sysdata.rda to /Users/alistaire/Documents/R_projects/passport/R
devtools::use_data(codes, overwrite = TRUE)
Saving codes as codes.rda to /Users/alistaire/Documents/R_projects/passport/data

Licensing

Data is licensed according to its source, most of which are in the public domain. Exceptions include

LS0tCnRpdGxlOiAiQ291bnRyeSBuYW1lIGFuZCBjb2RlIGFnZ3JlZ2F0aW9uIgphdXRob3I6ICJFZHdhcmQgVmlzZWwiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMjIEludHJvCgpUaGlzIGlzIHRoZSBzY3JpcHQgdGhhdCBzY3JhcGVzIGFuZCBhc3NlbWJsZXMgdGhlIGRhdGEgdXNlZCBieSB0aGUgcGFja2FnZS4gCldoaWxlIGJvdGggdGhlIHNjcmlwdCBhbmQgdGhlIGRhdGEgYXJlIGluY2x1ZGVkLCB0aGlzIHNjcmlwdCBoYXMgYSB2ZXJ5IGhpZ2ggCmNoYW5jZSBvZiBicmVha2luZywgZ2l2ZW4gdGhlIGxpa2VsaWhvb2Qgb2Ygd2Vic2l0ZXMgb3IgVVJMcyBjaGFuZ2luZywgbG9jYWxlcyAKZGlmZmVyaW5nLCBldGMuIElmIHlvdSdkIGxpa2UgdG8gYXNzZW1ibGUgdGhlIGRhdGEgZGlmZmVyZW50bHkgb3IgYXJlIGp1c3QgCmN1cmlvdXMgaG93IGl0IHdhcyBhc3NlbWJsZWQsIHRob3VnaCwgdGhpcyBzY3JpcHQgd2lsbCBiZSBvZiB1c2UuCgpBIGZ1bmN0aW9uIHRvIHJlZnJlc2ggZGF0YSBpcyBub3QgaW5jbHVkZWQgaW4gdGhlIHBhY2thZ2UgYmVjYXVzZSB0aGlzIHNjcmlwdCBpcwpkZXBlbmRzIG9uIHdlYiBzdHJ1Y3R1cmVzIHRoYXQgbWF5IHZhcnksIHJlcXVpcmVzIGEgbG90IG9mIGRlcGVuZGVuY2llcyAoc2VlIApiZWxvdykgYW5kIGlzIGlycmVsZXZhbnQgdG8gdGhlIHVzZSBvZiB0aGUgcGFja2FnZS4gSWYgeW91IGRvIGNob29zZSB0byBydW4gaXQsIAprZWVwIGluIG1pbmQgdGhhdCBpdCBzY3JhcGVzIGEgbG90IG9mIHNvdXJjZXM7IHBsZWFzZSBiZSBjdXJ0ZW91cyBhbmQgZG9uJ3QgCnJlLXNjcmFwZSBtb3JlIHRpbWVzIHRoYW4gbmVjZXNzYXJ5LiBEdWUgdG8gdGhlIG51bWJlciBhbmQgc2l6ZSBvZiBzb3VyY2VzLCBpdCAKd2lsbCB0YWtlIGEgd2hpbGUgdG8gcnVuLCBhbnl3YXksIGFuZCBzbyBpcyBwcm9iYWJseSBiZXN0IHJ1biBieSBjaHVuay4gV2hpbGUgCnN0cnVjdHVyZWQgYXMgYW4gUk1hcmtkb3duIG5vdGVib29rIGZvciBlYXNlIG9mIGRvY3VtZW50YXRpb24gYW5kIHN0cnVjdHVyZSwgdGhlCkhUTUwgZmlsZSBpdCBrbml0cyBpcyBub3QgdXNlZnVsIGFuZCBpcyB0aHVzIG5vdCBpbmNsdWRlZC4KCiMjIFNldHVwCgpQYWNrYWdlcyByZXF1aXJlZDogCgotIHJ2ZXN0Ci0gdGlkeXZlcnNlIChkcGx5ciwgcHVycnIsIHJlYWRyLCB0aWR5ciksIAotIHJpbyAod3JhcHBpbmcgcmVhZHhsKQotIGpzb25saXRlIChmb3IgZnJvbUpTT04pCi0gY291bnRyeWNvZGUgKGZvciByZWdleCBkYXRhKQotIE5MUCAoZm9yIHBhcnNlX0lFVEZfbGFuZ3VhZ2VfdGFnKQotIGphbml0b3IgKGZvciBjbGVhbl9uYW1lcykKLSBzdHJpbmdpICh0byBlbmNvZGUgVW5pY29kZSBjaGFyYWN0ZXJzIGZvciBDUkFOKQotIGRldnRvb2xzICh0byBhZGQgdG8gcGFja2FnZSkKCkFzaWRlIGZyb20gcnZlc3QgYW5kIHRpZHl2ZXJzZSwgbW9zdCBjb3VsZCBiZSBmYWlybHkgZWFzaWx5IHJlZmFjdG9yZWQgaW50byBhbiAKYWx0ZXJuYXRpdmUuCgpgYGB7ciBzZXR1cH0KbGlicmFyeShydmVzdCkKbGlicmFyeSh0aWR5dmVyc2UpCmBgYAoKIyMgU2NyYXBpbmcKCiMjIyBDSUEgV29ybGQgRmFjdGJvb2sKYGBge3IgY2lhfQojIENJQSBXb3JsZCBGYWN0Ym9vayBjb3VudHJ5IG5hbWVzCmNvdW50cnlfbmFtZXMgPC0gJ2h0dHBzOi8vd3d3LmNpYS5nb3YvbGlicmFyeS9wdWJsaWNhdGlvbnMvdGhlLXdvcmxkLWZhY3Rib29rL2ZpZWxkcy8yMTQyLmh0bWwnICU+JQogICAgcmVhZF9odG1sKCkgJT4lCiAgICBodG1sX25vZGVzKCd0YWJsZSB0cltpZF0nKSAlPiUKICAgIHsgc2V0TmFtZXMobWFwKC4sIGh0bWxfbm9kZXMsICd0ZCcpLCB0b3VwcGVyKGh0bWxfYXR0ciguLCAnaWQnKSkpIH0gJT4lCiAgICBtYXBfZGYofmRhdGFfZnJhbWUoCiAgICAgICAgY291bnRyeSA9IGh0bWxfdGV4dCgueFsxXSksCiAgICAgICAga2V5ID0gbWFwKC54WzJdLCBodG1sX25vZGVzLCBjc3MgPSAnc3Ryb25nJykgJT4lIG1hcChodG1sX3RleHQpLAogICAgICAgIHZhbHVlID0gbWFwKC54WzJdLCBodG1sX25vZGVzLCB4cGF0aCA9ICd0ZXh0KCknKSAlPiUKICAgICAgICAgICAgbWFwKGh0bWxfdGV4dCwgdHJpbSA9IFRSVUUpICU+JQogICAgICAgICAgICBtYXAoZGlzY2FyZCwgYD09YCwgJycpCiAgICApLCAuaWQgPSAnZ2VjJykgJT4lCiAgICB1bm5lc3QoKSAlPiUKICAgIG11dGF0ZShrZXkgPSBnc3ViKCc6XFxzKyR8YCcsICcnLCBrZXkpLAogICAgICAgICAgIGtleSA9IGdzdWIoJ2V0eW1vbGd5JywgJ2V0eW1vbG9neScsIGtleSksCiAgICAgICAgICAga2V5ID0gZ3N1Yignb2ZmaWNpYWx8UGFwaWFtZW50dScsICdsb2NhbCcsIGtleSksCiAgICAgICAgICAga2V5ID0gZ3N1YignRW5nbGlzaCcsICdjb252ZW50aW9uYWwnLCBrZXkpLAogICAgICAgICAgIGtleSA9IGlmZWxzZShjb3VudHJ5ID09ICdDdXJhY2FvJywKICAgICAgICAgICAgICAgICAgICAgICAgZ3N1YignRHV0Y2gnLCAnY29udmVudGlvbmFsJywga2V5KSwKICAgICAgICAgICAgICAgICAgICAgICAgZ3N1YignRHV0Y2gnLCAnbG9jYWwnLCBrZXkpKSwKICAgICAgICAgICBjb3VudHJ5ID0gaWZlbHNlKGdlYyA9PSAnQVMnLCAnQXVzdHJhbGlhJywgY291bnRyeSkpICU+JQogICAgc3ByZWFkKGtleSwgdmFsdWUpICU+JSAKICAgIG11dGF0ZShhYmJyZXZpYXRpb24gPSBpZmVsc2UoY291bnRyeSA9PSAnQXVzdHJhbGlhJywgTkEsIGFiYnJldmlhdGlvbikpCgoKIyBDSUEgV29ybGQgRmFjdGJvb2sgY291bnRyeSBjb2Rlcwpjb3VudHJ5X2NvZGVzIDwtICdodHRwczovL3d3dy5jaWEuZ292L2xpYnJhcnkvcHVibGljYXRpb25zL3RoZS13b3JsZC1mYWN0Ym9vay9hcHBlbmRpeC9hcHBlbmRpeC1kLmh0bWwnICU+JQogICAgcmVhZF9odG1sKCkgJT4lCiAgICBodG1sX25vZGVzKCd1bCNHZXRBcHBlbmRpeF9EIGxpJykgJT4lCiAgICBtYXAoaHRtbF9ub2RlcywgY3NzID0gJ3RkJykgJT4lCiAgICBtYXAoaHRtbF90ZXh0LCB0cmltID0gVFJVRSkgJT4lCiAgICBtYXAofi5bYygtMywgLTEwKV0pICU+JQogICAgdHJhbnNwb3NlKCkgJT4lCiAgICBzaW1wbGlmeV9hbGwoKSAlPiUKICAgIHNldE5hbWVzKGMoJ2NvdW50cnknLCAnZ2VjJywgJ2lzbzJjJywgJ2lzbzNjJywgJ2lzbzNuJywgJ3N0YW5hZycsICd0bGQnLCAnY29tbWVudCcpKSAlPiUKICAgIGFzX2RhdGFfZnJhbWUoKSAlPiUKICAgIG11dGF0ZV9hbGwobmFfaWYsIHkgPSAnLScpICU+JQogICAgbXV0YXRlKGNvbW1lbnQgPSBuYV9pZihjb21tZW50LCAnJykpCmBgYAoKIyMjIE5hdGlvbmFsIEdlb3NwYXRpYWwtSW50ZWxsaWdlbmNlIEFnZW5jeQpgYGB7ciBnZW5jfQojIGh0dHA6Ly9nZW9uYW1lcy5uZ2EubWlsL2ducy9odG1sL2NvdW50cnljb2Rlcy5odG1sCiMgaHR0cDovL2dlb25hbWVzLm5nYS5taWwvZ25zL2h0bWwvZG9jcy9HRU5DX0VEM1U1X0dFQ19YV0FMSy54bHN4CgpnZW5jIDwtIHJpbzo6aW1wb3J0KCdodHRwOi8vZ2VvbmFtZXMubmdhLm1pbC9nbnMvaHRtbC9kb2NzL0dFTkNfRUQzVTVfR0VDX1hXQUxLLnhsc3gnLCAKICAgICAgICAgICAgICAgICAgICBza2lwID0gMiwgc2V0Y2xhc3MgPSAndGJsX2RmJywgbmEgPSAnLS0nKSAlPiUgCiAgICBtb2RpZnkobmFfaWYsICdbTm9uZV0nKQpgYGAKCiMjIyBXaWtpcGVkaWEKYGBge3Igd2lraXBlZGlhfQojIFdpa2lwZWRpYSBjb3VudHJ5IGNvZGVzCncgPC0gJ2h0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0NhdGVnb3J5Okxpc3RzX29mX2NvdW50cnlfY29kZXMnICU+JQogICAgcmVhZF9odG1sKCkgJT4lCiAgICBodG1sX25vZGVzKCdhW3RpdGxlKj0iQ291bnRyeSBjb2RlczoiXScpICU+JQogICAgaHRtbF9hdHRyKCdocmVmJykgJT4lCiAgICBwYXN0ZTAoJ2h0dHBzOi8vZW4ud2lraXBlZGlhLm9yZycsIC4pICU+JQogICAgbWFwKHJlYWRfaHRtbCkgJT4lCiAgICBtYXAoaHRtbF9ub2RlcywgJ2gyICsgdGFibGUnKSAlPiUKICAgIG1vZGlmeV9kZXB0aCgyLCBodG1sX25vZGVzLCAndGQnKSAlPiUKICAgIG1hcChtYXBfZGYsIH5saXN0KAogICAgICAgIGtleSA9IG1hcCgueCwgaHRtbF9ub2RlcywgeHBhdGggPSAnYXx0ZXh0KCknKSAlPiUKICAgICAgICAgICAgbWFwKGh0bWxfdGV4dCkgJT4lCiAgICAgICAgICAgIG1hcF9jaHIocGFzdGUsIGNvbGxhcHNlID0gJycpICU+JQogICAgICAgICAgICB0cmltd3MoKSwKICAgICAgICB2YWx1ZSA9IGh0bWxfbm9kZXMoLngsICdwJykgJT4lIGh0bWxfdGV4dCgpCiAgICApLCAuaWQgPSAncm93JykgJT4lCiAgICBtYXBfZGYoc3ByZWFkLCBrZXksIHZhbHVlKSAlPiUKICAgIHNlbGVjdCgtcm93KSAlPiUKICAgIG11dGF0ZV9hbGwobmFfaWYsIHkgPSAn4oCUJykgJT4lIG1vZGlmeShuYV9pZiwgJy0nKSAlPiUKICAgIG1vZGlmeSh+Z3N1YignXFxuJywgJywgJywgLngpKSAlPiUKICAgIHNldE5hbWVzKGMoJ3RsZCcsICdjYWxsaW5nJywgJ21jYycsICdnZWMnLCAnZ3MxX2d0aW4nLCAnaWNhb19haXJjcmFmdCcsICdpY2FvX2FpcnBvcnQnLCAnaW9jJywgJ2lzbzJjJywgJ2lzbzNjJywgJ2lzbzNuJywgJ2l0dV9jYWxsc2lnbicsICdpdHUnLCAnaXR1X21hcml0aW1lJywgJ2xpY2Vuc2VfcGxhdGUnLCAnbWFyYycsICdzdGFuYWcnLCAnbmF0bzJjJywgJ3VuZHAnLCAnd21vJykpCgoKIyAjIFdpa2lwZWRpYSBGSUZBIGNvZGVzIC0gdW51c2VkCiMgZmlmYSA8LSAnaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvTGlzdF9vZl9GSUZBX2NvdW50cnlfY29kZXMnICU+JQojICAgICByZWFkX2h0bWwoKSAlPiUKIyAgICAgaHRtbF9ub2RlcygndGFibGUud2lraXRhYmxlJykgJT4lCiMgICAgIG1hcChodG1sX3RhYmxlLCBmaWxsID0gVFJVRSkgJT4lCiMgICAgIC5bLTc6LTldICU+JSAgICAjIHJlbW92ZSBvYnNvbGV0ZSBjb2RlcyB0YWJsZXMKIyAgICAgcmVkdWNlKGZ1bGxfam9pbikgJT4lCiMgICAgIG11dGF0ZShGSUZBID0gY29hbGVzY2UoQ29kZSwgRklGQSkpICU+JQojICAgICBzZWxlY3QoLUNvZGUsIC1Db25mZWRlcmF0aW9uKSAlPiUKIyAgICAgbXV0YXRlX2FsbChmdW5zKGdzdWIoJ1xcWy4qXFxdJywgJycsIC4pKSkgJT4lIG11dGF0ZV9hbGwobmFfaWYsIHkgPSAnJykgJT4lCiMgICAgIHNldE5hbWVzKHRvbG93ZXIobmFtZXMoLikpKSAlPiUgcmVuYW1lKGlzbzNjID0gaXNvKQpgYGAKCiMjIyBJVFUKVW51c2VkIGV4Y2VwdCBmb3IgY29ycmVjdGlvbnMgb2YgV2lraXBlZGlhIGlubmFjdXJhY2llcy4KYGBge3IgaXR1fQppdHUgPC0gJ2h0dHBzOi8vd3d3Lml0dS5pbnQvb25saW5lL21tL3NjcmlwdHMvZ2Vuc2VsOCcgJT4lIAogICAgcmVhZF9odG1sKCkgJT4lIAogICAgaHRtbF9ub2RlKCd0YWJsZScpICU+JSAKICAgIGh0bWxfdGFibGUoaGVhZGVyID0gVFJVRSkgJT4lIAogICAgc2VsZWN0KC01KSAlPiUgCiAgICBzZXRfbmFtZXMoYygnZW5faXNvJywgJ2l0dV9yZWdpb24nLCAnaXR1JywgJ3RsZCcpKSAlPiUgCiAgICBtdXRhdGUodGxkID0gdG9sb3dlcih0bGQpKQpgYGAKCgojIyMgVU4gSVNPIHJlZ2lvbnMKYGBge3IgcmVnaW9uc30KdW5zdGF0cyA8LSAnaHR0cHM6Ly91bnN0YXRzLnVuLm9yZy91bnNkL21ldGhvZG9sb2d5L200OS9vdmVydmlldy8nICU+JSAKICAgIHJlYWRfaHRtbCgpICU+JSAKICAgIGh0bWxfbm9kZXMoJ3RhYmxlJykgJT4lIAogICAgbWFwX2RmKH5odG1sX3RhYmxlKC54LCBoZWFkZXIgPSBUUlVFKSAlPiUgCiAgICAgICAgICAgICAgIG11dGF0ZShsYW5ndWFnZSA9IHRvbG93ZXIoc3ViKCdkb3dubG9hZFRhYmxlJywgJycsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBodG1sX2F0dHIoLngsICdpZCcpKSkpKSAlPiUgCiAgICB0YmxfZGYoKQpgYGAKCiMjIyBPS0ZOCmBgYHtyIG9rZm59Cm9rZm4gPC0gcmVhZF9jc3YoJ2h0dHBzOi8vZ2l0aHViLmNvbS9kYXRhc2V0cy9jb3VudHJ5LWNvZGVzL3Jhdy9tYXN0ZXIvZGF0YS9jb3VudHJ5LWNvZGVzLmNzdicpCmBgYAoKIyMjIFVuaWNvZGUgQ0xEUgpgYGB7ciB1bmljb2RlfQojIGh0dHA6Ly91bmljb2RlLm9yZy9jb3B5cmlnaHQuaHRtbAojIGh0dHA6Ly91bmljb2RlLm9yZy9yZXBvcy9jbGRyL3RydW5rL3VuaWNvZGUtbGljZW5zZS50eHQKCiMgbW9kZXJuCmxhbmdzX21vZGVybiA8LSAnaHR0cHM6Ly9naXRodWIuY29tL3VuaWNvZGUtY2xkci9jbGRyLWxvY2FsZW5hbWVzLW1vZGVybi90cmVlL21hc3Rlci9tYWluJyAlPiUKICAgIHJlYWRfaHRtbCgpICU+JQogICAgaHRtbF9ub2RlcygnLmNvbnRlbnQgc3BhbiBhJykgJT4lIGh0bWxfdGV4dCgpCgp1bmljb2RlX21vZGVybiA8LSBsYW5nc19tb2Rlcm4gJT4lCiAgICBzZXRfbmFtZXMoCiAgICAgICAgcGFzdGUwKCdodHRwczovL2dpdGh1Yi5jb20vdW5pY29kZS1jbGRyL2NsZHItbG9jYWxlbmFtZXMtbW9kZXJuL3Jhdy9tYXN0ZXIvbWFpbi8nLAogICAgICAgICAgICAgICAuLCAnL3RlcnJpdG9yaWVzLmpzb24nKSwKICAgICAgICAuKSAlPiUKICAgIG1hcChqc29ubGl0ZTo6ZnJvbUpTT04pICU+JQogICAgbWFwKGMoMSwgMSwgMiwgMSkpICU+JQogICAgc2ltcGxpZnlfYWxsKCkgJT4lCiAgICBtYXAyKG5hbWVzKC4pLAogICAgICAgICB+c2V0X25hbWVzKGRhdGFfZnJhbWUobmFtZXMoLngpLCAueCksCiAgICAgICAgICAgICAgICAgICAgYygnY29kZScsIC55KSkpICU+JQogICAgcmVkdWNlKGZ1bGxfam9pbiwgYnkgPSAnY29kZScpCgojICMgdW51c2VkCiMgbGFuZ19jb2RlcyA8LSAnaHR0cHM6Ly9naXRodWIuY29tL3VuaWNvZGUtY2xkci9jbGRyLWxvY2FsZW5hbWVzLW1vZGVybi9yYXcvbWFzdGVyL21haW4vZW4tVVMtUE9TSVgvbGFuZ3VhZ2VzLmpzb24nICU+JQojICAgICBqc29ubGl0ZTo6ZnJvbUpTT04oKSAlPiUKIyAgICAgbWFwKGMoMSwyLDEpKSAlPiUgLltbMV1dICU+JQojICAgICBzaW1wbGlmeSgpCiMgCiMgbGFuZ19jb2RlX2RmIDwtIGRhdGFfZnJhbWUobGFuZ3VhZ2UgPSBsYW5nX2NvZGVzLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvZGUgPSBuYW1lcyhsYW5nX2NvZGVzKSkKCnVuaWNvZGVfY29kZXMgPC0gJ2h0dHBzOi8vZ2l0aHViLmNvbS91bmljb2RlLWNsZHIvY2xkci1jb3JlL3Jhdy9tYXN0ZXIvc3VwcGxlbWVudGFsL2NvZGVNYXBwaW5ncy5qc29uJyAlPiUgCiAgICBqc29ubGl0ZTo6ZnJvbUpTT04oKSAlPiUgCiAgICAuW1sxXV0gJT4lIC5bWzJdXSAlPiUgCiAgICBiaW5kX3Jvd3MoLmlkID0gJ2lzbzJjJykgJT4lIAogICAgc2V0X25hbWVzKGMoJ2lzbzJjJywgJ2lzbzNuJywgJ2lzbzNjJywgJ2dlYycsICd0bGQnKSkgJT4lIAogICAgc2VsZWN0KC10bGQpICU+JSAKICAgIG11dGF0ZShpc28zYyA9IGNvYWxlc2NlKGlzbzNjLCBpc28yYyksIAogICAgICAgICAgIGlzbzJjID0gaWZlbHNlKG5jaGFyKGlzbzJjKSA+IDIsIE5BLCBpc28yYykpCmBgYAoKIyMgQ2xlYW5pbmcKYGBge3IgY2xlYW5pbmd9CiMgY2xlYW5pbmcKY291bnRyeV9jb2Rlc19jIDwtIGNvdW50cnlfY29kZXMgJT4lIHNlbGVjdCgtY291bnRyeSwgLWNvbW1lbnQpCgpjb3VudHJ5X25hbWVzX2MgPC0gY291bnRyeV9uYW1lcyAlPiUKICAgIHNlbGVjdCgtY291bnRyeSwgLWV0eW1vbG9neSwgLW5vdGUsIC1mb3JtZXIpICU+JQogICAgbXV0YXRlX2FsbChmdW5zKG5hX2lmKC4sICdub25lJykpKSAlPiUKICAgIGphbml0b3I6OmNsZWFuX25hbWVzKCkgJT4lCiAgICBzZXRfbmFtZXMoZ3N1YignY29udmVudGlvbmFsX3xfZm9ybScsICcnLCBuYW1lcyguKSkpICU+JQogICAgc2V0X25hbWVzKGMoJ2dlYycsIHBhc3RlMCgnZW5fY2lhXycsIG5hbWVzKC4pWy0xXSkpKQoKY291bnRyeV9uYW1lc19jIDwtIGNvdW50cnlfbmFtZXNfYyAlPiUgCiAgICBtdXRhdGUoZW5fY2lhX2xvbmcgPSBjb2FsZXNjZShlbl9jaWFfbG9uZywgZW5fY2lhX3Nob3J0KSwgCiAgICAgICAgICAgZW5fY2lhX2xvY2FsX2xvbmcgPSBjb2FsZXNjZShlbl9jaWFfbG9jYWxfbG9uZywgZW5fY2lhX2xvY2FsX3Nob3J0KSkgJT4lCiAgICBnYXRoZXIoY29kZSwgbmFtZSwgLWdlYywgLWVuX2NpYV9hYmJyZXZpYXRpb24pICU+JSAKICAgIHNlcGFyYXRlKGNvZGUsIGMoJ2NvZGUnLCAnYWx0JyksIHNlcCA9ICdfKD89c2hvcnR8bG9uZyknKSAlPiUgCiAgICBzcHJlYWQoY29kZSwgbmFtZSkgJT4lIAogICAgZmlsdGVyKC4sIHJvd1N1bXMoaXMubmEoLlstMV0pKSA8IDMpICU+JQogICAgbXV0YXRlKGFsdCA9IG5hX2lmKGFsdCwgJ2xvbmcnKSwKICAgICAgICAgICBlbl9jaWEgPSBnc3ViKCcgXFwoc29tZXRpbWVzLip8OyBub3RlLionLCAnJywgZW5fY2lhKSkKCmdlbmNfYyA8LSBnZW5jICU+JQogICAgamFuaXRvcjo6Y2xlYW5fbmFtZXMoKSAlPiUgc2VsZWN0KC1uYW1lKSAlPiUKICAgIHNldE5hbWVzKGMoJ2lzbzNjJywgJ2lzbzJjJywgJ2lzbzNuJywgJ2dlYycpKSAlPiUgCiAgICAgICAgZmlsdGVyKCFnZWMgJWluJSBjKCdHWicsICdTVicpKQoKdW5zdGF0c19jIDwtIHVuc3RhdHMgJT4lIAogICAgamFuaXRvcjo6Y2xlYW5fbmFtZXMoKSAlPiUKICAgIHRyYW5zbXV0ZShsYW5ndWFnZSwgCiAgICAgICAgICAgICAgdW5fcmVnaW9uX2NvZGUgPSByZWdpb25fY29kZSwKICAgICAgICAgICAgICB1bl9yZWdpb25fbmFtZSA9IHJlZ2lvbl9uYW1lLAogICAgICAgICAgICAgIHVuX3N1YnJlZ2lvbl9jb2RlID0gc3ViX3JlZ2lvbl9jb2RlLAogICAgICAgICAgICAgIHVuX3N1YnJlZ2lvbl9uYW1lID0gc3ViX3JlZ2lvbl9uYW1lLAogICAgICAgICAgICAgIHVuX2ludGVybWVkaWF0ZV9yZWdpb25fY29kZSA9IGludGVybWVkaWF0ZV9yZWdpb25fY29kZSwKICAgICAgICAgICAgICB1bl9pbnRlcm1lZGlhdGVfcmVnaW9uX25hbWUgPSBpbnRlcm1lZGlhdGVfcmVnaW9uX25hbWUsCiAgICAgICAgICAgICAgdW5fbmFtZSA9IGNvdW50cnlfb3JfYXJlYSwKICAgICAgICAgICAgICBtNDkgPSBtNDlfY29kZSwKICAgICAgICAgICAgICBpc28zYyA9IGlzb19hbHBoYTNfY29kZSwKICAgICAgICAgICAgICBsZGMgPSBsZWFzdF9kZXZlbG9wZWRfY291bnRyaWVzX2xkYyA9PSAneCcsCiAgICAgICAgICAgICAgbGxkYyA9IGxhbmRfbG9ja2VkX2RldmVsb3BpbmdfY291bnRyaWVzX2xsZGMgPT0gJ3gnLAogICAgICAgICAgICAgIHNpZHMgPSBzbWFsbF9pc2xhbmRfZGV2ZWxvcGluZ19zdGF0ZXNfc2lkcyA9PSAneCcsCiAgICAgICAgICAgICAgaXNfZGV2ZWxvcGVkID0gZGV2ZWxvcGVkX2RldmVsb3BpbmdfY291bnRyaWVzKSAlPiUgCiAgICBtb2RpZnkobmFfaWYsICcnKSAlPiUKICAgIGdhdGhlcih2YXIsIHZhbCwgbWF0Y2hlcygnbmFtZScpKSAlPiUgCiAgICB1bml0ZSh2YXIsIGxhbmd1YWdlLCB2YXIpICU+JSAKICAgIG11dGF0ZSh2YXIgPSBnc3ViKCdfbmFtZScsICcnLCB2YXIpKSAlPiUgCiAgICBzcHJlYWQodmFyLCB2YWwpCgpva2ZuX2MgPC0gb2tmbiAlPiUgc2VsZWN0KGVuX2lzbyA9IDIsIGZyX2lzbyA9IDMsIGlzbzJjID0gNCwgaXNvM2MgPSA1LCBpc28zbiA9IDYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgODo5LCBjYWxsaW5nID0gRGlhbCwgMTIsIGdlYyA9IEZJUFMsIDE0OjE1LCBpc280MjE3XzNjID0gMTYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgaXNvNDIxN19uYW1lID0gMTksIGlzbzQyMTdfM24gPSAyMCwgMjE6MjQsIDI3KSAlPiUKICAgIG11dGF0ZShnZWMgPSBpZmVsc2UoaXNvM2MgPT0gJ0JFUycsIE5BLCBnZWMpKSAlPiUgCiAgICBqYW5pdG9yOjpjbGVhbl9uYW1lcygpCgp3X2MgPC0gdyAlPiUgc2VsZWN0KHRsZCwgMjo0LCA2OjIwKSAlPiUKICAgIG11dGF0ZShsaWNlbnNlX3BsYXRlID0gZ3N1YignIFxcKC4qXFwpJywgJycsIGxpY2Vuc2VfcGxhdGUpLAogICAgICAgICAgIGl0dSA9IGNhc2Vfd2hlbihpc28yYyA9PSAnVEwnIH4gJ1RMUycsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGlzbzJjID09ICdLTicgfiAnS05BJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IGl0dSksCiAgICAgICAgICAgbmF0bzJjID0gaWZlbHNlKGlzbzJjID09ICdSVScsICdSVScsIG5hdG8yYykpICU+JSAKICAgIGRyb3BfbmEoaXNvMmMpCgp1bmljb2RlX21vZGVybl9jIDwtIHVuaWNvZGVfbW9kZXJuICU+JQogICAgc2VwYXJhdGUoY29kZSwgYygnY29kZScsICdhbHQnKSwgc2VwID0gJy1hbHQtJywgZmlsbCA9ICdyaWdodCcpICU+JSAKICAgIG11dGF0ZShpc28zbiA9IGlmZWxzZShuY2hhcihjb2RlKSA9PSAzLCBjb2RlLCBOQSksIAogICAgICAgICAgIGlzbzJjID0gaWZlbHNlKG5jaGFyKGNvZGUpID09IDIsIGNvZGUsIE5BKSkgJT4lIAogICAgc2VsZWN0KC1jb2RlKSAlPiUKICAgIGphbml0b3I6OmNsZWFuX25hbWVzKCkKCiMgbG9hZCBjb3VudHJ5Y29kZSBkYXRhIHN0cmFpZ2h0IGZyb20gZ2l0aHViCmNvbiA8LSB1cmwoJ2h0dHBzOi8vZ2l0aHViLmNvbS92aW5jZW50YXJlbGJ1bmRvY2svY291bnRyeWNvZGUvYmxvYi9tYXN0ZXIvZGF0YS9jb2RlbGlzdC5yZGE/cmF3PXRydWUnKQpsb2FkKGNvbikgICAjIGBjb2RlbGlzdGAKY2xvc2UoY29uKQpybShjb24pCgpjb3VudHJ5Y29kZV9kYXRhX2MgPC0gY29kZWxpc3QgJT4lIAogICAgbXV0YXRlKGlzbzJjID0gY29hbGVzY2UoaXNvMmMsIGdlbmMyYykpICU+JSAKICAgIHNlbGVjdChpc28yYywgbWF0Y2hlcygncmVnZXgnKSkgJT4lIAogICAgZHJvcF9uYShpc28yYykgJT4lCiAgICBqYW5pdG9yOjpjbGVhbl9uYW1lcygpICU+JSAKICAgIHNldF9uYW1lcyh+c3ViKCdjb3VudHJ5X25hbWVfJywgJycsIC54KSkKYGBgCgojIyBKb2luaW5nCmBgYHtyIGpvaW5pbmd9CmNpYSA8LSBmdWxsX2pvaW4oY291bnRyeV9jb2Rlc19jICU+JSBkcm9wX25hKGdlYyksIGNvdW50cnlfbmFtZXNfYykKCnVzZyA8LSBmdWxsX2pvaW4oZ2VuY19jICU+JSBkcm9wX25hKGdlYyksIGNpYSwgYnkgPSAnZ2VjJykgJT4lCiAgICBtdXRhdGUoaXNvM2MgPSBjb2FsZXNjZShpc28zYy54LCBpc28zYy55KSwKICAgICAgICAgICBpc28yYyA9IGNvYWxlc2NlKGlzbzJjLngsIGlzbzJjLnkpLAogICAgICAgICAgIGlzbzNuID0gY29hbGVzY2UoaXNvM24ueCwgaXNvM24ueSkpICU+JQogICAgc2VsZWN0KC1tYXRjaGVzKCdcXC4nKSkKCiAgICAgICAgICAgICAgICMgU2FjcmlmaWNlIENoYW5uZWwgSXNsYW5kcyBmb3IgU2Fyawpva191biA8LSBva2ZuX2MgJT4lIHNsaWNlKC0xKSAlPiUgZnVsbF9qb2luKHVuc3RhdHNfYykKCnVzX29rX3VuIDwtIGZ1bGxfam9pbihva191biwgdXNnLCBieSA9ICdpc28zbicpICU+JQogICAgbXV0YXRlKGlzbzNjID0gY29hbGVzY2UoaXNvM2MueCwgaXNvM2MueSksCiAgICAgICAgICAgaXNvMmMgPSBjb2FsZXNjZShpc28yYy54LCBpc28yYy55KSwKICAgICAgICAgICBnZWMgPSBjb2FsZXNjZShnZWMueCwgZ2VjLnkpLAogICAgICAgICAgIHRsZCA9IGNvYWxlc2NlKHRsZC54LCB0bGQueSkpICU+JQogICAgc2VsZWN0KC1tYXRjaGVzKCdcXC4nKSkKCnVzX29rX3VuX3cgPC0gZnVsbF9qb2luKHVzX29rX3VuLCB3X2MsIGJ5ID0gJ2lzbzJjJykgJT4lCiAgICBtdXRhdGUoaXNvM2MgPSBjb2FsZXNjZShpc28zYy54LCBpc28zYy55KSwKICAgICAgICAgICBpc28zbiA9IGNvYWxlc2NlKGlzbzNuLngsIGlzbzNuLnkpLAogICAgICAgICAgIGdlYyA9IGNvYWxlc2NlKGdlYy54LCBnZWMueSksCiAgICAgICAgICAgbWFyYyA9IGNvYWxlc2NlKG1hcmMueCwgbWFyYy55KSwKICAgICAgICAgICAjIHdtbyA9IGNvYWxlc2NlKHdtby54LCB3bW8ueSksICAgICMgdy9va2ZuIGNvZGVzIGRpZmZlciwgYW5kIG5vIG9mZmljaWFsIGxpc3QgdG8gdmVyaWZ5CiAgICAgICAgICAgY2FsbGluZyA9IGNvYWxlc2NlKGNhbGxpbmcueCwgY2FsbGluZy55KSwKICAgICAgICAgICBpb2MgPSBjb2FsZXNjZShpb2MueCwgaW9jLnkpLAogICAgICAgICAgIHN0YW5hZyA9IGNvYWxlc2NlKHN0YW5hZy54LCBzdGFuYWcueSksCiAgICAgICAgICAgdGxkID0gY29hbGVzY2UodGxkLngsIHRsZC55KSkgJT4lCiAgICBzZWxlY3QoLW1hdGNoZXMoJ1xcLicpKQoKdW5pY29kZSA8LSB1bmljb2RlX2NvZGVzICU+JSAKICAgIGRyb3BfbmEoaXNvMmMpICU+JSAKICAgIHJpZ2h0X2pvaW4odW5pY29kZV9tb2Rlcm5fYywgYnkgPSAnaXNvMmMnKSAlPiUgCiAgICBtdXRhdGUoaXNvM24gPSBjb2FsZXNjZShpc28zbi54LCBpc28zbi55KSkgJT4lIAogICAgc2VsZWN0KC1tYXRjaGVzKCdcXC4nKSkgJT4lIAogICAgbXV0YXRlKGlzbzNuID0gY2FzZV93aGVuKGlzbzJjID09ICdDUCcgfiAnOTA1JywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpc28yYyA9PSAnREcnIH4gJzkwOCcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaXNvMmMgPT0gJ1hLJyB+ICc5MDEnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBpc28zbiksCiAgICAgICAgICAgaXNvM2MgPSBpZmVsc2UoaXNvMmMgPT0gJ1hLJywgTkEsIGlzbzNjKSkKCmNvdW50cmllcyA8LSBmdWxsX2pvaW4odW5pY29kZSwgdXNfb2tfdW5fdywgYnkgPSBjKCdpc28zbicsICdpc28yYycsICdhbHQnKSkgJT4lIAogICAgbXV0YXRlKGlzbzNjID0gY29hbGVzY2UoaXNvM2MueCwgaXNvM2MueSksIAogICAgICAgICAgIGdlYyA9IGNvYWxlc2NlKGdlYy54LCBnZWMueSkpICU+JSAKICAgIHNlbGVjdCgtbWF0Y2hlcygnXFwuJykpCgpjb3VudHJpZXMgPC0gbGVmdF9qb2luKGNvdW50cmllcywgY291bnRyeWNvZGVfZGF0YV9jKQpgYGAKCmBgYHtyIHZlcmlmeX0KIyBjaGVjayBjb2RlIGR1cGxpY2F0aW9uCnVzX29rX3VuX3cgJT4lIG5hbWVzKCkgJT4lIAogICAgbWFwX2ludCh+IGNvdW50cmllcyAlPiUgCiAgICAgICAgICAgICAgICBmaWx0ZXIoaXMubmEoYWx0KSkgJT4lIAogICAgICAgICAgICAgICAgZ3JvdXBfYnlfKC5kb3RzID0gLngpICU+JSAKICAgICAgICAgICAgICAgIGZpbHRlcihuKCkgPiAxKSAlPiUgCiAgICAgICAgICAgICAgICBzZWxlY3QoZ2VjLCBlbiwgaXNvM2MsIGlzbzJjLCBpc28zbikgJT4lIAogICAgICAgICAgICAgICAgLlshaXMubmEoLltbLnhdXSksXSAlPiUgCiAgICAgICAgICAgICAgICBucm93KCkpICU+JSAKICAgIHNldF9uYW1lcyhuYW1lcyh1c19va191bl93KSkKYGBgCgojIyBEb2N1bWVudGluZwpgYGB7cn0KY291bnRyaWVzX2NvbG5hbWVzIDwtIG5hbWVzKGNvdW50cmllcykKCmNvZGVzIDwtIGRhdGFfZnJhbWUoY29sdW1uID0gY291bnRyaWVzX2NvbG5hbWVzLCAKICAgICAgICAgICAgICAgICBjb2RlID0gZ3N1YignXycsICctJywgY29sdW1uKSkgJT4lIAogICAgbXV0YXRlKGV4cGFuc2lvbiA9IG1hcChjb2RlLCBzYWZlbHkoTkxQOjpwYXJzZV9JRVRGX2xhbmd1YWdlX3RhZyksIGV4cGFuZCA9IFRSVUUpLCAKICAgICAgICAgICBleHBhbnNpb24gPSBtYXAoZXhwYW5zaW9uLCBjKDEsIDEpKSwgCiAgICAgICAgICAgZXhwYW5zaW9uID0gbWFwKGV4cGFuc2lvbiwgfmlmKGxlbmd0aCgueCkgPT0gMCkge2MoTGFuZ3VhZ2UgPSBOQV9jaGFyYWN0ZXJfKX0gZWxzZSAueCksIAogICAgICAgICAgIGV4cGFuc2lvbiA9IG1hcChleHBhbnNpb24sIG1hcF9kZiwgfnN1cHByZXNzV2FybmluZ3MobmFfaWYodG9TdHJpbmcobmEub21pdCgueCkpLCAnJykpKSwgCiAgICAgICAgICAgZXhwYW5zaW9uID0gbWFwKGV4cGFuc2lvbiwgfnNldF9uYW1lcygueCwgc3ViKCc9LionLCAnJywgbmFtZXMoLngpKSkpKSAlPiUgCiAgICB1bm5lc3QoKSAlPiUgCiAgICBtdXRhdGUoTGFuZ3VhZ2UgPSBjYXNlX3doZW4oY29sdW1uID09ICdhbHQnIH4gTkFfY2hhcmFjdGVyXywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2x1bW4gPT0gJ21jYycgfiBOQV9jaGFyYWN0ZXJfLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbHVtbiA9PSAndGxkJyB+IE5BX2NoYXJhY3Rlcl8sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IExhbmd1YWdlKSwKICAgICAgICAgICBWYXJpYW50ID0gaWZlbHNlKGNvbHVtbiA9PSAnZW5fdXNfcG9zaXgnLCAnUE9TSVgnLCBWYXJpYW50KSwKICAgICAgICAgICBWYXJpYW50ID0gaWZlbHNlKGdyZXBsKCdfaXNvJywgY29sdW1uKSwgJ0lTTycsIFZhcmlhbnQpLAogICAgICAgICAgIFZhcmlhbnQgPSBpZmVsc2UoZ3JlcGwoJ19jaWEnLCBjb2x1bW4pLCAnQ0lBIFdvcmxkIEZhY3Rib29rJywgVmFyaWFudCksCiAgICAgICAgICAgRXh0ZW5zaW9uID0gaWZlbHNlKGdyZXBsKCdfY2lhXycsIGNvbHVtbiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWIoJ2VuX2NpYV8nLCAnJywgY29sdW1uKSwgRXh0ZW5zaW9uKSwKICAgICAgICAgICBuYW1lID0gY2FzZV93aGVuKAogICAgICAgICAgICAgICBjb2x1bW4gPT0gJ2lzbzJjJyB+ICdJU08gMzE2Ni0xIEFscGhhLTIgY29kZScsCiAgICAgICAgICAgICAgIGNvbHVtbiA9PSAnaXNvM2MnIH4gJ0lTTyAzMTY2LTEgQWxwaGEtMyBjb2RlJywKICAgICAgICAgICAgICAgY29sdW1uID09ICdpc28zbicgfiAnSVNPIDMxNjYtMSBudW1lcmljIGNvZGUnLAogICAgICAgICAgICAgICBjb2x1bW4gPT0gJ2VuX2lzbycgfiAnSVNPIEVuZ2xpc2ggbmFtZScsCiAgICAgICAgICAgICAgIGNvbHVtbiA9PSAnZnJfaXNvJyB+ICdJU08gRnJlbmNoIG5hbWUnLAogICAgICAgICAgICAgICBjb2x1bW4gPT0gJ2dlYycgfiAnR2VvcG9saXRpY2FsIEVudGl0aWVzIGFuZCBDb2RlcycsCiAgICAgICAgICAgICAgIGNvbHVtbiA9PSAnZmlmYScgfiAnRklGQSAoRsOpZMOpcmF0aW9uIEludGVybmF0aW9uYWxlIGRlIEZvb3RiYWxsIEFzc29jaWF0aW9uKSBjb2RlJywKICAgICAgICAgICAgICAgY29sdW1uID09ICdnYXVsJyB+ICdHbG9iYWwgQWRtaW5pc3RyYXRpdmUgVW5pdCBMYXllcnMgZnJvbSB0aGUgRm9vZCBhbmQgQWdyaWN1bHR1cmUgT3JnYW5pemF0aW9uIChGQU8pIGNvZGUnLAogICAgICAgICAgICAgICBjb2x1bW4gPT0gJ2lzbzQyMTdfM2MnIH4gJ0lTTyA0MjE3IDMtY2hhcmFjdGVyIGN1cnJlbmN5IGNvZGUnLAogICAgICAgICAgICAgICBjb2x1bW4gPT0gJ2lzbzQyMTdfbmFtZScgfiAnSVNPIDQyMTcgY3VycmVuY3kgbmFtZScsCiAgICAgICAgICAgICAgIGNvbHVtbiA9PSAnaXNvNDIxN18zbicgfiAnSVNPIDQyMTcgbnVtZXJpYyBjdXJyZW5jeSBjb2RlJywKICAgICAgICAgICAgICAgY29sdW1uID09ICdpc19pbmRlcGVuZGVudCcgfiAnQ291bnRyeSBzb3ZlcmVpZ250eSBzdGF0dXMgZnJvbSB0aGUgQ0lBIFdvcmxkIEZhY3Rib29rJywKICAgICAgICAgICAgICAgY29sdW1uID09ICdjYXBpdGFsJyB+ICdDYXBpdGFsIGNpdHknLAogICAgICAgICAgICAgICBjb2x1bW4gPT0gJ2VkZ2FyJyB+ICdFREdBUiBjb3VudHJ5IGNvZGUgZnJvbSB0aGUgU0VDJywKICAgICAgICAgICAgICAgY29sdW1uID09ICdlbl9jaWEnIH4gJ0NvdW50cnkgbmFtZXMgZnJvbSB0aGUgQ0lBIFdvcmxkIEZhY3Rib29rJywKICAgICAgICAgICAgICAgY29sdW1uID09ICdlbl9jaWFfbG9jYWwnIH4gJ0xvY2FsIGNvdW50cnkgbmFtZXMgZnJvbSB0aGUgQ0lBIFdvcmxkIEZhY3Rib29rJywKICAgICAgICAgICAgICAgY29sdW1uID09ICdlbl9jaWFfYWJicmV2aWF0aW9uJyB+ICdDb21tb25seSB1c2VkIGNvdW50cnkgYWJicmV2aWF0aW9ucyBmcm9tIHRoZSBDSUEgV29ybGQgRmFjdGJvb2suJywKICAgICAgICAgICAgICAgY29sdW1uID09ICdtY2MnIH4gJ0ludGVybmF0aW9uYWwgVGVsZWNvbW11bmljYXRpb24gVW5pb24gKElUVSkgVGVsZWNvbW11bmljYXRpb24gU3RhbmRhcmRpemF0aW9uIFNlY3RvciAoSVRVLVQpIEUuMjEyIE1vYmlsZSBDb3VudHJ5IENvZGUnLAogICAgICAgICAgICAgICBjb2x1bW4gPT0gJ2l0dV9jYWxsc2lnbicgfiAnSW50ZXJuYXRpb25hbCBUZWxlY29tbXVuaWNhdGlvbiBVbmlvbiAoSVRVKSBjYWxsc2lnbiBwcmVmaXhlcyBmb3IgcmFkaW8gYW5kIHRlbGV2aXNpb24gc3RhdGlvbnMnLAogICAgICAgICAgICAgICBjb2x1bW4gPT0gJ2l0dScgfiAnSW50ZXJuYXRpb25hbCBUZWxlY29tbXVuaWNhdGlvbiBVbmlvbiAoSVRVKSAxLTMgY2hhcmFjdGVyIGNvdW50cnkgY29kZScsCiAgICAgICAgICAgICAgIGNvbHVtbiA9PSAnaXR1X21hcml0aW1lJyB+ICdJbnRlcm5hdGlvbmFsIFRlbGVjb21tdW5pY2F0aW9uIFVuaW9uIChJVFUpIE1hcml0aW1lIElkZW50aWZpY2F0aW9uIERpZ2l0cycsCiAgICAgICAgICAgICAgIGNvbHVtbiA9PSAnbGljZW5zZV9wbGF0ZScgfiAnTW90b3IgdmVoaWNsZSBsaWNlbmNlIHBsYXRlIGNvdW50cnkgY29kZScsCiAgICAgICAgICAgICAgIGNvbHVtbiA9PSAnc3RhbmFnJyB+ICdOb3J0aCBBdGxhbnRpYyBUcmVhdHkgT3JnYW5pemF0aW9uIChOQVRPL09UQU4pIFNUQU5BRyAxMDU5IExldHRlciBDb2RlcyBmb3IgR2VvZ3JhcGhpY2FsIEVudGl0aWVzJywKICAgICAgICAgICAgICAgY29sdW1uID09ICduYXRvMmMnIH4gJ05vcnRoIEF0bGFudGljIFRyZWF0eSBPcmdhbml6YXRpb24gKE5BVE8vT1RBTikgMi1sZXR0ZXIgY29kZS4nLAogICAgICAgICAgICAgICBjb2x1bW4gPT0gJ3VuZHAnIH4gJ1VuaXRlZCBOYXRpb25zIERldmVsb3BtZW50IFByb2dyYW1tZSAoVU5EUCkgY291bnRyeSBjb2RlJywKICAgICAgICAgICAgICAgY29sdW1uID09ICdtYXJjJyB+ICdNQWNoaW5lLVJlYWRhYmxlIENhdGFsb2dpbmcgKE1BUkMpIGNvZGVzIGZyb20gdGhlIFVTIExpYnJhcnkgb2YgQ29uZ3Jlc3MnLAogICAgICAgICAgICAgICBjb2x1bW4gPT0gJ2NhbGxpbmcnIH4gJ0ludGVybmF0aW9uYWwgVGVsZWNvbW11bmljYXRpb24gVW5pb24gKElUVSkgVGVsZWNvbW11bmljYXRpb24gU3RhbmRhcmRpemF0aW9uIFNlY3RvciAoSVRVLVQpIEUuMTY0IGludGVybmF0aW9uYWwgdGVsZXBob25lIGNhbGxpbmcgY29kZScsCiAgICAgICAgICAgICAgIGNvbHVtbiA9PSAnaW9jJyB+ICdJbnRlcm5hdGlvbmFsIE9seW1waWMgQ29tbWl0dGVlIGNvdW50cnkgY29kZScsCiAgICAgICAgICAgICAgIGNvbHVtbiA9PSAndGxkJyB+ICdJbnRlcm5ldCBBc3NpZ25lZCBOdW1iZXJzIEF1dGhvcml0eSAoSUFOQSkgY291bnRyeSBjb2RlIHRvcC1sZXZlbCBkb21haW4nLAogICAgICAgICAgICAgICBjb2x1bW4gPT0gJ200OScgfiAnVW5pdGVkIE5hdGlvbnMgU3RhdGlzdGljcyBEaXZpc2lvbiAoVU5TRCkgTS40OSBhcmVhIGNvZGUnLAogICAgICAgICAgICAgICBjb2x1bW4gPT0gJ2xkYycgfiAnVW5pdGVkIE5hdGlvbnMgKFVOKSBMZWFzdCBEZXZlbG9wZWQgQ291bnRyaWVzJywKICAgICAgICAgICAgICAgY29sdW1uID09ICdsbGRjJyB+ICdVbml0ZWQgTmF0aW9ucyAoVU4pIExhbmQgTG9ja2VkIERldmVsb3BpbmcgQ291bnRyaWVzJywKICAgICAgICAgICAgICAgY29sdW1uID09ICdzaWRzJyB+ICdVbml0ZWQgTmF0aW9ucyAoVU4pIFNtYWxsIElzbGFuZCBEZXZlbG9waW5nIFN0YXRlcycsCiAgICAgICAgICAgICAgIGNvbHVtbiA9PSAnaXNfZGV2ZWxvcGVkJyB+ICdVbml0ZWQgTmF0aW9ucyAoVU4pIGRldmVsb3BtZW50IHN0YXR1cycsCiAgICAgICAgICAgICAgIGdyZXBsKCdfdW4nLCBjb2x1bW4pIH4gJ1VuaXRlZCBOYXRpb25zIChVTikgR2Vvc2NoZW1lIHJlZ2lvbiBuYW1lJywKICAgICAgICAgICAgICAgVFJVRSB+IE5BX2NoYXJhY3Rlcl8KICAgICAgICAgICApLAogICAgICAgICAgIG5vdGVzID0gY2FzZV93aGVuKAogICAgICAgICAgICAgICBjb2x1bW4gPT0gJ2dlYycgfiAnRm9ybWVybHkgRklQUyBQdWIgMTAtNCwgd2hpY2ggd2FzIHdpdGhkcmF3biBieSBOSVNUIGluIDIwMDguIE1haW50YWluZWQgdW50aWwgMjAxNCBieSB0aGUgTmF0aW9uYWwgR2Vvc3BhdGlhbC1JbnRlbGxpZ2VuY2UgQWdlbmN5IChOR0EpLCBhZnRlciB3aGljaCBpdCB3YXMgZnJvemVuIGFuZCBzdXBlcmNlZGVkIGJ5IEdFTkMsIHRoZSBVUyBnb3Zlcm5tZW50IHByb2ZpbGUgb2YgSVNPIDMxNjYuJywKICAgICAgICAgICAgICAgY29sdW1uID09ICdlbl9pc28nIH4gJ0RvZXMgbm90IGluY2x1ZGUgVGFpd2FuLCB3aGljaCBpcyBub3QgYSBtZW1iZXIgb2YgdGhlIFVOLiBBIGZldyB1c2UgdW5jb21tb24gb2ZmaWNhbCBmb3JtcywgaW5jbHVkaW5nIE5vcnRoIGFuZCBTb3V0aCBLb3JlYSBhbmQgQm9saXZpYS4nLAogICAgICAgICAgICAgICBjb2x1bW4gPT0gJ2ZyX2lzbycgfiAnRG9lcyBub3QgaW5jbHVkZSBUYWl3YW4sIHdoaWNoIGlzIG5vdCBhIG1lbWJlciBvZiB0aGUgVU4uIEEgZmV3IHVzZSB1bmNvbW1vbiBvZmZpY2FsIGZvcm1zLCBpbmNsdWRpbmcgTm9ydGggYW5kIFNvdXRoIEtvcmVhIGFuZCBCb2xpdmlhLicsCiAgICAgICAgICAgICAgIGNvbHVtbiA9PSAnZW5fY2lhJyB+ICdNYW55IHNob3J0IGFuZCBsb25nIGZvcm1zLiBVc2VzICJCdXJtYSIgaW5zdGVhZCBvZiAiTXlhbm1hciIuJywKICAgICAgICAgICAgICAgY29sdW1uID09ICdlbl9jaWFfbG9jYWwnIH4gJ01hbnkgc2hvcnQgYW5kIGxvbmcgZm9ybXMuIEluY2x1ZGVzIGFsdGVybmF0aXZlcyBpbmxpbmUuIFRyYW5zbGl0ZXJhdGVzIHRvIExhdGluIHNjcmlwdC4nLAogICAgICAgICAgICAgICBjb2x1bW4gPT0gJ2VuX2NpYV9hYmJyZXZpYXRpb24nIH4gJ09ubHkgaW5jbHVkZWQgd2hlcmUgY29tbW9ubHkgdXNlZC4gSW5jbHVkZXMgYWx0ZXJuYXRpdmVzIGlubGluZS4nLAogICAgICAgICAgICAgICBjb2x1bW4gPT0gJ21jYycgfiAnSW5jbHVkZXMgcmFuZ2VzLicsCiAgICAgICAgICAgICAgIGNvbHVtbiA9PSAnaXR1X2NhbGxzaWduJyB+ICdJbmNsdWRlcyByYW5nZXMuJywKICAgICAgICAgICAgICAgY29sdW1uID09ICdpdHVfbWFyaXRpbWUnIH4gJ0luY2x1ZGVzIHJhbmdlcy4nLAogICAgICAgICAgICAgICBjb2x1bW4gPT0gJ25hdG8yYycgfiAnT2ZmaWNpYWxseSBkZXByZWNhdGVkIGluIGZhdm9yIG9mIFNUQU5BRyAxMDU5IChzZWUgInN0YW5hZyIpLicsCiAgICAgICAgICAgICAgIGNvbHVtbiA9PSAndGxkJyB+ICdJbmNsdWRlcyBsZWFkaW5nIHBlcmlvZC4nLAogICAgICAgICAgICAgICBncmVwbCgnX3VuX3JlZ2lvbicsIGNvbHVtbikgfiAnQ29udGluZW50JywKICAgICAgICAgICAgICAgZ3JlcGwoJ3JlZ2V4JywgY29sdW1uKSB+ICdSZWdleCB1c2VkIGZvciBgcGFyc2VfY291bnRyeWAuJywKICAgICAgICAgICAgICAgVFJVRSB+IE5BX2NoYXJhY3Rlcl8KICAgICAgICAgICApKSAlPiUgCiAgICBqYW5pdG9yOjpjbGVhbl9uYW1lcygpICU+JSAKICAgIGFycmFuZ2UoY29sdW1uKSAlPiUgCiAgICBzZWxlY3QoMToyLCA4OjksIDM6NykKYGBgCgoKIyMgU2F2aW5nCmBgYHtyIHNhdmluZ30KIyB0byBhdm9pZCBBU0NJSSBDUkFOIHdhcm5pbmcKY29kZXMgPC0gY29kZXMgJT4lIG1vZGlmeShzdHJpbmdpOjpzdHJpX3RyYW5zX2dlbmVyYWwsICdMYXRpbi1BU0NJSScpCgpkZXZ0b29sczo6dXNlX2RhdGEoY291bnRyaWVzLCBjb3VudHJpZXNfY29sbmFtZXMsIAogICAgICAgICAgICAgICAgICAgaW50ZXJuYWwgPSBUUlVFLCBvdmVyd3JpdGUgPSBUUlVFKQpkZXZ0b29sczo6dXNlX2RhdGEoY29kZXMsIG92ZXJ3cml0ZSA9IFRSVUUpCmBgYAoKIyMgTGljZW5zaW5nCgpEYXRhIGlzIGxpY2Vuc2VkIGFjY29yZGluZyB0byBpdHMgc291cmNlLCBtb3N0IG9mIHdoaWNoIGFyZSBpbiB0aGUgcHVibGljIApkb21haW4uIEV4Y2VwdGlvbnMgaW5jbHVkZQoKLSBVbmljb2RlIENMRFIgZGF0YSwgd2hvc2UgcGVybWlzc2l2ZSBsaWNlbnNlIGlzIGluY2x1ZGVkLCBhbmQgCi0gY291bnRyeWNvZGUgcmVnZXgsIHdoaWNoIGlzIGxpY2Vuc2VkIHVuZGVyIEdQTC0zLiBXaGlsZSB0aGlzIHBhY2thZ2Ugb25seSAKdXNlcyB0aGUgcmVnZXgsIGl0IGlzIGxpY2Vuc2VkIHVuZGVyIEdQTC0zIGFzIGEgbW9kaWZpZWQgdmVyc2lvbiAoc2VlIGNvZGUgCmFib3ZlOyBsYXN0IHJ1biAyMDE3LTA1LTI0IHdpdGggY291bnRyeWNvZGUgMC4xOSkgYW5kIGFjY29yZGluZ2x5IHJldGFpbnMgaXRzIApjb3B5bGVmdCBsaWNlbnNlLgo=