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

Several predictors (spending and purchasing activity) are highly skewed. To improve the approximate linearity between predictors and the log-odds of response, we apply log1p to right-skewed activity variables and a logit transform to the bounded return rate. These transformations reduce the influence of extreme values and stabilize variance while preserving continuous information. Importantly, all transformations are fit and applied on the training set only; the test set is transformed later with the same rules for a fair evaluation.

train_dat <- train %>%
dplyr::mutate(
RESP = dplyr::case_when(
RESP %in% c("Yes","yes",1) ~ "yes",
RESP %in% c("No","no",0)   ~ "no",
TRUE ~ NA_character_
),
RESP = factor(RESP, levels = c("no","yes")),
PERCRET_p     = pmin(pmax(PERCRET / 100, 1e-6), 1 - 1e-6),
PERCRET_logit = qlogis(PERCRET_p),
dplyr::across(
tidyselect::any_of(c("MON","FRE","STYLES","CLASSES","STORES","HI")),
~ log1p(.),
.names = "{.col}_log"
)
) %>%
dplyr::select(tidyselect::all_of(c(
"RESP","MON_log","FRE_log","STYLES_log","CLASSES_log","STORES_log",
"HI_log","PERCRET_logit","PROMOS","DAYS","GMP"
))) %>%
tidyr::drop_na()

Summary of variable handling:

  • Transformed (log1p): MON, FRE, STYLES, CLASSES, STORES, HI

  • Transformed (logit): PERCRET

  • Standardized: None

  • Discretized: None

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.

vif(larger)
      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.

vif(reduced)
   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)
PE.1_Full PE.2_Step PE.3_Reduced
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