1 Introduction

Following the analysis in Part 1, this section implements the Local Outlier Factor (LOF) algorithm. LOF is an unsupervised detection method that identifies anomalies by comparing the local density of a data point to that of its neighbors. A score significantly higher than 1 implies the point is in a sparse region (an outlier).

2 Setup and Data Loading

# Load the dataset
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")

3 Feature Engineering and Data Preparation

# Create the main dataframe
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 vs. Low Happiness
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")]

4 Unsupervised ML: Local Outlier Factor (LOF)

We utilize the lof() function from the {dbscan} package. The LOF score depends on the parameter \(k\) (neighborhood size).

4.1 Calculating LOF Scores

# Scale the predictor data (LOF is distance-based and requires scaling)
df_scaled <- scale(df_predictors)

# Calculate LOF scores using k = 20 nearest neighbors
k_value <- 20
lof_scores <- lof(df_scaled, minPts = k_value)

# Add the LOF scores to the main dataframe as a new feature
df_analysis$LOF_Score <- lof_scores

# Display summary statistics to understand the range (Min, Max)
cat("Summary of Local Outlier Factor (LOF) Scores:\n")
## Summary of Local Outlier Factor (LOF) Scores:
print(summary(df_analysis$LOF_Score))
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##  0.9512  0.9982  1.0328  1.0567  1.0885  1.4734

Summary of Analysis: The summary statistics for the computed Local Outlier Factor (LOF) scores reveal a distribution centered near 1.0 (Median: 1.0328, Mean: 1.0567). A score of approximately 1.0 indicates that a data point has a local density similar to its neighbors (an “inlier”). The maximum score observed is 1.4734. While this indicates the presence of data points that are less dense than their neighbors, the absence of extremely high scores (e.g., > 2.0 or higher) suggests that this dataset does not contain extreme anomalies or radical outliers. The majority of data points exhibit patterns that are relatively consistent with their peers.

4.2 Visualizing LOF Distribution

We visualize the LOF scores against the Happiness Index. Based on the summary statistics, we set a cut-off threshold of 1.25 to identify the most significant outliers in this specific dataset.

# Histogram of LOF Scores
hist(df_analysis$LOF_Score,
     breaks = 30,
     main = paste("Distribution of LOF Scores (k =", k_value, ")"),
     xlab = "LOF Score",
     col = "lightblue",
     border = "white")
abline(v = 1.25, col = "red", lwd = 2, lty = 2) # Threshold

# Scatter plot of LOF scores vs Happiness Index
# Threshold adjusted to 1.25 based on data distribution to catch the top ~5-10% outliers
threshold <- 1.25
plot(df_analysis$HappinessIndex, df_analysis$LOF_Score,
     main = "LOF Score vs. Happiness Index",
     xlab = "Happiness Index (Original)",
     ylab = "LOF Score",
     pch = 19,
     col = ifelse(df_analysis$LOF_Score > threshold, "red", "darkblue"))

legend("topright", 
       legend = c(paste("Outlier Score (>", threshold, ")", sep=""), "Normal Score"),
       col = c("red", "darkblue"), 
       pch = 19)

Summary of LOF Analysis: The histogram shows the density of LOF scores. Most data points cluster near 1.0 (Inliers). The scatter plot highlights observations with LOF scores greater than 1.25 in red. These points represent individuals whose behavioral patterns (Screen Time, Sleep, Stress, etc.) are significantly different from the local density of their peers.


5 Supervised Learning: Binary Classification

We compare a baseline logistic regression model against one enriched with the extracted LOF_Score.

5.1 Model Training

# Split data into Training (70%) and Testing (30%)
set.seed(123)
trainIndex <- createDataPartition(df_analysis$HighHappiness, p = 0.7, list = FALSE)
train_data <- df_analysis[trainIndex, ]
test_data <- df_analysis[-trainIndex, ]

# Model 1: Baseline Logistic Regression
model_baseline <- glm(HighHappiness ~ Age + ScreenTime + SleepQuality + 
                      StressLevel + DaysNoSM + ExerciseFreq,
                      data = train_data,
                      family = "binomial")

# Model 2: LOF-Enhanced Logistic Regression
model_lof <- glm(HighHappiness ~ Age + ScreenTime + SleepQuality + 
                 StressLevel + DaysNoSM + ExerciseFreq + LOF_Score,
                 data = train_data,
                 family = "binomial")

# Compare Model Summaries (AIC)
cat("Baseline Model AIC:", round(model_baseline$aic, 2), "\n")
## Baseline Model AIC: 257.24
cat("LOF-Enhanced Model AIC:", round(model_lof$aic, 2), "\n")
## LOF-Enhanced Model AIC: 258.91

Summary of Analysis: We utilized the Akaike Information Criterion (AIC) to compare the quality of the models, where a lower value indicates a better trade-off between model fit and complexity. * Baseline Model AIC: 257.24 * LOF-Enhanced Model AIC: 258.91

The results show that the Baseline model actually achieved a slightly lower AIC than the LOF-Enhanced model. This increase in AIC for the enhanced model suggests that the LOF_Score feature did not add sufficient predictive power to justify the penalty for the added model complexity. In statistical terms, the “outlierness” of a data point does not appear to improve the model’s fit to the training data compared to using the original predictors alone.

5.2 Model Evaluation (ROC and AUC)

# Predict probabilities
prob_baseline <- predict(model_baseline, newdata = test_data, type = "response")
prob_lof <- predict(model_lof, newdata = test_data, type = "response")

# Calculate ROC Curves
roc_baseline <- roc(test_data$HighHappiness, prob_baseline, levels = c("Low", "High"), direction = ">")
roc_lof <- roc(test_data$HighHappiness, prob_lof, levels = c("Low", "High"), direction = ">")

# Plot ROC Curves
plot(roc_baseline, col = "blue", main = "ROC Curve Comparison", lwd = 2)
plot(roc_lof, col = "red", add = TRUE, lwd = 2, lty = 2)
legend("bottomright", legend = c(paste("Baseline AUC =", round(auc(roc_baseline), 4)),
                                 paste("LOF AUC =", round(auc(roc_lof), 4))),
       col = c("blue", "red"), lty = c(1, 2), lwd = 2)

6 Conclusion

  1. Outlier Detection: Using a neighborhood size of \(k=20\), we identified a subset of observations with LOF scores exceeding 1.25. These “local outliers” represent unique behavioral profiles in the dataset.
  2. Feature Importance: By adding the LOF score to the classification model, we assessed its contribution to predicting happiness. The comparison of AIC and AUC values indicates whether the “unusualness” of a person’s habits serves as a predictive signal for their mental well-being.
LS0tCnRpdGxlOiAiUHJvamVjdCBUaHJlZTogRmVhdHVyZSBFeHRyYWN0aW9uIHdpdGggVW5zdXBlcnZpc2VkIEFsZ29yaXRobXMsIFBhcnQgMjogTG9jYWwgT3V0bGllciBGYWN0b3IgKExPRikiCmF1dGhvcjogIkplZmYgRGVsdmEiCmRhdGU6ICJOb3ZlbWJlciAyMHRoLCAyMDI1IgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwogICAgdG9jX2RlcHRoOiA0CiAgICBmaWdfd2lkdGg6IDgKICAgIGZpZ19oZWlnaHQ6IDUKICAgIGZpZ19jYXB0aW9uOiB5ZXMKICAgIG51bWJlcl9zZWN0aW9uczogeWVzCiAgICB0b2NfY29sbGFwc2VkOiB5ZXMKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgY29kZV9kb3dubG9hZDogeWVzCiAgICBzbW9vdGhfc2Nyb2xsOiB5ZXMKICAgIHRoZW1lOiBsdW1lbgogICAgaGlnaGxpZ2h0OiB0YW5nbwotLS0KCmBgYHtjc3MsIGVjaG8gPSBGQUxTRX0KaDEudGl0bGUgewogIGZvbnQtc2l6ZTogMjRweDsKICBmb250LXdlaWdodDogYm9sZDsKICBjb2xvcjogRGFya1JlZDsKICB0ZXh0LWFsaWduOiBjZW50ZXI7Cn0KaDQuYXV0aG9yLCBoNC5kYXRlIHsKICBmb250LXNpemU6IDE4cHg7CiAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgY29sb3I6IERhcmtCbHVlOwogIHRleHQtYWxpZ246IGNlbnRlcjsKfQpoMSB7CiAgICBmb250LXNpemU6IDIwcHg7CiAgICBmb250LXdlaWdodDogYm9sZDsKICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogICAgY29sb3I6IGRhcmtyZWQ7CiAgICB0ZXh0LWFsaWduOiBjZW50ZXI7Cn0KaDIgewogICAgZm9udC1zaXplOiAxOHB4OwogICAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICAgIGNvbG9yOiBuYXZ5OwogICAgdGV4dC1hbGlnbjogbGVmdDsKfQpoMyB7CiAgICBmb250LXNpemU6IDE2cHg7CiAgICBmb250LXdlaWdodDogYm9sZDsKICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogICAgY29sb3I6IG5hdnk7CiAgICB0ZXh0LWFsaWduOiBsZWZ0Owp9Ci5oZWFkZXItc2VjdGlvbi1udW1iZXI6OmFmdGVyIHsKICBjb250ZW50OiAiLiI7Cn0KYGBgCgojIyBJbnRyb2R1Y3Rpb24KCkZvbGxvd2luZyB0aGUgYW5hbHlzaXMgaW4gUGFydCAxLCB0aGlzIHNlY3Rpb24gaW1wbGVtZW50cyB0aGUgKipMb2NhbCBPdXRsaWVyIEZhY3RvciAoTE9GKSoqIGFsZ29yaXRobS4gTE9GIGlzIGFuIHVuc3VwZXJ2aXNlZCBkZXRlY3Rpb24gbWV0aG9kIHRoYXQgaWRlbnRpZmllcyBhbm9tYWxpZXMgYnkgY29tcGFyaW5nIHRoZSBsb2NhbCBkZW5zaXR5IG9mIGEgZGF0YSBwb2ludCB0byB0aGF0IG9mIGl0cyBuZWlnaGJvcnMuIEEgc2NvcmUgc2lnbmlmaWNhbnRseSBoaWdoZXIgdGhhbiAxIGltcGxpZXMgdGhlIHBvaW50IGlzIGluIGEgc3BhcnNlIHJlZ2lvbiAoYW4gb3V0bGllcikuCgojIyBTZXR1cCBhbmQgRGF0YSBMb2FkaW5nCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KIyBMb2FkIG5lY2Vzc2FyeSBsaWJyYXJpZXMKbGlicmFyeShzdGF0cykgICAgCmxpYnJhcnkoZGJzY2FuKSAgICMgRm9yIExvY2FsIE91dGxpZXIgRmFjdG9yIChMT0YpIGFsZ29yaXRobQpsaWJyYXJ5KHBST0MpICAgICAjIEZvciBST0MgY3VydmUgYW5kIEFVQyBjYWxjdWxhdGlvbgpsaWJyYXJ5KGNhcmV0KSAgICAjIEZvciBkYXRhIHNwbGl0dGluZwoKIyBTZXQgZ2xvYmFsIG9wdGlvbnMKa25pdHI6Om9wdHNfY2h1bmskc2V0KAogICAgZWNobyA9IFRSVUUsCiAgICBtZXNzYWdlID0gRkFMU0UsCiAgICB3YXJuaW5nID0gRkFMU0UsCiAgICBmaWcud2lkdGggPSA4LAogICAgZmlnLmhlaWdodCA9IDUKKQpgYGAKCmBgYHtyIGRhdGEtbG9hZH0KIyBMb2FkIHRoZSBkYXRhc2V0CnNldHdkKCIvVXNlcnMvamVmZmVyeS9MaWJyYXJ5L01vYmlsZSBEb2N1bWVudHMvY29tfmFwcGxlfkNsb3VkRG9jcy9Eb2N1bWVudHMvRG9jdW1lbnRzIC0gak1hY1AvV0NVUEEvQ2xhc3Nlcy9GYWxsIDIwMjUvU1RBNTUxL1Byb2plY3QgMyIpCmRmX3JhdyA8LSByZWFkLmNzdigiTWVudGFsX0hlYWx0aF9hbmRfU29jaWFsX01lZGlhX0JhbGFuY2VfRGF0YXNldC5jc3YiKQpgYGAKCiMjIEZlYXR1cmUgRW5naW5lZXJpbmcgYW5kIERhdGEgUHJlcGFyYXRpb24KCmBgYHtyIGZlYXR1cmUtZW5naW5lZXJpbmd9CiMgQ3JlYXRlIHRoZSBtYWluIGRhdGFmcmFtZQpkZl9hbmFseXNpcyA8LSBkYXRhLmZyYW1lKAogIEFnZSA9IGRmX3JhdyRBZ2UsCiAgU2NyZWVuVGltZSA9IGRmX3JhdyREYWlseV9TY3JlZW5fVGltZS5ocnMuLAogIFNsZWVwUXVhbGl0eSA9IGRmX3JhdyRTbGVlcF9RdWFsaXR5LjEuMTAuLAogIFN0cmVzc0xldmVsID0gZGZfcmF3JFN0cmVzc19MZXZlbC4xLjEwLiwKICBEYXlzTm9TTSA9IGRmX3JhdyREYXlzX1dpdGhvdXRfU29jaWFsX01lZGlhLAogIEV4ZXJjaXNlRnJlcSA9IGRmX3JhdyRFeGVyY2lzZV9GcmVxdWVuY3kud2Vlay4sCiAgSGFwcGluZXNzSW5kZXggPSBkZl9yYXckSGFwcGluZXNzX0luZGV4LjEuMTAuCikKCiMgQ3JlYXRlIHRoZSBiaW5hcnkgdGFyZ2V0IHZhcmlhYmxlIChZKTogSGlnaCBIYXBwaW5lc3MgdnMuIExvdyBIYXBwaW5lc3MKZGZfYW5hbHlzaXMkSGlnaEhhcHBpbmVzcyA8LSBmYWN0b3IoaWZlbHNlKGRmX2FuYWx5c2lzJEhhcHBpbmVzc0luZGV4ID4gOCwgIkhpZ2giLCAiTG93IikpCgojIENyZWF0ZSBhIGRhdGFmcmFtZSBvZiBvbmx5IHRoZSBjb250aW51b3VzIHByZWRpY3RvcnMgZm9yIHVuc3VwZXJ2aXNlZCBsZWFybmluZwpkZl9wcmVkaWN0b3JzIDwtIGRmX2FuYWx5c2lzWywgYygiQWdlIiwgIlNjcmVlblRpbWUiLCAiU2xlZXBRdWFsaXR5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlN0cmVzc0xldmVsIiwgIkRheXNOb1NNIiwgIkV4ZXJjaXNlRnJlcSIpXQpgYGAKCi0tLS0tCgojIyBVbnN1cGVydmlzZWQgTUw6IExvY2FsIE91dGxpZXIgRmFjdG9yIChMT0YpCgpXZSB1dGlsaXplIHRoZSBgbG9mKClgIGZ1bmN0aW9uIGZyb20gdGhlIGB7ZGJzY2FufWAgcGFja2FnZS4gVGhlIExPRiBzY29yZSBkZXBlbmRzIG9uIHRoZSBwYXJhbWV0ZXIgJGskIChuZWlnaGJvcmhvb2Qgc2l6ZSkuCgojIyMgQ2FsY3VsYXRpbmcgTE9GIFNjb3JlcwoKYGBge3IgbG9mLWNhbGN1bGF0aW9ufQojIFNjYWxlIHRoZSBwcmVkaWN0b3IgZGF0YSAoTE9GIGlzIGRpc3RhbmNlLWJhc2VkIGFuZCByZXF1aXJlcyBzY2FsaW5nKQpkZl9zY2FsZWQgPC0gc2NhbGUoZGZfcHJlZGljdG9ycykKCiMgQ2FsY3VsYXRlIExPRiBzY29yZXMgdXNpbmcgayA9IDIwIG5lYXJlc3QgbmVpZ2hib3JzCmtfdmFsdWUgPC0gMjAKbG9mX3Njb3JlcyA8LSBsb2YoZGZfc2NhbGVkLCBtaW5QdHMgPSBrX3ZhbHVlKQoKIyBBZGQgdGhlIExPRiBzY29yZXMgdG8gdGhlIG1haW4gZGF0YWZyYW1lIGFzIGEgbmV3IGZlYXR1cmUKZGZfYW5hbHlzaXMkTE9GX1Njb3JlIDwtIGxvZl9zY29yZXMKCiMgRGlzcGxheSBzdW1tYXJ5IHN0YXRpc3RpY3MgdG8gdW5kZXJzdGFuZCB0aGUgcmFuZ2UgKE1pbiwgTWF4KQpjYXQoIlN1bW1hcnkgb2YgTG9jYWwgT3V0bGllciBGYWN0b3IgKExPRikgU2NvcmVzOlxuIikKcHJpbnQoc3VtbWFyeShkZl9hbmFseXNpcyRMT0ZfU2NvcmUpKQpgYGAKCioqU3VtbWFyeSBvZiBBbmFseXNpczoqKiBUaGUgc3VtbWFyeSBzdGF0aXN0aWNzIGZvciB0aGUgY29tcHV0ZWQgTG9jYWwgT3V0bGllciBGYWN0b3IgKExPRikgc2NvcmVzIHJldmVhbCBhIGRpc3RyaWJ1dGlvbiBjZW50ZXJlZCBuZWFyIDEuMCAoTWVkaWFuOiAxLjAzMjgsIE1lYW46IDEuMDU2NykuIEEgc2NvcmUgb2YgYXBwcm94aW1hdGVseSAxLjAgaW5kaWNhdGVzIHRoYXQgYSBkYXRhIHBvaW50IGhhcyBhIGxvY2FsIGRlbnNpdHkgc2ltaWxhciB0byBpdHMgbmVpZ2hib3JzIChhbiAiaW5saWVyIikuIFRoZSBtYXhpbXVtIHNjb3JlIG9ic2VydmVkIGlzIDEuNDczNC4gV2hpbGUgdGhpcyBpbmRpY2F0ZXMgdGhlIHByZXNlbmNlIG9mIGRhdGEgcG9pbnRzIHRoYXQgYXJlIGxlc3MgZGVuc2UgdGhhbiB0aGVpciBuZWlnaGJvcnMsIHRoZSBhYnNlbmNlIG9mIGV4dHJlbWVseSBoaWdoIHNjb3JlcyAoZS5nLiwgPiAyLjAgb3IgaGlnaGVyKSBzdWdnZXN0cyB0aGF0IHRoaXMgZGF0YXNldCBkb2VzIG5vdCBjb250YWluIGV4dHJlbWUgYW5vbWFsaWVzIG9yIHJhZGljYWwgb3V0bGllcnMuIFRoZSBtYWpvcml0eSBvZiBkYXRhIHBvaW50cyBleGhpYml0IHBhdHRlcm5zIHRoYXQgYXJlIHJlbGF0aXZlbHkgY29uc2lzdGVudCB3aXRoIHRoZWlyIHBlZXJzLgoKIyMjIFZpc3VhbGl6aW5nIExPRiBEaXN0cmlidXRpb24KCldlIHZpc3VhbGl6ZSB0aGUgTE9GIHNjb3JlcyBhZ2FpbnN0IHRoZSBIYXBwaW5lc3MgSW5kZXguIEJhc2VkIG9uIHRoZSBzdW1tYXJ5IHN0YXRpc3RpY3MsIHdlIHNldCBhIGN1dC1vZmYgdGhyZXNob2xkIG9mICoqMS4yNSoqIHRvIGlkZW50aWZ5IHRoZSBtb3N0IHNpZ25pZmljYW50IG91dGxpZXJzIGluIHRoaXMgc3BlY2lmaWMgZGF0YXNldC4KCmBgYHtyIGxvZi12aXN1YWxzfQojIEhpc3RvZ3JhbSBvZiBMT0YgU2NvcmVzCmhpc3QoZGZfYW5hbHlzaXMkTE9GX1Njb3JlLAogICAgIGJyZWFrcyA9IDMwLAogICAgIG1haW4gPSBwYXN0ZSgiRGlzdHJpYnV0aW9uIG9mIExPRiBTY29yZXMgKGsgPSIsIGtfdmFsdWUsICIpIiksCiAgICAgeGxhYiA9ICJMT0YgU2NvcmUiLAogICAgIGNvbCA9ICJsaWdodGJsdWUiLAogICAgIGJvcmRlciA9ICJ3aGl0ZSIpCmFibGluZSh2ID0gMS4yNSwgY29sID0gInJlZCIsIGx3ZCA9IDIsIGx0eSA9IDIpICMgVGhyZXNob2xkCgojIFNjYXR0ZXIgcGxvdCBvZiBMT0Ygc2NvcmVzIHZzIEhhcHBpbmVzcyBJbmRleAojIFRocmVzaG9sZCBhZGp1c3RlZCB0byAxLjI1IGJhc2VkIG9uIGRhdGEgZGlzdHJpYnV0aW9uIHRvIGNhdGNoIHRoZSB0b3AgfjUtMTAlIG91dGxpZXJzCnRocmVzaG9sZCA8LSAxLjI1CnBsb3QoZGZfYW5hbHlzaXMkSGFwcGluZXNzSW5kZXgsIGRmX2FuYWx5c2lzJExPRl9TY29yZSwKICAgICBtYWluID0gIkxPRiBTY29yZSB2cy4gSGFwcGluZXNzIEluZGV4IiwKICAgICB4bGFiID0gIkhhcHBpbmVzcyBJbmRleCAoT3JpZ2luYWwpIiwKICAgICB5bGFiID0gIkxPRiBTY29yZSIsCiAgICAgcGNoID0gMTksCiAgICAgY29sID0gaWZlbHNlKGRmX2FuYWx5c2lzJExPRl9TY29yZSA+IHRocmVzaG9sZCwgInJlZCIsICJkYXJrYmx1ZSIpKQoKbGVnZW5kKCJ0b3ByaWdodCIsIAogICAgICAgbGVnZW5kID0gYyhwYXN0ZSgiT3V0bGllciBTY29yZSAoPiIsIHRocmVzaG9sZCwgIikiLCBzZXA9IiIpLCAiTm9ybWFsIFNjb3JlIiksCiAgICAgICBjb2wgPSBjKCJyZWQiLCAiZGFya2JsdWUiKSwgCiAgICAgICBwY2ggPSAxOSkKYGBgCgoqKlN1bW1hcnkgb2YgTE9GIEFuYWx5c2lzOioqIFRoZSBoaXN0b2dyYW0gc2hvd3MgdGhlIGRlbnNpdHkgb2YgTE9GIHNjb3Jlcy4gTW9zdCBkYXRhIHBvaW50cyBjbHVzdGVyIG5lYXIgMS4wIChJbmxpZXJzKS4gVGhlIHNjYXR0ZXIgcGxvdCBoaWdobGlnaHRzIG9ic2VydmF0aW9ucyB3aXRoIExPRiBzY29yZXMgZ3JlYXRlciB0aGFuIDEuMjUgaW4gcmVkLiBUaGVzZSBwb2ludHMgcmVwcmVzZW50IGluZGl2aWR1YWxzIHdob3NlIGJlaGF2aW9yYWwgcGF0dGVybnMgKFNjcmVlbiBUaW1lLCBTbGVlcCwgU3RyZXNzLCBldGMuKSBhcmUgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnQgZnJvbSB0aGUgbG9jYWwgZGVuc2l0eSBvZiB0aGVpciBwZWVycy4KCi0tLS0tCgojIyBTdXBlcnZpc2VkIExlYXJuaW5nOiBCaW5hcnkgQ2xhc3NpZmljYXRpb24KCldlIGNvbXBhcmUgYSBiYXNlbGluZSBsb2dpc3RpYyByZWdyZXNzaW9uIG1vZGVsIGFnYWluc3Qgb25lIGVucmljaGVkIHdpdGggdGhlIGV4dHJhY3RlZCBgTE9GX1Njb3JlYC4KCiMjIyBNb2RlbCBUcmFpbmluZwoKYGBge3IgY2xhc3NpZmljYXRpb24tbW9kZWxzfQojIFNwbGl0IGRhdGEgaW50byBUcmFpbmluZyAoNzAlKSBhbmQgVGVzdGluZyAoMzAlKQpzZXQuc2VlZCgxMjMpCnRyYWluSW5kZXggPC0gY3JlYXRlRGF0YVBhcnRpdGlvbihkZl9hbmFseXNpcyRIaWdoSGFwcGluZXNzLCBwID0gMC43LCBsaXN0ID0gRkFMU0UpCnRyYWluX2RhdGEgPC0gZGZfYW5hbHlzaXNbdHJhaW5JbmRleCwgXQp0ZXN0X2RhdGEgPC0gZGZfYW5hbHlzaXNbLXRyYWluSW5kZXgsIF0KCiMgTW9kZWwgMTogQmFzZWxpbmUgTG9naXN0aWMgUmVncmVzc2lvbgptb2RlbF9iYXNlbGluZSA8LSBnbG0oSGlnaEhhcHBpbmVzcyB+IEFnZSArIFNjcmVlblRpbWUgKyBTbGVlcFF1YWxpdHkgKyAKICAgICAgICAgICAgICAgICAgICAgIFN0cmVzc0xldmVsICsgRGF5c05vU00gKyBFeGVyY2lzZUZyZXEsCiAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gdHJhaW5fZGF0YSwKICAgICAgICAgICAgICAgICAgICAgIGZhbWlseSA9ICJiaW5vbWlhbCIpCgojIE1vZGVsIDI6IExPRi1FbmhhbmNlZCBMb2dpc3RpYyBSZWdyZXNzaW9uCm1vZGVsX2xvZiA8LSBnbG0oSGlnaEhhcHBpbmVzcyB+IEFnZSArIFNjcmVlblRpbWUgKyBTbGVlcFF1YWxpdHkgKyAKICAgICAgICAgICAgICAgICBTdHJlc3NMZXZlbCArIERheXNOb1NNICsgRXhlcmNpc2VGcmVxICsgTE9GX1Njb3JlLAogICAgICAgICAgICAgICAgIGRhdGEgPSB0cmFpbl9kYXRhLAogICAgICAgICAgICAgICAgIGZhbWlseSA9ICJiaW5vbWlhbCIpCgojIENvbXBhcmUgTW9kZWwgU3VtbWFyaWVzIChBSUMpCmNhdCgiQmFzZWxpbmUgTW9kZWwgQUlDOiIsIHJvdW5kKG1vZGVsX2Jhc2VsaW5lJGFpYywgMiksICJcbiIpCmNhdCgiTE9GLUVuaGFuY2VkIE1vZGVsIEFJQzoiLCByb3VuZChtb2RlbF9sb2YkYWljLCAyKSwgIlxuIikKYGBgCioqU3VtbWFyeSBvZiBBbmFseXNpczoqKgpXZSB1dGlsaXplZCB0aGUgQWthaWtlIEluZm9ybWF0aW9uIENyaXRlcmlvbiAoQUlDKSB0byBjb21wYXJlIHRoZSBxdWFsaXR5IG9mIHRoZSBtb2RlbHMsIHdoZXJlIGEgbG93ZXIgdmFsdWUgaW5kaWNhdGVzIGEgYmV0dGVyIHRyYWRlLW9mZiBiZXR3ZWVuIG1vZGVsIGZpdCBhbmQgY29tcGxleGl0eS4KKiAqKkJhc2VsaW5lIE1vZGVsIEFJQzoqKiAyNTcuMjQKKiAqKkxPRi1FbmhhbmNlZCBNb2RlbCBBSUM6KiogMjU4LjkxCgpUaGUgcmVzdWx0cyBzaG93IHRoYXQgdGhlIEJhc2VsaW5lIG1vZGVsIGFjdHVhbGx5IGFjaGlldmVkIGEgc2xpZ2h0bHkgbG93ZXIgQUlDIHRoYW4gdGhlIExPRi1FbmhhbmNlZCBtb2RlbC4gVGhpcyBpbmNyZWFzZSBpbiBBSUMgZm9yIHRoZSBlbmhhbmNlZCBtb2RlbCBzdWdnZXN0cyB0aGF0IHRoZSBgTE9GX1Njb3JlYCBmZWF0dXJlIGRpZCBub3QgYWRkIHN1ZmZpY2llbnQgcHJlZGljdGl2ZSBwb3dlciB0byBqdXN0aWZ5IHRoZSBwZW5hbHR5IGZvciB0aGUgYWRkZWQgbW9kZWwgY29tcGxleGl0eS4gSW4gc3RhdGlzdGljYWwgdGVybXMsIHRoZSAib3V0bGllcm5lc3MiIG9mIGEgZGF0YSBwb2ludCBkb2VzIG5vdCBhcHBlYXIgdG8gaW1wcm92ZSB0aGUgbW9kZWwncyBmaXQgdG8gdGhlIHRyYWluaW5nIGRhdGEgY29tcGFyZWQgdG8gdXNpbmcgdGhlIG9yaWdpbmFsIHByZWRpY3RvcnMgYWxvbmUuCgoKIyMjIE1vZGVsIEV2YWx1YXRpb24gKFJPQyBhbmQgQVVDKQoKYGBge3IgbW9kZWwtZXZhbHVhdGlvbn0KIyBQcmVkaWN0IHByb2JhYmlsaXRpZXMKcHJvYl9iYXNlbGluZSA8LSBwcmVkaWN0KG1vZGVsX2Jhc2VsaW5lLCBuZXdkYXRhID0gdGVzdF9kYXRhLCB0eXBlID0gInJlc3BvbnNlIikKcHJvYl9sb2YgPC0gcHJlZGljdChtb2RlbF9sb2YsIG5ld2RhdGEgPSB0ZXN0X2RhdGEsIHR5cGUgPSAicmVzcG9uc2UiKQoKIyBDYWxjdWxhdGUgUk9DIEN1cnZlcwpyb2NfYmFzZWxpbmUgPC0gcm9jKHRlc3RfZGF0YSRIaWdoSGFwcGluZXNzLCBwcm9iX2Jhc2VsaW5lLCBsZXZlbHMgPSBjKCJMb3ciLCAiSGlnaCIpLCBkaXJlY3Rpb24gPSAiPiIpCnJvY19sb2YgPC0gcm9jKHRlc3RfZGF0YSRIaWdoSGFwcGluZXNzLCBwcm9iX2xvZiwgbGV2ZWxzID0gYygiTG93IiwgIkhpZ2giKSwgZGlyZWN0aW9uID0gIj4iKQoKIyBQbG90IFJPQyBDdXJ2ZXMKcGxvdChyb2NfYmFzZWxpbmUsIGNvbCA9ICJibHVlIiwgbWFpbiA9ICJST0MgQ3VydmUgQ29tcGFyaXNvbiIsIGx3ZCA9IDIpCnBsb3Qocm9jX2xvZiwgY29sID0gInJlZCIsIGFkZCA9IFRSVUUsIGx3ZCA9IDIsIGx0eSA9IDIpCmxlZ2VuZCgiYm90dG9tcmlnaHQiLCBsZWdlbmQgPSBjKHBhc3RlKCJCYXNlbGluZSBBVUMgPSIsIHJvdW5kKGF1Yyhyb2NfYmFzZWxpbmUpLCA0KSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlKCJMT0YgQVVDID0iLCByb3VuZChhdWMocm9jX2xvZiksIDQpKSksCiAgICAgICBjb2wgPSBjKCJibHVlIiwgInJlZCIpLCBsdHkgPSBjKDEsIDIpLCBsd2QgPSAyKQpgYGAKCiMjIENvbmNsdXNpb24KCjEuICAqKk91dGxpZXIgRGV0ZWN0aW9uOioqIFVzaW5nIGEgbmVpZ2hib3Job29kIHNpemUgb2YgJGs9MjAkLCB3ZSBpZGVudGlmaWVkIGEgc3Vic2V0IG9mIG9ic2VydmF0aW9ucyB3aXRoIExPRiBzY29yZXMgZXhjZWVkaW5nIDEuMjUuIFRoZXNlICJsb2NhbCBvdXRsaWVycyIgcmVwcmVzZW50IHVuaXF1ZSBiZWhhdmlvcmFsIHByb2ZpbGVzIGluIHRoZSBkYXRhc2V0LgoyLiAgKipGZWF0dXJlIEltcG9ydGFuY2U6KiogQnkgYWRkaW5nIHRoZSBMT0Ygc2NvcmUgdG8gdGhlIGNsYXNzaWZpY2F0aW9uIG1vZGVsLCB3ZSBhc3Nlc3NlZCBpdHMgY29udHJpYnV0aW9uIHRvIHByZWRpY3RpbmcgaGFwcGluZXNzLiBUaGUgY29tcGFyaXNvbiBvZiBBSUMgYW5kIEFVQyB2YWx1ZXMgaW5kaWNhdGVzIHdoZXRoZXIgdGhlICJ1bnVzdWFsbmVzcyIgb2YgYSBwZXJzb24ncyBoYWJpdHMgc2VydmVzIGFzIGEgcHJlZGljdGl2ZSBzaWduYWwgZm9yIHRoZWlyIG1lbnRhbCB3ZWxsLWJlaW5nLgoK