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
## identify subsample where L[t+1]^j > VaR[t+1]^j
n=dim(covar.KO)[1]
end = nrow(r.KO) + 1
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)]
# 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)]
y <- loss.BA
rmat <- var.BA
covar <- covar.BA
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.147774 1.249532

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] 12.84 10.30  8.36  3.07 20.86  4.29
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.002 0.006
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.129 0.298
[2,] 0.000 0.000
[3,] 0.041 0.120
## 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.003
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.064 0.193
[2,] 0.000 0.000
[3,] 0.020 0.052
## 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 BA 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.BA <- -r.BA$r[(end-n):(end-1)]
y <- loss.BA
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.8982417 0.5836139
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] 6.51 2.37 4.14 2.74 1.37 4.11

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.169 0.143
[2,] 0.000 0.000
[3,] 0.333 0.163
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.365 0.239
[2,] 0.786 0.581
[3,] 0.186 0.090
## 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.085 0.254
[2,] 1.000 1.000
[3,] 0.834 1.000
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.183 0.333
[2,] 0.393 1.000
[3,] 0.093 0.190
## 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="BA", cex.main=0.8, lty = 1)
lines(time(yI),covar.BA[,1], col="red", lty = 2)
lines(time(yI),covar.BA[,5], col="black", lty = 3)
lines(time(yI),covar.BA[,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))

LS0tCnRpdGxlOiAiQ29WYVIgLS0gQkEiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMjIyBQcmVwYXJlIERhdGE6CgpgYGB7ciBpbmNsdWRlPVRSVUUsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZz1GQUxTRX0Kcm0obGlzdCA9IGxzKCkpCmxpYnJhcnkoInJ1Z2FyY2giKQpsaWJyYXJ5KCJmR2FyY2giKQpsaWJyYXJ5KCJNQVNTIikKbGlicmFyeSgiaXNtZXYiKQojIGxpYnJhcnkoImxtb20iKQojIGxpYnJhcnkoIlFSTSIpCmxpYnJhcnkoInNrZXd0IikKbGlicmFyeSgiem9vIikKbGlicmFyeSgicGxvdHJpeCIpCgpzb3VyY2UoIn4vT25lRHJpdmUgLSBJTlNFQUQvU2tld0VsbGlwdC9Db2RlX1VwZGF0ZS9SZm5zLlIiKQpzZXR3ZCgifi9PbmVEcml2ZSAtIElOU0VBRC9Ta2V3RWxsaXB0L0NvZGVfVXBkYXRlL05hdGFsaWEvb3V0NTAwLyIpCiMjPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMjIEJhY2t0ZXN0aW5nIENvVmFSCiMjPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CgpkYXQgPSBmcmVhZCgifi9PbmVEcml2ZSAtIElOU0VBRC9Ta2V3RWxsaXB0L0NvZGVfVXBkYXRlL05hdGFsaWEvUmV0X2RhdGEuY3N2IikgIyByYXcgZGF0YSBmaWxlICgxOTYyLzA3LzAyIC0gMjAxNy8wNy8zMSkKZGF0ID0gZGF0WyxgOj1gKFJFVD1hcy5udW1lcmljKGFzLmNoYXJhY3RlcihSRVQpKSwgU1A1MDAgPSBhcy5udW1lcmljKGFzLmNoYXJhY3RlcihTUDUwMCkpKV0KZGF0ID0gZGF0WyFpcy5uYShSRVQpXQpkYXQgPSB1bmlxdWUoZGF0LCBieSA9IGMoIlRJQ0tFUiIsICJkYXRlIikgKQpzZXRuYW1lcyhkYXQsICJSRVQiLCAiciIpCnIuS08gPSBkYXRbVElDS0VSID09ICdLTycsIGxpc3QoZGF0ZSwgVElDS0VSLCByLCBTUDUwMCldCnIuR0UgPSBkYXRbVElDS0VSID09ICdHRScsIGxpc3QoZGF0ZSwgVElDS0VSLCByLCBTUDUwMCldCnIuQkEgPSBkYXRbVElDS0VSID09ICdCQScsIGxpc3QoZGF0ZSwgVElDS0VSLCByLCBTUDUwMCldCnIuRElTID0gZGF0W1RJQ0tFUiA9PSAnRElTJywgbGlzdChkYXRlLCBUSUNLRVIsIHIsIFNQNTAwKV0KCmRhdC5pbmRpY2VzIDwtIHVuaXF1ZShkYXRhLmZyYW1lKGRhdCRkYXRlLGRhdCRSZXRfTSxkYXQkU1A1MDApKQpjb2xuYW1lcyhkYXQuaW5kaWNlcyk8LWMoImRhdGUiLCJyZXRNIiwic3A1MDAiKQpyTSA8LSB6b28oeD1kYXQuaW5kaWNlcyRyZXRNLG9yZGVyLmJ5ID0gc3RycHRpbWUoZGF0LmluZGljZXMkZGF0ZSwiJVklbSVkIikpCnJTUDwtIHpvbyh4PWRhdC5pbmRpY2VzJHNwNTAwLG9yZGVyLmJ5ID0gc3RycHRpbWUoZGF0LmluZGljZXMkZGF0ZSwiJVklbSVkIikpCgpsb2FkKCJDb1ZhUi5SREFUQSIpCiMgYXR0cmlidXRlcyhvdXQpCgojI2NvbHVtbnMgYXJlIDk1JSBDb1ZhUiBieSBFVlQgbWV0aG9kLCA5OSUgQ29WYVIgYnkgRVZUIG1ldGhvZCBhbmQgOTUlIENvVmFSIGJ5IGVtcGlyaWNhbCBtZXRob2QKCmNvdmFyLktPIDwtIG91dCRDb1ZhUi5LTwpjb3Zhci5CQSA8LSBvdXQkQ29WYVIuQkEKY292YXIuRElTIDwtIG91dCRDb1ZhUi5ESVMKIyBjb3Zhci5HRSA8LSBvdXQkQ29WYVIuR0UKCiMjIGlkZW50aWZ5IHN1YnNhbXBsZSB3aGVyZSBMW3QrMV1eaiA+IFZhUlt0KzFdXmoKbj1kaW0oY292YXIuS08pWzFdCmVuZCA9IG5yb3coci5LTykgKyAxCgpsb2FkKCJvdXRLTy5SREFUQSIpCnZhci5LTyA8LSBvdXQucCRzdEVWVFssMjozXQpsb3NzLktPIDwtIC1yLktPJHJbKGVuZC1uKTooZW5kLTEpXQoKbG9hZCgib3V0QkEuUkRBVEEiKQp2YXIuQkEgPC0gb3V0LnAkc3RFVlRbLDI6M10KbG9zcy5CQSA8LSAtci5CQSRyWyhlbmQtbik6KGVuZC0xKV0KCgpsb2FkKCJvdXRESVMuUkRBVEEiKQp2YXIuRElTIDwtIG91dC5wJHN0RVZUWywyOjNdCmxvc3MuRElTIDwtIC1yLkRJUyRyWyhlbmQtbik6KGVuZC0xKV0KIyBjb3Zhci5HRSA8LSBvdXQkQ29WYVIuR0UKYGBgCgoKIyMjIE91dC1vZi1zYW1wbGUgVGVzdApXZSBjYWxjdWFsdGUgb25lLWRheSBhaGVhZCBwcmVkaWN0ZWQgVmFSIGFuZCBDb1ZhUiB1c2luZyBwYXN0IDUwMCBkYXlzIChyb2xsb2luZyB3aW5kb3cpIGFuZCB0aGVuIG1hdGNoIHdpdGggbG9zcyBzZXJpZXMuIFNwZWNpZmljYWxseSwgd2UgdXNlIGRhdGEgZnJvbSBkYXkgMSB0byA1MDAgdG8gZml0IEdhcmNoIG1vZGVsIGFuZCBnZXQgcmVzaWR1YWwgc2VyaWVzIGFuZCBwcmVkaWN0ZWQgbXUgYW5kIHNpZ21hbC4gVGhlbiB3ZSBjYWxjdWxhdGUgb25lLWRheSBhaGVhZCBwcmVkaWN0ZWQgVmFSIGFuZCBDb1ZhUiwgdGhhdCBpcyBkYXkgNTAxIFZhUiBhbmQgQ29WYVIuCgoKYGBge3IsbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIyBpZGVudGlmeSBzdWJzYW1wbGUgd2hlcmUgTFt0KzFdXmogPiBWYVJbdCsxXV5qCm49ZGltKGNvdmFyLktPKVsxXQplbmQgPSBucm93KHIuS08pICsgMQpzZXR3ZCgifi9PbmVEcml2ZSAtIElOU0VBRC9Ta2V3RWxsaXB0L0NvZGVfVXBkYXRlL05hdGFsaWEvb3V0NTAwLyIpCmxvYWQoIm91dEtPLlJEQVRBIikKdmFyLktPIDwtIG91dC5wJHN0RVZUWywyOjNdCmxvc3MuS08gPC0gLXIuS08kclsoZW5kLW4pOihlbmQtMSldCgpsb2FkKCJvdXRCQS5SREFUQSIpCnZhci5CQSA8LSBvdXQucCRzdEVWVFssMjozXQpsb3NzLkJBIDwtIC1yLkJBJHJbKGVuZC1uKTooZW5kLTEpXQoKbG9hZCgib3V0RElTLlJEQVRBIikKdmFyLkRJUyA8LSBvdXQucCRzdEVWVFssMjozXQpsb3NzLkRJUyA8LSAtci5ESVMkclsoZW5kLW4pOihlbmQtMSldCmBgYAoKYGBge3J9CnkgPC0gbG9zcy5CQQpybWF0IDwtIHZhci5CQQpjb3ZhciA8LSBjb3Zhci5CQQp5SSA8LSBhcy52ZWN0b3IoLXJTUFsoZW5kLW4pOihlbmQtMSldKQpgYGAKCldlIGNoZWNrIHRoZSBwZXJmb3JtYW5jZSBvZiBwcmVkaWN0ZWQgVmFSOgpgYGB7cn0Kaz1kaW0ocm1hdClbMl0gIyBudW1iZXIgb2YgbWV0aG9kcy9jYXNlcwp5bWF0ID0gbWF0cml4KHJlcCh5LCBrKSwgbmNvbCA9IGssIGJ5cm93PUZBTFNFKQpobWF0ID0gKHltYXQgPiBybWF0KQoKYXBwbHkoaG1hdCwyLCJzdW0iLG5hLnJtPVQpL24qMTAwCmBgYAoKV2UgY2hlY2sgdGhlIHBlcmZvcm1hbmNlIG9mIHByZWRpY3RlZCBDb1ZhUjoKYGBge3J9CnIuZXZ0LnN1Yjk1IDwtIHN1YnNldChjb3ZhclssMV0saG1hdFssMV0pCnIuZXZ0LnN1Yjk5IDwtIHN1YnNldChjb3ZhclssMl0saG1hdFssMl0pCnIuZW1wLnN1Yjk1IDwtIHN1YnNldChjb3ZhclssM10saG1hdFssMV0pCnIuZW1wLnN1Yjk5IDwtIHN1YnNldChjb3ZhclssNF0saG1hdFssMl0pCnIuZnAuc3ViOTUgPC0gIHN1YnNldChjb3ZhclssNV0saG1hdFssMV0pCnIuZnAuc3ViOTkgPC0gIHN1YnNldChjb3ZhclssNl0saG1hdFssMl0pCgojIyBDaGVja2luZyAlIHZpb2xhdGlvbnMgb2YgQ29WYVIgYnkgdGhlIGluZGV4IGxvc3Nlcwp5SS5zdWI5NSA8LSBhcy5udW1lcmljKHN1YnNldCh5SSwgaG1hdFssMV0pKQp5SS5zdWI5OSA8LSBhcy5udW1lcmljKHN1YnNldCh5SSwgaG1hdFssMl0pKQoKIyBSZW1vdmUgTkEgdmFsdWVzCnIuc3ViOTUgPSByYmluZChyLmV2dC5zdWI5NSxyLmVtcC5zdWI5NSwgci5mcC5zdWI5NSkKaW5kLm5hOTUgPSB3aGljaCggKGlzLm5hKGFwcGx5KHIuc3ViOTUsMixzdW0pKSkgKQoKci5zdWI5OSA9IHJiaW5kKHIuZXZ0LnN1Yjk5LHIuZW1wLnN1Yjk5LCByLmZwLnN1Yjk5KQppbmQubmE5OSA9IHdoaWNoKChpcy5uYShhcHBseShyLnN1Yjk5LDIsc3VtKSkpICkKCmlmIChsZW5ndGgoaW5kLm5hOTUpPjApewogIHIuZXZ0LnN1Yjk1IDwtIHIuZXZ0LnN1Yjk1Wy1pbmQubmE5NV0KICByLmVtcC5zdWI5NSA8LSByLmVtcC5zdWI5NVstaW5kLm5hOTVdCiAgci5mcC5zdWI5NSA8LSByLmZwLnN1Yjk1Wy1pbmQubmE5NV0KICB5SS5zdWI5NSA8LSB5SS5zdWI5NVstaW5kLm5hOTVdCn0KaWYgKGxlbmd0aChpbmQubmE5OSk+MCl7CiAgci5ldnQuc3ViOTkgPC0gci5ldnQuc3ViOTlbLWluZC5uYTk5XQogIHIuZW1wLnN1Yjk5IDwtIHIuZW1wLnN1Yjk5Wy1pbmQubmE5OV0KICByLmZwLnN1Yjk5IDwtIHIuZnAuc3ViOTlbLWluZC5uYTk5XQogIHlJLnN1Yjk5IDwtIHlJLnN1Yjk5Wy1pbmQubmE5OV0KfQoKCm05NSA8LSBsZW5ndGgoeUkuc3ViOTUpICNzdWItc2FtcGxlIHNpemUgZm9yIHE9MC45NQptOTkgPC0gbGVuZ3RoKHlJLnN1Yjk5KSAjc3ViLXNhbXBsZSBzaXplIGZvciBxPTAuOTkKCnJvdW5kKGMoc3VtKHlJLnN1Yjk1PnIuZXZ0LnN1Yjk1KS9tOTUqMTAwLHN1bSh5SS5zdWI5NT5yLmVtcC5zdWI5NSkvbTk1KjEwMCwgc3VtKHlJLnN1Yjk1PnIuZnAuc3ViOTUpL205NSoxMDAsIHN1bSh5SS5zdWI5OT5yLmV2dC5zdWI5OSkvbTk5KjEwMCwgc3VtKHlJLnN1Yjk5PnIuZW1wLnN1Yjk5KS9tOTkqMTAwLCBzdW0oeUkuc3ViOTk+ci5mcC5zdWI5OSkvbTk5KjEwMCksMikKYGBgCgojIyMjIyBUaGUgRVZUIG1ldGhvZCBkb2VzIG5vdCBwZXJmb3JtIHdlbGwgZm9yIDk1JSBDb1ZhUiBlc3RpbWF0aW9uIGJ1dCByZWxhdGl2ZWx5IGdvb2QgZm9yIDk5JSBDb1ZhUiBlc3RpbWF0aW9uLiBTaW1wbGUgQ0NUIGlzIGNvbnNpc3RlbnQgd2l0aCB0aGlzIHJlc3VsdCwgYnV0IGNvbXBhcmF0aXZlIGJhY2t0ZXN0aW5nICBhbmQgVExNIHN1Z2dlc3RzIHRoYXQgRlAgaXMgc2xpZ2h0bHkgYmV0dGVyIHRoYW4gRVZULiAgSW4gc3VtbWFyeSwgRVZUIGFuZCBGUCBpcyBzaWduaWZpY2FudGx5IGJldHRlciB0aGFuIGVtcGlyaWNhbCBtZXRob2QgYXQgMTAlIGxldmVsIGZvciBlc3RpbWF0aW9uIDk5JSBDb1ZhUiwgYnV0IEVWVCBhbmQgRlAgYXJlIHF1aXRlIHNpbWlsYXIuCgoKYGBge3J9CmNjdCA8LSBtYXRyaXgobnJvdz0zLCBuY29sPTIpICMgc2ltcGxlICYgZ2VuZXJhbCBDQ1QKCnRtcCA8LSBjY3QuMnMuVmFSKHg9eUkuc3ViOTUsIHI9ci5ldnQuc3ViOTUsbGV2PTAuOTUpOyBjY3RbMSxdPC1jKHRtcCRwdi5hdmcsdG1wJHB2LmNvbmQpCnRtcCA8LSBjY3QuMnMuVmFSKHg9eUkuc3ViOTUsIHI9ci5lbXAuc3ViOTUsbGV2PTAuOTUpOyBjY3RbMixdPC1jKHRtcCRwdi5hdmcsdG1wJHB2LmNvbmQpCnRtcCA8LSBjY3QuMnMuVmFSKHg9eUkuc3ViOTUsIHI9ci5mcC5zdWI5NSxsZXY9MC45NSk7IGNjdFszLF08LWModG1wJHB2LmF2Zyx0bXAkcHYuY29uZCkKcm91bmQoY2N0LDMpCgp0bXAgPC0gY2N0LjJzLlZhUih4PXlJLnN1Yjk5LCByPXIuZXZ0LnN1Yjk5LGxldj0wLjk5KTsgY2N0WzEsXTwtYyh0bXAkcHYuYXZnLHRtcCRwdi5jb25kKQp0bXAgPC0gY2N0LjJzLlZhUih4PXlJLnN1Yjk5LCByPXIuZW1wLnN1Yjk5LGxldj0wLjk5KTsgY2N0WzIsXTwtYyh0bXAkcHYuYXZnLHRtcCRwdi5jb25kKQp0bXAgPC0gY2N0LjJzLlZhUih4PXlJLnN1Yjk5LCByPXIuZnAuc3ViOTksbGV2PTAuOTkpOyBjY3RbMyxdPC1jKHRtcCRwdi5hdmcsdG1wJHB2LmNvbmQpCnJvdW5kKGNjdCwzKQoKCiMjIE9ORS1TSURFRCBURVNUIG9mIHN1cGVyLWNhbGlicmF0aW9uIGFzIGluIEJhc2VsIEFjY29yZApjY3QuMXMgPC0gbWF0cml4KG5yb3c9MywgbmNvbD0yKSAjIHNpbXBsZSAmIGdlbmVyYWwgb25lLXNpZGVkIENDVCBvZiBzdXBlci1jYWxpYnJhdGlvbgp0bXAgPC0gY2N0LjFzLlZhUih4PXlJLnN1Yjk1LCByPXIuZXZ0LnN1Yjk1LGxldj0wLjk1KTsgY2N0LjFzWzEsXTwtYyh0bXAkcHYuYXZnLHRtcCRwdi5jb25kKQp0bXAgPC0gY2N0LjFzLlZhUih4PXlJLnN1Yjk1LCByPXIuZW1wLnN1Yjk1LGxldj0wLjk1KTsgY2N0LjFzWzIsXTwtYyh0bXAkcHYuYXZnLHRtcCRwdi5jb25kKQp0bXAgPC0gY2N0LjFzLlZhUih4PXlJLnN1Yjk1LCByPXIuZnAuc3ViOTUsbGV2PTAuOTUpOyBjY3QuMXNbMyxdPC1jKHRtcCRwdi5hdmcsdG1wJHB2LmNvbmQpCnJvdW5kKGNjdC4xcywzKQoKY2N0LjFzIDwtIG1hdHJpeChucm93PTMsIG5jb2w9MikgIyBzaW1wbGUgJiBnZW5lcmFsIG9uZS1zaWRlZCBDQ1Qgb2Ygc3VwZXItY2FsaWJyYXRpb24KdG1wIDwtIGNjdC4xcy5WYVIoeD15SS5zdWI5OSwgcj1yLmV2dC5zdWI5OSxsZXY9MC45OSk7IGNjdC4xc1sxLF08LWModG1wJHB2LmF2Zyx0bXAkcHYuY29uZCkKdG1wIDwtIGNjdC4xcy5WYVIoeD15SS5zdWI5OSwgcj1yLmVtcC5zdWI5OSxsZXY9MC45OSk7IGNjdC4xc1syLF08LWModG1wJHB2LmF2Zyx0bXAkcHYuY29uZCkKdG1wIDwtIGNjdC4xcy5WYVIoeD15SS5zdWI5OSwgcj1yLmZwLnN1Yjk5LGxldj0wLjk5KTsgY2N0LjFzWzMsXTwtYyh0bXAkcHYuYXZnLHRtcCRwdi5jb25kKQpyb3VuZChjY3QuMXMsMykKCiMjIENvbXBhcmF0aXZlIGJhY2t0ZXN0aW5nCiMjIHE9Ljk1CnNtYXQgPC0gbWF0cml4KG5yb3c9MywgbmNvbD0xKQpzbWF0WzEsMV0gPC0gbWVhbihzZlZhUihyPXIuZXZ0LnN1Yjk1LHg9eUkuc3ViOTUsYT0wLjk1LGg9MSkpCnNtYXRbMiwxXSA8LSBtZWFuKHNmVmFSKHI9ci5lbXAuc3ViOTUseD15SS5zdWI5NSxhPTAuOTUsaD0xKSkKc21hdFszLDFdIDwtIG1lYW4oc2ZWYVIocj1yLmZwLnN1Yjk1LHg9eUkuc3ViOTUsYT0wLjk1LGg9MSkpCmFwcGx5KHNtYXQsMiwicmFuayIpCgojIyBxPS45OQpzbWF0IDwtIG1hdHJpeChucm93PTMsIG5jb2w9MSkKc21hdFsxLDFdIDwtIG1lYW4oc2ZWYVIocj1yLmV2dC5zdWI5OSx4PXlJLnN1Yjk5LGE9MC45OSxoPTEpKQpzbWF0WzIsMV0gPC0gbWVhbihzZlZhUihyPXIuZW1wLnN1Yjk5LHg9eUkuc3ViOTksYT0wLjk5LGg9MSkpCnNtYXRbMywxXSA8LSBtZWFuKHNmVmFSKHI9ci5mcC5zdWI5OSx4PXlJLnN1Yjk5LGE9MC45OSxoPTEpKQphcHBseShzbWF0LDIsInJhbmsiKQoKIyMgVExNCnJtPTEKdGxtOTUgPC0gVExNZm4ocj1yYmluZChyLmV2dC5zdWI5NSxyLmVtcC5zdWI5NSxyLmZwLnN1Yjk1KSwgeT15SS5zdWI5NSwgcm09cm0sIGxldj0wLjk1LGg9MSkKcGxvdFRMTSh0bG05NSRUTE0xMCwgcm09MSwgbGV2PTAuOTUsbWV0aG9kPWMoImV2dCIsImVtcCIsInN0IikpCgp0bG05OSA8LSBUTE1mbihyPXJiaW5kKHIuZXZ0LnN1Yjk5LHIuZW1wLnN1Yjk5LHIuZnAuc3ViOTkpLCB5PXlJLnN1Yjk5LCBybT1ybSwgbGV2PTAuOTksaD0xKQpwbG90VExNKHRsbTk5JFRMTTEwLCBybT0xLCBsZXY9MC45OSxtZXRob2Q9YygiZXZ0IiwiZW1wIiwic3QiKSkKYGBgCgoKCiMjIyBJbi1TYW1wbGUgVGVzdApIb3dldmVyLCB3ZSBjYW4gc2hvdyB0aGF0IG1vdmVtZW50IGluIENvVmFSIGlzIGRyaXZlbiBieSB0aGUgcHJlZGljdCBzaWdtYWwgZnJvbSBHYXJjaCBtb2RlbCwgYW5kIHRoZSBwcmVkaWN0ZWQgc2lnbWFsIHNoYXJlcyB0aGUgc2ltaWxhciBwYXR0ZXJuIG9mIGxhZ2dlZCBsb3NzIHNlcmllcy4gVGhlIGZpZ3VyZSBibG93IHBsb3RzIHN1YnNhbXBsZSB3aXRoIDEwMCBkYXlzIGZvciBTUDUwMCBsb3NzIHNlcmllcy4gQXMgc2hvd24gaW4gdGhlIGZpZ3VyZSwgdGhlIHBlYWtzIG9mIHNpZ21hX1NQNTAwIGFyZSBpbiBsaW5lIHdpdGggQ29WYVIgZnJvbSBFVlQgYW5kIEZQLCBidXQgYXJlIG9uZS1wZXJpb2QgaGVhZCBvZiBsb3NzIHNlcmllcyAoc2VlIHgtYXhpcyA4MC0xMDApLiBUaGlzIHJlc3VsdCBjb21lcyBmcm9tIHRoZSBmYWN0IHRoYXQgcHJlZGljdGVkIHNpZ21hIGlzIGhlYXZpbHkgYWZmZWN0ZWQgYnkgdGhlIG1vc3QgcmVjZW50IGRhdGEuIFdoZW4gdGhlcmUgaXMgYSBoaWdoIHJldXRybiAob3IgbG9zcykgdG9kYXksIHRoZSBwcmVkaWN0ZWQgdm9sYXRpbGl0eSB3aWxsIGJlIHZlcnkgaGlnaCB0b21vcnJvdy4KCmBgYHtyIGluY2x1ZGU9VFJVRSwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nPUZBTFNFfQpwbG90KGNvdmFyWzU4MDA6NTkwMCwxXSwgdHlwZSA9ICJsIiwgY29sID0gImJsdWUiLCB5bGltID0gIGMoLTAuMSwwLjIpLCBsdHkgPSAzLCB5bGFiID0gIlJldHVybiIpCnBvaW50cyhjb3Zhcls1ODAwOjU5MDAsNV0sIHR5cGUgPSAibCIsIGNvbCA9ICJibGFjayIsIGx0eSA9IDEpCnBvaW50cyh5SVs1ODAwOjU5MDBdLCB0eXBlID0gImwiLCBjb2wgPSAicmVkIiwgbHR5ID0gMikKc2V0d2QoIn4vT25lRHJpdmUgLSBJTlNFQUQvU2tld0VsbGlwdC9Db2RlX1VwZGF0ZS9OYXRhbGlhL291dDUwMC8iKQpsb2FkKCJvdXRTUDUwMC5SREFUQSIpCnBvaW50cyhvdXQucCRzaWd0LnN0WzU4MDA6NTkwMF0sIHR5cGUgPSAibCIsIGNvbCA9ICdncmVlbicsIGx0eSA9IDQpCmxlZ2VuZCgidG9wcmlnaHQiLCBsZWdlbmQgPSBjKCJFVlQiLCAiRlAiLCAiU1A1MDAiLCJzaWdtYV9TUDUwMCIpLCBjb2wgPSBjKCJibHVlIiwgImJsYWNrIiwgInJlZCIsImdyZWVuIiksIGx0eSA9IGMoMywxLDIsNCkpCmBgYAoKU2ltaWxhcmx5LCBpZiB3ZSBwbG90IHN1YnNhbXBsZSBpbiB3aGljaCBCQSBsb3NzIGlzIGJleW9uZCA5OSUgVmFSLCB0aGUgcGVha3Mgb2YgU1AwMCBhbmQgQ29WYVIgZnJvbSBkaWZmZXJlbnQgbWV0aG9kcyBhcmUgbm90IGFsaWduZWQuCmBgYHtyfQpwbG90KHIuZnAuc3ViOTksIHR5cGUgPSAibCIsIGNvbCA9ICJibHVlIiwgeWxpbSA9ICBjKC0wLjAzLDAuMyksIGx0eSA9IDMsIHlsYWIgPSAiUmV0dXJuIikKcG9pbnRzKHlJLnN1Yjk5LCB0eXBlID0gImwiLCBjb2wgPSAiYmxhY2siLCBsdHkgPSAxKQpwb2ludHMoci5ldnQuc3ViOTksIHR5cGUgPSAibCIsIGNvbCA9ICJyZWQiLCBsdHkgPSAyKQpsZWdlbmQoInRvcHJpZ2h0IiwgbGVnZW5kID0gYygiRlAiLCAiRVZUIiwgIkxvc3MiKSwgY29sID0gYygiYmx1ZSIsICJyZWQiLCAiYmxhY2siKSwgbHR5ID0gYygzLDIsMSkpCmBgYAoKCklmIHdlIHNoaWZ0IExvc3Mgc2VyaWVzIG9uZS1kYXkgYWhlYWQgKG9yIHNoaWZ0IENvVmFSIG9uZSBkYXkgb25lLWRheSBiYWNrd2FyZCksIHRoZW4gdGhlIHBlYWtzIGFyZSBhbGlnbmVkLiBFc3NlbnRpYWxseSwgdGhpcyBpcyBpbi1zYW1wbGUgYW5hbHlzaXMuIFdlIGNvbXBhcmUgQ29WYVIgZXN0aWFtdGVkIHVzaW5nIGRheSAxIHRvIGRheSA1MDAgZGF0YSB3aXRoIGRheSA1MDAgbG9zcy4KCmBgYHtyLG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZz1GQUxTRX0KIyMgaWRlbnRpZnkgc3Vic2FtcGxlIHdoZXJlIExbdCsxXV5qID4gVmFSW3QrMV1eagpuPWRpbShjb3Zhci5LTylbMV0KZW5kID0gbnJvdyhyLktPKQoKbG9zcy5CQSA8LSAtci5CQSRyWyhlbmQtbik6KGVuZC0xKV0KeSA8LSBsb3NzLkJBCnlJIDwtIGFzLnZlY3RvcigtclNQWyhlbmQtbik6KGVuZC0xKV0pCgpwbG90KGNvdmFyWzU4MDA6NTkwMCwxXSwgdHlwZSA9ICJsIiwgY29sID0gImJsdWUiLCB5bGltID0gIGMoLTAuMSwwLjIpLCBsdHkgPSAzLCB5bGFiID0gIlJldHVybiIpCnBvaW50cyhjb3Zhcls1ODAwOjU5MDAsNV0sIHR5cGUgPSAibCIsIGNvbCA9ICJibGFjayIsIGx0eSA9IDEpCnBvaW50cyh5SVs1ODAwOjU5MDBdLCB0eXBlID0gImwiLCBjb2wgPSAicmVkIiwgbHR5ID0gMikKc2V0d2QoIn4vT25lRHJpdmUgLSBJTlNFQUQvU2tld0VsbGlwdC9Db2RlX1VwZGF0ZS9OYXRhbGlhL291dDUwMC8iKQpsb2FkKCJvdXRTUDUwMC5SREFUQSIpCnBvaW50cyhvdXQucCRzaWd0LnN0WzU4MDA6NTkwMF0sIHR5cGUgPSAibCIsIGNvbCA9ICdncmVlbicsIGx0eSA9IDQpCmxlZ2VuZCgidG9wcmlnaHQiLCBsZWdlbmQgPSBjKCJFVlQiLCAiRlAiLCAiU1A1MDAiLCJzaWdtYV9TUDUwMCIpLCBjb2wgPSBjKCJibHVlIiwgImJsYWNrIiwgInJlZCIsImdyZWVuIiksIGx0eSA9IGMoMywxLDIsNCkpCmBgYAoKCk5vdywgd2UgcmVwZWF0IGFsbCB0aGUgYW5hbHlzaXMgZm9yIGluLXNhbXBsZSBDb1ZhUi4KCgpgYGB7cn0Kaz1kaW0ocm1hdClbMl0gIyBudW1iZXIgb2YgbWV0aG9kcy9jYXNlcwp5bWF0ID0gbWF0cml4KHJlcCh5LCBrKSwgbmNvbCA9IGssIGJ5cm93PUZBTFNFKQpobWF0ID0gKHltYXQgPiBybWF0KQoKYXBwbHkoaG1hdCwyLCJzdW0iLG5hLnJtPVQpL24qMTAwCmBgYAoKCmBgYHtyfQpyLmV2dC5zdWI5NSA8LSBzdWJzZXQoY292YXJbLDFdLGhtYXRbLDFdKQpyLmV2dC5zdWI5OSA8LSBzdWJzZXQoY292YXJbLDJdLGhtYXRbLDJdKQpyLmVtcC5zdWI5NSA8LSBzdWJzZXQoY292YXJbLDNdLGhtYXRbLDFdKQpyLmVtcC5zdWI5OSA8LSBzdWJzZXQoY292YXJbLDRdLGhtYXRbLDJdKQpyLmZwLnN1Yjk1IDwtICBzdWJzZXQoY292YXJbLDVdLGhtYXRbLDFdKQpyLmZwLnN1Yjk5IDwtICBzdWJzZXQoY292YXJbLDZdLGhtYXRbLDJdKQoKIyMgQ2hlY2tpbmcgJSB2aW9sYXRpb25zIG9mIENvVmFSIGJ5IHRoZSBpbmRleCBsb3NzZXMKeUkuc3ViOTUgPC0gYXMubnVtZXJpYyhzdWJzZXQoeUksIGhtYXRbLDFdKSkKeUkuc3ViOTkgPC0gYXMubnVtZXJpYyhzdWJzZXQoeUksIGhtYXRbLDJdKSkKCiMgUmVtb3ZlIE5BIHZhbHVlcwpyLnN1Yjk1ID0gcmJpbmQoci5ldnQuc3ViOTUsci5lbXAuc3ViOTUsIHIuZnAuc3ViOTUpCmluZC5uYTk1ID0gd2hpY2goIChpcy5uYShhcHBseShyLnN1Yjk1LDIsc3VtKSkpICkKCnIuc3ViOTkgPSByYmluZChyLmV2dC5zdWI5OSxyLmVtcC5zdWI5OSwgci5mcC5zdWI5OSkKaW5kLm5hOTkgPSB3aGljaCgoaXMubmEoYXBwbHkoci5zdWI5OSwyLHN1bSkpKSApCgppZiAobGVuZ3RoKGluZC5uYTk1KT4wKXsKICByLmV2dC5zdWI5NSA8LSByLmV2dC5zdWI5NVstaW5kLm5hOTVdCiAgci5lbXAuc3ViOTUgPC0gci5lbXAuc3ViOTVbLWluZC5uYTk1XQogIHIuZnAuc3ViOTUgPC0gci5mcC5zdWI5NVstaW5kLm5hOTVdCiAgeUkuc3ViOTUgPC0geUkuc3ViOTVbLWluZC5uYTk1XQp9CmlmIChsZW5ndGgoaW5kLm5hOTkpPjApewogIHIuZXZ0LnN1Yjk5IDwtIHIuZXZ0LnN1Yjk5Wy1pbmQubmE5OV0KICByLmVtcC5zdWI5OSA8LSByLmVtcC5zdWI5OVstaW5kLm5hOTldCiAgci5mcC5zdWI5OSA8LSByLmZwLnN1Yjk5Wy1pbmQubmE5OV0KICB5SS5zdWI5OSA8LSB5SS5zdWI5OVstaW5kLm5hOTldCn0KCgptOTUgPC0gbGVuZ3RoKHlJLnN1Yjk1KSAjc3ViLXNhbXBsZSBzaXplIGZvciBxPTAuOTUKbTk5IDwtIGxlbmd0aCh5SS5zdWI5OSkgI3N1Yi1zYW1wbGUgc2l6ZSBmb3IgcT0wLjk5Cgpyb3VuZChjKHN1bSh5SS5zdWI5NT5yLmV2dC5zdWI5NSkvbTk1KjEwMCxzdW0oeUkuc3ViOTU+ci5lbXAuc3ViOTUpL205NSoxMDAsIHN1bSh5SS5zdWI5NT5yLmZwLnN1Yjk1KS9tOTUqMTAwLCBzdW0oeUkuc3ViOTk+ci5ldnQuc3ViOTkpL205OSoxMDAsIHN1bSh5SS5zdWI5OT5yLmVtcC5zdWI5OSkvbTk5KjEwMCwgc3VtKHlJLnN1Yjk5PnIuZnAuc3ViOTkpL205OSoxMDApLDIpCmBgYAoKIyMjIyBGcm9tIGFib3ZlIG51bWJlcnMsIEVWVCBsb29rcyB3b3JrIHF1aXRlIHdlbGwgZm9yIGluLXNhbXBsZSBhbmFseXNpcy4gSG93ZXZlciwgY29tcGFyYXRpdmUgYmFja3Rlc3RpbmcgYW5kIFRMTSBzZWVtIHRvIHN1Z2dlc3QgdGhhdCBFVlQgaXMgd29yc2UgdGhhbiBlbXBpcmljYWwgbWV0aG9kLiBJIGRvIG5vdCB1bmRlcnN0YW5kIHdoeSB3ZSBnZXQgZGlmZmVyZW50IHJlc3V0bHMgZnJvbSBkaWZmZXJlbnQgdGVzdHMuIAoKYGBge3J9CmNjdCA8LSBtYXRyaXgobnJvdz0zLCBuY29sPTIpICMgc2ltcGxlICYgZ2VuZXJhbCBDQ1QKCnRtcCA8LSBjY3QuMnMuVmFSKHg9eUkuc3ViOTUsIHI9ci5ldnQuc3ViOTUsbGV2PTAuOTUpOyBjY3RbMSxdPC1jKHRtcCRwdi5hdmcsdG1wJHB2LmNvbmQpCnRtcCA8LSBjY3QuMnMuVmFSKHg9eUkuc3ViOTUsIHI9ci5lbXAuc3ViOTUsbGV2PTAuOTUpOyBjY3RbMixdPC1jKHRtcCRwdi5hdmcsdG1wJHB2LmNvbmQpCnRtcCA8LSBjY3QuMnMuVmFSKHg9eUkuc3ViOTUsIHI9ci5mcC5zdWI5NSxsZXY9MC45NSk7IGNjdFszLF08LWModG1wJHB2LmF2Zyx0bXAkcHYuY29uZCkKcm91bmQoY2N0LDMpCgp0bXAgPC0gY2N0LjJzLlZhUih4PXlJLnN1Yjk5LCByPXIuZXZ0LnN1Yjk5LGxldj0wLjk5KTsgY2N0WzEsXTwtYyh0bXAkcHYuYXZnLHRtcCRwdi5jb25kKQp0bXAgPC0gY2N0LjJzLlZhUih4PXlJLnN1Yjk5LCByPXIuZW1wLnN1Yjk5LGxldj0wLjk5KTsgY2N0WzIsXTwtYyh0bXAkcHYuYXZnLHRtcCRwdi5jb25kKQp0bXAgPC0gY2N0LjJzLlZhUih4PXlJLnN1Yjk5LCByPXIuZnAuc3ViOTksbGV2PTAuOTkpOyBjY3RbMyxdPC1jKHRtcCRwdi5hdmcsdG1wJHB2LmNvbmQpCnJvdW5kKGNjdCwzKQoKCiMjIE9ORS1TSURFRCBURVNUIG9mIHN1cGVyLWNhbGlicmF0aW9uIGFzIGluIEJhc2VsIEFjY29yZApjY3QuMXMgPC0gbWF0cml4KG5yb3c9MywgbmNvbD0yKSAjIHNpbXBsZSAmIGdlbmVyYWwgb25lLXNpZGVkIENDVCBvZiBzdXBlci1jYWxpYnJhdGlvbgp0bXAgPC0gY2N0LjFzLlZhUih4PXlJLnN1Yjk1LCByPXIuZXZ0LnN1Yjk1LGxldj0wLjk1KTsgY2N0LjFzWzEsXTwtYyh0bXAkcHYuYXZnLHRtcCRwdi5jb25kKQp0bXAgPC0gY2N0LjFzLlZhUih4PXlJLnN1Yjk1LCByPXIuZW1wLnN1Yjk1LGxldj0wLjk1KTsgY2N0LjFzWzIsXTwtYyh0bXAkcHYuYXZnLHRtcCRwdi5jb25kKQp0bXAgPC0gY2N0LjFzLlZhUih4PXlJLnN1Yjk1LCByPXIuZnAuc3ViOTUsbGV2PTAuOTUpOyBjY3QuMXNbMyxdPC1jKHRtcCRwdi5hdmcsdG1wJHB2LmNvbmQpCnJvdW5kKGNjdC4xcywzKQoKY2N0LjFzIDwtIG1hdHJpeChucm93PTMsIG5jb2w9MikgIyBzaW1wbGUgJiBnZW5lcmFsIG9uZS1zaWRlZCBDQ1Qgb2Ygc3VwZXItY2FsaWJyYXRpb24KdG1wIDwtIGNjdC4xcy5WYVIoeD15SS5zdWI5OSwgcj1yLmV2dC5zdWI5OSxsZXY9MC45OSk7IGNjdC4xc1sxLF08LWModG1wJHB2LmF2Zyx0bXAkcHYuY29uZCkKdG1wIDwtIGNjdC4xcy5WYVIoeD15SS5zdWI5OSwgcj1yLmVtcC5zdWI5OSxsZXY9MC45OSk7IGNjdC4xc1syLF08LWModG1wJHB2LmF2Zyx0bXAkcHYuY29uZCkKdG1wIDwtIGNjdC4xcy5WYVIoeD15SS5zdWI5OSwgcj1yLmZwLnN1Yjk5LGxldj0wLjk5KTsgY2N0LjFzWzMsXTwtYyh0bXAkcHYuYXZnLHRtcCRwdi5jb25kKQpyb3VuZChjY3QuMXMsMykKCiMjIENvbXBhcmF0aXZlIGJhY2t0ZXN0aW5nCiMjIHE9Ljk1CnNtYXQgPC0gbWF0cml4KG5yb3c9MywgbmNvbD0xKQpzbWF0WzEsMV0gPC0gbWVhbihzZlZhUihyPXIuZXZ0LnN1Yjk1LHg9eUkuc3ViOTUsYT0wLjk1LGg9MSkpCnNtYXRbMiwxXSA8LSBtZWFuKHNmVmFSKHI9ci5lbXAuc3ViOTUseD15SS5zdWI5NSxhPTAuOTUsaD0xKSkKc21hdFszLDFdIDwtIG1lYW4oc2ZWYVIocj1yLmZwLnN1Yjk1LHg9eUkuc3ViOTUsYT0wLjk1LGg9MSkpCmFwcGx5KHNtYXQsMiwicmFuayIpCgojIyBxPS45OQpzbWF0IDwtIG1hdHJpeChucm93PTMsIG5jb2w9MSkKc21hdFsxLDFdIDwtIG1lYW4oc2ZWYVIocj1yLmV2dC5zdWI5OSx4PXlJLnN1Yjk5LGE9MC45OSxoPTEpKQpzbWF0WzIsMV0gPC0gbWVhbihzZlZhUihyPXIuZW1wLnN1Yjk5LHg9eUkuc3ViOTksYT0wLjk5LGg9MSkpCnNtYXRbMywxXSA8LSBtZWFuKHNmVmFSKHI9ci5mcC5zdWI5OSx4PXlJLnN1Yjk5LGE9MC45OSxoPTEpKQphcHBseShzbWF0LDIsInJhbmsiKQoKIyMgVExNCnJtPTEKdGxtOTUgPC0gVExNZm4ocj1yYmluZChyLmV2dC5zdWI5NSxyLmVtcC5zdWI5NSxyLmZwLnN1Yjk1KSwgeT15SS5zdWI5NSwgcm09cm0sIGxldj0wLjk1LGg9MSkKcGxvdFRMTSh0bG05NSRUTE0xMCwgcm09MSwgbGV2PTAuOTUsbWV0aG9kPWMoImV2dCIsImVtcCIsInN0IikpCgp0bG05OSA8LSBUTE1mbihyPXJiaW5kKHIuZXZ0LnN1Yjk5LHIuZW1wLnN1Yjk5LHIuZnAuc3ViOTkpLCB5PXlJLnN1Yjk5LCBybT1ybSwgbGV2PTAuOTksaD0xKQpwbG90VExNKHRsbTk5JFRMTTEwLCBybT0xLCBsZXY9MC45OSxtZXRob2Q9YygiZXZ0IiwiZW1wIiwic3QiKSkKYGBgCgpgYGB7cn0KcGxvdChyLmZwLnN1Yjk5LCB0eXBlID0gImwiLCBjb2wgPSAiYmx1ZSIsIHlsaW0gPSAgYygtMC4wMywwLjQpLCBsdHkgPSAzLCB5bGFiID0gIlJldHVybiIpCnBvaW50cyh5SS5zdWI5OSwgdHlwZSA9ICJsIiwgY29sID0gImJsYWNrIiwgbHR5ID0gMSkKcG9pbnRzKHIuZXZ0LnN1Yjk5LCB0eXBlID0gImwiLCBjb2wgPSAicmVkIiwgbHR5ID0gMikKbGVnZW5kKCJ0b3ByaWdodCIsIGxlZ2VuZCA9IGMoIkZQIiwgIkVWVCIsICJMb3NzIiksIGNvbCA9IGMoImJsdWUiLCAicmVkIiwgImJsYWNrIiksIGx0eSA9IGMoMywyLDEpKQpgYGAKCmBgYHtyfQpwbG90KHlJLCB5bGFiPSIiLCB5bGltPWMoLS4xMiwwLjQpLCBjb2w9ImdyYXkiLHhsYWI9IiIsIG1haW49IkJBIiwgY2V4Lm1haW49MC44LCBsdHkgPSAxKQpsaW5lcyh0aW1lKHlJKSxjb3Zhci5CQVssMV0sIGNvbD0icmVkIiwgbHR5ID0gMikKbGluZXModGltZSh5SSksY292YXIuQkFbLDVdLCBjb2w9ImJsYWNrIiwgbHR5ID0gMykKbGluZXModGltZSh5SSksY292YXIuQkFbLDNdLCBjb2w9ImdyZWVuIiwgbHR5ID0gNCkKbGVnZW5kKCJ0b3BsZWZ0IiwgbGVnZW5kID0gYygiU1A1MDAiLCAiRVZUIiwgIkZQIiwgIkhTIiksIGNvbCA9IGMoImdyZXkiLCAicmVkIiwgImJsYWNrIiwgImdyZWVuIiksIGx0eSA9IGMoMSwyLDMsNCkpCmBgYAoK