View the latest recording of this lecture

We have now considered two types of testing problems in multiple linear regression:

  1. Testing whether the response is related to at least one explanatory variable;
  2. Testing the effect of a given (single) explanatory variable having adjusted for other variables.

In this lecture, we investigate the importance of a group of covariates simultaneously.

To help our discussion later we may call the simplified model an “accepted model”, that is, with a set of variables that we think accept as being useful. The bigger model (with more variables) we may call an “extended model”, and we may refer to the additional variables as “candidate” variables.

Matrix formulation of the model

In a linear regression the predictor columns \(X_1, X_2, …,X_p\) are treated as being linked together into a specific arrangement called a data matrix X (sometimes also called the model matrix or Design matrix, usually depending on the amount of pre-planning there is in the data collection.

The columns don’t have to be next to each other in the worksheet: all you have to do is specify the column names and the software sets up the matrix for its own calculations.

If there is an intercept in the model, then the first column of the data matrix is assumed to be a column of 1s. This is the default. You don’t need to create this column: the software creates it automatically and uses it in its internal calculations – unless you specifically tell the software there is no intercept.

Note that since every entry on every row of this hidden column is the same number, then it is also referred to as the Constant column.

Next to the column of 1s, the software places into the data matrix the first column specified in the list of regression predictors. So in the example below, columns \(X_1\)=MnJanTemp, …,\(X_8\)=NorthIsland are shown. (This makes 9 columns in all).

If only predictors \(X_2\)=Lat, \(X_6\)=Height and \(X_1\)=MnJanTemp were included in the model (in that order), the data matrix would have the column of 1s, the column of \(X_2\) values, the column of \(X_6\) values, and finally the column of \(X_1\) values, in that order.

The regression parameters \(\beta_0, \beta_1, ….,\beta_8\) are similarly treated by the software as being arranged in an orderly fashion, in a matrix consisting of a single column of numbers. (A matrix with one column is called a (column) vector).

The Y values are similarly treated as a vector (one-column matrix of numbers in their particular order). We denote them by just the column name Y.

With the data organised this way in the computer, the mathematics takes over. Mathematically, the linear regression model can be written using Matrix Algebra as \[Y = X \beta + \varepsilon\]

where \(\boldsymbol{\varepsilon}\) is a vector of errors.

Now as before, our task is to find the estimates of the intercept and slopes \(\beta_0, \beta_1, …,\beta_p\) to make the sum of squared errors as small as possible. (i.e. to minimise \(\varepsilon_1^2 +\varepsilon_2^2+ ...+\varepsilon_n^2\))

The extraordinarily nice thing about writing the problem in matrix terms is that some matrix algebra gives an immediate solution that is easily programmed.
\[ \boldsymbol{b} =(X^T X)^{-1} X^T \boldsymbol{y} \]

This holds for all sizes of problem, in terms of both the number of rows (observations) and columns (variables) in the X model matrix.

Remember that proviso (condition for validity of the solution): The columns of X must be linearly independent, or more accurately, not have any linear dependencies.

A note on the intercept

The other point worth noting about the formula \[\boldsymbol{b} =(X^TX)^{-1} X^T \boldsymbol{y} \] is that the intercept is not treated any differently to any other predictor variable - it is just represented by a column of numbers in the data matrix X (in this case a column with every number=1).

The significance of this fact is that exactly the same rules and formulas apply to estimating the intercept \(\beta_0\) as apply to estimating any other slope \(\beta_1,...,\beta_p\). So if you read a regression textbook or a paper that gives a formula based on the slopes, they won’t necessarily give a separate formula for the intercept.

In what follows, we will occasionally talk about the design matrix (or data matrix) if it is helpful for understanding the way the regression models have been created.

Nested Models

A linear model M1 is said to be nested within another model M2 if M1 can be recovered as a special case of M1 by setting the parameters of M2 to the necessary values.

For the Climate data, define model M2 by

\[E[\mbox{MnJlyTemp}] = \beta_0 + \beta_1 \mbox{Lat} + \beta_2 \mbox{Height} + \beta_3 \mbox{Sea} + \beta_4 \mbox{NorthIsland} + \beta_5 \mbox{Rain}+ \beta_6 \mbox{Sun}+ \beta_7\mbox{Long}+ \beta_8 \mbox{MnJanTemp}\]

Then the model M1 defined by

\[E[\mbox{MnJlyTemp}] = \beta_0 + \beta_1 \mbox{Lat} + \beta_2 \mbox{Height} + \beta_3 \mbox{Sea} + \beta_4 \mbox{NorthIsland} \] is nested within M2 because we can obtain M1 by setting \(\beta_5 = \beta_6 = \beta_7 =\beta_8 =0\) in M2.

F Tests for Nested Models

The general ideas about model comparison continue to apply.

Selecting a model is equivalent to testing hypotheses about parameters of M2 (the more complex model).

Comparison of the models can be achieved by testing

H0: \(\beta_j = 0\) for all \(j \in J\) (i.e. M1 adequate); versus

H1: \(\beta_j\) not zero for all \(j \in J\) (i.e. M2 better)

where J indexes the p-q variables that appear in M2 but not M1.

The F-statistic to test these hypotheses is

\[F = \frac{[RSS_{M1} - RSS_{M2}]/(p-q)}{RSS_{M2}/(n-p-1)}\]

As before, extreme, large values of F provide evidence against H0 (hence evidence that we should prefer model M2 to M1).

If H0 is correct then F has an F distribution with (p-q),(n-p-1) degrees of freedom.

Hence if fobs is the observed value of the test statistic, and X is a random variable from an Fp-q,n-p-1 distribution, then the P-value is given by

\[P= P(X \ge f_{obs})\]

Interpretation of Test Results

Model Comparison for the Climate data

Our M2 and M1 were given above.

N.B. Download Climate.csv to replicate the following examples.

Climate.lm1 <- lm(MnJlyTemp ~ Lat + Height + Sea + NorthIsland, data = Climate)
anova(Climate.lm1)
Analysis of Variance Table

Response: MnJlyTemp
            Df  Sum Sq Mean Sq  F value    Pr(>F)    
Lat          1 157.428 157.428 173.4878 3.068e-14 ***
Height       1  71.463  71.463  78.7533 5.122e-10 ***
Sea          1   8.048   8.048   8.8688  0.005591 ** 
NorthIsland  1   5.260   5.260   5.7971  0.022193 *  
Residuals   31  28.130   0.907                       
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Climate.lm2 <- lm(MnJlyTemp ~ Lat + Height + Sea + NorthIsland + Rain + Sun + Long +
    MnJanTemp, data = Climate)
anova(Climate.lm2)
Analysis of Variance Table

Response: MnJlyTemp
            Df  Sum Sq Mean Sq  F value    Pr(>F)    
Lat          1 157.428 157.428 169.8702 3.664e-13 ***
Height       1  71.463  71.463  77.1111 2.136e-09 ***
Sea          1   8.048   8.048   8.6838  0.006543 ** 
NorthIsland  1   5.260   5.260   5.6762  0.024500 *  
Rain         1   2.343   2.343   2.5280  0.123481    
Sun          1   0.145   0.145   0.1563  0.695687    
Long         1   0.604   0.604   0.6521  0.426432    
MnJanTemp    1   0.016   0.016   0.0172  0.896762    
Residuals   27  25.022   0.927                       
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

\[F = \frac{[RSS_{M1} - RSS_{M2}]/(p-q)}{RSS_{M2}/(n-p-1)} = \frac{[28.13 - 25.022]/(8-4)}{25.022/(27)} = 0.8384\]

\[P(X \ge 0.8384) = 0.5129~~~~~~~~~~\mbox{where $X \sim F_{4,27}$}\]

Can we simplify further?

Suppose we want to know if we really need all four variables that are in our previous model Climate.lm1.

Maybe we can get by with an even simpler model.

\[E[\mbox{MnJlyTemp}] = \beta_0 + \beta_1 \mbox{Lat} + \beta_2 \mbox{Height} \]

So in terms of M1 we are setting \(\beta_3=\beta_4 =0\).

Climate.lm0 = lm(MnJlyTemp ~ Lat + Height, data = Climate)
anova(Climate.lm0, Climate.lm1)
Analysis of Variance Table

Model 1: MnJlyTemp ~ Lat + Height
Model 2: MnJlyTemp ~ Lat + Height + Sea + NorthIsland
  Res.Df    RSS Df Sum of Sq      F   Pr(>F)   
1     33 41.439                                
2     31 28.130  2    13.308 7.3329 0.002468 **
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Clearly we reject the hypothesis that \(\beta_3=\beta_4 =0\). There is something in these two variables that we need.

Connection with the Omnibus F Test

Connection with T Tests for Single Variables

There is a connection between the two approaches. Suppose we test H0: \[\beta_j = 0~~~~\mbox{versus}~~~~H_1:\beta_j \ne 0\] having adjusted for certain other variables.

If the observed t-test statistic is tobs, and the observed F test statistic is fobs, then

More Testing for the Climate Data

Climate.lm00 <- lm(MnJlyTemp ~ Lat + Height + Sea, data = Climate)
anova(Climate.lm0, Climate.lm00, Climate.lm1)
Analysis of Variance Table

Model 1: MnJlyTemp ~ Lat + Height
Model 2: MnJlyTemp ~ Lat + Height + Sea
Model 3: MnJlyTemp ~ Lat + Height + Sea + NorthIsland
  Res.Df    RSS Df Sum of Sq      F   Pr(>F)   
1     33 41.439                                
2     32 33.391  1    8.0478 8.8688 0.005591 **
3     31 28.130  1    5.2605 5.7971 0.022193 * 
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

If we look at the summary() output for M1 we get

summary(Climate.lm1)

Call:
lm(formula = MnJlyTemp ~ Lat + Height + Sea + NorthIsland, data = Climate)

Residuals:
    Min      1Q  Median      3Q     Max 
-1.2667 -0.5054 -0.2098  0.4707  3.4088 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) 21.378217   4.637932   4.609 6.56e-05 ***
Lat         -0.375517   0.101816  -3.688 0.000862 ***
Height      -0.004416   0.001109  -3.981 0.000385 ***
Sea          1.803422   0.483327   3.731 0.000766 ***
NorthIsland  1.559710   0.647795   2.408 0.022193 *  
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.9526 on 31 degrees of freedom
Multiple R-squared:  0.8959,    Adjusted R-squared:  0.8825 
F-statistic: 66.73 on 4 and 31 DF,  p-value: 8.723e-15
LS0tDQp0aXRsZTogIkxlY3R1cmUgMTQ6IENvbXBhcmlzb24gb2YgTXVsdGlwbGUgTGluZWFyIFJlZ3Jlc3Npb24gTW9kZWxzIg0Kc3VidGl0bGU6IDE2MS4yNTEgUmVncmVzc2lvbiBNb2RlbGxpbmcNCmF1dGhvcjogIlByZXNlbnRlZCBieSBKb25hdGhhbiBHb2RmcmV5IDxhLmouZ29kZnJleUBtYXNzZXkuYWMubno+IiAgDQpkYXRlOiAiV2VlayA1IG9mIFNlbWVzdGVyIDIsIGByIGx1YnJpZGF0ZTo6eWVhcihsdWJyaWRhdGU6Om5vdygpKWAiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgIHRoZW1lOiB5ZXRpDQogICAgaGlnaGxpZ2h0OiB0YW5nbw0KICBodG1sX25vdGVib29rOg0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICB0aGVtZTogeWV0aQ0KICAgIGhpZ2hsaWdodDogdGFuZ28NCiAgaW9zbGlkZXNfcHJlc2VudGF0aW9uOg0KICAgIHdpZGVzY3JlZW46IHRydWUNCiAgICBzbWFsbGVyOiB0cnVlDQogIHdvcmRfZG9jdW1lbnQ6IGRlZmF1bHQNCiAgc2xpZHlfcHJlc2VudGF0aW9uOiANCiAgICB0aGVtZTogeWV0aQ0KICAgIGhpZ2hsaWdodDogdGFuZ28NCiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0DQotLS0NCg0KDQoNCg0KDQpbVmlldyB0aGUgbGF0ZXN0IHJlY29yZGluZyBvZiB0aGlzIGxlY3R1cmVdKGh0dHBzOi8vUi1SZXNvdXJjZXMubWFzc2V5LmFjLm56L3ZpZGVvcy8yNTFMMTQubXA0KQ0KPCEtLS0gRGF0YSBpcyBvbg0KaHR0cHM6Ly9yLXJlc291cmNlcy5tYXNzZXkuYWMubnovZGF0YS8xNjEyNTEvDQotLS0+DQoNCmBgYHtyIHNldHVwLCBwdXJsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQ0KbGlicmFyeShrbml0cikNCm9wdHNfY2h1bmskc2V0KGRldj1jKCJwbmciLCAicGRmIikpDQpvcHRzX2NodW5rJHNldChmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD03LCBmaWcucGF0aD0iRmlndXJlcy8iLCBmaWcuYWx0PSJ1bmxhYmVsbGVkIikNCm9wdHNfY2h1bmskc2V0KGNvbW1lbnQ9IiIsIGZpZy5hbGlnbj0iY2VudGVyIiwgdGlkeT1UUlVFKQ0Kb3B0aW9ucyhrbml0ci5rYWJsZS5OQSA9ICcnKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGJyb29tKQ0KYGBgDQoNCg0KPCEtLS0gRG8gbm90IGVkaXQgYW55dGhpbmcgYWJvdmUgdGhpcyBsaW5lLiAtLS0+DQoNCg0KDQpXZSBoYXZlIG5vdyBjb25zaWRlcmVkIHR3byB0eXBlcyBvZiB0ZXN0aW5nIHByb2JsZW1zIGluIG11bHRpcGxlICAgbGluZWFyIHJlZ3Jlc3Npb246DQogICAgDQoxLiAgVGVzdGluZyB3aGV0aGVyIHRoZSByZXNwb25zZSBpcyByZWxhdGVkIHRvIGF0IGxlYXN0IG9uZQ0KICAgICAgICBleHBsYW5hdG9yeSB2YXJpYWJsZTsNCjIuICBUZXN0aW5nIHRoZSBlZmZlY3Qgb2YgYSBnaXZlbiAoc2luZ2xlKSBleHBsYW5hdG9yeSB2YXJpYWJsZSBoYXZpbmcgYWRqdXN0ZWQgZm9yIG90aGVyIHZhcmlhYmxlcy4NCg0KSW4gdGhpcyBsZWN0dXJlLCB3ZSBpbnZlc3RpZ2F0ZSB0aGUgaW1wb3J0YW5jZSBvZiBhIGdyb3VwIG9mIGNvdmFyaWF0ZXMgc2ltdWx0YW5lb3VzbHkuDQoNCi0gVGhpcyBwcm9ibGVtIGlzIGVxdWl2YWxlbnQgdG8gY29tcGFyaW5nIGEgZ2l2ZW4gbW9kZWwgd2l0aCBhIHNpbXBsaWZpZWQgdmVyc2lvbiBvZiB0aGF0IG1vZGVsLg0KDQpUbyBoZWxwIG91ciBkaXNjdXNzaW9uIGxhdGVyIHdlIG1heSBjYWxsIHRoZSBzaW1wbGlmaWVkIG1vZGVsIGFuICJhY2NlcHRlZCBtb2RlbCIsIHRoYXQgaXMsIHdpdGggYSBzZXQgb2YgdmFyaWFibGVzICB0aGF0IHdlIHRoaW5rIGFjY2VwdCBhcyBiZWluZyB1c2VmdWwuIFRoZSBiaWdnZXIgbW9kZWwgKHdpdGggbW9yZSB2YXJpYWJsZXMpIHdlIG1heSBjYWxsIGFuICJleHRlbmRlZCBtb2RlbCIsIGFuZCB3ZSBtYXkgcmVmZXIgdG8gdGhlIGFkZGl0aW9uYWwgdmFyaWFibGVzIGFzICJjYW5kaWRhdGUiIHZhcmlhYmxlcy4gDQoNCg0KIyMgTWF0cml4IGZvcm11bGF0aW9uIG9mIHRoZSBtb2RlbA0KDQpJbiBhIGxpbmVhciByZWdyZXNzaW9uIHRoZSBwcmVkaWN0b3IgY29sdW1ucyAkWF8xLCBYXzIsIOKApixYX3AkICBhcmUgdHJlYXRlZCBhcyBiZWluZyBsaW5rZWQgdG9nZXRoZXIgaW50byBhIHNwZWNpZmljIGFycmFuZ2VtZW50IGNhbGxlZCBhIGRhdGEgbWF0cml4ICAqKlgqKiAoc29tZXRpbWVzIGFsc28gY2FsbGVkIHRoZSBtb2RlbCBtYXRyaXggb3IgRGVzaWduIG1hdHJpeCwgdXN1YWxseSBkZXBlbmRpbmcgb24gdGhlIGFtb3VudCBvZiBwcmUtcGxhbm5pbmcgdGhlcmUgaXMgaW4gdGhlIGRhdGEgY29sbGVjdGlvbi4NCg0KVGhlIGNvbHVtbnMgZG9u4oCZdCBoYXZlIHRvIGJlIG5leHQgdG8gZWFjaCBvdGhlciBpbiB0aGUgd29ya3NoZWV0OiBhbGwgeW91IGhhdmUgdG8gZG8gaXMgc3BlY2lmeSB0aGUgY29sdW1uIG5hbWVzIGFuZCAgdGhlIHNvZnR3YXJlIHNldHMgdXAgdGhlIG1hdHJpeCBmb3IgaXRzIG93biBjYWxjdWxhdGlvbnMuICANCg0KSWYgdGhlcmUgaXMgYW4gaW50ZXJjZXB0IGluIHRoZSBtb2RlbCwgdGhlbiB0aGUgZmlyc3QgY29sdW1uIG9mIHRoZSBkYXRhIG1hdHJpeCBpcyBhc3N1bWVkIHRvIGJlIGEgY29sdW1uIG9mIDFzLiBUaGlzIGlzIHRoZSBkZWZhdWx0LiAgIFlvdSBkb27igJl0IG5lZWQgdG8gY3JlYXRlIHRoaXMgY29sdW1uOiAgdGhlIHNvZnR3YXJlIGNyZWF0ZXMgaXQgYXV0b21hdGljYWxseSBhbmQgdXNlcyBpdCBpbiBpdHMgaW50ZXJuYWwgY2FsY3VsYXRpb25zIOKAkyB1bmxlc3MgeW91IHNwZWNpZmljYWxseSB0ZWxsIHRoZSBzb2Z0d2FyZSB0aGVyZSBpcyBubyBpbnRlcmNlcHQuICAgICAgICAgDQoNCk5vdGUgdGhhdCBzaW5jZSBldmVyeSBlbnRyeSBvbiBldmVyeSByb3cgb2YgdGhpcyBoaWRkZW4gY29sdW1uIGlzIHRoZSBzYW1lIG51bWJlciwgdGhlbiBpdCBpcyBhbHNvIHJlZmVycmVkIHRvIGFzIHRoZSAqKkNvbnN0YW50KiogY29sdW1uLiANCg0KTmV4dCB0byB0aGUgY29sdW1uIG9mIDFzLCB0aGUgc29mdHdhcmUgcGxhY2VzIGludG8gdGhlIGRhdGEgbWF0cml4IHRoZSBmaXJzdCBjb2x1bW4gc3BlY2lmaWVkIGluIHRoZSBsaXN0IG9mIHJlZ3Jlc3Npb24gcHJlZGljdG9ycy4gICBTbyBpbiB0aGUgZXhhbXBsZSBiZWxvdywgY29sdW1ucyAkWF8xJD1NbkphblRlbXAsIOKApiwkWF84JD1Ob3J0aElzbGFuZCBhcmUgc2hvd24uICAoVGhpcyAgbWFrZXMgOSBjb2x1bW5zIGluIGFsbCkuIA0KDQpJZiBvbmx5IHByZWRpY3RvcnMgJFhfMiQ9TGF0LCAkWF82JD1IZWlnaHQgYW5kICRYXzEkPU1uSmFuVGVtcCAgd2VyZSBpbmNsdWRlZCBpbiB0aGUgbW9kZWwgKGluIHRoYXQgb3JkZXIpLCB0aGUgZGF0YSBtYXRyaXggd291bGQgaGF2ZSB0aGUgY29sdW1uIG9mIDFzLCAgdGhlIGNvbHVtbiBvZiAkWF8yJCB2YWx1ZXMsIHRoZSBjb2x1bW4gb2YgJFhfNiQgdmFsdWVzLCBhbmQgZmluYWxseSB0aGUgY29sdW1uIG9mICRYXzEkIHZhbHVlcywgaW4gdGhhdCBvcmRlci4gDQoNClRoZSByZWdyZXNzaW9uIHBhcmFtZXRlcnMgICRcYmV0YV8wLCBcYmV0YV8xLCDigKYuLFxiZXRhXzgkICBhcmUgc2ltaWxhcmx5IHRyZWF0ZWQgYnkgdGhlIHNvZnR3YXJlIGFzIGJlaW5nIGFycmFuZ2VkIGluIGFuIG9yZGVybHkgZmFzaGlvbiwgaW4gYSBtYXRyaXggY29uc2lzdGluZyBvZiBhIHNpbmdsZSBjb2x1bW4gb2YgbnVtYmVycy4gICAoQSBtYXRyaXggd2l0aCBvbmUgY29sdW1uIGlzIGNhbGxlZCBhIChjb2x1bW4pIHZlY3RvcikuDQoNCg0KVGhlICpZKiB2YWx1ZXMgYXJlIHNpbWlsYXJseSB0cmVhdGVkIGFzIGEgdmVjdG9yIChvbmUtY29sdW1uIG1hdHJpeCBvZiBudW1iZXJzIGluIHRoZWlyIHBhcnRpY3VsYXIgb3JkZXIpLiAgICBXZSBkZW5vdGUgdGhlbSBieSBqdXN0IHRoZSBjb2x1bW4gbmFtZSBgWWAuDQoNCldpdGggdGhlIGRhdGEgb3JnYW5pc2VkIHRoaXMgd2F5IGluIHRoZSBjb21wdXRlciwgICB0aGUgbWF0aGVtYXRpY3MgdGFrZXMgb3Zlci4gIE1hdGhlbWF0aWNhbGx5LCANCnRoZSBsaW5lYXIgcmVncmVzc2lvbiBtb2RlbCBjYW4gYmUgd3JpdHRlbiB1c2luZyBNYXRyaXggQWxnZWJyYSBhcyANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkJFkgPSBYIFxiZXRhICsgXHZhcmVwc2lsb24kJA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0Kd2hlcmUgJFxib2xkc3ltYm9se1x2YXJlcHNpbG9ufSQgIGlzIGEgdmVjdG9yIG9mIGVycm9ycy4gIA0KDQoNCg0KTm93IGFzIGJlZm9yZSwgb3VyIHRhc2sgaXMgdG8gZmluZCB0aGUgZXN0aW1hdGVzIG9mICB0aGUgaW50ZXJjZXB0IGFuZCBzbG9wZXMgJFxiZXRhXzAsIFxiZXRhXzEsIOKApixcYmV0YV9wJCAgICB0byBtYWtlIHRoZSBzdW0gb2Ygc3F1YXJlZCBlcnJvcnMgYXMgc21hbGwgYXMgcG9zc2libGUuICAgKGkuZS4gIHRvIG1pbmltaXNlICRcdmFyZXBzaWxvbl8xXjIgK1x2YXJlcHNpbG9uXzJeMisgLi4uK1x2YXJlcHNpbG9uX25eMiQpDQoNCg0KVGhlIGV4dHJhb3JkaW5hcmlseSBuaWNlIHRoaW5nIGFib3V0IHdyaXRpbmcgdGhlIHByb2JsZW0gaW4gbWF0cml4IHRlcm1zIGlzIHRoYXQgc29tZSBtYXRyaXggYWxnZWJyYSBnaXZlcyBhbiBpbW1lZGlhdGUgc29sdXRpb24gIHRoYXQgaXMgZWFzaWx5IHByb2dyYW1tZWQuICANCiQkIFxib2xkc3ltYm9se2J9ID0oWF5UIFgpXnstMX0gWF5UIFxib2xkc3ltYm9se3l9ICAkJCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQoNCg0KVGhpcyBob2xkcyBmb3IgYWxsIHNpemVzIG9mIHByb2JsZW0sIGluIHRlcm1zIG9mIGJvdGggdGhlIG51bWJlciBvZiByb3dzIChvYnNlcnZhdGlvbnMpIGFuZCBjb2x1bW5zICh2YXJpYWJsZXMpIGluIHRoZSAqWCogbW9kZWwgbWF0cml4Lg0KDQpSZW1lbWJlciB0aGF0IHByb3Zpc28gKGNvbmRpdGlvbiBmb3IgdmFsaWRpdHkgb2YgdGhlIHNvbHV0aW9uKTogICBUaGUgY29sdW1ucyBvZiAqWCogbXVzdCBiZSBsaW5lYXJseSBpbmRlcGVuZGVudCwgb3IgbW9yZSBhY2N1cmF0ZWx5LCBub3QgaGF2ZSBhbnkgbGluZWFyIGRlcGVuZGVuY2llcy4NCg0KIyMgQSBub3RlIG9uIHRoZSBpbnRlcmNlcHQNCg0KVGhlIG90aGVyIHBvaW50IHdvcnRoIG5vdGluZyBhYm91dCB0aGUgZm9ybXVsYSAgICAgICAgICAkJFxib2xkc3ltYm9se2J9ID0oWF5UWCleey0xfSAgWF5UIFxib2xkc3ltYm9se3l9ICAgJCQNCmlzIHRoYXQgdGhlIGludGVyY2VwdCBpcyBub3QgdHJlYXRlZCBhbnkgZGlmZmVyZW50bHkgdG8gYW55IG90aGVyIHByZWRpY3RvciB2YXJpYWJsZSAtICBpdCBpcyBqdXN0IHJlcHJlc2VudGVkIGJ5IGEgY29sdW1uIG9mIG51bWJlcnMgaW4gdGhlIGRhdGEgbWF0cml4ICoqWCoqIChpbiB0aGlzIGNhc2UgYSBjb2x1bW4gd2l0aCBldmVyeSBudW1iZXI9MSkuIA0KDQpUaGUgc2lnbmlmaWNhbmNlIG9mIHRoaXMgZmFjdCBpcyB0aGF0IGV4YWN0bHkgdGhlIHNhbWUgcnVsZXMgYW5kIGZvcm11bGFzIGFwcGx5IHRvIGVzdGltYXRpbmcgdGhlIGludGVyY2VwdCAkXGJldGFfMCQgYXMgYXBwbHkgdG8gZXN0aW1hdGluZyBhbnkgb3RoZXIgc2xvcGUgICRcYmV0YV8xLC4uLixcYmV0YV9wJC4gIFNvIGlmIHlvdSByZWFkIGEgcmVncmVzc2lvbiB0ZXh0Ym9vayBvciBhIHBhcGVyIHRoYXQgZ2l2ZXMgYSBmb3JtdWxhIGJhc2VkIG9uIHRoZSBzbG9wZXMsIHRoZXkgd29u4oCZdCBuZWNlc3NhcmlseSBnaXZlIGEgc2VwYXJhdGUgZm9ybXVsYSBmb3IgdGhlIGludGVyY2VwdC4gIA0KDQpJbiB3aGF0IGZvbGxvd3MsIHdlIHdpbGwgb2NjYXNpb25hbGx5IHRhbGsgYWJvdXQgdGhlIGRlc2lnbiBtYXRyaXggKG9yIGRhdGEgbWF0cml4KSBpZiBpdCBpcyBoZWxwZnVsIGZvciB1bmRlcnN0YW5kaW5nIHRoZSB3YXkgdGhlIHJlZ3Jlc3Npb24gbW9kZWxzIGhhdmUgYmVlbiBjcmVhdGVkLiANCg0KDQoNCg0KDQoNCg0KIyMgTmVzdGVkIE1vZGVscw0KDQpBIGxpbmVhciBtb2RlbCAqTTEqIGlzIHNhaWQgdG8gYmUgKipuZXN0ZWQqKiB3aXRoaW4gYW5vdGhlcg0KbW9kZWwgKk0yKiBpZiAqTTEqIGNhbiBiZSByZWNvdmVyZWQgYXMgYSBzcGVjaWFsIGNhc2Ugb2YgKk0xKiBieSBzZXR0aW5nIHRoZSBwYXJhbWV0ZXJzIG9mICpNMiogdG8gdGhlIG5lY2Vzc2FyeSB2YWx1ZXMuDQoNCkZvciB0aGUgQ2xpbWF0ZSBkYXRhLCBkZWZpbmUgbW9kZWwgKk0yKiBieQ0KDQokJEVbXG1ib3h7TW5KbHlUZW1wfV0gPSBcYmV0YV8wICsgXGJldGFfMSBcbWJveHtMYXR9ICsgXGJldGFfMiBcbWJveHtIZWlnaHR9ICsgXGJldGFfMyBcbWJveHtTZWF9ICsgXGJldGFfNCAgXG1ib3h7Tm9ydGhJc2xhbmR9ICAgICAgKyBcYmV0YV81IFxtYm94e1JhaW59KyBcYmV0YV82IFxtYm94e1N1bn0rIFxiZXRhXzdcbWJveHtMb25nfSsgXGJldGFfOCBcbWJveHtNbkphblRlbXB9JCQNCg0KVGhlbiB0aGUgbW9kZWwgKk0xKiBkZWZpbmVkIGJ5DQoNCg0KJCRFW1xtYm94e01uSmx5VGVtcH1dID0gXGJldGFfMCArIFxiZXRhXzEgXG1ib3h7TGF0fSArIFxiZXRhXzIgXG1ib3h7SGVpZ2h0fSArIFxiZXRhXzMgXG1ib3h7U2VhfSArIFxiZXRhXzQgXG1ib3h7Tm9ydGhJc2xhbmR9ICQkDQppcyBuZXN0ZWQgd2l0aGluICpNMiogYmVjYXVzZSB3ZSBjYW4gb2J0YWluICpNMSogYnkgc2V0dGluZyAkXGJldGFfNSA9IFxiZXRhXzYgPSBcYmV0YV83ID1cYmV0YV84ID0wJCBpbiAqTTIqLg0KDQoNCiMjICpGKiBUZXN0cyBmb3IgTmVzdGVkIE1vZGVscw0KDQpUaGUgZ2VuZXJhbCBpZGVhcyBhYm91dCBtb2RlbCBjb21wYXJpc29uICAgY29udGludWUgdG8gIGFwcGx5LiAgICANCg0KLSBXZSB3YW50IGEgImNoZWFwIiBtb2RlbCAoaS5lLiBvbmUgd2l0aCBmZXcgcGFyYW1ldGVycyk7DQotIFdlIHdhbnQgYSBtb2RlbCB0aGF0IGZpdHMgd2VsbCAoaS5lLiBvbmUgd2l0aCBzbWFsbCBSU1MuDQotIFRoZSBjaG9pY2Ugb2YgbW9kZWwgd2lsbCBiZSBhIHF1ZXN0aW9uIG9mIHdoZXRoZXIgdGhlIGltcHJvdmVtZW50IGluICAgICBnb29kbmVzcyBvZiBmaXQgb2YgdGhlIGV4dGVuZGVkIG1vZGVsICAqTTIqIG92ZXIgdGhlIHNpbXBsZXIgbW9kZWwgKk0xKiBpcyAgICAgIHdvcnRoIHRoZSBjb3N0Lg0KDQpTZWxlY3RpbmcgYSBtb2RlbCBpcyBlcXVpdmFsZW50IHRvIHRlc3RpbmcgaHlwb3RoZXNlcyBhYm91dCBwYXJhbWV0ZXJzIG9mICpNMiogKHRoZSBtb3JlIGNvbXBsZXggbW9kZWwpLg0KDQoNCi0gU3VwcG9zZSB0aGF0IGxpbmVhciBtb2RlbCAqTTEqIGhhcyAqcSogZXhwbGFuYXRvcnkgdmFyaWFibGVzIChoZW5jZSAqcSsxKiByZWdyZXNzaW9uIHBhcmFtZXRlcnMsIGluY2x1ZGluZyBpbnRlcmNlcHQpLg0KLSBTdXBwb3NlIHRoYXQgKk0xKiBpcyBuZXN0ZWQgd2l0aGluIGxpbmVhciBtb2RlbCAqTTIqIHdoaWNoIGhhcyAgKnAgPiBxKiBleHBsYW5hdG9yeSB2YXJpYWJsZXMgKGhlbmNlICpwKzEqIHJlZ3Jlc3Npb24gICAgIHBhcmFtZXRlcnMsIGluY2x1ZGluZyBpbnRlcmNlcHQpLg0KDQpDb21wYXJpc29uIG9mIHRoZSBtb2RlbHMgY2FuIGJlIGFjaGlldmVkIGJ5IHRlc3RpbmcNCg0KKkh+MH4qOiAkXGJldGFfaiA9IDAkIGZvciBhbGwgJGogXGluIEokIChpLmUuICpNMSogYWRlcXVhdGUpOyB2ZXJzdXMNCg0KKkh+MX4qOiAkXGJldGFfaiQgbm90IHplcm8gZm9yIGFsbCAkaiBcaW4gSiQgKGkuZS4gKk0yKiBiZXR0ZXIpDQogICAgDQp3aGVyZSAqSiogaW5kZXhlcyB0aGUgKnAtcSogdmFyaWFibGVzIHRoYXQgYXBwZWFyIGluICpNMiogYnV0IG5vdCAqTTEqLg0KDQoNClRoZSAqRiotc3RhdGlzdGljIHRvIHRlc3QgdGhlc2UgaHlwb3RoZXNlcyBpcw0KDQokJEYgPSBcZnJhY3tbUlNTX3tNMX0gLSBSU1Nfe00yfV0vKHAtcSl9e1JTU197TTJ9LyhuLXAtMSl9JCQNCg0KQXMgYmVmb3JlLCBleHRyZW1lLCBsYXJnZSB2YWx1ZXMgb2YgKkYqIHByb3ZpZGUgZXZpZGVuY2UgYWdhaW5zdCAqSH4wfiogKGhlbmNlIGV2aWRlbmNlIHRoYXQgd2Ugc2hvdWxkIHByZWZlciBtb2RlbCAqTTIqIHRvICpNMSopLg0KDQpJZiAqSH4wfiogaXMgY29ycmVjdCB0aGVuICpGKiBoYXMgYW4gKkYqIGRpc3RyaWJ1dGlvbiB3aXRoICoocC1xKSwobi1wLTEpKiBkZWdyZWVzIG9mIGZyZWVkb20uDQoNCkhlbmNlIGlmICpmfm9ic34qIGlzIHRoZSBvYnNlcnZlZCB2YWx1ZSBvZiB0aGUgdGVzdCBzdGF0aXN0aWMsIGFuZCAqWCogaXMgYSByYW5kb20gdmFyaWFibGUgZnJvbSBhbiAqRn5wLXEsbi1wLTF+KiBkaXN0cmlidXRpb24sIHRoZW4gdGhlICpQKi12YWx1ZSBpcyBnaXZlbiBieSANCg0KJCRQPSBQKFggXGdlIGZfe29ic30pJCQNCg0KIyMgSW50ZXJwcmV0YXRpb24gb2YgVGVzdCBSZXN1bHRzDQoNCi0gQXMgd2UgaGF2ZSBzZWVuIGVhcmxpZXIsIHRoZSBpbXBvcnRhbmNlIG9mIHZhcmlhYmxlcyBpbiBhIG11bHRpcGxlIHJlZ3Jlc3Npb24gaXMgZGVwZW5kZW50IHVwb24gY29udGV4dCAoaS5lLiB3aGF0IG90aGVyIHZhcmlhYmxlcyBhcmUgdGFrZW4gaW50byBhY2NvdW50KS4NCg0KLSBSZXRlbnRpb24gb2YgKkh+MH4qIChpLmUuIGFjY2VwdGFuY2UgdGhhdCBtb2RlbCAqTTEqIGlzIGFkZXF1YXRlKSBkb2VzIG5vdCBtZWFuIHRoYXQgdGhlICpwLXEqIHZhcmlhYmxlcyBpbmRleGVkIGJ5ICpKKiBhcmUgdW5yZWxhdGVkIHRvIHRoZSByZXNwb25zZS4NCi0gUmF0aGVyLCByZXRlbnRpb24gb2YgKkh+MH4qIGluZGljYXRlcyB0aGF0IHRoZSB2YXJpYWJsZXMgaW5kZXhlZCBieSAqSiogZG8gbm90IHByb3ZpZGUgYWRkaXRpb25hbCBpbmZvcm1hdGlvbiBhYm91dCB0aGUgcmVzcG9uc2UgaGF2aW5nIGFkanVzdGVkIGZvciBhbGwgdGhlIG90aGVyICgqcSopIHZhcmlhYmxlcy4NCg0KIyMgTW9kZWwgQ29tcGFyaXNvbiBmb3IgdGhlIENsaW1hdGUgZGF0YQ0KDQpPdXIgKk0yKiBhbmQgKk0xKiB3ZXJlIGdpdmVuIGFib3ZlLiANCg0KDQpOLkIuIGByIHhmdW46OmVtYmVkX2ZpbGUoIi4uLy4uL2RhdGEvQ2xpbWF0ZS5jc3YiKWAgdG8gcmVwbGljYXRlIHRoZSBmb2xsb3dpbmcgZXhhbXBsZXMuDQoNCg0KDQpgYGB7ciBmaXJzdE1vZGVscywgZWNobz0tMX0NCkNsaW1hdGUgPC0gcmVhZC5jc3YoZmlsZT0iLi4vLi4vZGF0YS9DbGltYXRlLmNzdiIsIGhlYWRlcj1UUlVFLCByb3cubmFtZXM9MSkgDQpDbGltYXRlLmxtMSA8LSBsbShNbkpseVRlbXB+IExhdCArIEhlaWdodCsgU2VhKyBOb3J0aElzbGFuZCwgZGF0YT1DbGltYXRlKQ0KYW5vdmEoQ2xpbWF0ZS5sbTEpDQpDbGltYXRlLmxtMiA8LSBsbShNbkpseVRlbXAgfiBMYXQgKyBIZWlnaHQrIFNlYSsgTm9ydGhJc2xhbmQrIFJhaW4rIFN1biArIExvbmcrIE1uSmFuVGVtcCwgZGF0YT1DbGltYXRlKQ0KYW5vdmEoQ2xpbWF0ZS5sbTIpDQpgYGANCg0KLSBGb3IgbW9kZWwgYENsaW1hdGUubG0xYCwgY2FsY3VsYXRpb25zIGdpdmUgKlJTU35NMX4gPSBgciByb3VuZChhbm92YShDbGltYXRlLmxtMSlbIlJlc2lkdWFscyIsICJTdW0gU3EiXSwzKWAqIGFuZCAqcT00Ki4NCi0gRm9yIG1vZGVsIGBDbGltYXRlLmxtMmAsIGNhbGN1bGF0aW9ucyBnaXZlICpSU1N+TTJ+ID0gIGByIHJvdW5kKGFub3ZhKENsaW1hdGUubG0yKVsiUmVzaWR1YWxzIiwgIlN1bSBTcSJdLCAzKWAqIGFuZCAqcD04Ki4NCg0KDQoNCiQkRiA9IFxmcmFje1tSU1Nfe00xfSAtIFJTU197TTJ9XS8ocC1xKX17UlNTX3tNMn0vKG4tcC0xKX0gPSBcZnJhY3tbMjguMTMgLSAyNS4wMjJdLyg4LTQpfXsyNS4wMjIvKDI3KX0gPSAwLjgzODQkJA0KDQoNCg0KDQoNCiQkUChYIFxnZSAwLjgzODQpID0gMC41MTI5fn5+fn5+fn5+flxtYm94e3doZXJlICRYIFxzaW0gRl97NCwyN30kfSQkDQoNCi0gV2UgY29uY2x1ZGUgdGhhdCAqSH4wfiogY2FuIGJlIHJldGFpbmVkIChpLmUuIG1vZGVsICpNMSogaXMgICAgICBhZGVxdWF0ZSkuIFRoZXJlIGlzIG5vIGV2aWRlbmNlIHRoYXQgUmFpbiwgU3VuLCBMb25nIGFuZCBNbkphblRlbXAgKGNvbnNpZGVyZWQgdG9nZXRoZXIpICAgcHJvdmlkZSBmdXJ0aGVyIGluZm9ybWF0aW9uIGFib3V0IE1uSmx5VGVtcCBvbmNlIHdlIGhhdmUgYWRqdXN0ZWQgZm9yIExhdCwgSGVpZ2h0LCBTZWEgYW5kIE5vcnRoSXNsYW5kLg0KDQpDYW4gd2Ugc2ltcGxpZnkgZnVydGhlcj8gDQoNCg0KU3VwcG9zZSB3ZSB3YW50IHRvIGtub3cgaWYgd2UgcmVhbGx5IG5lZWQgYWxsIGZvdXIgdmFyaWFibGVzIHRoYXQgYXJlIGluIG91ciBwcmV2aW91cyBtb2RlbCBgQ2xpbWF0ZS5sbTFgLiANCg0KDQpNYXliZSB3ZSBjYW4gZ2V0IGJ5IHdpdGggYW4gZXZlbiBzaW1wbGVyIG1vZGVsLg0KDQokJEVbXG1ib3h7TW5KbHlUZW1wfV0gPSBcYmV0YV8wICsgXGJldGFfMSBcbWJveHtMYXR9ICsgXGJldGFfMiBcbWJveHtIZWlnaHR9ICQkIA0KDQpTbyBpbiB0ZXJtcyBvZiBNMSB3ZSBhcmUgc2V0dGluZyAkXGJldGFfMz1cYmV0YV80ID0wJC4gDQoNCmBgYHtyIENsaW1hdGUubG0wfQ0KQ2xpbWF0ZS5sbTAgPWxtKCBNbkpseVRlbXAgfiBMYXQrIEhlaWdodCwgZGF0YSA9IENsaW1hdGUpDQphbm92YSggQ2xpbWF0ZS5sbTAsIENsaW1hdGUubG0xKQ0KYGBgDQoNCkNsZWFybHkgd2UgcmVqZWN0IHRoZSBoeXBvdGhlc2lzIHRoYXQgJFxiZXRhXzM9XGJldGFfNCA9MCQuIFRoZXJlIGlzIHNvbWV0aGluZyBpbiB0aGVzZSB0d28gdmFyaWFibGVzIHRoYXQgd2UgbmVlZC4gDQoNCg0KIyMgQ29ubmVjdGlvbiB3aXRoIHRoZSBPbW5pYnVzICpGKiBUZXN0DQoNCi0gVGhlIG9tbmlidXMgKkYqIHRlc3QgZm9yIG1vZGVsIHV0aWxpdHkgZGlzY3Vzc2VkIGVhcmxpZXIgaXMgYSAgICAgIHBhcnRpY3VsYXIgY2FzZSBvZiB0aGUgbW9yZSBnZW5lcmFsIG1ldGhvZG9sb2d5IGZvciBtb2RlbCBjb21wYXJpc29uICAgIHByZXNlbnRlZCBpbiB0aGlzIGxlY3R1cmUuDQotIFNwZWNpZmljYWxseSwgaW4gb21uaWJ1cyAqRiogdGVzdCB3ZSBhbHdheXMgdGFrZSAqTTEqIHRvIGJlIHRoZSAgICAgICpudWxsKiBtb2RlbCB3aXRoICpxPTAqIGV4cGxhbmF0b3J5IHZhcmlhYmxlcywgYW5kICAgICAgICpNMiogdG8gYmUgdGhlIGZ1bGwgbW9kZWwgd2l0aCAqcCogZXhwbGFuYXRvcnkgdmFyaWFibGVzLg0KDQoNCg0KDQojIyBDb25uZWN0aW9uIHdpdGggVCBUZXN0cyBmb3IgU2luZ2xlIFZhcmlhYmxlcw0KDQotICpGKiB0ZXN0cyBjYW4gYmUgdXNlZCB0byBjb21wYXJlIHR3byBtb2RlbHMgdGhhdCBkaWZmZXIgYnkgYSBzaW5nbGUgICAgICBleHBsYW5hdG9yeSB2YXJpYWJsZS4NCi0gYSAqVCogdGVzdCBjYW4gYWxzbyBiZSB1c2VkIHRvIGFzc2VzcyB0aGUgaW1wb3J0YW5jZSBvZiBhbnkgZ2l2ZW4gZXhwbGFuYXRvcnkgdmFyaWFibGUuDQoNCg0KVGhlcmUgaXMgYSBjb25uZWN0aW9uIGJldHdlZW4gdGhlIHR3byBhcHByb2FjaGVzLiBTdXBwb3NlIHdlIHRlc3QgKkh+MH4qOiAkJFxiZXRhX2ogPSAwfn5+flxtYm94e3ZlcnN1c31+fn5+SF8xOlxiZXRhX2ogXG5lIDAkJCBoYXZpbmcgYWRqdXN0ZWQgZm9yIGNlcnRhaW4gb3RoZXIgdmFyaWFibGVzLiANCg0KSWYgdGhlIG9ic2VydmVkICp0Ki10ZXN0IHN0YXRpc3RpYyBpcyAqdH5vYnN+KiwgYW5kIHRoZSBvYnNlcnZlZCAqRiogdGVzdCBzdGF0aXN0aWMgaXMgICAqZn5vYnN+KiwgdGhlbiANCg0KLSAqZn5vYnN+ID0gdH5vYnN+XjJeKi4NCi0gVGhlICpQKi12YWx1ZSBmcm9tIHRoZSB0d28gdGVzdHMgd2lsbCBiZSB0aGUgc2FtZS4NCg0KIyMgTW9yZSBUZXN0aW5nIGZvciB0aGUgQ2xpbWF0ZSAgRGF0YQ0KDQoNCi0gU3VwcG9zZSB0aGF0IHdlIHdpc2ggdG8gdGVzdCBmb3IgdGhlIGltcG9ydGFuY2Ugb2YgYE5vcnRoSXNsYW5kYCBoYXZpbmcgYWRqdXN0ZWQgZm9yIHRoZSBvdGhlciB2YXJpYWJsZXMgYExhdGAsIGBIZWlnaHRgIGFuZCBgU2VhYC4NCg0KLSBXZSB3YW50IHRvIHRlc3QgKkh+MH4qOiAkJFxiZXRhXzQgPSAwfn5+flxtYm94e3ZlcnN1c31+fn5+SF8xOlxiZXRhXzQgXG5lIDAkJCAgIA0KLSBXZSB3aWxsIHBlcmZvcm0gKnQqIGFuZCAqRiogdGVzdHMgdXNpbmcgUi4NCg0KDQpgYGB7ciBzZWNvbmRNb2RlbHN9DQpDbGltYXRlLmxtMDAgPC0gbG0oTW5KbHlUZW1wIH4gTGF0KyBIZWlnaHQrIFNlYSwgZGF0YT1DbGltYXRlKQ0KYW5vdmEoQ2xpbWF0ZS5sbTAsIENsaW1hdGUubG0wMCwgQ2xpbWF0ZS5sbTEpDQpgYGANCg0KLSBUaGUgZmlyc3QgKkYqLXN0YXRpc3RpYyAoZnJvbSB0aGUgYW5vdmEoKSBmdW5jdGlvbiBvdXRwdXQpIGlzICpmID0gOC44NjkqIHdpdGggY29ycmVzcG9uZGluZyAqUCotdmFsdWUgKlA9MC4wMDU1OSouIFNvIHdlIG5lZWQgU2VhIGluIGFkZGl0aW9uIHRvIExhdCBhbmQgSGVpZ2h0Lg0KLSBUaGUgc2Vjb25kICAqRiotc3RhdGlzdGljIGlzICAqZiA9IDUuNzk3KiB3aXRoIGNvcnJlc3BvbmRpbmcgKlAqLXZhbHVlICpQPTAuMDIyMTkqLiBTbyB3ZSBuZWVkIE5vcnRoSXNsYW5kICBpbiBhZGRpdGlvbiB0byBMYXQsIEhlaWdodCBhbmQgU2VhLiANCg0KSWYgd2UgbG9vayBhdCB0aGUgc3VtbWFyeSgpIG91dHB1dCBmb3IgTTEgIHdlIGdldA0KYGBge3Igc3VtbWFyeSBNMX0NCnN1bW1hcnkoQ2xpbWF0ZS5sbTEpDQpgYGANCg0KLSBUaGUgKnQqLXN0YXRpc3RpYyBmb3IgTm9ydGhJc2xhbmQgIGlzICp0PTIuNDA4KiB3aXRoIGNvcnJlc3BvbmRpbmcgKlAqLXZhbHVlICpQPTAuMDIyMTkqLg0KLSBOb3RlIHRoYXQgKmYqID0gNS43OTcgPSAyLjQwOF4yXiA9ICp0XjJeKi4NCg0KDQoNCg==