Predicting Customer Retention
Let’s load our required packages:
Our data structure we will be using for our models:
'data.frame': 1000 obs. of 10 variables:
$ pick : chr "OCC" "ATT" "OCC" "OCC" ...
$ income : chr "<7.5" "45-75" "" "" ...
$ moves : chr "0" "2" "0" "2" ...
$ age : chr "35-44" "25-34" "" "65+" ...
$ education : chr "HS" "HS" "" "<HS" ...
$ employment: chr "F" "F" "" "R" ...
$ usage : int 9 2 6 7 0 0 3 1 0 2 ...
$ nonpub : chr "YES" "YES" "NO" "NO" ...
$ reachout : chr "NO" "NO" "NO" "NO" ...
$ card : chr "NO" "NO" "YES" "NO" ...
NULL
Converting blank character fields to missing data codes
Convert character fields to factor fields
Let’s check our revised structure of att data frame:
'data.frame': 1000 obs. of 10 variables:
$ pick : Factor w/ 2 levels "ATT","OCC": 2 1 2 2 2 2 2 2 2 2 ...
$ income : Factor w/ 7 levels "<7.5",">75","15-25",..: 1 6 NA NA NA NA 4 3 NA 4 ...
$ moves : Factor w/ 9 levels ">10","0","1",..: 2 4 2 4 2 2 2 2 2 2 ...
$ age : Factor w/ 6 levels "18-24","25-34",..: 3 2 NA 6 6 6 4 5 5 4 ...
$ education : Factor w/ 6 levels "<HS",">BA","BA",..: 5 5 NA 1 5 NA 1 5 1 1 ...
$ employment: Factor w/ 7 levels "D","F","H","P",..: 2 2 NA 5 3 NA 2 5 2 3 ...
$ usage : int 9 2 6 7 0 0 3 1 0 2 ...
$ nonpub : Factor w/ 2 levels "NO","YES": 2 2 1 1 1 1 1 1 1 1 ...
$ reachout : Factor w/ 2 levels "NO","YES": 1 1 1 1 1 1 1 1 1 1 ...
$ card : Factor w/ 2 levels "NO","YES": 1 1 2 1 1 1 1 2 1 1 ...
NULL
listwise case deletion for usage and marketing factors
pick usage reachout card
ATT:502 Min. : 0.00 NO :919 NO :701
OCC:479 1st Qu.: 1.00 YES: 62 YES:280
Median : 6.00
Mean : 16.32
3rd Qu.: 23.00
Max. :291.00
provide overview of data
pick income moves age education employment usage
ATT:504 15-25 :185 0 :597 18-24: 61 <HS :153 F :548 Min. : 0.00
OCC:496 25-35 :171 1 :221 25-34:214 >BA : 60 R :215 1st Qu.: 1.00
7.5-15 :114 2 : 88 35-44:203 BA :150 H : 93 Median : 6.00
35-45 :107 3 : 38 45-54:152 Coll:187 P : 67 Mean : 16.34
<7.5 : 96 4 : 16 55-64:153 HS :361 U : 26 3rd Qu.: 23.00
(Other):112 (Other): 23 65+ :184 Voc : 54 (Other): 25 Max. :291.00
NA's :215 NA's : 17 NA's : 33 NA's: 35 NA's : 26
nonpub reachout card
NO :808 NO :919 NO :702
YES :188 YES : 62 YES :281
NA's: 4 NA's: 19 NA's: 17
Examine relationship between age and response to promotion. Switchers tend to have lower usage

Plotting the probability smooth for usage and switching:

Create a mosaic plot in using vcd package

Create a mosaic plot in using vcd package

Fittin our logistic regression model
Call:
glm(formula = att_spec, family = binomial, data = attwork)
Deviance Residuals:
Min 1Q Median 3Q Max
-1.3240 -1.1878 -0.5689 1.0693 2.6588
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 0.338302 0.087095 3.884 0.000103 ***
usage -0.013080 0.003362 -3.890 0.000100 ***
reachoutYES -0.869531 0.323727 -2.686 0.007231 **
cardYES -0.475578 0.149350 -3.184 0.001451 **
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 1359.4 on 980 degrees of freedom
Residual deviance: 1307.0 on 977 degrees of freedom
AIC: 1315
Number of Fisher Scoring iterations: 4
Printing ANOVA tests
Analysis of Deviance Table
Model: binomial, link: logit
Response: pick
Terms added sequentially (first to last)
Df Deviance Resid. Df Resid. Dev Pr(>Chi)
NULL 980 1359.4
usage 1 33.303 979 1326.1 7.886e-09 ***
reachout 1 8.872 978 1317.2 0.002895 **
card 1 10.227 977 1307.0 0.001384 **
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Compute predicted probability of switching service providers
Plotting Predicted Probability of Switching

Confusion Matrix (rows=Predicted Service Provider, columns=Actual Service Provider
ATT OCC
AT&T 250 159
OCC 252 320
Percent Accuracy: 58.1
pick
Predict_Pick ATT OCC <NA>
AT&T 250 159 0
OCC 252 320 0
<NA> 0 0 0
Plot predicted Service Provider (50 percent cut-off)

Ploting classification tree result from rpart
cex 1 xlim c(-0.2, 1.2) ylim c(0, 1)

Visual of fit random forest model to the training data

Ensuring complete data in both partitions were created
ATT OCC
502 479
ATT OCC
168 160
ATT OCC
334 319
Plotting ROC for logistic regression

Plotting ROC for support vector machines

Plotting ROC for random forest

Plotting ROC for Naive Bayes

Plotting ROC for Neural Network

LS0tDQp0aXRsZTogIkN1c3RvbWVyIFJldGVudGlvbiINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQogDQojIFByZWRpY3RpbmcgQ3VzdG9tZXIgUmV0ZW50aW9uDQoNCkxldCdzIGxvYWQgb3VyIHJlcXVpcmVkIHBhY2thZ2VzOg0KDQpgYGB7ciBldmFsPVRSVUUsIGVjaG89RkFMU0V9DQpsaWJyYXJ5KGxhdHRpY2UpICAjIGxhdHRpY2UgcGxvdA0KbGlicmFyeSh2Y2QpICAjIG1vc2FpYyBwbG90cw0KbGlicmFyeShnYW0pICAjIGdlbmVyYWxpemVkIGFkZGl0aXZlIG1vZGVscyBmb3IgcHJvYmFiaWxpdHkgc21vb3RoDQpsaWJyYXJ5KHJwYXJ0KSAgIyB0cmVlLXN0cnVjdHVyZWQgbW9kZWxpbmcNCmxpYnJhcnkoZTEwNzEpICAjIHN1cHBvcnQgdmVjdG9yIG1hY2hpbmVzDQpsaWJyYXJ5KHJhbmRvbUZvcmVzdCkgICMgcmFuZG9tIGZvcmVzdHMNCmxpYnJhcnkobm5ldCkgICMgbmV1cmFsIG5ldHdvcmtzDQpsaWJyYXJ5KHJwYXJ0LnBsb3QpICAjIHBsb3QgdHJlZS1zdHJ1Y3R1cmVkIG1vZGVsIGluZm9ybWF0aW9uDQpsaWJyYXJ5KFJPQ1IpICAjIFJPQyBjdXJ2ZSBvYmplY3RzIGZvciBiaW5hcnkgY2xhc3NpZmljYXRpb24gDQoNCmBgYA0KDQpgYGB7ciBldmFsPVRSVUUsIGVjaG89RkFMU0V9DQojIHVzZXItZGVmaW5lZCBmdW5jdGlvbiBmb3IgcGxvdHRpbmcgUk9DIGN1cnZlIHVzaW5nIFJPQyBvYmplY3RzIGZyb20gUk9DUg0KcGxvdF9yb2MgPC0gZnVuY3Rpb24odHJhaW5fcm9jLCB0cmFpbl9hdWMsIHRlc3Rfcm9jLCB0ZXN0X2F1Yykgew0KICAgIHBsb3QodHJhaW5fcm9jLCBjb2wgPSAiYmx1ZSIsIGx0eSA9ICJzb2xpZCIsIG1haW4gPSAiIiwgbHdkID0gMiwNCiAgICAgICAgeGxhYiA9ICJGYWxzZSBQb3NpdGl2ZSBSYXRlIiwNCiAgICAgICAgeWxhYiA9ICJUcnVlIFBvc2l0aXZlIFJhdGUiKQ0KICAgICAgICBwbG90KHRlc3Rfcm9jLCBjb2wgPSAicmVkIiwgbHR5ID0gImRhc2hlZCIsIGx3ZCA9IDIsIGFkZCA9IFRSVUUpDQogICAgICAgIGFibGluZShjKDAsMSkpDQogICAgICAgIyBEcmF3IGEgbGVnZW5kLg0KICAgICAgIHRyYWluLmxlZ2VuZCA8LSBwYXN0ZSgiVHJhaW5pbmcgQVVDID0gIiwgcm91bmQodHJhaW5fYXVjLCBkaWdpdHM9MykpDQogICAgICAgdGVzdC5sZWdlbmQgPC0gcGFzdGUoIlRlc3QgQVVDID0iLCByb3VuZCh0ZXN0X2F1YywgZGlnaXRzPTMpKQ0KICAgICAgIGxlZ2VuZCgiYm90dG9tcmlnaHQiLCBsZWdlbmQgPSBjKHRyYWluLmxlZ2VuZCwgdGVzdC5sZWdlbmQpLA0KICAgICAgICAgICBsdHkgPSBjKCJzb2xpZCIsICJkYXNoZWQiKSwgbHdkID0gMiwgY29sID0gYygiYmx1ZSIsICJyZWQiKSkNCiAgICB9ICAgICAgIA0KDQpgYGANCg0KT3VyIGRhdGEgc3RydWN0dXJlIHdlIHdpbGwgYmUgdXNpbmcgZm9yIG91ciBtb2RlbHM6DQoNCmBgYHtyIGV2YWw9VFJVRSwgZWNobz1GQUxTRX0NCiMgcmVhZCBpbiBjb21tYS1kZWxpbWl0ZWQgdGV4dCBmaWxlIGFuZCBjcmVhdGUgZGF0YSBmcmFtZQ0KIyB0aGVyZSBhcmUgYmxhbmsgY2hhcmFjdGVyIGZpZWxkcyBmb3IgbWlzc2luZyBkYXRhDQojIHJlYWQgdGhlbSBhcyBjaGFyYWN0ZXIgZmllbGRzIGluaXRpYWxseQ0KYXR0IDwtIHJlYWQuY3N2KCJhdHQuY3N2Iiwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQ0KcHJpbnQoc3RyKGF0dCkpDQoNCmBgYA0KDQpDb252ZXJ0aW5nIGJsYW5rIGNoYXJhY3RlciBmaWVsZHMgdG8gbWlzc2luZyBkYXRhIGNvZGVzDQoNCmBgYHtyIGV2YWw9VFJVRSwgZWNobz1GQUxTRX0NCiMgDQphdHRbYXR0ID09ICIiXSA8LSBOQQ0KYGBgDQoNCkNvbnZlcnQgY2hhcmFjdGVyIGZpZWxkcyB0byBmYWN0b3IgZmllbGRzDQoNCmBgYHtyIGV2YWw9VFJVRSwgZWNobz1GQUxTRX0gDQphdHQkcGljayA8LSBmYWN0b3IoYXR0JHBpY2spDQphdHQkaW5jb21lIDwtIGZhY3RvcihhdHQkaW5jb21lKQ0KYXR0JG1vdmVzIDwtIGZhY3RvcihhdHQkbW92ZXMpDQphdHQkYWdlIDwtIGZhY3RvcihhdHQkYWdlKQ0KYXR0JGVkdWNhdGlvbiA8LSBmYWN0b3IoYXR0JGVkdWNhdGlvbikNCmF0dCRlbXBsb3ltZW50IDwtIGZhY3RvcihhdHQkZW1wbG95bWVudCkNCmF0dCRub25wdWIgPC0gZmFjdG9yKGF0dCRub25wdWIpDQphdHQkcmVhY2hvdXQgPC0gZmFjdG9yKGF0dCRyZWFjaG91dCkNCmF0dCRjYXJkIDwtIGZhY3RvcihhdHQkY2FyZCkNCg0KYGBgDQoNCkxldCdzIGNoZWNrIG91ciByZXZpc2VkIHN0cnVjdHVyZSBvZiBhdHQgZGF0YSBmcmFtZToNCg0KYGBge3IgZXZhbD1UUlVFLCBlY2hvPUZBTFNFfQ0KcHJpbnQoc3RyKGF0dCkpDQoNCmBgYA0KDQpgYGB7ciBldmFsPVRSVUUsIGVjaG89RkFMU0V9DQojIHNlbGVjdCB1c2FnZSBhbmQgQVQmVCBtYXJrZXRpbmcgcGxhbiBmYWN0b3JzDQphdHR3b3JrIDwtIHN1YnNldChhdHQsIHNlbGVjdCA9IGMoInBpY2siLCAidXNhZ2UiLCAicmVhY2hvdXQiLCAiY2FyZCIpKQ0KYXR0d29yayA8LSBuYS5vbWl0KGF0dHdvcmspDQoNCmBgYA0KDQpsaXN0d2lzZSBjYXNlIGRlbGV0aW9uIGZvciB1c2FnZSBhbmQgbWFya2V0aW5nIGZhY3RvcnMNCg0KYGBge3IgZXZhbD1UUlVFLCBlY2hvPUZBTFNFfQ0KIyANCmF0dHdvcmsgPC0gbmEub21pdChhdHR3b3JrKQ0KcHJpbnQoc3VtbWFyeShhdHR3b3JrKSkNCmBgYA0KDQpwcm92aWRlIG92ZXJ2aWV3IG9mIGRhdGENCg0KYGBge3IgZXZhbD1UUlVFLCBlY2hvPUZBTFNFfQ0KIyBwcm92aWRlIG92ZXJ2aWV3IG9mIGRhdGENCnByaW50KHN1bW1hcnkoYXR0KSkNCg0KYGBgDQoNCkV4YW1pbmUgcmVsYXRpb25zaGlwIGJldHdlZW4gYWdlIGFuZCByZXNwb25zZSB0byBwcm9tb3Rpb24uIFN3aXRjaGVycyB0ZW5kIHRvIGhhdmUgbG93ZXIgdXNhZ2UNCg0KYGBge3IgZXZhbD1UUlVFLCBlY2hvPUZBTFNFfQ0KIyAtLS0tLS0tLS0tLS0tLS0tLQ0KIyB1c2FnZSBhbmQgcGljaw0KIyAtLS0tLS0tLS0tLS0tLS0tLQ0KIyBleGFtaW5lIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGFnZSBhbmQgcmVzcG9uc2UgdG8gcHJvbW90aW9uDQpwZGYoZmlsZSA9ICJmaWdfcmV0YWluaW5nX2N1c3RvbWVyc191c2FnZV9sYXR0aWNlLnBkZiIsIA0KICAgIHdpZHRoID0gOC41LCBoZWlnaHQgPSA4LjUpDQoNCmxhdHRpY2VfcGxvdF9vYmplY3QgPC0gaGlzdG9ncmFtKH51c2FnZSB8IHBpY2ssIGRhdGEgPSBhdHQsDQogICAgdHlwZSA9ICJkZW5zaXR5IiwgeGxhYiA9ICJUZWxlcGhvbmUgVXNhZ2UgKE1pbnV0ZXMgcGVyIE1vbnRoKSIsIA0KICAgIGxheW91dCA9IGMoMSwyKSkNCg0KcHJpbnQobGF0dGljZV9wbG90X29iamVjdCkgICMgc3dpdGNoZXJzIHRlbmQgdG8gaGF2ZSBsb3dlciB1c2FnZQ0KDQoNCmBgYA0KDQpgYGB7ciBldmFsPVRSVUUsIGVjaG89RkFMU0V9DQphdHRfZ2FtX21vZGVsIDwtIGdhbShwaWNrID09ICJPQ0MiICB+IHModXNhZ2UpLCBmYW1pbHk9Ymlub21pYWwsZGF0YT1hdHQpDQpgYGANCg0KUGxvdHRpbmcgdGhlIHByb2JhYmlsaXR5IHNtb290aCBmb3IgdXNhZ2UgYW5kIHN3aXRjaGluZzoNCg0KYGBge3IgZXZhbD1UUlVFLCBlY2hvPUZBTFNFfQ0KIyBwcm9iYWJpbGl0eSBzbW9vdGggZm9yIHVzYWdlIGFuZCBzd2l0Y2hpbmcNCnBkZihmaWxlID0gImZpZ19yZXRhaW5pbmdfY3VzdG9tZXJzX3VzYWdlX3Byb2JhYmlsaXR5X3Ntb290aC5wZGYiLCANCiAgICB3aWR0aCA9IDguNSwgaGVpZ2h0ID0gOC41KQ0KDQpwbG90KGF0dCR1c2FnZSwgYXR0JHBpY2sgPT0gIk9DQyIsIHR5cGU9Im4iLCANCiAgICAgeWxpbT1jKC0wLjEsMS4xKSwgeWF4dD0ibiIsIA0KICAgICB5bGFiPSJFc3RpbWF0ZWQgUHJvYmFiaWxpdHkgb2YgU3dpdGNoaW5nIiwgDQogICAgIHhsYWI9IlRlbGVwaG9uZSBVc2FnZSAoTWludXRlcyBwZXIgTW9udGgpIikgDQogICAgIGF4aXMoMiwgYXQ9YygwLC41LDEpKSANCiAgICAgcG9pbnRzKGppdHRlcihhdHQkdXNhZ2UpLCANCiAgICAgYXR0JHBpY2s9PSJPQ0MiLHBjaD0ifCIpIA0KICAgICBvIDwtIG9yZGVyKGF0dCR1c2FnZSkgDQogICAgIGxpbmVzKGF0dCR1c2FnZVtvXSxmaXR0ZWQoYXR0X2dhbV9tb2RlbClbb10pIA0KICAgICANCg0KDQpgYGANCg0KQ3JlYXRlIGEgbW9zYWljIHBsb3QgaW4gdXNpbmcgdmNkIHBhY2thZ2UNCg0KYGBge3IgZXZhbD1UUlVFLCBlY2hvPUZBTFNFfQ0KIyAtLS0tLS0tLS0tLS0tLS0tLQ0KIyByZWFjaG91dCBhbmQgcGljaw0KIyAtLS0tLS0tLS0tLS0tLS0tLQ0KDQojIGNyZWF0ZSBhIG1vc2FpYyBwbG90IGluIHVzaW5nIHZjZCBwYWNrYWdlDQpwZGYoZmlsZSA9ICJmaWdfcmV0YWluaW5nX2N1c3RvbWVyc19yZWFjaG91dF9tb3NhaWMucGRmIiwgDQogICAgd2lkdGggPSA4LjUsIGhlaWdodCA9IDguNSkNCg0KbW9zYWljKCB+IHBpY2sgKyByZWFjaG91dCwgZGF0YSA9IGF0dHdvcmssDQogIGxhYmVsaW5nX2FyZ3MgPSBsaXN0KHNldF92YXJuYW1lcyA9IGMocGljayA9ICJTZXJ2aWNlIFByb3ZpZGVyIENob2ljZSIsIA0KICByZWFjaG91dCA9ICJBVCZUIFJlYWNoIE91dCBBbWVyaWNhIFBsYW4iKSksDQogIGhpZ2hsaWdodGluZyA9ICJyZWFjaG91dCIsDQogIGhpZ2hsaWdodGluZ19maWxsID0gYygiY29ybnNpbGsiLCJ2aW9sZXQiKSwNCiAgcm90X2xhYmVscyA9IGMobGVmdCA9IDAsIHRvcCA9IDApLA0KICBwb3NfbGFiZWxzID0gYygiY2VudGVyIiwiY2VudGVyIiksDQogIG9mZnNldF9sYWJlbHMgPSBjKDAuMCwwLjYpKQ0KDQoNCg0KYGBgDQoNCkNyZWF0ZSBhIG1vc2FpYyBwbG90IGluIHVzaW5nIHZjZCBwYWNrYWdlDQoNCmBgYHtyIGV2YWw9VFJVRSwgZWNobz1GQUxTRX0NCiMgY3JlYXRlIGEgbW9zYWljIHBsb3QgaW4gdXNpbmcgdmNkIHBhY2thZ2UNCnBkZihmaWxlID0gImZpZ19yZXRhaW5pbmdfY3VzdG9tZXJzX2NhcmRfbW9zYWljLnBkZiIsIA0KICAgIHdpZHRoID0gOC41LCBoZWlnaHQgPSA4LjUpDQoNCm1vc2FpYyggfiBwaWNrICsgY2FyZCwgZGF0YSA9IGF0dHdvcmssDQogIGxhYmVsaW5nX2FyZ3MgPSBsaXN0KHNldF92YXJuYW1lcyA9IGMocGljayA9ICJTZXJ2aWNlIFByb3ZpZGVyIENob2ljZSIsIA0KICBjYXJkID0gIkFUJlQgQ3JlZGl0IENhcmQiKSksDQogIGhpZ2hsaWdodGluZyA9ICJjYXJkIiwNCiAgaGlnaGxpZ2h0aW5nX2ZpbGwgPSBjKCJjb3Juc2lsayIsInZpb2xldCIpLA0KICByb3RfbGFiZWxzID0gYyhsZWZ0ID0gMCwgdG9wID0gMCksDQogIHBvc19sYWJlbHMgPSBjKCJjZW50ZXIiLCJjZW50ZXIiKSwNCiAgb2Zmc2V0X2xhYmVscyA9IGMoMC4wLDAuNikpDQoNCg0KDQpgYGANCg0KRml0dGluIG91ciBsb2dpc3RpYyByZWdyZXNzaW9uIG1vZGVsDQoNCmBgYHtyIGV2YWw9VFJVRSwgZWNobz1GQUxTRX0NCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyBmaXQgbG9naXN0aWMgcmVncmVzc2lvbiBtb2RlbCANCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KYXR0X3NwZWMgPC0ge3BpY2sgfiB1c2FnZSArIHJlYWNob3V0ICsgY2FyZH0NCmF0dF9maXQgPC0gZ2xtKGF0dF9zcGVjLCBmYW1pbHk9Ymlub21pYWwsIGRhdGE9YXR0d29yaykNCnByaW50KHN1bW1hcnkoYXR0X2ZpdCkpDQoNCmBgYA0KDQpQcmludGluZyBBTk9WQSB0ZXN0cw0KDQpgYGB7ciBldmFsPVRSVUUsIGVjaG89RkFMU0V9DQpwcmludChhbm92YShhdHRfZml0LCB0ZXN0PSJDaGlzcSIpKQ0KDQpgYGANCg0KQ29tcHV0ZSBwcmVkaWN0ZWQgcHJvYmFiaWxpdHkgb2Ygc3dpdGNoaW5nIHNlcnZpY2UgcHJvdmlkZXJzDQoNCmBgYHtyIGV2YWw9VFJVRSwgZWNobz1GQUxTRX0NCiMgY29tcHV0ZSBwcmVkaWN0ZWQgcHJvYmFiaWxpdHkgb2Ygc3dpdGNoaW5nIHNlcnZpY2UgcHJvdmlkZXJzIA0KYXR0d29yayRQcmVkaWN0X1Byb2JfU3dpdGNoaW5nIDwtIHByZWRpY3QuZ2xtKGF0dF9maXQsIHR5cGUgPSAicmVzcG9uc2UiKSANCmBgYA0KDQpQbG90dGluZyBQcmVkaWN0ZWQgUHJvYmFiaWxpdHkgb2YgU3dpdGNoaW5nDQoNCmBgYHtyIGV2YWw9VFJVRSwgZWNobz1GQUxTRX0NCnBkZihmaWxlID0gImZpZ19yZXRhaW5pbmdfY3VzdG9tZXJzX2xvZ19yZWdfZGVuc2l0eV9ldmFsdWF0aW9uLnBkZiIsIA0KICAgIHdpZHRoID0gOC41LCBoZWlnaHQgPSA4LjUpDQoNCnBsb3R0aW5nX29iamVjdCA8LSBkZW5zaXR5cGxvdCggfiBQcmVkaWN0X1Byb2JfU3dpdGNoaW5nIHwgcGljaywgDQogICAgICAgICAgICAgICBkYXRhID0gYXR0d29yaywgDQogICAgICAgICAgICAgICBsYXlvdXQgPSBjKDEsMiksIGFzcGVjdD0xLCBjb2wgPSAiZGFya2JsdWUiLCANCiAgICAgICAgICAgICAgIHBsb3QucG9pbnRzID0gInJ1ZyIsDQogICAgICAgICAgICAgICBzdHJpcD1mdW5jdGlvbiguLi4pIHN0cmlwLmRlZmF1bHQoLi4uLCBzdHlsZT0xKSwNCiAgICAgICAgICAgICAgIHhsYWI9IlByZWRpY3RlZCBQcm9iYWJpbGl0eSBvZiBTd2l0Y2hpbmciKSANCg0KcHJpbnQocGxvdHRpbmdfb2JqZWN0KSANCg0KDQpgYGANCg0KYGBge3IgZXZhbD1UUlVFLCBlY2hvPUZBTFNFfQ0KIyB1c2UgYSAwLjUgY3V0LW9mZiBpbiB0aGlzIHByb2JsZW0NCmF0dHdvcmskUHJlZGljdF9QaWNrIDwtIA0KICAgIGlmZWxzZSgoYXR0d29yayRQcmVkaWN0X1Byb2JfU3dpdGNoaW5nID4gMC41KSwgMiwgMSkNCg0KYXR0d29yayRQcmVkaWN0X1BpY2sgPC0gZmFjdG9yKGF0dHdvcmskUHJlZGljdF9QaWNrLA0KICAgIGxldmVscyA9IGMoMSwgMiksIGxhYmVscyA9IGMoIkFUJlQiLCAiT0NDIikpICANCg0KY29uZnVzaW9uX21hdHJpeCA8LSB0YWJsZShhdHR3b3JrJFByZWRpY3RfUGljaywgYXR0d29yayRwaWNrKQ0KY2F0KCJcbkNvbmZ1c2lvbiBNYXRyaXggKHJvd3M9UHJlZGljdGVkIFNlcnZpY2UgUHJvdmlkZXIsIiwNCiAgICJjb2x1bW5zPUFjdHVhbCBTZXJ2aWNlIFByb3ZpZGVyXG4iKQ0KDQpwcmludChjb25mdXNpb25fbWF0cml4KQ0KDQpgYGANCg0KYGBge3IgZXZhbD1UUlVFLCBlY2hvPUZBTFNFfQ0KcHJlZGljdGl2ZV9hY2N1cmFjeSA8LSAoY29uZnVzaW9uX21hdHJpeFsxLDFdICsgY29uZnVzaW9uX21hdHJpeFsyLDJdKS8NCiAgICAgICAgICAgICAgICAgICAgICAgIHN1bShjb25mdXNpb25fbWF0cml4KSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCg0KY2F0KCJcblBlcmNlbnQgQWNjdXJhY3k6ICIsIHJvdW5kKHByZWRpY3RpdmVfYWNjdXJhY3kgKiAxMDAsIGRpZ2l0cyA9IDEpKQ0KYGBgDQoNCmBgYHtyIGV2YWw9VFJVRSwgZWNobz1GQUxTRX0NCiMgbW9zYWljIHJlbmRlcmluZyBvZiB0aGUgY2xhc3NpZmllciB3aXRoIDAuMTAgY3V0b2ZmDQp3aXRoKGF0dHdvcmssIHByaW50KHRhYmxlKFByZWRpY3RfUGljaywgcGljaywgdXNlTkEgPSBjKCJhbHdheXMiKSkpKQ0KYGBgDQoNClBsb3QgcHJlZGljdGVkIFNlcnZpY2UgUHJvdmlkZXIgKDUwIHBlcmNlbnQgY3V0LW9mZikNCg0KYGBge3IgZXZhbD1UUlVFLCBlY2hvPUZBTFNFfQ0KcGRmKGZpbGUgPSAiZmlnX3JldGFpbmluZ19jdXN0b21lcnNfY29uZnVzaW9uX21vc2FpY181MF9wZXJjZW50LnBkZiIsIA0KICAgIHdpZHRoID0gOC41LCBoZWlnaHQgPSA4LjUpDQoNCm1vc2FpYyggfiBQcmVkaWN0X1BpY2sgKyBwaWNrLCBkYXRhID0gYXR0d29yaywNCiAgbGFiZWxpbmdfYXJncyA9IGxpc3Qoc2V0X3Zhcm5hbWVzID0gDQogIGMoUHJlZGljdF9QaWNrID0gDQogICAgICAiUHJlZGljdGVkIFNlcnZpY2UgUHJvdmlkZXIgKDUwIHBlcmNlbnQgY3V0LW9mZikiLA0KICAgICAgIHBpY2sgPSAiQWN0dWFsIFNlcnZpY2UgUHJvdmlkZXIiKSksDQogIGhpZ2hsaWdodGluZyA9IGMoIlByZWRpY3RfUGljayIsICJwaWNrIiksDQogIGhpZ2hsaWdodGluZ19maWxsID0gYygiZ3JlZW4iLCJjb3Juc2lsayIsImNvcm5zaWxrIiwiZ3JlZW4iKSwNCiAgcm90X2xhYmVscyA9IGMobGVmdCA9IDAsIHRvcCA9IDApLA0KICBwb3NfbGFiZWxzID0gYygiY2VudGVyIiwiY2VudGVyIiksDQogIG9mZnNldF9sYWJlbHMgPSBjKDAuMCwwLjYpKQ0KDQoNCg0KYGBgDQoNClBsb3RpbmcgY2xhc3NpZmljYXRpb24gdHJlZSByZXN1bHQgZnJvbSBycGFydA0KDQpgYGB7ciBldmFsPVRSVUUsIGVjaG89RkFMU0V9DQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIGV4YW1wbGUgb2YgdHJlZS1zdHJ1Y3R1cmVkIGNsYXNzaWZpY2F0aW9uIA0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KYXR0X3RyZWVfZml0IDwtIHJwYXJ0KGF0dF9zcGVjLCBkYXRhID0gYXR0d29yaywgDQogICAgY29udHJvbCA9IHJwYXJ0LmNvbnRyb2woY3AgPSAwLjAwMjUpKQ0KDQojIHBsb3QgY2xhc3NpZmljYXRpb24gdHJlZSByZXN1bHQgZnJvbSBycGFydA0KcGRmKGZpbGUgPSAiZmlnX3JldGFpbmluZ19jdXN0b21lcnNfdHJlZV9jbGFzc2lmaWVyLnBkZiIsIA0KICAgIHdpZHRoID0gOC41LCBoZWlnaHQgPSA4LjUpDQoNCnBycChhdHRfdHJlZV9maXQsIG1haW49IiIsDQogICAgZGlnaXRzID0gMywgICMgZGlnaXRzIHRvIGRpc3BsYXkgaW4gdGVybWluYWwgbm9kZXMNCiAgICBubiA9IFRSVUUsICAjIGRpc3BsYXkgdGhlIG5vZGUgbnVtYmVycw0KICAgIGJyYW5jaCA9IDAuNSwgICMgY2hhbmdlIGFuZ2xlIG9mIGJyYW5jaCBsaW5lcw0KICAgIGJyYW5jaC5sd2QgPSAyLCAgIyB3aWR0aCBvZiBicmFuY2ggbGluZXMNCiAgICBmYWNsZW4gPSAwLCAgIyBkbyBub3QgYWJicmV2aWF0ZSBmYWN0b3IgbGV2ZWxzDQogICAgdHJhY2UgPSAxLCAgIyBwcmludCB0aGUgYXV0b21hdGljYWxseSBjYWxjdWxhdGVkIGNleA0KICAgIHNoYWRvdy5jb2wgPSAwLCAgIyBubyBzaGFkb3dzIHVuZGVyIHRoZSBsZWF2ZXMNCiAgICBicmFuY2gubHR5ID0gMSwgICMgZHJhdyBicmFuY2hlcyB1c2luZyBkb3R0ZWQgbGluZXMNCiAgICBzcGxpdC5jZXggPSAxLjIsICAjIG1ha2UgdGhlIHNwbGl0IHRleHQgbGFyZ2VyIHRoYW4gdGhlIG5vZGUgdGV4dA0KICAgIHNwbGl0LnByZWZpeCA9ICJpcyAiLCAgIyBwdXQgImlzIiBiZWZvcmUgc3BsaXQgdGV4dA0KICAgIHNwbGl0LnN1ZmZpeCA9ICI/IiwgICMgcHV0ICI/IiBhZnRlciBzcGxpdCB0ZXh0DQogICAgc3BsaXQuYm94LmNvbCA9ICJibHVlIiwgICMgbGlnaHRncmF5IHNwbGl0IGJveGVzIChkZWZhdWx0IGlzIHdoaXRlKQ0KICAgIHNwbGl0LmNvbCA9ICJ3aGl0ZSIsICAjIGNvbG9yIG9mIHRleHQgaW4gc3BsaXQgYm94IA0KICAgIHNwbGl0LmJvcmRlci5jb2wgPSAiYmx1ZSIsICAjIGRhcmtncmF5IGJvcmRlciBvbiBzcGxpdCBib3hlcw0KICAgIHNwbGl0LnJvdW5kID0gLjI1KSAgIyByb3VuZCB0aGUgc3BsaXQgYm94IGNvcm5lcnMgYSB0YWQNCg0KDQoNCmBgYA0KDQpWaXN1YWwgb2YgZml0IHJhbmRvbSBmb3Jlc3QgbW9kZWwgdG8gdGhlIHRyYWluaW5nIGRhdGENCg0KYGBge3IgZXZhbD1UUlVFLCBlY2hvPUZBTFNFfQ0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgZXhhbXBsZSBvZiByYW5kb20gZm9yZXN0IG1vZGVsIGZvciBpbXBvcnRhbmNlDQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyBmaXQgcmFuZG9tIGZvcmVzdCBtb2RlbCB0byB0aGUgdHJhaW5pbmcgZGF0YQ0Kc2V0LnNlZWQgKDk5OTkpICAjIGZvciByZXByb2R1Y2liaWxpdHkNCg0KYXR0d29ya19yZl9maXQgPC0gcmFuZG9tRm9yZXN0KGF0dF9zcGVjLCBkYXRhID0gYXR0d29yaywgDQogICBtdHJ5PTMsIGltcG9ydGFuY2U9VFJVRSwgbmEuYWN0aW9uPW5hLm9taXQpIA0KDQojIGNoZWNrIGltcG9ydGFuY2Ugb2YgdGhlIGluZGl2aWR1YWwgZXhwbGFuYXRvcnkgdmFyaWFibGVzIA0KcGRmKGZpbGUgPSAiZmlnX3JldGFpbmluZ19jdXN0b21lcnNfcmFuZG9tX2ZvcmVzdF9pbXBvcnRhbmNlLnBkZiIsIA0Kd2lkdGggPSAxMSwgaGVpZ2h0ID0gOC41KQ0KDQp2YXJJbXBQbG90KGF0dHdvcmtfcmZfZml0LCBtYWluID0gIiIsIHBjaCA9IDIwLCBjZXggPSAxLjI1KQ0KDQoNCmBgYA0KDQpgYGB7ciBldmFsPVRSVUUsIGVjaG89RkFMU0V9DQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyB0cmFpbmluZy1hbmQtdGVzdCBmb3IgZXZhbHVhdGluZyBhbHRlcm5hdGl2ZSBtb2RlbGluZyBtZXRob2RzIA0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCnNldC5zZWVkKDIwMjApDQoNCnBhcnRpdGlvbiA8LSBzYW1wbGUobnJvdyhhdHR3b3JrKSkgIyBwZXJtdXRlZCBsaXN0IG9mIHJvdyBpbmRleCBudW1iZXJzDQoNCmF0dHdvcmskZ3JvdXAgPC0gaWZlbHNlKChwYXJ0aXRpb24gPCBucm93KGF0dHdvcmspLygzLzIpKSwxLDIpDQoNCmF0dHdvcmskZ3JvdXAgPC0gZmFjdG9yKGF0dHdvcmskZ3JvdXAsIGxldmVscz1jKDEsMiksIA0KICAgIGxhYmVscz1jKCJUUkFJTiIsIlRFU1QiKSkNCg0KdHJhaW4gPC0gc3Vic2V0KGF0dHdvcmssIHN1YnNldCA9IChncm91cCA9PSAiVFJBSU4iKSwgDQogICAgc2VsZWN0ID0gYygicGljayIsICJ1c2FnZSIsICJyZWFjaG91dCIsICJjYXJkIikpDQoNCnRlc3QgPC0gc3Vic2V0KGF0dHdvcmssIHN1YnNldCA9IChncm91cCA9PSAiVEVTVCIpLCANCiAgICBzZWxlY3QgPSBjKCJwaWNrIiwgInVzYWdlIiwgInJlYWNob3V0IiwgImNhcmQiKSkNCg0KYGBgDQoNCkVuc3VyaW5nIGNvbXBsZXRlIGRhdGEgaW4gYm90aCBwYXJ0aXRpb25zIHdlcmUgY3JlYXRlZA0KDQpgYGB7ciBldmFsPVRSVUUsIGVjaG89RkFMU0V9DQojIGVuc3VyZSBjb21wbGV0ZSBkYXRhIGluIGJvdGggcGFydGl0aW9ucw0KdHJhaW4gPC0gbmEub21pdCh0cmFpbikNCnRlc3QgPC0gbmEub21pdCh0ZXN0KQ0KDQojIGNoZWNrIHBhcnRpdGlvbnMgZm9yIG5vLW92ZXJsYXAgYW5kIGNvcnJlY3QgcGljayBmcmVxdWVuY2llcw0KaWYobGVuZ3RoKGludGVyc2VjdChyb3duYW1lcyh0cmFpbiksIHJvd25hbWVzKHRlc3QpKSkgIT0gMCkgDQogICAgcHJpbnQoIlxuUHJvYmxlbSB3aXRoIHBhcnRpdGlvbiIpICANCg0KcHJpbnQodGFibGUoYXR0d29yayRwaWNrKSkNCg0KYGBgDQoNCmBgYHtyIGV2YWw9VFJVRSwgZWNobz1GQUxTRX0NCnByaW50KHRhYmxlKHRlc3QkcGljaykpIA0KDQpgYGANCg0KYGBge3IgZXZhbD1UUlVFLCBlY2hvPUZBTFNFfQ0KcHJpbnQodGFibGUodHJhaW4kcGljaykpICANCmBgYA0KDQpgYGB7ciBldmFsPVRSVUUsIGVjaG89RkFMU0V9DQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIExvZ2lzdGljIHJlZ3Jlc3Npb24gdHJhaW5pbmctYW5kLXRlc3QNCiMgYXVjID0gYXJlYSB1bmRlciBST0MgY3VydmUNCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgZml0IGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWwgdG8gdGhlIHRyYWluaW5nIHNldCANCnRyYWluX2xyX2ZpdCA8LSBnbG0oYXR0X3NwZWMsIGZhbWlseT1iaW5vbWlhbCwgZGF0YT10cmFpbikNCnRyYWluJGxyX3ByZWRpY3RfcHJvYiA8LSBwcmVkaWN0KHRyYWluX2xyX2ZpdCwgdHlwZSA9ICJyZXNwb25zZSIpDQp0cmFpbl9scl9wcmVkaWN0aW9uIDwtIHByZWRpY3Rpb24odHJhaW4kbHJfcHJlZGljdF9wcm9iLCB0cmFpbiRwaWNrKQ0KdHJhaW5fbHJfYXVjIDwtIGFzLm51bWVyaWMocGVyZm9ybWFuY2UodHJhaW5fbHJfcHJlZGljdGlvbiwgImF1YyIpQHkudmFsdWVzKQ0KDQpgYGANCg0KYGBge3IgZXZhbD1UUlVFLCBlY2hvPUZBTFNFfQ0KIyB1c2UgbW9kZWwgZml0IHRvIHRyYWluaW5nIHNldCB0byBldmFsdWF0ZSBvbiB0ZXN0IGRhdGENCnRlc3QkbHJfcHJlZGljdF9wcm9iIDwtIGFzLm51bWVyaWMocHJlZGljdCh0cmFpbl9scl9maXQsIG5ld2RhdGEgPSB0ZXN0LCANCiAgICB0eXBlID0gInJlc3BvbnNlIikpDQp0ZXN0X2xyX3ByZWRpY3Rpb24gPC0gcHJlZGljdGlvbih0ZXN0JGxyX3ByZWRpY3RfcHJvYiwgdGVzdCRwaWNrKQ0KdGVzdF9scl9hdWMgPC0gYXMubnVtZXJpYyhwZXJmb3JtYW5jZSh0ZXN0X2xyX3ByZWRpY3Rpb24sICJhdWMiKUB5LnZhbHVlcykNCg0KYGBgDQoNClBsb3R0aW5nIFJPQyBmb3IgbG9naXN0aWMgcmVncmVzc2lvbg0KDQpgYGB7ciBldmFsPVRSVUUsIGVjaG89RkFMU0V9DQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgUk9DIGZvciBsb2dpc3RpYyByZWdyZXNzaW9uDQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCnRyYWluX2xyX3JvYyA8LSBwZXJmb3JtYW5jZSh0cmFpbl9scl9wcmVkaWN0aW9uLCAidHByIiwgImZwciIpDQp0ZXN0X2xyX3JvYyA8LSBwZXJmb3JtYW5jZSh0ZXN0X2xyX3ByZWRpY3Rpb24sICJ0cHIiLCAiZnByIikNCnBkZihmaWxlID0gImZpZ19yZXRhaW5pbmdfY3VzdG9tZXJzX2xvZ2lzdGljX3JlZ3Jlc3Npb25fcm9jLnBkZiIsIA0KICAgIHdpZHRoID0gOC41LCBoZWlnaHQgPSA4LjUpDQoNCnBsb3Rfcm9jKHRyYWluX3JvYyA9IHRyYWluX2xyX3JvYywgDQogICAgdHJhaW5fYXVjID0gdHJhaW5fbHJfYXVjLCANCiAgICB0ZXN0X3JvYyA9IHRlc3RfbHJfcm9jLCANCiAgICB0ZXN0X2F1YyA9IHRlc3RfbHJfYXVjKSAgICAgICANCiAgICANCg0KYGBgDQoNCmBgYHtyIGV2YWw9VFJVRSwgZWNobz1GQUxTRX0NCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyBTdXBwb3J0IHZlY3RvciBtYWNoaW5lIHRyYWluaW5nLWFuZC10ZXN0DQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCnNldC5zZWVkICg5OTk5KSAgIyBmb3IgcmVwcm9kdWNpYmlsaXR5DQoNCiMgZGV0ZXJtaW5lIHR1bmluZyBwYXJhbWV0ZXJzIHByaW9yIHRvIGZpdHRpbmcgbW9kZWwgdG8gdHJhaW5pbmcgc2V0DQp0cmFpbl9zdm1fdHVuZSA8LSB0dW5lKHN2bSwgYXR0X3NwZWMsIGRhdGEgPSB0cmFpbiwNCiAgICAgICAgICAgICAgICAgICByYW5nZXMgPSBsaXN0KGdhbW1hID0gMl4oLTg6MSksIGNvc3QgPSAyXigwOjQpKSwNCiAgICAgICAgICAgICAgICAgICB0dW5lY29udHJvbCA9IHR1bmUuY29udHJvbChzYW1wbGluZyA9ICJmaXgiKSkNCg0KYGBgDQoNCmBgYHtyIGV2YWw9VFJVRSwgZWNobz1GQUxTRX0NCiMgZml0IHRoZSBzdXBwb3J0IHZlY3RvciBtYWNoaW5lIHRvIHRoZSB0cmFpbmluZyBzZXQgdXNpbmcgdHVuaW5nIHBhcmFtZXRlcnMNCnRyYWluX3N2bV9maXQgPC0gc3ZtKGF0dF9zcGVjLCBkYXRhID0gdHJhaW4sIA0KICAgIGNvc3QgPSB0cmFpbl9zdm1fdHVuZSRiZXN0LnBhcmFtZXRlcnMkY29zdCwgDQogICAgZ2FtbWE9dHJhaW5fc3ZtX3R1bmUkYmVzdC5wYXJhbWV0ZXJzJGdhbW1hLCANCiAgICBwcm9iYWJpbGl0eSA9IFRSVUUpICANCg0KdHJhaW5fc3ZtX3ByZWRpY3QgPC0gcHJlZGljdCh0cmFpbl9zdm1fZml0LCB0cmFpbiwgcHJvYmFiaWxpdHkgPSBUUlVFKQ0KdHJhaW4kc3ZtX3ByZWRpY3RfcHJvYiA8LSBhdHRyKHRyYWluX3N2bV9wcmVkaWN0LCAicHJvYmFiaWxpdGllcyIpWywxXQ0KdHJhaW5fc3ZtX3ByZWRpY3Rpb24gPC0gcHJlZGljdGlvbih0cmFpbiRzdm1fcHJlZGljdF9wcm9iLCB0cmFpbiRwaWNrKQ0KdHJhaW5fc3ZtX2F1YyA8LSBhcy5udW1lcmljKHBlcmZvcm1hbmNlKHRyYWluX3N2bV9wcmVkaWN0aW9uLCAiYXVjIilAeS52YWx1ZXMpDQoNCmBgYA0KDQpgYGB7ciBldmFsPVRSVUUsIGVjaG89RkFMU0V9DQojIHVzZSBtb2RlbCBmaXQgdG8gdHJhaW5pbmcgZGF0YSB0byBldmFsdWF0ZSBvbiB0ZXN0IHNldA0KdGVzdF9zdm1fcHJlZGljdCA8LSBwcmVkaWN0KHRyYWluX3N2bV9maXQsIHRlc3QsIHByb2JhYmlsaXR5ID0gVFJVRSkNCnRlc3Qkc3ZtX3ByZWRpY3RfcHJvYiA8LSBhdHRyKHRlc3Rfc3ZtX3ByZWRpY3QsICJwcm9iYWJpbGl0aWVzIilbLDFdDQp0ZXN0X3N2bV9wcmVkaWN0aW9uIDwtIHByZWRpY3Rpb24odGVzdCRzdm1fcHJlZGljdF9wcm9iLCB0ZXN0JHBpY2spDQp0ZXN0X3N2bV9hdWMgPC0gYXMubnVtZXJpYyhwZXJmb3JtYW5jZSh0ZXN0X3N2bV9wcmVkaWN0aW9uLCAiYXVjIilAeS52YWx1ZXMpDQoNCmBgYA0KDQpQbG90dGluZyBST0MgZm9yIHN1cHBvcnQgdmVjdG9yIG1hY2hpbmVzDQoNCmBgYHtyIGV2YWw9VFJVRSwgZWNobz1GQUxTRX0NCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgUk9DIGZvciBzdXBwb3J0IHZlY3RvciBtYWNoaW5lcw0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KdHJhaW5fc3ZtX3JvYyA8LSBwZXJmb3JtYW5jZSh0cmFpbl9zdm1fcHJlZGljdGlvbiwgInRwciIsICJmcHIiKQ0KdGVzdF9zdm1fcm9jIDwtIHBlcmZvcm1hbmNlKHRlc3Rfc3ZtX3ByZWRpY3Rpb24sICJ0cHIiLCAiZnByIikNCg0KcGRmKGZpbGUgPSAiZmlnX3JldGFpbmluZ19jdXN0b21lcnNfc3VwcG9ydF92ZWN0b3JfbWFjaGluZV9yb2MucGRmIiwgDQogICAgd2lkdGggPSA4LjUsIGhlaWdodCA9IDguNSkNCg0KcGxvdF9yb2ModHJhaW5fcm9jID0gdHJhaW5fc3ZtX3JvYywgDQogICAgdHJhaW5fYXVjID0gdHJhaW5fc3ZtX2F1YywgDQogICAgdGVzdF9yb2MgPSB0ZXN0X3N2bV9yb2MsIA0KICAgIHRlc3RfYXVjID0gdGVzdF9zdm1fYXVjKSAgICANCg0KDQpgYGANCg0KDQpgYGB7ciBldmFsPVRSVUUsIGVjaG89RkFMU0V9DQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgUmFuZG9tIGZvcmVzdCB0cmFpbmluZy1hbmQtdGVzdA0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQpzZXQuc2VlZCAoOTk5OSkgICMgZm9yIHJlcHJvZHVjaWJpbGl0eQ0KdHJhaW5fcmZfZml0IDwtIHJhbmRvbUZvcmVzdChhdHRfc3BlYywgZGF0YSA9IHRyYWluLCANCiAgIG10cnk9MywgaW1wb3J0YW5jZT1GQUxTRSwgbmEuYWN0aW9uPW5hLm9taXQpIA0KDQp0cmFpbiRyZl9wcmVkaWN0X3Byb2IgPC0gYXMubnVtZXJpYyhwcmVkaWN0KHRyYWluX3JmX2ZpdCwgdHlwZSA9ICJwcm9iIilbLDJdKQ0KdHJhaW5fcmZfcHJlZGljdGlvbiA8LSBwcmVkaWN0aW9uKHRyYWluJHJmX3ByZWRpY3RfcHJvYiwgdHJhaW4kcGljaykNCnRyYWluX3JmX2F1YyA8LSBhcy5udW1lcmljKHBlcmZvcm1hbmNlKHRyYWluX3JmX3ByZWRpY3Rpb24sICJhdWMiKUB5LnZhbHVlcykNCg0KYGBgDQoNCmBgYHtyIGV2YWw9VFJVRSwgZWNobz1GQUxTRX0NCiMgdXNlIG1vZGVsIGZpdCB0byB0cmFpbmluZyBzZXQgdG8gZXZhbHVhdGUgb24gdGVzdCBkYXRhDQp0ZXN0JHJmX3ByZWRpY3RfcHJvYiA8LSBhcy5udW1lcmljKHByZWRpY3QodHJhaW5fcmZfZml0LCBuZXdkYXRhID0gdGVzdCwgDQogICAgdHlwZSA9ICJwcm9iIilbLDJdKQ0KDQp0ZXN0X3JmX3ByZWRpY3Rpb24gPC0gcHJlZGljdGlvbih0ZXN0JHJmX3ByZWRpY3RfcHJvYiwgdGVzdCRwaWNrKQ0KdGVzdF9yZl9hdWMgPC0gYXMubnVtZXJpYyhwZXJmb3JtYW5jZSh0ZXN0X3JmX3ByZWRpY3Rpb24sICJhdWMiKUB5LnZhbHVlcykNCg0KYGBgDQoNClBsb3R0aW5nIFJPQyBmb3IgcmFuZG9tIGZvcmVzdA0KDQpgYGB7ciBldmFsPVRSVUUsIGVjaG89RkFMU0V9DQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIFJPQyBmb3IgcmFuZG9tIGZvcmVzdA0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KdHJhaW5fcmZfcm9jIDwtIHBlcmZvcm1hbmNlKHRyYWluX3JmX3ByZWRpY3Rpb24sICJ0cHIiLCAiZnByIikNCnRlc3RfcmZfcm9jIDwtIHBlcmZvcm1hbmNlKHRlc3RfcmZfcHJlZGljdGlvbiwgInRwciIsICJmcHIiKQ0KDQpwZGYoZmlsZSA9ICJmaWdfcmV0YWluaW5nX2N1c3RvbWVyc19yYW5kb21fZm9yZXN0X3JvYy5wZGYiLCANCiAgICB3aWR0aCA9IDguNSwgaGVpZ2h0ID0gOC41KQ0KDQpwbG90X3JvYyh0cmFpbl9yb2MgPSB0cmFpbl9yZl9yb2MsIA0KICAgIHRyYWluX2F1YyA9IHRyYWluX3JmX2F1YywgDQogICAgdGVzdF9yb2MgPSB0ZXN0X3JmX3JvYywgDQogICAgdGVzdF9hdWMgPSB0ZXN0X3JmX2F1YykgIA0KDQpgYGANCg0KYGBge3IgZXZhbD1UUlVFLCBlY2hvPUZBTFNFfQ0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIE5haXZlIEJheWVzIHRyYWluaW5nLWFuZC10ZXN0DQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCnNldC5zZWVkICg5OTk5KSAgIyBmb3IgcmVwcm9kdWNpYmlsaXR5DQp0cmFpbl9uYl9maXQgPC0gbmFpdmVCYXllcyhhdHRfc3BlYywgZGF0YSA9IHRyYWluKSANCnRyYWluJG5iX3ByZWRpY3RfcHJvYiA8LSBhcy5udW1lcmljKHByZWRpY3QodHJhaW5fbmJfZml0LCBuZXdkYXRhID0gdHJhaW4sDQogICAgdHlwZSA9ICJyYXciKVssMl0pDQp0cmFpbl9uYl9wcmVkaWN0aW9uIDwtIHByZWRpY3Rpb24odHJhaW4kbmJfcHJlZGljdF9wcm9iLCB0cmFpbiRwaWNrKQ0KdHJhaW5fbmJfYXVjIDwtIGFzLm51bWVyaWMocGVyZm9ybWFuY2UodHJhaW5fbmJfcHJlZGljdGlvbiwgImF1YyIpQHkudmFsdWVzKQ0KYGBgDQoNCmBgYHtyIGV2YWw9VFJVRSwgZWNobz1GQUxTRX0NCiMgdXNlIG1vZGVsIGZpdCB0byB0cmFpbmluZyBzZXQgdG8gZXZhbHVhdGUgb24gdGVzdCBkYXRhDQp0ZXN0JG5iX3ByZWRpY3RfcHJvYiA8LSBhcy5udW1lcmljKHByZWRpY3QodHJhaW5fbmJfZml0LCBuZXdkYXRhID0gdGVzdCwgDQogICAgdHlwZSA9ICJyYXciKVssMl0pDQp0ZXN0X25iX3ByZWRpY3Rpb24gPC0gcHJlZGljdGlvbih0ZXN0JG5iX3ByZWRpY3RfcHJvYiwgdGVzdCRwaWNrKQ0KdGVzdF9uYl9hdWMgPC0gYXMubnVtZXJpYyhwZXJmb3JtYW5jZSh0ZXN0X25iX3ByZWRpY3Rpb24sICJhdWMiKUB5LnZhbHVlcykNCg0KYGBgDQoNClBsb3R0aW5nIFJPQyBmb3IgTmFpdmUgQmF5ZXMNCg0KYGBge3IgZXZhbD1UUlVFLCBlY2hvPUZBTFNFfQ0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyBST0MgZm9yIE5haXZlIEJheWVzDQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQp0cmFpbl9uYl9yb2MgPC0gcGVyZm9ybWFuY2UodHJhaW5fbmJfcHJlZGljdGlvbiwgInRwciIsICJmcHIiKQ0KdGVzdF9uYl9yb2MgPC0gcGVyZm9ybWFuY2UodGVzdF9uYl9wcmVkaWN0aW9uLCAidHByIiwgImZwciIpDQoNCnBkZihmaWxlID0gImZpZ19yZXRhaW5pbmdfY3VzdG9tZXJzX25haXZlX2JheWVzX3JvYy5wZGYiLCANCiAgICB3aWR0aCA9IDguNSwgaGVpZ2h0ID0gOC41KQ0KDQpwbG90X3JvYyh0cmFpbl9yb2MgPSB0cmFpbl9uYl9yb2MsIA0KICAgIHRyYWluX2F1YyA9IHRyYWluX25iX2F1YywgDQogICAgdGVzdF9yb2MgPSB0ZXN0X25iX3JvYywgDQogICAgdGVzdF9hdWMgPSB0ZXN0X25iX2F1YykgICAgDQoNCg0KYGBgDQoNCmBgYHtyIGV2YWw9VFJVRSwgZWNobz1GQUxTRX0NCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyBOZXVyYWwgTmV0d29yayB0cmFpbmluZy1hbmQtdGVzdA0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQpzZXQuc2VlZCAoOTk5OSkgICMgZm9yIHJlcHJvZHVjaWJpbGl0eQ0KdHJhaW5fbm5ldF9maXQgPC0gbm5ldChhdHRfc3BlYywgZGF0YSA9IHRyYWluLCBzaXplID0gMywgZGVjYXkgPSAwLjAsDQogICAgcHJvYmFiaWxpdHkgPSBUUlVFLCB0cmFjZSA9IEZBTFNFKSANCg0KdHJhaW4kbm5ldF9wcmVkaWN0X3Byb2IgPC0gYXMubnVtZXJpYyhwcmVkaWN0KHRyYWluX25uZXRfZml0LCBuZXdkYXRhID0gdHJhaW4pKQ0KdHJhaW5fbm5ldF9wcmVkaWN0aW9uIDwtIHByZWRpY3Rpb24odHJhaW4kbm5ldF9wcmVkaWN0X3Byb2IsIHRyYWluJHBpY2spDQp0cmFpbl9ubmV0X2F1YyA8LSBhcy5udW1lcmljKHBlcmZvcm1hbmNlKHRyYWluX25uZXRfcHJlZGljdGlvbiwgImF1YyIpQHkudmFsdWVzKQ0KYGBgDQoNCmBgYHtyIGV2YWw9VFJVRSwgZWNobz1GQUxTRX0NCiMgdXNlIG1vZGVsIGZpdCB0byB0cmFpbmluZyBzZXQgdG8gZXZhbHVhdGUgb24gdGVzdCBkYXRhDQp0ZXN0JG5uZXRfcHJlZGljdF9wcm9iIDwtIGFzLm51bWVyaWMocHJlZGljdCh0cmFpbl9ubmV0X2ZpdCwgbmV3ZGF0YSA9IHRlc3QpKQ0KdGVzdF9ubmV0X3ByZWRpY3Rpb24gPC0gcHJlZGljdGlvbih0ZXN0JG5uZXRfcHJlZGljdF9wcm9iLCB0ZXN0JHBpY2spDQp0ZXN0X25uZXRfYXVjIDwtIGFzLm51bWVyaWMocGVyZm9ybWFuY2UodGVzdF9ubmV0X3ByZWRpY3Rpb24sICJhdWMiKUB5LnZhbHVlcykNCmBgYA0KDQpQbG90dGluZyBST0MgZm9yIE5ldXJhbCBOZXR3b3JrDQoNCmBgYHtyIGV2YWw9VFJVRSwgZWNobz1GQUxTRX0NCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgUk9DIGZvciBOZXVyYWwgTmV0d29yaw0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KdHJhaW5fbm5ldF9yb2MgPC0gcGVyZm9ybWFuY2UodHJhaW5fbm5ldF9wcmVkaWN0aW9uLCAidHByIiwgImZwciIpDQp0ZXN0X25uZXRfcm9jIDwtIHBlcmZvcm1hbmNlKHRlc3Rfbm5ldF9wcmVkaWN0aW9uLCAidHByIiwgImZwciIpDQoNCnBkZihmaWxlID0gImZpZ19yZXRhaW5pbmdfY3VzdG9tZXJzX25ldXJhbF9uZXR3b3JrX3JvYy5wZGYiLCANCiAgICB3aWR0aCA9IDguNSwgaGVpZ2h0ID0gOC41KQ0KDQpwbG90X3JvYyh0cmFpbl9yb2MgPSB0cmFpbl9ubmV0X3JvYywgdHJhaW5fYXVjID0gdHJhaW5fbm5ldF9hdWMsIA0KICAgIHRlc3Rfcm9jID0gdGVzdF9ubmV0X3JvYywgdGVzdF9hdWMgPSB0ZXN0X25uZXRfYXVjKSAgIA0KDQoNCmBgYA0K