#=========================================================
# PREAMBLE
#=========================================================
# load the plotting library
suppressMessages(library(ggplot2))
library(gridExtra)
library(ggExtra)
library(tikzDevice)
library(Hmisc)
library(pastecs)
theme_set(theme_bw())
options(scipen=999) # turn-off scientific notation like 1e+48
# size of point for scatterplots
POINT_SIZE = 0.1
#POINT_SIZE = 1
# timeout
TIMEOUT = params$timeout
TIMEOUT_VAL = 1.05 * TIMEOUT
ERR_VAL = 1.3 * TIMEOUT
# saturate
#TIME_MIN = 0.01 # seconds
TIME_MIN = 0.1 # seconds
BIG_SIZE=3
SMALL_SIZE=2
# FUNCTIONS
read_file <- function(file) {
filename = paste0(file)
df <- read.csv2(filename,
header=TRUE,
sep=";",
dec=",",
comment.char="",
quote="\"",
strip.white=TRUE,
allowEscapes=FALSE,
stringsAsFactors=FALSE)
return(df)
}
plot_scatter_log <- function(df, xlab, ylab, xstring=xlab, ystring=ylab) {
pscat <- ggplot(df, aes_string(x=xlab, y=ylab)) +
geom_point(size=POINT_SIZE) +
geom_abline(size=0.1) +
geom_vline(size=0.1, xintercept=TIMEOUT_VAL, linetype="dashed") +
geom_hline(size=0.1, yintercept=TIMEOUT_VAL, linetype="dashed") +
geom_rug(alpha = 0.2) +
scale_x_log10() +
scale_y_log10() +
theme(axis.text.y = element_text(angle = 90, hjust = 0.5)) +
#coord_fixed(xlim = c(TIME_MIN, TIMEOUT_VAL), ylim = c(0.1, TIMEOUT_VAL)) +
#coord_fixed(xlim = c(TIME_MIN, TIMEOUT_VAL), ylim = c(TIME_MIN, TIMEOUT_VAL)) +
coord_fixed(xlim = c(TIME_MIN, TIMEOUT_VAL), ylim = c(TIME_MIN, TIMEOUT_VAL)) +
labs(
#title="Title",
#subtitle="Subtitle",
x=xstring,
y=ystring)
# theme(
# panel.grid.major = element_blank(),
# panel.grid.minor = element_blank(),
# panel.background = element_rect(fill = "transparent",colour = NA),
# plot.background = element_rect(fill = "transparent",colour = NA)
# )
# theme_minimal()
# theme_bw()
# theme(plot.background = element_rect(fill = NA))
# pscat <- ggMarginal(pscat, type = "density", size=10)
# pscat <- pscat + theme_bw()
return(pscat)
}
make_tikz <- function(file, picture, width=2.5, height=2.5) {
font_size <- 1
tikz(file=file, onefile=T, width=width, height=height)
plot(picture)
garbage <- dev.off()
}
make_pdf <- function(file, picture, width=5, height=5) {
pdf(file=file, onefile=T, width, height)
plot(picture)
garbage <- dev.off()
}
df <- read_file(params$file_cmp)
orig_size <- nrow(df)
colnames(df)[colnames(df) == "dot.net"] <- "dotnet"
colnames(df)[names(df) == "dot.net.matches"] <- "dotnet.matches"
######################### SANITIZE ###############################
# clean the data
df_new <- df[!grepl("File not found", df$srm.matches),]
print(paste0("Removing ", nrow(df) - nrow(df_new), " lines due to generation of input text"))
[1] "Removing 2682 lines due to generation of input text"
df <- df_new
tools.times <- c("re2g", "cad", "grep", "srm", "dotnet")
#tools.times <- c("re2g", "cad", "srm", "dotnet")
tools.matches <- c("re2g.matches", "cad.matches", "grep.matches", "srm.matches", "dotnet.matches")
#tools.matches <- c("re2g.matches", "cad.matches", "srm.matches", "dotnet.matches")
# checking errors
errors.re2g <- nrow(df[grepl('ERR', df$re2g),])
errors.grep <- nrow(df[grepl('ERR', df$grep),])
errors.srm <- nrow(df[grepl('ERR', df$srm),])
errors.cad <- nrow(df[grepl('ERR', df$cad),])
errors.dotnet <- nrow(df[grepl('ERR', df$dotnet),])
#df <- df[!grepl('ERR', df$re2g),]
#df$re2g[df$re2g == 'ERR'] <- ERR_VAL
df[,tools.times][df[,tools.times] == 'ERR'] <- ERR_VAL
# change the type of columns other than the name
for (i in tools.times) {
df[,i] <- sub(",", ".", df[,i])
suppressWarnings(df[,i] <- as.numeric(df[,i]))
}
for (i in tools.matches) {
suppressWarnings(df[,i] <- as.integer(df[,i]))
}
df$src <- as.factor(df$src)
# get rid of extremal values
#df[,tools.times][df[,tools.times] > TIMEOUT] <- TIMEOUT_VAL
df[tools.times][is.na(df[tools.times])] <- TIMEOUT_VAL
#df[is.na(df)] <- TIMEOUT_VAL
#df[df == 0.00] <- TIME_MIN
df[,tools.times][df[,tools.times] < TIME_MIN] <- TIME_MIN
df <- df[!is.na(df$pattern),]
# clean the data
#df_new <- df[df$Lines != "ERROR WHILE CONVERTING TO DCA.",]
#print(paste0("Removing ", nrow(df) - nrow(df_new), " lines due to converting to DCA error"))
#df <- df_new
############################## COUNTING TIMEOUTS #######################
timeouts.re2g <- nrow(df[df$re2g == TIMEOUT_VAL,])
timeouts.cad <- nrow(df[df$cad == TIMEOUT_VAL,])
timeouts.grep <- nrow(df[df$grep == TIMEOUT_VAL,])
timeouts.srm <- nrow(df[df$srm == TIMEOUT_VAL,])
timeouts.dotnet <- nrow(df[df$dotnet == TIMEOUT_VAL,])
timeouts.re2.and.ca <- nrow(df[df$cad == TIMEOUT_VAL & df$re2g == TIMEOUT_VAL,])
# | **Timeouts grep** | `r timeouts.grep` |
These are results of the experiments for Counting Set Automata:
| File |
results-15-05-2020/nogrep/mergedResults/table-ALL-processed.csv |
|
| Timeout |
600 s |
|
| TIMEOUT_VAL |
630 s |
|
| TIME_MIN |
0.1 |
|
| original size |
4429 |
|
| Benchmarks |
1727 |
|
| Timeouts CA |
0 |
|
| Timeouts RE2 |
2 |
|
| Timeouts SRM |
15 |
|
| Timeouts grep |
12 |
|
| Timeouts .NET |
7 |
|
| Errors CA |
0 |
|
| Errors RE2 |
82 |
(removed) |
| Errors SRM |
0 |
|
| Errors grep |
52 |
|
| Errors .NET |
0 |
|
df
Summary of benchmarks
df_benches <- data.frame(summary(df$src))
df_benches
Sanity checks
df$inconsistent <- df$re2g.matches != df$grep.matches | df$re2g.matches != df$srm.matches | df$re2g.matches != df$dotnet.matches | df$re2g.matches != df$cad.matches
#df$inconsistent <- df$re2g.matches != df$srm.matches | df$re2g.matches != df$dotnet.matches | df$re2g.matches != df$cad.matches
df$grep.re2.mismatch <- !is.na(df$re2g.matches) & !is.na(df$grep.matches) & df$re2g.matches != df$grep.matches
df_grep_re2_mismatch <- df[df$grep.re2.mismatch,]
df$re2.ca.mismatch <- !is.na(df$re2g.matches) & !is.na(df$cad.matches) & df$re2g.matches != df$cad.matches
df_re2_ca_mismatch <- df[df$re2.ca.mismatch,]
df <- df[is.na(df$re2g.matches) | is.na(df$grep.matches) | df$re2g.matches == df$cad.matches,]
| CA and RE2 mismatched |
19 |
(removed) |
| grep and RE2 mismatched |
338 |
|
RE2 and CA mismatches
df_re2_ca_mismatch
Scatter Plots
plot.and.tikz <- function(df, xlab, ylab, xstring=xlab, ystring=ylab, width=4, height=width) {
pic <- plot_scatter_log(df, xlab, ylab, xstring, ystring)
#make_tikz(paste0("figs/", xlab, "-vs-", ylab, ".tikz"), pic, width, height)
make_pdf(paste0("figs/", xlab, "-vs-", ylab, ".pdf"), pic, width, height)
pic
}
df_grep <- df[is.na(df$grep.matches) | is.na(df$cad.matches) | df$grep.matches == df$cad.matches,]
plot1 <- plot.and.tikz(df, "re2g", "cad", xstring="RE2 [s]", ystring="CA [s]", width=BIG_SIZE)
plot2 <- plot.and.tikz(df_grep, "grep", "cad", xstring="grep [s]", ystring="CA [s]", width=SMALL_SIZE)
plot3 <- plot.and.tikz(df, "srm", "cad", xstring="SRM [s]", ystring="CA [s]", width=SMALL_SIZE)
plot4 <- plot.and.tikz(df, "dotnet", "cad", xstring=".NET [s]", ystring="CA [s]", width=SMALL_SIZE)
plot5 <- plot.and.tikz(df, "srm", "re2g")
plot6 <- plot.and.tikz(df, "grep", "re2g")
plot7 <- plot.and.tikz(df, "dotnet", "re2g")
plot8 <- plot.and.tikz(df, "srm", "grep")
plot9 <- plot.and.tikz(df, "dotnet", "grep")
plot10 <- plot.and.tikz(df, "dotnet", "srm")
#grid.arrange(plot1, plot3, ncol = 2)
#grid.arrange(plot4, plot5, ncol = 2)
#grid.arrange(plot7, plot10, ncol = 2)
grid.arrange(plot1, plot2, ncol = 2)

grid.arrange(plot3, plot4, ncol = 2)

grid.arrange(plot5, plot6, ncol = 2)

grid.arrange(plot7, plot8, ncol = 2)

grid.arrange(plot9, plot10, ncol = 2)

Histograms
hist1 <- ggplot(df, aes(x=re2g)) +
geom_histogram(color="blue", fill="lightblue") +
scale_y_log10()
hist2 <- ggplot(df, aes(x=cad)) +
geom_histogram(color="blue", fill="lightblue") +
scale_y_log10()
hist3 <- ggplot(df, aes(x=srm)) +
geom_histogram(color="blue", fill="lightblue") +
scale_y_log10()
#hist4 <- ggplot(df, aes(x=grep)) +
# geom_histogram(color="blue", fill="lightblue") +
# scale_y_log10()
hist5 <- ggplot(df, aes(x=dotnet)) +
geom_histogram(color="blue", fill="lightblue") +
scale_y_log10()
grid.arrange(hist1, hist2, ncol = 2)

grid.arrange(hist3, hist5, ncol = 2)

#grid.arrange(hist5, ncol = 2)
Finding winners
df$min <-pmin(df$grep, df$srm, df$re2g, df$dotnet, df$cad)
df$enemy.min <- pmin(df$grep, df$srm, df$re2g, df$dotnet)
#df$min <-pmin(df$srm, df$re2g, df$dotnet, df$cad)
#df$enemy.min <- pmin(df$srm, df$re2g, df$dotnet)
winners.grep <- nrow(df[df$min == df$grep,])
winners.re2 <- nrow(df[df$min == df$re2g,])
winners.ca <- nrow(df[df$min == df$cad,])
winners.srm <- nrow(df[df$min == df$srm,])
winners.dotnet <- nrow(df[df$min == df$dotnet,])
winners.ca.over.re2 <- nrow(df[df$cad <= df$re2g,])
winners.ca.over.grep <- nrow(df[df_grep$cad <= df_grep$grep,])
winners.ca.over.srm <- nrow(df[df$cad <= df$srm,])
winners.ca.over.dotnet <- nrow(df[df$cad <= df$dotnet,])
winners.10.ca.over.re2 <- nrow(df[10* df$cad <= df$re2g,])
winners.10.ca.over.grep <- nrow(df[10* df_grep$cad <= df_grep$grep,])
winners.10.ca.over.srm <- nrow(df[10* df$cad <= df$srm,])
winners.10.ca.over.dotnet <- nrow(df[10* df$cad <= df$dotnet,])
winners.100.ca.over.re2 <- nrow(df[100* df$cad <= df$re2g,])
winners.100.ca.over.grep <- nrow(df[100* df_grep$cad <= df_grep$grep,])
winners.100.ca.over.srm <- nrow(df[100* df$cad <= df$srm,])
winners.100.ca.over.dotnet <- nrow(df[100* df$cad <= df$dotnet,])
longer.than.10.seconds.ca <- nrow(df[df$cad > 10,])
longer.than.10.seconds.re2 <- nrow(df[df$re2g > 10,])
longer.than.10.seconds.srm <- nrow(df[df$srm > 10,])
longer.than.10.seconds.dotnet <- nrow(df[df$dotnet > 10,])
longer.than.10.seconds.grep <- nrow(df[df$grep > 10,])
| CA |
88 |
| RE2 |
1211 |
| SRM |
31 |
| .NET |
73 |
| grep |
699 |
| RE2 |
258 / 1727 |
| SRM |
312 / 1727 |
| .NET |
697 / 1727 |
| grep |
754 / 1373 |
| RE2 |
145 / 1727 |
| SRM |
152 / 1727 |
| .NET |
134 / 1727 |
| grep |
201 / 1373 |
| RE2 |
88 / 1727 |
| SRM |
93 / 1727 |
| .NET |
20 / 1727 |
| grep |
75 / 1373 |
| CA |
19 |
| RE2 |
147 |
| SRM |
152 |
| .NET |
155 |
| grep |
225 |
plot.and.tikz(df, "enemy.min", "cad", xstring="best enemy", ystring="CA [s]")

How much we are better than RE2
df$re2.vs.ca <- df$re2g / df$cad
df_sorted <- df[order(df$re2.vs.ca, decreasing=TRUE),]
#df_sorted[,c("src", "pattern", "file", "re2g", "cad", "re2.vs.ca", "re2.ca.mismatch")]
df_sorted <- df_sorted[1:10,c("src", "pattern", "file", tools.times)]
df_sorted
haf <- latex(df_sorted,
file="figs/best_results.tex",
booktabs=TRUE,
table.env=FALSE,
center="none")
Sorting according to total time
df$total.time <- df$grep + df$re2g + df$cad + df$srm + df$dotnet
df_sorted <- df[order(df$total.time, decreasing=TRUE),]
df_sorted
df_sorted <- df_sorted[1:10,c("src", "pattern", "file", tools.times)]
haf <- latex(df_sorted,
file="figs/total_time.tex",
booktabs=TRUE,
table.env=FALSE,
center="none")
Sorting according to enemy.min
df_sorted <- df[order(df$enemy.min, decreasing=TRUE),]
df_sorted
df_sorted <- df_sorted[1:10,c("src", "pattern", "file", tools.times)]
haf <- latex(df_sorted,
file="figs/enemy_min.tex",
booktabs=TRUE,
table.env=FALSE,
center="none")
Summaries
df_for_summary <- df[,c("re2g", "cad", "srm", "dotnet", "grep")]
#df.summary <- do.call(cbind, lapply(df_for_summary, summary))
#df.summary
desc <- stat.desc(df_for_summary)
desc
haf <- latex(desc,
file="figs/stats.tex",
booktabs=TRUE,
table.env=FALSE,
center="none")
Experiments with increasing counter value
big <- read_file(params$file_big)
big$re2g <- sub(",", ".", big$re2g)
big$re2g <- as.numeric(big$re2g)
NAs introduced by coercion
big
together <- big[, c("Counter", "re2g")]
names(together)[2] <- "time"
together$approach <- "RE2"
tmp <- big[, c("Counter", "cad")]
names(tmp)[2] <- "time"
tmp$approach <- "CA"
together <- rbind(together, tmp)
tmp <- big[, c("Counter", "srm")]
names(tmp)[2] <- "time"
tmp$approach <- "SRM"
together <- rbind(together, tmp)
tmp <- big[, c("Counter", "dot.net")]
names(tmp)[2] <- "time"
tmp$approach <- ".NET"
together <- rbind(together, tmp)
tmp <- big[, c("Counter", "grep")]
names(tmp)[2] <- "time"
tmp$approach <- "grep"
together <- rbind(together, tmp)
BIG_STEP=100
# remove too many points
together <- together[together$Counter %% BIG_STEP == 0,]
big_plot <- ggplot(data=together, aes(x=Counter, y=time, colour=approach)) +
geom_line() +
geom_point(aes(shape=approach)) +
xlim(NA,2000) +
ylim(NA,20) +
geom_hline(size=0.1, yintercept=0, linetype="dashed") +
theme(legend.position = c(.02, .98),
legend.justification = c("left", "top"),
#legend.box.background = element_rect(color="black", size=0.5),
legend.box.just = "right",
legend.margin = margin(1, 1, 1, 1),
legend.title = element_blank()) +
labs(
#title="Title",
#subtitle="Subtitle",
x="k",
y="time [s]")
# geom_line(data = big, aes(x = Counter, y = re2g), color = "red") +
# geom_line(data = big, aes(x = Counter, y = ca), color = "blue") +
# xlab('counter value') +
# ylab('time [s]')
#make_tikz(paste0("figs/big_plot.tikz"), big_plot, width=2.7, height=2.7)
make_pdf(paste0("figs/big_plot.pdf"), big_plot, width=BIG_SIZE, height=BIG_SIZE)
plot(big_plot)

# Information about DCAs
# df_dcas = read.csv2(params$file_dca,
# header=TRUE,
# sep="\t",
# dec=".",
# comment.char="",
# quote="",
# strip.white=TRUE,
# stringsAsFactors=FALSE)
#
# # sanitize
# df_dcas$timeouts.classical[is.na(df_dcas$timeouts.classical)] <- 0
#df_dcas
#tms.classical <- df_dcas[df_dcas$timeouts.classical == 1,]
#compute_timeouts <- function(df, col) {
# tmp <- df[df[, col] == TIMEOUT_VAL,]
# tmp
#}
LS0tCnRpdGxlOiAiQ250LVNldC1NYXRhIEFuYWx5c2lzIgpwYXJhbXM6CiAgI2ZpbGVfY21wOiBkYXRhL3Jlc3VsdHMtMjMtMDQtMjAyMC5jc3YKICAjZmlsZV9jbXA6IHJlc3VsdHMtMDUtMDUtMjAyMC9iZXR3ZWVuL3Jlc3VsdHMuY3N2CiAgI2ZpbGVfY21wOiByZXN1bHRzLTA5LTA1LTIwMjAvYmV0d2Vlbi9SRVNVTFRTLUFMTC1iZXR3ZWVuLmNzdgogICNmaWxlX2NtcDogcmVzdWx0cy0xMC0wNS0yMDIwL3RhYmxlLUFMTC5jc3YKICAjZmlsZV9jbXA6IHJlc3VsdHMtMTEtMDUtMjAyMC90YWJsZS1BTEwtb25kcmEtcHJvY2Vzc2VkLmNzdgogICNmaWxlX2NtcDogcmVzdWx0cy0xMi0wNS0yMDIwL3RhYmxlLUFMTC1vbmRyYS1wcm9jZXNzZWQuY3N2CiAgI2ZpbGVfY21wOiByZXN1bHRzLTE1LTA1LTIwMjAvbm9ncmVwL2N1dC90YWJsZS1BTEwtcHJvY2Vzc2VkLmNzdgogICNmaWxlX2NtcDogcmVzdWx0cy0xNS0wNS0yMDIwL25vZ3JlcC9ub2N1dC90YWJsZS1BTEwtcHJvY2Vzc2VkLmNzdgogICNmaWxlX2NtcDogcmVzdWx0cy0xNS0wNS0yMDIwL25vZ3JlcC9tZXJnZWQvdGFibGUtQUxMLXByb2Nlc3NlZC5jc3YKICBmaWxlX2NtcDogcmVzdWx0cy0xNS0wNS0yMDIwL25vZ3JlcC9tZXJnZWRSZXN1bHRzL3RhYmxlLUFMTC1wcm9jZXNzZWQuY3N2CiAgI2ZpbGVfYmlnOiByZXN1bHRzLTA1LTA1LTIwMjAvdGFibGUtYmlnLTI1MDM2MTAyLmNzdgogIGZpbGVfYmlnOiByZXN1bHRzLTExLTA1LTIwMjAvZ3JhcGgvdGFibGUtYmlnLTEwNjUyODk3MDQuY3N2CiAgZmlsZV9kY2E6IERDQXMvcmVzdWx0cy10cmFuc2xhdGlvbi50c3YKICB0aW1lb3V0OiA2MDAgIyBzZWNvbmRzCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0CiAgaHRtbF9kb2N1bWVudDoKICAgIGRmX3ByaW50OiBwYWdlZAogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKLS0tCgpgYGB7cn0KIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIFBSRUFNQkxFCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KCiMgbG9hZCB0aGUgcGxvdHRpbmcgbGlicmFyeQpzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkoZ2dwbG90MikpCmxpYnJhcnkoZ3JpZEV4dHJhKQpsaWJyYXJ5KGdnRXh0cmEpCmxpYnJhcnkodGlrekRldmljZSkKbGlicmFyeShIbWlzYykKbGlicmFyeShwYXN0ZWNzKQoKCgp0aGVtZV9zZXQodGhlbWVfYncoKSkKCm9wdGlvbnMoc2NpcGVuPTk5OSkgICMgdHVybi1vZmYgc2NpZW50aWZpYyBub3RhdGlvbiBsaWtlIDFlKzQ4CgojIHNpemUgb2YgcG9pbnQgZm9yIHNjYXR0ZXJwbG90cwpQT0lOVF9TSVpFID0gMC4xCiNQT0lOVF9TSVpFID0gMQoKIyB0aW1lb3V0ClRJTUVPVVQgPSBwYXJhbXMkdGltZW91dApUSU1FT1VUX1ZBTCA9IDEuMDUgKiBUSU1FT1VUCgpFUlJfVkFMID0gMS4zICogVElNRU9VVAoKIyBzYXR1cmF0ZQojVElNRV9NSU4gPSAwLjAxICMgc2Vjb25kcwpUSU1FX01JTiA9IDAuMSAjIHNlY29uZHMKCkJJR19TSVpFPTMKU01BTExfU0laRT0yCgoKIyBGVU5DVElPTlMKcmVhZF9maWxlIDwtIGZ1bmN0aW9uKGZpbGUpIHsKICBmaWxlbmFtZSA9IHBhc3RlMChmaWxlKQogIGRmIDwtIHJlYWQuY3N2MihmaWxlbmFtZSwKICAgICAgICAgICAgICAgICAgaGVhZGVyPVRSVUUsCiAgICAgICAgICAgICAgICAgIHNlcD0iOyIsCiAgICAgICAgICAgICAgICAgIGRlYz0iLCIsCiAgICAgICAgICAgICAgICAgIGNvbW1lbnQuY2hhcj0iIiwKICAgICAgICAgICAgICAgICAgcXVvdGU9IlwiIiwKICAgICAgICAgICAgICAgICAgc3RyaXAud2hpdGU9VFJVRSwKICAgICAgICAgICAgICAgICAgYWxsb3dFc2NhcGVzPUZBTFNFLAogICAgICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFKQogIAogIAogIHJldHVybihkZikKfQoKcGxvdF9zY2F0dGVyX2xvZyA8LSBmdW5jdGlvbihkZiwgeGxhYiwgeWxhYiwgeHN0cmluZz14bGFiLCB5c3RyaW5nPXlsYWIpIHsKICBwc2NhdCA8LSBnZ3Bsb3QoZGYsIGFlc19zdHJpbmcoeD14bGFiLCB5PXlsYWIpKSArCiAgICBnZW9tX3BvaW50KHNpemU9UE9JTlRfU0laRSkgKwogICAgZ2VvbV9hYmxpbmUoc2l6ZT0wLjEpICsKICAgIGdlb21fdmxpbmUoc2l6ZT0wLjEsIHhpbnRlcmNlcHQ9VElNRU9VVF9WQUwsIGxpbmV0eXBlPSJkYXNoZWQiKSArCiAgICBnZW9tX2hsaW5lKHNpemU9MC4xLCB5aW50ZXJjZXB0PVRJTUVPVVRfVkFMLCBsaW5ldHlwZT0iZGFzaGVkIikgKwogICAgZ2VvbV9ydWcoYWxwaGEgPSAwLjIpICsKICAgIHNjYWxlX3hfbG9nMTAoKSArCiAgICBzY2FsZV95X2xvZzEwKCkgKwogICAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAwLjUpKSArCiAgICAjY29vcmRfZml4ZWQoeGxpbSA9IGMoVElNRV9NSU4sIFRJTUVPVVRfVkFMKSwgeWxpbSA9IGMoMC4xLCBUSU1FT1VUX1ZBTCkpICsKICAgICNjb29yZF9maXhlZCh4bGltID0gYyhUSU1FX01JTiwgVElNRU9VVF9WQUwpLCB5bGltID0gYyhUSU1FX01JTiwgVElNRU9VVF9WQUwpKSArCiAgICAgICAgY29vcmRfZml4ZWQoeGxpbSA9IGMoVElNRV9NSU4sIFRJTUVPVVRfVkFMKSwgeWxpbSA9IGMoVElNRV9NSU4sIFRJTUVPVVRfVkFMKSkgKwogICAgbGFicygKICAgICAgI3RpdGxlPSJUaXRsZSIsCiAgICAgICNzdWJ0aXRsZT0iU3VidGl0bGUiLAogICAgICB4PXhzdHJpbmcsCiAgICAgIHk9eXN0cmluZykKIyAgICB0aGVtZSgKIyAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwgCiMgICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiMgICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsY29sb3VyID0gTkEpLAojICAgICAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsY29sb3VyID0gTkEpCiMgICAgICAgICkKIyAgdGhlbWVfbWluaW1hbCgpCiMgIHRoZW1lX2J3KCkKICMgdGhlbWUocGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOQSkpCiAjIHBzY2F0IDwtIGdnTWFyZ2luYWwocHNjYXQsIHR5cGUgPSAiZGVuc2l0eSIsIHNpemU9MTApCiMgIHBzY2F0IDwtIHBzY2F0ICsgdGhlbWVfYncoKQogIHJldHVybihwc2NhdCkKfQoKbWFrZV90aWt6IDwtIGZ1bmN0aW9uKGZpbGUsIHBpY3R1cmUsIHdpZHRoPTIuNSwgaGVpZ2h0PTIuNSkgewogIGZvbnRfc2l6ZSA8LSAxCiAgdGlreihmaWxlPWZpbGUsIG9uZWZpbGU9VCwgd2lkdGg9d2lkdGgsIGhlaWdodD1oZWlnaHQpCiAgcGxvdChwaWN0dXJlKQogIGdhcmJhZ2UgPC0gZGV2Lm9mZigpCn0KCm1ha2VfcGRmIDwtIGZ1bmN0aW9uKGZpbGUsIHBpY3R1cmUsIHdpZHRoPTUsIGhlaWdodD01KSB7CiAgcGRmKGZpbGU9ZmlsZSwgb25lZmlsZT1ULCB3aWR0aCwgaGVpZ2h0KQogIHBsb3QocGljdHVyZSkKICBnYXJiYWdlIDwtIGRldi5vZmYoKQp9CmBgYAoKYGBge3J9CmRmIDwtIHJlYWRfZmlsZShwYXJhbXMkZmlsZV9jbXApCm9yaWdfc2l6ZSA8LSBucm93KGRmKQoKY29sbmFtZXMoZGYpW2NvbG5hbWVzKGRmKSA9PSAiZG90Lm5ldCJdIDwtICJkb3RuZXQiCmNvbG5hbWVzKGRmKVtuYW1lcyhkZikgPT0gImRvdC5uZXQubWF0Y2hlcyJdIDwtICJkb3RuZXQubWF0Y2hlcyIKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMgU0FOSVRJWkUgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIGNsZWFuIHRoZSBkYXRhCmRmX25ldyA8LSBkZlshZ3JlcGwoIkZpbGUgbm90IGZvdW5kIiwgZGYkc3JtLm1hdGNoZXMpLF0KcHJpbnQocGFzdGUwKCJSZW1vdmluZyAiLCBucm93KGRmKSAtIG5yb3coZGZfbmV3KSwgIiBsaW5lcyBkdWUgdG8gZ2VuZXJhdGlvbiBvZiBpbnB1dCB0ZXh0IikpCmRmIDwtIGRmX25ldwoKdG9vbHMudGltZXMgPC0gYygicmUyZyIsICJjYWQiLCAiZ3JlcCIsICJzcm0iLCAiZG90bmV0IikKI3Rvb2xzLnRpbWVzIDwtIGMoInJlMmciLCAiY2FkIiwgInNybSIsICJkb3RuZXQiKQp0b29scy5tYXRjaGVzIDwtIGMoInJlMmcubWF0Y2hlcyIsICJjYWQubWF0Y2hlcyIsICJncmVwLm1hdGNoZXMiLCAic3JtLm1hdGNoZXMiLCAiZG90bmV0Lm1hdGNoZXMiKQojdG9vbHMubWF0Y2hlcyA8LSBjKCJyZTJnLm1hdGNoZXMiLCAiY2FkLm1hdGNoZXMiLCAic3JtLm1hdGNoZXMiLCAiZG90bmV0Lm1hdGNoZXMiKQoKIyBjaGVja2luZyBlcnJvcnMKZXJyb3JzLnJlMmcgPC0gbnJvdyhkZltncmVwbCgnRVJSJywgZGYkcmUyZyksXSkKZXJyb3JzLmdyZXAgPC0gbnJvdyhkZltncmVwbCgnRVJSJywgZGYkZ3JlcCksXSkKZXJyb3JzLnNybSA8LSBucm93KGRmW2dyZXBsKCdFUlInLCBkZiRzcm0pLF0pCmVycm9ycy5jYWQgPC0gbnJvdyhkZltncmVwbCgnRVJSJywgZGYkY2FkKSxdKQplcnJvcnMuZG90bmV0IDwtIG5yb3coZGZbZ3JlcGwoJ0VSUicsIGRmJGRvdG5ldCksXSkKCiNkZiA8LSBkZlshZ3JlcGwoJ0VSUicsIGRmJHJlMmcpLF0KI2RmJHJlMmdbZGYkcmUyZyA9PSAnRVJSJ10gPC0gRVJSX1ZBTApkZlssdG9vbHMudGltZXNdW2RmWyx0b29scy50aW1lc10gPT0gJ0VSUiddIDwtIEVSUl9WQUwKCgojIGNoYW5nZSB0aGUgdHlwZSBvZiBjb2x1bW5zIG90aGVyIHRoYW4gdGhlIG5hbWUKZm9yIChpIGluIHRvb2xzLnRpbWVzKSB7CiAgZGZbLGldIDwtIHN1YigiLCIsICIuIiwgZGZbLGldKQogIHN1cHByZXNzV2FybmluZ3MoZGZbLGldIDwtIGFzLm51bWVyaWMoZGZbLGldKSkKfQoKZm9yIChpIGluIHRvb2xzLm1hdGNoZXMpIHsKICBzdXBwcmVzc1dhcm5pbmdzKGRmWyxpXSA8LSBhcy5pbnRlZ2VyKGRmWyxpXSkpCn0KCmRmJHNyYyA8LSBhcy5mYWN0b3IoZGYkc3JjKQoKIyBnZXQgcmlkIG9mIGV4dHJlbWFsIHZhbHVlcwojZGZbLHRvb2xzLnRpbWVzXVtkZlssdG9vbHMudGltZXNdID4gVElNRU9VVF0gPC0gVElNRU9VVF9WQUwKZGZbdG9vbHMudGltZXNdW2lzLm5hKGRmW3Rvb2xzLnRpbWVzXSldIDwtIFRJTUVPVVRfVkFMCiNkZltpcy5uYShkZildIDwtIFRJTUVPVVRfVkFMCiNkZltkZiA9PSAwLjAwXSA8LSBUSU1FX01JTgpkZlssdG9vbHMudGltZXNdW2RmWyx0b29scy50aW1lc10gPCBUSU1FX01JTl0gPC0gVElNRV9NSU4KCmRmIDwtIGRmWyFpcy5uYShkZiRwYXR0ZXJuKSxdCgojIGNsZWFuIHRoZSBkYXRhCiNkZl9uZXcgPC0gZGZbZGYkTGluZXMgIT0gIkVSUk9SIFdISUxFIENPTlZFUlRJTkcgVE8gRENBLiIsXQojcHJpbnQocGFzdGUwKCJSZW1vdmluZyAiLCBucm93KGRmKSAtIG5yb3coZGZfbmV3KSwgIiBsaW5lcyBkdWUgdG8gY29udmVydGluZyB0byBEQ0EgZXJyb3IiKSkKI2RmIDwtIGRmX25ldwoKCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMgQ09VTlRJTkcgVElNRU9VVFMgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKdGltZW91dHMucmUyZyA8LSBucm93KGRmW2RmJHJlMmcgPT0gVElNRU9VVF9WQUwsXSkKdGltZW91dHMuY2FkIDwtIG5yb3coZGZbZGYkY2FkID09IFRJTUVPVVRfVkFMLF0pCnRpbWVvdXRzLmdyZXAgPC0gbnJvdyhkZltkZiRncmVwID09IFRJTUVPVVRfVkFMLF0pCnRpbWVvdXRzLnNybSA8LSBucm93KGRmW2RmJHNybSA9PSBUSU1FT1VUX1ZBTCxdKQp0aW1lb3V0cy5kb3RuZXQgPC0gbnJvdyhkZltkZiRkb3RuZXQgPT0gVElNRU9VVF9WQUwsXSkKdGltZW91dHMucmUyLmFuZC5jYSA8LSBucm93KGRmW2RmJGNhZCA9PSBUSU1FT1VUX1ZBTCAmIGRmJHJlMmcgPT0gVElNRU9VVF9WQUwsXSkKCiMgfCAqKlRpbWVvdXRzIGdyZXAqKiAgICB8IGByIHRpbWVvdXRzLmdyZXBgICB8CmBgYAoKVGhlc2UgYXJlIHJlc3VsdHMgb2YgdGhlIGV4cGVyaW1lbnRzIGZvciBDb3VudGluZyBTZXQgQXV0b21hdGE6Cgp8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgfAp8LS0tLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tOnwtfAp8ICoqRmlsZSoqICAgICAgICAgICAgfCBgciBwYXJhbXMkZmlsZV9jbXBgIHwKfCAqKlRpbWVvdXQqKiAgICAgICAgIHwgYHIgVElNRU9VVGAgcyAgICAgICB8CnwgKipUSU1FT1VUX1ZBTCoqICAgICB8IGByIFRJTUVPVVRfVkFMYCBzICAgfAp8ICoqVElNRV9NSU4qKiAgICAgICAgfCBgciBUSU1FX01JTmAgICAgICAgIHwKfCAqKm9yaWdpbmFsIHNpemUqKiAgIHwgYHIgb3JpZ19zaXplYCAgICAgICB8CnwgKipCZW5jaG1hcmtzKiogICAgICB8IGByIG5yb3coZGYpYCAgICAgICAgfAp8ICoqVGltZW91dHMgQ0EqKiAgICAgfCBgciB0aW1lb3V0cy5jYWRgICAgICB8CnwgKipUaW1lb3V0cyBSRTIqKiAgICB8IGByIHRpbWVvdXRzLnJlMmdgICAgIHwKfCAqKlRpbWVvdXRzIFNSTSoqICAgIHwgYHIgdGltZW91dHMuc3JtYCAgICB8IAp8ICoqVGltZW91dHMgZ3JlcCoqICAgfCBgciB0aW1lb3V0cy5ncmVwYCAgICB8IAp8ICoqVGltZW91dHMgLk5FVCoqICAgfCBgciB0aW1lb3V0cy5kb3RuZXRgICB8CnwgKipFcnJvcnMgQ0EqKiAgICAgfCBgciBlcnJvcnMuY2FkYCAgICAgfAp8ICoqRXJyb3JzIFJFMioqICAgIHwgYHIgZXJyb3JzLnJlMmdgICAgIHwgKHJlbW92ZWQpIHwKfCAqKkVycm9ycyBTUk0qKiAgICB8IGByIGVycm9ycy5zcm1gICAgIHwgCnwgKipFcnJvcnMgZ3JlcCoqICAgfCBgciBlcnJvcnMuZ3JlcGAgICAgfCAKfCAqKkVycm9ycyAuTkVUKiogICB8IGByIGVycm9ycy5kb3RuZXRgICB8CgoKCmBgYHtyfQpkZgpgYGAKCiMgU3VtbWFyeSBvZiBiZW5jaG1hcmtzCgpgYGB7cn0KZGZfYmVuY2hlcyA8LSBkYXRhLmZyYW1lKHN1bW1hcnkoZGYkc3JjKSkKZGZfYmVuY2hlcwpgYGAKCiMgU2FuaXR5IGNoZWNrcwoKYGBge3J9CmRmJGluY29uc2lzdGVudCA8LSBkZiRyZTJnLm1hdGNoZXMgIT0gZGYkZ3JlcC5tYXRjaGVzIHwgZGYkcmUyZy5tYXRjaGVzICE9IGRmJHNybS5tYXRjaGVzIHwgZGYkcmUyZy5tYXRjaGVzICE9IGRmJGRvdG5ldC5tYXRjaGVzIHwgZGYkcmUyZy5tYXRjaGVzICE9IGRmJGNhZC5tYXRjaGVzCgojZGYkaW5jb25zaXN0ZW50IDwtIGRmJHJlMmcubWF0Y2hlcyAhPSBkZiRzcm0ubWF0Y2hlcyB8IGRmJHJlMmcubWF0Y2hlcyAhPSBkZiRkb3RuZXQubWF0Y2hlcyB8IGRmJHJlMmcubWF0Y2hlcyAhPSBkZiRjYWQubWF0Y2hlcwoKZGYkZ3JlcC5yZTIubWlzbWF0Y2ggPC0gIWlzLm5hKGRmJHJlMmcubWF0Y2hlcykgJiAhaXMubmEoZGYkZ3JlcC5tYXRjaGVzKSAmIGRmJHJlMmcubWF0Y2hlcyAhPSBkZiRncmVwLm1hdGNoZXMKZGZfZ3JlcF9yZTJfbWlzbWF0Y2ggPC0gZGZbZGYkZ3JlcC5yZTIubWlzbWF0Y2gsXQoKZGYkcmUyLmNhLm1pc21hdGNoIDwtICFpcy5uYShkZiRyZTJnLm1hdGNoZXMpICYgIWlzLm5hKGRmJGNhZC5tYXRjaGVzKSAmIGRmJHJlMmcubWF0Y2hlcyAhPSBkZiRjYWQubWF0Y2hlcwpkZl9yZTJfY2FfbWlzbWF0Y2ggPC0gZGZbZGYkcmUyLmNhLm1pc21hdGNoLF0KCmRmIDwtIGRmW2lzLm5hKGRmJHJlMmcubWF0Y2hlcykgfCBpcy5uYShkZiRncmVwLm1hdGNoZXMpIHwgZGYkcmUyZy5tYXRjaGVzID09IGRmJGNhZC5tYXRjaGVzLF0KCmBgYAoKfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgIHwKfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS06fCAtLS0tLS0tOnwKfCAqKkNBIGFuZCBSRTIgbWlzbWF0Y2hlZCoqICAgfCBgciBucm93KGRmX3JlMl9jYV9taXNtYXRjaClgICAgfCAocmVtb3ZlZCkgfAp8ICoqZ3JlcCBhbmQgUkUyIG1pc21hdGNoZWQqKiB8IGByIG5yb3coZGZfZ3JlcF9yZTJfbWlzbWF0Y2gpYCB8CgoKIyMgUkUyIGFuZCBDQSBtaXNtYXRjaGVzCmBgYHtyfQpkZl9yZTJfY2FfbWlzbWF0Y2gKYGBgCgoKCiMgU2NhdHRlciBQbG90cwoKYGBge3J9CgpwbG90LmFuZC50aWt6IDwtIGZ1bmN0aW9uKGRmLCB4bGFiLCB5bGFiLCB4c3RyaW5nPXhsYWIsIHlzdHJpbmc9eWxhYiwgd2lkdGg9NCwgaGVpZ2h0PXdpZHRoKSB7CiAgcGljIDwtIHBsb3Rfc2NhdHRlcl9sb2coZGYsIHhsYWIsIHlsYWIsIHhzdHJpbmcsIHlzdHJpbmcpCiAgI21ha2VfdGlreihwYXN0ZTAoImZpZ3MvIiwgeGxhYiwgIi12cy0iLCB5bGFiLCAiLnRpa3oiKSwgcGljLCB3aWR0aCwgaGVpZ2h0KQogIG1ha2VfcGRmKHBhc3RlMCgiZmlncy8iLCB4bGFiLCAiLXZzLSIsIHlsYWIsICIucGRmIiksIHBpYywgd2lkdGgsIGhlaWdodCkKICBwaWMKfQoKZGZfZ3JlcCA8LSBkZltpcy5uYShkZiRncmVwLm1hdGNoZXMpIHwgaXMubmEoZGYkY2FkLm1hdGNoZXMpIHwgZGYkZ3JlcC5tYXRjaGVzID09IGRmJGNhZC5tYXRjaGVzLF0KCnBsb3QxIDwtIHBsb3QuYW5kLnRpa3ooZGYsICJyZTJnIiwgImNhZCIsIHhzdHJpbmc9IlJFMiBbc10iLCB5c3RyaW5nPSJDQSBbc10iLCB3aWR0aD1CSUdfU0laRSkKcGxvdDIgPC0gcGxvdC5hbmQudGlreihkZl9ncmVwLCAiZ3JlcCIsICJjYWQiLCB4c3RyaW5nPSJncmVwIFtzXSIsIHlzdHJpbmc9IkNBIFtzXSIsIHdpZHRoPVNNQUxMX1NJWkUpCnBsb3QzIDwtIHBsb3QuYW5kLnRpa3ooZGYsICJzcm0iLCAiY2FkIiwgeHN0cmluZz0iU1JNIFtzXSIsIHlzdHJpbmc9IkNBIFtzXSIsIHdpZHRoPVNNQUxMX1NJWkUpCnBsb3Q0IDwtIHBsb3QuYW5kLnRpa3ooZGYsICJkb3RuZXQiLCAiY2FkIiwgeHN0cmluZz0iLk5FVCBbc10iLCB5c3RyaW5nPSJDQSBbc10iLCB3aWR0aD1TTUFMTF9TSVpFKQpwbG90NSA8LSBwbG90LmFuZC50aWt6KGRmLCAic3JtIiwgInJlMmciKQpwbG90NiA8LSBwbG90LmFuZC50aWt6KGRmLCAiZ3JlcCIsICJyZTJnIikKcGxvdDcgPC0gcGxvdC5hbmQudGlreihkZiwgImRvdG5ldCIsICJyZTJnIikKcGxvdDggPC0gcGxvdC5hbmQudGlreihkZiwgInNybSIsICJncmVwIikKcGxvdDkgPC0gcGxvdC5hbmQudGlreihkZiwgImRvdG5ldCIsICJncmVwIikKcGxvdDEwIDwtIHBsb3QuYW5kLnRpa3ooZGYsICJkb3RuZXQiLCAic3JtIikKCgoKI2dyaWQuYXJyYW5nZShwbG90MSwgcGxvdDMsIG5jb2wgPSAyKQojZ3JpZC5hcnJhbmdlKHBsb3Q0LCBwbG90NSwgbmNvbCA9IDIpCiNncmlkLmFycmFuZ2UocGxvdDcsIHBsb3QxMCwgbmNvbCA9IDIpCgpncmlkLmFycmFuZ2UocGxvdDEsIHBsb3QyLCBuY29sID0gMikKZ3JpZC5hcnJhbmdlKHBsb3QzLCBwbG90NCwgbmNvbCA9IDIpCmdyaWQuYXJyYW5nZShwbG90NSwgcGxvdDYsIG5jb2wgPSAyKQpncmlkLmFycmFuZ2UocGxvdDcsIHBsb3Q4LCBuY29sID0gMikKZ3JpZC5hcnJhbmdlKHBsb3Q5LCBwbG90MTAsIG5jb2wgPSAyKQoKYGBgCgojIEhpc3RvZ3JhbXMKCmBgYHtyfQpoaXN0MSA8LSBnZ3Bsb3QoZGYsIGFlcyh4PXJlMmcpKSArCiAgZ2VvbV9oaXN0b2dyYW0oY29sb3I9ImJsdWUiLCBmaWxsPSJsaWdodGJsdWUiKSArCiAgc2NhbGVfeV9sb2cxMCgpCgpoaXN0MiA8LSBnZ3Bsb3QoZGYsIGFlcyh4PWNhZCkpICsgCiAgZ2VvbV9oaXN0b2dyYW0oY29sb3I9ImJsdWUiLCBmaWxsPSJsaWdodGJsdWUiKSArCiAgc2NhbGVfeV9sb2cxMCgpCgpoaXN0MyA8LSBnZ3Bsb3QoZGYsIGFlcyh4PXNybSkpICsgCiAgZ2VvbV9oaXN0b2dyYW0oY29sb3I9ImJsdWUiLCBmaWxsPSJsaWdodGJsdWUiKSArCiAgc2NhbGVfeV9sb2cxMCgpCgojaGlzdDQgPC0gZ2dwbG90KGRmLCBhZXMoeD1ncmVwKSkgKyAKIyAgZ2VvbV9oaXN0b2dyYW0oY29sb3I9ImJsdWUiLCBmaWxsPSJsaWdodGJsdWUiKSArCiMgIHNjYWxlX3lfbG9nMTAoKQoKaGlzdDUgPC0gZ2dwbG90KGRmLCBhZXMoeD1kb3RuZXQpKSArIAogIGdlb21faGlzdG9ncmFtKGNvbG9yPSJibHVlIiwgZmlsbD0ibGlnaHRibHVlIikgKwogIHNjYWxlX3lfbG9nMTAoKQoKZ3JpZC5hcnJhbmdlKGhpc3QxLCBoaXN0MiwgbmNvbCA9IDIpCmdyaWQuYXJyYW5nZShoaXN0MywgaGlzdDUsIG5jb2wgPSAyKQojZ3JpZC5hcnJhbmdlKGhpc3Q1LCBuY29sID0gMikKCgpgYGAKCiMgRmluZGluZyB3aW5uZXJzCgpgYGB7cn0KZGYkbWluIDwtcG1pbihkZiRncmVwLCBkZiRzcm0sIGRmJHJlMmcsIGRmJGRvdG5ldCwgZGYkY2FkKQpkZiRlbmVteS5taW4gPC0gcG1pbihkZiRncmVwLCBkZiRzcm0sIGRmJHJlMmcsIGRmJGRvdG5ldCkKI2RmJG1pbiA8LXBtaW4oZGYkc3JtLCBkZiRyZTJnLCBkZiRkb3RuZXQsIGRmJGNhZCkKI2RmJGVuZW15Lm1pbiA8LSBwbWluKGRmJHNybSwgZGYkcmUyZywgZGYkZG90bmV0KQoKd2lubmVycy5ncmVwIDwtIG5yb3coZGZbZGYkbWluID09IGRmJGdyZXAsXSkKd2lubmVycy5yZTIgPC0gbnJvdyhkZltkZiRtaW4gPT0gZGYkcmUyZyxdKQp3aW5uZXJzLmNhIDwtIG5yb3coZGZbZGYkbWluID09IGRmJGNhZCxdKQp3aW5uZXJzLnNybSA8LSBucm93KGRmW2RmJG1pbiA9PSBkZiRzcm0sXSkKd2lubmVycy5kb3RuZXQgPC0gbnJvdyhkZltkZiRtaW4gPT0gZGYkZG90bmV0LF0pCgp3aW5uZXJzLmNhLm92ZXIucmUyIDwtIG5yb3coZGZbZGYkY2FkIDw9IGRmJHJlMmcsXSkKd2lubmVycy5jYS5vdmVyLmdyZXAgPC0gbnJvdyhkZltkZl9ncmVwJGNhZCA8PSBkZl9ncmVwJGdyZXAsXSkKd2lubmVycy5jYS5vdmVyLnNybSA8LSBucm93KGRmW2RmJGNhZCA8PSBkZiRzcm0sXSkKd2lubmVycy5jYS5vdmVyLmRvdG5ldCA8LSBucm93KGRmW2RmJGNhZCA8PSBkZiRkb3RuZXQsXSkKCndpbm5lcnMuMTAuY2Eub3Zlci5yZTIgPC0gbnJvdyhkZlsxMCogZGYkY2FkIDw9IGRmJHJlMmcsXSkKd2lubmVycy4xMC5jYS5vdmVyLmdyZXAgPC0gbnJvdyhkZlsxMCogZGZfZ3JlcCRjYWQgPD0gZGZfZ3JlcCRncmVwLF0pCndpbm5lcnMuMTAuY2Eub3Zlci5zcm0gPC0gbnJvdyhkZlsxMCogZGYkY2FkIDw9IGRmJHNybSxdKQp3aW5uZXJzLjEwLmNhLm92ZXIuZG90bmV0IDwtIG5yb3coZGZbMTAqIGRmJGNhZCA8PSBkZiRkb3RuZXQsXSkKCndpbm5lcnMuMTAwLmNhLm92ZXIucmUyIDwtIG5yb3coZGZbMTAwKiBkZiRjYWQgPD0gZGYkcmUyZyxdKQp3aW5uZXJzLjEwMC5jYS5vdmVyLmdyZXAgPC0gbnJvdyhkZlsxMDAqIGRmX2dyZXAkY2FkIDw9IGRmX2dyZXAkZ3JlcCxdKQp3aW5uZXJzLjEwMC5jYS5vdmVyLnNybSA8LSBucm93KGRmWzEwMCogZGYkY2FkIDw9IGRmJHNybSxdKQp3aW5uZXJzLjEwMC5jYS5vdmVyLmRvdG5ldCA8LSBucm93KGRmWzEwMCogZGYkY2FkIDw9IGRmJGRvdG5ldCxdKQoKbG9uZ2VyLnRoYW4uMTAuc2Vjb25kcy5jYSA8LSBucm93KGRmW2RmJGNhZCA+IDEwLF0pCmxvbmdlci50aGFuLjEwLnNlY29uZHMucmUyIDwtIG5yb3coZGZbZGYkcmUyZyA+IDEwLF0pCmxvbmdlci50aGFuLjEwLnNlY29uZHMuc3JtIDwtIG5yb3coZGZbZGYkc3JtID4gMTAsXSkKbG9uZ2VyLnRoYW4uMTAuc2Vjb25kcy5kb3RuZXQgPC0gbnJvdyhkZltkZiRkb3RuZXQgPiAxMCxdKQpsb25nZXIudGhhbi4xMC5zZWNvbmRzLmdyZXAgPC0gbnJvdyhkZltkZiRncmVwID4gMTAsXSkKCgpgYGAKCnwgKipXaW5uZXIqKiAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfAp8LS0tLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tOnwKfCAqKkNBKiogICAgIHwgYHIgd2lubmVycy5jYWAgICAgIHwKfCAqKlJFMioqICAgIHwgYHIgd2lubmVycy5yZTJgICAgIHwKfCAqKlNSTSoqICAgIHwgYHIgd2lubmVycy5zcm1gICAgIHwgCnwgKiouTkVUKiogICAgfCBgciB3aW5uZXJzLmRvdG5ldGAgIHwKfCAqKmdyZXAqKiAgICB8IGByIHdpbm5lcnMuZ3JlcGAgIHwKCnwgKipXaW5zIG9mIENBIG92ZXIqKiAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfAp8LS0tLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tOnwKfCAqKlJFMioqICAgIHwgYHIgd2lubmVycy5jYS5vdmVyLnJlMmAgLyBgciBucm93KGRmKWAgICB8CnwgKipTUk0qKiAgICB8IGByIHdpbm5lcnMuY2Eub3Zlci5zcm1gIC8gYHIgbnJvdyhkZilgICAgIHwgCnwgKiouTkVUKiogICAgfCBgciB3aW5uZXJzLmNhLm92ZXIuZG90bmV0YCAvIGByIG5yb3coZGYpYCAgfAp8ICoqZ3JlcCoqICAgIHwgYHIgd2lubmVycy5jYS5vdmVyLmdyZXBgIC8gYHIgbnJvdyhkZl9ncmVwKWAgIHwKCnwgKipXaW5zIG9mIGF0IGxlYXN0IDEwIHRpbWVzIG9mIENBIG92ZXIqKiAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfAp8LS0tLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tOnwKfCAqKlJFMioqICAgIHwgYHIgd2lubmVycy4xMC5jYS5vdmVyLnJlMmAgLyBgciBucm93KGRmKWAgICB8CnwgKipTUk0qKiAgICB8IGByIHdpbm5lcnMuMTAuY2Eub3Zlci5zcm1gIC8gYHIgbnJvdyhkZilgICAgIHwgCnwgKiouTkVUKiogICAgfCBgciB3aW5uZXJzLjEwLmNhLm92ZXIuZG90bmV0YCAvIGByIG5yb3coZGYpYCAgfAp8ICoqZ3JlcCoqICAgIHwgYHIgd2lubmVycy4xMC5jYS5vdmVyLmdyZXBgIC8gYHIgbnJvdyhkZl9ncmVwKWAgIHwKCnwgKipXaW5zIG9mIGF0IGxlYXN0IDEwMCB0aW1lcyBvZiBDQSBvdmVyKiogICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwKfC0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLTp8CnwgKipSRTIqKiAgICB8IGByIHdpbm5lcnMuMTAwLmNhLm92ZXIucmUyYCAvIGByIG5yb3coZGYpYCAgIHwKfCAqKlNSTSoqICAgIHwgYHIgd2lubmVycy4xMDAuY2Eub3Zlci5zcm1gIC8gYHIgbnJvdyhkZilgICAgIHwgCnwgKiouTkVUKiogICAgfCBgciB3aW5uZXJzLjEwMC5jYS5vdmVyLmRvdG5ldGAgLyBgciBucm93KGRmKWAgIHwKfCAqKmdyZXAqKiAgICB8IGByIHdpbm5lcnMuMTAwLmNhLm92ZXIuZ3JlcGAgLyBgciBucm93KGRmX2dyZXApYCAgfAoKfCAqKkxvbmdlciB0aGFuIDEwIHMqKiAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfAp8LS0tLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tOnwKfCAqKkNBKiogICAgIHwgYHIgbG9uZ2VyLnRoYW4uMTAuc2Vjb25kcy5jYWAgICAgIHwKfCAqKlJFMioqICAgIHwgYHIgbG9uZ2VyLnRoYW4uMTAuc2Vjb25kcy5yZTJgICAgIHwKfCAqKlNSTSoqICAgIHwgYHIgbG9uZ2VyLnRoYW4uMTAuc2Vjb25kcy5zcm1gICAgIHwgCnwgKiouTkVUKiogICAgfCBgciBsb25nZXIudGhhbi4xMC5zZWNvbmRzLmRvdG5ldGAgIHwKfCAqKmdyZXAqKiAgICB8IGByIGxvbmdlci50aGFuLjEwLnNlY29uZHMuZ3JlcGAgIHwKCgoKYGBge3J9CnBsb3QuYW5kLnRpa3ooZGYsICJlbmVteS5taW4iLCAiY2FkIiwgeHN0cmluZz0iYmVzdCBlbmVteSIsIHlzdHJpbmc9IkNBIFtzXSIpCmBgYAoKIyBIb3cgbXVjaCB3ZSBhcmUgYmV0dGVyIHRoYW4gUkUyCgpgYGB7cn0KZGYkcmUyLnZzLmNhIDwtIGRmJHJlMmcgLyBkZiRjYWQKZGZfc29ydGVkIDwtIGRmW29yZGVyKGRmJHJlMi52cy5jYSwgZGVjcmVhc2luZz1UUlVFKSxdCgojZGZfc29ydGVkWyxjKCJzcmMiLCAicGF0dGVybiIsICJmaWxlIiwgInJlMmciLCAiY2FkIiwgInJlMi52cy5jYSIsICJyZTIuY2EubWlzbWF0Y2giKV0KZGZfc29ydGVkIDwtIGRmX3NvcnRlZFsxOjEwLGMoInNyYyIsICJwYXR0ZXJuIiwgImZpbGUiLCB0b29scy50aW1lcyldCmRmX3NvcnRlZApoYWYgPC0gbGF0ZXgoZGZfc29ydGVkLAogICAgICAgICAgICAgZmlsZT0iZmlncy9iZXN0X3Jlc3VsdHMudGV4IiwKICAgICAgICAgICAgIGJvb2t0YWJzPVRSVUUsCiAgICAgICAgICAgICB0YWJsZS5lbnY9RkFMU0UsCiAgICAgICAgICAgICBjZW50ZXI9Im5vbmUiKQpgYGAKCiMgSGFyZGVzdCBjYXNlcyBmb3IgdmFyaW91cyB0b29scwpgYGB7cn0KZGYucHJlLnNvcnQgPC0gZGYKZGYucHJlLnNvcnQgPC0gZGYucHJlLnNvcnRbb3JkZXIoZGYucHJlLnNvcnQkcmUyZywgZGVjcmVhc2luZz1UUlVFKSxdCmRmLnByZS5zb3J0IDwtIGRmLnByZS5zb3J0W29yZGVyKGRmLnByZS5zb3J0JGNhZCwgZGVjcmVhc2luZz1UUlVFKSxdCmRmLnByZS5zb3J0IDwtIGRmLnByZS5zb3J0W29yZGVyKGRmLnByZS5zb3J0JGdyZXAsIGRlY3JlYXNpbmc9VFJVRSksXQpkZi5wcmUuc29ydCA8LSBkZi5wcmUuc29ydFtvcmRlcihkZi5wcmUuc29ydCRzcm0sIGRlY3JlYXNpbmc9VFJVRSksXQpkZi5wcmUuc29ydCA8LSBkZi5wcmUuc29ydFtvcmRlcihkZi5wcmUuc29ydCRkb3RuZXQsIGRlY3JlYXNpbmc9VFJVRSksXQogIAoKZGYucmUyLmhhcmQgPC0gZGYucHJlLnNvcnRbb3JkZXIoZGYucHJlLnNvcnQkcmUyZywgZGVjcmVhc2luZz1UUlVFKSxdCmRmLmNhLmhhcmQgPC0gZGYucHJlLnNvcnRbb3JkZXIoZGYucHJlLnNvcnQkY2FkLCBkZWNyZWFzaW5nPVRSVUUpLF0KZGYuZ3JlcC5oYXJkIDwtIGRmLnByZS5zb3J0W29yZGVyKGRmLnByZS5zb3J0JGdyZXAsIGRlY3JlYXNpbmc9VFJVRSksXQpkZi5zcm0uaGFyZCA8LSBkZi5wcmUuc29ydFtvcmRlcihkZi5wcmUuc29ydCRzcm0sIGRlY3JlYXNpbmc9VFJVRSksXQpkZi5kb3RuZXQuaGFyZCA8LSBkZi5wcmUuc29ydFtvcmRlcihkZi5wcmUuc29ydCRkb3RuZXQsIGRlY3JlYXNpbmc9VFJVRSksXQoKZGYucmUyLmhhcmQKZGYuY2EuaGFyZApkZi5ncmVwLmhhcmQKZGYuc3JtLmhhcmQKZGYuZG90bmV0LmhhcmQKCmBgYAoKIyBTb3J0aW5nIGFjY29yZGluZyB0byB0b3RhbCB0aW1lCmBgYHtyfQpkZiR0b3RhbC50aW1lIDwtIGRmJGdyZXAgKyBkZiRyZTJnICsgZGYkY2FkICsgZGYkc3JtICsgZGYkZG90bmV0CgpkZl9zb3J0ZWQgPC0gZGZbb3JkZXIoZGYkdG90YWwudGltZSwgZGVjcmVhc2luZz1UUlVFKSxdCmRmX3NvcnRlZAoKZGZfc29ydGVkIDwtIGRmX3NvcnRlZFsxOjEwLGMoInNyYyIsICJwYXR0ZXJuIiwgImZpbGUiLCB0b29scy50aW1lcyldCmhhZiA8LSBsYXRleChkZl9zb3J0ZWQsCiAgICAgICAgICAgICBmaWxlPSJmaWdzL3RvdGFsX3RpbWUudGV4IiwKICAgICAgICAgICAgIGJvb2t0YWJzPVRSVUUsCiAgICAgICAgICAgICB0YWJsZS5lbnY9RkFMU0UsCiAgICAgICAgICAgICBjZW50ZXI9Im5vbmUiKQpgYGAKIyBTb3J0aW5nIGFjY29yZGluZyB0byBlbmVteS5taW4KYGBge3J9CmRmX3NvcnRlZCA8LSBkZltvcmRlcihkZiRlbmVteS5taW4sIGRlY3JlYXNpbmc9VFJVRSksXQpkZl9zb3J0ZWQKCmRmX3NvcnRlZCA8LSBkZl9zb3J0ZWRbMToxMCxjKCJzcmMiLCAicGF0dGVybiIsICJmaWxlIiwgdG9vbHMudGltZXMpXQpoYWYgPC0gbGF0ZXgoZGZfc29ydGVkLAogICAgICAgICAgICAgZmlsZT0iZmlncy9lbmVteV9taW4udGV4IiwKICAgICAgICAgICAgIGJvb2t0YWJzPVRSVUUsCiAgICAgICAgICAgICB0YWJsZS5lbnY9RkFMU0UsCiAgICAgICAgICAgICBjZW50ZXI9Im5vbmUiKQpgYGAKCiMgU3VtbWFyaWVzCgpgYGB7cn0KZGZfZm9yX3N1bW1hcnkgPC0gZGZbLGMoInJlMmciLCAiY2FkIiwgInNybSIsICJkb3RuZXQiLCAiZ3JlcCIpXQojZGYuc3VtbWFyeSA8LSBkby5jYWxsKGNiaW5kLCBsYXBwbHkoZGZfZm9yX3N1bW1hcnksIHN1bW1hcnkpKQojZGYuc3VtbWFyeQoKZGVzYyA8LSBzdGF0LmRlc2MoZGZfZm9yX3N1bW1hcnkpCmRlc2MKaGFmIDwtIGxhdGV4KGRlc2MsCiAgICAgICAgICAgICBmaWxlPSJmaWdzL3N0YXRzLnRleCIsCiAgICAgICAgICAgICBib29rdGFicz1UUlVFLAogICAgICAgICAgICAgdGFibGUuZW52PUZBTFNFLAogICAgICAgICAgICAgY2VudGVyPSJub25lIikKCmBgYAoKIyBFeHBlcmltZW50cyB3aXRoIGluY3JlYXNpbmcgY291bnRlciB2YWx1ZQoKYGBge3J9CmJpZyA8LSByZWFkX2ZpbGUocGFyYW1zJGZpbGVfYmlnKQpiaWckcmUyZyA8LSBzdWIoIiwiLCAiLiIsIGJpZyRyZTJnKQpiaWckcmUyZyA8LSBhcy5udW1lcmljKGJpZyRyZTJnKQoKYmlnCmBgYAoKCmBgYHtyfQoKdG9nZXRoZXIgPC0gYmlnWywgYygiQ291bnRlciIsICJyZTJnIildCm5hbWVzKHRvZ2V0aGVyKVsyXSA8LSAidGltZSIKdG9nZXRoZXIkYXBwcm9hY2ggPC0gIlJFMiIKCnRtcCA8LSBiaWdbLCBjKCJDb3VudGVyIiwgImNhZCIpXQpuYW1lcyh0bXApWzJdIDwtICJ0aW1lIgp0bXAkYXBwcm9hY2ggPC0gIkNBIgp0b2dldGhlciA8LSByYmluZCh0b2dldGhlciwgdG1wKQoKdG1wIDwtIGJpZ1ssIGMoIkNvdW50ZXIiLCAic3JtIildCm5hbWVzKHRtcClbMl0gPC0gInRpbWUiCnRtcCRhcHByb2FjaCA8LSAiU1JNIgp0b2dldGhlciA8LSByYmluZCh0b2dldGhlciwgdG1wKQoKdG1wIDwtIGJpZ1ssIGMoIkNvdW50ZXIiLCAiZG90Lm5ldCIpXQpuYW1lcyh0bXApWzJdIDwtICJ0aW1lIgp0bXAkYXBwcm9hY2ggPC0gIi5ORVQiCnRvZ2V0aGVyIDwtIHJiaW5kKHRvZ2V0aGVyLCB0bXApCgp0bXAgPC0gYmlnWywgYygiQ291bnRlciIsICJncmVwIildCm5hbWVzKHRtcClbMl0gPC0gInRpbWUiCnRtcCRhcHByb2FjaCA8LSAiZ3JlcCIKdG9nZXRoZXIgPC0gcmJpbmQodG9nZXRoZXIsIHRtcCkKCkJJR19TVEVQPTEwMAoKIyByZW1vdmUgdG9vIG1hbnkgcG9pbnRzCnRvZ2V0aGVyIDwtIHRvZ2V0aGVyW3RvZ2V0aGVyJENvdW50ZXIgJSUgQklHX1NURVAgPT0gMCxdCgpiaWdfcGxvdCA8LSBnZ3Bsb3QoZGF0YT10b2dldGhlciwgYWVzKHg9Q291bnRlciwgeT10aW1lLCBjb2xvdXI9YXBwcm9hY2gpKSArCiAgZ2VvbV9saW5lKCkgKwogIGdlb21fcG9pbnQoYWVzKHNoYXBlPWFwcHJvYWNoKSkgKwogIHhsaW0oTkEsMjAwMCkgKwogIHlsaW0oTkEsMjApICsKICBnZW9tX2hsaW5lKHNpemU9MC4xLCB5aW50ZXJjZXB0PTAsIGxpbmV0eXBlPSJkYXNoZWQiKSArCgogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoLjAyLCAuOTgpLAogICAgICAgIGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gYygibGVmdCIsICJ0b3AiKSwKICAgICAgICAjbGVnZW5kLmJveC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG9yPSJibGFjayIsIHNpemU9MC41KSwKICAgICAgICBsZWdlbmQuYm94Lmp1c3QgPSAicmlnaHQiLAogICAgICAgIGxlZ2VuZC5tYXJnaW4gPSBtYXJnaW4oMSwgMSwgMSwgMSksCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArCiAgbGFicygKICAgICAgI3RpdGxlPSJUaXRsZSIsCiAgICAgICNzdWJ0aXRsZT0iU3VidGl0bGUiLAogICAgICB4PSJrIiwKICAgICAgeT0idGltZSBbc10iKQogICAgICAgIAoKICAjIGdlb21fbGluZShkYXRhID0gYmlnLCBhZXMoeCA9IENvdW50ZXIsIHkgPSByZTJnKSwgY29sb3IgPSAicmVkIikgKwogICMgZ2VvbV9saW5lKGRhdGEgPSBiaWcsIGFlcyh4ID0gQ291bnRlciwgeSA9IGNhKSwgY29sb3IgPSAiYmx1ZSIpICsKICAjIHhsYWIoJ2NvdW50ZXIgdmFsdWUnKSArCiAgIyB5bGFiKCd0aW1lIFtzXScpCgojbWFrZV90aWt6KHBhc3RlMCgiZmlncy9iaWdfcGxvdC50aWt6IiksIGJpZ19wbG90LCB3aWR0aD0yLjcsIGhlaWdodD0yLjcpCm1ha2VfcGRmKHBhc3RlMCgiZmlncy9iaWdfcGxvdC5wZGYiKSwgYmlnX3Bsb3QsIHdpZHRoPUJJR19TSVpFLCBoZWlnaHQ9QklHX1NJWkUpCgoKcGxvdChiaWdfcGxvdCkKYGBgCgoKYGBge3J9CiMgSW5mb3JtYXRpb24gYWJvdXQgRENBcwoKIyBkZl9kY2FzID0gcmVhZC5jc3YyKHBhcmFtcyRmaWxlX2RjYSwKIyAgICAgICAgICAgICAgICAgICBoZWFkZXI9VFJVRSwKIyAgICAgICAgICAgICAgICAgICBzZXA9Ilx0IiwKIyAgICAgICAgICAgICAgICAgICBkZWM9Ii4iLAojICAgICAgICAgICAgICAgICAgIGNvbW1lbnQuY2hhcj0iIiwKIyAgICAgICAgICAgICAgICAgICBxdW90ZT0iIiwKIyAgICAgICAgICAgICAgICAgICBzdHJpcC53aGl0ZT1UUlVFLAojICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UpCiMgCiMgIyBzYW5pdGl6ZQojIGRmX2RjYXMkdGltZW91dHMuY2xhc3NpY2FsW2lzLm5hKGRmX2RjYXMkdGltZW91dHMuY2xhc3NpY2FsKV0gPC0gMAoKI2RmX2RjYXMKYGBgCgpgYGB7cn0KI3Rtcy5jbGFzc2ljYWwgPC0gZGZfZGNhc1tkZl9kY2FzJHRpbWVvdXRzLmNsYXNzaWNhbCA9PSAxLF0KYGBgCgoKCmBgYHtyfQojY29tcHV0ZV90aW1lb3V0cyA8LSBmdW5jdGlvbihkZiwgY29sKSB7CiMgIHRtcCA8LSBkZltkZlssIGNvbF0gPT0gVElNRU9VVF9WQUwsXQojICB0bXAKI30KCmBgYAoK