Communicating Statistics

1. Introduction & Background

Context: Spotify is a major platform that hosts millions of tracks with rich metadata and audio features.

Objective: To explore factors influencing track popularity, genre characteristics, and artist collaborations.

Purpose: To provide insights for content creators, playlist analysts, playlist designers, and music marketers.

2. Addressing the Problem

  • The goal of this project is to analyze the Spotify music tracks dataset to uncover trends in song popularity, artist collaborations, and genre distribution.

  • By examining relationships between audio features like valence and energy, the project seeks to identify key factors influencing track popularity.

  • Additionally, the project includes creating visualizations to effectively present the insights.

  • The analysis aims to provide actionable insights for music industry stakeholders to better understand audience preferences.

3. Dataset Overview

  • This is a dataset of Spotify tracks over a range of 125 different genres.
  • Each track has some audio features associated with it.
  • Collected from Kaggle.
  • Having 125,000 entries at the beginning, later sampled to 9000 entries based on a binary column data - explicit is “True“

4. Dataset Column Names

Important columns used in the dataset:

track_id, artists, popularity, explicit, danceability, energy, loudness, mode, liveness, valence, tempo, time_signature, track_genre

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(tidyverse)
── Attaching core tidyverse packages ──────────────────────────────────────────────────────────────────────── tidyverse 2.0.0 ──
✔ forcats   1.0.0     ✔ readr     2.1.5
✔ ggplot2   3.5.2     ✔ stringr   1.5.1
✔ lubridate 1.9.4     ✔ tibble    3.2.1
✔ purrr     1.0.4     ✔ tidyr     1.3.1── 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(readr)
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
head(data)

5. Generalised Hypotheses in overall Data

Here are the key hypotheses used in the Spotify music tracks dataset analysis:

  1. Tracks with higher energy tend to have higher popularity. Hypothesis: Energetic tracks are more engaging and thus more frequently streamed.

  2. Danceability and popularity are positively correlated. Hypothesis: Tracks that are easier to dance to are more likely to go viral or be added to playlists.

  3. Genre influences track popularity. Hypothesis: Some genres are more mainstream and favored by the broader Spotify audience.

  4. Combination of high valence and energy increases popularity. Hypothesis: Positive and high-energy songs evoke stronger emotional responses, increasing shareability.

  5. Certain artist collaborations lead to higher popularity. Hypothesis: Collaborative tracks between popular artists attract wider audiences.

6. Assumptions Made

  • Popularity scores (0-100) reflect listener engagement
  • Genre labels are sufficiently representative
  • Missing values have been removed without introducing bias

These assumptions are essential to streamline the analysis and modeling. For instance, while Spotify’s genre tags are vague, we treat them as meaningful categories. Also, popularity is assumed to reflect engagement reliably.

  • Assumed to cover a wide variety of tracks, making it statistically significant for general trends. Accepted due to the broad scope of the dataset.
  • Accepted as it directly correlates with user interactions on the platform.
  • Assumed that higher energy correlates with more intense, faster-paced tracks. Accepted based on established music theory and industry standards.

7. Initial EDA and Visualizations

a) Distribution of Popularity (Histogram)

ggplot(data, aes(x = popularity)) +
  geom_histogram(bins = 30, fill = "blue", alpha = 0.7) +
  labs(title = "Distribution of Popularity", x = "Popularity", y = "Count")

  • Numeric Summaries of Key Columns- popularity, danceability
  • Insight: Popularity is right-skewed with most tracks falling below 60

b) How popularity is co-relating with danceability

ggplot(data, aes(x = danceability, y = popularity)) +
  geom_point(alpha = 0.5, color = "red") +
  theme_minimal() +
  labs(title = "Danceability vs Popularity", x = "Danceability", y = "Popularity")

  • The scatter plot shows a weak positive correlation between danceability and popularity, meaning tracks with higher danceability tend to be more popular but not strongly. The points are widely dispersed, suggesting popularity is influenced by multiple factors beyond danceability.

  • Danceability tends to be moderately high, indicating a general bias toward upbeat tracks.

c) Heatmap of considered factors with resultant variable: popularity

# Select relevant columns for the heatmap (danceability, energy, loudness, tempo, etc.)
df_selected <- data[, c("danceability", "energy", "loudness", "tempo", "popularity")]

# Calculate the correlation matrix for the selected columns
correlation_matrix <- cor(df_selected, use = "complete.obs")

# Create a heatmap to visualize the correlation between danceability and other features
library(reshape2)
library(ggplot2)
library(RColorBrewer)

# Melt the correlation matrix for ggplot2
cor_melted <- melt(correlation_matrix)

# Create a heatmap
heatmap_plot <- ggplot(cor_melted, aes(Var1, Var2, fill = value)) +
  geom_tile() +
  scale_fill_gradient2(low = "blue", high = "red", mid = "white", midpoint = 0) +
  theme_minimal() +
  labs(title = "Correlation Heatmap for Danceability and Other Features",
       x = "Feature", y = "Feature") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

# Display the plot
print(heatmap_plot)

  • This correlation heatmap visualizes the relationships between five audio features: ‘danceability’, ‘energy’, ‘loudness’, ‘tempo’, and ‘popularity’.

  • The color intensity indicates the strength of the correlation, with red representing strong positive correlation (near 1.0) and purple/white indicating weak or no correlation (near 0.0).

  • We observe a strong positive correlation between ‘loudness’ and ‘energy’.

  • ‘Danceability’ shows moderate positive correlations with ‘energy’ and ‘loudness’, but a weak correlation (purple) with ‘energy’.

  • ‘Popularity’ and ‘tempo’ generally exhibit weaker correlations with the other analyzed features.

d) Analysis of factors for Popularity


# Select relevant audio features plus popularity
df_selected <- data[, c("danceability", "energy", "loudness", "tempo", "popularity")]

# Compute correlation matrix
correlation_matrix <- cor(df_selected, use = "complete.obs")

# Extract correlations of popularity with each feature
df_cor <- as.data.frame(correlation_matrix["popularity", ]) %>%
  tibble::rownames_to_column("feature") %>%
  rename(correlation = `correlation_matrix["popularity", ]`) %>%
  filter(feature != "popularity") %>%
  arrange(abs(correlation))

# Plot a horizontal bar chart of Pearson r values
ggplot(df_cor, aes(x = reorder(feature, correlation), y = correlation)) +
  geom_col(fill = "steelblue") +
  coord_flip() +
  labs(
    title = "Correlation of Popularity with Other Audio Features",
    x = NULL,
    y = "Pearson r"
  ) +
  theme_minimal()

The horizontal bar chart shows Pearson correlations between track popularity and four audio features. All effects are very weak (|r|≤0.15), but their signs and relative sizes are informative:

  • Energy (r ≈ –0.13) has the largest magnitude correlation: more energetic tracks tend to be slightly less popular.
  • Loudness (r ≈ –0.05) also correlates negatively with popularity, implying that louder songs are marginally less favored by listeners in this dataset.
  • Tempo (r ≈ +0.03) shows a small positive association, suggesting faster‐paced tracks are a bit more likely to be popular.
  • Danceability (r ≈ +0.05) has the strongest positive correlation of the four, indicating that higher “danceable” scores correspond with marginally higher popularity.

Taken together, these results imply that, within this sample, listeners’ preference skews slightly toward moderately paced, danceable recordings rather than toward heavy, loud, high-energy production.

e) Hypothesis Exploration with Box-Plots

# Create 'key_binary' column: classify key as 'Low' (0-5) or 'High' (6-11)
data$key_binary <- ifelse(data$key <= 5, "Low", "High")

# Convert to a factor for proper ordering
data$key_binary <- factor(data$key_binary, levels = c("Low", "High"))


ggplot(data, aes(x = key_binary, y = danceability, fill = key_binary)) +
  geom_boxplot(alpha = 0.7) +
  labs(title = "Danceability Distribution by Key Type", x = "Key Type", y = "Danceability") +
  theme_minimal()

The boxplot shows that Songs in high key types have a slightly higher median danceability (~0.68) compared to low key types (~0.65), indicating a minor positive effect of key type on danceability.

f) Boxplot of tempo by energy category

energy_threshold <- median(data$energy, na.rm = TRUE)
data$energy_category <- ifelse(data$energy >= energy_threshold, "High Energy", "Low Energy")

ggplot(data, aes(x = energy_category, y = tempo, fill = energy_category)) +
  geom_boxplot(alpha = 0.7) +
  labs(title = "Tempo Distribution by Energy Level", x = "Energy Category", y = "Tempo") +
  theme_minimal()

  • The boxplot shows that high energy songs have a higher median tempo (~130 BPM) than low energy songs (~115 BPM), indicating a clear association between energy level and tempo.

g) Boxplot to explain relation between Popularity and Key Type

# Box plot of Popularity vs Key Type
data$key_grouped <- ifelse(data$mode == 1, "Major", "Minor")
ggplot(data, aes(x = key_grouped, y = popularity, fill = key_grouped)) +
  geom_boxplot() +
  theme_minimal() +
  labs(title = "Popularity by Key Type", x = "Key Type", y = "Popularity") +
  scale_fill_manual(values = c("Major" = "blue", "Minor" = "red"))

  • The box plot visualizes the distribution of popularity scores for songs in Major (blue) and Minor (red) keys. The median popularity is nearly the same for both groups, with a similar interquartile range and spread, indicating that key type (Major or Minor) does not strongly influence popularity.

h) Violin Plot for Tempo Distribution

ggplot(data, aes(x = energy_category, y = tempo, fill = energy_category)) +
  geom_violin(alpha = 0.7) +
  geom_boxplot(width = 0.1, color = "black", outlier.shape = NA) +
  labs(title = "Tempo Distribution by Energy Level",
       x = "Energy Category",
       y = "Tempo (BPM)") +
  theme_minimal() +
  scale_fill_manual(values = c("High Energy" = "#FF5733", "Low Energy" = "#3498DB")) +
  theme(legend.position = "none")

  • This violin plot explains that high energy songs have a higher median tempo (~130BPM) than low energy songs(~115 BPM) indicating that higher energy is associated with faster tempos.

8. Regression Model

8.1. Logistic Regression

logit_model <- glm(mode ~ danceability + energy + tempo, data = data, family = binomial)

# Display model summary
summary(lm_model)

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

Residuals:
    Min      1Q  Median      3Q     Max 
-38.536 -16.037   0.756  19.325  62.067 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept)   32.3093     0.9803  32.960  < 2e-16 ***
danceability   6.4589     1.4866   4.345 1.41e-05 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 24.32 on 8998 degrees of freedom
Multiple R-squared:  0.002093,  Adjusted R-squared:  0.001983 
F-statistic: 18.88 on 1 and 8998 DF,  p-value: 1.41e-05
# Display model coefficients
coef(summary(logit_model))
                  Estimate   Std. Error   z value     Pr(>|z|)
(Intercept)   0.6439072068 0.1752088625  3.675084 2.377716e-04
danceability -0.9555884488 0.1382324699 -6.912909 4.748154e-12
energy        0.2539848178 0.1258129434  2.018750 4.351326e-02
tempo         0.0008446918 0.0007166936  1.178595 2.385593e-01
  • Danceability negatively affects mode, meaning more danceable songs are likely minor.
  • Energy positively affects mode, meaning high-energy songs are more likely major.
  • Tempo has no significant effect.

Significance: These findings suggest that dance-friendly songs tend to have minor tones, while high-energy songs are typically major, influencing music production and recommendation algorithms.

8.2. Linear Regression

model <- lm(popularity ~ danceability + energy + acousticness + valence + tempo + loudness + duration_ms, data = data)
summary(model)

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

Residuals:
    Min      1Q  Median      3Q     Max 
-46.957 -15.592   0.137  18.752  65.750 

Coefficients:
               Estimate Std. Error t value Pr(>|t|)    
(Intercept)   5.978e+01  3.072e+00  19.456  < 2e-16 ***
danceability -4.613e+00  1.860e+00  -2.480 0.013140 *  
energy       -2.700e+01  2.072e+00 -13.032  < 2e-16 ***
acousticness -6.520e-01  1.148e+00  -0.568 0.570210    
valence       2.991e-01  1.246e+00   0.240 0.810208    
tempo         2.858e-02  8.672e-03   3.296 0.000986 ***
loudness      6.300e-01  1.156e-01   5.448 5.22e-08 ***
duration_ms  -1.804e-06  3.027e-06  -0.596 0.551168    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 24.07 on 8992 degrees of freedom
Multiple R-squared:  0.02427,   Adjusted R-squared:  0.02351 
F-statistic: 31.95 on 7 and 8992 DF,  p-value: < 2.2e-16
  • The model is statistically significant overall (F‐statistic = 31.02, p < 2.2e-16), but explains only about 2.36% of the variance in popularity (Adjusted R² = 0.0228).

Conclusion

From all the Data Dives and analysis, we can understand that Popularity of a song or a particular music track, depends on various factors like danceability, tempo, valence, energy and loudness.

For instance, high danceability and energy often make a song more suitable for social settings and dance environments, increasing its chances of being played more frequently.

Similarly, valence, which measures the musical positivity of a track, can affect emotional appeal, while tempo and loudness contribute to the song’s overall intensity and mood.

Future Recommendations: To enrich user experience and musical diversity, it’s recommended that streaming platforms and creators should:

LS0tDQp0aXRsZTogIldlZWstMTMiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQojIENvbW11bmljYXRpbmcgU3RhdGlzdGljcw0KDQoNCg0KIyMgMS4gSW50cm9kdWN0aW9uICYgQmFja2dyb3VuZA0KDQoqKkNvbnRleHQ6KiogU3BvdGlmeSBpcyBhIG1ham9yIHBsYXRmb3JtIHRoYXQgaG9zdHMgbWlsbGlvbnMgb2YgdHJhY2tzIHdpdGggcmljaCBtZXRhZGF0YSBhbmQgYXVkaW8gZmVhdHVyZXMuDQoNCioqT2JqZWN0aXZlOioqIFRvIGV4cGxvcmUgZmFjdG9ycyBpbmZsdWVuY2luZyB0cmFjayBwb3B1bGFyaXR5LCBnZW5yZSBjaGFyYWN0ZXJpc3RpY3MsIGFuZCBhcnRpc3QgY29sbGFib3JhdGlvbnMuDQoNCioqUHVycG9zZToqKiBUbyBwcm92aWRlIGluc2lnaHRzIGZvciBjb250ZW50IGNyZWF0b3JzLCBwbGF5bGlzdCBhbmFseXN0cywgcGxheWxpc3QgZGVzaWduZXJzLCBhbmQgbXVzaWMgbWFya2V0ZXJzLg0KDQoNCiMjIDIuIEFkZHJlc3NpbmcgdGhlIFByb2JsZW0NCg0KLSBUaGUgZ29hbCBvZiB0aGlzIHByb2plY3QgaXMgdG8gYW5hbHl6ZSB0aGUgU3BvdGlmeSBtdXNpYyB0cmFja3MgZGF0YXNldCB0byB1bmNvdmVyIHRyZW5kcyBpbiBzb25nIHBvcHVsYXJpdHksIGFydGlzdCBjb2xsYWJvcmF0aW9ucywgYW5kIGdlbnJlIGRpc3RyaWJ1dGlvbi4gDQoNCi0gQnkgZXhhbWluaW5nIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiBhdWRpbyBmZWF0dXJlcyBsaWtlIHZhbGVuY2UgYW5kIGVuZXJneSwgdGhlIHByb2plY3Qgc2Vla3MgdG8gaWRlbnRpZnkga2V5IGZhY3RvcnMgaW5mbHVlbmNpbmcgdHJhY2sgcG9wdWxhcml0eS4gDQoNCi0gQWRkaXRpb25hbGx5LCB0aGUgcHJvamVjdCBpbmNsdWRlcyBjcmVhdGluZyB2aXN1YWxpemF0aW9ucyB0byBlZmZlY3RpdmVseSBwcmVzZW50IHRoZSBpbnNpZ2h0cy4gDQoNCi0gVGhlIGFuYWx5c2lzIGFpbXMgdG8gcHJvdmlkZSBhY3Rpb25hYmxlIGluc2lnaHRzIGZvciBtdXNpYyBpbmR1c3RyeSBzdGFrZWhvbGRlcnMgdG8gYmV0dGVyIHVuZGVyc3RhbmQgYXVkaWVuY2UgcHJlZmVyZW5jZXMuDQoNCg0KIyMgMy4gRGF0YXNldCBPdmVydmlldw0KDQotIFRoaXMgaXMgYSBkYXRhc2V0IG9mIFNwb3RpZnkgdHJhY2tzIG92ZXIgYSByYW5nZSBvZiAxMjUgZGlmZmVyZW50IGdlbnJlcy4gDQotIEVhY2ggdHJhY2sgaGFzIHNvbWUgYXVkaW8gZmVhdHVyZXMgYXNzb2NpYXRlZCB3aXRoIGl0Lg0KLSBDb2xsZWN0ZWQgZnJvbSBLYWdnbGUuDQotIEhhdmluZyAxMjUsMDAwIGVudHJpZXMgYXQgdGhlIGJlZ2lubmluZywgbGF0ZXIgc2FtcGxlZCB0byA5MDAwIGVudHJpZXMgYmFzZWQgb24gYSBiaW5hcnkgY29sdW1uIGRhdGEgLSBleHBsaWNpdCBpcyAiVHJ1ZeKAnA0KDQoNCiMjIDQuIERhdGFzZXQgQ29sdW1uIE5hbWVzDQoNCkltcG9ydGFudCBjb2x1bW5zIHVzZWQgaW4gdGhlIGRhdGFzZXQ6DQoNCnRyYWNrX2lkLA0KYXJ0aXN0cywNCnBvcHVsYXJpdHksDQpleHBsaWNpdCwNCmRhbmNlYWJpbGl0eSwNCmVuZXJneSwNCmxvdWRuZXNzLA0KbW9kZSwNCmxpdmVuZXNzLA0KdmFsZW5jZSwNCnRlbXBvLA0KdGltZV9zaWduYXR1cmUsDQp0cmFja19nZW5yZQ0KDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkocmVhZHIpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGNvbmZsaWN0ZWQpDQpgYGANCg0KDQpgYGB7cn0NCiNSZWFkaW5nIHRoZSBkYXRhIHNldA0KZGF0YSA8LSByZWFkLmNzdigiZGF0YXNldC5jc3YiKQ0KY29uZmxpY3RlZDo6Y29uZmxpY3RzX3ByZWZlcihkcGx5cjo6ZmlsdGVyKQ0KIyBGaWx0ZXJpbmcgZGF0YXNldCB3aGVyZSBleHBsaWNpdCBpcyAiVHJ1ZSIgYW5kIHRha2luZyBhIHNhbXBsZSBvZiA5LDAwMCByb3dzDQpzYW1wbGVfZGF0YSA8LSBkYXRhIHw+IGZpbHRlcihleHBsaWNpdCA9PSAiVHJ1ZSIpIHw+IHNhbXBsZV9uKDkwMDApDQpkYXRhIDwtIHNhbXBsZV9kYXRhDQpgYGANCg0KYGBge3J9DQpoZWFkKGRhdGEpDQpgYGANCg0KDQojIyMgNS4gR2VuZXJhbGlzZWQgSHlwb3RoZXNlcyBpbiBvdmVyYWxsIERhdGENCg0KSGVyZSBhcmUgdGhlIGtleSBoeXBvdGhlc2VzIHVzZWQgaW4gdGhlIFNwb3RpZnkgbXVzaWMgdHJhY2tzIGRhdGFzZXQgYW5hbHlzaXM6DQoNCjEuIFRyYWNrcyB3aXRoIGhpZ2hlciBlbmVyZ3kgdGVuZCB0byBoYXZlIGhpZ2hlciBwb3B1bGFyaXR5Lg0KSHlwb3RoZXNpczogRW5lcmdldGljIHRyYWNrcyBhcmUgbW9yZSBlbmdhZ2luZyBhbmQgdGh1cyBtb3JlIGZyZXF1ZW50bHkgc3RyZWFtZWQuDQoNCjIuIERhbmNlYWJpbGl0eSBhbmQgcG9wdWxhcml0eSBhcmUgcG9zaXRpdmVseSBjb3JyZWxhdGVkLg0KSHlwb3RoZXNpczogVHJhY2tzIHRoYXQgYXJlIGVhc2llciB0byBkYW5jZSB0byBhcmUgbW9yZSBsaWtlbHkgdG8gZ28gdmlyYWwgb3IgYmUgYWRkZWQgdG8gcGxheWxpc3RzLg0KDQozLiBHZW5yZSBpbmZsdWVuY2VzIHRyYWNrIHBvcHVsYXJpdHkuDQpIeXBvdGhlc2lzOiBTb21lIGdlbnJlcyBhcmUgbW9yZSBtYWluc3RyZWFtIGFuZCBmYXZvcmVkIGJ5IHRoZSBicm9hZGVyIFNwb3RpZnkgYXVkaWVuY2UuDQoNCjQuIENvbWJpbmF0aW9uIG9mIGhpZ2ggdmFsZW5jZSBhbmQgZW5lcmd5IGluY3JlYXNlcyBwb3B1bGFyaXR5LiANCkh5cG90aGVzaXM6IFBvc2l0aXZlIGFuZCBoaWdoLWVuZXJneSBzb25ncyBldm9rZSBzdHJvbmdlciBlbW90aW9uYWwgcmVzcG9uc2VzLCBpbmNyZWFzaW5nIHNoYXJlYWJpbGl0eS4NCiANCjUuIENlcnRhaW4gYXJ0aXN0IGNvbGxhYm9yYXRpb25zIGxlYWQgdG8gaGlnaGVyIHBvcHVsYXJpdHkuDQpIeXBvdGhlc2lzOiBDb2xsYWJvcmF0aXZlIHRyYWNrcyBiZXR3ZWVuIHBvcHVsYXIgYXJ0aXN0cyBhdHRyYWN0IHdpZGVyIGF1ZGllbmNlcy4NCg0KDQojIyA2LiBBc3N1bXB0aW9ucyBNYWRlDQoNCi0gUG9wdWxhcml0eSBzY29yZXMgKDAtMTAwKSByZWZsZWN0IGxpc3RlbmVyIGVuZ2FnZW1lbnQNCi0gR2VucmUgbGFiZWxzIGFyZSBzdWZmaWNpZW50bHkgcmVwcmVzZW50YXRpdmUNCi0gTWlzc2luZyB2YWx1ZXMgaGF2ZSBiZWVuIHJlbW92ZWQgd2l0aG91dCBpbnRyb2R1Y2luZyBiaWFzDQoNClRoZXNlIGFzc3VtcHRpb25zIGFyZSBlc3NlbnRpYWwgdG8gc3RyZWFtbGluZSB0aGUgYW5hbHlzaXMgYW5kIG1vZGVsaW5nLiBGb3IgaW5zdGFuY2UsIHdoaWxlIFNwb3RpZnkncyBnZW5yZSB0YWdzIGFyZSB2YWd1ZSwgd2UgdHJlYXQgdGhlbSBhcyBtZWFuaW5nZnVsIGNhdGVnb3JpZXMuIEFsc28sIHBvcHVsYXJpdHkgaXMgYXNzdW1lZCB0byByZWZsZWN0IGVuZ2FnZW1lbnQgcmVsaWFibHkuDQoNCi0gQXNzdW1lZCB0byBjb3ZlciBhIHdpZGUgdmFyaWV0eSBvZiB0cmFja3MsIG1ha2luZyBpdCBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IGZvciBnZW5lcmFsIHRyZW5kcy4gQWNjZXB0ZWQgZHVlIHRvIHRoZSBicm9hZCBzY29wZSBvZiB0aGUgZGF0YXNldC4NCi0gQWNjZXB0ZWQgYXMgaXQgZGlyZWN0bHkgY29ycmVsYXRlcyB3aXRoIHVzZXIgaW50ZXJhY3Rpb25zIG9uIHRoZSBwbGF0Zm9ybS4NCi0gQXNzdW1lZCB0aGF0IGhpZ2hlciBlbmVyZ3kgY29ycmVsYXRlcyB3aXRoIG1vcmUgaW50ZW5zZSwgZmFzdGVyLXBhY2VkIHRyYWNrcy4gQWNjZXB0ZWQgYmFzZWQgb24gZXN0YWJsaXNoZWQgbXVzaWMgdGhlb3J5IGFuZCBpbmR1c3RyeSBzdGFuZGFyZHMuDQoNCg0KIyMgNy4gSW5pdGlhbCBFREEgYW5kIFZpc3VhbGl6YXRpb25zDQoNCiMjIyBhKSBEaXN0cmlidXRpb24gb2YgUG9wdWxhcml0eSAoSGlzdG9ncmFtKQ0KDQpgYGB7cn0NCmdncGxvdChkYXRhLCBhZXMoeCA9IHBvcHVsYXJpdHkpKSArDQogIGdlb21faGlzdG9ncmFtKGJpbnMgPSAzMCwgZmlsbCA9ICJibHVlIiwgYWxwaGEgPSAwLjcpICsNCiAgbGFicyh0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgUG9wdWxhcml0eSIsIHggPSAiUG9wdWxhcml0eSIsIHkgPSAiQ291bnQiKQ0KYGBgDQoNCi0gTnVtZXJpYyBTdW1tYXJpZXMgb2YgS2V5IENvbHVtbnMtIHBvcHVsYXJpdHksIGRhbmNlYWJpbGl0eQ0KLSBJbnNpZ2h0OiBQb3B1bGFyaXR5IGlzIHJpZ2h0LXNrZXdlZCB3aXRoIG1vc3QgdHJhY2tzIGZhbGxpbmcgYmVsb3cgNjANCg0KDQojIyMgYikgSG93IHBvcHVsYXJpdHkgaXMgY28tcmVsYXRpbmcgd2l0aCBkYW5jZWFiaWxpdHkNCmBgYHtyfQ0KZ2dwbG90KGRhdGEsIGFlcyh4ID0gZGFuY2VhYmlsaXR5LCB5ID0gcG9wdWxhcml0eSkpICsNCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNSwgY29sb3IgPSAicmVkIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICBsYWJzKHRpdGxlID0gIkRhbmNlYWJpbGl0eSB2cyBQb3B1bGFyaXR5IiwgeCA9ICJEYW5jZWFiaWxpdHkiLCB5ID0gIlBvcHVsYXJpdHkiKQ0KYGBgDQotIFRoZSBzY2F0dGVyIHBsb3Qgc2hvd3MgYSB3ZWFrIHBvc2l0aXZlIGNvcnJlbGF0aW9uIGJldHdlZW4gZGFuY2VhYmlsaXR5IGFuZCBwb3B1bGFyaXR5LCBtZWFuaW5nIHRyYWNrcyB3aXRoIGhpZ2hlciBkYW5jZWFiaWxpdHkgdGVuZCB0byBiZSBtb3JlIHBvcHVsYXIgYnV0IG5vdCBzdHJvbmdseS4gVGhlIHBvaW50cyBhcmUgd2lkZWx5IGRpc3BlcnNlZCwgc3VnZ2VzdGluZyBwb3B1bGFyaXR5IGlzIGluZmx1ZW5jZWQgYnkgbXVsdGlwbGUgZmFjdG9ycyBiZXlvbmQgZGFuY2VhYmlsaXR5LiANCg0KLSBEYW5jZWFiaWxpdHkgdGVuZHMgdG8gYmUgbW9kZXJhdGVseSBoaWdoLCBpbmRpY2F0aW5nIGEgZ2VuZXJhbCBiaWFzIHRvd2FyZCB1cGJlYXQgdHJhY2tzLg0KDQoNCg0KIyMjIGMpIEhlYXRtYXAgb2YgY29uc2lkZXJlZCBmYWN0b3JzIHdpdGggcmVzdWx0YW50IHZhcmlhYmxlOiBwb3B1bGFyaXR5DQoNCmBgYHtyfQ0KIyBTZWxlY3QgcmVsZXZhbnQgY29sdW1ucyBmb3IgdGhlIGhlYXRtYXAgKGRhbmNlYWJpbGl0eSwgZW5lcmd5LCBsb3VkbmVzcywgdGVtcG8sIGV0Yy4pDQpkZl9zZWxlY3RlZCA8LSBkYXRhWywgYygiZGFuY2VhYmlsaXR5IiwgImVuZXJneSIsICJsb3VkbmVzcyIsICJ0ZW1wbyIsICJwb3B1bGFyaXR5IildDQoNCiMgQ2FsY3VsYXRlIHRoZSBjb3JyZWxhdGlvbiBtYXRyaXggZm9yIHRoZSBzZWxlY3RlZCBjb2x1bW5zDQpjb3JyZWxhdGlvbl9tYXRyaXggPC0gY29yKGRmX3NlbGVjdGVkLCB1c2UgPSAiY29tcGxldGUub2JzIikNCg0KIyBDcmVhdGUgYSBoZWF0bWFwIHRvIHZpc3VhbGl6ZSB0aGUgY29ycmVsYXRpb24gYmV0d2VlbiBkYW5jZWFiaWxpdHkgYW5kIG90aGVyIGZlYXR1cmVzDQpsaWJyYXJ5KHJlc2hhcGUyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShSQ29sb3JCcmV3ZXIpDQoNCiMgTWVsdCB0aGUgY29ycmVsYXRpb24gbWF0cml4IGZvciBnZ3Bsb3QyDQpjb3JfbWVsdGVkIDwtIG1lbHQoY29ycmVsYXRpb25fbWF0cml4KQ0KDQojIENyZWF0ZSBhIGhlYXRtYXANCmhlYXRtYXBfcGxvdCA8LSBnZ3Bsb3QoY29yX21lbHRlZCwgYWVzKFZhcjEsIFZhcjIsIGZpbGwgPSB2YWx1ZSkpICsNCiAgZ2VvbV90aWxlKCkgKw0KICBzY2FsZV9maWxsX2dyYWRpZW50Mihsb3cgPSAiYmx1ZSIsIGhpZ2ggPSAicmVkIiwgbWlkID0gIndoaXRlIiwgbWlkcG9pbnQgPSAwKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIGxhYnModGl0bGUgPSAiQ29ycmVsYXRpb24gSGVhdG1hcCBmb3IgRGFuY2VhYmlsaXR5IGFuZCBPdGhlciBGZWF0dXJlcyIsDQogICAgICAgeCA9ICJGZWF0dXJlIiwgeSA9ICJGZWF0dXJlIikgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQ0KDQojIERpc3BsYXkgdGhlIHBsb3QNCnByaW50KGhlYXRtYXBfcGxvdCkNCmBgYA0KLSBUaGlzIGNvcnJlbGF0aW9uIGhlYXRtYXAgdmlzdWFsaXplcyB0aGUgcmVsYXRpb25zaGlwcyBiZXR3ZWVuIGZpdmUgYXVkaW8gZmVhdHVyZXM6ICdkYW5jZWFiaWxpdHknLCAnZW5lcmd5JywgJ2xvdWRuZXNzJywgJ3RlbXBvJywgYW5kICdwb3B1bGFyaXR54oCZLg0KDQotIFRoZSBjb2xvciBpbnRlbnNpdHkgaW5kaWNhdGVzIHRoZSBzdHJlbmd0aCBvZiB0aGUgY29ycmVsYXRpb24sIHdpdGggcmVkIHJlcHJlc2VudGluZyBzdHJvbmcgcG9zaXRpdmUgY29ycmVsYXRpb24gKG5lYXIgMS4wKSBhbmQgcHVycGxlL3doaXRlIGluZGljYXRpbmcgd2VhayBvciBubyBjb3JyZWxhdGlvbiAobmVhciAwLjApLg0KDQotIFdlIG9ic2VydmUgYSBzdHJvbmcgcG9zaXRpdmUgY29ycmVsYXRpb24gYmV0d2VlbiAnbG91ZG5lc3MnIGFuZCAnZW5lcmd54oCZLiANCg0KLSDigJhEYW5jZWFiaWxpdHknIHNob3dzIG1vZGVyYXRlIHBvc2l0aXZlIGNvcnJlbGF0aW9ucyB3aXRoICdlbmVyZ3knIGFuZCAnbG91ZG5lc3MnLCBidXQgYSB3ZWFrIGNvcnJlbGF0aW9uIChwdXJwbGUpIHdpdGggJ2VuZXJneeKAmS4NCg0KLSAnUG9wdWxhcml0eScgYW5kICd0ZW1wbycgZ2VuZXJhbGx5IGV4aGliaXQgd2Vha2VyIGNvcnJlbGF0aW9ucyB3aXRoIHRoZSBvdGhlciBhbmFseXplZCBmZWF0dXJlcy4NCg0KDQoNCiMjIyBkKSBBbmFseXNpcyBvZiBmYWN0b3JzIGZvciBQb3B1bGFyaXR5DQoNCmBgYHtyfQ0KDQojIFNlbGVjdCByZWxldmFudCBhdWRpbyBmZWF0dXJlcyBwbHVzIHBvcHVsYXJpdHkNCmRmX3NlbGVjdGVkIDwtIGRhdGFbLCBjKCJkYW5jZWFiaWxpdHkiLCAiZW5lcmd5IiwgImxvdWRuZXNzIiwgInRlbXBvIiwgInBvcHVsYXJpdHkiKV0NCg0KIyBDb21wdXRlIGNvcnJlbGF0aW9uIG1hdHJpeA0KY29ycmVsYXRpb25fbWF0cml4IDwtIGNvcihkZl9zZWxlY3RlZCwgdXNlID0gImNvbXBsZXRlLm9icyIpDQoNCiMgRXh0cmFjdCBjb3JyZWxhdGlvbnMgb2YgcG9wdWxhcml0eSB3aXRoIGVhY2ggZmVhdHVyZQ0KZGZfY29yIDwtIGFzLmRhdGEuZnJhbWUoY29ycmVsYXRpb25fbWF0cml4WyJwb3B1bGFyaXR5IiwgXSkgJT4lDQogIHRpYmJsZTo6cm93bmFtZXNfdG9fY29sdW1uKCJmZWF0dXJlIikgJT4lDQogIHJlbmFtZShjb3JyZWxhdGlvbiA9IGBjb3JyZWxhdGlvbl9tYXRyaXhbInBvcHVsYXJpdHkiLCBdYCkgJT4lDQogIGZpbHRlcihmZWF0dXJlICE9ICJwb3B1bGFyaXR5IikgJT4lDQogIGFycmFuZ2UoYWJzKGNvcnJlbGF0aW9uKSkNCg0KIyBQbG90IGEgaG9yaXpvbnRhbCBiYXIgY2hhcnQgb2YgUGVhcnNvbiByIHZhbHVlcw0KZ2dwbG90KGRmX2NvciwgYWVzKHggPSByZW9yZGVyKGZlYXR1cmUsIGNvcnJlbGF0aW9uKSwgeSA9IGNvcnJlbGF0aW9uKSkgKw0KICBnZW9tX2NvbChmaWxsID0gInN0ZWVsYmx1ZSIpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJDb3JyZWxhdGlvbiBvZiBQb3B1bGFyaXR5IHdpdGggT3RoZXIgQXVkaW8gRmVhdHVyZXMiLA0KICAgIHggPSBOVUxMLA0KICAgIHkgPSAiUGVhcnNvbiByIg0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCmBgYA0KDQpUaGUgaG9yaXpvbnRhbCBiYXIgY2hhcnQgc2hvd3MgUGVhcnNvbiBjb3JyZWxhdGlvbnMgYmV0d2VlbiB0cmFjayBwb3B1bGFyaXR5IGFuZCBmb3VyIGF1ZGlvIGZlYXR1cmVzLiBBbGwgZWZmZWN0cyBhcmUgdmVyeSB3ZWFrICh8cnziiaQwLjE1KSwgYnV0IHRoZWlyIHNpZ25zIGFuZCByZWxhdGl2ZSBzaXplcyBhcmUgaW5mb3JtYXRpdmU6DQoNCi0gRW5lcmd5IChyIOKJiCDigJMwLjEzKSBoYXMgdGhlIGxhcmdlc3QgbWFnbml0dWRlIGNvcnJlbGF0aW9uOiBtb3JlIGVuZXJnZXRpYyB0cmFja3MgdGVuZCB0byBiZSBzbGlnaHRseSBsZXNzIHBvcHVsYXIuICANCi0gTG91ZG5lc3MgKHIg4omIIOKAkzAuMDUpIGFsc28gY29ycmVsYXRlcyBuZWdhdGl2ZWx5IHdpdGggcG9wdWxhcml0eSwgaW1wbHlpbmcgdGhhdCBsb3VkZXIgc29uZ3MgYXJlIG1hcmdpbmFsbHkgbGVzcyBmYXZvcmVkIGJ5IGxpc3RlbmVycyBpbiB0aGlzIGRhdGFzZXQuDQotIFRlbXBvIChyIOKJiCArMC4wMykgc2hvd3MgYSBzbWFsbCBwb3NpdGl2ZSBhc3NvY2lhdGlvbiwgc3VnZ2VzdGluZyBmYXN0ZXLigJBwYWNlZCB0cmFja3MgYXJlIGEgYml0IG1vcmUgbGlrZWx5IHRvIGJlIHBvcHVsYXIuICANCi0gRGFuY2VhYmlsaXR5IChyIOKJiCArMC4wNSkgaGFzIHRoZSBzdHJvbmdlc3QgcG9zaXRpdmUgY29ycmVsYXRpb24gb2YgdGhlIGZvdXIsIGluZGljYXRpbmcgdGhhdCBoaWdoZXIg4oCcZGFuY2VhYmxl4oCdIHNjb3JlcyBjb3JyZXNwb25kIHdpdGggbWFyZ2luYWxseSBoaWdoZXIgcG9wdWxhcml0eS4gIA0KDQpUYWtlbiB0b2dldGhlciwgdGhlc2UgcmVzdWx0cyBpbXBseSB0aGF0LCB3aXRoaW4gdGhpcyBzYW1wbGUsIGxpc3RlbmVycycgcHJlZmVyZW5jZSBza2V3cyBzbGlnaHRseSB0b3dhcmQgbW9kZXJhdGVseSBwYWNlZCwgZGFuY2VhYmxlIHJlY29yZGluZ3MgcmF0aGVyIHRoYW4gdG93YXJkIGhlYXZ5LCBsb3VkLCBoaWdoLWVuZXJneSBwcm9kdWN0aW9uLiANCg0KDQojIyMgIGUpIEh5cG90aGVzaXMgRXhwbG9yYXRpb24gd2l0aCBCb3gtUGxvdHMNCg0KYGBge3J9DQojIENyZWF0ZSAna2V5X2JpbmFyeScgY29sdW1uOiBjbGFzc2lmeSBrZXkgYXMgJ0xvdycgKDAtNSkgb3IgJ0hpZ2gnICg2LTExKQ0KZGF0YSRrZXlfYmluYXJ5IDwtIGlmZWxzZShkYXRhJGtleSA8PSA1LCAiTG93IiwgIkhpZ2giKQ0KDQojIENvbnZlcnQgdG8gYSBmYWN0b3IgZm9yIHByb3BlciBvcmRlcmluZw0KZGF0YSRrZXlfYmluYXJ5IDwtIGZhY3RvcihkYXRhJGtleV9iaW5hcnksIGxldmVscyA9IGMoIkxvdyIsICJIaWdoIikpDQoNCg0KZ2dwbG90KGRhdGEsIGFlcyh4ID0ga2V5X2JpbmFyeSwgeSA9IGRhbmNlYWJpbGl0eSwgZmlsbCA9IGtleV9iaW5hcnkpKSArDQogIGdlb21fYm94cGxvdChhbHBoYSA9IDAuNykgKw0KICBsYWJzKHRpdGxlID0gIkRhbmNlYWJpbGl0eSBEaXN0cmlidXRpb24gYnkgS2V5IFR5cGUiLCB4ID0gIktleSBUeXBlIiwgeSA9ICJEYW5jZWFiaWxpdHkiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNClRoZSBib3hwbG90IHNob3dzIHRoYXQgU29uZ3MgaW4gaGlnaCBrZXkgdHlwZXMgaGF2ZSBhIHNsaWdodGx5IGhpZ2hlciBtZWRpYW4gZGFuY2VhYmlsaXR5ICh+MC42OCkgY29tcGFyZWQgdG8gbG93IGtleSB0eXBlcyAofjAuNjUpLCBpbmRpY2F0aW5nIGEgbWlub3IgcG9zaXRpdmUgZWZmZWN0IG9mIGtleSB0eXBlIG9uIGRhbmNlYWJpbGl0eS4NCg0KIyMjIGYpICBCb3hwbG90IG9mIHRlbXBvIGJ5IGVuZXJneSBjYXRlZ29yeQ0KDQpgYGB7cn0NCmVuZXJneV90aHJlc2hvbGQgPC0gbWVkaWFuKGRhdGEkZW5lcmd5LCBuYS5ybSA9IFRSVUUpDQpkYXRhJGVuZXJneV9jYXRlZ29yeSA8LSBpZmVsc2UoZGF0YSRlbmVyZ3kgPj0gZW5lcmd5X3RocmVzaG9sZCwgIkhpZ2ggRW5lcmd5IiwgIkxvdyBFbmVyZ3kiKQ0KDQpnZ3Bsb3QoZGF0YSwgYWVzKHggPSBlbmVyZ3lfY2F0ZWdvcnksIHkgPSB0ZW1wbywgZmlsbCA9IGVuZXJneV9jYXRlZ29yeSkpICsNCiAgZ2VvbV9ib3hwbG90KGFscGhhID0gMC43KSArDQogIGxhYnModGl0bGUgPSAiVGVtcG8gRGlzdHJpYnV0aW9uIGJ5IEVuZXJneSBMZXZlbCIsIHggPSAiRW5lcmd5IENhdGVnb3J5IiwgeSA9ICJUZW1wbyIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KLSBUaGUgYm94cGxvdCBzaG93cyB0aGF0IGhpZ2ggZW5lcmd5IHNvbmdzIGhhdmUgYSBoaWdoZXIgbWVkaWFuIHRlbXBvICh+MTMwIEJQTSkgdGhhbiBsb3cgZW5lcmd5IHNvbmdzICh+MTE1IEJQTSksIGluZGljYXRpbmcgYSBjbGVhciBhc3NvY2lhdGlvbiBiZXR3ZWVuIGVuZXJneSBsZXZlbCBhbmQgdGVtcG8uDQoNCg0KIyMjIGcpIEJveHBsb3QgdG8gZXhwbGFpbiByZWxhdGlvbiBiZXR3ZWVuIFBvcHVsYXJpdHkgYW5kIEtleSBUeXBlDQpgYGB7cn0NCiMgQm94IHBsb3Qgb2YgUG9wdWxhcml0eSB2cyBLZXkgVHlwZQ0KZGF0YSRrZXlfZ3JvdXBlZCA8LSBpZmVsc2UoZGF0YSRtb2RlID09IDEsICJNYWpvciIsICJNaW5vciIpDQpnZ3Bsb3QoZGF0YSwgYWVzKHggPSBrZXlfZ3JvdXBlZCwgeSA9IHBvcHVsYXJpdHksIGZpbGwgPSBrZXlfZ3JvdXBlZCkpICsNCiAgZ2VvbV9ib3hwbG90KCkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICBsYWJzKHRpdGxlID0gIlBvcHVsYXJpdHkgYnkgS2V5IFR5cGUiLCB4ID0gIktleSBUeXBlIiwgeSA9ICJQb3B1bGFyaXR5IikgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJNYWpvciIgPSAiYmx1ZSIsICJNaW5vciIgPSAicmVkIikpDQpgYGANCg0KLSBUaGUgYm94IHBsb3QgdmlzdWFsaXplcyB0aGUgZGlzdHJpYnV0aW9uIG9mIHBvcHVsYXJpdHkgc2NvcmVzIGZvciBzb25ncyBpbiBNYWpvciAoYmx1ZSkgYW5kIE1pbm9yIChyZWQpIGtleXMuIFRoZSBtZWRpYW4gcG9wdWxhcml0eSBpcyBuZWFybHkgdGhlIHNhbWUgZm9yIGJvdGggZ3JvdXBzLCB3aXRoIGEgc2ltaWxhciBpbnRlcnF1YXJ0aWxlIHJhbmdlIGFuZCBzcHJlYWQsIGluZGljYXRpbmcgdGhhdCBrZXkgdHlwZSAoTWFqb3Igb3IgTWlub3IpIGRvZXMgbm90IHN0cm9uZ2x5IGluZmx1ZW5jZSBwb3B1bGFyaXR5Lg0KDQoNCiMjIyBoKSBWaW9saW4gUGxvdCBmb3IgVGVtcG8gRGlzdHJpYnV0aW9uDQpgYGB7cn0NCmdncGxvdChkYXRhLCBhZXMoeCA9IGVuZXJneV9jYXRlZ29yeSwgeSA9IHRlbXBvLCBmaWxsID0gZW5lcmd5X2NhdGVnb3J5KSkgKw0KICBnZW9tX3Zpb2xpbihhbHBoYSA9IDAuNykgKw0KICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjEsIGNvbG9yID0gImJsYWNrIiwgb3V0bGllci5zaGFwZSA9IE5BKSArDQogIGxhYnModGl0bGUgPSAiVGVtcG8gRGlzdHJpYnV0aW9uIGJ5IEVuZXJneSBMZXZlbCIsDQogICAgICAgeCA9ICJFbmVyZ3kgQ2F0ZWdvcnkiLA0KICAgICAgIHkgPSAiVGVtcG8gKEJQTSkiKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIkhpZ2ggRW5lcmd5IiA9ICIjRkY1NzMzIiwgIkxvdyBFbmVyZ3kiID0gIiMzNDk4REIiKSkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQpgYGANCi0gVGhpcyB2aW9saW4gcGxvdCBleHBsYWlucyB0aGF0IGhpZ2ggZW5lcmd5IHNvbmdzIGhhdmUgYSBoaWdoZXIgbWVkaWFuIHRlbXBvICh+MTMwQlBNKSB0aGFuIGxvdyBlbmVyZ3kgc29uZ3MofjExNSBCUE0pIGluZGljYXRpbmcgdGhhdCBoaWdoZXIgZW5lcmd5IGlzIGFzc29jaWF0ZWQgd2l0aCBmYXN0ZXIgdGVtcG9zLg0KDQoNCg0KDQoNCiMgOC4gUmVncmVzc2lvbiBNb2RlbA0KDQojIyAgOC4xLiBMb2dpc3RpYyBSZWdyZXNzaW9uDQpgYGB7cn0NCmxvZ2l0X21vZGVsIDwtIGdsbShtb2RlIH4gZGFuY2VhYmlsaXR5ICsgZW5lcmd5ICsgdGVtcG8sIGRhdGEgPSBkYXRhLCBmYW1pbHkgPSBiaW5vbWlhbCkNCg0KIyBEaXNwbGF5IG1vZGVsIHN1bW1hcnkNCnN1bW1hcnkobG1fbW9kZWwpDQoNCiMgRGlzcGxheSBtb2RlbCBjb2VmZmljaWVudHMNCmNvZWYoc3VtbWFyeShsb2dpdF9tb2RlbCkpDQpgYGANCg0KDQotIERhbmNlYWJpbGl0eSBuZWdhdGl2ZWx5IGFmZmVjdHMgbW9kZSwgbWVhbmluZyBtb3JlIGRhbmNlYWJsZSBzb25ncyBhcmUgbGlrZWx5IG1pbm9yLiANCi0gRW5lcmd5IHBvc2l0aXZlbHkgYWZmZWN0cyBtb2RlLCBtZWFuaW5nIGhpZ2gtZW5lcmd5IHNvbmdzIGFyZSBtb3JlIGxpa2VseSBtYWpvci4gDQotIFRlbXBvIGhhcyBubyBzaWduaWZpY2FudCBlZmZlY3QuIA0KDQoqKlNpZ25pZmljYW5jZToqKiBUaGVzZSBmaW5kaW5ncyBzdWdnZXN0IHRoYXQgZGFuY2UtZnJpZW5kbHkgc29uZ3MgdGVuZCB0byBoYXZlIG1pbm9yIHRvbmVzLCB3aGlsZSBoaWdoLWVuZXJneSBzb25ncyBhcmUgdHlwaWNhbGx5IG1ham9yLCBpbmZsdWVuY2luZyBtdXNpYyBwcm9kdWN0aW9uIGFuZCByZWNvbW1lbmRhdGlvbiBhbGdvcml0aG1zLiANCg0KDQojIyA4LjIuIExpbmVhciBSZWdyZXNzaW9uDQpgYGB7cn0NCm1vZGVsIDwtIGxtKHBvcHVsYXJpdHkgfiBkYW5jZWFiaWxpdHkgKyBlbmVyZ3kgKyBhY291c3RpY25lc3MgKyB2YWxlbmNlICsgdGVtcG8gKyBsb3VkbmVzcyArIGR1cmF0aW9uX21zLCBkYXRhID0gZGF0YSkNCnN1bW1hcnkobW9kZWwpDQpgYGANCg0KLSBUaGUgbW9kZWwgaXMgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBvdmVyYWxsIChG4oCQc3RhdGlzdGljID0gMzEuMDIsIHAgPCAyLjJlLTE2KSwgYnV0IGV4cGxhaW5zIG9ubHkgYWJvdXQgMi4zNiUgb2YgdGhlIHZhcmlhbmNlIGluIHBvcHVsYXJpdHkgKEFkanVzdGVkIFLCsiA9IDAuMDIyOCkuDQoNCg0KIyBDb25jbHVzaW9uICANCg0KRnJvbSBhbGwgdGhlIERhdGEgRGl2ZXMgYW5kIGFuYWx5c2lzLCB3ZSBjYW4gdW5kZXJzdGFuZCB0aGF0IFBvcHVsYXJpdHkgb2YgYSBzb25nIG9yIGEgcGFydGljdWxhciBtdXNpYyB0cmFjaywgZGVwZW5kcyBvbiB2YXJpb3VzIGZhY3RvcnMgbGlrZSBkYW5jZWFiaWxpdHksIHRlbXBvLCB2YWxlbmNlLCBlbmVyZ3kgYW5kIGxvdWRuZXNzLg0KIA0KRm9yIGluc3RhbmNlLCBoaWdoIGRhbmNlYWJpbGl0eSBhbmQgZW5lcmd5IG9mdGVuIG1ha2UgYSBzb25nIG1vcmUgc3VpdGFibGUgZm9yIHNvY2lhbCBzZXR0aW5ncyBhbmQgZGFuY2UgZW52aXJvbm1lbnRzLCBpbmNyZWFzaW5nIGl0cyBjaGFuY2VzIG9mIGJlaW5nIHBsYXllZCBtb3JlIGZyZXF1ZW50bHkuIA0KDQpTaW1pbGFybHksIHZhbGVuY2UsIHdoaWNoIG1lYXN1cmVzIHRoZSBtdXNpY2FsIHBvc2l0aXZpdHkgb2YgYSB0cmFjaywgY2FuIGFmZmVjdCBlbW90aW9uYWwgYXBwZWFsLCB3aGlsZSB0ZW1wbyBhbmQgbG91ZG5lc3MgY29udHJpYnV0ZSB0byB0aGUgc29uZ+KAmXMgb3ZlcmFsbCBpbnRlbnNpdHkgYW5kIG1vb2QuIA0KDQoNCioqRnV0dXJlIFJlY29tbWVuZGF0aW9uczoqKiBUbyBlbnJpY2ggdXNlciBleHBlcmllbmNlIGFuZCBtdXNpY2FsIGRpdmVyc2l0eSwgaXTigJlzIHJlY29tbWVuZGVkIHRoYXQgc3RyZWFtaW5nIHBsYXRmb3JtcyBhbmQgY3JlYXRvcnMgc2hvdWxkOiANCg0KLSBJbmNvcnBvcmF0ZSBsb3ctZnJlcXVlbmN5IGdyb3VwaW5ncyBmb3IgbXVzaWMgdHJhY2tzIHdpdGggaGlnaCBnZW5yZXMuDQoNCi0gRm9jdXNpbmcgb24gb3RoZXIgZmFjdG9ycyBsaWtlIHZhbGVuY2UgYW5kIGVuZXJneS4NCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0K