#=========================================================
Warning messages:
1: In readChar(file, size, TRUE) : truncating string with embedded nuls
2: In readChar(file, size, TRUE) : truncating string with embedded nuls
3: In readChar(file, size, TRUE) : truncating string with embedded nuls
4: In readChar(file, size, TRUE) : truncating string with embedded nuls
5: In readChar(file, size, TRUE) : truncating string with embedded nuls
6: In readChar(file, size, TRUE) : truncating string with embedded nuls
7: In readChar(file, size, TRUE) : truncating string with embedded nuls
8: In readChar(file, size, TRUE) : truncating string with embedded nuls
9: In readChar(file, size, TRUE) : truncating string with embedded nuls
# 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
# 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 2466 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),]
# 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
# 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-12-05-2020/table-ALL-ondra-processed.csv |
|
| Timeout |
600 s |
|
| TIMEOUT_VAL |
630 s |
|
| TIME_MIN |
0.1 |
|
| original size |
4397 |
|
| Benchmarks |
1866 |
|
| Timeouts CA |
0 |
|
| Timeouts RE2 |
0 |
|
| Timeouts SRM |
10 |
|
| Timeouts grep |
52 |
|
| Timeouts .NET |
7 |
|
| Errors CA |
0 |
|
| Errors RE2 |
48 |
(removed) |
| Errors SRM |
0 |
|
| Errors grep |
51 |
|
| 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 |
18 |
(removed) |
| grep and RE2 mismatched |
295 |
|
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 |
72 |
| RE2 |
1392 |
| SRM |
19 |
| .NET |
45 |
| grep |
833 |
| RE2 |
171 / 1866 |
| SRM |
266 / 1866 |
| .NET |
619 / 1866 |
| grep |
668 / 1581 |
| RE2 |
63 / 1866 |
| SRM |
127 / 1866 |
| .NET |
112 / 1866 |
| grep |
200 / 1581 |
| RE2 |
15 / 1866 |
| SRM |
82 / 1866 |
| .NET |
18 / 1866 |
| grep |
67 / 1581 |
| CA |
20 |
| RE2 |
63 |
| SRM |
127 |
| .NET |
132 |
| grep |
215 |
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")
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
#}
LS0tCnRpdGxlOiAiQ250LVNldC1NYXRhIEFuYWx5c2lzIgpwYXJhbXM6CiAgI2ZpbGVfY21wOiBkYXRhL3Jlc3VsdHMtMjMtMDQtMjAyMC5jc3YKICAjZmlsZV9jbXA6IHJlc3VsdHMtMDUtMDUtMjAyMC9iZXR3ZWVuL3Jlc3VsdHMuY3N2CiAgI2ZpbGVfY21wOiByZXN1bHRzLTA5LTA1LTIwMjAvYmV0d2Vlbi9SRVNVTFRTLUFMTC1iZXR3ZWVuLmNzdgogICNmaWxlX2NtcDogcmVzdWx0cy0xMC0wNS0yMDIwL3RhYmxlLUFMTC5jc3YKICAjZmlsZV9jbXA6IHJlc3VsdHMtMTEtMDUtMjAyMC90YWJsZS1BTEwtb25kcmEtcHJvY2Vzc2VkLmNzdgogIGZpbGVfY21wOiByZXN1bHRzLTEyLTA1LTIwMjAvdGFibGUtQUxMLW9uZHJhLXByb2Nlc3NlZC5jc3YKICAjZmlsZV9iaWc6IHJlc3VsdHMtMDUtMDUtMjAyMC90YWJsZS1iaWctMjUwMzYxMDIuY3N2CiAgZmlsZV9iaWc6IHJlc3VsdHMtMTEtMDUtMjAyMC9ncmFwaC90YWJsZS1iaWctMTA2NTI4OTcwNC5jc3YKICBmaWxlX2RjYTogRENBcy9yZXN1bHRzLXRyYW5zbGF0aW9uLnRzdgogIHRpbWVvdXQ6IDYwMCAjIHNlY29uZHMKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQKICBodG1sX2RvY3VtZW50OgogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQotLS0KCmBgYHtyfQojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgUFJFQU1CTEUKIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQoKIyBsb2FkIHRoZSBwbG90dGluZyBsaWJyYXJ5CnN1cHByZXNzTWVzc2FnZXMobGlicmFyeShnZ3Bsb3QyKSkKbGlicmFyeShncmlkRXh0cmEpCmxpYnJhcnkoZ2dFeHRyYSkKbGlicmFyeSh0aWt6RGV2aWNlKQpsaWJyYXJ5KEhtaXNjKQpsaWJyYXJ5KHBhc3RlY3MpCgoKCnRoZW1lX3NldCh0aGVtZV9idygpKQoKb3B0aW9ucyhzY2lwZW49OTk5KSAgIyB0dXJuLW9mZiBzY2llbnRpZmljIG5vdGF0aW9uIGxpa2UgMWUrNDgKCiMgc2l6ZSBvZiBwb2ludCBmb3Igc2NhdHRlcnBsb3RzClBPSU5UX1NJWkUgPSAwLjEKI1BPSU5UX1NJWkUgPSAxCgojIHRpbWVvdXQKVElNRU9VVCA9IHBhcmFtcyR0aW1lb3V0ClRJTUVPVVRfVkFMID0gMS4wNSAqIFRJTUVPVVQKCiMgc2F0dXJhdGUKI1RJTUVfTUlOID0gMC4wMSAjIHNlY29uZHMKVElNRV9NSU4gPSAwLjEgIyBzZWNvbmRzCgpCSUdfU0laRT0zClNNQUxMX1NJWkU9MgoKCiMgRlVOQ1RJT05TCnJlYWRfZmlsZSA8LSBmdW5jdGlvbihmaWxlKSB7CiAgZmlsZW5hbWUgPSBwYXN0ZTAoZmlsZSkKICBkZiA8LSByZWFkLmNzdjIoZmlsZW5hbWUsCiAgICAgICAgICAgICAgICAgIGhlYWRlcj1UUlVFLAogICAgICAgICAgICAgICAgICBzZXA9IjsiLAogICAgICAgICAgICAgICAgICBkZWM9IiwiLAogICAgICAgICAgICAgICAgICBjb21tZW50LmNoYXI9IiIsCiAgICAgICAgICAgICAgICAgIHF1b3RlPSJcIiIsCiAgICAgICAgICAgICAgICAgIHN0cmlwLndoaXRlPVRSVUUsCiAgICAgICAgICAgICAgICAgIGFsbG93RXNjYXBlcz1GQUxTRSwKICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycz1GQUxTRSkKICAKICAKICByZXR1cm4oZGYpCn0KCnBsb3Rfc2NhdHRlcl9sb2cgPC0gZnVuY3Rpb24oZGYsIHhsYWIsIHlsYWIsIHhzdHJpbmc9eGxhYiwgeXN0cmluZz15bGFiKSB7CiAgcHNjYXQgPC0gZ2dwbG90KGRmLCBhZXNfc3RyaW5nKHg9eGxhYiwgeT15bGFiKSkgKwogICAgZ2VvbV9wb2ludChzaXplPVBPSU5UX1NJWkUpICsKICAgIGdlb21fYWJsaW5lKHNpemU9MC4xKSArCiAgICBnZW9tX3ZsaW5lKHNpemU9MC4xLCB4aW50ZXJjZXB0PVRJTUVPVVRfVkFMLCBsaW5ldHlwZT0iZGFzaGVkIikgKwogICAgZ2VvbV9obGluZShzaXplPTAuMSwgeWludGVyY2VwdD1USU1FT1VUX1ZBTCwgbGluZXR5cGU9ImRhc2hlZCIpICsKICAgIGdlb21fcnVnKGFscGhhID0gMC4yKSArCiAgICBzY2FsZV94X2xvZzEwKCkgKwogICAgc2NhbGVfeV9sb2cxMCgpICsKICAgIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMC41KSkgKwogICAgI2Nvb3JkX2ZpeGVkKHhsaW0gPSBjKFRJTUVfTUlOLCBUSU1FT1VUX1ZBTCksIHlsaW0gPSBjKDAuMSwgVElNRU9VVF9WQUwpKSArCiAgICAjY29vcmRfZml4ZWQoeGxpbSA9IGMoVElNRV9NSU4sIFRJTUVPVVRfVkFMKSwgeWxpbSA9IGMoVElNRV9NSU4sIFRJTUVPVVRfVkFMKSkgKwogICAgICAgIGNvb3JkX2ZpeGVkKHhsaW0gPSBjKFRJTUVfTUlOLCBUSU1FT1VUX1ZBTCksIHlsaW0gPSBjKFRJTUVfTUlOLCBUSU1FT1VUX1ZBTCkpICsKICAgIGxhYnMoCiAgICAgICN0aXRsZT0iVGl0bGUiLAogICAgICAjc3VidGl0bGU9IlN1YnRpdGxlIiwKICAgICAgeD14c3RyaW5nLAogICAgICB5PXlzdHJpbmcpCiMgICAgdGhlbWUoCiMgICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksIAojICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAojICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLGNvbG91ciA9IE5BKSwKIyAgICAgICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLGNvbG91ciA9IE5BKQojICAgICAgICApCiMgIHRoZW1lX21pbmltYWwoKQojICB0aGVtZV9idygpCiAjIHRoZW1lKHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gTkEpKQogIyBwc2NhdCA8LSBnZ01hcmdpbmFsKHBzY2F0LCB0eXBlID0gImRlbnNpdHkiLCBzaXplPTEwKQojICBwc2NhdCA8LSBwc2NhdCArIHRoZW1lX2J3KCkKICByZXR1cm4ocHNjYXQpCn0KCm1ha2VfdGlreiA8LSBmdW5jdGlvbihmaWxlLCBwaWN0dXJlLCB3aWR0aD0yLjUsIGhlaWdodD0yLjUpIHsKICBmb250X3NpemUgPC0gMQogIHRpa3ooZmlsZT1maWxlLCBvbmVmaWxlPVQsIHdpZHRoPXdpZHRoLCBoZWlnaHQ9aGVpZ2h0KQogIHBsb3QocGljdHVyZSkKICBnYXJiYWdlIDwtIGRldi5vZmYoKQp9CgptYWtlX3BkZiA8LSBmdW5jdGlvbihmaWxlLCBwaWN0dXJlLCB3aWR0aD01LCBoZWlnaHQ9NSkgewogIHBkZihmaWxlPWZpbGUsIG9uZWZpbGU9VCwgd2lkdGgsIGhlaWdodCkKICBwbG90KHBpY3R1cmUpCiAgZ2FyYmFnZSA8LSBkZXYub2ZmKCkKfQpgYGAKCmBgYHtyfQpkZiA8LSByZWFkX2ZpbGUocGFyYW1zJGZpbGVfY21wKQpvcmlnX3NpemUgPC0gbnJvdyhkZikKCmNvbG5hbWVzKGRmKVtjb2xuYW1lcyhkZikgPT0gImRvdC5uZXQiXSA8LSAiZG90bmV0Igpjb2xuYW1lcyhkZilbbmFtZXMoZGYpID09ICJkb3QubmV0Lm1hdGNoZXMiXSA8LSAiZG90bmV0Lm1hdGNoZXMiCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIFNBTklUSVpFICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBjbGVhbiB0aGUgZGF0YQpkZl9uZXcgPC0gZGZbIWdyZXBsKCJGaWxlIG5vdCBmb3VuZCIsIGRmJHNybS5tYXRjaGVzKSxdCnByaW50KHBhc3RlMCgiUmVtb3ZpbmcgIiwgbnJvdyhkZikgLSBucm93KGRmX25ldyksICIgbGluZXMgZHVlIHRvIGdlbmVyYXRpb24gb2YgaW5wdXQgdGV4dCIpKQpkZiA8LSBkZl9uZXcKCnRvb2xzLnRpbWVzIDwtIGMoInJlMmciLCAiY2FkIiwgImdyZXAiLCAic3JtIiwgImRvdG5ldCIpCiN0b29scy50aW1lcyA8LSBjKCJyZTJnIiwgImNhZCIsICJzcm0iLCAiZG90bmV0IikKdG9vbHMubWF0Y2hlcyA8LSBjKCJyZTJnLm1hdGNoZXMiLCAiY2FkLm1hdGNoZXMiLCAiZ3JlcC5tYXRjaGVzIiwgInNybS5tYXRjaGVzIiwgImRvdG5ldC5tYXRjaGVzIikKI3Rvb2xzLm1hdGNoZXMgPC0gYygicmUyZy5tYXRjaGVzIiwgImNhZC5tYXRjaGVzIiwgInNybS5tYXRjaGVzIiwgImRvdG5ldC5tYXRjaGVzIikKCiMgY2hlY2tpbmcgZXJyb3JzCmVycm9ycy5yZTJnIDwtIG5yb3coZGZbZ3JlcGwoJ0VSUicsIGRmJHJlMmcpLF0pCmVycm9ycy5ncmVwIDwtIG5yb3coZGZbZ3JlcGwoJ0VSUicsIGRmJGdyZXApLF0pCmVycm9ycy5zcm0gPC0gbnJvdyhkZltncmVwbCgnRVJSJywgZGYkc3JtKSxdKQplcnJvcnMuY2FkIDwtIG5yb3coZGZbZ3JlcGwoJ0VSUicsIGRmJGNhZCksXSkKZXJyb3JzLmRvdG5ldCA8LSBucm93KGRmW2dyZXBsKCdFUlInLCBkZiRkb3RuZXQpLF0pCgpkZiA8LSBkZlshZ3JlcGwoJ0VSUicsIGRmJHJlMmcpLF0KCgojIGNoYW5nZSB0aGUgdHlwZSBvZiBjb2x1bW5zIG90aGVyIHRoYW4gdGhlIG5hbWUKZm9yIChpIGluIHRvb2xzLnRpbWVzKSB7CiAgZGZbLGldIDwtIHN1YigiLCIsICIuIiwgZGZbLGldKQogIHN1cHByZXNzV2FybmluZ3MoZGZbLGldIDwtIGFzLm51bWVyaWMoZGZbLGldKSkKfQoKZm9yIChpIGluIHRvb2xzLm1hdGNoZXMpIHsKICBzdXBwcmVzc1dhcm5pbmdzKGRmWyxpXSA8LSBhcy5pbnRlZ2VyKGRmWyxpXSkpCn0KCmRmJHNyYyA8LSBhcy5mYWN0b3IoZGYkc3JjKQoKIyBnZXQgcmlkIG9mIGV4dHJlbWFsIHZhbHVlcwpkZlssdG9vbHMudGltZXNdW2RmWyx0b29scy50aW1lc10gPiBUSU1FT1VUXSA8LSBUSU1FT1VUX1ZBTApkZlt0b29scy50aW1lc11baXMubmEoZGZbdG9vbHMudGltZXNdKV0gPC0gVElNRU9VVF9WQUwKI2RmW2lzLm5hKGRmKV0gPC0gVElNRU9VVF9WQUwKI2RmW2RmID09IDAuMDBdIDwtIFRJTUVfTUlOCmRmWyx0b29scy50aW1lc11bZGZbLHRvb2xzLnRpbWVzXSA8IFRJTUVfTUlOXSA8LSBUSU1FX01JTgoKCgojIGNsZWFuIHRoZSBkYXRhCiNkZl9uZXcgPC0gZGZbZGYkTGluZXMgIT0gIkVSUk9SIFdISUxFIENPTlZFUlRJTkcgVE8gRENBLiIsXQojcHJpbnQocGFzdGUwKCJSZW1vdmluZyAiLCBucm93KGRmKSAtIG5yb3coZGZfbmV3KSwgIiBsaW5lcyBkdWUgdG8gY29udmVydGluZyB0byBEQ0EgZXJyb3IiKSkKI2RmIDwtIGRmX25ldwoKCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMgQ09VTlRJTkcgVElNRU9VVFMgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKdGltZW91dHMucmUyZyA8LSBucm93KGRmW2RmJHJlMmcgPT0gVElNRU9VVF9WQUwsXSkKdGltZW91dHMuY2FkIDwtIG5yb3coZGZbZGYkY2FkID09IFRJTUVPVVRfVkFMLF0pCnRpbWVvdXRzLmdyZXAgPC0gbnJvdyhkZltkZiRncmVwID09IFRJTUVPVVRfVkFMLF0pCnRpbWVvdXRzLnNybSA8LSBucm93KGRmW2RmJHNybSA9PSBUSU1FT1VUX1ZBTCxdKQp0aW1lb3V0cy5kb3RuZXQgPC0gbnJvdyhkZltkZiRkb3RuZXQgPT0gVElNRU9VVF9WQUwsXSkKdGltZW91dHMucmUyLmFuZC5jYSA8LSBucm93KGRmW2RmJGNhZCA9PSBUSU1FT1VUX1ZBTCAmIGRmJHJlMmcgPT0gVElNRU9VVF9WQUwsXSkKCiMgfCAqKlRpbWVvdXRzIGdyZXAqKiAgICB8IGByIHRpbWVvdXRzLmdyZXBgICB8CmBgYAoKVGhlc2UgYXJlIHJlc3VsdHMgb2YgdGhlIGV4cGVyaW1lbnRzIGZvciBDb3VudGluZyBTZXQgQXV0b21hdGE6Cgp8ICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwgfAp8LS0tLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tOnwtfAp8ICoqRmlsZSoqICAgICAgICAgICAgfCBgciBwYXJhbXMkZmlsZV9jbXBgIHwKfCAqKlRpbWVvdXQqKiAgICAgICAgIHwgYHIgVElNRU9VVGAgcyAgICAgICB8CnwgKipUSU1FT1VUX1ZBTCoqICAgICB8IGByIFRJTUVPVVRfVkFMYCBzICAgfAp8ICoqVElNRV9NSU4qKiAgICAgICAgfCBgciBUSU1FX01JTmAgICAgICAgIHwKfCAqKm9yaWdpbmFsIHNpemUqKiAgIHwgYHIgb3JpZ19zaXplYCAgICAgICB8CnwgKipCZW5jaG1hcmtzKiogICAgICB8IGByIG5yb3coZGYpYCAgICAgICAgfAp8ICoqVGltZW91dHMgQ0EqKiAgICAgfCBgciB0aW1lb3V0cy5jYWRgICAgICB8CnwgKipUaW1lb3V0cyBSRTIqKiAgICB8IGByIHRpbWVvdXRzLnJlMmdgICAgIHwKfCAqKlRpbWVvdXRzIFNSTSoqICAgIHwgYHIgdGltZW91dHMuc3JtYCAgICB8IAp8ICoqVGltZW91dHMgZ3JlcCoqICAgfCBgciB0aW1lb3V0cy5ncmVwYCAgICB8IAp8ICoqVGltZW91dHMgLk5FVCoqICAgfCBgciB0aW1lb3V0cy5kb3RuZXRgICB8CnwgKipFcnJvcnMgQ0EqKiAgICAgfCBgciBlcnJvcnMuY2FkYCAgICAgfAp8ICoqRXJyb3JzIFJFMioqICAgIHwgYHIgZXJyb3JzLnJlMmdgICAgIHwgKHJlbW92ZWQpIHwKfCAqKkVycm9ycyBTUk0qKiAgICB8IGByIGVycm9ycy5zcm1gICAgIHwgCnwgKipFcnJvcnMgZ3JlcCoqICAgfCBgciBlcnJvcnMuZ3JlcGAgICAgfCAKfCAqKkVycm9ycyAuTkVUKiogICB8IGByIGVycm9ycy5kb3RuZXRgICB8CgoKCmBgYHtyfQpkZgpgYGAKCiMgU3VtbWFyeSBvZiBiZW5jaG1hcmtzCgpgYGB7cn0KZGZfYmVuY2hlcyA8LSBkYXRhLmZyYW1lKHN1bW1hcnkoZGYkc3JjKSkKZGZfYmVuY2hlcwpgYGAKCiMgU2FuaXR5IGNoZWNrcwoKYGBge3J9CmRmJGluY29uc2lzdGVudCA8LSBkZiRyZTJnLm1hdGNoZXMgIT0gZGYkZ3JlcC5tYXRjaGVzIHwgZGYkcmUyZy5tYXRjaGVzICE9IGRmJHNybS5tYXRjaGVzIHwgZGYkcmUyZy5tYXRjaGVzICE9IGRmJGRvdG5ldC5tYXRjaGVzIHwgZGYkcmUyZy5tYXRjaGVzICE9IGRmJGNhZC5tYXRjaGVzCgojZGYkaW5jb25zaXN0ZW50IDwtIGRmJHJlMmcubWF0Y2hlcyAhPSBkZiRzcm0ubWF0Y2hlcyB8IGRmJHJlMmcubWF0Y2hlcyAhPSBkZiRkb3RuZXQubWF0Y2hlcyB8IGRmJHJlMmcubWF0Y2hlcyAhPSBkZiRjYWQubWF0Y2hlcwoKZGYkZ3JlcC5yZTIubWlzbWF0Y2ggPC0gIWlzLm5hKGRmJHJlMmcubWF0Y2hlcykgJiAhaXMubmEoZGYkZ3JlcC5tYXRjaGVzKSAmIGRmJHJlMmcubWF0Y2hlcyAhPSBkZiRncmVwLm1hdGNoZXMKZGZfZ3JlcF9yZTJfbWlzbWF0Y2ggPC0gZGZbZGYkZ3JlcC5yZTIubWlzbWF0Y2gsXQoKZGYkcmUyLmNhLm1pc21hdGNoIDwtICFpcy5uYShkZiRyZTJnLm1hdGNoZXMpICYgIWlzLm5hKGRmJGNhZC5tYXRjaGVzKSAmIGRmJHJlMmcubWF0Y2hlcyAhPSBkZiRjYWQubWF0Y2hlcwpkZl9yZTJfY2FfbWlzbWF0Y2ggPC0gZGZbZGYkcmUyLmNhLm1pc21hdGNoLF0KCmRmIDwtIGRmW2lzLm5hKGRmJHJlMmcubWF0Y2hlcykgfCBpcy5uYShkZiRncmVwLm1hdGNoZXMpIHwgZGYkcmUyZy5tYXRjaGVzID09IGRmJGNhZC5tYXRjaGVzLF0KCmBgYAoKfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgIHwKfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS06fCAtLS0tLS0tOnwKfCAqKkNBIGFuZCBSRTIgbWlzbWF0Y2hlZCoqICAgfCBgciBucm93KGRmX3JlMl9jYV9taXNtYXRjaClgICAgfCAocmVtb3ZlZCkgfAp8ICoqZ3JlcCBhbmQgUkUyIG1pc21hdGNoZWQqKiB8IGByIG5yb3coZGZfZ3JlcF9yZTJfbWlzbWF0Y2gpYCB8CgoKIyMgUkUyIGFuZCBDQSBtaXNtYXRjaGVzCmBgYHtyfQpkZl9yZTJfY2FfbWlzbWF0Y2gKYGBgCgoKCiMgU2NhdHRlciBQbG90cwoKYGBge3J9CgpwbG90LmFuZC50aWt6IDwtIGZ1bmN0aW9uKGRmLCB4bGFiLCB5bGFiLCB4c3RyaW5nPXhsYWIsIHlzdHJpbmc9eWxhYiwgd2lkdGg9NCwgaGVpZ2h0PXdpZHRoKSB7CiAgcGljIDwtIHBsb3Rfc2NhdHRlcl9sb2coZGYsIHhsYWIsIHlsYWIsIHhzdHJpbmcsIHlzdHJpbmcpCiAgI21ha2VfdGlreihwYXN0ZTAoImZpZ3MvIiwgeGxhYiwgIi12cy0iLCB5bGFiLCAiLnRpa3oiKSwgcGljLCB3aWR0aCwgaGVpZ2h0KQogIG1ha2VfcGRmKHBhc3RlMCgiZmlncy8iLCB4bGFiLCAiLXZzLSIsIHlsYWIsICIucGRmIiksIHBpYywgd2lkdGgsIGhlaWdodCkKICBwaWMKfQoKZGZfZ3JlcCA8LSBkZltpcy5uYShkZiRncmVwLm1hdGNoZXMpIHwgaXMubmEoZGYkY2FkLm1hdGNoZXMpIHwgZGYkZ3JlcC5tYXRjaGVzID09IGRmJGNhZC5tYXRjaGVzLF0KCnBsb3QxIDwtIHBsb3QuYW5kLnRpa3ooZGYsICJyZTJnIiwgImNhZCIsIHhzdHJpbmc9IlJFMiBbc10iLCB5c3RyaW5nPSJDQSBbc10iLCB3aWR0aD1CSUdfU0laRSkKcGxvdDIgPC0gcGxvdC5hbmQudGlreihkZl9ncmVwLCAiZ3JlcCIsICJjYWQiLCB4c3RyaW5nPSJncmVwIFtzXSIsIHlzdHJpbmc9IkNBIFtzXSIsIHdpZHRoPVNNQUxMX1NJWkUpCnBsb3QzIDwtIHBsb3QuYW5kLnRpa3ooZGYsICJzcm0iLCAiY2FkIiwgeHN0cmluZz0iU1JNIFtzXSIsIHlzdHJpbmc9IkNBIFtzXSIsIHdpZHRoPVNNQUxMX1NJWkUpCnBsb3Q0IDwtIHBsb3QuYW5kLnRpa3ooZGYsICJkb3RuZXQiLCAiY2FkIiwgeHN0cmluZz0iLk5FVCBbc10iLCB5c3RyaW5nPSJDQSBbc10iLCB3aWR0aD1TTUFMTF9TSVpFKQpwbG90NSA8LSBwbG90LmFuZC50aWt6KGRmLCAic3JtIiwgInJlMmciKQpwbG90NiA8LSBwbG90LmFuZC50aWt6KGRmLCAiZ3JlcCIsICJyZTJnIikKcGxvdDcgPC0gcGxvdC5hbmQudGlreihkZiwgImRvdG5ldCIsICJyZTJnIikKcGxvdDggPC0gcGxvdC5hbmQudGlreihkZiwgInNybSIsICJncmVwIikKcGxvdDkgPC0gcGxvdC5hbmQudGlreihkZiwgImRvdG5ldCIsICJncmVwIikKcGxvdDEwIDwtIHBsb3QuYW5kLnRpa3ooZGYsICJkb3RuZXQiLCAic3JtIikKCgoKI2dyaWQuYXJyYW5nZShwbG90MSwgcGxvdDMsIG5jb2wgPSAyKQojZ3JpZC5hcnJhbmdlKHBsb3Q0LCBwbG90NSwgbmNvbCA9IDIpCiNncmlkLmFycmFuZ2UocGxvdDcsIHBsb3QxMCwgbmNvbCA9IDIpCgpncmlkLmFycmFuZ2UocGxvdDEsIHBsb3QyLCBuY29sID0gMikKZ3JpZC5hcnJhbmdlKHBsb3QzLCBwbG90NCwgbmNvbCA9IDIpCmdyaWQuYXJyYW5nZShwbG90NSwgcGxvdDYsIG5jb2wgPSAyKQpncmlkLmFycmFuZ2UocGxvdDcsIHBsb3Q4LCBuY29sID0gMikKZ3JpZC5hcnJhbmdlKHBsb3Q5LCBwbG90MTAsIG5jb2wgPSAyKQoKYGBgCgojIEhpc3RvZ3JhbXMKCmBgYHtyfQpoaXN0MSA8LSBnZ3Bsb3QoZGYsIGFlcyh4PXJlMmcpKSArCiAgZ2VvbV9oaXN0b2dyYW0oY29sb3I9ImJsdWUiLCBmaWxsPSJsaWdodGJsdWUiKSArCiAgc2NhbGVfeV9sb2cxMCgpCgpoaXN0MiA8LSBnZ3Bsb3QoZGYsIGFlcyh4PWNhZCkpICsgCiAgZ2VvbV9oaXN0b2dyYW0oY29sb3I9ImJsdWUiLCBmaWxsPSJsaWdodGJsdWUiKSArCiAgc2NhbGVfeV9sb2cxMCgpCgpoaXN0MyA8LSBnZ3Bsb3QoZGYsIGFlcyh4PXNybSkpICsgCiAgZ2VvbV9oaXN0b2dyYW0oY29sb3I9ImJsdWUiLCBmaWxsPSJsaWdodGJsdWUiKSArCiAgc2NhbGVfeV9sb2cxMCgpCgojaGlzdDQgPC0gZ2dwbG90KGRmLCBhZXMoeD1ncmVwKSkgKyAKIyAgZ2VvbV9oaXN0b2dyYW0oY29sb3I9ImJsdWUiLCBmaWxsPSJsaWdodGJsdWUiKSArCiMgIHNjYWxlX3lfbG9nMTAoKQoKaGlzdDUgPC0gZ2dwbG90KGRmLCBhZXMoeD1kb3RuZXQpKSArIAogIGdlb21faGlzdG9ncmFtKGNvbG9yPSJibHVlIiwgZmlsbD0ibGlnaHRibHVlIikgKwogIHNjYWxlX3lfbG9nMTAoKQoKZ3JpZC5hcnJhbmdlKGhpc3QxLCBoaXN0MiwgbmNvbCA9IDIpCmdyaWQuYXJyYW5nZShoaXN0MywgaGlzdDUsIG5jb2wgPSAyKQojZ3JpZC5hcnJhbmdlKGhpc3Q1LCBuY29sID0gMikKCgpgYGAKCiMgRmluZGluZyB3aW5uZXJzCgpgYGB7cn0KZGYkbWluIDwtcG1pbihkZiRncmVwLCBkZiRzcm0sIGRmJHJlMmcsIGRmJGRvdG5ldCwgZGYkY2FkKQpkZiRlbmVteS5taW4gPC0gcG1pbihkZiRncmVwLCBkZiRzcm0sIGRmJHJlMmcsIGRmJGRvdG5ldCkKI2RmJG1pbiA8LXBtaW4oZGYkc3JtLCBkZiRyZTJnLCBkZiRkb3RuZXQsIGRmJGNhZCkKI2RmJGVuZW15Lm1pbiA8LSBwbWluKGRmJHNybSwgZGYkcmUyZywgZGYkZG90bmV0KQoKd2lubmVycy5ncmVwIDwtIG5yb3coZGZbZGYkbWluID09IGRmJGdyZXAsXSkKd2lubmVycy5yZTIgPC0gbnJvdyhkZltkZiRtaW4gPT0gZGYkcmUyZyxdKQp3aW5uZXJzLmNhIDwtIG5yb3coZGZbZGYkbWluID09IGRmJGNhZCxdKQp3aW5uZXJzLnNybSA8LSBucm93KGRmW2RmJG1pbiA9PSBkZiRzcm0sXSkKd2lubmVycy5kb3RuZXQgPC0gbnJvdyhkZltkZiRtaW4gPT0gZGYkZG90bmV0LF0pCgp3aW5uZXJzLmNhLm92ZXIucmUyIDwtIG5yb3coZGZbZGYkY2FkIDw9IGRmJHJlMmcsXSkKd2lubmVycy5jYS5vdmVyLmdyZXAgPC0gbnJvdyhkZltkZl9ncmVwJGNhZCA8PSBkZl9ncmVwJGdyZXAsXSkKd2lubmVycy5jYS5vdmVyLnNybSA8LSBucm93KGRmW2RmJGNhZCA8PSBkZiRzcm0sXSkKd2lubmVycy5jYS5vdmVyLmRvdG5ldCA8LSBucm93KGRmW2RmJGNhZCA8PSBkZiRkb3RuZXQsXSkKCndpbm5lcnMuMTAuY2Eub3Zlci5yZTIgPC0gbnJvdyhkZlsxMCogZGYkY2FkIDw9IGRmJHJlMmcsXSkKd2lubmVycy4xMC5jYS5vdmVyLmdyZXAgPC0gbnJvdyhkZlsxMCogZGZfZ3JlcCRjYWQgPD0gZGZfZ3JlcCRncmVwLF0pCndpbm5lcnMuMTAuY2Eub3Zlci5zcm0gPC0gbnJvdyhkZlsxMCogZGYkY2FkIDw9IGRmJHNybSxdKQp3aW5uZXJzLjEwLmNhLm92ZXIuZG90bmV0IDwtIG5yb3coZGZbMTAqIGRmJGNhZCA8PSBkZiRkb3RuZXQsXSkKCndpbm5lcnMuMTAwLmNhLm92ZXIucmUyIDwtIG5yb3coZGZbMTAwKiBkZiRjYWQgPD0gZGYkcmUyZyxdKQp3aW5uZXJzLjEwMC5jYS5vdmVyLmdyZXAgPC0gbnJvdyhkZlsxMDAqIGRmX2dyZXAkY2FkIDw9IGRmX2dyZXAkZ3JlcCxdKQp3aW5uZXJzLjEwMC5jYS5vdmVyLnNybSA8LSBucm93KGRmWzEwMCogZGYkY2FkIDw9IGRmJHNybSxdKQp3aW5uZXJzLjEwMC5jYS5vdmVyLmRvdG5ldCA8LSBucm93KGRmWzEwMCogZGYkY2FkIDw9IGRmJGRvdG5ldCxdKQoKbG9uZ2VyLnRoYW4uMTAuc2Vjb25kcy5jYSA8LSBucm93KGRmW2RmJGNhZCA+IDEwLF0pCmxvbmdlci50aGFuLjEwLnNlY29uZHMucmUyIDwtIG5yb3coZGZbZGYkcmUyZyA+IDEwLF0pCmxvbmdlci50aGFuLjEwLnNlY29uZHMuc3JtIDwtIG5yb3coZGZbZGYkc3JtID4gMTAsXSkKbG9uZ2VyLnRoYW4uMTAuc2Vjb25kcy5kb3RuZXQgPC0gbnJvdyhkZltkZiRkb3RuZXQgPiAxMCxdKQpsb25nZXIudGhhbi4xMC5zZWNvbmRzLmdyZXAgPC0gbnJvdyhkZltkZiRncmVwID4gMTAsXSkKCgpgYGAKCnwgKipXaW5uZXIqKiAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfAp8LS0tLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tOnwKfCAqKkNBKiogICAgIHwgYHIgd2lubmVycy5jYWAgICAgIHwKfCAqKlJFMioqICAgIHwgYHIgd2lubmVycy5yZTJgICAgIHwKfCAqKlNSTSoqICAgIHwgYHIgd2lubmVycy5zcm1gICAgIHwgCnwgKiouTkVUKiogICAgfCBgciB3aW5uZXJzLmRvdG5ldGAgIHwKfCAqKmdyZXAqKiAgICB8IGByIHdpbm5lcnMuZ3JlcGAgIHwKCnwgKipXaW5zIG9mIENBIG92ZXIqKiAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfAp8LS0tLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tOnwKfCAqKlJFMioqICAgIHwgYHIgd2lubmVycy5jYS5vdmVyLnJlMmAgLyBgciBucm93KGRmKWAgICB8CnwgKipTUk0qKiAgICB8IGByIHdpbm5lcnMuY2Eub3Zlci5zcm1gIC8gYHIgbnJvdyhkZilgICAgIHwgCnwgKiouTkVUKiogICAgfCBgciB3aW5uZXJzLmNhLm92ZXIuZG90bmV0YCAvIGByIG5yb3coZGYpYCAgfAp8ICoqZ3JlcCoqICAgIHwgYHIgd2lubmVycy5jYS5vdmVyLmdyZXBgIC8gYHIgbnJvdyhkZl9ncmVwKWAgIHwKCnwgKipXaW5zIG9mIGF0IGxlYXN0IDEwIHRpbWVzIG9mIENBIG92ZXIqKiAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfAp8LS0tLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tOnwKfCAqKlJFMioqICAgIHwgYHIgd2lubmVycy4xMC5jYS5vdmVyLnJlMmAgLyBgciBucm93KGRmKWAgICB8CnwgKipTUk0qKiAgICB8IGByIHdpbm5lcnMuMTAuY2Eub3Zlci5zcm1gIC8gYHIgbnJvdyhkZilgICAgIHwgCnwgKiouTkVUKiogICAgfCBgciB3aW5uZXJzLjEwLmNhLm92ZXIuZG90bmV0YCAvIGByIG5yb3coZGYpYCAgfAp8ICoqZ3JlcCoqICAgIHwgYHIgd2lubmVycy4xMC5jYS5vdmVyLmdyZXBgIC8gYHIgbnJvdyhkZl9ncmVwKWAgIHwKCnwgKipXaW5zIG9mIGF0IGxlYXN0IDEwMCB0aW1lcyBvZiBDQSBvdmVyKiogICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwKfC0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLTp8CnwgKipSRTIqKiAgICB8IGByIHdpbm5lcnMuMTAwLmNhLm92ZXIucmUyYCAvIGByIG5yb3coZGYpYCAgIHwKfCAqKlNSTSoqICAgIHwgYHIgd2lubmVycy4xMDAuY2Eub3Zlci5zcm1gIC8gYHIgbnJvdyhkZilgICAgIHwgCnwgKiouTkVUKiogICAgfCBgciB3aW5uZXJzLjEwMC5jYS5vdmVyLmRvdG5ldGAgLyBgciBucm93KGRmKWAgIHwKfCAqKmdyZXAqKiAgICB8IGByIHdpbm5lcnMuMTAwLmNhLm92ZXIuZ3JlcGAgLyBgciBucm93KGRmX2dyZXApYCAgfAoKfCAqKkxvbmdlciB0aGFuIDEwIHMqKiAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfAp8LS0tLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tOnwKfCAqKkNBKiogICAgIHwgYHIgbG9uZ2VyLnRoYW4uMTAuc2Vjb25kcy5jYWAgICAgIHwKfCAqKlJFMioqICAgIHwgYHIgbG9uZ2VyLnRoYW4uMTAuc2Vjb25kcy5yZTJgICAgIHwKfCAqKlNSTSoqICAgIHwgYHIgbG9uZ2VyLnRoYW4uMTAuc2Vjb25kcy5zcm1gICAgIHwgCnwgKiouTkVUKiogICAgfCBgciBsb25nZXIudGhhbi4xMC5zZWNvbmRzLmRvdG5ldGAgIHwKfCAqKmdyZXAqKiAgICB8IGByIGxvbmdlci50aGFuLjEwLnNlY29uZHMuZ3JlcGAgIHwKCgoKYGBge3J9CnBsb3QuYW5kLnRpa3ooZGYsICJlbmVteS5taW4iLCAiY2FkIiwgeHN0cmluZz0iYmVzdCBlbmVteSIsIHlzdHJpbmc9IkNBIFtzXSIpCmBgYAoKIyBIb3cgbXVjaCB3ZSBhcmUgYmV0dGVyIHRoYW4gUkUyCgpgYGB7cn0KZGYkcmUyLnZzLmNhIDwtIGRmJHJlMmcgLyBkZiRjYWQKZGZfc29ydGVkIDwtIGRmW29yZGVyKGRmJHJlMi52cy5jYSwgZGVjcmVhc2luZz1UUlVFKSxdCgojZGZfc29ydGVkWyxjKCJzcmMiLCAicGF0dGVybiIsICJmaWxlIiwgInJlMmciLCAiY2FkIiwgInJlMi52cy5jYSIsICJyZTIuY2EubWlzbWF0Y2giKV0KZGZfc29ydGVkIDwtIGRmX3NvcnRlZFsxOjEwLGMoInNyYyIsICJwYXR0ZXJuIiwgImZpbGUiLCB0b29scy50aW1lcyldCmRmX3NvcnRlZApoYWYgPC0gbGF0ZXgoZGZfc29ydGVkLAogICAgICAgICAgICAgZmlsZT0iZmlncy9iZXN0X3Jlc3VsdHMudGV4IiwKICAgICAgICAgICAgIGJvb2t0YWJzPVRSVUUsCiAgICAgICAgICAgICB0YWJsZS5lbnY9RkFMU0UsCiAgICAgICAgICAgICBjZW50ZXI9Im5vbmUiKQoKYGBgCgojIFN1bW1hcmllcwoKYGBge3J9CmRmX2Zvcl9zdW1tYXJ5IDwtIGRmWyxjKCJyZTJnIiwgImNhZCIsICJzcm0iLCAiZG90bmV0IiwgImdyZXAiKV0KI2RmLnN1bW1hcnkgPC0gZG8uY2FsbChjYmluZCwgbGFwcGx5KGRmX2Zvcl9zdW1tYXJ5LCBzdW1tYXJ5KSkKI2RmLnN1bW1hcnkKCmRlc2MgPC0gc3RhdC5kZXNjKGRmX2Zvcl9zdW1tYXJ5KQpkZXNjCmhhZiA8LSBsYXRleChkZXNjLAogICAgICAgICAgICAgZmlsZT0iZmlncy9zdGF0cy50ZXgiLAogICAgICAgICAgICAgYm9va3RhYnM9VFJVRSwKICAgICAgICAgICAgIHRhYmxlLmVudj1GQUxTRSwKICAgICAgICAgICAgIGNlbnRlcj0ibm9uZSIpCgpgYGAKCiMgRXhwZXJpbWVudHMgd2l0aCBpbmNyZWFzaW5nIGNvdW50ZXIgdmFsdWUKCmBgYHtyfQpiaWcgPC0gcmVhZF9maWxlKHBhcmFtcyRmaWxlX2JpZykKYmlnJHJlMmcgPC0gc3ViKCIsIiwgIi4iLCBiaWckcmUyZykKYmlnJHJlMmcgPC0gYXMubnVtZXJpYyhiaWckcmUyZykKCmJpZwpgYGAKCgpgYGB7cn0KCnRvZ2V0aGVyIDwtIGJpZ1ssIGMoIkNvdW50ZXIiLCAicmUyZyIpXQpuYW1lcyh0b2dldGhlcilbMl0gPC0gInRpbWUiCnRvZ2V0aGVyJGFwcHJvYWNoIDwtICJSRTIiCgp0bXAgPC0gYmlnWywgYygiQ291bnRlciIsICJjYWQiKV0KbmFtZXModG1wKVsyXSA8LSAidGltZSIKdG1wJGFwcHJvYWNoIDwtICJDQSIKdG9nZXRoZXIgPC0gcmJpbmQodG9nZXRoZXIsIHRtcCkKCnRtcCA8LSBiaWdbLCBjKCJDb3VudGVyIiwgInNybSIpXQpuYW1lcyh0bXApWzJdIDwtICJ0aW1lIgp0bXAkYXBwcm9hY2ggPC0gIlNSTSIKdG9nZXRoZXIgPC0gcmJpbmQodG9nZXRoZXIsIHRtcCkKCnRtcCA8LSBiaWdbLCBjKCJDb3VudGVyIiwgImRvdC5uZXQiKV0KbmFtZXModG1wKVsyXSA8LSAidGltZSIKdG1wJGFwcHJvYWNoIDwtICIuTkVUIgp0b2dldGhlciA8LSByYmluZCh0b2dldGhlciwgdG1wKQoKdG1wIDwtIGJpZ1ssIGMoIkNvdW50ZXIiLCAiZ3JlcCIpXQpuYW1lcyh0bXApWzJdIDwtICJ0aW1lIgp0bXAkYXBwcm9hY2ggPC0gImdyZXAiCnRvZ2V0aGVyIDwtIHJiaW5kKHRvZ2V0aGVyLCB0bXApCgpCSUdfU1RFUD0xMDAKCiMgcmVtb3ZlIHRvbyBtYW55IHBvaW50cwp0b2dldGhlciA8LSB0b2dldGhlclt0b2dldGhlciRDb3VudGVyICUlIEJJR19TVEVQID09IDAsXQoKYmlnX3Bsb3QgPC0gZ2dwbG90KGRhdGE9dG9nZXRoZXIsIGFlcyh4PUNvdW50ZXIsIHk9dGltZSwgY29sb3VyPWFwcHJvYWNoKSkgKwogIGdlb21fbGluZSgpICsKICBnZW9tX3BvaW50KGFlcyhzaGFwZT1hcHByb2FjaCkpICsKICB4bGltKE5BLDIwMDApICsKICB5bGltKE5BLDIwKSArCiAgZ2VvbV9obGluZShzaXplPTAuMSwgeWludGVyY2VwdD0wLCBsaW5ldHlwZT0iZGFzaGVkIikgKwoKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKC4wMiwgLjk4KSwKICAgICAgICBsZWdlbmQuanVzdGlmaWNhdGlvbiA9IGMoImxlZnQiLCAidG9wIiksCiAgICAgICAgI2xlZ2VuZC5ib3guYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvcj0iYmxhY2siLCBzaXplPTAuNSksCiAgICAgICAgbGVnZW5kLmJveC5qdXN0ID0gInJpZ2h0IiwKICAgICAgICBsZWdlbmQubWFyZ2luID0gbWFyZ2luKDEsIDEsIDEsIDEpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKwogIGxhYnMoCiAgICAgICN0aXRsZT0iVGl0bGUiLAogICAgICAjc3VidGl0bGU9IlN1YnRpdGxlIiwKICAgICAgeD0iayIsCiAgICAgIHk9InRpbWUgW3NdIikKICAgICAgICAKCiAgIyBnZW9tX2xpbmUoZGF0YSA9IGJpZywgYWVzKHggPSBDb3VudGVyLCB5ID0gcmUyZyksIGNvbG9yID0gInJlZCIpICsKICAjIGdlb21fbGluZShkYXRhID0gYmlnLCBhZXMoeCA9IENvdW50ZXIsIHkgPSBjYSksIGNvbG9yID0gImJsdWUiKSArCiAgIyB4bGFiKCdjb3VudGVyIHZhbHVlJykgKwogICMgeWxhYigndGltZSBbc10nKQoKI21ha2VfdGlreihwYXN0ZTAoImZpZ3MvYmlnX3Bsb3QudGlreiIpLCBiaWdfcGxvdCwgd2lkdGg9Mi43LCBoZWlnaHQ9Mi43KQptYWtlX3BkZihwYXN0ZTAoImZpZ3MvYmlnX3Bsb3QucGRmIiksIGJpZ19wbG90LCB3aWR0aD1CSUdfU0laRSwgaGVpZ2h0PUJJR19TSVpFKQoKCnBsb3QoYmlnX3Bsb3QpCmBgYAoKCmBgYHtyfQojIEluZm9ybWF0aW9uIGFib3V0IERDQXMKCiMgZGZfZGNhcyA9IHJlYWQuY3N2MihwYXJhbXMkZmlsZV9kY2EsCiMgICAgICAgICAgICAgICAgICAgaGVhZGVyPVRSVUUsCiMgICAgICAgICAgICAgICAgICAgc2VwPSJcdCIsCiMgICAgICAgICAgICAgICAgICAgZGVjPSIuIiwKIyAgICAgICAgICAgICAgICAgICBjb21tZW50LmNoYXI9IiIsCiMgICAgICAgICAgICAgICAgICAgcXVvdGU9IiIsCiMgICAgICAgICAgICAgICAgICAgc3RyaXAud2hpdGU9VFJVRSwKIyAgICAgICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFKQojIAojICMgc2FuaXRpemUKIyBkZl9kY2FzJHRpbWVvdXRzLmNsYXNzaWNhbFtpcy5uYShkZl9kY2FzJHRpbWVvdXRzLmNsYXNzaWNhbCldIDwtIDAKCiNkZl9kY2FzCmBgYAoKYGBge3J9CiN0bXMuY2xhc3NpY2FsIDwtIGRmX2RjYXNbZGZfZGNhcyR0aW1lb3V0cy5jbGFzc2ljYWwgPT0gMSxdCmBgYAoKCgpgYGB7cn0KI2NvbXB1dGVfdGltZW91dHMgPC0gZnVuY3Rpb24oZGYsIGNvbCkgewojICB0bXAgPC0gZGZbZGZbLCBjb2xdID09IFRJTUVPVVRfVkFMLF0KIyAgdG1wCiN9CgpgYGAKCg==