Methodolgy &
Analysis
For this project, we want to determine the best exponential smoothing
model to use for this data set. To determine the best smoothing model we
are going to compare the accuracy of several different models, SES,
Holt, Holt-Winters and some additive, exponential and damped variations
of Holt and Holt-Winters.
test.homes = data.home.sales$Value[166:177]
train.homes = data.home.sales$Value[1:165]
home=ts(data.home.sales$Value[1:168], start=100, frequency = 12)
fit1 = ses(home, h=12)
fit2 = holt(home, initial="optimal", h=12) ## optimal alpha and beta
fit3 = holt(home,damped=TRUE, h=12 ) ## additive damping
fit4 = holt(home,exponential=TRUE, damped=TRUE, h =12) ## multiplicative damp
fit5 = hw(home,h=12, seasonal="additive") ## default h = 10
fit6 = hw(home,h=12, seasonal="multiplicative")
fit7 = hw(home,h=12, seasonal="additive",damped=TRUE)
fit8 = hw(home,h=12, seasonal="multiplicative",damped=TRUE)
accuracy.table = round(rbind(accuracy(fit1), accuracy(fit2), accuracy(fit3), accuracy(fit4),
accuracy(fit5), accuracy(fit6), accuracy(fit7), accuracy(fit8)),4)
row.names(accuracy.table)=c("SES","Holt Linear","Holt Add. Damped", "Holt Exp. Damped",
"HW Add.","HW Exp.","HW Add. Damp", "HW Exp. Damp")
kable(accuracy.table, caption = "The accuracy measures of various exponential smoothing models
based on the training data")
The accuracy measures of various exponential smoothing models
based on the training data
SES |
2.2136 |
48.4549 |
35.2626 |
0.0553 |
6.2339 |
0.4093 |
0.0004 |
Holt Linear |
-0.1598 |
48.4565 |
35.3792 |
-0.4352 |
6.2890 |
0.4106 |
0.0035 |
Holt Add. Damped |
2.2835 |
48.4843 |
35.4168 |
0.0809 |
6.2728 |
0.4111 |
0.0011 |
Holt Exp. Damped |
2.6742 |
48.4464 |
35.3365 |
0.2005 |
6.2397 |
0.4101 |
-0.0002 |
HW Add. |
-0.5234 |
48.3285 |
34.9578 |
-0.4813 |
6.1911 |
0.4057 |
0.0029 |
HW Exp. |
1.1751 |
53.2488 |
37.2653 |
-0.2176 |
6.6320 |
0.4325 |
0.2248 |
HW Add. Damp |
1.4851 |
48.3832 |
35.1746 |
-0.1231 |
6.2356 |
0.4082 |
0.0022 |
HW Exp. Damp |
1.0625 |
48.5948 |
35.5074 |
-0.1541 |
6.2970 |
0.4121 |
0.0241 |
Looking at the results from the table above, it seems like the
Holt-Winters additive model appears to be the most appropriate
exponential smoothing model. The Holt-Winters beats out the other models
in every situation except on where it gets beat out by Holt Exponential
Dampened.
In addition to the accuracy table above, it is also beneficial to see
a visual representation of the different exponential smoothing models
options and compare them to the original serial plot.
par(mfrow=c(2,1), mar=c(3,4,3,1))
###### plot the original data
pred.id = 166:177
plot(1:165, train.homes, lwd=2,type="o", ylab="Home Sales", xlab="",
xlim=c(1,177), ylim=c(200, 1200), cex=0.3,
main="Non-Seasonal Smoothing Models")
lines(pred.id, fit1$mean, col="red")
lines(pred.id, fit2$mean, col="blue")
lines(pred.id, fit3$mean, col="purple")
lines(pred.id, fit4$mean, col="navy")
##
points(pred.id, fit1$mean, pch=16, col="red", cex = 0.5)
points(pred.id, fit2$mean, pch=17, col="blue", cex = 0.5)
points(pred.id, fit3$mean, pch=19, col="purple", cex = 0.5)
points(pred.id, fit4$mean, pch=21, col="navy", cex = 0.5)
#points(fit0, col="black", pch=1)
legend("bottomright", lty=1, col=c("red","blue","purple", "navy"),pch=c(16,17,19,21),
c("SES","Holt Linear","Holt Linear Damped", "Holt Multiplicative Damped"),
cex = 0.7, bty="n")
###########
plot(1:165, train.homes, lwd=2,type="o", ylab="Home Sales", xlab="",
xlim=c(1,177), ylim=c(200, 1200), cex=0.3,
main="Holt-Winterd Trend and Seasonal Smoothing Models")
lines(pred.id, fit5$mean, col="red")
lines(pred.id, fit6$mean, col="blue")
lines(pred.id, fit7$mean, col="purple")
lines(pred.id, fit8$mean, col="navy")
##
points(pred.id, fit5$mean, pch=16, col="red", cex = 0.5)
points(pred.id, fit6$mean, pch=17, col="blue", cex = 0.5)
points(pred.id, fit7$mean, pch=19, col="purple", cex = 0.5)
points(pred.id, fit8$mean, pch=21, col="navy", cex = 0.5)
###
legend("bottomright", lty=1, col=c("red","blue","purple", "navy"),pch=c(16,17,19,21),
c("HW Additive","HW Multiplicative","HW Additive Damped", "HW Multiplicative Damped"),
cex = 0.7, bty="n")
Looking at the graphs above the first depiction shows the predictive
lines to almost go fully horizontal, or mainly horizontal with minimal
slope. However, the second graph does show predictive lines with more of
a shape and potential variation that is consistent with the information
seen in the existing serial plot. The Holt-Winters Additive line is
within the second graph, further cementing it as the most appropriate
model.
This assignment is also using a training data set, which will be used
to identify the best model, with the assistance of the testing data set.
In order to use the model for real-forecast, the model needs to be refit
using the entire data to update the final working models smoothing
parameters.
acc.fun = function(test.data, mod.obj){
PE=100*(test.data-mod.obj$mean)/mod.obj$mean
MAPE = mean(abs(PE))
###
E=test.data-mod.obj$mean
MSE=mean(E^2)
###
accuracy.metric=c(MSE=MSE, MAPE=MAPE)
accuracy.metric
}
pred.accuracy = rbind(SES =acc.fun(test.data=test.homes, mod.obj=fit1),
Holt.Add =acc.fun(test.data=test.homes, mod.obj=fit2),
Holt.Add.Damp =acc.fun(test.data=test.homes, mod.obj=fit3),
Holt.Exp =acc.fun(test.data=test.homes, mod.obj=fit4),
HW.Add =acc.fun(test.data=test.homes, mod.obj=fit5),
HW.Exp =acc.fun(test.data=test.homes, mod.obj=fit6),
HW.Add.Damp =acc.fun(test.data=test.homes, mod.obj=fit7),
HW.Exp.Damp =acc.fun(test.data=test.homes, mod.obj=fit8))
kable(pred.accuracy, caption="The accuracy measures of various exponential smoothing models
based on the testing data")
The accuracy measures of various exponential smoothing models
based on the testing data
SES |
2510.071 |
6.258430 |
Holt.Add |
1554.106 |
4.657823 |
Holt.Add.Damp |
2512.571 |
6.262516 |
Holt.Exp |
2511.084 |
6.260095 |
HW.Add |
1737.009 |
5.053927 |
HW.Exp |
2306.645 |
6.038416 |
HW.Add.Damp |
3082.966 |
7.147686 |
HW.Exp.Damp |
3664.936 |
8.133387 |
Looking at the above accuracy table, we actually see that the Holt
Additive is the best of the eight smoothing models, with Holt-Winters
Additive being a close second. This does come as a surprise considering
the Holt-Winters Additive model has been performing better so far. Since
the Holt-Winters Additive model was more often the preferred model, over
Holt Additive, and since Holt-Winters is a close second here, we are
going to move forward using this model. However, it is still important
to acknowledge that the above accuracy table does not identify this as
the number one model choice.
LS0tCnRpdGxlOiAiRXhwb25lbnRpYWwgU21vb3RoaW5nIG9mIGEgVGltZSBTZXJpZXMgd2l0aCBUcmVuZCBhbmQgU2Vhc29uYWxpdHkgZm9yIE5ldyBIb21lIFNhbGVzIgphdXRob3I6ICJDaGxvw6kgV2ludGVycyIKZGF0ZTogIjIwMjQtMTItMTEiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCiAgICB0b2NfZGVwdGg6IDQKICAgIGZpZ193aWR0aDogNgogICAgZmlnX2hlaWdodDogNAogICAgZmlnX2NhcHRpb246IHllcwogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKICAgIHRvY19jb2xsYXBzZWQ6IHllcwogICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMKICAgIHNtb290aF9zY3JvbGw6IHllcwogICAgdGhlbWU6IGx1bWVuCiAgcGRmX2RvY3VtZW50OiAKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDQKICAgIGZpZ19jYXB0aW9uOiB5ZXMKICAgIG51bWJlcl9zZWN0aW9uczogeWVzCiAgd29yZF9kb2N1bWVudDoKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6ICc0JwotLS0KCmBgYHs9aHRtbH0KCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+CgovKiBDYXNjYWRpbmcgU3R5bGUgU2hlZXRzIChDU1MpIGlzIGEgc3R5bGVzaGVldCBsYW5ndWFnZSB1c2VkIHRvIGRlc2NyaWJlIHRoZSBwcmVzZW50YXRpb24gb2YgYSBkb2N1bWVudCB3cml0dGVuIGluIEhUTUwgb3IgWE1MLiBpdCBpcyBhIHNpbXBsZSBtZWNoYW5pc20gZm9yIGFkZGluZyBzdHlsZSAoZS5nLiwgZm9udHMsIGNvbG9ycywgc3BhY2luZykgdG8gV2ViIGRvY3VtZW50cy4gKi8KCmgxLnRpdGxlIHsgIC8qIFRpdGxlIC0gZm9udCBzcGVjaWZpY2F0aW9ucyBvZiB0aGUgcmVwb3J0IHRpdGxlICovCiAgZm9udC1zaXplOiAyNHB4OwogIGNvbG9yOiBEYXJrUmVkOwogIHRleHQtYWxpZ246IGNlbnRlcjsKICBmb250LWZhbWlseTogIkdpbGwgU2FucyIsIHNhbnMtc2VyaWY7Cn0KaDQuYXV0aG9yIHsgLyogSGVhZGVyIDQgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciBhdXRob3JzICAqLwogIGZvbnQtc2l6ZTogMjBweDsKICBmb250LWZhbWlseTogc3lzdGVtLXVpOwogIGNvbG9yOiBEYXJrUmVkOwogIHRleHQtYWxpZ246IGNlbnRlcjsKfQpoNC5kYXRlIHsgLyogSGVhZGVyIDQgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciB0aGUgZGF0ZSAgKi8KICBmb250LXNpemU6IDE4cHg7CiAgZm9udC1mYW1pbHk6IHN5c3RlbS11aTsKICBjb2xvcjogRGFya0JsdWU7CiAgdGV4dC1hbGlnbjogY2VudGVyOwp9CmgxIHsgLyogSGVhZGVyIDEgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciBsZXZlbCAxIHNlY3Rpb24gdGl0bGUgICovCiAgICBmb250LXNpemU6IDIycHg7CiAgICBmb250LWZhbWlseTogc3lzdGVtLXVpOwogICAgY29sb3I6IG5hdnk7CiAgICB0ZXh0LWFsaWduOiBsZWZ0Owp9CmgyIHsgLyogSGVhZGVyIDIgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciBsZXZlbCAyIHNlY3Rpb24gdGl0bGUgKi8KICAgIGZvbnQtc2l6ZTogMjBweDsKICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogICAgY29sb3I6IG5hdnk7CiAgICB0ZXh0LWFsaWduOiBsZWZ0Owp9CgpoMyB7IC8qIEhlYWRlciAzIC0gZm9udCBzcGVjaWZpY2F0aW9ucyBvZiBsZXZlbCAzIHNlY3Rpb24gdGl0bGUgICovCiAgICBmb250LXNpemU6IDE4cHg7CiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICAgIGNvbG9yOiBuYXZ5OwogICAgdGV4dC1hbGlnbjogbGVmdDsKfQoKaDQgeyAvKiBIZWFkZXIgNCAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgb2YgbGV2ZWwgNCBzZWN0aW9uIHRpdGxlICAqLwogICAgZm9udC1zaXplOiAxOHB4OwogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgICBjb2xvcjogZGFya3JlZDsKICAgIHRleHQtYWxpZ246IGxlZnQ7Cn0KCmJvZHkgeyBiYWNrZ3JvdW5kLWNvbG9yOndoaXRlOyB9CgouaGlnaGxpZ2h0bWUgeyBiYWNrZ3JvdW5kLWNvbG9yOnllbGxvdzsgfQoKcCB7IGJhY2tncm91bmQtY29sb3I6d2hpdGU7IH0KCjwvc3R5bGU+CmBgYApgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KCiMKIyBzcGVjaWZpY2F0aW9ucyBvZiBvdXRwdXRzIG9mIGNvZGUgaW4gY29kZSBjaHVua3MKa25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCAgICAgIAogICAgICAgICAgICAgICAgICAgICAgd2FybmluZyA9IEZBTFNFLCAgIAogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFLCAgCiAgICAgICAgICAgICAgICAgICAgICByZXN1bHRzICA9IFRSVUUgICAgIAogICAgICAgICAgICAgICAgICAgICAgKSAgIAoKbGlicmFyeShrbml0cikKbGlicmFyeShwYW5kZXIpCmxpYnJhcnkobWxiZW5jaCkKbGlicmFyeShNQVNTKQpsaWJyYXJ5KGZvcmVjYXN0KQpsaWJyYXJ5KElTd1IpCmBgYAoKCiMgSW50cm9kdWN0aW9uCgpUaGlzIGFzc2luZ21lbnQgaXMgZ29pbmcgdG8gbG9vayBhdCBzZXZlcmFsIGRpZmZlcmVudCBvcHRpb25zIG9mIGV4cG9udGVudGlhbCBzbW9vdGhpbmcgbW9kZWxzIHRvIGRldGVybWluZSB0aGUgYmVzdCBhbmQgZmluYWwgbW9kZWwgZm9yIGEgdGltZSBzZXJpZXMgd2l0aCB0cmVuZCBhbmQgc2Vhc29uYWxpdHkuIAoKIyBNYXRlcmlhbHMKCiMjIERhdGEgU2V0CgpUaGlzIGFzc2lnbm1lbnQgdXNlcyBhIHRpbWUgc2VyaWVzIGRhdGEgc2V0IGZyb20gdGhlIFVuaXRlZCBTdGF0ZXMgQ2Vuc3VzIEJ1cmVhdS4gVGhlIHRpbWUgc2VyaWVzIGlzIEFubnVhbCBSYXRlIG9mIE5ldyBTaW5nbGUtRmFtaWx5IEhvdXNlcyBTb2xkLiBUaGlzIGRhdGEgc2V0IG9ubHkgY292ZXJzIGhvbWVzIHNvbGQgaW4gdGhlIFVuaXRlZCBTdGF0ZXMgb3ZlciB0aGUgc3BhbiBvZiA3NDQgbW9udGhzIGZyb20gSmFudWFyeSAxOTYzIHRvIERlY2VtYmVyIG9mIDIwMjQuIEhvd2V2ZXIsIGluIHRoaXMgYXNzaWdubWVudCB3ZSB3aWxsIG9ubHkgbG9vayBhdCB0aGUgZGF0YSBmcm9tIEphbnVhcnkgMjAxMCBhbmQgRGVjZW1iZXIgMjAyNC4KCgojIyBEYXRhIENsZWFuaW5nCgpUaGUgb3JpZ2luYWwgZGF0YSBzZXQgaXMgZ29pbmcgdG8gYmUgc3Vic2V0dGVkIGludG8gYSB0aW1lIHNlcmllcyBzcGFubmluZyBmcm9tIEphbnVhcnkgMjAxMCB0byBEZWNlbWJlciAyMDI0LiBIb3dldmVyLCBzaW5jZSB3ZSBhcmUgY3VycmVudGx5IGluIERlY2VtYmVyIG9mIDIwMjQgdGhlIGRhdGEgc2V0IGhhcyBub3QgYmVlbiBmdWxsIHVwZGF0ZWQsIHNvIHRoZXJlIGFyZSBzb21lIG9ic2VydmF0aW9ucyB0aGF0IG5lZWQgdG8gYmUgcmVtb3ZlZCBzaW5jZSB0aGV5IGFyZSBtaXNzaW5nLCBhZnRlciB0aGUgbWlzc2luZyB2YXJpYWJsZXMgYXJlIHJlbW92ZWQgdGhlIHZhbHVlIHZhcmlhYmxlIGNhbiBiZSBjb252ZXJ0ZWQgdG8gYSBudW1lcmljIHZhcmlhYmxlLiAKCmBgYHtyfQp1cmw9Imh0dHBzOi8vQ2hsb2VXaW50ZXJzNzkuZ2l0aHViLmlvL1NUQTMyMS9EYXRhL1VTSG9tZVNhbGVzLmNzdiIKaG9tZS5zYWxlcyA9IHJlYWQuY3N2KHVybCwgaGVhZGVyID0gVFJVRSkKbi5yb3cgPSBkaW0oaG9tZS5zYWxlcylbMV0KZGF0YS5ob21lLnNhbGVzLjAgPSBob21lLnNhbGVzWyhuLnJvdy0xNzkpOm4ucm93LCBdCmRhdGEuaG9tZS5zYWxlcyA9IHN1YnNldChkYXRhLmhvbWUuc2FsZXMuMCwgVmFsdWUgIT0gIk4vQSIpCmRhdGEuaG9tZS5zYWxlcyRWYWx1ZSA8LSBhcy5udW1lcmljKGFzLmNoYXJhY3RlcihkYXRhLmhvbWUuc2FsZXMkVmFsdWUpKQpgYGAKCiMjIFRyZW5kIGFuZCBTZWFzb25hbGl0eQoKVGhpcyBhc3NpZ25tZW50IGRvZXMgcmVxdWlyZSB0aGF0IHRoZSB0aW1lIHNlcmllcyB3ZSBhcmUgd29ya2luZyB3aXRoIHNob3cgYm90aCB0cmVuZCBhbmQgc2Vhc29uYWxpdHkuIFRvIGNvbmZpcm0gdGhhdCBib3RoIG9mIHRoZXNlIGFyZSBwcmVzZW50IGluIHRoZSB0aW1lIHNlcmllcywgc29tZSBncmFwaHMgd2VyZSBwcmludGVkIHRvIGFzc2VzIHRoZSB0cmVuZCBhbmQgc2Vhc29uYWxpdHkgb2YgdGhlIHRpbWUgc2VyaWVzLiAKCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLmNhcD0gIkNsYXNzaWNhbCBkZWNvbXBvc2l0aW9uIG9mIGFkZGl0aXZlIHRpbWUgc2VyaWVzIiwgZmlnLndpZHRoPTYsIGZpZy5oZWlnaHQ9NH0KaG9tZXNhbGVzLnRzID0gdHMoZGF0YS5ob21lLnNhbGVzWywyXSwgZnJlcXVlbmN5ID0gMTIsIHN0YXJ0ID0gYygyMDEwLCAxKSkKY2xzLmhvbWVzYWxlcyA9IGRlY29tcG9zZShob21lc2FsZXMudHMpCnBhcihtYXI9YygyLDIsMiwyKSkKcGxvdChjbHMuaG9tZXNhbGVzLCB4bGFiPSIiKQpgYGAKClRoZSBhYm92ZSBncmFwaCBzaG93cyB0aGUgZGVjb21wb3NpdGlvbiBvZiBhZGRpdGl2ZSB0aW1lIHNlcmllcywgaXQgc2hvd3MgYSBtb3N0bHkgcG9zaXRpdmUgaW5jcmVhc2luZyB0cmVuZCwgaG93ZXZlciB0aGVyZSBkb2VzIGFwcGVhciB0byBiZSBhIGRlY3JlYXNlIGFmdGVyIDIwMjAuIENvbnNpZGVyaW5nIHRoZSBjb250ZXh0IHRoYXQgMjAyMCB3YXMgdGhlIHN0YXJ0IG9mIHRoZSBDT1ZJRC0xOSBwYW5kZW1pYyBzaHV0IGRvd24gc28gc2VlaW5nIGEgZGlwIGluIHRoZSB0cmVuZCBpcyBub3Qgc2hvY2tpbmcgY29uc2lkZXJpbmcgdGhlIGNvbnRleHQuIEFkZGl0aW9uYWxseSwgd2UgY2FuIHNlZSBhIHNlYXNvbmFsIHBhdHRlcm4gcHJlc2VudCBpbiB0aGUgZ3JhcGgsIHdoaWNoIG1lYW5zIHRoZSB0aW1lIHNlcmllcyBtZWV0cyB0aGUgdHJlbmQgYW5kIHNlYXNvbmFsIHJlcXVpcmVtZW50cyBmb3IgdGhpcyBhc3NpZ25tZW50LiAKCiMgTWV0aG9kb2xneSAmIEFuYWx5c2lzIAoKRm9yIHRoaXMgcHJvamVjdCwgd2Ugd2FudCB0byBkZXRlcm1pbmUgdGhlIGJlc3QgZXhwb25lbnRpYWwgc21vb3RoaW5nIG1vZGVsIHRvIHVzZSBmb3IgdGhpcyBkYXRhIHNldC4gVG8gZGV0ZXJtaW5lIHRoZSBiZXN0IHNtb290aGluZyBtb2RlbCB3ZSBhcmUgZ29pbmcgdG8gY29tcGFyZSB0aGUgYWNjdXJhY3kgb2Ygc2V2ZXJhbCBkaWZmZXJlbnQgbW9kZWxzLCBTRVMsIEhvbHQsIEhvbHQtV2ludGVycyBhbmQgc29tZSBhZGRpdGl2ZSwgZXhwb25lbnRpYWwgYW5kIGRhbXBlZCB2YXJpYXRpb25zIG9mIEhvbHQgYW5kIEhvbHQtV2ludGVycy4KCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJyxmaWcud2lkdGg9NiwgZmlnLmhlaWdodD00LjUsIGZpZy5jYXA9IkNhc2Ugc3R1ZHk6IENvbXBhcmluZyB2YXJpb3VzIGV4cG9lbnRpYWwgc21vb3RoaW5nIG1vZGVscy4ifQp0ZXN0LmhvbWVzID0gZGF0YS5ob21lLnNhbGVzJFZhbHVlWzE2NjoxNzddCnRyYWluLmhvbWVzID0gZGF0YS5ob21lLnNhbGVzJFZhbHVlWzE6MTY1XQpob21lPXRzKGRhdGEuaG9tZS5zYWxlcyRWYWx1ZVsxOjE2OF0sIHN0YXJ0PTEwMCwgZnJlcXVlbmN5ID0gMTIpCmZpdDEgPSBzZXMoaG9tZSwgaD0xMikKZml0MiA9IGhvbHQoaG9tZSwgaW5pdGlhbD0ib3B0aW1hbCIsIGg9MTIpICAgICAgICAgICAgICMjIG9wdGltYWwgYWxwaGEgYW5kIGJldGEKZml0MyA9IGhvbHQoaG9tZSxkYW1wZWQ9VFJVRSwgaD0xMiApICAgICAgICAgICAgICAgICAgICMjIGFkZGl0aXZlIGRhbXBpbmcKZml0NCA9IGhvbHQoaG9tZSxleHBvbmVudGlhbD1UUlVFLCBkYW1wZWQ9VFJVRSwgaCA9MTIpICMjIG11bHRpcGxpY2F0aXZlIGRhbXAKZml0NSA9IGh3KGhvbWUsaD0xMiwgc2Vhc29uYWw9ImFkZGl0aXZlIikgICAgICAgICAgICAgICMjIGRlZmF1bHQgaCA9IDEwCmZpdDYgPSBodyhob21lLGg9MTIsIHNlYXNvbmFsPSJtdWx0aXBsaWNhdGl2ZSIpCmZpdDcgPSBodyhob21lLGg9MTIsIHNlYXNvbmFsPSJhZGRpdGl2ZSIsZGFtcGVkPVRSVUUpCmZpdDggPSBodyhob21lLGg9MTIsIHNlYXNvbmFsPSJtdWx0aXBsaWNhdGl2ZSIsZGFtcGVkPVRSVUUpCmBgYAoKYGBge3J9CmFjY3VyYWN5LnRhYmxlID0gcm91bmQocmJpbmQoYWNjdXJhY3koZml0MSksIGFjY3VyYWN5KGZpdDIpLCBhY2N1cmFjeShmaXQzKSwgYWNjdXJhY3koZml0NCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWNjdXJhY3koZml0NSksIGFjY3VyYWN5KGZpdDYpLCBhY2N1cmFjeShmaXQ3KSwgYWNjdXJhY3koZml0OCkpLDQpCnJvdy5uYW1lcyhhY2N1cmFjeS50YWJsZSk9YygiU0VTIiwiSG9sdCBMaW5lYXIiLCJIb2x0IEFkZC4gRGFtcGVkIiwgIkhvbHQgRXhwLiBEYW1wZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIkhXIEFkZC4iLCJIVyBFeHAuIiwiSFcgQWRkLiBEYW1wIiwgIkhXIEV4cC4gRGFtcCIpCmthYmxlKGFjY3VyYWN5LnRhYmxlLCBjYXB0aW9uID0gIlRoZSBhY2N1cmFjeSBtZWFzdXJlcyBvZiB2YXJpb3VzIGV4cG9uZW50aWFsIHNtb290aGluZyBtb2RlbHMgCiAgICAgIGJhc2VkIG9uIHRoZSB0cmFpbmluZyBkYXRhIikKYGBgCgpMb29raW5nIGF0IHRoZSByZXN1bHRzIGZyb20gdGhlIHRhYmxlIGFib3ZlLCBpdCBzZWVtcyBsaWtlIHRoZSBIb2x0LVdpbnRlcnMgYWRkaXRpdmUgbW9kZWwgYXBwZWFycyB0byBiZSB0aGUgbW9zdCBhcHByb3ByaWF0ZSBleHBvbmVudGlhbCBzbW9vdGhpbmcgbW9kZWwuIFRoZSBIb2x0LVdpbnRlcnMgYmVhdHMgb3V0IHRoZSBvdGhlciBtb2RlbHMgaW4gZXZlcnkgc2l0dWF0aW9uIGV4Y2VwdCBvbiB3aGVyZSBpdCBnZXRzIGJlYXQgb3V0IGJ5IEhvbHQgRXhwb25lbnRpYWwgRGFtcGVuZWQuIAoKSW4gYWRkaXRpb24gdG8gdGhlIGFjY3VyYWN5IHRhYmxlIGFib3ZlLCBpdCBpcyBhbHNvIGJlbmVmaWNpYWwgdG8gc2VlIGEgdmlzdWFsIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBkaWZmZXJlbnQgZXhwb25lbnRpYWwgc21vb3RoaW5nIG1vZGVscyBvcHRpb25zIGFuZCBjb21wYXJlIHRoZW0gdG8gdGhlIG9yaWdpbmFsIHNlcmlhbCBwbG90LiAKCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJyxmaWcud2lkdGg9NiwgZmlnLmhlaWdodD02LjUsIGZpZy5jYXA9IkNhc2Ugc3R1ZHk6IENvbXBhcmluZyB2YXJpb3VzIGV4cG9uZW50aWFsIHNtb290aGluZyBtb2RlbHMuIn0KcGFyKG1mcm93PWMoMiwxKSwgbWFyPWMoMyw0LDMsMSkpCiMjIyMjIyBwbG90IHRoZSBvcmlnaW5hbCBkYXRhCnByZWQuaWQgPSAxNjY6MTc3CnBsb3QoMToxNjUsIHRyYWluLmhvbWVzLCBsd2Q9Mix0eXBlPSJvIiwgeWxhYj0iSG9tZSBTYWxlcyIsIHhsYWI9IiIsIAogICAgIHhsaW09YygxLDE3NyksIHlsaW09YygyMDAsIDEyMDApLCBjZXg9MC4zLAogICAgIG1haW49Ik5vbi1TZWFzb25hbCBTbW9vdGhpbmcgTW9kZWxzIikKbGluZXMocHJlZC5pZCwgZml0MSRtZWFuLCBjb2w9InJlZCIpCmxpbmVzKHByZWQuaWQsIGZpdDIkbWVhbiwgY29sPSJibHVlIikKbGluZXMocHJlZC5pZCwgZml0MyRtZWFuLCBjb2w9InB1cnBsZSIpCmxpbmVzKHByZWQuaWQsIGZpdDQkbWVhbiwgY29sPSJuYXZ5IikKIyMKcG9pbnRzKHByZWQuaWQsIGZpdDEkbWVhbiwgcGNoPTE2LCBjb2w9InJlZCIsIGNleCA9IDAuNSkKcG9pbnRzKHByZWQuaWQsIGZpdDIkbWVhbiwgcGNoPTE3LCBjb2w9ImJsdWUiLCBjZXggPSAwLjUpCnBvaW50cyhwcmVkLmlkLCBmaXQzJG1lYW4sIHBjaD0xOSwgY29sPSJwdXJwbGUiLCBjZXggPSAwLjUpCnBvaW50cyhwcmVkLmlkLCBmaXQ0JG1lYW4sIHBjaD0yMSwgY29sPSJuYXZ5IiwgY2V4ID0gMC41KQojcG9pbnRzKGZpdDAsIGNvbD0iYmxhY2siLCBwY2g9MSkKbGVnZW5kKCJib3R0b21yaWdodCIsIGx0eT0xLCBjb2w9YygicmVkIiwiYmx1ZSIsInB1cnBsZSIsICJuYXZ5IikscGNoPWMoMTYsMTcsMTksMjEpLAogICBjKCJTRVMiLCJIb2x0IExpbmVhciIsIkhvbHQgTGluZWFyIERhbXBlZCIsICJIb2x0IE11bHRpcGxpY2F0aXZlIERhbXBlZCIpLCAKICAgY2V4ID0gMC43LCBidHk9Im4iKQojIyMjIyMjIyMjIwpwbG90KDE6MTY1LCB0cmFpbi5ob21lcywgbHdkPTIsdHlwZT0ibyIsIHlsYWI9IkhvbWUgU2FsZXMiLCB4bGFiPSIiLCAKICAgICB4bGltPWMoMSwxNzcpLCB5bGltPWMoMjAwLCAxMjAwKSwgY2V4PTAuMywKICAgICBtYWluPSJIb2x0LVdpbnRlcmQgVHJlbmQgYW5kIFNlYXNvbmFsIFNtb290aGluZyBNb2RlbHMiKQpsaW5lcyhwcmVkLmlkLCBmaXQ1JG1lYW4sIGNvbD0icmVkIikKbGluZXMocHJlZC5pZCwgZml0NiRtZWFuLCBjb2w9ImJsdWUiKQpsaW5lcyhwcmVkLmlkLCBmaXQ3JG1lYW4sIGNvbD0icHVycGxlIikKbGluZXMocHJlZC5pZCwgZml0OCRtZWFuLCBjb2w9Im5hdnkiKQojIwpwb2ludHMocHJlZC5pZCwgZml0NSRtZWFuLCBwY2g9MTYsIGNvbD0icmVkIiwgY2V4ID0gMC41KQpwb2ludHMocHJlZC5pZCwgZml0NiRtZWFuLCBwY2g9MTcsIGNvbD0iYmx1ZSIsIGNleCA9IDAuNSkKcG9pbnRzKHByZWQuaWQsIGZpdDckbWVhbiwgcGNoPTE5LCBjb2w9InB1cnBsZSIsIGNleCA9IDAuNSkKcG9pbnRzKHByZWQuaWQsIGZpdDgkbWVhbiwgcGNoPTIxLCBjb2w9Im5hdnkiLCBjZXggPSAwLjUpCiMjIwpsZWdlbmQoImJvdHRvbXJpZ2h0IiwgbHR5PTEsIGNvbD1jKCJyZWQiLCJibHVlIiwicHVycGxlIiwgIm5hdnkiKSxwY2g9YygxNiwxNywxOSwyMSksCiAgIGMoIkhXIEFkZGl0aXZlIiwiSFcgTXVsdGlwbGljYXRpdmUiLCJIVyBBZGRpdGl2ZSBEYW1wZWQiLCAiSFcgTXVsdGlwbGljYXRpdmUgRGFtcGVkIiksIAogICBjZXggPSAwLjcsIGJ0eT0ibiIpCmBgYAoKTG9va2luZyBhdCB0aGUgZ3JhcGhzIGFib3ZlIHRoZSBmaXJzdCBkZXBpY3Rpb24gc2hvd3MgdGhlIHByZWRpY3RpdmUgbGluZXMgdG8gYWxtb3N0IGdvIGZ1bGx5IGhvcml6b250YWwsIG9yIG1haW5seSBob3Jpem9udGFsIHdpdGggbWluaW1hbCBzbG9wZS4gSG93ZXZlciwgdGhlIHNlY29uZCBncmFwaCBkb2VzIHNob3cgcHJlZGljdGl2ZSBsaW5lcyB3aXRoIG1vcmUgb2YgYSBzaGFwZSBhbmQgcG90ZW50aWFsIHZhcmlhdGlvbiB0aGF0IGlzIGNvbnNpc3RlbnQgd2l0aCB0aGUgaW5mb3JtYXRpb24gc2VlbiBpbiB0aGUgZXhpc3Rpbmcgc2VyaWFsIHBsb3QuIFRoZSBIb2x0LVdpbnRlcnMgQWRkaXRpdmUgbGluZSBpcyB3aXRoaW4gdGhlIHNlY29uZCBncmFwaCwgZnVydGhlciBjZW1lbnRpbmcgaXQgYXMgdGhlIG1vc3QgYXBwcm9wcmlhdGUgbW9kZWwuIAoKVGhpcyBhc3NpZ25tZW50IGlzIGFsc28gdXNpbmcgYSB0cmFpbmluZyBkYXRhIHNldCwgd2hpY2ggd2lsbCBiZSB1c2VkIHRvIGlkZW50aWZ5IHRoZSBiZXN0IG1vZGVsLCB3aXRoIHRoZSBhc3Npc3RhbmNlIG9mIHRoZSB0ZXN0aW5nIGRhdGEgc2V0LiBJbiBvcmRlciB0byB1c2UgdGhlIG1vZGVsIGZvciByZWFsLWZvcmVjYXN0LCB0aGUgbW9kZWwgbmVlZHMgdG8gYmUgcmVmaXQgdXNpbmcgdGhlIGVudGlyZSBkYXRhIHRvIHVwZGF0ZSB0aGUgZmluYWwgd29ya2luZyBtb2RlbHMgc21vb3RoaW5nIHBhcmFtZXRlcnMuIAoKCmBgYHtyfQphY2MuZnVuID0gZnVuY3Rpb24odGVzdC5kYXRhLCBtb2Qub2JqKXsKICBQRT0xMDAqKHRlc3QuZGF0YS1tb2Qub2JqJG1lYW4pL21vZC5vYmokbWVhbgogIE1BUEUgPSBtZWFuKGFicyhQRSkpCiAgIyMjCiAgRT10ZXN0LmRhdGEtbW9kLm9iaiRtZWFuCiAgTVNFPW1lYW4oRV4yKQogICMjIwogIGFjY3VyYWN5Lm1ldHJpYz1jKE1TRT1NU0UsIE1BUEU9TUFQRSkKICBhY2N1cmFjeS5tZXRyaWMKfQpgYGAKCmBgYHtyfQpwcmVkLmFjY3VyYWN5ID0gcmJpbmQoU0VTID1hY2MuZnVuKHRlc3QuZGF0YT10ZXN0LmhvbWVzLCBtb2Qub2JqPWZpdDEpLAogICAgICAgICAgICAgICAgICAgICAgSG9sdC5BZGQgPWFjYy5mdW4odGVzdC5kYXRhPXRlc3QuaG9tZXMsIG1vZC5vYmo9Zml0MiksCiAgICAgICAgICAgICAgICAgICAgICBIb2x0LkFkZC5EYW1wID1hY2MuZnVuKHRlc3QuZGF0YT10ZXN0LmhvbWVzLCBtb2Qub2JqPWZpdDMpLAogICAgICAgICAgICAgICAgICAgICAgSG9sdC5FeHAgPWFjYy5mdW4odGVzdC5kYXRhPXRlc3QuaG9tZXMsIG1vZC5vYmo9Zml0NCksCiAgICAgICAgICAgICAgICAgICAgICBIVy5BZGQgPWFjYy5mdW4odGVzdC5kYXRhPXRlc3QuaG9tZXMsIG1vZC5vYmo9Zml0NSksCiAgICAgICAgICAgICAgICAgICAgICBIVy5FeHAgPWFjYy5mdW4odGVzdC5kYXRhPXRlc3QuaG9tZXMsIG1vZC5vYmo9Zml0NiksCiAgICAgICAgICAgICAgICAgICAgICBIVy5BZGQuRGFtcCA9YWNjLmZ1bih0ZXN0LmRhdGE9dGVzdC5ob21lcywgbW9kLm9iaj1maXQ3KSwKICAgICAgICAgICAgICAgICAgICAgIEhXLkV4cC5EYW1wID1hY2MuZnVuKHRlc3QuZGF0YT10ZXN0LmhvbWVzLCBtb2Qub2JqPWZpdDgpKQprYWJsZShwcmVkLmFjY3VyYWN5LCBjYXB0aW9uPSJUaGUgYWNjdXJhY3kgbWVhc3VyZXMgb2YgdmFyaW91cyBleHBvbmVudGlhbCBzbW9vdGhpbmcgbW9kZWxzIAogICAgICBiYXNlZCBvbiB0aGUgdGVzdGluZyBkYXRhIikKYGBgCgpMb29raW5nIGF0IHRoZSBhYm92ZSBhY2N1cmFjeSB0YWJsZSwgd2UgYWN0dWFsbHkgc2VlIHRoYXQgdGhlIEhvbHQgQWRkaXRpdmUgaXMgdGhlIGJlc3Qgb2YgdGhlIGVpZ2h0IHNtb290aGluZyBtb2RlbHMsIHdpdGggSG9sdC1XaW50ZXJzIEFkZGl0aXZlIGJlaW5nIGEgY2xvc2Ugc2Vjb25kLiBUaGlzIGRvZXMgY29tZSBhcyBhIHN1cnByaXNlIGNvbnNpZGVyaW5nIHRoZSBIb2x0LVdpbnRlcnMgQWRkaXRpdmUgbW9kZWwgaGFzIGJlZW4gcGVyZm9ybWluZyBiZXR0ZXIgc28gZmFyLiBTaW5jZSB0aGUgSG9sdC1XaW50ZXJzIEFkZGl0aXZlIG1vZGVsIHdhcyBtb3JlIG9mdGVuIHRoZSBwcmVmZXJyZWQgbW9kZWwsIG92ZXIgSG9sdCBBZGRpdGl2ZSwgYW5kIHNpbmNlIEhvbHQtV2ludGVycyBpcyBhIGNsb3NlIHNlY29uZCBoZXJlLCB3ZSBhcmUgZ29pbmcgdG8gbW92ZSBmb3J3YXJkIHVzaW5nIHRoaXMgbW9kZWwuIEhvd2V2ZXIsIGl0IGlzIHN0aWxsIGltcG9ydGFudCB0byBhY2tub3dsZWRnZSB0aGF0IHRoZSBhYm92ZSBhY2N1cmFjeSB0YWJsZSBkb2VzIG5vdCBpZGVudGlmeSB0aGlzIGFzIHRoZSBudW1iZXIgb25lIG1vZGVsIGNob2ljZS4gCgojIFJlc3VsdHMgJiBDb25jbHVzaW9ucyAKCkluIHRoZSBwcmV2aW91cyBhbmFseXNpcywgdGhlIG1vZGVsIHdhcyB0cmFpbmVkIHVzaW5nIHRoZSB0cmFpbmluZyBkYXRhIHNldCBpbiBvcmRlciB0byBpZGVudGlmeSB0aGUgYmVzdCBtb2RlbCBmb3IgYm90aCB0aGUgdGVzdGluZyBhbmQgdHJhaW5pbmcgZGF0YSBzZXRzLiBXaGVuIHVzaW5nIHJlYWwgZm9yZWNhc3QgdGhlIG1vZGVscyBuZWVkIHRvIGJlIHJlZml0dGVkIGF0IHRoZSBlbmQgb2YgdGhlIGFuYWx5c2lzIHVzaW5nIGJvdGggdGhlIHRyYWluaW5nIGFuZCB0ZXN0aW5nIGRhdGEgc2V0cywgY29tYmluZWQgdG8gY3JlYXRlIHRoZSB3aG9sZSBkYXRhIHNldC4gV2hlbiB1c2luZyB0aGUgdHJhaW5pbmcgYW5kIHRlc3Rpbmcgc2V0cyB0b2dldGhlciB0aGUgbW9kZWwgY2FuIGJlIHJlZml0IGFuZCBzbW9vdGhpbmcgcGFyYW1ldGVycyBpbiB0aGUgZmluYWwgbW9kZWwgY2FuIGJlIHVwZGF0ZWQuCgpgYGB7cn0KaG9tZXM9dHMoZGF0YS5ob21lLnNhbGVzJFZhbHVlWzE6MTc3XSwgc3RhcnQ9MjAwLCBmcmVxdWVuY3kgPSAxMikKZmluYWwubW9kZWwgPSBodyhob21lcyxoPTEyLCBzZWFzb25hbD0iYWRkaXRpdmUiKSAKc21vb3RoaW5nLnBhcmFtZXRlciA9IGZpbmFsLm1vZGVsJG1vZGVsJHBhclsxOjNdCmthYmxlKHNtb290aGluZy5wYXJhbWV0ZXIsIGNhcHRpb249IkVzdGltYXRlZCB2YWx1ZXMgb2YgdGhlIHNtb290aGluZyBwYXJhbWV0ZXJzIGluCiAgICAgIEhvbHQtV2ludGVycyBsaW5lYXIgdHJlbmQgd2l0aCBhZGRpdGl2ZSBzZWFzb25hbGl0eSIpCmBgYAoKVGhlIGVzdGltYXRlcyB2YWx1ZXMgZm9yIHRoZSBzbW9vdGhpbmcgcGFyYW1ldGVyIGFyZSB0aGUgdGhyZWUgdXBkYXRlZCB2YWx1ZXMsIGFscGhhLCBiZXRhLCBhbmQgZ2FtbWEgdGhhdCBhcmUgc2hvd24gYWJvdmUuIFRoZSB2YWx1ZXMgYXBwbHkgc3BlY2lmaWNhbGx5IHRvIHRoZSBIb2x0LVdpbnRlcnMgbWV0aG9kIGZvciBsaW5lYXIgdHJlbmRzIHdpdGggYWRkaXRpdmUgc2Vhc29uYWxpdHkuIFRha2luZyB0aGVzZSB2YWx1ZXMgaW50byBhY2NvdW50LCB0aGUgcmVhbC1mb3JlY2FzdGluZyBpcyBjb21wbGV0ZSBzaW5jZSB0aGUgbW9kZWwgd2FzIHJlZml0IHdpdGggdXBkYXRpbmcgc21vb3RoaW5nIHBhcmFtZXRlcnMgZm9yIHRoZSBzZWxlY3RlZCBmaW5hbCBtb2RlbC4gCgoKIyBHZW5lcmFsIERpc2N1c3Npb25zCgpXaGlsZSB0aGUgZmluYWwgc21vb3RoaW5nIG1vZGVsIHdhcyBzZWxlY3RlZCBhbmQgb3VyIGFuYWx5c2lzIHdhcyBjb25kdWN0ZWQgdGhlcmUgYXJlIHNvbWUgZHJhd2JhY2tzIG9mIHRoaXMgYXNzaWdubWVudCB0aGF0IG5lZWQgdG8gYmUgYWRkcmVzc2VkLiBUbyBzdGFydCwgdGhlIGRhdGEgc2V0IGl0c2VsZiBpcyBub3QgcGVyZmVjdC4gRHVlIHRvIHRoZSBDT1ZJRC0xOSBwYW5kZW1pYyBhbmQgc2h1dCBkb3duLCB0aGVyZSBpcyBhIHZlcnkgbGFyZ2Ugc3Bpa2UgYW5kIHRoZW4gc3Vic2VxdWVudCBkcm9wIGluIHRoZSBuZXcgaG9tZSBzYWxlcy4gVGhpcyBsYXJnZSBqdW1wIGFuZCBmYWxsIGlzIG5vdCBjb25zaXN0ZW50IHdpdGggdGhlIGVhcmxpZXIgdHJlbmQgYW5kIGJlZ3MgdGhlIHF1ZXN0aW9uIGlmIHRoYXQgaXMgd2hlcmUgdGhlIHRyZW5kIHdvdWxkIGhhdmUgd2VudCBpZiB0aGUgcGFuZGVtaWMgaGFkIG5vdCBoYXBwZW5lZC4gQWRkaXRpb25hbGx5LCB3aXRoIHRoaXMgdHJlbmQgYmVpbmcgc28gcmVjZW50LCBpdCBkb2VzIG1ha2Ugb25lIHF1ZXN0aW9uIGlmIGl0IGlzIGhhdmluZyBhIHNpZ25pZmljYW50IGltcGFjdCBvZiB0aGUgbW9kZWxzIGFuZCB0aGVpciBzbW9vdGhpbmcsIGFuZCBpZiBpdCBpcyBza2V3aW5nIHRoZSByZXN1bHRzIG9mIG91ciBhbmFseXNpcy4gCgpBZGRpdGlvbmFsbHksIGlzIHdhcyBub3QgZXhwZWN0ZWQgdGhhdCB0aGUgd2hlbiBsb29raW5nIGF0IHRoZSBhY2N1cmFjeSBtZWFzdXJlcyBiYXNlZCBqdXN0IG9uIHRoZSB0ZXN0aW5nIGRhdGEsIHRoYXQgSG9sdC1XaW50ZXJzIEFkZGl0aXZlIHdhcyBub3QgdGhlIGJlc3QgbW9kZWwsIGFuZCBpdCB3YXMgYWN0dWFsbHkgc2Vjb25kIHRvIEhvbHQgQWRkaXRpdmUuIE9uY2UgdGhlIHRyZW5kcyBzdGFydCB0byBnZXQgYmFjayB0byBub3JtYWwgcG9zdCBDT1ZJRC0xOSBhbmQgdGhlcmUgaXMgbW9yZSBwb3N0IENPVklEIGRhdGEgdG8gbG9vayBhdCBpdCB3b3VsZCBiZSBiZW5lZmljaWFsIHRvIGdvIGJhY2sgYW5kIHJlcnVuIHRoZSBhbmFseXNpcyBhbmQgc2VlIGlmIEhvbHQtV2ludGVycyBBZGRpdGl2ZSBzdGlsbCBtYWtlcyB0aGUgbW9zdCBzZW5zZSBhcyB0aGUgZmluYWwgbW9kZWwsIG9yIGlmIEhvbHQgQWRkaXRpdmUgc2VlbXMgdG8gYmUgdGhlIGJldHRlciBtb2RlbC4gSG93ZXZlciwgdGhhdCBpcyBhbmFseXNpcyB0aGF0IHdlIHdpbGwgaGF2ZSB0byB3YWl0IGEgZmV3IHNldmVyYWwgeWVhcnMgdG8gZG8uIAo=