Out-of-sample Test
We calcualte one-day ahead predicted VaR and CoVaR using past 500 days (rolloing window) and then match with loss series. Specifically, we use data from day 1 to 500 to fit Garch model and get residual series and predicted mu and sigmal. Then we calculate one-day ahead predicted VaR and CoVaR, that is day 501 VaR and CoVaR.
## identify subsample where L[t+1]^j > VaR[t+1]^j
n=dim(covar.KO)[1]
end = nrow(r.KO) + 1
setwd("~/OneDrive - INSEAD/SkewEllipt/Code_Update/Natalia/out500/")
load("outKO.RDATA")
var.KO <- out.p$stEVT[,2:3]
loss.KO <- -r.KO$r[(end-n):(end-1)]
load("outBA.RDATA")
var.BA <- out.p$stEVT[,2:3]
loss.BA <- -r.BA$r[(end-n):(end-1)]
load("outDIS.RDATA")
var.DIS <- out.p$stEVT[,2:3]
loss.DIS <- -r.DIS$r[(end-n):(end-1)]
load("outGE.RDATA")
var.GE <- out.p$stEVT[,2:3]
loss.GE <- -r.GE$r[(end-n):(end-1)]
y <- loss.DIS
rmat <- var.DIS
covar <- covar.DIS
yI <- as.vector(-rSP[(end-n):(end-1)])
We check the performance of predicted VaR:
k=dim(rmat)[2] # number of methods/cases
ymat = matrix(rep(y, k), ncol = k, byrow=FALSE)
hmat = (ymat > rmat)
apply(hmat,2,"sum",na.rm=T)/n*100
[1] 5.162738 1.234568
We check the performance of predicted CoVaR:
r.evt.sub95 <- subset(covar[,1],hmat[,1])
r.evt.sub99 <- subset(covar[,2],hmat[,2])
r.emp.sub95 <- subset(covar[,3],hmat[,1])
r.emp.sub99 <- subset(covar[,4],hmat[,2])
r.fp.sub95 <- subset(covar[,5],hmat[,1])
r.fp.sub99 <- subset(covar[,6],hmat[,2])
## Checking % violations of CoVaR by the index losses
yI.sub95 <- as.numeric(subset(yI, hmat[,1]))
yI.sub99 <- as.numeric(subset(yI, hmat[,2]))
# Remove NA values
r.sub95 = rbind(r.evt.sub95,r.emp.sub95, r.fp.sub95)
ind.na95 = which( (is.na(apply(r.sub95,2,sum))) )
r.sub99 = rbind(r.evt.sub99,r.emp.sub99, r.fp.sub99)
ind.na99 = which((is.na(apply(r.sub99,2,sum))) )
if (length(ind.na95)>0){
r.evt.sub95 <- r.evt.sub95[-ind.na95]
r.emp.sub95 <- r.emp.sub95[-ind.na95]
r.fp.sub95 <- r.fp.sub95[-ind.na95]
yI.sub95 <- yI.sub95[-ind.na95]
}
if (length(ind.na99)>0){
r.evt.sub99 <- r.evt.sub99[-ind.na99]
r.emp.sub99 <- r.emp.sub99[-ind.na99]
r.fp.sub99 <- r.fp.sub99[-ind.na99]
yI.sub99 <- yI.sub99[-ind.na99]
}
m95 <- length(yI.sub95) #sub-sample size for q=0.95
m99 <- length(yI.sub99) #sub-sample size for q=0.99
round(c(sum(yI.sub95>r.evt.sub95)/m95*100,sum(yI.sub95>r.emp.sub95)/m95*100, sum(yI.sub95>r.fp.sub95)/m95*100, sum(yI.sub99>r.evt.sub99)/m99*100, sum(yI.sub99>r.emp.sub99)/m99*100, sum(yI.sub99>r.fp.sub99)/m99*100),2)
[1] 14.22 9.58 6.39 3.66 23.78 2.44
The EVT method does not perform well for 95% CoVaR estimation but relatively good for 99% CoVaR estimation. Simple CCT is consistent with this result, but comparative backtesting and TLM suggests that FP is slightly better than EVT. In summary, EVT and FP is significantly better than empirical method at 10% level for estimation 99% CoVaR, but EVT and FP are quite similar.
cct <- matrix(nrow=3, ncol=2) # simple & general CCT
tmp <- cct.2s.VaR(x=yI.sub95, r=r.evt.sub95,lev=0.95); cct[1,]<-c(tmp$pv.avg,tmp$pv.cond)
tmp <- cct.2s.VaR(x=yI.sub95, r=r.emp.sub95,lev=0.95); cct[2,]<-c(tmp$pv.avg,tmp$pv.cond)
tmp <- cct.2s.VaR(x=yI.sub95, r=r.fp.sub95,lev=0.95); cct[3,]<-c(tmp$pv.avg,tmp$pv.cond)
round(cct,3)
[,1] [,2]
[1,] 0.000 0.000
[2,] 0.000 0.000
[3,] 0.137 0.194
# tmp <- cct.2s.VaR(x=yI.sub99, r=r.evt.sub99,lev=0.99); cct[1,]<-c(tmp$pv.avg,tmp$pv.cond)
# tmp <- cct.2s.VaR(x=yI.sub99, r=r.emp.sub99,lev=0.99); cct[2,]<-c(tmp$pv.avg,tmp$pv.cond)
# tmp <- cct.2s.VaR(x=yI.sub99, r=r.fp.sub99,lev=0.99); cct[3,]<-c(tmp$pv.avg,tmp$pv.cond)
# round(cct,3)
## ONE-SIDED TEST of super-calibration as in Basel Accord
cct.1s <- matrix(nrow=3, ncol=2) # simple & general one-sided CCT of super-calibration
tmp <- cct.1s.VaR(x=yI.sub95, r=r.evt.sub95,lev=0.95); cct.1s[1,]<-c(tmp$pv.avg,tmp$pv.cond)
tmp <- cct.1s.VaR(x=yI.sub95, r=r.emp.sub95,lev=0.95); cct.1s[2,]<-c(tmp$pv.avg,tmp$pv.cond)
tmp <- cct.1s.VaR(x=yI.sub95, r=r.fp.sub95,lev=0.95); cct.1s[3,]<-c(tmp$pv.avg,tmp$pv.cond)
round(cct.1s,3)
[,1] [,2]
[1,] 0.000 0.000
[2,] 0.000 0.000
[3,] 0.069 0.206
cct.1s <- matrix(nrow=3, ncol=2) # simple & general one-sided CCT of super-calibration
tmp <- cct.1s.VaR(x=yI.sub99, r=r.evt.sub99,lev=0.99); cct.1s[1,]<-c(tmp$pv.avg,tmp$pv.cond)
tmp <- cct.1s.VaR(x=yI.sub99, r=r.emp.sub99,lev=0.99); cct.1s[2,]<-c(tmp$pv.avg,tmp$pv.cond)
tmp <- cct.1s.VaR(x=yI.sub99, r=r.fp.sub99,lev=0.99); cct.1s[3,]<-c(tmp$pv.avg,tmp$pv.cond)
round(cct.1s,3)
[,1] [,2]
[1,] 0.036 0.109
[2,] 0.000 0.000
[3,] 0.117 0.221
## Comparative backtesting
## q=.95
smat <- matrix(nrow=3, ncol=1)
smat[1,1] <- mean(sfVaR(r=r.evt.sub95,x=yI.sub95,a=0.95,h=1))
smat[2,1] <- mean(sfVaR(r=r.emp.sub95,x=yI.sub95,a=0.95,h=1))
smat[3,1] <- mean(sfVaR(r=r.fp.sub95,x=yI.sub95,a=0.95,h=1))
apply(smat,2,"rank")
[,1]
[1,] 3
[2,] 2
[3,] 1
## q=.99
smat <- matrix(nrow=3, ncol=1)
smat[1,1] <- mean(sfVaR(r=r.evt.sub99,x=yI.sub99,a=0.99,h=1))
smat[2,1] <- mean(sfVaR(r=r.emp.sub99,x=yI.sub99,a=0.99,h=1))
smat[3,1] <- mean(sfVaR(r=r.fp.sub99,x=yI.sub99,a=0.99,h=1))
apply(smat,2,"rank")
[,1]
[1,] 1
[2,] 3
[3,] 2
## TLM
rm=1
tlm95 <- TLMfn(r=rbind(r.evt.sub95,r.emp.sub95,r.fp.sub95), y=yI.sub95, rm=rm, lev=0.95,h=1)
plotTLM(tlm95$TLM10, rm=1, lev=0.95,method=c("evt","emp","st"))

tlm99 <- TLMfn(r=rbind(r.evt.sub99,r.emp.sub99,r.fp.sub99), y=yI.sub99, rm=rm, lev=0.99,h=1)
plotTLM(tlm99$TLM10, rm=1, lev=0.99,method=c("evt","emp","st"))

In-Sample Test
However, we can show that movement in CoVaR is driven by the predict sigmal from Garch model, and the predicted sigmal shares the similar pattern of lagged loss series. The figure blow plots subsample with 100 days for SP500 loss series. As shown in the figure, the peaks of sigma_SP500 are in line with CoVaR from EVT and FP, but are one-period head of loss series (see x-axis 80-100). This result comes from the fact that predicted sigma is heavily affected by the most recent data. When there is a high reutrn (or loss) today, the predicted volatility will be very high tomorrow.
plot(covar[5800:5900,1], type = "l", col = "blue", ylim = c(-0.1,0.2), lty = 3, ylab = "Return")
points(covar[5800:5900,5], type = "l", col = "black", lty = 1)
points(yI[5800:5900], type = "l", col = "red", lty = 2)
setwd("~/OneDrive - INSEAD/SkewEllipt/Code_Update/Natalia/out500/")
load("outSP500.RDATA")
points(out.p$sigt.st[5800:5900], type = "l", col = 'green', lty = 4)
legend("topright", legend = c("EVT", "FP", "SP500","sigma_SP500"), col = c("blue", "black", "red","green"), lty = c(3,1,2,4))

Similarly, if we plot subsample in which DIS loss is beyond 99% VaR, the peaks of SP00 and CoVaR from different methods are not aligned.
plot(r.fp.sub99, type = "l", col = "blue", ylim = c(-0.03,0.3), lty = 3, ylab = "Return")
points(yI.sub99, type = "l", col = "black", lty = 1)
points(r.evt.sub99, type = "l", col = "red", lty = 2)
legend("topright", legend = c("FP", "EVT", "Loss"), col = c("blue", "red", "black"), lty = c(3,2,1))

If we shift Loss series one-day ahead (or shift CoVaR one day one-day backward), then the peaks are aligned. Essentially, this is in-sample analysis. We compare CoVaR estiamted using day 1 to day 500 data with day 500 loss.
## identify subsample where L[t+1]^j > VaR[t+1]^j
n=dim(covar.KO)[1]
end = nrow(r.KO)
loss.DIS <- -r.DIS$r[(end-n):(end-1)]
y <- loss.DIS
yI <- as.vector(-rSP[(end-n):(end-1)])
plot(covar[5800:5900,1], type = "l", col = "blue", ylim = c(-0.1,0.2), lty = 3, ylab = "Return")
points(covar[5800:5900,5], type = "l", col = "black", lty = 1)
points(yI[5800:5900], type = "l", col = "red", lty = 2)
setwd("~/OneDrive - INSEAD/SkewEllipt/Code_Update/Natalia/out500/")
load("outSP500.RDATA")
points(out.p$sigt.st[5800:5900], type = "l", col = 'green', lty = 4)
legend("topright", legend = c("EVT", "FP", "SP500","sigma_SP500"), col = c("blue", "black", "red","green"), lty = c(3,1,2,4))

Now, we repeat all the analysis for in-sample CoVaR.
k=dim(rmat)[2] # number of methods/cases
ymat = matrix(rep(y, k), ncol = k, byrow=FALSE)
hmat = (ymat > rmat)
apply(hmat,2,"sum",na.rm=T)/n*100
[1] 3.7186682 0.4489338
r.evt.sub95 <- subset(covar[,1],hmat[,1])
r.evt.sub99 <- subset(covar[,2],hmat[,2])
r.emp.sub95 <- subset(covar[,3],hmat[,1])
r.emp.sub99 <- subset(covar[,4],hmat[,2])
r.fp.sub95 <- subset(covar[,5],hmat[,1])
r.fp.sub99 <- subset(covar[,6],hmat[,2])
## Checking % violations of CoVaR by the index losses
yI.sub95 <- as.numeric(subset(yI, hmat[,1]))
yI.sub99 <- as.numeric(subset(yI, hmat[,2]))
# Remove NA values
r.sub95 = rbind(r.evt.sub95,r.emp.sub95, r.fp.sub95)
ind.na95 = which( (is.na(apply(r.sub95,2,sum))) )
r.sub99 = rbind(r.evt.sub99,r.emp.sub99, r.fp.sub99)
ind.na99 = which((is.na(apply(r.sub99,2,sum))) )
if (length(ind.na95)>0){
r.evt.sub95 <- r.evt.sub95[-ind.na95]
r.emp.sub95 <- r.emp.sub95[-ind.na95]
r.fp.sub95 <- r.fp.sub95[-ind.na95]
yI.sub95 <- yI.sub95[-ind.na95]
}
if (length(ind.na99)>0){
r.evt.sub99 <- r.evt.sub99[-ind.na99]
r.emp.sub99 <- r.emp.sub99[-ind.na99]
r.fp.sub99 <- r.fp.sub99[-ind.na99]
yI.sub99 <- yI.sub99[-ind.na99]
}
m95 <- length(yI.sub95) #sub-sample size for q=0.95
m99 <- length(yI.sub99) #sub-sample size for q=0.99
round(c(sum(yI.sub95>r.evt.sub95)/m95*100,sum(yI.sub95>r.emp.sub95)/m95*100, sum(yI.sub95>r.fp.sub95)/m95*100, sum(yI.sub99>r.evt.sub99)/m99*100, sum(yI.sub99>r.emp.sub99)/m99*100, sum(yI.sub99>r.fp.sub99)/m99*100),2)
[1] 4.84 2.42 2.62 0.00 0.00 0.00
From above numbers, EVT looks work quite well for in-sample analysis. However, comparative backtesting and TLM seem to suggest that EVT is worse than empirical method. I do not understand why we get different resutls from different tests.
cct <- matrix(nrow=3, ncol=2) # simple & general CCT
tmp <- cct.2s.VaR(x=yI.sub95, r=r.evt.sub95,lev=0.95); cct[1,]<-c(tmp$pv.avg,tmp$pv.cond)
tmp <- cct.2s.VaR(x=yI.sub95, r=r.emp.sub95,lev=0.95); cct[2,]<-c(tmp$pv.avg,tmp$pv.cond)
tmp <- cct.2s.VaR(x=yI.sub95, r=r.fp.sub95,lev=0.95); cct[3,]<-c(tmp$pv.avg,tmp$pv.cond)
round(cct,3)
[,1] [,2]
[1,] 0.867 0.795
[2,] 0.000 0.000
[3,] 0.001 0.002
# tmp <- cct.2s.VaR(x=yI.sub99, r=r.evt.sub99,lev=0.99); cct[1,]<-c(tmp$pv.avg,tmp$pv.cond)
# tmp <- cct.2s.VaR(x=yI.sub99, r=r.emp.sub99,lev=0.99); cct[2,]<-c(tmp$pv.avg,tmp$pv.cond)
# tmp <- cct.2s.VaR(x=yI.sub99, r=r.fp.sub99,lev=0.99); cct[3,]<-c(tmp$pv.avg,tmp$pv.cond)
# round(cct,3)
## ONE-SIDED TEST of super-calibration as in Basel Accord
cct.1s <- matrix(nrow=3, ncol=2) # simple & general one-sided CCT of super-calibration
tmp <- cct.1s.VaR(x=yI.sub95, r=r.evt.sub95,lev=0.95); cct.1s[1,]<-c(tmp$pv.avg,tmp$pv.cond)
tmp <- cct.1s.VaR(x=yI.sub95, r=r.emp.sub95,lev=0.95); cct.1s[2,]<-c(tmp$pv.avg,tmp$pv.cond)
tmp <- cct.1s.VaR(x=yI.sub95, r=r.fp.sub95,lev=0.95); cct.1s[3,]<-c(tmp$pv.avg,tmp$pv.cond)
round(cct.1s,3)
[,1] [,2]
[1,] 0.566 1
[2,] 1.000 1
[3,] 0.999 1
cct.1s <- matrix(nrow=3, ncol=2) # simple & general one-sided CCT of super-calibration
tmp <- cct.1s.VaR(x=yI.sub99, r=r.evt.sub99,lev=0.99); cct.1s[1,]<-c(tmp$pv.avg,tmp$pv.cond)
tmp <- cct.1s.VaR(x=yI.sub99, r=r.emp.sub99,lev=0.99); cct.1s[2,]<-c(tmp$pv.avg,tmp$pv.cond)
tmp <- cct.1s.VaR(x=yI.sub99, r=r.fp.sub99,lev=0.99); cct.1s[3,]<-c(tmp$pv.avg,tmp$pv.cond)
round(cct.1s,3)
[,1] [,2]
[1,] 1 1
[2,] 1 1
[3,] 1 1
## Comparative backtesting
## q=.95
smat <- matrix(nrow=3, ncol=1)
smat[1,1] <- mean(sfVaR(r=r.evt.sub95,x=yI.sub95,a=0.95,h=1))
smat[2,1] <- mean(sfVaR(r=r.emp.sub95,x=yI.sub95,a=0.95,h=1))
smat[3,1] <- mean(sfVaR(r=r.fp.sub95,x=yI.sub95,a=0.95,h=1))
apply(smat,2,"rank")
[,1]
[1,] 2
[2,] 1
[3,] 3
## q=.99
smat <- matrix(nrow=3, ncol=1)
smat[1,1] <- mean(sfVaR(r=r.evt.sub99,x=yI.sub99,a=0.99,h=1))
smat[2,1] <- mean(sfVaR(r=r.emp.sub99,x=yI.sub99,a=0.99,h=1))
smat[3,1] <- mean(sfVaR(r=r.fp.sub99,x=yI.sub99,a=0.99,h=1))
apply(smat,2,"rank")
[,1]
[1,] 3
[2,] 1
[3,] 2
## TLM
rm=1
tlm95 <- TLMfn(r=rbind(r.evt.sub95,r.emp.sub95,r.fp.sub95), y=yI.sub95, rm=rm, lev=0.95,h=1)
plotTLM(tlm95$TLM10, rm=1, lev=0.95,method=c("evt","emp","st"))

tlm99 <- TLMfn(r=rbind(r.evt.sub99,r.emp.sub99,r.fp.sub99), y=yI.sub99, rm=rm, lev=0.99,h=1)
plotTLM(tlm99$TLM10, rm=1, lev=0.99,method=c("evt","emp","st"))

plot(r.fp.sub99, type = "l", col = "blue", ylim = c(-0.03,0.4), lty = 3, ylab = "Return")
points(yI.sub99, type = "l", col = "black", lty = 1)
points(r.evt.sub99, type = "l", col = "red", lty = 2)
legend("topright", legend = c("FP", "EVT", "Loss"), col = c("blue", "red", "black"), lty = c(3,2,1))

plot(yI, ylab="", ylim=c(-.12,0.4), col="gray",xlab="", main="DIS", cex.main=0.8, lty = 1)
lines(time(yI),covar.DIS[,1], col="red", lty = 2)
lines(time(yI),covar.DIS[,5], col="black", lty = 3)
lines(time(yI),covar.DIS[,3], col="green", lty = 4)
legend("topleft", legend = c("SP500", "EVT", "FP", "HS"), col = c("grey", "red", "black", "green"), lty = c(1,2,3,4))

LS0tCnRpdGxlOiAiQ29WYVIgLS0gRElTIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgojIyMgUHJlcGFyZSBEYXRhOgoKYGBge3IgaW5jbHVkZT1UUlVFLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmc9RkFMU0V9CnJtKGxpc3QgPSBscygpKQpsaWJyYXJ5KCJydWdhcmNoIikKbGlicmFyeSgiZkdhcmNoIikKbGlicmFyeSgiTUFTUyIpCmxpYnJhcnkoImlzbWV2IikKIyBsaWJyYXJ5KCJsbW9tIikKIyBsaWJyYXJ5KCJRUk0iKQpsaWJyYXJ5KCJza2V3dCIpCmxpYnJhcnkoInpvbyIpCmxpYnJhcnkoInBsb3RyaXgiKQoKc291cmNlKCJ+L09uZURyaXZlIC0gSU5TRUFEL1NrZXdFbGxpcHQvQ29kZV9VcGRhdGUvUmZucy5SIikKc2V0d2QoIn4vT25lRHJpdmUgLSBJTlNFQUQvU2tld0VsbGlwdC9Db2RlX1VwZGF0ZS9OYXRhbGlhL291dDUwMC8iKQojIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIyBCYWNrdGVzdGluZyBDb1ZhUgojIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQoKZGF0ID0gZnJlYWQoIn4vT25lRHJpdmUgLSBJTlNFQUQvU2tld0VsbGlwdC9Db2RlX1VwZGF0ZS9OYXRhbGlhL1JldF9kYXRhLmNzdiIpICMgcmF3IGRhdGEgZmlsZSAoMTk2Mi8wNy8wMiAtIDIwMTcvMDcvMzEpCmRhdCA9IGRhdFssYDo9YChSRVQ9YXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoUkVUKSksIFNQNTAwID0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoU1A1MDApKSldCmRhdCA9IGRhdFshaXMubmEoUkVUKV0KZGF0ID0gdW5pcXVlKGRhdCwgYnkgPSBjKCJUSUNLRVIiLCAiZGF0ZSIpICkKc2V0bmFtZXMoZGF0LCAiUkVUIiwgInIiKQpyLktPID0gZGF0W1RJQ0tFUiA9PSAnS08nLCBsaXN0KGRhdGUsIFRJQ0tFUiwgciwgU1A1MDApXQpyLkdFID0gZGF0W1RJQ0tFUiA9PSAnR0UnLCBsaXN0KGRhdGUsIFRJQ0tFUiwgciwgU1A1MDApXQpyLkJBID0gZGF0W1RJQ0tFUiA9PSAnQkEnLCBsaXN0KGRhdGUsIFRJQ0tFUiwgciwgU1A1MDApXQpyLkRJUyA9IGRhdFtUSUNLRVIgPT0gJ0RJUycsIGxpc3QoZGF0ZSwgVElDS0VSLCByLCBTUDUwMCldCgpkYXQuaW5kaWNlcyA8LSB1bmlxdWUoZGF0YS5mcmFtZShkYXQkZGF0ZSxkYXQkUmV0X00sZGF0JFNQNTAwKSkKY29sbmFtZXMoZGF0LmluZGljZXMpPC1jKCJkYXRlIiwicmV0TSIsInNwNTAwIikKck0gPC0gem9vKHg9ZGF0LmluZGljZXMkcmV0TSxvcmRlci5ieSA9IHN0cnB0aW1lKGRhdC5pbmRpY2VzJGRhdGUsIiVZJW0lZCIpKQpyU1A8LSB6b28oeD1kYXQuaW5kaWNlcyRzcDUwMCxvcmRlci5ieSA9IHN0cnB0aW1lKGRhdC5pbmRpY2VzJGRhdGUsIiVZJW0lZCIpKQoKbG9hZCgiQ29WYVIuUkRBVEEiKQojIGF0dHJpYnV0ZXMob3V0KQoKIyNjb2x1bW5zIGFyZSA5NSUgQ29WYVIgYnkgRVZUIG1ldGhvZCwgOTklIENvVmFSIGJ5IEVWVCBtZXRob2QgYW5kIDk1JSBDb1ZhUiBieSBlbXBpcmljYWwgbWV0aG9kCgpjb3Zhci5LTyA8LSBvdXQkQ29WYVIuS08KY292YXIuQkEgPC0gb3V0JENvVmFSLkJBCmNvdmFyLkRJUyA8LSBvdXQkQ29WYVIuRElTCiMgY292YXIuR0UgPC0gb3V0JENvVmFSLkdFCmBgYAoKCiMjIyBPdXQtb2Ytc2FtcGxlIFRlc3QKV2UgY2FsY3VhbHRlIG9uZS1kYXkgYWhlYWQgcHJlZGljdGVkIFZhUiBhbmQgQ29WYVIgdXNpbmcgcGFzdCA1MDAgZGF5cyAocm9sbG9pbmcgd2luZG93KSBhbmQgdGhlbiBtYXRjaCB3aXRoIGxvc3Mgc2VyaWVzLiBTcGVjaWZpY2FsbHksIHdlIHVzZSBkYXRhIGZyb20gZGF5IDEgdG8gNTAwIHRvIGZpdCBHYXJjaCBtb2RlbCBhbmQgZ2V0IHJlc2lkdWFsIHNlcmllcyBhbmQgcHJlZGljdGVkIG11IGFuZCBzaWdtYWwuIFRoZW4gd2UgY2FsY3VsYXRlIG9uZS1kYXkgYWhlYWQgcHJlZGljdGVkIFZhUiBhbmQgQ29WYVIsIHRoYXQgaXMgZGF5IDUwMSBWYVIgYW5kIENvVmFSLgoKCmBgYHtyLG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZz1GQUxTRX0KIyMgaWRlbnRpZnkgc3Vic2FtcGxlIHdoZXJlIExbdCsxXV5qID4gVmFSW3QrMV1eagpuPWRpbShjb3Zhci5LTylbMV0KZW5kID0gbnJvdyhyLktPKSArIDEKc2V0d2QoIn4vT25lRHJpdmUgLSBJTlNFQUQvU2tld0VsbGlwdC9Db2RlX1VwZGF0ZS9OYXRhbGlhL291dDUwMC8iKQpsb2FkKCJvdXRLTy5SREFUQSIpCnZhci5LTyA8LSBvdXQucCRzdEVWVFssMjozXQpsb3NzLktPIDwtIC1yLktPJHJbKGVuZC1uKTooZW5kLTEpXQoKbG9hZCgib3V0QkEuUkRBVEEiKQp2YXIuQkEgPC0gb3V0LnAkc3RFVlRbLDI6M10KbG9zcy5CQSA8LSAtci5CQSRyWyhlbmQtbik6KGVuZC0xKV0KCmxvYWQoIm91dERJUy5SREFUQSIpCnZhci5ESVMgPC0gb3V0LnAkc3RFVlRbLDI6M10KbG9zcy5ESVMgPC0gLXIuRElTJHJbKGVuZC1uKTooZW5kLTEpXQoKbG9hZCgib3V0R0UuUkRBVEEiKQp2YXIuR0UgPC0gb3V0LnAkc3RFVlRbLDI6M10KbG9zcy5HRSA8LSAtci5HRSRyWyhlbmQtbik6KGVuZC0xKV0KYGBgCgpgYGB7cn0KeSA8LSBsb3NzLkRJUwpybWF0IDwtIHZhci5ESVMKY292YXIgPC0gY292YXIuRElTCnlJIDwtIGFzLnZlY3RvcigtclNQWyhlbmQtbik6KGVuZC0xKV0pCmBgYAoKV2UgY2hlY2sgdGhlIHBlcmZvcm1hbmNlIG9mIHByZWRpY3RlZCBWYVI6CmBgYHtyfQprPWRpbShybWF0KVsyXSAjIG51bWJlciBvZiBtZXRob2RzL2Nhc2VzCnltYXQgPSBtYXRyaXgocmVwKHksIGspLCBuY29sID0gaywgYnlyb3c9RkFMU0UpCmhtYXQgPSAoeW1hdCA+IHJtYXQpCgphcHBseShobWF0LDIsInN1bSIsbmEucm09VCkvbioxMDAKYGBgCgpXZSBjaGVjayB0aGUgcGVyZm9ybWFuY2Ugb2YgcHJlZGljdGVkIENvVmFSOgpgYGB7cn0Kci5ldnQuc3ViOTUgPC0gc3Vic2V0KGNvdmFyWywxXSxobWF0WywxXSkKci5ldnQuc3ViOTkgPC0gc3Vic2V0KGNvdmFyWywyXSxobWF0WywyXSkKci5lbXAuc3ViOTUgPC0gc3Vic2V0KGNvdmFyWywzXSxobWF0WywxXSkKci5lbXAuc3ViOTkgPC0gc3Vic2V0KGNvdmFyWyw0XSxobWF0WywyXSkKci5mcC5zdWI5NSA8LSAgc3Vic2V0KGNvdmFyWyw1XSxobWF0WywxXSkKci5mcC5zdWI5OSA8LSAgc3Vic2V0KGNvdmFyWyw2XSxobWF0WywyXSkKCiMjIENoZWNraW5nICUgdmlvbGF0aW9ucyBvZiBDb1ZhUiBieSB0aGUgaW5kZXggbG9zc2VzCnlJLnN1Yjk1IDwtIGFzLm51bWVyaWMoc3Vic2V0KHlJLCBobWF0WywxXSkpCnlJLnN1Yjk5IDwtIGFzLm51bWVyaWMoc3Vic2V0KHlJLCBobWF0WywyXSkpCgojIFJlbW92ZSBOQSB2YWx1ZXMKci5zdWI5NSA9IHJiaW5kKHIuZXZ0LnN1Yjk1LHIuZW1wLnN1Yjk1LCByLmZwLnN1Yjk1KQppbmQubmE5NSA9IHdoaWNoKCAoaXMubmEoYXBwbHkoci5zdWI5NSwyLHN1bSkpKSApCgpyLnN1Yjk5ID0gcmJpbmQoci5ldnQuc3ViOTksci5lbXAuc3ViOTksIHIuZnAuc3ViOTkpCmluZC5uYTk5ID0gd2hpY2goKGlzLm5hKGFwcGx5KHIuc3ViOTksMixzdW0pKSkgKQoKaWYgKGxlbmd0aChpbmQubmE5NSk+MCl7CiAgci5ldnQuc3ViOTUgPC0gci5ldnQuc3ViOTVbLWluZC5uYTk1XQogIHIuZW1wLnN1Yjk1IDwtIHIuZW1wLnN1Yjk1Wy1pbmQubmE5NV0KICByLmZwLnN1Yjk1IDwtIHIuZnAuc3ViOTVbLWluZC5uYTk1XQogIHlJLnN1Yjk1IDwtIHlJLnN1Yjk1Wy1pbmQubmE5NV0KfQppZiAobGVuZ3RoKGluZC5uYTk5KT4wKXsKICByLmV2dC5zdWI5OSA8LSByLmV2dC5zdWI5OVstaW5kLm5hOTldCiAgci5lbXAuc3ViOTkgPC0gci5lbXAuc3ViOTlbLWluZC5uYTk5XQogIHIuZnAuc3ViOTkgPC0gci5mcC5zdWI5OVstaW5kLm5hOTldCiAgeUkuc3ViOTkgPC0geUkuc3ViOTlbLWluZC5uYTk5XQp9CgoKbTk1IDwtIGxlbmd0aCh5SS5zdWI5NSkgI3N1Yi1zYW1wbGUgc2l6ZSBmb3IgcT0wLjk1Cm05OSA8LSBsZW5ndGgoeUkuc3ViOTkpICNzdWItc2FtcGxlIHNpemUgZm9yIHE9MC45OQoKcm91bmQoYyhzdW0oeUkuc3ViOTU+ci5ldnQuc3ViOTUpL205NSoxMDAsc3VtKHlJLnN1Yjk1PnIuZW1wLnN1Yjk1KS9tOTUqMTAwLCBzdW0oeUkuc3ViOTU+ci5mcC5zdWI5NSkvbTk1KjEwMCwgc3VtKHlJLnN1Yjk5PnIuZXZ0LnN1Yjk5KS9tOTkqMTAwLCBzdW0oeUkuc3ViOTk+ci5lbXAuc3ViOTkpL205OSoxMDAsIHN1bSh5SS5zdWI5OT5yLmZwLnN1Yjk5KS9tOTkqMTAwKSwyKQpgYGAKCiMjIyMjIFRoZSBFVlQgbWV0aG9kIGRvZXMgbm90IHBlcmZvcm0gd2VsbCBmb3IgOTUlIENvVmFSIGVzdGltYXRpb24gYnV0IHJlbGF0aXZlbHkgZ29vZCBmb3IgOTklIENvVmFSIGVzdGltYXRpb24uIFNpbXBsZSBDQ1QgaXMgY29uc2lzdGVudCB3aXRoIHRoaXMgcmVzdWx0LCBidXQgY29tcGFyYXRpdmUgYmFja3Rlc3RpbmcgIGFuZCBUTE0gc3VnZ2VzdHMgdGhhdCBGUCBpcyBzbGlnaHRseSBiZXR0ZXIgdGhhbiBFVlQuICBJbiBzdW1tYXJ5LCBFVlQgYW5kIEZQIGlzIHNpZ25pZmljYW50bHkgYmV0dGVyIHRoYW4gZW1waXJpY2FsIG1ldGhvZCBhdCAxMCUgbGV2ZWwgZm9yIGVzdGltYXRpb24gOTklIENvVmFSLCBidXQgRVZUIGFuZCBGUCBhcmUgcXVpdGUgc2ltaWxhci4KCgpgYGB7cn0KY2N0IDwtIG1hdHJpeChucm93PTMsIG5jb2w9MikgIyBzaW1wbGUgJiBnZW5lcmFsIENDVAoKdG1wIDwtIGNjdC4ycy5WYVIoeD15SS5zdWI5NSwgcj1yLmV2dC5zdWI5NSxsZXY9MC45NSk7IGNjdFsxLF08LWModG1wJHB2LmF2Zyx0bXAkcHYuY29uZCkKdG1wIDwtIGNjdC4ycy5WYVIoeD15SS5zdWI5NSwgcj1yLmVtcC5zdWI5NSxsZXY9MC45NSk7IGNjdFsyLF08LWModG1wJHB2LmF2Zyx0bXAkcHYuY29uZCkKdG1wIDwtIGNjdC4ycy5WYVIoeD15SS5zdWI5NSwgcj1yLmZwLnN1Yjk1LGxldj0wLjk1KTsgY2N0WzMsXTwtYyh0bXAkcHYuYXZnLHRtcCRwdi5jb25kKQpyb3VuZChjY3QsMykKCiMgdG1wIDwtIGNjdC4ycy5WYVIoeD15SS5zdWI5OSwgcj1yLmV2dC5zdWI5OSxsZXY9MC45OSk7IGNjdFsxLF08LWModG1wJHB2LmF2Zyx0bXAkcHYuY29uZCkKIyB0bXAgPC0gY2N0LjJzLlZhUih4PXlJLnN1Yjk5LCByPXIuZW1wLnN1Yjk5LGxldj0wLjk5KTsgY2N0WzIsXTwtYyh0bXAkcHYuYXZnLHRtcCRwdi5jb25kKQojIHRtcCA8LSBjY3QuMnMuVmFSKHg9eUkuc3ViOTksIHI9ci5mcC5zdWI5OSxsZXY9MC45OSk7IGNjdFszLF08LWModG1wJHB2LmF2Zyx0bXAkcHYuY29uZCkKIyByb3VuZChjY3QsMykKCgojIyBPTkUtU0lERUQgVEVTVCBvZiBzdXBlci1jYWxpYnJhdGlvbiBhcyBpbiBCYXNlbCBBY2NvcmQKY2N0LjFzIDwtIG1hdHJpeChucm93PTMsIG5jb2w9MikgIyBzaW1wbGUgJiBnZW5lcmFsIG9uZS1zaWRlZCBDQ1Qgb2Ygc3VwZXItY2FsaWJyYXRpb24KdG1wIDwtIGNjdC4xcy5WYVIoeD15SS5zdWI5NSwgcj1yLmV2dC5zdWI5NSxsZXY9MC45NSk7IGNjdC4xc1sxLF08LWModG1wJHB2LmF2Zyx0bXAkcHYuY29uZCkKdG1wIDwtIGNjdC4xcy5WYVIoeD15SS5zdWI5NSwgcj1yLmVtcC5zdWI5NSxsZXY9MC45NSk7IGNjdC4xc1syLF08LWModG1wJHB2LmF2Zyx0bXAkcHYuY29uZCkKdG1wIDwtIGNjdC4xcy5WYVIoeD15SS5zdWI5NSwgcj1yLmZwLnN1Yjk1LGxldj0wLjk1KTsgY2N0LjFzWzMsXTwtYyh0bXAkcHYuYXZnLHRtcCRwdi5jb25kKQpyb3VuZChjY3QuMXMsMykKCmNjdC4xcyA8LSBtYXRyaXgobnJvdz0zLCBuY29sPTIpICMgc2ltcGxlICYgZ2VuZXJhbCBvbmUtc2lkZWQgQ0NUIG9mIHN1cGVyLWNhbGlicmF0aW9uCnRtcCA8LSBjY3QuMXMuVmFSKHg9eUkuc3ViOTksIHI9ci5ldnQuc3ViOTksbGV2PTAuOTkpOyBjY3QuMXNbMSxdPC1jKHRtcCRwdi5hdmcsdG1wJHB2LmNvbmQpCnRtcCA8LSBjY3QuMXMuVmFSKHg9eUkuc3ViOTksIHI9ci5lbXAuc3ViOTksbGV2PTAuOTkpOyBjY3QuMXNbMixdPC1jKHRtcCRwdi5hdmcsdG1wJHB2LmNvbmQpCnRtcCA8LSBjY3QuMXMuVmFSKHg9eUkuc3ViOTksIHI9ci5mcC5zdWI5OSxsZXY9MC45OSk7IGNjdC4xc1szLF08LWModG1wJHB2LmF2Zyx0bXAkcHYuY29uZCkKcm91bmQoY2N0LjFzLDMpCgojIyBDb21wYXJhdGl2ZSBiYWNrdGVzdGluZwojIyBxPS45NQpzbWF0IDwtIG1hdHJpeChucm93PTMsIG5jb2w9MSkKc21hdFsxLDFdIDwtIG1lYW4oc2ZWYVIocj1yLmV2dC5zdWI5NSx4PXlJLnN1Yjk1LGE9MC45NSxoPTEpKQpzbWF0WzIsMV0gPC0gbWVhbihzZlZhUihyPXIuZW1wLnN1Yjk1LHg9eUkuc3ViOTUsYT0wLjk1LGg9MSkpCnNtYXRbMywxXSA8LSBtZWFuKHNmVmFSKHI9ci5mcC5zdWI5NSx4PXlJLnN1Yjk1LGE9MC45NSxoPTEpKQphcHBseShzbWF0LDIsInJhbmsiKQoKIyMgcT0uOTkKc21hdCA8LSBtYXRyaXgobnJvdz0zLCBuY29sPTEpCnNtYXRbMSwxXSA8LSBtZWFuKHNmVmFSKHI9ci5ldnQuc3ViOTkseD15SS5zdWI5OSxhPTAuOTksaD0xKSkKc21hdFsyLDFdIDwtIG1lYW4oc2ZWYVIocj1yLmVtcC5zdWI5OSx4PXlJLnN1Yjk5LGE9MC45OSxoPTEpKQpzbWF0WzMsMV0gPC0gbWVhbihzZlZhUihyPXIuZnAuc3ViOTkseD15SS5zdWI5OSxhPTAuOTksaD0xKSkKYXBwbHkoc21hdCwyLCJyYW5rIikKCiMjIFRMTQpybT0xCnRsbTk1IDwtIFRMTWZuKHI9cmJpbmQoci5ldnQuc3ViOTUsci5lbXAuc3ViOTUsci5mcC5zdWI5NSksIHk9eUkuc3ViOTUsIHJtPXJtLCBsZXY9MC45NSxoPTEpCnBsb3RUTE0odGxtOTUkVExNMTAsIHJtPTEsIGxldj0wLjk1LG1ldGhvZD1jKCJldnQiLCJlbXAiLCJzdCIpKQoKdGxtOTkgPC0gVExNZm4ocj1yYmluZChyLmV2dC5zdWI5OSxyLmVtcC5zdWI5OSxyLmZwLnN1Yjk5KSwgeT15SS5zdWI5OSwgcm09cm0sIGxldj0wLjk5LGg9MSkKcGxvdFRMTSh0bG05OSRUTE0xMCwgcm09MSwgbGV2PTAuOTksbWV0aG9kPWMoImV2dCIsImVtcCIsInN0IikpCmBgYAoKCgojIyMgSW4tU2FtcGxlIFRlc3QKSG93ZXZlciwgd2UgY2FuIHNob3cgdGhhdCBtb3ZlbWVudCBpbiBDb1ZhUiBpcyBkcml2ZW4gYnkgdGhlIHByZWRpY3Qgc2lnbWFsIGZyb20gR2FyY2ggbW9kZWwsIGFuZCB0aGUgcHJlZGljdGVkIHNpZ21hbCBzaGFyZXMgdGhlIHNpbWlsYXIgcGF0dGVybiBvZiBsYWdnZWQgbG9zcyBzZXJpZXMuIFRoZSBmaWd1cmUgYmxvdyBwbG90cyBzdWJzYW1wbGUgd2l0aCAxMDAgZGF5cyBmb3IgU1A1MDAgbG9zcyBzZXJpZXMuIEFzIHNob3duIGluIHRoZSBmaWd1cmUsIHRoZSBwZWFrcyBvZiBzaWdtYV9TUDUwMCBhcmUgaW4gbGluZSB3aXRoIENvVmFSIGZyb20gRVZUIGFuZCBGUCwgYnV0IGFyZSBvbmUtcGVyaW9kIGhlYWQgb2YgbG9zcyBzZXJpZXMgKHNlZSB4LWF4aXMgODAtMTAwKS4gVGhpcyByZXN1bHQgY29tZXMgZnJvbSB0aGUgZmFjdCB0aGF0IHByZWRpY3RlZCBzaWdtYSBpcyBoZWF2aWx5IGFmZmVjdGVkIGJ5IHRoZSBtb3N0IHJlY2VudCBkYXRhLiBXaGVuIHRoZXJlIGlzIGEgaGlnaCByZXV0cm4gKG9yIGxvc3MpIHRvZGF5LCB0aGUgcHJlZGljdGVkIHZvbGF0aWxpdHkgd2lsbCBiZSB2ZXJ5IGhpZ2ggdG9tb3Jyb3cuCgpgYGB7ciBpbmNsdWRlPVRSVUUsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZz1GQUxTRX0KcGxvdChjb3Zhcls1ODAwOjU5MDAsMV0sIHR5cGUgPSAibCIsIGNvbCA9ICJibHVlIiwgeWxpbSA9ICBjKC0wLjEsMC4yKSwgbHR5ID0gMywgeWxhYiA9ICJSZXR1cm4iKQpwb2ludHMoY292YXJbNTgwMDo1OTAwLDVdLCB0eXBlID0gImwiLCBjb2wgPSAiYmxhY2siLCBsdHkgPSAxKQpwb2ludHMoeUlbNTgwMDo1OTAwXSwgdHlwZSA9ICJsIiwgY29sID0gInJlZCIsIGx0eSA9IDIpCnNldHdkKCJ+L09uZURyaXZlIC0gSU5TRUFEL1NrZXdFbGxpcHQvQ29kZV9VcGRhdGUvTmF0YWxpYS9vdXQ1MDAvIikKbG9hZCgib3V0U1A1MDAuUkRBVEEiKQpwb2ludHMob3V0LnAkc2lndC5zdFs1ODAwOjU5MDBdLCB0eXBlID0gImwiLCBjb2wgPSAnZ3JlZW4nLCBsdHkgPSA0KQpsZWdlbmQoInRvcHJpZ2h0IiwgbGVnZW5kID0gYygiRVZUIiwgIkZQIiwgIlNQNTAwIiwic2lnbWFfU1A1MDAiKSwgY29sID0gYygiYmx1ZSIsICJibGFjayIsICJyZWQiLCJncmVlbiIpLCBsdHkgPSBjKDMsMSwyLDQpKQpgYGAKClNpbWlsYXJseSwgaWYgd2UgcGxvdCBzdWJzYW1wbGUgaW4gd2hpY2ggRElTIGxvc3MgaXMgYmV5b25kIDk5JSBWYVIsIHRoZSBwZWFrcyBvZiBTUDAwIGFuZCBDb1ZhUiBmcm9tIGRpZmZlcmVudCBtZXRob2RzIGFyZSBub3QgYWxpZ25lZC4KYGBge3J9CnBsb3Qoci5mcC5zdWI5OSwgdHlwZSA9ICJsIiwgY29sID0gImJsdWUiLCB5bGltID0gIGMoLTAuMDMsMC4zKSwgbHR5ID0gMywgeWxhYiA9ICJSZXR1cm4iKQpwb2ludHMoeUkuc3ViOTksIHR5cGUgPSAibCIsIGNvbCA9ICJibGFjayIsIGx0eSA9IDEpCnBvaW50cyhyLmV2dC5zdWI5OSwgdHlwZSA9ICJsIiwgY29sID0gInJlZCIsIGx0eSA9IDIpCmxlZ2VuZCgidG9wcmlnaHQiLCBsZWdlbmQgPSBjKCJGUCIsICJFVlQiLCAiTG9zcyIpLCBjb2wgPSBjKCJibHVlIiwgInJlZCIsICJibGFjayIpLCBsdHkgPSBjKDMsMiwxKSkKYGBgCgoKSWYgd2Ugc2hpZnQgTG9zcyBzZXJpZXMgb25lLWRheSBhaGVhZCAob3Igc2hpZnQgQ29WYVIgb25lIGRheSBvbmUtZGF5IGJhY2t3YXJkKSwgdGhlbiB0aGUgcGVha3MgYXJlIGFsaWduZWQuIEVzc2VudGlhbGx5LCB0aGlzIGlzIGluLXNhbXBsZSBhbmFseXNpcy4gV2UgY29tcGFyZSBDb1ZhUiBlc3RpYW10ZWQgdXNpbmcgZGF5IDEgdG8gZGF5IDUwMCBkYXRhIHdpdGggZGF5IDUwMCBsb3NzLgoKYGBge3IsbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIyBpZGVudGlmeSBzdWJzYW1wbGUgd2hlcmUgTFt0KzFdXmogPiBWYVJbdCsxXV5qCm49ZGltKGNvdmFyLktPKVsxXQplbmQgPSBucm93KHIuS08pCgpsb3NzLkRJUyA8LSAtci5ESVMkclsoZW5kLW4pOihlbmQtMSldCnkgPC0gbG9zcy5ESVMKeUkgPC0gYXMudmVjdG9yKC1yU1BbKGVuZC1uKTooZW5kLTEpXSkKCnBsb3QoY292YXJbNTgwMDo1OTAwLDFdLCB0eXBlID0gImwiLCBjb2wgPSAiYmx1ZSIsIHlsaW0gPSAgYygtMC4xLDAuMiksIGx0eSA9IDMsIHlsYWIgPSAiUmV0dXJuIikKcG9pbnRzKGNvdmFyWzU4MDA6NTkwMCw1XSwgdHlwZSA9ICJsIiwgY29sID0gImJsYWNrIiwgbHR5ID0gMSkKcG9pbnRzKHlJWzU4MDA6NTkwMF0sIHR5cGUgPSAibCIsIGNvbCA9ICJyZWQiLCBsdHkgPSAyKQpzZXR3ZCgifi9PbmVEcml2ZSAtIElOU0VBRC9Ta2V3RWxsaXB0L0NvZGVfVXBkYXRlL05hdGFsaWEvb3V0NTAwLyIpCmxvYWQoIm91dFNQNTAwLlJEQVRBIikKcG9pbnRzKG91dC5wJHNpZ3Quc3RbNTgwMDo1OTAwXSwgdHlwZSA9ICJsIiwgY29sID0gJ2dyZWVuJywgbHR5ID0gNCkKbGVnZW5kKCJ0b3ByaWdodCIsIGxlZ2VuZCA9IGMoIkVWVCIsICJGUCIsICJTUDUwMCIsInNpZ21hX1NQNTAwIiksIGNvbCA9IGMoImJsdWUiLCAiYmxhY2siLCAicmVkIiwiZ3JlZW4iKSwgbHR5ID0gYygzLDEsMiw0KSkKYGBgCgoKTm93LCB3ZSByZXBlYXQgYWxsIHRoZSBhbmFseXNpcyBmb3IgaW4tc2FtcGxlIENvVmFSLgoKCmBgYHtyfQprPWRpbShybWF0KVsyXSAjIG51bWJlciBvZiBtZXRob2RzL2Nhc2VzCnltYXQgPSBtYXRyaXgocmVwKHksIGspLCBuY29sID0gaywgYnlyb3c9RkFMU0UpCmhtYXQgPSAoeW1hdCA+IHJtYXQpCgphcHBseShobWF0LDIsInN1bSIsbmEucm09VCkvbioxMDAKYGBgCgoKYGBge3J9CnIuZXZ0LnN1Yjk1IDwtIHN1YnNldChjb3ZhclssMV0saG1hdFssMV0pCnIuZXZ0LnN1Yjk5IDwtIHN1YnNldChjb3ZhclssMl0saG1hdFssMl0pCnIuZW1wLnN1Yjk1IDwtIHN1YnNldChjb3ZhclssM10saG1hdFssMV0pCnIuZW1wLnN1Yjk5IDwtIHN1YnNldChjb3ZhclssNF0saG1hdFssMl0pCnIuZnAuc3ViOTUgPC0gIHN1YnNldChjb3ZhclssNV0saG1hdFssMV0pCnIuZnAuc3ViOTkgPC0gIHN1YnNldChjb3ZhclssNl0saG1hdFssMl0pCgojIyBDaGVja2luZyAlIHZpb2xhdGlvbnMgb2YgQ29WYVIgYnkgdGhlIGluZGV4IGxvc3Nlcwp5SS5zdWI5NSA8LSBhcy5udW1lcmljKHN1YnNldCh5SSwgaG1hdFssMV0pKQp5SS5zdWI5OSA8LSBhcy5udW1lcmljKHN1YnNldCh5SSwgaG1hdFssMl0pKQoKIyBSZW1vdmUgTkEgdmFsdWVzCnIuc3ViOTUgPSByYmluZChyLmV2dC5zdWI5NSxyLmVtcC5zdWI5NSwgci5mcC5zdWI5NSkKaW5kLm5hOTUgPSB3aGljaCggKGlzLm5hKGFwcGx5KHIuc3ViOTUsMixzdW0pKSkgKQoKci5zdWI5OSA9IHJiaW5kKHIuZXZ0LnN1Yjk5LHIuZW1wLnN1Yjk5LCByLmZwLnN1Yjk5KQppbmQubmE5OSA9IHdoaWNoKChpcy5uYShhcHBseShyLnN1Yjk5LDIsc3VtKSkpICkKCmlmIChsZW5ndGgoaW5kLm5hOTUpPjApewogIHIuZXZ0LnN1Yjk1IDwtIHIuZXZ0LnN1Yjk1Wy1pbmQubmE5NV0KICByLmVtcC5zdWI5NSA8LSByLmVtcC5zdWI5NVstaW5kLm5hOTVdCiAgci5mcC5zdWI5NSA8LSByLmZwLnN1Yjk1Wy1pbmQubmE5NV0KICB5SS5zdWI5NSA8LSB5SS5zdWI5NVstaW5kLm5hOTVdCn0KaWYgKGxlbmd0aChpbmQubmE5OSk+MCl7CiAgci5ldnQuc3ViOTkgPC0gci5ldnQuc3ViOTlbLWluZC5uYTk5XQogIHIuZW1wLnN1Yjk5IDwtIHIuZW1wLnN1Yjk5Wy1pbmQubmE5OV0KICByLmZwLnN1Yjk5IDwtIHIuZnAuc3ViOTlbLWluZC5uYTk5XQogIHlJLnN1Yjk5IDwtIHlJLnN1Yjk5Wy1pbmQubmE5OV0KfQoKCm05NSA8LSBsZW5ndGgoeUkuc3ViOTUpICNzdWItc2FtcGxlIHNpemUgZm9yIHE9MC45NQptOTkgPC0gbGVuZ3RoKHlJLnN1Yjk5KSAjc3ViLXNhbXBsZSBzaXplIGZvciBxPTAuOTkKCnJvdW5kKGMoc3VtKHlJLnN1Yjk1PnIuZXZ0LnN1Yjk1KS9tOTUqMTAwLHN1bSh5SS5zdWI5NT5yLmVtcC5zdWI5NSkvbTk1KjEwMCwgc3VtKHlJLnN1Yjk1PnIuZnAuc3ViOTUpL205NSoxMDAsIHN1bSh5SS5zdWI5OT5yLmV2dC5zdWI5OSkvbTk5KjEwMCwgc3VtKHlJLnN1Yjk5PnIuZW1wLnN1Yjk5KS9tOTkqMTAwLCBzdW0oeUkuc3ViOTk+ci5mcC5zdWI5OSkvbTk5KjEwMCksMikKYGBgCgojIyMjIEZyb20gYWJvdmUgbnVtYmVycywgRVZUIGxvb2tzIHdvcmsgcXVpdGUgd2VsbCBmb3IgaW4tc2FtcGxlIGFuYWx5c2lzLiBIb3dldmVyLCBjb21wYXJhdGl2ZSBiYWNrdGVzdGluZyBhbmQgVExNIHNlZW0gdG8gc3VnZ2VzdCB0aGF0IEVWVCBpcyB3b3JzZSB0aGFuIGVtcGlyaWNhbCBtZXRob2QuIEkgZG8gbm90IHVuZGVyc3RhbmQgd2h5IHdlIGdldCBkaWZmZXJlbnQgcmVzdXRscyBmcm9tIGRpZmZlcmVudCB0ZXN0cy4gCgpgYGB7cn0KY2N0IDwtIG1hdHJpeChucm93PTMsIG5jb2w9MikgIyBzaW1wbGUgJiBnZW5lcmFsIENDVAoKdG1wIDwtIGNjdC4ycy5WYVIoeD15SS5zdWI5NSwgcj1yLmV2dC5zdWI5NSxsZXY9MC45NSk7IGNjdFsxLF08LWModG1wJHB2LmF2Zyx0bXAkcHYuY29uZCkKdG1wIDwtIGNjdC4ycy5WYVIoeD15SS5zdWI5NSwgcj1yLmVtcC5zdWI5NSxsZXY9MC45NSk7IGNjdFsyLF08LWModG1wJHB2LmF2Zyx0bXAkcHYuY29uZCkKdG1wIDwtIGNjdC4ycy5WYVIoeD15SS5zdWI5NSwgcj1yLmZwLnN1Yjk1LGxldj0wLjk1KTsgY2N0WzMsXTwtYyh0bXAkcHYuYXZnLHRtcCRwdi5jb25kKQpyb3VuZChjY3QsMykKCiMgdG1wIDwtIGNjdC4ycy5WYVIoeD15SS5zdWI5OSwgcj1yLmV2dC5zdWI5OSxsZXY9MC45OSk7IGNjdFsxLF08LWModG1wJHB2LmF2Zyx0bXAkcHYuY29uZCkKIyB0bXAgPC0gY2N0LjJzLlZhUih4PXlJLnN1Yjk5LCByPXIuZW1wLnN1Yjk5LGxldj0wLjk5KTsgY2N0WzIsXTwtYyh0bXAkcHYuYXZnLHRtcCRwdi5jb25kKQojIHRtcCA8LSBjY3QuMnMuVmFSKHg9eUkuc3ViOTksIHI9ci5mcC5zdWI5OSxsZXY9MC45OSk7IGNjdFszLF08LWModG1wJHB2LmF2Zyx0bXAkcHYuY29uZCkKIyByb3VuZChjY3QsMykKCgojIyBPTkUtU0lERUQgVEVTVCBvZiBzdXBlci1jYWxpYnJhdGlvbiBhcyBpbiBCYXNlbCBBY2NvcmQKY2N0LjFzIDwtIG1hdHJpeChucm93PTMsIG5jb2w9MikgIyBzaW1wbGUgJiBnZW5lcmFsIG9uZS1zaWRlZCBDQ1Qgb2Ygc3VwZXItY2FsaWJyYXRpb24KdG1wIDwtIGNjdC4xcy5WYVIoeD15SS5zdWI5NSwgcj1yLmV2dC5zdWI5NSxsZXY9MC45NSk7IGNjdC4xc1sxLF08LWModG1wJHB2LmF2Zyx0bXAkcHYuY29uZCkKdG1wIDwtIGNjdC4xcy5WYVIoeD15SS5zdWI5NSwgcj1yLmVtcC5zdWI5NSxsZXY9MC45NSk7IGNjdC4xc1syLF08LWModG1wJHB2LmF2Zyx0bXAkcHYuY29uZCkKdG1wIDwtIGNjdC4xcy5WYVIoeD15SS5zdWI5NSwgcj1yLmZwLnN1Yjk1LGxldj0wLjk1KTsgY2N0LjFzWzMsXTwtYyh0bXAkcHYuYXZnLHRtcCRwdi5jb25kKQpyb3VuZChjY3QuMXMsMykKCmNjdC4xcyA8LSBtYXRyaXgobnJvdz0zLCBuY29sPTIpICMgc2ltcGxlICYgZ2VuZXJhbCBvbmUtc2lkZWQgQ0NUIG9mIHN1cGVyLWNhbGlicmF0aW9uCnRtcCA8LSBjY3QuMXMuVmFSKHg9eUkuc3ViOTksIHI9ci5ldnQuc3ViOTksbGV2PTAuOTkpOyBjY3QuMXNbMSxdPC1jKHRtcCRwdi5hdmcsdG1wJHB2LmNvbmQpCnRtcCA8LSBjY3QuMXMuVmFSKHg9eUkuc3ViOTksIHI9ci5lbXAuc3ViOTksbGV2PTAuOTkpOyBjY3QuMXNbMixdPC1jKHRtcCRwdi5hdmcsdG1wJHB2LmNvbmQpCnRtcCA8LSBjY3QuMXMuVmFSKHg9eUkuc3ViOTksIHI9ci5mcC5zdWI5OSxsZXY9MC45OSk7IGNjdC4xc1szLF08LWModG1wJHB2LmF2Zyx0bXAkcHYuY29uZCkKcm91bmQoY2N0LjFzLDMpCgojIyBDb21wYXJhdGl2ZSBiYWNrdGVzdGluZwojIyBxPS45NQpzbWF0IDwtIG1hdHJpeChucm93PTMsIG5jb2w9MSkKc21hdFsxLDFdIDwtIG1lYW4oc2ZWYVIocj1yLmV2dC5zdWI5NSx4PXlJLnN1Yjk1LGE9MC45NSxoPTEpKQpzbWF0WzIsMV0gPC0gbWVhbihzZlZhUihyPXIuZW1wLnN1Yjk1LHg9eUkuc3ViOTUsYT0wLjk1LGg9MSkpCnNtYXRbMywxXSA8LSBtZWFuKHNmVmFSKHI9ci5mcC5zdWI5NSx4PXlJLnN1Yjk1LGE9MC45NSxoPTEpKQphcHBseShzbWF0LDIsInJhbmsiKQoKIyMgcT0uOTkKc21hdCA8LSBtYXRyaXgobnJvdz0zLCBuY29sPTEpCnNtYXRbMSwxXSA8LSBtZWFuKHNmVmFSKHI9ci5ldnQuc3ViOTkseD15SS5zdWI5OSxhPTAuOTksaD0xKSkKc21hdFsyLDFdIDwtIG1lYW4oc2ZWYVIocj1yLmVtcC5zdWI5OSx4PXlJLnN1Yjk5LGE9MC45OSxoPTEpKQpzbWF0WzMsMV0gPC0gbWVhbihzZlZhUihyPXIuZnAuc3ViOTkseD15SS5zdWI5OSxhPTAuOTksaD0xKSkKYXBwbHkoc21hdCwyLCJyYW5rIikKCiMjIFRMTQpybT0xCnRsbTk1IDwtIFRMTWZuKHI9cmJpbmQoci5ldnQuc3ViOTUsci5lbXAuc3ViOTUsci5mcC5zdWI5NSksIHk9eUkuc3ViOTUsIHJtPXJtLCBsZXY9MC45NSxoPTEpCnBsb3RUTE0odGxtOTUkVExNMTAsIHJtPTEsIGxldj0wLjk1LG1ldGhvZD1jKCJldnQiLCJlbXAiLCJzdCIpKQoKdGxtOTkgPC0gVExNZm4ocj1yYmluZChyLmV2dC5zdWI5OSxyLmVtcC5zdWI5OSxyLmZwLnN1Yjk5KSwgeT15SS5zdWI5OSwgcm09cm0sIGxldj0wLjk5LGg9MSkKcGxvdFRMTSh0bG05OSRUTE0xMCwgcm09MSwgbGV2PTAuOTksbWV0aG9kPWMoImV2dCIsImVtcCIsInN0IikpCmBgYAoKYGBge3J9CnBsb3Qoci5mcC5zdWI5OSwgdHlwZSA9ICJsIiwgY29sID0gImJsdWUiLCB5bGltID0gIGMoLTAuMDMsMC40KSwgbHR5ID0gMywgeWxhYiA9ICJSZXR1cm4iKQpwb2ludHMoeUkuc3ViOTksIHR5cGUgPSAibCIsIGNvbCA9ICJibGFjayIsIGx0eSA9IDEpCnBvaW50cyhyLmV2dC5zdWI5OSwgdHlwZSA9ICJsIiwgY29sID0gInJlZCIsIGx0eSA9IDIpCmxlZ2VuZCgidG9wcmlnaHQiLCBsZWdlbmQgPSBjKCJGUCIsICJFVlQiLCAiTG9zcyIpLCBjb2wgPSBjKCJibHVlIiwgInJlZCIsICJibGFjayIpLCBsdHkgPSBjKDMsMiwxKSkKYGBgCgpgYGB7cn0KcGxvdCh5SSwgeWxhYj0iIiwgeWxpbT1jKC0uMTIsMC40KSwgY29sPSJncmF5Iix4bGFiPSIiLCBtYWluPSJESVMiLCBjZXgubWFpbj0wLjgsIGx0eSA9IDEpCmxpbmVzKHRpbWUoeUkpLGNvdmFyLkRJU1ssMV0sIGNvbD0icmVkIiwgbHR5ID0gMikKbGluZXModGltZSh5SSksY292YXIuRElTWyw1XSwgY29sPSJibGFjayIsIGx0eSA9IDMpCmxpbmVzKHRpbWUoeUkpLGNvdmFyLkRJU1ssM10sIGNvbD0iZ3JlZW4iLCBsdHkgPSA0KQpsZWdlbmQoInRvcGxlZnQiLCBsZWdlbmQgPSBjKCJTUDUwMCIsICJFVlQiLCAiRlAiLCAiSFMiKSwgY29sID0gYygiZ3JleSIsICJyZWQiLCAiYmxhY2siLCAiZ3JlZW4iKSwgbHR5ID0gYygxLDIsMyw0KSkKYGBgCgo=