Statistical models allow us to answer questions using data.
The validity of the conclusions that we reach is contingent upon the
appropriateness of the models that we use.
Once you have fitted a statistical model to data, it is therefore
important to check the assumptions underlying the model.
The tools to check these assumptions are often referred to as
model diagnostics.
We shall look at assumption checking for simple linear regression in
this lecture.
Assumptions for Simple Linear Regression
Recall that the linear regression model is \[Y_i = \beta_0 + \beta_1 x_i +
\varepsilon_i\]
where we make the following assumptions:
A1. \(E[\varepsilon_i] = 0\) for i=1, …
,n.
A2. \(\varepsilon_1, \ldots ,\varepsilon_n\) are
independent.
A3. var\((\varepsilon_i) = \sigma^2\) for
i=1,…,n (homoscedasticity).
A4. \(\varepsilon_1, \ldots ,\varepsilon_n\) are
normally distributed.
Class Discussion: Interpret these assumptions, and think about
situations in which each might fail.
Raw Residuals
The residuals (or raw residuals), \[\begin{aligned} e_i &=& y_i - \hat
\mu_i\\ &=& y_i - \hat \beta_0 - \hat \beta_1
x_i~~~~~~~~~(i=1,\ldots ,n)\end{aligned}\] are a fundamental
diagnostic aid.
These residuals are a kind of sample version of the error random
variables \(\varepsilon_1,\ldots,\varepsilon_n\).
Consequently we can test the assumptions by seeing if they hold for
\(e_1, \ldots ,e_n\) (instead of \(\varepsilon_1, \ldots
,\varepsilon_n\)).
Standardized Residuals
There is a technical problem with raw residuals as substitutes for
the error terms: it can be shown that the variance of the
ith raw residual is given by \[var(e_i) = \sigma^2 (1 -
h_{ii})~~~~~~(i=1,\ldots,n)\] where \[h_{ii} = \frac{1}{n} + \frac{(x_i - \bar
x)^2}{s_{xx}}.\]
Hence unlike error terms, raw residuals do not have equal
variance.
It is therefore preferable to work with the standardized residuals,
defined by \[r_i = \frac{e_i}{s
\sqrt{1-h_{ii}}}.\]
We will not need to evaluate this formula; R can produce standardized
residuals for us.
These standardized residuals have an approximately standard normal,
N(0,1), distribution and thus common variance.
In reality this technical issue is not a biggie. In practice there is
little visual difference between looking at a graph of ordinary
residuals and a graph of standardized residuals. For example the
following plots show ordinary and standardized residuals for the Hill
data introduced below. It is very hard to pick any difference in the
shape of the points.
So why do we bother with standardised residuals?
A practical reason is interpretability.
- If the units in which y is measured are very interpretable
(such as $, or kg) then the same units apply to the raw residuals, and
so the graph will be more interpretable in the original units.
- But suppose the units in which y is measured is rather
arbitrary, such as the total from a certain number of questions on a
questionnaire used to investigate some opinion, with each question being
recorded on some arbitrary scale (e.g. 1=strongly disagree, 2=disagree,
3=neutral, 4=agree, 5 =strongly agree). In that case the precise values
of y are not informative. E.g. if you were told your political
score was 32, what does that mean? It would only have meaning if you
knew what the average, and maximum and minimum attainable score were. So
it is better to convert y to a z-score so that the numbers
become more interpretable.
\[ z = \frac{y -
\bar{y}}{s_y}\]
E.g. we can interpret z=0 as average, -2 as very low, z=+1 as above
average, etc.
- Similarly the raw residuals will have the same uninterpretable units
as y, but we can interpret standardised residuals as z-scores.
\(r_i=-2\) meaning the \(y_i\) value is far below the regression
line, \(r_i=0\) as meaning the \(y_i\) value is on the regression line, and
\(r_i= +2.5\) meaning the \(y_i\) value is unusually far above the
regression line, etc.
Scottish Hill Racing Data
- Data comprise the record times in 1984 for 35 Scottish hill
races.
Variables are dist
distance (miles) climb
height gained (ft) time
record time (minutes)
- Data source: A.C. Atkinson (1986) Comment: Aspects of diagnostic
regression analysis. Statistical Science 1,
pp397-402.
We will first consider simple linear regression of time
on dist
in R.
Reading the Data into R
data(hills, package = "MASS")
Hills <- hills
## Hills <- read.csv(file = "https://r-resources.massey.ac.nz/161251/data/hills.csv",
## header = TRUE, row.names = 1)
The row.names=1
argument tells R that the first column
of data in the comma separated values file
hills.csv
contains information which should provide the row names for the data (in
this case, names of race locations).
The data is also available in the MASS
package that
comes with R. (Use one of these two data sources, not both!)
Fitting the Regression Model in R
Hills.lm <- lm(time ~ dist, data = Hills)
summary(Hills.lm)
Call:
lm(formula = time ~ dist, data = Hills)
Residuals:
Min 1Q Median 3Q Max
-35.745 -9.037 -4.201 2.849 76.170
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -4.8407 5.7562 -0.841 0.406
dist 8.3305 0.6196 13.446 6.08e-15 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 19.96 on 33 degrees of freedom
Multiple R-squared: 0.8456, Adjusted R-squared: 0.841
F-statistic: 180.8 on 1 and 33 DF, p-value: 6.084e-15
library(ggplot2)
ggplot(Hills, mapping = aes(x = time, y = dist)) + geom_point() + geom_smooth(method = "lm",
se = FALSE) + ylab("Winning time of race") + xlab("Race distance")
`geom_smooth()` using formula = 'y ~ x'
The fitted model is (to 2 decimal places)
\[E[\mbox{time}] = -4.84 + 8.33 \,
\mbox{dist}\]
The P-value of \(6.083904\times
10^{-15}\) for testing whether the regression slope is zero. This
is tiny, and indicates overwhelming evidence for (linear) dependence of
race time on distance.
The R-squared statistic of 0.8456 indicates that distance explains
quite a large proportion of the variation in race record times.
The command resid()
returns (raw) residuals for a fitted
linear regression model.
Greenmantle Carnethy Craig Dunain Ben Rha
0.09757971 3.20798304 -11.49201696 -12.03770125
Ben Lomond Goatfell Bens of Jura Cairnpapple
0.46407065 11.41407065 76.17042112 -8.77501696
Scolty Traprain Lairig Ghru Dollar
-7.06156077 -5.39201696 -35.74505318 6.23843923
Lomonds Cairn Table Eildon Two Cairngorm
-9.29861363 -1.00901696 -5.71333268 -6.21384173
Seven Hills Knock Hill Black Hill Creag Beag
-13.36866650 58.49935161 -15.22933268 -8.40978887
Kildcon Hill Meall Ant-Suidhe Half Ben Nevis Cow Hill
-4.20064839 3.58412351 2.49098304 6.11280780
N Berwick Law Creag Dubh Burnswark Largo Law
-1.46764839 -2.26410458 -10.70901696 -8.24456077
Criffel Acmony Ben Nevis Knockfarrel
1.19275494 -15.86156077 7.11915827 -12.75901696
Two Breweries Cockleroi Moffat Chase
25.14250874 -4.54633268 -1.93540365
These numbers are interpretable because the numbers are in units of
minutes above or below what would be expected.
Let’s see the commands used to get those graphs of raw and
standardised residuals shown earlier.
data(hills, package = "MASS")
Hills <- hills
Hills.lm = lm(time ~ dist, data = Hills)
plot(resid(Hills.lm) ~ predict.lm(Hills.lm), xlab = "Predictions", ylab = "Raw residuals")
plot(rstandard(Hills.lm) ~ predict.lm(Hills.lm), xlab = "Predictions", ylab = "Standardised residuals")
and some numerical details:
Min. 1st Qu. Median Mean 3rd Qu. Max.
-35.745 -9.037 -4.201 0.000 2.849 76.170
summary(rstandard(Hills.lm))
Min. 1st Qu. Median Mean 3rd Qu. Max.
-2.377778 -0.460171 -0.215778 -0.009795 0.145043 4.018411
Diagnostics for Failure of Model Assumptions
Assessing Assumption A1
Assumption A1 is equivalent to stating
\(E[Y_i] = \beta_0 + \beta_1 x_i\)
Failure of A1 indicates that we are fitting
the wrong mean function.
Looking for any trends in residual versus fitted values or a
covariate is a useful diagnostic.
Assessing Assumption A2
If A2 is correct, then residuals should
appear randomly scattered about zero if plotted against time order (if
known), fitted values or the predictor.
Long sequences of positive residuals followed by sequences of
negative residuals suggests that the error terms are not
independent.
Failure of this assumption will mean standard errors will be
incorrect, and so hypothesis tests and confidence intervals will be
unreliable.
We will look at regression models for time series later in the
course.
Assessing Assumption A3
If A3 is correct, then the
spread of the (standardized) residuals about zero
should not vary systematically with the fitted value or covariate.
Heteroscedasticity (unequal spread) is typically
recognized as a “fanning out” of (standardized) residuals when plotted
against fitted value or covariate. This means the errorvariance
increases with the mean response. (Alternatively one could have fanning
in).
Failure of this assumption will leave parameter estimates unbiased,
but standard errors will be incorrect, and hence test results and
confidence intervals will be unreliable.
A transformation of both response and predictor variables can
sometimes help in this case.
An alternative strategy is to use weighted linear
regression (covered later in the course).
Assessing Assumption A4
A normal probability plot, or normal Q-Q plot, is a
standard graphical tool for assessing the normality of a data set.
A normal Q-Q plot of the (standardized) residuals should show points
staying close to a straight line — curvature indicates a failure of
A4.
On the other hand failure of the normality assumption for the error
distribution is not usually a serious problem. Removal of (obvious)
outliers will often improve the normality of the standardized
residuals.
Diagnostics for Hill race s Example
The plot()
command applied to the fitted model
Hills.lm
produces four useful diagnostic plots. The
par()
command put first splits the graphing window into a
two-by-two grid so we can see all four graphs together.
par(mfrow = c(2, 2))
plot(Hills.lm)
The first three of these plots are:
- Plot of raw residuals versus fitted values
- Normal Q-Q plot for standardized residuals
- Scale-location plot (square root of absolute standardized residuals
against fitted value)
plot(Hills.lm, which = 1)
This residual plot shows some data points with very large
residuals.
The red line is a nonparametric estimate of trend (take care not to
over-interpret) it.
Would you say there is strong evidence of curvature, or of increasing
spread in residuals?
plot(Hills.lm, which = 2)
The Normal Q-Q plot is far from a straight line. This indicates
failure of the normality assumption.
Note that this plot is heavily influenced by data points with large
residuals.
plot(Hills.lm, which = 3)
For the scale-location plot, we look for a trend for the line to be
increasing (or decreasing) as we move from left to right. If so, it
provides a hint that spread of residuals is increasing (or decreasing)
with fitted value.
This graph suggests the error variance \(\sigma^2\) may not be constant for all data
points.
What about assumption A2, independent
error? We can just plot the residuals without an x
variable.
plot(Hills.lm$residuals)
abline(h = 0, lty = 2)
The outliers make it hard to tell, but the graph suggests the
residuals may not be entirely random - perhaps there is some relevant
order in the data.
Conclusions from Diagnostics for Example
Linear regression model assumptions do not appear valid.
Hence conclusions based on this model are questionable.
Problems with model seem largely down to a few odd
data points or outliers.
LS0tDQp0aXRsZTogIkxlY3R1cmUgNTogQ2hlY2tpbmcgdGhlIEFzc3VtcHRpb25zIg0Kc3VidGl0bGU6IDE2MS4yNTEgUmVncmVzc2lvbiBNb2RlbGxpbmcNCmF1dGhvcjogIlByZXNlbnRlZCBieSBNYXR0aGV3IFBhd2xleSA8TS5QYXdsZXlAbWFzc2V5LmFjLm56PiIgIA0KZGF0ZTogIldlZWsgMiBvZiBTZW1lc3RlciAyLCBgciBsdWJyaWRhdGU6OnllYXIobHVicmlkYXRlOjpub3coKSlgIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICB0aGVtZTogeWV0aQ0KICAgIGhpZ2hsaWdodDogdGFuZ28NCiAgaHRtbF9ub3RlYm9vazoNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgdGhlbWU6IHlldGkNCiAgICBoaWdobGlnaHQ6IHRhbmdvDQogIGlvc2xpZGVzX3ByZXNlbnRhdGlvbjoNCiAgICB3aWRlc2NyZWVuOiB0cnVlDQogICAgc21hbGxlcjogdHJ1ZQ0KICB3b3JkX2RvY3VtZW50OiBkZWZhdWx0DQogIHNsaWR5X3ByZXNlbnRhdGlvbjogDQogICAgdGhlbWU6IHlldGkNCiAgICBoaWdobGlnaHQ6IHRhbmdvDQogIHBkZl9kb2N1bWVudDogZGVmYXVsdA0KLS0tDQoNCg0KDQoNCjwhLS0tIERhdGEgaXMgb24NCmh0dHBzOi8vci1yZXNvdXJjZXMubWFzc2V5LmFjLm56L2RhdGEvMTYxMjUxLw0KLS0tPg0KDQpgYGB7ciBzZXR1cCwgcHVybD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0NCmxpYnJhcnkoa25pdHIpDQpvcHRzX2NodW5rJHNldChkZXY9YygicG5nIiwgInBkZiIpKQ0Kb3B0c19jaHVuayRzZXQoZmlnLmhlaWdodD02LCBmaWcud2lkdGg9NywgZmlnLnBhdGg9IkZpZ3VyZXMvIiwgZmlnLmFsdD0idW5sYWJlbGxlZCIpDQpvcHRzX2NodW5rJHNldChjb21tZW50PSIiLCBmaWcuYWxpZ249ImNlbnRlciIsIHRpZHk9VFJVRSkNCm9wdGlvbnMoa25pdHIua2FibGUuTkEgPSAnJykNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShicm9vbSkNCmBgYA0KDQoNCjwhLS0tIERvIG5vdCBlZGl0IGFueXRoaW5nIGFib3ZlIHRoaXMgbGluZS4gLS0tPg0KDQpTdGF0aXN0aWNhbCBtb2RlbHMgYWxsb3cgdXMgdG8gYW5zd2VyIHF1ZXN0aW9ucyB1c2luZyBkYXRhLg0KDQpUaGUgdmFsaWRpdHkgb2YgdGhlIGNvbmNsdXNpb25zIHRoYXQgd2UgcmVhY2ggaXMgY29udGluZ2VudCB1cG9uIHRoZSBhcHByb3ByaWF0ZW5lc3Mgb2YgdGhlIG1vZGVscyB0aGF0IHdlIHVzZS4NCg0KT25jZSB5b3UgaGF2ZSBmaXR0ZWQgYSBzdGF0aXN0aWNhbCBtb2RlbCB0byBkYXRhLCBpdCBpcyB0aGVyZWZvcmUgaW1wb3J0YW50IHRvIGNoZWNrIHRoZSBhc3N1bXB0aW9ucyB1bmRlcmx5aW5nIHRoZSBtb2RlbC4NCg0KVGhlIHRvb2xzIHRvIGNoZWNrIHRoZXNlIGFzc3VtcHRpb25zIGFyZSBvZnRlbiByZWZlcnJlZCB0byBhcyAqKm1vZGVsIGRpYWdub3N0aWNzKiouDQoNCldlIHNoYWxsIGxvb2sgYXQgYXNzdW1wdGlvbiBjaGVja2luZyBmb3Igc2ltcGxlIGxpbmVhciByZWdyZXNzaW9uIGluIHRoaXMgbGVjdHVyZS4NCg0KIyMgQXNzdW1wdGlvbnMgZm9yIFNpbXBsZSBMaW5lYXIgUmVncmVzc2lvbg0KDQpSZWNhbGwgdGhhdCB0aGUgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwgaXMNCiQkWV9pID0gXGJldGFfMCArIFxiZXRhXzEgeF9pICsgXHZhcmVwc2lsb25faSQkIA0KDQp3aGVyZSB3ZSBtYWtlIHRoZQ0KZm9sbG93aW5nIGFzc3VtcHRpb25zOg0KDQoqKipBMSoqKi4gICRFW1x2YXJlcHNpbG9uX2ldID0gMCQgZm9yICppPTEsIC4uLiAsbiouDQoNCioqKkEyKioqLiAgJFx2YXJlcHNpbG9uXzEsIFxsZG90cyAsXHZhcmVwc2lsb25fbiQgYXJlIGluZGVwZW5kZW50Lg0KDQoqKipBMyoqKi4gIHZhciQoXHZhcmVwc2lsb25faSkgPSBcc2lnbWFeMiQgZm9yICppPTEsLi4uLG4qICgqKmhvbW9zY2VkYXN0aWNpdHkqKikuDQoNCioqKkE0KioqLiAgJFx2YXJlcHNpbG9uXzEsIFxsZG90cyAsXHZhcmVwc2lsb25fbiQgYXJlIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLg0KDQoNCkNsYXNzIERpc2N1c3Npb246IEludGVycHJldCB0aGVzZSBhc3N1bXB0aW9ucywgYW5kIHRoaW5rIGFib3V0IHNpdHVhdGlvbnMgaW4gd2hpY2ggZWFjaCBtaWdodCBmYWlsLg0KDQojIyBSYXcgUmVzaWR1YWxzDQoNClRoZSByZXNpZHVhbHMgKG9yICoqcmF3IHJlc2lkdWFscyoqKSwgJCRcYmVnaW57YWxpZ25lZH0gZV9pICY9JiB5X2kgLSBcaGF0IFxtdV9pXFwgJj0mIHlfaSAtIFxoYXQgXGJldGFfMCAtIFxoYXQgXGJldGFfMSB4X2l+fn5+fn5+fn4oaT0xLFxsZG90cyAsbilcZW5ke2FsaWduZWR9JCQNCmFyZSBhIGZ1bmRhbWVudGFsIGRpYWdub3N0aWMgYWlkLg0KDQpUaGVzZSByZXNpZHVhbHMgYXJlIGEga2luZCBvZiBzYW1wbGUgdmVyc2lvbiBvZiB0aGUgZXJyb3IgcmFuZG9tIHZhcmlhYmxlcyAkXHZhcmVwc2lsb25fMSxcbGRvdHMsXHZhcmVwc2lsb25fbiQuDQoNCkNvbnNlcXVlbnRseSB3ZSBjYW4gdGVzdCB0aGUgYXNzdW1wdGlvbnMgYnkgc2VlaW5nIGlmIHRoZXkgaG9sZCBmb3IgJGVfMSwgXGxkb3RzICxlX24kIChpbnN0ZWFkIG9mICRcdmFyZXBzaWxvbl8xLCBcbGRvdHMgLFx2YXJlcHNpbG9uX24kKS4NCg0KIyMgU3RhbmRhcmRpemVkIFJlc2lkdWFscw0KDQpUaGVyZSBpcyBhICB0ZWNobmljYWwgcHJvYmxlbSB3aXRoIHJhdyByZXNpZHVhbHMgYXMgc3Vic3RpdHV0ZXMgZm9yIHRoZSBlcnJvciB0ZXJtczogaXQgY2FuIGJlIHNob3duIHRoYXQgdGhlIHZhcmlhbmNlIG9mIHRoZSAqaSpedGheIHJhdyByZXNpZHVhbCBpcyBnaXZlbiBieSANCiQkdmFyKGVfaSkgPSBcc2lnbWFeMiAoMSAtIGhfe2lpfSl+fn5+fn4oaT0xLFxsZG90cyxuKSQkIHdoZXJlDQokJGhfe2lpfSA9IFxmcmFjezF9e259ICsgXGZyYWN7KHhfaSAtIFxiYXIgeCleMn17c197eHh9fS4kJA0KDQpIZW5jZSB1bmxpa2UgZXJyb3IgdGVybXMsIHJhdyByZXNpZHVhbHMgZG8gbm90IGhhdmUgZXF1YWwgdmFyaWFuY2UuDQoNCkl0IGlzIHRoZXJlZm9yZSBwcmVmZXJhYmxlIHRvIHdvcmsgd2l0aCB0aGUgc3RhbmRhcmRpemVkIHJlc2lkdWFscywgZGVmaW5lZCBieSANCiQkcl9pID0gXGZyYWN7ZV9pfXtzIFxzcXJ0ezEtaF97aWl9fX0uJCQNCg0KV2Ugd2lsbCBub3QgbmVlZCB0byBldmFsdWF0ZSB0aGlzIGZvcm11bGE7IFIgY2FuIHByb2R1Y2Ugc3RhbmRhcmRpemVkIHJlc2lkdWFscyBmb3IgdXMuDQoNClRoZXNlIHN0YW5kYXJkaXplZCByZXNpZHVhbHMgaGF2ZSBhbiBhcHByb3hpbWF0ZWx5IHN0YW5kYXJkIG5vcm1hbCwgKk4oMCwxKSosIGRpc3RyaWJ1dGlvbiBhbmQgdGh1cyBjb21tb24gdmFyaWFuY2UuDQoNCg0KSW4gcmVhbGl0eSB0aGlzIHRlY2huaWNhbCBpc3N1ZSBpcyBub3QgYSBiaWdnaWUuICBJbiBwcmFjdGljZSB0aGVyZSBpcyBsaXR0bGUgdmlzdWFsIGRpZmZlcmVuY2UgYmV0d2VlbiBsb29raW5nIGF0IGEgZ3JhcGggb2Ygb3JkaW5hcnkgcmVzaWR1YWxzIGFuZCBhIGdyYXBoIG9mIHN0YW5kYXJkaXplZCByZXNpZHVhbHMuIEZvciBleGFtcGxlIHRoZSBmb2xsb3dpbmcgcGxvdHMgc2hvdyBvcmRpbmFyeSBhbmQgc3RhbmRhcmRpemVkIHJlc2lkdWFscyBmb3IgdGhlIEhpbGwgZGF0YSBpbnRyb2R1Y2VkIGJlbG93LiBJdCBpcyB2ZXJ5IGhhcmQgdG8gcGljayBhbnkgZGlmZmVyZW5jZSBpbiB0aGUgKioqc2hhcGUqKiogb2YgdGhlIHBvaW50cy4NCg0KYGBge3IgQ29tcGFyaW5nIHJlc2lkdWFsIHBsb3RzLCBlY2hvPUZBTFNFLCBmaWcuY2FwPSJQbG90cyBvZiByYXcgKHVwcGVyKSBhbmQgc3RhbmRhcmRpc2VkIChsb3dlcikgcmVzaWR1YWxzIGFnYWluc3QgdGhlIHByZWRpY3Rpb25zIGZyb20gdGhlIHNpbXBsZSBtb2RlbC4ifQ0KZGF0YShoaWxscywgcGFja2FnZSA9ICJNQVNTIikNCkhpbGxzIDwtIGhpbGxzDQpIaWxscy5sbSA9IGxtKHRpbWV+IGRpc3QsIGRhdGE9SGlsbHMpDQpwbG90KHJlc2lkKEhpbGxzLmxtKX4gcHJlZGljdC5sbShIaWxscy5sbSksIHhsYWI9IlByZWRpY3Rpb25zIiwgeWxhYj0iUmF3IHJlc2lkdWFscyIpDQpwbG90KHJzdGFuZGFyZChIaWxscy5sbSl+IHByZWRpY3QubG0oSGlsbHMubG0pLCB4bGFiPSJQcmVkaWN0aW9ucyIsIHlsYWI9IlN0YW5kYXJkaXNlZCByZXNpZHVhbHMiKQ0KYGBgDQoNCiMjIyBTbyB3aHkgZG8gd2UgYm90aGVyIHdpdGggc3RhbmRhcmRpc2VkIHJlc2lkdWFscz8gIA0KDQpBICBwcmFjdGljYWwgcmVhc29uIGlzIGludGVycHJldGFiaWxpdHkuDQoNCi0gSWYgdGhlIHVuaXRzIGluIHdoaWNoICp5KiBpcyBtZWFzdXJlZCBhcmUgdmVyeSBpbnRlcnByZXRhYmxlIChzdWNoIGFzIFwkLCBvciBrZykgIHRoZW4gdGhlIHNhbWUgdW5pdHMgYXBwbHkgdG8gdGhlIHJhdyByZXNpZHVhbHMsIGFuZCBzbyB0aGUgZ3JhcGggd2lsbCBiZSBtb3JlIGludGVycHJldGFibGUgaW4gdGhlIG9yaWdpbmFsIHVuaXRzLiANCi0gQnV0IHN1cHBvc2UgdGhlIHVuaXRzIGluIHdoaWNoICp5KiBpcyBtZWFzdXJlZCBpcyByYXRoZXIgYXJiaXRyYXJ5LCBzdWNoIGFzIHRoZSB0b3RhbCBmcm9tIGEgY2VydGFpbiBudW1iZXIgb2YgcXVlc3Rpb25zIG9uIGEgcXVlc3Rpb25uYWlyZSB1c2VkIHRvIGludmVzdGlnYXRlIHNvbWUgb3Bpbmlvbiwgd2l0aCBlYWNoIHF1ZXN0aW9uIGJlaW5nIHJlY29yZGVkIG9uIHNvbWUgYXJiaXRyYXJ5IHNjYWxlIChlLmcuIDE9c3Ryb25nbHkgZGlzYWdyZWUsIDI9ZGlzYWdyZWUsIDM9bmV1dHJhbCwgND1hZ3JlZSwgNSA9c3Ryb25nbHkgYWdyZWUpLiAgSW4gdGhhdCBjYXNlIHRoZSBwcmVjaXNlIHZhbHVlcyBvZiAqeSogYXJlIG5vdCBpbmZvcm1hdGl2ZS4gIEUuZy4gaWYgeW91IHdlcmUgdG9sZCB5b3VyIHBvbGl0aWNhbCBzY29yZSB3YXMgMzIsIHdoYXQgZG9lcyB0aGF0IG1lYW4/IEl0IHdvdWxkIG9ubHkgaGF2ZSBtZWFuaW5nIGlmIHlvdSBrbmV3IHdoYXQgdGhlIGF2ZXJhZ2UsIGFuZCBtYXhpbXVtIGFuZCBtaW5pbXVtIGF0dGFpbmFibGUgc2NvcmUgd2VyZS4gICBTbyBpdCBpcyBiZXR0ZXIgdG8gIGNvbnZlcnQgKnkqIHRvIGEgei1zY29yZSBzbyB0aGF0IHRoZSBudW1iZXJzIGJlY29tZSBtb3JlIGludGVycHJldGFibGUuDQoNCiQkIHogPSBcZnJhY3t5IC0gXGJhcnt5fX17c195fSQkDQoNCkUuZy4gd2UgY2FuIGludGVycHJldCB6PTAgYXMgYXZlcmFnZSwgIC0yIGFzIHZlcnkgbG93LCB6PSsxIGFzIGFib3ZlIGF2ZXJhZ2UsIGV0Yy4gDQoNCi0gU2ltaWxhcmx5IHRoZSByYXcgcmVzaWR1YWxzIHdpbGwgaGF2ZSB0aGUgc2FtZSB1bmludGVycHJldGFibGUgdW5pdHMgYXMgKnkqLCBidXQgd2UgY2FuIGludGVycHJldCBzdGFuZGFyZGlzZWQgcmVzaWR1YWxzIGFzIHotc2NvcmVzLiAkcl9pPS0yJCBtZWFuaW5nIHRoZSAkeV9pJCB2YWx1ZSBpcyBmYXIgYmVsb3cgdGhlIHJlZ3Jlc3Npb24gbGluZSwgICRyX2k9MCQgYXMgbWVhbmluZyB0aGUgJHlfaSQgdmFsdWUgaXMgb24gdGhlIHJlZ3Jlc3Npb24gbGluZSwgYW5kICRyX2k9ICsyLjUkIG1lYW5pbmcgdGhlICR5X2kkIHZhbHVlIGlzIHVudXN1YWxseSBmYXIgYWJvdmUgdGhlIHJlZ3Jlc3Npb24gbGluZSwgICBldGMuIA0KDQoNCg0KIyMgU2NvdHRpc2ggSGlsbCBSYWNpbmcgRGF0YQ0KDQoNCi0gRGF0YSBjb21wcmlzZSB0aGUgcmVjb3JkIHRpbWVzIGluIDE5ODQgZm9yIDM1IFNjb3R0aXNoIGhpbGwgcmFjZXMuDQoNClZhcmlhYmxlcyBhcmUgYGRpc3RgIGRpc3RhbmNlIChtaWxlcykgYGNsaW1iYCBoZWlnaHQgZ2FpbmVkIChmdCkgYHRpbWVgIHJlY29yZCB0aW1lIChtaW51dGVzKSAgDQoNCi0gRGF0YSBzb3VyY2U6IEEuQy4gQXRraW5zb24gKDE5ODYpIENvbW1lbnQ6IEFzcGVjdHMgb2YgZGlhZ25vc3RpYyByZWdyZXNzaW9uIGFuYWx5c2lzLiAqU3RhdGlzdGljYWwgU2NpZW5jZSogKioxKiosIHBwMzk3LTQwMi4NCg0KYGBge3IgUnVubmVySlBHLCBmaWcuY2FwPSJhIGhpbGwgcnVubmVyIiwgZWNobz1GQUxTRX0NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCIuLi9ncmFwaGljcy9oaWxscmFjZS5qcGciKQ0KYGBgDQoNCiAgDQoNCldlIHdpbGwgZmlyc3QgY29uc2lkZXIgc2ltcGxlIGxpbmVhciByZWdyZXNzaW9uIG9mIGB0aW1lYCBvbiBgZGlzdGAgaW4gUi4NCg0KDQpSZWFkaW5nIHRoZSBEYXRhIGludG8gUg0KDQpgYGB7ciBnZXRIaWxsc0RhdGEsIGV2YWw9LTN9DQpkYXRhKGhpbGxzLCBwYWNrYWdlPSJNQVNTIikgDQpIaWxscyA8LSBoaWxscw0KSGlsbHMgPC0gcmVhZC5jc3YoZmlsZT0iaHR0cHM6Ly9yLXJlc291cmNlcy5tYXNzZXkuYWMubnovMTYxMjUxL2RhdGEvaGlsbHMuY3N2IiwgaGVhZGVyPVRSVUUsIHJvdy5uYW1lcz0xKQ0KYGBgDQoNClRoZSBgcm93Lm5hbWVzPTFgIGFyZ3VtZW50IHRlbGxzIFIgdGhhdCB0aGUgZmlyc3QgY29sdW1uIG9mIGRhdGEgaW4gdGhlIGNvbW1hIHNlcGFyYXRlZCB2YWx1ZXMgZmlsZSBgciB4ZnVuOjplbWJlZF9maWxlKCIuLi8uLi9kYXRhL2hpbGxzLmNzdiIsIHRleHQ9ImhpbGxzLmNzdiIpYCBjb250YWlucyBpbmZvcm1hdGlvbiB3aGljaCBzaG91bGQgcHJvdmlkZSB0aGUgcm93IG5hbWVzIGZvciB0aGUgZGF0YSAoaW4gdGhpcyBjYXNlLCBuYW1lcyBvZiByYWNlIGxvY2F0aW9ucykuDQoNClRoZSBkYXRhIGlzIGFsc28gYXZhaWxhYmxlIGluIHRoZSBgTUFTU2AgcGFja2FnZSB0aGF0IGNvbWVzIHdpdGggUi4gKFVzZSBvbmUgb2YgdGhlc2UgdHdvIGRhdGEgc291cmNlcywgbm90IGJvdGghKQ0KDQoNCiMjIyBGaXR0aW5nIHRoZSBSZWdyZXNzaW9uIE1vZGVsIGluIFINCg0KYGBge3IgSGlsbHMubG19DQpIaWxscy5sbSA8LSBsbSh0aW1lfmRpc3QsIGRhdGE9SGlsbHMpIA0Kc3VtbWFyeShIaWxscy5sbSkNCmBgYA0KDQoNCmBgYHtyIEhpbGxzRml0dGVkTGluZVBsb3QsIGZpZy5jYXA9IkZpdHRlZCBsaW5lIHBsb3QgZm9yIHRoZSBmaXJzdCBtb2RlbCBmb3IgdGhlIGhpbGwgcmFjaW5nIGRhdGEifQ0KbGlicmFyeShnZ3Bsb3QyKQ0KZ2dwbG90KEhpbGxzLCBtYXBwaW5nID0gYWVzKHg9dGltZSwgeT1kaXN0KSkgKyBnZW9tX3BvaW50KCkgKw0KZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSkgKw0KeWxhYigiV2lubmluZyB0aW1lIG9mIHJhY2UiKSArIHhsYWIoIlJhY2UgZGlzdGFuY2UiKSAgDQpgYGANCg0KDQoNClRoZSBmaXR0ZWQgbW9kZWwgaXMgKHRvIDIgZGVjaW1hbCBwbGFjZXMpDQoNCiQkRVtcbWJveHt0aW1lfV0gPSBgciByb3VuZChjb2VmKEhpbGxzLmxtKVsxXSwgMilgICsgYHIgcm91bmQoY29lZihIaWxscy5sbSlbMl0sIDIpYCBcLCBcbWJveHtkaXN0fSQkDQoNClRoZSAqUCotdmFsdWUgb2YgJGByIHN1bW1hcnkoSGlsbHMubG0pJGNvZWZmaWNpZW50c1siZGlzdCIsICJQcig+fHR8KSJdYCQgZm9yIHRlc3Rpbmcgd2hldGhlciB0aGUgcmVncmVzc2lvbiBzbG9wZSBpcyB6ZXJvLiBUaGlzIGlzIHRpbnksIGFuZCBpbmRpY2F0ZXMgb3ZlcndoZWxtaW5nIGV2aWRlbmNlIGZvciAobGluZWFyKSBkZXBlbmRlbmNlIG9mIHJhY2UgdGltZSBvbiBkaXN0YW5jZS4NCg0KVGhlIFItc3F1YXJlZCBzdGF0aXN0aWMgb2YgYHIgcm91bmQoc3VtbWFyeShIaWxscy5sbSkkci5zcXVhcmVkLDQpYCAgaW5kaWNhdGVzIHRoYXQgZGlzdGFuY2UgZXhwbGFpbnMgcXVpdGUgYSBsYXJnZSBwcm9wb3J0aW9uIG9mIHRoZSB2YXJpYXRpb24gaW4gcmFjZSByZWNvcmQgdGltZXMuDQoNClRoZSBjb21tYW5kIGByZXNpZCgpYCByZXR1cm5zIChyYXcpIHJlc2lkdWFscyBmb3IgYSBmaXR0ZWQgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwuDQoNCmBgYHtyIGdldFJlc2lkc30NCnJlc2lkKEhpbGxzLmxtKQ0KYGBgDQoNClRoZXNlIG51bWJlcnMgYXJlIGludGVycHJldGFibGUgYmVjYXVzZSB0aGUgbnVtYmVycyBhcmUgaW4gdW5pdHMgb2YgbWludXRlcyBhYm92ZSBvciBiZWxvdyB3aGF0IHdvdWxkIGJlIGV4cGVjdGVkLiANCg0KTGV0J3Mgc2VlIHRoZSBjb21tYW5kcyB1c2VkIHRvIGdldCB0aG9zZSBncmFwaHMgb2YgcmF3IGFuZCBzdGFuZGFyZGlzZWQgcmVzaWR1YWxzIHNob3duIGVhcmxpZXIuDQoNCmBgYHtyIENvbXBhcmluZ1Jlc2lkdWFsUGxvdHMyLCBmaWcuY2FwPSJQbG90cyBvZiByYXcgKHVwcGVyKSBhbmQgc3RhbmRhcmRpc2VkIChsb3dlcikgcmVzaWR1YWxzIGFnYWluc3QgdGhlIHByZWRpY3Rpb25zIGZyb20gdGhlIHNpbXBsZSBtb2RlbC4ifQ0KZGF0YShoaWxscywgcGFja2FnZSA9ICJNQVNTIikNCkhpbGxzIDwtIGhpbGxzDQpIaWxscy5sbSA9IGxtKHRpbWV+IGRpc3QsIGRhdGE9SGlsbHMpDQpwbG90KHJlc2lkKEhpbGxzLmxtKX4gcHJlZGljdC5sbShIaWxscy5sbSksIHhsYWI9IlByZWRpY3Rpb25zIiwgeWxhYj0iUmF3IHJlc2lkdWFscyIpDQpwbG90KHJzdGFuZGFyZChIaWxscy5sbSl+IHByZWRpY3QubG0oSGlsbHMubG0pLCB4bGFiPSJQcmVkaWN0aW9ucyIsIHlsYWI9IlN0YW5kYXJkaXNlZCByZXNpZHVhbHMiKQ0KYGBgDQoNCmFuZCBzb21lIG51bWVyaWNhbCBkZXRhaWxzOg0KDQpgYGB7ciBSZXNpZERldGFpbHN9DQpzdW1tYXJ5KHJlc2lkKEhpbGxzLmxtKSkNCnN1bW1hcnkoIHJzdGFuZGFyZChIaWxscy5sbSkpDQpgYGANCiANCg0KIyMgRGlhZ25vc3RpY3MgZm9yIEZhaWx1cmUgb2YgTW9kZWwgQXNzdW1wdGlvbnMNCg0KIyMjIEFzc2Vzc2luZyBBc3N1bXB0aW9uIEExDQoNCkFzc3VtcHRpb24gKioqQTEqKiogaXMgZXF1aXZhbGVudCB0byBzdGF0aW5nICRFW1lfaV0gPSBcYmV0YV8wICsgXGJldGFfMSB4X2kkDQoNCkZhaWx1cmUgb2YgKioqQTEqKiogaW5kaWNhdGVzIHRoYXQgd2UgYXJlIGZpdHRpbmcgdGhlIHdyb25nIG1lYW4gZnVuY3Rpb24uDQoNCkxvb2tpbmcgZm9yIGFueSB0cmVuZHMgaW4gcmVzaWR1YWwgdmVyc3VzIGZpdHRlZCB2YWx1ZXMgb3IgYSBjb3ZhcmlhdGUgaXMgYSB1c2VmdWwgZGlhZ25vc3RpYy4NCg0KDQojIyMgQXNzZXNzaW5nIEFzc3VtcHRpb24gQTINCg0KSWYgKioqQTIqKiogaXMgY29ycmVjdCwgdGhlbiByZXNpZHVhbHMgc2hvdWxkIGFwcGVhciByYW5kb21seSBzY2F0dGVyZWQgYWJvdXQgemVybyBpZiBwbG90dGVkIGFnYWluc3QgdGltZSBvcmRlciAoaWYga25vd24pLCBmaXR0ZWQgdmFsdWVzIG9yIHRoZSBwcmVkaWN0b3IuDQoNCkxvbmcgc2VxdWVuY2VzIG9mIHBvc2l0aXZlIHJlc2lkdWFscyBmb2xsb3dlZCBieSBzZXF1ZW5jZXMgb2YgbmVnYXRpdmUgcmVzaWR1YWxzIHN1Z2dlc3RzIHRoYXQgdGhlIGVycm9yIHRlcm1zIGFyZSBub3QgaW5kZXBlbmRlbnQuDQoNCkZhaWx1cmUgb2YgdGhpcyBhc3N1bXB0aW9uIHdpbGwgbWVhbiBzdGFuZGFyZCBlcnJvcnMgd2lsbCBiZSBpbmNvcnJlY3QsICBhbmQgc28gaHlwb3RoZXNpcyB0ZXN0cyAgYW5kIGNvbmZpZGVuY2UgIGludGVydmFscyB3aWxsIGJlIHVucmVsaWFibGUuDQoNCldlIHdpbGwgbG9vayBhdCByZWdyZXNzaW9uIG1vZGVscyBmb3IgdGltZSBzZXJpZXMgbGF0ZXIgaW4gdGhlIGNvdXJzZS4NCg0KIyMjIEFzc2Vzc2luZyBBc3N1bXB0aW9uIEEzDQoNCklmICoqKkEzKioqIGlzIGNvcnJlY3QsIHRoZW4gdGhlICoqc3ByZWFkKiogb2YgdGhlIChzdGFuZGFyZGl6ZWQpIHJlc2lkdWFscyBhYm91dCB6ZXJvIHNob3VsZCBub3QgdmFyeSBzeXN0ZW1hdGljYWxseSB3aXRoIHRoZSBmaXR0ZWQgdmFsdWUgb3IgY292YXJpYXRlLg0KDQoqKkhldGVyb3NjZWRhc3RpY2l0eSoqICAodW5lcXVhbCBzcHJlYWQpIGlzIHR5cGljYWxseSByZWNvZ25pemVkIGFzIGEgImZhbm5pbmcgb3V0IiBvZiAoc3RhbmRhcmRpemVkKSByZXNpZHVhbHMgd2hlbiBwbG90dGVkIGFnYWluc3QgZml0dGVkIHZhbHVlIG9yICBjb3ZhcmlhdGUuICBUaGlzIG1lYW5zIHRoZSAgZXJyb3J2YXJpYW5jZSBpbmNyZWFzZXMgd2l0aCB0aGUgbWVhbiByZXNwb25zZS4gKEFsdGVybmF0aXZlbHkgb25lIGNvdWxkIGhhdmUgZmFubmluZyBpbikuDQoNCkZhaWx1cmUgb2YgdGhpcyBhc3N1bXB0aW9uIHdpbGwgbGVhdmUgcGFyYW1ldGVyIGVzdGltYXRlcyB1bmJpYXNlZCwgYnV0IHN0YW5kYXJkIGVycm9ycyB3aWxsIGJlIGluY29ycmVjdCwgYW5kIGhlbmNlICB0ZXN0IHJlc3VsdHMgYW5kIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIHdpbGwgYmUgdW5yZWxpYWJsZS4NCg0KQSB0cmFuc2Zvcm1hdGlvbiBvZiBib3RoIHJlc3BvbnNlIGFuZCBwcmVkaWN0b3IgdmFyaWFibGVzICAgIGNhbiBzb21ldGltZXMgaGVscCBpbiB0aGlzIGNhc2UuDQoNCkFuIGFsdGVybmF0aXZlIHN0cmF0ZWd5IGlzIHRvIHVzZSAqKndlaWdodGVkIGxpbmVhciByZWdyZXNzaW9uKiogKGNvdmVyZWQgbGF0ZXIgaW4gdGhlIGNvdXJzZSkuDQoNCg0KDQoNCiMjIyBBc3Nlc3NpbmcgQXNzdW1wdGlvbiBBNA0KDQpBIG5vcm1hbCBwcm9iYWJpbGl0eSBwbG90LCBvciAqKm5vcm1hbCBRLVEgcGxvdCoqLCBpcyBhIHN0YW5kYXJkIGdyYXBoaWNhbCB0b29sIGZvciBhc3Nlc3NpbmcgdGhlIG5vcm1hbGl0eSBvZiBhIGRhdGEgc2V0Lg0KDQpBIG5vcm1hbCBRLVEgcGxvdCBvZiB0aGUgKHN0YW5kYXJkaXplZCkgcmVzaWR1YWxzIHNob3VsZCBzaG93IHBvaW50cyBzdGF5aW5nIGNsb3NlICB0byBhIHN0cmFpZ2h0IGxpbmUgLS0tIGN1cnZhdHVyZSBpbmRpY2F0ZXMgYSBmYWlsdXJlIG9mICAqKipBNCoqKi4NCg0KT24gdGhlIG90aGVyIGhhbmQgZmFpbHVyZSBvZiB0aGUgIG5vcm1hbGl0eSBhc3N1bXB0aW9uIGZvciB0aGUgICBlcnJvciBkaXN0cmlidXRpb24gaXMgbm90IHVzdWFsbHkgYSBzZXJpb3VzIHByb2JsZW0uICBSZW1vdmFsIG9mIChvYnZpb3VzKSBvdXRsaWVycyB3aWxsIG9mdGVuIGltcHJvdmUgdGhlIG5vcm1hbGl0eSAgb2YgdGhlIHN0YW5kYXJkaXplZCByZXNpZHVhbHMuDQoNCg0KIyMgRGlhZ25vc3RpY3MgZm9yIEhpbGwgcmFjZSBzIEV4YW1wbGUgDQoNClRoZSBgcGxvdCgpYCBjb21tYW5kIGFwcGxpZWQgdG8gdGhlIGZpdHRlZCBtb2RlbCBgSGlsbHMubG1gIHByb2R1Y2VzIGZvdXIgdXNlZnVsIGRpYWdub3N0aWMgcGxvdHMuIFRoZSBgcGFyKClgIGNvbW1hbmQgcHV0IGZpcnN0IHNwbGl0cyB0aGUgZ3JhcGhpbmcgd2luZG93IGludG8gYSB0d28tYnktdHdvIGdyaWQgc28gd2UgY2FuIHNlZSBhbGwgZm91ciBncmFwaHMgdG9nZXRoZXIuIA0KYGBge3IgSGlsbHMubG1EaWFnLCBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9MTAsIGZpZy5jYXA9IlJlc2lkdWFsIGFuYWx5c2lzIHBsb3RzIGZvciB0aGUgZmlyc3QgbW9kZWwgYXBwbGllZCB0byB0aGUgaGlsbCByYWNpbmcgZGF0YS4ifQ0KcGFyKG1mcm93PWMoMiwyKSkNCnBsb3QoSGlsbHMubG0pDQpgYGAgIA0KDQpUaGUgZmlyc3QgdGhyZWUgb2YgdGhlc2UgcGxvdHMgYXJlOg0KDQotIFBsb3Qgb2YgcmF3IHJlc2lkdWFscyB2ZXJzdXMgZml0dGVkIHZhbHVlcw0KLSBOb3JtYWwgUS1RIHBsb3QgZm9yIHN0YW5kYXJkaXplZCByZXNpZHVhbHMNCi0gU2NhbGUtbG9jYXRpb24gcGxvdCAoc3F1YXJlIHJvb3Qgb2YgYWJzb2x1dGUgc3RhbmRhcmRpemVkIHJlc2lkdWFscyBhZ2FpbnN0IGZpdHRlZCB2YWx1ZSkNCg0KYGBge3IgSGlsbHMubG1EaWFnMSwgZmlnLmNhcD0iUmVzaWR1YWxzIHBsb3R0ZWQgYWdhaW5zdCBmaXR0ZWQgdmFsdWVzIGZvciB0aGUgZmlyc3QgbW9kZWwgZml0dGVkIHRvIHRoZSBoaWxsIHJhY2luZyBkYXRhIn0NCnBsb3QoSGlsbHMubG0sIHdoaWNoPTEpDQpgYGANCg0KDQoNCg0KDQpUaGlzIHJlc2lkdWFsIHBsb3Qgc2hvd3Mgc29tZSBkYXRhIHBvaW50cyB3aXRoIHZlcnkgbGFyZ2UgcmVzaWR1YWxzLg0KDQpUaGUgcmVkIGxpbmUgaXMgYSBub25wYXJhbWV0cmljIGVzdGltYXRlIG9mIHRyZW5kICh0YWtlIGNhcmUgbm90IHRvIG92ZXItaW50ZXJwcmV0KSBpdC4NCg0KDQpXb3VsZCB5b3Ugc2F5IHRoZXJlIGlzIHN0cm9uZyBldmlkZW5jZSBvZiBjdXJ2YXR1cmUsIG9yIG9mIGluY3JlYXNpbmcgc3ByZWFkIGluIHJlc2lkdWFscz8NCg0KDQoNCg0KYGBge3IgSGlsbHMubG1EaWFnMiwgZmlnLmNhcD0iTm9ybWFsaXR5IHBsb3Qgb2YgcmVzaWR1YWxzIGZvciB0aGUgZmlyc3QgbW9kZWwgZml0dGVkIHRvIHRoZSBoaWxsIHJhY2luZyBkYXRhIn0NCnBsb3QoSGlsbHMubG0sIHdoaWNoPTIpDQpgYGANCg0KDQoNClRoZSBOb3JtYWwgUS1RIHBsb3QgaXMgZmFyIGZyb20gYSBzdHJhaWdodCBsaW5lLiBUaGlzIGluZGljYXRlcyBmYWlsdXJlIG9mIHRoZSBub3JtYWxpdHkgYXNzdW1wdGlvbi4NCg0KTm90ZSB0aGF0IHRoaXMgcGxvdCBpcyBoZWF2aWx5IGluZmx1ZW5jZWQgYnkgZGF0YSBwb2ludHMgd2l0aCBsYXJnZSByZXNpZHVhbHMuDQoNCmBgYHtyIEhpbGxzLmxtRGlhZzMsIGZpZy5jYXA9IlNjYWxlIHZlcnN1cyBsb2NhdGlvbiBwbG90IGZvciB0aGUgZmlyc3QgbW9kZWwgZml0dGVkIHRvIHRoZSBoaWxsIHJhY2luZyBkYXRhIn0NCnBsb3QoSGlsbHMubG0sIHdoaWNoPTMpDQpgYGANCg0KRm9yIHRoZSBzY2FsZS1sb2NhdGlvbiBwbG90LCB3ZSBsb29rIGZvciBhIHRyZW5kIGZvciB0aGUgbGluZSB0byBiZSBpbmNyZWFzaW5nIChvciBkZWNyZWFzaW5nKSBhcyB3ZSBtb3ZlIGZyb20gbGVmdCB0byByaWdodC4gSWYgc28sIGl0ICBwcm92aWRlcyBhIGhpbnQgdGhhdCBzcHJlYWQgb2YgcmVzaWR1YWxzIGlzIGluY3JlYXNpbmcgKG9yIGRlY3JlYXNpbmcpIHdpdGggZml0dGVkIHZhbHVlLiANCg0KVGhpcyBncmFwaCBzdWdnZXN0cyB0aGUgZXJyb3IgdmFyaWFuY2UgJFxzaWdtYV4yJCBtYXkgbm90IGJlIGNvbnN0YW50IGZvciBhbGwgZGF0YSBwb2ludHMuDQoNCg0KIyMjIFdoYXQgYWJvdXQgYXNzdW1wdGlvbiAqKipBMioqKiwgaW5kZXBlbmRlbnQgZXJyb3I/IFdlIGNhbiBqdXN0IHBsb3QgdGhlIHJlc2lkdWFscyB3aXRob3V0IGFuICp4KiB2YXJpYWJsZS4gDQoNCmBgYHtyIFBsb3RPZkVycm9yc1NlcXVlbmNlfQ0KcGxvdChIaWxscy5sbSRyZXNpZHVhbHMpDQphYmxpbmUoaD0wLCBsdHk9MikNCmBgYA0KDQpUaGUgb3V0bGllcnMgbWFrZSBpdCBoYXJkIHRvIHRlbGwsIGJ1dCB0aGUgZ3JhcGggc3VnZ2VzdHMgdGhlIHJlc2lkdWFscyBtYXkgbm90IGJlIGVudGlyZWx5IHJhbmRvbSAtIHBlcmhhcHMgdGhlcmUgaXMgc29tZSByZWxldmFudCBvcmRlciBpbiB0aGUgZGF0YS4gDQoNCg0KIyMgQ29uY2x1c2lvbnMgZnJvbSBEaWFnbm9zdGljcyBmb3IgRXhhbXBsZSANCg0KTGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwgYXNzdW1wdGlvbnMgZG8gbm90IGFwcGVhciB2YWxpZC4NCg0KSGVuY2UgY29uY2x1c2lvbnMgYmFzZWQgb24gdGhpcyBtb2RlbCBhcmUgcXVlc3Rpb25hYmxlLg0KDQpQcm9ibGVtcyB3aXRoIG1vZGVsIHNlZW0gbGFyZ2VseSBkb3duIHRvIGEgZmV3ICoqb2RkKiogZGF0YSBwb2ludHMgb3IgKipvdXRsaWVycyoqLg0K