Once we’ve described some basic concepts of matrix algebra, we’re ready to move on to see how this is used in statistics and data analysis. A simple example:
- Mean \[\begin{align}A=\underbrace{\begin{pmatrix}1\\1\\\vdots\\1\end{pmatrix}}_{N\times 1}\Longrightarrow\frac{1}{N}A^{T}Y&=\frac{1}{N}\begin{pmatrix}1&1&...&1\end{pmatrix}\begin{pmatrix}y_{1}\\y_{2}\\\vdots\\y_{n}\end{pmatrix}\\&=\frac{1}{N}\sum_{i=1}^{N}y_{1}=\overline{Y}\end{align}\] As shown, we can use the matrix algebra notation to represent the sample average.
mean(y)
[1] 68.68407
N<-length(y)
A<-matrix(1,N,1)
Y<-matrix(y,N,1)
Y.bar<-(1/N)*t(A)%*%Y
Y.bar
[,1]
[1,] 68.68407
Let \(r\) be the deviations of each observation in \(Y\) with respect to the mean \(\overline{Y}\), called \(\textit{vector of residuals}\) \[r\equiv\begin{pmatrix}y_{1}-\overline{Y}\\\vdots\\y_{n}-\overline{Y}\end{pmatrix}\] and we can write the \(\textit{variance}\) as, \[\frac{1}{N}r^{T}r=\frac{1}{N}\sum_{i=1}^{N}(y_{i}-\overline{Y})^{2}\] in general, \(r^{T}r\) gives us the sum of squares of \(r\) entries.
Y.bar.v<-matrix(Y.bar,N,1)
r<-Y-Y.bar.v
variance<-(t(r)%*%r)/N
print(variance)
[,1]
[1,] 7.915196
var(Y)*(N-1)/N
[,1]
[1,] 7.915196
Using matrix algebra we can rewrite the general model: \[\begin{align}y_{i}=\beta_{0}+\sum_{j=1}^{N}\beta_{j}x_{i,j}+\varepsilon_{i} & & i=1,...,N\end{align}\] Simply as, \[Y=X\beta+\varepsilon\] Such that, \[\begin{align}Y=\begin{pmatrix}y_{1}\\y_{2}\\ \vdots\\ y_{N}\end{pmatrix},& & X=\begin{pmatrix}1&x_{1,1}&...&x_{1,p}\\1&x_{2,1}&...&x_{2,p}\\ \vdots &\vdots&\ddots&\vdots\\1&x_{N,1}&...&x_{N,p}\end{pmatrix},\end{align}\] \[\begin{align}\beta=\begin{pmatrix}\beta_{0}\\ \beta_{1}\\ \vdots\\ \beta_{p}\end{pmatrix}& &\text{and} & &\varepsilon=\begin{pmatrix}\varepsilon_{1}\\ \varepsilon_{2}\\ \vdots \\ \varepsilon_{N}\end{pmatrix}\end{align}\] So we have, \[\begin{pmatrix}y_{1}\\ y_{2}\\ \vdots \\ y_{N}\end{pmatrix}=\begin{pmatrix}1&x_{1,1}&...&x_{1,p}\\1&x_{2,1}&...&x_{2,p}\\ \vdots &\vdots&\ddots&\vdots\\1&x_{N,1}&...&x_{N,p}\end{pmatrix}\begin{pmatrix}\beta_{0}\\ \beta_{1}\\ \vdots\\ \beta_{p}\end{pmatrix}+\begin{pmatrix}\varepsilon_{1}\\ \varepsilon_{2}\\ \vdots \\ \varepsilon_{N}\end{pmatrix}\] One of the ways this is useful is that we can write down the residual sum of squares in a relatively simple formula. First, we need to find is the vector of betas that minimize the residual sums of squares. Minimizing Residual Sum of Squares: The RSS equation becomes simpler \[(Y-X\beta)^{T}(Y-X\beta)\] and to find the \(\hat{\beta}\) that minimizes this we solve (by taking the derivative): \[\begin{align}2X^{T}(Y-X\hat{\beta})&=0\\ \Leftrightarrow X^{T}X\hat{\beta}&=X^{T}Y\\ \Leftrightarrow \hat{\beta}&=(X^{T}X)^{-1}X^{T}Y\end{align}\]
x<-father.son$fheight
y<-father.son$sheight
X<-cbind(1,x)
beta.hat<-solve(t(X)%*%X)%*%t(X)%*%y
beta.hat
[,1]
33.886604
x 0.514093
Practice
g<-9.8 #gravity constant
N<-25 #number of observations
t<- seq(0,3.4,len=N) #sequence of numbers btwn 0-3,4
f<-56.67+0*t-0.5*g*t^{2} #1st term = constant height of the Tower of Pisa, 2nd term=linear term in time, 3rd term=square of time times g.
epsilon<-rnorm(N,0,1) #error term distributed as normal with mean=0 and variance=1
y<-f+epsilon
#install.packages("ggplot")
#library(ggplot2)
plot(t,y, xlab="Time in secs", ylab="Distance in metters")
lines(t,f,col=2)

t2<-t^2
fit<-lm(y~t+t2)
summary(fit)
Call:
lm(formula = y ~ t + t2)
Residuals:
Min 1Q Median 3Q Max
-2.1189 -0.3065 0.1061 0.8327 1.3394
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 56.2953 0.6000 93.825 < 2e-16 ***
t 0.3284 0.8173 0.402 0.692
t2 -4.9640 0.2322 -21.379 3.29e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 1.081 on 22 degrees of freedom
Multiple R-squared: 0.9967, Adjusted R-squared: 0.9964
F-statistic: 3285 on 2 and 22 DF, p-value: < 2.2e-16
We need first construct the \(X\) that has covariates as columns:
t<- seq(0,3.4,len=N)
t2<-t^2
N<-25
f<-56.67+0*t-0.5*g*t^{2}
epsilon<-rnorm(N,0,1)
y<-f+epsilon
intercept<-matrix(1,N,1)
X<-cbind(intercept,t,t2)
betas<-solve(t(X)%*%X)%*%t(X)%*%y
betas
[,1]
56.2523269
t 0.5732126
t2 -5.0763945
Exercises: Suppose we are analyzing a set of 4 samples. The first two samples are from a treatment group A and the second two samples are from a treatment group B. This design can be represented with a model matrix like so:
X
[,1] [,2]
a 1 0
a 1 0
b 1 1
b 1 1
Suppose that the fitted parameters for a linear model give us:
beta
[1] 5 2
Use the matrix multiplication operator, %*%, in R to answer the following questions:
Matrix Algebra Examples Exercises #1
What is the fitted value for the A samples? (The fitted Y values.)
Y<-X%*%beta
Y[1:2,]
Matrix Algebra Examples Exercises #2 What is the fitted value for the B samples? (The fitted Y values.)
Y[3:4,]
b b
7 7
Inference Review Exercises #1 We have shown how to find the least squares estimates with matrix algebra. These estimates are random variables as they are linear combinations of the data. For these estimates to be useful we also need to compute the standard errors.
Here we review standard errors in the context of linear models.
It is useful to think about where randomness comes from. In our falling object example, randomness was introduced through measurement errors. Every time we rerun the experiment a new set of measurement errors will be made which implies our data will be random. This implies that our estimate of, for example, the gravitational constant will change. The constant is fixed, but our estimates are not. To see this we can run a Monte Carlo simulation. Specifically we will generate the data repeatedly and compute the estimate for the quadratic term each time.
g <- 9.8 ## meters per second
h.0 <- 56.67
v.0 <- 0
N <- 25
tt <- seq(0,3.4,len=N) ##time in secs, t is a base function
y <- h.0 + v.0 *tt - 0.5* g*tt^2 + rnorm(N,sd=1)
Now we act as if we didn’t know \(h.0\), \(v.0\) and \(-0.5*g\) and use regression to estimate these. We can rewrite the model as \(y = \beta_{0} + \beta_{1}t + \beta_{2} t^2 + \varepsilon\) and obtain the LSE we have used in this class. Note that \(g = -2\beta_{2}\). To obtain the LSE in R we could write:
X <- cbind(1,tt,tt^2)
A <- solve(t(X)%*%X)%*%t(X)
Given how we have defined A, which of the following is the LSE of g, the acceleration due to gravity?
betas<-A%*%y
-2*betas[3]
[1] 8.895099
Inference Review Exercises #2 In the lines of code above, there was a call to a random function rnorm(). This means that each time the lines of code above are repeated, the estimate of \(g\) will be different.
Set the seed to 1, then use the code above in conjunction with the function replicate() to generate 100,000 Monte Carlo simulated datasets. For each dataset compute an estimate of g (remember to multiply by -2).
What is the standard deviation of this estimate?:
##Info Parenthesis
To use Monte Carlo methods, you need to be able to replicate some random process many times. There are two main ways this is commonly done: either with replicate() or with for() loops.
The replicate() function executes some expression many times and returns the output from each execution. Say we have a vector x, which represents 30 observations of fish length (mm):
x
[1] 468.4231 552.0125 492.7318 505.9992 522.0911 517.0467 464.9127 514.3202 495.0259 576.6961 509.8098
[12] 449.0348 466.7975 459.5749 493.6497 489.5787 474.1776 527.2837 533.8535 450.2837 536.4532 459.5868
[23] 495.1613 490.2220 510.0694 536.4575 484.2347 489.3954 509.4261 568.6227
We wish to build the sampling distribution of the mean length “by hand”. We can sample randomly from it, calculate the mean, then repeat this process many times:
means <- replicate(n = 1000, expr = {
x_i = sample(x, length(x), replace = T)
mean(x_i)
})
If we take mean(means) and sd(means), that should be very similar to mean(x) and se(x). Create the se() function and prove this to yourself:
se <- function(x) sd(x)/sqrt(length(x))
mean(means); mean(x)
[1] 501.4155
[1] 501.4311
sd(means); se(x)
[1] 6.144784
[1] 6.077123
##.
set.seed(1)
B <- 100000
g <- 9.8 ## meters per second
n <- 25
tt <- seq(0,3.4,len=n) ##time in secs, t is a base function
X <- cbind(1,tt,tt^2)
A <- solve(crossprod(X))%*%t(X)
betahat <- replicate(B,{
y = 56.67 - 0.5*g*tt^2 + rnorm(n,sd=1)
betahats = -2*A%*%y
return(betahats[3])
})
sqrt(mean( (betahat-mean(betahat) )^2))
[1] 0.4297449
LS0tCnRpdGxlOiAiREFUQSBBTkFMWVNJUyBXSVRIIE1BVFJJWCBBTEdFQlJBIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCk9uY2Ugd2UndmUgZGVzY3JpYmVkIHNvbWUgYmFzaWMgY29uY2VwdHMgb2YgbWF0cml4IGFsZ2VicmEsIHdlJ3JlIHJlYWR5IHRvIG1vdmUgb24gdG8gc2VlIGhvdyB0aGlzIGlzIHVzZWQgaW4gc3RhdGlzdGljcyBhbmQgZGF0YSBhbmFseXNpcy4KQSBzaW1wbGUgZXhhbXBsZToKCi0gTWVhbgokJFxiZWdpbnthbGlnbn1BPVx1bmRlcmJyYWNle1xiZWdpbntwbWF0cml4fTFcXDFcXFx2ZG90c1xcMVxlbmR7cG1hdHJpeH19X3tOXHRpbWVzIDF9XExvbmdyaWdodGFycm93XGZyYWN7MX17Tn1BXntUfVkmPVxmcmFjezF9e059XGJlZ2lue3BtYXRyaXh9MSYxJi4uLiYxXGVuZHtwbWF0cml4fVxiZWdpbntwbWF0cml4fXlfezF9XFx5X3syfVxcXHZkb3RzXFx5X3tufVxlbmR7cG1hdHJpeH1cXCY9XGZyYWN7MX17Tn1cc3VtX3tpPTF9XntOfXlfezF9PVxvdmVybGluZXtZfVxlbmR7YWxpZ259JCQKQXMgc2hvd24sIHdlIGNhbiB1c2UgdGhlIG1hdHJpeCBhbGdlYnJhIG5vdGF0aW9uIHRvIHJlcHJlc2VudCB0aGUgc2FtcGxlIGF2ZXJhZ2UuCmBgYHtyIEF2ZXJhZ2V9CiNpbnN0YWxsLnBhY2thZ2VzKCJVc2luZ1IiKQojbGlicmFyeShVc2luZ1IpCnk8LWZhdGhlci5zb24kc2hlaWdodCAjZ2VuZXJhdGVzIHZlY3RvciBvZiBzb24gaGVpZ2h0cy4KbWVhbih5KQpgYGAKYGBge3J9Ck48LWxlbmd0aCh5KQpBPC1tYXRyaXgoMSxOLDEpClk8LW1hdHJpeCh5LE4sMSkKWS5iYXI8LSgxL04pKnQoQSklKiVZClkuYmFyCmBgYAotIFRoZSB2YXJpYW5jZQoKTGV0ICRyJCBiZSB0aGUgZGV2aWF0aW9ucyBvZiBlYWNoIG9ic2VydmF0aW9uIGluICRZJCB3aXRoIHJlc3BlY3QgdG8gdGhlIG1lYW4gJFxvdmVybGluZXtZfSQsIGNhbGxlZCAkXHRleHRpdHt2ZWN0b3Igb2YgcmVzaWR1YWxzfSQKJCRyXGVxdWl2XGJlZ2lue3BtYXRyaXh9eV97MX0tXG92ZXJsaW5le1l9XFxcdmRvdHNcXHlfe259LVxvdmVybGluZXtZfVxlbmR7cG1hdHJpeH0kJAphbmQgd2UgY2FuIHdyaXRlIHRoZSAkXHRleHRpdHt2YXJpYW5jZX0kIGFzLAokJFxmcmFjezF9e059cl57VH1yPVxmcmFjezF9e059XHN1bV97aT0xfV57Tn0oeV97aX0tXG92ZXJsaW5le1l9KV57Mn0kJAppbiBnZW5lcmFsLCAkcl57VH1yJCBnaXZlcyB1cyB0aGUgc3VtIG9mIHNxdWFyZXMgb2YgJHIkIGVudHJpZXMuCmBgYHtyIFZhcmlhbmNlfQpZLmJhci52PC1tYXRyaXgoWS5iYXIsTiwxKQpyPC1ZLVkuYmFyLnYKdmFyaWFuY2U8LSh0KHIpJSolcikvTgpwcmludCh2YXJpYW5jZSkKI0VxdWl2YWxlbnQgdG86CnZhcihZKSooTi0xKS9OICN1bmJpYXNlZCBzYW1wbGUgdmFyaWFuY2UKYGBgClVzaW5nIG1hdHJpeCBhbGdlYnJhIHdlIGNhbiByZXdyaXRlIHRoZSBnZW5lcmFsIG1vZGVsOgokJFxiZWdpbnthbGlnbn15X3tpfT1cYmV0YV97MH0rXHN1bV97aj0xfV57Tn1cYmV0YV97an14X3tpLGp9K1x2YXJlcHNpbG9uX3tpfSAmICYgaT0xLC4uLixOXGVuZHthbGlnbn0kJApTaW1wbHkgYXMsCiQkWT1YXGJldGErXHZhcmVwc2lsb24kJApTdWNoIHRoYXQsCiQkXGJlZ2lue2FsaWdufVk9XGJlZ2lue3BtYXRyaXh9eV97MX1cXHlfezJ9XFwgXHZkb3RzXFwgeV97Tn1cZW5ke3BtYXRyaXh9LCYgJiBYPVxiZWdpbntwbWF0cml4fTEmeF97MSwxfSYuLi4meF97MSxwfVxcMSZ4X3syLDF9Ji4uLiZ4X3syLHB9XFwgXHZkb3RzICZcdmRvdHMmXGRkb3RzJlx2ZG90c1xcMSZ4X3tOLDF9Ji4uLiZ4X3tOLHB9XGVuZHtwbWF0cml4fSxcZW5ke2FsaWdufSQkCiQkXGJlZ2lue2FsaWdufVxiZXRhPVxiZWdpbntwbWF0cml4fVxiZXRhX3swfVxcIFxiZXRhX3sxfVxcIFx2ZG90c1xcICBcYmV0YV97cH1cZW5ke3BtYXRyaXh9JiAmXHRleHR7YW5kfSAmICZcdmFyZXBzaWxvbj1cYmVnaW57cG1hdHJpeH1cdmFyZXBzaWxvbl97MX1cXCBcdmFyZXBzaWxvbl97Mn1cXCBcdmRvdHMgXFwgXHZhcmVwc2lsb25fe059XGVuZHtwbWF0cml4fVxlbmR7YWxpZ259JCQKU28gd2UgaGF2ZSwKJCRcYmVnaW57cG1hdHJpeH15X3sxfVxcIHlfezJ9XFwgXHZkb3RzIFxcIHlfe059XGVuZHtwbWF0cml4fT1cYmVnaW57cG1hdHJpeH0xJnhfezEsMX0mLi4uJnhfezEscH1cXDEmeF97MiwxfSYuLi4meF97MixwfVxcIFx2ZG90cyAmXHZkb3RzJlxkZG90cyZcdmRvdHNcXDEmeF97TiwxfSYuLi4meF97TixwfVxlbmR7cG1hdHJpeH1cYmVnaW57cG1hdHJpeH1cYmV0YV97MH1cXCBcYmV0YV97MX1cXCBcdmRvdHNcXCAgXGJldGFfe3B9XGVuZHtwbWF0cml4fStcYmVnaW57cG1hdHJpeH1cdmFyZXBzaWxvbl97MX1cXCBcdmFyZXBzaWxvbl97Mn1cXCBcdmRvdHMgXFwgXHZhcmVwc2lsb25fe059XGVuZHtwbWF0cml4fSQkCk9uZSBvZiB0aGUgd2F5cyB0aGlzIGlzIHVzZWZ1bCBpcyB0aGF0IHdlIGNhbiB3cml0ZSBkb3duIHRoZSByZXNpZHVhbCBzdW0gb2Ygc3F1YXJlcyBpbiBhIHJlbGF0aXZlbHkgc2ltcGxlIGZvcm11bGEuIEZpcnN0LCB3ZSBuZWVkIHRvIGZpbmQgaXMgdGhlIHZlY3RvciBvZiBiZXRhcyB0aGF0IG1pbmltaXplIHRoZSByZXNpZHVhbCBzdW1zIG9mIHNxdWFyZXMuCk1pbmltaXppbmcgUmVzaWR1YWwgU3VtIG9mIFNxdWFyZXM6ClRoZSBSU1MgZXF1YXRpb24gYmVjb21lcyBzaW1wbGVyCiQkKFktWFxiZXRhKV57VH0oWS1YXGJldGEpJCQKYW5kIHRvIGZpbmQgdGhlICRcaGF0e1xiZXRhfSQgdGhhdCBtaW5pbWl6ZXMgdGhpcyB3ZSBzb2x2ZSAoYnkgdGFraW5nIHRoZSBkZXJpdmF0aXZlKToKJCRcYmVnaW57YWxpZ259Mlhee1R9KFktWFxoYXR7XGJldGF9KSY9MFxcIFxMZWZ0cmlnaHRhcnJvdyBYXntUfVhcaGF0e1xiZXRhfSY9WF57VH1ZXFwgIFxMZWZ0cmlnaHRhcnJvdyAgXGhhdHtcYmV0YX0mPShYXntUfVgpXnstMX1YXntUfVlcZW5ke2FsaWdufSQkCmBgYHtyfQp4PC1mYXRoZXIuc29uJGZoZWlnaHQKeTwtZmF0aGVyLnNvbiRzaGVpZ2h0Clg8LWNiaW5kKDEseCkKYmV0YS5oYXQ8LXNvbHZlKHQoWCklKiVYKSUqJXQoWCklKiV5CmJldGEuaGF0CmBgYAoKUHJhY3RpY2UKYGBge3J9Cmc8LTkuOCAjZ3Jhdml0eSBjb25zdGFudApOPC0yNSAjbnVtYmVyIG9mIG9ic2VydmF0aW9ucwp0PC0gc2VxKDAsMy40LGxlbj1OKSAjc2VxdWVuY2Ugb2YgbnVtYmVycyBidHduIDAtMyw0CmY8LTU2LjY3KzAqdC0wLjUqZyp0XnsyfSAjMXN0IHRlcm0gPSBjb25zdGFudCBoZWlnaHQgb2YgdGhlIFRvd2VyIG9mIFBpc2EsIDJuZCB0ZXJtPWxpbmVhciB0ZXJtIGluIHRpbWUsIDNyZCB0ZXJtPXNxdWFyZSBvZiB0aW1lIHRpbWVzIGcuCmVwc2lsb248LXJub3JtKE4sMCwxKSAjZXJyb3IgdGVybSBkaXN0cmlidXRlZCBhcyBub3JtYWwgd2l0aCBtZWFuPTAgYW5kIHZhcmlhbmNlPTEKeTwtZitlcHNpbG9uCiNpbnN0YWxsLnBhY2thZ2VzKCJnZ3Bsb3QiKQojbGlicmFyeShnZ3Bsb3QyKQpwbG90KHQseSwgeGxhYj0iVGltZSBpbiBzZWNzIiwgeWxhYj0iRGlzdGFuY2UgaW4gbWV0dGVycyIpCmxpbmVzKHQsZixjb2w9MikKYGBgCmBgYHtyfQp0MjwtdF4yCmZpdDwtbG0oeX50K3QyKQpzdW1tYXJ5KGZpdCkKYGBgCgpXZSBuZWVkIGZpcnN0IGNvbnN0cnVjdCB0aGUgJFgkIHRoYXQgaGFzIGNvdmFyaWF0ZXMgYXMgY29sdW1uczoKYGBge3J9CnQ8LSBzZXEoMCwzLjQsbGVuPU4pCnQyPC10XjIKTjwtMjUgCmY8LTU2LjY3KzAqdC0wLjUqZyp0XnsyfSAKZXBzaWxvbjwtcm5vcm0oTiwwLDEpCnk8LWYrZXBzaWxvbgppbnRlcmNlcHQ8LW1hdHJpeCgxLE4sMSkKWDwtY2JpbmQoaW50ZXJjZXB0LHQsdDIpCmJldGFzPC1zb2x2ZSh0KFgpJSolWCklKiV0KFgpJSoleQpiZXRhcwpgYGAKCkV4ZXJjaXNlczoKU3VwcG9zZSB3ZSBhcmUgYW5hbHl6aW5nIGEgc2V0IG9mIDQgc2FtcGxlcy4gVGhlIGZpcnN0IHR3byBzYW1wbGVzIGFyZSBmcm9tIGEgdHJlYXRtZW50IGdyb3VwIEEgYW5kIHRoZSBzZWNvbmQgdHdvIHNhbXBsZXMgYXJlIGZyb20gYSB0cmVhdG1lbnQgZ3JvdXAgQi4gVGhpcyBkZXNpZ24gY2FuIGJlIHJlcHJlc2VudGVkIHdpdGggYSBtb2RlbCBtYXRyaXggbGlrZSBzbzoKYGBge3J9ClggPC0gbWF0cml4KGMoMSwxLDEsMSwwLDAsMSwxKSxucm93PTQpCnJvd25hbWVzKFgpIDwtIGMoImEiLCJhIiwiYiIsImIiKQpYCmBgYApTdXBwb3NlIHRoYXQgdGhlIGZpdHRlZCBwYXJhbWV0ZXJzIGZvciBhIGxpbmVhciBtb2RlbCBnaXZlIHVzOgpgYGB7cn0KYmV0YSA8LSBjKDUsIDIpCmJldGEKYGBgClVzZSB0aGUgbWF0cml4IG11bHRpcGxpY2F0aW9uIG9wZXJhdG9yLCAlKiUsIGluIFIgdG8gYW5zd2VyIHRoZSBmb2xsb3dpbmcgcXVlc3Rpb25zOgoKTWF0cml4IEFsZ2VicmEgRXhhbXBsZXMgRXhlcmNpc2VzICMxCgpXaGF0IGlzIHRoZSBmaXR0ZWQgdmFsdWUgZm9yIHRoZSBBIHNhbXBsZXM/IChUaGUgZml0dGVkIFkgdmFsdWVzLikKCmBgYHtyfQpZPC1YJSolYmV0YQpZWzE6MixdCmBgYApNYXRyaXggQWxnZWJyYSBFeGFtcGxlcyBFeGVyY2lzZXMgIzIKV2hhdCBpcyB0aGUgZml0dGVkIHZhbHVlIGZvciB0aGUgQiBzYW1wbGVzPyAoVGhlIGZpdHRlZCBZIHZhbHVlcy4pCmBgYHtyfQpZWzM6NCxdCmBgYAoKSW5mZXJlbmNlIFJldmlldyBFeGVyY2lzZXMgIzEKV2UgaGF2ZSBzaG93biBob3cgdG8gZmluZCB0aGUgbGVhc3Qgc3F1YXJlcyBlc3RpbWF0ZXMgd2l0aCBtYXRyaXggYWxnZWJyYS4gVGhlc2UgZXN0aW1hdGVzIGFyZSByYW5kb20gdmFyaWFibGVzIGFzIHRoZXkgYXJlIGxpbmVhciBjb21iaW5hdGlvbnMgb2YgdGhlIGRhdGEuIEZvciB0aGVzZSBlc3RpbWF0ZXMgdG8gYmUgdXNlZnVsIHdlIGFsc28gbmVlZCB0byBjb21wdXRlIHRoZSBzdGFuZGFyZCBlcnJvcnMuCgpIZXJlIHdlIHJldmlldyBzdGFuZGFyZCBlcnJvcnMgaW4gdGhlIGNvbnRleHQgb2YgbGluZWFyIG1vZGVscy4KCkl0IGlzIHVzZWZ1bCB0byB0aGluayBhYm91dCB3aGVyZSByYW5kb21uZXNzIGNvbWVzIGZyb20uIEluIG91ciBmYWxsaW5nIG9iamVjdCBleGFtcGxlLCByYW5kb21uZXNzIHdhcyBpbnRyb2R1Y2VkIHRocm91Z2ggbWVhc3VyZW1lbnQgZXJyb3JzLiBFdmVyeSB0aW1lIHdlIHJlcnVuIHRoZSBleHBlcmltZW50IGEgbmV3IHNldCBvZiBtZWFzdXJlbWVudCBlcnJvcnMgd2lsbCBiZSBtYWRlIHdoaWNoIGltcGxpZXMgb3VyIGRhdGEgd2lsbCBiZSByYW5kb20uIFRoaXMgaW1wbGllcyB0aGF0IG91ciBlc3RpbWF0ZSBvZiwgZm9yIGV4YW1wbGUsIHRoZSBncmF2aXRhdGlvbmFsIGNvbnN0YW50IHdpbGwgY2hhbmdlLiBUaGUgY29uc3RhbnQgaXMgZml4ZWQsIGJ1dCBvdXIgZXN0aW1hdGVzIGFyZSBub3QuIFRvIHNlZSB0aGlzIHdlIGNhbiBydW4gYSBNb250ZSBDYXJsbyBzaW11bGF0aW9uLiBTcGVjaWZpY2FsbHkgd2Ugd2lsbCBnZW5lcmF0ZSB0aGUgZGF0YSByZXBlYXRlZGx5IGFuZCBjb21wdXRlIHRoZSBlc3RpbWF0ZSBmb3IgdGhlIHF1YWRyYXRpYyB0ZXJtIGVhY2ggdGltZS4KCmBgYHtyfQpnIDwtIDkuOCAjIyBtZXRlcnMgcGVyIHNlY29uZApoLjAgPC0gNTYuNjcKdi4wIDwtIDAKTiA8LSAyNQp0dCA8LSBzZXEoMCwzLjQsbGVuPU4pICMjdGltZSBpbiBzZWNzLCB0IGlzIGEgYmFzZSBmdW5jdGlvbgp5IDwtIGguMCArIHYuMCAqdHQgIC0gMC41KiBnKnR0XjIgKyBybm9ybShOLHNkPTEpCmBgYAoKTm93IHdlIGFjdCBhcyBpZiB3ZSBkaWRuJ3Qga25vdyAkaC4wJCwgJHYuMCQgYW5kICQtMC41KmckIGFuZCB1c2UgcmVncmVzc2lvbiB0byBlc3RpbWF0ZSB0aGVzZS4gV2UgY2FuIHJld3JpdGUgdGhlIG1vZGVsIGFzICR5ID0gXGJldGFfezB9ICsgXGJldGFfezF9dCArIFxiZXRhX3syfSB0XjIgKyBcdmFyZXBzaWxvbiQgYW5kIG9idGFpbiB0aGUgTFNFIHdlIGhhdmUgdXNlZCBpbiB0aGlzIGNsYXNzLiBOb3RlIHRoYXQgJGcgPSAtMlxiZXRhX3syfSQuClRvIG9idGFpbiB0aGUgTFNFIGluIFIgd2UgY291bGQgd3JpdGU6CmBgYHtyfQpYIDwtIGNiaW5kKDEsdHQsdHReMikKQSA8LSBzb2x2ZSh0KFgpJSolWCklKiV0KFgpCmBgYApHaXZlbiBob3cgd2UgaGF2ZSBkZWZpbmVkIEEsIHdoaWNoIG9mIHRoZSBmb2xsb3dpbmcgaXMgdGhlIExTRSBvZiBnLCB0aGUgYWNjZWxlcmF0aW9uIGR1ZSB0byBncmF2aXR5PwpgYGB7cn0KYmV0YXM8LUElKiV5Ci0yKmJldGFzWzNdCmBgYApJbmZlcmVuY2UgUmV2aWV3IEV4ZXJjaXNlcyAjMgpJbiB0aGUgbGluZXMgb2YgY29kZSBhYm92ZSwgdGhlcmUgd2FzIGEgY2FsbCB0byBhIHJhbmRvbSBmdW5jdGlvbiBybm9ybSgpLiBUaGlzIG1lYW5zIHRoYXQgZWFjaCB0aW1lIHRoZSBsaW5lcyBvZiBjb2RlIGFib3ZlIGFyZSByZXBlYXRlZCwgdGhlIGVzdGltYXRlIG9mICRnJCB3aWxsIGJlIGRpZmZlcmVudC4KClNldCB0aGUgc2VlZCB0byAxLCB0aGVuIHVzZSB0aGUgY29kZSBhYm92ZSBpbiBjb25qdW5jdGlvbiB3aXRoIHRoZSBmdW5jdGlvbiByZXBsaWNhdGUoKSB0byBnZW5lcmF0ZSAxMDAsMDAwIE1vbnRlIENhcmxvIHNpbXVsYXRlZCBkYXRhc2V0cy4gRm9yIGVhY2ggZGF0YXNldCBjb21wdXRlIGFuIGVzdGltYXRlIG9mIGcgKHJlbWVtYmVyIHRvIG11bHRpcGx5IGJ5IC0yKS4KCldoYXQgaXMgdGhlIHN0YW5kYXJkIGRldmlhdGlvbiBvZiB0aGlzIGVzdGltYXRlPzoKCiMjSW5mbyBQYXJlbnRoZXNpcwoKVG8gdXNlIE1vbnRlIENhcmxvIG1ldGhvZHMsIHlvdSBuZWVkIHRvIGJlIGFibGUgdG8gcmVwbGljYXRlIHNvbWUgcmFuZG9tIHByb2Nlc3MgbWFueSB0aW1lcy4gVGhlcmUgYXJlIHR3byBtYWluIHdheXMgdGhpcyBpcyBjb21tb25seSBkb25lOiBlaXRoZXIgd2l0aCByZXBsaWNhdGUoKSBvciB3aXRoIGZvcigpIGxvb3BzLgoKVGhlIHJlcGxpY2F0ZSgpIGZ1bmN0aW9uIGV4ZWN1dGVzIHNvbWUgZXhwcmVzc2lvbiBtYW55IHRpbWVzIGFuZCByZXR1cm5zIHRoZSBvdXRwdXQgZnJvbSBlYWNoIGV4ZWN1dGlvbi4gU2F5IHdlIGhhdmUgYSB2ZWN0b3IgeCwgd2hpY2ggcmVwcmVzZW50cyAzMCBvYnNlcnZhdGlvbnMgb2YgZmlzaCBsZW5ndGggKG1tKToKYGBge3J9CnggPC0gcm5vcm0oMzAsIDUwMCwgMzApCmBgYApXZSB3aXNoIHRvIGJ1aWxkIHRoZSBzYW1wbGluZyBkaXN0cmlidXRpb24gb2YgdGhlIG1lYW4gbGVuZ3RoIOKAnGJ5IGhhbmTigJ0uIFdlIGNhbiBzYW1wbGUgcmFuZG9tbHkgZnJvbSBpdCwgY2FsY3VsYXRlIHRoZSBtZWFuLCB0aGVuIHJlcGVhdCB0aGlzIHByb2Nlc3MgbWFueSB0aW1lczoKYGBge3J9Cm1lYW5zIDwtIHJlcGxpY2F0ZShuID0gMTAwMCwgZXhwciA9IHsKICB4X2kgPSBzYW1wbGUoeCwgbGVuZ3RoKHgpLCByZXBsYWNlID0gVCkKICBtZWFuKHhfaSkKfSkKYGBgCklmIHdlIHRha2UgbWVhbihtZWFucykgYW5kIHNkKG1lYW5zKSwgdGhhdCBzaG91bGQgYmUgdmVyeSBzaW1pbGFyIHRvIG1lYW4oeCkgYW5kIHNlKHgpLiBDcmVhdGUgdGhlIHNlKCkgZnVuY3Rpb24gIGFuZCBwcm92ZSB0aGlzIHRvIHlvdXJzZWxmOgpgYGB7cn0Kc2UgPC0gZnVuY3Rpb24oeCkgc2QoeCkvc3FydChsZW5ndGgoeCkpCm1lYW4obWVhbnMpOyBtZWFuKHgpCmBgYApgYGB7cn0Kc2QobWVhbnMpOyBzZSh4KQpgYGAKCiMjLgoKYGBge3J9CnNldC5zZWVkKDEpCkIgPC0gMTAwMDAwCmcgPC0gOS44ICMjIG1ldGVycyBwZXIgc2Vjb25kCm4gPC0gMjUKdHQgPC0gc2VxKDAsMy40LGxlbj1uKSAjI3RpbWUgaW4gc2VjcywgdCBpcyBhIGJhc2UgZnVuY3Rpb24KWCA8LSBjYmluZCgxLHR0LHR0XjIpCkEgPC0gc29sdmUoY3Jvc3Nwcm9kKFgpKSUqJXQoWCkKCmJldGFoYXQgPC0gcmVwbGljYXRlKEIsewogIHkgPSA1Ni42NyAgLSAwLjUqZyp0dF4yICsgcm5vcm0obixzZD0xKQogIGJldGFoYXRzID0gLTIqQSUqJXkKICByZXR1cm4oYmV0YWhhdHNbM10pCn0pCnNxcnQobWVhbiggKGJldGFoYXQtbWVhbihiZXRhaGF0KSApXjIpKQoKYGBgCgoKCgoKCgoK