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.
Key Takeaways
- Energy is the only significant predictor (p <
0.001) and has a strong negative effect on
popularity.
- Danceability and valence are not significant,
meaning they do not reliably predict popularity.
- 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=