Entropy, Gini Coefficient, Partition Trees, Bagging, and
Random Forest: A Study Guide
1. Entropy
Definition:
Entropy is a measure of disorder or randomness in a system. In
information theory, entropy quantifies the uncertainty associated with a
random variable. It is defined mathematically as:
Mathematical Representation: For a discrete random
variable \(X\) with possible outcomes
\(x_1, x_2, ..., x_n\) and
probabilities \(p_1, p_2, ..., p_n\),
entropy \(H(X)\) is given by:
\[
H(X) = - \sum_{i=1}^{n} p_i \log_2 p_i
\]
Where: - \(p_i\) is the probability
of occurrence of outcome \(x_i\) - The
base of the logarithm is typically 2 (log base 2), measuring information
in bits
Example: Fair Coin Flip If \(X\) represents the outcome of a fair coin
flip, then: - \(p(\text{heads}) = 0.5\)
- \(p(\text{tails}) = 0.5\)
Applying the entropy formula: \[
H(X) = - (0.5 \log_2 0.5 + 0.5 \log_2 0.5) = 1 \, \text{bit}
\]
A higher entropy value indicates more disorder, while a lower entropy
value represents more certainty or order.
Coding Representation in Python:
import numpy as np
def entropy(probabilities):
return -np.sum(probabilities * np.log2(probabilities))
# Example: Fair coin flip
probs = np.array([0.5, 0.5])
print("Entropy:", entropy(probs)) # Output: 1.0
2. Gini Coefficient vs. Gini Impurity
Gini Coefficient (Economics)
The Gini Coefficient measures income inequality in
economics. It ranges from 0 (perfect equality) to 1 (maximum
inequality).
Gini Impurity (Decision Trees)
Gini Impurity is a measure used in classification problems to
quantify how often a randomly chosen element would be incorrectly
labeled.
Mathematical Representation: For a classification
problem with \(k\) classes and
probabilities \(p_1, p_2, ..., p_k\),
the Gini impurity \(G(X)\) is
calculated as:
\[
G(X) = 1 - \sum_{i=1}^{k} p_i^2
\]
Example: Fair Coin Flip \[
G = 1 - (0.5^2 + 0.5^2) = 0.5
\]
Coding Representation in Python:
def gini_impurity(probabilities):
return 1 - np.sum(probabilities**2)
# Example: Fair coin flip
probs = np.array([0.5, 0.5])
print("Gini Impurity:", gini_impurity(probs)) # Output: 0.5
3. Partition Trees
Definition:
Partition trees (decision trees) are non-linear classifiers that
recursively split data into regions to maximize information gain.
Key Concepts:
- CART (Classification and Regression Trees): The
foundation for decision tree algorithms.
- Information Gain: The reduction in entropy or Gini
impurity when making a split.
- Stopping Criteria:
- Minimum information gain threshold
- Maximum depth
- Minimum samples per leaf
Coding Representation:
from sklearn.tree import DecisionTreeClassifier
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
# Load dataset
iris = load_iris()
X_train, X_test, y_train, y_test = train_test_split(iris.data, iris.target, test_size=0.2, random_state=42)
# Train decision tree classifier
clf = DecisionTreeClassifier(max_depth=3, criterion='gini')
clf.fit(X_train, y_train)
print("Decision Tree Score:", clf.score(X_test, y_test))
4. Bagging (Bootstrap Aggregation)
Definition:
Bagging is an ensemble technique that builds multiple models from
bootstrap samples and combines their predictions.
Key Concepts:
- Bootstrap Sampling: Randomly selecting samples with
replacement.
- Aggregation: Combining multiple models’ predictions
(e.g., averaging for regression, majority vote for classification).
Coding Representation:
from sklearn.ensemble import BaggingClassifier
# Bagging with decision trees
bagging_clf = BaggingClassifier(base_estimator=DecisionTreeClassifier(), n_estimators=100, random_state=42)
bagging_clf.fit(X_train, y_train)
print("Bagging Classifier Score:", bagging_clf.score(X_test, y_test))
5. Random Forest
Definition:
Random forest is an extension of bagging that builds multiple
decision trees and aggregates their results.
Key Concepts:
- Random Subsampling: Selecting a random subset of
data and features.
- Overfitting Prevention: Averaging many trees
reduces overfitting.
- Feature Importance: Identifying influential
features based on split criteria.
Coding Representation:
from sklearn.ensemble import RandomForestClassifier
# Train Random Forest classifier
rf_clf = RandomForestClassifier(n_estimators=100, random_state=42)
rf_clf.fit(X_train, y_train)
print("Random Forest Score:", rf_clf.score(X_test, y_test))
6. Bagging Exercise
Task:
Replication of Bagging Results Using
Scikit-Learn
Summary of Findings from the Paper
Leo Breiman’s 1994 paper on Bagging Predictors
introduced bootstrap aggregation (bagging) as a method
to improve the accuracy of classifiers and regression models by reducing
variance. Key findings include: - Bagging works best for
unstable models (e.g., decision trees and neural networks). -
Misclassification rates for classification trees
dropped significantly across multiple datasets. - 50 bootstrap
replicates were commonly used in classification tasks. -
25 bootstrap replicates were used in regression tasks.
- The most notable accuracy improvements were seen in
classification trees.
Replicating the Experiment Using Scikit-Learn
Below is a Python implementation of bagging using a Decision
Tree Classifier on the Breast Cancer dataset,
following Breiman’s approach.
Implementation in Python
import numpy as np
from sklearn.ensemble import BaggingClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
# Load dataset
data = load_breast_cancer()
X, y = data.data, data.target
# Split data into training and testing sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# Train a single Decision Tree (without bagging)
dt = DecisionTreeClassifier(random_state=42)
dt.fit(X_train, y_train)
y_pred_dt = dt.predict(X_test)
accuracy_dt = accuracy_score(y_test, y_pred_dt)
# Train a BaggingClassifier with 50 bootstrap samples (following Breiman's recommendation)
bagging = BaggingClassifier(base_estimator=DecisionTreeClassifier(), n_estimators=50, random_state=42)
bagging.fit(X_train, y_train)
y_pred_bagging = bagging.predict(X_test)
accuracy_bagging = accuracy_score(y_test, y_pred_bagging)
# Print results
print(f"Accuracy of single Decision Tree: {accuracy_dt:.4f}")
print(f"Accuracy with Bagging (50 estimators): {accuracy_bagging:.4f}")
Results & Discussion
- The Decision Tree Classifier will have
higher variance and could overfit to training
data.
- The Bagging Classifier (50 estimators) improves
accuracy by reducing variance, leading to
better generalization.
- Breiman’s study found an average misclassification reduction
of 20-47% for decision trees with bagging.
Discussion Questions for the Live Session
In modern applications, would 50 bootstrap replicates
still be the best choice?
Should we use an adaptive method to determine the number of bootstraps
dynamically?
Does bagging improve interpretability or just
accuracy?
How does bagging affect the interpretability of decision trees, and
should we sacrifice interpretability for performance?
What are the trade-offs of bagging vs. other ensemble
methods like boosting?
While bagging reduces variance, boosting reduces bias. In what
situations should one be preferred over the other?
This experiment is an attempt to replicate Breiman’s
findings and demonstrates the effectiveness of bagging in improving
model accuracy.
Discussion Questions:
- How does the number of bootstrap samples affect model
performance?
- What are the trade-offs between bagging and a single decision
tree?
- When would you use random forests over bagging?
Summary:
- Entropy quantifies randomness and information
gain.
- Gini Impurity measures classification
uncertainty.
- Partition Trees recursively split data for
decision-making.
- Bagging builds multiple models using bootstrap
aggregation.
- Random Forests improve bagging by introducing
feature randomness.
Three Relevant Questions for the Professor:
Regarding Entropy and Gini Impurity:
How do we decide when to use entropy versus Gini impurity as the
criterion for splitting in a decision tree? Are there specific datasets
or conditions where one consistently outperforms the other?
On Bagging and Random Forests:
In practical applications, is there a recommended threshold for the
number of bootstrap samples or decision trees in a random forest to
balance model performance and computational efficiency?
Overfitting in Partition Trees:
What are the best strategies to prevent overfitting in partition trees
besides limiting depth and minimum samples per leaf? Would pruning be
preferable to max-depth constraints?
Three Key Takeaways from the Asynchronous
Work:
Information Gain and Model Performance:
Both entropy and Gini impurity help measure disorder and information
gain, which guides decision tree splits. Lower entropy or Gini impurity
indicates a more informative decision boundary.
Bagging Enhances Generalization:
Bootstrap aggregation (bagging) reduces overfitting by averaging
multiple weak models, creating a more robust and generalizable ensemble
model.
Random Forests Leverage Feature
Randomness:
Unlike bagging alone, random forests introduce feature randomness in
addition to bootstrapped sampling, ensuring that individual decision
trees remain uncorrelated, which improves overall predictive accuracy
and model robustness.
LS0tDQp0aXRsZTogIjczMzMgTW9kdWxlIDcgLSBEZWNpc2lvbiBUcmVlcyINCmF1dGhvcjogIkplc3NpY2EgTWNQaGF1bCAtIGZvciBRVFcgU3ByaW5nIDIwMjUuIERyLiBTbGF0ZXIiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQoqKkVudHJvcHksIEdpbmkgQ29lZmZpY2llbnQsIFBhcnRpdGlvbiBUcmVlcywgQmFnZ2luZywgYW5kIFJhbmRvbSBGb3Jlc3Q6IEEgU3R1ZHkgR3VpZGUqKg0KDQojIyAxLiBFbnRyb3B5DQoNCiMjIyBEZWZpbml0aW9uOg0KRW50cm9weSBpcyBhIG1lYXN1cmUgb2YgZGlzb3JkZXIgb3IgcmFuZG9tbmVzcyBpbiBhIHN5c3RlbS4gSW4gaW5mb3JtYXRpb24gdGhlb3J5LCBlbnRyb3B5IHF1YW50aWZpZXMgdGhlIHVuY2VydGFpbnR5IGFzc29jaWF0ZWQgd2l0aCBhIHJhbmRvbSB2YXJpYWJsZS4gSXQgaXMgZGVmaW5lZCBtYXRoZW1hdGljYWxseSBhczoNCg0KKipNYXRoZW1hdGljYWwgUmVwcmVzZW50YXRpb246KioNCkZvciBhIGRpc2NyZXRlIHJhbmRvbSB2YXJpYWJsZSBcKCBYIFwpIHdpdGggcG9zc2libGUgb3V0Y29tZXMgXCggeF8xLCB4XzIsIC4uLiwgeF9uIFwpIGFuZCBwcm9iYWJpbGl0aWVzIFwoIHBfMSwgcF8yLCAuLi4sIHBfbiBcKSwgZW50cm9weSBcKCBIKFgpIFwpIGlzIGdpdmVuIGJ5Og0KDQpcWw0KSChYKSA9IC0gXHN1bV97aT0xfV57bn0gcF9pIFxsb2dfMiBwX2kNClxdDQoNCldoZXJlOg0KLSBcKCBwX2kgXCkgaXMgdGhlIHByb2JhYmlsaXR5IG9mIG9jY3VycmVuY2Ugb2Ygb3V0Y29tZSBcKCB4X2kgXCkNCi0gVGhlIGJhc2Ugb2YgdGhlIGxvZ2FyaXRobSBpcyB0eXBpY2FsbHkgMiAobG9nIGJhc2UgMiksIG1lYXN1cmluZyBpbmZvcm1hdGlvbiBpbiBiaXRzDQoNCioqRXhhbXBsZTogRmFpciBDb2luIEZsaXAqKg0KSWYgXCggWCBcKSByZXByZXNlbnRzIHRoZSBvdXRjb21lIG9mIGEgZmFpciBjb2luIGZsaXAsIHRoZW46DQotIFwoIHAoXHRleHR7aGVhZHN9KSA9IDAuNSBcKQ0KLSBcKCBwKFx0ZXh0e3RhaWxzfSkgPSAwLjUgXCkNCg0KQXBwbHlpbmcgdGhlIGVudHJvcHkgZm9ybXVsYToNClxbDQpIKFgpID0gLSAoMC41IFxsb2dfMiAwLjUgKyAwLjUgXGxvZ18yIDAuNSkgPSAxIFwsIFx0ZXh0e2JpdH0NClxdDQoNCkEgaGlnaGVyIGVudHJvcHkgdmFsdWUgaW5kaWNhdGVzIG1vcmUgZGlzb3JkZXIsIHdoaWxlIGEgbG93ZXIgZW50cm9weSB2YWx1ZSByZXByZXNlbnRzIG1vcmUgY2VydGFpbnR5IG9yIG9yZGVyLg0KDQojIyMgQ29kaW5nIFJlcHJlc2VudGF0aW9uIGluIFB5dGhvbjoNCmBgYHB5dGhvbg0KaW1wb3J0IG51bXB5IGFzIG5wDQoNCmRlZiBlbnRyb3B5KHByb2JhYmlsaXRpZXMpOg0KICAgIHJldHVybiAtbnAuc3VtKHByb2JhYmlsaXRpZXMgKiBucC5sb2cyKHByb2JhYmlsaXRpZXMpKQ0KDQojIEV4YW1wbGU6IEZhaXIgY29pbiBmbGlwDQpwcm9icyA9IG5wLmFycmF5KFswLjUsIDAuNV0pDQpwcmludCgiRW50cm9weToiLCBlbnRyb3B5KHByb2JzKSkgICMgT3V0cHV0OiAxLjANCmBgYA0KDQojIyAyLiBHaW5pIENvZWZmaWNpZW50IHZzLiBHaW5pIEltcHVyaXR5DQoNCiMjIyBHaW5pIENvZWZmaWNpZW50IChFY29ub21pY3MpDQpUaGUgKipHaW5pIENvZWZmaWNpZW50KiogbWVhc3VyZXMgaW5jb21lIGluZXF1YWxpdHkgaW4gZWNvbm9taWNzLiBJdCByYW5nZXMgZnJvbSAwIChwZXJmZWN0IGVxdWFsaXR5KSB0byAxIChtYXhpbXVtIGluZXF1YWxpdHkpLg0KDQojIyMgR2luaSBJbXB1cml0eSAoRGVjaXNpb24gVHJlZXMpDQpHaW5pIEltcHVyaXR5IGlzIGEgbWVhc3VyZSB1c2VkIGluIGNsYXNzaWZpY2F0aW9uIHByb2JsZW1zIHRvIHF1YW50aWZ5IGhvdyBvZnRlbiBhIHJhbmRvbWx5IGNob3NlbiBlbGVtZW50IHdvdWxkIGJlIGluY29ycmVjdGx5IGxhYmVsZWQuDQoNCioqTWF0aGVtYXRpY2FsIFJlcHJlc2VudGF0aW9uOioqDQpGb3IgYSBjbGFzc2lmaWNhdGlvbiBwcm9ibGVtIHdpdGggXCggayBcKSBjbGFzc2VzIGFuZCBwcm9iYWJpbGl0aWVzIFwoIHBfMSwgcF8yLCAuLi4sIHBfayBcKSwgdGhlIEdpbmkgaW1wdXJpdHkgXCggRyhYKSBcKSBpcyBjYWxjdWxhdGVkIGFzOg0KDQpcWw0KRyhYKSA9IDEgLSBcc3VtX3tpPTF9XntrfSBwX2leMg0KXF0NCg0KKipFeGFtcGxlOiBGYWlyIENvaW4gRmxpcCoqDQpcWw0KRyA9IDEgLSAoMC41XjIgKyAwLjVeMikgPSAwLjUNClxdDQoNCiMjIyBDb2RpbmcgUmVwcmVzZW50YXRpb24gaW4gUHl0aG9uOg0KYGBgcHl0aG9uDQpkZWYgZ2luaV9pbXB1cml0eShwcm9iYWJpbGl0aWVzKToNCiAgICByZXR1cm4gMSAtIG5wLnN1bShwcm9iYWJpbGl0aWVzKioyKQ0KDQojIEV4YW1wbGU6IEZhaXIgY29pbiBmbGlwDQpwcm9icyA9IG5wLmFycmF5KFswLjUsIDAuNV0pDQpwcmludCgiR2luaSBJbXB1cml0eToiLCBnaW5pX2ltcHVyaXR5KHByb2JzKSkgICMgT3V0cHV0OiAwLjUNCmBgYA0KDQojIyAzLiBQYXJ0aXRpb24gVHJlZXMNCg0KIyMjIERlZmluaXRpb246DQpQYXJ0aXRpb24gdHJlZXMgKGRlY2lzaW9uIHRyZWVzKSBhcmUgbm9uLWxpbmVhciBjbGFzc2lmaWVycyB0aGF0IHJlY3Vyc2l2ZWx5IHNwbGl0IGRhdGEgaW50byByZWdpb25zIHRvIG1heGltaXplIGluZm9ybWF0aW9uIGdhaW4uDQoNCiMjIyBLZXkgQ29uY2VwdHM6DQotICoqQ0FSVCAoQ2xhc3NpZmljYXRpb24gYW5kIFJlZ3Jlc3Npb24gVHJlZXMpKio6IFRoZSBmb3VuZGF0aW9uIGZvciBkZWNpc2lvbiB0cmVlIGFsZ29yaXRobXMuDQotICoqSW5mb3JtYXRpb24gR2FpbioqOiBUaGUgcmVkdWN0aW9uIGluIGVudHJvcHkgb3IgR2luaSBpbXB1cml0eSB3aGVuIG1ha2luZyBhIHNwbGl0Lg0KLSAqKlN0b3BwaW5nIENyaXRlcmlhKio6DQogIC0gTWluaW11bSBpbmZvcm1hdGlvbiBnYWluIHRocmVzaG9sZA0KICAtIE1heGltdW0gZGVwdGgNCiAgLSBNaW5pbXVtIHNhbXBsZXMgcGVyIGxlYWYNCg0KIyMjIENvZGluZyBSZXByZXNlbnRhdGlvbjoNCmBgYHB5dGhvbg0KZnJvbSBza2xlYXJuLnRyZWUgaW1wb3J0IERlY2lzaW9uVHJlZUNsYXNzaWZpZXINCmZyb20gc2tsZWFybi5kYXRhc2V0cyBpbXBvcnQgbG9hZF9pcmlzDQpmcm9tIHNrbGVhcm4ubW9kZWxfc2VsZWN0aW9uIGltcG9ydCB0cmFpbl90ZXN0X3NwbGl0DQoNCiMgTG9hZCBkYXRhc2V0DQppcmlzID0gbG9hZF9pcmlzKCkNClhfdHJhaW4sIFhfdGVzdCwgeV90cmFpbiwgeV90ZXN0ID0gdHJhaW5fdGVzdF9zcGxpdChpcmlzLmRhdGEsIGlyaXMudGFyZ2V0LCB0ZXN0X3NpemU9MC4yLCByYW5kb21fc3RhdGU9NDIpDQoNCiMgVHJhaW4gZGVjaXNpb24gdHJlZSBjbGFzc2lmaWVyDQpjbGYgPSBEZWNpc2lvblRyZWVDbGFzc2lmaWVyKG1heF9kZXB0aD0zLCBjcml0ZXJpb249J2dpbmknKQ0KY2xmLmZpdChYX3RyYWluLCB5X3RyYWluKQ0KDQpwcmludCgiRGVjaXNpb24gVHJlZSBTY29yZToiLCBjbGYuc2NvcmUoWF90ZXN0LCB5X3Rlc3QpKQ0KYGBgDQoNCiMjIDQuIEJhZ2dpbmcgKEJvb3RzdHJhcCBBZ2dyZWdhdGlvbikNCg0KIyMjIERlZmluaXRpb246DQpCYWdnaW5nIGlzIGFuIGVuc2VtYmxlIHRlY2huaXF1ZSB0aGF0IGJ1aWxkcyBtdWx0aXBsZSBtb2RlbHMgZnJvbSBib290c3RyYXAgc2FtcGxlcyBhbmQgY29tYmluZXMgdGhlaXIgcHJlZGljdGlvbnMuDQoNCiMjIyBLZXkgQ29uY2VwdHM6DQotICoqQm9vdHN0cmFwIFNhbXBsaW5nKio6IFJhbmRvbWx5IHNlbGVjdGluZyBzYW1wbGVzIHdpdGggcmVwbGFjZW1lbnQuDQotICoqQWdncmVnYXRpb24qKjogQ29tYmluaW5nIG11bHRpcGxlIG1vZGVscycgcHJlZGljdGlvbnMgKGUuZy4sIGF2ZXJhZ2luZyBmb3IgcmVncmVzc2lvbiwgbWFqb3JpdHkgdm90ZSBmb3IgY2xhc3NpZmljYXRpb24pLg0KDQojIyMgQ29kaW5nIFJlcHJlc2VudGF0aW9uOg0KYGBgcHl0aG9uDQpmcm9tIHNrbGVhcm4uZW5zZW1ibGUgaW1wb3J0IEJhZ2dpbmdDbGFzc2lmaWVyDQoNCiMgQmFnZ2luZyB3aXRoIGRlY2lzaW9uIHRyZWVzDQpiYWdnaW5nX2NsZiA9IEJhZ2dpbmdDbGFzc2lmaWVyKGJhc2VfZXN0aW1hdG9yPURlY2lzaW9uVHJlZUNsYXNzaWZpZXIoKSwgbl9lc3RpbWF0b3JzPTEwMCwgcmFuZG9tX3N0YXRlPTQyKQ0KYmFnZ2luZ19jbGYuZml0KFhfdHJhaW4sIHlfdHJhaW4pDQoNCnByaW50KCJCYWdnaW5nIENsYXNzaWZpZXIgU2NvcmU6IiwgYmFnZ2luZ19jbGYuc2NvcmUoWF90ZXN0LCB5X3Rlc3QpKQ0KYGBgDQoNCiMjIDUuIFJhbmRvbSBGb3Jlc3QNCg0KIyMjIERlZmluaXRpb246DQpSYW5kb20gZm9yZXN0IGlzIGFuIGV4dGVuc2lvbiBvZiBiYWdnaW5nIHRoYXQgYnVpbGRzIG11bHRpcGxlIGRlY2lzaW9uIHRyZWVzIGFuZCBhZ2dyZWdhdGVzIHRoZWlyIHJlc3VsdHMuDQoNCiMjIyBLZXkgQ29uY2VwdHM6DQotICoqUmFuZG9tIFN1YnNhbXBsaW5nKio6IFNlbGVjdGluZyBhIHJhbmRvbSBzdWJzZXQgb2YgZGF0YSBhbmQgZmVhdHVyZXMuDQotICoqT3ZlcmZpdHRpbmcgUHJldmVudGlvbioqOiBBdmVyYWdpbmcgbWFueSB0cmVlcyByZWR1Y2VzIG92ZXJmaXR0aW5nLg0KLSAqKkZlYXR1cmUgSW1wb3J0YW5jZSoqOiBJZGVudGlmeWluZyBpbmZsdWVudGlhbCBmZWF0dXJlcyBiYXNlZCBvbiBzcGxpdCBjcml0ZXJpYS4NCg0KIyMjIENvZGluZyBSZXByZXNlbnRhdGlvbjoNCmBgYHB5dGhvbg0KZnJvbSBza2xlYXJuLmVuc2VtYmxlIGltcG9ydCBSYW5kb21Gb3Jlc3RDbGFzc2lmaWVyDQoNCiMgVHJhaW4gUmFuZG9tIEZvcmVzdCBjbGFzc2lmaWVyDQpyZl9jbGYgPSBSYW5kb21Gb3Jlc3RDbGFzc2lmaWVyKG5fZXN0aW1hdG9ycz0xMDAsIHJhbmRvbV9zdGF0ZT00MikNCnJmX2NsZi5maXQoWF90cmFpbiwgeV90cmFpbikNCg0KcHJpbnQoIlJhbmRvbSBGb3Jlc3QgU2NvcmU6IiwgcmZfY2xmLnNjb3JlKFhfdGVzdCwgeV90ZXN0KSkNCmBgYA0KDQojIyA2LiBCYWdnaW5nIEV4ZXJjaXNlDQoNCiMjIyBUYXNrOg0KIyMjICoqUmVwbGljYXRpb24gb2YgQmFnZ2luZyBSZXN1bHRzIFVzaW5nIFNjaWtpdC1MZWFybioqDQoNCiMjIyMgKipTdW1tYXJ5IG9mIEZpbmRpbmdzIGZyb20gdGhlIFBhcGVyKioNCkxlbyBCcmVpbWFu4oCZcyAxOTk0IHBhcGVyIG9uICoqQmFnZ2luZyBQcmVkaWN0b3JzKiogaW50cm9kdWNlZCAqKmJvb3RzdHJhcCBhZ2dyZWdhdGlvbioqIChiYWdnaW5nKSBhcyBhIG1ldGhvZCB0byBpbXByb3ZlIHRoZSBhY2N1cmFjeSBvZiBjbGFzc2lmaWVycyBhbmQgcmVncmVzc2lvbiBtb2RlbHMgYnkgcmVkdWNpbmcgdmFyaWFuY2UuIEtleSBmaW5kaW5ncyBpbmNsdWRlOg0KLSAqKkJhZ2dpbmcgd29ya3MgYmVzdCBmb3IgdW5zdGFibGUgbW9kZWxzKiogKGUuZy4sIGRlY2lzaW9uIHRyZWVzIGFuZCBuZXVyYWwgbmV0d29ya3MpLg0KLSAqKk1pc2NsYXNzaWZpY2F0aW9uIHJhdGVzKiogZm9yIGNsYXNzaWZpY2F0aW9uIHRyZWVzIGRyb3BwZWQgc2lnbmlmaWNhbnRseSBhY3Jvc3MgbXVsdGlwbGUgZGF0YXNldHMuDQotICoqNTAgYm9vdHN0cmFwIHJlcGxpY2F0ZXMqKiB3ZXJlIGNvbW1vbmx5IHVzZWQgaW4gY2xhc3NpZmljYXRpb24gdGFza3MuDQotICoqMjUgYm9vdHN0cmFwIHJlcGxpY2F0ZXMqKiB3ZXJlIHVzZWQgaW4gcmVncmVzc2lvbiB0YXNrcy4NCi0gVGhlIG1vc3Qgbm90YWJsZSBhY2N1cmFjeSBpbXByb3ZlbWVudHMgd2VyZSBzZWVuIGluICoqY2xhc3NpZmljYXRpb24gdHJlZXMqKi4NCg0KLS0tDQoNCiMjIyAqKlJlcGxpY2F0aW5nIHRoZSBFeHBlcmltZW50IFVzaW5nIFNjaWtpdC1MZWFybioqDQpCZWxvdyBpcyBhIFB5dGhvbiBpbXBsZW1lbnRhdGlvbiBvZiBiYWdnaW5nIHVzaW5nIGEgKipEZWNpc2lvbiBUcmVlIENsYXNzaWZpZXIqKiBvbiB0aGUgKipCcmVhc3QgQ2FuY2VyIGRhdGFzZXQqKiwgZm9sbG93aW5nIEJyZWltYW7igJlzIGFwcHJvYWNoLg0KDQojIyMjICoqSW1wbGVtZW50YXRpb24gaW4gUHl0aG9uKioNCmBgYHB5dGhvbg0KaW1wb3J0IG51bXB5IGFzIG5wDQpmcm9tIHNrbGVhcm4uZW5zZW1ibGUgaW1wb3J0IEJhZ2dpbmdDbGFzc2lmaWVyDQpmcm9tIHNrbGVhcm4udHJlZSBpbXBvcnQgRGVjaXNpb25UcmVlQ2xhc3NpZmllcg0KZnJvbSBza2xlYXJuLmRhdGFzZXRzIGltcG9ydCBsb2FkX2JyZWFzdF9jYW5jZXINCmZyb20gc2tsZWFybi5tb2RlbF9zZWxlY3Rpb24gaW1wb3J0IHRyYWluX3Rlc3Rfc3BsaXQNCmZyb20gc2tsZWFybi5tZXRyaWNzIGltcG9ydCBhY2N1cmFjeV9zY29yZQ0KDQojIExvYWQgZGF0YXNldA0KZGF0YSA9IGxvYWRfYnJlYXN0X2NhbmNlcigpDQpYLCB5ID0gZGF0YS5kYXRhLCBkYXRhLnRhcmdldA0KDQojIFNwbGl0IGRhdGEgaW50byB0cmFpbmluZyBhbmQgdGVzdGluZyBzZXRzDQpYX3RyYWluLCBYX3Rlc3QsIHlfdHJhaW4sIHlfdGVzdCA9IHRyYWluX3Rlc3Rfc3BsaXQoWCwgeSwgdGVzdF9zaXplPTAuMiwgcmFuZG9tX3N0YXRlPTQyKQ0KDQojIFRyYWluIGEgc2luZ2xlIERlY2lzaW9uIFRyZWUgKHdpdGhvdXQgYmFnZ2luZykNCmR0ID0gRGVjaXNpb25UcmVlQ2xhc3NpZmllcihyYW5kb21fc3RhdGU9NDIpDQpkdC5maXQoWF90cmFpbiwgeV90cmFpbikNCnlfcHJlZF9kdCA9IGR0LnByZWRpY3QoWF90ZXN0KQ0KYWNjdXJhY3lfZHQgPSBhY2N1cmFjeV9zY29yZSh5X3Rlc3QsIHlfcHJlZF9kdCkNCg0KIyBUcmFpbiBhIEJhZ2dpbmdDbGFzc2lmaWVyIHdpdGggNTAgYm9vdHN0cmFwIHNhbXBsZXMgKGZvbGxvd2luZyBCcmVpbWFuJ3MgcmVjb21tZW5kYXRpb24pDQpiYWdnaW5nID0gQmFnZ2luZ0NsYXNzaWZpZXIoYmFzZV9lc3RpbWF0b3I9RGVjaXNpb25UcmVlQ2xhc3NpZmllcigpLCBuX2VzdGltYXRvcnM9NTAsIHJhbmRvbV9zdGF0ZT00MikNCmJhZ2dpbmcuZml0KFhfdHJhaW4sIHlfdHJhaW4pDQp5X3ByZWRfYmFnZ2luZyA9IGJhZ2dpbmcucHJlZGljdChYX3Rlc3QpDQphY2N1cmFjeV9iYWdnaW5nID0gYWNjdXJhY3lfc2NvcmUoeV90ZXN0LCB5X3ByZWRfYmFnZ2luZykNCg0KIyBQcmludCByZXN1bHRzDQpwcmludChmIkFjY3VyYWN5IG9mIHNpbmdsZSBEZWNpc2lvbiBUcmVlOiB7YWNjdXJhY3lfZHQ6LjRmfSIpDQpwcmludChmIkFjY3VyYWN5IHdpdGggQmFnZ2luZyAoNTAgZXN0aW1hdG9ycyk6IHthY2N1cmFjeV9iYWdnaW5nOi40Zn0iKQ0KYGBgDQoNCi0tLQ0KDQojIyMgKipSZXN1bHRzICYgRGlzY3Vzc2lvbioqDQotIFRoZSAqKkRlY2lzaW9uIFRyZWUgQ2xhc3NpZmllcioqIHdpbGwgaGF2ZSAqKmhpZ2hlciB2YXJpYW5jZSoqIGFuZCBjb3VsZCBvdmVyZml0IHRvIHRyYWluaW5nIGRhdGEuDQotIFRoZSAqKkJhZ2dpbmcgQ2xhc3NpZmllciAoNTAgZXN0aW1hdG9ycykqKiBpbXByb3ZlcyBhY2N1cmFjeSBieSAqKnJlZHVjaW5nIHZhcmlhbmNlKiosIGxlYWRpbmcgdG8gKipiZXR0ZXIgZ2VuZXJhbGl6YXRpb24qKi4NCi0gQnJlaW1hbuKAmXMgc3R1ZHkgZm91bmQgYW4gKiphdmVyYWdlIG1pc2NsYXNzaWZpY2F0aW9uIHJlZHVjdGlvbiBvZiAyMC00NyUqKiBmb3IgZGVjaXNpb24gdHJlZXMgd2l0aCBiYWdnaW5nLg0KDQotLS0NCg0KIyMjICoqRGlzY3Vzc2lvbiBRdWVzdGlvbnMgZm9yIHRoZSBMaXZlIFNlc3Npb24qKg0KMS4gKipJbiBtb2Rlcm4gYXBwbGljYXRpb25zLCB3b3VsZCA1MCBib290c3RyYXAgcmVwbGljYXRlcyBzdGlsbCBiZSB0aGUgYmVzdCBjaG9pY2U/KiogIA0KICAgU2hvdWxkIHdlIHVzZSBhbiBhZGFwdGl2ZSBtZXRob2QgdG8gZGV0ZXJtaW5lIHRoZSBudW1iZXIgb2YgYm9vdHN0cmFwcyBkeW5hbWljYWxseT8NCg0KMi4gKipEb2VzIGJhZ2dpbmcgaW1wcm92ZSBpbnRlcnByZXRhYmlsaXR5IG9yIGp1c3QgYWNjdXJhY3k/KiogIA0KICAgSG93IGRvZXMgYmFnZ2luZyBhZmZlY3QgdGhlIGludGVycHJldGFiaWxpdHkgb2YgZGVjaXNpb24gdHJlZXMsIGFuZCBzaG91bGQgd2Ugc2FjcmlmaWNlIGludGVycHJldGFiaWxpdHkgZm9yIHBlcmZvcm1hbmNlPw0KDQozLiAqKldoYXQgYXJlIHRoZSB0cmFkZS1vZmZzIG9mIGJhZ2dpbmcgdnMuIG90aGVyIGVuc2VtYmxlIG1ldGhvZHMgbGlrZSBib29zdGluZz8qKiAgDQogICBXaGlsZSBiYWdnaW5nIHJlZHVjZXMgdmFyaWFuY2UsIGJvb3N0aW5nIHJlZHVjZXMgYmlhcy4gSW4gd2hhdCBzaXR1YXRpb25zIHNob3VsZCBvbmUgYmUgcHJlZmVycmVkIG92ZXIgdGhlIG90aGVyPw0KDQotLS0NCg0KVGhpcyBleHBlcmltZW50IGlzIGFuIGF0dGVtcHQgdG8gKipyZXBsaWNhdGUqKiBCcmVpbWFu4oCZcyBmaW5kaW5ncyBhbmQgZGVtb25zdHJhdGVzIHRoZSBlZmZlY3RpdmVuZXNzIG9mIGJhZ2dpbmcgaW4gaW1wcm92aW5nIG1vZGVsIGFjY3VyYWN5LiANCg0KDQoNCiMjIyBEaXNjdXNzaW9uIFF1ZXN0aW9uczoNCi0gSG93IGRvZXMgdGhlIG51bWJlciBvZiBib290c3RyYXAgc2FtcGxlcyBhZmZlY3QgbW9kZWwgcGVyZm9ybWFuY2U/DQotIFdoYXQgYXJlIHRoZSB0cmFkZS1vZmZzIGJldHdlZW4gYmFnZ2luZyBhbmQgYSBzaW5nbGUgZGVjaXNpb24gdHJlZT8NCi0gV2hlbiB3b3VsZCB5b3UgdXNlIHJhbmRvbSBmb3Jlc3RzIG92ZXIgYmFnZ2luZz8NCg0KIyMjIFN1bW1hcnk6DQotICoqRW50cm9weSoqIHF1YW50aWZpZXMgcmFuZG9tbmVzcyBhbmQgaW5mb3JtYXRpb24gZ2Fpbi4NCi0gKipHaW5pIEltcHVyaXR5KiogbWVhc3VyZXMgY2xhc3NpZmljYXRpb24gdW5jZXJ0YWludHkuDQotICoqUGFydGl0aW9uIFRyZWVzKiogcmVjdXJzaXZlbHkgc3BsaXQgZGF0YSBmb3IgZGVjaXNpb24tbWFraW5nLg0KLSAqKkJhZ2dpbmcqKiBidWlsZHMgbXVsdGlwbGUgbW9kZWxzIHVzaW5nIGJvb3RzdHJhcCBhZ2dyZWdhdGlvbi4NCi0gKipSYW5kb20gRm9yZXN0cyoqIGltcHJvdmUgYmFnZ2luZyBieSBpbnRyb2R1Y2luZyBmZWF0dXJlIHJhbmRvbW5lc3MuDQoNCg0KIyMjICoqVGhyZWUgUmVsZXZhbnQgUXVlc3Rpb25zIGZvciB0aGUgUHJvZmVzc29yOioqDQoxLiAqKlJlZ2FyZGluZyBFbnRyb3B5IGFuZCBHaW5pIEltcHVyaXR5OioqICANCiAgIEhvdyBkbyB3ZSBkZWNpZGUgd2hlbiB0byB1c2UgZW50cm9weSB2ZXJzdXMgR2luaSBpbXB1cml0eSBhcyB0aGUgY3JpdGVyaW9uIGZvciBzcGxpdHRpbmcgaW4gYSBkZWNpc2lvbiB0cmVlPyBBcmUgdGhlcmUgc3BlY2lmaWMgZGF0YXNldHMgb3IgY29uZGl0aW9ucyB3aGVyZSBvbmUgY29uc2lzdGVudGx5IG91dHBlcmZvcm1zIHRoZSBvdGhlcj8NCg0KMi4gKipPbiBCYWdnaW5nIGFuZCBSYW5kb20gRm9yZXN0czoqKiAgDQogICBJbiBwcmFjdGljYWwgYXBwbGljYXRpb25zLCBpcyB0aGVyZSBhIHJlY29tbWVuZGVkIHRocmVzaG9sZCBmb3IgdGhlIG51bWJlciBvZiBib290c3RyYXAgc2FtcGxlcyBvciBkZWNpc2lvbiB0cmVlcyBpbiBhIHJhbmRvbSBmb3Jlc3QgdG8gYmFsYW5jZSBtb2RlbCBwZXJmb3JtYW5jZSBhbmQgY29tcHV0YXRpb25hbCBlZmZpY2llbmN5Pw0KDQozLiAqKk92ZXJmaXR0aW5nIGluIFBhcnRpdGlvbiBUcmVlczoqKiAgDQogICBXaGF0IGFyZSB0aGUgYmVzdCBzdHJhdGVnaWVzIHRvIHByZXZlbnQgb3ZlcmZpdHRpbmcgaW4gcGFydGl0aW9uIHRyZWVzIGJlc2lkZXMgbGltaXRpbmcgZGVwdGggYW5kIG1pbmltdW0gc2FtcGxlcyBwZXIgbGVhZj8gV291bGQgcHJ1bmluZyBiZSBwcmVmZXJhYmxlIHRvIG1heC1kZXB0aCBjb25zdHJhaW50cz8NCg0KLS0tDQoNCiMjIyAqKlRocmVlIEtleSBUYWtlYXdheXMgZnJvbSB0aGUgQXN5bmNocm9ub3VzIFdvcms6KioNCjEuICoqSW5mb3JtYXRpb24gR2FpbiBhbmQgTW9kZWwgUGVyZm9ybWFuY2U6KiogIA0KICAgQm90aCBlbnRyb3B5IGFuZCBHaW5pIGltcHVyaXR5IGhlbHAgbWVhc3VyZSBkaXNvcmRlciBhbmQgaW5mb3JtYXRpb24gZ2Fpbiwgd2hpY2ggZ3VpZGVzIGRlY2lzaW9uIHRyZWUgc3BsaXRzLiBMb3dlciBlbnRyb3B5IG9yIEdpbmkgaW1wdXJpdHkgaW5kaWNhdGVzIGEgbW9yZSBpbmZvcm1hdGl2ZSBkZWNpc2lvbiBib3VuZGFyeS4NCg0KMi4gKipCYWdnaW5nIEVuaGFuY2VzIEdlbmVyYWxpemF0aW9uOioqICANCiAgIEJvb3RzdHJhcCBhZ2dyZWdhdGlvbiAoYmFnZ2luZykgcmVkdWNlcyBvdmVyZml0dGluZyBieSBhdmVyYWdpbmcgbXVsdGlwbGUgd2VhayBtb2RlbHMsIGNyZWF0aW5nIGEgbW9yZSByb2J1c3QgYW5kIGdlbmVyYWxpemFibGUgZW5zZW1ibGUgbW9kZWwuDQoNCjMuICoqUmFuZG9tIEZvcmVzdHMgTGV2ZXJhZ2UgRmVhdHVyZSBSYW5kb21uZXNzOioqICANCiAgIFVubGlrZSBiYWdnaW5nIGFsb25lLCByYW5kb20gZm9yZXN0cyBpbnRyb2R1Y2UgZmVhdHVyZSByYW5kb21uZXNzIGluIGFkZGl0aW9uIHRvIGJvb3RzdHJhcHBlZCBzYW1wbGluZywgZW5zdXJpbmcgdGhhdCBpbmRpdmlkdWFsIGRlY2lzaW9uIHRyZWVzIHJlbWFpbiB1bmNvcnJlbGF0ZWQsIHdoaWNoIGltcHJvdmVzIG92ZXJhbGwgcHJlZGljdGl2ZSBhY2N1cmFjeSBhbmQgbW9kZWwgcm9idXN0bmVzcy4=