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

The campaign is run from 1. January 2018 to N January 2018.

knitr::opts_knit$set(root.dir = '/home/goransm/Work/___DataKolektiv/Projects/WikimediaDEU/_WMDE_Projects/_misc/NewEditors_Team/Thank_You_Campaign_2018/_dailyUpdate/')

0. Data Acquisiton

NOTE: the Data Acquisition code chunk is not fully reproducible from this Report. The data are collected by running the script ThankYou_2018_Production_SQL.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/WMDE_Campaigns/ThankYou2018/ThankYou_2018_Production_SQL.R.

### --- from stat1005: Thank You 2018 Banner Campaign
### --- production script: fetch the campaign data sets

### --- Campaign Details: 
# - estimated start: 1st January 2018 (+/- 2 days)
# - estimated duration: 6 to 10 days
# - Reporting should start on 2nd January 2018. 
# - The report must include any activity from the beginning of the campaign. 
# - The estimated start will be 1st January 2018.

# - Guided Tour names
# - (The training modules include 2 new guided tours):
# - ?tour=diskutieren
# - ?tour=seimutig

### --- Training Modules Schema: 
### --- https://meta.wikimedia.org/wiki/User:Stefan_Schneider_(WMDE)/dashboard_libraries/wikipedia-kurse.json
### --- the slug field is relevant for tracking

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

### --- Directories
bannerImpressionsDir <- '/home/goransm/RScripts/WMDE_Campaigns/ThankYou2018/BannerImpressions'
bannerClicksDir <- '/home/goransm/RScripts/WMDE_Campaigns/ThankYou2018/BannerClicks'
dailyUpdateDir <- '/home/goransm/RScripts/WMDE_Campaigns/ThankYou2018/ThankYou2018_DailyUpdate' 

### --- Campaign time range
startDate <- '2018-01-02'
endDate <- '2018-01-08'

### ------------------------------------------------------------
### --- S1. Banner Impression Data
### ------------------------------------------------------------

# - campaign tag
# - Name: bt1, ?campaign=wmde_etc2017_bt1

### --- loop over date range, create query, fetch, and store
dateRange <- seq.POSIXt(from = as.POSIXlt(startDate, tz = "CET"),
                        to = as.POSIXlt(endDate, tz = "CET"),
                        by = 'hour')
dateRange <- dateRange[-length(dateRange)]
cetDateRange <- as.character(dateRange)
cetDateRange <- sapply(cetDateRange, function(x) {
  strsplit(x, split = " ", fixed = T)[[1]][1]
})
names(dateRange) <- cetDateRange
dateRange <- as.POSIXlt(dateRange, tz = "UTC")
# - up to the campaign end:
endCampaign <- as.POSIXlt(endDate, tz = "UTC")
w <- which(dateRange > endCampaign)
if (length(w) > 0) {
  dateRange <- dateRange[-w]
}
dR <- list()
for (i in 1:length(dateRange)) {
  dR[[i]] <- data.frame(
    cetName = names(dateRange[i]),
    utcYear = year(dateRange[i]),
    utcMonth = month(dateRange[i]),
    utcDay = mday(dateRange[i]),
    utcHour = hour(dateRange[i])
  )
}
dR <- rbindlist(dR)
dR <- dR %>%
  group_by(cetName, utcYear, utcMonth, utcDay) %>%
  summarise(utcHour = paste("hour=", utcHour, collapse = " OR ", sep = ""))

### ------------------------------------------------------------
### --- S2. Banner Landing Page Data
### ------------------------------------------------------------

# - landing page link including the appropriate campaign tag
# - Link:https://de.wikipedia.org/wiki/Wikipedia:Wikimedia_Deutschland/LerneWikipedia?campaign=wmde_etc2017_bt1

# - set bannerClicksDir
setwd(bannerClicksDir)

for (i in 1:length(unique(dR$cetName))) {
  
  wCetName <- which(dR$cetName %in% unique(dR$cetName)[i])
  
  for (j in 1:length(wCetName)) {
    
    # - construct HiveQL query:
    y <- dR$utcYear[wCetName[j]]
    m <- dR$utcMonth[wCetName[j]]
    d <- dR$utcDay[wCetName[j]]
    hour <- dR$utcHour[wCetName[j]]
    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/LerneWikipedia' 
      AND year = ", y,
      " AND month = ", m,
      " AND day = ", d,
      " AND (", hour, ");",
      sep = "")
    # - write hql
    write(q, 'thankyou2018_BannerClicks.hql')
    # - prepare output file:
    fileName <- "thankyou2018_BannerClicks_"
    fileName <- paste0(fileName,
                       as.character(unique(dR$cetName)[i]),
                       "_", j,
                       ".tsv")
    fileName <- paste0(bannerClicksDir, "/", fileName)
    # - execute hql script:
    hiveArgs <-
      'beeline -f'
    hiveInput <- paste0('thankyou2018_BannerClicks.hql > ',
                        fileName)
    # - command:
    hiveCommand <- paste(hiveArgs, hiveInput)
    system(command = hiveCommand, wait = TRUE)
    
  }
  
}

### --- Wrangle this dataset:

### --- Banner tags:
campaignBanner <- 'wmde_etc2017_bt1'

### --- Dataset:
# - count non-empty files:
c <- 0
lF <- list.files()
lF <- lF[grepl('.tsv', lF, fixed = T)]
lF <- lF[grepl('Clicks', lF, fixed = T)]
dataSet <- list()
for (i in 1:length(lF)) {
  dS <- readLines(lF[i], n = -1)
  timeStamp <- strsplit(lF[i], split = "_")[[1]][3]
  bannerClicks <- sum(grepl(campaignBanner, dS, fixed = T))
  dataSet[[i]] <- data.frame(timestamp = timeStamp,
                             bannerClicks = bannerClicks,
                             stringsAsFactors = F)
}
dataSet <- rbindlist(dataSet)

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

### --- SQL
startDate <- '2018-01-01'

### ------------------------------------------------------------
### --- S3. User Registration Data
### ------------------------------------------------------------

# - NOTE: UTC timestamps - adjustment for CE(S)T introduced. 
# - ServerSideAccountCreation_5487345
qCommand <- paste("mysql --defaults-file=/etc/mysql/conf.d/analytics-research-client.cnf -h analytics-slave.eqiad.wmnet -A -e \"select * from log.ServerSideAccountCreation_5487345 where ((webHost = 'de.wikipedia.org') and (timestamp >= ", gsub("-", "", startDate, fixed = T), "220000));\" > ",
            dailyUpdateDir, "/thankyou_2018_userRegistrations.tsv", sep = "")
system(command = qCommand, wait = TRUE)


### ------------------------------------------------------------
### --- S4. Guided Tours Data
### ------------------------------------------------------------

# - NOTE: UTC timestamps - adjustment for CE(S)T introduced. 
# - ServerSideAccountCreation_5487345
qCommand <- paste("mysql --defaults-file=/etc/mysql/conf.d/analytics-research-client.cnf -h analytics-slave.eqiad.wmnet -A -e \"select * from log.GuidedTourExited_8690566 where ((webHost = 'de.wikipedia.org') and (timestamp >= ", 
                  gsub("-", "", startDate, fixed = T), "220000));\" > ", 
                  dailyUpdateDir, "/thankyou_2018_guidedTours.tsv", sep = "")
system(command = qCommand, wait = TRUE)

### ------------------------------------------------------------
### --- S5. User Edit Data
### ------------------------------------------------------------

# - get user IDs from registered:
lF <- list.files()
lF <- lF[grepl('userRegistrations', lF, fixed = T)]
userReg <- read.table(lF, 
                      quote = "",
                      sep = "\t",
                      header = T,
                      check.names = F,
                      stringsAsFactors = F)
userReg <- userReg %>% 
  dplyr::select(event_userId, event_isSelfMade, event_campaign) %>% 
  filter(event_isSelfMade == 1) %>% 
  filter(event_campaign %in% "wmde_etc2017_bt1")
# - 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 = ""), 
                      dailyUpdateDir, '/thankyou_2018_userEdits.tsv', sep = "")
system(command = mySqlCommand, 
       wait = TRUE)

### ------------------------------------------------------------
### --- S6. Training Module Data
### ------------------------------------------------------------

1A. Campaign Banner Impressions

1A. 1 The data set

# - report: current update
print(paste0("Current update: ", as.character(Sys.time())))
[1] "Current update: 2018-01-17 10:12:14"
bannerImpressions <- read.csv('thankyouBannerImpressions.csv',
                              row.names = 1,
                              header = T,
                              stringsAsFactors = F) %>% 
  gather(key =  Banner,
         value = Views,
         B17WMDE_thankyou_authors:B17WMDE_thankyou_authors_mob_B) %>% 
  group_by(timeStamp, Banner) %>% 
  summarise(Views = sum(Views))
knitr::kable(bannerImpressions, format = "html") %>% 
  kable_styling(full_width = F, position = "left")
timeStamp Banner Views
2018-01-01 B17WMDE_thankyou_authors 257533
2018-01-01 B17WMDE_thankyou_authors_B 128423
2018-01-01 B17WMDE_thankyou_authors_mob_A 0
2018-01-01 B17WMDE_thankyou_authors_mob_B 0
2018-01-01 B17WMDE_thankyou_authors_pad_A 0
2018-01-01 B17WMDE_thankyou_authors_pad_B 0
2018-01-02 B17WMDE_thankyou_authors 741533
2018-01-02 B17WMDE_thankyou_authors_B 370737
2018-01-02 B17WMDE_thankyou_authors_mob_A 0
2018-01-02 B17WMDE_thankyou_authors_mob_B 3
2018-01-02 B17WMDE_thankyou_authors_pad_A 0
2018-01-02 B17WMDE_thankyou_authors_pad_B 0
2018-01-03 B17WMDE_thankyou_authors 824290
2018-01-03 B17WMDE_thankyou_authors_B 410722
2018-01-03 B17WMDE_thankyou_authors_mob_A 0
2018-01-03 B17WMDE_thankyou_authors_mob_B 0
2018-01-03 B17WMDE_thankyou_authors_pad_A 0
2018-01-03 B17WMDE_thankyou_authors_pad_B 0
2018-01-04 B17WMDE_thankyou_authors 818331
2018-01-04 B17WMDE_thankyou_authors_B 409420
2018-01-04 B17WMDE_thankyou_authors_mob_A 0
2018-01-04 B17WMDE_thankyou_authors_mob_B 0
2018-01-04 B17WMDE_thankyou_authors_pad_A 0
2018-01-04 B17WMDE_thankyou_authors_pad_B 0
2018-01-05 B17WMDE_thankyou_authors 750962
2018-01-05 B17WMDE_thankyou_authors_B 375077
2018-01-05 B17WMDE_thankyou_authors_mob_A 0
2018-01-05 B17WMDE_thankyou_authors_mob_B 2
2018-01-05 B17WMDE_thankyou_authors_pad_A 0
2018-01-05 B17WMDE_thankyou_authors_pad_B 0
2018-01-06 B17WMDE_thankyou_authors 586811
2018-01-06 B17WMDE_thankyou_authors_B 293237
2018-01-06 B17WMDE_thankyou_authors_mob_A 0
2018-01-06 B17WMDE_thankyou_authors_mob_B 0
2018-01-06 B17WMDE_thankyou_authors_pad_A 0
2018-01-06 B17WMDE_thankyou_authors_pad_B 0
2018-01-07 B17WMDE_thankyou_authors 706186
2018-01-07 B17WMDE_thankyou_authors_B 352536
2018-01-07 B17WMDE_thankyou_authors_mob_A 0
2018-01-07 B17WMDE_thankyou_authors_mob_B 0
2018-01-07 B17WMDE_thankyou_authors_pad_A 0
2018-01-07 B17WMDE_thankyou_authors_pad_B 0
2018-01-08 B17WMDE_thankyou_authors 920162
2018-01-08 B17WMDE_thankyou_authors_B 460469
2018-01-08 B17WMDE_thankyou_authors_mob_A 0
2018-01-08 B17WMDE_thankyou_authors_mob_B 0
2018-01-08 B17WMDE_thankyou_authors_pad_A 0
2018-01-08 B17WMDE_thankyou_authors_pad_B 0
2018-01-09 B17WMDE_thankyou_authors 988107
2018-01-09 B17WMDE_thankyou_authors_B 495139
2018-01-09 B17WMDE_thankyou_authors_mob_A 0
2018-01-09 B17WMDE_thankyou_authors_mob_B 0
2018-01-09 B17WMDE_thankyou_authors_pad_A 0
2018-01-09 B17WMDE_thankyou_authors_pad_B 0
2018-01-10 B17WMDE_thankyou_authors 990820
2018-01-10 B17WMDE_thankyou_authors_B 495235
2018-01-10 B17WMDE_thankyou_authors_mob_A 0
2018-01-10 B17WMDE_thankyou_authors_mob_B 0
2018-01-10 B17WMDE_thankyou_authors_pad_A 0
2018-01-10 B17WMDE_thankyou_authors_pad_B 0
2018-01-11 B17WMDE_thankyou_authors 986539
2018-01-11 B17WMDE_thankyou_authors_B 493215
2018-01-11 B17WMDE_thankyou_authors_mob_A 0
2018-01-11 B17WMDE_thankyou_authors_mob_B 1
2018-01-11 B17WMDE_thankyou_authors_pad_A 0
2018-01-11 B17WMDE_thankyou_authors_pad_B 0
2018-01-12 B17WMDE_thankyou_authors 852340
2018-01-12 B17WMDE_thankyou_authors_B 426957
2018-01-12 B17WMDE_thankyou_authors_mob_A 0
2018-01-12 B17WMDE_thankyou_authors_mob_B 0
2018-01-12 B17WMDE_thankyou_authors_pad_A 0
2018-01-12 B17WMDE_thankyou_authors_pad_B 0
2018-01-13 B17WMDE_thankyou_authors 628561
2018-01-13 B17WMDE_thankyou_authors_B 313426
2018-01-13 B17WMDE_thankyou_authors_mob_A 0
2018-01-13 B17WMDE_thankyou_authors_mob_B 0
2018-01-13 B17WMDE_thankyou_authors_pad_A 0
2018-01-13 B17WMDE_thankyou_authors_pad_B 0
2018-01-14 B17WMDE_thankyou_authors 779314
2018-01-14 B17WMDE_thankyou_authors_B 389017
2018-01-14 B17WMDE_thankyou_authors_mob_A 0
2018-01-14 B17WMDE_thankyou_authors_mob_B 0
2018-01-14 B17WMDE_thankyou_authors_pad_A 0
2018-01-14 B17WMDE_thankyou_authors_pad_B 0

1A. 2 Chart

ggplot(bannerImpressions, aes(x = timeStamp,
                    y = Views,
                    color = Banner,
                    label = Views)) +
  geom_line(aes(group = Banner), size = .25) +
  geom_point(size = 1.5) +
  geom_point(size = 1, color = "white") + 
  scale_y_continuous(labels = scales::comma) +
  ggtitle('Thank You 2018:\nOverview of BannerImpressions') +
  ylab("Impressions") +
  geom_text_repel(size = 3) +
  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())

1B. Campaign Pageviews (Banner Clicks)

1B. 1 The data set

pageviews <- read.csv('thankyou2018_BannerClicksPageViews_Update.csv',
                      row.names = 1,
                      header = T,
                      stringsAsFactors = F)
pageviews <- pageviews %>% 
  group_by(timestamp) %>% 
  summarise(Pageviews = sum(bannerClicks))
knitr::kable(pageviews, format = "html") %>% 
  kable_styling(full_width = F, position = "left")
timestamp Pageviews
2018-01-01 533
2018-01-02 1188
2018-01-03 1269
2018-01-04 1148
2018-01-05 1122
2018-01-06 1148
2018-01-07 1242
2018-01-08 1150
2018-01-09 1254
2018-01-10 1347
2018-01-11 1773
2018-01-12 1214
2018-01-13 1201
2018-01-14 1492

1B. 2 Chart

ggplot(pageviews, aes(x = timestamp,
                    y = Pageviews,
                    label = Pageviews)) +
  geom_bar(stat = "identity", 
           position = "dodge", 
           width = .15, 
           fill = "white", 
           color = "darkblue") +
  ggtitle('Thank You 2018:\nOverview of Landing Pageviews') +
  geom_label(size = 3) +
  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())

2. Campaign User Registrations

2. 1 The data set

userReg <- read.delim('thankyou_2018_userRegistrations.tsv',
                      sep = "\t",
                      quote = "",
                      header = T,
                      # row.names = 1,
                      stringsAsFactors = F)
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)
  part1Date <- paste(y, m, d, sep = "-")
  hr <- substr(x, 9, 10)
  mi <- substr(x, 11, 12)
  se <- substr(x, 13, 14)
  part2Date <- paste(hr, mi, se, sep = ":")
  paste(part1Date, part2Date, sep = " ")
})
userReg$timestamp <- as.POSIXct(userReg$timestamp, tz = "UTC")
timeDiff <- 
  as.POSIXct(as.character(Sys.time()), tz = "UTC") - as.POSIXct(as.character(Sys.time()), tz = "Europe/Berlin")
userReg$timestamp <- as.character(userReg$timestamp + timeDiff)
userReg$timestamp <- sapply(userReg$timestamp, function(x) {
  y <- substr(x, 1, 4)
  m <- substr(x, 6, 7)
  d <- substr(x, 9, 10) 
  paste(y, m, d, sep = "-")
})
userReg <- userReg %>%
  filter(event_campaign %in% 'wmde_etc2017_bt1') %>% 
  group_by(timestamp) %>% 
  summarise(Registrations = n())
knitr::kable(userReg, format = "html") %>% 
  kable_styling(full_width = F, position = "left")
timestamp Registrations
2018-01-01 1
2018-01-02 8
2018-01-03 15
2018-01-04 13
2018-01-05 5
2018-01-06 6
2018-01-07 12
2018-01-08 6
2018-01-09 9
2018-01-10 7
2018-01-11 15
2018-01-12 9
2018-01-13 3
2018-01-14 11
2018-01-15 1

2. 2 Chart

ggplot(userReg, aes(x = timestamp,
                    y = Registrations,
                    label = Registrations)) +
  geom_bar(stat = "identity", 
           position = "dodge", 
           width = .15, 
           fill = "white", 
           color = "darkblue") +
  ggtitle('Thank You 2018:\nOverview of User Registrations') +
  geom_label(size = 3) +
  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 User Edits

3. 1 The data set

userEdits <- readLines('thankyou_2018_userEdits.tsv', n = -1)
if (length(userEdits) >= 1) {
  userEdits <- read.delim('thankyou_2018_userEdits.tsv',
                          sep = "\t",
                          header = T,
                          stringsAsFactors = F)
  # - report
  print(paste0(sum(userEdits$edits), " edits were made by the campaign registered users thus far."))
} else {
  print("There are currently no user edits from this campaign.")
}
[1] "135 edits were made by the campaign registered users thus far."

3. 2 Chart

4. Campaign Guided Tours

4. 1 The data set: Guided Tour Exit Steps

Campaign guided tours: diskutieren and seimutig.

tours <- c('diskutieren', 'seimutig')
# setwd('/home/goransm/Work/___DataKolektiv/Projects/WikimediaDEU/_WMDE_Projects/_misc/NewEditors_Team/Thank_You_Campaign_2018/_dailyUpdate/')
gTours <- read.delim('thankyou_2018_guidedTours.tsv',
                     sep = "\t",
                     header = T,
                     row.names = 1,
                     stringsAsFactors = F)
gTours$timestamp <- as.character(gTours$timestamp)
gTours$timestamp <- sapply(gTours$timestamp, function(x) {
  y <- substr(x, 1, 4)
  m <- substr(x, 5, 6)
  d <- substr(x, 7, 8)
  part1Date <- paste(y, m, d, sep = "-")
  hr <- substr(x, 9, 10)
  mi <- substr(x, 11, 12)
  se <- substr(x, 13, 14)
  part2Date <- paste(hr, mi, se, sep = ":")
  paste(part1Date, part2Date, sep = " ")
})
gTours$timestamp <- as.POSIXct(gTours$timestamp, tz = "UTC")
timeDiff <- 
  as.POSIXct(as.character(Sys.time()), tz = "UTC") - as.POSIXct(as.character(Sys.time()), tz = "Europe/Berlin")
gTours$timestamp <- as.character(gTours$timestamp + timeDiff)
gTours$timestamp <- sapply(gTours$timestamp, function(x) {
  y <- substr(x, 1, 4)
  m <- substr(x, 6, 7)
  d <- substr(x, 9, 10) 
  paste(y, m, d, sep = "-")
})
# - anonymize event_userId
eventUserId <- setdiff(unique(gTours$event_userId), 0)
an_userId <- character(length(eventUserId))
for (i in 1:length(an_userId)) {
  id <- round(runif(1, 1, 10e6))
  while (id %in% an_userId) {
    id <- round(runif(1, 1, 10e6))
  }
  an_userId[i] <- id
}
an_userId <- paste0("u_", an_userId)
gTours$an_userId <- sapply(gTours$event_userId, function(x) {
  w <- which(eventUserId %in% x)
  if (length(w) > 0) {
    an_userId[w]
  } else {
    x
  }
})
# - look up for the campaign guided tours
w <- which(gTours$event_tour %in% tours)
if (length(w) > 0) {
  gTours <- gTours[w, ]
  gTours <- gTours %>% 
    filter(event_userId != 0) %>% 
    select(timestamp, event_tour, event_step, an_userId)
  knitr::kable(gTours, format = "html") %>% 
  kable_styling(full_width = F, position = "left")
} else {
  print("There are currently no data on guided tours from this campaign.")
}
timestamp event_tour event_step an_userId
2018-01-03 diskutieren returnToTraining u_5167969
2018-01-03 seimutig returnToTraining u_5167969
2018-01-04 seimutig boldness u_6495795
2018-01-04 seimutig positionCursor u_6495795
2018-01-04 diskutieren returnToTraining u_6495795
2018-01-05 diskutieren saveReply u_6896279
2018-01-04 seimutig returnToTraining u_6495795
2018-01-04 seimutig editButtonCitation u_6495795
2018-01-06 seimutig editButton u_4706786
2018-01-06 seimutig boldness u_4706786
2018-01-06 diskutieren firstMessage u_4706786
2018-01-08 seimutig editBoldness u_2986526
2018-01-08 seimutig editSummary u_2986526
2018-01-08 diskutieren returnToTraining u_2986526
2018-01-10 seimutig editButton u_2672122
2018-01-10 seimutig editButton u_2672122
2018-01-10 seimutig editBoldness u_2672122
2018-01-10 seimutig editSummary u_2672122
2018-01-10 seimutig editButtonCitation u_2672122
2018-01-10 seimutig saveCitation u_2672122
2018-01-10 seimutig editButton u_2672122
2018-01-10 diskutieren returnToTraining u_2672122
2018-01-11 seimutig editBoldness u_771518
2018-01-11 seimutig boldness u_771518
2018-01-11 seimutig insertCitation u_771518
2018-01-11 seimutig anyEdit u_771518
2018-01-11 diskutieren returnToTraining u_771518
2018-01-11 seimutig anyEdit u_4425925

4. 2 Unique users in Guided Tours

Campaign guided tours: diskutieren and seimutig.

gTours %>% 
  select(event_tour) %>% 
  group_by(event_tour) %>% 
  summarise(`Unique users` = n()) %>% 
  knitr::kable(format = "html") %>% 
  kable_styling(full_width = F, position = "left")
event_tour Unique users
diskutieren 7
seimutig 21

5 Training Module

trainData <- read.csv('wmde_training_data.csv')
# - remove first two rows (test data)
trainData <- trainData[-c(1,2), ]
# - get user IDs from registered:
lF <- list.files()
lF <- lF[grepl('userRegistrations', lF, fixed = T)]
userData <- read.table(lF, 
                      quote = "",
                      sep = "\t",
                      header = T,
                      check.names = F,
                      stringsAsFactors = F)
gtData <- read.delim('thankyou_2018_guidedTours.tsv',
                     sep = "\t",
                     header = T,
                     row.names = 1,
                     stringsAsFactors = F)
edData <- read.delim('thankyou_2018_userEdits.tsv',
                     sep = "\t",
                     header = T,
                     stringsAsFactors = F)

5.1 Training Module Overview

How many registered users take the Training Module?

print(paste0("Number of uses who took the Training Module is ", 
             length(trainData$username),
             " , which is ",
             round(length(trainData$username)/sum(userReg$Registrations)*100, 2),
             "% of registered users."
               ))
[1] "Number of uses who took the Training Module is 67 , which is 55.37% of registered users."

What are the last completed slides per user Training Module?

slidesData <- trainData %>% 
  select(training_module, last_slide_completed) %>% 
  group_by(training_module, last_slide_completed) %>% 
  summarise(Count = n()) %>% 
  arrange(training_module, desc(Count))
knitr::kable(slidesData, format = "html") %>%
  kable_styling(full_width = F, position = "left")
training_module last_slide_completed Count
artikel-bewerten fertig 6
artikel-bewerten artikel-qualitat-bewerten 1
artikel-bewerten artikel-qualitat-quiz 1
editieren-basiswissen das-wars 7
editieren-basiswissen video-wiki-code 2
editieren-basiswissen visual-editor-buttons 2
editieren-basiswissen beobachtungsliste-video 1
editieren-basiswissen edit-vs-edit-quelle 1
editieren-basiswissen versuche-es 1
wikipedia-basiswissen relevanz-quiz-fortsetzung 35
wikipedia-basiswissen richtlinien-der-wikipedia 2
wikipedia-basiswissen urheberrecht-und-plagiate 2
wikipedia-basiswissen wikipedia-ist-frei 2
wikipedia-basiswissen nachweisbarkeit-quiz 1
wikipedia-basiswissen prinzipien-ruckblick 1
wikipedia-basiswissen relevanz 1
wikipedia-basiswissen sei-respektvoll 1
ggplot(slidesData, aes(x = last_slide_completed,
                       y = Count,
                       color = training_module,
                       label = Count)) +
  geom_line(aes(group = 1), size = .25) +
  geom_point(size = 1.5) +
  geom_point(size = 1, color = "white") + 
  scale_y_continuous(labels = scales::comma) +
  ggtitle('Thank You 2018:\nOverview of Training Modules') +
  ylab("No. Users") +
  geom_text_repel(size = 3) +
  facet_wrap(~training_module) +
  theme_minimal() + 
  theme(axis.text.x = element_text(angle = 90, size = 6.5, 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())

Do users start editing after training modules? Is there a difference in users with completed and not-completed or not at all having taken the modules?

userData <- userData %>% 
  filter(event_campaign %in% 'wmde_etc2017_bt1' & event_isSelfMade) %>% 
  select(event_userId, event_userName)
userData <- left_join(userData, trainData, by = c("event_userName" = "username"))
Column `event_userName`/`username` joining character vector and factor, coercing into character vector
userData$module_completion_date <- NA
userData <- left_join(userData, 
                      gtData[, c('event_userId', 'event_tour', 'event_step')],
                      by = c('event_userId'))
userData <- left_join(userData, edData,
                      by = c('event_userId' = 'rev_user'))

How many edits were made on behalf of those users who have started the Training Module vs. those who did not?

tAn <- userData %>% 
  select(training_module, edits) %>% 
  group_by(training_module) %>% 
  summarise(Users = n(), Edits = sum(edits, na.rm = T)) %>% 
  arrange(training_module, desc(Edits))
knitr::kable(tAn, format = "html") %>%
  kable_styling(full_width = F, position = "left")
training_module Users Edits
artikel-bewerten 7 36
editieren-basiswissen 6 36
wikipedia-basiswissen 20 38
NA 111 187
print(paste0("In total, the users who took the Training Module made ", 
             sum(tAn$Edits[1:3]),
             " edits, which is ",
             round(sum(tAn$Edits[1:3])/sum(tAn$Edits)*100, 2),
             "% of all edits."
               ))
[1] "In total, the users who took the Training Module made 110 edits, which is 37.04% of all edits."
print(paste0("On the other hand, the users who did not take the Training Module made ", 
             tAn$Edits[4],
             " edits, which is ",
             round(tAn$Edits[4]/sum(tAn$Edits)*100, 2),
             "% of all edits."
               ))
[1] "On the other hand, the users who did not take the Training Module made 187 edits, which is 62.96% of all edits."
LS0tCnRpdGxlOiAnVGhhbmsgWW91IENhbXBhaWduIDIwMTg6IFJlcG9ydCcKYXV0aG9yOiAiR29yYW4gUy4gTWlsb3Zhbm92aWMsIERhdGEgQW5hbHlzdCwgV01ERSIKZGF0ZTogIkphbnVhcnksIDIwMTgiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgICB0aGVtZTogc2ltcGxleAogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCiAgICB0b2NfZGVwdGg6IDUKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogNQotLS0KCgoqKkZlZWRiYWNrKiogc2hvdWxkIGJlIHNlbmQgdG8gYGdvcmFuLm1pbG92YW5vdmljX2V4dEB3aWtpbWVkaWEuZGVgLiAKClRoZSBjYW1wYWlnbiBpcyBydW4gZnJvbSAxLiBKYW51YXJ5IDIwMTggdG8gTiBKYW51YXJ5IDIwMTguCgpgYGB7ciBzZXR1cH0Ka25pdHI6Om9wdHNfa25pdCRzZXQocm9vdC5kaXIgPSAnL2hvbWUvZ29yYW5zbS9Xb3JrL19fX0RhdGFLb2xla3Rpdi9Qcm9qZWN0cy9XaWtpbWVkaWFERVUvX1dNREVfUHJvamVjdHMvX21pc2MvTmV3RWRpdG9yc19UZWFtL1RoYW5rX1lvdV9DYW1wYWlnbl8yMDE4L19kYWlseVVwZGF0ZS8nKQpgYGAKCmBgYHtyLCBlY2hvID0gRiwgd2FybmluZyA9IEYsIG1lc3NhZ2UgPSBGLCByZXN1bHRzID0gJ2hpZGUnfQojICFkaWFnbm9zdGljcyBvZmYKIyMjIC0tLSBTZXR1cAprbml0cjo6b3B0c19jaHVuayRzZXQoZmlnLndpZHRoID0gMTUsIGZpZy5oZWlnaHQgPSA4KSAKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KGRhdGEudGFibGUpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShnZ3JlcGVsKQpsaWJyYXJ5KHNjYWxlcykKbGlicmFyeShSQ29sb3JCcmV3ZXIpCmxpYnJhcnkoa2FibGVFeHRyYSkKbGlicmFyeShybWFya2Rvd24pCmxpYnJhcnkoa25pdHIpCmxpYnJhcnkoRFQpCmxpYnJhcnkocmVzaGFwZTIpCmBgYAoKIyMgMC4gRGF0YSBBY3F1aXNpdG9uCgoqKk5PVEU6KiogdGhlIERhdGEgQWNxdWlzaXRpb24gY29kZSBjaHVuayBpcyBub3QgZnVsbHkgcmVwcm9kdWNpYmxlIGZyb20gdGhpcyBSZXBvcnQuIFRoZSBkYXRhIGFyZSBjb2xsZWN0ZWQgYnkgcnVubmluZyB0aGUgc2NyaXB0IGBUaGFua1lvdV8yMDE4X1Byb2R1Y3Rpb25fU1FMLlJgIG9uIHN0YXQxMDA1LmVxaWFkLndtbmV0LCBjb2xsZWN0aW5nIHRoZSBkYXRhIGFzIGAudHN2YCBhbmQgYC5jc3ZgIGZpbGVzLCBjb3B5aW5nIG1hbnVhbGx5LCBhbmQgcHJvY2Vzc2luZyBsb2NhbGx5LiBSdW4gZnJvbSBzdGF0MTAwNSBzdGF0IGJveCBieSBleGVjdXRpbmcgYFJzY3JpcHQgL2hvbWUvZ29yYW5zbS9SU2NyaXB0cy9XTURFX0NhbXBhaWducy9UaGFua1lvdTIwMTgvVGhhbmtZb3VfMjAxOF9Qcm9kdWN0aW9uX1NRTC5SYC4KCmBgYHtyLCBlY2hvID0gVCwgZXZhbCA9IEZ9CgojIyMgLS0tIGZyb20gc3RhdDEwMDU6IFRoYW5rIFlvdSAyMDE4IEJhbm5lciBDYW1wYWlnbgojIyMgLS0tIHByb2R1Y3Rpb24gc2NyaXB0OiBmZXRjaCB0aGUgY2FtcGFpZ24gZGF0YSBzZXRzCgojIyMgLS0tIENhbXBhaWduIERldGFpbHM6IAojIC0gZXN0aW1hdGVkIHN0YXJ0OiAxc3QgSmFudWFyeSAyMDE4ICgrLy0gMiBkYXlzKQojIC0gZXN0aW1hdGVkIGR1cmF0aW9uOiA2IHRvIDEwIGRheXMKIyAtIFJlcG9ydGluZyBzaG91bGQgc3RhcnQgb24gMm5kIEphbnVhcnkgMjAxOC4gCiMgLSBUaGUgcmVwb3J0IG11c3QgaW5jbHVkZSBhbnkgYWN0aXZpdHkgZnJvbSB0aGUgYmVnaW5uaW5nIG9mIHRoZSBjYW1wYWlnbi4gCiMgLSBUaGUgZXN0aW1hdGVkIHN0YXJ0IHdpbGwgYmUgMXN0IEphbnVhcnkgMjAxOC4KCiMgLSBHdWlkZWQgVG91ciBuYW1lcwojIC0gKFRoZSB0cmFpbmluZyBtb2R1bGVzIGluY2x1ZGUgMiBuZXcgZ3VpZGVkIHRvdXJzKToKIyAtID90b3VyPWRpc2t1dGllcmVuCiMgLSA/dG91cj1zZWltdXRpZwoKIyMjIC0tLSBUcmFpbmluZyBNb2R1bGVzIFNjaGVtYTogCiMjIyAtLS0gaHR0cHM6Ly9tZXRhLndpa2ltZWRpYS5vcmcvd2lraS9Vc2VyOlN0ZWZhbl9TY2huZWlkZXJfKFdNREUpL2Rhc2hib2FyZF9saWJyYXJpZXMvd2lraXBlZGlhLWt1cnNlLmpzb24KIyMjIC0tLSB0aGUgc2x1ZyBmaWVsZCBpcyByZWxldmFudCBmb3IgdHJhY2tpbmcKCiMjIyAtLS0gU2V0dXAKbGlicmFyeShkcGx5cikKbGlicmFyeSh0aWR5cikKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KGRhdGEudGFibGUpCgojIyMgLS0tIERpcmVjdG9yaWVzCmJhbm5lckltcHJlc3Npb25zRGlyIDwtICcvaG9tZS9nb3JhbnNtL1JTY3JpcHRzL1dNREVfQ2FtcGFpZ25zL1RoYW5rWW91MjAxOC9CYW5uZXJJbXByZXNzaW9ucycKYmFubmVyQ2xpY2tzRGlyIDwtICcvaG9tZS9nb3JhbnNtL1JTY3JpcHRzL1dNREVfQ2FtcGFpZ25zL1RoYW5rWW91MjAxOC9CYW5uZXJDbGlja3MnCmRhaWx5VXBkYXRlRGlyIDwtICcvaG9tZS9nb3JhbnNtL1JTY3JpcHRzL1dNREVfQ2FtcGFpZ25zL1RoYW5rWW91MjAxOC9UaGFua1lvdTIwMThfRGFpbHlVcGRhdGUnIAoKIyMjIC0tLSBDYW1wYWlnbiB0aW1lIHJhbmdlCnN0YXJ0RGF0ZSA8LSAnMjAxOC0wMS0wMicKZW5kRGF0ZSA8LSAnMjAxOC0wMS0wOCcKCiMjIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyMjIC0tLSBTMS4gQmFubmVyIEltcHJlc3Npb24gRGF0YQojIyMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIC0gY2FtcGFpZ24gdGFnCiMgLSBOYW1lOiBidDEsID9jYW1wYWlnbj13bWRlX2V0YzIwMTdfYnQxCgojIyMgLS0tIGxvb3Agb3ZlciBkYXRlIHJhbmdlLCBjcmVhdGUgcXVlcnksIGZldGNoLCBhbmQgc3RvcmUKZGF0ZVJhbmdlIDwtIHNlcS5QT1NJWHQoZnJvbSA9IGFzLlBPU0lYbHQoc3RhcnREYXRlLCB0eiA9ICJDRVQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgdG8gPSBhcy5QT1NJWGx0KGVuZERhdGUsIHR6ID0gIkNFVCIpLAogICAgICAgICAgICAgICAgICAgICAgICBieSA9ICdob3VyJykKZGF0ZVJhbmdlIDwtIGRhdGVSYW5nZVstbGVuZ3RoKGRhdGVSYW5nZSldCmNldERhdGVSYW5nZSA8LSBhcy5jaGFyYWN0ZXIoZGF0ZVJhbmdlKQpjZXREYXRlUmFuZ2UgPC0gc2FwcGx5KGNldERhdGVSYW5nZSwgZnVuY3Rpb24oeCkgewogIHN0cnNwbGl0KHgsIHNwbGl0ID0gIiAiLCBmaXhlZCA9IFQpW1sxXV1bMV0KfSkKbmFtZXMoZGF0ZVJhbmdlKSA8LSBjZXREYXRlUmFuZ2UKZGF0ZVJhbmdlIDwtIGFzLlBPU0lYbHQoZGF0ZVJhbmdlLCB0eiA9ICJVVEMiKQojIC0gdXAgdG8gdGhlIGNhbXBhaWduIGVuZDoKZW5kQ2FtcGFpZ24gPC0gYXMuUE9TSVhsdChlbmREYXRlLCB0eiA9ICJVVEMiKQp3IDwtIHdoaWNoKGRhdGVSYW5nZSA+IGVuZENhbXBhaWduKQppZiAobGVuZ3RoKHcpID4gMCkgewogIGRhdGVSYW5nZSA8LSBkYXRlUmFuZ2VbLXddCn0KZFIgPC0gbGlzdCgpCmZvciAoaSBpbiAxOmxlbmd0aChkYXRlUmFuZ2UpKSB7CiAgZFJbW2ldXSA8LSBkYXRhLmZyYW1lKAogICAgY2V0TmFtZSA9IG5hbWVzKGRhdGVSYW5nZVtpXSksCiAgICB1dGNZZWFyID0geWVhcihkYXRlUmFuZ2VbaV0pLAogICAgdXRjTW9udGggPSBtb250aChkYXRlUmFuZ2VbaV0pLAogICAgdXRjRGF5ID0gbWRheShkYXRlUmFuZ2VbaV0pLAogICAgdXRjSG91ciA9IGhvdXIoZGF0ZVJhbmdlW2ldKQogICkKfQpkUiA8LSByYmluZGxpc3QoZFIpCmRSIDwtIGRSICU+JQogIGdyb3VwX2J5KGNldE5hbWUsIHV0Y1llYXIsIHV0Y01vbnRoLCB1dGNEYXkpICU+JQogIHN1bW1hcmlzZSh1dGNIb3VyID0gcGFzdGUoImhvdXI9IiwgdXRjSG91ciwgY29sbGFwc2UgPSAiIE9SICIsIHNlcCA9ICIiKSkKCiMjIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyMjIC0tLSBTMi4gQmFubmVyIExhbmRpbmcgUGFnZSBEYXRhCiMjIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMgLSBsYW5kaW5nIHBhZ2UgbGluayBpbmNsdWRpbmcgdGhlIGFwcHJvcHJpYXRlIGNhbXBhaWduIHRhZwojIC0gTGluazpodHRwczovL2RlLndpa2lwZWRpYS5vcmcvd2lraS9XaWtpcGVkaWE6V2lraW1lZGlhX0RldXRzY2hsYW5kL0xlcm5lV2lraXBlZGlhP2NhbXBhaWduPXdtZGVfZXRjMjAxN19idDEKCiMgLSBzZXQgYmFubmVyQ2xpY2tzRGlyCnNldHdkKGJhbm5lckNsaWNrc0RpcikKCmZvciAoaSBpbiAxOmxlbmd0aCh1bmlxdWUoZFIkY2V0TmFtZSkpKSB7CiAgCiAgd0NldE5hbWUgPC0gd2hpY2goZFIkY2V0TmFtZSAlaW4lIHVuaXF1ZShkUiRjZXROYW1lKVtpXSkKICAKICBmb3IgKGogaW4gMTpsZW5ndGgod0NldE5hbWUpKSB7CiAgICAKICAgICMgLSBjb25zdHJ1Y3QgSGl2ZVFMIHF1ZXJ5OgogICAgeSA8LSBkUiR1dGNZZWFyW3dDZXROYW1lW2pdXQogICAgbSA8LSBkUiR1dGNNb250aFt3Q2V0TmFtZVtqXV0KICAgIGQgPC0gZFIkdXRjRGF5W3dDZXROYW1lW2pdXQogICAgaG91ciA8LSBkUiR1dGNIb3VyW3dDZXROYW1lW2pdXQogICAgcSA8LSBwYXN0ZSgKICAgICAgIlVTRSB3bWY7CiAgICAgIFNFTEVDVCB1cmlfcGF0aCwgdXJpX3F1ZXJ5LCByZWZlcmVyIEZST00gd2VicmVxdWVzdAogICAgICBXSEVSRSB1cmlfaG9zdCA9ICdkZS53aWtpcGVkaWEub3JnJwogICAgICBBTkQgdXJpX3BhdGggPSAnL3dpa2kvV2lraXBlZGlhOldpa2ltZWRpYV9EZXV0c2NobGFuZC9MZXJuZVdpa2lwZWRpYScgCiAgICAgIEFORCB5ZWFyID0gIiwgeSwKICAgICAgIiBBTkQgbW9udGggPSAiLCBtLAogICAgICAiIEFORCBkYXkgPSAiLCBkLAogICAgICAiIEFORCAoIiwgaG91ciwgIik7IiwKICAgICAgc2VwID0gIiIpCiAgICAjIC0gd3JpdGUgaHFsCiAgICB3cml0ZShxLCAndGhhbmt5b3UyMDE4X0Jhbm5lckNsaWNrcy5ocWwnKQogICAgIyAtIHByZXBhcmUgb3V0cHV0IGZpbGU6CiAgICBmaWxlTmFtZSA8LSAidGhhbmt5b3UyMDE4X0Jhbm5lckNsaWNrc18iCiAgICBmaWxlTmFtZSA8LSBwYXN0ZTAoZmlsZU5hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgYXMuY2hhcmFjdGVyKHVuaXF1ZShkUiRjZXROYW1lKVtpXSksCiAgICAgICAgICAgICAgICAgICAgICAgIl8iLCBqLAogICAgICAgICAgICAgICAgICAgICAgICIudHN2IikKICAgIGZpbGVOYW1lIDwtIHBhc3RlMChiYW5uZXJDbGlja3NEaXIsICIvIiwgZmlsZU5hbWUpCiAgICAjIC0gZXhlY3V0ZSBocWwgc2NyaXB0OgogICAgaGl2ZUFyZ3MgPC0KICAgICAgJ2JlZWxpbmUgLWYnCiAgICBoaXZlSW5wdXQgPC0gcGFzdGUwKCd0aGFua3lvdTIwMThfQmFubmVyQ2xpY2tzLmhxbCA+ICcsCiAgICAgICAgICAgICAgICAgICAgICAgIGZpbGVOYW1lKQogICAgIyAtIGNvbW1hbmQ6CiAgICBoaXZlQ29tbWFuZCA8LSBwYXN0ZShoaXZlQXJncywgaGl2ZUlucHV0KQogICAgc3lzdGVtKGNvbW1hbmQgPSBoaXZlQ29tbWFuZCwgd2FpdCA9IFRSVUUpCiAgICAKICB9CiAgCn0KCiMjIyAtLS0gV3JhbmdsZSB0aGlzIGRhdGFzZXQ6CgojIyMgLS0tIEJhbm5lciB0YWdzOgpjYW1wYWlnbkJhbm5lciA8LSAnd21kZV9ldGMyMDE3X2J0MScKCiMjIyAtLS0gRGF0YXNldDoKIyAtIGNvdW50IG5vbi1lbXB0eSBmaWxlczoKYyA8LSAwCmxGIDwtIGxpc3QuZmlsZXMoKQpsRiA8LSBsRltncmVwbCgnLnRzdicsIGxGLCBmaXhlZCA9IFQpXQpsRiA8LSBsRltncmVwbCgnQ2xpY2tzJywgbEYsIGZpeGVkID0gVCldCmRhdGFTZXQgPC0gbGlzdCgpCmZvciAoaSBpbiAxOmxlbmd0aChsRikpIHsKICBkUyA8LSByZWFkTGluZXMobEZbaV0sIG4gPSAtMSkKICB0aW1lU3RhbXAgPC0gc3Ryc3BsaXQobEZbaV0sIHNwbGl0ID0gIl8iKVtbMV1dWzNdCiAgYmFubmVyQ2xpY2tzIDwtIHN1bShncmVwbChjYW1wYWlnbkJhbm5lciwgZFMsIGZpeGVkID0gVCkpCiAgZGF0YVNldFtbaV1dIDwtIGRhdGEuZnJhbWUodGltZXN0YW1wID0gdGltZVN0YW1wLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhbm5lckNsaWNrcyA9IGJhbm5lckNsaWNrcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzID0gRikKfQpkYXRhU2V0IDwtIHJiaW5kbGlzdChkYXRhU2V0KQoKIyMjIC0tLSBzdG9yZSBCYW5uZXJDbGlja3NQYWdlVmlld3NfVXBkYXRlLmNzdgpzZXR3ZChkYWlseVVwZGF0ZURpcikKd3JpdGUuY3N2KGRhdGFTZXQsIGZpbGUgPSAidGhhbmt5b3UyMDE4X0Jhbm5lckNsaWNrc1BhZ2VWaWV3c19VcGRhdGUuY3N2IikKCiMjIyAtLS0gU1FMCnN0YXJ0RGF0ZSA8LSAnMjAxOC0wMS0wMScKCiMjIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyMjIC0tLSBTMy4gVXNlciBSZWdpc3RyYXRpb24gRGF0YQojIyMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIC0gTk9URTogVVRDIHRpbWVzdGFtcHMgLSBhZGp1c3RtZW50IGZvciBDRShTKVQgaW50cm9kdWNlZC4gCiMgLSBTZXJ2ZXJTaWRlQWNjb3VudENyZWF0aW9uXzU0ODczNDUKcUNvbW1hbmQgPC0gcGFzdGUoIm15c3FsIC0tZGVmYXVsdHMtZmlsZT0vZXRjL215c3FsL2NvbmYuZC9hbmFseXRpY3MtcmVzZWFyY2gtY2xpZW50LmNuZiAtaCBhbmFseXRpY3Mtc2xhdmUuZXFpYWQud21uZXQgLUEgLWUgXCJzZWxlY3QgKiBmcm9tIGxvZy5TZXJ2ZXJTaWRlQWNjb3VudENyZWF0aW9uXzU0ODczNDUgd2hlcmUgKCh3ZWJIb3N0ID0gJ2RlLndpa2lwZWRpYS5vcmcnKSBhbmQgKHRpbWVzdGFtcCA+PSAiLCBnc3ViKCItIiwgIiIsIHN0YXJ0RGF0ZSwgZml4ZWQgPSBUKSwgIjIyMDAwMCkpO1wiID4gIiwKICAgICAgICAgICAgZGFpbHlVcGRhdGVEaXIsICIvdGhhbmt5b3VfMjAxOF91c2VyUmVnaXN0cmF0aW9ucy50c3YiLCBzZXAgPSAiIikKc3lzdGVtKGNvbW1hbmQgPSBxQ29tbWFuZCwgd2FpdCA9IFRSVUUpCgoKIyMjIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIyMgLS0tIFM0LiBHdWlkZWQgVG91cnMgRGF0YQojIyMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIC0gTk9URTogVVRDIHRpbWVzdGFtcHMgLSBhZGp1c3RtZW50IGZvciBDRShTKVQgaW50cm9kdWNlZC4gCiMgLSBTZXJ2ZXJTaWRlQWNjb3VudENyZWF0aW9uXzU0ODczNDUKcUNvbW1hbmQgPC0gcGFzdGUoIm15c3FsIC0tZGVmYXVsdHMtZmlsZT0vZXRjL215c3FsL2NvbmYuZC9hbmFseXRpY3MtcmVzZWFyY2gtY2xpZW50LmNuZiAtaCBhbmFseXRpY3Mtc2xhdmUuZXFpYWQud21uZXQgLUEgLWUgXCJzZWxlY3QgKiBmcm9tIGxvZy5HdWlkZWRUb3VyRXhpdGVkXzg2OTA1NjYgd2hlcmUgKCh3ZWJIb3N0ID0gJ2RlLndpa2lwZWRpYS5vcmcnKSBhbmQgKHRpbWVzdGFtcCA+PSAiLCAKICAgICAgICAgICAgICAgICAgZ3N1YigiLSIsICIiLCBzdGFydERhdGUsIGZpeGVkID0gVCksICIyMjAwMDApKTtcIiA+ICIsIAogICAgICAgICAgICAgICAgICBkYWlseVVwZGF0ZURpciwgIi90aGFua3lvdV8yMDE4X2d1aWRlZFRvdXJzLnRzdiIsIHNlcCA9ICIiKQpzeXN0ZW0oY29tbWFuZCA9IHFDb21tYW5kLCB3YWl0ID0gVFJVRSkKCiMjIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyMjIC0tLSBTNS4gVXNlciBFZGl0IERhdGEKIyMjIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyAtIGdldCB1c2VyIElEcyBmcm9tIHJlZ2lzdGVyZWQ6CmxGIDwtIGxpc3QuZmlsZXMoKQpsRiA8LSBsRltncmVwbCgndXNlclJlZ2lzdHJhdGlvbnMnLCBsRiwgZml4ZWQgPSBUKV0KdXNlclJlZyA8LSByZWFkLnRhYmxlKGxGLCAKICAgICAgICAgICAgICAgICAgICAgIHF1b3RlID0gIiIsCiAgICAgICAgICAgICAgICAgICAgICBzZXAgPSAiXHQiLAogICAgICAgICAgICAgICAgICAgICAgaGVhZGVyID0gVCwKICAgICAgICAgICAgICAgICAgICAgIGNoZWNrLm5hbWVzID0gRiwKICAgICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQp1c2VyUmVnIDwtIHVzZXJSZWcgJT4lIAogIGRwbHlyOjpzZWxlY3QoZXZlbnRfdXNlcklkLCBldmVudF9pc1NlbGZNYWRlLCBldmVudF9jYW1wYWlnbikgJT4lIAogIGZpbHRlcihldmVudF9pc1NlbGZNYWRlID09IDEpICU+JSAKICBmaWx0ZXIoZXZlbnRfY2FtcGFpZ24gJWluJSAid21kZV9ldGMyMDE3X2J0MSIpCiMgLSB1aWRzOgp1aWQgPC0gdXNlclJlZyRldmVudF91c2VySWQKIyAtIHNxbCBxdWVyeQpzcWxRdWVyeSA8LSBwYXN0ZSgnU0VMRUNUIENPVU5UKCopIGFzIGVkaXRzLCByZXZfdXNlciBGUk9NIHJldmlzaW9uIFdIRVJFIHJldl91c2VyIElOICgnLAogICAgICAgICAgICAgICAgICBwYXN0ZSh1aWQsIGNvbGxhcHNlID0gIiwgIiksCiAgICAgICAgICAgICAgICAgICcpIEdST1VQIEJZIHJldl91c2VyOycsCiAgICAgICAgICAgICAgICAgIHNlcCA9ICIiKQpteVNxbENvbW1hbmQgPC0gcGFzdGUoJ215c3FsIC1oIGFuYWx5dGljcy1zdG9yZS5lcWlhZC53bW5ldCBkZXdpa2kgLWUgJywKICAgICAgICAgICAgICAgICAgICAgIHBhc3RlKCciJywgc3FsUXVlcnksICciID4gJywgc2VwID0gIiIpLCAKICAgICAgICAgICAgICAgICAgICAgIGRhaWx5VXBkYXRlRGlyLCAnL3RoYW5reW91XzIwMThfdXNlckVkaXRzLnRzdicsIHNlcCA9ICIiKQpzeXN0ZW0oY29tbWFuZCA9IG15U3FsQ29tbWFuZCwgCiAgICAgICB3YWl0ID0gVFJVRSkKCiMjIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyMjIC0tLSBTNi4gVHJhaW5pbmcgTW9kdWxlIERhdGEKIyMjIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKYGBgCgojIyAxQS4gQ2FtcGFpZ24gQmFubmVyIEltcHJlc3Npb25zCgojIyMgMUEuIDEgVGhlIGRhdGEgc2V0CmBgYHtyIGVjaG8gPSBULCB3YXJuaW5nID0gJ2hpZGUnLCBtZXNzYWdlID0gRn0KIyAtIHJlcG9ydDogY3VycmVudCB1cGRhdGUKcHJpbnQocGFzdGUwKCJDdXJyZW50IHVwZGF0ZTogIiwgYXMuY2hhcmFjdGVyKFN5cy50aW1lKCkpKSkKYmFubmVySW1wcmVzc2lvbnMgPC0gcmVhZC5jc3YoJ3RoYW5reW91QmFubmVySW1wcmVzc2lvbnMuY3N2JywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93Lm5hbWVzID0gMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGVhZGVyID0gVCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IEYpICU+JSAKICBnYXRoZXIoa2V5ID0gIEJhbm5lciwKICAgICAgICAgdmFsdWUgPSBWaWV3cywKICAgICAgICAgQjE3V01ERV90aGFua3lvdV9hdXRob3JzOkIxN1dNREVfdGhhbmt5b3VfYXV0aG9yc19tb2JfQikgJT4lIAogIGdyb3VwX2J5KHRpbWVTdGFtcCwgQmFubmVyKSAlPiUgCiAgc3VtbWFyaXNlKFZpZXdzID0gc3VtKFZpZXdzKSkKa25pdHI6OmthYmxlKGJhbm5lckltcHJlc3Npb25zLCBmb3JtYXQgPSAiaHRtbCIpICU+JSAKICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBGLCBwb3NpdGlvbiA9ICJsZWZ0IikKYGBgCiMjIyAxQS4gMiBDaGFydAoKYGBge3IgZWNobyA9IFQsIHdhcm5pbmcgPSAnaGlkZScsIG1lc3NhZ2UgPSBGfQpnZ3Bsb3QoYmFubmVySW1wcmVzc2lvbnMsIGFlcyh4ID0gdGltZVN0YW1wLAogICAgICAgICAgICAgICAgICAgIHkgPSBWaWV3cywKICAgICAgICAgICAgICAgICAgICBjb2xvciA9IEJhbm5lciwKICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IFZpZXdzKSkgKwogIGdlb21fbGluZShhZXMoZ3JvdXAgPSBCYW5uZXIpLCBzaXplID0gLjI1KSArCiAgZ2VvbV9wb2ludChzaXplID0gMS41KSArCiAgZ2VvbV9wb2ludChzaXplID0gMSwgY29sb3IgPSAid2hpdGUiKSArIAogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OmNvbW1hKSArCiAgZ2d0aXRsZSgnVGhhbmsgWW91IDIwMTg6XG5PdmVydmlldyBvZiBCYW5uZXJJbXByZXNzaW9ucycpICsKICB5bGFiKCJJbXByZXNzaW9ucyIpICsKICBnZW9tX3RleHRfcmVwZWwoc2l6ZSA9IDMpICsKICB0aGVtZV9taW5pbWFsKCkgKyAKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBzaXplID0gOCwgaGp1c3QgPSAxKSkgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSkgKwogIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfYmxhbmsoKSkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSkgKwogIHRoZW1lKHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCkpCmBgYAoKIyMgMUIuIENhbXBhaWduIFBhZ2V2aWV3cyAoQmFubmVyIENsaWNrcykKCiMjIyAxQi4gMSBUaGUgZGF0YSBzZXQKCmBgYHtyIGVjaG8gPSBULCB3YXJuaW5nID0gJ2hpZGUnLCBtZXNzYWdlID0gRn0KcGFnZXZpZXdzIDwtIHJlYWQuY3N2KCd0aGFua3lvdTIwMThfQmFubmVyQ2xpY2tzUGFnZVZpZXdzX1VwZGF0ZS5jc3YnLAogICAgICAgICAgICAgICAgICAgICAgcm93Lm5hbWVzID0gMSwKICAgICAgICAgICAgICAgICAgICAgIGhlYWRlciA9IFQsCiAgICAgICAgICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzID0gRikKcGFnZXZpZXdzIDwtIHBhZ2V2aWV3cyAlPiUgCiAgZ3JvdXBfYnkodGltZXN0YW1wKSAlPiUgCiAgc3VtbWFyaXNlKFBhZ2V2aWV3cyA9IHN1bShiYW5uZXJDbGlja3MpKQprbml0cjo6a2FibGUocGFnZXZpZXdzLCBmb3JtYXQgPSAiaHRtbCIpICU+JSAKICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBGLCBwb3NpdGlvbiA9ICJsZWZ0IikKYGBgCgojIyMgMUIuIDIgQ2hhcnQKCmBgYHtyIGVjaG8gPSBULCB3YXJuaW5nID0gJ2hpZGUnLCBtZXNzYWdlID0gRn0KZ2dwbG90KHBhZ2V2aWV3cywgYWVzKHggPSB0aW1lc3RhbXAsCiAgICAgICAgICAgICAgICAgICAgeSA9IFBhZ2V2aWV3cywKICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IFBhZ2V2aWV3cykpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgCiAgICAgICAgICAgcG9zaXRpb24gPSAiZG9kZ2UiLCAKICAgICAgICAgICB3aWR0aCA9IC4xNSwgCiAgICAgICAgICAgZmlsbCA9ICJ3aGl0ZSIsIAogICAgICAgICAgIGNvbG9yID0gImRhcmtibHVlIikgKwogIGdndGl0bGUoJ1RoYW5rIFlvdSAyMDE4OlxuT3ZlcnZpZXcgb2YgTGFuZGluZyBQYWdldmlld3MnKSArCiAgZ2VvbV9sYWJlbChzaXplID0gMykgKwogIHRoZW1lX21pbmltYWwoKSArIAogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHNpemUgPSA4LCBoanVzdCA9IDEpKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApKSArCiAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vci54ID0gZWxlbWVudF9ibGFuaygpKSArCiAgdGhlbWUocGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCgoKIyMgMi4gQ2FtcGFpZ24gVXNlciBSZWdpc3RyYXRpb25zCgojIyMgMi4gMSBUaGUgZGF0YSBzZXQKCmBgYHtyIGVjaG8gPSBULCB3YXJuaW5nID0gJ2hpZGUnLCBtZXNzYWdlID0gRn0KdXNlclJlZyA8LSByZWFkLmRlbGltKCd0aGFua3lvdV8yMDE4X3VzZXJSZWdpc3RyYXRpb25zLnRzdicsCiAgICAgICAgICAgICAgICAgICAgICBzZXAgPSAiXHQiLAogICAgICAgICAgICAgICAgICAgICAgcXVvdGUgPSAiIiwKICAgICAgICAgICAgICAgICAgICAgIGhlYWRlciA9IFQsCiAgICAgICAgICAgICAgICAgICAgICAjIHJvdy5uYW1lcyA9IDEsCiAgICAgICAgICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzID0gRikKdXNlclJlZyR0aW1lc3RhbXAgPC0gYXMuY2hhcmFjdGVyKHVzZXJSZWckdGltZXN0YW1wKQp1c2VyUmVnJHRpbWVzdGFtcCA8LSBzYXBwbHkodXNlclJlZyR0aW1lc3RhbXAsIGZ1bmN0aW9uKHgpIHsKICB5IDwtIHN1YnN0cih4LCAxLCA0KQogIG0gPC0gc3Vic3RyKHgsIDUsIDYpCiAgZCA8LSBzdWJzdHIoeCwgNywgOCkKICBwYXJ0MURhdGUgPC0gcGFzdGUoeSwgbSwgZCwgc2VwID0gIi0iKQogIGhyIDwtIHN1YnN0cih4LCA5LCAxMCkKICBtaSA8LSBzdWJzdHIoeCwgMTEsIDEyKQogIHNlIDwtIHN1YnN0cih4LCAxMywgMTQpCiAgcGFydDJEYXRlIDwtIHBhc3RlKGhyLCBtaSwgc2UsIHNlcCA9ICI6IikKICBwYXN0ZShwYXJ0MURhdGUsIHBhcnQyRGF0ZSwgc2VwID0gIiAiKQp9KQp1c2VyUmVnJHRpbWVzdGFtcCA8LSBhcy5QT1NJWGN0KHVzZXJSZWckdGltZXN0YW1wLCB0eiA9ICJVVEMiKQp0aW1lRGlmZiA8LSAKICBhcy5QT1NJWGN0KGFzLmNoYXJhY3RlcihTeXMudGltZSgpKSwgdHogPSAiVVRDIikgLSBhcy5QT1NJWGN0KGFzLmNoYXJhY3RlcihTeXMudGltZSgpKSwgdHogPSAiRXVyb3BlL0JlcmxpbiIpCnVzZXJSZWckdGltZXN0YW1wIDwtIGFzLmNoYXJhY3Rlcih1c2VyUmVnJHRpbWVzdGFtcCArIHRpbWVEaWZmKQp1c2VyUmVnJHRpbWVzdGFtcCA8LSBzYXBwbHkodXNlclJlZyR0aW1lc3RhbXAsIGZ1bmN0aW9uKHgpIHsKICB5IDwtIHN1YnN0cih4LCAxLCA0KQogIG0gPC0gc3Vic3RyKHgsIDYsIDcpCiAgZCA8LSBzdWJzdHIoeCwgOSwgMTApIAogIHBhc3RlKHksIG0sIGQsIHNlcCA9ICItIikKfSkKdXNlclJlZyA8LSB1c2VyUmVnICU+JQogIGZpbHRlcihldmVudF9jYW1wYWlnbiAlaW4lICd3bWRlX2V0YzIwMTdfYnQxJykgJT4lIAogIGdyb3VwX2J5KHRpbWVzdGFtcCkgJT4lIAogIHN1bW1hcmlzZShSZWdpc3RyYXRpb25zID0gbigpKQprbml0cjo6a2FibGUodXNlclJlZywgZm9ybWF0ID0gImh0bWwiKSAlPiUgCiAga2FibGVfc3R5bGluZyhmdWxsX3dpZHRoID0gRiwgcG9zaXRpb24gPSAibGVmdCIpCmBgYAoKIyMjIDIuIDIgQ2hhcnQKCmBgYHtyIGVjaG8gPSBULCB3YXJuaW5nID0gJ2hpZGUnLCBtZXNzYWdlID0gRn0KZ2dwbG90KHVzZXJSZWcsIGFlcyh4ID0gdGltZXN0YW1wLAogICAgICAgICAgICAgICAgICAgIHkgPSBSZWdpc3RyYXRpb25zLAogICAgICAgICAgICAgICAgICAgIGxhYmVsID0gUmVnaXN0cmF0aW9ucykpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgCiAgICAgICAgICAgcG9zaXRpb24gPSAiZG9kZ2UiLCAKICAgICAgICAgICB3aWR0aCA9IC4xNSwgCiAgICAgICAgICAgZmlsbCA9ICJ3aGl0ZSIsIAogICAgICAgICAgIGNvbG9yID0gImRhcmtibHVlIikgKwogIGdndGl0bGUoJ1RoYW5rIFlvdSAyMDE4OlxuT3ZlcnZpZXcgb2YgVXNlciBSZWdpc3RyYXRpb25zJykgKwogIGdlb21fbGFiZWwoc2l6ZSA9IDMpICsKICB0aGVtZV9taW5pbWFsKCkgKyAKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBzaXplID0gOCwgaGp1c3QgPSAxKSkgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSkgKwogIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfYmxhbmsoKSkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSkgKwogIHRoZW1lKHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCkpCmBgYAoKIyMgMy4gQ2FtcGFpZ24gVXNlciBFZGl0cwoKIyMjIDMuIDEgVGhlIGRhdGEgc2V0CgpgYGB7ciBlY2hvID0gVCwgd2FybmluZyA9ICdoaWRlJywgbWVzc2FnZSA9IEZ9CnVzZXJFZGl0cyA8LSByZWFkTGluZXMoJ3RoYW5reW91XzIwMThfdXNlckVkaXRzLnRzdicsIG4gPSAtMSkKaWYgKGxlbmd0aCh1c2VyRWRpdHMpID49IDEpIHsKICB1c2VyRWRpdHMgPC0gcmVhZC5kZWxpbSgndGhhbmt5b3VfMjAxOF91c2VyRWRpdHMudHN2JywKICAgICAgICAgICAgICAgICAgICAgICAgICBzZXAgPSAiXHQiLAogICAgICAgICAgICAgICAgICAgICAgICAgIGhlYWRlciA9IFQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IEYpCiAgIyAtIHJlcG9ydAogIHByaW50KHBhc3RlMChzdW0odXNlckVkaXRzJGVkaXRzKSwgIiBlZGl0cyB3ZXJlIG1hZGUgYnkgdGhlIGNhbXBhaWduIHJlZ2lzdGVyZWQgdXNlcnMgdGh1cyBmYXIuIikpCn0gZWxzZSB7CiAgcHJpbnQoIlRoZXJlIGFyZSBjdXJyZW50bHkgbm8gdXNlciBlZGl0cyBmcm9tIHRoaXMgY2FtcGFpZ24uIikKfQpgYGAKCiMjIyAzLiAyIENoYXJ0CgpgYGB7ciBlY2hvID0gVCwgd2FybmluZyA9ICdoaWRlJywgbWVzc2FnZSA9IEZ9CmBgYAoKIyMgNC4gQ2FtcGFpZ24gR3VpZGVkIFRvdXJzCgojIyMgNC4gMSBUaGUgZGF0YSBzZXQ6IEd1aWRlZCBUb3VyIEV4aXQgU3RlcHMKCkNhbXBhaWduIGd1aWRlZCB0b3VyczogYGRpc2t1dGllcmVuYCBhbmQgYHNlaW11dGlnYC4KCmBgYHtyIGVjaG8gPSBULCB3YXJuaW5nID0gJ2hpZGUnLCBtZXNzYWdlID0gRn0KdG91cnMgPC0gYygnZGlza3V0aWVyZW4nLCAnc2VpbXV0aWcnKQojIHNldHdkKCcvaG9tZS9nb3JhbnNtL1dvcmsvX19fRGF0YUtvbGVrdGl2L1Byb2plY3RzL1dpa2ltZWRpYURFVS9fV01ERV9Qcm9qZWN0cy9fbWlzYy9OZXdFZGl0b3JzX1RlYW0vVGhhbmtfWW91X0NhbXBhaWduXzIwMTgvX2RhaWx5VXBkYXRlLycpCmdUb3VycyA8LSByZWFkLmRlbGltKCd0aGFua3lvdV8yMDE4X2d1aWRlZFRvdXJzLnRzdicsCiAgICAgICAgICAgICAgICAgICAgIHNlcCA9ICJcdCIsCiAgICAgICAgICAgICAgICAgICAgIGhlYWRlciA9IFQsCiAgICAgICAgICAgICAgICAgICAgIHJvdy5uYW1lcyA9IDEsCiAgICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQpnVG91cnMkdGltZXN0YW1wIDwtIGFzLmNoYXJhY3RlcihnVG91cnMkdGltZXN0YW1wKQpnVG91cnMkdGltZXN0YW1wIDwtIHNhcHBseShnVG91cnMkdGltZXN0YW1wLCBmdW5jdGlvbih4KSB7CiAgeSA8LSBzdWJzdHIoeCwgMSwgNCkKICBtIDwtIHN1YnN0cih4LCA1LCA2KQogIGQgPC0gc3Vic3RyKHgsIDcsIDgpCiAgcGFydDFEYXRlIDwtIHBhc3RlKHksIG0sIGQsIHNlcCA9ICItIikKICBociA8LSBzdWJzdHIoeCwgOSwgMTApCiAgbWkgPC0gc3Vic3RyKHgsIDExLCAxMikKICBzZSA8LSBzdWJzdHIoeCwgMTMsIDE0KQogIHBhcnQyRGF0ZSA8LSBwYXN0ZShociwgbWksIHNlLCBzZXAgPSAiOiIpCiAgcGFzdGUocGFydDFEYXRlLCBwYXJ0MkRhdGUsIHNlcCA9ICIgIikKfSkKZ1RvdXJzJHRpbWVzdGFtcCA8LSBhcy5QT1NJWGN0KGdUb3VycyR0aW1lc3RhbXAsIHR6ID0gIlVUQyIpCnRpbWVEaWZmIDwtIAogIGFzLlBPU0lYY3QoYXMuY2hhcmFjdGVyKFN5cy50aW1lKCkpLCB0eiA9ICJVVEMiKSAtIGFzLlBPU0lYY3QoYXMuY2hhcmFjdGVyKFN5cy50aW1lKCkpLCB0eiA9ICJFdXJvcGUvQmVybGluIikKZ1RvdXJzJHRpbWVzdGFtcCA8LSBhcy5jaGFyYWN0ZXIoZ1RvdXJzJHRpbWVzdGFtcCArIHRpbWVEaWZmKQpnVG91cnMkdGltZXN0YW1wIDwtIHNhcHBseShnVG91cnMkdGltZXN0YW1wLCBmdW5jdGlvbih4KSB7CiAgeSA8LSBzdWJzdHIoeCwgMSwgNCkKICBtIDwtIHN1YnN0cih4LCA2LCA3KQogIGQgPC0gc3Vic3RyKHgsIDksIDEwKSAKICBwYXN0ZSh5LCBtLCBkLCBzZXAgPSAiLSIpCn0pCiMgLSBhbm9ueW1pemUgZXZlbnRfdXNlcklkCmV2ZW50VXNlcklkIDwtIHNldGRpZmYodW5pcXVlKGdUb3VycyRldmVudF91c2VySWQpLCAwKQphbl91c2VySWQgPC0gY2hhcmFjdGVyKGxlbmd0aChldmVudFVzZXJJZCkpCmZvciAoaSBpbiAxOmxlbmd0aChhbl91c2VySWQpKSB7CiAgaWQgPC0gcm91bmQocnVuaWYoMSwgMSwgMTBlNikpCiAgd2hpbGUgKGlkICVpbiUgYW5fdXNlcklkKSB7CiAgICBpZCA8LSByb3VuZChydW5pZigxLCAxLCAxMGU2KSkKICB9CiAgYW5fdXNlcklkW2ldIDwtIGlkCn0KYW5fdXNlcklkIDwtIHBhc3RlMCgidV8iLCBhbl91c2VySWQpCmdUb3VycyRhbl91c2VySWQgPC0gc2FwcGx5KGdUb3VycyRldmVudF91c2VySWQsIGZ1bmN0aW9uKHgpIHsKICB3IDwtIHdoaWNoKGV2ZW50VXNlcklkICVpbiUgeCkKICBpZiAobGVuZ3RoKHcpID4gMCkgewogICAgYW5fdXNlcklkW3ddCiAgfSBlbHNlIHsKICAgIHgKICB9Cn0pCiMgLSBsb29rIHVwIGZvciB0aGUgY2FtcGFpZ24gZ3VpZGVkIHRvdXJzCncgPC0gd2hpY2goZ1RvdXJzJGV2ZW50X3RvdXIgJWluJSB0b3VycykKaWYgKGxlbmd0aCh3KSA+IDApIHsKICBnVG91cnMgPC0gZ1RvdXJzW3csIF0KICBnVG91cnMgPC0gZ1RvdXJzICU+JSAKICAgIGZpbHRlcihldmVudF91c2VySWQgIT0gMCkgJT4lIAogICAgc2VsZWN0KHRpbWVzdGFtcCwgZXZlbnRfdG91ciwgZXZlbnRfc3RlcCwgYW5fdXNlcklkKQogIGtuaXRyOjprYWJsZShnVG91cnMsIGZvcm1hdCA9ICJodG1sIikgJT4lIAogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEYsIHBvc2l0aW9uID0gImxlZnQiKQp9IGVsc2UgewogIHByaW50KCJUaGVyZSBhcmUgY3VycmVudGx5IG5vIGRhdGEgb24gZ3VpZGVkIHRvdXJzIGZyb20gdGhpcyBjYW1wYWlnbi4iKQp9CmBgYAojIyMgNC4gMiBVbmlxdWUgdXNlcnMgaW4gR3VpZGVkIFRvdXJzCgpDYW1wYWlnbiBndWlkZWQgdG91cnM6IGBkaXNrdXRpZXJlbmAgYW5kIGBzZWltdXRpZ2AuCgpgYGB7ciBlY2hvID0gVCwgd2FybmluZyA9ICdoaWRlJywgbWVzc2FnZSA9IEZ9CmdUb3VycyAlPiUgCiAgc2VsZWN0KGV2ZW50X3RvdXIpICU+JSAKICBncm91cF9ieShldmVudF90b3VyKSAlPiUgCiAgc3VtbWFyaXNlKGBVbmlxdWUgdXNlcnNgID0gbigpKSAlPiUgCiAga25pdHI6OmthYmxlKGZvcm1hdCA9ICJodG1sIikgJT4lIAogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEYsIHBvc2l0aW9uID0gImxlZnQiKQpgYGAKCiMjIDUgVHJhaW5pbmcgTW9kdWxlCgpgYGB7ciBlY2hvID0gVCwgd2FybmluZyA9ICdoaWRlJywgbWVzc2FnZSA9IEZ9CnRyYWluRGF0YSA8LSByZWFkLmNzdignd21kZV90cmFpbmluZ19kYXRhLmNzdicpCiMgLSByZW1vdmUgZmlyc3QgdHdvIHJvd3MgKHRlc3QgZGF0YSkKdHJhaW5EYXRhIDwtIHRyYWluRGF0YVstYygxLDIpLCBdCiMgLSBnZXQgdXNlciBJRHMgZnJvbSByZWdpc3RlcmVkOgpsRiA8LSBsaXN0LmZpbGVzKCkKbEYgPC0gbEZbZ3JlcGwoJ3VzZXJSZWdpc3RyYXRpb25zJywgbEYsIGZpeGVkID0gVCldCnVzZXJEYXRhIDwtIHJlYWQudGFibGUobEYsIAogICAgICAgICAgICAgICAgICAgICAgcXVvdGUgPSAiIiwKICAgICAgICAgICAgICAgICAgICAgIHNlcCA9ICJcdCIsCiAgICAgICAgICAgICAgICAgICAgICBoZWFkZXIgPSBULAogICAgICAgICAgICAgICAgICAgICAgY2hlY2submFtZXMgPSBGLAogICAgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IEYpCmd0RGF0YSA8LSByZWFkLmRlbGltKCd0aGFua3lvdV8yMDE4X2d1aWRlZFRvdXJzLnRzdicsCiAgICAgICAgICAgICAgICAgICAgIHNlcCA9ICJcdCIsCiAgICAgICAgICAgICAgICAgICAgIGhlYWRlciA9IFQsCiAgICAgICAgICAgICAgICAgICAgIHJvdy5uYW1lcyA9IDEsCiAgICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQplZERhdGEgPC0gcmVhZC5kZWxpbSgndGhhbmt5b3VfMjAxOF91c2VyRWRpdHMudHN2JywKICAgICAgICAgICAgICAgICAgICAgc2VwID0gIlx0IiwKICAgICAgICAgICAgICAgICAgICAgaGVhZGVyID0gVCwKICAgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IEYpCmBgYAoKCiMjIyA1LjEgVHJhaW5pbmcgTW9kdWxlIE92ZXJ2aWV3CgpIb3cgbWFueSByZWdpc3RlcmVkIHVzZXJzIHRha2UgdGhlIFRyYWluaW5nIE1vZHVsZT8KCmBgYHtyIGVjaG8gPSBULCB3YXJuaW5nID0gJ2hpZGUnLCBtZXNzYWdlID0gRn0KcHJpbnQocGFzdGUwKCJOdW1iZXIgb2YgdXNlcyB3aG8gdG9vayB0aGUgVHJhaW5pbmcgTW9kdWxlIGlzICIsIAogICAgICAgICAgICAgbGVuZ3RoKHRyYWluRGF0YSR1c2VybmFtZSksCiAgICAgICAgICAgICAiICwgd2hpY2ggaXMgIiwKICAgICAgICAgICAgIHJvdW5kKGxlbmd0aCh0cmFpbkRhdGEkdXNlcm5hbWUpL3N1bSh1c2VyUmVnJFJlZ2lzdHJhdGlvbnMpKjEwMCwgMiksCiAgICAgICAgICAgICAiJSBvZiByZWdpc3RlcmVkIHVzZXJzLiIKICAgICAgICAgICAgICAgKSkKYGBgCgpXaGF0IGFyZSB0aGUgbGFzdCBjb21wbGV0ZWQgc2xpZGVzIHBlciB1c2VyIFRyYWluaW5nIE1vZHVsZT8KCmBgYHtyIGVjaG8gPSBULCB3YXJuaW5nID0gJ2hpZGUnLCBtZXNzYWdlID0gRn0Kc2xpZGVzRGF0YSA8LSB0cmFpbkRhdGEgJT4lIAogIHNlbGVjdCh0cmFpbmluZ19tb2R1bGUsIGxhc3Rfc2xpZGVfY29tcGxldGVkKSAlPiUgCiAgZ3JvdXBfYnkodHJhaW5pbmdfbW9kdWxlLCBsYXN0X3NsaWRlX2NvbXBsZXRlZCkgJT4lIAogIHN1bW1hcmlzZShDb3VudCA9IG4oKSkgJT4lIAogIGFycmFuZ2UodHJhaW5pbmdfbW9kdWxlLCBkZXNjKENvdW50KSkKa25pdHI6OmthYmxlKHNsaWRlc0RhdGEsIGZvcm1hdCA9ICJodG1sIikgJT4lCiAga2FibGVfc3R5bGluZyhmdWxsX3dpZHRoID0gRiwgcG9zaXRpb24gPSAibGVmdCIpCmBgYAoKYGBge3IgZWNobyA9IFQsIHdhcm5pbmcgPSAnaGlkZScsIG1lc3NhZ2UgPSBGfQpnZ3Bsb3Qoc2xpZGVzRGF0YSwgYWVzKHggPSBsYXN0X3NsaWRlX2NvbXBsZXRlZCwKICAgICAgICAgICAgICAgICAgICAgICB5ID0gQ291bnQsCiAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSB0cmFpbmluZ19tb2R1bGUsCiAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSBDb3VudCkpICsKICBnZW9tX2xpbmUoYWVzKGdyb3VwID0gMSksIHNpemUgPSAuMjUpICsKICBnZW9tX3BvaW50KHNpemUgPSAxLjUpICsKICBnZW9tX3BvaW50KHNpemUgPSAxLCBjb2xvciA9ICJ3aGl0ZSIpICsgCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6Y29tbWEpICsKICBnZ3RpdGxlKCdUaGFuayBZb3UgMjAxODpcbk92ZXJ2aWV3IG9mIFRyYWluaW5nIE1vZHVsZXMnKSArCiAgeWxhYigiTm8uIFVzZXJzIikgKwogIGdlb21fdGV4dF9yZXBlbChzaXplID0gMykgKwogIGZhY2V0X3dyYXAofnRyYWluaW5nX21vZHVsZSkgKwogIHRoZW1lX21pbmltYWwoKSArIAogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHNpemUgPSA2LjUsIGhqdXN0ID0gMSkpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCkpICsKICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsKICB0aGVtZShwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCkpICsKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yLnggPSBlbGVtZW50X2JsYW5rKCkpICsKICB0aGVtZShwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpKQpgYGAKCkRvIHVzZXJzIHN0YXJ0IGVkaXRpbmcgYWZ0ZXIgdHJhaW5pbmcgbW9kdWxlcz8gSXMgdGhlcmUgYSBkaWZmZXJlbmNlIGluIHVzZXJzIHdpdGggY29tcGxldGVkIGFuZCBub3QtY29tcGxldGVkIG9yIG5vdCBhdCBhbGwgaGF2aW5nIHRha2VuIHRoZSBtb2R1bGVzPwoKYGBge3IgZWNobyA9IFQsIHdhcm5pbmcgPSAnaGlkZScsIG1lc3NhZ2UgPSBGfQp1c2VyRGF0YSA8LSB1c2VyRGF0YSAlPiUgCiAgZmlsdGVyKGV2ZW50X2NhbXBhaWduICVpbiUgJ3dtZGVfZXRjMjAxN19idDEnICYgZXZlbnRfaXNTZWxmTWFkZSkgJT4lIAogIHNlbGVjdChldmVudF91c2VySWQsIGV2ZW50X3VzZXJOYW1lKQp1c2VyRGF0YSA8LSBsZWZ0X2pvaW4odXNlckRhdGEsIHRyYWluRGF0YSwgYnkgPSBjKCJldmVudF91c2VyTmFtZSIgPSAidXNlcm5hbWUiKSkKdXNlckRhdGEkbW9kdWxlX2NvbXBsZXRpb25fZGF0ZSA8LSBOQQp1c2VyRGF0YSA8LSBsZWZ0X2pvaW4odXNlckRhdGEsIAogICAgICAgICAgICAgICAgICAgICAgZ3REYXRhWywgYygnZXZlbnRfdXNlcklkJywgJ2V2ZW50X3RvdXInLCAnZXZlbnRfc3RlcCcpXSwKICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gYygnZXZlbnRfdXNlcklkJykpCnVzZXJEYXRhIDwtIGxlZnRfam9pbih1c2VyRGF0YSwgZWREYXRhLAogICAgICAgICAgICAgICAgICAgICAgYnkgPSBjKCdldmVudF91c2VySWQnID0gJ3Jldl91c2VyJykpCmBgYAoKSG93IG1hbnkgZWRpdHMgd2VyZSBtYWRlIG9uIGJlaGFsZiBvZiB0aG9zZSB1c2VycyB3aG8gaGF2ZSBzdGFydGVkIHRoZSBUcmFpbmluZyBNb2R1bGUgdnMuIHRob3NlIHdobyBkaWQgbm90PwoKYGBge3IgZWNobyA9IFQsIHdhcm5pbmcgPSAnaGlkZScsIG1lc3NhZ2UgPSBGfQp0QW4gPC0gdXNlckRhdGEgJT4lIAogIHNlbGVjdCh0cmFpbmluZ19tb2R1bGUsIGVkaXRzKSAlPiUgCiAgZ3JvdXBfYnkodHJhaW5pbmdfbW9kdWxlKSAlPiUgCiAgc3VtbWFyaXNlKFVzZXJzID0gbigpLCBFZGl0cyA9IHN1bShlZGl0cywgbmEucm0gPSBUKSkgJT4lIAogIGFycmFuZ2UodHJhaW5pbmdfbW9kdWxlLCBkZXNjKEVkaXRzKSkKa25pdHI6OmthYmxlKHRBbiwgZm9ybWF0ID0gImh0bWwiKSAlPiUKICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBGLCBwb3NpdGlvbiA9ICJsZWZ0IikKYGBgCgpgYGB7ciBlY2hvID0gVCwgd2FybmluZyA9ICdoaWRlJywgbWVzc2FnZSA9IEZ9CnByaW50KHBhc3RlMCgiSW4gdG90YWwsIHRoZSB1c2VycyB3aG8gdG9vayB0aGUgVHJhaW5pbmcgTW9kdWxlIG1hZGUgIiwgCiAgICAgICAgICAgICBzdW0odEFuJEVkaXRzWzE6M10pLAogICAgICAgICAgICAgIiBlZGl0cywgd2hpY2ggaXMgIiwKICAgICAgICAgICAgIHJvdW5kKHN1bSh0QW4kRWRpdHNbMTozXSkvc3VtKHRBbiRFZGl0cykqMTAwLCAyKSwKICAgICAgICAgICAgICIlIG9mIGFsbCBlZGl0cy4iCiAgICAgICAgICAgICAgICkpCnByaW50KHBhc3RlMCgiT24gdGhlIG90aGVyIGhhbmQsIHRoZSB1c2VycyB3aG8gZGlkIG5vdCB0YWtlIHRoZSBUcmFpbmluZyBNb2R1bGUgbWFkZSAiLCAKICAgICAgICAgICAgIHRBbiRFZGl0c1s0XSwKICAgICAgICAgICAgICIgZWRpdHMsIHdoaWNoIGlzICIsCiAgICAgICAgICAgICByb3VuZCh0QW4kRWRpdHNbNF0vc3VtKHRBbiRFZGl0cykqMTAwLCAyKSwKICAgICAgICAgICAgICIlIG9mIGFsbCBlZGl0cy4iCiAgICAgICAgICAgICAgICkpCmBgYAoKCgo=