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:

  1. 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.

  2. 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.

  3. 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.

  4. 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:

  1. 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.

  2. 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.

  3. 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.

  4. 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=