1 Petrobras data

#install.packages("tidyquant")
library("tidyquant")
## Registered S3 method overwritten by 'quantmod':
##   method            from
##   as.zoo.data.frame zoo
## ── Attaching core tidyquant packages ──────────────────────── tidyquant 1.0.9 ──
## ✔ PerformanceAnalytics 2.0.4      ✔ TTR                  0.24.4
## ✔ quantmod             0.4.26     ✔ xts                  0.13.2
## ── Conflicts ────────────────────────────────────────── tidyquant_conflicts() ──
## ✖ zoo::as.Date()                 masks base::as.Date()
## ✖ zoo::as.Date.numeric()         masks base::as.Date.numeric()
## ✖ PerformanceAnalytics::legend() masks graphics::legend()
## ✖ quantmod::summary()            masks base::summary()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
getSymbols('PBR',src='yahoo',return.class='ts',from="2019-01-01")
## [1] "PBR"
n = nrow(PBR)

ret = log(PBR[2:n,6]/PBR[1:(n-1),6])

y   = ret-mean(ret)
n   = n - 1
par(mfrow=c(1,1))
ts.plot(PBR[,4],main="",ylab="Price")

par(mfrow=c(1,2))
ts.plot(ret,main="",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.03279088

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.03279088 0.01934535 3.00000000
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")
M        = 10000
burn     = 10000
fit.sv   = svsample(ret,draws=M,burnin=burn,quiet=TRUE)
## Argument 'y' (data vector) contains values very close to zero. I am applying an offset constant of size 3.28023364663639e-06 to do the auxiliary mixture sampling. If you want to avoid this, you might consider de-meaning the returns before calling this function.
fit.svt  = svtsample(ret,draws=M,burnin=burn,quiet=TRUE)
## Argument 'y' (data vector) contains values very close to zero. I am applying an offset constant of size 3.28023364663639e-06 to do the auxiliary mixture sampling. If you want to avoid this, you might consider de-meaning the returns before calling this function.
fit.svl  = svlsample(ret,draws=M,burnin=burn,quiet=TRUE)
## Argument 'y' (data vector) contains values very close to zero. I am applying an offset constant of size 3.28023364663639e-06 to do the auxiliary mixture sampling. If you want to avoid this, you might consider de-meaning the returns before calling this function.
fit.svtl = svtlsample(ret,draws=M,burnin=burn,quiet=TRUE)
## Argument 'y' (data vector) contains values very close to zero. I am applying an offset constant of size 3.28023364663639e-06 to do the auxiliary mixture sampling. If you want to avoid this, you might consider de-meaning the returns before calling this function.
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))
pars = cbind(exp(fit.sv$para[[1]][,1]/2),exp(fit.svt$para[[1]][,1]/2),
             exp(fit.svl$para[[1]][,1]/2),exp(fit.svtl$para[[1]][,1]/2))
plot(density(pars[,1]),xlab=expression(mu),main="",xlim=c(0,0.05))
for (i in 2:4) lines(density(pars[,i]),col=i)
legend("topright",legend=c("SV","SVt","SVl","SVtl"),col=1:4,lty=1)

pars = cbind(fit.sv$para[[1]][,2],fit.svt$para[[1]][,2],fit.svl$para[[1]][,2],fit.svtl$para[[1]][,2])
plot(density(pars[,1]),xlab=expression(phi),main="",xlim=range(pars),ylim=c(0,40))
for (i in 2:4) lines(density(pars[,i]),col=i)

pars = cbind(fit.sv$para[[1]][,3],fit.svt$para[[1]][,3],fit.svl$para[[1]][,3],fit.svtl$para[[1]][,3])
plot(density(pars[,1]),xlab=expression(sigma),main="",xlim=range(pars),ylim=c(0,20))
for (i in 2:4) lines(density(pars[,i]),col=i)

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

pars = cbind(fit.svl$para[[1]][,5],fit.svtl$para[[1]][,5])
plot(density(pars[,1]),xlab=expression(rho),main="",xlim=range(pars),col=3)
lines(density(pars[,2]),col=4)

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)
legend("topleft",legend=c("SV","SVt","SVl","SVtl"),col=1:4,lty=1)

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)

LS0tCnRpdGxlOiAiUGV0cm9icmFzIHJldHVybnMiCnN1YnRpdGxlOiAiR2F1c3NpYW4sIFN0dWRlbnQncyAkdCQgb3IgU1Y/IgphdXRob3I6ICJIZWRpYmVydCBGcmVpdGFzIExvcGVzIgpkYXRlOiAiOS8xMi8yMDI0IgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICB0b2NfZGVwdGg6IDIKICAgIHRvY19mbG9hdDogCiAgICAgIGNvbGxhcHNlZDogZmFsc2UKICAgICAgc21vb3RoX3Njcm9sbDogZmFsc2UKICAgIGNvZGVfZG93bmxvYWQ6IHllcwotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpCmBgYAoKIyBQZXRyb2JyYXMgZGF0YSAKYGBge3J9CiNpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5cXVhbnQiKQpsaWJyYXJ5KCJ0aWR5cXVhbnQiKQoKZ2V0U3ltYm9scygnUEJSJyxzcmM9J3lhaG9vJyxyZXR1cm4uY2xhc3M9J3RzJyxmcm9tPSIyMDE5LTAxLTAxIikKCm4gPSBucm93KFBCUikKCnJldCA9IGxvZyhQQlJbMjpuLDZdL1BCUlsxOihuLTEpLDZdKQoKeSAgID0gcmV0LW1lYW4ocmV0KQpuICAgPSBuIC0gMQpgYGAKCmBgYHtyIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTZ9CnBhcihtZnJvdz1jKDEsMSkpCnRzLnBsb3QoUEJSWyw0XSxtYWluPSIiLHlsYWI9IlByaWNlIikKYGBgCgpgYGB7ciBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9Nn0KcGFyKG1mcm93PWMoMSwyKSkKdHMucGxvdChyZXQsbWFpbj0iIix5bGFiPSJMb2ctcmV0dXJuIikKaGlzdChyZXQsYnJlYWtzPXNlcSgtbWF4KGFicyhyZXQpKSxtYXgoYWJzKHJldCkpLGxlbmd0aD01MCkscHJvYj1UUlVFLHhsYWI9IkxvZy1yZXR1cm4iLG1haW49IiIpCmBgYAoKIyBNb2RlbCAxOiBpaWQgR2F1c3NpYW4KeV90IGlpZCBOKDAsc2lnMikKYGBge3J9CnNpZy5oYXQuMSA9IHNxcnQobWVhbih5XjIpKQpzaWcuaGF0LjEKYGBgCgojIEdhdXNzaWFuIHZzIFN0dWRlbnQncyAkdCQKYGBge3IgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9Nn0KeHh4ID0gc2VxKC0xMCwxMCxsZW5ndGg9MTAwMCkKcGFyKG1mcm93PWMoMSwxKSkKcGxvdCh4eHgsZG5vcm0oeHh4KSx0eXBlPSJsIix4bGFiPSJ4Iix5bGFiPSJEZW5zaXR5IikKbGluZXMoeHh4LGR0KHh4eCxkZj0xKSxjb2w9MikKbGluZXMoeHh4LGR0KHh4eCxkZj0yKSxjb2w9MykKbGluZXMoeHh4LGR0KHh4eCxkZj0zMCksY29sPTQpCmxlZ2VuZCgidG9wbGVmdCIsbGVnZW5kPWMoImRmPTEiLCJkZj0yIiwiZGY9MzAiLCJHYXVzc2lhbiIpLGNvbD1jKDI6NCwxKSxsdHk9MSxsd2Q9MikKYGBgCgpgYGB7ciBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD02fQpwYXIobWZyb3c9YygxLDEpKQpwbG90KHh4eCxsb2coZG5vcm0oeHh4KSksdHlwZT0ibCIseGxhYj0ieCIseWxhYj0iTG9nIGRlbnNpdHkiKQpsaW5lcyh4eHgsbG9nKGR0KHh4eCxkZj0xKSksY29sPTIpCmxpbmVzKHh4eCxsb2coZHQoeHh4LGRmPTIpKSxjb2w9MykKbGluZXMoeHh4LGxvZyhkdCh4eHgsZGY9MzApKSxjb2w9NCkKYGBgCgojIE1vZGVsIDI6IGlpZCBTdHVkZW50J3MgJHQkCgpgYGB7cn0Kc2lncyA9IHNlcSgwLjAwMSwwLjE1LGxlbmd0aD0xMDAwKQpudXMgID0gYygxOjMwLHNlcSgzNSwxMDAsYnk9NSksc2VxKDIwMCwxMDAwLGJ5PTEwMCkpCm5udSAgPSBsZW5ndGgobnVzKQpsaWtlID0gcmVwKDAsMTAwMCkKc2lnLm1sZSA9IHJlcCgwLG5udSkKbGlrZXMgPSByZXAoMCxubnUpCmZvciAoaiBpbiAxOm5udSl7CiAgZm9yIChpIGluIDE6MTAwMCkKICAgIGxpa2VbaV0gPSBzdW0oZHQoeS9zaWdzW2ldLGRmPW51c1tqXSxsb2c9VFJVRSkpLW4qbG9nKHNpZ3NbaV0pCiAgc2lnLm1sZVtqXSA9IHNpZ3NbbGlrZT09bWF4KGxpa2UpXQogIGxpa2VzW2pdID0gbGlrZVtsaWtlPT1tYXgobGlrZSldCn0KCnNpZy5oYXQuMiA9IHNpZy5tbGVbbGlrZXM9PW1heChsaWtlcyldCm51LmhhdCA9IG51c1tsaWtlcz09bWF4KGxpa2VzKV0KCmMoc2lnLmhhdC4xLHNpZy5oYXQuMixudS5oYXQpCmBgYAoKYGBge3IgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9Nn0KcGFyKG1mcm93PWMoMSwxKSkKcGxvdChudXMsc2lnLm1sZSx5bGltPXJhbmdlKHNpZy5tbGUsc2lnLmhhdC4xKSkKYWJsaW5lKGg9c2lnLmhhdC4xKQpgYGAKCmBgYHtyIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTZ9CnBhcihtZnJvdz1jKDEsMSkpCnBsb3QobGlrZXMsc2lnLm1sZSxjb2w9MCkKdGV4dChsaWtlcyxzaWcubWxlLG51cyxjZXg9MC41KQpgYGAKCmBgYHtyIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTZ9CnBhcihtZnJvdz1jKDEsMSkpCnh4eCA9IHNlcSgtbWF4KGFicyhyZXQpKSxtYXgoYWJzKHJldCkpLGxlbmd0aD0xMDAwKQp4YnJlYWtzID0gc2VxKC1tYXgoYWJzKHJldCkpLG1heChhYnMocmV0KSksbGVuZ3RoPTUwKQpoaXN0KHJldCxicmVha3M9eGJyZWFrcyxwcm9iPVRSVUUseGxhYj0iTG9nLXJldHVybiIsbWFpbj0iIikKbGluZXMoeHh4LGRub3JtKHh4eCwwLHNpZy5oYXQuMSksY29sPTIsbHdkPTMpCmxpbmVzKHh4eCxkdCh4eHgvc2lnLmhhdC4yLGRmPW51LmhhdCkvc2lnLmhhdC4yLGNvbD00LGx3ZD0yKQpgYGAKCmBgYHtyIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTZ9CnBhcihtZnJvdz1jKDEsMSkpCmxlZ2VuZHMgID0gYygiRGF0YSIsIkdhdXNzaWFuIG1vZGVsIiwiU3R1ZGVudCdzIHQgbW9kZWwiKQphbHBoYXMgICA9IHNlcSgwLjAxLDAuOTksYnk9MC4wMikKcWRhdGEgICAgPSBxdWFudGlsZShyZXQsYWxwaGFzKQpxbm9ybWFsICA9IHFub3JtKGFscGhhcywwLHNpZy5oYXQuMSkKcXN0dWRlbnQgPSBzaWcuaGF0LjIqcXQoYWxwaGFzLGRmPW51LmhhdCkKeHJhbmdlICAgPSByYW5nZShxZGF0YSxxbm9ybWFsLHFzdHVkZW50KQpwbG90KHFkYXRhLGFscGhhcyx0eXBlPSJsIix4bGltPXhyYW5nZSx5bGFiPSJUYWlsIHByb2JhYmlsaXRpZXMiLHhsYWI9IlF1YW50aWxlcyIsbHdkPTIpCmxpbmVzKHFub3JtYWwsYWxwaGFzLHR5cGU9ImwiLGNvbD0yLGx3ZD0yKQpsaW5lcyhxc3R1ZGVudCxhbHBoYXMsdHlwZT0ibCIsY29sPTQsbHdkPTIpCmxlZ2VuZCgidG9wbGVmdCIsbGVnZW5kPWxlZ2VuZHMsY29sPWMoMSwyLDQpLGx3ZD0zLGx0eT0xKQpgYGAKCiMgU3RvY2hhc3RpYyB2b2xhdGlsaXR5IG1vZGVscwoKSGVyZSB3ZSBhc3N1bWUgdGhhdCAKXGJlZ2lue2VxbmFycmF5Kn0KeV90ICY9JiBlXntoX3QvMn0gXHZhcmVwc2lsb25fdFxcCmhfe3QrMX0gJj0mIFxtdSArIFxwaGkgKGhfdC1cbXUpICsgXHNpZ21hIHVfdCwKXGVuZHtlcW5hcnJheSp9CndpdGggJGNvcihcdmFyZXBzaWxvbl90LHVfdCk9XHJobyQuICAKCgojIyBTViwgU1Z0LCBTVmwsIFNWdGwKCkZvdXIgbW9kZWxzIGNvbnRlbXBsYXRlZCBieSBHcmVnb3IgS2FzdG5lcidzIFIgcGFja2FnZSAqc3RvY2h2b2wqOgoKKiBTViB3aXRoIEdhdXNzaWFuIGVycm9ycyAoU1YpCiQkClx2YXJlcHNpbG9uX3QgXHNpbSBOKDAsMSksXCB1X3QgXHNpbSBOKDAsMSksIFwgXHJobz0wCiQkCgoqIFNWIHdpdGggU3R1ZGVudCdzICR0JCBlcnJvcnMgKFNWdCkKJCQKXHZhcmVwc2lsb25fdCBcc2ltIHRfXG51KDAsMSksXCB1X3QgXHNpbSBOKDAsMSksIFwgXHJobz0wLCBcIFxudSBcIFxtYm94e3Vua25vd259CiQkCgoqIFNWIHdpdGggR2F1c3NpYW4gZXJyb3JzIGFuZCBsZXZlcmFnZSBlZmZlY3QgKFNWbCkKJCQKXHZhcmVwc2lsb25fdCBcc2ltIE4oMCwxKSxcIHVfdCBcc2ltIE4oMCwxKSwgXCBccmhvIFwgXG1ib3h7dW5rbm93bn0sCiQkCgoqIFNWIHdpdGggU3R1ZGVudCdzICR0JCBlcnJvcnMgYW5kIGxldmVyYWdlIGVmZmVjdCAoU1Z0bCkKJCQKXHZhcmVwc2lsb25fdCBcc2ltIE4oMCwxKSxcIHVfdCBcc2ltIE4oMCwxKSwgXCBccmhvIFwgXG1ib3h7dW5rbm93bn0sIFwgXG51IFwgXG1ib3h7dW5rbm93bn0KJCQKCiMjIFByaW9yIGRpc3RyaWJ1dGlvbnMKClRoZSBwYWNrYWdlICpzdG9jaHZvbCogaGFzIHRoZSBmb2xsb3dpbmcgZGVmYXVsdCBwcmlvciBzcGVjaWZpY2F0aW9uczoKXGJlZ2lue2VxbmFycmF5Kn0KXG11ICAgICAgICZcc2ltJiBOKDAsMTAwXjIpXFwKKFxwaGkrMSkvMiAmXHNpbSYgQmV0YSg1LDEuNSlcXApcc2lnbWFeMiAgICAmXHNpbSYgR2FtbWEoMS8yLDEvMilcXApoXzEgICAgICAmXHNpbSYgTihcbXUsXHNpZ21hXjIvKDEtXHBoaV4yKSlcXAooXHJobysxKS8yICZcc2ltJiBCZXRhKDQsNClcXApcbnUgICAgICAgICZcc2ltJiBFeHAoMC4xKQpcZW5ke2VxbmFycmF5Kn0KCgojIyBSZWZlcmVuY2VzCgoqIFNvdXJjZTogTW9kZWxpbmcgVW5pdmFyaWF0ZSBhbmQgTXVsdGl2YXJpYXRlIFN0b2NoYXN0aWMgVm9sYXRpbGl0eSBpbiBSIHdpdGggc3RvY2h2b2wgYW5kIGZhY3RvcnN0b2Nodm9sIC0gaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2ZhY3RvcnN0b2Nodm9sL3ZpZ25ldHRlcy9wYXBlci5wZGYKCiogS2FzdG5lciAoMjAxNikgRGVhbGluZyB3aXRoIFN0b2NoYXN0aWMgVm9sYXRpbGl0eSBpbiBUaW1lIFNlcmllcyBVc2luZyB0aGUgUiBQYWNrYWdlIHN0b2Nodm9sLiAgSm91cm5hbCBvZiBTdGF0aXN0aWNhbCBTb2Z0d2FyZSwgNjkoNSksIDEtMzAuIGRvaToxMC4xODYzNy9qc3MudjA2OS5pMDUuCgoqIEthc3RuZXIoMjAxOSkgU3BhcnNlIEJheWVzaWFuIFRpbWUtVmFyeWluZyBDb3ZhcmlhbmNlIEVzdGltYXRpb24gaW4gTWFueSBEaW1lbnNpb25zLiAgSm91cm5hbCBvZiBFY29ub21ldHJpY3MsIDIxMCgxKSwgOTgtMTE1LiBkb2k6MTAuMTAxNi9qLmplY29ub20uMjAxOC4xMS4wMDcuCgoqIEthc3RuZXIgYW5kIEZydWh3aXJ0aC1TY2huYXR0ZXIgKDIwMTQpIEFuY2lsbGFyaXR5LVN1ZmZpY2llbmN5IEludGVyd2VhdmluZyBTdHJhdGVneSAoQVNJUykgZm9yIEJvb3N0aW5nIE1DTUMgRXN0aW1hdGlvbiBvZiBTdG9jaGFzdGljIFZvbGF0aWxpdHkgTW9kZWxzLiAgQ29tcHV0YXRpb25hbCBTdGF0aXN0aWNzIGFuZCBEYXRhIEFuYWx5c2lzLCA3NiwgNDA44oCTNDIzLiBkb2k6MTAuMTAxNi9qLmNzZGEuMjAxMy4wMS4wMDIuCgoqIEthc3RuZXIsIEZydWh3aXJ0aC1TY2huYXR0ZXIgYW5kIExvcGVzICgyMDE3KSBFZmZpY2llbnQgQmF5ZXNpYW4gSW5mZXJlbmNlIGZvciBNdWx0aXZhcmlhdGUgRmFjdG9yIFN0b2NoYXN0aWMgVm9sYXRpbGl0eSBNb2RlbHMuIEpvdXJuYWwgb2YgQ29tcHV0YXRpb25hbCBhbmQgR3JhcGhpY2FsIFN0YXRpc3RpY3MsIDI2KDQpLCA5MDXigJM5MTcuIGRvaToxMC4xMDgwLzEwNjE4NjAwLjIwMTcuMTMyMjA5MS4KCmBgYHtyfQpsaWJyYXJ5KCJzdG9jaHZvbCIpCk0gICAgICAgID0gMTAwMDAKYnVybiAgICAgPSAxMDAwMApmaXQuc3YgICA9IHN2c2FtcGxlKHJldCxkcmF3cz1NLGJ1cm5pbj1idXJuLHF1aWV0PVRSVUUpCmZpdC5zdnQgID0gc3Z0c2FtcGxlKHJldCxkcmF3cz1NLGJ1cm5pbj1idXJuLHF1aWV0PVRSVUUpCmZpdC5zdmwgID0gc3Zsc2FtcGxlKHJldCxkcmF3cz1NLGJ1cm5pbj1idXJuLHF1aWV0PVRSVUUpCmZpdC5zdnRsID0gc3Z0bHNhbXBsZShyZXQsZHJhd3M9TSxidXJuaW49YnVybixxdWlldD1UUlVFKQoKcWxvZ3ZvbHMgPSBjYmluZChhcHBseShmaXQuc3YkbGF0ZW50W1sxXV0sMixtZWRpYW4pLGFwcGx5KGZpdC5zdnQkbGF0ZW50W1sxXV0sMixtZWRpYW4pLAphcHBseShmaXQuc3ZsJGxhdGVudFtbMV1dLDIsbWVkaWFuKSxhcHBseShmaXQuc3Z0bCRsYXRlbnRbWzFdXSwyLG1lZGlhbikpCgpxc3RkLnN2ICAgPSB0KGFwcGx5KGV4cChmaXQuc3YkbGF0ZW50W1sxXV0vMiksMixxdWFudGlsZSxjKDAuMDUsMC41LDAuOTUpKSkKcXN0ZC5zdnQgID0gdChhcHBseShleHAoZml0LnN2dCRsYXRlbnRbWzFdXS8yKSwyLHF1YW50aWxlLGMoMC4wNSwwLjUsMC45NSkpKQpxc3RkLnN2bCAgPSB0KGFwcGx5KGV4cChmaXQuc3ZsJGxhdGVudFtbMV1dLzIpLDIscXVhbnRpbGUsYygwLjA1LDAuNSwwLjk1KSkpCnFzdGQuc3Z0bCA9IHQoYXBwbHkoZXhwKGZpdC5zdnRsJGxhdGVudFtbMV1dLzIpLDIscXVhbnRpbGUsYygwLjA1LDAuNSwwLjk1KSkpCmBgYAoKYGBge3IgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTh9CnBhcihtZnJvdz1jKDIsMykpCnBhcnMgPSBjYmluZChleHAoZml0LnN2JHBhcmFbWzFdXVssMV0vMiksZXhwKGZpdC5zdnQkcGFyYVtbMV1dWywxXS8yKSwKICAgICAgICAgICAgIGV4cChmaXQuc3ZsJHBhcmFbWzFdXVssMV0vMiksZXhwKGZpdC5zdnRsJHBhcmFbWzFdXVssMV0vMikpCnBsb3QoZGVuc2l0eShwYXJzWywxXSkseGxhYj1leHByZXNzaW9uKG11KSxtYWluPSIiLHhsaW09YygwLDAuMDUpKQpmb3IgKGkgaW4gMjo0KSBsaW5lcyhkZW5zaXR5KHBhcnNbLGldKSxjb2w9aSkKbGVnZW5kKCJ0b3ByaWdodCIsbGVnZW5kPWMoIlNWIiwiU1Z0IiwiU1ZsIiwiU1Z0bCIpLGNvbD0xOjQsbHR5PTEpCgpwYXJzID0gY2JpbmQoZml0LnN2JHBhcmFbWzFdXVssMl0sZml0LnN2dCRwYXJhW1sxXV1bLDJdLGZpdC5zdmwkcGFyYVtbMV1dWywyXSxmaXQuc3Z0bCRwYXJhW1sxXV1bLDJdKQpwbG90KGRlbnNpdHkocGFyc1ssMV0pLHhsYWI9ZXhwcmVzc2lvbihwaGkpLG1haW49IiIseGxpbT1yYW5nZShwYXJzKSx5bGltPWMoMCw0MCkpCmZvciAoaSBpbiAyOjQpIGxpbmVzKGRlbnNpdHkocGFyc1ssaV0pLGNvbD1pKQoKcGFycyA9IGNiaW5kKGZpdC5zdiRwYXJhW1sxXV1bLDNdLGZpdC5zdnQkcGFyYVtbMV1dWywzXSxmaXQuc3ZsJHBhcmFbWzFdXVssM10sZml0LnN2dGwkcGFyYVtbMV1dWywzXSkKcGxvdChkZW5zaXR5KHBhcnNbLDFdKSx4bGFiPWV4cHJlc3Npb24oc2lnbWEpLG1haW49IiIseGxpbT1yYW5nZShwYXJzKSx5bGltPWMoMCwyMCkpCmZvciAoaSBpbiAyOjQpIGxpbmVzKGRlbnNpdHkocGFyc1ssaV0pLGNvbD1pKQoKcGFycyA9IGNiaW5kKGZpdC5zdnQkcGFyYVtbMV1dWyw0XSxmaXQuc3Z0bCRwYXJhW1sxXV1bLDRdKQpwbG90KGRlbnNpdHkocGFyc1ssMV0pLHhsYWI9ZXhwcmVzc2lvbihudSksbWFpbj0iIix4bGltPXJhbmdlKHBhcnMpLGNvbD0yLHlsaW09YygwLDAuNSkpCmxpbmVzKGRlbnNpdHkocGFyc1ssMl0pLGNvbD00KQoKcGFycyA9IGNiaW5kKGZpdC5zdmwkcGFyYVtbMV1dWyw1XSxmaXQuc3Z0bCRwYXJhW1sxXV1bLDVdKQpwbG90KGRlbnNpdHkocGFyc1ssMV0pLHhsYWI9ZXhwcmVzc2lvbihyaG8pLG1haW49IiIseGxpbT1yYW5nZShwYXJzKSxjb2w9MykKbGluZXMoZGVuc2l0eShwYXJzWywyXSksY29sPTQpCmBgYAoKYGBge3IgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9Nn0KcGFyKG1mcm93PWMoMSwxKSkKcGxvdChxbG9ndm9sc1ssMV0sdHlwZT0ibCIseWxpbT1yYW5nZShxbG9ndm9scykseGxhYj0iVGltZSIseWxhYj0iTG9nIHZvbGF0aWxpdGllcyIpCmxpbmVzKHFsb2d2b2xzWywyXSxjb2w9MikKbGluZXMocWxvZ3ZvbHNbLDNdLGNvbD0zKQpsaW5lcyhxbG9ndm9sc1ssNF0sY29sPTQpCmxlZ2VuZCgidG9wbGVmdCIsbGVnZW5kPWMoIlNWIiwiU1Z0IiwiU1ZsIiwiU1Z0bCIpLGNvbD0xOjQsbHR5PTEpCmBgYAoKYGBge3IgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9Nn0KeXJhbmdlID0gcmFuZ2UoMCxxc3RkLnN2WywyXSxxc3RkLnN2dFssMl0scXN0ZC5zdmxbLDJdLHFzdGQuc3Z0bFssMl0pCnBhcihtZnJvdz1jKDEsMSkpCnBsb3QocXN0ZC5zdlssMl0seWxhYj0iU3RhbmRhcmQgZGV2aWF0aW9ucyIseWxpbT15cmFuZ2UsdHlwZT0ibCIseGxhYj0iVGltZSIpCmxpbmVzKHFzdGQuc3Z0WywyXSxjb2w9MikKbGluZXMocXN0ZC5zdmxbLDJdLGNvbD0zKQpsaW5lcyhxc3RkLnN2dGxbLDJdLGNvbD00KQpsZWdlbmQoInRvcGxlZnQiLGxlZ2VuZD1jKCJTViIsIlNWdCIsIlNWbCIsIlNWdGwiKSxjb2w9MTo0LGx0eT0xKQpgYGAKCmBgYHtyIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD04fQpwYXIobWZyb3c9YygyLDIpKQp5cmFuZ2UgPSByYW5nZShxc3RkLnN2LHFzdGQuc3Z0LHFzdGQuc3ZsLHFzdGQuc3Z0bCkKdHMucGxvdChxc3RkLnN2LHlsYWI9IlN0YW5kYXJkIGRldmlhdGlvbnMiLGNvbD1jKDMsMiwzKSx5bGltPXlyYW5nZSkKbGluZXMoMC4xKmFicyhyZXQpLHR5cGU9ImgiKTt0aXRsZSgiU1YiKQp0cy5wbG90KHFzdGQuc3Z0LHlsYWI9IlN0YW5kYXJkIGRldmlhdGlvbnMiLGNvbD1jKDMsMiwzKSx5bGltPXlyYW5nZSkKbGluZXMoMC4xKmFicyhyZXQpLHR5cGU9ImgiKTt0aXRsZSgiU1Z0IikKdHMucGxvdChxc3RkLnN2bCx5bGFiPSJTdGFuZGFyZCBkZXZpYXRpb25zIixjb2w9YygzLDIsMykseWxpbT15cmFuZ2UpCmxpbmVzKDAuMSphYnMocmV0KSx0eXBlPSJoIik7dGl0bGUoIlNWbCIpCnRzLnBsb3QocXN0ZC5zdnRsLHlsYWI9IlN0YW5kYXJkIGRldmlhdGlvbnMiLGNvbD1jKDMsMiwzKSx5bGltPXlyYW5nZSkKbGluZXMoMC4xKmFicyhyZXQpLHR5cGU9ImgiKTt0aXRsZSgiU1Z0bCIpCmBgYAoKYGBge3IgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTh9CnBhcihtZnJvdz1jKDIsMikpCmZvciAoaSBpbiAxOjQpewogIGluZCA9ICgoaS0xKSpuLzQrMSk6KGkqbi80KQogIHlyYW5nZSA9IHJhbmdlKDAscXN0ZC5zdltpbmQsMl0scXN0ZC5zdnRbaW5kLDJdLHFzdGQuc3ZsW2luZCwyXSxxc3RkLnN2dGxbaW5kLDJdKQogIHBsb3QoaW5kLHFzdGQuc3ZbaW5kLDJdLHlsYWI9IlN0YW5kYXJkIGRldmlhdGlvbnMiLHlsaW09eXJhbmdlLHR5cGU9ImwiLHhsYWI9IlRpbWUiKQogIGxpbmVzKGluZCxxc3RkLnN2dFtpbmQsMl0sY29sPTIpCiAgbGluZXMoaW5kLHFzdGQuc3ZsW2luZCwyXSxjb2w9MykKICBsaW5lcyhpbmQscXN0ZC5zdnRsW2luZCwyXSxjb2w9NCkKICBsaW5lcyhpbmQsMC4zKmFicyhyZXRbaW5kXSksdHlwZT0iaCIpCn0KbGVnZW5kKCJ0b3BsZWZ0IixsZWdlbmQ9YygiU1YiLCJTVnQiLCJTVmwiLCJTVnRsIiksY29sPTE6NCxsdHk9MSkKYGBgCg==