1 Introduction

The Capital Asset Pricing Model (CAPM) is one of the cornerstones of modern financial theory, establishing a linear relationship between an asset’s systematic risk and its expected return. Developed in the 1960s, the model postulates that an investment’s return should be proportional to its exposure to market risk, measured by the Beta (\(\beta\)) coefficient, in addition to a risk-free rate.

The central premise is that investors should be compensated only for risk that cannot be diversified (systematic risk), while company-specific risk can be eliminated through a well-structured portfolio. Despite criticisms regarding its simplifications—such as market efficiency and the focus on a single risk factor—CAPM remains widely used to estimate the cost of equity and evaluate the performance of portfolio managers.

1.1 Behavior of \(\beta\)

In the context of the Capital Asset Pricing Model (CAPM), the Beta (\(\beta\)) coefficient is a measure of an asset’s systematic risk—the risk that cannot be diversified away. It quantifies how sensitive a specific stock’s returns are to the movements of the broader market.+1Mathematically, it is defined as: \[ \beta = \frac{Cov(R, R_m)}{Var(R_m)} \] Where \(R\) and \(R_m\) are the asset and market returns, respectively.

  • \(\beta > 1\) (High Sensitivity) - The asset is more volatile than the market. If the market rises by 10%, a stock with a \(\beta\) of 1.5 is expected to rise by 15%. Conversely, it will likely fall further than the market during a downturn. Stocks in sectors like technology or biotechnology often have high betas.

  • \(\beta = 1\) (Market Neutrality) - The asset moves in lockstep with the market. Its systematic risk is identical to that of the market proxy (like the S&P 500).

  • \(0<\beta<1\) (Low Sensitivity) - The asset is less volatile than the market. It is considered a “defensive” stock. For example, a utility company might have a \(\beta\) of 0.5, meaning it only captures about half of the market’s swings.

  • \(\beta=0\) (No Correlation) - The asset’s returns have no linear relationship with the market’s returns. A risk-free asset, like a Treasury bond (in theory), has a \(\beta\) of 0. Gold is also sometimes cited as having a beta near zero, as its price is often driven by factors unrelated to equity markets.

  • \(\beta<0\) (Inverse Correlation) - The asset moves in the opposite direction of the market. While rare for individual stocks, some “inverse ETFs” or “put options” are designed to have negative betas. Historically, during extreme market crashes, very few traditional assets maintain a negative beta consistently, though some “safe havens” may exhibit this behavior temporarily.

1.2 Petrobras vs S&P500

In this document, we estimate the CAPM parameters for Petrobras (PBR), traded on the NYSE, using the S&P 500 (SPY) as the market proxy. We adopt a Bayesian framework, which allows us to incorporate prior beliefs and obtain a full posterior distribution for the risk parameters.

The CAPM equation is defined as:

\[ R_t = \alpha + \beta R_{mt}+ \epsilon_t \]

Where:

  • \(t\) is the time frequency, usually daily.

  • \(R_t\): Return of the risky asset (PBR).

  • \(R_{mt}\): Return of the market index (S&P 500).

  • \(\alpha\): The “Alpha”, representing abnormal returns.

  • \(\beta\): The “Beta”, measuring the asset’s sensitivity to market movements.

  • \(\epsilon_t \sim N(0, \sigma^2)\): The idiosyncratic error term with variance \(\sigma^2\).

2 Uploading and processing the data

We uploaded data from February 10th 2016 to February 9th 2026, ie about 10 years of daily data or \(n=2514\) observations.

if (!require("pacman")) install.packages("pacman")
## Loading required package: pacman
pacman::p_load(quantmod, brms, tidyverse, PerformanceAnalytics)

symbols <- c("PBR", "SPY")
getSymbols(symbols, src = "yahoo", from = "2016-02-09", to = Sys.Date())
## [1] "PBR" "SPY"
# Computing returns
returns_pbr <- Return.calculate(Cl(PBR), method = "log")
returns_spy <- Return.calculate(Cl(SPY), method = "log")

# Combining the time series and removing missing values
data_capm <- merge(returns_pbr, returns_spy) %>% 
  as.data.frame() %>% 
  drop_na()
colnames(data_capm) <- c("PBR", "Market")

y = data_capm[,1]

x = data_capm[,2]

par(mfrow=c(1,1))
ts.plot(y,ylab="Returns")
lines(x,col=2)
legend("topright",legend=c("PBR","SPY"),col=1:2,lty=1,bty="n",lwd=2)

3 Ordinary least squares

summary(lm(y~x))
## 
## Call:
## lm(formula = y ~ x)
## 
## Residuals:
##       Min        1Q    Median        3Q       Max 
## -0.272099 -0.013966  0.000262  0.014354  0.157838 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept) 0.0000107  0.0005673   0.019    0.985    
## x           1.2151846  0.0499735  24.317   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.02841 on 2512 degrees of freedom
## Multiple R-squared:  0.1905, Adjusted R-squared:  0.1902 
## F-statistic: 591.3 on 1 and 2512 DF,  p-value: < 2.2e-16
par(mfrow=c(1,1))
plot(x,y,xlab="SPY",ylab="PBR")
title("Jan 3rd 2020 - February 6th 2026")
abline(lm(y~x),col=2,lwd=2)

4 Maximum likelihood estimation

When \(x=(x_1,\ldots,x_n)'\) and \(X\) is an \((n \times 2)\) matrix where the first column contains only ones (for the intercept) and the second column is \(x\), the Gaussian linear model can be represented as \[ y = X \theta + \epsilon \qquad \qquad \epsilon \sim N(0,\sigma^2 I_n) \] with parameters \(\theta=(\alpha,\beta)\) and \(\sigma^2\). The ML estimator of \(\theta\) and \(\sigma^2\) are \[ {\widehat \theta} = (X'X)^{-1}X'y \qquad \mbox{and} \qquad {\widehat \sigma}^2 = \frac{(y-X{\widehat \theta})'(y-X{\widehat \theta})}{n}, \] respectively.

X         = cbind(1,x)
n         = nrow(X)
p         = ncol(X)
theta.mle = solve(t(X)%*%X)%*%t(X)%*%y
y.hat     = X%*%theta.mle
e.hat     = y-y.hat
sig.mle   = sqrt(mean(e.hat^2))

table = round(rbind(cbind(theta.mle,lm(y~X-1)$coef),
              c(sig.mle,(n-p)/n*summary(lm(y~X-1))$sigma)),4)
colnames(table)      = c("Our function","lm function")
rownames(table)[1]   = "constant"
rownames(table)[p+1] = "sigma"
table
##          Our function lm function
## constant       0.0000      0.0000
## x              1.2152      1.2152
## sigma          0.0284      0.0284

5 Closed-form Bayesian inference (conjugacy)

Let us combine the above Gaussian linear model with a conjugate prior for \(\theta,\sigma^2\): \[\begin{eqnarray*} \theta|\sigma^2 &\sim& N(b_0,\sigma^2 B_0)\\ \sigma^2 &\sim& IG(\nu_0/2,\nu_0\sigma_0^2/2), \end{eqnarray*}\] for hyperparameters \(b_0,B_0,\nu_0\) and \(\sigma_0^2\). This prior is conjugate since the posterior follows the same family of distributions as the prior with hyperparameters adjusted by the observed data. More precisely, \[\begin{eqnarray*} \theta|\sigma^2,\mbox{data} &\sim& N(b_1,\sigma^2 B_1)\\ \sigma^2|\mbox{data} &\sim& IG(\nu_1/2,\nu_1\sigma_1^2/2)\\ \theta|\mbox{data} &\sim& t_{\nu_1}(b_1,\sigma_1^2 B_1), \end{eqnarray*}\] where \[\begin{eqnarray*} B_1 &=& (B_0^{-1}+X'X)^{-1}\\ B_1^{-1} b_1 &=& B_0^{-1} b_0 + X'y\\ \nu_1 &=& \nu_0 + n\\ \nu_1\sigma_1^2 &=& \nu_0\sigma_0^2 + (y-X b_1)'y + (b_0-b_1)'B_0^{-1}b_0. \end{eqnarray*}\]

Notice that the above derivations, both MLE and Bayesian with conjugate prior, for the Gaussian linear regression is still valid for \(p>2\) and is the base of the standard Gaussian linear regression framework taught in virtually all introductory econometrics classes.

# Prior hyperparameters
b0       = c(0,1)
B0       = diag(c(1000,250),2)
nu0      = 0.002
sig20    = 1.0

# Posterior hyperparameters
nu0sig20 = nu0*sig20
iB0      = solve(B0)
iB0b0    = iB0%*%b0
B1       = solve(iB0+t(X)%*%X)
tcB1     = t(chol(B1))
b1       = B1%*%(iB0b0+t(X)%*%y)
nu1      = nu0 + n
sig21    = ((nu0sig20+sum((y-X%*%b1)*y)+t(b0-b1)%*%iB0b0)/nu1)[1]
se       = sqrt(nu1/(nu1-2)*sig21*diag(B1))

tab = round(cbind(b1,se,b1/se,2*(1-pt(abs(b1/se),df=nu1))),5)
colnames(tab)=c("Mean","StDev","t","tail")
rownames(tab)=c("Intercept","Market")
tab
##              Mean   StDev        t    tail
## Intercept 0.00001 0.00057  0.02129 0.98302
## Market    1.21255 0.04969 24.40050 0.00000

6 MCMC-based Bayesian inference (conditionally conjugacy)

When the conjugate prior, presented above, is replaced by the following conditionally conjugate one, we loose closed form derivation for posterior inference: \[\begin{eqnarray*} \theta|\sigma^2 &\sim& N(b_0,V_0)\\ \sigma^2 &\sim& IG(c_0,d_0). \end{eqnarray*}\] In this case, a standard solution since the early 1990s is to implement an Markov chain Monte Carlo (MCMC) algorithm. For the Gaussian linear model with conditionally conjugate prior, it is well established that the Gibbs sampler is the simplest and cleanest MCMC scheme.

The Gibbs sampler, in our particular set up, cycles through the two full conditionals \[ p(\theta|\sigma^2,\mbox{data}) \ \ \ \mbox{and} \ \ \ p(\sigma^2|\theta,\mbox{data}), \] both of which are easily derived: \[ N(b_1,V_1) \ \ \ \mbox{and} \ \ \ IG(c_1,d_1) \] where \[\begin{eqnarray*} V_1^{-1} &=& X'X/\sigma^2 + V_0^{-1}\\ V_1^{-1}b_1 &=& X'y/\sigma^2 + V_0^{-1} b_0\\ c_1 &=& c_0 + n/2\\ d_1 &=& d_0 + (y-X'\theta)(y-X'\theta)/2 \end{eqnarray*}\]

# Prior knowledge 
b0 = rep(0,p)
V0 = diag(c(1,0.25))
c0 = 0.001
d0 = 0.001
iV0 = solve(V0)
iV0b0 = iV0%*%b0

# Gibbs sampler
sigma2  = 1 
M0      = 1000
M       = 10000
thin    = 1
niter   = M0+M*thin
thetas  = matrix(0,niter,p)
sigs    = rep(0,niter)
for (iter in 1:niter){
  V1 = solve(t(X)%*%X/sigma2+iV0)
  b1 = V1%*%(t(X)%*%y/sigma2+iV0b0)
  theta = b1 + t(chol(V1))%*%rnorm(p)
  c1 = c0 + n/2
  d1 = d0 + sum((y-X%*%theta)^2)/2
  sigma2 = 1/rgamma(1,c1,d1)
  thetas[iter,] = theta
  sigs[iter] = sqrt(sigma2)
}
ind    = seq(M0+1,niter,by=thin)
thetas = thetas[ind,]
sigs   = sigs[ind]

mean.theta = apply(thetas,2,mean)
table = round(cbind(theta.mle,mean.theta),5)
colnames(table) = c("ML","Bayes")
rownames(table) = c("Intercept","Market")
table
##                ML   Bayes
## Intercept 0.00001 0.00002
## Market    1.21518 1.20305
par(mfrow=c(3,3))
ts.plot(thetas[,1],xlab="Iterations",ylab="",main=expression(alpha))
ts.plot(thetas[,2],xlab="Iterations",ylab="",main=expression(beta))
ts.plot(sigs,xlab="Iterations",ylab="",main=expression(sigma))
acf(thetas[,1],main="")
acf(thetas[,2],main="")
acf(sigs,main="")
hist(thetas[,1],prob=TRUE,xlab="",main="")
hist(thetas[,2],prob=TRUE,xlab="",main="")
hist(sigs,prob=TRUE,xlab="",main="")

7 Comparison

We compare the ML estimate with the posterior densities, based on both conjugate and conditionally conjugate priors, for the parameters \(\alpha\), \(\beta\) and \(\sigma^2\).

par(mfrow=c(1,3))
plot(density(thetas[,1]),xlab="Intercept",main="")
bb = seq(min(thetas[,1]),max(thetas[,1]),length=1000)
den = dt((bb-b1[1,1])/sqrt(sig21*B1[1,1]),df=nu1)/sqrt(sig21*B1[1,1])
lines(bb,den,col=2,lwd=2)
abline(v=theta.mle[1,1],col=3,lwd=2)
legend("topleft",legend=c("MLE","C Prior","CC prior"),col=c(3,2,1),bty="n",lwd=2)

plot(density(thetas[,2]),xlab="Slope",main="")
bb = seq(min(thetas[,2]),max(thetas[,2]),length=1000)
den = dt((bb-b1[2,1])/sqrt(sig21*B1[2,2]),df=nu1)/sqrt(sig21*B1[2,2])
lines(bb,den,col=2,lwd=2)
abline(v=theta.mle[2,1],col=3,lwd=2)
legend("topleft",legend=c("MLE","C Prior","CC prior"),col=c(3,2,1),bty="n",lwd=2)


sigs2 = sigs^2
s2    = seq(min(sigs2),max(sigs2),length=1000)
den   = dgamma(1/s2,nu1/2,nu1*sig21/2)/(s2^2)
den.d = density(sigs2)
plot(den.d$x,den.d$y,xlab="Error variance",main="",ylim=range(den.d$y,den),type="l",ylab="Density")
lines(s2,den,col=2,lwd=2)
abline(v=sig.mle^2,col=3,lwd=2)
legend("topleft",legend=c("MLE","C Prior","CC prior"),col=c(3,2,1),bty="n",lwd=2)

8 Things you had to know to understand this class

  1. Covariance

  2. Variance

  3. Fitting a line via ordinary least squares

  4. Gaussian linear model

  5. Basic matrix algebra

  6. Likelihood function

  7. maximum likelihood estimator

  8. Prior and posterior distributions

  9. Inverse-gamma distribution

  10. Conjugacy

  11. Conditional conjugacy

  12. Monte Carlo posterior simulation

LS0tCnRpdGxlOiAiQ0FQTTogQmF5ZXNpYW4gbGluZWFyIG1vZGVsaW5nIgpzdWJ0aXRsZTogIlBldHJvYnJhcyB2cyBTJlAgNTAwIgphdXRob3I6ICJIZWRpYmVydCBGcmVpdGFzIExvcGVzIgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdGhlbWU6IGZsYXRseQogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgdG9jOiB0cnVlCiAgICB0b2NfZGVwdGg6IDMKICAgIHRvY19jb2xsYXBzZWQ6IHRydWUKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQotLS0KCiMgSW50cm9kdWN0aW9uCgpUaGUgKipDYXBpdGFsIEFzc2V0IFByaWNpbmcgTW9kZWwgKENBUE0pKiogaXMgb25lIG9mIHRoZSBjb3JuZXJzdG9uZXMgb2YgbW9kZXJuIGZpbmFuY2lhbCB0aGVvcnksIGVzdGFibGlzaGluZyBhIGxpbmVhciByZWxhdGlvbnNoaXAgYmV0d2VlbiBhbiBhc3NldCdzIHN5c3RlbWF0aWMgcmlzayBhbmQgaXRzIGV4cGVjdGVkIHJldHVybi4gRGV2ZWxvcGVkIGluIHRoZSAxOTYwcywgdGhlIG1vZGVsIHBvc3R1bGF0ZXMgdGhhdCBhbiBpbnZlc3RtZW50J3MgcmV0dXJuIHNob3VsZCBiZSBwcm9wb3J0aW9uYWwgdG8gaXRzIGV4cG9zdXJlIHRvIG1hcmtldCByaXNrLCBtZWFzdXJlZCBieSB0aGUgQmV0YSAoJFxiZXRhJCkgY29lZmZpY2llbnQsIGluIGFkZGl0aW9uIHRvIGEgcmlzay1mcmVlIHJhdGUuICAKClRoZSBjZW50cmFsIHByZW1pc2UgaXMgdGhhdCBpbnZlc3RvcnMgc2hvdWxkIGJlIGNvbXBlbnNhdGVkIG9ubHkgZm9yIHJpc2sgdGhhdCBjYW5ub3QgYmUgZGl2ZXJzaWZpZWQgKHN5c3RlbWF0aWMgcmlzayksIHdoaWxlIGNvbXBhbnktc3BlY2lmaWMgcmlzayBjYW4gYmUgZWxpbWluYXRlZCB0aHJvdWdoIGEgd2VsbC1zdHJ1Y3R1cmVkIHBvcnRmb2xpby4gRGVzcGl0ZSBjcml0aWNpc21zIHJlZ2FyZGluZyBpdHMgc2ltcGxpZmljYXRpb25z4oCUc3VjaCBhcyBtYXJrZXQgZWZmaWNpZW5jeSBhbmQgdGhlIGZvY3VzIG9uIGEgc2luZ2xlIHJpc2sgZmFjdG9y4oCUQ0FQTSByZW1haW5zIHdpZGVseSB1c2VkIHRvIGVzdGltYXRlIHRoZSBjb3N0IG9mIGVxdWl0eSBhbmQgZXZhbHVhdGUgdGhlIHBlcmZvcm1hbmNlIG9mIHBvcnRmb2xpbyBtYW5hZ2Vycy4KCiMjIEJlaGF2aW9yIG9mICRcYmV0YSQKCkluIHRoZSBjb250ZXh0IG9mIHRoZSBDYXBpdGFsIEFzc2V0IFByaWNpbmcgTW9kZWwgKENBUE0pLCB0aGUgQmV0YSAoJFxiZXRhJCkgY29lZmZpY2llbnQgaXMgYSBtZWFzdXJlIG9mIGFuIGFzc2V0J3Mgc3lzdGVtYXRpYyByaXNr4oCUdGhlIHJpc2sgdGhhdCBjYW5ub3QgYmUgZGl2ZXJzaWZpZWQgYXdheS4gSXQgcXVhbnRpZmllcyBob3cgc2Vuc2l0aXZlIGEgc3BlY2lmaWMgc3RvY2sncyByZXR1cm5zIGFyZSB0byB0aGUgbW92ZW1lbnRzIG9mIHRoZSBicm9hZGVyIG1hcmtldC4rMU1hdGhlbWF0aWNhbGx5LCBpdCBpcyBkZWZpbmVkIGFzOgokJApcYmV0YSA9IFxmcmFje0NvdihSLCBSX20pfXtWYXIoUl9tKX0KJCQKV2hlcmUgJFIkIGFuZCAkUl9tJCBhcmUgdGhlIGFzc2V0IGFuZCBtYXJrZXQgcmV0dXJucywgcmVzcGVjdGl2ZWx5LgoKKiAkXGJldGEgPiAxJCAqKEhpZ2ggU2Vuc2l0aXZpdHkpKiAtIFRoZSBhc3NldCBpcyBtb3JlIHZvbGF0aWxlIHRoYW4gdGhlIG1hcmtldC4gSWYgdGhlIG1hcmtldCByaXNlcyBieSAxMCUsIGEgc3RvY2sgd2l0aCBhICRcYmV0YSQgb2YgMS41IGlzIGV4cGVjdGVkIHRvIHJpc2UgYnkgMTUlLiBDb252ZXJzZWx5LCBpdCB3aWxsIGxpa2VseSBmYWxsIGZ1cnRoZXIgdGhhbiB0aGUgbWFya2V0IGR1cmluZyBhIGRvd250dXJuLiBTdG9ja3MgaW4gc2VjdG9ycyBsaWtlIHRlY2hub2xvZ3kgb3IgYmlvdGVjaG5vbG9neSBvZnRlbiBoYXZlIGhpZ2ggYmV0YXMuCgoqICRcYmV0YSA9IDEkICooTWFya2V0IE5ldXRyYWxpdHkpKiAtIFRoZSBhc3NldCBtb3ZlcyBpbiBsb2Nrc3RlcCB3aXRoIHRoZSBtYXJrZXQuIEl0cyBzeXN0ZW1hdGljIHJpc2sgaXMgaWRlbnRpY2FsIHRvIHRoYXQgb2YgdGhlIG1hcmtldCBwcm94eSAobGlrZSB0aGUgUyZQIDUwMCkuCgoqICQwPFxiZXRhPDEkICooTG93IFNlbnNpdGl2aXR5KSogLSBUaGUgYXNzZXQgaXMgbGVzcyB2b2xhdGlsZSB0aGFuIHRoZSBtYXJrZXQuIEl0IGlzIGNvbnNpZGVyZWQgYSAiZGVmZW5zaXZlIiBzdG9jay4gRm9yIGV4YW1wbGUsIGEgdXRpbGl0eSBjb21wYW55IG1pZ2h0IGhhdmUgYSAkXGJldGEkIG9mIDAuNSwgbWVhbmluZyBpdCBvbmx5IGNhcHR1cmVzIGFib3V0IGhhbGYgb2YgdGhlIG1hcmtldCdzIHN3aW5ncy4KCiogJFxiZXRhPTAkICooTm8gQ29ycmVsYXRpb24pKiAtIFRoZSBhc3NldCdzIHJldHVybnMgaGF2ZSBubyBsaW5lYXIgcmVsYXRpb25zaGlwIHdpdGggdGhlIG1hcmtldCdzIHJldHVybnMuIEEgcmlzay1mcmVlIGFzc2V0LCBsaWtlIGEgVHJlYXN1cnkgYm9uZCAoaW4gdGhlb3J5KSwgaGFzIGEgJFxiZXRhJCBvZiAwLiBHb2xkIGlzIGFsc28gc29tZXRpbWVzIGNpdGVkIGFzIGhhdmluZyBhIGJldGEgbmVhciB6ZXJvLCBhcyBpdHMgcHJpY2UgaXMgb2Z0ZW4gZHJpdmVuIGJ5IGZhY3RvcnMgdW5yZWxhdGVkIHRvIGVxdWl0eSBtYXJrZXRzLgoKKiAkXGJldGE8MCQgKihJbnZlcnNlIENvcnJlbGF0aW9uKSogLSBUaGUgYXNzZXQgbW92ZXMgaW4gdGhlIG9wcG9zaXRlIGRpcmVjdGlvbiBvZiB0aGUgbWFya2V0LiBXaGlsZSByYXJlIGZvciBpbmRpdmlkdWFsIHN0b2Nrcywgc29tZSAiaW52ZXJzZSBFVEZzIiBvciAicHV0IG9wdGlvbnMiIGFyZSBkZXNpZ25lZCB0byBoYXZlIG5lZ2F0aXZlIGJldGFzLiBIaXN0b3JpY2FsbHksIGR1cmluZyBleHRyZW1lIG1hcmtldCBjcmFzaGVzLCB2ZXJ5IGZldyB0cmFkaXRpb25hbCBhc3NldHMgbWFpbnRhaW4gYSBuZWdhdGl2ZSBiZXRhIGNvbnNpc3RlbnRseSwgdGhvdWdoIHNvbWUgInNhZmUgaGF2ZW5zIiBtYXkgZXhoaWJpdCB0aGlzIGJlaGF2aW9yIHRlbXBvcmFyaWx5LgoKIyMgUGV0cm9icmFzIHZzIFMmUDUwMAoKSW4gdGhpcyBkb2N1bWVudCwgd2UgZXN0aW1hdGUgdGhlIENBUE0gcGFyYW1ldGVycyBmb3IgKipQZXRyb2JyYXMgKFBCUikqKiwgdHJhZGVkIG9uIHRoZSBOWVNFLCB1c2luZyB0aGUgKipTJlAgNTAwIChTUFkpKiogYXMgdGhlIG1hcmtldCBwcm94eS4gV2UgYWRvcHQgYSBCYXllc2lhbiBmcmFtZXdvcmssIHdoaWNoIGFsbG93cyB1cyB0byBpbmNvcnBvcmF0ZSBwcmlvciBiZWxpZWZzIGFuZCBvYnRhaW4gYSBmdWxsIHBvc3RlcmlvciBkaXN0cmlidXRpb24gZm9yIHRoZSByaXNrIHBhcmFtZXRlcnMuCgpUaGUgQ0FQTSBlcXVhdGlvbiBpcyBkZWZpbmVkIGFzOgoKJCQKUl90ID0gXGFscGhhICsgXGJldGEgUl97bXR9KyBcZXBzaWxvbl90CiQkCgpXaGVyZToKCiogJHQkIGlzIHRoZSB0aW1lIGZyZXF1ZW5jeSwgdXN1YWxseSBkYWlseS4KCiogJFJfdCQ6IFJldHVybiBvZiB0aGUgcmlza3kgYXNzZXQgKFBCUikuCgoqICRSX3ttdH0kOiBSZXR1cm4gb2YgdGhlIG1hcmtldCBpbmRleCAoUyZQIDUwMCkuCgoqICRcYWxwaGEkOiBUaGUgIkFscGhhIiwgcmVwcmVzZW50aW5nIGFibm9ybWFsIHJldHVybnMuCgoqICRcYmV0YSQ6IFRoZSAiQmV0YSIsIG1lYXN1cmluZyB0aGUgYXNzZXQncyBzZW5zaXRpdml0eSB0byBtYXJrZXQgbW92ZW1lbnRzLgoKKiAkXGVwc2lsb25fdCBcc2ltIE4oMCwgXHNpZ21hXjIpJDogVGhlIGlkaW9zeW5jcmF0aWMgZXJyb3IgdGVybSB3aXRoIHZhcmlhbmNlICRcc2lnbWFeMiQuCgojIFVwbG9hZGluZyBhbmQgcHJvY2Vzc2luZyB0aGUgZGF0YQoKV2UgdXBsb2FkZWQgZGF0YSBmcm9tIEZlYnJ1YXJ5IDEwdGggMjAxNiB0byBGZWJydWFyeSA5dGggMjAyNiwgaWUgYWJvdXQgMTAgeWVhcnMgb2YgZGFpbHkgZGF0YSBvciAkbj0yNTE0JCBvYnNlcnZhdGlvbnMuCgpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD02fQppZiAoIXJlcXVpcmUoInBhY21hbiIpKSBpbnN0YWxsLnBhY2thZ2VzKCJwYWNtYW4iKQpwYWNtYW46OnBfbG9hZChxdWFudG1vZCwgYnJtcywgdGlkeXZlcnNlLCBQZXJmb3JtYW5jZUFuYWx5dGljcykKCnN5bWJvbHMgPC0gYygiUEJSIiwgIlNQWSIpCmdldFN5bWJvbHMoc3ltYm9scywgc3JjID0gInlhaG9vIiwgZnJvbSA9ICIyMDE2LTAyLTA5IiwgdG8gPSBTeXMuRGF0ZSgpKQoKIyBDb21wdXRpbmcgcmV0dXJucwpyZXR1cm5zX3BiciA8LSBSZXR1cm4uY2FsY3VsYXRlKENsKFBCUiksIG1ldGhvZCA9ICJsb2ciKQpyZXR1cm5zX3NweSA8LSBSZXR1cm4uY2FsY3VsYXRlKENsKFNQWSksIG1ldGhvZCA9ICJsb2ciKQoKIyBDb21iaW5pbmcgdGhlIHRpbWUgc2VyaWVzIGFuZCByZW1vdmluZyBtaXNzaW5nIHZhbHVlcwpkYXRhX2NhcG0gPC0gbWVyZ2UocmV0dXJuc19wYnIsIHJldHVybnNfc3B5KSAlPiUgCiAgYXMuZGF0YS5mcmFtZSgpICU+JSAKICBkcm9wX25hKCkKY29sbmFtZXMoZGF0YV9jYXBtKSA8LSBjKCJQQlIiLCAiTWFya2V0IikKCnkgPSBkYXRhX2NhcG1bLDFdCgp4ID0gZGF0YV9jYXBtWywyXQoKcGFyKG1mcm93PWMoMSwxKSkKdHMucGxvdCh5LHlsYWI9IlJldHVybnMiKQpsaW5lcyh4LGNvbD0yKQpsZWdlbmQoInRvcHJpZ2h0IixsZWdlbmQ9YygiUEJSIiwiU1BZIiksY29sPTE6MixsdHk9MSxidHk9Im4iLGx3ZD0yKQpgYGAKCiMgT3JkaW5hcnkgbGVhc3Qgc3F1YXJlcwpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD02fQpzdW1tYXJ5KGxtKHl+eCkpCgpwYXIobWZyb3c9YygxLDEpKQpwbG90KHgseSx4bGFiPSJTUFkiLHlsYWI9IlBCUiIpCnRpdGxlKCJKYW4gM3JkIDIwMjAgLSBGZWJydWFyeSA2dGggMjAyNiIpCmFibGluZShsbSh5fngpLGNvbD0yLGx3ZD0yKQpgYGAKCiMgTWF4aW11bSBsaWtlbGlob29kIGVzdGltYXRpb24KV2hlbiAkeD0oeF8xLFxsZG90cyx4X24pJyQgYW5kICRYJCBpcyBhbiAkKG4gXHRpbWVzIDIpJCBtYXRyaXggd2hlcmUgdGhlIGZpcnN0IGNvbHVtbiBjb250YWlucyBvbmx5IG9uZXMgKGZvciB0aGUgaW50ZXJjZXB0KSBhbmQgdGhlIHNlY29uZCBjb2x1bW4gaXMgJHgkLCB0aGUgR2F1c3NpYW4gbGluZWFyIG1vZGVsIGNhbiBiZSByZXByZXNlbnRlZCBhcwokJAp5ID0gWCBcdGhldGEgKyBcZXBzaWxvbiBccXF1YWQgXHFxdWFkIFxlcHNpbG9uIFxzaW0gTigwLFxzaWdtYV4yIElfbikKJCQKd2l0aCBwYXJhbWV0ZXJzICRcdGhldGE9KFxhbHBoYSxcYmV0YSkkIGFuZCAkXHNpZ21hXjIkLiAgVGhlIE1MIGVzdGltYXRvciBvZiAkXHRoZXRhJCBhbmQgJFxzaWdtYV4yJCBhcmUKJCQKe1x3aWRlaGF0IFx0aGV0YX0gPSAoWCdYKV57LTF9WCd5IFxxcXVhZCBcbWJveHthbmR9IFxxcXVhZAp7XHdpZGVoYXQgXHNpZ21hfV4yID0gXGZyYWN7KHktWHtcd2lkZWhhdCBcdGhldGF9KScoeS1Ye1x3aWRlaGF0IFx0aGV0YX0pfXtufSwKJCQKcmVzcGVjdGl2ZWx5LgoKYGBge3J9ClggICAgICAgICA9IGNiaW5kKDEseCkKbiAgICAgICAgID0gbnJvdyhYKQpwICAgICAgICAgPSBuY29sKFgpCnRoZXRhLm1sZSA9IHNvbHZlKHQoWCklKiVYKSUqJXQoWCklKiV5CnkuaGF0ICAgICA9IFglKiV0aGV0YS5tbGUKZS5oYXQgICAgID0geS15LmhhdApzaWcubWxlICAgPSBzcXJ0KG1lYW4oZS5oYXReMikpCgp0YWJsZSA9IHJvdW5kKHJiaW5kKGNiaW5kKHRoZXRhLm1sZSxsbSh5flgtMSkkY29lZiksCiAgICAgICAgICAgICAgYyhzaWcubWxlLChuLXApL24qc3VtbWFyeShsbSh5flgtMSkpJHNpZ21hKSksNCkKY29sbmFtZXModGFibGUpICAgICAgPSBjKCJPdXIgZnVuY3Rpb24iLCJsbSBmdW5jdGlvbiIpCnJvd25hbWVzKHRhYmxlKVsxXSAgID0gImNvbnN0YW50Igpyb3duYW1lcyh0YWJsZSlbcCsxXSA9ICJzaWdtYSIKdGFibGUKYGBgCgoKIyBDbG9zZWQtZm9ybSBCYXllc2lhbiBpbmZlcmVuY2UgKGNvbmp1Z2FjeSkKTGV0IHVzIGNvbWJpbmUgdGhlIGFib3ZlIEdhdXNzaWFuIGxpbmVhciBtb2RlbCB3aXRoIGEgY29uanVnYXRlIHByaW9yCmZvciAkXHRoZXRhLFxzaWdtYV4yJDoKXGJlZ2lue2VxbmFycmF5Kn0KXHRoZXRhfFxzaWdtYV4yICZcc2ltJiBOKGJfMCxcc2lnbWFeMiBCXzApXFwKXHNpZ21hXjIgJlxzaW0mIElHKFxudV8wLzIsXG51XzBcc2lnbWFfMF4yLzIpLApcZW5ke2VxbmFycmF5Kn0KZm9yIGh5cGVycGFyYW1ldGVycyAkYl8wLEJfMCxcbnVfMCQgYW5kICRcc2lnbWFfMF4yJC4gIFRoaXMgcHJpb3IgaXMgY29uanVnYXRlIHNpbmNlIHRoZSBwb3N0ZXJpb3IgZm9sbG93cyB0aGUgc2FtZSBmYW1pbHkgb2YgZGlzdHJpYnV0aW9ucyBhcyB0aGUgcHJpb3Igd2l0aCBoeXBlcnBhcmFtZXRlcnMgYWRqdXN0ZWQgYnkgdGhlIG9ic2VydmVkIGRhdGEuICBNb3JlIHByZWNpc2VseSwKXGJlZ2lue2VxbmFycmF5Kn0KXHRoZXRhfFxzaWdtYV4yLFxtYm94e2RhdGF9ICZcc2ltJiBOKGJfMSxcc2lnbWFeMiBCXzEpXFwKXHNpZ21hXjJ8XG1ib3h7ZGF0YX0gJlxzaW0mIElHKFxudV8xLzIsXG51XzFcc2lnbWFfMV4yLzIpXFwKXHRoZXRhfFxtYm94e2RhdGF9ICZcc2ltJiB0X3tcbnVfMX0oYl8xLFxzaWdtYV8xXjIgQl8xKSwKXGVuZHtlcW5hcnJheSp9CndoZXJlIApcYmVnaW57ZXFuYXJyYXkqfQpCXzEgJj0mIChCXzBeey0xfStYJ1gpXnstMX1cXApCXzFeey0xfSBiXzEgJj0mIEJfMF57LTF9IGJfMCArIFgneVxcClxudV8xICY9JiBcbnVfMCArIG5cXApcbnVfMVxzaWdtYV8xXjIgJj0mIFxudV8wXHNpZ21hXzBeMiArICh5LVggYl8xKSd5ICsgKGJfMC1iXzEpJ0JfMF57LTF9Yl8wLgpcZW5ke2VxbmFycmF5Kn0KCgpOb3RpY2UgdGhhdCB0aGUgYWJvdmUgZGVyaXZhdGlvbnMsIGJvdGggTUxFIGFuZCBCYXllc2lhbiB3aXRoIGNvbmp1Z2F0ZSBwcmlvciwgZm9yIHRoZSBHYXVzc2lhbiBsaW5lYXIgcmVncmVzc2lvbiBpcyBzdGlsbCB2YWxpZCBmb3IgJHA+MiQgYW5kIGlzIHRoZSBiYXNlIG9mIHRoZSBzdGFuZGFyZCBHYXVzc2lhbiBsaW5lYXIgcmVncmVzc2lvbiBmcmFtZXdvcmsgdGF1Z2h0IGluIHZpcnR1YWxseSBhbGwgaW50cm9kdWN0b3J5IGVjb25vbWV0cmljcyBjbGFzc2VzLgoKCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTE4fQojIFByaW9yIGh5cGVycGFyYW1ldGVycwpiMCAgICAgICA9IGMoMCwxKQpCMCAgICAgICA9IGRpYWcoYygxMDAwLDI1MCksMikKbnUwICAgICAgPSAwLjAwMgpzaWcyMCAgICA9IDEuMAoKIyBQb3N0ZXJpb3IgaHlwZXJwYXJhbWV0ZXJzCm51MHNpZzIwID0gbnUwKnNpZzIwCmlCMCAgICAgID0gc29sdmUoQjApCmlCMGIwICAgID0gaUIwJSolYjAKQjEgICAgICAgPSBzb2x2ZShpQjArdChYKSUqJVgpCnRjQjEgICAgID0gdChjaG9sKEIxKSkKYjEgICAgICAgPSBCMSUqJShpQjBiMCt0KFgpJSoleSkKbnUxICAgICAgPSBudTAgKyBuCnNpZzIxICAgID0gKChudTBzaWcyMCtzdW0oKHktWCUqJWIxKSp5KSt0KGIwLWIxKSUqJWlCMGIwKS9udTEpWzFdCnNlICAgICAgID0gc3FydChudTEvKG51MS0yKSpzaWcyMSpkaWFnKEIxKSkKCnRhYiA9IHJvdW5kKGNiaW5kKGIxLHNlLGIxL3NlLDIqKDEtcHQoYWJzKGIxL3NlKSxkZj1udTEpKSksNSkKY29sbmFtZXModGFiKT1jKCJNZWFuIiwiU3REZXYiLCJ0IiwidGFpbCIpCnJvd25hbWVzKHRhYik9YygiSW50ZXJjZXB0IiwiTWFya2V0IikKdGFiCmBgYAoKIyBNQ01DLWJhc2VkIEJheWVzaWFuIGluZmVyZW5jZSAoY29uZGl0aW9uYWxseSBjb25qdWdhY3kpCldoZW4gdGhlIGNvbmp1Z2F0ZSBwcmlvciwgcHJlc2VudGVkIGFib3ZlLCBpcyByZXBsYWNlZCBieSB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbmFsbHkgY29uanVnYXRlIG9uZSwgd2UgbG9vc2UgY2xvc2VkIGZvcm0gZGVyaXZhdGlvbiBmb3IgCnBvc3RlcmlvciBpbmZlcmVuY2U6ClxiZWdpbntlcW5hcnJheSp9Clx0aGV0YXxcc2lnbWFeMiAmXHNpbSYgTihiXzAsVl8wKVxcClxzaWdtYV4yICZcc2ltJiBJRyhjXzAsZF8wKS4KXGVuZHtlcW5hcnJheSp9CkluIHRoaXMgY2FzZSwgYSBzdGFuZGFyZCBzb2x1dGlvbiBzaW5jZSB0aGUgZWFybHkgMTk5MHMgaXMgdG8gaW1wbGVtZW50IGFuIE1hcmtvdiBjaGFpbiBNb250ZSBDYXJsbyAoTUNNQykgYWxnb3JpdGhtLiAgRm9yIHRoZSBHYXVzc2lhbiBsaW5lYXIgbW9kZWwgd2l0aCBjb25kaXRpb25hbGx5IGNvbmp1Z2F0ZSBwcmlvciwgaXQgaXMgd2VsbCBlc3RhYmxpc2hlZCB0aGF0IHRoZSBHaWJicyBzYW1wbGVyIGlzIHRoZSBzaW1wbGVzdCBhbmQgY2xlYW5lc3QgTUNNQyBzY2hlbWUuCgpUaGUgR2liYnMgc2FtcGxlciwgaW4gb3VyIHBhcnRpY3VsYXIgc2V0IHVwLCBjeWNsZXMgdGhyb3VnaCB0aGUgdHdvIGZ1bGwgY29uZGl0aW9uYWxzIAokJApwKFx0aGV0YXxcc2lnbWFeMixcbWJveHtkYXRhfSkgXCBcIFwgXG1ib3h7YW5kfSBcIFwgXCAKcChcc2lnbWFeMnxcdGhldGEsXG1ib3h7ZGF0YX0pLAokJApib3RoIG9mIHdoaWNoIGFyZSBlYXNpbHkgZGVyaXZlZDoKJCQKTihiXzEsVl8xKSBcIFwgXCBcbWJveHthbmR9IFwgXCBcIElHKGNfMSxkXzEpCiQkCndoZXJlClxiZWdpbntlcW5hcnJheSp9ClZfMV57LTF9ICY9JiBYJ1gvXHNpZ21hXjIgKyBWXzBeey0xfVxcClZfMV57LTF9Yl8xICY9JiAgWCd5L1xzaWdtYV4yICsgVl8wXnstMX0gYl8wXFwKY18xICY9JiBjXzAgICsgbi8yXFwKZF8xICY9JiBkXzAgKyAoeS1YJ1x0aGV0YSkoeS1YJ1x0aGV0YSkvMgpcZW5ke2VxbmFycmF5Kn0KCgpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD05LCBmaWcuaGVpZ2h0PTl9CiMgUHJpb3Iga25vd2xlZGdlIApiMCA9IHJlcCgwLHApClYwID0gZGlhZyhjKDEsMC4yNSkpCmMwID0gMC4wMDEKZDAgPSAwLjAwMQppVjAgPSBzb2x2ZShWMCkKaVYwYjAgPSBpVjAlKiViMAoKIyBHaWJicyBzYW1wbGVyCnNpZ21hMiAgPSAxIApNMCAgICAgID0gMTAwMApNICAgICAgID0gMTAwMDAKdGhpbiAgICA9IDEKbml0ZXIgICA9IE0wK00qdGhpbgp0aGV0YXMgID0gbWF0cml4KDAsbml0ZXIscCkKc2lncyAgICA9IHJlcCgwLG5pdGVyKQpmb3IgKGl0ZXIgaW4gMTpuaXRlcil7CiAgVjEgPSBzb2x2ZSh0KFgpJSolWC9zaWdtYTIraVYwKQogIGIxID0gVjElKiUodChYKSUqJXkvc2lnbWEyK2lWMGIwKQogIHRoZXRhID0gYjEgKyB0KGNob2woVjEpKSUqJXJub3JtKHApCiAgYzEgPSBjMCArIG4vMgogIGQxID0gZDAgKyBzdW0oKHktWCUqJXRoZXRhKV4yKS8yCiAgc2lnbWEyID0gMS9yZ2FtbWEoMSxjMSxkMSkKICB0aGV0YXNbaXRlcixdID0gdGhldGEKICBzaWdzW2l0ZXJdID0gc3FydChzaWdtYTIpCn0KaW5kICAgID0gc2VxKE0wKzEsbml0ZXIsYnk9dGhpbikKdGhldGFzID0gdGhldGFzW2luZCxdCnNpZ3MgICA9IHNpZ3NbaW5kXQoKbWVhbi50aGV0YSA9IGFwcGx5KHRoZXRhcywyLG1lYW4pCnRhYmxlID0gcm91bmQoY2JpbmQodGhldGEubWxlLG1lYW4udGhldGEpLDUpCmNvbG5hbWVzKHRhYmxlKSA9IGMoIk1MIiwiQmF5ZXMiKQpyb3duYW1lcyh0YWJsZSkgPSBjKCJJbnRlcmNlcHQiLCJNYXJrZXQiKQp0YWJsZQoKcGFyKG1mcm93PWMoMywzKSkKdHMucGxvdCh0aGV0YXNbLDFdLHhsYWI9Ikl0ZXJhdGlvbnMiLHlsYWI9IiIsbWFpbj1leHByZXNzaW9uKGFscGhhKSkKdHMucGxvdCh0aGV0YXNbLDJdLHhsYWI9Ikl0ZXJhdGlvbnMiLHlsYWI9IiIsbWFpbj1leHByZXNzaW9uKGJldGEpKQp0cy5wbG90KHNpZ3MseGxhYj0iSXRlcmF0aW9ucyIseWxhYj0iIixtYWluPWV4cHJlc3Npb24oc2lnbWEpKQphY2YodGhldGFzWywxXSxtYWluPSIiKQphY2YodGhldGFzWywyXSxtYWluPSIiKQphY2Yoc2lncyxtYWluPSIiKQpoaXN0KHRoZXRhc1ssMV0scHJvYj1UUlVFLHhsYWI9IiIsbWFpbj0iIikKaGlzdCh0aGV0YXNbLDJdLHByb2I9VFJVRSx4bGFiPSIiLG1haW49IiIpCmhpc3Qoc2lncyxwcm9iPVRSVUUseGxhYj0iIixtYWluPSIiKQpgYGAKCiMgQ29tcGFyaXNvbgoKV2UgY29tcGFyZSB0aGUgTUwgZXN0aW1hdGUgd2l0aCB0aGUgcG9zdGVyaW9yIGRlbnNpdGllcywgYmFzZWQgb24gYm90aCBjb25qdWdhdGUgYW5kIGNvbmRpdGlvbmFsbHkgY29uanVnYXRlIHByaW9ycywgZm9yIHRoZSBwYXJhbWV0ZXJzICRcYWxwaGEkLCAkXGJldGEkIGFuZCAkXHNpZ21hXjIkLgoKYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9NH0KcGFyKG1mcm93PWMoMSwzKSkKcGxvdChkZW5zaXR5KHRoZXRhc1ssMV0pLHhsYWI9IkludGVyY2VwdCIsbWFpbj0iIikKYmIgPSBzZXEobWluKHRoZXRhc1ssMV0pLG1heCh0aGV0YXNbLDFdKSxsZW5ndGg9MTAwMCkKZGVuID0gZHQoKGJiLWIxWzEsMV0pL3NxcnQoc2lnMjEqQjFbMSwxXSksZGY9bnUxKS9zcXJ0KHNpZzIxKkIxWzEsMV0pCmxpbmVzKGJiLGRlbixjb2w9Mixsd2Q9MikKYWJsaW5lKHY9dGhldGEubWxlWzEsMV0sY29sPTMsbHdkPTIpCmxlZ2VuZCgidG9wbGVmdCIsbGVnZW5kPWMoIk1MRSIsIkMgUHJpb3IiLCJDQyBwcmlvciIpLGNvbD1jKDMsMiwxKSxidHk9Im4iLGx3ZD0yKQoKcGxvdChkZW5zaXR5KHRoZXRhc1ssMl0pLHhsYWI9IlNsb3BlIixtYWluPSIiKQpiYiA9IHNlcShtaW4odGhldGFzWywyXSksbWF4KHRoZXRhc1ssMl0pLGxlbmd0aD0xMDAwKQpkZW4gPSBkdCgoYmItYjFbMiwxXSkvc3FydChzaWcyMSpCMVsyLDJdKSxkZj1udTEpL3NxcnQoc2lnMjEqQjFbMiwyXSkKbGluZXMoYmIsZGVuLGNvbD0yLGx3ZD0yKQphYmxpbmUodj10aGV0YS5tbGVbMiwxXSxjb2w9Myxsd2Q9MikKbGVnZW5kKCJ0b3BsZWZ0IixsZWdlbmQ9YygiTUxFIiwiQyBQcmlvciIsIkNDIHByaW9yIiksY29sPWMoMywyLDEpLGJ0eT0ibiIsbHdkPTIpCgoKc2lnczIgPSBzaWdzXjIKczIgICAgPSBzZXEobWluKHNpZ3MyKSxtYXgoc2lnczIpLGxlbmd0aD0xMDAwKQpkZW4gICA9IGRnYW1tYSgxL3MyLG51MS8yLG51MSpzaWcyMS8yKS8oczJeMikKZGVuLmQgPSBkZW5zaXR5KHNpZ3MyKQpwbG90KGRlbi5kJHgsZGVuLmQkeSx4bGFiPSJFcnJvciB2YXJpYW5jZSIsbWFpbj0iIix5bGltPXJhbmdlKGRlbi5kJHksZGVuKSx0eXBlPSJsIix5bGFiPSJEZW5zaXR5IikKbGluZXMoczIsZGVuLGNvbD0yLGx3ZD0yKQphYmxpbmUodj1zaWcubWxlXjIsY29sPTMsbHdkPTIpCmxlZ2VuZCgidG9wbGVmdCIsbGVnZW5kPWMoIk1MRSIsIkMgUHJpb3IiLCJDQyBwcmlvciIpLGNvbD1jKDMsMiwxKSxidHk9Im4iLGx3ZD0yKQpgYGAKCiMgVGhpbmdzIHlvdSBoYWQgdG8ga25vdyB0byB1bmRlcnN0YW5kIHRoaXMgY2xhc3MKCjEuIENvdmFyaWFuY2UKCjIuIFZhcmlhbmNlCgozLiBGaXR0aW5nIGEgbGluZSB2aWEgb3JkaW5hcnkgbGVhc3Qgc3F1YXJlcwoKNC4gR2F1c3NpYW4gbGluZWFyIG1vZGVsCgo1LiBCYXNpYyBtYXRyaXggYWxnZWJyYQoKNi4gTGlrZWxpaG9vZCBmdW5jdGlvbgoKNy4gbWF4aW11bSBsaWtlbGlob29kIGVzdGltYXRvcgoKOC4gUHJpb3IgYW5kIHBvc3RlcmlvciBkaXN0cmlidXRpb25zCgo5LiBJbnZlcnNlLWdhbW1hIGRpc3RyaWJ1dGlvbgoKMTAuIENvbmp1Z2FjeQoKMTEuIENvbmRpdGlvbmFsIGNvbmp1Z2FjeQoKMTIuIE1vbnRlIENhcmxvIHBvc3RlcmlvciBzaW11bGF0aW9uCg==