This is a reproduction for study purpose from https://towardsdatascience.com/bayesian-regression-with-implementation-in-r-fa71396dd59e

Starting from the basics

Recall that in linear regression, we are given target values y, data X, and we use the model: where y is N1 vector, X is ND matrix, w is D1 vector, and the error is N1 vector. We have N data points. Dimension D is understood in terms of features, so if we use a list of x, a list of x² (and a list of 1’s corresponding to w_0), we say D=3. In classic linear regression, the error term is assumed to have Normal distribution, and so it immediately follows that y is normally distributed with mean Xw, and variance of whatever variance the error term has (denote by σ², or diagonal matrix with entries σ²). The normal assumption turns out well in most cases, and this normal model is also what we use in Bayesian regression.

Parameter Inference

We are now faced with two problems: inference of w, and prediction of y for any new X. Using the well-known Bayes rule and the above assumptions, we are only steps away towards not only solving these two problems, but also giving a full probability distribution of y for any new X. Here is the Bayes rule using our notations, which expresses the posterior distribution of parameter w given data: Bayes π and f are probability density functions. Since the result is a function of w, we can ignore the denominator, knowing that the numerator is proportional to lefthand side by a constant. We know from assumptions that the likelihood function f(y|w,x) follows the normal distribution. The other term is prior distribution of w, and this reflects, as the name suggests, prior knowledge of the parameters. - Prior Distribution Defining the prior is an interesting part of the Bayesian workflow. For convenience we let \(w \sim N(m_0, S_0)\), and the hyperparameters \(m_0\) and \(S_0\) now reflect prior knowledge of w. If you have little knowledge of \(w\), or find any assignment of \(m_0\) and \(S_0\) too subjective, ‘non-informative’ priors are an amendment. In this case, we set \(m_0\) to 0 and more importantly set \(S_0\) as a diagonal matrix with very large values. We are saying that \(w\) has a very high variance, and so we have little knowledge of what \(w\) will be.

With all these probability functions defined, a few lines of simply algebraic manipulations (quite a few lines in fact) will give the posterior after observation of N data points: posterior

Predictive Distribution

A full Bayesian approach means not only getting a single prediction (denote new pair of data by \(y_0, x_0\)), but also acquiring the distribution of this new point. What we have done is the reverse of marginalizing from joint to get marginal distribution on the first line, and using Bayes rule inside the integral on the second line, where we have also removed unnecessary dependences. Notice that we know what the last two probability functions are. The result of full predictive distribution is:

Implementation in R

Implementation in R is quite convenient. Backed up with the above theoretical results, we just input matrix multiplications into our code and get results of both predictions and predictive distributions. To illustrate with an example, we use a toy problem: X is from -1 to 1, evenly spaced, and y is constructed as the following additions of sinusoidal curves with normal noise (see graph below for illustration of y). BayesianToyProblem The following code gets this data.

The following code (under section Maximum a Posteriori) implements all the above theoretical results through matrix multiplications. We also expand features of x (denoted in code as phi_X, under section Construct basis functions). Just as we would expand x into x², etc., we now expand it into 9 radial basis functions, each one looking like the follows. Note that although these look like normal density, they are not interpreted as probabilities. One advantage of radial basis functions is that radial basis functions can fit a variety of curves, including polynomial and sinusoidal. RBF1

# — — — — — Construct basis functions — — — — — — — — — — — —+
phi_X <- matrix(0, nrow=N, ncol=D)
phi_X[,1] <- X
mu <- seq(min(X),max(X),length.out=D+1)
mu <- mu[c(-1,-length(mu))]
for(i in 2:D){
 phi_X[,i] <- exp(-(X-mu[i-1])^2/(2*var))
}
# — — — — — Maximum a Posteriori — — — — — — — — — — — — — — —+
# Commented out is general prior
# m0 <- matrix(0,D,1)
# S0 <- diag(x=1000,D,D) 
# SN <- inv(inv(S0)+t(phi_X)%*%phi_X/var)
# mN <- SN%*%(inv(S0)%*%m0 + t(phi_X)%*%Y/var)
# Y_hat <- t(mN) %*% t(phi_X)
# We use non-informative prior for now
m0 <- matrix(0,D,1)
SN <- solve(t(phi_X)%*%phi_X/var)
mN <- SN%*%t(phi_X)%*%Y/var
Y_hat <- t(mN) %*% t(phi_X)
var_hat <- array(0, N)
for(i in 1:N){
 var_hat[i] <- var + phi_X[i,]%*%SN%*%phi_X[i,]
}
g_bayes <- g1 + geom_line(mapping=aes(x=X,y=Y_hat[1,]),color='#0000FF') +
              geom_line(aes(x=X,y=EY),color='red')
g_bayes

g_bayes_full <- g_bayes + geom_ribbon(mapping=aes(x=X,y=Y_hat[1,],
                  ymin=Y_hat[1,]-1.96*var_hat^0.5,
                  ymax=Y_hat[1,]+1.96*var_hat^0.5, alpha=0.1),fill="#9999FF")
Ignoring unknown aesthetics: y
g_bayes_full

The blue line is the expected value of the predictive distribution at each point x, and the light blue region refers to regions within two standard deviations. Red line is the true function of y. Dots are data randomly generated from the given function with normal noise.

Remarks

Multiple linear regression result is same as the case of Bayesian regression using improper prior with an infinite covariance matrix. However, Bayesian regression’s predictive distribution usually has a tighter variance. Generally, it is good practice to obtain some domain knowledge regarding the parameters, and use an informative prior. Bayesian regression can then quickly quantify and show how different prior knowledge impact predictions.

Bayesian regression is quite flexible as it quantifies all uncertainties — predictions, and all parameters. This flexibility offers several conveniences. For example, you can marginalize out any variables from the joint distributions, and study the distribution of any combinations of variables. Also, data fitting in this perspective makes it easy for you to ‘learn as you go’. Say I first observed 10000 data points, and computed a posterior of parameter w. After that, I somehow managed to acquire 1000 more data points, and instead of running the whole regression again, I can use the previously computed posterior as my prior for these 1000 points. This sequential process yields the same result as using the whole data all over again. I like this idea in that it’s very intuitive, in the manner as a learned opinion is proportional to previously learned opinions plus new observations, and the learning goes on. A joke says that a Bayesian who dreams of a horse and observes a donkey, will call it a mule. But if he takes more observations of it, eventually he will say it is indeed a donkey.

LS0tCnRpdGxlOiAiQmF5ZXNpYW4gcmVncmVzc2lvbiB3aXRoIGltcGxlbWVudGF0aW9uIGluIFIiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KVGhpcyBpcyBhIHJlcHJvZHVjdGlvbiBmb3Igc3R1ZHkgcHVycG9zZSBmcm9tIGh0dHBzOi8vdG93YXJkc2RhdGFzY2llbmNlLmNvbS9iYXllc2lhbi1yZWdyZXNzaW9uLXdpdGgtaW1wbGVtZW50YXRpb24taW4tci1mYTcxMzk2ZGQ1OWUKCiMgU3RhcnRpbmcgZnJvbSB0aGUgYmFzaWNzClJlY2FsbCB0aGF0IGluIGxpbmVhciByZWdyZXNzaW9uLCB3ZSBhcmUgZ2l2ZW4gdGFyZ2V0IHZhbHVlcyB5LCBkYXRhIFgsIGFuZCB3ZSB1c2UgdGhlIG1vZGVsOgohW10oL1VzZXJzL21heGFuZGNoYW5nL09uZURyaXZlL01vZGVsQ29tcGFyaXNvbi9MaW5lYXJNb2RlbC5wbmcpCndoZXJlIHkgaXMgTioxIHZlY3RvciwgWCBpcyBOKkQgbWF0cml4LCB3IGlzIEQqMSB2ZWN0b3IsIGFuZCB0aGUgZXJyb3IgaXMgTioxIHZlY3Rvci4gV2UgaGF2ZSBOIGRhdGEgcG9pbnRzLiBEaW1lbnNpb24gRCBpcyB1bmRlcnN0b29kIGluIHRlcm1zIG9mIGZlYXR1cmVzLCBzbyBpZiB3ZSB1c2UgYSBsaXN0IG9mIHgsIGEgbGlzdCBvZiB4wrIgKGFuZCBhIGxpc3Qgb2YgMeKAmXMgY29ycmVzcG9uZGluZyB0byB3XzApLCB3ZSBzYXkgRD0zLgpJbiBjbGFzc2ljIGxpbmVhciByZWdyZXNzaW9uLCB0aGUgZXJyb3IgdGVybSBpcyBhc3N1bWVkIHRvIGhhdmUgTm9ybWFsIGRpc3RyaWJ1dGlvbiwgYW5kIHNvIGl0IGltbWVkaWF0ZWx5IGZvbGxvd3MgdGhhdCB5IGlzIG5vcm1hbGx5IGRpc3RyaWJ1dGVkIHdpdGggbWVhbiBYdywgYW5kIHZhcmlhbmNlIG9mIHdoYXRldmVyIHZhcmlhbmNlIHRoZSBlcnJvciB0ZXJtIGhhcyAoZGVub3RlIGJ5IM+DwrIsIG9yIGRpYWdvbmFsIG1hdHJpeCB3aXRoIGVudHJpZXMgz4PCsikuIFRoZSBub3JtYWwgYXNzdW1wdGlvbiB0dXJucyBvdXQgd2VsbCBpbiBtb3N0IGNhc2VzLCBhbmQgdGhpcyBub3JtYWwgbW9kZWwgaXMgYWxzbyB3aGF0IHdlIHVzZSBpbiBCYXllc2lhbiByZWdyZXNzaW9uLgoKIyBQYXJhbWV0ZXIgSW5mZXJlbmNlCldlIGFyZSBub3cgZmFjZWQgd2l0aCB0d28gcHJvYmxlbXM6IGluZmVyZW5jZSBvZiB3LCBhbmQgcHJlZGljdGlvbiBvZiB5IGZvciBhbnkgbmV3IFguIFVzaW5nIHRoZSB3ZWxsLWtub3duIEJheWVzIHJ1bGUgYW5kIHRoZSBhYm92ZSBhc3N1bXB0aW9ucywgd2UgYXJlIG9ubHkgc3RlcHMgYXdheSB0b3dhcmRzIG5vdCBvbmx5IHNvbHZpbmcgdGhlc2UgdHdvIHByb2JsZW1zLCBidXQgYWxzbyBnaXZpbmcgYSBmdWxsIHByb2JhYmlsaXR5IGRpc3RyaWJ1dGlvbiBvZiB5IGZvciBhbnkgbmV3IFguIEhlcmUgaXMgdGhlIEJheWVzIHJ1bGUgdXNpbmcgb3VyIG5vdGF0aW9ucywgd2hpY2ggZXhwcmVzc2VzIHRoZSBwb3N0ZXJpb3IgZGlzdHJpYnV0aW9uIG9mIHBhcmFtZXRlciB3IGdpdmVuIGRhdGE6CiFbQmF5ZXNdKC9Vc2Vycy9tYXhhbmRjaGFuZy9PbmVEcml2ZS9Nb2RlbENvbXBhcmlzb24vQmF5ZXMucG5nKQrPgCBhbmQgZiBhcmUgcHJvYmFiaWxpdHkgZGVuc2l0eSBmdW5jdGlvbnMuIFNpbmNlIHRoZSByZXN1bHQgaXMgYSBmdW5jdGlvbiBvZiB3LCB3ZSBjYW4gaWdub3JlIHRoZSBkZW5vbWluYXRvciwga25vd2luZyB0aGF0IHRoZSBudW1lcmF0b3IgaXMgcHJvcG9ydGlvbmFsIHRvIGxlZnRoYW5kIHNpZGUgYnkgYSBjb25zdGFudC4gV2Uga25vdyBmcm9tIGFzc3VtcHRpb25zIHRoYXQgdGhlIGxpa2VsaWhvb2QgZnVuY3Rpb24gZih5fHcseCkgZm9sbG93cyB0aGUgbm9ybWFsIGRpc3RyaWJ1dGlvbi4gVGhlIG90aGVyIHRlcm0gaXMgcHJpb3IgZGlzdHJpYnV0aW9uIG9mIHcsIGFuZCB0aGlzIHJlZmxlY3RzLCBhcyB0aGUgbmFtZSBzdWdnZXN0cywgcHJpb3Iga25vd2xlZGdlIG9mIHRoZSBwYXJhbWV0ZXJzLgotIFByaW9yIERpc3RyaWJ1dGlvbiAKRGVmaW5pbmcgdGhlIHByaW9yIGlzIGFuIGludGVyZXN0aW5nIHBhcnQgb2YgdGhlIEJheWVzaWFuIHdvcmtmbG93LiBGb3IgY29udmVuaWVuY2Ugd2UgbGV0ICR3IFxzaW0gTihtXzAsIFNfMCkkLCBhbmQgdGhlIGh5cGVycGFyYW1ldGVycyAkbV8wJCBhbmQgJFNfMCQgbm93IHJlZmxlY3QgcHJpb3Iga25vd2xlZGdlIG9mIHcuIElmIHlvdSBoYXZlIGxpdHRsZSBrbm93bGVkZ2Ugb2YgJHckLCBvciBmaW5kIGFueSBhc3NpZ25tZW50IG9mICRtXzAkIGFuZCAkU18wJCB0b28gc3ViamVjdGl2ZSwg4oCYbm9uLWluZm9ybWF0aXZl4oCZIHByaW9ycyBhcmUgYW4gYW1lbmRtZW50LiBJbiB0aGlzIGNhc2UsIHdlIHNldCAkbV8wJCB0byAwIGFuZCBtb3JlIGltcG9ydGFudGx5IHNldCAkU18wJCBhcyBhIGRpYWdvbmFsIG1hdHJpeCB3aXRoIHZlcnkgbGFyZ2UgdmFsdWVzLiBXZSBhcmUgc2F5aW5nIHRoYXQgJHckIGhhcyBhIHZlcnkgaGlnaCB2YXJpYW5jZSwgYW5kIHNvIHdlIGhhdmUgbGl0dGxlIGtub3dsZWRnZSBvZiB3aGF0ICR3JCB3aWxsIGJlLgoKV2l0aCBhbGwgdGhlc2UgcHJvYmFiaWxpdHkgZnVuY3Rpb25zIGRlZmluZWQsIGEgZmV3IGxpbmVzIG9mIHNpbXBseSBhbGdlYnJhaWMgbWFuaXB1bGF0aW9ucyAocXVpdGUgYSBmZXcgbGluZXMgaW4gZmFjdCkgd2lsbCBnaXZlIHRoZSBwb3N0ZXJpb3IgYWZ0ZXIgb2JzZXJ2YXRpb24gb2YgTiBkYXRhIHBvaW50czoKIVtwb3N0ZXJpb3JdKC9Vc2Vycy9tYXhhbmRjaGFuZy9PbmVEcml2ZS9Nb2RlbENvbXBhcmlzb24vcG9zdGVyaW9yLnBuZykKCiMgUHJlZGljdGl2ZSBEaXN0cmlidXRpb24KQSBmdWxsIEJheWVzaWFuIGFwcHJvYWNoIG1lYW5zIG5vdCBvbmx5IGdldHRpbmcgYSBzaW5nbGUgcHJlZGljdGlvbiAoZGVub3RlIG5ldyBwYWlyIG9mIGRhdGEgYnkgJHlfMCwgeF8wJCksIGJ1dCBhbHNvIGFjcXVpcmluZyB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoaXMgbmV3IHBvaW50LgohW10oL1VzZXJzL21heGFuZGNoYW5nL09uZURyaXZlL01vZGVsQ29tcGFyaXNvbi9OZXdEaXN0cmlidXRpb24ucG5nKQpXaGF0IHdlIGhhdmUgZG9uZSBpcyB0aGUgcmV2ZXJzZSBvZiBtYXJnaW5hbGl6aW5nIGZyb20gam9pbnQgdG8gZ2V0IG1hcmdpbmFsIGRpc3RyaWJ1dGlvbiBvbiB0aGUgZmlyc3QgbGluZSwgYW5kIHVzaW5nIEJheWVzIHJ1bGUgaW5zaWRlIHRoZSBpbnRlZ3JhbCBvbiB0aGUgc2Vjb25kIGxpbmUsIHdoZXJlIHdlIGhhdmUgYWxzbyByZW1vdmVkIHVubmVjZXNzYXJ5IGRlcGVuZGVuY2VzLiBOb3RpY2UgdGhhdCB3ZSBrbm93IHdoYXQgdGhlIGxhc3QgdHdvIHByb2JhYmlsaXR5IGZ1bmN0aW9ucyBhcmUuIFRoZSByZXN1bHQgb2YgZnVsbCBwcmVkaWN0aXZlIGRpc3RyaWJ1dGlvbiBpczoKIVtdKC9Vc2Vycy9tYXhhbmRjaGFuZy9PbmVEcml2ZS9Nb2RlbENvbXBhcmlzb24vUHJlZGljdGl2ZURpc3RyaWJ1dGlvbi5wbmcpCgojIEltcGxlbWVudGF0aW9uIGluIFIKCkltcGxlbWVudGF0aW9uIGluIFIgaXMgcXVpdGUgY29udmVuaWVudC4gQmFja2VkIHVwIHdpdGggdGhlIGFib3ZlIHRoZW9yZXRpY2FsIHJlc3VsdHMsIHdlIGp1c3QgaW5wdXQgbWF0cml4IG11bHRpcGxpY2F0aW9ucyBpbnRvIG91ciBjb2RlIGFuZCBnZXQgcmVzdWx0cyBvZiBib3RoIHByZWRpY3Rpb25zIGFuZCBwcmVkaWN0aXZlIGRpc3RyaWJ1dGlvbnMuIFRvIGlsbHVzdHJhdGUgd2l0aCBhbiBleGFtcGxlLCB3ZSB1c2UgYSB0b3kgcHJvYmxlbTogWCBpcyBmcm9tIC0xIHRvIDEsIGV2ZW5seSBzcGFjZWQsIGFuZCB5IGlzIGNvbnN0cnVjdGVkIGFzIHRoZSBmb2xsb3dpbmcgYWRkaXRpb25zIG9mIHNpbnVzb2lkYWwgY3VydmVzIHdpdGggbm9ybWFsIG5vaXNlIChzZWUgZ3JhcGggYmVsb3cgZm9yIGlsbHVzdHJhdGlvbiBvZiB5KS4KIVtCYXllc2lhblRveVByb2JsZW1dKC9Vc2Vycy9tYXhhbmRjaGFuZy9PbmVEcml2ZS9Nb2RlbENvbXBhcmlzb24vQmF5ZXNpYW5Ub3lQcm9ibGVtLnBuZykKVGhlIGZvbGxvd2luZyBjb2RlIGdldHMgdGhpcyBkYXRhLgpgYGB7cn0KbGlicmFyeShnZ3Bsb3QyKQojIOKAlCDigJQg4oCUIOKAlCDigJQgR2V0IGRhdGEg4oCUIOKAlCDigJQg4oCUIOKAlCDigJQg4oCUIOKAlCDigJQg4oCUIOKAlCDigJQg4oCUIOKAlCDigJQg4oCUIOKAlCDigJQg4oCUIOKAlCDigJQrClggPC0gKC0zMDozMCkvMzAgCk4gPC0gbGVuZ3RoKFgpIApEIDwtIDEwIAp2YXIgPC0gMC4xNSowLjE1IAplIDwtIHJub3JtKE4sMCx2YXJeMC41KSAKRVkgPC0gc2luKDIqcGkqWCkqKFg8PTApICsgMC41KnNpbig0KnBpKlgpKihYPjApIApZIDwtIHNpbigyKnBpKlgpKihYPD0wKSArIDAuNSpzaW4oNCpwaSpYKSooWD4wKSArIGUgCmRhdGEgPC0gZGF0YS5mcmFtZShYLFkpIApnMSA8LSBnZ3Bsb3QoZGF0YT1kYXRhKSArIGdlb21fcG9pbnQobWFwcGluZz1hZXMoeD1YLHk9WSkpCmcxCmBgYApUaGUgZm9sbG93aW5nIGNvZGUgKHVuZGVyIHNlY3Rpb24gTWF4aW11bSBhIFBvc3RlcmlvcmkpIGltcGxlbWVudHMgYWxsIHRoZSBhYm92ZSB0aGVvcmV0aWNhbCByZXN1bHRzIHRocm91Z2ggbWF0cml4IG11bHRpcGxpY2F0aW9ucy4gV2UgYWxzbyBleHBhbmQgZmVhdHVyZXMgb2YgeCAoZGVub3RlZCBpbiBjb2RlIGFzIHBoaV9YLCB1bmRlciBzZWN0aW9uIENvbnN0cnVjdCBiYXNpcyBmdW5jdGlvbnMpLiBKdXN0IGFzIHdlIHdvdWxkIGV4cGFuZCB4IGludG8geMKyLCBldGMuLCB3ZSBub3cgZXhwYW5kIGl0IGludG8gOSByYWRpYWwgYmFzaXMgZnVuY3Rpb25zLCBlYWNoIG9uZSBsb29raW5nIGxpa2UgdGhlIGZvbGxvd3MuIE5vdGUgdGhhdCBhbHRob3VnaCB0aGVzZSBsb29rIGxpa2Ugbm9ybWFsIGRlbnNpdHksIHRoZXkgYXJlIG5vdCBpbnRlcnByZXRlZCBhcyBwcm9iYWJpbGl0aWVzLgpPbmUgYWR2YW50YWdlIG9mIHJhZGlhbCBiYXNpcyBmdW5jdGlvbnMgaXMgdGhhdCByYWRpYWwgYmFzaXMgZnVuY3Rpb25zIGNhbiBmaXQgYSB2YXJpZXR5IG9mIGN1cnZlcywgaW5jbHVkaW5nIHBvbHlub21pYWwgYW5kIHNpbnVzb2lkYWwuCiFbUkJGMV0oL1VzZXJzL21heGFuZGNoYW5nL09uZURyaXZlL01vZGVsQ29tcGFyaXNvbi9SQkYxLnBuZykKYGBge3J9CiMg4oCUIOKAlCDigJQg4oCUIOKAlCBDb25zdHJ1Y3QgYmFzaXMgZnVuY3Rpb25zIOKAlCDigJQg4oCUIOKAlCDigJQg4oCUIOKAlCDigJQg4oCUIOKAlCDigJQg4oCUKwpwaGlfWCA8LSBtYXRyaXgoMCwgbnJvdz1OLCBuY29sPUQpCnBoaV9YWywxXSA8LSBYCm11IDwtIHNlcShtaW4oWCksbWF4KFgpLGxlbmd0aC5vdXQ9RCsxKQptdSA8LSBtdVtjKC0xLC1sZW5ndGgobXUpKV0KZm9yKGkgaW4gMjpEKXsKIHBoaV9YWyxpXSA8LSBleHAoLShYLW11W2ktMV0pXjIvKDIqdmFyKSkKfQoKIyDigJQg4oCUIOKAlCDigJQg4oCUIE1heGltdW0gYSBQb3N0ZXJpb3JpIOKAlCDigJQg4oCUIOKAlCDigJQg4oCUIOKAlCDigJQg4oCUIOKAlCDigJQg4oCUIOKAlCDigJQg4oCUKwojIENvbW1lbnRlZCBvdXQgaXMgZ2VuZXJhbCBwcmlvcgojIG0wIDwtIG1hdHJpeCgwLEQsMSkKIyBTMCA8LSBkaWFnKHg9MTAwMCxELEQpIAojIFNOIDwtIGludihpbnYoUzApK3QocGhpX1gpJSolcGhpX1gvdmFyKQojIG1OIDwtIFNOJSolKGludihTMCklKiVtMCArIHQocGhpX1gpJSolWS92YXIpCiMgWV9oYXQgPC0gdChtTikgJSolIHQocGhpX1gpCgojIFdlIHVzZSBub24taW5mb3JtYXRpdmUgcHJpb3IgZm9yIG5vdwptMCA8LSBtYXRyaXgoMCxELDEpClNOIDwtIHNvbHZlKHQocGhpX1gpJSolcGhpX1gvdmFyKQptTiA8LSBTTiUqJXQocGhpX1gpJSolWS92YXIKWV9oYXQgPC0gdChtTikgJSolIHQocGhpX1gpCnZhcl9oYXQgPC0gYXJyYXkoMCwgTikKZm9yKGkgaW4gMTpOKXsKIHZhcl9oYXRbaV0gPC0gdmFyICsgcGhpX1hbaSxdJSolU04lKiVwaGlfWFtpLF0KfQpnX2JheWVzIDwtIGcxICsgZ2VvbV9saW5lKG1hcHBpbmc9YWVzKHg9WCx5PVlfaGF0WzEsXSksY29sb3I9JyMwMDAwRkYnKSArCiAgICAgICAgICAgICAgZ2VvbV9saW5lKGFlcyh4PVgseT1FWSksY29sb3I9J3JlZCcpCmdfYmF5ZXMKZ19iYXllc19mdWxsIDwtIGdfYmF5ZXMgKyBnZW9tX3JpYmJvbihtYXBwaW5nPWFlcyh4PVgseT1ZX2hhdFsxLF0sCiAgICAgICAgICAgICAgICAgIHltaW49WV9oYXRbMSxdLTEuOTYqdmFyX2hhdF4wLjUsCiAgICAgICAgICAgICAgICAgIHltYXg9WV9oYXRbMSxdKzEuOTYqdmFyX2hhdF4wLjUsIGFscGhhPTAuMSksZmlsbD0iIzk5OTlGRiIpCmdfYmF5ZXNfZnVsbApgYGAKVGhlIGJsdWUgbGluZSBpcyB0aGUgZXhwZWN0ZWQgdmFsdWUgb2YgdGhlIHByZWRpY3RpdmUgZGlzdHJpYnV0aW9uIGF0IGVhY2ggcG9pbnQgeCwgYW5kIHRoZSBsaWdodCBibHVlIHJlZ2lvbiByZWZlcnMgdG8gcmVnaW9ucyB3aXRoaW4gdHdvIHN0YW5kYXJkIGRldmlhdGlvbnMuIFJlZCBsaW5lIGlzIHRoZSB0cnVlIGZ1bmN0aW9uIG9mIHkuIERvdHMgYXJlIGRhdGEgcmFuZG9tbHkgZ2VuZXJhdGVkIGZyb20gdGhlIGdpdmVuIGZ1bmN0aW9uIHdpdGggbm9ybWFsIG5vaXNlLgoKIyBSZW1hcmtzCk11bHRpcGxlIGxpbmVhciByZWdyZXNzaW9uIHJlc3VsdCBpcyBzYW1lIGFzIHRoZSBjYXNlIG9mIEJheWVzaWFuIHJlZ3Jlc3Npb24gdXNpbmcgaW1wcm9wZXIgcHJpb3Igd2l0aCBhbiBpbmZpbml0ZSBjb3ZhcmlhbmNlIG1hdHJpeC4gSG93ZXZlciwgQmF5ZXNpYW4gcmVncmVzc2lvbuKAmXMgcHJlZGljdGl2ZSBkaXN0cmlidXRpb24gdXN1YWxseSBoYXMgYSB0aWdodGVyIHZhcmlhbmNlLiBHZW5lcmFsbHksIGl0IGlzIGdvb2QgcHJhY3RpY2UgdG8gb2J0YWluIHNvbWUgZG9tYWluIGtub3dsZWRnZSByZWdhcmRpbmcgdGhlIHBhcmFtZXRlcnMsIGFuZCB1c2UgYW4gaW5mb3JtYXRpdmUgcHJpb3IuIEJheWVzaWFuIHJlZ3Jlc3Npb24gY2FuIHRoZW4gcXVpY2tseSBxdWFudGlmeSBhbmQgc2hvdyBob3cgZGlmZmVyZW50IHByaW9yIGtub3dsZWRnZSBpbXBhY3QgcHJlZGljdGlvbnMuCgpCYXllc2lhbiByZWdyZXNzaW9uIGlzIHF1aXRlIGZsZXhpYmxlIGFzIGl0IHF1YW50aWZpZXMgYWxsIHVuY2VydGFpbnRpZXMg4oCUIHByZWRpY3Rpb25zLCBhbmQgYWxsIHBhcmFtZXRlcnMuIFRoaXMgZmxleGliaWxpdHkgb2ZmZXJzIHNldmVyYWwgY29udmVuaWVuY2VzLiBGb3IgZXhhbXBsZSwgeW91IGNhbiBtYXJnaW5hbGl6ZSBvdXQgYW55IHZhcmlhYmxlcyBmcm9tIHRoZSBqb2ludCBkaXN0cmlidXRpb25zLCBhbmQgc3R1ZHkgdGhlIGRpc3RyaWJ1dGlvbiBvZiBhbnkgY29tYmluYXRpb25zIG9mIHZhcmlhYmxlcy4gQWxzbywgZGF0YSBmaXR0aW5nIGluIHRoaXMgcGVyc3BlY3RpdmUgbWFrZXMgaXQgZWFzeSBmb3IgeW91IHRvIOKAmGxlYXJuIGFzIHlvdSBnb+KAmS4gU2F5IEkgZmlyc3Qgb2JzZXJ2ZWQgMTAwMDAgZGF0YSBwb2ludHMsIGFuZCBjb21wdXRlZCBhIHBvc3RlcmlvciBvZiBwYXJhbWV0ZXIgdy4gQWZ0ZXIgdGhhdCwgSSBzb21laG93IG1hbmFnZWQgdG8gYWNxdWlyZSAxMDAwIG1vcmUgZGF0YSBwb2ludHMsIGFuZCBpbnN0ZWFkIG9mIHJ1bm5pbmcgdGhlIHdob2xlIHJlZ3Jlc3Npb24gYWdhaW4sIEkgY2FuIHVzZSB0aGUgcHJldmlvdXNseSBjb21wdXRlZCBwb3N0ZXJpb3IgYXMgbXkgcHJpb3IgZm9yIHRoZXNlIDEwMDAgcG9pbnRzLiBUaGlzIHNlcXVlbnRpYWwgcHJvY2VzcyB5aWVsZHMgdGhlIHNhbWUgcmVzdWx0IGFzIHVzaW5nIHRoZSB3aG9sZSBkYXRhIGFsbCBvdmVyIGFnYWluLiBJIGxpa2UgdGhpcyBpZGVhIGluIHRoYXQgaXTigJlzIHZlcnkgaW50dWl0aXZlLCBpbiB0aGUgbWFubmVyIGFzIGEgbGVhcm5lZCBvcGluaW9uIGlzIHByb3BvcnRpb25hbCB0byBwcmV2aW91c2x5IGxlYXJuZWQgb3BpbmlvbnMgcGx1cyBuZXcgb2JzZXJ2YXRpb25zLCBhbmQgdGhlIGxlYXJuaW5nIGdvZXMgb24uIEEgam9rZSBzYXlzIHRoYXQgYSBCYXllc2lhbiB3aG8gZHJlYW1zIG9mIGEgaG9yc2UgYW5kIG9ic2VydmVzIGEgZG9ua2V5LCB3aWxsIGNhbGwgaXQgYSBtdWxlLiBCdXQgaWYgaGUgdGFrZXMgbW9yZSBvYnNlcnZhdGlvbnMgb2YgaXQsIGV2ZW50dWFsbHkgaGUgd2lsbCBzYXkgaXQgaXMgaW5kZWVkIGEgZG9ua2V5Lgo=