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