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.KO
rmat <- var.KO
covar <- covar.KO
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.409652 1.174710
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] 11.41 11.27 5.99 2.63 20.39 5.92
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.269 0.091
# 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.135 0.404
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.106 0.317
[2,] 0.000 0.000
[3,] 0.006 0.018
## 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,] 1
[3,] 2
## 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 KO 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.KO <- -r.KO$r[(end-n):(end-1)]
y <- loss.KO
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] 4.0478863 0.5312383
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.80 3.07 2.88 0.00 4.48 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.830 0.119
[2,] 0.011 0.029
[3,] 0.004 0.010
# 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.585 1
[2,] 0.994 1
[3,] 0.998 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.000 1.000
[2,] 0.087 0.262
[3,] 1.000 1.000
## 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="KO", cex.main=0.8, lty = 1)
lines(time(yI),covar.KO[,1], col="red", lty = 2)
lines(time(yI),covar.KO[,5], col="black", lty = 3)
lines(time(yI),covar.KO[,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))

LS0tCnRpdGxlOiAiQ29WYVIgLS0gS08iCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMjIyBQcmVwYXJlIERhdGE6CgpgYGB7ciBpbmNsdWRlPVRSVUUsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZz1GQUxTRX0Kcm0obGlzdCA9IGxzKCkpCmxpYnJhcnkoInJ1Z2FyY2giKQpsaWJyYXJ5KCJmR2FyY2giKQpsaWJyYXJ5KCJNQVNTIikKbGlicmFyeSgiaXNtZXYiKQojIGxpYnJhcnkoImxtb20iKQojIGxpYnJhcnkoIlFSTSIpCmxpYnJhcnkoInNrZXd0IikKbGlicmFyeSgiem9vIikKbGlicmFyeSgicGxvdHJpeCIpCgpzb3VyY2UoIn4vT25lRHJpdmUgLSBJTlNFQUQvU2tld0VsbGlwdC9Db2RlX1VwZGF0ZS9SZm5zLlIiKQpzZXR3ZCgifi9PbmVEcml2ZSAtIElOU0VBRC9Ta2V3RWxsaXB0L0NvZGVfVXBkYXRlL05hdGFsaWEvb3V0NTAwLyIpCiMjPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMjIEJhY2t0ZXN0aW5nIENvVmFSCiMjPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CgpkYXQgPSBmcmVhZCgifi9PbmVEcml2ZSAtIElOU0VBRC9Ta2V3RWxsaXB0L0NvZGVfVXBkYXRlL05hdGFsaWEvUmV0X2RhdGEuY3N2IikgIyByYXcgZGF0YSBmaWxlICgxOTYyLzA3LzAyIC0gMjAxNy8wNy8zMSkKZGF0ID0gZGF0WyxgOj1gKFJFVD1hcy5udW1lcmljKGFzLmNoYXJhY3RlcihSRVQpKSwgU1A1MDAgPSBhcy5udW1lcmljKGFzLmNoYXJhY3RlcihTUDUwMCkpKV0KZGF0ID0gZGF0WyFpcy5uYShSRVQpXQpkYXQgPSB1bmlxdWUoZGF0LCBieSA9IGMoIlRJQ0tFUiIsICJkYXRlIikgKQpzZXRuYW1lcyhkYXQsICJSRVQiLCAiciIpCnIuS08gPSBkYXRbVElDS0VSID09ICdLTycsIGxpc3QoZGF0ZSwgVElDS0VSLCByLCBTUDUwMCldCnIuR0UgPSBkYXRbVElDS0VSID09ICdHRScsIGxpc3QoZGF0ZSwgVElDS0VSLCByLCBTUDUwMCldCnIuQkEgPSBkYXRbVElDS0VSID09ICdCQScsIGxpc3QoZGF0ZSwgVElDS0VSLCByLCBTUDUwMCldCnIuRElTID0gZGF0W1RJQ0tFUiA9PSAnRElTJywgbGlzdChkYXRlLCBUSUNLRVIsIHIsIFNQNTAwKV0KCmRhdC5pbmRpY2VzIDwtIHVuaXF1ZShkYXRhLmZyYW1lKGRhdCRkYXRlLGRhdCRSZXRfTSxkYXQkU1A1MDApKQpjb2xuYW1lcyhkYXQuaW5kaWNlcyk8LWMoImRhdGUiLCJyZXRNIiwic3A1MDAiKQpyTSA8LSB6b28oeD1kYXQuaW5kaWNlcyRyZXRNLG9yZGVyLmJ5ID0gc3RycHRpbWUoZGF0LmluZGljZXMkZGF0ZSwiJVklbSVkIikpCnJTUDwtIHpvbyh4PWRhdC5pbmRpY2VzJHNwNTAwLG9yZGVyLmJ5ID0gc3RycHRpbWUoZGF0LmluZGljZXMkZGF0ZSwiJVklbSVkIikpCgpsb2FkKCJDb1ZhUi5SREFUQSIpCiMgYXR0cmlidXRlcyhvdXQpCgojI2NvbHVtbnMgYXJlIDk1JSBDb1ZhUiBieSBFVlQgbWV0aG9kLCA5OSUgQ29WYVIgYnkgRVZUIG1ldGhvZCBhbmQgOTUlIENvVmFSIGJ5IGVtcGlyaWNhbCBtZXRob2QKCmNvdmFyLktPIDwtIG91dCRDb1ZhUi5LTwpjb3Zhci5CQSA8LSBvdXQkQ29WYVIuQkEKY292YXIuRElTIDwtIG91dCRDb1ZhUi5ESVMKY292YXIuR0UgPC0gb3V0JENvVmFSLkdFCmBgYAoKCiMjIyBPdXQtb2Ytc2FtcGxlIFRlc3QKV2UgY2FsY3VhbHRlIG9uZS1kYXkgYWhlYWQgcHJlZGljdGVkIFZhUiBhbmQgQ29WYVIgdXNpbmcgcGFzdCA1MDAgZGF5cyAocm9sbG9pbmcgd2luZG93KSBhbmQgdGhlbiBtYXRjaCB3aXRoIGxvc3Mgc2VyaWVzLiBTcGVjaWZpY2FsbHksIHdlIHVzZSBkYXRhIGZyb20gZGF5IDEgdG8gNTAwIHRvIGZpdCBHYXJjaCBtb2RlbCBhbmQgZ2V0IHJlc2lkdWFsIHNlcmllcyBhbmQgcHJlZGljdGVkIG11IGFuZCBzaWdtYWwuIFRoZW4gd2UgY2FsY3VsYXRlIG9uZS1kYXkgYWhlYWQgcHJlZGljdGVkIFZhUiBhbmQgQ29WYVIsIHRoYXQgaXMgZGF5IDUwMSBWYVIgYW5kIENvVmFSLgoKCmBgYHtyLG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZz1GQUxTRX0KIyMgaWRlbnRpZnkgc3Vic2FtcGxlIHdoZXJlIExbdCsxXV5qID4gVmFSW3QrMV1eagpuPWRpbShjb3Zhci5LTylbMV0KZW5kID0gbnJvdyhyLktPKSArIDEKc2V0d2QoIn4vT25lRHJpdmUgLSBJTlNFQUQvU2tld0VsbGlwdC9Db2RlX1VwZGF0ZS9OYXRhbGlhL291dDUwMC8iKQpsb2FkKCJvdXRLTy5SREFUQSIpCnZhci5LTyA8LSBvdXQucCRzdEVWVFssMjozXQpsb3NzLktPIDwtIC1yLktPJHJbKGVuZC1uKTooZW5kLTEpXQoKbG9hZCgib3V0QkEuUkRBVEEiKQp2YXIuQkEgPC0gb3V0LnAkc3RFVlRbLDI6M10KbG9zcy5CQSA8LSAtci5CQSRyWyhlbmQtbik6KGVuZC0xKV0KCmxvYWQoIm91dERJUy5SREFUQSIpCnZhci5ESVMgPC0gb3V0LnAkc3RFVlRbLDI6M10KbG9zcy5ESVMgPC0gLXIuRElTJHJbKGVuZC1uKTooZW5kLTEpXQoKbG9hZCgib3V0R0UuUkRBVEEiKQp2YXIuR0UgPC0gb3V0LnAkc3RFVlRbLDI6M10KbG9zcy5HRSA8LSAtci5HRSRyWyhlbmQtbik6KGVuZC0xKV0KYGBgCgpgYGB7cn0KeSA8LSBsb3NzLktPCnJtYXQgPC0gdmFyLktPCmNvdmFyIDwtIGNvdmFyLktPCnlJIDwtIGFzLnZlY3RvcigtclNQWyhlbmQtbik6KGVuZC0xKV0pCmBgYAoKV2UgY2hlY2sgdGhlIHBlcmZvcm1hbmNlIG9mIHByZWRpY3RlZCBWYVI6CmBgYHtyfQprPWRpbShybWF0KVsyXSAjIG51bWJlciBvZiBtZXRob2RzL2Nhc2VzCnltYXQgPSBtYXRyaXgocmVwKHksIGspLCBuY29sID0gaywgYnlyb3c9RkFMU0UpCmhtYXQgPSAoeW1hdCA+IHJtYXQpCgphcHBseShobWF0LDIsInN1bSIsbmEucm09VCkvbioxMDAKYGBgCgpXZSBjaGVjayB0aGUgcGVyZm9ybWFuY2Ugb2YgcHJlZGljdGVkIENvVmFSOgpgYGB7cn0Kci5ldnQuc3ViOTUgPC0gc3Vic2V0KGNvdmFyWywxXSxobWF0WywxXSkKci5ldnQuc3ViOTkgPC0gc3Vic2V0KGNvdmFyWywyXSxobWF0WywyXSkKci5lbXAuc3ViOTUgPC0gc3Vic2V0KGNvdmFyWywzXSxobWF0WywxXSkKci5lbXAuc3ViOTkgPC0gc3Vic2V0KGNvdmFyWyw0XSxobWF0WywyXSkKci5mcC5zdWI5NSA8LSAgc3Vic2V0KGNvdmFyWyw1XSxobWF0WywxXSkKci5mcC5zdWI5OSA8LSAgc3Vic2V0KGNvdmFyWyw2XSxobWF0WywyXSkKCiMjIENoZWNraW5nICUgdmlvbGF0aW9ucyBvZiBDb1ZhUiBieSB0aGUgaW5kZXggbG9zc2VzCnlJLnN1Yjk1IDwtIGFzLm51bWVyaWMoc3Vic2V0KHlJLCBobWF0WywxXSkpCnlJLnN1Yjk5IDwtIGFzLm51bWVyaWMoc3Vic2V0KHlJLCBobWF0WywyXSkpCgojIFJlbW92ZSBOQSB2YWx1ZXMKci5zdWI5NSA9IHJiaW5kKHIuZXZ0LnN1Yjk1LHIuZW1wLnN1Yjk1LCByLmZwLnN1Yjk1KQppbmQubmE5NSA9IHdoaWNoKCAoaXMubmEoYXBwbHkoci5zdWI5NSwyLHN1bSkpKSApCgpyLnN1Yjk5ID0gcmJpbmQoci5ldnQuc3ViOTksci5lbXAuc3ViOTksIHIuZnAuc3ViOTkpCmluZC5uYTk5ID0gd2hpY2goKGlzLm5hKGFwcGx5KHIuc3ViOTksMixzdW0pKSkgKQoKaWYgKGxlbmd0aChpbmQubmE5NSk+MCl7CiAgci5ldnQuc3ViOTUgPC0gci5ldnQuc3ViOTVbLWluZC5uYTk1XQogIHIuZW1wLnN1Yjk1IDwtIHIuZW1wLnN1Yjk1Wy1pbmQubmE5NV0KICByLmZwLnN1Yjk1IDwtIHIuZnAuc3ViOTVbLWluZC5uYTk1XQogIHlJLnN1Yjk1IDwtIHlJLnN1Yjk1Wy1pbmQubmE5NV0KfQppZiAobGVuZ3RoKGluZC5uYTk5KT4wKXsKICByLmV2dC5zdWI5OSA8LSByLmV2dC5zdWI5OVstaW5kLm5hOTldCiAgci5lbXAuc3ViOTkgPC0gci5lbXAuc3ViOTlbLWluZC5uYTk5XQogIHIuZnAuc3ViOTkgPC0gci5mcC5zdWI5OVstaW5kLm5hOTldCiAgeUkuc3ViOTkgPC0geUkuc3ViOTlbLWluZC5uYTk5XQp9CgoKbTk1IDwtIGxlbmd0aCh5SS5zdWI5NSkgI3N1Yi1zYW1wbGUgc2l6ZSBmb3IgcT0wLjk1Cm05OSA8LSBsZW5ndGgoeUkuc3ViOTkpICNzdWItc2FtcGxlIHNpemUgZm9yIHE9MC45OQoKcm91bmQoYyhzdW0oeUkuc3ViOTU+ci5ldnQuc3ViOTUpL205NSoxMDAsc3VtKHlJLnN1Yjk1PnIuZW1wLnN1Yjk1KS9tOTUqMTAwLCBzdW0oeUkuc3ViOTU+ci5mcC5zdWI5NSkvbTk1KjEwMCwgc3VtKHlJLnN1Yjk5PnIuZXZ0LnN1Yjk5KS9tOTkqMTAwLCBzdW0oeUkuc3ViOTk+ci5lbXAuc3ViOTkpL205OSoxMDAsIHN1bSh5SS5zdWI5OT5yLmZwLnN1Yjk5KS9tOTkqMTAwKSwyKQpgYGAKCiMjIyMjIFRoZSBFVlQgbWV0aG9kIGRvZXMgbm90IHBlcmZvcm0gd2VsbCBmb3IgOTUlIENvVmFSIGVzdGltYXRpb24gYnV0IHJlbGF0aXZlbHkgZ29vZCBmb3IgOTklIENvVmFSIGVzdGltYXRpb24uIFNpbXBsZSBDQ1QgaXMgY29uc2lzdGVudCB3aXRoIHRoaXMgcmVzdWx0LCBidXQgY29tcGFyYXRpdmUgYmFja3Rlc3RpbmcgIGFuZCBUTE0gc3VnZ2VzdHMgdGhhdCBGUCBpcyBzbGlnaHRseSBiZXR0ZXIgdGhhbiBFVlQuICBJbiBzdW1tYXJ5LCBFVlQgYW5kIEZQIGlzIHNpZ25pZmljYW50bHkgYmV0dGVyIHRoYW4gZW1waXJpY2FsIG1ldGhvZCBhdCAxMCUgbGV2ZWwgZm9yIGVzdGltYXRpb24gOTklIENvVmFSLCBidXQgRVZUIGFuZCBGUCBhcmUgcXVpdGUgc2ltaWxhci4KCgpgYGB7cn0KY2N0IDwtIG1hdHJpeChucm93PTMsIG5jb2w9MikgIyBzaW1wbGUgJiBnZW5lcmFsIENDVAoKdG1wIDwtIGNjdC4ycy5WYVIoeD15SS5zdWI5NSwgcj1yLmV2dC5zdWI5NSxsZXY9MC45NSk7IGNjdFsxLF08LWModG1wJHB2LmF2Zyx0bXAkcHYuY29uZCkKdG1wIDwtIGNjdC4ycy5WYVIoeD15SS5zdWI5NSwgcj1yLmVtcC5zdWI5NSxsZXY9MC45NSk7IGNjdFsyLF08LWModG1wJHB2LmF2Zyx0bXAkcHYuY29uZCkKdG1wIDwtIGNjdC4ycy5WYVIoeD15SS5zdWI5NSwgcj1yLmZwLnN1Yjk1LGxldj0wLjk1KTsgY2N0WzMsXTwtYyh0bXAkcHYuYXZnLHRtcCRwdi5jb25kKQpyb3VuZChjY3QsMykKCiMgdG1wIDwtIGNjdC4ycy5WYVIoeD15SS5zdWI5OSwgcj1yLmV2dC5zdWI5OSxsZXY9MC45OSk7IGNjdFsxLF08LWModG1wJHB2LmF2Zyx0bXAkcHYuY29uZCkKIyB0bXAgPC0gY2N0LjJzLlZhUih4PXlJLnN1Yjk5LCByPXIuZW1wLnN1Yjk5LGxldj0wLjk5KTsgY2N0WzIsXTwtYyh0bXAkcHYuYXZnLHRtcCRwdi5jb25kKQojIHRtcCA8LSBjY3QuMnMuVmFSKHg9eUkuc3ViOTksIHI9ci5mcC5zdWI5OSxsZXY9MC45OSk7IGNjdFszLF08LWModG1wJHB2LmF2Zyx0bXAkcHYuY29uZCkKIyByb3VuZChjY3QsMykKCgojIyBPTkUtU0lERUQgVEVTVCBvZiBzdXBlci1jYWxpYnJhdGlvbiBhcyBpbiBCYXNlbCBBY2NvcmQKY2N0LjFzIDwtIG1hdHJpeChucm93PTMsIG5jb2w9MikgIyBzaW1wbGUgJiBnZW5lcmFsIG9uZS1zaWRlZCBDQ1Qgb2Ygc3VwZXItY2FsaWJyYXRpb24KdG1wIDwtIGNjdC4xcy5WYVIoeD15SS5zdWI5NSwgcj1yLmV2dC5zdWI5NSxsZXY9MC45NSk7IGNjdC4xc1sxLF08LWModG1wJHB2LmF2Zyx0bXAkcHYuY29uZCkKdG1wIDwtIGNjdC4xcy5WYVIoeD15SS5zdWI5NSwgcj1yLmVtcC5zdWI5NSxsZXY9MC45NSk7IGNjdC4xc1syLF08LWModG1wJHB2LmF2Zyx0bXAkcHYuY29uZCkKdG1wIDwtIGNjdC4xcy5WYVIoeD15SS5zdWI5NSwgcj1yLmZwLnN1Yjk1LGxldj0wLjk1KTsgY2N0LjFzWzMsXTwtYyh0bXAkcHYuYXZnLHRtcCRwdi5jb25kKQpyb3VuZChjY3QuMXMsMykKCmNjdC4xcyA8LSBtYXRyaXgobnJvdz0zLCBuY29sPTIpICMgc2ltcGxlICYgZ2VuZXJhbCBvbmUtc2lkZWQgQ0NUIG9mIHN1cGVyLWNhbGlicmF0aW9uCnRtcCA8LSBjY3QuMXMuVmFSKHg9eUkuc3ViOTksIHI9ci5ldnQuc3ViOTksbGV2PTAuOTkpOyBjY3QuMXNbMSxdPC1jKHRtcCRwdi5hdmcsdG1wJHB2LmNvbmQpCnRtcCA8LSBjY3QuMXMuVmFSKHg9eUkuc3ViOTksIHI9ci5lbXAuc3ViOTksbGV2PTAuOTkpOyBjY3QuMXNbMixdPC1jKHRtcCRwdi5hdmcsdG1wJHB2LmNvbmQpCnRtcCA8LSBjY3QuMXMuVmFSKHg9eUkuc3ViOTksIHI9ci5mcC5zdWI5OSxsZXY9MC45OSk7IGNjdC4xc1szLF08LWModG1wJHB2LmF2Zyx0bXAkcHYuY29uZCkKcm91bmQoY2N0LjFzLDMpCgojIyBDb21wYXJhdGl2ZSBiYWNrdGVzdGluZwojIyBxPS45NQpzbWF0IDwtIG1hdHJpeChucm93PTMsIG5jb2w9MSkKc21hdFsxLDFdIDwtIG1lYW4oc2ZWYVIocj1yLmV2dC5zdWI5NSx4PXlJLnN1Yjk1LGE9MC45NSxoPTEpKQpzbWF0WzIsMV0gPC0gbWVhbihzZlZhUihyPXIuZW1wLnN1Yjk1LHg9eUkuc3ViOTUsYT0wLjk1LGg9MSkpCnNtYXRbMywxXSA8LSBtZWFuKHNmVmFSKHI9ci5mcC5zdWI5NSx4PXlJLnN1Yjk1LGE9MC45NSxoPTEpKQphcHBseShzbWF0LDIsInJhbmsiKQoKIyMgcT0uOTkKc21hdCA8LSBtYXRyaXgobnJvdz0zLCBuY29sPTEpCnNtYXRbMSwxXSA8LSBtZWFuKHNmVmFSKHI9ci5ldnQuc3ViOTkseD15SS5zdWI5OSxhPTAuOTksaD0xKSkKc21hdFsyLDFdIDwtIG1lYW4oc2ZWYVIocj1yLmVtcC5zdWI5OSx4PXlJLnN1Yjk5LGE9MC45OSxoPTEpKQpzbWF0WzMsMV0gPC0gbWVhbihzZlZhUihyPXIuZnAuc3ViOTkseD15SS5zdWI5OSxhPTAuOTksaD0xKSkKYXBwbHkoc21hdCwyLCJyYW5rIikKCiMjIFRMTQpybT0xCnRsbTk1IDwtIFRMTWZuKHI9cmJpbmQoci5ldnQuc3ViOTUsci5lbXAuc3ViOTUsci5mcC5zdWI5NSksIHk9eUkuc3ViOTUsIHJtPXJtLCBsZXY9MC45NSxoPTEpCnBsb3RUTE0odGxtOTUkVExNMTAsIHJtPTEsIGxldj0wLjk1LG1ldGhvZD1jKCJldnQiLCJlbXAiLCJzdCIpKQoKdGxtOTkgPC0gVExNZm4ocj1yYmluZChyLmV2dC5zdWI5OSxyLmVtcC5zdWI5OSxyLmZwLnN1Yjk5KSwgeT15SS5zdWI5OSwgcm09cm0sIGxldj0wLjk5LGg9MSkKcGxvdFRMTSh0bG05OSRUTE0xMCwgcm09MSwgbGV2PTAuOTksbWV0aG9kPWMoImV2dCIsImVtcCIsInN0IikpCmBgYAoKCgojIyMgSW4tU2FtcGxlIFRlc3QKSG93ZXZlciwgd2UgY2FuIHNob3cgdGhhdCBtb3ZlbWVudCBpbiBDb1ZhUiBpcyBkcml2ZW4gYnkgdGhlIHByZWRpY3Qgc2lnbWFsIGZyb20gR2FyY2ggbW9kZWwsIGFuZCB0aGUgcHJlZGljdGVkIHNpZ21hbCBzaGFyZXMgdGhlIHNpbWlsYXIgcGF0dGVybiBvZiBsYWdnZWQgbG9zcyBzZXJpZXMuIFRoZSBmaWd1cmUgYmxvdyBwbG90cyBzdWJzYW1wbGUgd2l0aCAxMDAgZGF5cyBmb3IgU1A1MDAgbG9zcyBzZXJpZXMuIEFzIHNob3duIGluIHRoZSBmaWd1cmUsIHRoZSBwZWFrcyBvZiBzaWdtYV9TUDUwMCBhcmUgaW4gbGluZSB3aXRoIENvVmFSIGZyb20gRVZUIGFuZCBGUCwgYnV0IGFyZSBvbmUtcGVyaW9kIGhlYWQgb2YgbG9zcyBzZXJpZXMgKHNlZSB4LWF4aXMgODAtMTAwKS4gVGhpcyByZXN1bHQgY29tZXMgZnJvbSB0aGUgZmFjdCB0aGF0IHByZWRpY3RlZCBzaWdtYSBpcyBoZWF2aWx5IGFmZmVjdGVkIGJ5IHRoZSBtb3N0IHJlY2VudCBkYXRhLiBXaGVuIHRoZXJlIGlzIGEgaGlnaCByZXV0cm4gKG9yIGxvc3MpIHRvZGF5LCB0aGUgcHJlZGljdGVkIHZvbGF0aWxpdHkgd2lsbCBiZSB2ZXJ5IGhpZ2ggdG9tb3Jyb3cuCgpgYGB7ciBpbmNsdWRlPVRSVUUsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZz1GQUxTRX0KcGxvdChjb3Zhcls1ODAwOjU5MDAsMV0sIHR5cGUgPSAibCIsIGNvbCA9ICJibHVlIiwgeWxpbSA9ICBjKC0wLjEsMC4yKSwgbHR5ID0gMywgeWxhYiA9ICJSZXR1cm4iKQpwb2ludHMoY292YXJbNTgwMDo1OTAwLDVdLCB0eXBlID0gImwiLCBjb2wgPSAiYmxhY2siLCBsdHkgPSAxKQpwb2ludHMoeUlbNTgwMDo1OTAwXSwgdHlwZSA9ICJsIiwgY29sID0gInJlZCIsIGx0eSA9IDIpCnNldHdkKCJ+L09uZURyaXZlIC0gSU5TRUFEL1NrZXdFbGxpcHQvQ29kZV9VcGRhdGUvTmF0YWxpYS9vdXQ1MDAvIikKbG9hZCgib3V0U1A1MDAuUkRBVEEiKQpwb2ludHMob3V0LnAkc2lndC5zdFs1ODAwOjU5MDBdLCB0eXBlID0gImwiLCBjb2wgPSAnZ3JlZW4nLCBsdHkgPSA0KQpsZWdlbmQoInRvcHJpZ2h0IiwgbGVnZW5kID0gYygiRVZUIiwgIkZQIiwgIlNQNTAwIiwic2lnbWFfU1A1MDAiKSwgY29sID0gYygiYmx1ZSIsICJibGFjayIsICJyZWQiLCJncmVlbiIpLCBsdHkgPSBjKDMsMSwyLDQpKQpgYGAKClNpbWlsYXJseSwgaWYgd2UgcGxvdCBzdWJzYW1wbGUgaW4gd2hpY2ggS08gbG9zcyBpcyBiZXlvbmQgOTklIFZhUiwgdGhlIHBlYWtzIG9mIFNQMDAgYW5kIENvVmFSIGZyb20gZGlmZmVyZW50IG1ldGhvZHMgYXJlIG5vdCBhbGlnbmVkLgpgYGB7cn0KcGxvdChyLmZwLnN1Yjk5LCB0eXBlID0gImwiLCBjb2wgPSAiYmx1ZSIsIHlsaW0gPSAgYygtMC4wMywwLjMpLCBsdHkgPSAzLCB5bGFiID0gIlJldHVybiIpCnBvaW50cyh5SS5zdWI5OSwgdHlwZSA9ICJsIiwgY29sID0gImJsYWNrIiwgbHR5ID0gMSkKcG9pbnRzKHIuZXZ0LnN1Yjk5LCB0eXBlID0gImwiLCBjb2wgPSAicmVkIiwgbHR5ID0gMikKbGVnZW5kKCJ0b3ByaWdodCIsIGxlZ2VuZCA9IGMoIkZQIiwgIkVWVCIsICJMb3NzIiksIGNvbCA9IGMoImJsdWUiLCAicmVkIiwgImJsYWNrIiksIGx0eSA9IGMoMywyLDEpKQpgYGAKCgpJZiB3ZSBzaGlmdCBMb3NzIHNlcmllcyBvbmUtZGF5IGFoZWFkIChvciBzaGlmdCBDb1ZhUiBvbmUgZGF5IG9uZS1kYXkgYmFja3dhcmQpLCB0aGVuIHRoZSBwZWFrcyBhcmUgYWxpZ25lZC4gRXNzZW50aWFsbHksIHRoaXMgaXMgaW4tc2FtcGxlIGFuYWx5c2lzLiBXZSBjb21wYXJlIENvVmFSIGVzdGlhbXRlZCB1c2luZyBkYXkgMSB0byBkYXkgNTAwIGRhdGEgd2l0aCBkYXkgNTAwIGxvc3MuCgpgYGB7cixtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMjIGlkZW50aWZ5IHN1YnNhbXBsZSB3aGVyZSBMW3QrMV1eaiA+IFZhUlt0KzFdXmoKbj1kaW0oY292YXIuS08pWzFdCmVuZCA9IG5yb3coci5LTykKCmxvc3MuS08gPC0gLXIuS08kclsoZW5kLW4pOihlbmQtMSldCnkgPC0gbG9zcy5LTwp5SSA8LSBhcy52ZWN0b3IoLXJTUFsoZW5kLW4pOihlbmQtMSldKQoKcGxvdChjb3Zhcls1ODAwOjU5MDAsMV0sIHR5cGUgPSAibCIsIGNvbCA9ICJibHVlIiwgeWxpbSA9ICBjKC0wLjEsMC4yKSwgbHR5ID0gMywgeWxhYiA9ICJSZXR1cm4iKQpwb2ludHMoY292YXJbNTgwMDo1OTAwLDVdLCB0eXBlID0gImwiLCBjb2wgPSAiYmxhY2siLCBsdHkgPSAxKQpwb2ludHMoeUlbNTgwMDo1OTAwXSwgdHlwZSA9ICJsIiwgY29sID0gInJlZCIsIGx0eSA9IDIpCnNldHdkKCJ+L09uZURyaXZlIC0gSU5TRUFEL1NrZXdFbGxpcHQvQ29kZV9VcGRhdGUvTmF0YWxpYS9vdXQ1MDAvIikKbG9hZCgib3V0U1A1MDAuUkRBVEEiKQpwb2ludHMob3V0LnAkc2lndC5zdFs1ODAwOjU5MDBdLCB0eXBlID0gImwiLCBjb2wgPSAnZ3JlZW4nLCBsdHkgPSA0KQpsZWdlbmQoInRvcHJpZ2h0IiwgbGVnZW5kID0gYygiRVZUIiwgIkZQIiwgIlNQNTAwIiwic2lnbWFfU1A1MDAiKSwgY29sID0gYygiYmx1ZSIsICJibGFjayIsICJyZWQiLCJncmVlbiIpLCBsdHkgPSBjKDMsMSwyLDQpKQpgYGAKCgpOb3csIHdlIHJlcGVhdCBhbGwgdGhlIGFuYWx5c2lzIGZvciBpbi1zYW1wbGUgQ29WYVIuCgoKYGBge3J9Cms9ZGltKHJtYXQpWzJdICMgbnVtYmVyIG9mIG1ldGhvZHMvY2FzZXMKeW1hdCA9IG1hdHJpeChyZXAoeSwgayksIG5jb2wgPSBrLCBieXJvdz1GQUxTRSkKaG1hdCA9ICh5bWF0ID4gcm1hdCkKCmFwcGx5KGhtYXQsMiwic3VtIixuYS5ybT1UKS9uKjEwMApgYGAKCgpgYGB7cn0Kci5ldnQuc3ViOTUgPC0gc3Vic2V0KGNvdmFyWywxXSxobWF0WywxXSkKci5ldnQuc3ViOTkgPC0gc3Vic2V0KGNvdmFyWywyXSxobWF0WywyXSkKci5lbXAuc3ViOTUgPC0gc3Vic2V0KGNvdmFyWywzXSxobWF0WywxXSkKci5lbXAuc3ViOTkgPC0gc3Vic2V0KGNvdmFyWyw0XSxobWF0WywyXSkKci5mcC5zdWI5NSA8LSAgc3Vic2V0KGNvdmFyWyw1XSxobWF0WywxXSkKci5mcC5zdWI5OSA8LSAgc3Vic2V0KGNvdmFyWyw2XSxobWF0WywyXSkKCiMjIENoZWNraW5nICUgdmlvbGF0aW9ucyBvZiBDb1ZhUiBieSB0aGUgaW5kZXggbG9zc2VzCnlJLnN1Yjk1IDwtIGFzLm51bWVyaWMoc3Vic2V0KHlJLCBobWF0WywxXSkpCnlJLnN1Yjk5IDwtIGFzLm51bWVyaWMoc3Vic2V0KHlJLCBobWF0WywyXSkpCgojIFJlbW92ZSBOQSB2YWx1ZXMKci5zdWI5NSA9IHJiaW5kKHIuZXZ0LnN1Yjk1LHIuZW1wLnN1Yjk1LCByLmZwLnN1Yjk1KQppbmQubmE5NSA9IHdoaWNoKCAoaXMubmEoYXBwbHkoci5zdWI5NSwyLHN1bSkpKSApCgpyLnN1Yjk5ID0gcmJpbmQoci5ldnQuc3ViOTksci5lbXAuc3ViOTksIHIuZnAuc3ViOTkpCmluZC5uYTk5ID0gd2hpY2goKGlzLm5hKGFwcGx5KHIuc3ViOTksMixzdW0pKSkgKQoKaWYgKGxlbmd0aChpbmQubmE5NSk+MCl7CiAgci5ldnQuc3ViOTUgPC0gci5ldnQuc3ViOTVbLWluZC5uYTk1XQogIHIuZW1wLnN1Yjk1IDwtIHIuZW1wLnN1Yjk1Wy1pbmQubmE5NV0KICByLmZwLnN1Yjk1IDwtIHIuZnAuc3ViOTVbLWluZC5uYTk1XQogIHlJLnN1Yjk1IDwtIHlJLnN1Yjk1Wy1pbmQubmE5NV0KfQppZiAobGVuZ3RoKGluZC5uYTk5KT4wKXsKICByLmV2dC5zdWI5OSA8LSByLmV2dC5zdWI5OVstaW5kLm5hOTldCiAgci5lbXAuc3ViOTkgPC0gci5lbXAuc3ViOTlbLWluZC5uYTk5XQogIHIuZnAuc3ViOTkgPC0gci5mcC5zdWI5OVstaW5kLm5hOTldCiAgeUkuc3ViOTkgPC0geUkuc3ViOTlbLWluZC5uYTk5XQp9CgoKbTk1IDwtIGxlbmd0aCh5SS5zdWI5NSkgI3N1Yi1zYW1wbGUgc2l6ZSBmb3IgcT0wLjk1Cm05OSA8LSBsZW5ndGgoeUkuc3ViOTkpICNzdWItc2FtcGxlIHNpemUgZm9yIHE9MC45OQoKcm91bmQoYyhzdW0oeUkuc3ViOTU+ci5ldnQuc3ViOTUpL205NSoxMDAsc3VtKHlJLnN1Yjk1PnIuZW1wLnN1Yjk1KS9tOTUqMTAwLCBzdW0oeUkuc3ViOTU+ci5mcC5zdWI5NSkvbTk1KjEwMCwgc3VtKHlJLnN1Yjk5PnIuZXZ0LnN1Yjk5KS9tOTkqMTAwLCBzdW0oeUkuc3ViOTk+ci5lbXAuc3ViOTkpL205OSoxMDAsIHN1bSh5SS5zdWI5OT5yLmZwLnN1Yjk5KS9tOTkqMTAwKSwyKQpgYGAKCiMjIyMgRnJvbSBhYm92ZSBudW1iZXJzLCBFVlQgbG9va3Mgd29yayBxdWl0ZSB3ZWxsIGZvciBpbi1zYW1wbGUgYW5hbHlzaXMuIEhvd2V2ZXIsIGNvbXBhcmF0aXZlIGJhY2t0ZXN0aW5nIGFuZCBUTE0gc2VlbSB0byBzdWdnZXN0IHRoYXQgRVZUIGlzIHdvcnNlIHRoYW4gZW1waXJpY2FsIG1ldGhvZC4gSSBkbyBub3QgdW5kZXJzdGFuZCB3aHkgd2UgZ2V0IGRpZmZlcmVudCByZXN1dGxzIGZyb20gZGlmZmVyZW50IHRlc3RzLiAKCmBgYHtyfQpjY3QgPC0gbWF0cml4KG5yb3c9MywgbmNvbD0yKSAjIHNpbXBsZSAmIGdlbmVyYWwgQ0NUCgp0bXAgPC0gY2N0LjJzLlZhUih4PXlJLnN1Yjk1LCByPXIuZXZ0LnN1Yjk1LGxldj0wLjk1KTsgY2N0WzEsXTwtYyh0bXAkcHYuYXZnLHRtcCRwdi5jb25kKQp0bXAgPC0gY2N0LjJzLlZhUih4PXlJLnN1Yjk1LCByPXIuZW1wLnN1Yjk1LGxldj0wLjk1KTsgY2N0WzIsXTwtYyh0bXAkcHYuYXZnLHRtcCRwdi5jb25kKQp0bXAgPC0gY2N0LjJzLlZhUih4PXlJLnN1Yjk1LCByPXIuZnAuc3ViOTUsbGV2PTAuOTUpOyBjY3RbMyxdPC1jKHRtcCRwdi5hdmcsdG1wJHB2LmNvbmQpCnJvdW5kKGNjdCwzKQoKIyB0bXAgPC0gY2N0LjJzLlZhUih4PXlJLnN1Yjk5LCByPXIuZXZ0LnN1Yjk5LGxldj0wLjk5KTsgY2N0WzEsXTwtYyh0bXAkcHYuYXZnLHRtcCRwdi5jb25kKQojIHRtcCA8LSBjY3QuMnMuVmFSKHg9eUkuc3ViOTksIHI9ci5lbXAuc3ViOTksbGV2PTAuOTkpOyBjY3RbMixdPC1jKHRtcCRwdi5hdmcsdG1wJHB2LmNvbmQpCiMgdG1wIDwtIGNjdC4ycy5WYVIoeD15SS5zdWI5OSwgcj1yLmZwLnN1Yjk5LGxldj0wLjk5KTsgY2N0WzMsXTwtYyh0bXAkcHYuYXZnLHRtcCRwdi5jb25kKQojIHJvdW5kKGNjdCwzKQoKCiMjIE9ORS1TSURFRCBURVNUIG9mIHN1cGVyLWNhbGlicmF0aW9uIGFzIGluIEJhc2VsIEFjY29yZApjY3QuMXMgPC0gbWF0cml4KG5yb3c9MywgbmNvbD0yKSAjIHNpbXBsZSAmIGdlbmVyYWwgb25lLXNpZGVkIENDVCBvZiBzdXBlci1jYWxpYnJhdGlvbgp0bXAgPC0gY2N0LjFzLlZhUih4PXlJLnN1Yjk1LCByPXIuZXZ0LnN1Yjk1LGxldj0wLjk1KTsgY2N0LjFzWzEsXTwtYyh0bXAkcHYuYXZnLHRtcCRwdi5jb25kKQp0bXAgPC0gY2N0LjFzLlZhUih4PXlJLnN1Yjk1LCByPXIuZW1wLnN1Yjk1LGxldj0wLjk1KTsgY2N0LjFzWzIsXTwtYyh0bXAkcHYuYXZnLHRtcCRwdi5jb25kKQp0bXAgPC0gY2N0LjFzLlZhUih4PXlJLnN1Yjk1LCByPXIuZnAuc3ViOTUsbGV2PTAuOTUpOyBjY3QuMXNbMyxdPC1jKHRtcCRwdi5hdmcsdG1wJHB2LmNvbmQpCnJvdW5kKGNjdC4xcywzKQoKY2N0LjFzIDwtIG1hdHJpeChucm93PTMsIG5jb2w9MikgIyBzaW1wbGUgJiBnZW5lcmFsIG9uZS1zaWRlZCBDQ1Qgb2Ygc3VwZXItY2FsaWJyYXRpb24KdG1wIDwtIGNjdC4xcy5WYVIoeD15SS5zdWI5OSwgcj1yLmV2dC5zdWI5OSxsZXY9MC45OSk7IGNjdC4xc1sxLF08LWModG1wJHB2LmF2Zyx0bXAkcHYuY29uZCkKdG1wIDwtIGNjdC4xcy5WYVIoeD15SS5zdWI5OSwgcj1yLmVtcC5zdWI5OSxsZXY9MC45OSk7IGNjdC4xc1syLF08LWModG1wJHB2LmF2Zyx0bXAkcHYuY29uZCkKdG1wIDwtIGNjdC4xcy5WYVIoeD15SS5zdWI5OSwgcj1yLmZwLnN1Yjk5LGxldj0wLjk5KTsgY2N0LjFzWzMsXTwtYyh0bXAkcHYuYXZnLHRtcCRwdi5jb25kKQpyb3VuZChjY3QuMXMsMykKCiMjIENvbXBhcmF0aXZlIGJhY2t0ZXN0aW5nCiMjIHE9Ljk1CnNtYXQgPC0gbWF0cml4KG5yb3c9MywgbmNvbD0xKQpzbWF0WzEsMV0gPC0gbWVhbihzZlZhUihyPXIuZXZ0LnN1Yjk1LHg9eUkuc3ViOTUsYT0wLjk1LGg9MSkpCnNtYXRbMiwxXSA8LSBtZWFuKHNmVmFSKHI9ci5lbXAuc3ViOTUseD15SS5zdWI5NSxhPTAuOTUsaD0xKSkKc21hdFszLDFdIDwtIG1lYW4oc2ZWYVIocj1yLmZwLnN1Yjk1LHg9eUkuc3ViOTUsYT0wLjk1LGg9MSkpCmFwcGx5KHNtYXQsMiwicmFuayIpCgojIyBxPS45OQpzbWF0IDwtIG1hdHJpeChucm93PTMsIG5jb2w9MSkKc21hdFsxLDFdIDwtIG1lYW4oc2ZWYVIocj1yLmV2dC5zdWI5OSx4PXlJLnN1Yjk5LGE9MC45OSxoPTEpKQpzbWF0WzIsMV0gPC0gbWVhbihzZlZhUihyPXIuZW1wLnN1Yjk5LHg9eUkuc3ViOTksYT0wLjk5LGg9MSkpCnNtYXRbMywxXSA8LSBtZWFuKHNmVmFSKHI9ci5mcC5zdWI5OSx4PXlJLnN1Yjk5LGE9MC45OSxoPTEpKQphcHBseShzbWF0LDIsInJhbmsiKQoKIyMgVExNCnJtPTEKdGxtOTUgPC0gVExNZm4ocj1yYmluZChyLmV2dC5zdWI5NSxyLmVtcC5zdWI5NSxyLmZwLnN1Yjk1KSwgeT15SS5zdWI5NSwgcm09cm0sIGxldj0wLjk1LGg9MSkKcGxvdFRMTSh0bG05NSRUTE0xMCwgcm09MSwgbGV2PTAuOTUsbWV0aG9kPWMoImV2dCIsImVtcCIsInN0IikpCgp0bG05OSA8LSBUTE1mbihyPXJiaW5kKHIuZXZ0LnN1Yjk5LHIuZW1wLnN1Yjk5LHIuZnAuc3ViOTkpLCB5PXlJLnN1Yjk5LCBybT1ybSwgbGV2PTAuOTksaD0xKQpwbG90VExNKHRsbTk5JFRMTTEwLCBybT0xLCBsZXY9MC45OSxtZXRob2Q9YygiZXZ0IiwiZW1wIiwic3QiKSkKYGBgCgpgYGB7cn0KcGxvdChyLmZwLnN1Yjk5LCB0eXBlID0gImwiLCBjb2wgPSAiYmx1ZSIsIHlsaW0gPSAgYygtMC4wMywwLjQpLCBsdHkgPSAzLCB5bGFiID0gIlJldHVybiIpCnBvaW50cyh5SS5zdWI5OSwgdHlwZSA9ICJsIiwgY29sID0gImJsYWNrIiwgbHR5ID0gMSkKcG9pbnRzKHIuZXZ0LnN1Yjk5LCB0eXBlID0gImwiLCBjb2wgPSAicmVkIiwgbHR5ID0gMikKbGVnZW5kKCJ0b3ByaWdodCIsIGxlZ2VuZCA9IGMoIkZQIiwgIkVWVCIsICJMb3NzIiksIGNvbCA9IGMoImJsdWUiLCAicmVkIiwgImJsYWNrIiksIGx0eSA9IGMoMywyLDEpKQpgYGAKCmBgYHtyfQpwbG90KHlJLCB5bGFiPSIiLCB5bGltPWMoLS4xMiwwLjQpLCBjb2w9ImdyYXkiLHhsYWI9IiIsIG1haW49IktPIiwgY2V4Lm1haW49MC44LCBsdHkgPSAxKQpsaW5lcyh0aW1lKHlJKSxjb3Zhci5LT1ssMV0sIGNvbD0icmVkIiwgbHR5ID0gMikKbGluZXModGltZSh5SSksY292YXIuS09bLDVdLCBjb2w9ImJsYWNrIiwgbHR5ID0gMykKbGluZXModGltZSh5SSksY292YXIuS09bLDNdLCBjb2w9ImdyZWVuIiwgbHR5ID0gNCkKbGVnZW5kKCJ0b3BsZWZ0IiwgbGVnZW5kID0gYygiU1A1MDAiLCAiRVZUIiwgIkZQIiwgIkhTIiksIGNvbCA9IGMoImdyZXkiLCAicmVkIiwgImJsYWNrIiwgImdyZWVuIiksIGx0eSA9IGMoMSwyLDMsNCkpCmBgYAoK