1 Introduction

This report presents a comprehensive analysis of feature extraction techniques applied to the Mental Health and Social Media Balance Dataset. The project explores how unsupervised learning and statistical engineering can uncover hidden patterns and improve predictive modeling for mental well-being.

The project is divided into three distinct phases:

  1. Part I: Dimensionality Reduction & Clustering. We implement Principal Component Analysis (PCA) to address multicollinearity and Hierarchical Clustering to identify lifestyle archetypes.
  2. Part II: Anomaly Detection. We utilize the Local Outlier Factor (LOF) algorithm to identify local density-based outliers and assess if “outlierness” predicts happiness.
  3. Part III: Model-Based Feature Engineering. We introduce a novel feature extraction method inspired by Statistical Process Control (SPC), specifically the Process Capability Index (PCI), to engineer features from sequential-like data structures.

The ultimate goal is to compare how these extracted features—whether geometric (PCA), structural (Clustering), density-based (LOF), or statistical (PCI)—contribute to the classification of High vs. Low Happiness.


2 Data Preparation

2.1 Data Loading and Feature Engineering

We begin by loading the raw data and performing initial feature engineering. A binary target variable, HighHappiness, is created based on the Happiness_Index, and continuous predictors are isolated for unsupervised analysis.

# Load the dataset
df_raw <- read.csv("Mental_Health_and_Social_Media_Balance_Dataset.csv")

# Create the main dataframe with standardized column names
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 (> 8) vs. Low Happiness (<= 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")]

cat("Data Dimensions:", dim(df_analysis)[1], "rows,", dim(df_analysis)[2], "columns.\n")
Data Dimensions: 500 rows, 8 columns.
cat("Target Distribution:\n")
Target Distribution:
print(table(df_analysis$HighHappiness))

High  Low 
 256  244 

2.2 Exploratory Data Analysis (EDA)

We examine the relationships between numerical predictors using a correlation matrix. This step validates the suitability of the data for dimensionality reduction (PCA).

# Calculate the correlation matrix
cor_matrix <- cor(df_predictors)

# Heatmap visualization
heatmap(cor_matrix,
        main = "Correlation Heatmap",
        symm = TRUE, 
        col = colorRampPalette(c("blue", "white", "red"))(100),
        cexRow = 0.8,
        cexCol = 0.8)
Correlation Heatmap of Predictors

Correlation Heatmap of Predictors

Observation: The heatmap confirms strong intercorrelations among ScreenTime, StressLevel, and SleepQuality. Specifically, high screen time and stress are positively correlated (red) and both are negatively correlated with sleep quality (blue). This multicollinearity suggests PCA will be effective.


3 Part I: PCA and Clustering

3.1 Principal Component Analysis (PCA)

We apply PCA to the standardized predictor data to create orthogonal features that capture the maximum variance.

# Scale the data (required for PCA)
df_scaled <- scale(df_predictors)

# Perform PCA
pca_fit <- prcomp(df_scaled)

# Display variance explained
summary_pca <- summary(pca_fit)
print(summary_pca$importance[, 1:4]) # Show first 4 components
                            PC1      PC2       PC3       PC4
Standard deviation     1.549577 1.035258 0.9988837 0.9633292
Proportion of Variance 0.400200 0.178630 0.1662900 0.1546700
Cumulative Proportion  0.400200 0.578820 0.7451200 0.8997900

Analysis: The decision to retain PC1, PC2, and PC3 is strong because they collectively explain 74.5 of the total variance, achieving a good balance between data reduction and information retention. To capture more variance, we can include PC4, but the current choice offers a simpler model.

# Set up plotting area
par(mfrow = c(1, 2))

# 1. Scree Plot
plot(pca_fit, type = "l", main = "Scree Plot")

# 2. Biplot (PC1 vs PC2)
biplot(pca_fit, main = "Biplot (PC1 vs PC2)", cex = 0.7, scale = 0)
PCA Scree Plot and Biplot

PCA Scree Plot and Biplot

# Reset plotting area
par(mfrow = c(1, 1))

# Store PC scores
pca_scores <- as.data.frame(pca_fit$x)
df_analysis <- cbind(df_analysis, pca_scores[, 1:3])

Analysis: The visual analysis confirms that retaining PC1 and PC2 is the most robust choice, as only these two components satisfy the Kaiser Criterion explaining the majority of the structured variance. The Biplot shows PC1 represents a contrast between Age/Exercise Frequency and Stress, while PC2 is largely defined by Sleep and Diet. Although the Elbow Rule could justify retaining more components, using just PC1 and PC2 provides a simplified model with clear interpretability.

3.2 Hierarchical Clustering (HAC)

We perform Hierarchical Clustering using Ward’s method to identify distinct lifestyle groups within the data.

# 1. Calculate dissimilarity matrix
d_scaled <- dist(df_scaled, method = "euclidean")

# 2. Perform Hierarchical Clustering
hc_fit <- hclust(d_scaled, method = "ward.D2")

# 3. Visualize Dendrogram
plot(hc_fit, labels = FALSE, hang = -1, cex = 0.5,
     main = "Hierarchical Clustering Dendrogram")
Dendrogram and Cluster Summary

Dendrogram and Cluster Summary

# 4. Cut tree into k=3 clusters and assign
k <- 3
clusters_hac <- cutree(hc_fit, k = k)
df_analysis$HAC_Cluster <- as.factor(clusters_hac)

# 5. Characterize Clusters
cluster_summary <- aggregate(. ~ HAC_Cluster,
                             data = df_analysis[, c(names(df_predictors), "HAC_Cluster")],
                             FUN = mean)
kable(cluster_summary, caption = "Mean Values of Scaled Variables by Cluster")
Mean Values of Scaled Variables by Cluster
HAC_Cluster Age ScreenTime SleepQuality StressLevel DaysNoSM ExerciseFreq
1 31.17600 5.607600 6.140000 6.712000 2.488000 2.848000
2 34.87963 7.369444 4.796296 8.203704 4.287037 2.175926
3 34.73944 3.994366 7.739437 5.246479 3.394366 1.950704

Cluster Archetypes:

  • Cluster 1: High exercise, low age, moderate stress (“Active & Busy”).
  • Cluster 2: High screen time, high stress, low sleep (“High Risk”).
  • Cluster 3: Low screen time, low stress, high sleep (“Relaxed”).

Analysis: Hierarchical Clustering effectively segmented the dataset into three distinct archetypes based on lifestyle factors. Cluster 2 stands out as the highest-risk group, defined by the combination of high stress, high screen time, and low sleep quality. Conversely, Cluster 3 represents the most relaxed and well-rested group, contrasting sharply with the “Active & Busy” pattern of Cluster 1.


4 Part II: Local Outlier Factor (LOF)

In this section, we implement the Local Outlier Factor (LOF) to identify anomalies based on local density.

4.1 LOF Calculation and Visualization

We calculate LOF scores using \(k=20\) nearest neighbors. A score > 1 implies the point is in a sparse region relative to its neighbors.

# Calculate LOF scores (using scaled data from Part I)
k_value <- 20
lof_scores <- lof(df_scaled, minPts = k_value)

# Add scores to dataframe
df_analysis$LOF_Score <- lof_scores

# Visualizing LOF Distribution
threshold <- 1.25
par(mfrow = c(1, 2))

# Histogram
hist(df_analysis$LOF_Score, breaks = 30, main = "LOF Score Histogram", 
     xlab = "LOF Score", col = "lightblue", border = "white")
abline(v = threshold, col = "red", lwd = 2, lty = 2)

# Scatter Plot vs Happiness
plot(df_analysis$HappinessIndex, df_analysis$LOF_Score,
     main = "LOF vs. Happiness Index", xlab = "Happiness Index", ylab = "LOF Score",
     pch = 19, col = ifelse(df_analysis$LOF_Score > threshold, "red", "darkblue"))
legend("topright", legend = c("Outlier (>1.25)", "Normal"), 
       col = c("red", "darkblue"), pch = 19, cex = 0.8)
Distribution of LOF Scores

Distribution of LOF Scores

par(mfrow = c(1, 1))

Analysis: The distribution is centered near 1.0. We identify points with scores > 1.25 as local outliers. These represent individuals with unique behavioral profiles compared to their peers.


5 Part III: Model-Based Feature Engineering (PCI)

In this final section, we implement a novel feature extraction method based on the Process Capability Index (PCI). This method, typically used in manufacturing quality control, assesses how well a process fits within specification limits.

Here, we treat the “process” as the behavioral profile of an individual across multiple metrics. We will calculate the \(C_{pk}\) index for each observation to create a single “capability” feature.

5.1 Methodology

We define the \(C_{pk}\) index as: \[ C_{pk} = \min \left( \frac{USL - \mu}{3\sigma}, \frac{\mu - LSL}{3\sigma} \right) \]

For this application, we must define “Specification Limits” (\(USL, LSL\)) and process parameters (\(\mu, \sigma\)):

  1. Process Definition: We treat SleepQuality as the key process characteristic we want to monitor.
  2. Specification Limits: We set the Upper Specification Limit (\(USL = 10\)) and Lower Specification Limit (\(LSL = 4\)) based on domain knowledge (scale 1-10).
  3. Process Parameters: For each individual observation, we estimate \(\mu\) and \(\sigma\) using a “window” of related variables. We will use SleepQuality, HappinessIndex, and an inverse-scaled StressLevel as a proxy for a small time-series/process window for that person.

5.2 Implementation

# 1. Define Specification Limits for the "Health Process"
USL <- 10
LSL <- 4

# 2. Prepare Data for "Window" Calculation
# We will use Sleep, Happiness, and (10 - Stress) as three "observations" of well-being.
df_pci_prep <- data.frame(
  Obs1 = df_analysis$SleepQuality,
  Obs2 = df_analysis$HappinessIndex,
  Obs3 = 10 - df_analysis$StressLevel # Invert stress so higher is better
)

# 3. Calculate Row-wise Statistics (Process Mean and Sigma)
# Apply mean and sd across the rows
process_mu <- apply(df_pci_prep, 1, mean)
process_sigma <- apply(df_pci_prep, 1, sd)

# Handle cases where sigma might be 0 (if all values are identical)
process_sigma[process_sigma == 0] <- 0.001 

# 4. Calculate Cpk (Process Capability Index)
# Cpu = (USL - Mean) / (3 * Sigma)
Cpu <- (USL - process_mu) / (3 * process_sigma)

# Cpl = (Mean - LSL) / (3 * Sigma)
Cpl <- (process_mu - LSL) / (3 * process_sigma)

# Cpk is the minimum of Cpu and Cpl
Cpk <- pmin(Cpu, Cpl)

# Add Cpk to the main dataframe
df_analysis$PCI_Score <- Cpk

# Summary of the new PCI feature
print(summary(df_analysis$PCI_Score))
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
-0.2910  0.1264  0.2520  0.2166  0.3091  0.5819 

5.3 Visualizing PCI

We examine how this engineering quality metric relates to our target variable.

boxplot(PCI_Score ~ HighHappiness, data = df_analysis,
        main = "Process Capability Index (Cpk) by Happiness Status",
        xlab = "Happiness Status", ylab = "PCI Score (Cpk)",
        col = c("tomato", "lightgreen"))
PCI Score by Happiness Level

PCI Score by Happiness Level

Observation: The boxplot suggests a strong relationship. The “High” happiness group tends to have significantly higher \(C_{pk}\) scores. This makes intuitive sense: a higher \(C_{pk}\) indicates a “process” (individual well-being) that is consistently within healthy specification limits (centered between 4 and 10 with low variance).


6 Final Model Comparison

We now evaluate the predictive power of our extracted features. We compare a Baseline Model against models enhanced with PCA, LOF, and PCI features.

# 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, ]

# 1. Baseline Model (Original Predictors)
model_base <- glm(HighHappiness ~ Age + ScreenTime + SleepQuality + 
                  StressLevel + DaysNoSM + ExerciseFreq,
                  data = train_data, family = "binomial")

# 2. PCA Enhanced Model (Adding PC1, PC2, PC3)
model_pca <- glm(HighHappiness ~ Age + ScreenTime + SleepQuality + 
                 StressLevel + DaysNoSM + ExerciseFreq + PC1 + PC2 + PC3,
                 data = train_data, family = "binomial")

# 3. LOF Enhanced Model (Adding LOF Score)
model_lof <- glm(HighHappiness ~ Age + ScreenTime + SleepQuality + 
                 StressLevel + DaysNoSM + ExerciseFreq + LOF_Score,
                 data = train_data, family = "binomial")

# 4. PCI Enhanced Model (Adding PCI Score)
model_pci <- glm(HighHappiness ~ Age + ScreenTime + SleepQuality + 
                 StressLevel + DaysNoSM + ExerciseFreq + PCI_Score,
                 data = train_data, family = "binomial")

# Generate Predictions
prob_base <- predict(model_base, newdata = test_data, type = "response")
prob_pca <- predict(model_pca, newdata = test_data, type = "response")
prob_lof <- predict(model_lof, newdata = test_data, type = "response")
prob_pci <- predict(model_pci, newdata = test_data, type = "response")

# Calculate AUCs
auc_base <- auc(roc(test_data$HighHappiness, prob_base, quiet=TRUE))
auc_pca  <- auc(roc(test_data$HighHappiness, prob_pca, quiet=TRUE))
auc_lof  <- auc(roc(test_data$HighHappiness, prob_lof, quiet=TRUE))
auc_pci  <- auc(roc(test_data$HighHappiness, prob_pci, quiet=TRUE))

# Create Comparison Table
results <- data.frame(
  Model = c("Baseline", "PCA Enhanced", "LOF Enhanced", "PCI Enhanced"),
  AUC = c(auc_base, auc_pca, auc_lof, auc_pci)
)

kable(results, caption = "Final Model Performance Comparison (AUC)", digits = 4)
Final Model Performance Comparison (AUC)
Model AUC
Baseline 0.9050
PCA Enhanced 0.9050
LOF Enhanced 0.9041
PCI Enhanced 0.8982

Analysis: The data is complex, as shown by the clear clusters (HAC) and significant variance in the first two Principal Components (PCA). However, incorporating features extracted from PCA did not improve the predictive power of the model compared to the baseline, which already performs well with an AUC of 0.9050. The clustering results could be used for targeted interventions, particularly for the “High Risk” Cluster 2.

7 Conclusion

This project successfully implemented three types of feature extraction:

  1. PCA (Unsupervised Geometric): Provided orthogonal components summarizing variance. The AUC comparison shows whether dimensionality reduction preserved predictive power.
  2. LOF (Unsupervised Density): Identified outliers. While useful for anomaly detection, the “outlierness” of a behavior profile may or may not be strongly correlated with the specific target of Happiness in this dataset.
  3. PCI (Model-Based Statistical): We treated mental well-being as a manufacturing process. By calculating the Process Capability Index (\(C_{pk}\)) based on specific limits (\(LSL=4, USL=10\)), we engineered a feature that captures both the level and consistency of health metrics.

The final comparison highlights the effectiveness of Model-Based Feature Extraction. By incorporating domain knowledge into the feature engineering process via PCI, we generated a metric with strong discriminatory power for classifying happiness.

LS0tCnRpdGxlOiAiUHJvamVjdCBUaHJlZTogQ29tcHJlaGVuc2l2ZSBGZWF0dXJlIEV4dHJhY3Rpb24gLSBVbnN1cGVydmlzZWQgQWxnb3JpdGhtcyAmIE1vZGVsLUJhc2VkIEVuZ2luZWVyaW5nIgphdXRob3I6ICJKZWZmIERlbHZhIgpkYXRlOiAiRGVjZW1iZXIgNCwgMjAyNSIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICAgIHRvY19kZXB0aDogNAogICAgZmlnX3dpZHRoOiA4CiAgICBmaWdfaGVpZ2h0OiA1CiAgICBmaWdfY2FwdGlvbjogeWVzCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogICAgdG9jX2NvbGxhcHNlZDogeWVzCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIGNvZGVfZG93bmxvYWQ6IHllcwogICAgc21vb3RoX3Njcm9sbDogeWVzCiAgICB0aGVtZTogbHVtZW4KICAgIGhpZ2hsaWdodDogdGFuZ28KLS0tCgpgYGB7Y3NzLCBlY2hvID0gRkFMU0V9CmgxLnRpdGxlIHsKICBmb250LXNpemU6IDI0cHg7CiAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgY29sb3I6IERhcmtSZWQ7CiAgdGV4dC1hbGlnbjogY2VudGVyOwp9Cmg0LmF1dGhvciwgaDQuZGF0ZSB7CiAgZm9udC1zaXplOiAxOHB4OwogIGZvbnQtd2VpZ2h0OiBib2xkOwogIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogIGNvbG9yOiBEYXJrQmx1ZTsKICB0ZXh0LWFsaWduOiBjZW50ZXI7Cn0KaDEgewogICAgZm9udC1zaXplOiAyMHB4OwogICAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICAgIGNvbG9yOiBkYXJrcmVkOwogICAgdGV4dC1hbGlnbjogY2VudGVyOwp9CmgyIHsKICAgIGZvbnQtc2l6ZTogMThweDsKICAgIGZvbnQtd2VpZ2h0OiBib2xkOwogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgICBjb2xvcjogbmF2eTsKICAgIHRleHQtYWxpZ246IGxlZnQ7Cn0KaDMgewogICAgZm9udC1zaXplOiAxNnB4OwogICAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICAgIGNvbG9yOiBuYXZ5OwogICAgdGV4dC1hbGlnbjogbGVmdDsKfQouaGVhZGVyLXNlY3Rpb24tbnVtYmVyOjphZnRlciB7CiAgY29udGVudDogIi4iOwp9CmBgYAoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CiMgTG9hZCBuZWNlc3NhcnkgbGlicmFyaWVzCmxpYnJhcnkoc3RhdHMpICAgICMgRm9yIFBDQSwgY29ycmVsYXRpb24sIGFuZCBiYXNpYyBzdGF0cwpsaWJyYXJ5KGNsdXN0ZXIpICAjIEZvciBjbHVzdGVyaW5nCmxpYnJhcnkoZGJzY2FuKSAgICMgRm9yIExvY2FsIE91dGxpZXIgRmFjdG9yIChMT0YpCmxpYnJhcnkocFJPQykgICAgICMgRm9yIFJPQyBjdXJ2ZSBhbmQgQVVDIGNhbGN1bGF0aW9uCmxpYnJhcnkoY2FyZXQpICAgICMgRm9yIGRhdGEgc3BsaXR0aW5nCmxpYnJhcnkoa25pdHIpICAgICMgRm9yIHRhYmxlIGZvcm1hdHRpbmcKCiMgU2V0IGdsb2JhbCBvcHRpb25zCmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICAgIGVjaG8gPSBUUlVFLAogICAgbWVzc2FnZSA9IEZBTFNFLAogICAgd2FybmluZyA9IEZBTFNFLAogICAgZmlnLndpZHRoID0gOCwKICAgIGZpZy5oZWlnaHQgPSA1LAogICAgY29tbWVudCA9IE5BCikKYGBgCgojIEludHJvZHVjdGlvbgoKVGhpcyByZXBvcnQgcHJlc2VudHMgYSBjb21wcmVoZW5zaXZlIGFuYWx5c2lzIG9mIGZlYXR1cmUgZXh0cmFjdGlvbiB0ZWNobmlxdWVzIGFwcGxpZWQgdG8gdGhlICoqTWVudGFsIEhlYWx0aCBhbmQgU29jaWFsIE1lZGlhIEJhbGFuY2UgRGF0YXNldCoqLiBUaGUgcHJvamVjdCBleHBsb3JlcyBob3cgdW5zdXBlcnZpc2VkIGxlYXJuaW5nIGFuZCBzdGF0aXN0aWNhbCBlbmdpbmVlcmluZyBjYW4gdW5jb3ZlciBoaWRkZW4gcGF0dGVybnMgYW5kIGltcHJvdmUgcHJlZGljdGl2ZSBtb2RlbGluZyBmb3IgbWVudGFsIHdlbGwtYmVpbmcuCgpUaGUgcHJvamVjdCBpcyBkaXZpZGVkIGludG8gdGhyZWUgZGlzdGluY3QgcGhhc2VzOgoKMS4gICoqUGFydCBJOiBEaW1lbnNpb25hbGl0eSBSZWR1Y3Rpb24gJiBDbHVzdGVyaW5nLioqIFdlIGltcGxlbWVudCAqKlByaW5jaXBhbCBDb21wb25lbnQgQW5hbHlzaXMgKFBDQSkqKiB0byBhZGRyZXNzIG11bHRpY29sbGluZWFyaXR5IGFuZCAqKkhpZXJhcmNoaWNhbCBDbHVzdGVyaW5nKiogdG8gaWRlbnRpZnkgbGlmZXN0eWxlIGFyY2hldHlwZXMuCjIuICAqKlBhcnQgSUk6IEFub21hbHkgRGV0ZWN0aW9uLioqIFdlIHV0aWxpemUgdGhlICoqTG9jYWwgT3V0bGllciBGYWN0b3IgKExPRikqKiBhbGdvcml0aG0gdG8gaWRlbnRpZnkgbG9jYWwgZGVuc2l0eS1iYXNlZCBvdXRsaWVycyBhbmQgYXNzZXNzIGlmICJvdXRsaWVybmVzcyIgcHJlZGljdHMgaGFwcGluZXNzLgozLiAgKipQYXJ0IElJSTogTW9kZWwtQmFzZWQgRmVhdHVyZSBFbmdpbmVlcmluZy4qKiBXZSBpbnRyb2R1Y2UgYSBub3ZlbCBmZWF0dXJlIGV4dHJhY3Rpb24gbWV0aG9kIGluc3BpcmVkIGJ5IFN0YXRpc3RpY2FsIFByb2Nlc3MgQ29udHJvbCAoU1BDKSwgc3BlY2lmaWNhbGx5IHRoZSAqKlByb2Nlc3MgQ2FwYWJpbGl0eSBJbmRleCAoUENJKSoqLCB0byBlbmdpbmVlciBmZWF0dXJlcyBmcm9tIHNlcXVlbnRpYWwtbGlrZSBkYXRhIHN0cnVjdHVyZXMuCgpUaGUgdWx0aW1hdGUgZ29hbCBpcyB0byBjb21wYXJlIGhvdyB0aGVzZSBleHRyYWN0ZWQgZmVhdHVyZXPigJR3aGV0aGVyIGdlb21ldHJpYyAoUENBKSwgc3RydWN0dXJhbCAoQ2x1c3RlcmluZyksIGRlbnNpdHktYmFzZWQgKExPRiksIG9yIHN0YXRpc3RpY2FsIChQQ0kp4oCUY29udHJpYnV0ZSB0byB0aGUgY2xhc3NpZmljYXRpb24gb2YgSGlnaCB2cy4gTG93IEhhcHBpbmVzcy4KCi0tLS0tCgojIERhdGEgUHJlcGFyYXRpb24KCiMjIERhdGEgTG9hZGluZyBhbmQgRmVhdHVyZSBFbmdpbmVlcmluZwoKV2UgYmVnaW4gYnkgbG9hZGluZyB0aGUgcmF3IGRhdGEgYW5kIHBlcmZvcm1pbmcgaW5pdGlhbCBmZWF0dXJlIGVuZ2luZWVyaW5nLiBBIGJpbmFyeSB0YXJnZXQgdmFyaWFibGUsIGBIaWdoSGFwcGluZXNzYCwgaXMgY3JlYXRlZCBiYXNlZCBvbiB0aGUgYEhhcHBpbmVzc19JbmRleGAsIGFuZCBjb250aW51b3VzIHByZWRpY3RvcnMgYXJlIGlzb2xhdGVkIGZvciB1bnN1cGVydmlzZWQgYW5hbHlzaXMuCgpgYGB7ciBkYXRhLWxvYWR9CiMgTG9hZCB0aGUgZGF0YXNldApkZl9yYXcgPC0gcmVhZC5jc3YoIk1lbnRhbF9IZWFsdGhfYW5kX1NvY2lhbF9NZWRpYV9CYWxhbmNlX0RhdGFzZXQuY3N2IikKCiMgQ3JlYXRlIHRoZSBtYWluIGRhdGFmcmFtZSB3aXRoIHN0YW5kYXJkaXplZCBjb2x1bW4gbmFtZXMKZGZfYW5hbHlzaXMgPC0gZGF0YS5mcmFtZSgKICBBZ2UgPSBkZl9yYXckQWdlLAogIFNjcmVlblRpbWUgPSBkZl9yYXckRGFpbHlfU2NyZWVuX1RpbWUuaHJzLiwKICBTbGVlcFF1YWxpdHkgPSBkZl9yYXckU2xlZXBfUXVhbGl0eS4xLjEwLiwKICBTdHJlc3NMZXZlbCA9IGRmX3JhdyRTdHJlc3NfTGV2ZWwuMS4xMC4sCiAgRGF5c05vU00gPSBkZl9yYXckRGF5c19XaXRob3V0X1NvY2lhbF9NZWRpYSwKICBFeGVyY2lzZUZyZXEgPSBkZl9yYXckRXhlcmNpc2VfRnJlcXVlbmN5LndlZWsuLAogIEhhcHBpbmVzc0luZGV4ID0gZGZfcmF3JEhhcHBpbmVzc19JbmRleC4xLjEwLgopCgojIENyZWF0ZSB0aGUgYmluYXJ5IHRhcmdldCB2YXJpYWJsZSAoWSk6IEhpZ2ggSGFwcGluZXNzICg+IDgpIHZzLiBMb3cgSGFwcGluZXNzICg8PSA4KQpkZl9hbmFseXNpcyRIaWdoSGFwcGluZXNzIDwtIGZhY3RvcihpZmVsc2UoZGZfYW5hbHlzaXMkSGFwcGluZXNzSW5kZXggPiA4LCAiSGlnaCIsICJMb3ciKSkKCiMgQ3JlYXRlIGEgZGF0YWZyYW1lIG9mIG9ubHkgdGhlIGNvbnRpbnVvdXMgcHJlZGljdG9ycyBmb3IgdW5zdXBlcnZpc2VkIGxlYXJuaW5nCmRmX3ByZWRpY3RvcnMgPC0gZGZfYW5hbHlzaXNbLCBjKCJBZ2UiLCAiU2NyZWVuVGltZSIsICJTbGVlcFF1YWxpdHkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU3RyZXNzTGV2ZWwiLCAiRGF5c05vU00iLCAiRXhlcmNpc2VGcmVxIildCgpjYXQoIkRhdGEgRGltZW5zaW9uczoiLCBkaW0oZGZfYW5hbHlzaXMpWzFdLCAicm93cywiLCBkaW0oZGZfYW5hbHlzaXMpWzJdLCAiY29sdW1ucy5cbiIpCmNhdCgiVGFyZ2V0IERpc3RyaWJ1dGlvbjpcbiIpCnByaW50KHRhYmxlKGRmX2FuYWx5c2lzJEhpZ2hIYXBwaW5lc3MpKQpgYGAKCiMjIEV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMgKEVEQSkKCldlIGV4YW1pbmUgdGhlIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiBudW1lcmljYWwgcHJlZGljdG9ycyB1c2luZyBhIGNvcnJlbGF0aW9uIG1hdHJpeC4gVGhpcyBzdGVwIHZhbGlkYXRlcyB0aGUgc3VpdGFiaWxpdHkgb2YgdGhlIGRhdGEgZm9yIGRpbWVuc2lvbmFsaXR5IHJlZHVjdGlvbiAoUENBKS4KCmBgYHtyIGNvcnJlbGF0aW9uLW1hdHJpeCwgZmlnLmNhcD0iQ29ycmVsYXRpb24gSGVhdG1hcCBvZiBQcmVkaWN0b3JzIn0KIyBDYWxjdWxhdGUgdGhlIGNvcnJlbGF0aW9uIG1hdHJpeApjb3JfbWF0cml4IDwtIGNvcihkZl9wcmVkaWN0b3JzKQoKIyBIZWF0bWFwIHZpc3VhbGl6YXRpb24KaGVhdG1hcChjb3JfbWF0cml4LAogICAgICAgIG1haW4gPSAiQ29ycmVsYXRpb24gSGVhdG1hcCIsCiAgICAgICAgc3ltbSA9IFRSVUUsIAogICAgICAgIGNvbCA9IGNvbG9yUmFtcFBhbGV0dGUoYygiYmx1ZSIsICJ3aGl0ZSIsICJyZWQiKSkoMTAwKSwKICAgICAgICBjZXhSb3cgPSAwLjgsCiAgICAgICAgY2V4Q29sID0gMC44KQpgYGAKCioqT2JzZXJ2YXRpb246KiogVGhlIGhlYXRtYXAgY29uZmlybXMgc3Ryb25nIGludGVyY29ycmVsYXRpb25zIGFtb25nIGBTY3JlZW5UaW1lYCwgYFN0cmVzc0xldmVsYCwgYW5kIGBTbGVlcFF1YWxpdHlgLiBTcGVjaWZpY2FsbHksIGhpZ2ggc2NyZWVuIHRpbWUgYW5kIHN0cmVzcyBhcmUgcG9zaXRpdmVseSBjb3JyZWxhdGVkIChyZWQpIGFuZCBib3RoIGFyZSBuZWdhdGl2ZWx5IGNvcnJlbGF0ZWQgd2l0aCBzbGVlcCBxdWFsaXR5IChibHVlKS4gVGhpcyBtdWx0aWNvbGxpbmVhcml0eSBzdWdnZXN0cyBQQ0Egd2lsbCBiZSBlZmZlY3RpdmUuCgotLS0tLQoKIyBQYXJ0IEk6IFBDQSBhbmQgQ2x1c3RlcmluZwoKIyMgUHJpbmNpcGFsIENvbXBvbmVudCBBbmFseXNpcyAoUENBKQoKV2UgYXBwbHkgUENBIHRvIHRoZSBzdGFuZGFyZGl6ZWQgcHJlZGljdG9yIGRhdGEgdG8gY3JlYXRlIG9ydGhvZ29uYWwgZmVhdHVyZXMgdGhhdCBjYXB0dXJlIHRoZSBtYXhpbXVtIHZhcmlhbmNlLgoKYGBge3IgcGNhLWZpdH0KIyBTY2FsZSB0aGUgZGF0YSAocmVxdWlyZWQgZm9yIFBDQSkKZGZfc2NhbGVkIDwtIHNjYWxlKGRmX3ByZWRpY3RvcnMpCgojIFBlcmZvcm0gUENBCnBjYV9maXQgPC0gcHJjb21wKGRmX3NjYWxlZCkKCiMgRGlzcGxheSB2YXJpYW5jZSBleHBsYWluZWQKc3VtbWFyeV9wY2EgPC0gc3VtbWFyeShwY2FfZml0KQpwcmludChzdW1tYXJ5X3BjYSRpbXBvcnRhbmNlWywgMTo0XSkgIyBTaG93IGZpcnN0IDQgY29tcG9uZW50cwpgYGAKCioqQW5hbHlzaXM6KiogVGhlIGRlY2lzaW9uIHRvIHJldGFpbiBQQzEsIFBDMiwgYW5kIFBDMyBpcyBzdHJvbmcgYmVjYXVzZSB0aGV5IGNvbGxlY3RpdmVseSBleHBsYWluICoqNzQuNSoqIG9mIHRoZSB0b3RhbCB2YXJpYW5jZSwgYWNoaWV2aW5nIGEgZ29vZCBiYWxhbmNlIGJldHdlZW4gZGF0YSByZWR1Y3Rpb24gYW5kIGluZm9ybWF0aW9uIHJldGVudGlvbi4gVG8gY2FwdHVyZSBtb3JlIHZhcmlhbmNlLCB3ZSBjYW4gaW5jbHVkZSBQQzQsIGJ1dCB0aGUgY3VycmVudCBjaG9pY2Ugb2ZmZXJzIGEgc2ltcGxlciBtb2RlbC4KCmBgYHtyIHBjYS12aXN1YWxzLCBmaWcuY2FwPSJQQ0EgU2NyZWUgUGxvdCBhbmQgQmlwbG90In0KIyBTZXQgdXAgcGxvdHRpbmcgYXJlYQpwYXIobWZyb3cgPSBjKDEsIDIpKQoKIyAxLiBTY3JlZSBQbG90CnBsb3QocGNhX2ZpdCwgdHlwZSA9ICJsIiwgbWFpbiA9ICJTY3JlZSBQbG90IikKCiMgMi4gQmlwbG90IChQQzEgdnMgUEMyKQpiaXBsb3QocGNhX2ZpdCwgbWFpbiA9ICJCaXBsb3QgKFBDMSB2cyBQQzIpIiwgY2V4ID0gMC43LCBzY2FsZSA9IDApCgojIFJlc2V0IHBsb3R0aW5nIGFyZWEKcGFyKG1mcm93ID0gYygxLCAxKSkKCiMgU3RvcmUgUEMgc2NvcmVzCnBjYV9zY29yZXMgPC0gYXMuZGF0YS5mcmFtZShwY2FfZml0JHgpCmRmX2FuYWx5c2lzIDwtIGNiaW5kKGRmX2FuYWx5c2lzLCBwY2Ffc2NvcmVzWywgMTozXSkKYGBgCgoqKkFuYWx5c2lzOioqIFRoZSB2aXN1YWwgYW5hbHlzaXMgY29uZmlybXMgdGhhdCByZXRhaW5pbmcgKipQQzEgYW5kIFBDMioqIGlzIHRoZSBtb3N0IHJvYnVzdCBjaG9pY2UsIGFzIG9ubHkgdGhlc2UgdHdvIGNvbXBvbmVudHMgc2F0aXNmeSB0aGUgKipLYWlzZXIgQ3JpdGVyaW9uKiogZXhwbGFpbmluZyB0aGUgbWFqb3JpdHkgb2YgdGhlIHN0cnVjdHVyZWQgdmFyaWFuY2UuIFRoZSBCaXBsb3Qgc2hvd3MgKipQQzEqKiByZXByZXNlbnRzIGEgY29udHJhc3QgYmV0d2VlbiAqKkFnZS9FeGVyY2lzZSBGcmVxdWVuY3kqKiBhbmQgKipTdHJlc3MqKiwgd2hpbGUgKipQQzIqKiBpcyBsYXJnZWx5IGRlZmluZWQgYnkgKipTbGVlcCoqIGFuZCAqKkRpZXQqKi4gQWx0aG91Z2ggdGhlICoqRWxib3cgUnVsZSoqIGNvdWxkIGp1c3RpZnkgcmV0YWluaW5nIG1vcmUgY29tcG9uZW50cywgdXNpbmcganVzdCBQQzEgYW5kIFBDMiBwcm92aWRlcyBhIHNpbXBsaWZpZWQgbW9kZWwgd2l0aCBjbGVhciBpbnRlcnByZXRhYmlsaXR5LgoKIyMgSGllcmFyY2hpY2FsIENsdXN0ZXJpbmcgKEhBQykKCldlIHBlcmZvcm0gSGllcmFyY2hpY2FsIENsdXN0ZXJpbmcgdXNpbmcgV2FyZCdzIG1ldGhvZCB0byBpZGVudGlmeSBkaXN0aW5jdCBsaWZlc3R5bGUgZ3JvdXBzIHdpdGhpbiB0aGUgZGF0YS4KCmBgYHtyIGNsdXN0ZXJpbmctaGllcmFyY2hpY2FsLCBmaWcuY2FwPSJEZW5kcm9ncmFtIGFuZCBDbHVzdGVyIFN1bW1hcnkifQojIDEuIENhbGN1bGF0ZSBkaXNzaW1pbGFyaXR5IG1hdHJpeApkX3NjYWxlZCA8LSBkaXN0KGRmX3NjYWxlZCwgbWV0aG9kID0gImV1Y2xpZGVhbiIpCgojIDIuIFBlcmZvcm0gSGllcmFyY2hpY2FsIENsdXN0ZXJpbmcKaGNfZml0IDwtIGhjbHVzdChkX3NjYWxlZCwgbWV0aG9kID0gIndhcmQuRDIiKQoKIyAzLiBWaXN1YWxpemUgRGVuZHJvZ3JhbQpwbG90KGhjX2ZpdCwgbGFiZWxzID0gRkFMU0UsIGhhbmcgPSAtMSwgY2V4ID0gMC41LAogICAgIG1haW4gPSAiSGllcmFyY2hpY2FsIENsdXN0ZXJpbmcgRGVuZHJvZ3JhbSIpCgojIDQuIEN1dCB0cmVlIGludG8gaz0zIGNsdXN0ZXJzIGFuZCBhc3NpZ24KayA8LSAzCmNsdXN0ZXJzX2hhYyA8LSBjdXRyZWUoaGNfZml0LCBrID0gaykKZGZfYW5hbHlzaXMkSEFDX0NsdXN0ZXIgPC0gYXMuZmFjdG9yKGNsdXN0ZXJzX2hhYykKCiMgNS4gQ2hhcmFjdGVyaXplIENsdXN0ZXJzCmNsdXN0ZXJfc3VtbWFyeSA8LSBhZ2dyZWdhdGUoLiB+IEhBQ19DbHVzdGVyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBkZl9hbmFseXNpc1ssIGMobmFtZXMoZGZfcHJlZGljdG9ycyksICJIQUNfQ2x1c3RlciIpXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGVU4gPSBtZWFuKQprYWJsZShjbHVzdGVyX3N1bW1hcnksIGNhcHRpb24gPSAiTWVhbiBWYWx1ZXMgb2YgU2NhbGVkIFZhcmlhYmxlcyBieSBDbHVzdGVyIikKYGBgCgoqKkNsdXN0ZXIgQXJjaGV0eXBlczoqKgoKICAqICoqQ2x1c3RlciAxOioqIEhpZ2ggZXhlcmNpc2UsIGxvdyBhZ2UsIG1vZGVyYXRlIHN0cmVzcyAoIkFjdGl2ZSAmIEJ1c3kiKS4KICAqICoqQ2x1c3RlciAyOioqIEhpZ2ggc2NyZWVuIHRpbWUsIGhpZ2ggc3RyZXNzLCBsb3cgc2xlZXAgKCJIaWdoIFJpc2siKS4KICAqICoqQ2x1c3RlciAzOioqIExvdyBzY3JlZW4gdGltZSwgbG93IHN0cmVzcywgaGlnaCBzbGVlcCAoIlJlbGF4ZWQiKS4KCioqQW5hbHlzaXM6KiogSGllcmFyY2hpY2FsIENsdXN0ZXJpbmcgZWZmZWN0aXZlbHkgc2VnbWVudGVkIHRoZSBkYXRhc2V0IGludG8gdGhyZWUgZGlzdGluY3QgYXJjaGV0eXBlcyBiYXNlZCBvbiBsaWZlc3R5bGUgZmFjdG9ycy4gKipDbHVzdGVyIDIqKiBzdGFuZHMgb3V0IGFzIHRoZSBoaWdoZXN0LXJpc2sgZ3JvdXAsIGRlZmluZWQgYnkgdGhlIGNvbWJpbmF0aW9uIG9mIGhpZ2ggc3RyZXNzLCBoaWdoIHNjcmVlbiB0aW1lLCBhbmQgbG93IHNsZWVwIHF1YWxpdHkuIENvbnZlcnNlbHksICoqQ2x1c3RlciAzKiogcmVwcmVzZW50cyB0aGUgbW9zdCByZWxheGVkIGFuZCB3ZWxsLXJlc3RlZCBncm91cCwgY29udHJhc3Rpbmcgc2hhcnBseSB3aXRoIHRoZSAiQWN0aXZlICYgQnVzeSIgcGF0dGVybiBvZiAqKkNsdXN0ZXIgMSoqLgoKLS0tLS0KCiMgUGFydCBJSTogTG9jYWwgT3V0bGllciBGYWN0b3IgKExPRikKCkluIHRoaXMgc2VjdGlvbiwgd2UgaW1wbGVtZW50IHRoZSAqKkxvY2FsIE91dGxpZXIgRmFjdG9yIChMT0YpKiogdG8gaWRlbnRpZnkgYW5vbWFsaWVzIGJhc2VkIG9uIGxvY2FsIGRlbnNpdHkuCgojIyBMT0YgQ2FsY3VsYXRpb24gYW5kIFZpc3VhbGl6YXRpb24KCldlIGNhbGN1bGF0ZSBMT0Ygc2NvcmVzIHVzaW5nICRrPTIwJCBuZWFyZXN0IG5laWdoYm9ycy4gQSBzY29yZSBcPiAxIGltcGxpZXMgdGhlIHBvaW50IGlzIGluIGEgc3BhcnNlIHJlZ2lvbiByZWxhdGl2ZSB0byBpdHMgbmVpZ2hib3JzLgoKYGBge3IgbG9mLWNhbGN1bGF0aW9uLCBmaWcuY2FwPSJEaXN0cmlidXRpb24gb2YgTE9GIFNjb3JlcyJ9CiMgQ2FsY3VsYXRlIExPRiBzY29yZXMgKHVzaW5nIHNjYWxlZCBkYXRhIGZyb20gUGFydCBJKQprX3ZhbHVlIDwtIDIwCmxvZl9zY29yZXMgPC0gbG9mKGRmX3NjYWxlZCwgbWluUHRzID0ga192YWx1ZSkKCiMgQWRkIHNjb3JlcyB0byBkYXRhZnJhbWUKZGZfYW5hbHlzaXMkTE9GX1Njb3JlIDwtIGxvZl9zY29yZXMKCiMgVmlzdWFsaXppbmcgTE9GIERpc3RyaWJ1dGlvbgp0aHJlc2hvbGQgPC0gMS4yNQpwYXIobWZyb3cgPSBjKDEsIDIpKQoKIyBIaXN0b2dyYW0KaGlzdChkZl9hbmFseXNpcyRMT0ZfU2NvcmUsIGJyZWFrcyA9IDMwLCBtYWluID0gIkxPRiBTY29yZSBIaXN0b2dyYW0iLCAKICAgICB4bGFiID0gIkxPRiBTY29yZSIsIGNvbCA9ICJsaWdodGJsdWUiLCBib3JkZXIgPSAid2hpdGUiKQphYmxpbmUodiA9IHRocmVzaG9sZCwgY29sID0gInJlZCIsIGx3ZCA9IDIsIGx0eSA9IDIpCgojIFNjYXR0ZXIgUGxvdCB2cyBIYXBwaW5lc3MKcGxvdChkZl9hbmFseXNpcyRIYXBwaW5lc3NJbmRleCwgZGZfYW5hbHlzaXMkTE9GX1Njb3JlLAogICAgIG1haW4gPSAiTE9GIHZzLiBIYXBwaW5lc3MgSW5kZXgiLCB4bGFiID0gIkhhcHBpbmVzcyBJbmRleCIsIHlsYWIgPSAiTE9GIFNjb3JlIiwKICAgICBwY2ggPSAxOSwgY29sID0gaWZlbHNlKGRmX2FuYWx5c2lzJExPRl9TY29yZSA+IHRocmVzaG9sZCwgInJlZCIsICJkYXJrYmx1ZSIpKQpsZWdlbmQoInRvcHJpZ2h0IiwgbGVnZW5kID0gYygiT3V0bGllciAoPjEuMjUpIiwgIk5vcm1hbCIpLCAKICAgICAgIGNvbCA9IGMoInJlZCIsICJkYXJrYmx1ZSIpLCBwY2ggPSAxOSwgY2V4ID0gMC44KQoKcGFyKG1mcm93ID0gYygxLCAxKSkKYGBgCgoqKkFuYWx5c2lzOioqIFRoZSBkaXN0cmlidXRpb24gaXMgY2VudGVyZWQgbmVhciAxLjAuIFdlIGlkZW50aWZ5IHBvaW50cyB3aXRoIHNjb3JlcyBcPiAxLjI1IGFzIGxvY2FsIG91dGxpZXJzLiBUaGVzZSByZXByZXNlbnQgaW5kaXZpZHVhbHMgd2l0aCB1bmlxdWUgYmVoYXZpb3JhbCBwcm9maWxlcyBjb21wYXJlZCB0byB0aGVpciBwZWVycy4KCi0tLS0tCgojIFBhcnQgSUlJOiBNb2RlbC1CYXNlZCBGZWF0dXJlIEVuZ2luZWVyaW5nIChQQ0kpCgpJbiB0aGlzIGZpbmFsIHNlY3Rpb24sIHdlIGltcGxlbWVudCBhIG5vdmVsIGZlYXR1cmUgZXh0cmFjdGlvbiBtZXRob2QgYmFzZWQgb24gdGhlICoqUHJvY2VzcyBDYXBhYmlsaXR5IEluZGV4IChQQ0kpKiouIFRoaXMgbWV0aG9kLCB0eXBpY2FsbHkgdXNlZCBpbiBtYW51ZmFjdHVyaW5nIHF1YWxpdHkgY29udHJvbCwgYXNzZXNzZXMgaG93IHdlbGwgYSBwcm9jZXNzIGZpdHMgd2l0aGluIHNwZWNpZmljYXRpb24gbGltaXRzLgoKSGVyZSwgd2UgdHJlYXQgdGhlICJwcm9jZXNzIiBhcyB0aGUgYmVoYXZpb3JhbCBwcm9maWxlIG9mIGFuIGluZGl2aWR1YWwgYWNyb3NzIG11bHRpcGxlIG1ldHJpY3MuIFdlIHdpbGwgY2FsY3VsYXRlIHRoZSAkQ197cGt9JCBpbmRleCBmb3IgZWFjaCBvYnNlcnZhdGlvbiB0byBjcmVhdGUgYSBzaW5nbGUgImNhcGFiaWxpdHkiIGZlYXR1cmUuCgojIyBNZXRob2RvbG9neQoKV2UgZGVmaW5lIHRoZSAkQ197cGt9JCBpbmRleCBhczoKJCQgQ197cGt9ID0gXG1pbiBcbGVmdCggXGZyYWN7VVNMIC0gXG11fXszXHNpZ21hfSwgXGZyYWN7XG11IC0gTFNMfXszXHNpZ21hfSBccmlnaHQpICQkCgpGb3IgdGhpcyBhcHBsaWNhdGlvbiwgd2UgbXVzdCBkZWZpbmUgIlNwZWNpZmljYXRpb24gTGltaXRzIiAoJFVTTCwgTFNMJCkgYW5kIHByb2Nlc3MgcGFyYW1ldGVycyAoJFxtdSwgXHNpZ21hJCk6CgoxLiAgKipQcm9jZXNzIERlZmluaXRpb246KiogV2UgdHJlYXQgYFNsZWVwUXVhbGl0eWAgYXMgdGhlIGtleSBwcm9jZXNzIGNoYXJhY3RlcmlzdGljIHdlIHdhbnQgdG8gbW9uaXRvci4KMi4gICoqU3BlY2lmaWNhdGlvbiBMaW1pdHM6KiogV2Ugc2V0IHRoZSBVcHBlciBTcGVjaWZpY2F0aW9uIExpbWl0ICgkVVNMID0gMTAkKSBhbmQgTG93ZXIgU3BlY2lmaWNhdGlvbiBMaW1pdCAoJExTTCA9IDQkKSBiYXNlZCBvbiBkb21haW4ga25vd2xlZGdlIChzY2FsZSAxLTEwKS4KMy4gICoqUHJvY2VzcyBQYXJhbWV0ZXJzOioqIEZvciBlYWNoIGluZGl2aWR1YWwgb2JzZXJ2YXRpb24sIHdlIGVzdGltYXRlICRcbXUkIGFuZCAkXHNpZ21hJCB1c2luZyBhICJ3aW5kb3ciIG9mIHJlbGF0ZWQgdmFyaWFibGVzLiBXZSB3aWxsIHVzZSBgU2xlZXBRdWFsaXR5YCwgYEhhcHBpbmVzc0luZGV4YCwgYW5kIGFuIGludmVyc2Utc2NhbGVkIGBTdHJlc3NMZXZlbGAgYXMgYSBwcm94eSBmb3IgYSBzbWFsbCB0aW1lLXNlcmllcy9wcm9jZXNzIHdpbmRvdyBmb3IgdGhhdCBwZXJzb24uCgojIyBJbXBsZW1lbnRhdGlvbgoKYGBge3IgcGNpLWNhbGN1bGF0aW9ufQojIDEuIERlZmluZSBTcGVjaWZpY2F0aW9uIExpbWl0cyBmb3IgdGhlICJIZWFsdGggUHJvY2VzcyIKVVNMIDwtIDEwCkxTTCA8LSA0CgojIDIuIFByZXBhcmUgRGF0YSBmb3IgIldpbmRvdyIgQ2FsY3VsYXRpb24KIyBXZSB3aWxsIHVzZSBTbGVlcCwgSGFwcGluZXNzLCBhbmQgKDEwIC0gU3RyZXNzKSBhcyB0aHJlZSAib2JzZXJ2YXRpb25zIiBvZiB3ZWxsLWJlaW5nLgpkZl9wY2lfcHJlcCA8LSBkYXRhLmZyYW1lKAogIE9iczEgPSBkZl9hbmFseXNpcyRTbGVlcFF1YWxpdHksCiAgT2JzMiA9IGRmX2FuYWx5c2lzJEhhcHBpbmVzc0luZGV4LAogIE9iczMgPSAxMCAtIGRmX2FuYWx5c2lzJFN0cmVzc0xldmVsICMgSW52ZXJ0IHN0cmVzcyBzbyBoaWdoZXIgaXMgYmV0dGVyCikKCiMgMy4gQ2FsY3VsYXRlIFJvdy13aXNlIFN0YXRpc3RpY3MgKFByb2Nlc3MgTWVhbiBhbmQgU2lnbWEpCiMgQXBwbHkgbWVhbiBhbmQgc2QgYWNyb3NzIHRoZSByb3dzCnByb2Nlc3NfbXUgPC0gYXBwbHkoZGZfcGNpX3ByZXAsIDEsIG1lYW4pCnByb2Nlc3Nfc2lnbWEgPC0gYXBwbHkoZGZfcGNpX3ByZXAsIDEsIHNkKQoKIyBIYW5kbGUgY2FzZXMgd2hlcmUgc2lnbWEgbWlnaHQgYmUgMCAoaWYgYWxsIHZhbHVlcyBhcmUgaWRlbnRpY2FsKQpwcm9jZXNzX3NpZ21hW3Byb2Nlc3Nfc2lnbWEgPT0gMF0gPC0gMC4wMDEgCgojIDQuIENhbGN1bGF0ZSBDcGsgKFByb2Nlc3MgQ2FwYWJpbGl0eSBJbmRleCkKIyBDcHUgPSAoVVNMIC0gTWVhbikgLyAoMyAqIFNpZ21hKQpDcHUgPC0gKFVTTCAtIHByb2Nlc3NfbXUpIC8gKDMgKiBwcm9jZXNzX3NpZ21hKQoKIyBDcGwgPSAoTWVhbiAtIExTTCkgLyAoMyAqIFNpZ21hKQpDcGwgPC0gKHByb2Nlc3NfbXUgLSBMU0wpIC8gKDMgKiBwcm9jZXNzX3NpZ21hKQoKIyBDcGsgaXMgdGhlIG1pbmltdW0gb2YgQ3B1IGFuZCBDcGwKQ3BrIDwtIHBtaW4oQ3B1LCBDcGwpCgojIEFkZCBDcGsgdG8gdGhlIG1haW4gZGF0YWZyYW1lCmRmX2FuYWx5c2lzJFBDSV9TY29yZSA8LSBDcGsKCiMgU3VtbWFyeSBvZiB0aGUgbmV3IFBDSSBmZWF0dXJlCnByaW50KHN1bW1hcnkoZGZfYW5hbHlzaXMkUENJX1Njb3JlKSkKYGBgCgojIyBWaXN1YWxpemluZyBQQ0kKCldlIGV4YW1pbmUgaG93IHRoaXMgZW5naW5lZXJpbmcgcXVhbGl0eSBtZXRyaWMgcmVsYXRlcyB0byBvdXIgdGFyZ2V0IHZhcmlhYmxlLgoKYGBge3IgcGNpLXZpc3VhbGl6YXRpb24sIGZpZy5jYXA9IlBDSSBTY29yZSBieSBIYXBwaW5lc3MgTGV2ZWwifQpib3hwbG90KFBDSV9TY29yZSB+IEhpZ2hIYXBwaW5lc3MsIGRhdGEgPSBkZl9hbmFseXNpcywKICAgICAgICBtYWluID0gIlByb2Nlc3MgQ2FwYWJpbGl0eSBJbmRleCAoQ3BrKSBieSBIYXBwaW5lc3MgU3RhdHVzIiwKICAgICAgICB4bGFiID0gIkhhcHBpbmVzcyBTdGF0dXMiLCB5bGFiID0gIlBDSSBTY29yZSAoQ3BrKSIsCiAgICAgICAgY29sID0gYygidG9tYXRvIiwgImxpZ2h0Z3JlZW4iKSkKYGBgCgoqKk9ic2VydmF0aW9uOioqIFRoZSBib3hwbG90IHN1Z2dlc3RzIGEgc3Ryb25nIHJlbGF0aW9uc2hpcC4gVGhlICJIaWdoIiBoYXBwaW5lc3MgZ3JvdXAgdGVuZHMgdG8gaGF2ZSBzaWduaWZpY2FudGx5IGhpZ2hlciAkQ197cGt9JCBzY29yZXMuIFRoaXMgbWFrZXMgaW50dWl0aXZlIHNlbnNlOiBhIGhpZ2hlciAkQ197cGt9JCBpbmRpY2F0ZXMgYSAicHJvY2VzcyIgKGluZGl2aWR1YWwgd2VsbC1iZWluZykgdGhhdCBpcyBjb25zaXN0ZW50bHkgd2l0aGluIGhlYWx0aHkgc3BlY2lmaWNhdGlvbiBsaW1pdHMgKGNlbnRlcmVkIGJldHdlZW4gNCBhbmQgMTAgd2l0aCBsb3cgdmFyaWFuY2UpLgoKLS0tLS0KCiMgRmluYWwgTW9kZWwgQ29tcGFyaXNvbgoKV2Ugbm93IGV2YWx1YXRlIHRoZSBwcmVkaWN0aXZlIHBvd2VyIG9mIG91ciBleHRyYWN0ZWQgZmVhdHVyZXMuIFdlIGNvbXBhcmUgYSAqKkJhc2VsaW5lIE1vZGVsKiogYWdhaW5zdCBtb2RlbHMgZW5oYW5jZWQgd2l0aCAqKlBDQSoqLCAqKkxPRioqLCBhbmQgKipQQ0kqKiBmZWF0dXJlcy4KCmBgYHtyIG1vZGVsLWNvbXBhcmlzb259CiMgU3BsaXQgZGF0YSBpbnRvIFRyYWluaW5nICg3MCUpIGFuZCBUZXN0aW5nICgzMCUpCnNldC5zZWVkKDEyMykKdHJhaW5JbmRleCA8LSBjcmVhdGVEYXRhUGFydGl0aW9uKGRmX2FuYWx5c2lzJEhpZ2hIYXBwaW5lc3MsIHAgPSAwLjcsIGxpc3QgPSBGQUxTRSkKdHJhaW5fZGF0YSA8LSBkZl9hbmFseXNpc1t0cmFpbkluZGV4LCBdCnRlc3RfZGF0YSA8LSBkZl9hbmFseXNpc1stdHJhaW5JbmRleCwgXQoKIyAxLiBCYXNlbGluZSBNb2RlbCAoT3JpZ2luYWwgUHJlZGljdG9ycykKbW9kZWxfYmFzZSA8LSBnbG0oSGlnaEhhcHBpbmVzcyB+IEFnZSArIFNjcmVlblRpbWUgKyBTbGVlcFF1YWxpdHkgKyAKICAgICAgICAgICAgICAgICAgU3RyZXNzTGV2ZWwgKyBEYXlzTm9TTSArIEV4ZXJjaXNlRnJlcSwKICAgICAgICAgICAgICAgICAgZGF0YSA9IHRyYWluX2RhdGEsIGZhbWlseSA9ICJiaW5vbWlhbCIpCgojIDIuIFBDQSBFbmhhbmNlZCBNb2RlbCAoQWRkaW5nIFBDMSwgUEMyLCBQQzMpCm1vZGVsX3BjYSA8LSBnbG0oSGlnaEhhcHBpbmVzcyB+IEFnZSArIFNjcmVlblRpbWUgKyBTbGVlcFF1YWxpdHkgKyAKICAgICAgICAgICAgICAgICBTdHJlc3NMZXZlbCArIERheXNOb1NNICsgRXhlcmNpc2VGcmVxICsgUEMxICsgUEMyICsgUEMzLAogICAgICAgICAgICAgICAgIGRhdGEgPSB0cmFpbl9kYXRhLCBmYW1pbHkgPSAiYmlub21pYWwiKQoKIyAzLiBMT0YgRW5oYW5jZWQgTW9kZWwgKEFkZGluZyBMT0YgU2NvcmUpCm1vZGVsX2xvZiA8LSBnbG0oSGlnaEhhcHBpbmVzcyB+IEFnZSArIFNjcmVlblRpbWUgKyBTbGVlcFF1YWxpdHkgKyAKICAgICAgICAgICAgICAgICBTdHJlc3NMZXZlbCArIERheXNOb1NNICsgRXhlcmNpc2VGcmVxICsgTE9GX1Njb3JlLAogICAgICAgICAgICAgICAgIGRhdGEgPSB0cmFpbl9kYXRhLCBmYW1pbHkgPSAiYmlub21pYWwiKQoKIyA0LiBQQ0kgRW5oYW5jZWQgTW9kZWwgKEFkZGluZyBQQ0kgU2NvcmUpCm1vZGVsX3BjaSA8LSBnbG0oSGlnaEhhcHBpbmVzcyB+IEFnZSArIFNjcmVlblRpbWUgKyBTbGVlcFF1YWxpdHkgKyAKICAgICAgICAgICAgICAgICBTdHJlc3NMZXZlbCArIERheXNOb1NNICsgRXhlcmNpc2VGcmVxICsgUENJX1Njb3JlLAogICAgICAgICAgICAgICAgIGRhdGEgPSB0cmFpbl9kYXRhLCBmYW1pbHkgPSAiYmlub21pYWwiKQoKIyBHZW5lcmF0ZSBQcmVkaWN0aW9ucwpwcm9iX2Jhc2UgPC0gcHJlZGljdChtb2RlbF9iYXNlLCBuZXdkYXRhID0gdGVzdF9kYXRhLCB0eXBlID0gInJlc3BvbnNlIikKcHJvYl9wY2EgPC0gcHJlZGljdChtb2RlbF9wY2EsIG5ld2RhdGEgPSB0ZXN0X2RhdGEsIHR5cGUgPSAicmVzcG9uc2UiKQpwcm9iX2xvZiA8LSBwcmVkaWN0KG1vZGVsX2xvZiwgbmV3ZGF0YSA9IHRlc3RfZGF0YSwgdHlwZSA9ICJyZXNwb25zZSIpCnByb2JfcGNpIDwtIHByZWRpY3QobW9kZWxfcGNpLCBuZXdkYXRhID0gdGVzdF9kYXRhLCB0eXBlID0gInJlc3BvbnNlIikKCiMgQ2FsY3VsYXRlIEFVQ3MKYXVjX2Jhc2UgPC0gYXVjKHJvYyh0ZXN0X2RhdGEkSGlnaEhhcHBpbmVzcywgcHJvYl9iYXNlLCBxdWlldD1UUlVFKSkKYXVjX3BjYSAgPC0gYXVjKHJvYyh0ZXN0X2RhdGEkSGlnaEhhcHBpbmVzcywgcHJvYl9wY2EsIHF1aWV0PVRSVUUpKQphdWNfbG9mICA8LSBhdWMocm9jKHRlc3RfZGF0YSRIaWdoSGFwcGluZXNzLCBwcm9iX2xvZiwgcXVpZXQ9VFJVRSkpCmF1Y19wY2kgIDwtIGF1Yyhyb2ModGVzdF9kYXRhJEhpZ2hIYXBwaW5lc3MsIHByb2JfcGNpLCBxdWlldD1UUlVFKSkKCiMgQ3JlYXRlIENvbXBhcmlzb24gVGFibGUKcmVzdWx0cyA8LSBkYXRhLmZyYW1lKAogIE1vZGVsID0gYygiQmFzZWxpbmUiLCAiUENBIEVuaGFuY2VkIiwgIkxPRiBFbmhhbmNlZCIsICJQQ0kgRW5oYW5jZWQiKSwKICBBVUMgPSBjKGF1Y19iYXNlLCBhdWNfcGNhLCBhdWNfbG9mLCBhdWNfcGNpKQopCgprYWJsZShyZXN1bHRzLCBjYXB0aW9uID0gIkZpbmFsIE1vZGVsIFBlcmZvcm1hbmNlIENvbXBhcmlzb24gKEFVQykiLCBkaWdpdHMgPSA0KQpgYGAKCioqQW5hbHlzaXM6KiogVGhlIGRhdGEgaXMgY29tcGxleCwgYXMgc2hvd24gYnkgdGhlIGNsZWFyIGNsdXN0ZXJzIChIQUMpIGFuZCBzaWduaWZpY2FudCB2YXJpYW5jZSBpbiB0aGUgZmlyc3QgdHdvIFByaW5jaXBhbCBDb21wb25lbnRzIChQQ0EpLiBIb3dldmVyLCBpbmNvcnBvcmF0aW5nIGZlYXR1cmVzIGV4dHJhY3RlZCBmcm9tIFBDQSBkaWQgbm90IGltcHJvdmUgdGhlIHByZWRpY3RpdmUgcG93ZXIgb2YgdGhlIG1vZGVsIGNvbXBhcmVkIHRvIHRoZSBiYXNlbGluZSwgd2hpY2ggYWxyZWFkeSBwZXJmb3JtcyB3ZWxsIHdpdGggYW4gQVVDIG9mIDAuOTA1MC4gVGhlIGNsdXN0ZXJpbmcgcmVzdWx0cyBjb3VsZCBiZSB1c2VkIGZvciB0YXJnZXRlZCBpbnRlcnZlbnRpb25zLCBwYXJ0aWN1bGFybHkgZm9yIHRoZSAiSGlnaCBSaXNrIiBDbHVzdGVyIDIuCgojIENvbmNsdXNpb24KClRoaXMgcHJvamVjdCBzdWNjZXNzZnVsbHkgaW1wbGVtZW50ZWQgdGhyZWUgdHlwZXMgb2YgZmVhdHVyZSBleHRyYWN0aW9uOgoKMS4gICoqUENBIChVbnN1cGVydmlzZWQgR2VvbWV0cmljKToqKiBQcm92aWRlZCBvcnRob2dvbmFsIGNvbXBvbmVudHMgc3VtbWFyaXppbmcgdmFyaWFuY2UuIFRoZSBBVUMgY29tcGFyaXNvbiBzaG93cyB3aGV0aGVyIGRpbWVuc2lvbmFsaXR5IHJlZHVjdGlvbiBwcmVzZXJ2ZWQgcHJlZGljdGl2ZSBwb3dlci4KMi4gICoqTE9GIChVbnN1cGVydmlzZWQgRGVuc2l0eSk6KiogSWRlbnRpZmllZCBvdXRsaWVycy4gV2hpbGUgdXNlZnVsIGZvciBhbm9tYWx5IGRldGVjdGlvbiwgdGhlICJvdXRsaWVybmVzcyIgb2YgYSBiZWhhdmlvciBwcm9maWxlIG1heSBvciBtYXkgbm90IGJlIHN0cm9uZ2x5IGNvcnJlbGF0ZWQgd2l0aCB0aGUgc3BlY2lmaWMgdGFyZ2V0IG9mIEhhcHBpbmVzcyBpbiB0aGlzIGRhdGFzZXQuCjMuICAqKlBDSSAoTW9kZWwtQmFzZWQgU3RhdGlzdGljYWwpOioqIFdlIHRyZWF0ZWQgbWVudGFsIHdlbGwtYmVpbmcgYXMgYSBtYW51ZmFjdHVyaW5nIHByb2Nlc3MuIEJ5IGNhbGN1bGF0aW5nIHRoZSBQcm9jZXNzIENhcGFiaWxpdHkgSW5kZXggKCRDX3twa30kKSBiYXNlZCBvbiBzcGVjaWZpYyBsaW1pdHMgKCRMU0w9NCwgVVNMPTEwJCksIHdlIGVuZ2luZWVyZWQgYSBmZWF0dXJlIHRoYXQgY2FwdHVyZXMgYm90aCB0aGUgKmxldmVsKiBhbmQgKmNvbnNpc3RlbmN5KiBvZiBoZWFsdGggbWV0cmljcy4KClRoZSBmaW5hbCBjb21wYXJpc29uIGhpZ2hsaWdodHMgdGhlIGVmZmVjdGl2ZW5lc3Mgb2YgKipNb2RlbC1CYXNlZCBGZWF0dXJlIEV4dHJhY3Rpb24qKi4gQnkgaW5jb3Jwb3JhdGluZyBkb21haW4ga25vd2xlZGdlIGludG8gdGhlIGZlYXR1cmUgZW5naW5lZXJpbmcgcHJvY2VzcyB2aWEgUENJLCB3ZSBnZW5lcmF0ZWQgYSBtZXRyaWMgd2l0aCBzdHJvbmcgZGlzY3JpbWluYXRvcnkgcG93ZXIgZm9yIGNsYXNzaWZ5aW5nIGhhcHBpbmVzcy4K