In this lesson we’re going to describe the language of linear model which is called “linear algebra”. Later, we’ll see how this notation is useful to describe models and perform computation on these models, to code them up, to describe them in papers.

VECTORS In R, write down a series of numbers as vectors:

#install.packages("UsingR")
#library(UsingR)
data("father.son",package="UsingR")
summary(father.son)
    fheight         sheight     
 Min.   :59.01   Min.   :58.51  
 1st Qu.:65.79   1st Qu.:66.93  
 Median :67.77   Median :68.62  
 Mean   :67.69   Mean   :68.68  
 3rd Qu.:69.60   3rd Qu.:70.47  
 Max.   :75.43   Max.   :78.36  
x<-father.son$fheight #from the dataset father.son we create the vector x that is the height of the sons.
length(x) #we can count the entrees of the vector with the function length().
[1] 1078

In mathematical notation a vector can be expressed as follows:

\[Y=\begin{pmatrix}y_{1}\\ y_{2} \\ \vdots\\y_{n}\end{pmatrix}\]

capital \(Y\) represents the vector. And it holds in the \(n\) observations \(y_{1}\) through \(y_{n}\). We can rewrite these vectors for the predictor of covariates as well.

So in the example of dropping object we showed in the intro section this would be the time on \(X_{1}\) and then time squared in \(X_{2}\).

\[\begin{align*}X_{1}&=\begin{pmatrix}x_{1,1}\\ x_{2,1} \\ \vdots\\x_{N,1}\end{pmatrix} &\text{and}& & X_{2}&=\begin{pmatrix}x_{1,2}\\ x_{2,2} \\ \vdots\\x_{N,2}\end{pmatrix}\end{align*}\]

It is useful to put these vectors join them together into what we call matrices. Matrices, we can thing of them as a series of vectors one next to each other.So here we can see a matrix that has \(n\) rows and 2 columns:

\[X=[X_{1}X_{2}]=\begin{pmatrix}x_{1,1}& x_{1,2}\\ x_{2,1} & x_{2,2} \\ \vdots & \vdots\\x_{N,1} &x_{N,2}\end{pmatrix}\]

The number of rows and columns define its dimensions. This is an \(N\times 2\) matrix.

n<- 25
t<- seq(0,3.4,len=n) #time in secs, t is a base function. function seq()  generates a sequence from 0 to 3.4
X<- cbind(X1=t,X2=t^2) #this functions combine the time variable and the time squared variable
X
             X1          X2
 [1,] 0.0000000  0.00000000
 [2,] 0.1416667  0.02006944
 [3,] 0.2833333  0.08027778
 [4,] 0.4250000  0.18062500
 [5,] 0.5666667  0.32111111
 [6,] 0.7083333  0.50173611
 [7,] 0.8500000  0.72250000
 [8,] 0.9916667  0.98340278
 [9,] 1.1333333  1.28444444
[10,] 1.2750000  1.62562500
[11,] 1.4166667  2.00694444
[12,] 1.5583333  2.42840278
[13,] 1.7000000  2.89000000
[14,] 1.8416667  3.39173611
[15,] 1.9833333  3.93361111
[16,] 2.1250000  4.51562500
[17,] 2.2666667  5.13777778
[18,] 2.4083333  5.80006944
[19,] 2.5500000  6.50250000
[20,] 2.6916667  7.24506944
[21,] 2.8333333  8.02777778
[22,] 2.9750000  8.85062500
[23,] 3.1166667  9.71361111
[24,] 3.2583333 10.61673611
[25,] 3.4000000 11.56000000
dim(X)
[1] 25  2

Matrices can have any number of rows and columns, so in general we write \(X\) to represent any matrix. For the general linear model we use:

\[X=\begin{pmatrix}x_{1,1}&...&x_{1,p}\\ x_{2,1}&...&x_{2,p}\\ \vdots &\vdots & \vdots\\ x_{N,1}&...&x_{N,p} \end{pmatrix}\]

\(X\) is an \(N\times p\) matrix.

#In R we have vectors and matrices. You can create your own vectors with the function c().
vector<-c(1,2,3)
#Vectors are also the output of many functions such as:
rnorm(10)
#You can turn vectors into matrices using functions such as rbind(), cbind() or matrix().

Matrix Notation Exercises #1:

Create the matrix from the vector 1:1000 like this:

#What is the entry in row 25, column 3?
X[25,3]
[1] 225

Matrix Notation Exercises #2

Using the function cbind(), create a 10 x 5 matrix with first column x=1:10. Then use 2x, 3x, 4x and 5x respectively in columns 2 through 5.

M[7,1]+M[7,2]+M[7,3]+M[7,4]+M[7,5]
[1] 105
sum(M[7,])
[1] 105

Before we go into the use of matrix algebra to solve and operate on linear models, we have to learn a few operations. Linear algebra was developed to solve a system of equations, like the one I’m showing here. Solve this system of equations: \[\begin{align}a+b+c&=6\\ 3a-2b+c&=2\\ 2a+b-c&=1\end{align}\] Matrix algebra notation:

\[\begin{pmatrix}1 & 1 & 1\\ 3 & -2 & 1\\2 & 1 & -1\end{pmatrix}\begin{pmatrix}a\\b\\c\end{pmatrix}=\begin{pmatrix}6\\2\\1\end{pmatrix}\Longrightarrow\begin{pmatrix}a\\b\\c\end{pmatrix}=\begin{pmatrix}1 & 1 & 1\\ 3 & -2 & 1\\2 & 1 & -1\end{pmatrix}^{-1}\begin{pmatrix}6\\2\\1\end{pmatrix}\] it gives us the general solution to any system of equations.

Before going and solve systems of equations we’ll remind some basic operations of matrices:

If \(a\in\mathbb{R}\) is a scalar and \(X\) is a \(N\times N\) matrix, then \[aX=\begin{pmatrix}ax_{1,1}&...&ax_{1,N}\\ \vdots & \ddots & \vdots\\ ax_{N,1}&...&ax_{N,N}\end{pmatrix}\]

a<-2
X<-matrix(1:20,4,5)
mult<-a*X
print(X)
     [,1] [,2] [,3] [,4] [,5]
[1,]    1    5    9   13   17
[2,]    2    6   10   14   18
[3,]    3    7   11   15   19
[4,]    4    8   12   16   20
print(mult)
     [,1] [,2] [,3] [,4] [,5]
[1,]    2   10   18   26   34
[2,]    4   12   20   28   36
[3,]    6   14   22   30   38
[4,]    8   16   24   32   40

The transpose is an operation that simply change the columns to rows: \[\begin{align}X=\begin{pmatrix}x_{1,1}&...&x_{1,p}\\ \vdots & \ddots & \vdots\\ x_{N,1}&...&x_{N,p}\end{pmatrix} & & &\Longleftrightarrow& X^{T}=\begin{pmatrix}x_{1,1} & ... & x_{N,1}\\ \vdots & \ddots &\vdots\\x_{1,p}&...&x_{N,p} \end{pmatrix} \end{align}\]

To do so, we only take the columns of the matrix X and make them rows.

X<-matrix(1:24,6,4)
print(X)
     [,1] [,2] [,3] [,4]
[1,]    1    7   13   19
[2,]    2    8   14   20
[3,]    3    9   15   21
[4,]    4   10   16   22
[5,]    5   11   17   23
[6,]    6   12   18   24
t(X)
     [,1] [,2] [,3] [,4] [,5] [,6]
[1,]    1    2    3    4    5    6
[2,]    7    8    9   10   11   12
[3,]   13   14   15   16   17   18
[4,]   19   20   21   22   23   24

Let’s back to the system of equations we described before: \[\begin{align}a+b+c&=6\\ 3a-2b+c&=2\\ 2a+b-c&=1\end{align}\] - Matrix multiplication The multiplication of the matrix works as follows: Each entry in the matrix rows are multiplied by each entry in the second matrix column: \[\begin{pmatrix}1 & 1 & 1\\ 3 & -2 & 1\\2 & 1 & -1\end{pmatrix}\begin{pmatrix}a\\b\\c\end{pmatrix}=\begin{pmatrix}a+b+c\\3a-2b+c\\2a+b-c\end{pmatrix}=\begin{pmatrix}6\\ 2\\ 1\end{pmatrix}\]

multiplication
     [,1]
[1,]    6
[2,]    6
[3,]    7

For now let’s define general matrix multiplication:

\[\begin{align}AX&=\begin{pmatrix}a_{11} & ... & a_{1,N}\\ \vdots & \ddots & \vdots\\ a_{M,1} & ... & a_{M,N}\end{pmatrix} \begin{pmatrix}x_{1,1} &...& x_{1,p}\\ \vdots &\ddots & \vdots\\ x_{N,1}&...&x_{N,p}\end{pmatrix}\\ \\ &=\begin{pmatrix}\sum_{i=1}^{N}a_{1,i}x_{i,1} &...& \sum_{i=1}^{N}a_{1,i}x_{i,p}\\ &\vdots&\\ \sum_{i=1} ^{N}a_{M,i}x_{i,1} &...& \sum_{i=1}^{N}a_{M,i}x_{i,p} \end{pmatrix}\end{align}\] Note that the number of columns of first must match with the number of rows of the second.

diag(5) #function diag(dimension) generates an identity matrix of any dimension. Note that the identity matrix must be square

-The Inverse

The inverse is very useful. If you remember the system of equations that we showed before, the solution can be written as the inverse of a matrix times a vector of numbers. That was going to give us a solution to what a, b, and c are. Some square matrices have inverses, not all of them. The inverse of matrix \(X\) is denoted by \(X^{-1}\). And \(XX^{-1}=I\).

Let’s back to our system of equations:

\[\begin{align}a+b+c&=6\\ 3a-2b+c&=2\\ 2a+b-c&=1\end{align}\] The solution requires to invert the matrix: \[\begin{pmatrix}a\\b\\c\end{pmatrix}=\begin{pmatrix}1 & 1 & 1\\ 3 & -2 & 1\\2 & 1 & -1\end{pmatrix}^{-1}\begin{pmatrix}6\\2\\1\end{pmatrix}\]

X
     [,1] [,2] [,3]
[1,]    1    1    1
[2,]    3   -2    1
[3,]    2    1   -1
Y<-matrix(c(6,2,1),3,1)
Y
     [,1]
[1,]    6
[2,]    2
[3,]    1
solve(X)%*%Y
     [,1]
[1,]    1
[2,]    2
[3,]    3

Matrix Operation Exercises #2

Solve the following system of equations using R:

\[\begin{align} 3a+4b-5c+d&=10\\2a+2b+2c-d&=5\\a-b+5c-5d&=7\\5a+d&=4\end{align}\] \[\begin{align}\begin{pmatrix} 3&4&-5&1\\ 2&2&2&-1\\ 1&-1&5&-5\\5&0&0&1\end{pmatrix}\begin{pmatrix}a\\b\\c\\d\end{pmatrix}&=\begin{pmatrix}10\\5\\7\\4\end{pmatrix}\\ \\ \Leftrightarrow \underbrace{\begin{pmatrix} 3&4&-5&1\\ 2&2&2&-1\\ 1&-1&5&-5\\5&0&0&1\end{pmatrix}^{-1}}_{A^{-1}}\underbrace{\begin{pmatrix}10\\5\\7\\4\end{pmatrix}}_{B}&=\begin{pmatrix}a\\b\\c\\d\end{pmatrix}\end{align}\]

A<-matrix(c(3,2,1,5,4,2,-1,0,-5,2,5,0,1,-1,-5,1),4,4)
A
     [,1] [,2] [,3] [,4]
[1,]    3    4   -5    1
[2,]    2    2    2   -1
[3,]    1   -1    5   -5
[4,]    5    0    0    1
B<-matrix(c(10,5,7,4),4,1)
X<-solve(A)%*%B
name<-c("a","b","c","d")
X<-data.frame(name,X)
X
a <- matrix(1:12, nrow=4)
b <- matrix(1:15, nrow=3)

Matrix Operation Exercises #3

What is the value in the 3rd row and the 2nd column of the matrix product of \(a\) and \(b\)?

N<-a%*%b
N
     [,1] [,2] [,3] [,4] [,5]
[1,]   38   83  128  173  218
[2,]   44   98  152  206  260
[3,]   50  113  176  239  302
[4,]   56  128  200  272  344
N[3,2]
[1] 113

Matrix Operation Exercises #4

Multiply the 3rd row of \(a\) with the 2nd column of \(b\), using the element-wise vector multiplication with *.

What is the sum of the elements in the resulting vector?

sum(a[3,]*b[,2])
[1] 113
LS0tCnRpdGxlOiAiTUFUUklYIEFMR0VCUkEiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCkluIHRoaXMgbGVzc29uIHdlJ3JlIGdvaW5nIHRvIGRlc2NyaWJlIHRoZSBsYW5ndWFnZSBvZiBsaW5lYXIgbW9kZWwgd2hpY2ggaXMgY2FsbGVkICJsaW5lYXIgYWxnZWJyYSIuIExhdGVyLCB3ZSdsbCBzZWUgaG93IHRoaXMgbm90YXRpb24gaXMgdXNlZnVsIHRvIGRlc2NyaWJlIG1vZGVscyBhbmQgcGVyZm9ybSBjb21wdXRhdGlvbiBvbiB0aGVzZSBtb2RlbHMsIHRvIGNvZGUgdGhlbSB1cCwgdG8gZGVzY3JpYmUgdGhlbSBpbiBwYXBlcnMuCgpWRUNUT1JTCkluIFIsIHdyaXRlIGRvd24gYSBzZXJpZXMgb2YgbnVtYmVycyBhcyB2ZWN0b3JzOgpgYGB7cn0KI2luc3RhbGwucGFja2FnZXMoIlVzaW5nUiIpCiNsaWJyYXJ5KFVzaW5nUikKZGF0YSgiZmF0aGVyLnNvbiIscGFja2FnZT0iVXNpbmdSIikKc3VtbWFyeShmYXRoZXIuc29uKQp4PC1mYXRoZXIuc29uJGZoZWlnaHQgI2Zyb20gdGhlIGRhdGFzZXQgZmF0aGVyLnNvbiB3ZSBjcmVhdGUgdGhlIHZlY3RvciB4IHRoYXQgaXMgdGhlIGhlaWdodCBvZiB0aGUgc29ucy4KbGVuZ3RoKHgpICN3ZSBjYW4gY291bnQgdGhlIGVudHJpZXMgb2YgdGhlIHZlY3RvciB3aXRoIHRoZSBmdW5jdGlvbiBsZW5ndGgoKS4KYGBgCkluIG1hdGhlbWF0aWNhbCBub3RhdGlvbiBhIHZlY3RvciBjYW4gYmUgZXhwcmVzc2VkIGFzIGZvbGxvd3M6CgokJFk9XGJlZ2lue3BtYXRyaXh9eV97MX1cXCB5X3syfSBcXCBcdmRvdHNcXHlfe259XGVuZHtwbWF0cml4fSQkCgpjYXBpdGFsICRZJCByZXByZXNlbnRzIHRoZSB2ZWN0b3IuIEFuZCBpdCBob2xkcyBpbiB0aGUgJG4kIG9ic2VydmF0aW9ucyAkeV97MX0kIHRocm91Z2ggJHlfe259JC4gV2UgY2FuIHJld3JpdGUgdGhlc2UgdmVjdG9ycyBmb3IgdGhlIHByZWRpY3RvciBvZiBjb3ZhcmlhdGVzIGFzIHdlbGwuIAoKU28gaW4gdGhlIGV4YW1wbGUgb2YgZHJvcHBpbmcgb2JqZWN0IHdlIHNob3dlZCBpbiB0aGUgaW50cm8gc2VjdGlvbiB0aGlzIHdvdWxkIGJlIHRoZSB0aW1lIG9uICRYX3sxfSQgYW5kIHRoZW4gdGltZSBzcXVhcmVkIGluICRYX3syfSQuCgokJFxiZWdpbnthbGlnbip9WF97MX0mPVxiZWdpbntwbWF0cml4fXhfezEsMX1cXCB4X3syLDF9IFxcIFx2ZG90c1xceF97TiwxfVxlbmR7cG1hdHJpeH0gJlx0ZXh0e2FuZH0mICYgWF97Mn0mPVxiZWdpbntwbWF0cml4fXhfezEsMn1cXCB4X3syLDJ9IFxcIFx2ZG90c1xceF97TiwyfVxlbmR7cG1hdHJpeH1cZW5ke2FsaWduKn0kJAoKSXQgaXMgdXNlZnVsIHRvIHB1dCB0aGVzZSB2ZWN0b3JzIGpvaW4gdGhlbSB0b2dldGhlciBpbnRvIHdoYXQgd2UgY2FsbCBtYXRyaWNlcy4gTWF0cmljZXMsIHdlIGNhbiB0aGluZyBvZiB0aGVtIGFzIGEgc2VyaWVzIG9mIHZlY3RvcnMgb25lIG5leHQgdG8gZWFjaCBvdGhlci5TbyBoZXJlIHdlIGNhbiBzZWUgYSBtYXRyaXggdGhhdCBoYXMgJG4kIHJvd3MgYW5kIDIgY29sdW1uczoKCiQkWD1bWF97MX1YX3syfV09XGJlZ2lue3BtYXRyaXh9eF97MSwxfSYgeF97MSwyfVxcIHhfezIsMX0gJiB4X3syLDJ9IFxcIFx2ZG90cyAmIFx2ZG90c1xceF97TiwxfSAmeF97TiwyfVxlbmR7cG1hdHJpeH0kJAoKVGhlIG51bWJlciBvZiByb3dzIGFuZCBjb2x1bW5zIGRlZmluZSBpdHMgZGltZW5zaW9ucy4gVGhpcyBpcyBhbiAkTlx0aW1lcyAyJCBtYXRyaXguCgpgYGB7cn0KbjwtIDI1CnQ8LSBzZXEoMCwzLjQsbGVuPW4pICN0aW1lIGluIHNlY3MsIHQgaXMgYSBiYXNlIGZ1bmN0aW9uLiBmdW5jdGlvbiBzZXEoKSAgZ2VuZXJhdGVzIGEgc2VxdWVuY2UgZnJvbSAwIHRvIDMuNApYPC0gY2JpbmQoWDE9dCxYMj10XjIpICN0aGlzIGZ1bmN0aW9ucyBjb21iaW5lIHRoZSB0aW1lIHZhcmlhYmxlIGFuZCB0aGUgdGltZSBzcXVhcmVkIHZhcmlhYmxlClgKZGltKFgpCmBgYAoKTWF0cmljZXMgY2FuIGhhdmUgYW55IG51bWJlciBvZiByb3dzIGFuZCBjb2x1bW5zLCBzbyBpbiBnZW5lcmFsIHdlIHdyaXRlICRYJCB0byByZXByZXNlbnQgYW55IG1hdHJpeC4gRm9yIHRoZSBnZW5lcmFsIGxpbmVhciBtb2RlbCB3ZSB1c2U6CgokJFg9XGJlZ2lue3BtYXRyaXh9eF97MSwxfSYuLi4meF97MSxwfVxcIHhfezIsMX0mLi4uJnhfezIscH1cXCBcdmRvdHMgJlx2ZG90cyAmIFx2ZG90c1xcIHhfe04sMX0mLi4uJnhfe04scH0gXGVuZHtwbWF0cml4fSQkCgokWCQgaXMgYW4gJE5cdGltZXMgcCQgbWF0cml4LgoKYGBge3J9CiNJbiBSIHdlIGhhdmUgdmVjdG9ycyBhbmQgbWF0cmljZXMuIFlvdSBjYW4gY3JlYXRlIHlvdXIgb3duIHZlY3RvcnMgd2l0aCB0aGUgZnVuY3Rpb24gYygpLgp2ZWN0b3I8LWMoMSwyLDMpCiNWZWN0b3JzIGFyZSBhbHNvIHRoZSBvdXRwdXQgb2YgbWFueSBmdW5jdGlvbnMgc3VjaCBhczoKcm5vcm0oMTApCiNZb3UgY2FuIHR1cm4gdmVjdG9ycyBpbnRvIG1hdHJpY2VzIHVzaW5nIGZ1bmN0aW9ucyBzdWNoIGFzIHJiaW5kKCksIGNiaW5kKCkgb3IgbWF0cml4KCkuCmBgYAoKTWF0cml4IE5vdGF0aW9uIEV4ZXJjaXNlcyAjMToKCkNyZWF0ZSB0aGUgbWF0cml4IGZyb20gdGhlIHZlY3RvciAxOjEwMDAgbGlrZSB0aGlzOgpgYGB7cn0KWCA9IG1hdHJpeCgxOjEwMDAsMTAwLDEwKSAjbnVtYmVycyBmcm9tIDEgdGhyb3VnaCAxMDAwIGluIDEwMCAgcm93cyBhbmQgMTAgY29sdW1ucwojV2hhdCBpcyB0aGUgZW50cnkgaW4gcm93IDI1LCBjb2x1bW4gMz8KWFsyNSwzXQpgYGAKTWF0cml4IE5vdGF0aW9uIEV4ZXJjaXNlcyAjMgoKVXNpbmcgdGhlIGZ1bmN0aW9uIGNiaW5kKCksIGNyZWF0ZSBhIDEwIHggNSBtYXRyaXggd2l0aCBmaXJzdCBjb2x1bW4geD0xOjEwLiBUaGVuIHVzZSAyKngsIDMqeCwgNCp4IGFuZCA1KnggcmVzcGVjdGl2ZWx5IGluIGNvbHVtbnMgMiB0aHJvdWdoIDUuCmBgYHtyfQp4PC1tYXRyaXgoMToxMCwxMCwxKQphPC0yKngKYjwtMyp4CmM8LTQqeApkPC01KngKTTwtY2JpbmQoeCxhLGIsYyxkKQpNWzcsMV0rTVs3LDJdK01bNywzXStNWzcsNF0rTVs3LDVdCnN1bShNWzcsXSkgI3N1bSgpCmBgYAoKQmVmb3JlIHdlIGdvIGludG8gdGhlIHVzZSBvZiBtYXRyaXggYWxnZWJyYSB0byBzb2x2ZSBhbmQgb3BlcmF0ZSBvbiBsaW5lYXIgbW9kZWxzLCB3ZSBoYXZlIHRvIGxlYXJuIGEgZmV3IG9wZXJhdGlvbnMuIExpbmVhciBhbGdlYnJhIHdhcyBkZXZlbG9wZWQgdG8gc29sdmUgYSBzeXN0ZW0gb2YgZXF1YXRpb25zLCBsaWtlIHRoZSBvbmUgSSdtIHNob3dpbmcgaGVyZS4KU29sdmUgdGhpcyBzeXN0ZW0gb2YgZXF1YXRpb25zOgokJFxiZWdpbnthbGlnbn1hK2IrYyY9NlxcIDNhLTJiK2MmPTJcXCAyYStiLWMmPTFcZW5ke2FsaWdufSQkCk1hdHJpeCBhbGdlYnJhIG5vdGF0aW9uOgoKJCRcYmVnaW57cG1hdHJpeH0xICYgMSAmIDFcXCAzICYgLTIgJiAxXFwyICYgMSAmIC0xXGVuZHtwbWF0cml4fVxiZWdpbntwbWF0cml4fWFcXGJcXGNcZW5ke3BtYXRyaXh9PVxiZWdpbntwbWF0cml4fTZcXDJcXDFcZW5ke3BtYXRyaXh9XExvbmdyaWdodGFycm93XGJlZ2lue3BtYXRyaXh9YVxcYlxcY1xlbmR7cG1hdHJpeH09XGJlZ2lue3BtYXRyaXh9MSAmIDEgJiAxXFwgMyAmIC0yICYgMVxcMiAmIDEgJiAtMVxlbmR7cG1hdHJpeH1eey0xfVxiZWdpbntwbWF0cml4fTZcXDJcXDFcZW5ke3BtYXRyaXh9JCQKaXQgZ2l2ZXMgdXMgdGhlIGdlbmVyYWwgc29sdXRpb24gdG8gYW55IHN5c3RlbSBvZiBlcXVhdGlvbnMuCgpCZWZvcmUgZ29pbmcgYW5kIHNvbHZlIHN5c3RlbXMgb2YgZXF1YXRpb25zIHdlJ2xsIHJlbWluZCBzb21lIGJhc2ljIG9wZXJhdGlvbnMgb2YgbWF0cmljZXM6CgotIE11bHRpcGx5aW5nIGJ5IHNjYWxhci4KCklmICRhXGluXG1hdGhiYntSfSQgaXMgYSBzY2FsYXIgYW5kICRYJCBpcyBhICROXHRpbWVzIE4kIG1hdHJpeCwgdGhlbgokJGFYPVxiZWdpbntwbWF0cml4fWF4X3sxLDF9Ji4uLiZheF97MSxOfVxcIFx2ZG90cyAmIFxkZG90cyAmIFx2ZG90c1xcIGF4X3tOLDF9Ji4uLiZheF97TixOfVxlbmR7cG1hdHJpeH0kJApgYGB7ciBTY2FsYXIgTXVsdH0KYTwtMgpYPC1tYXRyaXgoMToyMCw0LDUpCm11bHQ8LWEqWApwcmludChYKQpwcmludChtdWx0KQpgYGAKCi0gVGhlIFRyYW5zcG9zZS4KClRoZSB0cmFuc3Bvc2UgaXMgYW4gb3BlcmF0aW9uIHRoYXQgc2ltcGx5IGNoYW5nZSB0aGUgY29sdW1ucyB0byByb3dzOgokJFxiZWdpbnthbGlnbn1YPVxiZWdpbntwbWF0cml4fXhfezEsMX0mLi4uJnhfezEscH1cXCBcdmRvdHMgJiBcZGRvdHMgJiBcdmRvdHNcXCB4X3tOLDF9Ji4uLiZ4X3tOLHB9XGVuZHtwbWF0cml4fSAmICYgJlxMb25nbGVmdHJpZ2h0YXJyb3cmIFhee1R9PVxiZWdpbntwbWF0cml4fXhfezEsMX0gJiAuLi4gJiB4X3tOLDF9XFwgXHZkb3RzICYgXGRkb3RzICZcdmRvdHNcXHhfezEscH0mLi4uJnhfe04scH0gXGVuZHtwbWF0cml4fSBcZW5ke2FsaWdufSQkCgpUbyBkbyBzbywgd2Ugb25seSB0YWtlIHRoZSBjb2x1bW5zIG9mIHRoZSBtYXRyaXggWCBhbmQgbWFrZSB0aGVtIHJvd3MuCmBgYHtyfQpYPC1tYXRyaXgoMToyNCw2LDQpCnByaW50KFgpCnQoWCkgI3QoKSBmdW5jdGlvbiB0cmFuc3Bvc2VzIHRoZSBtYXRyaXgKYGBgCkxldCdzIGJhY2sgIHRvIHRoZSBzeXN0ZW0gb2YgZXF1YXRpb25zIHdlIGRlc2NyaWJlZCBiZWZvcmU6CiQkXGJlZ2lue2FsaWdufWErYitjJj02XFwgM2EtMmIrYyY9MlxcIDJhK2ItYyY9MVxlbmR7YWxpZ259JCQKLSBNYXRyaXggbXVsdGlwbGljYXRpb24KVGhlIG11bHRpcGxpY2F0aW9uIG9mIHRoZSBtYXRyaXggd29ya3MgYXMgZm9sbG93czoKRWFjaCBlbnRyeSBpbiB0aGUgbWF0cml4IHJvd3MgYXJlIG11bHRpcGxpZWQgYnkgZWFjaCBlbnRyeSBpbiB0aGUgc2Vjb25kIG1hdHJpeCBjb2x1bW46CiQkXGJlZ2lue3BtYXRyaXh9MSAmIDEgJiAxXFwgMyAmIC0yICYgMVxcMiAmIDEgJiAtMVxlbmR7cG1hdHJpeH1cYmVnaW57cG1hdHJpeH1hXFxiXFxjXGVuZHtwbWF0cml4fT1cYmVnaW57cG1hdHJpeH1hK2IrY1xcM2EtMmIrY1xcMmErYi1jXGVuZHtwbWF0cml4fT1cYmVnaW57cG1hdHJpeH02XFwgMlxcIDFcZW5ke3BtYXRyaXh9JCQKCmBgYHtyfQpYPC1tYXRyaXgoYygxLDMsMiwxLC0yLDEsMSwxLC0xKSwzLDMpICNub3RlIHRoYXQgdGhlIHZlY3RvciBjKCkgaGFzIDkgZW50cmllcywgYW5kIHdlIHJlYXJyYW5nZSBzdWNoIHZlY3RvciBpbiBhIDN4MyBtYXRyaXgKYmV0YTwtYygzLDIsMSkKbXVsdGlwbGljYXRpb249WCUqJWJldGEgIyUqJSBpcyB0aGUgbXVsdGlwbHkgb3BlcmF0b3IgZm9yIG1hdHJpY2VzLgptdWx0aXBsaWNhdGlvbiAjbm90ZSB0aGF0IHZlY3RvciBiZXRhPSgzLDIsMSkgbXVsdGlwbGllZCBieSBtYXRyaXggWCDiiaAgKDYsMiwxKS4gV2UgYXJlIGdvaW5nIHRvIHNvbHZlIHRoZSBzeXN0ZW0gaW4gb3RoZXIgY2h1bmsuCmBgYApGb3Igbm93IGxldCdzIGRlZmluZSBnZW5lcmFsIG1hdHJpeCBtdWx0aXBsaWNhdGlvbjoKCiQkXGJlZ2lue2FsaWdufUFYJj1cYmVnaW57cG1hdHJpeH1hX3sxMX0gJiAuLi4gJiBhX3sxLE59XFwgXHZkb3RzICYgXGRkb3RzICYgXHZkb3RzXFwgYV97TSwxfSAmIC4uLiAmIGFfe00sTn1cZW5ke3BtYXRyaXh9IFxiZWdpbntwbWF0cml4fXhfezEsMX0gJi4uLiYgeF97MSxwfVxcIFx2ZG90cyAmXGRkb3RzICYgXHZkb3RzXFwgeF97TiwxfSYuLi4meF97TixwfVxlbmR7cG1hdHJpeH1cXCBcXCAgJj1cYmVnaW57cG1hdHJpeH1cc3VtX3tpPTF9XntOfWFfezEsaX14X3tpLDF9ICYuLi4mIFxzdW1fe2k9MX1ee059YV97MSxpfXhfe2kscH1cXCAmXHZkb3RzJlxcIFxzdW1fe2k9MX0gXntOfWFfe00saX14X3tpLDF9ICYuLi4mIFxzdW1fe2k9MX1ee059YV97TSxpfXhfe2kscH0gXGVuZHtwbWF0cml4fVxlbmR7YWxpZ259JCQKTm90ZSB0aGF0IHRoZSBudW1iZXIgb2YgY29sdW1ucyBvZiBmaXJzdCBtdXN0IG1hdGNoIHdpdGggdGhlIG51bWJlciBvZiByb3dzIG9mIHRoZSBzZWNvbmQuCgotIElkZW50aXR5IE1hdHJpeApUaGUgaWRlbnRpdHkgbWF0cml4ICgkSSQpaGFzIHRoZSBwcm9wZXJ0eSB0aGF0ICRBST1BJCwgaXQgaGFzIHRoaXMgZm9ybToKJCRJPVxiZWdpbntwbWF0cml4fTEmMCYwJjAmLi4uJjAmMFxcMCYxJjAmMCYuLi4mMCYwXFwgMCYwJjEmMCYuLi4mMCYwXFwgXHZkb3RzJlx2ZG90cyZcdmRvdHMmXHZkb3RzJlxkZG90cyZcdmRvdHMmXHZkb3RzXFwwJjAmMCYwJi4uLiYxJjBcXDAmMCYwJjAmLi4uJjAmMVxlbmR7cG1hdHJpeH0kJApgYGB7ciBJZGVudGl0eSBNYXRyaXh9CmRpYWcoNSkgI2Z1bmN0aW9uIGRpYWcoZGltZW5zaW9uKSBnZW5lcmF0ZXMgYW4gaWRlbnRpdHkgbWF0cml4IG9mIGFueSBkaW1lbnNpb24uIE5vdGUgdGhhdCB0aGUgaWRlbnRpdHkgbWF0cml4IG11c3QgYmUgc3F1YXJlCmBgYAoKLVRoZSBJbnZlcnNlCgpUaGUgaW52ZXJzZSBpcyB2ZXJ5IHVzZWZ1bC4gSWYgeW91IHJlbWVtYmVyIHRoZSBzeXN0ZW0gb2YgZXF1YXRpb25zIHRoYXQgd2Ugc2hvd2VkIGJlZm9yZSwgdGhlIHNvbHV0aW9uIGNhbiBiZSB3cml0dGVuIGFzIHRoZSBpbnZlcnNlIG9mIGEgbWF0cml4IHRpbWVzIGEgdmVjdG9yIG9mIG51bWJlcnMuIFRoYXQgd2FzIGdvaW5nIHRvIGdpdmUgdXMgYSBzb2x1dGlvbiB0byB3aGF0IGEsIGIsIGFuZCBjIGFyZS4KU29tZSBzcXVhcmUgbWF0cmljZXMgaGF2ZSBpbnZlcnNlcywgbm90IGFsbCBvZiB0aGVtLiBUaGUgaW52ZXJzZSBvZiBtYXRyaXggJFgkIGlzIGRlbm90ZWQgYnkgJFheey0xfSQuIEFuZCAkWFheey0xfT1JJC4gCgpMZXQncyBiYWNrIHRvIG91ciBzeXN0ZW0gb2YgZXF1YXRpb25zOgoKJCRcYmVnaW57YWxpZ259YStiK2MmPTZcXCAzYS0yYitjJj0yXFwgMmErYi1jJj0xXGVuZHthbGlnbn0kJApUaGUgc29sdXRpb24gcmVxdWlyZXMgdG8gaW52ZXJ0IHRoZSBtYXRyaXg6CiQkXGJlZ2lue3BtYXRyaXh9YVxcYlxcY1xlbmR7cG1hdHJpeH09XGJlZ2lue3BtYXRyaXh9MSAmIDEgJiAxXFwgMyAmIC0yICYgMVxcMiAmIDEgJiAtMVxlbmR7cG1hdHJpeH1eey0xfVxiZWdpbntwbWF0cml4fTZcXDJcXDFcZW5ke3BtYXRyaXh9JCQKYGBge3J9ClgKWTwtbWF0cml4KGMoNiwyLDEpLDMsMSkKWQpzb2x2ZShYKSUqJVkgI3dlIGNhbiB1c2UgdGhlIHNvbHZlKCkgZnVuY3Rpb24gYXMgYSBmdW5jdGlvbiB0byBpbnZlcnNlIHRoZSBtYXRyaXgKYGBgCgpNYXRyaXggT3BlcmF0aW9uIEV4ZXJjaXNlcyAjMgoKU29sdmUgdGhlIGZvbGxvd2luZyBzeXN0ZW0gb2YgZXF1YXRpb25zIHVzaW5nIFI6CgokJFxiZWdpbnthbGlnbn0gM2ErNGItNWMrZCY9MTBcXDJhKzJiKzJjLWQmPTVcXGEtYis1Yy01ZCY9N1xcNWErZCY9NFxlbmR7YWxpZ259JCQKJCRcYmVnaW57YWxpZ259XGJlZ2lue3BtYXRyaXh9IDMmNCYtNSYxXFwgMiYyJjImLTFcXCAxJi0xJjUmLTVcXDUmMCYwJjFcZW5ke3BtYXRyaXh9XGJlZ2lue3BtYXRyaXh9YVxcYlxcY1xcZFxlbmR7cG1hdHJpeH0mPVxiZWdpbntwbWF0cml4fTEwXFw1XFw3XFw0XGVuZHtwbWF0cml4fVxcIFxcIFxMZWZ0cmlnaHRhcnJvdyBcdW5kZXJicmFjZXtcYmVnaW57cG1hdHJpeH0gMyY0Ji01JjFcXCAyJjImMiYtMVxcIDEmLTEmNSYtNVxcNSYwJjAmMVxlbmR7cG1hdHJpeH1eey0xfX1fe0Feey0xfX1cdW5kZXJicmFjZXtcYmVnaW57cG1hdHJpeH0xMFxcNVxcN1xcNFxlbmR7cG1hdHJpeH19X3tCfSY9XGJlZ2lue3BtYXRyaXh9YVxcYlxcY1xcZFxlbmR7cG1hdHJpeH1cZW5ke2FsaWdufSQkCmBgYHtyfQpBPC1tYXRyaXgoYygzLDIsMSw1LDQsMiwtMSwwLC01LDIsNSwwLDEsLTEsLTUsMSksNCw0KQpBCkI8LW1hdHJpeChjKDEwLDUsNyw0KSw0LDEpClg8LXNvbHZlKEEpJSolQgpuYW1lPC1jKCJhIiwiYiIsImMiLCJkIikKWDwtZGF0YS5mcmFtZShuYW1lLFgpClgKYGBgCmBgYHtyfQphIDwtIG1hdHJpeCgxOjEyLCBucm93PTQpCmIgPC0gbWF0cml4KDE6MTUsIG5yb3c9MykKYGBgCgpNYXRyaXggT3BlcmF0aW9uIEV4ZXJjaXNlcyAjMwoKV2hhdCBpcyB0aGUgdmFsdWUgaW4gdGhlIDNyZCByb3cgYW5kIHRoZSAybmQgY29sdW1uIG9mIHRoZSBtYXRyaXggcHJvZHVjdCBvZiAkYSQgYW5kICRiJD8KYGBge3J9Ck48LWElKiViCk4KTlszLDJdCmBgYAoKTWF0cml4IE9wZXJhdGlvbiBFeGVyY2lzZXMgIzQKCk11bHRpcGx5IHRoZSAzcmQgcm93IG9mICRhJCB3aXRoIHRoZSAybmQgY29sdW1uIG9mICRiJCwgdXNpbmcgdGhlIGVsZW1lbnQtd2lzZSB2ZWN0b3IgbXVsdGlwbGljYXRpb24gd2l0aCAqLgoKV2hhdCBpcyB0aGUgc3VtIG9mIHRoZSBlbGVtZW50cyBpbiB0aGUgcmVzdWx0aW5nIHZlY3Rvcj8KYGBge3J9CnN1bShhWzMsXSpiWywyXSkKYGBgCgoKCgoKCgoKCgoKCg==