1 Introduction

This project analyzes monthly U.S. gasoline prices using publicly available data from the Federal Reserve Bank of St. Louis (FRED). The goal of the analysis is to evaluate how recent price levels compare with long-term patterns by addressing the research question: How do U.S. gasoline prices in early 2025 compare to their long-term historical trend? To investigate this, the most recent 150 months of data are extracted and converted into a time series object for structured analysis. Classical and STL decomposition methods are applied to separate the series into trend, seasonal, and remainder components, allowing for an examination of underlying movements over time. Several training windows are then constructed, with the final six months held out as a test set, and STL-based naive forecasts are generated. Forecast accuracy is assessed using MSE and MAPE across the different training sizes, providing insight into how well recent gasoline prices align with expectations based on long-term historical behavior.

2 Description of Data Set

The time series data used in this study is from the Federal Reserve Bank of St. Louis. The data contains the gas price for the first of every month since September 1, 1990. We will be observsing only the most recent 150 observations, which ranges from May 2013 to October 2025. Our observation ID and explanatory variable will be the Observation Date. Our response variable is Dollars per Gallon (GASREGCOVM).

price_recent <- tail(price, 150)

In the above code chunk, we take the 150 most recent dates, or observations, in the data set.

3 Plotting Our Data

Since this is monthly data, frequency = 12 will be used to define the time series object.

price.ts <- ts(price_recent[, 2], frequency = 12, start = c(2013, 5))

par(mar = c(2, 2, 2, 2))
plot(
  price.ts,
  main = "US Regular Conventional Gas Prices: May 2013 to October 2025",
  ylab = "Monthly Price (USD per gallon)",
  xlab = "")

The time series plot of U.S. gasoline prices from May 2013 to October 2025 shows several clear shifts. Prices decline from about $3.50 in 2013 to a low near $2 in early 2016, then gradually rise through 2019. A sharp increase begins in 2021, peaking above $4.50 in 2022. After the peak, prices decline but remain more volatile, settling around the mid-$3 range through 2023–2025. Overall, the graph highlights a major upward surge after 2020 followed by partial stabilization.

4 Forecasting with Decomposition

To analyze the underlying structure of the gasoline price time series, this project applies both classical decomposition and STL (Seasonal-Trend Decomposition using LOESS). Using both methods provides a more complete understanding of how the data behaves over time. Classical decomposition separates the series into trend, seasonal, and remainder components using fixed seasonal patterns, which helps identify broad structural features in a straightforward way. STL decomposition, on the other hand, offers a more flexible and robust approach that can capture smoother trends and adapt to changes in seasonality. By performing both methods, the analysis can compare how each technique represents the data, highlight differences in trend and seasonal behavior, and ensure that the decomposition used for forecasting is based on the method that best reflects the characteristics of the gasoline price series.

4.1 Classical

Here, I apply the classical decomposition to break the series into its trend, seasonal, and irregular components, providing a baseline understanding of how the data behaves over time.

cls.decomp = decompose(price.ts)
par(mar=c(2,2,2,2))
plot(cls.decomp, xlab="")

The classical decomposition separates the gasoline price series into its observed, trend, seasonal, and remainder components. The trend component shows a gradual decline from 2013 through 2016, followed by a steady rise leading into the sharp peak around 2022, before leveling off toward 2025. The seasonal component displays a consistent repeating yearly pattern, indicating modest but regular seasonal fluctuations in gasoline prices. The remainder component captures short-term volatility not explained by trend or seasonality, with larger irregular movements appearing during periods of rapid price change, particularly around 2020–2022. Overall, classical decomposition reveals a clear long-term upward trend and stable seasonal behavior throughout the series.

4.2 STL

We will now perform the STL method.

stl.decomp=stl(price.ts, s.window = 12)
par(mar=c(2,2,2,2))
plot(stl.decomp)

The STL decomposition provides a smooth and flexible breakdown of the gasoline price series into trend, seasonal, and remainder components. The trend component clearly shows the long downward movement through 2016, followed by a steady rise and a pronounced peak in 2022, before gradually declining toward 2025. The seasonal component displays a stable, repeating yearly pattern, indicating that gasoline prices follow consistent seasonal fluctuations over time. The remainder component captures short-term variability that is not explained by the trend or seasonality, with noticeable spikes during periods of rapid price change, especially around 2020–2022. Compared with classical decomposition, the STL trend is smoother and better highlights the underlying long-term movements in the data.

5 Training Data

To evaluate the forecasting performance of the time series model, the final six months of gasoline price data are reserved as a test set. This 6-month horizon provides a practical short-term evaluation window while limiting the uncertainty associated with longer-range forecasts. The remaining observations serve as the training data, and multiple training window sizes are created to assess how the amount of historical information influences forecast accuracy. By generating forecasts for each training window and comparing them to the six held-out observations, the analysis identifies which training size yields the most reliable predictions for short-term gasoline price behavior.

To examine how the amount of historical data influences forecasting performance, four different training window sizes were created using the gasoline price time series. After holding out the final six observations as the test set, the remaining data were used to construct training sets of 144, 120, 96, and 72 months. These sizes were selected to represent a range of long, medium, and shorter training periods, allowing the analysis to evaluate whether using more or less historical information leads to better short-term forecasts. Each training window forecasts the same six-month test period, ensuring a fair comparison of predictive accuracy across models. By comparing the forecasting errors associated with these four training sizes, the analysis identifies which amount of historical data provides the most reliable short-term predictions for gasoline prices.

ini.data <- as.numeric(price.ts)
n0 <- length(ini.data)   # should be 150

# -------------------------------
# Training data sets
# -------------------------------
train.data01 <- ini.data[1:(n0 - 6)]                 # 144 months
train.data02 <- ini.data[(n0 - 6 - 119):(n0 - 6)]    # 120 months
train.data03 <- ini.data[(n0 - 6 - 95):(n0 - 6)]     # 96 months
train.data04 <- ini.data[(n0 - 6 - 71):(n0 - 6)]     # 72 months

# -------------------------------
# Test data (last 6 observations)
# -------------------------------
test.data <- ini.data[(n0 - 5):n0]

# -------------------------------
# Convert each training set to ts()
# Start = May 2013 (2013,5)
# -------------------------------

# Training 1: full 144 months starting at May 2013
train01.ts <- ts(train.data01, frequency = 12, start = c(2013, 5))

# Training 2: 120 months starting 24 months later (2015-05)
train02.ts <- ts(train.data02, frequency = 12, start = c(2015, 5))

# Training 3: 96 months starting 48 months after start (2017-05)
train03.ts <- ts(train.data03, frequency = 12, start = c(2017, 5))

# Training 4: 72 months starting 72 months after start (2019-05)
train04.ts <- ts(train.data04, frequency = 12, start = c(2019, 5))

# -------------------------------
# STL decomposition
# -------------------------------
stl01 <- stl(train01.ts, s.window = 12)
stl02 <- stl(train02.ts, s.window = 12)
stl03 <- stl(train03.ts, s.window = 12)
stl04 <- stl(train04.ts, s.window = 12)

# -------------------------------
# Forecast 6 months ahead
# -------------------------------

fcst01 <- forecast(stl01, h = 6, method = "naive")
fcst02 <- forecast(stl02, h = 6, method = "naive")
fcst03 <- forecast(stl03, h = 6, method = "naive")
fcst04 <- forecast(stl04, h = 6, method = "naive")

We next perform error analysis

# -------------------------------
# Prediction errors (MAPE without %) 
# -------------------------------
PE01 <- (test.data - fcst01$mean) / fcst01$mean
PE02 <- (test.data - fcst02$mean) / fcst02$mean
PE03 <- (test.data - fcst03$mean) / fcst03$mean
PE04 <- (test.data - fcst04$mean) / fcst04$mean

MAPE1 <- mean(abs(PE01))
MAPE2 <- mean(abs(PE02))
MAPE3 <- mean(abs(PE03))
MAPE4 <- mean(abs(PE04))

# -------------------------------
# Squared errors (MSE)
# -------------------------------
E1 <- test.data - fcst01$mean
E2 <- test.data - fcst02$mean
E3 <- test.data - fcst03$mean
E4 <- test.data - fcst04$mean

MSE1 <- mean(E1^2)
MSE2 <- mean(E2^2)
MSE3 <- mean(E3^2)
MSE4 <- mean(E4^2)

# -------------------------------
# Accuracy table
# -------------------------------
MSE  <- c(MSE1, MSE2, MSE3, MSE4)
MAPE <- c(MAPE1, MAPE2, MAPE3, MAPE4)

accuracy <- cbind(MSE = MSE, MAPE = MAPE)
row.names(accuracy) <- c("n=144", "n=120", "n=96", "n=72")

accuracy
              MSE       MAPE
n=144 0.009722946 0.02726487
n=120 0.009754861 0.02722784
n=96  0.010678115 0.02817212
n=72  0.010577313 0.02718487
# If you want it nicely formatted like the case study:
knitr::kable(
  accuracy, 
  caption = "Error comparison between forecast results with different training sample sizes"
)
Error comparison between forecast results with different training sample sizes
MSE MAPE
n=144 0.0097229 0.0272649
n=120 0.0097549 0.0272278
n=96 0.0106781 0.0281721
n=72 0.0105773 0.0271849

The error comparison table shows how forecast accuracy changes across different training window sizes. The models trained with 144 and 120 months of historical data produce the lowest MSE values (0.00972 and 0.00975), indicating the most accurate forecasts in terms of squared error. MAPE values are also very similar across these two windows, both around 0.027, suggesting nearly identical relative accuracy. Forecast accuracy declines slightly when using 96 and 72 months of training data, as reflected by higher MSE and MAPE values. Overall, the results suggest that using a longer training window—specifically 144 or 120 months—provides the most reliable short-term forecasts for gasoline prices, while shorter windows lead to modest reductions in predictive performance.

After computing MSE and MAPE for each training window, I visualize the errors to compare forecasting performance across sample sizes. The plots below show how prediction accuracy changes as the training period becomes shorter.

par(mfrow = c(1, 2))

# -----------------------
# MSE Plot
# -----------------------
plot(1:4, MSE, type = "b", col = "darkred",
     ylab = "Error", xlab = "",
     main = "MSE", axes = FALSE)

labs <- c("n=144", "n=120", "n=96", "n=72")
axis(1, at = 1:4, labels = labs)
axis(2)

# Label the points with their values
text(1:4, MSE - 0.002, as.character(round(MSE, 4)),
     col = "darkred", cex = 0.7)


# -----------------------
# MAPE Plot
# -----------------------
plot(1:4, MAPE, type = "b", col = "blue",
     ylab = "Error", xlab = "",
     main = "MAPE", axes = FALSE)

axis(1, at = 1:4, labels = labs)
axis(2)

# Label the points with their values
text(1:4, MAPE + 0.001, as.character(round(MAPE, 4)),
     col = "blue", cex = 0.7)

par(mfrow = c(1,1))

The error plots show how forecast accuracy changes with different training window sizes. Both MSE and MAPE are lowest when using the largest training windows (n = 144 and n = 120), indicating that models with more historical data produce more accurate six-month forecasts. Error values increase for the shorter training windows (n = 96 and n = 72), especially for MSE, suggesting that reducing the amount of available history weakens predictive performance. Overall, the visual patterns confirm that longer training periods lead to more reliable short-term gasoline price forecasts, while shorter windows introduce more variability and higher forecasting errors.

6 Conclusion

This analysis examined monthly U.S. gasoline prices from May 2013 to October 2025 to evaluate how recent price movements compare with long-term historical trends. Both classical and STL decomposition revealed clear structural patterns, including a gradual decline through 2016, a steady rise heading into 2020, and a sharp peak in 2022 followed by partial stabilization. STL produced a smoother and more reliable trend estimate, making it more suitable for forecasting. Using the last six months as a test set and training windows of 144, 120, 96, and 72 months, the results showed that the longest training windows produced the lowest MSE and MAPE values, indicating that incorporating more historical information leads to better short-term predictions. While these findings provide useful insight into how gasoline prices in early 2025 align with long-term trends, the analysis is subject to several limitations. The dataset contains only 150 observations, restricting how many meaningful training windows could be used, and gasoline prices are influenced by external economic and geopolitical factors that are not captured in a univariate time series. Potential user errors—such as indexing mistakes or assumptions about start dates—could also affect the results, and classical decomposition’s additive structure may oversimplify a series with periods of heightened volatility. Future analyses could be strengthened by using a larger dataset, experimenting with additional forecasting models such as ARIMA or exponential smoothing, incorporating external predictors like crude oil prices, or applying rolling-origin validation to better assess forecasting performance. Despite these limitations, the analysis provides a structured and data-driven assessment of short-term gasoline price behavior relative to long-term historical patterns.

LS0tDQp0aXRsZTogIkZvcmVjYXN0aW5nIFUuUy4gR2Fzb2xpbmUgUHJpY2VzIFVzaW5nIFRpbWUgU2VyaWVzIERlY29tcG9zaXRpb24iDQphdXRob3I6ICJMdWtlIFZvbG0iDQpkYXRlOiAiMjAyNS0xMS0yMCINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDogICAgICAgICAgICMgb3V0cHV0IGRvY3VtZW50IGZvcm1hdA0KICAgIHRvYzogeWVzICAgICAgICAgICAgICAgIyBhZGQgdGFibGUgY29udGVudHMNCiAgICB0b2NfZmxvYXQ6IHllcyAgICAgICAgICMgdG9jX3Byb3BlcnR5OiBmbG9hdGluZw0KICAgIHRvY19kZXB0aDogNCAgICAgICAgICAgIyBkZXB0aCBvZiBUT0MgaGVhZGluZ3MNCiAgICBmaWdfd2lkdGg6IDYgICAgICAgICAgICMgZ2xvYmFsIGZpZ3VyZSB3aWR0aA0KICAgIGZpZ19oZWlnaHQ6IDQgICAgICAgICAgIyBnbG9iYWwgZmlndXJlIGhlaWdodA0KICAgIGZpZ19jYXB0aW9uOiB5ZXMgICAgICAgIyBhZGQgZmlndXJlIGNhcHRpb24NCiAgICBudW1iZXJfc2VjdGlvbnM6IG5vICAgIyBudW1iZXJpbmcgc2VjdGlvbiBoZWFkaW5ncw0KICAgIHRvY19jb2xsYXBzZWQ6IHllcyAgICAgIyBUT0Mgc3ViaGVhZGluZyBjb2xsYXBzaW5nDQogICAgY29kZV9mb2xkaW5nOiBoaWRlICAgICAjIGZvbGRpbmcvc2hvd2luZyBjb2RlIA0KICAgIGNvZGVfZG93bmxvYWQ6IHllcyAgICAgIyBhbGxvdyB0byBkb3dubG9hZCBjb21wbGV0ZSBSTWFya2Rvd24gc291cmNlIGNvZGUNCiAgICBzbW9vdGhfc2Nyb2xsOiB5ZXMgICAgICMgc2Nyb2xsaW5nIHRleHQgb2YgdGhlIGRvY3VtZW50DQogICAgdGhlbWU6IGx1bWVuICAgICAgICAgICAjIHZpc3VhbCB0aGVtZSBmb3IgSFRNTCBkb2N1bWVudCBvbmx5DQogICAgaGlnaGxpZ2h0OiB0YW5nbyAgICAgICAjIGNvZGUgc3ludGF4IGhpZ2hsaWdodGluZyBzdHlsZXMNCiAgcGRmX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICB3b3JkX2RvY3VtZW50Og0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiAnNCcNCi0tLQ0KDQpgYGB7Y3NzLCBlY2hvID0gRkFMU0V9DQpkaXYjVE9DIGx3ZXsgICAgIC8qIHRhYmxlIG9mIGNvbnRlbnQgICovDQogICAgbGlzdC1zdHlsZTp1cHBlci1yb21hbjsNCiAgICBiYWNrZ3JvdW5kLWltYWdlOm5vbmU7DQogICAgYmFja2dyb3VuZC1yZXBlYXQ6bm9uZTsNCiAgICBiYWNrZ3JvdW5kLXBvc2l0aW9uOjA7DQp9DQoNCmgxLnRpdGxlIHsgICAgLyogbGV2ZWwgMSBoZWFkZXIgb2YgdGl0bGUgICovDQogIGZvbnQtc2l6ZTogMjRweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGNvbG9yOiBEYXJrUmVkOw0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQoNCmg0LmF1dGhvciB7IC8qIEhlYWRlciA0IC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogIGZvbnQtc2l6ZTogMThweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICBjb2xvcjogRGFya1JlZDsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KDQpoNC5kYXRlIHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgZm9udC1zaXplOiAxOHB4Ow0KICBmb250LXdlaWdodDogYm9sZDsNCiAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogIGNvbG9yOiBEYXJrQmx1ZTsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KDQpoMSB7IC8qIEhlYWRlciAxIC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogICAgZm9udC1zaXplOiAyMHB4Ow0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBkYXJrcmVkOw0KICAgIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCg0KaDIgeyAvKiBIZWFkZXIgMiAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICAgIGZvbnQtc2l6ZTogMThweDsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogbmF2eTsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQpoMyB7IC8qIEhlYWRlciAzIC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogICAgZm9udC1zaXplOiAxNnB4Ow0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCmg0IHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDE0cHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBkYXJrcmVkOw0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCi8qIEFkZCBkb3RzIGFmdGVyIG51bWJlcmVkIGhlYWRlcnMgKi8NCi5oZWFkZXItc2VjdGlvbi1udW1iZXI6OmFmdGVyIHsNCiAgY29udGVudDogIi4iOw0KfQ0KYGBgDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0KbGlicmFyeShyZWFkeGwpDQpsaWJyYXJ5KGJvb3QpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShrbml0cikNCmxpYnJhcnkocHN5Y2gpDQpsaWJyYXJ5KE1BU1MpDQpsaWJyYXJ5KHRpZHlyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShjYXIpDQpsaWJyYXJ5KHBhbmRlcikNCmxpYnJhcnkoZm9yZWNhc3QpDQoNCiMgU2V0IHNlZWQgZm9yIHJlcHJvZHVjaWJpbGl0eQ0Kc2V0LnNlZWQoMTIzKQ0KDQojIFJlYWQgaW4gZGF0YSAoZHJvcCBmaXJzdCBjb2x1bW4gaWYgaXQncyBqdXN0IGFuIGluZGV4L0lEKQ0Kc2V0d2QoIkM6L1VzZXJzL3ZvbG0xL09uZURyaXZlL0Rlc2t0b3AvU1RBMzIxIG5ldyIpDQpwcmljZSA8LSByZWFkLmNzdigiR0FTUkVHQ09WTS5jc3YiKQ0KIyBHbG9iYWwgY2h1bmsgb3B0aW9ucw0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KA0KICBlY2hvID0gVFJVRSwgICAgICAjIHNob3cgY29kZQ0KICB3YXJuaW5nID0gRkFMU0UsICAjIHN1cHByZXNzIHdhcm5pbmdzDQogIG1lc3NhZ2UgPSBGQUxTRSwgICMgc3VwcHJlc3MgbWVzc2FnZXMNCiAgcmVzdWx0cyA9IFRSVUUsICAgIyBzaG93IHJlc3VsdHMNCiAgY29tbWVudCA9IE5BICAgICAgIyBjbGVhbmVyIG91dHB1dCAobm8gIiMjIiBwcmVmaXgpDQopDQpgYGANCg0KIyAxIEludHJvZHVjdGlvbg0KDQpUaGlzIHByb2plY3QgYW5hbHl6ZXMgbW9udGhseSBVLlMuIGdhc29saW5lIHByaWNlcyB1c2luZyBwdWJsaWNseSBhdmFpbGFibGUgZGF0YSBmcm9tIHRoZSBGZWRlcmFsIFJlc2VydmUgQmFuayBvZiBTdC4gTG91aXMgKEZSRUQpLiBUaGUgZ29hbCBvZiB0aGUgYW5hbHlzaXMgaXMgdG8gZXZhbHVhdGUgaG93IHJlY2VudCBwcmljZSBsZXZlbHMgY29tcGFyZSB3aXRoIGxvbmctdGVybSBwYXR0ZXJucyBieSBhZGRyZXNzaW5nIHRoZSByZXNlYXJjaCBxdWVzdGlvbjogSG93IGRvIFUuUy4gZ2Fzb2xpbmUgcHJpY2VzIGluIGVhcmx5IDIwMjUgY29tcGFyZSB0byB0aGVpciBsb25nLXRlcm0gaGlzdG9yaWNhbCB0cmVuZD8gVG8gaW52ZXN0aWdhdGUgdGhpcywgdGhlIG1vc3QgcmVjZW50IDE1MCBtb250aHMgb2YgZGF0YSBhcmUgZXh0cmFjdGVkIGFuZCBjb252ZXJ0ZWQgaW50byBhIHRpbWUgc2VyaWVzIG9iamVjdCBmb3Igc3RydWN0dXJlZCBhbmFseXNpcy4gQ2xhc3NpY2FsIGFuZCBTVEwgZGVjb21wb3NpdGlvbiBtZXRob2RzIGFyZSBhcHBsaWVkIHRvIHNlcGFyYXRlIHRoZSBzZXJpZXMgaW50byB0cmVuZCwgc2Vhc29uYWwsIGFuZCByZW1haW5kZXIgY29tcG9uZW50cywgYWxsb3dpbmcgZm9yIGFuIGV4YW1pbmF0aW9uIG9mIHVuZGVybHlpbmcgbW92ZW1lbnRzIG92ZXIgdGltZS4gU2V2ZXJhbCB0cmFpbmluZyB3aW5kb3dzIGFyZSB0aGVuIGNvbnN0cnVjdGVkLCB3aXRoIHRoZSBmaW5hbCBzaXggbW9udGhzIGhlbGQgb3V0IGFzIGEgdGVzdCBzZXQsIGFuZCBTVEwtYmFzZWQgbmFpdmUgZm9yZWNhc3RzIGFyZSBnZW5lcmF0ZWQuIEZvcmVjYXN0IGFjY3VyYWN5IGlzIGFzc2Vzc2VkIHVzaW5nIE1TRSBhbmQgTUFQRSBhY3Jvc3MgdGhlIGRpZmZlcmVudCB0cmFpbmluZyBzaXplcywgcHJvdmlkaW5nIGluc2lnaHQgaW50byBob3cgd2VsbCByZWNlbnQgZ2Fzb2xpbmUgcHJpY2VzIGFsaWduIHdpdGggZXhwZWN0YXRpb25zIGJhc2VkIG9uIGxvbmctdGVybSBoaXN0b3JpY2FsIGJlaGF2aW9yLg0KDQojIDIgRGVzY3JpcHRpb24gb2YgRGF0YSBTZXQNCg0KVGhlIHRpbWUgc2VyaWVzIGRhdGEgdXNlZCBpbiB0aGlzIHN0dWR5IGlzIGZyb20gdGhlIEZlZGVyYWwgUmVzZXJ2ZSBCYW5rIG9mIFN0LiBMb3Vpcy4gVGhlIGRhdGEgY29udGFpbnMgdGhlIGdhcyBwcmljZSBmb3IgdGhlIGZpcnN0IG9mIGV2ZXJ5IG1vbnRoIHNpbmNlIFNlcHRlbWJlciAxLCAxOTkwLiBXZSB3aWxsIGJlIG9ic2VydnNpbmcgb25seSB0aGUgbW9zdCByZWNlbnQgMTUwIG9ic2VydmF0aW9ucywgd2hpY2ggcmFuZ2VzIGZyb20gTWF5IDIwMTMgdG8gT2N0b2JlciAyMDI1LiBPdXIgb2JzZXJ2YXRpb24gSUQgYW5kIGV4cGxhbmF0b3J5IHZhcmlhYmxlIHdpbGwgYmUgdGhlIE9ic2VydmF0aW9uIERhdGUuIE91ciByZXNwb25zZSB2YXJpYWJsZSBpcyBEb2xsYXJzIHBlciBHYWxsb24gKEdBU1JFR0NPVk0pLg0KDQpgYGB7cn0NCg0KcHJpY2VfcmVjZW50IDwtIHRhaWwocHJpY2UsIDE1MCkNCg0KYGBgDQoNCkluIHRoZSBhYm92ZSBjb2RlIGNodW5rLCB3ZSB0YWtlIHRoZSAxNTAgbW9zdCByZWNlbnQgZGF0ZXMsIG9yIG9ic2VydmF0aW9ucywgaW4gdGhlIGRhdGEgc2V0Lg0KDQojIDMgUGxvdHRpbmcgT3VyIERhdGENCg0KU2luY2UgdGhpcyBpcyBtb250aGx5IGRhdGEsIGZyZXF1ZW5jeSA9IDEyIHdpbGwgYmUgdXNlZCB0byBkZWZpbmUgdGhlIHRpbWUgc2VyaWVzIG9iamVjdC4gDQoNCmBgYHtyfQ0KDQpwcmljZS50cyA8LSB0cyhwcmljZV9yZWNlbnRbLCAyXSwgZnJlcXVlbmN5ID0gMTIsIHN0YXJ0ID0gYygyMDEzLCA1KSkNCg0KcGFyKG1hciA9IGMoMiwgMiwgMiwgMikpDQpwbG90KA0KICBwcmljZS50cywNCiAgbWFpbiA9ICJVUyBSZWd1bGFyIENvbnZlbnRpb25hbCBHYXMgUHJpY2VzOiBNYXkgMjAxMyB0byBPY3RvYmVyIDIwMjUiLA0KICB5bGFiID0gIk1vbnRobHkgUHJpY2UgKFVTRCBwZXIgZ2FsbG9uKSIsDQogIHhsYWIgPSAiIikNCmBgYA0KDQpUaGUgdGltZSBzZXJpZXMgcGxvdCBvZiBVLlMuIGdhc29saW5lIHByaWNlcyBmcm9tIE1heSAyMDEzIHRvIE9jdG9iZXIgMjAyNSBzaG93cyBzZXZlcmFsIGNsZWFyIHNoaWZ0cy4gUHJpY2VzIGRlY2xpbmUgZnJvbSBhYm91dCAkMy41MCBpbiAyMDEzIHRvIGEgbG93IG5lYXIgJDIgaW4gZWFybHkgMjAxNiwgdGhlbiBncmFkdWFsbHkgcmlzZSB0aHJvdWdoIDIwMTkuIEEgc2hhcnAgaW5jcmVhc2UgYmVnaW5zIGluIDIwMjEsIHBlYWtpbmcgYWJvdmUgJDQuNTAgaW4gMjAyMi4gQWZ0ZXIgdGhlIHBlYWssIHByaWNlcyBkZWNsaW5lIGJ1dCByZW1haW4gbW9yZSB2b2xhdGlsZSwgc2V0dGxpbmcgYXJvdW5kIHRoZSBtaWQtJDMgcmFuZ2UgdGhyb3VnaCAyMDIz4oCTMjAyNS4gT3ZlcmFsbCwgdGhlIGdyYXBoIGhpZ2hsaWdodHMgYSBtYWpvciB1cHdhcmQgc3VyZ2UgYWZ0ZXIgMjAyMCBmb2xsb3dlZCBieSBwYXJ0aWFsIHN0YWJpbGl6YXRpb24uDQoNCiMgNCBGb3JlY2FzdGluZyB3aXRoIERlY29tcG9zaXRpb24NCg0KVG8gYW5hbHl6ZSB0aGUgdW5kZXJseWluZyBzdHJ1Y3R1cmUgb2YgdGhlIGdhc29saW5lIHByaWNlIHRpbWUgc2VyaWVzLCB0aGlzIHByb2plY3QgYXBwbGllcyBib3RoIGNsYXNzaWNhbCBkZWNvbXBvc2l0aW9uIGFuZCBTVEwgKFNlYXNvbmFsLVRyZW5kIERlY29tcG9zaXRpb24gdXNpbmcgTE9FU1MpLiBVc2luZyBib3RoIG1ldGhvZHMgcHJvdmlkZXMgYSBtb3JlIGNvbXBsZXRlIHVuZGVyc3RhbmRpbmcgb2YgaG93IHRoZSBkYXRhIGJlaGF2ZXMgb3ZlciB0aW1lLiBDbGFzc2ljYWwgZGVjb21wb3NpdGlvbiBzZXBhcmF0ZXMgdGhlIHNlcmllcyBpbnRvIHRyZW5kLCBzZWFzb25hbCwgYW5kIHJlbWFpbmRlciBjb21wb25lbnRzIHVzaW5nIGZpeGVkIHNlYXNvbmFsIHBhdHRlcm5zLCB3aGljaCBoZWxwcyBpZGVudGlmeSBicm9hZCBzdHJ1Y3R1cmFsIGZlYXR1cmVzIGluIGEgc3RyYWlnaHRmb3J3YXJkIHdheS4gU1RMIGRlY29tcG9zaXRpb24sIG9uIHRoZSBvdGhlciBoYW5kLCBvZmZlcnMgYSBtb3JlIGZsZXhpYmxlIGFuZCByb2J1c3QgYXBwcm9hY2ggdGhhdCBjYW4gY2FwdHVyZSBzbW9vdGhlciB0cmVuZHMgYW5kIGFkYXB0IHRvIGNoYW5nZXMgaW4gc2Vhc29uYWxpdHkuIEJ5IHBlcmZvcm1pbmcgYm90aCBtZXRob2RzLCB0aGUgYW5hbHlzaXMgY2FuIGNvbXBhcmUgaG93IGVhY2ggdGVjaG5pcXVlIHJlcHJlc2VudHMgdGhlIGRhdGEsIGhpZ2hsaWdodCBkaWZmZXJlbmNlcyBpbiB0cmVuZCBhbmQgc2Vhc29uYWwgYmVoYXZpb3IsIGFuZCBlbnN1cmUgdGhhdCB0aGUgZGVjb21wb3NpdGlvbiB1c2VkIGZvciBmb3JlY2FzdGluZyBpcyBiYXNlZCBvbiB0aGUgbWV0aG9kIHRoYXQgYmVzdCByZWZsZWN0cyB0aGUgY2hhcmFjdGVyaXN0aWNzIG9mIHRoZSBnYXNvbGluZSBwcmljZSBzZXJpZXMuDQoNCiMjIDQuMSBDbGFzc2ljYWwNCg0KSGVyZSwgSSBhcHBseSB0aGUgY2xhc3NpY2FsIGRlY29tcG9zaXRpb24gdG8gYnJlYWsgdGhlIHNlcmllcyBpbnRvIGl0cyB0cmVuZCwgc2Vhc29uYWwsIGFuZCBpcnJlZ3VsYXIgY29tcG9uZW50cywgcHJvdmlkaW5nIGEgYmFzZWxpbmUgdW5kZXJzdGFuZGluZyBvZiBob3cgdGhlIGRhdGEgYmVoYXZlcyBvdmVyIHRpbWUuDQoNCmBgYHtyfQ0KDQpjbHMuZGVjb21wID0gZGVjb21wb3NlKHByaWNlLnRzKQ0KcGFyKG1hcj1jKDIsMiwyLDIpKQ0KcGxvdChjbHMuZGVjb21wLCB4bGFiPSIiKQ0KDQpgYGANCg0KVGhlIGNsYXNzaWNhbCBkZWNvbXBvc2l0aW9uIHNlcGFyYXRlcyB0aGUgZ2Fzb2xpbmUgcHJpY2Ugc2VyaWVzIGludG8gaXRzIG9ic2VydmVkLCB0cmVuZCwgc2Vhc29uYWwsIGFuZCByZW1haW5kZXIgY29tcG9uZW50cy4gVGhlIHRyZW5kIGNvbXBvbmVudCBzaG93cyBhIGdyYWR1YWwgZGVjbGluZSBmcm9tIDIwMTMgdGhyb3VnaCAyMDE2LCBmb2xsb3dlZCBieSBhIHN0ZWFkeSByaXNlIGxlYWRpbmcgaW50byB0aGUgc2hhcnAgcGVhayBhcm91bmQgMjAyMiwgYmVmb3JlIGxldmVsaW5nIG9mZiB0b3dhcmQgMjAyNS4gVGhlIHNlYXNvbmFsIGNvbXBvbmVudCBkaXNwbGF5cyBhIGNvbnNpc3RlbnQgcmVwZWF0aW5nIHllYXJseSBwYXR0ZXJuLCBpbmRpY2F0aW5nIG1vZGVzdCBidXQgcmVndWxhciBzZWFzb25hbCBmbHVjdHVhdGlvbnMgaW4gZ2Fzb2xpbmUgcHJpY2VzLiBUaGUgcmVtYWluZGVyIGNvbXBvbmVudCBjYXB0dXJlcyBzaG9ydC10ZXJtIHZvbGF0aWxpdHkgbm90IGV4cGxhaW5lZCBieSB0cmVuZCBvciBzZWFzb25hbGl0eSwgd2l0aCBsYXJnZXIgaXJyZWd1bGFyIG1vdmVtZW50cyBhcHBlYXJpbmcgZHVyaW5nIHBlcmlvZHMgb2YgcmFwaWQgcHJpY2UgY2hhbmdlLCBwYXJ0aWN1bGFybHkgYXJvdW5kIDIwMjDigJMyMDIyLiBPdmVyYWxsLCBjbGFzc2ljYWwgZGVjb21wb3NpdGlvbiByZXZlYWxzIGEgY2xlYXIgbG9uZy10ZXJtIHVwd2FyZCB0cmVuZCBhbmQgc3RhYmxlIHNlYXNvbmFsIGJlaGF2aW9yIHRocm91Z2hvdXQgdGhlIHNlcmllcy4NCg0KIyMgNC4yIFNUTA0KDQpXZSB3aWxsIG5vdyBwZXJmb3JtIHRoZSBTVEwgbWV0aG9kLg0KDQpgYGB7cn0NCg0Kc3RsLmRlY29tcD1zdGwocHJpY2UudHMsIHMud2luZG93ID0gMTIpDQpwYXIobWFyPWMoMiwyLDIsMikpDQpwbG90KHN0bC5kZWNvbXApDQoNCmBgYA0KDQpUaGUgU1RMIGRlY29tcG9zaXRpb24gcHJvdmlkZXMgYSBzbW9vdGggYW5kIGZsZXhpYmxlIGJyZWFrZG93biBvZiB0aGUgZ2Fzb2xpbmUgcHJpY2Ugc2VyaWVzIGludG8gdHJlbmQsIHNlYXNvbmFsLCBhbmQgcmVtYWluZGVyIGNvbXBvbmVudHMuIFRoZSB0cmVuZCBjb21wb25lbnQgY2xlYXJseSBzaG93cyB0aGUgbG9uZyBkb3dud2FyZCBtb3ZlbWVudCB0aHJvdWdoIDIwMTYsIGZvbGxvd2VkIGJ5IGEgc3RlYWR5IHJpc2UgYW5kIGEgcHJvbm91bmNlZCBwZWFrIGluIDIwMjIsIGJlZm9yZSBncmFkdWFsbHkgZGVjbGluaW5nIHRvd2FyZCAyMDI1LiBUaGUgc2Vhc29uYWwgY29tcG9uZW50IGRpc3BsYXlzIGEgc3RhYmxlLCByZXBlYXRpbmcgeWVhcmx5IHBhdHRlcm4sIGluZGljYXRpbmcgdGhhdCBnYXNvbGluZSBwcmljZXMgZm9sbG93IGNvbnNpc3RlbnQgc2Vhc29uYWwgZmx1Y3R1YXRpb25zIG92ZXIgdGltZS4gVGhlIHJlbWFpbmRlciBjb21wb25lbnQgY2FwdHVyZXMgc2hvcnQtdGVybSB2YXJpYWJpbGl0eSB0aGF0IGlzIG5vdCBleHBsYWluZWQgYnkgdGhlIHRyZW5kIG9yIHNlYXNvbmFsaXR5LCB3aXRoIG5vdGljZWFibGUgc3Bpa2VzIGR1cmluZyBwZXJpb2RzIG9mIHJhcGlkIHByaWNlIGNoYW5nZSwgZXNwZWNpYWxseSBhcm91bmQgMjAyMOKAkzIwMjIuIENvbXBhcmVkIHdpdGggY2xhc3NpY2FsIGRlY29tcG9zaXRpb24sIHRoZSBTVEwgdHJlbmQgaXMgc21vb3RoZXIgYW5kIGJldHRlciBoaWdobGlnaHRzIHRoZSB1bmRlcmx5aW5nIGxvbmctdGVybSBtb3ZlbWVudHMgaW4gdGhlIGRhdGEuDQoNCiMgNSBUcmFpbmluZyBEYXRhDQoNClRvIGV2YWx1YXRlIHRoZSBmb3JlY2FzdGluZyBwZXJmb3JtYW5jZSBvZiB0aGUgdGltZSBzZXJpZXMgbW9kZWwsIHRoZSBmaW5hbCBzaXggbW9udGhzIG9mIGdhc29saW5lIHByaWNlIGRhdGEgYXJlIHJlc2VydmVkIGFzIGEgdGVzdCBzZXQuIFRoaXMgNi1tb250aCBob3Jpem9uIHByb3ZpZGVzIGEgcHJhY3RpY2FsIHNob3J0LXRlcm0gZXZhbHVhdGlvbiB3aW5kb3cgd2hpbGUgbGltaXRpbmcgdGhlIHVuY2VydGFpbnR5IGFzc29jaWF0ZWQgd2l0aCBsb25nZXItcmFuZ2UgZm9yZWNhc3RzLiBUaGUgcmVtYWluaW5nIG9ic2VydmF0aW9ucyBzZXJ2ZSBhcyB0aGUgdHJhaW5pbmcgZGF0YSwgYW5kIG11bHRpcGxlIHRyYWluaW5nIHdpbmRvdyBzaXplcyBhcmUgY3JlYXRlZCB0byBhc3Nlc3MgaG93IHRoZSBhbW91bnQgb2YgaGlzdG9yaWNhbCBpbmZvcm1hdGlvbiBpbmZsdWVuY2VzIGZvcmVjYXN0IGFjY3VyYWN5LiBCeSBnZW5lcmF0aW5nIGZvcmVjYXN0cyBmb3IgZWFjaCB0cmFpbmluZyB3aW5kb3cgYW5kIGNvbXBhcmluZyB0aGVtIHRvIHRoZSBzaXggaGVsZC1vdXQgb2JzZXJ2YXRpb25zLCB0aGUgYW5hbHlzaXMgaWRlbnRpZmllcyB3aGljaCB0cmFpbmluZyBzaXplIHlpZWxkcyB0aGUgbW9zdCByZWxpYWJsZSBwcmVkaWN0aW9ucyBmb3Igc2hvcnQtdGVybSBnYXNvbGluZSBwcmljZSBiZWhhdmlvci4NCg0KVG8gZXhhbWluZSBob3cgdGhlIGFtb3VudCBvZiBoaXN0b3JpY2FsIGRhdGEgaW5mbHVlbmNlcyBmb3JlY2FzdGluZyBwZXJmb3JtYW5jZSwgZm91ciBkaWZmZXJlbnQgdHJhaW5pbmcgd2luZG93IHNpemVzIHdlcmUgY3JlYXRlZCB1c2luZyB0aGUgZ2Fzb2xpbmUgcHJpY2UgdGltZSBzZXJpZXMuIEFmdGVyIGhvbGRpbmcgb3V0IHRoZSBmaW5hbCBzaXggb2JzZXJ2YXRpb25zIGFzIHRoZSB0ZXN0IHNldCwgdGhlIHJlbWFpbmluZyBkYXRhIHdlcmUgdXNlZCB0byBjb25zdHJ1Y3QgdHJhaW5pbmcgc2V0cyBvZiAxNDQsIDEyMCwgOTYsIGFuZCA3MiBtb250aHMuIFRoZXNlIHNpemVzIHdlcmUgc2VsZWN0ZWQgdG8gcmVwcmVzZW50IGEgcmFuZ2Ugb2YgbG9uZywgbWVkaXVtLCBhbmQgc2hvcnRlciB0cmFpbmluZyBwZXJpb2RzLCBhbGxvd2luZyB0aGUgYW5hbHlzaXMgdG8gZXZhbHVhdGUgd2hldGhlciB1c2luZyBtb3JlIG9yIGxlc3MgaGlzdG9yaWNhbCBpbmZvcm1hdGlvbiBsZWFkcyB0byBiZXR0ZXIgc2hvcnQtdGVybSBmb3JlY2FzdHMuIEVhY2ggdHJhaW5pbmcgd2luZG93IGZvcmVjYXN0cyB0aGUgc2FtZSBzaXgtbW9udGggdGVzdCBwZXJpb2QsIGVuc3VyaW5nIGEgZmFpciBjb21wYXJpc29uIG9mIHByZWRpY3RpdmUgYWNjdXJhY3kgYWNyb3NzIG1vZGVscy4gQnkgY29tcGFyaW5nIHRoZSBmb3JlY2FzdGluZyBlcnJvcnMgYXNzb2NpYXRlZCB3aXRoIHRoZXNlIGZvdXIgdHJhaW5pbmcgc2l6ZXMsIHRoZSBhbmFseXNpcyBpZGVudGlmaWVzIHdoaWNoIGFtb3VudCBvZiBoaXN0b3JpY2FsIGRhdGEgcHJvdmlkZXMgdGhlIG1vc3QgcmVsaWFibGUgc2hvcnQtdGVybSBwcmVkaWN0aW9ucyBmb3IgZ2Fzb2xpbmUgcHJpY2VzLg0KDQpgYGB7cn0NCg0KaW5pLmRhdGEgPC0gYXMubnVtZXJpYyhwcmljZS50cykNCm4wIDwtIGxlbmd0aChpbmkuZGF0YSkgICAjIHNob3VsZCBiZSAxNTANCg0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIFRyYWluaW5nIGRhdGEgc2V0cw0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQp0cmFpbi5kYXRhMDEgPC0gaW5pLmRhdGFbMToobjAgLSA2KV0gICAgICAgICAgICAgICAgICMgMTQ0IG1vbnRocw0KdHJhaW4uZGF0YTAyIDwtIGluaS5kYXRhWyhuMCAtIDYgLSAxMTkpOihuMCAtIDYpXSAgICAjIDEyMCBtb250aHMNCnRyYWluLmRhdGEwMyA8LSBpbmkuZGF0YVsobjAgLSA2IC0gOTUpOihuMCAtIDYpXSAgICAgIyA5NiBtb250aHMNCnRyYWluLmRhdGEwNCA8LSBpbmkuZGF0YVsobjAgLSA2IC0gNzEpOihuMCAtIDYpXSAgICAgIyA3MiBtb250aHMNCg0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIFRlc3QgZGF0YSAobGFzdCA2IG9ic2VydmF0aW9ucykNCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KdGVzdC5kYXRhIDwtIGluaS5kYXRhWyhuMCAtIDUpOm4wXQ0KDQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgQ29udmVydCBlYWNoIHRyYWluaW5nIHNldCB0byB0cygpDQojIFN0YXJ0ID0gTWF5IDIwMTMgKDIwMTMsNSkNCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQojIFRyYWluaW5nIDE6IGZ1bGwgMTQ0IG1vbnRocyBzdGFydGluZyBhdCBNYXkgMjAxMw0KdHJhaW4wMS50cyA8LSB0cyh0cmFpbi5kYXRhMDEsIGZyZXF1ZW5jeSA9IDEyLCBzdGFydCA9IGMoMjAxMywgNSkpDQoNCiMgVHJhaW5pbmcgMjogMTIwIG1vbnRocyBzdGFydGluZyAyNCBtb250aHMgbGF0ZXIgKDIwMTUtMDUpDQp0cmFpbjAyLnRzIDwtIHRzKHRyYWluLmRhdGEwMiwgZnJlcXVlbmN5ID0gMTIsIHN0YXJ0ID0gYygyMDE1LCA1KSkNCg0KIyBUcmFpbmluZyAzOiA5NiBtb250aHMgc3RhcnRpbmcgNDggbW9udGhzIGFmdGVyIHN0YXJ0ICgyMDE3LTA1KQ0KdHJhaW4wMy50cyA8LSB0cyh0cmFpbi5kYXRhMDMsIGZyZXF1ZW5jeSA9IDEyLCBzdGFydCA9IGMoMjAxNywgNSkpDQoNCiMgVHJhaW5pbmcgNDogNzIgbW9udGhzIHN0YXJ0aW5nIDcyIG1vbnRocyBhZnRlciBzdGFydCAoMjAxOS0wNSkNCnRyYWluMDQudHMgPC0gdHModHJhaW4uZGF0YTA0LCBmcmVxdWVuY3kgPSAxMiwgc3RhcnQgPSBjKDIwMTksIDUpKQ0KDQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgU1RMIGRlY29tcG9zaXRpb24NCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0Kc3RsMDEgPC0gc3RsKHRyYWluMDEudHMsIHMud2luZG93ID0gMTIpDQpzdGwwMiA8LSBzdGwodHJhaW4wMi50cywgcy53aW5kb3cgPSAxMikNCnN0bDAzIDwtIHN0bCh0cmFpbjAzLnRzLCBzLndpbmRvdyA9IDEyKQ0Kc3RsMDQgPC0gc3RsKHRyYWluMDQudHMsIHMud2luZG93ID0gMTIpDQoNCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyBGb3JlY2FzdCA2IG1vbnRocyBhaGVhZA0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCmZjc3QwMSA8LSBmb3JlY2FzdChzdGwwMSwgaCA9IDYsIG1ldGhvZCA9ICJuYWl2ZSIpDQpmY3N0MDIgPC0gZm9yZWNhc3Qoc3RsMDIsIGggPSA2LCBtZXRob2QgPSAibmFpdmUiKQ0KZmNzdDAzIDwtIGZvcmVjYXN0KHN0bDAzLCBoID0gNiwgbWV0aG9kID0gIm5haXZlIikNCmZjc3QwNCA8LSBmb3JlY2FzdChzdGwwNCwgaCA9IDYsIG1ldGhvZCA9ICJuYWl2ZSIpDQoNCmBgYA0KDQpXZSBuZXh0IHBlcmZvcm0gZXJyb3IgYW5hbHlzaXMNCg0KYGBge3J9DQoNCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyBQcmVkaWN0aW9uIGVycm9ycyAoTUFQRSB3aXRob3V0ICUpIA0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQpQRTAxIDwtICh0ZXN0LmRhdGEgLSBmY3N0MDEkbWVhbikgLyBmY3N0MDEkbWVhbg0KUEUwMiA8LSAodGVzdC5kYXRhIC0gZmNzdDAyJG1lYW4pIC8gZmNzdDAyJG1lYW4NClBFMDMgPC0gKHRlc3QuZGF0YSAtIGZjc3QwMyRtZWFuKSAvIGZjc3QwMyRtZWFuDQpQRTA0IDwtICh0ZXN0LmRhdGEgLSBmY3N0MDQkbWVhbikgLyBmY3N0MDQkbWVhbg0KDQpNQVBFMSA8LSBtZWFuKGFicyhQRTAxKSkNCk1BUEUyIDwtIG1lYW4oYWJzKFBFMDIpKQ0KTUFQRTMgPC0gbWVhbihhYnMoUEUwMykpDQpNQVBFNCA8LSBtZWFuKGFicyhQRTA0KSkNCg0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIFNxdWFyZWQgZXJyb3JzIChNU0UpDQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCkUxIDwtIHRlc3QuZGF0YSAtIGZjc3QwMSRtZWFuDQpFMiA8LSB0ZXN0LmRhdGEgLSBmY3N0MDIkbWVhbg0KRTMgPC0gdGVzdC5kYXRhIC0gZmNzdDAzJG1lYW4NCkU0IDwtIHRlc3QuZGF0YSAtIGZjc3QwNCRtZWFuDQoNCk1TRTEgPC0gbWVhbihFMV4yKQ0KTVNFMiA8LSBtZWFuKEUyXjIpDQpNU0UzIDwtIG1lYW4oRTNeMikNCk1TRTQgPC0gbWVhbihFNF4yKQ0KDQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgQWNjdXJhY3kgdGFibGUNCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KTVNFICA8LSBjKE1TRTEsIE1TRTIsIE1TRTMsIE1TRTQpDQpNQVBFIDwtIGMoTUFQRTEsIE1BUEUyLCBNQVBFMywgTUFQRTQpDQoNCmFjY3VyYWN5IDwtIGNiaW5kKE1TRSA9IE1TRSwgTUFQRSA9IE1BUEUpDQpyb3cubmFtZXMoYWNjdXJhY3kpIDwtIGMoIm49MTQ0IiwgIm49MTIwIiwgIm49OTYiLCAibj03MiIpDQoNCmFjY3VyYWN5DQoNCiMgSWYgeW91IHdhbnQgaXQgbmljZWx5IGZvcm1hdHRlZCBsaWtlIHRoZSBjYXNlIHN0dWR5Og0Ka25pdHI6OmthYmxlKA0KICBhY2N1cmFjeSwgDQogIGNhcHRpb24gPSAiRXJyb3IgY29tcGFyaXNvbiBiZXR3ZWVuIGZvcmVjYXN0IHJlc3VsdHMgd2l0aCBkaWZmZXJlbnQgdHJhaW5pbmcgc2FtcGxlIHNpemVzIg0KKQ0KYGBgDQoNClRoZSBlcnJvciBjb21wYXJpc29uIHRhYmxlIHNob3dzIGhvdyBmb3JlY2FzdCBhY2N1cmFjeSBjaGFuZ2VzIGFjcm9zcyBkaWZmZXJlbnQgdHJhaW5pbmcgd2luZG93IHNpemVzLiBUaGUgbW9kZWxzIHRyYWluZWQgd2l0aCAxNDQgYW5kIDEyMCBtb250aHMgb2YgaGlzdG9yaWNhbCBkYXRhIHByb2R1Y2UgdGhlIGxvd2VzdCBNU0UgdmFsdWVzICgwLjAwOTcyIGFuZCAwLjAwOTc1KSwgaW5kaWNhdGluZyB0aGUgbW9zdCBhY2N1cmF0ZSBmb3JlY2FzdHMgaW4gdGVybXMgb2Ygc3F1YXJlZCBlcnJvci4gTUFQRSB2YWx1ZXMgYXJlIGFsc28gdmVyeSBzaW1pbGFyIGFjcm9zcyB0aGVzZSB0d28gd2luZG93cywgYm90aCBhcm91bmQgMC4wMjcsIHN1Z2dlc3RpbmcgbmVhcmx5IGlkZW50aWNhbCByZWxhdGl2ZSBhY2N1cmFjeS4gRm9yZWNhc3QgYWNjdXJhY3kgZGVjbGluZXMgc2xpZ2h0bHkgd2hlbiB1c2luZyA5NiBhbmQgNzIgbW9udGhzIG9mIHRyYWluaW5nIGRhdGEsIGFzIHJlZmxlY3RlZCBieSBoaWdoZXIgTVNFIGFuZCBNQVBFIHZhbHVlcy4gT3ZlcmFsbCwgdGhlIHJlc3VsdHMgc3VnZ2VzdCB0aGF0IHVzaW5nIGEgbG9uZ2VyIHRyYWluaW5nIHdpbmRvd+KAlHNwZWNpZmljYWxseSAxNDQgb3IgMTIwIG1vbnRoc+KAlHByb3ZpZGVzIHRoZSBtb3N0IHJlbGlhYmxlIHNob3J0LXRlcm0gZm9yZWNhc3RzIGZvciBnYXNvbGluZSBwcmljZXMsIHdoaWxlIHNob3J0ZXIgd2luZG93cyBsZWFkIHRvIG1vZGVzdCByZWR1Y3Rpb25zIGluIHByZWRpY3RpdmUgcGVyZm9ybWFuY2UuDQoNCkFmdGVyIGNvbXB1dGluZyBNU0UgYW5kIE1BUEUgZm9yIGVhY2ggdHJhaW5pbmcgd2luZG93LCBJIHZpc3VhbGl6ZSB0aGUgZXJyb3JzIHRvIGNvbXBhcmUgZm9yZWNhc3RpbmcgcGVyZm9ybWFuY2UgYWNyb3NzIHNhbXBsZSBzaXplcy4gVGhlIHBsb3RzIGJlbG93IHNob3cgaG93IHByZWRpY3Rpb24gYWNjdXJhY3kgY2hhbmdlcyBhcyB0aGUgdHJhaW5pbmcgcGVyaW9kIGJlY29tZXMgc2hvcnRlci4NCg0KYGBge3J9DQoNCnBhcihtZnJvdyA9IGMoMSwgMikpDQoNCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgTVNFIFBsb3QNCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCnBsb3QoMTo0LCBNU0UsIHR5cGUgPSAiYiIsIGNvbCA9ICJkYXJrcmVkIiwNCiAgICAgeWxhYiA9ICJFcnJvciIsIHhsYWIgPSAiIiwNCiAgICAgbWFpbiA9ICJNU0UiLCBheGVzID0gRkFMU0UpDQoNCmxhYnMgPC0gYygibj0xNDQiLCAibj0xMjAiLCAibj05NiIsICJuPTcyIikNCmF4aXMoMSwgYXQgPSAxOjQsIGxhYmVscyA9IGxhYnMpDQpheGlzKDIpDQoNCiMgTGFiZWwgdGhlIHBvaW50cyB3aXRoIHRoZWlyIHZhbHVlcw0KdGV4dCgxOjQsIE1TRSAtIDAuMDAyLCBhcy5jaGFyYWN0ZXIocm91bmQoTVNFLCA0KSksDQogICAgIGNvbCA9ICJkYXJrcmVkIiwgY2V4ID0gMC43KQ0KDQoNCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgTUFQRSBQbG90DQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQpwbG90KDE6NCwgTUFQRSwgdHlwZSA9ICJiIiwgY29sID0gImJsdWUiLA0KICAgICB5bGFiID0gIkVycm9yIiwgeGxhYiA9ICIiLA0KICAgICBtYWluID0gIk1BUEUiLCBheGVzID0gRkFMU0UpDQoNCmF4aXMoMSwgYXQgPSAxOjQsIGxhYmVscyA9IGxhYnMpDQpheGlzKDIpDQoNCiMgTGFiZWwgdGhlIHBvaW50cyB3aXRoIHRoZWlyIHZhbHVlcw0KdGV4dCgxOjQsIE1BUEUgKyAwLjAwMSwgYXMuY2hhcmFjdGVyKHJvdW5kKE1BUEUsIDQpKSwNCiAgICAgY29sID0gImJsdWUiLCBjZXggPSAwLjcpDQoNCnBhcihtZnJvdyA9IGMoMSwxKSkNCmBgYA0KDQpUaGUgZXJyb3IgcGxvdHMgc2hvdyBob3cgZm9yZWNhc3QgYWNjdXJhY3kgY2hhbmdlcyB3aXRoIGRpZmZlcmVudCB0cmFpbmluZyB3aW5kb3cgc2l6ZXMuIEJvdGggTVNFIGFuZCBNQVBFIGFyZSBsb3dlc3Qgd2hlbiB1c2luZyB0aGUgbGFyZ2VzdCB0cmFpbmluZyB3aW5kb3dzIChuID0gMTQ0IGFuZCBuID0gMTIwKSwgaW5kaWNhdGluZyB0aGF0IG1vZGVscyB3aXRoIG1vcmUgaGlzdG9yaWNhbCBkYXRhIHByb2R1Y2UgbW9yZSBhY2N1cmF0ZSBzaXgtbW9udGggZm9yZWNhc3RzLiBFcnJvciB2YWx1ZXMgaW5jcmVhc2UgZm9yIHRoZSBzaG9ydGVyIHRyYWluaW5nIHdpbmRvd3MgKG4gPSA5NiBhbmQgbiA9IDcyKSwgZXNwZWNpYWxseSBmb3IgTVNFLCBzdWdnZXN0aW5nIHRoYXQgcmVkdWNpbmcgdGhlIGFtb3VudCBvZiBhdmFpbGFibGUgaGlzdG9yeSB3ZWFrZW5zIHByZWRpY3RpdmUgcGVyZm9ybWFuY2UuIE92ZXJhbGwsIHRoZSB2aXN1YWwgcGF0dGVybnMgY29uZmlybSB0aGF0IGxvbmdlciB0cmFpbmluZyBwZXJpb2RzIGxlYWQgdG8gbW9yZSByZWxpYWJsZSBzaG9ydC10ZXJtIGdhc29saW5lIHByaWNlIGZvcmVjYXN0cywgd2hpbGUgc2hvcnRlciB3aW5kb3dzIGludHJvZHVjZSBtb3JlIHZhcmlhYmlsaXR5IGFuZCBoaWdoZXIgZm9yZWNhc3RpbmcgZXJyb3JzLg0KDQojIDYgQ29uY2x1c2lvbg0KDQpUaGlzIGFuYWx5c2lzIGV4YW1pbmVkIG1vbnRobHkgVS5TLiBnYXNvbGluZSBwcmljZXMgZnJvbSBNYXkgMjAxMyB0byBPY3RvYmVyIDIwMjUgdG8gZXZhbHVhdGUgaG93IHJlY2VudCBwcmljZSBtb3ZlbWVudHMgY29tcGFyZSB3aXRoIGxvbmctdGVybSBoaXN0b3JpY2FsIHRyZW5kcy4gQm90aCBjbGFzc2ljYWwgYW5kIFNUTCBkZWNvbXBvc2l0aW9uIHJldmVhbGVkIGNsZWFyIHN0cnVjdHVyYWwgcGF0dGVybnMsIGluY2x1ZGluZyBhIGdyYWR1YWwgZGVjbGluZSB0aHJvdWdoIDIwMTYsIGEgc3RlYWR5IHJpc2UgaGVhZGluZyBpbnRvIDIwMjAsIGFuZCBhIHNoYXJwIHBlYWsgaW4gMjAyMiBmb2xsb3dlZCBieSBwYXJ0aWFsIHN0YWJpbGl6YXRpb24uIFNUTCBwcm9kdWNlZCBhIHNtb290aGVyIGFuZCBtb3JlIHJlbGlhYmxlIHRyZW5kIGVzdGltYXRlLCBtYWtpbmcgaXQgbW9yZSBzdWl0YWJsZSBmb3IgZm9yZWNhc3RpbmcuIFVzaW5nIHRoZSBsYXN0IHNpeCBtb250aHMgYXMgYSB0ZXN0IHNldCBhbmQgdHJhaW5pbmcgd2luZG93cyBvZiAxNDQsIDEyMCwgOTYsIGFuZCA3MiBtb250aHMsIHRoZSByZXN1bHRzIHNob3dlZCB0aGF0IHRoZSBsb25nZXN0IHRyYWluaW5nIHdpbmRvd3MgcHJvZHVjZWQgdGhlIGxvd2VzdCBNU0UgYW5kIE1BUEUgdmFsdWVzLCBpbmRpY2F0aW5nIHRoYXQgaW5jb3Jwb3JhdGluZyBtb3JlIGhpc3RvcmljYWwgaW5mb3JtYXRpb24gbGVhZHMgdG8gYmV0dGVyIHNob3J0LXRlcm0gcHJlZGljdGlvbnMuIFdoaWxlIHRoZXNlIGZpbmRpbmdzIHByb3ZpZGUgdXNlZnVsIGluc2lnaHQgaW50byBob3cgZ2Fzb2xpbmUgcHJpY2VzIGluIGVhcmx5IDIwMjUgYWxpZ24gd2l0aCBsb25nLXRlcm0gdHJlbmRzLCB0aGUgYW5hbHlzaXMgaXMgc3ViamVjdCB0byBzZXZlcmFsIGxpbWl0YXRpb25zLiBUaGUgZGF0YXNldCBjb250YWlucyBvbmx5IDE1MCBvYnNlcnZhdGlvbnMsIHJlc3RyaWN0aW5nIGhvdyBtYW55IG1lYW5pbmdmdWwgdHJhaW5pbmcgd2luZG93cyBjb3VsZCBiZSB1c2VkLCBhbmQgZ2Fzb2xpbmUgcHJpY2VzIGFyZSBpbmZsdWVuY2VkIGJ5IGV4dGVybmFsIGVjb25vbWljIGFuZCBnZW9wb2xpdGljYWwgZmFjdG9ycyB0aGF0IGFyZSBub3QgY2FwdHVyZWQgaW4gYSB1bml2YXJpYXRlIHRpbWUgc2VyaWVzLiBQb3RlbnRpYWwgdXNlciBlcnJvcnPigJRzdWNoIGFzIGluZGV4aW5nIG1pc3Rha2VzIG9yIGFzc3VtcHRpb25zIGFib3V0IHN0YXJ0IGRhdGVz4oCUY291bGQgYWxzbyBhZmZlY3QgdGhlIHJlc3VsdHMsIGFuZCBjbGFzc2ljYWwgZGVjb21wb3NpdGlvbuKAmXMgYWRkaXRpdmUgc3RydWN0dXJlIG1heSBvdmVyc2ltcGxpZnkgYSBzZXJpZXMgd2l0aCBwZXJpb2RzIG9mIGhlaWdodGVuZWQgdm9sYXRpbGl0eS4gRnV0dXJlIGFuYWx5c2VzIGNvdWxkIGJlIHN0cmVuZ3RoZW5lZCBieSB1c2luZyBhIGxhcmdlciBkYXRhc2V0LCBleHBlcmltZW50aW5nIHdpdGggYWRkaXRpb25hbCBmb3JlY2FzdGluZyBtb2RlbHMgc3VjaCBhcyBBUklNQSBvciBleHBvbmVudGlhbCBzbW9vdGhpbmcsIGluY29ycG9yYXRpbmcgZXh0ZXJuYWwgcHJlZGljdG9ycyBsaWtlIGNydWRlIG9pbCBwcmljZXMsIG9yIGFwcGx5aW5nIHJvbGxpbmctb3JpZ2luIHZhbGlkYXRpb24gdG8gYmV0dGVyIGFzc2VzcyBmb3JlY2FzdGluZyBwZXJmb3JtYW5jZS4gRGVzcGl0ZSB0aGVzZSBsaW1pdGF0aW9ucywgdGhlIGFuYWx5c2lzIHByb3ZpZGVzIGEgc3RydWN0dXJlZCBhbmQgZGF0YS1kcml2ZW4gYXNzZXNzbWVudCBvZiBzaG9ydC10ZXJtIGdhc29saW5lIHByaWNlIGJlaGF2aW9yIHJlbGF0aXZlIHRvIGxvbmctdGVybSBoaXN0b3JpY2FsIHBhdHRlcm5zLg==