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
# Listing out all the column_names of the dataset
names(data)
[1] "X" "track_id" "artists" "album_name" "track_name" "popularity"
[7] "duration_ms" "explicit" "danceability" "energy" "key" "loudness"
[13] "mode" "speechiness" "acousticness" "instrumentalness" "liveness" "valence"
[19] "tempo" "time_signature" "track_genre"
# Columns with continuous variables
continuous_vars <- data[, sapply(data, is.numeric)]
names(continuous_vars)
[1] "X" "popularity" "duration_ms" "danceability" "energy" "key"
[7] "loudness" "mode" "speechiness" "acousticness" "instrumentalness" "liveness"
[13] "valence" "tempo" "time_signature"
1. Choose two numeric variables, and pair each one with a column you
built (i.e., calculated based on others)
Creating a new column1 “Beats Per Millisecond(beats)” :
tempo/duration_ms
# Creating a new column "Beats Per Millisecond(beats)" : tempo/duration_ms
data$beats <- data$tempo / data$duration_ms
sum(!is.na(data$beats))
[1] 9000
Creating a new column2 : Energy_Dance_Ratio =
energy/danceability
# Create the new column "Energy_Dance_Ratio"
data$energy_dance_ratio <- data$energy / data$danceability
sum(!is.na(data$energy_dance_ratio))
[1] 9000
Pair 1 (Response vs. Explanatory Variable)
Response Variable: beats (Beats Per Millisecond)
Explanatory Variable: tempo (original column)
Why?: beats is derived from tempo, and we analyze how tempo affects
beats (explanatory -> response).
Pair 2 (Numeric Variables for Analysis)
Original Variable: energy
Created Variable: energy_dance_ratio
Why?: This helps explore whether energy correlates well with a
track’s danceability.
Summarising Pairs
# Summary of Pair 1
summary(data[, c("tempo", "beats")])
tempo beats
Min. : 35.39 Min. :4.096e-05
1st Qu.: 96.45 1st Qu.:4.641e-04
Median :119.97 Median :6.151e-04
Mean :121.75 Mean :6.688e-04
3rd Qu.:143.02 3rd Qu.:7.917e-04
Max. :213.78 Max. :4.456e-03
# Summary of Pair 2
summary(data[, c("energy", "energy_dance_ratio")])
energy energy_dance_ratio
Min. :0.0423 Min. : 0.05763
1st Qu.:0.5830 1st Qu.: 0.80925
Median :0.7290 Median : 1.05939
Mean :0.7207 Mean : 1.31954
3rd Qu.:0.8820 3rd Qu.: 1.56062
Max. :1.0000 Max. :15.39413
2. Plot a visualization for each relationship, and draw some
conclusions based on the plots
# Scatterplot for Pair 1 (beats vs. tempo)
ggplot(data, aes(x = tempo, y = beats)) +
geom_point(color = "blue") +
geom_smooth(method = "lm", se = FALSE, color = "red") +
labs(title = "Beats Per Millisecond vs Tempo", x = "Tempo", y = "Beats Per Millisecond")

The graph shows a positive correlation between tempo and beats per
millisecond, indicating that as the tempo of a track increases, the
frequency of beats per millisecond also tends to rise.
Graph 1: Tempo vs. Beats per Millisecond
Strong positive correlation: There’s a clear linear relationship
between tempo and beats per millisecond, indicating a direct link
between these two metrics.
Data concentration: Most tracks cluster in the lower tempo and beats
per millisecond range, suggesting that moderate-paced songs are more
common in the dataset.
Outlier potential: Any points significantly deviating from the trend
line could represent interesting outliers, possibly indicating unique
rhythmic structures or data anomalies.
Genre insights: The distribution along this line could potentially be
used to categorize or identify different music genres based on their
tempo and beat frequency characteristics.
# Scatterplot for Pair 2 (energy_dance_ratio vs. energy)
ggplot(data, aes(x = energy, y = energy_dance_ratio)) +
geom_point(color = "green") +
geom_smooth(method = "lm", se = FALSE, color = "red") +
labs(title = "Energy-Dance Ratio vs Energy", x = "Energy", y = "Energy-Dance Ratio")

The graph shows a weak positive trend between energy and the
energy-dance ratio, with higher energy tracks occasionally exhibiting
extreme energy-dance ratio values.
Graph 2: Energy vs. Energy-Dance Ratio
Weak positive trend: There’s a slight upward trend in the
energy-dance ratio as energy increases, but the relationship is not
strong or consistent.
High variability: For any given energy level, there’s a wide range of
energy-dance ratios, indicating complex relationships between energy,
danceability, and possibly other factors.
Outliers at high energy: There are notable outliers with very high
energy-dance ratios, particularly for tracks with high energy levels.
These could represent unique or genre-defying tracks.
Clustering patterns: The data points seem to form some vertical
striping or clustering, which might indicate certain preferred or common
combinations of energy and danceability in music production.
3. Calculate the appropriate correlation coefficient for each of
these combinations. Explain why the value makes sense (or doesn’t) based
on the visualization(s)
# For Tempo vs. Beats per Millisecond
cor_tempo_beats <- cor(data$tempo, data$beats, method = "spearman")
# For Energy vs. Energy-Dance Ratio
cor_energy_ratio <- cor(data$energy, data$energy_dance_ratio, method = "spearman")
# Print results
cat("Spearman correlation between Tempo and Beats per Millisecond:", cor_tempo_beats, "\n")
Spearman correlation between Tempo and Beats per Millisecond: 0.6466698
cat("Spearman correlation between Energy and Energy-Dance Ratio:", cor_energy_ratio, "\n")
Spearman correlation between Energy and Energy-Dance Ratio: 0.8675833
Reasons for using Spearman’s correlation:
Non-linear relationships: It can capture monotonic but non-linear
relationships, which may be present in the energy vs. energy-dance ratio
data.
Robustness: It’s less sensitive to outliers, which were observed in
the energy vs. energy-dance ratio scatter plot.
No assumption of normality: Unlike Pearson’s, Spearman’s doesn’t
assume normally distributed variables.
Rank-based: It uses the ranks of the data rather than the actual
values, which can be beneficial when dealing with derived variables like
the energy-dance ratio.
The moderate correlation (0.6470153) between tempo and beats per
millisecond is unexpectedly low, suggesting potential data
inconsistencies or calculation issues that warrant further
investigation.
The strong correlation (0.8679517) between energy and energy-dance
ratio indicates a clear positive relationship, while also implying that
other factors (like danceability) play a role in determining the
energy-dance ratio.
4. Build a confidence interval for each of the response variable(s).
Provide a detailed conclusion of the response variable (i.e., the
population) based on your confidence interval.
# Function to calculate and print confidence interval
ci_analysis <- function(data, variable) {
ci <- t.test(data[[variable]])$conf.int
cat(paste0("95% Confidence Interval for ", variable, ": (",
round(ci[1], 4), ", ", round(ci[2], 4), ")\n"))
mean_val <- mean(data[[variable]], na.rm = TRUE)
cat(paste0("Sample mean: ", round(mean_val, 4), "\n\n"))
}
# Calculate CIs for each variable
ci_analysis(data, "tempo")
95% Confidence Interval for tempo: (121.1228, 122.3844)
Sample mean: 121.7536
ci_analysis(data, "beats")
95% Confidence Interval for beats: (7e-04, 7e-04)
Sample mean: 7e-04
ci_analysis(data, "energy")
95% Confidence Interval for energy: (0.7168, 0.7246)
Sample mean: 0.7207
ci_analysis(data, "energy_dance_ratio")
95% Confidence Interval for energy_dance_ratio: (1.3015, 1.3376)
Sample mean: 1.3195
Interpretation:
Tempo: With 95% confidence, the population mean tempo is between
121.1228 and 122.3844 BPM, with a sample mean of 121.7536 BPM,
indicating a relatively fast average tempo in the dataset.
Beats: The confidence interval and sample mean for beats are both
7e-04, suggesting extremely precise measurement or calculation of this
variable, likely derived directly from tempo.
Energy: The population mean energy level is estimated to be
between 0.7168 and 0.7246, with a sample mean of 0.7207, indicating that
tracks in the dataset tend to have relatively high energy
levels.
Energy-Dance Ratio: The 95% confidence interval for the
energy-dance ratio is 1.3015 to 1.3376, with a sample mean of 1.3195,
suggesting that on average, the energy of tracks tends to be higher than
their danceability.
Using bootstrap in estimating confidence interval
library(boot)
# Bootstrap function
boot_mean <- function(data, indices) {
return(mean(data[indices]))
}
# Function to perform bootstrap and plot results
bootstrap_analysis <- function(data, variable, n_boot = 10000) {
boot_results <- boot(data[[variable]], boot_mean, R = n_boot)
ci <- boot.ci(boot_results, type = "perc")
# Plot histogram of bootstrap means
df <- data.frame(means = boot_results$t)
p <- ggplot(df, aes(x = means)) +
geom_histogram(bins = 30, fill = "skyblue", color = "black") +
geom_vline(xintercept = ci$percent[4:5], color = "red", linetype = "dashed") +
labs(title = paste("Bootstrap Distribution of Mean", variable),
x = "Mean", y = "Frequency") +
theme_minimal()
print(p)
cat(paste0("95% Bootstrap CI for ", variable, ": (",
round(ci$percent[4], 4), ", ", round(ci$percent[5], 4), ")\n"))
cat(paste0("Sample mean: ", round(mean(data[[variable]], na.rm = TRUE), 4), "\n\n"))
}
# Perform bootstrap analysis for each variable
set.seed(123) # for reproducibility
bootstrap_analysis(data, "tempo")
95% Bootstrap CI for tempo: (121.1263, 122.386)
Sample mean: 121.7536

bootstrap_analysis(data, "beats")
95% Bootstrap CI for beats: (7e-04, 7e-04)
Sample mean: 7e-04

bootstrap_analysis(data, "energy")
95% Bootstrap CI for energy: (0.7168, 0.7246)
Sample mean: 0.7207

bootstrap_analysis(data, "energy_dance_ratio")
95% Bootstrap CI for energy_dance_ratio: (1.3017, 1.3376)
Sample mean: 1.3195

Conclusion
Based on the bootstrap analysis of our Spotify dataset, we can draw
the following conclusions:
Tempo: The bootstrap 95% confidence interval for the mean tempo
is narrow, indicating a precise estimate of the average tempo in the
population. The distribution of bootstrap means appears roughly normal,
suggesting robustness in our estimate.
Beats: The extremely narrow confidence interval for beats per
millisecond confirms the direct mathematical relationship with tempo.
The lack of variability in the bootstrap distribution underscores the
deterministic nature of this variable.
Energy: The bootstrap analysis reveals a relatively narrow
confidence interval for mean energy, suggesting consistency in energy
levels across tracks. The symmetrical distribution of bootstrap means
indicates stability in this measure.
Energy-Dance Ratio: The wider confidence interval for the
energy-dance ratio reflects more variability in this derived measure.
The distribution of bootstrap means may show slight skewness, indicating
potential complexity in the relationship between energy and
danceability.
Overall, the bootstrap results provide robust estimates of population
parameters, accounting for potential non-normality and outliers in the
data. These insights offer a more nuanced understanding of the musical
characteristics in our dataset, particularly useful for applications in
music analysis, recommendation systems, or genre classification.
LS0tDQp0aXRsZTogIkRhdGEgRGl2ZSA2Ig0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCmBgYHtyfQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkocmVhZHIpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoY29uZmxpY3RlZCkNCmBgYA0KYGBge3J9DQojUmVhZGluZyB0aGUgZGF0YSBzZXQNCmRhdGEgPC0gcmVhZC5jc3YoImRhdGFzZXQuY3N2IikNCmNvbmZsaWN0ZWQ6OmNvbmZsaWN0c19wcmVmZXIoZHBseXI6OmZpbHRlcikNCiMgRmlsdGVyaW5nIGRhdGFzZXQgd2hlcmUgZXhwbGljaXQgaXMgIlRydWUiIGFuZCB0YWtpbmcgYSBzYW1wbGUgb2YgOSwwMDAgcm93cw0Kc2FtcGxlX2RhdGEgPC0gZGF0YSB8PiBmaWx0ZXIoZXhwbGljaXQgPT0gIlRydWUiKSB8PiBzYW1wbGVfbig5MDAwKQ0KZGF0YSA8LSBzYW1wbGVfZGF0YQ0KZGF0YQ0KYGBgDQpgYGB7cn0gDQojIExpc3Rpbmcgb3V0IGFsbCB0aGUgY29sdW1uX25hbWVzIG9mIHRoZSBkYXRhc2V0DQpuYW1lcyhkYXRhKQ0KYGBgDQpgYGB7cn0NCiMgQ29sdW1ucyB3aXRoIGNvbnRpbnVvdXMgdmFyaWFibGVzDQpjb250aW51b3VzX3ZhcnMgPC0gZGF0YVssIHNhcHBseShkYXRhLCBpcy5udW1lcmljKV0NCm5hbWVzKGNvbnRpbnVvdXNfdmFycykNCmBgYA0KDQoNCg0KDQoNCiMjIyAxLiBDaG9vc2UgdHdvIG51bWVyaWMgdmFyaWFibGVzLCBhbmQgcGFpciBlYWNoIG9uZSB3aXRoIGEgY29sdW1uIHlvdSBidWlsdCAoaS5lLiwgY2FsY3VsYXRlZCBiYXNlZCBvbiBvdGhlcnMpDQoNCg0KIyMjIENyZWF0aW5nIGEgbmV3IGNvbHVtbjEgIkJlYXRzIFBlciBNaWxsaXNlY29uZChiZWF0cykiIDogdGVtcG8vZHVyYXRpb25fbXMNCmBgYHtyfQ0KIyBDcmVhdGluZyBhIG5ldyBjb2x1bW4gIkJlYXRzIFBlciBNaWxsaXNlY29uZChiZWF0cykiIDogdGVtcG8vZHVyYXRpb25fbXMNCmRhdGEkYmVhdHMgPC0gZGF0YSR0ZW1wbyAvIGRhdGEkZHVyYXRpb25fbXMNCnN1bSghaXMubmEoZGF0YSRiZWF0cykpDQpgYGANCg0KIyMjIENyZWF0aW5nIGEgbmV3IGNvbHVtbjIgOiBFbmVyZ3lfRGFuY2VfUmF0aW8gPSBlbmVyZ3kvZGFuY2VhYmlsaXR5DQpgYGB7cn0NCiMgQ3JlYXRlIHRoZSBuZXcgY29sdW1uICJFbmVyZ3lfRGFuY2VfUmF0aW8iDQpkYXRhJGVuZXJneV9kYW5jZV9yYXRpbyA8LSBkYXRhJGVuZXJneSAvIGRhdGEkZGFuY2VhYmlsaXR5DQpzdW0oIWlzLm5hKGRhdGEkZW5lcmd5X2RhbmNlX3JhdGlvKSkNCmBgYA0KDQoNCiMjIyBQYWlyIDEgKFJlc3BvbnNlIHZzLiBFeHBsYW5hdG9yeSBWYXJpYWJsZSkgDQoNClJlc3BvbnNlIFZhcmlhYmxlOiBiZWF0cyAoQmVhdHMgUGVyIE1pbGxpc2Vjb25kKQ0KDQpFeHBsYW5hdG9yeSBWYXJpYWJsZTogdGVtcG8gKG9yaWdpbmFsIGNvbHVtbikNCg0KV2h5PzogYmVhdHMgaXMgZGVyaXZlZCBmcm9tIHRlbXBvLCBhbmQgd2UgYW5hbHl6ZSBob3cgdGVtcG8gYWZmZWN0cyBiZWF0cyAoZXhwbGFuYXRvcnkgLT4gcmVzcG9uc2UpLg0KDQojIyMgUGFpciAyIChOdW1lcmljIFZhcmlhYmxlcyBmb3IgQW5hbHlzaXMpIA0KDQpPcmlnaW5hbCBWYXJpYWJsZTogZW5lcmd5DQoNCkNyZWF0ZWQgVmFyaWFibGU6IGVuZXJneV9kYW5jZV9yYXRpbw0KDQpXaHk/OiBUaGlzIGhlbHBzIGV4cGxvcmUgd2hldGhlciBlbmVyZ3kgY29ycmVsYXRlcyB3ZWxsIHdpdGggYSB0cmFja+KAmXMgZGFuY2VhYmlsaXR5Lg0KDQoNCiMjIyBTdW1tYXJpc2luZyBQYWlycw0KYGBge3J9DQojIFN1bW1hcnkgb2YgUGFpciAxDQpzdW1tYXJ5KGRhdGFbLCBjKCJ0ZW1wbyIsICJiZWF0cyIpXSkNCg0KIyBTdW1tYXJ5IG9mIFBhaXIgMg0Kc3VtbWFyeShkYXRhWywgYygiZW5lcmd5IiwgImVuZXJneV9kYW5jZV9yYXRpbyIpXSkNCg0KYGBgDQoNCg0KIyMjIDIuIFBsb3QgYSB2aXN1YWxpemF0aW9uIGZvciBlYWNoIHJlbGF0aW9uc2hpcCwgYW5kIGRyYXcgc29tZSBjb25jbHVzaW9ucyBiYXNlZCBvbiB0aGUgcGxvdHMNCg0KYGBge3J9DQojIFNjYXR0ZXJwbG90IGZvciBQYWlyIDEgKGJlYXRzIHZzLiB0ZW1wbykNCmdncGxvdChkYXRhLCBhZXMoeCA9IHRlbXBvLCB5ID0gYmVhdHMpKSArDQogIGdlb21fcG9pbnQoY29sb3IgPSAiYmx1ZSIpICsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgY29sb3IgPSAicmVkIikgKw0KICBsYWJzKHRpdGxlID0gIkJlYXRzIFBlciBNaWxsaXNlY29uZCB2cyBUZW1wbyIsIHggPSAiVGVtcG8iLCB5ID0gIkJlYXRzIFBlciBNaWxsaXNlY29uZCIpDQpgYGANClRoZSBncmFwaCBzaG93cyBhIHBvc2l0aXZlIGNvcnJlbGF0aW9uIGJldHdlZW4gdGVtcG8gYW5kIGJlYXRzIHBlciBtaWxsaXNlY29uZCwgaW5kaWNhdGluZyB0aGF0IGFzIHRoZSB0ZW1wbyBvZiBhIHRyYWNrIGluY3JlYXNlcywgdGhlIGZyZXF1ZW5jeSBvZiBiZWF0cyBwZXIgbWlsbGlzZWNvbmQgYWxzbyB0ZW5kcyB0byByaXNlLg0KDQpHcmFwaCAxOiBUZW1wbyB2cy4gQmVhdHMgcGVyIE1pbGxpc2Vjb25kDQoNClN0cm9uZyBwb3NpdGl2ZSBjb3JyZWxhdGlvbjogVGhlcmUncyBhIGNsZWFyIGxpbmVhciByZWxhdGlvbnNoaXAgYmV0d2VlbiB0ZW1wbyBhbmQgYmVhdHMgcGVyIG1pbGxpc2Vjb25kLCBpbmRpY2F0aW5nIGEgZGlyZWN0IGxpbmsgYmV0d2VlbiB0aGVzZSB0d28gbWV0cmljcy4NCg0KRGF0YSBjb25jZW50cmF0aW9uOiBNb3N0IHRyYWNrcyBjbHVzdGVyIGluIHRoZSBsb3dlciB0ZW1wbyBhbmQgYmVhdHMgcGVyIG1pbGxpc2Vjb25kIHJhbmdlLCBzdWdnZXN0aW5nIHRoYXQgbW9kZXJhdGUtcGFjZWQgc29uZ3MgYXJlIG1vcmUgY29tbW9uIGluIHRoZSBkYXRhc2V0Lg0KDQpPdXRsaWVyIHBvdGVudGlhbDogQW55IHBvaW50cyBzaWduaWZpY2FudGx5IGRldmlhdGluZyBmcm9tIHRoZSB0cmVuZCBsaW5lIGNvdWxkIHJlcHJlc2VudCBpbnRlcmVzdGluZyBvdXRsaWVycywgcG9zc2libHkgaW5kaWNhdGluZyB1bmlxdWUgcmh5dGhtaWMgc3RydWN0dXJlcyBvciBkYXRhIGFub21hbGllcy4NCg0KR2VucmUgaW5zaWdodHM6IFRoZSBkaXN0cmlidXRpb24gYWxvbmcgdGhpcyBsaW5lIGNvdWxkIHBvdGVudGlhbGx5IGJlIHVzZWQgdG8gY2F0ZWdvcml6ZSBvciBpZGVudGlmeSBkaWZmZXJlbnQgbXVzaWMgZ2VucmVzIGJhc2VkIG9uIHRoZWlyIHRlbXBvIGFuZCBiZWF0IGZyZXF1ZW5jeSBjaGFyYWN0ZXJpc3RpY3MuDQoNCmBgYHtyfQ0KIyBTY2F0dGVycGxvdCBmb3IgUGFpciAyIChlbmVyZ3lfZGFuY2VfcmF0aW8gdnMuIGVuZXJneSkNCmdncGxvdChkYXRhLCBhZXMoeCA9IGVuZXJneSwgeSA9IGVuZXJneV9kYW5jZV9yYXRpbykpICsNCiAgZ2VvbV9wb2ludChjb2xvciA9ICJncmVlbiIpICsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgY29sb3IgPSAicmVkIikgKw0KICBsYWJzKHRpdGxlID0gIkVuZXJneS1EYW5jZSBSYXRpbyB2cyBFbmVyZ3kiLCB4ID0gIkVuZXJneSIsIHkgPSAiRW5lcmd5LURhbmNlIFJhdGlvIikNCmBgYA0KVGhlIGdyYXBoIHNob3dzIGEgd2VhayBwb3NpdGl2ZSB0cmVuZCBiZXR3ZWVuIGVuZXJneSBhbmQgdGhlIGVuZXJneS1kYW5jZSByYXRpbywgd2l0aCBoaWdoZXIgZW5lcmd5IHRyYWNrcyBvY2Nhc2lvbmFsbHkgZXhoaWJpdGluZyBleHRyZW1lIGVuZXJneS1kYW5jZSByYXRpbyB2YWx1ZXMuDQoNCkdyYXBoIDI6IEVuZXJneSB2cy4gRW5lcmd5LURhbmNlIFJhdGlvDQoNCldlYWsgcG9zaXRpdmUgdHJlbmQ6IFRoZXJlJ3MgYSBzbGlnaHQgdXB3YXJkIHRyZW5kIGluIHRoZSBlbmVyZ3ktZGFuY2UgcmF0aW8gYXMgZW5lcmd5IGluY3JlYXNlcywgYnV0IHRoZSByZWxhdGlvbnNoaXAgaXMgbm90IHN0cm9uZyBvciBjb25zaXN0ZW50Lg0KDQpIaWdoIHZhcmlhYmlsaXR5OiBGb3IgYW55IGdpdmVuIGVuZXJneSBsZXZlbCwgdGhlcmUncyBhIHdpZGUgcmFuZ2Ugb2YgZW5lcmd5LWRhbmNlIHJhdGlvcywgaW5kaWNhdGluZyBjb21wbGV4IHJlbGF0aW9uc2hpcHMgYmV0d2VlbiBlbmVyZ3ksIGRhbmNlYWJpbGl0eSwgYW5kIHBvc3NpYmx5IG90aGVyIGZhY3RvcnMuDQoNCk91dGxpZXJzIGF0IGhpZ2ggZW5lcmd5OiBUaGVyZSBhcmUgbm90YWJsZSBvdXRsaWVycyB3aXRoIHZlcnkgaGlnaCBlbmVyZ3ktZGFuY2UgcmF0aW9zLCBwYXJ0aWN1bGFybHkgZm9yIHRyYWNrcyB3aXRoIGhpZ2ggZW5lcmd5IGxldmVscy4gVGhlc2UgY291bGQgcmVwcmVzZW50IHVuaXF1ZSBvciBnZW5yZS1kZWZ5aW5nIHRyYWNrcy4NCg0KQ2x1c3RlcmluZyBwYXR0ZXJuczogVGhlIGRhdGEgcG9pbnRzIHNlZW0gdG8gZm9ybSBzb21lIHZlcnRpY2FsIHN0cmlwaW5nIG9yIGNsdXN0ZXJpbmcsIHdoaWNoIG1pZ2h0IGluZGljYXRlIGNlcnRhaW4gcHJlZmVycmVkIG9yIGNvbW1vbiBjb21iaW5hdGlvbnMgb2YgZW5lcmd5IGFuZCBkYW5jZWFiaWxpdHkgaW4gbXVzaWMgcHJvZHVjdGlvbi4NCg0KDQoNCg0KIyMjIDMuIENhbGN1bGF0ZSB0aGUgYXBwcm9wcmlhdGUgY29ycmVsYXRpb24gY29lZmZpY2llbnQgZm9yIGVhY2ggb2YgdGhlc2UgY29tYmluYXRpb25zLiBFeHBsYWluIHdoeSB0aGUgdmFsdWUgbWFrZXMgc2Vuc2UgKG9yIGRvZXNuJ3QpIGJhc2VkIG9uIHRoZSB2aXN1YWxpemF0aW9uKHMpDQoNCmBgYHtyfQ0KIyBGb3IgVGVtcG8gdnMuIEJlYXRzIHBlciBNaWxsaXNlY29uZA0KY29yX3RlbXBvX2JlYXRzIDwtIGNvcihkYXRhJHRlbXBvLCBkYXRhJGJlYXRzLCBtZXRob2QgPSAic3BlYXJtYW4iKQ0KDQojIEZvciBFbmVyZ3kgdnMuIEVuZXJneS1EYW5jZSBSYXRpbw0KY29yX2VuZXJneV9yYXRpbyA8LSBjb3IoZGF0YSRlbmVyZ3ksIGRhdGEkZW5lcmd5X2RhbmNlX3JhdGlvLCBtZXRob2QgPSAic3BlYXJtYW4iKQ0KDQojIFByaW50IHJlc3VsdHMNCmNhdCgiU3BlYXJtYW4gY29ycmVsYXRpb24gYmV0d2VlbiBUZW1wbyBhbmQgQmVhdHMgcGVyIE1pbGxpc2Vjb25kOiIsIGNvcl90ZW1wb19iZWF0cywgIlxuIikNCmNhdCgiU3BlYXJtYW4gY29ycmVsYXRpb24gYmV0d2VlbiBFbmVyZ3kgYW5kIEVuZXJneS1EYW5jZSBSYXRpbzoiLCBjb3JfZW5lcmd5X3JhdGlvLCAiXG4iKQ0KDQpgYGANCiMjIyBSZWFzb25zIGZvciB1c2luZyBTcGVhcm1hbidzIGNvcnJlbGF0aW9uOg0KDQpOb24tbGluZWFyIHJlbGF0aW9uc2hpcHM6IEl0IGNhbiBjYXB0dXJlIG1vbm90b25pYyBidXQgbm9uLWxpbmVhciByZWxhdGlvbnNoaXBzLCB3aGljaCBtYXkgYmUgcHJlc2VudCBpbiB0aGUgZW5lcmd5IHZzLiBlbmVyZ3ktZGFuY2UgcmF0aW8gZGF0YS4NCg0KUm9idXN0bmVzczogSXQncyBsZXNzIHNlbnNpdGl2ZSB0byBvdXRsaWVycywgd2hpY2ggd2VyZSBvYnNlcnZlZCBpbiB0aGUgZW5lcmd5IHZzLiBlbmVyZ3ktZGFuY2UgcmF0aW8gc2NhdHRlciBwbG90Lg0KDQpObyBhc3N1bXB0aW9uIG9mIG5vcm1hbGl0eTogVW5saWtlIFBlYXJzb24ncywgU3BlYXJtYW4ncyBkb2Vzbid0IGFzc3VtZSBub3JtYWxseSBkaXN0cmlidXRlZCB2YXJpYWJsZXMuDQoNClJhbmstYmFzZWQ6IEl0IHVzZXMgdGhlIHJhbmtzIG9mIHRoZSBkYXRhIHJhdGhlciB0aGFuIHRoZSBhY3R1YWwgdmFsdWVzLCB3aGljaCBjYW4gYmUgYmVuZWZpY2lhbCB3aGVuIGRlYWxpbmcgd2l0aCBkZXJpdmVkIHZhcmlhYmxlcyBsaWtlIHRoZSBlbmVyZ3ktZGFuY2UgcmF0aW8uDQoNCg0KVGhlIG1vZGVyYXRlIGNvcnJlbGF0aW9uICgwLjY0NzAxNTMpIGJldHdlZW4gdGVtcG8gYW5kIGJlYXRzIHBlciBtaWxsaXNlY29uZCBpcyB1bmV4cGVjdGVkbHkgbG93LCBzdWdnZXN0aW5nIHBvdGVudGlhbCBkYXRhIGluY29uc2lzdGVuY2llcyBvciBjYWxjdWxhdGlvbiBpc3N1ZXMgdGhhdCB3YXJyYW50IGZ1cnRoZXIgaW52ZXN0aWdhdGlvbi4gDQoNClRoZSBzdHJvbmcgY29ycmVsYXRpb24gKDAuODY3OTUxNykgYmV0d2VlbiBlbmVyZ3kgYW5kIGVuZXJneS1kYW5jZSByYXRpbyBpbmRpY2F0ZXMgYSBjbGVhciBwb3NpdGl2ZSByZWxhdGlvbnNoaXAsIHdoaWxlIGFsc28gaW1wbHlpbmcgdGhhdCBvdGhlciBmYWN0b3JzIChsaWtlIGRhbmNlYWJpbGl0eSkgcGxheSBhIHJvbGUgaW4gZGV0ZXJtaW5pbmcgdGhlIGVuZXJneS1kYW5jZSByYXRpby4NCg0KDQojIyMgNC4gQnVpbGQgYSBjb25maWRlbmNlIGludGVydmFsIGZvciBlYWNoIG9mIHRoZSByZXNwb25zZSB2YXJpYWJsZShzKS4gUHJvdmlkZSBhIGRldGFpbGVkIGNvbmNsdXNpb24gb2YgdGhlIHJlc3BvbnNlIHZhcmlhYmxlIChpLmUuLCB0aGUgcG9wdWxhdGlvbikgYmFzZWQgb24geW91ciBjb25maWRlbmNlIGludGVydmFsLg0KDQpgYGB7cn0NCiMgRnVuY3Rpb24gdG8gY2FsY3VsYXRlIGFuZCBwcmludCBjb25maWRlbmNlIGludGVydmFsDQpjaV9hbmFseXNpcyA8LSBmdW5jdGlvbihkYXRhLCB2YXJpYWJsZSkgew0KICBjaSA8LSB0LnRlc3QoZGF0YVtbdmFyaWFibGVdXSkkY29uZi5pbnQNCiAgY2F0KHBhc3RlMCgiOTUlIENvbmZpZGVuY2UgSW50ZXJ2YWwgZm9yICIsIHZhcmlhYmxlLCAiOiAoIiwgDQogICAgICAgICAgICAgcm91bmQoY2lbMV0sIDQpLCAiLCAiLCByb3VuZChjaVsyXSwgNCksICIpXG4iKSkNCiAgDQogIG1lYW5fdmFsIDwtIG1lYW4oZGF0YVtbdmFyaWFibGVdXSwgbmEucm0gPSBUUlVFKQ0KICBjYXQocGFzdGUwKCJTYW1wbGUgbWVhbjogIiwgcm91bmQobWVhbl92YWwsIDQpLCAiXG5cbiIpKQ0KfQ0KDQojIENhbGN1bGF0ZSBDSXMgZm9yIGVhY2ggdmFyaWFibGUNCmNpX2FuYWx5c2lzKGRhdGEsICJ0ZW1wbyIpDQpjaV9hbmFseXNpcyhkYXRhLCAiYmVhdHMiKQ0KY2lfYW5hbHlzaXMoZGF0YSwgImVuZXJneSIpDQpjaV9hbmFseXNpcyhkYXRhLCAiZW5lcmd5X2RhbmNlX3JhdGlvIikNCmBgYA0KDQojIyMgSW50ZXJwcmV0YXRpb246DQoNCjEuIFRlbXBvOiBXaXRoIDk1JSBjb25maWRlbmNlLCB0aGUgcG9wdWxhdGlvbiBtZWFuIHRlbXBvIGlzIGJldHdlZW4gMTIxLjEyMjggYW5kIDEyMi4zODQ0IEJQTSwgd2l0aCBhIHNhbXBsZSBtZWFuIG9mIDEyMS43NTM2IEJQTSwgaW5kaWNhdGluZyBhIHJlbGF0aXZlbHkgZmFzdCBhdmVyYWdlIHRlbXBvIGluIHRoZSBkYXRhc2V0Lg0KDQoyLiBCZWF0czogVGhlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgYW5kIHNhbXBsZSBtZWFuIGZvciBiZWF0cyBhcmUgYm90aCA3ZS0wNCwgc3VnZ2VzdGluZyBleHRyZW1lbHkgcHJlY2lzZSBtZWFzdXJlbWVudCBvciBjYWxjdWxhdGlvbiBvZiB0aGlzIHZhcmlhYmxlLCBsaWtlbHkgZGVyaXZlZCBkaXJlY3RseSBmcm9tIHRlbXBvLg0KDQozLiBFbmVyZ3k6IFRoZSBwb3B1bGF0aW9uIG1lYW4gZW5lcmd5IGxldmVsIGlzIGVzdGltYXRlZCB0byBiZSBiZXR3ZWVuIDAuNzE2OCBhbmQgMC43MjQ2LCB3aXRoIGEgc2FtcGxlIG1lYW4gb2YgMC43MjA3LCBpbmRpY2F0aW5nIHRoYXQgdHJhY2tzIGluIHRoZSBkYXRhc2V0IHRlbmQgdG8gaGF2ZSByZWxhdGl2ZWx5IGhpZ2ggZW5lcmd5IGxldmVscy4NCg0KNC4gRW5lcmd5LURhbmNlIFJhdGlvOiBUaGUgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgZm9yIHRoZSBlbmVyZ3ktZGFuY2UgcmF0aW8gaXMgMS4zMDE1IHRvIDEuMzM3Niwgd2l0aCBhIHNhbXBsZSBtZWFuIG9mIDEuMzE5NSwgc3VnZ2VzdGluZyB0aGF0IG9uIGF2ZXJhZ2UsIHRoZSBlbmVyZ3kgb2YgdHJhY2tzIHRlbmRzIHRvIGJlIGhpZ2hlciB0aGFuIHRoZWlyIGRhbmNlYWJpbGl0eS4NCg0KIyMjIFVzaW5nIGJvb3RzdHJhcCBpbiBlc3RpbWF0aW5nIGNvbmZpZGVuY2UgaW50ZXJ2YWwNCg0KYGBge3J9DQpsaWJyYXJ5KGJvb3QpDQojIEJvb3RzdHJhcCBmdW5jdGlvbg0KYm9vdF9tZWFuIDwtIGZ1bmN0aW9uKGRhdGEsIGluZGljZXMpIHsNCiAgcmV0dXJuKG1lYW4oZGF0YVtpbmRpY2VzXSkpDQp9DQojIEZ1bmN0aW9uIHRvIHBlcmZvcm0gYm9vdHN0cmFwIGFuZCBwbG90IHJlc3VsdHMNCmJvb3RzdHJhcF9hbmFseXNpcyA8LSBmdW5jdGlvbihkYXRhLCB2YXJpYWJsZSwgbl9ib290ID0gMTAwMDApIHsNCiAgYm9vdF9yZXN1bHRzIDwtIGJvb3QoZGF0YVtbdmFyaWFibGVdXSwgYm9vdF9tZWFuLCBSID0gbl9ib290KQ0KICBjaSA8LSBib290LmNpKGJvb3RfcmVzdWx0cywgdHlwZSA9ICJwZXJjIikNCiAgDQogICMgUGxvdCBoaXN0b2dyYW0gb2YgYm9vdHN0cmFwIG1lYW5zDQogIGRmIDwtIGRhdGEuZnJhbWUobWVhbnMgPSBib290X3Jlc3VsdHMkdCkNCiAgcCA8LSBnZ3Bsb3QoZGYsIGFlcyh4ID0gbWVhbnMpKSArDQogICAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDMwLCBmaWxsID0gInNreWJsdWUiLCBjb2xvciA9ICJibGFjayIpICsNCiAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjaSRwZXJjZW50WzQ6NV0sIGNvbG9yID0gInJlZCIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsNCiAgICBsYWJzKHRpdGxlID0gcGFzdGUoIkJvb3RzdHJhcCBEaXN0cmlidXRpb24gb2YgTWVhbiIsIHZhcmlhYmxlKSwNCiAgICAgICAgIHggPSAiTWVhbiIsIHkgPSAiRnJlcXVlbmN5IikgKw0KICAgIHRoZW1lX21pbmltYWwoKQ0KICANCiAgcHJpbnQocCkNCiAgDQogIGNhdChwYXN0ZTAoIjk1JSBCb290c3RyYXAgQ0kgZm9yICIsIHZhcmlhYmxlLCAiOiAoIiwgDQogICAgICAgICAgICAgcm91bmQoY2kkcGVyY2VudFs0XSwgNCksICIsICIsIHJvdW5kKGNpJHBlcmNlbnRbNV0sIDQpLCAiKVxuIikpDQogIGNhdChwYXN0ZTAoIlNhbXBsZSBtZWFuOiAiLCByb3VuZChtZWFuKGRhdGFbW3ZhcmlhYmxlXV0sIG5hLnJtID0gVFJVRSksIDQpLCAiXG5cbiIpKQ0KfQ0KDQojIFBlcmZvcm0gYm9vdHN0cmFwIGFuYWx5c2lzIGZvciBlYWNoIHZhcmlhYmxlDQpzZXQuc2VlZCgxMjMpICAjIGZvciByZXByb2R1Y2liaWxpdHkNCmJvb3RzdHJhcF9hbmFseXNpcyhkYXRhLCAidGVtcG8iKQ0KYm9vdHN0cmFwX2FuYWx5c2lzKGRhdGEsICJiZWF0cyIpDQpib290c3RyYXBfYW5hbHlzaXMoZGF0YSwgImVuZXJneSIpDQpib290c3RyYXBfYW5hbHlzaXMoZGF0YSwgImVuZXJneV9kYW5jZV9yYXRpbyIpDQoNCmBgYA0KDQojIyMgQ29uY2x1c2lvbg0KDQpCYXNlZCBvbiB0aGUgYm9vdHN0cmFwIGFuYWx5c2lzIG9mIG91ciBTcG90aWZ5IGRhdGFzZXQsIHdlIGNhbiBkcmF3IHRoZSBmb2xsb3dpbmcgY29uY2x1c2lvbnM6DQoNCjEuIFRlbXBvOiBUaGUgYm9vdHN0cmFwIDk1JSBjb25maWRlbmNlIGludGVydmFsIGZvciB0aGUgbWVhbiB0ZW1wbyBpcyBuYXJyb3csIGluZGljYXRpbmcgYSBwcmVjaXNlIGVzdGltYXRlIG9mIHRoZSBhdmVyYWdlIHRlbXBvIGluIHRoZSBwb3B1bGF0aW9uLiBUaGUgZGlzdHJpYnV0aW9uIG9mIGJvb3RzdHJhcCBtZWFucyBhcHBlYXJzIHJvdWdobHkgbm9ybWFsLCBzdWdnZXN0aW5nIHJvYnVzdG5lc3MgaW4gb3VyIGVzdGltYXRlLg0KDQoyLiBCZWF0czogVGhlIGV4dHJlbWVseSBuYXJyb3cgY29uZmlkZW5jZSBpbnRlcnZhbCBmb3IgYmVhdHMgcGVyIG1pbGxpc2Vjb25kIGNvbmZpcm1zIHRoZSBkaXJlY3QgbWF0aGVtYXRpY2FsIHJlbGF0aW9uc2hpcCB3aXRoIHRlbXBvLiBUaGUgbGFjayBvZiB2YXJpYWJpbGl0eSBpbiB0aGUgYm9vdHN0cmFwIGRpc3RyaWJ1dGlvbiB1bmRlcnNjb3JlcyB0aGUgZGV0ZXJtaW5pc3RpYyBuYXR1cmUgb2YgdGhpcyB2YXJpYWJsZS4NCg0KMy4gRW5lcmd5OiBUaGUgYm9vdHN0cmFwIGFuYWx5c2lzIHJldmVhbHMgYSByZWxhdGl2ZWx5IG5hcnJvdyBjb25maWRlbmNlIGludGVydmFsIGZvciBtZWFuIGVuZXJneSwgc3VnZ2VzdGluZyBjb25zaXN0ZW5jeSBpbiBlbmVyZ3kgbGV2ZWxzIGFjcm9zcyB0cmFja3MuIFRoZSBzeW1tZXRyaWNhbCBkaXN0cmlidXRpb24gb2YgYm9vdHN0cmFwIG1lYW5zIGluZGljYXRlcyBzdGFiaWxpdHkgaW4gdGhpcyBtZWFzdXJlLg0KDQo0LiBFbmVyZ3ktRGFuY2UgUmF0aW86IFRoZSB3aWRlciBjb25maWRlbmNlIGludGVydmFsIGZvciB0aGUgZW5lcmd5LWRhbmNlIHJhdGlvIHJlZmxlY3RzIG1vcmUgdmFyaWFiaWxpdHkgaW4gdGhpcyBkZXJpdmVkIG1lYXN1cmUuIFRoZSBkaXN0cmlidXRpb24gb2YgYm9vdHN0cmFwIG1lYW5zIG1heSBzaG93IHNsaWdodCBza2V3bmVzcywgaW5kaWNhdGluZyBwb3RlbnRpYWwgY29tcGxleGl0eSBpbiB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gZW5lcmd5IGFuZCBkYW5jZWFiaWxpdHkuDQoNCk92ZXJhbGwsIHRoZSBib290c3RyYXAgcmVzdWx0cyBwcm92aWRlIHJvYnVzdCBlc3RpbWF0ZXMgb2YgcG9wdWxhdGlvbiBwYXJhbWV0ZXJzLCBhY2NvdW50aW5nIGZvciBwb3RlbnRpYWwgbm9uLW5vcm1hbGl0eSBhbmQgb3V0bGllcnMgaW4gdGhlIGRhdGEuIFRoZXNlIGluc2lnaHRzIG9mZmVyIGEgbW9yZSBudWFuY2VkIHVuZGVyc3RhbmRpbmcgb2YgdGhlIG11c2ljYWwgY2hhcmFjdGVyaXN0aWNzIGluIG91ciBkYXRhc2V0LCBwYXJ0aWN1bGFybHkgdXNlZnVsIGZvciBhcHBsaWNhdGlvbnMgaW4gbXVzaWMgYW5hbHlzaXMsIHJlY29tbWVuZGF0aW9uIHN5c3RlbXMsIG9yIGdlbnJlIGNsYXNzaWZpY2F0aW9uLg0KDQo=