1 Introduction and Background

Here we have a dataset composed of historical records of the New York Stock Exchange’s most famous index, the S&P 500. Made up of the top 500 companies for which trades across the United States are made, the S&P 500 (or S&P), was believed to have had a market cap of just over $57 trillion as of this past August. Since it’s inception, the S&P has been used as a political benchmark for the growth and overall health of the United States’ economy.

For my analysis, I wanted to specifically focus on what the opening price of the S&P was at the first trading day of each year, which ranged from January 2nd to January 4th depending on if the New Years’ holiday coincided with the weekend. On top of observing any possible historical trends, I also used this data as grounds to test multiple different time series modeling methods. A breakdown of the dataset’s original structure is below.

Name Meaning Data_Type
Date Date for that observation; YYYY-MM-DD form Date
Open S&P’s opening market price double
High That day’s highest recorded price double
Low That day’s lowest recorded price double
Close S&P’s closing market price double
Adj Close S&P’s closing market price, accounting for corporate activity* double
Volume Total number of shares traded in the market that day double
  • Corporate activity primarily includes, but is not limited to, dividend payouts and stock splits

2 Model Creation

For my time series modeling experiments, I chose to divide my dataset into separate portions, with the larger chunk being used for model training and the later part being used for model testing. More specifically, the S&P’s year-beginning market open from 1928 to 2010 I dedicated to training. While the observations from 2011 to 2020 will be used to test my model’s accuracy.

I created four different time series models - Moving Average, Naive, Seasonal Naive and Drift - using the training data. Each model was set to have a forecast horizon (number of future intervals to predict) of 10. A table summary of each model’s predictions for the ten years after our training data’s end is below.

##### Moving Average Model
Moving_Average = round(meanf(TS_Training_Data, h=10)$mean, 4)
  # argument h represents the forecast horizon, which is the number of intervals into the future we are predicting values for
  # Setting h=10 since we used 10 for the sample size of the testing data

##### Naive Model
Naive = round(naive(TS_Training_Data, h=10)$mean, 4)

##### Seasonal Naive Model
Seasonal_Naive = round(snaive(TS_Training_Data, h=10)$mean, 4)

##### Drift Model
Drift = round(rwf(TS_Training_Data, h=10, drift=TRUE)$mean, 4)
  # function rwf stands for "random walk with drift"
  # Note that we MUST set drift = TRUE in order for it to be a proper drift model

Year = c("2011", "2012", "2013", "2014", "2015", "2016", "2017", "2018", "2019", "2020")

Baseline_Models = cbind(Year, Moving_Average, Naive, Seasonal_Naive, Drift)

colnames(Baseline_Models) = c("Year", "Moving Average", "Naive", "Seasonal Naive", "Drift")

kable(Baseline_Models, caption = "Model Forecasting Projections")
Model Forecasting Projections
Year Moving Average Naive Seasonal Naive Drift
2011 283.2408 1116.5601 1116.5601 1129.9601
2012 283.2408 1116.5601 1116.5601 1143.3601
2013 283.2408 1116.5601 1116.5601 1156.7601
2014 283.2408 1116.5601 1116.5601 1170.1601
2015 283.2408 1116.5601 1116.5601 1183.5601
2016 283.2408 1116.5601 1116.5601 1196.9601
2017 283.2408 1116.5601 1116.5601 1210.3601
2018 283.2408 1116.5601 1116.5601 1223.7601
2019 283.2408 1116.5601 1116.5601 1237.1601
2020 283.2408 1116.5601 1116.5601 1250.5601

Looking at our summary table, we see a few interesting takeaways.

  • First, we see that the year-to-year predicted values from the moving average model are far beneath those of the other 3 models. This is because the moving average method operates on the assumption that all future values will be equal to the mean of all previous values. A large amount of our training data (58 of the 73) years, had a market open below $200.

  • We also notice there is total equality between the naive and seasonal naive models. The naive method assumes that all future observations will have equal value to that of the most previous observation (which explains why the predicted value is the same for each year in the string of forecasts). Meanwhile, the seasonal naive approach applies the premise of the naive method to data that operates in a cyclical manner (think frequencies of weather related events tied to seasonal changes). In the case of our dataset, each S&P market opening is occurring at approximately the same day every year, making the naive and seasonal naive model results practically identical.

  • Lastly, we see that the drift model is the only one in which forecasted values differ from year to year. Unlike the other three methods, the drift method does account for historical averages in rate of increase and decrease as well as averages in overall value as well. Given that the S&P has always gained value when looked at from a long term perspective, it is not surprising that our drift forecasts show an average increase of about 13 to 14 USD in projected market opening from one year to the next.

3 Model Forecast Visualizations

After examining the model forecasts year-by-year, I decided to graph each model’s predictions alongside the known historical data to allow for a quick examination of how accurate each model was. The first graph consists of the entire scope of this dataset’s observations (1929 to 2020), while the second graph I constrained to this century’s market opens. It should be noted that, in both graphs, the representation of the naive model forecasts can be difficult to see as they perfectly overlap with those of the seasonal naive model.

DF_Predictions = cbind(2011:2020, data.frame(Moving_Average), data.frame(Naive), data.frame(Seasonal_Naive), data.frame(Drift))
  colnames(DF_Predictions) = c("Year", "Moving Average", "Naive", "Seasonal Naive", "Drift")

Full_Graph = (ggplot() +
  geom_line(data = First_Day, mapping = aes (x = Year, y = Open)) +             
      geom_point(data = First_Day, mapping = aes(x = Year, y = Open)) +
      labs(x = "Year", y = "S&P 500 Open ($)", title ="S&P 500 First Market Open of the Year") + 
  geom_line(data = DF_Predictions, mapping = aes (x = Year, y = Moving_Average)) +
      geom_point(data = DF_Predictions, mapping = aes (x = Year, y = Moving_Average, color = "Moving Average")) + 
  
  geom_line(data = DF_Predictions, mapping = aes (x = Year, y = Naive)) + 
      geom_point(data = DF_Predictions, mapping = aes (x = Year, y = Naive, color = "Naive")) + 
  
  geom_line(data = DF_Predictions, mapping=aes(x = Year, y = `Seasonal Naive`)) +
      geom_point(data = DF_Predictions, mapping = aes (x = Year, y = Seasonal_Naive, color = "Seasonal Naive")) + 
  
  geom_line(data = DF_Predictions, mapping=aes(x = Year, y = `Drift`)) +
      geom_point(data = DF_Predictions, mapping = aes (x = Year, y = Drift, color = "Drift")) +
  
  scale_x_continuous(
    limits = c(1925, 2020),
    breaks = seq(1930, 2020, 10) 
  ) +

  scale_y_continuous(
    limits = c(0, 3250),
    breaks = seq(0, 3500, 500) 
  ))

Full_Graph

########################
Reduced_Graph = (ggplot() +  
  geom_line(data = First_Day, mapping = aes (x = Year, y = Open)) +
      geom_point(data = First_Day, mapping = aes(x = Year, y = Open)) +
  labs(x = "Year", y = "S&P 500 Open ($)", title ="S&P 500 First Market Open of the Year (2000 - 2020)") + 
  geom_line(data = DF_Predictions, mapping = aes (x = Year, y = Moving_Average)) +
      geom_point(data = DF_Predictions, mapping = aes (x = Year, y = Moving_Average, color = "Moving Average",)) + 
  
  geom_line(data = DF_Predictions, mapping = aes (x = Year, y = Naive)) + 
      geom_point(data = DF_Predictions, mapping = aes (x = Year, y = Naive, color = "Naive")) + 
  
  geom_line(data = DF_Predictions, mapping=aes(x = Year, y = `Seasonal Naive`)) +
      geom_point(data = DF_Predictions, mapping = aes (x = Year, y = Seasonal_Naive, color = "Seasonal Naive")) + 
  
  geom_line(data = DF_Predictions, mapping=aes(x = Year, y = `Drift`)) +
      geom_point(data = DF_Predictions, mapping = aes (x = Year, y = Drift, color = "Drift")) +
  
  scale_x_continuous(
    limits = c(2000, 2020),
    breaks = seq(2000, 2020, 4) 
  ) +
  
  scale_y_continuous(
    limits = c(250, 3250),
   breaks = seq(250, 3250, 500)
  )
  )

Reduced_Graph

We can see from our two graphs that, like seen in the summary table above, the moving average model’s forecasts are well beneath those of the other three models. That is because of the much greater influence that the first roughly 50 years of the S&P’s opening market price has on the moving average’s calculation than it does on the naive, seasonal naive or drift. The average opening price from 1928 to 1978 was only about $45.64.

Additionally, while our other three models’ forecasts resemble that of the index’ true opening value far greater than those of our moving average model, they also consistently underestimated. The drift model’s predicted values were the most accurate, which is not suprising given that, as previously said, the drift approach does account for historical trends in increase or decrease. The reason the drift forecasts’ trend was in the proper direction (increasing over time), but at a rate far lesser than the true rate of market open increase is due to the extraordinary weakness of the S&P opening’s upward trend throughout the first five decades or so of our dataset.

4 Model Accuracy Measures

Finally, I wanted to quantify the strength of my four models using some standard measures of modeling accuracy. Below is a breakdown of each model’s mean error (ME), mean square error (MSE) and mean absolute prediction error (MAPE). Mean error and mean square error are considered measures of absolute error, and are a good reference statistic to summarize how “off” our models’ forecasts were on average. Meanwhile, MAPE is called a measure of relative error, as it tells us on average how “off” our models’ forecasts were as a percent.

None of the metrics calculated in the table below are particularly surprising. They are in-line with our previous graphical displays and forecast summary table. Our drift model is the most accurate, our naive and seasonal naive models are slightly worse, and the moving average is significantly less useful than the others.

# Will find mean error (ME), mean squared error (MSE) and mean absolute prediction error (MAPE) for each of the 4 baseline models. Then cbind them all into a table and output with kable function.

### ME first
Moving_Average_Errors = data.frame(DF_Predictions$`Moving Average` - Testing_Data$Open)
    Moving_Average_ME = sum(Moving_Average_Errors)/nrow(Moving_Average_Errors)

Naive_Errors = data.frame(DF_Predictions$Naive - Testing_Data$Open)
    Naive_ME = sum(Naive_Errors)/nrow(Naive_Errors)
    
Seasonal_Naive_Errors = data.frame(DF_Predictions$`Seasonal Naive` - Testing_Data$Open)
    Seasonal_Naive_ME = sum(Seasonal_Naive_Errors)/nrow(Seasonal_Naive_Errors)
    
Drift_Errors = data.frame(DF_Predictions$Drift - Testing_Data$Open)
    Drift_ME = sum(Drift_Errors)/nrow(Drift_Errors)

All_Model_MEs = rbind(Moving_Average_ME, Naive_ME, Seasonal_Naive_ME, Drift_ME)

### MSE second

# Create squared error data frames
Moving_Average_SQErrors = data.frame(Moving_Average_Errors^2)
Naive_SQErrors = data.frame(Naive_Errors^2)
Seasonal_Naive_SQErrors = data.frame(Seasonal_Naive_Errors^2)
Drift_SQErrors = data.frame(Drift_Errors^2)

# Use squared error data frames to create MSE objects
Moving_Average_MSE = sum(Moving_Average_SQErrors)/nrow(Moving_Average_SQErrors)
Naive_MSE = sum(Naive_SQErrors)/nrow(Naive_SQErrors)
Seasonal_Naive_MSE = sum(Seasonal_Naive_SQErrors)/nrow(Seasonal_Naive_SQErrors)
Drift_MSE = sum(Drift_SQErrors)/nrow(Drift_SQErrors)

All_Model_MSEs = rbind(Moving_Average_MSE, Naive_MSE, Seasonal_Naive_MSE, Drift_MSE)

#MAPE third
Moving_Average_PEI = data.frame((Moving_Average_Errors/Testing_Data$Open)*100)
Moving_Average_MAPE = round(sum(abs(Moving_Average_PEI))/nrow(Moving_Average_PEI),4)

Naive_PEI = data.frame((Naive_Errors/Testing_Data$Open)*100)
Naive_MAPE = round(sum(abs(Naive_PEI))/nrow(Naive_PEI),4)

Seasonal_Naive_PEI = data.frame((Seasonal_Naive_Errors/Testing_Data$Open)*100)
Seasonal_Naive_MAPE = round(sum(abs(Seasonal_Naive_PEI))/nrow(Seasonal_Naive_PEI),4)

Drift_PEI = data.frame((Drift_Errors/Testing_Data$Open)*100)
Drift_MAPE = round(sum(abs(Drift_PEI))/nrow(Drift_PEI),4)

All_Model_MAPEs = rbind(Moving_Average_MAPE, Naive_MAPE, Seasonal_Naive_MAPE, Drift_MAPE)

Model_Accuracy = cbind(All_Model_MEs, All_Model_MSEs, All_Model_MAPEs)
rownames(Model_Accuracy) = c("Moving Average", "Naive", "Seasonal Naive", "Drift")
colnames(Model_Accuracy) = c("ME", "MSE", "MAPE")
kable(Model_Accuracy, caption = "Model Accuracy Summary")
Model Accuracy Summary
ME MSE MAPE
Moving Average -1771.0152 3510134 84.8822
Naive -937.6959 1252913 40.4043
Seasonal Naive -937.6959 1252913 40.4043
Drift -863.9959 1076191 37.0768

5 Conclusion

In conclusion, we can see that the straightforward application of these four standard and common time series modeling methods on the historical stock market data that was examined, were not particularly useful in forecasting future S&P 500 opening market prices. This was largely due to the consistently low market opens throughout the first 50 or so years of the S&P index. In the future, it would be interesting to examine the model accuracy of these methods - particularly the moving average and drift - if the range of the training data was greatly reduced to only include more recent decades.

LS0tCnRpdGxlOiAiQW5hbHlzaXMgb2YgWWVhci10by1ZZWFyIFMmUCA1MDAgT3BlbmluZyBQcmljZSIKYXV0aG9yOiAiQ2hyaXMgQmFobSIKZGF0ZTogIjIwMjUtMTEtMTQiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6CiAgICAgIGNvbGxhcHNlZDogdHJ1ZQogICAgICBzbW9vdGhfc2Nyb2xsOiB0cnVlCiAgICB0b2NfZGVwdGg6IDQKICAgIGZpZ193aWR0aDogNgogICAgZmlnX2hlaWdodDogNAogICAgZmlnX2NhcHRpb246IHRydWUKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICB0aGVtZTogbHVtZW4KICAgIGhpZ2hsaWdodDogdGFuZ28KICBwZGZfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKICAgIHRvY19kZXB0aDogNAogICAgZmlnX2NhcHRpb246IHRydWUKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogIHdvcmRfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKICAgIHRvY19kZXB0aDogNAotLS0KCmBgYHtjc3MsIGVjaG8gPSBGQUxTRX0KZGl2I1RPQyBsaSB7ICAgICAvKiB0YWJsZSBvZiBjb250ZW50ICAqLwogICAgbGlzdC1zdHlsZTp1cHBlci1yb21hbjsKICAgIGJhY2tncm91bmQtaW1hZ2U6bm9uZTsKICAgIGJhY2tncm91bmQtcmVwZWF0Om5vbmU7CiAgICBiYWNrZ3JvdW5kLXBvc2l0aW9uOjA7Cn0KCmgxLnRpdGxlIHsgICAgLyogbGV2ZWwgMSBoZWFkZXIgb2YgdGl0bGUgICovCiAgZm9udC1zaXplOiAyNHB4OwogIGZvbnQtd2VpZ2h0OiBib2xkOwogIGNvbG9yOiBEYXJrUmVkOwogIHRleHQtYWxpZ246IGNlbnRlcjsKfQoKaDQuYXV0aG9yIHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8KICBmb250LXNpemU6IDE4cHg7CiAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgY29sb3I6IERhcmtSZWQ7CiAgdGV4dC1hbGlnbjogY2VudGVyOwp9CgpoNC5kYXRlIHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8KICBmb250LXNpemU6IDE4cHg7CiAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgY29sb3I6IERhcmtCbHVlOwogIHRleHQtYWxpZ246IGNlbnRlcjsKfQoKaDEgeyAvKiBIZWFkZXIgMSAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLwogICAgZm9udC1zaXplOiAyMHB4OwogICAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICAgIGNvbG9yOiBkYXJrcmVkOwogICAgdGV4dC1hbGlnbjogY2VudGVyOwp9CgpoMiB7IC8qIEhlYWRlciAyIC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovCiAgICBmb250LXNpemU6IDE4cHg7CiAgICBmb250LXdlaWdodDogYm9sZDsKICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogICAgY29sb3I6IG5hdnk7CiAgICB0ZXh0LWFsaWduOiBsZWZ0Owp9CgpoMyB7IC8qIEhlYWRlciAzIC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovCiAgICBmb250LXNpemU6IDE2cHg7CiAgICBmb250LXdlaWdodDogYm9sZDsKICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogICAgY29sb3I6IG5hdnk7CiAgICB0ZXh0LWFsaWduOiBsZWZ0Owp9CgpoNCB7IC8qIEhlYWRlciA0IC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovCiAgICBmb250LXNpemU6IDE0cHg7CiAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICAgIGNvbG9yOiBkYXJrcmVkOwogICAgdGV4dC1hbGlnbjogbGVmdDsKfQoKLyogQWRkIGRvdHMgYWZ0ZXIgbnVtYmVyZWQgaGVhZGVycyAqLwouaGVhZGVyLXNlY3Rpb24tbnVtYmVyOjphZnRlciB7CiAgY29udGVudDogIi4iOwp9CmBgYAoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CiMgY29kZSBjaHVuayBzcGVjaWZpZXMgd2hldGhlciB0aGUgUiBjb2RlLCB3YXJuaW5ncywgYW5kIG91dHB1dCAKIyB3aWxsIGJlIGluY2x1ZGVkIGluIHRoZSBvdXRwdXQgZmlsZXMuCgppZiAoIXJlcXVpcmUoImtuaXRyIikpIHsgICAgICAgICAgICAgICAgICAgICAgIyB1c2UgY29uZGl0aW9uYWwgc3RhdGVtZW50IHRvIGRldGVjdAogICBpbnN0YWxsLnBhY2thZ2VzKCJrbml0ciIpICAgICAgICAgICAgICAgICAgIyB3aGV0aGVyIGEgcGFja2FnZSB3YXMgaW5zdGFsbGVkIGluCiAgIGxpYnJhcnkoa25pdHIpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHlvdXIgbWFjaGluZS4gSWYgbm90LCBpbnN0YWxsIGl0IGFuZAp9ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBsb2FkIGl0IHRvIHRoZSB3b3JraW5nIGRpcmVjdG9yeS4KCmlmICghcmVxdWlyZSh0aWR5dmVyc2UpKSB7bGlicmFyeSh0aWR5dnNlcnNlKX0gCgppZiAoIXJlcXVpcmUoR0dhbGx5KSkge2xpYnJhcnkoR0dhbGx5KX0gCgppZiAoIXJlcXVpcmUoa2FibGVFeHRyYSkpIHtsaWJyYXJ5KGthYmxlRXh0cmEpfSAKCmlmICghcmVxdWlyZShnZ3Bsb3QyKSkge2xpYnJhcnkoZ2dwbG90Mil9IAoKaWYgKCFyZXF1aXJlKGNhcikpIHtsaWJyYXJ5KGNhcil9IAoKaWYgKCFyZXF1aXJlKGRwbHlyKSkge2xpYnJhcnkoZHBseXIpfSAKCmlmICghcmVxdWlyZShwYW5kZXIpKSB7bGlicmFyeShwYW5kZXIpfSAKCmlmICghcmVxdWlyZShmb3JlY2FzdCkpIHtsaWJyYXJ5KGZvcmVjYXN0KX0gCgppZiAoIXJlcXVpcmUobHVicmlkYXRlKSkge2xpYnJhcnkobHVicmlkYXRlKX0gCgppZiAoIXJlcXVpcmUoInNjYWxlcyIpKSB7Cmluc3RhbGwucGFja2FnZXMoInNjYWxlcyIpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIApsaWJyYXJ5KCJzY2FsZXMiKSAKfQoKa25pdHI6Om9wdHNfY2h1bmskc2V0KAoJZWNobyA9IFRSVUUsCgltZXNzYWdlID0gRkFMU0UsCgl3YXJuaW5nID0gRkFMU0UsCgljb21tZW50ID0gTkEsCglyZXN1bHRzID0gVFJVRQopCmBgYAoKIyBJbnRyb2R1Y3Rpb24gYW5kIEJhY2tncm91bmQKSGVyZSB3ZSBoYXZlIGEgZGF0YXNldCBjb21wb3NlZCBvZiBoaXN0b3JpY2FsIHJlY29yZHMgb2YgdGhlIE5ldyBZb3JrIFN0b2NrIEV4Y2hhbmdlJ3MgbW9zdCBmYW1vdXMgaW5kZXgsIHRoZSBTJlAgNTAwLiBNYWRlIHVwIG9mIHRoZSB0b3AgNTAwIGNvbXBhbmllcyBmb3Igd2hpY2ggdHJhZGVzIGFjcm9zcyB0aGUgVW5pdGVkIFN0YXRlcyBhcmUgbWFkZSwgdGhlIFMmUCA1MDAgKG9yIFMmUCksIHdhcyBiZWxpZXZlZCB0byBoYXZlIGhhZCBhIG1hcmtldCBjYXAgb2YganVzdCBvdmVyICoqJDU3IHRyaWxsaW9uKiogYXMgb2YgdGhpcyBwYXN0IEF1Z3VzdC4gU2luY2UgaXQncyBpbmNlcHRpb24sIHRoZSBTJlAgaGFzIGJlZW4gdXNlZCBhcyBhIHBvbGl0aWNhbCBiZW5jaG1hcmsgZm9yIHRoZSBncm93dGggYW5kIG92ZXJhbGwgaGVhbHRoIG9mIHRoZSBVbml0ZWQgU3RhdGVzJyBlY29ub215LiAKCkZvciBteSBhbmFseXNpcywgSSB3YW50ZWQgdG8gc3BlY2lmaWNhbGx5IGZvY3VzIG9uIHdoYXQgdGhlIG9wZW5pbmcgcHJpY2Ugb2YgdGhlIFMmUCB3YXMgYXQgdGhlIGZpcnN0IHRyYWRpbmcgZGF5IG9mIGVhY2ggeWVhciwgd2hpY2ggcmFuZ2VkIGZyb20gSmFudWFyeSAybmQgdG8gSmFudWFyeSA0dGggZGVwZW5kaW5nIG9uIGlmIHRoZSBOZXcgWWVhcnMnIGhvbGlkYXkgY29pbmNpZGVkIHdpdGggdGhlIHdlZWtlbmQuIE9uIHRvcCBvZiBvYnNlcnZpbmcgYW55IHBvc3NpYmxlIGhpc3RvcmljYWwgdHJlbmRzLCBJIGFsc28gdXNlZCB0aGlzIGRhdGEgYXMgZ3JvdW5kcyB0byB0ZXN0IG11bHRpcGxlIGRpZmZlcmVudCB0aW1lIHNlcmllcyBtb2RlbGluZyBtZXRob2RzLiBBIGJyZWFrZG93biBvZiB0aGUgZGF0YXNldCdzIG9yaWdpbmFsIHN0cnVjdHVyZSBpcyBiZWxvdy4KCmBgYHtyIERhdGEgTG9hZGluZyBhbmQgQ2xlYW5pbmcsIGluY2x1ZGU9RkFMU0V9CkRhdGFfVXJsPSAiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL0NocmlzQjIzMjMvU1RBMzIxL3JlZnMvaGVhZHMvbWFpbi9TUFguY3N2IgoKRGF0YSA9IHJlYWRfZGVsaW0oRGF0YV9VcmwsIGRlbGltID0gIiwiLCBzaG93X2NvbF90eXBlcyA9IEZBTFNFKQoKc3VtKGlzLm5hKERhdGEpKQojIE5vIG1pc3NpbmcgdmFsdWVzIGluIGRhdGFzZXQKCmdsaW1wc2UoRGF0YSkKIyBBbGwgdmFyaWFibGVzIGZvcm1hdHRlZCBwcm9wZXJseQogICMgT3BlbiwgSGlnaCwgTG93LCBDbG9zZSBhbmQgQWRqIENsb3NlIGFsbCBpbiBzaW5nbGUgZG9sbGFyIHVuaXRzCgoKIyBCZWxvdyBjcmVhdGVkIGEgc3Vic2V0IG9mIHRoZSBkYXRhLCBsb29raW5nIGF0IGZpcnN0IHRyYWRpbmcgZGF5IG9mIGVhY2ggeWVhcgpGaXJzdF9EYXkgPSBEYXRhICU+JQogICMgRXh0cmFjdCB5ZWFyIGZyb20gZWFjaCBkYXRlCiAgbXV0YXRlKFllYXIgPSB5ZWFyKERhdGUpKSAlPiUKICAjIEZpbHRlciBvbmx5IHllYXJzIDE5MjjigJMyMDE5CiAgZmlsdGVyKFllYXIgPj0gMTkyOCkgJT4lCiAgIyBHcm91cCBieSB5ZWFyCiAgZ3JvdXBfYnkoWWVhcikgJT4lCiAgIyBQaWNrIHRoZSByb3cgd2l0aCB0aGUgZWFybGllc3QgZGF0ZSBpbiB0aGF0IHllYXIKICBzbGljZV9taW4oRGF0ZSwgbiA9IDEsIHdpdGhfdGllcyA9IEZBTFNFKSAlPiUKICB1bmdyb3VwKCkKCkZpcnN0X0RheV9PcGVuaW5nID0gRmlyc3RfRGF5WyAsYygiRGF0ZSIsICJPcGVuIildCgojIFllYXJzIDE5MjggdG8gMjAxMCB3aWxsIGJlIGZvciBtb2RlbCB0cmFpbmluZwpUcmFpbmluZ19EYXRhID0gRmlyc3RfRGF5X09wZW5pbmdbMTo4MyxdCgojIFllYXJzIDIwMTEgdG8gMjAyMCB3aWxsIGJlIGZvciBtb2RlbCB0ZXN0aW5nClRlc3RpbmdfRGF0YSA9IEZpcnN0X0RheV9PcGVuaW5nWzg0OjkzLF0KCiMgV2UgY3JlYXRlIHRoZSB0aW1lIHNlcmllcyBvYmplY3Qgd2l0aCB0aGUgdHMoKSBmdW5jdGlvbiwgY29taW5nIGZyb20gZm9yZWNhc3QgcGFja2FnZQpUU19UcmFpbmluZ19EYXRhID0gdHMoVHJhaW5pbmdfRGF0YSRPcGVuLAogICAgICAgICAgICAgICAgICAgICAgc3RhcnQgPSAxOTI4LAogICAgICAgICAgICAgICAgICAgICAgZW5kID0gMjAxMCwKICAgICAgICAgICAgICAgICAgICAgIGZyZXF1ZW5jeSA9IDEpCgppbnZpc2libGUoVFNfVHJhaW5pbmdfRGF0YSkgCmBgYAoKYGBge3IgVmFyaWFibGUgVGFibGUsIGVjaG89RkFMU0V9CmxpYnJhcnkoa25pdHIpCiNnbGltcHNlKERhdGEpCgpWYXJfVGFibGUgPSBkYXRhLmZyYW1lKAogIE5hbWUgPSBjKCJEYXRlIiwKICAgICAgICAgICAiT3BlbiIsIAogICAgICAgICAgICJIaWdoIiwgCiAgICAgICAgICAgIkxvdyIsCiAgICAgICAgICAgIkNsb3NlIiwgCiAgICAgICAgICAgIkFkaiBDbG9zZSIsIAogICAgICAgICAgICJWb2x1bWUiKSwKICAKICBNZWFuaW5nID0gYygiRGF0ZSBmb3IgdGhhdCBvYnNlcnZhdGlvbjsgWVlZWS1NTS1ERCBmb3JtIiwgCiAgICAgICAgICAgICAgIlMmUCdzIG9wZW5pbmcgbWFya2V0IHByaWNlIiwKICAgICAgICAgICAgICAiVGhhdCBkYXkncyBoaWdoZXN0IHJlY29yZGVkIHByaWNlIiwgCiAgICAgICAgICAgICAgIlRoYXQgZGF5J3MgbG93ZXN0IHJlY29yZGVkIHByaWNlIiwgCiAgICAgICAgICAgICAgIlMmUCdzIGNsb3NpbmcgbWFya2V0IHByaWNlIiwgIAogICAgICAgICAgICAgICJTJlAncyBjbG9zaW5nIG1hcmtldCBwcmljZSwgYWNjb3VudGluZyBmb3IgY29ycG9yYXRlIGFjdGl2aXR5KiIsCiAgICAgICAgICAgICAgIlRvdGFsIG51bWJlciBvZiBzaGFyZXMgdHJhZGVkIGluIHRoZSBtYXJrZXQgdGhhdCBkYXkiKSwgCiAgICAgICAgICAgICAgCiAgCiAgRGF0YV9UeXBlID0gYygiRGF0ZSIsICJkb3VibGUiLCAiZG91YmxlIiwgImRvdWJsZSIsICJkb3VibGUiLCAiZG91YmxlIiwgImRvdWJsZSIpKQoKa2FibGUoVmFyX1RhYmxlKSAlPiUKICBrYWJsZV9zdHlsaW5nKAogICAgYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImJvcmRlcmVkIiksCiAgICBmdWxsX3dpZHRoID0gRkFMU0UsCiAgICBwb3NpdGlvbiA9ICJjZW50ZXIiKQpgYGAKKiBDb3Jwb3JhdGUgYWN0aXZpdHkgcHJpbWFyaWx5IGluY2x1ZGVzLCBidXQgaXMgbm90IGxpbWl0ZWQgdG8sIGRpdmlkZW5kIHBheW91dHMgYW5kIHN0b2NrIHNwbGl0cwoKIyBNb2RlbCBDcmVhdGlvbgpGb3IgbXkgdGltZSBzZXJpZXMgbW9kZWxpbmcgZXhwZXJpbWVudHMsIEkgY2hvc2UgdG8gZGl2aWRlIG15IGRhdGFzZXQgaW50byBzZXBhcmF0ZSBwb3J0aW9ucywgd2l0aCB0aGUgbGFyZ2VyIGNodW5rIGJlaW5nIHVzZWQgZm9yIG1vZGVsIHRyYWluaW5nIGFuZCB0aGUgbGF0ZXIgcGFydCBiZWluZyB1c2VkIGZvciBtb2RlbCB0ZXN0aW5nLiBNb3JlIHNwZWNpZmljYWxseSwgdGhlIFMmUCdzIHllYXItYmVnaW5uaW5nIG1hcmtldCBvcGVuIGZyb20gMTkyOCB0byAyMDEwIEkgZGVkaWNhdGVkIHRvICoqdHJhaW5pbmcqKi4gV2hpbGUgdGhlIG9ic2VydmF0aW9ucyBmcm9tIDIwMTEgdG8gMjAyMCB3aWxsIGJlIHVzZWQgdG8gKip0ZXN0KiogbXkgbW9kZWwncyBhY2N1cmFjeS4KCkkgY3JlYXRlZCBmb3VyIGRpZmZlcmVudCB0aW1lIHNlcmllcyBtb2RlbHMgLSBNb3ZpbmcgQXZlcmFnZSwgTmFpdmUsIFNlYXNvbmFsIE5haXZlIGFuZCBEcmlmdCAtIHVzaW5nIHRoZSB0cmFpbmluZyBkYXRhLiBFYWNoIG1vZGVsIHdhcyBzZXQgdG8gaGF2ZSBhIGZvcmVjYXN0IGhvcml6b24gKG51bWJlciBvZiBmdXR1cmUgaW50ZXJ2YWxzIHRvIHByZWRpY3QpIG9mIDEwLiBBIHRhYmxlIHN1bW1hcnkgb2YgZWFjaCBtb2RlbCdzIHByZWRpY3Rpb25zIGZvciB0aGUgdGVuIHllYXJzIGFmdGVyIG91ciB0cmFpbmluZyBkYXRhJ3MgZW5kIGlzIGJlbG93LgpgYGB7ciwgQmFzZWxpbmUgRm9yZWNhc3RpbmcgTW9kZWwgQ3JlYXRpb259CiMjIyMjIE1vdmluZyBBdmVyYWdlIE1vZGVsCk1vdmluZ19BdmVyYWdlID0gcm91bmQobWVhbmYoVFNfVHJhaW5pbmdfRGF0YSwgaD0xMCkkbWVhbiwgNCkKICAjIGFyZ3VtZW50IGggcmVwcmVzZW50cyB0aGUgZm9yZWNhc3QgaG9yaXpvbiwgd2hpY2ggaXMgdGhlIG51bWJlciBvZiBpbnRlcnZhbHMgaW50byB0aGUgZnV0dXJlIHdlIGFyZSBwcmVkaWN0aW5nIHZhbHVlcyBmb3IKICAjIFNldHRpbmcgaD0xMCBzaW5jZSB3ZSB1c2VkIDEwIGZvciB0aGUgc2FtcGxlIHNpemUgb2YgdGhlIHRlc3RpbmcgZGF0YQoKIyMjIyMgTmFpdmUgTW9kZWwKTmFpdmUgPSByb3VuZChuYWl2ZShUU19UcmFpbmluZ19EYXRhLCBoPTEwKSRtZWFuLCA0KQoKIyMjIyMgU2Vhc29uYWwgTmFpdmUgTW9kZWwKU2Vhc29uYWxfTmFpdmUgPSByb3VuZChzbmFpdmUoVFNfVHJhaW5pbmdfRGF0YSwgaD0xMCkkbWVhbiwgNCkKCiMjIyMjIERyaWZ0IE1vZGVsCkRyaWZ0ID0gcm91bmQocndmKFRTX1RyYWluaW5nX0RhdGEsIGg9MTAsIGRyaWZ0PVRSVUUpJG1lYW4sIDQpCiAgIyBmdW5jdGlvbiByd2Ygc3RhbmRzIGZvciAicmFuZG9tIHdhbGsgd2l0aCBkcmlmdCIKICAjIE5vdGUgdGhhdCB3ZSBNVVNUIHNldCBkcmlmdCA9IFRSVUUgaW4gb3JkZXIgZm9yIGl0IHRvIGJlIGEgcHJvcGVyIGRyaWZ0IG1vZGVsCgpZZWFyID0gYygiMjAxMSIsICIyMDEyIiwgIjIwMTMiLCAiMjAxNCIsICIyMDE1IiwgIjIwMTYiLCAiMjAxNyIsICIyMDE4IiwgIjIwMTkiLCAiMjAyMCIpCgpCYXNlbGluZV9Nb2RlbHMgPSBjYmluZChZZWFyLCBNb3ZpbmdfQXZlcmFnZSwgTmFpdmUsIFNlYXNvbmFsX05haXZlLCBEcmlmdCkKCmNvbG5hbWVzKEJhc2VsaW5lX01vZGVscykgPSBjKCJZZWFyIiwgIk1vdmluZyBBdmVyYWdlIiwgIk5haXZlIiwgIlNlYXNvbmFsIE5haXZlIiwgIkRyaWZ0IikKCmthYmxlKEJhc2VsaW5lX01vZGVscywgY2FwdGlvbiA9ICJNb2RlbCBGb3JlY2FzdGluZyBQcm9qZWN0aW9ucyIpCmBgYApMb29raW5nIGF0IG91ciBzdW1tYXJ5IHRhYmxlLCB3ZSBzZWUgYSBmZXcgaW50ZXJlc3RpbmcgdGFrZWF3YXlzLiAKCi0gRmlyc3QsIHdlIHNlZSB0aGF0IHRoZSB5ZWFyLXRvLXllYXIgcHJlZGljdGVkIHZhbHVlcyBmcm9tIHRoZSBtb3ZpbmcgYXZlcmFnZSBtb2RlbCBhcmUgKipmYXIqKiBiZW5lYXRoIHRob3NlIG9mIHRoZSBvdGhlciAzIG1vZGVscy4gVGhpcyBpcyBiZWNhdXNlIHRoZSBtb3ZpbmcgYXZlcmFnZSBtZXRob2Qgb3BlcmF0ZXMgb24gdGhlIGFzc3VtcHRpb24gdGhhdCBhbGwgZnV0dXJlIHZhbHVlcyB3aWxsIGJlIGVxdWFsIHRvIHRoZSBtZWFuIG9mIGFsbCBwcmV2aW91cyB2YWx1ZXMuIEEgbGFyZ2UgYW1vdW50IG9mIG91ciB0cmFpbmluZyBkYXRhICg1OCBvZiB0aGUgNzMpIHllYXJzLCBoYWQgYSBtYXJrZXQgb3BlbiBiZWxvdyAkMjAwLgoKLSBXZSBhbHNvIG5vdGljZSB0aGVyZSBpcyB0b3RhbCBlcXVhbGl0eSBiZXR3ZWVuIHRoZSBuYWl2ZSBhbmQgc2Vhc29uYWwgbmFpdmUgbW9kZWxzLiBUaGUgbmFpdmUgbWV0aG9kIGFzc3VtZXMgdGhhdCBhbGwgZnV0dXJlIG9ic2VydmF0aW9ucyB3aWxsIGhhdmUgZXF1YWwgdmFsdWUgdG8gdGhhdCBvZiB0aGUgbW9zdCBwcmV2aW91cyBvYnNlcnZhdGlvbiAod2hpY2ggZXhwbGFpbnMgd2h5IHRoZSBwcmVkaWN0ZWQgdmFsdWUgaXMgdGhlIHNhbWUgZm9yIGVhY2ggeWVhciBpbiB0aGUgc3RyaW5nIG9mIGZvcmVjYXN0cykuIE1lYW53aGlsZSwgdGhlIHNlYXNvbmFsIG5haXZlIGFwcHJvYWNoIGFwcGxpZXMgdGhlIHByZW1pc2Ugb2YgdGhlIG5haXZlIG1ldGhvZCB0byBkYXRhIHRoYXQgb3BlcmF0ZXMgaW4gYSBjeWNsaWNhbCBtYW5uZXIgKHRoaW5rIGZyZXF1ZW5jaWVzIG9mIHdlYXRoZXIgcmVsYXRlZCBldmVudHMgdGllZCB0byBzZWFzb25hbCBjaGFuZ2VzKS4gSW4gdGhlIGNhc2Ugb2Ygb3VyIGRhdGFzZXQsIGVhY2ggUyZQIG1hcmtldCBvcGVuaW5nIGlzIG9jY3VycmluZyBhdCAqYXBwcm94aW1hdGVseSogdGhlIHNhbWUgZGF5IGV2ZXJ5IHllYXIsIG1ha2luZyB0aGUgbmFpdmUgYW5kIHNlYXNvbmFsIG5haXZlIG1vZGVsIHJlc3VsdHMgcHJhY3RpY2FsbHkgaWRlbnRpY2FsLgoKLSBMYXN0bHksIHdlIHNlZSB0aGF0IHRoZSBkcmlmdCBtb2RlbCBpcyB0aGUgb25seSBvbmUgaW4gd2hpY2ggZm9yZWNhc3RlZCB2YWx1ZXMgZGlmZmVyIGZyb20geWVhciB0byB5ZWFyLiBVbmxpa2UgdGhlIG90aGVyIHRocmVlIG1ldGhvZHMsIHRoZSBkcmlmdCBtZXRob2QgZG9lcyBhY2NvdW50IGZvciBoaXN0b3JpY2FsIGF2ZXJhZ2VzIGluIHJhdGUgb2YgaW5jcmVhc2UgYW5kIGRlY3JlYXNlIGFzIHdlbGwgYXMgYXZlcmFnZXMgaW4gb3ZlcmFsbCB2YWx1ZSBhcyB3ZWxsLiBHaXZlbiB0aGF0IHRoZSBTJlAgaGFzIGFsd2F5cyBnYWluZWQgdmFsdWUgd2hlbiBsb29rZWQgYXQgZnJvbSBhIGxvbmcgdGVybSBwZXJzcGVjdGl2ZSwgaXQgaXMgbm90IHN1cnByaXNpbmcgdGhhdCBvdXIgZHJpZnQgZm9yZWNhc3RzIHNob3cgYW4gYXZlcmFnZSBpbmNyZWFzZSBvZiBhYm91dCAxMyB0byAxNCBVU0QgaW4gcHJvamVjdGVkIG1hcmtldCBvcGVuaW5nIGZyb20gb25lIHllYXIgdG8gdGhlIG5leHQuCgojIE1vZGVsIEZvcmVjYXN0IFZpc3VhbGl6YXRpb25zCkFmdGVyIGV4YW1pbmluZyB0aGUgbW9kZWwgZm9yZWNhc3RzIHllYXItYnkteWVhciwgSSBkZWNpZGVkIHRvIGdyYXBoIGVhY2ggbW9kZWwncyBwcmVkaWN0aW9ucyBhbG9uZ3NpZGUgdGhlIGtub3duIGhpc3RvcmljYWwgZGF0YSB0byBhbGxvdyBmb3IgYSBxdWljayBleGFtaW5hdGlvbiBvZiBob3cgYWNjdXJhdGUgZWFjaCBtb2RlbCB3YXMuIFRoZSBmaXJzdCBncmFwaCBjb25zaXN0cyBvZiB0aGUgZW50aXJlIHNjb3BlIG9mIHRoaXMgZGF0YXNldCdzIG9ic2VydmF0aW9ucyAoMTkyOSB0byAyMDIwKSwgd2hpbGUgdGhlIHNlY29uZCBncmFwaCBJIGNvbnN0cmFpbmVkIHRvIHRoaXMgY2VudHVyeSdzIG1hcmtldCBvcGVucy4gSXQgc2hvdWxkIGJlIG5vdGVkIHRoYXQsIGluIGJvdGggZ3JhcGhzLCB0aGUgcmVwcmVzZW50YXRpb24gb2YgdGhlIG5haXZlIG1vZGVsIGZvcmVjYXN0cyBjYW4gYmUgZGlmZmljdWx0IHRvIHNlZSBhcyB0aGV5IHBlcmZlY3RseSBvdmVybGFwIHdpdGggdGhvc2Ugb2YgdGhlIHNlYXNvbmFsIG5haXZlIG1vZGVsLgpgYGB7ciBHcmFwaHMsIGZpZy5hbGlnbj0nY2VudGVyJywgd2FybmluZz1GQUxTRX0KREZfUHJlZGljdGlvbnMgPSBjYmluZCgyMDExOjIwMjAsIGRhdGEuZnJhbWUoTW92aW5nX0F2ZXJhZ2UpLCBkYXRhLmZyYW1lKE5haXZlKSwgZGF0YS5mcmFtZShTZWFzb25hbF9OYWl2ZSksIGRhdGEuZnJhbWUoRHJpZnQpKQogIGNvbG5hbWVzKERGX1ByZWRpY3Rpb25zKSA9IGMoIlllYXIiLCAiTW92aW5nIEF2ZXJhZ2UiLCAiTmFpdmUiLCAiU2Vhc29uYWwgTmFpdmUiLCAiRHJpZnQiKQoKRnVsbF9HcmFwaCA9IChnZ3Bsb3QoKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBGaXJzdF9EYXksIG1hcHBpbmcgPSBhZXMgKHggPSBZZWFyLCB5ID0gT3BlbikpICsgICAgICAgICAgICAgCiAgICAgIGdlb21fcG9pbnQoZGF0YSA9IEZpcnN0X0RheSwgbWFwcGluZyA9IGFlcyh4ID0gWWVhciwgeSA9IE9wZW4pKSArCiAgICAgIGxhYnMoeCA9ICJZZWFyIiwgeSA9ICJTJlAgNTAwIE9wZW4gKCQpIiwgdGl0bGUgPSJTJlAgNTAwIEZpcnN0IE1hcmtldCBPcGVuIG9mIHRoZSBZZWFyIikgKyAKICBnZW9tX2xpbmUoZGF0YSA9IERGX1ByZWRpY3Rpb25zLCBtYXBwaW5nID0gYWVzICh4ID0gWWVhciwgeSA9IE1vdmluZ19BdmVyYWdlKSkgKwogICAgICBnZW9tX3BvaW50KGRhdGEgPSBERl9QcmVkaWN0aW9ucywgbWFwcGluZyA9IGFlcyAoeCA9IFllYXIsIHkgPSBNb3ZpbmdfQXZlcmFnZSwgY29sb3IgPSAiTW92aW5nIEF2ZXJhZ2UiKSkgKyAKICAKICBnZW9tX2xpbmUoZGF0YSA9IERGX1ByZWRpY3Rpb25zLCBtYXBwaW5nID0gYWVzICh4ID0gWWVhciwgeSA9IE5haXZlKSkgKyAKICAgICAgZ2VvbV9wb2ludChkYXRhID0gREZfUHJlZGljdGlvbnMsIG1hcHBpbmcgPSBhZXMgKHggPSBZZWFyLCB5ID0gTmFpdmUsIGNvbG9yID0gIk5haXZlIikpICsgCiAgCiAgZ2VvbV9saW5lKGRhdGEgPSBERl9QcmVkaWN0aW9ucywgbWFwcGluZz1hZXMoeCA9IFllYXIsIHkgPSBgU2Vhc29uYWwgTmFpdmVgKSkgKwogICAgICBnZW9tX3BvaW50KGRhdGEgPSBERl9QcmVkaWN0aW9ucywgbWFwcGluZyA9IGFlcyAoeCA9IFllYXIsIHkgPSBTZWFzb25hbF9OYWl2ZSwgY29sb3IgPSAiU2Vhc29uYWwgTmFpdmUiKSkgKyAKICAKICBnZW9tX2xpbmUoZGF0YSA9IERGX1ByZWRpY3Rpb25zLCBtYXBwaW5nPWFlcyh4ID0gWWVhciwgeSA9IGBEcmlmdGApKSArCiAgICAgIGdlb21fcG9pbnQoZGF0YSA9IERGX1ByZWRpY3Rpb25zLCBtYXBwaW5nID0gYWVzICh4ID0gWWVhciwgeSA9IERyaWZ0LCBjb2xvciA9ICJEcmlmdCIpKSArCiAgCiAgc2NhbGVfeF9jb250aW51b3VzKAogICAgbGltaXRzID0gYygxOTI1LCAyMDIwKSwKICAgIGJyZWFrcyA9IHNlcSgxOTMwLCAyMDIwLCAxMCkgCiAgKSArCgogIHNjYWxlX3lfY29udGludW91cygKICAgIGxpbWl0cyA9IGMoMCwgMzI1MCksCiAgICBicmVha3MgPSBzZXEoMCwgMzUwMCwgNTAwKSAKICApKQoKRnVsbF9HcmFwaAoKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpSZWR1Y2VkX0dyYXBoID0gKGdncGxvdCgpICsgIAogIGdlb21fbGluZShkYXRhID0gRmlyc3RfRGF5LCBtYXBwaW5nID0gYWVzICh4ID0gWWVhciwgeSA9IE9wZW4pKSArCiAgICAgIGdlb21fcG9pbnQoZGF0YSA9IEZpcnN0X0RheSwgbWFwcGluZyA9IGFlcyh4ID0gWWVhciwgeSA9IE9wZW4pKSArCiAgbGFicyh4ID0gIlllYXIiLCB5ID0gIlMmUCA1MDAgT3BlbiAoJCkiLCB0aXRsZSA9IlMmUCA1MDAgRmlyc3QgTWFya2V0IE9wZW4gb2YgdGhlIFllYXIgKDIwMDAgLSAyMDIwKSIpICsgCiAgZ2VvbV9saW5lKGRhdGEgPSBERl9QcmVkaWN0aW9ucywgbWFwcGluZyA9IGFlcyAoeCA9IFllYXIsIHkgPSBNb3ZpbmdfQXZlcmFnZSkpICsKICAgICAgZ2VvbV9wb2ludChkYXRhID0gREZfUHJlZGljdGlvbnMsIG1hcHBpbmcgPSBhZXMgKHggPSBZZWFyLCB5ID0gTW92aW5nX0F2ZXJhZ2UsIGNvbG9yID0gIk1vdmluZyBBdmVyYWdlIiwpKSArIAogIAogIGdlb21fbGluZShkYXRhID0gREZfUHJlZGljdGlvbnMsIG1hcHBpbmcgPSBhZXMgKHggPSBZZWFyLCB5ID0gTmFpdmUpKSArIAogICAgICBnZW9tX3BvaW50KGRhdGEgPSBERl9QcmVkaWN0aW9ucywgbWFwcGluZyA9IGFlcyAoeCA9IFllYXIsIHkgPSBOYWl2ZSwgY29sb3IgPSAiTmFpdmUiKSkgKyAKICAKICBnZW9tX2xpbmUoZGF0YSA9IERGX1ByZWRpY3Rpb25zLCBtYXBwaW5nPWFlcyh4ID0gWWVhciwgeSA9IGBTZWFzb25hbCBOYWl2ZWApKSArCiAgICAgIGdlb21fcG9pbnQoZGF0YSA9IERGX1ByZWRpY3Rpb25zLCBtYXBwaW5nID0gYWVzICh4ID0gWWVhciwgeSA9IFNlYXNvbmFsX05haXZlLCBjb2xvciA9ICJTZWFzb25hbCBOYWl2ZSIpKSArIAogIAogIGdlb21fbGluZShkYXRhID0gREZfUHJlZGljdGlvbnMsIG1hcHBpbmc9YWVzKHggPSBZZWFyLCB5ID0gYERyaWZ0YCkpICsKICAgICAgZ2VvbV9wb2ludChkYXRhID0gREZfUHJlZGljdGlvbnMsIG1hcHBpbmcgPSBhZXMgKHggPSBZZWFyLCB5ID0gRHJpZnQsIGNvbG9yID0gIkRyaWZ0IikpICsKICAKICBzY2FsZV94X2NvbnRpbnVvdXMoCiAgICBsaW1pdHMgPSBjKDIwMDAsIDIwMjApLAogICAgYnJlYWtzID0gc2VxKDIwMDAsIDIwMjAsIDQpIAogICkgKwogIAogIHNjYWxlX3lfY29udGludW91cygKICAgIGxpbWl0cyA9IGMoMjUwLCAzMjUwKSwKICAgYnJlYWtzID0gc2VxKDI1MCwgMzI1MCwgNTAwKQogICkKICApCgpSZWR1Y2VkX0dyYXBoCmBgYApXZSBjYW4gc2VlIGZyb20gb3VyIHR3byBncmFwaHMgdGhhdCwgbGlrZSBzZWVuIGluIHRoZSBzdW1tYXJ5IHRhYmxlIGFib3ZlLCB0aGUgbW92aW5nIGF2ZXJhZ2UgbW9kZWwncyBmb3JlY2FzdHMgYXJlIHdlbGwgYmVuZWF0aCB0aG9zZSBvZiB0aGUgb3RoZXIgdGhyZWUgbW9kZWxzLiBUaGF0IGlzIGJlY2F1c2Ugb2YgdGhlIG11Y2ggZ3JlYXRlciBpbmZsdWVuY2UgdGhhdCB0aGUgZmlyc3Qgcm91Z2hseSA1MCB5ZWFycyBvZiB0aGUgUyZQJ3Mgb3BlbmluZyBtYXJrZXQgcHJpY2UgaGFzIG9uIHRoZSBtb3ZpbmcgYXZlcmFnZSdzIGNhbGN1bGF0aW9uIHRoYW4gaXQgZG9lcyBvbiB0aGUgbmFpdmUsIHNlYXNvbmFsIG5haXZlIG9yIGRyaWZ0LiBUaGUgYXZlcmFnZSBvcGVuaW5nIHByaWNlIGZyb20gMTkyOCB0byAxOTc4IHdhcyBvbmx5IGFib3V0ICRgciByb3VuZChzdW0oVHJhaW5pbmdfRGF0YVsxOjUxLCAyXSkvNTAsIDIpYC4KCkFkZGl0aW9uYWxseSwgd2hpbGUgb3VyIG90aGVyIHRocmVlIG1vZGVscycgZm9yZWNhc3RzIHJlc2VtYmxlIHRoYXQgb2YgdGhlIGluZGV4JyB0cnVlIG9wZW5pbmcgdmFsdWUgZmFyIGdyZWF0ZXIgdGhhbiB0aG9zZSBvZiBvdXIgbW92aW5nIGF2ZXJhZ2UgbW9kZWwsIHRoZXkgYWxzbyBjb25zaXN0ZW50bHkgdW5kZXJlc3RpbWF0ZWQuIFRoZSBkcmlmdCBtb2RlbCdzIHByZWRpY3RlZCB2YWx1ZXMgd2VyZSB0aGUgbW9zdCBhY2N1cmF0ZSwgd2hpY2ggaXMgbm90IHN1cHJpc2luZyBnaXZlbiB0aGF0LCBhcyBwcmV2aW91c2x5IHNhaWQsIHRoZSBkcmlmdCBhcHByb2FjaCBkb2VzIGFjY291bnQgZm9yIGhpc3RvcmljYWwgdHJlbmRzIGluIGluY3JlYXNlIG9yIGRlY3JlYXNlLiBUaGUgcmVhc29uIHRoZSBkcmlmdCBmb3JlY2FzdHMnIHRyZW5kIHdhcyBpbiB0aGUgcHJvcGVyIGRpcmVjdGlvbiAoaW5jcmVhc2luZyBvdmVyIHRpbWUpLCBidXQgYXQgYSByYXRlIGZhciBsZXNzZXIgdGhhbiB0aGUgdHJ1ZSByYXRlIG9mIG1hcmtldCBvcGVuIGluY3JlYXNlIGlzIGR1ZSB0byB0aGUgZXh0cmFvcmRpbmFyeSB3ZWFrbmVzcyBvZiB0aGUgUyZQIG9wZW5pbmcncyB1cHdhcmQgdHJlbmQgdGhyb3VnaG91dCB0aGUgZmlyc3QgZml2ZSBkZWNhZGVzIG9yIHNvIG9mIG91ciBkYXRhc2V0LgoKYGBge3IsIGluY2x1ZGU9RkFMU0V9CiMgQXZlcmFnZSBTJlAgb3BlbmluZyBwcmljZSBmcm9tIDE5MjggLSAxOTc4CnN1bShUcmFpbmluZ19EYXRhWzE6NTEsIDJdKS81MApgYGAKCiMgTW9kZWwgQWNjdXJhY3kgTWVhc3VyZXMKRmluYWxseSwgSSB3YW50ZWQgdG8gcXVhbnRpZnkgdGhlIHN0cmVuZ3RoIG9mIG15IGZvdXIgbW9kZWxzIHVzaW5nIHNvbWUgc3RhbmRhcmQgbWVhc3VyZXMgb2YgbW9kZWxpbmcgYWNjdXJhY3kuIEJlbG93IGlzIGEgYnJlYWtkb3duIG9mIGVhY2ggbW9kZWwncyBtZWFuIGVycm9yIChNRSksIG1lYW4gc3F1YXJlIGVycm9yIChNU0UpIGFuZCBtZWFuIGFic29sdXRlIHByZWRpY3Rpb24gZXJyb3IgKE1BUEUpLiBNZWFuIGVycm9yIGFuZCBtZWFuIHNxdWFyZSBlcnJvciBhcmUgY29uc2lkZXJlZCBtZWFzdXJlcyBvZiBhYnNvbHV0ZSBlcnJvciwgYW5kIGFyZSBhIGdvb2QgcmVmZXJlbmNlIHN0YXRpc3RpYyB0byBzdW1tYXJpemUgaG93ICJvZmYiIG91ciBtb2RlbHMnIGZvcmVjYXN0cyB3ZXJlIG9uIGF2ZXJhZ2UuIE1lYW53aGlsZSwgTUFQRSBpcyBjYWxsZWQgYSBtZWFzdXJlIG9mIHJlbGF0aXZlIGVycm9yLCBhcyBpdCB0ZWxscyB1cyBvbiBhdmVyYWdlIGhvdyAib2ZmIiBvdXIgbW9kZWxzJyBmb3JlY2FzdHMgd2VyZSBhcyBhICpwZXJjZW50Ki4KCk5vbmUgb2YgdGhlIG1ldHJpY3MgY2FsY3VsYXRlZCBpbiB0aGUgdGFibGUgYmVsb3cgYXJlIHBhcnRpY3VsYXJseSBzdXJwcmlzaW5nLiBUaGV5IGFyZSBpbi1saW5lIHdpdGggb3VyIHByZXZpb3VzIGdyYXBoaWNhbCBkaXNwbGF5cyBhbmQgZm9yZWNhc3Qgc3VtbWFyeSB0YWJsZS4gT3VyIGRyaWZ0IG1vZGVsIGlzIHRoZSBtb3N0IGFjY3VyYXRlLCBvdXIgbmFpdmUgYW5kIHNlYXNvbmFsIG5haXZlIG1vZGVscyBhcmUgc2xpZ2h0bHkgd29yc2UsIGFuZCB0aGUgbW92aW5nIGF2ZXJhZ2UgaXMgc2lnbmlmaWNhbnRseSBsZXNzIHVzZWZ1bCB0aGFuIHRoZSBvdGhlcnMuCmBgYHtyfQojIFdpbGwgZmluZCBtZWFuIGVycm9yIChNRSksIG1lYW4gc3F1YXJlZCBlcnJvciAoTVNFKSBhbmQgbWVhbiBhYnNvbHV0ZSBwcmVkaWN0aW9uIGVycm9yIChNQVBFKSBmb3IgZWFjaCBvZiB0aGUgNCBiYXNlbGluZSBtb2RlbHMuIFRoZW4gY2JpbmQgdGhlbSBhbGwgaW50byBhIHRhYmxlIGFuZCBvdXRwdXQgd2l0aCBrYWJsZSBmdW5jdGlvbi4KCiMjIyBNRSBmaXJzdApNb3ZpbmdfQXZlcmFnZV9FcnJvcnMgPSBkYXRhLmZyYW1lKERGX1ByZWRpY3Rpb25zJGBNb3ZpbmcgQXZlcmFnZWAgLSBUZXN0aW5nX0RhdGEkT3BlbikKICAgIE1vdmluZ19BdmVyYWdlX01FID0gc3VtKE1vdmluZ19BdmVyYWdlX0Vycm9ycykvbnJvdyhNb3ZpbmdfQXZlcmFnZV9FcnJvcnMpCgpOYWl2ZV9FcnJvcnMgPSBkYXRhLmZyYW1lKERGX1ByZWRpY3Rpb25zJE5haXZlIC0gVGVzdGluZ19EYXRhJE9wZW4pCiAgICBOYWl2ZV9NRSA9IHN1bShOYWl2ZV9FcnJvcnMpL25yb3coTmFpdmVfRXJyb3JzKQogICAgClNlYXNvbmFsX05haXZlX0Vycm9ycyA9IGRhdGEuZnJhbWUoREZfUHJlZGljdGlvbnMkYFNlYXNvbmFsIE5haXZlYCAtIFRlc3RpbmdfRGF0YSRPcGVuKQogICAgU2Vhc29uYWxfTmFpdmVfTUUgPSBzdW0oU2Vhc29uYWxfTmFpdmVfRXJyb3JzKS9ucm93KFNlYXNvbmFsX05haXZlX0Vycm9ycykKICAgIApEcmlmdF9FcnJvcnMgPSBkYXRhLmZyYW1lKERGX1ByZWRpY3Rpb25zJERyaWZ0IC0gVGVzdGluZ19EYXRhJE9wZW4pCiAgICBEcmlmdF9NRSA9IHN1bShEcmlmdF9FcnJvcnMpL25yb3coRHJpZnRfRXJyb3JzKQoKQWxsX01vZGVsX01FcyA9IHJiaW5kKE1vdmluZ19BdmVyYWdlX01FLCBOYWl2ZV9NRSwgU2Vhc29uYWxfTmFpdmVfTUUsIERyaWZ0X01FKQoKIyMjIE1TRSBzZWNvbmQKCiMgQ3JlYXRlIHNxdWFyZWQgZXJyb3IgZGF0YSBmcmFtZXMKTW92aW5nX0F2ZXJhZ2VfU1FFcnJvcnMgPSBkYXRhLmZyYW1lKE1vdmluZ19BdmVyYWdlX0Vycm9yc14yKQpOYWl2ZV9TUUVycm9ycyA9IGRhdGEuZnJhbWUoTmFpdmVfRXJyb3JzXjIpClNlYXNvbmFsX05haXZlX1NRRXJyb3JzID0gZGF0YS5mcmFtZShTZWFzb25hbF9OYWl2ZV9FcnJvcnNeMikKRHJpZnRfU1FFcnJvcnMgPSBkYXRhLmZyYW1lKERyaWZ0X0Vycm9yc14yKQoKIyBVc2Ugc3F1YXJlZCBlcnJvciBkYXRhIGZyYW1lcyB0byBjcmVhdGUgTVNFIG9iamVjdHMKTW92aW5nX0F2ZXJhZ2VfTVNFID0gc3VtKE1vdmluZ19BdmVyYWdlX1NRRXJyb3JzKS9ucm93KE1vdmluZ19BdmVyYWdlX1NRRXJyb3JzKQpOYWl2ZV9NU0UgPSBzdW0oTmFpdmVfU1FFcnJvcnMpL25yb3coTmFpdmVfU1FFcnJvcnMpClNlYXNvbmFsX05haXZlX01TRSA9IHN1bShTZWFzb25hbF9OYWl2ZV9TUUVycm9ycykvbnJvdyhTZWFzb25hbF9OYWl2ZV9TUUVycm9ycykKRHJpZnRfTVNFID0gc3VtKERyaWZ0X1NRRXJyb3JzKS9ucm93KERyaWZ0X1NRRXJyb3JzKQoKQWxsX01vZGVsX01TRXMgPSByYmluZChNb3ZpbmdfQXZlcmFnZV9NU0UsIE5haXZlX01TRSwgU2Vhc29uYWxfTmFpdmVfTVNFLCBEcmlmdF9NU0UpCgojTUFQRSB0aGlyZApNb3ZpbmdfQXZlcmFnZV9QRUkgPSBkYXRhLmZyYW1lKChNb3ZpbmdfQXZlcmFnZV9FcnJvcnMvVGVzdGluZ19EYXRhJE9wZW4pKjEwMCkKTW92aW5nX0F2ZXJhZ2VfTUFQRSA9IHJvdW5kKHN1bShhYnMoTW92aW5nX0F2ZXJhZ2VfUEVJKSkvbnJvdyhNb3ZpbmdfQXZlcmFnZV9QRUkpLDQpCgpOYWl2ZV9QRUkgPSBkYXRhLmZyYW1lKChOYWl2ZV9FcnJvcnMvVGVzdGluZ19EYXRhJE9wZW4pKjEwMCkKTmFpdmVfTUFQRSA9IHJvdW5kKHN1bShhYnMoTmFpdmVfUEVJKSkvbnJvdyhOYWl2ZV9QRUkpLDQpCgpTZWFzb25hbF9OYWl2ZV9QRUkgPSBkYXRhLmZyYW1lKChTZWFzb25hbF9OYWl2ZV9FcnJvcnMvVGVzdGluZ19EYXRhJE9wZW4pKjEwMCkKU2Vhc29uYWxfTmFpdmVfTUFQRSA9IHJvdW5kKHN1bShhYnMoU2Vhc29uYWxfTmFpdmVfUEVJKSkvbnJvdyhTZWFzb25hbF9OYWl2ZV9QRUkpLDQpCgpEcmlmdF9QRUkgPSBkYXRhLmZyYW1lKChEcmlmdF9FcnJvcnMvVGVzdGluZ19EYXRhJE9wZW4pKjEwMCkKRHJpZnRfTUFQRSA9IHJvdW5kKHN1bShhYnMoRHJpZnRfUEVJKSkvbnJvdyhEcmlmdF9QRUkpLDQpCgpBbGxfTW9kZWxfTUFQRXMgPSByYmluZChNb3ZpbmdfQXZlcmFnZV9NQVBFLCBOYWl2ZV9NQVBFLCBTZWFzb25hbF9OYWl2ZV9NQVBFLCBEcmlmdF9NQVBFKQoKTW9kZWxfQWNjdXJhY3kgPSBjYmluZChBbGxfTW9kZWxfTUVzLCBBbGxfTW9kZWxfTVNFcywgQWxsX01vZGVsX01BUEVzKQpyb3duYW1lcyhNb2RlbF9BY2N1cmFjeSkgPSBjKCJNb3ZpbmcgQXZlcmFnZSIsICJOYWl2ZSIsICJTZWFzb25hbCBOYWl2ZSIsICJEcmlmdCIpCmNvbG5hbWVzKE1vZGVsX0FjY3VyYWN5KSA9IGMoIk1FIiwgIk1TRSIsICJNQVBFIikKa2FibGUoTW9kZWxfQWNjdXJhY3ksIGNhcHRpb24gPSAiTW9kZWwgQWNjdXJhY3kgU3VtbWFyeSIpCmBgYAoKIyBDb25jbHVzaW9uCkluIGNvbmNsdXNpb24sIHdlIGNhbiBzZWUgdGhhdCB0aGUgc3RyYWlnaHRmb3J3YXJkIGFwcGxpY2F0aW9uIG9mIHRoZXNlIGZvdXIgc3RhbmRhcmQgYW5kIGNvbW1vbiB0aW1lIHNlcmllcyBtb2RlbGluZyBtZXRob2RzIG9uIHRoZSBoaXN0b3JpY2FsIHN0b2NrIG1hcmtldCBkYXRhIHRoYXQgd2FzIGV4YW1pbmVkLCB3ZXJlIG5vdCBwYXJ0aWN1bGFybHkgdXNlZnVsIGluIGZvcmVjYXN0aW5nIGZ1dHVyZSBTJlAgNTAwIG9wZW5pbmcgbWFya2V0IHByaWNlcy4gVGhpcyB3YXMgbGFyZ2VseSBkdWUgdG8gdGhlIGNvbnNpc3RlbnRseSBsb3cgbWFya2V0IG9wZW5zIHRocm91Z2hvdXQgdGhlIGZpcnN0IDUwIG9yIHNvIHllYXJzIG9mIHRoZSBTJlAgaW5kZXguIEluIHRoZSBmdXR1cmUsIGl0IHdvdWxkIGJlIGludGVyZXN0aW5nIHRvIGV4YW1pbmUgdGhlIG1vZGVsIGFjY3VyYWN5IG9mIHRoZXNlIG1ldGhvZHMgLSBwYXJ0aWN1bGFybHkgdGhlIG1vdmluZyBhdmVyYWdlIGFuZCBkcmlmdCAtIGlmIHRoZSByYW5nZSBvZiB0aGUgdHJhaW5pbmcgZGF0YSB3YXMgZ3JlYXRseSByZWR1Y2VkIHRvIG9ubHkgaW5jbHVkZSBtb3JlIHJlY2VudCBkZWNhZGVzLgoKIyBSZWZlcmVuY2VzOgoKT3JpZ2luYWwgRGF0YXNldCBTb3VyY2U6CgotIGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vZGF0YXNldHMvaGVucnloYW4xMTcvc3AtNTAwLWhpc3RvcmljYWwtZGF0YS9kYXRhCgpEYXRhc2V0IERvd25sb2FkIExpbmsgdmlhIEdpdGh1YjoKCi0gaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL0NocmlzQjIzMjMvU1RBMzIxL3JlZnMvaGVhZHMvbWFpbi9TUFguY3N2Cg==