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

The campaign is run from 2018/08/01 to 2018/08/08.

CURRENT UPDATE: Complete dataset as of 2018/08/09.

0. Data Acquisiton

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

0.1 Daily Update

# - wle_2018_de

### --- WMDE Spring Banner Campaign 2018
### --- Daily Update

rm(list = ls())

### --- Libraries
library(dplyr)
library(tidyr)
library(stringr)
library(data.table)

### --- Directories
outDir <- '/home/goransm/RScripts/NewEditors/2018_SummerBannerCampaign/'
setwd(outDir)

### --- General Info:
# First Banner (https://de.wikipedia.org/wiki/Wikipedia:Hauptseite?banner=B18WMDE_authors_02_180801_1&force=1)
# Registration Name: Tesssssttttt
# Created: Mo, 30.07.2018 around 15:42
# 
# Second Banner (https://de.wikipedia.org/wiki/Wikipedia:Hauptseite?banner=B18WMDE_authors_02_180801_2&force=1)
# Registration name: Tessssttttt
# Created: Mo, 30.07.2018 around 15:45
# 
# Third Banner (https://de.wikipedia.org/wiki/Wikipedia:Hauptseite?banner=B18WMDE_authors_02_180801_3&force=1)
# Registration name: Tttteesssstt
# Created: Mo, 30.07.2018 around 15:45

### --- banner names (/beacon/impression):
# - B18WMDE_authors_02_180801_1
# - B18WMDE_authors_02_180801_2
# - B18WMDE_authors_02_180801_3

### --- campaign tags
# - WMDE_neweditors_summer2018_1
# - WMDE_neweditors_summer2018_2
# - WMDE_neweditors_summer2018_3

### --- landingpage including the campaign tag and anchor
# - Banner 1: https://de.wikipedia.org/wiki/Wikipedia:Wikimedia_Deutschland/Neue_Ehrenamtliche/FAQ?campaign=WMDE_neweditors_summer2018_1#Wer-darf-schreiben
# - Banner 2: https://de.wikipedia.org/wiki/Wikipedia:Wikimedia_Deutschland/Neue_Ehrenamtliche/FAQ?campaign=WMDE_neweditors_summer2018_2#Wikipedia-Buero
# - Banner 3: https://de.wikipedia.org/wiki/Wikipedia:Wikimedia_Deutschland/Neue_Ehrenamtliche/FAQ?campaign=WMDE_neweditors_summer2018_3#Schutz-vor-Missbrauch
# - Second landing page: https://de.wikipedia.org/wiki/Wikipedia:Wikimedia_Deutschland/LerneWikipedia

# - Update on (Reminder: stat1005 time is UTC): today minus one day
today <- strsplit(
  strsplit(
    as.character(as.POSIXct(Sys.time()) - 24*60*60),
    split = " ",
    fixed = TRUE)[[1]][1],
  split = "-",
  fixed = TRUE)[[1]]
today <- as.list(today)
names(today) <- c('year', 'month', 'day')

# - construct wmf.webrequest year/month/day/hour condition
# - for today:
dateCondition <- paste0("((year = ", today$year,
                        " AND month = ", today$month,
                        " AND day = ", as.integer(today$day) - 1,
                        " AND (hour = 22 OR hour = 23))",
                        " OR ",
                        "(year = ", today$year,
                        " AND month = ", today$month,
                        " AND day = ", today$day,
                        " AND (hour >= 0 OR hour < 22)))"
                        )

### --- Collect Banner Impressions for Update: HiveQL
q <- paste(
  "USE wmf;
  SELECT uri_query FROM webrequest
  WHERE uri_host = 'de.wikipedia.org'
  AND uri_path = '/beacon/impression'
  AND ",
  dateCondition,
  " AND ((uri_query LIKE '%B18WMDE_authors_02_180801_1%') OR
    (uri_query LIKE '%B18WMDE_authors_02_180801_2%') OR
    (uri_query LIKE '%B18WMDE_authors_02_180801_3%'));",
  sep = "")
# - write hql
write(q, 'summerBC2018_BannerImpressionsDaily.hql')
# - prepare output file:
fileName <- 'sbc2018_BannerImpressionsDaily.tsv'
# - execute hql script:
hiveArgs <- 'beeline --verbose=true -f'
hiveInput <- paste0('summerBC2018_BannerImpressionsDaily.hql > ', fileName)
# - command:
hiveCommand <- paste(hiveArgs, hiveInput)
system(command = hiveCommand, wait = TRUE)

### --- Collect Pageviews == Banner clicks for Update: HiveQL
# https://de.wikipedia.org/wiki/Wikipedia:Wikimedia_Deutschland/LerneWikipedia
q <- paste(
  "USE wmf;
  SELECT uri_path, uri_query, referer FROM webrequest
  WHERE uri_host = 'de.wikipedia.org'
  AND ((uri_path = '/wiki/Wikipedia:Wikimedia_Deutschland/Neue_Ehrenamtliche/FAQ' AND uri_query LIKE '%campaign=WMDE_neweditors_summer2018%')
  OR (uri_path = '/wiki/Wikipedia:Wikimedia_Deutschland/LerneWikipedia')) 
  AND ", dateCondition,
  " ;",
  sep = "")
# - write hql
write(q, 'summerBC2018_PageViewsDaily.hql')
# - prepare output file:
fileName <- 'sbc2018_PageViewsDaily.tsv'
# - execute hql script:
hiveArgs <- 'beeline --verbose=true -f'
hiveInput <- paste0('summerBC2018_PageViewsDaily.hql > ', fileName)
# - command:
hiveCommand <- paste(hiveArgs, hiveInput)
system(command = hiveCommand, wait = TRUE)

### --- Collect Use Registrations for Update: SQL
# - ServerSideAccountCreation_17719237 schema
qCommand <- "mysql --defaults-file=/etc/mysql/conf.d/analytics-research-client.cnf -h analytics-slave.eqiad.wmnet -A -e \"select * from log.ServerSideAccountCreation_17719237 where ((webHost = 'de.wikipedia.org') and (timestamp >= 20180729000000) and ((event_campaign like '%WMDE_neweditors_summer2018_1%') or (event_campaign like '%WMDE_neweditors_summer2018_2%') or (event_campaign like '%WMDE_neweditors_summer2018_3%')));\" > /home/goransm/RScripts/NewEditors/2018_SummerBannerCampaign/summerBC2018_userRegistrations.tsv"
system(command = qCommand, wait = TRUE)

### --- Collect Banner Events for Update: SQL
# - WMDEBannerEvents_18193948 schema
qCommand <- "mysql --defaults-file=/etc/mysql/conf.d/analytics-research-client.cnf -h analytics-slave.eqiad.wmnet -A -e \"select * from log.WMDEBannerEvents_18193948 where timestamp >= 20180729000000;\" > /home/goransm/RScripts/NewEditors/2018_SummerBannerCampaign/summerBC2018_bannerEvents.tsv"
system(command = qCommand, wait = TRUE)


### --- Prepare for repoting

# - Banner Impressions
bImpData <- readLines('sbc2018_BannerImpressionsDaily.tsv', n = -1)
bImpData <- bImpData[9:(length(bImpData) - 2)]
bImpData <- bImpData[-1]
bImpData <- data.frame(dat = bImpData, stringsAsFactors = F)
bannerA <- length(which(grepl("banner=B18WMDE_authors_02_180801_1", bImpData$dat, fixed = T)))
bannerB <- length(which(grepl("banner=B18WMDE_authors_02_180801_2", bImpData$dat, fixed = T)))
bannerC <- length(which(grepl("banner=B18WMDE_authors_02_180801_3", bImpData$dat, fixed = T)))
DailyBannerImpressions <- data.frame(
  Banner = c('B18WMDE_authors_1', 'B18WMDE_authors_2', 'B18WMDE_authors_3'),
  Count = c(bannerA, bannerB, bannerC),
  CampaignDay = rep(paste0(today, collapse = "-", sep = ""), 3)
)
DailyBannerImpressions$Count <- DailyBannerImpressions$Count/.01
# - DailyBannerImpressions
lF <- list.files()
if ('DailyBannerImpressions.csv' %in% lF) {
  dPS <- read.csv('DailyBannerImpressions.csv',
                  header = T,
                  row.names = 1)
  DailyBannerImpressions <- rbind(dPS, DailyBannerImpressions)
  write.csv(DailyBannerImpressions, 'DailyBannerImpressions.csv')
} else {
  write.csv(DailyBannerImpressions, 'DailyBannerImpressions.csv')
}

# - Pageviews
pageViews <- readLines('sbc2018_PageViewsDaily.tsv', n = -1)
pageViews <- pageViews[8:(length(pageViews) - 2)]
header = pageViews[1]
pageViews <- pageViews[-1]
header <- unlist(strsplit(header, "\t")[[1]])
pageViews <- data.frame(dat = pageViews, stringsAsFactors = F)
pageViews <- separate(pageViews,
                      dat,
                      into = c('uri_path', 'uri_query', 'referer'),
                      sep = "\t")
dailyPageviewsSet <- pageViews %>% 
  filter(grepl('campaign=WMDE_neweditors_summer2018', uri_query) | 
           grepl('/wiki/Wikipedia:Wikimedia_Deutschland/LerneWikipedia', uri_path)) %>%
  group_by(uri_query, uri_path) %>%
  summarise(Count = n())
dailyPageviewsSet$CampaignDay <- paste(unlist(today), collapse = "-", sep = "")
# - DailyPageviews
lF <- list.files()
if ('DailyPageviews.csv' %in% lF) {
  dPS <- read.csv('DailyPageviews.csv',
                  header = T,
                  row.names = 1)
  dailyPageviewsSet <- rbind(dPS, as.data.frame(dailyPageviewsSet))
  write.csv(dailyPageviewsSet, 'DailyPageviews.csv')
} else {
  write.csv(dailyPageviewsSet, 'DailyPageviews.csv')
}

# - User registrations
userRegistrations <- read.delim('summerBC2018_userRegistrations.tsv', 
                                sep = "\t",
                                header = T,
                                quote = "", 
                                stringsAsFactors = F)
userRegistrations <- userRegistrations[grepl('is_bot": false', userRegistrations$userAgent, fixed = T), ]
userRegistrations$timestamp <- as.character(userRegistrations$timestamp)
userRegistrations$timestamp <- as.POSIXct(userRegistrations$timestamp, tz = "UTC", format = "%Y%m%d%H%M%S") 
# - CEST correction on POSIXct class, +2hours:
userRegistrations$timestamp <- userRegistrations$timestamp + 2*60*60
# - wrangle
userRegistrations$CampaignDay <- sapply(userRegistrations$timestamp, function(x) {
  paste(c(
    substr(x, 1,4),
    substr(x, 6,7),
    substr(x, 9,10)
    ),
    collapse = "-",
    sep = "")
})
userRegistrations <- userRegistrations[which(userRegistrations$CampaignDay %in% paste(today, collapse = "-", sep = "")), ]
dailyUserRegSet <- userRegistrations %>%
  select(event_campaign) %>%
  group_by(event_campaign) %>%
  summarise(Count = n())
dailyUserRegSet$CampaignDay <- paste(unlist(today), collapse = "-", sep = "")
# - Daily User Registrations
lF <- list.files()
if ('dailyUserRegistrations.csv' %in% lF) {
  dPS <- read.csv('dailyUserRegistrations.csv', 
                  header = T, 
                  row.names = 1)
  dailyUserRegSet <- rbind(dPS, dailyUserRegSet)
  write.csv(dailyUserRegSet, 'dailyUserRegistrations.csv')
} else {
  write.csv(dailyUserRegSet, 'dailyUserRegistrations.csv')
}

0.1 Post-Campaign Analytics

NOTE: Training Module data are obtained directly from the application maintainer. The following code retrieves all user registrations and edits.

### --- User registrations

### --- Libraries
library(dplyr)
library(tidyr)
library(stringr)
library(data.table)

# - ServerSideAccountCreation_5487345
qCommand <- "mysql --defaults-file=/etc/mysql/conf.d/analytics-research-client.cnf -h analytics-slave.eqiad.wmnet -A -e \"select * from log.ServerSideAccountCreation_17719237 where ((webHost = 'de.wikipedia.org') and (timestamp >= 20180729000000) and ((event_campaign like '%WMDE_neweditors_summer2018_1%') or (event_campaign like '%WMDE_neweditors_summer2018_2%') or (event_campaign like '%WMDE_neweditors_summer2018_3%')));\" > /home/goransm/RScripts/NewEditors/2018_SummerBannerCampaign/summerBC2018_userRegistrations_FULL.tsv"
system(command = qCommand, wait = TRUE)

### --- User edits
# - get user IDs from registered:
userReg <- read.table('/home/goransm/RScripts/NewEditors/2018_SummerBannerCampaign/summerBC2018_userRegistrations_FULL.tsv', 
                      quote = "",
                      sep = "\t",
                      header = T,
                      check.names = F,
                      stringsAsFactors = F)
userReg <- userReg %>% 
  dplyr::select(event_userId, event_isSelfMade) %>% 
  filter(event_isSelfMade == 1)
# - uids:
uid <- userReg$event_userId
# - sql query
sqlQuery <- paste('SELECT COUNT(*) as edits, rev_user FROM revision WHERE rev_user IN (',
                  paste(uid, collapse = ", "),
                  ') GROUP BY rev_user;',
                  sep = "")
mySqlCommand <- paste('mysql -h analytics-store.eqiad.wmnet dewiki -e ',
                      paste('"', sqlQuery, '" > ', sep = ""),
                      '/home/goransm/RScripts/NewEditors/2018_SummerBannerCampaign/sBC2018_userEdits_FULL.tsv', sep = "")
system(command = mySqlCommand, 
       wait = TRUE)

1. Campaign Banners and Pages

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

1.4 User Registrations

Chart 1. 4. Daily user registrations per banner

dataSet <- read.delim('/home/goransm/Work/___DataKolektiv/Projects/WikimediaDEU/_WMDE_Projects/_misc/NewEditors_Team/2018_SummerBannerCampaign/_data/summerBC2018_userRegistrations_FULL.tsv',
                    header = T,
                    check.names = F,
                    sep = "\t",
                    quote = "",
                    stringsAsFactors = F)
dataSet <- dataSet[grepl('is_bot": false', dataSet$userAgent, fixed = T), ]
dataSet$timestamp <- as.character(dataSet$timestamp)
dataSet$timestamp <- as.POSIXct(dataSet$timestamp, tz = "UTC", format = "%Y%m%d%H%M%S") 
# - CEST correction on POSIXct class, +2hours:
dataSet$timestamp <- dataSet$timestamp + 2*60*60
# - Campaign day:
dataSet$CampaignDay <- sapply(dataSet$timestamp, function(x) {
  paste(c(
    substr(x, 1,4),
    substr(x, 6,7),
    substr(x, 9,10)
    ),
    collapse = "-",
    sep = "")
})
dataSet <- filter(dataSet,
                  CampaignDay %in% c("2018-08-01", 
                                     "2018-08-02",
                                     "2018-08-03",
                                     "2018-08-04",
                                     "2018-08-05",
                                     "2018-08-06",
                                     "2018-08-07",
                                     "2018-08-08"))
userReg <- dataSet %>% 
  select(event_campaign, CampaignDay) %>% 
  group_by(CampaignDay, event_campaign) %>% 
  summarise(Count = n())
colnames(userReg)[2] <- "Banner"
# - Visualize w. {ggplot2}
ggplot(userReg, aes(x = CampaignDay,
                    y = Count,
                    group = Banner,
                    color = Banner,
                    fill = Banner,
                    label = Count)) + 
  geom_path(size = .5) + 
  geom_point(size = 1.5) +
  scale_y_continuous(labels = comma) +
  ggtitle('Summer Banner Campaign 2018: User Registrations') +
  theme_minimal() + 
  geom_text_repel(size = 3.5, show.legend = FALSE) + 
  scale_y_continuous(labels = comma) +
  theme(axis.text.x = element_text(angle = 90, size = 8)) +
  theme(plot.title = element_text(size = 10)) +
  theme(legend.title = element_blank())

Table 1. 4. Daily user registrations per banner

### --- Full Dataset (Table Report)
datatable(userReg)

Table 1. 4. 1 Banner Conversion Rates

### --- Banner Conversion Rates
totalRegs <- userReg[, 2:3] %>% 
  select(Banner, Count) %>%
  group_by(Banner) %>%
  summarise(totalReg = sum(Count))
totalRegs$Banner[grepl("WMDE_neweditors_summer2018_1", totalRegs$Banner)] <- 'B18WMDE_authors_1'
totalRegs$Banner[grepl("WMDE_neweditors_summer2018_2", totalRegs$Banner)] <- 'B18WMDE_authors_2'
totalRegs$Banner[grepl("WMDE_neweditors_summer2018_3", totalRegs$Banner)] <- 'B18WMDE_authors_3'
totalClicks$uri_query[grepl("WMDE_neweditors_summer2018_1", totalClicks$uri_query)] <- 'B18WMDE_authors_1'
totalClicks$uri_query[grepl("WMDE_neweditors_summer2018_2", totalClicks$uri_query)] <- 'B18WMDE_authors_2'
totalClicks$uri_query[grepl("WMDE_neweditors_summer2018_3", totalClicks$uri_query)] <- 'B18WMDE_authors_3'
totalClicks <- totalClicks %>% 
  group_by(uri_query) %>% 
  summarise(totalClicks = sum(totalClicks))
totalRegs <- left_join(totalRegs, totalClicks,
                       by = c("Banner" = "uri_query"))
totalRegs$`Registrations/Clicks` <- round(totalRegs$totalReg/totalRegs$totalClicks, 5)
datatable(totalRegs)

1.5 User Edits

Chart 1. 5. Edits of registered users per banner and campaign day of registration

NOTE: the Campaign Day here refers to the day when the user has registered, not the day in which the respective edits were made.

dataSet2 <- read.delim('/home/goransm/Work/___DataKolektiv/Projects/WikimediaDEU/_WMDE_Projects/_misc/NewEditors_Team/2018_SummerBannerCampaign/_data/sBC2018_userEdits_FULL.tsv',
                    header = T,
                    check.names = F,
                    sep = "\t",
                    quote = "",
                    stringsAsFactors = F)
dataSet <- left_join(dataSet, dataSet2, by = c("event_userId" = "rev_user"))
dataSet$edits[is.na(dataSet$edits)] <- 0
userEds <- dataSet %>% 
  select(event_campaign, CampaignDay, edits) %>% 
  group_by(CampaignDay, event_campaign) %>% 
  summarise(Edits = sum(edits))
colnames(userEds)[2] <- "Banner"
# - Visualize w. {ggplot2}
ggplot(userEds, aes(x = CampaignDay,
                    y = Edits,
                    group = Banner,
                    color = Banner,
                    fill = Banner,
                    label = Edits)) + 
  geom_path(size = .5) + 
  geom_point(size = 1.5) +
  scale_y_continuous(labels = comma) +
  ggtitle('Summer Banner Campaign 2018: User Edits') +
  theme_minimal() + 
  geom_text_repel(size = 3.5, show.legend = FALSE) + 
  scale_y_continuous(labels = comma) +
  theme(axis.text.x = element_text(angle = 90, size = 8)) +
  theme(plot.title = element_text(size = 10)) +
  theme(legend.title = element_blank())

Table 1. 5. Edits of registered users per banner and campaign day of registration

### --- Full Dataset (Table Report)
datatable(userEds)

Table 1. 5. 1 Edits of registered users per banner and campaign day of registration

Total number of user edits per banner:

totalEdits <- userEds %>% 
  group_by(Banner) %>% 
  summarise(Edits = sum(Edits))
datatable(totalEdits)

Table 1. 5. 2 Users reaching their 10th edit per banner

edit10 <- dataSet %>% 
  filter(edits >= 10) %>% 
  select(event_campaign) %>% 
  group_by(event_campaign) %>%
  summarise(`edit10th` = n())
datatable(edit10)

Table 1. 5. 3 Full user edits distribution

### --- Full Dataset (Table Report)
pltEdits <- as.tbl(dataSet) %>% 
  dplyr::group_by(edits) %>% 
  count()
colnames(pltEdits) <- c('Edits', 'Num.users')
knitr::kable(pltEdits, format = "html") %>%
  kable_styling(full_width = F, position = "left")
Edits Num.users
0 78
1 11
2 9
3 5
4 3
5 2
8 1
9 1
48 1

Table 1. 5. 4 Users edit categories

edits0 <- pltEdits$`Num.users`[pltEdits$Edits == 0]
edits <- sum(pltEdits$`Num.users`[pltEdits$Edits > 0])
edits1 <- sum(pltEdits$`Num.users`[pltEdits$Edits == 1])
edits2_4 <- sum(pltEdits$`Num.users`[pltEdits$Edits >= 2 & pltEdits$Edits <= 4])
edits5_10 <- sum(pltEdits$`Num.users`[pltEdits$Edits >= 5 & pltEdits$Edits <= 10])
edits10 <- sum(pltEdits$`Num.users`[pltEdits$Edits > 10])
editClasses <- data.frame(`No edits` = edits0,
                          `Edited` = edits,
                          `1 edit` = edits1,
                          `2 - 4 edits` = edits2_4,
                          `5 - 10 edits` = edits5_10, 
                          `> 10 edits` = edits10,
                          check.names = F,
                          stringsAsFactors = F)
knitr::kable(editClasses, format = "html") %>%
  kable_styling(full_width = F, position = "left")
No edits Edited 1 edit 2 - 4 edits 5 - 10 edits > 10 edits
78 33 11 17 4 1

1.6 Training Modules

This dataset is not provided yet.

LS0tCnRpdGxlOiAnU3VtbWVyIEJhbm5lciBDYW1wYWlnbiAyMDE4OiBSZXBvcnQnCmF1dGhvcjogIkdvcmFuIFMuIE1pbG92YW5vdmljLCBEYXRhIFNjaWVudGlzdCwgV01ERSIKZGF0ZTogIkF1Z3VzdCAwOSwgMjAxOCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIHRoZW1lOiBzaW1wbGV4CiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICAgIHRvY19kZXB0aDogNQogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiA1Ci0tLQoKCioqRmVlZGJhY2sqKiBzaG91bGQgYmUgc2VuZCB0byBgZ29yYW4ubWlsb3Zhbm92aWNfZXh0QHdpa2ltZWRpYS5kZWAuIAoKVGhlIGNhbXBhaWduIGlzIHJ1biBmcm9tIDIwMTgvMDgvMDEgdG8gMjAxOC8wOC8wOC4KCioqQ1VSUkVOVCBVUERBVEU6KiogQ29tcGxldGUgZGF0YXNldCBhcyBvZiAyMDE4LzA4LzA5LgoKYGBge3IsIGVjaG8gPSBGLCB3YXJuaW5nID0gJ2hpZGUnLCBtZXNzYWdlID0gRiwgcmVzdWx0cyA9ICdoaWRlJ30KIyAhZGlhZ25vc3RpY3Mgb2ZmCiMjIyAtLS0gU2V0dXAKa25pdHI6Om9wdHNfY2h1bmskc2V0KGZpZy53aWR0aCA9IDE1LCBmaWcuaGVpZ2h0ID0gOCkgCnJtKGxpc3QgPSBscygpKQpsaWJyYXJ5KHN0cmluZ3IpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkoZGF0YS50YWJsZSkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGdncmVwZWwpCmxpYnJhcnkoc2NhbGVzKQpsaWJyYXJ5KFJDb2xvckJyZXdlcikKbGlicmFyeShrYWJsZUV4dHJhKQpsaWJyYXJ5KHJtYXJrZG93bikKbGlicmFyeShrbml0cikKbGlicmFyeShEVCkKbGlicmFyeShyZXNoYXBlMikKYGBgCgojIyAwLiBEYXRhIEFjcXVpc2l0b24KCioqTk9URToqKiB0aGUgRGF0YSBBY3F1aXNpdGlvbiBjb2RlIGNodW5rIGlzIG5vdCBmdWxseSByZXByb2R1Y2libGUgZnJvbSB0aGlzIFJlcG9ydC4gVGhlIGRhdGEgYXJlIGNvbGxlY3RlZCBieSBydW5uaW5nIHRoZSBzY3JpcHQgYFN1bW1lckJDMjAxOF9EYWlseVVwZGF0ZV9QUk9EVUNUSU9OLlJgIG9uIHN0YXQxMDA1LmVxaWFkLndtbmV0LCBjb2xsZWN0aW5nIHRoZSBkYXRhIGFzIGAudHN2YCBhbmQgYC5jc3ZgIGZpbGVzLCBjb3B5aW5nIG1hbnVhbGx5LCBhbmQgcHJvY2Vzc2luZyBsb2NhbGx5LiAKCiMjIyAwLjEgRGFpbHkgVXBkYXRlCgpgYGB7ciwgZWNobyA9IFQsIGV2YWwgPSBGfQoKIyAtIHdsZV8yMDE4X2RlCgojIyMgLS0tIFdNREUgU3ByaW5nIEJhbm5lciBDYW1wYWlnbiAyMDE4CiMjIyAtLS0gRGFpbHkgVXBkYXRlCgpybShsaXN0ID0gbHMoKSkKCiMjIyAtLS0gTGlicmFyaWVzCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkoc3RyaW5ncikKbGlicmFyeShkYXRhLnRhYmxlKQoKIyMjIC0tLSBEaXJlY3RvcmllcwpvdXREaXIgPC0gJy9ob21lL2dvcmFuc20vUlNjcmlwdHMvTmV3RWRpdG9ycy8yMDE4X1N1bW1lckJhbm5lckNhbXBhaWduLycKc2V0d2Qob3V0RGlyKQoKIyMjIC0tLSBHZW5lcmFsIEluZm86CiMgRmlyc3QgQmFubmVyIChodHRwczovL2RlLndpa2lwZWRpYS5vcmcvd2lraS9XaWtpcGVkaWE6SGF1cHRzZWl0ZT9iYW5uZXI9QjE4V01ERV9hdXRob3JzXzAyXzE4MDgwMV8xJmZvcmNlPTEpCiMgUmVnaXN0cmF0aW9uIE5hbWU6IFRlc3Nzc3N0dHR0dAojIENyZWF0ZWQ6IE1vLCAzMC4wNy4yMDE4IGFyb3VuZCAxNTo0MgojIAojIFNlY29uZCBCYW5uZXIgKGh0dHBzOi8vZGUud2lraXBlZGlhLm9yZy93aWtpL1dpa2lwZWRpYTpIYXVwdHNlaXRlP2Jhbm5lcj1CMThXTURFX2F1dGhvcnNfMDJfMTgwODAxXzImZm9yY2U9MSkKIyBSZWdpc3RyYXRpb24gbmFtZTogVGVzc3NzdHR0dHQKIyBDcmVhdGVkOiBNbywgMzAuMDcuMjAxOCBhcm91bmQgMTU6NDUKIyAKIyBUaGlyZCBCYW5uZXIgKGh0dHBzOi8vZGUud2lraXBlZGlhLm9yZy93aWtpL1dpa2lwZWRpYTpIYXVwdHNlaXRlP2Jhbm5lcj1CMThXTURFX2F1dGhvcnNfMDJfMTgwODAxXzMmZm9yY2U9MSkKIyBSZWdpc3RyYXRpb24gbmFtZTogVHR0dGVlc3Nzc3R0CiMgQ3JlYXRlZDogTW8sIDMwLjA3LjIwMTggYXJvdW5kIDE1OjQ1CgojIyMgLS0tIGJhbm5lciBuYW1lcyAoL2JlYWNvbi9pbXByZXNzaW9uKToKIyAtIEIxOFdNREVfYXV0aG9yc18wMl8xODA4MDFfMQojIC0gQjE4V01ERV9hdXRob3JzXzAyXzE4MDgwMV8yCiMgLSBCMThXTURFX2F1dGhvcnNfMDJfMTgwODAxXzMKCiMjIyAtLS0gY2FtcGFpZ24gdGFncwojIC0gV01ERV9uZXdlZGl0b3JzX3N1bW1lcjIwMThfMQojIC0gV01ERV9uZXdlZGl0b3JzX3N1bW1lcjIwMThfMgojIC0gV01ERV9uZXdlZGl0b3JzX3N1bW1lcjIwMThfMwoKIyMjIC0tLSBsYW5kaW5ncGFnZSBpbmNsdWRpbmcgdGhlIGNhbXBhaWduIHRhZyBhbmQgYW5jaG9yCiMgLSBCYW5uZXIgMTogaHR0cHM6Ly9kZS53aWtpcGVkaWEub3JnL3dpa2kvV2lraXBlZGlhOldpa2ltZWRpYV9EZXV0c2NobGFuZC9OZXVlX0VocmVuYW10bGljaGUvRkFRP2NhbXBhaWduPVdNREVfbmV3ZWRpdG9yc19zdW1tZXIyMDE4XzEjV2VyLWRhcmYtc2NocmVpYmVuCiMgLSBCYW5uZXIgMjogaHR0cHM6Ly9kZS53aWtpcGVkaWEub3JnL3dpa2kvV2lraXBlZGlhOldpa2ltZWRpYV9EZXV0c2NobGFuZC9OZXVlX0VocmVuYW10bGljaGUvRkFRP2NhbXBhaWduPVdNREVfbmV3ZWRpdG9yc19zdW1tZXIyMDE4XzIjV2lraXBlZGlhLUJ1ZXJvCiMgLSBCYW5uZXIgMzogaHR0cHM6Ly9kZS53aWtpcGVkaWEub3JnL3dpa2kvV2lraXBlZGlhOldpa2ltZWRpYV9EZXV0c2NobGFuZC9OZXVlX0VocmVuYW10bGljaGUvRkFRP2NhbXBhaWduPVdNREVfbmV3ZWRpdG9yc19zdW1tZXIyMDE4XzMjU2NodXR6LXZvci1NaXNzYnJhdWNoCiMgLSBTZWNvbmQgbGFuZGluZyBwYWdlOiBodHRwczovL2RlLndpa2lwZWRpYS5vcmcvd2lraS9XaWtpcGVkaWE6V2lraW1lZGlhX0RldXRzY2hsYW5kL0xlcm5lV2lraXBlZGlhCgojIC0gVXBkYXRlIG9uIChSZW1pbmRlcjogc3RhdDEwMDUgdGltZSBpcyBVVEMpOiB0b2RheSBtaW51cyBvbmUgZGF5CnRvZGF5IDwtIHN0cnNwbGl0KAogIHN0cnNwbGl0KAogICAgYXMuY2hhcmFjdGVyKGFzLlBPU0lYY3QoU3lzLnRpbWUoKSkgLSAyNCo2MCo2MCksCiAgICBzcGxpdCA9ICIgIiwKICAgIGZpeGVkID0gVFJVRSlbWzFdXVsxXSwKICBzcGxpdCA9ICItIiwKICBmaXhlZCA9IFRSVUUpW1sxXV0KdG9kYXkgPC0gYXMubGlzdCh0b2RheSkKbmFtZXModG9kYXkpIDwtIGMoJ3llYXInLCAnbW9udGgnLCAnZGF5JykKCiMgLSBjb25zdHJ1Y3Qgd21mLndlYnJlcXVlc3QgeWVhci9tb250aC9kYXkvaG91ciBjb25kaXRpb24KIyAtIGZvciB0b2RheToKZGF0ZUNvbmRpdGlvbiA8LSBwYXN0ZTAoIigoeWVhciA9ICIsIHRvZGF5JHllYXIsCiAgICAgICAgICAgICAgICAgICAgICAgICIgQU5EIG1vbnRoID0gIiwgdG9kYXkkbW9udGgsCiAgICAgICAgICAgICAgICAgICAgICAgICIgQU5EIGRheSA9ICIsIGFzLmludGVnZXIodG9kYXkkZGF5KSAtIDEsCiAgICAgICAgICAgICAgICAgICAgICAgICIgQU5EIChob3VyID0gMjIgT1IgaG91ciA9IDIzKSkiLAogICAgICAgICAgICAgICAgICAgICAgICAiIE9SICIsCiAgICAgICAgICAgICAgICAgICAgICAgICIoeWVhciA9ICIsIHRvZGF5JHllYXIsCiAgICAgICAgICAgICAgICAgICAgICAgICIgQU5EIG1vbnRoID0gIiwgdG9kYXkkbW9udGgsCiAgICAgICAgICAgICAgICAgICAgICAgICIgQU5EIGRheSA9ICIsIHRvZGF5JGRheSwKICAgICAgICAgICAgICAgICAgICAgICAgIiBBTkQgKGhvdXIgPj0gMCBPUiBob3VyIDwgMjIpKSkiCiAgICAgICAgICAgICAgICAgICAgICAgICkKCiMjIyAtLS0gQ29sbGVjdCBCYW5uZXIgSW1wcmVzc2lvbnMgZm9yIFVwZGF0ZTogSGl2ZVFMCnEgPC0gcGFzdGUoCiAgIlVTRSB3bWY7CiAgU0VMRUNUIHVyaV9xdWVyeSBGUk9NIHdlYnJlcXVlc3QKICBXSEVSRSB1cmlfaG9zdCA9ICdkZS53aWtpcGVkaWEub3JnJwogIEFORCB1cmlfcGF0aCA9ICcvYmVhY29uL2ltcHJlc3Npb24nCiAgQU5EICIsCiAgZGF0ZUNvbmRpdGlvbiwKICAiIEFORCAoKHVyaV9xdWVyeSBMSUtFICclQjE4V01ERV9hdXRob3JzXzAyXzE4MDgwMV8xJScpIE9SCiAgICAodXJpX3F1ZXJ5IExJS0UgJyVCMThXTURFX2F1dGhvcnNfMDJfMTgwODAxXzIlJykgT1IKICAgICh1cmlfcXVlcnkgTElLRSAnJUIxOFdNREVfYXV0aG9yc18wMl8xODA4MDFfMyUnKSk7IiwKICBzZXAgPSAiIikKIyAtIHdyaXRlIGhxbAp3cml0ZShxLCAnc3VtbWVyQkMyMDE4X0Jhbm5lckltcHJlc3Npb25zRGFpbHkuaHFsJykKIyAtIHByZXBhcmUgb3V0cHV0IGZpbGU6CmZpbGVOYW1lIDwtICdzYmMyMDE4X0Jhbm5lckltcHJlc3Npb25zRGFpbHkudHN2JwojIC0gZXhlY3V0ZSBocWwgc2NyaXB0OgpoaXZlQXJncyA8LSAnYmVlbGluZSAtLXZlcmJvc2U9dHJ1ZSAtZicKaGl2ZUlucHV0IDwtIHBhc3RlMCgnc3VtbWVyQkMyMDE4X0Jhbm5lckltcHJlc3Npb25zRGFpbHkuaHFsID4gJywgZmlsZU5hbWUpCiMgLSBjb21tYW5kOgpoaXZlQ29tbWFuZCA8LSBwYXN0ZShoaXZlQXJncywgaGl2ZUlucHV0KQpzeXN0ZW0oY29tbWFuZCA9IGhpdmVDb21tYW5kLCB3YWl0ID0gVFJVRSkKCiMjIyAtLS0gQ29sbGVjdCBQYWdldmlld3MgPT0gQmFubmVyIGNsaWNrcyBmb3IgVXBkYXRlOiBIaXZlUUwKIyBodHRwczovL2RlLndpa2lwZWRpYS5vcmcvd2lraS9XaWtpcGVkaWE6V2lraW1lZGlhX0RldXRzY2hsYW5kL0xlcm5lV2lraXBlZGlhCnEgPC0gcGFzdGUoCiAgIlVTRSB3bWY7CiAgU0VMRUNUIHVyaV9wYXRoLCB1cmlfcXVlcnksIHJlZmVyZXIgRlJPTSB3ZWJyZXF1ZXN0CiAgV0hFUkUgdXJpX2hvc3QgPSAnZGUud2lraXBlZGlhLm9yZycKICBBTkQgKCh1cmlfcGF0aCA9ICcvd2lraS9XaWtpcGVkaWE6V2lraW1lZGlhX0RldXRzY2hsYW5kL05ldWVfRWhyZW5hbXRsaWNoZS9GQVEnIEFORCB1cmlfcXVlcnkgTElLRSAnJWNhbXBhaWduPVdNREVfbmV3ZWRpdG9yc19zdW1tZXIyMDE4JScpCiAgT1IgKHVyaV9wYXRoID0gJy93aWtpL1dpa2lwZWRpYTpXaWtpbWVkaWFfRGV1dHNjaGxhbmQvTGVybmVXaWtpcGVkaWEnKSkgCiAgQU5EICIsIGRhdGVDb25kaXRpb24sCiAgIiA7IiwKICBzZXAgPSAiIikKIyAtIHdyaXRlIGhxbAp3cml0ZShxLCAnc3VtbWVyQkMyMDE4X1BhZ2VWaWV3c0RhaWx5LmhxbCcpCiMgLSBwcmVwYXJlIG91dHB1dCBmaWxlOgpmaWxlTmFtZSA8LSAnc2JjMjAxOF9QYWdlVmlld3NEYWlseS50c3YnCiMgLSBleGVjdXRlIGhxbCBzY3JpcHQ6CmhpdmVBcmdzIDwtICdiZWVsaW5lIC0tdmVyYm9zZT10cnVlIC1mJwpoaXZlSW5wdXQgPC0gcGFzdGUwKCdzdW1tZXJCQzIwMThfUGFnZVZpZXdzRGFpbHkuaHFsID4gJywgZmlsZU5hbWUpCiMgLSBjb21tYW5kOgpoaXZlQ29tbWFuZCA8LSBwYXN0ZShoaXZlQXJncywgaGl2ZUlucHV0KQpzeXN0ZW0oY29tbWFuZCA9IGhpdmVDb21tYW5kLCB3YWl0ID0gVFJVRSkKCiMjIyAtLS0gQ29sbGVjdCBVc2UgUmVnaXN0cmF0aW9ucyBmb3IgVXBkYXRlOiBTUUwKIyAtIFNlcnZlclNpZGVBY2NvdW50Q3JlYXRpb25fMTc3MTkyMzcgc2NoZW1hCnFDb21tYW5kIDwtICJteXNxbCAtLWRlZmF1bHRzLWZpbGU9L2V0Yy9teXNxbC9jb25mLmQvYW5hbHl0aWNzLXJlc2VhcmNoLWNsaWVudC5jbmYgLWggYW5hbHl0aWNzLXNsYXZlLmVxaWFkLndtbmV0IC1BIC1lIFwic2VsZWN0ICogZnJvbSBsb2cuU2VydmVyU2lkZUFjY291bnRDcmVhdGlvbl8xNzcxOTIzNyB3aGVyZSAoKHdlYkhvc3QgPSAnZGUud2lraXBlZGlhLm9yZycpIGFuZCAodGltZXN0YW1wID49IDIwMTgwNzI5MDAwMDAwKSBhbmQgKChldmVudF9jYW1wYWlnbiBsaWtlICclV01ERV9uZXdlZGl0b3JzX3N1bW1lcjIwMThfMSUnKSBvciAoZXZlbnRfY2FtcGFpZ24gbGlrZSAnJVdNREVfbmV3ZWRpdG9yc19zdW1tZXIyMDE4XzIlJykgb3IgKGV2ZW50X2NhbXBhaWduIGxpa2UgJyVXTURFX25ld2VkaXRvcnNfc3VtbWVyMjAxOF8zJScpKSk7XCIgPiAvaG9tZS9nb3JhbnNtL1JTY3JpcHRzL05ld0VkaXRvcnMvMjAxOF9TdW1tZXJCYW5uZXJDYW1wYWlnbi9zdW1tZXJCQzIwMThfdXNlclJlZ2lzdHJhdGlvbnMudHN2IgpzeXN0ZW0oY29tbWFuZCA9IHFDb21tYW5kLCB3YWl0ID0gVFJVRSkKCiMjIyAtLS0gQ29sbGVjdCBCYW5uZXIgRXZlbnRzIGZvciBVcGRhdGU6IFNRTAojIC0gV01ERUJhbm5lckV2ZW50c18xODE5Mzk0OCBzY2hlbWEKcUNvbW1hbmQgPC0gIm15c3FsIC0tZGVmYXVsdHMtZmlsZT0vZXRjL215c3FsL2NvbmYuZC9hbmFseXRpY3MtcmVzZWFyY2gtY2xpZW50LmNuZiAtaCBhbmFseXRpY3Mtc2xhdmUuZXFpYWQud21uZXQgLUEgLWUgXCJzZWxlY3QgKiBmcm9tIGxvZy5XTURFQmFubmVyRXZlbnRzXzE4MTkzOTQ4IHdoZXJlIHRpbWVzdGFtcCA+PSAyMDE4MDcyOTAwMDAwMDtcIiA+IC9ob21lL2dvcmFuc20vUlNjcmlwdHMvTmV3RWRpdG9ycy8yMDE4X1N1bW1lckJhbm5lckNhbXBhaWduL3N1bW1lckJDMjAxOF9iYW5uZXJFdmVudHMudHN2IgpzeXN0ZW0oY29tbWFuZCA9IHFDb21tYW5kLCB3YWl0ID0gVFJVRSkKCgojIyMgLS0tIFByZXBhcmUgZm9yIHJlcG90aW5nCgojIC0gQmFubmVyIEltcHJlc3Npb25zCmJJbXBEYXRhIDwtIHJlYWRMaW5lcygnc2JjMjAxOF9CYW5uZXJJbXByZXNzaW9uc0RhaWx5LnRzdicsIG4gPSAtMSkKYkltcERhdGEgPC0gYkltcERhdGFbOToobGVuZ3RoKGJJbXBEYXRhKSAtIDIpXQpiSW1wRGF0YSA8LSBiSW1wRGF0YVstMV0KYkltcERhdGEgPC0gZGF0YS5mcmFtZShkYXQgPSBiSW1wRGF0YSwgc3RyaW5nc0FzRmFjdG9ycyA9IEYpCmJhbm5lckEgPC0gbGVuZ3RoKHdoaWNoKGdyZXBsKCJiYW5uZXI9QjE4V01ERV9hdXRob3JzXzAyXzE4MDgwMV8xIiwgYkltcERhdGEkZGF0LCBmaXhlZCA9IFQpKSkKYmFubmVyQiA8LSBsZW5ndGgod2hpY2goZ3JlcGwoImJhbm5lcj1CMThXTURFX2F1dGhvcnNfMDJfMTgwODAxXzIiLCBiSW1wRGF0YSRkYXQsIGZpeGVkID0gVCkpKQpiYW5uZXJDIDwtIGxlbmd0aCh3aGljaChncmVwbCgiYmFubmVyPUIxOFdNREVfYXV0aG9yc18wMl8xODA4MDFfMyIsIGJJbXBEYXRhJGRhdCwgZml4ZWQgPSBUKSkpCkRhaWx5QmFubmVySW1wcmVzc2lvbnMgPC0gZGF0YS5mcmFtZSgKICBCYW5uZXIgPSBjKCdCMThXTURFX2F1dGhvcnNfMScsICdCMThXTURFX2F1dGhvcnNfMicsICdCMThXTURFX2F1dGhvcnNfMycpLAogIENvdW50ID0gYyhiYW5uZXJBLCBiYW5uZXJCLCBiYW5uZXJDKSwKICBDYW1wYWlnbkRheSA9IHJlcChwYXN0ZTAodG9kYXksIGNvbGxhcHNlID0gIi0iLCBzZXAgPSAiIiksIDMpCikKRGFpbHlCYW5uZXJJbXByZXNzaW9ucyRDb3VudCA8LSBEYWlseUJhbm5lckltcHJlc3Npb25zJENvdW50Ly4wMQojIC0gRGFpbHlCYW5uZXJJbXByZXNzaW9ucwpsRiA8LSBsaXN0LmZpbGVzKCkKaWYgKCdEYWlseUJhbm5lckltcHJlc3Npb25zLmNzdicgJWluJSBsRikgewogIGRQUyA8LSByZWFkLmNzdignRGFpbHlCYW5uZXJJbXByZXNzaW9ucy5jc3YnLAogICAgICAgICAgICAgICAgICBoZWFkZXIgPSBULAogICAgICAgICAgICAgICAgICByb3cubmFtZXMgPSAxKQogIERhaWx5QmFubmVySW1wcmVzc2lvbnMgPC0gcmJpbmQoZFBTLCBEYWlseUJhbm5lckltcHJlc3Npb25zKQogIHdyaXRlLmNzdihEYWlseUJhbm5lckltcHJlc3Npb25zLCAnRGFpbHlCYW5uZXJJbXByZXNzaW9ucy5jc3YnKQp9IGVsc2UgewogIHdyaXRlLmNzdihEYWlseUJhbm5lckltcHJlc3Npb25zLCAnRGFpbHlCYW5uZXJJbXByZXNzaW9ucy5jc3YnKQp9CgojIC0gUGFnZXZpZXdzCnBhZ2VWaWV3cyA8LSByZWFkTGluZXMoJ3NiYzIwMThfUGFnZVZpZXdzRGFpbHkudHN2JywgbiA9IC0xKQpwYWdlVmlld3MgPC0gcGFnZVZpZXdzWzg6KGxlbmd0aChwYWdlVmlld3MpIC0gMildCmhlYWRlciA9IHBhZ2VWaWV3c1sxXQpwYWdlVmlld3MgPC0gcGFnZVZpZXdzWy0xXQpoZWFkZXIgPC0gdW5saXN0KHN0cnNwbGl0KGhlYWRlciwgIlx0IilbWzFdXSkKcGFnZVZpZXdzIDwtIGRhdGEuZnJhbWUoZGF0ID0gcGFnZVZpZXdzLCBzdHJpbmdzQXNGYWN0b3JzID0gRikKcGFnZVZpZXdzIDwtIHNlcGFyYXRlKHBhZ2VWaWV3cywKICAgICAgICAgICAgICAgICAgICAgIGRhdCwKICAgICAgICAgICAgICAgICAgICAgIGludG8gPSBjKCd1cmlfcGF0aCcsICd1cmlfcXVlcnknLCAncmVmZXJlcicpLAogICAgICAgICAgICAgICAgICAgICAgc2VwID0gIlx0IikKZGFpbHlQYWdldmlld3NTZXQgPC0gcGFnZVZpZXdzICU+JSAKICBmaWx0ZXIoZ3JlcGwoJ2NhbXBhaWduPVdNREVfbmV3ZWRpdG9yc19zdW1tZXIyMDE4JywgdXJpX3F1ZXJ5KSB8IAogICAgICAgICAgIGdyZXBsKCcvd2lraS9XaWtpcGVkaWE6V2lraW1lZGlhX0RldXRzY2hsYW5kL0xlcm5lV2lraXBlZGlhJywgdXJpX3BhdGgpKSAlPiUKICBncm91cF9ieSh1cmlfcXVlcnksIHVyaV9wYXRoKSAlPiUKICBzdW1tYXJpc2UoQ291bnQgPSBuKCkpCmRhaWx5UGFnZXZpZXdzU2V0JENhbXBhaWduRGF5IDwtIHBhc3RlKHVubGlzdCh0b2RheSksIGNvbGxhcHNlID0gIi0iLCBzZXAgPSAiIikKIyAtIERhaWx5UGFnZXZpZXdzCmxGIDwtIGxpc3QuZmlsZXMoKQppZiAoJ0RhaWx5UGFnZXZpZXdzLmNzdicgJWluJSBsRikgewogIGRQUyA8LSByZWFkLmNzdignRGFpbHlQYWdldmlld3MuY3N2JywKICAgICAgICAgICAgICAgICAgaGVhZGVyID0gVCwKICAgICAgICAgICAgICAgICAgcm93Lm5hbWVzID0gMSkKICBkYWlseVBhZ2V2aWV3c1NldCA8LSByYmluZChkUFMsIGFzLmRhdGEuZnJhbWUoZGFpbHlQYWdldmlld3NTZXQpKQogIHdyaXRlLmNzdihkYWlseVBhZ2V2aWV3c1NldCwgJ0RhaWx5UGFnZXZpZXdzLmNzdicpCn0gZWxzZSB7CiAgd3JpdGUuY3N2KGRhaWx5UGFnZXZpZXdzU2V0LCAnRGFpbHlQYWdldmlld3MuY3N2JykKfQoKIyAtIFVzZXIgcmVnaXN0cmF0aW9ucwp1c2VyUmVnaXN0cmF0aW9ucyA8LSByZWFkLmRlbGltKCdzdW1tZXJCQzIwMThfdXNlclJlZ2lzdHJhdGlvbnMudHN2JywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VwID0gIlx0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoZWFkZXIgPSBULAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHF1b3RlID0gIiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQp1c2VyUmVnaXN0cmF0aW9ucyA8LSB1c2VyUmVnaXN0cmF0aW9uc1tncmVwbCgnaXNfYm90IjogZmFsc2UnLCB1c2VyUmVnaXN0cmF0aW9ucyR1c2VyQWdlbnQsIGZpeGVkID0gVCksIF0KdXNlclJlZ2lzdHJhdGlvbnMkdGltZXN0YW1wIDwtIGFzLmNoYXJhY3Rlcih1c2VyUmVnaXN0cmF0aW9ucyR0aW1lc3RhbXApCnVzZXJSZWdpc3RyYXRpb25zJHRpbWVzdGFtcCA8LSBhcy5QT1NJWGN0KHVzZXJSZWdpc3RyYXRpb25zJHRpbWVzdGFtcCwgdHogPSAiVVRDIiwgZm9ybWF0ID0gIiVZJW0lZCVIJU0lUyIpIAojIC0gQ0VTVCBjb3JyZWN0aW9uIG9uIFBPU0lYY3QgY2xhc3MsICsyaG91cnM6CnVzZXJSZWdpc3RyYXRpb25zJHRpbWVzdGFtcCA8LSB1c2VyUmVnaXN0cmF0aW9ucyR0aW1lc3RhbXAgKyAyKjYwKjYwCiMgLSB3cmFuZ2xlCnVzZXJSZWdpc3RyYXRpb25zJENhbXBhaWduRGF5IDwtIHNhcHBseSh1c2VyUmVnaXN0cmF0aW9ucyR0aW1lc3RhbXAsIGZ1bmN0aW9uKHgpIHsKICBwYXN0ZShjKAogICAgc3Vic3RyKHgsIDEsNCksCiAgICBzdWJzdHIoeCwgNiw3KSwKICAgIHN1YnN0cih4LCA5LDEwKQogICAgKSwKICAgIGNvbGxhcHNlID0gIi0iLAogICAgc2VwID0gIiIpCn0pCnVzZXJSZWdpc3RyYXRpb25zIDwtIHVzZXJSZWdpc3RyYXRpb25zW3doaWNoKHVzZXJSZWdpc3RyYXRpb25zJENhbXBhaWduRGF5ICVpbiUgcGFzdGUodG9kYXksIGNvbGxhcHNlID0gIi0iLCBzZXAgPSAiIikpLCBdCmRhaWx5VXNlclJlZ1NldCA8LSB1c2VyUmVnaXN0cmF0aW9ucyAlPiUKICBzZWxlY3QoZXZlbnRfY2FtcGFpZ24pICU+JQogIGdyb3VwX2J5KGV2ZW50X2NhbXBhaWduKSAlPiUKICBzdW1tYXJpc2UoQ291bnQgPSBuKCkpCmRhaWx5VXNlclJlZ1NldCRDYW1wYWlnbkRheSA8LSBwYXN0ZSh1bmxpc3QodG9kYXkpLCBjb2xsYXBzZSA9ICItIiwgc2VwID0gIiIpCiMgLSBEYWlseSBVc2VyIFJlZ2lzdHJhdGlvbnMKbEYgPC0gbGlzdC5maWxlcygpCmlmICgnZGFpbHlVc2VyUmVnaXN0cmF0aW9ucy5jc3YnICVpbiUgbEYpIHsKICBkUFMgPC0gcmVhZC5jc3YoJ2RhaWx5VXNlclJlZ2lzdHJhdGlvbnMuY3N2JywgCiAgICAgICAgICAgICAgICAgIGhlYWRlciA9IFQsIAogICAgICAgICAgICAgICAgICByb3cubmFtZXMgPSAxKQogIGRhaWx5VXNlclJlZ1NldCA8LSByYmluZChkUFMsIGRhaWx5VXNlclJlZ1NldCkKICB3cml0ZS5jc3YoZGFpbHlVc2VyUmVnU2V0LCAnZGFpbHlVc2VyUmVnaXN0cmF0aW9ucy5jc3YnKQp9IGVsc2UgewogIHdyaXRlLmNzdihkYWlseVVzZXJSZWdTZXQsICdkYWlseVVzZXJSZWdpc3RyYXRpb25zLmNzdicpCn0KYGBgCgojIyMgMC4xIFBvc3QtQ2FtcGFpZ24gQW5hbHl0aWNzCgoqKk5PVEU6KiogVHJhaW5pbmcgTW9kdWxlIGRhdGEgYXJlIG9idGFpbmVkIGRpcmVjdGx5IGZyb20gdGhlIGFwcGxpY2F0aW9uIG1haW50YWluZXIuIFRoZSBmb2xsb3dpbmcgY29kZSByZXRyaWV2ZXMgYWxsIHVzZXIgcmVnaXN0cmF0aW9ucyBhbmQgZWRpdHMuCgpgYGB7ciwgZWNobyA9IFQsIGV2YWwgPSBGfQojIyMgLS0tIFVzZXIgcmVnaXN0cmF0aW9ucwoKIyMjIC0tLSBMaWJyYXJpZXMKbGlicmFyeShkcGx5cikKbGlicmFyeSh0aWR5cikKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KGRhdGEudGFibGUpCgojIC0gU2VydmVyU2lkZUFjY291bnRDcmVhdGlvbl81NDg3MzQ1CnFDb21tYW5kIDwtICJteXNxbCAtLWRlZmF1bHRzLWZpbGU9L2V0Yy9teXNxbC9jb25mLmQvYW5hbHl0aWNzLXJlc2VhcmNoLWNsaWVudC5jbmYgLWggYW5hbHl0aWNzLXNsYXZlLmVxaWFkLndtbmV0IC1BIC1lIFwic2VsZWN0ICogZnJvbSBsb2cuU2VydmVyU2lkZUFjY291bnRDcmVhdGlvbl8xNzcxOTIzNyB3aGVyZSAoKHdlYkhvc3QgPSAnZGUud2lraXBlZGlhLm9yZycpIGFuZCAodGltZXN0YW1wID49IDIwMTgwNzI5MDAwMDAwKSBhbmQgKChldmVudF9jYW1wYWlnbiBsaWtlICclV01ERV9uZXdlZGl0b3JzX3N1bW1lcjIwMThfMSUnKSBvciAoZXZlbnRfY2FtcGFpZ24gbGlrZSAnJVdNREVfbmV3ZWRpdG9yc19zdW1tZXIyMDE4XzIlJykgb3IgKGV2ZW50X2NhbXBhaWduIGxpa2UgJyVXTURFX25ld2VkaXRvcnNfc3VtbWVyMjAxOF8zJScpKSk7XCIgPiAvaG9tZS9nb3JhbnNtL1JTY3JpcHRzL05ld0VkaXRvcnMvMjAxOF9TdW1tZXJCYW5uZXJDYW1wYWlnbi9zdW1tZXJCQzIwMThfdXNlclJlZ2lzdHJhdGlvbnNfRlVMTC50c3YiCnN5c3RlbShjb21tYW5kID0gcUNvbW1hbmQsIHdhaXQgPSBUUlVFKQoKIyMjIC0tLSBVc2VyIGVkaXRzCiMgLSBnZXQgdXNlciBJRHMgZnJvbSByZWdpc3RlcmVkOgp1c2VyUmVnIDwtIHJlYWQudGFibGUoJy9ob21lL2dvcmFuc20vUlNjcmlwdHMvTmV3RWRpdG9ycy8yMDE4X1N1bW1lckJhbm5lckNhbXBhaWduL3N1bW1lckJDMjAxOF91c2VyUmVnaXN0cmF0aW9uc19GVUxMLnRzdicsIAogICAgICAgICAgICAgICAgICAgICAgcXVvdGUgPSAiIiwKICAgICAgICAgICAgICAgICAgICAgIHNlcCA9ICJcdCIsCiAgICAgICAgICAgICAgICAgICAgICBoZWFkZXIgPSBULAogICAgICAgICAgICAgICAgICAgICAgY2hlY2submFtZXMgPSBGLAogICAgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IEYpCnVzZXJSZWcgPC0gdXNlclJlZyAlPiUgCiAgZHBseXI6OnNlbGVjdChldmVudF91c2VySWQsIGV2ZW50X2lzU2VsZk1hZGUpICU+JSAKICBmaWx0ZXIoZXZlbnRfaXNTZWxmTWFkZSA9PSAxKQojIC0gdWlkczoKdWlkIDwtIHVzZXJSZWckZXZlbnRfdXNlcklkCiMgLSBzcWwgcXVlcnkKc3FsUXVlcnkgPC0gcGFzdGUoJ1NFTEVDVCBDT1VOVCgqKSBhcyBlZGl0cywgcmV2X3VzZXIgRlJPTSByZXZpc2lvbiBXSEVSRSByZXZfdXNlciBJTiAoJywKICAgICAgICAgICAgICAgICAgcGFzdGUodWlkLCBjb2xsYXBzZSA9ICIsICIpLAogICAgICAgICAgICAgICAgICAnKSBHUk9VUCBCWSByZXZfdXNlcjsnLAogICAgICAgICAgICAgICAgICBzZXAgPSAiIikKbXlTcWxDb21tYW5kIDwtIHBhc3RlKCdteXNxbCAtaCBhbmFseXRpY3Mtc3RvcmUuZXFpYWQud21uZXQgZGV3aWtpIC1lICcsCiAgICAgICAgICAgICAgICAgICAgICBwYXN0ZSgnIicsIHNxbFF1ZXJ5LCAnIiA+ICcsIHNlcCA9ICIiKSwKICAgICAgICAgICAgICAgICAgICAgICcvaG9tZS9nb3JhbnNtL1JTY3JpcHRzL05ld0VkaXRvcnMvMjAxOF9TdW1tZXJCYW5uZXJDYW1wYWlnbi9zQkMyMDE4X3VzZXJFZGl0c19GVUxMLnRzdicsIHNlcCA9ICIiKQpzeXN0ZW0oY29tbWFuZCA9IG15U3FsQ29tbWFuZCwgCiAgICAgICB3YWl0ID0gVFJVRSkKYGBgCgojIyAxLiBDYW1wYWlnbiBCYW5uZXJzIGFuZCBQYWdlcwoKVGhpcyBzZWN0aW9uIHByZXNlbnRzIGFsbCBkYXRhIGFuZCBzdGF0aXN0aWNzIG9uIHRoZSBjYW1wYWlnbiBiYW5uZXJzIGFuZCBwYWdlcy4KCiMjIyAxLjEgQmFubmVyIEltcHJlc3Npb25zCgoqKkNoYXJ0IDEuIDEuIERhaWx5IEJhbm5lciBJbXByZXNzaW9ucyAqKgoKYGBge3IgZWNobyA9IFQsIGV2YWwgPSBULCB3YXJuaW5nID0gJ2hpZGUnLCBtZXNzYWdlID0gRkFMU0V9CmRhdGFTZXQgPC0gcmVhZC5jc3YoJy9ob21lL2dvcmFuc20vV29yay9fX19EYXRhS29sZWt0aXYvUHJvamVjdHMvV2lraW1lZGlhREVVL19XTURFX1Byb2plY3RzL19taXNjL05ld0VkaXRvcnNfVGVhbS8yMDE4X1N1bW1lckJhbm5lckNhbXBhaWduL19kYXRhL0RhaWx5QmFubmVySW1wcmVzc2lvbnMuY3N2JywKICAgICAgICAgICAgICAgICAgICBoZWFkZXIgPSBULAogICAgICAgICAgICAgICAgICAgIHJvdy5uYW1lcyA9IDEsCiAgICAgICAgICAgICAgICAgICAgY2hlY2submFtZXMgPSBGLAogICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQoKIyAtIGJhbm5lciBpbXByZXNzaW9uIHJhdGUgPT0gLjAxCiMgLSBkYXRhU2V0JENvdW50IDwtIGRhdGFTZXQkQ291bnQgKiAoMS8uMDEpCgojIC0gVmlzdWFsaXplIHcuIHtnZ3Bsb3QyfQpnZ3Bsb3QoZGF0YVNldCwgYWVzKHggPSBDYW1wYWlnbkRheSwKICAgICAgICAgICAgICAgICAgICB5ID0gQ291bnQsCiAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSBCYW5uZXIsCiAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBCYW5uZXIsCiAgICAgICAgICAgICAgICAgICAgZmlsbCA9IEJhbm5lciwKICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IENvdW50LAogICAgICAgICAgICAgICAgICAgICkpICsgCiAgZ2VvbV9wYXRoKHNpemUgPSAuNSkgKyAKICBnZW9tX3BvaW50KHNpemUgPSAxLjUpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEpICsKICBnZ3RpdGxlKCdTdW1tZXIgQmFubmVyIENhbXBhaWduIDIwMTg6IEJhbm5lciBJbXByZXNzaW9ucycpICsKICB0aGVtZV9taW5pbWFsKCkgKyAKICBnZW9tX3RleHRfcmVwZWwoc2l6ZSA9IDMuNSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBzaXplID0gOCkpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCkpICsKICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCmBgYAoKKipUYWJsZSAxLiAxLiBEYWlseSBCYW5uZXIgSW1wcmVzc2lvbnMgKioKCmBgYHtyIGVjaG8gPSBULCB3YXJuaW5nID0gJ2hpZGUnLCBtZXNzYWdlID0gRn0KIyMjIC0tLSBGdWxsIERhdGFzZXQgKFRhYmxlIFJlcG9ydCkKZGF0YXRhYmxlKGRhdGFTZXQpCmBgYAoKKipUYWJsZSAxLiAxLiAxIFRvdGFsIEJhbm5lciBJbXByZXNzaW9ucyBwZXIgQmFubmVyICoqCgpgYGB7ciBlY2hvID0gVCwgd2FybmluZyA9ICdoaWRlJywgbWVzc2FnZSA9IEZ9CiMjIyAtLS0gU3VtbWFyeSBTdGF0cyBmb3IgQmFubmVyIEltcHJlc3Npb25zCnRvdGFsSW1wcmVzc2lvbnMgPC0gZGF0YVNldCAlPiUgCiAgZ3JvdXBfYnkoQmFubmVyKSAlPiUgCiAgc3VtbWFyaXNlKHRvdGFsSW1wcmVzc2lvbnMgPSBzdW0oQ291bnQpKQpkYXRhdGFibGUodG90YWxJbXByZXNzaW9ucykKYGBgCgojIyMgMS4yIEJhbm5lciBDbGlja3MgKFBhZ2V2aWV3cykKCioqQ2hhcnQgMS4gMi4gRGFpbHkgQmFubmVyIENsaWNrcyAoTGFuZGluZyBQYWdlIFZpZXdzKSAqKgoKRmlyc3Qgd2UgcGxvdCAob24gbG9nYXJpdGhtaWMgeS1heGlzLCBpbiBvcmRlciB0byBzY2FsZSB0aGUgZGF0YSBmcm9tIGRpZmZlcmVudCBzb3VyY2VzIGFwcHJvcHJpYXRlbHkpLCBkYWlseSBwYWdldmlld3MgZnJvbSBhbGwgc291cmNlcy4gVGhlIGZvbGxvd2luZyB0d28gZmlndXJlcyAob24gcmVndWxhciwgbGluZWFyIHktYXhlcykgYXJlIHByb2JhYmx5IG1vcmUgcmVhZGJsZS4KCmBgYHtyIGVjaG8gPSBULCBldmFsID0gVCwgd2FybmluZyA9ICdoaWRlJywgbWVzc2FnZSA9IEZBTFNFfQpkYXRhU2V0IDwtIHJlYWQuY3N2KHBhc3RlKCcvaG9tZS9nb3JhbnNtL1dvcmsvX19fRGF0YUtvbGVrdGl2L1Byb2plY3RzL1dpa2ltZWRpYURFVS9fV01ERV9Qcm9qZWN0cy9fbWlzYy9OZXdFZGl0b3JzX1RlYW0vMjAxOF9TdW1tZXJCYW5uZXJDYW1wYWlnbi9fZGF0YS9EYWlseVBhZ2V2aWV3cy5jc3YnKSwKICAgICAgICAgICAgICAgICAgICBoZWFkZXIgPSBULAogICAgICAgICAgICAgICAgICAgIGNoZWNrLm5hbWVzID0gRiwKICAgICAgICAgICAgICAgICAgICByb3cubmFtZXMgPSAxLAogICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQpkYXRhU2V0JHVyaV9xdWVyeSA8LSBnc3ViKCI/Y2FtcGFpZ249IiwgIiIsIGRhdGFTZXQkdXJpX3F1ZXJ5LCBmaXhlZCA9IFQpCmRhdGFTZXQgPC0gZGF0YVNldCAlPiUgCiAgZmlsdGVyKCEoZ3JlcGwoIldNREVfMjAxOF9zcHJidDF8V01ERV8yMDE4X3NwcmJ0Mnx3bWRlX2V0YzIwMTdfYnQxIiwgdXJpX3F1ZXJ5KSkpCmRhdGFTZXQkdXJpX3F1ZXJ5W3doaWNoKGRhdGFTZXQkdXJpX3F1ZXJ5ID09ICIiKV0gPC0gIk5vIHJlZmVyZXIiCiMgLSBWaXN1YWxpemUgdy4ge2dncGxvdDJ9CmdncGxvdChkYXRhU2V0LCBhZXMoeCA9IENhbXBhaWduRGF5LAogICAgICAgICAgICAgICAgICAgIHkgPSBsb2coQ291bnQpLAogICAgICAgICAgICAgICAgICAgIGdyb3VwID0gdXJpX3F1ZXJ5LAogICAgICAgICAgICAgICAgICAgIGNvbG9yID0gdXJpX3F1ZXJ5LAogICAgICAgICAgICAgICAgICAgIGZpbGwgPSB1cmlfcXVlcnksCiAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSBDb3VudCkpICsgCiAgZ2VvbV9wYXRoKHNpemUgPSAuNSkgKyAKICBnZW9tX3BvaW50KHNpemUgPSAxLjUpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEpICsKICBnZ3RpdGxlKCdTdW1tZXIgQmFubmVyIENhbXBhaWduIDIwMTg6IEJhbm5lciBDbGlrcyAoUGFnZXZpZXdzKScpICsKICB0aGVtZV9taW5pbWFsKCkgKyAKICBnZW9tX3RleHRfcmVwZWwoc2l6ZSA9IDMuNSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBzaXplID0gOCkpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCkpICsKICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gICdyaWdodCcpICsgCiAgdGhlbWUobGVnZW5kLnRleHQgPSAgZWxlbWVudF90ZXh0KHNpemUgPSA3KSkKYGBgCgpgYGB7ciBlY2hvID0gVCwgZXZhbCA9IFQsIHdhcm5pbmcgPSAnaGlkZScsIG1lc3NhZ2UgPSBGQUxTRX0KZGF0YVNldCA8LSByZWFkLmNzdihwYXN0ZSgnL2hvbWUvZ29yYW5zbS9Xb3JrL19fX0RhdGFLb2xla3Rpdi9Qcm9qZWN0cy9XaWtpbWVkaWFERVUvX1dNREVfUHJvamVjdHMvX21pc2MvTmV3RWRpdG9yc19UZWFtLzIwMThfU3VtbWVyQmFubmVyQ2FtcGFpZ24vX2RhdGEvRGFpbHlQYWdldmlld3MuY3N2JyksCiAgICAgICAgICAgICAgICAgICAgaGVhZGVyID0gVCwKICAgICAgICAgICAgICAgICAgICBjaGVjay5uYW1lcyA9IEYsCiAgICAgICAgICAgICAgICAgICAgcm93Lm5hbWVzID0gMSwKICAgICAgICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzID0gRikKZGF0YVNldCR1cmlfcXVlcnkgPC0gZ3N1YigiP2NhbXBhaWduPSIsICIiLCBkYXRhU2V0JHVyaV9xdWVyeSwgZml4ZWQgPSBUKQpkYXRhU2V0JHVyaV9xdWVyeVt3aGljaChkYXRhU2V0JHVyaV9xdWVyeSA9PSAiIildIDwtICJObyByZWZlcmVyIgpkYXRhU2V0IDwtIGRhdGFTZXQgJT4lIAogIGZpbHRlcigoZ3JlcGwoIl5XTURFX25ld2VkaXRvcnNfc3VtbWVyMjAxOF8xJCIsIHVyaV9xdWVyeSkpIHwgCiAgICAgICAgICAgKGdyZXBsKCJeV01ERV9uZXdlZGl0b3JzX3N1bW1lcjIwMThfMiQiLCB1cmlfcXVlcnkpKSB8IAogICAgICAgICAgIChncmVwbCgiXldNREVfbmV3ZWRpdG9yc19zdW1tZXIyMDE4XzMkIiwgdXJpX3F1ZXJ5KSkgfCAKICAgICAgICAgICAoZ3JlcGwoIl5ObyByZWZlcmVyJCIsIHVyaV9xdWVyeSkpIHwgCiAgICAgICAgICAgKGdyZXBsKCJeV01ERV9uZXdlZGl0b3JzX3N1bW1lcjIwMThfTFAyJCIsIHVyaV9xdWVyeSkpKQojIC0gVmlzdWFsaXplIHcuIHtnZ3Bsb3QyfQpnZ3Bsb3QoZGF0YVNldCwgYWVzKHggPSBDYW1wYWlnbkRheSwKICAgICAgICAgICAgICAgICAgICB5ID0gQ291bnQsCiAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSB1cmlfcXVlcnksCiAgICAgICAgICAgICAgICAgICAgY29sb3IgPSB1cmlfcXVlcnksCiAgICAgICAgICAgICAgICAgICAgZmlsbCA9IHVyaV9xdWVyeSwKICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IENvdW50KSkgKyAKICBnZW9tX3BhdGgoc2l6ZSA9IC41KSArIAogIGdlb21fcG9pbnQoc2l6ZSA9IDEuNSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBjb21tYSkgKwogIGdndGl0bGUoJ1N1bW1lciBCYW5uZXIgQ2FtcGFpZ24gMjAxODogQmFubmVyIENsaWtzIChQYWdldmlld3MpJykgKwogIHRoZW1lX21pbmltYWwoKSArIAogIGdlb21fdGV4dF9yZXBlbChzaXplID0gMy41LCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArIAogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBjb21tYSkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHNpemUgPSA4KSkgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSkgKwogIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAgJ3JpZ2h0JykgKyAKICB0aGVtZShsZWdlbmQudGV4dCA9ICBlbGVtZW50X3RleHQoc2l6ZSA9IDcpKQpgYGAKCmBgYHtyIGVjaG8gPSBULCBldmFsID0gVCwgd2FybmluZyA9ICdoaWRlJywgbWVzc2FnZSA9IEZBTFNFfQpkYXRhU2V0IDwtIHJlYWQuY3N2KHBhc3RlKCcvaG9tZS9nb3JhbnNtL1dvcmsvX19fRGF0YUtvbGVrdGl2L1Byb2plY3RzL1dpa2ltZWRpYURFVS9fV01ERV9Qcm9qZWN0cy9fbWlzYy9OZXdFZGl0b3JzX1RlYW0vMjAxOF9TdW1tZXJCYW5uZXJDYW1wYWlnbi9fZGF0YS9EYWlseVBhZ2V2aWV3cy5jc3YnKSwKICAgICAgICAgICAgICAgICAgICBoZWFkZXIgPSBULAogICAgICAgICAgICAgICAgICAgIGNoZWNrLm5hbWVzID0gRiwKICAgICAgICAgICAgICAgICAgICByb3cubmFtZXMgPSAxLAogICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQpkYXRhU2V0JHVyaV9xdWVyeSA8LSBnc3ViKCI/Y2FtcGFpZ249IiwgIiIsIGRhdGFTZXQkdXJpX3F1ZXJ5LCBmaXhlZCA9IFQpCmRhdGFTZXQkdXJpX3F1ZXJ5W3doaWNoKGRhdGFTZXQkdXJpX3F1ZXJ5ID09ICIiKV0gPC0gIk5vIHJlZmVyZXIiCmRhdGFTZXQgPC0gZGF0YVNldCAlPiUgCiAgZmlsdGVyKCEoKGdyZXBsKCJeV01ERV9uZXdlZGl0b3JzX3N1bW1lcjIwMThfMSQiLCB1cmlfcXVlcnkpKSB8IAogICAgICAgICAgIChncmVwbCgiXldNREVfbmV3ZWRpdG9yc19zdW1tZXIyMDE4XzIkIiwgdXJpX3F1ZXJ5KSkgfCAKICAgICAgICAgICAoZ3JlcGwoIl5XTURFX25ld2VkaXRvcnNfc3VtbWVyMjAxOF8zJCIsIHVyaV9xdWVyeSkpIHwgCiAgICAgICAgICAgKGdyZXBsKCJeTm8gcmVmZXJlciQiLCB1cmlfcXVlcnkpKSB8IAogICAgICAgICAgIChncmVwbCgiXldNREVfbmV3ZWRpdG9yc19zdW1tZXIyMDE4X0xQMiQiLCB1cmlfcXVlcnkpKSkpICU+JSAKICBmaWx0ZXIoIShncmVwbCgiV01ERV8yMDE4X3NwcmJ0MXxXTURFXzIwMThfc3ByYnQyfHdtZGVfZXRjMjAxN19idDEiLCB1cmlfcXVlcnkpKSkKIyAtIFZpc3VhbGl6ZSB3LiB7Z2dwbG90Mn0KZ2dwbG90KGRhdGFTZXQsIGFlcyh4ID0gQ2FtcGFpZ25EYXksCiAgICAgICAgICAgICAgICAgICAgeSA9IENvdW50LAogICAgICAgICAgICAgICAgICAgIGdyb3VwID0gdXJpX3F1ZXJ5LAogICAgICAgICAgICAgICAgICAgIGNvbG9yID0gdXJpX3F1ZXJ5LAogICAgICAgICAgICAgICAgICAgIGZpbGwgPSB1cmlfcXVlcnksCiAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSBDb3VudCkpICsgCiAgZ2VvbV9wYXRoKHNpemUgPSAuNSkgKyAKICBnZW9tX3BvaW50KHNpemUgPSAxLjUpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEpICsKICBnZ3RpdGxlKCdTdW1tZXIgQmFubmVyIENhbXBhaWduIDIwMTg6IEJhbm5lciBDbGlrcyAoUGFnZXZpZXdzKScpICsKICB0aGVtZV9taW5pbWFsKCkgKyAKICBnZW9tX3RleHRfcmVwZWwoc2l6ZSA9IDMuNSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBzaXplID0gOCkpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCkpICsKICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gICdyaWdodCcpICsgCiAgdGhlbWUobGVnZW5kLnRleHQgPSAgZWxlbWVudF90ZXh0KHNpemUgPSA3KSkKYGBgCgoqKlRhYmxlIDEuIDIuIERhaWx5IEJhbm5lciBDbGlja3MgKExhbmRpbmcgUGFnZSBWaWV3cykgKioKCmBgYHtyIGVjaG8gPSBULCB3YXJuaW5nID0gJ2hpZGUnLCBtZXNzYWdlID0gRn0KIyMjIC0tLSBGdWxsIERhdGFzZXQgKFRhYmxlIFJlcG9ydCkKZGF0YVNldCA8LSByZWFkLmNzdignL2hvbWUvZ29yYW5zbS9Xb3JrL19fX0RhdGFLb2xla3Rpdi9Qcm9qZWN0cy9XaWtpbWVkaWFERVUvX1dNREVfUHJvamVjdHMvX21pc2MvTmV3RWRpdG9yc19UZWFtLzIwMThfU3VtbWVyQmFubmVyQ2FtcGFpZ24vX2RhdGEvRGFpbHlQYWdldmlld3MuY3N2JywKICAgICAgICAgICAgICAgICAgICBoZWFkZXIgPSBULAogICAgICAgICAgICAgICAgICAgIGNoZWNrLm5hbWVzID0gRiwKICAgICAgICAgICAgICAgICAgICByb3cubmFtZXMgPSAxLAogICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQpkYXRhU2V0JHVyaV9xdWVyeVt3aGljaChkYXRhU2V0JHVyaV9xdWVyeSA9PSAiIildIDwtICJObyByZWZlcmVyIgpkYXRhdGFibGUoZGF0YVNldCkKYGBgCgoqKlRhYmxlIDEuIDIuIDEgVG90YWwgQmFubmVyIENsaWNrcy9QYWdldmlld3MgcGVyIEJhbm5lciAqKgoKYGBge3IgZWNobyA9IFQsIHdhcm5pbmcgPSAnaGlkZScsIG1lc3NhZ2UgPSBGfQojIyMgLS0tIFN1bW1hcnkgU3RhdHMgZm9yIEJhbm5lciBJbXByZXNzaW9ucwp0b3RhbENsaWNrcyA8LSBkYXRhU2V0ICU+JSAKICBncm91cF9ieSh1cmlfcXVlcnkpICU+JSAKICBzdW1tYXJpc2UodG90YWxDbGlja3MgPSBzdW0oQ291bnQpKSAlPiUgCiAgYXJyYW5nZShkZXNjKHRvdGFsQ2xpY2tzKSkKZGF0YXRhYmxlKHRvdGFsQ2xpY2tzKQpgYGAKCiMjIyAxLjMgQmFubmVyIENsaWNrcy9JbXByZXNzaW9ucyBDbGlja3MgKFBhZ2V2aWV3cykKCioqQ2hhcnQgMS4gMy4gVGhlIENsaWNrcy9JbXByZXNzaW9ucyByYXRpbyBwZXIgYmFubmVyKioKCmBgYHtyIGVjaG8gPSBULCBldmFsID0gVCwgd2FybmluZyA9ICdoaWRlJywgbWVzc2FnZSA9IEZBTFNFfQppbXByZXNzaW9ucyA8LSByZWFkLmNzdignL2hvbWUvZ29yYW5zbS9Xb3JrL19fX0RhdGFLb2xla3Rpdi9Qcm9qZWN0cy9XaWtpbWVkaWFERVUvX1dNREVfUHJvamVjdHMvX21pc2MvTmV3RWRpdG9yc19UZWFtLzIwMThfU3VtbWVyQmFubmVyQ2FtcGFpZ24vX2RhdGEvRGFpbHlCYW5uZXJJbXByZXNzaW9ucy5jc3YnLAogICAgICAgICAgICAgICAgICAgIGhlYWRlciA9IFQsCiAgICAgICAgICAgICAgICAgICAgcm93Lm5hbWVzID0gMSwKICAgICAgICAgICAgICAgICAgICBjaGVjay5uYW1lcyA9IEYsCiAgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IEYpCiMgLSBhZGp1c3QgZm9yIGJhbm5lciBpbXByZXNzaW9ucyBzYW1wbGUgcmF0ZQpjbGlja3MgPC0gcmVhZC5jc3YocGFzdGUoJy9ob21lL2dvcmFuc20vV29yay9fX19EYXRhS29sZWt0aXYvUHJvamVjdHMvV2lraW1lZGlhREVVL19XTURFX1Byb2plY3RzL19taXNjL05ld0VkaXRvcnNfVGVhbS8yMDE4X1N1bW1lckJhbm5lckNhbXBhaWduL19kYXRhL0RhaWx5UGFnZXZpZXdzLmNzdicpLAogICAgICAgICAgICAgICAgICAgIGhlYWRlciA9IFQsCiAgICAgICAgICAgICAgICAgICAgY2hlY2submFtZXMgPSBGLAogICAgICAgICAgICAgICAgICAgIHJvdy5uYW1lcyA9IDEsCiAgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IEYpCmNsaWNrcyR1cmlfcXVlcnlbd2hpY2goY2xpY2tzJHVyaV9xdWVyeSA9PSAiIildIDwtICJObyByZWZlcmVyIgpjbGlja3MkdXJpX3F1ZXJ5IDwtIGdzdWIoIj9jYW1wYWlnbj0iLCAiIiwgY2xpY2tzJHVyaV9xdWVyeSwgZml4ZWQgPSBUKQpjbGlja3MgPC0gY2xpY2tzICU+JSAKICBmaWx0ZXIoIShncmVwbCgiV01ERV8yMDE4X3NwcmJ0MXxXTURFXzIwMThfc3ByYnQyfHdtZGVfZXRjMjAxN19idDEiLCB1cmlfcXVlcnkpKSkKY2xpY2tzJHVyaV9xdWVyeVtncmVwbCgiV01ERV9uZXdlZGl0b3JzX3N1bW1lcjIwMThfMSIsIGNsaWNrcyR1cmlfcXVlcnkpXSA8LSAnQjE4V01ERV9hdXRob3JzXzEnCmNsaWNrcyR1cmlfcXVlcnlbZ3JlcGwoIldNREVfbmV3ZWRpdG9yc19zdW1tZXIyMDE4XzIiLCBjbGlja3MkdXJpX3F1ZXJ5KV0gPC0gJ0IxOFdNREVfYXV0aG9yc18yJwpjbGlja3MkdXJpX3F1ZXJ5W2dyZXBsKCJXTURFX25ld2VkaXRvcnNfc3VtbWVyMjAxOF8zIiwgY2xpY2tzJHVyaV9xdWVyeSldIDwtICdCMThXTURFX2F1dGhvcnNfMycKY2xpY2tzIDwtIGNsaWNrcyAlPiUgCiAgZ3JvdXBfYnkodXJpX3F1ZXJ5LCBDYW1wYWlnbkRheSkgJT4lIAogIHN1bW1hcmlzZShDb3VudCA9IHN1bShDb3VudCkpCiMgLSBqb2luIGltcHJlc3Npb25zIGFuZCBjbGlja3M6ICAKZGF0YVNldCA8LSBsZWZ0X2pvaW4oaW1wcmVzc2lvbnMsIGNsaWNrcywgCiAgICAgICAgICAgICAgICAgICAgIGJ5ID0gYygiQmFubmVyIiA9ICJ1cmlfcXVlcnkiLCAiQ2FtcGFpZ25EYXkiKSkKZGF0YVNldCRgQ2xpY2tzL0ltcHJlc3Npb25zYCA8LSByb3VuZChkYXRhU2V0JENvdW50LnkvZGF0YVNldCRDb3VudC54LCA1KQojIC0gVmlzdWFsaXplIHcuIHtnZ3Bsb3QyfQpnZ3Bsb3QoZGF0YVNldCwgYWVzKHggPSBDYW1wYWlnbkRheSwKICAgICAgICAgICAgICAgICAgICB5ID0gYENsaWNrcy9JbXByZXNzaW9uc2AsCiAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSBCYW5uZXIsCiAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBCYW5uZXIsCiAgICAgICAgICAgICAgICAgICAgZmlsbCA9IEJhbm5lciwKICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IGBDbGlja3MvSW1wcmVzc2lvbnNgKSkgKyAKICBnZW9tX3BhdGgoc2l6ZSA9IC41KSArIAogIGdlb21fcG9pbnQoc2l6ZSA9IDEuNSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBjb21tYSkgKwogIGdndGl0bGUoJ1N1bW1lciBCYW5uZXIgQ2FtcGFpZ24gMjAxODogQmFubmVyIENsaWNrcy9JbXByZXNzaW9ucycpICsKICB0aGVtZV9taW5pbWFsKCkgKyAKICBnZW9tX3RleHRfcmVwZWwoc2l6ZSA9IDMuNSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBzaXplID0gOCkpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCkpICsKICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCmBgYAoKKipUYWJsZSAxLiAzLiBUaGUgQ2xpY2tzL0ltcHJlc3Npb25zIHJhdGlvIHBlciBiYW5uZXIqKgoKYGBge3IgZWNobyA9IFQsIHdhcm5pbmcgPSAnaGlkZScsIG1lc3NhZ2UgPSBGfQojIyMgLS0tIEZ1bGwgRGF0YXNldCAoVGFibGUgUmVwb3J0KQpkYXRhdGFibGUoZGF0YVNldFssIGMoMSwgMywgNSldKQpgYGAKCioqVGFibGUgMS4gMy4gMSBUb3RhbCBDbGlja3MvSW1wcmVzc2lvbnMgcmF0aW8gcGVyIGJhbm5lcioqCgpgYGB7ciBlY2hvID0gVCwgd2FybmluZyA9ICdoaWRlJywgbWVzc2FnZSA9IEZ9CiMjIyAtLS0gRnVsbCBEYXRhc2V0IChUYWJsZSBSZXBvcnQpCnRvdGFsSW1wQ2xpY2tzIDwtIGRhdGFTZXQgJT4lIAogIHNlbGVjdChCYW5uZXIsIENvdW50LngsIENvdW50LnkpICU+JSAKICBncm91cF9ieShCYW5uZXIpICU+JSAKICBzdW1tYXJpc2UoSW1wcmVzc2lvbnMgPSBzdW0oQ291bnQueCksIENsaWNrcyA9IHN1bShDb3VudC55KSkKdG90YWxJbXBDbGlja3MkYENsaWNrcy9JbXByZXNzaW9uc2AgPC0gcm91bmQodG90YWxJbXBDbGlja3MkQ2xpY2tzL3RvdGFsSW1wQ2xpY2tzJEltcHJlc3Npb25zLCA1KQpkYXRhdGFibGUodG90YWxJbXBDbGlja3MpCmBgYAoKIyMjIDEuNCBVc2VyIFJlZ2lzdHJhdGlvbnMKCioqQ2hhcnQgMS4gNC4gRGFpbHkgdXNlciByZWdpc3RyYXRpb25zIHBlciBiYW5uZXIqKgoKYGBge3IgZWNobyA9IFQsIGV2YWwgPSBULCB3YXJuaW5nID0gJ2hpZGUnLCBtZXNzYWdlID0gRkFMU0V9CmRhdGFTZXQgPC0gcmVhZC5kZWxpbSgnL2hvbWUvZ29yYW5zbS9Xb3JrL19fX0RhdGFLb2xla3Rpdi9Qcm9qZWN0cy9XaWtpbWVkaWFERVUvX1dNREVfUHJvamVjdHMvX21pc2MvTmV3RWRpdG9yc19UZWFtLzIwMThfU3VtbWVyQmFubmVyQ2FtcGFpZ24vX2RhdGEvc3VtbWVyQkMyMDE4X3VzZXJSZWdpc3RyYXRpb25zX0ZVTEwudHN2JywKICAgICAgICAgICAgICAgICAgICBoZWFkZXIgPSBULAogICAgICAgICAgICAgICAgICAgIGNoZWNrLm5hbWVzID0gRiwKICAgICAgICAgICAgICAgICAgICBzZXAgPSAiXHQiLAogICAgICAgICAgICAgICAgICAgIHF1b3RlID0gIiIsCiAgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IEYpCmRhdGFTZXQgPC0gZGF0YVNldFtncmVwbCgnaXNfYm90IjogZmFsc2UnLCBkYXRhU2V0JHVzZXJBZ2VudCwgZml4ZWQgPSBUKSwgXQpkYXRhU2V0JHRpbWVzdGFtcCA8LSBhcy5jaGFyYWN0ZXIoZGF0YVNldCR0aW1lc3RhbXApCmRhdGFTZXQkdGltZXN0YW1wIDwtIGFzLlBPU0lYY3QoZGF0YVNldCR0aW1lc3RhbXAsIHR6ID0gIlVUQyIsIGZvcm1hdCA9ICIlWSVtJWQlSCVNJVMiKSAKIyAtIENFU1QgY29ycmVjdGlvbiBvbiBQT1NJWGN0IGNsYXNzLCArMmhvdXJzOgpkYXRhU2V0JHRpbWVzdGFtcCA8LSBkYXRhU2V0JHRpbWVzdGFtcCArIDIqNjAqNjAKIyAtIENhbXBhaWduIGRheToKZGF0YVNldCRDYW1wYWlnbkRheSA8LSBzYXBwbHkoZGF0YVNldCR0aW1lc3RhbXAsIGZ1bmN0aW9uKHgpIHsKICBwYXN0ZShjKAogICAgc3Vic3RyKHgsIDEsNCksCiAgICBzdWJzdHIoeCwgNiw3KSwKICAgIHN1YnN0cih4LCA5LDEwKQogICAgKSwKICAgIGNvbGxhcHNlID0gIi0iLAogICAgc2VwID0gIiIpCn0pCmRhdGFTZXQgPC0gZmlsdGVyKGRhdGFTZXQsCiAgICAgICAgICAgICAgICAgIENhbXBhaWduRGF5ICVpbiUgYygiMjAxOC0wOC0wMSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjIwMTgtMDgtMDIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjIwMTgtMDgtMDMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjIwMTgtMDgtMDQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjIwMTgtMDgtMDUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjIwMTgtMDgtMDYiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjIwMTgtMDgtMDciLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjIwMTgtMDgtMDgiKSkKdXNlclJlZyA8LSBkYXRhU2V0ICU+JSAKICBzZWxlY3QoZXZlbnRfY2FtcGFpZ24sIENhbXBhaWduRGF5KSAlPiUgCiAgZ3JvdXBfYnkoQ2FtcGFpZ25EYXksIGV2ZW50X2NhbXBhaWduKSAlPiUgCiAgc3VtbWFyaXNlKENvdW50ID0gbigpKQpjb2xuYW1lcyh1c2VyUmVnKVsyXSA8LSAiQmFubmVyIgoKIyAtIFZpc3VhbGl6ZSB3LiB7Z2dwbG90Mn0KZ2dwbG90KHVzZXJSZWcsIGFlcyh4ID0gQ2FtcGFpZ25EYXksCiAgICAgICAgICAgICAgICAgICAgeSA9IENvdW50LAogICAgICAgICAgICAgICAgICAgIGdyb3VwID0gQmFubmVyLAogICAgICAgICAgICAgICAgICAgIGNvbG9yID0gQmFubmVyLAogICAgICAgICAgICAgICAgICAgIGZpbGwgPSBCYW5uZXIsCiAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSBDb3VudCkpICsgCiAgZ2VvbV9wYXRoKHNpemUgPSAuNSkgKyAKICBnZW9tX3BvaW50KHNpemUgPSAxLjUpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEpICsKICBnZ3RpdGxlKCdTdW1tZXIgQmFubmVyIENhbXBhaWduIDIwMTg6IFVzZXIgUmVnaXN0cmF0aW9ucycpICsKICB0aGVtZV9taW5pbWFsKCkgKyAKICBnZW9tX3RleHRfcmVwZWwoc2l6ZSA9IDMuNSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBzaXplID0gOCkpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCkpICsKICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCmBgYAoKKipUYWJsZSAxLiA0LiBEYWlseSB1c2VyIHJlZ2lzdHJhdGlvbnMgcGVyIGJhbm5lcioqCgpgYGB7ciBlY2hvID0gVCwgZXZhbCA9IFQsIHdhcm5pbmcgPSAnaGlkZScsIG1lc3NhZ2UgPSBGQUxTRX0KIyMjIC0tLSBGdWxsIERhdGFzZXQgKFRhYmxlIFJlcG9ydCkKZGF0YXRhYmxlKHVzZXJSZWcpCmBgYAoKKipUYWJsZSAxLiA0LiAxIEJhbm5lciBDb252ZXJzaW9uIFJhdGVzKioKCmBgYHtyIGVjaG8gPSBULCBldmFsID0gVCwgd2FybmluZyA9ICdoaWRlJywgbWVzc2FnZSA9IEZ9CiMjIyAtLS0gQmFubmVyIENvbnZlcnNpb24gUmF0ZXMKdG90YWxSZWdzIDwtIHVzZXJSZWdbLCAyOjNdICU+JSAKICBzZWxlY3QoQmFubmVyLCBDb3VudCkgJT4lCiAgZ3JvdXBfYnkoQmFubmVyKSAlPiUKICBzdW1tYXJpc2UodG90YWxSZWcgPSBzdW0oQ291bnQpKQp0b3RhbFJlZ3MkQmFubmVyW2dyZXBsKCJXTURFX25ld2VkaXRvcnNfc3VtbWVyMjAxOF8xIiwgdG90YWxSZWdzJEJhbm5lcildIDwtICdCMThXTURFX2F1dGhvcnNfMScKdG90YWxSZWdzJEJhbm5lcltncmVwbCgiV01ERV9uZXdlZGl0b3JzX3N1bW1lcjIwMThfMiIsIHRvdGFsUmVncyRCYW5uZXIpXSA8LSAnQjE4V01ERV9hdXRob3JzXzInCnRvdGFsUmVncyRCYW5uZXJbZ3JlcGwoIldNREVfbmV3ZWRpdG9yc19zdW1tZXIyMDE4XzMiLCB0b3RhbFJlZ3MkQmFubmVyKV0gPC0gJ0IxOFdNREVfYXV0aG9yc18zJwp0b3RhbENsaWNrcyR1cmlfcXVlcnlbZ3JlcGwoIldNREVfbmV3ZWRpdG9yc19zdW1tZXIyMDE4XzEiLCB0b3RhbENsaWNrcyR1cmlfcXVlcnkpXSA8LSAnQjE4V01ERV9hdXRob3JzXzEnCnRvdGFsQ2xpY2tzJHVyaV9xdWVyeVtncmVwbCgiV01ERV9uZXdlZGl0b3JzX3N1bW1lcjIwMThfMiIsIHRvdGFsQ2xpY2tzJHVyaV9xdWVyeSldIDwtICdCMThXTURFX2F1dGhvcnNfMicKdG90YWxDbGlja3MkdXJpX3F1ZXJ5W2dyZXBsKCJXTURFX25ld2VkaXRvcnNfc3VtbWVyMjAxOF8zIiwgdG90YWxDbGlja3MkdXJpX3F1ZXJ5KV0gPC0gJ0IxOFdNREVfYXV0aG9yc18zJwp0b3RhbENsaWNrcyA8LSB0b3RhbENsaWNrcyAlPiUgCiAgZ3JvdXBfYnkodXJpX3F1ZXJ5KSAlPiUgCiAgc3VtbWFyaXNlKHRvdGFsQ2xpY2tzID0gc3VtKHRvdGFsQ2xpY2tzKSkKdG90YWxSZWdzIDwtIGxlZnRfam9pbih0b3RhbFJlZ3MsIHRvdGFsQ2xpY2tzLAogICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gYygiQmFubmVyIiA9ICJ1cmlfcXVlcnkiKSkKdG90YWxSZWdzJGBSZWdpc3RyYXRpb25zL0NsaWNrc2AgPC0gcm91bmQodG90YWxSZWdzJHRvdGFsUmVnL3RvdGFsUmVncyR0b3RhbENsaWNrcywgNSkKZGF0YXRhYmxlKHRvdGFsUmVncykKYGBgCgojIyMgMS41IFVzZXIgRWRpdHMKCioqQ2hhcnQgMS4gNS4gRWRpdHMgb2YgcmVnaXN0ZXJlZCB1c2VycyBwZXIgYmFubmVyIGFuZCBjYW1wYWlnbiBkYXkgb2YgcmVnaXN0cmF0aW9uKioKCioqTk9URToqKiB0aGUgQ2FtcGFpZ24gRGF5IGhlcmUgcmVmZXJzIHRvIHRoZSBkYXkgd2hlbiB0aGUgdXNlciBoYXMgcmVnaXN0ZXJlZCwgbm90IHRoZSBkYXkgaW4gd2hpY2ggdGhlIHJlc3BlY3RpdmUgZWRpdHMgd2VyZSBtYWRlLgoKYGBge3IgZWNobyA9IFQsIGV2YWwgPSBULCB3YXJuaW5nID0gJ2hpZGUnLCBtZXNzYWdlID0gRkFMU0V9CmRhdGFTZXQyIDwtIHJlYWQuZGVsaW0oJy9ob21lL2dvcmFuc20vV29yay9fX19EYXRhS29sZWt0aXYvUHJvamVjdHMvV2lraW1lZGlhREVVL19XTURFX1Byb2plY3RzL19taXNjL05ld0VkaXRvcnNfVGVhbS8yMDE4X1N1bW1lckJhbm5lckNhbXBhaWduL19kYXRhL3NCQzIwMThfdXNlckVkaXRzX0ZVTEwudHN2JywKICAgICAgICAgICAgICAgICAgICBoZWFkZXIgPSBULAogICAgICAgICAgICAgICAgICAgIGNoZWNrLm5hbWVzID0gRiwKICAgICAgICAgICAgICAgICAgICBzZXAgPSAiXHQiLAogICAgICAgICAgICAgICAgICAgIHF1b3RlID0gIiIsCiAgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IEYpCmRhdGFTZXQgPC0gbGVmdF9qb2luKGRhdGFTZXQsIGRhdGFTZXQyLCBieSA9IGMoImV2ZW50X3VzZXJJZCIgPSAicmV2X3VzZXIiKSkKZGF0YVNldCRlZGl0c1tpcy5uYShkYXRhU2V0JGVkaXRzKV0gPC0gMAoKdXNlckVkcyA8LSBkYXRhU2V0ICU+JSAKICBzZWxlY3QoZXZlbnRfY2FtcGFpZ24sIENhbXBhaWduRGF5LCBlZGl0cykgJT4lIAogIGdyb3VwX2J5KENhbXBhaWduRGF5LCBldmVudF9jYW1wYWlnbikgJT4lIAogIHN1bW1hcmlzZShFZGl0cyA9IHN1bShlZGl0cykpCmNvbG5hbWVzKHVzZXJFZHMpWzJdIDwtICJCYW5uZXIiCgojIC0gVmlzdWFsaXplIHcuIHtnZ3Bsb3QyfQpnZ3Bsb3QodXNlckVkcywgYWVzKHggPSBDYW1wYWlnbkRheSwKICAgICAgICAgICAgICAgICAgICB5ID0gRWRpdHMsCiAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSBCYW5uZXIsCiAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBCYW5uZXIsCiAgICAgICAgICAgICAgICAgICAgZmlsbCA9IEJhbm5lciwKICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IEVkaXRzKSkgKyAKICBnZW9tX3BhdGgoc2l6ZSA9IC41KSArIAogIGdlb21fcG9pbnQoc2l6ZSA9IDEuNSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBjb21tYSkgKwogIGdndGl0bGUoJ1N1bW1lciBCYW5uZXIgQ2FtcGFpZ24gMjAxODogVXNlciBFZGl0cycpICsKICB0aGVtZV9taW5pbWFsKCkgKyAKICBnZW9tX3RleHRfcmVwZWwoc2l6ZSA9IDMuNSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBzaXplID0gOCkpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCkpICsKICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCmBgYAoKKipUYWJsZSAxLiA1LiBFZGl0cyBvZiByZWdpc3RlcmVkIHVzZXJzIHBlciBiYW5uZXIgYW5kIGNhbXBhaWduIGRheSBvZiByZWdpc3RyYXRpb24qKgoKYGBge3IgZWNobyA9IFQsIHdhcm5pbmcgPSAnaGlkZScsIG1lc3NhZ2UgPSBGfQojIyMgLS0tIEZ1bGwgRGF0YXNldCAoVGFibGUgUmVwb3J0KQpkYXRhdGFibGUodXNlckVkcykKYGBgCgoKKipUYWJsZSAxLiA1LiAxIEVkaXRzIG9mIHJlZ2lzdGVyZWQgdXNlcnMgcGVyIGJhbm5lciBhbmQgY2FtcGFpZ24gZGF5IG9mIHJlZ2lzdHJhdGlvbioqCgpUb3RhbCBudW1iZXIgb2YgdXNlciBlZGl0cyBwZXIgYmFubmVyOgoKYGBge3IgZWNobyA9IFQsIHdhcm5pbmcgPSAnaGlkZScsIG1lc3NhZ2UgPSBGfQp0b3RhbEVkaXRzIDwtIHVzZXJFZHMgJT4lIAogIGdyb3VwX2J5KEJhbm5lcikgJT4lIAogIHN1bW1hcmlzZShFZGl0cyA9IHN1bShFZGl0cykpCmRhdGF0YWJsZSh0b3RhbEVkaXRzKQpgYGAKCioqVGFibGUgMS4gNS4gMiBVc2VycyByZWFjaGluZyB0aGVpciAxMHRoIGVkaXQgcGVyIGJhbm5lcioqCgpgYGB7ciBlY2hvID0gVCwgZXZhbCA9IFQsIHdhcm5pbmcgPSAnaGlkZScsIG1lc3NhZ2UgPSBGfQplZGl0MTAgPC0gZGF0YVNldCAlPiUgCiAgZmlsdGVyKGVkaXRzID49IDEwKSAlPiUgCiAgc2VsZWN0KGV2ZW50X2NhbXBhaWduKSAlPiUgCiAgZ3JvdXBfYnkoZXZlbnRfY2FtcGFpZ24pICU+JQogIHN1bW1hcmlzZShgZWRpdDEwdGhgID0gbigpKQpkYXRhdGFibGUoZWRpdDEwKQpgYGAKCioqVGFibGUgMS4gNS4gMyBGdWxsIHVzZXIgZWRpdHMgZGlzdHJpYnV0aW9uKioKCmBgYHtyIGVjaG8gPSBULCBldmFsID0gVCwgd2FybmluZyA9ICdoaWRlJywgbWVzc2FnZSA9IEZ9CiMjIyAtLS0gRnVsbCBEYXRhc2V0IChUYWJsZSBSZXBvcnQpCnBsdEVkaXRzIDwtIGFzLnRibChkYXRhU2V0KSAlPiUgCiAgZHBseXI6Omdyb3VwX2J5KGVkaXRzKSAlPiUgCiAgY291bnQoKQpjb2xuYW1lcyhwbHRFZGl0cykgPC0gYygnRWRpdHMnLCAnTnVtLnVzZXJzJykKa25pdHI6OmthYmxlKHBsdEVkaXRzLCBmb3JtYXQgPSAiaHRtbCIpICU+JQogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEYsIHBvc2l0aW9uID0gImxlZnQiKQpgYGAKCgoqKlRhYmxlIDEuIDUuIDQgVXNlcnMgZWRpdCBjYXRlZ29yaWVzKioKCmBgYHtyIGVjaG8gPSBULCBldmFsID0gVCwgd2FybmluZyA9ICdoaWRlJywgbWVzc2FnZSA9IEZ9CmVkaXRzMCA8LSBwbHRFZGl0cyRgTnVtLnVzZXJzYFtwbHRFZGl0cyRFZGl0cyA9PSAwXQplZGl0cyA8LSBzdW0ocGx0RWRpdHMkYE51bS51c2Vyc2BbcGx0RWRpdHMkRWRpdHMgPiAwXSkKZWRpdHMxIDwtIHN1bShwbHRFZGl0cyRgTnVtLnVzZXJzYFtwbHRFZGl0cyRFZGl0cyA9PSAxXSkKZWRpdHMyXzQgPC0gc3VtKHBsdEVkaXRzJGBOdW0udXNlcnNgW3BsdEVkaXRzJEVkaXRzID49IDIgJiBwbHRFZGl0cyRFZGl0cyA8PSA0XSkKZWRpdHM1XzEwIDwtIHN1bShwbHRFZGl0cyRgTnVtLnVzZXJzYFtwbHRFZGl0cyRFZGl0cyA+PSA1ICYgcGx0RWRpdHMkRWRpdHMgPD0gMTBdKQplZGl0czEwIDwtIHN1bShwbHRFZGl0cyRgTnVtLnVzZXJzYFtwbHRFZGl0cyRFZGl0cyA+IDEwXSkKZWRpdENsYXNzZXMgPC0gZGF0YS5mcmFtZShgTm8gZWRpdHNgID0gZWRpdHMwLAogICAgICAgICAgICAgICAgICAgICAgICAgIGBFZGl0ZWRgID0gZWRpdHMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgYDEgZWRpdGAgPSBlZGl0czEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgYDIgLSA0IGVkaXRzYCA9IGVkaXRzMl80LAogICAgICAgICAgICAgICAgICAgICAgICAgIGA1IC0gMTAgZWRpdHNgID0gZWRpdHM1XzEwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBgPiAxMCBlZGl0c2AgPSBlZGl0czEwLAogICAgICAgICAgICAgICAgICAgICAgICAgIGNoZWNrLm5hbWVzID0gRiwKICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzID0gRikKa25pdHI6OmthYmxlKGVkaXRDbGFzc2VzLCBmb3JtYXQgPSAiaHRtbCIpICU+JQogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEYsIHBvc2l0aW9uID0gImxlZnQiKQpgYGAKCiMjIyAxLjYgVHJhaW5pbmcgTW9kdWxlcwoKVGhpcyBkYXRhc2V0IGlzIG5vdCBbcHJvdmlkZWQgeWV0XShodHRwczovL3BoYWJyaWNhdG9yLndpa2ltZWRpYS5vcmcvVDE5OTY5NikuCgo=