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

NOTE: The campaign will be run from … to … of October 2017.

0. Data Acquisiton

NOTE: the Data Acquisition code chunk is not fully reproducible from this Report. The data are collected by running the script abc2017_PROD_OverallDailyUpdate.R on stat1005.eqiad.wmnet, collecting the data as .tsv and .csv files, copying manually, and processing locally. Run from stat1005 stat box by executing Rscript /home/goransm/RScripts/abc2017/abc2017_PROD_OverallDailyUpdate.R.

### --- Script: abc2017_PROD_OverallDailyUpdate.R
### --- the following runs on stat1005.eqiad.wmnet
### --- Rscript /home/goransm/RScripts/abc2017/abc2017_PROD_OverallDailyUpdate.R

### --- The script collects and wrangles all datasets
### --- for the WMDE Autumn Banner Campaign 2017.

### --- Goran S. Milovanovic, Data Analyst, WMDE
### --- September 26, 2017.

### -----------------------------------------------------------------------------
### 0. Setup
### -----------------------------------------------------------------------------

rm(list = ls())
library(dplyr)
library(tidyr)
library(stringr)
library(data.table)
startDate <- '2017-09-20'
endDate <- '2017-09-26'
bannerImpressiomnsDir <- '/home/goransm/_miscWMDE/abc2017_DataOUT/abc2017_OfficialDatasets/abc2017BannerImpressions/'
bannerClicksDir <- '/home/goransm/_miscWMDE/abc2017_DataOUT/abc2017_OfficialDatasets/abc2017BannerClicksLandingPages/'
userRegDir <- '/home/goransm/_miscWMDE/abc2017_DataOUT/abc2017_OfficialDatasets/abc2017UserReg/'
dailyUpdateDir <- '/home/goransm/_miscWMDE/abc2017_DataOUT/abc2017_OfficialDatasets/abc2017_DailyUpdate/' 

### -----------------------------------------------------------------------------
### 1. Banner Impressions
### -----------------------------------------------------------------------------

### --- Campaign Banner Tags:
# - (1) ?campaign=wmde_abc2017_bt1 - banner for Specific Task 1;
# - (2) ?campaign=wmde_abc2017_bt2 - banner for Specific Task 2;
# - (3) ?campaign=wmde_abc2017_bt3 - banner for Specific Task 3;
# - (4) ?campaign=wmde_abc2017_gib_lp - banner for the General Invitation 
# - which leads to the Landing Page upon click;
# - (5) ?campaign=wmde_abc2017_gib_rg - banner for the General Invitation 
# which leads directly to Registration upon click.

### --- from wmf.webrequest, run the following script on stat 1005
### --- to collect banner impressions
### --- Rscript /home/goransm/RScripts/abc2017/abc2017_PROD_BannerImpressions.R

### --- HiveQL for everything with ?campaign like "wmde_abc2017" 
### --- and then look for the desired tags.

### --- loop over date range, create query, fetch, and store
# dateRange <- seq(from = as.Date(startDate),
#                  to = as.Date(endDate),
#                  by = 'day')
# dateRange <- as.character(dateRange)
# # - set outDir
# outDir <- bannerImpressiomnsDir
# # - store query dir:
# qDir <- bannerImpressiomnsDir
# setwd(qDir)
# # - set HiveQL query dir:
# for (i in 1:length(dateRange)) {
#   # - construct HiveQL query:
#   y <- as.numeric(strsplit(dateRange[i], split = "-")[[1]][1])
#   m <- as.numeric(strsplit(dateRange[i], split = "-")[[1]][2])
#   d <- as.numeric(strsplit(dateRange[i], split = "-")[[1]][3])
#   q <- paste(
#     "USE wmf;
#     SELECT uri_query FROM webrequest
#     WHERE uri_host = 'de.wikipedia.org'
#     AND uri_path = '/beacon/impression'
#     AND year = ", y,
#     " AND month = ", m,
#     " AND day = ", d,
#     sep = "")
#   # - write hql
#   write(q, 'abc2017_BannerImpressions.hql')
#   # - prepare output file:
#   fileName <- "abc2017_BannerImpressions_"
#   fileName <- paste0(fileName, dateRange[i], ".tsv")
#   fileName <- paste0(outDir, "/", fileName)
#   # - execute hql script:
#   hiveArgs <-
#     'beeline -f'
#   hiveInput <- paste0('abc2017_BannerImpressions.hql > ',
#                       fileName)
#   # - command:
#   hiveCommand <- paste(hiveArgs, hiveInput)
#   system(command = hiveCommand, wait = TRUE)
# }

### -----------------------------------------------------------------------------
### 2. Banner Clicks and Landing Page Views
### -----------------------------------------------------------------------------

### --- campaign URL
# - https://de.wikipedia.org/wiki/Wikipedia:Wikimedia_Deutschland/Entdeckungen-sortieren?campaign=wmde2017summer1&wmdesource=bannerclick

### --- Campaign Banner Tags:
# - (1) ?campaign=wmde_abc2017_bt1 - banner for Specific Task 1;
# - (2) ?campaign=wmde_abc2017_bt2 - banner for Specific Task 2;
# - (3) ?campaign=wmde_abc2017_bt3 - banner for Specific Task 3;
# - (4) ?campaign=wmde_abc2017_gib_lp - banner for the General Invitation 
# - which leads to the Landing Page upon click;
# - (5) ?campaign=wmde_abc2017_gib_rg - banner for the General Invitation 
# which leads directly to Registration upon click.

### --- Landing/Registration pages:
# - Landing Page, Specific Tasks, Banner bt1:
# - https://de.wikipedia.org/wiki/Wikipedia:Wikimedia_Deutschland/Fehler_korrigieren?campaign=wmde_abc2017_bt1
# - Landing Page, Specific Tasks, Banner bt2:
# - https://de.wikipedia.org/wiki/Wikipedia:Wikimedia_Deutschland/Fehler_korrigieren?campaign=wmde_abc2017_bt2
# - Landing Page, Specific Tasks, Banner bt3:
# - https://de.wikipedia.org/wiki/Wikipedia:Wikimedia_Deutschland/Fehler_korrigieren?campaign=wmde_abc2017_bt3
# - Landing Page, General, Banner gib_lp
# - https://de.wikipedia.org/wiki/Wikipedia:Wikimedia_Deutschland/Mach_mit?campaign=wmde_abc2017_gib_lp
# - Registration Page, banner gib_rg
# - https://de.wikipedia.org/wiki/Spezial:Benutzerkonto_anlegen?campaign=wmde_abc2017_gib_rg

# campaignQuery <- c('campaign=wmde_abc2017_bt1&wmdesource=bannerclick',
#                    'campaign=wmde_abc2017_bt2&wmdesource=bannerclick',
#                    'campaign=wmde_abc2017_bt3&wmdesource=bannerclick',
#                    'campaign=wmde_abc2017_gib_lp&wmdesource=bannerclick',
#                    'campaign=wmde_abc2017_gib_rg&wmdesource=bannerclick')

### --- loop over date range, create query, fetch, and store
dateRange <- seq(from = as.Date(startDate),
                 to = as.Date(endDate),
                 by = 'day')
dateRange <- as.character(dateRange)
# - set outDir
outDir <- bannerClicksDir
# - store query dir:
qDir <- bannerClicksDir
setwd(qDir)
# - set HiveQL query dir:
for (i in 1:length(dateRange)) {
  # - construct HiveQL query:
  y <- as.numeric(strsplit(dateRange[i], split = "-")[[1]][1])
  m <- as.numeric(strsplit(dateRange[i], split = "-")[[1]][2])
  d <- as.numeric(strsplit(dateRange[i], split = "-")[[1]][3])
  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/Fehler_korrigieren' OR uri_path = '/wiki/Wikipedia:Wikimedia_Deutschland/Mach_mit' OR uri_path = '/wiki/Spezial:Benutzerkonto_anlegen')
    AND year = ", y,
    " AND month = ", m,
    " AND day = ", d, ");",
    sep = "")
  # - write hql
  write(q, 'abc2017_BannerClicks.hql')
  # - prepare output file:
  fileName <- "abc2017_BannerClicks_"
  fileName <- paste0(fileName, dateRange[i], ".tsv")
  fileName <- paste0(outDir, "/", fileName)
  # - execute hql script:
  hiveArgs <-
    'beeline -f'
  hiveInput <- paste0('abc2017_BannerClicks.hql > ',
                      fileName)
  # - command:
  hiveCommand <- paste(hiveArgs, hiveInput)
  system(command = hiveCommand, wait = TRUE)
}

### --- Wrangle this dataset:

### --- Landing pages:
specTaskPage <- '/wiki/Wikipedia:Wikimedia_Deutschland/Fehler_korrigieren'
genInvPage <- '/wiki/Wikipedia:Wikimedia_Deutschland/Mach_mit'
regPage <- '/wiki/Spezial:Benutzerkonto_anlegen'

### --- Banner tags:
specTaskBanner1 <- '?campaign=wmde_abc2017_bt1'
specTaskBanner2 <- '?campaign=wmde_abc2017_bt2'
specTaskBanner3 <- '?campaign=wmde_abc2017_bt3'
genInvPage_rg <- '?campaign=wmde_abc2017_gib_rg'
genInvPage_lp <- '?campaign=wmde_abc2017_gib_lp'

### --- Dataset:
# - count non-empty files:
c <- 0
lF <- list.files()
lF <- lF[grepl('.tsv', lF, fixed = T)]
dataSet <- list()
for (i in 1:length(lF)) {
  dS <- readLines(lF[i], n = -1)
  dS <- dS[8:(length(dS)-2)]
  if (length(dS > 0)) {
    c <- c + 1
    dS <- lapply(dS, function(x) {
      dat <- strsplit(x, split = "\t", fixed = T)[[1]]
      data.frame(page = dat[1], banner = dat[2], refer = dat[3], stringsAsFactors = F)
    })
  }
  dS <- rbindlist(dS)
  dS$date <- strsplit(
    strsplit(lF[i], split = "_", fixed = T)[[1]][3],
    split = ".",
    fixed = T)[[1]][1]
  dataSet[[c]] <- dS
  rm(dS); gc()
}
dataSet <- rbindlist(dataSet)
# - replace values:
dataSet$page <- sapply(dataSet$page, function(x) {
  strsplit(x, split = "/", fixed = T)[[1]][length(strsplit(x, split = "/", fixed = T)[[1]])]
})
dataSet$banner[which(dataSet$banner %in% specTaskBanner1)] <- 'BT1'
dataSet$banner[which(dataSet$banner %in% specTaskBanner2)] <- 'BT2'
dataSet$banner[which(dataSet$banner %in% specTaskBanner3)] <- 'BT3'
dataSet$banner[which(dataSet$banner %in% genInvPage_rg)] <- 'GIP_RG'
dataSet$banner[which(dataSet$banner %in% genInvPage_lp)] <- 'GIP_LP'
dataSet$banner <- paste(dataSet$banner, "_click", sep = "")
dataSet$banner[which(!(dataSet$banner %in% c('BT1_click', 'BT2_click', 'BT3_click', 'GIP_RG_click', 'GIP_LP_click')))] <- 
  'Other'
colnames(dataSet) <- c('Page', 'Source', 'Referer', 'Date')
dataSet$Source[dataSet$Page %in% 'Spezial:Benutzerkonto_anlegen' & dataSet$Source == 'Other'] <- 
  str_extract(dataSet$Referer[dataSet$Page %in% 'Spezial:Benutzerkonto_anlegen' & dataSet$Source == 'Other'],
              "campaign=wmde_abc(.)+$")
dataSet$Source[dataSet$Page %in% 'Spezial:Benutzerkonto_anlegen' & grepl("wmde_abc2017_bt1", dataSet$Source)] <- "Fehler_korrigieren_BT1"
dataSet$Source[dataSet$Page %in% 'Spezial:Benutzerkonto_anlegen' & grepl("wmde_abc2017_bt2", dataSet$Source)] <- "Fehler_korrigieren_BT2"
dataSet$Source[dataSet$Page %in% 'Spezial:Benutzerkonto_anlegen' & grepl("wmde_abc2017_bt3", dataSet$Source)] <- "Fehler_korrigieren_BT3"
dataSet$Source[dataSet$Page %in% 'Spezial:Benutzerkonto_anlegen' & grepl("wmde_abc2017_gib_rg", dataSet$Source)] <- "GIP_RG_click"
dataSet$Source[dataSet$Page %in% 'Spezial:Benutzerkonto_anlegen' & grepl("wmde_abc2017_gib_lp", dataSet$Source)] <- "Mach_mit"
dataSet$Source[dataSet$Page %in% 'Spezial:Benutzerkonto_anlegen' & dataSet$Referer %in% '-'] <- "Unknown"
dataSet$Source[dataSet$Page %in% 'Mach_mit' & dataSet$Referer %in% '-'] <- "Unknown"
dataSet$Source[dataSet$Page %in% 'Fehler_korrigieren' & dataSet$Referer %in% '-'] <- "Unknown"
dataSet$Source[is.na(dataSet$Source)] <- 'Other'
dataSet$Referer <- NULL

### --- store abc_BannerClicksPageViews_Update.csv
setwd(dailyUpdateDir)
write.csv(dataSet, file = "abc_BannerClicksPageViews_Update.csv")

### -----------------------------------------------------------------------------
### 3. User Registration Data
### -----------------------------------------------------------------------------

# - ServerSideAccountCreation_5487345
qCommand <- "mysql --defaults-file=/etc/mysql/conf.d/analytics-research-client.cnf -h analytics-store.eqiad.wmnet -A -e \"select * from log.ServerSideAccountCreation_5487345 where ((webHost = 'de.wikipedia.org') and (timestamp >= 20170920000000));\" > /home/goransm/_miscWMDE/abc2017_DataOUT/abc2017_OfficialDatasets/abc2017_DailyUpdate/abc2017_userRegistrations.tsv"
system(command = qCommand, wait = TRUE)

### -----------------------------------------------------------------------------
### 4. Guided Tour Data
### -----------------------------------------------------------------------------

### -----------------------------------------------------------------------------
### 5. User Edits Data
### -----------------------------------------------------------------------------

1. Campaign Banners

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

1.2.0 The Dataset

dataSet <- read.csv(paste('./_dailyUpdateDATA/', 'abc_BannerClicksPageViews_Update.csv', sep = ""),
                    header = T,
                    check.names = F,
                    row.names = 1,
                    stringsAsFactors = F)
# - Chart colors
chartCols <- c('indianred1', 'indianred2', 'indianred3',
               'cadetblue', 'cadetblue2', 
               'deepskyblue', 'violetred1', 'violetred2', 'violetred3',
               'lightslategrey', 'lightgrey')
names(chartCols) <- c('BT1_click', 'BT2_click', 'BT3_click',
                                                    'GIP_LP_click', 'GIP_RG_click',
                                                    'Mach_Mit', 'Fehler_korrigieren_BT1', 'Fehler_korrigieren_BT2', 'Fehler_korrigieren_BT3',
                                                    'Other', 'Unknown')
dataSet$Source <- factor(dataSet$Source, levels = c('BT1_click', 'BT2_click', 'BT3_click',
                                                    'GIP_LP_click', 'GIP_RG_click',
                                                    'Mach_Mit', 'Fehler_korrigieren_BT1', 'Fehler_korrigieren_BT2', 'Fehler_korrigieren_BT3',
                                                    'Other', 'Unknown'))
# - Page Chart Colors
pageChartColors <- c('orange', 'deepskyblue', 'lightgreen')
names(pageChartColors) <- c('Fehler_korrigieren', 'Spezial:Benutzerkonto_anlegen', 'Mach_mit')
dataSet$Page <- factor(dataSet$Page, 
                       levels = c('Fehler_korrigieren', 'Spezial:Benutzerkonto_anlegen', 'Mach_mit'))
# - Campaign Chart Colors
campaignChartColors <- c('indianred1', 'indianred2', 'indianred3',
               'cadetblue', 'cadetblue2')
names(campaignChartColors) <- c('BT1', 'BT2', 'BT3', 'GIP_LP', 'GIP_RG')

1.2.1 Landing Pages: Referers

The following charts represents the breakdown of referers (i.e. sources) for the campaign pages: one registration page, and two landing pages.

### --- Banner clicks and Landing Page Views
# - Table Report
tableSet <- dataSet %>%
  dplyr::group_by(Page, Source, Date) %>% 
  dplyr::summarise(Count = n()) %>% 
  dplyr::arrange(Date, Page, Source)
ggplot(tableSet, aes(x = Page,
                    y = Count,
                    group = Source,
                    color = Source,
                    fill = Source,
                    label = Count)) +
  geom_bar(stat = "identity", 
           position = "dodge", 
           width = .35) +
  scale_fill_manual("legend", values = chartCols) +
  scale_color_manual("legend", values = chartCols) +
  ggtitle('Autumn Banner Campaign 2017:\nBreakdown of Landing Page Views sources') +
  theme_minimal() + 
  theme(axis.text.x = element_text(angle = 90, size = 8, hjust = 1)) +
  theme(plot.title = element_text(size = 10)) +
  theme(legend.title = element_blank()) +
  theme(panel.grid.major.x = element_blank()) +
  theme(panel.grid.minor.x = element_blank()) +
  theme(panel.background = element_blank())

1.2.2 Landing Pages: Referer Breakdown

The following three pie charts present a breakdown of referers (i.e. sources) for the Campaign pages (two landing pages and one registration page.

### --- Page Views: Sources
# - Spezial:Benutzerkonto_anlegen
pageSource <- dataSet %>% 
  dplyr::count(Page, Source) %>%
  dplyr::group_by(Page) %>% 
  dplyr::mutate(Percent = n/sum(n))
pageSource$Percent <- paste(round(pageSource$Percent*100, 2), "%", sep = "")
pageSourcePlot <- filter(pageSource, Page %in% 'Spezial:Benutzerkonto_anlegen')
ggplot(pageSourcePlot, aes(x = '',
                           y = n,
                           color = Source,
                           fill = Source,
                           label = Percent)) +
  geom_bar(aes(x = '',
               y = n,
               color = Source,
               fill = Source), 
           stat = "identity", 
           width = 1) +
  coord_polar("y", start = 0) +
  geom_text(aes(x = 1),
            colour = "white",
            fontface = "bold",
            position = position_stack(vjust = 0.5),
            size = 3,
            show.legend = F) +
  scale_fill_manual("legend", values = chartCols) +
  scale_color_manual("legend", values = chartCols) +
  ggtitle('Autumn Banner Campaign 2017:\nPage Views Sources for Spezial:Benutzerkonto_anlegen') +
  xlab("Outter = Count") + ylab("") +
  theme_minimal() + 
  # theme(axis.text.x = element_blank()) +
  theme(plot.title = element_text(size = 10)) +
  theme(legend.title = element_blank()) +
  theme(panel.grid.major.y = element_blank()) +
  theme(panel.grid.minor.y = element_blank())

# - Spezial:Benutzerkonto_anlegen - Unknown/Other
pageSource <- dataSet %>% 
  filter(!(dataSet$Source %in% 'Other' | dataSet$Source %in% 'Unknown')) %>%
  dplyr::count(Page, Source) %>%
  dplyr::group_by(Page) %>% 
  dplyr::mutate(Percent = n/sum(n))
pageSource$Percent <- paste(round(pageSource$Percent*100, 2), "%", sep = "")
pageSourcePlot <- filter(pageSource, Page %in% 'Spezial:Benutzerkonto_anlegen')
ggplot(pageSourcePlot, aes(x = '',
                           y = n,
                           color = Source,
                           fill = Source,
                           label = Percent)) +
  geom_bar(aes(x = '',
               y = n,
               color = Source,
               fill = Source), 
           stat = "identity", 
           width = 1) +
  coord_polar("y", start = 0) +
  geom_text(aes(x = 1),
            colour = "white",
            fontface = "bold",
            position = position_stack(vjust = 0.5),
            size = 3,
            show.legend = F) +
  scale_fill_manual("legend", values = chartCols) +
  scale_color_manual("legend", values = chartCols) +
  ggtitle('Autumn Banner Campaign 2017:\nPage Views Sources for Spezial:Benutzerkonto_anlegen (Campaign only)') +
  xlab("Outter = Count") + ylab("") +
  theme_minimal() + 
  # theme(axis.text.x = element_blank()) +
  theme(plot.title = element_text(size = 10)) +
  theme(legend.title = element_blank()) +
  theme(panel.grid.major.y = element_blank()) +
  theme(panel.grid.minor.y = element_blank())

# - Fehler_korrigieren
pageSource <- dataSet %>% 
  dplyr::count(Page, Source) %>%
  dplyr::group_by(Page) %>% 
  dplyr::mutate(Percent = n/sum(n))
pageSource$Percent <- paste(round(pageSource$Percent*100, 2), "%", sep = "")
pageSourcePlot <- filter(pageSource, Page %in% 'Fehler_korrigieren')
ggplot(pageSourcePlot, aes(x = '',
                           y = n,
                           color = Source,
                           fill = Source,
                           label = Percent)) +
  geom_bar(aes(x = '',
               y = n,
               color = Source,
               fill = Source), 
           stat = "identity", 
           width = 1) +
  coord_polar("y", start = 0) +
  geom_text(aes(x = 1),
            colour = "white",
            fontface = "bold",
            position = position_stack(vjust = 0.5),
            size = 3,
            show.legend = F) +
  scale_fill_manual("legend", values = chartCols) +
  scale_color_manual("legend", values = chartCols) +
  ggtitle('Autumn Banner Campaign 2017:\nPage Views Sources for Fehler_korrigieren') +
  xlab("Outter = Count") + ylab("") +
  theme_minimal() + 
  # theme(axis.text.x = element_blank()) +
  theme(plot.title = element_text(size = 10)) +
  theme(legend.title = element_blank()) +
  theme(panel.grid.major.y = element_blank()) +
  theme(panel.grid.minor.y = element_blank()) +
  theme(panel.background = element_blank())

# - Fehler_korrigieren - minus Unknown/Other
pageSource <- dataSet %>%
  filter(!(dataSet$Source %in% 'Other' | dataSet$Source %in% 'Unknown')) %>%
  dplyr::count(Page, Source) %>%
  dplyr::group_by(Page) %>% 
  dplyr::mutate(Percent = n/sum(n))
pageSource$Percent <- paste(round(pageSource$Percent*100, 2), "%", sep = "")
pageSourcePlot <- filter(pageSource, Page %in% 'Fehler_korrigieren')
ggplot(pageSourcePlot, aes(x = '',
                           y = n,
                           color = Source,
                           fill = Source,
                           label = Percent)) +
  geom_bar(aes(x = '',
               y = n,
               color = Source,
               fill = Source), 
           stat = "identity", 
           width = 1) +
  coord_polar("y", start = 0) +
  geom_text(aes(x = 1),
            colour = "white",
            fontface = "bold",
            position = position_stack(vjust = 0.5),
            size = 3,
            show.legend = F) +
  scale_fill_manual("legend", values = chartCols) +
  scale_color_manual("legend", values = chartCols) +
  ggtitle('Autumn Banner Campaign 2017:\nPage Views Sources for Fehler_korrigieren (Campaign only)') +
  xlab("Outter = Count") + ylab("") +
  theme_minimal() + 
  # theme(axis.text.x = element_blank()) +
  theme(plot.title = element_text(size = 10)) +
  theme(legend.title = element_blank()) +
  theme(panel.grid.major.y = element_blank()) +
  theme(panel.grid.minor.y = element_blank()) +
  theme(panel.background = element_blank())

# - Mach_mit
pageSource <- dataSet %>% 
  dplyr::count(Page, Source) %>%
  dplyr::group_by(Page) %>% 
  dplyr::mutate(Percent = n/sum(n))
pageSource$Percent <- paste(round(pageSource$Percent*100, 2), "%", sep = "")
pageSourcePlot <- filter(pageSource, Page %in% 'Mach_mit')
ggplot(pageSourcePlot, aes(x = '',
                           y = n,
                           color = Source,
                           fill = Source,
                           label = Percent)) +
  geom_bar(aes(x = '',
               y = n,
               color = Source,
               fill = Source), 
           stat = "identity", 
           width = 1) +
  coord_polar("y", start = 0) +
  geom_text(aes(x = 1),
            colour = "white",
            fontface = "bold",
            position = position_stack(vjust = 0.5),
            size = 3,
            show.legend = F) +
  scale_fill_manual("legend", values = chartCols) +
  scale_color_manual("legend", values = chartCols) +
  ggtitle('Autumn Banner Campaign 2017:\nPage Views Sources for Mach_mit') +
  xlab("Outter = Count") + ylab("") +
  theme_minimal() + 
  # theme(axis.text.x = element_blank()) +
  theme(plot.title = element_text(size = 10)) +
  theme(legend.title = element_blank()) +
  theme(panel.grid.major.y = element_blank()) +
  theme(panel.grid.minor.y = element_blank()) +
  theme(panel.background = element_blank())

# - Mach_mit - minus Unknown/Other
pageSource <- dataSet %>% 
  filter(!(dataSet$Source %in% 'Other' | dataSet$Source %in% 'Unknown')) %>%
  dplyr::count(Page, Source) %>%
  dplyr::group_by(Page) %>% 
  dplyr::mutate(Percent = n/sum(n))
pageSource$Percent <- paste(round(pageSource$Percent*100, 2), "%", sep = "")
pageSourcePlot <- filter(pageSource, Page %in% 'Mach_mit')
ggplot(pageSourcePlot, aes(x = '',
                           y = n,
                           color = Source,
                           fill = Source,
                           label = Percent)) +
  geom_bar(aes(x = '',
               y = n,
               color = Source,
               fill = Source), 
           stat = "identity", 
           width = 1) +
  coord_polar("y", start = 0) +
  geom_text(aes(x = 1),
            colour = "white",
            fontface = "bold",
            position = position_stack(vjust = 0.5),
            size = 3,
            show.legend = F) +
  scale_fill_manual("legend", values = chartCols) +
  scale_color_manual("legend", values = chartCols) +
  ggtitle('Autumn Banner Campaign 2017:\nPage Views Sources for Mach_mit') +
  xlab("Outter = Count") + ylab("") +
  theme_minimal() + 
  # theme(axis.text.x = element_blank()) +
  theme(plot.title = element_text(size = 10)) +
  theme(legend.title = element_blank()) +
  theme(panel.grid.major.y = element_blank()) +
  theme(panel.grid.minor.y = element_blank()) +
  theme(panel.background = element_blank())

1.2.4 Page Views: Campaign Total

The following chart presents the number of page views for the two landing pages and one registration page during the course of the campaign, and encompassing only page views generated from the campaign.

### --- Temporal Page Views
# - Chart
pagePlotSet <- dataSet %>% 
  filter(!(dataSet$Source %in% 'Other' | dataSet$Source %in% 'Unknown')) %>%
  dplyr::select(Page, Date) %>%
  dplyr::group_by(Page, Date) %>% 
  dplyr::summarise(Count = n()) %>% 
  dplyr::arrange(Date)
ggplot(pagePlotSet, aes(x = Date,
                        y = Count,
                        group = Page,
                        color = Page,
                        fill = Page,
                        label = Count)) +
  geom_bar(stat = "identity", 
           position = "dodge", 
           width = .2) +
  scale_fill_manual("legend", values = pageChartColors) +
  scale_color_manual("legend", values = pageChartColors) +
  ggtitle('Autumn Banner Campaign 2017: Page Views') +
  theme_minimal() + 
  theme(axis.text.x = element_text(angle = 90, size = 8, hjust = 1)) +
  theme(plot.title = element_text(size = 10)) +
  theme(legend.title = element_blank()) +
  theme(panel.grid.major.x = element_blank()) +
  theme(panel.grid.minor.x = element_blank()) +
  theme(panel.background = element_blank())

1.2.4 Page Views/Banner Clicks Dataset

The Page column refers to either one of the two campaign landing pages or the registration page. The Source column encompasses both campaign banner clicks and campaign pages as referers of the Page. The Count data have a daily resolution.

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

2. Campaign User Registrations

2.1 Analyze User Registration Data

### --- Campaign User Registrations
lF <- list.files(path = "./_dailyUpdateDATA/")
lF <- lF[grepl('userRegistrations', lF, fixed = T)]
userReg <- read.table(paste("./userRegDATA/", lF, sep = ""),
                      sep = "\t",
                      header = T,
                      check.names = F,
                      stringsAsFactors = F)
EOF within quoted string
userReg$timestamp <- as.character(userReg$timestamp)
userReg$timestamp <- sapply(userReg$timestamp, function(x) {
  y <- substr(x, 1, 4)
  m <- substr(x, 5, 6)
  d <- substr(x, 7, 8)
  paste(y, m, d, sep = "-")
})
userReg <- userReg %>% 
  dplyr::select(id, event_userId, timestamp, event_isSelfMade, event_campaign) %>% 
  filter(event_isSelfMade == 1)
regPlotSet <- userReg %>% 
  dplyr::filter(event_isSelfMade == 1 & grepl("wmde_abc2017", event_campaign)) %>% 
  group_by(event_campaign, timestamp) %>% 
  summarise(Registrations = n()) %>% 
  arrange(timestamp)
colnames(regPlotSet) <- c('Campaign', 'Date', 'Registrations')
regPlotSet$Campaign <- sapply(regPlotSet$Campaign, function(x) {
  out <- toupper(strsplit(x, split = "_", fixed = T)[[1]][3])
})
ggplot(regPlotSet, aes(x = Date,
                       y = Registrations,
                       group = Campaign,
                       color = Campaign,
                       fill = Campaign,
                       label = Registrations)) +
  geom_bar(stat = "identity", 
           position = "dodge", 
           width = .5) +
  scale_fill_manual("legend", values = campaignChartColors) +
  scale_color_manual("legend", values = campaignChartColors) +
  ggtitle('Autumn Banner Campaign 2017: User Registrations') +
  theme_minimal() + 
  theme(axis.text.x = element_text(angle = 90, size = 8, hjust = 1)) +
  theme(plot.title = element_text(size = 10)) +
  theme(legend.title = element_blank()) +
  theme(panel.grid.major.x = element_blank()) +
  theme(panel.grid.minor.x = element_blank()) +
  theme(panel.background = element_blank())

3. Campaign Guided Tour

3.1 Collect Guided Tour Data

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

### --- NOTE:
# For the guided tours it would be great to have two numbers:
# 
#     Number of people who started the guided tour / completed the first step /and than did whatever (exited, or not)
#     Number of people who completed the guided tour


# log.GuidedTourExited_8690566
# https://meta.wikimedia.org/wiki/Schema:GuidedTourExited
# ALSO TAKE A LOOK AT: log.GuidedTourGuiderHidden_8690549
# ALSO TAKE A LOOK AT: https://meta.wikimedia.org/wiki/Schema:GuidedTourGuiderHidden

### 2.1 Collect User Registration Data
### --- Script: abc2017_PROD_GuidedTour.R
### --- the following runs on stat1005.eqiad.wmnet
### --- Rscript /home/goransm/RScripts/abc2017/abc2017_PROD_Registrations.R

# - ServerSideAccountCreation_5487345
qCommand <- "mysql --defaults-file=/etc/mysql/conf.d/analytics-research-client.cnf -h analytics-store.eqiad.wmnet -A -e \"select * from log.GuidedTourExited_8690566 where ((webHost = 'de.wikipedia.org') and (timestamp >= 20170920000000));\" > /home/goransm/_miscWMDE/abc2017_DataOUT/abc_test/abc2017_guidedTours.tsv"
system(command = qCommand, wait = TRUE)

3.2 Analyze Guided Tour Data

4. User Edits

5. Campaign Evaluation

5.1 Campaign Multi-Channel Attribution Model

5.2 Campaign Causal Impact

LS0tCnRpdGxlOiAnQXV0dW1uIEJhbm5lciBDYW1wYWlnbiAyMDE3OiBSZXBvcnQnCmF1dGhvcjogIkdvcmFuIFMuIE1pbG92YW5vdmljLCBEYXRhIEFuYWx5c3QsIFdNREUiCmRhdGU6ICJTZXB0ZW1iZXIvT2N0b2JlciwgMjAxNyIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIHRoZW1lOiBzaW1wbGV4CiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiA0CiAgICB0b2NfZmxvYXQ6IHllcwogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiA0Ci0tLQoKCioqTk9URToqKiBGZWVkYmFjayBzaG91bGQgYmUgc2VuZCB0byBgZ29yYW4ubWlsb3Zhbm92aWNfZXh0QHdpa2ltZWRpYS5kZWAuIAoKKipOT1RFOioqIFRoZSBjYW1wYWlnbiB3aWxsIGJlIHJ1biBmcm9tIC4uLiB0byAuLi4gb2YgT2N0b2JlciAyMDE3LgoKYGBge3IsIGVjaG8gPSBGLCB3YXJuaW5nID0gRiwgbWVzc2FnZSA9IEYsIHJlc3VsdHMgPSAnaGlkZSd9CiMjIyAtLS0gU2V0dXAKcm0obGlzdCA9IGxzKCkpCmxpYnJhcnkoc3RyaW5ncikKbGlicmFyeShkcGx5cikKbGlicmFyeSh0aWR5cikKbGlicmFyeShkYXRhLnRhYmxlKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpsaWJyYXJ5KGthYmxlRXh0cmEpCmxpYnJhcnkocm1hcmtkb3duKQpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KERUKQpsaWJyYXJ5KHJlc2hhcGUyKQpsaWJyYXJ5KHpvbykKbGlicmFyeShDYXVzYWxJbXBhY3QpCmBgYAoKIyMgMC4gRGF0YSBBY3F1aXNpdG9uCgoqKk5PVEU6KiogdGhlIERhdGEgQWNxdWlzaXRpb24gY29kZSBjaHVuayBpcyBub3QgZnVsbHkgcmVwcm9kdWNpYmxlIGZyb20gdGhpcyBSZXBvcnQuIFRoZSBkYXRhIGFyZSBjb2xsZWN0ZWQgYnkgcnVubmluZyB0aGUgc2NyaXB0IGBhYmMyMDE3X1BST0RfT3ZlcmFsbERhaWx5VXBkYXRlLlJgIG9uIHN0YXQxMDA1LmVxaWFkLndtbmV0LCBjb2xsZWN0aW5nIHRoZSBkYXRhIGFzIGAudHN2YCBhbmQgYC5jc3ZgIGZpbGVzLCBjb3B5aW5nIG1hbnVhbGx5LCBhbmQgcHJvY2Vzc2luZyBsb2NhbGx5LiBSdW4gZnJvbSBzdGF0MTAwNSBzdGF0IGJveCBieSBleGVjdXRpbmcgYFJzY3JpcHQgL2hvbWUvZ29yYW5zbS9SU2NyaXB0cy9hYmMyMDE3L2FiYzIwMTdfUFJPRF9PdmVyYWxsRGFpbHlVcGRhdGUuUmAuCgpgYGB7ciwgZWNobyA9IFQsIGV2YWwgPSBGfQojIyMgLS0tIFNjcmlwdDogYWJjMjAxN19QUk9EX092ZXJhbGxEYWlseVVwZGF0ZS5SCiMjIyAtLS0gdGhlIGZvbGxvd2luZyBydW5zIG9uIHN0YXQxMDA1LmVxaWFkLndtbmV0CiMjIyAtLS0gUnNjcmlwdCAvaG9tZS9nb3JhbnNtL1JTY3JpcHRzL2FiYzIwMTcvYWJjMjAxN19QUk9EX092ZXJhbGxEYWlseVVwZGF0ZS5SCgojIyMgLS0tIFRoZSBzY3JpcHQgY29sbGVjdHMgYW5kIHdyYW5nbGVzIGFsbCBkYXRhc2V0cwojIyMgLS0tIGZvciB0aGUgV01ERSBBdXR1bW4gQmFubmVyIENhbXBhaWduIDIwMTcuCgojIyMgLS0tIEdvcmFuIFMuIE1pbG92YW5vdmljLCBEYXRhIEFuYWx5c3QsIFdNREUKIyMjIC0tLSBTZXB0ZW1iZXIgMjYsIDIwMTcuCgojIyMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyMjIDAuIFNldHVwCiMjIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKcm0obGlzdCA9IGxzKCkpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkoc3RyaW5ncikKbGlicmFyeShkYXRhLnRhYmxlKQpzdGFydERhdGUgPC0gJzIwMTctMDktMjAnCmVuZERhdGUgPC0gJzIwMTctMDktMjYnCmJhbm5lckltcHJlc3Npb21uc0RpciA8LSAnL2hvbWUvZ29yYW5zbS9fbWlzY1dNREUvYWJjMjAxN19EYXRhT1VUL2FiYzIwMTdfT2ZmaWNpYWxEYXRhc2V0cy9hYmMyMDE3QmFubmVySW1wcmVzc2lvbnMvJwpiYW5uZXJDbGlja3NEaXIgPC0gJy9ob21lL2dvcmFuc20vX21pc2NXTURFL2FiYzIwMTdfRGF0YU9VVC9hYmMyMDE3X09mZmljaWFsRGF0YXNldHMvYWJjMjAxN0Jhbm5lckNsaWNrc0xhbmRpbmdQYWdlcy8nCnVzZXJSZWdEaXIgPC0gJy9ob21lL2dvcmFuc20vX21pc2NXTURFL2FiYzIwMTdfRGF0YU9VVC9hYmMyMDE3X09mZmljaWFsRGF0YXNldHMvYWJjMjAxN1VzZXJSZWcvJwpkYWlseVVwZGF0ZURpciA8LSAnL2hvbWUvZ29yYW5zbS9fbWlzY1dNREUvYWJjMjAxN19EYXRhT1VUL2FiYzIwMTdfT2ZmaWNpYWxEYXRhc2V0cy9hYmMyMDE3X0RhaWx5VXBkYXRlLycgCgojIyMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyMjIDEuIEJhbm5lciBJbXByZXNzaW9ucwojIyMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMjIyAtLS0gQ2FtcGFpZ24gQmFubmVyIFRhZ3M6CiMgLSAoMSkgP2NhbXBhaWduPXdtZGVfYWJjMjAxN19idDEgLSBiYW5uZXIgZm9yIFNwZWNpZmljIFRhc2sgMTsKIyAtICgyKSA/Y2FtcGFpZ249d21kZV9hYmMyMDE3X2J0MiAtIGJhbm5lciBmb3IgU3BlY2lmaWMgVGFzayAyOwojIC0gKDMpID9jYW1wYWlnbj13bWRlX2FiYzIwMTdfYnQzIC0gYmFubmVyIGZvciBTcGVjaWZpYyBUYXNrIDM7CiMgLSAoNCkgP2NhbXBhaWduPXdtZGVfYWJjMjAxN19naWJfbHAgLSBiYW5uZXIgZm9yIHRoZSBHZW5lcmFsIEludml0YXRpb24gCiMgLSB3aGljaCBsZWFkcyB0byB0aGUgTGFuZGluZyBQYWdlIHVwb24gY2xpY2s7CiMgLSAoNSkgP2NhbXBhaWduPXdtZGVfYWJjMjAxN19naWJfcmcgLSBiYW5uZXIgZm9yIHRoZSBHZW5lcmFsIEludml0YXRpb24gCiMgd2hpY2ggbGVhZHMgZGlyZWN0bHkgdG8gUmVnaXN0cmF0aW9uIHVwb24gY2xpY2suCgojIyMgLS0tIGZyb20gd21mLndlYnJlcXVlc3QsIHJ1biB0aGUgZm9sbG93aW5nIHNjcmlwdCBvbiBzdGF0IDEwMDUKIyMjIC0tLSB0byBjb2xsZWN0IGJhbm5lciBpbXByZXNzaW9ucwojIyMgLS0tIFJzY3JpcHQgL2hvbWUvZ29yYW5zbS9SU2NyaXB0cy9hYmMyMDE3L2FiYzIwMTdfUFJPRF9CYW5uZXJJbXByZXNzaW9ucy5SCgojIyMgLS0tIEhpdmVRTCBmb3IgZXZlcnl0aGluZyB3aXRoID9jYW1wYWlnbiBsaWtlICJ3bWRlX2FiYzIwMTciIAojIyMgLS0tIGFuZCB0aGVuIGxvb2sgZm9yIHRoZSBkZXNpcmVkIHRhZ3MuCgojIyMgLS0tIGxvb3Agb3ZlciBkYXRlIHJhbmdlLCBjcmVhdGUgcXVlcnksIGZldGNoLCBhbmQgc3RvcmUKIyBkYXRlUmFuZ2UgPC0gc2VxKGZyb20gPSBhcy5EYXRlKHN0YXJ0RGF0ZSksCiMgICAgICAgICAgICAgICAgICB0byA9IGFzLkRhdGUoZW5kRGF0ZSksCiMgICAgICAgICAgICAgICAgICBieSA9ICdkYXknKQojIGRhdGVSYW5nZSA8LSBhcy5jaGFyYWN0ZXIoZGF0ZVJhbmdlKQojICMgLSBzZXQgb3V0RGlyCiMgb3V0RGlyIDwtIGJhbm5lckltcHJlc3Npb21uc0RpcgojICMgLSBzdG9yZSBxdWVyeSBkaXI6CiMgcURpciA8LSBiYW5uZXJJbXByZXNzaW9tbnNEaXIKIyBzZXR3ZChxRGlyKQojICMgLSBzZXQgSGl2ZVFMIHF1ZXJ5IGRpcjoKIyBmb3IgKGkgaW4gMTpsZW5ndGgoZGF0ZVJhbmdlKSkgewojICAgIyAtIGNvbnN0cnVjdCBIaXZlUUwgcXVlcnk6CiMgICB5IDwtIGFzLm51bWVyaWMoc3Ryc3BsaXQoZGF0ZVJhbmdlW2ldLCBzcGxpdCA9ICItIilbWzFdXVsxXSkKIyAgIG0gPC0gYXMubnVtZXJpYyhzdHJzcGxpdChkYXRlUmFuZ2VbaV0sIHNwbGl0ID0gIi0iKVtbMV1dWzJdKQojICAgZCA8LSBhcy5udW1lcmljKHN0cnNwbGl0KGRhdGVSYW5nZVtpXSwgc3BsaXQgPSAiLSIpW1sxXV1bM10pCiMgICBxIDwtIHBhc3RlKAojICAgICAiVVNFIHdtZjsKIyAgICAgU0VMRUNUIHVyaV9xdWVyeSBGUk9NIHdlYnJlcXVlc3QKIyAgICAgV0hFUkUgdXJpX2hvc3QgPSAnZGUud2lraXBlZGlhLm9yZycKIyAgICAgQU5EIHVyaV9wYXRoID0gJy9iZWFjb24vaW1wcmVzc2lvbicKIyAgICAgQU5EIHllYXIgPSAiLCB5LAojICAgICAiIEFORCBtb250aCA9ICIsIG0sCiMgICAgICIgQU5EIGRheSA9ICIsIGQsCiMgICAgIHNlcCA9ICIiKQojICAgIyAtIHdyaXRlIGhxbAojICAgd3JpdGUocSwgJ2FiYzIwMTdfQmFubmVySW1wcmVzc2lvbnMuaHFsJykKIyAgICMgLSBwcmVwYXJlIG91dHB1dCBmaWxlOgojICAgZmlsZU5hbWUgPC0gImFiYzIwMTdfQmFubmVySW1wcmVzc2lvbnNfIgojICAgZmlsZU5hbWUgPC0gcGFzdGUwKGZpbGVOYW1lLCBkYXRlUmFuZ2VbaV0sICIudHN2IikKIyAgIGZpbGVOYW1lIDwtIHBhc3RlMChvdXREaXIsICIvIiwgZmlsZU5hbWUpCiMgICAjIC0gZXhlY3V0ZSBocWwgc2NyaXB0OgojICAgaGl2ZUFyZ3MgPC0KIyAgICAgJ2JlZWxpbmUgLWYnCiMgICBoaXZlSW5wdXQgPC0gcGFzdGUwKCdhYmMyMDE3X0Jhbm5lckltcHJlc3Npb25zLmhxbCA+ICcsCiMgICAgICAgICAgICAgICAgICAgICAgIGZpbGVOYW1lKQojICAgIyAtIGNvbW1hbmQ6CiMgICBoaXZlQ29tbWFuZCA8LSBwYXN0ZShoaXZlQXJncywgaGl2ZUlucHV0KQojICAgc3lzdGVtKGNvbW1hbmQgPSBoaXZlQ29tbWFuZCwgd2FpdCA9IFRSVUUpCiMgfQoKIyMjIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiMjIyAyLiBCYW5uZXIgQ2xpY2tzIGFuZCBMYW5kaW5nIFBhZ2UgVmlld3MKIyMjIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIyMgLS0tIGNhbXBhaWduIFVSTAojIC0gaHR0cHM6Ly9kZS53aWtpcGVkaWEub3JnL3dpa2kvV2lraXBlZGlhOldpa2ltZWRpYV9EZXV0c2NobGFuZC9FbnRkZWNrdW5nZW4tc29ydGllcmVuP2NhbXBhaWduPXdtZGUyMDE3c3VtbWVyMSZ3bWRlc291cmNlPWJhbm5lcmNsaWNrCgojIyMgLS0tIENhbXBhaWduIEJhbm5lciBUYWdzOgojIC0gKDEpID9jYW1wYWlnbj13bWRlX2FiYzIwMTdfYnQxIC0gYmFubmVyIGZvciBTcGVjaWZpYyBUYXNrIDE7CiMgLSAoMikgP2NhbXBhaWduPXdtZGVfYWJjMjAxN19idDIgLSBiYW5uZXIgZm9yIFNwZWNpZmljIFRhc2sgMjsKIyAtICgzKSA/Y2FtcGFpZ249d21kZV9hYmMyMDE3X2J0MyAtIGJhbm5lciBmb3IgU3BlY2lmaWMgVGFzayAzOwojIC0gKDQpID9jYW1wYWlnbj13bWRlX2FiYzIwMTdfZ2liX2xwIC0gYmFubmVyIGZvciB0aGUgR2VuZXJhbCBJbnZpdGF0aW9uIAojIC0gd2hpY2ggbGVhZHMgdG8gdGhlIExhbmRpbmcgUGFnZSB1cG9uIGNsaWNrOwojIC0gKDUpID9jYW1wYWlnbj13bWRlX2FiYzIwMTdfZ2liX3JnIC0gYmFubmVyIGZvciB0aGUgR2VuZXJhbCBJbnZpdGF0aW9uIAojIHdoaWNoIGxlYWRzIGRpcmVjdGx5IHRvIFJlZ2lzdHJhdGlvbiB1cG9uIGNsaWNrLgoKIyMjIC0tLSBMYW5kaW5nL1JlZ2lzdHJhdGlvbiBwYWdlczoKIyAtIExhbmRpbmcgUGFnZSwgU3BlY2lmaWMgVGFza3MsIEJhbm5lciBidDE6CiMgLSBodHRwczovL2RlLndpa2lwZWRpYS5vcmcvd2lraS9XaWtpcGVkaWE6V2lraW1lZGlhX0RldXRzY2hsYW5kL0ZlaGxlcl9rb3JyaWdpZXJlbj9jYW1wYWlnbj13bWRlX2FiYzIwMTdfYnQxCiMgLSBMYW5kaW5nIFBhZ2UsIFNwZWNpZmljIFRhc2tzLCBCYW5uZXIgYnQyOgojIC0gaHR0cHM6Ly9kZS53aWtpcGVkaWEub3JnL3dpa2kvV2lraXBlZGlhOldpa2ltZWRpYV9EZXV0c2NobGFuZC9GZWhsZXJfa29ycmlnaWVyZW4/Y2FtcGFpZ249d21kZV9hYmMyMDE3X2J0MgojIC0gTGFuZGluZyBQYWdlLCBTcGVjaWZpYyBUYXNrcywgQmFubmVyIGJ0MzoKIyAtIGh0dHBzOi8vZGUud2lraXBlZGlhLm9yZy93aWtpL1dpa2lwZWRpYTpXaWtpbWVkaWFfRGV1dHNjaGxhbmQvRmVobGVyX2tvcnJpZ2llcmVuP2NhbXBhaWduPXdtZGVfYWJjMjAxN19idDMKIyAtIExhbmRpbmcgUGFnZSwgR2VuZXJhbCwgQmFubmVyIGdpYl9scAojIC0gaHR0cHM6Ly9kZS53aWtpcGVkaWEub3JnL3dpa2kvV2lraXBlZGlhOldpa2ltZWRpYV9EZXV0c2NobGFuZC9NYWNoX21pdD9jYW1wYWlnbj13bWRlX2FiYzIwMTdfZ2liX2xwCiMgLSBSZWdpc3RyYXRpb24gUGFnZSwgYmFubmVyIGdpYl9yZwojIC0gaHR0cHM6Ly9kZS53aWtpcGVkaWEub3JnL3dpa2kvU3BlemlhbDpCZW51dHplcmtvbnRvX2FubGVnZW4/Y2FtcGFpZ249d21kZV9hYmMyMDE3X2dpYl9yZwoKIyBjYW1wYWlnblF1ZXJ5IDwtIGMoJ2NhbXBhaWduPXdtZGVfYWJjMjAxN19idDEmd21kZXNvdXJjZT1iYW5uZXJjbGljaycsCiMgICAgICAgICAgICAgICAgICAgICdjYW1wYWlnbj13bWRlX2FiYzIwMTdfYnQyJndtZGVzb3VyY2U9YmFubmVyY2xpY2snLAojICAgICAgICAgICAgICAgICAgICAnY2FtcGFpZ249d21kZV9hYmMyMDE3X2J0MyZ3bWRlc291cmNlPWJhbm5lcmNsaWNrJywKIyAgICAgICAgICAgICAgICAgICAgJ2NhbXBhaWduPXdtZGVfYWJjMjAxN19naWJfbHAmd21kZXNvdXJjZT1iYW5uZXJjbGljaycsCiMgICAgICAgICAgICAgICAgICAgICdjYW1wYWlnbj13bWRlX2FiYzIwMTdfZ2liX3JnJndtZGVzb3VyY2U9YmFubmVyY2xpY2snKQoKIyMjIC0tLSBsb29wIG92ZXIgZGF0ZSByYW5nZSwgY3JlYXRlIHF1ZXJ5LCBmZXRjaCwgYW5kIHN0b3JlCmRhdGVSYW5nZSA8LSBzZXEoZnJvbSA9IGFzLkRhdGUoc3RhcnREYXRlKSwKICAgICAgICAgICAgICAgICB0byA9IGFzLkRhdGUoZW5kRGF0ZSksCiAgICAgICAgICAgICAgICAgYnkgPSAnZGF5JykKZGF0ZVJhbmdlIDwtIGFzLmNoYXJhY3RlcihkYXRlUmFuZ2UpCiMgLSBzZXQgb3V0RGlyCm91dERpciA8LSBiYW5uZXJDbGlja3NEaXIKIyAtIHN0b3JlIHF1ZXJ5IGRpcjoKcURpciA8LSBiYW5uZXJDbGlja3NEaXIKc2V0d2QocURpcikKIyAtIHNldCBIaXZlUUwgcXVlcnkgZGlyOgpmb3IgKGkgaW4gMTpsZW5ndGgoZGF0ZVJhbmdlKSkgewogICMgLSBjb25zdHJ1Y3QgSGl2ZVFMIHF1ZXJ5OgogIHkgPC0gYXMubnVtZXJpYyhzdHJzcGxpdChkYXRlUmFuZ2VbaV0sIHNwbGl0ID0gIi0iKVtbMV1dWzFdKQogIG0gPC0gYXMubnVtZXJpYyhzdHJzcGxpdChkYXRlUmFuZ2VbaV0sIHNwbGl0ID0gIi0iKVtbMV1dWzJdKQogIGQgPC0gYXMubnVtZXJpYyhzdHJzcGxpdChkYXRlUmFuZ2VbaV0sIHNwbGl0ID0gIi0iKVtbMV1dWzNdKQogIHEgPC0gcGFzdGUoCiAgICAiVVNFIHdtZjsKICAgIFNFTEVDVCB1cmlfcGF0aCwgdXJpX3F1ZXJ5LCByZWZlcmVyIEZST00gd2VicmVxdWVzdAogICAgV0hFUkUgKHVyaV9ob3N0ID0gJ2RlLndpa2lwZWRpYS5vcmcnCiAgICBBTkQgKHVyaV9wYXRoID0gJy93aWtpL1dpa2lwZWRpYTpXaWtpbWVkaWFfRGV1dHNjaGxhbmQvRmVobGVyX2tvcnJpZ2llcmVuJyBPUiB1cmlfcGF0aCA9ICcvd2lraS9XaWtpcGVkaWE6V2lraW1lZGlhX0RldXRzY2hsYW5kL01hY2hfbWl0JyBPUiB1cmlfcGF0aCA9ICcvd2lraS9TcGV6aWFsOkJlbnV0emVya29udG9fYW5sZWdlbicpCiAgICBBTkQgeWVhciA9ICIsIHksCiAgICAiIEFORCBtb250aCA9ICIsIG0sCiAgICAiIEFORCBkYXkgPSAiLCBkLCAiKTsiLAogICAgc2VwID0gIiIpCiAgIyAtIHdyaXRlIGhxbAogIHdyaXRlKHEsICdhYmMyMDE3X0Jhbm5lckNsaWNrcy5ocWwnKQogICMgLSBwcmVwYXJlIG91dHB1dCBmaWxlOgogIGZpbGVOYW1lIDwtICJhYmMyMDE3X0Jhbm5lckNsaWNrc18iCiAgZmlsZU5hbWUgPC0gcGFzdGUwKGZpbGVOYW1lLCBkYXRlUmFuZ2VbaV0sICIudHN2IikKICBmaWxlTmFtZSA8LSBwYXN0ZTAob3V0RGlyLCAiLyIsIGZpbGVOYW1lKQogICMgLSBleGVjdXRlIGhxbCBzY3JpcHQ6CiAgaGl2ZUFyZ3MgPC0KICAgICdiZWVsaW5lIC1mJwogIGhpdmVJbnB1dCA8LSBwYXN0ZTAoJ2FiYzIwMTdfQmFubmVyQ2xpY2tzLmhxbCA+ICcsCiAgICAgICAgICAgICAgICAgICAgICBmaWxlTmFtZSkKICAjIC0gY29tbWFuZDoKICBoaXZlQ29tbWFuZCA8LSBwYXN0ZShoaXZlQXJncywgaGl2ZUlucHV0KQogIHN5c3RlbShjb21tYW5kID0gaGl2ZUNvbW1hbmQsIHdhaXQgPSBUUlVFKQp9CgojIyMgLS0tIFdyYW5nbGUgdGhpcyBkYXRhc2V0OgoKIyMjIC0tLSBMYW5kaW5nIHBhZ2VzOgpzcGVjVGFza1BhZ2UgPC0gJy93aWtpL1dpa2lwZWRpYTpXaWtpbWVkaWFfRGV1dHNjaGxhbmQvRmVobGVyX2tvcnJpZ2llcmVuJwpnZW5JbnZQYWdlIDwtICcvd2lraS9XaWtpcGVkaWE6V2lraW1lZGlhX0RldXRzY2hsYW5kL01hY2hfbWl0JwpyZWdQYWdlIDwtICcvd2lraS9TcGV6aWFsOkJlbnV0emVya29udG9fYW5sZWdlbicKCiMjIyAtLS0gQmFubmVyIHRhZ3M6CnNwZWNUYXNrQmFubmVyMSA8LSAnP2NhbXBhaWduPXdtZGVfYWJjMjAxN19idDEnCnNwZWNUYXNrQmFubmVyMiA8LSAnP2NhbXBhaWduPXdtZGVfYWJjMjAxN19idDInCnNwZWNUYXNrQmFubmVyMyA8LSAnP2NhbXBhaWduPXdtZGVfYWJjMjAxN19idDMnCmdlbkludlBhZ2VfcmcgPC0gJz9jYW1wYWlnbj13bWRlX2FiYzIwMTdfZ2liX3JnJwpnZW5JbnZQYWdlX2xwIDwtICc/Y2FtcGFpZ249d21kZV9hYmMyMDE3X2dpYl9scCcKCiMjIyAtLS0gRGF0YXNldDoKIyAtIGNvdW50IG5vbi1lbXB0eSBmaWxlczoKYyA8LSAwCmxGIDwtIGxpc3QuZmlsZXMoKQpsRiA8LSBsRltncmVwbCgnLnRzdicsIGxGLCBmaXhlZCA9IFQpXQpkYXRhU2V0IDwtIGxpc3QoKQpmb3IgKGkgaW4gMTpsZW5ndGgobEYpKSB7CiAgZFMgPC0gcmVhZExpbmVzKGxGW2ldLCBuID0gLTEpCiAgZFMgPC0gZFNbODoobGVuZ3RoKGRTKS0yKV0KICBpZiAobGVuZ3RoKGRTID4gMCkpIHsKICAgIGMgPC0gYyArIDEKICAgIGRTIDwtIGxhcHBseShkUywgZnVuY3Rpb24oeCkgewogICAgICBkYXQgPC0gc3Ryc3BsaXQoeCwgc3BsaXQgPSAiXHQiLCBmaXhlZCA9IFQpW1sxXV0KICAgICAgZGF0YS5mcmFtZShwYWdlID0gZGF0WzFdLCBiYW5uZXIgPSBkYXRbMl0sIHJlZmVyID0gZGF0WzNdLCBzdHJpbmdzQXNGYWN0b3JzID0gRikKICAgIH0pCiAgfQogIGRTIDwtIHJiaW5kbGlzdChkUykKICBkUyRkYXRlIDwtIHN0cnNwbGl0KAogICAgc3Ryc3BsaXQobEZbaV0sIHNwbGl0ID0gIl8iLCBmaXhlZCA9IFQpW1sxXV1bM10sCiAgICBzcGxpdCA9ICIuIiwKICAgIGZpeGVkID0gVClbWzFdXVsxXQogIGRhdGFTZXRbW2NdXSA8LSBkUwogIHJtKGRTKTsgZ2MoKQp9CmRhdGFTZXQgPC0gcmJpbmRsaXN0KGRhdGFTZXQpCiMgLSByZXBsYWNlIHZhbHVlczoKZGF0YVNldCRwYWdlIDwtIHNhcHBseShkYXRhU2V0JHBhZ2UsIGZ1bmN0aW9uKHgpIHsKICBzdHJzcGxpdCh4LCBzcGxpdCA9ICIvIiwgZml4ZWQgPSBUKVtbMV1dW2xlbmd0aChzdHJzcGxpdCh4LCBzcGxpdCA9ICIvIiwgZml4ZWQgPSBUKVtbMV1dKV0KfSkKZGF0YVNldCRiYW5uZXJbd2hpY2goZGF0YVNldCRiYW5uZXIgJWluJSBzcGVjVGFza0Jhbm5lcjEpXSA8LSAnQlQxJwpkYXRhU2V0JGJhbm5lclt3aGljaChkYXRhU2V0JGJhbm5lciAlaW4lIHNwZWNUYXNrQmFubmVyMildIDwtICdCVDInCmRhdGFTZXQkYmFubmVyW3doaWNoKGRhdGFTZXQkYmFubmVyICVpbiUgc3BlY1Rhc2tCYW5uZXIzKV0gPC0gJ0JUMycKZGF0YVNldCRiYW5uZXJbd2hpY2goZGF0YVNldCRiYW5uZXIgJWluJSBnZW5JbnZQYWdlX3JnKV0gPC0gJ0dJUF9SRycKZGF0YVNldCRiYW5uZXJbd2hpY2goZGF0YVNldCRiYW5uZXIgJWluJSBnZW5JbnZQYWdlX2xwKV0gPC0gJ0dJUF9MUCcKZGF0YVNldCRiYW5uZXIgPC0gcGFzdGUoZGF0YVNldCRiYW5uZXIsICJfY2xpY2siLCBzZXAgPSAiIikKZGF0YVNldCRiYW5uZXJbd2hpY2goIShkYXRhU2V0JGJhbm5lciAlaW4lIGMoJ0JUMV9jbGljaycsICdCVDJfY2xpY2snLCAnQlQzX2NsaWNrJywgJ0dJUF9SR19jbGljaycsICdHSVBfTFBfY2xpY2snKSkpXSA8LSAKICAnT3RoZXInCmNvbG5hbWVzKGRhdGFTZXQpIDwtIGMoJ1BhZ2UnLCAnU291cmNlJywgJ1JlZmVyZXInLCAnRGF0ZScpCmRhdGFTZXQkU291cmNlW2RhdGFTZXQkUGFnZSAlaW4lICdTcGV6aWFsOkJlbnV0emVya29udG9fYW5sZWdlbicgJiBkYXRhU2V0JFNvdXJjZSA9PSAnT3RoZXInXSA8LSAKICBzdHJfZXh0cmFjdChkYXRhU2V0JFJlZmVyZXJbZGF0YVNldCRQYWdlICVpbiUgJ1NwZXppYWw6QmVudXR6ZXJrb250b19hbmxlZ2VuJyAmIGRhdGFTZXQkU291cmNlID09ICdPdGhlciddLAogICAgICAgICAgICAgICJjYW1wYWlnbj13bWRlX2FiYyguKSskIikKZGF0YVNldCRTb3VyY2VbZGF0YVNldCRQYWdlICVpbiUgJ1NwZXppYWw6QmVudXR6ZXJrb250b19hbmxlZ2VuJyAmIGdyZXBsKCJ3bWRlX2FiYzIwMTdfYnQxIiwgZGF0YVNldCRTb3VyY2UpXSA8LSAiRmVobGVyX2tvcnJpZ2llcmVuX0JUMSIKZGF0YVNldCRTb3VyY2VbZGF0YVNldCRQYWdlICVpbiUgJ1NwZXppYWw6QmVudXR6ZXJrb250b19hbmxlZ2VuJyAmIGdyZXBsKCJ3bWRlX2FiYzIwMTdfYnQyIiwgZGF0YVNldCRTb3VyY2UpXSA8LSAiRmVobGVyX2tvcnJpZ2llcmVuX0JUMiIKZGF0YVNldCRTb3VyY2VbZGF0YVNldCRQYWdlICVpbiUgJ1NwZXppYWw6QmVudXR6ZXJrb250b19hbmxlZ2VuJyAmIGdyZXBsKCJ3bWRlX2FiYzIwMTdfYnQzIiwgZGF0YVNldCRTb3VyY2UpXSA8LSAiRmVobGVyX2tvcnJpZ2llcmVuX0JUMyIKZGF0YVNldCRTb3VyY2VbZGF0YVNldCRQYWdlICVpbiUgJ1NwZXppYWw6QmVudXR6ZXJrb250b19hbmxlZ2VuJyAmIGdyZXBsKCJ3bWRlX2FiYzIwMTdfZ2liX3JnIiwgZGF0YVNldCRTb3VyY2UpXSA8LSAiR0lQX1JHX2NsaWNrIgpkYXRhU2V0JFNvdXJjZVtkYXRhU2V0JFBhZ2UgJWluJSAnU3BlemlhbDpCZW51dHplcmtvbnRvX2FubGVnZW4nICYgZ3JlcGwoIndtZGVfYWJjMjAxN19naWJfbHAiLCBkYXRhU2V0JFNvdXJjZSldIDwtICJNYWNoX21pdCIKZGF0YVNldCRTb3VyY2VbZGF0YVNldCRQYWdlICVpbiUgJ1NwZXppYWw6QmVudXR6ZXJrb250b19hbmxlZ2VuJyAmIGRhdGFTZXQkUmVmZXJlciAlaW4lICctJ10gPC0gIlVua25vd24iCmRhdGFTZXQkU291cmNlW2RhdGFTZXQkUGFnZSAlaW4lICdNYWNoX21pdCcgJiBkYXRhU2V0JFJlZmVyZXIgJWluJSAnLSddIDwtICJVbmtub3duIgpkYXRhU2V0JFNvdXJjZVtkYXRhU2V0JFBhZ2UgJWluJSAnRmVobGVyX2tvcnJpZ2llcmVuJyAmIGRhdGFTZXQkUmVmZXJlciAlaW4lICctJ10gPC0gIlVua25vd24iCmRhdGFTZXQkU291cmNlW2lzLm5hKGRhdGFTZXQkU291cmNlKV0gPC0gJ090aGVyJwpkYXRhU2V0JFJlZmVyZXIgPC0gTlVMTAoKIyMjIC0tLSBzdG9yZSBhYmNfQmFubmVyQ2xpY2tzUGFnZVZpZXdzX1VwZGF0ZS5jc3YKc2V0d2QoZGFpbHlVcGRhdGVEaXIpCndyaXRlLmNzdihkYXRhU2V0LCBmaWxlID0gImFiY19CYW5uZXJDbGlja3NQYWdlVmlld3NfVXBkYXRlLmNzdiIpCgojIyMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyMjIDMuIFVzZXIgUmVnaXN0cmF0aW9uIERhdGEKIyMjIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIC0gU2VydmVyU2lkZUFjY291bnRDcmVhdGlvbl81NDg3MzQ1CnFDb21tYW5kIDwtICJteXNxbCAtLWRlZmF1bHRzLWZpbGU9L2V0Yy9teXNxbC9jb25mLmQvYW5hbHl0aWNzLXJlc2VhcmNoLWNsaWVudC5jbmYgLWggYW5hbHl0aWNzLXN0b3JlLmVxaWFkLndtbmV0IC1BIC1lIFwic2VsZWN0ICogZnJvbSBsb2cuU2VydmVyU2lkZUFjY291bnRDcmVhdGlvbl81NDg3MzQ1IHdoZXJlICgod2ViSG9zdCA9ICdkZS53aWtpcGVkaWEub3JnJykgYW5kICh0aW1lc3RhbXAgPj0gMjAxNzA5MjAwMDAwMDApKTtcIiA+IC9ob21lL2dvcmFuc20vX21pc2NXTURFL2FiYzIwMTdfRGF0YU9VVC9hYmMyMDE3X09mZmljaWFsRGF0YXNldHMvYWJjMjAxN19EYWlseVVwZGF0ZS9hYmMyMDE3X3VzZXJSZWdpc3RyYXRpb25zLnRzdiIKc3lzdGVtKGNvbW1hbmQgPSBxQ29tbWFuZCwgd2FpdCA9IFRSVUUpCgojIyMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyMjIDQuIEd1aWRlZCBUb3VyIERhdGEKIyMjIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIyMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyMjIDUuIFVzZXIgRWRpdHMgRGF0YQojIyMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCmBgYAoKIyMgMS4gQ2FtcGFpZ24gQmFubmVycwoKVGhpcyBzZWN0aW9uIHByZXNlbnRzIGFsbCBkYXRhIGFuZCBzdGF0aXN0aWNzIG9uIHRoZSBjYW1wYWlnbiByZWxldmFudCBiYW5uZXJzLgoKIyMjIDEuMSBCYW5uZXIgSW1wcmVzc2lvbnMKCmBgYHtyIGVjaG8gPSBULCBldmFsID0gRn0KIyMjIC0tLSBleHRyYWN0IG9ubHkgY2FtcGFpZ24gcmVsZXZhbnQgZGF0YQojIC0gY2FtcGFpZ24gYmFubmVyczoKQlQxIDwtICd3bWRlX2FiYzIwMTdfYnQxJwpCVDIgPC0gJ3dtZGVfYWJjMjAxN19idDInCkJUMyA8LSAnd21kZV9hYmMyMDE3X2J0MycKR0lQX1JHIDwtICd3bWRlX2FiYzIwMTdfZ2liX3JnJwpHSVBfTFAgPC0gJ3dtZGVfYWJjMjAxN19naWJfbHAnCiMgLSBjb3VudCBub24tZW1wdHkgZmlsZXM6CmMgPC0gMApsRiA8LSBsaXN0LmZpbGVzKHBhdGggPSAiLi9fZGFpbHlVcGRhdGVEQVRBLyIpCmxGIDwtIGxGW2dyZXBsKCcudHN2JywgbEYsIGZpeGVkID0gVCldCmRhdGFTZXQgPC0gbGlzdCgpCmZvciAoaSBpbiAxOmxlbmd0aChsRikpIHsKICBkUyA8LSByZWFkTGluZXMocGFzdGUoIi4vX2RhaWx5VXBkYXRlREFUQS8iLGxGW2ldLCBzZXAgPSAiIiksIG4gPSAtMSkKICBkUyA8LSBkU1s4Omxlbmd0aChkUyldCiAgd0MgPC0gdW5uYW1lKHNhcHBseShkUywgZnVuY3Rpb24oeCkgewogICAgZ3JlcGwocGFzdGUoYyhCVDEsIEJUMiwgQlQzLCBHSVBfUkcsIEdJUF9MUCksIHNlcCA9ICIiLCBjb2xsYXBzZSA9ICJ8IiksIHgpCiAgfSkpCiAgaWYgKGxlbmd0aCh3aGljaCh3QykgPiAwKSkgewogICAgYyA8LSBjICsgMQogICAgZFMgPC0gZFNbd0NdCiAgICBybSh3Qyk7IGdjKCkKICAgIGRTIDwtIGRhdGEuZnJhbWUocXVlcnkgPSBkUywgc3RyaW5nc0FzRmFjdG9ycyA9IEYpCiAgICBkUyRkYXRlIDwtIHN0cnNwbGl0KAogICAgICBzdHJzcGxpdChsRltpXSwgc3BsaXQgPSAiXyIsIGZpeGVkID0gVClbWzFdXVs0XSwKICAgICAgc3BsaXQgPSAiLiIsCiAgICAgIGZpeGVkID0gVClbWzFdXVsxXQogICAgZGF0YVNldFtbY11dIDwtIGRTCiAgICB9CiAgcm0oZFMpOyBnYygpCn0KZGF0YVNldCA8LSByYmluZGxpc3QoZGF0YVNldCkKZGF0YVNldCRpbXByZXNzUmF0ZSA8LSBzYXBwbHkoZGF0YVNldCRxdWVyeSwgZnVuY3Rpb24oeCkgewogIGFzLm51bWVyaWMoCiAgICBzdHJfZXh0cmFjdCgKICAgICAgc3RyX2V4dHJhY3QoeCwgcGF0dGVybiA9ICJyZWNvcmRJbXByZXNzaW9uU2FtcGxlUmF0ZT0oW1s6ZGlnaXQ6XV18XFwuKSsiKSwKICAgICAgcGF0dGVybiA9ICIoW1s6ZGlnaXQ6XV18XFwuKSsiKQogICkKfSkKCiMjIyAtLS0gQ291bnQgZGFpbHkgYmFubmVyIGltcHJlc3Npb25zOgoKa25pdHI6OmthYmxlKGJhbm5lckltcCwgCiAgICAgICAgICAgICBmb3JtYXQgPSAiaHRtbCIpICU+JSAKICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBGLCAKICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gImxlZnQiKQpiYW5uZXJJbXAgPC0gZ2F0aGVyKGJhbm5lckltcCwKICAgICAgICAgICAgICAgICAgICBrZXkgPSBCYW5uZXIsCiAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSBJbXByZXNzaW9ucywKICAgICAgICAgICAgICAgICAgICBgQmFubmVyIEFgOmBCYW5uZXIgQmApCgojIC0gVmlzdWFsaXplIHcuIHtnZ3Bsb3QyfQpjaGFydENvbHMgPC0gYnJld2VyLnBhbCg4LCAnU2V0MicpW2MoMSwgMiwgMywgNSwgNildCmdncGxvdChiYW5uZXJJbXAsIGFlcyh4ID0gRGF0ZSwKICAgICAgICAgICAgICAgICAgICAgIHkgPSBJbXByZXNzaW9ucywKICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gQmFubmVyLAogICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBCYW5uZXIsCiAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gQmFubmVyLAogICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSBJbXByZXNzaW9ucykpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgCiAgICAgICAgICAgcG9zaXRpb24gPSAiZG9kZ2UiLCAKICAgICAgICAgICB3aWR0aCA9IC4zKSArCiAgZ2VvbV9sYWJlbChhZXMoZmlsbCA9IEJhbm5lciksIAogICAgICAgICAgICAgY29sb3VyID0gIndoaXRlIiwgCiAgICAgICAgICAgICBmb250ZmFjZSA9ICJib2xkIiwgCiAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSksCiAgICAgICAgICAgICBzaXplID0gMiwgCiAgICAgICAgICAgICBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgc2NhbGVfZmlsbF9tYW51YWwoImxlZ2VuZCIsIHZhbHVlcyA9IGMoIkJhbm5lciBBIiA9ICJvcmFuZ2UiLCAiQmFubmVyIEIiID0gImZpcmVicmljayIpKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCgibGVnZW5kIiwgdmFsdWVzID0gYygiQmFubmVyIEEiID0gIm9yYW5nZSIsICJCYW5uZXIgQiIgPSAiZmlyZWJyaWNrIikpICsKICBnZ3RpdGxlKCdBdXR1bW4gQmFubmVyIENhbXBhaWduIDIwMTc6IEJhbm5lciBJbXByZXNzaW9uc1xuU291cmNlOiB3ZWJyZXF1ZXN0LCBoZGZzJykgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHNpemUgPSA4KSkgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSkgKwogIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfYmxhbmsoKSkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCgoKIyMjIDEuMiBCYW5uZXIgQ2xpY2tzIGFuZCBMYW5kaW5nIFBhZ2UgVmlld3MKCiMjIyAxLjIuMCBUaGUgRGF0YXNldAoKYGBge3IgZWNobyA9IFR9CmRhdGFTZXQgPC0gcmVhZC5jc3YocGFzdGUoJy4vX2RhaWx5VXBkYXRlREFUQS8nLCAnYWJjX0Jhbm5lckNsaWNrc1BhZ2VWaWV3c19VcGRhdGUuY3N2Jywgc2VwID0gIiIpLAogICAgICAgICAgICAgICAgICAgIGhlYWRlciA9IFQsCiAgICAgICAgICAgICAgICAgICAgY2hlY2submFtZXMgPSBGLAogICAgICAgICAgICAgICAgICAgIHJvdy5uYW1lcyA9IDEsCiAgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IEYpCiMgLSBDaGFydCBjb2xvcnMKY2hhcnRDb2xzIDwtIGMoJ2luZGlhbnJlZDEnLCAnaW5kaWFucmVkMicsICdpbmRpYW5yZWQzJywKICAgICAgICAgICAgICAgJ2NhZGV0Ymx1ZScsICdjYWRldGJsdWUyJywgCiAgICAgICAgICAgICAgICdkZWVwc2t5Ymx1ZScsICd2aW9sZXRyZWQxJywgJ3Zpb2xldHJlZDInLCAndmlvbGV0cmVkMycsCiAgICAgICAgICAgICAgICdsaWdodHNsYXRlZ3JleScsICdsaWdodGdyZXknKQpuYW1lcyhjaGFydENvbHMpIDwtIGMoJ0JUMV9jbGljaycsICdCVDJfY2xpY2snLCAnQlQzX2NsaWNrJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdHSVBfTFBfY2xpY2snLCAnR0lQX1JHX2NsaWNrJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdNYWNoX01pdCcsICdGZWhsZXJfa29ycmlnaWVyZW5fQlQxJywgJ0ZlaGxlcl9rb3JyaWdpZXJlbl9CVDInLCAnRmVobGVyX2tvcnJpZ2llcmVuX0JUMycsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnT3RoZXInLCAnVW5rbm93bicpCmRhdGFTZXQkU291cmNlIDwtIGZhY3RvcihkYXRhU2V0JFNvdXJjZSwgbGV2ZWxzID0gYygnQlQxX2NsaWNrJywgJ0JUMl9jbGljaycsICdCVDNfY2xpY2snLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0dJUF9MUF9jbGljaycsICdHSVBfUkdfY2xpY2snLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ01hY2hfTWl0JywgJ0ZlaGxlcl9rb3JyaWdpZXJlbl9CVDEnLCAnRmVobGVyX2tvcnJpZ2llcmVuX0JUMicsICdGZWhsZXJfa29ycmlnaWVyZW5fQlQzJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdPdGhlcicsICdVbmtub3duJykpCgojIC0gUGFnZSBDaGFydCBDb2xvcnMKcGFnZUNoYXJ0Q29sb3JzIDwtIGMoJ29yYW5nZScsICdkZWVwc2t5Ymx1ZScsICdsaWdodGdyZWVuJykKbmFtZXMocGFnZUNoYXJ0Q29sb3JzKSA8LSBjKCdGZWhsZXJfa29ycmlnaWVyZW4nLCAnU3BlemlhbDpCZW51dHplcmtvbnRvX2FubGVnZW4nLCAnTWFjaF9taXQnKQpkYXRhU2V0JFBhZ2UgPC0gZmFjdG9yKGRhdGFTZXQkUGFnZSwgCiAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygnRmVobGVyX2tvcnJpZ2llcmVuJywgJ1NwZXppYWw6QmVudXR6ZXJrb250b19hbmxlZ2VuJywgJ01hY2hfbWl0JykpCgojIC0gQ2FtcGFpZ24gQ2hhcnQgQ29sb3JzCmNhbXBhaWduQ2hhcnRDb2xvcnMgPC0gYygnaW5kaWFucmVkMScsICdpbmRpYW5yZWQyJywgJ2luZGlhbnJlZDMnLAogICAgICAgICAgICAgICAnY2FkZXRibHVlJywgJ2NhZGV0Ymx1ZTInKQpuYW1lcyhjYW1wYWlnbkNoYXJ0Q29sb3JzKSA8LSBjKCdCVDEnLCAnQlQyJywgJ0JUMycsICdHSVBfTFAnLCAnR0lQX1JHJykKYGBgCgojIyMjIDEuMi4xIExhbmRpbmcgUGFnZXM6IFJlZmVyZXJzIAoKVGhlIGZvbGxvd2luZyBjaGFydHMgcmVwcmVzZW50cyB0aGUgYnJlYWtkb3duIG9mIHJlZmVyZXJzIChpLmUuIHNvdXJjZXMpIGZvciB0aGUgY2FtcGFpZ24gcGFnZXM6IG9uZSByZWdpc3RyYXRpb24gcGFnZSwgYW5kIHR3byBsYW5kaW5nIHBhZ2VzLgoKYGBge3IgZWNobyA9IFQsIHdhcm5pbmcgPSAnaGlkZScsIG1lc3NhZ2UgPSBGfQojIyMgLS0tIEJhbm5lciBjbGlja3MgYW5kIExhbmRpbmcgUGFnZSBWaWV3cwojIC0gVGFibGUgUmVwb3J0CnRhYmxlU2V0IDwtIGRhdGFTZXQgJT4lCiAgZHBseXI6Omdyb3VwX2J5KFBhZ2UsIFNvdXJjZSwgRGF0ZSkgJT4lIAogIGRwbHlyOjpzdW1tYXJpc2UoQ291bnQgPSBuKCkpICU+JSAKICBkcGx5cjo6YXJyYW5nZShEYXRlLCBQYWdlLCBTb3VyY2UpCgpnZ3Bsb3QodGFibGVTZXQsIGFlcyh4ID0gUGFnZSwKICAgICAgICAgICAgICAgICAgICB5ID0gQ291bnQsCiAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSBTb3VyY2UsCiAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBTb3VyY2UsCiAgICAgICAgICAgICAgICAgICAgZmlsbCA9IFNvdXJjZSwKICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IENvdW50KSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCAKICAgICAgICAgICBwb3NpdGlvbiA9ICJkb2RnZSIsIAogICAgICAgICAgIHdpZHRoID0gLjM1KSArCiAgc2NhbGVfZmlsbF9tYW51YWwoImxlZ2VuZCIsIHZhbHVlcyA9IGNoYXJ0Q29scykgKwogIHNjYWxlX2NvbG9yX21hbnVhbCgibGVnZW5kIiwgdmFsdWVzID0gY2hhcnRDb2xzKSArCiAgZ2d0aXRsZSgnQXV0dW1uIEJhbm5lciBDYW1wYWlnbiAyMDE3OlxuQnJlYWtkb3duIG9mIExhbmRpbmcgUGFnZSBWaWV3cyBzb3VyY2VzJykgKwogIHRoZW1lX21pbmltYWwoKSArIAogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHNpemUgPSA4LCBoanVzdCA9IDEpKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApKSArCiAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vci54ID0gZWxlbWVudF9ibGFuaygpKSArCiAgdGhlbWUocGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCgojIyMjIDEuMi4yIExhbmRpbmcgUGFnZXM6IFJlZmVyZXIgQnJlYWtkb3duIAoKVGhlIGZvbGxvd2luZyB0aHJlZSBwaWUgY2hhcnRzIHByZXNlbnQgYSBicmVha2Rvd24gb2YgcmVmZXJlcnMgKGkuZS4gc291cmNlcykgZm9yIHRoZSBDYW1wYWlnbiBwYWdlcyAodHdvIGxhbmRpbmcgcGFnZXMgYW5kIG9uZSByZWdpc3RyYXRpb24gcGFnZS4KCmBgYHtyIGVjaG8gPSBULCB3YXJuaW5nID0gJ2hpZGUnLCBtZXNzYWdlID0gRn0KIyMjIC0tLSBQYWdlIFZpZXdzOiBTb3VyY2VzCgojIC0gU3BlemlhbDpCZW51dHplcmtvbnRvX2FubGVnZW4KcGFnZVNvdXJjZSA8LSBkYXRhU2V0ICU+JSAKICBkcGx5cjo6Y291bnQoUGFnZSwgU291cmNlKSAlPiUKICBkcGx5cjo6Z3JvdXBfYnkoUGFnZSkgJT4lIAogIGRwbHlyOjptdXRhdGUoUGVyY2VudCA9IG4vc3VtKG4pKQpwYWdlU291cmNlJFBlcmNlbnQgPC0gcGFzdGUocm91bmQocGFnZVNvdXJjZSRQZXJjZW50KjEwMCwgMiksICIlIiwgc2VwID0gIiIpCnBhZ2VTb3VyY2VQbG90IDwtIGZpbHRlcihwYWdlU291cmNlLCBQYWdlICVpbiUgJ1NwZXppYWw6QmVudXR6ZXJrb250b19hbmxlZ2VuJykKZ2dwbG90KHBhZ2VTb3VyY2VQbG90LCBhZXMoeCA9ICcnLAogICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBTb3VyY2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBTb3VyY2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gUGVyY2VudCkpICsKICBnZW9tX2JhcihhZXMoeCA9ICcnLAogICAgICAgICAgICAgICB5ID0gbiwKICAgICAgICAgICAgICAgY29sb3IgPSBTb3VyY2UsCiAgICAgICAgICAgICAgIGZpbGwgPSBTb3VyY2UpLCAKICAgICAgICAgICBzdGF0ID0gImlkZW50aXR5IiwgCiAgICAgICAgICAgd2lkdGggPSAxKSArCiAgY29vcmRfcG9sYXIoInkiLCBzdGFydCA9IDApICsKICBnZW9tX3RleHQoYWVzKHggPSAxKSwKICAgICAgICAgICAgY29sb3VyID0gIndoaXRlIiwKICAgICAgICAgICAgZm9udGZhY2UgPSAiYm9sZCIsCiAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAwLjUpLAogICAgICAgICAgICBzaXplID0gMywKICAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBGKSArCiAgc2NhbGVfZmlsbF9tYW51YWwoImxlZ2VuZCIsIHZhbHVlcyA9IGNoYXJ0Q29scykgKwogIHNjYWxlX2NvbG9yX21hbnVhbCgibGVnZW5kIiwgdmFsdWVzID0gY2hhcnRDb2xzKSArCiAgZ2d0aXRsZSgnQXV0dW1uIEJhbm5lciBDYW1wYWlnbiAyMDE3OlxuUGFnZSBWaWV3cyBTb3VyY2VzIGZvciBTcGV6aWFsOkJlbnV0emVya29udG9fYW5sZWdlbicpICsKICB4bGFiKCJPdXR0ZXIgPSBDb3VudCIpICsgeWxhYigiIikgKwogIHRoZW1lX21pbmltYWwoKSArIAogICMgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCkpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCkpICsKICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsKICB0aGVtZShwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2JsYW5rKCkpICsKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yLnkgPSBlbGVtZW50X2JsYW5rKCkpCgojIC0gU3BlemlhbDpCZW51dHplcmtvbnRvX2FubGVnZW4gLSBVbmtub3duL090aGVyCnBhZ2VTb3VyY2UgPC0gZGF0YVNldCAlPiUgCiAgZmlsdGVyKCEoZGF0YVNldCRTb3VyY2UgJWluJSAnT3RoZXInIHwgZGF0YVNldCRTb3VyY2UgJWluJSAnVW5rbm93bicpKSAlPiUKICBkcGx5cjo6Y291bnQoUGFnZSwgU291cmNlKSAlPiUKICBkcGx5cjo6Z3JvdXBfYnkoUGFnZSkgJT4lIAogIGRwbHlyOjptdXRhdGUoUGVyY2VudCA9IG4vc3VtKG4pKQpwYWdlU291cmNlJFBlcmNlbnQgPC0gcGFzdGUocm91bmQocGFnZVNvdXJjZSRQZXJjZW50KjEwMCwgMiksICIlIiwgc2VwID0gIiIpCnBhZ2VTb3VyY2VQbG90IDwtIGZpbHRlcihwYWdlU291cmNlLCBQYWdlICVpbiUgJ1NwZXppYWw6QmVudXR6ZXJrb250b19hbmxlZ2VuJykKZ2dwbG90KHBhZ2VTb3VyY2VQbG90LCBhZXMoeCA9ICcnLAogICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBTb3VyY2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBTb3VyY2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gUGVyY2VudCkpICsKICBnZW9tX2JhcihhZXMoeCA9ICcnLAogICAgICAgICAgICAgICB5ID0gbiwKICAgICAgICAgICAgICAgY29sb3IgPSBTb3VyY2UsCiAgICAgICAgICAgICAgIGZpbGwgPSBTb3VyY2UpLCAKICAgICAgICAgICBzdGF0ID0gImlkZW50aXR5IiwgCiAgICAgICAgICAgd2lkdGggPSAxKSArCiAgY29vcmRfcG9sYXIoInkiLCBzdGFydCA9IDApICsKICBnZW9tX3RleHQoYWVzKHggPSAxKSwKICAgICAgICAgICAgY29sb3VyID0gIndoaXRlIiwKICAgICAgICAgICAgZm9udGZhY2UgPSAiYm9sZCIsCiAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAwLjUpLAogICAgICAgICAgICBzaXplID0gMywKICAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBGKSArCiAgc2NhbGVfZmlsbF9tYW51YWwoImxlZ2VuZCIsIHZhbHVlcyA9IGNoYXJ0Q29scykgKwogIHNjYWxlX2NvbG9yX21hbnVhbCgibGVnZW5kIiwgdmFsdWVzID0gY2hhcnRDb2xzKSArCiAgZ2d0aXRsZSgnQXV0dW1uIEJhbm5lciBDYW1wYWlnbiAyMDE3OlxuUGFnZSBWaWV3cyBTb3VyY2VzIGZvciBTcGV6aWFsOkJlbnV0emVya29udG9fYW5sZWdlbiAoQ2FtcGFpZ24gb25seSknKSArCiAgeGxhYigiT3V0dGVyID0gQ291bnQiKSArIHlsYWIoIiIpICsKICB0aGVtZV9taW5pbWFsKCkgKyAKICAjIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApKSArCiAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9ibGFuaygpKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vci55ID0gZWxlbWVudF9ibGFuaygpKQoKIyAtIEZlaGxlcl9rb3JyaWdpZXJlbgpwYWdlU291cmNlIDwtIGRhdGFTZXQgJT4lIAogIGRwbHlyOjpjb3VudChQYWdlLCBTb3VyY2UpICU+JQogIGRwbHlyOjpncm91cF9ieShQYWdlKSAlPiUgCiAgZHBseXI6Om11dGF0ZShQZXJjZW50ID0gbi9zdW0obikpCnBhZ2VTb3VyY2UkUGVyY2VudCA8LSBwYXN0ZShyb3VuZChwYWdlU291cmNlJFBlcmNlbnQqMTAwLCAyKSwgIiUiLCBzZXAgPSAiIikKcGFnZVNvdXJjZVBsb3QgPC0gZmlsdGVyKHBhZ2VTb3VyY2UsIFBhZ2UgJWluJSAnRmVobGVyX2tvcnJpZ2llcmVuJykKZ2dwbG90KHBhZ2VTb3VyY2VQbG90LCBhZXMoeCA9ICcnLAogICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBTb3VyY2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBTb3VyY2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gUGVyY2VudCkpICsKICBnZW9tX2JhcihhZXMoeCA9ICcnLAogICAgICAgICAgICAgICB5ID0gbiwKICAgICAgICAgICAgICAgY29sb3IgPSBTb3VyY2UsCiAgICAgICAgICAgICAgIGZpbGwgPSBTb3VyY2UpLCAKICAgICAgICAgICBzdGF0ID0gImlkZW50aXR5IiwgCiAgICAgICAgICAgd2lkdGggPSAxKSArCiAgY29vcmRfcG9sYXIoInkiLCBzdGFydCA9IDApICsKICBnZW9tX3RleHQoYWVzKHggPSAxKSwKICAgICAgICAgICAgY29sb3VyID0gIndoaXRlIiwKICAgICAgICAgICAgZm9udGZhY2UgPSAiYm9sZCIsCiAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAwLjUpLAogICAgICAgICAgICBzaXplID0gMywKICAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBGKSArCiAgc2NhbGVfZmlsbF9tYW51YWwoImxlZ2VuZCIsIHZhbHVlcyA9IGNoYXJ0Q29scykgKwogIHNjYWxlX2NvbG9yX21hbnVhbCgibGVnZW5kIiwgdmFsdWVzID0gY2hhcnRDb2xzKSArCiAgZ2d0aXRsZSgnQXV0dW1uIEJhbm5lciBDYW1wYWlnbiAyMDE3OlxuUGFnZSBWaWV3cyBTb3VyY2VzIGZvciBGZWhsZXJfa29ycmlnaWVyZW4nKSArCiAgeGxhYigiT3V0dGVyID0gQ291bnQiKSArIHlsYWIoIiIpICsKICB0aGVtZV9taW5pbWFsKCkgKyAKICAjIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApKSArCiAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9ibGFuaygpKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vci55ID0gZWxlbWVudF9ibGFuaygpKSArCiAgdGhlbWUocGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSkKCiMgLSBGZWhsZXJfa29ycmlnaWVyZW4gLSBtaW51cyBVbmtub3duL090aGVyCnBhZ2VTb3VyY2UgPC0gZGF0YVNldCAlPiUKICBmaWx0ZXIoIShkYXRhU2V0JFNvdXJjZSAlaW4lICdPdGhlcicgfCBkYXRhU2V0JFNvdXJjZSAlaW4lICdVbmtub3duJykpICU+JQogIGRwbHlyOjpjb3VudChQYWdlLCBTb3VyY2UpICU+JQogIGRwbHlyOjpncm91cF9ieShQYWdlKSAlPiUgCiAgZHBseXI6Om11dGF0ZShQZXJjZW50ID0gbi9zdW0obikpCnBhZ2VTb3VyY2UkUGVyY2VudCA8LSBwYXN0ZShyb3VuZChwYWdlU291cmNlJFBlcmNlbnQqMTAwLCAyKSwgIiUiLCBzZXAgPSAiIikKcGFnZVNvdXJjZVBsb3QgPC0gZmlsdGVyKHBhZ2VTb3VyY2UsIFBhZ2UgJWluJSAnRmVobGVyX2tvcnJpZ2llcmVuJykKZ2dwbG90KHBhZ2VTb3VyY2VQbG90LCBhZXMoeCA9ICcnLAogICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBTb3VyY2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBTb3VyY2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gUGVyY2VudCkpICsKICBnZW9tX2JhcihhZXMoeCA9ICcnLAogICAgICAgICAgICAgICB5ID0gbiwKICAgICAgICAgICAgICAgY29sb3IgPSBTb3VyY2UsCiAgICAgICAgICAgICAgIGZpbGwgPSBTb3VyY2UpLCAKICAgICAgICAgICBzdGF0ID0gImlkZW50aXR5IiwgCiAgICAgICAgICAgd2lkdGggPSAxKSArCiAgY29vcmRfcG9sYXIoInkiLCBzdGFydCA9IDApICsKICBnZW9tX3RleHQoYWVzKHggPSAxKSwKICAgICAgICAgICAgY29sb3VyID0gIndoaXRlIiwKICAgICAgICAgICAgZm9udGZhY2UgPSAiYm9sZCIsCiAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAwLjUpLAogICAgICAgICAgICBzaXplID0gMywKICAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBGKSArCiAgc2NhbGVfZmlsbF9tYW51YWwoImxlZ2VuZCIsIHZhbHVlcyA9IGNoYXJ0Q29scykgKwogIHNjYWxlX2NvbG9yX21hbnVhbCgibGVnZW5kIiwgdmFsdWVzID0gY2hhcnRDb2xzKSArCiAgZ2d0aXRsZSgnQXV0dW1uIEJhbm5lciBDYW1wYWlnbiAyMDE3OlxuUGFnZSBWaWV3cyBTb3VyY2VzIGZvciBGZWhsZXJfa29ycmlnaWVyZW4gKENhbXBhaWduIG9ubHkpJykgKwogIHhsYWIoIk91dHRlciA9IENvdW50IikgKyB5bGFiKCIiKSArCiAgdGhlbWVfbWluaW1hbCgpICsgCiAgIyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSkgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSkgKwogIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKSkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IueSA9IGVsZW1lbnRfYmxhbmsoKSkgKwogIHRoZW1lKHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCkpCgojIC0gTWFjaF9taXQKcGFnZVNvdXJjZSA8LSBkYXRhU2V0ICU+JSAKICBkcGx5cjo6Y291bnQoUGFnZSwgU291cmNlKSAlPiUKICBkcGx5cjo6Z3JvdXBfYnkoUGFnZSkgJT4lIAogIGRwbHlyOjptdXRhdGUoUGVyY2VudCA9IG4vc3VtKG4pKQpwYWdlU291cmNlJFBlcmNlbnQgPC0gcGFzdGUocm91bmQocGFnZVNvdXJjZSRQZXJjZW50KjEwMCwgMiksICIlIiwgc2VwID0gIiIpCnBhZ2VTb3VyY2VQbG90IDwtIGZpbHRlcihwYWdlU291cmNlLCBQYWdlICVpbiUgJ01hY2hfbWl0JykKZ2dwbG90KHBhZ2VTb3VyY2VQbG90LCBhZXMoeCA9ICcnLAogICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBTb3VyY2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBTb3VyY2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gUGVyY2VudCkpICsKICBnZW9tX2JhcihhZXMoeCA9ICcnLAogICAgICAgICAgICAgICB5ID0gbiwKICAgICAgICAgICAgICAgY29sb3IgPSBTb3VyY2UsCiAgICAgICAgICAgICAgIGZpbGwgPSBTb3VyY2UpLCAKICAgICAgICAgICBzdGF0ID0gImlkZW50aXR5IiwgCiAgICAgICAgICAgd2lkdGggPSAxKSArCiAgY29vcmRfcG9sYXIoInkiLCBzdGFydCA9IDApICsKICBnZW9tX3RleHQoYWVzKHggPSAxKSwKICAgICAgICAgICAgY29sb3VyID0gIndoaXRlIiwKICAgICAgICAgICAgZm9udGZhY2UgPSAiYm9sZCIsCiAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAwLjUpLAogICAgICAgICAgICBzaXplID0gMywKICAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBGKSArCiAgc2NhbGVfZmlsbF9tYW51YWwoImxlZ2VuZCIsIHZhbHVlcyA9IGNoYXJ0Q29scykgKwogIHNjYWxlX2NvbG9yX21hbnVhbCgibGVnZW5kIiwgdmFsdWVzID0gY2hhcnRDb2xzKSArCiAgZ2d0aXRsZSgnQXV0dW1uIEJhbm5lciBDYW1wYWlnbiAyMDE3OlxuUGFnZSBWaWV3cyBTb3VyY2VzIGZvciBNYWNoX21pdCcpICsKICB4bGFiKCJPdXR0ZXIgPSBDb3VudCIpICsgeWxhYigiIikgKwogIHRoZW1lX21pbmltYWwoKSArIAogICMgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCkpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCkpICsKICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsKICB0aGVtZShwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2JsYW5rKCkpICsKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yLnkgPSBlbGVtZW50X2JsYW5rKCkpICsKICB0aGVtZShwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpKQoKIyAtIE1hY2hfbWl0IC0gbWludXMgVW5rbm93bi9PdGhlcgpwYWdlU291cmNlIDwtIGRhdGFTZXQgJT4lIAogIGZpbHRlcighKGRhdGFTZXQkU291cmNlICVpbiUgJ090aGVyJyB8IGRhdGFTZXQkU291cmNlICVpbiUgJ1Vua25vd24nKSkgJT4lCiAgZHBseXI6OmNvdW50KFBhZ2UsIFNvdXJjZSkgJT4lCiAgZHBseXI6Omdyb3VwX2J5KFBhZ2UpICU+JSAKICBkcGx5cjo6bXV0YXRlKFBlcmNlbnQgPSBuL3N1bShuKSkKcGFnZVNvdXJjZSRQZXJjZW50IDwtIHBhc3RlKHJvdW5kKHBhZ2VTb3VyY2UkUGVyY2VudCoxMDAsIDIpLCAiJSIsIHNlcCA9ICIiKQpwYWdlU291cmNlUGxvdCA8LSBmaWx0ZXIocGFnZVNvdXJjZSwgUGFnZSAlaW4lICdNYWNoX21pdCcpCmdncGxvdChwYWdlU291cmNlUGxvdCwgYWVzKHggPSAnJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IG4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gU291cmNlLAogICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gU291cmNlLAogICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IFBlcmNlbnQpKSArCiAgZ2VvbV9iYXIoYWVzKHggPSAnJywKICAgICAgICAgICAgICAgeSA9IG4sCiAgICAgICAgICAgICAgIGNvbG9yID0gU291cmNlLAogICAgICAgICAgICAgICBmaWxsID0gU291cmNlKSwgCiAgICAgICAgICAgc3RhdCA9ICJpZGVudGl0eSIsIAogICAgICAgICAgIHdpZHRoID0gMSkgKwogIGNvb3JkX3BvbGFyKCJ5Iiwgc3RhcnQgPSAwKSArCiAgZ2VvbV90ZXh0KGFlcyh4ID0gMSksCiAgICAgICAgICAgIGNvbG91ciA9ICJ3aGl0ZSIsCiAgICAgICAgICAgIGZvbnRmYWNlID0gImJvbGQiLAogICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX3N0YWNrKHZqdXN0ID0gMC41KSwKICAgICAgICAgICAgc2l6ZSA9IDMsCiAgICAgICAgICAgIHNob3cubGVnZW5kID0gRikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKCJsZWdlbmQiLCB2YWx1ZXMgPSBjaGFydENvbHMpICsKICBzY2FsZV9jb2xvcl9tYW51YWwoImxlZ2VuZCIsIHZhbHVlcyA9IGNoYXJ0Q29scykgKwogIGdndGl0bGUoJ0F1dHVtbiBCYW5uZXIgQ2FtcGFpZ24gMjAxNzpcblBhZ2UgVmlld3MgU291cmNlcyBmb3IgTWFjaF9taXQnKSArCiAgeGxhYigiT3V0dGVyID0gQ291bnQiKSArIHlsYWIoIiIpICsKICB0aGVtZV9taW5pbWFsKCkgKyAKICAjIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApKSArCiAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9ibGFuaygpKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vci55ID0gZWxlbWVudF9ibGFuaygpKSArCiAgdGhlbWUocGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCgojIyMjIDEuMi4zIEJhbm5lciBDbGlja3M6IENhbXBhaWduIFRvdGFsICAKClRoZSBmb2xsb3dpbmcgY2hhcnRzIHJlcHJlc2VudHMgdGhlIG51bWJlciBvZiBiYW5uZXIgY2xpY2tzIGZvciBlYWNoIGNhbXBhaWduIGJhbm5lciBkdXJpbmcgdGhlIGNvdXJzZSBvZiB0aGUgY2FtcGFpZ24uCgpgYGB7ciBlY2hvID0gVCwgd2FybmluZyA9ICdoaWRlJywgbWVzc2FnZSA9IEZ9CiMjIyAtLS0gVGVtcG9yYWwgQmFubmVyIENsaWNrcwojIC0gQ2hhcnQKY2xpY2tQbG90U2V0IDwtIGRhdGFTZXQgJT4lIAogIGRwbHlyOjpzZWxlY3QoU291cmNlLCBEYXRlKSAlPiUKICBkcGx5cjo6ZmlsdGVyKGdyZXBsKCJfY2xpY2siLCBTb3VyY2UpKSAlPiUKICBkcGx5cjo6Z3JvdXBfYnkoU291cmNlLCBEYXRlKSAlPiUgCiAgZHBseXI6OnN1bW1hcmlzZShDb3VudCA9IG4oKSkgJT4lCiAgZHBseXI6OmFycmFuZ2UoRGF0ZSkKZ2dwbG90KGNsaWNrUGxvdFNldCwgYWVzKHggPSBEYXRlLAogICAgICAgICAgICAgICAgICAgICAgICAgeSA9IENvdW50LAogICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSBTb3VyY2UsCiAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IFNvdXJjZSwKICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBTb3VyY2UsCiAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IENvdW50KSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCAKICAgICAgICAgICBwb3NpdGlvbiA9ICJkb2RnZSIsIAogICAgICAgICAgIHdpZHRoID0gLjUpICsKICBzY2FsZV9maWxsX21hbnVhbCgibGVnZW5kIiwgdmFsdWVzID0gY2hhcnRDb2xzKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKCJsZWdlbmQiLCB2YWx1ZXMgPSBjaGFydENvbHMpICsKICBnZ3RpdGxlKCdBdXR1bW4gQmFubmVyIENhbXBhaWduIDIwMTc6IEJhbm5lciBDbGlja3MnKSArCiAgdGhlbWVfbWluaW1hbCgpICsgCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgc2l6ZSA9IDgsIGhqdXN0ID0gMSkpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCkpICsKICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsKICB0aGVtZShwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCkpICsKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yLnggPSBlbGVtZW50X2JsYW5rKCkpICsKICB0aGVtZShwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpKQpgYGAKCiMjIyMgMS4yLjQgUGFnZSBWaWV3czogQ2FtcGFpZ24gVG90YWwgIAoKVGhlIGZvbGxvd2luZyBjaGFydCBwcmVzZW50cyB0aGUgbnVtYmVyIG9mIHBhZ2Ugdmlld3MgZm9yIHRoZSB0d28gbGFuZGluZyBwYWdlcyBhbmQgb25lIHJlZ2lzdHJhdGlvbiBwYWdlIGR1cmluZyB0aGUgY291cnNlIG9mIHRoZSBjYW1wYWlnbiwgYW5kIGVuY29tcGFzc2luZyBvbmx5IHBhZ2Ugdmlld3MgZ2VuZXJhdGVkIGZyb20gdGhlIGNhbXBhaWduLgoKYGBge3IgZWNobyA9IFQsIHdhcm5pbmcgPSAnaGlkZScsIG1lc3NhZ2UgPSBGfQojIyMgLS0tIFRlbXBvcmFsIFBhZ2UgVmlld3MKIyAtIENoYXJ0CnBhZ2VQbG90U2V0IDwtIGRhdGFTZXQgJT4lIAogIGZpbHRlcighKGRhdGFTZXQkU291cmNlICVpbiUgJ090aGVyJyB8IGRhdGFTZXQkU291cmNlICVpbiUgJ1Vua25vd24nKSkgJT4lCiAgZHBseXI6OnNlbGVjdChQYWdlLCBEYXRlKSAlPiUKICBkcGx5cjo6Z3JvdXBfYnkoUGFnZSwgRGF0ZSkgJT4lIAogIGRwbHlyOjpzdW1tYXJpc2UoQ291bnQgPSBuKCkpICU+JSAKICBkcGx5cjo6YXJyYW5nZShEYXRlKQpnZ3Bsb3QocGFnZVBsb3RTZXQsIGFlcyh4ID0gRGF0ZSwKICAgICAgICAgICAgICAgICAgICAgICAgeSA9IENvdW50LAogICAgICAgICAgICAgICAgICAgICAgICBncm91cCA9IFBhZ2UsCiAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gUGFnZSwKICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IFBhZ2UsCiAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gQ291bnQpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIAogICAgICAgICAgIHBvc2l0aW9uID0gImRvZGdlIiwgCiAgICAgICAgICAgd2lkdGggPSAuMikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKCJsZWdlbmQiLCB2YWx1ZXMgPSBwYWdlQ2hhcnRDb2xvcnMpICsKICBzY2FsZV9jb2xvcl9tYW51YWwoImxlZ2VuZCIsIHZhbHVlcyA9IHBhZ2VDaGFydENvbG9ycykgKwogIGdndGl0bGUoJ0F1dHVtbiBCYW5uZXIgQ2FtcGFpZ24gMjAxNzogUGFnZSBWaWV3cycpICsKICB0aGVtZV9taW5pbWFsKCkgKyAKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBzaXplID0gOCwgaGp1c3QgPSAxKSkgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSkgKwogIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfYmxhbmsoKSkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSkgKwogIHRoZW1lKHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCkpCmBgYAoKIyMjIyAxLjIuNCBQYWdlIFZpZXdzL0Jhbm5lciBDbGlja3MgRGF0YXNldCAgCgpUaGUgYFBhZ2VgIGNvbHVtbiByZWZlcnMgdG8gZWl0aGVyIG9uZSBvZiB0aGUgdHdvIGNhbXBhaWduIGxhbmRpbmcgcGFnZXMgb3IgdGhlIHJlZ2lzdHJhdGlvbiBwYWdlLiBUaGUgYFNvdXJjZWAgY29sdW1uIGVuY29tcGFzc2VzIGJvdGggY2FtcGFpZ24gYmFubmVyIGNsaWNrcyBhbmQgY2FtcGFpZ24gcGFnZXMgYXMgcmVmZXJlcnMgb2YgdGhlIGBQYWdlYC4gVGhlIGBDb3VudGAgZGF0YSBoYXZlIGEgZGFpbHkgcmVzb2x1dGlvbi4gIAoKYGBge3IgZWNobyA9IFQsIHdhcm5pbmcgPSAnaGlkZScsIG1lc3NhZ2UgPSBGfQojIyMgLS0tIEZ1bGwgRGF0YXNldCAoVGFibGUgUmVwb3J0KQpkYXRhdGFibGUodGFibGVTZXQpCmBgYAoKIyMgMi4gQ2FtcGFpZ24gVXNlciBSZWdpc3RyYXRpb25zCgojIyMgMi4xIEFuYWx5emUgVXNlciBSZWdpc3RyYXRpb24gRGF0YQoKYGBge3IgZWNobyA9IFQsIHdhcm5pbmcgPSAnaGlkZScsIG1lc3NhZ2UgPSBGfQojIyMgLS0tIENhbXBhaWduIFVzZXIgUmVnaXN0cmF0aW9ucwpsRiA8LSBsaXN0LmZpbGVzKHBhdGggPSAiLi9fZGFpbHlVcGRhdGVEQVRBLyIpCmxGIDwtIGxGW2dyZXBsKCd1c2VyUmVnaXN0cmF0aW9ucycsIGxGLCBmaXhlZCA9IFQpXQp1c2VyUmVnIDwtIHJlYWQudGFibGUocGFzdGUoIi4vdXNlclJlZ0RBVEEvIiwgbEYsIHNlcCA9ICIiKSwKICAgICAgICAgICAgICAgICAgICAgIHNlcCA9ICJcdCIsCiAgICAgICAgICAgICAgICAgICAgICBoZWFkZXIgPSBULAogICAgICAgICAgICAgICAgICAgICAgY2hlY2submFtZXMgPSBGLAogICAgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IEYpCnVzZXJSZWckdGltZXN0YW1wIDwtIGFzLmNoYXJhY3Rlcih1c2VyUmVnJHRpbWVzdGFtcCkKdXNlclJlZyR0aW1lc3RhbXAgPC0gc2FwcGx5KHVzZXJSZWckdGltZXN0YW1wLCBmdW5jdGlvbih4KSB7CiAgeSA8LSBzdWJzdHIoeCwgMSwgNCkKICBtIDwtIHN1YnN0cih4LCA1LCA2KQogIGQgPC0gc3Vic3RyKHgsIDcsIDgpCiAgcGFzdGUoeSwgbSwgZCwgc2VwID0gIi0iKQp9KQp1c2VyUmVnIDwtIHVzZXJSZWcgJT4lIAogIGRwbHlyOjpzZWxlY3QoaWQsIGV2ZW50X3VzZXJJZCwgdGltZXN0YW1wLCBldmVudF9pc1NlbGZNYWRlLCBldmVudF9jYW1wYWlnbikgJT4lIAogIGZpbHRlcihldmVudF9pc1NlbGZNYWRlID09IDEpCnJlZ1Bsb3RTZXQgPC0gdXNlclJlZyAlPiUgCiAgZHBseXI6OmZpbHRlcihldmVudF9pc1NlbGZNYWRlID09IDEgJiBncmVwbCgid21kZV9hYmMyMDE3IiwgZXZlbnRfY2FtcGFpZ24pKSAlPiUgCiAgZ3JvdXBfYnkoZXZlbnRfY2FtcGFpZ24sIHRpbWVzdGFtcCkgJT4lIAogIHN1bW1hcmlzZShSZWdpc3RyYXRpb25zID0gbigpKSAlPiUgCiAgYXJyYW5nZSh0aW1lc3RhbXApCmNvbG5hbWVzKHJlZ1Bsb3RTZXQpIDwtIGMoJ0NhbXBhaWduJywgJ0RhdGUnLCAnUmVnaXN0cmF0aW9ucycpCnJlZ1Bsb3RTZXQkQ2FtcGFpZ24gPC0gc2FwcGx5KHJlZ1Bsb3RTZXQkQ2FtcGFpZ24sIGZ1bmN0aW9uKHgpIHsKICBvdXQgPC0gdG91cHBlcihzdHJzcGxpdCh4LCBzcGxpdCA9ICJfIiwgZml4ZWQgPSBUKVtbMV1dWzNdKQp9KQpnZ3Bsb3QocmVnUGxvdFNldCwgYWVzKHggPSBEYXRlLAogICAgICAgICAgICAgICAgICAgICAgIHkgPSBSZWdpc3RyYXRpb25zLAogICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gQ2FtcGFpZ24sCiAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBDYW1wYWlnbiwKICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gQ2FtcGFpZ24sCiAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSBSZWdpc3RyYXRpb25zKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCAKICAgICAgICAgICBwb3NpdGlvbiA9ICJkb2RnZSIsIAogICAgICAgICAgIHdpZHRoID0gLjUpICsKICBzY2FsZV9maWxsX21hbnVhbCgibGVnZW5kIiwgdmFsdWVzID0gY2FtcGFpZ25DaGFydENvbG9ycykgKwogIHNjYWxlX2NvbG9yX21hbnVhbCgibGVnZW5kIiwgdmFsdWVzID0gY2FtcGFpZ25DaGFydENvbG9ycykgKwogIGdndGl0bGUoJ0F1dHVtbiBCYW5uZXIgQ2FtcGFpZ24gMjAxNzogVXNlciBSZWdpc3RyYXRpb25zJykgKwogIHRoZW1lX21pbmltYWwoKSArIAogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHNpemUgPSA4LCBoanVzdCA9IDEpKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApKSArCiAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vci54ID0gZWxlbWVudF9ibGFuaygpKSArCiAgdGhlbWUocGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCgojIyAzLiBDYW1wYWlnbiBHdWlkZWQgVG91cgoKIyMjIDMuMSBDb2xsZWN0IEd1aWRlZCBUb3VyIERhdGEKCioqTk9URToqKiB0aGUgZm9sbG93aW5nIGNvZGUgaXMgbm90IGZ1bGx5IHJlcHJvZHVjaWJsZSBmcm9tIHRoaXMgUmVwb3J0LiBUaGUgZGF0YSBhcmUgY29sbGVjdGVkIGJ5IHJ1bm5pbmcgdGhlIHNjcmlwdCBgYWJjMjAxN19QUk9EX0d1aWRlZFRvdXIuUmAgb24gc3RhdDEwMDUuZXFpYWQud21uZXQsIGNvbGxlY3RpbmcgdGhlIGRhdGEgYXMgYC5jc3ZgIGZpbGVzLCBjb3B5aW5nIG1hbnVhbGx5LCBhbmQgcHJvY2Vzc2luZyBsb2NhbGx5LgoKYGBge3IgZWNobyA9IFQsIGV2YWwgPSBGfQoKIyMjIC0tLSBOT1RFOgojIEZvciB0aGUgZ3VpZGVkIHRvdXJzIGl0IHdvdWxkIGJlIGdyZWF0IHRvIGhhdmUgdHdvIG51bWJlcnM6CiMgCiMgICAgIE51bWJlciBvZiBwZW9wbGUgd2hvIHN0YXJ0ZWQgdGhlIGd1aWRlZCB0b3VyIC8gY29tcGxldGVkIHRoZSBmaXJzdCBzdGVwIC9hbmQgdGhhbiBkaWQgd2hhdGV2ZXIgKGV4aXRlZCwgb3Igbm90KQojICAgICBOdW1iZXIgb2YgcGVvcGxlIHdobyBjb21wbGV0ZWQgdGhlIGd1aWRlZCB0b3VyCgoKIyBsb2cuR3VpZGVkVG91ckV4aXRlZF84NjkwNTY2CiMgaHR0cHM6Ly9tZXRhLndpa2ltZWRpYS5vcmcvd2lraS9TY2hlbWE6R3VpZGVkVG91ckV4aXRlZAojIEFMU08gVEFLRSBBIExPT0sgQVQ6IGxvZy5HdWlkZWRUb3VyR3VpZGVySGlkZGVuXzg2OTA1NDkKIyBBTFNPIFRBS0UgQSBMT09LIEFUOiBodHRwczovL21ldGEud2lraW1lZGlhLm9yZy93aWtpL1NjaGVtYTpHdWlkZWRUb3VyR3VpZGVySGlkZGVuCgojIyMgMi4xIENvbGxlY3QgVXNlciBSZWdpc3RyYXRpb24gRGF0YQojIyMgLS0tIFNjcmlwdDogYWJjMjAxN19QUk9EX0d1aWRlZFRvdXIuUgojIyMgLS0tIHRoZSBmb2xsb3dpbmcgcnVucyBvbiBzdGF0MTAwNS5lcWlhZC53bW5ldAojIyMgLS0tIFJzY3JpcHQgL2hvbWUvZ29yYW5zbS9SU2NyaXB0cy9hYmMyMDE3L2FiYzIwMTdfUFJPRF9SZWdpc3RyYXRpb25zLlIKCiMgLSBTZXJ2ZXJTaWRlQWNjb3VudENyZWF0aW9uXzU0ODczNDUKcUNvbW1hbmQgPC0gIm15c3FsIC0tZGVmYXVsdHMtZmlsZT0vZXRjL215c3FsL2NvbmYuZC9hbmFseXRpY3MtcmVzZWFyY2gtY2xpZW50LmNuZiAtaCBhbmFseXRpY3Mtc3RvcmUuZXFpYWQud21uZXQgLUEgLWUgXCJzZWxlY3QgKiBmcm9tIGxvZy5HdWlkZWRUb3VyRXhpdGVkXzg2OTA1NjYgd2hlcmUgKCh3ZWJIb3N0ID0gJ2RlLndpa2lwZWRpYS5vcmcnKSBhbmQgKHRpbWVzdGFtcCA+PSAyMDE3MDkyMDAwMDAwMCkpO1wiID4gL2hvbWUvZ29yYW5zbS9fbWlzY1dNREUvYWJjMjAxN19EYXRhT1VUL2FiY190ZXN0L2FiYzIwMTdfZ3VpZGVkVG91cnMudHN2IgpzeXN0ZW0oY29tbWFuZCA9IHFDb21tYW5kLCB3YWl0ID0gVFJVRSkKYGBgCgojIyMgMy4yIEFuYWx5emUgR3VpZGVkIFRvdXIgRGF0YQoKCiMjIDQuIFVzZXIgRWRpdHMKCgojIyA1LiBDYW1wYWlnbiBFdmFsdWF0aW9uCgoKIyMjIDUuMSBDYW1wYWlnbiBNdWx0aS1DaGFubmVsIEF0dHJpYnV0aW9uIE1vZGVsCgoKIyMjIDUuMiBDYW1wYWlnbiBDYXVzYWwgSW1wYWN0CgoKCgoK