Variable selection

In previous lectures we have looked at tests for single explanatory variables and groups of explanatory variables.

Often, however, a statistician will simply want to know what is the best group of explanatory variables for describing the response.

In this lecture we will consider various criteria for model selection, and cover an example on finding a suitable variable set “by hand”.

Overfitting and Underfitting

We begin by considering the following question: Should all the explanatory variables be used, or should some be omitted?

Why might we want to omit variables?

We first consider the risks and benefits of including a predictor that might have coefficient \(\beta=0\).

Dropping or Including Variables that have \(\beta=0\)

Suppose we have a regression model with several variables. We might suspect one has regression coefficient \(\beta=0\). Should we drop it?

Some mathematical theory shows that if we omit a variable which (truly) has regression coefficient \(\beta=0\) then

Both these things are good.

Conversely if we include a variable whose coefficient \(\beta=0\) this increases these variances unnecessarily. This is called overfitting. We want to avoid this.

Dropping or Including Variables that have \(\beta \ne 0\)

On the other hand suppose we make a mistake and omit a variable that has regression coefficient \(\ne 0\).

Then we have the opposite problem, called underfitting. Mathematical theory shows the consequence of underfitting is that

Both these things are bad!

In practice we do not know if parameters are zero. We could use a hypothesis test to help us decide, but this is not a definitive answer.

A Numerical Illustration of Under and Overfitting

In this artificial example, we consider an industrial process whose Yield is thought to depend on the process temperature at stage A of the process, and possibly also on the temperature at stage B.

i.e. We consider the model \[ Y=\beta_0 + \beta_1 A+ \beta_2 B +\varepsilon.\]

We will assume the values of \(A\) and \(B\) and \(\varepsilon\) are given in the data below. The errors are random \(\varepsilon \sim \mbox{Normal}(0, 1)\).

Download simulation1.csv

## sim = read.csv("simulation1.csv", header = TRUE)

What we want to know is, what are the implications of using an incorrect model, i.e. incorrect assumptions about the \(\beta\)s. To understand the implications, we simulate two scenarios.

Scenario 1: \(\beta_0=50\), \(\beta_1=10\) and \(\beta_2=0\).

For this illustration, the correct model doesn’t depend on \(B\) at all: \[Y = 50 + 10 A + \varepsilon\]

The following shows the result of modelling \(Y\) by (1) \(A\) alone and (2) by \(A\) and \(B\).

dat <- sim |>
    mutate(Y = 50 + 10 * A + epsilon)
lm1 = lm(Y ~ A, data = dat)
lm2 = lm(Y ~ A + B, data = dat)
lst(lm1, lm2) |>
    map_dfr(tidy, .id = "model")
# A tibble: 5 × 6
  model term        estimate std.error statistic  p.value
  <chr> <chr>          <dbl>     <dbl>     <dbl>    <dbl>
1 lm1   (Intercept)   49.3       2.03     24.2   3.43e-15
2 lm1   A             10.0       0.112    89.4   2.71e-25
3 lm2   (Intercept)   48.8       2.14     22.8   3.43e-14
4 lm2   A              9.76      0.338    28.9   7.01e-16
5 lm2   B              0.290     0.350     0.827 4.19e- 1

Adding the unnecessary variable doesn’t introduce bias (\(\hat\beta_1 \approx 10\)), but the standard error of \(\hat\beta_1\) is higher in the misspecified model.

Scenario 2: \(\beta_0=50\), \(\beta_1=5\) and \(\beta_2=5\).

We consider the model where \(Y\) depends on both \(A\) and \(B\), \[ Y = 50 + 5 A + 5 B + \varepsilon \]

dat <- sim |>
    mutate(Y = 50 + 5 * A + 5 * B + epsilon)
lm1 = lm(Y ~ A, data = dat)
lm2 = lm(Y ~ A + B, data = dat)
lst(lm1, lm2) |>
    map_dfr(tidy, .id = "model")
# A tibble: 5 × 6
  model term        estimate std.error statistic  p.value
  <chr> <chr>          <dbl>     <dbl>     <dbl>    <dbl>
1 lm1   (Intercept)    57.8      7.57       7.63 4.74e- 7
2 lm1   A               9.58     0.418     22.9  8.94e-15
3 lm2   (Intercept)    48.8      2.14      22.8  3.43e-14
4 lm2   A               4.76     0.338     14.1  8.48e-11
5 lm2   B               5.29     0.350     15.1  2.75e-11

In the first model, \(B\) is wrongly ignored and \(A\) is both biased and has a larger standard error. In the second model, the values of \(\hat\beta_1\) and \(\hat\beta_2\) are close to the true ones and the standard errors are the same as in the second analysis of Scenario 1.

In summary, if we omit a needed variable then we may introduce bias into our estimation.

The big problem with bias is that there may be no sign that we have a mistake.

In some cases we don’t even have the needed variable, so we can’t try it in the model.

At least in case 1, when we wrongly enter an unnecessary variable, it doesn’t bias our estimates, just increases our standard errors. So at least we know exactly how bad things are. But with an omitted variable we don’t know how bad things are.

For this reason, we may decide to err on the side of caution and add in variables even if we are uncertain about their relevance. Then at least we can avoid bias.

Model Selection: Bias and Variance

Model selection, then, comes down to balancing the effects of variance and bias.

So what should we choose? There is no settled rule for every circumstance, but in general we should probably be more concerned to avoid bias (especially since we don’t know how bad this is!) than to avoid a small increase in variance (at least we do know how bad it is - we can see the standard errors.)

Consequently we may decide to err on the side of including variables with P-values a little bigger than 0.05, especially if they seem to induce a sizeable change in the other coefficient estimates. This is another thing to watch out for in model selection.

Review of Model Selection Criteria

There are a number of measures we can use for model selection:

Each of these are slightly different, so it pays to consider more than one.

Coefficient of determination \(R^2\)

Recall that this is the proportion of total variation which is explained by the model. (Alternatively, 1 minus the ratio of unexplained variation to total variation): \[ R^2 = \frac{SS_{Regn}}{SST} = 1 - \frac{\sum(y_i-\hat y_i)^2}{\sum(y_i-\bar y)^2}. \] \(R^2\) is useful for comparing two models with the same number of regression parameters. If models have different numbers of regression parameters we use the adjusted version.

Adjusted Coefficient of determination \(R^2_{Adj}\)

Recall that this is 1 minus the ratio of Mean Square Error to Mean Square Total: \[ R^2_{Adj} = 1 - \frac{MSE}{MST} = 1 - \frac{\sum(y_i-\hat y_i)^2/(n-p)}{\sum(y_i-\bar y)^2/(n-1)}.\] When considering adding a variable to a regression, the \(R^2_{Adj}\) goes up if the variable is “worth” at least one row of data (one degree of freedom), which is a pretty low bar to cross.

But at least if a variable can’t meet that rule then we know to exclude it.

Residual Standard Error \(S\)

This is the standard deviation of the residuals, \[ S = \frac{1}{n-p}\sum{(y_i - \hat y_i)^2} \] or in other words the standard deviation of how the \(y_i\)s vary around the model predictions. We might choose to include a variable if it reduces the \(S\).

\(P\)-value for individual coefficients

We usually prefer models that only include variables with coefficient \(P\)-value is small (e.g. \(< 0.05\)).

However the “0.05” criterion is somewhat arbitrary and occasionally we allow in variables with slightly higher \(P\)-values to potentially reduce bias.

Example: Model Selection for Climate Data

We wish to model the mean temperature in July (winter) in Aotearoa New Zealand using data from 36 towns. We have information on location (latitude, longitude, height (elevation), whether they’re by the sea or in the North island) as well as climate information (mean temperature in January, total sunshine hours and total rainfall).

Download climate.csv

## climate = read_csv("climate.csv")
climate
# A tibble: 36 × 10
   Place      Lat  Long MnJanTemp MnJlyTemp  Rain   Sun Height   Sea NorthIsland
   <chr>    <dbl> <dbl>     <dbl>     <dbl> <dbl> <dbl>  <dbl> <dbl>       <dbl>
 1 Kaitaia   35.1  173.      19.3      11.7  1418  2113     80     1           1
 2 Kerikeri  35.2  174       18.9      10.8  1682  2004     73     1           1
 3 Dargavi…  36    174.      18.6      10.7  1248  1956     20     1           1
 4 Whangar…  35.7  174.      19.7      11    1600  1925     29     1           1
 5 Auckland  36.9  175.      19.4      11    1185  2102     49     1           1
 6 Tauranga  37.7  176.      18.5       9.3  1349  2277      4     1           1
 7 Hamilton  37.8  175.      17.8       8.3  1201  2006     40     0           1
 8 Rotorua   38.2  176.      17.5       7.3  1439  1948    307     0           1
 9 Gisborne  38.7  178       18.7      13.6  1058  2204      4     1           1
10 Taupo     38.7  177.      17.3       6.5  1178  2021    376     0           1
# ℹ 26 more rows

Climate Exploratory Data Analysis

climate |>
    pivot_longer(-c(Place, MnJlyTemp)) |>
    ggplot() + geom_point(mapping = aes(x = value, y = MnJlyTemp)) + facet_wrap(vars(name),
    scales = "free_x", ncol = 4)

unlabelled

Higher winter temperature associations

Many of these are likely correlated.

Climate: Latitude/Longitude and North vs South

ggplot(climate) + geom_point(mapping = aes(x = Long, y = -Lat, shape = as_factor(NorthIsland),
    col = MnJlyTemp)) + geom_text(mapping = aes(x = Long, y = -Lat, label = Place),
    size = 2, hjust = "right", nudge_x = 0.1, nudge_y = 0.2) + coord_equal()

unlabelled

Climate: Latitude/Longitude and North vs South

Ok, so we can see that the temperature is being driven by latitude (further north is warmer) - the longitude effect is possibly just due to orientation. It’s clear there’s an elevation (height) effect as well, though that is possibly confounded with whether the town is close to the sea (it can’t really be both!)

So we’d expect some collinearity here and figuring out which are the best variables to be used might take a bit of playing!

We’ll start with Latitude, then add in Height and Sea:

lm1 = lm(MnJlyTemp ~ Lat, data = climate)
lm2 = lm(MnJlyTemp ~ Lat + Height, data = climate)
lm3 = lm(MnJlyTemp ~ Lat + Height + Sea, data = climate)

Climate: model output

lm1 |>
    summary()

Call:
lm(formula = MnJlyTemp ~ Lat, data = climate)

Residuals:
    Min      1Q  Median      3Q     Max 
-3.6992 -0.9786  0.1566  1.0588  4.7930 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) 34.42127    3.94299   8.730 3.35e-10 ***
Lat         -0.66187    0.09613  -6.885 6.25e-08 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 1.822 on 34 degrees of freedom
Multiple R-squared:  0.5824,    Adjusted R-squared:  0.5701 
F-statistic: 47.41 on 1 and 34 DF,  p-value: 6.25e-08

lm2 |>
    summary()

Call:
lm(formula = MnJlyTemp ~ Lat + Height, data = climate)

Residuals:
    Min      1Q  Median      3Q     Max 
-2.0607 -0.6215 -0.1021  0.5145  3.9898 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept) 32.8788366  2.4333203  13.512 5.30e-15 ***
Lat         -0.6005121  0.0596687 -10.064 1.38e-11 ***
Height      -0.0071984  0.0009542  -7.544 1.12e-08 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 1.121 on 33 degrees of freedom
Multiple R-squared:  0.8467,    Adjusted R-squared:  0.8374 
F-statistic: 91.14 on 2 and 33 DF,  p-value: 3.639e-14

lm3 |>
    summary()

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

Residuals:
    Min      1Q  Median      3Q     Max 
-1.7969 -0.4792 -0.0299  0.5042  3.7850 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) 31.290016   2.290747  13.659 6.71e-15 ***
Lat         -0.587826   0.054584 -10.769 3.59e-12 ***
Height      -0.005121   0.001147  -4.463 9.38e-05 ***
Sea          1.294326   0.466063   2.777  0.00909 ** 
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 1.022 on 32 degrees of freedom
Multiple R-squared:  0.8765,    Adjusted R-squared:  0.8649 
F-statistic: 75.69 on 3 and 32 DF,  p-value: 1.275e-14

Climate: First three predictors.

For these first three predictors:

There is no reason to doubt that Lat, Height and Sea should all be included.

Also note the regression coefficient for Height altered by about 2 standard errors, which suggests that Sea is correcting for bias, all the more reason for including it.

This makes sense - sea level towns will mostly have a very low height, but there’ll also be an additional warming effect of being close to the sea.

Climate: Adding island

lm4 = lm(MnJlyTemp ~ Lat + Height + Sea + NorthIsland, data = climate)
lm4 |>
    summary()

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

Same conclusions as before, we should include NorthIsland

Including it has induced big changes in the coefficients (especially Lat) which again is evidence it is important.

Why do you think adding North vs South island is useful over and above Latitude? Wouldn’t Latitude do everything here??

Adding Rain

lm5 = lm(MnJlyTemp ~ Lat + Height + Sea + NorthIsland + Rain, data = climate)
lm5 |>
    summary()

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

Residuals:
    Min      1Q  Median      3Q     Max 
-1.2829 -0.5042 -0.1944  0.4422  3.4651 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept) 19.6651523  4.6317227   4.246 0.000194 ***
Lat         -0.3437001  0.1009517  -3.405 0.001900 ** 
Height      -0.0049792  0.0011322  -4.398 0.000127 ***
Sea          1.6435808  0.4802716   3.422 0.001814 ** 
NorthIsland  1.7682036  0.6430084   2.750 0.010003 *  
Rain         0.0003583  0.0002170   1.651 0.109182    
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.9271 on 30 degrees of freedom
Multiple R-squared:  0.9046,    Adjusted R-squared:  0.8887 
F-statistic:  56.9 on 5 and 30 DF,  p-value: 2.11e-14

The Rain variable is not significant (P=0.1) and \(S\) has gone up, which go against including Rain. However the adjusted R-squared has gone up. So we may decide that if our aim is to predict for new data, then we should include this variable in the model.

Adding Longitude

lm6 = lm(MnJlyTemp ~ Lat + Height + Sea + NorthIsland + Rain + Long, data = climate)
lm6 |>
    summary()

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

Residuals:
    Min      1Q  Median      3Q     Max 
-1.3360 -0.4832 -0.1712  0.4008  3.2814 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept)  6.8938252 21.1286658   0.326 0.746557    
Lat         -0.3272942  0.1053819  -3.106 0.004216 ** 
Height      -0.0050077  0.0011449  -4.374 0.000144 ***
Sea          1.6381187  0.4853578   3.375 0.002113 ** 
NorthIsland  1.5548897  0.7352242   2.115 0.043156 *  
Rain         0.0004002  0.0002295   1.744 0.091750 .  
Long         0.0701947  0.1132443   0.620 0.540196    
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.9368 on 29 degrees of freedom
Multiple R-squared:  0.9059,    Adjusted R-squared:  0.8864 
F-statistic: 46.51 on 6 and 29 DF,  p-value: 1.402e-13

At this point all the indications are bad: The P-value for Long is >0.5, the adjusted R-squared has gone down and S has gone up.

In conclusion we should include the first four variables, and optionally the fifth one, Rain.

LS0tDQp0aXRsZTogIkxlY3R1cmUgMjc6IFZhcmlhYmxlIFNlbGVjdGlvbiINCnN1YnRpdGxlOiAxNjEuMjUxIFJlZ3Jlc3Npb24gTW9kZWxsaW5nDQphdXRob3I6ICJQcmVzZW50ZWQgYnkgSm9uYXRoYW4gTWFyc2hhbGwgPEouQy5tYXJzaGFsbEBtYXNzZXkuYWMubno+IiAgDQpkYXRlOiAiV2VlayAxMCBvZiBTZW1lc3RlciAyLCBgciBsdWJyaWRhdGU6OnllYXIobHVicmlkYXRlOjpub3coKSlgIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICB0aGVtZTogeWV0aQ0KICAgIGhpZ2hsaWdodDogdGFuZ28NCiAgaHRtbF9ub3RlYm9vazoNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgdGhlbWU6IHlldGkNCiAgICBoaWdobGlnaHQ6IHRhbmdvDQogIGlvc2xpZGVzX3ByZXNlbnRhdGlvbjoNCiAgICB3aWRlc2NyZWVuOiB0cnVlDQogICAgc21hbGxlcjogdHJ1ZQ0KICB3b3JkX2RvY3VtZW50OiBkZWZhdWx0DQogIHNsaWR5X3ByZXNlbnRhdGlvbjogDQogICAgdGhlbWU6IHlldGkNCiAgICBoaWdobGlnaHQ6IHRhbmdvDQogIHBkZl9kb2N1bWVudDogZGVmYXVsdA0KLS0tDQoNCg0KDQoNCjwhLS0tIERhdGEgaXMgb24NCmh0dHBzOi8vci1yZXNvdXJjZXMubWFzc2V5LmFjLm56L2RhdGEvMTYxMjUxLw0KLS0tPg0KDQpgYGB7ciBzZXR1cCwgcHVybD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0NCmxpYnJhcnkoa25pdHIpDQpvcHRzX2NodW5rJHNldChkZXY9YygicG5nIiwgInBkZiIpKQ0Kb3B0c19jaHVuayRzZXQoZmlnLmhlaWdodD02LCBmaWcud2lkdGg9NywgZmlnLnBhdGg9IkZpZ3VyZXMvIiwgZmlnLmFsdD0idW5sYWJlbGxlZCIpDQpvcHRzX2NodW5rJHNldChjb21tZW50PSIiLCBmaWcuYWxpZ249ImNlbnRlciIsIHRpZHk9VFJVRSkNCm9wdGlvbnMoa25pdHIua2FibGUuTkEgPSAnJykNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShicm9vbSkNCmBgYA0KDQoNCjwhLS0tIERvIG5vdCBlZGl0IGFueXRoaW5nIGFib3ZlIHRoaXMgbGluZS4gLS0tPg0KCiMjIFZhcmlhYmxlIHNlbGVjdGlvbgoKSW4gcHJldmlvdXMgbGVjdHVyZXMgd2UgaGF2ZSBsb29rZWQgYXQgdGVzdHMgZm9yIHNpbmdsZSBleHBsYW5hdG9yeSB2YXJpYWJsZXMgYW5kIGdyb3VwcyBvZiBleHBsYW5hdG9yeSB2YXJpYWJsZXMuCgpPZnRlbiwgaG93ZXZlciwgYSBzdGF0aXN0aWNpYW4gd2lsbCBzaW1wbHkgd2FudCB0byBrbm93IHdoYXQgaXMgdGhlICAgICBiZXN0IGdyb3VwIG9mIGV4cGxhbmF0b3J5IHZhcmlhYmxlcyBmb3IgZGVzY3JpYmluZyB0aGUgcmVzcG9uc2UuCgpJbiB0aGlzIGxlY3R1cmUgd2Ugd2lsbCBjb25zaWRlciB2YXJpb3VzIGNyaXRlcmlhIGZvciBtb2RlbCBzZWxlY3Rpb24sIGFuZCBjb3ZlciBhbiBleGFtcGxlIG9uIGZpbmRpbmcgYSBzdWl0YWJsZSB2YXJpYWJsZSBzZXQgImJ5IGhhbmQiLgoKIyMgT3ZlcmZpdHRpbmcgYW5kIFVuZGVyZml0dGluZwoKV2UgYmVnaW4gYnkgY29uc2lkZXJpbmcgdGhlIGZvbGxvd2luZyBxdWVzdGlvbjogIFNob3VsZCBhbGwgdGhlIGV4cGxhbmF0b3J5IHZhcmlhYmxlcyBiZSB1c2VkLCBvciBzaG91bGQgc29tZSBiZSBvbWl0dGVkPwoKV2h5IG1pZ2h0IHdlIHdhbnQgdG8gb21pdCB2YXJpYWJsZXM/IAoKLQlQZXJoYXBzIHdlIHdhbnQgdG8gZGV0ZWN0IHZhcmlhYmxlcyB3aGljaCBhZmZlY3QgdGhlIHJlc3BvbnNlICBidXQgYXZvaWQgY29sbGVjdGluZyB1bm5lY2Vzc2FyeSBtZWFzdXJlbWVudHMgaW4gdGhlIGZ1dHVyZS4gVGhpcyBpcyBjYWxsZWQgdmFyaWFibGUgc2NyZWVuaW5nCgotCVBlcmhhcHMgd2Ugd2FudCB0byBwcmVkaWN0IGZyb20gdGhlIG1vZGVsLiBPdXIgcHJlZGljdGlvbnMgd2lsbCBiZSBsZXNzIGFjY3VyYXRlIGlmIHRoZSBtb2RlbCBpcyBpbmNvcnJlY3RseSBzcGVjaWZpZWQuCgkKV2UgZmlyc3QgY29uc2lkZXIgdGhlIHJpc2tzIGFuZCBiZW5lZml0cyBvZiBpbmNsdWRpbmcgYSBwcmVkaWN0b3IgdGhhdCBtaWdodCBoYXZlIGNvZWZmaWNpZW50ICRcYmV0YT0wJC4KCiMjICBEcm9wcGluZyBvciBJbmNsdWRpbmcgVmFyaWFibGVzIHRoYXQgaGF2ZSAkXGJldGE9MCQKClN1cHBvc2Ugd2UgaGF2ZSBhIHJlZ3Jlc3Npb24gbW9kZWwgd2l0aCBzZXZlcmFsIHZhcmlhYmxlcy4gIFdlIG1pZ2h0IHN1c3BlY3Qgb25lIGhhcyByZWdyZXNzaW9uIGNvZWZmaWNpZW50ICRcYmV0YT0wJC4gIFNob3VsZCB3ZSBkcm9wIGl0PwoKU29tZSBtYXRoZW1hdGljYWwgdGhlb3J5IHNob3dzIHRoYXQgaWYgd2Ugb21pdCBhIHZhcmlhYmxlIHdoaWNoICh0cnVseSkgaGFzIHJlZ3Jlc3Npb24gY29lZmZpY2llbnQgICRcYmV0YT0wJCAgdGhlbgoKLSBWYXJpYW5jZXMgb2YgdGhlIHJlbWFpbmluZyByZWdyZXNzaW9uIGNvZWZmaWNpZW50cyBhcmUgcmVkdWNlZAoKLSBWYXJpYW5jZXMgb2YgcHJlZGljdGlvbnMgZnJvbSB0aGUgbW9kZWwgIGF0IGFueSBwb2ludCAkeF8wJCAgYXJlIHJlZHVjZWQuIAoKQm90aCB0aGVzZSB0aGluZ3MgYXJlIGdvb2QuCgpDb252ZXJzZWx5IGlmIHdlIGluY2x1ZGUgYSB2YXJpYWJsZSB3aG9zZSBjb2VmZmljaWVudCAkXGJldGE9MCQgdGhpcyAgaW5jcmVhc2VzIHRoZXNlIHZhcmlhbmNlcyB1bm5lY2Vzc2FyaWx5LiBUaGlzIGlzIGNhbGxlZCAqKm92ZXJmaXR0aW5nKiouIFdlIHdhbnQgdG8gYXZvaWQgdGhpcy4KCiMjIERyb3BwaW5nIG9yIEluY2x1ZGluZyBWYXJpYWJsZXMgdGhhdCBoYXZlICRcYmV0YSBcbmUgMCQKCk9uIHRoZSBvdGhlciBoYW5kIHN1cHBvc2Ugd2UgbWFrZSBhIG1pc3Rha2UgYW5kIG9taXQgYSB2YXJpYWJsZSB0aGF0IGhhcyByZWdyZXNzaW9uIGNvZWZmaWNpZW50ICRcbmUgMCQuICAgCgpUaGVuIHdlIGhhdmUgdGhlIG9wcG9zaXRlIHByb2JsZW0sIGNhbGxlZCAqKnVuZGVyZml0dGluZyoqLiAgTWF0aGVtYXRpY2FsIHRoZW9yeSBzaG93cyB0aGUgY29uc2VxdWVuY2Ugb2YgdW5kZXJmaXR0aW5nIGlzIHRoYXQgCgotCWlmIHRoZSB3cm9uZ2x5LW9taXR0ZWQgdmFyaWFibGVzIGFyZSBjb3JyZWxhdGVkIHdpdGggdGhlIHJlbWFpbmluZyB2YXJpYWJsZXMgdGhlbiB0aGUgZXhwZWN0ZWQgdmFsdWVzIG9mIHRoZSByZW1haW5pbmcgcmVncmVzc2lvbiBjb2VmZmljaWVudHMgJFxiZXRhXzAsXGJldGFfMSwuLi5cYmV0YV97cC0xfSQgYXJlICoqYmlhc2VkKiouIChpLmUuIG1heSBiZSBhIHRvbyBiaWcgb3IgdG9vIHNtYWxsKS4KCi0gV2hldGhlciBvciBub3QgdGhlIG9taXR0ZWQgdmFyaWFibGVzIGFyZSBjb3JyZWxhdGVkIHdpdGggdGhlIGV4aXN0aW5nIG9uZXMsIHRoZSBwcmVkaWN0aW9ucyAkXGhhdCB5X2kkIGFyZSBiaWFzZWQuCgpCb3RoIHRoZXNlIHRoaW5ncyBhcmUgYmFkIQoKKipJbiBwcmFjdGljZSB3ZSBkbyBub3Qga25vdyBpZiBwYXJhbWV0ZXJzIGFyZSB6ZXJvLioqIFdlIGNvdWxkIHVzZSBhIGh5cG90aGVzaXMgdGVzdCB0byBoZWxwIHVzIGRlY2lkZSwgYnV0IHRoaXMgaXMgbm90IGEgZGVmaW5pdGl2ZSBhbnN3ZXIuCgojIyBBIE51bWVyaWNhbCBJbGx1c3RyYXRpb24gb2YgVW5kZXIgYW5kIE92ZXJmaXR0aW5nCgpJbiB0aGlzIGFydGlmaWNpYWwgZXhhbXBsZSwgd2UgY29uc2lkZXIgYW4gaW5kdXN0cmlhbCBwcm9jZXNzIHdob3NlIFlpZWxkIGlzIHRob3VnaHQgIHRvIGRlcGVuZCBvbiB0aGUgcHJvY2VzcyB0ZW1wZXJhdHVyZSBhdCBzdGFnZSBBIG9mIHRoZSBwcm9jZXNzLCBhbmQgcG9zc2libHkgYWxzbyBvbiB0aGUgdGVtcGVyYXR1cmUgYXQgc3RhZ2UgQi4gICAKCmkuZS4gIFdlIGNvbnNpZGVyIHRoZSBtb2RlbCAKJCQgWT1cYmV0YV8wICsgXGJldGFfMSBBKyBcYmV0YV8yIEIgK1x2YXJlcHNpbG9uLiQkCgkKV2Ugd2lsbCBhc3N1bWUgdGhlIHZhbHVlcyBvZiAkQSQgYW5kICRCJCBhbmQgJFx2YXJlcHNpbG9uJCBhcmUgZ2l2ZW4gaW4gdGhlIGRhdGEgYmVsb3cuICBUaGUgZXJyb3JzIGFyZSByYW5kb20gJFx2YXJlcHNpbG9uIFxzaW0gXG1ib3h7Tm9ybWFsfSgwLCAxKSQuCgpgciB4ZnVuOjplbWJlZF9maWxlKCIuLi8uLi9kYXRhL3NpbXVsYXRpb24xLmNzdiIpYCAKCmBgYHtyIHJlYWQgU2ltdWxhdGlvbjEsIGV2YWw9LTEsIGVjaG89LTIsIG1lc3NhZ2U9RkFMU0V9CnNpbSA9IHJlYWQuY3N2KCJzaW11bGF0aW9uMS5jc3YiLGhlYWRlcj1UUlVFKQpzaW0gPSByZWFkLmNzdigiLi4vLi4vZGF0YS9zaW11bGF0aW9uMS5jc3YiLGhlYWRlcj1UUlVFKQpgYGAKCgpXaGF0IHdlIHdhbnQgdG8ga25vdyBpcywgd2hhdCBhcmUgdGhlIGltcGxpY2F0aW9ucyBvZiB1c2luZyBhbiBpbmNvcnJlY3QgbW9kZWwsIAlpLmUuIGluY29ycmVjdCBhc3N1bXB0aW9ucyBhYm91dCB0aGUgJFxiZXRhJHMuIFRvIHVuZGVyc3RhbmQgdGhlIGltcGxpY2F0aW9ucywgd2Ugc2ltdWxhdGUgdHdvIHNjZW5hcmlvcy4gCgojIyBTY2VuYXJpbyAxOiAkXGJldGFfMD01MCQsICRcYmV0YV8xPTEwJCBhbmQgJFxiZXRhXzI9MCQuCgpGb3IgdGhpcyBpbGx1c3RyYXRpb24sIHRoZSBjb3JyZWN0IG1vZGVsIGRvZXNuJ3QgZGVwZW5kIG9uICRCJCBhdCBhbGw6CiQkWSAgPSAgNTAgKyAxMCBBICsgXHZhcmVwc2lsb24kJAoKVGhlIGZvbGxvd2luZyBzaG93cyB0aGUgcmVzdWx0IG9mIG1vZGVsbGluZyAkWSQgYnkgKDEpICRBJCBhbG9uZSBhbmQgICgyKSBieSAkQSQgYW5kICRCJC4KCmBgYHtyIG92ZXJmaXR0aW5nfQpkYXQgPC0gc2ltIHw+IG11dGF0ZShZID0gNTAgKyAxMCpBICsgZXBzaWxvbikKbG0xID0gbG0oWSB+IEEsIGRhdGE9ZGF0KQpsbTIgPSBsbShZIH4gQSArIEIsIGRhdGE9ZGF0KQpsc3QobG0xLCBsbTIpIHw+IG1hcF9kZnIodGlkeSwgLmlkPSdtb2RlbCcpCmBgYAoKQWRkaW5nIHRoZSB1bm5lY2Vzc2FyeSB2YXJpYWJsZSBkb2Vzbid0IGludHJvZHVjZSBiaWFzICgkXGhhdFxiZXRhXzEgXGFwcHJveCAxMCQpLCBidXQgdGhlIHN0YW5kYXJkIGVycm9yIG9mICRcaGF0XGJldGFfMSQgaXMgaGlnaGVyIGluIHRoZSBtaXNzcGVjaWZpZWQgbW9kZWwuCgojIyBTY2VuYXJpbyAyOiAkXGJldGFfMD01MCQsICRcYmV0YV8xPTUkIGFuZCAkXGJldGFfMj01JC4KCldlIGNvbnNpZGVyIHRoZSBtb2RlbCB3aGVyZSAkWSQgZGVwZW5kcyBvbiBib3RoICRBJCBhbmQgJEIkLAokJAlZICA9ICA1MCArIDUgQSArIDUgQiArIFx2YXJlcHNpbG9uICQkCgpgYGB7ciB1bmRlcmZpdHRpbmd9CmRhdCA8LSBzaW0gfD4gbXV0YXRlKFkgPSA1MCArIDUqQSArIDUqQiArIGVwc2lsb24pCmxtMSA9IGxtKFkgfiBBLCBkYXRhPWRhdCkKbG0yID0gbG0oWSB+IEEgKyBCLCBkYXRhPWRhdCkKbHN0KGxtMSwgbG0yKSB8PiBtYXBfZGZyKHRpZHksIC5pZD0nbW9kZWwnKQpgYGAKCkluIHRoZSBmaXJzdCBtb2RlbCwgJEIkIGlzIHdyb25nbHkgaWdub3JlZCBhbmQgJEEkIGlzIGJvdGggYmlhc2VkIGFuZCBoYXMgYSBsYXJnZXIgc3RhbmRhcmQgZXJyb3IuIEluIHRoZSBzZWNvbmQgbW9kZWwsIHRoZSB2YWx1ZXMgb2YgJFxoYXRcYmV0YV8xJCBhbmQgJFxoYXRcYmV0YV8yJCBhcmUgY2xvc2UgdG8gdGhlIHRydWUgb25lcyBhbmQgdGhlIHN0YW5kYXJkIGVycm9ycyBhcmUgdGhlIHNhbWUgYXMgaW4gdGhlIHNlY29uZCBhbmFseXNpcyBvZiBTY2VuYXJpbyAxLgoKIyMKCkluIHN1bW1hcnksIGlmIHdlIG9taXQgYSBuZWVkZWQgdmFyaWFibGUgdGhlbiB3ZSBtYXkgaW50cm9kdWNlIGJpYXMgaW50byBvdXIgZXN0aW1hdGlvbi4KCQpUaGUgYmlnIHByb2JsZW0gd2l0aCBiaWFzIGlzIHRoYXQgdGhlcmUgbWF5IGJlIG5vIHNpZ24gdGhhdCB3ZSBoYXZlIGEgbWlzdGFrZS4gCgpJbiBzb21lIGNhc2VzIHdlIGRvbid0IGV2ZW4gKmhhdmUqIHRoZSBuZWVkZWQgdmFyaWFibGUsIHNvIHdlIGNhbid0IHRyeSBpdCBpbiB0aGUgbW9kZWwuIAoKQXQgbGVhc3QgaW4gY2FzZSAxLCB3aGVuIHdlIHdyb25nbHkgZW50ZXIgYW4gdW5uZWNlc3NhcnkgdmFyaWFibGUsIGl0IGRvZXNuJ3QgYmlhcyBvdXIgZXN0aW1hdGVzLCBqdXN0IGluY3JlYXNlcyBvdXIgc3RhbmRhcmQgZXJyb3JzLiBTbyBhdCBsZWFzdCB3ZSBrbm93IGV4YWN0bHkgaG93IGJhZCB0aGluZ3MgYXJlLiBCdXQgd2l0aCBhbiBvbWl0dGVkIHZhcmlhYmxlIHdlIGRvbid0IGtub3cgaG93IGJhZCB0aGluZ3MgYXJlLgoJCkZvciB0aGlzIHJlYXNvbiwgd2UgbWF5IGRlY2lkZSB0byBlcnIgb24gdGhlIHNpZGUgb2YgY2F1dGlvbiBhbmQgYWRkIGluIHZhcmlhYmxlcyBldmVuIGlmIHdlIGFyZSB1bmNlcnRhaW4gYWJvdXQgdGhlaXIgcmVsZXZhbmNlLiAgVGhlbiBhdCBsZWFzdCB3ZSBjYW4gYXZvaWQgYmlhcy4gCgojIyBNb2RlbCBTZWxlY3Rpb246IEJpYXMgYW5kIFZhcmlhbmNlCgpNb2RlbCBzZWxlY3Rpb24sIHRoZW4sIGNvbWVzIGRvd24gdG8gYmFsYW5jaW5nIHRoZSBlZmZlY3RzIG9mIHZhcmlhbmNlIGFuZCBiaWFzLgoKLSBJZiB3ZSBvbWl0IGEgdmFyaWFibGUsIGl0IG1heSBkcmFtYXRpY2FsbHkgZGVjcmVhc2UgdGhlIHZhcmlhbmNlIG9mIHRoZSBvdGhlciBwYXJhbWV0ZXIgZXN0aW1hdGVzLiBUaGlzIGlzIGEgcGx1cy4gCgotIEJ1dCBpZiB0aGUgdmFyaWFibGUgaXMgaW1wb3J0YW50LCB0aGVuIHRoZSBvdGhlciBwYXJhbWV0ZXIgZXN0aW1hdGVzIG1heSBiZSBiaWFzZWQuICBUaGlzIGlzIGEgbWludXMuIAoKU28gd2hhdCBzaG91bGQgd2UgY2hvb3NlPyAgVGhlcmUgaXMgbm8gc2V0dGxlZCBydWxlIGZvciBldmVyeSBjaXJjdW1zdGFuY2UsIGJ1dCBpbiBnZW5lcmFsIHdlIHNob3VsZCBwcm9iYWJseSBiZSBtb3JlIGNvbmNlcm5lZCB0byBhdm9pZCBiaWFzIChlc3BlY2lhbGx5IHNpbmNlIHdlIGRvbid0IGtub3cgaG93IGJhZCB0aGlzIGlzISkgdGhhbiB0byBhdm9pZCBhIHNtYWxsIGluY3JlYXNlIGluIHZhcmlhbmNlIChhdCBsZWFzdCB3ZSBkbyBrbm93IGhvdyBiYWQgaXQgaXMgLSB3ZSBjYW4gc2VlIHRoZSBzdGFuZGFyZCBlcnJvcnMuKQoKQ29uc2VxdWVudGx5IHdlIG1heSBkZWNpZGUgdG8gZXJyIG9uIHRoZSBzaWRlIG9mIGluY2x1ZGluZyB2YXJpYWJsZXMgd2l0aCBQLXZhbHVlcyBhIGxpdHRsZSAgYmlnZ2VyIHRoYW4gMC4wNSwgKmVzcGVjaWFsbHkgaWYgdGhleSBzZWVtIHRvIGluZHVjZSBhIHNpemVhYmxlIGNoYW5nZSBpbiB0aGUgb3RoZXIgY29lZmZpY2llbnQgZXN0aW1hdGVzLiogICBUaGlzIGlzIGFub3RoZXIgdGhpbmcgdG8gd2F0Y2ggb3V0IGZvciBpbiBtb2RlbCBzZWxlY3Rpb24uIAoKIyMgUmV2aWV3IG9mIE1vZGVsIFNlbGVjdGlvbiBDcml0ZXJpYQoKVGhlcmUgYXJlIGEgbnVtYmVyIG9mIG1lYXN1cmVzIHdlIGNhbiB1c2UgZm9yIG1vZGVsIHNlbGVjdGlvbjoKCi0gQ29lZmZpY2llbnQgb2YgZGV0ZXJtaW5hdGlvbiAkUl4yJAoKLSBBZGp1c3RlZCBDb2VmZmljaWVudCBvZiBkZXRlcm1pbmF0aW9uICRSXjJfe0Fkan0kCgotIFJlc2lkdWFsIFN0YW5kYXJkIEVycm9yICRTJAoKLSAkUCQtdmFsdWVzIG9mIGluZGl2aWR1YWwgY29lZmZpY2llbnRzCgpFYWNoIG9mIHRoZXNlIGFyZSBzbGlnaHRseSBkaWZmZXJlbnQsIHNvIGl0IHBheXMgdG8gY29uc2lkZXIgbW9yZSB0aGFuIG9uZS4KCiMjIENvZWZmaWNpZW50IG9mIGRldGVybWluYXRpb24gJFJeMiQKClJlY2FsbCB0aGF0IHRoaXMgaXMgdGhlIHByb3BvcnRpb24gb2YgdG90YWwgdmFyaWF0aW9uICB3aGljaCBpcyBleHBsYWluZWQgYnkgdGhlIG1vZGVsLiAoQWx0ZXJuYXRpdmVseSwgMSBtaW51cyB0aGUgcmF0aW8gb2YgdW5leHBsYWluZWQgdmFyaWF0aW9uIHRvIHRvdGFsIHZhcmlhdGlvbik6CiQkIFJeMiA9IFxmcmFje1NTX3tSZWdufX17U1NUfSAgPSAxIC0gXGZyYWN7XHN1bSh5X2ktXGhhdCB5X2kpXjJ9e1xzdW0oeV9pLVxiYXIgeSleMn0uICQkCiRSXjIkIGlzIHVzZWZ1bCBmb3IgY29tcGFyaW5nIHR3byBtb2RlbHMgd2l0aCB0aGUgKipzYW1lKiogbnVtYmVyIG9mIHJlZ3Jlc3Npb24gcGFyYW1ldGVycy4gICBJZiBtb2RlbHMgaGF2ZSBkaWZmZXJlbnQgbnVtYmVycyBvZiByZWdyZXNzaW9uIHBhcmFtZXRlcnMgd2UgdXNlIHRoZSBhZGp1c3RlZCB2ZXJzaW9uLgoKIyMgQWRqdXN0ZWQgQ29lZmZpY2llbnQgb2YgZGV0ZXJtaW5hdGlvbiAkUl4yX3tBZGp9JAoKUmVjYWxsIHRoYXQgdGhpcyBpcyAxIG1pbnVzIHRoZSByYXRpbyBvZiBNZWFuIFNxdWFyZSBFcnJvciB0byBNZWFuIFNxdWFyZSBUb3RhbDogCiQkIFJeMl97QWRqfSA9IDEgLSBcZnJhY3tNU0V9e01TVH0gID0gMSAtIFxmcmFje1xzdW0oeV9pLVxoYXQgeV9pKV4yLyhuLXApfXtcc3VtKHlfaS1cYmFyIHkpXjIvKG4tMSl9LiQkCldoZW4gY29uc2lkZXJpbmcgYWRkaW5nIGEgdmFyaWFibGUgdG8gYSByZWdyZXNzaW9uLCB0aGUgJFJeMl97QWRqfSQgZ29lcyB1cCBpZiB0aGUgdmFyaWFibGUgaXMgIndvcnRoIiBhdCBsZWFzdCBvbmUgcm93IG9mIGRhdGEgKG9uZSBkZWdyZWUgb2YgZnJlZWRvbSksIHdoaWNoIGlzIGEgcHJldHR5IGxvdyBiYXIgdG8gY3Jvc3MuCgpCdXQgYXQgbGVhc3QgaWYgYSB2YXJpYWJsZSBjYW4ndCBtZWV0IHRoYXQgcnVsZSB0aGVuIHdlIGtub3cgdG8gZXhjbHVkZSBpdC4KCiMjIFJlc2lkdWFsIFN0YW5kYXJkIEVycm9yICRTJAoKVGhpcyBpcyB0aGUgc3RhbmRhcmQgZGV2aWF0aW9uIG9mIHRoZSByZXNpZHVhbHMsIAokJCBTID0gXGZyYWN7MX17bi1wfVxzdW17KHlfaSAtIFxoYXQgeV9pKV4yfSAkJApvciBpbiBvdGhlciB3b3JkcyB0aGUgc3RhbmRhcmQgZGV2aWF0aW9uIG9mIGhvdyB0aGUgJHlfaSRzIHZhcnkgYXJvdW5kIHRoZSBtb2RlbCBwcmVkaWN0aW9ucy4gV2UgbWlnaHQgY2hvb3NlIHRvIGluY2x1ZGUgYSB2YXJpYWJsZSBpZiBpdCByZWR1Y2VzIHRoZSAkUyQuCgojIyAkUCQtdmFsdWUgZm9yIGluZGl2aWR1YWwgY29lZmZpY2llbnRzCgpXZSB1c3VhbGx5IHByZWZlciBtb2RlbHMgdGhhdCBvbmx5IGluY2x1ZGUgdmFyaWFibGVzIHdpdGggY29lZmZpY2llbnQgJFAkLXZhbHVlIGlzIHNtYWxsIChlLmcuICQ8IDAuMDUkKS4KCkhvd2V2ZXIgdGhlICIwLjA1IiBjcml0ZXJpb24gaXMgc29tZXdoYXQgYXJiaXRyYXJ5IGFuZCBvY2Nhc2lvbmFsbHkgd2UgYWxsb3cgaW4gdmFyaWFibGVzIHdpdGggc2xpZ2h0bHkgaGlnaGVyICRQJC12YWx1ZXMgdG8gcG90ZW50aWFsbHkgcmVkdWNlIGJpYXMuCgojIyBFeGFtcGxlOiAgTW9kZWwgU2VsZWN0aW9uIGZvciBDbGltYXRlIERhdGEKCldlIHdpc2ggdG8gbW9kZWwgdGhlIG1lYW4gdGVtcGVyYXR1cmUgaW4gSnVseSAod2ludGVyKSBpbiBBb3RlYXJvYSBOZXcgWmVhbGFuZCB1c2luZyBkYXRhIGZyb20gMzYgdG93bnMuIFdlIGhhdmUgaW5mb3JtYXRpb24gb24gbG9jYXRpb24gKGxhdGl0dWRlLCBsb25naXR1ZGUsIGhlaWdodCAoZWxldmF0aW9uKSwgd2hldGhlciB0aGV5J3JlIGJ5IHRoZSBzZWEgb3IgaW4gdGhlIE5vcnRoIGlzbGFuZCkgYXMgd2VsbCBhcyBjbGltYXRlIGluZm9ybWF0aW9uIChtZWFuIHRlbXBlcmF0dXJlIGluIEphbnVhcnksIHRvdGFsIHN1bnNoaW5lIGhvdXJzIGFuZCB0b3RhbCByYWluZmFsbCkuCgpgciB4ZnVuOjplbWJlZF9maWxlKCIuLi8uLi9kYXRhL2NsaW1hdGUuY3N2IilgIAoKYGBge3IgcmVhZCBjbGltYXRlLGV2YWw9LTEsIGVjaG89LTIsIG1lc3NhZ2U9RkFMU0V9CmNsaW1hdGUgPSByZWFkX2NzdigiY2xpbWF0ZS5jc3YiKQpjbGltYXRlID0gcmVhZF9jc3YoIi4uLy4uL2RhdGEvY2xpbWF0ZS5jc3YiKQpjbGltYXRlCmBgYAoKIyMgQ2xpbWF0ZSBFeHBsb3JhdG9yeSBEYXRhIEFuYWx5c2lzCgpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTR9CmNsaW1hdGUgfD4KICBwaXZvdF9sb25nZXIoLWMoUGxhY2UsIE1uSmx5VGVtcCkpIHw+CiAgZ2dwbG90KCkgKwogIGdlb21fcG9pbnQobWFwcGluZz1hZXMoeD12YWx1ZSwgeT1NbkpseVRlbXApKSArCiAgZmFjZXRfd3JhcCh2YXJzKG5hbWUpLCBzY2FsZXMgPSAnZnJlZV94JywgbmNvbD00KQpgYGAKCiMjIEhpZ2hlciB3aW50ZXIgdGVtcGVyYXR1cmUgYXNzb2NpYXRpb25zCgotIExvd2VyIGVsZXZhdGlvbnMgKGhlaWdodCkKLSBMb3dlciBsYXRpdHVkZXMgKGZ1cnRoZXIgbm9ydGgpCi0gSGlnaGVyIGxvbmdpdHVkZXMgKGZ1cnRoZXIgZWFzdCAtIHJlY2FsbCBob3cgQW8vTlogaXMgb3JpZW50ZWQgb24gYSBtYXAgLSBwb3NzaWJseSBjb3JyZWxhdGlvbiB3aXRoIGxhdGl0dWRlLCB3aWxsIGNoZWNrIG5leHQhKQotIEhpZ2hlciBzdW1tZXIgdGVtcGVyYXR1cmVzCi0gTm9ydGggaXNsYW5kIChjb3VsZCBqdXN0IGJlIGxhdGl0dWRlPykKLSBJbmNyZWFzZWQgcmFpbmZhbGwgLSB1cCB0byBhIHBvaW50ISAoc3VidHJvcGljYWwgdnMgcmFpbnkgd2VzdGNvYXN0IC0gaW50ZXJhY3Rpb24gd2l0aCBJc2xhbmQvbGF0aXR1ZGU/PykKLSBDbG9zZW5lc3MgdG8gdGhlIHNlYQotIEluY3JlYXNlZCBzdW5zaGluZSBob3VycwoKTWFueSBvZiB0aGVzZSBhcmUgbGlrZWx5IGNvcnJlbGF0ZWQuCgojIyBDbGltYXRlOiBMYXRpdHVkZS9Mb25naXR1ZGUgYW5kIE5vcnRoIHZzIFNvdXRoCgpgYGB7cn0KZ2dwbG90KGNsaW1hdGUpICsKICBnZW9tX3BvaW50KG1hcHBpbmc9YWVzKHg9TG9uZywgeT0tTGF0LCBzaGFwZT1hc19mYWN0b3IoTm9ydGhJc2xhbmQpLCBjb2w9TW5KbHlUZW1wKSkgKwogIGdlb21fdGV4dChtYXBwaW5nPWFlcyh4PUxvbmcsIHk9LUxhdCwgbGFiZWw9UGxhY2UpLCBzaXplPTIsIGhqdXN0PSdyaWdodCcsIG51ZGdlX3g9MC4xLCBudWRnZV95PTAuMikgKwogIGNvb3JkX2VxdWFsKCkKYGBgCgojIyBDbGltYXRlOiBMYXRpdHVkZS9Mb25naXR1ZGUgYW5kIE5vcnRoIHZzIFNvdXRoCgpPaywgc28gd2UgY2FuIHNlZSB0aGF0IHRoZSB0ZW1wZXJhdHVyZSBpcyBiZWluZyBkcml2ZW4gYnkgbGF0aXR1ZGUgKGZ1cnRoZXIgbm9ydGggaXMgd2FybWVyKSAtIHRoZSBsb25naXR1ZGUgZWZmZWN0IGlzIHBvc3NpYmx5IGp1c3QgZHVlIHRvIG9yaWVudGF0aW9uLiBJdCdzIGNsZWFyIHRoZXJlJ3MgYW4gZWxldmF0aW9uIChoZWlnaHQpIGVmZmVjdCBhcyB3ZWxsLCB0aG91Z2ggdGhhdCBpcyBwb3NzaWJseSBjb25mb3VuZGVkIHdpdGggd2hldGhlciB0aGUgdG93biBpcyBjbG9zZSB0byB0aGUgc2VhIChpdCBjYW4ndCByZWFsbHkgYmUgYm90aCEpCgpTbyB3ZSdkIGV4cGVjdCBzb21lIGNvbGxpbmVhcml0eSBoZXJlIGFuZCBmaWd1cmluZyBvdXQgd2hpY2ggYXJlIHRoZSBiZXN0IHZhcmlhYmxlcyB0byBiZSB1c2VkIG1pZ2h0IHRha2UgYSBiaXQgb2YgcGxheWluZyEKCldlJ2xsIHN0YXJ0IHdpdGggTGF0aXR1ZGUsIHRoZW4gYWRkIGluIEhlaWdodCBhbmQgU2VhOgoKYGBge3J9CmxtMSA9IGxtKCBNbkpseVRlbXAgfiBMYXQsIGRhdGE9Y2xpbWF0ZSkKbG0yID0gbG0oIE1uSmx5VGVtcCB+IExhdCArIEhlaWdodCwgZGF0YT1jbGltYXRlKQpsbTMgPSBsbSggTW5KbHlUZW1wIH4gTGF0ICsgSGVpZ2h0KyBTZWEsIGRhdGE9Y2xpbWF0ZSkKYGBgCgojIyBDbGltYXRlOiBtb2RlbCBvdXRwdXQKCmBgYHtyfQpsbTEgfD4gc3VtbWFyeSgpCmBgYAoKIyMKCmBgYHtyfQpsbTIgfD4gc3VtbWFyeSgpCmBgYAoKIyMKCmBgYHtyfQpsbTMgfD4gc3VtbWFyeSgpCmBgYAoKIyMgQ2xpbWF0ZTogRmlyc3QgdGhyZWUgcHJlZGljdG9ycy4KCkZvciB0aGVzZSBmaXJzdCB0aHJlZSBwcmVkaWN0b3JzOgoKIC0gVGhleSAgaGF2ZSBzaWduaWZpY2FudCBwLXZhbHVlcwogLSAkUyQgaGFzIGdvbmUgZG93biBlYWNoIHRpbWUKIC0gVGhlIGFkanVzdGVkICRSXjIkIGFuZCBoYXMgZ29uZSB1cCBlYWNoIHRpbWUuCiAKVGhlcmUgaXMgbm8gcmVhc29uIHRvIGRvdWJ0IHRoYXQgYExhdGAsIGBIZWlnaHRgIGFuZCBgU2VhYCBzaG91bGQgYWxsIGJlIGluY2x1ZGVkLiAgIAoKQWxzbyBub3RlIHRoZSByZWdyZXNzaW9uIGNvZWZmaWNpZW50IGZvciBgSGVpZ2h0YCBhbHRlcmVkIGJ5IGFib3V0IDIgc3RhbmRhcmQgZXJyb3JzLCB3aGljaCBzdWdnZXN0cyB0aGF0IGBTZWFgIGlzIGNvcnJlY3RpbmcgZm9yIGJpYXMsIGFsbCB0aGUgbW9yZSByZWFzb24gZm9yIGluY2x1ZGluZyBpdC4KClRoaXMgbWFrZXMgc2Vuc2UgLSBzZWEgbGV2ZWwgdG93bnMgd2lsbCBtb3N0bHkgaGF2ZSBhIHZlcnkgbG93IGhlaWdodCwgYnV0IHRoZXJlJ2xsIGFsc28gYmUgYW4gYWRkaXRpb25hbCB3YXJtaW5nIGVmZmVjdCBvZiBiZWluZyBjbG9zZSB0byB0aGUgc2VhLgoKIyMgQ2xpbWF0ZTogQWRkaW5nIGlzbGFuZAoKYGBge3IgZm91cnRoIHZhcmlhYmxlfQpsbTQgPSBsbSggTW5KbHlUZW1wIH4gTGF0KyBIZWlnaHQrIFNlYSArIE5vcnRoSXNsYW5kLCBkYXRhPWNsaW1hdGUpCmxtNCB8PiBzdW1tYXJ5KCkKYGBgCgojIwoKU2FtZSBjb25jbHVzaW9ucyBhcyBiZWZvcmUsIHdlIHNob3VsZCBpbmNsdWRlIGBOb3J0aElzbGFuZGAKCkluY2x1ZGluZyBpdCBoYXMgaW5kdWNlZCBiaWcgY2hhbmdlcyBpbiB0aGUgY29lZmZpY2llbnRzIChlc3BlY2lhbGx5IGBMYXRgKSB3aGljaCBhZ2FpbiBpcyBldmlkZW5jZSBpdCBpcyBpbXBvcnRhbnQuCgoqKldoeSBkbyB5b3UgdGhpbmsgYWRkaW5nIE5vcnRoIHZzIFNvdXRoIGlzbGFuZCBpcyB1c2VmdWwgb3ZlciBhbmQgYWJvdmUgTGF0aXR1ZGU/IFdvdWxkbid0IExhdGl0dWRlIGRvIGV2ZXJ5dGhpbmcgaGVyZT8/KioKCiMjIEFkZGluZyBSYWluCgpgYGB7ciBmaWZ0aCB2YXJpYWJsZX0KbG01ID0gbG0oIE1uSmx5VGVtcCB+IExhdCsgSGVpZ2h0KyBTZWEgKyBOb3J0aElzbGFuZCsgUmFpbiwgZGF0YT1jbGltYXRlKQpsbTUgfD4gc3VtbWFyeSgpCmBgYAoKIyMKClRoZSBgUmFpbmAgdmFyaWFibGUgaXMgbm90IHNpZ25pZmljYW50IChQPTAuMSkgYW5kICRTJCBoYXMgZ29uZSB1cCwgd2hpY2ggZ28gYWdhaW5zdCBpbmNsdWRpbmcgYFJhaW5gLiAgSG93ZXZlciB0aGUgYWRqdXN0ZWQgUi1zcXVhcmVkIGhhcyBnb25lIHVwLiAgU28gd2UgbWF5IGRlY2lkZSB0aGF0IGlmIG91ciBhaW0gaXMgdG8gcHJlZGljdCBmb3IgbmV3IGRhdGEsIHRoZW4gd2Ugc2hvdWxkIGluY2x1ZGUgdGhpcyB2YXJpYWJsZSBpbiB0aGUgbW9kZWwuCgojIyBBZGRpbmcgTG9uZ2l0dWRlCgpgYGB7ciBzaXh0aCB2YXJpYWJsZX0KbG02ID0gbG0oIE1uSmx5VGVtcCB+IExhdCsgSGVpZ2h0KyBTZWEgKyBOb3J0aElzbGFuZCsgUmFpbiArIExvbmcsIGRhdGE9Y2xpbWF0ZSkKbG02IHw+IHN1bW1hcnkoKQpgYGAKCiMjCgpBdCB0aGlzIHBvaW50IGFsbCB0aGUgaW5kaWNhdGlvbnMgYXJlIGJhZDogIFRoZSBQLXZhbHVlIGZvciBgTG9uZ2AgaXMgPjAuNSwgdGhlIGFkanVzdGVkIFItc3F1YXJlZCBoYXMgZ29uZSBkb3duIGFuZCBTIGhhcyBnb25lIHVwLgoKSW4gY29uY2x1c2lvbiB3ZSBzaG91bGQgaW5jbHVkZSB0aGUgZmlyc3QgZm91ciB2YXJpYWJsZXMsIGFuZCBvcHRpb25hbGx5IHRoZSBmaWZ0aCBvbmUsIGBSYWluYC4=