Load libraries
library(fpp3)
── Attaching packages ────────────────────────────────────────────────────────────────────────────────────────────────────────────────── fpp3 0.5 ──
✔ tibble 3.2.1 ✔ tsibble 1.1.3
✔ dplyr 1.1.3 ✔ tsibbledata 0.4.1
✔ tidyr 1.3.0 ✔ feasts 0.3.1
✔ lubridate 1.9.2 ✔ fable 0.3.3
✔ ggplot2 3.4.3 ✔ fabletools 0.3.3
── Conflicts ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────── fpp3_conflicts ──
✖ lubridate::date() masks base::date()
✖ dplyr::filter() masks stats::filter()
✖ tsibble::intersect() masks base::intersect()
✖ tsibble::interval() masks lubridate::interval()
✖ dplyr::lag() masks stats::lag()
✖ tsibble::setdiff() masks base::setdiff()
✖ tsibble::union() masks base::union()
library(GGally)
Registered S3 method overwritten by 'GGally':
method from
+.gg ggplot2
library(seasonal)
Attaching package: ‘seasonal’
The following object is masked from ‘package:tibble’:
view
Inflation adjustments
Australian newspapers adjusted for inlfation
## Retail CPI
aus_dataset <- aus_retail |>
filter(Industry == "Newspaper and book retailing") |>
group_by(Industry) |>
index_by(Year = year(Month)) |>
summarise(Turnover = sum(Turnover))
aus_dataset |> autoplot()
Plot variable not specified, automatically selected `.vars = Turnover`

- We see the data going up untill around 2010 and then start dipping
down.
- Is this because a change in industry or just a change in the
CPI?
- Or is it because the CPI?
## CPI
aus_economy <- global_economy |>
filter(Code == "AUS")
aus_economy
Joining the datasets
aus_dataset |>
left_join(aus_economy, by="Year") |>
mutate(Adjusted_Turnover = Turnover / CPI *100) |>
pivot_longer(c(Turnover, Adjusted_Turnover), values_to = "Turnover") |>
mutate(name=factor(name, levels = c("Turnover","Adjusted_turnover"))) |>
ggplot(aes(x=Year,y=Turnover)) + geom_line() +
facet_grid(name ~ ., scales = "free_y") +
labs(title="Turnover: Australian print media industry", y="$AU")

- We can see that adjusted for CPI the Turnover has been declining
since 1980’s
- Decline since 2010 is been faster, but has been going on since
1980
When forecasting you want to forecast taking in to account CPI
The original plot:
food |> autoplot(Turnover)

Square root:
Works, but variations at the start of series are still bigger than
variations at the end
food |> autoplot(sqrt(Turnover)) + labs(title = "Square root Turnover")

Cube root
Works, but variations at the start of series are still bigger than
variations at the end
food |> autoplot(Turnover^(1/3)) + labs(title = "Cube root Turnover")

Log
food |> autoplot(log(Turnover)) + labs(title = "Log Turnover")

- Much better, variations are more HOMOGENEOUS
- Size of fluctuations at the start are about same size at end
This is going to make modeling much easier Makes timeseries
decompositions easier Good first step to remove that extra heterogeneity
Allows us to fit a much simpler model
Function to compute the optimal lambda
food |> features(Turnover, features = guerrero)
This attempts to balance the seasonal fluctuations and random
variation across the series Always check the results A low value of
lambda can give extremely large prediction intervals
Time series components
A time series decomposition involves estimating timeseries
components
- Trend: long term increase or decrease
- Seasonal pattern: influenced by the calendar
- Cycles: rises or falls that are not of fixed period
Decomposition: yt = f(St, Tt, Rt) where: * yt = data at period t * St
= seasonal component at period t * Tt = trend at period t * Rt =
remainder component at period t
Additive decomposition: yt = St + Tt + Rt Multiplicative
decomposition: yt = St * Tt * Rt
Additive model
Appropiate if magnitude of seasonal fluctuations does not vary
with level
If seasonal patterns are proportional to the level of the series
-> MULTIPLICATIVE MODEL
Multiplicative decomposition more prevalent with economic
series
ALTERNATIVE: Use a Box-Cox transformation, and then
use additive decomposition
Logs turn multiplicative relationships in to additive
relationships
yt = St * Tt * Rt --> ln(yt) = ln(St) + ln(Tt) + ln(Rt )
Example
us_employment |>
filter(Title == "Retail Trade", year(Month) >= 1990) |>
select(-Series_ID) -> us_retail_employment_1990
us_retail_employment_1990 |> autoplot(Employed) + geom_point() +
labs(y="Persons (thousands)", title = "Total employment in US retail")

- We have Trend + Cycle + Seasonality, lets fit a model
us_retail_employment_1990 |>
model(stl = STL(Employed))
Looking at the model components
dcmp <- us_retail_employment_1990 |>
model(stl = STL(Employed))
components(dcmp)
Autoplot the components
components(dcmp) |> autoplot()

Other things we can do with the components
us_retail_employment_1990 |>
autoplot(Employed, color="black") +
autolayer(components(dcmp), trend, color="#D55E00") +
labs(y= "Persons (thousands)", title = "Total employment in US retail")

Subseries plot
Useful if interested in SHAPE of seasonality
components(dcmp) |> gg_subseries(season_year)

Sesonal Adjustment
- Useful by-product of decomposition: an easy way to calculate
seasonally adjusted data
- Additive decomposition: seasonally adjusted data given by yt - St =
Tt + Rt
- Multiplicative: yt/St = Tt * Rt
Plotting the seasonally adjusted data: yt - St = Tt + Rt
us_retail_employment_1990 |>
autoplot(Employed, color="black") +
autolayer(components(dcmp), season_adjust, color="blue") +
labs(y="Persons (thousands)", title = "Total employment in US retail")

Observations:
- We can see the season_adjust (blue) line is more wobbly than the
trend line in the above chart
- This is due to the effect of Rt the remainder, which is almost
always noisy in nature
How to seasonal adjust:
- We use estimates of S based on past values to seasonally adjust a
current value
- Seasonally adjusted series reflect remainders as
well as trend
- Therefore they are
not smooth, and
downturns or upturns can be
misleading
It is better to use the trend-cycle component to look for turning points
Moving Averages (Classical Decomposition)
- Traditional way to perform time series decompositions,
- Originated in the 1920’s but still the basis for many
decompositions.
A moving average is an average of nearby points
- observations nearby in time are also likely to be
close in value
- average eliminates some
randomness in the data, leaving
a smooth trend-cycle component
- 3-MA: Tt = (y(t-1) + yt + y(t+1))/3
- 5-MA: Tt = (y(t-2) + y(t-1) + yt + y(t+1) + y(t+2))/5
- each average computed by dropping
oldest observation
and including next observation
- averaging
moves trough time series until trend-cycle
computed at each observation possible
First step: Get and estimate of the trend component
- We use Moving Averages for this:
global_economy |>
filter(Country == "Australia") |>
autoplot(Exports) +
labs(y="% of GDP", title = "Total Australian exports")

Why is there no estimates at the ends?
- for a 3-MA, there cannot be estimates at time 1 or time T because
the observations at time 0 and T+1 are not available
- Generally: there cannot be estimates at times near the
endpoints
The order of the MA
- larger order means smoother, flatter curve
- larger order means more points lost at ends
if order = lenght of season or cycle IT
removes pattern
- But so far odd orders?
- with even orders, we need to take 2 moving averages, to center the
data
If order==4: 1/4[yt-2 + yt-1 + yt + yt+1] or 1/4[yt-1 + yt + yt+1 +
yt+2] There are 2 options to compute the same 4-MA so we need to
recenter at half of both 4_MA : 1/2(1/4[yt-2 + yt-1 + yt + yt+1] +
1/4[yt-1 + yt + yt+1 + yt+2]) = 1/8yt-2 + 1/4yt-1 + 1/4yt + 1/4yt=1 +
1/8yt+2
A MA of the same lenght as the season removes the seasonal pattern
- For quarterly data: use 2x4 MA
- For monthly data: use a 2x12 MA
Moving average trend-cycle
us_retail_employment_1990 |>
mutate(`12-MA` = slider::slide_dbl(Employed, mean,
.before = 5, .after = 6, .complete = TRUE),
`2x12-MA` = slider::slide_dbl(`12-MA`, mean,
.before = 1, .after = 0, .complete = TRUE)) -> us_retail_employment_1990_ma
us_retail_employment_1990_ma
Plotting it
us_retail_employment_1990_ma |>
autoplot(Employed, color="black") +
autolayer(us_retail_employment_1990_ma, vars("2x12-MA"),
color="blue") +
labs(y="Persons (thousands)", title = "Total employment in US retail")

Classical Decomposition (estimating time series components)
Additive decomposition: components add
Multiplicative Decomposition: components multiply
EStimate Tt using MA (2xm)-MA if m is even. Otherwise, estimate
Tt using m-MA
Compute de-trended series
- Additive decomposition: yt - Tt
- Multiplicative decomposition: yt/Tt
- De-trending
Remove smoothed series Tt from yt to leave St and Rt
- Additive model yt - Tt + (Tt + St + Rt) - St = St + Rt
- Multiplicative model: yt/Tt = TtxStxRt/Tt = StxRt
This will leave behind Seasonal and Remainder
- Estimate Seasonal component
- Seasonal index for each season is estimated as an average of the
detrended series for that season of successive years
- E.g. take averages across all Januaries to get S1 if your data is
monthly
If necessary CONSTRAIN adjust the seasonal indices so
that:
- Additive: S1 + S2 + … + SN = 0
- Multiplicative: S1 + S2 + … + SN = m
The seasonal component St simply consists of replications of the
seasonal indices
- Additive decomposition: Rt = yt - Tt - St
- Multiplicative decomposition: Rt = yt/(Tt*St)
Classical decomposition
- Choose additive or multiplicative depending on which gives the most
stable components
- For multiplicative model, this method a.k.a.
ratio-to-moving-average method
Additive
dcmp <- us_retail_employment_1990 |>
model(stl = STL(Employed))
components(dcmp) |> autoplot() +
labs(title = "Classical additive decomposition of US retail employment")

Multiplicative
dcmp <- us_retail_employment_1990 |>
model(classical_decomposition(Employed, type = "multiplicative"))
components(dcmp) |> autoplot() +
labs(title = "Classical multiplicative decomposition of US retail employment")

Methods used in official statistics
Timeseries decomposition is officially used in official statistics
bureaus
- Classical method originated in 1920
Census II method introduced in 1957
- Basis for
X-11 method and variants (including X-12,
X-12-ARIMA, X-13-ARIMA)
STL method introduced in 1983 at BELL
LABS
TRAMO/SEATS introduced in 1990s in Europe
(bank of Spain)
National Statistics Offices
- ABS (Australia) uses X-12-ARIMA
- US Census Bureau uses X-13ARIMA-SEATS
- Statistics Canada uses X-12-ARIMA
- ONS (UK) uses X-12-ARIMA
- EuroStat uses X-13ARIMA-SEATS
How to do it using the FABLE packages
Install packages
# install.packages("seasonal")
Load packages
# library(seasonal)
X-13-ARIMA-SEATS Decomposition
x11_dcmp <- us_retail_employment_1990 |>
model(x11 = X_13ARIMA_SEATS(Employed ~ x11()))
components(x11_dcmp) # show the components
Plotting X-13-ARIMA MULTIPLICATIVE
components(x11_dcmp) |> autoplot()

Advantages
- Relatively robust to outliers
- Completly automated choices for trend and seasonal changes
- Very widely tested on economic data over a long period of time
Disadvantages
- No prediction/confidence intervals
- Ad hoc method with no underlying model
ONLY DEVELOPED FOR MONTHLY/QUARTER DATA
Extensions: X-12ARIMA- and X-13ARIMA
- The X11, X12ARIMA, X13ARIMA methods are based on Census II
decomposition
- These allow adjustments for trading days and other explanatory
variables
- Known outliers can be ommited
- Level shifts and ramp effects can be modelled
- Missing values estimated and replaced
- Holiday factors can be estimated
X-13ARIMA-SEATS
seats_dcmp <- us_retail_employment_1990 |>
model(seats = X_13ARIMA_SEATS(Employed ~ seats()))
components(seats_dcmp) |> autoplot()

Advantages of X-13ARIMA-SEATS
- Model based
CAN GET CONFIDENCE INTERVALS
- Smooth trend estimate
- Allows estimates at end points
- Allows changing seasonality
- Developed for economic data
Disadvantages of X-13ARIMA-SEATS
ONLY DEVELOPED FOR Q AND M DATA
STL Seasonal and Trend decomposition using Loess
- Loess is a form of smoothing based on locally linear
regressions
- Very versatile and robust
- Will handle any type of seasonality
- Seasonal component allowed to change over time
- Rate of change controlled by user
- Smoothness of trend-cycle also controlled by user
- Robust to outliers
Disadvantages:
- No trading day adjustment
- No calendar adjustments
- Only additive
For multiplicative: Take logs to get multiplicative decomposition Use
Box-Cox transformations to get other decompositions
Example
us_retail_employment_1990 |>
model(STL(Employed)) |>
components() |>
autoplot()

We can control the change in seasonal pattern and trend with
windows
us_retail_employment_1990 |>
model(STL(Employed ~ season(window=15) + trend(window=6665))) |>
components() |>
autoplot()

Observations
- Lot of structure in the remainder
- Because trend window = 6665
- Trend becomes a straight line
- What should have gone in trend goes to remainder
Default params work pretty good
Trend with small window
us_retail_employment_1990 |>
model(STL(Employed ~ season(window=15) + trend(window=15))) |>
components() |>
autoplot()

Robust argument (default is false)
us_retail_employment_1990 |>
model(STL(Employed ~ season(window=15) + trend(window=15), robust = TRUE)) |>
components() |>
autoplot()

Summary
- trend(window = ?) controls wiggliness of trend component
- Because of Loes
- weighted least squared fits
- smaller windows, fewer obs for each local linear regression
- season(window = ?) controls variations on seasonal component
- Same component in different years
- How many years to use when estimating each of seasonal
component
- season(window = ‘periodic’) is equivalent to infinite window
By default
- chooses season(window=13)
- Can include transformations
STL DECOMPOSITION
- Default trend: window =
nextodd(ceiling((1.5*period)/(1-(1.5/s.window))))
- Default season: window = 13
How does it work?
- Updated the trend and seasonal component iteratively
- Starts off by saying, lets suppose there is no trend, estimate
seasonality by classical decomp
- Removes that, tries to estimate trend using LOES curve
- Iterates
Explanation:
- Starts with Tt = 0
- Uses a mixture of
loess and MA to
sucessively refine the trend and seasonal
estimates
- The trend window controls
loess bandwidth applied to
deasonalised values
- The season window controls
loess bandwidth applied to
detrended subseries
- Robustbess weights based on remainder
THE END
LS0tCnRpdGxlOiAiVGltZSBTZXJpZXMgRGVjb21wb3NpdGlvbiIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyMgTG9hZCBsaWJyYXJpZXMKCmBgYHtyfQpsaWJyYXJ5KGZwcDMpCmBgYAoKCmBgYHtyfQpsaWJyYXJ5KEdHYWxseSkKYGBgCgoKYGBge3J9CmxpYnJhcnkoc2Vhc29uYWwpCmBgYAoKIyMjIFRyYW5zZm9ybWF0aW9ucyBhbmQgYWRqdXN0bWVudHMKCiogUGVyIGNhcGl0YSBhZGp1c3RtZW50czogRGl2aWRpbmcgZGF0YSBieSBwb3B1bGF0aW9uCgoKYGBge3J9Cmdsb2JhbF9lY29ub215IHw+CiAgZmlsdGVyKENvdW50cnkgPT0gIkF1c3RyYWxpYSIpIHw+CiAgYXV0b3Bsb3QoR0RQIC8gUG9wdWxhdGlvbikKYGBgCgojIyMgSW5mbGF0aW9uIGFkanVzdG1lbnRzCgpBdXN0cmFsaWFuIG5ld3NwYXBlcnMgYWRqdXN0ZWQgZm9yIGlubGZhdGlvbgoKYGBge3J9CiMjIFJldGFpbCBDUEkKYXVzX2RhdGFzZXQgPC0gYXVzX3JldGFpbCB8PgogIGZpbHRlcihJbmR1c3RyeSA9PSAiTmV3c3BhcGVyIGFuZCBib29rIHJldGFpbGluZyIpIHw+CiAgZ3JvdXBfYnkoSW5kdXN0cnkpIHw+CiAgaW5kZXhfYnkoWWVhciA9IHllYXIoTW9udGgpKSB8PgogIHN1bW1hcmlzZShUdXJub3ZlciA9IHN1bShUdXJub3ZlcikpCgphdXNfZGF0YXNldCB8PiBhdXRvcGxvdCgpCmBgYAoqIFdlIHNlZSB0aGUgZGF0YSBnb2luZyB1cCB1bnRpbGwgYXJvdW5kIDIwMTAgYW5kIHRoZW4gc3RhcnQgZGlwcGluZyBkb3duLgoqIElzIHRoaXMgYmVjYXVzZSBhIGNoYW5nZSBpbiBpbmR1c3RyeSBvciBqdXN0IGEgY2hhbmdlIGluIHRoZSBDUEk/CiogT3IgaXMgaXQgYmVjYXVzZSB0aGUgQ1BJPwoKYGBge3J9CiMjIENQSQphdXNfZWNvbm9teSA8LSBnbG9iYWxfZWNvbm9teSB8PgogIGZpbHRlcihDb2RlID09ICJBVVMiKQoKYXVzX2Vjb25vbXkKYGBgCgpKb2luaW5nIHRoZSBkYXRhc2V0cwoKYGBge3J9CmF1c19kYXRhc2V0IHw+CiAgbGVmdF9qb2luKGF1c19lY29ub215LCBieT0iWWVhciIpIHw+CiAgbXV0YXRlKEFkanVzdGVkX1R1cm5vdmVyID0gVHVybm92ZXIgLyBDUEkgKjEwMCkgfD4KICBwaXZvdF9sb25nZXIoYyhUdXJub3ZlciwgQWRqdXN0ZWRfVHVybm92ZXIpLCB2YWx1ZXNfdG8gPSAiVHVybm92ZXIiKSB8PgogIG11dGF0ZShuYW1lPWZhY3RvcihuYW1lLCBsZXZlbHMgPSBjKCJUdXJub3ZlciIsIkFkanVzdGVkX3R1cm5vdmVyIikpKSB8PgogIGdncGxvdChhZXMoeD1ZZWFyLHk9VHVybm92ZXIpKSArIGdlb21fbGluZSgpICsKICBmYWNldF9ncmlkKG5hbWUgfiAuLCBzY2FsZXMgPSAiZnJlZV95IikgKwogIGxhYnModGl0bGU9IlR1cm5vdmVyOiBBdXN0cmFsaWFuIHByaW50IG1lZGlhIGluZHVzdHJ5IiwgeT0iJEFVIikKYGBgCgoqIFdlIGNhbiBzZWUgdGhhdCBhZGp1c3RlZCBmb3IgQ1BJIHRoZSBUdXJub3ZlciBoYXMgYmVlbiBkZWNsaW5pbmcgc2luY2UgMTk4MCdzCiogRGVjbGluZSBzaW5jZSAyMDEwIGlzIGJlZW4gZmFzdGVyLCBidXQgaGFzIGJlZW4gZ29pbmcgb24gc2luY2UgMTk4MAoKYFdoZW4gZm9yZWNhc3RpbmcgeW91IHdhbnQgdG8gZm9yZWNhc3QgdGFraW5nIGluIHRvIGFjY291bnQgQ1BJYAoKIyMjIE1hdGhlbWF0aWNhbCBUcmFuc2Zvcm1hdGlvbgoKKiBUYWtlIGRhdGEgYW5kIHRyYW5zZm9ybSBieSBhcHBseWluZyBhIG1hdGhlbWF0aWNhbCB0cmFuc2Zvcm1hdGlvbgoqIFdlIHRyeSB0byBtYWtlIHRoZSB2YXJpYXRpb25zIGluIHRoZSBzZXJpZXMgbW9yZSBIT01PR0VORU9VUwoKYGBge3J9CmZvb2QgPC0gYXVzX3JldGFpbCB8PgogIGZpbHRlcihJbmR1c3RyeSA9PSAiRm9vZCByZXRhaWxpbmciKSB8PgogIHN1bW1hcmlzZShUdXJub3ZlciA9IHN1bShUdXJub3ZlcikpCmZvb2QKYGBgCgojIyMgVGhlIG9yaWdpbmFsIHBsb3Q6CgpgYGB7cn0KZm9vZCB8PiBhdXRvcGxvdChUdXJub3ZlcikKYGBgCgojIyMgU3F1YXJlIHJvb3Q6CgpXb3JrcywgYnV0IHZhcmlhdGlvbnMgYXQgdGhlIHN0YXJ0IG9mIHNlcmllcyBhcmUgc3RpbGwgYmlnZ2VyIHRoYW4gdmFyaWF0aW9ucyBhdCB0aGUgZW5kCgpgYGB7cn0KZm9vZCB8PiBhdXRvcGxvdChzcXJ0KFR1cm5vdmVyKSkgKyBsYWJzKHRpdGxlID0gIlNxdWFyZSByb290IFR1cm5vdmVyIikKYGBgCgojIyMgQ3ViZSByb290CgpXb3JrcywgYnV0IHZhcmlhdGlvbnMgYXQgdGhlIHN0YXJ0IG9mIHNlcmllcyBhcmUgc3RpbGwgYmlnZ2VyIHRoYW4gdmFyaWF0aW9ucyBhdCB0aGUgZW5kCgpgYGB7cn0KZm9vZCB8PiBhdXRvcGxvdChUdXJub3Zlcl4oMS8zKSkgKyBsYWJzKHRpdGxlID0gIkN1YmUgcm9vdCBUdXJub3ZlciIpCmBgYAoKIyMjIExvZwoKYGBge3J9CmZvb2QgfD4gYXV0b3Bsb3QobG9nKFR1cm5vdmVyKSkgKyBsYWJzKHRpdGxlID0gIkxvZyBUdXJub3ZlciIpCmBgYAoKKiBNdWNoIGJldHRlciwgdmFyaWF0aW9ucyBhcmUgbW9yZSBIT01PR0VORU9VUwoqIFNpemUgb2YgZmx1Y3R1YXRpb25zIGF0IHRoZSBzdGFydCBhcmUgYWJvdXQgc2FtZSBzaXplIGF0IGVuZAoKVGhpcyBpcyBnb2luZyB0byBtYWtlIG1vZGVsaW5nIG11Y2ggZWFzaWVyCk1ha2VzIHRpbWVzZXJpZXMgZGVjb21wb3NpdGlvbnMgZWFzaWVyCkdvb2QgZmlyc3Qgc3RlcCB0byByZW1vdmUgdGhhdCBleHRyYSBoZXRlcm9nZW5laXR5CkFsbG93cyB1cyB0byBmaXQgYSBtdWNoIHNpbXBsZXIgbW9kZWwKCiMjIyBJbnZlcnNlIHRyYW5zZm9ybWF0aW9uCgpgYGB7cn0KZm9vZCB8PiBhdXRvcGxvdCgtMS9UdXJub3ZlcikgKyBsYWJzKHRpdGxlID0gIi0xL1R1cm5vdmVyIikKYGBgCgoqIEdvbmUgdG9vIGZhciwgTG9nIHdhcyBhYm91dCByaWdodAoKIyMjIEJPWC1DT1ggVHJhbnNmb3JtYXRpb25zCgpCaWNrZWwtRG9rc3VtIHRyYW5zZm9ybWF0aW9ucwoKIyMjIEZ1bmN0aW9uIHRvIGNvbXB1dGUgdGhlIG9wdGltYWwgbGFtYmRhCgpgYGB7cn0KZm9vZCB8PiBmZWF0dXJlcyhUdXJub3ZlciwgZmVhdHVyZXMgPSBndWVycmVybykKYGBgClRoaXMgYXR0ZW1wdHMgdG8gYmFsYW5jZSB0aGUgc2Vhc29uYWwgZmx1Y3R1YXRpb25zIGFuZCByYW5kb20gdmFyaWF0aW9uIGFjcm9zcyB0aGUgc2VyaWVzCkFsd2F5cyBjaGVjayB0aGUgcmVzdWx0cwpBIGxvdyB2YWx1ZSBvZiBsYW1iZGEgY2FuIGdpdmUgZXh0cmVtZWx5IGxhcmdlIHByZWRpY3Rpb24gaW50ZXJ2YWxzCgoKIyMjIFVzaW5nIHRoZSBndWVycmVybyB0cmFuc2Zvcm1hdGlvbgoKYGBge3J9CmZvb2QgfD4gYXV0b3Bsb3QoYm94X2NveChUdXJub3ZlciwgMC4wODk1MjY5NikpICsKICBsYWJzKHRpdGxlID0gIkJveC1Db3ggVHJhbnNmb3JtZWQgdHVybm92ZXIiKQpgYGAKCiogT2Z0ZW4gbm8gdHJhbnNmb3JtYXRpb25zIG5lZWRlZAoqIFNpbXBsZSB0cmFuc2Zvcm1hdGlvbnMgYXJlIGVhc2llciB0byBleHBsYWluIGFuZCB3b3JrIHdlbGwgZW5vdWdoCiogQ2FuIGhhdmUgYSBWRVJZIExBUkdFIGVmZmVjdCBvbiBQcmVkaWN0aW9uIEludGVydmFsCiogSWYgc29tZSBkYXRhIGFyZSAwIG9yIG5lZ2F0aXZlLCB0aGVuIHVzZSBsYW1iZGEgPiAwCiogbG9nMXAoKSBjYW4gYWxzbyBiZSB1c2VmdWwgZm9yIGRhdGEgd2l0aCAwcwoqIENob29zaW5nIGxvZ3MgaXMgYSBzaW1wbGUgd2F5IHRvIGZvcmNlIGZvcmVjYXN0cyB0byBiZSBwb3NpdGl2ZQoqIFRyYW5zZm9ybWF0aW9ucyBtdXN0IGJlIHJldmVyc2VkIHRvIG9idGFpbiBmb3JlY2FzdHMgb24gdGhlIG9yaWdpbmFsIHNjYWxlLiAoSGFuZGxlZCBhdXRvbWF0aWNhbGx5IGJ5IGZhYmxlKQoKIyBUaW1lIHNlcmllcyBjb21wb25lbnRzCgpBIHRpbWUgc2VyaWVzIGRlY29tcG9zaXRpb24gaW52b2x2ZXMgZXN0aW1hdGluZyB0aW1lc2VyaWVzIGNvbXBvbmVudHMKCiogVHJlbmQ6IGxvbmcgdGVybSBpbmNyZWFzZSBvciBkZWNyZWFzZQoqIFNlYXNvbmFsIHBhdHRlcm46IGluZmx1ZW5jZWQgYnkgdGhlIGNhbGVuZGFyCiogQ3ljbGVzOiByaXNlcyBvciBmYWxscyB0aGF0IGFyZSBub3Qgb2YgZml4ZWQgcGVyaW9kCgpEZWNvbXBvc2l0aW9uOiB5dCA9IGYoU3QsIFR0LCBSdCkgd2hlcmU6CiogeXQgPSBkYXRhIGF0IHBlcmlvZCB0CiogU3QgPSBzZWFzb25hbCBjb21wb25lbnQgYXQgcGVyaW9kIHQKKiBUdCA9IHRyZW5kIGF0IHBlcmlvZCB0CiogUnQgPSByZW1haW5kZXIgY29tcG9uZW50IGF0IHBlcmlvZCB0CgpBZGRpdGl2ZSBkZWNvbXBvc2l0aW9uOiB5dCA9IFN0ICsgVHQgKyBSdApNdWx0aXBsaWNhdGl2ZSBkZWNvbXBvc2l0aW9uOiB5dCA9IFN0ICogVHQgKiBSdAoKIyMjIEFkZGl0aXZlIG1vZGVsCgoqIEFwcHJvcGlhdGUgaWYgbWFnbml0dWRlIG9mIHNlYXNvbmFsIGZsdWN0dWF0aW9ucyBkb2VzIG5vdCB2YXJ5IHdpdGggbGV2ZWwKKiBJZiBzZWFzb25hbCBwYXR0ZXJucyBhcmUgcHJvcG9ydGlvbmFsIHRvIHRoZSBsZXZlbCBvZiB0aGUgc2VyaWVzIC0+IE1VTFRJUExJQ0FUSVZFIE1PREVMCiogTXVsdGlwbGljYXRpdmUgZGVjb21wb3NpdGlvbiBtb3JlIHByZXZhbGVudCB3aXRoIGVjb25vbWljIHNlcmllcwoKKiBgQUxURVJOQVRJVkVgOiBVc2UgYSBCb3gtQ294IHRyYW5zZm9ybWF0aW9uLCBhbmQgdGhlbiB1c2UgYWRkaXRpdmUgZGVjb21wb3NpdGlvbgoqIExvZ3MgdHVybiBtdWx0aXBsaWNhdGl2ZSByZWxhdGlvbnNoaXBzIGluIHRvIGFkZGl0aXZlIHJlbGF0aW9uc2hpcHMKCmB5dCA9IFN0ICogVHQgKiBSdCAtLT4gbG4oeXQpID0gbG4oU3QpICsgbG4oVHQpICsgbG4oUnQgKWAKCiMjIyBFeGFtcGxlIAoKYGBge3J9CnVzX2VtcGxveW1lbnQgfD4gCiAgZmlsdGVyKFRpdGxlID09ICJSZXRhaWwgVHJhZGUiLCB5ZWFyKE1vbnRoKSA+PSAxOTkwKSB8PgogIHNlbGVjdCgtU2VyaWVzX0lEKSAtPiB1c19yZXRhaWxfZW1wbG95bWVudF8xOTkwCgp1c19yZXRhaWxfZW1wbG95bWVudF8xOTkwIHw+IGF1dG9wbG90KEVtcGxveWVkKSArIGdlb21fcG9pbnQoKSArCiAgbGFicyh5PSJQZXJzb25zICh0aG91c2FuZHMpIiwgdGl0bGUgPSAiVG90YWwgZW1wbG95bWVudCBpbiBVUyByZXRhaWwiKQpgYGAKCiogV2UgaGF2ZSBUcmVuZCArIEN5Y2xlICsgU2Vhc29uYWxpdHksIGxldHMgZml0IGEgbW9kZWwKCmBgYHtyfQp1c19yZXRhaWxfZW1wbG95bWVudF8xOTkwIHw+CiAgbW9kZWwoc3RsID0gU1RMKEVtcGxveWVkKSkKYGBgCgojIyMgTG9va2luZyBhdCB0aGUgbW9kZWwgY29tcG9uZW50cwoKYGBge3J9CmRjbXAgPC0gdXNfcmV0YWlsX2VtcGxveW1lbnRfMTk5MCB8PgogIG1vZGVsKHN0bCA9IFNUTChFbXBsb3llZCkpCmNvbXBvbmVudHMoZGNtcCkKYGBgCgojIyMgQXV0b3Bsb3QgdGhlIGNvbXBvbmVudHMKCmBgYHtyfQpjb21wb25lbnRzKGRjbXApIHw+IGF1dG9wbG90KCkKYGBgCgojIyMgT3RoZXIgdGhpbmdzIHdlIGNhbiBkbyB3aXRoIHRoZSBjb21wb25lbnRzCgpgYGB7cn0KdXNfcmV0YWlsX2VtcGxveW1lbnRfMTk5MCB8PgogIGF1dG9wbG90KEVtcGxveWVkLCBjb2xvcj0iYmxhY2siKSArCiAgYXV0b2xheWVyKGNvbXBvbmVudHMoZGNtcCksIHRyZW5kLCBjb2xvcj0iI0Q1NUUwMCIpICsKICBsYWJzKHk9ICJQZXJzb25zICh0aG91c2FuZHMpIiwgdGl0bGUgPSAiVG90YWwgZW1wbG95bWVudCBpbiBVUyByZXRhaWwiKQpgYGAKCiMjIyBTdWJzZXJpZXMgcGxvdCBgVXNlZnVsIGlmIGludGVyZXN0ZWQgaW4gU0hBUEUgb2Ygc2Vhc29uYWxpdHlgCgpgYGB7cn0KY29tcG9uZW50cyhkY21wKSB8PiBnZ19zdWJzZXJpZXMoc2Vhc29uX3llYXIpCmBgYAoKIyMjIFNlc29uYWwgQWRqdXN0bWVudAoKKiBVc2VmdWwgYnktcHJvZHVjdCBvZiBkZWNvbXBvc2l0aW9uOiBhbiBlYXN5IHdheSB0byBjYWxjdWxhdGUgc2Vhc29uYWxseSBhZGp1c3RlZCBkYXRhCiogQWRkaXRpdmUgZGVjb21wb3NpdGlvbjogc2Vhc29uYWxseSBhZGp1c3RlZCBkYXRhIGdpdmVuIGJ5IHl0IC0gU3QgPSBUdCArIFJ0CiogTXVsdGlwbGljYXRpdmU6IHl0L1N0ID0gVHQgKiBSdAoKUGxvdHRpbmcgdGhlIHNlYXNvbmFsbHkgYWRqdXN0ZWQgZGF0YTogeXQgLSBTdCA9IFR0ICsgUnQKCgpgYGB7cn0KdXNfcmV0YWlsX2VtcGxveW1lbnRfMTk5MCB8PgogIGF1dG9wbG90KEVtcGxveWVkLCBjb2xvcj0iYmxhY2siKSArCiAgYXV0b2xheWVyKGNvbXBvbmVudHMoZGNtcCksIHNlYXNvbl9hZGp1c3QsIGNvbG9yPSJibHVlIikgKwogIGxhYnMoeT0iUGVyc29ucyAodGhvdXNhbmRzKSIsIHRpdGxlID0gIlRvdGFsIGVtcGxveW1lbnQgaW4gVVMgcmV0YWlsIikKYGBgCgpPYnNlcnZhdGlvbnM6CgoqIFdlIGNhbiBzZWUgdGhlIHNlYXNvbl9hZGp1c3QgKGJsdWUpIGxpbmUgaXMgbW9yZSB3b2JibHkgdGhhbiB0aGUgdHJlbmQgbGluZSBpbiB0aGUgYWJvdmUgY2hhcnQKKiBUaGlzIGlzIGR1ZSB0byB0aGUgZWZmZWN0IG9mIFJ0IHRoZSByZW1haW5kZXIsIHdoaWNoIGlzIGFsbW9zdCBhbHdheXMgbm9pc3kgaW4gbmF0dXJlCgojIyMgSG93IHRvIHNlYXNvbmFsIGFkanVzdDoKCiogV2UgdXNlIGVzdGltYXRlcyBvZiBTIGJhc2VkIG9uIHBhc3QgdmFsdWVzIHRvIHNlYXNvbmFsbHkgYWRqdXN0IGEgY3VycmVudCB2YWx1ZQoqIFNlYXNvbmFsbHkgYWRqdXN0ZWQgc2VyaWVzIHJlZmxlY3QgKipyZW1haW5kZXJzKiogYXMgd2VsbCBhcyAqKnRyZW5kKioKKiBUaGVyZWZvcmUgdGhleSBhcmUgYG5vdGAgYHNtb290aGAsIGFuZCBgZG93bnR1cm5zYCBvciBgdXB0dXJuc2AgY2FuIGJlIGBtaXNsZWFkaW5nYAoqIGBJdCBpcyBiZXR0ZXIgdG8gdXNlIHRoZSB0cmVuZC1jeWNsZSBjb21wb25lbnQgdG8gbG9vayBmb3IgdHVybmluZyBwb2ludHNgCgojIE1vdmluZyBBdmVyYWdlcyAoQ2xhc3NpY2FsIERlY29tcG9zaXRpb24pCgoqIFRyYWRpdGlvbmFsIHdheSB0byBwZXJmb3JtIHRpbWUgc2VyaWVzIGRlY29tcG9zaXRpb25zLCAKKiBPcmlnaW5hdGVkIGluIHRoZSAxOTIwJ3MgYnV0IHN0aWxsIHRoZSBiYXNpcyBmb3IgbWFueSBkZWNvbXBvc2l0aW9ucy4KCkEgbW92aW5nIGF2ZXJhZ2UgaXMgYW4gYXZlcmFnZSBvZiBuZWFyYnkgcG9pbnRzCgoqIG9ic2VydmF0aW9ucyBuZWFyYnkgaW4gdGltZSBhcmUgYWxzbyBsaWtlbHkgdG8gYmUgYGNsb3NlIGluIHZhbHVlYAoqIGF2ZXJhZ2UgZWxpbWluYXRlcyBzb21lIGByYW5kb21uZXNzYCBpbiB0aGUgZGF0YSwgbGVhdmluZyBhIHNtb290aCB0cmVuZC1jeWNsZSBjb21wb25lbnQKKiAzLU1BOiBUdCA9ICh5KHQtMSkgKyB5dCArIHkodCsxKSkvMwoqIDUtTUE6IFR0ID0gKHkodC0yKSArIHkodC0xKSArIHl0ICsgeSh0KzEpICsgeSh0KzIpKS81CiogZWFjaCBhdmVyYWdlIGNvbXB1dGVkIGJ5IGRyb3BwaW5nIGBvbGRlc3RgIG9ic2VydmF0aW9uIGFuZCBpbmNsdWRpbmcgYG5leHRgIG9ic2VydmF0aW9uCiogYXZlcmFnaW5nIGBtb3Zlc2AgdHJvdWdoIHRpbWUgc2VyaWVzIHVudGlsIHRyZW5kLWN5Y2xlIGNvbXB1dGVkIGF0IGVhY2ggb2JzZXJ2YXRpb24gcG9zc2libGUKCiMjIyBGaXJzdCBzdGVwOiBHZXQgYW5kIGVzdGltYXRlIG9mIHRoZSB0cmVuZCBjb21wb25lbnQKCiogV2UgdXNlIE1vdmluZyBBdmVyYWdlcyBmb3IgdGhpczoKCgpgYGB7cn0KZ2xvYmFsX2Vjb25vbXkgfD4KICBmaWx0ZXIoQ291bnRyeSA9PSAiQXVzdHJhbGlhIikgfD4KICBhdXRvcGxvdChFeHBvcnRzKSArCiAgbGFicyh5PSIlIG9mIEdEUCIsIHRpdGxlID0gIlRvdGFsIEF1c3RyYWxpYW4gZXhwb3J0cyIpCmBgYAoKCiMjIyBXaHkgaXMgdGhlcmUgbm8gZXN0aW1hdGVzIGF0IHRoZSBlbmRzPwoKKiBmb3IgYSAzLU1BLCB0aGVyZSBjYW5ub3QgYmUgZXN0aW1hdGVzIGF0IHRpbWUgMSBvciB0aW1lIFQgYmVjYXVzZSB0aGUgb2JzZXJ2YXRpb25zIGF0IHRpbWUgMCBhbmQgVCsxIGFyZSBub3QgYXZhaWxhYmxlCiogR2VuZXJhbGx5OiB0aGVyZSBjYW5ub3QgYmUgZXN0aW1hdGVzIGF0IHRpbWVzIG5lYXIgdGhlIGVuZHBvaW50cwoKIyMjIFRoZSBvcmRlciBvZiB0aGUgTUEKCiogbGFyZ2VyIG9yZGVyIG1lYW5zIHNtb290aGVyLCBmbGF0dGVyIGN1cnZlCiogbGFyZ2VyIG9yZGVyIG1lYW5zIG1vcmUgcG9pbnRzIGxvc3QgYXQgZW5kcwoqIGBpZiBvcmRlciA9IGxlbmdodCBvZiBzZWFzb24gb3IgY3ljbGVgIElUIGByZW1vdmVzIHBhdHRlcm5gCiogQnV0IHNvIGZhciBvZGQgb3JkZXJzPwoqIHdpdGggZXZlbiBvcmRlcnMsIHdlIG5lZWQgdG8gdGFrZSAyIG1vdmluZyBhdmVyYWdlcywgdG8gY2VudGVyIHRoZSBkYXRhCgpJZiBvcmRlcj09NDogMS80W3l0LTIgKyB5dC0xICsgeXQgKyB5dCsxXSBvciAxLzRbeXQtMSArIHl0ICsgeXQrMSArIHl0KzJdClRoZXJlIGFyZSAyIG9wdGlvbnMgdG8gY29tcHV0ZSB0aGUgc2FtZSA0LU1BIHNvIHdlIG5lZWQgdG8gcmVjZW50ZXIgYXQgaGFsZiBvZiBib3RoCjRfTUEgOiAxLzIoMS80W3l0LTIgKyB5dC0xICsgeXQgKyB5dCsxXSArIDEvNFt5dC0xICsgeXQgKyB5dCsxICsgeXQrMl0pID0gMS84eXQtMiArIDEvNHl0LTEgKyAxLzR5dCArIDEvNHl0PTEgKyAxLzh5dCsyCgpgQSBNQSBvZiB0aGUgc2FtZSBsZW5naHQgYXMgdGhlIHNlYXNvbiByZW1vdmVzIHRoZSBzZWFzb25hbCBwYXR0ZXJuYAoKKiBGb3IgcXVhcnRlcmx5IGRhdGE6IHVzZSAyeDQgTUEKKiBGb3IgbW9udGhseSBkYXRhOiB1c2UgYSAyeDEyIE1BCgojIyMgTW92aW5nIGF2ZXJhZ2UgdHJlbmQtY3ljbGUKCmBgYHtyfQp1c19yZXRhaWxfZW1wbG95bWVudF8xOTkwIHw+CiAgbXV0YXRlKGAxMi1NQWAgPSBzbGlkZXI6OnNsaWRlX2RibChFbXBsb3llZCwgbWVhbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5iZWZvcmUgPSA1LCAuYWZ0ZXIgPSA2LCAuY29tcGxldGUgPSBUUlVFKSwKICAgICAgICAgYDJ4MTItTUFgID0gc2xpZGVyOjpzbGlkZV9kYmwoYDEyLU1BYCwgbWVhbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5iZWZvcmUgPSAxLCAuYWZ0ZXIgPSAwLCAuY29tcGxldGUgPSBUUlVFKSkgLT4gdXNfcmV0YWlsX2VtcGxveW1lbnRfMTk5MF9tYQoKdXNfcmV0YWlsX2VtcGxveW1lbnRfMTk5MF9tYQpgYGAKCiMjIyBQbG90dGluZyBpdAoKYGBge3J9CnVzX3JldGFpbF9lbXBsb3ltZW50XzE5OTBfbWEgfD4KICBhdXRvcGxvdChFbXBsb3llZCwgY29sb3I9ImJsYWNrIikgKwogIGF1dG9sYXllcih1c19yZXRhaWxfZW1wbG95bWVudF8xOTkwX21hLCB2YXJzKCIyeDEyLU1BIiksCiAgICAgICAgICAgIGNvbG9yPSJibHVlIikgKwogIGxhYnMoeT0iUGVyc29ucyAodGhvdXNhbmRzKSIsIHRpdGxlID0gIlRvdGFsIGVtcGxveW1lbnQgaW4gVVMgcmV0YWlsIikKYGBgCgojIENsYXNzaWNhbCBEZWNvbXBvc2l0aW9uIChlc3RpbWF0aW5nIHRpbWUgc2VyaWVzIGNvbXBvbmVudHMpCgpBZGRpdGl2ZSBkZWNvbXBvc2l0aW9uOiBjb21wb25lbnRzIGFkZAoKKiB5dCA9IFR0ICsgU3QgKyBSdAoKTXVsdGlwbGljYXRpdmUgRGVjb21wb3NpdGlvbjogY29tcG9uZW50cyBtdWx0aXBseQoKKiB5dCA9IFR0ICogU3QgKiBSdAoKMS4gRVN0aW1hdGUgVHQgdXNpbmcgTUEgKDJ4bSktTUEgaWYgbSBpcyBldmVuLiBPdGhlcndpc2UsIGVzdGltYXRlIFR0IHVzaW5nIG0tTUEKCjIuIENvbXB1dGUgZGUtdHJlbmRlZCBzZXJpZXMKCiAgKiBBZGRpdGl2ZSBkZWNvbXBvc2l0aW9uOiB5dCAtIFR0CiAgKiBNdWx0aXBsaWNhdGl2ZSBkZWNvbXBvc2l0aW9uOiB5dC9UdAoKMy4gRGUtdHJlbmRpbmcKClJlbW92ZSBzbW9vdGhlZCBzZXJpZXMgVHQgZnJvbSB5dCB0byBsZWF2ZSBTdCBhbmQgUnQKCiogQWRkaXRpdmUgbW9kZWwgeXQgLSBUdCArIChUdCArIFN0ICsgUnQpIC0gU3QgPSBTdCArIFJ0CiogTXVsdGlwbGljYXRpdmUgbW9kZWw6IHl0L1R0ID0gVHR4U3R4UnQvVHQgPSBTdHhSdAoKVGhpcyB3aWxsIGxlYXZlIGJlaGluZCBTZWFzb25hbCBhbmQgUmVtYWluZGVyCgo0LiBFc3RpbWF0ZSBTZWFzb25hbCBjb21wb25lbnQKCiogU2Vhc29uYWwgaW5kZXggZm9yIGVhY2ggc2Vhc29uIGlzIGVzdGltYXRlZCBhcyBhbiBhdmVyYWdlIG9mIHRoZSBkZXRyZW5kZWQgc2VyaWVzIGZvciB0aGF0IHNlYXNvbiBvZiBzdWNjZXNzaXZlIHllYXJzCiogRS5nLiB0YWtlIGF2ZXJhZ2VzIGFjcm9zcyBhbGwgSmFudWFyaWVzIHRvIGdldCBTMSBpZiB5b3VyIGRhdGEgaXMgbW9udGhseQoKSWYgbmVjZXNzYXJ5IGBDT05TVFJBSU5gIGFkanVzdCB0aGUgc2Vhc29uYWwgaW5kaWNlcyBzbyB0aGF0OgoKICAqIEFkZGl0aXZlOiBTMSArIFMyICsgLi4uICsgU04gPSAwCiAgKiBNdWx0aXBsaWNhdGl2ZTogUzEgKyBTMiArIC4uLiArIFNOID0gbQogIApUaGUgc2Vhc29uYWwgY29tcG9uZW50IFN0IHNpbXBseSBjb25zaXN0cyBvZiByZXBsaWNhdGlvbnMgb2YgdGhlIHNlYXNvbmFsIGluZGljZXMKCiogQWRkaXRpdmUgZGVjb21wb3NpdGlvbjogUnQgPSB5dCAtIFR0IC0gU3QKKiBNdWx0aXBsaWNhdGl2ZSBkZWNvbXBvc2l0aW9uOiBSdCA9IHl0LyhUdCpTdCkKCmBDbGFzc2ljYWwgZGVjb21wb3NpdGlvbmAKCiogQ2hvb3NlIGFkZGl0aXZlIG9yIG11bHRpcGxpY2F0aXZlIGRlcGVuZGluZyBvbiB3aGljaCBnaXZlcyB0aGUgbW9zdCBzdGFibGUgY29tcG9uZW50cwoqIEZvciBtdWx0aXBsaWNhdGl2ZSBtb2RlbCwgdGhpcyBtZXRob2QgYS5rLmEuIGByYXRpby10by1tb3ZpbmctYXZlcmFnZWAgbWV0aG9kCgojIyMgQWRkaXRpdmUKCmBgYHtyfQpkY21wIDwtIHVzX3JldGFpbF9lbXBsb3ltZW50XzE5OTAgfD4KICBtb2RlbChzdGwgPSBTVEwoRW1wbG95ZWQpKQpjb21wb25lbnRzKGRjbXApIHw+IGF1dG9wbG90KCkgKwogIGxhYnModGl0bGUgPSAiQ2xhc3NpY2FsIGFkZGl0aXZlIGRlY29tcG9zaXRpb24gb2YgVVMgcmV0YWlsIGVtcGxveW1lbnQiKQpgYGAKCiMjIyBNdWx0aXBsaWNhdGl2ZQoKYGBge3J9CmRjbXAgPC0gdXNfcmV0YWlsX2VtcGxveW1lbnRfMTk5MCB8PgogIG1vZGVsKGNsYXNzaWNhbF9kZWNvbXBvc2l0aW9uKEVtcGxveWVkLCB0eXBlID0gIm11bHRpcGxpY2F0aXZlIikpCmNvbXBvbmVudHMoZGNtcCkgfD4gYXV0b3Bsb3QoKSArCiAgbGFicyh0aXRsZSA9ICJDbGFzc2ljYWwgbXVsdGlwbGljYXRpdmUgZGVjb21wb3NpdGlvbiBvZiBVUyByZXRhaWwgZW1wbG95bWVudCIpCmBgYAoKIyMjIEdlbmVyYWwgY29tbWVudHMgb2YgQ2xhc3NpY2FsIERlY29tcG9zaXRpb24KCiogRXN0aW1hdGUgb2YgdHJlbmQgaXMgdW5hdmFpbGFibGUgZm9yIGZpcnN0IGZldyBhbmQgbGFzdCBmZXcgb2JzZXJ2YXRpb25zCiogKipTZWFzb25hbCBjb21wb25lbnQgcmVwZWF0cyoqIGZvcm0geWVhciB0byB5ZWFyLiBNYXkgbm90IGJlIHJlYWxpc3RpYwoqICoqTm90IHJvYnVzdCB0byBvdXRsaWVycyoqCiogTmV3ZXIgbWV0aG9kcyBkZXNpbmdlZCB0byBvdmVyY29tZSB0aGVzZSBwcm9ibGVtcwogIAojIGBNZXRob2RzIHVzZWQgaW4gb2ZmaWNpYWwgc3RhdGlzdGljc2AKClRpbWVzZXJpZXMgZGVjb21wb3NpdGlvbiBpcyBvZmZpY2lhbGx5IHVzZWQgaW4gb2ZmaWNpYWwgc3RhdGlzdGljcyBidXJlYXVzCgoqIENsYXNzaWNhbCBtZXRob2Qgb3JpZ2luYXRlZCBpbiAxOTIwCiogYENlbnN1cyBJSWAgbWV0aG9kIGludHJvZHVjZWQgaW4gYDE5NTdgCiogQmFzaXMgZm9yIGBYLTExYCBtZXRob2QgYW5kIHZhcmlhbnRzIChpbmNsdWRpbmcgWC0xMiwgWC0xMi1BUklNQSwgWC0xMy1BUklNQSkKKiBgU1RMYCBtZXRob2QgaW50cm9kdWNlZCBpbiBgMTk4M2AgYXQgQkVMTCBMQUJTCiogYFRSQU1PL1NFQVRTYCBpbnRyb2R1Y2VkIGluIGAxOTkwc2AgaW4gRXVyb3BlIChiYW5rIG9mIFNwYWluKQoKTmF0aW9uYWwgU3RhdGlzdGljcyBPZmZpY2VzCgoqIEFCUyAoQXVzdHJhbGlhKSB1c2VzIFgtMTItQVJJTUEKKiBVUyBDZW5zdXMgQnVyZWF1IHVzZXMgWC0xM0FSSU1BLVNFQVRTCiogU3RhdGlzdGljcyBDYW5hZGEgdXNlcyBYLTEyLUFSSU1BCiogT05TIChVSykgdXNlcyBYLTEyLUFSSU1BCiogRXVyb1N0YXQgdXNlcyBYLTEzQVJJTUEtU0VBVFMKCiMjIEhvdyB0byBkbyBpdCB1c2luZyB0aGUgYEZBQkxFYCBwYWNrYWdlcwoKIyMjIEluc3RhbGwgcGFja2FnZXMKCmBgYHtyfQojIGluc3RhbGwucGFja2FnZXMoInNlYXNvbmFsIikKYGBgCiMjIyBMb2FkIHBhY2thZ2VzCgpgYGB7cn0KIyBsaWJyYXJ5KHNlYXNvbmFsKQpgYGAKCiMjIyBYLTEzLUFSSU1BLVNFQVRTIERlY29tcG9zaXRpb24KCmBgYHtyfQp4MTFfZGNtcCA8LSB1c19yZXRhaWxfZW1wbG95bWVudF8xOTkwIHw+CiAgbW9kZWwoeDExID0gWF8xM0FSSU1BX1NFQVRTKEVtcGxveWVkIH4geDExKCkpKQoKY29tcG9uZW50cyh4MTFfZGNtcCkgIyBzaG93IHRoZSBjb21wb25lbnRzCmBgYAoKIyMjIFBsb3R0aW5nIFgtMTMtQVJJTUEgYE1VTFRJUExJQ0FUSVZFYAoKYGBge3J9CmNvbXBvbmVudHMoeDExX2RjbXApIHw+IGF1dG9wbG90KCkKYGBgCgojIyMgQWR2YW50YWdlcwoKKiBSZWxhdGl2ZWx5IHJvYnVzdCB0byBvdXRsaWVycwoqIENvbXBsZXRseSBhdXRvbWF0ZWQgY2hvaWNlcyBmb3IgdHJlbmQgYW5kIHNlYXNvbmFsIGNoYW5nZXMKKiBWZXJ5IHdpZGVseSB0ZXN0ZWQgb24gZWNvbm9taWMgZGF0YSBvdmVyIGEgbG9uZyBwZXJpb2Qgb2YgdGltZQoKIyMjIERpc2FkdmFudGFnZXMKCiogTm8gcHJlZGljdGlvbi9jb25maWRlbmNlIGludGVydmFscwoqIEFkIGhvYyBtZXRob2Qgd2l0aCBubyB1bmRlcmx5aW5nIG1vZGVsCiogYE9OTFkgREVWRUxPUEVEIEZPUiBNT05USExZL1FVQVJURVIgREFUQWAKCiMjIyBFeHRlbnNpb25zOiBYLTEyQVJJTUEtIGFuZCBYLTEzQVJJTUEKCiogVGhlIFgxMSwgWDEyQVJJTUEsIFgxM0FSSU1BIG1ldGhvZHMgYXJlIGJhc2VkIG9uIENlbnN1cyBJSSBkZWNvbXBvc2l0aW9uCiogVGhlc2UgYWxsb3cgYWRqdXN0bWVudHMgZm9yIHRyYWRpbmcgZGF5cyBhbmQgb3RoZXIgZXhwbGFuYXRvcnkgdmFyaWFibGVzCiogS25vd24gb3V0bGllcnMgY2FuIGJlIG9tbWl0ZWQKKiBMZXZlbCBzaGlmdHMgYW5kIHJhbXAgZWZmZWN0cyBjYW4gYmUgbW9kZWxsZWQKKiBNaXNzaW5nIHZhbHVlcyBlc3RpbWF0ZWQgYW5kIHJlcGxhY2VkCiogSG9saWRheSBmYWN0b3JzIGNhbiBiZSBlc3RpbWF0ZWQKCiMjIFgtMTNBUklNQS1TRUFUUwoKYGBge3J9CnNlYXRzX2RjbXAgPC0gdXNfcmV0YWlsX2VtcGxveW1lbnRfMTk5MCB8PgogIG1vZGVsKHNlYXRzID0gWF8xM0FSSU1BX1NFQVRTKEVtcGxveWVkIH4gc2VhdHMoKSkpCgpjb21wb25lbnRzKHNlYXRzX2RjbXApIHw+IGF1dG9wbG90KCkKYGBgCgojIyMgQWR2YW50YWdlcyBvZiBgWC0xM0FSSU1BLVNFQVRTYAoKKiBNb2RlbCBiYXNlZAoqIGBDQU4gR0VUIENPTkZJREVOQ0UgSU5URVJWQUxTYAoqIFNtb290aCB0cmVuZCBlc3RpbWF0ZQoqIEFsbG93cyBlc3RpbWF0ZXMgYXQgZW5kIHBvaW50cwoqIEFsbG93cyBjaGFuZ2luZyBzZWFzb25hbGl0eQoqIERldmVsb3BlZCBmb3IgZWNvbm9taWMgZGF0YQoKIyMjIERpc2FkdmFudGFnZXMgb2YgYFgtMTNBUklNQS1TRUFUU2AKCiogYE9OTFkgREVWRUxPUEVEIEZPUiBRIEFORCBNIERBVEFgCgojIFNUTCBTZWFzb25hbCBhbmQgVHJlbmQgZGVjb21wb3NpdGlvbiB1c2luZyBMb2VzcwoKKiBMb2VzcyBpcyBhIGZvcm0gb2Ygc21vb3RoaW5nIGJhc2VkIG9uIGxvY2FsbHkgbGluZWFyIHJlZ3Jlc3Npb25zCiogVmVyeSB2ZXJzYXRpbGUgYW5kIHJvYnVzdAoqIFdpbGwgaGFuZGxlIGFueSB0eXBlIG9mIHNlYXNvbmFsaXR5CiogU2Vhc29uYWwgY29tcG9uZW50IGFsbG93ZWQgdG8gY2hhbmdlIG92ZXIgdGltZQogICogUmF0ZSBvZiBjaGFuZ2UgY29udHJvbGxlZCBieSB1c2VyCiogU21vb3RobmVzcyBvZiB0cmVuZC1jeWNsZSBhbHNvIGNvbnRyb2xsZWQgYnkgdXNlcgoqIFJvYnVzdCB0byBvdXRsaWVycwoKRGlzYWR2YW50YWdlczoKCiogTm8gdHJhZGluZyBkYXkgYWRqdXN0bWVudAoqIE5vIGNhbGVuZGFyIGFkanVzdG1lbnRzCiogT25seSBhZGRpdGl2ZQoKRm9yIG11bHRpcGxpY2F0aXZlOiBUYWtlIGxvZ3MgdG8gZ2V0IG11bHRpcGxpY2F0aXZlIGRlY29tcG9zaXRpb24KVXNlIEJveC1Db3ggdHJhbnNmb3JtYXRpb25zIHRvIGdldCBvdGhlciBkZWNvbXBvc2l0aW9ucwoKIyMjIEV4YW1wbGUKCmBgYHtyfQp1c19yZXRhaWxfZW1wbG95bWVudF8xOTkwIHw+CiAgbW9kZWwoU1RMKEVtcGxveWVkKSkgfD4KICBjb21wb25lbnRzKCkgfD4KICBhdXRvcGxvdCgpCmBgYAoKIyMjIFdlIGNhbiBjb250cm9sIHRoZSBjaGFuZ2UgaW4gc2Vhc29uYWwgcGF0dGVybiBhbmQgdHJlbmQgd2l0aCB3aW5kb3dzCgpgYGB7cn0KdXNfcmV0YWlsX2VtcGxveW1lbnRfMTk5MCB8PgogIG1vZGVsKFNUTChFbXBsb3llZCB+IHNlYXNvbih3aW5kb3c9MTUpICsgdHJlbmQod2luZG93PTY2NjUpKSkgfD4KICBjb21wb25lbnRzKCkgfD4KICBhdXRvcGxvdCgpCmBgYAoKT2JzZXJ2YXRpb25zCgoqIExvdCBvZiBzdHJ1Y3R1cmUgaW4gdGhlIHJlbWFpbmRlcgoqIEJlY2F1c2UgdHJlbmQgd2luZG93ID0gNjY2NQoqIFRyZW5kIGJlY29tZXMgYSBzdHJhaWdodCBsaW5lCiogV2hhdCBzaG91bGQgaGF2ZSBnb25lIGluIHRyZW5kIGdvZXMgdG8gcmVtYWluZGVyCiogYERlZmF1bHQgcGFyYW1zIHdvcmsgcHJldHR5IGdvb2RgCgojIyMgVHJlbmQgd2l0aCBzbWFsbCB3aW5kb3cKCmBgYHtyfQp1c19yZXRhaWxfZW1wbG95bWVudF8xOTkwIHw+CiAgbW9kZWwoU1RMKEVtcGxveWVkIH4gc2Vhc29uKHdpbmRvdz0xNSkgKyB0cmVuZCh3aW5kb3c9MTUpKSkgfD4KICBjb21wb25lbnRzKCkgfD4KICBhdXRvcGxvdCgpCmBgYAoKKiBPYnNlcnZhdGlvbnMKCiogV2l0aCB0cmVuZCB3aW5kb3cgPSAxNQoqIFdlIGNhcHR1cmUgdGhlIGludGVyZXN0aW5nIGJlaGF2aW91ciBvdXIgaW4gVHJlbmQKKiBOb2lzZSBnb2VzIHRvIHJlbWFpbmRlcgoqIE5vIHN0cm9uZyBzdHJ1Y3R1cmUgaW4gcmVtYWluZGVyCgojIyMgUm9idXN0IGFyZ3VtZW50IChkZWZhdWx0IGlzIGZhbHNlKQoKYGBge3J9CnVzX3JldGFpbF9lbXBsb3ltZW50XzE5OTAgfD4KICBtb2RlbChTVEwoRW1wbG95ZWQgfiBzZWFzb24od2luZG93PTE1KSArIHRyZW5kKHdpbmRvdz0xNSksIHJvYnVzdCA9IFRSVUUpKSB8PgogIGNvbXBvbmVudHMoKSB8PgogIGF1dG9wbG90KCkKYGBgCgojIyMgU3VtbWFyeQoKKiB0cmVuZCh3aW5kb3cgPSA/KSBjb250cm9scyB3aWdnbGluZXNzIG9mIHRyZW5kIGNvbXBvbmVudAogICogQmVjYXVzZSBvZiBMb2VzCiAgKiB3ZWlnaHRlZCBsZWFzdCBzcXVhcmVkIGZpdHMKICAqIHNtYWxsZXIgd2luZG93cywgZmV3ZXIgb2JzIGZvciBlYWNoIGxvY2FsIGxpbmVhciByZWdyZXNzaW9uCiAgCiogc2Vhc29uKHdpbmRvdyA9ID8pIGNvbnRyb2xzIHZhcmlhdGlvbnMgb24gc2Vhc29uYWwgY29tcG9uZW50CiAgKiBTYW1lIGNvbXBvbmVudCBpbiBkaWZmZXJlbnQgeWVhcnMKICAqIEhvdyBtYW55IHllYXJzIHRvIHVzZSB3aGVuIGVzdGltYXRpbmcgZWFjaCBvZiBzZWFzb25hbCBjb21wb25lbnQKKiBzZWFzb24od2luZG93ID0gJ3BlcmlvZGljJykgaXMgZXF1aXZhbGVudCB0byBpbmZpbml0ZSB3aW5kb3cKCkJ5IGRlZmF1bHQKCiogY2hvb3NlcyBzZWFzb24od2luZG93PTEzKQoqIENhbiBpbmNsdWRlIHRyYW5zZm9ybWF0aW9ucwoKYFNUTCBERUNPTVBPU0lUSU9OYAoKKiBEZWZhdWx0IHRyZW5kOiB3aW5kb3cgPSBuZXh0b2RkKGNlaWxpbmcoKDEuNSpwZXJpb2QpLygxLSgxLjUvcy53aW5kb3cpKSkpCiogRGVmYXVsdCBzZWFzb246IHdpbmRvdyA9IDEzCgpIb3cgZG9lcyBpdCB3b3JrPwoKKiBVcGRhdGVkIHRoZSB0cmVuZCBhbmQgc2Vhc29uYWwgY29tcG9uZW50IGl0ZXJhdGl2ZWx5CiogU3RhcnRzIG9mZiBieSBzYXlpbmcsIGxldHMgc3VwcG9zZSB0aGVyZSBpcyBubyB0cmVuZCwgZXN0aW1hdGUgc2Vhc29uYWxpdHkgYnkgY2xhc3NpY2FsIGRlY29tcAoqIFJlbW92ZXMgdGhhdCwgdHJpZXMgdG8gZXN0aW1hdGUgdHJlbmQgdXNpbmcgTE9FUyBjdXJ2ZQoqIEl0ZXJhdGVzCgpFeHBsYW5hdGlvbjoKCiogU3RhcnRzIHdpdGggVHQgPSAwCiogVXNlcyBhIG1peHR1cmUgb2YgYGxvZXNzYCBhbmQgYE1BYCB0byBzdWNlc3NpdmVseSByZWZpbmUgdGhlIGB0cmVuZGAgYW5kIGBzZWFzb25hbGAgZXN0aW1hdGVzCiogVGhlIHRyZW5kIHdpbmRvdyBjb250cm9scyBgbG9lc3NgIGJhbmR3aWR0aCBhcHBsaWVkIHRvIGRlYXNvbmFsaXNlZCB2YWx1ZXMKKiBUaGUgc2Vhc29uIHdpbmRvdyBjb250cm9scyBgbG9lc3NgIGJhbmR3aWR0aCBhcHBsaWVkIHRvIGRldHJlbmRlZCBzdWJzZXJpZXMKKiBSb2J1c3RiZXNzIHdlaWdodHMgYmFzZWQgb24gcmVtYWluZGVyCgojIyMgTElOSyBUTyBQQVBFUjoKCmh0dHA6Ly9iaXQubHkvc3RsMTk5MAoKCiMgVEhFIEVORAo=