Install required packages

# install.packages("multdyn")
# install.packages("testit")
# install.packages("ggplot2")
# install.packages("cowplot")
# install.packages("reshape2")
# install.packages("data.table")

Load libraries

library(DGM)
library(ggplot2)
library(cowplot)
library(reshape2)
library(data.table)
library(testit)

Main variables

PATH_HOME = "/home/simon"
PATH_NET  = file.path(PATH_HOME, 'Drive', 'DGM_NetMats10_results')
PATH_NET_BO=file.path(PATH_HOME, 'Drive', 'DGM_NetMats10_results_stepwise')
PATH_TS   = file.path(PATH_HOME, 'Drive', 'HCP900_Parcellation_Timeseries_Netmats_ICAd25')
PATH      = file.path(PATH_HOME, 'Dropbox', 'Data', 'DGM-Sim')
PATH_DATA = file.path(PATH, 'data')
PATH_DEMOG =file.path(PATH_HOME, 'Drive', 'HCP')
PATH_FIG  = file.path(PATH, 'figures')
N      = 500
Nn = 10 # RSNs
N_t    = 1200 # Volumes
N_runs = 4
INFO   = 'NetMats10'
SUBJECTS = as.matrix(read.table(file.path(PATH_TS, 'subjectIDs.txt')))
TR=0.72
labels = read.table(file.path(PATH, 'results', 'RSN10Labels.txt'), header = T)
labels = labels[order(labels$NoNetMats25),]
COMP=labels$NoNetMats25
print(labels)

Demographics

We use the HCP 900 release

Load data

subj = as.matrix(read.table(file.path(PATH_TS, 'subjectIDs.txt')))
subj=subj[1:N]
           
demog=read.table(file.path(PATH_DEMOG, 'unrestricted_schwab_9_19_2017_8_41_11.csv'), 
                 sep = ",", header = TRUE)
idx = is.element(demog$Subject, subj)
assert(sum(idx) == N)
demog = subset(demog, idx)
assert(nrow(demog) == N)
summary(demog$Gender)/N
    F     M 
0.566 0.434 
summary(demog$Age)/N
22-25 26-30 31-35   36+ 
0.206 0.422 0.362 0.010 

Loading network data

# subj_r1 = vector(mode = "list", length = N)
# subj_r2 = vector(mode = "list", length = N)
# subj_r3 = vector(mode = "list", length = N)
# subj_r4 = vector(mode = "list", length = N)
# 
# for (s in 1:N) {
#   subj_r1[[s]] = read.subject(PATH_NET, sprintf("%s_Run_%03d", SUBJECTS[s], 1), Nn)
#   subj_r2[[s]] = read.subject(PATH_NET, sprintf("%s_Run_%03d", SUBJECTS[s], 2), Nn)
#   subj_r3[[s]] = read.subject(PATH_NET, sprintf("%s_Run_%03d", SUBJECTS[s], 3), Nn)
#   subj_r4[[s]] = read.subject(PATH_NET, sprintf("%s_Run_%03d", SUBJECTS[s], 4), Nn)
#   print(sprintf("Subject %03d loaded",s))
# }
# 
# dgm.net10.r1 = dgm.group(subj_r1)
# dgm.net10.r2 = dgm.group(subj_r2)
# dgm.net10.r3 = dgm.group(subj_r3)
# dgm.net10.r4 = dgm.group(subj_r4)
# 
# # save some space
# #dgm.net10.r1$models = NULL
# dgm.net10.r2$models = NULL
# dgm.net10.r3$models = NULL
# dgm.net10.r4$models = NULL
# 
# f=file(file.path(PATH,"results", "DGM-RSN10.RData"))
# save(dgm.net10.r1, dgm.net10.r2, dgm.net10.r3, dgm.net10.r4, file = f, compress = T)
# close(f)
load(file.path(PATH, 'results', 'DGM-RSN10.RData'))

Plot: discount factor delta distribution per node

d.r1=melt(dgm.net10.r1$df_)
d.r2=melt(dgm.net10.r2$df_)
d.r3=melt(dgm.net10.r3$df_)
d.r4=melt(dgm.net10.r4$df_)
set.seed(1980) # because jitter will always create a slightly different image
p1 = ggplot(d.r1, aes(x=as.factor(Var2), y=value)) +
  geom_point(shape=1, color="gray50", size=2, position = position_jitter(width = NULL, height = 0.01)) +
  geom_boxplot(width=0.6) +
  ggtitle(sprintf("Run 1", N)) + ylab("df") + xlab("node")
p2 = ggplot(d.r2, aes(x=as.factor(Var2), y=value)) +
  geom_point(shape=1, color="gray50", size=2, position = position_jitter(width = NULL, height = 0.01)) +
  geom_boxplot(width=0.6) +
  ggtitle(sprintf("Run 2", N)) + ylab("df") + xlab("node")
p3 = ggplot(d.r3, aes(x=as.factor(Var2), y=value)) +
  geom_point(shape=1, color="gray50", size=2, position = position_jitter(width = NULL, height = 0.01)) +
  geom_boxplot(width=0.6) +
  ggtitle(sprintf("Run 3", N)) + ylab("df") + xlab("node")
p4 = ggplot(d.r4, aes(x=as.factor(Var2), y=value)) +
  geom_point(shape=1, color="gray50", size=2, position = position_jitter(width = NULL, height = 0.01)) +
  geom_boxplot(width=0.6) +
  ggtitle(sprintf("Run 4", N)) + ylab("df") + xlab("node")
plot_grid(p1, p2, p3, p4, ncol = 2, nrow = 2)

DFs with parents only

df.10r1 = dgm.net10.r1$df_
df.10r2 = dgm.net10.r2$df_
df.10r3 = dgm.net10.r3$df_
df.10r4 = dgm.net10.r4$df_
df.10r1[t(apply(dgm.net10.r1$am, 3, colSums)) == 0] = NA
df.10r2[t(apply(dgm.net10.r2$am, 3, colSums)) == 0] = NA
df.10r3[t(apply(dgm.net10.r3$am, 3, colSums)) == 0] = NA
df.10r4[t(apply(dgm.net10.r4$am, 3, colSums)) == 0] = NA
summary(colMeans(df.10r1, na.rm = T))
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
 0.6951  0.7418  0.7986  0.8082  0.8766  0.9480 
summary(colMeans(df.10r2, na.rm = T))
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
 0.6947  0.7266  0.7995  0.8010  0.8580  0.9554 
summary(colMeans(df.10r3, na.rm = T))
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
 0.6649  0.7396  0.8057  0.8083  0.8876  0.9481 
summary(colMeans(df.10r4, na.rm = T))
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
 0.6606  0.7258  0.8295  0.8099  0.8806  0.9478 

Load time series data

# f = list.files(file.path(PATH_TS, "node_timeseries", "3T_HCP820_MSMAll_d25_ts2"), "*.txt")
# # read data
# ts = array(NA, dim=c(N_t, Nn, N_runs, N))
# for (s in 1:N) {
#   d = scaleTs(as.matrix(read.table(file.path(PATH_TS, "node_timeseries", "3T_HCP820_MSMAll_d25_ts2", f[s]))))
#   assert(nrow(d) == N_t*N_runs)
#   ts[,,1,s] = d[1:1200,COMP]
#   ts[,,2,s] = d[1201:2400,COMP]
#   ts[,,3,s] = d[2401:3600,COMP]
#   ts[,,4,s] = d[3601:4800,COMP]
# }
# 
# f=file(file.path(PATH,"RSN10-ts.RData"))
# save(ts, file = f)
# close(f)
load(file.path(PATH, 'results', 'RSN10-ts.RData'))

Variance of nodes

We calculate the SD across time for the subject’s node.

# ts 1200 x 10 x 4 x 500
r1=apply(ts[,,1,], c(3,2), sd)
r2=apply(ts[,,2,], c(3,2), sd)
r3=apply(ts[,,3,], c(3,2), sd)
r4=apply(ts[,,4,], c(3,2), sd)
p1 = ggplot(melt(r1), aes(x=as.factor(Var2), y=value)) +
  geom_point(shape=1, color="gray50", size=2) +
  geom_boxplot(width=0.3) +
  ggtitle(sprintf("Run 1", N)) + ylab("SD") + xlab("RSNs")
p2 = ggplot(melt(r2), aes(x=as.factor(Var2), y=value)) +
  geom_point(shape=1, color="gray50", size=2) +
  geom_boxplot(width=0.3) +
  ggtitle(sprintf("Run 2", N)) + ylab("SD") + xlab("RSNs")
p3 = ggplot(melt(r3), aes(x=as.factor(Var2), y=value)) +
  geom_point(shape=1, color="gray50", size=2) +
  geom_boxplot(width=0.3) +
  ggtitle(sprintf("Run 3", N)) + ylab("SD") + xlab("RSNs")
p4 = ggplot(melt(r4), aes(x=as.factor(Var2), y=value)) +
  geom_point(shape=1, color="gray50", size=2) +
  geom_boxplot(width=0.3) +
  ggtitle(sprintf("Run 4", N)) + ylab("SD") + xlab("RSNs")
plot_grid(p1, p2, p3, p4, ncol = 2, nrow = 2)

ggsave(path = PATH_FIG, "Sd_10RSNs.png")
Saving 6 x 4 in image

Correlation Plots

LIM=c(-0.65,0.65)
p1 = gplotMat(rmdiag(corTs(ts[,,1,])), title=sprintf("Run 1", N), lim=LIM, nodeLabels = labels$Label,
              axisTextSize = 8, xAngle = 90, colMapLabel=expression("Pearson\'s"~italic(r)),
              gradient = c("blue", "white", "red")) +
  xlab("Node") + ylab("Node") + scale_x_continuous(breaks = 0.5:9.5, labels = labels$Label )
p2 = gplotMat(rmdiag(corTs(ts[,,2,])), title=sprintf("Run 2", N), lim=LIM, nodeLabels = labels$Label,
              axisTextSize = 8, xAngle = 90, colMapLabel=expression("Pearson\'s"~italic(r)),
              gradient = c("blue", "white", "red")) +
  xlab("Node") + ylab("Node") + scale_x_continuous(breaks = 0.5:9.5, labels = labels$Label )
p3 = gplotMat(rmdiag(corTs(ts[,,3,])), title=sprintf("Run 3", N), lim=LIM, nodeLabels = labels$Label,
              axisTextSize = 8, xAngle = 90, colMapLabel=expression("Pearson\'s"~italic(r)),
              gradient = c("blue", "white", "red")) +
  xlab("Node") + ylab("Node") + scale_x_continuous(breaks = 0.5:9.5, labels = labels$Label )
p4 = gplotMat(rmdiag(corTs(ts[,,4,])), title=sprintf("Run 4", N), lim=LIM, nodeLabels = labels$Label,
              axisTextSize = 8, xAngle = 90, colMapLabel=expression("Pearson\'s"~italic(r)),
              gradient = c("blue", "white", "red")) +
  xlab("Node") + ylab("Node") + scale_x_continuous(breaks = 0.5:9.5, labels = labels$Label )
plot_grid(p1, p2, p3, p4, ncol = 2, nrow = 2, rel_widths = c(1, 1))

ggsave(path = PATH_FIG, "R_10RSNs.png")

Plot example timeseries

idx = 1:round(120/TR) # first 2 minutes
# random sampling of subject s and nodes n
nodes = 5 # no. of nodes to plot
d = ts[idx,sample(Nn,nodes),,sample(N,1)]
p1 = ggplot(melt(d[,1,]), aes(x = Var1, y = value, group=Var2, color=as.factor(Var2))) + 
  geom_line() + theme_minimal() + ggtitle("Run 1")
p2 = ggplot(melt(d[,2,]), aes(x = Var1, y = value, group=Var2, color=as.factor(Var2))) +
  geom_line() + theme_minimal() + ggtitle("Run 2")
p3 = ggplot(melt(d[,3,]), aes(x = Var1, y = value, group=Var2, color=as.factor(Var2))) +
  geom_line() + theme_minimal() + ggtitle("Run 3")
p4 = ggplot(melt(d[,4,]), aes(x = Var1, y = value, group=Var2, color=as.factor(Var2))) + 
  geom_line() + theme_minimal() + ggtitle("Run 4")
plot_grid(p1, p2, p3, p4, ncol = 1, nrow = 4, rel_widths = c(1, 1))

Network consistency across subjects

stats.r1 = binom.nettest(dgm.net10.r1$am, alter = "greater")
stats.r2 = binom.nettest(dgm.net10.r2$am, alter = "greater")
stats.r3 = binom.nettest(dgm.net10.r3$am, alter = "greater")
stats.r4 = binom.nettest(dgm.net10.r4$am, alter = "greater")

Difference between e=0 and e=20

x = c(sum(dgm.net10.r1$tam != dgm.net10.r1$am),
      sum(dgm.net10.r2$tam != dgm.net10.r2$am),
      sum(dgm.net10.r3$tam != dgm.net10.r3$am),
      sum(dgm.net10.r4$tam != dgm.net10.r4$am)
)
print(x)
[1] 300 243 237 229
print(x/(N*Nn*(Nn-1)))
[1] 0.006666667 0.005400000 0.005266667 0.005088889

Figure 8

mylim = c(0.1, 0.68)
pos = 0.5:9.5
s = 0.2
p1 = gplotMat(stats.r1$adj, title = "run 1", titleTextSize = 12, nodeLabels=labels$Label,
              axisTextSize=8, xAngle=90, lim = mylim, barWidth = 0.2, textSize = 11) +
  scale_x_continuous(breaks = pos, labels = labels$Label) +
  theme(plot.margin = unit(c(s, 0, 0, 0), "cm"))
p2 = gplotMat(rmna(stats.r1$adj_fdr), title = "binomial test", titleTextSize = 12, nodeLabels=labels$Label,
              axisTextSize=8, xAngle=90, lim = mylim, barWidth = 0.2, textSize = 11) +
  scale_x_continuous(breaks = pos, labels = labels$Label) +
  theme(plot.margin = unit(c(s, 0, 0, 0), "cm"))
p3 = gplotMat(stats.r2$adj, title = "run 2", titleTextSize = 12, nodeLabels=labels$Label,
              axisTextSize=8, xAngle=90, lim = mylim, barWidth = 0.2, textSize = 11) +
  scale_x_continuous(breaks = pos, labels = labels$Label) +
  theme(plot.margin = unit(c(s, 0, 0, 0), "cm"))
p4 = gplotMat(rmna(stats.r2$adj_fdr), title = "binomial test", titleTextSize = 12, nodeLabels=labels$Label,
              axisTextSize=8, xAngle=90, lim = mylim, barWidth = 0.2, textSize = 11) +
  scale_x_continuous(breaks = pos, labels = labels$Label) +
  theme(plot.margin = unit(c(s, 0, 0, 0), "cm"))
p5 = gplotMat(stats.r3$adj, title = "run 3", titleTextSize = 12, nodeLabels=labels$Label,
              axisTextSize=8, xAngle=90, lim = mylim, barWidth = 0.2, textSize = 11) +
  scale_x_continuous(breaks = pos, labels = labels$Label) +
  theme(plot.margin = unit(c(s, 0, 0, 0), "cm"))
p6 = gplotMat(rmna(stats.r3$adj_fdr), title = "binomial test", titleTextSize = 12, nodeLabels=labels$Label,
              axisTextSize=8, xAngle=90, lim = mylim, barWidth = 0.2, textSize = 11) +
  scale_x_continuous(breaks = pos, labels = labels$Label) +
  theme(plot.margin = unit(c(s, 0, 0, 0), "cm"))
p7 = gplotMat(stats.r4$adj, title = "run 4", titleTextSize = 12, nodeLabels=labels$Label,
              axisTextSize=8, xAngle=90, lim = mylim, barWidth = 0.2, textSize = 11) +
  scale_x_continuous(breaks = pos, labels = labels$Label) +
  theme(plot.margin = unit(c(s, 0, 0, 0), "cm"))
p8 = gplotMat(rmna(stats.r4$adj_fdr), title = "binomial test", titleTextSize = 12, nodeLabels=labels$Label,
              axisTextSize=8, xAngle=90, lim = mylim, barWidth = 0.2, textSize = 11) +
  scale_x_continuous(breaks = pos, labels = labels$Label) +
  theme(plot.margin = unit(c(s, 0, 0, 0), "cm"))
plot_grid(p1, p2, p3, p4, p5, p6, p7, p8, ncol = 2, nrow = 4, rel_heights = c(1,1,1,1))

ggsave(path = PATH_FIG, "Fig8.png")

Networks consistency across runs

# edge reproduced in 3 runs or more
m3 = dgm.net10.r1$am + dgm.net10.r2$am + dgm.net10.r3$am + dgm.net10.r4$am > 2
# edge reproduced in all runs
m4 = dgm.net10.r1$am * dgm.net10.r2$am * dgm.net10.r3$am * dgm.net10.r4$am
# consistently no edge in all runs
mn = (1-dgm.net10.r1$am) * (1-dgm.net10.r2$am) * (1-dgm.net10.r3$am) * (1-dgm.net10.r4$am)
stats.m3 = binom.nettest(m3, alter = "greater")
stats.m4 = binom.nettest(m4, alter = "greater")
stats.mn = binom.nettest(mn, alter = "greater")

Figure 9

p1 = gplotMat(stats.m3$adj, title = "edge in 3/4 runs", nodeLabels=labels$Label,
              axisTextSize=8, xAngle=90, lim = c(0.1, 0.62), barWidth = 0.2, textSize = 11) +
  scale_x_continuous(breaks = pos, labels = labels$Label) +
  theme(plot.margin = unit(c(s, 0, 0, 0), "cm"))
p2 = gplotMat(rmna(stats.m3$adj_fdr), title = "binomial test", nodeLabels=labels$Label,
              axisTextSize=8, xAngle=90, lim = c(0.1, 0.62), barWidth = 0.2, textSize = 11) +
  scale_x_continuous(breaks = pos, labels = labels$Label) +
  theme(plot.margin = unit(c(s, 0, 0, 0), "cm"))
p3 = gplotMat(stats.m4$adj, title = "edge in 4/4 runs", nodeLabels=labels$Label,
              axisTextSize=8, xAngle=90, lim = c(0.1, 0.62), barWidth = 0.2, textSize = 11) +
  scale_x_continuous(breaks = pos, labels = labels$Label) +
  theme(plot.margin = unit(c(s, 0, 0, 0), "cm"))
p4 = gplotMat(rmna(stats.m4$adj_fdr), title = "binomial test", nodeLabels=labels$Label, 
              axisTextSize=8, xAngle=90, lim = c(0.1,0.62), barWidth = 0.2, textSize = 11) +
  scale_x_continuous(breaks = pos, labels = labels$Label) +
  theme(plot.margin = unit(c(s, 0, 0, 0), "cm"))
p5 = gplotMat(rmdiag(stats.mn$adj), title = "no edge in 4/4 runs", nodeLabels=labels$Label,
              gradient = c("white", "violet", "blue"), axisTextSize=8, xAngle=90, 
              barWidth = 0.2, textSize = 11) +
  scale_x_continuous(breaks = pos, labels = labels$Label) +
  theme(plot.margin = unit(c(s, 0, 0, 0), "cm"))
p6 = gplotMat(rmdiag(rmna(stats.mn$adj_fdr)), title = "binomial test", nodeLabels=labels$Label,
              gradient = c("white", "violet", "blue"), axisTextSize=8, xAngle=90,
              barWidth = 0.2, textSize = 11) +
  scale_x_continuous(breaks = pos, labels = labels$Label) +
  theme(plot.margin = unit(c(s, 0, 0, 0), "cm"))
plot_grid(p1, p2, p3, p4, p5, p6, labels=c("A", "", "", "", "B", ""),
          ncol = 2, nrow = 3, rel_heights = c(1,1,1))

ggsave(path = PATH_FIG, "Fig9.png")

Figure connectivity strength

# find representative subject showing group effect [DMN VisMed and Aud]->Cereb
# s=sample(N,1) # subject
s=35
idx=array(FALSE, dim=c(Nn, Nn))
idx[2,8] = idx[3,8] = idx[9,8] = TRUE
#stats.r1$adj_fdr[idx]
a=dgm.net10.r1$am[,,s]
a[idx]
[1] 1 1 1
r=1 # run
node=8
# get model space
sub = read.subject(PATH_NET, sprintf("%s_Run_%03d", SUBJECTS[s], r), Nn)
df = sub$winner[12,node]
pars = sub$winner[2:Nn,node]
pars = pars[pars != 0]
mypars=c(2,9)
idxpar=match(mypars,pars)
Nt=nrow(ts)
Ft=array(1,dim=c(Nt,length(pars)+1))
Ft[,2:ncol(Ft)]=ts[,pars,r,s] # selects parents
Yt=ts[,node,r,s]
# get df corresponding to parent model pars
#df = getModel(sub$models[[1]], pars)[Nn+2]
fit=dlm.lpl(Yt, t(Ft), delta = df)
y = dlm.retro(fit$mt, fit$CSt, fit$RSt, fit$nt, fit$dt)
theta=t(y$smt[2:(length(pars)+1),])
scaleFUN <- function(x) sprintf("%.1f", x)
start=1
seconds=500 # max is 864
idx=round(start/TR):round((start+seconds)/TR)
Nt_=length(idx)
d=melt(Yt[idx])
d$time=1:Nt_
d$labels="Cer  "
p1 = ggplot(d, aes(x = time*TR, y = value, color=labels)) + geom_line() +
  theme_minimal() + ggtitle("Node time series (child)") +
  scale_color_discrete(name = "labels") + xlab("seconds") + ylab("BOLD") + #xlim(c(0,seconds)) +
  scale_y_continuous(labels=scaleFUN) +
  theme(axis.text.x = element_text(size=10), axis.text.y = element_text(size=10),
        axis.title.y = element_text(size=10), legend.text=element_text(size=10),
        plot.title = element_text(size=10,face="bold"))
#p1 = p1 + scale_colour_brewer(palette="Dark2")
#d=melt(Ft[idx,2:(length(pars)+1)])
d=melt(Ft[idx,idxpar+1])
d$time=1:Nt_
d$labels=c(rep("DMN", Nt_),rep("Au", Nt_))
p2 = ggplot(d, aes(x = time*TR, y = value, group=Var2, color=labels)) + geom_line() +
  theme_minimal() + ggtitle("Node time series (parents)") +
  scale_color_discrete(name = "labels") + xlab("seconds") + ylab("BOLD") + #xlim(c(0,seconds)) +
  scale_y_continuous(labels=scaleFUN) +
  theme(axis.text.x = element_text(size=10), axis.text.y = element_text(size=10),
        axis.title.y = element_text(size=10), legend.text=element_text(size=10),
        plot.title = element_text(size=10,face="bold"))
d=melt(theta[idx,idxpar])
d$time=1:Nt_
d$labels=c(rep("DMN", Nt_),rep("Au", Nt_))
p3 = ggplot(d, aes(x = time*TR, y = value, group=Var2, color=labels)) + geom_line() +
  theme_minimal() + ggtitle("Influence of parents on the child node") +
  #scale_color_discrete(name = expression(paste(italic(theta^"r=1"), ""[italic("t")]))) +
  scale_color_discrete(name = "labels") +
  xlab("seconds") + ylab(expression(theta)) + #xlim(c(0,seconds)) +
  theme(axis.text.x = element_text(size=10), axis.text.y = element_text(size=10),
        axis.title.y = element_text(size=10), legend.text=element_text(size=10),
        plot.title = element_text(size=10,face="bold"))
plot_grid(p1, p2, p3, ncol = 1, nrow = 3, rel_widths = c(1,1,1), labels = c("A", "B", "C"))

ggsave(path = PATH_FIG, "Theta_RSN.png")
Saving 5 x 5 in image
LS0tCnRpdGxlOiAiREdNLVJTTjEwIgphdXRob3I6ICJTaW1vbiBTY2h3YWIiCmRhdGU6ICIyNiBGZWIgMjAxOCIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyMgSW5zdGFsbCByZXF1aXJlZCBwYWNrYWdlcyAKYGBge3J9CiMgaW5zdGFsbC5wYWNrYWdlcygibXVsdGR5biIpCiMgaW5zdGFsbC5wYWNrYWdlcygidGVzdGl0IikKIyBpbnN0YWxsLnBhY2thZ2VzKCJnZ3Bsb3QyIikKIyBpbnN0YWxsLnBhY2thZ2VzKCJjb3dwbG90IikKIyBpbnN0YWxsLnBhY2thZ2VzKCJyZXNoYXBlMiIpCiMgaW5zdGFsbC5wYWNrYWdlcygiZGF0YS50YWJsZSIpCmBgYAoKIyMgTG9hZCBsaWJyYXJpZXMgCmBgYHtyLCBtZXNzYWdlPUZBTFNFfQpsaWJyYXJ5KERHTSkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGNvd3Bsb3QpCmxpYnJhcnkocmVzaGFwZTIpCmxpYnJhcnkoZGF0YS50YWJsZSkKbGlicmFyeSh0ZXN0aXQpCmBgYAoKIyMgTWFpbiB2YXJpYWJsZXMgCmBgYHtyfQpQQVRIX0hPTUUgPSAiL2hvbWUvc2ltb24iClBBVEhfTkVUICA9IGZpbGUucGF0aChQQVRIX0hPTUUsICdEcml2ZScsICdER01fTmV0TWF0czEwX3Jlc3VsdHMnKQpQQVRIX05FVF9CTz1maWxlLnBhdGgoUEFUSF9IT01FLCAnRHJpdmUnLCAnREdNX05ldE1hdHMxMF9yZXN1bHRzX3N0ZXB3aXNlJykKUEFUSF9UUyAgID0gZmlsZS5wYXRoKFBBVEhfSE9NRSwgJ0RyaXZlJywgJ0hDUDkwMF9QYXJjZWxsYXRpb25fVGltZXNlcmllc19OZXRtYXRzX0lDQWQyNScpClBBVEggICAgICA9IGZpbGUucGF0aChQQVRIX0hPTUUsICdEcm9wYm94JywgJ0RhdGEnLCAnREdNLVNpbScpClBBVEhfREFUQSA9IGZpbGUucGF0aChQQVRILCAnZGF0YScpClBBVEhfREVNT0cgPWZpbGUucGF0aChQQVRIX0hPTUUsICdEcml2ZScsICdIQ1AnKQpQQVRIX0ZJRyAgPSBmaWxlLnBhdGgoUEFUSCwgJ2ZpZ3VyZXMnKQoKTiAgICAgID0gNTAwCk5uID0gMTAgIyBSU05zCk5fdCAgICA9IDEyMDAgIyBWb2x1bWVzCk5fcnVucyA9IDQKSU5GTyAgID0gJ05ldE1hdHMxMCcKU1VCSkVDVFMgPSBhcy5tYXRyaXgocmVhZC50YWJsZShmaWxlLnBhdGgoUEFUSF9UUywgJ3N1YmplY3RJRHMudHh0JykpKQpUUj0wLjcyCmxhYmVscyA9IHJlYWQudGFibGUoZmlsZS5wYXRoKFBBVEgsICdyZXN1bHRzJywgJ1JTTjEwTGFiZWxzLnR4dCcpLCBoZWFkZXIgPSBUKQpsYWJlbHMgPSBsYWJlbHNbb3JkZXIobGFiZWxzJE5vTmV0TWF0czI1KSxdCkNPTVA9bGFiZWxzJE5vTmV0TWF0czI1CgpwcmludChsYWJlbHMpCmBgYAoKIyMgRGVtb2dyYXBoaWNzCldlIHVzZSB0aGUgSENQIDkwMCByZWxlYXNlCgpMb2FkIGRhdGEKYGBge3J9CnN1YmogPSBhcy5tYXRyaXgocmVhZC50YWJsZShmaWxlLnBhdGgoUEFUSF9UUywgJ3N1YmplY3RJRHMudHh0JykpKQpzdWJqPXN1YmpbMTpOXQogICAgICAgICAgIApkZW1vZz1yZWFkLnRhYmxlKGZpbGUucGF0aChQQVRIX0RFTU9HLCAndW5yZXN0cmljdGVkX3NjaHdhYl85XzE5XzIwMTdfOF80MV8xMS5jc3YnKSwgCiAgICAgICAgICAgICAgICAgc2VwID0gIiwiLCBoZWFkZXIgPSBUUlVFKQppZHggPSBpcy5lbGVtZW50KGRlbW9nJFN1YmplY3QsIHN1YmopCmFzc2VydChzdW0oaWR4KSA9PSBOKQoKZGVtb2cgPSBzdWJzZXQoZGVtb2csIGlkeCkKYXNzZXJ0KG5yb3coZGVtb2cpID09IE4pCmBgYAoKYGBge3J9CnN1bW1hcnkoZGVtb2ckR2VuZGVyKS9OCgpzdW1tYXJ5KGRlbW9nJEFnZSkvTgpgYGAKCiMjIExvYWRpbmcgbmV0d29yayBkYXRhCmBgYHtyfQojIHN1YmpfcjEgPSB2ZWN0b3IobW9kZSA9ICJsaXN0IiwgbGVuZ3RoID0gTikKIyBzdWJqX3IyID0gdmVjdG9yKG1vZGUgPSAibGlzdCIsIGxlbmd0aCA9IE4pCiMgc3Vial9yMyA9IHZlY3Rvcihtb2RlID0gImxpc3QiLCBsZW5ndGggPSBOKQojIHN1YmpfcjQgPSB2ZWN0b3IobW9kZSA9ICJsaXN0IiwgbGVuZ3RoID0gTikKIyAKIyBmb3IgKHMgaW4gMTpOKSB7CiMgICBzdWJqX3IxW1tzXV0gPSByZWFkLnN1YmplY3QoUEFUSF9ORVQsIHNwcmludGYoIiVzX1J1bl8lMDNkIiwgU1VCSkVDVFNbc10sIDEpLCBObikKIyAgIHN1YmpfcjJbW3NdXSA9IHJlYWQuc3ViamVjdChQQVRIX05FVCwgc3ByaW50ZigiJXNfUnVuXyUwM2QiLCBTVUJKRUNUU1tzXSwgMiksIE5uKQojICAgc3Vial9yM1tbc11dID0gcmVhZC5zdWJqZWN0KFBBVEhfTkVULCBzcHJpbnRmKCIlc19SdW5fJTAzZCIsIFNVQkpFQ1RTW3NdLCAzKSwgTm4pCiMgICBzdWJqX3I0W1tzXV0gPSByZWFkLnN1YmplY3QoUEFUSF9ORVQsIHNwcmludGYoIiVzX1J1bl8lMDNkIiwgU1VCSkVDVFNbc10sIDQpLCBObikKIyAgIHByaW50KHNwcmludGYoIlN1YmplY3QgJTAzZCBsb2FkZWQiLHMpKQojIH0KIyAKIyBkZ20ubmV0MTAucjEgPSBkZ20uZ3JvdXAoc3Vial9yMSkKIyBkZ20ubmV0MTAucjIgPSBkZ20uZ3JvdXAoc3Vial9yMikKIyBkZ20ubmV0MTAucjMgPSBkZ20uZ3JvdXAoc3Vial9yMykKIyBkZ20ubmV0MTAucjQgPSBkZ20uZ3JvdXAoc3Vial9yNCkKIyAKIyAjIHNhdmUgc29tZSBzcGFjZQojICNkZ20ubmV0MTAucjEkbW9kZWxzID0gTlVMTAojIGRnbS5uZXQxMC5yMiRtb2RlbHMgPSBOVUxMCiMgZGdtLm5ldDEwLnIzJG1vZGVscyA9IE5VTEwKIyBkZ20ubmV0MTAucjQkbW9kZWxzID0gTlVMTAojIAojIGY9ZmlsZShmaWxlLnBhdGgoUEFUSCwicmVzdWx0cyIsICJER00tUlNOMTAuUkRhdGEiKSkKIyBzYXZlKGRnbS5uZXQxMC5yMSwgZGdtLm5ldDEwLnIyLCBkZ20ubmV0MTAucjMsIGRnbS5uZXQxMC5yNCwgZmlsZSA9IGYsIGNvbXByZXNzID0gVCkKIyBjbG9zZShmKQpsb2FkKGZpbGUucGF0aChQQVRILCAncmVzdWx0cycsICdER00tUlNOMTAuUkRhdGEnKSkKYGBgCgojIyBQbG90OiBkaXNjb3VudCBmYWN0b3IgZGVsdGEgZGlzdHJpYnV0aW9uIHBlciBub2RlCmBgYHtyLCBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD01fQoKZC5yMT1tZWx0KGRnbS5uZXQxMC5yMSRkZl8pCmQucjI9bWVsdChkZ20ubmV0MTAucjIkZGZfKQpkLnIzPW1lbHQoZGdtLm5ldDEwLnIzJGRmXykKZC5yND1tZWx0KGRnbS5uZXQxMC5yNCRkZl8pCgpzZXQuc2VlZCgxOTgwKSAjIGJlY2F1c2Ugaml0dGVyIHdpbGwgYWx3YXlzIGNyZWF0ZSBhIHNsaWdodGx5IGRpZmZlcmVudCBpbWFnZQpwMSA9IGdncGxvdChkLnIxLCBhZXMoeD1hcy5mYWN0b3IoVmFyMiksIHk9dmFsdWUpKSArCiAgZ2VvbV9wb2ludChzaGFwZT0xLCBjb2xvcj0iZ3JheTUwIiwgc2l6ZT0yLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcih3aWR0aCA9IE5VTEwsIGhlaWdodCA9IDAuMDEpKSArCiAgZ2VvbV9ib3hwbG90KHdpZHRoPTAuNikgKwogIGdndGl0bGUoc3ByaW50ZigiUnVuIDEiLCBOKSkgKyB5bGFiKCJkZiIpICsgeGxhYigibm9kZSIpCgpwMiA9IGdncGxvdChkLnIyLCBhZXMoeD1hcy5mYWN0b3IoVmFyMiksIHk9dmFsdWUpKSArCiAgZ2VvbV9wb2ludChzaGFwZT0xLCBjb2xvcj0iZ3JheTUwIiwgc2l6ZT0yLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcih3aWR0aCA9IE5VTEwsIGhlaWdodCA9IDAuMDEpKSArCiAgZ2VvbV9ib3hwbG90KHdpZHRoPTAuNikgKwogIGdndGl0bGUoc3ByaW50ZigiUnVuIDIiLCBOKSkgKyB5bGFiKCJkZiIpICsgeGxhYigibm9kZSIpCgpwMyA9IGdncGxvdChkLnIzLCBhZXMoeD1hcy5mYWN0b3IoVmFyMiksIHk9dmFsdWUpKSArCiAgZ2VvbV9wb2ludChzaGFwZT0xLCBjb2xvcj0iZ3JheTUwIiwgc2l6ZT0yLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcih3aWR0aCA9IE5VTEwsIGhlaWdodCA9IDAuMDEpKSArCiAgZ2VvbV9ib3hwbG90KHdpZHRoPTAuNikgKwogIGdndGl0bGUoc3ByaW50ZigiUnVuIDMiLCBOKSkgKyB5bGFiKCJkZiIpICsgeGxhYigibm9kZSIpCgpwNCA9IGdncGxvdChkLnI0LCBhZXMoeD1hcy5mYWN0b3IoVmFyMiksIHk9dmFsdWUpKSArCiAgZ2VvbV9wb2ludChzaGFwZT0xLCBjb2xvcj0iZ3JheTUwIiwgc2l6ZT0yLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcih3aWR0aCA9IE5VTEwsIGhlaWdodCA9IDAuMDEpKSArCiAgZ2VvbV9ib3hwbG90KHdpZHRoPTAuNikgKwogIGdndGl0bGUoc3ByaW50ZigiUnVuIDQiLCBOKSkgKyB5bGFiKCJkZiIpICsgeGxhYigibm9kZSIpCgpwbG90X2dyaWQocDEsIHAyLCBwMywgcDQsIG5jb2wgPSAyLCBucm93ID0gMikKYGBgCgojIyMgREZzIHdpdGggcGFyZW50cyBvbmx5CgpgYGB7ciwgZmlnLmhlaWdodD0yLCBmaWcud2lkdGg9NH0KZGYuMTByMSA9IGRnbS5uZXQxMC5yMSRkZl8KZGYuMTByMiA9IGRnbS5uZXQxMC5yMiRkZl8KZGYuMTByMyA9IGRnbS5uZXQxMC5yMyRkZl8KZGYuMTByNCA9IGRnbS5uZXQxMC5yNCRkZl8KCmRmLjEwcjFbdChhcHBseShkZ20ubmV0MTAucjEkYW0sIDMsIGNvbFN1bXMpKSA9PSAwXSA9IE5BCmRmLjEwcjJbdChhcHBseShkZ20ubmV0MTAucjIkYW0sIDMsIGNvbFN1bXMpKSA9PSAwXSA9IE5BCmRmLjEwcjNbdChhcHBseShkZ20ubmV0MTAucjMkYW0sIDMsIGNvbFN1bXMpKSA9PSAwXSA9IE5BCmRmLjEwcjRbdChhcHBseShkZ20ubmV0MTAucjQkYW0sIDMsIGNvbFN1bXMpKSA9PSAwXSA9IE5BCgpzdW1tYXJ5KGNvbE1lYW5zKGRmLjEwcjEsIG5hLnJtID0gVCkpCnN1bW1hcnkoY29sTWVhbnMoZGYuMTByMiwgbmEucm0gPSBUKSkKc3VtbWFyeShjb2xNZWFucyhkZi4xMHIzLCBuYS5ybSA9IFQpKQpzdW1tYXJ5KGNvbE1lYW5zKGRmLjEwcjQsIG5hLnJtID0gVCkpCmBgYAoKIyMgTG9hZCB0aW1lIHNlcmllcyBkYXRhCmBgYHtyfQojIGYgPSBsaXN0LmZpbGVzKGZpbGUucGF0aChQQVRIX1RTLCAibm9kZV90aW1lc2VyaWVzIiwgIjNUX0hDUDgyMF9NU01BbGxfZDI1X3RzMiIpLCAiKi50eHQiKQojICMgcmVhZCBkYXRhCiMgdHMgPSBhcnJheShOQSwgZGltPWMoTl90LCBObiwgTl9ydW5zLCBOKSkKIyBmb3IgKHMgaW4gMTpOKSB7CiMgICBkID0gc2NhbGVUcyhhcy5tYXRyaXgocmVhZC50YWJsZShmaWxlLnBhdGgoUEFUSF9UUywgIm5vZGVfdGltZXNlcmllcyIsICIzVF9IQ1A4MjBfTVNNQWxsX2QyNV90czIiLCBmW3NdKSkpKQojICAgYXNzZXJ0KG5yb3coZCkgPT0gTl90Kk5fcnVucykKIyAgIHRzWywsMSxzXSA9IGRbMToxMjAwLENPTVBdCiMgICB0c1ssLDIsc10gPSBkWzEyMDE6MjQwMCxDT01QXQojICAgdHNbLCwzLHNdID0gZFsyNDAxOjM2MDAsQ09NUF0KIyAgIHRzWywsNCxzXSA9IGRbMzYwMTo0ODAwLENPTVBdCiMgfQojIAojIGY9ZmlsZShmaWxlLnBhdGgoUEFUSCwiUlNOMTAtdHMuUkRhdGEiKSkKIyBzYXZlKHRzLCBmaWxlID0gZikKIyBjbG9zZShmKQpsb2FkKGZpbGUucGF0aChQQVRILCAncmVzdWx0cycsICdSU04xMC10cy5SRGF0YScpKQpgYGAKCiMjIyBWYXJpYW5jZSBvZiBub2RlcwpXZSBjYWxjdWxhdGUgdGhlIFNEIGFjcm9zcyB0aW1lIGZvciB0aGUgc3ViamVjdCdzIG5vZGUuCmBgYHtyfQojIHRzIDEyMDAgeCAxMCB4IDQgeCA1MDAKcjE9YXBwbHkodHNbLCwxLF0sIGMoMywyKSwgc2QpCnIyPWFwcGx5KHRzWywsMixdLCBjKDMsMiksIHNkKQpyMz1hcHBseSh0c1ssLDMsXSwgYygzLDIpLCBzZCkKcjQ9YXBwbHkodHNbLCw0LF0sIGMoMywyKSwgc2QpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTZ9CnAxID0gZ2dwbG90KG1lbHQocjEpLCBhZXMoeD1hcy5mYWN0b3IoVmFyMiksIHk9dmFsdWUpKSArCiAgZ2VvbV9wb2ludChzaGFwZT0xLCBjb2xvcj0iZ3JheTUwIiwgc2l6ZT0yKSArCiAgZ2VvbV9ib3hwbG90KHdpZHRoPTAuMykgKwogIGdndGl0bGUoc3ByaW50ZigiUnVuIDEiLCBOKSkgKyB5bGFiKCJTRCIpICsgeGxhYigiUlNOcyIpCgpwMiA9IGdncGxvdChtZWx0KHIyKSwgYWVzKHg9YXMuZmFjdG9yKFZhcjIpLCB5PXZhbHVlKSkgKwogIGdlb21fcG9pbnQoc2hhcGU9MSwgY29sb3I9ImdyYXk1MCIsIHNpemU9MikgKwogIGdlb21fYm94cGxvdCh3aWR0aD0wLjMpICsKICBnZ3RpdGxlKHNwcmludGYoIlJ1biAyIiwgTikpICsgeWxhYigiU0QiKSArIHhsYWIoIlJTTnMiKQoKcDMgPSBnZ3Bsb3QobWVsdChyMyksIGFlcyh4PWFzLmZhY3RvcihWYXIyKSwgeT12YWx1ZSkpICsKICBnZW9tX3BvaW50KHNoYXBlPTEsIGNvbG9yPSJncmF5NTAiLCBzaXplPTIpICsKICBnZW9tX2JveHBsb3Qod2lkdGg9MC4zKSArCiAgZ2d0aXRsZShzcHJpbnRmKCJSdW4gMyIsIE4pKSArIHlsYWIoIlNEIikgKyB4bGFiKCJSU05zIikKCnA0ID0gZ2dwbG90KG1lbHQocjQpLCBhZXMoeD1hcy5mYWN0b3IoVmFyMiksIHk9dmFsdWUpKSArCiAgZ2VvbV9wb2ludChzaGFwZT0xLCBjb2xvcj0iZ3JheTUwIiwgc2l6ZT0yKSArCiAgZ2VvbV9ib3hwbG90KHdpZHRoPTAuMykgKwogIGdndGl0bGUoc3ByaW50ZigiUnVuIDQiLCBOKSkgKyB5bGFiKCJTRCIpICsgeGxhYigiUlNOcyIpCgpwbG90X2dyaWQocDEsIHAyLCBwMywgcDQsIG5jb2wgPSAyLCBucm93ID0gMikKZ2dzYXZlKHBhdGggPSBQQVRIX0ZJRywgIlNkXzEwUlNOcy5wbmciKQpgYGAKCiMjIENvcnJlbGF0aW9uIFBsb3RzCmBgYHtyLCBmaWcuaGVpZ2h0PTQuNywgZmlnLndpZHRoPTYuNSwgbWVzc2FnZT1GQUxTRX0KTElNPWMoLTAuNjUsMC42NSkKCnAxID0gZ3Bsb3RNYXQocm1kaWFnKGNvclRzKHRzWywsMSxdKSksIHRpdGxlPXNwcmludGYoIlJ1biAxIiwgTiksIGxpbT1MSU0sIG5vZGVMYWJlbHMgPSBsYWJlbHMkTGFiZWwsCiAgICAgICAgICAgICAgYXhpc1RleHRTaXplID0gOCwgeEFuZ2xlID0gOTAsIGNvbE1hcExhYmVsPWV4cHJlc3Npb24oIlBlYXJzb25cJ3Mifml0YWxpYyhyKSksCiAgICAgICAgICAgICAgZ3JhZGllbnQgPSBjKCJibHVlIiwgIndoaXRlIiwgInJlZCIpKSArCiAgeGxhYigiTm9kZSIpICsgeWxhYigiTm9kZSIpICsgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IDAuNTo5LjUsIGxhYmVscyA9IGxhYmVscyRMYWJlbCApCgpwMiA9IGdwbG90TWF0KHJtZGlhZyhjb3JUcyh0c1ssLDIsXSkpLCB0aXRsZT1zcHJpbnRmKCJSdW4gMiIsIE4pLCBsaW09TElNLCBub2RlTGFiZWxzID0gbGFiZWxzJExhYmVsLAogICAgICAgICAgICAgIGF4aXNUZXh0U2l6ZSA9IDgsIHhBbmdsZSA9IDkwLCBjb2xNYXBMYWJlbD1leHByZXNzaW9uKCJQZWFyc29uXCdzIn5pdGFsaWMocikpLAogICAgICAgICAgICAgIGdyYWRpZW50ID0gYygiYmx1ZSIsICJ3aGl0ZSIsICJyZWQiKSkgKwogIHhsYWIoIk5vZGUiKSArIHlsYWIoIk5vZGUiKSArIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSAwLjU6OS41LCBsYWJlbHMgPSBsYWJlbHMkTGFiZWwgKQoKcDMgPSBncGxvdE1hdChybWRpYWcoY29yVHModHNbLCwzLF0pKSwgdGl0bGU9c3ByaW50ZigiUnVuIDMiLCBOKSwgbGltPUxJTSwgbm9kZUxhYmVscyA9IGxhYmVscyRMYWJlbCwKICAgICAgICAgICAgICBheGlzVGV4dFNpemUgPSA4LCB4QW5nbGUgPSA5MCwgY29sTWFwTGFiZWw9ZXhwcmVzc2lvbigiUGVhcnNvblwncyJ+aXRhbGljKHIpKSwKICAgICAgICAgICAgICBncmFkaWVudCA9IGMoImJsdWUiLCAid2hpdGUiLCAicmVkIikpICsKICB4bGFiKCJOb2RlIikgKyB5bGFiKCJOb2RlIikgKyBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gMC41OjkuNSwgbGFiZWxzID0gbGFiZWxzJExhYmVsICkKCnA0ID0gZ3Bsb3RNYXQocm1kaWFnKGNvclRzKHRzWywsNCxdKSksIHRpdGxlPXNwcmludGYoIlJ1biA0IiwgTiksIGxpbT1MSU0sIG5vZGVMYWJlbHMgPSBsYWJlbHMkTGFiZWwsCiAgICAgICAgICAgICAgYXhpc1RleHRTaXplID0gOCwgeEFuZ2xlID0gOTAsIGNvbE1hcExhYmVsPWV4cHJlc3Npb24oIlBlYXJzb25cJ3Mifml0YWxpYyhyKSksCiAgICAgICAgICAgICAgZ3JhZGllbnQgPSBjKCJibHVlIiwgIndoaXRlIiwgInJlZCIpKSArCiAgeGxhYigiTm9kZSIpICsgeWxhYigiTm9kZSIpICsgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IDAuNTo5LjUsIGxhYmVscyA9IGxhYmVscyRMYWJlbCApCgpwbG90X2dyaWQocDEsIHAyLCBwMywgcDQsIG5jb2wgPSAyLCBucm93ID0gMiwgcmVsX3dpZHRocyA9IGMoMSwgMSkpCmdnc2F2ZShwYXRoID0gUEFUSF9GSUcsICJSXzEwUlNOcy5wbmciKQpgYGAKCiMjIFBsb3QgZXhhbXBsZSB0aW1lc2VyaWVzCmBgYHtyLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMH0KaWR4ID0gMTpyb3VuZCgxMjAvVFIpICMgZmlyc3QgMiBtaW51dGVzCgojIHJhbmRvbSBzYW1wbGluZyBvZiBzdWJqZWN0IHMgYW5kIG5vZGVzIG4Kbm9kZXMgPSA1ICMgbm8uIG9mIG5vZGVzIHRvIHBsb3QKCmQgPSB0c1tpZHgsc2FtcGxlKE5uLG5vZGVzKSwsc2FtcGxlKE4sMSldCgpwMSA9IGdncGxvdChtZWx0KGRbLDEsXSksIGFlcyh4ID0gVmFyMSwgeSA9IHZhbHVlLCBncm91cD1WYXIyLCBjb2xvcj1hcy5mYWN0b3IoVmFyMikpKSArIAogIGdlb21fbGluZSgpICsgdGhlbWVfbWluaW1hbCgpICsgZ2d0aXRsZSgiUnVuIDEiKQoKcDIgPSBnZ3Bsb3QobWVsdChkWywyLF0pLCBhZXMoeCA9IFZhcjEsIHkgPSB2YWx1ZSwgZ3JvdXA9VmFyMiwgY29sb3I9YXMuZmFjdG9yKFZhcjIpKSkgKwogIGdlb21fbGluZSgpICsgdGhlbWVfbWluaW1hbCgpICsgZ2d0aXRsZSgiUnVuIDIiKQoKcDMgPSBnZ3Bsb3QobWVsdChkWywzLF0pLCBhZXMoeCA9IFZhcjEsIHkgPSB2YWx1ZSwgZ3JvdXA9VmFyMiwgY29sb3I9YXMuZmFjdG9yKFZhcjIpKSkgKwogIGdlb21fbGluZSgpICsgdGhlbWVfbWluaW1hbCgpICsgZ2d0aXRsZSgiUnVuIDMiKQoKcDQgPSBnZ3Bsb3QobWVsdChkWyw0LF0pLCBhZXMoeCA9IFZhcjEsIHkgPSB2YWx1ZSwgZ3JvdXA9VmFyMiwgY29sb3I9YXMuZmFjdG9yKFZhcjIpKSkgKyAKICBnZW9tX2xpbmUoKSArIHRoZW1lX21pbmltYWwoKSArIGdndGl0bGUoIlJ1biA0IikKCnBsb3RfZ3JpZChwMSwgcDIsIHAzLCBwNCwgbmNvbCA9IDEsIG5yb3cgPSA0LCByZWxfd2lkdGhzID0gYygxLCAxKSkKYGBgCgojIyBOZXR3b3JrIGNvbnNpc3RlbmN5IGFjcm9zcyBzdWJqZWN0cwpgYGB7cn0Kc3RhdHMucjEgPSBiaW5vbS5uZXR0ZXN0KGRnbS5uZXQxMC5yMSRhbSwgYWx0ZXIgPSAiZ3JlYXRlciIpCnN0YXRzLnIyID0gYmlub20ubmV0dGVzdChkZ20ubmV0MTAucjIkYW0sIGFsdGVyID0gImdyZWF0ZXIiKQpzdGF0cy5yMyA9IGJpbm9tLm5ldHRlc3QoZGdtLm5ldDEwLnIzJGFtLCBhbHRlciA9ICJncmVhdGVyIikKc3RhdHMucjQgPSBiaW5vbS5uZXR0ZXN0KGRnbS5uZXQxMC5yNCRhbSwgYWx0ZXIgPSAiZ3JlYXRlciIpCmBgYAoKIyMjIERpZmZlcmVuY2UgYmV0d2VlbiBlPTAgYW5kIGU9MjAKYGBge3J9CnggPSBjKHN1bShkZ20ubmV0MTAucjEkdGFtICE9IGRnbS5uZXQxMC5yMSRhbSksCiAgICAgIHN1bShkZ20ubmV0MTAucjIkdGFtICE9IGRnbS5uZXQxMC5yMiRhbSksCiAgICAgIHN1bShkZ20ubmV0MTAucjMkdGFtICE9IGRnbS5uZXQxMC5yMyRhbSksCiAgICAgIHN1bShkZ20ubmV0MTAucjQkdGFtICE9IGRnbS5uZXQxMC5yNCRhbSkKKQpwcmludCh4KQpwcmludCh4LyhOKk5uKihObi0xKSkpCgpgYGAKCgojIyBGaWd1cmUgOApgYGB7ciwgZmlnLndpZHRoPTQuNSwgZmlnLmhlaWdodD03LjgsIG1lc3NhZ2U9RkFMU0V9Cm15bGltID0gYygwLjEsIDAuNjgpCnBvcyA9IDAuNTo5LjUKcyA9IDAuMgpwMSA9IGdwbG90TWF0KHN0YXRzLnIxJGFkaiwgdGl0bGUgPSAicnVuIDEiLCB0aXRsZVRleHRTaXplID0gMTIsIG5vZGVMYWJlbHM9bGFiZWxzJExhYmVsLAogICAgICAgICAgICAgIGF4aXNUZXh0U2l6ZT04LCB4QW5nbGU9OTAsIGxpbSA9IG15bGltLCBiYXJXaWR0aCA9IDAuMiwgdGV4dFNpemUgPSAxMSkgKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBwb3MsIGxhYmVscyA9IGxhYmVscyRMYWJlbCkgKwogIHRoZW1lKHBsb3QubWFyZ2luID0gdW5pdChjKHMsIDAsIDAsIDApLCAiY20iKSkKCnAyID0gZ3Bsb3RNYXQocm1uYShzdGF0cy5yMSRhZGpfZmRyKSwgdGl0bGUgPSAiYmlub21pYWwgdGVzdCIsIHRpdGxlVGV4dFNpemUgPSAxMiwgbm9kZUxhYmVscz1sYWJlbHMkTGFiZWwsCiAgICAgICAgICAgICAgYXhpc1RleHRTaXplPTgsIHhBbmdsZT05MCwgbGltID0gbXlsaW0sIGJhcldpZHRoID0gMC4yLCB0ZXh0U2l6ZSA9IDExKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHBvcywgbGFiZWxzID0gbGFiZWxzJExhYmVsKSArCiAgdGhlbWUocGxvdC5tYXJnaW4gPSB1bml0KGMocywgMCwgMCwgMCksICJjbSIpKQoKcDMgPSBncGxvdE1hdChzdGF0cy5yMiRhZGosIHRpdGxlID0gInJ1biAyIiwgdGl0bGVUZXh0U2l6ZSA9IDEyLCBub2RlTGFiZWxzPWxhYmVscyRMYWJlbCwKICAgICAgICAgICAgICBheGlzVGV4dFNpemU9OCwgeEFuZ2xlPTkwLCBsaW0gPSBteWxpbSwgYmFyV2lkdGggPSAwLjIsIHRleHRTaXplID0gMTEpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gcG9zLCBsYWJlbHMgPSBsYWJlbHMkTGFiZWwpICsKICB0aGVtZShwbG90Lm1hcmdpbiA9IHVuaXQoYyhzLCAwLCAwLCAwKSwgImNtIikpCgpwNCA9IGdwbG90TWF0KHJtbmEoc3RhdHMucjIkYWRqX2ZkciksIHRpdGxlID0gImJpbm9taWFsIHRlc3QiLCB0aXRsZVRleHRTaXplID0gMTIsIG5vZGVMYWJlbHM9bGFiZWxzJExhYmVsLAogICAgICAgICAgICAgIGF4aXNUZXh0U2l6ZT04LCB4QW5nbGU9OTAsIGxpbSA9IG15bGltLCBiYXJXaWR0aCA9IDAuMiwgdGV4dFNpemUgPSAxMSkgKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBwb3MsIGxhYmVscyA9IGxhYmVscyRMYWJlbCkgKwogIHRoZW1lKHBsb3QubWFyZ2luID0gdW5pdChjKHMsIDAsIDAsIDApLCAiY20iKSkKCnA1ID0gZ3Bsb3RNYXQoc3RhdHMucjMkYWRqLCB0aXRsZSA9ICJydW4gMyIsIHRpdGxlVGV4dFNpemUgPSAxMiwgbm9kZUxhYmVscz1sYWJlbHMkTGFiZWwsCiAgICAgICAgICAgICAgYXhpc1RleHRTaXplPTgsIHhBbmdsZT05MCwgbGltID0gbXlsaW0sIGJhcldpZHRoID0gMC4yLCB0ZXh0U2l6ZSA9IDExKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHBvcywgbGFiZWxzID0gbGFiZWxzJExhYmVsKSArCiAgdGhlbWUocGxvdC5tYXJnaW4gPSB1bml0KGMocywgMCwgMCwgMCksICJjbSIpKQoKcDYgPSBncGxvdE1hdChybW5hKHN0YXRzLnIzJGFkal9mZHIpLCB0aXRsZSA9ICJiaW5vbWlhbCB0ZXN0IiwgdGl0bGVUZXh0U2l6ZSA9IDEyLCBub2RlTGFiZWxzPWxhYmVscyRMYWJlbCwKICAgICAgICAgICAgICBheGlzVGV4dFNpemU9OCwgeEFuZ2xlPTkwLCBsaW0gPSBteWxpbSwgYmFyV2lkdGggPSAwLjIsIHRleHRTaXplID0gMTEpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gcG9zLCBsYWJlbHMgPSBsYWJlbHMkTGFiZWwpICsKICB0aGVtZShwbG90Lm1hcmdpbiA9IHVuaXQoYyhzLCAwLCAwLCAwKSwgImNtIikpCgpwNyA9IGdwbG90TWF0KHN0YXRzLnI0JGFkaiwgdGl0bGUgPSAicnVuIDQiLCB0aXRsZVRleHRTaXplID0gMTIsIG5vZGVMYWJlbHM9bGFiZWxzJExhYmVsLAogICAgICAgICAgICAgIGF4aXNUZXh0U2l6ZT04LCB4QW5nbGU9OTAsIGxpbSA9IG15bGltLCBiYXJXaWR0aCA9IDAuMiwgdGV4dFNpemUgPSAxMSkgKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBwb3MsIGxhYmVscyA9IGxhYmVscyRMYWJlbCkgKwogIHRoZW1lKHBsb3QubWFyZ2luID0gdW5pdChjKHMsIDAsIDAsIDApLCAiY20iKSkKCnA4ID0gZ3Bsb3RNYXQocm1uYShzdGF0cy5yNCRhZGpfZmRyKSwgdGl0bGUgPSAiYmlub21pYWwgdGVzdCIsIHRpdGxlVGV4dFNpemUgPSAxMiwgbm9kZUxhYmVscz1sYWJlbHMkTGFiZWwsCiAgICAgICAgICAgICAgYXhpc1RleHRTaXplPTgsIHhBbmdsZT05MCwgbGltID0gbXlsaW0sIGJhcldpZHRoID0gMC4yLCB0ZXh0U2l6ZSA9IDExKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHBvcywgbGFiZWxzID0gbGFiZWxzJExhYmVsKSArCiAgdGhlbWUocGxvdC5tYXJnaW4gPSB1bml0KGMocywgMCwgMCwgMCksICJjbSIpKQoKcGxvdF9ncmlkKHAxLCBwMiwgcDMsIHA0LCBwNSwgcDYsIHA3LCBwOCwgbmNvbCA9IDIsIG5yb3cgPSA0LCByZWxfaGVpZ2h0cyA9IGMoMSwxLDEsMSkpCmdnc2F2ZShwYXRoID0gUEFUSF9GSUcsICJGaWc4LnBuZyIpCmBgYAoKIyMgTmV0d29ya3MgY29uc2lzdGVuY3kgYWNyb3NzIHJ1bnMKYGBge3J9CiMgZWRnZSByZXByb2R1Y2VkIGluIDMgcnVucyBvciBtb3JlCm0zID0gZGdtLm5ldDEwLnIxJGFtICsgZGdtLm5ldDEwLnIyJGFtICsgZGdtLm5ldDEwLnIzJGFtICsgZGdtLm5ldDEwLnI0JGFtID4gMgojIGVkZ2UgcmVwcm9kdWNlZCBpbiBhbGwgcnVucwptNCA9IGRnbS5uZXQxMC5yMSRhbSAqIGRnbS5uZXQxMC5yMiRhbSAqIGRnbS5uZXQxMC5yMyRhbSAqIGRnbS5uZXQxMC5yNCRhbQojIGNvbnNpc3RlbnRseSBubyBlZGdlIGluIGFsbCBydW5zCm1uID0gKDEtZGdtLm5ldDEwLnIxJGFtKSAqICgxLWRnbS5uZXQxMC5yMiRhbSkgKiAoMS1kZ20ubmV0MTAucjMkYW0pICogKDEtZGdtLm5ldDEwLnI0JGFtKQoKc3RhdHMubTMgPSBiaW5vbS5uZXR0ZXN0KG0zLCBhbHRlciA9ICJncmVhdGVyIikKc3RhdHMubTQgPSBiaW5vbS5uZXR0ZXN0KG00LCBhbHRlciA9ICJncmVhdGVyIikKc3RhdHMubW4gPSBiaW5vbS5uZXR0ZXN0KG1uLCBhbHRlciA9ICJncmVhdGVyIikKYGBgCgojIyBGaWd1cmUgOQpgYGB7ciwgZmlnLmhlaWdodD02LjIsIGZpZy53aWR0aD00LjUsIG1lc3NhZ2U9RkFMU0V9CgpwMSA9IGdwbG90TWF0KHN0YXRzLm0zJGFkaiwgdGl0bGUgPSAiZWRnZSBpbiAzLzQgcnVucyIsIG5vZGVMYWJlbHM9bGFiZWxzJExhYmVsLAogICAgICAgICAgICAgIGF4aXNUZXh0U2l6ZT04LCB4QW5nbGU9OTAsIGxpbSA9IGMoMC4xLCAwLjYyKSwgYmFyV2lkdGggPSAwLjIsIHRleHRTaXplID0gMTEpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gcG9zLCBsYWJlbHMgPSBsYWJlbHMkTGFiZWwpICsKICB0aGVtZShwbG90Lm1hcmdpbiA9IHVuaXQoYyhzLCAwLCAwLCAwKSwgImNtIikpCgpwMiA9IGdwbG90TWF0KHJtbmEoc3RhdHMubTMkYWRqX2ZkciksIHRpdGxlID0gImJpbm9taWFsIHRlc3QiLCBub2RlTGFiZWxzPWxhYmVscyRMYWJlbCwKICAgICAgICAgICAgICBheGlzVGV4dFNpemU9OCwgeEFuZ2xlPTkwLCBsaW0gPSBjKDAuMSwgMC42MiksIGJhcldpZHRoID0gMC4yLCB0ZXh0U2l6ZSA9IDExKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHBvcywgbGFiZWxzID0gbGFiZWxzJExhYmVsKSArCiAgdGhlbWUocGxvdC5tYXJnaW4gPSB1bml0KGMocywgMCwgMCwgMCksICJjbSIpKQoKcDMgPSBncGxvdE1hdChzdGF0cy5tNCRhZGosIHRpdGxlID0gImVkZ2UgaW4gNC80IHJ1bnMiLCBub2RlTGFiZWxzPWxhYmVscyRMYWJlbCwKICAgICAgICAgICAgICBheGlzVGV4dFNpemU9OCwgeEFuZ2xlPTkwLCBsaW0gPSBjKDAuMSwgMC42MiksIGJhcldpZHRoID0gMC4yLCB0ZXh0U2l6ZSA9IDExKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHBvcywgbGFiZWxzID0gbGFiZWxzJExhYmVsKSArCiAgdGhlbWUocGxvdC5tYXJnaW4gPSB1bml0KGMocywgMCwgMCwgMCksICJjbSIpKQoKcDQgPSBncGxvdE1hdChybW5hKHN0YXRzLm00JGFkal9mZHIpLCB0aXRsZSA9ICJiaW5vbWlhbCB0ZXN0Iiwgbm9kZUxhYmVscz1sYWJlbHMkTGFiZWwsIAogICAgICAgICAgICAgIGF4aXNUZXh0U2l6ZT04LCB4QW5nbGU9OTAsIGxpbSA9IGMoMC4xLDAuNjIpLCBiYXJXaWR0aCA9IDAuMiwgdGV4dFNpemUgPSAxMSkgKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBwb3MsIGxhYmVscyA9IGxhYmVscyRMYWJlbCkgKwogIHRoZW1lKHBsb3QubWFyZ2luID0gdW5pdChjKHMsIDAsIDAsIDApLCAiY20iKSkKCnA1ID0gZ3Bsb3RNYXQocm1kaWFnKHN0YXRzLm1uJGFkaiksIHRpdGxlID0gIm5vIGVkZ2UgaW4gNC80IHJ1bnMiLCBub2RlTGFiZWxzPWxhYmVscyRMYWJlbCwKICAgICAgICAgICAgICBncmFkaWVudCA9IGMoIndoaXRlIiwgInZpb2xldCIsICJibHVlIiksIGF4aXNUZXh0U2l6ZT04LCB4QW5nbGU9OTAsIAogICAgICAgICAgICAgIGJhcldpZHRoID0gMC4yLCB0ZXh0U2l6ZSA9IDExKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHBvcywgbGFiZWxzID0gbGFiZWxzJExhYmVsKSArCiAgdGhlbWUocGxvdC5tYXJnaW4gPSB1bml0KGMocywgMCwgMCwgMCksICJjbSIpKQoKcDYgPSBncGxvdE1hdChybWRpYWcocm1uYShzdGF0cy5tbiRhZGpfZmRyKSksIHRpdGxlID0gImJpbm9taWFsIHRlc3QiLCBub2RlTGFiZWxzPWxhYmVscyRMYWJlbCwKICAgICAgICAgICAgICBncmFkaWVudCA9IGMoIndoaXRlIiwgInZpb2xldCIsICJibHVlIiksIGF4aXNUZXh0U2l6ZT04LCB4QW5nbGU9OTAsCiAgICAgICAgICAgICAgYmFyV2lkdGggPSAwLjIsIHRleHRTaXplID0gMTEpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gcG9zLCBsYWJlbHMgPSBsYWJlbHMkTGFiZWwpICsKICB0aGVtZShwbG90Lm1hcmdpbiA9IHVuaXQoYyhzLCAwLCAwLCAwKSwgImNtIikpCgpwbG90X2dyaWQocDEsIHAyLCBwMywgcDQsIHA1LCBwNiwgbGFiZWxzPWMoIkEiLCAiIiwgIiIsICIiLCAiQiIsICIiKSwKICAgICAgICAgIG5jb2wgPSAyLCBucm93ID0gMywgcmVsX2hlaWdodHMgPSBjKDEsMSwxKSkKCmdnc2F2ZShwYXRoID0gUEFUSF9GSUcsICJGaWc5LnBuZyIpCmBgYAoKIyMgRmlndXJlIGNvbm5lY3Rpdml0eSBzdHJlbmd0aApgYGB7ciBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD01fQojIGZpbmQgcmVwcmVzZW50YXRpdmUgc3ViamVjdCBzaG93aW5nIGdyb3VwIGVmZmVjdCBbRE1OIFZpc01lZCBhbmQgQXVkXS0+Q2VyZWIKIyBzPXNhbXBsZShOLDEpICMgc3ViamVjdApzPTM1CgppZHg9YXJyYXkoRkFMU0UsIGRpbT1jKE5uLCBObikpCmlkeFsyLDhdID0gaWR4WzMsOF0gPSBpZHhbOSw4XSA9IFRSVUUKI3N0YXRzLnIxJGFkal9mZHJbaWR4XQphPWRnbS5uZXQxMC5yMSRhbVssLHNdCmFbaWR4XQoKcj0xICMgcnVuCm5vZGU9OAoKIyBnZXQgbW9kZWwgc3BhY2UKc3ViID0gcmVhZC5zdWJqZWN0KFBBVEhfTkVULCBzcHJpbnRmKCIlc19SdW5fJTAzZCIsIFNVQkpFQ1RTW3NdLCByKSwgTm4pCmRmID0gc3ViJHdpbm5lclsxMixub2RlXQpwYXJzID0gc3ViJHdpbm5lclsyOk5uLG5vZGVdCnBhcnMgPSBwYXJzW3BhcnMgIT0gMF0KbXlwYXJzPWMoMiw5KQppZHhwYXI9bWF0Y2gobXlwYXJzLHBhcnMpCgpOdD1ucm93KHRzKQoKRnQ9YXJyYXkoMSxkaW09YyhOdCxsZW5ndGgocGFycykrMSkpCkZ0WywyOm5jb2woRnQpXT10c1sscGFycyxyLHNdICMgc2VsZWN0cyBwYXJlbnRzCll0PXRzWyxub2RlLHIsc10KCiMgZ2V0IGRmIGNvcnJlc3BvbmRpbmcgdG8gcGFyZW50IG1vZGVsIHBhcnMKI2RmID0gZ2V0TW9kZWwoc3ViJG1vZGVsc1tbMV1dLCBwYXJzKVtObisyXQoKZml0PWRsbS5scGwoWXQsIHQoRnQpLCBkZWx0YSA9IGRmKQp5ID0gZGxtLnJldHJvKGZpdCRtdCwgZml0JENTdCwgZml0JFJTdCwgZml0JG50LCBmaXQkZHQpCgp0aGV0YT10KHkkc210WzI6KGxlbmd0aChwYXJzKSsxKSxdKQoKc2NhbGVGVU4gPC0gZnVuY3Rpb24oeCkgc3ByaW50ZigiJS4xZiIsIHgpCnN0YXJ0PTEKc2Vjb25kcz01MDAgIyBtYXggaXMgODY0CmlkeD1yb3VuZChzdGFydC9UUik6cm91bmQoKHN0YXJ0K3NlY29uZHMpL1RSKQpOdF89bGVuZ3RoKGlkeCkKCmQ9bWVsdChZdFtpZHhdKQpkJHRpbWU9MTpOdF8KZCRsYWJlbHM9IkNlciAgIgpwMSA9IGdncGxvdChkLCBhZXMoeCA9IHRpbWUqVFIsIHkgPSB2YWx1ZSwgY29sb3I9bGFiZWxzKSkgKyBnZW9tX2xpbmUoKSArCiAgdGhlbWVfbWluaW1hbCgpICsgZ2d0aXRsZSgiTm9kZSB0aW1lIHNlcmllcyAoY2hpbGQpIikgKwogIHNjYWxlX2NvbG9yX2Rpc2NyZXRlKG5hbWUgPSAibGFiZWxzIikgKyB4bGFiKCJzZWNvbmRzIikgKyB5bGFiKCJCT0xEIikgKyAjeGxpbShjKDAsc2Vjb25kcykpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPXNjYWxlRlVOKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT0xMCksIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemU9MTApLAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplPTEwKSwgbGVnZW5kLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MTApLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xMCxmYWNlPSJib2xkIikpCiNwMSA9IHAxICsgc2NhbGVfY29sb3VyX2JyZXdlcihwYWxldHRlPSJEYXJrMiIpCgojZD1tZWx0KEZ0W2lkeCwyOihsZW5ndGgocGFycykrMSldKQpkPW1lbHQoRnRbaWR4LGlkeHBhcisxXSkKZCR0aW1lPTE6TnRfCmQkbGFiZWxzPWMocmVwKCJETU4iLCBOdF8pLHJlcCgiQXUiLCBOdF8pKQpwMiA9IGdncGxvdChkLCBhZXMoeCA9IHRpbWUqVFIsIHkgPSB2YWx1ZSwgZ3JvdXA9VmFyMiwgY29sb3I9bGFiZWxzKSkgKyBnZW9tX2xpbmUoKSArCiAgdGhlbWVfbWluaW1hbCgpICsgZ2d0aXRsZSgiTm9kZSB0aW1lIHNlcmllcyAocGFyZW50cykiKSArCiAgc2NhbGVfY29sb3JfZGlzY3JldGUobmFtZSA9ICJsYWJlbHMiKSArIHhsYWIoInNlY29uZHMiKSArIHlsYWIoIkJPTEQiKSArICN4bGltKGMoMCxzZWNvbmRzKSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHM9c2NhbGVGVU4pICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTEwKSwgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZT0xMCksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemU9MTApLCBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xMCksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTEwLGZhY2U9ImJvbGQiKSkKCmQ9bWVsdCh0aGV0YVtpZHgsaWR4cGFyXSkKZCR0aW1lPTE6TnRfCmQkbGFiZWxzPWMocmVwKCJETU4iLCBOdF8pLHJlcCgiQXUiLCBOdF8pKQpwMyA9IGdncGxvdChkLCBhZXMoeCA9IHRpbWUqVFIsIHkgPSB2YWx1ZSwgZ3JvdXA9VmFyMiwgY29sb3I9bGFiZWxzKSkgKyBnZW9tX2xpbmUoKSArCiAgdGhlbWVfbWluaW1hbCgpICsgZ2d0aXRsZSgiSW5mbHVlbmNlIG9mIHBhcmVudHMgb24gdGhlIGNoaWxkIG5vZGUiKSArCiAgI3NjYWxlX2NvbG9yX2Rpc2NyZXRlKG5hbWUgPSBleHByZXNzaW9uKHBhc3RlKGl0YWxpYyh0aGV0YV4icj0xIiksICIiW2l0YWxpYygidCIpXSkpKSArCiAgc2NhbGVfY29sb3JfZGlzY3JldGUobmFtZSA9ICJsYWJlbHMiKSArCiAgeGxhYigic2Vjb25kcyIpICsgeWxhYihleHByZXNzaW9uKHRoZXRhKSkgKyAjeGxpbShjKDAsc2Vjb25kcykpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTEwKSwgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZT0xMCksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemU9MTApLCBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xMCksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTEwLGZhY2U9ImJvbGQiKSkKCgpwbG90X2dyaWQocDEsIHAyLCBwMywgbmNvbCA9IDEsIG5yb3cgPSAzLCByZWxfd2lkdGhzID0gYygxLDEsMSksIGxhYmVscyA9IGMoIkEiLCAiQiIsICJDIikpCgpnZ3NhdmUocGF0aCA9IFBBVEhfRklHLCAiVGhldGFfUlNOLnBuZyIpCmBgYAo=