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:
- Part I: Dimensionality Reduction & Clustering.
We implement Principal Component Analysis (PCA) to
address multicollinearity and Hierarchical Clustering
to identify lifestyle archetypes.
- Part II: Anomaly Detection. We utilize the
Local Outlier Factor (LOF) algorithm to identify local
density-based outliers and assess if “outlierness” predicts
happiness.
- 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.
Data Preparation
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
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)
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.
Part I: PCA and
Clustering
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)
# 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.
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")
# 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
| 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.
Part II: Local Outlier
Factor (LOF)
In this section, we implement the Local Outlier Factor
(LOF) to identify anomalies based on local density.
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)
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.
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.
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\)):
- Process Definition: We treat
SleepQuality as the key process characteristic we want to
monitor.
- Specification Limits: We set the Upper
Specification Limit (\(USL = 10\)) and
Lower Specification Limit (\(LSL = 4\))
based on domain knowledge (scale 1-10).
- 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.
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
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"))
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).
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)
| 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.
Conclusion
This project successfully implemented three types of feature
extraction:
- PCA (Unsupervised Geometric): Provided orthogonal
components summarizing variance. The AUC comparison shows whether
dimensionality reduction preserved predictive power.
- 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.
- 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