#=========================================================
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 2682 lines due to generation of input text"
df <- df_new

tools.times <- c("re2g", "cad", "grep", "srm", "dotnet")
#tools.times <- c("re2g", "cad", "srm", "dotnet")
tools.matches <- c("re2g.matches", "cad.matches", "grep.matches", "srm.matches", "dotnet.matches")
#tools.matches <- c("re2g.matches", "cad.matches", "srm.matches", "dotnet.matches")

# checking errors
errors.re2g <- nrow(df[grepl('ERR', df$re2g),])
errors.grep <- nrow(df[grepl('ERR', df$grep),])
errors.srm <- nrow(df[grepl('ERR', df$srm),])
errors.cad <- nrow(df[grepl('ERR', df$cad),])
errors.dotnet <- nrow(df[grepl('ERR', df$dotnet),])

df <- df[!grepl('ERR', df$re2g),]


# 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/mergedResults/table-ALL-processed.csv
Timeout 600 s
TIMEOUT_VAL 630 s
TIME_MIN 0.1
original size 4405
Benchmarks 1644
Timeouts CA 0
Timeouts RE2 1
Timeouts SRM 9
Timeouts grep 47
Timeouts .NET 2
Errors CA 0
Errors RE2 60 (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 19 (removed)
grep and RE2 mismatched 338

RE2 and CA mismatches

df_re2_ca_mismatch

Scatter Plots


plot.and.tikz <- function(df, xlab, ylab, xstring=xlab, ystring=ylab, width=4, height=width) {
  pic <- plot_scatter_log(df, xlab, ylab, xstring, ystring)
  #make_tikz(paste0("figs/", xlab, "-vs-", ylab, ".tikz"), pic, width, height)
  make_pdf(paste0("figs/", xlab, "-vs-", ylab, ".pdf"), pic, width, height)
  pic
}

df_grep <- df[is.na(df$grep.matches) | is.na(df$cad.matches) | df$grep.matches == df$cad.matches,]

plot1 <- plot.and.tikz(df, "re2g", "cad", xstring="RE2 [s]", ystring="CA [s]", width=BIG_SIZE)
plot2 <- plot.and.tikz(df_grep, "grep", "cad", xstring="grep [s]", ystring="CA [s]", width=SMALL_SIZE)
plot3 <- plot.and.tikz(df, "srm", "cad", xstring="SRM [s]", ystring="CA [s]", width=SMALL_SIZE)
plot4 <- plot.and.tikz(df, "dotnet", "cad", xstring=".NET [s]", ystring="CA [s]", width=SMALL_SIZE)
plot5 <- plot.and.tikz(df, "srm", "re2g")
plot6 <- plot.and.tikz(df, "grep", "re2g")
plot7 <- plot.and.tikz(df, "dotnet", "re2g")
plot8 <- plot.and.tikz(df, "srm", "grep")
plot9 <- plot.and.tikz(df, "dotnet", "grep")
plot10 <- plot.and.tikz(df, "dotnet", "srm")



#grid.arrange(plot1, plot3, ncol = 2)
#grid.arrange(plot4, plot5, ncol = 2)
#grid.arrange(plot7, plot10, ncol = 2)

grid.arrange(plot1, plot2, ncol = 2)

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

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

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

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

Histograms

hist1 <- ggplot(df, aes(x=re2g)) +
  geom_histogram(color="blue", fill="lightblue") +
  scale_y_log10()

hist2 <- ggplot(df, aes(x=cad)) + 
  geom_histogram(color="blue", fill="lightblue") +
  scale_y_log10()

hist3 <- ggplot(df, aes(x=srm)) + 
  geom_histogram(color="blue", fill="lightblue") +
  scale_y_log10()

#hist4 <- ggplot(df, aes(x=grep)) + 
#  geom_histogram(color="blue", fill="lightblue") +
#  scale_y_log10()

hist5 <- ggplot(df, aes(x=dotnet)) + 
  geom_histogram(color="blue", fill="lightblue") +
  scale_y_log10()

grid.arrange(hist1, hist2, ncol = 2)

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

#grid.arrange(hist5, ncol = 2)

Finding winners

df$min <-pmin(df$grep, df$srm, df$re2g, df$dotnet, df$cad)
df$enemy.min <- pmin(df$grep, df$srm, df$re2g, df$dotnet)
#df$min <-pmin(df$srm, df$re2g, df$dotnet, df$cad)
#df$enemy.min <- pmin(df$srm, df$re2g, df$dotnet)

winners.grep <- nrow(df[df$min == df$grep,])
winners.re2 <- nrow(df[df$min == df$re2g,])
winners.ca <- nrow(df[df$min == df$cad,])
winners.srm <- nrow(df[df$min == df$srm,])
winners.dotnet <- nrow(df[df$min == df$dotnet,])

winners.ca.over.re2 <- nrow(df[df$cad <= df$re2g,])
winners.ca.over.grep <- nrow(df[df_grep$cad <= df_grep$grep,])
winners.ca.over.srm <- nrow(df[df$cad <= df$srm,])
winners.ca.over.dotnet <- nrow(df[df$cad <= df$dotnet,])

winners.10.ca.over.re2 <- nrow(df[10* df$cad <= df$re2g,])
winners.10.ca.over.grep <- nrow(df[10* df_grep$cad <= df_grep$grep,])
winners.10.ca.over.srm <- nrow(df[10* df$cad <= df$srm,])
winners.10.ca.over.dotnet <- nrow(df[10* df$cad <= df$dotnet,])

winners.100.ca.over.re2 <- nrow(df[100* df$cad <= df$re2g,])
winners.100.ca.over.grep <- nrow(df[100* df_grep$cad <= df_grep$grep,])
winners.100.ca.over.srm <- nrow(df[100* df$cad <= df$srm,])
winners.100.ca.over.dotnet <- nrow(df[100* df$cad <= df$dotnet,])

longer.than.10.seconds.ca <- nrow(df[df$cad > 10,])
longer.than.10.seconds.re2 <- nrow(df[df$re2g > 10,])
longer.than.10.seconds.srm <- nrow(df[df$srm > 10,])
longer.than.10.seconds.dotnet <- nrow(df[df$dotnet > 10,])
longer.than.10.seconds.grep <- nrow(df[df$grep > 10,])
Winner
CA 73
RE2 1211
SRM 13
.NET 39
grep 680
Wins of CA over
RE2 175 / 1644
SRM 265 / 1644
.NET 657 / 1644
grep 693 / 1311
Wins of at least 10 times of CA over
RE2 63 / 1644
SRM 128 / 1644
.NET 125 / 1644
grep 170 / 1311
Wins of at least 100 times of CA over
RE2 11 / 1644
SRM 83 / 1644
.NET 12 / 1644
grep 56 / 1311
Longer than 10 s
CA 13
RE2 64
SRM 128
.NET 146
grep 190
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
#}
LS0tCnRpdGxlOiAiQ250LVNldC1NYXRhIEFuYWx5c2lzIgpwYXJhbXM6CiAgI2ZpbGVfY21wOiBkYXRhL3Jlc3VsdHMtMjMtMDQtMjAyMC5jc3YKICAjZmlsZV9jbXA6IHJlc3VsdHMtMDUtMDUtMjAyMC9iZXR3ZWVuL3Jlc3VsdHMuY3N2CiAgI2ZpbGVfY21wOiByZXN1bHRzLTA5LTA1LTIwMjAvYmV0d2Vlbi9SRVNVTFRTLUFMTC1iZXR3ZWVuLmNzdgogICNmaWxlX2NtcDogcmVzdWx0cy0xMC0wNS0yMDIwL3RhYmxlLUFMTC5jc3YKICAjZmlsZV9jbXA6IHJlc3VsdHMtMTEtMDUtMjAyMC90YWJsZS1BTEwtb25kcmEtcHJvY2Vzc2VkLmNzdgogICNmaWxlX2NtcDogcmVzdWx0cy0xMi0wNS0yMDIwL3RhYmxlLUFMTC1vbmRyYS1wcm9jZXNzZWQuY3N2CiAgI2ZpbGVfY21wOiByZXN1bHRzLTE1LTA1LTIwMjAvbm9ncmVwL2N1dC90YWJsZS1BTEwtcHJvY2Vzc2VkLmNzdgogICNmaWxlX2NtcDogcmVzdWx0cy0xNS0wNS0yMDIwL25vZ3JlcC9ub2N1dC90YWJsZS1BTEwtcHJvY2Vzc2VkLmNzdgogICNmaWxlX2NtcDogcmVzdWx0cy0xNS0wNS0yMDIwL25vZ3JlcC9tZXJnZWQvdGFibGUtQUxMLXByb2Nlc3NlZC5jc3YKICBmaWxlX2NtcDogcmVzdWx0cy0xNS0wNS0yMDIwL25vZ3JlcC9tZXJnZWRSZXN1bHRzL3RhYmxlLUFMTC1wcm9jZXNzZWQuY3N2CiAgI2ZpbGVfYmlnOiByZXN1bHRzLTA1LTA1LTIwMjAvdGFibGUtYmlnLTI1MDM2MTAyLmNzdgogIGZpbGVfYmlnOiByZXN1bHRzLTExLTA1LTIwMjAvZ3JhcGgvdGFibGUtYmlnLTEwNjUyODk3MDQuY3N2CiAgZmlsZV9kY2E6IERDQXMvcmVzdWx0cy10cmFuc2xhdGlvbi50c3YKICB0aW1lb3V0OiA2MDAgIyBzZWNvbmRzCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0CiAgaHRtbF9kb2N1bWVudDoKICAgIGRmX3ByaW50OiBwYWdlZAogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKLS0tCgpgYGB7cn0KIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIFBSRUFNQkxFCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KCiMgbG9hZCB0aGUgcGxvdHRpbmcgbGlicmFyeQpzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkoZ2dwbG90MikpCmxpYnJhcnkoZ3JpZEV4dHJhKQpsaWJyYXJ5KGdnRXh0cmEpCmxpYnJhcnkodGlrekRldmljZSkKbGlicmFyeShIbWlzYykKbGlicmFyeShwYXN0ZWNzKQoKCgp0aGVtZV9zZXQodGhlbWVfYncoKSkKCm9wdGlvbnMoc2NpcGVuPTk5OSkgICMgdHVybi1vZmYgc2NpZW50aWZpYyBub3RhdGlvbiBsaWtlIDFlKzQ4CgojIHNpemUgb2YgcG9pbnQgZm9yIHNjYXR0ZXJwbG90cwpQT0lOVF9TSVpFID0gMC4xCiNQT0lOVF9TSVpFID0gMQoKIyB0aW1lb3V0ClRJTUVPVVQgPSBwYXJhbXMkdGltZW91dApUSU1FT1VUX1ZBTCA9IDEuMDUgKiBUSU1FT1VUCgojIHNhdHVyYXRlCiNUSU1FX01JTiA9IDAuMDEgIyBzZWNvbmRzClRJTUVfTUlOID0gMC4xICMgc2Vjb25kcwoKQklHX1NJWkU9MwpTTUFMTF9TSVpFPTIKCgojIEZVTkNUSU9OUwpyZWFkX2ZpbGUgPC0gZnVuY3Rpb24oZmlsZSkgewogIGZpbGVuYW1lID0gcGFzdGUwKGZpbGUpCiAgZGYgPC0gcmVhZC5jc3YyKGZpbGVuYW1lLAogICAgICAgICAgICAgICAgICBoZWFkZXI9VFJVRSwKICAgICAgICAgICAgICAgICAgc2VwPSI7IiwKICAgICAgICAgICAgICAgICAgZGVjPSIsIiwKICAgICAgICAgICAgICAgICAgY29tbWVudC5jaGFyPSIiLAogICAgICAgICAgICAgICAgICBxdW90ZT0iXCIiLAogICAgICAgICAgICAgICAgICBzdHJpcC53aGl0ZT1UUlVFLAogICAgICAgICAgICAgICAgICBhbGxvd0VzY2FwZXM9RkFMU0UsCiAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UpCiAgCiAgCiAgcmV0dXJuKGRmKQp9CgpwbG90X3NjYXR0ZXJfbG9nIDwtIGZ1bmN0aW9uKGRmLCB4bGFiLCB5bGFiLCB4c3RyaW5nPXhsYWIsIHlzdHJpbmc9eWxhYikgewogIHBzY2F0IDwtIGdncGxvdChkZiwgYWVzX3N0cmluZyh4PXhsYWIsIHk9eWxhYikpICsKICAgIGdlb21fcG9pbnQoc2l6ZT1QT0lOVF9TSVpFKSArCiAgICBnZW9tX2FibGluZShzaXplPTAuMSkgKwogICAgZ2VvbV92bGluZShzaXplPTAuMSwgeGludGVyY2VwdD1USU1FT1VUX1ZBTCwgbGluZXR5cGU9ImRhc2hlZCIpICsKICAgIGdlb21faGxpbmUoc2l6ZT0wLjEsIHlpbnRlcmNlcHQ9VElNRU9VVF9WQUwsIGxpbmV0eXBlPSJkYXNoZWQiKSArCiAgICBnZW9tX3J1ZyhhbHBoYSA9IDAuMikgKwogICAgc2NhbGVfeF9sb2cxMCgpICsKICAgIHNjYWxlX3lfbG9nMTAoKSArCiAgICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDAuNSkpICsKICAgICNjb29yZF9maXhlZCh4bGltID0gYyhUSU1FX01JTiwgVElNRU9VVF9WQUwpLCB5bGltID0gYygwLjEsIFRJTUVPVVRfVkFMKSkgKwogICAgI2Nvb3JkX2ZpeGVkKHhsaW0gPSBjKFRJTUVfTUlOLCBUSU1FT1VUX1ZBTCksIHlsaW0gPSBjKFRJTUVfTUlOLCBUSU1FT1VUX1ZBTCkpICsKICAgICAgICBjb29yZF9maXhlZCh4bGltID0gYyhUSU1FX01JTiwgVElNRU9VVF9WQUwpLCB5bGltID0gYyhUSU1FX01JTiwgVElNRU9VVF9WQUwpKSArCiAgICBsYWJzKAogICAgICAjdGl0bGU9IlRpdGxlIiwKICAgICAgI3N1YnRpdGxlPSJTdWJ0aXRsZSIsCiAgICAgIHg9eHN0cmluZywKICAgICAgeT15c3RyaW5nKQojICAgIHRoZW1lKAojICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLCAKIyAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKIyAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50Iixjb2xvdXIgPSBOQSksCiMgICAgICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50Iixjb2xvdXIgPSBOQSkKIyAgICAgICAgKQojICB0aGVtZV9taW5pbWFsKCkKIyAgdGhlbWVfYncoKQogIyB0aGVtZShwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9IE5BKSkKICMgcHNjYXQgPC0gZ2dNYXJnaW5hbChwc2NhdCwgdHlwZSA9ICJkZW5zaXR5Iiwgc2l6ZT0xMCkKIyAgcHNjYXQgPC0gcHNjYXQgKyB0aGVtZV9idygpCiAgcmV0dXJuKHBzY2F0KQp9CgptYWtlX3Rpa3ogPC0gZnVuY3Rpb24oZmlsZSwgcGljdHVyZSwgd2lkdGg9Mi41LCBoZWlnaHQ9Mi41KSB7CiAgZm9udF9zaXplIDwtIDEKICB0aWt6KGZpbGU9ZmlsZSwgb25lZmlsZT1ULCB3aWR0aD13aWR0aCwgaGVpZ2h0PWhlaWdodCkKICBwbG90KHBpY3R1cmUpCiAgZ2FyYmFnZSA8LSBkZXYub2ZmKCkKfQoKbWFrZV9wZGYgPC0gZnVuY3Rpb24oZmlsZSwgcGljdHVyZSwgd2lkdGg9NSwgaGVpZ2h0PTUpIHsKICBwZGYoZmlsZT1maWxlLCBvbmVmaWxlPVQsIHdpZHRoLCBoZWlnaHQpCiAgcGxvdChwaWN0dXJlKQogIGdhcmJhZ2UgPC0gZGV2Lm9mZigpCn0KYGBgCgpgYGB7cn0KZGYgPC0gcmVhZF9maWxlKHBhcmFtcyRmaWxlX2NtcCkKb3JpZ19zaXplIDwtIG5yb3coZGYpCgpjb2xuYW1lcyhkZilbY29sbmFtZXMoZGYpID09ICJkb3QubmV0Il0gPC0gImRvdG5ldCIKY29sbmFtZXMoZGYpW25hbWVzKGRmKSA9PSAiZG90Lm5ldC5tYXRjaGVzIl0gPC0gImRvdG5ldC5tYXRjaGVzIgoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyBTQU5JVElaRSAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgY2xlYW4gdGhlIGRhdGEKZGZfbmV3IDwtIGRmWyFncmVwbCgiRmlsZSBub3QgZm91bmQiLCBkZiRzcm0ubWF0Y2hlcyksXQpwcmludChwYXN0ZTAoIlJlbW92aW5nICIsIG5yb3coZGYpIC0gbnJvdyhkZl9uZXcpLCAiIGxpbmVzIGR1ZSB0byBnZW5lcmF0aW9uIG9mIGlucHV0IHRleHQiKSkKZGYgPC0gZGZfbmV3Cgp0b29scy50aW1lcyA8LSBjKCJyZTJnIiwgImNhZCIsICJncmVwIiwgInNybSIsICJkb3RuZXQiKQojdG9vbHMudGltZXMgPC0gYygicmUyZyIsICJjYWQiLCAic3JtIiwgImRvdG5ldCIpCnRvb2xzLm1hdGNoZXMgPC0gYygicmUyZy5tYXRjaGVzIiwgImNhZC5tYXRjaGVzIiwgImdyZXAubWF0Y2hlcyIsICJzcm0ubWF0Y2hlcyIsICJkb3RuZXQubWF0Y2hlcyIpCiN0b29scy5tYXRjaGVzIDwtIGMoInJlMmcubWF0Y2hlcyIsICJjYWQubWF0Y2hlcyIsICJzcm0ubWF0Y2hlcyIsICJkb3RuZXQubWF0Y2hlcyIpCgojIGNoZWNraW5nIGVycm9ycwplcnJvcnMucmUyZyA8LSBucm93KGRmW2dyZXBsKCdFUlInLCBkZiRyZTJnKSxdKQplcnJvcnMuZ3JlcCA8LSBucm93KGRmW2dyZXBsKCdFUlInLCBkZiRncmVwKSxdKQplcnJvcnMuc3JtIDwtIG5yb3coZGZbZ3JlcGwoJ0VSUicsIGRmJHNybSksXSkKZXJyb3JzLmNhZCA8LSBucm93KGRmW2dyZXBsKCdFUlInLCBkZiRjYWQpLF0pCmVycm9ycy5kb3RuZXQgPC0gbnJvdyhkZltncmVwbCgnRVJSJywgZGYkZG90bmV0KSxdKQoKZGYgPC0gZGZbIWdyZXBsKCdFUlInLCBkZiRyZTJnKSxdCgoKIyBjaGFuZ2UgdGhlIHR5cGUgb2YgY29sdW1ucyBvdGhlciB0aGFuIHRoZSBuYW1lCmZvciAoaSBpbiB0b29scy50aW1lcykgewogIGRmWyxpXSA8LSBzdWIoIiwiLCAiLiIsIGRmWyxpXSkKICBzdXBwcmVzc1dhcm5pbmdzKGRmWyxpXSA8LSBhcy5udW1lcmljKGRmWyxpXSkpCn0KCmZvciAoaSBpbiB0b29scy5tYXRjaGVzKSB7CiAgc3VwcHJlc3NXYXJuaW5ncyhkZlssaV0gPC0gYXMuaW50ZWdlcihkZlssaV0pKQp9CgpkZiRzcmMgPC0gYXMuZmFjdG9yKGRmJHNyYykKCiMgZ2V0IHJpZCBvZiBleHRyZW1hbCB2YWx1ZXMKZGZbLHRvb2xzLnRpbWVzXVtkZlssdG9vbHMudGltZXNdID4gVElNRU9VVF0gPC0gVElNRU9VVF9WQUwKZGZbdG9vbHMudGltZXNdW2lzLm5hKGRmW3Rvb2xzLnRpbWVzXSldIDwtIFRJTUVPVVRfVkFMCiNkZltpcy5uYShkZildIDwtIFRJTUVPVVRfVkFMCiNkZltkZiA9PSAwLjAwXSA8LSBUSU1FX01JTgpkZlssdG9vbHMudGltZXNdW2RmWyx0b29scy50aW1lc10gPCBUSU1FX01JTl0gPC0gVElNRV9NSU4KCgoKIyBjbGVhbiB0aGUgZGF0YQojZGZfbmV3IDwtIGRmW2RmJExpbmVzICE9ICJFUlJPUiBXSElMRSBDT05WRVJUSU5HIFRPIERDQS4iLF0KI3ByaW50KHBhc3RlMCgiUmVtb3ZpbmcgIiwgbnJvdyhkZikgLSBucm93KGRmX25ldyksICIgbGluZXMgZHVlIHRvIGNvbnZlcnRpbmcgdG8gRENBIGVycm9yIikpCiNkZiA8LSBkZl9uZXcKCgoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIENPVU5USU5HIFRJTUVPVVRTICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCnRpbWVvdXRzLnJlMmcgPC0gbnJvdyhkZltkZiRyZTJnID09IFRJTUVPVVRfVkFMLF0pCnRpbWVvdXRzLmNhZCA8LSBucm93KGRmW2RmJGNhZCA9PSBUSU1FT1VUX1ZBTCxdKQp0aW1lb3V0cy5ncmVwIDwtIG5yb3coZGZbZGYkZ3JlcCA9PSBUSU1FT1VUX1ZBTCxdKQp0aW1lb3V0cy5zcm0gPC0gbnJvdyhkZltkZiRzcm0gPT0gVElNRU9VVF9WQUwsXSkKdGltZW91dHMuZG90bmV0IDwtIG5yb3coZGZbZGYkZG90bmV0ID09IFRJTUVPVVRfVkFMLF0pCnRpbWVvdXRzLnJlMi5hbmQuY2EgPC0gbnJvdyhkZltkZiRjYWQgPT0gVElNRU9VVF9WQUwgJiBkZiRyZTJnID09IFRJTUVPVVRfVkFMLF0pCgojIHwgKipUaW1lb3V0cyBncmVwKiogICAgfCBgciB0aW1lb3V0cy5ncmVwYCAgfApgYGAKClRoZXNlIGFyZSByZXN1bHRzIG9mIHRoZSBleHBlcmltZW50cyBmb3IgQ291bnRpbmcgU2V0IEF1dG9tYXRhOgoKfCAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgICAgICAgICAgICAgICB8IHwKfC0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLTp8LXwKfCAqKkZpbGUqKiAgICAgICAgICAgIHwgYHIgcGFyYW1zJGZpbGVfY21wYCB8CnwgKipUaW1lb3V0KiogICAgICAgICB8IGByIFRJTUVPVVRgIHMgICAgICAgfAp8ICoqVElNRU9VVF9WQUwqKiAgICAgfCBgciBUSU1FT1VUX1ZBTGAgcyAgIHwKfCAqKlRJTUVfTUlOKiogICAgICAgIHwgYHIgVElNRV9NSU5gICAgICAgICB8CnwgKipvcmlnaW5hbCBzaXplKiogICB8IGByIG9yaWdfc2l6ZWAgICAgICAgfAp8ICoqQmVuY2htYXJrcyoqICAgICAgfCBgciBucm93KGRmKWAgICAgICAgIHwKfCAqKlRpbWVvdXRzIENBKiogICAgIHwgYHIgdGltZW91dHMuY2FkYCAgICAgfAp8ICoqVGltZW91dHMgUkUyKiogICAgfCBgciB0aW1lb3V0cy5yZTJnYCAgICB8CnwgKipUaW1lb3V0cyBTUk0qKiAgICB8IGByIHRpbWVvdXRzLnNybWAgICAgfCAKfCAqKlRpbWVvdXRzIGdyZXAqKiAgIHwgYHIgdGltZW91dHMuZ3JlcGAgICAgfCAKfCAqKlRpbWVvdXRzIC5ORVQqKiAgIHwgYHIgdGltZW91dHMuZG90bmV0YCAgfAp8ICoqRXJyb3JzIENBKiogICAgIHwgYHIgZXJyb3JzLmNhZGAgICAgIHwKfCAqKkVycm9ycyBSRTIqKiAgICB8IGByIGVycm9ycy5yZTJnYCAgICB8IChyZW1vdmVkKSB8CnwgKipFcnJvcnMgU1JNKiogICAgfCBgciBlcnJvcnMuc3JtYCAgICB8IAp8ICoqRXJyb3JzIGdyZXAqKiAgIHwgYHIgZXJyb3JzLmdyZXBgICAgIHwgCnwgKipFcnJvcnMgLk5FVCoqICAgfCBgciBlcnJvcnMuZG90bmV0YCAgfAoKCgpgYGB7cn0KZGYKYGBgCgojIFN1bW1hcnkgb2YgYmVuY2htYXJrcwoKYGBge3J9CmRmX2JlbmNoZXMgPC0gZGF0YS5mcmFtZShzdW1tYXJ5KGRmJHNyYykpCmRmX2JlbmNoZXMKYGBgCgojIFNhbml0eSBjaGVja3MKCmBgYHtyfQpkZiRpbmNvbnNpc3RlbnQgPC0gZGYkcmUyZy5tYXRjaGVzICE9IGRmJGdyZXAubWF0Y2hlcyB8IGRmJHJlMmcubWF0Y2hlcyAhPSBkZiRzcm0ubWF0Y2hlcyB8IGRmJHJlMmcubWF0Y2hlcyAhPSBkZiRkb3RuZXQubWF0Y2hlcyB8IGRmJHJlMmcubWF0Y2hlcyAhPSBkZiRjYWQubWF0Y2hlcwoKI2RmJGluY29uc2lzdGVudCA8LSBkZiRyZTJnLm1hdGNoZXMgIT0gZGYkc3JtLm1hdGNoZXMgfCBkZiRyZTJnLm1hdGNoZXMgIT0gZGYkZG90bmV0Lm1hdGNoZXMgfCBkZiRyZTJnLm1hdGNoZXMgIT0gZGYkY2FkLm1hdGNoZXMKCmRmJGdyZXAucmUyLm1pc21hdGNoIDwtICFpcy5uYShkZiRyZTJnLm1hdGNoZXMpICYgIWlzLm5hKGRmJGdyZXAubWF0Y2hlcykgJiBkZiRyZTJnLm1hdGNoZXMgIT0gZGYkZ3JlcC5tYXRjaGVzCmRmX2dyZXBfcmUyX21pc21hdGNoIDwtIGRmW2RmJGdyZXAucmUyLm1pc21hdGNoLF0KCmRmJHJlMi5jYS5taXNtYXRjaCA8LSAhaXMubmEoZGYkcmUyZy5tYXRjaGVzKSAmICFpcy5uYShkZiRjYWQubWF0Y2hlcykgJiBkZiRyZTJnLm1hdGNoZXMgIT0gZGYkY2FkLm1hdGNoZXMKZGZfcmUyX2NhX21pc21hdGNoIDwtIGRmW2RmJHJlMi5jYS5taXNtYXRjaCxdCgpkZiA8LSBkZltpcy5uYShkZiRyZTJnLm1hdGNoZXMpIHwgaXMubmEoZGYkZ3JlcC5tYXRjaGVzKSB8IGRmJHJlMmcubWF0Y2hlcyA9PSBkZiRjYWQubWF0Y2hlcyxdCgpgYGAKCnwgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgICB8CnwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tOnwgLS0tLS0tLTp8CnwgKipDQSBhbmQgUkUyIG1pc21hdGNoZWQqKiAgIHwgYHIgbnJvdyhkZl9yZTJfY2FfbWlzbWF0Y2gpYCAgIHwgKHJlbW92ZWQpIHwKfCAqKmdyZXAgYW5kIFJFMiBtaXNtYXRjaGVkKiogfCBgciBucm93KGRmX2dyZXBfcmUyX21pc21hdGNoKWAgfAoKCiMjIFJFMiBhbmQgQ0EgbWlzbWF0Y2hlcwpgYGB7cn0KZGZfcmUyX2NhX21pc21hdGNoCmBgYAoKCgojIFNjYXR0ZXIgUGxvdHMKCmBgYHtyfQoKcGxvdC5hbmQudGlreiA8LSBmdW5jdGlvbihkZiwgeGxhYiwgeWxhYiwgeHN0cmluZz14bGFiLCB5c3RyaW5nPXlsYWIsIHdpZHRoPTQsIGhlaWdodD13aWR0aCkgewogIHBpYyA8LSBwbG90X3NjYXR0ZXJfbG9nKGRmLCB4bGFiLCB5bGFiLCB4c3RyaW5nLCB5c3RyaW5nKQogICNtYWtlX3Rpa3oocGFzdGUwKCJmaWdzLyIsIHhsYWIsICItdnMtIiwgeWxhYiwgIi50aWt6IiksIHBpYywgd2lkdGgsIGhlaWdodCkKICBtYWtlX3BkZihwYXN0ZTAoImZpZ3MvIiwgeGxhYiwgIi12cy0iLCB5bGFiLCAiLnBkZiIpLCBwaWMsIHdpZHRoLCBoZWlnaHQpCiAgcGljCn0KCmRmX2dyZXAgPC0gZGZbaXMubmEoZGYkZ3JlcC5tYXRjaGVzKSB8IGlzLm5hKGRmJGNhZC5tYXRjaGVzKSB8IGRmJGdyZXAubWF0Y2hlcyA9PSBkZiRjYWQubWF0Y2hlcyxdCgpwbG90MSA8LSBwbG90LmFuZC50aWt6KGRmLCAicmUyZyIsICJjYWQiLCB4c3RyaW5nPSJSRTIgW3NdIiwgeXN0cmluZz0iQ0EgW3NdIiwgd2lkdGg9QklHX1NJWkUpCnBsb3QyIDwtIHBsb3QuYW5kLnRpa3ooZGZfZ3JlcCwgImdyZXAiLCAiY2FkIiwgeHN0cmluZz0iZ3JlcCBbc10iLCB5c3RyaW5nPSJDQSBbc10iLCB3aWR0aD1TTUFMTF9TSVpFKQpwbG90MyA8LSBwbG90LmFuZC50aWt6KGRmLCAic3JtIiwgImNhZCIsIHhzdHJpbmc9IlNSTSBbc10iLCB5c3RyaW5nPSJDQSBbc10iLCB3aWR0aD1TTUFMTF9TSVpFKQpwbG90NCA8LSBwbG90LmFuZC50aWt6KGRmLCAiZG90bmV0IiwgImNhZCIsIHhzdHJpbmc9Ii5ORVQgW3NdIiwgeXN0cmluZz0iQ0EgW3NdIiwgd2lkdGg9U01BTExfU0laRSkKcGxvdDUgPC0gcGxvdC5hbmQudGlreihkZiwgInNybSIsICJyZTJnIikKcGxvdDYgPC0gcGxvdC5hbmQudGlreihkZiwgImdyZXAiLCAicmUyZyIpCnBsb3Q3IDwtIHBsb3QuYW5kLnRpa3ooZGYsICJkb3RuZXQiLCAicmUyZyIpCnBsb3Q4IDwtIHBsb3QuYW5kLnRpa3ooZGYsICJzcm0iLCAiZ3JlcCIpCnBsb3Q5IDwtIHBsb3QuYW5kLnRpa3ooZGYsICJkb3RuZXQiLCAiZ3JlcCIpCnBsb3QxMCA8LSBwbG90LmFuZC50aWt6KGRmLCAiZG90bmV0IiwgInNybSIpCgoKCiNncmlkLmFycmFuZ2UocGxvdDEsIHBsb3QzLCBuY29sID0gMikKI2dyaWQuYXJyYW5nZShwbG90NCwgcGxvdDUsIG5jb2wgPSAyKQojZ3JpZC5hcnJhbmdlKHBsb3Q3LCBwbG90MTAsIG5jb2wgPSAyKQoKZ3JpZC5hcnJhbmdlKHBsb3QxLCBwbG90MiwgbmNvbCA9IDIpCmdyaWQuYXJyYW5nZShwbG90MywgcGxvdDQsIG5jb2wgPSAyKQpncmlkLmFycmFuZ2UocGxvdDUsIHBsb3Q2LCBuY29sID0gMikKZ3JpZC5hcnJhbmdlKHBsb3Q3LCBwbG90OCwgbmNvbCA9IDIpCmdyaWQuYXJyYW5nZShwbG90OSwgcGxvdDEwLCBuY29sID0gMikKCmBgYAoKIyBIaXN0b2dyYW1zCgpgYGB7cn0KaGlzdDEgPC0gZ2dwbG90KGRmLCBhZXMoeD1yZTJnKSkgKwogIGdlb21faGlzdG9ncmFtKGNvbG9yPSJibHVlIiwgZmlsbD0ibGlnaHRibHVlIikgKwogIHNjYWxlX3lfbG9nMTAoKQoKaGlzdDIgPC0gZ2dwbG90KGRmLCBhZXMoeD1jYWQpKSArIAogIGdlb21faGlzdG9ncmFtKGNvbG9yPSJibHVlIiwgZmlsbD0ibGlnaHRibHVlIikgKwogIHNjYWxlX3lfbG9nMTAoKQoKaGlzdDMgPC0gZ2dwbG90KGRmLCBhZXMoeD1zcm0pKSArIAogIGdlb21faGlzdG9ncmFtKGNvbG9yPSJibHVlIiwgZmlsbD0ibGlnaHRibHVlIikgKwogIHNjYWxlX3lfbG9nMTAoKQoKI2hpc3Q0IDwtIGdncGxvdChkZiwgYWVzKHg9Z3JlcCkpICsgCiMgIGdlb21faGlzdG9ncmFtKGNvbG9yPSJibHVlIiwgZmlsbD0ibGlnaHRibHVlIikgKwojICBzY2FsZV95X2xvZzEwKCkKCmhpc3Q1IDwtIGdncGxvdChkZiwgYWVzKHg9ZG90bmV0KSkgKyAKICBnZW9tX2hpc3RvZ3JhbShjb2xvcj0iYmx1ZSIsIGZpbGw9ImxpZ2h0Ymx1ZSIpICsKICBzY2FsZV95X2xvZzEwKCkKCmdyaWQuYXJyYW5nZShoaXN0MSwgaGlzdDIsIG5jb2wgPSAyKQpncmlkLmFycmFuZ2UoaGlzdDMsIGhpc3Q1LCBuY29sID0gMikKI2dyaWQuYXJyYW5nZShoaXN0NSwgbmNvbCA9IDIpCgoKYGBgCgojIEZpbmRpbmcgd2lubmVycwoKYGBge3J9CmRmJG1pbiA8LXBtaW4oZGYkZ3JlcCwgZGYkc3JtLCBkZiRyZTJnLCBkZiRkb3RuZXQsIGRmJGNhZCkKZGYkZW5lbXkubWluIDwtIHBtaW4oZGYkZ3JlcCwgZGYkc3JtLCBkZiRyZTJnLCBkZiRkb3RuZXQpCiNkZiRtaW4gPC1wbWluKGRmJHNybSwgZGYkcmUyZywgZGYkZG90bmV0LCBkZiRjYWQpCiNkZiRlbmVteS5taW4gPC0gcG1pbihkZiRzcm0sIGRmJHJlMmcsIGRmJGRvdG5ldCkKCndpbm5lcnMuZ3JlcCA8LSBucm93KGRmW2RmJG1pbiA9PSBkZiRncmVwLF0pCndpbm5lcnMucmUyIDwtIG5yb3coZGZbZGYkbWluID09IGRmJHJlMmcsXSkKd2lubmVycy5jYSA8LSBucm93KGRmW2RmJG1pbiA9PSBkZiRjYWQsXSkKd2lubmVycy5zcm0gPC0gbnJvdyhkZltkZiRtaW4gPT0gZGYkc3JtLF0pCndpbm5lcnMuZG90bmV0IDwtIG5yb3coZGZbZGYkbWluID09IGRmJGRvdG5ldCxdKQoKd2lubmVycy5jYS5vdmVyLnJlMiA8LSBucm93KGRmW2RmJGNhZCA8PSBkZiRyZTJnLF0pCndpbm5lcnMuY2Eub3Zlci5ncmVwIDwtIG5yb3coZGZbZGZfZ3JlcCRjYWQgPD0gZGZfZ3JlcCRncmVwLF0pCndpbm5lcnMuY2Eub3Zlci5zcm0gPC0gbnJvdyhkZltkZiRjYWQgPD0gZGYkc3JtLF0pCndpbm5lcnMuY2Eub3Zlci5kb3RuZXQgPC0gbnJvdyhkZltkZiRjYWQgPD0gZGYkZG90bmV0LF0pCgp3aW5uZXJzLjEwLmNhLm92ZXIucmUyIDwtIG5yb3coZGZbMTAqIGRmJGNhZCA8PSBkZiRyZTJnLF0pCndpbm5lcnMuMTAuY2Eub3Zlci5ncmVwIDwtIG5yb3coZGZbMTAqIGRmX2dyZXAkY2FkIDw9IGRmX2dyZXAkZ3JlcCxdKQp3aW5uZXJzLjEwLmNhLm92ZXIuc3JtIDwtIG5yb3coZGZbMTAqIGRmJGNhZCA8PSBkZiRzcm0sXSkKd2lubmVycy4xMC5jYS5vdmVyLmRvdG5ldCA8LSBucm93KGRmWzEwKiBkZiRjYWQgPD0gZGYkZG90bmV0LF0pCgp3aW5uZXJzLjEwMC5jYS5vdmVyLnJlMiA8LSBucm93KGRmWzEwMCogZGYkY2FkIDw9IGRmJHJlMmcsXSkKd2lubmVycy4xMDAuY2Eub3Zlci5ncmVwIDwtIG5yb3coZGZbMTAwKiBkZl9ncmVwJGNhZCA8PSBkZl9ncmVwJGdyZXAsXSkKd2lubmVycy4xMDAuY2Eub3Zlci5zcm0gPC0gbnJvdyhkZlsxMDAqIGRmJGNhZCA8PSBkZiRzcm0sXSkKd2lubmVycy4xMDAuY2Eub3Zlci5kb3RuZXQgPC0gbnJvdyhkZlsxMDAqIGRmJGNhZCA8PSBkZiRkb3RuZXQsXSkKCmxvbmdlci50aGFuLjEwLnNlY29uZHMuY2EgPC0gbnJvdyhkZltkZiRjYWQgPiAxMCxdKQpsb25nZXIudGhhbi4xMC5zZWNvbmRzLnJlMiA8LSBucm93KGRmW2RmJHJlMmcgPiAxMCxdKQpsb25nZXIudGhhbi4xMC5zZWNvbmRzLnNybSA8LSBucm93KGRmW2RmJHNybSA+IDEwLF0pCmxvbmdlci50aGFuLjEwLnNlY29uZHMuZG90bmV0IDwtIG5yb3coZGZbZGYkZG90bmV0ID4gMTAsXSkKbG9uZ2VyLnRoYW4uMTAuc2Vjb25kcy5ncmVwIDwtIG5yb3coZGZbZGYkZ3JlcCA+IDEwLF0pCgoKYGBgCgp8ICoqV2lubmVyKiogICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwKfC0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLTp8CnwgKipDQSoqICAgICB8IGByIHdpbm5lcnMuY2FgICAgICB8CnwgKipSRTIqKiAgICB8IGByIHdpbm5lcnMucmUyYCAgICB8CnwgKipTUk0qKiAgICB8IGByIHdpbm5lcnMuc3JtYCAgICB8IAp8ICoqLk5FVCoqICAgIHwgYHIgd2lubmVycy5kb3RuZXRgICB8CnwgKipncmVwKiogICAgfCBgciB3aW5uZXJzLmdyZXBgICB8Cgp8ICoqV2lucyBvZiBDQSBvdmVyKiogICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwKfC0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLTp8CnwgKipSRTIqKiAgICB8IGByIHdpbm5lcnMuY2Eub3Zlci5yZTJgIC8gYHIgbnJvdyhkZilgICAgfAp8ICoqU1JNKiogICAgfCBgciB3aW5uZXJzLmNhLm92ZXIuc3JtYCAvIGByIG5yb3coZGYpYCAgICB8IAp8ICoqLk5FVCoqICAgIHwgYHIgd2lubmVycy5jYS5vdmVyLmRvdG5ldGAgLyBgciBucm93KGRmKWAgIHwKfCAqKmdyZXAqKiAgICB8IGByIHdpbm5lcnMuY2Eub3Zlci5ncmVwYCAvIGByIG5yb3coZGZfZ3JlcClgICB8Cgp8ICoqV2lucyBvZiBhdCBsZWFzdCAxMCB0aW1lcyBvZiBDQSBvdmVyKiogICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwKfC0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLTp8CnwgKipSRTIqKiAgICB8IGByIHdpbm5lcnMuMTAuY2Eub3Zlci5yZTJgIC8gYHIgbnJvdyhkZilgICAgfAp8ICoqU1JNKiogICAgfCBgciB3aW5uZXJzLjEwLmNhLm92ZXIuc3JtYCAvIGByIG5yb3coZGYpYCAgICB8IAp8ICoqLk5FVCoqICAgIHwgYHIgd2lubmVycy4xMC5jYS5vdmVyLmRvdG5ldGAgLyBgciBucm93KGRmKWAgIHwKfCAqKmdyZXAqKiAgICB8IGByIHdpbm5lcnMuMTAuY2Eub3Zlci5ncmVwYCAvIGByIG5yb3coZGZfZ3JlcClgICB8Cgp8ICoqV2lucyBvZiBhdCBsZWFzdCAxMDAgdGltZXMgb2YgQ0Egb3ZlcioqICAgICAgICAgIHwgICAgICAgICAgICAgICAgICAgICB8CnwtLS0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS06fAp8ICoqUkUyKiogICAgfCBgciB3aW5uZXJzLjEwMC5jYS5vdmVyLnJlMmAgLyBgciBucm93KGRmKWAgICB8CnwgKipTUk0qKiAgICB8IGByIHdpbm5lcnMuMTAwLmNhLm92ZXIuc3JtYCAvIGByIG5yb3coZGYpYCAgICB8IAp8ICoqLk5FVCoqICAgIHwgYHIgd2lubmVycy4xMDAuY2Eub3Zlci5kb3RuZXRgIC8gYHIgbnJvdyhkZilgICB8CnwgKipncmVwKiogICAgfCBgciB3aW5uZXJzLjEwMC5jYS5vdmVyLmdyZXBgIC8gYHIgbnJvdyhkZl9ncmVwKWAgIHwKCnwgKipMb25nZXIgdGhhbiAxMCBzKiogICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgIHwKfC0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLTp8CnwgKipDQSoqICAgICB8IGByIGxvbmdlci50aGFuLjEwLnNlY29uZHMuY2FgICAgICB8CnwgKipSRTIqKiAgICB8IGByIGxvbmdlci50aGFuLjEwLnNlY29uZHMucmUyYCAgICB8CnwgKipTUk0qKiAgICB8IGByIGxvbmdlci50aGFuLjEwLnNlY29uZHMuc3JtYCAgICB8IAp8ICoqLk5FVCoqICAgIHwgYHIgbG9uZ2VyLnRoYW4uMTAuc2Vjb25kcy5kb3RuZXRgICB8CnwgKipncmVwKiogICAgfCBgciBsb25nZXIudGhhbi4xMC5zZWNvbmRzLmdyZXBgICB8CgoKCmBgYHtyfQpwbG90LmFuZC50aWt6KGRmLCAiZW5lbXkubWluIiwgImNhZCIsIHhzdHJpbmc9ImJlc3QgZW5lbXkiLCB5c3RyaW5nPSJDQSBbc10iKQpgYGAKCiMgSG93IG11Y2ggd2UgYXJlIGJldHRlciB0aGFuIFJFMgoKYGBge3J9CmRmJHJlMi52cy5jYSA8LSBkZiRyZTJnIC8gZGYkY2FkCmRmX3NvcnRlZCA8LSBkZltvcmRlcihkZiRyZTIudnMuY2EsIGRlY3JlYXNpbmc9VFJVRSksXQoKI2RmX3NvcnRlZFssYygic3JjIiwgInBhdHRlcm4iLCAiZmlsZSIsICJyZTJnIiwgImNhZCIsICJyZTIudnMuY2EiLCAicmUyLmNhLm1pc21hdGNoIildCmRmX3NvcnRlZCA8LSBkZl9zb3J0ZWRbMToxMCxjKCJzcmMiLCAicGF0dGVybiIsICJmaWxlIiwgdG9vbHMudGltZXMpXQpkZl9zb3J0ZWQKaGFmIDwtIGxhdGV4KGRmX3NvcnRlZCwKICAgICAgICAgICAgIGZpbGU9ImZpZ3MvYmVzdF9yZXN1bHRzLnRleCIsCiAgICAgICAgICAgICBib29rdGFicz1UUlVFLAogICAgICAgICAgICAgdGFibGUuZW52PUZBTFNFLAogICAgICAgICAgICAgY2VudGVyPSJub25lIikKCmBgYAoKIyBTdW1tYXJpZXMKCmBgYHtyfQpkZl9mb3Jfc3VtbWFyeSA8LSBkZlssYygicmUyZyIsICJjYWQiLCAic3JtIiwgImRvdG5ldCIsICJncmVwIildCiNkZi5zdW1tYXJ5IDwtIGRvLmNhbGwoY2JpbmQsIGxhcHBseShkZl9mb3Jfc3VtbWFyeSwgc3VtbWFyeSkpCiNkZi5zdW1tYXJ5CgpkZXNjIDwtIHN0YXQuZGVzYyhkZl9mb3Jfc3VtbWFyeSkKZGVzYwpoYWYgPC0gbGF0ZXgoZGVzYywKICAgICAgICAgICAgIGZpbGU9ImZpZ3Mvc3RhdHMudGV4IiwKICAgICAgICAgICAgIGJvb2t0YWJzPVRSVUUsCiAgICAgICAgICAgICB0YWJsZS5lbnY9RkFMU0UsCiAgICAgICAgICAgICBjZW50ZXI9Im5vbmUiKQoKYGBgCgojIEV4cGVyaW1lbnRzIHdpdGggaW5jcmVhc2luZyBjb3VudGVyIHZhbHVlCgpgYGB7cn0KYmlnIDwtIHJlYWRfZmlsZShwYXJhbXMkZmlsZV9iaWcpCmJpZyRyZTJnIDwtIHN1YigiLCIsICIuIiwgYmlnJHJlMmcpCmJpZyRyZTJnIDwtIGFzLm51bWVyaWMoYmlnJHJlMmcpCgpiaWcKYGBgCgoKYGBge3J9Cgp0b2dldGhlciA8LSBiaWdbLCBjKCJDb3VudGVyIiwgInJlMmciKV0KbmFtZXModG9nZXRoZXIpWzJdIDwtICJ0aW1lIgp0b2dldGhlciRhcHByb2FjaCA8LSAiUkUyIgoKdG1wIDwtIGJpZ1ssIGMoIkNvdW50ZXIiLCAiY2FkIildCm5hbWVzKHRtcClbMl0gPC0gInRpbWUiCnRtcCRhcHByb2FjaCA8LSAiQ0EiCnRvZ2V0aGVyIDwtIHJiaW5kKHRvZ2V0aGVyLCB0bXApCgp0bXAgPC0gYmlnWywgYygiQ291bnRlciIsICJzcm0iKV0KbmFtZXModG1wKVsyXSA8LSAidGltZSIKdG1wJGFwcHJvYWNoIDwtICJTUk0iCnRvZ2V0aGVyIDwtIHJiaW5kKHRvZ2V0aGVyLCB0bXApCgp0bXAgPC0gYmlnWywgYygiQ291bnRlciIsICJkb3QubmV0IildCm5hbWVzKHRtcClbMl0gPC0gInRpbWUiCnRtcCRhcHByb2FjaCA8LSAiLk5FVCIKdG9nZXRoZXIgPC0gcmJpbmQodG9nZXRoZXIsIHRtcCkKCnRtcCA8LSBiaWdbLCBjKCJDb3VudGVyIiwgImdyZXAiKV0KbmFtZXModG1wKVsyXSA8LSAidGltZSIKdG1wJGFwcHJvYWNoIDwtICJncmVwIgp0b2dldGhlciA8LSByYmluZCh0b2dldGhlciwgdG1wKQoKQklHX1NURVA9MTAwCgojIHJlbW92ZSB0b28gbWFueSBwb2ludHMKdG9nZXRoZXIgPC0gdG9nZXRoZXJbdG9nZXRoZXIkQ291bnRlciAlJSBCSUdfU1RFUCA9PSAwLF0KCmJpZ19wbG90IDwtIGdncGxvdChkYXRhPXRvZ2V0aGVyLCBhZXMoeD1Db3VudGVyLCB5PXRpbWUsIGNvbG91cj1hcHByb2FjaCkpICsKICBnZW9tX2xpbmUoKSArCiAgZ2VvbV9wb2ludChhZXMoc2hhcGU9YXBwcm9hY2gpKSArCiAgeGxpbShOQSwyMDAwKSArCiAgeWxpbShOQSwyMCkgKwogIGdlb21faGxpbmUoc2l6ZT0wLjEsIHlpbnRlcmNlcHQ9MCwgbGluZXR5cGU9ImRhc2hlZCIpICsKCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gYyguMDIsIC45OCksCiAgICAgICAgbGVnZW5kLmp1c3RpZmljYXRpb24gPSBjKCJsZWZ0IiwgInRvcCIpLAogICAgICAgICNsZWdlbmQuYm94LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3I9ImJsYWNrIiwgc2l6ZT0wLjUpLAogICAgICAgIGxlZ2VuZC5ib3guanVzdCA9ICJyaWdodCIsCiAgICAgICAgbGVnZW5kLm1hcmdpbiA9IG1hcmdpbigxLCAxLCAxLCAxKSwKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsKICBsYWJzKAogICAgICAjdGl0bGU9IlRpdGxlIiwKICAgICAgI3N1YnRpdGxlPSJTdWJ0aXRsZSIsCiAgICAgIHg9ImsiLAogICAgICB5PSJ0aW1lIFtzXSIpCiAgICAgICAgCgogICMgZ2VvbV9saW5lKGRhdGEgPSBiaWcsIGFlcyh4ID0gQ291bnRlciwgeSA9IHJlMmcpLCBjb2xvciA9ICJyZWQiKSArCiAgIyBnZW9tX2xpbmUoZGF0YSA9IGJpZywgYWVzKHggPSBDb3VudGVyLCB5ID0gY2EpLCBjb2xvciA9ICJibHVlIikgKwogICMgeGxhYignY291bnRlciB2YWx1ZScpICsKICAjIHlsYWIoJ3RpbWUgW3NdJykKCiNtYWtlX3Rpa3oocGFzdGUwKCJmaWdzL2JpZ19wbG90LnRpa3oiKSwgYmlnX3Bsb3QsIHdpZHRoPTIuNywgaGVpZ2h0PTIuNykKbWFrZV9wZGYocGFzdGUwKCJmaWdzL2JpZ19wbG90LnBkZiIpLCBiaWdfcGxvdCwgd2lkdGg9QklHX1NJWkUsIGhlaWdodD1CSUdfU0laRSkKCgpwbG90KGJpZ19wbG90KQpgYGAKCgpgYGB7cn0KIyBJbmZvcm1hdGlvbiBhYm91dCBEQ0FzCgojIGRmX2RjYXMgPSByZWFkLmNzdjIocGFyYW1zJGZpbGVfZGNhLAojICAgICAgICAgICAgICAgICAgIGhlYWRlcj1UUlVFLAojICAgICAgICAgICAgICAgICAgIHNlcD0iXHQiLAojICAgICAgICAgICAgICAgICAgIGRlYz0iLiIsCiMgICAgICAgICAgICAgICAgICAgY29tbWVudC5jaGFyPSIiLAojICAgICAgICAgICAgICAgICAgIHF1b3RlPSIiLAojICAgICAgICAgICAgICAgICAgIHN0cmlwLndoaXRlPVRSVUUsCiMgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycz1GQUxTRSkKIyAKIyAjIHNhbml0aXplCiMgZGZfZGNhcyR0aW1lb3V0cy5jbGFzc2ljYWxbaXMubmEoZGZfZGNhcyR0aW1lb3V0cy5jbGFzc2ljYWwpXSA8LSAwCgojZGZfZGNhcwpgYGAKCmBgYHtyfQojdG1zLmNsYXNzaWNhbCA8LSBkZl9kY2FzW2RmX2RjYXMkdGltZW91dHMuY2xhc3NpY2FsID09IDEsXQpgYGAKCgoKYGBge3J9CiNjb21wdXRlX3RpbWVvdXRzIDwtIGZ1bmN0aW9uKGRmLCBjb2wpIHsKIyAgdG1wIDwtIGRmW2RmWywgY29sXSA9PSBUSU1FT1VUX1ZBTCxdCiMgIHRtcAojfQoKYGBgCgo=