List of abbreviations

Abbreviation Description
ACF Autocorrelation function
GWh Gigawatt hour
ILR Institut Luxembourgeois de Régulation
IQR Interquartile Range
MAD Mean absolute deviation
MSD Mean squared deviation
Q1 First quartile
Q3 Third quartile
Var Variance
sd Standard deviation

1 Introduction

This document presents the analysis of residential gas consumption data in Luxembourg.

2 Data sources

The analysis hereafter is based on two data sources with the following characteristics.

Data source Producer URL Format
Monthly residential gas consumption in Luxembourg Institut Luxembourgeois de Régulation (ILR) https://data.public.lu/en/datasets/donnees-statistiques-du-secteur-de-gaz-naturel-ilr/ .xlsx
Monthly mean air temperature in Luxembourg MeteoLux https://data.public.lu/en/datasets/inspire-annex-iii-meteorological-geographical-features-pointtimeseriesobservation-monthly-weather-measurements-at-luxembourg-findel-airport-1/ .gml

For conciseness, the details of data download, import and tidying are not discussed here. If you are interested, you can use the R code from GitHub to download, import, and tidy the data.

3 Data description

For our analysis, we are only interested in the monthly residential gas consumption in GWh. Note that the raw data has two other types of gas consumption (industrial consumption and production/co-generation).

We use tsibble objects as they are specifically designed for time series analysis. A tsibble is a special kind of tibble.

After downloading, importing, and tidying the data, the resulting tsibble, named df is shown below.

We observe that:

  • There are 93 rows and 3 columns
  • The interval (time step) is 1 month (month column)
  • There are two time series:
    • Monthly residential gas consumption in GWh (consumption_gwh column)
    • Monthly average temperature in degrees Celcius (temp_celcius column)

Although the first 10 rows are displayed, the month column contains 8 years.

unique(year(df$month))
## [1] 2017 2018 2019 2020 2021 2022 2023 2024

Furthermore, we observe that the time series:

  • starts at Jan-2017
  • ends at Sep-2024
  • has 0 gaps

Next, we perform an exploratory data analysis to understand the patterns in the data.

4 Exploratory data analysis

4.1 Desriptive statistics

The following descriptive statistics are computed for the monthly temperature in Celcius.

Statistic Value
n 93.0
min -1.6
q1 4.9
mean 10.8
median 10.0
q3 16.7
max 22.1

For the residential gas consumption in GWh, we compute a more comprehensive list of statistics.

consumption_gwh_stats <- df |>
  as_tibble() |>
  summarise(
    n = n(),
    sum = sum(consumption_gwh),
    min = min(consumption_gwh),
    q1 = quantile(consumption_gwh, 0.25),
    mean = mean(consumption_gwh),
    median = median(consumption_gwh),
    q3 = quantile(consumption_gwh, 0.75),
    max = max(consumption_gwh),
    var = var(consumption_gwh),
    sd = sd(consumption_gwh),
    skewness = skewness(consumption_gwh),
    kurtosis = kurtosis(consumption_gwh),
    IQR = IQR(consumption_gwh),
    MAD = mad(consumption_gwh, center = mean(consumption_gwh)),
    MSD = mean((consumption_gwh - mean(consumption_gwh))^2)
  ) |>
  pivot_longer(everything(),
    names_to = "Statistic",
    values_to = "Value"
  ) |>
  mutate(Value = round(Value, 2))


kbl(consumption_gwh_stats) |>
  kable_styling(bootstrap_options = "striped",
                full_width = FALSE,
                position = "center")
Statistic Value
n 93.00
sum 21212.76
min 32.47
q1 172.14
mean 228.09
median 225.09
q3 309.17
max 416.42
var 10287.68
sd 101.43
skewness -0.16
kurtosis 2.17
IQR 137.03
MAD 102.52
MSD 10177.06

We observe that:

  • The total residential gas consumption was 21,212.76 GWh.
  • The average monthly residential gas consumption is 228.09 GWh.

4.2 Histograms

Let us examine the distribution of the data.

4.3 Density plots

We observe that both distributions are bimodal. The temperature distribution has a more pronounced bimodal feature.

4.4 Boxplots

One simple yet effective method to detect outliers graphically is the boxplot. These are the boxplots for our two variables.

The lower and upper hinges correspond to the first and third quartiles (the 25th and 75th percentiles). The line between the hinges corresponds to the median. The upper whisker extends from the hinge to the largest value no further than 1.5 * IQR from the hinge. IQR is the distance between the first and third quartiles. The lower whisker extends from the hinge to the smallest value at most 1.5 * IQR of the hinge. Data beyond the end of the whiskers are called “outliers” and are plotted individually.

We observe that both distributions do not contain any outliers.

4.5 Time plots

Perhaps the most useful data visualization when it comes to time series is the time plot. Here is the time plot for our data.

The time plot of the gas consumption (upper plot) immediately reveals some interesting features.

  • Peaks happen in the winter.
  • Low points happen in the summer.
  • There is a decreasing trend.
  • The seasonal pattern increases in size as the level of the series increases. This causes the variance to increase over time and it is also known as heteroskedasticity.

The spikes during the winter months are probably caused due to household gas heating. Similarly, the low points in the summer could be due to the reduced need for household gas heating.

The time plot of the mean monthly temperature (lower plot) exhibits the opposite pattern.

  • Peaks happen in the summer
  • Low points happen in the winter.
  • There is a flat trend.
  • The data appears to be homoskedastic.

Both time series have a strong seasonal pattern.

4.6 Seasonal plots

A seasonal plot is similar to a time plot except that the data are plotted against the individual month in which the data were observed.

In addition to the observations made by the time plot, we observe that:

  • February and March 2018 have a higher gas consumption than the same months in other years.
  • February 2024 has a lower gas consumption than the same month in other years.
  • There are two “clusters” of curves. The first cluster has 2017 to 2021 curves and the second cluster has 2022 to 2024 curves. The curves of the second cluster are below than the curves of the first cluster, from April to November. This could be explained by the higher-than-usual residential gas prices observed from 2022 until

The higher-than-usual gas consumption in February and March 2018 is most likely explained by the low mean temperature during these months, as observed in the graph below.

4.7 Seasonal subseries plot

An alternative plot that emphasizes the seasonal patterns is where the data for each season are collected together in separate mini time plots. The blue horizontal lines indicate the means for each month. The x-axis indicates the year.

We observe that the pattern is similar between months, except from January.

We do not detect any clear pattern in this seasonal subseries graph.

Up until now, we have observed each time series individually. This is also called a univariate analysis. Next, we will look at how these time series behave together. This is also called a multivariate analysis.

4.8 Scatterplot

Let us visualize the data points of gas consumption and mean temperature together. The most common plot for this task is the scatterplot, as shown below. A linear fit is also plotted.

As expected, we observe a negative correlation between mean temperature and gas consumption. We also observe that the upper left corner (low temperature, high consumption) has data points closer to the linear regression line. In contrast, the lower right corner (high temperature, low consumption) has data points scattered away from the linear regression line.

The correlation coefficient measures the strength of the linear relationship between mean temperature and gas consumption. For this data, the correlation coefficient is -0.85.

As shown below, the correlation test indicates that the correlation coefficient is significantly different than zero.

cor.test(df$consumption_gwh, df$temp_celcius, method = "pearson",
         alternative = "two.sided", conf.level = 0.95)
## 
##  Pearson's product-moment correlation
## 
## data:  df$consumption_gwh and df$temp_celcius
## t = -15.48, df = 91, p-value < 2.2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  -0.8991106 -0.7834962
## sample estimates:
##        cor 
## -0.8513285

4.9 Lag plots

The figure below displays scatterplots where the horizontal axis shows lagged values (k) of the time series. Each graph shows
monthly gas consumption data points plotted against themselves at different lags.

df |>
  gg_lag(consumption_gwh, geom = "point", lags = 1:12) +
  labs(
    x = "lag(gas consumption in GWh, k)",
    y = "Gas consumption in GWh",
    color = "Month"
  ) +
  theme_minimal()

The colors indicate the month of the variable on the vertical axis. The relationship is strongly positive at lags 1 and 12, reflecting the strong seasonality in the data. The negative relationship seen for lag 6 occurs because peaks of gas consumption (in the winther) are plotted against troughs (in the summer).

4.10 Autocorrelation

Just as correlation measures the extent of a linear relationship between two variables, autocorrelation measures the linear relationship between lagged values of a time series.

There are several autocorrelation coefficients, corresponding to each panel in the lag plot above.

The autocorrelation coefficients make up the autocorrelation function or ACF.

df |>
  ACF(consumption_gwh, lag_max = 48) |>
  autoplot() +
  labs(
    title = "ACF plot: Monthly gas consumption in GWh",
    x = "Lag in months",
    y = "ACF"
  ) +
  theme_minimal()

In this graph:

  • The autocorrelation coefficients at lag 1, 12, 24, etc. (denoted \(r_1\), \(r_{12}\), and \(r_{24}\) respectively) are high. This is due to the seasonal pattern in the data: the peaks tend to be 12 months apart and the low points tend to also be 12 months apart.
  • The dashed blue lines indicate whether the correlations are significantly different from zero. If an autocorrelation coefficient lies outside the blue bound, it is significantly different from zero.

4.11 Box-Cox transformation

For more details, please refer to (Hyndman & Athanasopoulos, 2021).

lambda <- df |>
  features(consumption_gwh, features = guerrero) |>
  pull(lambda_guerrero)

The optimal lambda for variance stabilization is 1.73.

4.12 Time series decomposition

dcmp <- df |>
  model(stl = STL(consumption_gwh)) |>
  components()

dcmp

4.13 Trend and seasonal strength

Feature Monthly gas consumption in GWh Monthly mean temperature in Celcius
trend_strength 0.8324117 0.1722841
seasonal_strength_year 0.9463735 0.9527928
seasonal_peak_year 1 7
seasonal_trough_year 8 1
spikiness 51.265714290 0.001106719
linearity -394.9711522 0.3238554
curvature -100.9533782 -0.1425342
stl_e_acf1 0.3120111 -0.1448544
stl_e_acf10 0.6141027 0.2663283

References

Hyndman, R. J., & Athanasopoulos, G. (2021). Forecasting: Principles and Practice (3rd ed.). https://OTexts.com/fpp3; OTexts: Melbourne, Australia.
LS0tCnRpdGxlOiAiQW5hbHlzaXMgb2YgcmVzaWRlbnRpYWwgZ2FzIGNvbnN1bXB0aW9uIGRhdGEgaW4gTHV4ZW1ib3VyZyIKYXV0aG9yOiAiQ2hyaXN0b3MgQXZyaWxpb25pcyIKZGF0ZTogIjIwMjUtMTEtMjQiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OiAKICAgIGFuY2hvcl9zZWN0aW9uczogZmFsc2UKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IGZhbHNlCiAgICAgIHNtb290aF9zY3JvbGw6IHRydWUKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIGNvZGVfZm9sZGluZzogbm9uZQogICAgY3NzOiBzdHlsZS5jc3MKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgZmlnX3dpZHRoOiA5CiAgICBmaWdfY2FwdGlvbjogZmFsc2UKICAgIGRmX3ByaW50OiBwYWdlZApiaWJsaW9ncmFwaHk6IHJlZmVyZW5jZXMuYmliCmNzbDogYXBhLmNzbAplZGl0b3Jfb3B0aW9uczogCiAgbWFya2Rvd246IAogICAgd3JhcDogNzIKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZSA9IEZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpCgpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMoewogIGxpYnJhcnkodGlkeXZlcnNlKQogIGxpYnJhcnkoZ3JpZEV4dHJhKQogIGxpYnJhcnkobW9tZW50cykKICBsaWJyYXJ5KGZhYmxlKQogIGxpYnJhcnkoZmFibGV0b29scykKICBsaWJyYXJ5KGZlYXN0cykKICBsaWJyYXJ5KGdncmVwZWwpCiAgbGlicmFyeShsYXRleDJleHApCiAgbGlicmFyeShrYWJsZUV4dHJhKQp9KQpgYGAKCiFbXSguLy4uL3d3dy90aGVybW9zdGF0LmpwZyl7LmNlbnRlci1pbWFnZX0KCioqTGlzdCBvZiBhYmJyZXZpYXRpb25zKioKCmBgYHtyIGFiYnJldmlhdGlvbnMsIGVjaG89RkFMU0V9CgphYmJyIDwtIHJlYWRfZGVsaW0oIi4vLi4vZGF0YS9hYmJyZXZpYXRpb25zLmNzdiIsCiAgICAgICAgICAgICAgICAgICBkZWxpbSA9ICJ8IiwKICAgICAgICAgICAgICAgICAgIGNvbF9uYW1lcyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICBzaG93X2NvbF90eXBlcyA9IEZBTFNFKSB8PgogIGFycmFuZ2UoQWJicmV2aWF0aW9uKQoKa2JsKGFiYnIpIHw+CiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9ICJzdHJpcGVkIiwKICAgICAgICAgICAgICAgIGZ1bGxfd2lkdGggPSBGQUxTRSwKICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gImNlbnRlciIpCmBgYAoKIyMgSW50cm9kdWN0aW9uCgpUaGlzIGRvY3VtZW50IHByZXNlbnRzIHRoZSBhbmFseXNpcyBvZiByZXNpZGVudGlhbCBnYXMgY29uc3VtcHRpb24gZGF0YQppbiBMdXhlbWJvdXJnLgoKIyMgRGF0YSBzb3VyY2VzCgpUaGUgYW5hbHlzaXMgaGVyZWFmdGVyIGlzIGJhc2VkIG9uIHR3byBkYXRhIHNvdXJjZXMgd2l0aCB0aGUgZm9sbG93aW5nCmNoYXJhY3RlcmlzdGljcy4KCnwgRGF0YSBzb3VyY2UgfCBQcm9kdWNlciB8IFVSTCB8IEZvcm1hdCB8CnwtLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tfAp8IE1vbnRobHkgcmVzaWRlbnRpYWwgZ2FzIGNvbnN1bXB0aW9uIGluIEx1eGVtYm91cmcgfCAqSW5zdGl0dXQgTHV4ZW1ib3VyZ2VvaXMgZGUgUsOpZ3VsYXRpb24gKElMUikqIHwgPGh0dHBzOi8vZGF0YS5wdWJsaWMubHUvZW4vZGF0YXNldHMvZG9ubmVlcy1zdGF0aXN0aXF1ZXMtZHUtc2VjdGV1ci1kZS1nYXotbmF0dXJlbC1pbHIvPiB8IC54bHN4IHwKfCBNb250aGx5IG1lYW4gYWlyIHRlbXBlcmF0dXJlIGluIEx1eGVtYm91cmcgfCBNZXRlb0x1eCB8IDxodHRwczovL2RhdGEucHVibGljLmx1L2VuL2RhdGFzZXRzL2luc3BpcmUtYW5uZXgtaWlpLW1ldGVvcm9sb2dpY2FsLWdlb2dyYXBoaWNhbC1mZWF0dXJlcy1wb2ludHRpbWVzZXJpZXNvYnNlcnZhdGlvbi1tb250aGx5LXdlYXRoZXItbWVhc3VyZW1lbnRzLWF0LWx1eGVtYm91cmctZmluZGVsLWFpcnBvcnQtMS8+IHwgLmdtbCB8CgpGb3IgY29uY2lzZW5lc3MsIHRoZSBkZXRhaWxzIG9mIGRhdGEgZG93bmxvYWQsIGltcG9ydCBhbmQgdGlkeWluZyBhcmUKbm90IGRpc2N1c3NlZCBoZXJlLiBJZiB5b3UgYXJlIGludGVyZXN0ZWQsIHlvdSBjYW4gdXNlIHRoZSBSIGNvZGUgZnJvbQpbR2l0SHViXShodHRwczovL2dpdGh1Yi5jb20vY2F2cmlsaW9uaXMvbHUtZ2FzLWFuYWx5c2lzL2Jsb2IvbWFpbi9SKSB0bwpkb3dubG9hZCwgaW1wb3J0LCBhbmQgdGlkeSB0aGUgZGF0YS4KCmBgYHtyIGRvd25sb2FkX2RhdGEsIGluY2x1ZGUgPSBGQUxTRX0Kc291cmNlKCIwMS1kb3dubG9hZF9kYXRhLlIiKQpgYGAKCmBgYHtyIGltcG9ydF9kYXRhLCBpbmNsdWRlID0gRkFMU0V9CnNvdXJjZSgiMDItaW1wb3J0LWRhdGEuUiIpCmBgYAoKIyMgRGF0YSBkZXNjcmlwdGlvbgoKRm9yIG91ciBhbmFseXNpcywgd2UgYXJlIG9ubHkgaW50ZXJlc3RlZCBpbiB0aGUgbW9udGhseSByZXNpZGVudGlhbCBnYXMKY29uc3VtcHRpb24gaW4gR1doLiBOb3RlIHRoYXQgdGhlIHJhdyBkYXRhIGhhcyB0d28gb3RoZXIgdHlwZXMgb2YgZ2FzCmNvbnN1bXB0aW9uIChpbmR1c3RyaWFsIGNvbnN1bXB0aW9uIGFuZCBwcm9kdWN0aW9uL2NvLWdlbmVyYXRpb24pLgoKV2UgdXNlIGB0c2liYmxlYCBvYmplY3RzIGFzIHRoZXkgYXJlIHNwZWNpZmljYWxseSBkZXNpZ25lZCBmb3IgdGltZQpzZXJpZXMgYW5hbHlzaXMuIEEgYHRzaWJibGVgIGlzIGEgc3BlY2lhbCBraW5kIG9mIGB0aWJibGVgLgoKQWZ0ZXIgZG93bmxvYWRpbmcsIGltcG9ydGluZywgYW5kIHRpZHlpbmcgdGhlIGRhdGEsIHRoZSByZXN1bHRpbmcKYHRzaWJibGVgLCBuYW1lZCBgZGZgIGlzIHNob3duIGJlbG93LgoKYGBge3IgcHJpbnRfZGYsIGVjaG8gPSBGQUxTRX0KZGYKYGBgCgpXZSBvYnNlcnZlIHRoYXQ6CgotICAgVGhlcmUgYXJlIGByIG5yb3coZGYpYCByb3dzIGFuZCBgciBuY29sKGRmKWAgY29sdW1ucwotICAgVGhlIGludGVydmFsICh0aW1lIHN0ZXApIGlzIDEgbW9udGggKGBtb250aGAgY29sdW1uKQotICAgVGhlcmUgYXJlIHR3byB0aW1lIHNlcmllczoKICAgIC0gICBNb250aGx5IHJlc2lkZW50aWFsIGdhcyBjb25zdW1wdGlvbiBpbiBHV2ggKGBjb25zdW1wdGlvbl9nd2hgCiAgICAgICAgY29sdW1uKQogICAgLSAgIE1vbnRobHkgYXZlcmFnZSB0ZW1wZXJhdHVyZSBpbiBkZWdyZWVzIENlbGNpdXMgKGB0ZW1wX2NlbGNpdXNgCiAgICAgICAgY29sdW1uKQoKQWx0aG91Z2ggdGhlIGZpcnN0IDEwIHJvd3MgYXJlIGRpc3BsYXllZCwgdGhlIGBtb250aGAgY29sdW1uIGNvbnRhaW5zCmByIGxlbmd0aCh1bmlxdWUoeWVhcihkZiRtb250aCkpKWAgeWVhcnMuCgpgYGB7ciB1bmlxdWVfbW9udGhzfQp1bmlxdWUoeWVhcihkZiRtb250aCkpCmBgYAoKRnVydGhlcm1vcmUsIHdlIG9ic2VydmUgdGhhdCB0aGUgdGltZSBzZXJpZXM6CgotICAgc3RhcnRzIGF0IGByIGZvcm1hdChtaW4oZGYkbW9udGgpLCAiJWItJVkiKWAKLSAgIGVuZHMgYXQgYHIgZm9ybWF0KG1heChkZiRtb250aCksICIlYi0lWSIpYAotICAgaGFzIGByIG5yb3coY291bnRfZ2FwcyhkZikpYCBnYXBzCgpOZXh0LCB3ZSBwZXJmb3JtIGFuIGV4cGxvcmF0b3J5IGRhdGEgYW5hbHlzaXMgdG8gdW5kZXJzdGFuZCB0aGUgcGF0dGVybnMKaW4gdGhlIGRhdGEuCgojIyBFeHBsb3JhdG9yeSBkYXRhIGFuYWx5c2lzCgojIyMgRGVzcmlwdGl2ZSBzdGF0aXN0aWNzCgpUaGUgZm9sbG93aW5nIGRlc2NyaXB0aXZlIHN0YXRpc3RpY3MgYXJlIGNvbXB1dGVkIGZvciB0aGUgbW9udGhseQp0ZW1wZXJhdHVyZSBpbiBDZWxjaXVzLgoKYGBge3Igc3RhdHNfdGVtcF9jZWxjaXVzLCBlY2hvID0gRkFMU0V9CnRlbXBfY2VsY2l1c19zdGF0cyA8LSBkZiB8PgogIGFzX3RpYmJsZSgpIHw+CiAgc3VtbWFyaXNlKAogICAgbiA9IG4oKSwKICAgIG1pbiA9IG1pbih0ZW1wX2NlbGNpdXMpLAogICAgcTEgPSBxdWFudGlsZSh0ZW1wX2NlbGNpdXMsIDAuMjUpLAogICAgbWVhbiA9IG1lYW4odGVtcF9jZWxjaXVzKSwKICAgIG1lZGlhbiA9IG1lZGlhbih0ZW1wX2NlbGNpdXMpLAogICAgcTMgPSBxdWFudGlsZSh0ZW1wX2NlbGNpdXMsIDAuNzUpLAogICAgbWF4ID0gbWF4KHRlbXBfY2VsY2l1cykKICApIHw+CiAgcGl2b3RfbG9uZ2VyKGV2ZXJ5dGhpbmcoKSwKICAgIG5hbWVzX3RvID0gIlN0YXRpc3RpYyIsCiAgICB2YWx1ZXNfdG8gPSAiVmFsdWUiCiAgKSB8PgogIG11dGF0ZShWYWx1ZSA9IHJvdW5kKFZhbHVlLCAxKSkKCmtibCh0ZW1wX2NlbGNpdXNfc3RhdHMpIHw+CiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9ICJzdHJpcGVkIiwKICAgICAgICAgICAgICAgIGZ1bGxfd2lkdGggPSBGQUxTRSwKICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gImNlbnRlciIpCmBgYAoKRm9yIHRoZSByZXNpZGVudGlhbCBnYXMgY29uc3VtcHRpb24gaW4gR1doLCB3ZSBjb21wdXRlIGEgbW9yZQpjb21wcmVoZW5zaXZlIGxpc3Qgb2Ygc3RhdGlzdGljcy4KCmBgYHtyIHN0YXRzX2NvbnN1bXB0aW9uX2d3aH0KY29uc3VtcHRpb25fZ3doX3N0YXRzIDwtIGRmIHw+CiAgYXNfdGliYmxlKCkgfD4KICBzdW1tYXJpc2UoCiAgICBuID0gbigpLAogICAgc3VtID0gc3VtKGNvbnN1bXB0aW9uX2d3aCksCiAgICBtaW4gPSBtaW4oY29uc3VtcHRpb25fZ3doKSwKICAgIHExID0gcXVhbnRpbGUoY29uc3VtcHRpb25fZ3doLCAwLjI1KSwKICAgIG1lYW4gPSBtZWFuKGNvbnN1bXB0aW9uX2d3aCksCiAgICBtZWRpYW4gPSBtZWRpYW4oY29uc3VtcHRpb25fZ3doKSwKICAgIHEzID0gcXVhbnRpbGUoY29uc3VtcHRpb25fZ3doLCAwLjc1KSwKICAgIG1heCA9IG1heChjb25zdW1wdGlvbl9nd2gpLAogICAgdmFyID0gdmFyKGNvbnN1bXB0aW9uX2d3aCksCiAgICBzZCA9IHNkKGNvbnN1bXB0aW9uX2d3aCksCiAgICBza2V3bmVzcyA9IHNrZXduZXNzKGNvbnN1bXB0aW9uX2d3aCksCiAgICBrdXJ0b3NpcyA9IGt1cnRvc2lzKGNvbnN1bXB0aW9uX2d3aCksCiAgICBJUVIgPSBJUVIoY29uc3VtcHRpb25fZ3doKSwKICAgIE1BRCA9IG1hZChjb25zdW1wdGlvbl9nd2gsIGNlbnRlciA9IG1lYW4oY29uc3VtcHRpb25fZ3doKSksCiAgICBNU0QgPSBtZWFuKChjb25zdW1wdGlvbl9nd2ggLSBtZWFuKGNvbnN1bXB0aW9uX2d3aCkpXjIpCiAgKSB8PgogIHBpdm90X2xvbmdlcihldmVyeXRoaW5nKCksCiAgICBuYW1lc190byA9ICJTdGF0aXN0aWMiLAogICAgdmFsdWVzX3RvID0gIlZhbHVlIgogICkgfD4KICBtdXRhdGUoVmFsdWUgPSByb3VuZChWYWx1ZSwgMikpCgoKa2JsKGNvbnN1bXB0aW9uX2d3aF9zdGF0cykgfD4KICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gInN0cmlwZWQiLAogICAgICAgICAgICAgICAgZnVsbF93aWR0aCA9IEZBTFNFLAogICAgICAgICAgICAgICAgcG9zaXRpb24gPSAiY2VudGVyIikKYGBgCgpXZSBvYnNlcnZlIHRoYXQ6CgotICAgVGhlIHRvdGFsIHJlc2lkZW50aWFsIGdhcyBjb25zdW1wdGlvbiB3YXMKICAgIGByIGNvbnN1bXB0aW9uX2d3aF9zdGF0cyB8PiBmaWx0ZXIoU3RhdGlzdGljID09ICJzdW0iKSB8PiBwdWxsKFZhbHVlKSB8PiBmb3JtYXQoYmlnLm1hcmsgPSAiLCIsIHNjaWVudGlmaWMgPSBGQUxTRSlgCiAgICBHV2guCi0gICBUaGUgYXZlcmFnZSBtb250aGx5IHJlc2lkZW50aWFsIGdhcyBjb25zdW1wdGlvbiBpcwogICAgYHIgY29uc3VtcHRpb25fZ3doX3N0YXRzIHw+IGZpbHRlcihTdGF0aXN0aWMgPT0gIm1lYW4iKSB8PiBwdWxsKFZhbHVlKSB8PiByb3VuZCgyKWAKICAgIEdXaC4KCiMjIyBIaXN0b2dyYW1zCgpMZXQgdXMgZXhhbWluZSB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBkYXRhLgoKYGBge3IgaGlzdG9ncmFtcywgZWNobyA9IEZBTFNFfQpid19jb25zIDwtIDIgKiBJUVIoZGYkY29uc3VtcHRpb25fZ3doKSAvIGxlbmd0aChkZiRjb25zdW1wdGlvbl9nd2gpXigxIC8gMykKCnAxIDwtIGdncGxvdChkZiwgYWVzKHggPSBjb25zdW1wdGlvbl9nd2gpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSBid19jb25zLCBmaWxsID0gImxpZ2h0Z3JleSIsIGNvbG9yID0gImdyZXkzNSIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnMoCiAgICB4ID0gIk1vbnRobHkgZ2FzIGNvbnN1bXB0aW9uIGluIEdXaCIsCiAgICB5ID0gIkZyZXF1ZW5jeSIKICApCgpid190ZW1wIDwtIDIgKiBJUVIoZGYkdGVtcF9jZWxjaXVzKSAvIGxlbmd0aChkZiR0ZW1wX2NlbGNpdXMpXigxIC8gMykKCnAyIDwtIGdncGxvdChkZiwgYWVzKHggPSB0ZW1wX2NlbGNpdXMpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSBid190ZW1wLCBmaWxsID0gImxpZ2h0Z3JleSIsIGNvbG9yID0gImdyZXkzNSIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnMoCiAgICB4ID0gIk1lYW4gbW9udGhseSB0ZW1wZXJhdHVyZSBpbiBkZWdyZWVzIENlbGNpdXMiLAogICAgeSA9ICJGcmVxdWVuY3kiCiAgKQoKZ3JpZC5hcnJhbmdlKHAxLCBwMiwgbmNvbCA9IDIpCmBgYAoKIyMjIERlbnNpdHkgcGxvdHMKCmBgYHtyLCBkZW5zaXR5X3Bsb3RzLCBlY2hvID0gRkFMU0V9CnAxIDwtIGdncGxvdChkZiwgYWVzKHggPSBjb25zdW1wdGlvbl9nd2gpKSArCiAgZ2VvbV9kZW5zaXR5KGZpbGwgPSAibGlnaHRncmV5IiwgY29sb3IgPSAibGlnaHRncmV5IikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgbGFicygKICAgIHggPSAiTW9udGhseSBnYXMgY29uc3VtcHRpb24gaW4gR1doIiwKICAgIHkgPSBOVUxMCiAgKSArCiAgdGhlbWUoCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHBhbmVsLmdyaWQubWlub3IueSA9IGVsZW1lbnRfYmxhbmsoKQogICkKCnAyIDwtIGdncGxvdChkZiwgYWVzKHggPSB0ZW1wX2NlbGNpdXMpKSArCiAgZ2VvbV9kZW5zaXR5KGZpbGwgPSAibGlnaHRncmV5IiwgY29sb3IgPSAibGlnaHRncmV5IikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgbGFicygKICAgIHggPSAiTWVhbiBtb250aGx5IHRlbXBlcmF0dXJlIGluIGRlZ3JlZXMgQ2VsY2l1cyIsCiAgICB5ID0gTlVMTAogICkgKwogIHRoZW1lKAogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICBwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICBwYW5lbC5ncmlkLm1pbm9yLnkgPSBlbGVtZW50X2JsYW5rKCkKICApCgpncmlkLmFycmFuZ2UocDEsIHAyLCBuY29sID0gMikKYGBgCgpXZSBvYnNlcnZlIHRoYXQgYm90aCBkaXN0cmlidXRpb25zIGFyZSBiaW1vZGFsLiBUaGUgdGVtcGVyYXR1cmUKZGlzdHJpYnV0aW9uIGhhcyBhIG1vcmUgcHJvbm91bmNlZCBiaW1vZGFsIGZlYXR1cmUuCgojIyMgQm94cGxvdHMKCk9uZSBzaW1wbGUgeWV0IGVmZmVjdGl2ZSBtZXRob2QgdG8gZGV0ZWN0IG91dGxpZXJzIGdyYXBoaWNhbGx5IGlzIHRoZQpib3hwbG90LiBUaGVzZSBhcmUgdGhlIGJveHBsb3RzIGZvciBvdXIgdHdvIHZhcmlhYmxlcy4KCmBgYHtyIGJveHBsb3RzLCBlY2hvID0gRkFMU0UsIGZpZy5oZWlnaHQ9Mn0KcDEgPC0gZ2dwbG90KGRmLCBhZXMoeCA9IGNvbnN1bXB0aW9uX2d3aCkpICsKICBnZW9tX2JveHBsb3Qob3V0bGllcnMgPSBUUlVFKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZSgKICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuZ3JpZC5taW5vci55ID0gZWxlbWVudF9ibGFuaygpCiAgKSArCiAgbGFicyh4ID0gIk1vbnRobHkgZ2FzIGNvbnN1bXB0aW9uIGluIEdXaCIsIHRpdGxlID0gTlVMTCkKCnAyIDwtIGdncGxvdChkZiwgYWVzKHggPSB0ZW1wX2NlbGNpdXMpKSArCiAgZ2VvbV9ib3hwbG90KG91dGxpZXJzID0gVFJVRSkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHBhbmVsLmdyaWQubWlub3IueSA9IGVsZW1lbnRfYmxhbmsoKQogICkgKwogIGxhYnMoeCA9ICJNZWFuIG1vbnRobHkgdGVtcGVyYXR1cmUgaW4gZGVncmVlcyBDZWxjaXVzIiwgdGl0bGUgPSBOVUxMKQoKZ3JpZC5hcnJhbmdlKHAxLCBwMiwgbmNvbCA9IDIpCmBgYAoKVGhlIGxvd2VyIGFuZCB1cHBlciBoaW5nZXMgY29ycmVzcG9uZCB0byB0aGUgZmlyc3QgYW5kIHRoaXJkIHF1YXJ0aWxlcwoodGhlIDI1dGggYW5kIDc1dGggcGVyY2VudGlsZXMpLiBUaGUgbGluZSBiZXR3ZWVuIHRoZSBoaW5nZXMgY29ycmVzcG9uZHMKdG8gdGhlIG1lZGlhbi4gVGhlIHVwcGVyIHdoaXNrZXIgZXh0ZW5kcyBmcm9tIHRoZSBoaW5nZSB0byB0aGUgbGFyZ2VzdAp2YWx1ZSBubyBmdXJ0aGVyIHRoYW4gMS41IFwqIElRUiBmcm9tIHRoZSBoaW5nZS4gSVFSIGlzIHRoZSBkaXN0YW5jZQpiZXR3ZWVuIHRoZSBmaXJzdCBhbmQgdGhpcmQgcXVhcnRpbGVzLiBUaGUgbG93ZXIgd2hpc2tlciBleHRlbmRzIGZyb20KdGhlIGhpbmdlIHRvIHRoZSBzbWFsbGVzdCB2YWx1ZSBhdCBtb3N0IDEuNSBcKiBJUVIgb2YgdGhlIGhpbmdlLiBEYXRhCmJleW9uZCB0aGUgZW5kIG9mIHRoZSB3aGlza2VycyBhcmUgY2FsbGVkICJvdXRsaWVycyIgYW5kIGFyZSBwbG90dGVkCmluZGl2aWR1YWxseS4KCldlIG9ic2VydmUgdGhhdCBib3RoIGRpc3RyaWJ1dGlvbnMgZG8gbm90IGNvbnRhaW4gYW55IG91dGxpZXJzLgoKIyMjIFRpbWUgcGxvdHMKClBlcmhhcHMgdGhlIG1vc3QgdXNlZnVsIGRhdGEgdmlzdWFsaXphdGlvbiB3aGVuIGl0IGNvbWVzIHRvIHRpbWUgc2VyaWVzCmlzIHRoZSB0aW1lIHBsb3QuIEhlcmUgaXMgdGhlIHRpbWUgcGxvdCBmb3Igb3VyIGRhdGEuCgpgYGB7ciB0aW1lX3Bsb3RzLCBlY2hvID0gRkFMU0UsIGZpZy5oZWlnaHQgPSA3fQpwMSA8LSBkZiB8PgogIGF1dG9wbG90KGNvbnN1bXB0aW9uX2d3aCkgKwogIGxhYnMoCiAgICB4ID0gIk1vbnRoIiwKICAgIHkgPSBOVUxMLAogICAgdGl0bGUgPSAiTW9udGhseSBnYXMgY29uc3VtcHRpb24gaW4gR1doIgogICkgKwogIHlsaW0oMCwgTkEpICsKICB0aGVtZV9taW5pbWFsKCkKCnAyIDwtIGRmIHw+CiAgYXV0b3Bsb3QodGVtcF9jZWxjaXVzKSArCiAgbGFicygKICAgIHggPSAiTW9udGgiLAogICAgeSA9IE5VTEwsCiAgICB0aXRsZSA9ICJNZWFuIG1vbnRobHkgdGVtcGVyYXR1cmUgaW4gZGVncmVlcyBDZWxjaXVzIgogICkgKwogIHRoZW1lX21pbmltYWwoKQoKZ3JpZC5hcnJhbmdlKHAxLCBwMiwgbnJvdyA9IDIsIG5jb2wgPSAxKQpgYGAKClRoZSB0aW1lIHBsb3Qgb2YgdGhlIGdhcyBjb25zdW1wdGlvbiAodXBwZXIgcGxvdCkgaW1tZWRpYXRlbHkgcmV2ZWFscwpzb21lIGludGVyZXN0aW5nIGZlYXR1cmVzLgoKLSAgIFBlYWtzIGhhcHBlbiBpbiB0aGUgd2ludGVyLgotICAgTG93IHBvaW50cyBoYXBwZW4gaW4gdGhlIHN1bW1lci4KLSAgIFRoZXJlIGlzIGEgZGVjcmVhc2luZyB0cmVuZC4KLSAgIFRoZSBzZWFzb25hbCBwYXR0ZXJuIGluY3JlYXNlcyBpbiBzaXplIGFzIHRoZSBsZXZlbCBvZiB0aGUgc2VyaWVzCiAgICBpbmNyZWFzZXMuIFRoaXMgY2F1c2VzIHRoZSB2YXJpYW5jZSB0byBpbmNyZWFzZSBvdmVyIHRpbWUgYW5kIGl0IGlzCiAgICBhbHNvIGtub3duIGFzCiAgICBbaGV0ZXJvc2tlZGFzdGljaXR5XShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Ib21vc2NlZGFzdGljaXR5X2FuZF9oZXRlcm9zY2VkYXN0aWNpdHkpLgoKVGhlIHNwaWtlcyBkdXJpbmcgdGhlIHdpbnRlciBtb250aHMgYXJlIHByb2JhYmx5IGNhdXNlZCBkdWUgdG8gaG91c2Vob2xkCmdhcyBoZWF0aW5nLiBTaW1pbGFybHksIHRoZSBsb3cgcG9pbnRzIGluIHRoZSBzdW1tZXIgY291bGQgYmUgZHVlIHRvIHRoZQpyZWR1Y2VkIG5lZWQgZm9yIGhvdXNlaG9sZCBnYXMgaGVhdGluZy4KClRoZSB0aW1lIHBsb3Qgb2YgdGhlIG1lYW4gbW9udGhseSB0ZW1wZXJhdHVyZSAobG93ZXIgcGxvdCkgZXhoaWJpdHMgdGhlCm9wcG9zaXRlIHBhdHRlcm4uCgotICAgUGVha3MgaGFwcGVuIGluIHRoZSBzdW1tZXIKLSAgIExvdyBwb2ludHMgaGFwcGVuIGluIHRoZSB3aW50ZXIuCi0gICBUaGVyZSBpcyBhIGZsYXQgdHJlbmQuCi0gICBUaGUgZGF0YSBhcHBlYXJzIHRvIGJlIGhvbW9za2VkYXN0aWMuCgpCb3RoIHRpbWUgc2VyaWVzIGhhdmUgYSBzdHJvbmcgc2Vhc29uYWwgcGF0dGVybi4KCiMjIyBTZWFzb25hbCBwbG90cwoKQSBzZWFzb25hbCBwbG90IGlzIHNpbWlsYXIgdG8gYSB0aW1lIHBsb3QgZXhjZXB0IHRoYXQgdGhlIGRhdGEgYXJlCnBsb3R0ZWQgYWdhaW5zdCB0aGUgaW5kaXZpZHVhbCBtb250aCBpbiB3aGljaCB0aGUgZGF0YSB3ZXJlIG9ic2VydmVkLgoKYGBge3Igc2Vhc29uYWxfcGxvdF9jb25zdW1wdGlvbiwgZWNobyA9IEZBTFNFfQpkZiB8PgogIGdnX3NlYXNvbihjb25zdW1wdGlvbl9nd2gsIGxhYmVscyA9ICJib3RoIiwgbGFiZWxzX3JlcGVsID0gVFJVRSkgKwogIGxhYnMoCiAgICB4ID0gIk1vbnRoIiwKICAgIHkgPSBOVUxMLAogICAgdGl0bGUgPSAiU2Vhc29uYWwgcGxvdDogTW9udGhseSByZXNpZGVudGlhbCBnYXMgY29uc3VtcHRpb24gaW4gR1doIgogICkgKwogIHlsaW0oMCwgTkEpICsKICB0aGVtZV9taW5pbWFsKCkKYGBgCgpJbiBhZGRpdGlvbiB0byB0aGUgb2JzZXJ2YXRpb25zIG1hZGUgYnkgdGhlIHRpbWUgcGxvdCwgd2Ugb2JzZXJ2ZSB0aGF0OgoKLSAgIEZlYnJ1YXJ5IGFuZCBNYXJjaCAyMDE4IGhhdmUgYSBoaWdoZXIgZ2FzIGNvbnN1bXB0aW9uIHRoYW4gdGhlIHNhbWUKICAgIG1vbnRocyBpbiBvdGhlciB5ZWFycy4KLSAgIEZlYnJ1YXJ5IDIwMjQgaGFzIGEgbG93ZXIgZ2FzIGNvbnN1bXB0aW9uIHRoYW4gdGhlIHNhbWUgbW9udGggaW4KICAgIG90aGVyIHllYXJzLgotICAgVGhlcmUgYXJlIHR3byAiY2x1c3RlcnMiIG9mIGN1cnZlcy4gVGhlIGZpcnN0IGNsdXN0ZXIgaGFzIDIwMTcgdG8KICAgIDIwMjEgY3VydmVzIGFuZCB0aGUgc2Vjb25kIGNsdXN0ZXIgaGFzIDIwMjIgdG8gMjAyNCBjdXJ2ZXMuIFRoZQogICAgY3VydmVzIG9mIHRoZSBzZWNvbmQgY2x1c3RlciBhcmUgYmVsb3cgdGhhbiB0aGUgY3VydmVzIG9mIHRoZSBmaXJzdAogICAgY2x1c3RlciwgZnJvbSBBcHJpbCB0byBOb3ZlbWJlci4gVGhpcyBjb3VsZCBiZSBleHBsYWluZWQgYnkgdGhlCiAgICBoaWdoZXItdGhhbi11c3VhbCByZXNpZGVudGlhbCBnYXMgcHJpY2VzIG9ic2VydmVkIGZyb20gMjAyMiB1bnRpbAogICAgMjAyNC4KClRoZSBoaWdoZXItdGhhbi11c3VhbCBnYXMgY29uc3VtcHRpb24gaW4gRmVicnVhcnkgYW5kIE1hcmNoIDIwMTggaXMgbW9zdApsaWtlbHkgZXhwbGFpbmVkIGJ5IHRoZSBsb3cgbWVhbiB0ZW1wZXJhdHVyZSBkdXJpbmcgdGhlc2UgbW9udGhzLCBhcwpvYnNlcnZlZCBpbiB0aGUgZ3JhcGggYmVsb3cuCgpgYGB7ciBzZWFzb25hbF9wbG90X3RlbXBlcmF0dXJlLCBlY2hvID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRX0KZGYgfD4KICBnZ19zZWFzb24odGVtcF9jZWxjaXVzLCBsYWJlbHMgPSAiYm90aCIsIGxhYmVsc19yZXBlbCA9IFRSVUUpICsKICBsYWJzKAogICAgeCA9ICJNb250aCIsCiAgICB5ID0gTlVMTCwKICAgIHRpdGxlID0gIlNlYXNvbmFsIHBsb3Q6IE1lYW4gbW9udGhseSB0ZW1wZXJhdHVyZSBpbiBkZWdyZWVzIENlbGNpdXMiCiAgKSArCiAgdGhlbWVfbWluaW1hbCgpCmBgYAoKIyMjIFNlYXNvbmFsIHN1YnNlcmllcyBwbG90CgpBbiBhbHRlcm5hdGl2ZSBwbG90IHRoYXQgZW1waGFzaXplcyB0aGUgc2Vhc29uYWwgcGF0dGVybnMgaXMgd2hlcmUgdGhlCmRhdGEgZm9yIGVhY2ggc2Vhc29uIGFyZSBjb2xsZWN0ZWQgdG9nZXRoZXIgaW4gc2VwYXJhdGUgbWluaSB0aW1lIHBsb3RzLgpUaGUgYmx1ZSBob3Jpem9udGFsIGxpbmVzIGluZGljYXRlIHRoZSBtZWFucyBmb3IgZWFjaCBtb250aC4gVGhlIHgtYXhpcwppbmRpY2F0ZXMgdGhlIHllYXIuCgpgYGB7ciBzZWFzb25hbF9zdWJzZXJpZXNfcGxvdF9jb25zdW1wdGlvbiwgZWNobyA9IEZBTFNFfQpkZiB8PgogIGdnX3N1YnNlcmllcyhjb25zdW1wdGlvbl9nd2gpICsKICBsYWJzKAogICAgeCA9ICJZZWFyIiwKICAgIHkgPSBOVUxMLAogICAgdGl0bGUgPSAiU2Vhc29uYWwgc3Vic2VyaWVzIHBsb3Q6IE1vbnRobHkgZ2FzIGNvbnN1bXB0aW9uIGluIEdXaCIKICApICsKICB5bGltKDAsIE5BKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZSgKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSwgdmp1c3QgPSAwLjUpLAogICAgcGFuZWwuZ3JpZC5taW5vci54ID0gZWxlbWVudF9ibGFuaygpCiAgKQpgYGAKCldlIG9ic2VydmUgdGhhdCB0aGUgcGF0dGVybiBpcyBzaW1pbGFyIGJldHdlZW4gbW9udGhzLCBleGNlcHQgZnJvbQpKYW51YXJ5LgoKYGBge3Igc2Vhc29uYWxfc3Vic2VyaWVzX3Bsb3RfdGVtcGVyYXR1cmUsIGVjaG8gPSBGQUxTRX0KZGYgfD4KICBnZ19zdWJzZXJpZXModGVtcF9jZWxjaXVzKSArCiAgbGFicygKICAgIHggPSAiWWVhciIsCiAgICB5ID0gTlVMTCwKICAgIHRpdGxlID0gIlNlYXNvbmFsIHN1YnNlcmllcyBwbG90OiBNb250aGx5IHRlbXBlcmF0dXJlIGluIGRlZ3JlZXMgQ2VsY2l1cyIKICApICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxLCB2anVzdCA9IDAuNSksCiAgICBwYW5lbC5ncmlkLm1pbm9yLnggPSBlbGVtZW50X2JsYW5rKCkKICApCmBgYAoKV2UgZG8gbm90IGRldGVjdCBhbnkgY2xlYXIgcGF0dGVybiBpbiB0aGlzIHNlYXNvbmFsIHN1YnNlcmllcyBncmFwaC4KClVwIHVudGlsIG5vdywgd2UgaGF2ZSBvYnNlcnZlZCBlYWNoIHRpbWUgc2VyaWVzIGluZGl2aWR1YWxseS4gVGhpcyBpcwphbHNvIGNhbGxlZCBhIHVuaXZhcmlhdGUgYW5hbHlzaXMuIE5leHQsIHdlIHdpbGwgbG9vayBhdCBob3cgdGhlc2UgdGltZQpzZXJpZXMgYmVoYXZlIHRvZ2V0aGVyLiBUaGlzIGlzIGFsc28gY2FsbGVkIGEgbXVsdGl2YXJpYXRlIGFuYWx5c2lzLgoKIyMjIFNjYXR0ZXJwbG90CgpMZXQgdXMgdmlzdWFsaXplIHRoZSBkYXRhIHBvaW50cyBvZiBnYXMgY29uc3VtcHRpb24gYW5kIG1lYW4gdGVtcGVyYXR1cmUKdG9nZXRoZXIuIFRoZSBtb3N0IGNvbW1vbiBwbG90IGZvciB0aGlzIHRhc2sgaXMgdGhlIHNjYXR0ZXJwbG90LCBhcwpzaG93biBiZWxvdy4gQSBsaW5lYXIgZml0IGlzIGFsc28gcGxvdHRlZC4KCmBgYHtyIHNjYXR0ZXJwbG90LCBlY2hvID0gRkFMU0V9CmdncGxvdChkZiwgYWVzKHggPSB0ZW1wX2NlbGNpdXMsIHkgPSBjb25zdW1wdGlvbl9nd2gpKSArCiAgZ2VvbV9wb2ludChzaXplID0gMywgc2hhcGUgPSAxKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgZm9ybXVsYSA9ICJ5IH4geCIpICsKICBsYWJzKAogICAgeCA9ICJNZWFuIHRlbXBlcmF0dXJlIGluIENlbGNpdXMiLAogICAgeSA9ICJDb25zdW1wdGlvbiBpbiBHV2giLAogICAgdGl0bGUgPSBOVUxMCiAgKSArCiAgdGhlbWVfbWluaW1hbCgpCmBgYAoKQXMgZXhwZWN0ZWQsIHdlIG9ic2VydmUgYSBuZWdhdGl2ZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIG1lYW4gdGVtcGVyYXR1cmUKYW5kIGdhcyBjb25zdW1wdGlvbi4gV2UgYWxzbyBvYnNlcnZlIHRoYXQgdGhlIHVwcGVyIGxlZnQgY29ybmVyIChsb3cKdGVtcGVyYXR1cmUsIGhpZ2ggY29uc3VtcHRpb24pIGhhcyBkYXRhIHBvaW50cyBjbG9zZXIgdG8gdGhlIGxpbmVhcgpyZWdyZXNzaW9uIGxpbmUuIEluIGNvbnRyYXN0LCB0aGUgbG93ZXIgcmlnaHQgY29ybmVyIChoaWdoIHRlbXBlcmF0dXJlLApsb3cgY29uc3VtcHRpb24pIGhhcyBkYXRhIHBvaW50cyBzY2F0dGVyZWQgYXdheSBmcm9tIHRoZSBsaW5lYXIKcmVncmVzc2lvbiBsaW5lLgoKVGhlIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50IG1lYXN1cmVzIHRoZSBzdHJlbmd0aCBvZiB0aGUgKipsaW5lYXIqKgpyZWxhdGlvbnNoaXAgYmV0d2VlbiBtZWFuIHRlbXBlcmF0dXJlIGFuZCBnYXMgY29uc3VtcHRpb24uIEZvciB0aGlzCmRhdGEsIHRoZSBjb3JyZWxhdGlvbiBjb2VmZmljaWVudCBpcwpgciByb3VuZChjb3IoZGYkY29uc3VtcHRpb25fZ3doLCBkZiR0ZW1wX2NlbGNpdXMpLCAyKWAuCgpBcyBzaG93biBiZWxvdywgdGhlIGNvcnJlbGF0aW9uIHRlc3QgaW5kaWNhdGVzIHRoYXQgdGhlIGNvcnJlbGF0aW9uCmNvZWZmaWNpZW50IGlzIHNpZ25pZmljYW50bHkgZGlmZmVyZW50IHRoYW4gemVyby4KCmBgYHtyIGNvcnJlbGF0aW9uX3Rlc3R9CmNvci50ZXN0KGRmJGNvbnN1bXB0aW9uX2d3aCwgZGYkdGVtcF9jZWxjaXVzLCBtZXRob2QgPSAicGVhcnNvbiIsCiAgICAgICAgIGFsdGVybmF0aXZlID0gInR3by5zaWRlZCIsIGNvbmYubGV2ZWwgPSAwLjk1KQpgYGAKCiMjIyBMYWcgcGxvdHMKClRoZSBmaWd1cmUgYmVsb3cgZGlzcGxheXMgc2NhdHRlcnBsb3RzIHdoZXJlIHRoZSBob3Jpem9udGFsIGF4aXMgc2hvd3MKbGFnZ2VkIHZhbHVlcyAoaykgb2YgdGhlIHRpbWUgc2VyaWVzLiBFYWNoIGdyYXBoIHNob3dzXAptb250aGx5IGdhcyBjb25zdW1wdGlvbiBkYXRhIHBvaW50cyBwbG90dGVkIGFnYWluc3QgdGhlbXNlbHZlcyBhdApkaWZmZXJlbnQgbGFncy4KCmBgYHtyIGxhZ19wbG90fQpkZiB8PgogIGdnX2xhZyhjb25zdW1wdGlvbl9nd2gsIGdlb20gPSAicG9pbnQiLCBsYWdzID0gMToxMikgKwogIGxhYnMoCiAgICB4ID0gImxhZyhnYXMgY29uc3VtcHRpb24gaW4gR1doLCBrKSIsCiAgICB5ID0gIkdhcyBjb25zdW1wdGlvbiBpbiBHV2giLAogICAgY29sb3IgPSAiTW9udGgiCiAgKSArCiAgdGhlbWVfbWluaW1hbCgpCmBgYAoKVGhlIGNvbG9ycyBpbmRpY2F0ZSB0aGUgbW9udGggb2YgdGhlIHZhcmlhYmxlIG9uIHRoZSB2ZXJ0aWNhbCBheGlzLiBUaGUKcmVsYXRpb25zaGlwIGlzIHN0cm9uZ2x5IHBvc2l0aXZlIGF0IGxhZ3MgMSBhbmQgMTIsIHJlZmxlY3RpbmcgdGhlCnN0cm9uZyBzZWFzb25hbGl0eSBpbiB0aGUgZGF0YS4gVGhlIG5lZ2F0aXZlIHJlbGF0aW9uc2hpcCBzZWVuIGZvciBsYWcgNgpvY2N1cnMgYmVjYXVzZSBwZWFrcyBvZiBnYXMgY29uc3VtcHRpb24gKGluIHRoZSB3aW50aGVyKSBhcmUgcGxvdHRlZAphZ2FpbnN0IHRyb3VnaHMgKGluIHRoZSBzdW1tZXIpLgoKIyMjIEF1dG9jb3JyZWxhdGlvbgoKSnVzdCBhcyBjb3JyZWxhdGlvbiBtZWFzdXJlcyB0aGUgZXh0ZW50IG9mIGEgbGluZWFyIHJlbGF0aW9uc2hpcCBiZXR3ZWVuCnR3byB2YXJpYWJsZXMsIGF1dG9jb3JyZWxhdGlvbiBtZWFzdXJlcyB0aGUgbGluZWFyIHJlbGF0aW9uc2hpcCBiZXR3ZWVuCmxhZ2dlZCB2YWx1ZXMgb2YgYSB0aW1lIHNlcmllcy4KClRoZXJlIGFyZSBzZXZlcmFsIGF1dG9jb3JyZWxhdGlvbiBjb2VmZmljaWVudHMsIGNvcnJlc3BvbmRpbmcgdG8gZWFjaApwYW5lbCBpbiB0aGUgbGFnIHBsb3QgYWJvdmUuCgpUaGUgYXV0b2NvcnJlbGF0aW9uIGNvZWZmaWNpZW50cyBtYWtlIHVwIHRoZSAqYXV0b2NvcnJlbGF0aW9uIGZ1bmN0aW9uKgpvciBBQ0YuCgpgYGB7ciBhY2Z9CmRmIHw+CiAgQUNGKGNvbnN1bXB0aW9uX2d3aCwgbGFnX21heCA9IDQ4KSB8PgogIGF1dG9wbG90KCkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJBQ0YgcGxvdDogTW9udGhseSBnYXMgY29uc3VtcHRpb24gaW4gR1doIiwKICAgIHggPSAiTGFnIGluIG1vbnRocyIsCiAgICB5ID0gIkFDRiIKICApICsKICB0aGVtZV9taW5pbWFsKCkKYGBgCgpJbiB0aGlzIGdyYXBoOgoKLSAgIFRoZSBhdXRvY29ycmVsYXRpb24gY29lZmZpY2llbnRzIGF0IGxhZyAxLCAxMiwgMjQsIGV0Yy4gKGRlbm90ZWQKICAgICRyXzEkLCAkcl97MTJ9JCwgYW5kICRyX3syNH0kIHJlc3BlY3RpdmVseSkgYXJlIGhpZ2guIFRoaXMgaXMgZHVlIHRvCiAgICB0aGUgc2Vhc29uYWwgcGF0dGVybiBpbiB0aGUgZGF0YTogdGhlIHBlYWtzIHRlbmQgdG8gYmUgMTIgbW9udGhzCiAgICBhcGFydCBhbmQgdGhlIGxvdyBwb2ludHMgdGVuZCB0byBhbHNvIGJlIDEyIG1vbnRocyBhcGFydC4KLSAgIFRoZSBkYXNoZWQgYmx1ZSBsaW5lcyBpbmRpY2F0ZSB3aGV0aGVyIHRoZSBjb3JyZWxhdGlvbnMgYXJlCiAgICBzaWduaWZpY2FudGx5IGRpZmZlcmVudCBmcm9tIHplcm8uIElmIGFuIGF1dG9jb3JyZWxhdGlvbiBjb2VmZmljaWVudAogICAgbGllcyBvdXRzaWRlIHRoZSBibHVlIGJvdW5kLCBpdCBpcyBzaWduaWZpY2FudGx5IGRpZmZlcmVudCBmcm9tCiAgICB6ZXJvLgoKIyMjIEJveC1Db3ggdHJhbnNmb3JtYXRpb24KCkZvciBtb3JlIGRldGFpbHMsIHBsZWFzZSByZWZlciB0byBbQGZwcDNdLgoKYGBge3IgYm94X2NveH0KbGFtYmRhIDwtIGRmIHw+CiAgZmVhdHVyZXMoY29uc3VtcHRpb25fZ3doLCBmZWF0dXJlcyA9IGd1ZXJyZXJvKSB8PgogIHB1bGwobGFtYmRhX2d1ZXJyZXJvKQpgYGAKClRoZSBvcHRpbWFsIGxhbWJkYSBmb3IgdmFyaWFuY2Ugc3RhYmlsaXphdGlvbiBpcyBgciByb3VuZChsYW1iZGEsIDIpYC4KCmBgYHtyIHRyYW5zZm9ybWVkX3NlcmllcywgZWNobz1GQUxTRX0KZGYgfD4KICBhdXRvcGxvdChib3hfY294KGNvbnN1bXB0aW9uX2d3aCwgbGFtYmRhKSkgKwogIGxhYnMoCiAgICB4ID0gIk1vbnRoIiwKICAgIHkgPSAiVHJhbnNmb3JtZWQgZ2FzIGNvbnN1bXB0aW9uIiwKICAgIHRpdGxlID0gVGVYKHBhc3RlMCgKICAgICAgIkJveC1Db3ggdHJhbnNmb3JtYXRpb24gd2l0aCAkXFxsYW1iZGEkID0gIiwKICAgICAgcm91bmQobGFtYmRhLCAyKQogICAgKSkKICApICsKICB5bGltKDAsIE5BKSArCiAgdGhlbWVfbWluaW1hbCgpCmBgYAoKIyMjIFRpbWUgc2VyaWVzIGRlY29tcG9zaXRpb24KCmBgYHtyIGRlY29tcG9zaXRpb25fdGFibGV9CmRjbXAgPC0gZGYgfD4KICBtb2RlbChzdGwgPSBTVEwoY29uc3VtcHRpb25fZ3doKSkgfD4KICBjb21wb25lbnRzKCkKCmRjbXAKYGBgCgpgYGB7ciBkZWNvbXBvc2l0aW9uX3Bsb3RzLCBlY2hvID0gRkFMU0UsIGZpZy5oZWlnaHQgPSAxMH0KZGNtcCB8PgogIGF1dG9wbG90KCkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgbGFicyh4ID0gIk1vbnRoIikKYGBgCgojIyMgVHJlbmQgYW5kIHNlYXNvbmFsIHN0cmVuZ3RoCgpgYGB7ciBzdHJlbmd0aF9kYXRhLCBlY2hvID0gRkFMU0V9CmZlYXRfc3RsX2NvbnN1bXB0aW9uX2d3aCA8LSBkZiB8PgogIGZlYXR1cmVzKGNvbnN1bXB0aW9uX2d3aCwgZmVhdF9zdGwpIHw+CiAgYXNfdGliYmxlKCkgfD4KICBtdXRhdGUodHMgPSAiTW9udGhseSBnYXMgY29uc3VtcHRpb24gaW4gR1doIiwgLmJlZm9yZSA9IGV2ZXJ5dGhpbmcoKSkKCmZlYXRfc3RsX3RlbXBfY2VsY2l1cyA8LSBkZiB8PgogIGZlYXR1cmVzKHRlbXBfY2VsY2l1cywgZmVhdF9zdGwpIHw+CiAgYXNfdGliYmxlKCkgfD4KICBtdXRhdGUodHMgPSAiTW9udGhseSBtZWFuIHRlbXBlcmF0dXJlIGluIENlbGNpdXMiLCAuYmVmb3JlID0gZXZlcnl0aGluZygpKQoKZmVhdF9zdGwgPC0gcmJpbmQoZmVhdF9zdGxfY29uc3VtcHRpb25fZ3doLCBmZWF0X3N0bF90ZW1wX2NlbGNpdXMpCgpmZWF0X3N0bF90IDwtIGZlYXRfc3RsIHw+CiAgdCgpIHw+CiAgYXMuZGF0YS5mcmFtZSgpIHw+CiAgcm93bmFtZXNfdG9fY29sdW1uKCJGZWF0dXJlIikKICAKY29sbmFtZXMoZmVhdF9zdGxfdCkgPC0gYygiRmVhdHVyZSIsIGZlYXRfc3RsX3RbMSwgMl0sIGZlYXRfc3RsX3RbMSwgM10pCgpmZWF0X3N0bF90IHw+CiAgc2xpY2UoLTEpIHw+IAogIGtibCgpIHw+IAogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSAic3RyaXBlZCIsCiAgICAgICAgICAgICAgICBmdWxsX3dpZHRoID0gRkFMU0UsCiAgICAgICAgICAgICAgICBwb3NpdGlvbiA9ICJjZW50ZXIiKQpgYGAKCmBgYHtyIHN0cmVuZ3RoX3Bsb3QsIGVjaG8gPSBGQUxTRX0KZmVhdF9zdGwgfD4KICBnZ3Bsb3QoYWVzKHggPSB0cmVuZF9zdHJlbmd0aCwgeSA9IHNlYXNvbmFsX3N0cmVuZ3RoX3llYXIpKSArCiAgZ2VvbV9wb2ludChzaXplID0gMykgKwogIGdlb21fdGV4dF9yZXBlbChhZXMobGFiZWwgPSB0cyksCiAgICBib3gucGFkZGluZyA9IDAuNSwKICAgIHBvaW50LnBhZGRpbmcgPSAwLjMsCiAgICBmb3JjZSA9IDEsCiAgICBtYXgub3ZlcmxhcHMgPSAxNQogICkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgeWxpbSgwLCAxKSArCiAgeGxpbSgwLCAxKSArCiAgbGFicyh4ID0gIlRyZW5kIHN0cmVuZ3RoIiwgeSA9ICJTZWFzb25hbCBzdHJlbmd0aCIpCmBgYAoKIyMgUmVmZXJlbmNlcwo=