Feedback should be send to goran.milovanovic_ext@wikimedia.de.

The campaign is run from 2021/10/18 to 2021/10/31.

CURRENT UPDATE: Complete dataset as of 2021/10/31.

0. Data Acquisiton

NOTE: the Data Acquisition code chunk is not fully reproducible from this Report. The data are collected by running an R script on stat1007.eqiad.wmnet, collecting the data as .tsv and .csv files, copying manually, and processing locally.

0.1 Daily Update

### ----------------------------------------------------------------
### --- WMDE 2021 Ocassional Editors
### --- https://phabricator.wikimedia.org/T291635
### ----------------------------------------------------------------

### ----------------------------------------------------------------
### --- Campaign Description and Parameters
### ----------------------------------------------------------------

# - Landing Pages:
# - Landing Page 1: https://de.wikipedia.org/wiki/Wikipedia:Wikimedia_Deutschland/DeinEngagement
# - Landing Page 2a: https://tools.wmflabs.org/mitmachen/
# - Landing Page 2b: https://de.wikipedia.org/wiki/Wikipedia:Wikimedia_Deutschland/LerneWikipedia
# - Landing Page 2c: https://de.wikipedia.org/wiki/Wikipedia:F%C3%B6rderung/F%C3%B6rderangebote
# - Campaign tags:
# - WMDE_oceditors_fall_2021

# - Start of the banner campaign: October 12th
# - End of the banner campaign: October 26 th
# - Tracking test: October 5 - 7
# - Preliminary report for tracking: beginning of November
# - Track editing behavior four weeks after end of campaign: November 23rd
# - final report for tracking: beginning of December

### --- libraries
library(tidyverse)
library(data.table)
library(lubridate)

### --- campaign specifics
campaignName <- 'OccasionalEditors_2021'

### --- dir structure
campaignPath <- '/home/goransm/Analytics/NewEditors/2021_OccasionalEditors/'
dataDir <- paste0(campaignPath, "_data/")
analyticsDir <- paste0(campaignPath, "_analytics/")
publicDir <- '/srv/published/datasets/wmde-analytics-engineering/NewEditors/campaigns/2021_OccasionalEditors/'

### --- determine cetDay
cetDay <- Sys.time()
cetDay
attr(cetDay, "tzone") <- "Europe/Berlin"
# - one day behind for crontab
# - (i.e. waiting for wmf.webrequest to complete is data acquisition)
cetDay <- ymd(
  strsplit(as.character(cetDay), 
           split = " ", 
           fixed = T)[[1]][1]
) - 1

### ----------------------------------------------------------
### --- Banner Interactions:
### --- via event.WMDEBannerInteractions
### --- https://meta.wikimedia.org/wiki/Schema:WMDEBannerInteractions
### ----------------------------------------------------------

# - select dt, event.bannerName, event.bannerAction, event.bannerImpressions, event.userID 
# - from event.wmdebannerinteractions where year=2020 and month=5 and (day=11 or day=12 or day=13);

# - function: wmde_banner_actions
wmde_banner_actions <- function(uri_query_filter,
                                cetDay,
                                queryFile,
                                fileName,
                                analyticsDir,
                                campaignName) {
  
  # - NOTE:
  # - expected format for cetDay is: YYYY-MM-DD
  
  # - WHERE condition: create datetime_condition
  cet_condition <- seq(
    from = as.POSIXct(paste0(cetDay," 0:00"), tz = "Europe/Berlin"),
    to = as.POSIXct(paste0(cetDay," 23:00"), tz = "Europe/Berlin"),
    by = "hour"
  ) 
  attr(cet_condition, "tzone") <- "UTC"
  cet_condition <- as.character(cet_condition)
  cet_condition <- unlist(str_extract_all(cet_condition, "^([[:digit:]]|\\s|-)*"))
  cet_years <- sapply(
    strsplit(cet_condition, split = " ", fixed = T), function(x) {
      strsplit(x, split = "-")[[1]][1]
    })
  cet_months <- sapply(
    strsplit(cet_condition, split = " ", fixed = T), function(x) {
      strsplit(x, split = "-")[[1]][2]
    })
  cet_months <- gsub("^0", "", cet_months)
  cet_days <- sapply(
    strsplit(cet_condition, split = " ", fixed = T), function(x) {
      strsplit(x, split = "-")[[1]][3]
    })
  cet_days <- gsub("^0", "", cet_days)
  cet_hours <- sapply(strsplit(cet_condition, split = " ", fixed = T), 
                      function(x) {
                        x[2]
                      })
  cet_hours <- gsub("^0", "", cet_hours)
  datetimeCondition <- paste0(
    "year = ", cet_years, " AND ",
    "month = ", cet_months, " AND ",
    "day = ", cet_days, " AND ", 
    "hour = ", cet_hours
  )
  datetimeCondition <- paste("(", 
                             datetimeCondition, 
                             ")",
                             collapse = " OR ", 
                             sep = "")
  
  
  # - WHERE condition: create eventBannerName_condition
  if (length(uri_query_filter) > 1) {
    eventBannerName_condition <- paste0("(",
                                        paste(
                                          paste0("event.bannerName LIKE '%", uri_query_filter, "%'"),
                                          collapse = " OR ", sep = " "),
                                        ")"
    )
  } else {
    eventBannerName_condition = paste0("event.bannerName LIKE '%", uri_query_filter, "%'")
  }
  
  # - compose HiveQL query
  hiveQuery <- paste0( 
    "select dt, event.bannerName, event.bannerAction, event.bannerImpressions, event.userID from event.wmdebannerinteractions 
    WHERE (",
    eventBannerName_condition, " AND ",
    "(", datetimeCondition, ")",
    ");"
  )
  
  # - write hql
  write(hiveQuery, paste0(dataDir, queryFile))
  # - execute hql script:
  kerberosPrefix <- 
    'sudo -u analytics-privatedata kerberos-run-command analytics-privatedata '
  # - Kerberos init
  system(command = paste0(kerberosPrefix, ' hdfs dfs -ls'), 
         wait = T)
  # - Run query
  query <- system(command = paste(kerberosPrefix, 
                                  '/usr/local/bin/beeline --incremental=true --silent -f "',
                                  paste0(dataDir, queryFile),
                                  '" > ', dataDir, fileName,
                                  sep = ""),
                  wait = TRUE)
  
  # - Wrangle Banner Interactions
  # - load
  bannerData <- tryCatch({
    as.data.frame(fread(paste0(dataDir, fileName)))
  },
  error = function(condition) {
    return(FALSE)
  })
  
  # - process
  if (class(bannerData) == 'logical') {
    
    return(FALSE) 
    
  } else { 
    
    # - whoClicked
    whoClicked <- bannerData %>% 
      dplyr::filter(banneraction == "banner-clicked")
    whoClicked <- data.frame(userid = unique(whoClicked$userid))
    
    # - store:
    write.csv(whoClicked, 
              paste0(analyticsDir, 
                     "whoClicked_",
                     strsplit(
                       strsplit(fileName, split = "_", fixed = T)[[1]][2],
                       split = ".", 
                       fixed = T)[[1]][1],
                     ".csv"
              )
    )
    
    # - process bannerData
    bannerData <- t(table(bannerData$banneraction,
                          bannerData$bannername))
    bannerData <- as.data.frame(bannerData)
    colnames(bannerData) <- c('banner', 'action', 'count')
    bannerData$day <- cetDay
    bannerData$campaign <- campaignName
    
    # - store:
    write.csv(bannerData, 
              paste0(analyticsDir, 
                     "bannerInteractionsAggregated_",
                     strsplit(
                       strsplit(fileName, split = "_", fixed = T)[[1]][2],
                       split = ".", 
                       fixed = T)[[1]][1],
                     ".csv"
              ))
  }
  
}

# - set params for wmde_banner_actions()
queryFile <- paste0(campaignName, "_bannerInteractions.hql")
fileName <- paste0("bannerInteractions_", cetDay, ".tsv")
uri_query_filter <- 'WMDE_oceditors_fall_2021'
banner_status <- wmde_banner_actions(uri_query_filter = uri_query_filter,
                                     cetDay = cetDay,
                                     queryFile = queryFile,
                                     fileName = fileName,
                                     analyticsDir = analyticsDir, 
                                     campaignName = campaignName)

### ----------------------------------------------------------
### --- Pageviews
### ----------------------------------------------------------

# - function: wmde_collect_pageviews
wmde_collect_pageviews <- function(uri_host,
                                   uri_path,
                                   cetDay,
                                   queryFile,
                                   fileName,
                                   dataDir) {
  
  # - NOTE:
  # - expected format for cetDay is: YYYY-MM-DD
  
  # - to dataDir
  setwd(dataDir)
  
  # - libraries
  library(stringr)
  
  # - WHERE condition: create datetime_condition
  cet_condition <- seq(
    from = as.POSIXct(paste0(cetDay," 0:00"), tz = "Europe/Berlin"),
    to = as.POSIXct(paste0(cetDay," 23:00"), tz = "Europe/Berlin"),
    by = "hour"
  ) 
  attr(cet_condition, "tzone") <- "UTC"
  cet_condition <- as.character(cet_condition)
  cet_condition <- unlist(str_extract_all(cet_condition, "^([[:digit:]]|\\s|-)*"))
  cet_years <- sapply(
    strsplit(cet_condition, split = " ", fixed = T), function(x) {
      strsplit(x, split = "-")[[1]][1]
    })
  cet_months <- sapply(
    strsplit(cet_condition, split = " ", fixed = T), function(x) {
      strsplit(x, split = "-")[[1]][2]
    })
  cet_months <- gsub("^0", "", cet_months)
  cet_days <- sapply(
    strsplit(cet_condition, split = " ", fixed = T), function(x) {
      strsplit(x, split = "-")[[1]][3]
    })
  cet_days <- gsub("^0", "", cet_days)
  cet_hours <- sapply(strsplit(cet_condition, split = " ", fixed = T), 
                      function(x) {
                        x[2]
                      })
  cet_hours <- gsub("^0", "", cet_hours)
  datetimeCondition <- paste0(
    "year = ", cet_years, " AND ",
    "month = ", cet_months, " AND ",
    "day = ", cet_days, " AND ", 
    "hour = ", cet_hours
  )
  datetimeCondition <- paste("(", 
                             datetimeCondition, 
                             ")",
                             collapse = " OR ", 
                             sep = "")
  
  # - WHERE condition: create uri_host_condition
  if (length(uri_host) > 1) {
    uri_host_condition <- paste0("(",
                                 paste(
                                   paste0("uri_host = '", uri_host, "'"),
                                   collapse = " OR ", sep = " "),
                                 ")"
    )
  } else {
    uri_host_condition = paste0("uri_host = '", uri_host, "'")
  }
  
  # - WHERE condition: create uri_path_condition
  if (length(uri_path) > 1) {
    uri_path_condition <- paste0("(",
                                 paste(
                                   paste0("uri_path = '", uri_path, "'"),
                                   collapse = " OR ", sep = " "),
                                 ")"
    )
  } else {
    uri_path_condition = paste0("uri_path = '", uri_path, "'")
  }
  
  # - compose HiveQL query
  hiveQuery <- paste0( 
    "USE wmf;
    SELECT uri_host, uri_path, uri_query, referer FROM webrequest
    WHERE (",
    uri_host_condition, " AND ",
    uri_path_condition, " AND ",
    "(", datetimeCondition, ")",
    ");"
  )
  
  # - write hql
  write(hiveQuery, queryFile)
  # - execute hql script:
  kerberosPrefix <- 
    'sudo -u analytics-privatedata kerberos-run-command analytics-privatedata '
  # - Kerberos init
  system(command = paste0(kerberosPrefix, ' hdfs dfs -ls'), 
         wait = T)
  # - Run query
  query <- system(command = paste(kerberosPrefix, 
                                  '/usr/local/bin/beeline --incremental=true --silent -f "',
                                  paste0(dataDir, queryFile),
                                  '" > ', dataDir, fileName,
                                  sep = ""),
                  wait = TRUE)
}

# - set params to wmde_collect_pageviews
uri_host <- c('de.wikipedia.org', 'de.m.wikipedia.org')
uri_path  <- c('/wiki/Wikipedia:Wikimedia_Deutschland/DeinEngagement',
               '/wiki/Wikipedia:Wikimedia_Deutschland/LerneWikipedia', 
               '/wiki/Wikipedia:F%C3%B6rderung/F%C3%B6rderangebote')
queryFile <- 'WMDE_oceditors_fall_2021_Pageviews.hql'
fileName <- paste0("pageviews_", cetDay, ".tsv")

# - collect Pageviews data
wmde_collect_pageviews(uri_host,
                       uri_path,
                       cetDay,
                       queryFile,
                       fileName,
                       dataDir)

### --- Wrangle Pageviews
# - function: wmde_process_pageviews
wmde_process_pageviews <- function(fileName,
                                   dataDir, 
                                   uri_query_filter,
                                   page_filter,
                                   cetDay = cetDay,
                                   campaignName = campaignName) {
  
  # - to dataDir
  setwd(dataDir)
  
  # - libraries
  library(stringr)
  library(dplyr)
  library(tidyr)
  library(data.table)
  
  # - load
  pageviewsData <- readLines(fileName)
  wStart <- which(grepl("uri_host", pageviewsData))
  pageviewsData <- pageviewsData[(wStart + 1):(length(pageviewsData) - 1)]
  pageviewsData <- data.frame(dat = pageviewsData, 
                              stringsAsFactors = F)
  pageviewsData <- separate(pageviewsData,
                            dat,
                            into = c('uri_host', 'uri_path', 'uri_query', 'referer'),
                            sep = "\t")
  # - apply page_filter
  wFilter1 <- unique(unname(unlist(sapply(page_filter, function (x) {
    which(grepl(x, pageviewsData$uri_path))
  }))))
  pageviewsData <- pageviewsData[wFilter1, ]
  # - apply uri_query_filter
  w_uri_query_1 <- which(grepl(uri_query_filter, pageviewsData$uri_query))
  w_uri_query_2 <- which(grepl(uri_query_filter, pageviewsData$referer))
  w_uri_query <- unique(c(w_uri_query_1, w_uri_query_2))

  if (length(w_uri_query) > 0) {
    
    # - filter for w_uri_query
    pageviewsData <- pageviewsData[w_uri_query, ] 
    
    # - copy uri_query from referer where uri_query is empty:
    wCuriq <- which(pageviewsData$uri_query == "")
    curiq <- stringr::str_extract(pageviewsData$referer[wCuriq], 
                                  paste0(uri_query_filter, ".+$"))
    pageviewsData$uri_query[wCuriq] <- curiq
    # - remove ?campaign= from pageviewsData$uri_query
    pageviewsData$uri_query <- gsub("?campaign=", 
                                    "",
                                    pageviewsData$uri_query, 
                                    fixed = T)
    
    # - aggregate:
    pageviewsData$uri_path <- paste0(pageviewsData$uri_host, pageviewsData$uri_path)
    pageviewsData$uri_host <- NULL
    pageviewsData$page <- NULL
    pageviewsData$referer <- NULL
    pageviewsData <- pageviewsData %>% 
      dplyr::select(uri_query, uri_path) %>% 
      dplyr::group_by(uri_query, uri_path) %>% 
      dplyr::summarise(pageviews = n())
    colnames(pageviewsData) <- c('Tag', 'Page', 'Pageviews')
    
    # - add cetDay, campaignName
    pageviewsData$date <- cetDay
    pageviewsData$campaign <- campaignName
    
    # - store:
    write.csv(pageviewsData, 
              paste0(analyticsDir, 
                     "pageviewsAggregated_",
                     strsplit(
                       strsplit(fileName, split = "_", fixed = T)[[1]][2],
                       split = ".", 
                       fixed = T)[[1]][1],
                     ".csv"
              )
    )
    
  }
  
}

# - set params to wmde_process_pageviews
uri_query_filter <- 'WMDE_oceditors_fall_2021'
page_filter <- c('/wiki/Wikipedia:Wikimedia_Deutschland/DeinEngagement',
                 '/wiki/Wikipedia:Wikimedia_Deutschland/LerneWikipedia', 
                 '/wiki/Wikipedia:F%C3%B6rderung/F%C3%B6rderangebote')

# - wrangle pageviews
wmde_process_pageviews(fileName = fileName,
                       dataDir = dataDir,
                       uri_query_filter = uri_query_filter, 
                       page_filter = page_filter,
                       cetDay = cetDay,
                       campaignName = campaignName)


### ---------------------------------------------------------------------------
### --- Compose and copy to publicDir
### ---------------------------------------------------------------------------

lF <- list.files(analyticsDir)
lF <- lF[grepl("Aggregated", lF)]
lFp <- lF[grepl("pageviews", lF)]
lFp <- lapply(paste0(analyticsDir, lFp),
              data.table::fread)
lFp <- data.table::rbindlist(lFp)
write.csv(lFp, 
          paste0(publicDir, 
                 "2021_OccasionalEditors_Pageviews.csv"))
lFb <- lF[grepl("banner", lF)]
lFb <- lapply(paste0(analyticsDir, lFb),
              data.table::fread)
lFb <- data.table::rbindlist(lFb)
write.csv(lFb, 
          paste0(publicDir, 
                 "2021_OccasionalEditors_Banners.csv"))

1. Campaign Banners

This section presents all data and statistics on the campaign banners.

2. Pageviews

2.1 Pageviews Overview

Chart 2.1.1. Pageviews Overview.

Table 2.2.1. Pageviews Overview

### --- Full Dataset (Table Report)
datatable(dataSet %>% arrange(desc(Pageviews)))

2.2 Pageviews Daily

2.3 Pageviews per Tag

2.4 Pageviews per Page

LS0tCnRpdGxlOiAnT2NjYXNpb25hbCBFZGl0b3JzIDIwMjE6IEludGVyaW0gUmVwb3J0JwphdXRob3I6ICJHb3JhbiBTLiBNaWxvdmFub3ZpYywgRGF0YSBTY2llbnRpc3QsIFdNREUiCmRhdGU6ICJOb3ZlbWJlciAzLCAyMDIxIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgdGhlbWU6IGNvc21vCiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICAgIHRvY19kZXB0aDogNQogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiA1Ci0tLQoKKipGZWVkYmFjayoqIHNob3VsZCBiZSBzZW5kIHRvIGBnb3Jhbi5taWxvdmFub3ZpY19leHRAd2lraW1lZGlhLmRlYC4gCgpUaGUgY2FtcGFpZ24gaXMgcnVuIGZyb20gMjAyMS8xMC8xOCB0byAyMDIxLzEwLzMxLgoKKipDVVJSRU5UIFVQREFURToqKiBDb21wbGV0ZSBkYXRhc2V0IGFzIG9mIDIwMjEvMTAvMzEuCgpgYGB7ciwgZWNobyA9IEYsIHdhcm5pbmcgPSAnaGlkZScsIG1lc3NhZ2UgPSBGLCByZXN1bHRzID0gJ2hpZGUnfQojICFkaWFnbm9zdGljcyBvZmYKIyMjIC0tLSBTZXR1cApvcHRpb25zKGRwbHlyLnN1bW1hcmlzZS5pbmZvcm0gPSBGQUxTRSkKa25pdHI6Om9wdHNfY2h1bmskc2V0KGZpZy53aWR0aCA9IDE1LCBmaWcuaGVpZ2h0ID0gOCkgCnJtKGxpc3QgPSBscygpKQpsaWJyYXJ5KHN0cmluZ3IpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkoZGF0YS50YWJsZSkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGdncmVwZWwpCmxpYnJhcnkoc2NhbGVzKQpsaWJyYXJ5KFJDb2xvckJyZXdlcikKbGlicmFyeShrYWJsZUV4dHJhKQpsaWJyYXJ5KHJtYXJrZG93bikKbGlicmFyeShrbml0cikKbGlicmFyeShEVCkKbGlicmFyeShyZXNoYXBlMikKbGlicmFyeShwdXJycikKYGBgCgojIyAwLiBEYXRhIEFjcXVpc2l0b24KCioqTk9URToqKiB0aGUgRGF0YSBBY3F1aXNpdGlvbiBjb2RlIGNodW5rIGlzIG5vdCBmdWxseSByZXByb2R1Y2libGUgZnJvbSB0aGlzIFJlcG9ydC4gVGhlIGRhdGEgYXJlIGNvbGxlY3RlZCBieSBydW5uaW5nIGFuIFIgc2NyaXB0IG9uIGBzdGF0MTAwNy5lcWlhZC53bW5ldGAsIGNvbGxlY3RpbmcgdGhlIGRhdGEgYXMgYC50c3ZgIGFuZCBgLmNzdmAgZmlsZXMsIGNvcHlpbmcgbWFudWFsbHksIGFuZCBwcm9jZXNzaW5nIGxvY2FsbHkuIAoKIyMjIDAuMSBEYWlseSBVcGRhdGUKCmBgYHtyLCBlY2hvID0gVCwgZXZhbCA9IEZ9CgojIyMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIyMgLS0tIFdNREUgMjAyMSBPY2Fzc2lvbmFsIEVkaXRvcnMKIyMjIC0tLSBodHRwczovL3BoYWJyaWNhdG9yLndpa2ltZWRpYS5vcmcvVDI5MTYzNQojIyMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyMjIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyMjIC0tLSBDYW1wYWlnbiBEZXNjcmlwdGlvbiBhbmQgUGFyYW1ldGVycwojIyMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyAtIExhbmRpbmcgUGFnZXM6CiMgLSBMYW5kaW5nIFBhZ2UgMTogaHR0cHM6Ly9kZS53aWtpcGVkaWEub3JnL3dpa2kvV2lraXBlZGlhOldpa2ltZWRpYV9EZXV0c2NobGFuZC9EZWluRW5nYWdlbWVudAojIC0gTGFuZGluZyBQYWdlIDJhOiBodHRwczovL3Rvb2xzLndtZmxhYnMub3JnL21pdG1hY2hlbi8KIyAtIExhbmRpbmcgUGFnZSAyYjogaHR0cHM6Ly9kZS53aWtpcGVkaWEub3JnL3dpa2kvV2lraXBlZGlhOldpa2ltZWRpYV9EZXV0c2NobGFuZC9MZXJuZVdpa2lwZWRpYQojIC0gTGFuZGluZyBQYWdlIDJjOiBodHRwczovL2RlLndpa2lwZWRpYS5vcmcvd2lraS9XaWtpcGVkaWE6RiVDMyVCNnJkZXJ1bmcvRiVDMyVCNnJkZXJhbmdlYm90ZQojIC0gQ2FtcGFpZ24gdGFnczoKIyAtIFdNREVfb2NlZGl0b3JzX2ZhbGxfMjAyMQoKIyAtIFN0YXJ0IG9mIHRoZSBiYW5uZXIgY2FtcGFpZ246IE9jdG9iZXIgMTJ0aAojIC0gRW5kIG9mIHRoZSBiYW5uZXIgY2FtcGFpZ246IE9jdG9iZXIgMjYgdGgKIyAtIFRyYWNraW5nIHRlc3Q6IE9jdG9iZXIgNSAtIDcKIyAtIFByZWxpbWluYXJ5IHJlcG9ydCBmb3IgdHJhY2tpbmc6IGJlZ2lubmluZyBvZiBOb3ZlbWJlcgojIC0gVHJhY2sgZWRpdGluZyBiZWhhdmlvciBmb3VyIHdlZWtzIGFmdGVyIGVuZCBvZiBjYW1wYWlnbjogTm92ZW1iZXIgMjNyZAojIC0gZmluYWwgcmVwb3J0IGZvciB0cmFja2luZzogYmVnaW5uaW5nIG9mIERlY2VtYmVyCgojIyMgLS0tIGxpYnJhcmllcwpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShkYXRhLnRhYmxlKQpsaWJyYXJ5KGx1YnJpZGF0ZSkKCiMjIyAtLS0gY2FtcGFpZ24gc3BlY2lmaWNzCmNhbXBhaWduTmFtZSA8LSAnT2NjYXNpb25hbEVkaXRvcnNfMjAyMScKCiMjIyAtLS0gZGlyIHN0cnVjdHVyZQpjYW1wYWlnblBhdGggPC0gJy9ob21lL2dvcmFuc20vQW5hbHl0aWNzL05ld0VkaXRvcnMvMjAyMV9PY2Nhc2lvbmFsRWRpdG9ycy8nCmRhdGFEaXIgPC0gcGFzdGUwKGNhbXBhaWduUGF0aCwgIl9kYXRhLyIpCmFuYWx5dGljc0RpciA8LSBwYXN0ZTAoY2FtcGFpZ25QYXRoLCAiX2FuYWx5dGljcy8iKQpwdWJsaWNEaXIgPC0gJy9zcnYvcHVibGlzaGVkL2RhdGFzZXRzL3dtZGUtYW5hbHl0aWNzLWVuZ2luZWVyaW5nL05ld0VkaXRvcnMvY2FtcGFpZ25zLzIwMjFfT2NjYXNpb25hbEVkaXRvcnMvJwoKIyMjIC0tLSBkZXRlcm1pbmUgY2V0RGF5CmNldERheSA8LSBTeXMudGltZSgpCmNldERheQphdHRyKGNldERheSwgInR6b25lIikgPC0gIkV1cm9wZS9CZXJsaW4iCiMgLSBvbmUgZGF5IGJlaGluZCBmb3IgY3JvbnRhYgojIC0gKGkuZS4gd2FpdGluZyBmb3Igd21mLndlYnJlcXVlc3QgdG8gY29tcGxldGUgaXMgZGF0YSBhY3F1aXNpdGlvbikKY2V0RGF5IDwtIHltZCgKICBzdHJzcGxpdChhcy5jaGFyYWN0ZXIoY2V0RGF5KSwgCiAgICAgICAgICAgc3BsaXQgPSAiICIsIAogICAgICAgICAgIGZpeGVkID0gVClbWzFdXVsxXQopIC0gMQoKIyMjIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyMjIC0tLSBCYW5uZXIgSW50ZXJhY3Rpb25zOgojIyMgLS0tIHZpYSBldmVudC5XTURFQmFubmVySW50ZXJhY3Rpb25zCiMjIyAtLS0gaHR0cHM6Ly9tZXRhLndpa2ltZWRpYS5vcmcvd2lraS9TY2hlbWE6V01ERUJhbm5lckludGVyYWN0aW9ucwojIyMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyAtIHNlbGVjdCBkdCwgZXZlbnQuYmFubmVyTmFtZSwgZXZlbnQuYmFubmVyQWN0aW9uLCBldmVudC5iYW5uZXJJbXByZXNzaW9ucywgZXZlbnQudXNlcklEIAojIC0gZnJvbSBldmVudC53bWRlYmFubmVyaW50ZXJhY3Rpb25zIHdoZXJlIHllYXI9MjAyMCBhbmQgbW9udGg9NSBhbmQgKGRheT0xMSBvciBkYXk9MTIgb3IgZGF5PTEzKTsKCiMgLSBmdW5jdGlvbjogd21kZV9iYW5uZXJfYWN0aW9ucwp3bWRlX2Jhbm5lcl9hY3Rpb25zIDwtIGZ1bmN0aW9uKHVyaV9xdWVyeV9maWx0ZXIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2V0RGF5LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHF1ZXJ5RmlsZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxlTmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbmFseXRpY3NEaXIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FtcGFpZ25OYW1lKSB7CiAgCiAgIyAtIE5PVEU6CiAgIyAtIGV4cGVjdGVkIGZvcm1hdCBmb3IgY2V0RGF5IGlzOiBZWVlZLU1NLURECiAgCiAgIyAtIFdIRVJFIGNvbmRpdGlvbjogY3JlYXRlIGRhdGV0aW1lX2NvbmRpdGlvbgogIGNldF9jb25kaXRpb24gPC0gc2VxKAogICAgZnJvbSA9IGFzLlBPU0lYY3QocGFzdGUwKGNldERheSwiIDA6MDAiKSwgdHogPSAiRXVyb3BlL0JlcmxpbiIpLAogICAgdG8gPSBhcy5QT1NJWGN0KHBhc3RlMChjZXREYXksIiAyMzowMCIpLCB0eiA9ICJFdXJvcGUvQmVybGluIiksCiAgICBieSA9ICJob3VyIgogICkgCiAgYXR0cihjZXRfY29uZGl0aW9uLCAidHpvbmUiKSA8LSAiVVRDIgogIGNldF9jb25kaXRpb24gPC0gYXMuY2hhcmFjdGVyKGNldF9jb25kaXRpb24pCiAgY2V0X2NvbmRpdGlvbiA8LSB1bmxpc3Qoc3RyX2V4dHJhY3RfYWxsKGNldF9jb25kaXRpb24sICJeKFtbOmRpZ2l0Ol1dfFxcc3wtKSoiKSkKICBjZXRfeWVhcnMgPC0gc2FwcGx5KAogICAgc3Ryc3BsaXQoY2V0X2NvbmRpdGlvbiwgc3BsaXQgPSAiICIsIGZpeGVkID0gVCksIGZ1bmN0aW9uKHgpIHsKICAgICAgc3Ryc3BsaXQoeCwgc3BsaXQgPSAiLSIpW1sxXV1bMV0KICAgIH0pCiAgY2V0X21vbnRocyA8LSBzYXBwbHkoCiAgICBzdHJzcGxpdChjZXRfY29uZGl0aW9uLCBzcGxpdCA9ICIgIiwgZml4ZWQgPSBUKSwgZnVuY3Rpb24oeCkgewogICAgICBzdHJzcGxpdCh4LCBzcGxpdCA9ICItIilbWzFdXVsyXQogICAgfSkKICBjZXRfbW9udGhzIDwtIGdzdWIoIl4wIiwgIiIsIGNldF9tb250aHMpCiAgY2V0X2RheXMgPC0gc2FwcGx5KAogICAgc3Ryc3BsaXQoY2V0X2NvbmRpdGlvbiwgc3BsaXQgPSAiICIsIGZpeGVkID0gVCksIGZ1bmN0aW9uKHgpIHsKICAgICAgc3Ryc3BsaXQoeCwgc3BsaXQgPSAiLSIpW1sxXV1bM10KICAgIH0pCiAgY2V0X2RheXMgPC0gZ3N1YigiXjAiLCAiIiwgY2V0X2RheXMpCiAgY2V0X2hvdXJzIDwtIHNhcHBseShzdHJzcGxpdChjZXRfY29uZGl0aW9uLCBzcGxpdCA9ICIgIiwgZml4ZWQgPSBUKSwgCiAgICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbih4KSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHhbMl0KICAgICAgICAgICAgICAgICAgICAgIH0pCiAgY2V0X2hvdXJzIDwtIGdzdWIoIl4wIiwgIiIsIGNldF9ob3VycykKICBkYXRldGltZUNvbmRpdGlvbiA8LSBwYXN0ZTAoCiAgICAieWVhciA9ICIsIGNldF95ZWFycywgIiBBTkQgIiwKICAgICJtb250aCA9ICIsIGNldF9tb250aHMsICIgQU5EICIsCiAgICAiZGF5ID0gIiwgY2V0X2RheXMsICIgQU5EICIsIAogICAgImhvdXIgPSAiLCBjZXRfaG91cnMKICApCiAgZGF0ZXRpbWVDb25kaXRpb24gPC0gcGFzdGUoIigiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRldGltZUNvbmRpdGlvbiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIikiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbGxhcHNlID0gIiBPUiAiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXAgPSAiIikKICAKICAKICAjIC0gV0hFUkUgY29uZGl0aW9uOiBjcmVhdGUgZXZlbnRCYW5uZXJOYW1lX2NvbmRpdGlvbgogIGlmIChsZW5ndGgodXJpX3F1ZXJ5X2ZpbHRlcikgPiAxKSB7CiAgICBldmVudEJhbm5lck5hbWVfY29uZGl0aW9uIDwtIHBhc3RlMCgiKCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZSgKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUwKCJldmVudC5iYW5uZXJOYW1lIExJS0UgJyUiLCB1cmlfcXVlcnlfZmlsdGVyLCAiJSciKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sbGFwc2UgPSAiIE9SICIsIHNlcCA9ICIgIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiKSIKICAgICkKICB9IGVsc2UgewogICAgZXZlbnRCYW5uZXJOYW1lX2NvbmRpdGlvbiA9IHBhc3RlMCgiZXZlbnQuYmFubmVyTmFtZSBMSUtFICclIiwgdXJpX3F1ZXJ5X2ZpbHRlciwgIiUnIikKICB9CiAgCiAgIyAtIGNvbXBvc2UgSGl2ZVFMIHF1ZXJ5CiAgaGl2ZVF1ZXJ5IDwtIHBhc3RlMCggCiAgICAic2VsZWN0IGR0LCBldmVudC5iYW5uZXJOYW1lLCBldmVudC5iYW5uZXJBY3Rpb24sIGV2ZW50LmJhbm5lckltcHJlc3Npb25zLCBldmVudC51c2VySUQgZnJvbSBldmVudC53bWRlYmFubmVyaW50ZXJhY3Rpb25zIAogICAgV0hFUkUgKCIsCiAgICBldmVudEJhbm5lck5hbWVfY29uZGl0aW9uLCAiIEFORCAiLAogICAgIigiLCBkYXRldGltZUNvbmRpdGlvbiwgIikiLAogICAgIik7IgogICkKICAKICAjIC0gd3JpdGUgaHFsCiAgd3JpdGUoaGl2ZVF1ZXJ5LCBwYXN0ZTAoZGF0YURpciwgcXVlcnlGaWxlKSkKICAjIC0gZXhlY3V0ZSBocWwgc2NyaXB0OgogIGtlcmJlcm9zUHJlZml4IDwtIAogICAgJ3N1ZG8gLXUgYW5hbHl0aWNzLXByaXZhdGVkYXRhIGtlcmJlcm9zLXJ1bi1jb21tYW5kIGFuYWx5dGljcy1wcml2YXRlZGF0YSAnCiAgIyAtIEtlcmJlcm9zIGluaXQKICBzeXN0ZW0oY29tbWFuZCA9IHBhc3RlMChrZXJiZXJvc1ByZWZpeCwgJyBoZGZzIGRmcyAtbHMnKSwgCiAgICAgICAgIHdhaXQgPSBUKQogICMgLSBSdW4gcXVlcnkKICBxdWVyeSA8LSBzeXN0ZW0oY29tbWFuZCA9IHBhc3RlKGtlcmJlcm9zUHJlZml4LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICcvdXNyL2xvY2FsL2Jpbi9iZWVsaW5lIC0taW5jcmVtZW50YWw9dHJ1ZSAtLXNpbGVudCAtZiAiJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlMChkYXRhRGlyLCBxdWVyeUZpbGUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJyIgPiAnLCBkYXRhRGlyLCBmaWxlTmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcCA9ICIiKSwKICAgICAgICAgICAgICAgICAgd2FpdCA9IFRSVUUpCiAgCiAgIyAtIFdyYW5nbGUgQmFubmVyIEludGVyYWN0aW9ucwogICMgLSBsb2FkCiAgYmFubmVyRGF0YSA8LSB0cnlDYXRjaCh7CiAgICBhcy5kYXRhLmZyYW1lKGZyZWFkKHBhc3RlMChkYXRhRGlyLCBmaWxlTmFtZSkpKQogIH0sCiAgZXJyb3IgPSBmdW5jdGlvbihjb25kaXRpb24pIHsKICAgIHJldHVybihGQUxTRSkKICB9KQogIAogICMgLSBwcm9jZXNzCiAgaWYgKGNsYXNzKGJhbm5lckRhdGEpID09ICdsb2dpY2FsJykgewogICAgCiAgICByZXR1cm4oRkFMU0UpIAogICAgCiAgfSBlbHNlIHsgCiAgICAKICAgICMgLSB3aG9DbGlja2VkCiAgICB3aG9DbGlja2VkIDwtIGJhbm5lckRhdGEgJT4lIAogICAgICBkcGx5cjo6ZmlsdGVyKGJhbm5lcmFjdGlvbiA9PSAiYmFubmVyLWNsaWNrZWQiKQogICAgd2hvQ2xpY2tlZCA8LSBkYXRhLmZyYW1lKHVzZXJpZCA9IHVuaXF1ZSh3aG9DbGlja2VkJHVzZXJpZCkpCiAgICAKICAgICMgLSBzdG9yZToKICAgIHdyaXRlLmNzdih3aG9DbGlja2VkLCAKICAgICAgICAgICAgICBwYXN0ZTAoYW5hbHl0aWNzRGlyLCAKICAgICAgICAgICAgICAgICAgICAgIndob0NsaWNrZWRfIiwKICAgICAgICAgICAgICAgICAgICAgc3Ryc3BsaXQoCiAgICAgICAgICAgICAgICAgICAgICAgc3Ryc3BsaXQoZmlsZU5hbWUsIHNwbGl0ID0gIl8iLCBmaXhlZCA9IFQpW1sxXV1bMl0sCiAgICAgICAgICAgICAgICAgICAgICAgc3BsaXQgPSAiLiIsIAogICAgICAgICAgICAgICAgICAgICAgIGZpeGVkID0gVClbWzFdXVsxXSwKICAgICAgICAgICAgICAgICAgICAgIi5jc3YiCiAgICAgICAgICAgICAgKQogICAgKQogICAgCiAgICAjIC0gcHJvY2VzcyBiYW5uZXJEYXRhCiAgICBiYW5uZXJEYXRhIDwtIHQodGFibGUoYmFubmVyRGF0YSRiYW5uZXJhY3Rpb24sCiAgICAgICAgICAgICAgICAgICAgICAgICAgYmFubmVyRGF0YSRiYW5uZXJuYW1lKSkKICAgIGJhbm5lckRhdGEgPC0gYXMuZGF0YS5mcmFtZShiYW5uZXJEYXRhKQogICAgY29sbmFtZXMoYmFubmVyRGF0YSkgPC0gYygnYmFubmVyJywgJ2FjdGlvbicsICdjb3VudCcpCiAgICBiYW5uZXJEYXRhJGRheSA8LSBjZXREYXkKICAgIGJhbm5lckRhdGEkY2FtcGFpZ24gPC0gY2FtcGFpZ25OYW1lCiAgICAKICAgICMgLSBzdG9yZToKICAgIHdyaXRlLmNzdihiYW5uZXJEYXRhLCAKICAgICAgICAgICAgICBwYXN0ZTAoYW5hbHl0aWNzRGlyLCAKICAgICAgICAgICAgICAgICAgICAgImJhbm5lckludGVyYWN0aW9uc0FnZ3JlZ2F0ZWRfIiwKICAgICAgICAgICAgICAgICAgICAgc3Ryc3BsaXQoCiAgICAgICAgICAgICAgICAgICAgICAgc3Ryc3BsaXQoZmlsZU5hbWUsIHNwbGl0ID0gIl8iLCBmaXhlZCA9IFQpW1sxXV1bMl0sCiAgICAgICAgICAgICAgICAgICAgICAgc3BsaXQgPSAiLiIsIAogICAgICAgICAgICAgICAgICAgICAgIGZpeGVkID0gVClbWzFdXVsxXSwKICAgICAgICAgICAgICAgICAgICAgIi5jc3YiCiAgICAgICAgICAgICAgKSkKICB9CiAgCn0KCiMgLSBzZXQgcGFyYW1zIGZvciB3bWRlX2Jhbm5lcl9hY3Rpb25zKCkKcXVlcnlGaWxlIDwtIHBhc3RlMChjYW1wYWlnbk5hbWUsICJfYmFubmVySW50ZXJhY3Rpb25zLmhxbCIpCmZpbGVOYW1lIDwtIHBhc3RlMCgiYmFubmVySW50ZXJhY3Rpb25zXyIsIGNldERheSwgIi50c3YiKQp1cmlfcXVlcnlfZmlsdGVyIDwtICdXTURFX29jZWRpdG9yc19mYWxsXzIwMjEnCmJhbm5lcl9zdGF0dXMgPC0gd21kZV9iYW5uZXJfYWN0aW9ucyh1cmlfcXVlcnlfZmlsdGVyID0gdXJpX3F1ZXJ5X2ZpbHRlciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNldERheSA9IGNldERheSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHF1ZXJ5RmlsZSA9IHF1ZXJ5RmlsZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGVOYW1lID0gZmlsZU5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbmFseXRpY3NEaXIgPSBhbmFseXRpY3NEaXIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FtcGFpZ25OYW1lID0gY2FtcGFpZ25OYW1lKQoKIyMjIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyMjIC0tLSBQYWdldmlld3MKIyMjIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMgLSBmdW5jdGlvbjogd21kZV9jb2xsZWN0X3BhZ2V2aWV3cwp3bWRlX2NvbGxlY3RfcGFnZXZpZXdzIDwtIGZ1bmN0aW9uKHVyaV9ob3N0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVyaV9wYXRoLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNldERheSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBxdWVyeUZpbGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsZU5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YURpcikgewogIAogICMgLSBOT1RFOgogICMgLSBleHBlY3RlZCBmb3JtYXQgZm9yIGNldERheSBpczogWVlZWS1NTS1ERAogIAogICMgLSB0byBkYXRhRGlyCiAgc2V0d2QoZGF0YURpcikKICAKICAjIC0gbGlicmFyaWVzCiAgbGlicmFyeShzdHJpbmdyKQogIAogICMgLSBXSEVSRSBjb25kaXRpb246IGNyZWF0ZSBkYXRldGltZV9jb25kaXRpb24KICBjZXRfY29uZGl0aW9uIDwtIHNlcSgKICAgIGZyb20gPSBhcy5QT1NJWGN0KHBhc3RlMChjZXREYXksIiAwOjAwIiksIHR6ID0gIkV1cm9wZS9CZXJsaW4iKSwKICAgIHRvID0gYXMuUE9TSVhjdChwYXN0ZTAoY2V0RGF5LCIgMjM6MDAiKSwgdHogPSAiRXVyb3BlL0JlcmxpbiIpLAogICAgYnkgPSAiaG91ciIKICApIAogIGF0dHIoY2V0X2NvbmRpdGlvbiwgInR6b25lIikgPC0gIlVUQyIKICBjZXRfY29uZGl0aW9uIDwtIGFzLmNoYXJhY3RlcihjZXRfY29uZGl0aW9uKQogIGNldF9jb25kaXRpb24gPC0gdW5saXN0KHN0cl9leHRyYWN0X2FsbChjZXRfY29uZGl0aW9uLCAiXihbWzpkaWdpdDpdXXxcXHN8LSkqIikpCiAgY2V0X3llYXJzIDwtIHNhcHBseSgKICAgIHN0cnNwbGl0KGNldF9jb25kaXRpb24sIHNwbGl0ID0gIiAiLCBmaXhlZCA9IFQpLCBmdW5jdGlvbih4KSB7CiAgICAgIHN0cnNwbGl0KHgsIHNwbGl0ID0gIi0iKVtbMV1dWzFdCiAgICB9KQogIGNldF9tb250aHMgPC0gc2FwcGx5KAogICAgc3Ryc3BsaXQoY2V0X2NvbmRpdGlvbiwgc3BsaXQgPSAiICIsIGZpeGVkID0gVCksIGZ1bmN0aW9uKHgpIHsKICAgICAgc3Ryc3BsaXQoeCwgc3BsaXQgPSAiLSIpW1sxXV1bMl0KICAgIH0pCiAgY2V0X21vbnRocyA8LSBnc3ViKCJeMCIsICIiLCBjZXRfbW9udGhzKQogIGNldF9kYXlzIDwtIHNhcHBseSgKICAgIHN0cnNwbGl0KGNldF9jb25kaXRpb24sIHNwbGl0ID0gIiAiLCBmaXhlZCA9IFQpLCBmdW5jdGlvbih4KSB7CiAgICAgIHN0cnNwbGl0KHgsIHNwbGl0ID0gIi0iKVtbMV1dWzNdCiAgICB9KQogIGNldF9kYXlzIDwtIGdzdWIoIl4wIiwgIiIsIGNldF9kYXlzKQogIGNldF9ob3VycyA8LSBzYXBwbHkoc3Ryc3BsaXQoY2V0X2NvbmRpdGlvbiwgc3BsaXQgPSAiICIsIGZpeGVkID0gVCksIAogICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oeCkgewogICAgICAgICAgICAgICAgICAgICAgICB4WzJdCiAgICAgICAgICAgICAgICAgICAgICB9KQogIGNldF9ob3VycyA8LSBnc3ViKCJeMCIsICIiLCBjZXRfaG91cnMpCiAgZGF0ZXRpbWVDb25kaXRpb24gPC0gcGFzdGUwKAogICAgInllYXIgPSAiLCBjZXRfeWVhcnMsICIgQU5EICIsCiAgICAibW9udGggPSAiLCBjZXRfbW9udGhzLCAiIEFORCAiLAogICAgImRheSA9ICIsIGNldF9kYXlzLCAiIEFORCAiLCAKICAgICJob3VyID0gIiwgY2V0X2hvdXJzCiAgKQogIGRhdGV0aW1lQ29uZGl0aW9uIDwtIHBhc3RlKCIoIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0ZXRpbWVDb25kaXRpb24sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICIpIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xsYXBzZSA9ICIgT1IgIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VwID0gIiIpCiAgCiAgIyAtIFdIRVJFIGNvbmRpdGlvbjogY3JlYXRlIHVyaV9ob3N0X2NvbmRpdGlvbgogIGlmIChsZW5ndGgodXJpX2hvc3QpID4gMSkgewogICAgdXJpX2hvc3RfY29uZGl0aW9uIDwtIHBhc3RlMCgiKCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlKAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlMCgidXJpX2hvc3QgPSAnIiwgdXJpX2hvc3QsICInIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sbGFwc2UgPSAiIE9SICIsIHNlcCA9ICIgIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIpIgogICAgKQogIH0gZWxzZSB7CiAgICB1cmlfaG9zdF9jb25kaXRpb24gPSBwYXN0ZTAoInVyaV9ob3N0ID0gJyIsIHVyaV9ob3N0LCAiJyIpCiAgfQogIAogICMgLSBXSEVSRSBjb25kaXRpb246IGNyZWF0ZSB1cmlfcGF0aF9jb25kaXRpb24KICBpZiAobGVuZ3RoKHVyaV9wYXRoKSA+IDEpIHsKICAgIHVyaV9wYXRoX2NvbmRpdGlvbiA8LSBwYXN0ZTAoIigiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZSgKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZTAoInVyaV9wYXRoID0gJyIsIHVyaV9wYXRoLCAiJyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbGxhcHNlID0gIiBPUiAiLCBzZXAgPSAiICIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiKSIKICAgICkKICB9IGVsc2UgewogICAgdXJpX3BhdGhfY29uZGl0aW9uID0gcGFzdGUwKCJ1cmlfcGF0aCA9ICciLCB1cmlfcGF0aCwgIiciKQogIH0KICAKICAjIC0gY29tcG9zZSBIaXZlUUwgcXVlcnkKICBoaXZlUXVlcnkgPC0gcGFzdGUwKCAKICAgICJVU0Ugd21mOwogICAgU0VMRUNUIHVyaV9ob3N0LCB1cmlfcGF0aCwgdXJpX3F1ZXJ5LCByZWZlcmVyIEZST00gd2VicmVxdWVzdAogICAgV0hFUkUgKCIsCiAgICB1cmlfaG9zdF9jb25kaXRpb24sICIgQU5EICIsCiAgICB1cmlfcGF0aF9jb25kaXRpb24sICIgQU5EICIsCiAgICAiKCIsIGRhdGV0aW1lQ29uZGl0aW9uLCAiKSIsCiAgICAiKTsiCiAgKQogIAogICMgLSB3cml0ZSBocWwKICB3cml0ZShoaXZlUXVlcnksIHF1ZXJ5RmlsZSkKICAjIC0gZXhlY3V0ZSBocWwgc2NyaXB0OgogIGtlcmJlcm9zUHJlZml4IDwtIAogICAgJ3N1ZG8gLXUgYW5hbHl0aWNzLXByaXZhdGVkYXRhIGtlcmJlcm9zLXJ1bi1jb21tYW5kIGFuYWx5dGljcy1wcml2YXRlZGF0YSAnCiAgIyAtIEtlcmJlcm9zIGluaXQKICBzeXN0ZW0oY29tbWFuZCA9IHBhc3RlMChrZXJiZXJvc1ByZWZpeCwgJyBoZGZzIGRmcyAtbHMnKSwgCiAgICAgICAgIHdhaXQgPSBUKQogICMgLSBSdW4gcXVlcnkKICBxdWVyeSA8LSBzeXN0ZW0oY29tbWFuZCA9IHBhc3RlKGtlcmJlcm9zUHJlZml4LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICcvdXNyL2xvY2FsL2Jpbi9iZWVsaW5lIC0taW5jcmVtZW50YWw9dHJ1ZSAtLXNpbGVudCAtZiAiJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlMChkYXRhRGlyLCBxdWVyeUZpbGUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJyIgPiAnLCBkYXRhRGlyLCBmaWxlTmFtZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcCA9ICIiKSwKICAgICAgICAgICAgICAgICAgd2FpdCA9IFRSVUUpCn0KCiMgLSBzZXQgcGFyYW1zIHRvIHdtZGVfY29sbGVjdF9wYWdldmlld3MKdXJpX2hvc3QgPC0gYygnZGUud2lraXBlZGlhLm9yZycsICdkZS5tLndpa2lwZWRpYS5vcmcnKQp1cmlfcGF0aCAgPC0gYygnL3dpa2kvV2lraXBlZGlhOldpa2ltZWRpYV9EZXV0c2NobGFuZC9EZWluRW5nYWdlbWVudCcsCiAgICAgICAgICAgICAgICcvd2lraS9XaWtpcGVkaWE6V2lraW1lZGlhX0RldXRzY2hsYW5kL0xlcm5lV2lraXBlZGlhJywgCiAgICAgICAgICAgICAgICcvd2lraS9XaWtpcGVkaWE6RiVDMyVCNnJkZXJ1bmcvRiVDMyVCNnJkZXJhbmdlYm90ZScpCnF1ZXJ5RmlsZSA8LSAnV01ERV9vY2VkaXRvcnNfZmFsbF8yMDIxX1BhZ2V2aWV3cy5ocWwnCmZpbGVOYW1lIDwtIHBhc3RlMCgicGFnZXZpZXdzXyIsIGNldERheSwgIi50c3YiKQoKIyAtIGNvbGxlY3QgUGFnZXZpZXdzIGRhdGEKd21kZV9jb2xsZWN0X3BhZ2V2aWV3cyh1cmlfaG9zdCwKICAgICAgICAgICAgICAgICAgICAgICB1cmlfcGF0aCwKICAgICAgICAgICAgICAgICAgICAgICBjZXREYXksCiAgICAgICAgICAgICAgICAgICAgICAgcXVlcnlGaWxlLAogICAgICAgICAgICAgICAgICAgICAgIGZpbGVOYW1lLAogICAgICAgICAgICAgICAgICAgICAgIGRhdGFEaXIpCgojIyMgLS0tIFdyYW5nbGUgUGFnZXZpZXdzCiMgLSBmdW5jdGlvbjogd21kZV9wcm9jZXNzX3BhZ2V2aWV3cwp3bWRlX3Byb2Nlc3NfcGFnZXZpZXdzIDwtIGZ1bmN0aW9uKGZpbGVOYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGFEaXIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVyaV9xdWVyeV9maWx0ZXIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFnZV9maWx0ZXIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2V0RGF5ID0gY2V0RGF5LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhbXBhaWduTmFtZSA9IGNhbXBhaWduTmFtZSkgewogIAogICMgLSB0byBkYXRhRGlyCiAgc2V0d2QoZGF0YURpcikKICAKICAjIC0gbGlicmFyaWVzCiAgbGlicmFyeShzdHJpbmdyKQogIGxpYnJhcnkoZHBseXIpCiAgbGlicmFyeSh0aWR5cikKICBsaWJyYXJ5KGRhdGEudGFibGUpCiAgCiAgIyAtIGxvYWQKICBwYWdldmlld3NEYXRhIDwtIHJlYWRMaW5lcyhmaWxlTmFtZSkKICB3U3RhcnQgPC0gd2hpY2goZ3JlcGwoInVyaV9ob3N0IiwgcGFnZXZpZXdzRGF0YSkpCiAgcGFnZXZpZXdzRGF0YSA8LSBwYWdldmlld3NEYXRhWyh3U3RhcnQgKyAxKToobGVuZ3RoKHBhZ2V2aWV3c0RhdGEpIC0gMSldCiAgcGFnZXZpZXdzRGF0YSA8LSBkYXRhLmZyYW1lKGRhdCA9IHBhZ2V2aWV3c0RhdGEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzID0gRikKICBwYWdldmlld3NEYXRhIDwtIHNlcGFyYXRlKHBhZ2V2aWV3c0RhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbnRvID0gYygndXJpX2hvc3QnLCAndXJpX3BhdGgnLCAndXJpX3F1ZXJ5JywgJ3JlZmVyZXInKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcCA9ICJcdCIpCiAgIyAtIGFwcGx5IHBhZ2VfZmlsdGVyCiAgd0ZpbHRlcjEgPC0gdW5pcXVlKHVubmFtZSh1bmxpc3Qoc2FwcGx5KHBhZ2VfZmlsdGVyLCBmdW5jdGlvbiAoeCkgewogICAgd2hpY2goZ3JlcGwoeCwgcGFnZXZpZXdzRGF0YSR1cmlfcGF0aCkpCiAgfSkpKSkKICBwYWdldmlld3NEYXRhIDwtIHBhZ2V2aWV3c0RhdGFbd0ZpbHRlcjEsIF0KICAjIC0gYXBwbHkgdXJpX3F1ZXJ5X2ZpbHRlcgogIHdfdXJpX3F1ZXJ5XzEgPC0gd2hpY2goZ3JlcGwodXJpX3F1ZXJ5X2ZpbHRlciwgcGFnZXZpZXdzRGF0YSR1cmlfcXVlcnkpKQogIHdfdXJpX3F1ZXJ5XzIgPC0gd2hpY2goZ3JlcGwodXJpX3F1ZXJ5X2ZpbHRlciwgcGFnZXZpZXdzRGF0YSRyZWZlcmVyKSkKICB3X3VyaV9xdWVyeSA8LSB1bmlxdWUoYyh3X3VyaV9xdWVyeV8xLCB3X3VyaV9xdWVyeV8yKSkKCiAgaWYgKGxlbmd0aCh3X3VyaV9xdWVyeSkgPiAwKSB7CiAgICAKICAgICMgLSBmaWx0ZXIgZm9yIHdfdXJpX3F1ZXJ5CiAgICBwYWdldmlld3NEYXRhIDwtIHBhZ2V2aWV3c0RhdGFbd191cmlfcXVlcnksIF0gCiAgICAKICAgICMgLSBjb3B5IHVyaV9xdWVyeSBmcm9tIHJlZmVyZXIgd2hlcmUgdXJpX3F1ZXJ5IGlzIGVtcHR5OgogICAgd0N1cmlxIDwtIHdoaWNoKHBhZ2V2aWV3c0RhdGEkdXJpX3F1ZXJ5ID09ICIiKQogICAgY3VyaXEgPC0gc3RyaW5ncjo6c3RyX2V4dHJhY3QocGFnZXZpZXdzRGF0YSRyZWZlcmVyW3dDdXJpcV0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUwKHVyaV9xdWVyeV9maWx0ZXIsICIuKyQiKSkKICAgIHBhZ2V2aWV3c0RhdGEkdXJpX3F1ZXJ5W3dDdXJpcV0gPC0gY3VyaXEKICAgICMgLSByZW1vdmUgP2NhbXBhaWduPSBmcm9tIHBhZ2V2aWV3c0RhdGEkdXJpX3F1ZXJ5CiAgICBwYWdldmlld3NEYXRhJHVyaV9xdWVyeSA8LSBnc3ViKCI/Y2FtcGFpZ249IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYWdldmlld3NEYXRhJHVyaV9xdWVyeSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpeGVkID0gVCkKICAgIAogICAgIyAtIGFnZ3JlZ2F0ZToKICAgIHBhZ2V2aWV3c0RhdGEkdXJpX3BhdGggPC0gcGFzdGUwKHBhZ2V2aWV3c0RhdGEkdXJpX2hvc3QsIHBhZ2V2aWV3c0RhdGEkdXJpX3BhdGgpCiAgICBwYWdldmlld3NEYXRhJHVyaV9ob3N0IDwtIE5VTEwKICAgIHBhZ2V2aWV3c0RhdGEkcGFnZSA8LSBOVUxMCiAgICBwYWdldmlld3NEYXRhJHJlZmVyZXIgPC0gTlVMTAogICAgcGFnZXZpZXdzRGF0YSA8LSBwYWdldmlld3NEYXRhICU+JSAKICAgICAgZHBseXI6OnNlbGVjdCh1cmlfcXVlcnksIHVyaV9wYXRoKSAlPiUgCiAgICAgIGRwbHlyOjpncm91cF9ieSh1cmlfcXVlcnksIHVyaV9wYXRoKSAlPiUgCiAgICAgIGRwbHlyOjpzdW1tYXJpc2UocGFnZXZpZXdzID0gbigpKQogICAgY29sbmFtZXMocGFnZXZpZXdzRGF0YSkgPC0gYygnVGFnJywgJ1BhZ2UnLCAnUGFnZXZpZXdzJykKICAgIAogICAgIyAtIGFkZCBjZXREYXksIGNhbXBhaWduTmFtZQogICAgcGFnZXZpZXdzRGF0YSRkYXRlIDwtIGNldERheQogICAgcGFnZXZpZXdzRGF0YSRjYW1wYWlnbiA8LSBjYW1wYWlnbk5hbWUKICAgIAogICAgIyAtIHN0b3JlOgogICAgd3JpdGUuY3N2KHBhZ2V2aWV3c0RhdGEsIAogICAgICAgICAgICAgIHBhc3RlMChhbmFseXRpY3NEaXIsIAogICAgICAgICAgICAgICAgICAgICAicGFnZXZpZXdzQWdncmVnYXRlZF8iLAogICAgICAgICAgICAgICAgICAgICBzdHJzcGxpdCgKICAgICAgICAgICAgICAgICAgICAgICBzdHJzcGxpdChmaWxlTmFtZSwgc3BsaXQgPSAiXyIsIGZpeGVkID0gVClbWzFdXVsyXSwKICAgICAgICAgICAgICAgICAgICAgICBzcGxpdCA9ICIuIiwgCiAgICAgICAgICAgICAgICAgICAgICAgZml4ZWQgPSBUKVtbMV1dWzFdLAogICAgICAgICAgICAgICAgICAgICAiLmNzdiIKICAgICAgICAgICAgICApCiAgICApCiAgICAKICB9CiAgCn0KCiMgLSBzZXQgcGFyYW1zIHRvIHdtZGVfcHJvY2Vzc19wYWdldmlld3MKdXJpX3F1ZXJ5X2ZpbHRlciA8LSAnV01ERV9vY2VkaXRvcnNfZmFsbF8yMDIxJwpwYWdlX2ZpbHRlciA8LSBjKCcvd2lraS9XaWtpcGVkaWE6V2lraW1lZGlhX0RldXRzY2hsYW5kL0RlaW5FbmdhZ2VtZW50JywKICAgICAgICAgICAgICAgICAnL3dpa2kvV2lraXBlZGlhOldpa2ltZWRpYV9EZXV0c2NobGFuZC9MZXJuZVdpa2lwZWRpYScsIAogICAgICAgICAgICAgICAgICcvd2lraS9XaWtpcGVkaWE6RiVDMyVCNnJkZXJ1bmcvRiVDMyVCNnJkZXJhbmdlYm90ZScpCgojIC0gd3JhbmdsZSBwYWdldmlld3MKd21kZV9wcm9jZXNzX3BhZ2V2aWV3cyhmaWxlTmFtZSA9IGZpbGVOYW1lLAogICAgICAgICAgICAgICAgICAgICAgIGRhdGFEaXIgPSBkYXRhRGlyLAogICAgICAgICAgICAgICAgICAgICAgIHVyaV9xdWVyeV9maWx0ZXIgPSB1cmlfcXVlcnlfZmlsdGVyLCAKICAgICAgICAgICAgICAgICAgICAgICBwYWdlX2ZpbHRlciA9IHBhZ2VfZmlsdGVyLAogICAgICAgICAgICAgICAgICAgICAgIGNldERheSA9IGNldERheSwKICAgICAgICAgICAgICAgICAgICAgICBjYW1wYWlnbk5hbWUgPSBjYW1wYWlnbk5hbWUpCgoKIyMjIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIyMgLS0tIENvbXBvc2UgYW5kIGNvcHkgdG8gcHVibGljRGlyCiMjIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCmxGIDwtIGxpc3QuZmlsZXMoYW5hbHl0aWNzRGlyKQpsRiA8LSBsRltncmVwbCgiQWdncmVnYXRlZCIsIGxGKV0KbEZwIDwtIGxGW2dyZXBsKCJwYWdldmlld3MiLCBsRildCmxGcCA8LSBsYXBwbHkocGFzdGUwKGFuYWx5dGljc0RpciwgbEZwKSwKICAgICAgICAgICAgICBkYXRhLnRhYmxlOjpmcmVhZCkKbEZwIDwtIGRhdGEudGFibGU6OnJiaW5kbGlzdChsRnApCndyaXRlLmNzdihsRnAsIAogICAgICAgICAgcGFzdGUwKHB1YmxpY0RpciwgCiAgICAgICAgICAgICAgICAgIjIwMjFfT2NjYXNpb25hbEVkaXRvcnNfUGFnZXZpZXdzLmNzdiIpKQpsRmIgPC0gbEZbZ3JlcGwoImJhbm5lciIsIGxGKV0KbEZiIDwtIGxhcHBseShwYXN0ZTAoYW5hbHl0aWNzRGlyLCBsRmIpLAogICAgICAgICAgICAgIGRhdGEudGFibGU6OmZyZWFkKQpsRmIgPC0gZGF0YS50YWJsZTo6cmJpbmRsaXN0KGxGYikKd3JpdGUuY3N2KGxGYiwgCiAgICAgICAgICBwYXN0ZTAocHVibGljRGlyLCAKICAgICAgICAgICAgICAgICAiMjAyMV9PY2Nhc2lvbmFsRWRpdG9yc19CYW5uZXJzLmNzdiIpKQoKCgpgYGAKCgojIyAxLiBDYW1wYWlnbiBCYW5uZXJzCgpUaGlzIHNlY3Rpb24gcHJlc2VudHMgYWxsIGRhdGEgYW5kIHN0YXRpc3RpY3Mgb24gdGhlIGNhbXBhaWduIGJhbm5lcnMuCgojIyMgMS4xIEJhbm5lciBJbXByZXNzaW9ucwojIyMjIDEuMS4xIEJhbm5lciBJbXByZXNzaW9ucyBPdmVydmlldwoKKipDaGFydCAxLjEuMSoqIERhaWx5IEJhbm5lciBJbXByZXNzaW9ucwoKYGBge3IgZWNobyA9IFQsIGV2YWwgPSBULCB3YXJuaW5nID0gJ2hpZGUnLCBtZXNzYWdlID0gRkFMU0V9CiMgLSB3cmFuZ2xlIGRhdGFTZXQKZGF0YVNldCA8LSByZWFkLmNzdigKICAnX3JlcG9ydGluZy8yMDIxX09jY2FzaW9uYWxFZGl0b3JzX0Jhbm5lcnMuY3N2JywKICAgICAgICAgICAgICAgICAgICBoZWFkZXIgPSBULAogICAgICAgICAgICAgICAgICAgIHJvdy5uYW1lcyA9IDEsCiAgICAgICAgICAgICAgICAgICAgY2hlY2submFtZXMgPSBGLAogICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQpkYXRhU2V0JFYxIDwtIE5VTEwKZGF0YVNldCA8LSBkYXRhU2V0ICU+JSAKICBkcGx5cjo6ZmlsdGVyKCFncmVwbCgiMjAyMS0xMSIsIGRhdGFTZXQkZGF5KSkKZGF0YVNldCRiYW5uZXIgPC0gZ3N1YigiX2N0cmwiLCAiIiwgZGF0YVNldCRiYW5uZXIsIGZpeGVkID0gVCkKZGF0YVNldCRiYW5uZXIgPC0gc2FwcGx5KGRhdGFTZXQkYmFubmVyLCBmdW5jdGlvbih4KSB7CiAgaWYgKGdyZXBsKCJpcGFkJCIsIHgpKSB7CiAgICAiaXBhZCIKICB9IGVsc2UgaWYgKGdyZXBsKCJtb2JpbGUkIiwgeCkpIHsKICAgICJtb2JpbGUiCiAgfSBlbHNlIHsKICAgICJkZXNrdG9wIgogIH0KfSkKCiMgLSBwRnJhbWUKcEZyYW1lIDwtIGRhdGFTZXQgJT4lIAogIGRwbHlyOjpzZWxlY3QoLWNhbXBhaWduKSAlPiUgCiAgZHBseXI6OmZpbHRlcihhY3Rpb24gPT0gImJhbm5lci1zZWVuIikgJT4lIAogIGRwbHlyOjpzZWxlY3QoLWFjdGlvbikKCiMgLSBWaXN1YWxpemUgdy4ge2dncGxvdDJ9CmdncGxvdChwRnJhbWUsIGFlcyh4ID0gZGF5LAogICAgICAgICAgICAgICAgICAgIHkgPSBjb3VudCwKICAgICAgICAgICAgICAgICAgICBncm91cCA9IGJhbm5lciwKICAgICAgICAgICAgICAgICAgICBjb2xvciA9IGJhbm5lciwKICAgICAgICAgICAgICAgICAgICBmaWxsID0gYmFubmVyCiAgICAgICAgICAgICAgICAgICAgKSkgKyAKICBnZW9tX2xpbmUoc2l6ZSA9IC41KSArIAogIGdlb21fcG9pbnQoc2l6ZSA9IDEuNSkgKwogIGdndGl0bGUoJ09jY2FzaW9uYWwgRWRpdG9ycyAyMDIxOiBEYWlseSBCYW5uZXIgSW1wcmVzc2lvbnMnKSArCiAgdGhlbWVfbWluaW1hbCgpICsgCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgc2l6ZSA9IDgpKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApKSArCiAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQpgYGAKCiMjIyMgMS4xLjEgQmFubmVyIEltcHJlc3Npb25zIE92ZXJ2aWV3OiBUYWJsZQoKKipUYWJsZSAxLjEuMS4qKiBEYWlseSBCYW5uZXIgSW1wcmVzc2lvbnMKCmBgYHtyIGVjaG8gPSBULCBldmFsID0gVCwgd2FybmluZyA9ICdoaWRlJywgbWVzc2FnZSA9IEZBTFNFfQojIyMgLS0tIEZ1bGwgRGF0YXNldCAoVGFibGUgUmVwb3J0KQpkYXRhdGFibGUocEZyYW1lKQpgYGAKCiMjIyMgMS4xLjIgVG90YWwgQmFubmVyIEltcHJlc3Npb25zCgoqKkNoYXJ0IDEuMS4yLioqIFRvdGFsIEJhbm5lciBJbXByZXNzaW9ucwoKYGBge3IgZWNobyA9IFQsIGV2YWwgPSBULCB3YXJuaW5nID0gJ2hpZGUnLCBtZXNzYWdlID0gRkFMU0V9CiMgLSBwRnJhbWUKcEZyYW1lIDwtIGRhdGFTZXQgJT4lIAogIGRwbHlyOjpzZWxlY3QoLWNhbXBhaWduKSAlPiUgCiAgZHBseXI6OmZpbHRlcihhY3Rpb24gPT0gImJhbm5lci1zZWVuIikgJT4lCiAgZHBseXI6OnNlbGVjdCgtYWN0aW9uLCAtIGRheSkgJT4lIAogIGRwbHlyOjpncm91cF9ieShiYW5uZXIpICU+JSAKICBkcGx5cjo6c3VtbWFyaXNlKHRvdGFsSW1wcmVzc2lvbnMgPSBzdW0oY291bnQpKQoKZ2dwbG90KHBGcmFtZSwgYWVzKHggPSBiYW5uZXIsIAogICAgICAgICAgICAgICAgICAgIHkgPSB0b3RhbEltcHJlc3Npb25zLCAKICAgICAgICAgICAgICAgICAgICBjb2xvciA9IGJhbm5lciwgCiAgICAgICAgICAgICAgICAgICAgZmlsbCA9IGJhbm5lciwgCiAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSB0b3RhbEltcHJlc3Npb25zKSkgKyAKICBnZW9tX2Jhcih3aWR0aCA9IC41LCBzdGF0ID0gImlkZW50aXR5IikgKyAKICBnZ3RpdGxlKCdPY2Nhc2lvbmFsIEVkaXRvcnMgMjAyMTogQmFubmVyIEltcHJlc3Npb25zJykgKwogIHRoZW1lX21pbmltYWwoKSArIAogIGdlb21fbGFiZWxfcmVwZWwoc2l6ZSA9IDMuNSwgY29sb3IgPSAid2hpdGUiLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArIAogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBjb21tYSkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHNpemUgPSA4KSkgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSkgKwogIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKSArIAogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKQpgYGAKCiMjIyMgMS4xLjMgQmFubmVyIEltcHJlc3Npb25zIHBlciBEYXkKCioqQ2hhcnQgMS4xLjMuKiogQmFubmVyIEltcHJlc3Npb25zIHBlciBEYXkKCmBgYHtyIGVjaG8gPSBULCBldmFsID0gVCwgd2FybmluZyA9ICdoaWRlJywgbWVzc2FnZSA9IEZBTFNFfQojIC0gcEZyYW1lCnBGcmFtZSA8LSBkYXRhU2V0ICU+JSAKICBkcGx5cjo6c2VsZWN0KC1jYW1wYWlnbikgJT4lIAogIGRwbHlyOjpmaWx0ZXIoYWN0aW9uID09ICJiYW5uZXItc2VlbiIpICU+JQogIGRwbHlyOjpzZWxlY3QoLWFjdGlvbiwgLWJhbm5lcikgJT4lIAogIGRwbHlyOjpncm91cF9ieShkYXkpICU+JSAKICBkcGx5cjo6c3VtbWFyaXNlKHRvdGFsSW1wcmVzc2lvbnMgPSBzdW0oY291bnQpKQoKCmdncGxvdChwRnJhbWUsIGFlcyh4ID0gZGF5LCAKICAgICAgICAgICAgICAgICAgICB5ID0gdG90YWxJbXByZXNzaW9ucywgCiAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSB0b3RhbEltcHJlc3Npb25zKSkgKwogIGdlb21fcGF0aChzaXplID0gLjI1LCBncm91cCA9IDEsIGNvbG9yID0gImRhcmtibHVlIikgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDEuNSwgY29sb3IgPSAiZGFya2JsdWUiKSArIAogIGdlb21fcG9pbnQoc2l6ZSA9IDEsIGNvbG9yID0gIndoaXRlIikgKyAKICBnZ3RpdGxlKCdPY2Nhc2lvbmFsIEVkaXRvcnMgMjAyMTogQmFubmVyIEltcHJlc3Npb25zJykgKwogIHRoZW1lX21pbmltYWwoKSArIAogIGdlb21fbGFiZWxfcmVwZWwoc2l6ZSA9IDMuNSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBzaXplID0gOCkpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCkpICsKICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IikgKyAKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkKYGBgCgojIyMgMS4yIEJhbm5lciBDbGlja3MKIyMjIyAxLjIuMSBCYW5uZXIgQ2xpY2tzIE92ZXJ2aWV3CgoqKkNoYXJ0IDEuMi4xKiogRGFpbHkgQmFubmVyIENsaWNrcwoKYGBge3IgZWNobyA9IFQsIGV2YWwgPSBULCB3YXJuaW5nID0gJ2hpZGUnLCBtZXNzYWdlID0gRkFMU0V9CiMgLSBwRnJhbWUKcEZyYW1lIDwtIGRhdGFTZXQgJT4lIAogIGRwbHlyOjpzZWxlY3QoLWNhbXBhaWduKSAlPiUgCiAgZHBseXI6OmZpbHRlcihhY3Rpb24gPT0gImJhbm5lci1jbGlja2VkIikgJT4lIAogIGRwbHlyOjpzZWxlY3QoLWFjdGlvbikKCiMgLSBWaXN1YWxpemUgdy4ge2dncGxvdDJ9CmdncGxvdChwRnJhbWUsIGFlcyh4ID0gZGF5LAogICAgICAgICAgICAgICAgICAgIHkgPSBjb3VudCwKICAgICAgICAgICAgICAgICAgICBncm91cCA9IGJhbm5lciwKICAgICAgICAgICAgICAgICAgICBjb2xvciA9IGJhbm5lciwKICAgICAgICAgICAgICAgICAgICBmaWxsID0gYmFubmVyCiAgICAgICAgICAgICAgICAgICAgKSkgKyAKICBnZW9tX2xpbmUoc2l6ZSA9IC41KSArIAogIGdlb21fcG9pbnQoc2l6ZSA9IDEuNSkgKwogIGdndGl0bGUoJ09jY2FzaW9uYWwgRWRpdG9ycyAyMDIxOiBEYWlseSBCYW5uZXIgQ2xpY2tzJykgKwogIHRoZW1lX21pbmltYWwoKSArIAogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHNpemUgPSA4KSkgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSkgKwogIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKYGBgCgojIyMjIDEuMi4xIEJhbm5lciBDbGlja3MgT3ZlcnZpZXc6IFRhYmxlCgoqKlRhYmxlIDEuMi4xLioqIERhaWx5IEJhbm5lciBDbGlja3MKCmBgYHtyIGVjaG8gPSBULCBldmFsID0gVCwgd2FybmluZyA9ICdoaWRlJywgbWVzc2FnZSA9IEZBTFNFfQojIyMgLS0tIEZ1bGwgRGF0YXNldCAoVGFibGUgUmVwb3J0KQpkYXRhdGFibGUocEZyYW1lKQpgYGAKCiMjIyMgMS4yLjIgVG90YWwgQmFubmVyIENsaWNrcwoKKipDaGFydCAxLjIuMi4qKiBUb3RhbCBCYW5uZXIgQ2xpY2tzCgpgYGB7ciBlY2hvID0gVCwgZXZhbCA9IFQsIHdhcm5pbmcgPSAnaGlkZScsIG1lc3NhZ2UgPSBGQUxTRX0KIyAtIHBGcmFtZQpwRnJhbWUgPC0gZGF0YVNldCAlPiUgCiAgZHBseXI6OnNlbGVjdCgtY2FtcGFpZ24pICU+JSAKICBkcGx5cjo6ZmlsdGVyKGFjdGlvbiA9PSAiYmFubmVyLWNsaWNrZWQiKSAlPiUKICBkcGx5cjo6c2VsZWN0KC1hY3Rpb24sIC0gZGF5KSAlPiUgCiAgZHBseXI6Omdyb3VwX2J5KGJhbm5lcikgJT4lIAogIGRwbHlyOjpzdW1tYXJpc2UodG90YWxDbGlja3MgPSBzdW0oY291bnQpKQoKZ2dwbG90KHBGcmFtZSwgYWVzKHggPSBiYW5uZXIsIAogICAgICAgICAgICAgICAgICAgIHkgPSB0b3RhbENsaWNrcywgCiAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBiYW5uZXIsIAogICAgICAgICAgICAgICAgICAgIGZpbGwgPSBiYW5uZXIsIAogICAgICAgICAgICAgICAgICAgIGxhYmVsID0gdG90YWxDbGlja3MpKSArIAogIGdlb21fYmFyKHdpZHRoID0gLjUsIHN0YXQgPSAiaWRlbnRpdHkiKSArIAogIGdndGl0bGUoJ09jY2FzaW9uYWwgRWRpdG9ycyAyMDIxOiBCYW5uZXIgQ2xpY2tzJykgKwogIHRoZW1lX21pbmltYWwoKSArIAogIGdlb21fbGFiZWxfcmVwZWwoc2l6ZSA9IDMuNSwgY29sb3IgPSAid2hpdGUiLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArIAogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBjb21tYSkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHNpemUgPSA4KSkgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSkgKwogIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKSArIAogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKQpgYGAKCiMjIyMgMS4yLjMgQmFubmVyIENsaWNrcyBwZXIgRGF5CgoqKkNoYXJ0IDEuMi4zLioqIEJhbm5lciBDbGlja3MgcGVyIERheQoKYGBge3IgZWNobyA9IFQsIGV2YWwgPSBULCB3YXJuaW5nID0gJ2hpZGUnLCBtZXNzYWdlID0gRkFMU0V9CiMgLSBwRnJhbWUKcEZyYW1lIDwtIGRhdGFTZXQgJT4lIAogIGRwbHlyOjpzZWxlY3QoLWNhbXBhaWduKSAlPiUgCiAgZHBseXI6OmZpbHRlcihhY3Rpb24gPT0gImJhbm5lci1jbGlja2VkIikgJT4lCiAgZHBseXI6OnNlbGVjdCgtYWN0aW9uLCAtYmFubmVyKSAlPiUgCiAgZHBseXI6Omdyb3VwX2J5KGRheSkgJT4lIAogIGRwbHlyOjpzdW1tYXJpc2UodG90YWxDbGlja3MgPSBzdW0oY291bnQpKQoKCmdncGxvdChwRnJhbWUsIGFlcyh4ID0gZGF5LCAKICAgICAgICAgICAgICAgICAgICB5ID0gdG90YWxDbGlja3MsIAogICAgICAgICAgICAgICAgICAgIGxhYmVsID0gdG90YWxDbGlja3MpKSArCiAgZ2VvbV9wYXRoKHNpemUgPSAuMjUsIGdyb3VwID0gMSwgY29sb3IgPSAiZGFya2JsdWUiKSArCiAgZ2VvbV9wb2ludChzaXplID0gMS41LCBjb2xvciA9ICJkYXJrYmx1ZSIpICsgCiAgZ2VvbV9wb2ludChzaXplID0gMSwgY29sb3IgPSAid2hpdGUiKSArIAogIGdndGl0bGUoJ09jY2FzaW9uYWwgRWRpdG9ycyAyMDIxOiBCYW5uZXIgQ2xpY2tzJykgKwogIHRoZW1lX21pbmltYWwoKSArIAogIGdlb21fbGFiZWxfcmVwZWwoc2l6ZSA9IDMuNSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBzaXplID0gOCkpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCkpICsKICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IikgKyAKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkKYGBgCgojIyMgMS4zIEJhbm5lciBDbG9zZQojIyMjIDEuMy4xIEJhbm5lciBDbG9zZSBPdmVydmlldwoKKipDaGFydCAxLjMuMSoqIERhaWx5IEJhbm5lciBDbG9zZQoKYGBge3IgZWNobyA9IFQsIGV2YWwgPSBULCB3YXJuaW5nID0gJ2hpZGUnLCBtZXNzYWdlID0gRkFMU0V9CiMgLSBwRnJhbWUKcEZyYW1lIDwtIGRhdGFTZXQgJT4lIAogIGRwbHlyOjpzZWxlY3QoLWNhbXBhaWduKSAlPiUgCiAgZHBseXI6OmZpbHRlcihhY3Rpb24gPT0gImJhbm5lci1jbG9zZWQiKSAlPiUgCiAgZHBseXI6OnNlbGVjdCgtYWN0aW9uKQoKIyAtIFZpc3VhbGl6ZSB3LiB7Z2dwbG90Mn0KZ2dwbG90KHBGcmFtZSwgYWVzKHggPSBkYXksCiAgICAgICAgICAgICAgICAgICAgeSA9IGNvdW50LAogICAgICAgICAgICAgICAgICAgIGdyb3VwID0gYmFubmVyLAogICAgICAgICAgICAgICAgICAgIGNvbG9yID0gYmFubmVyLAogICAgICAgICAgICAgICAgICAgIGZpbGwgPSBiYW5uZXIKICAgICAgICAgICAgICAgICAgICApKSArIAogIGdlb21fbGluZShzaXplID0gLjUpICsgCiAgZ2VvbV9wb2ludChzaXplID0gMS41KSArCiAgZ2d0aXRsZSgnT2NjYXNpb25hbCBFZGl0b3JzIDIwMjE6IERhaWx5IEJhbm5lciBDbG9zZScpICsKICB0aGVtZV9taW5pbWFsKCkgKyAKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBzaXplID0gOCkpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCkpICsKICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCmBgYAoKIyMjIyAxLjMuMSBCYW5uZXIgQ2xvc2UgT3ZlcnZpZXc6IFRhYmxlCgoqKlRhYmxlIDEuMy4xLioqIERhaWx5IEJhbm5lciBDbG9zZQoKYGBge3IgZWNobyA9IFQsIGV2YWwgPSBULCB3YXJuaW5nID0gJ2hpZGUnLCBtZXNzYWdlID0gRkFMU0V9CiMjIyAtLS0gRnVsbCBEYXRhc2V0IChUYWJsZSBSZXBvcnQpCmRhdGF0YWJsZShwRnJhbWUpCmBgYAoKIyMjIyAxLjMuMiBUb3RhbCBCYW5uZXIgQ2xvc2UKCioqQ2hhcnQgMS4zLjIuKiogVG90YWwgQmFubmVyIENsb3NlCgpgYGB7ciBlY2hvID0gVCwgZXZhbCA9IFQsIHdhcm5pbmcgPSAnaGlkZScsIG1lc3NhZ2UgPSBGQUxTRX0KIyAtIHBGcmFtZQpwRnJhbWUgPC0gZGF0YVNldCAlPiUgCiAgZHBseXI6OnNlbGVjdCgtY2FtcGFpZ24pICU+JSAKICBkcGx5cjo6ZmlsdGVyKGFjdGlvbiA9PSAiYmFubmVyLWNsb3NlZCIpICU+JQogIGRwbHlyOjpzZWxlY3QoLWFjdGlvbiwgLSBkYXkpICU+JSAKICBkcGx5cjo6Z3JvdXBfYnkoYmFubmVyKSAlPiUgCiAgZHBseXI6OnN1bW1hcmlzZSh0b3RhbENsb3NlID0gc3VtKGNvdW50KSkKCmdncGxvdChwRnJhbWUsIGFlcyh4ID0gYmFubmVyLCAKICAgICAgICAgICAgICAgICAgICB5ID0gdG90YWxDbG9zZSwgCiAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBiYW5uZXIsIAogICAgICAgICAgICAgICAgICAgIGZpbGwgPSBiYW5uZXIsIAogICAgICAgICAgICAgICAgICAgIGxhYmVsID0gdG90YWxDbG9zZSkpICsgCiAgZ2VvbV9iYXIod2lkdGggPSAuNSwgc3RhdCA9ICJpZGVudGl0eSIpICsgCiAgZ2d0aXRsZSgnT2NjYXNpb25hbCBFZGl0b3JzIDIwMjE6IEJhbm5lciBDbG9zZScpICsKICB0aGVtZV9taW5pbWFsKCkgKyAKICBnZW9tX2xhYmVsX3JlcGVsKHNpemUgPSAzLjUsIGNvbG9yID0gIndoaXRlIiwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBzaXplID0gOCkpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCkpICsKICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IikgKyAKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCgojIyMjIDEuMy4zIEJhbm5lciBDbG9zZSBwZXIgRGF5CgoqKkNoYXJ0IDEuMy4zLioqIEJhbm5lciBDbG9zZSBwZXIgRGF5CgpgYGB7ciBlY2hvID0gVCwgZXZhbCA9IFQsIHdhcm5pbmcgPSAnaGlkZScsIG1lc3NhZ2UgPSBGQUxTRX0KIyAtIHBGcmFtZQpwRnJhbWUgPC0gZGF0YVNldCAlPiUgCiAgZHBseXI6OnNlbGVjdCgtY2FtcGFpZ24pICU+JSAKICBkcGx5cjo6ZmlsdGVyKGFjdGlvbiA9PSAiYmFubmVyLWNsb3NlZCIpICU+JQogIGRwbHlyOjpzZWxlY3QoLWFjdGlvbiwgLWJhbm5lcikgJT4lIAogIGRwbHlyOjpncm91cF9ieShkYXkpICU+JSAKICBkcGx5cjo6c3VtbWFyaXNlKHRvdGFsQ2xvc2UgPSBzdW0oY291bnQpKQoKCmdncGxvdChwRnJhbWUsIGFlcyh4ID0gZGF5LCAKICAgICAgICAgICAgICAgICAgICB5ID0gdG90YWxDbG9zZSwgCiAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSB0b3RhbENsb3NlKSkgKwogIGdlb21fcGF0aChzaXplID0gLjI1LCBncm91cCA9IDEsIGNvbG9yID0gImRhcmtibHVlIikgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDEuNSwgY29sb3IgPSAiZGFya2JsdWUiKSArIAogIGdlb21fcG9pbnQoc2l6ZSA9IDEsIGNvbG9yID0gIndoaXRlIikgKyAKICBnZ3RpdGxlKCdPY2Nhc2lvbmFsIEVkaXRvcnMgMjAyMTogQmFubmVyIENsb3NlJykgKwogIHRoZW1lX21pbmltYWwoKSArIAogIGdlb21fbGFiZWxfcmVwZWwoc2l6ZSA9IDMuNSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBzaXplID0gOCkpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCkpICsKICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IikgKyAKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkKYGBgCgojIyMgMS40IEJhbm5lciBDbGljayBSYXRlCiMjIyMgMS40LjEgQmFubmVyIENsaWNrIFJhdGUgT3ZlcnZpZXcKCioqQ2hhcnQgMS40LjEqKiBEYWlseSBCYW5uZXIgQ2xvc2UKCmBgYHtyIGVjaG8gPSBULCBldmFsID0gVCwgd2FybmluZyA9ICdoaWRlJywgbWVzc2FnZSA9IEZBTFNFfQojIC0gcEZyYW1lCnBGcmFtZSA8LSBkYXRhU2V0ICU+JSAKICBkcGx5cjo6c2VsZWN0KC1jYW1wYWlnbikgJT4lIAogIGRwbHlyOjpmaWx0ZXIoYWN0aW9uICE9ICJiYW5uZXItY2xvc2VkIikgJT4lIAogIHRpZHlyOjpwaXZvdF93aWRlcihuYW1lc19mcm9tID0gImFjdGlvbiIsIAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXNfZnJvbSA9ICJjb3VudCIsCiAgICAgICAgICAgICAgICAgICAgIHZhbHVlc19maWxsID0gMCkKcEZyYW1lJGNsaWNrX3JhdGUgPC0gcEZyYW1lJGBiYW5uZXItY2xpY2tlZGAvcEZyYW1lJGBiYW5uZXItc2VlbmAKcEZyYW1lIDwtIHBGcmFtZSAlPiUgCiAgZHBseXI6OnNlbGVjdChiYW5uZXIsIGRheSwgY2xpY2tfcmF0ZSkKCiMgLSBWaXN1YWxpemUgdy4ge2dncGxvdDJ9CmdncGxvdChwRnJhbWUsIGFlcyh4ID0gZGF5LAogICAgICAgICAgICAgICAgICAgIHkgPSBjbGlja19yYXRlLAogICAgICAgICAgICAgICAgICAgIGdyb3VwID0gYmFubmVyLAogICAgICAgICAgICAgICAgICAgIGNvbG9yID0gYmFubmVyLAogICAgICAgICAgICAgICAgICAgIGZpbGwgPSBiYW5uZXIKICAgICAgICAgICAgICAgICAgICApKSArIAogIGdlb21fbGluZShzaXplID0gLjUpICsgCiAgZ2VvbV9wb2ludChzaXplID0gMS41KSArCiAgZ2d0aXRsZSgnT2NjYXNpb25hbCBFZGl0b3JzIDIwMjE6IERhaWx5IEJhbm5lciBDbGljayBSYXRlJykgKwogIHRoZW1lX21pbmltYWwoKSArIAogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHNpemUgPSA4KSkgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSkgKwogIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKYGBgCgojIyMjIDEuNC4xIEJhbm5lciBDbG9zZSBPdmVydmlldzogVGFibGUKCioqVGFibGUgMS40LjEuKiogRGFpbHkgQmFubmVyIENsb3NlCgpgYGB7ciBlY2hvID0gVCwgZXZhbCA9IFQsIHdhcm5pbmcgPSAnaGlkZScsIG1lc3NhZ2UgPSBGQUxTRX0KIyMjIC0tLSBGdWxsIERhdGFzZXQgKFRhYmxlIFJlcG9ydCkKZGF0YXRhYmxlKHBGcmFtZSkKYGBgCgojIyMjIDEuNC4yIEF2ZXJhZ2UgQmFubmVyIENsaWNrIFJhdGUKCioqQ2hhcnQgMS40LjIuKiogQXZlcmFnZSBCYW5uZXIgQ2xpY2sgUmF0ZQoKYGBge3IgZWNobyA9IFQsIGV2YWwgPSBULCB3YXJuaW5nID0gJ2hpZGUnLCBtZXNzYWdlID0gRkFMU0V9CiMgLSBwRnJhbWUKcHBGcmFtZSA8LSBwRnJhbWUgJT4lIAogIGRwbHlyOjpzZWxlY3QoYmFubmVyLCBjbGlja19yYXRlKSAlPiUgCiAgZHBseXI6Omdyb3VwX2J5KGJhbm5lcikgJT4lIAogIGRwbHlyOjpzdW1tYXJpc2UoYXZnX2NsaWNrX3JhdGUgPSBtZWFuKGNsaWNrX3JhdGUpKQoKZ2dwbG90KHBwRnJhbWUsIGFlcyh4ID0gYmFubmVyLCAKICAgICAgICAgICAgICAgICAgICB5ID0gYXZnX2NsaWNrX3JhdGUsIAogICAgICAgICAgICAgICAgICAgIGNvbG9yID0gYmFubmVyLCAKICAgICAgICAgICAgICAgICAgICBmaWxsID0gYmFubmVyLCAKICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IHJvdW5kKGF2Z19jbGlja19yYXRlLCAyKSkpICsgCiAgZ2VvbV9iYXIod2lkdGggPSAuNSwgc3RhdCA9ICJpZGVudGl0eSIpICsgCiAgZ2d0aXRsZSgnT2NjYXNpb25hbCBFZGl0b3JzIDIwMjE6IEF2ZXJhZ2UgQmFubmVyIENsaWNrIFJhdGUnKSArCiAgdGhlbWVfbWluaW1hbCgpICsgCiAgZ2VvbV9sYWJlbF9yZXBlbChzaXplID0gMy41LCBjb2xvciA9ICJ3aGl0ZSIsIHNob3cubGVnZW5kID0gRkFMU0UpICsgCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGNvbW1hKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgc2l6ZSA9IDgpKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApKSArCiAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIpICsgCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCkpCmBgYAoKIyMjIyAxLjQuMyBBdmVyYWdlIEJhbm5lciBDbGljayBSYXRlIHBlciBEYXkKCioqQ2hhcnQgMS4zLjMuKiogQXZlcmFnZSBCYW5uZXIgQ2xpY2sgUmF0ZSBwZXIgRGF5CgpgYGB7ciBlY2hvID0gVCwgZXZhbCA9IFQsIHdhcm5pbmcgPSAnaGlkZScsIG1lc3NhZ2UgPSBGQUxTRX0KIyAtIHBGcmFtZQpwcEZyYW1lIDwtIHBGcmFtZSAlPiUgCiAgZHBseXI6OnNlbGVjdChkYXksIGNsaWNrX3JhdGUpICU+JSAKICBkcGx5cjo6Z3JvdXBfYnkoZGF5KSAlPiUgCiAgZHBseXI6OnN1bW1hcmlzZShhdmdfY2xpY2tfcmF0ZSA9IG1lYW4oY2xpY2tfcmF0ZSkpCiAgCmdncGxvdChwcEZyYW1lLCBhZXMoeCA9IGRheSwgCiAgICAgICAgICAgICAgICAgICAgeSA9IGF2Z19jbGlja19yYXRlLCAKICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IHJvdW5kKGF2Z19jbGlja19yYXRlLCAyKSkpICsKICBnZW9tX3BhdGgoc2l6ZSA9IC4yNSwgZ3JvdXAgPSAxLCBjb2xvciA9ICJkYXJrYmx1ZSIpICsKICBnZW9tX3BvaW50KHNpemUgPSAxLjUsIGNvbG9yID0gImRhcmtibHVlIikgKyAKICBnZW9tX3BvaW50KHNpemUgPSAxLCBjb2xvciA9ICJ3aGl0ZSIpICsgCiAgZ2d0aXRsZSgnT2NjYXNpb25hbCBFZGl0b3JzIDIwMjE6IEF2ZXJhZ2UgQmFubmVyIENsaWNrIFJhdGUnKSArCiAgdGhlbWVfbWluaW1hbCgpICsgCiAgZ2VvbV9sYWJlbF9yZXBlbChzaXplID0gMy41LCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArIAogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBjb21tYSkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHNpemUgPSA4KSkgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSkgKwogIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKSArIAogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApKQpgYGAKCiMjIDIuIFBhZ2V2aWV3cwoKIyMjIDIuMSBQYWdldmlld3MgT3ZlcnZpZXcKCioqQ2hhcnQgMi4xLjEuKiogUGFnZXZpZXdzIE92ZXJ2aWV3LiAKCmBgYHtyIGVjaG8gPSBULCBldmFsID0gVCwgd2FybmluZyA9ICdoaWRlJywgbWVzc2FnZSA9IEZBTFNFLCBmaWcuaGVpZ2h0ICA9IDEwfQpkYXRhU2V0IDwtIHJlYWQuY3N2KAogICdfcmVwb3J0aW5nLzIwMjFfT2NjYXNpb25hbEVkaXRvcnNfUGFnZXZpZXdzLmNzdicsCiAgICAgICAgICAgICAgICAgICAgaGVhZGVyID0gVCwKICAgICAgICAgICAgICAgICAgICByb3cubmFtZXMgPSAxLAogICAgICAgICAgICAgICAgICAgIGNoZWNrLm5hbWVzID0gRiwKICAgICAgICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzID0gRikKZGF0YVNldCRWMSA8LSBOVUxMCmRhdGFTZXQgPC0gZGF0YVNldCAlPiUgCiAgZHBseXI6OmZpbHRlcighKGdyZXBsKCIyMDIxLTExIiwgZGF0ZSkpKQpkYXRhU2V0JFRhZyA8LSBzYXBwbHkoZGF0YVNldCRUYWcsIGZ1bmN0aW9uKHgpIHsKICBpZiAoZ3JlcGwoImlwYWQkIiwgeCkpIHsKICAgICJpcGFkIgogIH0gZWxzZSBpZiAoZ3JlcGwoIm1vYmlsZSQiLCB4KSkgewogICAgIm1vYmlsZSIKICB9IGVsc2UgewogICAgImRlc2t0b3AiCiAgfQp9KQpkYXRhU2V0JFBhZ2UgPC0gc2FwcGx5KGRhdGFTZXQkUGFnZSwgZnVuY3Rpb24oeCkgewogIGlmIChncmVwbCgiRiVDMyVCNnJkZXJhbmdlYm90ZSIsIHgpKSB7CiAgICByZXR1cm4oIkbDtnJkZXJ1bmcvRsO2cmRlcmFuZ2Vib3RlIikKICB9IGVsc2UgaWYgKGdyZXBsKCJEZWluRW5nYWdlbWVudCIsIHgpKSB7CiAgICByZXR1cm4oIkRlaW5FbmdhZ2VtZW50ICIpCiAgfSBlbHNlIHsKICAgIHJldHVybigiTGVybmVXaWtpcGVkaWEiKQogIH0KfSkKZGF0YVNldCA8LSBkYXRhU2V0ICU+JSAKICBkcGx5cjo6c2VsZWN0KC1jYW1wYWlnbikgJT4lIAogIGRwbHlyOjpncm91cF9ieShkYXRlLCBUYWcsIFBhZ2UpICU+JSAKICBkcGx5cjo6c3VtbWFyaXNlKFBhZ2V2aWV3cyA9IHN1bShQYWdldmlld3MpKQoKIyAtIFZpc3VhbGl6ZSB3LiB7Z2dwbG90Mn0KZ2dwbG90KGRhdGFTZXQsIGFlcyh4ID0gZGF0ZSwKICAgICAgICAgICAgICAgICAgICB5ID0gbG9nKFBhZ2V2aWV3cyksCiAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSBQYWdlLAogICAgICAgICAgICAgICAgICAgIGNvbG9yID0gUGFnZSwKICAgICAgICAgICAgICAgICAgICBmaWxsID0gUGFnZSwKICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IFBhZ2V2aWV3cywKICAgICAgICAgICAgICAgICAgICApKSArIAogIGdlb21fcGF0aChzaXplID0gLjI1KSArIAogIGdlb21fcG9pbnQoc2l6ZSA9IDEuNSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDEsIGNvbG9yID0gIndoaXRlIikgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBjb21tYSkgKwogIGdndGl0bGUoJ09jY2FzaW9uYWwgRWRpdG9ycyAyMDIxOiBQYWdldmlld3MnKSArCiAgeWxhYigibG9nKFBhZ2V2aWV3cykiKSArIAogIHRoZW1lX21pbmltYWwoKSArIAogIGdlb21fdGV4dF9yZXBlbChzaXplID0gNiwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyAKICBmYWNldF93cmFwKH5UYWcsIG5jb2wgPSAyKSArIAogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHNpemUgPSAxMikpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSkpICsKICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgdGhlbWUobGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1KSkgKwogIHRoZW1lKHN0cmlwLnRleHQgPSAgZWxlbWVudF90ZXh0KHNpemUgPSAxNSkpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKYGBgCgoKKipUYWJsZSAyLjIuMS4qKiBQYWdldmlld3MgT3ZlcnZpZXcKCmBgYHtyIGVjaG8gPSBULCBldmFsID0gVCwgd2FybmluZyA9ICdoaWRlJywgbWVzc2FnZSA9IEZBTFNFfQojIyMgLS0tIEZ1bGwgRGF0YXNldCAoVGFibGUgUmVwb3J0KQpkYXRhdGFibGUoZGF0YVNldCAlPiUgYXJyYW5nZShkZXNjKFBhZ2V2aWV3cykpKQpgYGAKCiMjIyAyLjIgUGFnZXZpZXdzIERhaWx5CgpgYGB7ciBlY2hvID0gVCwgZXZhbCA9IFQsIHdhcm5pbmcgPSAnaGlkZScsIG1lc3NhZ2UgPSBGQUxTRX0KcEZyYW1lIDwtIGRhdGFTZXQgJT4lIAogIGRwbHlyOjpzZWxlY3QoZGF0ZSwgUGFnZXZpZXdzKSAlPiUgCiAgZHBseXI6Omdyb3VwX2J5KGRhdGUpICU+JSAKICBkcGx5cjo6c3VtbWFyaXNlKFBhZ2V2aWV3cyA9IHN1bShQYWdldmlld3MpKQoKIyAtIFZpc3VhbGl6ZSB3LiB7Z2dwbG90Mn0KZ2dwbG90KHBGcmFtZSwgYWVzKHggPSBkYXRlLAogICAgICAgICAgICAgICAgICAgIHkgPSBQYWdldmlld3MsCiAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSBQYWdldmlld3MsCiAgICAgICAgICAgICAgICAgICAgKSkgKyAKICBnZW9tX2xpbmUoc2l6ZSA9IC4yNSwgZ3JvdXAgPSAxKSArIAogIGdlb21fcG9pbnQoc2l6ZSA9IDEuNSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDEsIGNvbG9yID0gIndoaXRlIikgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBjb21tYSkgKwogIGdndGl0bGUoJ09jY2FzaW9uYWwgRWRpdG9ycyAyMDIxOiBQYWdldmlld3MnKSArCiAgdGhlbWVfbWluaW1hbCgpICsgCiAgZ2VvbV90ZXh0X3JlcGVsKHNpemUgPSA2LCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArIAogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHNpemUgPSAxMikpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSkpICsKICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgdGhlbWUobGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1KSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQpgYGAKCiMjIyAyLjMgUGFnZXZpZXdzIHBlciBUYWcKCmBgYHtyIGVjaG8gPSBULCBldmFsID0gVCwgd2FybmluZyA9ICdoaWRlJywgbWVzc2FnZSA9IEZBTFNFfQpwRnJhbWUgPC0gZGF0YVNldCAlPiUgCiAgZHBseXI6OnNlbGVjdChUYWcsIFBhZ2V2aWV3cykgJT4lIAogIGRwbHlyOjpncm91cF9ieShUYWcpICU+JSAKICBkcGx5cjo6c3VtbWFyaXNlKFBhZ2V2aWV3cyA9IHN1bShQYWdldmlld3MpKQoKIyAtIFZpc3VhbGl6ZSB3LiB7Z2dwbG90Mn0KZ2dwbG90KHBGcmFtZSwgYWVzKHggPSBUYWcsCiAgICAgICAgICAgICAgICAgICB5ID0gUGFnZXZpZXdzLAogICAgICAgICAgICAgICAgICAgbGFiZWwgPSBQYWdldmlld3MpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAiZGVlcHNreWJsdWUiKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGNvbW1hKSArCiAgZ2d0aXRsZSgnT2NjYXNpb25hbCBFZGl0b3JzIDIwMjE6IFBhZ2V2aWV3cycpICsKICB0aGVtZV9taW5pbWFsKCkgKyAKICBnZW9tX3RleHRfcmVwZWwoc2l6ZSA9IDYsIHNob3cubGVnZW5kID0gRkFMU0UpICsgCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgc2l6ZSA9IDEyKSkgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1KSkgKwogIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICB0aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCmBgYAoKIyMjIDIuNCBQYWdldmlld3MgcGVyIFBhZ2UKCmBgYHtyIGVjaG8gPSBULCBldmFsID0gVCwgd2FybmluZyA9ICdoaWRlJywgbWVzc2FnZSA9IEZBTFNFfQpwRnJhbWUgPC0gZGF0YVNldCAlPiUgCiAgZHBseXI6OnNlbGVjdChQYWdlLCBQYWdldmlld3MpICU+JSAKICBkcGx5cjo6Z3JvdXBfYnkoUGFnZSkgJT4lIAogIGRwbHlyOjpzdW1tYXJpc2UoUGFnZXZpZXdzID0gc3VtKFBhZ2V2aWV3cykpCgojIC0gVmlzdWFsaXplIHcuIHtnZ3Bsb3QyfQpnZ3Bsb3QocEZyYW1lLCBhZXMoeCA9IFBhZ2UsCiAgICAgICAgICAgICAgICAgICB5ID0gUGFnZXZpZXdzLAogICAgICAgICAgICAgICAgICAgbGFiZWwgPSBQYWdldmlld3MpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAiZGFya29yYW5nZSIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEpICsKICBnZ3RpdGxlKCdPY2Nhc2lvbmFsIEVkaXRvcnMgMjAyMTogUGFnZXZpZXdzJykgKwogIHRoZW1lX21pbmltYWwoKSArIAogIGdlb21fdGV4dF9yZXBlbChzaXplID0gNiwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyAKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBzaXplID0gMTIpKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpKSArCiAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArIAogIHRoZW1lKGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSkpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKYGBgCgoKCgo=