Splines and LOESS: Flexible Regression Curves
So far most of our mean models have imposed a fairly simple global
shape. In this lecture we use the Seoul Bike Sharing data to deal with a
different problem: the relationship between demand and weather is
clearly nonlinear. We want the mean response to bend where the data
support it without giving up the regression framework.
By the end of this lecture, students should be able to:
- Explain why a straight-line mean function can be too
restrictive.
- Use LOESS to explore nonlinear structure.
- Explain how cubic splines use knots to let a regression curve change
shape smoothly.
- Fit and interpret cubic and natural cubic splines.
- Explain how degrees of freedom control the flexibility of a cubic
spline.
Running Example: Hourly Bike Demand
Download seoul_bike_hourly.csv
seoul_hourly = read_csv("../data/seoul_bike_hourly.csv")
seoul_hourly
# A tibble: 8,760 × 16
date datetime day_index hour rented_bike_count temperature
<date> <dttm> <dbl> <dbl> <dbl> <dbl>
1 2017-12-01 2017-12-01 00:00:00 1 0 254 -5.2
2 2017-12-01 2017-12-01 01:00:00 1 1 204 -5.5
3 2017-12-01 2017-12-01 02:00:00 1 2 173 -6
4 2017-12-01 2017-12-01 03:00:00 1 3 107 -6.2
5 2017-12-01 2017-12-01 04:00:00 1 4 78 -6
6 2017-12-01 2017-12-01 05:00:00 1 5 100 -6.4
7 2017-12-01 2017-12-01 06:00:00 1 6 181 -6.6
8 2017-12-01 2017-12-01 07:00:00 1 7 460 -7.4
9 2017-12-01 2017-12-01 08:00:00 1 8 930 -7.6
10 2017-12-01 2017-12-01 09:00:00 1 9 490 -6.5
# ℹ 8,750 more rows
# ℹ 10 more variables: humidity <dbl>, wind_speed <dbl>, visibility <dbl>,
# dew_point_temperature <dbl>, solar_radiation <dbl>, rainfall <dbl>,
# snowfall <dbl>, season <chr>, holiday <chr>, functioning_day <chr>
The core question for this lecture is:
How does hourly bike demand change with temperature?
Why Go Beyond Straight Lines?
A straight-line model can underfit. A highly flexible curve can
overfit. Our aim is to describe the mean relationship without losing the
regression framing.
seoul_hourly |>
ggplot(aes(x = temperature, y = rented_bike_count)) + geom_point(alpha = 0.06) +
labs(x = "Temperature (C)", y = "Hourly rented bike count", title = "Bike demand changes nonlinearly with temperature")

Example 1: LOESS
The LOESS Idea
LOESS fits a separate regression at each predictor value where we
want an estimate. At a target value \(x_0\), R’s default LOESS fit uses a local
quadratic working model for observations near \(x_0\):
\[Y_i = \beta_0(x_0) +
\beta_1(x_0)(x_i-x_0) + \beta_2(x_0)(x_i-x_0)^2 +
\varepsilon_i.\]
The coefficients depend on \(x_0\).
We choose them to minimise the weighted sum of squares
\[\sum_{i=1}^n
w_i(x_0)\left\{y_i-\beta_0(x_0)-\beta_1(x_0)(x_i-x_0)-\beta_2(x_0)(x_i-x_0)^2\right\}^2.\]
Local Weights
Observations close to \(x_0\)
receive more weight, while observations outside its neighbourhood or
span receive none. Because we have centred the predictor at
\(x_0\), the fitted value there is
\(\hat f(x_0)=\hat\beta_0(x_0)\).
Repeat the calculation at other values of \(x_0\) and those fitted values form the
curve. There is no single set of quadratic coefficients for the whole
predictor range.
These are distance weights. In the previous lecture, we used weights
to account for differences in precision; here the weights decide which
observations matter for a local fit. For an observation inside
the neighbourhood of \(x_0\), the usual
tricube weight is
\[
w_i(x_0)=\left[1-\left(\frac{|x_i-x_0|}{d(x_0)}\right)^3\right]^3,
\]
with weight zero outside the neighbourhood. Here \(d(x_0)\) is the distance to its edge. The
nearest observations receive the largest weights.
The distinction between these distance weights and Lecture 30’s
precision weights is span sets the proportion of X%
‘closest’ points. Therefore a span of 1 is all points in a neighbourhood
around \(x_0\) and .25 is a quarter of
the points closest to \(x_0\).
Therefore, a small span gives a flexible curve that can follow random
fluctuations. A larger span borrows from farther away, producing a
smoother curve that may miss a sharp change in the mean.
The weight formula is not examinable;
LOESS: Span
Seoul Bike Data
We have already fitted polynomials and piecewise regression models. A
polynomial uses one global curve, so changing its coefficients can alter
the fit across the entire range. A piecewise model lets the shape change
at selected predictor values. Here LOESS gives us another view of the
relationship between temperature and bike demand before we commit to a
particular regression formula.
seoul_hourly |>
ggplot(aes(x = temperature, y = rented_bike_count)) + geom_point(alpha = 0.05) +
geom_smooth(method = "loess", formula = y ~ x, span = 0.15, se = FALSE, linewidth = 1,
aes(colour = "Span = 0.15", alpha = "Span = 0.15")) + geom_smooth(method = "loess",
formula = y ~ x, span = 0.45, se = FALSE, linewidth = 1, aes(colour = "Span = 0.45",
alpha = "Span = 0.45")) + scale_colour_manual(values = c(`Span = 0.15` = "green4",
`Span = 0.45` = "blue")) + scale_alpha_manual(values = c(`Span = 0.15` = 0.8,
`Span = 0.45` = 0.8)) + labs(x = "Temperature (C)", y = "Hourly rented bike count",
colour = "LOESS span", alpha = "LOESS span", title = "LOESS span controls the smoothness of the fitted curve")

The smaller span follows local changes more closely, including random
fluctuations. The larger span smooths those fluctuations but may miss a
sharp change in the mean. Let’s check which features persist across both
curves before choosing a regression formula.
The animation keeps the observations fixed and changes only the span.
Watch what happens to the smaller local features as each fit borrows
information from farther away.

From Piecewise Lines to Cubic Splines
We have already seen the basic idea behind a spline. In Lecture 18, a
piecewise linear model with one knot at \(\kappa\) was
\[
f(x)=\beta_0+\beta_1x+\beta_2(x-\kappa)_+.
\]
The extra term is zero before the knot and changes the slope after
it. The lines join, but there can be a sharp corner at the knot.
A cubic spline uses the same piecewise idea with
cubic curves. One way to write a cubic spline with knots \(\kappa_1,\ldots,\kappa_K\) is
\[
f(x)=\beta_0+\beta_1x+\beta_2x^2+\beta_3x^3
+\sum_{j=1}^{K}\gamma_j(x-\kappa_j)_+^3.
\]
Each new term is zero before its knot. At the knot, \((x-\kappa)_+^3\) and its first two
derivatives are all zero. The new cubic piece can therefore change the
shape after the knot without introducing a jump, a corner, or an abrupt
change in curvature.
So a cubic spline is simply piecewise cubic, with the pieces
joined smoothly. We use the equation to understand the
construction; we do not need to calculate these coefficients by
hand.
Fitting a Cubic Spline in R
R’s bs() function constructs the terms needed to fit a
cubic spline. Cubic is the default, so
lm(rented_bike_count ~ bs(temperature, df = 5), data = seoul_temp)
fits a cubic spline, not a fifth-degree
polynomial.
For a cubic spline fitted with the default
intercept = FALSE,
\[
\text{number of internal knots} = df - 3.
\]
So df = 5 gives two internal knots. Increasing the
degrees of freedom keeps the pieces cubic but adds more internal knots,
giving the curve more places where its curvature can adapt.
Degrees of Freedom and Flexibility
The animation holds the data and the cubic degree fixed. Only the
degrees of freedom change: df = 4, 5, 8, 10. The dashed
lines mark the internal knots. As df increases, the spline
gains more knots and can adapt its curvature in more places.

More flexibility is not automatically better. A larger
df will usually follow the observed data more closely, but
it also gives the fitted mean more opportunity to follow random
variation.
Cubic and Natural Cubic Splines
Now compare three mean functions for exactly the same temperature
data: a straight line, an ordinary cubic spline, and a natural cubic
spline. Both spline fits use df = 5.
lm_cubic_spline <- lm(
rented_bike_count ~ bs(temperature, df = 5),
data = seoul_temp
)
lm_natural_spline <- lm(
rented_bike_count ~ ns(temperature, df = 5),
data = seoul_temp
)
The two R functions use different constructions internally, so the
same df does not imply identical internal knot locations.
What matters here is the difference in the fitted curves, especially
near the boundaries.

Natural Splines at the Boundaries
A cubic regression spline can keep curving beyond the temperatures we
observed. A natural cubic spline is cubic through the
data but is defined to have linear tails beyond its boundary knots,
\(a\) and \(b\). Its curvature is zero where those
tails begin:
\[
f''(a)=0 \qquad\text{and}\qquad f''(b)=0.
\]
The middle of the fitted curve can still bend. The boundary rule
limits what happens at the edges, where the data give us the least
guidance.

The ordinary cubic spline can continue curving; the natural cubic
spline is straight beyond each boundary. Linear tails prevent one kind
of unstable extension, but they do not provide information about bike
demand at unobserved temperatures. A flexible curve will also tend to
fit the observed data more closely, which alone does not make it the
better model.
Where Does the Flexibility Come From?
| Straight line |
\(1,x\) |
One slope everywhere |
| Cubic polynomial |
\(1,x,x^2,x^3\) |
One global cubic curve |
| Piecewise linear |
Line plus hinge terms |
Slope changes at knots |
| Cubic spline |
Smoothly joined cubic pieces |
Curvature can change around knots |
| Natural cubic spline |
Smoothly joined cubic pieces with linear tails |
Curvature can change around knots; straight beyond boundaries |
| LOESS |
Repeated distance-weighted regressions |
Local neighbourhoods |
Comparing Models
Every model below uses the same hourly Seoul observations, and every
panel uses the same axes. The piecewise fit uses the same two knot
locations as the df = 5 cubic spline; the LOESS fit uses
span = 0.45. The polynomial is cubic, and both spline fits
use df = 5.

A Second Nonlinear Signal
Temperature is not the only candidate for nonlinear modelling. Solar
radiation may also have a curved relationship with demand.
seoul_hourly |>
ggplot(aes(x = solar_radiation, y = rented_bike_count)) + geom_point(alpha = 0.05) +
geom_smooth(method = "loess", formula = y ~ x, se = FALSE, linewidth = 1) + labs(x = "Solar radiation",
y = "Hourly rented bike count", title = "Other weather predictors may also need flexible mean functions")

What Have We Changed? What has stayed the same?
We have changed the shape allowed for the mean response. A polynomial
gives us one global curve. Piecewise regression lets the slope change at
knots. Cubic splines keep the piecewise construction but join the pieces
smoothly, and natural splines restrict the tails to straight lines.
LOESS takes a different route: it repeatedly fits a distance-weighted
local regression.
None of these choices removes the question of how much flexibility
the data support. For LOESS, that choice is mainly the span. For a cubic
spline, it is the number and placement of knots, which we control in R
through the degrees of freedom. A close fit to these observations is
not, by itself, evidence that the curve will predict new observations
well.
LOESS is useful when we want to inspect the shape of a relationship
without committing to one global equation. Cubic splines let us put that
flexibility directly into a regression model alongside other predictors.
In the next lecture, time itself enters the mean model: first through a
seasonal indicator in ski sales, then through trend and seasonal terms
for daily Seoul bike demand. Later we will ask whether observations
close together in time can still be treated as independent.
LS0tDQp0aXRsZTogIkxlY3R1cmUgMzE6IFNwbGluZXMgYW5kIExPRVNTOiBGbGV4aWJsZSBSZWdyZXNzaW9uIEN1cnZlcyINCnN1YnRpdGxlOiAxNjEuMjUxIFJlZ3Jlc3Npb24gTW9kZWxsaW5nDQphdXRob3I6ICJQcmVzZW50ZWQgYnkgIiAgDQpkYXRlOiAiV2VlayAxMSBvZiBTZW1lc3RlciAyLCBgciBsdWJyaWRhdGU6OnllYXIobHVicmlkYXRlOjpub3coKSlgIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICB0aGVtZTogeWV0aQ0KICAgIGhpZ2hsaWdodF9zdHlsZTogcHlnbWVudHMNCiAgaHRtbF9ub3RlYm9vazoNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgdGhlbWU6IHlldGkNCiAgICBoaWdobGlnaHRfc3R5bGU6IHB5Z21lbnRzDQogIGlvc2xpZGVzX3ByZXNlbnRhdGlvbjoNCiAgICB3aWRlc2NyZWVuOiB0cnVlDQogICAgc21hbGxlcjogdHJ1ZQ0KICB3b3JkX2RvY3VtZW50OiBkZWZhdWx0DQogIHNsaWR5X3ByZXNlbnRhdGlvbjogDQogICAgdGhlbWU6IHlldGkNCiAgICBoaWdobGlnaHRfc3R5bGU6IHB5Z21lbnRzDQogIHBkZl9kb2N1bWVudDogZGVmYXVsdA0KLS0tDQoNCg0KDQoNCjwhLS0tIERhdGEgaXMgb24NCmh0dHBzOi8vci1yZXNvdXJjZXMubWFzc2V5LmFjLm56L2RhdGEvMTYxMjUxLw0KLS0tPg0KDQpgYGB7ciBzZXR1cCwgcHVybD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0NCmxpYnJhcnkoa25pdHIpDQpvcHRzX2NodW5rJHNldChkZXY9YygicG5nIiwgInBkZiIpKQ0Kb3B0c19jaHVuayRzZXQoZmlnLmhlaWdodD02LCBmaWcud2lkdGg9NywgZmlnLnBhdGg9IkZpZ3VyZXMvIiwgZmlnLmFsdD0idW5sYWJlbGxlZCIpDQpvcHRzX2NodW5rJHNldChjb21tZW50PSIiLCBmaWcuYWxpZ249ImNlbnRlciIsIHRpZHk9VFJVRSkNCm9wdGlvbnMoa25pdHIua2FibGUuTkEgPSAnJykNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShicm9vbSkNCmBgYA0KDQoNCjwhLS0tIERvIG5vdCBlZGl0IGFueXRoaW5nIGFib3ZlIHRoaXMgbGluZS4gLS0tPg0KDQojIyBTcGxpbmVzIGFuZCBMT0VTUzogRmxleGlibGUgUmVncmVzc2lvbiBDdXJ2ZXMNCg0KYGBge3IgbGVjdHVyZTMxLXBhY2thZ2VzLCBpbmNsdWRlPUZBTFNFLCBjYWNoZT1GQUxTRX0NCmxpYnJhcnkoa25pdHIpDQpsaWJyYXJ5KHhmdW4pDQpsaWJyYXJ5KHNwbGluZXMpDQpsaWJyYXJ5KHBhdGNod29yaykNCmBgYA0KDQpTbyBmYXIgbW9zdCBvZiBvdXIgbWVhbiBtb2RlbHMgaGF2ZSBpbXBvc2VkIGEgZmFpcmx5IHNpbXBsZSBnbG9iYWwgc2hhcGUuIEluIHRoaXMgbGVjdHVyZSB3ZSB1c2UgdGhlIFNlb3VsIEJpa2UgU2hhcmluZyBkYXRhIHRvIGRlYWwgd2l0aCBhIGRpZmZlcmVudCBwcm9ibGVtOiB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gZGVtYW5kIGFuZCB3ZWF0aGVyIGlzIGNsZWFybHkgbm9ubGluZWFyLiBXZSB3YW50IHRoZSBtZWFuIHJlc3BvbnNlIHRvIGJlbmQgd2hlcmUgdGhlIGRhdGEgc3VwcG9ydCBpdCB3aXRob3V0IGdpdmluZyB1cCB0aGUgcmVncmVzc2lvbiBmcmFtZXdvcmsuDQoNCkJ5IHRoZSBlbmQgb2YgdGhpcyBsZWN0dXJlLCBzdHVkZW50cyBzaG91bGQgYmUgYWJsZSB0bzoNCg0KMS4gRXhwbGFpbiB3aHkgYSBzdHJhaWdodC1saW5lIG1lYW4gZnVuY3Rpb24gY2FuIGJlIHRvbyByZXN0cmljdGl2ZS4NCjIuIFVzZSBMT0VTUyB0byBleHBsb3JlIG5vbmxpbmVhciBzdHJ1Y3R1cmUuDQozLiBFeHBsYWluIGhvdyBjdWJpYyBzcGxpbmVzIHVzZSBrbm90cyB0byBsZXQgYSByZWdyZXNzaW9uIGN1cnZlIGNoYW5nZSBzaGFwZSBzbW9vdGhseS4NCjQuIEZpdCBhbmQgaW50ZXJwcmV0IGN1YmljIGFuZCBuYXR1cmFsIGN1YmljIHNwbGluZXMuDQo1LiBFeHBsYWluIGhvdyBkZWdyZWVzIG9mIGZyZWVkb20gY29udHJvbCB0aGUgZmxleGliaWxpdHkgb2YgYSBjdWJpYyBzcGxpbmUuDQoNCiMjIFJ1bm5pbmcgRXhhbXBsZTogSG91cmx5IEJpa2UgRGVtYW5kDQoNCmByIGVtYmVkX2ZpbGUoIi4uL2RhdGEvc2VvdWxfYmlrZV9ob3VybHkuY3N2IilgDQoNCmBgYHtyIHJlYWQtc2VvdWwtaG91cmx5LCBtZXNzYWdlPUZBTFNFfQ0Kc2VvdWxfaG91cmx5ID0gcmVhZF9jc3YoIi4uL2RhdGEvc2VvdWxfYmlrZV9ob3VybHkuY3N2IikNCnNlb3VsX2hvdXJseQ0KYGBgDQoNClRoZSBjb3JlIHF1ZXN0aW9uIGZvciB0aGlzIGxlY3R1cmUgaXM6DQoNCj4gSG93IGRvZXMgaG91cmx5IGJpa2UgZGVtYW5kIGNoYW5nZSB3aXRoIHRlbXBlcmF0dXJlPw0KDQojIyMgV2h5IEdvIEJleW9uZCBTdHJhaWdodCBMaW5lcz8NCg0KQSBzdHJhaWdodC1saW5lIG1vZGVsIGNhbiB1bmRlcmZpdC4gQSBoaWdobHkgZmxleGlibGUgY3VydmUgY2FuIG92ZXJmaXQuIE91ciBhaW0gaXMgdG8gZGVzY3JpYmUgdGhlIG1lYW4gcmVsYXRpb25zaGlwIHdpdGhvdXQgbG9zaW5nIHRoZSByZWdyZXNzaW9uIGZyYW1pbmcuDQoNCmBgYHtyIHNlb3VsLXRlbXBlcmF0dXJlLXNjYXR0ZXIsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQpzZW91bF9ob3VybHkgfD4NCiAgZ2dwbG90KGFlcyh4ID0gdGVtcGVyYXR1cmUsIHkgPSByZW50ZWRfYmlrZV9jb3VudCkpICsNCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMDYpICsNCiAgbGFicygNCiAgICB4ID0gIlRlbXBlcmF0dXJlIChDKSIsDQogICAgeSA9ICJIb3VybHkgcmVudGVkIGJpa2UgY291bnQiLA0KICAgIHRpdGxlID0gIkJpa2UgZGVtYW5kIGNoYW5nZXMgbm9ubGluZWFybHkgd2l0aCB0ZW1wZXJhdHVyZSINCiAgKQ0KYGBgDQoNCiMjIEV4YW1wbGUgMTogTE9FU1MNCg0KIyMjIFRoZSBMT0VTUyBJZGVhDQoNCkxPRVNTIGZpdHMgYSBzZXBhcmF0ZSByZWdyZXNzaW9uIGF0IGVhY2ggcHJlZGljdG9yIHZhbHVlIHdoZXJlIHdlIHdhbnQgYW4gZXN0aW1hdGUuIEF0IGEgdGFyZ2V0IHZhbHVlICR4XzAkLCBSJ3MgZGVmYXVsdCBMT0VTUyBmaXQgdXNlcyBhIGxvY2FsIHF1YWRyYXRpYyB3b3JraW5nIG1vZGVsIGZvciBvYnNlcnZhdGlvbnMgbmVhciAkeF8wJDoNCg0KJCRZX2kgPSBcYmV0YV8wKHhfMCkgKyBcYmV0YV8xKHhfMCkoeF9pLXhfMCkgKyBcYmV0YV8yKHhfMCkoeF9pLXhfMCleMiArIFx2YXJlcHNpbG9uX2kuJCQNCg0KVGhlIGNvZWZmaWNpZW50cyBkZXBlbmQgb24gJHhfMCQuIFdlIGNob29zZSB0aGVtIHRvIG1pbmltaXNlIHRoZSB3ZWlnaHRlZCBzdW0gb2Ygc3F1YXJlcw0KDQokJFxzdW1fe2k9MX1ebiB3X2koeF8wKVxsZWZ0XHt5X2ktXGJldGFfMCh4XzApLVxiZXRhXzEoeF8wKSh4X2kteF8wKS1cYmV0YV8yKHhfMCkoeF9pLXhfMCleMlxyaWdodFx9XjIuJCQNCg0KIyMjIExvY2FsIFdlaWdodHMNCg0KT2JzZXJ2YXRpb25zIGNsb3NlIHRvICR4XzAkIHJlY2VpdmUgbW9yZSB3ZWlnaHQsIHdoaWxlIG9ic2VydmF0aW9ucyBvdXRzaWRlIGl0cyBuZWlnaGJvdXJob29kIG9yIGBzcGFuYCByZWNlaXZlIG5vbmUuIEJlY2F1c2Ugd2UgaGF2ZSBjZW50cmVkIHRoZSBwcmVkaWN0b3IgYXQgJHhfMCQsIHRoZSBmaXR0ZWQgdmFsdWUgdGhlcmUgaXMgJFxoYXQgZih4XzApPVxoYXRcYmV0YV8wKHhfMCkkLiBSZXBlYXQgdGhlIGNhbGN1bGF0aW9uIGF0IG90aGVyIHZhbHVlcyBvZiAkeF8wJCBhbmQgdGhvc2UgZml0dGVkIHZhbHVlcyBmb3JtIHRoZSBjdXJ2ZS4gVGhlcmUgaXMgbm8gc2luZ2xlIHNldCBvZiBxdWFkcmF0aWMgY29lZmZpY2llbnRzIGZvciB0aGUgd2hvbGUgcHJlZGljdG9yIHJhbmdlLg0KDQpUaGVzZSBhcmUgZGlzdGFuY2Ugd2VpZ2h0cy4gSW4gdGhlIHByZXZpb3VzIGxlY3R1cmUsIHdlIHVzZWQgd2VpZ2h0cyB0byBhY2NvdW50IGZvciBkaWZmZXJlbmNlcyBpbiBwcmVjaXNpb247IGhlcmUgdGhlIHdlaWdodHMgZGVjaWRlIHdoaWNoIG9ic2VydmF0aW9ucyBtYXR0ZXIgZm9yIGEgKmxvY2FsKiBmaXQuIEZvciBhbiBvYnNlcnZhdGlvbiBpbnNpZGUgdGhlIG5laWdoYm91cmhvb2Qgb2YgJHhfMCQsIHRoZSB1c3VhbCB0cmljdWJlIHdlaWdodCBpcw0KDQokJA0Kd19pKHhfMCk9XGxlZnRbMS1cbGVmdChcZnJhY3t8eF9pLXhfMHx9e2QoeF8wKX1ccmlnaHQpXjNccmlnaHRdXjMsDQokJA0KDQp3aXRoIHdlaWdodCB6ZXJvIG91dHNpZGUgdGhlIG5laWdoYm91cmhvb2QuIEhlcmUgJGQoeF8wKSQgaXMgdGhlIGRpc3RhbmNlIHRvIGl0cyBlZGdlLiBUaGUgbmVhcmVzdCBvYnNlcnZhdGlvbnMgcmVjZWl2ZSB0aGUgbGFyZ2VzdCB3ZWlnaHRzLiANCg0KVGhlIGRpc3RpbmN0aW9uIGJldHdlZW4gdGhlc2UgZGlzdGFuY2Ugd2VpZ2h0cyBhbmQgTGVjdHVyZSAzMCdzIHByZWNpc2lvbiB3ZWlnaHRzIGlzIGBzcGFuYCBzZXRzIHRoZSBwcm9wb3J0aW9uIG9mIFglICdjbG9zZXN0JyBwb2ludHMuIFRoZXJlZm9yZSBhIHNwYW4gb2YgMSBpcyBhbGwgcG9pbnRzIGluIGEgbmVpZ2hib3VyaG9vZCBhcm91bmQgJHhfMCQgYW5kIC4yNSBpcyBhIHF1YXJ0ZXIgb2YgdGhlIHBvaW50cyBjbG9zZXN0IHRvICR4XzAkLiBUaGVyZWZvcmUsIGEgc21hbGwgc3BhbiBnaXZlcyBhIGZsZXhpYmxlIGN1cnZlIHRoYXQgY2FuIGZvbGxvdyByYW5kb20gZmx1Y3R1YXRpb25zLiBBIGxhcmdlciBzcGFuIGJvcnJvd3MgZnJvbSBmYXJ0aGVyIGF3YXksIHByb2R1Y2luZyBhIHNtb290aGVyIGN1cnZlIHRoYXQgbWF5IG1pc3MgYSBzaGFycCBjaGFuZ2UgaW4gdGhlIG1lYW4uDQoNCioqVGhlIHdlaWdodCBmb3JtdWxhIGlzIG5vdCBleGFtaW5hYmxlKio7IA0KDQojIyBMT0VTUzogU3Bhbg0KDQojIyMgU2VvdWwgQmlrZSBEYXRhDQoNCldlIGhhdmUgYWxyZWFkeSBmaXR0ZWQgcG9seW5vbWlhbHMgYW5kIHBpZWNld2lzZSByZWdyZXNzaW9uIG1vZGVscy4gQSBwb2x5bm9taWFsIHVzZXMgb25lIGdsb2JhbCBjdXJ2ZSwgc28gY2hhbmdpbmcgaXRzIGNvZWZmaWNpZW50cyBjYW4gYWx0ZXIgdGhlIGZpdCBhY3Jvc3MgdGhlIGVudGlyZSByYW5nZS4gQSBwaWVjZXdpc2UgbW9kZWwgbGV0cyB0aGUgc2hhcGUgY2hhbmdlIGF0IHNlbGVjdGVkIHByZWRpY3RvciB2YWx1ZXMuIEhlcmUgTE9FU1MgZ2l2ZXMgdXMgYW5vdGhlciB2aWV3IG9mIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0ZW1wZXJhdHVyZSBhbmQgYmlrZSBkZW1hbmQgYmVmb3JlIHdlIGNvbW1pdCB0byBhIHBhcnRpY3VsYXIgcmVncmVzc2lvbiBmb3JtdWxhLg0KDQpgYGB7ciBsb2Vzcy1zZW91bCwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCnNlb3VsX2hvdXJseSB8Pg0KICBnZ3Bsb3QoYWVzKHggPSB0ZW1wZXJhdHVyZSwgeSA9IHJlbnRlZF9iaWtlX2NvdW50KSkgKw0KICBnZW9tX3BvaW50KGFscGhhID0gMC4wNSkgKw0KICBnZW9tX3Ntb290aCgNCiAgICBtZXRob2QgPSAibG9lc3MiLA0KICAgIGZvcm11bGEgPSB5IH4geCwNCiAgICBzcGFuID0gMC4xNSwNCiAgICBzZSA9IEZBTFNFLA0KICAgIGxpbmV3aWR0aCA9IDEsDQogICAgYWVzKGNvbG91ciA9ICJTcGFuID0gMC4xNSIsIGFscGhhID0gIlNwYW4gPSAwLjE1IikNCiAgKSArDQogIGdlb21fc21vb3RoKA0KICAgIG1ldGhvZCA9ICJsb2VzcyIsDQogICAgZm9ybXVsYSA9IHkgfiB4LA0KICAgIHNwYW4gPSAwLjQ1LA0KICAgIHNlID0gRkFMU0UsDQogICAgbGluZXdpZHRoID0gMSwNCiAgICBhZXMoY29sb3VyID0gIlNwYW4gPSAwLjQ1IiwgYWxwaGEgPSAiU3BhbiA9IDAuNDUiKQ0KICApICsNCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJTcGFuID0gMC4xNSIgPSAiZ3JlZW40IiwgIlNwYW4gPSAwLjQ1IiA9ICJibHVlIikpICsNCiAgc2NhbGVfYWxwaGFfbWFudWFsKHZhbHVlcyA9IGMoIlNwYW4gPSAwLjE1IiA9IDAuOCwgIlNwYW4gPSAwLjQ1IiA9IDAuOCkpICsNCiAgbGFicygNCiAgICB4ID0gIlRlbXBlcmF0dXJlIChDKSIsDQogICAgeSA9ICJIb3VybHkgcmVudGVkIGJpa2UgY291bnQiLA0KICAgIGNvbG91ciA9ICJMT0VTUyBzcGFuIiwNCiAgICBhbHBoYSA9ICJMT0VTUyBzcGFuIiwNCiAgICB0aXRsZSA9ICJMT0VTUyBzcGFuIGNvbnRyb2xzIHRoZSBzbW9vdGhuZXNzIG9mIHRoZSBmaXR0ZWQgY3VydmUiDQogICkNCmBgYA0KDQpUaGUgc21hbGxlciBzcGFuIGZvbGxvd3MgbG9jYWwgY2hhbmdlcyBtb3JlIGNsb3NlbHksIGluY2x1ZGluZyByYW5kb20gZmx1Y3R1YXRpb25zLiBUaGUgbGFyZ2VyIHNwYW4gc21vb3RocyB0aG9zZSBmbHVjdHVhdGlvbnMgYnV0IG1heSBtaXNzIGEgc2hhcnAgY2hhbmdlIGluIHRoZSBtZWFuLiBMZXQncyBjaGVjayB3aGljaCBmZWF0dXJlcyBwZXJzaXN0IGFjcm9zcyBib3RoIGN1cnZlcyBiZWZvcmUgY2hvb3NpbmcgYSByZWdyZXNzaW9uIGZvcm11bGEuDQoNClRoZSBhbmltYXRpb24ga2VlcHMgdGhlIG9ic2VydmF0aW9ucyBmaXhlZCBhbmQgY2hhbmdlcyBvbmx5IHRoZSBzcGFuLiBXYXRjaCB3aGF0IGhhcHBlbnMgdG8gdGhlIHNtYWxsZXIgbG9jYWwgZmVhdHVyZXMgYXMgZWFjaCBmaXQgYm9ycm93cyBpbmZvcm1hdGlvbiBmcm9tIGZhcnRoZXIgYXdheS4NCg0KYGBge3IgbG9lc3Mtc3Bhbi1hbmltYXRpb24sIGVjaG89RkFMU0UsIHJlc3VsdHM9J2FzaXMnLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0KbG9lc3NfZ2lmIDwtICIuLi9ncmFwaGljcy9sZWN0dXJlMzEvbG9lc3Mtc3Bhbi5naWYiDQoNCmlmIChmaWxlLmV4aXN0cyhsb2Vzc19naWYpICYmIHBhbmRvY190bygpICVpbiUgYygiaHRtbCIsICJodG1sNCIsICJodG1sNSIsICJzbGlkeSIpKSB7DQogIGNhdChzcHJpbnRmKCc8aW1nIHNyYz0iJXMiIHN0eWxlPSJ3aWR0aDo4NSUlO2Rpc3BsYXk6YmxvY2s7bWFyZ2luOmF1dG87IiBhbHQ9IkFuaW1hdGVkIExPRVNTIGZpdHMgd2l0aCBpbmNyZWFzaW5nIHNwYW4iPlxuJywgbG9lc3NfZ2lmKSkNCn0gZWxzZSB7DQogIGxvZXNzX3NwYW5zIDwtIGMoMC4xNSwgMC4zMCwgMC40NSwgMC42MCkNCg0KICBsb2Vzc19zdGF0aWMgPC0gcHVycnI6Om1hcF9kZnIobG9lc3Nfc3BhbnMsIGZ1bmN0aW9uKHNwYW5fdmFsdWUpIHsNCiAgICBmaXQgPC0gbG9lc3MoDQogICAgICByZW50ZWRfYmlrZV9jb3VudCB+IHRlbXBlcmF0dXJlLA0KICAgICAgZGF0YSA9IHNlb3VsX2hvdXJseSwNCiAgICAgIHNwYW4gPSBzcGFuX3ZhbHVlLA0KICAgICAgZGVncmVlID0gMiwNCiAgICAgIGNvbnRyb2wgPSBsb2Vzcy5jb250cm9sKHN1cmZhY2UgPSAiZGlyZWN0IikNCiAgICApDQoNCiAgICBncmlkIDwtIHRpYmJsZSgNCiAgICAgIHRlbXBlcmF0dXJlID0gc2VxKA0KICAgICAgICBtaW4oc2VvdWxfaG91cmx5JHRlbXBlcmF0dXJlKSwNCiAgICAgICAgbWF4KHNlb3VsX2hvdXJseSR0ZW1wZXJhdHVyZSksDQogICAgICAgIGxlbmd0aC5vdXQgPSAyNTANCiAgICAgICkNCiAgICApDQoNCiAgICBncmlkIHw+DQogICAgICBtdXRhdGUoDQogICAgICAgIGZpdHRlZCA9IHByZWRpY3QoZml0LCBuZXdkYXRhID0gZ3JpZCksDQogICAgICAgIHNwYW4gPSBmYWN0b3Ioc3Bhbl92YWx1ZSwgbGV2ZWxzID0gbG9lc3Nfc3BhbnMpDQogICAgICApDQogIH0pDQoNCiAgcHJpbnQoDQogICAgZ2dwbG90KHNlb3VsX2hvdXJseSwgYWVzKHRlbXBlcmF0dXJlLCByZW50ZWRfYmlrZV9jb3VudCkpICsNCiAgICAgIGdlb21fcG9pbnQoYWxwaGEgPSAwLjAzNSwgc2l6ZSA9IDAuMzUpICsNCiAgICAgIGdlb21fbGluZSgNCiAgICAgICAgZGF0YSA9IGxvZXNzX3N0YXRpYywNCiAgICAgICAgYWVzKHkgPSBmaXR0ZWQpLA0KICAgICAgICBjb2xvdXIgPSAiZm9yZXN0Z3JlZW4iLA0KICAgICAgICBsaW5ld2lkdGggPSAwLjkNCiAgICAgICkgKw0KICAgICAgZmFjZXRfd3JhcCh+c3BhbiwgbmNvbCA9IDIsIGxhYmVsbGVyID0gbGFiZWxfYm90aCkgKw0KICAgICAgbGFicygNCiAgICAgICAgeCA9ICJUZW1wZXJhdHVyZSAowrBDKSIsDQogICAgICAgIHkgPSAiSG91cmx5IHJlbnRlZCBiaWtlIGNvdW50IiwNCiAgICAgICAgdGl0bGUgPSAiTGFyZ2VyIExPRVNTIHNwYW5zIHByb2R1Y2Ugc21vb3RoZXIgZml0dGVkIGN1cnZlcyINCiAgICAgICkNCiAgKQ0KfQ0KYGBgDQoNCg0KDQojIyBGcm9tIFBpZWNld2lzZSBMaW5lcyB0byBDdWJpYyBTcGxpbmVzDQoNCldlIGhhdmUgYWxyZWFkeSBzZWVuIHRoZSBiYXNpYyBpZGVhIGJlaGluZCBhIHNwbGluZS4gSW4gTGVjdHVyZSAxOCwgYSBwaWVjZXdpc2UgbGluZWFyIG1vZGVsIHdpdGggb25lIGtub3QgYXQgJFxrYXBwYSQgd2FzDQoNCiQkDQpmKHgpPVxiZXRhXzArXGJldGFfMXgrXGJldGFfMih4LVxrYXBwYSlfKy4NCiQkDQoNClRoZSBleHRyYSB0ZXJtIGlzIHplcm8gYmVmb3JlIHRoZSBrbm90IGFuZCBjaGFuZ2VzIHRoZSBzbG9wZSBhZnRlciBpdC4gVGhlIGxpbmVzIGpvaW4sIGJ1dCB0aGVyZSBjYW4gYmUgYSBzaGFycCBjb3JuZXIgYXQgdGhlIGtub3QuDQoNCkEgKipjdWJpYyBzcGxpbmUqKiB1c2VzIHRoZSBzYW1lIHBpZWNld2lzZSBpZGVhIHdpdGggY3ViaWMgY3VydmVzLiBPbmUgd2F5IHRvIHdyaXRlIGEgY3ViaWMgc3BsaW5lIHdpdGgga25vdHMgJFxrYXBwYV8xLFxsZG90cyxca2FwcGFfSyQgaXMNCg0KJCQNCmYoeCk9XGJldGFfMCtcYmV0YV8xeCtcYmV0YV8yeF4yK1xiZXRhXzN4XjMNCiAgICAgK1xzdW1fe2o9MX1ee0t9XGdhbW1hX2ooeC1ca2FwcGFfailfK14zLg0KJCQNCg0KRWFjaCBuZXcgdGVybSBpcyB6ZXJvIGJlZm9yZSBpdHMga25vdC4gQXQgdGhlIGtub3QsICQoeC1ca2FwcGEpXyteMyQgYW5kIGl0cyBmaXJzdCB0d28gZGVyaXZhdGl2ZXMgYXJlIGFsbCB6ZXJvLiBUaGUgbmV3IGN1YmljIHBpZWNlIGNhbiB0aGVyZWZvcmUgY2hhbmdlIHRoZSBzaGFwZSBhZnRlciB0aGUga25vdCB3aXRob3V0IGludHJvZHVjaW5nIGEganVtcCwgYSBjb3JuZXIsIG9yIGFuIGFicnVwdCBjaGFuZ2UgaW4gY3VydmF0dXJlLg0KDQpTbyBhIGN1YmljIHNwbGluZSBpcyBzaW1wbHkgKipwaWVjZXdpc2UgY3ViaWMsIHdpdGggdGhlIHBpZWNlcyBqb2luZWQgc21vb3RobHkqKi4gV2UgdXNlIHRoZSBlcXVhdGlvbiB0byB1bmRlcnN0YW5kIHRoZSBjb25zdHJ1Y3Rpb247IHdlIGRvIG5vdCBuZWVkIHRvIGNhbGN1bGF0ZSB0aGVzZSBjb2VmZmljaWVudHMgYnkgaGFuZC4NCg0KIyMgRml0dGluZyBhIEN1YmljIFNwbGluZSBpbiBSDQoNClIncyBgYnMoKWAgZnVuY3Rpb24gY29uc3RydWN0cyB0aGUgdGVybXMgbmVlZGVkIHRvIGZpdCBhIGN1YmljIHNwbGluZS4gQ3ViaWMgaXMgdGhlIGRlZmF1bHQsIHNvDQoNCmBgYHINCmxtKHJlbnRlZF9iaWtlX2NvdW50IH4gYnModGVtcGVyYXR1cmUsIGRmID0gNSksIGRhdGEgPSBzZW91bF90ZW1wKQ0KYGBgDQoNCmZpdHMgYSAqKmN1YmljIHNwbGluZSoqLCBub3QgYSBmaWZ0aC1kZWdyZWUgcG9seW5vbWlhbC4NCg0KRm9yIGEgY3ViaWMgc3BsaW5lIGZpdHRlZCB3aXRoIHRoZSBkZWZhdWx0IGBpbnRlcmNlcHQgPSBGQUxTRWAsDQoNCiQkDQpcdGV4dHtudW1iZXIgb2YgaW50ZXJuYWwga25vdHN9ID0gZGYgLSAzLg0KJCQNCg0KU28gYGRmID0gNWAgZ2l2ZXMgdHdvIGludGVybmFsIGtub3RzLiBJbmNyZWFzaW5nIHRoZSBkZWdyZWVzIG9mIGZyZWVkb20ga2VlcHMgdGhlIHBpZWNlcyBjdWJpYyBidXQgYWRkcyBtb3JlIGludGVybmFsIGtub3RzLCBnaXZpbmcgdGhlIGN1cnZlIG1vcmUgcGxhY2VzIHdoZXJlIGl0cyBjdXJ2YXR1cmUgY2FuIGFkYXB0Lg0KDQpgYGB7ciBzcGxpbmUtc2VvdWwtc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQpzZW91bF90ZW1wIDwtIHNlb3VsX2hvdXJseSB8Pg0KICBzZWxlY3QodGVtcGVyYXR1cmUsIHJlbnRlZF9iaWtlX2NvdW50KSB8Pg0KICBmaWx0ZXIoaXMuZmluaXRlKHRlbXBlcmF0dXJlKSwgaXMuZmluaXRlKHJlbnRlZF9iaWtlX2NvdW50KSkNCg0KbG1fbGluZWFyIDwtIGxtKHJlbnRlZF9iaWtlX2NvdW50IH4gdGVtcGVyYXR1cmUsIGRhdGEgPSBzZW91bF90ZW1wKQ0KbG1fY3ViaWNfc3BsaW5lIDwtIGxtKA0KICByZW50ZWRfYmlrZV9jb3VudCB+IGJzKHRlbXBlcmF0dXJlLCBkZiA9IDUpLA0KICBkYXRhID0gc2VvdWxfdGVtcA0KKQ0KbG1fbmF0dXJhbF9zcGxpbmUgPC0gbG0oDQogIHJlbnRlZF9iaWtlX2NvdW50IH4gbnModGVtcGVyYXR1cmUsIGRmID0gNSksDQogIGRhdGEgPSBzZW91bF90ZW1wDQopDQoNCmN1YmljX3NwbGluZV90ZXJtcyA8LSBicyhzZW91bF90ZW1wJHRlbXBlcmF0dXJlLCBkZiA9IDUpDQpzcGxpbmVfa25vdHMgPC0gYXR0cihjdWJpY19zcGxpbmVfdGVybXMsICJrbm90cyIpDQp0ZW1wX2dyaWQgPC0gdGliYmxlKA0KICB0ZW1wZXJhdHVyZSA9IHNlcSgNCiAgICBtaW4oc2VvdWxfdGVtcCR0ZW1wZXJhdHVyZSksDQogICAgbWF4KHNlb3VsX3RlbXAkdGVtcGVyYXR1cmUpLA0KICAgIGxlbmd0aC5vdXQgPSAyNTANCiAgKQ0KKQ0KYGBgDQoNCiMjIERlZ3JlZXMgb2YgRnJlZWRvbSBhbmQgRmxleGliaWxpdHkNCg0KVGhlIGFuaW1hdGlvbiBob2xkcyB0aGUgZGF0YSBhbmQgdGhlIGN1YmljIGRlZ3JlZSBmaXhlZC4gT25seSB0aGUgZGVncmVlcyBvZiBmcmVlZG9tIGNoYW5nZTogYGRmID0gNCwgNSwgOCwgMTBgLiBUaGUgZGFzaGVkIGxpbmVzIG1hcmsgdGhlIGludGVybmFsIGtub3RzLiBBcyBgZGZgIGluY3JlYXNlcywgdGhlIHNwbGluZSBnYWlucyBtb3JlIGtub3RzIGFuZCBjYW4gYWRhcHQgaXRzIGN1cnZhdHVyZSBpbiBtb3JlIHBsYWNlcy4NCg0KYGBge3Igc3BsaW5lLWRmLWFuaW1hdGlvbiwgZWNobz1GQUxTRSwgcmVzdWx0cz0nYXNpcycsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQpzcGxpbmVfZ2lmIDwtICIuLi9ncmFwaGljcy9sZWN0dXJlMzEvY3ViaWMtc3BsaW5lLWRmLmdpZiINCg0KaWYgKGZpbGUuZXhpc3RzKHNwbGluZV9naWYpICYmIHBhbmRvY190bygpICVpbiUgYygiaHRtbCIsICJodG1sNCIsICJodG1sNSIsICJzbGlkeSIpKSB7DQogIGNhdChzcHJpbnRmKCc8aW1nIHNyYz0iJXMiIHN0eWxlPSJ3aWR0aDo4NSUlO2Rpc3BsYXk6YmxvY2s7bWFyZ2luOmF1dG87IiBhbHQ9IkFuaW1hdGVkIGN1YmljIHNwbGluZSBmaXRzIHdpdGggaW5jcmVhc2luZyBkZWdyZWVzIG9mIGZyZWVkb20iPlxuJywgc3BsaW5lX2dpZikpDQp9IGVsc2Ugew0KICBzcGxpbmVfZGZzIDwtIGMoNCwgNSwgOCwgMTApDQoNCiAgc3BsaW5lX3N0YXRpYyA8LSBwdXJycjo6bWFwX2RmcihzcGxpbmVfZGZzLCBmdW5jdGlvbihkZl92YWx1ZSkgew0KICAgIGZpdCA8LSBsbSgNCiAgICAgIHJlbnRlZF9iaWtlX2NvdW50IH4gYnModGVtcGVyYXR1cmUsIGRmID0gZGZfdmFsdWUpLA0KICAgICAgZGF0YSA9IHNlb3VsX3RlbXANCiAgICApDQoNCiAgICBncmlkIDwtIHRlbXBfZ3JpZCB8Pg0KICAgICAgbXV0YXRlKA0KICAgICAgICBmaXR0ZWQgPSBwcmVkaWN0KGZpdCwgbmV3ZGF0YSA9IHRlbXBfZ3JpZCksDQogICAgICAgIGRmID0gZmFjdG9yKGRmX3ZhbHVlLCBsZXZlbHMgPSBzcGxpbmVfZGZzKQ0KICAgICAgKQ0KDQogICAgZ3JpZA0KICB9KQ0KDQogIHByaW50KA0KICAgIGdncGxvdChzZW91bF90ZW1wLCBhZXModGVtcGVyYXR1cmUsIHJlbnRlZF9iaWtlX2NvdW50KSkgKw0KICAgICAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMDM1LCBzaXplID0gMC4zNSkgKw0KICAgICAgZ2VvbV9saW5lKA0KICAgICAgICBkYXRhID0gc3BsaW5lX3N0YXRpYywNCiAgICAgICAgYWVzKHkgPSBmaXR0ZWQpLA0KICAgICAgICBjb2xvdXIgPSAiYmx1ZTMiLA0KICAgICAgICBsaW5ld2lkdGggPSAwLjkNCiAgICAgICkgKw0KICAgICAgZmFjZXRfd3JhcCh+ZGYsIG5jb2wgPSAyLCBsYWJlbGxlciA9IGxhYmVsX2JvdGgpICsNCiAgICAgIGxhYnMoDQogICAgICAgIHggPSAiVGVtcGVyYXR1cmUgKMKwQykiLA0KICAgICAgICB5ID0gIkhvdXJseSByZW50ZWQgYmlrZSBjb3VudCIsDQogICAgICAgIHRpdGxlID0gIk1vcmUgc3BsaW5lIGRlZ3JlZXMgb2YgZnJlZWRvbSBhbGxvdyBtb3JlIGxvY2FsIGN1cnZhdHVyZSINCiAgICAgICkNCiAgKQ0KfQ0KYGBgDQoNCk1vcmUgZmxleGliaWxpdHkgaXMgbm90IGF1dG9tYXRpY2FsbHkgYmV0dGVyLiBBIGxhcmdlciBgZGZgIHdpbGwgdXN1YWxseSBmb2xsb3cgdGhlIG9ic2VydmVkIGRhdGEgbW9yZSBjbG9zZWx5LCBidXQgaXQgYWxzbyBnaXZlcyB0aGUgZml0dGVkIG1lYW4gbW9yZSBvcHBvcnR1bml0eSB0byBmb2xsb3cgcmFuZG9tIHZhcmlhdGlvbi4NCg0KIyMgQ3ViaWMgYW5kIE5hdHVyYWwgQ3ViaWMgU3BsaW5lcw0KDQpOb3cgY29tcGFyZSB0aHJlZSBtZWFuIGZ1bmN0aW9ucyBmb3IgZXhhY3RseSB0aGUgc2FtZSB0ZW1wZXJhdHVyZSBkYXRhOiBhIHN0cmFpZ2h0IGxpbmUsIGFuIG9yZGluYXJ5IGN1YmljIHNwbGluZSwgYW5kIGEgbmF0dXJhbCBjdWJpYyBzcGxpbmUuIEJvdGggc3BsaW5lIGZpdHMgdXNlIGBkZiA9IDVgLg0KDQpgYGByDQpsbV9jdWJpY19zcGxpbmUgPC0gbG0oDQogIHJlbnRlZF9iaWtlX2NvdW50IH4gYnModGVtcGVyYXR1cmUsIGRmID0gNSksDQogIGRhdGEgPSBzZW91bF90ZW1wDQopDQoNCmxtX25hdHVyYWxfc3BsaW5lIDwtIGxtKA0KICByZW50ZWRfYmlrZV9jb3VudCB+IG5zKHRlbXBlcmF0dXJlLCBkZiA9IDUpLA0KICBkYXRhID0gc2VvdWxfdGVtcA0KKQ0KYGBgDQoNClRoZSB0d28gUiBmdW5jdGlvbnMgdXNlIGRpZmZlcmVudCBjb25zdHJ1Y3Rpb25zIGludGVybmFsbHksIHNvIHRoZSBzYW1lIGBkZmAgZG9lcyBub3QgaW1wbHkgaWRlbnRpY2FsIGludGVybmFsIGtub3QgbG9jYXRpb25zLiBXaGF0IG1hdHRlcnMgaGVyZSBpcyB0aGUgZGlmZmVyZW5jZSBpbiB0aGUgZml0dGVkIGN1cnZlcywgZXNwZWNpYWxseSBuZWFyIHRoZSBib3VuZGFyaWVzLg0KDQpgYGB7ciBzcGxpbmUtc2VvdWwtbW9kZWxzLCBlY2hvPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBmaWcuaGVpZ2h0PTV9DQpwcmVkaWN0aW9ucyA8LSB0ZW1wX2dyaWQgfD4NCiAgbXV0YXRlKA0KICAgIGxpbmVhciA9IHByZWRpY3QobG1fbGluZWFyLCBuZXdkYXRhID0gdGVtcF9ncmlkKSwNCiAgICBjdWJpY19zcGxpbmUgPSBwcmVkaWN0KGxtX2N1YmljX3NwbGluZSwgbmV3ZGF0YSA9IHRlbXBfZ3JpZCksDQogICAgbmF0dXJhbF9zcGxpbmUgPSBwcmVkaWN0KGxtX25hdHVyYWxfc3BsaW5lLCBuZXdkYXRhID0gdGVtcF9ncmlkKQ0KICApIHw+DQogIHBpdm90X2xvbmdlcigtdGVtcGVyYXR1cmUsIG5hbWVzX3RvID0gIm1vZGVsIiwNCiAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJmaXR0ZWRfYmlrZXMiKSB8Pg0KICBtdXRhdGUobW9kZWwgPSByZWNvZGVfdmFsdWVzKA0KICAgIG1vZGVsLA0KICAgICJsaW5lYXIiIH4gIkxpbmVhciIsDQogICAgImN1YmljX3NwbGluZSIgfiAiQ3ViaWMgc3BsaW5lIiwNCiAgICAibmF0dXJhbF9zcGxpbmUiIH4gIk5hdHVyYWwgY3ViaWMgc3BsaW5lIiwNCiAgICB1bm1hdGNoZWQgPSAiZXJyb3IiDQogICkpDQoNCnNlb3VsX3RlbXAgfD4NCiAgZ2dwbG90KGFlcyh0ZW1wZXJhdHVyZSwgcmVudGVkX2Jpa2VfY291bnQpKSArDQogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjA1KSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IHNwbGluZV9rbm90cywNCiAgICAgICAgICAgICBjb2xvdXIgPSAiZ3JleTQ1IiwgbGluZXR5cGUgPSAiZGFzaGVkIiwNCiAgICAgICAgICAgICBsaW5ld2lkdGggPSAwLjUpICsNCiAgZ2VvbV9saW5lKA0KICAgIGRhdGEgPSBwcmVkaWN0aW9ucywNCiAgICBhZXModGVtcGVyYXR1cmUsIGZpdHRlZF9iaWtlcywgY29sb3VyID0gbW9kZWwsDQogICAgICAgIGxpbmV0eXBlID0gbW9kZWwpLCBsaW5ld2lkdGggPSAxDQogICkgKw0KICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoDQogICAgTGluZWFyID0gInJlZCIsICJDdWJpYyBzcGxpbmUiID0gImJsdWUiLA0KICAgICJOYXR1cmFsIGN1YmljIHNwbGluZSIgPSAiZm9yZXN0Z3JlZW4iDQogICkpICsNCiAgbGFicygNCiAgICB4ID0gIlRlbXBlcmF0dXJlICjCsEMpIiwgeSA9ICJIb3VybHkgcmVudGVkIGJpa2UgY291bnQiLA0KICAgIGNvbG91ciA9ICJNb2RlbCIsIGxpbmV0eXBlID0gIk1vZGVsIiwNCiAgICB0aXRsZSA9ICJUaHJlZSBtZWFuIGZ1bmN0aW9ucyBmb3IgdGhlIHNhbWUgdGVtcGVyYXR1cmUgZGF0YSIsDQogICAgY2FwdGlvbiA9ICJEYXNoZWQgZ3VpZGVzIG1hcmsgY3ViaWMgc3BsaW5lIGtub3RzLiBUaGUgbmF0dXJhbCBzcGxpbmUgdXNlcyBkaWZmZXJlbnQgaW50ZXJuYWwga25vdHMgYXQgZGYgPSA1LiINCiAgKQ0KYGBgDQoNCiMjIE5hdHVyYWwgU3BsaW5lcyBhdCB0aGUgQm91bmRhcmllcw0KDQpBIGN1YmljIHJlZ3Jlc3Npb24gc3BsaW5lIGNhbiBrZWVwIGN1cnZpbmcgYmV5b25kIHRoZSB0ZW1wZXJhdHVyZXMgd2Ugb2JzZXJ2ZWQuIEEgKipuYXR1cmFsIGN1YmljIHNwbGluZSoqIGlzIGN1YmljIHRocm91Z2ggdGhlIGRhdGEgYnV0IGlzIGRlZmluZWQgdG8gaGF2ZSBsaW5lYXIgdGFpbHMgYmV5b25kIGl0cyBib3VuZGFyeSBrbm90cywgJGEkIGFuZCAkYiQuIEl0cyBjdXJ2YXR1cmUgaXMgemVybyB3aGVyZSB0aG9zZSB0YWlscyBiZWdpbjoNCg0KJCQNCmYnJyhhKT0wIFxxcXVhZFx0ZXh0e2FuZH1ccXF1YWQgZicnKGIpPTAuDQokJA0KDQpUaGUgbWlkZGxlIG9mIHRoZSBmaXR0ZWQgY3VydmUgY2FuIHN0aWxsIGJlbmQuIFRoZSBib3VuZGFyeSBydWxlIGxpbWl0cyB3aGF0IGhhcHBlbnMgYXQgdGhlIGVkZ2VzLCB3aGVyZSB0aGUgZGF0YSBnaXZlIHVzIHRoZSBsZWFzdCBndWlkYW5jZS4NCg0KYGBge3Igc3BsaW5lLWJvdW5kYXJ5LCBlY2hvPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBmaWcuaGVpZ2h0PTQuOH0NCnRlbXBlcmF0dXJlX2xpbWl0cyA8LSByYW5nZShzZW91bF90ZW1wJHRlbXBlcmF0dXJlKQ0KZXh0ZW5kZWRfZ3JpZCA8LSB0aWJibGUodGVtcGVyYXR1cmUgPSBzZXEoDQogIHRlbXBlcmF0dXJlX2xpbWl0c1sxXSAtIDQsIHRlbXBlcmF0dXJlX2xpbWl0c1syXSArIDQsDQogIGxlbmd0aC5vdXQgPSAzMDANCikpDQp0YWlsX3ByZWRpY3Rpb25zIDwtIGV4dGVuZGVkX2dyaWQgfD4NCiAgbXV0YXRlKA0KICAgIGN1YmljX3NwbGluZSA9IHN1cHByZXNzV2FybmluZ3MocHJlZGljdChsbV9jdWJpY19zcGxpbmUsIG5ld2RhdGEgPSBleHRlbmRlZF9ncmlkKSksDQogICAgbmF0dXJhbF9zcGxpbmUgPSBwcmVkaWN0KGxtX25hdHVyYWxfc3BsaW5lLCBuZXdkYXRhID0gZXh0ZW5kZWRfZ3JpZCkNCiAgKSB8Pg0KICBwaXZvdF9sb25nZXIoLXRlbXBlcmF0dXJlLCBuYW1lc190byA9ICJtb2RlbCIsDQogICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAiZml0dGVkX2Jpa2VzIikgfD4NCiAgbXV0YXRlKG1vZGVsID0gcmVjb2RlX3ZhbHVlcygNCiAgICBtb2RlbCwNCiAgICAiY3ViaWNfc3BsaW5lIiB+ICJDdWJpYyBzcGxpbmUiLA0KICAgICJuYXR1cmFsX3NwbGluZSIgfiAiTmF0dXJhbCBjdWJpYyBzcGxpbmUiLA0KICAgIHVubWF0Y2hlZCA9ICJlcnJvciINCiAgKSkNCm91dHNpZGVfYmFuZHMgPC0gdGliYmxlKA0KICB4bWluID0gYyh0ZW1wZXJhdHVyZV9saW1pdHNbMV0gLSA0LCB0ZW1wZXJhdHVyZV9saW1pdHNbMl0pLA0KICB4bWF4ID0gYyh0ZW1wZXJhdHVyZV9saW1pdHNbMV0sIHRlbXBlcmF0dXJlX2xpbWl0c1syXSArIDQpDQopDQoNCmdncGxvdCh0YWlsX3ByZWRpY3Rpb25zLA0KICAgICAgIGFlcyh0ZW1wZXJhdHVyZSwgZml0dGVkX2Jpa2VzLCBjb2xvdXIgPSBtb2RlbCkpICsNCiAgZ2VvbV9yZWN0KA0KICAgIGRhdGEgPSBvdXRzaWRlX2JhbmRzLA0KICAgIGFlcyh4bWluID0geG1pbiwgeG1heCA9IHhtYXgsIHltaW4gPSAtSW5mLCB5bWF4ID0gSW5mKSwNCiAgICBpbmhlcml0LmFlcyA9IEZBTFNFLCBmaWxsID0gImdyZXk4NSIsIGFscGhhID0gMC41NQ0KICApICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gdGVtcGVyYXR1cmVfbGltaXRzLA0KICAgICAgICAgICAgIGNvbG91ciA9ICJncmV5NDUiLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArDQogIGdlb21fbGluZShsaW5ld2lkdGggPSAxKSArDQogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygNCiAgICAiQ3ViaWMgc3BsaW5lIiA9ICJibHVlIiwgIk5hdHVyYWwgY3ViaWMgc3BsaW5lIiA9ICJmb3Jlc3RncmVlbiINCiAgKSkgKw0KICBsYWJzKA0KICAgIHggPSAiVGVtcGVyYXR1cmUgKMKwQykiLCB5ID0gIkZpdHRlZCBob3VybHkgYmlrZSBjb3VudCIsDQogICAgY29sb3VyID0gIk1vZGVsIiwNCiAgICB0aXRsZSA9ICJUaGUgbmF0dXJhbCBzcGxpbmUgaGFzIHN0cmFpZ2h0IHRhaWxzIiwNCiAgICBzdWJ0aXRsZSA9ICJTaGFkZWQgdGVtcGVyYXR1cmVzIGxpZSBvdXRzaWRlIHRoZSBvYnNlcnZlZCByYW5nZSIsDQogICAgY2FwdGlvbiA9ICJUaGVzZSBleHRlbnNpb25zIHNob3cgdGhlIG1vZGVsIGNvbnN0cmFpbnQ7IHRoZXkgYXJlIG5vdCByZWxpYWJsZSBmb3JlY2FzdHMuIg0KICApDQpgYGANCg0KVGhlIG9yZGluYXJ5IGN1YmljIHNwbGluZSBjYW4gY29udGludWUgY3VydmluZzsgdGhlIG5hdHVyYWwgY3ViaWMgc3BsaW5lIGlzIHN0cmFpZ2h0IGJleW9uZCBlYWNoIGJvdW5kYXJ5LiBMaW5lYXIgdGFpbHMgcHJldmVudCBvbmUga2luZCBvZiB1bnN0YWJsZSBleHRlbnNpb24sIGJ1dCB0aGV5IGRvIG5vdCBwcm92aWRlIGluZm9ybWF0aW9uIGFib3V0IGJpa2UgZGVtYW5kIGF0IHVub2JzZXJ2ZWQgdGVtcGVyYXR1cmVzLiBBIGZsZXhpYmxlIGN1cnZlIHdpbGwgYWxzbyB0ZW5kIHRvIGZpdCB0aGUgb2JzZXJ2ZWQgZGF0YSBtb3JlIGNsb3NlbHksIHdoaWNoIGFsb25lIGRvZXMgbm90IG1ha2UgaXQgdGhlIGJldHRlciBtb2RlbC4NCg0KIyMgV2hlcmUgRG9lcyB0aGUgRmxleGliaWxpdHkgQ29tZSBGcm9tPw0KDQp8IE1ldGhvZCB8IEJ1aWxkaW5nIGJsb2NrcyBvciBmaXR0aW5nIHJ1bGUgfCBXaGVyZSBzaGFwZSBjYW4gY2hhbmdlIHwNCnwtLS18LS0tfC0tLXwNCnwgU3RyYWlnaHQgbGluZSB8ICQxLHgkIHwgT25lIHNsb3BlIGV2ZXJ5d2hlcmUgfA0KfCBDdWJpYyBwb2x5bm9taWFsIHwgJDEseCx4XjIseF4zJCB8IE9uZSBnbG9iYWwgY3ViaWMgY3VydmUgfA0KfCBQaWVjZXdpc2UgbGluZWFyIHwgTGluZSBwbHVzIGhpbmdlIHRlcm1zIHwgU2xvcGUgY2hhbmdlcyBhdCBrbm90cyB8DQp8IEN1YmljIHNwbGluZSB8IFNtb290aGx5IGpvaW5lZCBjdWJpYyBwaWVjZXMgfCBDdXJ2YXR1cmUgY2FuIGNoYW5nZSBhcm91bmQga25vdHMgfA0KfCBOYXR1cmFsIGN1YmljIHNwbGluZSB8IFNtb290aGx5IGpvaW5lZCBjdWJpYyBwaWVjZXMgd2l0aCBsaW5lYXIgdGFpbHMgfCBDdXJ2YXR1cmUgY2FuIGNoYW5nZSBhcm91bmQga25vdHM7IHN0cmFpZ2h0IGJleW9uZCBib3VuZGFyaWVzIHwNCnwgTE9FU1MgfCBSZXBlYXRlZCBkaXN0YW5jZS13ZWlnaHRlZCByZWdyZXNzaW9ucyB8IExvY2FsIG5laWdoYm91cmhvb2RzIHwNCg0KIyMgQ29tcGFyaW5nIE1vZGVscw0KDQpFdmVyeSBtb2RlbCBiZWxvdyB1c2VzIHRoZSBzYW1lIGhvdXJseSBTZW91bCBvYnNlcnZhdGlvbnMsIGFuZCBldmVyeSBwYW5lbCB1c2VzIHRoZSBzYW1lIGF4ZXMuIFRoZSBwaWVjZXdpc2UgZml0IHVzZXMgdGhlIHNhbWUgdHdvIGtub3QgbG9jYXRpb25zIGFzIHRoZSBgZGYgPSA1YCBjdWJpYyBzcGxpbmU7IHRoZSBMT0VTUyBmaXQgdXNlcyBgc3BhbiA9IDAuNDVgLiBUaGUgcG9seW5vbWlhbCBpcyBjdWJpYywgYW5kIGJvdGggc3BsaW5lIGZpdHMgdXNlIGBkZiA9IDVgLg0KDQpgYGB7ciBzZW91bC1zaXgtY3VydmVzLCBlY2hvPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9OH0NCnBpZWNld2lzZV9kYXRhIDwtIHNlb3VsX3RlbXAgfD4NCiAgbXV0YXRlKA0KICAgIGhpbmdlXzEgPSBwbWF4KHRlbXBlcmF0dXJlIC0gc3BsaW5lX2tub3RzWzFdLCAwKSwNCiAgICBoaW5nZV8yID0gcG1heCh0ZW1wZXJhdHVyZSAtIHNwbGluZV9rbm90c1syXSwgMCkNCiAgKQ0KcGllY2V3aXNlX2dyaWQgPC0gdGVtcF9ncmlkIHw+DQogIG11dGF0ZSgNCiAgICBoaW5nZV8xID0gcG1heCh0ZW1wZXJhdHVyZSAtIHNwbGluZV9rbm90c1sxXSwgMCksDQogICAgaGluZ2VfMiA9IHBtYXgodGVtcGVyYXR1cmUgLSBzcGxpbmVfa25vdHNbMl0sIDApDQogICkNCmxtX2N1YmljIDwtIGxtKA0KICByZW50ZWRfYmlrZV9jb3VudCB+IHBvbHkodGVtcGVyYXR1cmUsIDMsIHJhdyA9IFRSVUUpLA0KICBkYXRhID0gc2VvdWxfdGVtcA0KKQ0KbG1fcGllY2V3aXNlIDwtIGxtKA0KICByZW50ZWRfYmlrZV9jb3VudCB+IHRlbXBlcmF0dXJlICsgaGluZ2VfMSArIGhpbmdlXzIsDQogIGRhdGEgPSBwaWVjZXdpc2VfZGF0YQ0KKQ0KbG9lc3NfY29tcGFyZSA8LSBsb2VzcygNCiAgcmVudGVkX2Jpa2VfY291bnQgfiB0ZW1wZXJhdHVyZSwgZGF0YSA9IHNlb3VsX3RlbXAsDQogIHNwYW4gPSAwLjQ1LCBkZWdyZWUgPSAyLA0KICBjb250cm9sID0gbG9lc3MuY29udHJvbChzdXJmYWNlID0gImRpcmVjdCIpDQopDQoNCmNvbXBhcmlzb25fY3VydmVzIDwtIHRlbXBfZ3JpZCB8Pg0KICBtdXRhdGUoDQogICAgbGluZWFyID0gcHJlZGljdChsbV9saW5lYXIsIG5ld2RhdGEgPSB0ZW1wX2dyaWQpLA0KICAgIGN1YmljX3BvbHlub21pYWwgPSBwcmVkaWN0KGxtX2N1YmljLCBuZXdkYXRhID0gdGVtcF9ncmlkKSwNCiAgICBwaWVjZXdpc2VfbGluZWFyID0gcHJlZGljdChsbV9waWVjZXdpc2UsIG5ld2RhdGEgPSBwaWVjZXdpc2VfZ3JpZCksDQogICAgY3ViaWNfc3BsaW5lID0gcHJlZGljdChsbV9jdWJpY19zcGxpbmUsIG5ld2RhdGEgPSB0ZW1wX2dyaWQpLA0KICAgIG5hdHVyYWxfc3BsaW5lID0gcHJlZGljdChsbV9uYXR1cmFsX3NwbGluZSwgbmV3ZGF0YSA9IHRlbXBfZ3JpZCksDQogICAgbG9lc3MgPSBwcmVkaWN0KGxvZXNzX2NvbXBhcmUsIG5ld2RhdGEgPSB0ZW1wX2dyaWQpDQogICkgfD4NCiAgcGl2b3RfbG9uZ2VyKC10ZW1wZXJhdHVyZSwgbmFtZXNfdG8gPSAibW9kZWwiLA0KICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gImZpdHRlZF9iaWtlcyIpIHw+DQogIG11dGF0ZShtb2RlbCA9IHJlY29kZV92YWx1ZXMoDQogICAgbW9kZWwsDQogICAgImxpbmVhciIgfiAiU3RyYWlnaHQgbGluZSIsDQogICAgImN1YmljX3BvbHlub21pYWwiIH4gIkN1YmljIHBvbHlub21pYWwiLA0KICAgICJwaWVjZXdpc2VfbGluZWFyIiB+ICJQaWVjZXdpc2UgbGluZWFyIiwNCiAgICAiY3ViaWNfc3BsaW5lIiB+ICJDdWJpYyBzcGxpbmUiLA0KICAgICJuYXR1cmFsX3NwbGluZSIgfiAiTmF0dXJhbCBjdWJpYyBzcGxpbmUiLA0KICAgICJsb2VzcyIgfiAiTE9FU1MiLA0KICAgIHVubWF0Y2hlZCA9ICJlcnJvciINCiAgKSkgfD4NCiAgbXV0YXRlKG1vZGVsID0gZmFjdG9yKG1vZGVsLCBsZXZlbHMgPSBjKA0KICAgICJTdHJhaWdodCBsaW5lIiwgIkN1YmljIHBvbHlub21pYWwiLCAiUGllY2V3aXNlIGxpbmVhciIsDQogICAgIkN1YmljIHNwbGluZSIsICJOYXR1cmFsIGN1YmljIHNwbGluZSIsICJMT0VTUyINCiAgKSkpDQoNCmdncGxvdCgpICsNCiAgZ2VvbV9wb2ludCgNCiAgICBkYXRhID0gc2VvdWxfdGVtcCwNCiAgICBhZXModGVtcGVyYXR1cmUsIHJlbnRlZF9iaWtlX2NvdW50KSwNCiAgICBhbHBoYSA9IDAuMDM1LCBzaXplID0gMC4zNQ0KICApICsNCiAgZ2VvbV9saW5lKA0KICAgIGRhdGEgPSBjb21wYXJpc29uX2N1cnZlcywNCiAgICBhZXModGVtcGVyYXR1cmUsIGZpdHRlZF9iaWtlcyksDQogICAgY29sb3VyID0gImJsdWUzIiwgbGluZXdpZHRoID0gMC45DQogICkgKw0KICBmYWNldF93cmFwKH5tb2RlbCwgbmNvbCA9IDMsIHNjYWxlcyA9ICJmaXhlZCIpICsNCiAgbGFicyh4ID0gIlRlbXBlcmF0dXJlICjCsEMpIiwgeSA9ICJIb3VybHkgcmVudGVkIGJpa2UgY291bnQiLA0KICAgICAgIHRpdGxlID0gIlRoZSBzYW1lIG9ic2VydmF0aW9ucywgc2l4IHJ1bGVzIGZvciB0aGUgZml0dGVkIG1lYW4iKQ0KYGBgDQoNCiMjIEEgU2Vjb25kIE5vbmxpbmVhciBTaWduYWwNCg0KVGVtcGVyYXR1cmUgaXMgbm90IHRoZSBvbmx5IGNhbmRpZGF0ZSBmb3Igbm9ubGluZWFyIG1vZGVsbGluZy4gU29sYXIgcmFkaWF0aW9uIG1heSBhbHNvIGhhdmUgYSBjdXJ2ZWQgcmVsYXRpb25zaGlwIHdpdGggZGVtYW5kLg0KDQpgYGB7ciBzZW91bC1zb2xhci1sb2Vzcywgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCnNlb3VsX2hvdXJseSB8Pg0KICBnZ3Bsb3QoYWVzKHggPSBzb2xhcl9yYWRpYXRpb24sIHkgPSByZW50ZWRfYmlrZV9jb3VudCkpICsNCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMDUpICsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxvZXNzIiwgZm9ybXVsYSA9IHkgfiB4LCBzZSA9IEZBTFNFLCBsaW5ld2lkdGggPSAxKSArDQogIGxhYnMoDQogICAgeCA9ICJTb2xhciByYWRpYXRpb24iLA0KICAgIHkgPSAiSG91cmx5IHJlbnRlZCBiaWtlIGNvdW50IiwNCiAgICB0aXRsZSA9ICJPdGhlciB3ZWF0aGVyIHByZWRpY3RvcnMgbWF5IGFsc28gbmVlZCBmbGV4aWJsZSBtZWFuIGZ1bmN0aW9ucyINCiAgKQ0KYGBgDQoNCiMjIFdoYXQgSGF2ZSBXZSBDaGFuZ2VkPyBXaGF0IGhhcyBzdGF5ZWQgdGhlIHNhbWU/DQoNCldlIGhhdmUgY2hhbmdlZCB0aGUgc2hhcGUgYWxsb3dlZCBmb3IgdGhlIG1lYW4gcmVzcG9uc2UuIEEgcG9seW5vbWlhbCBnaXZlcyB1cyBvbmUgZ2xvYmFsIGN1cnZlLiBQaWVjZXdpc2UgcmVncmVzc2lvbiBsZXRzIHRoZSBzbG9wZSBjaGFuZ2UgYXQga25vdHMuIEN1YmljIHNwbGluZXMga2VlcCB0aGUgcGllY2V3aXNlIGNvbnN0cnVjdGlvbiBidXQgam9pbiB0aGUgcGllY2VzIHNtb290aGx5LCBhbmQgbmF0dXJhbCBzcGxpbmVzIHJlc3RyaWN0IHRoZSB0YWlscyB0byBzdHJhaWdodCBsaW5lcy4gTE9FU1MgdGFrZXMgYSBkaWZmZXJlbnQgcm91dGU6IGl0IHJlcGVhdGVkbHkgZml0cyBhIGRpc3RhbmNlLXdlaWdodGVkIGxvY2FsIHJlZ3Jlc3Npb24uDQoNCk5vbmUgb2YgdGhlc2UgY2hvaWNlcyByZW1vdmVzIHRoZSBxdWVzdGlvbiBvZiBob3cgbXVjaCBmbGV4aWJpbGl0eSB0aGUgZGF0YSBzdXBwb3J0LiBGb3IgTE9FU1MsIHRoYXQgY2hvaWNlIGlzIG1haW5seSB0aGUgc3Bhbi4gRm9yIGEgY3ViaWMgc3BsaW5lLCBpdCBpcyB0aGUgbnVtYmVyIGFuZCBwbGFjZW1lbnQgb2Yga25vdHMsIHdoaWNoIHdlIGNvbnRyb2wgaW4gUiB0aHJvdWdoIHRoZSBkZWdyZWVzIG9mIGZyZWVkb20uIEEgY2xvc2UgZml0IHRvIHRoZXNlIG9ic2VydmF0aW9ucyBpcyBub3QsIGJ5IGl0c2VsZiwgZXZpZGVuY2UgdGhhdCB0aGUgY3VydmUgd2lsbCBwcmVkaWN0IG5ldyBvYnNlcnZhdGlvbnMgd2VsbC4NCg0KTE9FU1MgaXMgdXNlZnVsIHdoZW4gd2Ugd2FudCB0byBpbnNwZWN0IHRoZSBzaGFwZSBvZiBhIHJlbGF0aW9uc2hpcCB3aXRob3V0IGNvbW1pdHRpbmcgdG8gb25lIGdsb2JhbCBlcXVhdGlvbi4gQ3ViaWMgc3BsaW5lcyBsZXQgdXMgcHV0IHRoYXQgZmxleGliaWxpdHkgZGlyZWN0bHkgaW50byBhIHJlZ3Jlc3Npb24gbW9kZWwgYWxvbmdzaWRlIG90aGVyIHByZWRpY3RvcnMuIEluIHRoZSBuZXh0IGxlY3R1cmUsIHRpbWUgaXRzZWxmIGVudGVycyB0aGUgbWVhbiBtb2RlbDogZmlyc3QgdGhyb3VnaCBhIHNlYXNvbmFsIGluZGljYXRvciBpbiBza2kgc2FsZXMsIHRoZW4gdGhyb3VnaCB0cmVuZCBhbmQgc2Vhc29uYWwgdGVybXMgZm9yIGRhaWx5IFNlb3VsIGJpa2UgZGVtYW5kLiBMYXRlciB3ZSB3aWxsIGFzayB3aGV0aGVyIG9ic2VydmF0aW9ucyBjbG9zZSB0b2dldGhlciBpbiB0aW1lIGNhbiBzdGlsbCBiZSB0cmVhdGVkIGFzIGluZGVwZW5kZW50Lg0K