Prepare Data:

rm(list = ls())
library("rugarch")
library("fGarch")
library("MASS")
library("ismev")
# library("lmom")
# library("QRM")
library("skewt")
library("zoo")
library("plotrix")
source("~/OneDrive - INSEAD/SkewEllipt/Code_Update/Rfns.R")
setwd("~/OneDrive - INSEAD/SkewEllipt/Code_Update/Natalia/out500/")
##=========================================================
## Backtesting CoVaR
##=========================================================
dat = fread("~/OneDrive - INSEAD/SkewEllipt/Code_Update/Natalia/Ret_data.csv") # raw data file (1962/07/02 - 2017/07/31)
dat = dat[,`:=`(RET=as.numeric(as.character(RET)), SP500 = as.numeric(as.character(SP500)))]
dat = dat[!is.na(RET)]
dat = unique(dat, by = c("TICKER", "date") )
setnames(dat, "RET", "r")
r.KO = dat[TICKER == 'KO', list(date, TICKER, r, SP500)]
r.GE = dat[TICKER == 'GE', list(date, TICKER, r, SP500)]
r.BA = dat[TICKER == 'BA', list(date, TICKER, r, SP500)]
r.DIS = dat[TICKER == 'DIS', list(date, TICKER, r, SP500)]
dat.indices <- unique(data.frame(dat$date,dat$Ret_M,dat$SP500))
colnames(dat.indices)<-c("date","retM","sp500")
rM <- zoo(x=dat.indices$retM,order.by = strptime(dat.indices$date,"%Y%m%d"))
rSP<- zoo(x=dat.indices$sp500,order.by = strptime(dat.indices$date,"%Y%m%d"))
load("CoVaR.RDATA")
# attributes(out)
##columns are 95% CoVaR by EVT method, 99% CoVaR by EVT method and 95% CoVaR by empirical method
covar.KO <- out$CoVaR.KO
covar.BA <- out$CoVaR.BA
covar.DIS <- out$CoVaR.DIS
covar.GE <- out$CoVaR.GE

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.GE
rmat <- var.GE
covar <- covar.GE
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.237561 1.114852

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.99  9.21  8.19  4.14 19.31  7.59
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.001
[3,] 0.003 0.007
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)
      [,1]  [,2]
[1,] 0.061 0.008
[2,] 0.000 0.000
[3,] 0.004 0.000
## 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.001 0.004
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.030 0.091
[2,] 0.000 0.000
[3,] 0.002 0.005
## 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,]    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 GE 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.GE <- -r.GE$r[(end-n):(end-1)]
y <- loss.GE
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.9955107 0.4713805
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.22 1.92 3.84 1.64 3.28 1.64

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.378 0.201
[2,] 0.000 0.000
[3,] 0.168 0.187
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)
      [,1]  [,2]
[1,] 0.695 0.557
[2,] 0.322 0.220
[3,] 0.695 0.557
## 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.811    1
[2,] 1.000    1
[3,] 0.916    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,] 0.347 0.521
[2,] 0.161 0.482
[3,] 0.347 0.521
## 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,]    2
[2,]    1
[3,]    3
## 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="GE", cex.main=0.8, lty = 1)
lines(time(yI),covar.GE[,1], col="red", lty = 2)
lines(time(yI),covar.GE[,5], col="black", lty = 3)
lines(time(yI),covar.GE[,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))

LS0tCnRpdGxlOiAiQ29WYVIgLS0gR0UiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMjIyBQcmVwYXJlIERhdGE6CgpgYGB7ciBpbmNsdWRlPVRSVUUsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZz1GQUxTRX0Kcm0obGlzdCA9IGxzKCkpCmxpYnJhcnkoInJ1Z2FyY2giKQpsaWJyYXJ5KCJmR2FyY2giKQpsaWJyYXJ5KCJNQVNTIikKbGlicmFyeSgiaXNtZXYiKQojIGxpYnJhcnkoImxtb20iKQojIGxpYnJhcnkoIlFSTSIpCmxpYnJhcnkoInNrZXd0IikKbGlicmFyeSgiem9vIikKbGlicmFyeSgicGxvdHJpeCIpCgpzb3VyY2UoIn4vT25lRHJpdmUgLSBJTlNFQUQvU2tld0VsbGlwdC9Db2RlX1VwZGF0ZS9SZm5zLlIiKQpzZXR3ZCgifi9PbmVEcml2ZSAtIElOU0VBRC9Ta2V3RWxsaXB0L0NvZGVfVXBkYXRlL05hdGFsaWEvb3V0NTAwLyIpCiMjPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMjIEJhY2t0ZXN0aW5nIENvVmFSCiMjPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CgpkYXQgPSBmcmVhZCgifi9PbmVEcml2ZSAtIElOU0VBRC9Ta2V3RWxsaXB0L0NvZGVfVXBkYXRlL05hdGFsaWEvUmV0X2RhdGEuY3N2IikgIyByYXcgZGF0YSBmaWxlICgxOTYyLzA3LzAyIC0gMjAxNy8wNy8zMSkKZGF0ID0gZGF0WyxgOj1gKFJFVD1hcy5udW1lcmljKGFzLmNoYXJhY3RlcihSRVQpKSwgU1A1MDAgPSBhcy5udW1lcmljKGFzLmNoYXJhY3RlcihTUDUwMCkpKV0KZGF0ID0gZGF0WyFpcy5uYShSRVQpXQpkYXQgPSB1bmlxdWUoZGF0LCBieSA9IGMoIlRJQ0tFUiIsICJkYXRlIikgKQpzZXRuYW1lcyhkYXQsICJSRVQiLCAiciIpCnIuS08gPSBkYXRbVElDS0VSID09ICdLTycsIGxpc3QoZGF0ZSwgVElDS0VSLCByLCBTUDUwMCldCnIuR0UgPSBkYXRbVElDS0VSID09ICdHRScsIGxpc3QoZGF0ZSwgVElDS0VSLCByLCBTUDUwMCldCnIuQkEgPSBkYXRbVElDS0VSID09ICdCQScsIGxpc3QoZGF0ZSwgVElDS0VSLCByLCBTUDUwMCldCnIuRElTID0gZGF0W1RJQ0tFUiA9PSAnRElTJywgbGlzdChkYXRlLCBUSUNLRVIsIHIsIFNQNTAwKV0KCmRhdC5pbmRpY2VzIDwtIHVuaXF1ZShkYXRhLmZyYW1lKGRhdCRkYXRlLGRhdCRSZXRfTSxkYXQkU1A1MDApKQpjb2xuYW1lcyhkYXQuaW5kaWNlcyk8LWMoImRhdGUiLCJyZXRNIiwic3A1MDAiKQpyTSA8LSB6b28oeD1kYXQuaW5kaWNlcyRyZXRNLG9yZGVyLmJ5ID0gc3RycHRpbWUoZGF0LmluZGljZXMkZGF0ZSwiJVklbSVkIikpCnJTUDwtIHpvbyh4PWRhdC5pbmRpY2VzJHNwNTAwLG9yZGVyLmJ5ID0gc3RycHRpbWUoZGF0LmluZGljZXMkZGF0ZSwiJVklbSVkIikpCgpsb2FkKCJDb1ZhUi5SREFUQSIpCiMgYXR0cmlidXRlcyhvdXQpCgojI2NvbHVtbnMgYXJlIDk1JSBDb1ZhUiBieSBFVlQgbWV0aG9kLCA5OSUgQ29WYVIgYnkgRVZUIG1ldGhvZCBhbmQgOTUlIENvVmFSIGJ5IGVtcGlyaWNhbCBtZXRob2QKCmNvdmFyLktPIDwtIG91dCRDb1ZhUi5LTwpjb3Zhci5CQSA8LSBvdXQkQ29WYVIuQkEKY292YXIuRElTIDwtIG91dCRDb1ZhUi5ESVMKY292YXIuR0UgPC0gb3V0JENvVmFSLkdFCmBgYAoKCiMjIyBPdXQtb2Ytc2FtcGxlIFRlc3QKV2UgY2FsY3VhbHRlIG9uZS1kYXkgYWhlYWQgcHJlZGljdGVkIFZhUiBhbmQgQ29WYVIgdXNpbmcgcGFzdCA1MDAgZGF5cyAocm9sbG9pbmcgd2luZG93KSBhbmQgdGhlbiBtYXRjaCB3aXRoIGxvc3Mgc2VyaWVzLiBTcGVjaWZpY2FsbHksIHdlIHVzZSBkYXRhIGZyb20gZGF5IDEgdG8gNTAwIHRvIGZpdCBHYXJjaCBtb2RlbCBhbmQgZ2V0IHJlc2lkdWFsIHNlcmllcyBhbmQgcHJlZGljdGVkIG11IGFuZCBzaWdtYWwuIFRoZW4gd2UgY2FsY3VsYXRlIG9uZS1kYXkgYWhlYWQgcHJlZGljdGVkIFZhUiBhbmQgQ29WYVIsIHRoYXQgaXMgZGF5IDUwMSBWYVIgYW5kIENvVmFSLgoKCmBgYHtyLG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZz1GQUxTRX0KIyMgaWRlbnRpZnkgc3Vic2FtcGxlIHdoZXJlIExbdCsxXV5qID4gVmFSW3QrMV1eagpuPWRpbShjb3Zhci5LTylbMV0KZW5kID0gbnJvdyhyLktPKSArIDEKc2V0d2QoIn4vT25lRHJpdmUgLSBJTlNFQUQvU2tld0VsbGlwdC9Db2RlX1VwZGF0ZS9OYXRhbGlhL291dDUwMC8iKQpsb2FkKCJvdXRLTy5SREFUQSIpCnZhci5LTyA8LSBvdXQucCRzdEVWVFssMjozXQpsb3NzLktPIDwtIC1yLktPJHJbKGVuZC1uKTooZW5kLTEpXQoKbG9hZCgib3V0QkEuUkRBVEEiKQp2YXIuQkEgPC0gb3V0LnAkc3RFVlRbLDI6M10KbG9zcy5CQSA8LSAtci5CQSRyWyhlbmQtbik6KGVuZC0xKV0KCmxvYWQoIm91dERJUy5SREFUQSIpCnZhci5ESVMgPC0gb3V0LnAkc3RFVlRbLDI6M10KbG9zcy5ESVMgPC0gLXIuRElTJHJbKGVuZC1uKTooZW5kLTEpXQoKbG9hZCgib3V0R0UuUkRBVEEiKQp2YXIuR0UgPC0gb3V0LnAkc3RFVlRbLDI6M10KbG9zcy5HRSA8LSAtci5HRSRyWyhlbmQtbik6KGVuZC0xKV0KYGBgCgpgYGB7cn0KeSA8LSBsb3NzLkdFCnJtYXQgPC0gdmFyLkdFCmNvdmFyIDwtIGNvdmFyLkdFCnlJIDwtIGFzLnZlY3RvcigtclNQWyhlbmQtbik6KGVuZC0xKV0pCmBgYAoKV2UgY2hlY2sgdGhlIHBlcmZvcm1hbmNlIG9mIHByZWRpY3RlZCBWYVI6CmBgYHtyfQprPWRpbShybWF0KVsyXSAjIG51bWJlciBvZiBtZXRob2RzL2Nhc2VzCnltYXQgPSBtYXRyaXgocmVwKHksIGspLCBuY29sID0gaywgYnlyb3c9RkFMU0UpCmhtYXQgPSAoeW1hdCA+IHJtYXQpCgphcHBseShobWF0LDIsInN1bSIsbmEucm09VCkvbioxMDAKYGBgCgpXZSBjaGVjayB0aGUgcGVyZm9ybWFuY2Ugb2YgcHJlZGljdGVkIENvVmFSOgpgYGB7cn0Kci5ldnQuc3ViOTUgPC0gc3Vic2V0KGNvdmFyWywxXSxobWF0WywxXSkKci5ldnQuc3ViOTkgPC0gc3Vic2V0KGNvdmFyWywyXSxobWF0WywyXSkKci5lbXAuc3ViOTUgPC0gc3Vic2V0KGNvdmFyWywzXSxobWF0WywxXSkKci5lbXAuc3ViOTkgPC0gc3Vic2V0KGNvdmFyWyw0XSxobWF0WywyXSkKci5mcC5zdWI5NSA8LSAgc3Vic2V0KGNvdmFyWyw1XSxobWF0WywxXSkKci5mcC5zdWI5OSA8LSAgc3Vic2V0KGNvdmFyWyw2XSxobWF0WywyXSkKCiMjIENoZWNraW5nICUgdmlvbGF0aW9ucyBvZiBDb1ZhUiBieSB0aGUgaW5kZXggbG9zc2VzCnlJLnN1Yjk1IDwtIGFzLm51bWVyaWMoc3Vic2V0KHlJLCBobWF0WywxXSkpCnlJLnN1Yjk5IDwtIGFzLm51bWVyaWMoc3Vic2V0KHlJLCBobWF0WywyXSkpCgojIFJlbW92ZSBOQSB2YWx1ZXMKci5zdWI5NSA9IHJiaW5kKHIuZXZ0LnN1Yjk1LHIuZW1wLnN1Yjk1LCByLmZwLnN1Yjk1KQppbmQubmE5NSA9IHdoaWNoKCAoaXMubmEoYXBwbHkoci5zdWI5NSwyLHN1bSkpKSApCgpyLnN1Yjk5ID0gcmJpbmQoci5ldnQuc3ViOTksci5lbXAuc3ViOTksIHIuZnAuc3ViOTkpCmluZC5uYTk5ID0gd2hpY2goKGlzLm5hKGFwcGx5KHIuc3ViOTksMixzdW0pKSkgKQoKaWYgKGxlbmd0aChpbmQubmE5NSk+MCl7CiAgci5ldnQuc3ViOTUgPC0gci5ldnQuc3ViOTVbLWluZC5uYTk1XQogIHIuZW1wLnN1Yjk1IDwtIHIuZW1wLnN1Yjk1Wy1pbmQubmE5NV0KICByLmZwLnN1Yjk1IDwtIHIuZnAuc3ViOTVbLWluZC5uYTk1XQogIHlJLnN1Yjk1IDwtIHlJLnN1Yjk1Wy1pbmQubmE5NV0KfQppZiAobGVuZ3RoKGluZC5uYTk5KT4wKXsKICByLmV2dC5zdWI5OSA8LSByLmV2dC5zdWI5OVstaW5kLm5hOTldCiAgci5lbXAuc3ViOTkgPC0gci5lbXAuc3ViOTlbLWluZC5uYTk5XQogIHIuZnAuc3ViOTkgPC0gci5mcC5zdWI5OVstaW5kLm5hOTldCiAgeUkuc3ViOTkgPC0geUkuc3ViOTlbLWluZC5uYTk5XQp9CgoKbTk1IDwtIGxlbmd0aCh5SS5zdWI5NSkgI3N1Yi1zYW1wbGUgc2l6ZSBmb3IgcT0wLjk1Cm05OSA8LSBsZW5ndGgoeUkuc3ViOTkpICNzdWItc2FtcGxlIHNpemUgZm9yIHE9MC45OQoKcm91bmQoYyhzdW0oeUkuc3ViOTU+ci5ldnQuc3ViOTUpL205NSoxMDAsc3VtKHlJLnN1Yjk1PnIuZW1wLnN1Yjk1KS9tOTUqMTAwLCBzdW0oeUkuc3ViOTU+ci5mcC5zdWI5NSkvbTk1KjEwMCwgc3VtKHlJLnN1Yjk5PnIuZXZ0LnN1Yjk5KS9tOTkqMTAwLCBzdW0oeUkuc3ViOTk+ci5lbXAuc3ViOTkpL205OSoxMDAsIHN1bSh5SS5zdWI5OT5yLmZwLnN1Yjk5KS9tOTkqMTAwKSwyKQpgYGAKCiMjIyMjIFRoZSBFVlQgbWV0aG9kIGRvZXMgbm90IHBlcmZvcm0gd2VsbCBmb3IgOTUlIENvVmFSIGVzdGltYXRpb24gYnV0IHJlbGF0aXZlbHkgZ29vZCBmb3IgOTklIENvVmFSIGVzdGltYXRpb24uIFNpbXBsZSBDQ1QgaXMgY29uc2lzdGVudCB3aXRoIHRoaXMgcmVzdWx0LCBidXQgY29tcGFyYXRpdmUgYmFja3Rlc3RpbmcgIGFuZCBUTE0gc3VnZ2VzdHMgdGhhdCBGUCBpcyBzbGlnaHRseSBiZXR0ZXIgdGhhbiBFVlQuICBJbiBzdW1tYXJ5LCBFVlQgYW5kIEZQIGlzIHNpZ25pZmljYW50bHkgYmV0dGVyIHRoYW4gZW1waXJpY2FsIG1ldGhvZCBhdCAxMCUgbGV2ZWwgZm9yIGVzdGltYXRpb24gOTklIENvVmFSLCBidXQgRVZUIGFuZCBGUCBhcmUgcXVpdGUgc2ltaWxhci4KCgpgYGB7cn0KY2N0IDwtIG1hdHJpeChucm93PTMsIG5jb2w9MikgIyBzaW1wbGUgJiBnZW5lcmFsIENDVAoKdG1wIDwtIGNjdC4ycy5WYVIoeD15SS5zdWI5NSwgcj1yLmV2dC5zdWI5NSxsZXY9MC45NSk7IGNjdFsxLF08LWModG1wJHB2LmF2Zyx0bXAkcHYuY29uZCkKdG1wIDwtIGNjdC4ycy5WYVIoeD15SS5zdWI5NSwgcj1yLmVtcC5zdWI5NSxsZXY9MC45NSk7IGNjdFsyLF08LWModG1wJHB2LmF2Zyx0bXAkcHYuY29uZCkKdG1wIDwtIGNjdC4ycy5WYVIoeD15SS5zdWI5NSwgcj1yLmZwLnN1Yjk1LGxldj0wLjk1KTsgY2N0WzMsXTwtYyh0bXAkcHYuYXZnLHRtcCRwdi5jb25kKQpyb3VuZChjY3QsMykKCnRtcCA8LSBjY3QuMnMuVmFSKHg9eUkuc3ViOTksIHI9ci5ldnQuc3ViOTksbGV2PTAuOTkpOyBjY3RbMSxdPC1jKHRtcCRwdi5hdmcsdG1wJHB2LmNvbmQpCnRtcCA8LSBjY3QuMnMuVmFSKHg9eUkuc3ViOTksIHI9ci5lbXAuc3ViOTksbGV2PTAuOTkpOyBjY3RbMixdPC1jKHRtcCRwdi5hdmcsdG1wJHB2LmNvbmQpCnRtcCA8LSBjY3QuMnMuVmFSKHg9eUkuc3ViOTksIHI9ci5mcC5zdWI5OSxsZXY9MC45OSk7IGNjdFszLF08LWModG1wJHB2LmF2Zyx0bXAkcHYuY29uZCkKcm91bmQoY2N0LDMpCgoKIyMgT05FLVNJREVEIFRFU1Qgb2Ygc3VwZXItY2FsaWJyYXRpb24gYXMgaW4gQmFzZWwgQWNjb3JkCmNjdC4xcyA8LSBtYXRyaXgobnJvdz0zLCBuY29sPTIpICMgc2ltcGxlICYgZ2VuZXJhbCBvbmUtc2lkZWQgQ0NUIG9mIHN1cGVyLWNhbGlicmF0aW9uCnRtcCA8LSBjY3QuMXMuVmFSKHg9eUkuc3ViOTUsIHI9ci5ldnQuc3ViOTUsbGV2PTAuOTUpOyBjY3QuMXNbMSxdPC1jKHRtcCRwdi5hdmcsdG1wJHB2LmNvbmQpCnRtcCA8LSBjY3QuMXMuVmFSKHg9eUkuc3ViOTUsIHI9ci5lbXAuc3ViOTUsbGV2PTAuOTUpOyBjY3QuMXNbMixdPC1jKHRtcCRwdi5hdmcsdG1wJHB2LmNvbmQpCnRtcCA8LSBjY3QuMXMuVmFSKHg9eUkuc3ViOTUsIHI9ci5mcC5zdWI5NSxsZXY9MC45NSk7IGNjdC4xc1szLF08LWModG1wJHB2LmF2Zyx0bXAkcHYuY29uZCkKcm91bmQoY2N0LjFzLDMpCgpjY3QuMXMgPC0gbWF0cml4KG5yb3c9MywgbmNvbD0yKSAjIHNpbXBsZSAmIGdlbmVyYWwgb25lLXNpZGVkIENDVCBvZiBzdXBlci1jYWxpYnJhdGlvbgp0bXAgPC0gY2N0LjFzLlZhUih4PXlJLnN1Yjk5LCByPXIuZXZ0LnN1Yjk5LGxldj0wLjk5KTsgY2N0LjFzWzEsXTwtYyh0bXAkcHYuYXZnLHRtcCRwdi5jb25kKQp0bXAgPC0gY2N0LjFzLlZhUih4PXlJLnN1Yjk5LCByPXIuZW1wLnN1Yjk5LGxldj0wLjk5KTsgY2N0LjFzWzIsXTwtYyh0bXAkcHYuYXZnLHRtcCRwdi5jb25kKQp0bXAgPC0gY2N0LjFzLlZhUih4PXlJLnN1Yjk5LCByPXIuZnAuc3ViOTksbGV2PTAuOTkpOyBjY3QuMXNbMyxdPC1jKHRtcCRwdi5hdmcsdG1wJHB2LmNvbmQpCnJvdW5kKGNjdC4xcywzKQoKIyMgQ29tcGFyYXRpdmUgYmFja3Rlc3RpbmcKIyMgcT0uOTUKc21hdCA8LSBtYXRyaXgobnJvdz0zLCBuY29sPTEpCnNtYXRbMSwxXSA8LSBtZWFuKHNmVmFSKHI9ci5ldnQuc3ViOTUseD15SS5zdWI5NSxhPTAuOTUsaD0xKSkKc21hdFsyLDFdIDwtIG1lYW4oc2ZWYVIocj1yLmVtcC5zdWI5NSx4PXlJLnN1Yjk1LGE9MC45NSxoPTEpKQpzbWF0WzMsMV0gPC0gbWVhbihzZlZhUihyPXIuZnAuc3ViOTUseD15SS5zdWI5NSxhPTAuOTUsaD0xKSkKYXBwbHkoc21hdCwyLCJyYW5rIikKCiMjIHE9Ljk5CnNtYXQgPC0gbWF0cml4KG5yb3c9MywgbmNvbD0xKQpzbWF0WzEsMV0gPC0gbWVhbihzZlZhUihyPXIuZXZ0LnN1Yjk5LHg9eUkuc3ViOTksYT0wLjk5LGg9MSkpCnNtYXRbMiwxXSA8LSBtZWFuKHNmVmFSKHI9ci5lbXAuc3ViOTkseD15SS5zdWI5OSxhPTAuOTksaD0xKSkKc21hdFszLDFdIDwtIG1lYW4oc2ZWYVIocj1yLmZwLnN1Yjk5LHg9eUkuc3ViOTksYT0wLjk5LGg9MSkpCmFwcGx5KHNtYXQsMiwicmFuayIpCgojIyBUTE0Kcm09MQp0bG05NSA8LSBUTE1mbihyPXJiaW5kKHIuZXZ0LnN1Yjk1LHIuZW1wLnN1Yjk1LHIuZnAuc3ViOTUpLCB5PXlJLnN1Yjk1LCBybT1ybSwgbGV2PTAuOTUsaD0xKQpwbG90VExNKHRsbTk1JFRMTTEwLCBybT0xLCBsZXY9MC45NSxtZXRob2Q9YygiZXZ0IiwiZW1wIiwic3QiKSkKCnRsbTk5IDwtIFRMTWZuKHI9cmJpbmQoci5ldnQuc3ViOTksci5lbXAuc3ViOTksci5mcC5zdWI5OSksIHk9eUkuc3ViOTksIHJtPXJtLCBsZXY9MC45OSxoPTEpCnBsb3RUTE0odGxtOTkkVExNMTAsIHJtPTEsIGxldj0wLjk5LG1ldGhvZD1jKCJldnQiLCJlbXAiLCJzdCIpKQpgYGAKCgoKIyMjIEluLVNhbXBsZSBUZXN0Ckhvd2V2ZXIsIHdlIGNhbiBzaG93IHRoYXQgbW92ZW1lbnQgaW4gQ29WYVIgaXMgZHJpdmVuIGJ5IHRoZSBwcmVkaWN0IHNpZ21hbCBmcm9tIEdhcmNoIG1vZGVsLCBhbmQgdGhlIHByZWRpY3RlZCBzaWdtYWwgc2hhcmVzIHRoZSBzaW1pbGFyIHBhdHRlcm4gb2YgbGFnZ2VkIGxvc3Mgc2VyaWVzLiBUaGUgZmlndXJlIGJsb3cgcGxvdHMgc3Vic2FtcGxlIHdpdGggMTAwIGRheXMgZm9yIFNQNTAwIGxvc3Mgc2VyaWVzLiBBcyBzaG93biBpbiB0aGUgZmlndXJlLCB0aGUgcGVha3Mgb2Ygc2lnbWFfU1A1MDAgYXJlIGluIGxpbmUgd2l0aCBDb1ZhUiBmcm9tIEVWVCBhbmQgRlAsIGJ1dCBhcmUgb25lLXBlcmlvZCBoZWFkIG9mIGxvc3Mgc2VyaWVzIChzZWUgeC1heGlzIDgwLTEwMCkuIFRoaXMgcmVzdWx0IGNvbWVzIGZyb20gdGhlIGZhY3QgdGhhdCBwcmVkaWN0ZWQgc2lnbWEgaXMgaGVhdmlseSBhZmZlY3RlZCBieSB0aGUgbW9zdCByZWNlbnQgZGF0YS4gV2hlbiB0aGVyZSBpcyBhIGhpZ2ggcmV1dHJuIChvciBsb3NzKSB0b2RheSwgdGhlIHByZWRpY3RlZCB2b2xhdGlsaXR5IHdpbGwgYmUgdmVyeSBoaWdoIHRvbW9ycm93LgoKYGBge3IgaW5jbHVkZT1UUlVFLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmc9RkFMU0V9CnBsb3QoY292YXJbNTgwMDo1OTAwLDFdLCB0eXBlID0gImwiLCBjb2wgPSAiYmx1ZSIsIHlsaW0gPSAgYygtMC4xLDAuMiksIGx0eSA9IDMsIHlsYWIgPSAiUmV0dXJuIikKcG9pbnRzKGNvdmFyWzU4MDA6NTkwMCw1XSwgdHlwZSA9ICJsIiwgY29sID0gImJsYWNrIiwgbHR5ID0gMSkKcG9pbnRzKHlJWzU4MDA6NTkwMF0sIHR5cGUgPSAibCIsIGNvbCA9ICJyZWQiLCBsdHkgPSAyKQpzZXR3ZCgifi9PbmVEcml2ZSAtIElOU0VBRC9Ta2V3RWxsaXB0L0NvZGVfVXBkYXRlL05hdGFsaWEvb3V0NTAwLyIpCmxvYWQoIm91dFNQNTAwLlJEQVRBIikKcG9pbnRzKG91dC5wJHNpZ3Quc3RbNTgwMDo1OTAwXSwgdHlwZSA9ICJsIiwgY29sID0gJ2dyZWVuJywgbHR5ID0gNCkKbGVnZW5kKCJ0b3ByaWdodCIsIGxlZ2VuZCA9IGMoIkVWVCIsICJGUCIsICJTUDUwMCIsInNpZ21hX1NQNTAwIiksIGNvbCA9IGMoImJsdWUiLCAiYmxhY2siLCAicmVkIiwiZ3JlZW4iKSwgbHR5ID0gYygzLDEsMiw0KSkKYGBgCgpTaW1pbGFybHksIGlmIHdlIHBsb3Qgc3Vic2FtcGxlIGluIHdoaWNoIEdFIGxvc3MgaXMgYmV5b25kIDk5JSBWYVIsIHRoZSBwZWFrcyBvZiBTUDAwIGFuZCBDb1ZhUiBmcm9tIGRpZmZlcmVudCBtZXRob2RzIGFyZSBub3QgYWxpZ25lZC4KYGBge3J9CnBsb3Qoci5mcC5zdWI5OSwgdHlwZSA9ICJsIiwgY29sID0gImJsdWUiLCB5bGltID0gIGMoLTAuMDMsMC4zKSwgbHR5ID0gMywgeWxhYiA9ICJSZXR1cm4iKQpwb2ludHMoeUkuc3ViOTksIHR5cGUgPSAibCIsIGNvbCA9ICJibGFjayIsIGx0eSA9IDEpCnBvaW50cyhyLmV2dC5zdWI5OSwgdHlwZSA9ICJsIiwgY29sID0gInJlZCIsIGx0eSA9IDIpCmxlZ2VuZCgidG9wcmlnaHQiLCBsZWdlbmQgPSBjKCJGUCIsICJFVlQiLCAiTG9zcyIpLCBjb2wgPSBjKCJibHVlIiwgInJlZCIsICJibGFjayIpLCBsdHkgPSBjKDMsMiwxKSkKYGBgCgoKSWYgd2Ugc2hpZnQgTG9zcyBzZXJpZXMgb25lLWRheSBhaGVhZCAob3Igc2hpZnQgQ29WYVIgb25lIGRheSBvbmUtZGF5IGJhY2t3YXJkKSwgdGhlbiB0aGUgcGVha3MgYXJlIGFsaWduZWQuIEVzc2VudGlhbGx5LCB0aGlzIGlzIGluLXNhbXBsZSBhbmFseXNpcy4gV2UgY29tcGFyZSBDb1ZhUiBlc3RpYW10ZWQgdXNpbmcgZGF5IDEgdG8gZGF5IDUwMCBkYXRhIHdpdGggZGF5IDUwMCBsb3NzLgoKYGBge3IsbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIyBpZGVudGlmeSBzdWJzYW1wbGUgd2hlcmUgTFt0KzFdXmogPiBWYVJbdCsxXV5qCm49ZGltKGNvdmFyLktPKVsxXQplbmQgPSBucm93KHIuS08pCgpsb3NzLkdFIDwtIC1yLkdFJHJbKGVuZC1uKTooZW5kLTEpXQp5IDwtIGxvc3MuR0UKeUkgPC0gYXMudmVjdG9yKC1yU1BbKGVuZC1uKTooZW5kLTEpXSkKCnBsb3QoY292YXJbNTgwMDo1OTAwLDFdLCB0eXBlID0gImwiLCBjb2wgPSAiYmx1ZSIsIHlsaW0gPSAgYygtMC4xLDAuMiksIGx0eSA9IDMsIHlsYWIgPSAiUmV0dXJuIikKcG9pbnRzKGNvdmFyWzU4MDA6NTkwMCw1XSwgdHlwZSA9ICJsIiwgY29sID0gImJsYWNrIiwgbHR5ID0gMSkKcG9pbnRzKHlJWzU4MDA6NTkwMF0sIHR5cGUgPSAibCIsIGNvbCA9ICJyZWQiLCBsdHkgPSAyKQpzZXR3ZCgifi9PbmVEcml2ZSAtIElOU0VBRC9Ta2V3RWxsaXB0L0NvZGVfVXBkYXRlL05hdGFsaWEvb3V0NTAwLyIpCmxvYWQoIm91dFNQNTAwLlJEQVRBIikKcG9pbnRzKG91dC5wJHNpZ3Quc3RbNTgwMDo1OTAwXSwgdHlwZSA9ICJsIiwgY29sID0gJ2dyZWVuJywgbHR5ID0gNCkKbGVnZW5kKCJ0b3ByaWdodCIsIGxlZ2VuZCA9IGMoIkVWVCIsICJGUCIsICJTUDUwMCIsInNpZ21hX1NQNTAwIiksIGNvbCA9IGMoImJsdWUiLCAiYmxhY2siLCAicmVkIiwiZ3JlZW4iKSwgbHR5ID0gYygzLDEsMiw0KSkKYGBgCgoKTm93LCB3ZSByZXBlYXQgYWxsIHRoZSBhbmFseXNpcyBmb3IgaW4tc2FtcGxlIENvVmFSLgoKCmBgYHtyfQprPWRpbShybWF0KVsyXSAjIG51bWJlciBvZiBtZXRob2RzL2Nhc2VzCnltYXQgPSBtYXRyaXgocmVwKHksIGspLCBuY29sID0gaywgYnlyb3c9RkFMU0UpCmhtYXQgPSAoeW1hdCA+IHJtYXQpCgphcHBseShobWF0LDIsInN1bSIsbmEucm09VCkvbioxMDAKYGBgCgoKYGBge3J9CnIuZXZ0LnN1Yjk1IDwtIHN1YnNldChjb3ZhclssMV0saG1hdFssMV0pCnIuZXZ0LnN1Yjk5IDwtIHN1YnNldChjb3ZhclssMl0saG1hdFssMl0pCnIuZW1wLnN1Yjk1IDwtIHN1YnNldChjb3ZhclssM10saG1hdFssMV0pCnIuZW1wLnN1Yjk5IDwtIHN1YnNldChjb3ZhclssNF0saG1hdFssMl0pCnIuZnAuc3ViOTUgPC0gIHN1YnNldChjb3ZhclssNV0saG1hdFssMV0pCnIuZnAuc3ViOTkgPC0gIHN1YnNldChjb3ZhclssNl0saG1hdFssMl0pCgojIyBDaGVja2luZyAlIHZpb2xhdGlvbnMgb2YgQ29WYVIgYnkgdGhlIGluZGV4IGxvc3Nlcwp5SS5zdWI5NSA8LSBhcy5udW1lcmljKHN1YnNldCh5SSwgaG1hdFssMV0pKQp5SS5zdWI5OSA8LSBhcy5udW1lcmljKHN1YnNldCh5SSwgaG1hdFssMl0pKQoKIyBSZW1vdmUgTkEgdmFsdWVzCnIuc3ViOTUgPSByYmluZChyLmV2dC5zdWI5NSxyLmVtcC5zdWI5NSwgci5mcC5zdWI5NSkKaW5kLm5hOTUgPSB3aGljaCggKGlzLm5hKGFwcGx5KHIuc3ViOTUsMixzdW0pKSkgKQoKci5zdWI5OSA9IHJiaW5kKHIuZXZ0LnN1Yjk5LHIuZW1wLnN1Yjk5LCByLmZwLnN1Yjk5KQppbmQubmE5OSA9IHdoaWNoKChpcy5uYShhcHBseShyLnN1Yjk5LDIsc3VtKSkpICkKCmlmIChsZW5ndGgoaW5kLm5hOTUpPjApewogIHIuZXZ0LnN1Yjk1IDwtIHIuZXZ0LnN1Yjk1Wy1pbmQubmE5NV0KICByLmVtcC5zdWI5NSA8LSByLmVtcC5zdWI5NVstaW5kLm5hOTVdCiAgci5mcC5zdWI5NSA8LSByLmZwLnN1Yjk1Wy1pbmQubmE5NV0KICB5SS5zdWI5NSA8LSB5SS5zdWI5NVstaW5kLm5hOTVdCn0KaWYgKGxlbmd0aChpbmQubmE5OSk+MCl7CiAgci5ldnQuc3ViOTkgPC0gci5ldnQuc3ViOTlbLWluZC5uYTk5XQogIHIuZW1wLnN1Yjk5IDwtIHIuZW1wLnN1Yjk5Wy1pbmQubmE5OV0KICByLmZwLnN1Yjk5IDwtIHIuZnAuc3ViOTlbLWluZC5uYTk5XQogIHlJLnN1Yjk5IDwtIHlJLnN1Yjk5Wy1pbmQubmE5OV0KfQoKCm05NSA8LSBsZW5ndGgoeUkuc3ViOTUpICNzdWItc2FtcGxlIHNpemUgZm9yIHE9MC45NQptOTkgPC0gbGVuZ3RoKHlJLnN1Yjk5KSAjc3ViLXNhbXBsZSBzaXplIGZvciBxPTAuOTkKCnJvdW5kKGMoc3VtKHlJLnN1Yjk1PnIuZXZ0LnN1Yjk1KS9tOTUqMTAwLHN1bSh5SS5zdWI5NT5yLmVtcC5zdWI5NSkvbTk1KjEwMCwgc3VtKHlJLnN1Yjk1PnIuZnAuc3ViOTUpL205NSoxMDAsIHN1bSh5SS5zdWI5OT5yLmV2dC5zdWI5OSkvbTk5KjEwMCwgc3VtKHlJLnN1Yjk5PnIuZW1wLnN1Yjk5KS9tOTkqMTAwLCBzdW0oeUkuc3ViOTk+ci5mcC5zdWI5OSkvbTk5KjEwMCksMikKYGBgCgojIyMjIEZyb20gYWJvdmUgbnVtYmVycywgRVZUIGxvb2tzIHdvcmsgcXVpdGUgd2VsbCBmb3IgaW4tc2FtcGxlIGFuYWx5c2lzLiBIb3dldmVyLCBjb21wYXJhdGl2ZSBiYWNrdGVzdGluZyBhbmQgVExNIHNlZW0gdG8gc3VnZ2VzdCB0aGF0IEVWVCBpcyB3b3JzZSB0aGFuIGVtcGlyaWNhbCBtZXRob2QuIEkgZG8gbm90IHVuZGVyc3RhbmQgd2h5IHdlIGdldCBkaWZmZXJlbnQgcmVzdXRscyBmcm9tIGRpZmZlcmVudCB0ZXN0cy4gCgpgYGB7cn0KY2N0IDwtIG1hdHJpeChucm93PTMsIG5jb2w9MikgIyBzaW1wbGUgJiBnZW5lcmFsIENDVAoKdG1wIDwtIGNjdC4ycy5WYVIoeD15SS5zdWI5NSwgcj1yLmV2dC5zdWI5NSxsZXY9MC45NSk7IGNjdFsxLF08LWModG1wJHB2LmF2Zyx0bXAkcHYuY29uZCkKdG1wIDwtIGNjdC4ycy5WYVIoeD15SS5zdWI5NSwgcj1yLmVtcC5zdWI5NSxsZXY9MC45NSk7IGNjdFsyLF08LWModG1wJHB2LmF2Zyx0bXAkcHYuY29uZCkKdG1wIDwtIGNjdC4ycy5WYVIoeD15SS5zdWI5NSwgcj1yLmZwLnN1Yjk1LGxldj0wLjk1KTsgY2N0WzMsXTwtYyh0bXAkcHYuYXZnLHRtcCRwdi5jb25kKQpyb3VuZChjY3QsMykKCnRtcCA8LSBjY3QuMnMuVmFSKHg9eUkuc3ViOTksIHI9ci5ldnQuc3ViOTksbGV2PTAuOTkpOyBjY3RbMSxdPC1jKHRtcCRwdi5hdmcsdG1wJHB2LmNvbmQpCnRtcCA8LSBjY3QuMnMuVmFSKHg9eUkuc3ViOTksIHI9ci5lbXAuc3ViOTksbGV2PTAuOTkpOyBjY3RbMixdPC1jKHRtcCRwdi5hdmcsdG1wJHB2LmNvbmQpCnRtcCA8LSBjY3QuMnMuVmFSKHg9eUkuc3ViOTksIHI9ci5mcC5zdWI5OSxsZXY9MC45OSk7IGNjdFszLF08LWModG1wJHB2LmF2Zyx0bXAkcHYuY29uZCkKcm91bmQoY2N0LDMpCgoKIyMgT05FLVNJREVEIFRFU1Qgb2Ygc3VwZXItY2FsaWJyYXRpb24gYXMgaW4gQmFzZWwgQWNjb3JkCmNjdC4xcyA8LSBtYXRyaXgobnJvdz0zLCBuY29sPTIpICMgc2ltcGxlICYgZ2VuZXJhbCBvbmUtc2lkZWQgQ0NUIG9mIHN1cGVyLWNhbGlicmF0aW9uCnRtcCA8LSBjY3QuMXMuVmFSKHg9eUkuc3ViOTUsIHI9ci5ldnQuc3ViOTUsbGV2PTAuOTUpOyBjY3QuMXNbMSxdPC1jKHRtcCRwdi5hdmcsdG1wJHB2LmNvbmQpCnRtcCA8LSBjY3QuMXMuVmFSKHg9eUkuc3ViOTUsIHI9ci5lbXAuc3ViOTUsbGV2PTAuOTUpOyBjY3QuMXNbMixdPC1jKHRtcCRwdi5hdmcsdG1wJHB2LmNvbmQpCnRtcCA8LSBjY3QuMXMuVmFSKHg9eUkuc3ViOTUsIHI9ci5mcC5zdWI5NSxsZXY9MC45NSk7IGNjdC4xc1szLF08LWModG1wJHB2LmF2Zyx0bXAkcHYuY29uZCkKcm91bmQoY2N0LjFzLDMpCgpjY3QuMXMgPC0gbWF0cml4KG5yb3c9MywgbmNvbD0yKSAjIHNpbXBsZSAmIGdlbmVyYWwgb25lLXNpZGVkIENDVCBvZiBzdXBlci1jYWxpYnJhdGlvbgp0bXAgPC0gY2N0LjFzLlZhUih4PXlJLnN1Yjk5LCByPXIuZXZ0LnN1Yjk5LGxldj0wLjk5KTsgY2N0LjFzWzEsXTwtYyh0bXAkcHYuYXZnLHRtcCRwdi5jb25kKQp0bXAgPC0gY2N0LjFzLlZhUih4PXlJLnN1Yjk5LCByPXIuZW1wLnN1Yjk5LGxldj0wLjk5KTsgY2N0LjFzWzIsXTwtYyh0bXAkcHYuYXZnLHRtcCRwdi5jb25kKQp0bXAgPC0gY2N0LjFzLlZhUih4PXlJLnN1Yjk5LCByPXIuZnAuc3ViOTksbGV2PTAuOTkpOyBjY3QuMXNbMyxdPC1jKHRtcCRwdi5hdmcsdG1wJHB2LmNvbmQpCnJvdW5kKGNjdC4xcywzKQoKIyMgQ29tcGFyYXRpdmUgYmFja3Rlc3RpbmcKIyMgcT0uOTUKc21hdCA8LSBtYXRyaXgobnJvdz0zLCBuY29sPTEpCnNtYXRbMSwxXSA8LSBtZWFuKHNmVmFSKHI9ci5ldnQuc3ViOTUseD15SS5zdWI5NSxhPTAuOTUsaD0xKSkKc21hdFsyLDFdIDwtIG1lYW4oc2ZWYVIocj1yLmVtcC5zdWI5NSx4PXlJLnN1Yjk1LGE9MC45NSxoPTEpKQpzbWF0WzMsMV0gPC0gbWVhbihzZlZhUihyPXIuZnAuc3ViOTUseD15SS5zdWI5NSxhPTAuOTUsaD0xKSkKYXBwbHkoc21hdCwyLCJyYW5rIikKCiMjIHE9Ljk5CnNtYXQgPC0gbWF0cml4KG5yb3c9MywgbmNvbD0xKQpzbWF0WzEsMV0gPC0gbWVhbihzZlZhUihyPXIuZXZ0LnN1Yjk5LHg9eUkuc3ViOTksYT0wLjk5LGg9MSkpCnNtYXRbMiwxXSA8LSBtZWFuKHNmVmFSKHI9ci5lbXAuc3ViOTkseD15SS5zdWI5OSxhPTAuOTksaD0xKSkKc21hdFszLDFdIDwtIG1lYW4oc2ZWYVIocj1yLmZwLnN1Yjk5LHg9eUkuc3ViOTksYT0wLjk5LGg9MSkpCmFwcGx5KHNtYXQsMiwicmFuayIpCgojIyBUTE0Kcm09MQp0bG05NSA8LSBUTE1mbihyPXJiaW5kKHIuZXZ0LnN1Yjk1LHIuZW1wLnN1Yjk1LHIuZnAuc3ViOTUpLCB5PXlJLnN1Yjk1LCBybT1ybSwgbGV2PTAuOTUsaD0xKQpwbG90VExNKHRsbTk1JFRMTTEwLCBybT0xLCBsZXY9MC45NSxtZXRob2Q9YygiZXZ0IiwiZW1wIiwic3QiKSkKCnRsbTk5IDwtIFRMTWZuKHI9cmJpbmQoci5ldnQuc3ViOTksci5lbXAuc3ViOTksci5mcC5zdWI5OSksIHk9eUkuc3ViOTksIHJtPXJtLCBsZXY9MC45OSxoPTEpCnBsb3RUTE0odGxtOTkkVExNMTAsIHJtPTEsIGxldj0wLjk5LG1ldGhvZD1jKCJldnQiLCJlbXAiLCJzdCIpKQpgYGAKCmBgYHtyfQpwbG90KHIuZnAuc3ViOTksIHR5cGUgPSAibCIsIGNvbCA9ICJibHVlIiwgeWxpbSA9ICBjKC0wLjAzLDAuNCksIGx0eSA9IDMsIHlsYWIgPSAiUmV0dXJuIikKcG9pbnRzKHlJLnN1Yjk5LCB0eXBlID0gImwiLCBjb2wgPSAiYmxhY2siLCBsdHkgPSAxKQpwb2ludHMoci5ldnQuc3ViOTksIHR5cGUgPSAibCIsIGNvbCA9ICJyZWQiLCBsdHkgPSAyKQpsZWdlbmQoInRvcHJpZ2h0IiwgbGVnZW5kID0gYygiRlAiLCAiRVZUIiwgIkxvc3MiKSwgY29sID0gYygiYmx1ZSIsICJyZWQiLCAiYmxhY2siKSwgbHR5ID0gYygzLDIsMSkpCmBgYAoKYGBge3J9CnBsb3QoeUksIHlsYWI9IiIsIHlsaW09YygtLjEyLDAuNCksIGNvbD0iZ3JheSIseGxhYj0iIiwgbWFpbj0iR0UiLCBjZXgubWFpbj0wLjgsIGx0eSA9IDEpCmxpbmVzKHRpbWUoeUkpLGNvdmFyLkdFWywxXSwgY29sPSJyZWQiLCBsdHkgPSAyKQpsaW5lcyh0aW1lKHlJKSxjb3Zhci5HRVssNV0sIGNvbD0iYmxhY2siLCBsdHkgPSAzKQpsaW5lcyh0aW1lKHlJKSxjb3Zhci5HRVssM10sIGNvbD0iZ3JlZW4iLCBsdHkgPSA0KQpsZWdlbmQoInRvcGxlZnQiLCBsZWdlbmQgPSBjKCJTUDUwMCIsICJFVlQiLCAiRlAiLCAiSFMiKSwgY29sID0gYygiZ3JleSIsICJyZWQiLCAiYmxhY2siLCAiZ3JlZW4iKSwgbHR5ID0gYygxLDIsMyw0KSkKYGBgCgo=