1 SP500 data

data = read.table("sp500.txt",header=TRUE)
n    = nrow(data)
data = data[n:1,]

attach(data)

ret = log(adjclose[2:n]/adjclose[1:(n-1)])
y   = ret-mean(ret)
n   = n - 1
par(mfrow=c(1,1))
ts.plot(adjclose,main=paste("May 9th 2017 - May 6th 2022\n n=",n+1,sep=""),ylab="Price")

par(mfrow=c(1,2))
ts.plot(ret,main=paste("May 10th 2017 - May 6th 2022\n n=",n,sep=""),ylab="Log-return")
hist(ret,breaks=seq(-max(abs(ret)),max(abs(ret)),length=50),prob=TRUE,xlab="Log-return",main="")

2 Model 1: iid Gaussian

y_t iid N(0,sig2)

sig.hat.1 = sqrt(mean(y^2))
sig.hat.1
## [1] 0.01272944

3 Gaussian vs Student’s \(t\)

xxx = seq(-10,10,length=1000)
par(mfrow=c(1,1))
plot(xxx,dnorm(xxx),type="l",xlab="x",ylab="Density")
lines(xxx,dt(xxx,df=1),col=2)
lines(xxx,dt(xxx,df=2),col=3)
lines(xxx,dt(xxx,df=30),col=4)
legend("topleft",legend=c("df=1","df=2","df=30","Gaussian"),col=c(2:4,1),lty=1,lwd=2)

par(mfrow=c(1,1))
plot(xxx,log(dnorm(xxx)),type="l",xlab="x",ylab="Log density")
lines(xxx,log(dt(xxx,df=1)),col=2)
lines(xxx,log(dt(xxx,df=2)),col=3)
lines(xxx,log(dt(xxx,df=30)),col=4)

4 Model 2: iid Student’s \(t\)

sigs = seq(0.001,0.15,length=1000)
nus  = c(1:30,seq(35,100,by=5),seq(200,1000,by=100))
nnu  = length(nus)
like = rep(0,1000)
sig.mle = rep(0,nnu)
likes = rep(0,nnu)
for (j in 1:nnu){
  for (i in 1:1000)
    like[i] = sum(dt(y/sigs[i],df=nus[j],log=TRUE))-n*log(sigs[i])
  sig.mle[j] = sigs[like==max(like)]
  likes[j] = like[like==max(like)]
}

sig.hat.2 = sig.mle[likes==max(likes)]
nu.hat = nus[likes==max(likes)]

c(sig.hat.1,sig.hat.2,nu.hat)
## [1] 0.012729444 0.005921922 2.000000000
par(mfrow=c(1,1))
plot(nus,sig.mle,ylim=range(sig.mle,sig.hat.1))
abline(h=sig.hat.1)

par(mfrow=c(1,1))
plot(likes,sig.mle,col=0)
text(likes,sig.mle,nus,cex=0.5)

par(mfrow=c(1,1))
xxx = seq(-max(abs(ret)),max(abs(ret)),length=1000)
xbreaks = seq(-max(abs(ret)),max(abs(ret)),length=50)
hist(ret,breaks=xbreaks,prob=TRUE,xlab="Log-return",main="")
lines(xxx,dnorm(xxx,0,sig.hat.1),col=2,lwd=3)
lines(xxx,dt(xxx/sig.hat.2,df=nu.hat)/sig.hat.2,col=4,lwd=2)

par(mfrow=c(1,1))
legends  = c("Data","Gaussian model","Student's t model")
alphas   = seq(0.01,0.99,by=0.02)
qdata    = quantile(ret,alphas)
qnormal  = qnorm(alphas,0,sig.hat.1)
qstudent = sig.hat.2*qt(alphas,df=nu.hat)
xrange   = range(qdata,qnormal,qstudent)
plot(qdata,alphas,type="l",xlim=xrange,ylab="Tail probabilities",xlab="Quantiles",lwd=2)
lines(qnormal,alphas,type="l",col=2,lwd=2)
lines(qstudent,alphas,type="l",col=4,lwd=2)
legend("topleft",legend=legends,col=c(1,2,4),lwd=3,lty=1)

5 Stochastic volatility models

Here we assume that \[\begin{eqnarray*} y_t &=& e^{h_t/2} \varepsilon_t\\ h_{t+1} &=& \mu + \phi (h_t-\mu) + \sigma u_t, \end{eqnarray*}\] with \(cor(\varepsilon_t,u_t)=\rho\).

5.1 SV, SVt, SVl, SVtl

Four models contemplated by Gregor Kastner’s R package stochvol:

  • SV with Gaussian errors (SV) \[ \varepsilon_t \sim N(0,1),\ u_t \sim N(0,1), \ \rho=0 \]

  • SV with Student’s \(t\) errors (SVt) \[ \varepsilon_t \sim t_\nu(0,1),\ u_t \sim N(0,1), \ \rho=0, \ \nu \ \mbox{unknown} \]

  • SV with Gaussian errors and leverage effect (SVl) \[ \varepsilon_t \sim N(0,1),\ u_t \sim N(0,1), \ \rho \ \mbox{unknown}, \]

  • SV with Student’s \(t\) errors and leverage effect (SVtl) \[ \varepsilon_t \sim N(0,1),\ u_t \sim N(0,1), \ \rho \ \mbox{unknown}, \ \nu \ \mbox{unknown} \]

5.2 Prior distributions

The package stochvol has the following default prior specifications: \[\begin{eqnarray*} \mu &\sim& N(0,100^2)\\ (\phi+1)/2 &\sim& Beta(5,1.5)\\ \sigma^2 &\sim& Gamma(1/2,1/2)\\ h_1 &\sim& N(\mu,\sigma^2/(1-\phi^2))\\ (\rho+1)/2 &\sim& Beta(4,4)\\ \nu &\sim& Exp(0.1) \end{eqnarray*}\]

5.3 References

  • Source: Modeling Univariate and Multivariate Stochastic Volatility in R with stochvol and factorstochvol - https://cran.r-project.org/web/packages/factorstochvol/vignettes/paper.pdf

  • Kastner (2016) Dealing with Stochastic Volatility in Time Series Using the R Package stochvol. Journal of Statistical Software, 69(5), 1-30. doi:10.18637/jss.v069.i05.

  • Kastner(2019) Sparse Bayesian Time-Varying Covariance Estimation in Many Dimensions. Journal of Econometrics, 210(1), 98-115. doi:10.1016/j.jeconom.2018.11.007.

  • Kastner and Fruhwirth-Schnatter (2014) Ancillarity-Sufficiency Interweaving Strategy (ASIS) for Boosting MCMC Estimation of Stochastic Volatility Models. Computational Statistics and Data Analysis, 76, 408–423. doi:10.1016/j.csda.2013.01.002.

  • Kastner, Fruhwirth-Schnatter and Lopes (2017) Efficient Bayesian Inference for Multivariate Factor Stochastic Volatility Models. Journal of Computational and Graphical Statistics, 26(4), 905–917. doi:10.1080/10618600.2017.1322091.

library("stochvol")
fit.sv   = svsample(ret,draws=1000,burnin=100,quiet=TRUE)
fit.svt  = svtsample(ret,draws=1000,burnin=100,quiet=TRUE)
fit.svl  = svlsample(ret,draws=1000,burnin=100,quiet=TRUE)
fit.svtl = svtlsample(ret,draws=1000,burnin=100,quiet=TRUE)

qlogvols = cbind(apply(fit.sv$latent[[1]],2,median),apply(fit.svt$latent[[1]],2,median),
apply(fit.svl$latent[[1]],2,median),apply(fit.svtl$latent[[1]],2,median))

qstd.sv   = t(apply(exp(fit.sv$latent[[1]]/2),2,quantile,c(0.05,0.5,0.95)))
qstd.svt  = t(apply(exp(fit.svt$latent[[1]]/2),2,quantile,c(0.05,0.5,0.95)))
qstd.svl  = t(apply(exp(fit.svl$latent[[1]]/2),2,quantile,c(0.05,0.5,0.95)))
qstd.svtl = t(apply(exp(fit.svtl$latent[[1]]/2),2,quantile,c(0.05,0.5,0.95)))
par(mfrow=c(2,3))
plot(density(exp(fit.sv$para[[1]][,1]/2)),xlab=expression(mu),main="",ylim=c(0,550),xlim=c(0.004,0.015))
lines(density(exp(fit.svt$para[[1]][,1]/2)),col=2)
lines(density(exp(fit.svl$para[[1]][,1]/2)),col=3)
lines(density(exp(fit.svtl$para[[1]][,1]/2)),col=4)
legend("topleft",legend=c("SV","SVt","SVl","SVtl"),col=1:4,lty=1)

plot(density(fit.sv$para[[1]][,2]),xlab=expression(phi),main="",ylim=c(0,50))
lines(density(fit.svt$para[[1]][,2]),col=2)
lines(density(fit.svl$para[[1]][,2]),col=3)
lines(density(fit.svtl$para[[1]][,2]),col=4)

plot(density(fit.sv$para[[1]][,3]),xlab=expression(sigma),main="",ylim=c(0,12))
lines(density(fit.svt$para[[1]][,3]),col=2)
lines(density(fit.svl$para[[1]][,3]),col=3)
lines(density(fit.svtl$para[[1]][,3]),col=4)

plot(density(fit.svt$para[[1]][,4]),xlab=expression(nu),main="",ylim=c(0,0.08))
lines(density(fit.svtl$para[[1]][,4]),col=2)

plot(density(fit.svl$para[[1]][,5]),xlab=expression(rho),main="",xlim=c(-0.9,-0.4))
lines(density(fit.svtl$para[[1]][,5]),col=2)

par(mfrow=c(1,1))
plot(qlogvols[,1],type="l",ylim=range(qlogvols),xlab="Time",ylab="Log volatilities")
lines(qlogvols[,2],col=2)
lines(qlogvols[,3],col=3)
lines(qlogvols[,4],col=4)

yrange = range(0,qstd.sv[,2],qstd.svt[,2],qstd.svl[,2],qstd.svtl[,2])
par(mfrow=c(1,1))
plot(qstd.sv[,2],ylab="Standard deviations",ylim=yrange,type="l",xlab="Time")
lines(qstd.svt[,2],col=2)
lines(qstd.svl[,2],col=3)
lines(qstd.svtl[,2],col=4)
legend("topleft",legend=c("SV","SVt","SVl","SVtl"),col=1:4,lty=1)

par(mfrow=c(2,2))
yrange = range(qstd.sv,qstd.svt,qstd.svl,qstd.svtl)
ts.plot(qstd.sv,ylab="Standard deviations",col=c(3,2,3),ylim=yrange)
lines(0.1*abs(ret),type="h");title("SV")
ts.plot(qstd.svt,ylab="Standard deviations",col=c(3,2,3),ylim=yrange)
lines(0.1*abs(ret),type="h");title("SVt")
ts.plot(qstd.svl,ylab="Standard deviations",col=c(3,2,3),ylim=yrange)
lines(0.1*abs(ret),type="h");title("SVl")
ts.plot(qstd.svtl,ylab="Standard deviations",col=c(3,2,3),ylim=yrange)
lines(0.1*abs(ret),type="h");title("SVtl")

par(mfrow=c(2,2))
for (i in 1:4){
  ind = ((i-1)*n/4+1):(i*n/4)
  yrange = range(0,qstd.sv[ind,2],qstd.svt[ind,2],qstd.svl[ind,2],qstd.svtl[ind,2])
  plot(ind,qstd.sv[ind,2],ylab="Standard deviations",ylim=yrange,type="l",xlab="Time")
  lines(ind,qstd.svt[ind,2],col=2)
  lines(ind,qstd.svl[ind,2],col=3)
  lines(ind,qstd.svtl[ind,2],col=4)
  lines(ind,0.3*abs(ret[ind]),type="h")
}
legend("topleft",legend=c("SV","SVt","SVl","SVtl"),col=1:4,lty=1)

LS0tCnRpdGxlOiAiU1A1MDAgcmV0dXJucyIKc3VidGl0bGU6ICJHYXVzc2lhbiwgU3R1ZGVudCdzICR0JCBvciBTVj8iCmF1dGhvcjogIkhlZGliZXJ0IEZyZWl0YXMgTG9wZXMiCmRhdGU6ICI1LzExLzIwMjIiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHRvY19kZXB0aDogMgogICAgdG9jX2Zsb2F0OiAKICAgICAgY29sbGFwc2VkOiBmYWxzZQogICAgICBzbW9vdGhfc2Nyb2xsOiBmYWxzZQogICAgY29kZV9kb3dubG9hZDogeWVzCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkKYGBgCgojIFNQNTAwIGRhdGEgCmBgYHtyfQpkYXRhID0gcmVhZC50YWJsZSgic3A1MDAudHh0IixoZWFkZXI9VFJVRSkKbiAgICA9IG5yb3coZGF0YSkKZGF0YSA9IGRhdGFbbjoxLF0KCmF0dGFjaChkYXRhKQoKcmV0ID0gbG9nKGFkamNsb3NlWzI6bl0vYWRqY2xvc2VbMToobi0xKV0pCnkgICA9IHJldC1tZWFuKHJldCkKbiAgID0gbiAtIDEKYGBgCgpgYGB7ciBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD02fQpwYXIobWZyb3c9YygxLDEpKQp0cy5wbG90KGFkamNsb3NlLG1haW49cGFzdGUoIk1heSA5dGggMjAxNyAtIE1heSA2dGggMjAyMlxuIG49IixuKzEsc2VwPSIiKSx5bGFiPSJQcmljZSIpCmBgYAoKYGBge3IgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTZ9CnBhcihtZnJvdz1jKDEsMikpCnRzLnBsb3QocmV0LG1haW49cGFzdGUoIk1heSAxMHRoIDIwMTcgLSBNYXkgNnRoIDIwMjJcbiBuPSIsbixzZXA9IiIpLHlsYWI9IkxvZy1yZXR1cm4iKQpoaXN0KHJldCxicmVha3M9c2VxKC1tYXgoYWJzKHJldCkpLG1heChhYnMocmV0KSksbGVuZ3RoPTUwKSxwcm9iPVRSVUUseGxhYj0iTG9nLXJldHVybiIsbWFpbj0iIikKYGBgCgojIE1vZGVsIDE6IGlpZCBHYXVzc2lhbgp5X3QgaWlkIE4oMCxzaWcyKQpgYGB7cn0Kc2lnLmhhdC4xID0gc3FydChtZWFuKHleMikpCnNpZy5oYXQuMQpgYGAKCiMgR2F1c3NpYW4gdnMgU3R1ZGVudCdzICR0JApgYGB7ciBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD02fQp4eHggPSBzZXEoLTEwLDEwLGxlbmd0aD0xMDAwKQpwYXIobWZyb3c9YygxLDEpKQpwbG90KHh4eCxkbm9ybSh4eHgpLHR5cGU9ImwiLHhsYWI9IngiLHlsYWI9IkRlbnNpdHkiKQpsaW5lcyh4eHgsZHQoeHh4LGRmPTEpLGNvbD0yKQpsaW5lcyh4eHgsZHQoeHh4LGRmPTIpLGNvbD0zKQpsaW5lcyh4eHgsZHQoeHh4LGRmPTMwKSxjb2w9NCkKbGVnZW5kKCJ0b3BsZWZ0IixsZWdlbmQ9YygiZGY9MSIsImRmPTIiLCJkZj0zMCIsIkdhdXNzaWFuIiksY29sPWMoMjo0LDEpLGx0eT0xLGx3ZD0yKQpgYGAKCmBgYHtyIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTZ9CnBhcihtZnJvdz1jKDEsMSkpCnBsb3QoeHh4LGxvZyhkbm9ybSh4eHgpKSx0eXBlPSJsIix4bGFiPSJ4Iix5bGFiPSJMb2cgZGVuc2l0eSIpCmxpbmVzKHh4eCxsb2coZHQoeHh4LGRmPTEpKSxjb2w9MikKbGluZXMoeHh4LGxvZyhkdCh4eHgsZGY9MikpLGNvbD0zKQpsaW5lcyh4eHgsbG9nKGR0KHh4eCxkZj0zMCkpLGNvbD00KQpgYGAKCiMgTW9kZWwgMjogaWlkIFN0dWRlbnQncyAkdCQKCmBgYHtyfQpzaWdzID0gc2VxKDAuMDAxLDAuMTUsbGVuZ3RoPTEwMDApCm51cyAgPSBjKDE6MzAsc2VxKDM1LDEwMCxieT01KSxzZXEoMjAwLDEwMDAsYnk9MTAwKSkKbm51ICA9IGxlbmd0aChudXMpCmxpa2UgPSByZXAoMCwxMDAwKQpzaWcubWxlID0gcmVwKDAsbm51KQpsaWtlcyA9IHJlcCgwLG5udSkKZm9yIChqIGluIDE6bm51KXsKICBmb3IgKGkgaW4gMToxMDAwKQogICAgbGlrZVtpXSA9IHN1bShkdCh5L3NpZ3NbaV0sZGY9bnVzW2pdLGxvZz1UUlVFKSktbipsb2coc2lnc1tpXSkKICBzaWcubWxlW2pdID0gc2lnc1tsaWtlPT1tYXgobGlrZSldCiAgbGlrZXNbal0gPSBsaWtlW2xpa2U9PW1heChsaWtlKV0KfQoKc2lnLmhhdC4yID0gc2lnLm1sZVtsaWtlcz09bWF4KGxpa2VzKV0KbnUuaGF0ID0gbnVzW2xpa2VzPT1tYXgobGlrZXMpXQoKYyhzaWcuaGF0LjEsc2lnLmhhdC4yLG51LmhhdCkKYGBgCgpgYGB7ciBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD02fQpwYXIobWZyb3c9YygxLDEpKQpwbG90KG51cyxzaWcubWxlLHlsaW09cmFuZ2Uoc2lnLm1sZSxzaWcuaGF0LjEpKQphYmxpbmUoaD1zaWcuaGF0LjEpCmBgYAoKYGBge3IgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9Nn0KcGFyKG1mcm93PWMoMSwxKSkKcGxvdChsaWtlcyxzaWcubWxlLGNvbD0wKQp0ZXh0KGxpa2VzLHNpZy5tbGUsbnVzLGNleD0wLjUpCmBgYAoKYGBge3IgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9Nn0KcGFyKG1mcm93PWMoMSwxKSkKeHh4ID0gc2VxKC1tYXgoYWJzKHJldCkpLG1heChhYnMocmV0KSksbGVuZ3RoPTEwMDApCnhicmVha3MgPSBzZXEoLW1heChhYnMocmV0KSksbWF4KGFicyhyZXQpKSxsZW5ndGg9NTApCmhpc3QocmV0LGJyZWFrcz14YnJlYWtzLHByb2I9VFJVRSx4bGFiPSJMb2ctcmV0dXJuIixtYWluPSIiKQpsaW5lcyh4eHgsZG5vcm0oeHh4LDAsc2lnLmhhdC4xKSxjb2w9Mixsd2Q9MykKbGluZXMoeHh4LGR0KHh4eC9zaWcuaGF0LjIsZGY9bnUuaGF0KS9zaWcuaGF0LjIsY29sPTQsbHdkPTIpCmBgYAoKYGBge3IgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9Nn0KcGFyKG1mcm93PWMoMSwxKSkKbGVnZW5kcyAgPSBjKCJEYXRhIiwiR2F1c3NpYW4gbW9kZWwiLCJTdHVkZW50J3MgdCBtb2RlbCIpCmFscGhhcyAgID0gc2VxKDAuMDEsMC45OSxieT0wLjAyKQpxZGF0YSAgICA9IHF1YW50aWxlKHJldCxhbHBoYXMpCnFub3JtYWwgID0gcW5vcm0oYWxwaGFzLDAsc2lnLmhhdC4xKQpxc3R1ZGVudCA9IHNpZy5oYXQuMipxdChhbHBoYXMsZGY9bnUuaGF0KQp4cmFuZ2UgICA9IHJhbmdlKHFkYXRhLHFub3JtYWwscXN0dWRlbnQpCnBsb3QocWRhdGEsYWxwaGFzLHR5cGU9ImwiLHhsaW09eHJhbmdlLHlsYWI9IlRhaWwgcHJvYmFiaWxpdGllcyIseGxhYj0iUXVhbnRpbGVzIixsd2Q9MikKbGluZXMocW5vcm1hbCxhbHBoYXMsdHlwZT0ibCIsY29sPTIsbHdkPTIpCmxpbmVzKHFzdHVkZW50LGFscGhhcyx0eXBlPSJsIixjb2w9NCxsd2Q9MikKbGVnZW5kKCJ0b3BsZWZ0IixsZWdlbmQ9bGVnZW5kcyxjb2w9YygxLDIsNCksbHdkPTMsbHR5PTEpCmBgYAoKIyBTdG9jaGFzdGljIHZvbGF0aWxpdHkgbW9kZWxzCgpIZXJlIHdlIGFzc3VtZSB0aGF0IApcYmVnaW57ZXFuYXJyYXkqfQp5X3QgJj0mIGVee2hfdC8yfSBcdmFyZXBzaWxvbl90XFwKaF97dCsxfSAmPSYgXG11ICsgXHBoaSAoaF90LVxtdSkgKyBcc2lnbWEgdV90LApcZW5ke2VxbmFycmF5Kn0Kd2l0aCAkY29yKFx2YXJlcHNpbG9uX3QsdV90KT1ccmhvJC4gIAoKCiMjIFNWLCBTVnQsIFNWbCwgU1Z0bAoKRm91ciBtb2RlbHMgY29udGVtcGxhdGVkIGJ5IEdyZWdvciBLYXN0bmVyJ3MgUiBwYWNrYWdlICpzdG9jaHZvbCo6CgoqIFNWIHdpdGggR2F1c3NpYW4gZXJyb3JzIChTVikKJCQKXHZhcmVwc2lsb25fdCBcc2ltIE4oMCwxKSxcIHVfdCBcc2ltIE4oMCwxKSwgXCBccmhvPTAKJCQKCiogU1Ygd2l0aCBTdHVkZW50J3MgJHQkIGVycm9ycyAoU1Z0KQokJApcdmFyZXBzaWxvbl90IFxzaW0gdF9cbnUoMCwxKSxcIHVfdCBcc2ltIE4oMCwxKSwgXCBccmhvPTAsIFwgXG51IFwgXG1ib3h7dW5rbm93bn0KJCQKCiogU1Ygd2l0aCBHYXVzc2lhbiBlcnJvcnMgYW5kIGxldmVyYWdlIGVmZmVjdCAoU1ZsKQokJApcdmFyZXBzaWxvbl90IFxzaW0gTigwLDEpLFwgdV90IFxzaW0gTigwLDEpLCBcIFxyaG8gXCBcbWJveHt1bmtub3dufSwKJCQKCiogU1Ygd2l0aCBTdHVkZW50J3MgJHQkIGVycm9ycyBhbmQgbGV2ZXJhZ2UgZWZmZWN0IChTVnRsKQokJApcdmFyZXBzaWxvbl90IFxzaW0gTigwLDEpLFwgdV90IFxzaW0gTigwLDEpLCBcIFxyaG8gXCBcbWJveHt1bmtub3dufSwgXCBcbnUgXCBcbWJveHt1bmtub3dufQokJAoKIyMgUHJpb3IgZGlzdHJpYnV0aW9ucwoKVGhlIHBhY2thZ2UgKnN0b2Nodm9sKiBoYXMgdGhlIGZvbGxvd2luZyBkZWZhdWx0IHByaW9yIHNwZWNpZmljYXRpb25zOgpcYmVnaW57ZXFuYXJyYXkqfQpcbXUgICAgICAgJlxzaW0mIE4oMCwxMDBeMilcXAooXHBoaSsxKS8yICZcc2ltJiBCZXRhKDUsMS41KVxcClxzaWdtYV4yICAgICZcc2ltJiBHYW1tYSgxLzIsMS8yKVxcCmhfMSAgICAgICZcc2ltJiBOKFxtdSxcc2lnbWFeMi8oMS1ccGhpXjIpKVxcCihccmhvKzEpLzIgJlxzaW0mIEJldGEoNCw0KVxcClxudSAgICAgICAgJlxzaW0mIEV4cCgwLjEpClxlbmR7ZXFuYXJyYXkqfQoKCiMjIFJlZmVyZW5jZXMKCiogU291cmNlOiBNb2RlbGluZyBVbml2YXJpYXRlIGFuZCBNdWx0aXZhcmlhdGUgU3RvY2hhc3RpYyBWb2xhdGlsaXR5IGluIFIgd2l0aCBzdG9jaHZvbCBhbmQgZmFjdG9yc3RvY2h2b2wgLSBodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvZmFjdG9yc3RvY2h2b2wvdmlnbmV0dGVzL3BhcGVyLnBkZgoKKiBLYXN0bmVyICgyMDE2KSBEZWFsaW5nIHdpdGggU3RvY2hhc3RpYyBWb2xhdGlsaXR5IGluIFRpbWUgU2VyaWVzIFVzaW5nIHRoZSBSIFBhY2thZ2Ugc3RvY2h2b2wuICBKb3VybmFsIG9mIFN0YXRpc3RpY2FsIFNvZnR3YXJlLCA2OSg1KSwgMS0zMC4gZG9pOjEwLjE4NjM3L2pzcy52MDY5LmkwNS4KCiogS2FzdG5lcigyMDE5KSBTcGFyc2UgQmF5ZXNpYW4gVGltZS1WYXJ5aW5nIENvdmFyaWFuY2UgRXN0aW1hdGlvbiBpbiBNYW55IERpbWVuc2lvbnMuICBKb3VybmFsIG9mIEVjb25vbWV0cmljcywgMjEwKDEpLCA5OC0xMTUuIGRvaToxMC4xMDE2L2ouamVjb25vbS4yMDE4LjExLjAwNy4KCiogS2FzdG5lciBhbmQgRnJ1aHdpcnRoLVNjaG5hdHRlciAoMjAxNCkgQW5jaWxsYXJpdHktU3VmZmljaWVuY3kgSW50ZXJ3ZWF2aW5nIFN0cmF0ZWd5IChBU0lTKSBmb3IgQm9vc3RpbmcgTUNNQyBFc3RpbWF0aW9uIG9mIFN0b2NoYXN0aWMgVm9sYXRpbGl0eSBNb2RlbHMuICBDb21wdXRhdGlvbmFsIFN0YXRpc3RpY3MgYW5kIERhdGEgQW5hbHlzaXMsIDc2LCA0MDjigJM0MjMuIGRvaToxMC4xMDE2L2ouY3NkYS4yMDEzLjAxLjAwMi4KCiogS2FzdG5lciwgRnJ1aHdpcnRoLVNjaG5hdHRlciBhbmQgTG9wZXMgKDIwMTcpIEVmZmljaWVudCBCYXllc2lhbiBJbmZlcmVuY2UgZm9yIE11bHRpdmFyaWF0ZSBGYWN0b3IgU3RvY2hhc3RpYyBWb2xhdGlsaXR5IE1vZGVscy4gSm91cm5hbCBvZiBDb21wdXRhdGlvbmFsIGFuZCBHcmFwaGljYWwgU3RhdGlzdGljcywgMjYoNCksIDkwNeKAkzkxNy4gZG9pOjEwLjEwODAvMTA2MTg2MDAuMjAxNy4xMzIyMDkxLgoKYGBge3J9CmxpYnJhcnkoInN0b2Nodm9sIikKZml0LnN2ICAgPSBzdnNhbXBsZShyZXQsZHJhd3M9MTAwMCxidXJuaW49MTAwLHF1aWV0PVRSVUUpCmZpdC5zdnQgID0gc3Z0c2FtcGxlKHJldCxkcmF3cz0xMDAwLGJ1cm5pbj0xMDAscXVpZXQ9VFJVRSkKZml0LnN2bCAgPSBzdmxzYW1wbGUocmV0LGRyYXdzPTEwMDAsYnVybmluPTEwMCxxdWlldD1UUlVFKQpmaXQuc3Z0bCA9IHN2dGxzYW1wbGUocmV0LGRyYXdzPTEwMDAsYnVybmluPTEwMCxxdWlldD1UUlVFKQoKcWxvZ3ZvbHMgPSBjYmluZChhcHBseShmaXQuc3YkbGF0ZW50W1sxXV0sMixtZWRpYW4pLGFwcGx5KGZpdC5zdnQkbGF0ZW50W1sxXV0sMixtZWRpYW4pLAphcHBseShmaXQuc3ZsJGxhdGVudFtbMV1dLDIsbWVkaWFuKSxhcHBseShmaXQuc3Z0bCRsYXRlbnRbWzFdXSwyLG1lZGlhbikpCgpxc3RkLnN2ICAgPSB0KGFwcGx5KGV4cChmaXQuc3YkbGF0ZW50W1sxXV0vMiksMixxdWFudGlsZSxjKDAuMDUsMC41LDAuOTUpKSkKcXN0ZC5zdnQgID0gdChhcHBseShleHAoZml0LnN2dCRsYXRlbnRbWzFdXS8yKSwyLHF1YW50aWxlLGMoMC4wNSwwLjUsMC45NSkpKQpxc3RkLnN2bCAgPSB0KGFwcGx5KGV4cChmaXQuc3ZsJGxhdGVudFtbMV1dLzIpLDIscXVhbnRpbGUsYygwLjA1LDAuNSwwLjk1KSkpCnFzdGQuc3Z0bCA9IHQoYXBwbHkoZXhwKGZpdC5zdnRsJGxhdGVudFtbMV1dLzIpLDIscXVhbnRpbGUsYygwLjA1LDAuNSwwLjk1KSkpCmBgYAoKYGBge3IgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTh9CnBhcihtZnJvdz1jKDIsMykpCnBsb3QoZGVuc2l0eShleHAoZml0LnN2JHBhcmFbWzFdXVssMV0vMikpLHhsYWI9ZXhwcmVzc2lvbihtdSksbWFpbj0iIix5bGltPWMoMCw1NTApLHhsaW09YygwLjAwNCwwLjAxNSkpCmxpbmVzKGRlbnNpdHkoZXhwKGZpdC5zdnQkcGFyYVtbMV1dWywxXS8yKSksY29sPTIpCmxpbmVzKGRlbnNpdHkoZXhwKGZpdC5zdmwkcGFyYVtbMV1dWywxXS8yKSksY29sPTMpCmxpbmVzKGRlbnNpdHkoZXhwKGZpdC5zdnRsJHBhcmFbWzFdXVssMV0vMikpLGNvbD00KQpsZWdlbmQoInRvcGxlZnQiLGxlZ2VuZD1jKCJTViIsIlNWdCIsIlNWbCIsIlNWdGwiKSxjb2w9MTo0LGx0eT0xKQoKcGxvdChkZW5zaXR5KGZpdC5zdiRwYXJhW1sxXV1bLDJdKSx4bGFiPWV4cHJlc3Npb24ocGhpKSxtYWluPSIiLHlsaW09YygwLDUwKSkKbGluZXMoZGVuc2l0eShmaXQuc3Z0JHBhcmFbWzFdXVssMl0pLGNvbD0yKQpsaW5lcyhkZW5zaXR5KGZpdC5zdmwkcGFyYVtbMV1dWywyXSksY29sPTMpCmxpbmVzKGRlbnNpdHkoZml0LnN2dGwkcGFyYVtbMV1dWywyXSksY29sPTQpCgpwbG90KGRlbnNpdHkoZml0LnN2JHBhcmFbWzFdXVssM10pLHhsYWI9ZXhwcmVzc2lvbihzaWdtYSksbWFpbj0iIix5bGltPWMoMCwxMikpCmxpbmVzKGRlbnNpdHkoZml0LnN2dCRwYXJhW1sxXV1bLDNdKSxjb2w9MikKbGluZXMoZGVuc2l0eShmaXQuc3ZsJHBhcmFbWzFdXVssM10pLGNvbD0zKQpsaW5lcyhkZW5zaXR5KGZpdC5zdnRsJHBhcmFbWzFdXVssM10pLGNvbD00KQoKcGxvdChkZW5zaXR5KGZpdC5zdnQkcGFyYVtbMV1dWyw0XSkseGxhYj1leHByZXNzaW9uKG51KSxtYWluPSIiLHlsaW09YygwLDAuMDgpKQpsaW5lcyhkZW5zaXR5KGZpdC5zdnRsJHBhcmFbWzFdXVssNF0pLGNvbD0yKQoKcGxvdChkZW5zaXR5KGZpdC5zdmwkcGFyYVtbMV1dWyw1XSkseGxhYj1leHByZXNzaW9uKHJobyksbWFpbj0iIix4bGltPWMoLTAuOSwtMC40KSkKbGluZXMoZGVuc2l0eShmaXQuc3Z0bCRwYXJhW1sxXV1bLDVdKSxjb2w9MikKYGBgCgpgYGB7ciBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD02fQpwYXIobWZyb3c9YygxLDEpKQpwbG90KHFsb2d2b2xzWywxXSx0eXBlPSJsIix5bGltPXJhbmdlKHFsb2d2b2xzKSx4bGFiPSJUaW1lIix5bGFiPSJMb2cgdm9sYXRpbGl0aWVzIikKbGluZXMocWxvZ3ZvbHNbLDJdLGNvbD0yKQpsaW5lcyhxbG9ndm9sc1ssM10sY29sPTMpCmxpbmVzKHFsb2d2b2xzWyw0XSxjb2w9NCkKYGBgCgpgYGB7ciBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD02fQp5cmFuZ2UgPSByYW5nZSgwLHFzdGQuc3ZbLDJdLHFzdGQuc3Z0WywyXSxxc3RkLnN2bFssMl0scXN0ZC5zdnRsWywyXSkKcGFyKG1mcm93PWMoMSwxKSkKcGxvdChxc3RkLnN2WywyXSx5bGFiPSJTdGFuZGFyZCBkZXZpYXRpb25zIix5bGltPXlyYW5nZSx0eXBlPSJsIix4bGFiPSJUaW1lIikKbGluZXMocXN0ZC5zdnRbLDJdLGNvbD0yKQpsaW5lcyhxc3RkLnN2bFssMl0sY29sPTMpCmxpbmVzKHFzdGQuc3Z0bFssMl0sY29sPTQpCmxlZ2VuZCgidG9wbGVmdCIsbGVnZW5kPWMoIlNWIiwiU1Z0IiwiU1ZsIiwiU1Z0bCIpLGNvbD0xOjQsbHR5PTEpCmBgYAoKYGBge3IgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTh9CnBhcihtZnJvdz1jKDIsMikpCnlyYW5nZSA9IHJhbmdlKHFzdGQuc3YscXN0ZC5zdnQscXN0ZC5zdmwscXN0ZC5zdnRsKQp0cy5wbG90KHFzdGQuc3YseWxhYj0iU3RhbmRhcmQgZGV2aWF0aW9ucyIsY29sPWMoMywyLDMpLHlsaW09eXJhbmdlKQpsaW5lcygwLjEqYWJzKHJldCksdHlwZT0iaCIpO3RpdGxlKCJTViIpCnRzLnBsb3QocXN0ZC5zdnQseWxhYj0iU3RhbmRhcmQgZGV2aWF0aW9ucyIsY29sPWMoMywyLDMpLHlsaW09eXJhbmdlKQpsaW5lcygwLjEqYWJzKHJldCksdHlwZT0iaCIpO3RpdGxlKCJTVnQiKQp0cy5wbG90KHFzdGQuc3ZsLHlsYWI9IlN0YW5kYXJkIGRldmlhdGlvbnMiLGNvbD1jKDMsMiwzKSx5bGltPXlyYW5nZSkKbGluZXMoMC4xKmFicyhyZXQpLHR5cGU9ImgiKTt0aXRsZSgiU1ZsIikKdHMucGxvdChxc3RkLnN2dGwseWxhYj0iU3RhbmRhcmQgZGV2aWF0aW9ucyIsY29sPWMoMywyLDMpLHlsaW09eXJhbmdlKQpsaW5lcygwLjEqYWJzKHJldCksdHlwZT0iaCIpO3RpdGxlKCJTVnRsIikKYGBgCgpgYGB7ciBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9OH0KcGFyKG1mcm93PWMoMiwyKSkKZm9yIChpIGluIDE6NCl7CiAgaW5kID0gKChpLTEpKm4vNCsxKTooaSpuLzQpCiAgeXJhbmdlID0gcmFuZ2UoMCxxc3RkLnN2W2luZCwyXSxxc3RkLnN2dFtpbmQsMl0scXN0ZC5zdmxbaW5kLDJdLHFzdGQuc3Z0bFtpbmQsMl0pCiAgcGxvdChpbmQscXN0ZC5zdltpbmQsMl0seWxhYj0iU3RhbmRhcmQgZGV2aWF0aW9ucyIseWxpbT15cmFuZ2UsdHlwZT0ibCIseGxhYj0iVGltZSIpCiAgbGluZXMoaW5kLHFzdGQuc3Z0W2luZCwyXSxjb2w9MikKICBsaW5lcyhpbmQscXN0ZC5zdmxbaW5kLDJdLGNvbD0zKQogIGxpbmVzKGluZCxxc3RkLnN2dGxbaW5kLDJdLGNvbD00KQogIGxpbmVzKGluZCwwLjMqYWJzKHJldFtpbmRdKSx0eXBlPSJoIikKfQpsZWdlbmQoInRvcGxlZnQiLGxlZ2VuZD1jKCJTViIsIlNWdCIsIlNWbCIsIlNWdGwiKSxjb2w9MTo0LGx0eT0xKQpgYGAK