#=========================================================
There were 18 warnings (use warnings() to see them)
# 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 2687 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-15-05-2020/nogrep/cut/table-ALL-processed.csv |
|
| Timeout |
600 s |
|
| TIMEOUT_VAL |
630 s |
|
| TIME_MIN |
0.1 |
|
| original size |
4403 |
|
| Benchmarks |
1647 |
|
| Timeouts CA |
1 |
|
| Timeouts RE2 |
2 |
|
| Timeouts SRM |
9 |
|
| Timeouts grep |
48 |
|
| Timeouts .NET |
4 |
|
| Errors CA |
0 |
|
| Errors RE2 |
59 |
(removed) |
| Errors SRM |
0 |
|
| Errors grep |
46 |
|
| 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 |
10 |
(removed) |
| grep and RE2 mismatched |
101 |
|
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 |
65 |
| RE2 |
1185 |
| SRM |
14 |
| .NET |
35 |
| grep |
824 |
| RE2 |
160 / 1647 |
| SRM |
244 / 1647 |
| .NET |
638 / 1647 |
| grep |
539 / 1550 |
| RE2 |
54 / 1647 |
| SRM |
115 / 1647 |
| .NET |
122 / 1647 |
| grep |
154 / 1550 |
| RE2 |
9 / 1647 |
| SRM |
73 / 1647 |
| .NET |
14 / 1647 |
| grep |
54 / 1550 |
| CA |
15 |
| RE2 |
56 |
| SRM |
116 |
| .NET |
144 |
| grep |
178 |
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
#}
LS0tCnRpdGxlOiAiQ250LVNldC1NYXRhIEFuYWx5c2lzIgpwYXJhbXM6CiAgI2ZpbGVfY21wOiBkYXRhL3Jlc3VsdHMtMjMtMDQtMjAyMC5jc3YKICAjZmlsZV9jbXA6IHJlc3VsdHMtMDUtMDUtMjAyMC9iZXR3ZWVuL3Jlc3VsdHMuY3N2CiAgI2ZpbGVfY21wOiByZXN1bHRzLTA5LTA1LTIwMjAvYmV0d2Vlbi9SRVNVTFRTLUFMTC1iZXR3ZWVuLmNzdgogICNmaWxlX2NtcDogcmVzdWx0cy0xMC0wNS0yMDIwL3RhYmxlLUFMTC5jc3YKICAjZmlsZV9jbXA6IHJlc3VsdHMtMTEtMDUtMjAyMC90YWJsZS1BTEwtb25kcmEtcHJvY2Vzc2VkLmNzdgogICNmaWxlX2NtcDogcmVzdWx0cy0xMi0wNS0yMDIwL3RhYmxlLUFMTC1vbmRyYS1wcm9jZXNzZWQuY3N2CiAgZmlsZV9jbXA6IHJlc3VsdHMtMTUtMDUtMjAyMC9ub2dyZXAvY3V0L3RhYmxlLUFMTC1wcm9jZXNzZWQuY3N2CiAgI2ZpbGVfY21wOiByZXN1bHRzLTE1LTA1LTIwMjAvbm9ncmVwL25vY3V0L3RhYmxlLUFMTC1wcm9jZXNzZWQuY3N2CiAgI2ZpbGVfY21wOiByZXN1bHRzLTE1LTA1LTIwMjAvbm9ncmVwL21lcmdlZC90YWJsZS1BTEwtcHJvY2Vzc2VkLmNzdgogICNmaWxlX2JpZzogcmVzdWx0cy0wNS0wNS0yMDIwL3RhYmxlLWJpZy0yNTAzNjEwMi5jc3YKICBmaWxlX2JpZzogcmVzdWx0cy0xMS0wNS0yMDIwL2dyYXBoL3RhYmxlLWJpZy0xMDY1Mjg5NzA0LmNzdgogIGZpbGVfZGNhOiBEQ0FzL3Jlc3VsdHMtdHJhbnNsYXRpb24udHN2CiAgdGltZW91dDogNjAwICMgc2Vjb25kcwpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIGNvZGVfZm9sZGluZzogaGlkZQogIHBkZl9kb2N1bWVudDogZGVmYXVsdAogIGh0bWxfZG9jdW1lbnQ6CiAgICBkZl9wcmludDogcGFnZWQKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCi0tLQoKYGBge3J9CiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIyBQUkVBTUJMRQojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CgojIGxvYWQgdGhlIHBsb3R0aW5nIGxpYnJhcnkKc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KGdncGxvdDIpKQpsaWJyYXJ5KGdyaWRFeHRyYSkKbGlicmFyeShnZ0V4dHJhKQpsaWJyYXJ5KHRpa3pEZXZpY2UpCmxpYnJhcnkoSG1pc2MpCmxpYnJhcnkocGFzdGVjcykKCgoKdGhlbWVfc2V0KHRoZW1lX2J3KCkpCgpvcHRpb25zKHNjaXBlbj05OTkpICAjIHR1cm4tb2ZmIHNjaWVudGlmaWMgbm90YXRpb24gbGlrZSAxZSs0OAoKIyBzaXplIG9mIHBvaW50IGZvciBzY2F0dGVycGxvdHMKUE9JTlRfU0laRSA9IDAuMQojUE9JTlRfU0laRSA9IDEKCiMgdGltZW91dApUSU1FT1VUID0gcGFyYW1zJHRpbWVvdXQKVElNRU9VVF9WQUwgPSAxLjA1ICogVElNRU9VVAoKIyBzYXR1cmF0ZQojVElNRV9NSU4gPSAwLjAxICMgc2Vjb25kcwpUSU1FX01JTiA9IDAuMSAjIHNlY29uZHMKCkJJR19TSVpFPTMKU01BTExfU0laRT0yCgoKIyBGVU5DVElPTlMKcmVhZF9maWxlIDwtIGZ1bmN0aW9uKGZpbGUpIHsKICBmaWxlbmFtZSA9IHBhc3RlMChmaWxlKQogIGRmIDwtIHJlYWQuY3N2MihmaWxlbmFtZSwKICAgICAgICAgICAgICAgICAgaGVhZGVyPVRSVUUsCiAgICAgICAgICAgICAgICAgIHNlcD0iOyIsCiAgICAgICAgICAgICAgICAgIGRlYz0iLCIsCiAgICAgICAgICAgICAgICAgIGNvbW1lbnQuY2hhcj0iIiwKICAgICAgICAgICAgICAgICAgcXVvdGU9IlwiIiwKICAgICAgICAgICAgICAgICAgc3RyaXAud2hpdGU9VFJVRSwKICAgICAgICAgICAgICAgICAgYWxsb3dFc2NhcGVzPUZBTFNFLAogICAgICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFKQogIAogIAogIHJldHVybihkZikKfQoKcGxvdF9zY2F0dGVyX2xvZyA8LSBmdW5jdGlvbihkZiwgeGxhYiwgeWxhYiwgeHN0cmluZz14bGFiLCB5c3RyaW5nPXlsYWIpIHsKICBwc2NhdCA8LSBnZ3Bsb3QoZGYsIGFlc19zdHJpbmcoeD14bGFiLCB5PXlsYWIpKSArCiAgICBnZW9tX3BvaW50KHNpemU9UE9JTlRfU0laRSkgKwogICAgZ2VvbV9hYmxpbmUoc2l6ZT0wLjEpICsKICAgIGdlb21fdmxpbmUoc2l6ZT0wLjEsIHhpbnRlcmNlcHQ9VElNRU9VVF9WQUwsIGxpbmV0eXBlPSJkYXNoZWQiKSArCiAgICBnZW9tX2hsaW5lKHNpemU9MC4xLCB5aW50ZXJjZXB0PVRJTUVPVVRfVkFMLCBsaW5ldHlwZT0iZGFzaGVkIikgKwogICAgZ2VvbV9ydWcoYWxwaGEgPSAwLjIpICsKICAgIHNjYWxlX3hfbG9nMTAoKSArCiAgICBzY2FsZV95X2xvZzEwKCkgKwogICAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAwLjUpKSArCiAgICAjY29vcmRfZml4ZWQoeGxpbSA9IGMoVElNRV9NSU4sIFRJTUVPVVRfVkFMKSwgeWxpbSA9IGMoMC4xLCBUSU1FT1VUX1ZBTCkpICsKICAgICNjb29yZF9maXhlZCh4bGltID0gYyhUSU1FX01JTiwgVElNRU9VVF9WQUwpLCB5bGltID0gYyhUSU1FX01JTiwgVElNRU9VVF9WQUwpKSArCiAgICAgICAgY29vcmRfZml4ZWQoeGxpbSA9IGMoVElNRV9NSU4sIFRJTUVPVVRfVkFMKSwgeWxpbSA9IGMoVElNRV9NSU4sIFRJTUVPVVRfVkFMKSkgKwogICAgbGFicygKICAgICAgI3RpdGxlPSJUaXRsZSIsCiAgICAgICNzdWJ0aXRsZT0iU3VidGl0bGUiLAogICAgICB4PXhzdHJpbmcsCiAgICAgIHk9eXN0cmluZykKIyAgICB0aGVtZSgKIyAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwgCiMgICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiMgICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsY29sb3VyID0gTkEpLAojICAgICAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsY29sb3VyID0gTkEpCiMgICAgICAgICkKIyAgdGhlbWVfbWluaW1hbCgpCiMgIHRoZW1lX2J3KCkKICMgdGhlbWUocGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOQSkpCiAjIHBzY2F0IDwtIGdnTWFyZ2luYWwocHNjYXQsIHR5cGUgPSAiZGVuc2l0eSIsIHNpemU9MTApCiMgIHBzY2F0IDwtIHBzY2F0ICsgdGhlbWVfYncoKQogIHJldHVybihwc2NhdCkKfQoKbWFrZV90aWt6IDwtIGZ1bmN0aW9uKGZpbGUsIHBpY3R1cmUsIHdpZHRoPTIuNSwgaGVpZ2h0PTIuNSkgewogIGZvbnRfc2l6ZSA8LSAxCiAgdGlreihmaWxlPWZpbGUsIG9uZWZpbGU9VCwgd2lkdGg9d2lkdGgsIGhlaWdodD1oZWlnaHQpCiAgcGxvdChwaWN0dXJlKQogIGdhcmJhZ2UgPC0gZGV2Lm9mZigpCn0KCm1ha2VfcGRmIDwtIGZ1bmN0aW9uKGZpbGUsIHBpY3R1cmUsIHdpZHRoPTUsIGhlaWdodD01KSB7CiAgcGRmKGZpbGU9ZmlsZSwgb25lZmlsZT1ULCB3aWR0aCwgaGVpZ2h0KQogIHBsb3QocGljdHVyZSkKICBnYXJiYWdlIDwtIGRldi5vZmYoKQp9CmBgYAoKYGBge3J9CmRmIDwtIHJlYWRfZmlsZShwYXJhbXMkZmlsZV9jbXApCm9yaWdfc2l6ZSA8LSBucm93KGRmKQoKY29sbmFtZXMoZGYpW2NvbG5hbWVzKGRmKSA9PSAiZG90Lm5ldCJdIDwtICJkb3RuZXQiCmNvbG5hbWVzKGRmKVtuYW1lcyhkZikgPT0gImRvdC5uZXQubWF0Y2hlcyJdIDwtICJkb3RuZXQubWF0Y2hlcyIKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMgU0FOSVRJWkUgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIGNsZWFuIHRoZSBkYXRhCmRmX25ldyA8LSBkZlshZ3JlcGwoIkZpbGUgbm90IGZvdW5kIiwgZGYkc3JtLm1hdGNoZXMpLF0KcHJpbnQocGFzdGUwKCJSZW1vdmluZyAiLCBucm93KGRmKSAtIG5yb3coZGZfbmV3KSwgIiBsaW5lcyBkdWUgdG8gZ2VuZXJhdGlvbiBvZiBpbnB1dCB0ZXh0IikpCmRmIDwtIGRmX25ldwoKdG9vbHMudGltZXMgPC0gYygicmUyZyIsICJjYWQiLCAiZ3JlcCIsICJzcm0iLCAiZG90bmV0IikKI3Rvb2xzLnRpbWVzIDwtIGMoInJlMmciLCAiY2FkIiwgInNybSIsICJkb3RuZXQiKQp0b29scy5tYXRjaGVzIDwtIGMoInJlMmcubWF0Y2hlcyIsICJjYWQubWF0Y2hlcyIsICJncmVwLm1hdGNoZXMiLCAic3JtLm1hdGNoZXMiLCAiZG90bmV0Lm1hdGNoZXMiKQojdG9vbHMubWF0Y2hlcyA8LSBjKCJyZTJnLm1hdGNoZXMiLCAiY2FkLm1hdGNoZXMiLCAic3JtLm1hdGNoZXMiLCAiZG90bmV0Lm1hdGNoZXMiKQoKIyBjaGVja2luZyBlcnJvcnMKZXJyb3JzLnJlMmcgPC0gbnJvdyhkZltncmVwbCgnRVJSJywgZGYkcmUyZyksXSkKZXJyb3JzLmdyZXAgPC0gbnJvdyhkZltncmVwbCgnRVJSJywgZGYkZ3JlcCksXSkKZXJyb3JzLnNybSA8LSBucm93KGRmW2dyZXBsKCdFUlInLCBkZiRzcm0pLF0pCmVycm9ycy5jYWQgPC0gbnJvdyhkZltncmVwbCgnRVJSJywgZGYkY2FkKSxdKQplcnJvcnMuZG90bmV0IDwtIG5yb3coZGZbZ3JlcGwoJ0VSUicsIGRmJGRvdG5ldCksXSkKCmRmIDwtIGRmWyFncmVwbCgnRVJSJywgZGYkcmUyZyksXQoKCiMgY2hhbmdlIHRoZSB0eXBlIG9mIGNvbHVtbnMgb3RoZXIgdGhhbiB0aGUgbmFtZQpmb3IgKGkgaW4gdG9vbHMudGltZXMpIHsKICBkZlssaV0gPC0gc3ViKCIsIiwgIi4iLCBkZlssaV0pCiAgc3VwcHJlc3NXYXJuaW5ncyhkZlssaV0gPC0gYXMubnVtZXJpYyhkZlssaV0pKQp9Cgpmb3IgKGkgaW4gdG9vbHMubWF0Y2hlcykgewogIHN1cHByZXNzV2FybmluZ3MoZGZbLGldIDwtIGFzLmludGVnZXIoZGZbLGldKSkKfQoKZGYkc3JjIDwtIGFzLmZhY3RvcihkZiRzcmMpCgojIGdldCByaWQgb2YgZXh0cmVtYWwgdmFsdWVzCmRmWyx0b29scy50aW1lc11bZGZbLHRvb2xzLnRpbWVzXSA+IFRJTUVPVVRdIDwtIFRJTUVPVVRfVkFMCmRmW3Rvb2xzLnRpbWVzXVtpcy5uYShkZlt0b29scy50aW1lc10pXSA8LSBUSU1FT1VUX1ZBTAojZGZbaXMubmEoZGYpXSA8LSBUSU1FT1VUX1ZBTAojZGZbZGYgPT0gMC4wMF0gPC0gVElNRV9NSU4KZGZbLHRvb2xzLnRpbWVzXVtkZlssdG9vbHMudGltZXNdIDwgVElNRV9NSU5dIDwtIFRJTUVfTUlOCgoKCiMgY2xlYW4gdGhlIGRhdGEKI2RmX25ldyA8LSBkZltkZiRMaW5lcyAhPSAiRVJST1IgV0hJTEUgQ09OVkVSVElORyBUTyBEQ0EuIixdCiNwcmludChwYXN0ZTAoIlJlbW92aW5nICIsIG5yb3coZGYpIC0gbnJvdyhkZl9uZXcpLCAiIGxpbmVzIGR1ZSB0byBjb252ZXJ0aW5nIHRvIERDQSBlcnJvciIpKQojZGYgPC0gZGZfbmV3CgoKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyBDT1VOVElORyBUSU1FT1VUUyAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwp0aW1lb3V0cy5yZTJnIDwtIG5yb3coZGZbZGYkcmUyZyA9PSBUSU1FT1VUX1ZBTCxdKQp0aW1lb3V0cy5jYWQgPC0gbnJvdyhkZltkZiRjYWQgPT0gVElNRU9VVF9WQUwsXSkKdGltZW91dHMuZ3JlcCA8LSBucm93KGRmW2RmJGdyZXAgPT0gVElNRU9VVF9WQUwsXSkKdGltZW91dHMuc3JtIDwtIG5yb3coZGZbZGYkc3JtID09IFRJTUVPVVRfVkFMLF0pCnRpbWVvdXRzLmRvdG5ldCA8LSBucm93KGRmW2RmJGRvdG5ldCA9PSBUSU1FT1VUX1ZBTCxdKQp0aW1lb3V0cy5yZTIuYW5kLmNhIDwtIG5yb3coZGZbZGYkY2FkID09IFRJTUVPVVRfVkFMICYgZGYkcmUyZyA9PSBUSU1FT1VUX1ZBTCxdKQoKIyB8ICoqVGltZW91dHMgZ3JlcCoqICAgIHwgYHIgdGltZW91dHMuZ3JlcGAgIHwKYGBgCgpUaGVzZSBhcmUgcmVzdWx0cyBvZiB0aGUgZXhwZXJpbWVudHMgZm9yIENvdW50aW5nIFNldCBBdXRvbWF0YToKCnwgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCB8CnwtLS0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS06fC18CnwgKipGaWxlKiogICAgICAgICAgICB8IGByIHBhcmFtcyRmaWxlX2NtcGAgfAp8ICoqVGltZW91dCoqICAgICAgICAgfCBgciBUSU1FT1VUYCBzICAgICAgIHwKfCAqKlRJTUVPVVRfVkFMKiogICAgIHwgYHIgVElNRU9VVF9WQUxgIHMgICB8CnwgKipUSU1FX01JTioqICAgICAgICB8IGByIFRJTUVfTUlOYCAgICAgICAgfAp8ICoqb3JpZ2luYWwgc2l6ZSoqICAgfCBgciBvcmlnX3NpemVgICAgICAgIHwKfCAqKkJlbmNobWFya3MqKiAgICAgIHwgYHIgbnJvdyhkZilgICAgICAgICB8CnwgKipUaW1lb3V0cyBDQSoqICAgICB8IGByIHRpbWVvdXRzLmNhZGAgICAgIHwKfCAqKlRpbWVvdXRzIFJFMioqICAgIHwgYHIgdGltZW91dHMucmUyZ2AgICAgfAp8ICoqVGltZW91dHMgU1JNKiogICAgfCBgciB0aW1lb3V0cy5zcm1gICAgIHwgCnwgKipUaW1lb3V0cyBncmVwKiogICB8IGByIHRpbWVvdXRzLmdyZXBgICAgIHwgCnwgKipUaW1lb3V0cyAuTkVUKiogICB8IGByIHRpbWVvdXRzLmRvdG5ldGAgIHwKfCAqKkVycm9ycyBDQSoqICAgICB8IGByIGVycm9ycy5jYWRgICAgICB8CnwgKipFcnJvcnMgUkUyKiogICAgfCBgciBlcnJvcnMucmUyZ2AgICAgfCAocmVtb3ZlZCkgfAp8ICoqRXJyb3JzIFNSTSoqICAgIHwgYHIgZXJyb3JzLnNybWAgICAgfCAKfCAqKkVycm9ycyBncmVwKiogICB8IGByIGVycm9ycy5ncmVwYCAgICB8IAp8ICoqRXJyb3JzIC5ORVQqKiAgIHwgYHIgZXJyb3JzLmRvdG5ldGAgIHwKCgoKYGBge3J9CmRmCmBgYAoKIyBTdW1tYXJ5IG9mIGJlbmNobWFya3MKCmBgYHtyfQpkZl9iZW5jaGVzIDwtIGRhdGEuZnJhbWUoc3VtbWFyeShkZiRzcmMpKQpkZl9iZW5jaGVzCmBgYAoKIyBTYW5pdHkgY2hlY2tzCgpgYGB7cn0KZGYkaW5jb25zaXN0ZW50IDwtIGRmJHJlMmcubWF0Y2hlcyAhPSBkZiRncmVwLm1hdGNoZXMgfCBkZiRyZTJnLm1hdGNoZXMgIT0gZGYkc3JtLm1hdGNoZXMgfCBkZiRyZTJnLm1hdGNoZXMgIT0gZGYkZG90bmV0Lm1hdGNoZXMgfCBkZiRyZTJnLm1hdGNoZXMgIT0gZGYkY2FkLm1hdGNoZXMKCiNkZiRpbmNvbnNpc3RlbnQgPC0gZGYkcmUyZy5tYXRjaGVzICE9IGRmJHNybS5tYXRjaGVzIHwgZGYkcmUyZy5tYXRjaGVzICE9IGRmJGRvdG5ldC5tYXRjaGVzIHwgZGYkcmUyZy5tYXRjaGVzICE9IGRmJGNhZC5tYXRjaGVzCgpkZiRncmVwLnJlMi5taXNtYXRjaCA8LSAhaXMubmEoZGYkcmUyZy5tYXRjaGVzKSAmICFpcy5uYShkZiRncmVwLm1hdGNoZXMpICYgZGYkcmUyZy5tYXRjaGVzICE9IGRmJGdyZXAubWF0Y2hlcwpkZl9ncmVwX3JlMl9taXNtYXRjaCA8LSBkZltkZiRncmVwLnJlMi5taXNtYXRjaCxdCgpkZiRyZTIuY2EubWlzbWF0Y2ggPC0gIWlzLm5hKGRmJHJlMmcubWF0Y2hlcykgJiAhaXMubmEoZGYkY2FkLm1hdGNoZXMpICYgZGYkcmUyZy5tYXRjaGVzICE9IGRmJGNhZC5tYXRjaGVzCmRmX3JlMl9jYV9taXNtYXRjaCA8LSBkZltkZiRyZTIuY2EubWlzbWF0Y2gsXQoKZGYgPC0gZGZbaXMubmEoZGYkcmUyZy5tYXRjaGVzKSB8IGlzLm5hKGRmJGdyZXAubWF0Y2hlcykgfCBkZiRyZTJnLm1hdGNoZXMgPT0gZGYkY2FkLm1hdGNoZXMsXQoKYGBgCgp8ICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgfAp8LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLTp8IC0tLS0tLS06fAp8ICoqQ0EgYW5kIFJFMiBtaXNtYXRjaGVkKiogICB8IGByIG5yb3coZGZfcmUyX2NhX21pc21hdGNoKWAgICB8IChyZW1vdmVkKSB8CnwgKipncmVwIGFuZCBSRTIgbWlzbWF0Y2hlZCoqIHwgYHIgbnJvdyhkZl9ncmVwX3JlMl9taXNtYXRjaClgIHwKCgojIyBSRTIgYW5kIENBIG1pc21hdGNoZXMKYGBge3J9CmRmX3JlMl9jYV9taXNtYXRjaApgYGAKCgoKIyBTY2F0dGVyIFBsb3RzCgpgYGB7cn0KCnBsb3QuYW5kLnRpa3ogPC0gZnVuY3Rpb24oZGYsIHhsYWIsIHlsYWIsIHhzdHJpbmc9eGxhYiwgeXN0cmluZz15bGFiLCB3aWR0aD00LCBoZWlnaHQ9d2lkdGgpIHsKICBwaWMgPC0gcGxvdF9zY2F0dGVyX2xvZyhkZiwgeGxhYiwgeWxhYiwgeHN0cmluZywgeXN0cmluZykKICAjbWFrZV90aWt6KHBhc3RlMCgiZmlncy8iLCB4bGFiLCAiLXZzLSIsIHlsYWIsICIudGlreiIpLCBwaWMsIHdpZHRoLCBoZWlnaHQpCiAgbWFrZV9wZGYocGFzdGUwKCJmaWdzLyIsIHhsYWIsICItdnMtIiwgeWxhYiwgIi5wZGYiKSwgcGljLCB3aWR0aCwgaGVpZ2h0KQogIHBpYwp9CgpkZl9ncmVwIDwtIGRmW2lzLm5hKGRmJGdyZXAubWF0Y2hlcykgfCBpcy5uYShkZiRjYWQubWF0Y2hlcykgfCBkZiRncmVwLm1hdGNoZXMgPT0gZGYkY2FkLm1hdGNoZXMsXQoKcGxvdDEgPC0gcGxvdC5hbmQudGlreihkZiwgInJlMmciLCAiY2FkIiwgeHN0cmluZz0iUkUyIFtzXSIsIHlzdHJpbmc9IkNBIFtzXSIsIHdpZHRoPUJJR19TSVpFKQpwbG90MiA8LSBwbG90LmFuZC50aWt6KGRmX2dyZXAsICJncmVwIiwgImNhZCIsIHhzdHJpbmc9ImdyZXAgW3NdIiwgeXN0cmluZz0iQ0EgW3NdIiwgd2lkdGg9U01BTExfU0laRSkKcGxvdDMgPC0gcGxvdC5hbmQudGlreihkZiwgInNybSIsICJjYWQiLCB4c3RyaW5nPSJTUk0gW3NdIiwgeXN0cmluZz0iQ0EgW3NdIiwgd2lkdGg9U01BTExfU0laRSkKcGxvdDQgPC0gcGxvdC5hbmQudGlreihkZiwgImRvdG5ldCIsICJjYWQiLCB4c3RyaW5nPSIuTkVUIFtzXSIsIHlzdHJpbmc9IkNBIFtzXSIsIHdpZHRoPVNNQUxMX1NJWkUpCnBsb3Q1IDwtIHBsb3QuYW5kLnRpa3ooZGYsICJzcm0iLCAicmUyZyIpCnBsb3Q2IDwtIHBsb3QuYW5kLnRpa3ooZGYsICJncmVwIiwgInJlMmciKQpwbG90NyA8LSBwbG90LmFuZC50aWt6KGRmLCAiZG90bmV0IiwgInJlMmciKQpwbG90OCA8LSBwbG90LmFuZC50aWt6KGRmLCAic3JtIiwgImdyZXAiKQpwbG90OSA8LSBwbG90LmFuZC50aWt6KGRmLCAiZG90bmV0IiwgImdyZXAiKQpwbG90MTAgPC0gcGxvdC5hbmQudGlreihkZiwgImRvdG5ldCIsICJzcm0iKQoKCgojZ3JpZC5hcnJhbmdlKHBsb3QxLCBwbG90MywgbmNvbCA9IDIpCiNncmlkLmFycmFuZ2UocGxvdDQsIHBsb3Q1LCBuY29sID0gMikKI2dyaWQuYXJyYW5nZShwbG90NywgcGxvdDEwLCBuY29sID0gMikKCmdyaWQuYXJyYW5nZShwbG90MSwgcGxvdDIsIG5jb2wgPSAyKQpncmlkLmFycmFuZ2UocGxvdDMsIHBsb3Q0LCBuY29sID0gMikKZ3JpZC5hcnJhbmdlKHBsb3Q1LCBwbG90NiwgbmNvbCA9IDIpCmdyaWQuYXJyYW5nZShwbG90NywgcGxvdDgsIG5jb2wgPSAyKQpncmlkLmFycmFuZ2UocGxvdDksIHBsb3QxMCwgbmNvbCA9IDIpCgpgYGAKCiMgSGlzdG9ncmFtcwoKYGBge3J9Cmhpc3QxIDwtIGdncGxvdChkZiwgYWVzKHg9cmUyZykpICsKICBnZW9tX2hpc3RvZ3JhbShjb2xvcj0iYmx1ZSIsIGZpbGw9ImxpZ2h0Ymx1ZSIpICsKICBzY2FsZV95X2xvZzEwKCkKCmhpc3QyIDwtIGdncGxvdChkZiwgYWVzKHg9Y2FkKSkgKyAKICBnZW9tX2hpc3RvZ3JhbShjb2xvcj0iYmx1ZSIsIGZpbGw9ImxpZ2h0Ymx1ZSIpICsKICBzY2FsZV95X2xvZzEwKCkKCmhpc3QzIDwtIGdncGxvdChkZiwgYWVzKHg9c3JtKSkgKyAKICBnZW9tX2hpc3RvZ3JhbShjb2xvcj0iYmx1ZSIsIGZpbGw9ImxpZ2h0Ymx1ZSIpICsKICBzY2FsZV95X2xvZzEwKCkKCiNoaXN0NCA8LSBnZ3Bsb3QoZGYsIGFlcyh4PWdyZXApKSArIAojICBnZW9tX2hpc3RvZ3JhbShjb2xvcj0iYmx1ZSIsIGZpbGw9ImxpZ2h0Ymx1ZSIpICsKIyAgc2NhbGVfeV9sb2cxMCgpCgpoaXN0NSA8LSBnZ3Bsb3QoZGYsIGFlcyh4PWRvdG5ldCkpICsgCiAgZ2VvbV9oaXN0b2dyYW0oY29sb3I9ImJsdWUiLCBmaWxsPSJsaWdodGJsdWUiKSArCiAgc2NhbGVfeV9sb2cxMCgpCgpncmlkLmFycmFuZ2UoaGlzdDEsIGhpc3QyLCBuY29sID0gMikKZ3JpZC5hcnJhbmdlKGhpc3QzLCBoaXN0NSwgbmNvbCA9IDIpCiNncmlkLmFycmFuZ2UoaGlzdDUsIG5jb2wgPSAyKQoKCmBgYAoKIyBGaW5kaW5nIHdpbm5lcnMKCmBgYHtyfQpkZiRtaW4gPC1wbWluKGRmJGdyZXAsIGRmJHNybSwgZGYkcmUyZywgZGYkZG90bmV0LCBkZiRjYWQpCmRmJGVuZW15Lm1pbiA8LSBwbWluKGRmJGdyZXAsIGRmJHNybSwgZGYkcmUyZywgZGYkZG90bmV0KQojZGYkbWluIDwtcG1pbihkZiRzcm0sIGRmJHJlMmcsIGRmJGRvdG5ldCwgZGYkY2FkKQojZGYkZW5lbXkubWluIDwtIHBtaW4oZGYkc3JtLCBkZiRyZTJnLCBkZiRkb3RuZXQpCgp3aW5uZXJzLmdyZXAgPC0gbnJvdyhkZltkZiRtaW4gPT0gZGYkZ3JlcCxdKQp3aW5uZXJzLnJlMiA8LSBucm93KGRmW2RmJG1pbiA9PSBkZiRyZTJnLF0pCndpbm5lcnMuY2EgPC0gbnJvdyhkZltkZiRtaW4gPT0gZGYkY2FkLF0pCndpbm5lcnMuc3JtIDwtIG5yb3coZGZbZGYkbWluID09IGRmJHNybSxdKQp3aW5uZXJzLmRvdG5ldCA8LSBucm93KGRmW2RmJG1pbiA9PSBkZiRkb3RuZXQsXSkKCndpbm5lcnMuY2Eub3Zlci5yZTIgPC0gbnJvdyhkZltkZiRjYWQgPD0gZGYkcmUyZyxdKQp3aW5uZXJzLmNhLm92ZXIuZ3JlcCA8LSBucm93KGRmW2RmX2dyZXAkY2FkIDw9IGRmX2dyZXAkZ3JlcCxdKQp3aW5uZXJzLmNhLm92ZXIuc3JtIDwtIG5yb3coZGZbZGYkY2FkIDw9IGRmJHNybSxdKQp3aW5uZXJzLmNhLm92ZXIuZG90bmV0IDwtIG5yb3coZGZbZGYkY2FkIDw9IGRmJGRvdG5ldCxdKQoKd2lubmVycy4xMC5jYS5vdmVyLnJlMiA8LSBucm93KGRmWzEwKiBkZiRjYWQgPD0gZGYkcmUyZyxdKQp3aW5uZXJzLjEwLmNhLm92ZXIuZ3JlcCA8LSBucm93KGRmWzEwKiBkZl9ncmVwJGNhZCA8PSBkZl9ncmVwJGdyZXAsXSkKd2lubmVycy4xMC5jYS5vdmVyLnNybSA8LSBucm93KGRmWzEwKiBkZiRjYWQgPD0gZGYkc3JtLF0pCndpbm5lcnMuMTAuY2Eub3Zlci5kb3RuZXQgPC0gbnJvdyhkZlsxMCogZGYkY2FkIDw9IGRmJGRvdG5ldCxdKQoKd2lubmVycy4xMDAuY2Eub3Zlci5yZTIgPC0gbnJvdyhkZlsxMDAqIGRmJGNhZCA8PSBkZiRyZTJnLF0pCndpbm5lcnMuMTAwLmNhLm92ZXIuZ3JlcCA8LSBucm93KGRmWzEwMCogZGZfZ3JlcCRjYWQgPD0gZGZfZ3JlcCRncmVwLF0pCndpbm5lcnMuMTAwLmNhLm92ZXIuc3JtIDwtIG5yb3coZGZbMTAwKiBkZiRjYWQgPD0gZGYkc3JtLF0pCndpbm5lcnMuMTAwLmNhLm92ZXIuZG90bmV0IDwtIG5yb3coZGZbMTAwKiBkZiRjYWQgPD0gZGYkZG90bmV0LF0pCgpsb25nZXIudGhhbi4xMC5zZWNvbmRzLmNhIDwtIG5yb3coZGZbZGYkY2FkID4gMTAsXSkKbG9uZ2VyLnRoYW4uMTAuc2Vjb25kcy5yZTIgPC0gbnJvdyhkZltkZiRyZTJnID4gMTAsXSkKbG9uZ2VyLnRoYW4uMTAuc2Vjb25kcy5zcm0gPC0gbnJvdyhkZltkZiRzcm0gPiAxMCxdKQpsb25nZXIudGhhbi4xMC5zZWNvbmRzLmRvdG5ldCA8LSBucm93KGRmW2RmJGRvdG5ldCA+IDEwLF0pCmxvbmdlci50aGFuLjEwLnNlY29uZHMuZ3JlcCA8LSBucm93KGRmW2RmJGdyZXAgPiAxMCxdKQoKCmBgYAoKfCAqKldpbm5lcioqICAgICAgICAgIHwgICAgICAgICAgICAgICAgICAgICB8CnwtLS0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS06fAp8ICoqQ0EqKiAgICAgfCBgciB3aW5uZXJzLmNhYCAgICAgfAp8ICoqUkUyKiogICAgfCBgciB3aW5uZXJzLnJlMmAgICAgfAp8ICoqU1JNKiogICAgfCBgciB3aW5uZXJzLnNybWAgICAgfCAKfCAqKi5ORVQqKiAgICB8IGByIHdpbm5lcnMuZG90bmV0YCAgfAp8ICoqZ3JlcCoqICAgIHwgYHIgd2lubmVycy5ncmVwYCAgfAoKfCAqKldpbnMgb2YgQ0Egb3ZlcioqICAgICAgICAgIHwgICAgICAgICAgICAgICAgICAgICB8CnwtLS0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS06fAp8ICoqUkUyKiogICAgfCBgciB3aW5uZXJzLmNhLm92ZXIucmUyYCAvIGByIG5yb3coZGYpYCAgIHwKfCAqKlNSTSoqICAgIHwgYHIgd2lubmVycy5jYS5vdmVyLnNybWAgLyBgciBucm93KGRmKWAgICAgfCAKfCAqKi5ORVQqKiAgICB8IGByIHdpbm5lcnMuY2Eub3Zlci5kb3RuZXRgIC8gYHIgbnJvdyhkZilgICB8CnwgKipncmVwKiogICAgfCBgciB3aW5uZXJzLmNhLm92ZXIuZ3JlcGAgLyBgciBucm93KGRmX2dyZXApYCAgfAoKfCAqKldpbnMgb2YgYXQgbGVhc3QgMTAgdGltZXMgb2YgQ0Egb3ZlcioqICAgICAgICAgIHwgICAgICAgICAgICAgICAgICAgICB8CnwtLS0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS06fAp8ICoqUkUyKiogICAgfCBgciB3aW5uZXJzLjEwLmNhLm92ZXIucmUyYCAvIGByIG5yb3coZGYpYCAgIHwKfCAqKlNSTSoqICAgIHwgYHIgd2lubmVycy4xMC5jYS5vdmVyLnNybWAgLyBgciBucm93KGRmKWAgICAgfCAKfCAqKi5ORVQqKiAgICB8IGByIHdpbm5lcnMuMTAuY2Eub3Zlci5kb3RuZXRgIC8gYHIgbnJvdyhkZilgICB8CnwgKipncmVwKiogICAgfCBgciB3aW5uZXJzLjEwLmNhLm92ZXIuZ3JlcGAgLyBgciBucm93KGRmX2dyZXApYCAgfAoKfCAqKldpbnMgb2YgYXQgbGVhc3QgMTAwIHRpbWVzIG9mIENBIG92ZXIqKiAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfAp8LS0tLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tOnwKfCAqKlJFMioqICAgIHwgYHIgd2lubmVycy4xMDAuY2Eub3Zlci5yZTJgIC8gYHIgbnJvdyhkZilgICAgfAp8ICoqU1JNKiogICAgfCBgciB3aW5uZXJzLjEwMC5jYS5vdmVyLnNybWAgLyBgciBucm93KGRmKWAgICAgfCAKfCAqKi5ORVQqKiAgICB8IGByIHdpbm5lcnMuMTAwLmNhLm92ZXIuZG90bmV0YCAvIGByIG5yb3coZGYpYCAgfAp8ICoqZ3JlcCoqICAgIHwgYHIgd2lubmVycy4xMDAuY2Eub3Zlci5ncmVwYCAvIGByIG5yb3coZGZfZ3JlcClgICB8Cgp8ICoqTG9uZ2VyIHRoYW4gMTAgcyoqICAgICAgICAgIHwgICAgICAgICAgICAgICAgICAgICB8CnwtLS0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS06fAp8ICoqQ0EqKiAgICAgfCBgciBsb25nZXIudGhhbi4xMC5zZWNvbmRzLmNhYCAgICAgfAp8ICoqUkUyKiogICAgfCBgciBsb25nZXIudGhhbi4xMC5zZWNvbmRzLnJlMmAgICAgfAp8ICoqU1JNKiogICAgfCBgciBsb25nZXIudGhhbi4xMC5zZWNvbmRzLnNybWAgICAgfCAKfCAqKi5ORVQqKiAgICB8IGByIGxvbmdlci50aGFuLjEwLnNlY29uZHMuZG90bmV0YCAgfAp8ICoqZ3JlcCoqICAgIHwgYHIgbG9uZ2VyLnRoYW4uMTAuc2Vjb25kcy5ncmVwYCAgfAoKCgpgYGB7cn0KcGxvdC5hbmQudGlreihkZiwgImVuZW15Lm1pbiIsICJjYWQiLCB4c3RyaW5nPSJiZXN0IGVuZW15IiwgeXN0cmluZz0iQ0EgW3NdIikKYGBgCgojIEhvdyBtdWNoIHdlIGFyZSBiZXR0ZXIgdGhhbiBSRTIKCmBgYHtyfQpkZiRyZTIudnMuY2EgPC0gZGYkcmUyZyAvIGRmJGNhZApkZl9zb3J0ZWQgPC0gZGZbb3JkZXIoZGYkcmUyLnZzLmNhLCBkZWNyZWFzaW5nPVRSVUUpLF0KCiNkZl9zb3J0ZWRbLGMoInNyYyIsICJwYXR0ZXJuIiwgImZpbGUiLCAicmUyZyIsICJjYWQiLCAicmUyLnZzLmNhIiwgInJlMi5jYS5taXNtYXRjaCIpXQpkZl9zb3J0ZWQgPC0gZGZfc29ydGVkWzE6MTAsYygic3JjIiwgInBhdHRlcm4iLCAiZmlsZSIsIHRvb2xzLnRpbWVzKV0KZGZfc29ydGVkCmhhZiA8LSBsYXRleChkZl9zb3J0ZWQsCiAgICAgICAgICAgICBmaWxlPSJmaWdzL2Jlc3RfcmVzdWx0cy50ZXgiLAogICAgICAgICAgICAgYm9va3RhYnM9VFJVRSwKICAgICAgICAgICAgIHRhYmxlLmVudj1GQUxTRSwKICAgICAgICAgICAgIGNlbnRlcj0ibm9uZSIpCgpgYGAKCiMgU3VtbWFyaWVzCgpgYGB7cn0KZGZfZm9yX3N1bW1hcnkgPC0gZGZbLGMoInJlMmciLCAiY2FkIiwgInNybSIsICJkb3RuZXQiLCAiZ3JlcCIpXQojZGYuc3VtbWFyeSA8LSBkby5jYWxsKGNiaW5kLCBsYXBwbHkoZGZfZm9yX3N1bW1hcnksIHN1bW1hcnkpKQojZGYuc3VtbWFyeQoKZGVzYyA8LSBzdGF0LmRlc2MoZGZfZm9yX3N1bW1hcnkpCmRlc2MKaGFmIDwtIGxhdGV4KGRlc2MsCiAgICAgICAgICAgICBmaWxlPSJmaWdzL3N0YXRzLnRleCIsCiAgICAgICAgICAgICBib29rdGFicz1UUlVFLAogICAgICAgICAgICAgdGFibGUuZW52PUZBTFNFLAogICAgICAgICAgICAgY2VudGVyPSJub25lIikKCmBgYAoKIyBFeHBlcmltZW50cyB3aXRoIGluY3JlYXNpbmcgY291bnRlciB2YWx1ZQoKYGBge3J9CmJpZyA8LSByZWFkX2ZpbGUocGFyYW1zJGZpbGVfYmlnKQpiaWckcmUyZyA8LSBzdWIoIiwiLCAiLiIsIGJpZyRyZTJnKQpiaWckcmUyZyA8LSBhcy5udW1lcmljKGJpZyRyZTJnKQoKYmlnCmBgYAoKCmBgYHtyfQoKdG9nZXRoZXIgPC0gYmlnWywgYygiQ291bnRlciIsICJyZTJnIildCm5hbWVzKHRvZ2V0aGVyKVsyXSA8LSAidGltZSIKdG9nZXRoZXIkYXBwcm9hY2ggPC0gIlJFMiIKCnRtcCA8LSBiaWdbLCBjKCJDb3VudGVyIiwgImNhZCIpXQpuYW1lcyh0bXApWzJdIDwtICJ0aW1lIgp0bXAkYXBwcm9hY2ggPC0gIkNBIgp0b2dldGhlciA8LSByYmluZCh0b2dldGhlciwgdG1wKQoKdG1wIDwtIGJpZ1ssIGMoIkNvdW50ZXIiLCAic3JtIildCm5hbWVzKHRtcClbMl0gPC0gInRpbWUiCnRtcCRhcHByb2FjaCA8LSAiU1JNIgp0b2dldGhlciA8LSByYmluZCh0b2dldGhlciwgdG1wKQoKdG1wIDwtIGJpZ1ssIGMoIkNvdW50ZXIiLCAiZG90Lm5ldCIpXQpuYW1lcyh0bXApWzJdIDwtICJ0aW1lIgp0bXAkYXBwcm9hY2ggPC0gIi5ORVQiCnRvZ2V0aGVyIDwtIHJiaW5kKHRvZ2V0aGVyLCB0bXApCgp0bXAgPC0gYmlnWywgYygiQ291bnRlciIsICJncmVwIildCm5hbWVzKHRtcClbMl0gPC0gInRpbWUiCnRtcCRhcHByb2FjaCA8LSAiZ3JlcCIKdG9nZXRoZXIgPC0gcmJpbmQodG9nZXRoZXIsIHRtcCkKCkJJR19TVEVQPTEwMAoKIyByZW1vdmUgdG9vIG1hbnkgcG9pbnRzCnRvZ2V0aGVyIDwtIHRvZ2V0aGVyW3RvZ2V0aGVyJENvdW50ZXIgJSUgQklHX1NURVAgPT0gMCxdCgpiaWdfcGxvdCA8LSBnZ3Bsb3QoZGF0YT10b2dldGhlciwgYWVzKHg9Q291bnRlciwgeT10aW1lLCBjb2xvdXI9YXBwcm9hY2gpKSArCiAgZ2VvbV9saW5lKCkgKwogIGdlb21fcG9pbnQoYWVzKHNoYXBlPWFwcHJvYWNoKSkgKwogIHhsaW0oTkEsMjAwMCkgKwogIHlsaW0oTkEsMjApICsKICBnZW9tX2hsaW5lKHNpemU9MC4xLCB5aW50ZXJjZXB0PTAsIGxpbmV0eXBlPSJkYXNoZWQiKSArCgogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoLjAyLCAuOTgpLAogICAgICAgIGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gYygibGVmdCIsICJ0b3AiKSwKICAgICAgICAjbGVnZW5kLmJveC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG9yPSJibGFjayIsIHNpemU9MC41KSwKICAgICAgICBsZWdlbmQuYm94Lmp1c3QgPSAicmlnaHQiLAogICAgICAgIGxlZ2VuZC5tYXJnaW4gPSBtYXJnaW4oMSwgMSwgMSwgMSksCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArCiAgbGFicygKICAgICAgI3RpdGxlPSJUaXRsZSIsCiAgICAgICNzdWJ0aXRsZT0iU3VidGl0bGUiLAogICAgICB4PSJrIiwKICAgICAgeT0idGltZSBbc10iKQogICAgICAgIAoKICAjIGdlb21fbGluZShkYXRhID0gYmlnLCBhZXMoeCA9IENvdW50ZXIsIHkgPSByZTJnKSwgY29sb3IgPSAicmVkIikgKwogICMgZ2VvbV9saW5lKGRhdGEgPSBiaWcsIGFlcyh4ID0gQ291bnRlciwgeSA9IGNhKSwgY29sb3IgPSAiYmx1ZSIpICsKICAjIHhsYWIoJ2NvdW50ZXIgdmFsdWUnKSArCiAgIyB5bGFiKCd0aW1lIFtzXScpCgojbWFrZV90aWt6KHBhc3RlMCgiZmlncy9iaWdfcGxvdC50aWt6IiksIGJpZ19wbG90LCB3aWR0aD0yLjcsIGhlaWdodD0yLjcpCm1ha2VfcGRmKHBhc3RlMCgiZmlncy9iaWdfcGxvdC5wZGYiKSwgYmlnX3Bsb3QsIHdpZHRoPUJJR19TSVpFLCBoZWlnaHQ9QklHX1NJWkUpCgoKcGxvdChiaWdfcGxvdCkKYGBgCgoKYGBge3J9CiMgSW5mb3JtYXRpb24gYWJvdXQgRENBcwoKIyBkZl9kY2FzID0gcmVhZC5jc3YyKHBhcmFtcyRmaWxlX2RjYSwKIyAgICAgICAgICAgICAgICAgICBoZWFkZXI9VFJVRSwKIyAgICAgICAgICAgICAgICAgICBzZXA9Ilx0IiwKIyAgICAgICAgICAgICAgICAgICBkZWM9Ii4iLAojICAgICAgICAgICAgICAgICAgIGNvbW1lbnQuY2hhcj0iIiwKIyAgICAgICAgICAgICAgICAgICBxdW90ZT0iIiwKIyAgICAgICAgICAgICAgICAgICBzdHJpcC53aGl0ZT1UUlVFLAojICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UpCiMgCiMgIyBzYW5pdGl6ZQojIGRmX2RjYXMkdGltZW91dHMuY2xhc3NpY2FsW2lzLm5hKGRmX2RjYXMkdGltZW91dHMuY2xhc3NpY2FsKV0gPC0gMAoKI2RmX2RjYXMKYGBgCgpgYGB7cn0KI3Rtcy5jbGFzc2ljYWwgPC0gZGZfZGNhc1tkZl9kY2FzJHRpbWVvdXRzLmNsYXNzaWNhbCA9PSAxLF0KYGBgCgoKCmBgYHtyfQojY29tcHV0ZV90aW1lb3V0cyA8LSBmdW5jdGlvbihkZiwgY29sKSB7CiMgIHRtcCA8LSBkZltkZlssIGNvbF0gPT0gVElNRU9VVF9WQUwsXQojICB0bXAKI30KCmBgYAoK