1 Introduction and Background

The dataset I examined today tracked the day-to-day performance of Amazon’s stock from May 15, 1997 to October 27, 2021. These daily observations recorded the stock’s price at market opening and closing, as well as its high, low, adjusted closing rate and trading volume for the day.

For the purposes of my analysis, I chose to track the history of Amazon’s market performance on a month-by-month basis. I took the stock’s average opening price for each month, and constrained the timeline from January 2009 to October of 2021, a total of 154 samples of monthly data. I used this subset of the data to create a number of time series models with the hopes of formulating at least one that can forecast Amazon’s average market opening on a month-by-month timeline with relative accuracy.

This is not an associative analysis that attempts to greatly explain why the stock’s opening price has historically moved the way it has, but rather simply a predictive tool. The primary methods of forecast modeling I utilized include exponential smoothing, Holt and Holt-Winters calculations.

Data_Url= "https://raw.githubusercontent.com/ChrisB2323/STA321/refs/heads/main/Amazon.csv"
Original_Data = read_delim(Data_Url, delim = ",", show_col_types = FALSE)

#(glimpse(Original_Data))
  # Everything stored the right way ^^

#sum(is.na(Original_Data)) = 0
Data = mutate(Original_Data,
       Month = month(Date, label = TRUE),
       Year = year(Date),
  )

Data = group_by(Data, Month, Year)
Data = summarize(Data, mean(Open))
  # ^^ Since I am looking at month-by-month opens, need to summarize and group
Data = sort_by(Data, Data$Year, Data$Month)
  # ^^ Prioritized sorting, first sort by year (oldest first), and then by month of year (January to December)

# Restricting my analysis from Jan 2009 to Oct 2021, rounding opening price to nearest cent
Data = Data[141:294,]
colnames(Data)[3] = "Open"
Data$Open = round(Data$Open,2)  

Data$Season[Data$Month == "Dec" | Data$Month == "Jan" | Data$Month == "Feb"] = "Winter"
Data$Season[Data$Month == "Mar" | Data$Month == "Apr" | Data$Month == "May"] = "Spring"
Data$Season[Data$Month == "Jun" | Data$Month == "Jul" | Data$Month == "Aug"] = "Summer"
Data$Season[Data$Month == "Sep" | Data$Month == "Oct" | Data$Month == "Nov"] = "Fall"
  # Added variable Season to better analyze seasonality of data over time (more with this later)

Winter_Months = filter(Data, Season == "Winter")
Spring_Months = filter(Data, Season == "Spring")
Summer_Months = filter(Data, Season == "Summer")
Fall_Months = filter(Data, Season == "Fall")

2 Data Visualization

Before beginning model creation, I wanted to visualize two essential parts of the data at hand, its trend and seasonal components. These elements play an important role in understanding the model-to-model accuracy comparisons that will be examined later.

2.1 Trend

Below I plotted the chosen analysis interval (January 2009 to October 2021). What we see is a tale of two very different half-decades; with a rather mildly increasing trend from 2009 to about 2016, and then a large and exponential increase in market value from 2016 onward.

Time_Series = ts(Data$Open, frequency = 12, start = c(2009,1))

plot(Time_Series,
     main = "Amazon Stock Opening Price (2009 - 2021)",
     xlab = "Year",
     ylab = "Price ($USD)",
     lwd = 3)

2.2 Seasonality

While the trend component of Amazon’s stock opening is rather straightforward, it is also valuable to breakdown the seasonal aspect of its historical performance. Below is a table averaging its opening price per season for each respective year, with the total across all the cited years at the bottom.

# Making a season-by-season breakdown throughout the designated data range
Season_By_Season = group_by(Data, Season, Year)
Season_By_Season = summarize(Season_By_Season, mean(Open))
colnames(Season_By_Season)[3] = "Open"
Season_By_Season = sort_by(Season_By_Season, Season_By_Season$Year, Season_By_Season$Season)
Season_By_Season$Open = round(Season_By_Season$Open,2)

Years = data.frame(c("2009", "2010", "2011", "2012", "2013","2014", "2015", "2016", "2017", "2018", "2019", "2020", "2021"))
colnames(Years) = "Year"

Winter_Seasons = Season_By_Season[Season_By_Season$Season == "Winter", ]
Spring_Seasons = Season_By_Season[Season_By_Season$Season == "Spring", ]
Summer_Seasons = Season_By_Season[Season_By_Season$Season == "Summer", ]
Fall_Seasons = Season_By_Season[Season_By_Season$Season == "Fall", ]

# Subsetting that season-by-season breakdown to look at each season throughout the years

All_Seasons = cbind(Years, Winter_Seasons$Open, Spring_Seasons$Open, Summer_Seasons$Open, Fall_Seasons$Open)
  colnames(All_Seasons) = c("Year", "Winter", "Spring", "Summer", "Fall")

# To have an averages for the seasons across the years
Season_Totals = data.frame("All Years",
      round(mean(Winter_Months$Open),2),
      round(mean(Spring_Months$Open),2),
      round(mean(Summer_Months$Open),2),
      round(mean(Fall_Months$Open),2))
  colnames(Season_Totals) = c("Year", "Winter", "Spring", "Summer", "Fall")
  invisible(as.numeric(Season_Totals[,(2:5)]))
  
All_Seasons = rbind(All_Seasons, Season_Totals)
kable(All_Seasons, caption = "Amazon Stock Opening Season-By-Season", align = "c")
Amazon Stock Opening Season-By-Season
Year Winter Spring Summer Fall
2009 83.52 74.82 83.55 104.99
2010 141.88 133.00 121.50 158.39
2011 182.57 183.51 202.11 218.72
2012 206.41 201.55 227.00 245.09
2013 308.55 263.60 287.88 330.99
2014 353.48 330.20 330.07 318.70
2015 448.61 398.81 477.79 581.10
2016 633.37 626.20 740.80 793.35
2017 936.48 906.07 991.98 1036.30
2018 1440.47 1536.16 1792.45 1797.06
2019 1681.56 1818.38 1872.48 1775.40
2020 2383.95 2156.80 2967.89 3189.74
2021 3237.10 3227.87 3427.83 3379.21
All Years 865.18 912.07 1040.26 1010.73

As we can see, the summer has historically been Amazon’s best season according to the market, averaging a market open of $1040.26. Fall’s yearly average trails slightly behind at $1010.73, with spring and winter’s averages being noticeably lower. Beyond that, it is also visible that the difference in the stock’s lowest and highest seasonal average tends to increase in magnitude as the years went on. In 2009, the difference between Amazon’s best and worst seasonal average was $30.17. In 2021, that same metric was $199.96. This increasing magnitude of in-year seasonal difference can be seen at greater ease with the plots below.

###### Make a plot of all the data
plot(x = Winter_Seasons$Year, y = Winter_Seasons$Open,
     main = "Amazon Stock Opening Season-By-Season",
     xlab = "Year",
     ylab = "Value($USD)")
  lines(x = Winter_Seasons$Year, y = Winter_Seasons$Open, col = "red", lwd = 1.5)
    points(x = Winter_Seasons$Year, y = Winter_Seasons$Open, col = "red", pch = 21, bg = "red")
    
  lines(x = Spring_Seasons$Year, y = Spring_Seasons$Open, col = "black", lwd = 1.5)
    points(x = Spring_Seasons$Year, y = Spring_Seasons$Open, col = "black", pch = 21, bg = "black")
    
  lines(x = Summer_Seasons$Year, y = Summer_Seasons$Open, col = "green", lwd = 1.5)
    points(x = Summer_Seasons$Year, y = Summer_Seasons$Open, col = "green", pch = 21, bg = "green")
    
  lines(x = Fall_Seasons$Year, y = Fall_Seasons$Open, col = "purple", lwd = 1.5)
    points(x = Fall_Seasons$Year, y = Fall_Seasons$Open, col = "purple", pch = 21, bg = "purple")
    
    legend("topleft",
       legend = c("Winter", "Spring", "Summer", "Fall"),
       col = c("red", "black", "green", "purple"),
       lty = 1, pch = 16, lwd = 2)

###### Make a reduced plot, 2015 to 2021
Reduced_Winter_Seasons = Winter_Seasons[7:13,]
Reduced_Spring_Seasons = Spring_Seasons[7:13,]
Reduced_Summer_Seasons = Summer_Seasons[7:13,]
Reduced_Fall_Seasons = Fall_Seasons[7:13,]

plot(x = Reduced_Winter_Seasons$Year, y = Reduced_Winter_Seasons$Open,
     main = "Amazon Stock Opening Season-By-Season \n (2015 - 2021)",
     xlab = "Year",
     ylab = "Value($USD)")
  lines(x = Reduced_Winter_Seasons$Year, y = Reduced_Winter_Seasons$Open, col = "red", lwd = 2)
    points(x = Reduced_Winter_Seasons$Year, y = Reduced_Winter_Seasons$Open, col = "red", pch = 21, bg = "red")
    
  lines(x = Reduced_Spring_Seasons$Year, y = Reduced_Spring_Seasons$Open, col = "black", lwd = 2)
    points(x = Reduced_Spring_Seasons$Year, y = Reduced_Spring_Seasons$Open, col = "black", pch = 21, bg = "black")
    
  lines(x = Reduced_Summer_Seasons$Year, y = Reduced_Summer_Seasons$Open, col = "green", lwd = 2)
    points(x = Reduced_Summer_Seasons$Year, y = Reduced_Summer_Seasons$Open, col = "green", pch = 21, bg = "green")
    
  lines(x = Reduced_Fall_Seasons$Year, y = Reduced_Fall_Seasons$Open, col = "purple", lwd = 2)
    points(x = Reduced_Fall_Seasons$Year, y = Reduced_Fall_Seasons$Open, col = "purple", pch = 21, bg = "purple")
    
   legend("topleft",
     legend = c("Winter", "Spring", "Summer", "Fall"),
     col = c("red", "black", "green", "purple"),
     lty = 1, pch = 16, lwd = 2)  

These plots offer a visual confirmation for the numerical patterns present in the table above. Graphically speaking, seasonal differences in average opening price are rather unnoticeable from 2009 to about 2016 or 2017. But as time continues beyond that point, the seasonal oscillation increases. This is a similar phenomenon to the trend component of the graph seen earlier, meaning that Amazon’s stock opening price season-by-season is inconsistent, and that inconsistency expands with the upward trend of the overall opening data.

3 Forecast Modeling

Now with a solid grasp of the data’s trend and seasonality, I moved forward and began the forecast modeling process. In total, I created eight models - one simple exponential smoothing, three Holt and four Holt-Winters.

3.1 Training and Testing Sets

Since it is poor statistical practice to test a model on the same data which it is trained/built on, I separated my data into two distinct subsets. The training dataset consisted of monthly observations from the nearly 12 year span of January 2009 to October 2020. Meanwhile, the testing dataset (the observations which my time series models will attempt to computationally predict or forecast), consists of monthly averages from November 2020 to October 2021.

Training_Data = Data[1:142,]
Testing_Data = Data[143:154,]

Time_Series_Training = ts(Training_Data$Open, frequency = 12, start = c(2009,1))
Time_Series_Testing = ts(Testing_Data$Open, frequency = 12, start = c(2020,11))

3.2 Model Creation

Setting each model’s forecast interval equal to 12, I constructed 8 time series models. A breakdown of each model type with a corresponding brief explanation is below.

  • Simple Exponential Smoothing (SES): Older observations are given an exponentially decreasing degree of weight in the calculation of forecasted values. This is done with the use of what is called smoothing constants. Forecasts from an SES model are all equal to the same value, as SES does not consider a dataset’s trend or seasonality, but rather simply calculates a weighted moving average.

  • Holt Additive: A generalization of the SES approach. Forecast calculations include the addition of the data’s trend parameter.

  • Holt Additive W/ Damp: A modification of the additive Holt approach, as it includes a damping parameter that reduces the absolute value of a trend’s increasing or decreasing effect on forecasts over time. This is a popular choice when it is believed that a trend will “flatten out” in the somewhat near future.

  • Holt Multiplicative W/ Damp: Carries the idea of its additive version, but the damping parameter is multiplied and takes the role of a proportional weight, rather than added as an absolute value. *Holt models do not explicitly include a dataset’s seasonal component in its calculations, however the multiplicative damp model is still seen as preferable to the additive when seasonal oscillations are inconsistent throughout the time length of the data.

  • Holt-Winters (HW) Additive: Parallel to the Holt additive model, but also takes into account the data’s seasonal oscillations.

  • HW Additive W/ Damp: Adds parameters representative of both the trend and seasonality respectively to the forecast calculations. Used when there is an assumption of a “flattening curve” phenomenon regarding the dataset’s trend.

  • HW Multiplicative:: Builds on the Holt multiplicative model by multiplying that calculation by a seasonal factor.

  • HW Multiplicative W/ Damp:: Used when we assume a decrease in the severity of data’s upward or downward trend. Factors in, via multiplication, both the response’s trend and seasonal oscillation.

# Use h = 12 for all these forecasts

##### Simple Exponential Smoothing
Simple_Model = ses(Time_Series_Training, h = 12) #Model 1
    Simple_Predictions = data.frame(round(Simple_Model$mean,2)) # the next 10 forecasts

##### Holt
  # "damped" is the assumption that the magnitude of time series' trend or seasonal components will DECREASE over time
Holt_Model_Add = holt(Time_Series_Training, h = 12, damped = FALSE) #Model 2
    Holt_Add_Predictions = data.frame(round(Holt_Model_Add$mean,2))
    
Holt_Model_Add_Damp = holt(Time_Series_Training, h = 12, damped = TRUE) #Model 3
    Holt_Add_Damp_Predictions = data.frame(round(Holt_Model_Add_Damp$mean,2))
    
Holt_Model_Mult_Damp = holt(Time_Series_Training, h = 12, exponential = TRUE, damped = TRUE) #Model 4
    Holt_Mult_Damp_Predictions = data.frame(round(Holt_Model_Mult_Damp$mean,2))

##### Holt-Winters (HW)
HW_Model_Add = hw(Time_Series_Training, h = 12, damped = FALSE, seasonal = "additive") #Model 5
    HW_Add_Predictions = data.frame(round(HW_Model_Add$mean,2))
  
HW_Model_Mult = hw(Time_Series_Training, h = 12, damped = FALSE, seasonal = "multiplicative") #Model 6
    HW_Mult_Predictions = data.frame(round(HW_Model_Mult$mean,2))
  
HW_Model_Add_Damp = hw(Time_Series_Training, h = 12, damped = TRUE, seasonal = "additive") #Model 7
    HW_Add_Damp_Predictions = data.frame(round(HW_Model_Add_Damp$mean,2))
    
HW_Model_Mult_Damp = hw(Time_Series_Training, h = 12, damped = TRUE, seasonal = "multiplicative") #Model 8
    HW_Mult_Damp_Predictions = data.frame(round(HW_Model_Mult_Damp$mean,2))    

Below we can see a breakdown of each model’s forecasted stock opening values for the 12 periods following the training set’s last observation (Nov 2020 - Oct 2021). A summary of some interesting takeaways are also available.

##### Putting them all together  
Predictions = cbind(Simple_Predictions, #1
                    Holt_Add_Predictions, #2
                    Holt_Add_Damp_Predictions, #3
                    Holt_Mult_Damp_Predictions, #4
                    HW_Add_Predictions, #5
                    HW_Mult_Predictions, #6
                    HW_Add_Damp_Predictions, #7 
                    HW_Mult_Damp_Predictions) #8

colnames(Predictions) = c("SES", "Holt Add", "Holt Add W/ Damp", "Holt Multiply W/ Damp", "HW Add", "HW Multiply", "HW Add W/ Damp", "HW Multiply W/ Damp")
kable(Predictions, caption = "Model Forecasts for Monthly Amazon Stock Openings", align = "c")
Model Forecasts for Monthly Amazon Stock Openings
SES Holt Add Holt Add W/ Damp Holt Multiply W/ Damp HW Add HW Multiply HW Add W/ Damp HW Multiply W/ Damp
3241.35 3340.39 3289.48 3300.31 3331.56 3212.56 3318.53 3197.97
3241.35 3439.42 3327.95 3360.33 3419.13 3237.60 3389.56 3200.23
3241.35 3538.45 3358.72 3409.14 3526.80 3386.01 3470.33 3326.71
3241.35 3637.48 3383.34 3448.69 3636.39 3473.67 3557.02 3472.25
3241.35 3736.51 3403.03 3480.66 3719.15 3493.00 3614.45 3430.89
3241.35 3835.53 3418.79 3506.45 3847.23 3780.15 3711.32 3696.34
3241.35 3934.56 3431.39 3527.23 3979.00 3984.88 3811.29 3830.22
3241.35 4033.59 3441.48 3543.93 4087.03 4274.96 3880.84 3946.92
3241.35 4132.62 3449.54 3557.35 4207.22 4678.05 3961.56 4258.44
3241.35 4231.65 3456.00 3568.13 4293.29 4670.11 4008.19 4273.38
3241.35 4330.68 3461.16 3576.77 4395.84 4695.49 4064.64 4165.20
3241.35 4429.70 3465.29 3583.70 4479.89 4599.32 4099.32 4050.32

First, we see that our SES model’s forecasts were all equal to $3241.35. This means that, if we were to assume no future deviation due to trend or seasonal complication, Amazon’s stock should continue to have an average opening of that amount. Next, the highest predicted values, by a substantial amount, came from the Holt additive, Holt-Winters additive and Holt-Winters multiplicative models. This is not surprising as they are the three models out of the eight created ones that take into account the increasing trend that Amazon’s market open had from January 2009 to October 2020 and operate under the assumption that such trend will continue at approximately the same rate.

3.3 Model Evaluation/Ranking Metrics

After looking at each models’ predicted values, I chose to run standard accuracy metrics on each one, using the training data to do so. Ultimate error analysis down the line will utilize the testing data.

Accuracy_Table = data.frame(rbind(round(accuracy(Simple_Model),4),
                       round(accuracy(Holt_Model_Add),4),
                       round(accuracy(Holt_Model_Add_Damp),4),
                       round(accuracy(Holt_Model_Mult_Damp),4),
                       round(accuracy(HW_Model_Add),4),
                       round(accuracy(HW_Model_Mult),4),
                       round(accuracy(HW_Model_Add_Damp),4),
                       round(accuracy(HW_Model_Mult_Damp),4)
                       ))
                       
rownames(Accuracy_Table) = colnames(Predictions)
kable(Accuracy_Table, caption = "Model Accuracy Summary Table", align = "c")
Model Accuracy Summary Table
ME RMSE MAE MPE MAPE MASE ACF1
SES 22.4633 78.0381 43.8711 2.6342 5.8786 0.1942 0.2736
Holt Add 6.3619 72.6341 39.5756 0.3233 5.5699 0.1752 0.1400
Holt Add W/ Damp 10.2700 72.0711 39.6539 1.1240 5.7019 0.1755 -0.0207
Holt Multiply W/ Damp 8.7280 71.7120 39.3588 0.9515 5.7406 0.1742 -0.0186
HW Add 6.1619 70.4673 41.9370 0.3457 7.9333 0.1856 0.1267
HW Multiply 6.1625 67.4218 41.9806 0.1399 6.6633 0.1858 0.0722
HW Add W/ Damp 9.0695 70.5768 42.2699 0.7657 8.0253 0.1871 0.1107
HW Multiply W/ Damp 11.6052 61.5790 39.8682 0.9885 6.2923 0.1765 0.1686

Along with creating the table seen above, I also created sorted subtables for each accuracy metric, ranking model performance from best to worst. I took particular note of the SES, Holt additive with damp and Holt multiplicative with damp models, as their predicted values are the most similar to the true opening stock values present in our testing set. The others all overforecasted to a noticeable degree.

Regarding the three models of heightened interest, the SES model actually ranked last in all metrics except MAPE, and both the damped Holt additive and damped Holt multiplicative models ranked anywhere between 3rd and 5th on most metrics. While this seems contradictory to my previous observation that these three models’ forecasts were most similar to the testing set’s true monthly average Amazon market opens, it is crucial to remember that the accuracy calculations at hand were performed via the training data. Therefore, this is something to note and to keep in mind while moving forward in the analysis.

Ranked_ME = data.frame(rownames(Accuracy_Table), Accuracy_Table$ME)
colnames(Ranked_ME) = c("Model", "ME")
  Ranked_ME = arrange(Ranked_ME, ME)
  
Ranked_RMSE = data.frame(rownames(Accuracy_Table), Accuracy_Table$RMSE)
colnames(Ranked_RMSE) = c("Model", "RMSE")
  Ranked_RMSE = arrange(Ranked_RMSE, RMSE)
  
Ranked_MAE = data.frame(rownames(Accuracy_Table), Accuracy_Table$MAE)
colnames(Ranked_MAE) = c("Model", "MAE")
  Ranked_MAE = arrange(Ranked_MAE, MAE)
  
Ranked_MPE = data.frame(rownames(Accuracy_Table), Accuracy_Table$MPE)
colnames(Ranked_MPE) = c("Model", "MPE")
  Ranked_MPE = arrange(Ranked_MPE, MPE)
  
Ranked_MAPE = data.frame(rownames(Accuracy_Table), Accuracy_Table$MAPE)
colnames(Ranked_MAPE) = c("Model", "MAPE")
  Ranked_MAPE = arrange(Ranked_MAPE, MAPE)
  
Ranked_MASE = data.frame(rownames(Accuracy_Table), Accuracy_Table$MASE)
colnames(Ranked_MASE) = c("Model", "MASE")
  Ranked_MASE = arrange(Ranked_MASE, MASE)
  
Ranked_ACF1 = data.frame(rownames(Accuracy_Table), Accuracy_Table$ACF1)
colnames(Ranked_ACF1) = c("Model", "ACF1")
  Ranked_ACF1 = arrange(Ranked_ACF1, ACF1)
  
kable(Ranked_ME)
kable(Ranked_RMSE)
kable(Ranked_MAE)
kable(Ranked_MPE)
kable(Ranked_MAPE)
kable(Ranked_MASE)
kable(Ranked_ACF1)

3.4 Model Plotting

Below I plotted the forecasts of all eight models in comparison to the values from our testing dataset. For greater visual ease, my first plot contains the four models whose predictions do not factor in seasonal oscillations. While my second plot displays the four seasonally-considerate models (the Holt-Winters ones).

# Seasonal
  colnames(Simple_Predictions) = "Open"
  colnames(Holt_Add_Predictions) = "Open"
  colnames(Holt_Add_Damp_Predictions) = "Open"
  colnames(Holt_Mult_Damp_Predictions) = "Open"

# Non-seasonal
  colnames(HW_Add_Predictions) = "Open"
  colnames(HW_Add_Damp_Predictions) = "Open"
  colnames(HW_Mult_Predictions) = "Open"
  colnames(HW_Mult_Damp_Predictions) = "Open"

List_Of_Dates = as.Date(c("2020-11-01", "2020-12-01", "2021-01-01", "2021-02-01", "2021-03-01", "2021-04-01", "2021-05-01", "2021-06-01", "2021-07-01", "2021-08-01", "2021-09-01", "2021-10-01"))  
 
Testing_Data = cbind(List_Of_Dates, Testing_Data)
colnames(Testing_Data)[1] = "Date"

###### Plot 1: Non-Seasonal Methods
plot(x = Testing_Data$Date, y = Testing_Data$Open,
     main = "Non-Seasonal Forecasting Methods", 
     mtext("Simple Exponential Smoothing and Holt Models", side = 3, line = 0.5, cex = 0.8),
     xlab = "Time (Nov 2020 - Oct 2021)",
     ylab = "Amazon Stock Opening ($USD)",
     ylim = c(3000, 4500))
  lines(x = Testing_Data$Date, y = Testing_Data$Open, col = "black", lwd = 3)
    points(x = Testing_Data$Date, y = Testing_Data$Open, col = "black", pch = 8, bg = "black")
   
  # Simple   
  lines(x = Testing_Data$Date, y = Simple_Predictions$Open, col = "darkblue", lwd = 2)
    points(x = Testing_Data$Date, y = Simple_Predictions$Open, col = "darkblue", pch = 21, bg = "darkblue")
    
  # Holt Add W/O Damp
  lines(x = Testing_Data$Date, y = Holt_Add_Predictions$Open, col = "darkred", lwd = 2)
    points(x = Testing_Data$Date, y = Holt_Add_Predictions$Open, col = "darkred", pch = 21, bg = "darkred")
    
  # Holt Add W/ Damp
  lines(x = Testing_Data$Date, y = Holt_Add_Damp_Predictions$Open, col = "darkgreen", lwd = 2)
    points(x = Testing_Data$Date, y = Holt_Add_Damp_Predictions$Open, col = "darkgreen", pch = 21, bg = "darkgreen") 
    
  # Holt Mult W/ Damp
  lines(x = Testing_Data$Date, y = Holt_Mult_Damp_Predictions$Open, col = "gray", lwd = 2)
    points(x = Testing_Data$Date, y = Holt_Mult_Damp_Predictions$Open, col = "gray", pch = 21, bg = "gray")
    
    legend("topleft",
     legend = c("True Values", "Simple", "Holt Add", "Holt Add W/ Damp", "Holt Mult W/ Damp"),
     col = c("black", "darkblue", "darkred", "darkgreen", "gray"),
     lty = 1, pch = 16, lwd = 2)

From our non-seasonal plot, it is noticeable right away that the SES and damped Holt models performed far better predictively than the non-damped additive Holt model. Meanwhile, the multiplicative Holt model overforecasted more than the additive Holt or SES model.

###### Plot 2: Seasonal HW Methods
plot(x = Testing_Data$Date, y = Testing_Data$Open,
     main = "Seasonal Forecasting Methods", 
     mtext("Holt-Winters Models", side = 3, line = 0.5, cex = 0.8),
     xlab = "Time (Nov 2020 - Oct 2021)",
     ylab = "Amazon Stock Opening ($USD)",
     ylim = c(3000, 4800))
  lines(x = Testing_Data$Date, y = Testing_Data$Open, col = "black", lwd = 3)
    points(x = Testing_Data$Date, y = Testing_Data$Open, col = "black", pch = 8, bg = "black")
   
  # Simple   
  lines(x = Testing_Data$Date, y = HW_Add_Predictions$Open, col = "darkblue", lwd = 2)
    points(x = Testing_Data$Date, y = HW_Add_Predictions$Open, col = "darkblue", pch = 21, bg = "darkblue")
    
  # Holt Add W/O Damp
  lines(x = Testing_Data$Date, y = HW_Add_Damp_Predictions$Open, col = "darkred", lwd = 2)
    points(x = Testing_Data$Date, y = HW_Add_Damp_Predictions$Open, col = "darkred", pch = 21, bg = "darkred")
    
  # Holt Add W/ Damp
  lines(x = Testing_Data$Date, y = HW_Mult_Predictions$Open, col = "darkgreen", lwd = 2)
    points(x = Testing_Data$Date, y = HW_Mult_Predictions$Open, col = "darkgreen", pch = 21, bg = "darkgreen") 
    
  # Holt Mult W/ Damp
  lines(x = Testing_Data$Date, y = HW_Mult_Damp_Predictions$Open, col = "gray", lwd = 2)
    points(x = Testing_Data$Date, y = HW_Mult_Damp_Predictions$Open, col = "gray", pch = 21, bg = "gray")
    
   legend("topleft",
     legend = c("True Values", "HW Add", "HW Add W/ Damp", "HW Mult", "HW Mult W/ Damp"),
     col = c("black", "darkblue", "darkred", "darkgreen", "gray"),
     lty = 1, pch = 16, lwd = 2)

After taking a look at the four Holts-Winters (HW) models - the ones that consider a dataset’s seasonal component - I saw clear and consistent overprediction. Even the damped HW models, which operate under the presumption that an increasing or decreasing trend previously seen in the data will mitigate in effect over time, did not have a forecasted value close to matching the true recorded average opening market value for Amazon those selected months.

After reviewing each of the eight models’ forecasted values, and then seeing them all plotted in relation to the known values from our testing dataset, I chose to designate the damped additive Holt model and the SES model as the two most effective in their prediction accuracy. Next up I took a closer look at the two, running error analysis, this time by comparing each model’s forecasts to the testing data values.

3.5 Final Model Selection

Finally, before selecting which of these models was most effective in this predictive analysis scenario, I wanted to look at each model’s errors, both observation-by-observation and holistically. I created a table that broke down each model’s error for each of the 12 months’ forecasts, as well as calculating the respective mean square error (MSE) and mean absolute prediction error (MAPE). Per these calculations, I deemed the SES model as the most effective for forecasting purposes of the eight available.

Simple_Errors = Simple_Predictions - Testing_Data$Open
Holt_Add_Damp_Errors = Holt_Add_Damp_Predictions - Testing_Data$Open

Model_Select_Table = cbind(Testing_Data$Open, 
                           Simple_Predictions, Simple_Errors,
                           Holt_Add_Damp_Predictions, Holt_Add_Damp_Errors)

colnames(Model_Select_Table) = c("True Values", "Simple Smoothing", "Simple Smoothing Errors", "Holt Addition W/ Damp", "Holt Errors")
kable(Model_Select_Table, caption = "Prediction and Error Breakdown for SES and Additive Holt Models", align = "c")
Prediction and Error Breakdown for SES and Additive Holt Models
True Values Simple Smoothing Simple Smoothing Errors Holt Addition W/ Damp Holt Errors
3147.33 3241.35 94.02 3289.48 142.15
3199.93 3241.35 41.42 3327.95 128.02
3206.54 3241.35 34.81 3358.72 152.18
3267.66 3241.35 -26.31 3383.34 115.68
3074.58 3241.35 166.77 3403.03 328.45
3347.73 3241.35 -106.38 3418.79 71.06
3261.31 3241.35 -19.96 3431.39 170.08
3360.01 3241.35 -118.66 3441.48 81.47
3612.71 3241.35 -371.36 3449.54 -163.17
3310.76 3241.35 -69.41 3456.00 145.24
3432.44 3241.35 -191.09 3461.16 28.72
3325.98 3241.35 -84.63 3465.29 139.31
# MSE
Simple_Err_MSE = sum(Simple_Errors^2)/nrow(Simple_Errors)
Holt_Add_Damp_Errors_MSE = sum(Holt_Add_Damp_Errors^2)/nrow(Holt_Add_Damp_Errors)

# MAPE
Simple_Err_MAPE = (sum(abs((Simple_Errors/Testing_Data$Open)*100)))/nrow(Simple_Errors)
Holt_Add_Damp_Errors_MAPE = (sum(abs((Holt_Add_Damp_Errors/Testing_Data$Open)*100)))/nrow(Holt_Add_Damp_Errors)

Error_Summary = data.frame(rbind(Simple_Err_MSE, Holt_Add_Damp_Errors_MSE),
                            rbind(Simple_Err_MAPE, Holt_Add_Damp_Errors_MAPE))
colnames(Error_Summary) = c("MSE", "MAPE")
rownames(Error_Summary) = c("Simple Exponential Smoothing", "Holt Additive W/ Damp")
kable(Error_Summary, caption = "Accuracy Calculations for SES and Additive Holt Models", align = "c")
Accuracy Calculations for SES and Additive Holt Models
MSE MAPE
Simple Exponential Smoothing 21039.21 3.283775
Holt Additive W/ Damp 24131.76 4.264767

4 Conclusion

Ultimately, of the eight models that were created throughout this analysis, the most straightforward one - simple exponential smoothing (SES) - was the most effective. Retrospectively, I believe this can be attributed to two reasons; the first being the spike in the rate of Amazon’s stock increase from about 2018 to October of 2021 (the ending quarter of the data used for this analysis). The magnitude of the rise in value, in relation to the amount of time passed during that interval, was so much greater than the first three quarters of the dataset. Because of this, all of the non-damped models (both Holt and HW), drastically and consistently overforecasted. Essentially, the assumption of these non-damped models that the trend visible in the dataset (and more heavily influenced by more recent observations) was representative of a new constant rate of increase, was the downfall in their forecasting accuracy.

The second explanation for SES turning out to be the most accurate in this instance is that the data’s seasonal component was rather parallel to the trend in its behavior relative to the time period. It was visible in the season-by-season plots that the seasonal differences in average Amazon stock opening during the last years of the time interval were much greater than said differences in the early years of the time interval. All the HW models, both damped and non-damped, take seasonality into calculative consideration. Too much weight was given to the increase in seasonal disparity in the most recent years, leading to consistent overforecasting.

In the future, it would be useful to analyze Amazon’s historical monthly average market opening price with a method less vulnerable to near-term and recent spikes in overall increasing/decreasing trends and/or seasonal oscillations. # References:

Original Dataset Source:

Dataset Download Link via Github:

LS0tCnRpdGxlOiAiVGltZSBTZXJpZXMgQW5hbHlzaXMgb2YgQW1hem9uJ3MgTW9udGgtdG8tTW9udGggU3RvY2sgUHJpY2UiCmF1dGhvcjogIkNocmlzIEJhaG0iCmRhdGU6ICIyMDI1LTExLTI1IgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IHRydWUKICAgICAgc21vb3RoX3Njcm9sbDogdHJ1ZQogICAgdG9jX2RlcHRoOiA0CiAgICBmaWdfd2lkdGg6IDYKICAgIGZpZ19oZWlnaHQ6IDQKICAgIGZpZ19jYXB0aW9uOiB0cnVlCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgdGhlbWU6IGx1bWVuCiAgICBoaWdobGlnaHQ6IHRhbmdvCiAgcGRmX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICB0b2NfZGVwdGg6IDQKICAgIGZpZ19jYXB0aW9uOiB0cnVlCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICB3b3JkX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICB0b2NfZGVwdGg6IDQKLS0tCgpgYGB7Y3NzLCBlY2hvID0gRkFMU0V9CmRpdiNUT0MgbGkgeyAgICAgLyogdGFibGUgb2YgY29udGVudCAgKi8KICAgIGxpc3Qtc3R5bGU6dXBwZXItcm9tYW47CiAgICBiYWNrZ3JvdW5kLWltYWdlOm5vbmU7CiAgICBiYWNrZ3JvdW5kLXJlcGVhdDpub25lOwogICAgYmFja2dyb3VuZC1wb3NpdGlvbjowOwp9CgpoMS50aXRsZSB7ICAgIC8qIGxldmVsIDEgaGVhZGVyIG9mIHRpdGxlICAqLwogIGZvbnQtc2l6ZTogMjRweDsKICBmb250LXdlaWdodDogYm9sZDsKICBjb2xvcjogRGFya1JlZDsKICB0ZXh0LWFsaWduOiBjZW50ZXI7Cn0KCmg0LmF1dGhvciB7IC8qIEhlYWRlciA0IC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovCiAgZm9udC1zaXplOiAxOHB4OwogIGZvbnQtd2VpZ2h0OiBib2xkOwogIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogIGNvbG9yOiBEYXJrUmVkOwogIHRleHQtYWxpZ246IGNlbnRlcjsKfQoKaDQuZGF0ZSB7IC8qIEhlYWRlciA0IC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovCiAgZm9udC1zaXplOiAxOHB4OwogIGZvbnQtd2VpZ2h0OiBib2xkOwogIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogIGNvbG9yOiBEYXJrQmx1ZTsKICB0ZXh0LWFsaWduOiBjZW50ZXI7Cn0KCmgxIHsgLyogSGVhZGVyIDEgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8KICAgIGZvbnQtc2l6ZTogMjBweDsKICAgIGZvbnQtd2VpZ2h0OiBib2xkOwogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgICBjb2xvcjogZGFya3JlZDsKICAgIHRleHQtYWxpZ246IGNlbnRlcjsKfQoKaDIgeyAvKiBIZWFkZXIgMiAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLwogICAgZm9udC1zaXplOiAxOHB4OwogICAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICAgIGNvbG9yOiBuYXZ5OwogICAgdGV4dC1hbGlnbjogbGVmdDsKfQoKaDMgeyAvKiBIZWFkZXIgMyAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLwogICAgZm9udC1zaXplOiAxNnB4OwogICAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICAgIGNvbG9yOiBuYXZ5OwogICAgdGV4dC1hbGlnbjogbGVmdDsKfQoKaDQgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLwogICAgZm9udC1zaXplOiAxNHB4OwogIGZvbnQtd2VpZ2h0OiBib2xkOwogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgICBjb2xvcjogZGFya3JlZDsKICAgIHRleHQtYWxpZ246IGxlZnQ7Cn0KCi8qIEFkZCBkb3RzIGFmdGVyIG51bWJlcmVkIGhlYWRlcnMgKi8KLmhlYWRlci1zZWN0aW9uLW51bWJlcjo6YWZ0ZXIgewogIGNvbnRlbnQ6ICIuIjsKfQpgYGAKCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQojIGNvZGUgY2h1bmsgc3BlY2lmaWVzIHdoZXRoZXIgdGhlIFIgY29kZSwgd2FybmluZ3MsIGFuZCBvdXRwdXQgCiMgd2lsbCBiZSBpbmNsdWRlZCBpbiB0aGUgb3V0cHV0IGZpbGVzLgoKaWYgKCFyZXF1aXJlKCJrbml0ciIpKSB7ICAgICAgICAgICAgICAgICAgICAgICMgdXNlIGNvbmRpdGlvbmFsIHN0YXRlbWVudCB0byBkZXRlY3QKICAgaW5zdGFsbC5wYWNrYWdlcygia25pdHIiKSAgICAgICAgICAgICAgICAgICMgd2hldGhlciBhIHBhY2thZ2Ugd2FzIGluc3RhbGxlZCBpbgogICBsaWJyYXJ5KGtuaXRyKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB5b3VyIG1hY2hpbmUuIElmIG5vdCwgaW5zdGFsbCBpdCBhbmQKfSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgbG9hZCBpdCB0byB0aGUgd29ya2luZyBkaXJlY3RvcnkuCgppZiAoIXJlcXVpcmUodGlkeXZlcnNlKSkge2xpYnJhcnkodGlkeXZzZXJzZSl9IAoKaWYgKCFyZXF1aXJlKEdHYWxseSkpIHtsaWJyYXJ5KEdHYWxseSl9IAoKaWYgKCFyZXF1aXJlKGthYmxlRXh0cmEpKSB7bGlicmFyeShrYWJsZUV4dHJhKX0gCgppZiAoIXJlcXVpcmUoZ2dwbG90MikpIHtsaWJyYXJ5KGdncGxvdDIpfSAKCmlmICghcmVxdWlyZShjYXIpKSB7bGlicmFyeShjYXIpfSAKCmlmICghcmVxdWlyZShkcGx5cikpIHtsaWJyYXJ5KGRwbHlyKX0gCgppZiAoIXJlcXVpcmUocGFuZGVyKSkge2xpYnJhcnkocGFuZGVyKX0gCgppZiAoIXJlcXVpcmUoZm9yZWNhc3QpKSB7bGlicmFyeShmb3JlY2FzdCl9IAoKaWYgKCFyZXF1aXJlKGx1YnJpZGF0ZSkpIHtsaWJyYXJ5KGx1YnJpZGF0ZSl9IAoKaWYgKCFyZXF1aXJlKCJzY2FsZXMiKSkgewppbnN0YWxsLnBhY2thZ2VzKCJzY2FsZXMiKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKbGlicmFyeSgic2NhbGVzIikgCn0KCmtuaXRyOjpvcHRzX2NodW5rJHNldCgKCWVjaG8gPSBUUlVFLAoJbWVzc2FnZSA9IEZBTFNFLAoJd2FybmluZyA9IEZBTFNFLAoJY29tbWVudCA9IE5BLAoJcmVzdWx0cyA9IFRSVUUKKQpgYGAKCiMgSW50cm9kdWN0aW9uIGFuZCBCYWNrZ3JvdW5kIApUaGUgZGF0YXNldCBJIGV4YW1pbmVkIHRvZGF5IHRyYWNrZWQgdGhlIGRheS10by1kYXkgcGVyZm9ybWFuY2Ugb2YgQW1hem9uJ3Mgc3RvY2sgZnJvbSBNYXkgMTUsIDE5OTcgdG8gT2N0b2JlciAyNywgMjAyMS4gVGhlc2UgZGFpbHkgb2JzZXJ2YXRpb25zIHJlY29yZGVkIHRoZSBzdG9jaydzIHByaWNlIGF0IG1hcmtldCBvcGVuaW5nIGFuZCBjbG9zaW5nLCBhcyB3ZWxsIGFzIGl0cyBoaWdoLCBsb3csIGFkanVzdGVkIGNsb3NpbmcgcmF0ZSBhbmQgdHJhZGluZyB2b2x1bWUgZm9yIHRoZSBkYXkuCgpGb3IgdGhlIHB1cnBvc2VzIG9mIG15IGFuYWx5c2lzLCBJIGNob3NlIHRvIHRyYWNrIHRoZSBoaXN0b3J5IG9mIEFtYXpvbidzIG1hcmtldCBwZXJmb3JtYW5jZSBvbiBhIG1vbnRoLWJ5LW1vbnRoIGJhc2lzLiBJIHRvb2sgdGhlIHN0b2NrJ3MgYXZlcmFnZSBvcGVuaW5nIHByaWNlIGZvciBlYWNoIG1vbnRoLCBhbmQgY29uc3RyYWluZWQgdGhlIHRpbWVsaW5lIGZyb20gSmFudWFyeSAyMDA5IHRvIE9jdG9iZXIgb2YgMjAyMSwgYSB0b3RhbCBvZiAxNTQgc2FtcGxlcyBvZiBtb250aGx5IGRhdGEuIEkgdXNlZCB0aGlzIHN1YnNldCBvZiB0aGUgZGF0YSB0byBjcmVhdGUgYSBudW1iZXIgb2YgdGltZSBzZXJpZXMgbW9kZWxzIHdpdGggdGhlIGhvcGVzIG9mIGZvcm11bGF0aW5nIGF0IGxlYXN0IG9uZSB0aGF0IGNhbiBmb3JlY2FzdCBBbWF6b24ncyBhdmVyYWdlIG1hcmtldCBvcGVuaW5nIG9uIGEgbW9udGgtYnktbW9udGggdGltZWxpbmUgd2l0aCByZWxhdGl2ZSBhY2N1cmFjeS4gCgpUaGlzIGlzIG5vdCBhbiBhc3NvY2lhdGl2ZSBhbmFseXNpcyB0aGF0IGF0dGVtcHRzIHRvIGdyZWF0bHkgZXhwbGFpbiAqd2h5KiB0aGUgc3RvY2sncyBvcGVuaW5nIHByaWNlIGhhcyBoaXN0b3JpY2FsbHkgbW92ZWQgdGhlIHdheSBpdCBoYXMsIGJ1dCByYXRoZXIgc2ltcGx5IGEgcHJlZGljdGl2ZSB0b29sLiBUaGUgcHJpbWFyeSBtZXRob2RzIG9mIGZvcmVjYXN0IG1vZGVsaW5nIEkgdXRpbGl6ZWQgaW5jbHVkZSBleHBvbmVudGlhbCBzbW9vdGhpbmcsIEhvbHQgYW5kIEhvbHQtV2ludGVycyBjYWxjdWxhdGlvbnMuCgpgYGB7ciBEYXRhIExvYWRpbmcgYW5kIENsZWFuaW5nfQpEYXRhX1VybD0gImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9DaHJpc0IyMzIzL1NUQTMyMS9yZWZzL2hlYWRzL21haW4vQW1hem9uLmNzdiIKT3JpZ2luYWxfRGF0YSA9IHJlYWRfZGVsaW0oRGF0YV9VcmwsIGRlbGltID0gIiwiLCBzaG93X2NvbF90eXBlcyA9IEZBTFNFKQoKIyhnbGltcHNlKE9yaWdpbmFsX0RhdGEpKQogICMgRXZlcnl0aGluZyBzdG9yZWQgdGhlIHJpZ2h0IHdheSBeXgoKI3N1bShpcy5uYShPcmlnaW5hbF9EYXRhKSkgPSAwCkRhdGEgPSBtdXRhdGUoT3JpZ2luYWxfRGF0YSwKICAgICAgIE1vbnRoID0gbW9udGgoRGF0ZSwgbGFiZWwgPSBUUlVFKSwKICAgICAgIFllYXIgPSB5ZWFyKERhdGUpLAogICkKCkRhdGEgPSBncm91cF9ieShEYXRhLCBNb250aCwgWWVhcikKRGF0YSA9IHN1bW1hcml6ZShEYXRhLCBtZWFuKE9wZW4pKQogICMgXl4gU2luY2UgSSBhbSBsb29raW5nIGF0IG1vbnRoLWJ5LW1vbnRoIG9wZW5zLCBuZWVkIHRvIHN1bW1hcml6ZSBhbmQgZ3JvdXAKRGF0YSA9IHNvcnRfYnkoRGF0YSwgRGF0YSRZZWFyLCBEYXRhJE1vbnRoKQogICMgXl4gUHJpb3JpdGl6ZWQgc29ydGluZywgZmlyc3Qgc29ydCBieSB5ZWFyIChvbGRlc3QgZmlyc3QpLCBhbmQgdGhlbiBieSBtb250aCBvZiB5ZWFyIChKYW51YXJ5IHRvIERlY2VtYmVyKQoKIyBSZXN0cmljdGluZyBteSBhbmFseXNpcyBmcm9tIEphbiAyMDA5IHRvIE9jdCAyMDIxLCByb3VuZGluZyBvcGVuaW5nIHByaWNlIHRvIG5lYXJlc3QgY2VudApEYXRhID0gRGF0YVsxNDE6Mjk0LF0KY29sbmFtZXMoRGF0YSlbM10gPSAiT3BlbiIKRGF0YSRPcGVuID0gcm91bmQoRGF0YSRPcGVuLDIpICAKCkRhdGEkU2Vhc29uW0RhdGEkTW9udGggPT0gIkRlYyIgfCBEYXRhJE1vbnRoID09ICJKYW4iIHwgRGF0YSRNb250aCA9PSAiRmViIl0gPSAiV2ludGVyIgpEYXRhJFNlYXNvbltEYXRhJE1vbnRoID09ICJNYXIiIHwgRGF0YSRNb250aCA9PSAiQXByIiB8IERhdGEkTW9udGggPT0gIk1heSJdID0gIlNwcmluZyIKRGF0YSRTZWFzb25bRGF0YSRNb250aCA9PSAiSnVuIiB8IERhdGEkTW9udGggPT0gIkp1bCIgfCBEYXRhJE1vbnRoID09ICJBdWciXSA9ICJTdW1tZXIiCkRhdGEkU2Vhc29uW0RhdGEkTW9udGggPT0gIlNlcCIgfCBEYXRhJE1vbnRoID09ICJPY3QiIHwgRGF0YSRNb250aCA9PSAiTm92Il0gPSAiRmFsbCIKICAjIEFkZGVkIHZhcmlhYmxlIFNlYXNvbiB0byBiZXR0ZXIgYW5hbHl6ZSBzZWFzb25hbGl0eSBvZiBkYXRhIG92ZXIgdGltZSAobW9yZSB3aXRoIHRoaXMgbGF0ZXIpCgpXaW50ZXJfTW9udGhzID0gZmlsdGVyKERhdGEsIFNlYXNvbiA9PSAiV2ludGVyIikKU3ByaW5nX01vbnRocyA9IGZpbHRlcihEYXRhLCBTZWFzb24gPT0gIlNwcmluZyIpClN1bW1lcl9Nb250aHMgPSBmaWx0ZXIoRGF0YSwgU2Vhc29uID09ICJTdW1tZXIiKQpGYWxsX01vbnRocyA9IGZpbHRlcihEYXRhLCBTZWFzb24gPT0gIkZhbGwiKQpgYGAKCiMgRGF0YSBWaXN1YWxpemF0aW9uCkJlZm9yZSBiZWdpbm5pbmcgbW9kZWwgY3JlYXRpb24sIEkgd2FudGVkIHRvIHZpc3VhbGl6ZSB0d28gZXNzZW50aWFsIHBhcnRzIG9mIHRoZSBkYXRhIGF0IGhhbmQsIGl0cyB0cmVuZCBhbmQgc2Vhc29uYWwgY29tcG9uZW50cy4gVGhlc2UgZWxlbWVudHMgcGxheSBhbiBpbXBvcnRhbnQgcm9sZSBpbiB1bmRlcnN0YW5kaW5nIHRoZSBtb2RlbC10by1tb2RlbCBhY2N1cmFjeSBjb21wYXJpc29ucyB0aGF0IHdpbGwgYmUgZXhhbWluZWQgbGF0ZXIuCgojIyBUcmVuZApCZWxvdyBJIHBsb3R0ZWQgdGhlIGNob3NlbiBhbmFseXNpcyBpbnRlcnZhbCAoSmFudWFyeSAyMDA5IHRvIE9jdG9iZXIgMjAyMSkuIFdoYXQgd2Ugc2VlIGlzIGEgdGFsZSBvZiB0d28gdmVyeSBkaWZmZXJlbnQgaGFsZi1kZWNhZGVzOyB3aXRoIGEgcmF0aGVyIG1pbGRseSBpbmNyZWFzaW5nIHRyZW5kIGZyb20gMjAwOSB0byBhYm91dCAyMDE2LCBhbmQgdGhlbiBhIGxhcmdlIGFuZCBleHBvbmVudGlhbCBpbmNyZWFzZSBpbiBtYXJrZXQgdmFsdWUgZnJvbSAyMDE2IG9ud2FyZC4KYGBge3IsIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLmhlaWdodCA9IDV9ClRpbWVfU2VyaWVzID0gdHMoRGF0YSRPcGVuLCBmcmVxdWVuY3kgPSAxMiwgc3RhcnQgPSBjKDIwMDksMSkpCgpwbG90KFRpbWVfU2VyaWVzLAogICAgIG1haW4gPSAiQW1hem9uIFN0b2NrIE9wZW5pbmcgUHJpY2UgKDIwMDkgLSAyMDIxKSIsCiAgICAgeGxhYiA9ICJZZWFyIiwKICAgICB5bGFiID0gIlByaWNlICgkVVNEKSIsCiAgICAgbHdkID0gMykKYGBgCgojIyBTZWFzb25hbGl0eQpXaGlsZSB0aGUgdHJlbmQgY29tcG9uZW50IG9mIEFtYXpvbidzIHN0b2NrIG9wZW5pbmcgaXMgcmF0aGVyIHN0cmFpZ2h0Zm9yd2FyZCwgaXQgaXMgYWxzbyB2YWx1YWJsZSB0byBicmVha2Rvd24gdGhlIHNlYXNvbmFsIGFzcGVjdCBvZiBpdHMgaGlzdG9yaWNhbCBwZXJmb3JtYW5jZS4gQmVsb3cgaXMgYSB0YWJsZSBhdmVyYWdpbmcgaXRzIG9wZW5pbmcgcHJpY2UgcGVyIHNlYXNvbiBmb3IgZWFjaCByZXNwZWN0aXZlIHllYXIsIHdpdGggdGhlIHRvdGFsIGFjcm9zcyBhbGwgdGhlIGNpdGVkIHllYXJzIGF0IHRoZSBib3R0b20uIAoKYGBge3IgRGF0YSBWaXN1YWxpemF0aW9uLCBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy5oZWlnaHQgPSA1fQojIE1ha2luZyBhIHNlYXNvbi1ieS1zZWFzb24gYnJlYWtkb3duIHRocm91Z2hvdXQgdGhlIGRlc2lnbmF0ZWQgZGF0YSByYW5nZQpTZWFzb25fQnlfU2Vhc29uID0gZ3JvdXBfYnkoRGF0YSwgU2Vhc29uLCBZZWFyKQpTZWFzb25fQnlfU2Vhc29uID0gc3VtbWFyaXplKFNlYXNvbl9CeV9TZWFzb24sIG1lYW4oT3BlbikpCmNvbG5hbWVzKFNlYXNvbl9CeV9TZWFzb24pWzNdID0gIk9wZW4iClNlYXNvbl9CeV9TZWFzb24gPSBzb3J0X2J5KFNlYXNvbl9CeV9TZWFzb24sIFNlYXNvbl9CeV9TZWFzb24kWWVhciwgU2Vhc29uX0J5X1NlYXNvbiRTZWFzb24pClNlYXNvbl9CeV9TZWFzb24kT3BlbiA9IHJvdW5kKFNlYXNvbl9CeV9TZWFzb24kT3BlbiwyKQoKWWVhcnMgPSBkYXRhLmZyYW1lKGMoIjIwMDkiLCAiMjAxMCIsICIyMDExIiwgIjIwMTIiLCAiMjAxMyIsIjIwMTQiLCAiMjAxNSIsICIyMDE2IiwgIjIwMTciLCAiMjAxOCIsICIyMDE5IiwgIjIwMjAiLCAiMjAyMSIpKQpjb2xuYW1lcyhZZWFycykgPSAiWWVhciIKCldpbnRlcl9TZWFzb25zID0gU2Vhc29uX0J5X1NlYXNvbltTZWFzb25fQnlfU2Vhc29uJFNlYXNvbiA9PSAiV2ludGVyIiwgXQpTcHJpbmdfU2Vhc29ucyA9IFNlYXNvbl9CeV9TZWFzb25bU2Vhc29uX0J5X1NlYXNvbiRTZWFzb24gPT0gIlNwcmluZyIsIF0KU3VtbWVyX1NlYXNvbnMgPSBTZWFzb25fQnlfU2Vhc29uW1NlYXNvbl9CeV9TZWFzb24kU2Vhc29uID09ICJTdW1tZXIiLCBdCkZhbGxfU2Vhc29ucyA9IFNlYXNvbl9CeV9TZWFzb25bU2Vhc29uX0J5X1NlYXNvbiRTZWFzb24gPT0gIkZhbGwiLCBdCgojIFN1YnNldHRpbmcgdGhhdCBzZWFzb24tYnktc2Vhc29uIGJyZWFrZG93biB0byBsb29rIGF0IGVhY2ggc2Vhc29uIHRocm91Z2hvdXQgdGhlIHllYXJzCgpBbGxfU2Vhc29ucyA9IGNiaW5kKFllYXJzLCBXaW50ZXJfU2Vhc29ucyRPcGVuLCBTcHJpbmdfU2Vhc29ucyRPcGVuLCBTdW1tZXJfU2Vhc29ucyRPcGVuLCBGYWxsX1NlYXNvbnMkT3BlbikKICBjb2xuYW1lcyhBbGxfU2Vhc29ucykgPSBjKCJZZWFyIiwgIldpbnRlciIsICJTcHJpbmciLCAiU3VtbWVyIiwgIkZhbGwiKQoKIyBUbyBoYXZlIGFuIGF2ZXJhZ2VzIGZvciB0aGUgc2Vhc29ucyBhY3Jvc3MgdGhlIHllYXJzClNlYXNvbl9Ub3RhbHMgPSBkYXRhLmZyYW1lKCJBbGwgWWVhcnMiLAogICAgICByb3VuZChtZWFuKFdpbnRlcl9Nb250aHMkT3BlbiksMiksCiAgICAgIHJvdW5kKG1lYW4oU3ByaW5nX01vbnRocyRPcGVuKSwyKSwKICAgICAgcm91bmQobWVhbihTdW1tZXJfTW9udGhzJE9wZW4pLDIpLAogICAgICByb3VuZChtZWFuKEZhbGxfTW9udGhzJE9wZW4pLDIpKQogIGNvbG5hbWVzKFNlYXNvbl9Ub3RhbHMpID0gYygiWWVhciIsICJXaW50ZXIiLCAiU3ByaW5nIiwgIlN1bW1lciIsICJGYWxsIikKICBpbnZpc2libGUoYXMubnVtZXJpYyhTZWFzb25fVG90YWxzWywoMjo1KV0pKQogIApBbGxfU2Vhc29ucyA9IHJiaW5kKEFsbF9TZWFzb25zLCBTZWFzb25fVG90YWxzKQprYWJsZShBbGxfU2Vhc29ucywgY2FwdGlvbiA9ICJBbWF6b24gU3RvY2sgT3BlbmluZyBTZWFzb24tQnktU2Vhc29uIiwgYWxpZ24gPSAiYyIpCmBgYAoKQXMgd2UgY2FuIHNlZSwgdGhlIHN1bW1lciBoYXMgaGlzdG9yaWNhbGx5IGJlZW4gQW1hem9uJ3MgYmVzdCBzZWFzb24gYWNjb3JkaW5nIHRvIHRoZSBtYXJrZXQsIGF2ZXJhZ2luZyBhIG1hcmtldCBvcGVuIG9mICQxMDQwLjI2LiBGYWxsJ3MgeWVhcmx5IGF2ZXJhZ2UgdHJhaWxzIHNsaWdodGx5IGJlaGluZCBhdCAkMTAxMC43Mywgd2l0aCBzcHJpbmcgYW5kIHdpbnRlcidzIGF2ZXJhZ2VzIGJlaW5nIG5vdGljZWFibHkgbG93ZXIuIEJleW9uZCB0aGF0LCBpdCBpcyBhbHNvIHZpc2libGUgdGhhdCB0aGUgZGlmZmVyZW5jZSBpbiB0aGUgc3RvY2sncyBsb3dlc3QgYW5kIGhpZ2hlc3Qgc2Vhc29uYWwgYXZlcmFnZSB0ZW5kcyB0byBpbmNyZWFzZSBpbiBtYWduaXR1ZGUgYXMgdGhlIHllYXJzIHdlbnQgb24uIEluIDIwMDksIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gQW1hem9uJ3MgYmVzdCBhbmQgd29yc3Qgc2Vhc29uYWwgYXZlcmFnZSB3YXMgJDMwLjE3LiBJbiAyMDIxLCB0aGF0IHNhbWUgbWV0cmljIHdhcyAkMTk5Ljk2LiBUaGlzIGluY3JlYXNpbmcgbWFnbml0dWRlIG9mIGluLXllYXIgc2Vhc29uYWwgZGlmZmVyZW5jZSBjYW4gYmUgc2VlbiBhdCBncmVhdGVyIGVhc2Ugd2l0aCB0aGUgcGxvdHMgYmVsb3cuCgpgYGB7ciwgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcuaGVpZ2h0ID0gNX0KIyMjIyMjIE1ha2UgYSBwbG90IG9mIGFsbCB0aGUgZGF0YQpwbG90KHggPSBXaW50ZXJfU2Vhc29ucyRZZWFyLCB5ID0gV2ludGVyX1NlYXNvbnMkT3BlbiwKICAgICBtYWluID0gIkFtYXpvbiBTdG9jayBPcGVuaW5nIFNlYXNvbi1CeS1TZWFzb24iLAogICAgIHhsYWIgPSAiWWVhciIsCiAgICAgeWxhYiA9ICJWYWx1ZSgkVVNEKSIpCiAgbGluZXMoeCA9IFdpbnRlcl9TZWFzb25zJFllYXIsIHkgPSBXaW50ZXJfU2Vhc29ucyRPcGVuLCBjb2wgPSAicmVkIiwgbHdkID0gMS41KQogICAgcG9pbnRzKHggPSBXaW50ZXJfU2Vhc29ucyRZZWFyLCB5ID0gV2ludGVyX1NlYXNvbnMkT3BlbiwgY29sID0gInJlZCIsIHBjaCA9IDIxLCBiZyA9ICJyZWQiKQogICAgCiAgbGluZXMoeCA9IFNwcmluZ19TZWFzb25zJFllYXIsIHkgPSBTcHJpbmdfU2Vhc29ucyRPcGVuLCBjb2wgPSAiYmxhY2siLCBsd2QgPSAxLjUpCiAgICBwb2ludHMoeCA9IFNwcmluZ19TZWFzb25zJFllYXIsIHkgPSBTcHJpbmdfU2Vhc29ucyRPcGVuLCBjb2wgPSAiYmxhY2siLCBwY2ggPSAyMSwgYmcgPSAiYmxhY2siKQogICAgCiAgbGluZXMoeCA9IFN1bW1lcl9TZWFzb25zJFllYXIsIHkgPSBTdW1tZXJfU2Vhc29ucyRPcGVuLCBjb2wgPSAiZ3JlZW4iLCBsd2QgPSAxLjUpCiAgICBwb2ludHMoeCA9IFN1bW1lcl9TZWFzb25zJFllYXIsIHkgPSBTdW1tZXJfU2Vhc29ucyRPcGVuLCBjb2wgPSAiZ3JlZW4iLCBwY2ggPSAyMSwgYmcgPSAiZ3JlZW4iKQogICAgCiAgbGluZXMoeCA9IEZhbGxfU2Vhc29ucyRZZWFyLCB5ID0gRmFsbF9TZWFzb25zJE9wZW4sIGNvbCA9ICJwdXJwbGUiLCBsd2QgPSAxLjUpCiAgICBwb2ludHMoeCA9IEZhbGxfU2Vhc29ucyRZZWFyLCB5ID0gRmFsbF9TZWFzb25zJE9wZW4sIGNvbCA9ICJwdXJwbGUiLCBwY2ggPSAyMSwgYmcgPSAicHVycGxlIikKICAgIAogICAgbGVnZW5kKCJ0b3BsZWZ0IiwKICAgICAgIGxlZ2VuZCA9IGMoIldpbnRlciIsICJTcHJpbmciLCAiU3VtbWVyIiwgIkZhbGwiKSwKICAgICAgIGNvbCA9IGMoInJlZCIsICJibGFjayIsICJncmVlbiIsICJwdXJwbGUiKSwKICAgICAgIGx0eSA9IDEsIHBjaCA9IDE2LCBsd2QgPSAyKQogICAgCiMjIyMjIyBNYWtlIGEgcmVkdWNlZCBwbG90LCAyMDE1IHRvIDIwMjEKUmVkdWNlZF9XaW50ZXJfU2Vhc29ucyA9IFdpbnRlcl9TZWFzb25zWzc6MTMsXQpSZWR1Y2VkX1NwcmluZ19TZWFzb25zID0gU3ByaW5nX1NlYXNvbnNbNzoxMyxdClJlZHVjZWRfU3VtbWVyX1NlYXNvbnMgPSBTdW1tZXJfU2Vhc29uc1s3OjEzLF0KUmVkdWNlZF9GYWxsX1NlYXNvbnMgPSBGYWxsX1NlYXNvbnNbNzoxMyxdCgpwbG90KHggPSBSZWR1Y2VkX1dpbnRlcl9TZWFzb25zJFllYXIsIHkgPSBSZWR1Y2VkX1dpbnRlcl9TZWFzb25zJE9wZW4sCiAgICAgbWFpbiA9ICJBbWF6b24gU3RvY2sgT3BlbmluZyBTZWFzb24tQnktU2Vhc29uIFxuICgyMDE1IC0gMjAyMSkiLAogICAgIHhsYWIgPSAiWWVhciIsCiAgICAgeWxhYiA9ICJWYWx1ZSgkVVNEKSIpCiAgbGluZXMoeCA9IFJlZHVjZWRfV2ludGVyX1NlYXNvbnMkWWVhciwgeSA9IFJlZHVjZWRfV2ludGVyX1NlYXNvbnMkT3BlbiwgY29sID0gInJlZCIsIGx3ZCA9IDIpCiAgICBwb2ludHMoeCA9IFJlZHVjZWRfV2ludGVyX1NlYXNvbnMkWWVhciwgeSA9IFJlZHVjZWRfV2ludGVyX1NlYXNvbnMkT3BlbiwgY29sID0gInJlZCIsIHBjaCA9IDIxLCBiZyA9ICJyZWQiKQogICAgCiAgbGluZXMoeCA9IFJlZHVjZWRfU3ByaW5nX1NlYXNvbnMkWWVhciwgeSA9IFJlZHVjZWRfU3ByaW5nX1NlYXNvbnMkT3BlbiwgY29sID0gImJsYWNrIiwgbHdkID0gMikKICAgIHBvaW50cyh4ID0gUmVkdWNlZF9TcHJpbmdfU2Vhc29ucyRZZWFyLCB5ID0gUmVkdWNlZF9TcHJpbmdfU2Vhc29ucyRPcGVuLCBjb2wgPSAiYmxhY2siLCBwY2ggPSAyMSwgYmcgPSAiYmxhY2siKQogICAgCiAgbGluZXMoeCA9IFJlZHVjZWRfU3VtbWVyX1NlYXNvbnMkWWVhciwgeSA9IFJlZHVjZWRfU3VtbWVyX1NlYXNvbnMkT3BlbiwgY29sID0gImdyZWVuIiwgbHdkID0gMikKICAgIHBvaW50cyh4ID0gUmVkdWNlZF9TdW1tZXJfU2Vhc29ucyRZZWFyLCB5ID0gUmVkdWNlZF9TdW1tZXJfU2Vhc29ucyRPcGVuLCBjb2wgPSAiZ3JlZW4iLCBwY2ggPSAyMSwgYmcgPSAiZ3JlZW4iKQogICAgCiAgbGluZXMoeCA9IFJlZHVjZWRfRmFsbF9TZWFzb25zJFllYXIsIHkgPSBSZWR1Y2VkX0ZhbGxfU2Vhc29ucyRPcGVuLCBjb2wgPSAicHVycGxlIiwgbHdkID0gMikKICAgIHBvaW50cyh4ID0gUmVkdWNlZF9GYWxsX1NlYXNvbnMkWWVhciwgeSA9IFJlZHVjZWRfRmFsbF9TZWFzb25zJE9wZW4sIGNvbCA9ICJwdXJwbGUiLCBwY2ggPSAyMSwgYmcgPSAicHVycGxlIikKICAgIAogICBsZWdlbmQoInRvcGxlZnQiLAogICAgIGxlZ2VuZCA9IGMoIldpbnRlciIsICJTcHJpbmciLCAiU3VtbWVyIiwgIkZhbGwiKSwKICAgICBjb2wgPSBjKCJyZWQiLCAiYmxhY2siLCAiZ3JlZW4iLCAicHVycGxlIiksCiAgICAgbHR5ID0gMSwgcGNoID0gMTYsIGx3ZCA9IDIpICAKYGBgCgpUaGVzZSBwbG90cyBvZmZlciBhIHZpc3VhbCBjb25maXJtYXRpb24gZm9yIHRoZSBudW1lcmljYWwgcGF0dGVybnMgcHJlc2VudCBpbiB0aGUgdGFibGUgYWJvdmUuIEdyYXBoaWNhbGx5IHNwZWFraW5nLCBzZWFzb25hbCBkaWZmZXJlbmNlcyBpbiBhdmVyYWdlIG9wZW5pbmcgcHJpY2UgYXJlIHJhdGhlciB1bm5vdGljZWFibGUgZnJvbSAyMDA5IHRvIGFib3V0IDIwMTYgb3IgMjAxNy4gQnV0IGFzIHRpbWUgY29udGludWVzIGJleW9uZCB0aGF0IHBvaW50LCB0aGUgc2Vhc29uYWwgb3NjaWxsYXRpb24gaW5jcmVhc2VzLiBUaGlzIGlzIGEgc2ltaWxhciBwaGVub21lbm9uIHRvIHRoZSB0cmVuZCBjb21wb25lbnQgb2YgdGhlIGdyYXBoIHNlZW4gZWFybGllciwgbWVhbmluZyB0aGF0IEFtYXpvbidzIHN0b2NrIG9wZW5pbmcgcHJpY2Ugc2Vhc29uLWJ5LXNlYXNvbiBpcyBpbmNvbnNpc3RlbnQsIGFuZCB0aGF0IGluY29uc2lzdGVuY3kgZXhwYW5kcyB3aXRoIHRoZSB1cHdhcmQgdHJlbmQgb2YgdGhlIG92ZXJhbGwgb3BlbmluZyBkYXRhLgoKIyBGb3JlY2FzdCBNb2RlbGluZwpOb3cgd2l0aCBhIHNvbGlkIGdyYXNwIG9mIHRoZSBkYXRhJ3MgdHJlbmQgYW5kIHNlYXNvbmFsaXR5LCBJIG1vdmVkIGZvcndhcmQgYW5kIGJlZ2FuIHRoZSBmb3JlY2FzdCBtb2RlbGluZyBwcm9jZXNzLiBJbiB0b3RhbCwgSSBjcmVhdGVkIGVpZ2h0IG1vZGVscyAtIG9uZSBzaW1wbGUgZXhwb25lbnRpYWwgc21vb3RoaW5nLCB0aHJlZSBIb2x0IGFuZCBmb3VyIEhvbHQtV2ludGVycy4KCiMjIFRyYWluaW5nIGFuZCBUZXN0aW5nIFNldHMKU2luY2UgaXQgaXMgcG9vciBzdGF0aXN0aWNhbCBwcmFjdGljZSB0byB0ZXN0IGEgbW9kZWwgb24gdGhlIHNhbWUgZGF0YSB3aGljaCBpdCBpcyB0cmFpbmVkL2J1aWx0IG9uLCBJIHNlcGFyYXRlZCBteSBkYXRhIGludG8gdHdvIGRpc3RpbmN0IHN1YnNldHMuIFRoZSB0cmFpbmluZyBkYXRhc2V0IGNvbnNpc3RlZCBvZiBtb250aGx5IG9ic2VydmF0aW9ucyBmcm9tIHRoZSBuZWFybHkgMTIgeWVhciBzcGFuIG9mIEphbnVhcnkgMjAwOSB0byBPY3RvYmVyIDIwMjAuIE1lYW53aGlsZSwgdGhlIHRlc3RpbmcgZGF0YXNldCAodGhlIG9ic2VydmF0aW9ucyB3aGljaCBteSB0aW1lIHNlcmllcyBtb2RlbHMgd2lsbCBhdHRlbXB0IHRvIGNvbXB1dGF0aW9uYWxseSBwcmVkaWN0IG9yIGZvcmVjYXN0KSwgY29uc2lzdHMgb2YgbW9udGhseSBhdmVyYWdlcyBmcm9tIE5vdmVtYmVyIDIwMjAgdG8gT2N0b2JlciAyMDIxLgpgYGB7cn0KVHJhaW5pbmdfRGF0YSA9IERhdGFbMToxNDIsXQpUZXN0aW5nX0RhdGEgPSBEYXRhWzE0MzoxNTQsXQoKVGltZV9TZXJpZXNfVHJhaW5pbmcgPSB0cyhUcmFpbmluZ19EYXRhJE9wZW4sIGZyZXF1ZW5jeSA9IDEyLCBzdGFydCA9IGMoMjAwOSwxKSkKVGltZV9TZXJpZXNfVGVzdGluZyA9IHRzKFRlc3RpbmdfRGF0YSRPcGVuLCBmcmVxdWVuY3kgPSAxMiwgc3RhcnQgPSBjKDIwMjAsMTEpKQpgYGAKCiMjIE1vZGVsIENyZWF0aW9uClNldHRpbmcgZWFjaCBtb2RlbCdzIGZvcmVjYXN0IGludGVydmFsIGVxdWFsIHRvIDEyLCBJIGNvbnN0cnVjdGVkIDggdGltZSBzZXJpZXMgbW9kZWxzLiBBIGJyZWFrZG93biBvZiBlYWNoIG1vZGVsIHR5cGUgd2l0aCBhIGNvcnJlc3BvbmRpbmcgYnJpZWYgZXhwbGFuYXRpb24gaXMgYmVsb3cuCgotIFNpbXBsZSBFeHBvbmVudGlhbCBTbW9vdGhpbmcgKFNFUyk6IE9sZGVyIG9ic2VydmF0aW9ucyBhcmUgZ2l2ZW4gYW4gZXhwb25lbnRpYWxseSBkZWNyZWFzaW5nIGRlZ3JlZSBvZiB3ZWlnaHQgaW4gdGhlIGNhbGN1bGF0aW9uIG9mIGZvcmVjYXN0ZWQgdmFsdWVzLiBUaGlzIGlzIGRvbmUgd2l0aCB0aGUgdXNlIG9mIHdoYXQgaXMgY2FsbGVkIHNtb290aGluZyBjb25zdGFudHMuIEZvcmVjYXN0cyBmcm9tIGFuIFNFUyBtb2RlbCBhcmUgYWxsIGVxdWFsIHRvIHRoZSBzYW1lIHZhbHVlLCBhcyBTRVMgZG9lcyBub3QgY29uc2lkZXIgYSBkYXRhc2V0J3MgdHJlbmQgb3Igc2Vhc29uYWxpdHksIGJ1dCByYXRoZXIgc2ltcGx5IGNhbGN1bGF0ZXMgYSB3ZWlnaHRlZCBtb3ZpbmcgYXZlcmFnZS4KCi0gPHNwYW4gc3R5bGU9ImNvbG9yOnJlZDsiPkhvbHQgQWRkaXRpdmU8L3NwYW4+OiBBIGdlbmVyYWxpemF0aW9uIG9mIHRoZSBTRVMgYXBwcm9hY2guIEZvcmVjYXN0IGNhbGN1bGF0aW9ucyBpbmNsdWRlIHRoZSAqKmFkZGl0aW9uKiogb2YgdGhlIGRhdGEncyB0cmVuZCBwYXJhbWV0ZXIuIAoKLSA8c3BhbiBzdHlsZT0iY29sb3I6cmVkOyI+SG9sdCBBZGRpdGl2ZSBXLyBEYW1wPC9zcGFuPjogQSBtb2RpZmljYXRpb24gb2YgdGhlIGFkZGl0aXZlIEhvbHQgYXBwcm9hY2gsIGFzIGl0IGluY2x1ZGVzIGEgZGFtcGluZyBwYXJhbWV0ZXIgdGhhdCByZWR1Y2VzIHRoZSBhYnNvbHV0ZSB2YWx1ZSBvZiBhIHRyZW5kJ3MgaW5jcmVhc2luZyBvciBkZWNyZWFzaW5nIGVmZmVjdCBvbiBmb3JlY2FzdHMgb3ZlciB0aW1lLiBUaGlzIGlzIGEgcG9wdWxhciBjaG9pY2Ugd2hlbiBpdCBpcyBiZWxpZXZlZCB0aGF0IGEgdHJlbmQgd2lsbCAiZmxhdHRlbiBvdXQiIGluIHRoZSBzb21ld2hhdCBuZWFyIGZ1dHVyZS4KCi0gPHNwYW4gc3R5bGU9ImNvbG9yOnJlZDsiPkhvbHQgTXVsdGlwbGljYXRpdmUgVy8gRGFtcDwvc3Bhbj46IENhcnJpZXMgdGhlIGlkZWEgb2YgaXRzIGFkZGl0aXZlIHZlcnNpb24sIGJ1dCB0aGUgZGFtcGluZyBwYXJhbWV0ZXIgaXMgKiptdWx0aXBsaWVkKiogYW5kIHRha2VzIHRoZSByb2xlIG9mIGEgcHJvcG9ydGlvbmFsIHdlaWdodCwgcmF0aGVyIHRoYW4gYWRkZWQgYXMgYW4gYWJzb2x1dGUgdmFsdWUuICAqSG9sdCBtb2RlbHMgZG8gbm90IGV4cGxpY2l0bHkgaW5jbHVkZSBhIGRhdGFzZXQncyBzZWFzb25hbCBjb21wb25lbnQgaW4gaXRzIGNhbGN1bGF0aW9ucywgaG93ZXZlciB0aGUgbXVsdGlwbGljYXRpdmUgZGFtcCBtb2RlbCBpcyBzdGlsbCBzZWVuIGFzIHByZWZlcmFibGUgdG8gdGhlIGFkZGl0aXZlIHdoZW4gc2Vhc29uYWwgb3NjaWxsYXRpb25zIGFyZSBpbmNvbnNpc3RlbnQgdGhyb3VnaG91dCB0aGUgdGltZSBsZW5ndGggb2YgdGhlIGRhdGEuCgotIDxzcGFuIHN0eWxlPSJjb2xvcjojMDAwMEZGOyI+SG9sdC1XaW50ZXJzIChIVykgQWRkaXRpdmU8L3NwYW4+OiBQYXJhbGxlbCB0byB0aGUgSG9sdCBhZGRpdGl2ZSBtb2RlbCwgYnV0IGFsc28gdGFrZXMgaW50byBhY2NvdW50IHRoZSBkYXRhJ3Mgc2Vhc29uYWwgb3NjaWxsYXRpb25zLiAKCi0gPHNwYW4gc3R5bGU9ImNvbG9yOiMwMDAwRkY7Ij5IVyBBZGRpdGl2ZSBXLyBEYW1wPC9zcGFuPjogQWRkcyBwYXJhbWV0ZXJzIHJlcHJlc2VudGF0aXZlIG9mIGJvdGggdGhlIHRyZW5kICoqYW5kKiogc2Vhc29uYWxpdHkgcmVzcGVjdGl2ZWx5IHRvIHRoZSBmb3JlY2FzdCBjYWxjdWxhdGlvbnMuIFVzZWQgd2hlbiB0aGVyZSBpcyBhbiBhc3N1bXB0aW9uIG9mIGEgImZsYXR0ZW5pbmcgY3VydmUiIHBoZW5vbWVub24gcmVnYXJkaW5nIHRoZSBkYXRhc2V0J3MgdHJlbmQuCgotIDxzcGFuIHN0eWxlPSJjb2xvcjojMDAwMEZGOyI+SFcgTXVsdGlwbGljYXRpdmU6PC9zcGFuPjogQnVpbGRzIG9uIHRoZSBIb2x0IG11bHRpcGxpY2F0aXZlIG1vZGVsIGJ5IG11bHRpcGx5aW5nIHRoYXQgY2FsY3VsYXRpb24gYnkgYSBzZWFzb25hbCBmYWN0b3IuCgotIDxzcGFuIHN0eWxlPSJjb2xvcjojMDAwMEZGOyI+SFcgTXVsdGlwbGljYXRpdmUgVy8gRGFtcDo8L3NwYW4+OiBVc2VkIHdoZW4gd2UgYXNzdW1lIGEgZGVjcmVhc2UgaW4gdGhlIHNldmVyaXR5IG9mIGRhdGEncyB1cHdhcmQgb3IgZG93bndhcmQgdHJlbmQuIEZhY3RvcnMgaW4sIHZpYSBtdWx0aXBsaWNhdGlvbiwgYm90aCB0aGUgcmVzcG9uc2UncyB0cmVuZCBhbmQgc2Vhc29uYWwgb3NjaWxsYXRpb24uIApgYGB7ciwgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9NX0gCiMgVXNlIGggPSAxMiBmb3IgYWxsIHRoZXNlIGZvcmVjYXN0cwoKIyMjIyMgU2ltcGxlIEV4cG9uZW50aWFsIFNtb290aGluZwpTaW1wbGVfTW9kZWwgPSBzZXMoVGltZV9TZXJpZXNfVHJhaW5pbmcsIGggPSAxMikgI01vZGVsIDEKICAgIFNpbXBsZV9QcmVkaWN0aW9ucyA9IGRhdGEuZnJhbWUocm91bmQoU2ltcGxlX01vZGVsJG1lYW4sMikpICMgdGhlIG5leHQgMTAgZm9yZWNhc3RzCgojIyMjIyBIb2x0CiAgIyAiZGFtcGVkIiBpcyB0aGUgYXNzdW1wdGlvbiB0aGF0IHRoZSBtYWduaXR1ZGUgb2YgdGltZSBzZXJpZXMnIHRyZW5kIG9yIHNlYXNvbmFsIGNvbXBvbmVudHMgd2lsbCBERUNSRUFTRSBvdmVyIHRpbWUKSG9sdF9Nb2RlbF9BZGQgPSBob2x0KFRpbWVfU2VyaWVzX1RyYWluaW5nLCBoID0gMTIsIGRhbXBlZCA9IEZBTFNFKSAjTW9kZWwgMgogICAgSG9sdF9BZGRfUHJlZGljdGlvbnMgPSBkYXRhLmZyYW1lKHJvdW5kKEhvbHRfTW9kZWxfQWRkJG1lYW4sMikpCiAgICAKSG9sdF9Nb2RlbF9BZGRfRGFtcCA9IGhvbHQoVGltZV9TZXJpZXNfVHJhaW5pbmcsIGggPSAxMiwgZGFtcGVkID0gVFJVRSkgI01vZGVsIDMKICAgIEhvbHRfQWRkX0RhbXBfUHJlZGljdGlvbnMgPSBkYXRhLmZyYW1lKHJvdW5kKEhvbHRfTW9kZWxfQWRkX0RhbXAkbWVhbiwyKSkKICAgIApIb2x0X01vZGVsX011bHRfRGFtcCA9IGhvbHQoVGltZV9TZXJpZXNfVHJhaW5pbmcsIGggPSAxMiwgZXhwb25lbnRpYWwgPSBUUlVFLCBkYW1wZWQgPSBUUlVFKSAjTW9kZWwgNAogICAgSG9sdF9NdWx0X0RhbXBfUHJlZGljdGlvbnMgPSBkYXRhLmZyYW1lKHJvdW5kKEhvbHRfTW9kZWxfTXVsdF9EYW1wJG1lYW4sMikpCgojIyMjIyBIb2x0LVdpbnRlcnMgKEhXKQpIV19Nb2RlbF9BZGQgPSBodyhUaW1lX1Nlcmllc19UcmFpbmluZywgaCA9IDEyLCBkYW1wZWQgPSBGQUxTRSwgc2Vhc29uYWwgPSAiYWRkaXRpdmUiKSAjTW9kZWwgNQogICAgSFdfQWRkX1ByZWRpY3Rpb25zID0gZGF0YS5mcmFtZShyb3VuZChIV19Nb2RlbF9BZGQkbWVhbiwyKSkKICAKSFdfTW9kZWxfTXVsdCA9IGh3KFRpbWVfU2VyaWVzX1RyYWluaW5nLCBoID0gMTIsIGRhbXBlZCA9IEZBTFNFLCBzZWFzb25hbCA9ICJtdWx0aXBsaWNhdGl2ZSIpICNNb2RlbCA2CiAgICBIV19NdWx0X1ByZWRpY3Rpb25zID0gZGF0YS5mcmFtZShyb3VuZChIV19Nb2RlbF9NdWx0JG1lYW4sMikpCiAgCkhXX01vZGVsX0FkZF9EYW1wID0gaHcoVGltZV9TZXJpZXNfVHJhaW5pbmcsIGggPSAxMiwgZGFtcGVkID0gVFJVRSwgc2Vhc29uYWwgPSAiYWRkaXRpdmUiKSAjTW9kZWwgNwogICAgSFdfQWRkX0RhbXBfUHJlZGljdGlvbnMgPSBkYXRhLmZyYW1lKHJvdW5kKEhXX01vZGVsX0FkZF9EYW1wJG1lYW4sMikpCiAgICAKSFdfTW9kZWxfTXVsdF9EYW1wID0gaHcoVGltZV9TZXJpZXNfVHJhaW5pbmcsIGggPSAxMiwgZGFtcGVkID0gVFJVRSwgc2Vhc29uYWwgPSAibXVsdGlwbGljYXRpdmUiKSAjTW9kZWwgOAogICAgSFdfTXVsdF9EYW1wX1ByZWRpY3Rpb25zID0gZGF0YS5mcmFtZShyb3VuZChIV19Nb2RlbF9NdWx0X0RhbXAkbWVhbiwyKSkgICAgCmBgYAoKQmVsb3cgd2UgY2FuIHNlZSBhIGJyZWFrZG93biBvZiBlYWNoIG1vZGVsJ3MgZm9yZWNhc3RlZCBzdG9jayBvcGVuaW5nIHZhbHVlcyBmb3IgdGhlIDEyIHBlcmlvZHMgZm9sbG93aW5nIHRoZSB0cmFpbmluZyBzZXQncyBsYXN0IG9ic2VydmF0aW9uIChOb3YgMjAyMCAtIE9jdCAyMDIxKS4gQSBzdW1tYXJ5IG9mIHNvbWUgaW50ZXJlc3RpbmcgdGFrZWF3YXlzIGFyZSBhbHNvIGF2YWlsYWJsZS4KCmBgYHtyfQojIyMjIyBQdXR0aW5nIHRoZW0gYWxsIHRvZ2V0aGVyICAKUHJlZGljdGlvbnMgPSBjYmluZChTaW1wbGVfUHJlZGljdGlvbnMsICMxCiAgICAgICAgICAgICAgICAgICAgSG9sdF9BZGRfUHJlZGljdGlvbnMsICMyCiAgICAgICAgICAgICAgICAgICAgSG9sdF9BZGRfRGFtcF9QcmVkaWN0aW9ucywgIzMKICAgICAgICAgICAgICAgICAgICBIb2x0X011bHRfRGFtcF9QcmVkaWN0aW9ucywgIzQKICAgICAgICAgICAgICAgICAgICBIV19BZGRfUHJlZGljdGlvbnMsICM1CiAgICAgICAgICAgICAgICAgICAgSFdfTXVsdF9QcmVkaWN0aW9ucywgIzYKICAgICAgICAgICAgICAgICAgICBIV19BZGRfRGFtcF9QcmVkaWN0aW9ucywgIzcgCiAgICAgICAgICAgICAgICAgICAgSFdfTXVsdF9EYW1wX1ByZWRpY3Rpb25zKSAjOAoKY29sbmFtZXMoUHJlZGljdGlvbnMpID0gYygiU0VTIiwgIkhvbHQgQWRkIiwgIkhvbHQgQWRkIFcvIERhbXAiLCAiSG9sdCBNdWx0aXBseSBXLyBEYW1wIiwgIkhXIEFkZCIsICJIVyBNdWx0aXBseSIsICJIVyBBZGQgVy8gRGFtcCIsICJIVyBNdWx0aXBseSBXLyBEYW1wIikKa2FibGUoUHJlZGljdGlvbnMsIGNhcHRpb24gPSAiTW9kZWwgRm9yZWNhc3RzIGZvciBNb250aGx5IEFtYXpvbiBTdG9jayBPcGVuaW5ncyIsIGFsaWduID0gImMiKQpgYGAKCkZpcnN0LCB3ZSBzZWUgdGhhdCBvdXIgU0VTIG1vZGVsJ3MgZm9yZWNhc3RzIHdlcmUgYWxsIGVxdWFsIHRvICQzMjQxLjM1LiBUaGlzIG1lYW5zIHRoYXQsIGlmIHdlIHdlcmUgdG8gYXNzdW1lIG5vIGZ1dHVyZSBkZXZpYXRpb24gZHVlIHRvIHRyZW5kIG9yIHNlYXNvbmFsIGNvbXBsaWNhdGlvbiwgQW1hem9uJ3Mgc3RvY2sgc2hvdWxkIGNvbnRpbnVlIHRvIGhhdmUgYW4gYXZlcmFnZSBvcGVuaW5nIG9mIHRoYXQgYW1vdW50LiBOZXh0LCB0aGUgaGlnaGVzdCBwcmVkaWN0ZWQgdmFsdWVzLCBieSBhIHN1YnN0YW50aWFsIGFtb3VudCwgY2FtZSBmcm9tIHRoZSBIb2x0IGFkZGl0aXZlLCBIb2x0LVdpbnRlcnMgYWRkaXRpdmUgYW5kIEhvbHQtV2ludGVycyBtdWx0aXBsaWNhdGl2ZSBtb2RlbHMuIFRoaXMgaXMgbm90IHN1cnByaXNpbmcgYXMgdGhleSBhcmUgdGhlIHRocmVlIG1vZGVscyBvdXQgb2YgdGhlIGVpZ2h0IGNyZWF0ZWQgb25lcyB0aGF0IHRha2UgaW50byBhY2NvdW50IHRoZSBpbmNyZWFzaW5nIHRyZW5kIHRoYXQgQW1hem9uJ3MgbWFya2V0IG9wZW4gaGFkIGZyb20gSmFudWFyeSAyMDA5IHRvIE9jdG9iZXIgMjAyMCAqKmFuZCoqIG9wZXJhdGUgdW5kZXIgdGhlIGFzc3VtcHRpb24gdGhhdCBzdWNoIHRyZW5kIHdpbGwgY29udGludWUgYXQgYXBwcm94aW1hdGVseSB0aGUgc2FtZSByYXRlLgoKIyMgTW9kZWwgRXZhbHVhdGlvbi9SYW5raW5nIE1ldHJpY3MKQWZ0ZXIgbG9va2luZyBhdCBlYWNoIG1vZGVscycgcHJlZGljdGVkIHZhbHVlcywgSSBjaG9zZSB0byBydW4gc3RhbmRhcmQgYWNjdXJhY3kgbWV0cmljcyBvbiBlYWNoIG9uZSwgdXNpbmcgdGhlICoqdHJhaW5pbmcqKiBkYXRhIHRvIGRvIHNvLiBVbHRpbWF0ZSBlcnJvciBhbmFseXNpcyBkb3duIHRoZSBsaW5lIHdpbGwgdXRpbGl6ZSB0aGUgdGVzdGluZyBkYXRhLgoKYGBge3IsIGZpZy5hbGlnbj0nY2VudGVyJ30KQWNjdXJhY3lfVGFibGUgPSBkYXRhLmZyYW1lKHJiaW5kKHJvdW5kKGFjY3VyYWN5KFNpbXBsZV9Nb2RlbCksNCksCiAgICAgICAgICAgICAgICAgICAgICAgcm91bmQoYWNjdXJhY3koSG9sdF9Nb2RlbF9BZGQpLDQpLAogICAgICAgICAgICAgICAgICAgICAgIHJvdW5kKGFjY3VyYWN5KEhvbHRfTW9kZWxfQWRkX0RhbXApLDQpLAogICAgICAgICAgICAgICAgICAgICAgIHJvdW5kKGFjY3VyYWN5KEhvbHRfTW9kZWxfTXVsdF9EYW1wKSw0KSwKICAgICAgICAgICAgICAgICAgICAgICByb3VuZChhY2N1cmFjeShIV19Nb2RlbF9BZGQpLDQpLAogICAgICAgICAgICAgICAgICAgICAgIHJvdW5kKGFjY3VyYWN5KEhXX01vZGVsX011bHQpLDQpLAogICAgICAgICAgICAgICAgICAgICAgIHJvdW5kKGFjY3VyYWN5KEhXX01vZGVsX0FkZF9EYW1wKSw0KSwKICAgICAgICAgICAgICAgICAgICAgICByb3VuZChhY2N1cmFjeShIV19Nb2RlbF9NdWx0X0RhbXApLDQpCiAgICAgICAgICAgICAgICAgICAgICAgKSkKICAgICAgICAgICAgICAgICAgICAgICAKcm93bmFtZXMoQWNjdXJhY3lfVGFibGUpID0gY29sbmFtZXMoUHJlZGljdGlvbnMpCmthYmxlKEFjY3VyYWN5X1RhYmxlLCBjYXB0aW9uID0gIk1vZGVsIEFjY3VyYWN5IFN1bW1hcnkgVGFibGUiLCBhbGlnbiA9ICJjIikKYGBgCgpBbG9uZyB3aXRoIGNyZWF0aW5nIHRoZSB0YWJsZSBzZWVuIGFib3ZlLCBJIGFsc28gY3JlYXRlZCBzb3J0ZWQgc3VidGFibGVzIGZvciBlYWNoIGFjY3VyYWN5IG1ldHJpYywgcmFua2luZyBtb2RlbCBwZXJmb3JtYW5jZSBmcm9tIGJlc3QgdG8gd29yc3QuIEkgdG9vayBwYXJ0aWN1bGFyIG5vdGUgb2YgdGhlIFNFUywgSG9sdCBhZGRpdGl2ZSB3aXRoIGRhbXAgYW5kIEhvbHQgbXVsdGlwbGljYXRpdmUgd2l0aCBkYW1wIG1vZGVscywgYXMgdGhlaXIgcHJlZGljdGVkIHZhbHVlcyBhcmUgdGhlIG1vc3Qgc2ltaWxhciB0byB0aGUgdHJ1ZSBvcGVuaW5nIHN0b2NrIHZhbHVlcyBwcmVzZW50IGluIG91ciB0ZXN0aW5nIHNldC4gVGhlIG90aGVycyBhbGwgb3ZlcmZvcmVjYXN0ZWQgdG8gYSBub3RpY2VhYmxlIGRlZ3JlZS4gCgpSZWdhcmRpbmcgdGhlIHRocmVlIG1vZGVscyBvZiBoZWlnaHRlbmVkIGludGVyZXN0LCB0aGUgU0VTIG1vZGVsIGFjdHVhbGx5IHJhbmtlZCAqbGFzdCogaW4gYWxsIG1ldHJpY3MgZXhjZXB0IE1BUEUsIGFuZCBib3RoIHRoZSBkYW1wZWQgSG9sdCBhZGRpdGl2ZSBhbmQgZGFtcGVkIEhvbHQgbXVsdGlwbGljYXRpdmUgbW9kZWxzIHJhbmtlZCBhbnl3aGVyZSBiZXR3ZWVuIDNyZCBhbmQgNXRoIG9uIG1vc3QgbWV0cmljcy4gV2hpbGUgdGhpcyBzZWVtcyBjb250cmFkaWN0b3J5IHRvIG15IHByZXZpb3VzIG9ic2VydmF0aW9uIHRoYXQgdGhlc2UgdGhyZWUgbW9kZWxzJyBmb3JlY2FzdHMgd2VyZSBtb3N0IHNpbWlsYXIgdG8gdGhlIHRlc3Rpbmcgc2V0J3MgdHJ1ZSBtb250aGx5IGF2ZXJhZ2UgQW1hem9uIG1hcmtldCBvcGVucywgaXQgaXMgY3J1Y2lhbCB0byByZW1lbWJlciB0aGF0IHRoZSBhY2N1cmFjeSBjYWxjdWxhdGlvbnMgYXQgaGFuZCB3ZXJlIHBlcmZvcm1lZCB2aWEgdGhlIHRyYWluaW5nIGRhdGEuIFRoZXJlZm9yZSwgdGhpcyBpcyBzb21ldGhpbmcgdG8gbm90ZSBhbmQgdG8ga2VlcCBpbiBtaW5kIHdoaWxlIG1vdmluZyBmb3J3YXJkIGluIHRoZSBhbmFseXNpcy4KCmBgYHtyLCByZXN1bHRzPSdoaWRlJ30KUmFua2VkX01FID0gZGF0YS5mcmFtZShyb3duYW1lcyhBY2N1cmFjeV9UYWJsZSksIEFjY3VyYWN5X1RhYmxlJE1FKQpjb2xuYW1lcyhSYW5rZWRfTUUpID0gYygiTW9kZWwiLCAiTUUiKQogIFJhbmtlZF9NRSA9IGFycmFuZ2UoUmFua2VkX01FLCBNRSkKICAKUmFua2VkX1JNU0UgPSBkYXRhLmZyYW1lKHJvd25hbWVzKEFjY3VyYWN5X1RhYmxlKSwgQWNjdXJhY3lfVGFibGUkUk1TRSkKY29sbmFtZXMoUmFua2VkX1JNU0UpID0gYygiTW9kZWwiLCAiUk1TRSIpCiAgUmFua2VkX1JNU0UgPSBhcnJhbmdlKFJhbmtlZF9STVNFLCBSTVNFKQogIApSYW5rZWRfTUFFID0gZGF0YS5mcmFtZShyb3duYW1lcyhBY2N1cmFjeV9UYWJsZSksIEFjY3VyYWN5X1RhYmxlJE1BRSkKY29sbmFtZXMoUmFua2VkX01BRSkgPSBjKCJNb2RlbCIsICJNQUUiKQogIFJhbmtlZF9NQUUgPSBhcnJhbmdlKFJhbmtlZF9NQUUsIE1BRSkKICAKUmFua2VkX01QRSA9IGRhdGEuZnJhbWUocm93bmFtZXMoQWNjdXJhY3lfVGFibGUpLCBBY2N1cmFjeV9UYWJsZSRNUEUpCmNvbG5hbWVzKFJhbmtlZF9NUEUpID0gYygiTW9kZWwiLCAiTVBFIikKICBSYW5rZWRfTVBFID0gYXJyYW5nZShSYW5rZWRfTVBFLCBNUEUpCiAgClJhbmtlZF9NQVBFID0gZGF0YS5mcmFtZShyb3duYW1lcyhBY2N1cmFjeV9UYWJsZSksIEFjY3VyYWN5X1RhYmxlJE1BUEUpCmNvbG5hbWVzKFJhbmtlZF9NQVBFKSA9IGMoIk1vZGVsIiwgIk1BUEUiKQogIFJhbmtlZF9NQVBFID0gYXJyYW5nZShSYW5rZWRfTUFQRSwgTUFQRSkKICAKUmFua2VkX01BU0UgPSBkYXRhLmZyYW1lKHJvd25hbWVzKEFjY3VyYWN5X1RhYmxlKSwgQWNjdXJhY3lfVGFibGUkTUFTRSkKY29sbmFtZXMoUmFua2VkX01BU0UpID0gYygiTW9kZWwiLCAiTUFTRSIpCiAgUmFua2VkX01BU0UgPSBhcnJhbmdlKFJhbmtlZF9NQVNFLCBNQVNFKQogIApSYW5rZWRfQUNGMSA9IGRhdGEuZnJhbWUocm93bmFtZXMoQWNjdXJhY3lfVGFibGUpLCBBY2N1cmFjeV9UYWJsZSRBQ0YxKQpjb2xuYW1lcyhSYW5rZWRfQUNGMSkgPSBjKCJNb2RlbCIsICJBQ0YxIikKICBSYW5rZWRfQUNGMSA9IGFycmFuZ2UoUmFua2VkX0FDRjEsIEFDRjEpCiAgCmthYmxlKFJhbmtlZF9NRSkKa2FibGUoUmFua2VkX1JNU0UpCmthYmxlKFJhbmtlZF9NQUUpCmthYmxlKFJhbmtlZF9NUEUpCmthYmxlKFJhbmtlZF9NQVBFKQprYWJsZShSYW5rZWRfTUFTRSkKa2FibGUoUmFua2VkX0FDRjEpCmBgYAoKIyMgTW9kZWwgUGxvdHRpbmcKQmVsb3cgSSBwbG90dGVkIHRoZSBmb3JlY2FzdHMgb2YgYWxsIGVpZ2h0IG1vZGVscyBpbiBjb21wYXJpc29uIHRvIHRoZSB2YWx1ZXMgZnJvbSBvdXIgdGVzdGluZyBkYXRhc2V0LgpGb3IgZ3JlYXRlciB2aXN1YWwgZWFzZSwgbXkgZmlyc3QgcGxvdCBjb250YWlucyB0aGUgZm91ciBtb2RlbHMgd2hvc2UgcHJlZGljdGlvbnMgZG8gbm90IGZhY3RvciBpbiBzZWFzb25hbCBvc2NpbGxhdGlvbnMuIFdoaWxlIG15IHNlY29uZCBwbG90IGRpc3BsYXlzIHRoZSBmb3VyIHNlYXNvbmFsbHktY29uc2lkZXJhdGUgbW9kZWxzICh0aGUgSG9sdC1XaW50ZXJzIG9uZXMpLgoKYGBge3IsIGZpZy5oZWlnaHQgPSA1LCBmaWcuYWxpZ249J2NlbnRlcid9CiMgU2Vhc29uYWwKICBjb2xuYW1lcyhTaW1wbGVfUHJlZGljdGlvbnMpID0gIk9wZW4iCiAgY29sbmFtZXMoSG9sdF9BZGRfUHJlZGljdGlvbnMpID0gIk9wZW4iCiAgY29sbmFtZXMoSG9sdF9BZGRfRGFtcF9QcmVkaWN0aW9ucykgPSAiT3BlbiIKICBjb2xuYW1lcyhIb2x0X011bHRfRGFtcF9QcmVkaWN0aW9ucykgPSAiT3BlbiIKCiMgTm9uLXNlYXNvbmFsCiAgY29sbmFtZXMoSFdfQWRkX1ByZWRpY3Rpb25zKSA9ICJPcGVuIgogIGNvbG5hbWVzKEhXX0FkZF9EYW1wX1ByZWRpY3Rpb25zKSA9ICJPcGVuIgogIGNvbG5hbWVzKEhXX011bHRfUHJlZGljdGlvbnMpID0gIk9wZW4iCiAgY29sbmFtZXMoSFdfTXVsdF9EYW1wX1ByZWRpY3Rpb25zKSA9ICJPcGVuIgoKTGlzdF9PZl9EYXRlcyA9IGFzLkRhdGUoYygiMjAyMC0xMS0wMSIsICIyMDIwLTEyLTAxIiwgIjIwMjEtMDEtMDEiLCAiMjAyMS0wMi0wMSIsICIyMDIxLTAzLTAxIiwgIjIwMjEtMDQtMDEiLCAiMjAyMS0wNS0wMSIsICIyMDIxLTA2LTAxIiwgIjIwMjEtMDctMDEiLCAiMjAyMS0wOC0wMSIsICIyMDIxLTA5LTAxIiwgIjIwMjEtMTAtMDEiKSkgIAogClRlc3RpbmdfRGF0YSA9IGNiaW5kKExpc3RfT2ZfRGF0ZXMsIFRlc3RpbmdfRGF0YSkKY29sbmFtZXMoVGVzdGluZ19EYXRhKVsxXSA9ICJEYXRlIgoKIyMjIyMjIFBsb3QgMTogTm9uLVNlYXNvbmFsIE1ldGhvZHMKcGxvdCh4ID0gVGVzdGluZ19EYXRhJERhdGUsIHkgPSBUZXN0aW5nX0RhdGEkT3BlbiwKICAgICBtYWluID0gIk5vbi1TZWFzb25hbCBGb3JlY2FzdGluZyBNZXRob2RzIiwgCiAgICAgbXRleHQoIlNpbXBsZSBFeHBvbmVudGlhbCBTbW9vdGhpbmcgYW5kIEhvbHQgTW9kZWxzIiwgc2lkZSA9IDMsIGxpbmUgPSAwLjUsIGNleCA9IDAuOCksCiAgICAgeGxhYiA9ICJUaW1lIChOb3YgMjAyMCAtIE9jdCAyMDIxKSIsCiAgICAgeWxhYiA9ICJBbWF6b24gU3RvY2sgT3BlbmluZyAoJFVTRCkiLAogICAgIHlsaW0gPSBjKDMwMDAsIDQ1MDApKQogIGxpbmVzKHggPSBUZXN0aW5nX0RhdGEkRGF0ZSwgeSA9IFRlc3RpbmdfRGF0YSRPcGVuLCBjb2wgPSAiYmxhY2siLCBsd2QgPSAzKQogICAgcG9pbnRzKHggPSBUZXN0aW5nX0RhdGEkRGF0ZSwgeSA9IFRlc3RpbmdfRGF0YSRPcGVuLCBjb2wgPSAiYmxhY2siLCBwY2ggPSA4LCBiZyA9ICJibGFjayIpCiAgIAogICMgU2ltcGxlICAgCiAgbGluZXMoeCA9IFRlc3RpbmdfRGF0YSREYXRlLCB5ID0gU2ltcGxlX1ByZWRpY3Rpb25zJE9wZW4sIGNvbCA9ICJkYXJrYmx1ZSIsIGx3ZCA9IDIpCiAgICBwb2ludHMoeCA9IFRlc3RpbmdfRGF0YSREYXRlLCB5ID0gU2ltcGxlX1ByZWRpY3Rpb25zJE9wZW4sIGNvbCA9ICJkYXJrYmx1ZSIsIHBjaCA9IDIxLCBiZyA9ICJkYXJrYmx1ZSIpCiAgICAKICAjIEhvbHQgQWRkIFcvTyBEYW1wCiAgbGluZXMoeCA9IFRlc3RpbmdfRGF0YSREYXRlLCB5ID0gSG9sdF9BZGRfUHJlZGljdGlvbnMkT3BlbiwgY29sID0gImRhcmtyZWQiLCBsd2QgPSAyKQogICAgcG9pbnRzKHggPSBUZXN0aW5nX0RhdGEkRGF0ZSwgeSA9IEhvbHRfQWRkX1ByZWRpY3Rpb25zJE9wZW4sIGNvbCA9ICJkYXJrcmVkIiwgcGNoID0gMjEsIGJnID0gImRhcmtyZWQiKQogICAgCiAgIyBIb2x0IEFkZCBXLyBEYW1wCiAgbGluZXMoeCA9IFRlc3RpbmdfRGF0YSREYXRlLCB5ID0gSG9sdF9BZGRfRGFtcF9QcmVkaWN0aW9ucyRPcGVuLCBjb2wgPSAiZGFya2dyZWVuIiwgbHdkID0gMikKICAgIHBvaW50cyh4ID0gVGVzdGluZ19EYXRhJERhdGUsIHkgPSBIb2x0X0FkZF9EYW1wX1ByZWRpY3Rpb25zJE9wZW4sIGNvbCA9ICJkYXJrZ3JlZW4iLCBwY2ggPSAyMSwgYmcgPSAiZGFya2dyZWVuIikgCiAgICAKICAjIEhvbHQgTXVsdCBXLyBEYW1wCiAgbGluZXMoeCA9IFRlc3RpbmdfRGF0YSREYXRlLCB5ID0gSG9sdF9NdWx0X0RhbXBfUHJlZGljdGlvbnMkT3BlbiwgY29sID0gImdyYXkiLCBsd2QgPSAyKQogICAgcG9pbnRzKHggPSBUZXN0aW5nX0RhdGEkRGF0ZSwgeSA9IEhvbHRfTXVsdF9EYW1wX1ByZWRpY3Rpb25zJE9wZW4sIGNvbCA9ICJncmF5IiwgcGNoID0gMjEsIGJnID0gImdyYXkiKQogICAgCiAgICBsZWdlbmQoInRvcGxlZnQiLAogICAgIGxlZ2VuZCA9IGMoIlRydWUgVmFsdWVzIiwgIlNpbXBsZSIsICJIb2x0IEFkZCIsICJIb2x0IEFkZCBXLyBEYW1wIiwgIkhvbHQgTXVsdCBXLyBEYW1wIiksCiAgICAgY29sID0gYygiYmxhY2siLCAiZGFya2JsdWUiLCAiZGFya3JlZCIsICJkYXJrZ3JlZW4iLCAiZ3JheSIpLAogICAgIGx0eSA9IDEsIHBjaCA9IDE2LCBsd2QgPSAyKQpgYGAKCkZyb20gb3VyIG5vbi1zZWFzb25hbCBwbG90LCBpdCBpcyBub3RpY2VhYmxlIHJpZ2h0IGF3YXkgdGhhdCB0aGUgU0VTIGFuZCBkYW1wZWQgSG9sdCBtb2RlbHMgcGVyZm9ybWVkICoqZmFyKiogYmV0dGVyIHByZWRpY3RpdmVseSB0aGFuIHRoZSBub24tZGFtcGVkIGFkZGl0aXZlIEhvbHQgbW9kZWwuIE1lYW53aGlsZSwgdGhlIG11bHRpcGxpY2F0aXZlIEhvbHQgbW9kZWwgb3ZlcmZvcmVjYXN0ZWQgbW9yZSB0aGFuIHRoZSBhZGRpdGl2ZSBIb2x0IG9yIFNFUyBtb2RlbC4KCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNSwgZmlnLmFsaWduPSdjZW50ZXInfSAgCiMjIyMjIyBQbG90IDI6IFNlYXNvbmFsIEhXIE1ldGhvZHMKcGxvdCh4ID0gVGVzdGluZ19EYXRhJERhdGUsIHkgPSBUZXN0aW5nX0RhdGEkT3BlbiwKICAgICBtYWluID0gIlNlYXNvbmFsIEZvcmVjYXN0aW5nIE1ldGhvZHMiLCAKICAgICBtdGV4dCgiSG9sdC1XaW50ZXJzIE1vZGVscyIsIHNpZGUgPSAzLCBsaW5lID0gMC41LCBjZXggPSAwLjgpLAogICAgIHhsYWIgPSAiVGltZSAoTm92IDIwMjAgLSBPY3QgMjAyMSkiLAogICAgIHlsYWIgPSAiQW1hem9uIFN0b2NrIE9wZW5pbmcgKCRVU0QpIiwKICAgICB5bGltID0gYygzMDAwLCA0ODAwKSkKICBsaW5lcyh4ID0gVGVzdGluZ19EYXRhJERhdGUsIHkgPSBUZXN0aW5nX0RhdGEkT3BlbiwgY29sID0gImJsYWNrIiwgbHdkID0gMykKICAgIHBvaW50cyh4ID0gVGVzdGluZ19EYXRhJERhdGUsIHkgPSBUZXN0aW5nX0RhdGEkT3BlbiwgY29sID0gImJsYWNrIiwgcGNoID0gOCwgYmcgPSAiYmxhY2siKQogICAKICAjIFNpbXBsZSAgIAogIGxpbmVzKHggPSBUZXN0aW5nX0RhdGEkRGF0ZSwgeSA9IEhXX0FkZF9QcmVkaWN0aW9ucyRPcGVuLCBjb2wgPSAiZGFya2JsdWUiLCBsd2QgPSAyKQogICAgcG9pbnRzKHggPSBUZXN0aW5nX0RhdGEkRGF0ZSwgeSA9IEhXX0FkZF9QcmVkaWN0aW9ucyRPcGVuLCBjb2wgPSAiZGFya2JsdWUiLCBwY2ggPSAyMSwgYmcgPSAiZGFya2JsdWUiKQogICAgCiAgIyBIb2x0IEFkZCBXL08gRGFtcAogIGxpbmVzKHggPSBUZXN0aW5nX0RhdGEkRGF0ZSwgeSA9IEhXX0FkZF9EYW1wX1ByZWRpY3Rpb25zJE9wZW4sIGNvbCA9ICJkYXJrcmVkIiwgbHdkID0gMikKICAgIHBvaW50cyh4ID0gVGVzdGluZ19EYXRhJERhdGUsIHkgPSBIV19BZGRfRGFtcF9QcmVkaWN0aW9ucyRPcGVuLCBjb2wgPSAiZGFya3JlZCIsIHBjaCA9IDIxLCBiZyA9ICJkYXJrcmVkIikKICAgIAogICMgSG9sdCBBZGQgVy8gRGFtcAogIGxpbmVzKHggPSBUZXN0aW5nX0RhdGEkRGF0ZSwgeSA9IEhXX011bHRfUHJlZGljdGlvbnMkT3BlbiwgY29sID0gImRhcmtncmVlbiIsIGx3ZCA9IDIpCiAgICBwb2ludHMoeCA9IFRlc3RpbmdfRGF0YSREYXRlLCB5ID0gSFdfTXVsdF9QcmVkaWN0aW9ucyRPcGVuLCBjb2wgPSAiZGFya2dyZWVuIiwgcGNoID0gMjEsIGJnID0gImRhcmtncmVlbiIpIAogICAgCiAgIyBIb2x0IE11bHQgVy8gRGFtcAogIGxpbmVzKHggPSBUZXN0aW5nX0RhdGEkRGF0ZSwgeSA9IEhXX011bHRfRGFtcF9QcmVkaWN0aW9ucyRPcGVuLCBjb2wgPSAiZ3JheSIsIGx3ZCA9IDIpCiAgICBwb2ludHMoeCA9IFRlc3RpbmdfRGF0YSREYXRlLCB5ID0gSFdfTXVsdF9EYW1wX1ByZWRpY3Rpb25zJE9wZW4sIGNvbCA9ICJncmF5IiwgcGNoID0gMjEsIGJnID0gImdyYXkiKQogICAgCiAgIGxlZ2VuZCgidG9wbGVmdCIsCiAgICAgbGVnZW5kID0gYygiVHJ1ZSBWYWx1ZXMiLCAiSFcgQWRkIiwgIkhXIEFkZCBXLyBEYW1wIiwgIkhXIE11bHQiLCAiSFcgTXVsdCBXLyBEYW1wIiksCiAgICAgY29sID0gYygiYmxhY2siLCAiZGFya2JsdWUiLCAiZGFya3JlZCIsICJkYXJrZ3JlZW4iLCAiZ3JheSIpLAogICAgIGx0eSA9IDEsIHBjaCA9IDE2LCBsd2QgPSAyKQpgYGAKCkFmdGVyIHRha2luZyBhIGxvb2sgYXQgdGhlIGZvdXIgSG9sdHMtV2ludGVycyAoSFcpIG1vZGVscyAtIHRoZSBvbmVzIHRoYXQgY29uc2lkZXIgYSBkYXRhc2V0J3Mgc2Vhc29uYWwgY29tcG9uZW50IC0gSSBzYXcgY2xlYXIgYW5kIGNvbnNpc3RlbnQgb3ZlcnByZWRpY3Rpb24uIEV2ZW4gdGhlIGRhbXBlZCBIVyBtb2RlbHMsIHdoaWNoIG9wZXJhdGUgdW5kZXIgdGhlIHByZXN1bXB0aW9uIHRoYXQgYW4gaW5jcmVhc2luZyBvciBkZWNyZWFzaW5nIHRyZW5kIHByZXZpb3VzbHkgc2VlbiBpbiB0aGUgZGF0YSB3aWxsIG1pdGlnYXRlIGluIGVmZmVjdCBvdmVyIHRpbWUsIGRpZCBub3QgaGF2ZSBhIGZvcmVjYXN0ZWQgdmFsdWUgY2xvc2UgdG8gbWF0Y2hpbmcgdGhlIHRydWUgcmVjb3JkZWQgYXZlcmFnZSBvcGVuaW5nIG1hcmtldCB2YWx1ZSBmb3IgQW1hem9uIHRob3NlIHNlbGVjdGVkIG1vbnRocy4KCkFmdGVyIHJldmlld2luZyBlYWNoIG9mIHRoZSBlaWdodCBtb2RlbHMnIGZvcmVjYXN0ZWQgdmFsdWVzLCBhbmQgdGhlbiBzZWVpbmcgdGhlbSBhbGwgcGxvdHRlZCBpbiByZWxhdGlvbiB0byB0aGUga25vd24gdmFsdWVzIGZyb20gb3VyIHRlc3RpbmcgZGF0YXNldCwgSSBjaG9zZSB0byBkZXNpZ25hdGUgdGhlIGRhbXBlZCBhZGRpdGl2ZSBIb2x0IG1vZGVsIGFuZCB0aGUgU0VTIG1vZGVsIGFzIHRoZSB0d28gbW9zdCBlZmZlY3RpdmUgaW4gdGhlaXIgcHJlZGljdGlvbiBhY2N1cmFjeS4gTmV4dCB1cCBJIHRvb2sgYSBjbG9zZXIgbG9vayBhdCB0aGUgdHdvLCBydW5uaW5nIGVycm9yIGFuYWx5c2lzLCB0aGlzIHRpbWUgYnkgY29tcGFyaW5nIGVhY2ggbW9kZWwncyBmb3JlY2FzdHMgdG8gdGhlICoqdGVzdGluZyoqIGRhdGEgdmFsdWVzLgoKIyMgRmluYWwgTW9kZWwgU2VsZWN0aW9uCkZpbmFsbHksIGJlZm9yZSBzZWxlY3Rpbmcgd2hpY2ggb2YgdGhlc2UgbW9kZWxzIHdhcyBtb3N0IGVmZmVjdGl2ZSBpbiB0aGlzIHByZWRpY3RpdmUgYW5hbHlzaXMgc2NlbmFyaW8sIEkgd2FudGVkIHRvIGxvb2sgYXQgZWFjaCBtb2RlbCdzIGVycm9ycywgYm90aCBvYnNlcnZhdGlvbi1ieS1vYnNlcnZhdGlvbiBhbmQgaG9saXN0aWNhbGx5LgpJIGNyZWF0ZWQgYSB0YWJsZSB0aGF0IGJyb2tlIGRvd24gZWFjaCBtb2RlbCdzIGVycm9yIGZvciBlYWNoIG9mIHRoZSAxMiBtb250aHMnIGZvcmVjYXN0cywgYXMgd2VsbCBhcyBjYWxjdWxhdGluZyB0aGUgcmVzcGVjdGl2ZSBtZWFuIHNxdWFyZSBlcnJvciAoTVNFKSBhbmQgbWVhbiBhYnNvbHV0ZSBwcmVkaWN0aW9uIGVycm9yIChNQVBFKS4gUGVyIHRoZXNlIGNhbGN1bGF0aW9ucywgSSBkZWVtZWQgdGhlIFNFUyBtb2RlbCBhcyB0aGUgbW9zdCBlZmZlY3RpdmUgZm9yIGZvcmVjYXN0aW5nIHB1cnBvc2VzIG9mIHRoZSBlaWdodCBhdmFpbGFibGUuCmBgYHtyfQpTaW1wbGVfRXJyb3JzID0gU2ltcGxlX1ByZWRpY3Rpb25zIC0gVGVzdGluZ19EYXRhJE9wZW4KSG9sdF9BZGRfRGFtcF9FcnJvcnMgPSBIb2x0X0FkZF9EYW1wX1ByZWRpY3Rpb25zIC0gVGVzdGluZ19EYXRhJE9wZW4KCk1vZGVsX1NlbGVjdF9UYWJsZSA9IGNiaW5kKFRlc3RpbmdfRGF0YSRPcGVuLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgU2ltcGxlX1ByZWRpY3Rpb25zLCBTaW1wbGVfRXJyb3JzLAogICAgICAgICAgICAgICAgICAgICAgICAgICBIb2x0X0FkZF9EYW1wX1ByZWRpY3Rpb25zLCBIb2x0X0FkZF9EYW1wX0Vycm9ycykKCmNvbG5hbWVzKE1vZGVsX1NlbGVjdF9UYWJsZSkgPSBjKCJUcnVlIFZhbHVlcyIsICJTaW1wbGUgU21vb3RoaW5nIiwgIlNpbXBsZSBTbW9vdGhpbmcgRXJyb3JzIiwgIkhvbHQgQWRkaXRpb24gVy8gRGFtcCIsICJIb2x0IEVycm9ycyIpCmthYmxlKE1vZGVsX1NlbGVjdF9UYWJsZSwgY2FwdGlvbiA9ICJQcmVkaWN0aW9uIGFuZCBFcnJvciBCcmVha2Rvd24gZm9yIFNFUyBhbmQgQWRkaXRpdmUgSG9sdCBNb2RlbHMiLCBhbGlnbiA9ICJjIikKCiMgTVNFClNpbXBsZV9FcnJfTVNFID0gc3VtKFNpbXBsZV9FcnJvcnNeMikvbnJvdyhTaW1wbGVfRXJyb3JzKQpIb2x0X0FkZF9EYW1wX0Vycm9yc19NU0UgPSBzdW0oSG9sdF9BZGRfRGFtcF9FcnJvcnNeMikvbnJvdyhIb2x0X0FkZF9EYW1wX0Vycm9ycykKCiMgTUFQRQpTaW1wbGVfRXJyX01BUEUgPSAoc3VtKGFicygoU2ltcGxlX0Vycm9ycy9UZXN0aW5nX0RhdGEkT3BlbikqMTAwKSkpL25yb3coU2ltcGxlX0Vycm9ycykKSG9sdF9BZGRfRGFtcF9FcnJvcnNfTUFQRSA9IChzdW0oYWJzKChIb2x0X0FkZF9EYW1wX0Vycm9ycy9UZXN0aW5nX0RhdGEkT3BlbikqMTAwKSkpL25yb3coSG9sdF9BZGRfRGFtcF9FcnJvcnMpCgpFcnJvcl9TdW1tYXJ5ID0gZGF0YS5mcmFtZShyYmluZChTaW1wbGVfRXJyX01TRSwgSG9sdF9BZGRfRGFtcF9FcnJvcnNfTVNFKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJiaW5kKFNpbXBsZV9FcnJfTUFQRSwgSG9sdF9BZGRfRGFtcF9FcnJvcnNfTUFQRSkpCmNvbG5hbWVzKEVycm9yX1N1bW1hcnkpID0gYygiTVNFIiwgIk1BUEUiKQpyb3duYW1lcyhFcnJvcl9TdW1tYXJ5KSA9IGMoIlNpbXBsZSBFeHBvbmVudGlhbCBTbW9vdGhpbmciLCAiSG9sdCBBZGRpdGl2ZSBXLyBEYW1wIikKa2FibGUoRXJyb3JfU3VtbWFyeSwgY2FwdGlvbiA9ICJBY2N1cmFjeSBDYWxjdWxhdGlvbnMgZm9yIFNFUyBhbmQgQWRkaXRpdmUgSG9sdCBNb2RlbHMiLCBhbGlnbiA9ICJjIikKYGBgCgojIENvbmNsdXNpb24KVWx0aW1hdGVseSwgb2YgdGhlIGVpZ2h0IG1vZGVscyB0aGF0IHdlcmUgY3JlYXRlZCB0aHJvdWdob3V0IHRoaXMgYW5hbHlzaXMsIHRoZSBtb3N0IHN0cmFpZ2h0Zm9yd2FyZCBvbmUgLSBzaW1wbGUgZXhwb25lbnRpYWwgc21vb3RoaW5nIChTRVMpIC0gd2FzIHRoZSBtb3N0IGVmZmVjdGl2ZS4gUmV0cm9zcGVjdGl2ZWx5LCBJIGJlbGlldmUgdGhpcyBjYW4gYmUgYXR0cmlidXRlZCB0byB0d28gcmVhc29uczsgdGhlIGZpcnN0IGJlaW5nIHRoZSBzcGlrZSBpbiB0aGUgcmF0ZSBvZiBBbWF6b24ncyBzdG9jayBpbmNyZWFzZSBmcm9tIGFib3V0IDIwMTggdG8gT2N0b2JlciBvZiAyMDIxICh0aGUgZW5kaW5nIHF1YXJ0ZXIgb2YgdGhlIGRhdGEgdXNlZCBmb3IgdGhpcyBhbmFseXNpcykuIFRoZSBtYWduaXR1ZGUgb2YgdGhlIHJpc2UgaW4gdmFsdWUsIGluIHJlbGF0aW9uIHRvIHRoZSBhbW91bnQgb2YgdGltZSBwYXNzZWQgZHVyaW5nIHRoYXQgaW50ZXJ2YWwsIHdhcyBzbyBtdWNoIGdyZWF0ZXIgdGhhbiB0aGUgZmlyc3QgdGhyZWUgcXVhcnRlcnMgb2YgdGhlIGRhdGFzZXQuIEJlY2F1c2Ugb2YgdGhpcywgYWxsIG9mIHRoZSBub24tZGFtcGVkIG1vZGVscyAoYm90aCBIb2x0IGFuZCBIVyksIGRyYXN0aWNhbGx5IGFuZCBjb25zaXN0ZW50bHkgb3ZlcmZvcmVjYXN0ZWQuIEVzc2VudGlhbGx5LCB0aGUgYXNzdW1wdGlvbiBvZiB0aGVzZSBub24tZGFtcGVkIG1vZGVscyB0aGF0IHRoZSB0cmVuZCB2aXNpYmxlIGluIHRoZSBkYXRhc2V0IChhbmQgbW9yZSBoZWF2aWx5IGluZmx1ZW5jZWQgYnkgbW9yZSByZWNlbnQgb2JzZXJ2YXRpb25zKSB3YXMgcmVwcmVzZW50YXRpdmUgb2YgYSBuZXcgY29uc3RhbnQgcmF0ZSBvZiBpbmNyZWFzZSwgd2FzIHRoZSBkb3duZmFsbCBpbiB0aGVpciBmb3JlY2FzdGluZyBhY2N1cmFjeS4KClRoZSBzZWNvbmQgZXhwbGFuYXRpb24gZm9yIFNFUyB0dXJuaW5nIG91dCB0byBiZSB0aGUgbW9zdCBhY2N1cmF0ZSBpbiB0aGlzIGluc3RhbmNlIGlzIHRoYXQgdGhlIGRhdGEncyBzZWFzb25hbCBjb21wb25lbnQgd2FzIHJhdGhlciBwYXJhbGxlbCB0byB0aGUgdHJlbmQgaW4gaXRzIGJlaGF2aW9yIHJlbGF0aXZlIHRvIHRoZSB0aW1lIHBlcmlvZC4gSXQgd2FzIHZpc2libGUgaW4gdGhlIHNlYXNvbi1ieS1zZWFzb24gcGxvdHMgdGhhdCB0aGUgc2Vhc29uYWwgZGlmZmVyZW5jZXMgaW4gYXZlcmFnZSBBbWF6b24gc3RvY2sgb3BlbmluZyBkdXJpbmcgdGhlIGxhc3QgeWVhcnMgb2YgdGhlIHRpbWUgaW50ZXJ2YWwgd2VyZSBtdWNoIGdyZWF0ZXIgdGhhbiBzYWlkIGRpZmZlcmVuY2VzIGluIHRoZSBlYXJseSB5ZWFycyBvZiB0aGUgdGltZSBpbnRlcnZhbC4gQWxsIHRoZSBIVyBtb2RlbHMsIGJvdGggZGFtcGVkIGFuZCBub24tZGFtcGVkLCB0YWtlIHNlYXNvbmFsaXR5IGludG8gY2FsY3VsYXRpdmUgY29uc2lkZXJhdGlvbi4gVG9vIG11Y2ggd2VpZ2h0IHdhcyBnaXZlbiB0byB0aGUgaW5jcmVhc2UgaW4gc2Vhc29uYWwgZGlzcGFyaXR5IGluIHRoZSBtb3N0IHJlY2VudCB5ZWFycywgbGVhZGluZyB0byBjb25zaXN0ZW50IG92ZXJmb3JlY2FzdGluZy4KCkluIHRoZSBmdXR1cmUsIGl0IHdvdWxkIGJlIHVzZWZ1bCB0byBhbmFseXplIEFtYXpvbidzIGhpc3RvcmljYWwgbW9udGhseSBhdmVyYWdlIG1hcmtldCBvcGVuaW5nIHByaWNlIHdpdGggYSBtZXRob2QgbGVzcyB2dWxuZXJhYmxlIHRvIG5lYXItdGVybSBhbmQgcmVjZW50IHNwaWtlcyBpbiBvdmVyYWxsIGluY3JlYXNpbmcvZGVjcmVhc2luZyB0cmVuZHMgYW5kL29yIHNlYXNvbmFsIG9zY2lsbGF0aW9ucy4KIyBSZWZlcmVuY2VzOgoKT3JpZ2luYWwgRGF0YXNldCBTb3VyY2U6CgotIGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vZGF0YXNldHMva2FubmFuMTMxNC9hbWF6b24tc3RvY2stcHJpY2UtYWxsLXRpbWUvZGF0YQoKRGF0YXNldCBEb3dubG9hZCBMaW5rIHZpYSBHaXRodWI6CgotIGh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9DaHJpc0IyMzIzL1NUQTMyMS9yZWZzL2hlYWRzL21haW4vQW1hem9uLmNzdgo=