1 The data

The following non-linear regression model was considered by Marske (1967), and studied in detail by Bates and Watts (1988), relates biochemical oxygen demand (bod), denoted here by \(y\) and measured in mg/l, of prepared water samples to incubation time x (in days).

x = c(1:5,7)
y = c(8.3,10.3,19,16,15.6,19.8)
n = length(x)
plot(x,y,xlab="Incubation time (days)",ylab="biochemical oxygen demand (mg/l)")

2 The nonlinear-regression model

We will assume that \(y_i\) is related to \(x_i\), for \(i=1,\ldots,n\), nonlinearly as follows \[ y_i = \beta_1(1-e^{-\beta_2 x_i}) + \varepsilon_i \qquad \varepsilon_i \sim N(0,\sigma^2), \] where \(\beta_1\) is the asymptotic maximum BOD and \(\beta_2\) is the rate constant.

2.1 Contours of the likelihood function

Here we are assuming \(\sigma=2.55\) (which is actually an MLE estimate) in order to plot the contours of the bivariate likelihood for \((\beta_1,\beta_2)\).

like = function(beta1,beta2,sigma){
  prod(dnorm(y,beta1*(1-exp(-beta2*x)),sigma))
}
prior = function(beta1,beta2){
  V = cbind(1-exp(-beta2*x),beta1*x*(1-exp(-beta2*x)))
  return(sqrt(det(t(V)%*%V)))
}
post = function(beta1,beta2,sigma){
  prior(beta1,beta2)*like(beta1,beta2,sigma)
}

sigma.mle = 2.55
N      = 200
beta1  = seq(10,40,length=N)
beta2  = seq(0,2.5,length=N)
likes  = matrix(0,N,N)
priors = matrix(0,N,N)
for (i in 1:N)
  for (j in 1:N){
    likes[i,j] = like(beta1[i],beta2[j],sigma.mle)
    priors[i,j] = prior(beta1[i],beta2[j])
  }
posts = priors*likes

par(mfrow=c(1,3))
contour(beta1,beta2,priors,drawlabels=FALSE,nlevels=20,xlab=expression(beta[1]),ylab=expression(beta[2]),main="Prior")
contour(beta1,beta2,likes,drawlabels=FALSE,nlevels=20,xlab=expression(beta[1]),ylab=expression(beta[2]),main="Likelihood")
contour(beta1,beta2,posts,drawlabels=FALSE,nlevels=20,xlab=expression(beta[1]),ylab=expression(beta[2]),main="Posterior")

3 Maximum likelihood estimation

We will fit the non-linear model to find MLEs via the nls R fucntion for nonlinear least squares, which is equivalent to MLE for Gaussian errors.

#install.packages("MASS")
#install.packages("mvtnorm")
library("MASS")
library("mvtnorm")

model = nls(y~beta1*(1-exp(-beta2*x)),start=list(beta1=20,beta2=0.5))

summary(model)
## 
## Formula: y ~ beta1 * (1 - exp(-beta2 * x))
## 
## Parameters:
##       Estimate Std. Error t value Pr(>|t|)   
## beta1  19.1426     2.4959   7.670  0.00155 **
## beta2   0.5311     0.2031   2.615  0.05910 . 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 2.549 on 4 degrees of freedom
## 
## Number of iterations to convergence: 3 
## Achieved convergence tolerance: 1.459e-06
# MLE of beta1, beta2 and sigma2
beta.mle  = coef(model)
beta1.mle = beta.mle["beta1"]
beta2.mle = beta.mle["beta2"]
res       = residuals(model)
sigma.mle = sqrt(sum(res^2)/(n-2))

c(beta.mle,sigma.mle)
##      beta1      beta2            
## 19.1425816  0.5310908  2.5490325
xx = seq(min(x),max(x),length=N)
plot(x,y,xlab="Incubation time (days)",ylab="biochemical oxygen demand (mg/l)")
lines(xx,beta1.mle*(1-exp(-beta2.mle*xx)),col=4)

3.1 Asymptotic Covariance Matrix

f.beta1   = 1-exp(-beta1.mle*x)
f.beta2   = beta1.mle*x*exp(-beta2.mle*x)
F.mat     = cbind(f.beta1,f.beta2)
V.beta    = sigma.mle^2*solve(t(F.mat)%*%F.mat)
V.beta
##           f.beta1     f.beta2
## f.beta1  9.187636 -0.87944303
## f.beta2 -0.879443  0.09542849

4 SIR using bivariate normal as proposal

4.1 Proposal draws

set.seed(54321)
k = 9
M1 = 100000
M = 20000
beta.draws  = mvrnorm(M1,beta.mle,k*V.beta)
sigma.draws = runif(M1,0,10)

par(mfrow=c(1,1))
plot(beta.draws,xlab=expression(beta[1]),ylab=expression(beta[2]))
contour(beta1,beta2,posts,drawlabels=FALSE,nlevels=10,add=TRUE,col=3)
title("Proposal draws")

4.2 Computing resampling weights

w = rep(0,M1)
for (i in 1:M1)
  w[i] = post(beta.draws[i,1],beta.draws[i,2],sigma.draws[i])/dmvnorm(beta.draws[i,],beta.mle, k*V.beta)

4.3 Resampling

ind        = sample(1:M1,size=M,replace=TRUE,prob=w)
beta.post  = beta.draws[ind,]
sigma.post = sigma.draws[ind]

par(mfrow=c(2,2))
plot(beta.post,xlab=expression(beta[1]),ylab=expression(beta[2]),pch=16)
contour(beta1,beta2,posts,drawlabels=FALSE,nlevels=20,add=TRUE,col=3,lwd=2)
title("Posterior draws")
hist(beta.post[,1],prob=TRUE,main="",xlab=expression(beta[1]),ylab="Posterior density")
hist(beta.post[,2],prob=TRUE,main="",xlab=expression(beta[2]),ylab="Posterior density")
hist(sigma.post,prob=TRUE,main="",xlab=expression(sigma),ylab="Posterior density")

4.4 Preditive analysis

Below we will sample from \[ p(y_{new}|x,y,x_{new}) = \int_\Theta p(y_{new}|x_{new},\theta)p(\theta|x,y)d\theta, \] where \(x_{new}\) will be values between \(1\) and \(7\). Since we have draws \(\theta^{(1)},\ldots,\theta^{(M)}\) from \(p(\theta|x,y)\), we can sample \(y_{new}^{(i)}\) from \(p(y|x_{new},\theta^{(i)}))\), for \(i=1,\ldots,M\). Therefore \[ y_{new}^{(1)},\ldots,y_{new}^{(M)}\sim p(y_{new}|x,y,x_{new}). \]

set.seed(1256654)
N    = 60
xx   = seq(min(x),max(x),length=N)
pred = matrix(0,M,N)
predx6 = rep(0,M)
for (i in 1:M){
  pred[i,]  = beta.post[i,1]*(1-exp(-beta.post[i,2]*xx))+rnorm(N,0,sigma.post[i])
  predx6[i] = beta.post[i,1]*(1-exp(-beta.post[i,2]*6))+rnorm(1,0,sigma.post[i])
}
qpred = t(apply(pred,2,quantile,c(0.1,0.5,0.9)))
qx6 = round(quantile(predx6,c(0.1,0.5,0.9)),1)

par(mfrow=c(1,2))
plot(x,y,ylim=range(qpred,y),xlab="Incubation time (days)",ylab="biochemical oxygen demand (mg/l)",pch=16)
lines(xx,qpred[,1],lwd=2,col=2,lty=2)
lines(xx,qpred[,2],lwd=2,col=2,lty=2)
lines(xx,qpred[,3],lwd=2,col=2,lty=2)
lines(xx,beta1.mle*(1-exp(-beta2.mle*xx)),col=4,lwd=2)
legend("bottomright",legend=c("OLS/MLE","BAYES"),lty=1,col=c(4,2),bty="n",lwd=2)
hist(predx6,prob=TRUE,main=paste("90% IC:(",qx6[1],",",qx6[3],")\n Median=",qx6[2],sep=""),
     xlab="BOD (mg/l) when x[new]=6",ylab="Predictive density",breaks=20)

LS0tCnRpdGxlOiAiTm9ubGluZWFyIHJlZ3Jlc3Npb24iCnN1YnRpdGxlOiAiUG9zdGVyaW9yIGluZmVyZW5jZSB2aWEgU0lSIgphdXRob3I6ICJIZWRpYmVydCBGcmVpdGFzIExvcGVzIgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdGhlbWU6IHBhcGVyCiAgICBoaWdobGlnaHQ6IHB5Z21lbnRzCiAgICB0b2M6IHRydWUKICAgIHRvY19kZXB0aDogMwogICAgdG9jX2NvbGxhcHNlZDogdHJ1ZQojICAgIHRvY19mbG9hdDogdHJ1ZQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCi0tLQoKCiMgVGhlIGRhdGEKClRoZSBmb2xsb3dpbmcgbm9uLWxpbmVhciByZWdyZXNzaW9uIG1vZGVsIHdhcyBjb25zaWRlcmVkIGJ5IE1hcnNrZSAoMTk2NyksIGFuZCBzdHVkaWVkIGluIGRldGFpbCBieSBCYXRlcyBhbmQgV2F0dHMgKDE5ODgpLCByZWxhdGVzIGJpb2NoZW1pY2FsIG94eWdlbiBkZW1hbmQgKGJvZCksIGRlbm90ZWQgaGVyZSBieSAkeSQgYW5kIG1lYXN1cmVkIGluIG1nL2wsIG9mIHByZXBhcmVkIHdhdGVyIHNhbXBsZXMgdG8gaW5jdWJhdGlvbiB0aW1lIHggKGluIGRheXMpLiAgCgpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTZ9CnggPSBjKDE6NSw3KQp5ID0gYyg4LjMsMTAuMywxOSwxNiwxNS42LDE5LjgpCm4gPSBsZW5ndGgoeCkKcGxvdCh4LHkseGxhYj0iSW5jdWJhdGlvbiB0aW1lIChkYXlzKSIseWxhYj0iYmlvY2hlbWljYWwgb3h5Z2VuIGRlbWFuZCAobWcvbCkiKQpgYGAKCiMgVGhlIG5vbmxpbmVhci1yZWdyZXNzaW9uIG1vZGVsCgpXZSB3aWxsIGFzc3VtZSB0aGF0ICR5X2kkIGlzIHJlbGF0ZWQgdG8gJHhfaSQsIGZvciAkaT0xLFxsZG90cyxuJCwgbm9ubGluZWFybHkgYXMgZm9sbG93cwokJAp5X2kgPSBcYmV0YV8xKDEtZV57LVxiZXRhXzIgeF9pfSkgKyBcdmFyZXBzaWxvbl9pIFxxcXVhZCBcdmFyZXBzaWxvbl9pIFxzaW0gTigwLFxzaWdtYV4yKSwKJCQKd2hlcmUgJFxiZXRhXzEkIGlzIHRoZSBhc3ltcHRvdGljIG1heGltdW0gQk9EIGFuZCAkXGJldGFfMiQgaXMgdGhlIHJhdGUgCmNvbnN0YW50LiAgCgoqIOKBoEJhdGVzIEQuIE0uLCBXYXR0cyBELiBHLiAoMTk4OCkuIE5vbmxpbmVhciBSZWdyZXNzaW9uIEFuYWx5c2lzIGFuZCBJdHMgQXBwbGljYXRpb25zLCBzZXJpZXMgV2lsZXkgU2VyaWVzIGluIFByb2JhYmlsaXR5IGFuZCBTdGF0aXN0aWNzLiBXaWxleS4KCiog4oGgTWFyc2tlIEQuIE0uICgxOTY3KS4gQmlvY2hlbWljYWwgT3h5Z2VuIERlbWFuZCBEYXRhIEludGVycHJldGF0aW9uIFVzaW5nClN1bSBvZiBTcXVhcmVzIFN1cmZhY2UuIE1hc3RlcidzIHRoZXNpcywgVW5pdmVyc2l0eSBvZiBXaXNjb25zaW4g4oCTIE1hZGlzb24uCgojIyBDb250b3VycyBvZiB0aGUgbGlrZWxpaG9vZCBmdW5jdGlvbgoKSGVyZSB3ZSBhcmUgYXNzdW1pbmcgJFxzaWdtYT0yLjU1JCAod2hpY2ggaXMgYWN0dWFsbHkgYW4gTUxFIGVzdGltYXRlKSBpbiBvcmRlciB0byBwbG90IHRoZSBjb250b3VycyBvZiB0aGUgYml2YXJpYXRlIGxpa2VsaWhvb2QgZm9yICQoXGJldGFfMSxcYmV0YV8yKSQuCgpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD00fQpsaWtlID0gZnVuY3Rpb24oYmV0YTEsYmV0YTIsc2lnbWEpewogIHByb2QoZG5vcm0oeSxiZXRhMSooMS1leHAoLWJldGEyKngpKSxzaWdtYSkpCn0KcHJpb3IgPSBmdW5jdGlvbihiZXRhMSxiZXRhMil7CiAgViA9IGNiaW5kKDEtZXhwKC1iZXRhMip4KSxiZXRhMSp4KigxLWV4cCgtYmV0YTIqeCkpKQogIHJldHVybihzcXJ0KGRldCh0KFYpJSolVikpKQp9CnBvc3QgPSBmdW5jdGlvbihiZXRhMSxiZXRhMixzaWdtYSl7CiAgcHJpb3IoYmV0YTEsYmV0YTIpKmxpa2UoYmV0YTEsYmV0YTIsc2lnbWEpCn0KCnNpZ21hLm1sZSA9IDIuNTUKTiAgICAgID0gMjAwCmJldGExICA9IHNlcSgxMCw0MCxsZW5ndGg9TikKYmV0YTIgID0gc2VxKDAsMi41LGxlbmd0aD1OKQpsaWtlcyAgPSBtYXRyaXgoMCxOLE4pCnByaW9ycyA9IG1hdHJpeCgwLE4sTikKZm9yIChpIGluIDE6TikKICBmb3IgKGogaW4gMTpOKXsKICAgIGxpa2VzW2ksal0gPSBsaWtlKGJldGExW2ldLGJldGEyW2pdLHNpZ21hLm1sZSkKICAgIHByaW9yc1tpLGpdID0gcHJpb3IoYmV0YTFbaV0sYmV0YTJbal0pCiAgfQpwb3N0cyA9IHByaW9ycypsaWtlcwoKcGFyKG1mcm93PWMoMSwzKSkKY29udG91cihiZXRhMSxiZXRhMixwcmlvcnMsZHJhd2xhYmVscz1GQUxTRSxubGV2ZWxzPTIwLHhsYWI9ZXhwcmVzc2lvbihiZXRhWzFdKSx5bGFiPWV4cHJlc3Npb24oYmV0YVsyXSksbWFpbj0iUHJpb3IiKQpjb250b3VyKGJldGExLGJldGEyLGxpa2VzLGRyYXdsYWJlbHM9RkFMU0UsbmxldmVscz0yMCx4bGFiPWV4cHJlc3Npb24oYmV0YVsxXSkseWxhYj1leHByZXNzaW9uKGJldGFbMl0pLG1haW49Ikxpa2VsaWhvb2QiKQpjb250b3VyKGJldGExLGJldGEyLHBvc3RzLGRyYXdsYWJlbHM9RkFMU0UsbmxldmVscz0yMCx4bGFiPWV4cHJlc3Npb24oYmV0YVsxXSkseWxhYj1leHByZXNzaW9uKGJldGFbMl0pLG1haW49IlBvc3RlcmlvciIpCmBgYAoKIyBNYXhpbXVtIGxpa2VsaWhvb2QgZXN0aW1hdGlvbgpXZSB3aWxsIGZpdCB0aGUgbm9uLWxpbmVhciBtb2RlbCB0byBmaW5kIE1MRXMgdmlhIHRoZSAqKm5scyoqIFIgZnVjbnRpb24gZm9yIG5vbmxpbmVhciBsZWFzdCBzcXVhcmVzLCB3aGljaCBpcyBlcXVpdmFsZW50IHRvIE1MRSBmb3IgR2F1c3NpYW4gZXJyb3JzLgoKYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD02fQojaW5zdGFsbC5wYWNrYWdlcygiTUFTUyIpCiNpbnN0YWxsLnBhY2thZ2VzKCJtdnRub3JtIikKbGlicmFyeSgiTUFTUyIpCmxpYnJhcnkoIm12dG5vcm0iKQoKbW9kZWwgPSBubHMoeX5iZXRhMSooMS1leHAoLWJldGEyKngpKSxzdGFydD1saXN0KGJldGExPTIwLGJldGEyPTAuNSkpCgpzdW1tYXJ5KG1vZGVsKQoKIyBNTEUgb2YgYmV0YTEsIGJldGEyIGFuZCBzaWdtYTIKYmV0YS5tbGUgID0gY29lZihtb2RlbCkKYmV0YTEubWxlID0gYmV0YS5tbGVbImJldGExIl0KYmV0YTIubWxlID0gYmV0YS5tbGVbImJldGEyIl0KcmVzICAgICAgID0gcmVzaWR1YWxzKG1vZGVsKQpzaWdtYS5tbGUgPSBzcXJ0KHN1bShyZXNeMikvKG4tMikpCgpjKGJldGEubWxlLHNpZ21hLm1sZSkKCnh4ID0gc2VxKG1pbih4KSxtYXgoeCksbGVuZ3RoPU4pCnBsb3QoeCx5LHhsYWI9IkluY3ViYXRpb24gdGltZSAoZGF5cykiLHlsYWI9ImJpb2NoZW1pY2FsIG94eWdlbiBkZW1hbmQgKG1nL2wpIikKbGluZXMoeHgsYmV0YTEubWxlKigxLWV4cCgtYmV0YTIubWxlKnh4KSksY29sPTQpCmBgYAoKIyMgQXN5bXB0b3RpYyBDb3ZhcmlhbmNlIE1hdHJpeAoKYGBge3J9CmYuYmV0YTEgICA9IDEtZXhwKC1iZXRhMS5tbGUqeCkKZi5iZXRhMiAgID0gYmV0YTEubWxlKngqZXhwKC1iZXRhMi5tbGUqeCkKRi5tYXQgICAgID0gY2JpbmQoZi5iZXRhMSxmLmJldGEyKQpWLmJldGEgICAgPSBzaWdtYS5tbGVeMipzb2x2ZSh0KEYubWF0KSUqJUYubWF0KQpWLmJldGEKYGBgCgoKCgojIFNJUiB1c2luZyBiaXZhcmlhdGUgbm9ybWFsIGFzIHByb3Bvc2FsCgojIyBQcm9wb3NhbCBkcmF3cwpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTZ9CnNldC5zZWVkKDU0MzIxKQprID0gOQpNMSA9IDEwMDAwMApNID0gMjAwMDAKYmV0YS5kcmF3cyAgPSBtdnJub3JtKE0xLGJldGEubWxlLGsqVi5iZXRhKQpzaWdtYS5kcmF3cyA9IHJ1bmlmKE0xLDAsMTApCgpwYXIobWZyb3c9YygxLDEpKQpwbG90KGJldGEuZHJhd3MseGxhYj1leHByZXNzaW9uKGJldGFbMV0pLHlsYWI9ZXhwcmVzc2lvbihiZXRhWzJdKSkKY29udG91cihiZXRhMSxiZXRhMixwb3N0cyxkcmF3bGFiZWxzPUZBTFNFLG5sZXZlbHM9MTAsYWRkPVRSVUUsY29sPTMpCnRpdGxlKCJQcm9wb3NhbCBkcmF3cyIpCmBgYAoKIyMgQ29tcHV0aW5nIHJlc2FtcGxpbmcgd2VpZ2h0cwpgYGB7cn0KdyA9IHJlcCgwLE0xKQpmb3IgKGkgaW4gMTpNMSkKICB3W2ldID0gcG9zdChiZXRhLmRyYXdzW2ksMV0sYmV0YS5kcmF3c1tpLDJdLHNpZ21hLmRyYXdzW2ldKS9kbXZub3JtKGJldGEuZHJhd3NbaSxdLGJldGEubWxlLCBrKlYuYmV0YSkKYGBgCgojIyBSZXNhbXBsaW5nCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTh9CmluZCAgICAgICAgPSBzYW1wbGUoMTpNMSxzaXplPU0scmVwbGFjZT1UUlVFLHByb2I9dykKYmV0YS5wb3N0ICA9IGJldGEuZHJhd3NbaW5kLF0Kc2lnbWEucG9zdCA9IHNpZ21hLmRyYXdzW2luZF0KCnBhcihtZnJvdz1jKDIsMikpCnBsb3QoYmV0YS5wb3N0LHhsYWI9ZXhwcmVzc2lvbihiZXRhWzFdKSx5bGFiPWV4cHJlc3Npb24oYmV0YVsyXSkscGNoPTE2KQpjb250b3VyKGJldGExLGJldGEyLHBvc3RzLGRyYXdsYWJlbHM9RkFMU0UsbmxldmVscz0yMCxhZGQ9VFJVRSxjb2w9Myxsd2Q9MikKdGl0bGUoIlBvc3RlcmlvciBkcmF3cyIpCmhpc3QoYmV0YS5wb3N0WywxXSxwcm9iPVRSVUUsbWFpbj0iIix4bGFiPWV4cHJlc3Npb24oYmV0YVsxXSkseWxhYj0iUG9zdGVyaW9yIGRlbnNpdHkiKQpoaXN0KGJldGEucG9zdFssMl0scHJvYj1UUlVFLG1haW49IiIseGxhYj1leHByZXNzaW9uKGJldGFbMl0pLHlsYWI9IlBvc3RlcmlvciBkZW5zaXR5IikKaGlzdChzaWdtYS5wb3N0LHByb2I9VFJVRSxtYWluPSIiLHhsYWI9ZXhwcmVzc2lvbihzaWdtYSkseWxhYj0iUG9zdGVyaW9yIGRlbnNpdHkiKQpgYGAKCiMjIFByZWRpdGl2ZSBhbmFseXNpcwoKQmVsb3cgd2Ugd2lsbCBzYW1wbGUgZnJvbSAKJCQKcCh5X3tuZXd9fHgseSx4X3tuZXd9KSA9IFxpbnRfXFRoZXRhIHAoeV97bmV3fXx4X3tuZXd9LFx0aGV0YSlwKFx0aGV0YXx4LHkpZFx0aGV0YSwKJCQKd2hlcmUgJHhfe25ld30kIHdpbGwgYmUgdmFsdWVzIGJldHdlZW4gJDEkIGFuZCAkNyQuICBTaW5jZSB3ZSBoYXZlIGRyYXdzICRcdGhldGFeeygxKX0sXGxkb3RzLFx0aGV0YV57KE0pfSQgZnJvbSAkcChcdGhldGF8eCx5KSQsIHdlIGNhbiBzYW1wbGUKJHlfe25ld31eeyhpKX0kIGZyb20gJHAoeXx4X3tuZXd9LFx0aGV0YV57KGkpfSkpJCwgZm9yICRpPTEsXGxkb3RzLE0kLgpUaGVyZWZvcmUKJCQKeV97bmV3fV57KDEpfSxcbGRvdHMseV97bmV3fV57KE0pfVxzaW0gcCh5X3tuZXd9fHgseSx4X3tuZXd9KS4KJCQKCgpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD01fQpzZXQuc2VlZCgxMjU2NjU0KQpOICAgID0gNjAKeHggICA9IHNlcShtaW4oeCksbWF4KHgpLGxlbmd0aD1OKQpwcmVkID0gbWF0cml4KDAsTSxOKQpwcmVkeDYgPSByZXAoMCxNKQpmb3IgKGkgaW4gMTpNKXsKICBwcmVkW2ksXSAgPSBiZXRhLnBvc3RbaSwxXSooMS1leHAoLWJldGEucG9zdFtpLDJdKnh4KSkrcm5vcm0oTiwwLHNpZ21hLnBvc3RbaV0pCiAgcHJlZHg2W2ldID0gYmV0YS5wb3N0W2ksMV0qKDEtZXhwKC1iZXRhLnBvc3RbaSwyXSo2KSkrcm5vcm0oMSwwLHNpZ21hLnBvc3RbaV0pCn0KcXByZWQgPSB0KGFwcGx5KHByZWQsMixxdWFudGlsZSxjKDAuMSwwLjUsMC45KSkpCnF4NiA9IHJvdW5kKHF1YW50aWxlKHByZWR4NixjKDAuMSwwLjUsMC45KSksMSkKCnBhcihtZnJvdz1jKDEsMikpCnBsb3QoeCx5LHlsaW09cmFuZ2UocXByZWQseSkseGxhYj0iSW5jdWJhdGlvbiB0aW1lIChkYXlzKSIseWxhYj0iYmlvY2hlbWljYWwgb3h5Z2VuIGRlbWFuZCAobWcvbCkiLHBjaD0xNikKbGluZXMoeHgscXByZWRbLDFdLGx3ZD0yLGNvbD0yLGx0eT0yKQpsaW5lcyh4eCxxcHJlZFssMl0sbHdkPTIsY29sPTIsbHR5PTIpCmxpbmVzKHh4LHFwcmVkWywzXSxsd2Q9Mixjb2w9MixsdHk9MikKbGluZXMoeHgsYmV0YTEubWxlKigxLWV4cCgtYmV0YTIubWxlKnh4KSksY29sPTQsbHdkPTIpCmxlZ2VuZCgiYm90dG9tcmlnaHQiLGxlZ2VuZD1jKCJPTFMvTUxFIiwiQkFZRVMiKSxsdHk9MSxjb2w9Yyg0LDIpLGJ0eT0ibiIsbHdkPTIpCmhpc3QocHJlZHg2LHByb2I9VFJVRSxtYWluPXBhc3RlKCI5MCUgSUM6KCIscXg2WzFdLCIsIixxeDZbM10sIilcbiBNZWRpYW49IixxeDZbMl0sc2VwPSIiKSwKICAgICB4bGFiPSJCT0QgKG1nL2wpIHdoZW4geFtuZXddPTYiLHlsYWI9IlByZWRpY3RpdmUgZGVuc2l0eSIsYnJlYWtzPTIwKQpgYGAKCg==