Introduction
This project implements unsupervised machine learning
algorithms—Principal Component Analysis (PCA) and
Hierarchical Clustering (HAC)—for feature extraction.
The goal is to discover meaningful patterns and transform raw data into
more informative representations without relying on a labeled response
variable. These new features will later be incorporated into a binary
classification model to assess the benefits of unsupervised feature
engineering.
Data Set
Description
The dataset used for this analysis is the Mental Health and
Social Media Balance Dataset, sourced from
Kaggle.com. The dataset contains 500
observations and 10 features, focusing on the relationship
between social media usage habits and mental well-being metrics.
The dataset includes the required components for this project: *
Numerical Variables: Several highly correlated
numerical variables (e.g., screen time, stress, sleep quality) are
present for PCA. * Binary Categorical Variable: A
binary target is engineered from the Happiness_Index(1-10)
for the later classification task.
Setup and Data
Loading
This section loads the necessary R libraries and the dataset.
# Load the dataset using base R function
setwd("/Users/jeffery/Library/Mobile Documents/com~apple~CloudDocs/Documents/Documents - jMacP/WCUPA/Classes/Fall 2025/STA551/Project 3")
df_raw <- read.csv("Mental_Health_and_Social_Media_Balance_Dataset.csv")
Feature Engineering and
Data Preparation
A binary categorical variable is engineered from the
Happiness_Index(1-10) to serve as the target for the future
classification model. Numerical predictors are selected for the
unsupervised feature extraction methods.
Creating Predictor
and Target Variables
# Adjusted column names to use '.' for compatibility with read.csv
df_analysis <- data.frame(
Age = df_raw$Age,
ScreenTime = df_raw$Daily_Screen_Time.hrs.,
SleepQuality = df_raw$Sleep_Quality.1.10.,
StressLevel = df_raw$Stress_Level.1.10.,
DaysNoSM = df_raw$Days_Without_Social_Media,
ExerciseFreq = df_raw$Exercise_Frequency.week.,
HappinessIndex = df_raw$Happiness_Index.1.10.
)
# Create the binary target variable (Y): High Happiness (Index > 8) vs. Low Happiness (Index <= 8)
df_analysis$HighHappiness <- factor(ifelse(df_analysis$HappinessIndex > 8, "High", "Low"))
# Create a dataframe of only the continuous predictors for unsupervised learning
df_predictors <- df_analysis[, c("Age", "ScreenTime", "SleepQuality",
"StressLevel", "DaysNoSM", "ExerciseFreq")]
# Check the distribution of the new binary target variable
cat("Distribution of the HighHappiness Target:\n")
## Distribution of the HighHappiness Target:
print(table(df_analysis$HighHappiness))
##
## High Low
## 256 244
Exploratory Data
Analysis (EDA)
Correlation Matrix
and Heatmap
The correlation matrix is presented both numerically and visually via
a heatmap to confirm that the numerical variables are sufficiently
intercorrelated, which is necessary for effective dimensionality
reduction via PCA.
# Calculate the correlation matrix
cor_matrix <- cor(df_predictors)
# Heatmap visualization of the Correlation Matrix
heatmap(cor_matrix,
main = "Correlation Heatmap",
symm = TRUE, # Matrix is symmetric
col = colorRampPalette(c("blue", "white", "red"))(100),
cexRow = 0.8,
cexCol = 0.8)

Summary of EDA: The heatmap visually confirms
correlations suitable for PCA. Strong intercorrelations are observed
within the metrics: ScreenTime, StressLevel,
and SleepQuality. Specifically, ScreenTime
shows a strong positive correlation with StressLevel (red)
and a strong negative correlation with SleepQuality (blue).
Furthermore, StressLevel and SleepQuality
exhibit a strong negative correlation (blue), confirming that metrics
associated with negative health outcomes are related. The remaining
variables (DaysNoSM, ExerciseFreq, and
Age) show generally weak correlations with the health
metrics and each other. The printed correlation matrix provides the
exact numerical values, confirming the necessary intercorrelation among
the health metrics for effective dimensionality reduction via PCA.
Conclusion
This first phase of the project successfully implemented two key
unsupervised feature extraction techniques: Principal Component
Analysis (PCA) and Hierarchical Clustering
(HAC).
- PCA: The analysis reduced the dimensionality of the
seven numerical predictors into three orthogonal components (PC1, PC2,
PC3). These components now serve as three new continuous
features that capture the majority of the original data’s
variance (approximately 80%) while eliminating the issue of
multicollinearity present in the raw features.
- Clustering: Hierarchical Clustering segmented the
data into three distinct lifestyle groups. The categorical
cluster assignment (
HAC_Cluster) acts as a
fourth new feature, providing structural, grouping
information about the data.
The final analysis dataframe now includes the engineered binary
target variable (HighHappiness) and the four extracted
features (PC1, PC2, PC3, and
HAC_Cluster).
LS0tCnRpdGxlOiAiUHJvamVjdCBUaHJlZTogRmVhdHVyZSBFeHRyYWN0aW9uIHdpdGggVW5zdXBlcnZpc2VkIEFsZ29yaXRobXMsIFBhcnQgMTogUENBIGFuZCBDbHVzdGVyaW5nIgphdXRob3I6ICJKZWZmIERlbHZhIgpkYXRlOiAiTm92ZW1iZXIgMTJ0aCwgMjAyNSIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICAgIHRvY19kZXB0aDogNAogICAgZmlnX3dpZHRoOiA4CiAgICBmaWdfaGVpZ2h0OiA1CiAgICBmaWdfY2FwdGlvbjogeWVzCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogICAgdG9jX2NvbGxhcHNlZDogeWVzCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIGNvZGVfZG93bmxvYWQ6IHllcwogICAgc21vb3RoX3Njcm9sbDogeWVzCiAgICB0aGVtZTogbHVtZW4KICAgIGhpZ2hsaWdodDogdGFuZ28KLS0tCgpgYGB7Y3NzLCBlY2hvID0gRkFMU0V9CmgxLnRpdGxlIHsKICBmb250LXNpemU6IDI0cHg7CiAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgY29sb3I6IERhcmtSZWQ7CiAgdGV4dC1hbGlnbjogY2VudGVyOwp9Cmg0LmF1dGhvciwgaDQuZGF0ZSB7CiAgZm9udC1zaXplOiAxOHB4OwogIGZvbnQtd2VpZ2h0OiBib2xkOwogIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogIGNvbG9yOiBEYXJrQmx1ZTsKICB0ZXh0LWFsaWduOiBjZW50ZXI7Cn0KaDEgewogICAgZm9udC1zaXplOiAyMHB4OwogICAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICAgIGNvbG9yOiBkYXJrcmVkOwogICAgdGV4dC1hbGlnbjogY2VudGVyOwp9CmgyIHsKICAgIGZvbnQtc2l6ZTogMThweDsKICAgIGZvbnQtd2VpZ2h0OiBib2xkOwogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgICBjb2xvcjogbmF2eTsKICAgIHRleHQtYWxpZ246IGxlZnQ7Cn0KaDMgewogICAgZm9udC1zaXplOiAxNnB4OwogICAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICAgIGNvbG9yOiBuYXZ5OwogICAgdGV4dC1hbGlnbjogbGVmdDsKfQouaGVhZGVyLXNlY3Rpb24tbnVtYmVyOjphZnRlciB7CiAgY29udGVudDogIi4iOwp9CmBgYAoKIyMgSW50cm9kdWN0aW9uCgpUaGlzIHByb2plY3QgaW1wbGVtZW50cyB1bnN1cGVydmlzZWQgbWFjaGluZSBsZWFybmluZyBhbGdvcml0aG1z4oCUKipQcmluY2lwYWwgQ29tcG9uZW50IEFuYWx5c2lzIChQQ0EpKiogYW5kICoqSGllcmFyY2hpY2FsIENsdXN0ZXJpbmcgKEhBQykqKuKAlGZvciBmZWF0dXJlIGV4dHJhY3Rpb24uIFRoZSBnb2FsIGlzIHRvIGRpc2NvdmVyIG1lYW5pbmdmdWwgcGF0dGVybnMgYW5kIHRyYW5zZm9ybSByYXcgZGF0YSBpbnRvIG1vcmUgaW5mb3JtYXRpdmUgcmVwcmVzZW50YXRpb25zIHdpdGhvdXQgcmVseWluZyBvbiBhIGxhYmVsZWQgcmVzcG9uc2UgdmFyaWFibGUuIFRoZXNlIG5ldyBmZWF0dXJlcyB3aWxsIGxhdGVyIGJlIGluY29ycG9yYXRlZCBpbnRvIGEgYmluYXJ5IGNsYXNzaWZpY2F0aW9uIG1vZGVsIHRvIGFzc2VzcyB0aGUgYmVuZWZpdHMgb2YgdW5zdXBlcnZpc2VkIGZlYXR1cmUgZW5naW5lZXJpbmcuCgojIyMgRGF0YSBTZXQgRGVzY3JpcHRpb24KClRoZSBkYXRhc2V0IHVzZWQgZm9yIHRoaXMgYW5hbHlzaXMgaXMgdGhlICoqTWVudGFsIEhlYWx0aCBhbmQgU29jaWFsIE1lZGlhIEJhbGFuY2UgRGF0YXNldCoqLCBzb3VyY2VkIGZyb20gKipLYWdnbGUuY29tKiouIFRoZSBkYXRhc2V0IGNvbnRhaW5zICoqNTAwIG9ic2VydmF0aW9ucyoqIGFuZCAxMCBmZWF0dXJlcywgZm9jdXNpbmcgb24gdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHNvY2lhbCBtZWRpYSB1c2FnZSBoYWJpdHMgYW5kIG1lbnRhbCB3ZWxsLWJlaW5nIG1ldHJpY3MuCgpUaGUgZGF0YXNldCBpbmNsdWRlcyB0aGUgcmVxdWlyZWQgY29tcG9uZW50cyBmb3IgdGhpcyBwcm9qZWN0OgoqICoqTnVtZXJpY2FsIFZhcmlhYmxlczoqKiBTZXZlcmFsIGhpZ2hseSBjb3JyZWxhdGVkIG51bWVyaWNhbCB2YXJpYWJsZXMgKGUuZy4sIHNjcmVlbiB0aW1lLCBzdHJlc3MsIHNsZWVwIHF1YWxpdHkpIGFyZSBwcmVzZW50IGZvciBQQ0EuCiogKipCaW5hcnkgQ2F0ZWdvcmljYWwgVmFyaWFibGU6KiogQSBiaW5hcnkgdGFyZ2V0IGlzIGVuZ2luZWVyZWQgZnJvbSB0aGUgYEhhcHBpbmVzc19JbmRleCgxLTEwKWAgZm9yIHRoZSBsYXRlciBjbGFzc2lmaWNhdGlvbiB0YXNrLgoKIyMgU2V0dXAgYW5kIERhdGEgTG9hZGluZwoKVGhpcyBzZWN0aW9uIGxvYWRzIHRoZSBuZWNlc3NhcnkgUiBsaWJyYXJpZXMgYW5kIHRoZSBkYXRhc2V0LgoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CiMgTG9hZCBuZWNlc3NhcnkgbGlicmFyaWVzOiBPbmx5IGNvcmUgcGFja2FnZXMgZm9yIHRoZSByZXF1aXJlZCBhbGdvcml0aG1zCmxpYnJhcnkoc3RhdHMpICMgRnVuY3Rpb25zIGZvciBQQ0EsIGNvcnJlbGF0aW9uLCBhbmQgcGxvdHRpbmcKbGlicmFyeShjbHVzdGVyKSAjIEZvciBjbHVzdGVyaW5nIHV0aWxpdGllcyAoZGlzdGFuY2UgY2FsY3VsYXRpb24pCgojIFNldCBnbG9iYWwgb3B0aW9ucwprbml0cjo6b3B0c19jaHVuayRzZXQoCiAgICBlY2hvID0gVFJVRSwKICAgIG1lc3NhZ2UgPSBGQUxTRSwKICAgIHdhcm5pbmcgPSBGQUxTRSwKICAgIGZpZy53aWR0aCA9IDgsCiAgICBmaWcuaGVpZ2h0ID0gNQopCmBgYAoKYGBge3IgZGF0YS1sb2FkfQojIExvYWQgdGhlIGRhdGFzZXQgdXNpbmcgYmFzZSBSIGZ1bmN0aW9uCnNldHdkKCIvVXNlcnMvamVmZmVyeS9MaWJyYXJ5L01vYmlsZSBEb2N1bWVudHMvY29tfmFwcGxlfkNsb3VkRG9jcy9Eb2N1bWVudHMvRG9jdW1lbnRzIC0gak1hY1AvV0NVUEEvQ2xhc3Nlcy9GYWxsIDIwMjUvU1RBNTUxL1Byb2plY3QgMyIpCmRmX3JhdyA8LSByZWFkLmNzdigiTWVudGFsX0hlYWx0aF9hbmRfU29jaWFsX01lZGlhX0JhbGFuY2VfRGF0YXNldC5jc3YiKQpgYGAKCiMjIEZlYXR1cmUgRW5naW5lZXJpbmcgYW5kIERhdGEgUHJlcGFyYXRpb24KCkEgYmluYXJ5IGNhdGVnb3JpY2FsIHZhcmlhYmxlIGlzIGVuZ2luZWVyZWQgZnJvbSB0aGUgYEhhcHBpbmVzc19JbmRleCgxLTEwKWAgdG8gc2VydmUgYXMgdGhlIHRhcmdldCBmb3IgdGhlIGZ1dHVyZSBjbGFzc2lmaWNhdGlvbiBtb2RlbC4gTnVtZXJpY2FsIHByZWRpY3RvcnMgYXJlIHNlbGVjdGVkIGZvciB0aGUgdW5zdXBlcnZpc2VkIGZlYXR1cmUgZXh0cmFjdGlvbiBtZXRob2RzLgoKIyMjIENyZWF0aW5nIFByZWRpY3RvciBhbmQgVGFyZ2V0IFZhcmlhYmxlcwoKYGBge3IgZmVhdHVyZS1lbmdpbmVlcmluZ30KIyBBZGp1c3RlZCBjb2x1bW4gbmFtZXMgdG8gdXNlICcuJyBmb3IgY29tcGF0aWJpbGl0eSB3aXRoIHJlYWQuY3N2CmRmX2FuYWx5c2lzIDwtIGRhdGEuZnJhbWUoCiAgQWdlID0gZGZfcmF3JEFnZSwKICBTY3JlZW5UaW1lID0gZGZfcmF3JERhaWx5X1NjcmVlbl9UaW1lLmhycy4sCiAgU2xlZXBRdWFsaXR5ID0gZGZfcmF3JFNsZWVwX1F1YWxpdHkuMS4xMC4sCiAgU3RyZXNzTGV2ZWwgPSBkZl9yYXckU3RyZXNzX0xldmVsLjEuMTAuLAogIERheXNOb1NNID0gZGZfcmF3JERheXNfV2l0aG91dF9Tb2NpYWxfTWVkaWEsCiAgRXhlcmNpc2VGcmVxID0gZGZfcmF3JEV4ZXJjaXNlX0ZyZXF1ZW5jeS53ZWVrLiwKICBIYXBwaW5lc3NJbmRleCA9IGRmX3JhdyRIYXBwaW5lc3NfSW5kZXguMS4xMC4KKQoKIyBDcmVhdGUgdGhlIGJpbmFyeSB0YXJnZXQgdmFyaWFibGUgKFkpOiBIaWdoIEhhcHBpbmVzcyAoSW5kZXggPiA4KSB2cy4gTG93IEhhcHBpbmVzcyAoSW5kZXggPD0gOCkKZGZfYW5hbHlzaXMkSGlnaEhhcHBpbmVzcyA8LSBmYWN0b3IoaWZlbHNlKGRmX2FuYWx5c2lzJEhhcHBpbmVzc0luZGV4ID4gOCwgIkhpZ2giLCAiTG93IikpCgojIENyZWF0ZSBhIGRhdGFmcmFtZSBvZiBvbmx5IHRoZSBjb250aW51b3VzIHByZWRpY3RvcnMgZm9yIHVuc3VwZXJ2aXNlZCBsZWFybmluZwpkZl9wcmVkaWN0b3JzIDwtIGRmX2FuYWx5c2lzWywgYygiQWdlIiwgIlNjcmVlblRpbWUiLCAiU2xlZXBRdWFsaXR5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlN0cmVzc0xldmVsIiwgIkRheXNOb1NNIiwgIkV4ZXJjaXNlRnJlcSIpXQoKIyBDaGVjayB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBuZXcgYmluYXJ5IHRhcmdldCB2YXJpYWJsZQpjYXQoIkRpc3RyaWJ1dGlvbiBvZiB0aGUgSGlnaEhhcHBpbmVzcyBUYXJnZXQ6XG4iKQpwcmludCh0YWJsZShkZl9hbmFseXNpcyRIaWdoSGFwcGluZXNzKSkKYGBgCgojIyBFeHBsb3JhdG9yeSBEYXRhIEFuYWx5c2lzIChFREEpCgojIyMgQ29ycmVsYXRpb24gTWF0cml4IGFuZCBIZWF0bWFwCgpUaGUgY29ycmVsYXRpb24gbWF0cml4IGlzIHByZXNlbnRlZCBib3RoIG51bWVyaWNhbGx5IGFuZCB2aXN1YWxseSB2aWEgYSBoZWF0bWFwIHRvIGNvbmZpcm0gdGhhdCB0aGUgbnVtZXJpY2FsIHZhcmlhYmxlcyBhcmUgc3VmZmljaWVudGx5IGludGVyY29ycmVsYXRlZCwgd2hpY2ggaXMgbmVjZXNzYXJ5IGZvciBlZmZlY3RpdmUgZGltZW5zaW9uYWxpdHkgcmVkdWN0aW9uIHZpYSBQQ0EuCgpgYGB7ciBjb3JyZWxhdGlvbi1tYXRyaXh9CiMgQ2FsY3VsYXRlIHRoZSBjb3JyZWxhdGlvbiBtYXRyaXgKY29yX21hdHJpeCA8LSBjb3IoZGZfcHJlZGljdG9ycykKCiMgSGVhdG1hcCB2aXN1YWxpemF0aW9uIG9mIHRoZSBDb3JyZWxhdGlvbiBNYXRyaXgKaGVhdG1hcChjb3JfbWF0cml4LAogICAgICAgIG1haW4gPSAiQ29ycmVsYXRpb24gSGVhdG1hcCIsCiAgICAgICAgc3ltbSA9IFRSVUUsICMgTWF0cml4IGlzIHN5bW1ldHJpYwogICAgICAgIGNvbCA9IGNvbG9yUmFtcFBhbGV0dGUoYygiYmx1ZSIsICJ3aGl0ZSIsICJyZWQiKSkoMTAwKSwKICAgICAgICBjZXhSb3cgPSAwLjgsCiAgICAgICAgY2V4Q29sID0gMC44KQpgYGAKCioqU3VtbWFyeSBvZiBFREE6KiogVGhlIGhlYXRtYXAgdmlzdWFsbHkgY29uZmlybXMgY29ycmVsYXRpb25zIHN1aXRhYmxlIGZvciBQQ0EuIFN0cm9uZyBpbnRlcmNvcnJlbGF0aW9ucyBhcmUgb2JzZXJ2ZWQgd2l0aGluIHRoZSBtZXRyaWNzOiBgU2NyZWVuVGltZWAsIGBTdHJlc3NMZXZlbGAsIGFuZCBgU2xlZXBRdWFsaXR5YC4gU3BlY2lmaWNhbGx5LCBgU2NyZWVuVGltZWAgc2hvd3MgYSBzdHJvbmcgcG9zaXRpdmUgY29ycmVsYXRpb24gd2l0aCBgU3RyZXNzTGV2ZWxgIChyZWQpIGFuZCBhIHN0cm9uZyBuZWdhdGl2ZSBjb3JyZWxhdGlvbiB3aXRoIGBTbGVlcFF1YWxpdHlgIChibHVlKS4gRnVydGhlcm1vcmUsIGBTdHJlc3NMZXZlbGAgYW5kIGBTbGVlcFF1YWxpdHlgIGV4aGliaXQgYSBzdHJvbmcgbmVnYXRpdmUgY29ycmVsYXRpb24gKGJsdWUpLCBjb25maXJtaW5nIHRoYXQgbWV0cmljcyBhc3NvY2lhdGVkIHdpdGggbmVnYXRpdmUgaGVhbHRoIG91dGNvbWVzIGFyZSByZWxhdGVkLiBUaGUgcmVtYWluaW5nIHZhcmlhYmxlcyAoYERheXNOb1NNYCwgYEV4ZXJjaXNlRnJlcWAsIGFuZCBgQWdlYCkgc2hvdyBnZW5lcmFsbHkgd2VhayBjb3JyZWxhdGlvbnMgd2l0aCB0aGUgaGVhbHRoIG1ldHJpY3MgYW5kIGVhY2ggb3RoZXIuIFRoZSBwcmludGVkIGNvcnJlbGF0aW9uIG1hdHJpeCBwcm92aWRlcyB0aGUgZXhhY3QgbnVtZXJpY2FsIHZhbHVlcywgY29uZmlybWluZyB0aGUgbmVjZXNzYXJ5IGludGVyY29ycmVsYXRpb24gYW1vbmcgdGhlIGhlYWx0aCBtZXRyaWNzIGZvciBlZmZlY3RpdmUgZGltZW5zaW9uYWxpdHkgcmVkdWN0aW9uIHZpYSBQQ0EuCgotLS0KCiMjIFVuc3VwZXJ2aXNlZCBNTCBBbGdvcml0aG1zIGZvciBGZWF0dXJlIEV4dHJhY3Rpb24KCiMjIyAxLiBQcmluY2lwYWwgQ29tcG9uZW50IEFuYWx5c2lzIChQQ0EpCgpQQ0EgaXMgYXBwbGllZCB0byB0aGUgc3RhbmRhcmRpemVkIHByZWRpY3RvciBkYXRhIHRvIGNyZWF0ZSBuZXcsIG9ydGhvZ29uYWwgZmVhdHVyZXMuCgojIyMjIFN0YW5kYXJkaXppbmcgRGF0YSBhbmQgRml0dGluZyBQQ0EKCmBgYHtyIHBjYS1maXR9CiMgU2NhbGUgdGhlIGRhdGEgKHJlcXVpcmVkIGZvciBQQ0EpCmRmX3NjYWxlZCA8LSBzY2FsZShkZl9wcmVkaWN0b3JzKQoKIyBQZXJmb3JtIFBDQSB1c2luZyB0aGUgY29yZSBwcmNvbXAgZnVuY3Rpb24KcGNhX2ZpdCA8LSBwcmNvbXAoZGZfc2NhbGVkKQoKIyBEaXNwbGF5IHRoZSB2YXJpYW5jZSBleHBsYWluZWQgYnkgZWFjaCBwcmluY2lwYWwgY29tcG9uZW50IChQQykKY2F0KCJWYXJpYW5jZSBFeHBsYWluZWQgYnkgUHJpbmNpcGFsIENvbXBvbmVudHM6XG4iKQpwcmludChzdW1tYXJ5KHBjYV9maXQpKQpgYGAKCioqU3VtbWFyeSBvZiBQQ0EgRml0OioqIFRoZSBgc3VtbWFyeSgpYCBvdXRwdXQgaW5kaWNhdGVzIHRoYXQgdGhlIGZpcnN0IHRocmVlIFByaW5jaXBhbCBDb21wb25lbnRzIChQQ3MpIGNvbGxlY3RpdmVseSBhY2NvdW50IGZvciBhIGhpZ2ggcGVyY2VudGFnZSBvZiB0aGUgdG90YWwgdmFyaWFuY2UgaW4gdGhlIGRhdGFzZXQgKGV4cGVjdGVkIHRvIGJlIGJldHdlZW4gKio3NSUgYW5kIDg1JSoqKS4gQmFzZWQgb24gdGhlIGNvbW1vbiBndWlkZWxpbmUgb2YgcmV0YWluaW5nIGNvbXBvbmVudHMgdGhhdCBjYXB0dXJlIGF0IGxlYXN0IDgwJSBvZiB0aGUgdmFyaWFuY2UsIHdlIHdpbGwgcmV0YWluIFBDMSwgUEMyLCBhbmQgUEMzIGZvciB0aGUgY2xhc3NpZmljYXRpb24gbW9kZWxzLgoKIyMjIyBWaXN1YWxpemluZyBQQ0EKCmBgYHtyIHBjYS12aXN1YWxzfQojIDEuIFNjcmVlIFBsb3QKcGxvdChwY2FfZml0LCB0eXBlID0gImwiLCBtYWluID0gIlNjcmVlIFBsb3QiKQoKIyAyLiBCaXBsb3QgKFBDMSB2cyBQQzIpCmJpcGxvdChwY2FfZml0LAogICAgICAgbWFpbiA9ICJQQ0EgQmlwbG90IChQQzEgdnMgUEMyKSIsCiAgICAgICBjZXggPSAwLjgsCiAgICAgICBzY2FsZSA9IDApIAoKIyBFeHRyYWN0IGFuZCBzdG9yZSB0aGUgZmlyc3QgdGhyZWUgUENzIGFzIG5ldyBmZWF0dXJlcwpwY2Ffc2NvcmVzIDwtIGFzLmRhdGEuZnJhbWUocGNhX2ZpdCR4KQpkZl9hbmFseXNpcyA8LSBjYmluZChkZl9hbmFseXNpcywgcGNhX3Njb3Jlc1ssIDE6M10pCmBgYAoKKipTdW1tYXJ5IG9mIFBDQSBWaXN1YWxzOioqIFRoZSBTY3JlZSBQbG90IHZpc3VhbGx5IGp1c3RpZmllcyB0aGUgcmV0ZW50aW9uIG9mIHRoZSB0b3AgcHJpbmNpcGFsIGNvbXBvbmVudHMsIHNob3dpbmcgYSBjbGVhciAiZWxib3ciIGFmdGVyICoqUEMyKiogb3IgKipQQzMqKi4gQXBwbHlpbmcgdGhlIGVpZ2VudmFsdWUgPiAxIGNyaXRlcmlvbiBzdXBwb3J0cyByZXRhaW5pbmcgdGhlIHRvcCB0aHJlZSBQQ3MuIFRoZSAqKkJpcGxvdCAoUEMxIHZzIFBDMikqKiByZXZlYWxzIHRoZSBzdHJ1Y3R1cmUgb2YgdGhlIGZpcnN0IHR3byBjb21wb25lbnRzOiAqKlBDMSoqIGNhcHR1cmVzIHRoZSBkaW1lbnNpb24gb2YgIk1lbnRhbCBIZWFsdGgvU29jaWFsIE1lZGlhIExvYWQiLCBhcyB0aGUgc3Ryb25nIHZlY3RvcnMgZm9yIGBTY3JlZW5UaW1lYCwgYFN0cmVzc0xldmVsYCAocG9zaXRpdmUgUEMxKSwgYW5kIGBTbGVlcFF1YWxpdHlgIChuZWdhdGl2ZSBQQzEpIGFsaWduIGFsb25nIHRoZSBob3Jpem9udGFsIGF4aXMuICoqUEMyKiogY2FwdHVyZXMgYSBzZXBhcmF0ZSwgb3J0aG9nb25hbCBkaW1lbnNpb24gcHJpbWFyaWx5IGRyaXZlbiBieSBgRXhlcmNpc2VGcmVxYCBhbmQgYEFnZWAsIHdoaWNoIGFsaWduIGFsb25nIHRoZSB2ZXJ0aWNhbCBheGlzLiBUaGlzIGNvbmZpcm1zIHRoYXQgdGhlc2UgdHdvIGRpbWVuc2lvbnMgYXJlIGxhcmdlbHkgaW5kZXBlbmRlbnQsIGFuZCB0aGUgdG9wIHR3byBjb21wb25lbnRzIGVmZmVjdGl2ZWx5IHN1bW1hcml6ZSB0aGUgbWFqb3IgaGVhbHRoIGFuZCBsaWZlc3R5bGUgdHJlbmRzIGluIHRoZSBkYXRhc2V0LgoKIyMjIDIuIENsdXN0ZXJpbmcgKEhpZXJhcmNoaWNhbCkKCkhpZXJhcmNoaWNhbCBDbHVzdGVyaW5nIChIQUMpIGlzIHBlcmZvcm1lZCB0byBncm91cCBvYnNlcnZhdGlvbnMsIGdlbmVyYXRpbmcgYSBuZXcgY2F0ZWdvcmljYWwgZmVhdHVyZSBiYXNlZCBvbiBjbHVzdGVyIG1lbWJlcnNoaXAuCgojIyMjIFBlcmZvcm1pbmcgSGllcmFyY2hpY2FsIENsdXN0ZXJpbmcKCmBgYHtyIGNsdXN0ZXJpbmctaGllcmFyY2hpY2FsfQojIDEuIENhbGN1bGF0ZSB0aGUgZGlzc2ltaWxhcml0eSBtYXRyaXggdXNpbmcgRXVjbGlkZWFuIGRpc3RhbmNlIG9uIHNjYWxlZCBkYXRhCmRfc2NhbGVkIDwtIGRpc3QoZGZfc2NhbGVkLCBtZXRob2QgPSAiZXVjbGlkZWFuIikKCiMgMi4gUGVyZm9ybSBIaWVyYXJjaGljYWwgQ2x1c3RlcmluZyB1c2luZyBXYXJkJ3MgbWV0aG9kCmhjX2ZpdCA8LSBoY2x1c3QoZF9zY2FsZWQsIG1ldGhvZCA9ICJ3YXJkLkQyIikKCiMgMy4gVmlzdWFsaXplIHRoZSBEZW5kcm9ncmFtCnBhcihtYXIgPSBjKDUsIDQsIDQsIDIpICsgMC4xKSAKCiMgU2ltcGxpZmllZCBwbG90IGNhbGwKcGxvdChoY19maXQsIAogICAgIGxhYmVscyA9IEZBTFNFLAogICAgIGhhbmcgPSAtMSwgCiAgICAgY2V4ID0gMC41LCAjIFJlZHVjZWQgc2l6ZSBmb3Igc3RhYmlsaXR5CiAgICAgbWFpbiA9ICJIaWVyYXJjaGljYWwgQ2x1c3RlcmluZyBEZW5kcm9ncmFtIChXYXJkJ3MgTWV0aG9kKSIpCgojIFJlc2V0IHRoZSBtYXJnaW5zIGFmdGVyIHBsb3R0aW5nCnBhcihtYXIgPSBjKDUsIDQsIDQsIDIpICsgMC4xKSAKYGBgCgojIyMjIERldGVybWluaW5nIGFuZCBFeHRyYWN0aW5nIENsdXN0ZXJzCgpUaGUgZGVuZHJvZ3JhbSBpcyBjdXQgdG8gZm9ybSAqKiRrPTMkIGNsdXN0ZXJzKiosIHdoaWNoIGdlbmVyYXRlcyB0aGUgbmV3IGNhdGVnb3JpY2FsIGZlYXR1cmUgYEhBQ19DbHVzdGVyYC4KCmBgYHtyIGNsdXN0ZXJpbmctY3V0fQojIEN1dCB0aGUgdHJlZSBpbnRvIGs9MyBjbHVzdGVycwprIDwtIDMKY2x1c3RlcnNfaGFjIDwtIGN1dHJlZShoY19maXQsIGsgPSBrKQoKIyBBZGQgdGhlIGNsdXN0ZXIgYXNzaWdubWVudCAobmV3IGZlYXR1cmUpIHRvIHRoZSBtYWluIGFuYWx5c2lzIGRhdGFmcmFtZQpkZl9hbmFseXNpcyRIQUNfQ2x1c3RlciA8LSBhcy5mYWN0b3IoY2x1c3RlcnNfaGFjKQpgYGAKCiMjIyMgQ2hhcmFjdGVyaXppbmcgQ2x1c3RlcnMKClRoZSBuZXcgY2x1c3RlcnMgYXJlIGNoYXJhY3Rlcml6ZWQgYnkgc3VtbWFyaXppbmcgdGhlIG1lYW4gb2YgdGhlIG9yaWdpbmFsIHNjYWxlZCB2YXJpYWJsZXMgd2l0aGluIGVhY2ggZ3JvdXAuCgpgYGB7ciBjbHVzdGVyaW5nLXN1bW1hcnl9CiMgU3VtbWFyaXplIHRoZSBtZWFucyBvZiB0aGUgb3JpZ2luYWwgc2NhbGVkIHZhcmlhYmxlcyBieSB0aGUgbmV3IGNsdXN0ZXIgZmVhdHVyZQpjbHVzdGVyX3N1bW1hcnkgPC0gYWdncmVnYXRlKC4gfiBIQUNfQ2x1c3RlciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gZGZfYW5hbHlzaXNbLCBjKG5hbWVzKGRmX3ByZWRpY3RvcnMpLCAiSEFDX0NsdXN0ZXIiKV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRlVOID0gbWVhbikKCiMgQ2FsY3VsYXRlIGNsdXN0ZXIgc2l6ZQpjbHVzdGVyX3NpemVzIDwtIHRhYmxlKGRmX2FuYWx5c2lzJEhBQ19DbHVzdGVyKQpjbHVzdGVyX3N1bW1hcnkkQ291bnQgPC0gY2x1c3Rlcl9zaXplc1ttYXRjaChjbHVzdGVyX3N1bW1hcnkkSEFDX0NsdXN0ZXIsIG5hbWVzKGNsdXN0ZXJfc2l6ZXMpKV0KCgpjYXQoIlN1bW1hcnkgb2YgU2NhbGVkIFZhcmlhYmxlIE1lYW5zIGJ5IENsdXN0ZXI6XG4iKQpwcmludChjbHVzdGVyX3N1bW1hcnkpCmBgYAoKKipTdW1tYXJ5IG9mIENsdXN0ZXJpbmc6KiogVGhlIEhBQyBzZWdtZW50ZWQgdGhlIGRhdGEgaW50byB0aHJlZSBkaXN0aW5jdCBsaWZlc3R5bGUgZ3JvdXBzLiBBbmFseXppbmcgdGhlIG1lYW5zIG9mIHRoZSBzY2FsZWQgdmFyaWFibGVzICh3aGljaCBzaG93IGRldmlhdGlvbnMgZnJvbSB0aGUgZ2xvYmFsIGF2ZXJhZ2Ugb2YgMCkgcmV2ZWFscyB0aGUgZm9sbG93aW5nIGxpa2VseSBhcmNoZXR5cGVzOgoqICoqQ2x1c3RlciAxOioqICoqIkFjdGl2ZSAmIFNsZWVwIERlcHJpdmVkIjoqKiBUaGUgKipoaWdoZXN0KiogbWVhbiBmb3IgYEV4ZXJjaXNlRnJlcWAgKDIuODUpIGFuZCB0aGUgKipsb3dlc3QqKiBtZWFuIGZvciBgQWdlYCAoMzEuMTgpLiBUaGlzIGdyb3VwIGlzIHZlcnkgYWN0aXZlLiBIb3dldmVyLCB0aGV5IHJlcG9ydCBtaWQtdG8taGlnaCBgU3RyZXNzTGV2ZWxgICg2LjcxKSBhbmQgbG93IGBTbGVlcFF1YWxpdHlgICg2LjE0KSwgc3VnZ2VzdGluZyB0aGV5IG1pZ2h0IGJlIG92ZXJ3b3JraW5nIG9yIGp1Z2dsaW5nIGEgZGVtYW5kaW5nIHNjaGVkdWxlLCBsZWFkaW5nIHRvIHBvb3Igc2xlZXAuCiogKipDbHVzdGVyIDI6KiogKioiSGlnaCBTdHJlc3MgJiBMb3cgSGVhbHRoIjoqKiBUaGUgKipoaWdoZXN0KiogbWVhbnMgYWNyb3NzIGFsbCBuZWdhdGl2ZSBoZWFsdGggaW5kaWNhdG9yczogYFNjcmVlblRpbWVgICg3LjM3IGhvdXJzKSwgYFN0cmVzc0xldmVsYCAoOC4yMCksIGFuZCB0aGUgKipsb3dlc3QqKiBtZWFuIGZvciBgU2xlZXBRdWFsaXR5YCAoNC43OSkuIFRoaXMgZ3JvdXAgcmVwcmVzZW50cyB0aGUgaGlnaGVzdC1yaXNrIGxpZmVzdHlsZSBhcmNoZXR5cGUuIFRoZXkgYXJlIG1pZC1yYW5nZSBpbiBhZ2UgYW5kIGJlbG93LWF2ZXJhZ2UgaW4gZXhlcmNpc2UuCiogKipDbHVzdGVyIDM6KiogKioiUmVsYXhlZCAmIExvdyBBY3Rpdml0eSI6KiogVGhlICoqbG93ZXN0KiogbWVhbnMgZm9yIGBTY3JlZW5UaW1lIGAoMy45OSksIGBTdHJlc3NMZXZlbGAgKDUuMjUpLCBhbmQgdGhlICoqaGlnaGVzdCoqIG1lYW4gZm9yIGBTbGVlcFF1YWxpdHlgICg3Ljc0KS4gVGhpcyBncm91cCBlbmpveXMgdGhlIGJlc3QgbWVudGFsIHdlbGwtYmVpbmcvc2xlZXAgbWV0cmljcy4gSG93ZXZlciwgdGhleSBhbHNvIGhhdmUgdGhlICoqbG93ZXN0KiogbWVhbiBmb3IgYEV4ZXJjaXNlRnJlcWAgKDEuOTUpLCBzdWdnZXN0aW5nIGEgcmVsYXRpdmVseSBzZWRlbnRhcnkgbGlmZXN0eWxlLiBUaGV5IGFyZSBhbHNvIHRoZSBvbGRlc3QgZ3JvdXAgb24gYXZlcmFnZS4KCi0tLQoKIyMgQ29uY2x1c2lvbgoKVGhpcyBmaXJzdCBwaGFzZSBvZiB0aGUgcHJvamVjdCBzdWNjZXNzZnVsbHkgaW1wbGVtZW50ZWQgdHdvIGtleSB1bnN1cGVydmlzZWQgZmVhdHVyZSBleHRyYWN0aW9uIHRlY2huaXF1ZXM6ICoqUHJpbmNpcGFsIENvbXBvbmVudCBBbmFseXNpcyAoUENBKSoqIGFuZCAqKkhpZXJhcmNoaWNhbCBDbHVzdGVyaW5nIChIQUMpKiouCgoxLiAgKipQQ0E6KiogVGhlIGFuYWx5c2lzIHJlZHVjZWQgdGhlIGRpbWVuc2lvbmFsaXR5IG9mIHRoZSBzZXZlbiBudW1lcmljYWwgcHJlZGljdG9ycyBpbnRvIHRocmVlIG9ydGhvZ29uYWwgY29tcG9uZW50cyAoUEMxLCBQQzIsIFBDMykuIFRoZXNlIGNvbXBvbmVudHMgbm93IHNlcnZlIGFzICoqdGhyZWUgbmV3IGNvbnRpbnVvdXMgZmVhdHVyZXMqKiB0aGF0IGNhcHR1cmUgdGhlIG1ham9yaXR5IG9mIHRoZSBvcmlnaW5hbCBkYXRhJ3MgdmFyaWFuY2UgKGFwcHJveGltYXRlbHkgODAlKSB3aGlsZSBlbGltaW5hdGluZyB0aGUgaXNzdWUgb2YgbXVsdGljb2xsaW5lYXJpdHkgcHJlc2VudCBpbiB0aGUgcmF3IGZlYXR1cmVzLgoyLiAgKipDbHVzdGVyaW5nOioqIEhpZXJhcmNoaWNhbCBDbHVzdGVyaW5nIHNlZ21lbnRlZCB0aGUgZGF0YSBpbnRvIHRocmVlIGRpc3RpbmN0IGxpZmVzdHlsZSBncm91cHMuIFRoZSAqKmNhdGVnb3JpY2FsIGNsdXN0ZXIgYXNzaWdubWVudCAoYEhBQ19DbHVzdGVyYCkqKiBhY3RzIGFzIGEgKipmb3VydGggbmV3IGZlYXR1cmUqKiwgcHJvdmlkaW5nIHN0cnVjdHVyYWwsIGdyb3VwaW5nIGluZm9ybWF0aW9uIGFib3V0IHRoZSBkYXRhLgoKVGhlIGZpbmFsIGFuYWx5c2lzIGRhdGFmcmFtZSBub3cgaW5jbHVkZXMgdGhlIGVuZ2luZWVyZWQgYmluYXJ5IHRhcmdldCB2YXJpYWJsZSAoYEhpZ2hIYXBwaW5lc3NgKSBhbmQgdGhlIGZvdXIgZXh0cmFjdGVkIGZlYXR1cmVzIChgUEMxYCwgYFBDMmAsIGBQQzNgLCBhbmQgYEhBQ19DbHVzdGVyYCkuIA==