1 The Monte Carlo algorithms

1.1 rnorm

In R, it is easy to sample from a standard normal using the rnorm function

x = rnorm(10000)
c(mean(x),var(x),dnorm(0),qnorm(0.975),pnorm(0))
## [1] 0.009393749 1.006472627 0.398942280 1.959963985 0.500000000
par(mfrow=c(1,2))
hist(x,prob=TRUE,main="Draws from N(0,1)",xlab="")
plot(density(x),xlab="",main="Kernel density approximation")

1.2 Box-Muller method

The Box-Muller transform is a classic algorithm used to generate pairs of independent, standard normally distributed random numbers from a source of uniformly distributed random numbers. It relies on the fact that a two-dimensional standard normal distribution is rotationally symmetric. When expressed in polar coordinates, the angle is uniformly distributed, and the squared radius follows an exponential distribution. If \(U_1\) and \(U_2\) are independent random variables \(U(0,1)\), then the variables \(Z_0\) and \(Z_1\) \[\begin{eqnarray*} Z_0 &=& \left(-2 \ln U_1\right)^{1/2} \cos(2\pi U_2)\\ Z_1 &=& \left(-2 \ln U_1\right)^{1/2} \sin(2\pi U_2), \end{eqnarray*}\] are independent \(N(0, 1)\).

BOXMULLER = function(M){
  u1 = runif(M/2)
  u2 = runif(M/2)
  z0 = sqrt(-2*log(u1))*cos(2*pi*u2)
  z1 = sqrt(-2*log(u1))*sin(2*pi*u2)
  return(c(z0,z1))
}

1.3 Marsaglia polar method

The method is an improvement on the Box-Muller transform because it avoids the computationally expensive calls to \(sin\) and \(cos\). Instead, it uses a rejection sampling step to pick a point \((v_1,v_2)\) inside the unit disk: (1) Generate \(v_1,v_2 \sim U(-1,1)\) and (2) Compute \(s=v_1^2+v_2^2\). (3) If \(s < 1\), return two independent standard normal draws: \[\begin{eqnarray*} z_1 &=& v_1 \left(-\frac{2 \ln s}{s}\right)^{1/2}\\ z_2 &=& v_2 \left(-\frac{2 \ln s}{s}\right)^{1/2}, \end{eqnarray*}\] otherwise reject and repeat steps (1) and (2). The main trade-off is “wasting” some uniform draws (about \(21\%\) are rejected), but you gain speed by skipping the trigonometry.

MARSAGLIA = function(M){
  v1 = runif(M,-1,1)
  v2 = runif(M,-1,1)
  s  = v1^2+v2^2
  ind = s<1
  s  = (s[ind])[1:(M/2)]
  v1 = (v1[ind])[1:(M/2)]
  v2 = (v2[ind])[1:(M/2)]  
  z0 = v1*sqrt(-2*log(s)/s)
  z1 = v2*sqrt(-2*log(s)/s)
  return(c(z0,z1))
}

1.4 Sampling importance resampling

We’ve already talked about the SIR scheme in your previous classes.

SIR = function(M,N){
  draw = rt(M,df=4)
  w    = dnorm(draw)/dt(draw,df=4)
  return(sample(draw,replace=TRUE,size=N,prob=w))
}

2 Sampling and comparison

We compare histograms based on the sampling schemes to the exact density evaluations

M = 20000
N = 20000
samples = matrix(0,M,4)
samples[,1] = rnorm(M)
samples[,2] = BOXMULLER(M)
samples[,3] = MARSAGLIA(M)
samples[,4] = SIR(M,N)

titles = c("rnorm","Box-Muller","Marsaglia","SIR")
x      = seq(min(samples),max(samples),length=1000)
den    = dnorm(x)
breaks = seq(min(samples),max(samples),length=30)
par(mfrow=c(2,2))
for (i in 1:4){
  hist(samples[,i],prob=TRUE,breaks=breaks,main=titles[i],col="skyblue",xlab="Draws")
  lines(x,den,col=2,lwd=2)
}

3 Comparing quantiles

probs  = c(0.01,0.025,0.05,0.1,0.25,0.34)
quants = qnorm(probs)
tab   = cbind(probs,qnorm(probs),apply(samples,2,quantile,probs))
colnames(tab) = c("Quantile","Exact","rnorm","Box-Muller","Marsaglia","SIR")
round(tab,3)
##      Quantile  Exact  rnorm Box-Muller Marsaglia    SIR
## 1%      0.010 -2.326 -2.350     -2.359    -2.346 -2.318
## 2.5%    0.025 -1.960 -1.976     -1.979    -1.977 -1.988
## 5%      0.050 -1.645 -1.650     -1.659    -1.650 -1.684
## 10%     0.100 -1.282 -1.273     -1.284    -1.300 -1.328
## 25%     0.250 -0.674 -0.682     -0.680    -0.684 -0.686
## 34%     0.340 -0.412 -0.419     -0.431    -0.431 -0.404

4 Monte Carlo exercise

set.seed(12345)
Rep      = 100
nprob    = length(probs)
error    = array(0,c(Rep,nprob,4))
error1   = array(0,c(Rep,nprob,4))
samples  = matrix(0,M,4)
for (rep in 1:Rep){
  samples[,1] = rnorm(M)
  samples[,2] = BOXMULLER(M)
  samples[,3] = MARSAGLIA(M)
  samples[,4] = SIR(M,N)
  for (i in 1:4){
    quants.d       = quantile(samples[,i],probs)
    error[rep,,i]  = quants-quants.d
    error1[rep,,i] = abs(100*(error[rep,,i]/quants))
  }
}

4.1 Approximation performance: absolute errors

par(mfrow=c(2,2))
for (i in 1:4)
  boxplot(error[,,i],ylim=range(error),main=titles[i],
          ylab="Quantile error",names=probs,xlab=titles[i])

4.2 Approximation performance: percentage errors

par(mfrow=c(2,2))
for (i in 1:4)
  boxplot(error1[,,i],ylim=range(error1),main=titles[i],
          ylab="Percentage error",names=probs,xlab=titles[i])

4.3 RMSE, MAE and other measures

rmse = matrix(0,nprob,4)
mae  = matrix(0,nprob,4)
mdae = matrix(0,nprob,4)
for (i in 1:4){
  rmse[,i] = sqrt(apply(error[,,i]^2,2,mean))
  mae[,i]  = apply(abs(error[,,i]),2,mean)
  mdae[,i] = apply(error1[,,i],2,median)
}

par(mfrow=c(1,3))
plot(rmse[,1],ylim=range(rmse,mae),type="b",pch=16,axes=FALSE,
     xlab="N(0,1) tail probability",ylab="Error measure")
axis(2);box();axis(1,at=1:nprob,label=probs)
for (i in 2:4)
  points(rmse[,i],col=i,type="b",pch=16)
legend("topright",legend=titles,col=1:4,pch=16,bty="n")
title("Root mean squared error")

plot(mae[,1],ylim=range(rmse,mae),type="b",pch=16,axes=FALSE,
     xlab="N(0,1) tail probability",ylab="Error measure")
axis(2);box();axis(1,at=1:nprob,label=probs)
for (i in 2:4)
  points(mae[,i],col=i,type="b",pch=16)
title("Mean absolute error")


plot(mdae[,1],ylim=range(rmse,mae,mdae),type="b",pch=16,axes=FALSE,
     xlab="N(0,1) tail probability",ylab="Error measure")
axis(2);box();axis(1,at=1:nprob,label=probs)
for (i in 2:4)
  points(mdae[,i],col=i,type="b",pch=16)
title("Median absolute percentage error")

LS0tCnRpdGxlOiAiU2FtcGxpbmcgZnJvbSAkTigwLDEpJCIKc3VidGl0bGU6ICJybm9ybSwgQm94LU1pbGxlciwgTWFyc2FnbGlhIGFuZCBTSVIiCmF1dGhvcjogIkhlZGliZXJ0IEZyZWl0YXMgTG9wZXMiCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICB0aGVtZTogcGFwZXIKICAgIGhpZ2hsaWdodDogcHlnbWVudHMKICAgIHRvYzogdHJ1ZQogICAgdG9jX2RlcHRoOiAzCiAgICB0b2NfY29sbGFwc2VkOiB0cnVlCiMgICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKLS0tCgoKIyBUaGUgTW9udGUgQ2FybG8gYWxnb3JpdGhtcwoKIyMgcm5vcm0KCkluIFIsIGl0IGlzIGVhc3kgdG8gc2FtcGxlIGZyb20gYSBzdGFuZGFyZCBub3JtYWwgdXNpbmcgdGhlICoqcm5vcm0qKiBmdW5jdGlvbgpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTR9CnggPSBybm9ybSgxMDAwMCkKYyhtZWFuKHgpLHZhcih4KSxkbm9ybSgwKSxxbm9ybSgwLjk3NSkscG5vcm0oMCkpCnBhcihtZnJvdz1jKDEsMikpCmhpc3QoeCxwcm9iPVRSVUUsbWFpbj0iRHJhd3MgZnJvbSBOKDAsMSkiLHhsYWI9IiIpCnBsb3QoZGVuc2l0eSh4KSx4bGFiPSIiLG1haW49Iktlcm5lbCBkZW5zaXR5IGFwcHJveGltYXRpb24iKQpgYGAKCiMjIEJveC1NdWxsZXIgbWV0aG9kCgpUaGUgQm94LU11bGxlciB0cmFuc2Zvcm0gaXMgYSBjbGFzc2ljIGFsZ29yaXRobSB1c2VkIHRvIGdlbmVyYXRlIHBhaXJzIG9mIGluZGVwZW5kZW50LCBzdGFuZGFyZCBub3JtYWxseSBkaXN0cmlidXRlZCByYW5kb20gbnVtYmVycyBmcm9tIGEgc291cmNlIG9mIHVuaWZvcm1seSBkaXN0cmlidXRlZCByYW5kb20gbnVtYmVycy4gIEl0IHJlbGllcyBvbiB0aGUgZmFjdCB0aGF0IGEgdHdvLWRpbWVuc2lvbmFsIHN0YW5kYXJkIG5vcm1hbCBkaXN0cmlidXRpb24gaXMgcm90YXRpb25hbGx5IHN5bW1ldHJpYy4gV2hlbiBleHByZXNzZWQgaW4gcG9sYXIgY29vcmRpbmF0ZXMsIHRoZSBhbmdsZSBpcyB1bmlmb3JtbHkgZGlzdHJpYnV0ZWQsIGFuZCB0aGUgc3F1YXJlZCByYWRpdXMgZm9sbG93cyBhbiBleHBvbmVudGlhbCBkaXN0cmlidXRpb24uICBJZiAkVV8xJCBhbmQgJFVfMiQgYXJlIGluZGVwZW5kZW50IHJhbmRvbSB2YXJpYWJsZXMgJFUoMCwxKSQsIHRoZW4gdGhlIHZhcmlhYmxlcyAkWl8wJCBhbmQgJFpfMSQgClxiZWdpbntlcW5hcnJheSp9ClpfMCAmPSYgXGxlZnQoLTIgXGxuIFVfMVxyaWdodCleezEvMn0gXGNvcygyXHBpIFVfMilcXApaXzEgJj0mIFxsZWZ0KC0yIFxsbiBVXzFccmlnaHQpXnsxLzJ9IFxzaW4oMlxwaSBVXzIpLApcZW5ke2VxbmFycmF5Kn0KYXJlIGluZGVwZW5kZW50ICROKDAsIDEpJC4KCmBgYHtyfQpCT1hNVUxMRVIgPSBmdW5jdGlvbihNKXsKICB1MSA9IHJ1bmlmKE0vMikKICB1MiA9IHJ1bmlmKE0vMikKICB6MCA9IHNxcnQoLTIqbG9nKHUxKSkqY29zKDIqcGkqdTIpCiAgejEgPSBzcXJ0KC0yKmxvZyh1MSkpKnNpbigyKnBpKnUyKQogIHJldHVybihjKHowLHoxKSkKfQpgYGAKCiMjIE1hcnNhZ2xpYSBwb2xhciBtZXRob2QKClRoZSBtZXRob2QgaXMgYW4gaW1wcm92ZW1lbnQgb24gdGhlIEJveC1NdWxsZXIgdHJhbnNmb3JtIGJlY2F1c2UgaXQgYXZvaWRzIHRoZSBjb21wdXRhdGlvbmFsbHkgZXhwZW5zaXZlIGNhbGxzIHRvICRzaW4kIGFuZCAkY29zJC4gIEluc3RlYWQsIGl0IHVzZXMgYSByZWplY3Rpb24gc2FtcGxpbmcgc3RlcCB0byBwaWNrIGEgcG9pbnQgJCh2XzEsdl8yKSQgaW5zaWRlIHRoZSB1bml0IGRpc2s6ICgxKSAKR2VuZXJhdGUgJHZfMSx2XzIgXHNpbSBVKC0xLDEpJCBhbmQgKDIpIENvbXB1dGUgJHM9dl8xXjIrdl8yXjIkLiAoMykgSWYgJHMgPCAxJCwgcmV0dXJuIHR3byBpbmRlcGVuZGVudCBzdGFuZGFyZCBub3JtYWwgZHJhd3M6ClxiZWdpbntlcW5hcnJheSp9CnpfMSAmPSYgdl8xIFxsZWZ0KC1cZnJhY3syIFxsbiBzfXtzfVxyaWdodCleezEvMn1cXAp6XzIgJj0mIHZfMiBcbGVmdCgtXGZyYWN7MiBcbG4gc317c31ccmlnaHQpXnsxLzJ9LApcZW5ke2VxbmFycmF5Kn0Kb3RoZXJ3aXNlIHJlamVjdCBhbmQgcmVwZWF0IHN0ZXBzICgxKSBhbmQgKDIpLiAgVGhlIG1haW4gdHJhZGUtb2ZmIGlzICJ3YXN0aW5nIgpzb21lIHVuaWZvcm0gZHJhd3MgKGFib3V0ICQyMVwlJCBhcmUgcmVqZWN0ZWQpLCBidXQgeW91IGdhaW4gc3BlZWQgYnkgc2tpcHBpbmcgCnRoZSB0cmlnb25vbWV0cnkuCgpgYGB7cn0KTUFSU0FHTElBID0gZnVuY3Rpb24oTSl7CiAgdjEgPSBydW5pZihNLC0xLDEpCiAgdjIgPSBydW5pZihNLC0xLDEpCiAgcyAgPSB2MV4yK3YyXjIKICBpbmQgPSBzPDEKICBzICA9IChzW2luZF0pWzE6KE0vMildCiAgdjEgPSAodjFbaW5kXSlbMTooTS8yKV0KICB2MiA9ICh2MltpbmRdKVsxOihNLzIpXSAgCiAgejAgPSB2MSpzcXJ0KC0yKmxvZyhzKS9zKQogIHoxID0gdjIqc3FydCgtMipsb2cocykvcykKICByZXR1cm4oYyh6MCx6MSkpCn0KYGBgCgojIyBTYW1wbGluZyBpbXBvcnRhbmNlIHJlc2FtcGxpbmcgCgpXZSd2ZSBhbHJlYWR5IHRhbGtlZCBhYm91dCB0aGUgU0lSIHNjaGVtZSBpbiB5b3VyIHByZXZpb3VzIGNsYXNzZXMuCgpgYGB7cn0KU0lSID0gZnVuY3Rpb24oTSxOKXsKICBkcmF3ID0gcnQoTSxkZj00KQogIHcgICAgPSBkbm9ybShkcmF3KS9kdChkcmF3LGRmPTQpCiAgcmV0dXJuKHNhbXBsZShkcmF3LHJlcGxhY2U9VFJVRSxzaXplPU4scHJvYj13KSkKfQpgYGAKCgojIFNhbXBsaW5nIGFuZCBjb21wYXJpc29uCgpXZSBjb21wYXJlIGhpc3RvZ3JhbXMgYmFzZWQgb24gdGhlIHNhbXBsaW5nIHNjaGVtZXMgdG8gdGhlIApleGFjdCBkZW5zaXR5IGV2YWx1YXRpb25zCgoKYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD02fQpNID0gMjAwMDAKTiA9IDIwMDAwCnNhbXBsZXMgPSBtYXRyaXgoMCxNLDQpCnNhbXBsZXNbLDFdID0gcm5vcm0oTSkKc2FtcGxlc1ssMl0gPSBCT1hNVUxMRVIoTSkKc2FtcGxlc1ssM10gPSBNQVJTQUdMSUEoTSkKc2FtcGxlc1ssNF0gPSBTSVIoTSxOKQoKdGl0bGVzID0gYygicm5vcm0iLCJCb3gtTXVsbGVyIiwiTWFyc2FnbGlhIiwiU0lSIikKeCAgICAgID0gc2VxKG1pbihzYW1wbGVzKSxtYXgoc2FtcGxlcyksbGVuZ3RoPTEwMDApCmRlbiAgICA9IGRub3JtKHgpCmJyZWFrcyA9IHNlcShtaW4oc2FtcGxlcyksbWF4KHNhbXBsZXMpLGxlbmd0aD0zMCkKcGFyKG1mcm93PWMoMiwyKSkKZm9yIChpIGluIDE6NCl7CiAgaGlzdChzYW1wbGVzWyxpXSxwcm9iPVRSVUUsYnJlYWtzPWJyZWFrcyxtYWluPXRpdGxlc1tpXSxjb2w9InNreWJsdWUiLHhsYWI9IkRyYXdzIikKICBsaW5lcyh4LGRlbixjb2w9Mixsd2Q9MikKfQpgYGAKCiMgQ29tcGFyaW5nIHF1YW50aWxlcwpgYGB7cn0KcHJvYnMgID0gYygwLjAxLDAuMDI1LDAuMDUsMC4xLDAuMjUsMC4zNCkKcXVhbnRzID0gcW5vcm0ocHJvYnMpCnRhYiAgID0gY2JpbmQocHJvYnMscW5vcm0ocHJvYnMpLGFwcGx5KHNhbXBsZXMsMixxdWFudGlsZSxwcm9icykpCmNvbG5hbWVzKHRhYikgPSBjKCJRdWFudGlsZSIsIkV4YWN0Iiwicm5vcm0iLCJCb3gtTXVsbGVyIiwiTWFyc2FnbGlhIiwiU0lSIikKcm91bmQodGFiLDMpCmBgYAoKCiMgTW9udGUgQ2FybG8gZXhlcmNpc2UKCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9OH0Kc2V0LnNlZWQoMTIzNDUpClJlcCAgICAgID0gMTAwCm5wcm9iICAgID0gbGVuZ3RoKHByb2JzKQplcnJvciAgICA9IGFycmF5KDAsYyhSZXAsbnByb2IsNCkpCmVycm9yMSAgID0gYXJyYXkoMCxjKFJlcCxucHJvYiw0KSkKc2FtcGxlcyAgPSBtYXRyaXgoMCxNLDQpCmZvciAocmVwIGluIDE6UmVwKXsKICBzYW1wbGVzWywxXSA9IHJub3JtKE0pCiAgc2FtcGxlc1ssMl0gPSBCT1hNVUxMRVIoTSkKICBzYW1wbGVzWywzXSA9IE1BUlNBR0xJQShNKQogIHNhbXBsZXNbLDRdID0gU0lSKE0sTikKICBmb3IgKGkgaW4gMTo0KXsKICAJcXVhbnRzLmQgICAgICAgPSBxdWFudGlsZShzYW1wbGVzWyxpXSxwcm9icykKICAgIGVycm9yW3JlcCwsaV0gID0gcXVhbnRzLXF1YW50cy5kCiAgICBlcnJvcjFbcmVwLCxpXSA9IGFicygxMDAqKGVycm9yW3JlcCwsaV0vcXVhbnRzKSkKICB9Cn0KYGBgCgojIyBBcHByb3hpbWF0aW9uIHBlcmZvcm1hbmNlOiBhYnNvbHV0ZSBlcnJvcnMKCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9OH0KcGFyKG1mcm93PWMoMiwyKSkKZm9yIChpIGluIDE6NCkKICBib3hwbG90KGVycm9yWywsaV0seWxpbT1yYW5nZShlcnJvciksbWFpbj10aXRsZXNbaV0sCiAgICAgICAgICB5bGFiPSJRdWFudGlsZSBlcnJvciIsbmFtZXM9cHJvYnMseGxhYj10aXRsZXNbaV0pCmBgYAoKCiMjIEFwcHJveGltYXRpb24gcGVyZm9ybWFuY2U6IHBlcmNlbnRhZ2UgZXJyb3JzCgpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTh9CnBhcihtZnJvdz1jKDIsMikpCmZvciAoaSBpbiAxOjQpCiAgYm94cGxvdChlcnJvcjFbLCxpXSx5bGltPXJhbmdlKGVycm9yMSksbWFpbj10aXRsZXNbaV0sCiAgICAgICAgICB5bGFiPSJQZXJjZW50YWdlIGVycm9yIixuYW1lcz1wcm9icyx4bGFiPXRpdGxlc1tpXSkKYGBgCgoKIyMgUk1TRSwgTUFFIGFuZCBvdGhlciBtZWFzdXJlcwoKYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9NH0Kcm1zZSA9IG1hdHJpeCgwLG5wcm9iLDQpCm1hZSAgPSBtYXRyaXgoMCxucHJvYiw0KQptZGFlID0gbWF0cml4KDAsbnByb2IsNCkKZm9yIChpIGluIDE6NCl7CiAgcm1zZVssaV0gPSBzcXJ0KGFwcGx5KGVycm9yWywsaV1eMiwyLG1lYW4pKQogIG1hZVssaV0gID0gYXBwbHkoYWJzKGVycm9yWywsaV0pLDIsbWVhbikKICBtZGFlWyxpXSA9IGFwcGx5KGVycm9yMVssLGldLDIsbWVkaWFuKQp9CgpwYXIobWZyb3c9YygxLDMpKQpwbG90KHJtc2VbLDFdLHlsaW09cmFuZ2Uocm1zZSxtYWUpLHR5cGU9ImIiLHBjaD0xNixheGVzPUZBTFNFLAogICAgIHhsYWI9Ik4oMCwxKSB0YWlsIHByb2JhYmlsaXR5Iix5bGFiPSJFcnJvciBtZWFzdXJlIikKYXhpcygyKTtib3goKTtheGlzKDEsYXQ9MTpucHJvYixsYWJlbD1wcm9icykKZm9yIChpIGluIDI6NCkKICBwb2ludHMocm1zZVssaV0sY29sPWksdHlwZT0iYiIscGNoPTE2KQpsZWdlbmQoInRvcHJpZ2h0IixsZWdlbmQ9dGl0bGVzLGNvbD0xOjQscGNoPTE2LGJ0eT0ibiIpCnRpdGxlKCJSb290IG1lYW4gc3F1YXJlZCBlcnJvciIpCgpwbG90KG1hZVssMV0seWxpbT1yYW5nZShybXNlLG1hZSksdHlwZT0iYiIscGNoPTE2LGF4ZXM9RkFMU0UsCiAgICAgeGxhYj0iTigwLDEpIHRhaWwgcHJvYmFiaWxpdHkiLHlsYWI9IkVycm9yIG1lYXN1cmUiKQpheGlzKDIpO2JveCgpO2F4aXMoMSxhdD0xOm5wcm9iLGxhYmVsPXByb2JzKQpmb3IgKGkgaW4gMjo0KQogIHBvaW50cyhtYWVbLGldLGNvbD1pLHR5cGU9ImIiLHBjaD0xNikKdGl0bGUoIk1lYW4gYWJzb2x1dGUgZXJyb3IiKQoKCnBsb3QobWRhZVssMV0seWxpbT1yYW5nZShybXNlLG1hZSxtZGFlKSx0eXBlPSJiIixwY2g9MTYsYXhlcz1GQUxTRSwKICAgICB4bGFiPSJOKDAsMSkgdGFpbCBwcm9iYWJpbGl0eSIseWxhYj0iRXJyb3IgbWVhc3VyZSIpCmF4aXMoMik7Ym94KCk7YXhpcygxLGF0PTE6bnByb2IsbGFiZWw9cHJvYnMpCmZvciAoaSBpbiAyOjQpCiAgcG9pbnRzKG1kYWVbLGldLGNvbD1pLHR5cGU9ImIiLHBjaD0xNikKdGl0bGUoIk1lZGlhbiBhYnNvbHV0ZSBwZXJjZW50YWdlIGVycm9yIikKCmBgYAoKCg==