To get started, let’s first talk about what are stocks and what is S&P 500?

In short terms, a stock is a small piece of ownership in a company. When you buy a stock, you own a share of that company. If the company does well, your stock’s value may go up — and you might earn money. If the company does poorly, the value can go down.

What is S&P 500? The Standard and Poor’s 500, or simply the S&P 500, is a stock market index tracking the stock performance of 500 leading companies listed on stock exchanges in the United States.It is one of the most commonly followed equity indices and includes approximately 80% of the total market capitalization of U.S. public companies. In better terms, it is like a report card for the United States Stock Market by showing how big, important companies are doing overall in finance. It only tracks the top 500 largest publicly traded Companies in the USA. (Source: Wikipedia 2025)

📉 Major S&P 500 Crashes (Summary)

Year Name Drop Cause
1929 Great Depression ~86% Stock bubble burst
1987 Black Monday -20% (1 day) Panic + computer trading
2000 Dot-Com Crash ~49% Tech bubble burst
2008 Financial Crisis ~57% Housing + bank collapse
2020 COVID Crash ~34% Pandemic panic
2022 Inflation Bear Market ~25% Inflation + interest rates
2025 Tariff Crash ~0.75% President Trump’s extreme tariffs

Goal for this project: The objective of this analysis is to explore the relationships between financial indicators (e.g., revenue growth, market capitalization, sector classification) and stock performance (e.g., current price) of companies in the S&P 500. Specifically, we aim to identify which company attributes are most strongly associated with higher stock valuations and to evaluate the predictive power of select features using logistic regression and ROC analysis.

First we will install the package containing the dataset.

#install.packages("palmerpenguins")
install.packages("GGally")

We will now load the dataset, and necessary libraries.

data("sp500")
SP500 <- na.omit("sp500")
library(tidyverse)
library(ggplot2)
library(GGally)

Let us take a look at the top 10 companies with the highest revenue. According to the chart and the bar graph, you can see that the Company “NVR”, founded in 1980 by Dwight Schar, currently has the highest revenue in S&P 500. NVR is considered one of America’s leading homebuilders in the East. They operate in 2 business segments which is homebuilding and mortgage banking. The homebuilding unit sells and constructs homes under the Ryan Homes, NVHomes, and Heartland Homes brands.

# Order dataset by Currentprice descending, then take top 10 rows
top10_companies <- sp500[order(-sp500$Currentprice), ][1:10, ]

# View the result
print(top10_companies)

stocks <- data.frame(
  company = c("NVR", "BKNG", "AZO", "FICO", "TDG", "MTD", "ORLY", "TPL", "GWW", "NOW"),
  price = c(8276.28, 5048.59, 3253.47, 2090.98, 1276.15, 1230.74, 1219.11, 1133.12, 1092.96, 1091.25)
)

top_stocks <- stocks %>%
  arrange(desc(price)) %>%
  head(10)

ggplot(top_stocks, aes(x = reorder(company, price), y = price, fill = company)) +
  geom_bar(stat = "identity") +
  coord_flip() +  # horizontal bars for readability
  labs(title = "Top 10 Stock Prices", x = "Symbol", y = "Current Price") +
  theme_minimal()

This scatter plot illustrates the relationship between revenue growth and the current stock price of companies within the S&P 500 index. Each point represents a company, with its position determined by its revenue growth rate on one axis and its current stock price on the other. This visualization helps identify patterns or correlations between how much a company’s revenue is increasing and how the market is currently valuing its stock.

ggplot(sp500, aes(x = Revenuegrowth, y = Currentprice)) +
  geom_point() +
  labs(title = "Scatterplot of Current Price vs Revenue Growth",
       x = "Revenue growth",
       y = "Currentprice")
Warning: Removed 3 rows containing missing values or values outside the
scale range (`geom_point()`).

Now, let us look and visualize the S&P 500 Revenue Growth using a boxplot! The S&P 500 revenue growth measures the percentage change in total sales of the companies within the S&P 500 index. It reflects the collective sales performance of these large-cap U.S. companies and is a key indicator of the overall health and shows a significant growth to the United States Economy.

ggplot(sp500)+
  aes(`Revenuegrowth`)+
  geom_boxplot() 
Warning: Removed 3 rows containing non-finite outside the scale range
(`stat_boxplot()`).

Let’s take a look at all the Exchanges for S&P 500. According to the results, you can see that NYQ(New York Quarterly) is the highest out of all exchanges.

sp500 %>%
  count(Exchange, sort = TRUE) %>%
  head(4)

Let us visualize the Sector in S&P 500. For those who don’t know what it does, The S&P 500 sectors represent groupings of companies within the S&P 500 index that are categorized by their primary industry or business activity. These sectors allow investors to analyze and track the performance of specific industries within the broader market, and to potentially make more targeted investments

ggplot(sp500)+
  aes(`Sector`)+
  geom_bar() +
 theme(axis.text.x = element_text(angle = 45, hjust = 1))

According to Yahoo Finance, This is the entire stock market starting from November 1996 till today! As you know, it was originated in 1923. You will get data from 1996 because thats when the dot-com buble ballooned during the late 1990s.(TIP: When Yahoo Finance updates the stock market, the stock market shown in the Preview on Posit will also update if you keep running it every month!).

library(quantmod)  # For downloading financial data
Loading required package: xts
Loading required package: zoo

Attaching package: ‘zoo’

The following objects are masked from ‘package:base’:

    as.Date, as.Date.numeric


######################### Warning from 'xts' package ##########################
#                                                                             #
# The dplyr lag() function breaks how base R's lag() function is supposed to  #
# work, which breaks lag(my_xts). Calls to lag(my_xts) that you type or       #
# source() into this session won't work correctly.                            #
#                                                                             #
# Use stats::lag() to make sure you're not using dplyr::lag(), or you can add #
# conflictRules('dplyr', exclude = 'lag') to your .Rprofile to stop           #
# dplyr from breaking base R's lag() function.                                #
#                                                                             #
# Code in packages is not affected. It's protected by R's namespace mechanism #
# Set `options(xts.warn_dplyr_breaks_lag = FALSE)` to suppress this warning.  #
#                                                                             #
###############################################################################

Attaching package: ‘xts’

The following objects are masked from ‘package:dplyr’:

    first, last

Loading required package: TTR
Registered S3 method overwritten by 'quantmod':
  method            from
  as.zoo.data.frame zoo 
library(ggplot2)

start_date <- "1996-11-22"
end_date <- "2025-12-31" 

# Download S&P 500 data (using its common ticker symbol ^GSPC)
# The quantmod package can download data from sources like Yahoo Finance
getSymbols("^GSPC", src = "yahoo", from = start_date, to = end_date, auto.assign = TRUE) #
[1] "GSPC"
# You'll now have a time series object named 'GSPC' in your R environment

# Convert the xts object to a data frame for use with ggplot2
GSPC_df <- data.frame(Date = index(GSPC), coredata(GSPC))

# Rename the columns to something more convenient
colnames(GSPC_df) <- c("Date", "Open", "High", "Low", "Close", "Volume", "Adjusted")

# Create a line chart of the S&P 500 closing price
ggplot(GSPC_df, aes(x = Date, y = Close)) +
  geom_line() + # Create the line chart
  labs(
    title = "S&P 500 Closing Price in 2025",
    x = "Date(Months)",
    y = "Closing Price"
  ) +
  theme_minimal() 

You can notice on the stock chart that it crashed on early April due to President Trump’s extensive tariffs. While the S&P 500 did rebound later in Mid April, the initial downturn on April 7th and the preceding days was a direct consequence of President Trump’s tariff policies and the resulting market panic.

Now, let us see what companies are investing from which country! You can see that about 93% of the companies investing in S&P 500 are USA Based companies.

ggplot(sp500, aes(Country)) +
  geom_bar() +
  theme(axis.text.x = element_text(angle = 55, hjust = 1)) +
  geom_text(stat = "count", 
            aes(label = after_stat(count)),
            vjust = -0.25
  )

This bar graph helps us know what state is each company from that is in the top 500 for S&P 500. I used theme and rotated the text to prevent it from overlapping with each other.

ggplot(sp500, aes(State)) +
  geom_bar() +
  theme(axis.text.x = element_text(angle = 55, hjust = 1)) 

The ROC Curve tells us the # of true positives and false positive rate for the logistic regression model as the threshold changes. It tells how your model does for categorizing the data.

# Install the following packages for all these lines of code to work
library(rsample)
library(brglm2)
library(caret)
Loading required package: lattice

Attaching package: ‘caret’

The following object is masked from ‘package:purrr’:

    lift
library(pROC)
Type 'citation("pROC")' for a citation.

Attaching package: ‘pROC’

The following objects are masked from ‘package:stats’:

    cov, smooth, var
# Create a Categorical Variable
sp500 <- sp500 %>%
  mutate(Tech = if_else(Sector %in% c("Technology"), "1", "0" ))

# Splitting the Data into Train and Test Data
set.seed(123)
split <- initial_split(sp500, prop = 0.5, strata = Exchange)

train_data <- training(split)
test_data <- testing(split)

# Fitting the Logistic Regression
model <- glm(as.factor(Tech) ~ as.factor(Exchange), data = train_data, family = "binomial", method = "brglmFit")
Warning: brglmFit: algorithm did not converge. Try changing the optimization algorithm defaults, e.g. the defaults for one or more of `maxit`, `epsilon`, `slowit`, and `response_adjustment`; see `?brglm_control` for default values and available options
Warning: brglmFit: fitted probabilities numerically 0 or 1 occurred
# Testing the Logistic Regression Model
test_data$predicted_prob <- predict(model, newdata = test_data, type = "response")
test_data$predicted_class <- ifelse(test_data$predicted_prob > 0.5, 1, 0)

test_data$actual <- factor(test_data$Tech)
test_data$predicted_class <- factor(test_data$predicted_class)

# Confusion Matrix (Evaluates the Model and seeing how it does)
confusionMatrix(test_data$predicted_class, test_data$actual)
Warning in confusionMatrix.default(test_data$predicted_class, test_data$actual) :
  Levels are not in the same order for reference and data. Refactoring data to match.
Confusion Matrix and Statistics

          Reference
Prediction   0   1
         0 216  35
         1   0   0
                                          
               Accuracy : 0.8606          
                 95% CI : (0.8114, 0.9009)
    No Information Rate : 0.8606          
    P-Value [Acc > NIR] : 0.5449          
                                          
                  Kappa : 0               
                                          
 Mcnemar's Test P-Value : 9.081e-09       
                                          
            Sensitivity : 1.0000          
            Specificity : 0.0000          
         Pos Pred Value : 0.8606          
         Neg Pred Value :    NaN          
             Prevalence : 0.8606          
         Detection Rate : 0.8606          
   Detection Prevalence : 1.0000          
      Balanced Accuracy : 0.5000          
                                          
       'Positive' Class : 0               
                                          
roc_obj <- roc(test_data$actual, test_data$predicted_prob)
Setting levels: control = 0, case = 1
Setting direction: controls < cases
plot(roc_obj, main = "ROC Curve")

Finally, concluding our analysis of the S&P 500 2025 Stock Market, here is a linear regression model. A linear regression model is used as a way to find the best-fitting straight line through a set of data points In order for your regression model to work, you will need to have 2 numerical variables. In this scenario, I have Revenue Growth and Market Cap. It will help predict future values of something based on related factors and understands how 1 variable changes as another increases or decreases. In your Y-Axis, you have a market cap. For example, The 1e+12 for example means 1 trillion but in scientific notation.

model <- lm(Marketcap ~ Revenuegrowth, data = sp500) 
summary(model)

Call:
lm(formula = Marketcap ~ Revenuegrowth, data = sp500)

Residuals:
       Min         1Q     Median         3Q        Max 
-5.740e+11 -8.529e+10 -6.263e+10 -2.039e+10  3.739e+12 

Coefficients:
               Estimate Std. Error t value Pr(>|t|)    
(Intercept)   8.866e+10  1.638e+10   5.413 9.64e-08 ***
Revenuegrowth 3.143e+11  8.469e+10   3.712 0.000229 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 3.407e+11 on 497 degrees of freedom
  (3 observations deleted due to missingness)
Multiple R-squared:  0.02697,   Adjusted R-squared:  0.02501 
F-statistic: 13.78 on 1 and 497 DF,  p-value: 0.0002293
library(ggplot2)

ggplot(sp500, aes(x = Revenuegrowth, y = Marketcap)) +
  geom_point(position = position_jitter(width = 0.2), alpha = 0.6) +
  geom_smooth(method = "lm", se = TRUE, color = "turquoise", size = 1) +
  labs(title = "Linear Regression: Market Cap vs Revenue Growth") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))
`geom_smooth()` using formula = 'y ~ x'
Warning: Removed 3 rows containing non-finite outside the scale range
(`stat_smooth()`).
Warning: Removed 3 rows containing missing values or values outside the
scale range (`geom_point()`).

Today, Data science helps investors, analysts, and companies understand, track, and predict the performance of the S&P 500. And R is a powerful tool used to do that analysis by analyzing trends, making predictions of the stock chart, Portfolio Optimization, and lastly, risk management.

Thanks for listening! Hope this helps you understand mostly about the S&P 500 and stocks!

Made by Sid

LS0tCnRpdGxlOiAiUyZQIDUwMCAyMDI1IFN0b2NrIFVwZGF0ZSIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKVG8gZ2V0IHN0YXJ0ZWQsIGxldCdzIGZpcnN0IHRhbGsgYWJvdXQgd2hhdCBhcmUgc3RvY2tzIGFuZCB3aGF0IGlzIFMmUCA1MDA/CgogSW4gc2hvcnQgdGVybXMsIGEgc3RvY2sgaXMgYSBzbWFsbCBwaWVjZSBvZiBvd25lcnNoaXAgaW4gYSBjb21wYW55LiBXaGVuIHlvdSBidXkgYSBzdG9jaywgeW91IG93biBhIHNoYXJlIG9mIHRoYXQgY29tcGFueS4gSWYgdGhlIGNvbXBhbnkgZG9lcyB3ZWxsLCB5b3VyIHN0b2NrJ3MgdmFsdWUgbWF5IGdvIHVwIOKAlCBhbmQgeW91IG1pZ2h0IGVhcm4gbW9uZXkuIElmIHRoZSBjb21wYW55IGRvZXMgcG9vcmx5LCB0aGUgdmFsdWUgY2FuIGdvIGRvd24uIAoKV2hhdCBpcyBTJlAgNTAwPyBUaGUgU3RhbmRhcmQgYW5kIFBvb3IncyA1MDAsIG9yIHNpbXBseSB0aGUgUyZQIDUwMCwgaXMgYSBzdG9jayBtYXJrZXQgaW5kZXggdHJhY2tpbmcgdGhlIHN0b2NrIHBlcmZvcm1hbmNlIG9mIDUwMCBsZWFkaW5nIGNvbXBhbmllcyBsaXN0ZWQgb24gc3RvY2sgZXhjaGFuZ2VzIGluIHRoZSBVbml0ZWQgU3RhdGVzLkl0IGlzIG9uZSBvZiB0aGUgbW9zdCBjb21tb25seSBmb2xsb3dlZCBlcXVpdHkgaW5kaWNlcyBhbmQgaW5jbHVkZXMgYXBwcm94aW1hdGVseSA4MCUgb2YgdGhlIHRvdGFsIG1hcmtldCBjYXBpdGFsaXphdGlvbiBvZiBVLlMuIHB1YmxpYyBjb21wYW5pZXMuIEluIGJldHRlciB0ZXJtcywgaXQgaXMgbGlrZSBhIHJlcG9ydCBjYXJkIGZvciB0aGUgVW5pdGVkIFN0YXRlcyBTdG9jayBNYXJrZXQgYnkgc2hvd2luZyBob3cgYmlnLCBpbXBvcnRhbnQgY29tcGFuaWVzIGFyZSBkb2luZyBvdmVyYWxsIGluIGZpbmFuY2UuIEl0IG9ubHkgdHJhY2tzIHRoZSB0b3AgNTAwIGxhcmdlc3QgcHVibGljbHkgdHJhZGVkIENvbXBhbmllcyBpbiB0aGUgVVNBLiAoU291cmNlOiBXaWtpcGVkaWEgMjAyNSkKCiMg8J+TiSBNYWpvciBTJlAgNTAwIENyYXNoZXMgKFN1bW1hcnkpCgp8IFllYXIgfCBOYW1lICAgICAgICAgICAgICAgICAgfCBEcm9wICAgICAgICAgfCBDYXVzZSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8IC0tLS0gfCAtLS0tLS0tLS0tLS0tLS0tLS0tLS0gfCAtLS0tLS0tLS0tLS0gfCAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gfAp8IDE5MjkgfCBHcmVhdCBEZXByZXNzaW9uICAgICAgfCBcfjg2JSAgICAgICAgfCBTdG9jayBidWJibGUgYnVyc3QgICAgICAgICAgICAgICAgfAp8IDE5ODcgfCBCbGFjayBNb25kYXkgICAgICAgICAgfCAtMjAlICgxIGRheSkgfCBQYW5pYyArIGNvbXB1dGVyIHRyYWRpbmcgICAgICAgICAgfAp8IDIwMDAgfCBEb3QtQ29tIENyYXNoICAgICAgICAgfCBcfjQ5JSAgICAgICAgfCBUZWNoIGJ1YmJsZSBidXJzdCAgICAgICAgICAgICAgICAgfAp8IDIwMDggfCBGaW5hbmNpYWwgQ3Jpc2lzICAgICAgfCBcfjU3JSAgICAgICAgfCBIb3VzaW5nICsgYmFuayBjb2xsYXBzZSAgICAgICAgICAgfAp8IDIwMjAgfCBDT1ZJRCBDcmFzaCAgICAgICAgICAgfCBcfjM0JSAgICAgICAgfCBQYW5kZW1pYyBwYW5pYyAgICAgICAgICAgICAgICAgICAgfAp8IDIwMjIgfCBJbmZsYXRpb24gQmVhciBNYXJrZXQgfCBcfjI1JSAgICAgICAgfCBJbmZsYXRpb24gKyBpbnRlcmVzdCByYXRlcyAgICAgICAgfAp8IDIwMjUgfCBUYXJpZmYgQ3Jhc2ggICAgICAgICAgfCBcfjAuNzUlICAgICAgfCBQcmVzaWRlbnQgVHJ1bXDigJlzIGV4dHJlbWUgdGFyaWZmcyB8CgpHb2FsIGZvciB0aGlzIHByb2plY3Q6IFRoZSBvYmplY3RpdmUgb2YgdGhpcyBhbmFseXNpcyBpcyB0byBleHBsb3JlIHRoZSByZWxhdGlvbnNoaXBzIGJldHdlZW4gZmluYW5jaWFsIGluZGljYXRvcnMgKGUuZy4sIHJldmVudWUgZ3Jvd3RoLCBtYXJrZXQgY2FwaXRhbGl6YXRpb24sIHNlY3RvciBjbGFzc2lmaWNhdGlvbikgYW5kIHN0b2NrIHBlcmZvcm1hbmNlIChlLmcuLCBjdXJyZW50IHByaWNlKSBvZiBjb21wYW5pZXMgaW4gdGhlIFMmUCA1MDAuIFNwZWNpZmljYWxseSwgd2UgYWltIHRvIGlkZW50aWZ5IHdoaWNoIGNvbXBhbnkgYXR0cmlidXRlcyBhcmUgbW9zdCBzdHJvbmdseSBhc3NvY2lhdGVkIHdpdGggaGlnaGVyIHN0b2NrIHZhbHVhdGlvbnMgYW5kIHRvIGV2YWx1YXRlIHRoZSBwcmVkaWN0aXZlIHBvd2VyIG9mIHNlbGVjdCBmZWF0dXJlcyB1c2luZyBsb2dpc3RpYyByZWdyZXNzaW9uIGFuZCBST0MgYW5hbHlzaXMuCgpGaXJzdCB3ZSB3aWxsIGluc3RhbGwgdGhlIHBhY2thZ2UgY29udGFpbmluZyB0aGUgZGF0YXNldC4gCgpgYGB7cn0KI2luc3RhbGwucGFja2FnZXMoInBhbG1lcnBlbmd1aW5zIikKaW5zdGFsbC5wYWNrYWdlcygiR0dhbGx5IikKYGBgCldlIHdpbGwgbm93IGxvYWQgdGhlIGRhdGFzZXQsIGFuZCBuZWNlc3NhcnkgbGlicmFyaWVzLiAKYGBge3J9CmRhdGEoInNwNTAwIikKU1A1MDAgPC0gbmEub21pdCgic3A1MDAiKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KEdHYWxseSkKYGBgCgpMZXQgdXMgdGFrZSBhIGxvb2sgYXQgdGhlIHRvcCAxMCBjb21wYW5pZXMgd2l0aCB0aGUgaGlnaGVzdCByZXZlbnVlLiBBY2NvcmRpbmcgdG8gdGhlIGNoYXJ0IGFuZCB0aGUgYmFyIGdyYXBoLCB5b3UgY2FuIHNlZSB0aGF0IHRoZSBDb21wYW55ICJOVlIiLCBmb3VuZGVkIGluIDE5ODAgYnkgRHdpZ2h0IFNjaGFyLCBjdXJyZW50bHkgaGFzIHRoZSBoaWdoZXN0IHJldmVudWUgaW4gUyZQIDUwMC4gTlZSIGlzIGNvbnNpZGVyZWQgb25lIG9mIEFtZXJpY2EncyBsZWFkaW5nIGhvbWVidWlsZGVycyBpbiB0aGUgRWFzdC4gVGhleSBvcGVyYXRlIGluIDIgYnVzaW5lc3Mgc2VnbWVudHMgd2hpY2ggaXMgaG9tZWJ1aWxkaW5nIGFuZCBtb3J0Z2FnZSBiYW5raW5nLiBUaGUgaG9tZWJ1aWxkaW5nIHVuaXQgc2VsbHMgYW5kIGNvbnN0cnVjdHMgaG9tZXMgdW5kZXIgdGhlIFJ5YW4gSG9tZXMsIE5WSG9tZXMsIGFuZCBIZWFydGxhbmQgSG9tZXMgYnJhbmRzLgpgYGB7cn0KIyBPcmRlciBkYXRhc2V0IGJ5IEN1cnJlbnRwcmljZSBkZXNjZW5kaW5nLCB0aGVuIHRha2UgdG9wIDEwIHJvd3MKdG9wMTBfY29tcGFuaWVzIDwtIHNwNTAwW29yZGVyKC1zcDUwMCRDdXJyZW50cHJpY2UpLCBdWzE6MTAsIF0KCiMgVmlldyB0aGUgcmVzdWx0CnByaW50KHRvcDEwX2NvbXBhbmllcykKYGBgCmBgYHtyfQoKc3RvY2tzIDwtIGRhdGEuZnJhbWUoCiAgY29tcGFueSA9IGMoIk5WUiIsICJCS05HIiwgIkFaTyIsICJGSUNPIiwgIlRERyIsICJNVEQiLCAiT1JMWSIsICJUUEwiLCAiR1dXIiwgIk5PVyIpLAogIHByaWNlID0gYyg4Mjc2LjI4LCA1MDQ4LjU5LCAzMjUzLjQ3LCAyMDkwLjk4LCAxMjc2LjE1LCAxMjMwLjc0LCAxMjE5LjExLCAxMTMzLjEyLCAxMDkyLjk2LCAxMDkxLjI1KQopCgp0b3Bfc3RvY2tzIDwtIHN0b2NrcyAlPiUKICBhcnJhbmdlKGRlc2MocHJpY2UpKSAlPiUKICBoZWFkKDEwKQoKZ2dwbG90KHRvcF9zdG9ja3MsIGFlcyh4ID0gcmVvcmRlcihjb21wYW55LCBwcmljZSksIHkgPSBwcmljZSwgZmlsbCA9IGNvbXBhbnkpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsKICBjb29yZF9mbGlwKCkgKyAgIyBob3Jpem9udGFsIGJhcnMgZm9yIHJlYWRhYmlsaXR5CiAgbGFicyh0aXRsZSA9ICJUb3AgMTAgU3RvY2sgUHJpY2VzIiwgeCA9ICJTeW1ib2wiLCB5ID0gIkN1cnJlbnQgUHJpY2UiKSArCiAgdGhlbWVfbWluaW1hbCgpCmBgYApUaGlzIHNjYXR0ZXIgcGxvdCBpbGx1c3RyYXRlcyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gcmV2ZW51ZSBncm93dGggYW5kIHRoZSBjdXJyZW50IHN0b2NrIHByaWNlIG9mIGNvbXBhbmllcyB3aXRoaW4gdGhlIFMmUCA1MDAgaW5kZXguIEVhY2ggcG9pbnQgcmVwcmVzZW50cyBhIGNvbXBhbnksIHdpdGggaXRzIHBvc2l0aW9uIGRldGVybWluZWQgYnkgaXRzIHJldmVudWUgZ3Jvd3RoIHJhdGUgb24gb25lIGF4aXMgYW5kIGl0cyBjdXJyZW50IHN0b2NrIHByaWNlIG9uIHRoZSBvdGhlci4gVGhpcyB2aXN1YWxpemF0aW9uIGhlbHBzIGlkZW50aWZ5IHBhdHRlcm5zIG9yIGNvcnJlbGF0aW9ucyBiZXR3ZWVuIGhvdyBtdWNoIGEgY29tcGFueSdzIHJldmVudWUgaXMgaW5jcmVhc2luZyBhbmQgaG93IHRoZSBtYXJrZXQgaXMgY3VycmVudGx5IHZhbHVpbmcgaXRzIHN0b2NrLgpgYGB7cn0KZ2dwbG90KHNwNTAwLCBhZXMoeCA9IFJldmVudWVncm93dGgsIHkgPSBDdXJyZW50cHJpY2UpKSArCiAgZ2VvbV9wb2ludCgpICsKICBsYWJzKHRpdGxlID0gIlNjYXR0ZXJwbG90IG9mIEN1cnJlbnQgUHJpY2UgdnMgUmV2ZW51ZSBHcm93dGgiLAogICAgICAgeCA9ICJSZXZlbnVlIGdyb3d0aCIsCiAgICAgICB5ID0gIkN1cnJlbnRwcmljZSIpCmBgYApOb3csIGxldCB1cyBsb29rIGFuZCB2aXN1YWxpemUgdGhlIFMmUCA1MDAgUmV2ZW51ZSBHcm93dGggdXNpbmcgYSBib3hwbG90ISBUaGUgUyZQIDUwMCByZXZlbnVlIGdyb3d0aCBtZWFzdXJlcyB0aGUgcGVyY2VudGFnZSBjaGFuZ2UgaW4gdG90YWwgc2FsZXMgb2YgdGhlIGNvbXBhbmllcyB3aXRoaW4gdGhlIFMmUCA1MDAgaW5kZXguIEl0IHJlZmxlY3RzIHRoZSBjb2xsZWN0aXZlIHNhbGVzIHBlcmZvcm1hbmNlIG9mIHRoZXNlIGxhcmdlLWNhcCBVLlMuIGNvbXBhbmllcyBhbmQgaXMgYSBrZXkgaW5kaWNhdG9yIG9mIHRoZSBvdmVyYWxsIGhlYWx0aCBhbmQgc2hvd3MgYSBzaWduaWZpY2FudCBncm93dGggdG8gdGhlIFVuaXRlZCBTdGF0ZXMgRWNvbm9teS4gCgpgYGB7cn0KZ2dwbG90KHNwNTAwKSsKICBhZXMoYFJldmVudWVncm93dGhgKSsKICBnZW9tX2JveHBsb3QoKSAKYGBgCgpMZXQncyB0YWtlIGEgbG9vayBhdCBhbGwgdGhlIEV4Y2hhbmdlcyBmb3IgUyZQIDUwMC4gQWNjb3JkaW5nIHRvIHRoZSByZXN1bHRzLCB5b3UgY2FuIHNlZSB0aGF0IE5ZUShOZXcgWW9yayBRdWFydGVybHkpIGlzIHRoZSBoaWdoZXN0IG91dCBvZiBhbGwgZXhjaGFuZ2VzLgpgYGB7cn0Kc3A1MDAgJT4lCiAgY291bnQoRXhjaGFuZ2UsIHNvcnQgPSBUUlVFKSAlPiUKICBoZWFkKDQpCmBgYApMZXQgdXMgdmlzdWFsaXplIHRoZSBTZWN0b3IgaW4gUyZQIDUwMC4gRm9yIHRob3NlIHdobyBkb24ndCBrbm93IHdoYXQgaXQgZG9lcywgVGhlIFMmUCA1MDAgc2VjdG9ycyByZXByZXNlbnQgZ3JvdXBpbmdzIG9mIGNvbXBhbmllcyB3aXRoaW4gdGhlIFMmUCA1MDAgaW5kZXggdGhhdCBhcmUgY2F0ZWdvcml6ZWQgYnkgdGhlaXIgcHJpbWFyeSBpbmR1c3RyeSBvciBidXNpbmVzcyBhY3Rpdml0eS4gVGhlc2Ugc2VjdG9ycyBhbGxvdyBpbnZlc3RvcnMgdG8gYW5hbHl6ZSBhbmQgdHJhY2sgdGhlIHBlcmZvcm1hbmNlIG9mIHNwZWNpZmljIGluZHVzdHJpZXMgd2l0aGluIHRoZSBicm9hZGVyIG1hcmtldCwgYW5kIHRvIHBvdGVudGlhbGx5IG1ha2UgbW9yZSB0YXJnZXRlZCBpbnZlc3RtZW50cwpgYGB7cn0KZ2dwbG90KHNwNTAwKSsKICBhZXMoYFNlY3RvcmApKwogIGdlb21fYmFyKCkgKwogdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkKYGBgCkFjY29yZGluZyB0byBZYWhvbyBGaW5hbmNlLCBUaGlzIGlzIHRoZSBlbnRpcmUgc3RvY2sgbWFya2V0IHN0YXJ0aW5nIGZyb20gTm92ZW1iZXIgMTk5NiB0aWxsIHRvZGF5ISBBcyB5b3Uga25vdywgaXQgd2FzIG9yaWdpbmF0ZWQgaW4gMTkyMy4gWW91IHdpbGwgZ2V0IGRhdGEgZnJvbSAxOTk2IGJlY2F1c2UgdGhhdHMgd2hlbiB0aGUgZG90LWNvbSBidWJsZSBiYWxsb29uZWQgZHVyaW5nIHRoZSBsYXRlIDE5OTBzLihUSVA6IFdoZW4gWWFob28gRmluYW5jZSB1cGRhdGVzIHRoZSBzdG9jayBtYXJrZXQsIHRoZSBzdG9jayBtYXJrZXQgc2hvd24gaW4gdGhlIFByZXZpZXcgb24gUG9zaXQgd2lsbCBhbHNvIHVwZGF0ZSBpZiB5b3Uga2VlcCBydW5uaW5nIGl0IGV2ZXJ5IG1vbnRoISkuIApgYGB7cn0KbGlicmFyeShxdWFudG1vZCkgICMgRm9yIGRvd25sb2FkaW5nIGZpbmFuY2lhbCBkYXRhCmxpYnJhcnkoZ2dwbG90MikKCnN0YXJ0X2RhdGUgPC0gIjE5OTYtMTEtMjIiCmVuZF9kYXRlIDwtICIyMDI1LTEyLTMxIiAKCiMgRG93bmxvYWQgUyZQIDUwMCBkYXRhICh1c2luZyBpdHMgY29tbW9uIHRpY2tlciBzeW1ib2wgXkdTUEMpCiMgVGhlIHF1YW50bW9kIHBhY2thZ2UgY2FuIGRvd25sb2FkIGRhdGEgZnJvbSBzb3VyY2VzIGxpa2UgWWFob28gRmluYW5jZQpnZXRTeW1ib2xzKCJeR1NQQyIsIHNyYyA9ICJ5YWhvbyIsIGZyb20gPSBzdGFydF9kYXRlLCB0byA9IGVuZF9kYXRlLCBhdXRvLmFzc2lnbiA9IFRSVUUpICMKCiMgWW91J2xsIG5vdyBoYXZlIGEgdGltZSBzZXJpZXMgb2JqZWN0IG5hbWVkICdHU1BDJyBpbiB5b3VyIFIgZW52aXJvbm1lbnQKCiMgQ29udmVydCB0aGUgeHRzIG9iamVjdCB0byBhIGRhdGEgZnJhbWUgZm9yIHVzZSB3aXRoIGdncGxvdDIKR1NQQ19kZiA8LSBkYXRhLmZyYW1lKERhdGUgPSBpbmRleChHU1BDKSwgY29yZWRhdGEoR1NQQykpCgojIFJlbmFtZSB0aGUgY29sdW1ucyB0byBzb21ldGhpbmcgbW9yZSBjb252ZW5pZW50CmNvbG5hbWVzKEdTUENfZGYpIDwtIGMoIkRhdGUiLCAiT3BlbiIsICJIaWdoIiwgIkxvdyIsICJDbG9zZSIsICJWb2x1bWUiLCAiQWRqdXN0ZWQiKQoKIyBDcmVhdGUgYSBsaW5lIGNoYXJ0IG9mIHRoZSBTJlAgNTAwIGNsb3NpbmcgcHJpY2UKZ2dwbG90KEdTUENfZGYsIGFlcyh4ID0gRGF0ZSwgeSA9IENsb3NlKSkgKwogIGdlb21fbGluZSgpICsgIyBDcmVhdGUgdGhlIGxpbmUgY2hhcnQKICBsYWJzKAogICAgdGl0bGUgPSAiUyZQIDUwMCBDbG9zaW5nIFByaWNlIGluIDIwMjUiLAogICAgeCA9ICJEYXRlKE1vbnRocykiLAogICAgeSA9ICJDbG9zaW5nIFByaWNlIgogICkgKwogIHRoZW1lX21pbmltYWwoKSAKYGBgCllvdSBjYW4gbm90aWNlIG9uIHRoZSBzdG9jayBjaGFydCB0aGF0IGl0IGNyYXNoZWQgb24gZWFybHkgQXByaWwgZHVlIHRvIFByZXNpZGVudCBUcnVtcCdzIGV4dGVuc2l2ZSB0YXJpZmZzLiBXaGlsZSB0aGUgUyZQIDUwMCBkaWQgcmVib3VuZCBsYXRlciBpbiBNaWQgQXByaWwsIHRoZSBpbml0aWFsIGRvd250dXJuIG9uIEFwcmlsIDd0aCBhbmQgdGhlIHByZWNlZGluZyBkYXlzIHdhcyBhIGRpcmVjdCBjb25zZXF1ZW5jZSBvZiBQcmVzaWRlbnQgVHJ1bXAncyB0YXJpZmYgcG9saWNpZXMgYW5kIHRoZSByZXN1bHRpbmcgbWFya2V0IHBhbmljLiAKCk5vdywgbGV0IHVzIHNlZSB3aGF0IGNvbXBhbmllcyBhcmUgaW52ZXN0aW5nIGZyb20gd2hpY2ggY291bnRyeSEgWW91IGNhbiBzZWUgdGhhdCBhYm91dCA5MyUgb2YgdGhlIGNvbXBhbmllcyBpbnZlc3RpbmcgaW4gUyZQIDUwMCBhcmUgVVNBIEJhc2VkIGNvbXBhbmllcy4KYGBge3J9CmdncGxvdChzcDUwMCwgYWVzKENvdW50cnkpKSArCiAgZ2VvbV9iYXIoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA1NSwgaGp1c3QgPSAxKSkgKwogIGdlb21fdGV4dChzdGF0ID0gImNvdW50IiwgCiAgICAgICAgICAgIGFlcyhsYWJlbCA9IGFmdGVyX3N0YXQoY291bnQpKSwKICAgICAgICAgICAgdmp1c3QgPSAtMC4yNQogICkKYGBgClRoaXMgYmFyIGdyYXBoIGhlbHBzIHVzIGtub3cgd2hhdCBzdGF0ZSBpcyBlYWNoIGNvbXBhbnkgZnJvbSB0aGF0IGlzIGluIHRoZSB0b3AgNTAwIGZvciBTJlAgNTAwLiBJIHVzZWQgdGhlbWUgYW5kIHJvdGF0ZWQgdGhlIHRleHQgdG8gcHJldmVudCBpdCBmcm9tIG92ZXJsYXBwaW5nIHdpdGggZWFjaCBvdGhlci4KYGBge3J9CmdncGxvdChzcDUwMCwgYWVzKFN0YXRlKSkgKwogIGdlb21fYmFyKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNTUsIGhqdXN0ID0gMSkpIApgYGAKVGhlIFJPQyBDdXJ2ZSB0ZWxscyB1cyB0aGUgIyBvZiB0cnVlIHBvc2l0aXZlcyBhbmQgZmFsc2UgcG9zaXRpdmUgcmF0ZSBmb3IgdGhlIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWwgYXMgdGhlIHRocmVzaG9sZCBjaGFuZ2VzLiBJdCB0ZWxscyBob3cgeW91ciBtb2RlbCBkb2VzIGZvciBjYXRlZ29yaXppbmcgdGhlIGRhdGEuIApgYGB7cn0KIyBJbnN0YWxsIHRoZSBmb2xsb3dpbmcgcGFja2FnZXMgZm9yIGFsbCB0aGVzZSBsaW5lcyBvZiBjb2RlIHRvIHdvcmsKbGlicmFyeShyc2FtcGxlKQpsaWJyYXJ5KGJyZ2xtMikKbGlicmFyeShjYXJldCkKbGlicmFyeShwUk9DKQoKIyBDcmVhdGUgYSBDYXRlZ29yaWNhbCBWYXJpYWJsZQpzcDUwMCA8LSBzcDUwMCAlPiUKICBtdXRhdGUoVGVjaCA9IGlmX2Vsc2UoU2VjdG9yICVpbiUgYygiVGVjaG5vbG9neSIpLCAiMSIsICIwIiApKQoKIyBTcGxpdHRpbmcgdGhlIERhdGEgaW50byBUcmFpbiBhbmQgVGVzdCBEYXRhCnNldC5zZWVkKDEyMykKc3BsaXQgPC0gaW5pdGlhbF9zcGxpdChzcDUwMCwgcHJvcCA9IDAuNSwgc3RyYXRhID0gRXhjaGFuZ2UpCgp0cmFpbl9kYXRhIDwtIHRyYWluaW5nKHNwbGl0KQp0ZXN0X2RhdGEgPC0gdGVzdGluZyhzcGxpdCkKCiMgRml0dGluZyB0aGUgTG9naXN0aWMgUmVncmVzc2lvbgptb2RlbCA8LSBnbG0oYXMuZmFjdG9yKFRlY2gpIH4gYXMuZmFjdG9yKEV4Y2hhbmdlKSwgZGF0YSA9IHRyYWluX2RhdGEsIGZhbWlseSA9ICJiaW5vbWlhbCIsIG1ldGhvZCA9ICJicmdsbUZpdCIpCgojIFRlc3RpbmcgdGhlIExvZ2lzdGljIFJlZ3Jlc3Npb24gTW9kZWwKdGVzdF9kYXRhJHByZWRpY3RlZF9wcm9iIDwtIHByZWRpY3QobW9kZWwsIG5ld2RhdGEgPSB0ZXN0X2RhdGEsIHR5cGUgPSAicmVzcG9uc2UiKQp0ZXN0X2RhdGEkcHJlZGljdGVkX2NsYXNzIDwtIGlmZWxzZSh0ZXN0X2RhdGEkcHJlZGljdGVkX3Byb2IgPiAwLjUsIDEsIDApCgp0ZXN0X2RhdGEkYWN0dWFsIDwtIGZhY3Rvcih0ZXN0X2RhdGEkVGVjaCkKdGVzdF9kYXRhJHByZWRpY3RlZF9jbGFzcyA8LSBmYWN0b3IodGVzdF9kYXRhJHByZWRpY3RlZF9jbGFzcykKCiMgQ29uZnVzaW9uIE1hdHJpeCAoRXZhbHVhdGVzIHRoZSBNb2RlbCBhbmQgc2VlaW5nIGhvdyBpdCBkb2VzKQpjb25mdXNpb25NYXRyaXgodGVzdF9kYXRhJHByZWRpY3RlZF9jbGFzcywgdGVzdF9kYXRhJGFjdHVhbCkKCnJvY19vYmogPC0gcm9jKHRlc3RfZGF0YSRhY3R1YWwsIHRlc3RfZGF0YSRwcmVkaWN0ZWRfcHJvYikKcGxvdChyb2Nfb2JqLCBtYWluID0gIlJPQyBDdXJ2ZSIpCmBgYApGaW5hbGx5LCBjb25jbHVkaW5nIG91ciBhbmFseXNpcyBvZiB0aGUgUyZQIDUwMCAyMDI1IFN0b2NrIE1hcmtldCwgaGVyZSBpcyBhIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsLiBBIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsIGlzIHVzZWQgYXMgYSB3YXkgdG8gZmluZCB0aGUgYmVzdC1maXR0aW5nIHN0cmFpZ2h0IGxpbmUgdGhyb3VnaCBhIHNldCBvZiBkYXRhIHBvaW50cyBJbiBvcmRlciBmb3IgeW91ciByZWdyZXNzaW9uIG1vZGVsIHRvIHdvcmssIHlvdSB3aWxsIG5lZWQgdG8gaGF2ZSAyIG51bWVyaWNhbCB2YXJpYWJsZXMuIEluIHRoaXMgc2NlbmFyaW8sIEkgaGF2ZSBSZXZlbnVlIEdyb3d0aCBhbmQgTWFya2V0IENhcC4gSXQgd2lsbCBoZWxwIHByZWRpY3QgZnV0dXJlIHZhbHVlcyBvZiBzb21ldGhpbmcgYmFzZWQgb24gcmVsYXRlZCBmYWN0b3JzIGFuZCB1bmRlcnN0YW5kcyBob3cgMSB2YXJpYWJsZSBjaGFuZ2VzIGFzIGFub3RoZXIgaW5jcmVhc2VzIG9yIGRlY3JlYXNlcy4gSW4geW91ciBZLUF4aXMsIHlvdSBoYXZlIGEgbWFya2V0IGNhcC4gRm9yIGV4YW1wbGUsIFRoZSAxZSsxMiBmb3IgZXhhbXBsZSBtZWFucyAxIHRyaWxsaW9uIGJ1dCBpbiBzY2llbnRpZmljIG5vdGF0aW9uLgpgYGB7cn0KbW9kZWwgPC0gbG0oTWFya2V0Y2FwIH4gUmV2ZW51ZWdyb3d0aCwgZGF0YSA9IHNwNTAwKSAKc3VtbWFyeShtb2RlbCkKCmxpYnJhcnkoZ2dwbG90MikKCmdncGxvdChzcDUwMCwgYWVzKHggPSBSZXZlbnVlZ3Jvd3RoLCB5ID0gTWFya2V0Y2FwKSkgKwogIGdlb21fcG9pbnQocG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXIod2lkdGggPSAwLjIpLCBhbHBoYSA9IDAuNikgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gVFJVRSwgY29sb3IgPSAidHVycXVvaXNlIiwgc2l6ZSA9IDEpICsKICBsYWJzKHRpdGxlID0gIkxpbmVhciBSZWdyZXNzaW9uOiBNYXJrZXQgQ2FwIHZzIFJldmVudWUgR3Jvd3RoIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkKYGBgCgpUb2RheSwgRGF0YSBzY2llbmNlIGhlbHBzIGludmVzdG9ycywgYW5hbHlzdHMsIGFuZCBjb21wYW5pZXMgdW5kZXJzdGFuZCwgdHJhY2ssIGFuZCBwcmVkaWN0IHRoZSBwZXJmb3JtYW5jZSBvZiB0aGUgUyZQIDUwMC4KQW5kIFIgaXMgYSBwb3dlcmZ1bCB0b29sIHVzZWQgdG8gZG8gdGhhdCBhbmFseXNpcyBieSBhbmFseXppbmcgdHJlbmRzLCBtYWtpbmcgcHJlZGljdGlvbnMgb2YgdGhlIHN0b2NrIGNoYXJ0LCBQb3J0Zm9saW8gT3B0aW1pemF0aW9uLCBhbmQgbGFzdGx5LCByaXNrIG1hbmFnZW1lbnQuCgpUaGFua3MgZm9yIGxpc3RlbmluZyEgSG9wZSB0aGlzIGhlbHBzIHlvdSB1bmRlcnN0YW5kIG1vc3RseSBhYm91dCB0aGUgUyZQIDUwMCBhbmQgc3RvY2tzIQoKTWFkZSBieSBTaWQg