#=========================================================
There were 48 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
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 0 lines due to generation of input text"
df <- df_new
tools.times <- c("re2g", "cad", "cam", "grep", "srm", "dotnet")
#tools.times <- c("re2g", "cad", "grep", "srm", "dotnet")
#tools.times <- c("re2g", "cad", "srm", "dotnet")
tools.matches <- c("re2g.matches", "cad.matches", "cam.matches", "grep.matches", "srm.matches", "dotnet.matches")
#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.cam <- nrow(df[grepl('ERR', df$cam),])
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.cam <- nrow(df[df$cam == 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-03-06-2020/table-ALL-processed.csv |
|
| Timeout |
600 s |
|
| TIMEOUT_VAL |
630 s |
|
| TIME_MIN |
0.1 |
|
| original size |
1764 |
|
| Benchmarks |
1740 |
|
| Timeouts CA |
0 |
|
| Timeouts CAM |
0 |
|
| Timeouts RE2 |
0 |
|
| Timeouts SRM |
12 |
|
| Timeouts grep |
10 |
|
| Timeouts .NET |
10 |
|
| Errors CA |
0 |
|
| Errors CAM |
0 |
|
| Errors RE2 |
74 |
(removed) |
| Errors SRM |
0 |
|
| Errors grep |
58 |
|
| 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 |
24 |
(removed) |
| grep and RE2 mismatched |
363 |
|
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")
plot11 <- plot.and.tikz(df, "re2g", "cam", xstring="RE2 [s]", ystring="CAM [s]", width=BIG_SIZE)
plot12 <- plot.and.tikz(df_grep, "grep", "cam", xstring="grep [s]", ystring="CAM [s]", width=SMALL_SIZE)
plot13 <- plot.and.tikz(df, "srm", "cam", xstring="SRM [s]", ystring="CA [s]", width=SMALL_SIZE)
plot14 <- plot.and.tikz(df, "dotnet", "cam", xstring=".NET [s]", ystring="CA [s]", width=SMALL_SIZE)
plot15 <- plot.and.tikz(df, "cad", "cam", xstring="CAD [s]", ystring="CAM [s]", width=BIG_SIZE)
#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)

grid.arrange(plot11, plot12, ncol = 2)

grid.arrange(plot13, plot14, ncol = 2)

grid.arrange(plot15, 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$cam)
#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.cam <- nrow(df[df$min == df$cam,])
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.cam.over.re2 <- nrow(df[df$cam <= df$re2g,])
winners.cam.over.grep <- nrow(df[df_grep$cam <= df_grep$grep,])
winners.cam.over.srm <- nrow(df[df$cam <= df$srm,])
winners.cam.over.dotnet <- nrow(df[df$cam <= df$dotnet,])
winners.cam.over.cad <- nrow(df[df$cam <= df$cad,])
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 |
15 |
| RE2 |
1220 |
| SRM |
31 |
| .NET |
79 |
| grep |
670 |
| RE2 |
263 / 1740 |
| SRM |
307 / 1740 |
| .NET |
685 / 1740 |
| grep |
856 / 1366 |
| RE2 |
266 / 1740 |
| SRM |
382 / 1740 |
| .NET |
739 / 1740 |
| grep |
875 / 1366 |
| cad |
1640 / 1740 |
| RE2 |
150 / 1740 |
| SRM |
163 / 1740 |
| .NET |
128 / 1740 |
| grep |
236 / 1366 |
| RE2 |
89 / 1740 |
| SRM |
104 / 1740 |
| .NET |
29 / 1740 |
| grep |
100 / 1366 |
| CA |
29 |
| RE2 |
155 |
| SRM |
163 |
| .NET |
144 |
| grep |
234 |
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", "cam", "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
#}
LS0tCnRpdGxlOiAiQ250LVNldC1NYXRhIEFuYWx5c2lzIgpwYXJhbXM6CiAgI2ZpbGVfY21wOiBkYXRhL3Jlc3VsdHMtMjMtMDQtMjAyMC5jc3YKICAjZmlsZV9jbXA6IHJlc3VsdHMtMDUtMDUtMjAyMC9iZXR3ZWVuL3Jlc3VsdHMuY3N2CiAgI2ZpbGVfY21wOiByZXN1bHRzLTA5LTA1LTIwMjAvYmV0d2Vlbi9SRVNVTFRTLUFMTC1iZXR3ZWVuLmNzdgogICNmaWxlX2NtcDogcmVzdWx0cy0xMC0wNS0yMDIwL3RhYmxlLUFMTC5jc3YKICAjZmlsZV9jbXA6IHJlc3VsdHMtMTEtMDUtMjAyMC90YWJsZS1BTEwtb25kcmEtcHJvY2Vzc2VkLmNzdgogICNmaWxlX2NtcDogcmVzdWx0cy0xMi0wNS0yMDIwL3RhYmxlLUFMTC1vbmRyYS1wcm9jZXNzZWQuY3N2CiAgI2ZpbGVfY21wOiByZXN1bHRzLTE1LTA1LTIwMjAvbm9ncmVwL2N1dC90YWJsZS1BTEwtcHJvY2Vzc2VkLmNzdgogICNmaWxlX2NtcDogcmVzdWx0cy0xNS0wNS0yMDIwL25vZ3JlcC9ub2N1dC90YWJsZS1BTEwtcHJvY2Vzc2VkLmNzdgogICNmaWxlX2NtcDogcmVzdWx0cy0xNS0wNS0yMDIwL25vZ3JlcC9tZXJnZWQvdGFibGUtQUxMLXByb2Nlc3NlZC5jc3YKICAjZmlsZV9jbXA6IHJlc3VsdHMtMTUtMDUtMjAyMC9ub2dyZXAvbWVyZ2VkUmVzdWx0cy90YWJsZS1BTEwtcHJvY2Vzc2VkLmNzdgogICNmaWxlX2NtcDogcmVzdWx0cy0yMy0wNS0yMDIwL3RhYmxlLUFMTC1wcm9jZXNzZWQuY3N2CiAgI2ZpbGVfYmlnOiByZXN1bHRzLTA1LTA1LTIwMjAvdGFibGUtYmlnLTI1MDM2MTAyLmNzdgogICNmaWxlX2NtcDogcmVzdWx0cy0yOC0wNS0yMDIwL3RhYmxlLUFMTC1wcm9jZXNzZWQuY3N2CiAgZmlsZV9jbXA6IHJlc3VsdHMtMDMtMDYtMjAyMC90YWJsZS1BTEwtcHJvY2Vzc2VkLmNzdgogIGZpbGVfYmlnOiByZXN1bHRzLTExLTA1LTIwMjAvZ3JhcGgvdGFibGUtYmlnLTEwNjUyODk3MDQuY3N2CiAgZmlsZV9kY2E6IERDQXMvcmVzdWx0cy10cmFuc2xhdGlvbi50c3YKICB0aW1lb3V0OiA2MDAgIyBzZWNvbmRzCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0CiAgaHRtbF9kb2N1bWVudDoKICAgIGRmX3ByaW50OiBwYWdlZAogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKLS0tCgpgYGB7cn0KIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIFBSRUFNQkxFCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KCiMgbG9hZCB0aGUgcGxvdHRpbmcgbGlicmFyeQpzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkoZ2dwbG90MikpCmxpYnJhcnkoZ3JpZEV4dHJhKQpsaWJyYXJ5KGdnRXh0cmEpCmxpYnJhcnkodGlrekRldmljZSkKbGlicmFyeShIbWlzYykKbGlicmFyeShwYXN0ZWNzKQoKCgp0aGVtZV9zZXQodGhlbWVfYncoKSkKCm9wdGlvbnMoc2NpcGVuPTk5OSkgICMgdHVybi1vZmYgc2NpZW50aWZpYyBub3RhdGlvbiBsaWtlIDFlKzQ4CgojIHNpemUgb2YgcG9pbnQgZm9yIHNjYXR0ZXJwbG90cwpQT0lOVF9TSVpFID0gMC4xCiNQT0lOVF9TSVpFID0gMQoKIyB0aW1lb3V0ClRJTUVPVVQgPSBwYXJhbXMkdGltZW91dApUSU1FT1VUX1ZBTCA9IDEuMDUgKiBUSU1FT1VUCgpFUlJfVkFMID0gMS4zICogVElNRU9VVAoKIyBzYXR1cmF0ZQojVElNRV9NSU4gPSAwLjAxICMgc2Vjb25kcwpUSU1FX01JTiA9IDAuMSAjIHNlY29uZHMKCkJJR19TSVpFPTMKU01BTExfU0laRT0yCgoKIyBGVU5DVElPTlMKcmVhZF9maWxlIDwtIGZ1bmN0aW9uKGZpbGUpIHsKICBmaWxlbmFtZSA9IHBhc3RlMChmaWxlKQogIGRmIDwtIHJlYWQuY3N2MihmaWxlbmFtZSwKICAgICAgICAgICAgICAgICAgaGVhZGVyPVRSVUUsCiAgICAgICAgICAgICAgICAgIHNlcD0iOyIsCiAgICAgICAgICAgICAgICAgIGRlYz0iLCIsCiAgICAgICAgICAgICAgICAgIGNvbW1lbnQuY2hhcj0iIiwKICAgICAgICAgICAgICAgICAgcXVvdGU9IlwiIiwKICAgICAgICAgICAgICAgICAgc3RyaXAud2hpdGU9VFJVRSwKICAgICAgICAgICAgICAgICAgYWxsb3dFc2NhcGVzPUZBTFNFLAogICAgICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFKQogIAogIAogIHJldHVybihkZikKfQoKcGxvdF9zY2F0dGVyX2xvZyA8LSBmdW5jdGlvbihkZiwgeGxhYiwgeWxhYiwgeHN0cmluZz14bGFiLCB5c3RyaW5nPXlsYWIpIHsKICBwc2NhdCA8LSBnZ3Bsb3QoZGYsIGFlc19zdHJpbmcoeD14bGFiLCB5PXlsYWIpKSArCiAgICBnZW9tX3BvaW50KHNpemU9UE9JTlRfU0laRSkgKwogICAgZ2VvbV9hYmxpbmUoc2l6ZT0wLjEpICsKICAgIGdlb21fdmxpbmUoc2l6ZT0wLjEsIHhpbnRlcmNlcHQ9VElNRU9VVF9WQUwsIGxpbmV0eXBlPSJkYXNoZWQiKSArCiAgICBnZW9tX2hsaW5lKHNpemU9MC4xLCB5aW50ZXJjZXB0PVRJTUVPVVRfVkFMLCBsaW5ldHlwZT0iZGFzaGVkIikgKwogICAgZ2VvbV9ydWcoYWxwaGEgPSAwLjIpICsKICAgIHNjYWxlX3hfbG9nMTAoKSArCiAgICBzY2FsZV95X2xvZzEwKCkgKwogICAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAwLjUpKSArCiAgICAjY29vcmRfZml4ZWQoeGxpbSA9IGMoVElNRV9NSU4sIFRJTUVPVVRfVkFMKSwgeWxpbSA9IGMoMC4xLCBUSU1FT1VUX1ZBTCkpICsKICAgICNjb29yZF9maXhlZCh4bGltID0gYyhUSU1FX01JTiwgVElNRU9VVF9WQUwpLCB5bGltID0gYyhUSU1FX01JTiwgVElNRU9VVF9WQUwpKSArCiAgICAgICAgY29vcmRfZml4ZWQoeGxpbSA9IGMoVElNRV9NSU4sIFRJTUVPVVRfVkFMKSwgeWxpbSA9IGMoVElNRV9NSU4sIFRJTUVPVVRfVkFMKSkgKwogICAgbGFicygKICAgICAgI3RpdGxlPSJUaXRsZSIsCiAgICAgICNzdWJ0aXRsZT0iU3VidGl0bGUiLAogICAgICB4PXhzdHJpbmcsCiAgICAgIHk9eXN0cmluZykKIyAgICB0aGVtZSgKIyAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwgCiMgICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiMgICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsY29sb3VyID0gTkEpLAojICAgICAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsY29sb3VyID0gTkEpCiMgICAgICAgICkKIyAgdGhlbWVfbWluaW1hbCgpCiMgIHRoZW1lX2J3KCkKICMgdGhlbWUocGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOQSkpCiAjIHBzY2F0IDwtIGdnTWFyZ2luYWwocHNjYXQsIHR5cGUgPSAiZGVuc2l0eSIsIHNpemU9MTApCiMgIHBzY2F0IDwtIHBzY2F0ICsgdGhlbWVfYncoKQogIHJldHVybihwc2NhdCkKfQoKbWFrZV90aWt6IDwtIGZ1bmN0aW9uKGZpbGUsIHBpY3R1cmUsIHdpZHRoPTIuNSwgaGVpZ2h0PTIuNSkgewogIGZvbnRfc2l6ZSA8LSAxCiAgdGlreihmaWxlPWZpbGUsIG9uZWZpbGU9VCwgd2lkdGg9d2lkdGgsIGhlaWdodD1oZWlnaHQpCiAgcGxvdChwaWN0dXJlKQogIGdhcmJhZ2UgPC0gZGV2Lm9mZigpCn0KCm1ha2VfcGRmIDwtIGZ1bmN0aW9uKGZpbGUsIHBpY3R1cmUsIHdpZHRoPTUsIGhlaWdodD01KSB7CiAgcGRmKGZpbGU9ZmlsZSwgb25lZmlsZT1ULCB3aWR0aCwgaGVpZ2h0KQogIHBsb3QocGljdHVyZSkKICBnYXJiYWdlIDwtIGRldi5vZmYoKQp9CmBgYAoKYGBge3J9CmRmIDwtIHJlYWRfZmlsZShwYXJhbXMkZmlsZV9jbXApCm9yaWdfc2l6ZSA8LSBucm93KGRmKQoKY29sbmFtZXMoZGYpW2NvbG5hbWVzKGRmKSA9PSAiZG90Lm5ldCJdIDwtICJkb3RuZXQiCmNvbG5hbWVzKGRmKVtuYW1lcyhkZikgPT0gImRvdC5uZXQubWF0Y2hlcyJdIDwtICJkb3RuZXQubWF0Y2hlcyIKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMgU0FOSVRJWkUgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIGNsZWFuIHRoZSBkYXRhCmRmX25ldyA8LSBkZlshZ3JlcGwoIkZpbGUgbm90IGZvdW5kIiwgZGYkc3JtLm1hdGNoZXMpLF0KcHJpbnQocGFzdGUwKCJSZW1vdmluZyAiLCBucm93KGRmKSAtIG5yb3coZGZfbmV3KSwgIiBsaW5lcyBkdWUgdG8gZ2VuZXJhdGlvbiBvZiBpbnB1dCB0ZXh0IikpCmRmIDwtIGRmX25ldwoKdG9vbHMudGltZXMgPC0gYygicmUyZyIsICJjYWQiLCAiY2FtIiwgImdyZXAiLCAic3JtIiwgImRvdG5ldCIpCiN0b29scy50aW1lcyA8LSBjKCJyZTJnIiwgImNhZCIsICJncmVwIiwgInNybSIsICJkb3RuZXQiKQojdG9vbHMudGltZXMgPC0gYygicmUyZyIsICJjYWQiLCAic3JtIiwgImRvdG5ldCIpCnRvb2xzLm1hdGNoZXMgPC0gYygicmUyZy5tYXRjaGVzIiwgImNhZC5tYXRjaGVzIiwgImNhbS5tYXRjaGVzIiwgImdyZXAubWF0Y2hlcyIsICJzcm0ubWF0Y2hlcyIsICJkb3RuZXQubWF0Y2hlcyIpCiN0b29scy5tYXRjaGVzIDwtIGMoInJlMmcubWF0Y2hlcyIsICJjYWQubWF0Y2hlcyIsICJncmVwLm1hdGNoZXMiLCAic3JtLm1hdGNoZXMiLCAiZG90bmV0Lm1hdGNoZXMiKQojdG9vbHMubWF0Y2hlcyA8LSBjKCJyZTJnLm1hdGNoZXMiLCAiY2FkLm1hdGNoZXMiLCAic3JtLm1hdGNoZXMiLCAiZG90bmV0Lm1hdGNoZXMiKQoKIyBjaGVja2luZyBlcnJvcnMKZXJyb3JzLnJlMmcgPC0gbnJvdyhkZltncmVwbCgnRVJSJywgZGYkcmUyZyksXSkKZXJyb3JzLmdyZXAgPC0gbnJvdyhkZltncmVwbCgnRVJSJywgZGYkZ3JlcCksXSkKZXJyb3JzLnNybSA8LSBucm93KGRmW2dyZXBsKCdFUlInLCBkZiRzcm0pLF0pCmVycm9ycy5jYWQgPC0gbnJvdyhkZltncmVwbCgnRVJSJywgZGYkY2FkKSxdKQplcnJvcnMuY2FtIDwtIG5yb3coZGZbZ3JlcGwoJ0VSUicsIGRmJGNhbSksXSkKZXJyb3JzLmRvdG5ldCA8LSBucm93KGRmW2dyZXBsKCdFUlInLCBkZiRkb3RuZXQpLF0pCgojZGYgPC0gZGZbIWdyZXBsKCdFUlInLCBkZiRyZTJnKSxdCiNkZiRyZTJnW2RmJHJlMmcgPT0gJ0VSUiddIDwtIEVSUl9WQUwKZGZbLHRvb2xzLnRpbWVzXVtkZlssdG9vbHMudGltZXNdID09ICdFUlInXSA8LSBFUlJfVkFMCgoKIyBjaGFuZ2UgdGhlIHR5cGUgb2YgY29sdW1ucyBvdGhlciB0aGFuIHRoZSBuYW1lCmZvciAoaSBpbiB0b29scy50aW1lcykgewogIGRmWyxpXSA8LSBzdWIoIiwiLCAiLiIsIGRmWyxpXSkKICBzdXBwcmVzc1dhcm5pbmdzKGRmWyxpXSA8LSBhcy5udW1lcmljKGRmWyxpXSkpCn0KCmZvciAoaSBpbiB0b29scy5tYXRjaGVzKSB7CiAgc3VwcHJlc3NXYXJuaW5ncyhkZlssaV0gPC0gYXMuaW50ZWdlcihkZlssaV0pKQp9CgpkZiRzcmMgPC0gYXMuZmFjdG9yKGRmJHNyYykKCiMgZ2V0IHJpZCBvZiBleHRyZW1hbCB2YWx1ZXMKI2RmWyx0b29scy50aW1lc11bZGZbLHRvb2xzLnRpbWVzXSA+IFRJTUVPVVRdIDwtIFRJTUVPVVRfVkFMCmRmW3Rvb2xzLnRpbWVzXVtpcy5uYShkZlt0b29scy50aW1lc10pXSA8LSBUSU1FT1VUX1ZBTAojZGZbaXMubmEoZGYpXSA8LSBUSU1FT1VUX1ZBTAojZGZbZGYgPT0gMC4wMF0gPC0gVElNRV9NSU4KZGZbLHRvb2xzLnRpbWVzXVtkZlssdG9vbHMudGltZXNdIDwgVElNRV9NSU5dIDwtIFRJTUVfTUlOCgpkZiA8LSBkZlshaXMubmEoZGYkcGF0dGVybiksXQoKIyBjbGVhbiB0aGUgZGF0YQojZGZfbmV3IDwtIGRmW2RmJExpbmVzICE9ICJFUlJPUiBXSElMRSBDT05WRVJUSU5HIFRPIERDQS4iLF0KI3ByaW50KHBhc3RlMCgiUmVtb3ZpbmcgIiwgbnJvdyhkZikgLSBucm93KGRmX25ldyksICIgbGluZXMgZHVlIHRvIGNvbnZlcnRpbmcgdG8gRENBIGVycm9yIikpCiNkZiA8LSBkZl9uZXcKCgoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIENPVU5USU5HIFRJTUVPVVRTICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCnRpbWVvdXRzLnJlMmcgPC0gbnJvdyhkZltkZiRyZTJnID09IFRJTUVPVVRfVkFMLF0pCnRpbWVvdXRzLmNhZCA8LSBucm93KGRmW2RmJGNhZCA9PSBUSU1FT1VUX1ZBTCxdKQp0aW1lb3V0cy5jYW0gPC0gbnJvdyhkZltkZiRjYW0gPT0gVElNRU9VVF9WQUwsXSkKdGltZW91dHMuZ3JlcCA8LSBucm93KGRmW2RmJGdyZXAgPT0gVElNRU9VVF9WQUwsXSkKdGltZW91dHMuc3JtIDwtIG5yb3coZGZbZGYkc3JtID09IFRJTUVPVVRfVkFMLF0pCnRpbWVvdXRzLmRvdG5ldCA8LSBucm93KGRmW2RmJGRvdG5ldCA9PSBUSU1FT1VUX1ZBTCxdKQp0aW1lb3V0cy5yZTIuYW5kLmNhIDwtIG5yb3coZGZbZGYkY2FkID09IFRJTUVPVVRfVkFMICYgZGYkcmUyZyA9PSBUSU1FT1VUX1ZBTCxdKQoKIyB8ICoqVGltZW91dHMgZ3JlcCoqICAgIHwgYHIgdGltZW91dHMuZ3JlcGAgIHwKYGBgCgpUaGVzZSBhcmUgcmVzdWx0cyBvZiB0aGUgZXhwZXJpbWVudHMgZm9yIENvdW50aW5nIFNldCBBdXRvbWF0YToKCnwgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfCB8CnwtLS0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS06fC18CnwgKipGaWxlKiogICAgICAgICAgICB8IGByIHBhcmFtcyRmaWxlX2NtcGAgfAp8ICoqVGltZW91dCoqICAgICAgICAgfCBgciBUSU1FT1VUYCBzICAgICAgIHwKfCAqKlRJTUVPVVRfVkFMKiogICAgIHwgYHIgVElNRU9VVF9WQUxgIHMgICB8CnwgKipUSU1FX01JTioqICAgICAgICB8IGByIFRJTUVfTUlOYCAgICAgICAgfAp8ICoqb3JpZ2luYWwgc2l6ZSoqICAgfCBgciBvcmlnX3NpemVgICAgICAgIHwKfCAqKkJlbmNobWFya3MqKiAgICAgIHwgYHIgbnJvdyhkZilgICAgICAgICB8CnwgKipUaW1lb3V0cyBDQSoqICAgICB8IGByIHRpbWVvdXRzLmNhZGAgICAgIHwKfCAqKlRpbWVvdXRzIENBTSoqICAgICB8IGByIHRpbWVvdXRzLmNhbWAgICAgIHwKfCAqKlRpbWVvdXRzIFJFMioqICAgIHwgYHIgdGltZW91dHMucmUyZ2AgICAgfAp8ICoqVGltZW91dHMgU1JNKiogICAgfCBgciB0aW1lb3V0cy5zcm1gICAgIHwgCnwgKipUaW1lb3V0cyBncmVwKiogICB8IGByIHRpbWVvdXRzLmdyZXBgICAgIHwgCnwgKipUaW1lb3V0cyAuTkVUKiogICB8IGByIHRpbWVvdXRzLmRvdG5ldGAgIHwKfCAqKkVycm9ycyBDQSoqICAgICB8IGByIGVycm9ycy5jYWRgICAgICB8CnwgKipFcnJvcnMgQ0FNKiogICAgIHwgYHIgZXJyb3JzLmNhbWAgICAgIHwKfCAqKkVycm9ycyBSRTIqKiAgICB8IGByIGVycm9ycy5yZTJnYCAgICB8IChyZW1vdmVkKSB8CnwgKipFcnJvcnMgU1JNKiogICAgfCBgciBlcnJvcnMuc3JtYCAgICB8IAp8ICoqRXJyb3JzIGdyZXAqKiAgIHwgYHIgZXJyb3JzLmdyZXBgICAgIHwgCnwgKipFcnJvcnMgLk5FVCoqICAgfCBgciBlcnJvcnMuZG90bmV0YCAgfAoKCgpgYGB7cn0KZGYKYGBgCgojIFN1bW1hcnkgb2YgYmVuY2htYXJrcwoKYGBge3J9CmRmX2JlbmNoZXMgPC0gZGF0YS5mcmFtZShzdW1tYXJ5KGRmJHNyYykpCmRmX2JlbmNoZXMKYGBgCgojIFNhbml0eSBjaGVja3MKCmBgYHtyfQpkZiRpbmNvbnNpc3RlbnQgPC0gZGYkcmUyZy5tYXRjaGVzICE9IGRmJGdyZXAubWF0Y2hlcyB8IGRmJHJlMmcubWF0Y2hlcyAhPSBkZiRzcm0ubWF0Y2hlcyB8IGRmJHJlMmcubWF0Y2hlcyAhPSBkZiRkb3RuZXQubWF0Y2hlcyB8IGRmJHJlMmcubWF0Y2hlcyAhPSBkZiRjYWQubWF0Y2hlcwoKI2RmJGluY29uc2lzdGVudCA8LSBkZiRyZTJnLm1hdGNoZXMgIT0gZGYkc3JtLm1hdGNoZXMgfCBkZiRyZTJnLm1hdGNoZXMgIT0gZGYkZG90bmV0Lm1hdGNoZXMgfCBkZiRyZTJnLm1hdGNoZXMgIT0gZGYkY2FkLm1hdGNoZXMKCmRmJGdyZXAucmUyLm1pc21hdGNoIDwtICFpcy5uYShkZiRyZTJnLm1hdGNoZXMpICYgIWlzLm5hKGRmJGdyZXAubWF0Y2hlcykgJiBkZiRyZTJnLm1hdGNoZXMgIT0gZGYkZ3JlcC5tYXRjaGVzCmRmX2dyZXBfcmUyX21pc21hdGNoIDwtIGRmW2RmJGdyZXAucmUyLm1pc21hdGNoLF0KCmRmJHJlMi5jYS5taXNtYXRjaCA8LSAhaXMubmEoZGYkcmUyZy5tYXRjaGVzKSAmICFpcy5uYShkZiRjYWQubWF0Y2hlcykgJiBkZiRyZTJnLm1hdGNoZXMgIT0gZGYkY2FkLm1hdGNoZXMKZGZfcmUyX2NhX21pc21hdGNoIDwtIGRmW2RmJHJlMi5jYS5taXNtYXRjaCxdCgpkZiA8LSBkZltpcy5uYShkZiRyZTJnLm1hdGNoZXMpIHwgaXMubmEoZGYkZ3JlcC5tYXRjaGVzKSB8IGRmJHJlMmcubWF0Y2hlcyA9PSBkZiRjYWQubWF0Y2hlcyxdCgpgYGAKCnwgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgICB8CnwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tOnwgLS0tLS0tLTp8CnwgKipDQSBhbmQgUkUyIG1pc21hdGNoZWQqKiAgIHwgYHIgbnJvdyhkZl9yZTJfY2FfbWlzbWF0Y2gpYCAgIHwgKHJlbW92ZWQpIHwKfCAqKmdyZXAgYW5kIFJFMiBtaXNtYXRjaGVkKiogfCBgciBucm93KGRmX2dyZXBfcmUyX21pc21hdGNoKWAgfAoKCiMjIFJFMiBhbmQgQ0EgbWlzbWF0Y2hlcwpgYGB7cn0KZGZfcmUyX2NhX21pc21hdGNoCmBgYAoKCgojIFNjYXR0ZXIgUGxvdHMKCmBgYHtyfQoKcGxvdC5hbmQudGlreiA8LSBmdW5jdGlvbihkZiwgeGxhYiwgeWxhYiwgeHN0cmluZz14bGFiLCB5c3RyaW5nPXlsYWIsIHdpZHRoPTQsIGhlaWdodD13aWR0aCkgewogIHBpYyA8LSBwbG90X3NjYXR0ZXJfbG9nKGRmLCB4bGFiLCB5bGFiLCB4c3RyaW5nLCB5c3RyaW5nKQogICNtYWtlX3Rpa3oocGFzdGUwKCJmaWdzLyIsIHhsYWIsICItdnMtIiwgeWxhYiwgIi50aWt6IiksIHBpYywgd2lkdGgsIGhlaWdodCkKICBtYWtlX3BkZihwYXN0ZTAoImZpZ3MvIiwgeGxhYiwgIi12cy0iLCB5bGFiLCAiLnBkZiIpLCBwaWMsIHdpZHRoLCBoZWlnaHQpCiAgcGljCn0KCmRmX2dyZXAgPC0gZGZbaXMubmEoZGYkZ3JlcC5tYXRjaGVzKSB8IGlzLm5hKGRmJGNhZC5tYXRjaGVzKSB8IGRmJGdyZXAubWF0Y2hlcyA9PSBkZiRjYWQubWF0Y2hlcyxdCgpwbG90MSA8LSBwbG90LmFuZC50aWt6KGRmLCAicmUyZyIsICJjYWQiLCB4c3RyaW5nPSJSRTIgW3NdIiwgeXN0cmluZz0iQ0EgW3NdIiwgd2lkdGg9QklHX1NJWkUpCnBsb3QyIDwtIHBsb3QuYW5kLnRpa3ooZGZfZ3JlcCwgImdyZXAiLCAiY2FkIiwgeHN0cmluZz0iZ3JlcCBbc10iLCB5c3RyaW5nPSJDQSBbc10iLCB3aWR0aD1TTUFMTF9TSVpFKQpwbG90MyA8LSBwbG90LmFuZC50aWt6KGRmLCAic3JtIiwgImNhZCIsIHhzdHJpbmc9IlNSTSBbc10iLCB5c3RyaW5nPSJDQSBbc10iLCB3aWR0aD1TTUFMTF9TSVpFKQpwbG90NCA8LSBwbG90LmFuZC50aWt6KGRmLCAiZG90bmV0IiwgImNhZCIsIHhzdHJpbmc9Ii5ORVQgW3NdIiwgeXN0cmluZz0iQ0EgW3NdIiwgd2lkdGg9U01BTExfU0laRSkKcGxvdDUgPC0gcGxvdC5hbmQudGlreihkZiwgInNybSIsICJyZTJnIikKcGxvdDYgPC0gcGxvdC5hbmQudGlreihkZiwgImdyZXAiLCAicmUyZyIpCnBsb3Q3IDwtIHBsb3QuYW5kLnRpa3ooZGYsICJkb3RuZXQiLCAicmUyZyIpCnBsb3Q4IDwtIHBsb3QuYW5kLnRpa3ooZGYsICJzcm0iLCAiZ3JlcCIpCnBsb3Q5IDwtIHBsb3QuYW5kLnRpa3ooZGYsICJkb3RuZXQiLCAiZ3JlcCIpCnBsb3QxMCA8LSBwbG90LmFuZC50aWt6KGRmLCAiZG90bmV0IiwgInNybSIpCgpwbG90MTEgPC0gcGxvdC5hbmQudGlreihkZiwgInJlMmciLCAiY2FtIiwgeHN0cmluZz0iUkUyIFtzXSIsIHlzdHJpbmc9IkNBTSBbc10iLCB3aWR0aD1CSUdfU0laRSkKcGxvdDEyIDwtIHBsb3QuYW5kLnRpa3ooZGZfZ3JlcCwgImdyZXAiLCAiY2FtIiwgeHN0cmluZz0iZ3JlcCBbc10iLCB5c3RyaW5nPSJDQU0gW3NdIiwgd2lkdGg9U01BTExfU0laRSkKcGxvdDEzIDwtIHBsb3QuYW5kLnRpa3ooZGYsICJzcm0iLCAiY2FtIiwgeHN0cmluZz0iU1JNIFtzXSIsIHlzdHJpbmc9IkNBIFtzXSIsIHdpZHRoPVNNQUxMX1NJWkUpCnBsb3QxNCA8LSBwbG90LmFuZC50aWt6KGRmLCAiZG90bmV0IiwgImNhbSIsIHhzdHJpbmc9Ii5ORVQgW3NdIiwgeXN0cmluZz0iQ0EgW3NdIiwgd2lkdGg9U01BTExfU0laRSkKcGxvdDE1IDwtIHBsb3QuYW5kLnRpa3ooZGYsICJjYWQiLCAiY2FtIiwgeHN0cmluZz0iQ0FEIFtzXSIsIHlzdHJpbmc9IkNBTSBbc10iLCB3aWR0aD1CSUdfU0laRSkKCgojZ3JpZC5hcnJhbmdlKHBsb3QxLCBwbG90MywgbmNvbCA9IDIpCiNncmlkLmFycmFuZ2UocGxvdDQsIHBsb3Q1LCBuY29sID0gMikKI2dyaWQuYXJyYW5nZShwbG90NywgcGxvdDEwLCBuY29sID0gMikKCmdyaWQuYXJyYW5nZShwbG90MSwgcGxvdDIsIG5jb2wgPSAyKQpncmlkLmFycmFuZ2UocGxvdDMsIHBsb3Q0LCBuY29sID0gMikKZ3JpZC5hcnJhbmdlKHBsb3Q1LCBwbG90NiwgbmNvbCA9IDIpCmdyaWQuYXJyYW5nZShwbG90NywgcGxvdDgsIG5jb2wgPSAyKQpncmlkLmFycmFuZ2UocGxvdDksIHBsb3QxMCwgbmNvbCA9IDIpCgpncmlkLmFycmFuZ2UocGxvdDExLCBwbG90MTIsIG5jb2wgPSAyKQpncmlkLmFycmFuZ2UocGxvdDEzLCBwbG90MTQsIG5jb2wgPSAyKQpncmlkLmFycmFuZ2UocGxvdDE1LCBuY29sID0gMikKYGBgCgojIEhpc3RvZ3JhbXMKCmBgYHtyfQpoaXN0MSA8LSBnZ3Bsb3QoZGYsIGFlcyh4PXJlMmcpKSArCiAgZ2VvbV9oaXN0b2dyYW0oY29sb3I9ImJsdWUiLCBmaWxsPSJsaWdodGJsdWUiKSArCiAgc2NhbGVfeV9sb2cxMCgpCgpoaXN0MiA8LSBnZ3Bsb3QoZGYsIGFlcyh4PWNhZCkpICsgCiAgZ2VvbV9oaXN0b2dyYW0oY29sb3I9ImJsdWUiLCBmaWxsPSJsaWdodGJsdWUiKSArCiAgc2NhbGVfeV9sb2cxMCgpCgpoaXN0MyA8LSBnZ3Bsb3QoZGYsIGFlcyh4PXNybSkpICsgCiAgZ2VvbV9oaXN0b2dyYW0oY29sb3I9ImJsdWUiLCBmaWxsPSJsaWdodGJsdWUiKSArCiAgc2NhbGVfeV9sb2cxMCgpCgojaGlzdDQgPC0gZ2dwbG90KGRmLCBhZXMoeD1ncmVwKSkgKyAKIyAgZ2VvbV9oaXN0b2dyYW0oY29sb3I9ImJsdWUiLCBmaWxsPSJsaWdodGJsdWUiKSArCiMgIHNjYWxlX3lfbG9nMTAoKQoKaGlzdDUgPC0gZ2dwbG90KGRmLCBhZXMoeD1kb3RuZXQpKSArIAogIGdlb21faGlzdG9ncmFtKGNvbG9yPSJibHVlIiwgZmlsbD0ibGlnaHRibHVlIikgKwogIHNjYWxlX3lfbG9nMTAoKQoKZ3JpZC5hcnJhbmdlKGhpc3QxLCBoaXN0MiwgbmNvbCA9IDIpCmdyaWQuYXJyYW5nZShoaXN0MywgaGlzdDUsIG5jb2wgPSAyKQojZ3JpZC5hcnJhbmdlKGhpc3Q1LCBuY29sID0gMikKCgpgYGAKCiMgRmluZGluZyB3aW5uZXJzCgpgYGB7cn0KZGYkbWluIDwtcG1pbihkZiRncmVwLCBkZiRzcm0sIGRmJHJlMmcsIGRmJGRvdG5ldCwgZGYkY2FkLCBkZiRjYW0pCiNkZiRtaW4gPC1wbWluKGRmJGdyZXAsIGRmJHNybSwgZGYkcmUyZywgZGYkZG90bmV0LCBkZiRjYWQpCmRmJGVuZW15Lm1pbiA8LSBwbWluKGRmJGdyZXAsIGRmJHNybSwgZGYkcmUyZywgZGYkZG90bmV0KQojZGYkbWluIDwtcG1pbihkZiRzcm0sIGRmJHJlMmcsIGRmJGRvdG5ldCwgZGYkY2FkKQojZGYkZW5lbXkubWluIDwtIHBtaW4oZGYkc3JtLCBkZiRyZTJnLCBkZiRkb3RuZXQpCgp3aW5uZXJzLmdyZXAgPC0gbnJvdyhkZltkZiRtaW4gPT0gZGYkZ3JlcCxdKQp3aW5uZXJzLnJlMiA8LSBucm93KGRmW2RmJG1pbiA9PSBkZiRyZTJnLF0pCndpbm5lcnMuY2EgPC0gbnJvdyhkZltkZiRtaW4gPT0gZGYkY2FkLF0pCndpbm5lcnMuY2FtIDwtIG5yb3coZGZbZGYkbWluID09IGRmJGNhbSxdKQp3aW5uZXJzLnNybSA8LSBucm93KGRmW2RmJG1pbiA9PSBkZiRzcm0sXSkKd2lubmVycy5kb3RuZXQgPC0gbnJvdyhkZltkZiRtaW4gPT0gZGYkZG90bmV0LF0pCgp3aW5uZXJzLmNhLm92ZXIucmUyIDwtIG5yb3coZGZbZGYkY2FkIDw9IGRmJHJlMmcsXSkKd2lubmVycy5jYS5vdmVyLmdyZXAgPC0gbnJvdyhkZltkZl9ncmVwJGNhZCA8PSBkZl9ncmVwJGdyZXAsXSkKd2lubmVycy5jYS5vdmVyLnNybSA8LSBucm93KGRmW2RmJGNhZCA8PSBkZiRzcm0sXSkKd2lubmVycy5jYS5vdmVyLmRvdG5ldCA8LSBucm93KGRmW2RmJGNhZCA8PSBkZiRkb3RuZXQsXSkKCndpbm5lcnMuY2FtLm92ZXIucmUyIDwtIG5yb3coZGZbZGYkY2FtIDw9IGRmJHJlMmcsXSkKd2lubmVycy5jYW0ub3Zlci5ncmVwIDwtIG5yb3coZGZbZGZfZ3JlcCRjYW0gPD0gZGZfZ3JlcCRncmVwLF0pCndpbm5lcnMuY2FtLm92ZXIuc3JtIDwtIG5yb3coZGZbZGYkY2FtIDw9IGRmJHNybSxdKQp3aW5uZXJzLmNhbS5vdmVyLmRvdG5ldCA8LSBucm93KGRmW2RmJGNhbSA8PSBkZiRkb3RuZXQsXSkKd2lubmVycy5jYW0ub3Zlci5jYWQgPC0gbnJvdyhkZltkZiRjYW0gPD0gZGYkY2FkLF0pCgoKCndpbm5lcnMuMTAuY2Eub3Zlci5yZTIgPC0gbnJvdyhkZlsxMCogZGYkY2FkIDw9IGRmJHJlMmcsXSkKd2lubmVycy4xMC5jYS5vdmVyLmdyZXAgPC0gbnJvdyhkZlsxMCogZGZfZ3JlcCRjYWQgPD0gZGZfZ3JlcCRncmVwLF0pCndpbm5lcnMuMTAuY2Eub3Zlci5zcm0gPC0gbnJvdyhkZlsxMCogZGYkY2FkIDw9IGRmJHNybSxdKQp3aW5uZXJzLjEwLmNhLm92ZXIuZG90bmV0IDwtIG5yb3coZGZbMTAqIGRmJGNhZCA8PSBkZiRkb3RuZXQsXSkKCndpbm5lcnMuMTAwLmNhLm92ZXIucmUyIDwtIG5yb3coZGZbMTAwKiBkZiRjYWQgPD0gZGYkcmUyZyxdKQp3aW5uZXJzLjEwMC5jYS5vdmVyLmdyZXAgPC0gbnJvdyhkZlsxMDAqIGRmX2dyZXAkY2FkIDw9IGRmX2dyZXAkZ3JlcCxdKQp3aW5uZXJzLjEwMC5jYS5vdmVyLnNybSA8LSBucm93KGRmWzEwMCogZGYkY2FkIDw9IGRmJHNybSxdKQp3aW5uZXJzLjEwMC5jYS5vdmVyLmRvdG5ldCA8LSBucm93KGRmWzEwMCogZGYkY2FkIDw9IGRmJGRvdG5ldCxdKQoKbG9uZ2VyLnRoYW4uMTAuc2Vjb25kcy5jYSA8LSBucm93KGRmW2RmJGNhZCA+IDEwLF0pCmxvbmdlci50aGFuLjEwLnNlY29uZHMucmUyIDwtIG5yb3coZGZbZGYkcmUyZyA+IDEwLF0pCmxvbmdlci50aGFuLjEwLnNlY29uZHMuc3JtIDwtIG5yb3coZGZbZGYkc3JtID4gMTAsXSkKbG9uZ2VyLnRoYW4uMTAuc2Vjb25kcy5kb3RuZXQgPC0gbnJvdyhkZltkZiRkb3RuZXQgPiAxMCxdKQpsb25nZXIudGhhbi4xMC5zZWNvbmRzLmdyZXAgPC0gbnJvdyhkZltkZiRncmVwID4gMTAsXSkKCgpgYGAKCnwgKipXaW5uZXIqKiAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfAp8LS0tLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tOnwKfCAqKkNBKiogICAgIHwgYHIgd2lubmVycy5jYWAgICAgIHwKfCAqKlJFMioqICAgIHwgYHIgd2lubmVycy5yZTJgICAgIHwKfCAqKlNSTSoqICAgIHwgYHIgd2lubmVycy5zcm1gICAgIHwgCnwgKiouTkVUKiogICAgfCBgciB3aW5uZXJzLmRvdG5ldGAgIHwKfCAqKmdyZXAqKiAgICB8IGByIHdpbm5lcnMuZ3JlcGAgIHwKCnwgKipXaW5zIG9mIENBIG92ZXIqKiAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfAp8LS0tLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tOnwKfCAqKlJFMioqICAgIHwgYHIgd2lubmVycy5jYS5vdmVyLnJlMmAgLyBgciBucm93KGRmKWAgICB8CnwgKipTUk0qKiAgICB8IGByIHdpbm5lcnMuY2Eub3Zlci5zcm1gIC8gYHIgbnJvdyhkZilgICAgIHwgCnwgKiouTkVUKiogICAgfCBgciB3aW5uZXJzLmNhLm92ZXIuZG90bmV0YCAvIGByIG5yb3coZGYpYCAgfAp8ICoqZ3JlcCoqICAgIHwgYHIgd2lubmVycy5jYS5vdmVyLmdyZXBgIC8gYHIgbnJvdyhkZl9ncmVwKWAgIHwKCnwgKipXaW5zIG9mIENBTSBvdmVyKiogICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwKfC0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLTp8CnwgKipSRTIqKiAgICB8IGByIHdpbm5lcnMuY2FtLm92ZXIucmUyYCAvIGByIG5yb3coZGYpYCAgIHwKfCAqKlNSTSoqICAgIHwgYHIgd2lubmVycy5jYW0ub3Zlci5zcm1gIC8gYHIgbnJvdyhkZilgICAgIHwgCnwgKiouTkVUKiogICAgfCBgciB3aW5uZXJzLmNhbS5vdmVyLmRvdG5ldGAgLyBgciBucm93KGRmKWAgIHwKfCAqKmdyZXAqKiAgICB8IGByIHdpbm5lcnMuY2FtLm92ZXIuZ3JlcGAgLyBgciBucm93KGRmX2dyZXApYCAgfAp8ICoqY2FkKiogICAgfCBgciB3aW5uZXJzLmNhbS5vdmVyLmNhZGAgLyBgciBucm93KGRmKWAgIHwKCnwgKipXaW5zIG9mIGF0IGxlYXN0IDEwIHRpbWVzIG9mIENBIG92ZXIqKiAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfAp8LS0tLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tOnwKfCAqKlJFMioqICAgIHwgYHIgd2lubmVycy4xMC5jYS5vdmVyLnJlMmAgLyBgciBucm93KGRmKWAgICB8CnwgKipTUk0qKiAgICB8IGByIHdpbm5lcnMuMTAuY2Eub3Zlci5zcm1gIC8gYHIgbnJvdyhkZilgICAgIHwgCnwgKiouTkVUKiogICAgfCBgciB3aW5uZXJzLjEwLmNhLm92ZXIuZG90bmV0YCAvIGByIG5yb3coZGYpYCAgfAp8ICoqZ3JlcCoqICAgIHwgYHIgd2lubmVycy4xMC5jYS5vdmVyLmdyZXBgIC8gYHIgbnJvdyhkZl9ncmVwKWAgIHwKCnwgKipXaW5zIG9mIGF0IGxlYXN0IDEwMCB0aW1lcyBvZiBDQSBvdmVyKiogICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwKfC0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLTp8CnwgKipSRTIqKiAgICB8IGByIHdpbm5lcnMuMTAwLmNhLm92ZXIucmUyYCAvIGByIG5yb3coZGYpYCAgIHwKfCAqKlNSTSoqICAgIHwgYHIgd2lubmVycy4xMDAuY2Eub3Zlci5zcm1gIC8gYHIgbnJvdyhkZilgICAgIHwgCnwgKiouTkVUKiogICAgfCBgciB3aW5uZXJzLjEwMC5jYS5vdmVyLmRvdG5ldGAgLyBgciBucm93KGRmKWAgIHwKfCAqKmdyZXAqKiAgICB8IGByIHdpbm5lcnMuMTAwLmNhLm92ZXIuZ3JlcGAgLyBgciBucm93KGRmX2dyZXApYCAgfAoKfCAqKkxvbmdlciB0aGFuIDEwIHMqKiAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgfAp8LS0tLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tOnwKfCAqKkNBKiogICAgIHwgYHIgbG9uZ2VyLnRoYW4uMTAuc2Vjb25kcy5jYWAgICAgIHwKfCAqKlJFMioqICAgIHwgYHIgbG9uZ2VyLnRoYW4uMTAuc2Vjb25kcy5yZTJgICAgIHwKfCAqKlNSTSoqICAgIHwgYHIgbG9uZ2VyLnRoYW4uMTAuc2Vjb25kcy5zcm1gICAgIHwgCnwgKiouTkVUKiogICAgfCBgciBsb25nZXIudGhhbi4xMC5zZWNvbmRzLmRvdG5ldGAgIHwKfCAqKmdyZXAqKiAgICB8IGByIGxvbmdlci50aGFuLjEwLnNlY29uZHMuZ3JlcGAgIHwKCgoKYGBge3J9CnBsb3QuYW5kLnRpa3ooZGYsICJlbmVteS5taW4iLCAiY2FkIiwgeHN0cmluZz0iYmVzdCBlbmVteSIsIHlzdHJpbmc9IkNBIFtzXSIpCmBgYAoKIyBIb3cgbXVjaCB3ZSBhcmUgYmV0dGVyIHRoYW4gUkUyCgpgYGB7cn0KZGYkcmUyLnZzLmNhIDwtIGRmJHJlMmcgLyBkZiRjYWQKZGZfc29ydGVkIDwtIGRmW29yZGVyKGRmJHJlMi52cy5jYSwgZGVjcmVhc2luZz1UUlVFKSxdCgojZGZfc29ydGVkWyxjKCJzcmMiLCAicGF0dGVybiIsICJmaWxlIiwgInJlMmciLCAiY2FkIiwgInJlMi52cy5jYSIsICJyZTIuY2EubWlzbWF0Y2giKV0KZGZfc29ydGVkIDwtIGRmX3NvcnRlZFsxOjEwLGMoInNyYyIsICJwYXR0ZXJuIiwgImZpbGUiLCB0b29scy50aW1lcyldCmRmX3NvcnRlZApoYWYgPC0gbGF0ZXgoZGZfc29ydGVkLAogICAgICAgICAgICAgZmlsZT0iZmlncy9iZXN0X3Jlc3VsdHMudGV4IiwKICAgICAgICAgICAgIGJvb2t0YWJzPVRSVUUsCiAgICAgICAgICAgICB0YWJsZS5lbnY9RkFMU0UsCiAgICAgICAgICAgICBjZW50ZXI9Im5vbmUiKQpgYGAKCiMgSGFyZGVzdCBjYXNlcyBmb3IgdmFyaW91cyB0b29scwpgYGB7cn0KZGYucHJlLnNvcnQgPC0gZGYKZGYucHJlLnNvcnQgPC0gZGYucHJlLnNvcnRbb3JkZXIoZGYucHJlLnNvcnQkcmUyZywgZGVjcmVhc2luZz1UUlVFKSxdCmRmLnByZS5zb3J0IDwtIGRmLnByZS5zb3J0W29yZGVyKGRmLnByZS5zb3J0JGNhZCwgZGVjcmVhc2luZz1UUlVFKSxdCmRmLnByZS5zb3J0IDwtIGRmLnByZS5zb3J0W29yZGVyKGRmLnByZS5zb3J0JGdyZXAsIGRlY3JlYXNpbmc9VFJVRSksXQpkZi5wcmUuc29ydCA8LSBkZi5wcmUuc29ydFtvcmRlcihkZi5wcmUuc29ydCRzcm0sIGRlY3JlYXNpbmc9VFJVRSksXQpkZi5wcmUuc29ydCA8LSBkZi5wcmUuc29ydFtvcmRlcihkZi5wcmUuc29ydCRkb3RuZXQsIGRlY3JlYXNpbmc9VFJVRSksXQogIAoKZGYucmUyLmhhcmQgPC0gZGYucHJlLnNvcnRbb3JkZXIoZGYucHJlLnNvcnQkcmUyZywgZGVjcmVhc2luZz1UUlVFKSxdCmRmLmNhLmhhcmQgPC0gZGYucHJlLnNvcnRbb3JkZXIoZGYucHJlLnNvcnQkY2FkLCBkZWNyZWFzaW5nPVRSVUUpLF0KZGYuZ3JlcC5oYXJkIDwtIGRmLnByZS5zb3J0W29yZGVyKGRmLnByZS5zb3J0JGdyZXAsIGRlY3JlYXNpbmc9VFJVRSksXQpkZi5zcm0uaGFyZCA8LSBkZi5wcmUuc29ydFtvcmRlcihkZi5wcmUuc29ydCRzcm0sIGRlY3JlYXNpbmc9VFJVRSksXQpkZi5kb3RuZXQuaGFyZCA8LSBkZi5wcmUuc29ydFtvcmRlcihkZi5wcmUuc29ydCRkb3RuZXQsIGRlY3JlYXNpbmc9VFJVRSksXQoKZGYucmUyLmhhcmQKZGYuY2EuaGFyZApkZi5ncmVwLmhhcmQKZGYuc3JtLmhhcmQKZGYuZG90bmV0LmhhcmQKCmBgYAoKIyBTb3J0aW5nIGFjY29yZGluZyB0byB0b3RhbCB0aW1lCmBgYHtyfQpkZiR0b3RhbC50aW1lIDwtIGRmJGdyZXAgKyBkZiRyZTJnICsgZGYkY2FkICsgZGYkc3JtICsgZGYkZG90bmV0CgpkZl9zb3J0ZWQgPC0gZGZbb3JkZXIoZGYkdG90YWwudGltZSwgZGVjcmVhc2luZz1UUlVFKSxdCmRmX3NvcnRlZAoKZGZfc29ydGVkIDwtIGRmX3NvcnRlZFsxOjEwLGMoInNyYyIsICJwYXR0ZXJuIiwgImZpbGUiLCB0b29scy50aW1lcyldCmhhZiA8LSBsYXRleChkZl9zb3J0ZWQsCiAgICAgICAgICAgICBmaWxlPSJmaWdzL3RvdGFsX3RpbWUudGV4IiwKICAgICAgICAgICAgIGJvb2t0YWJzPVRSVUUsCiAgICAgICAgICAgICB0YWJsZS5lbnY9RkFMU0UsCiAgICAgICAgICAgICBjZW50ZXI9Im5vbmUiKQpgYGAKIyBTb3J0aW5nIGFjY29yZGluZyB0byBlbmVteS5taW4KYGBge3J9CmRmX3NvcnRlZCA8LSBkZltvcmRlcihkZiRlbmVteS5taW4sIGRlY3JlYXNpbmc9VFJVRSksXQpkZl9zb3J0ZWQKCmRmX3NvcnRlZCA8LSBkZl9zb3J0ZWRbMToxMCxjKCJzcmMiLCAicGF0dGVybiIsICJmaWxlIiwgdG9vbHMudGltZXMpXQpoYWYgPC0gbGF0ZXgoZGZfc29ydGVkLAogICAgICAgICAgICAgZmlsZT0iZmlncy9lbmVteV9taW4udGV4IiwKICAgICAgICAgICAgIGJvb2t0YWJzPVRSVUUsCiAgICAgICAgICAgICB0YWJsZS5lbnY9RkFMU0UsCiAgICAgICAgICAgICBjZW50ZXI9Im5vbmUiKQpgYGAKCiMgU3VtbWFyaWVzCgpgYGB7cn0KZGZfZm9yX3N1bW1hcnkgPC0gZGZbLGMoInJlMmciLCAiY2FkIiwgImNhbSIsICJzcm0iLCAiZG90bmV0IiwgImdyZXAiKV0KI2RmLnN1bW1hcnkgPC0gZG8uY2FsbChjYmluZCwgbGFwcGx5KGRmX2Zvcl9zdW1tYXJ5LCBzdW1tYXJ5KSkKI2RmLnN1bW1hcnkKCmRlc2MgPC0gc3RhdC5kZXNjKGRmX2Zvcl9zdW1tYXJ5KQpkZXNjCmhhZiA8LSBsYXRleChkZXNjLAogICAgICAgICAgICAgZmlsZT0iZmlncy9zdGF0cy50ZXgiLAogICAgICAgICAgICAgYm9va3RhYnM9VFJVRSwKICAgICAgICAgICAgIHRhYmxlLmVudj1GQUxTRSwKICAgICAgICAgICAgIGNlbnRlcj0ibm9uZSIpCgpgYGAKCiMgRXhwZXJpbWVudHMgd2l0aCBpbmNyZWFzaW5nIGNvdW50ZXIgdmFsdWUKCmBgYHtyfQpiaWcgPC0gcmVhZF9maWxlKHBhcmFtcyRmaWxlX2JpZykKYmlnJHJlMmcgPC0gc3ViKCIsIiwgIi4iLCBiaWckcmUyZykKYmlnJHJlMmcgPC0gYXMubnVtZXJpYyhiaWckcmUyZykKCmJpZwpgYGAKCgpgYGB7cn0KCnRvZ2V0aGVyIDwtIGJpZ1ssIGMoIkNvdW50ZXIiLCAicmUyZyIpXQpuYW1lcyh0b2dldGhlcilbMl0gPC0gInRpbWUiCnRvZ2V0aGVyJGFwcHJvYWNoIDwtICJSRTIiCgp0bXAgPC0gYmlnWywgYygiQ291bnRlciIsICJjYWQiKV0KbmFtZXModG1wKVsyXSA8LSAidGltZSIKdG1wJGFwcHJvYWNoIDwtICJDQSIKdG9nZXRoZXIgPC0gcmJpbmQodG9nZXRoZXIsIHRtcCkKCnRtcCA8LSBiaWdbLCBjKCJDb3VudGVyIiwgInNybSIpXQpuYW1lcyh0bXApWzJdIDwtICJ0aW1lIgp0bXAkYXBwcm9hY2ggPC0gIlNSTSIKdG9nZXRoZXIgPC0gcmJpbmQodG9nZXRoZXIsIHRtcCkKCnRtcCA8LSBiaWdbLCBjKCJDb3VudGVyIiwgImRvdC5uZXQiKV0KbmFtZXModG1wKVsyXSA8LSAidGltZSIKdG1wJGFwcHJvYWNoIDwtICIuTkVUIgp0b2dldGhlciA8LSByYmluZCh0b2dldGhlciwgdG1wKQoKdG1wIDwtIGJpZ1ssIGMoIkNvdW50ZXIiLCAiZ3JlcCIpXQpuYW1lcyh0bXApWzJdIDwtICJ0aW1lIgp0bXAkYXBwcm9hY2ggPC0gImdyZXAiCnRvZ2V0aGVyIDwtIHJiaW5kKHRvZ2V0aGVyLCB0bXApCgpCSUdfU1RFUD0xMDAKCiMgcmVtb3ZlIHRvbyBtYW55IHBvaW50cwp0b2dldGhlciA8LSB0b2dldGhlclt0b2dldGhlciRDb3VudGVyICUlIEJJR19TVEVQID09IDAsXQoKYmlnX3Bsb3QgPC0gZ2dwbG90KGRhdGE9dG9nZXRoZXIsIGFlcyh4PUNvdW50ZXIsIHk9dGltZSwgY29sb3VyPWFwcHJvYWNoKSkgKwogIGdlb21fbGluZSgpICsKICBnZW9tX3BvaW50KGFlcyhzaGFwZT1hcHByb2FjaCkpICsKICB4bGltKE5BLDIwMDApICsKICB5bGltKE5BLDIwKSArCiAgZ2VvbV9obGluZShzaXplPTAuMSwgeWludGVyY2VwdD0wLCBsaW5ldHlwZT0iZGFzaGVkIikgKwoKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKC4wMiwgLjk4KSwKICAgICAgICBsZWdlbmQuanVzdGlmaWNhdGlvbiA9IGMoImxlZnQiLCAidG9wIiksCiAgICAgICAgI2xlZ2VuZC5ib3guYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvcj0iYmxhY2siLCBzaXplPTAuNSksCiAgICAgICAgbGVnZW5kLmJveC5qdXN0ID0gInJpZ2h0IiwKICAgICAgICBsZWdlbmQubWFyZ2luID0gbWFyZ2luKDEsIDEsIDEsIDEpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKwogIGxhYnMoCiAgICAgICN0aXRsZT0iVGl0bGUiLAogICAgICAjc3VidGl0bGU9IlN1YnRpdGxlIiwKICAgICAgeD0iayIsCiAgICAgIHk9InRpbWUgW3NdIikKICAgICAgICAKCiAgIyBnZW9tX2xpbmUoZGF0YSA9IGJpZywgYWVzKHggPSBDb3VudGVyLCB5ID0gcmUyZyksIGNvbG9yID0gInJlZCIpICsKICAjIGdlb21fbGluZShkYXRhID0gYmlnLCBhZXMoeCA9IENvdW50ZXIsIHkgPSBjYSksIGNvbG9yID0gImJsdWUiKSArCiAgIyB4bGFiKCdjb3VudGVyIHZhbHVlJykgKwogICMgeWxhYigndGltZSBbc10nKQoKI21ha2VfdGlreihwYXN0ZTAoImZpZ3MvYmlnX3Bsb3QudGlreiIpLCBiaWdfcGxvdCwgd2lkdGg9Mi43LCBoZWlnaHQ9Mi43KQptYWtlX3BkZihwYXN0ZTAoImZpZ3MvYmlnX3Bsb3QucGRmIiksIGJpZ19wbG90LCB3aWR0aD1CSUdfU0laRSwgaGVpZ2h0PUJJR19TSVpFKQoKCnBsb3QoYmlnX3Bsb3QpCmBgYAoKCmBgYHtyfQojIEluZm9ybWF0aW9uIGFib3V0IERDQXMKCiMgZGZfZGNhcyA9IHJlYWQuY3N2MihwYXJhbXMkZmlsZV9kY2EsCiMgICAgICAgICAgICAgICAgICAgaGVhZGVyPVRSVUUsCiMgICAgICAgICAgICAgICAgICAgc2VwPSJcdCIsCiMgICAgICAgICAgICAgICAgICAgZGVjPSIuIiwKIyAgICAgICAgICAgICAgICAgICBjb21tZW50LmNoYXI9IiIsCiMgICAgICAgICAgICAgICAgICAgcXVvdGU9IiIsCiMgICAgICAgICAgICAgICAgICAgc3RyaXAud2hpdGU9VFJVRSwKIyAgICAgICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFKQojIAojICMgc2FuaXRpemUKIyBkZl9kY2FzJHRpbWVvdXRzLmNsYXNzaWNhbFtpcy5uYShkZl9kY2FzJHRpbWVvdXRzLmNsYXNzaWNhbCldIDwtIDAKCiNkZl9kY2FzCmBgYAoKYGBge3J9CiN0bXMuY2xhc3NpY2FsIDwtIGRmX2RjYXNbZGZfZGNhcyR0aW1lb3V0cy5jbGFzc2ljYWwgPT0gMSxdCmBgYAoKCgpgYGB7cn0KI2NvbXB1dGVfdGltZW91dHMgPC0gZnVuY3Rpb24oZGYsIGNvbCkgewojICB0bXAgPC0gZGZbZGZbLCBjb2xdID09IFRJTUVPVVRfVkFMLF0KIyAgdG1wCiN9CgpgYGAKCg==