1 Introduction
This project builds a data-driven framework to identify which
customers are most likely to respond to a direct-mail promotion for a
regional clothing retailer. This project uses the Clothing Store
Dataset—a real dataset from a New England retail chain. I first explore
purchasing, engagement, and account-history patterns to understand data
quality, distributional shape, and relationships among key variables.
Based on those findings, I prepare the data by recoding the response,
addressing skewed predictors with appropriate transformations, and
checking for redundancy among highly correlated shopping-activity
measures.
With the data curated, I develop a series of logistic regression
models to link customer characteristics to response propensity. I
compare a comprehensive “larger” specification to a more parsimonious
“reduced” alternative, using variance inflation factors to monitor
multicollinearity and cross-validation to select among candidates on
predictive grounds. The analysis plan includes a train/test split for
honest out-of-sample evaluation, threshold-based classification metrics
(e.g., accuracy/PE), and clear interpretation of effect sizes through
odds ratios. The goal is not just to fit a model, but to produce a
transparent, defensible approach that a marketing team could use to
prioritize outreach and improve campaign efficiency.
Research Question: Can customer purchasing and
engagement behaviors be used to predict whether a customer will respond
to a direct-mail marketing promotion?
2 Description of Dataset
These are 20 explanatory variables in this data set: 1. HHKEY
(categorical) → Unique encrypted customer ID 2. ZIP_CODE (categorical) →
Customer’s ZIP code 3. FRE (numerical) → Number of purchase visits 4.
MON (numerical) → Total net sales 5. AVRG (numerical) → Average spend
per visit 6. AMSPEND, PSSPEND, CSSPEND, AXSPEND (categorical) → Spend
across four different franchise brands 7. OMONSPEND, TMONSPEND, SMOSPEND
(categorical) → Spend over past 1, 3, and 6 months 8. PREVPD
(categorical) → Spend in the same period last year 9. GMP (numerical) →
Gross margin percentage 10. PROMOS (numerical) → Number of marketing
promotions on file 11. DAYS (numerical) → Number of days customer has
been on file 12. FREDAYS, LTFREDAY (categorical) → Time between
purchases (recent & lifetime average) 13. CLASSES (numerical) →
Number of different product classes purchased 14. STYLES (numerical) →
Number of individual items purchased 15. STORES (numerical) → Number of
stores shopped at 16. MARKDOWN, COUPONS, MAILED, RESPONDE, RESPONSERATE
(categorical) → Promotion and discount engagement 17. HI (numerical) →
Product uniformity (lower = more diverse purchases) 18. CLUSTYPE
(categorical) → Lifestyle cluster type (encrypted) 19. PERCRET
(numerical) → Percent of returns 20. CC_CARD, VALPHON, WEB (categorical)
→ Flags for credit card, valid phone number, and web shopper status
Our response variable is:
RESP → whether a customer responded to a promotion (yes/no)
The dataset originates from the customer relationship management
system of a regional New England clothing retailer. It includes
transactional, demographic, and behavioral information used for targeted
marketing analysis. Each record represents an individual customer and
their corresponding promotional response. We have 2847 observations, or
customers, in this dataset. We will now remove all observations with
missing values.
CSDS_clean <- na.omit(CSDS)
response <- factor(CSDS_clean$RESP, levels = c("no","yes"))
After removing missing values, 2619 customers remain for
modeling.
3 Exploratory Data Analysis
We will make a correlation matrix with all of the numerical variables
to see if any variables are highly correlated with each other. We will
be dropping the categorical variables because they are all either
redundant to what we have with the numerical variables, or are
irrelevant to the question.
vars <- c("FRE","MON", "AVRG","GMP","PROMOS","DAYS","CLASSES","STYLES","STORES","HI","PERCRET")
vars <- intersect(vars, names(CSDS_clean))
cor_mat <- cor(CSDS_clean[ , vars, drop = FALSE],
use = "pairwise.complete.obs",
method = "pearson")
cor_mat
FRE MON AVRG GMP PROMOS
FRE 1.0000000 0.674209463 -0.152217058 -0.114920260 0.46902853
MON 0.6742095 1.000000000 0.271555910 0.038859950 0.38456147
AVRG -0.1522171 0.271555910 1.000000000 0.287400964 0.04592048
GMP -0.1149203 0.038859950 0.287400964 1.000000000 0.05949538
PROMOS 0.4690285 0.384561473 0.045920482 0.059495381 1.00000000
DAYS 0.3910812 0.261051031 -0.122708281 -0.021326578 0.60409827
CLASSES 0.7948576 0.675174039 0.087937020 -0.105308252 0.52413518
STYLES 0.7931651 0.935759837 0.135948828 -0.076199344 0.40263287
STORES 0.5909190 0.430123659 -0.088488953 -0.103484318 0.37306720
HI -0.4323462 -0.309591043 -0.002372335 0.150835861 -0.33013811
PERCRET 0.1559934 0.009115226 -0.180623484 -0.007074185 0.04475647
DAYS CLASSES STYLES STORES HI
FRE 0.39108118 0.79485761 0.79316506 0.59091903 -0.432346183
MON 0.26105103 0.67517404 0.93575984 0.43012366 -0.309591043
AVRG -0.12270828 0.08793702 0.13594883 -0.08848895 -0.002372335
GMP -0.02132658 -0.10530825 -0.07619934 -0.10348432 0.150835861
PROMOS 0.60409827 0.52413518 0.40263287 0.37306720 -0.330138107
DAYS 1.00000000 0.40606251 0.29344949 0.32782601 -0.277643174
CLASSES 0.40606251 1.00000000 0.75321727 0.60280152 -0.619839913
STYLES 0.29344949 0.75321727 1.00000000 0.51226171 -0.360716264
STORES 0.32782601 0.60280152 0.51226171 1.00000000 -0.414095001
HI -0.27764317 -0.61983991 -0.36071626 -0.41409500 1.000000000
PERCRET 0.03418407 0.10271670 0.06785920 0.09372079 -0.252625218
PERCRET
FRE 0.155993396
MON 0.009115226
AVRG -0.180623484
GMP -0.007074185
PROMOS 0.044756473
DAYS 0.034184072
CLASSES 0.102716699
STYLES 0.067859197
STORES 0.093720788
HI -0.252625218
PERCRET 1.000000000
Pairwise correlations reveal strong relationships among purchasing
activity variables. For example, FRE (visits) correlates highly with
STYLES (items purchased) and CLASSES (product classes), and MON (net
sales) correlates very strongly with STYLES. These patterns are
intuitive; customers who shop more often tend to buy more items across
more classes, leading to higher sales. We retain these variables
initially and address redundancy later during model refinement.
We will now conduct frequency distributions for all of the numerical
variables to identify any patterns and skewness.
par(mfrow=c(1,2))
hist(CSDS_clean$FRE, xlab="# of Purchase Visits", main = "")
hist(CSDS_clean$MON, xlab="Total Net Sales", main = "")

hist(CSDS_clean$AVRG, xlab="Average Spend Per Visit", main = "")
hist(CSDS_clean$GMP, xlab="Gross Margin %", main = "")

hist(CSDS_clean$PROMOS, xlab="# of Marketing Promos", main = "")
hist(CSDS_clean$DAYS, xlab="Days on File", main = "")

hist(CSDS_clean$CLASSES, xlab="# of Different Products Purchased", main = "")
hist(CSDS_clean$STYLES, xlab="# of Individual Items Purchased", main = "")

hist(CSDS_clean$STORES, xlab="# of Stores Shopped At", main = "")
hist(CSDS_clean$HI, xlab="Product Uniformity", main = "")

hist(CSDS_clean$PERCRET, xlab="% of Returns", main = "")

None of our variables are distributed normally. Number of purchase
visits, Total Net Sales, Average Spend Per Visit, Number of Marketing
Promos, Number of Different Products Purchased, Number of Individual
Items Purchased, Number of Stores Shopped At, Product Uniformity, and
Percent of Returns are all skewed to the right. Gross Margin Percentage
and Days on File are skewed left. We will apply appropriate
transformations (log1p() and qlogis()) prior to modeling. But, we will
not be discretizing the variables because they are all significantly
skewed. We will also not be standardizing the variables because log1p()
and qlogis() handle the issue of skewness and nonlinear
relationships.
4 Data Split - Training and Testing Data
We first split the data into 70% training and 30% testing. All
transformations, feature selection, and model tuning are performed only
on the training set to avoid data leakage. The test set remains
untouched and is used once at the end to estimate out-of-sample
performance.
## splitting data: 70% training and 30% testing
n <- dim(CSDS_clean)[1]
train.n <- round(0.7*n)
train.id <- sample(1:n, train.n, replace = FALSE)
## training and testing data sets
train <- CSDS_clean[train.id, ]
test <- CSDS_clean[-train.id, ]
5 Data Transformation and Candidate Models
In this section, we transform the training data to address skewness
and then develop candidate logistic regression models, comparing them on
fit and parsimony before settling on a final specification.
5.2 Larger Model
We begin with a larger model containing all major transformed
numerical predictors to capture the full set of potential drivers of
response.
larger <- glm( RESP ~ MON_log + FRE_log + STYLES_log + CLASSES_log + STORES_log + HI_log + PERCRET_logit + PROMOS + DAYS + GMP, data = train_dat, family = binomial )
summary(larger)
Call:
glm(formula = RESP ~ MON_log + FRE_log + STYLES_log + CLASSES_log +
STORES_log + HI_log + PERCRET_logit + PROMOS + DAYS + GMP,
family = binomial, data = train_dat)
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) -3.1999993 0.9678648 -3.306 0.000946 ***
MON_log -0.0065322 0.2574462 -0.025 0.979757
FRE_log 1.4237810 0.2445699 5.822 5.83e-09 ***
STYLES_log 0.5900700 0.3271112 1.804 0.071250 .
CLASSES_log -0.4153607 0.3824896 -1.086 0.277506
STORES_log 0.0390271 0.2368922 0.165 0.869144
HI_log -0.2155549 0.2210891 -0.975 0.329576
PERCRET_logit -0.0187766 0.0281758 -0.666 0.505150
PROMOS -0.0374719 0.0152068 -2.464 0.013734 *
DAYS -0.0008740 0.0005152 -1.697 0.089783 .
GMP -0.6675410 0.5612068 -1.189 0.234253
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 1535.9 on 1832 degrees of freedom
Residual deviance: 1229.4 on 1822 degrees of freedom
AIC: 1251.4
Number of Fisher Scoring iterations: 5
The initial logistic regression model predicts the likelihood that a
customer responds to a marketing promotion based on a comprehensive set
of purchasing, engagement, and demographic variables. This model
includes ten predictors: MON_log, FRE_log, STYLES_log, CLASSES_log,
STORES_log, HI_log, PERCRET_logit, PROMOS, DAYS, and GMP.
FRE_log (β = 1.42, p < .001): Each one-unit increase
multiplies the odds of response by about 4.1 times.
PROMOS (β = –0.037, p = .014): Each additional promotion slightly
reduces response odds (≈ –4%).
STYLES_log (β = 0.59, p = .07): Positive but marginally
significant.
All other predictors are not statistically significant (p >
.10).
The model’s residual deviance (1229.4) and AIC (1251.4) reflect a
strong overall fit relative to the null deviance (1535.9). However,
multicollinearity diagnostics revealed inflated VIF values among several
purchasing activity variables, such as MON_log, CLASSES_log, and
STYLES_log. To address redundancy and improve interpretability, a
reduced model was developed containing only the key predictors —
FRE_log, PROMOS, and STYLES_log — which produced a more parsimonious and
stable model without loss of explanatory power. Before shortening our
model, let’s see if there is multicollinearity within our predictor
variables. We will run a VIF matrix.
MON_log FRE_log STYLES_log CLASSES_log STORES_log
12.044901 5.518902 15.808105 9.951538 1.519444
HI_log PERCRET_logit PROMOS DAYS GMP
3.555838 2.066177 2.270283 1.862572 1.704003
Variance inflation factors (VIF) reveal substantial multicollinearity
among purchase-activity variables—especially STYLES_log (≈15.8), MON_log
(≈12.0), and CLASSES_log (≈10.0)—which mirrors the very high
correlations observed earlier (e.g., MON–STYLES ≈ 0.94, FRE–STYLES ≈
0.79). Because several of these variables are not statistically
significant once frequency is included, we remove redundant predictors
and proceed to a reduced model that improves interpretability and
numerical stability.
5.3 Reduced Model
Guided by significance and multicollinearity diagnostics, the reduced
model focuses on the key predictors FRE_log, PROMOS, and STYLES_log.
reduced <- glm(
RESP ~ FRE_log + PROMOS + STYLES_log,
data = train_dat, family = binomial
)
summary(reduced)
Call:
glm(formula = RESP ~ FRE_log + PROMOS + STYLES_log, family = binomial,
data = train_dat)
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) -4.57821 0.24982 -18.326 < 2e-16 ***
FRE_log 1.35110 0.21459 6.296 3.05e-10 ***
PROMOS -0.05475 0.01302 -4.205 2.61e-05 ***
STYLES_log 0.45571 0.16893 2.698 0.00698 **
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 1535.9 on 1832 degrees of freedom
Residual deviance: 1236.3 on 1829 degrees of freedom
AIC: 1244.3
Number of Fisher Scoring iterations: 5
The final logistic regression model predicts the likelihood that a
customer responds to a marketing promotion based on purchase frequency
(FRE_log), number of promotions (PROMOS), and number of unique items
purchased (STYLES_log).
FRE_log (β = 1.35, p < .001): A one-unit increase in
log-transformed purchase frequency multiplies the odds of response by
approximately 3.9× (e¹·³⁵ ≈ 3.86).
PROMOS (β = –0.055, p < .001): Each additional promotion on
file slightly reduces the odds of response by about 5% (e⁻⁰·⁰⁵⁵ ≈
0.95).
STYLES_log (β = 0.46, p = .007): A one-unit increase in
log-transformed styles purchased increases the odds of response by
roughly 1.6× (e⁰·⁴⁶ ≈ 1.58).
The model’s residual deviance (1236.3) and AIC (1244.3) represent a
strong improvement over the null deviance (1535.9), confirming good
model fit. Overall, this reduced model is parsimonious, statistically
robust, and interpretable, highlighting that shopping frequency and
purchase diversity are strong positive predictors of promotional
response, while excessive promotion frequency slightly dampens it.
FRE_log PROMOS STYLES_log
4.286025 1.656890 4.286738
All three VIF values are below 5, meaning multicollinearity is no
longer a serious issue.
6 Cross-Validation for Best Model Identification
Here, we use 5-fold cross validation to make sure our data set has
enough observations, or customers.
## 5-fold cross-validation on TRAINING DATA (train_dat) ## Requires: library(MASS); library(pander) set.seed(123)
k <- 5
fold.size <- floor(nrow(train_dat) / k)
# Keep columns so '.' in formula means exactly these predictors
train_cols <- c("RESP","MON_log","FRE_log","STYLES_log","CLASSES_log", "STORES_log","HI_log","PERCRET_logit","PROMOS","DAYS","GMP")
PE1 <- numeric(k) # full
PE2 <- numeric(k) # stepAIC (forward)
PE3 <- numeric(k) # reduced
for (i in 1:k) {
# Validation and training folds (simple contiguous folds)
valid.id <- (fold.size*(i-1)+1):(fold.size*i)
valid <- train_dat[valid.id, train_cols, drop = FALSE]
train_cv <- train_dat[-valid.id, train_cols, drop = FALSE]
## full model (matches your larger spec)
larger <- glm( RESP ~ MON_log + FRE_log + STYLES_log + CLASSES_log + STORES_log + HI_log + PERCRET_logit + PROMOS + DAYS + GMP, data = train_cv, family = binomial )
## reduced model (your trio)
reduced <- glm( RESP ~ FRE_log + PROMOS + STYLES_log,data = train_cv, family = binomial )
## forward step between reduced (lower) and full (upper)
model2 <- MASS::stepAIC( larger, scope = list(lower = formula(reduced), upper = formula(larger)), direction = "forward", trace = 0 )
## predicted probabilities on validation fold
pred01 <- predict(larger, newdata = valid, type = "response")
pred02 <- predict(model2, newdata = valid, type = "response")
pred03 <- predict(reduced, newdata = valid, type = "response")
## classify with threshold 0.4 (to match your template)
yhat01 <- ifelse(pred01 > 0.4, "yes", "no")
yhat02 <- ifelse(pred02 > 0.4, "yes", "no")
yhat03 <- ifelse(pred03 > 0.4, "yes", "no")
## misclassification error vs true RESP
PE1[i] <- mean(yhat01 != as.character(valid$RESP))
PE2[i] <- mean(yhat02 != as.character(valid$RESP))
PE3[i] <- mean(yhat03 != as.character(valid$RESP)) }
avg.pe <- cbind(PE.1_Full = mean(PE1),
PE.2_Step = mean(PE2),
PE.3_Reduced = mean(PE3))
pander::pander(avg.pe, caption = "5-fold CV: Average prediction errors (lower is better)")
5-fold CV: Average prediction errors (lower is
better)
| 0.1454 |
0.1454 |
0.1448 |
In 5-fold CV on the training data, prediction errors were 0.1454
(full), 0.1454 (stepwise), and 0.1448 (reduced), indicating comparable
performance; we select the reduced model for its slightly lower error
and improved interpretability.
7 Conclusion
The purpose of this project was to determine which customer
characteristics most effectively predict response to a direct-mail
marketing promotion. Through exploratory analysis, we found that
purchasing behavior variables—such as purchase frequency, number of
styles purchased, and total sales—were highly correlated and strongly
skewed. To improve model stability, these predictors were
log-transformed, and redundant variables were removed based on both
multicollinearity (VIF) and statistical insignificance.
Two logistic regression models were evaluated: a larger model
including all transformed numeric predictors, and a reduced model
focusing on the most meaningful predictors (FRE_log, STYLES_log, and
PROMOS). Both models achieved similar predictive accuracy in 5-fold
cross-validation, with the reduced model producing the lowest average
prediction error (0.1448). Because it provided nearly identical
performance with fewer parameters and no multicollinearity concerns, the
reduced model was selected as the final specification.
The final model reveals that customers who shop more frequently and
purchase a wider variety of items are significantly more likely to
respond to a marketing promotion, while those who receive more
promotions tend to respond less, possibly due to saturation or fatigue.
Overall, this analysis successfully answers the research question: yes,
certain behavioral characteristics—especially shopping frequency and
product variety—can reliably predict whether a customer will respond to
a direct-mail promotion. These insights can guide future marketing
strategies by helping retailers better target high-engagement customers
and refine their promotional frequency for optimal impact.
LS0tDQp0aXRsZTogIk1vZGVsaW5nIEN1c3RvbWVyIEVuZ2FnZW1lbnQgaW4gUmV0YWlsIFByb21vdGlvbnMgVGhyb3VnaCBMb2dpc3RpYyBSZWdyZXNzaW9uIg0KYXV0aG9yOiAiTHVrZSBWb2xtIg0KZGF0ZTogIjIwMjUtMTAtMTAiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6ICAgICAgICAgICAjIG91dHB1dCBkb2N1bWVudCBmb3JtYXQNCiAgICB0b2M6IHllcyAgICAgICAgICAgICAgICMgYWRkIHRhYmxlIGNvbnRlbnRzDQogICAgdG9jX2Zsb2F0OiB5ZXMgICAgICAgICAjIHRvY19wcm9wZXJ0eTogZmxvYXRpbmcNCiAgICB0b2NfZGVwdGg6IDQgICAgICAgICAgICMgZGVwdGggb2YgVE9DIGhlYWRpbmdzDQogICAgZmlnX3dpZHRoOiA2ICAgICAgICAgICAjIGdsb2JhbCBmaWd1cmUgd2lkdGgNCiAgICBmaWdfaGVpZ2h0OiA0ICAgICAgICAgICMgZ2xvYmFsIGZpZ3VyZSBoZWlnaHQNCiAgICBmaWdfY2FwdGlvbjogeWVzICAgICAgICMgYWRkIGZpZ3VyZSBjYXB0aW9uDQogICAgbnVtYmVyX3NlY3Rpb25zOiBubyAgICMgbnVtYmVyaW5nIHNlY3Rpb24gaGVhZGluZ3MNCiAgICB0b2NfY29sbGFwc2VkOiB5ZXMgICAgICMgVE9DIHN1YmhlYWRpbmcgY29sbGFwc2luZw0KICAgIGNvZGVfZm9sZGluZzogaGlkZSAgICAgIyBmb2xkaW5nL3Nob3dpbmcgY29kZSANCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMgICAgICMgYWxsb3cgdG8gZG93bmxvYWQgY29tcGxldGUgUk1hcmtkb3duIHNvdXJjZSBjb2RlDQogICAgc21vb3RoX3Njcm9sbDogeWVzICAgICAjIHNjcm9sbGluZyB0ZXh0IG9mIHRoZSBkb2N1bWVudA0KICAgIHRoZW1lOiBsdW1lbiAgICAgICAgICAgIyB2aXN1YWwgdGhlbWUgZm9yIEhUTUwgZG9jdW1lbnQgb25seQ0KICAgIGhpZ2hsaWdodDogdGFuZ28gICAgICAgIyBjb2RlIHN5bnRheCBoaWdobGlnaHRpbmcgc3R5bGVzDQogIHBkZl9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICBmaWdfY2FwdGlvbjogeWVzDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgd29yZF9kb2N1bWVudDoNCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogJzQnDQotLS0NCg0KYGBge2NzcywgZWNobyA9IEZBTFNFfQ0KZGl2I1RPQyBsd2V7ICAgICAvKiB0YWJsZSBvZiBjb250ZW50ICAqLw0KICAgIGxpc3Qtc3R5bGU6dXBwZXItcm9tYW47DQogICAgYmFja2dyb3VuZC1pbWFnZTpub25lOw0KICAgIGJhY2tncm91bmQtcmVwZWF0Om5vbmU7DQogICAgYmFja2dyb3VuZC1wb3NpdGlvbjowOw0KfQ0KDQpoMS50aXRsZSB7ICAgIC8qIGxldmVsIDEgaGVhZGVyIG9mIHRpdGxlICAqLw0KICBmb250LXNpemU6IDI0cHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBjb2xvcjogRGFya1JlZDsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KDQpoNC5hdXRob3IgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICBmb250LXNpemU6IDE4cHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgY29sb3I6IERhcmtSZWQ7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCg0KaDQuZGF0ZSB7IC8qIEhlYWRlciA0IC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogIGZvbnQtc2l6ZTogMThweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICBjb2xvcjogRGFya0JsdWU7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCg0KaDEgeyAvKiBIZWFkZXIgMSAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICAgIGZvbnQtc2l6ZTogMjBweDsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogZGFya3JlZDsNCiAgICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQoNCmgyIHsgLyogSGVhZGVyIDIgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDE4cHg7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IG5hdnk7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KaDMgeyAvKiBIZWFkZXIgMyAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICAgIGZvbnQtc2l6ZTogMTZweDsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogbmF2eTsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQpoNCB7IC8qIEhlYWRlciA0IC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogICAgZm9udC1zaXplOiAxNHB4Ow0KICBmb250LXdlaWdodDogYm9sZDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogZGFya3JlZDsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQovKiBBZGQgZG90cyBhZnRlciBudW1iZXJlZCBoZWFkZXJzICovDQouaGVhZGVyLXNlY3Rpb24tbnVtYmVyOjphZnRlciB7DQogIGNvbnRlbnQ6ICIuIjsNCn0NCmBgYA0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmxpYnJhcnkocmVhZHhsKQ0KbGlicmFyeShib290KQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoa25pdHIpDQpsaWJyYXJ5KHBzeWNoKQ0KbGlicmFyeShNQVNTKQ0KbGlicmFyeSh0aWR5cikNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoY2FyKQ0KbGlicmFyeShwYW5kZXIpDQoNCiMgU2V0IHNlZWQgZm9yIHJlcHJvZHVjaWJpbGl0eQ0Kc2V0LnNlZWQoMTIzKQ0KDQojIFJlYWQgaW4gZGF0YSAoZHJvcCBmaXJzdCBjb2x1bW4gaWYgaXQncyBqdXN0IGFuIGluZGV4L0lEKQ0Kc2V0d2QoIkM6L1VzZXJzL3ZvbG0xL09uZURyaXZlL0Rlc2t0b3AvU1RBMzIxIG5ldyIpDQpDU0RTIDwtIHJlYWQuY3N2KCJDbG90aGluZyBTdG9yZSBEYXRhIFNldC5jc3YiKQ0KIyBHbG9iYWwgY2h1bmsgb3B0aW9ucw0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KA0KICBlY2hvID0gVFJVRSwgICAgICAjIHNob3cgY29kZQ0KICB3YXJuaW5nID0gRkFMU0UsICAjIHN1cHByZXNzIHdhcm5pbmdzDQogIG1lc3NhZ2UgPSBGQUxTRSwgICMgc3VwcHJlc3MgbWVzc2FnZXMNCiAgcmVzdWx0cyA9IFRSVUUsICAgIyBzaG93IHJlc3VsdHMNCiAgY29tbWVudCA9IE5BICAgICAgIyBjbGVhbmVyIG91dHB1dCAobm8gIiMjIiBwcmVmaXgpDQopDQpgYGANCg0KIyAxIEludHJvZHVjdGlvbg0KDQpUaGlzIHByb2plY3QgYnVpbGRzIGEgZGF0YS1kcml2ZW4gZnJhbWV3b3JrIHRvIGlkZW50aWZ5IHdoaWNoIGN1c3RvbWVycyBhcmUgbW9zdCBsaWtlbHkgdG8gcmVzcG9uZCB0byBhIGRpcmVjdC1tYWlsIHByb21vdGlvbiBmb3IgYSByZWdpb25hbCBjbG90aGluZyByZXRhaWxlci4gVGhpcyBwcm9qZWN0IHVzZXMgdGhlIENsb3RoaW5nIFN0b3JlIERhdGFzZXTigJRhIHJlYWwgZGF0YXNldCBmcm9tIGEgTmV3IEVuZ2xhbmQgcmV0YWlsIGNoYWluLiBJIGZpcnN0IGV4cGxvcmUgcHVyY2hhc2luZywgZW5nYWdlbWVudCwgYW5kIGFjY291bnQtaGlzdG9yeSBwYXR0ZXJucyB0byB1bmRlcnN0YW5kIGRhdGEgcXVhbGl0eSwgZGlzdHJpYnV0aW9uYWwgc2hhcGUsIGFuZCByZWxhdGlvbnNoaXBzIGFtb25nIGtleSB2YXJpYWJsZXMuIEJhc2VkIG9uIHRob3NlIGZpbmRpbmdzLCBJIHByZXBhcmUgdGhlIGRhdGEgYnkgcmVjb2RpbmcgdGhlIHJlc3BvbnNlLCBhZGRyZXNzaW5nIHNrZXdlZCBwcmVkaWN0b3JzIHdpdGggYXBwcm9wcmlhdGUgdHJhbnNmb3JtYXRpb25zLCBhbmQgY2hlY2tpbmcgZm9yIHJlZHVuZGFuY3kgYW1vbmcgaGlnaGx5IGNvcnJlbGF0ZWQgc2hvcHBpbmctYWN0aXZpdHkgbWVhc3VyZXMuDQoNCldpdGggdGhlIGRhdGEgY3VyYXRlZCwgSSBkZXZlbG9wIGEgc2VyaWVzIG9mIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWxzIHRvIGxpbmsgY3VzdG9tZXIgY2hhcmFjdGVyaXN0aWNzIHRvIHJlc3BvbnNlIHByb3BlbnNpdHkuIEkgY29tcGFyZSBhIGNvbXByZWhlbnNpdmUg4oCcbGFyZ2Vy4oCdIHNwZWNpZmljYXRpb24gdG8gYSBtb3JlIHBhcnNpbW9uaW91cyDigJxyZWR1Y2Vk4oCdIGFsdGVybmF0aXZlLCB1c2luZyB2YXJpYW5jZSBpbmZsYXRpb24gZmFjdG9ycyB0byBtb25pdG9yIG11bHRpY29sbGluZWFyaXR5IGFuZCBjcm9zcy12YWxpZGF0aW9uIHRvIHNlbGVjdCBhbW9uZyBjYW5kaWRhdGVzIG9uIHByZWRpY3RpdmUgZ3JvdW5kcy4gVGhlIGFuYWx5c2lzIHBsYW4gaW5jbHVkZXMgYSB0cmFpbi90ZXN0IHNwbGl0IGZvciBob25lc3Qgb3V0LW9mLXNhbXBsZSBldmFsdWF0aW9uLCB0aHJlc2hvbGQtYmFzZWQgY2xhc3NpZmljYXRpb24gbWV0cmljcyAoZS5nLiwgYWNjdXJhY3kvUEUpLCBhbmQgY2xlYXIgaW50ZXJwcmV0YXRpb24gb2YgZWZmZWN0IHNpemVzIHRocm91Z2ggb2RkcyByYXRpb3MuIFRoZSBnb2FsIGlzIG5vdCBqdXN0IHRvIGZpdCBhIG1vZGVsLCBidXQgdG8gcHJvZHVjZSBhIHRyYW5zcGFyZW50LCBkZWZlbnNpYmxlIGFwcHJvYWNoIHRoYXQgYSBtYXJrZXRpbmcgdGVhbSBjb3VsZCB1c2UgdG8gcHJpb3JpdGl6ZSBvdXRyZWFjaCBhbmQgaW1wcm92ZSBjYW1wYWlnbiBlZmZpY2llbmN5Lg0KDQoqKlJlc2VhcmNoIFF1ZXN0aW9uKio6IENhbiBjdXN0b21lciBwdXJjaGFzaW5nIGFuZCBlbmdhZ2VtZW50IGJlaGF2aW9ycyBiZSB1c2VkIHRvIHByZWRpY3Qgd2hldGhlciBhIGN1c3RvbWVyIHdpbGwgcmVzcG9uZCB0byBhIGRpcmVjdC1tYWlsIG1hcmtldGluZyBwcm9tb3Rpb24/DQoNCiMgMiBEZXNjcmlwdGlvbiBvZiBEYXRhc2V0DQoNClRoZXNlIGFyZSAyMCBleHBsYW5hdG9yeSB2YXJpYWJsZXMgaW4gdGhpcyBkYXRhIHNldDogDQoxLiBISEtFWSAoY2F0ZWdvcmljYWwpIOKGkiBVbmlxdWUgZW5jcnlwdGVkIGN1c3RvbWVyIElEDQoyLiBaSVBfQ09ERSAoY2F0ZWdvcmljYWwpIOKGkiBDdXN0b21lcuKAmXMgWklQIGNvZGUNCjMuIEZSRSAobnVtZXJpY2FsKSDihpIgTnVtYmVyIG9mIHB1cmNoYXNlIHZpc2l0cw0KNC4gTU9OIChudW1lcmljYWwpIOKGkiBUb3RhbCBuZXQgc2FsZXMNCjUuIEFWUkcgKG51bWVyaWNhbCkg4oaSIEF2ZXJhZ2Ugc3BlbmQgcGVyIHZpc2l0DQo2LiBBTVNQRU5ELCBQU1NQRU5ELCBDU1NQRU5ELCBBWFNQRU5EIChjYXRlZ29yaWNhbCkg4oaSIFNwZW5kIGFjcm9zcyBmb3VyIGRpZmZlcmVudCBmcmFuY2hpc2UgYnJhbmRzDQo3LiBPTU9OU1BFTkQsIFRNT05TUEVORCwgU01PU1BFTkQgKGNhdGVnb3JpY2FsKSDihpIgU3BlbmQgb3ZlciBwYXN0IDEsIDMsIGFuZCA2IG1vbnRocw0KOC4gUFJFVlBEIChjYXRlZ29yaWNhbCkg4oaSIFNwZW5kIGluIHRoZSBzYW1lIHBlcmlvZCBsYXN0IHllYXINCjkuIEdNUCAobnVtZXJpY2FsKSDihpIgR3Jvc3MgbWFyZ2luIHBlcmNlbnRhZ2UNCjEwLiBQUk9NT1MgKG51bWVyaWNhbCkg4oaSIE51bWJlciBvZiBtYXJrZXRpbmcgcHJvbW90aW9ucyBvbiBmaWxlDQoxMS4gREFZUyAobnVtZXJpY2FsKSDihpIgTnVtYmVyIG9mIGRheXMgY3VzdG9tZXIgaGFzIGJlZW4gb24gZmlsZQ0KMTIuIEZSRURBWVMsIExURlJFREFZIChjYXRlZ29yaWNhbCkg4oaSIFRpbWUgYmV0d2VlbiBwdXJjaGFzZXMgKHJlY2VudCAmIGxpZmV0aW1lIGF2ZXJhZ2UpDQoxMy4gQ0xBU1NFUyAobnVtZXJpY2FsKSDihpIgTnVtYmVyIG9mIGRpZmZlcmVudCBwcm9kdWN0IGNsYXNzZXMgcHVyY2hhc2VkDQoxNC4gU1RZTEVTIChudW1lcmljYWwpIOKGkiBOdW1iZXIgb2YgaW5kaXZpZHVhbCBpdGVtcyBwdXJjaGFzZWQNCjE1LiBTVE9SRVMgKG51bWVyaWNhbCkg4oaSIE51bWJlciBvZiBzdG9yZXMgc2hvcHBlZCBhdA0KMTYuIE1BUktET1dOLCBDT1VQT05TLCBNQUlMRUQsIFJFU1BPTkRFLCBSRVNQT05TRVJBVEUgKGNhdGVnb3JpY2FsKSDihpIgUHJvbW90aW9uIGFuZCBkaXNjb3VudCBlbmdhZ2VtZW50DQoxNy4gSEkgKG51bWVyaWNhbCkg4oaSIFByb2R1Y3QgdW5pZm9ybWl0eSAobG93ZXIgPSBtb3JlIGRpdmVyc2UgcHVyY2hhc2VzKQ0KMTguIENMVVNUWVBFIChjYXRlZ29yaWNhbCkg4oaSIExpZmVzdHlsZSBjbHVzdGVyIHR5cGUgKGVuY3J5cHRlZCkNCjE5LiBQRVJDUkVUIChudW1lcmljYWwpIOKGkiBQZXJjZW50IG9mIHJldHVybnMNCjIwLiBDQ19DQVJELCBWQUxQSE9OLCBXRUIgKGNhdGVnb3JpY2FsKSDihpIgRmxhZ3MgZm9yIGNyZWRpdCBjYXJkLCB2YWxpZCBwaG9uZSBudW1iZXIsIGFuZCB3ZWIgc2hvcHBlciBzdGF0dXMNCg0KT3VyIHJlc3BvbnNlIHZhcmlhYmxlIGlzOg0KDQpSRVNQIOKGkiB3aGV0aGVyIGEgY3VzdG9tZXIgcmVzcG9uZGVkIHRvIGEgcHJvbW90aW9uICh5ZXMvbm8pDQoNClRoZSBkYXRhc2V0IG9yaWdpbmF0ZXMgZnJvbSB0aGUgY3VzdG9tZXIgcmVsYXRpb25zaGlwIG1hbmFnZW1lbnQgc3lzdGVtIG9mIGEgcmVnaW9uYWwgTmV3IEVuZ2xhbmQgY2xvdGhpbmcgcmV0YWlsZXIuIEl0IGluY2x1ZGVzIHRyYW5zYWN0aW9uYWwsIGRlbW9ncmFwaGljLCBhbmQgYmVoYXZpb3JhbCBpbmZvcm1hdGlvbiB1c2VkIGZvciB0YXJnZXRlZCBtYXJrZXRpbmcgYW5hbHlzaXMuIEVhY2ggcmVjb3JkIHJlcHJlc2VudHMgYW4gaW5kaXZpZHVhbCBjdXN0b21lciBhbmQgdGhlaXIgY29ycmVzcG9uZGluZyBwcm9tb3Rpb25hbCByZXNwb25zZS4gV2UgaGF2ZSAyODQ3IG9ic2VydmF0aW9ucywgb3IgY3VzdG9tZXJzLCBpbiB0aGlzIGRhdGFzZXQuIFdlIHdpbGwgbm93IHJlbW92ZSBhbGwgb2JzZXJ2YXRpb25zIHdpdGggbWlzc2luZyB2YWx1ZXMuDQoNCmBgYHtyfQ0KDQpDU0RTX2NsZWFuIDwtIG5hLm9taXQoQ1NEUykNCnJlc3BvbnNlIDwtIGZhY3RvcihDU0RTX2NsZWFuJFJFU1AsIGxldmVscyA9IGMoIm5vIiwieWVzIikpDQpgYGANCg0KQWZ0ZXIgcmVtb3ZpbmcgbWlzc2luZyB2YWx1ZXMsIDI2MTkgY3VzdG9tZXJzIHJlbWFpbiBmb3IgbW9kZWxpbmcuDQoNCiMgMyBFeHBsb3JhdG9yeSBEYXRhIEFuYWx5c2lzDQoNCldlIHdpbGwgbWFrZSBhIGNvcnJlbGF0aW9uIG1hdHJpeCB3aXRoIGFsbCBvZiB0aGUgbnVtZXJpY2FsIHZhcmlhYmxlcyB0byBzZWUgaWYgYW55IHZhcmlhYmxlcyBhcmUgaGlnaGx5IGNvcnJlbGF0ZWQgd2l0aCBlYWNoIG90aGVyLiBXZSB3aWxsIGJlIGRyb3BwaW5nIHRoZSBjYXRlZ29yaWNhbCB2YXJpYWJsZXMgYmVjYXVzZSB0aGV5IGFyZSBhbGwgZWl0aGVyIHJlZHVuZGFudCB0byB3aGF0IHdlIGhhdmUgd2l0aCB0aGUgbnVtZXJpY2FsIHZhcmlhYmxlcywgb3IgYXJlIGlycmVsZXZhbnQgdG8gdGhlIHF1ZXN0aW9uLg0KDQpgYGB7cn0NCg0KdmFycyA8LSBjKCJGUkUiLCJNT04iLCAiQVZSRyIsIkdNUCIsIlBST01PUyIsIkRBWVMiLCJDTEFTU0VTIiwiU1RZTEVTIiwiU1RPUkVTIiwiSEkiLCJQRVJDUkVUIikNCnZhcnMgPC0gaW50ZXJzZWN0KHZhcnMsIG5hbWVzKENTRFNfY2xlYW4pKQ0KY29yX21hdCA8LSBjb3IoQ1NEU19jbGVhblsgLCB2YXJzLCBkcm9wID0gRkFMU0VdLA0KdXNlID0gInBhaXJ3aXNlLmNvbXBsZXRlLm9icyIsDQptZXRob2QgPSAicGVhcnNvbiIpDQpjb3JfbWF0DQoNCmBgYA0KDQpQYWlyd2lzZSBjb3JyZWxhdGlvbnMgcmV2ZWFsIHN0cm9uZyByZWxhdGlvbnNoaXBzIGFtb25nIHB1cmNoYXNpbmcgYWN0aXZpdHkgdmFyaWFibGVzLiBGb3IgZXhhbXBsZSwgRlJFICh2aXNpdHMpIGNvcnJlbGF0ZXMgaGlnaGx5IHdpdGggU1RZTEVTIChpdGVtcyBwdXJjaGFzZWQpIGFuZCBDTEFTU0VTIChwcm9kdWN0IGNsYXNzZXMpLCBhbmQgTU9OIChuZXQgc2FsZXMpIGNvcnJlbGF0ZXMgdmVyeSBzdHJvbmdseSB3aXRoIFNUWUxFUy4gVGhlc2UgcGF0dGVybnMgYXJlIGludHVpdGl2ZTsgY3VzdG9tZXJzIHdobyBzaG9wIG1vcmUgb2Z0ZW4gdGVuZCB0byBidXkgbW9yZSBpdGVtcyBhY3Jvc3MgbW9yZSBjbGFzc2VzLCBsZWFkaW5nIHRvIGhpZ2hlciBzYWxlcy4gV2UgcmV0YWluIHRoZXNlIHZhcmlhYmxlcyBpbml0aWFsbHkgYW5kIGFkZHJlc3MgcmVkdW5kYW5jeSBsYXRlciBkdXJpbmcgbW9kZWwgcmVmaW5lbWVudC4NCg0KV2Ugd2lsbCBub3cgY29uZHVjdCBmcmVxdWVuY3kgZGlzdHJpYnV0aW9ucyBmb3IgYWxsIG9mIHRoZSBudW1lcmljYWwgdmFyaWFibGVzIHRvIGlkZW50aWZ5IGFueSBwYXR0ZXJucyBhbmQgc2tld25lc3MuDQoNCmBgYHtyfQ0KDQpwYXIobWZyb3c9YygxLDIpKQ0KaGlzdChDU0RTX2NsZWFuJEZSRSwgeGxhYj0iIyBvZiBQdXJjaGFzZSBWaXNpdHMiLCBtYWluID0gIiIpDQpoaXN0KENTRFNfY2xlYW4kTU9OLCB4bGFiPSJUb3RhbCBOZXQgU2FsZXMiLCBtYWluID0gIiIpDQpoaXN0KENTRFNfY2xlYW4kQVZSRywgeGxhYj0iQXZlcmFnZSBTcGVuZCBQZXIgVmlzaXQiLCBtYWluID0gIiIpDQpoaXN0KENTRFNfY2xlYW4kR01QLCB4bGFiPSJHcm9zcyBNYXJnaW4gJSIsIG1haW4gPSAiIikNCmhpc3QoQ1NEU19jbGVhbiRQUk9NT1MsIHhsYWI9IiMgb2YgTWFya2V0aW5nIFByb21vcyIsIG1haW4gPSAiIikNCmhpc3QoQ1NEU19jbGVhbiREQVlTLCB4bGFiPSJEYXlzIG9uIEZpbGUiLCBtYWluID0gIiIpDQpoaXN0KENTRFNfY2xlYW4kQ0xBU1NFUywgeGxhYj0iIyBvZiBEaWZmZXJlbnQgUHJvZHVjdHMgUHVyY2hhc2VkIiwgbWFpbiA9ICIiKQ0KaGlzdChDU0RTX2NsZWFuJFNUWUxFUywgeGxhYj0iIyBvZiBJbmRpdmlkdWFsIEl0ZW1zIFB1cmNoYXNlZCIsIG1haW4gPSAiIikNCmhpc3QoQ1NEU19jbGVhbiRTVE9SRVMsIHhsYWI9IiMgb2YgU3RvcmVzIFNob3BwZWQgQXQiLCBtYWluID0gIiIpDQpoaXN0KENTRFNfY2xlYW4kSEksIHhsYWI9IlByb2R1Y3QgVW5pZm9ybWl0eSIsIG1haW4gPSAiIikNCmhpc3QoQ1NEU19jbGVhbiRQRVJDUkVULCB4bGFiPSIlIG9mIFJldHVybnMiLCBtYWluID0gIiIpDQoNCmBgYA0KDQpOb25lIG9mIG91ciB2YXJpYWJsZXMgYXJlIGRpc3RyaWJ1dGVkIG5vcm1hbGx5LiBOdW1iZXIgb2YgcHVyY2hhc2UgdmlzaXRzLCBUb3RhbCBOZXQgU2FsZXMsIEF2ZXJhZ2UgU3BlbmQgUGVyIFZpc2l0LCBOdW1iZXIgb2YgTWFya2V0aW5nIFByb21vcywgTnVtYmVyIG9mIERpZmZlcmVudCBQcm9kdWN0cyBQdXJjaGFzZWQsIE51bWJlciBvZiBJbmRpdmlkdWFsIEl0ZW1zIFB1cmNoYXNlZCwgTnVtYmVyIG9mIFN0b3JlcyBTaG9wcGVkIEF0LCBQcm9kdWN0IFVuaWZvcm1pdHksIGFuZCBQZXJjZW50IG9mIFJldHVybnMgYXJlIGFsbCBza2V3ZWQgdG8gdGhlIHJpZ2h0LiBHcm9zcyBNYXJnaW4gUGVyY2VudGFnZSBhbmQgRGF5cyBvbiBGaWxlIGFyZSBza2V3ZWQgbGVmdC4gV2Ugd2lsbCBhcHBseSBhcHByb3ByaWF0ZSB0cmFuc2Zvcm1hdGlvbnMgKGxvZzFwKCkgYW5kIHFsb2dpcygpKSBwcmlvciB0byBtb2RlbGluZy4gQnV0LCB3ZSB3aWxsIG5vdCBiZSBkaXNjcmV0aXppbmcgdGhlIHZhcmlhYmxlcyBiZWNhdXNlIHRoZXkgYXJlIGFsbCBzaWduaWZpY2FudGx5IHNrZXdlZC4gV2Ugd2lsbCBhbHNvIG5vdCBiZSBzdGFuZGFyZGl6aW5nIHRoZSB2YXJpYWJsZXMgYmVjYXVzZSBsb2cxcCgpIGFuZCBxbG9naXMoKSBoYW5kbGUgdGhlIGlzc3VlIG9mIHNrZXduZXNzIGFuZCBub25saW5lYXIgcmVsYXRpb25zaGlwcy4NCg0KIyA0IERhdGEgU3BsaXQgLSBUcmFpbmluZyBhbmQgVGVzdGluZyBEYXRhDQoNCldlIGZpcnN0IHNwbGl0IHRoZSBkYXRhIGludG8gNzAlIHRyYWluaW5nIGFuZCAzMCUgdGVzdGluZy4gQWxsIHRyYW5zZm9ybWF0aW9ucywgZmVhdHVyZSBzZWxlY3Rpb24sIGFuZCBtb2RlbCB0dW5pbmcgYXJlIHBlcmZvcm1lZCBvbmx5IG9uIHRoZSB0cmFpbmluZyBzZXQgdG8gYXZvaWQgZGF0YSBsZWFrYWdlLiBUaGUgdGVzdCBzZXQgcmVtYWlucyB1bnRvdWNoZWQgYW5kIGlzIHVzZWQgb25jZSBhdCB0aGUgZW5kIHRvIGVzdGltYXRlIG91dC1vZi1zYW1wbGUgcGVyZm9ybWFuY2UuDQoNCmBgYHtyfQ0KDQojIyBzcGxpdHRpbmcgZGF0YTogNzAlIHRyYWluaW5nIGFuZCAzMCUgdGVzdGluZyANCm4gPC0gZGltKENTRFNfY2xlYW4pWzFdIA0KdHJhaW4ubiA8LSByb3VuZCgwLjcqbikgDQp0cmFpbi5pZCA8LSBzYW1wbGUoMTpuLCB0cmFpbi5uLCByZXBsYWNlID0gRkFMU0UpIA0KIyMgdHJhaW5pbmcgYW5kIHRlc3RpbmcgZGF0YSBzZXRzIA0KdHJhaW4gPC0gQ1NEU19jbGVhblt0cmFpbi5pZCwgXSANCnRlc3QgPC0gQ1NEU19jbGVhblstdHJhaW4uaWQsIF0NCg0KYGBgDQoNCiMgNSBEYXRhIFRyYW5zZm9ybWF0aW9uIGFuZCBDYW5kaWRhdGUgTW9kZWxzDQoNCkluIHRoaXMgc2VjdGlvbiwgd2UgdHJhbnNmb3JtIHRoZSB0cmFpbmluZyBkYXRhIHRvIGFkZHJlc3Mgc2tld25lc3MgYW5kIHRoZW4gZGV2ZWxvcCBjYW5kaWRhdGUgbG9naXN0aWMgcmVncmVzc2lvbiBtb2RlbHMsIGNvbXBhcmluZyB0aGVtIG9uIGZpdCBhbmQgcGFyc2ltb255IGJlZm9yZSBzZXR0bGluZyBvbiBhIGZpbmFsIHNwZWNpZmljYXRpb24uDQoNCiMjIDUuMSBEYXRhIFRyYW5zZm9ybWF0aW9uDQoNClNldmVyYWwgcHJlZGljdG9ycyAoc3BlbmRpbmcgYW5kIHB1cmNoYXNpbmcgYWN0aXZpdHkpIGFyZSBoaWdobHkgc2tld2VkLiBUbyBpbXByb3ZlIHRoZSBhcHByb3hpbWF0ZSBsaW5lYXJpdHkgYmV0d2VlbiBwcmVkaWN0b3JzIGFuZCB0aGUgbG9nLW9kZHMgb2YgcmVzcG9uc2UsIHdlIGFwcGx5IGxvZzFwIHRvIHJpZ2h0LXNrZXdlZCBhY3Rpdml0eSB2YXJpYWJsZXMgYW5kIGEgbG9naXQgdHJhbnNmb3JtIHRvIHRoZSBib3VuZGVkIHJldHVybiByYXRlLiBUaGVzZSB0cmFuc2Zvcm1hdGlvbnMgcmVkdWNlIHRoZSBpbmZsdWVuY2Ugb2YgZXh0cmVtZSB2YWx1ZXMgYW5kIHN0YWJpbGl6ZSB2YXJpYW5jZSB3aGlsZSBwcmVzZXJ2aW5nIGNvbnRpbnVvdXMgaW5mb3JtYXRpb24uIEltcG9ydGFudGx5LCBhbGwgdHJhbnNmb3JtYXRpb25zIGFyZSBmaXQgYW5kIGFwcGxpZWQgb24gdGhlIHRyYWluaW5nIHNldCBvbmx5OyB0aGUgdGVzdCBzZXQgaXMgdHJhbnNmb3JtZWQgbGF0ZXIgd2l0aCB0aGUgc2FtZSBydWxlcyBmb3IgYSBmYWlyIGV2YWx1YXRpb24uDQoNCmBgYHtyfQ0KDQp0cmFpbl9kYXQgPC0gdHJhaW4gJT4lDQpkcGx5cjo6bXV0YXRlKA0KUkVTUCA9IGRwbHlyOjpjYXNlX3doZW4oDQpSRVNQICVpbiUgYygiWWVzIiwieWVzIiwxKSB+ICJ5ZXMiLA0KUkVTUCAlaW4lIGMoIk5vIiwibm8iLDApICAgfiAibm8iLA0KVFJVRSB+IE5BX2NoYXJhY3Rlcl8NCiksDQpSRVNQID0gZmFjdG9yKFJFU1AsIGxldmVscyA9IGMoIm5vIiwieWVzIikpLA0KUEVSQ1JFVF9wICAgICA9IHBtaW4ocG1heChQRVJDUkVUIC8gMTAwLCAxZS02KSwgMSAtIDFlLTYpLA0KUEVSQ1JFVF9sb2dpdCA9IHFsb2dpcyhQRVJDUkVUX3ApLA0KZHBseXI6OmFjcm9zcygNCnRpZHlzZWxlY3Q6OmFueV9vZihjKCJNT04iLCJGUkUiLCJTVFlMRVMiLCJDTEFTU0VTIiwiU1RPUkVTIiwiSEkiKSksDQp+IGxvZzFwKC4pLA0KLm5hbWVzID0gInsuY29sfV9sb2ciDQopDQopICU+JQ0KZHBseXI6OnNlbGVjdCh0aWR5c2VsZWN0OjphbGxfb2YoYygNCiJSRVNQIiwiTU9OX2xvZyIsIkZSRV9sb2ciLCJTVFlMRVNfbG9nIiwiQ0xBU1NFU19sb2ciLCJTVE9SRVNfbG9nIiwNCiJISV9sb2ciLCJQRVJDUkVUX2xvZ2l0IiwiUFJPTU9TIiwiREFZUyIsIkdNUCINCikpKSAlPiUNCnRpZHlyOjpkcm9wX25hKCkNCmBgYA0KDQpTdW1tYXJ5IG9mIHZhcmlhYmxlIGhhbmRsaW5nOg0KDQoqICoqVHJhbnNmb3JtZWQgKGxvZzFwKSoqOiBNT04sIEZSRSwgU1RZTEVTLCBDTEFTU0VTLCBTVE9SRVMsIEhJDQoNCiogKipUcmFuc2Zvcm1lZCAobG9naXQpKio6IFBFUkNSRVQNCg0KKiAqKlN0YW5kYXJkaXplZCoqOiBOb25lDQoNCiogKipEaXNjcmV0aXplZCoqOiBOb25lDQoNCiMjIDUuMiBMYXJnZXIgTW9kZWwNCg0KV2UgYmVnaW4gd2l0aCBhIGxhcmdlciBtb2RlbCBjb250YWluaW5nIGFsbCBtYWpvciB0cmFuc2Zvcm1lZCBudW1lcmljYWwgcHJlZGljdG9ycyB0byBjYXB0dXJlIHRoZSBmdWxsIHNldCBvZiBwb3RlbnRpYWwgZHJpdmVycyBvZiByZXNwb25zZS4NCg0KYGBge3J9DQoNCmxhcmdlciA8LSBnbG0oIFJFU1AgfiBNT05fbG9nICsgRlJFX2xvZyArIFNUWUxFU19sb2cgKyBDTEFTU0VTX2xvZyArIFNUT1JFU19sb2cgKyBISV9sb2cgKyBQRVJDUkVUX2xvZ2l0ICsgUFJPTU9TICsgREFZUyArIEdNUCwgZGF0YSA9IHRyYWluX2RhdCwgZmFtaWx5ID0gYmlub21pYWwgKSANCg0Kc3VtbWFyeShsYXJnZXIpDQpgYGANCg0KVGhlIGluaXRpYWwgbG9naXN0aWMgcmVncmVzc2lvbiBtb2RlbCBwcmVkaWN0cyB0aGUgbGlrZWxpaG9vZCB0aGF0IGEgY3VzdG9tZXIgcmVzcG9uZHMgdG8gYSBtYXJrZXRpbmcgcHJvbW90aW9uIGJhc2VkIG9uIGEgY29tcHJlaGVuc2l2ZSBzZXQgb2YgcHVyY2hhc2luZywgZW5nYWdlbWVudCwgYW5kIGRlbW9ncmFwaGljIHZhcmlhYmxlcy4gVGhpcyBtb2RlbCBpbmNsdWRlcyB0ZW4gcHJlZGljdG9yczogTU9OX2xvZywgRlJFX2xvZywgU1RZTEVTX2xvZywgQ0xBU1NFU19sb2csIFNUT1JFU19sb2csIEhJX2xvZywgUEVSQ1JFVF9sb2dpdCwgUFJPTU9TLCBEQVlTLCBhbmQgR01QLg0KDQoqIEZSRV9sb2cgKM6yID0gMS40MiwgcCA8IC4wMDEpOiBFYWNoIG9uZS11bml0IGluY3JlYXNlIG11bHRpcGxpZXMgdGhlIG9kZHMgb2YgcmVzcG9uc2UgYnkgYWJvdXQgNC4xIHRpbWVzLg0KDQoqIFBST01PUyAozrIgPSDigJMwLjAzNywgcCA9IC4wMTQpOiBFYWNoIGFkZGl0aW9uYWwgcHJvbW90aW9uIHNsaWdodGx5IHJlZHVjZXMgcmVzcG9uc2Ugb2RkcyAo4omIIOKAkzQlKS4NCg0KKiBTVFlMRVNfbG9nICjOsiA9IDAuNTksIHAgPSAuMDcpOiBQb3NpdGl2ZSBidXQgbWFyZ2luYWxseSBzaWduaWZpY2FudC4NCg0KQWxsIG90aGVyIHByZWRpY3RvcnMgYXJlIG5vdCBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IChwID4gLjEwKS4NCg0KVGhlIG1vZGVs4oCZcyByZXNpZHVhbCBkZXZpYW5jZSAoMTIyOS40KSBhbmQgQUlDICgxMjUxLjQpIHJlZmxlY3QgYSBzdHJvbmcgb3ZlcmFsbCBmaXQgcmVsYXRpdmUgdG8gdGhlIG51bGwgZGV2aWFuY2UgKDE1MzUuOSkuIEhvd2V2ZXIsIG11bHRpY29sbGluZWFyaXR5IGRpYWdub3N0aWNzIHJldmVhbGVkIGluZmxhdGVkIFZJRiB2YWx1ZXMgYW1vbmcgc2V2ZXJhbCBwdXJjaGFzaW5nIGFjdGl2aXR5IHZhcmlhYmxlcywgc3VjaCBhcyBNT05fbG9nLCBDTEFTU0VTX2xvZywgYW5kIFNUWUxFU19sb2cuIFRvIGFkZHJlc3MgcmVkdW5kYW5jeSBhbmQgaW1wcm92ZSBpbnRlcnByZXRhYmlsaXR5LCBhIHJlZHVjZWQgbW9kZWwgd2FzIGRldmVsb3BlZCBjb250YWluaW5nIG9ubHkgdGhlIGtleSBwcmVkaWN0b3JzIOKAlCBGUkVfbG9nLCBQUk9NT1MsIGFuZCBTVFlMRVNfbG9nIOKAlCB3aGljaCBwcm9kdWNlZCBhIG1vcmUgcGFyc2ltb25pb3VzIGFuZCBzdGFibGUgbW9kZWwgd2l0aG91dCBsb3NzIG9mIGV4cGxhbmF0b3J5IHBvd2VyLiBCZWZvcmUgc2hvcnRlbmluZyBvdXIgbW9kZWwsIGxldCdzIHNlZSBpZiB0aGVyZSBpcyBtdWx0aWNvbGxpbmVhcml0eSB3aXRoaW4gb3VyIHByZWRpY3RvciB2YXJpYWJsZXMuIFdlIHdpbGwgcnVuIGEgVklGIG1hdHJpeC4NCg0KYGBge3J9DQoNCnZpZihsYXJnZXIpDQoNCmBgYA0KDQpWYXJpYW5jZSBpbmZsYXRpb24gZmFjdG9ycyAoVklGKSByZXZlYWwgc3Vic3RhbnRpYWwgbXVsdGljb2xsaW5lYXJpdHkgYW1vbmcgcHVyY2hhc2UtYWN0aXZpdHkgdmFyaWFibGVz4oCUZXNwZWNpYWxseSBTVFlMRVNfbG9nICjiiYgxNS44KSwgTU9OX2xvZyAo4omIMTIuMCksIGFuZCBDTEFTU0VTX2xvZyAo4omIMTAuMCnigJR3aGljaCBtaXJyb3JzIHRoZSB2ZXJ5IGhpZ2ggY29ycmVsYXRpb25zIG9ic2VydmVkIGVhcmxpZXIgKGUuZy4sIE1PTuKAk1NUWUxFUyDiiYggMC45NCwgRlJF4oCTU1RZTEVTIOKJiCAwLjc5KS4gQmVjYXVzZSBzZXZlcmFsIG9mIHRoZXNlIHZhcmlhYmxlcyBhcmUgbm90IHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgb25jZSBmcmVxdWVuY3kgaXMgaW5jbHVkZWQsIHdlIHJlbW92ZSByZWR1bmRhbnQgcHJlZGljdG9ycyBhbmQgcHJvY2VlZCB0byBhIHJlZHVjZWQgbW9kZWwgdGhhdCBpbXByb3ZlcyBpbnRlcnByZXRhYmlsaXR5IGFuZCBudW1lcmljYWwgc3RhYmlsaXR5Lg0KDQojIyA1LjMgUmVkdWNlZCBNb2RlbA0KDQpHdWlkZWQgYnkgc2lnbmlmaWNhbmNlIGFuZCBtdWx0aWNvbGxpbmVhcml0eSBkaWFnbm9zdGljcywgdGhlIHJlZHVjZWQgbW9kZWwgZm9jdXNlcyBvbiB0aGUga2V5IHByZWRpY3RvcnMgRlJFX2xvZywgUFJPTU9TLCBhbmQgU1RZTEVTX2xvZy4NCg0KYGBge3J9DQoNCnJlZHVjZWQgPC0gZ2xtKA0KUkVTUCB+IEZSRV9sb2cgKyBQUk9NT1MgKyBTVFlMRVNfbG9nLA0KZGF0YSA9IHRyYWluX2RhdCwgZmFtaWx5ID0gYmlub21pYWwNCikNCnN1bW1hcnkocmVkdWNlZCkNCg0KYGBgDQoNClRoZSBmaW5hbCBsb2dpc3RpYyByZWdyZXNzaW9uIG1vZGVsIHByZWRpY3RzIHRoZSBsaWtlbGlob29kIHRoYXQgYSBjdXN0b21lciByZXNwb25kcyB0byBhIG1hcmtldGluZyBwcm9tb3Rpb24gYmFzZWQgb24gcHVyY2hhc2UgZnJlcXVlbmN5IChGUkVfbG9nKSwgbnVtYmVyIG9mIHByb21vdGlvbnMgKFBST01PUyksIGFuZCBudW1iZXIgb2YgdW5pcXVlIGl0ZW1zIHB1cmNoYXNlZCAoU1RZTEVTX2xvZykuDQoNCiogRlJFX2xvZyAozrIgPSAxLjM1LCBwIDwgLjAwMSk6IEEgb25lLXVuaXQgaW5jcmVhc2UgaW4gbG9nLXRyYW5zZm9ybWVkIHB1cmNoYXNlIGZyZXF1ZW5jeSBtdWx0aXBsaWVzIHRoZSBvZGRzIG9mIHJlc3BvbnNlIGJ5IGFwcHJveGltYXRlbHkgMy45w5cgKGXCucK3wrPigbUg4omIIDMuODYpLg0KDQoqIFBST01PUyAozrIgPSDigJMwLjA1NSwgcCA8IC4wMDEpOiBFYWNoIGFkZGl0aW9uYWwgcHJvbW90aW9uIG9uIGZpbGUgc2xpZ2h0bHkgcmVkdWNlcyB0aGUgb2RkcyBvZiByZXNwb25zZSBieSBhYm91dCA1JSAoZeKBu+KBsMK34oGw4oG14oG1IOKJiCAwLjk1KS4NCg0KKiBTVFlMRVNfbG9nICjOsiA9IDAuNDYsIHAgPSAuMDA3KTogQSBvbmUtdW5pdCBpbmNyZWFzZSBpbiBsb2ctdHJhbnNmb3JtZWQgc3R5bGVzIHB1cmNoYXNlZCBpbmNyZWFzZXMgdGhlIG9kZHMgb2YgcmVzcG9uc2UgYnkgcm91Z2hseSAxLjbDlyAoZeKBsMK34oG04oG2IOKJiCAxLjU4KS4NCg0KVGhlIG1vZGVs4oCZcyByZXNpZHVhbCBkZXZpYW5jZSAoMTIzNi4zKSBhbmQgQUlDICgxMjQ0LjMpIHJlcHJlc2VudCBhIHN0cm9uZyBpbXByb3ZlbWVudCBvdmVyIHRoZSBudWxsIGRldmlhbmNlICgxNTM1LjkpLCBjb25maXJtaW5nIGdvb2QgbW9kZWwgZml0LiBPdmVyYWxsLCB0aGlzIHJlZHVjZWQgbW9kZWwgaXMgcGFyc2ltb25pb3VzLCBzdGF0aXN0aWNhbGx5IHJvYnVzdCwgYW5kIGludGVycHJldGFibGUsIGhpZ2hsaWdodGluZyB0aGF0IHNob3BwaW5nIGZyZXF1ZW5jeSBhbmQgcHVyY2hhc2UgZGl2ZXJzaXR5IGFyZSBzdHJvbmcgcG9zaXRpdmUgcHJlZGljdG9ycyBvZiBwcm9tb3Rpb25hbCByZXNwb25zZSwgd2hpbGUgZXhjZXNzaXZlIHByb21vdGlvbiBmcmVxdWVuY3kgc2xpZ2h0bHkgZGFtcGVucyBpdC4NCg0KYGBge3J9DQoNCnZpZihyZWR1Y2VkKQ0KDQpgYGANCg0KQWxsIHRocmVlIFZJRiB2YWx1ZXMgYXJlIGJlbG93IDUsIG1lYW5pbmcgbXVsdGljb2xsaW5lYXJpdHkgaXMgbm8gbG9uZ2VyIGEgc2VyaW91cyBpc3N1ZS4NCg0KIyA2IENyb3NzLVZhbGlkYXRpb24gZm9yIEJlc3QgTW9kZWwgSWRlbnRpZmljYXRpb24NCg0KSGVyZSwgd2UgdXNlIDUtZm9sZCBjcm9zcyB2YWxpZGF0aW9uIHRvIG1ha2Ugc3VyZSBvdXIgZGF0YSBzZXQgaGFzIGVub3VnaCBvYnNlcnZhdGlvbnMsIG9yIGN1c3RvbWVycy4NCg0KYGBge3J9DQoNCiMjIDUtZm9sZCBjcm9zcy12YWxpZGF0aW9uIG9uIFRSQUlOSU5HIERBVEEgKHRyYWluX2RhdCkgIyMgUmVxdWlyZXM6IGxpYnJhcnkoTUFTUyk7IGxpYnJhcnkocGFuZGVyKSBzZXQuc2VlZCgxMjMpIA0KDQprIDwtIDUgDQpmb2xkLnNpemUgPC0gZmxvb3IobnJvdyh0cmFpbl9kYXQpIC8gaykgDQoNCiMgS2VlcCBjb2x1bW5zIHNvICcuJyBpbiBmb3JtdWxhIG1lYW5zIGV4YWN0bHkgdGhlc2UgcHJlZGljdG9ycw0KDQp0cmFpbl9jb2xzIDwtIGMoIlJFU1AiLCJNT05fbG9nIiwiRlJFX2xvZyIsIlNUWUxFU19sb2ciLCJDTEFTU0VTX2xvZyIsICJTVE9SRVNfbG9nIiwiSElfbG9nIiwiUEVSQ1JFVF9sb2dpdCIsIlBST01PUyIsIkRBWVMiLCJHTVAiKSANClBFMSA8LSBudW1lcmljKGspICMgZnVsbCANCg0KUEUyIDwtIG51bWVyaWMoaykgIyBzdGVwQUlDIChmb3J3YXJkKSANCg0KUEUzIDwtIG51bWVyaWMoaykgIyByZWR1Y2VkDQoNCmZvciAoaSBpbiAxOmspIHsgDQogIA0KIyBWYWxpZGF0aW9uIGFuZCB0cmFpbmluZyBmb2xkcyAoc2ltcGxlIGNvbnRpZ3VvdXMgZm9sZHMpIA0KICANCnZhbGlkLmlkIDwtIChmb2xkLnNpemUqKGktMSkrMSk6KGZvbGQuc2l6ZSppKSANCnZhbGlkIDwtIHRyYWluX2RhdFt2YWxpZC5pZCwgdHJhaW5fY29scywgZHJvcCA9IEZBTFNFXSANCnRyYWluX2N2IDwtIHRyYWluX2RhdFstdmFsaWQuaWQsIHRyYWluX2NvbHMsIGRyb3AgPSBGQUxTRV0gDQoNCiMjIGZ1bGwgbW9kZWwgKG1hdGNoZXMgeW91ciBsYXJnZXIgc3BlYykgDQoNCmxhcmdlciA8LSBnbG0oIFJFU1AgfiBNT05fbG9nICsgRlJFX2xvZyArIFNUWUxFU19sb2cgKyBDTEFTU0VTX2xvZyArIFNUT1JFU19sb2cgKyBISV9sb2cgKyBQRVJDUkVUX2xvZ2l0ICsgUFJPTU9TICsgREFZUyArIEdNUCwgZGF0YSA9IHRyYWluX2N2LCBmYW1pbHkgPSBiaW5vbWlhbCApIA0KDQojIyByZWR1Y2VkIG1vZGVsICh5b3VyIHRyaW8pIA0KDQpyZWR1Y2VkIDwtIGdsbSggUkVTUCB+IEZSRV9sb2cgKyBQUk9NT1MgKyBTVFlMRVNfbG9nLGRhdGEgPSB0cmFpbl9jdiwgZmFtaWx5ID0gYmlub21pYWwgKSANCg0KIyMgZm9yd2FyZCBzdGVwIGJldHdlZW4gcmVkdWNlZCAobG93ZXIpIGFuZCBmdWxsICh1cHBlcikgDQoNCm1vZGVsMiA8LSBNQVNTOjpzdGVwQUlDKCBsYXJnZXIsIHNjb3BlID0gbGlzdChsb3dlciA9IGZvcm11bGEocmVkdWNlZCksIHVwcGVyID0gZm9ybXVsYShsYXJnZXIpKSwgZGlyZWN0aW9uID0gImZvcndhcmQiLCB0cmFjZSA9IDAgKQ0KDQojIyBwcmVkaWN0ZWQgcHJvYmFiaWxpdGllcyBvbiB2YWxpZGF0aW9uIGZvbGQgDQoNCnByZWQwMSA8LSBwcmVkaWN0KGxhcmdlciwgbmV3ZGF0YSA9IHZhbGlkLCB0eXBlID0gInJlc3BvbnNlIikgDQoNCnByZWQwMiA8LSBwcmVkaWN0KG1vZGVsMiwgbmV3ZGF0YSA9IHZhbGlkLCB0eXBlID0gInJlc3BvbnNlIikgDQoNCnByZWQwMyA8LSBwcmVkaWN0KHJlZHVjZWQsIG5ld2RhdGEgPSB2YWxpZCwgdHlwZSA9ICJyZXNwb25zZSIpIA0KDQojIyBjbGFzc2lmeSB3aXRoIHRocmVzaG9sZCAwLjQgKHRvIG1hdGNoIHlvdXIgdGVtcGxhdGUpIA0KDQp5aGF0MDEgPC0gaWZlbHNlKHByZWQwMSA+IDAuNCwgInllcyIsICJubyIpIA0KeWhhdDAyIDwtIGlmZWxzZShwcmVkMDIgPiAwLjQsICJ5ZXMiLCAibm8iKSANCnloYXQwMyA8LSBpZmVsc2UocHJlZDAzID4gMC40LCAieWVzIiwgIm5vIikgDQojIyBtaXNjbGFzc2lmaWNhdGlvbiBlcnJvciB2cyB0cnVlIFJFU1AgDQpQRTFbaV0gPC0gbWVhbih5aGF0MDEgIT0gYXMuY2hhcmFjdGVyKHZhbGlkJFJFU1ApKSANClBFMltpXSA8LSBtZWFuKHloYXQwMiAhPSBhcy5jaGFyYWN0ZXIodmFsaWQkUkVTUCkpIA0KUEUzW2ldIDwtIG1lYW4oeWhhdDAzICE9IGFzLmNoYXJhY3Rlcih2YWxpZCRSRVNQKSkgfSANCg0KYXZnLnBlIDwtIGNiaW5kKFBFLjFfRnVsbCA9IG1lYW4oUEUxKSwgDQogIFBFLjJfU3RlcCA9IG1lYW4oUEUyKSwgDQogIFBFLjNfUmVkdWNlZCA9IG1lYW4oUEUzKSkgDQpwYW5kZXI6OnBhbmRlcihhdmcucGUsIGNhcHRpb24gPSAiNS1mb2xkIENWOiBBdmVyYWdlIHByZWRpY3Rpb24gZXJyb3JzIChsb3dlciBpcyBiZXR0ZXIpIikNCg0KYGBgDQoNCkluIDUtZm9sZCBDViBvbiB0aGUgdHJhaW5pbmcgZGF0YSwgcHJlZGljdGlvbiBlcnJvcnMgd2VyZSAwLjE0NTQgKGZ1bGwpLCAwLjE0NTQgKHN0ZXB3aXNlKSwgYW5kIDAuMTQ0OCAocmVkdWNlZCksIGluZGljYXRpbmcgY29tcGFyYWJsZSBwZXJmb3JtYW5jZTsgd2Ugc2VsZWN0IHRoZSByZWR1Y2VkIG1vZGVsIGZvciBpdHMgc2xpZ2h0bHkgbG93ZXIgZXJyb3IgYW5kIGltcHJvdmVkIGludGVycHJldGFiaWxpdHkuDQoNCiMgNyBDb25jbHVzaW9uDQoNClRoZSBwdXJwb3NlIG9mIHRoaXMgcHJvamVjdCB3YXMgdG8gZGV0ZXJtaW5lIHdoaWNoIGN1c3RvbWVyIGNoYXJhY3RlcmlzdGljcyBtb3N0IGVmZmVjdGl2ZWx5IHByZWRpY3QgcmVzcG9uc2UgdG8gYSBkaXJlY3QtbWFpbCBtYXJrZXRpbmcgcHJvbW90aW9uLiBUaHJvdWdoIGV4cGxvcmF0b3J5IGFuYWx5c2lzLCB3ZSBmb3VuZCB0aGF0IHB1cmNoYXNpbmcgYmVoYXZpb3IgdmFyaWFibGVz4oCUc3VjaCBhcyBwdXJjaGFzZSBmcmVxdWVuY3ksIG51bWJlciBvZiBzdHlsZXMgcHVyY2hhc2VkLCBhbmQgdG90YWwgc2FsZXPigJR3ZXJlIGhpZ2hseSBjb3JyZWxhdGVkIGFuZCBzdHJvbmdseSBza2V3ZWQuIFRvIGltcHJvdmUgbW9kZWwgc3RhYmlsaXR5LCB0aGVzZSBwcmVkaWN0b3JzIHdlcmUgbG9nLXRyYW5zZm9ybWVkLCBhbmQgcmVkdW5kYW50IHZhcmlhYmxlcyB3ZXJlIHJlbW92ZWQgYmFzZWQgb24gYm90aCBtdWx0aWNvbGxpbmVhcml0eSAoVklGKSBhbmQgc3RhdGlzdGljYWwgaW5zaWduaWZpY2FuY2UuDQoNClR3byBsb2dpc3RpYyByZWdyZXNzaW9uIG1vZGVscyB3ZXJlIGV2YWx1YXRlZDogYSBsYXJnZXIgbW9kZWwgaW5jbHVkaW5nIGFsbCB0cmFuc2Zvcm1lZCBudW1lcmljIHByZWRpY3RvcnMsIGFuZCBhIHJlZHVjZWQgbW9kZWwgZm9jdXNpbmcgb24gdGhlIG1vc3QgbWVhbmluZ2Z1bCBwcmVkaWN0b3JzIChGUkVfbG9nLCBTVFlMRVNfbG9nLCBhbmQgUFJPTU9TKS4gQm90aCBtb2RlbHMgYWNoaWV2ZWQgc2ltaWxhciBwcmVkaWN0aXZlIGFjY3VyYWN5IGluIDUtZm9sZCBjcm9zcy12YWxpZGF0aW9uLCB3aXRoIHRoZSByZWR1Y2VkIG1vZGVsIHByb2R1Y2luZyB0aGUgbG93ZXN0IGF2ZXJhZ2UgcHJlZGljdGlvbiBlcnJvciAoMC4xNDQ4KS4gQmVjYXVzZSBpdCBwcm92aWRlZCBuZWFybHkgaWRlbnRpY2FsIHBlcmZvcm1hbmNlIHdpdGggZmV3ZXIgcGFyYW1ldGVycyBhbmQgbm8gbXVsdGljb2xsaW5lYXJpdHkgY29uY2VybnMsIHRoZSByZWR1Y2VkIG1vZGVsIHdhcyBzZWxlY3RlZCBhcyB0aGUgZmluYWwgc3BlY2lmaWNhdGlvbi4NCg0KVGhlIGZpbmFsIG1vZGVsIHJldmVhbHMgdGhhdCBjdXN0b21lcnMgd2hvIHNob3AgbW9yZSBmcmVxdWVudGx5IGFuZCBwdXJjaGFzZSBhIHdpZGVyIHZhcmlldHkgb2YgaXRlbXMgYXJlIHNpZ25pZmljYW50bHkgbW9yZSBsaWtlbHkgdG8gcmVzcG9uZCB0byBhIG1hcmtldGluZyBwcm9tb3Rpb24sIHdoaWxlIHRob3NlIHdobyByZWNlaXZlIG1vcmUgcHJvbW90aW9ucyB0ZW5kIHRvIHJlc3BvbmQgbGVzcywgcG9zc2libHkgZHVlIHRvIHNhdHVyYXRpb24gb3IgZmF0aWd1ZS4gT3ZlcmFsbCwgdGhpcyBhbmFseXNpcyBzdWNjZXNzZnVsbHkgYW5zd2VycyB0aGUgcmVzZWFyY2ggcXVlc3Rpb246IHllcywgY2VydGFpbiBiZWhhdmlvcmFsIGNoYXJhY3RlcmlzdGljc+KAlGVzcGVjaWFsbHkgc2hvcHBpbmcgZnJlcXVlbmN5IGFuZCBwcm9kdWN0IHZhcmlldHnigJRjYW4gcmVsaWFibHkgcHJlZGljdCB3aGV0aGVyIGEgY3VzdG9tZXIgd2lsbCByZXNwb25kIHRvIGEgZGlyZWN0LW1haWwgcHJvbW90aW9uLiBUaGVzZSBpbnNpZ2h0cyBjYW4gZ3VpZGUgZnV0dXJlIG1hcmtldGluZyBzdHJhdGVnaWVzIGJ5IGhlbHBpbmcgcmV0YWlsZXJzIGJldHRlciB0YXJnZXQgaGlnaC1lbmdhZ2VtZW50IGN1c3RvbWVycyBhbmQgcmVmaW5lIHRoZWlyIHByb21vdGlvbmFsIGZyZXF1ZW5jeSBmb3Igb3B0aW1hbCBpbXBhY3Qu