General
Statistical Learning (Data mining) methods can be classified as
supervised
or unsupervised.
\(X\) -> predictors, independent
variables, features, variables.
\(Y\) -> response, dependent
variable.
\(X = (X_1,X_2,...,X_p)\) and \(Y\) -> \(Y =
f(X) + \epsilon\), \(\epsilon\)
is a random error term and has mean zero. Data mining refers to a set of
approaches to estimate \(f\).
We estimate \(f\) to :
1. prediction. \(\hat Y = \hat
f(X)\)
2. inference. ( learn the relationship )
The accuracy of \(\hat Y\) as a
prediction for \(Y\) depends on:
1. reducible error
2. irreducible error
overfitting
-> It is an undesirable situation because
the fit obtained will not yield accurate estimates of the response on
new observations that were not part of the original training data
set.
Trade-Off between Prediction Accuracy and Model
Interpretability
DT
is good for interpreting.
Bagging
, Boosting
, RF
has higher
Accuracy, hard to interpret.
Supervised vs Unsupervised
supervised
- for each observation of the predictor
measurement(s) \(x_i, i=1,...n\) there
is an associated response measurement \(y_i\) -> predict \(Y\) or learn relationship between \(X\) and \(Y\) .
unsupervised
- for each observations \(x_i, i=1,...n\) we observe a vector of
measurements \(x_i\) but
no associated response \(y_i\) -> understand relationship between
the \(X_i\)s or observations.
Regression vs Classification
regression
-> quantitative response, numerical
response
classification
-> qualitative response, categorical
response
Model Accuracy
Regression
\[
MSE = \frac{1}{n} \sum_{i=1}^n {(y_i - \hat f(x_i))^2}
\] where \(\hat f(x_i) -> \hat
y_i\) (the prediction).
we are interested in the accuracy of the predictions that we obtain
when we apply our method to previously unseen test data. there is no
guarantee that the method with the lowest training MSE will also have
the lowest test MSE.
When a given method yields a small training MSE but a large test MSE,
we are said to be overfitting the data
.
Cross-Validation (CV) can be used to estimate the
test MSE on the training data.
Classification
Error rate: \[
error rate = \frac{1}{n} \sum_{i=1}^n {y_i \ne \hat y_i}
\] Bayes Classifier: \[
Pr(Y=k|X=x) \\
Pr(Y=1|X=x) > 0.5 \ \therefore k=1
\] KNN \[
Pr(Y=j|X=x_0) = \frac{1}{K} \sum_{i\in N_0}{I(y_i=j)}
\] \(N_0\) -> K points in the
training data that are closet to \(x_0\)
The Bias-Variance Trande-Off
Expected test MSE for a given value \(x_0\) can be given as:
In order to minimize the expected test error, we need to select a
statistical learning method that simultaneously achieves
low variance
and low bias
.
- Variance
-> Variance refers to the amount by which
\(\hat f\) would change if we estimated
it using a different training data set. (due to randomness on data) -
Bias
-> bias refers to the error that is introduced by
approximating a real-life problem, which may be extremely complicated,
by a much simpler model. (due to simplification)
model is too simple -> high bias (just use several \(X_i\))
model is too complex -> low bias (use too much \(X_i\), overfitting)
Classification
Response variable is qualitative.
simple:
- Naive Bayes
- KNN
computer intensive:
- DT
- Begging
- RF
- Boosting
Confusion Matrix
- Accuracy: ratio of correct predictions over all actual obs. \(\frac{TP+TN}{A0+A1}\) = \(\frac{TP+TN}{P0+P1}\)
- Sensitivity=Recall=True Positive Rate: # of correct ‘1’ s over all
actual ’1’s. \(\frac{TP}{A1}\) = \(\frac{TP}{TP+FN}\).
- Specificity : # of correct ‘0’ s over all actual ‘0’ s. \(\frac{TN}{A0}\) = \(\frac{TN}{TN+FP}\)
- Precision: # of correct ‘1’ s over all predicted ‘1’ s. \(\frac{TP}{P1}\) = \(\frac{TP}{TP+FP}\)
- F-score: \(\frac{2\times precision \
\times\ recall }{precision + recall}\)
Naive Bayes Classifier
\(X: X_1,X_2,...X_p\)
Predicted label is \(Y\)
Bayes theory: \[
P(Y|X) = \frac{P(X|Y)P(Y)}{P(X)}
\]
Naive
Bayes: (ignore the dependence)
\[
P(X_1,X_2,...X_p|Y) = P(X_1|Y)P(X_2|Y)...P(X_P|Y) \\
\] \[
P(Y=1|X_1,X_2,..X_p) = \frac{P(X_1,X_2,...X_p|Y=1)
P(Y=1)}{P(X_1)P(X_2)...P(X_p)} \\
P(Y=0|X_1,X_2,..X_p) = \frac{P(X_1,X_2,...X_p|Y=0)
P(Y=0)}{P(X_1)P(X_2)...P(X_p)}
\] and \(P(Y=1|X)P(X) + P(Y=0|X)P(X) =
1\)
if the Variable is numerical, we use PDF.
\[
PDF= f(x|\mu,\sigma^2) =
\frac{1}{\sqrt{2\pi\sigma^2}}e^{-\frac{(x-\mu)^2}{2\sigma^2}}
\] \[
Pr(X|Y=1)=
\frac{1}{\sqrt{2\pi\sigma_{y=1}^2}}e^{-\frac{(X-\mu_{y=1})^2}{2\sigma_{y=1}^2}}
\\
Pr(X|Y=0)=
\frac{1}{\sqrt{2\pi\sigma_{y=0}^2}}e^{-\frac{(X-\mu_{y=0})^2}{2\sigma_{y=0}^2}}
\\
\]
KNN
KNN dose not require training. All of the methods that needs to
calculate the distance, requires normalization.
Estimates conditional distribution of y given x and then classifies a
given observation to the class with highest probability.
Step 1: Pick integer K.
Step 2: for \(x_0\) (test observation),
identify K points in the data that are closet to the \(x_0\) (\(N_0\)).
Step3: Estimate the conditional probability for each class j, as the
fraction of points, in \(N_0\), whose
response values equal to j. \[
Pr(y=j|X=x_0) = \frac{1}{K} \sum_{i\in N_0} (I(y_i=j))
\] Step4: Apply bayes rule, classifiy to the class with larger
probability.
Resampling Methods
Resampling methods: Draw samples from a training set, to fit the same
statistical method multiple times using different subset of the training
data.
Resampling Methods:
1. Validation Set Approach
2. Cross Validation
3. Bootstrap
- Evaluating models performance -> model assessment
- Selecting the proper level of complexity -> model selection
Validation Set Approach
We explore the use of the validation set approach in order to
estimate the test error rates that result from fitting various linear
models on the Auto data set.
- test error rate can be highly variable
- only a subset of the observations are used to fit the model
Leave-One-Out Cross-Validation (LOOCV)
LOOCV has a couple of major advantages:
- First, it has far less bias.
- Second,there is no randomness in the training/validation set
splits.
drawbacks:
- expensive to implement
- very time consuming
- uses too much computational power
LOOCV is a very general method, and can be used with any kind of
predictive modeling.
K-Fold Cross-Validation
k-fold CV. This approach involves randomly dividing the set of
observations into k groups, or folds, of approximately equal size.
LOOCV is a special case of k-fold CV in which k is set to equal
n.
advantages:
- The most obvious advantage is computational.
there is some variability in the CV, But this variability is
typically much lower than the variability in the test error estimates
that results from the validation set approach
CV can be used for model selection : find the location of the minimum
point in the estimated test MSE curve.
\[
CV_{k} = \frac{1}{k} \sum_{i=1}^k {MSE_k}
\] \[
CV_{k} = \frac{1}{k} \sum_{i=1}^k {Err_k}
\] where \(Err_k = I(Y_i \ne \hat
Y)\).
Bootstrap
Randomly select, with replacement, n obs from training dataset.
invest in \(X,Y\) (there is some
variability). We want: \[
minimize \ Var(\alpha X+(1-\alpha)Y) \\
minimize \ \hat \alpha = \frac{\hat \sigma_Y^2 - \hat \sigma_{XY}}{\hat
\sigma_X^2+\hat \sigma_Y^2-2\hat \sigma_{XY}}
\] where: \(\hat \sigma_Y^2 = Var(Y),
\hat \sigma_X^2 = Var(X),\hat \sigma_{XY} = Cov(X,Y)\) we
estimate \(\alpha\) using historical
data (train data).
the bootstrap approach allows us to use a computer to emulate the
process of obtaining new sample sets, so that we can estimate the
variability of ˆα without generating additional samples.
Rather than repeatedly obtaining independent data sets from the
population, we instead obtain distinct data sets by repeatedly sampling
observations from the original data set.
Tree Based Methods
Decision Tree: Classification Tree + Regression Tree
Logic: Segment the predictor space into a number of Simple Rectangle
Regions.
- Decision Tree Based methods are simple and useful for
interpretation.
- Begging, Random Forest, Boosting produces multiple tree then combine
them to yield a single consensus prediction.
Regression Tree
The goal is to find rectangles (boxes) \(R_1,R_2,...R_J\) that minimizes the RSS
given by:
\[
RSS = \sum_{j=1}^J \sum_{i \in R_J} (y_i - \hat y_{Rj})^2
\] \(R_1,R_2,R_3...\) - terminal
nodes, leaf nodes.
\(\hat y_{Rj}\) mean response for the
training observations within \(j\)th
Rectangle (terminal node).
Recursive Binary Splitting (Greedy):
Pick \(X_j\) and the cut pint \(s\), so that it will devide the area to :
\(R_1 = \{X|X_j <s\}\) and \(R_2 = \{X|X_j \ge s \}\) . \[
RSS_{R_1} = \sum_{i \in R_1} (y_i - \hat y_{i})^2 \\
RSS_{R_2} = \sum_{i \in R_2} (y_i - \hat y_{i})^2 \\
\text{total RSS from this split}\ RSS = RSS_{R_1} + RSS_{R_2}
\]
and we seek the value of \(X_j\) and
\(s\) that minimize
the
total RSS.
We use RSS a method to pick \(X_j\)
when split.
Classification Tree
Instead of RSS, in classification tree we use impurety measure to
pick the \(X_j\) that minimizes the
impurity.
impurity measures are: \[
\text{error rate} \ E=1-\underset{k}{max} (\hat p_k) \\
\text{Gini index} \ G=1-\sum_{k=1}^mp_k^2 \\
\text{Entropy} \ E=-\sum_{k=1}^m p_k log_2(p_k)\\
\text{Deviance} \ D=-2\sum_{k=1}^m n_k ln(p_k)\\
\] \(p_k\) -> propertion of
the training obs belong to class m.
\(n_k\) -> number of training obs
belong to class m.
When the values are smaller, much better (much pure)
Tree Pruning
The trees might overfit, this is because the resulting tree might be
too complex. Smaller tree with fewer splits ( fewer regions) might led
to:
- lower variance
- better interpretation ( at the cost of a little bit bias)
Build a Large Tree \(T_0\) ->
Prune -> Sub Tree \(T\).
How do we determind the best way to prune the tree? Intuitivly our
goal is to select a sub tree that leads to the lowest test error rate
(with cv let’s say).
A sequence of Trees indexed by a non negative tuning parameter \(\alpha\), for each value of \(\alpha\) corresponds a sub tree \(T \in T_o\) such that: \[
\sum_{m=1}^{|T|} \sum_{i:i\in R_m} (y_i-\hat y_{R_m})2 + \alpha |T|
\]
\(|T|\) # of terminal nodes of the
tree T. \(R_m\) is the rectangle
corresponding to the \(m\)th terminal
node. \(\hat y_{R_m}\) is the predicted
response associated with R_m.
when \(\alpha\) increases there is a
price to pay for having a tree with many terminal nodes.
we can select a value of \(\alpha\)
using a validation set or using CV approach then return to the full data
set and obtain the subtree with corresponding \(\alpha\) or tree size.
Ansemble methods : Begging, RF, Boosting
An enseble method is an approach that combines many simple “building
block” models in order to obtain a single and potentially very powerful
model.
for Beg,RF,Boost those building block is the “regression or
classification tree”.
Begging
Bootstrap Aggregation or Begging is a general purpose procedure for
reducing the variance of a statistical learning method.
Averaging a set of observation, reduces variance.
Begging: We use Bootstrap, take repeated samples from the single
training data set so that we generate B different Bootstrapped training
dataset, and we do aggregation (build a separate prediction model using
each training set and average the resulting predictions) \[
\hat f_{bag(x)} = \frac{1}{B} \sum_{b=1}^B \hat f_b(x)
\] begging can improve predictions.
- Split Data: \(D\) -> \(D_T\), \(D_V\), \(len(D_T)=B\)
- Bootstrap: \(DT\) -> \(B_1,B_2,B_3,...B_B\)
- Train: \(B_1 -> \hat
f_1\),…,\(B_B -> \hat
f_B\)
- Predict(CV/OOB): \(\hat f_1 -> \hat
y_1\),…,\(\hat f_B -> \hat
y_B\)
- Aggregate: \(\hat y =
\frac{1}{B}\sum_b^B\hat y_b\) or \(\hat
y =\text{Majority Vote}\)
Begging = Bootstrapping + Aggregation
ADV: - averaging reduces variance. - test error rate is lower than
test error rate of single tree
OOB-Error
It turns out that there is a very strightforward way to estimate the
test error of a begged model, without the need to perform CV.
Each bagged tree \(B_b\) makes use
of around 2/3 of the observations. Remaining 1/3 of the observations not
used to fit a given bagged tree are referred to as the out-of-bag
observations.
So we can use OOB observations for testing, when number of B is
sufficiently large, OOB error is visually equivelent to LOOCV error.
OOB error testing is better because is uses observations that model
has not seen to test the model.
Variable Importance
Bagging: - ADV: Improve accuracy than single tree - DAV: Difficult to
interpret.
VarIMP: - On regression: For each bag, we record the amount of RSS
decrease due to split over a given predictor, then we take average on
all B trees. - On classification: For each bag, we record the amount of
Impurity decrease due to split over a given predictor, then we take
average on all B trees.
Random Forest
Random Forest provides an improvment over bagged tree by a way of a
small teak – that decorrelates the tree.
In RF, a fresh sample of m predictors is taken randomly on each
split. typically \(m=\sqrt{p}\). RF
eliminates the affects of very strong predictors by randomly picking
inoput predictors.
If there is strong predictors, then almost in all B trees , will use
this predictor to split the tree, resulting tees are very much
correlated.
averaging many highly correlated quantities dose not lead to as large
of reduction in variance.
RF: adds a step tp decorrelates the tree. RF: reduction in both test
error and OOB-error over bagging. Bagging,RF: will not overfit if we
increase number of B.
- Split Data: \(D\) -> \(D_T\), \(D_V\), \(len(D_T)=B\)
- Bootstrap: \(DT\) -> \(B_1,B_2,B_3,...B_B\)
- Decorrelate X: rnd from \(\{X_1,X_2,...X_p\}\) pick \(\{X_1,X_2,...X_m\}\).
- Train: \(B_1 -> \hat
f_1\),…,\(B_B -> \hat
f_B\)
- Predict(CV/OOB): \(\hat f_1 -> \hat
y_1\),…,\(\hat f_B -> \hat
y_B\)
- Aggregate: \(\hat y =
\frac{1}{B}\sum_b^B\hat y_b\) or \(\hat
y =\text{Majority Vote}\)
Boosting
Yet another approach for improving the predictions resuylting from a
decision tree.
bagging involves creating multiple copies of the original training
data set using the bootstrap, fitting a separate decision tree to each
copy, and then combining all of the trees in order to create a single
predictive model.
trees are grown sequentially : each tree is grown using information
from previously grown trees. Boosting does not involve bootstrap
sampling; instead each tree is fit on a modified version of the original
data set.
Boosting: - learns slow, with stumps (weak learner) - fit a tree
using the current residuals rather than the outcome Y, we then add this
new decision tree into fitted function in order to update the
residuals.
\[
\hat f(x) = \hat f(x) + \lambda \hat f_b(x) \\
r_i <- r_i - \lambda \hat f_b (x_i) \\
\hat f(x)=\sum_{b-1}^B(\lambda \hat f_b(x))
\] 1. Unlike bagging and random forest, Boosting can overfit if B
is too large. 2. Shrinkage controlls the learning rate (lamda) 3. Often
we split the each tree to stumps ( each involves onlya single
variable)
Using stumps leads to additive model.
LS0tCnRpdGxlOiAiTVQtUmV2aWV3IEdlbmVyaWMiCm91dHB1dDogaHRtbF9ub3RlYm9vawpkYXRlOiAyMDIzLTA1LTA4CmF1dGhvcjogQXphdAotLS0KCiMjIEdlbmVyYWwgCgpTdGF0aXN0aWNhbCBMZWFybmluZyAoRGF0YSBtaW5pbmcpIG1ldGhvZHMgY2FuIGJlIGNsYXNzaWZpZWQgYXMgYHN1cGVydmlzZWRgIG9yIGB1bnN1cGVydmlzZWQuYCAgICAgCgokWCQgLT4gcHJlZGljdG9ycywgaW5kZXBlbmRlbnQgdmFyaWFibGVzLCBmZWF0dXJlcywgdmFyaWFibGVzLiAgCiRZJCAtPiByZXNwb25zZSwgZGVwZW5kZW50IHZhcmlhYmxlLiAgICAKJFggPSAoWF8xLFhfMiwuLi4sWF9wKSQgYW5kICRZJCAtPiAkWSA9IGYoWCkgKyBcZXBzaWxvbiQsCiRcZXBzaWxvbiQgaXMgYSByYW5kb20gZXJyb3IgdGVybSBhbmQgaGFzIG1lYW4gemVyby4gRGF0YSBtaW5pbmcgcmVmZXJzIHRvIGEgc2V0IG9mIGFwcHJvYWNoZXMgdG8gZXN0aW1hdGUgJGYkLiAgICAKCldlIGVzdGltYXRlICRmJCB0byA6ICAgICAgICAgCjEuIHByZWRpY3Rpb24uICRcaGF0IFkgPSBcaGF0IGYoWCkkICAgCjIuIGluZmVyZW5jZS4gKCBsZWFybiB0aGUgcmVsYXRpb25zaGlwICkgICAgCgpUaGUgYWNjdXJhY3kgb2YgJFxoYXQgWSQgYXMgYSBwcmVkaWN0aW9uIGZvciAkWSQgZGVwZW5kcyBvbjogICAgCjEuIHJlZHVjaWJsZSBlcnJvciAgICAKMi4gaXJyZWR1Y2libGUgZXJyb3IgICAgCiFbXShhc3NldHMvZXJyb3ItcmVkLWlyci5wbmcpICAgICAKCmBvdmVyZml0dGluZ2AgLT4gSXQgaXMgYW4gdW5kZXNpcmFibGUgc2l0dWF0aW9uIGJlY2F1c2UKdGhlIGZpdCBvYnRhaW5lZCB3aWxsIG5vdCB5aWVsZCBhY2N1cmF0ZSBlc3RpbWF0ZXMgb2YgdGhlIHJlc3BvbnNlIG9uIG5ldyBvYnNlcnZhdGlvbnMgdGhhdCB3ZXJlIG5vdCBwYXJ0IG9mIHRoZSBvcmlnaW5hbCB0cmFpbmluZyBkYXRhIHNldC4KCiMjIyBUcmFkZS1PZmYgYmV0d2VlbiBQcmVkaWN0aW9uIEFjY3VyYWN5IGFuZCBNb2RlbCBJbnRlcnByZXRhYmlsaXR5IAoKYERUYCBpcyBnb29kIGZvciBpbnRlcnByZXRpbmcuICAgIApgQmFnZ2luZ2AsIGBCb29zdGluZ2AsIGBSRmAgaGFzIGhpZ2hlciBBY2N1cmFjeSwgaGFyZCB0byBpbnRlcnByZXQuCgojIyMgU3VwZXJ2aXNlZCB2cyBVbnN1cGVydmlzZWQKLSBgc3VwZXJ2aXNlZGAgLSBmb3IgZWFjaCBvYnNlcnZhdGlvbiBvZiB0aGUgcHJlZGljdG9yIG1lYXN1cmVtZW50KHMpICR4X2ksIGk9MSwuLi5uJCB0aGVyZSBpcyBhbiBhc3NvY2lhdGVkIHJlc3BvbnNlIG1lYXN1cmVtZW50ICR5X2kkIC0+IHByZWRpY3QgJFkkIG9yIGxlYXJuIHJlbGF0aW9uc2hpcCBiZXR3ZWVuICRYJCBhbmQgJFkkIC4KLSBgdW5zdXBlcnZpc2VkYCAtIGZvciBlYWNoIG9ic2VydmF0aW9ucyAkeF9pLCBpPTEsLi4ubiQgd2Ugb2JzZXJ2ZSBhIHZlY3RvciBvZiBtZWFzdXJlbWVudHMgJHhfaSQgYnV0ICoqbm8qKiBhc3NvY2lhdGVkIHJlc3BvbnNlICR5X2kkIC0+IHVuZGVyc3RhbmQgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlICRYX2kkcyBvciBvYnNlcnZhdGlvbnMuICAgICAKCiMjIyBSZWdyZXNzaW9uIHZzIENsYXNzaWZpY2F0aW9uICAgIApgcmVncmVzc2lvbmAgLT4gcXVhbnRpdGF0aXZlIHJlc3BvbnNlLCBudW1lcmljYWwgcmVzcG9uc2UgICAKYGNsYXNzaWZpY2F0aW9uYCAtPiBxdWFsaXRhdGl2ZSByZXNwb25zZSwgY2F0ZWdvcmljYWwgcmVzcG9uc2UgIAoKIyMjIE1vZGVsIEFjY3VyYWN5CgojIyMjIFJlZ3Jlc3Npb24KCiQkCk1TRSA9IFxmcmFjezF9e259IFxzdW1fe2k9MX1ebiB7KHlfaSAtIFxoYXQgZih4X2kpKV4yfQokJAp3aGVyZSAkXGhhdCBmKHhfaSkgLT4gXGhhdCB5X2kkICh0aGUgcHJlZGljdGlvbikuCgp3ZSBhcmUgaW50ZXJlc3RlZCBpbiB0aGUgYWNjdXJhY3kgb2YgdGhlIHByZWRpY3Rpb25zIHRoYXQgd2Ugb2J0YWluIHdoZW4gd2UgYXBwbHkgb3VyIG1ldGhvZCB0byBwcmV2aW91c2x5IHVuc2VlbiB0ZXN0IGRhdGEuIHRoZXJlIGlzIG5vIGd1YXJhbnRlZSB0aGF0IHRoZSBtZXRob2Qgd2l0aCB0aGUgbG93ZXN0IHRyYWluaW5nIE1TRSB3aWxsIGFsc28gaGF2ZSB0aGUgbG93ZXN0IHRlc3QgTVNFLiAgIAoKV2hlbiBhIGdpdmVuIG1ldGhvZCB5aWVsZHMgYSBzbWFsbCB0cmFpbmluZyBNU0UgYnV0IGEgbGFyZ2UgdGVzdCBNU0UsIHdlIGFyZSBzYWlkIHRvIGJlIGBvdmVyZml0dGluZyB0aGUgZGF0YWAuICAgIAoKQ3Jvc3MtVmFsaWRhdGlvbiAoQ1YpIGNhbiBiZSB1c2VkIHRvICoqZXN0aW1hdGUqKiB0aGUgdGVzdCBNU0Ugb24gdGhlIHRyYWluaW5nIGRhdGEuCgojIyMjIENsYXNzaWZpY2F0aW9uCgpFcnJvciByYXRlOgokJAplcnJvciByYXRlID0gXGZyYWN7MX17bn0gXHN1bV97aT0xfV5uIHt5X2kgXG5lIFxoYXQgeV9pfQokJApCYXllcyBDbGFzc2lmaWVyOiAKJCQKUHIoWT1rfFg9eCkgXFwKUHIoWT0xfFg9eCkgPiAwLjUgXCBcdGhlcmVmb3JlIGs9MQokJApLTk4gCiQkClByKFk9anxYPXhfMCkgPSBcZnJhY3sxfXtLfSBcc3VtX3tpXGluIE5fMH17SSh5X2k9ail9CiQkCiROXzAkIC0+IEsgcG9pbnRzIGluIHRoZSB0cmFpbmluZyBkYXRhIHRoYXQgYXJlIGNsb3NldCB0byAkeF8wJCAKCiMjIyBUaGUgQmlhcy1WYXJpYW5jZSBUcmFuZGUtT2ZmIAoKRXhwZWN0ZWQgdGVzdCBNU0UgZm9yIGEgZ2l2ZW4gdmFsdWUgJHhfMCQgY2FuIGJlIGdpdmVuIGFzOgohW10oYXNzZXRzL2V4cC1lcnIucG5nKSAgIAoKSW4gb3JkZXIgdG8gbWluaW1pemUgdGhlIGV4cGVjdGVkIHRlc3QgZXJyb3IsCndlIG5lZWQgdG8gc2VsZWN0IGEgc3RhdGlzdGljYWwgbGVhcm5pbmcgbWV0aG9kIHRoYXQgc2ltdWx0YW5lb3VzbHkgYWNoaWV2ZXMgYGxvdyB2YXJpYW5jZWAgYW5kIGBsb3cgYmlhc2AuICAgIAotIGBWYXJpYW5jZWAgLT4gVmFyaWFuY2UgcmVmZXJzIHRvIHRoZSBhbW91bnQgYnkgd2hpY2ggJFxoYXQgZiQgd291bGQgY2hhbmdlIGlmIHdlIGVzdGltYXRlZCBpdCB1c2luZyBhIGRpZmZlcmVudCB0cmFpbmluZyBkYXRhIHNldC4gKGR1ZSB0byByYW5kb21uZXNzIG9uIGRhdGEpIAotIGBCaWFzYCAtPiBiaWFzIHJlZmVycyB0byB0aGUgZXJyb3IgdGhhdCBpcyBpbnRyb2R1Y2VkIGJ5IGFwcHJveGltYXRpbmcgYSByZWFsLWxpZmUgcHJvYmxlbSwgd2hpY2ggbWF5IGJlIGV4dHJlbWVseSBjb21wbGljYXRlZCwgYnkgYSBtdWNoIHNpbXBsZXIgbW9kZWwuIChkdWUgdG8gc2ltcGxpZmljYXRpb24pIAoKbW9kZWwgaXMgdG9vIHNpbXBsZSAtPiBoaWdoIGJpYXMgKGp1c3QgdXNlIHNldmVyYWwgJFhfaSQpICAgCm1vZGVsIGlzIHRvbyBjb21wbGV4IC0+IGxvdyBiaWFzICh1c2UgdG9vIG11Y2ggJFhfaSQsIG92ZXJmaXR0aW5nKSAgICAKCiMjIENsYXNzaWZpY2F0aW9uIAoKUmVzcG9uc2UgdmFyaWFibGUgaXMgcXVhbGl0YXRpdmUuICAgCnNpbXBsZTogICAgCi0gTmFpdmUgQmF5ZXMgICAKLSBLTk4KCmNvbXB1dGVyIGludGVuc2l2ZTogICAKICAtIERUICAgIAogIC0gQmVnZ2luZyAgIAogIC0gUkYgICAgCiAgLSBCb29zdGluZyAgICAKCiMjIyBDb25mdXNpb24gTWF0cml4ICAgIAohW10oYXNzZXRzL2NtLnBuZykKCi0gQWNjdXJhY3k6IHJhdGlvIG9mIGNvcnJlY3QgcHJlZGljdGlvbnMgb3ZlciBhbGwgYWN0dWFsIG9icy4gJFxmcmFje1RQK1ROfXtBMCtBMX0kID0gJFxmcmFje1RQK1ROfXtQMCtQMX0kIAotIFNlbnNpdGl2aXR5PVJlY2FsbD1UcnVlIFBvc2l0aXZlIFJhdGU6ICMgb2YgY29ycmVjdCAnMScgcyBvdmVyIGFsbCBhY3R1YWwgJzEncy4gJFxmcmFje1RQfXtBMX0kID0gJFxmcmFje1RQfXtUUCtGTn0kLiAgIAotIFNwZWNpZmljaXR5IDogIyBvZiBjb3JyZWN0ICcwJyBzIG92ZXIgYWxsIGFjdHVhbCAnMCcgcy4gJFxmcmFje1ROfXtBMH0kID0gJFxmcmFje1ROfXtUTitGUH0kICAKLSBQcmVjaXNpb246ICMgb2YgY29ycmVjdCAnMScgcyBvdmVyIGFsbCBwcmVkaWN0ZWQgJzEnIHMuICRcZnJhY3tUUH17UDF9JCA9ICRcZnJhY3tUUH17VFArRlB9JCAKLSBGLXNjb3JlOiAkXGZyYWN7Mlx0aW1lcyBwcmVjaXNpb24gXCBcdGltZXNcICByZWNhbGwgfXtwcmVjaXNpb24gKyByZWNhbGx9JCAgCgojIyMgTmFpdmUgQmF5ZXMgQ2xhc3NpZmllciAKJFg6IFhfMSxYXzIsLi4uWF9wJCAgClByZWRpY3RlZCBsYWJlbCBpcyAkWSQgIAoKQmF5ZXMgdGhlb3J5OiAKJCQKUChZfFgpID0gXGZyYWN7UChYfFkpUChZKX17UChYKX0KJCQKCmBOYWl2ZWAgQmF5ZXM6IChpZ25vcmUgdGhlIGRlcGVuZGVuY2UpICAgIAokJApQKFhfMSxYXzIsLi4uWF9wfFkpID0gUChYXzF8WSlQKFhfMnxZKS4uLlAoWF9QfFkpIFxcCiQkCiQkClAoWT0xfFhfMSxYXzIsLi5YX3ApID0gXGZyYWN7UChYXzEsWF8yLC4uLlhfcHxZPTEpIFAoWT0xKX17UChYXzEpUChYXzIpLi4uUChYX3ApfSBcXApQKFk9MHxYXzEsWF8yLC4uWF9wKSA9IFxmcmFje1AoWF8xLFhfMiwuLi5YX3B8WT0wKSBQKFk9MCl9e1AoWF8xKVAoWF8yKS4uLlAoWF9wKX0gCiQkCmFuZCAkUChZPTF8WClQKFgpICsgUChZPTB8WClQKFgpID0gMSQgCgppZiB0aGUgVmFyaWFibGUgaXMgbnVtZXJpY2FsLCB3ZSB1c2UgUERGLiAKCiQkClBERj0gZih4fFxtdSxcc2lnbWFeMikgPSBcZnJhY3sxfXtcc3FydHsyXHBpXHNpZ21hXjJ9fWVeey1cZnJhY3soeC1cbXUpXjJ9ezJcc2lnbWFeMn19CiQkCiQkClByKFh8WT0xKT0gXGZyYWN7MX17XHNxcnR7MlxwaVxzaWdtYV97eT0xfV4yfX1lXnstXGZyYWN7KFgtXG11X3t5PTF9KV4yfXsyXHNpZ21hX3t5PTF9XjJ9fSBcXApQcihYfFk9MCk9IFxmcmFjezF9e1xzcXJ0ezJccGlcc2lnbWFfe3k9MH1eMn19ZV57LVxmcmFjeyhYLVxtdV97eT0wfSleMn17MlxzaWdtYV97eT0wfV4yfX0gXFwKJCQKCiMjIyBLTk4KCktOTiBkb3NlIG5vdCByZXF1aXJlIHRyYWluaW5nLiAKQWxsIG9mIHRoZSBtZXRob2RzIHRoYXQgbmVlZHMgdG8gY2FsY3VsYXRlIHRoZSBkaXN0YW5jZSwgcmVxdWlyZXMgbm9ybWFsaXphdGlvbi4KCkVzdGltYXRlcyBjb25kaXRpb25hbCBkaXN0cmlidXRpb24gb2YgeSBnaXZlbiB4IGFuZCB0aGVuIGNsYXNzaWZpZXMgYSBnaXZlbiBvYnNlcnZhdGlvbiB0byB0aGUgY2xhc3Mgd2l0aCBoaWdoZXN0IHByb2JhYmlsaXR5LgoKU3RlcCAxOiBQaWNrIGludGVnZXIgSy4gIApTdGVwIDI6IGZvciAkeF8wJCAodGVzdCBvYnNlcnZhdGlvbiksIGlkZW50aWZ5IEsgcG9pbnRzIGluIHRoZSBkYXRhIHRoYXQgYXJlIGNsb3NldCB0byB0aGUgJHhfMCQgKCROXzAkKS4gICAgClN0ZXAzOiBFc3RpbWF0ZSB0aGUgY29uZGl0aW9uYWwgcHJvYmFiaWxpdHkgZm9yIGVhY2ggY2xhc3MgaiwgYXMgdGhlIGZyYWN0aW9uIG9mIHBvaW50cywgaW4gJE5fMCQsIHdob3NlIHJlc3BvbnNlIHZhbHVlcyBlcXVhbCB0byBqLgokJApQcih5PWp8WD14XzApID0gXGZyYWN7MX17S30gXHN1bV97aVxpbiBOXzB9IChJKHlfaT1qKSkKJCQKU3RlcDQ6IEFwcGx5IGJheWVzIHJ1bGUsIGNsYXNzaWZpeSB0byB0aGUgY2xhc3Mgd2l0aCBsYXJnZXIgcHJvYmFiaWxpdHkuCgohW10oYXNzZXRzL2tubi5wbmcpCgojIyBSZXNhbXBsaW5nIE1ldGhvZHMgICAKClJlc2FtcGxpbmcgbWV0aG9kczogRHJhdyBzYW1wbGVzIGZyb20gYSB0cmFpbmluZyBzZXQsIHRvIGZpdCB0aGUgc2FtZSBzdGF0aXN0aWNhbCBtZXRob2QgbXVsdGlwbGUgdGltZXMgdXNpbmcgZGlmZmVyZW50IHN1YnNldCBvZiB0aGUgdHJhaW5pbmcgZGF0YS4KClJlc2FtcGxpbmcgTWV0aG9kczogICAKMS4gVmFsaWRhdGlvbiBTZXQgQXBwcm9hY2ggICAgCjIuIENyb3NzIFZhbGlkYXRpb24gICAgICAgICAKMy4gQm9vdHN0cmFwICAgICAgICAgICAKLSBFdmFsdWF0aW5nIG1vZGVscyBwZXJmb3JtYW5jZSAtPiBtb2RlbCBhc3Nlc3NtZW50ICAgIAotIFNlbGVjdGluZyB0aGUgcHJvcGVyIGxldmVsIG9mIGNvbXBsZXhpdHkgLT4gbW9kZWwgc2VsZWN0aW9uIAoKIyMjIFZhbGlkYXRpb24gU2V0IEFwcHJvYWNoCgpXZSBleHBsb3JlIHRoZSB1c2Ugb2YgdGhlIHZhbGlkYXRpb24gc2V0IGFwcHJvYWNoIGluIG9yZGVyIHRvIGVzdGltYXRlIHRoZQp0ZXN0IGVycm9yIHJhdGVzIHRoYXQgcmVzdWx0IGZyb20gZml0dGluZyB2YXJpb3VzIGxpbmVhciBtb2RlbHMgb24gdGhlIEF1dG8KZGF0YSBzZXQuCgohW10oYXNzZXRzL3ZhbC1zZXQucG5nKSAgICAgICAgIAoKLSB0ZXN0IGVycm9yIHJhdGUgY2FuIGJlIGhpZ2hseSB2YXJpYWJsZQotIG9ubHkgYSBzdWJzZXQgb2YgdGhlIG9ic2VydmF0aW9ucyBhcmUgdXNlZCB0byBmaXQgdGhlIG1vZGVsCgojIyMgTGVhdmUtT25lLU91dCBDcm9zcy1WYWxpZGF0aW9uIChMT09DVikgICAgCgpMT09DViBoYXMgYSBjb3VwbGUgb2YgbWFqb3IgKiphZHZhbnRhZ2VzKio6CgogLSBGaXJzdCwgaXQgaGFzIGZhciBsZXNzIGJpYXMuICAgCiAtIFNlY29uZCx0aGVyZSBpcyBubyByYW5kb21uZXNzIGluIHRoZSB0cmFpbmluZy92YWxpZGF0aW9uCnNldCBzcGxpdHMuICAgICAKCioqZHJhd2JhY2tzKio6CgotIGV4cGVuc2l2ZSB0byBpbXBsZW1lbnQKLSB2ZXJ5IHRpbWUgY29uc3VtaW5nCi0gdXNlcyB0b28gbXVjaCBjb21wdXRhdGlvbmFsIHBvd2VyCgpMT09DViBpcyBhIHZlcnkgZ2VuZXJhbCBtZXRob2QsIGFuZCBjYW4gYmUgdXNlZCB3aXRoIGFueSBraW5kIG9mCnByZWRpY3RpdmUgbW9kZWxpbmcuCgohW10oYXNzZXRzL2xvb2N2LnBuZykgIAoKIyMjIEstRm9sZCBDcm9zcy1WYWxpZGF0aW9uICAgCgprLWZvbGQgQ1YuIFRoaXMgYXBwcm9hY2ggaW52b2x2ZXMgcmFuZG9tbHkgZGl2aWRpbmcgdGhlIHNldCBvZiBvYnNlcnZhdGlvbnMgaW50byBrIGdyb3Vwcywgb3IgZm9sZHMsIG9mIGFwcHJveGltYXRlbHkgZXF1YWwgc2l6ZS4gCgpMT09DViBpcyBhIHNwZWNpYWwgY2FzZSBvZiBrLWZvbGQgQ1YgaW4gd2hpY2ggayBpcyBzZXQgdG8gZXF1YWwgbi4gCgoqKmFkdmFudGFnZXM6KiogCgotIFRoZSBtb3N0IG9idmlvdXMgYWR2YW50YWdlIGlzIGNvbXB1dGF0aW9uYWwuCgoKdGhlcmUgaXMgc29tZSB2YXJpYWJpbGl0eSBpbiB0aGUgQ1YsIEJ1dCB0aGlzIHZhcmlhYmlsaXR5IGlzIHR5cGljYWxseQptdWNoIGxvd2VyIHRoYW4gdGhlIHZhcmlhYmlsaXR5IGluIHRoZSB0ZXN0IGVycm9yIGVzdGltYXRlcyB0aGF0IHJlc3VsdHMgZnJvbQp0aGUgdmFsaWRhdGlvbiBzZXQgYXBwcm9hY2ggCgoKQ1YgY2FuIGJlIHVzZWQgZm9yIG1vZGVsIHNlbGVjdGlvbiA6IGZpbmQgdGhlIGxvY2F0aW9uIG9mIHRoZSBtaW5pbXVtIHBvaW50IGluIHRoZSBlc3RpbWF0ZWQgdGVzdCBNU0UgY3VydmUuCgoKJCQKQ1Zfe2t9ID0gXGZyYWN7MX17a30gXHN1bV97aT0xfV5rIHtNU0Vfa30KJCQKJCQKQ1Zfe2t9ID0gXGZyYWN7MX17a30gXHN1bV97aT0xfV5rIHtFcnJfa30gCiQkCndoZXJlICRFcnJfayA9IEkoWV9pIFxuZSBcaGF0IFkpJC4gICAgCgojIyMgQm9vdHN0cmFwICAgCgpSYW5kb21seSBzZWxlY3QsIHdpdGggcmVwbGFjZW1lbnQsIG4gb2JzIGZyb20gdHJhaW5pbmcgZGF0YXNldC4gCmludmVzdCBpbiAkWCxZJCAodGhlcmUgaXMgc29tZSB2YXJpYWJpbGl0eSkuIFdlIHdhbnQ6IAokJAptaW5pbWl6ZSBcIFZhcihcYWxwaGEgWCsoMS1cYWxwaGEpWSkgXFwKbWluaW1pemUgXCBcaGF0IFxhbHBoYSA9IFxmcmFje1xoYXQgXHNpZ21hX1leMiAtIFxoYXQgXHNpZ21hX3tYWX19e1xoYXQgXHNpZ21hX1heMitcaGF0IFxzaWdtYV9ZXjItMlxoYXQgXHNpZ21hX3tYWX19CiQkCndoZXJlOiAkXGhhdCBcc2lnbWFfWV4yID0gVmFyKFkpLCBcaGF0IFxzaWdtYV9YXjIgPSBWYXIoWCksXGhhdCBcc2lnbWFfe1hZfSA9IENvdihYLFkpJCAKd2UgZXN0aW1hdGUgJFxhbHBoYSQgdXNpbmcgaGlzdG9yaWNhbCBkYXRhICh0cmFpbiBkYXRhKS4gCiFbXShhc3NldHMvYm9vdHN0cmFwLnBuZykKCnRoZSBib290c3RyYXAgYXBwcm9hY2ggYWxsb3dzIHVzCnRvIHVzZSBhIGNvbXB1dGVyIHRvIGVtdWxhdGUgdGhlIHByb2Nlc3Mgb2Ygb2J0YWluaW5nIG5ldyBzYW1wbGUgc2V0cywKc28gdGhhdCB3ZSBjYW4gZXN0aW1hdGUgdGhlIHZhcmlhYmlsaXR5IG9mIMuGzrEgd2l0aG91dCBnZW5lcmF0aW5nIGFkZGl0aW9uYWwKc2FtcGxlcy4KClJhdGhlciB0aGFuIHJlcGVhdGVkbHkgb2J0YWluaW5nIGluZGVwZW5kZW50IGRhdGEgc2V0cyBmcm9tIHRoZQpwb3B1bGF0aW9uLCB3ZSBpbnN0ZWFkIG9idGFpbiBkaXN0aW5jdCBkYXRhIHNldHMgYnkgcmVwZWF0ZWRseSBzYW1wbGluZwpvYnNlcnZhdGlvbnMgZnJvbSB0aGUgb3JpZ2luYWwgZGF0YSBzZXQuCgojIyBUcmVlIEJhc2VkIE1ldGhvZHMgCgpEZWNpc2lvbiBUcmVlOiBDbGFzc2lmaWNhdGlvbiBUcmVlICsgUmVncmVzc2lvbiBUcmVlICAgIApMb2dpYzogU2VnbWVudCB0aGUgcHJlZGljdG9yIHNwYWNlIGludG8gYSBudW1iZXIgb2YgU2ltcGxlIFJlY3RhbmdsZSBSZWdpb25zLgoKLSBEZWNpc2lvbiBUcmVlIEJhc2VkIG1ldGhvZHMgYXJlIHNpbXBsZSBhbmQgdXNlZnVsIGZvciBpbnRlcnByZXRhdGlvbi4gCi0gQmVnZ2luZywgUmFuZG9tIEZvcmVzdCwgQm9vc3RpbmcgcHJvZHVjZXMgbXVsdGlwbGUgdHJlZSB0aGVuIGNvbWJpbmUgdGhlbSB0byB5aWVsZCBhIHNpbmdsZSBjb25zZW5zdXMgcHJlZGljdGlvbi4gICAgCgojIyMgUmVncmVzc2lvbiBUcmVlIAoKVGhlIGdvYWwgaXMgdG8gZmluZCByZWN0YW5nbGVzIChib3hlcykgJFJfMSxSXzIsLi4uUl9KJCB0aGF0IG1pbmltaXplcyB0aGUgUlNTIGdpdmVuIGJ5OgoKJCQKUlNTID0gXHN1bV97aj0xfV5KIFxzdW1fe2kgXGluIFJfSn0gKHlfaSAtIFxoYXQgeV97Ump9KV4yCiQkCiRSXzEsUl8yLFJfMy4uLiQgLSB0ZXJtaW5hbCBub2RlcywgbGVhZiBub2Rlcy4gICAgCiRcaGF0IHlfe1JqfSQgbWVhbiByZXNwb25zZSBmb3IgdGhlIHRyYWluaW5nIG9ic2VydmF0aW9ucyB3aXRoaW4gJGokdGggUmVjdGFuZ2xlICh0ZXJtaW5hbCBub2RlKS4gICAKClJlY3Vyc2l2ZSBCaW5hcnkgU3BsaXR0aW5nIChHcmVlZHkpOiAgICAKUGljayAkWF9qJCBhbmQgdGhlIGN1dCBwaW50ICRzJCwgc28gdGhhdCBpdCB3aWxsIGRldmlkZSB0aGUgYXJlYSB0byA6ICAgJFJfMSA9IFx7WHxYX2ogPHNcfSQgIGFuZCAkUl8yID0gXHtYfFhfaiBcZ2UgcyBcfSQgLgokJApSU1Nfe1JfMX0gPSBcc3VtX3tpIFxpbiBSXzF9ICh5X2kgLSBcaGF0IHlfe2l9KV4yIFxcClJTU197Ul8yfSA9IFxzdW1fe2kgXGluIFJfMn0gKHlfaSAtIFxoYXQgeV97aX0pXjIgXFwKXHRleHR7dG90YWwgUlNTIGZyb20gdGhpcyBzcGxpdH1cIFJTUyA9IFJTU197Ul8xfSArIFJTU197Ul8yfQokJAoKYW5kIHdlIHNlZWsgdGhlIHZhbHVlIG9mICRYX2okIGFuZCAkcyQgdGhhdCBgbWluaW1pemVgIHRoZSB0b3RhbCBSU1MuICAgIAoKV2UgdXNlIFJTUyBhIG1ldGhvZCB0byBwaWNrICRYX2okIHdoZW4gc3BsaXQuCgojIyMgQ2xhc3NpZmljYXRpb24gVHJlZSAKCkluc3RlYWQgb2YgUlNTLCBpbiBjbGFzc2lmaWNhdGlvbiB0cmVlIHdlIHVzZSBpbXB1cmV0eSBtZWFzdXJlIHRvIHBpY2sgdGhlICRYX2okIHRoYXQgbWluaW1pemVzIHRoZSBpbXB1cml0eS4KCmltcHVyaXR5IG1lYXN1cmVzIGFyZTogCiQkClx0ZXh0e2Vycm9yIHJhdGV9IFwgRT0xLVx1bmRlcnNldHtrfXttYXh9IChcaGF0IHBfaykgXFwKXHRleHR7R2luaSBpbmRleH0gXCBHPTEtXHN1bV97az0xfV5tcF9rXjIgXFwKXHRleHR7RW50cm9weX0gXCBFPS1cc3VtX3trPTF9Xm0gcF9rIGxvZ18yKHBfaylcXApcdGV4dHtEZXZpYW5jZX0gXCBEPS0yXHN1bV97az0xfV5tIG5fayBsbihwX2spXFwKJCQKJHBfayQgLT4gcHJvcGVydGlvbiBvZiB0aGUgdHJhaW5pbmcgb2JzIGJlbG9uZyB0byBjbGFzcyBtLiAgICAKJG5fayQgLT4gbnVtYmVyIG9mIHRyYWluaW5nIG9icyBiZWxvbmcgdG8gY2xhc3MgbS4KCldoZW4gdGhlIHZhbHVlcyBhcmUgc21hbGxlciwgbXVjaCBiZXR0ZXIgKG11Y2ggcHVyZSkKCiMjIyBUcmVlIFBydW5pbmcgICAgCgpUaGUgdHJlZXMgbWlnaHQgb3ZlcmZpdCwgdGhpcyBpcyBiZWNhdXNlIHRoZSByZXN1bHRpbmcgdHJlZSBtaWdodCBiZSB0b28gY29tcGxleC4gClNtYWxsZXIgdHJlZSB3aXRoIGZld2VyIHNwbGl0cyAoIGZld2VyIHJlZ2lvbnMpIG1pZ2h0IGxlZCB0bzogICAgCi0gbG93ZXIgdmFyaWFuY2UgIAotIGJldHRlciBpbnRlcnByZXRhdGlvbiAoIGF0IHRoZSBjb3N0IG9mIGEgbGl0dGxlIGJpdCBiaWFzKQoKQnVpbGQgYSBMYXJnZSBUcmVlICRUXzAkIC0+IFBydW5lIC0+IFN1YiBUcmVlICRUJC4gCgpIb3cgZG8gd2UgZGV0ZXJtaW5kIHRoZSBiZXN0IHdheSB0byBwcnVuZSB0aGUgdHJlZT8gSW50dWl0aXZseSBvdXIgZ29hbCBpcyB0byBzZWxlY3QgYSBzdWIgdHJlZSB0aGF0IGxlYWRzIHRvIHRoZSBsb3dlc3QgdGVzdCBlcnJvciByYXRlICh3aXRoIGN2IGxldCdzIHNheSkuIAoKQSBzZXF1ZW5jZSBvZiBUcmVlcyBpbmRleGVkIGJ5IGEgbm9uIG5lZ2F0aXZlIHR1bmluZyBwYXJhbWV0ZXIgJFxhbHBoYSQsIGZvciBlYWNoIHZhbHVlIG9mICRcYWxwaGEkIGNvcnJlc3BvbmRzIGEgc3ViIHRyZWUgJFQgXGluIFRfbyQgIHN1Y2ggdGhhdDogCiQkClxzdW1fe209MX1ee3xUfH0gXHN1bV97aTppXGluIFJfbX0gKHlfaS1caGF0IHlfe1JfbX0pMiArIFxhbHBoYSB8VHwKJCQKCiR8VHwkICMgb2YgdGVybWluYWwgbm9kZXMgb2YgdGhlIHRyZWUgVC4KJFJfbSQgaXMgdGhlIHJlY3RhbmdsZSBjb3JyZXNwb25kaW5nIHRvIHRoZSAkbSR0aCB0ZXJtaW5hbCBub2RlLgokXGhhdCB5X3tSX219JCBpcyB0aGUgcHJlZGljdGVkIHJlc3BvbnNlIGFzc29jaWF0ZWQgd2l0aCBSX20uCgp3aGVuICRcYWxwaGEkIGluY3JlYXNlcyB0aGVyZSBpcyBhIHByaWNlIHRvIHBheSBmb3IgaGF2aW5nIGEgdHJlZSB3aXRoIG1hbnkgdGVybWluYWwgbm9kZXMuCgp3ZSBjYW4gc2VsZWN0IGEgdmFsdWUgb2YgJFxhbHBoYSQgdXNpbmcgYSB2YWxpZGF0aW9uIHNldCBvciB1c2luZyBDViBhcHByb2FjaCB0aGVuIHJldHVybiB0byB0aGUgZnVsbCBkYXRhIHNldCBhbmQgb2J0YWluIHRoZSBzdWJ0cmVlIHdpdGggY29ycmVzcG9uZGluZyAkXGFscGhhJCBvciB0cmVlIHNpemUuCgojIyMgQW5zZW1ibGUgbWV0aG9kcyA6IEJlZ2dpbmcsIFJGLCBCb29zdGluZyAKQW4gZW5zZWJsZSBtZXRob2QgaXMgYW4gYXBwcm9hY2ggdGhhdCBjb21iaW5lcyBtYW55IHNpbXBsZSAiYnVpbGRpbmcgYmxvY2siIG1vZGVscyBpbiBvcmRlciB0byBvYnRhaW4gYSBzaW5nbGUgYW5kIHBvdGVudGlhbGx5IHZlcnkgcG93ZXJmdWwgbW9kZWwuCgpmb3IgQmVnLFJGLEJvb3N0IHRob3NlIGJ1aWxkaW5nIGJsb2NrIGlzIHRoZSAicmVncmVzc2lvbiBvciBjbGFzc2lmaWNhdGlvbiB0cmVlIi4gCgojIyMgQmVnZ2luZyAKCkJvb3RzdHJhcCBBZ2dyZWdhdGlvbiBvciBCZWdnaW5nIGlzIGEgZ2VuZXJhbCBwdXJwb3NlIHByb2NlZHVyZSBmb3IgcmVkdWNpbmcgdGhlIHZhcmlhbmNlIG9mIGEgc3RhdGlzdGljYWwgbGVhcm5pbmcgbWV0aG9kLgoKQXZlcmFnaW5nIGEgc2V0IG9mIG9ic2VydmF0aW9uLCByZWR1Y2VzIHZhcmlhbmNlLgoKQmVnZ2luZzogV2UgdXNlIEJvb3RzdHJhcCwgdGFrZSByZXBlYXRlZCBzYW1wbGVzIGZyb20gdGhlIHNpbmdsZSB0cmFpbmluZyBkYXRhIHNldCBzbyB0aGF0IHdlIGdlbmVyYXRlIEIgZGlmZmVyZW50IEJvb3RzdHJhcHBlZCB0cmFpbmluZyBkYXRhc2V0LCBhbmQgd2UgZG8gYWdncmVnYXRpb24gKGJ1aWxkIGEgc2VwYXJhdGUgcHJlZGljdGlvbiBtb2RlbCB1c2luZyBlYWNoIHRyYWluaW5nIHNldCBhbmQgYXZlcmFnZSB0aGUgcmVzdWx0aW5nIHByZWRpY3Rpb25zKQokJApcaGF0IGZfe2JhZyh4KX0gPSBcZnJhY3sxfXtCfSBcc3VtX3tiPTF9XkIgXGhhdCBmX2IoeCkgCiQkCmJlZ2dpbmcgY2FuIGltcHJvdmUgcHJlZGljdGlvbnMuCgoxLiBTcGxpdCBEYXRhOiAkRCQgLT4gJERfVCQsICREX1YkLCAkbGVuKERfVCk9QiQKMi4gQm9vdHN0cmFwOiAkRFQkIC0+ICRCXzEsQl8yLEJfMywuLi5CX0IkCjMuIFRyYWluOiAkQl8xIC0+IFxoYXQgZl8xJCwuLi4sJEJfQiAtPiBcaGF0IGZfQiQKNC4gUHJlZGljdChDVi9PT0IpOiAkXGhhdCBmXzEgLT4gXGhhdCB5XzEkLC4uLiwkXGhhdCBmX0IgLT4gXGhhdCB5X0IkCjUuIEFnZ3JlZ2F0ZTogJFxoYXQgeSA9IFxmcmFjezF9e0J9XHN1bV9iXkJcaGF0IHlfYiQgb3IgJFxoYXQgeSA9XHRleHR7TWFqb3JpdHkgVm90ZX0kCgpCZWdnaW5nID0gQm9vdHN0cmFwcGluZyArIEFnZ3JlZ2F0aW9uIAoKQURWOiAKLSBhdmVyYWdpbmcgcmVkdWNlcyB2YXJpYW5jZS4gCi0gdGVzdCBlcnJvciByYXRlIGlzIGxvd2VyIHRoYW4gdGVzdCBlcnJvciByYXRlIG9mIHNpbmdsZSB0cmVlCgojIyMjIE9PQi1FcnJvcgpJdCB0dXJucyBvdXQgdGhhdCB0aGVyZSBpcyBhIHZlcnkgc3RyaWdodGZvcndhcmQgd2F5IHRvIGVzdGltYXRlIHRoZSB0ZXN0IGVycm9yIG9mIGEgYmVnZ2VkIG1vZGVsLCB3aXRob3V0IHRoZSBuZWVkIHRvIHBlcmZvcm0gQ1YuCgpFYWNoIGJhZ2dlZCB0cmVlICRCX2IkIG1ha2VzIHVzZSBvZiBhcm91bmQgMi8zIG9mIHRoZSBvYnNlcnZhdGlvbnMuIFJlbWFpbmluZyAxLzMgb2YgdGhlIG9ic2VydmF0aW9ucyBub3QgdXNlZCB0byBmaXQgYSBnaXZlbiBiYWdnZWQgdHJlZSBhcmUgcmVmZXJyZWQgdG8gYXMgdGhlIG91dC1vZi1iYWcgb2JzZXJ2YXRpb25zLgoKU28gd2UgY2FuIHVzZSBPT0Igb2JzZXJ2YXRpb25zIGZvciB0ZXN0aW5nLCB3aGVuIG51bWJlciBvZiBCIGlzIHN1ZmZpY2llbnRseSBsYXJnZSwgT09CIGVycm9yIGlzIHZpc3VhbGx5IGVxdWl2ZWxlbnQgdG8gTE9PQ1YgZXJyb3IuCgpPT0IgZXJyb3IgdGVzdGluZyBpcyBiZXR0ZXIgYmVjYXVzZSBpcyB1c2VzIG9ic2VydmF0aW9ucyB0aGF0IG1vZGVsIGhhcyBub3Qgc2VlbiB0byB0ZXN0IHRoZSBtb2RlbC4KCiMjIyMgVmFyaWFibGUgSW1wb3J0YW5jZSAKCkJhZ2dpbmc6IAotIEFEVjogSW1wcm92ZSBhY2N1cmFjeSB0aGFuIHNpbmdsZSB0cmVlCi0gREFWOiBEaWZmaWN1bHQgdG8gaW50ZXJwcmV0LiAKClZhcklNUDoKLSBPbiByZWdyZXNzaW9uOiBGb3IgZWFjaCBiYWcsIHdlIHJlY29yZCB0aGUgYW1vdW50IG9mIFJTUyBkZWNyZWFzZSBkdWUgdG8gc3BsaXQgb3ZlciBhIGdpdmVuIHByZWRpY3RvciwgdGhlbiB3ZSB0YWtlIGF2ZXJhZ2Ugb24gYWxsIEIgdHJlZXMuCi0gT24gY2xhc3NpZmljYXRpb246IEZvciBlYWNoIGJhZywgd2UgcmVjb3JkIHRoZSBhbW91bnQgb2YgSW1wdXJpdHkgZGVjcmVhc2UgZHVlIHRvIHNwbGl0IG92ZXIgYSBnaXZlbiBwcmVkaWN0b3IsIHRoZW4gd2UgdGFrZSBhdmVyYWdlIG9uIGFsbCBCIHRyZWVzLgoKIyMjIFJhbmRvbSBGb3Jlc3QKClJhbmRvbSBGb3Jlc3QgcHJvdmlkZXMgYW4gaW1wcm92bWVudCBvdmVyIGJhZ2dlZCB0cmVlIGJ5IGEgd2F5IG9mIGEgc21hbGwgdGVhayAtLSB0aGF0IGRlY29ycmVsYXRlcyB0aGUgdHJlZS4KCkluIFJGLCBhIGZyZXNoIHNhbXBsZSBvZiBtIHByZWRpY3RvcnMgaXMgdGFrZW4gcmFuZG9tbHkgb24gZWFjaCBzcGxpdC4gdHlwaWNhbGx5ICRtPVxzcXJ0e3B9JC4KUkYgZWxpbWluYXRlcyB0aGUgYWZmZWN0cyBvZiB2ZXJ5IHN0cm9uZyBwcmVkaWN0b3JzIGJ5IHJhbmRvbWx5IHBpY2tpbmcgaW5vcHV0IHByZWRpY3RvcnMuICAgCgpJZiB0aGVyZSBpcyBzdHJvbmcgcHJlZGljdG9ycywgdGhlbiBhbG1vc3QgaW4gYWxsIEIgdHJlZXMgLCB3aWxsIHVzZSB0aGlzIHByZWRpY3RvciB0byBzcGxpdCB0aGUgdHJlZSwgcmVzdWx0aW5nIHRlZXMgYXJlIHZlcnkgbXVjaCBjb3JyZWxhdGVkLgoKYXZlcmFnaW5nIG1hbnkgaGlnaGx5IGNvcnJlbGF0ZWQgcXVhbnRpdGllcyBkb3NlIG5vdCBsZWFkIHRvIGFzIGxhcmdlIG9mIHJlZHVjdGlvbiBpbiB2YXJpYW5jZS4KClJGOiBhZGRzIGEgc3RlcCB0cCBkZWNvcnJlbGF0ZXMgdGhlIHRyZWUuClJGOiByZWR1Y3Rpb24gaW4gYm90aCB0ZXN0IGVycm9yIGFuZCBPT0ItZXJyb3Igb3ZlciBiYWdnaW5nLiAKQmFnZ2luZyxSRjogd2lsbCBub3Qgb3ZlcmZpdCBpZiB3ZSBpbmNyZWFzZSBudW1iZXIgb2YgQi4KCjEuIFNwbGl0IERhdGE6ICREJCAtPiAkRF9UJCwgJERfViQsICRsZW4oRF9UKT1CJAoyLiBCb290c3RyYXA6ICREVCQgLT4gJEJfMSxCXzIsQl8zLC4uLkJfQiQKMy4gRGVjb3JyZWxhdGUgWDogcm5kIGZyb20gJFx7WF8xLFhfMiwuLi5YX3BcfSQgcGljayAkXHtYXzEsWF8yLC4uLlhfbVx9JC4KMy4gVHJhaW46ICRCXzEgLT4gXGhhdCBmXzEkLC4uLiwkQl9CIC0+IFxoYXQgZl9CJAo0LiBQcmVkaWN0KENWL09PQik6ICRcaGF0IGZfMSAtPiBcaGF0IHlfMSQsLi4uLCRcaGF0IGZfQiAtPiBcaGF0IHlfQiQKNS4gQWdncmVnYXRlOiAkXGhhdCB5ID0gXGZyYWN7MX17Qn1cc3VtX2JeQlxoYXQgeV9iJCBvciAkXGhhdCB5ID1cdGV4dHtNYWpvcml0eSBWb3RlfSQKCiMjIyBCb29zdGluZyAKCllldCBhbm90aGVyIGFwcHJvYWNoIGZvciBpbXByb3ZpbmcgdGhlIHByZWRpY3Rpb25zIHJlc3V5bHRpbmcgZnJvbSBhIGRlY2lzaW9uIHRyZWUuCgpiYWdnaW5nIGludm9sdmVzIGNyZWF0aW5nIG11bHRpcGxlIGNvcGllcyBvZiB0aGUgb3JpZ2luYWwgdHJhaW5pbmcKZGF0YSBzZXQgdXNpbmcgdGhlIGJvb3RzdHJhcCwgZml0dGluZyBhIHNlcGFyYXRlIGRlY2lzaW9uIHRyZWUgdG8gZWFjaApjb3B5LCBhbmQgdGhlbiBjb21iaW5pbmcgYWxsIG9mIHRoZSB0cmVlcyBpbiBvcmRlciB0byBjcmVhdGUgYSBzaW5nbGUgcHJlZGljdGl2ZQptb2RlbC4KCnRyZWVzIGFyZQpncm93biBzZXF1ZW50aWFsbHkgOiBlYWNoIHRyZWUgaXMgZ3Jvd24gdXNpbmcgaW5mb3JtYXRpb24gZnJvbSBwcmV2aW91c2x5Cmdyb3duIHRyZWVzLiBCb29zdGluZyBkb2VzIG5vdCBpbnZvbHZlIGJvb3RzdHJhcCBzYW1wbGluZzsgaW5zdGVhZCBlYWNoCnRyZWUgaXMgZml0IG9uIGEgbW9kaWZpZWQgdmVyc2lvbiBvZiB0aGUgb3JpZ2luYWwgZGF0YSBzZXQuCgpCb29zdGluZzoKLSBsZWFybnMgc2xvdywgd2l0aCBzdHVtcHMgKHdlYWsgbGVhcm5lcikKLSBmaXQgYSB0cmVlIHVzaW5nIHRoZSBjdXJyZW50IHJlc2lkdWFscyByYXRoZXIgdGhhbiB0aGUgb3V0Y29tZSBZLCB3ZSB0aGVuIGFkZCB0aGlzIG5ldyBkZWNpc2lvbiB0cmVlIGludG8gZml0dGVkIGZ1bmN0aW9uIGluIG9yZGVyIHRvIHVwZGF0ZSB0aGUgcmVzaWR1YWxzLiAgICAKJCQKXGhhdCBmKHgpID0gXGhhdCBmKHgpICsgXGxhbWJkYSBcaGF0IGZfYih4KSBcXApyX2kgPC0gcl9pIC0gXGxhbWJkYSBcaGF0IGZfYiAoeF9pKSBcXApcaGF0IGYoeCk9XHN1bV97Yi0xfV5CKFxsYW1iZGEgXGhhdCBmX2IoeCkpCiQkCjEuIFVubGlrZSBiYWdnaW5nIGFuZCByYW5kb20gZm9yZXN0LCBCb29zdGluZyBjYW4gb3ZlcmZpdCBpZiBCIGlzIHRvbyBsYXJnZS4KMi4gU2hyaW5rYWdlIGNvbnRyb2xscyB0aGUgbGVhcm5pbmcgcmF0ZSAobGFtZGEpCjMuIE9mdGVuIHdlIHNwbGl0IHRoZSBlYWNoIHRyZWUgdG8gc3R1bXBzICggZWFjaCBpbnZvbHZlcyBvbmx5YSBzaW5nbGUgdmFyaWFibGUpCgpVc2luZyBzdHVtcHMgbGVhZHMgdG8gYWRkaXRpdmUgbW9kZWwuCgoK