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"
1. A list of at least 3 columns (or values) in your data which are
unclear until you read the documentation.
At first, by seeing the dataset, the column name X seems to be
unknown. Later, after seeing values in it, I came to recognise it as the
index. Also, again I wondered as ‘track_id’ can act as a unique
identifier, but, after going through documentation, I found that
track_id is unique id generated for each music track and X acts as an
identifier of it in the dataset.It will be unclear whether this ID is
unique for each track, reused across different versions, or linked to an
external database.
“mode” – The meaning of “mode” is unclear without refering to
documentation. In music-related datasets, it refers to the musical mode
(major(1) or minor(0)). This classification is based on Western music
theory, where a major scale tends to sound positive, while a minor scale
often conveys a more somber or emotional feel. 0 → Minor mode
(associated with darker, sadder, or more melancholic tones) 1 → Major
mode (associated with brighter, happier, or more uplifting
tones)
“valence” – This term isn’t self-explanatory. In Spotify dataset,
“valence” represents the musical positivity of a track. Valence values
are decimals which ranges from 0 to 1 varying from sad to happy state.
In simpler terms, valence quantifies the emotional tone of a song, with
higher values indicating a more upbeat, joyful feel, and lower values
indicating a more somber, introspective vibe.
“Time_signature” - It’s value is likely an integer that reflects
one of these time signatures: 4: Represents 4/4 time (most common in pop
and rock music-meaning there are 4 beats per measure, and each beat is a
quarter note) 3: Represents 3/4 time (waltz or certain classical
music-typically found in waltzes, meaning there are 3 beats per measure,
each a quarter note) Other values (like 6 or 7) might appear but are
less common.Often used in ballads or faster-paced tunes, meaning there
are 6 beats per measure, and each beat is an eighth note.
Why do you think they chose to encode the data the way they did?
What could have happened if you didn’t read the documentation?
The encoding choices in the music dataset, such as using binary
values for “mode” (0 for minor, 1 for major), a
0-1 range for ”valence”** (emotional positivity), and
integers for “time_signature”, are likely made to
efficiently represent important musical attributes in a compact and
meaningful way. These encodings allow for quick categorization and
analysis, with “mode” distinguishing major and minor
scales, “valence” capturing the emotional tone of the
track, and “time_signature” reflecting the rhythmic
structure of the song.
Without reading the documentation, however,one could easily
misinterpret these features—such as assuming “mode” is
an arbitrary number or misunderstanding “valence” as a
technical feature. This could lead to confusion and incorrect analysis,
emphasizing the importance of understanding the context behind the data
to ensure accurate insights.
2. At least one element or your data that is unclear even after
reading the documentation.
Even after reading the documentation of spotify dataset, one element
of the data that might still remain unclear is the
“track_id”. While it’s clear that this is an identifier
for each track, the exact nature of this ID is ambiguous. For example,
it is uncertain whether it is a globally unique identifier, if it’s
linked to an external database, or if the same track might share the
same ID in different contexts (such as different versions of a song or
remixes). To clarify this, we need to explore the dataset further by
checking for duplicates, cross-referencing with external sources like
youtube music or music databases, or even analyzing the distribution and
pattern of these IDs to understand their uniqueness and relevance.
3. Build at least two visualizations which use a column of data that
is affected by the issue you brought up in bullet #2, above. In these
visualizations, find a way to highlight the issue from different
perspectives, explain what is unclear, and why it might be
concerning.
# Creates a frequency table of track_ids
track_id_count <- table(data$track_id)
# Get the top 10 most frequent track_ids
top_10_tracks <- head(sort(track_id_count, decreasing = TRUE), 10)
# Creates a bar plot to visualize the top 10 most frequent track_ids
top_10_plot <- ggplot(as.data.frame(top_10_tracks), aes(x = Var1, y = Freq)) +
geom_bar(stat = "identity", fill = "skyblue") +
theme_minimal() +
labs(title = "Top 10 Most Frequent Track IDs", x = "Track ID", y = "Frequency") +
theme(axis.text.x = element_text(angle = 90, hjust = 1))
# Display the plot
print(top_10_plot)

The top 10 track_id frequency plot can reveal
repeated tracks, indicating possible duplicates or multiple versions of
the same song. If certain track_id appear too often, it
suggests data redundancy, which can skew analysis. This could also
indicate a data quality issue, as track_id should
ideally be unique. Addressing these repetitions through data cleaning
would ensure more accurate insights.
# Create a table of frequencies for mode (0 and 1)
mode_count <- table(data$mode)
# Create a pie chart to visualize the distribution of major (1) vs minor (0) tracks
mode_plot <- ggplot(as.data.frame(mode_count), aes(x = "", y = Freq, fill = factor(Var1))) +
geom_bar(stat = "identity", width = 1) +
coord_polar(theta = "y") +
scale_fill_manual(values = c("green", "orange")) +
labs(title = "Distribution of Mode (Major vs Minor)", fill = "Mode") +
theme_minimal()
# Display the plot
print(mode_plot)

The pie chart visually shows the distribution of
mode values (0 for minor, 1 for major), highlighting
how many tracks are in each category. If one category (minor or major)
overwhelmingly dominates, it clarifies any potential imbalance in the
dataset. The chart provides a clear overview of the mode feature,
helping to ensure it’s interpreted correctly. It also addresses any
uncertainty about the proportion of songs in major vs minor modes.
# 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 heatmap helps clarify if the track_id represents meaningful
variations in musical features or if there’s an overrepresentation of
certain track_ids that might skew the dataset. By aggregating values for
each track, the heatmap can reveal patterns that indicate whether
track_id is simply an identifier or if it plays a larger role in
distinguishing track characteristics. Since track_id likely represents
different songs, we can use a heatmap to see if any track_id has
distinct patterns across features such as popularity, energy, or
danceability. By aggregating values of other columns by track_id, we can
observe if certain tracks dominate specific ranges of values.
There seems certain risks and respective solutions for them -
- Risk: Overrepresentation of Certain Tracks Solution: Ensure each
track_id represents a unique song.
- Risk: Data Redundancy Solution: Filter out redundant entries and
aggregate data to represent each song only once.
- Risk: Inaccurate Aggregation of Multiple Versions Solution:
Carefully aggregate features by track_id, ensuring different versions of
the same song are handled appropriately.
- Risk: Overfitting in Models Solution: Use cross-validation
techniques to ensure the model generalizes well and is not biased by
repeated tracks.
4. For at least two categorical columns, check for examples of the
following, and describe what you find:
Are there explicitly missing rows?
Are there implicitly missing rows?
Are there empty groups?
- Explicitly missing rows: Rows where the data is clearly marked as
missing (e.g., empty cells, “N/A”, or null values).
- Implicitly missing rows: Rows that are not present in the dataset
but should logically exist based on the context of other data.
- Empty groups: Categories within a column that have no corresponding
data entries.
# Check for missing values (NA) in each column of the dataset
missing_values <- sapply(data, function(x) sum(is.na(x)))
# Display the count of missing values per column
print(missing_values)
a. Artists Column
Name of the categorical column observed: artists
Explicit missing rows: There are no explicitly missing rows in
the artists column. All rows contain an artist name.
Implicit missing rows: There don’t appear to be any implicitly
missing rows. The dataset seems to include a wide variety of artists
without any obvious omissions.
Empty groups: There are no empty groups in the artists column.
Each row has an associated artist.
Additional observation: The artists column contains a mix of
individual artists (e.g., “Gen Hoshino”, “Jason Mraz”) and
collaborations (e.g., “Ingrid Michaelson; ZAYN”).
b. Track Genre Column
Name of the categorical column observed: track_genre
Explicit missing rows: There are no explicitly missing rows in
the track_genre column. All rows have a genre assigned.
Implicit missing rows: There don’t appear to be any implicitly
missing rows in terms of genres. However, it’s worth noting that all
tracks in the visible data are labeled as “acoustic”, which might
suggest that other genres are implicitly missing from this
dataset.
Empty groups: There are no empty groups in the track_genre
column. All rows have the genre “acoustic” assigned.
Additional observation: The lack of variety in the track_genre
column (all tracks labeled as “acoustic”) might indicate that this
dataset is focused specifically on acoustic tracks or that there’s an
issue with the genre classification in the data.
5.For at least one continuous column, what would you define as an
outlier and why?
To analyze outliers in a continuous column, selecting ‘popularity’
column, which contains numerical values ranging from 0 to 82.
An outlier in the popularity column can be defined as a value that
falls significantly outside the typical range of popularity scores for
the tracks in this dataset.
Here’s how we can define outliers using the IQR method: Compute the
Interquartile Range (IQR) = Q3 - Q1= 60 - 30 = 30 Define the lower bound
as Q1 - 1.5 * IQR = 30 - 1.5 * 30 = -15 Define the upper bound as Q3 +
1.5 * IQR = 60 + 1.5 * 30 = 105
Any value below the lower bound or above the upper bound is
considered an outlier. Since popularity scores are always non-negative
and have a maximum of 100, we can adjust our definition: Any popularity
score below 0 (which isn’t possible in this case) or above 105 would be
considered an outlier.
In this dataset, we don’t see any values above 105, so there are no
upper outliers. However, tracks with very low popularity scores (close
to 0) could be considered as lower outliers.
LS0tDQp0aXRsZTogIkRhdGEgRGl2ZSA1Ig0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCmBgYHtyfQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkocmVhZHIpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoY29uZmxpY3RlZCkNCmBgYA0KDQpgYGB7cn0NCiNSZWFkaW5nIHRoZSBkYXRhIHNldA0KZGF0YSA8LSByZWFkLmNzdigiZGF0YXNldC5jc3YiKQ0KY29uZmxpY3RlZDo6Y29uZmxpY3RzX3ByZWZlcihkcGx5cjo6ZmlsdGVyKQ0KIyBGaWx0ZXJpbmcgZGF0YXNldCB3aGVyZSBleHBsaWNpdCBpcyAiVHJ1ZSIgYW5kIHRha2luZyBhIHNhbXBsZSBvZiA5LDAwMCByb3dzDQpzYW1wbGVfZGF0YSA8LSBkYXRhIHw+IGZpbHRlcihleHBsaWNpdCA9PSAiVHJ1ZSIpIHw+IHNhbXBsZV9uKDkwMDApDQpkYXRhIDwtIHNhbXBsZV9kYXRhDQpkYXRhDQpgYGANCg0KYGBge3J9IA0KIyBMaXN0aW5nIG91dCBhbGwgdGhlIGNvbHVtbl9uYW1lcyBvZiB0aGUgZGF0YXNldA0KbmFtZXMoZGF0YSkNCmBgYA0KIyMjIDEuIEEgbGlzdCBvZiBhdCBsZWFzdCAzIGNvbHVtbnMgKG9yIHZhbHVlcykgaW4geW91ciBkYXRhIHdoaWNoIGFyZSB1bmNsZWFyIHVudGlsIHlvdSByZWFkIHRoZSBkb2N1bWVudGF0aW9uLg0KDQoxLiBBdCBmaXJzdCwgYnkgc2VlaW5nIHRoZSBkYXRhc2V0LCB0aGUgY29sdW1uIG5hbWUgWCBzZWVtcyB0byBiZSB1bmtub3duLg0KTGF0ZXIsIGFmdGVyIHNlZWluZyB2YWx1ZXMgaW4gaXQsIEkgY2FtZSB0byByZWNvZ25pc2UgaXQgYXMgdGhlIGluZGV4Lg0KQWxzbywgYWdhaW4gSSB3b25kZXJlZCBhcyAndHJhY2tfaWQnIGNhbiBhY3QgYXMgYSB1bmlxdWUgaWRlbnRpZmllciwgYnV0LCBhZnRlciBnb2luZyB0aHJvdWdoIGRvY3VtZW50YXRpb24sIEkgZm91bmQgdGhhdCB0cmFja19pZCBpcyB1bmlxdWUgaWQgZ2VuZXJhdGVkIGZvciBlYWNoIG11c2ljIHRyYWNrIGFuZCBYIGFjdHMgYXMgYW4gaWRlbnRpZmllciBvZiBpdCBpbiB0aGUgZGF0YXNldC5JdCB3aWxsIGJlIHVuY2xlYXIgd2hldGhlciB0aGlzIElEIGlzIHVuaXF1ZSBmb3IgZWFjaCB0cmFjaywgcmV1c2VkIGFjcm9zcyBkaWZmZXJlbnQgdmVyc2lvbnMsIG9yIGxpbmtlZCB0byBhbiBleHRlcm5hbCBkYXRhYmFzZS4NCg0KMi4gIm1vZGUiIOKAkyBUaGUgbWVhbmluZyBvZiAibW9kZSIgaXMgdW5jbGVhciB3aXRob3V0IHJlZmVyaW5nIHRvIGRvY3VtZW50YXRpb24uIEluIG11c2ljLXJlbGF0ZWQgZGF0YXNldHMsIGl0IHJlZmVycyB0byB0aGUgbXVzaWNhbCBtb2RlIChtYWpvcigxKSBvciBtaW5vcigwKSkuIFRoaXMgY2xhc3NpZmljYXRpb24gaXMgYmFzZWQgb24gV2VzdGVybiBtdXNpYyB0aGVvcnksIHdoZXJlIGEgbWFqb3Igc2NhbGUgdGVuZHMgdG8gc291bmQgcG9zaXRpdmUsIHdoaWxlIGEgbWlub3Igc2NhbGUgb2Z0ZW4gY29udmV5cyBhIG1vcmUgc29tYmVyIG9yIGVtb3Rpb25hbCBmZWVsLg0KMCDihpIgTWlub3IgbW9kZSAoYXNzb2NpYXRlZCB3aXRoIGRhcmtlciwgc2FkZGVyLCBvciBtb3JlIG1lbGFuY2hvbGljIHRvbmVzKQ0KMSDihpIgTWFqb3IgbW9kZSAoYXNzb2NpYXRlZCB3aXRoIGJyaWdodGVyLCBoYXBwaWVyLCBvciBtb3JlIHVwbGlmdGluZyB0b25lcykNCg0KMy4gInZhbGVuY2UiIOKAkyBUaGlzIHRlcm0gaXNuJ3Qgc2VsZi1leHBsYW5hdG9yeS4gSW4gU3BvdGlmeSBkYXRhc2V0LCAidmFsZW5jZSIgcmVwcmVzZW50cyB0aGUgbXVzaWNhbCBwb3NpdGl2aXR5IG9mIGEgdHJhY2suDQpWYWxlbmNlIHZhbHVlcyBhcmUgZGVjaW1hbHMgd2hpY2ggcmFuZ2VzIGZyb20gMCB0byAxIHZhcnlpbmcgZnJvbSBzYWQgdG8gaGFwcHkgc3RhdGUuIEluIHNpbXBsZXIgdGVybXMsIHZhbGVuY2UgcXVhbnRpZmllcyB0aGUgZW1vdGlvbmFsIHRvbmUgb2YgYSBzb25nLCB3aXRoIGhpZ2hlciB2YWx1ZXMgaW5kaWNhdGluZyBhIG1vcmUgdXBiZWF0LCBqb3lmdWwgZmVlbCwgYW5kIGxvd2VyIHZhbHVlcyBpbmRpY2F0aW5nIGEgbW9yZSBzb21iZXIsIGludHJvc3BlY3RpdmUgdmliZS4NCg0KNC4gIlRpbWVfc2lnbmF0dXJlIiAtIEl0J3MgdmFsdWUgaXMgbGlrZWx5IGFuIGludGVnZXIgdGhhdCByZWZsZWN0cyBvbmUgb2YgdGhlc2UgdGltZSBzaWduYXR1cmVzOiANCiAgICAgIDQ6IFJlcHJlc2VudHMgNC80IHRpbWUgKG1vc3QgY29tbW9uIGluIHBvcCBhbmQgcm9jayBtdXNpYy1tZWFuaW5nIHRoZXJlIGFyZSA0IGJlYXRzIHBlciBtZWFzdXJlLCBhbmQgZWFjaCBiZWF0IGlzIGEgcXVhcnRlciBub3RlKQ0KICAgICAgMzogUmVwcmVzZW50cyAzLzQgdGltZSAod2FsdHogb3IgY2VydGFpbiBjbGFzc2ljYWwgbXVzaWMtdHlwaWNhbGx5IGZvdW5kIGluIHdhbHR6ZXMsIG1lYW5pbmcgdGhlcmUgYXJlIDMgYmVhdHMgcGVyIG1lYXN1cmUsIGVhY2ggICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGEgcXVhcnRlciBub3RlKQ0KICAgICAgT3RoZXIgdmFsdWVzIChsaWtlIDYgb3IgNykgbWlnaHQgYXBwZWFyIGJ1dCBhcmUgbGVzcyBjb21tb24uT2Z0ZW4gdXNlZCBpbiBiYWxsYWRzIG9yIGZhc3Rlci1wYWNlZCB0dW5lcywgbWVhbmluZyB0aGVyZSBhcmUgNiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmVhdHMgcGVyIG1lYXN1cmUsIGFuZCBlYWNoIGJlYXQgaXMgYW4gZWlnaHRoIG5vdGUuDQogDQogDQojIyMgV2h5IGRvIHlvdSB0aGluayB0aGV5IGNob3NlIHRvIGVuY29kZSB0aGUgZGF0YSB0aGUgd2F5IHRoZXkgZGlkPyBXaGF0IGNvdWxkIGhhdmUgaGFwcGVuZWQgaWYgeW91IGRpZG4ndCByZWFkIHRoZSBkb2N1bWVudGF0aW9uPw0KDQpUaGUgZW5jb2RpbmcgY2hvaWNlcyBpbiB0aGUgbXVzaWMgZGF0YXNldCwgc3VjaCBhcyB1c2luZyBiaW5hcnkgdmFsdWVzIGZvciAqKiJtb2RlIioqICgwIGZvciBtaW5vciwgMSBmb3IgbWFqb3IpLCBhICoqMC0xIHJhbmdlIGZvciAqKiJ2YWxlbmNlIioqIChlbW90aW9uYWwgcG9zaXRpdml0eSksIGFuZCBpbnRlZ2VycyBmb3IgKioidGltZV9zaWduYXR1cmUiKiosIGFyZSBsaWtlbHkgbWFkZSB0byBlZmZpY2llbnRseSByZXByZXNlbnQgaW1wb3J0YW50IG11c2ljYWwgYXR0cmlidXRlcyBpbiBhIGNvbXBhY3QgYW5kIG1lYW5pbmdmdWwgd2F5LiBUaGVzZSBlbmNvZGluZ3MgYWxsb3cgZm9yIHF1aWNrIGNhdGVnb3JpemF0aW9uIGFuZCBhbmFseXNpcywgd2l0aCAqKiJtb2RlIioqIGRpc3Rpbmd1aXNoaW5nIG1ham9yIGFuZCBtaW5vciBzY2FsZXMsICoqInZhbGVuY2UiKiogY2FwdHVyaW5nIHRoZSBlbW90aW9uYWwgdG9uZSBvZiB0aGUgdHJhY2ssIGFuZCAqKiJ0aW1lX3NpZ25hdHVyZSIqKiByZWZsZWN0aW5nIHRoZSByaHl0aG1pYyBzdHJ1Y3R1cmUgb2YgdGhlIHNvbmcuIA0KDQpXaXRob3V0IHJlYWRpbmcgdGhlIGRvY3VtZW50YXRpb24sIGhvd2V2ZXIsb25lIGNvdWxkIGVhc2lseSBtaXNpbnRlcnByZXQgdGhlc2UgZmVhdHVyZXPigJRzdWNoIGFzIGFzc3VtaW5nICoqIm1vZGUiKiogaXMgYW4gYXJiaXRyYXJ5IG51bWJlciBvciBtaXN1bmRlcnN0YW5kaW5nICoqInZhbGVuY2UiKiogYXMgYSB0ZWNobmljYWwgZmVhdHVyZS4gVGhpcyBjb3VsZCBsZWFkIHRvIGNvbmZ1c2lvbiBhbmQgaW5jb3JyZWN0IGFuYWx5c2lzLCBlbXBoYXNpemluZyB0aGUgaW1wb3J0YW5jZSBvZiB1bmRlcnN0YW5kaW5nIHRoZSBjb250ZXh0IGJlaGluZCB0aGUgZGF0YSB0byBlbnN1cmUgYWNjdXJhdGUgaW5zaWdodHMuDQoNCiMjIyAyLiBBdCBsZWFzdCBvbmUgZWxlbWVudCBvciB5b3VyIGRhdGEgdGhhdCBpcyB1bmNsZWFyIGV2ZW4gYWZ0ZXIgcmVhZGluZyB0aGUgZG9jdW1lbnRhdGlvbi4NCg0KRXZlbiBhZnRlciByZWFkaW5nIHRoZSBkb2N1bWVudGF0aW9uIG9mIHNwb3RpZnkgZGF0YXNldCwgb25lIGVsZW1lbnQgb2YgdGhlIGRhdGEgdGhhdCBtaWdodCBzdGlsbCByZW1haW4gdW5jbGVhciBpcyB0aGUgKioidHJhY2tfaWQiKiouIFdoaWxlIGl04oCZcyBjbGVhciB0aGF0IHRoaXMgaXMgYW4gaWRlbnRpZmllciBmb3IgZWFjaCB0cmFjaywgdGhlIGV4YWN0IG5hdHVyZSBvZiB0aGlzIElEIGlzIGFtYmlndW91cy4gRm9yIGV4YW1wbGUsIGl0IGlzIHVuY2VydGFpbiB3aGV0aGVyIGl0IGlzIGEgZ2xvYmFsbHkgdW5pcXVlIGlkZW50aWZpZXIsIGlmIGl04oCZcyBsaW5rZWQgdG8gYW4gZXh0ZXJuYWwgZGF0YWJhc2UsIG9yIGlmIHRoZSBzYW1lIHRyYWNrIG1pZ2h0IHNoYXJlIHRoZSBzYW1lIElEIGluIGRpZmZlcmVudCBjb250ZXh0cyAoc3VjaCBhcyBkaWZmZXJlbnQgdmVyc2lvbnMgb2YgYSBzb25nIG9yIHJlbWl4ZXMpLiBUbyBjbGFyaWZ5IHRoaXMsIHdlIG5lZWQgdG8gZXhwbG9yZSB0aGUgZGF0YXNldCBmdXJ0aGVyIGJ5IGNoZWNraW5nIGZvciBkdXBsaWNhdGVzLCBjcm9zcy1yZWZlcmVuY2luZyB3aXRoIGV4dGVybmFsIHNvdXJjZXMgbGlrZSB5b3V0dWJlIG11c2ljIG9yIG11c2ljIGRhdGFiYXNlcywgb3IgZXZlbiBhbmFseXppbmcgdGhlIGRpc3RyaWJ1dGlvbiBhbmQgcGF0dGVybiBvZiB0aGVzZSBJRHMgdG8gdW5kZXJzdGFuZCB0aGVpciB1bmlxdWVuZXNzIGFuZCByZWxldmFuY2UuDQoNCg0KIyMjIDMuIEJ1aWxkIGF0IGxlYXN0IHR3byB2aXN1YWxpemF0aW9ucyB3aGljaCB1c2UgYSBjb2x1bW4gb2YgZGF0YSB0aGF0IGlzIGFmZmVjdGVkIGJ5IHRoZSBpc3N1ZSB5b3UgYnJvdWdodCB1cCBpbiBidWxsZXQgIzIsIGFib3ZlLiBJbiB0aGVzZSB2aXN1YWxpemF0aW9ucywgZmluZCBhIHdheSB0byBoaWdobGlnaHQgdGhlIGlzc3VlIGZyb20gZGlmZmVyZW50IHBlcnNwZWN0aXZlcywgZXhwbGFpbiB3aGF0IGlzIHVuY2xlYXIsIGFuZCB3aHkgaXQgbWlnaHQgYmUgY29uY2VybmluZy4NCg0KYGBge3J9DQojIENyZWF0ZXMgYSBmcmVxdWVuY3kgdGFibGUgb2YgdHJhY2tfaWRzDQp0cmFja19pZF9jb3VudCA8LSB0YWJsZShkYXRhJHRyYWNrX2lkKQ0KDQojIEdldCB0aGUgdG9wIDEwIG1vc3QgZnJlcXVlbnQgdHJhY2tfaWRzDQp0b3BfMTBfdHJhY2tzIDwtIGhlYWQoc29ydCh0cmFja19pZF9jb3VudCwgZGVjcmVhc2luZyA9IFRSVUUpLCAxMCkNCg0KIyBDcmVhdGVzIGEgYmFyIHBsb3QgdG8gdmlzdWFsaXplIHRoZSB0b3AgMTAgbW9zdCBmcmVxdWVudCB0cmFja19pZHMNCnRvcF8xMF9wbG90IDwtIGdncGxvdChhcy5kYXRhLmZyYW1lKHRvcF8xMF90cmFja3MpLCBhZXMoeCA9IFZhcjEsIHkgPSBGcmVxKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJza3libHVlIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICBsYWJzKHRpdGxlID0gIlRvcCAxMCBNb3N0IEZyZXF1ZW50IFRyYWNrIElEcyIsIHggPSAiVHJhY2sgSUQiLCB5ID0gIkZyZXF1ZW5jeSIpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkNCg0KDQojIERpc3BsYXkgdGhlIHBsb3QNCnByaW50KHRvcF8xMF9wbG90KQ0KYGBgDQpUaGUgdG9wIDEwICoqdHJhY2tfaWQqKiBmcmVxdWVuY3kgcGxvdCBjYW4gcmV2ZWFsIHJlcGVhdGVkIHRyYWNrcywgaW5kaWNhdGluZyBwb3NzaWJsZSBkdXBsaWNhdGVzIG9yIG11bHRpcGxlIHZlcnNpb25zIG9mIHRoZSBzYW1lIHNvbmcuIElmIGNlcnRhaW4gKip0cmFja19pZCoqIGFwcGVhciB0b28gb2Z0ZW4sIGl0IHN1Z2dlc3RzIGRhdGEgcmVkdW5kYW5jeSwgd2hpY2ggY2FuIHNrZXcgYW5hbHlzaXMuIFRoaXMgY291bGQgYWxzbyBpbmRpY2F0ZSBhIGRhdGEgcXVhbGl0eSBpc3N1ZSwgYXMgKip0cmFja19pZCoqIHNob3VsZCBpZGVhbGx5IGJlIHVuaXF1ZS4gQWRkcmVzc2luZyB0aGVzZSByZXBldGl0aW9ucyB0aHJvdWdoIGRhdGEgY2xlYW5pbmcgd291bGQgZW5zdXJlIG1vcmUgYWNjdXJhdGUgaW5zaWdodHMuDQoNCmBgYHtyfQ0KIyBDcmVhdGUgYSB0YWJsZSBvZiBmcmVxdWVuY2llcyBmb3IgbW9kZSAoMCBhbmQgMSkNCm1vZGVfY291bnQgPC0gdGFibGUoZGF0YSRtb2RlKQ0KDQojIENyZWF0ZSBhIHBpZSBjaGFydCB0byB2aXN1YWxpemUgdGhlIGRpc3RyaWJ1dGlvbiBvZiBtYWpvciAoMSkgdnMgbWlub3IgKDApIHRyYWNrcw0KbW9kZV9wbG90IDwtIGdncGxvdChhcy5kYXRhLmZyYW1lKG1vZGVfY291bnQpLCBhZXMoeCA9ICIiLCB5ID0gRnJlcSwgZmlsbCA9IGZhY3RvcihWYXIxKSkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMSkgKw0KICBjb29yZF9wb2xhcih0aGV0YSA9ICJ5IikgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJncmVlbiIsICJvcmFuZ2UiKSkgKw0KICBsYWJzKHRpdGxlID0gIkRpc3RyaWJ1dGlvbiBvZiBNb2RlIChNYWpvciB2cyBNaW5vcikiLCBmaWxsID0gIk1vZGUiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQojIERpc3BsYXkgdGhlIHBsb3QNCnByaW50KG1vZGVfcGxvdCkNCmBgYA0KVGhlIHBpZSBjaGFydCB2aXN1YWxseSBzaG93cyB0aGUgZGlzdHJpYnV0aW9uIG9mICoqbW9kZSoqIHZhbHVlcyAoMCBmb3IgbWlub3IsIDEgZm9yIG1ham9yKSwgaGlnaGxpZ2h0aW5nIGhvdyBtYW55IHRyYWNrcyBhcmUgaW4gZWFjaCBjYXRlZ29yeS4gSWYgb25lIGNhdGVnb3J5IChtaW5vciBvciBtYWpvcikgb3ZlcndoZWxtaW5nbHkgZG9taW5hdGVzLCBpdCBjbGFyaWZpZXMgYW55IHBvdGVudGlhbCBpbWJhbGFuY2UgaW4gdGhlIGRhdGFzZXQuIFRoZSBjaGFydCBwcm92aWRlcyBhIGNsZWFyIG92ZXJ2aWV3IG9mIHRoZSBtb2RlIGZlYXR1cmUsIGhlbHBpbmcgdG8gZW5zdXJlIGl0J3MgaW50ZXJwcmV0ZWQgY29ycmVjdGx5LiBJdCBhbHNvIGFkZHJlc3NlcyBhbnkgdW5jZXJ0YWludHkgYWJvdXQgdGhlIHByb3BvcnRpb24gb2Ygc29uZ3MgaW4gbWFqb3IgdnMgbWlub3IgbW9kZXMuDQoNCmBgYHtyfQ0KIyBTZWxlY3QgcmVsZXZhbnQgY29sdW1ucyBmb3IgdGhlIGhlYXRtYXAgKGRhbmNlYWJpbGl0eSwgZW5lcmd5LCBsb3VkbmVzcywgdGVtcG8sIGV0Yy4pDQpkZl9zZWxlY3RlZCA8LSBkYXRhWywgYygiZGFuY2VhYmlsaXR5IiwgImVuZXJneSIsICJsb3VkbmVzcyIsICJ0ZW1wbyIsICJwb3B1bGFyaXR5IildDQoNCiMgQ2FsY3VsYXRlIHRoZSBjb3JyZWxhdGlvbiBtYXRyaXggZm9yIHRoZSBzZWxlY3RlZCBjb2x1bW5zDQpjb3JyZWxhdGlvbl9tYXRyaXggPC0gY29yKGRmX3NlbGVjdGVkLCB1c2UgPSAiY29tcGxldGUub2JzIikNCg0KIyBDcmVhdGUgYSBoZWF0bWFwIHRvIHZpc3VhbGl6ZSB0aGUgY29ycmVsYXRpb24gYmV0d2VlbiBkYW5jZWFiaWxpdHkgYW5kIG90aGVyIGZlYXR1cmVzDQpsaWJyYXJ5KHJlc2hhcGUyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShSQ29sb3JCcmV3ZXIpDQoNCiMgTWVsdCB0aGUgY29ycmVsYXRpb24gbWF0cml4IGZvciBnZ3Bsb3QyDQpjb3JfbWVsdGVkIDwtIG1lbHQoY29ycmVsYXRpb25fbWF0cml4KQ0KDQojIENyZWF0ZSBhIGhlYXRtYXANCmhlYXRtYXBfcGxvdCA8LSBnZ3Bsb3QoY29yX21lbHRlZCwgYWVzKFZhcjEsIFZhcjIsIGZpbGwgPSB2YWx1ZSkpICsNCiAgZ2VvbV90aWxlKCkgKw0KICBzY2FsZV9maWxsX2dyYWRpZW50Mihsb3cgPSAiYmx1ZSIsIGhpZ2ggPSAicmVkIiwgbWlkID0gIndoaXRlIiwgbWlkcG9pbnQgPSAwKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIGxhYnModGl0bGUgPSAiQ29ycmVsYXRpb24gSGVhdG1hcCBmb3IgRGFuY2VhYmlsaXR5IGFuZCBPdGhlciBGZWF0dXJlcyIsDQogICAgICAgeCA9ICJGZWF0dXJlIiwgeSA9ICJGZWF0dXJlIikgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQ0KDQojIERpc3BsYXkgdGhlIHBsb3QNCnByaW50KGhlYXRtYXBfcGxvdCkNCg0KYGBgDQpUaGlzIGhlYXRtYXAgaGVscHMgY2xhcmlmeSBpZiB0aGUgdHJhY2tfaWQgcmVwcmVzZW50cyBtZWFuaW5nZnVsIHZhcmlhdGlvbnMgaW4gbXVzaWNhbCBmZWF0dXJlcyBvciBpZiB0aGVyZeKAmXMgYW4gb3ZlcnJlcHJlc2VudGF0aW9uIG9mIGNlcnRhaW4gdHJhY2tfaWRzIHRoYXQgbWlnaHQgc2tldyB0aGUgZGF0YXNldC4gDQpCeSBhZ2dyZWdhdGluZyB2YWx1ZXMgZm9yIGVhY2ggdHJhY2ssIHRoZSBoZWF0bWFwIGNhbiByZXZlYWwgcGF0dGVybnMgdGhhdCBpbmRpY2F0ZSB3aGV0aGVyIHRyYWNrX2lkIGlzIHNpbXBseSBhbiBpZGVudGlmaWVyIG9yIGlmIGl0IHBsYXlzIGEgbGFyZ2VyIHJvbGUgaW4gZGlzdGluZ3Vpc2hpbmcgdHJhY2sgY2hhcmFjdGVyaXN0aWNzLiANClNpbmNlIHRyYWNrX2lkIGxpa2VseSByZXByZXNlbnRzIGRpZmZlcmVudCBzb25ncywgd2UgY2FuIHVzZSBhIGhlYXRtYXAgdG8gc2VlIGlmIGFueSB0cmFja19pZCBoYXMgZGlzdGluY3QgcGF0dGVybnMgYWNyb3NzIGZlYXR1cmVzIHN1Y2ggYXMgcG9wdWxhcml0eSwgZW5lcmd5LCBvciBkYW5jZWFiaWxpdHkuIA0KQnkgYWdncmVnYXRpbmcgdmFsdWVzIG9mIG90aGVyIGNvbHVtbnMgYnkgdHJhY2tfaWQsIHdlIGNhbiBvYnNlcnZlIGlmIGNlcnRhaW4gdHJhY2tzIGRvbWluYXRlIHNwZWNpZmljIHJhbmdlcyBvZiB2YWx1ZXMuDQoNClRoZXJlIHNlZW1zIGNlcnRhaW4gcmlza3MgYW5kIHJlc3BlY3RpdmUgc29sdXRpb25zIGZvciB0aGVtIC0NCg0KMS4gUmlzazogT3ZlcnJlcHJlc2VudGF0aW9uIG9mIENlcnRhaW4gVHJhY2tzDQogICBTb2x1dGlvbjogRW5zdXJlIGVhY2ggdHJhY2tfaWQgcmVwcmVzZW50cyBhIHVuaXF1ZSBzb25nLg0KMi4gUmlzazogRGF0YSBSZWR1bmRhbmN5DQogICBTb2x1dGlvbjogRmlsdGVyIG91dCByZWR1bmRhbnQgZW50cmllcyBhbmQgYWdncmVnYXRlIGRhdGEgdG8gcmVwcmVzZW50IGVhY2ggc29uZyBvbmx5IG9uY2UuDQozLiBSaXNrOiBJbmFjY3VyYXRlIEFnZ3JlZ2F0aW9uIG9mIE11bHRpcGxlIFZlcnNpb25zDQogICBTb2x1dGlvbjogQ2FyZWZ1bGx5IGFnZ3JlZ2F0ZSBmZWF0dXJlcyBieSB0cmFja19pZCwgZW5zdXJpbmcgZGlmZmVyZW50IHZlcnNpb25zIG9mIHRoZSBzYW1lIHNvbmcgYXJlIGhhbmRsZWQgYXBwcm9wcmlhdGVseS4NCjQuIFJpc2s6IE92ZXJmaXR0aW5nIGluIE1vZGVscw0KICAgU29sdXRpb246IFVzZSBjcm9zcy12YWxpZGF0aW9uIHRlY2huaXF1ZXMgdG8gZW5zdXJlIHRoZSBtb2RlbCBnZW5lcmFsaXplcyB3ZWxsIGFuZCBpcyBub3QgYmlhc2VkIGJ5IHJlcGVhdGVkIHRyYWNrcy4NCiAgIA0KICAgDQojIyMgNC4gRm9yIGF0IGxlYXN0IHR3byBjYXRlZ29yaWNhbCBjb2x1bW5zLCBjaGVjayBmb3IgZXhhbXBsZXMgb2YgdGhlIGZvbGxvd2luZywgYW5kIGRlc2NyaWJlIHdoYXQgeW91IGZpbmQ6DQojIyMgQXJlIHRoZXJlIGV4cGxpY2l0bHkgbWlzc2luZyByb3dzPw0KIyMjIEFyZSB0aGVyZSBpbXBsaWNpdGx5IG1pc3Npbmcgcm93cz8NCiMjIyBBcmUgdGhlcmUgZW1wdHkgZ3JvdXBzPw0KDQotIEV4cGxpY2l0bHkgbWlzc2luZyByb3dzOiBSb3dzIHdoZXJlIHRoZSBkYXRhIGlzIGNsZWFybHkgbWFya2VkIGFzIG1pc3NpbmcgKGUuZy4sIGVtcHR5IGNlbGxzLCAiTi9BIiwgb3IgbnVsbCB2YWx1ZXMpLg0KLSBJbXBsaWNpdGx5IG1pc3Npbmcgcm93czogUm93cyB0aGF0IGFyZSBub3QgcHJlc2VudCBpbiB0aGUgZGF0YXNldCBidXQgc2hvdWxkIGxvZ2ljYWxseSBleGlzdCBiYXNlZCBvbiB0aGUgY29udGV4dCBvZiBvdGhlciBkYXRhLg0KLSBFbXB0eSBncm91cHM6IENhdGVnb3JpZXMgd2l0aGluIGEgY29sdW1uIHRoYXQgaGF2ZSBubyBjb3JyZXNwb25kaW5nIGRhdGEgZW50cmllcy4NCg0KYGBge3J9DQojIENoZWNrIGZvciBtaXNzaW5nIHZhbHVlcyAoTkEpIGluIGVhY2ggY29sdW1uIG9mIHRoZSBkYXRhc2V0DQptaXNzaW5nX3ZhbHVlcyA8LSBzYXBwbHkoZGF0YSwgZnVuY3Rpb24oeCkgc3VtKGlzLm5hKHgpKSkNCg0KIyBEaXNwbGF5IHRoZSBjb3VudCBvZiBtaXNzaW5nIHZhbHVlcyBwZXIgY29sdW1uDQpwcmludChtaXNzaW5nX3ZhbHVlcykNCmBgYA0KDQojIyMgYS4gQXJ0aXN0cyBDb2x1bW4NCg0KMS4gTmFtZSBvZiB0aGUgY2F0ZWdvcmljYWwgY29sdW1uIG9ic2VydmVkOiBhcnRpc3RzDQoNCjIuIEV4cGxpY2l0IG1pc3Npbmcgcm93czogVGhlcmUgYXJlIG5vIGV4cGxpY2l0bHkgbWlzc2luZyByb3dzIGluIHRoZSBhcnRpc3RzIGNvbHVtbi4gQWxsIHJvd3MgY29udGFpbiBhbiBhcnRpc3QgbmFtZS4NCg0KMy4gSW1wbGljaXQgbWlzc2luZyByb3dzOiBUaGVyZSBkb24ndCBhcHBlYXIgdG8gYmUgYW55IGltcGxpY2l0bHkgbWlzc2luZyByb3dzLiBUaGUgZGF0YXNldCBzZWVtcyB0byBpbmNsdWRlIGEgd2lkZSB2YXJpZXR5IG9mIGFydGlzdHMgICAgd2l0aG91dCBhbnkgb2J2aW91cyBvbWlzc2lvbnMuDQoNCjQuIEVtcHR5IGdyb3VwczogVGhlcmUgYXJlIG5vIGVtcHR5IGdyb3VwcyBpbiB0aGUgYXJ0aXN0cyBjb2x1bW4uIEVhY2ggcm93IGhhcyBhbiBhc3NvY2lhdGVkIGFydGlzdC4NCg0KNS4gQWRkaXRpb25hbCBvYnNlcnZhdGlvbjogVGhlIGFydGlzdHMgY29sdW1uIGNvbnRhaW5zIGEgbWl4IG9mIGluZGl2aWR1YWwgYXJ0aXN0cyAoZS5nLiwgIkdlbiBIb3NoaW5vIiwgIkphc29uIE1yYXoiKSBhbmQgY29sbGFib3JhdGlvbnMgKGUuZy4sICJJbmdyaWQgTWljaGFlbHNvbjsgWkFZTiIpLg0KDQoNCg0KIyMjIGIuIFRyYWNrIEdlbnJlIENvbHVtbg0KDQoxLiBOYW1lIG9mIHRoZSBjYXRlZ29yaWNhbCBjb2x1bW4gb2JzZXJ2ZWQ6IHRyYWNrX2dlbnJlDQoNCjIuIEV4cGxpY2l0IG1pc3Npbmcgcm93czogVGhlcmUgYXJlIG5vIGV4cGxpY2l0bHkgbWlzc2luZyByb3dzIGluIHRoZSB0cmFja19nZW5yZSBjb2x1bW4uIEFsbCByb3dzIGhhdmUgYSBnZW5yZSBhc3NpZ25lZC4NCg0KMy4gSW1wbGljaXQgbWlzc2luZyByb3dzOiBUaGVyZSBkb24ndCBhcHBlYXIgdG8gYmUgYW55IGltcGxpY2l0bHkgbWlzc2luZyByb3dzIGluIHRlcm1zIG9mIGdlbnJlcy4gSG93ZXZlciwgaXQncyB3b3J0aCBub3RpbmcgdGhhdCBhbGwgdHJhY2tzIGluIHRoZSB2aXNpYmxlIGRhdGEgYXJlIGxhYmVsZWQgYXMgImFjb3VzdGljIiwgd2hpY2ggbWlnaHQgc3VnZ2VzdCB0aGF0IG90aGVyIGdlbnJlcyBhcmUgaW1wbGljaXRseSBtaXNzaW5nIGZyb20gdGhpcyBkYXRhc2V0Lg0KDQo0LiBFbXB0eSBncm91cHM6IFRoZXJlIGFyZSBubyBlbXB0eSBncm91cHMgaW4gdGhlIHRyYWNrX2dlbnJlIGNvbHVtbi4gQWxsIHJvd3MgaGF2ZSB0aGUgZ2VucmUgImFjb3VzdGljIiBhc3NpZ25lZC4NCg0KNS4gQWRkaXRpb25hbCBvYnNlcnZhdGlvbjogVGhlIGxhY2sgb2YgdmFyaWV0eSBpbiB0aGUgdHJhY2tfZ2VucmUgY29sdW1uIChhbGwgdHJhY2tzIGxhYmVsZWQgYXMgImFjb3VzdGljIikgbWlnaHQgaW5kaWNhdGUgdGhhdCB0aGlzIGRhdGFzZXQgaXMgZm9jdXNlZCBzcGVjaWZpY2FsbHkgb24gYWNvdXN0aWMgdHJhY2tzIG9yIHRoYXQgdGhlcmUncyBhbiBpc3N1ZSB3aXRoIHRoZSBnZW5yZSBjbGFzc2lmaWNhdGlvbiBpbiB0aGUgZGF0YS4NCg0KDQojIyMgNS5Gb3IgYXQgbGVhc3Qgb25lIGNvbnRpbnVvdXMgY29sdW1uLCB3aGF0IHdvdWxkIHlvdSBkZWZpbmUgYXMgYW4gb3V0bGllciBhbmQgd2h5Pw0KDQpUbyBhbmFseXplIG91dGxpZXJzIGluIGEgY29udGludW91cyBjb2x1bW4sIHNlbGVjdGluZyAncG9wdWxhcml0eScgY29sdW1uLCB3aGljaCBjb250YWlucyBudW1lcmljYWwgdmFsdWVzIHJhbmdpbmcgZnJvbSAwIHRvIDgyLiANCg0KQW4gb3V0bGllciBpbiB0aGUgcG9wdWxhcml0eSBjb2x1bW4gY2FuIGJlIGRlZmluZWQgYXMgYSB2YWx1ZSB0aGF0IGZhbGxzIHNpZ25pZmljYW50bHkgb3V0c2lkZSB0aGUgdHlwaWNhbCByYW5nZSBvZiBwb3B1bGFyaXR5IHNjb3JlcyBmb3IgdGhlIHRyYWNrcyBpbiB0aGlzIGRhdGFzZXQuDQoNCkhlcmUncyBob3cgd2UgY2FuIGRlZmluZSBvdXRsaWVycyB1c2luZyB0aGUgSVFSIG1ldGhvZDoNCkNvbXB1dGUgdGhlIEludGVycXVhcnRpbGUgUmFuZ2UgKElRUikgPSBRMyAtIFExPSA2MCAtIDMwID0gMzANCkRlZmluZSB0aGUgbG93ZXIgYm91bmQgYXMgUTEgLSAxLjUgKiBJUVIgPSAzMCAtIDEuNSAqIDMwID0gLTE1DQpEZWZpbmUgdGhlIHVwcGVyIGJvdW5kIGFzIFEzICsgMS41ICogSVFSID0gNjAgKyAxLjUgKiAzMCA9IDEwNQ0KDQpBbnkgdmFsdWUgYmVsb3cgdGhlIGxvd2VyIGJvdW5kIG9yIGFib3ZlIHRoZSB1cHBlciBib3VuZCBpcyBjb25zaWRlcmVkIGFuIG91dGxpZXIuDQpTaW5jZSBwb3B1bGFyaXR5IHNjb3JlcyBhcmUgYWx3YXlzIG5vbi1uZWdhdGl2ZSBhbmQgaGF2ZSBhIG1heGltdW0gb2YgMTAwLCB3ZSBjYW4gYWRqdXN0IG91ciBkZWZpbml0aW9uOg0KQW55IHBvcHVsYXJpdHkgc2NvcmUgYmVsb3cgMCAod2hpY2ggaXNuJ3QgcG9zc2libGUgaW4gdGhpcyBjYXNlKSBvciBhYm92ZSAxMDUgd291bGQgYmUgY29uc2lkZXJlZCBhbiBvdXRsaWVyLg0KDQpJbiB0aGlzIGRhdGFzZXQsIHdlIGRvbid0IHNlZSBhbnkgdmFsdWVzIGFib3ZlIDEwNSwgc28gdGhlcmUgYXJlIG5vIHVwcGVyIG91dGxpZXJzLiANCkhvd2V2ZXIsIHRyYWNrcyB3aXRoIHZlcnkgbG93IHBvcHVsYXJpdHkgc2NvcmVzIChjbG9zZSB0byAwKSBjb3VsZCBiZSBjb25zaWRlcmVkIGFzIGxvd2VyIG91dGxpZXJzLg0KDQo=