Install required packages

# install.packages("devtools")
# install.packages("testit")
# install.packages("ggplot2")
# install.packages("cowplot")
# install.packages("reshape2")

Load libraries

library(DGM)
library(testit)
library(ggplot2)
library(cowplot)
library(reshape2)

Main variables

N=16 # Number of simulated subjects/datasets
Nn=14 # Number of nodes, does not apply to all datasets
Nn1=8
Nn2=6
N_t= 2000 # Volumes/no. of timepoints
PATH_HOME = "/home/simon"
PATH = file.path(PATH_HOME, 'Data', 'DGM-Sim')
PATH_DATA = file.path(PATH_HOME, "Drive", "Mouse")

Loading network data

# subj=list()
# for (s in 1:N) {
#   subj[[s]] = read.subject(file.path(PATH_DATA, 'Mouse_14ROIs_CP_results'), sprintf("Mouse_%03d",s), 14)
# }
# dgm.mouse14=dgm.group(subj)
# 
# subj=list()
# for (s in 1:8) {
#   subj[[s]] = read.subject(file.path(PATH_DATA, 'Mouse_N816ROIs_results'), sprintf("Mouse_%03d",s), 16)
# }
# dgm.mouse16=dgm.group(subj)
# 
# subj=list()
# for (s in 1:N) {
#   subj[[s]] = read.subject(file.path(PATH_DATA, 'Net1_WT_results'), sprintf("Mouse_%03d",s), 8)
# }
# dgm.net1wt=dgm.group(subj)
# 
# subj=list()
# for (s in 1:N) {
#   subj[[s]] = read.subject(file.path(PATH_DATA, 'Net2_WT_results'), sprintf("Mouse_%03d",s), 6)
# }
# dgm.net2wt=dgm.group(subj)
# 
# f=file(file.path(PATH,"results", "DGM-Mouse.RData"))
# save(dgm.mouse14, dgm.mouse16, dgm.net1wt, dgm.net2wt, file =f, compress = T)
# close(f)
# takes quite long to load above data
load(file.path(PATH, "results", "DGM-Mouse.RData"))

Plot: discount factor delta distribution per node

node=as.factor(sort(rep(1:14,N)))
d1=data.frame(df=c(dgm.mouse14$df_), node=node)
node=as.factor(sort(rep(1:16,8)))
d2=data.frame(df=c(dgm.mouse16$df_), node=node)
node=as.factor(sort(rep(1:8,N)))
d3=data.frame(df=c(dgm.net1wt$df_),  node=node)
node=as.factor(sort(rep(1:6,16)))
d4=data.frame(df=c(dgm.net2wt$df_),  node=node)
p1 = ggplot(d1, aes(x=node, y=df)) + geom_boxplot(width=0.4, color="blue1") +
  geom_point(shape=1, color="gray50", size=1, position = position_jitter(width = 0.2, height = 0.0003)) + ggtitle("Mouse 14 ROIs (N=16)")
p2 = ggplot(d2, aes(x=node, y=df)) + geom_boxplot(width=0.4, color="blue1") +
  geom_point(shape=1, color="gray50", size=1, position = position_jitter(width = 0.2, height = 0.0003)) + ggtitle("Mouse 16 ROIs (N=8)")
p3 = ggplot(d3, aes(x=node, y=df)) + geom_boxplot(width=0.4, color="blue1") +
  geom_point(shape=1, color="gray50", size=1, position = position_jitter(width = 0.2, height = 0.0003)) + ggtitle("Net1_WT (N=16)")
p4 = ggplot(d4, aes(x=node, y=df)) + geom_boxplot(width=0.4, color="blue1") +
  geom_point(shape=1, color="gray50", size=1, position = position_jitter(width = 0.2, height = 0.0003)) + ggtitle("Net2_WT (N=16)")
plot_grid(p1, p3, p2, p4, ncol = 2, nrow = 2, rel_widths = c(1, 0.5))

DFs with parents only

df.1 = dgm.net1wt$df_
df.2 = dgm.net2wt$df_
df.1[t(apply(dgm.net1wt$am, 3, colSums)) == 0] = NA
df.2[t(apply(dgm.net2wt$am, 3, colSums)) == 0] = NA
summary(colMeans(df.1, na.rm = T))
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
 0.9900  0.9922  0.9930  0.9926  0.9933  0.9940       2 
summary(colMeans(df.2, na.rm = T))
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
 0.9550  0.9779  0.9914  0.9835  0.9941  0.9947 

Correlation plot

f14 = list.files(file.path(PATH_DATA, "Timeseries_14ROIs_CP"), "*.txt")
f16 = list.files(file.path(PATH_DATA, "WT_fmr1ko_120d_dr_stage1"), "*.txt")
f1  = list.files(file.path(PATH_DATA, "Net1_WT"), "*.txt")
f2  = list.files(file.path(PATH_DATA, "Net2_WT"), "*.txt")
assert(length(f14) == N)
assert(length(f16) == 8)
assert(length(f1)  == N)
assert(length(f2)  == N)
# read data
d14 = array(NA, dim=c(N_t, Nn, N))
d16 = array(NA, dim=c(N_t, 16, 8))
d1  = array(NA, dim=c(N_t, Nn1, N))
d2  = array(NA, dim=c(N_t, Nn2, N))
for (s in 1:N) {
  d14[,,s]= scaleTs(as.matrix(read.table(file.path(PATH_DATA, "Timeseries_14ROIs_CP", f14[s]))))
  if (s <=8) {
    d16[,,s]= scaleTs(as.matrix(read.table(file.path(PATH_DATA, "WT_fmr1ko_120d_dr_stage1", f16[s]))))
  }
  d1[,,s] = scaleTs(as.matrix(read.table(file.path(PATH_DATA, "Net1_WT", f1[s]))))
  d2[,,s] = scaleTs(as.matrix(read.table(file.path(PATH_DATA, "Net2_WT", f2[s]))))
  #d=scaleTs(d)
  assert(nrow(d14) == N_t)
  assert(nrow(d16) == N_t)
  assert(nrow(d1) == N_t)
  assert(nrow(d2) == N_t)
  assert(ncol(d14) == Nn)
  assert(ncol(d16) == 16)
  assert(ncol(d1) == Nn1)
  assert(ncol(d2) == Nn2)
}
p1 = gplotMat(rmdiag(corTs(d14)), title='14 ROIs (N=16)', lim=c(0, 1),
              colMapLabel=expression("Pearson\'s"~italic(r))) + xlab("Node") + ylab("Node")
p2 = gplotMat(rmdiag(corTs(d16)), title='16 ROIs (N=8)', lim=c(-0.4, 0.6),
              colMapLabel=expression("Pearson\'s"~italic(r)), gradient = c("blue", "white", "red")) + xlab("Node") + ylab("Node")
p3 = gplotMat(rmdiag(corTs(d1)), title='Net1_WT (N=16)', lim=c(0, 0.5),
              colMapLabel=expression("Pearson\'s"~italic(r))) + xlab("Node") + ylab("Node")
p4 = gplotMat(rmdiag(corTs(d2)), title='Net2_WT (N=16)', lim=c(0, 0.5),
              colMapLabel=expression("Pearson\'s"~italic(r))) + xlab("Node") + ylab("Node")
plot_grid(p1, p2, p3, p4, ncol = 2, nrow = 2, rel_widths = c(1, 1))

Plot random timeseries

t = 1:200 # interval to plot
# random sampling mice m and nodes n
nodes = 5 # no. of nodes to plot
d = melt(d14[t,sample(14,nodes),sample(N,1)])
p1=ggplot(d, aes(x = Var1, y = value, group=Var2, color=as.factor(Var2))) + geom_line() + theme_minimal() + 
  ggtitle("Mouse 14 ROIs")
d = melt(d16[t,sample(16,nodes),sample(8,1)])
p2=ggplot(d, aes(x = Var1, y = value, group=Var2, color=as.factor(Var2))) + geom_line() + theme_minimal() + ggtitle("Mouse 16 ROIs")
d = melt(d1[t,sample(8,nodes),sample(N,1)])
p3=ggplot(d, aes(x = Var1, y = value, group=Var2, color=as.factor(Var2))) + geom_line() + theme_minimal() + ggtitle("Net1_WT")
d = melt(d2[t,sample(6,nodes),sample(N,1)])
p4=ggplot(d, aes(x = Var1, y = value, group=Var2, color=as.factor(Var2))) + geom_line() + theme_minimal() + ggtitle("Net2_WT")
plot_grid(p1, p2, p3, p4, ncol = 1, nrow = 4, rel_widths = c(1, 1))

Network consistency across mice

stats1 = binom.nettest(dgm.mouse14$am)
stats2 = binom.nettest(dgm.mouse16$am)
p1 = gplotMat(stats1$adj, title = "Mouse 14 ROIs")
p2 = gplotMat(rmna(stats1$adj_fdr), title = "binom test & FDR")
p3 = gplotMat(stats2$adj, title = "Mouse 16 ROIs")
p4 = gplotMat(rmna(stats2$adj_fdr), title = "binom test & FDR")
plot_grid(p1, p2, p3, p4, ncol = 2, nrow = 2, rel_heights = c(1,1), labels = c("A", "", "B") )

Figure 11

stats3 = binom.nettest(dgm.net1wt$am)
stats4 = binom.nettest(dgm.net2wt$am)
pos = 0.5:8.4
mylabels = c("OrbM", "OrbL", "NAcc", "Cing",  "Amyg", "CA1", "DG", "Entorh")
p5 = gplotMat(stats3$adj, title = "amyg-hipp-enthorin", nodeLabels=mylabels, axisTextSize=9,
              xAngle=90, barWidth = 0.2) + 
  scale_x_continuous(breaks = pos, labels = mylabels)
Scale for 'x' is already present. Adding another scale for 'x', which will replace the existing scale.
p6 = gplotMat(rmna(stats3$adj_fdr), title = "binomial test", nodeLabels=mylabels, axisTextSize=9,
              xAngle=90, barWidth = 0.2) +
  scale_x_continuous(breaks = pos, labels = mylabels)
Scale for 'x' is already present. Adding another scale for 'x', which will replace the existing scale.
pos = 0.5:6.4
mylabels = c("SomSensR", "MotorR", "PutamR", "SomSensL", "MotorL", "PutamL")
p7 = gplotMat(stats4$adj, title = "cort-striat-pallid", nodeLabels=mylabels, axisTextSize=9, 
              xAngle=90, barWidth = 0.2) + 
  scale_x_continuous(breaks = pos, labels = mylabels)
Scale for 'x' is already present. Adding another scale for 'x', which will replace the existing scale.
p8 = gplotMat(rmna(stats4$adj_fdr), title = "binomial test", nodeLabels=mylabels, axisTextSize=9, 
              xAngle=90, barWidth = 0.2) +
  scale_x_continuous(breaks = pos, labels = mylabels)
Scale for 'x' is already present. Adding another scale for 'x', which will replace the existing scale.
plot_grid(p5, p6, p7, p8, ncol = 2, nrow = 2,
          rel_heights = c(1,1), labels = c("A", "", "B") )

ggsave(path = file.path(PATH, 'figures'), "Fig11.png")
Saving 5.2 x 4.5 in image

Difference between e=0 and e=20

x= c(sum(dgm.net1wt$am != dgm.net1wt$tam),
     sum(dgm.net2wt$am != dgm.net2wt$tam))
print(x)
[1] NA NA
print(x/c(N*Nn1*(Nn1-1), N*Nn2*(Nn2-1)))
[1] NA NA

Proportions

stats3$adj
       [,1]   [,2]   [,3]   [,4]   [,5] [,6]   [,7] [,8]
[1,] 0.0000 0.3125 0.3125 0.9375 0.3125    0 0.4375    0
[2,] 0.8125 0.0000 0.3125 0.3125 0.2500    0 0.2500    0
[3,] 0.8125 0.3125 0.0000 0.3750 0.3125    0 0.3750    0
[4,] 0.7500 0.0625 0.1250 0.0000 0.0000    0 0.5000    0
[5,] 0.5000 0.1875 0.2500 0.4375 0.0000    0 0.3125    0
[6,] 0.5000 0.1875 0.3125 0.6250 0.0625    0 0.5000    0
[7,] 0.6250 0.1250 0.1250 0.7500 0.1875    0 0.0000    0
[8,] 0.4375 0.1875 0.0625 0.3125 0.3125    0 0.1250    0
max(stats3$adj)
[1] 0.9375
stats4$adj
       [,1]   [,2]   [,3]   [,4]   [,5]   [,6]
[1,] 0.0000 0.3750 0.1875 0.6875 0.5000 0.5000
[2,] 0.1875 0.0000 0.1875 0.4375 0.9375 0.5625
[3,] 0.2500 0.4375 0.0000 0.3125 0.5000 0.8125
[4,] 0.3125 0.3750 0.1875 0.0000 0.7500 0.3125
[5,] 0.2500 0.6875 0.1875 0.4375 0.0000 0.2500
[6,] 0.2500 0.4375 0.5000 0.2500 0.3125 0.0000
max(stats4$adj)
[1] 0.9375
LS0tCnRpdGxlOiAiREdNLU1vdXNlIgphdXRob3I6ICJTaW1vbiBTY2h3YWIiCmRhdGU6ICIyNiBGZWIgMjAxOCIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyMgSW5zdGFsbCByZXF1aXJlZCBwYWNrYWdlcyAKYGBge3J9CiMgaW5zdGFsbC5wYWNrYWdlcygiZGV2dG9vbHMiKQojIGluc3RhbGwucGFja2FnZXMoInRlc3RpdCIpCiMgaW5zdGFsbC5wYWNrYWdlcygiZ2dwbG90MiIpCiMgaW5zdGFsbC5wYWNrYWdlcygiY293cGxvdCIpCiMgaW5zdGFsbC5wYWNrYWdlcygicmVzaGFwZTIiKQpgYGAKCiMjIExvYWQgbGlicmFyaWVzIApgYGB7cn0KbGlicmFyeShER00pCmxpYnJhcnkodGVzdGl0KQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoY293cGxvdCkKbGlicmFyeShyZXNoYXBlMikKYGBgCgojIyBNYWluIHZhcmlhYmxlcyAKYGBge3J9Ck49MTYgIyBOdW1iZXIgb2Ygc2ltdWxhdGVkIHN1YmplY3RzL2RhdGFzZXRzCk5uPTE0ICMgTnVtYmVyIG9mIG5vZGVzLCBkb2VzIG5vdCBhcHBseSB0byBhbGwgZGF0YXNldHMKTm4xPTgKTm4yPTYKTl90PSAyMDAwICMgVm9sdW1lcy9uby4gb2YgdGltZXBvaW50cwpQQVRIX0hPTUUgPSAiL2hvbWUvc2ltb24iClBBVEggPSBmaWxlLnBhdGgoUEFUSF9IT01FLCAnRGF0YScsICdER00tU2ltJykKUEFUSF9EQVRBID0gZmlsZS5wYXRoKFBBVEhfSE9NRSwgIkRyaXZlIiwgIk1vdXNlIikKYGBgCgojIyBMb2FkaW5nIG5ldHdvcmsgZGF0YQpgYGB7cn0KIyBzdWJqPWxpc3QoKQojIGZvciAocyBpbiAxOk4pIHsKIyAgIHN1YmpbW3NdXSA9IHJlYWQuc3ViamVjdChmaWxlLnBhdGgoUEFUSF9EQVRBLCAnTW91c2VfMTRST0lzX0NQX3Jlc3VsdHMnKSwgc3ByaW50ZigiTW91c2VfJTAzZCIscyksIDE0KQojIH0KIyBkZ20ubW91c2UxND1kZ20uZ3JvdXAoc3ViaikKIyAKIyBzdWJqPWxpc3QoKQojIGZvciAocyBpbiAxOjgpIHsKIyAgIHN1YmpbW3NdXSA9IHJlYWQuc3ViamVjdChmaWxlLnBhdGgoUEFUSF9EQVRBLCAnTW91c2VfTjgxNlJPSXNfcmVzdWx0cycpLCBzcHJpbnRmKCJNb3VzZV8lMDNkIixzKSwgMTYpCiMgfQojIGRnbS5tb3VzZTE2PWRnbS5ncm91cChzdWJqKQojIAojIHN1Ymo9bGlzdCgpCiMgZm9yIChzIGluIDE6TikgewojICAgc3Vialtbc11dID0gcmVhZC5zdWJqZWN0KGZpbGUucGF0aChQQVRIX0RBVEEsICdOZXQxX1dUX3Jlc3VsdHMnKSwgc3ByaW50ZigiTW91c2VfJTAzZCIscyksIDgpCiMgfQojIGRnbS5uZXQxd3Q9ZGdtLmdyb3VwKHN1YmopCiMgCiMgc3Viaj1saXN0KCkKIyBmb3IgKHMgaW4gMTpOKSB7CiMgICBzdWJqW1tzXV0gPSByZWFkLnN1YmplY3QoZmlsZS5wYXRoKFBBVEhfREFUQSwgJ05ldDJfV1RfcmVzdWx0cycpLCBzcHJpbnRmKCJNb3VzZV8lMDNkIixzKSwgNikKIyB9CiMgZGdtLm5ldDJ3dD1kZ20uZ3JvdXAoc3ViaikKIyAKIyBmPWZpbGUoZmlsZS5wYXRoKFBBVEgsInJlc3VsdHMiLCAiREdNLU1vdXNlLlJEYXRhIikpCiMgc2F2ZShkZ20ubW91c2UxNCwgZGdtLm1vdXNlMTYsIGRnbS5uZXQxd3QsIGRnbS5uZXQyd3QsIGZpbGUgPWYsIGNvbXByZXNzID0gVCkKIyBjbG9zZShmKQoKIyB0YWtlcyBxdWl0ZSBsb25nIHRvIGxvYWQgYWJvdmUgZGF0YQpsb2FkKGZpbGUucGF0aChQQVRILCAicmVzdWx0cyIsICJER00tTW91c2UuUkRhdGEiKSkKYGBgCgojIyBQbG90OiBkaXNjb3VudCBmYWN0b3IgZGVsdGEgZGlzdHJpYnV0aW9uIHBlciBub2RlCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPVRSVUUsIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTYuNX0KCm5vZGU9YXMuZmFjdG9yKHNvcnQocmVwKDE6MTQsTikpKQpkMT1kYXRhLmZyYW1lKGRmPWMoZGdtLm1vdXNlMTQkZGZfKSwgbm9kZT1ub2RlKQoKbm9kZT1hcy5mYWN0b3Ioc29ydChyZXAoMToxNiw4KSkpCmQyPWRhdGEuZnJhbWUoZGY9YyhkZ20ubW91c2UxNiRkZl8pLCBub2RlPW5vZGUpCgpub2RlPWFzLmZhY3Rvcihzb3J0KHJlcCgxOjgsTikpKQpkMz1kYXRhLmZyYW1lKGRmPWMoZGdtLm5ldDF3dCRkZl8pLCAgbm9kZT1ub2RlKQoKbm9kZT1hcy5mYWN0b3Ioc29ydChyZXAoMTo2LDE2KSkpCmQ0PWRhdGEuZnJhbWUoZGY9YyhkZ20ubmV0Mnd0JGRmXyksICBub2RlPW5vZGUpCgpwMSA9IGdncGxvdChkMSwgYWVzKHg9bm9kZSwgeT1kZikpICsgZ2VvbV9ib3hwbG90KHdpZHRoPTAuNCwgY29sb3I9ImJsdWUxIikgKwogIGdlb21fcG9pbnQoc2hhcGU9MSwgY29sb3I9ImdyYXk1MCIsIHNpemU9MSwgcG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXIod2lkdGggPSAwLjIsIGhlaWdodCA9IDAuMDAwMykpICsgZ2d0aXRsZSgiTW91c2UgMTQgUk9JcyAoTj0xNikiKQpwMiA9IGdncGxvdChkMiwgYWVzKHg9bm9kZSwgeT1kZikpICsgZ2VvbV9ib3hwbG90KHdpZHRoPTAuNCwgY29sb3I9ImJsdWUxIikgKwogIGdlb21fcG9pbnQoc2hhcGU9MSwgY29sb3I9ImdyYXk1MCIsIHNpemU9MSwgcG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXIod2lkdGggPSAwLjIsIGhlaWdodCA9IDAuMDAwMykpICsgZ2d0aXRsZSgiTW91c2UgMTYgUk9JcyAoTj04KSIpCnAzID0gZ2dwbG90KGQzLCBhZXMoeD1ub2RlLCB5PWRmKSkgKyBnZW9tX2JveHBsb3Qod2lkdGg9MC40LCBjb2xvcj0iYmx1ZTEiKSArCiAgZ2VvbV9wb2ludChzaGFwZT0xLCBjb2xvcj0iZ3JheTUwIiwgc2l6ZT0xLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcih3aWR0aCA9IDAuMiwgaGVpZ2h0ID0gMC4wMDAzKSkgKyBnZ3RpdGxlKCJOZXQxX1dUIChOPTE2KSIpCnA0ID0gZ2dwbG90KGQ0LCBhZXMoeD1ub2RlLCB5PWRmKSkgKyBnZW9tX2JveHBsb3Qod2lkdGg9MC40LCBjb2xvcj0iYmx1ZTEiKSArCiAgZ2VvbV9wb2ludChzaGFwZT0xLCBjb2xvcj0iZ3JheTUwIiwgc2l6ZT0xLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcih3aWR0aCA9IDAuMiwgaGVpZ2h0ID0gMC4wMDAzKSkgKyBnZ3RpdGxlKCJOZXQyX1dUIChOPTE2KSIpCgpwbG90X2dyaWQocDEsIHAzLCBwMiwgcDQsIG5jb2wgPSAyLCBucm93ID0gMiwgcmVsX3dpZHRocyA9IGMoMSwgMC41KSkKYGBgCgojIyMgREZzIHdpdGggcGFyZW50cyBvbmx5CmBgYHtyLCBmaWcuaGVpZ2h0PTIsIGZpZy53aWR0aD00fQpkZi4xID0gZGdtLm5ldDF3dCRkZl8KZGYuMiA9IGRnbS5uZXQyd3QkZGZfCgpkZi4xW3QoYXBwbHkoZGdtLm5ldDF3dCRhbSwgMywgY29sU3VtcykpID09IDBdID0gTkEKZGYuMlt0KGFwcGx5KGRnbS5uZXQyd3QkYW0sIDMsIGNvbFN1bXMpKSA9PSAwXSA9IE5BCgpzdW1tYXJ5KGNvbE1lYW5zKGRmLjEsIG5hLnJtID0gVCkpCnN1bW1hcnkoY29sTWVhbnMoZGYuMiwgbmEucm0gPSBUKSkKYGBgCgojIyBDb3JyZWxhdGlvbiBwbG90CmBgYHtyLCBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD01Ljh9CmYxNCA9IGxpc3QuZmlsZXMoZmlsZS5wYXRoKFBBVEhfREFUQSwgIlRpbWVzZXJpZXNfMTRST0lzX0NQIiksICIqLnR4dCIpCmYxNiA9IGxpc3QuZmlsZXMoZmlsZS5wYXRoKFBBVEhfREFUQSwgIldUX2ZtcjFrb18xMjBkX2RyX3N0YWdlMSIpLCAiKi50eHQiKQpmMSAgPSBsaXN0LmZpbGVzKGZpbGUucGF0aChQQVRIX0RBVEEsICJOZXQxX1dUIiksICIqLnR4dCIpCmYyICA9IGxpc3QuZmlsZXMoZmlsZS5wYXRoKFBBVEhfREFUQSwgIk5ldDJfV1QiKSwgIioudHh0IikKYXNzZXJ0KGxlbmd0aChmMTQpID09IE4pCmFzc2VydChsZW5ndGgoZjE2KSA9PSA4KQphc3NlcnQobGVuZ3RoKGYxKSAgPT0gTikKYXNzZXJ0KGxlbmd0aChmMikgID09IE4pCgojIHJlYWQgZGF0YQpkMTQgPSBhcnJheShOQSwgZGltPWMoTl90LCBObiwgTikpCmQxNiA9IGFycmF5KE5BLCBkaW09YyhOX3QsIDE2LCA4KSkKZDEgID0gYXJyYXkoTkEsIGRpbT1jKE5fdCwgTm4xLCBOKSkKZDIgID0gYXJyYXkoTkEsIGRpbT1jKE5fdCwgTm4yLCBOKSkKZm9yIChzIGluIDE6TikgewogIGQxNFssLHNdPSBzY2FsZVRzKGFzLm1hdHJpeChyZWFkLnRhYmxlKGZpbGUucGF0aChQQVRIX0RBVEEsICJUaW1lc2VyaWVzXzE0Uk9Jc19DUCIsIGYxNFtzXSkpKSkKICBpZiAocyA8PTgpIHsKICAgIGQxNlssLHNdPSBzY2FsZVRzKGFzLm1hdHJpeChyZWFkLnRhYmxlKGZpbGUucGF0aChQQVRIX0RBVEEsICJXVF9mbXIxa29fMTIwZF9kcl9zdGFnZTEiLCBmMTZbc10pKSkpCiAgfQogIGQxWywsc10gPSBzY2FsZVRzKGFzLm1hdHJpeChyZWFkLnRhYmxlKGZpbGUucGF0aChQQVRIX0RBVEEsICJOZXQxX1dUIiwgZjFbc10pKSkpCiAgZDJbLCxzXSA9IHNjYWxlVHMoYXMubWF0cml4KHJlYWQudGFibGUoZmlsZS5wYXRoKFBBVEhfREFUQSwgIk5ldDJfV1QiLCBmMltzXSkpKSkKICAjZD1zY2FsZVRzKGQpCiAgYXNzZXJ0KG5yb3coZDE0KSA9PSBOX3QpCiAgYXNzZXJ0KG5yb3coZDE2KSA9PSBOX3QpCiAgYXNzZXJ0KG5yb3coZDEpID09IE5fdCkKICBhc3NlcnQobnJvdyhkMikgPT0gTl90KQogIGFzc2VydChuY29sKGQxNCkgPT0gTm4pCiAgYXNzZXJ0KG5jb2woZDE2KSA9PSAxNikKICBhc3NlcnQobmNvbChkMSkgPT0gTm4xKQogIGFzc2VydChuY29sKGQyKSA9PSBObjIpCn0KCnAxID0gZ3Bsb3RNYXQocm1kaWFnKGNvclRzKGQxNCkpLCB0aXRsZT0nMTQgUk9JcyAoTj0xNiknLCBsaW09YygwLCAxKSwKICAgICAgICAgICAgICBjb2xNYXBMYWJlbD1leHByZXNzaW9uKCJQZWFyc29uXCdzIn5pdGFsaWMocikpKSArIHhsYWIoIk5vZGUiKSArIHlsYWIoIk5vZGUiKQpwMiA9IGdwbG90TWF0KHJtZGlhZyhjb3JUcyhkMTYpKSwgdGl0bGU9JzE2IFJPSXMgKE49OCknLCBsaW09YygtMC40LCAwLjYpLAogICAgICAgICAgICAgIGNvbE1hcExhYmVsPWV4cHJlc3Npb24oIlBlYXJzb25cJ3Mifml0YWxpYyhyKSksIGdyYWRpZW50ID0gYygiYmx1ZSIsICJ3aGl0ZSIsICJyZWQiKSkgKyB4bGFiKCJOb2RlIikgKyB5bGFiKCJOb2RlIikKcDMgPSBncGxvdE1hdChybWRpYWcoY29yVHMoZDEpKSwgdGl0bGU9J05ldDFfV1QgKE49MTYpJywgbGltPWMoMCwgMC41KSwKICAgICAgICAgICAgICBjb2xNYXBMYWJlbD1leHByZXNzaW9uKCJQZWFyc29uXCdzIn5pdGFsaWMocikpKSArIHhsYWIoIk5vZGUiKSArIHlsYWIoIk5vZGUiKQpwNCA9IGdwbG90TWF0KHJtZGlhZyhjb3JUcyhkMikpLCB0aXRsZT0nTmV0Ml9XVCAoTj0xNiknLCBsaW09YygwLCAwLjUpLAogICAgICAgICAgICAgIGNvbE1hcExhYmVsPWV4cHJlc3Npb24oIlBlYXJzb25cJ3Mifml0YWxpYyhyKSkpICsgeGxhYigiTm9kZSIpICsgeWxhYigiTm9kZSIpCgpwbG90X2dyaWQocDEsIHAyLCBwMywgcDQsIG5jb2wgPSAyLCBucm93ID0gMiwgcmVsX3dpZHRocyA9IGMoMSwgMSkpCgpgYGAKCiMjIFBsb3QgcmFuZG9tIHRpbWVzZXJpZXMKYGBge3IsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEwfQp0ID0gMToyMDAgIyBpbnRlcnZhbCB0byBwbG90CgojIHJhbmRvbSBzYW1wbGluZyBtaWNlIG0gYW5kIG5vZGVzIG4Kbm9kZXMgPSA1ICMgbm8uIG9mIG5vZGVzIHRvIHBsb3QKCmQgPSBtZWx0KGQxNFt0LHNhbXBsZSgxNCxub2Rlcyksc2FtcGxlKE4sMSldKQpwMT1nZ3Bsb3QoZCwgYWVzKHggPSBWYXIxLCB5ID0gdmFsdWUsIGdyb3VwPVZhcjIsIGNvbG9yPWFzLmZhY3RvcihWYXIyKSkpICsgZ2VvbV9saW5lKCkgKyB0aGVtZV9taW5pbWFsKCkgKyAKICBnZ3RpdGxlKCJNb3VzZSAxNCBST0lzIikKCmQgPSBtZWx0KGQxNlt0LHNhbXBsZSgxNixub2Rlcyksc2FtcGxlKDgsMSldKQpwMj1nZ3Bsb3QoZCwgYWVzKHggPSBWYXIxLCB5ID0gdmFsdWUsIGdyb3VwPVZhcjIsIGNvbG9yPWFzLmZhY3RvcihWYXIyKSkpICsgZ2VvbV9saW5lKCkgKyB0aGVtZV9taW5pbWFsKCkgKyBnZ3RpdGxlKCJNb3VzZSAxNiBST0lzIikKCmQgPSBtZWx0KGQxW3Qsc2FtcGxlKDgsbm9kZXMpLHNhbXBsZShOLDEpXSkKcDM9Z2dwbG90KGQsIGFlcyh4ID0gVmFyMSwgeSA9IHZhbHVlLCBncm91cD1WYXIyLCBjb2xvcj1hcy5mYWN0b3IoVmFyMikpKSArIGdlb21fbGluZSgpICsgdGhlbWVfbWluaW1hbCgpICsgZ2d0aXRsZSgiTmV0MV9XVCIpCgpkID0gbWVsdChkMlt0LHNhbXBsZSg2LG5vZGVzKSxzYW1wbGUoTiwxKV0pCnA0PWdncGxvdChkLCBhZXMoeCA9IFZhcjEsIHkgPSB2YWx1ZSwgZ3JvdXA9VmFyMiwgY29sb3I9YXMuZmFjdG9yKFZhcjIpKSkgKyBnZW9tX2xpbmUoKSArIHRoZW1lX21pbmltYWwoKSArIGdndGl0bGUoIk5ldDJfV1QiKQoKcGxvdF9ncmlkKHAxLCBwMiwgcDMsIHA0LCBuY29sID0gMSwgbnJvdyA9IDQsIHJlbF93aWR0aHMgPSBjKDEsIDEpKQoKYGBgCgojIyBOZXR3b3JrIGNvbnNpc3RlbmN5IGFjcm9zcyBtaWNlCgpgYGB7ciwgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9NS4yfQoKc3RhdHMxID0gYmlub20ubmV0dGVzdChkZ20ubW91c2UxNCRhbSkKc3RhdHMyID0gYmlub20ubmV0dGVzdChkZ20ubW91c2UxNiRhbSkKCnAxID0gZ3Bsb3RNYXQoc3RhdHMxJGFkaiwgdGl0bGUgPSAiTW91c2UgMTQgUk9JcyIpCnAyID0gZ3Bsb3RNYXQocm1uYShzdGF0czEkYWRqX2ZkciksIHRpdGxlID0gImJpbm9tIHRlc3QgJiBGRFIiKQoKcDMgPSBncGxvdE1hdChzdGF0czIkYWRqLCB0aXRsZSA9ICJNb3VzZSAxNiBST0lzIikKcDQgPSBncGxvdE1hdChybW5hKHN0YXRzMiRhZGpfZmRyKSwgdGl0bGUgPSAiYmlub20gdGVzdCAmIEZEUiIpCgpwbG90X2dyaWQocDEsIHAyLCBwMywgcDQsIG5jb2wgPSAyLCBucm93ID0gMiwgcmVsX2hlaWdodHMgPSBjKDEsMSksIGxhYmVscyA9IGMoIkEiLCAiIiwgIkIiKSApCmBgYAoKCiMjIEZpZ3VyZSAxMQpgYGB7ciwgZmlnLmhlaWdodD00LjUsIGZpZy53aWR0aD01LjJ9CnN0YXRzMyA9IGJpbm9tLm5ldHRlc3QoZGdtLm5ldDF3dCRhbSkKc3RhdHM0ID0gYmlub20ubmV0dGVzdChkZ20ubmV0Mnd0JGFtKQoKcG9zID0gMC41OjguNApteWxhYmVscyA9IGMoIk9yYk0iLCAiT3JiTCIsICJOQWNjIiwgIkNpbmciLCAgIkFteWciLCAiQ0ExIiwgIkRHIiwgIkVudG9yaCIpCgpwNSA9IGdwbG90TWF0KHN0YXRzMyRhZGosIHRpdGxlID0gImFteWctaGlwcC1lbnRob3JpbiIsIG5vZGVMYWJlbHM9bXlsYWJlbHMsIGF4aXNUZXh0U2l6ZT05LAogICAgICAgICAgICAgIHhBbmdsZT05MCwgYmFyV2lkdGggPSAwLjIpICsgCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHBvcywgbGFiZWxzID0gbXlsYWJlbHMpCgpwNiA9IGdwbG90TWF0KHJtbmEoc3RhdHMzJGFkal9mZHIpLCB0aXRsZSA9ICJiaW5vbWlhbCB0ZXN0Iiwgbm9kZUxhYmVscz1teWxhYmVscywgYXhpc1RleHRTaXplPTksCiAgICAgICAgICAgICAgeEFuZ2xlPTkwLCBiYXJXaWR0aCA9IDAuMikgKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBwb3MsIGxhYmVscyA9IG15bGFiZWxzKQoKcG9zID0gMC41OjYuNApteWxhYmVscyA9IGMoIlNvbVNlbnNSIiwgIk1vdG9yUiIsICJQdXRhbVIiLCAiU29tU2Vuc0wiLCAiTW90b3JMIiwgIlB1dGFtTCIpCgpwNyA9IGdwbG90TWF0KHN0YXRzNCRhZGosIHRpdGxlID0gImNvcnQtc3RyaWF0LXBhbGxpZCIsIG5vZGVMYWJlbHM9bXlsYWJlbHMsIGF4aXNUZXh0U2l6ZT05LCAKICAgICAgICAgICAgICB4QW5nbGU9OTAsIGJhcldpZHRoID0gMC4yKSArIAogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBwb3MsIGxhYmVscyA9IG15bGFiZWxzKQoKcDggPSBncGxvdE1hdChybW5hKHN0YXRzNCRhZGpfZmRyKSwgdGl0bGUgPSAiYmlub21pYWwgdGVzdCIsIG5vZGVMYWJlbHM9bXlsYWJlbHMsIGF4aXNUZXh0U2l6ZT05LCAKICAgICAgICAgICAgICB4QW5nbGU9OTAsIGJhcldpZHRoID0gMC4yKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHBvcywgbGFiZWxzID0gbXlsYWJlbHMpCgpwbG90X2dyaWQocDUsIHA2LCBwNywgcDgsIG5jb2wgPSAyLCBucm93ID0gMiwKICAgICAgICAgIHJlbF9oZWlnaHRzID0gYygxLDEpLCBsYWJlbHMgPSBjKCJBIiwgIiIsICJCIikgKQpnZ3NhdmUocGF0aCA9IGZpbGUucGF0aChQQVRILCAnZmlndXJlcycpLCAiRmlnMTEucG5nIikKYGBgCgojIyMgRGlmZmVyZW5jZSBiZXR3ZWVuIGU9MCBhbmQgZT0yMApgYGB7cn0KeD0gYyhzdW0oZGdtLm5ldDF3dCRhbSAhPSBkZ20ubmV0MXd0JHRhbSksCiAgICAgc3VtKGRnbS5uZXQyd3QkYW0gIT0gZGdtLm5ldDJ3dCR0YW0pKQoKcHJpbnQoeCkKcHJpbnQoeC9jKE4qTm4xKihObjEtMSksIE4qTm4yKihObjItMSkpKQpgYGAKCgojIyBQcm9wb3J0aW9ucwpgYGB7cn0Kc3RhdHMzJGFkagptYXgoc3RhdHMzJGFkaikKCnN0YXRzNCRhZGoKbWF4KHN0YXRzNCRhZGopCmBgYAoKCg==