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

  1. 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?

  2. Does bagging improve interpretability or just accuracy?
    How does bagging affect the interpretability of decision trees, and should we sacrifice interpretability for performance?

  3. 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:

  1. 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?

  2. 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?

  3. 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:

  1. 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.

  2. Bagging Enhances Generalization:
    Bootstrap aggregation (bagging) reduces overfitting by averaging multiple weak models, creating a more robust and generalizable ensemble model.

  3. 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=