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

0. New Editor Defition

  • Having made more than 10 edits, of course,
  • but also depending upon the following constraints defined in respece to the
  • wmf.mediawiki_history Hive table (conjunction): – event_type = 'create' – event_user_is_created_by_self = true – event_user_is_bot_by_name = false – page_namespace = 0 – page_is_redirect_latest = false – !(event_user_id = 0)

The code chunk in 1. Data Acquistion encompasses the HiveQL query used to fetch the data from wmf.mediawiki_history. At this point, this Hive table does not encompass the historical page_is_redirect, introducing the most severe problem in the current implementation of this Report. It is expected that this field will become available during Q4/2017 T161146

1. Data Acquistion

The Data Acquisition code chunk is not reproducible from this report. It is run as an newEds_mediawiki_history.R script in production (currently stat1005). The userIds are anonymized and the dataset is copied mannually from production and processed locally to produce this Report.

### --- Script: newEds_mediawiki_history.R
### --- the following runs on stat1005.eqiad.wmnet
### --- Rscript /home/goransm/_miscWMDE/newEditors_MediaWikiHistory/newEds_mediawiki_history.R

### --- The script collects (a) userIds, and (b) dates (yyyymmdd) on which a particular user
### --- has reached >= 10 edits on a given project.
### --- The datasets are used for the New Editors Report on `dewiki`

### --- Goran S. Milovanovic, Data Analyst, WMDE
### --- October 16, 2017.

rm(list = ls())
library(dplyr)
library(tidyr)
library(stringr)
library(data.table)

### --- Define snapshot for wmf.mediawiki_history
snapshot <- as.character(Sys.time())
snapshotY <- strsplit(snapshot, split = "-")[[1]][1]
snapshotM <- strsplit(snapshot, split = "-")[[1]][2]
snapshot <- paste(snapshotY, snapshotM, sep = "-")
### --- NOTE OCTOBER SNAPSHOT NOT READY (11/11/2017)
snapshot <- '2017-09' 
### --- END define snapshot

### --- projects list
projects <- c('dewiki', 'enwiki', 'frwiki')

### --- dir struct:
baseDir <- '/srv/home/goransm/_miscWMDE/newEditors_MediaWikiHistory'
outDir <- paste(baseDir, '/_results/', sep = "")
scriptDir <- paste(baseDir, '/_script/', sep = "")
setwd(scriptDir)

### --- run HiveQL scripts
for (i in 1:length(projects)) {
  
  hiveQL <- paste("SELECT event_user_id, SUBSTR(from_utc_timestamp(event_timestamp, 'CET'), 1, 10) 
                    FROM (
                      SELECT *,
                      row_number() OVER (partition by event_user_id ORDER by event_timestamp) rownum
                      FROM wmf.mediawiki_history WHERE wiki_db = '", projects[i],
                      "' AND event_entity = 'revision'
                      AND event_type = 'create'
                      AND event_user_is_created_by_self = true
                      AND event_user_is_bot_by_name = false
                      AND page_namespace = 0 
                      AND page_is_redirect = false
                      AND !(event_user_id = 0) 
                      AND snapshot = '", snapshot,
                  "') tab1 
                    WHERE rownum = 10;",
                  sep = "")
  
  # - write hql
  write(hiveQL, 'newEds10.hql')
  
  ### --- output filename
  filename <- paste('newUsers10_', projects[i],".tsv", sep = "")
  filename <- paste(outDir, filename, sep = "")
  
  ### --- execute hql script:
  hiveArgs <- 'beeline -f'
  hiveInput <- paste(paste(scriptDir, 'newEds10.hql', sep = ""),
                     " > ",
                     filename,
                     sep = "")
  # - command:
  hiveCommand <- paste(hiveArgs, hiveInput)
  system(command = hiveCommand, wait = TRUE)
}
### --- END run HiveQL scripts

### --- anonymize, wrangle, and save
setwd(outDir)
Sys.setlocale("LC_TIME", "C")
lF <- list.files()
lF <- lF[grepl("tsv", lF, fixed = T)]
for (i in 1:length(lF)) {
  project <- strsplit(
    strsplit(lF[i], split = "_", fixed = T)[[1]][2],
    split = ".", fixed = T)[[1]][1]
  dataSet <- readLines(lF[i])
  dataSet <- dataSet[16:(length(dataSet) - 2)]
  User <- sapply(dataSet, function(x) {
    strsplit(x, split = "\t", fixed = T)[[1]][1]
  })
  Date <- sapply(dataSet, function(x) {
    strsplit(x, split = "\t", fixed = T)[[1]][2]
  })
  dsFrame <- data.frame(User = User, 
                        Date = Date, 
                        stringsAsFactors = F,
                        row.names = seq(1, length(User), by = 1))
  rm(Date); rm(User); rm(dataSet); gc()
  dsFrame$Date <- as.Date(dsFrame$Date)
  dsFrame <- dsFrame %>% 
    arrange(Date)
  # - anonymize user Ids
  dsFrame$User <- paste("u_", seq(1, length(dsFrame$User), by = 1))
  # - produce dataset w. daily resoluton
  filename <- paste("NewUsersDaily_", project, ".csv", sep = "")
  dailyRes <- dsFrame %>% 
    group_by(Date) %>% 
    summarise(Count = n())
  dailyRes$Month <- sapply(months(dailyRes$Date), function(x) {
    which(month.name %in% x)
  })
  dailyRes$Year <- year(dailyRes$Date)
  dailyRes$Week <- week(dailyRes$Date)
  dailyRes$DayWeek <- weekdays(dailyRes$Date)
  write.csv(dailyRes, filename)
}

4. dewiki Forecast

The optimal ARIMA forecast for dewiki, starting from the first year with a complete monthly dataset (2007):

### --- Data
dataSet <- read.csv(paste(getwd(), '/_results/NewUsersDaily_dewiki.csv', sep = ''),
                    header = T,
                    check.names = F,
                    stringsAsFactors = F,
                    row.names = 1)
### --- Wrangle
dataSet$Month <- sapply(dataSet$Month, function(x) {
  if(nchar(x) == 1) {
    x <- paste("0", x, sep = "")
  }
  x
})
dataSet <- arrange(dataSet, Year, Month)
# - complete data since 2007:
completeYears <- 2007:2017
wComplete <- rowSums(sapply(completeYears, function(x) {
  grepl(x, dataSet$Year)
  }))
dataSet <- dataSet[as.logical(wComplete), ]
# - summarise per month and drop incomplete data for the last month:
dataSet <- dataSet %>% 
  select(Year, Month, Count) %>% 
  group_by(Year, Month) %>% 
  summarise(Edits = sum(Count))
### --- as time series object:
timeEds <- ts(dataSet$Edits, 
              start = c(2007, 1), 
              end = c(2017, as.numeric(dataSet$Month[dim(dataSet)[1]])), 
              frequency = 12)
### --- ARIMA model
timeEdsARIMA <- auto.arima(timeEds, D = 1, seasonal = T)
timeEdsARIMA
Series: timeEds 
ARIMA(0,1,1)(2,1,0)[12] 

Coefficients:
          ma1     sar1     sar2
      -0.4675  -0.9148  -0.4445
s.e.   0.0821   0.0864   0.0908

sigma^2 estimated as 2867:  log likelihood=-641.46
AIC=1290.92   AICc=1291.28   BIC=1302.01
plot(forecast(timeEdsARIMA))

LS0tCnRpdGxlOiAiTmV3IEVkaXRvcnMgb24gZGUud2lraXBlZGlhLm9yZyIKYXV0aG9yOiAiR29yYW4gUy4gTWlsb3Zhbm92aWMsIERhdGEgU2NpZW50aXN0LCBXTURFIgpkYXRlOiAiSmFudWFyeSAwNCwgMjAxNyIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIHRoZW1lOiBzaW1wbGV4CiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiAyCiAgICB0b2NfZmxvYXQ6IHllcwogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiAyCi0tLQoKKipGZWVkYmFjayoqIHNob3VsZCBiZSBzZW5kIHRvIGBnb3Jhbi5taWxvdmFub3ZpY19leHRAd2lraW1lZGlhLmRlYC4gCgpgYGB7ciwgZWNobyA9IEYsIHdhcm5pbmcgPSBGLCBtZXNzYWdlID0gRiwgcmVzdWx0cyA9ICdoaWRlJ30KIyAhZGlhZ25vc3RpY3Mgb2ZmCiMjIyAtLS0gU2V0dXAKa25pdHI6Om9wdHNfY2h1bmskc2V0KGZpZy53aWR0aCA9IDE1LCBmaWcuaGVpZ2h0ID0gOCkgCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShnZ3JlcGVsKQpsaWJyYXJ5KHNjYWxlcykKbGlicmFyeShrYWJsZUV4dHJhKQpsaWJyYXJ5KHJtYXJrZG93bikKbGlicmFyeShrbml0cikKbGlicmFyeSh0c2VyaWVzKQpsaWJyYXJ5KGZvcmVjYXN0KQpgYGAKCiMjIDAuIE5ldyBFZGl0b3IgRGVmaXRpb24KCi0gSGF2aW5nIG1hZGUgbW9yZSB0aGFuIDEwIGVkaXRzLCBvZiBjb3Vyc2UsIAotIGJ1dCBhbHNvIGRlcGVuZGluZyB1cG9uIHRoZSBmb2xsb3dpbmcgY29uc3RyYWludHMgZGVmaW5lZCBpbiByZXNwZWNlIHRvIHRoZQotIGB3bWYubWVkaWF3aWtpX2hpc3RvcnlgIEhpdmUgdGFibGUgKGNvbmp1bmN0aW9uKToKLS0gYGV2ZW50X3R5cGUgPSAnY3JlYXRlJ2AKLS0gYGV2ZW50X3VzZXJfaXNfY3JlYXRlZF9ieV9zZWxmID0gdHJ1ZWAKLS0gYGV2ZW50X3VzZXJfaXNfYm90X2J5X25hbWUgPSBmYWxzZWAKLS0gYHBhZ2VfbmFtZXNwYWNlID0gMGAKLS0gYHBhZ2VfaXNfcmVkaXJlY3RfbGF0ZXN0ID0gZmFsc2VgCi0tIGAhKGV2ZW50X3VzZXJfaWQgPSAwKWAKClRoZSBjb2RlIGNodW5rIGluIGAxLiBEYXRhIEFjcXVpc3Rpb25gIGVuY29tcGFzc2VzIHRoZSBgSGl2ZVFMYCBxdWVyeSB1c2VkIHRvIGZldGNoIHRoZSBkYXRhIGZyb20gYHdtZi5tZWRpYXdpa2lfaGlzdG9yeWAuIEF0IHRoaXMgcG9pbnQsIHRoaXMgSGl2ZSB0YWJsZSBkb2VzIG5vdCBlbmNvbXBhc3MgdGhlIGhpc3RvcmljYWwgYHBhZ2VfaXNfcmVkaXJlY3RgLCBpbnRyb2R1Y2luZyB0aGUgbW9zdCBzZXZlcmUgcHJvYmxlbSBpbiB0aGUgY3VycmVudCBpbXBsZW1lbnRhdGlvbiBvZiB0aGlzIFJlcG9ydC4gSXQgaXMgZXhwZWN0ZWQgdGhhdCB0aGlzIGZpZWxkIHdpbGwgYmVjb21lIGF2YWlsYWJsZSBkdXJpbmcgYFE0LzIwMTdgIFtUMTYxMTQ2XShodHRwczovL3BoYWJyaWNhdG9yLndpa2ltZWRpYS5vcmcvVDE2MTE0NikKCiMjIDEuIERhdGEgQWNxdWlzdGlvbgoKVGhlIERhdGEgQWNxdWlzaXRpb24gY29kZSBjaHVuayBpcyBub3QgcmVwcm9kdWNpYmxlIGZyb20gdGhpcyByZXBvcnQuIEl0IGlzIHJ1biBhcyBhbiBgbmV3RWRzX21lZGlhd2lraV9oaXN0b3J5LlJgIHNjcmlwdCBpbiBwcm9kdWN0aW9uIChjdXJyZW50bHkgYHN0YXQxMDA1YCkuIFRoZSBgdXNlcklkc2AgYXJlIGFub255bWl6ZWQgYW5kIHRoZSBkYXRhc2V0IGlzIGNvcGllZCBtYW5udWFsbHkgZnJvbSBwcm9kdWN0aW9uIGFuZCBwcm9jZXNzZWQgbG9jYWxseSB0byBwcm9kdWNlIHRoaXMgUmVwb3J0LgoKYGBge3IsIGVjaG8gPSBULCBldmFsID0gRn0KIyMjIC0tLSBTY3JpcHQ6IG5ld0Vkc19tZWRpYXdpa2lfaGlzdG9yeS5SCiMjIyAtLS0gdGhlIGZvbGxvd2luZyBydW5zIG9uIHN0YXQxMDA1LmVxaWFkLndtbmV0CiMjIyAtLS0gUnNjcmlwdCAvaG9tZS9nb3JhbnNtL19taXNjV01ERS9uZXdFZGl0b3JzX01lZGlhV2lraUhpc3RvcnkvbmV3RWRzX21lZGlhd2lraV9oaXN0b3J5LlIKCiMjIyAtLS0gVGhlIHNjcmlwdCBjb2xsZWN0cyAoYSkgdXNlcklkcywgYW5kIChiKSBkYXRlcyAoeXl5eW1tZGQpIG9uIHdoaWNoIGEgcGFydGljdWxhciB1c2VyCiMjIyAtLS0gaGFzIHJlYWNoZWQgPj0gMTAgZWRpdHMgb24gYSBnaXZlbiBwcm9qZWN0LgojIyMgLS0tIFRoZSBkYXRhc2V0cyBhcmUgdXNlZCBmb3IgdGhlIE5ldyBFZGl0b3JzIFJlcG9ydCBvbiBgZGV3aWtpYAoKIyMjIC0tLSBHb3JhbiBTLiBNaWxvdmFub3ZpYywgRGF0YSBBbmFseXN0LCBXTURFCiMjIyAtLS0gT2N0b2JlciAxNiwgMjAxNy4KCnJtKGxpc3QgPSBscygpKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KHN0cmluZ3IpCmxpYnJhcnkoZGF0YS50YWJsZSkKCiMjIyAtLS0gRGVmaW5lIHNuYXBzaG90IGZvciB3bWYubWVkaWF3aWtpX2hpc3RvcnkKc25hcHNob3QgPC0gYXMuY2hhcmFjdGVyKFN5cy50aW1lKCkpCnNuYXBzaG90WSA8LSBzdHJzcGxpdChzbmFwc2hvdCwgc3BsaXQgPSAiLSIpW1sxXV1bMV0Kc25hcHNob3RNIDwtIHN0cnNwbGl0KHNuYXBzaG90LCBzcGxpdCA9ICItIilbWzFdXVsyXQpzbmFwc2hvdCA8LSBwYXN0ZShzbmFwc2hvdFksIHNuYXBzaG90TSwgc2VwID0gIi0iKQojIyMgLS0tIE5PVEUgT0NUT0JFUiBTTkFQU0hPVCBOT1QgUkVBRFkgKDExLzExLzIwMTcpCnNuYXBzaG90IDwtICcyMDE3LTA5JyAKIyMjIC0tLSBFTkQgZGVmaW5lIHNuYXBzaG90CgojIyMgLS0tIHByb2plY3RzIGxpc3QKcHJvamVjdHMgPC0gYygnZGV3aWtpJywgJ2Vud2lraScsICdmcndpa2knKQoKIyMjIC0tLSBkaXIgc3RydWN0OgpiYXNlRGlyIDwtICcvc3J2L2hvbWUvZ29yYW5zbS9fbWlzY1dNREUvbmV3RWRpdG9yc19NZWRpYVdpa2lIaXN0b3J5JwpvdXREaXIgPC0gcGFzdGUoYmFzZURpciwgJy9fcmVzdWx0cy8nLCBzZXAgPSAiIikKc2NyaXB0RGlyIDwtIHBhc3RlKGJhc2VEaXIsICcvX3NjcmlwdC8nLCBzZXAgPSAiIikKc2V0d2Qoc2NyaXB0RGlyKQoKIyMjIC0tLSBydW4gSGl2ZVFMIHNjcmlwdHMKZm9yIChpIGluIDE6bGVuZ3RoKHByb2plY3RzKSkgewogIAogIGhpdmVRTCA8LSBwYXN0ZSgiU0VMRUNUIGV2ZW50X3VzZXJfaWQsIFNVQlNUUihmcm9tX3V0Y190aW1lc3RhbXAoZXZlbnRfdGltZXN0YW1wLCAnQ0VUJyksIDEsIDEwKSAKICAgICAgICAgICAgICAgICAgICBGUk9NICgKICAgICAgICAgICAgICAgICAgICAgIFNFTEVDVCAqLAogICAgICAgICAgICAgICAgICAgICAgcm93X251bWJlcigpIE9WRVIgKHBhcnRpdGlvbiBieSBldmVudF91c2VyX2lkIE9SREVSIGJ5IGV2ZW50X3RpbWVzdGFtcCkgcm93bnVtCiAgICAgICAgICAgICAgICAgICAgICBGUk9NIHdtZi5tZWRpYXdpa2lfaGlzdG9yeSBXSEVSRSB3aWtpX2RiID0gJyIsIHByb2plY3RzW2ldLAogICAgICAgICAgICAgICAgICAgICAgIicgQU5EIGV2ZW50X2VudGl0eSA9ICdyZXZpc2lvbicKICAgICAgICAgICAgICAgICAgICAgIEFORCBldmVudF90eXBlID0gJ2NyZWF0ZScKICAgICAgICAgICAgICAgICAgICAgIEFORCBldmVudF91c2VyX2lzX2NyZWF0ZWRfYnlfc2VsZiA9IHRydWUKICAgICAgICAgICAgICAgICAgICAgIEFORCBldmVudF91c2VyX2lzX2JvdF9ieV9uYW1lID0gZmFsc2UKICAgICAgICAgICAgICAgICAgICAgIEFORCBwYWdlX25hbWVzcGFjZSA9IDAgCiAgICAgICAgICAgICAgICAgICAgICBBTkQgcGFnZV9pc19yZWRpcmVjdCA9IGZhbHNlCiAgICAgICAgICAgICAgICAgICAgICBBTkQgIShldmVudF91c2VyX2lkID0gMCkgCiAgICAgICAgICAgICAgICAgICAgICBBTkQgc25hcHNob3QgPSAnIiwgc25hcHNob3QsCiAgICAgICAgICAgICAgICAgICInKSB0YWIxIAogICAgICAgICAgICAgICAgICAgIFdIRVJFIHJvd251bSA9IDEwOyIsCiAgICAgICAgICAgICAgICAgIHNlcCA9ICIiKQogIAogICMgLSB3cml0ZSBocWwKICB3cml0ZShoaXZlUUwsICduZXdFZHMxMC5ocWwnKQogIAogICMjIyAtLS0gb3V0cHV0IGZpbGVuYW1lCiAgZmlsZW5hbWUgPC0gcGFzdGUoJ25ld1VzZXJzMTBfJywgcHJvamVjdHNbaV0sIi50c3YiLCBzZXAgPSAiIikKICBmaWxlbmFtZSA8LSBwYXN0ZShvdXREaXIsIGZpbGVuYW1lLCBzZXAgPSAiIikKICAKICAjIyMgLS0tIGV4ZWN1dGUgaHFsIHNjcmlwdDoKICBoaXZlQXJncyA8LSAnYmVlbGluZSAtZicKICBoaXZlSW5wdXQgPC0gcGFzdGUocGFzdGUoc2NyaXB0RGlyLCAnbmV3RWRzMTAuaHFsJywgc2VwID0gIiIpLAogICAgICAgICAgICAgICAgICAgICAiID4gIiwKICAgICAgICAgICAgICAgICAgICAgZmlsZW5hbWUsCiAgICAgICAgICAgICAgICAgICAgIHNlcCA9ICIiKQogICMgLSBjb21tYW5kOgogIGhpdmVDb21tYW5kIDwtIHBhc3RlKGhpdmVBcmdzLCBoaXZlSW5wdXQpCiAgc3lzdGVtKGNvbW1hbmQgPSBoaXZlQ29tbWFuZCwgd2FpdCA9IFRSVUUpCn0KIyMjIC0tLSBFTkQgcnVuIEhpdmVRTCBzY3JpcHRzCgojIyMgLS0tIGFub255bWl6ZSwgd3JhbmdsZSwgYW5kIHNhdmUKc2V0d2Qob3V0RGlyKQpTeXMuc2V0bG9jYWxlKCJMQ19USU1FIiwgIkMiKQpsRiA8LSBsaXN0LmZpbGVzKCkKbEYgPC0gbEZbZ3JlcGwoInRzdiIsIGxGLCBmaXhlZCA9IFQpXQpmb3IgKGkgaW4gMTpsZW5ndGgobEYpKSB7CiAgcHJvamVjdCA8LSBzdHJzcGxpdCgKICAgIHN0cnNwbGl0KGxGW2ldLCBzcGxpdCA9ICJfIiwgZml4ZWQgPSBUKVtbMV1dWzJdLAogICAgc3BsaXQgPSAiLiIsIGZpeGVkID0gVClbWzFdXVsxXQogIGRhdGFTZXQgPC0gcmVhZExpbmVzKGxGW2ldKQogIGRhdGFTZXQgPC0gZGF0YVNldFsxNjoobGVuZ3RoKGRhdGFTZXQpIC0gMildCiAgVXNlciA8LSBzYXBwbHkoZGF0YVNldCwgZnVuY3Rpb24oeCkgewogICAgc3Ryc3BsaXQoeCwgc3BsaXQgPSAiXHQiLCBmaXhlZCA9IFQpW1sxXV1bMV0KICB9KQogIERhdGUgPC0gc2FwcGx5KGRhdGFTZXQsIGZ1bmN0aW9uKHgpIHsKICAgIHN0cnNwbGl0KHgsIHNwbGl0ID0gIlx0IiwgZml4ZWQgPSBUKVtbMV1dWzJdCiAgfSkKICBkc0ZyYW1lIDwtIGRhdGEuZnJhbWUoVXNlciA9IFVzZXIsIAogICAgICAgICAgICAgICAgICAgICAgICBEYXRlID0gRGF0ZSwgCiAgICAgICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGLAogICAgICAgICAgICAgICAgICAgICAgICByb3cubmFtZXMgPSBzZXEoMSwgbGVuZ3RoKFVzZXIpLCBieSA9IDEpKQogIHJtKERhdGUpOyBybShVc2VyKTsgcm0oZGF0YVNldCk7IGdjKCkKICBkc0ZyYW1lJERhdGUgPC0gYXMuRGF0ZShkc0ZyYW1lJERhdGUpCiAgZHNGcmFtZSA8LSBkc0ZyYW1lICU+JSAKICAgIGFycmFuZ2UoRGF0ZSkKICAjIC0gYW5vbnltaXplIHVzZXIgSWRzCiAgZHNGcmFtZSRVc2VyIDwtIHBhc3RlKCJ1XyIsIHNlcSgxLCBsZW5ndGgoZHNGcmFtZSRVc2VyKSwgYnkgPSAxKSkKICAjIC0gcHJvZHVjZSBkYXRhc2V0IHcuIGRhaWx5IHJlc29sdXRvbgogIGZpbGVuYW1lIDwtIHBhc3RlKCJOZXdVc2Vyc0RhaWx5XyIsIHByb2plY3QsICIuY3N2Iiwgc2VwID0gIiIpCiAgZGFpbHlSZXMgPC0gZHNGcmFtZSAlPiUgCiAgICBncm91cF9ieShEYXRlKSAlPiUgCiAgICBzdW1tYXJpc2UoQ291bnQgPSBuKCkpCiAgZGFpbHlSZXMkTW9udGggPC0gc2FwcGx5KG1vbnRocyhkYWlseVJlcyREYXRlKSwgZnVuY3Rpb24oeCkgewogICAgd2hpY2gobW9udGgubmFtZSAlaW4lIHgpCiAgfSkKICBkYWlseVJlcyRZZWFyIDwtIHllYXIoZGFpbHlSZXMkRGF0ZSkKICBkYWlseVJlcyRXZWVrIDwtIHdlZWsoZGFpbHlSZXMkRGF0ZSkKICBkYWlseVJlcyREYXlXZWVrIDwtIHdlZWtkYXlzKGRhaWx5UmVzJERhdGUpCiAgd3JpdGUuY3N2KGRhaWx5UmVzLCBmaWxlbmFtZSkKfQpgYGAKCiMjIDIuIFdlZWtseSBUcmVuZHMgKEJpZyBQaWN0dXJlKQoKYGBge3IgZWNobyA9IFQsIHdhcm5pbmcgPSAnaGlkZScsIG1lc3NhZ2UgPSBGfQojIyMgLS0tIERlZmluZSBwcm9qZWN0cyB1bmRlciBjb25zaWRlcmF0aW9uOgpwcm9qZWN0cyA8LSBjKCdkZXdpa2knLCAnZW53aWtpJywgJ2Zyd2lraScpCmxGIDwtIGxpc3QuZmlsZXMoJy4vX3Jlc3VsdHMvJykKbEYgPC0gbEZbZ3JlcGwoIi5jc3YiLCBsRiwgZml4ZWQgPSBUKV0KZHdTZXRzIDwtIGxpc3QoKQojIyMgLS0tIFJlY2VudCB3ZWVrbHkgdHJlbmRzOgpmb3IgKGkgaW4gMTpsZW5ndGgocHJvamVjdHMpKSB7CiAgdyA8LSB3aGljaChncmVwbChwcm9qZWN0c1tpXSwgbEYsIGZpeGVkID0gVCkpCiAgZGF0YVNldCA8LSByZWFkLmNzdihwYXN0ZSgnLi9fcmVzdWx0cy8nLCBsRlt3XSwgc2VwID0gIiIpLCAKICAgICAgICAgICAgICAgICAgICAgIHJvdy5uYW1lcyA9IDEsCiAgICAgICAgICAgICAgICAgICAgICBjaGVjay5uYW1lcyA9IEYsCiAgICAgICAgICAgICAgICAgICAgICBoZWFkZXIgPSBULAogICAgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IEYpCiAgZFdlZWtseSA8LSBkYXRhU2V0CiAgZFdlZWtseSRNb250aCA8LSBzYXBwbHkoZFdlZWtseSRNb250aCwgZnVuY3Rpb24oeCkgewogICAgaWYgKCEobmNoYXIoeCkgPT0gMikpIHsKICAgICAgcmV0dXJuKHBhc3RlKCIwIiwgeCwgc2VwID0gIiIpKQogICAgfSBlbHNlIHsKICAgICAgcmV0dXJuKHgpCiAgICB9CiAgfSkKICBkV2Vla2x5JFdlZWsgPC0gc2FwcGx5KGRXZWVrbHkkV2VlaywgZnVuY3Rpb24oeCkgewogICAgaWYgKCEobmNoYXIoeCkgPT0gMikpIHsKICAgICAgcmV0dXJuKHBhc3RlKCIwIiwgeCwgc2VwID0gIiIpKQogICAgfSBlbHNlIHsKICAgICAgcmV0dXJuKHgpCiAgICB9CiAgfSkKICBkV2Vla2x5JFlXIDwtIHBhc3RlKGRXZWVrbHkkWWVhciwgZFdlZWtseSRXZWVrLCBzZXAgPSAiLSIpCiAgZFdlZWtseSA8LSBkV2Vla2x5ICU+JSAKICAgIGdyb3VwX2J5KFlXKSAlPiUgCiAgICBzdW1tYXJpc2UoQ291bnQgPSBzdW0oQ291bnQpKSAlPiUgCiAgICBhcnJhbmdlKFlXKQogIGR3U2V0c1tbaV1dIDwtIGRXZWVrbHkKICBybShkV2Vla2x5KTsgcm0oZGF0YVNldCk7IGdjKCkKfQojIyMgLS0tIHByb2R1Y2UgcGxvdFNldApkd2Vla3MgPC0gdW5saXN0KGxhcHBseShkd1NldHMsIGZ1bmN0aW9uKHgpIHsKICB4JFlXCn0pKQpkTWF0IDwtIGFzLmRhdGEuZnJhbWUobWF0cml4KCcnLCBucm93ID0gbGVuZ3RoKGR3ZWVrcyksIG5jb2wgPSBsZW5ndGgocHJvamVjdHMpICsgMSksIAogICAgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IEYpCmNvbG5hbWVzKGRNYXQpWzFdIDwtICdXZWVrJwpjb2xuYW1lcyhkTWF0KVsyOmRpbShkTWF0KVsyXV0gPC0gcHJvamVjdHMKZE1hdFssIDFdIDwtIGR3ZWVrcwpmb3IgKGkgaW4gMTpsZW5ndGgoZHdTZXRzKSkgewogIHcgPC0gd2hpY2goZE1hdCRXZWVrICVpbiUgZHdTZXRzW1tpXV0kWVcpCiAgZE1hdFssIGkrMV1bd10gPC0gZHdTZXRzW1tpXV0kQ291bnQgCn0KZE1hdCA8LSBkTWF0ICU+JSAKICBnYXRoZXIoa2V5ID0gUHJvamVjdCwKICAgICAgICAgdmFsdWUgPSBDb3VudCwKICAgICAgICAgcHJvamVjdHMpCmRNYXQkQ291bnQgPC0gYXMubnVtZXJpYyhkTWF0JENvdW50KQojIC0geC1heGlzIGxhYmVscwpkTWF0JFhMYWJzIDwtIHNhcHBseShkTWF0JFdlZWssIGZ1bmN0aW9uKHgpIHsKICBpZiAoZ3JlcGwoIi0wMSQiLCB4KSkgewogICAgcmV0dXJuKHN0cnNwbGl0KHgsIHNwbGl0ID0gIi0iLCBmaXhlZCA9IFQpW1sxXV1bMV0pIAogIH0gZWxzZSB7CiAgICByZXR1cm4oIiIpCiAgICB9Cn0pCiMgLSBWaXN1YWxpemUgdy4ge2dncGxvdDJ9CmdncGxvdChkTWF0LCBhZXMoeCA9IFdlZWssCiAgICAgICAgICAgICAgICAgeSA9IENvdW50LAogICAgICAgICAgICAgICAgIGdyb3VwID0gUHJvamVjdCwKICAgICAgICAgICAgICAgICBjb2xvciA9IFByb2plY3QsCiAgICAgICAgICAgICAgICAgZmlsbCA9IFByb2plY3QpKSArIAogIGdlb21fbGluZShzaXplID0gLjI1KSArIAogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBjb21tYSkgKyAKICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscyA9IGRNYXQkWExhYnMpICsKICB4bGFiKCJZZWFyICh3ZWVrbHkgZGF0YSByZXNvbHV0aW9uKSIpICsKICB5bGFiKCJOZXcgZWRpdG9ycyIpICsKICBnZ3RpdGxlKCdOZXcgRWRpdG9ycyAoPj0gMTAgZWRpdHMpIEluY29tZTpcbldlZWtseSBjb21wYXJpc29uIChzdGFydGluZyBhdDogV2VlayAxNi4gb2YgMjAxNi4pJykgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCkpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCkpICsKICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpKSArIAogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCgpMb2ctc2NhbGU6CgpgYGB7ciBlY2hvID0gVCwgd2FybmluZyA9ICdoaWRlJywgbWVzc2FnZSA9IEZ9CiMgLSBWaXN1YWxpemUgdy4ge2dncGxvdDJ9CmdncGxvdChkTWF0LCBhZXMoeCA9IFdlZWssCiAgICAgICAgICAgICAgICAgeSA9IGxvZyhDb3VudCksCiAgICAgICAgICAgICAgICAgZ3JvdXAgPSBQcm9qZWN0LAogICAgICAgICAgICAgICAgIGNvbG9yID0gUHJvamVjdCwKICAgICAgICAgICAgICAgICBmaWxsID0gUHJvamVjdCkpICsgCiAgZ2VvbV9saW5lKHNpemUgPSAuMjUpICsgCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGNvbW1hKSArIAogIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzID0gZE1hdCRYTGFicykgKwogIHhsYWIoIlllYXIgKHdlZWtseSBkYXRhIHJlc29sdXRpb24pIikgKwogIHlsYWIoImxvZyhOZXcgZWRpdG9ycykiKSArCiAgZ2d0aXRsZSgnTmV3IEVkaXRvcnMgKD49IDEwIGVkaXRzKSBJbmNvbWU6XG5XZWVrbHkgY29tcGFyaXNvbiAoc3RhcnRpbmcgYXQ6IFdlZWsgMTYuIG9mIDIwMTYuKScpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApKSArCiAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArIAogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yLnggPSBlbGVtZW50X2JsYW5rKCkpCmBgYAoKIyMgMy4gTW9udGhseSBUcmVuZHM6IFRoZSBQcmV2aW91cyBTaXggTW9udGhzCgpgYGB7ciBlY2hvID0gVCwgd2FybmluZyA9ICdoaWRlJywgbWVzc2FnZSA9IEZ9CiMjIyAtLS0gRGVmaW5lIHByb2plY3RzIHVuZGVyIGNvbnNpZGVyYXRpb24vZ2V0IGZpbGVzCmxGIDwtIGxpc3QuZmlsZXMoJy4vX3Jlc3VsdHMvJykKbEYgPC0gbEZbZ3JlcGwoIi5jc3YiLCBsRiwgZml4ZWQgPSBUKV0KZHdTZXRzIDwtIGxpc3QoKQojIyMgLS0tIE1vbnRobHkgdHJlbmRzOgpmb3IgKGkgaW4gMTpsZW5ndGgobEYpKSB7CiAgcHJvamVjdCA8LSBzdHJzcGxpdCgKICAgIHN0cnNwbGl0KGxGW2ldLCBzcGxpdCA9ICJfIiwgZml4ZWQgPSBUKVtbMV1dWzJdLAogICAgc3BsaXQgPSAiLiIsIGZpeGVkID0gVClbWzFdXVsxXQogIGRTIDwtIHJlYWQuY3N2KHBhc3RlKCcuL19yZXN1bHRzLycsIGxGW2ldLCBzZXAgPSAiIiksCiAgICAgICAgICAgICAgIGhlYWRlciA9IFQsCiAgICAgICAgICAgICAgIGNoZWNrLm5hbWVzID0gRiwKICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IEYsCiAgICAgICAgICAgICAgIHJvdy5uYW1lcyA9IDEpCiAgZFMkWWVhck1vbnRoIDwtIHBhc3RlKGRTJFllYXIsIAogICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UobmNoYXIoZFMkTW9udGgpID09IDIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZFMkTW9udGgsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUoIjAiLCBkUyRNb250aCwgc2VwID0gIiIpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgICAgICAgICBzZXAgPSAiLSIpCiAgZFMgPC0gZHBseXI6OnNlbGVjdChkUywgWWVhck1vbnRoLCBDb3VudCkKICBkUyRQcm9qZWN0IDwtIHByb2plY3QKICBkd1NldHNbW2ldXSA8LSBkUwogIHJtKGRTKQp9CmR3U2V0cyA8LSByYmluZGxpc3QoZHdTZXRzKQpkd1NldHMgPC0gZHdTZXRzICU+JSAKICBncm91cF9ieShQcm9qZWN0LCBZZWFyTW9udGgpICU+JSAKICBzdW1tYXJpc2UoRWRpdG9ycyA9IHN1bShDb3VudCkpICU+JSAKICBhcnJhbmdlKFByb2plY3QsIFllYXJNb250aCkKIyMjIC0tLSBkZXRlcm1pbmU6IGxhc3QgNiBtb250aHMKYWN0dWFsRGF0ZSA8LSBhcy5jaGFyYWN0ZXIoU3lzLnRpbWUoKSkKYWN0dWFsRGF0ZVkgPC0gYXMubnVtZXJpYyhzdHJzcGxpdChhY3R1YWxEYXRlLCBzcGxpdCA9ICItIilbWzFdXVsxXSkKYWN0dWFsRGF0ZU0gPC0gYXMubnVtZXJpYyhzdHJzcGxpdChhY3R1YWxEYXRlLCBzcGxpdCA9ICItIilbWzFdXVsyXSkKYWN0dWFsRGF0ZU0gPC0gYWN0dWFsRGF0ZU0gLSAxCmFjdHVhbERhdGVNMSA8LSBhY3R1YWxEYXRlTSAtIDUKbW9udGhzU2VxIDwtIGFjdHVhbERhdGVNMTphY3R1YWxEYXRlTQp5ZWFyc1NlcSA8LSByZXAoYWN0dWFsRGF0ZVksIGxlbmd0aChtb250aHNTZXEpKQp5ZWFyc1NlcVt3aGljaChtb250aHNTZXEgPD0gMCldIDwtIGFjdHVhbERhdGVZIC0gMQptb250aHNTZXFbd2hpY2gobW9udGhzU2VxPD0gMCldIDwtIDEyIC0gYWJzKG1vbnRoc1NlcVt3aGljaChtb250aHNTZXE8PSAwKV0pCnRhcmdldFlNIDwtIHBhc3RlKHllYXJzU2VxLCAKICAgICAgICAgICAgICAgICAgaWZlbHNlKG5jaGFyKG1vbnRoc1NlcSkgPT0gMiwKICAgICAgICAgICAgICAgICAgICAgICAgIG1vbnRoc1NlcSwKICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlKCIwIiwgbW9udGhzU2VxLCBzZXAgPSAiIikKICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICAgIHNlcCA9ICItIikKIyMjIC0tLSBmaWx0ZXI6IGxhc3QgNiBtb250aHMKZHdTZXRzIDwtIGR3U2V0cyAlPiUgCiAgZmlsdGVyKFllYXJNb250aCAlaW4lIHRhcmdldFlNKQojIyMgLS0tIHZpc3VhbGl6ZSB3LiB7Z2dwbG90Mn0KY29sbmFtZXMoZHdTZXRzKVsyXSA8LSAnTW9udGgnCmR3U2V0cyRNb250aCA8LSBmYWN0b3IoZHdTZXRzJE1vbnRoLCBsZXZlbHMgPSBzb3J0KHVuaXF1ZShkd1NldHMkTW9udGgpKSkKZ2dwbG90KGR3U2V0cywKICAgICAgIGFlcyh4ID0gTW9udGgsIHkgPSBFZGl0b3JzLCBsYWJlbCA9IEVkaXRvcnMpKSArCiAgICAgICAgICBnZW9tX2xpbmUoc2l6ZSA9IC4yNSwgY29sb3IgPSAiIzRjOGNmZiIsIGdyb3VwID0gMSkgKwogICAgICAgICAgZ2VvbV9wb2ludChzaXplID0gMS41LCBjb2xvciA9ICIjNGM4Y2ZmIikgKyAKICAgICAgICAgIGdlb21fcG9pbnQoc2l6ZSA9IDEsIGNvbG9yID0gIndoaXRlIikgKyAKICAgICAgICAgIGdlb21fdGV4dF9yZXBlbChkYXRhID0gZHdTZXRzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBhZXMoeCA9IE1vbnRoLCB5ID0gRWRpdG9ycywgbGFiZWwgPSBFZGl0b3JzKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDMpICsKICAgICAgICAgIGZhY2V0X3dyYXAofiBQcm9qZWN0LCBuY29sID0gMywgc2NhbGVzID0gImZyZWVfeSIpICsKICAgICAgICAgIHhsYWIoJ01vbnRoJykgKyB5bGFiKCdOZXcgRWRpdG9ycyAoPj0gMTAgZWRpdHMpJykgKwogICAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGNvbW1hKSArIAogICAgICAgICAgdGhlbWVfbWluaW1hbCgpICsKICAgICAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHNpemUgPSAxMCwgaGp1c3QgPSAxKSkgKwogICAgICAgICAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMikpICsKICAgICAgICAgIHRoZW1lKGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpKSArCiAgICAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSkpCmBgYAoKIyMgMy4gTW9udGhseSBUcmVuZHM6IFRoZSBQcmV2aW91cyBUd28gWWVhcnMKCmBgYHtyIGVjaG8gPSBULCB3YXJuaW5nID0gJ2hpZGUnLCBtZXNzYWdlID0gRn0KIyMjIC0tLSBEZWZpbmUgcHJvamVjdHMgdW5kZXIgY29uc2lkZXJhdGlvbi9nZXQgZmlsZXMKbEYgPC0gbGlzdC5maWxlcygnLi9fcmVzdWx0cy8nKQpsRiA8LSBsRltncmVwbCgiLmNzdiIsIGxGLCBmaXhlZCA9IFQpXQpkd1NldHMgPC0gbGlzdCgpCiMjIyAtLS0gTW9udGhseSB0cmVuZHM6CmZvciAoaSBpbiAxOmxlbmd0aChsRikpIHsKICBwcm9qZWN0IDwtIHN0cnNwbGl0KAogICAgc3Ryc3BsaXQobEZbaV0sIHNwbGl0ID0gIl8iLCBmaXhlZCA9IFQpW1sxXV1bMl0sCiAgICBzcGxpdCA9ICIuIiwgZml4ZWQgPSBUKVtbMV1dWzFdCiAgZFMgPC0gcmVhZC5jc3YocGFzdGUoJy4vX3Jlc3VsdHMvJywgbEZbaV0sIHNlcCA9ICIiKSwKICAgICAgICAgICAgICAgaGVhZGVyID0gVCwKICAgICAgICAgICAgICAgY2hlY2submFtZXMgPSBGLAogICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzID0gRiwKICAgICAgICAgICAgICAgcm93Lm5hbWVzID0gMSkKICBkUyRZZWFyTW9udGggPC0gcGFzdGUoZFMkWWVhciwgCiAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShuY2hhcihkUyRNb250aCkgPT0gMiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkUyRNb250aCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZSgiMCIsIGRTJE1vbnRoLCBzZXAgPSAiIikKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICAgICAgICAgIHNlcCA9ICItIikKICBkUyA8LSBkcGx5cjo6c2VsZWN0KGRTLCBZZWFyTW9udGgsIENvdW50KQogIGRTJFByb2plY3QgPC0gcHJvamVjdAogIGR3U2V0c1tbaV1dIDwtIGRTCiAgcm0oZFMpCn0KZHdTZXRzIDwtIHJiaW5kbGlzdChkd1NldHMpCmR3U2V0cyA8LSBkd1NldHMgJT4lIAogIGdyb3VwX2J5KFByb2plY3QsIFllYXJNb250aCkgJT4lIAogIHN1bW1hcmlzZShFZGl0b3JzID0gc3VtKENvdW50KSkgJT4lIAogIGFycmFuZ2UoUHJvamVjdCwgWWVhck1vbnRoKQojIyMgLS0tIGRldGVybWluZTogbGFzdCAyIHllYXJzCmFjdHVhbERhdGUgPC0gYXMuY2hhcmFjdGVyKFN5cy50aW1lKCkpCmFjdHVhbERhdGVZIDwtIGFzLm51bWVyaWMoc3Ryc3BsaXQoYWN0dWFsRGF0ZSwgc3BsaXQgPSAiLSIpW1sxXV1bMV0pCmFjdHVhbERhdGVNIDwtIGFzLm51bWVyaWMoc3Ryc3BsaXQoYWN0dWFsRGF0ZSwgc3BsaXQgPSAiLSIpW1sxXV1bMl0pCmFjdHVhbERhdGVNIDwtIGFjdHVhbERhdGVNIC0gMQphY3R1YWxEYXRlTTEgPC0gYWN0dWFsRGF0ZU0gLSAxMgptb250aHNTZXEgPC0gYWN0dWFsRGF0ZU0xOmFjdHVhbERhdGVNCnllYXJzU2VxIDwtIHJlcChhY3R1YWxEYXRlWSwgbGVuZ3RoKG1vbnRoc1NlcSkpCnllYXJzU2VxW3doaWNoKG1vbnRoc1NlcSA8PSAwKV0gPC0gYWN0dWFsRGF0ZVkgLSAxCm1vbnRoc1NlcVt3aGljaChtb250aHNTZXEgPD0gMCldIDwtIDEyIC0gYWJzKG1vbnRoc1NlcVt3aGljaChtb250aHNTZXE8PSAwKV0pCnRhcmdldFlNIDwtIHBhc3RlKHllYXJzU2VxLCAKICAgICAgICAgICAgICAgICAgaWZlbHNlKG5jaGFyKG1vbnRoc1NlcSkgPT0gMiwKICAgICAgICAgICAgICAgICAgICAgICAgIG1vbnRoc1NlcSwKICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlKCIwIiwgbW9udGhzU2VxLCBzZXAgPSAiIikKICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICAgIHNlcCA9ICItIikKdGFyZ2V0WU0xIDwtIGxhcHBseSh0YXJnZXRZTSwgZnVuY3Rpb24oeCkgewogIHggPC0gc3Ryc3BsaXQoeCwgc3BsaXQgPSAiLSIpW1sxXV0KICB4WzFdIDwtIGFzLm51bWVyaWMoeFsxXSkgLSAxCiAgeCA8LSBwYXN0ZSh4LCBjb2xsYXBzZSA9ICItIikKICByZXR1cm4oeCkKfSkKdGFyZ2V0WU0gPC0gdW5pcXVlKGModGFyZ2V0WU0sIHVubGlzdCh0YXJnZXRZTTEpKSkKIyMjIC0tLSBmaWx0ZXI6IGxhc3QgNiBtb250aHMKZHdTZXRzIDwtIGR3U2V0cyAlPiUgCiAgZmlsdGVyKFllYXJNb250aCAlaW4lIHRhcmdldFlNKQojIyMgLS0tIHZpc3VhbGl6ZSB3LiB7Z2dwbG90Mn0KY29sbmFtZXMoZHdTZXRzKVsyXSA8LSAnTW9udGgnCmR3U2V0cyRNb250aCA8LSBmYWN0b3IoZHdTZXRzJE1vbnRoLCBsZXZlbHMgPSBzb3J0KHVuaXF1ZShkd1NldHMkTW9udGgpKSkKZ2dwbG90KGR3U2V0cywKICAgICAgIGFlcyh4ID0gTW9udGgsIHkgPSBFZGl0b3JzLCBsYWJlbCA9IEVkaXRvcnMpKSArCiAgICAgICAgICBnZW9tX2xpbmUoc2l6ZSA9IC4yNSwgY29sb3IgPSAiIzRjOGNmZiIsIGdyb3VwID0gMSkgKwogICAgICAgICAgZ2VvbV9wb2ludChzaXplID0gMS41LCBjb2xvciA9ICIjNGM4Y2ZmIikgKyAKICAgICAgICAgIGdlb21fcG9pbnQoc2l6ZSA9IDEsIGNvbG9yID0gIndoaXRlIikgKyAKICAgICAgICAgIGdlb21fdGV4dF9yZXBlbChkYXRhID0gZHdTZXRzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBhZXMoeCA9IE1vbnRoLCB5ID0gRWRpdG9ycywgbGFiZWwgPSBFZGl0b3JzKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDMpICsKICAgICAgICAgIGZhY2V0X3dyYXAofiBQcm9qZWN0LCBuY29sID0gMSwgc2NhbGVzID0gImZyZWVfeSIpICsKICAgICAgICAgIHhsYWIoJ01vbnRoJykgKyB5bGFiKCdOZXcgRWRpdG9ycyAoPj0gMTAgZWRpdHMpJykgKwogICAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGNvbW1hKSArIAogICAgICAgICAgdGhlbWVfbWluaW1hbCgpICsKICAgICAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHNpemUgPSA4LCBoanVzdCA9IDEpKSArCiAgICAgICAgICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSkgKwogICAgICAgICAgdGhlbWUoYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMikpICsKICAgICAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1KSkKYGBgCgojIyA0LiBkZXdpa2kgRm9yZWNhc3QKClRoZSBvcHRpbWFsIEFSSU1BIGZvcmVjYXN0IGZvciBgZGV3aWtpYCwgc3RhcnRpbmcgZnJvbSB0aGUgZmlyc3QgeWVhciB3aXRoIGEgY29tcGxldGUgbW9udGhseSBkYXRhc2V0ICgyMDA3KToKCmBgYHtyIGVjaG8gPSBULCB3YXJuaW5nID0gJ2hpZGUnLCBtZXNzYWdlID0gRn0KIyMjIC0tLSBEYXRhCmRhdGFTZXQgPC0gcmVhZC5jc3YocGFzdGUoZ2V0d2QoKSwgJy9fcmVzdWx0cy9OZXdVc2Vyc0RhaWx5X2Rld2lraS5jc3YnLCBzZXAgPSAnJyksCiAgICAgICAgICAgICAgICAgICAgaGVhZGVyID0gVCwKICAgICAgICAgICAgICAgICAgICBjaGVjay5uYW1lcyA9IEYsCiAgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IEYsCiAgICAgICAgICAgICAgICAgICAgcm93Lm5hbWVzID0gMSkKIyMjIC0tLSBXcmFuZ2xlCmRhdGFTZXQkTW9udGggPC0gc2FwcGx5KGRhdGFTZXQkTW9udGgsIGZ1bmN0aW9uKHgpIHsKICBpZihuY2hhcih4KSA9PSAxKSB7CiAgICB4IDwtIHBhc3RlKCIwIiwgeCwgc2VwID0gIiIpCiAgfQogIHgKfSkKZGF0YVNldCA8LSBhcnJhbmdlKGRhdGFTZXQsIFllYXIsIE1vbnRoKQojIC0gY29tcGxldGUgZGF0YSBzaW5jZSAyMDA3Ogpjb21wbGV0ZVllYXJzIDwtIDIwMDc6MjAxNwp3Q29tcGxldGUgPC0gcm93U3VtcyhzYXBwbHkoY29tcGxldGVZZWFycywgZnVuY3Rpb24oeCkgewogIGdyZXBsKHgsIGRhdGFTZXQkWWVhcikKICB9KSkKZGF0YVNldCA8LSBkYXRhU2V0W2FzLmxvZ2ljYWwod0NvbXBsZXRlKSwgXQojIC0gc3VtbWFyaXNlIHBlciBtb250aCBhbmQgZHJvcCBpbmNvbXBsZXRlIGRhdGEgZm9yIHRoZSBsYXN0IG1vbnRoOgpkYXRhU2V0IDwtIGRhdGFTZXQgJT4lIAogIHNlbGVjdChZZWFyLCBNb250aCwgQ291bnQpICU+JSAKICBncm91cF9ieShZZWFyLCBNb250aCkgJT4lIAogIHN1bW1hcmlzZShFZGl0cyA9IHN1bShDb3VudCkpCiMjIyAtLS0gYXMgdGltZSBzZXJpZXMgb2JqZWN0Ogp0aW1lRWRzIDwtIHRzKGRhdGFTZXQkRWRpdHMsIAogICAgICAgICAgICAgIHN0YXJ0ID0gYygyMDA3LCAxKSwgCiAgICAgICAgICAgICAgZW5kID0gYygyMDE3LCBhcy5udW1lcmljKGRhdGFTZXQkTW9udGhbZGltKGRhdGFTZXQpWzFdXSkpLCAKICAgICAgICAgICAgICBmcmVxdWVuY3kgPSAxMikKIyMjIC0tLSBBUklNQSBtb2RlbAp0aW1lRWRzQVJJTUEgPC0gYXV0by5hcmltYSh0aW1lRWRzLCBEID0gMSwgc2Vhc29uYWwgPSBUKQp0aW1lRWRzQVJJTUEKcGxvdChmb3JlY2FzdCh0aW1lRWRzQVJJTUEpKQpgYGAK