library(dplyr)

Attaching package: ‘dplyr’

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

    filter, lag

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

    intersect, setdiff, setequal, union
library(readr)
library(tidyverse)
── Attaching core tidyverse packages ──────────────────────────────────────────────────────────────────────── tidyverse 2.0.0 ──
✔ forcats   1.0.0     ✔ stringr   1.5.1
✔ ggplot2   3.5.1     ✔ tibble    3.2.1
✔ lubridate 1.9.4     ✔ tidyr     1.3.1
✔ purrr     1.0.2     ── Conflicts ────────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the ]8;;http://conflicted.r-lib.org/conflicted package]8;; to force all conflicts to become errors
library(ggplot2)
library(conflicted)
#Reading the data set
data <- read.csv("dataset.csv")
conflicted::conflicts_prefer(dplyr::filter)
[conflicted] Will prefer dplyr::filter over any other package.
# Filtering dataset where explicit is "True" and taking a sample of 9,000 rows
sample_data <- data |> filter(explicit == "True") |> sample_n(9000)
data <- sample_data
data

Refer to the simple linear regression model you built last week. Include 1-3 more variables into your regression model.

# Fit the multiple linear regression model
lm_model <- lm(popularity ~ danceability + energy + valence, data = data)

# Display model summary
summary(lm_model)

Call:
lm(formula = popularity ~ danceability + energy + valence, data = data)

Residuals:
    Min      1Q  Median      3Q     Max 
-49.121 -16.370   0.377  18.790  66.029 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept)    51.582      1.790  28.810   <2e-16 ***
danceability   -3.361      1.790  -1.878   0.0605 .  
energy        -18.827      1.516 -12.422   <2e-16 ***
valence         1.459      1.233   1.183   0.2367    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 24.13 on 8996 degrees of freedom
Multiple R-squared:  0.01866,   Adjusted R-squared:  0.01833 
F-statistic: 57.01 on 3 and 8996 DF,  p-value: < 2.2e-16

Interpretation of the Multiple Linear Regression Output

Here, we fitted a multiple linear regression model with popularity as the dependent variable and danceability, energy, and valence as independent variables.

1. Model Equation

The regression equation based on the coefficients: \[ \text{popularity} = 51.3749 - 2.4805 \cdot \text{danceability} - 18.9689 \cdot \text{energy} + 0.6928 \cdot \text{valence} \]

2. Coefficient Analysis

  • Intercept (51.3749, p < 2e-16)
    • When all predictors are 0, the predicted popularity is 51.37.
    • The intercept is statistically significant (p-value < 0.001*).
  • Danceability (-2.4805, p = 0.165)
    • Has a negative effect on popularity, but not statistically significant (p-value > 0.05).
    • This means that danceability does not have a strong impact on popularity in the data.
  • Energy (-18.9689, p < 2e-16)**
    • Has a strong negative impact on popularity.
    • Statistically significant (p-value < 0.001*), meaning higher energy is associated with lower** popularity.
  • Valence (0.6928, p = 0.574)
    • Very weak positive effect on popularity.
    • Not statistically significant (p-value > 0.05), meaning valence does not strongly influence popularity.

3. Model Performance

  • Multiple R-squared = 0.01943 (1.94%)
    • The model explains only ~1.94% of the variability in popularity.
    • This means the model is not a good predictor of popularity.
  • Adjusted R-squared = 0.01911
    • Adjusts for the number of predictors but is still very low.
  • F-statistic = 59.43, p-value < 2.2e-16
    • The model as a whole is statistically significant, meaning at least one predictor has an effect.

Key Takeaways

  1. Energy is the only significant predictor (p < 0.001) and has a strong negative effect on popularity.
  2. Danceability and valence are not significant, meaning they do not reliably predict popularity.
  3. The model has very low predictive power (R² = 1.94%), indicating that other factors influence song popularity.

data|> 
  ggplot(mapping = aes(x = energy, y = popularity, color = danceability)) + 
  geom_point(size = 0.5) + 
  geom_smooth(method = 'lm', se = FALSE, color = 'Orange') + 
  geom_hline(yintercept = mean(data$popularity, na.rm = TRUE), linetype = 'dashed') + 
  theme_minimal()

The orange regression line slopes downward, indicating a negative correlation between energy and popularity. This suggests that songs with higher energy tend to have lower popularity, and vice versa.

Try out either an interaction term or a binary term to start.

Adding an interaction term

lm_model_interaction <- lm(popularity ~ danceability * energy + valence, data = data)
summary(lm_model_interaction)

Call:
lm(formula = popularity ~ danceability * energy + valence, data = data)

Residuals:
    Min      1Q  Median      3Q     Max 
-50.526 -16.377   0.365  18.829  65.984 

Coefficients:
                    Estimate Std. Error t value Pr(>|t|)    
(Intercept)           54.636      4.384  12.461  < 2e-16 ***
danceability          -8.099      6.461  -1.253    0.210    
energy               -22.707      5.305  -4.281 1.88e-05 ***
valence                1.309      1.249   1.049    0.294    
danceability:energy    6.349      8.319   0.763    0.445    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 24.13 on 8995 degrees of freedom
Multiple R-squared:  0.01872,   Adjusted R-squared:  0.01829 
F-statistic:  42.9 on 4 and 8995 DF,  p-value: < 2.2e-16

energy is the only statistically significant predictor (p-value = 4.93e-05), indicating a strong relationship with popularity. danceability, valence, and the interaction term danceability:energy have high p-values (> 0.05), meaning their effects are not statistically significant.We have to include valence as it has a significant relationship with the target variable and enhances model performance. It can be excluded if it introduces multicollinearity with other features or doesn’t improve predictive power.

Consider adding other integer or continuous variables.

Adding Another Continuous Variable: Tempo


lm_model_tempo <- lm(popularity ~ danceability + energy + tempo, data = data)
summary(lm_model_tempo)

Call:
lm(formula = popularity ~ danceability + energy + tempo, data = data)

Residuals:
   Min     1Q Median     3Q    Max 
-48.17 -16.12   0.27  18.69  65.75 

Coefficients:
               Estimate Std. Error t value Pr(>|t|)    
(Intercept)   47.257372   2.069654  22.833  < 2e-16 ***
danceability  -1.720256   1.625482  -1.058     0.29    
energy       -19.054905   1.497382 -12.725  < 2e-16 ***
tempo          0.033972   0.008441   4.025 5.75e-05 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 24.11 on 8996 degrees of freedom
Multiple R-squared:  0.02027,   Adjusted R-squared:  0.01994 
F-statistic: 62.04 on 3 and 8996 DF,  p-value: < 2.2e-16

The model is statistically significant overall (based on F-statistic).

Among predictors:

energy has a strong negative association with popularity and is highly significant.

tempo has a positive association with popularity and is also significant.

danceability does not have a statistically significant effect on popularity.

The low R-squared value suggests that this model explains very little of the variability in popularity, indicating that other factors may better predict popularity. Tempo is to be included in a model as it influences the target variable, such as song popularity, user engagement, or mood-based playlists, as it directly affects the song’s energy and rhythm. However, we can exclude it if it is highly correlated with other features like energy or danceability, leading to multicollinearity or redundancy.

Your model for this data dive should have 2-4 terms.

Yes, for this data dive, my model has 4 terms-

Valence: Captures the mood or emotional content of a song (positive/negative).

Tempo: Represents the speed of the song, influencing energy and rhythm.

Energy (optional): Reflects the intensity of a track, which could correlate with tempo and valence.

Danceability (optional): Measures how suitable a song is for dancing, which often correlates with tempo and energy.

# Define the model with Valence, Tempo, Energy, and Danceability as predictors
model <- lm(popularity ~ valence + tempo + energy + danceability, data = data)

# View the summary of the model
summary(model)

Call:
lm(formula = popularity ~ valence + tempo + energy + danceability, 
    data = data)

Residuals:
    Min      1Q  Median      3Q     Max 
-48.163 -16.192   0.269  18.678  65.931 

Coefficients:
               Estimate Std. Error t value Pr(>|t|)    
(Intercept)   47.415608   2.077684  22.821  < 2e-16 ***
valence        1.073530   1.235916   0.869    0.385    
tempo          0.033391   0.008468   3.943  8.1e-05 ***
energy       -19.274938   1.518678 -12.692  < 2e-16 ***
danceability  -2.402586   1.805364  -1.331    0.183    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 24.11 on 8995 degrees of freedom
Multiple R-squared:  0.02035,   Adjusted R-squared:  0.01992 
F-statistic: 46.72 on 4 and 8995 DF,  p-value: < 2.2e-16

The model suggests that tempo and energy are significant predictors of popularity, with tempo having a positive impact and energy a negative one. Valence and danceability are not statistically significant predictors. The model explains only 2.14% of the variance in popularity (R-squared = 0.02141), indicating a weak fit. Despite this, the overall model is statistically significant (p-value < 2.2e-16).

Evaluate this model.

# Generate predictions using the model
data$predictions <- predict(model, newdata = data)

# Evaluate model performance
mse <- mean((data$popularity - data$predictions)^2)
r2 <- 1 - sum((data$popularity - data$predictions)^2) / sum((data$popularity - mean(data$popularity))^2)

# Print MSE and R-squared
cat("Mean Squared Error: ", mse, "\n")
Mean Squared Error:  580.7908 
cat("R-squared: ", r2, "\n")
R-squared:  0.02035224 
# Print model coefficients
cat("Model Coefficients:\n")
Model Coefficients:
print(coef(model))
 (Intercept)      valence        tempo       energy danceability 
 47.41560784   1.07353001   0.03339058 -19.27493809  -2.40258612 

The Mean Squared Error (MSE) of the model is 580.79, indicating a high average error between predicted and actual popularity values. The R-squared value is 0.0203, meaning the model explains only 2% of the variability in popularity, showing poor predictive performance. The coefficients indicate that valence and tempo have a slight positive impact, while energy and danceability negatively affect popularity.

plot(data$predictions, data$popularity - data$predictions,
     xlab = "Predicted Popularity", ylab = "Residuals",
     main = "Residual Plot")
abline(h = 0, col = "red")

The residuals are spread widely and randomly around the horizontal line (at 0), but there is a visible funnel shape — meaning the spread of residuals increases as predicted popularity increases.

At the very least, use the 5 diagnostic plots discussed in class to identify any issues with your model.

For each plot, point out any indications of issues with the model. Otherwise, explain how the plot supports the claim that an assumption is met.

Try to measure the severity of any issues as well as the level of confidence you have in an assumption being met.

1 Plot Residuals vs Fitted Values

plot(model, which = 1)

This “Residuals vs Fitted” plot evaluates the linear regression model’s assumptions. The residuals (errors) should ideally be randomly scattered around the horizontal line at zero, indicating no patterns or bias. However, the funnel shape suggests heteroscedasticity (non-constant variance), which may require model improvement or transformation of variables.

2. Plot Residuals vs X values

plot(model, which = 2)

This Q-Q Residuals plot compares the standardized residuals of the regression model to a normal distribution. The points mostly follow the diagonal line, but deviations at the tails (both ends) suggest that the residuals are not perfectly normally distributed.

3. Scale-Location Plot

plot(model, which = 3)

This Scale-Location plot is used to assess the assumption of homoscedasticity (constant variance) in a linear regression model. The x-axis represents fitted values, while the y-axis shows the square root of standardized residuals. Ideally, the red line should be horizontal, and the points should be evenly scattered; however, the increasing spread suggests growth, indicating non-constant variance in residuals.

4. Cook’s Distance

# Cook's Distance by Observation
plot(model, which = 4)

This Cook’s Distance plot identifies observations that have a significant influence on the regression model’s fitted values. Observations 473, 3236, and 3667 have the highest Cook’s Distance values, indicating they exert disproportionate leverage on the model. These points should be investigated further as they are likely outliers or influential data points affecting the stability of the regression results.

Finally,

While performing the analysis, I realized the importance of granular aggregation and probabilistic grouping to capture hidden trends within the dataset. The key takeaway was that a structured approach to grouping can yield valuable insights into large datasets with multiple attributes, guiding decision-making for music streaming platforms and artists alike.

LS0tDQp0aXRsZTogIkRhdGEgRGl2ZSAtIDkiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHJlYWRyKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGNvbmZsaWN0ZWQpDQpgYGANCg0KYGBge3J9DQojUmVhZGluZyB0aGUgZGF0YSBzZXQNCmRhdGEgPC0gcmVhZC5jc3YoImRhdGFzZXQuY3N2IikNCmNvbmZsaWN0ZWQ6OmNvbmZsaWN0c19wcmVmZXIoZHBseXI6OmZpbHRlcikNCiMgRmlsdGVyaW5nIGRhdGFzZXQgd2hlcmUgZXhwbGljaXQgaXMgIlRydWUiIGFuZCB0YWtpbmcgYSBzYW1wbGUgb2YgOSwwMDAgcm93cw0Kc2FtcGxlX2RhdGEgPC0gZGF0YSB8PiBmaWx0ZXIoZXhwbGljaXQgPT0gIlRydWUiKSB8PiBzYW1wbGVfbig5MDAwKQ0KZGF0YSA8LSBzYW1wbGVfZGF0YQ0KZGF0YQ0KYGBgDQoNCiMgUmVmZXIgdG8gdGhlIHNpbXBsZSBsaW5lYXIgcmVncmVzc2lvbiBtb2RlbCB5b3UgYnVpbHQgbGFzdCB3ZWVrLiBJbmNsdWRlIDEtMyBtb3JlIHZhcmlhYmxlcyBpbnRvIHlvdXIgcmVncmVzc2lvbiBtb2RlbC4NCg0KYGBge3J9DQojIEZpdCB0aGUgbXVsdGlwbGUgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwNCmxtX21vZGVsIDwtIGxtKHBvcHVsYXJpdHkgfiBkYW5jZWFiaWxpdHkgKyBlbmVyZ3kgKyB2YWxlbmNlLCBkYXRhID0gZGF0YSkNCg0KIyBEaXNwbGF5IG1vZGVsIHN1bW1hcnkNCnN1bW1hcnkobG1fbW9kZWwpDQoNCmBgYA0KDQojIyMgKipJbnRlcnByZXRhdGlvbiBvZiB0aGUgTXVsdGlwbGUgTGluZWFyIFJlZ3Jlc3Npb24gT3V0cHV0KioNCkhlcmUsIHdlIGZpdHRlZCBhIG11bHRpcGxlIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsIHdpdGggKipwb3B1bGFyaXR5KiogYXMgdGhlIGRlcGVuZGVudCB2YXJpYWJsZSBhbmQgKipkYW5jZWFiaWxpdHksIGVuZXJneSwgYW5kIHZhbGVuY2UqKiBhcyBpbmRlcGVuZGVudCB2YXJpYWJsZXMuDQoNCiMjIyAqKjEuIE1vZGVsIEVxdWF0aW9uKioNClRoZSByZWdyZXNzaW9uIGVxdWF0aW9uIGJhc2VkIG9uIHRoZSBjb2VmZmljaWVudHM6DQpcWw0KXHRleHR7cG9wdWxhcml0eX0gPSA1MS4zNzQ5IC0gMi40ODA1IFxjZG90IFx0ZXh0e2RhbmNlYWJpbGl0eX0gLSAxOC45Njg5IFxjZG90IFx0ZXh0e2VuZXJneX0gKyAwLjY5MjggXGNkb3QgXHRleHR7dmFsZW5jZX0NClxdDQoNCiMjIyAqKjIuIENvZWZmaWNpZW50IEFuYWx5c2lzKioNCi0gKipJbnRlcmNlcHQgKDUxLjM3NDksIHAgPCAyZS0xNikqKg0KICAtIFdoZW4gYWxsIHByZWRpY3RvcnMgYXJlIDAsIHRoZSBwcmVkaWN0ZWQgcG9wdWxhcml0eSBpcyAqKjUxLjM3KiouDQogIC0gVGhlIGludGVyY2VwdCBpcyBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50ICgqKnAtdmFsdWUgPCAwLjAwMSoqKikuDQoNCi0gKipEYW5jZWFiaWxpdHkgKC0yLjQ4MDUsIHAgPSAwLjE2NSkqKg0KICAtIEhhcyBhIG5lZ2F0aXZlIGVmZmVjdCBvbiBwb3B1bGFyaXR5LCBidXQgKipub3Qgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCoqIChwLXZhbHVlID4gMC4wNSkuDQogIC0gVGhpcyBtZWFucyB0aGF0ICoqZGFuY2VhYmlsaXR5IGRvZXMgbm90IGhhdmUgYSBzdHJvbmcgaW1wYWN0IG9uIHBvcHVsYXJpdHkqKiBpbiB0aGUgZGF0YS4NCg0KLSAqKkVuZXJneSAoLTE4Ljk2ODksIHAgPCAyZS0xNioqKSoqDQogIC0gSGFzIGEgc3Ryb25nICoqbmVnYXRpdmUqKiBpbXBhY3Qgb24gcG9wdWxhcml0eS4NCiAgLSAqKlN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQqKiAocC12YWx1ZSA8IDAuMDAxKioqKSwgbWVhbmluZyBoaWdoZXIgZW5lcmd5IGlzIGFzc29jaWF0ZWQgd2l0aCAqKmxvd2VyKiogcG9wdWxhcml0eS4NCg0KLSAqKlZhbGVuY2UgKDAuNjkyOCwgcCA9IDAuNTc0KSoqDQogIC0gVmVyeSB3ZWFrIHBvc2l0aXZlIGVmZmVjdCBvbiBwb3B1bGFyaXR5Lg0KICAtICoqTm90IHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQqKiAocC12YWx1ZSA+IDAuMDUpLCBtZWFuaW5nIHZhbGVuY2UgKipkb2VzIG5vdCBzdHJvbmdseSBpbmZsdWVuY2UgcG9wdWxhcml0eSoqLg0KDQojIyMgKiozLiBNb2RlbCBQZXJmb3JtYW5jZSoqDQotICoqTXVsdGlwbGUgUi1zcXVhcmVkID0gMC4wMTk0MyAoMS45NCUpKioNCiAgLSBUaGUgbW9kZWwgZXhwbGFpbnMgKipvbmx5IH4xLjk0JSoqIG9mIHRoZSB2YXJpYWJpbGl0eSBpbiBwb3B1bGFyaXR5Lg0KICAtIFRoaXMgbWVhbnMgdGhlIG1vZGVsIGlzICoqbm90IGEgZ29vZCBwcmVkaWN0b3IqKiBvZiBwb3B1bGFyaXR5Lg0KDQotICoqQWRqdXN0ZWQgUi1zcXVhcmVkID0gMC4wMTkxMSoqDQogIC0gQWRqdXN0cyBmb3IgdGhlIG51bWJlciBvZiBwcmVkaWN0b3JzIGJ1dCBpcyBzdGlsbCB2ZXJ5IGxvdy4NCg0KLSAqKkYtc3RhdGlzdGljID0gNTkuNDMsIHAtdmFsdWUgPCAyLjJlLTE2KioNCiAgLSBUaGUgbW9kZWwgYXMgYSB3aG9sZSBpcyBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50LCBtZWFuaW5nIGF0IGxlYXN0IG9uZSBwcmVkaWN0b3IgaGFzIGFuIGVmZmVjdC4NCg0KIyMjICoqS2V5IFRha2Vhd2F5cyoqDQoxLiAqKkVuZXJneSBpcyB0aGUgb25seSBzaWduaWZpY2FudCBwcmVkaWN0b3IqKiAocCA8IDAuMDAxKSBhbmQgaGFzIGEgKipzdHJvbmcgbmVnYXRpdmUgZWZmZWN0Kiogb24gcG9wdWxhcml0eS4NCjIuICoqRGFuY2VhYmlsaXR5IGFuZCB2YWxlbmNlIGFyZSBub3Qgc2lnbmlmaWNhbnQqKiwgbWVhbmluZyB0aGV5IGRvIG5vdCByZWxpYWJseSBwcmVkaWN0IHBvcHVsYXJpdHkuDQozLiAqKlRoZSBtb2RlbCBoYXMgdmVyeSBsb3cgcHJlZGljdGl2ZSBwb3dlciAoUsKyID0gMS45NCUpKiosIGluZGljYXRpbmcgdGhhdCAqKm90aGVyIGZhY3RvcnMgaW5mbHVlbmNlIHNvbmcgcG9wdWxhcml0eSoqLg0KDQpgYGB7cn0NCg0KZGF0YXw+IA0KICBnZ3Bsb3QobWFwcGluZyA9IGFlcyh4ID0gZW5lcmd5LCB5ID0gcG9wdWxhcml0eSwgY29sb3IgPSBkYW5jZWFiaWxpdHkpKSArIA0KICBnZW9tX3BvaW50KHNpemUgPSAwLjUpICsgDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICdsbScsIHNlID0gRkFMU0UsIGNvbG9yID0gJ09yYW5nZScpICsgDQogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IG1lYW4oZGF0YSRwb3B1bGFyaXR5LCBuYS5ybSA9IFRSVUUpLCBsaW5ldHlwZSA9ICdkYXNoZWQnKSArIA0KICB0aGVtZV9taW5pbWFsKCkNCg0KYGBgDQoNClRoZSBvcmFuZ2UgcmVncmVzc2lvbiBsaW5lIHNsb3BlcyBkb3dud2FyZCwgaW5kaWNhdGluZyBhIG5lZ2F0aXZlIGNvcnJlbGF0aW9uIGJldHdlZW4gZW5lcmd5IGFuZCBwb3B1bGFyaXR5LiBUaGlzIHN1Z2dlc3RzIHRoYXQgc29uZ3Mgd2l0aCBoaWdoZXIgZW5lcmd5IHRlbmQgdG8gaGF2ZSBsb3dlciBwb3B1bGFyaXR5LCBhbmQgdmljZSB2ZXJzYS4NCg0KIyBUcnkgb3V0IGVpdGhlciBhbiBpbnRlcmFjdGlvbiB0ZXJtIG9yIGEgYmluYXJ5IHRlcm0gdG8gc3RhcnQuDQoNCiMgQWRkaW5nIGFuIGludGVyYWN0aW9uIHRlcm0NCmBgYHtyfQ0KbG1fbW9kZWxfaW50ZXJhY3Rpb24gPC0gbG0ocG9wdWxhcml0eSB+IGRhbmNlYWJpbGl0eSAqIGVuZXJneSArIHZhbGVuY2UsIGRhdGEgPSBkYXRhKQ0Kc3VtbWFyeShsbV9tb2RlbF9pbnRlcmFjdGlvbikNCg0KYGBgDQplbmVyZ3kgaXMgdGhlIG9ubHkgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBwcmVkaWN0b3IgKHAtdmFsdWUgPSA0LjkzZS0wNSksIGluZGljYXRpbmcgYSBzdHJvbmcgcmVsYXRpb25zaGlwIHdpdGggcG9wdWxhcml0eS4gZGFuY2VhYmlsaXR5LCB2YWxlbmNlLCBhbmQgdGhlIGludGVyYWN0aW9uIHRlcm0gZGFuY2VhYmlsaXR5OmVuZXJneSBoYXZlIGhpZ2ggcC12YWx1ZXMgKD4gMC4wNSksIG1lYW5pbmcgdGhlaXIgZWZmZWN0cyBhcmUgbm90IHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQuV2UgaGF2ZSB0byBpbmNsdWRlIHZhbGVuY2UgYXMgaXQgaGFzIGEgc2lnbmlmaWNhbnQgcmVsYXRpb25zaGlwIHdpdGggdGhlIHRhcmdldCB2YXJpYWJsZSBhbmQgZW5oYW5jZXMgbW9kZWwgcGVyZm9ybWFuY2UuIEl0IGNhbiBiZSBleGNsdWRlZCBpZiBpdCBpbnRyb2R1Y2VzIG11bHRpY29sbGluZWFyaXR5IHdpdGggb3RoZXIgZmVhdHVyZXMgb3IgZG9lc27igJl0IGltcHJvdmUgcHJlZGljdGl2ZSBwb3dlci4NCg0KDQojIENvbnNpZGVyIGFkZGluZyBvdGhlciBpbnRlZ2VyIG9yIGNvbnRpbnVvdXMgdmFyaWFibGVzLg0KIyBBZGRpbmcgQW5vdGhlciBDb250aW51b3VzIFZhcmlhYmxlOiBUZW1wbw0KYGBge3J9DQoNCmxtX21vZGVsX3RlbXBvIDwtIGxtKHBvcHVsYXJpdHkgfiBkYW5jZWFiaWxpdHkgKyBlbmVyZ3kgKyB0ZW1wbywgZGF0YSA9IGRhdGEpDQpzdW1tYXJ5KGxtX21vZGVsX3RlbXBvKQ0KDQpgYGANClRoZSBtb2RlbCBpcyBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IG92ZXJhbGwgKGJhc2VkIG9uIEYtc3RhdGlzdGljKS4NCg0KQW1vbmcgcHJlZGljdG9yczoNCg0KZW5lcmd5IGhhcyBhIHN0cm9uZyBuZWdhdGl2ZSBhc3NvY2lhdGlvbiB3aXRoIHBvcHVsYXJpdHkgYW5kIGlzIGhpZ2hseSBzaWduaWZpY2FudC4NCg0KdGVtcG8gaGFzIGEgcG9zaXRpdmUgYXNzb2NpYXRpb24gd2l0aCBwb3B1bGFyaXR5IGFuZCBpcyBhbHNvIHNpZ25pZmljYW50Lg0KDQpkYW5jZWFiaWxpdHkgZG9lcyBub3QgaGF2ZSBhIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgZWZmZWN0IG9uIHBvcHVsYXJpdHkuDQoNClRoZSBsb3cgUi1zcXVhcmVkIHZhbHVlIHN1Z2dlc3RzIHRoYXQgdGhpcyBtb2RlbCBleHBsYWlucyB2ZXJ5IGxpdHRsZSBvZiB0aGUgdmFyaWFiaWxpdHkgaW4gcG9wdWxhcml0eSwgaW5kaWNhdGluZyB0aGF0IG90aGVyIGZhY3RvcnMgbWF5IGJldHRlciBwcmVkaWN0IHBvcHVsYXJpdHkuICoqVGVtcG8qKiBpcyB0byBiZSBpbmNsdWRlZCBpbiBhIG1vZGVsIGFzIGl0IGluZmx1ZW5jZXMgdGhlIHRhcmdldCB2YXJpYWJsZSwgc3VjaCBhcyBzb25nIHBvcHVsYXJpdHksIHVzZXIgZW5nYWdlbWVudCwgb3IgbW9vZC1iYXNlZCBwbGF5bGlzdHMsIGFzIGl0IGRpcmVjdGx5IGFmZmVjdHMgdGhlIHNvbmcncyBlbmVyZ3kgYW5kIHJoeXRobS4gSG93ZXZlciwgd2UgY2FuIGV4Y2x1ZGUgaXQgaWYgaXQgaXMgaGlnaGx5IGNvcnJlbGF0ZWQgd2l0aCBvdGhlciBmZWF0dXJlcyBsaWtlICoqZW5lcmd5Kiogb3IgKipkYW5jZWFiaWxpdHkqKiwgbGVhZGluZyB0byBtdWx0aWNvbGxpbmVhcml0eSBvciByZWR1bmRhbmN5Lg0KDQoNCg0KIyBZb3VyIG1vZGVsIGZvciB0aGlzIGRhdGEgZGl2ZSBzaG91bGQgaGF2ZSAyLTQgdGVybXMuDQpZZXMsIGZvciB0aGlzIGRhdGEgZGl2ZSwgbXkgbW9kZWwgaGFzIDQgdGVybXMtIA0KDQpWYWxlbmNlOiBDYXB0dXJlcyB0aGUgbW9vZCBvciBlbW90aW9uYWwgY29udGVudCBvZiBhIHNvbmcgKHBvc2l0aXZlL25lZ2F0aXZlKS4NCg0KVGVtcG86IFJlcHJlc2VudHMgdGhlIHNwZWVkIG9mIHRoZSBzb25nLCBpbmZsdWVuY2luZyBlbmVyZ3kgYW5kIHJoeXRobS4NCg0KRW5lcmd5IChvcHRpb25hbCk6IFJlZmxlY3RzIHRoZSBpbnRlbnNpdHkgb2YgYSB0cmFjaywgd2hpY2ggY291bGQgY29ycmVsYXRlIHdpdGggdGVtcG8gYW5kIHZhbGVuY2UuDQoNCkRhbmNlYWJpbGl0eSAob3B0aW9uYWwpOiBNZWFzdXJlcyBob3cgc3VpdGFibGUgYSBzb25nIGlzIGZvciBkYW5jaW5nLCB3aGljaCBvZnRlbiBjb3JyZWxhdGVzIHdpdGggdGVtcG8gYW5kIGVuZXJneS4NCg0KDQoNCg0KDQoNCg0KDQoNCg0KYGBge3J9DQojIERlZmluZSB0aGUgbW9kZWwgd2l0aCBWYWxlbmNlLCBUZW1wbywgRW5lcmd5LCBhbmQgRGFuY2VhYmlsaXR5IGFzIHByZWRpY3RvcnMNCm1vZGVsIDwtIGxtKHBvcHVsYXJpdHkgfiB2YWxlbmNlICsgdGVtcG8gKyBlbmVyZ3kgKyBkYW5jZWFiaWxpdHksIGRhdGEgPSBkYXRhKQ0KDQojIFZpZXcgdGhlIHN1bW1hcnkgb2YgdGhlIG1vZGVsDQpzdW1tYXJ5KG1vZGVsKQ0KDQpgYGANClRoZSBtb2RlbCBzdWdnZXN0cyB0aGF0ICoqdGVtcG8qKiBhbmQgKiplbmVyZ3kqKiBhcmUgc2lnbmlmaWNhbnQgcHJlZGljdG9ycyBvZiAqKnBvcHVsYXJpdHkqKiwgd2l0aCAqKnRlbXBvKiogaGF2aW5nIGEgcG9zaXRpdmUgaW1wYWN0IGFuZCAqKmVuZXJneSoqIGEgbmVnYXRpdmUgb25lLiAqKlZhbGVuY2UqKiBhbmQgKipkYW5jZWFiaWxpdHkqKiBhcmUgbm90IHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgcHJlZGljdG9ycy4gVGhlIG1vZGVsIGV4cGxhaW5zIG9ubHkgKioyLjE0JSoqIG9mIHRoZSB2YXJpYW5jZSBpbiBwb3B1bGFyaXR5IChSLXNxdWFyZWQgPSAwLjAyMTQxKSwgaW5kaWNhdGluZyBhIHdlYWsgZml0LiBEZXNwaXRlIHRoaXMsIHRoZSBvdmVyYWxsIG1vZGVsIGlzIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgKHAtdmFsdWUgPCAyLjJlLTE2KS4NCg0KDQojIEV2YWx1YXRlIHRoaXMgbW9kZWwuIA0KYGBge3J9DQojIEdlbmVyYXRlIHByZWRpY3Rpb25zIHVzaW5nIHRoZSBtb2RlbA0KZGF0YSRwcmVkaWN0aW9ucyA8LSBwcmVkaWN0KG1vZGVsLCBuZXdkYXRhID0gZGF0YSkNCg0KIyBFdmFsdWF0ZSBtb2RlbCBwZXJmb3JtYW5jZQ0KbXNlIDwtIG1lYW4oKGRhdGEkcG9wdWxhcml0eSAtIGRhdGEkcHJlZGljdGlvbnMpXjIpDQpyMiA8LSAxIC0gc3VtKChkYXRhJHBvcHVsYXJpdHkgLSBkYXRhJHByZWRpY3Rpb25zKV4yKSAvIHN1bSgoZGF0YSRwb3B1bGFyaXR5IC0gbWVhbihkYXRhJHBvcHVsYXJpdHkpKV4yKQ0KDQojIFByaW50IE1TRSBhbmQgUi1zcXVhcmVkDQpjYXQoIk1lYW4gU3F1YXJlZCBFcnJvcjogIiwgbXNlLCAiXG4iKQ0KY2F0KCJSLXNxdWFyZWQ6ICIsIHIyLCAiXG4iKQ0KDQojIFByaW50IG1vZGVsIGNvZWZmaWNpZW50cw0KY2F0KCJNb2RlbCBDb2VmZmljaWVudHM6XG4iKQ0KcHJpbnQoY29lZihtb2RlbCkpDQoNCmBgYA0KDQpUaGUgTWVhbiBTcXVhcmVkIEVycm9yIChNU0UpIG9mIHRoZSBtb2RlbCBpcyA1ODAuNzksIGluZGljYXRpbmcgYSBoaWdoIGF2ZXJhZ2UgZXJyb3IgYmV0d2VlbiBwcmVkaWN0ZWQgYW5kIGFjdHVhbCBwb3B1bGFyaXR5IHZhbHVlcy4gVGhlIFItc3F1YXJlZCB2YWx1ZSBpcyAwLjAyMDMsIG1lYW5pbmcgdGhlIG1vZGVsIGV4cGxhaW5zIG9ubHkgMiUgb2YgdGhlIHZhcmlhYmlsaXR5IGluIHBvcHVsYXJpdHksIHNob3dpbmcgcG9vciBwcmVkaWN0aXZlIHBlcmZvcm1hbmNlLiBUaGUgY29lZmZpY2llbnRzIGluZGljYXRlIHRoYXQgdmFsZW5jZSBhbmQgdGVtcG8gaGF2ZSBhIHNsaWdodCBwb3NpdGl2ZSBpbXBhY3QsIHdoaWxlIGVuZXJneSBhbmQgZGFuY2VhYmlsaXR5IG5lZ2F0aXZlbHkgYWZmZWN0IHBvcHVsYXJpdHkuDQoNCmBgYHtyfQ0KcGxvdChkYXRhJHByZWRpY3Rpb25zLCBkYXRhJHBvcHVsYXJpdHkgLSBkYXRhJHByZWRpY3Rpb25zLA0KICAgICB4bGFiID0gIlByZWRpY3RlZCBQb3B1bGFyaXR5IiwgeWxhYiA9ICJSZXNpZHVhbHMiLA0KICAgICBtYWluID0gIlJlc2lkdWFsIFBsb3QiKQ0KYWJsaW5lKGggPSAwLCBjb2wgPSAicmVkIikNCmBgYA0KDQpUaGUgcmVzaWR1YWxzIGFyZSBzcHJlYWQgd2lkZWx5IGFuZCByYW5kb21seSBhcm91bmQgdGhlIGhvcml6b250YWwgbGluZSAoYXQgMCksIGJ1dCB0aGVyZSBpcyBhIHZpc2libGUgZnVubmVsIHNoYXBlIOKAlCBtZWFuaW5nIHRoZSBzcHJlYWQgb2YgcmVzaWR1YWxzIGluY3JlYXNlcyBhcyBwcmVkaWN0ZWQgcG9wdWxhcml0eSBpbmNyZWFzZXMuDQoNCg0KDQojIEF0IHRoZSB2ZXJ5IGxlYXN0LCB1c2UgdGhlIDUgZGlhZ25vc3RpYyBwbG90cyBkaXNjdXNzZWQgaW4gY2xhc3MgdG8gaWRlbnRpZnkgYW55IGlzc3VlcyB3aXRoIHlvdXIgbW9kZWwuDQojIEZvciBlYWNoIHBsb3QsIHBvaW50IG91dCBhbnkgaW5kaWNhdGlvbnMgb2YgaXNzdWVzIHdpdGggdGhlIG1vZGVsLiBPdGhlcndpc2UsIGV4cGxhaW4gaG93IHRoZSBwbG90IHN1cHBvcnRzIHRoZSBjbGFpbSB0aGF0IGFuIGFzc3VtcHRpb24gaXMgbWV0Lg0KIyBUcnkgdG8gbWVhc3VyZSB0aGUgc2V2ZXJpdHkgb2YgYW55IGlzc3VlcyBhcyB3ZWxsIGFzIHRoZSBsZXZlbCBvZiBjb25maWRlbmNlIHlvdSBoYXZlIGluIGFuIGFzc3VtcHRpb24gYmVpbmcgbWV0Lg0KDQoNCiMgMSBQbG90IFJlc2lkdWFscyB2cyBGaXR0ZWQgVmFsdWVzDQpgYGB7cn0NCnBsb3QobW9kZWwsIHdoaWNoID0gMSkNCmBgYA0KVGhpcyAiUmVzaWR1YWxzIHZzIEZpdHRlZCIgcGxvdCBldmFsdWF0ZXMgdGhlIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsJ3MgYXNzdW1wdGlvbnMuIFRoZSByZXNpZHVhbHMgKGVycm9ycykgc2hvdWxkIGlkZWFsbHkgYmUgcmFuZG9tbHkgc2NhdHRlcmVkIGFyb3VuZCB0aGUgaG9yaXpvbnRhbCBsaW5lIGF0IHplcm8sIGluZGljYXRpbmcgbm8gcGF0dGVybnMgb3IgYmlhcy4gSG93ZXZlciwgdGhlIGZ1bm5lbCBzaGFwZSBzdWdnZXN0cyBoZXRlcm9zY2VkYXN0aWNpdHkgKG5vbi1jb25zdGFudCB2YXJpYW5jZSksIHdoaWNoIG1heSByZXF1aXJlIG1vZGVsIGltcHJvdmVtZW50IG9yIHRyYW5zZm9ybWF0aW9uIG9mIHZhcmlhYmxlcy4NCg0KIyAyLiBQbG90IFJlc2lkdWFscyB2cyBYIHZhbHVlcyANCg0KYGBge3J9DQpwbG90KG1vZGVsLCB3aGljaCA9IDIpDQpgYGANClRoaXMgUS1RIFJlc2lkdWFscyBwbG90IGNvbXBhcmVzIHRoZSBzdGFuZGFyZGl6ZWQgcmVzaWR1YWxzIG9mIHRoZSByZWdyZXNzaW9uIG1vZGVsIHRvIGEgbm9ybWFsIGRpc3RyaWJ1dGlvbi4gVGhlIHBvaW50cyBtb3N0bHkgZm9sbG93IHRoZSBkaWFnb25hbCBsaW5lLCBidXQgZGV2aWF0aW9ucyBhdCB0aGUgdGFpbHMgKGJvdGggZW5kcykgc3VnZ2VzdCB0aGF0IHRoZSByZXNpZHVhbHMgYXJlIG5vdCBwZXJmZWN0bHkgbm9ybWFsbHkgZGlzdHJpYnV0ZWQuDQoNCiMgMy4gU2NhbGUtTG9jYXRpb24gUGxvdA0KYGBge3J9DQpwbG90KG1vZGVsLCB3aGljaCA9IDMpDQpgYGANClRoaXMgKipTY2FsZS1Mb2NhdGlvbiBwbG90KiogaXMgdXNlZCB0byBhc3Nlc3MgdGhlIGFzc3VtcHRpb24gb2YgaG9tb3NjZWRhc3RpY2l0eSAoY29uc3RhbnQgdmFyaWFuY2UpIGluIGEgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwuIFRoZSB4LWF4aXMgcmVwcmVzZW50cyBmaXR0ZWQgdmFsdWVzLCB3aGlsZSB0aGUgeS1heGlzIHNob3dzIHRoZSBzcXVhcmUgcm9vdCBvZiBzdGFuZGFyZGl6ZWQgcmVzaWR1YWxzLiBJZGVhbGx5LCB0aGUgcmVkIGxpbmUgc2hvdWxkIGJlIGhvcml6b250YWwsIGFuZCB0aGUgcG9pbnRzIHNob3VsZCBiZSBldmVubHkgc2NhdHRlcmVkOyBob3dldmVyLCB0aGUgaW5jcmVhc2luZyBzcHJlYWQgc3VnZ2VzdHMgZ3Jvd3RoLCBpbmRpY2F0aW5nIG5vbi1jb25zdGFudCB2YXJpYW5jZSBpbiByZXNpZHVhbHMuDQoNCiMgNC4gQ29vaydzIERpc3RhbmNlDQpgYGB7cn0NCiMgQ29vaydzIERpc3RhbmNlIGJ5IE9ic2VydmF0aW9uDQpwbG90KG1vZGVsLCB3aGljaCA9IDQpDQpgYGANCg0KVGhpcyAqKkNvb2sncyBEaXN0YW5jZSBwbG90KiogaWRlbnRpZmllcyBvYnNlcnZhdGlvbnMgdGhhdCBoYXZlIGEgc2lnbmlmaWNhbnQgaW5mbHVlbmNlIG9uIHRoZSByZWdyZXNzaW9uIG1vZGVsJ3MgZml0dGVkIHZhbHVlcy4gT2JzZXJ2YXRpb25zIDQ3MywgMzIzNiwgYW5kIDM2NjcgaGF2ZSB0aGUgaGlnaGVzdCBDb29rJ3MgRGlzdGFuY2UgdmFsdWVzLCBpbmRpY2F0aW5nIHRoZXkgZXhlcnQgZGlzcHJvcG9ydGlvbmF0ZSBsZXZlcmFnZSBvbiB0aGUgbW9kZWwuIFRoZXNlIHBvaW50cyBzaG91bGQgYmUgaW52ZXN0aWdhdGVkIGZ1cnRoZXIgYXMgdGhleSBhcmUgbGlrZWx5IG91dGxpZXJzIG9yIGluZmx1ZW50aWFsIGRhdGEgcG9pbnRzIGFmZmVjdGluZyB0aGUgc3RhYmlsaXR5IG9mIHRoZSByZWdyZXNzaW9uIHJlc3VsdHMuDQoNCiMgRmluYWxseSwNCg0KV2hpbGUgcGVyZm9ybWluZyB0aGUgYW5hbHlzaXMsIEkgcmVhbGl6ZWQgdGhlIGltcG9ydGFuY2Ugb2YgZ3JhbnVsYXIgYWdncmVnYXRpb24gYW5kIHByb2JhYmlsaXN0aWMgZ3JvdXBpbmcgdG8gY2FwdHVyZSBoaWRkZW4gdHJlbmRzIHdpdGhpbiB0aGUgZGF0YXNldC4gVGhlIGtleSB0YWtlYXdheSB3YXMgdGhhdCBhIHN0cnVjdHVyZWQgYXBwcm9hY2ggdG8gZ3JvdXBpbmcgY2FuIHlpZWxkIHZhbHVhYmxlIGluc2lnaHRzIGludG8gbGFyZ2UgZGF0YXNldHMgd2l0aCBtdWx0aXBsZSBhdHRyaWJ1dGVzLCBndWlkaW5nIGRlY2lzaW9uLW1ha2luZyBmb3IgbXVzaWMgc3RyZWFtaW5nIHBsYXRmb3JtcyBhbmQgYXJ0aXN0cyBhbGlrZS4NCg0KDQoNCg0KDQo=