Objective: The primary goal is to forecast future prices of Tesla
(TSLA) stock using time series analysis techniques. This includes
fitting an ARIMA model to historical stock price data to generate
forecasts for the future price movement of the stock.
install.packages(c("quantmod", "forecast", "tseries", "TTR", "ggplot2", "tidyverse"))
Installs all necessary packages.
library(quantmod)
getSymbols("TSLA", from = "2023-01-01", to = "2024-12-31")
[1] "TSLA"
prices <- Cl(TSLA)
Explanation: This code block loads the quantmod package and retrieves
historical stock price data for Tesla (TSLA) from January 1, 2023, to
December 31, 2024. The getSymbols function downloads the data, and the
Cl() function extracts the closing prices.
Benefit: By loading historical price data, us can perform time series
analysis and forecasting on real-world stock prices, making the analysis
more relevant and practical.
library(tseries)
prices_ts <- ts(prices, frequency = 252)
Explanation: This block loads the tseries package and converts the
extracted closing prices into a time series object using the ts()
function. The frequency is set to 252, which corresponds to the
approximate number of trading days in a year.
Benefit: Converting the data into a time series format allows us to
apply time series analysis techniques and models, such as ARIMA, which
are specifically designed for this type of data.
library(TTR)
ma20 <- SMA(prices, n = 20)
ma50 <- SMA(prices, n = 50)
Explanation: This code calculates the 20-day and 50-day simple moving
averages (SMA) using the SMA() function from the TTR package. Moving
averages smooth out price data, helping to identify trends by reducing
noise.
Benefit: The moving averages provide additional insight into the
stock’s price trends, making it easier to spot patterns such as upward
or downward trends. This is useful for both short-term and long-term
forecasting.
library(forecast)
fit <- auto.arima(prices_ts)
Explanation: This block loads the forecast package and automatically
fits an ARIMA model to the time series data using the auto.arima()
function.
Benefit: ARIMA models are powerful tools for time series forecasting.
The auto.arima() function simplifies the process by automatically
selecting the best parameters for the model, saving time and ensuring an
optimal fit.
forecast_prices <- forecast(fit, h = 30)
print(forecast_prices)
Explanation: This code uses the fitted ARIMA model to forecast
Tesla’s stock prices for the next 30 trading days. The forecast()
function produces point forecasts and confidence intervals.
Benefit: Forecasting future prices is crucial for making informed
investment decisions. This step provides us with predictive insights
into Tesla’s future stock performance, including potential risks and
opportunities.
# Plot the historical prices
plot(prices_ts, main = "ARIMA Forecast for TSLA Stock Prices", xlab = "Time", ylab = "Price", col = "blue", type = "l")
# Add the forecasted prices to the plot
lines(forecast_prices$fitted, col = "red", lty = 2)
# Add the forecast object to show the forecast and confidence intervals
lines(forecast_prices$mean, col = "green")
lines(forecast_prices$lower[,2], col = "orange")
lines(forecast_prices$upper[,2], col = "orange")

Explanation: This section of code creates a plot of the historical
stock prices using the plot() function. It then adds the fitted values
from the ARIMA model in red, the forecasted mean prices in green, and
the confidence intervals in orange.
Benefit: Visualizing the historical and forecasted prices together
helps us understand how well the model fits the historical data and what
future prices might look like. The confidence intervals provide a range
of likely values, helping us assess the uncertainty of the
forecasts.
# Convert to data frame for ggplot2
historical_prices <- data.frame(Date = index(prices), Price = coredata(prices))
ma20_df <- data.frame(Date = index(prices), MA20 = coredata(ma20))
ma50_df <- data.frame(Date = index(prices), MA50 = coredata(ma50))
# Forecast data preparation
forecast_dates <- seq(as.Date("2024-08-08"), by = "day", length.out = 30)
forecast_df <- data.frame(Date = forecast_dates,
Forecast = as.numeric(forecast_prices$mean),
Lower = as.numeric(forecast_prices$lower[,2]),
Upper = as.numeric(forecast_prices$upper[,2]))
library(ggplot2)
ggplot() +
geom_line(data = historical_prices, aes(x = Date, y = TSLA.Close), color = "blue") +
geom_line(data = ma20_df, aes(x = Date, y = ma20), color = "purple", linetype = "dashed") +
geom_line(data = ma50_df, aes(x = Date, y = ma50), color = "orange", linetype = "dashed") +
geom_line(data = forecast_df, aes(x = Date, y = Forecast), color = "red") +
geom_ribbon(data = forecast_df, aes(x = Date, ymin = Lower, ymax = Upper), fill = "green", alpha = 0.2) +
labs(title = "ARIMA Forecast for TSLA Stock Prices with Moving Averages", x = "Date", y = "Price") +
theme_minimal() +
theme(legend.position = "top")
Warning: Removed 19 rows containing missing values or values outside the scale range (`geom_line()`).
Warning: Removed 49 rows containing missing values or values outside the scale range (`geom_line()`).

Explanation: This section creates a more detailed plot using ggplot2.
It visualizes historical prices, moving averages (20-day and 50-day),
and forecasted prices with confidence intervals. Data frames are
prepared for ggplot2 to handle the data more effectively.
Benefit: This plot provides a comprehensive view of Tesla’s stock
performance, including historical trends, moving averages, and future
forecasts. It’s particularly useful for visualizing the interaction
between past performance and future predictions, allowing for better
analysis and decision-making.
accuracy(forecast_prices)
ME RMSE MAE MPE MAPE MASE ACF1
Training set 0.2229182 7.143882 5.268739 0.09118097 2.555366 0.1636046 0.01290762
Understanding the Metrics:
ME (Mean Error): Value: 0.2229182 Explanation: ME represents the
average of the errors (the difference between actual and predicted
values). A value close to 0 suggests that the predictions are relatively
unbiased. The positive value here indicates that, on average, the model
slightly underestimates the actual prices, but the bias is minimal.
RMSE (Root Mean Squared Error): Value: 7.143882 Explanation: RMSE
measures the square root of the average squared differences between
actual and predicted values. It’s sensitive to large errors, which can
heavily influence the overall accuracy. A lower RMSE value indicates
better accuracy, and the value here suggests that the model has a
reasonable overall error magnitude.
MAE (Mean Absolute Error): Value: 5.268739 Explanation: MAE is the
average of the absolute differences between actual and predicted values.
It’s a straightforward metric for understanding model accuracy, with a
lower value indicating better performance. Here, the MAE indicates that
the model’s predictions, on average, deviate by approximately 5.27 units
from the actual prices.
MPE (Mean Percentage Error): Value: 0.09118097 Explanation: MPE
represents the average of the percentage errors between actual and
predicted values. A positive MPE suggests that the model slightly
underestimates the actual values. The small positive value here shows
that the model’s bias is minimal.
MAPE (Mean Absolute Percentage Error): Value: 2.555366 Explanation:
MAPE is the average of the absolute percentage errors between actual and
predicted values. It’s a common metric for assessing forecasting
accuracy, with lower values indicating better performance. The MAPE of
2.555366% means that the model’s predictions are, on average, within
2.56% of the actual values, which indicates strong forecasting
accuracy.
MASE (Mean Absolute Scaled Error): Value: 0.1636046 Explanation: MASE
compares the model’s errors to those from a naive benchmark model. A
MASE value below 1 indicates that the model outperforms the naive model.
Here, the value of 0.1631641 suggests that the model performs
significantly better than the naive approach, which is a positive
outcome.
ACF1 (Autocorrelation of Errors at Lag 1): Value: 0.01290762
Explanation: ACF1 measures the correlation between forecast errors at
lag 1. If errors are independent, ACF1 should be close to 0. The value
here, 0.01468789, indicates that there is minimal autocorrelation in the
errors, which is desirable and suggests that the model’s errors are not
patterned or predictable.
Interpretation and Recommendations: Overall Model Performance: The
model performs well, with low RMSE and MAE values, indicating accurate
predictions. The minimal positive ME and MPE suggest that the model
slightly underestimates actual prices, but this bias is very small.
MAPE: The MAPE of 2.555366% indicates high accuracy, as the
predictions are typically within 2.56% of the actual values.
MASE: The MASE value of 0.1636046 demonstrates that the model
significantly outperforms a naive benchmark, indicating strong
performance.
ACF1: The low ACF1 value indicates that the forecast errors are
largely independent, which is a good sign for model reliability.
Conclusion: These metrics show that the ARIMA model used in this
project is effective and provides accurate forecasts with minimal bias
and error. This suggests that the model is reliable for short-term
forecasting, and further tuning may not be necessary unless we desire
more precision.
LS0tCnRpdGxlOiAiRmluYW5jaWFsIFRpbWUgU2VyaWVzIEZvcmVjYXN0aW5nIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCk9iamVjdGl2ZTogVGhlIHByaW1hcnkgZ29hbCBpcyB0byBmb3JlY2FzdCBmdXR1cmUgcHJpY2VzIG9mIFRlc2xhIChUU0xBKSBzdG9jayB1c2luZyB0aW1lIHNlcmllcyBhbmFseXNpcyB0ZWNobmlxdWVzLiBUaGlzIGluY2x1ZGVzIGZpdHRpbmcgYW4gQVJJTUEgbW9kZWwgdG8gaGlzdG9yaWNhbCBzdG9jayBwcmljZSBkYXRhIHRvIGdlbmVyYXRlIGZvcmVjYXN0cyBmb3IgdGhlIGZ1dHVyZSBwcmljZSBtb3ZlbWVudCBvZiB0aGUgc3RvY2suCgoKYGBge3J9Cmluc3RhbGwucGFja2FnZXMoYygicXVhbnRtb2QiLCAiZm9yZWNhc3QiLCAidHNlcmllcyIsICJUVFIiLCAiZ2dwbG90MiIsICJ0aWR5dmVyc2UiKSkKYGBgCkluc3RhbGxzIGFsbCBuZWNlc3NhcnkgcGFja2FnZXMuCgoKCgpgYGB7cn0KbGlicmFyeShxdWFudG1vZCkKZ2V0U3ltYm9scygiVFNMQSIsIGZyb20gPSAiMjAyMy0wMS0wMSIsIHRvID0gIjIwMjQtMTItMzEiKQpwcmljZXMgPC0gQ2woVFNMQSkKYGBgCkV4cGxhbmF0aW9uOiBUaGlzIGNvZGUgYmxvY2sgbG9hZHMgdGhlIHF1YW50bW9kIHBhY2thZ2UgYW5kIHJldHJpZXZlcyBoaXN0b3JpY2FsIHN0b2NrIHByaWNlIGRhdGEgZm9yIFRlc2xhIChUU0xBKSBmcm9tIEphbnVhcnkgMSwgMjAyMywgdG8gRGVjZW1iZXIgMzEsIDIwMjQuIFRoZSBnZXRTeW1ib2xzIGZ1bmN0aW9uIGRvd25sb2FkcyB0aGUgZGF0YSwgYW5kIHRoZSBDbCgpIGZ1bmN0aW9uIGV4dHJhY3RzIHRoZSBjbG9zaW5nIHByaWNlcy4KCkJlbmVmaXQ6IEJ5IGxvYWRpbmcgaGlzdG9yaWNhbCBwcmljZSBkYXRhLCB1cyBjYW4gcGVyZm9ybSB0aW1lIHNlcmllcyBhbmFseXNpcyBhbmQgZm9yZWNhc3Rpbmcgb24gcmVhbC13b3JsZCBzdG9jayBwcmljZXMsIG1ha2luZyB0aGUgYW5hbHlzaXMgbW9yZSByZWxldmFudCBhbmQgcHJhY3RpY2FsLgoKCgoKCmBgYHtyfQpsaWJyYXJ5KHRzZXJpZXMpCnByaWNlc190cyA8LSB0cyhwcmljZXMsIGZyZXF1ZW5jeSA9IDI1MikKYGBgCkV4cGxhbmF0aW9uOiBUaGlzIGJsb2NrIGxvYWRzIHRoZSB0c2VyaWVzIHBhY2thZ2UgYW5kIGNvbnZlcnRzIHRoZSBleHRyYWN0ZWQgY2xvc2luZyBwcmljZXMgaW50byBhIHRpbWUgc2VyaWVzIG9iamVjdCB1c2luZyB0aGUgdHMoKSBmdW5jdGlvbi4gVGhlIGZyZXF1ZW5jeSBpcyBzZXQgdG8gMjUyLCB3aGljaCBjb3JyZXNwb25kcyB0byB0aGUgYXBwcm94aW1hdGUgbnVtYmVyIG9mIHRyYWRpbmcgZGF5cyBpbiBhIHllYXIuCgpCZW5lZml0OiBDb252ZXJ0aW5nIHRoZSBkYXRhIGludG8gYSB0aW1lIHNlcmllcyBmb3JtYXQgYWxsb3dzIHVzIHRvIGFwcGx5IHRpbWUgc2VyaWVzIGFuYWx5c2lzIHRlY2huaXF1ZXMgYW5kIG1vZGVscywgc3VjaCBhcyBBUklNQSwgd2hpY2ggYXJlIHNwZWNpZmljYWxseSBkZXNpZ25lZCBmb3IgdGhpcyB0eXBlIG9mIGRhdGEuCgoKCgoKYGBge3J9CmxpYnJhcnkoVFRSKQptYTIwIDwtIFNNQShwcmljZXMsIG4gPSAyMCkKbWE1MCA8LSBTTUEocHJpY2VzLCBuID0gNTApCmBgYApFeHBsYW5hdGlvbjogVGhpcyBjb2RlIGNhbGN1bGF0ZXMgdGhlIDIwLWRheSBhbmQgNTAtZGF5IHNpbXBsZSBtb3ZpbmcgYXZlcmFnZXMgKFNNQSkgdXNpbmcgdGhlIFNNQSgpIGZ1bmN0aW9uIGZyb20gdGhlIFRUUiBwYWNrYWdlLiBNb3ZpbmcgYXZlcmFnZXMgc21vb3RoIG91dCBwcmljZSBkYXRhLCBoZWxwaW5nIHRvIGlkZW50aWZ5IHRyZW5kcyBieSByZWR1Y2luZyBub2lzZS4KCkJlbmVmaXQ6IFRoZSBtb3ZpbmcgYXZlcmFnZXMgcHJvdmlkZSBhZGRpdGlvbmFsIGluc2lnaHQgaW50byB0aGUgc3RvY2sncyBwcmljZSB0cmVuZHMsIG1ha2luZyBpdCBlYXNpZXIgdG8gc3BvdCBwYXR0ZXJucyBzdWNoIGFzIHVwd2FyZCBvciBkb3dud2FyZCB0cmVuZHMuIFRoaXMgaXMgdXNlZnVsIGZvciBib3RoIHNob3J0LXRlcm0gYW5kIGxvbmctdGVybSBmb3JlY2FzdGluZy4KCgoKCgoKCgpgYGB7cn0KbGlicmFyeShmb3JlY2FzdCkKZml0IDwtIGF1dG8uYXJpbWEocHJpY2VzX3RzKQpgYGAKRXhwbGFuYXRpb246IFRoaXMgYmxvY2sgbG9hZHMgdGhlIGZvcmVjYXN0IHBhY2thZ2UgYW5kIGF1dG9tYXRpY2FsbHkgZml0cyBhbiBBUklNQSBtb2RlbCB0byB0aGUgdGltZSBzZXJpZXMgZGF0YSB1c2luZyB0aGUgYXV0by5hcmltYSgpIGZ1bmN0aW9uLgoKQmVuZWZpdDogQVJJTUEgbW9kZWxzIGFyZSBwb3dlcmZ1bCB0b29scyBmb3IgdGltZSBzZXJpZXMgZm9yZWNhc3RpbmcuIFRoZSBhdXRvLmFyaW1hKCkgZnVuY3Rpb24gc2ltcGxpZmllcyB0aGUgcHJvY2VzcyBieSBhdXRvbWF0aWNhbGx5IHNlbGVjdGluZyB0aGUgYmVzdCBwYXJhbWV0ZXJzIGZvciB0aGUgbW9kZWwsIHNhdmluZyB0aW1lIGFuZCBlbnN1cmluZyBhbiBvcHRpbWFsIGZpdC4KCgoKCgoKCmBgYHtyfQpmb3JlY2FzdF9wcmljZXMgPC0gZm9yZWNhc3QoZml0LCBoID0gMzApCnByaW50KGZvcmVjYXN0X3ByaWNlcykKYGBgCkV4cGxhbmF0aW9uOiBUaGlzIGNvZGUgdXNlcyB0aGUgZml0dGVkIEFSSU1BIG1vZGVsIHRvIGZvcmVjYXN0IFRlc2xhJ3Mgc3RvY2sgcHJpY2VzIGZvciB0aGUgbmV4dCAzMCB0cmFkaW5nIGRheXMuIFRoZSBmb3JlY2FzdCgpIGZ1bmN0aW9uIHByb2R1Y2VzIHBvaW50IGZvcmVjYXN0cyBhbmQgY29uZmlkZW5jZSBpbnRlcnZhbHMuCgpCZW5lZml0OiBGb3JlY2FzdGluZyBmdXR1cmUgcHJpY2VzIGlzIGNydWNpYWwgZm9yIG1ha2luZyBpbmZvcm1lZCBpbnZlc3RtZW50IGRlY2lzaW9ucy4gVGhpcyBzdGVwIHByb3ZpZGVzIHVzIHdpdGggcHJlZGljdGl2ZSBpbnNpZ2h0cyBpbnRvIFRlc2xhJ3MgZnV0dXJlIHN0b2NrIHBlcmZvcm1hbmNlLCBpbmNsdWRpbmcgcG90ZW50aWFsIHJpc2tzIGFuZCBvcHBvcnR1bml0aWVzLgoKCgoKCgoKYGBge3J9CiMgUGxvdCB0aGUgaGlzdG9yaWNhbCBwcmljZXMKcGxvdChwcmljZXNfdHMsIG1haW4gPSAiQVJJTUEgRm9yZWNhc3QgZm9yIFRTTEEgU3RvY2sgUHJpY2VzIiwgeGxhYiA9ICJUaW1lIiwgeWxhYiA9ICJQcmljZSIsIGNvbCA9ICJibHVlIiwgdHlwZSA9ICJsIikKCiMgQWRkIHRoZSBmb3JlY2FzdGVkIHByaWNlcyB0byB0aGUgcGxvdApsaW5lcyhmb3JlY2FzdF9wcmljZXMkZml0dGVkLCBjb2wgPSAicmVkIiwgbHR5ID0gMikKCiMgQWRkIHRoZSBmb3JlY2FzdCBvYmplY3QgdG8gc2hvdyB0aGUgZm9yZWNhc3QgYW5kIGNvbmZpZGVuY2UgaW50ZXJ2YWxzCmxpbmVzKGZvcmVjYXN0X3ByaWNlcyRtZWFuLCBjb2wgPSAiZ3JlZW4iKQpsaW5lcyhmb3JlY2FzdF9wcmljZXMkbG93ZXJbLDJdLCBjb2wgPSAib3JhbmdlIikKbGluZXMoZm9yZWNhc3RfcHJpY2VzJHVwcGVyWywyXSwgY29sID0gIm9yYW5nZSIpCgpgYGAKRXhwbGFuYXRpb246IFRoaXMgc2VjdGlvbiBvZiBjb2RlIGNyZWF0ZXMgYSBwbG90IG9mIHRoZSBoaXN0b3JpY2FsIHN0b2NrIHByaWNlcyB1c2luZyB0aGUgcGxvdCgpIGZ1bmN0aW9uLiBJdCB0aGVuIGFkZHMgdGhlIGZpdHRlZCB2YWx1ZXMgZnJvbSB0aGUgQVJJTUEgbW9kZWwgaW4gcmVkLCB0aGUgZm9yZWNhc3RlZCBtZWFuIHByaWNlcyBpbiBncmVlbiwgYW5kIHRoZSBjb25maWRlbmNlIGludGVydmFscyBpbiBvcmFuZ2UuCgpCZW5lZml0OiBWaXN1YWxpemluZyB0aGUgaGlzdG9yaWNhbCBhbmQgZm9yZWNhc3RlZCBwcmljZXMgdG9nZXRoZXIgaGVscHMgdXMgdW5kZXJzdGFuZCBob3cgd2VsbCB0aGUgbW9kZWwgZml0cyB0aGUgaGlzdG9yaWNhbCBkYXRhIGFuZCB3aGF0IGZ1dHVyZSBwcmljZXMgbWlnaHQgbG9vayBsaWtlLiBUaGUgY29uZmlkZW5jZSBpbnRlcnZhbHMgcHJvdmlkZSBhIHJhbmdlIG9mIGxpa2VseSB2YWx1ZXMsIGhlbHBpbmcgdXMgYXNzZXNzIHRoZSB1bmNlcnRhaW50eSBvZiB0aGUgZm9yZWNhc3RzLgoKCgoKCgoKCmBgYHtyfQojIENvbnZlcnQgdG8gZGF0YSBmcmFtZSBmb3IgZ2dwbG90MgpoaXN0b3JpY2FsX3ByaWNlcyA8LSBkYXRhLmZyYW1lKERhdGUgPSBpbmRleChwcmljZXMpLCBQcmljZSA9IGNvcmVkYXRhKHByaWNlcykpCm1hMjBfZGYgPC0gZGF0YS5mcmFtZShEYXRlID0gaW5kZXgocHJpY2VzKSwgTUEyMCA9IGNvcmVkYXRhKG1hMjApKQptYTUwX2RmIDwtIGRhdGEuZnJhbWUoRGF0ZSA9IGluZGV4KHByaWNlcyksIE1BNTAgPSBjb3JlZGF0YShtYTUwKSkKCiMgRm9yZWNhc3QgZGF0YSBwcmVwYXJhdGlvbgpmb3JlY2FzdF9kYXRlcyA8LSBzZXEoYXMuRGF0ZSgiMjAyNC0wOC0wOCIpLCBieSA9ICJkYXkiLCBsZW5ndGgub3V0ID0gMzApCmZvcmVjYXN0X2RmIDwtIGRhdGEuZnJhbWUoRGF0ZSA9IGZvcmVjYXN0X2RhdGVzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgRm9yZWNhc3QgPSBhcy5udW1lcmljKGZvcmVjYXN0X3ByaWNlcyRtZWFuKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgTG93ZXIgPSBhcy5udW1lcmljKGZvcmVjYXN0X3ByaWNlcyRsb3dlclssMl0pLAogICAgICAgICAgICAgICAgICAgICAgICAgICBVcHBlciA9IGFzLm51bWVyaWMoZm9yZWNhc3RfcHJpY2VzJHVwcGVyWywyXSkpCmxpYnJhcnkoZ2dwbG90MikKCmdncGxvdCgpICsKICBnZW9tX2xpbmUoZGF0YSA9IGhpc3RvcmljYWxfcHJpY2VzLCBhZXMoeCA9IERhdGUsIHkgPSBUU0xBLkNsb3NlKSwgY29sb3IgPSAiYmx1ZSIpICsKICBnZW9tX2xpbmUoZGF0YSA9IG1hMjBfZGYsIGFlcyh4ID0gRGF0ZSwgeSA9IG1hMjApLCBjb2xvciA9ICJwdXJwbGUiLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBtYTUwX2RmLCBhZXMoeCA9IERhdGUsIHkgPSBtYTUwKSwgY29sb3IgPSAib3JhbmdlIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21fbGluZShkYXRhID0gZm9yZWNhc3RfZGYsIGFlcyh4ID0gRGF0ZSwgeSA9IEZvcmVjYXN0KSwgY29sb3IgPSAicmVkIikgKwogIGdlb21fcmliYm9uKGRhdGEgPSBmb3JlY2FzdF9kZiwgYWVzKHggPSBEYXRlLCB5bWluID0gTG93ZXIsIHltYXggPSBVcHBlciksIGZpbGwgPSAiZ3JlZW4iLCBhbHBoYSA9IDAuMikgKwogIGxhYnModGl0bGUgPSAiQVJJTUEgRm9yZWNhc3QgZm9yIFRTTEEgU3RvY2sgUHJpY2VzIHdpdGggTW92aW5nIEF2ZXJhZ2VzIiwgeCA9ICJEYXRlIiwgeSA9ICJQcmljZSIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQoKYGBgCkV4cGxhbmF0aW9uOiBUaGlzIHNlY3Rpb24gY3JlYXRlcyBhIG1vcmUgZGV0YWlsZWQgcGxvdCB1c2luZyBnZ3Bsb3QyLiBJdCB2aXN1YWxpemVzIGhpc3RvcmljYWwgcHJpY2VzLCBtb3ZpbmcgYXZlcmFnZXMgKDIwLWRheSBhbmQgNTAtZGF5KSwgYW5kIGZvcmVjYXN0ZWQgcHJpY2VzIHdpdGggY29uZmlkZW5jZSBpbnRlcnZhbHMuIERhdGEgZnJhbWVzIGFyZSBwcmVwYXJlZCBmb3IgZ2dwbG90MiB0byBoYW5kbGUgdGhlIGRhdGEgbW9yZSBlZmZlY3RpdmVseS4KCkJlbmVmaXQ6IFRoaXMgcGxvdCBwcm92aWRlcyBhIGNvbXByZWhlbnNpdmUgdmlldyBvZiBUZXNsYSdzIHN0b2NrIHBlcmZvcm1hbmNlLCBpbmNsdWRpbmcgaGlzdG9yaWNhbCB0cmVuZHMsIG1vdmluZyBhdmVyYWdlcywgYW5kIGZ1dHVyZSBmb3JlY2FzdHMuIEl04oCZcyBwYXJ0aWN1bGFybHkgdXNlZnVsIGZvciB2aXN1YWxpemluZyB0aGUgaW50ZXJhY3Rpb24gYmV0d2VlbiBwYXN0IHBlcmZvcm1hbmNlIGFuZCBmdXR1cmUgcHJlZGljdGlvbnMsIGFsbG93aW5nIGZvciBiZXR0ZXIgYW5hbHlzaXMgYW5kIGRlY2lzaW9uLW1ha2luZy4KCgoKCgpgYGB7cn0KYWNjdXJhY3koZm9yZWNhc3RfcHJpY2VzKQpgYGAKClVuZGVyc3RhbmRpbmcgdGhlIE1ldHJpY3M6CgpNRSAoTWVhbiBFcnJvcik6ClZhbHVlOiAwLjIyMjkxODIKRXhwbGFuYXRpb246IE1FIHJlcHJlc2VudHMgdGhlIGF2ZXJhZ2Ugb2YgdGhlIGVycm9ycyAodGhlIGRpZmZlcmVuY2UgYmV0d2VlbiBhY3R1YWwgYW5kIHByZWRpY3RlZCB2YWx1ZXMpLiBBIHZhbHVlIGNsb3NlIHRvIDAgc3VnZ2VzdHMgdGhhdCB0aGUgcHJlZGljdGlvbnMgYXJlIHJlbGF0aXZlbHkgdW5iaWFzZWQuIFRoZSBwb3NpdGl2ZSB2YWx1ZSBoZXJlIGluZGljYXRlcyB0aGF0LCBvbiBhdmVyYWdlLCB0aGUgbW9kZWwgc2xpZ2h0bHkgdW5kZXJlc3RpbWF0ZXMgdGhlIGFjdHVhbCBwcmljZXMsIGJ1dCB0aGUgYmlhcyBpcyBtaW5pbWFsLgoKUk1TRSAoUm9vdCBNZWFuIFNxdWFyZWQgRXJyb3IpOgpWYWx1ZTogNy4xNDM4ODIKRXhwbGFuYXRpb246IFJNU0UgbWVhc3VyZXMgdGhlIHNxdWFyZSByb290IG9mIHRoZSBhdmVyYWdlIHNxdWFyZWQgZGlmZmVyZW5jZXMgYmV0d2VlbiBhY3R1YWwgYW5kIHByZWRpY3RlZCB2YWx1ZXMuIEl0J3Mgc2Vuc2l0aXZlIHRvIGxhcmdlIGVycm9ycywgd2hpY2ggY2FuIGhlYXZpbHkgaW5mbHVlbmNlIHRoZSBvdmVyYWxsIGFjY3VyYWN5LiBBIGxvd2VyIFJNU0UgdmFsdWUgaW5kaWNhdGVzIGJldHRlciBhY2N1cmFjeSwgYW5kIHRoZSB2YWx1ZSBoZXJlIHN1Z2dlc3RzIHRoYXQgdGhlIG1vZGVsIGhhcyBhIHJlYXNvbmFibGUgb3ZlcmFsbCBlcnJvciBtYWduaXR1ZGUuCgpNQUUgKE1lYW4gQWJzb2x1dGUgRXJyb3IpOgpWYWx1ZTogNS4yNjg3MzkKRXhwbGFuYXRpb246IE1BRSBpcyB0aGUgYXZlcmFnZSBvZiB0aGUgYWJzb2x1dGUgZGlmZmVyZW5jZXMgYmV0d2VlbiBhY3R1YWwgYW5kIHByZWRpY3RlZCB2YWx1ZXMuIEl0J3MgYSBzdHJhaWdodGZvcndhcmQgbWV0cmljIGZvciB1bmRlcnN0YW5kaW5nIG1vZGVsIGFjY3VyYWN5LCB3aXRoIGEgbG93ZXIgdmFsdWUgaW5kaWNhdGluZyBiZXR0ZXIgcGVyZm9ybWFuY2UuIEhlcmUsIHRoZSBNQUUgaW5kaWNhdGVzIHRoYXQgdGhlIG1vZGVsJ3MgcHJlZGljdGlvbnMsIG9uIGF2ZXJhZ2UsIGRldmlhdGUgYnkgYXBwcm94aW1hdGVseSA1LjI3IHVuaXRzIGZyb20gdGhlIGFjdHVhbCBwcmljZXMuCgpNUEUgKE1lYW4gUGVyY2VudGFnZSBFcnJvcik6ClZhbHVlOiAwLjA5MTE4MDk3CkV4cGxhbmF0aW9uOiBNUEUgcmVwcmVzZW50cyB0aGUgYXZlcmFnZSBvZiB0aGUgcGVyY2VudGFnZSBlcnJvcnMgYmV0d2VlbiBhY3R1YWwgYW5kIHByZWRpY3RlZCB2YWx1ZXMuIEEgcG9zaXRpdmUgTVBFIHN1Z2dlc3RzIHRoYXQgdGhlIG1vZGVsIHNsaWdodGx5IHVuZGVyZXN0aW1hdGVzIHRoZSBhY3R1YWwgdmFsdWVzLiBUaGUgc21hbGwgcG9zaXRpdmUgdmFsdWUgaGVyZSBzaG93cyB0aGF0IHRoZSBtb2RlbCdzIGJpYXMgaXMgbWluaW1hbC4KCk1BUEUgKE1lYW4gQWJzb2x1dGUgUGVyY2VudGFnZSBFcnJvcik6ClZhbHVlOiAyLjU1NTM2NgpFeHBsYW5hdGlvbjogTUFQRSBpcyB0aGUgYXZlcmFnZSBvZiB0aGUgYWJzb2x1dGUgcGVyY2VudGFnZSBlcnJvcnMgYmV0d2VlbiBhY3R1YWwgYW5kIHByZWRpY3RlZCB2YWx1ZXMuIEl0J3MgYSBjb21tb24gbWV0cmljIGZvciBhc3Nlc3NpbmcgZm9yZWNhc3RpbmcgYWNjdXJhY3ksIHdpdGggbG93ZXIgdmFsdWVzIGluZGljYXRpbmcgYmV0dGVyIHBlcmZvcm1hbmNlLiBUaGUgTUFQRSBvZiAyLjU1NTM2NiUgbWVhbnMgdGhhdCB0aGUgbW9kZWwncyBwcmVkaWN0aW9ucyBhcmUsIG9uIGF2ZXJhZ2UsIHdpdGhpbiAyLjU2JSBvZiB0aGUgYWN0dWFsIHZhbHVlcywgd2hpY2ggaW5kaWNhdGVzIHN0cm9uZyBmb3JlY2FzdGluZyBhY2N1cmFjeS4KCk1BU0UgKE1lYW4gQWJzb2x1dGUgU2NhbGVkIEVycm9yKToKVmFsdWU6IDAuMTYzNjA0NgpFeHBsYW5hdGlvbjogTUFTRSBjb21wYXJlcyB0aGUgbW9kZWwncyBlcnJvcnMgdG8gdGhvc2UgZnJvbSBhIG5haXZlIGJlbmNobWFyayBtb2RlbC4gQSBNQVNFIHZhbHVlIGJlbG93IDEgaW5kaWNhdGVzIHRoYXQgdGhlIG1vZGVsIG91dHBlcmZvcm1zIHRoZSBuYWl2ZSBtb2RlbC4gSGVyZSwgdGhlIHZhbHVlIG9mIDAuMTYzMTY0MSBzdWdnZXN0cyB0aGF0IHRoZSBtb2RlbCBwZXJmb3JtcyBzaWduaWZpY2FudGx5IGJldHRlciB0aGFuIHRoZSBuYWl2ZSBhcHByb2FjaCwgd2hpY2ggaXMgYSBwb3NpdGl2ZSBvdXRjb21lLgoKQUNGMSAoQXV0b2NvcnJlbGF0aW9uIG9mIEVycm9ycyBhdCBMYWcgMSk6ClZhbHVlOiAwLjAxMjkwNzYyCkV4cGxhbmF0aW9uOiBBQ0YxIG1lYXN1cmVzIHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIGZvcmVjYXN0IGVycm9ycyBhdCBsYWcgMS4gSWYgZXJyb3JzIGFyZSBpbmRlcGVuZGVudCwgQUNGMSBzaG91bGQgYmUgY2xvc2UgdG8gMC4gVGhlIHZhbHVlIGhlcmUsIDAuMDE0Njg3ODksIGluZGljYXRlcyB0aGF0IHRoZXJlIGlzIG1pbmltYWwgYXV0b2NvcnJlbGF0aW9uIGluIHRoZSBlcnJvcnMsIHdoaWNoIGlzIGRlc2lyYWJsZSBhbmQgc3VnZ2VzdHMgdGhhdCB0aGUgbW9kZWwncyBlcnJvcnMgYXJlIG5vdCBwYXR0ZXJuZWQgb3IgcHJlZGljdGFibGUuCgpJbnRlcnByZXRhdGlvbiBhbmQgUmVjb21tZW5kYXRpb25zOgpPdmVyYWxsIE1vZGVsIFBlcmZvcm1hbmNlOiBUaGUgbW9kZWwgcGVyZm9ybXMgd2VsbCwgd2l0aCBsb3cgUk1TRSBhbmQgTUFFIHZhbHVlcywgaW5kaWNhdGluZyBhY2N1cmF0ZSBwcmVkaWN0aW9ucy4gVGhlIG1pbmltYWwgcG9zaXRpdmUgTUUgYW5kIE1QRSBzdWdnZXN0IHRoYXQgdGhlIG1vZGVsIHNsaWdodGx5IHVuZGVyZXN0aW1hdGVzIGFjdHVhbCBwcmljZXMsIGJ1dCB0aGlzIGJpYXMgaXMgdmVyeSBzbWFsbC4KCk1BUEU6IFRoZSBNQVBFIG9mIDIuNTU1MzY2JSBpbmRpY2F0ZXMgaGlnaCBhY2N1cmFjeSwgYXMgdGhlIHByZWRpY3Rpb25zIGFyZSB0eXBpY2FsbHkgd2l0aGluIDIuNTYlIG9mIHRoZSBhY3R1YWwgdmFsdWVzLgoKTUFTRTogVGhlIE1BU0UgdmFsdWUgb2YgMC4xNjM2MDQ2IGRlbW9uc3RyYXRlcyB0aGF0IHRoZSBtb2RlbCBzaWduaWZpY2FudGx5IG91dHBlcmZvcm1zIGEgbmFpdmUgYmVuY2htYXJrLCBpbmRpY2F0aW5nIHN0cm9uZyBwZXJmb3JtYW5jZS4KCkFDRjE6IFRoZSBsb3cgQUNGMSB2YWx1ZSBpbmRpY2F0ZXMgdGhhdCB0aGUgZm9yZWNhc3QgZXJyb3JzIGFyZSBsYXJnZWx5IGluZGVwZW5kZW50LCB3aGljaCBpcyBhIGdvb2Qgc2lnbiBmb3IgbW9kZWwgcmVsaWFiaWxpdHkuCgpDb25jbHVzaW9uOgpUaGVzZSBtZXRyaWNzIHNob3cgdGhhdCB0aGUgQVJJTUEgbW9kZWwgdXNlZCBpbiB0aGlzIHByb2plY3QgaXMgZWZmZWN0aXZlIGFuZCBwcm92aWRlcyBhY2N1cmF0ZSBmb3JlY2FzdHMgd2l0aCBtaW5pbWFsIGJpYXMgYW5kIGVycm9yLiBUaGlzIHN1Z2dlc3RzIHRoYXQgdGhlIG1vZGVsIGlzIHJlbGlhYmxlIGZvciBzaG9ydC10ZXJtIGZvcmVjYXN0aW5nLCBhbmQgZnVydGhlciB0dW5pbmcgbWF5IG5vdCBiZSBuZWNlc3NhcnkgdW5sZXNzIHdlIGRlc2lyZSBtb3JlIHByZWNpc2lvbi4K