This is an R Markdown
Notebook. When you execute code within the notebook, the results appear
beneath the code.
Try executing this chunk by clicking the Run button within
the chunk or by placing your cursor inside it and pressing
Cmd+Shift+Enter.
Load the Obesity Dataset
Project Overview: Predicting Weight Based on Lifestyle Factors
For our project, we chose the Obesity Levels dataset from the UCI
Machine Learning Repository. This dataset combines real and synthetic
data, capturing details about people’s eating habits, physical activity,
and biological traits (like age, gender, and height). Our main goal is
to predict weight—a continuous variable—using these different lifestyle
and health factors.
Data Preparation & Initial Insights
Before diving into modeling, we cleaned and prepared the data by:
Converting text-based (categorical) variables into numerical factors
for analysis. Ensuring no missing values were present that could skew
results. Splitting the data into an 80% training set (to build models)
and a 20% testing set (to evaluate their performance fairly).
Key observations from early exploration:
Variables include age, height, dietary patterns (e.g., frequent
high-calorie food consumption), and activity levels (exercise frequency,
screen time). Weight is our target, analyzed as a continuous value—ideal
for regression techniques. The dataset was already quite clean,
requiring minimal adjustments before modeling.
# Load necessary libraries
library(tidyverse)
library(rpart)
library(rpart.plot)
library(caret)
library(knitr) # for neat tables
# Read the dataset
obesity_data <- read.csv("~/Desktop/ObesityDataSet_raw_and_data_sinthetic.csv")
# View first few rows
head(obesity_data)
# Calculate BMI
obesity_data$BMI <- obesity_data$Weight / (obesity_data$Height^2)
# Remove NObeyesdad (target leakage)
obesity_data <- obesity_data %>% select(-NObeyesdad)
Data Preprocessing
# Check variable types
str(obesity_data)
'data.frame': 2111 obs. of 17 variables:
$ Gender : chr "Female" "Female" "Male" "Male" ...
$ Age : num 21 21 23 27 22 29 23 22 24 22 ...
$ Height : num 1.62 1.52 1.8 1.8 1.78 1.62 1.5 1.64 1.78 1.72 ...
$ Weight : num 64 56 77 87 89.8 53 55 53 64 68 ...
$ family_history_with_overweight: chr "yes" "yes" "yes" "no" ...
$ FAVC : chr "no" "no" "no" "no" ...
$ FCVC : num 2 3 2 3 2 2 3 2 3 2 ...
$ NCP : num 3 3 3 3 1 3 3 3 3 3 ...
$ CAEC : chr "Sometimes" "Sometimes" "Sometimes" "Sometimes" ...
$ SMOKE : chr "no" "yes" "no" "no" ...
$ CH2O : num 2 3 2 2 2 2 2 2 2 2 ...
$ SCC : chr "no" "yes" "no" "no" ...
$ FAF : num 0 3 2 2 0 0 1 3 1 1 ...
$ TUE : num 1 0 1 0 0 0 0 0 1 1 ...
$ CALC : chr "no" "Sometimes" "Frequently" "Frequently" ...
$ MTRANS : chr "Public_Transportation" "Public_Transportation" "Public_Transportation" "Walking" ...
$ BMI : num 24.4 24.2 23.8 26.9 28.3 ...
# Convert character variables to factors
obesity_data <- obesity_data %>%
mutate(across(where(is.character), as.factor))
# Remove any missing values
obesity_data <- na.omit(obesity_data)
# Split the data into training and testing sets (80/20 split)
set.seed(123)
train_index <- createDataPartition(obesity_data$BMI, p = 0.8, list = FALSE)
train_data <- obesity_data[train_index, ]
test_data <- obesity_data[-train_index, ]
First, we checked the structure of our dataset (obesity_data) to see
what types of variables we were working with—like numbers, categories,
or text.
Since some columns were stored as text (characters), we converted
them into factors—a format R understands better for statistical
modeling. This helps the models recognize categories (like “Male” or
“Female”) properly.
Next, we made sure our data was clean and complete by removing any
rows with missing values. This avoids errors or biased results later
on.
Finally, we split the data into two parts:
Training set (80%): Used to build and train our models. Testing set
(20%): Reserved to check how well the models perform on unseen data. We
set a random seed (set.seed(123)) to ensure this split is
reproducible—meaning anyone running the code gets the same
training/testing groups for fair comparisons.
Build a Shallow Decision Tree
# Train a shallow decision tree to predict BMI
tree_model <- rpart(BMI ~ .,
data = train_data,
method = "anova",
control = rpart.control(maxdepth = 3, cp = 0.01))
# Plot the decision tree
rpart.plot(tree_model,
type = 4,
extra = 101,
fallen.leaves = TRUE,
box.palette = "Blues",
shadow.col = "gray")

We started by training a basic Decision Tree model to predict Body
Mass Index (BMI) using all other available variables in the dataset
(excluding NObeyesdad, which was removed to prevent target leakage).
To keep the model intentionally simple and interpretable, we
restricted its complexity in two ways:
We limited the maximum depth to 3 levels to avoid overfitting and
unnecessary complexity. We set a relatively high complexity parameter
(cp = 0.01) to encourage pruning of less informative splits. Since BMI
is a continuous variable, we used the ‘anova’ method in the rpart()
function to indicate regression rather than classification.
For visualization, we created a clean and informative tree plot that
shows:
The hierarchical decision points (splits) based on the most
influential predictors The predicted BMI values at each terminal node
(leaf) A color gradient (using a blue palette) to visually indicate
different prediction ranges Subtle shadows to improve readability and
distinguish branches
This restrained approach gives us a model that is:
Easy to interpret and explain to non-technical stakeholders Quick to
train and computationally efficient Provides a solid baseline for
comparison with more complex models such as XGBoost The tree
visualization acts as both a diagnostic tool (to assess if splits make
logical sense) and a communication tool (to help explain how input
factors influence BMI outcomes).
Evaluate the Model
# Predict on training and test data
train_pred <- predict(tree_model, newdata = train_data)
test_pred <- predict(tree_model, newdata = test_data)
# Calculate RMSE (Root Mean Squared Error)
train_rmse <- sqrt(mean((train_pred - train_data$BMI)^2))
test_rmse <- sqrt(mean((test_pred - test_data$BMI)^2))
# Print RMSE neatly
cat("Training RMSE:", round(train_rmse, 2), "\n")
Training RMSE: 2.51
cat("Testing RMSE:", round(test_rmse, 2), "\n")
Testing RMSE: 2.65
We used our decision tree to predict BMI in two scenarios:
For individuals in the training set (data the model had already seen)
For individuals in the testing set (new, unseen data)
To evaluate how accurate the model’s predictions were, we calculated
the Root Mean Squared Error (RMSE). RMSE gives us one number that
summarizes the typical prediction error — smaller values indicate more
accurate predictions.
The steps were as follows:
First, we generated predictions for both the training and testing
sets.
Then, we calculated RMSE by:
- Taking the difference between the predicted and actual BMI
values
- Squaring those differences
- Averaging them
- Taking the square root of that average
Finally, we printed the Training RMSE and Testing RMSE:
Training RMSE shows how well the model fits the data it was trained
on. Testing RMSE shows how well the model performs on new data, which is
a better indicator of real-world performance. This evaluation helps us
understand whether the model is overfitting, underfitting, or performing
as expected, and gives us a sense of how accurate its BMI predictions
are in practice.
Analyze Important Features
# Check variable importance
importance <- data.frame(
Variable = names(tree_model$variable.importance),
Importance = as.numeric(tree_model$variable.importance)
)
# Display neatly
kable(importance, caption = "Variable Importance in Decision Tree Model")
Variable Importance in Decision Tree Model
Weight |
92294.2396 |
Height |
18200.5106 |
Age |
16343.7744 |
FCVC |
14226.0842 |
Gender |
8125.2846 |
CH2O |
7416.5660 |
CAEC |
3835.4491 |
family_history_with_overweight |
3096.4359 |
FAF |
2365.9833 |
NCP |
1446.6894 |
FAVC |
316.7405 |
Understanding What Really Affects Weight Predictions
After building our BMI prediction model, we wanted to identify which
variables had the most influence on the predictions. To do this, we
extracted the variable importance scores from the decision tree
model.
These scores reflect how frequently and effectively each variable was
used to split the data in the tree. Variables that played a larger role
in creating accurate predictions received higher scores.
We then organized this information into a clear table with two
columns:
Variable: The name of each predictor (e.g., Height, Age, FCVC)
Importance: A numeric score indicating how influential the variable was
in the model
Using the kable() function, we displayed the table in a professional
format and added a clear caption for context. This made it easy to
compare which features had the most impact.
This analysis helps answer key questions such as:
- Which lifestyle or demographic factors most influence BMI?
- Are there specific variables we should focus on in future data
collection?
- Do the most important predictors align with our expectations and
domain knowledge?
Conclusion:
Methods - Describe building a shallow Decision Tree with depth = 3,
reason for balance between interpretability and prediction. Results -
Report Training RMSE, Testing RMSE, include the Decision Tree plot
(Figure 1), and Variable Importance (Table 1). Discussion - Discuss
Decision Trees being simple to interpret but sometimes underfitting
complex patterns.
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKVGhpcyBpcyBhbiBbUiBNYXJrZG93bl0oaHR0cDovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbSkgTm90ZWJvb2suIFdoZW4geW91IGV4ZWN1dGUgY29kZSB3aXRoaW4gdGhlIG5vdGVib29rLCB0aGUgcmVzdWx0cyBhcHBlYXIgYmVuZWF0aCB0aGUgY29kZS4gCgpUcnkgZXhlY3V0aW5nIHRoaXMgY2h1bmsgYnkgY2xpY2tpbmcgdGhlICpSdW4qIGJ1dHRvbiB3aXRoaW4gdGhlIGNodW5rIG9yIGJ5IHBsYWNpbmcgeW91ciBjdXJzb3IgaW5zaWRlIGl0IGFuZCBwcmVzc2luZyAqQ21kK1NoaWZ0K0VudGVyKi4gCgotLS0tLS0tLQoKIyBMb2FkIHRoZSBPYmVzaXR5IERhdGFzZXQKCgojIFByb2plY3QgT3ZlcnZpZXc6IFByZWRpY3RpbmcgV2VpZ2h0IEJhc2VkIG9uIExpZmVzdHlsZSBGYWN0b3JzCgpGb3Igb3VyIHByb2plY3QsIHdlIGNob3NlIHRoZSBPYmVzaXR5IExldmVscyBkYXRhc2V0IGZyb20gdGhlIFVDSSBNYWNoaW5lIExlYXJuaW5nIFJlcG9zaXRvcnkuIFRoaXMgZGF0YXNldCBjb21iaW5lcyByZWFsIGFuZCBzeW50aGV0aWMgZGF0YSwgY2FwdHVyaW5nIGRldGFpbHMgYWJvdXQgcGVvcGxl4oCZcyBlYXRpbmcgaGFiaXRzLCBwaHlzaWNhbCBhY3Rpdml0eSwgYW5kIGJpb2xvZ2ljYWwgdHJhaXRzIChsaWtlIGFnZSwgZ2VuZGVyLCBhbmQgaGVpZ2h0KS4gT3VyIG1haW4gZ29hbCBpcyB0byBwcmVkaWN0IHdlaWdodOKAlGEgY29udGludW91cyB2YXJpYWJsZeKAlHVzaW5nIHRoZXNlIGRpZmZlcmVudCBsaWZlc3R5bGUgYW5kIGhlYWx0aCBmYWN0b3JzLgoKIyBEYXRhIFByZXBhcmF0aW9uICYgSW5pdGlhbCBJbnNpZ2h0cwpCZWZvcmUgZGl2aW5nIGludG8gbW9kZWxpbmcsIHdlIGNsZWFuZWQgYW5kIHByZXBhcmVkIHRoZSBkYXRhIGJ5OgoKQ29udmVydGluZyB0ZXh0LWJhc2VkIChjYXRlZ29yaWNhbCkgdmFyaWFibGVzIGludG8gbnVtZXJpY2FsIGZhY3RvcnMgZm9yIGFuYWx5c2lzLgpFbnN1cmluZyBubyBtaXNzaW5nIHZhbHVlcyB3ZXJlIHByZXNlbnQgdGhhdCBjb3VsZCBza2V3IHJlc3VsdHMuClNwbGl0dGluZyB0aGUgZGF0YSBpbnRvIGFuIDgwJSB0cmFpbmluZyBzZXQgKHRvIGJ1aWxkIG1vZGVscykgYW5kIGEgMjAlIHRlc3Rpbmcgc2V0ICh0byBldmFsdWF0ZSB0aGVpciBwZXJmb3JtYW5jZSBmYWlybHkpLgoKIyBLZXkgb2JzZXJ2YXRpb25zIGZyb20gZWFybHkgZXhwbG9yYXRpb246CgpWYXJpYWJsZXMgaW5jbHVkZSBhZ2UsIGhlaWdodCwgZGlldGFyeSBwYXR0ZXJucyAoZS5nLiwgZnJlcXVlbnQgaGlnaC1jYWxvcmllIGZvb2QgY29uc3VtcHRpb24pLCBhbmQgYWN0aXZpdHkgbGV2ZWxzIChleGVyY2lzZSBmcmVxdWVuY3ksIHNjcmVlbiB0aW1lKS4KV2VpZ2h0IGlzIG91ciB0YXJnZXQsIGFuYWx5emVkIGFzIGEgY29udGludW91cyB2YWx1ZeKAlGlkZWFsIGZvciByZWdyZXNzaW9uIHRlY2huaXF1ZXMuClRoZSBkYXRhc2V0IHdhcyBhbHJlYWR5IHF1aXRlIGNsZWFuLCByZXF1aXJpbmcgbWluaW1hbCBhZGp1c3RtZW50cyBiZWZvcmUgbW9kZWxpbmcuCgpgYGB7cn0KIyBMb2FkIG5lY2Vzc2FyeSBsaWJyYXJpZXMKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkocnBhcnQpCmxpYnJhcnkocnBhcnQucGxvdCkKbGlicmFyeShjYXJldCkKbGlicmFyeShrbml0cikgICMgZm9yIG5lYXQgdGFibGVzCgojIFJlYWQgdGhlIGRhdGFzZXQKb2Jlc2l0eV9kYXRhIDwtIHJlYWQuY3N2KCJ+L0Rlc2t0b3AvT2Jlc2l0eURhdGFTZXRfcmF3X2FuZF9kYXRhX3NpbnRoZXRpYy5jc3YiKQoKIyBWaWV3IGZpcnN0IGZldyByb3dzCmhlYWQob2Jlc2l0eV9kYXRhKQoKIyBDYWxjdWxhdGUgQk1JCm9iZXNpdHlfZGF0YSRCTUkgPC0gb2Jlc2l0eV9kYXRhJFdlaWdodCAvIChvYmVzaXR5X2RhdGEkSGVpZ2h0XjIpCgojIFJlbW92ZSBOT2JleWVzZGFkICh0YXJnZXQgbGVha2FnZSkKb2Jlc2l0eV9kYXRhIDwtIG9iZXNpdHlfZGF0YSAlPiUgc2VsZWN0KC1OT2JleWVzZGFkKQpgYGAKCgojIERhdGEgUHJlcHJvY2Vzc2luZwoKYGBge3J9CiMgQ2hlY2sgdmFyaWFibGUgdHlwZXMKc3RyKG9iZXNpdHlfZGF0YSkKCiMgQ29udmVydCBjaGFyYWN0ZXIgdmFyaWFibGVzIHRvIGZhY3RvcnMKb2Jlc2l0eV9kYXRhIDwtIG9iZXNpdHlfZGF0YSAlPiUgCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5jaGFyYWN0ZXIpLCBhcy5mYWN0b3IpKQoKIyBSZW1vdmUgYW55IG1pc3NpbmcgdmFsdWVzCm9iZXNpdHlfZGF0YSA8LSBuYS5vbWl0KG9iZXNpdHlfZGF0YSkKCiMgU3BsaXQgdGhlIGRhdGEgaW50byB0cmFpbmluZyBhbmQgdGVzdGluZyBzZXRzICg4MC8yMCBzcGxpdCkKc2V0LnNlZWQoMTIzKQp0cmFpbl9pbmRleCA8LSBjcmVhdGVEYXRhUGFydGl0aW9uKG9iZXNpdHlfZGF0YSRCTUksIHAgPSAwLjgsIGxpc3QgPSBGQUxTRSkKdHJhaW5fZGF0YSA8LSBvYmVzaXR5X2RhdGFbdHJhaW5faW5kZXgsIF0KdGVzdF9kYXRhIDwtIG9iZXNpdHlfZGF0YVstdHJhaW5faW5kZXgsIF0KYGBgCgpGaXJzdCwgd2UgY2hlY2tlZCB0aGUgc3RydWN0dXJlIG9mIG91ciBkYXRhc2V0IChvYmVzaXR5X2RhdGEpIHRvIHNlZSB3aGF0IHR5cGVzIG9mIHZhcmlhYmxlcyB3ZSB3ZXJlIHdvcmtpbmcgd2l0aOKAlGxpa2UgbnVtYmVycywgY2F0ZWdvcmllcywgb3IgdGV4dC4KClNpbmNlIHNvbWUgY29sdW1ucyB3ZXJlIHN0b3JlZCBhcyB0ZXh0IChjaGFyYWN0ZXJzKSwgd2UgY29udmVydGVkIHRoZW0gaW50byBmYWN0b3Jz4oCUYSBmb3JtYXQgUiB1bmRlcnN0YW5kcyBiZXR0ZXIgZm9yIHN0YXRpc3RpY2FsIG1vZGVsaW5nLiBUaGlzIGhlbHBzIHRoZSBtb2RlbHMgcmVjb2duaXplIGNhdGVnb3JpZXMgKGxpa2UgIk1hbGUiIG9yICJGZW1hbGUiKSBwcm9wZXJseS4KCk5leHQsIHdlIG1hZGUgc3VyZSBvdXIgZGF0YSB3YXMgY2xlYW4gYW5kIGNvbXBsZXRlIGJ5IHJlbW92aW5nIGFueSByb3dzIHdpdGggbWlzc2luZyB2YWx1ZXMuIFRoaXMgYXZvaWRzIGVycm9ycyBvciBiaWFzZWQgcmVzdWx0cyBsYXRlciBvbi4KCkZpbmFsbHksIHdlIHNwbGl0IHRoZSBkYXRhIGludG8gdHdvIHBhcnRzOgoKVHJhaW5pbmcgc2V0ICg4MCUpOiBVc2VkIHRvIGJ1aWxkIGFuZCB0cmFpbiBvdXIgbW9kZWxzLgpUZXN0aW5nIHNldCAoMjAlKTogUmVzZXJ2ZWQgdG8gY2hlY2sgaG93IHdlbGwgdGhlIG1vZGVscyBwZXJmb3JtIG9uIHVuc2VlbiBkYXRhLgpXZSBzZXQgYSByYW5kb20gc2VlZCAoc2V0LnNlZWQoMTIzKSkgdG8gZW5zdXJlIHRoaXMgc3BsaXQgaXMgcmVwcm9kdWNpYmxl4oCUbWVhbmluZyBhbnlvbmUgcnVubmluZyB0aGUgY29kZSBnZXRzIHRoZSBzYW1lIHRyYWluaW5nL3Rlc3RpbmcgZ3JvdXBzIGZvciBmYWlyIGNvbXBhcmlzb25zLgoKCiMgQnVpbGQgYSBTaGFsbG93IERlY2lzaW9uIFRyZWUKCmBgYHtyfQojIFRyYWluIGEgc2hhbGxvdyBkZWNpc2lvbiB0cmVlIHRvIHByZWRpY3QgQk1JCnRyZWVfbW9kZWwgPC0gcnBhcnQoQk1JIH4gLiwgCiAgICAgICAgICAgICAgICAgICAgZGF0YSA9IHRyYWluX2RhdGEsIAogICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJhbm92YSIsIAogICAgICAgICAgICAgICAgICAgIGNvbnRyb2wgPSBycGFydC5jb250cm9sKG1heGRlcHRoID0gMywgY3AgPSAwLjAxKSkKCiMgUGxvdCB0aGUgZGVjaXNpb24gdHJlZQpycGFydC5wbG90KHRyZWVfbW9kZWwsCiAgICAgICAgICAgdHlwZSA9IDQsCiAgICAgICAgICAgZXh0cmEgPSAxMDEsCiAgICAgICAgICAgZmFsbGVuLmxlYXZlcyA9IFRSVUUsCiAgICAgICAgICAgYm94LnBhbGV0dGUgPSAiQmx1ZXMiLAogICAgICAgICAgIHNoYWRvdy5jb2wgPSAiZ3JheSIpCmBgYApXZSBzdGFydGVkIGJ5IHRyYWluaW5nIGEgYmFzaWMgRGVjaXNpb24gVHJlZSBtb2RlbCB0byBwcmVkaWN0IEJvZHkgTWFzcyBJbmRleCAoQk1JKSB1c2luZyBhbGwgb3RoZXIgYXZhaWxhYmxlIHZhcmlhYmxlcyBpbiB0aGUgZGF0YXNldCAoZXhjbHVkaW5nIE5PYmV5ZXNkYWQsIHdoaWNoIHdhcyByZW1vdmVkIHRvIHByZXZlbnQgdGFyZ2V0IGxlYWthZ2UpLgoKVG8ga2VlcCB0aGUgbW9kZWwgaW50ZW50aW9uYWxseSBzaW1wbGUgYW5kIGludGVycHJldGFibGUsIHdlIHJlc3RyaWN0ZWQgaXRzIGNvbXBsZXhpdHkgaW4gdHdvIHdheXM6CgpXZSBsaW1pdGVkIHRoZSBtYXhpbXVtIGRlcHRoIHRvIDMgbGV2ZWxzIHRvIGF2b2lkIG92ZXJmaXR0aW5nIGFuZCB1bm5lY2Vzc2FyeSBjb21wbGV4aXR5LgpXZSBzZXQgYSByZWxhdGl2ZWx5IGhpZ2ggY29tcGxleGl0eSBwYXJhbWV0ZXIgKGNwID0gMC4wMSkgdG8gZW5jb3VyYWdlIHBydW5pbmcgb2YgbGVzcyBpbmZvcm1hdGl2ZSBzcGxpdHMuClNpbmNlIEJNSSBpcyBhIGNvbnRpbnVvdXMgdmFyaWFibGUsIHdlIHVzZWQgdGhlICdhbm92YScgbWV0aG9kIGluIHRoZSBycGFydCgpIGZ1bmN0aW9uIHRvIGluZGljYXRlIHJlZ3Jlc3Npb24gcmF0aGVyIHRoYW4gY2xhc3NpZmljYXRpb24uCgpGb3IgdmlzdWFsaXphdGlvbiwgd2UgY3JlYXRlZCBhIGNsZWFuIGFuZCBpbmZvcm1hdGl2ZSB0cmVlIHBsb3QgdGhhdCBzaG93czoKClRoZSBoaWVyYXJjaGljYWwgZGVjaXNpb24gcG9pbnRzIChzcGxpdHMpIGJhc2VkIG9uIHRoZSBtb3N0IGluZmx1ZW50aWFsIHByZWRpY3RvcnMKVGhlIHByZWRpY3RlZCBCTUkgdmFsdWVzIGF0IGVhY2ggdGVybWluYWwgbm9kZSAobGVhZikKQSBjb2xvciBncmFkaWVudCAodXNpbmcgYSBibHVlIHBhbGV0dGUpIHRvIHZpc3VhbGx5IGluZGljYXRlIGRpZmZlcmVudCBwcmVkaWN0aW9uIHJhbmdlcwpTdWJ0bGUgc2hhZG93cyB0byBpbXByb3ZlIHJlYWRhYmlsaXR5IGFuZCBkaXN0aW5ndWlzaCBicmFuY2hlcwoKVGhpcyByZXN0cmFpbmVkIGFwcHJvYWNoIGdpdmVzIHVzIGEgbW9kZWwgdGhhdCBpczoKCkVhc3kgdG8gaW50ZXJwcmV0IGFuZCBleHBsYWluIHRvIG5vbi10ZWNobmljYWwgc3Rha2Vob2xkZXJzClF1aWNrIHRvIHRyYWluIGFuZCBjb21wdXRhdGlvbmFsbHkgZWZmaWNpZW50ClByb3ZpZGVzIGEgc29saWQgYmFzZWxpbmUgZm9yIGNvbXBhcmlzb24gd2l0aCBtb3JlIGNvbXBsZXggbW9kZWxzIHN1Y2ggYXMgWEdCb29zdApUaGUgdHJlZSB2aXN1YWxpemF0aW9uIGFjdHMgYXMgYm90aCBhIGRpYWdub3N0aWMgdG9vbCAodG8gYXNzZXNzIGlmIHNwbGl0cyBtYWtlIGxvZ2ljYWwgc2Vuc2UpIGFuZCBhIGNvbW11bmljYXRpb24gdG9vbCAodG8gaGVscCBleHBsYWluIGhvdyBpbnB1dCBmYWN0b3JzIGluZmx1ZW5jZSBCTUkgb3V0Y29tZXMpLgoKCiMgRXZhbHVhdGUgdGhlIE1vZGVsCgpgYGB7cn0KIyBQcmVkaWN0IG9uIHRyYWluaW5nIGFuZCB0ZXN0IGRhdGEKdHJhaW5fcHJlZCA8LSBwcmVkaWN0KHRyZWVfbW9kZWwsIG5ld2RhdGEgPSB0cmFpbl9kYXRhKQp0ZXN0X3ByZWQgPC0gcHJlZGljdCh0cmVlX21vZGVsLCBuZXdkYXRhID0gdGVzdF9kYXRhKQoKIyBDYWxjdWxhdGUgUk1TRSAoUm9vdCBNZWFuIFNxdWFyZWQgRXJyb3IpCnRyYWluX3Jtc2UgPC0gc3FydChtZWFuKCh0cmFpbl9wcmVkIC0gdHJhaW5fZGF0YSRCTUkpXjIpKQp0ZXN0X3Jtc2UgPC0gc3FydChtZWFuKCh0ZXN0X3ByZWQgLSB0ZXN0X2RhdGEkQk1JKV4yKSkKCiMgUHJpbnQgUk1TRSBuZWF0bHkKY2F0KCJUcmFpbmluZyBSTVNFOiIsIHJvdW5kKHRyYWluX3Jtc2UsIDIpLCAiXG4iKQpjYXQoIlRlc3RpbmcgUk1TRToiLCByb3VuZCh0ZXN0X3Jtc2UsIDIpLCAiXG4iKQpgYGAKCldlIHVzZWQgb3VyIGRlY2lzaW9uIHRyZWUgdG8gcHJlZGljdCBCTUkgaW4gdHdvIHNjZW5hcmlvczoKCkZvciBpbmRpdmlkdWFscyBpbiB0aGUgdHJhaW5pbmcgc2V0IChkYXRhIHRoZSBtb2RlbCBoYWQgYWxyZWFkeSBzZWVuKQpGb3IgaW5kaXZpZHVhbHMgaW4gdGhlIHRlc3Rpbmcgc2V0IChuZXcsIHVuc2VlbiBkYXRhKQoKVG8gZXZhbHVhdGUgaG93IGFjY3VyYXRlIHRoZSBtb2RlbOKAmXMgcHJlZGljdGlvbnMgd2VyZSwgd2UgY2FsY3VsYXRlZCB0aGUgUm9vdCBNZWFuIFNxdWFyZWQgRXJyb3IgKFJNU0UpLiBSTVNFIGdpdmVzIHVzIG9uZSBudW1iZXIgdGhhdCBzdW1tYXJpemVzIHRoZSB0eXBpY2FsIHByZWRpY3Rpb24gZXJyb3Ig4oCUIHNtYWxsZXIgdmFsdWVzIGluZGljYXRlIG1vcmUgYWNjdXJhdGUgcHJlZGljdGlvbnMuCgpUaGUgc3RlcHMgd2VyZSBhcyBmb2xsb3dzOgoKRmlyc3QsIHdlIGdlbmVyYXRlZCBwcmVkaWN0aW9ucyBmb3IgYm90aCB0aGUgdHJhaW5pbmcgYW5kIHRlc3Rpbmcgc2V0cy4KClRoZW4sIHdlIGNhbGN1bGF0ZWQgUk1TRSBieToKCjEuIFRha2luZyB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBwcmVkaWN0ZWQgYW5kIGFjdHVhbCBCTUkgdmFsdWVzCjIuIFNxdWFyaW5nIHRob3NlIGRpZmZlcmVuY2VzCjMuIEF2ZXJhZ2luZyB0aGVtCjQuIFRha2luZyB0aGUgc3F1YXJlIHJvb3Qgb2YgdGhhdCBhdmVyYWdlCgpGaW5hbGx5LCB3ZSBwcmludGVkIHRoZSBUcmFpbmluZyBSTVNFIGFuZCBUZXN0aW5nIFJNU0U6CgpUcmFpbmluZyBSTVNFIHNob3dzIGhvdyB3ZWxsIHRoZSBtb2RlbCBmaXRzIHRoZSBkYXRhIGl0IHdhcyB0cmFpbmVkIG9uLgpUZXN0aW5nIFJNU0Ugc2hvd3MgaG93IHdlbGwgdGhlIG1vZGVsIHBlcmZvcm1zIG9uIG5ldyBkYXRhLCB3aGljaCBpcyBhIGJldHRlciBpbmRpY2F0b3Igb2YgcmVhbC13b3JsZCBwZXJmb3JtYW5jZS4KVGhpcyBldmFsdWF0aW9uIGhlbHBzIHVzIHVuZGVyc3RhbmQgd2hldGhlciB0aGUgbW9kZWwgaXMgb3ZlcmZpdHRpbmcsIHVuZGVyZml0dGluZywgb3IgcGVyZm9ybWluZyBhcyBleHBlY3RlZCwgYW5kIGdpdmVzIHVzIGEgc2Vuc2Ugb2YgaG93IGFjY3VyYXRlIGl0cyBCTUkgcHJlZGljdGlvbnMgYXJlIGluIHByYWN0aWNlLgoKCiMgQW5hbHl6ZSBJbXBvcnRhbnQgRmVhdHVyZXMKCmBgYHtyfQojIENoZWNrIHZhcmlhYmxlIGltcG9ydGFuY2UKaW1wb3J0YW5jZSA8LSBkYXRhLmZyYW1lKAogIFZhcmlhYmxlID0gbmFtZXModHJlZV9tb2RlbCR2YXJpYWJsZS5pbXBvcnRhbmNlKSwKICBJbXBvcnRhbmNlID0gYXMubnVtZXJpYyh0cmVlX21vZGVsJHZhcmlhYmxlLmltcG9ydGFuY2UpCikKCiMgRGlzcGxheSBuZWF0bHkKa2FibGUoaW1wb3J0YW5jZSwgY2FwdGlvbiA9ICJWYXJpYWJsZSBJbXBvcnRhbmNlIGluIERlY2lzaW9uIFRyZWUgTW9kZWwiKQpgYGAKCiMgVW5kZXJzdGFuZGluZyBXaGF0IFJlYWxseSBBZmZlY3RzIFdlaWdodCBQcmVkaWN0aW9ucwoKQWZ0ZXIgYnVpbGRpbmcgb3VyIEJNSSBwcmVkaWN0aW9uIG1vZGVsLCB3ZSB3YW50ZWQgdG8gaWRlbnRpZnkgd2hpY2ggdmFyaWFibGVzIGhhZCB0aGUgbW9zdCBpbmZsdWVuY2Ugb24gdGhlIHByZWRpY3Rpb25zLiBUbyBkbyB0aGlzLCB3ZSBleHRyYWN0ZWQgdGhlIHZhcmlhYmxlIGltcG9ydGFuY2Ugc2NvcmVzIGZyb20gdGhlIGRlY2lzaW9uIHRyZWUgbW9kZWwuCgpUaGVzZSBzY29yZXMgcmVmbGVjdCBob3cgZnJlcXVlbnRseSBhbmQgZWZmZWN0aXZlbHkgZWFjaCB2YXJpYWJsZSB3YXMgdXNlZCB0byBzcGxpdCB0aGUgZGF0YSBpbiB0aGUgdHJlZS4gVmFyaWFibGVzIHRoYXQgcGxheWVkIGEgbGFyZ2VyIHJvbGUgaW4gY3JlYXRpbmcgYWNjdXJhdGUgcHJlZGljdGlvbnMgcmVjZWl2ZWQgaGlnaGVyIHNjb3Jlcy4KCldlIHRoZW4gb3JnYW5pemVkIHRoaXMgaW5mb3JtYXRpb24gaW50byBhIGNsZWFyIHRhYmxlIHdpdGggdHdvIGNvbHVtbnM6CgpWYXJpYWJsZTogVGhlIG5hbWUgb2YgZWFjaCBwcmVkaWN0b3IgKGUuZy4sIEhlaWdodCwgQWdlLCBGQ1ZDKQpJbXBvcnRhbmNlOiBBIG51bWVyaWMgc2NvcmUgaW5kaWNhdGluZyBob3cgaW5mbHVlbnRpYWwgdGhlIHZhcmlhYmxlIHdhcyBpbiB0aGUgbW9kZWwKClVzaW5nIHRoZSBrYWJsZSgpIGZ1bmN0aW9uLCB3ZSBkaXNwbGF5ZWQgdGhlIHRhYmxlIGluIGEgcHJvZmVzc2lvbmFsIGZvcm1hdCBhbmQgYWRkZWQgYSBjbGVhciBjYXB0aW9uIGZvciBjb250ZXh0LiBUaGlzIG1hZGUgaXQgZWFzeSB0byBjb21wYXJlIHdoaWNoIGZlYXR1cmVzIGhhZCB0aGUgbW9zdCBpbXBhY3QuCgpUaGlzIGFuYWx5c2lzIGhlbHBzIGFuc3dlciBrZXkgcXVlc3Rpb25zIHN1Y2ggYXM6CgoxLiBXaGljaCBsaWZlc3R5bGUgb3IgZGVtb2dyYXBoaWMgZmFjdG9ycyBtb3N0IGluZmx1ZW5jZSBCTUk/CjIuIEFyZSB0aGVyZSBzcGVjaWZpYyB2YXJpYWJsZXMgd2Ugc2hvdWxkIGZvY3VzIG9uIGluIGZ1dHVyZSBkYXRhIGNvbGxlY3Rpb24/CjMuIERvIHRoZSBtb3N0IGltcG9ydGFudCBwcmVkaWN0b3JzIGFsaWduIHdpdGggb3VyIGV4cGVjdGF0aW9ucyBhbmQgZG9tYWluIGtub3dsZWRnZT8KCgojIENvbmNsdXNpb246CgpNZXRob2RzCS0gRGVzY3JpYmUgYnVpbGRpbmcgYSBzaGFsbG93IERlY2lzaW9uIFRyZWUgd2l0aCBkZXB0aCA9IDMsIHJlYXNvbiBmb3IgYmFsYW5jZSBiZXR3ZWVuIGludGVycHJldGFiaWxpdHkgYW5kIHByZWRpY3Rpb24uClJlc3VsdHMJLSBSZXBvcnQgVHJhaW5pbmcgUk1TRSwgVGVzdGluZyBSTVNFLCBpbmNsdWRlIHRoZSBEZWNpc2lvbiBUcmVlIHBsb3QgKEZpZ3VyZSAxKSwgYW5kIFZhcmlhYmxlIEltcG9ydGFuY2UgKFRhYmxlIDEpLgpEaXNjdXNzaW9uCS0gRGlzY3VzcyBEZWNpc2lvbiBUcmVlcyBiZWluZyBzaW1wbGUgdG8gaW50ZXJwcmV0IGJ1dCBzb21ldGltZXMgdW5kZXJmaXR0aW5nIGNvbXBsZXggcGF0dGVybnMuCgoK