1 Introduction

The following data is from https://www.census.gov. The data set contains the number of homes sold (by the thousands) in the United States from the years 1963 to 2024. Each year contains 12 observations for each month of the year with the exception of 2024 that only has 9 observations. There are a total of 741 observations. For this analysis, we will only use the 175 most recent observations.

1.1 Variable Description

  • Period - The year and month the number of houses sold was recorded.
  • Value - The number of houses bought in the United states in thousands. (Example: 400 = 400,000 houses sold)

1.2 Practical Question

What patterns can be found in our time series and what methods of smoothing and decomposition should be used on it?

2 Exploratory Analysis

First, the data is downloaded. Next, the data is cut down to the 175 most recent observations. this means we are only using observations from the years 2010 to 2024.We also modify the Vale variable so it does not contain commas. There appears to be no missing values in the data.

house <- read.csv("https://raw.githubusercontent.com/AvaDeSt/STA-321/refs/heads/main/Book%203(Sheet1).csv", header = TRUE)
n.row = dim(house)[1]
data.house = house[(n.row-150):n.row, ]
          
data.house$Value = as.numeric(gsub(",", "", data.house$Value))

2.1 Define Time Series Object

Here is a graph of the data with the number of houses sold by the thousands on the y axis. Since the data is recorded by month. Frequency = 12 will be used to define the time series object.

house.ts = ts(data.house[,2], frequency = 12, start = c(2012, 1))
par(mar=c(2,2,2,2))
plot(house.ts, main="US Houses Bought Between March, 2012 and Sept, 2024", ylab="Houses Bought", xlab="")
US Houses Bought Monthly

US Houses Bought Monthly

We can see that the number of houses sold increases gradually throughout the years with a large spike right after 2020. The time series for the most part is additive.

3 Forecasting with Decomposing

Next, we will try forecasting using both classical decomposing and STL decomposing to see which one performs better.

cls.decomp = decompose(house.ts)
par(mar=c(2,2,2,2))
plot(cls.decomp, xlab="")
Classical decomposition of additive time series

Classical decomposition of additive time series

stl.decomp=stl(house.ts, s.window = 12)
par(mar=c(2,2,2,2))
plot(stl.decomp)
STL decomposition of additive time series

STL decomposition of additive time series

We can see that in this case, STL decomposition works a little better for our data. While the time series is additive and relatively constant, there is a large spike in the number of houses sold right after 2020, creating a few outliers. Since STL decomposition is more robust, it works better in this case.

4 Data Training and Testing

Next, we will hold the last ten periods of the data for testing. We will define four different training data sets. The training set sizes used in this analysis are 144, 109, 73, and 48. The same test set with size ten will be used to calculate the prediction error.

ini.data = data.house[,2]
n0 = length(ini.data)
##
train.data01 = data.house[1:(n0-7), 2]
train.data02 = data.house[37:(n0-7), 2]
train.data03 = data.house[73:(n0-7), 2]
train.data04 = data.house[97:(n0-7), 2]
## last 7 observations
test.data = data.house[(n0-6):n0,2]
##
train01.ts = ts(train.data01, frequency = 12, start = c(2012, 1))
train02.ts = ts(train.data02, frequency = 12, start = c(2015, 1))
train03.ts = ts(train.data03, frequency = 12, start = c(2018, 1))
train04.ts = ts(train.data04, frequency = 12, start = c(2020, 1))
##
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 with decomposing
fcst01 = forecast(stl01,h=10, method="naive")
fcst02 = forecast(stl02,h=10, method="naive")
fcst03 = forecast(stl03,h=10, method="naive")
fcst04 = forecast(stl04,h=10, method="naive")

Next, we perform error analysis.

PE01=(test.data-fcst01$mean)/fcst01$mean
## Warning in `-.default`(test.data, fcst01$mean): longer object length is not a
## multiple of shorter object length
PE02=(test.data-fcst02$mean)/fcst02$mean
## Warning in `-.default`(test.data, fcst02$mean): longer object length is not a
## multiple of shorter object length
PE03=(test.data-fcst03$mean)/fcst03$mean
## Warning in `-.default`(test.data, fcst03$mean): longer object length is not a
## multiple of shorter object length
PE04=(test.data-fcst04$mean)/fcst04$mean
## Warning in `-.default`(test.data, fcst04$mean): longer object length is not a
## multiple of shorter object length
###
MAPE1 = mean(abs(PE01))
MAPE2 = mean(abs(PE02))
MAPE3 = mean(abs(PE03))
MAPE4 = mean(abs(PE04))
###
E1=test.data-fcst01$mean
## Warning in `-.default`(test.data, fcst01$mean): longer object length is not a
## multiple of shorter object length
E2=test.data-fcst02$mean
## Warning in `-.default`(test.data, fcst02$mean): longer object length is not a
## multiple of shorter object length
E3=test.data-fcst03$mean
## Warning in `-.default`(test.data, fcst03$mean): longer object length is not a
## multiple of shorter object length
E4=test.data-fcst04$mean
## Warning in `-.default`(test.data, fcst04$mean): longer object length is not a
## multiple of shorter object length
##
MSE1=mean(E1^2)
MSE2=mean(E2^2)
MSE3=mean(E3^2)
MSE4=mean(E4^2)
###
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.109", "n. 73", "n. 48")
kable(accuracy, caption="Error comparison between forecast results with different sample sizes")
Error comparison between forecast results with different sample sizes
MSE MAPE
n.144 3528.487 0.0802875
n.109 3491.738 0.0795013
n. 73 3965.483 0.0852145
n. 48 5327.657 0.1013145

We can see from the table above that a training size of 109 performs the best and has the lowest errors. While the mean square errors look normal, the mean absolute percentage error is well into the thousands. Some possible reasons for this are the observations in our time series ranges from about 300 to a little over one thousand. The time series also follows several patterns including seasonal trends and being additive. We will take a closer look at the errors next by making one graph for the MSE and one for the MAPE.

par(mfrow=c(1,2))
plot(1:4, MSE, type="b", col="darkred", ylab="Error", xlab="",
     #ylim=c(0.4,.85),xlim = c(0.5,4.5), 
     main="MSE", axes=FALSE)
labs=c("n=144", "n=109", "n=73", "n=48")
axis(1, at=1:4, label=labs)
axis(2)
#lines(1:4, MAPE, type="b", col="blue")
text(1:4, MAPE+0.03, as.character(round(MAPE,4)), col="blue", cex=0.7)
text(1:4, MSE-0.03, as.character(round(MSE,4)), col="darkred", cex=0.7)
legend(1.5, 0.63, c("MSE", "MAPE"), col=c("darkred","blue"), lty=1, bty="n", cex=0.7)
###
#```{r fig.align='center', fig.cap= "Comparing forecast errors", fig.width=5, fig.height=3.5}
plot(1:4, MAPE, type="b", col="darkred", ylab="Error", xlab="",
     #ylim=c(0.4,.85),xlim = c(0.5,4.5), 
     main="MAPE", axes=FALSE)
labs=c("n=144", "n=109", "n=73", "n=48")
axis(1, at=1:4, label=labs)
axis(2)
Comparing forecast errors

Comparing forecast errors

5 Summary and Conclusion

To conclude, we examined a time series from the years 2012 to 2024 totaling 151 observations. The data looks at the number of houses sold in the United States for each month of the years recorded. We noticed that the time series follows a mostly seasonal trend that is additive. The only exception was a spike in the observations after 2020 that eventually went back down. We found that STL decomposition works better for this time series because it is more robust. Were this analysis to be continued in the future, I would focus on reducing the MAPE. A way I would try to do this would be by using a different model that accounts more for seasonal patterns and possibly outliers that do not follow a pattern since this time series contains a few.

LS0tDQp0aXRsZTogVGltZSBTZXJpZXMgRGVjb21wb3NpdGlvbiBmb3IgSG91c2VzIFNvbGQgaW4gdGhlIFVTDQphdXRob3I6ICJBdmEgRGVTdGVmYW5vIg0KZGF0ZTogIjExLTI0LTI0Ig0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDogeWVzDQogICAgdG9jX2RlcHRoOiA0DQogICAgZmlnX3dpZHRoOiA2DQogICAgZmlnX2hlaWdodDogNA0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIHRvY19jb2xsYXBzZWQ6IHllcw0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIHNtb290aF9zY3JvbGw6IHllcw0KICAgIHRoZW1lOiBsdW1lbg0KICAgIGRmX3ByaW50OiBrYWJsZQ0KICB3b3JkX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBrZWVwX21kOiB5ZXMNCiAgcGRmX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIGZpZ193aWR0aDogNQ0KICAgIGZpZ19oZWlnaHQ6IDQNCi0tLQ0KDQpgYGB7PWh0bWx9DQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPg0KDQpkaXYjVE9DIGxpIHsNCiAgICBsaXN0LXN0eWxlOm5vbmU7DQogICAgYmFja2dyb3VuZC1pbWFnZTpub25lOw0KICAgIGJhY2tncm91bmQtcmVwZWF0Om5vbmU7DQogICAgYmFja2dyb3VuZC1wb3NpdGlvbjowOw0KfQ0KDQpoMS50aXRsZSB7DQogIGZvbnQtc2l6ZTogMjRweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGNvbG9yOiBEYXJrUmVkOw0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQpoNC5hdXRob3IgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICAgIGZvbnQtc2l6ZTogMThweDsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCiAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogIGNvbG9yOiBEYXJrUmVkOw0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQpoNC5kYXRlIHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgZm9udC1zaXplOiAxOHB4Ow0KICBmb250LXdlaWdodDogYm9sZDsNCiAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogIGNvbG9yOiBEYXJrQmx1ZTsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KaDEgeyAvKiBIZWFkZXIgMyAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICAgIGZvbnQtc2l6ZTogMjJweDsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogZGFya3JlZDsNCiAgICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQpoMiB7IC8qIEhlYWRlciAzIC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogICAgZm9udC1zaXplOiAxOHB4Ow0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCmgzIHsgLyogSGVhZGVyIDMgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDE1cHg7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IG5hdnk7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KaDQgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICAgIGZvbnQtc2l6ZTogMThweDsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogZGFya3JlZDsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KPC9zdHlsZT4NCmBgYA0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCiMgY29kZSBjaHVuayBzcGVjaWZpZXMgd2hldGhlciB0aGUgUiBjb2RlLCB3YXJuaW5ncywgYW5kIG91dHB1dCANCiMgd2lsbCBiZSBpbmNsdWRlZCBpbiB0aGUgb3V0cHV0IGZpbGVzLg0KaWYgKCFyZXF1aXJlKCJJU3dSIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoIklTd1IiKQ0KICAgbGlicmFyeShJU3dSKQ0KfQ0KaWYgKCFyZXF1aXJlKCJNQVNTIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoIk1BU1MiKQ0KICAgbGlicmFyeShNQVNTKQ0KfQ0KaWYgKCFyZXF1aXJlKCJrbml0ciIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJrbml0ciIpDQogICBsaWJyYXJ5KGtuaXRyKQ0KfQ0KaWYgKCFyZXF1aXJlKCJmb3JlY2FzdCIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJmb3JlY2FzdCIpDQogICBsaWJyYXJ5KGZvcmVjYXN0KQ0KfQ0KDQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgIHdhcm5pbmdzID0gRkFMU0UsICAgDQogICAgICAgICAgICAgICAgICAgICAgcmVzdWx0cyA9IFRSVUUsICAgDQogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFLA0KICAgICAgICAgICAgICAgICAgICAgIGZpZy5hbGlnbj0nY2VudGVyJywgDQogICAgICAgICAgICAgICAgICAgICAgZmlnLnBvcyA9ICdodCcpDQpgYGANCg0KIyBJbnRyb2R1Y3Rpb24NCg0KVGhlIGZvbGxvd2luZyBkYXRhIGlzIGZyb20gaHR0cHM6Ly93d3cuY2Vuc3VzLmdvdi4gVGhlIGRhdGEgc2V0IGNvbnRhaW5zIHRoZSBudW1iZXIgb2YgaG9tZXMgc29sZCAoYnkgdGhlIHRob3VzYW5kcykgaW4gdGhlIFVuaXRlZCBTdGF0ZXMgZnJvbSB0aGUgeWVhcnMgMTk2MyB0byAyMDI0LiBFYWNoIHllYXIgY29udGFpbnMgMTIgb2JzZXJ2YXRpb25zIGZvciBlYWNoIG1vbnRoIG9mIHRoZSB5ZWFyIHdpdGggdGhlIGV4Y2VwdGlvbiBvZiAyMDI0IHRoYXQgb25seSBoYXMgOSBvYnNlcnZhdGlvbnMuIFRoZXJlIGFyZSBhIHRvdGFsIG9mIDc0MSBvYnNlcnZhdGlvbnMuIEZvciB0aGlzIGFuYWx5c2lzLCB3ZSB3aWxsIG9ubHkgdXNlIHRoZSAxNzUgbW9zdCByZWNlbnQgb2JzZXJ2YXRpb25zLg0KDQojIyBWYXJpYWJsZSBEZXNjcmlwdGlvbg0KDQoqIFBlcmlvZCAtIFRoZSB5ZWFyIGFuZCBtb250aCB0aGUgbnVtYmVyIG9mIGhvdXNlcyBzb2xkIHdhcyByZWNvcmRlZC4NCiogVmFsdWUgLSBUaGUgbnVtYmVyIG9mIGhvdXNlcyBib3VnaHQgaW4gdGhlIFVuaXRlZCBzdGF0ZXMgaW4gdGhvdXNhbmRzLiAoRXhhbXBsZTogNDAwID0gNDAwLDAwMCBob3VzZXMgc29sZCkNCg0KIyMgUHJhY3RpY2FsIFF1ZXN0aW9uDQoNCldoYXQgcGF0dGVybnMgY2FuIGJlIGZvdW5kIGluIG91ciB0aW1lIHNlcmllcyBhbmQgd2hhdCBtZXRob2RzIG9mIHNtb290aGluZyBhbmQgZGVjb21wb3NpdGlvbiBzaG91bGQgYmUgdXNlZCBvbiBpdD8gDQoNCiMgRXhwbG9yYXRvcnkgQW5hbHlzaXMNCg0KRmlyc3QsIHRoZSBkYXRhIGlzIGRvd25sb2FkZWQuIE5leHQsIHRoZSBkYXRhIGlzIGN1dCBkb3duIHRvIHRoZSAxNzUgbW9zdCByZWNlbnQgb2JzZXJ2YXRpb25zLiB0aGlzIG1lYW5zIHdlIGFyZSBvbmx5IHVzaW5nIG9ic2VydmF0aW9ucyBmcm9tIHRoZSB5ZWFycyAyMDEwIHRvIDIwMjQuV2UgYWxzbyBtb2RpZnkgdGhlIFZhbGUgdmFyaWFibGUgc28gaXQgZG9lcyBub3QgY29udGFpbiBjb21tYXMuIFRoZXJlIGFwcGVhcnMgdG8gYmUgbm8gbWlzc2luZyB2YWx1ZXMgaW4gdGhlIGRhdGEuIA0KDQpgYGB7cn0NCmhvdXNlIDwtIHJlYWQuY3N2KCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vQXZhRGVTdC9TVEEtMzIxL3JlZnMvaGVhZHMvbWFpbi9Cb29rJTIwMyhTaGVldDEpLmNzdiIsIGhlYWRlciA9IFRSVUUpDQpuLnJvdyA9IGRpbShob3VzZSlbMV0NCmRhdGEuaG91c2UgPSBob3VzZVsobi5yb3ctMTUwKTpuLnJvdywgXQ0KICAgICAgICAgIA0KZGF0YS5ob3VzZSRWYWx1ZSA9IGFzLm51bWVyaWMoZ3N1YigiLCIsICIiLCBkYXRhLmhvdXNlJFZhbHVlKSkNCmBgYA0KDQojIyBEZWZpbmUgVGltZSBTZXJpZXMgT2JqZWN0DQoNCkhlcmUgaXMgYSBncmFwaCBvZiB0aGUgZGF0YSB3aXRoIHRoZSBudW1iZXIgb2YgaG91c2VzIHNvbGQgYnkgdGhlIHRob3VzYW5kcyBvbiB0aGUgeSBheGlzLiBTaW5jZSB0aGUgZGF0YSBpcyByZWNvcmRlZCBieSBtb250aC4gRnJlcXVlbmN5ID0gMTIgd2lsbCBiZSB1c2VkIHRvIGRlZmluZSB0aGUgdGltZSBzZXJpZXMgb2JqZWN0LiANCg0KYGBge3IgIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTcsIGZpZy5oZWlnaHQ9IDMsIGZpZy5jYXA9IlVTIEhvdXNlcyBCb3VnaHQgTW9udGhseSJ9DQpob3VzZS50cyA9IHRzKGRhdGEuaG91c2VbLDJdLCBmcmVxdWVuY3kgPSAxMiwgc3RhcnQgPSBjKDIwMTIsIDEpKQ0KcGFyKG1hcj1jKDIsMiwyLDIpKQ0KcGxvdChob3VzZS50cywgbWFpbj0iVVMgSG91c2VzIEJvdWdodCBCZXR3ZWVuIE1hcmNoLCAyMDEyIGFuZCBTZXB0LCAyMDI0IiwgeWxhYj0iSG91c2VzIEJvdWdodCIsIHhsYWI9IiIpDQpgYGANCg0KV2UgY2FuIHNlZSB0aGF0IHRoZSBudW1iZXIgb2YgaG91c2VzIHNvbGQgaW5jcmVhc2VzIGdyYWR1YWxseSB0aHJvdWdob3V0IHRoZSB5ZWFycyB3aXRoIGEgbGFyZ2Ugc3Bpa2UgcmlnaHQgYWZ0ZXIgMjAyMC4gVGhlIHRpbWUgc2VyaWVzIGZvciB0aGUgbW9zdCBwYXJ0IGlzIGFkZGl0aXZlLiANCg0KIyBGb3JlY2FzdGluZyB3aXRoIERlY29tcG9zaW5nIA0KDQpOZXh0LCB3ZSB3aWxsIHRyeSBmb3JlY2FzdGluZyB1c2luZyBib3RoIGNsYXNzaWNhbCBkZWNvbXBvc2luZyBhbmQgU1RMIGRlY29tcG9zaW5nIHRvIHNlZSB3aGljaCBvbmUgcGVyZm9ybXMgYmV0dGVyLiANCg0KYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcuY2FwPSAiQ2xhc3NpY2FsIGRlY29tcG9zaXRpb24gb2YgYWRkaXRpdmUgdGltZSBzZXJpZXMiLCBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD00fQ0KY2xzLmRlY29tcCA9IGRlY29tcG9zZShob3VzZS50cykNCnBhcihtYXI9YygyLDIsMiwyKSkNCnBsb3QoY2xzLmRlY29tcCwgeGxhYj0iIikNCmBgYA0KYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcuY2FwPSAiU1RMIGRlY29tcG9zaXRpb24gb2YgYWRkaXRpdmUgdGltZSBzZXJpZXMiLCBmaWcud2lkdGg9NywgZmlnLmhlaWdodD00fQ0Kc3RsLmRlY29tcD1zdGwoaG91c2UudHMsIHMud2luZG93ID0gMTIpDQpwYXIobWFyPWMoMiwyLDIsMikpDQpwbG90KHN0bC5kZWNvbXApDQpgYGANCldlIGNhbiBzZWUgdGhhdCBpbiB0aGlzIGNhc2UsIFNUTCBkZWNvbXBvc2l0aW9uIHdvcmtzIGEgbGl0dGxlIGJldHRlciBmb3Igb3VyIGRhdGEuIFdoaWxlIHRoZSB0aW1lIHNlcmllcyBpcyBhZGRpdGl2ZSBhbmQgcmVsYXRpdmVseSBjb25zdGFudCwgdGhlcmUgaXMgYSBsYXJnZSBzcGlrZSBpbiB0aGUgbnVtYmVyIG9mIGhvdXNlcyBzb2xkIHJpZ2h0IGFmdGVyIDIwMjAsIGNyZWF0aW5nIGEgZmV3IG91dGxpZXJzLiBTaW5jZSBTVEwgZGVjb21wb3NpdGlvbiBpcyBtb3JlIHJvYnVzdCwgaXQgd29ya3MgYmV0dGVyIGluIHRoaXMgY2FzZS4gDQoNCiMgRGF0YSBUcmFpbmluZyBhbmQgVGVzdGluZw0KDQpOZXh0LCB3ZSB3aWxsIGhvbGQgdGhlIGxhc3QgdGVuIHBlcmlvZHMgb2YgdGhlIGRhdGEgZm9yIHRlc3RpbmcuIFdlIHdpbGwgZGVmaW5lICBmb3VyIGRpZmZlcmVudCB0cmFpbmluZyBkYXRhIHNldHMuIFRoZSB0cmFpbmluZyBzZXQgc2l6ZXMgdXNlZCBpbiB0aGlzIGFuYWx5c2lzIGFyZSAxNDQsIDEwOSwgNzMsIGFuZCA0OC4gVGhlIHNhbWUgdGVzdCBzZXQgd2l0aCBzaXplIHRlbiB3aWxsIGJlIHVzZWQgdG8gY2FsY3VsYXRlIHRoZSBwcmVkaWN0aW9uIGVycm9yLg0KDQpgYGB7cn0NCmluaS5kYXRhID0gZGF0YS5ob3VzZVssMl0NCm4wID0gbGVuZ3RoKGluaS5kYXRhKQ0KIyMNCnRyYWluLmRhdGEwMSA9IGRhdGEuaG91c2VbMToobjAtNyksIDJdDQp0cmFpbi5kYXRhMDIgPSBkYXRhLmhvdXNlWzM3OihuMC03KSwgMl0NCnRyYWluLmRhdGEwMyA9IGRhdGEuaG91c2VbNzM6KG4wLTcpLCAyXQ0KdHJhaW4uZGF0YTA0ID0gZGF0YS5ob3VzZVs5NzoobjAtNyksIDJdDQojIyBsYXN0IDcgb2JzZXJ2YXRpb25zDQp0ZXN0LmRhdGEgPSBkYXRhLmhvdXNlWyhuMC02KTpuMCwyXQ0KIyMNCnRyYWluMDEudHMgPSB0cyh0cmFpbi5kYXRhMDEsIGZyZXF1ZW5jeSA9IDEyLCBzdGFydCA9IGMoMjAxMiwgMSkpDQp0cmFpbjAyLnRzID0gdHModHJhaW4uZGF0YTAyLCBmcmVxdWVuY3kgPSAxMiwgc3RhcnQgPSBjKDIwMTUsIDEpKQ0KdHJhaW4wMy50cyA9IHRzKHRyYWluLmRhdGEwMywgZnJlcXVlbmN5ID0gMTIsIHN0YXJ0ID0gYygyMDE4LCAxKSkNCnRyYWluMDQudHMgPSB0cyh0cmFpbi5kYXRhMDQsIGZyZXF1ZW5jeSA9IDEyLCBzdGFydCA9IGMoMjAyMCwgMSkpDQojIw0Kc3RsMDEgPSBzdGwodHJhaW4wMS50cywgcy53aW5kb3cgPSAxMikNCnN0bDAyID0gc3RsKHRyYWluMDIudHMsIHMud2luZG93ID0gMTIpDQpzdGwwMyA9IHN0bCh0cmFpbjAzLnRzLCBzLndpbmRvdyA9IDEyKQ0Kc3RsMDQgPSBzdGwodHJhaW4wNC50cywgcy53aW5kb3cgPSAxMikNCiMjIEZvcmVjYXN0IHdpdGggZGVjb21wb3NpbmcNCmZjc3QwMSA9IGZvcmVjYXN0KHN0bDAxLGg9MTAsIG1ldGhvZD0ibmFpdmUiKQ0KZmNzdDAyID0gZm9yZWNhc3Qoc3RsMDIsaD0xMCwgbWV0aG9kPSJuYWl2ZSIpDQpmY3N0MDMgPSBmb3JlY2FzdChzdGwwMyxoPTEwLCBtZXRob2Q9Im5haXZlIikNCmZjc3QwNCA9IGZvcmVjYXN0KHN0bDA0LGg9MTAsIG1ldGhvZD0ibmFpdmUiKQ0KDQpgYGANCg0KTmV4dCwgd2UgcGVyZm9ybSBlcnJvciBhbmFseXNpcy4NCg0KYGBge3J9DQpQRTAxPSh0ZXN0LmRhdGEtZmNzdDAxJG1lYW4pL2Zjc3QwMSRtZWFuDQpQRTAyPSh0ZXN0LmRhdGEtZmNzdDAyJG1lYW4pL2Zjc3QwMiRtZWFuDQpQRTAzPSh0ZXN0LmRhdGEtZmNzdDAzJG1lYW4pL2Zjc3QwMyRtZWFuDQpQRTA0PSh0ZXN0LmRhdGEtZmNzdDA0JG1lYW4pL2Zjc3QwNCRtZWFuDQojIyMNCk1BUEUxID0gbWVhbihhYnMoUEUwMSkpDQpNQVBFMiA9IG1lYW4oYWJzKFBFMDIpKQ0KTUFQRTMgPSBtZWFuKGFicyhQRTAzKSkNCk1BUEU0ID0gbWVhbihhYnMoUEUwNCkpDQojIyMNCkUxPXRlc3QuZGF0YS1mY3N0MDEkbWVhbg0KRTI9dGVzdC5kYXRhLWZjc3QwMiRtZWFuDQpFMz10ZXN0LmRhdGEtZmNzdDAzJG1lYW4NCkU0PXRlc3QuZGF0YS1mY3N0MDQkbWVhbg0KIyMNCk1TRTE9bWVhbihFMV4yKQ0KTVNFMj1tZWFuKEUyXjIpDQpNU0UzPW1lYW4oRTNeMikNCk1TRTQ9bWVhbihFNF4yKQ0KIyMjDQpNU0U9YyhNU0UxLCBNU0UyLCBNU0UzLCBNU0U0KQ0KTUFQRT1jKE1BUEUxLCBNQVBFMiwgTUFQRTMsIE1BUEU0KQ0KYWNjdXJhY3k9Y2JpbmQoTVNFPU1TRSwgTUFQRT1NQVBFKQ0Kcm93Lm5hbWVzKGFjY3VyYWN5KT1jKCJuLjE0NCIsICJuLjEwOSIsICJuLiA3MyIsICJuLiA0OCIpDQprYWJsZShhY2N1cmFjeSwgY2FwdGlvbj0iRXJyb3IgY29tcGFyaXNvbiBiZXR3ZWVuIGZvcmVjYXN0IHJlc3VsdHMgd2l0aCBkaWZmZXJlbnQgc2FtcGxlIHNpemVzIikNCmBgYA0KDQpXZSBjYW4gc2VlIGZyb20gdGhlIHRhYmxlIGFib3ZlIHRoYXQgYSB0cmFpbmluZyBzaXplIG9mIDEwOSBwZXJmb3JtcyB0aGUgYmVzdCBhbmQgaGFzIHRoZSBsb3dlc3QgZXJyb3JzLiBXaGlsZSB0aGUgbWVhbiBzcXVhcmUgZXJyb3JzIGxvb2sgbm9ybWFsLCB0aGUgbWVhbiBhYnNvbHV0ZSBwZXJjZW50YWdlIGVycm9yIGlzIHdlbGwgaW50byB0aGUgdGhvdXNhbmRzLiBTb21lIHBvc3NpYmxlIHJlYXNvbnMgZm9yIHRoaXMgYXJlIHRoZSBvYnNlcnZhdGlvbnMgaW4gb3VyIHRpbWUgc2VyaWVzIHJhbmdlcyBmcm9tIGFib3V0IDMwMCB0byBhIGxpdHRsZSBvdmVyIG9uZSB0aG91c2FuZC4gVGhlIHRpbWUgc2VyaWVzIGFsc28gZm9sbG93cyBzZXZlcmFsIHBhdHRlcm5zIGluY2x1ZGluZyBzZWFzb25hbCB0cmVuZHMgYW5kIGJlaW5nIGFkZGl0aXZlLiBXZSB3aWxsIHRha2UgYSBjbG9zZXIgbG9vayBhdCB0aGUgZXJyb3JzIG5leHQgYnkgbWFraW5nIG9uZSBncmFwaCBmb3IgdGhlIE1TRSBhbmQgb25lIGZvciB0aGUgTUFQRS4gDQoNCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLmNhcD0gIkNvbXBhcmluZyBmb3JlY2FzdCBlcnJvcnMiLCBmaWcud2lkdGg9NywgZmlnLmhlaWdodD00fQ0KcGFyKG1mcm93PWMoMSwyKSkNCnBsb3QoMTo0LCBNU0UsIHR5cGU9ImIiLCBjb2w9ImRhcmtyZWQiLCB5bGFiPSJFcnJvciIsIHhsYWI9IiIsDQogICAgICN5bGltPWMoMC40LC44NSkseGxpbSA9IGMoMC41LDQuNSksIA0KICAgICBtYWluPSJNU0UiLCBheGVzPUZBTFNFKQ0KbGFicz1jKCJuPTE0NCIsICJuPTEwOSIsICJuPTczIiwgIm49NDgiKQ0KYXhpcygxLCBhdD0xOjQsIGxhYmVsPWxhYnMpDQpheGlzKDIpDQojbGluZXMoMTo0LCBNQVBFLCB0eXBlPSJiIiwgY29sPSJibHVlIikNCnRleHQoMTo0LCBNQVBFKzAuMDMsIGFzLmNoYXJhY3Rlcihyb3VuZChNQVBFLDQpKSwgY29sPSJibHVlIiwgY2V4PTAuNykNCnRleHQoMTo0LCBNU0UtMC4wMywgYXMuY2hhcmFjdGVyKHJvdW5kKE1TRSw0KSksIGNvbD0iZGFya3JlZCIsIGNleD0wLjcpDQpsZWdlbmQoMS41LCAwLjYzLCBjKCJNU0UiLCAiTUFQRSIpLCBjb2w9YygiZGFya3JlZCIsImJsdWUiKSwgbHR5PTEsIGJ0eT0ibiIsIGNleD0wLjcpDQojIyMNCiNgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy5jYXA9ICJDb21wYXJpbmcgZm9yZWNhc3QgZXJyb3JzIiwgZmlnLndpZHRoPTUsIGZpZy5oZWlnaHQ9My41fQ0KcGxvdCgxOjQsIE1BUEUsIHR5cGU9ImIiLCBjb2w9ImRhcmtyZWQiLCB5bGFiPSJFcnJvciIsIHhsYWI9IiIsDQogICAgICN5bGltPWMoMC40LC44NSkseGxpbSA9IGMoMC41LDQuNSksIA0KICAgICBtYWluPSJNQVBFIiwgYXhlcz1GQUxTRSkNCmxhYnM9Yygibj0xNDQiLCAibj0xMDkiLCAibj03MyIsICJuPTQ4IikNCmF4aXMoMSwgYXQ9MTo0LCBsYWJlbD1sYWJzKQ0KYXhpcygyKQ0KYGBgDQoNCiMgU3VtbWFyeSBhbmQgQ29uY2x1c2lvbg0KDQpUbyBjb25jbHVkZSwgd2UgZXhhbWluZWQgYSB0aW1lIHNlcmllcyBmcm9tIHRoZSB5ZWFycyAyMDEyIHRvIDIwMjQgdG90YWxpbmcgMTUxIG9ic2VydmF0aW9ucy4gVGhlIGRhdGEgbG9va3MgYXQgdGhlIG51bWJlciBvZiBob3VzZXMgc29sZCBpbiB0aGUgVW5pdGVkIFN0YXRlcyBmb3IgZWFjaCBtb250aCBvZiB0aGUgeWVhcnMgcmVjb3JkZWQuIFdlIG5vdGljZWQgdGhhdCB0aGUgdGltZSBzZXJpZXMgZm9sbG93cyBhIG1vc3RseSBzZWFzb25hbCB0cmVuZCB0aGF0IGlzIGFkZGl0aXZlLiBUaGUgb25seSBleGNlcHRpb24gd2FzIGEgc3Bpa2UgaW4gdGhlIG9ic2VydmF0aW9ucyBhZnRlciAyMDIwIHRoYXQgZXZlbnR1YWxseSB3ZW50IGJhY2sgZG93bi4gV2UgZm91bmQgdGhhdCBTVEwgZGVjb21wb3NpdGlvbiB3b3JrcyBiZXR0ZXIgZm9yIHRoaXMgdGltZSBzZXJpZXMgYmVjYXVzZSBpdCBpcyBtb3JlIHJvYnVzdC4gV2VyZSB0aGlzIGFuYWx5c2lzIHRvIGJlIGNvbnRpbnVlZCBpbiB0aGUgZnV0dXJlLCBJIHdvdWxkIGZvY3VzIG9uIHJlZHVjaW5nIHRoZSBNQVBFLiBBIHdheSBJIHdvdWxkIHRyeSB0byBkbyB0aGlzIHdvdWxkIGJlIGJ5IHVzaW5nIGEgZGlmZmVyZW50IG1vZGVsIHRoYXQgYWNjb3VudHMgbW9yZSBmb3Igc2Vhc29uYWwgcGF0dGVybnMgYW5kIHBvc3NpYmx5IG91dGxpZXJzIHRoYXQgZG8gbm90IGZvbGxvdyBhIHBhdHRlcm4gc2luY2UgdGhpcyB0aW1lIHNlcmllcyBjb250YWlucyBhIGZldy4gDQoNCg==