library(fpp3)
-- Attaching packages --------------------- fpp3 0.3 --
v tibble      3.0.6       v tsibble     0.9.3  
v dplyr       1.0.3       v tsibbledata 0.2.0  
v tidyr       1.1.2       v feasts      0.1.6  
v lubridate   1.7.9.2     v fable       0.2.1  
v ggplot2     3.3.3       
-- Conflicts ------------------------ fpp3_conflicts --
x lubridate::date()   masks base::date()
x dplyr::filter()     masks stats::filter()
x tsibble::interval() masks lubridate::interval()
x dplyr::lag()        masks stats::lag()

https://robjhyndman.com/seminars/uwa2017/

https://robjhyndman.com/seminars/isi2019workshop/

https://github.com/robjhyndman/ETC3550Slides/tree/fable

https://github.com/rstudio-conf-2020/time-series-forecasting/blob/master/materials/labs.R

http://www.gradaanwr.net/

1 Getting started

1.1 What can be forecast?

The predictability of an event or a quantity depends on several factors including:

  1. how well we understand the factors that contribute to it;
  2. how much data is available;
  3. whether the forecasts can affect the thing we are trying to forecast.

Good forecasts capture the genuine patterns and relationships which exist in the historical data, but do not replicate past events that will not occur again.

Forecasts rarely assume that the environment is unchanging. What is normally assumed is that the way in which the environment is changing will continue into the future.

1.2 Forecasting, planning and goals

They are three different things.

  • Forecasting: is about predicting the future as accurately as possible, given all of the information available, including historical data and knowledge of any future events that might impact the forecasts.

  • Goals: are what you would like to have happen. Goals should be linked to forecasts and plans, but this does not always occur. Too often, goals are set without any plan for how to achieve them, and no forecasts for whether they are realistic.

  • Planning: is a response to forecasts and goals. Planning involves determining the appropriate actions that are required to make your forecasts match your goals.

Modern organisations require short-term,medium-term and long-term forecasts, depending on the specific application.

1.3 Determining what to forecast

In the early stages of a forecasting project, decisions need to be made about what should be forecast. It is also necessary to consider the forecasting horizon.

Once it has been determined what forecasts are required, it is then necessary to find or collect the data on which the forecasts will be based.

1.4 Forecasting data and methods

If there are no data available, or if the data available are not relevant to the forecasts, then qualitative forecasting methods must be used.

Quantitative forecasting can be applied when two conditions are satisfied:

  • numerical information about the past is available;
  • it is reasonable to assume that some aspects of the past patterns will continue into the future.

1.4.1 Time series forecasting

The simplest time series forecasting methods use only information on the variable to be forecast, and make no attempt to discover the factors that affect its behaviour. Therefore they will extrapolate trend and seasonal patterns, but they ignore all other information such as marketing initiatives, competitor activity, changes in economic conditions, and so on.

1.4.2 Predictor variables and time series forecasting

Predictor variables are often useful in time series forecasting. For example, suppose we wish to forecast the hourly electricity demand (ED) of a hot region during the summer period. A model with predictor variables might be of the form

\[\begin{align*} \text{ED} = & f(\text{current temperature, strength of economy, population,}\\ & \qquad\text{time of day, day of week, error}). \end{align*}\]

The “error” term on the right allows for random variation and the effects of relevant variables that are not included in the model. We call this an explanatory model because it helps explain what causes the variation in electricity demand.

Because the electricity demand data form a time series, we could also use a time series model for forecasting. In this case, a suitable time series forecasting equation is of the form

\[\begin{align*} {ED}_{t+1} = f(\text{ED}_{t}, \text{ED}_{t-1}, \text{ED}_{t-2}, \text{ED}_{t-3},\dots, \text{error} \end{align*}\]

Here, prediction of the future is based on past values of a variable, but not on external variables that may affect the system. Again, the “error” term on the right allows for random variation and the effects of relevant variables that are not included in the model.

There is also a third type of model which combines the features of the above two models.

\[\begin{align*} \text{ED}_{t+1} = f(\text{ED}_{t}, \text{current temperature, time of day, day of week, error}). \end{align*}\]

They are known as dynamic regression models, panel data models, longitudinal models, transfer function models, and linear system models (assuming that \(f\) is linear).

The model to be used in forecasting depends on the resources and data available, the accuracy of the competing models, and the way in which the forecasting model is to be used.

1.5 The basic steps in a forecasting task

1.5.1 Step 1: Problem definition.

Defining the problem carefully requires an understanding of the way the forecasts will be used, who requires the forecasts, and how the forecasting function fits within the organisation requiring the forecasts. A forecaster needs to spend time talking to everyone who will be involved in collecting data, maintaining databases, and using the forecasts for future planning.

1.5.2 Step 2: Gathering information.

There are always at least two kinds of information required: (a) statistical data, and (b) the accumulated expertise of the people who collect the data and use the forecasts. Occasionally, old data will be less useful due to structural changes in the system being forecast; then we may choose to use only the most recent data. However, remember that good statistical models will handle evolutionary changes in the system; don’t throw away good data unnecessarily.

1.5.3 Step 3: Preliminary (exploratory) analysis.

Always start by graphing the data. Are there consistent patterns? Is there a significant trend? Is seasonality important? Is there evidence of the presence of business cycles? Are there any outliers in the data that need to be explained by those with expert knowledge? How strong are the relationships among the variables available for analysis?

1.5.4 Step 4: Choosing and fitting models

The best model to use depends on the availability of historical data, the strength of relationships between the forecast variable and any explanatory variables, and the way in which the forecasts are to be used. It is common to compare two or three potential models. Each model is itself an artificial construct that is based on a set of assumptions (explicit and implicit) and usually involves one or more parameters which must be estimated using the known historical data.

1.5.5 Step 5: Using and evaluating a forecasting model.

Once a model has been selected and its parameters estimated, the model is used to make forecasts. The performance of the model can only be properly evaluated after the data for the forecast period have become available.

1.6 The statistical forecasting perspective

The further ahead we forecast, the more uncertain we are. When we obtain a forecast, we are estimating the middle of the range of possible values the random variable could take. Often, a forecast is accompanied by a prediction interval giving a range of values the random variable could take with relatively high probability.

\(y_t\) will denote the observation at time t

Suppose we denote all the information we have observed as \(\mathcal{I}\) and we want to forecast \(y_t\). We then write \(y_{t} |\mathcal{I}\) meaning “the random variable \(y_t\) given what we know in \(\mathcal{I}\).” The set of values that this random variable could take, along with their relative probabilities, is known as the “probability distribution” of \(y_{t} |\mathcal{I}\) . In forecasting, we call this the forecast distribution.

When we talk about the “forecast,” we usually mean the average value of the forecast distribution, and we put a “hat” over \(y\) to show this (\(\hat{y}_t\)).

2 Time series graphics

2.1 tsibble objects

https://otexts.com/fpp3/tsibbles.html

tsibble objects extend tidy data frames (tibble objects) by introducing temporal structure.

y <- tsibble(Year = 2015:2019, Observation = c(123, 39, 78, 52, 110), index = Year)

We have set the time series index to be the Year column, which associates the measurements (Observation) with the time of recording (Year).

For observations that are more frequent than once per year, we need to use a time class function on the index.

2.2 Time plots

melsyd_economy <- ansett %>%
  filter(Airports == "MEL-SYD", Class == "Economy")
autoplot(melsyd_economy, Passengers) +
  labs(title = "Ansett economy class passengers",
       subtitle = "Melbourne-Sydney")

The time plot immediately reveals some interesting features.

  • There was a period in 1989 when no passengers were carried — this was due to an industrial dispute.
  • There was a period of reduced load in 1992. This was due to a trial in which some economy class seats were replaced by business class seats.
  • A large increase in passenger load occurred in the second half of 1991. There are some large dips in load around the start of each year. These are due to holiday effects.
  • There is a long-term fluctuation in the level of the series which increases during 1987, decreases in 1989, and increases again through 1990 and 1991.
  • There are some periods of missing observations.
PBS %>%
  filter(ATC2 == "A10") %>%
  select(Month, Concession, Type, Cost) %>%
  summarise(TotalC = sum(Cost)) %>%
  mutate(Cost = TotalC / 1e6) -> a10

autoplot(a10, Cost) +
  labs(y = "$ million", title = "Antidiabetic drug sales")

Here, there is a clear and increasing trend. There is also a strong seasonal pattern that increases in size as the level of the series increases. The sudden drop at the start of each year is caused by a government subsidisation scheme that makes it cost-effective for patients to stockpile drugs at the end of the calendar year. Any forecasts of this series would need to capture the seasonal pattern, and the fact that the trend is changing slowly.

2.3 Time series patterns

  • Trend: A trend exists when there is a long-term increase or decrease in the data. Sometimes we will refer to a trend as “changing direction,” when it might go from an increasing trend to a decreasing trend.

  • Seasonal: A seasonal pattern occurs when a time series is affected by seasonal factors such as the time of the year or the day of the week. Seasonality is always of a fixed and known period.

  • Cyclic: A cycle occurs when the data exhibit rises and falls that are not of a fixed frequency. These fluctuations are usually due to economic conditions, and are often related to the “business cycle.”

2.4 Seasonal plots

a10 %>%
  gg_season(Cost, labels = "both") +
  labs(y = "$ million",
       title = "Seasonal plot: antidiabetic drug sales")

It is clear that there is a large jump in sales in January each year. Actually, these are probably sales in late December as customers stockpile before the end of the calendar year, but the sales are not registered with the government until a week or two later. The graph also shows that there was an unusually small number of sales in March 2008 (most other years show an increase between February and March). The small number of sales in June 2008 is probably due to incomplete counting of sales at the time the data were collected.

2.4.1 Multiple seasonal periods

Where the data has more than one seasonal pattern, the period argument can be used to select which seasonal plot is required.

vic_elec %>% gg_season(Demand, period = "day") + theme(legend.position = "none")

vic_elec %>% gg_season(Demand, period = "week") + theme(legend.position = "none")

vic_elec %>% gg_season(Demand, period = "year")

2.5 Seasonal subseries plots

a10 %>%
  gg_subseries(Cost) +
  labs(y = "$ million",
       title = "Seasonal subseries plot: antidiabetic drug sales")

The blue horizontal lines indicate the means for each month. This form of plot enables the underlying seasonal pattern to be seen clearly, and also shows the changes in seasonality over time. It is especially useful in identifying changes within particular seasons. In this example, the plot is not particularly revealing; but in some cases, this is the most useful way of viewing seasonal changes over time.

2.5.1 Example: Australian holiday tourism

total visitor nights spent on Holiday by State for each quarter

holidays <- tourism %>%
  filter(Purpose == "Holiday") %>%
  group_by(State) %>%
  summarise(Trips = sum(Trips))

head(holidays)

Strong seasonality for most states but seasonal peaks do not coincide.

autoplot(holidays, Trips) +
  labs(y = "thousands of trips",
       title = "Australian domestic holiday nights")

Southern states of Australia (Tasmania, Victoria and South Australia) have strongest tourism in Q1 (their summer), while the northern states (Queensland and the Northern Territory) have the strongest tourism in Q3 (their dry season).

gg_season(holidays, Trips) +
  labs(y = "thousands of trips",
       title = "Australian domestic holiday nights")

Corresponding subseries plots:

holidays %>%
  gg_subseries(Trips) +
  labs(y = "thousands of trips",
       title = "Australian domestic holiday nights")

2.6 Scatterplots

Explore relationships between time series.

vic_elec %>%
  filter(year(Time) == 2014) %>%
  autoplot(Demand) +
  labs(y = "Demand (GW)",
       title = "Half-hourly electricity demand: Victoria, Australia")

vic_elec %>%
  filter(year(Time) == 2014) %>%
  autoplot(Temperature) +
  labs(y = "Temperature (degrees Celsius)",
       title = "Half-hourly temperatures: Melbourne, Australia")

We can study the relationship between demand and temperature by plotting one series against the other.

vic_elec %>%
  filter(year(Time) == 2014) %>%
  ggplot(aes(x = Temperature, y = Demand)) +
  geom_point() +
  labs(y = "Demand (GW)", x = "Temperature (degrees Celsius)")

It is clear that high demand occurs when temperatures are high due to the effect of air-conditioning. But there is also a heating effect, where demand increases for very low temperatures.

2.6.1 Correlation

Correlation coefficients to measure the strength of the relationship between two variables.

\[\begin{align*} r = \frac{\sum (x_{t} - \bar{x})(y_{t}-\bar{y})}{\sqrt{\sum(x_{t}-\bar{x})^2}\sqrt{\sum(y_{t}-\bar{y})^2}}. \end{align*}\]

The value of \(r\) always lies between \(−1\) and \(1\) with negative values indicating a negative relationship and positive values indicating a positive relationship.

2.6.2 Scatterplot matrices

When there are several potential predictor variables, it is useful to plot each variable against each other variable.

visitors <- tourism %>%
  group_by(State) %>%
  summarise(Trips = sum(Trips))
visitors %>%
  ggplot(aes(x = Quarter, y = Trips)) +
  geom_line() +
  facet_grid(vars(State), scales = "free_y") +
  labs(y = "Number of visitor nights each quarter (millions)")

visitors %>%
  pivot_wider(values_from=Trips, names_from=State) %>%
  GGally::ggpairs(columns = 2:9)

In this example, mostly positive relationships are revealed, with the strongest relationships being between the neighboring states located in the south and south east coast of Australia, namely, New South Wales, Victoria and South Australia. Some negative relationships are also revealed between the Northern Territory and other regions. The Northern Territory is located in the north of Australia famous for its outback desert landscapes visited mostly in winter. Hence, the peak visitation in the Northern Territory is in the July (winter) quarter in contrast to January (summer) quarter for the rest of the regions.

2.7 Lag plots

horizontal axis shows lagged values of the time series. Each graph shows \(y_t\) plotted against \(y_{t−k}\) for different values of \(k\).

recent_production <- aus_production %>%
  filter(year(Quarter) >= 2000)
recent_production %>% gg_lag(Beer, geom = "point")

The relationship is strongly positive at lags 4 and 8, reflecting the strong seasonality in the data.

2.8 Autocorrelation

Autocorrelation measures the linear relationship between lagged values of a time series.

\[\begin{align*} r_{k} = \frac{\sum\limits_{t=k+1}^T (y_{t}-\bar{y})(y_{t-k}-\bar{y})} {\sum\limits_{t=1}^T (y_{t}-\bar{y})^2}, \end{align*}\]

The autocorrelation coefficients make up the autocorrelation function or ACF.

recent_production %>% ACF(Beer, lag_max = 9)

We usually plot the ACF to see how the correlations change with the lag \(k\). The plot is sometimes known as a correlogram.

recent_production %>%
  ACF(Beer) %>%
  autoplot()

  • \(r_4\) is higher than for the other lags. This is due to the seasonal pattern in the data: the peaks tend to be four quarters apart and the troughs tend to be four quarters apart.
  • \(r_2\) is more negative than for the other lags because troughs tend to be two quarters behind peaks.
  • The dashed blue lines indicate whether the correlations are significantly different from zero.

2.8.1 Trend and seasonality in ACF plots

When data have a trend, the autocorrelations for small lags tend to be large and positive because observations nearby in time are also nearby in size. So the ACF of trended time series tend to have positive values that slowly decrease as the lags increase.

a10 %>%
  ACF(Cost, lag_max = 48) %>%
  autoplot()

The slow decrease in the ACF as the lags increase is due to the trend, while the “scalloped” shape is due to the seasonality.

2.9 White noise

Time series that show no autocorrelation are called white noise.

set.seed(30)
y <- tsibble(sample = 1:50, wn = rnorm(50), index = sample)
y %>% autoplot(wn) + labs(title = "White noise")

y %>%
  ACF(wn) %>%
  autoplot()

We expect each autocorrelation to be close to zero. . If one or more large spikes are outside these bounds, or if substantially more than 5% of spikes are outside these bounds, then the series is probably not white noise.

LS0tDQp0aXRsZTogIkZvcmVjYXN0aW5nOiBQcmluY2lwbGVzIGFuZCBQcmFjdGljZSAzIg0KYXV0aG9yOiAiSW50cm9kdWN0aW9uIGFuZCBQbG90cyINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazoNCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZmxvYXQ6IHRydWUNCiAgICB0b2NfY29sbGFwc2VkOiBmYWxzZQ0KICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQ0KICAgIA0KdG9jX2RlcHRoOiAzDQotLS0NCmBgYHtyfQ0KbGlicmFyeShmcHAzKQ0KYGBgDQoNCmh0dHBzOi8vcm9iamh5bmRtYW4uY29tL3NlbWluYXJzL3V3YTIwMTcvDQoNCmh0dHBzOi8vcm9iamh5bmRtYW4uY29tL3NlbWluYXJzL2lzaTIwMTl3b3Jrc2hvcC8NCg0KaHR0cHM6Ly9naXRodWIuY29tL3JvYmpoeW5kbWFuL0VUQzM1NTBTbGlkZXMvdHJlZS9mYWJsZQ0KDQpodHRwczovL2dpdGh1Yi5jb20vcnN0dWRpby1jb25mLTIwMjAvdGltZS1zZXJpZXMtZm9yZWNhc3RpbmcvYmxvYi9tYXN0ZXIvbWF0ZXJpYWxzL2xhYnMuUg0KDQpodHRwOi8vd3d3LmdyYWRhYW53ci5uZXQvDQoNCiMgR2V0dGluZyBzdGFydGVkDQoNCiMjIFdoYXQgY2FuIGJlIGZvcmVjYXN0Pw0KDQpUaGUgcHJlZGljdGFiaWxpdHkgb2YgYW4gZXZlbnQgb3IgYSBxdWFudGl0eSBkZXBlbmRzIG9uIHNldmVyYWwgZmFjdG9ycyBpbmNsdWRpbmc6DQoNCjEuIGhvdyB3ZWxsIHdlIHVuZGVyc3RhbmQgdGhlIGZhY3RvcnMgdGhhdCBjb250cmlidXRlIHRvIGl0Ow0KMi4gaG93IG11Y2ggZGF0YSBpcyBhdmFpbGFibGU7DQozLiB3aGV0aGVyIHRoZSBmb3JlY2FzdHMgY2FuIGFmZmVjdCB0aGUgdGhpbmcgd2UgYXJlIHRyeWluZyB0byBmb3JlY2FzdC4NCg0KR29vZCBmb3JlY2FzdHMgY2FwdHVyZSB0aGUgZ2VudWluZSBwYXR0ZXJucyBhbmQgcmVsYXRpb25zaGlwcyB3aGljaCBleGlzdCBpbiB0aGUgaGlzdG9yaWNhbCBkYXRhLCBidXQgZG8gbm90IHJlcGxpY2F0ZSBwYXN0IGV2ZW50cyB0aGF0IHdpbGwgbm90IG9jY3VyIGFnYWluLg0KDQpGb3JlY2FzdHMgcmFyZWx5IGFzc3VtZSB0aGF0IHRoZSBlbnZpcm9ubWVudCBpcyB1bmNoYW5naW5nLiBXaGF0IGlzIG5vcm1hbGx5IGFzc3VtZWQgaXMgdGhhdCB0aGUgd2F5IGluIHdoaWNoIHRoZSBlbnZpcm9ubWVudCBpcyBjaGFuZ2luZyB3aWxsIGNvbnRpbnVlIGludG8gdGhlIGZ1dHVyZS4NCg0KIyMgRm9yZWNhc3RpbmcsIHBsYW5uaW5nIGFuZCBnb2Fscw0KDQpUaGV5IGFyZSB0aHJlZSBkaWZmZXJlbnQgdGhpbmdzLg0KDQotICoqRm9yZWNhc3RpbmcqKjogaXMgYWJvdXQgcHJlZGljdGluZyB0aGUgZnV0dXJlIGFzIGFjY3VyYXRlbHkgYXMgcG9zc2libGUsIGdpdmVuIGFsbCBvZiB0aGUgaW5mb3JtYXRpb24gYXZhaWxhYmxlLCBpbmNsdWRpbmcgaGlzdG9yaWNhbCBkYXRhIGFuZCBrbm93bGVkZ2Ugb2YgYW55IGZ1dHVyZSBldmVudHMgdGhhdCBtaWdodCBpbXBhY3QgdGhlIGZvcmVjYXN0cy4NCg0KLSAqKkdvYWxzKio6IGFyZSB3aGF0IHlvdSB3b3VsZCBsaWtlIHRvIGhhdmUgaGFwcGVuLiBHb2FscyBzaG91bGQgYmUgbGlua2VkIHRvIGZvcmVjYXN0cyBhbmQgcGxhbnMsIGJ1dCB0aGlzIGRvZXMgbm90IGFsd2F5cyBvY2N1ci4gVG9vIG9mdGVuLCBnb2FscyBhcmUgc2V0IHdpdGhvdXQgYW55IHBsYW4gZm9yIGhvdyB0byBhY2hpZXZlIHRoZW0sIGFuZCBubyBmb3JlY2FzdHMgZm9yIHdoZXRoZXIgdGhleSBhcmUgcmVhbGlzdGljLg0KDQotICoqUGxhbm5pbmcqKjogaXMgYSByZXNwb25zZSB0byBmb3JlY2FzdHMgYW5kIGdvYWxzLiBQbGFubmluZyBpbnZvbHZlcyBkZXRlcm1pbmluZyB0aGUgYXBwcm9wcmlhdGUgYWN0aW9ucyB0aGF0IGFyZSByZXF1aXJlZCB0byBtYWtlIHlvdXIgZm9yZWNhc3RzIG1hdGNoIHlvdXIgZ29hbHMuDQoNCk1vZGVybiBvcmdhbmlzYXRpb25zIHJlcXVpcmUgKipzaG9ydC10ZXJtKiosKiptZWRpdW0tdGVybSoqIGFuZCAqKmxvbmctdGVybSoqIGZvcmVjYXN0cywgZGVwZW5kaW5nIG9uIHRoZSBzcGVjaWZpYyBhcHBsaWNhdGlvbi4NCg0KIyMgRGV0ZXJtaW5pbmcgd2hhdCB0byBmb3JlY2FzdA0KDQpJbiB0aGUgZWFybHkgc3RhZ2VzIG9mIGEgZm9yZWNhc3RpbmcgcHJvamVjdCwgZGVjaXNpb25zIG5lZWQgdG8gYmUgbWFkZSBhYm91dCB3aGF0IHNob3VsZCBiZSBmb3JlY2FzdC4gSXQgaXMgYWxzbyBuZWNlc3NhcnkgdG8gY29uc2lkZXIgdGhlIGZvcmVjYXN0aW5nIGhvcml6b24uDQoNCk9uY2UgaXQgaGFzIGJlZW4gZGV0ZXJtaW5lZCB3aGF0IGZvcmVjYXN0cyBhcmUgcmVxdWlyZWQsIGl0IGlzIHRoZW4gbmVjZXNzYXJ5IHRvIGZpbmQgb3IgY29sbGVjdCB0aGUgZGF0YSBvbiB3aGljaCB0aGUgZm9yZWNhc3RzIHdpbGwgYmUgYmFzZWQuIA0KDQojIyBGb3JlY2FzdGluZyBkYXRhIGFuZCBtZXRob2RzDQoNCklmIHRoZXJlIGFyZSBubyBkYXRhIGF2YWlsYWJsZSwgb3IgaWYgdGhlIGRhdGEgYXZhaWxhYmxlIGFyZSBub3QgcmVsZXZhbnQgdG8gdGhlIGZvcmVjYXN0cywgdGhlbiAqKnF1YWxpdGF0aXZlIGZvcmVjYXN0aW5nKiogbWV0aG9kcyBtdXN0IGJlIHVzZWQuDQoNCioqUXVhbnRpdGF0aXZlIGZvcmVjYXN0aW5nKiogY2FuIGJlIGFwcGxpZWQgd2hlbiB0d28gY29uZGl0aW9ucyBhcmUgc2F0aXNmaWVkOg0KDQotIG51bWVyaWNhbCBpbmZvcm1hdGlvbiBhYm91dCB0aGUgcGFzdCBpcyBhdmFpbGFibGU7DQotIGl0IGlzIHJlYXNvbmFibGUgdG8gYXNzdW1lIHRoYXQgc29tZSBhc3BlY3RzIG9mIHRoZSBwYXN0IHBhdHRlcm5zIHdpbGwgY29udGludWUgaW50byB0aGUgZnV0dXJlLg0KDQojIyMgVGltZSBzZXJpZXMgZm9yZWNhc3RpbmcNCg0KVGhlIHNpbXBsZXN0IHRpbWUgc2VyaWVzIGZvcmVjYXN0aW5nIG1ldGhvZHMgdXNlIG9ubHkgaW5mb3JtYXRpb24gb24gdGhlIHZhcmlhYmxlIHRvIGJlIGZvcmVjYXN0LCBhbmQgbWFrZSBubyBhdHRlbXB0IHRvIGRpc2NvdmVyIHRoZSBmYWN0b3JzIHRoYXQgYWZmZWN0IGl0cyBiZWhhdmlvdXIuIFRoZXJlZm9yZSB0aGV5IHdpbGwgZXh0cmFwb2xhdGUgdHJlbmQgYW5kIHNlYXNvbmFsIHBhdHRlcm5zLCBidXQgdGhleSBpZ25vcmUgYWxsIG90aGVyIGluZm9ybWF0aW9uIHN1Y2ggYXMgbWFya2V0aW5nIGluaXRpYXRpdmVzLCBjb21wZXRpdG9yIGFjdGl2aXR5LCBjaGFuZ2VzIGluIGVjb25vbWljIGNvbmRpdGlvbnMsIGFuZCBzbyBvbi4NCg0KIyMjIFByZWRpY3RvciB2YXJpYWJsZXMgYW5kIHRpbWUgc2VyaWVzIGZvcmVjYXN0aW5nDQoNClByZWRpY3RvciB2YXJpYWJsZXMgYXJlIG9mdGVuIHVzZWZ1bCBpbiB0aW1lIHNlcmllcyBmb3JlY2FzdGluZy4gRm9yIGV4YW1wbGUsIHN1cHBvc2Ugd2Ugd2lzaCB0byBmb3JlY2FzdCB0aGUgaG91cmx5IGVsZWN0cmljaXR5IGRlbWFuZCAoRUQpIG9mIGEgaG90IHJlZ2lvbiBkdXJpbmcgdGhlIHN1bW1lciBwZXJpb2QuIEEgbW9kZWwgd2l0aCBwcmVkaWN0b3IgdmFyaWFibGVzIG1pZ2h0IGJlIG9mIHRoZSBmb3JtDQoNClxiZWdpbnthbGlnbip9DQogIFx0ZXh0e0VEfSA9ICYgZihcdGV4dHtjdXJyZW50IHRlbXBlcmF0dXJlLCBzdHJlbmd0aCBvZiBlY29ub215LCBwb3B1bGF0aW9uLH1cXA0KICYgIFxxcXVhZFx0ZXh0e3RpbWUgb2YgZGF5LCBkYXkgb2Ygd2VlaywgZXJyb3J9KS4NClxlbmR7YWxpZ24qfQ0KDQpUaGUg4oCcZXJyb3LigJ0gdGVybSBvbiB0aGUgcmlnaHQgYWxsb3dzIGZvciByYW5kb20gdmFyaWF0aW9uIGFuZCB0aGUgZWZmZWN0cyBvZiByZWxldmFudCB2YXJpYWJsZXMgdGhhdCBhcmUgbm90IGluY2x1ZGVkIGluIHRoZSBtb2RlbC4gV2UgY2FsbCB0aGlzIGFuICoqZXhwbGFuYXRvcnkgbW9kZWwqKiBiZWNhdXNlIGl0IGhlbHBzIGV4cGxhaW4gd2hhdCBjYXVzZXMgdGhlIHZhcmlhdGlvbiBpbiBlbGVjdHJpY2l0eSBkZW1hbmQuDQoNCkJlY2F1c2UgdGhlIGVsZWN0cmljaXR5IGRlbWFuZCBkYXRhIGZvcm0gYSB0aW1lIHNlcmllcywgd2UgY291bGQgYWxzbyB1c2UgYSB0aW1lIHNlcmllcyBtb2RlbCBmb3IgZm9yZWNhc3RpbmcuIEluIHRoaXMgY2FzZSwgYSBzdWl0YWJsZSB0aW1lIHNlcmllcyBmb3JlY2FzdGluZyBlcXVhdGlvbiBpcyBvZiB0aGUgZm9ybQ0KDQpcYmVnaW57YWxpZ24qfQ0Ke0VEfV97dCsxfSA9IGYoXHRleHR7RUR9X3t0fSwgXHRleHR7RUR9X3t0LTF9LCBcdGV4dHtFRH1fe3QtMn0sIFx0ZXh0e0VEfV97dC0zfSxcZG90cywgXHRleHR7ZXJyb3J9DQpcZW5ke2FsaWduKn0NCg0KSGVyZSwgcHJlZGljdGlvbiBvZiB0aGUgZnV0dXJlIGlzIGJhc2VkIG9uIHBhc3QgdmFsdWVzIG9mIGEgdmFyaWFibGUsIGJ1dCBub3Qgb24gZXh0ZXJuYWwgdmFyaWFibGVzIHRoYXQgbWF5IGFmZmVjdCB0aGUgc3lzdGVtLiBBZ2FpbiwgdGhlIOKAnGVycm9y4oCdIHRlcm0gb24gdGhlIHJpZ2h0IGFsbG93cyBmb3IgcmFuZG9tIHZhcmlhdGlvbiBhbmQgdGhlIGVmZmVjdHMgb2YgcmVsZXZhbnQgdmFyaWFibGVzIHRoYXQgYXJlIG5vdCBpbmNsdWRlZCBpbiB0aGUgbW9kZWwuDQoNClRoZXJlIGlzIGFsc28gYSB0aGlyZCB0eXBlIG9mIG1vZGVsIHdoaWNoIGNvbWJpbmVzIHRoZSBmZWF0dXJlcyBvZiB0aGUgYWJvdmUgdHdvIG1vZGVscy4NCg0KXGJlZ2lue2FsaWduKn0NClx0ZXh0e0VEfV97dCsxfSA9IGYoXHRleHR7RUR9X3t0fSwgXHRleHR7Y3VycmVudCB0ZW1wZXJhdHVyZSwgdGltZSBvZiBkYXksIGRheSBvZiB3ZWVrLCBlcnJvcn0pLg0KXGVuZHthbGlnbip9DQoNClRoZXkgYXJlIGtub3duIGFzIGR5bmFtaWMgcmVncmVzc2lvbiBtb2RlbHMsIHBhbmVsIGRhdGEgbW9kZWxzLCBsb25naXR1ZGluYWwgbW9kZWxzLCB0cmFuc2ZlciBmdW5jdGlvbiBtb2RlbHMsIGFuZCBsaW5lYXIgc3lzdGVtIG1vZGVscyAoYXNzdW1pbmcgdGhhdCAkZiQgaXMgbGluZWFyKS4gDQoNClRoZSBtb2RlbCB0byBiZSB1c2VkIGluIGZvcmVjYXN0aW5nIGRlcGVuZHMgb24gdGhlIHJlc291cmNlcyBhbmQgZGF0YSBhdmFpbGFibGUsIHRoZSBhY2N1cmFjeSBvZiB0aGUgY29tcGV0aW5nIG1vZGVscywgYW5kIHRoZSB3YXkgaW4gd2hpY2ggdGhlIGZvcmVjYXN0aW5nIG1vZGVsIGlzIHRvIGJlIHVzZWQuDQoNCiMjIFRoZSBiYXNpYyBzdGVwcyBpbiBhIGZvcmVjYXN0aW5nIHRhc2sNCg0KIyMjIFN0ZXAgMTogUHJvYmxlbSBkZWZpbml0aW9uLg0KDQpEZWZpbmluZyB0aGUgcHJvYmxlbSBjYXJlZnVsbHkgcmVxdWlyZXMgYW4gdW5kZXJzdGFuZGluZyBvZiB0aGUgd2F5IHRoZSBmb3JlY2FzdHMgd2lsbCBiZSB1c2VkLCB3aG8gcmVxdWlyZXMgdGhlIGZvcmVjYXN0cywgYW5kIGhvdyB0aGUgZm9yZWNhc3RpbmcgZnVuY3Rpb24gZml0cyB3aXRoaW4gdGhlIG9yZ2FuaXNhdGlvbiByZXF1aXJpbmcgdGhlIGZvcmVjYXN0cy4gQSBmb3JlY2FzdGVyIG5lZWRzIHRvIHNwZW5kIHRpbWUgdGFsa2luZyB0byBldmVyeW9uZSB3aG8gd2lsbCBiZSBpbnZvbHZlZCBpbiBjb2xsZWN0aW5nIGRhdGEsIG1haW50YWluaW5nIGRhdGFiYXNlcywgYW5kIHVzaW5nIHRoZSBmb3JlY2FzdHMgZm9yIGZ1dHVyZSBwbGFubmluZy4NCg0KIyMjIFN0ZXAgMjogR2F0aGVyaW5nIGluZm9ybWF0aW9uLg0KDQpUaGVyZSBhcmUgYWx3YXlzIGF0IGxlYXN0IHR3byBraW5kcyBvZiBpbmZvcm1hdGlvbiByZXF1aXJlZDogKGEpIHN0YXRpc3RpY2FsIGRhdGEsIGFuZCAoYikgdGhlIGFjY3VtdWxhdGVkIGV4cGVydGlzZSBvZiB0aGUgcGVvcGxlIHdobyBjb2xsZWN0IHRoZSBkYXRhIGFuZCB1c2UgdGhlIGZvcmVjYXN0cy4gT2NjYXNpb25hbGx5LCBvbGQgZGF0YSB3aWxsIGJlIGxlc3MgdXNlZnVsIGR1ZSB0byBzdHJ1Y3R1cmFsIGNoYW5nZXMgaW4gdGhlIHN5c3RlbSBiZWluZyBmb3JlY2FzdDsgdGhlbiB3ZSBtYXkgY2hvb3NlIHRvIHVzZSBvbmx5IHRoZSBtb3N0IHJlY2VudCBkYXRhLiBIb3dldmVyLCByZW1lbWJlciB0aGF0IGdvb2Qgc3RhdGlzdGljYWwgbW9kZWxzIHdpbGwgaGFuZGxlIGV2b2x1dGlvbmFyeSBjaGFuZ2VzIGluIHRoZSBzeXN0ZW07IGRvbuKAmXQgdGhyb3cgYXdheSBnb29kIGRhdGEgdW5uZWNlc3NhcmlseS4NCg0KIyMjIFN0ZXAgMzogUHJlbGltaW5hcnkgKGV4cGxvcmF0b3J5KSBhbmFseXNpcy4NCg0KQWx3YXlzIHN0YXJ0IGJ5IGdyYXBoaW5nIHRoZSBkYXRhLiBBcmUgdGhlcmUgY29uc2lzdGVudCBwYXR0ZXJucz8gSXMgdGhlcmUgYSBzaWduaWZpY2FudCB0cmVuZD8gSXMgc2Vhc29uYWxpdHkgaW1wb3J0YW50PyBJcyB0aGVyZSBldmlkZW5jZSBvZiB0aGUgcHJlc2VuY2Ugb2YgYnVzaW5lc3MgY3ljbGVzPyBBcmUgdGhlcmUgYW55IG91dGxpZXJzIGluIHRoZSBkYXRhIHRoYXQgbmVlZCB0byBiZSBleHBsYWluZWQgYnkgdGhvc2Ugd2l0aCBleHBlcnQga25vd2xlZGdlPyBIb3cgc3Ryb25nIGFyZSB0aGUgcmVsYXRpb25zaGlwcyBhbW9uZyB0aGUgdmFyaWFibGVzIGF2YWlsYWJsZSBmb3IgYW5hbHlzaXM/IA0KDQojIyMgU3RlcCA0OiBDaG9vc2luZyBhbmQgZml0dGluZyBtb2RlbHMNCg0KVGhlIGJlc3QgbW9kZWwgdG8gdXNlIGRlcGVuZHMgb24gdGhlIGF2YWlsYWJpbGl0eSBvZiBoaXN0b3JpY2FsIGRhdGEsIHRoZSBzdHJlbmd0aCBvZiByZWxhdGlvbnNoaXBzIGJldHdlZW4gdGhlIGZvcmVjYXN0IHZhcmlhYmxlIGFuZCBhbnkgZXhwbGFuYXRvcnkgdmFyaWFibGVzLCBhbmQgdGhlIHdheSBpbiB3aGljaCB0aGUgZm9yZWNhc3RzIGFyZSB0byBiZSB1c2VkLiBJdCBpcyBjb21tb24gdG8gY29tcGFyZSB0d28gb3IgdGhyZWUgcG90ZW50aWFsIG1vZGVscy4gRWFjaCBtb2RlbCBpcyBpdHNlbGYgYW4gYXJ0aWZpY2lhbCBjb25zdHJ1Y3QgdGhhdCBpcyBiYXNlZCBvbiBhIHNldCBvZiBhc3N1bXB0aW9ucyAoZXhwbGljaXQgYW5kIGltcGxpY2l0KSBhbmQgdXN1YWxseSBpbnZvbHZlcyBvbmUgb3IgbW9yZSBwYXJhbWV0ZXJzIHdoaWNoIG11c3QgYmUgZXN0aW1hdGVkIHVzaW5nIHRoZSBrbm93biBoaXN0b3JpY2FsIGRhdGEuIA0KDQojIyMgU3RlcCA1OiBVc2luZyBhbmQgZXZhbHVhdGluZyBhIGZvcmVjYXN0aW5nIG1vZGVsLg0KDQpPbmNlIGEgbW9kZWwgaGFzIGJlZW4gc2VsZWN0ZWQgYW5kIGl0cyBwYXJhbWV0ZXJzIGVzdGltYXRlZCwgdGhlIG1vZGVsIGlzIHVzZWQgdG8gbWFrZSBmb3JlY2FzdHMuIFRoZSBwZXJmb3JtYW5jZSBvZiB0aGUgbW9kZWwgY2FuIG9ubHkgYmUgcHJvcGVybHkgZXZhbHVhdGVkIGFmdGVyIHRoZSBkYXRhIGZvciB0aGUgZm9yZWNhc3QgcGVyaW9kIGhhdmUgYmVjb21lIGF2YWlsYWJsZS4NCg0KIyMgVGhlIHN0YXRpc3RpY2FsIGZvcmVjYXN0aW5nIHBlcnNwZWN0aXZlDQoNClRoZSBmdXJ0aGVyIGFoZWFkIHdlIGZvcmVjYXN0LCB0aGUgbW9yZSB1bmNlcnRhaW4gd2UgYXJlLiBXaGVuIHdlIG9idGFpbiBhIGZvcmVjYXN0LCB3ZSBhcmUgZXN0aW1hdGluZyB0aGUgbWlkZGxlIG9mIHRoZSByYW5nZSBvZiBwb3NzaWJsZSB2YWx1ZXMgdGhlIHJhbmRvbSB2YXJpYWJsZSBjb3VsZCB0YWtlLiBPZnRlbiwgYSBmb3JlY2FzdCBpcyBhY2NvbXBhbmllZCBieSBhIHByZWRpY3Rpb24gaW50ZXJ2YWwgZ2l2aW5nIGEgcmFuZ2Ugb2YgdmFsdWVzIHRoZSByYW5kb20gdmFyaWFibGUgY291bGQgdGFrZSB3aXRoIHJlbGF0aXZlbHkgaGlnaCBwcm9iYWJpbGl0eS4gDQoNCiR5X3QkIHdpbGwgZGVub3RlIHRoZSBvYnNlcnZhdGlvbiBhdCB0aW1lICp0Kg0KDQpTdXBwb3NlIHdlIGRlbm90ZSBhbGwgdGhlIGluZm9ybWF0aW9uIHdlIGhhdmUgb2JzZXJ2ZWQgYXMgJFxtYXRoY2Fse0l9JCBhbmQgd2Ugd2FudCB0byBmb3JlY2FzdCAkeV90JC4gV2UgdGhlbiB3cml0ZSAgJHlfe3R9IHxcbWF0aGNhbHtJfSQgbWVhbmluZyDigJx0aGUgcmFuZG9tIHZhcmlhYmxlICR5X3QkIGdpdmVuIHdoYXQgd2Uga25vdyBpbiAkXG1hdGhjYWx7SX0kLuKAnSBUaGUgc2V0IG9mIHZhbHVlcyB0aGF0IHRoaXMgcmFuZG9tIHZhcmlhYmxlIGNvdWxkIHRha2UsIGFsb25nIHdpdGggdGhlaXIgcmVsYXRpdmUgcHJvYmFiaWxpdGllcywgaXMga25vd24gYXMgdGhlIOKAnHByb2JhYmlsaXR5IGRpc3RyaWJ1dGlvbuKAnSBvZiAgJHlfe3R9IHxcbWF0aGNhbHtJfSQgLiBJbiBmb3JlY2FzdGluZywgd2UgY2FsbCB0aGlzIHRoZSAqKmZvcmVjYXN0IGRpc3RyaWJ1dGlvbioqLg0KDQpXaGVuIHdlIHRhbGsgYWJvdXQgdGhlIOKAnGZvcmVjYXN0LOKAnSB3ZSB1c3VhbGx5IG1lYW4gdGhlIGF2ZXJhZ2UgdmFsdWUgb2YgdGhlIGZvcmVjYXN0IGRpc3RyaWJ1dGlvbiwgYW5kIHdlIHB1dCBhIOKAnGhhdOKAnSBvdmVyICR5JCB0byBzaG93IHRoaXMgKCRcaGF0e3l9X3QkKS4NCg0KIyBUaW1lIHNlcmllcyBncmFwaGljcw0KDQojIyB0c2liYmxlIG9iamVjdHMNCg0KaHR0cHM6Ly9vdGV4dHMuY29tL2ZwcDMvdHNpYmJsZXMuaHRtbA0KDQp0c2liYmxlIG9iamVjdHMgZXh0ZW5kIHRpZHkgZGF0YSBmcmFtZXMgKHRpYmJsZSBvYmplY3RzKSBieSBpbnRyb2R1Y2luZyB0ZW1wb3JhbCBzdHJ1Y3R1cmUuDQoNCmBgYHtyfQ0KeSA8LSB0c2liYmxlKFllYXIgPSAyMDE1OjIwMTksIE9ic2VydmF0aW9uID0gYygxMjMsIDM5LCA3OCwgNTIsIDExMCksIGluZGV4ID0gWWVhcikNCmBgYA0KV2UgaGF2ZSBzZXQgdGhlIHRpbWUgc2VyaWVzIGluZGV4IHRvIGJlIHRoZSBZZWFyIGNvbHVtbiwgd2hpY2ggYXNzb2NpYXRlcyB0aGUgbWVhc3VyZW1lbnRzIChPYnNlcnZhdGlvbikgd2l0aCB0aGUgdGltZSBvZiByZWNvcmRpbmcgKFllYXIpLg0KDQpGb3Igb2JzZXJ2YXRpb25zIHRoYXQgYXJlIG1vcmUgZnJlcXVlbnQgdGhhbiBvbmNlIHBlciB5ZWFyLCB3ZSBuZWVkIHRvIHVzZSBhIHRpbWUgY2xhc3MgZnVuY3Rpb24gb24gdGhlIGluZGV4Lg0KDQojIyBUaW1lIHBsb3RzDQoNCmBgYHtyfQ0KbWVsc3lkX2Vjb25vbXkgPC0gYW5zZXR0ICU+JQ0KICBmaWx0ZXIoQWlycG9ydHMgPT0gIk1FTC1TWUQiLCBDbGFzcyA9PSAiRWNvbm9teSIpDQphdXRvcGxvdChtZWxzeWRfZWNvbm9teSwgUGFzc2VuZ2VycykgKw0KICBsYWJzKHRpdGxlID0gIkFuc2V0dCBlY29ub215IGNsYXNzIHBhc3NlbmdlcnMiLA0KICAgICAgIHN1YnRpdGxlID0gIk1lbGJvdXJuZS1TeWRuZXkiKQ0KYGBgDQpUaGUgdGltZSBwbG90IGltbWVkaWF0ZWx5IHJldmVhbHMgc29tZSBpbnRlcmVzdGluZyBmZWF0dXJlcy4NCg0KLSBUaGVyZSB3YXMgYSBwZXJpb2QgaW4gMTk4OSB3aGVuIG5vIHBhc3NlbmdlcnMgd2VyZSBjYXJyaWVkIOKAlCB0aGlzIHdhcyBkdWUgdG8gYW4gaW5kdXN0cmlhbCBkaXNwdXRlLg0KLSBUaGVyZSB3YXMgYSBwZXJpb2Qgb2YgcmVkdWNlZCBsb2FkIGluIDE5OTIuIFRoaXMgd2FzIGR1ZSB0byBhIHRyaWFsIGluIHdoaWNoIHNvbWUgZWNvbm9teSBjbGFzcyBzZWF0cyB3ZXJlIHJlcGxhY2VkIGJ5IGJ1c2luZXNzIGNsYXNzIHNlYXRzLg0KLSBBIGxhcmdlIGluY3JlYXNlIGluIHBhc3NlbmdlciBsb2FkIG9jY3VycmVkIGluIHRoZSBzZWNvbmQgaGFsZiBvZiAxOTkxLg0KVGhlcmUgYXJlIHNvbWUgbGFyZ2UgZGlwcyBpbiBsb2FkIGFyb3VuZCB0aGUgc3RhcnQgb2YgZWFjaCB5ZWFyLiBUaGVzZSBhcmUgZHVlIHRvIGhvbGlkYXkgZWZmZWN0cy4NCi0gVGhlcmUgaXMgYSBsb25nLXRlcm0gZmx1Y3R1YXRpb24gaW4gdGhlIGxldmVsIG9mIHRoZSBzZXJpZXMgd2hpY2ggaW5jcmVhc2VzIGR1cmluZyAxOTg3LCBkZWNyZWFzZXMgaW4gMTk4OSwgYW5kIGluY3JlYXNlcyBhZ2FpbiB0aHJvdWdoIDE5OTAgYW5kIDE5OTEuDQotIFRoZXJlIGFyZSBzb21lIHBlcmlvZHMgb2YgbWlzc2luZyBvYnNlcnZhdGlvbnMuDQoNCmBgYHtyfQ0KUEJTICU+JQ0KICBmaWx0ZXIoQVRDMiA9PSAiQTEwIikgJT4lDQogIHNlbGVjdChNb250aCwgQ29uY2Vzc2lvbiwgVHlwZSwgQ29zdCkgJT4lDQogIHN1bW1hcmlzZShUb3RhbEMgPSBzdW0oQ29zdCkpICU+JQ0KICBtdXRhdGUoQ29zdCA9IFRvdGFsQyAvIDFlNikgLT4gYTEwDQoNCmF1dG9wbG90KGExMCwgQ29zdCkgKw0KICBsYWJzKHkgPSAiJCBtaWxsaW9uIiwgdGl0bGUgPSAiQW50aWRpYWJldGljIGRydWcgc2FsZXMiKQ0KYGBgDQpIZXJlLCB0aGVyZSBpcyBhIGNsZWFyIGFuZCBpbmNyZWFzaW5nIHRyZW5kLiBUaGVyZSBpcyBhbHNvIGEgc3Ryb25nIHNlYXNvbmFsIHBhdHRlcm4gdGhhdCBpbmNyZWFzZXMgaW4gc2l6ZSBhcyB0aGUgbGV2ZWwgb2YgdGhlIHNlcmllcyBpbmNyZWFzZXMuIFRoZSBzdWRkZW4gZHJvcCBhdCB0aGUgc3RhcnQgb2YgZWFjaCB5ZWFyIGlzIGNhdXNlZCBieSBhIGdvdmVybm1lbnQgc3Vic2lkaXNhdGlvbiBzY2hlbWUgdGhhdCBtYWtlcyBpdCBjb3N0LWVmZmVjdGl2ZSBmb3IgcGF0aWVudHMgdG8gc3RvY2twaWxlIGRydWdzIGF0IHRoZSBlbmQgb2YgdGhlIGNhbGVuZGFyIHllYXIuIEFueSBmb3JlY2FzdHMgb2YgdGhpcyBzZXJpZXMgd291bGQgbmVlZCB0byBjYXB0dXJlIHRoZSBzZWFzb25hbCBwYXR0ZXJuLCBhbmQgdGhlIGZhY3QgdGhhdCB0aGUgdHJlbmQgaXMgY2hhbmdpbmcgc2xvd2x5Lg0KDQojIyBUaW1lIHNlcmllcyBwYXR0ZXJucw0KDQotICoqVHJlbmQqKjogQSB0cmVuZCBleGlzdHMgd2hlbiB0aGVyZSBpcyBhIGxvbmctdGVybSBpbmNyZWFzZSBvciBkZWNyZWFzZSBpbiB0aGUgZGF0YS4gU29tZXRpbWVzIHdlIHdpbGwgcmVmZXIgdG8gYSB0cmVuZCBhcyDigJxjaGFuZ2luZyBkaXJlY3Rpb24s4oCdIHdoZW4gaXQgbWlnaHQgZ28gZnJvbSBhbiBpbmNyZWFzaW5nIHRyZW5kIHRvIGEgZGVjcmVhc2luZyB0cmVuZC4NCg0KLSAqKlNlYXNvbmFsKio6IEEgc2Vhc29uYWwgcGF0dGVybiBvY2N1cnMgd2hlbiBhIHRpbWUgc2VyaWVzIGlzIGFmZmVjdGVkIGJ5IHNlYXNvbmFsIGZhY3RvcnMgc3VjaCBhcyB0aGUgdGltZSBvZiB0aGUgeWVhciBvciB0aGUgZGF5IG9mIHRoZSB3ZWVrLiBTZWFzb25hbGl0eSBpcyBhbHdheXMgb2YgYSBmaXhlZCBhbmQga25vd24gcGVyaW9kLg0KDQotICoqQ3ljbGljKio6IEEgY3ljbGUgb2NjdXJzIHdoZW4gdGhlIGRhdGEgZXhoaWJpdCByaXNlcyBhbmQgZmFsbHMgdGhhdCBhcmUgbm90IG9mIGEgZml4ZWQgZnJlcXVlbmN5LiBUaGVzZSBmbHVjdHVhdGlvbnMgYXJlIHVzdWFsbHkgZHVlIHRvIGVjb25vbWljIGNvbmRpdGlvbnMsIGFuZCBhcmUgb2Z0ZW4gcmVsYXRlZCB0byB0aGUg4oCcYnVzaW5lc3MgY3ljbGUu4oCdDQoNCiMjIFNlYXNvbmFsIHBsb3RzDQoNCmBgYHtyfQ0KYTEwICU+JQ0KICBnZ19zZWFzb24oQ29zdCwgbGFiZWxzID0gImJvdGgiKSArDQogIGxhYnMoeSA9ICIkIG1pbGxpb24iLA0KICAgICAgIHRpdGxlID0gIlNlYXNvbmFsIHBsb3Q6IGFudGlkaWFiZXRpYyBkcnVnIHNhbGVzIikNCmBgYA0KSXQgaXMgY2xlYXIgdGhhdCB0aGVyZSBpcyBhIGxhcmdlIGp1bXAgaW4gc2FsZXMgaW4gSmFudWFyeSBlYWNoIHllYXIuIEFjdHVhbGx5LCB0aGVzZSBhcmUgcHJvYmFibHkgc2FsZXMgaW4gbGF0ZSBEZWNlbWJlciBhcyBjdXN0b21lcnMgc3RvY2twaWxlIGJlZm9yZSB0aGUgZW5kIG9mIHRoZSBjYWxlbmRhciB5ZWFyLCBidXQgdGhlIHNhbGVzIGFyZSBub3QgcmVnaXN0ZXJlZCB3aXRoIHRoZSBnb3Zlcm5tZW50IHVudGlsIGEgd2VlayBvciB0d28gbGF0ZXIuIFRoZSBncmFwaCBhbHNvIHNob3dzIHRoYXQgdGhlcmUgd2FzIGFuIHVudXN1YWxseSBzbWFsbCBudW1iZXIgb2Ygc2FsZXMgaW4gTWFyY2ggMjAwOCAobW9zdCBvdGhlciB5ZWFycyBzaG93IGFuIGluY3JlYXNlIGJldHdlZW4gRmVicnVhcnkgYW5kIE1hcmNoKS4gVGhlIHNtYWxsIG51bWJlciBvZiBzYWxlcyBpbiBKdW5lIDIwMDggaXMgcHJvYmFibHkgZHVlIHRvIGluY29tcGxldGUgY291bnRpbmcgb2Ygc2FsZXMgYXQgdGhlIHRpbWUgdGhlIGRhdGEgd2VyZSBjb2xsZWN0ZWQuDQoNCiMjIyBNdWx0aXBsZSBzZWFzb25hbCBwZXJpb2RzDQoNCldoZXJlIHRoZSBkYXRhIGhhcyBtb3JlIHRoYW4gb25lIHNlYXNvbmFsIHBhdHRlcm4sIHRoZSBwZXJpb2QgYXJndW1lbnQgY2FuIGJlIHVzZWQgdG8gc2VsZWN0IHdoaWNoIHNlYXNvbmFsIHBsb3QgaXMgcmVxdWlyZWQuIA0KYGBge3J9DQp2aWNfZWxlYyAlPiUgZ2dfc2Vhc29uKERlbWFuZCwgcGVyaW9kID0gImRheSIpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KYGBgDQpgYGB7cn0NCnZpY19lbGVjICU+JSBnZ19zZWFzb24oRGVtYW5kLCBwZXJpb2QgPSAid2VlayIpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KYGBgDQpgYGB7cn0NCnZpY19lbGVjICU+JSBnZ19zZWFzb24oRGVtYW5kLCBwZXJpb2QgPSAieWVhciIpDQpgYGANCiMjIFNlYXNvbmFsIHN1YnNlcmllcyBwbG90cw0KDQpgYGB7cn0NCmExMCAlPiUNCiAgZ2dfc3Vic2VyaWVzKENvc3QpICsNCiAgbGFicyh5ID0gIiQgbWlsbGlvbiIsDQogICAgICAgdGl0bGUgPSAiU2Vhc29uYWwgc3Vic2VyaWVzIHBsb3Q6IGFudGlkaWFiZXRpYyBkcnVnIHNhbGVzIikNCmBgYA0KVGhlIGJsdWUgaG9yaXpvbnRhbCBsaW5lcyBpbmRpY2F0ZSB0aGUgbWVhbnMgZm9yIGVhY2ggbW9udGguIFRoaXMgZm9ybSBvZiBwbG90IGVuYWJsZXMgdGhlIHVuZGVybHlpbmcgc2Vhc29uYWwgcGF0dGVybiB0byBiZSBzZWVuIGNsZWFybHksIGFuZCBhbHNvIHNob3dzIHRoZSBjaGFuZ2VzIGluIHNlYXNvbmFsaXR5IG92ZXIgdGltZS4gSXQgaXMgZXNwZWNpYWxseSB1c2VmdWwgaW4gaWRlbnRpZnlpbmcgY2hhbmdlcyB3aXRoaW4gcGFydGljdWxhciBzZWFzb25zLiBJbiB0aGlzIGV4YW1wbGUsIHRoZSBwbG90IGlzIG5vdCBwYXJ0aWN1bGFybHkgcmV2ZWFsaW5nOyBidXQgaW4gc29tZSBjYXNlcywgdGhpcyBpcyB0aGUgbW9zdCB1c2VmdWwgd2F5IG9mIHZpZXdpbmcgc2Vhc29uYWwgY2hhbmdlcyBvdmVyIHRpbWUuDQoNCiMjIyBFeGFtcGxlOiBBdXN0cmFsaWFuIGhvbGlkYXkgdG91cmlzbQ0KDQp0b3RhbCB2aXNpdG9yIG5pZ2h0cyBzcGVudCBvbiBIb2xpZGF5IGJ5IFN0YXRlIGZvciBlYWNoIHF1YXJ0ZXIgDQpgYGB7cn0NCmhvbGlkYXlzIDwtIHRvdXJpc20gJT4lDQogIGZpbHRlcihQdXJwb3NlID09ICJIb2xpZGF5IikgJT4lDQogIGdyb3VwX2J5KFN0YXRlKSAlPiUNCiAgc3VtbWFyaXNlKFRyaXBzID0gc3VtKFRyaXBzKSkNCg0KaGVhZChob2xpZGF5cykNCmBgYA0KU3Ryb25nIHNlYXNvbmFsaXR5IGZvciBtb3N0IHN0YXRlcyBidXQgc2Vhc29uYWwgcGVha3MgZG8gbm90IGNvaW5jaWRlLg0KYGBge3J9DQphdXRvcGxvdChob2xpZGF5cywgVHJpcHMpICsNCiAgbGFicyh5ID0gInRob3VzYW5kcyBvZiB0cmlwcyIsDQogICAgICAgdGl0bGUgPSAiQXVzdHJhbGlhbiBkb21lc3RpYyBob2xpZGF5IG5pZ2h0cyIpDQpgYGANClNvdXRoZXJuIHN0YXRlcyBvZiBBdXN0cmFsaWEgKFRhc21hbmlhLCBWaWN0b3JpYSBhbmQgU291dGggQXVzdHJhbGlhKSBoYXZlIHN0cm9uZ2VzdCB0b3VyaXNtIGluIFExICh0aGVpciBzdW1tZXIpLCB3aGlsZSB0aGUgbm9ydGhlcm4gc3RhdGVzIChRdWVlbnNsYW5kIGFuZCB0aGUgTm9ydGhlcm4gVGVycml0b3J5KSBoYXZlIHRoZSBzdHJvbmdlc3QgdG91cmlzbSBpbiBRMyAodGhlaXIgZHJ5IHNlYXNvbikuDQpgYGB7ciB3YXJuaW5nPUZBTFNFfQ0KZ2dfc2Vhc29uKGhvbGlkYXlzLCBUcmlwcykgKw0KICBsYWJzKHkgPSAidGhvdXNhbmRzIG9mIHRyaXBzIiwNCiAgICAgICB0aXRsZSA9ICJBdXN0cmFsaWFuIGRvbWVzdGljIGhvbGlkYXkgbmlnaHRzIikNCmBgYA0KQ29ycmVzcG9uZGluZyBzdWJzZXJpZXMgcGxvdHM6DQpgYGB7cn0NCmhvbGlkYXlzICU+JQ0KICBnZ19zdWJzZXJpZXMoVHJpcHMpICsNCiAgbGFicyh5ID0gInRob3VzYW5kcyBvZiB0cmlwcyIsDQogICAgICAgdGl0bGUgPSAiQXVzdHJhbGlhbiBkb21lc3RpYyBob2xpZGF5IG5pZ2h0cyIpDQpgYGANCiMjIFNjYXR0ZXJwbG90cw0KDQpFeHBsb3JlIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiB0aW1lIHNlcmllcy4NCmBgYHtyfQ0KdmljX2VsZWMgJT4lDQogIGZpbHRlcih5ZWFyKFRpbWUpID09IDIwMTQpICU+JQ0KICBhdXRvcGxvdChEZW1hbmQpICsNCiAgbGFicyh5ID0gIkRlbWFuZCAoR1cpIiwNCiAgICAgICB0aXRsZSA9ICJIYWxmLWhvdXJseSBlbGVjdHJpY2l0eSBkZW1hbmQ6IFZpY3RvcmlhLCBBdXN0cmFsaWEiKQ0KYGBgDQpgYGB7cn0NCnZpY19lbGVjICU+JQ0KICBmaWx0ZXIoeWVhcihUaW1lKSA9PSAyMDE0KSAlPiUNCiAgYXV0b3Bsb3QoVGVtcGVyYXR1cmUpICsNCiAgbGFicyh5ID0gIlRlbXBlcmF0dXJlIChkZWdyZWVzIENlbHNpdXMpIiwNCiAgICAgICB0aXRsZSA9ICJIYWxmLWhvdXJseSB0ZW1wZXJhdHVyZXM6IE1lbGJvdXJuZSwgQXVzdHJhbGlhIikNCmBgYA0KV2UgY2FuIHN0dWR5IHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBkZW1hbmQgYW5kIHRlbXBlcmF0dXJlIGJ5IHBsb3R0aW5nIG9uZSBzZXJpZXMgYWdhaW5zdCB0aGUgb3RoZXIuDQpgYGB7cn0NCnZpY19lbGVjICU+JQ0KICBmaWx0ZXIoeWVhcihUaW1lKSA9PSAyMDE0KSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gVGVtcGVyYXR1cmUsIHkgPSBEZW1hbmQpKSArDQogIGdlb21fcG9pbnQoKSArDQogIGxhYnMoeSA9ICJEZW1hbmQgKEdXKSIsIHggPSAiVGVtcGVyYXR1cmUgKGRlZ3JlZXMgQ2Vsc2l1cykiKQ0KYGBgDQpJdCBpcyBjbGVhciB0aGF0IGhpZ2ggZGVtYW5kIG9jY3VycyB3aGVuIHRlbXBlcmF0dXJlcyBhcmUgaGlnaCBkdWUgdG8gdGhlIGVmZmVjdCBvZiBhaXItY29uZGl0aW9uaW5nLiBCdXQgdGhlcmUgaXMgYWxzbyBhIGhlYXRpbmcgZWZmZWN0LCB3aGVyZSBkZW1hbmQgaW5jcmVhc2VzIGZvciB2ZXJ5IGxvdyB0ZW1wZXJhdHVyZXMuDQoNCiMjIyBDb3JyZWxhdGlvbg0KDQpDb3JyZWxhdGlvbiBjb2VmZmljaWVudHMgdG8gbWVhc3VyZSB0aGUgc3RyZW5ndGggb2YgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHR3byB2YXJpYWJsZXMuDQoNClxiZWdpbnthbGlnbip9DQpyID0gXGZyYWN7XHN1bSAoeF97dH0gLSBcYmFye3h9KSh5X3t0fS1cYmFye3l9KX17XHNxcnR7XHN1bSh4X3t0fS1cYmFye3h9KV4yfVxzcXJ0e1xzdW0oeV97dH0tXGJhcnt5fSleMn19Lg0KXGVuZHthbGlnbip9DQoNClRoZSB2YWx1ZSBvZiAkciQgYWx3YXlzIGxpZXMgYmV0d2VlbiAk4oiSMSQgYW5kICQxJCB3aXRoIG5lZ2F0aXZlIHZhbHVlcyBpbmRpY2F0aW5nIGEgbmVnYXRpdmUgcmVsYXRpb25zaGlwIGFuZCBwb3NpdGl2ZSB2YWx1ZXMgaW5kaWNhdGluZyBhIHBvc2l0aXZlIHJlbGF0aW9uc2hpcC4gDQoNCiMjIyBTY2F0dGVycGxvdCBtYXRyaWNlcw0KDQpXaGVuIHRoZXJlIGFyZSBzZXZlcmFsIHBvdGVudGlhbCBwcmVkaWN0b3IgdmFyaWFibGVzLCBpdCBpcyB1c2VmdWwgdG8gcGxvdCBlYWNoIHZhcmlhYmxlIGFnYWluc3QgZWFjaCBvdGhlciB2YXJpYWJsZS4gDQpgYGB7cn0NCnZpc2l0b3JzIDwtIHRvdXJpc20gJT4lDQogIGdyb3VwX2J5KFN0YXRlKSAlPiUNCiAgc3VtbWFyaXNlKFRyaXBzID0gc3VtKFRyaXBzKSkNCnZpc2l0b3JzICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBRdWFydGVyLCB5ID0gVHJpcHMpKSArDQogIGdlb21fbGluZSgpICsNCiAgZmFjZXRfZ3JpZCh2YXJzKFN0YXRlKSwgc2NhbGVzID0gImZyZWVfeSIpICsNCiAgbGFicyh5ID0gIk51bWJlciBvZiB2aXNpdG9yIG5pZ2h0cyBlYWNoIHF1YXJ0ZXIgKG1pbGxpb25zKSIpDQpgYGANCmBgYHtyIG1lc3NhZ2U9RkFMU0V9DQp2aXNpdG9ycyAlPiUNCiAgcGl2b3Rfd2lkZXIodmFsdWVzX2Zyb209VHJpcHMsIG5hbWVzX2Zyb209U3RhdGUpICU+JQ0KICBHR2FsbHk6OmdncGFpcnMoY29sdW1ucyA9IDI6OSkNCmBgYA0KSW4gdGhpcyBleGFtcGxlLCBtb3N0bHkgcG9zaXRpdmUgcmVsYXRpb25zaGlwcyBhcmUgcmV2ZWFsZWQsIHdpdGggdGhlIHN0cm9uZ2VzdCByZWxhdGlvbnNoaXBzIGJlaW5nIGJldHdlZW4gdGhlIG5laWdoYm9yaW5nIHN0YXRlcyBsb2NhdGVkIGluIHRoZSBzb3V0aCBhbmQgc291dGggZWFzdCBjb2FzdCBvZiBBdXN0cmFsaWEsIG5hbWVseSwgTmV3IFNvdXRoIFdhbGVzLCBWaWN0b3JpYSBhbmQgU291dGggQXVzdHJhbGlhLiBTb21lIG5lZ2F0aXZlIHJlbGF0aW9uc2hpcHMgYXJlIGFsc28gcmV2ZWFsZWQgYmV0d2VlbiB0aGUgTm9ydGhlcm4gVGVycml0b3J5IGFuZCBvdGhlciByZWdpb25zLiBUaGUgTm9ydGhlcm4gVGVycml0b3J5IGlzIGxvY2F0ZWQgaW4gdGhlIG5vcnRoIG9mIEF1c3RyYWxpYSBmYW1vdXMgZm9yIGl0cyBvdXRiYWNrIGRlc2VydCBsYW5kc2NhcGVzIHZpc2l0ZWQgbW9zdGx5IGluIHdpbnRlci4gSGVuY2UsIHRoZSBwZWFrIHZpc2l0YXRpb24gaW4gdGhlIE5vcnRoZXJuIFRlcnJpdG9yeSBpcyBpbiB0aGUgSnVseSAod2ludGVyKSBxdWFydGVyIGluIGNvbnRyYXN0IHRvIEphbnVhcnkgKHN1bW1lcikgcXVhcnRlciBmb3IgdGhlIHJlc3Qgb2YgdGhlIHJlZ2lvbnMuDQoNCiMjIExhZyBwbG90cw0KDQpob3Jpem9udGFsIGF4aXMgc2hvd3MgbGFnZ2VkIHZhbHVlcyBvZiB0aGUgdGltZSBzZXJpZXMuIEVhY2ggZ3JhcGggc2hvd3MgJHlfdCQgcGxvdHRlZCBhZ2FpbnN0ICR5X3t04oiSa30kIGZvciBkaWZmZXJlbnQgdmFsdWVzIG9mICRrJC4NCg0KYGBge3J9DQpyZWNlbnRfcHJvZHVjdGlvbiA8LSBhdXNfcHJvZHVjdGlvbiAlPiUNCiAgZmlsdGVyKHllYXIoUXVhcnRlcikgPj0gMjAwMCkNCnJlY2VudF9wcm9kdWN0aW9uICU+JSBnZ19sYWcoQmVlciwgZ2VvbSA9ICJwb2ludCIpDQpgYGANClRoZSByZWxhdGlvbnNoaXAgaXMgc3Ryb25nbHkgcG9zaXRpdmUgYXQgbGFncyA0IGFuZCA4LCByZWZsZWN0aW5nIHRoZSBzdHJvbmcgc2Vhc29uYWxpdHkgaW4gdGhlIGRhdGEuDQoNCiMjIEF1dG9jb3JyZWxhdGlvbg0KDQpBdXRvY29ycmVsYXRpb24gbWVhc3VyZXMgdGhlIGxpbmVhciByZWxhdGlvbnNoaXAgYmV0d2VlbiBsYWdnZWQgdmFsdWVzIG9mIGEgdGltZSBzZXJpZXMuDQoNClxiZWdpbnthbGlnbip9DQpyX3trfSA9IFxmcmFje1xzdW1cbGltaXRzX3t0PWsrMX1eVCAoeV97dH0tXGJhcnt5fSkoeV97dC1rfS1cYmFye3l9KX0NCiB7XHN1bVxsaW1pdHNfe3Q9MX1eVCAoeV97dH0tXGJhcnt5fSleMn0sDQpcZW5ke2FsaWduKn0NCiANClRoZSBhdXRvY29ycmVsYXRpb24gY29lZmZpY2llbnRzIG1ha2UgdXAgdGhlIGF1dG9jb3JyZWxhdGlvbiBmdW5jdGlvbiBvciBBQ0YuDQpgYGB7cn0NCnJlY2VudF9wcm9kdWN0aW9uICU+JSBBQ0YoQmVlciwgbGFnX21heCA9IDkpDQpgYGANCldlIHVzdWFsbHkgcGxvdCB0aGUgQUNGIHRvIHNlZSBob3cgdGhlIGNvcnJlbGF0aW9ucyBjaGFuZ2Ugd2l0aCB0aGUgbGFnICRrJC4gVGhlIHBsb3QgaXMgc29tZXRpbWVzIGtub3duIGFzIGEgY29ycmVsb2dyYW0uDQogDQpgYGB7cn0NCnJlY2VudF9wcm9kdWN0aW9uICU+JQ0KICBBQ0YoQmVlcikgJT4lDQogIGF1dG9wbG90KCkNCmBgYA0KLSAkcl80JCBpcyBoaWdoZXIgdGhhbiBmb3IgdGhlIG90aGVyIGxhZ3MuIFRoaXMgaXMgZHVlIHRvIHRoZSBzZWFzb25hbCBwYXR0ZXJuIGluIHRoZSBkYXRhOiB0aGUgcGVha3MgdGVuZCB0byBiZSBmb3VyIHF1YXJ0ZXJzIGFwYXJ0IGFuZCB0aGUgdHJvdWdocyB0ZW5kIHRvIGJlIGZvdXIgcXVhcnRlcnMgYXBhcnQuDQotICRyXzIkIGlzIG1vcmUgbmVnYXRpdmUgdGhhbiBmb3IgdGhlIG90aGVyIGxhZ3MgYmVjYXVzZSB0cm91Z2hzIHRlbmQgdG8gYmUgdHdvIHF1YXJ0ZXJzIGJlaGluZCBwZWFrcy4NCi0gVGhlIGRhc2hlZCBibHVlIGxpbmVzIGluZGljYXRlIHdoZXRoZXIgdGhlIGNvcnJlbGF0aW9ucyBhcmUgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnQgZnJvbSB6ZXJvLiANCg0KIyMjIFRyZW5kIGFuZCBzZWFzb25hbGl0eSBpbiBBQ0YgcGxvdHMNCg0KV2hlbiBkYXRhIGhhdmUgYSB0cmVuZCwgdGhlIGF1dG9jb3JyZWxhdGlvbnMgZm9yIHNtYWxsIGxhZ3MgdGVuZCB0byBiZSBsYXJnZSBhbmQgcG9zaXRpdmUgYmVjYXVzZSBvYnNlcnZhdGlvbnMgbmVhcmJ5IGluIHRpbWUgYXJlIGFsc28gbmVhcmJ5IGluIHNpemUuIFNvIHRoZSBBQ0Ygb2YgdHJlbmRlZCB0aW1lIHNlcmllcyB0ZW5kIHRvIGhhdmUgcG9zaXRpdmUgdmFsdWVzIHRoYXQgc2xvd2x5IGRlY3JlYXNlIGFzIHRoZSBsYWdzIGluY3JlYXNlLg0KDQpgYGB7cn0NCmExMCAlPiUNCiAgQUNGKENvc3QsIGxhZ19tYXggPSA0OCkgJT4lDQogIGF1dG9wbG90KCkNCmBgYA0KVGhlIHNsb3cgZGVjcmVhc2UgaW4gdGhlIEFDRiBhcyB0aGUgbGFncyBpbmNyZWFzZSBpcyBkdWUgdG8gdGhlIHRyZW5kLCB3aGlsZSB0aGUg4oCcc2NhbGxvcGVk4oCdIHNoYXBlIGlzIGR1ZSB0byB0aGUgc2Vhc29uYWxpdHkuDQoNCiMjIFdoaXRlIG5vaXNlDQoNClRpbWUgc2VyaWVzIHRoYXQgc2hvdyBubyBhdXRvY29ycmVsYXRpb24gYXJlIGNhbGxlZCB3aGl0ZSBub2lzZS4NCmBgYHtyfQ0Kc2V0LnNlZWQoMzApDQp5IDwtIHRzaWJibGUoc2FtcGxlID0gMTo1MCwgd24gPSBybm9ybSg1MCksIGluZGV4ID0gc2FtcGxlKQ0KeSAlPiUgYXV0b3Bsb3Qod24pICsgbGFicyh0aXRsZSA9ICJXaGl0ZSBub2lzZSIpDQpgYGANCmBgYHtyfQ0KeSAlPiUNCiAgQUNGKHduKSAlPiUNCiAgYXV0b3Bsb3QoKQ0KYGBgDQpXZSBleHBlY3QgZWFjaCBhdXRvY29ycmVsYXRpb24gdG8gYmUgY2xvc2UgdG8gemVyby4gLiBJZiBvbmUgb3IgbW9yZSBsYXJnZSBzcGlrZXMgYXJlIG91dHNpZGUgdGhlc2UgYm91bmRzLCBvciBpZiBzdWJzdGFudGlhbGx5IG1vcmUgdGhhbiA1JSBvZiBzcGlrZXMgYXJlIG91dHNpZGUgdGhlc2UgYm91bmRzLCB0aGVuIHRoZSBzZXJpZXMgaXMgcHJvYmFibHkgbm90IHdoaXRlIG5vaXNlLg==