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 DECEMBER SNAPSHOT NOT READY (comment: 01/04/2018)
snapshot <- '2017-11' 
### --- 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)(1,1,1)[12] 

Coefficients:
          ma1     sar1     sma1
      -0.5099  -0.3550  -0.5699
s.e.   0.0797   0.1271   0.1223

sigma^2 estimated as 3090:  log likelihood=-645.56
AIC=1299.12   AICc=1299.48   BIC=1310.21
plot(forecast(timeEdsARIMA))

LS0tCnRpdGxlOiAiTmV3IEVkaXRvcnMgb24gZGUud2lraXBlZGlhLm9yZyIKYXV0aG9yOiAiR29yYW4gUy4gTWlsb3Zhbm92aWMsIERhdGEgU2NpZW50aXN0LCBXTURFIgpkYXRlOiAiSmFudWFyeSAwOCwgMjAxNyIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIHRoZW1lOiBzaW1wbGV4CiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiAyCiAgICB0b2NfZmxvYXQ6IHllcwogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiAyCi0tLQoKKipGZWVkYmFjayoqIHNob3VsZCBiZSBzZW5kIHRvIGBnb3Jhbi5taWxvdmFub3ZpY19leHRAd2lraW1lZGlhLmRlYC4gCgpgYGB7ciwgZWNobyA9IEYsIHdhcm5pbmcgPSBGLCBtZXNzYWdlID0gRiwgcmVzdWx0cyA9ICdoaWRlJ30KIyAhZGlhZ25vc3RpY3Mgb2ZmCiMjIyAtLS0gU2V0dXAKa25pdHI6Om9wdHNfY2h1bmskc2V0KGZpZy53aWR0aCA9IDE1LCBmaWcuaGVpZ2h0ID0gOCkgCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShnZ3JlcGVsKQpsaWJyYXJ5KHNjYWxlcykKbGlicmFyeShrYWJsZUV4dHJhKQpsaWJyYXJ5KHJtYXJrZG93bikKbGlicmFyeShrbml0cikKbGlicmFyeSh0c2VyaWVzKQpsaWJyYXJ5KGZvcmVjYXN0KQpsaWJyYXJ5KGRhdGEudGFibGUpCmBgYAoKIyMgMC4gTmV3IEVkaXRvciBEZWZpdGlvbgoKLSBIYXZpbmcgbWFkZSBtb3JlIHRoYW4gMTAgZWRpdHMsIG9mIGNvdXJzZSwgCi0gYnV0IGFsc28gZGVwZW5kaW5nIHVwb24gdGhlIGZvbGxvd2luZyBjb25zdHJhaW50cyBkZWZpbmVkIGluIHJlc3BlY2UgdG8gdGhlCi0gYHdtZi5tZWRpYXdpa2lfaGlzdG9yeWAgSGl2ZSB0YWJsZSAoY29uanVuY3Rpb24pOgotLSBgZXZlbnRfdHlwZSA9ICdjcmVhdGUnYAotLSBgZXZlbnRfdXNlcl9pc19jcmVhdGVkX2J5X3NlbGYgPSB0cnVlYAotLSBgZXZlbnRfdXNlcl9pc19ib3RfYnlfbmFtZSA9IGZhbHNlYAotLSBgcGFnZV9uYW1lc3BhY2UgPSAwYAotLSBgcGFnZV9pc19yZWRpcmVjdF9sYXRlc3QgPSBmYWxzZWAKLS0gYCEoZXZlbnRfdXNlcl9pZCA9IDApYAoKVGhlIGNvZGUgY2h1bmsgaW4gYDEuIERhdGEgQWNxdWlzdGlvbmAgZW5jb21wYXNzZXMgdGhlIGBIaXZlUUxgIHF1ZXJ5IHVzZWQgdG8gZmV0Y2ggdGhlIGRhdGEgZnJvbSBgd21mLm1lZGlhd2lraV9oaXN0b3J5YC4gQXQgdGhpcyBwb2ludCwgdGhpcyBIaXZlIHRhYmxlIGRvZXMgbm90IGVuY29tcGFzcyB0aGUgaGlzdG9yaWNhbCBgcGFnZV9pc19yZWRpcmVjdGAsIGludHJvZHVjaW5nIHRoZSBtb3N0IHNldmVyZSBwcm9ibGVtIGluIHRoZSBjdXJyZW50IGltcGxlbWVudGF0aW9uIG9mIHRoaXMgUmVwb3J0LiBJdCBpcyBleHBlY3RlZCB0aGF0IHRoaXMgZmllbGQgd2lsbCBiZWNvbWUgYXZhaWxhYmxlIGR1cmluZyBgUTQvMjAxN2AgW1QxNjExNDZdKGh0dHBzOi8vcGhhYnJpY2F0b3Iud2lraW1lZGlhLm9yZy9UMTYxMTQ2KQoKIyMgMS4gRGF0YSBBY3F1aXN0aW9uCgpUaGUgRGF0YSBBY3F1aXNpdGlvbiBjb2RlIGNodW5rIGlzIG5vdCByZXByb2R1Y2libGUgZnJvbSB0aGlzIHJlcG9ydC4gSXQgaXMgcnVuIGFzIGFuIGBuZXdFZHNfbWVkaWF3aWtpX2hpc3RvcnkuUmAgc2NyaXB0IGluIHByb2R1Y3Rpb24gKGN1cnJlbnRseSBgc3RhdDEwMDVgKS4gVGhlIGB1c2VySWRzYCBhcmUgYW5vbnltaXplZCBhbmQgdGhlIGRhdGFzZXQgaXMgY29waWVkIG1hbm51YWxseSBmcm9tIHByb2R1Y3Rpb24gYW5kIHByb2Nlc3NlZCBsb2NhbGx5IHRvIHByb2R1Y2UgdGhpcyBSZXBvcnQuCgpgYGB7ciwgZWNobyA9IFQsIGV2YWwgPSBGfQojIyMgLS0tIFNjcmlwdDogbmV3RWRzX21lZGlhd2lraV9oaXN0b3J5LlIKIyMjIC0tLSB0aGUgZm9sbG93aW5nIHJ1bnMgb24gc3RhdDEwMDUuZXFpYWQud21uZXQKIyMjIC0tLSBSc2NyaXB0IC9ob21lL2dvcmFuc20vX21pc2NXTURFL25ld0VkaXRvcnNfTWVkaWFXaWtpSGlzdG9yeS9uZXdFZHNfbWVkaWF3aWtpX2hpc3RvcnkuUgoKIyMjIC0tLSBUaGUgc2NyaXB0IGNvbGxlY3RzIChhKSB1c2VySWRzLCBhbmQgKGIpIGRhdGVzICh5eXl5bW1kZCkgb24gd2hpY2ggYSBwYXJ0aWN1bGFyIHVzZXIKIyMjIC0tLSBoYXMgcmVhY2hlZCA+PSAxMCBlZGl0cyBvbiBhIGdpdmVuIHByb2plY3QuCiMjIyAtLS0gVGhlIGRhdGFzZXRzIGFyZSB1c2VkIGZvciB0aGUgTmV3IEVkaXRvcnMgUmVwb3J0IG9uIGBkZXdpa2lgCgojIyMgLS0tIEdvcmFuIFMuIE1pbG92YW5vdmljLCBEYXRhIEFuYWx5c3QsIFdNREUKIyMjIC0tLSBPY3RvYmVyIDE2LCAyMDE3LgoKcm0obGlzdCA9IGxzKCkpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkoc3RyaW5ncikKbGlicmFyeShkYXRhLnRhYmxlKQoKIyMjIC0tLSBEZWZpbmUgc25hcHNob3QgZm9yIHdtZi5tZWRpYXdpa2lfaGlzdG9yeQpzbmFwc2hvdCA8LSBhcy5jaGFyYWN0ZXIoU3lzLnRpbWUoKSkKc25hcHNob3RZIDwtIHN0cnNwbGl0KHNuYXBzaG90LCBzcGxpdCA9ICItIilbWzFdXVsxXQpzbmFwc2hvdE0gPC0gc3Ryc3BsaXQoc25hcHNob3QsIHNwbGl0ID0gIi0iKVtbMV1dWzJdCnNuYXBzaG90IDwtIHBhc3RlKHNuYXBzaG90WSwgc25hcHNob3RNLCBzZXAgPSAiLSIpCiMjIyAtLS0gTk9URSBERUNFTUJFUiBTTkFQU0hPVCBOT1QgUkVBRFkgKGNvbW1lbnQ6IDAxLzA0LzIwMTgpCnNuYXBzaG90IDwtICcyMDE3LTExJyAKIyMjIC0tLSBFTkQgZGVmaW5lIHNuYXBzaG90CgojIyMgLS0tIHByb2plY3RzIGxpc3QKcHJvamVjdHMgPC0gYygnZGV3aWtpJywgJ2Vud2lraScsICdmcndpa2knKQoKIyMjIC0tLSBkaXIgc3RydWN0OgpiYXNlRGlyIDwtICcvc3J2L2hvbWUvZ29yYW5zbS9fbWlzY1dNREUvbmV3RWRpdG9yc19NZWRpYVdpa2lIaXN0b3J5JwpvdXREaXIgPC0gcGFzdGUoYmFzZURpciwgJy9fcmVzdWx0cy8nLCBzZXAgPSAiIikKc2NyaXB0RGlyIDwtIHBhc3RlKGJhc2VEaXIsICcvX3NjcmlwdC8nLCBzZXAgPSAiIikKc2V0d2Qoc2NyaXB0RGlyKQoKIyMjIC0tLSBydW4gSGl2ZVFMIHNjcmlwdHMKZm9yIChpIGluIDE6bGVuZ3RoKHByb2plY3RzKSkgewoKICBoaXZlUUwgPC0gcGFzdGUoIlNFTEVDVCBldmVudF91c2VyX2lkLCBTVUJTVFIoZnJvbV91dGNfdGltZXN0YW1wKGV2ZW50X3RpbWVzdGFtcCwgJ0NFVCcpLCAxLCAxMCkgCiAgICAgICAgICAgICAgICAgICAgRlJPTSAoCiAgICAgICAgICAgICAgICAgICAgICBTRUxFQ1QgKiwKICAgICAgICAgICAgICAgICAgICAgIHJvd19udW1iZXIoKSBPVkVSIChwYXJ0aXRpb24gYnkgZXZlbnRfdXNlcl9pZCBPUkRFUiBieSBldmVudF90aW1lc3RhbXApIHJvd251bQogICAgICAgICAgICAgICAgICAgICAgRlJPTSB3bWYubWVkaWF3aWtpX2hpc3RvcnkgV0hFUkUgd2lraV9kYiA9ICciLCBwcm9qZWN0c1tpXSwKICAgICAgICAgICAgICAgICAgICAgICInIEFORCBldmVudF9lbnRpdHkgPSAncmV2aXNpb24nCiAgICAgICAgICAgICAgICAgICAgICBBTkQgZXZlbnRfdHlwZSA9ICdjcmVhdGUnCiAgICAgICAgICAgICAgICAgICAgICBBTkQgZXZlbnRfdXNlcl9pc19jcmVhdGVkX2J5X3NlbGYgPSB0cnVlCiAgICAgICAgICAgICAgICAgICAgICBBTkQgZXZlbnRfdXNlcl9pc19ib3RfYnlfbmFtZSA9IGZhbHNlCiAgICAgICAgICAgICAgICAgICAgICBBTkQgcGFnZV9uYW1lc3BhY2UgPSAwIAogICAgICAgICAgICAgICAgICAgICAgQU5EIHBhZ2VfaXNfcmVkaXJlY3QgPSBmYWxzZQogICAgICAgICAgICAgICAgICAgICAgQU5EICEoZXZlbnRfdXNlcl9pZCA9IDApIAogICAgICAgICAgICAgICAgICAgICAgQU5EIHNuYXBzaG90ID0gJyIsIHNuYXBzaG90LAogICAgICAgICAgICAgICAgICAiJykgdGFiMSAKICAgICAgICAgICAgICAgICAgICBXSEVSRSByb3dudW0gPSAxMDsiLAogICAgICAgICAgICAgICAgICBzZXAgPSAiIikKICAKICAjIC0gd3JpdGUgaHFsCiAgd3JpdGUoaGl2ZVFMLCAnbmV3RWRzMTAuaHFsJykKICAKICAjIyMgLS0tIG91dHB1dCBmaWxlbmFtZQogIGZpbGVuYW1lIDwtIHBhc3RlKCduZXdVc2VyczEwXycsIHByb2plY3RzW2ldLCIudHN2Iiwgc2VwID0gIiIpCiAgZmlsZW5hbWUgPC0gcGFzdGUob3V0RGlyLCBmaWxlbmFtZSwgc2VwID0gIiIpCiAgCiAgIyMjIC0tLSBleGVjdXRlIGhxbCBzY3JpcHQ6CiAgaGl2ZUFyZ3MgPC0gJ2JlZWxpbmUgLWYnCiAgaGl2ZUlucHV0IDwtIHBhc3RlKHBhc3RlKHNjcmlwdERpciwgJ25ld0VkczEwLmhxbCcsIHNlcCA9ICIiKSwKICAgICAgICAgICAgICAgICAgICAgIiA+ICIsCiAgICAgICAgICAgICAgICAgICAgIGZpbGVuYW1lLAogICAgICAgICAgICAgICAgICAgICBzZXAgPSAiIikKICAjIC0gY29tbWFuZDoKICBoaXZlQ29tbWFuZCA8LSBwYXN0ZShoaXZlQXJncywgaGl2ZUlucHV0KQogIHN5c3RlbShjb21tYW5kID0gaGl2ZUNvbW1hbmQsIHdhaXQgPSBUUlVFKQp9CiMjIyAtLS0gRU5EIHJ1biBIaXZlUUwgc2NyaXB0cwoKIyMjIC0tLSBhbm9ueW1pemUsIHdyYW5nbGUsIGFuZCBzYXZlCnNldHdkKG91dERpcikKU3lzLnNldGxvY2FsZSgiTENfVElNRSIsICJDIikKbEYgPC0gbGlzdC5maWxlcygpCmxGIDwtIGxGW2dyZXBsKCJ0c3YiLCBsRiwgZml4ZWQgPSBUKV0KZm9yIChpIGluIDE6bGVuZ3RoKGxGKSkgewogIHByb2plY3QgPC0gc3Ryc3BsaXQoCiAgICBzdHJzcGxpdChsRltpXSwgc3BsaXQgPSAiXyIsIGZpeGVkID0gVClbWzFdXVsyXSwKICAgIHNwbGl0ID0gIi4iLCBmaXhlZCA9IFQpW1sxXV1bMV0KICBkYXRhU2V0IDwtIHJlYWRMaW5lcyhsRltpXSkKICBkYXRhU2V0IDwtIGRhdGFTZXRbMTY6KGxlbmd0aChkYXRhU2V0KSAtIDIpXQogIFVzZXIgPC0gc2FwcGx5KGRhdGFTZXQsIGZ1bmN0aW9uKHgpIHsKICAgIHN0cnNwbGl0KHgsIHNwbGl0ID0gIlx0IiwgZml4ZWQgPSBUKVtbMV1dWzFdCiAgfSkKICBEYXRlIDwtIHNhcHBseShkYXRhU2V0LCBmdW5jdGlvbih4KSB7CiAgICBzdHJzcGxpdCh4LCBzcGxpdCA9ICJcdCIsIGZpeGVkID0gVClbWzFdXVsyXQogIH0pCiAgZHNGcmFtZSA8LSBkYXRhLmZyYW1lKFVzZXIgPSBVc2VyLCAKICAgICAgICAgICAgICAgICAgICAgICAgRGF0ZSA9IERhdGUsIAogICAgICAgICAgICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzID0gRiwKICAgICAgICAgICAgICAgICAgICAgICAgcm93Lm5hbWVzID0gc2VxKDEsIGxlbmd0aChVc2VyKSwgYnkgPSAxKSkKICBybShEYXRlKTsgcm0oVXNlcik7IHJtKGRhdGFTZXQpOyBnYygpCiAgZHNGcmFtZSREYXRlIDwtIGFzLkRhdGUoZHNGcmFtZSREYXRlKQogIGRzRnJhbWUgPC0gZHNGcmFtZSAlPiUgCiAgICBhcnJhbmdlKERhdGUpCiAgIyAtIGFub255bWl6ZSB1c2VyIElkcwogIGRzRnJhbWUkVXNlciA8LSBwYXN0ZSgidV8iLCBzZXEoMSwgbGVuZ3RoKGRzRnJhbWUkVXNlciksIGJ5ID0gMSkpCiAgIyAtIHByb2R1Y2UgZGF0YXNldCB3LiBkYWlseSByZXNvbHV0b24KICBmaWxlbmFtZSA8LSBwYXN0ZSgiTmV3VXNlcnNEYWlseV8iLCBwcm9qZWN0LCAiLmNzdiIsIHNlcCA9ICIiKQogIGRhaWx5UmVzIDwtIGRzRnJhbWUgJT4lIAogICAgZ3JvdXBfYnkoRGF0ZSkgJT4lIAogICAgc3VtbWFyaXNlKENvdW50ID0gbigpKQogIGRhaWx5UmVzJE1vbnRoIDwtIHNhcHBseShtb250aHMoZGFpbHlSZXMkRGF0ZSksIGZ1bmN0aW9uKHgpIHsKICAgIHdoaWNoKG1vbnRoLm5hbWUgJWluJSB4KQogIH0pCiAgZGFpbHlSZXMkWWVhciA8LSB5ZWFyKGRhaWx5UmVzJERhdGUpCiAgZGFpbHlSZXMkV2VlayA8LSB3ZWVrKGRhaWx5UmVzJERhdGUpCiAgZGFpbHlSZXMkRGF5V2VlayA8LSB3ZWVrZGF5cyhkYWlseVJlcyREYXRlKQogIHdyaXRlLmNzdihkYWlseVJlcywgZmlsZW5hbWUpCn0KYGBgCgojIyAyLiBXZWVrbHkgVHJlbmRzIChCaWcgUGljdHVyZSkKCmBgYHtyIGVjaG8gPSBULCB3YXJuaW5nID0gJ2hpZGUnLCBtZXNzYWdlID0gRn0KIyMjIC0tLSBEZWZpbmUgcHJvamVjdHMgdW5kZXIgY29uc2lkZXJhdGlvbjoKIyAtIHJlcG9ydDogY3VycmVudCB1cGRhdGUKcHJpbnQocGFzdGUwKCJDdXJyZW50IHVwZGF0ZTogIiwgYXMuY2hhcmFjdGVyKFN5cy50aW1lKCkpKSkKcHJvamVjdHMgPC0gYygnZGV3aWtpJywgJ2Vud2lraScsICdmcndpa2knKQpsRiA8LSBsaXN0LmZpbGVzKCcuL19yZXN1bHRzLycpCmxGIDwtIGxGW2dyZXBsKCIuY3N2IiwgbEYsIGZpeGVkID0gVCldCmR3U2V0cyA8LSBsaXN0KCkKIyMjIC0tLSBSZWNlbnQgd2Vla2x5IHRyZW5kczoKZm9yIChpIGluIDE6bGVuZ3RoKHByb2plY3RzKSkgewogIHcgPC0gd2hpY2goZ3JlcGwocHJvamVjdHNbaV0sIGxGLCBmaXhlZCA9IFQpKQogIGRhdGFTZXQgPC0gcmVhZC5jc3YocGFzdGUoJy4vX3Jlc3VsdHMvJywgbEZbd10sIHNlcCA9ICIiKSwgCiAgICAgICAgICAgICAgICAgICAgICByb3cubmFtZXMgPSAxLAogICAgICAgICAgICAgICAgICAgICAgY2hlY2submFtZXMgPSBGLAogICAgICAgICAgICAgICAgICAgICAgaGVhZGVyID0gVCwKICAgICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQogIGRXZWVrbHkgPC0gZGF0YVNldAogIGRXZWVrbHkkTW9udGggPC0gc2FwcGx5KGRXZWVrbHkkTW9udGgsIGZ1bmN0aW9uKHgpIHsKICAgIGlmICghKG5jaGFyKHgpID09IDIpKSB7CiAgICAgIHJldHVybihwYXN0ZSgiMCIsIHgsIHNlcCA9ICIiKSkKICAgIH0gZWxzZSB7CiAgICAgIHJldHVybih4KQogICAgfQogIH0pCiAgZFdlZWtseSRXZWVrIDwtIHNhcHBseShkV2Vla2x5JFdlZWssIGZ1bmN0aW9uKHgpIHsKICAgIGlmICghKG5jaGFyKHgpID09IDIpKSB7CiAgICAgIHJldHVybihwYXN0ZSgiMCIsIHgsIHNlcCA9ICIiKSkKICAgIH0gZWxzZSB7CiAgICAgIHJldHVybih4KQogICAgfQogIH0pCiAgZFdlZWtseSRZVyA8LSBwYXN0ZShkV2Vla2x5JFllYXIsIGRXZWVrbHkkV2Vlaywgc2VwID0gIi0iKQogIGRXZWVrbHkgPC0gZFdlZWtseSAlPiUgCiAgICBncm91cF9ieShZVykgJT4lIAogICAgc3VtbWFyaXNlKENvdW50ID0gc3VtKENvdW50KSkgJT4lIAogICAgYXJyYW5nZShZVykKICBkd1NldHNbW2ldXSA8LSBkV2Vla2x5CiAgcm0oZFdlZWtseSk7IHJtKGRhdGFTZXQpOyBnYygpCn0KIyMjIC0tLSBwcm9kdWNlIHBsb3RTZXQKZHdlZWtzIDwtIHVubGlzdChsYXBwbHkoZHdTZXRzLCBmdW5jdGlvbih4KSB7CiAgeCRZVwp9KSkKZE1hdCA8LSBhcy5kYXRhLmZyYW1lKG1hdHJpeCgnJywgbnJvdyA9IGxlbmd0aChkd2Vla3MpLCBuY29sID0gbGVuZ3RoKHByb2plY3RzKSArIDEpLCAKICAgICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQpjb2xuYW1lcyhkTWF0KVsxXSA8LSAnV2VlaycKY29sbmFtZXMoZE1hdClbMjpkaW0oZE1hdClbMl1dIDwtIHByb2plY3RzCmRNYXRbLCAxXSA8LSBkd2Vla3MKZm9yIChpIGluIDE6bGVuZ3RoKGR3U2V0cykpIHsKICB3IDwtIHdoaWNoKGRNYXQkV2VlayAlaW4lIGR3U2V0c1tbaV1dJFlXKQogIGRNYXRbLCBpKzFdW3ddIDwtIGR3U2V0c1tbaV1dJENvdW50IAp9CmRNYXQgPC0gZE1hdCAlPiUgCiAgZ2F0aGVyKGtleSA9IFByb2plY3QsCiAgICAgICAgIHZhbHVlID0gQ291bnQsCiAgICAgICAgIHByb2plY3RzKQpkTWF0JENvdW50IDwtIGFzLm51bWVyaWMoZE1hdCRDb3VudCkKIyAtIHgtYXhpcyBsYWJlbHMKZE1hdCRYTGFicyA8LSBzYXBwbHkoZE1hdCRXZWVrLCBmdW5jdGlvbih4KSB7CiAgaWYgKGdyZXBsKCItMDEkIiwgeCkpIHsKICAgIHJldHVybihzdHJzcGxpdCh4LCBzcGxpdCA9ICItIiwgZml4ZWQgPSBUKVtbMV1dWzFdKSAKICB9IGVsc2UgewogICAgcmV0dXJuKCIiKQogICAgfQp9KQojIC0gVmlzdWFsaXplIHcuIHtnZ3Bsb3QyfQpnZ3Bsb3QoZE1hdCwgYWVzKHggPSBXZWVrLAogICAgICAgICAgICAgICAgIHkgPSBDb3VudCwKICAgICAgICAgICAgICAgICBncm91cCA9IFByb2plY3QsCiAgICAgICAgICAgICAgICAgY29sb3IgPSBQcm9qZWN0LAogICAgICAgICAgICAgICAgIGZpbGwgPSBQcm9qZWN0KSkgKyAKICBnZW9tX2xpbmUoc2l6ZSA9IC4yNSkgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEpICsgCiAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHMgPSBkTWF0JFhMYWJzKSArCiAgeGxhYigiWWVhciAod2Vla2x5IGRhdGEgcmVzb2x1dGlvbikiKSArCiAgeWxhYigiTmV3IGVkaXRvcnMiKSArCiAgZ2d0aXRsZSgnTmV3IEVkaXRvcnMgKD49IDEwIGVkaXRzKSBJbmNvbWU6XG5XZWVrbHkgY29tcGFyaXNvbiAoc3RhcnRpbmcgYXQ6IFdlZWsgMTYuIG9mIDIwMTYuKScpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApKSArCiAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArIAogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yLnggPSBlbGVtZW50X2JsYW5rKCkpCmBgYAoKTG9nLXNjYWxlOgoKYGBge3IgZWNobyA9IFQsIHdhcm5pbmcgPSAnaGlkZScsIG1lc3NhZ2UgPSBGfQojIC0gVmlzdWFsaXplIHcuIHtnZ3Bsb3QyfQpnZ3Bsb3QoZE1hdCwgYWVzKHggPSBXZWVrLAogICAgICAgICAgICAgICAgIHkgPSBsb2coQ291bnQpLAogICAgICAgICAgICAgICAgIGdyb3VwID0gUHJvamVjdCwKICAgICAgICAgICAgICAgICBjb2xvciA9IFByb2plY3QsCiAgICAgICAgICAgICAgICAgZmlsbCA9IFByb2plY3QpKSArIAogIGdlb21fbGluZShzaXplID0gLjI1KSArIAogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBjb21tYSkgKyAKICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscyA9IGRNYXQkWExhYnMpICsKICB4bGFiKCJZZWFyICh3ZWVrbHkgZGF0YSByZXNvbHV0aW9uKSIpICsKICB5bGFiKCJsb2coTmV3IGVkaXRvcnMpIikgKwogIGdndGl0bGUoJ05ldyBFZGl0b3JzICg+PSAxMCBlZGl0cykgSW5jb21lOlxuV2Vla2x5IGNvbXBhcmlzb24gKHN0YXJ0aW5nIGF0OiBXZWVrIDE2LiBvZiAyMDE2LiknKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSkgKwogIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICB0aGVtZShwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vci54ID0gZWxlbWVudF9ibGFuaygpKQpgYGAKCiMjIDMuIE1vbnRobHkgVHJlbmRzOiBUaGUgUHJldmlvdXMgU2l4IE1vbnRocwoKYGBge3IgZWNobyA9IFQsIHdhcm5pbmcgPSAnaGlkZScsIG1lc3NhZ2UgPSBGfQojIyMgLS0tIERlZmluZSBwcm9qZWN0cyB1bmRlciBjb25zaWRlcmF0aW9uL2dldCBmaWxlcwpsRiA8LSBsaXN0LmZpbGVzKCcuL19yZXN1bHRzLycpCmxGIDwtIGxGW2dyZXBsKCIuY3N2IiwgbEYsIGZpeGVkID0gVCldCmR3U2V0cyA8LSBsaXN0KCkKIyMjIC0tLSBNb250aGx5IHRyZW5kczoKZm9yIChpIGluIDE6bGVuZ3RoKGxGKSkgewogIHByb2plY3QgPC0gc3Ryc3BsaXQoCiAgICBzdHJzcGxpdChsRltpXSwgc3BsaXQgPSAiXyIsIGZpeGVkID0gVClbWzFdXVsyXSwKICAgIHNwbGl0ID0gIi4iLCBmaXhlZCA9IFQpW1sxXV1bMV0KICBkUyA8LSByZWFkLmNzdihwYXN0ZSgnLi9fcmVzdWx0cy8nLCBsRltpXSwgc2VwID0gIiIpLAogICAgICAgICAgICAgICBoZWFkZXIgPSBULAogICAgICAgICAgICAgICBjaGVjay5uYW1lcyA9IEYsCiAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGLAogICAgICAgICAgICAgICByb3cubmFtZXMgPSAxKQogIGRTJFllYXJNb250aCA8LSBwYXN0ZShkUyRZZWFyLCAKICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKG5jaGFyKGRTJE1vbnRoKSA9PSAyLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRTJE1vbnRoLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlKCIwIiwgZFMkTW9udGgsIHNlcCA9ICIiKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgICAgICAgICAgc2VwID0gIi0iKQogIGRTIDwtIGRwbHlyOjpzZWxlY3QoZFMsIFllYXJNb250aCwgQ291bnQpCiAgZFMkUHJvamVjdCA8LSBwcm9qZWN0CiAgZHdTZXRzW1tpXV0gPC0gZFMKICBybShkUykKfQpkd1NldHMgPC0gcmJpbmRsaXN0KGR3U2V0cykKZHdTZXRzIDwtIGR3U2V0cyAlPiUgCiAgZ3JvdXBfYnkoUHJvamVjdCwgWWVhck1vbnRoKSAlPiUgCiAgc3VtbWFyaXNlKEVkaXRvcnMgPSBzdW0oQ291bnQpKSAlPiUgCiAgYXJyYW5nZShQcm9qZWN0LCBZZWFyTW9udGgpCiMjIyAtLS0gZGV0ZXJtaW5lOiBsYXN0IDYgbW9udGhzCmFjdHVhbERhdGUgPC0gYXMuY2hhcmFjdGVyKFN5cy50aW1lKCkpCmFjdHVhbERhdGVZIDwtIGFzLm51bWVyaWMoc3Ryc3BsaXQoYWN0dWFsRGF0ZSwgc3BsaXQgPSAiLSIpW1sxXV1bMV0pCmFjdHVhbERhdGVNIDwtIGFzLm51bWVyaWMoc3Ryc3BsaXQoYWN0dWFsRGF0ZSwgc3BsaXQgPSAiLSIpW1sxXV1bMl0pCmFjdHVhbERhdGVNIDwtIGFjdHVhbERhdGVNIC0gMQphY3R1YWxEYXRlTTEgPC0gYWN0dWFsRGF0ZU0gLSA1Cm1vbnRoc1NlcSA8LSBhY3R1YWxEYXRlTTE6YWN0dWFsRGF0ZU0KeWVhcnNTZXEgPC0gcmVwKGFjdHVhbERhdGVZLCBsZW5ndGgobW9udGhzU2VxKSkKeWVhcnNTZXFbd2hpY2gobW9udGhzU2VxIDw9IDApXSA8LSBhY3R1YWxEYXRlWSAtIDEKbW9udGhzU2VxW3doaWNoKG1vbnRoc1NlcTw9IDApXSA8LSAxMiAtIGFicyhtb250aHNTZXFbd2hpY2gobW9udGhzU2VxPD0gMCldKQp0YXJnZXRZTSA8LSBwYXN0ZSh5ZWFyc1NlcSwgCiAgICAgICAgICAgICAgICAgIGlmZWxzZShuY2hhcihtb250aHNTZXEpID09IDIsCiAgICAgICAgICAgICAgICAgICAgICAgICBtb250aHNTZXEsCiAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZSgiMCIsIG1vbnRoc1NlcSwgc2VwID0gIiIpCiAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgICBzZXAgPSAiLSIpCiMjIyAtLS0gZmlsdGVyOiBsYXN0IDYgbW9udGhzCmR3U2V0cyA8LSBkd1NldHMgJT4lIAogIGZpbHRlcihZZWFyTW9udGggJWluJSB0YXJnZXRZTSkKIyMjIC0tLSB2aXN1YWxpemUgdy4ge2dncGxvdDJ9CmNvbG5hbWVzKGR3U2V0cylbMl0gPC0gJ01vbnRoJwpkd1NldHMkTW9udGggPC0gZmFjdG9yKGR3U2V0cyRNb250aCwgbGV2ZWxzID0gc29ydCh1bmlxdWUoZHdTZXRzJE1vbnRoKSkpCmdncGxvdChkd1NldHMsCiAgICAgICBhZXMoeCA9IE1vbnRoLCB5ID0gRWRpdG9ycywgbGFiZWwgPSBFZGl0b3JzKSkgKwogICAgICAgICAgZ2VvbV9saW5lKHNpemUgPSAuMjUsIGNvbG9yID0gIiM0YzhjZmYiLCBncm91cCA9IDEpICsKICAgICAgICAgIGdlb21fcG9pbnQoc2l6ZSA9IDEuNSwgY29sb3IgPSAiIzRjOGNmZiIpICsgCiAgICAgICAgICBnZW9tX3BvaW50KHNpemUgPSAxLCBjb2xvciA9ICJ3aGl0ZSIpICsgCiAgICAgICAgICBnZW9tX3RleHRfcmVwZWwoZGF0YSA9IGR3U2V0cywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgYWVzKHggPSBNb250aCwgeSA9IEVkaXRvcnMsIGxhYmVsID0gRWRpdG9ycyksIAogICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAzKSArCiAgICAgICAgICBmYWNldF93cmFwKH4gUHJvamVjdCwgbmNvbCA9IDMsIHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgICAgICAgICB4bGFiKCdNb250aCcpICsgeWxhYignTmV3IEVkaXRvcnMgKD49IDEwIGVkaXRzKScpICsKICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBjb21tYSkgKyAKICAgICAgICAgIHRoZW1lX21pbmltYWwoKSArCiAgICAgICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBzaXplID0gMTAsIGhqdXN0ID0gMSkpICsKICAgICAgICAgIHRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpKSArCiAgICAgICAgICB0aGVtZShheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSkgKwogICAgICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpKQpgYGAKCiMjIDMuIE1vbnRobHkgVHJlbmRzOiBUaGUgUHJldmlvdXMgVHdvIFllYXJzCgpgYGB7ciBlY2hvID0gVCwgd2FybmluZyA9ICdoaWRlJywgbWVzc2FnZSA9IEZ9CiMjIyAtLS0gRGVmaW5lIHByb2plY3RzIHVuZGVyIGNvbnNpZGVyYXRpb24vZ2V0IGZpbGVzCmxGIDwtIGxpc3QuZmlsZXMoJy4vX3Jlc3VsdHMvJykKbEYgPC0gbEZbZ3JlcGwoIi5jc3YiLCBsRiwgZml4ZWQgPSBUKV0KZHdTZXRzIDwtIGxpc3QoKQojIyMgLS0tIE1vbnRobHkgdHJlbmRzOgpmb3IgKGkgaW4gMTpsZW5ndGgobEYpKSB7CiAgcHJvamVjdCA8LSBzdHJzcGxpdCgKICAgIHN0cnNwbGl0KGxGW2ldLCBzcGxpdCA9ICJfIiwgZml4ZWQgPSBUKVtbMV1dWzJdLAogICAgc3BsaXQgPSAiLiIsIGZpeGVkID0gVClbWzFdXVsxXQogIGRTIDwtIHJlYWQuY3N2KHBhc3RlKCcuL19yZXN1bHRzLycsIGxGW2ldLCBzZXAgPSAiIiksCiAgICAgICAgICAgICAgIGhlYWRlciA9IFQsCiAgICAgICAgICAgICAgIGNoZWNrLm5hbWVzID0gRiwKICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IEYsCiAgICAgICAgICAgICAgIHJvdy5uYW1lcyA9IDEpCiAgZFMkWWVhck1vbnRoIDwtIHBhc3RlKGRTJFllYXIsIAogICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UobmNoYXIoZFMkTW9udGgpID09IDIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZFMkTW9udGgsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUoIjAiLCBkUyRNb250aCwgc2VwID0gIiIpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgICAgICAgICBzZXAgPSAiLSIpCiAgZFMgPC0gZHBseXI6OnNlbGVjdChkUywgWWVhck1vbnRoLCBDb3VudCkKICBkUyRQcm9qZWN0IDwtIHByb2plY3QKICBkd1NldHNbW2ldXSA8LSBkUwogIHJtKGRTKQp9CmR3U2V0cyA8LSByYmluZGxpc3QoZHdTZXRzKQpkd1NldHMgPC0gZHdTZXRzICU+JSAKICBncm91cF9ieShQcm9qZWN0LCBZZWFyTW9udGgpICU+JSAKICBzdW1tYXJpc2UoRWRpdG9ycyA9IHN1bShDb3VudCkpICU+JSAKICBhcnJhbmdlKFByb2plY3QsIFllYXJNb250aCkKIyMjIC0tLSBkZXRlcm1pbmU6IGxhc3QgMiB5ZWFycwphY3R1YWxEYXRlIDwtIGFzLmNoYXJhY3RlcihTeXMudGltZSgpKQphY3R1YWxEYXRlWSA8LSBhcy5udW1lcmljKHN0cnNwbGl0KGFjdHVhbERhdGUsIHNwbGl0ID0gIi0iKVtbMV1dWzFdKQphY3R1YWxEYXRlTSA8LSBhcy5udW1lcmljKHN0cnNwbGl0KGFjdHVhbERhdGUsIHNwbGl0ID0gIi0iKVtbMV1dWzJdKQphY3R1YWxEYXRlTSA8LSBhY3R1YWxEYXRlTSAtIDEKYWN0dWFsRGF0ZU0xIDwtIGFjdHVhbERhdGVNIC0gMTIKbW9udGhzU2VxIDwtIGFjdHVhbERhdGVNMTphY3R1YWxEYXRlTQp5ZWFyc1NlcSA8LSByZXAoYWN0dWFsRGF0ZVksIGxlbmd0aChtb250aHNTZXEpKQp5ZWFyc1NlcVt3aGljaChtb250aHNTZXEgPD0gMCldIDwtIGFjdHVhbERhdGVZIC0gMQptb250aHNTZXFbd2hpY2gobW9udGhzU2VxIDw9IDApXSA8LSAxMiAtIGFicyhtb250aHNTZXFbd2hpY2gobW9udGhzU2VxPD0gMCldKQp0YXJnZXRZTSA8LSBwYXN0ZSh5ZWFyc1NlcSwgCiAgICAgICAgICAgICAgICAgIGlmZWxzZShuY2hhcihtb250aHNTZXEpID09IDIsCiAgICAgICAgICAgICAgICAgICAgICAgICBtb250aHNTZXEsCiAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZSgiMCIsIG1vbnRoc1NlcSwgc2VwID0gIiIpCiAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgICBzZXAgPSAiLSIpCnRhcmdldFlNMSA8LSBsYXBwbHkodGFyZ2V0WU0sIGZ1bmN0aW9uKHgpIHsKICB4IDwtIHN0cnNwbGl0KHgsIHNwbGl0ID0gIi0iKVtbMV1dCiAgeFsxXSA8LSBhcy5udW1lcmljKHhbMV0pIC0gMQogIHggPC0gcGFzdGUoeCwgY29sbGFwc2UgPSAiLSIpCiAgcmV0dXJuKHgpCn0pCnRhcmdldFlNIDwtIHVuaXF1ZShjKHRhcmdldFlNLCB1bmxpc3QodGFyZ2V0WU0xKSkpCiMjIyAtLS0gZmlsdGVyOiBsYXN0IDYgbW9udGhzCmR3U2V0cyA8LSBkd1NldHMgJT4lIAogIGZpbHRlcihZZWFyTW9udGggJWluJSB0YXJnZXRZTSkKIyMjIC0tLSB2aXN1YWxpemUgdy4ge2dncGxvdDJ9CmNvbG5hbWVzKGR3U2V0cylbMl0gPC0gJ01vbnRoJwpkd1NldHMkTW9udGggPC0gZmFjdG9yKGR3U2V0cyRNb250aCwgbGV2ZWxzID0gc29ydCh1bmlxdWUoZHdTZXRzJE1vbnRoKSkpCmdncGxvdChkd1NldHMsCiAgICAgICBhZXMoeCA9IE1vbnRoLCB5ID0gRWRpdG9ycywgbGFiZWwgPSBFZGl0b3JzKSkgKwogICAgICAgICAgZ2VvbV9saW5lKHNpemUgPSAuMjUsIGNvbG9yID0gIiM0YzhjZmYiLCBncm91cCA9IDEpICsKICAgICAgICAgIGdlb21fcG9pbnQoc2l6ZSA9IDEuNSwgY29sb3IgPSAiIzRjOGNmZiIpICsgCiAgICAgICAgICBnZW9tX3BvaW50KHNpemUgPSAxLCBjb2xvciA9ICJ3aGl0ZSIpICsgCiAgICAgICAgICBnZW9tX3RleHRfcmVwZWwoZGF0YSA9IGR3U2V0cywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgYWVzKHggPSBNb250aCwgeSA9IEVkaXRvcnMsIGxhYmVsID0gRWRpdG9ycyksIAogICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAzKSArCiAgICAgICAgICBmYWNldF93cmFwKH4gUHJvamVjdCwgbmNvbCA9IDEsIHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgICAgICAgICB4bGFiKCdNb250aCcpICsgeWxhYignTmV3IEVkaXRvcnMgKD49IDEwIGVkaXRzKScpICsKICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBjb21tYSkgKyAKICAgICAgICAgIHRoZW1lX21pbmltYWwoKSArCiAgICAgICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBzaXplID0gOCwgaGp1c3QgPSAxKSkgKwogICAgICAgICAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMikpICsKICAgICAgICAgIHRoZW1lKGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpKSArCiAgICAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSkpCmBgYAoKIyMgNC4gZGV3aWtpIEZvcmVjYXN0CgpUaGUgb3B0aW1hbCBBUklNQSBmb3JlY2FzdCBmb3IgYGRld2lraWAsIHN0YXJ0aW5nIGZyb20gdGhlIGZpcnN0IHllYXIgd2l0aCBhIGNvbXBsZXRlIG1vbnRobHkgZGF0YXNldCAoMjAwNyk6CgpgYGB7ciBlY2hvID0gVCwgd2FybmluZyA9ICdoaWRlJywgbWVzc2FnZSA9IEZ9CiMjIyAtLS0gRGF0YQpkYXRhU2V0IDwtIHJlYWQuY3N2KHBhc3RlKGdldHdkKCksICcvX3Jlc3VsdHMvTmV3VXNlcnNEYWlseV9kZXdpa2kuY3N2Jywgc2VwID0gJycpLAogICAgICAgICAgICAgICAgICAgIGhlYWRlciA9IFQsCiAgICAgICAgICAgICAgICAgICAgY2hlY2submFtZXMgPSBGLAogICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGLAogICAgICAgICAgICAgICAgICAgIHJvdy5uYW1lcyA9IDEpCiMjIyAtLS0gV3JhbmdsZQpkYXRhU2V0JE1vbnRoIDwtIHNhcHBseShkYXRhU2V0JE1vbnRoLCBmdW5jdGlvbih4KSB7CiAgaWYobmNoYXIoeCkgPT0gMSkgewogICAgeCA8LSBwYXN0ZSgiMCIsIHgsIHNlcCA9ICIiKQogIH0KICB4Cn0pCmRhdGFTZXQgPC0gYXJyYW5nZShkYXRhU2V0LCBZZWFyLCBNb250aCkKIyAtIGNvbXBsZXRlIGRhdGEgc2luY2UgMjAwNzoKY29tcGxldGVZZWFycyA8LSAyMDA3OjIwMTcKd0NvbXBsZXRlIDwtIHJvd1N1bXMoc2FwcGx5KGNvbXBsZXRlWWVhcnMsIGZ1bmN0aW9uKHgpIHsKICBncmVwbCh4LCBkYXRhU2V0JFllYXIpCiAgfSkpCmRhdGFTZXQgPC0gZGF0YVNldFthcy5sb2dpY2FsKHdDb21wbGV0ZSksIF0KIyAtIHN1bW1hcmlzZSBwZXIgbW9udGggYW5kIGRyb3AgaW5jb21wbGV0ZSBkYXRhIGZvciB0aGUgbGFzdCBtb250aDoKZGF0YVNldCA8LSBkYXRhU2V0ICU+JSAKICBzZWxlY3QoWWVhciwgTW9udGgsIENvdW50KSAlPiUgCiAgZ3JvdXBfYnkoWWVhciwgTW9udGgpICU+JSAKICBzdW1tYXJpc2UoRWRpdHMgPSBzdW0oQ291bnQpKQojIyMgLS0tIGFzIHRpbWUgc2VyaWVzIG9iamVjdDoKdGltZUVkcyA8LSB0cyhkYXRhU2V0JEVkaXRzLCAKICAgICAgICAgICAgICBzdGFydCA9IGMoMjAwNywgMSksIAogICAgICAgICAgICAgIGVuZCA9IGMoMjAxNywgYXMubnVtZXJpYyhkYXRhU2V0JE1vbnRoW2RpbShkYXRhU2V0KVsxXV0pKSwgCiAgICAgICAgICAgICAgZnJlcXVlbmN5ID0gMTIpCiMjIyAtLS0gQVJJTUEgbW9kZWwKdGltZUVkc0FSSU1BIDwtIGF1dG8uYXJpbWEodGltZUVkcywgRCA9IDEsIHNlYXNvbmFsID0gVCkKdGltZUVkc0FSSU1BCnBsb3QoZm9yZWNhc3QodGltZUVkc0FSSU1BKSkKYGBgCg==