Objective of the project is to analyze the impact of factors such as brand, type of product etc on the mode of payment. Analyzing the price of the product along the same factors also helps the management to deduce insights on the customer behavior.

Understanding the dataset

There are 29 different variables in the dataset with 45898 observations. One sample observation is listed below

setwd("~/Downloads")
The working directory was changed to /Users/Ramya/Downloads inside a notebook chunk. The working directory will be reset when the chunk is finished running. Use the knitr root.dir option in the setup chunk to change the the working directory for notebook chunks.
ecommrough<-read.csv('PromotionDataV4.csv')
colnames(ecommrough)
 [1] "OrderItemCode"       "OrderID"             "OrderDate"           "Category"           
 [5] "SubCategory"         "Brand"               "ProductColor"        "ProductSize"        
 [9] "MRP"                 "FinalTotalPrice"     "VATPercent"          "VAT"                
[13] "CODCharge"           "VendorDiscount"      "WebsiteDiscountCode" "WebsiteDiscount"    
[17] "HasVendorDiscount"   "HasWebsiteDiscount"  "CustomerID"          "COD"                
[21] "ShippingName"        "ShippingCity"        "ShippingState"       "ShippingPincode"    
[25] "ShippingAddressType" "BillingCity"         "BillingState"        "BillingPincode"     
[29] "BillingAddressType" 

Unique count of different variables of interest are as below:

x<-c("Brand","Product Category","Customers","Orders")
y<-c(length(unique(ecommrough$Brand)),length(unique(ecommrough$SubCategory)),length(unique(ecommrough$CustomerID)),length(unique(ecommrough$OrderID)))
z<-rbind(x,y)
z
  [,1]    [,2]               [,3]        [,4]    
x "Brand" "Product Category" "Customers" "Orders"
y "10"    "58"               "31869"     "34913" 

Categorizing Brands

Different brands have various price points. As depicted by the below graph, some brands on an average have higher MRP

brandprice<-aggregate(ecommrough$MRP,by=list(Brand=ecommrough$Brand),FUN=mean)
Brandplot <- plot(brandprice$Brand,brandprice$x,type="p",xlab="Brands",ylab="MRP",Main="Brands and their Prices",pch=6)

Different Brands and their categories are as follows:

brandprice$Type<-ifelse(brandprice$x>=1200,brandprice$Type<-"High",ifelse(brandprice$x>=1000,brandprice$Type<-"Medium",brandprice$Type<-"Low"))
ecommrough$BrandCategory<-ifelse(ecommrough$Brand=="Athena" | ecommrough$Brand=="MISS CHASE" | ecommrough$Brand=="MR BUTTON",ecommrough$BrandCategory<-2,ifelse(ecommrough$Brand=="FABALLEY" | ecommrough$Brand=="HARPA" | ecommrough$Brand=="THE VANCA",ecommrough$BrandCategory<-1,ecommrough$BrandCategory<-0))
brandprice

Effect of Brand on MRP:

Model 1: \(COD = BRAND1*\beta1 + BRAND2*\beta2+.....BRAND10*\beta10+\epsilon\)

Model 2: \(COD = BrandCategory1*\beta1 + BrandCategory2*\beta2+BrandCategory3*\beta3+\epsilon\)

d1<-ecommrough[,c(6,20)]
Model1<-glm(COD ~.,family=binomial(link='logit'),data=d1)
anova(Model1, test="Chisq")
Analysis of Deviance Table

Model: binomial, link: logit

Response: COD

Terms added sequentially (first to last)

      Df Deviance Resid. Df Resid. Dev  Pr(>Chi)    
NULL                  45897      61256              
Brand  9   223.76     45888      61032 < 2.2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
d2<-ecommrough[,c(20,30)]
Model2<-glm(COD ~.,family=binomial(link='logit'),data=d2)
anova(Model2, test="Chisq")
Analysis of Deviance Table

Model: binomial, link: logit

Response: COD

Terms added sequentially (first to last)

              Df Deviance Resid. Df Resid. Dev  Pr(>Chi)    
NULL                          45897      61256              
BrandCategory  2   136.75     45895      61119 < 2.2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Model2 has lesser deviation and is hence a better model. Hence rather than considering independent brands it is better to consider brand categories (high/medium/low)

z<-cbind(aggregate(ecommrough$COD,by=list(ecommrough$BrandCategory),FUN=sum),aggregate(ecommrough$BrandCategory,by=list(ecommrough$BrandCategory),length)[,2])
z$CODShare<-z[,c(2)]*100/z[,c(3)]
colnames(z)<-c("Brand Category", "COD Purchases", "Total Purchases", "% of COD Purchases")
z

It can be noted that as the value of Brand increases COD preference is also increasing.Hence customers prefer COD for more expensive brands

Categorizing Customers

There are two categories of customer based on the frequency: a) Repeat Customer b)Non-Repeating Customer. Since the data is for a limited period, it is not necessary that a non-repeating customer is actually a new customer.

x<-ecommrough$CustomerID[duplicated(ecommrough$CustomerID)]
ecommrough$RepeatCustomer<-ifelse(is.element(ecommrough$CustomerID,x),1,0)
boxplot(ecommrough$MRP~ecommrough$RepeatCustomer,xlab="Repeat Customer",ylab="MRP",Main=" Prices and Customer Frequency",col="powder blue",ylim=c(0,3000))

Model 3: \(COD = \alpha+RepeatCustomer*\beta +\epsilon\)

Model 4: \(MRP = \alpha+RepeatCustomer*\beta + \epsilon\)

d3<-ecommrough[,c(20,31)]
Model3<-glm(COD ~.,family=binomial(link='logit'),data=d3)
anova(Model3, test="Chisq")
Analysis of Deviance Table

Model: binomial, link: logit

Response: COD

Terms added sequentially (first to last)

               Df Deviance Resid. Df Resid. Dev Pr(>Chi)
NULL                           45897      61256         
RepeatCustomer  1   1.7522     45896      61254   0.1856
d4<-ecommrough[,c(9,31)]
Model4<-lm(MRP~RepeatCustomer,data=d4)
summary(Model4)

Call:
lm(formula = MRP ~ RepeatCustomer, data = d4)

Residuals:
    Min      1Q  Median      3Q     Max 
 -794.7  -335.4   -94.7   256.3 10064.6 

Coefficients:
               Estimate Std. Error t value Pr(>|t|)    
(Intercept)    1093.670      3.004  364.13   <2e-16 ***
RepeatCustomer -159.306      4.275  -37.27   <2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 457.9 on 45896 degrees of freedom
Multiple R-squared:  0.02937,   Adjusted R-squared:  0.02935 
F-statistic:  1389 on 1 and 45896 DF,  p-value: < 2.2e-16

Customer Purchase Frequency significantly impacts the price of product purchased. However the choice on mode of payment is independent of customer purchase frequency. The same is indicated by the share of COD in total purchases of repeat v/s new customers.

z1<-cbind(aggregate(ecommrough$COD,by=list(CustomerFrequency=ecommrough$RepeatCustomer),FUN=sum),aggregate(ecommrough$RepeatCustomer,by=list(ecommrough$RepeatCustomer),length)[,2])
z1$CODCustomer<-z1[,c(2)]*100/z1[,c(3)]
z1$CustomerFrequency<-factor(z1$CustomerFrequency,labels = c("Non-Repeat","Repeat"))
colnames(z1)<-c("Customer Type", "COD Purchases", "Total Purchases", "% of COD Purchases")
z1

Pricing

price<-aggregate(ecommrough[10],by=list(ecommrough$OrderID),FUN=sum)
demand<-aggregate(ecommrough[2],by=list(ecommrough$OrderID),FUN=length)
ecomm<-merge(price,demand, by.x="Group.1",by.y="Group.1")
ecomm$revenue<-ecomm$FinalTotalPrice*ecomm$OrderID
colnames(ecomm)<-c("Order ID", "Price", "Demand", "Revenue")
COD<-aggregate(ecommrough[20],by=list(ecommrough$OrderID),FUN=mean)
ecomm<-merge(ecomm,COD, by.x="Order ID",by.y="Group.1")
library(gplots)
plotmeans(ecomm$Price~ecomm$COD, legends = c("Non-COD","COD"),mean.labels=TRUE)

shapiro.test(ecomm$Price[1:5000])

    Shapiro-Wilk normality test

data:  ecomm$Price[1:5000]
W = 0.77411, p-value < 2.2e-16

The data is not normal

boxplot(ecomm$Price~ecomm$COD,names = c("Non-COD","COD"),ylab="Price",main="Average Price v/s Payment Options",col=c("gold","grey"),ylim=c(0,3000))

wilcox.test(ecomm$Price~ecomm$COD)

    Wilcoxon rank sum test with continuity correction

data:  ecomm$Price by ecomm$COD
W = 134560000, p-value < 2.2e-16
alternative hypothesis: true location shift is not equal to 0

Hence we can conclude that there is significant difference in the average product price in payments with/without COD. COD payments are of higher value

Revenue

library(gplots)
plotmeans(ecomm$Revenue~ecomm$COD, legends = c("Non-COD","COD"),mean.labels=TRUE)

shapiro.test(ecomm$Revenue[1:5000])

    Shapiro-Wilk normality test

data:  ecomm$Revenue[1:5000]
W = 0.24022, p-value < 2.2e-16

The data is not normal

boxplot(ecomm$Revenue~ecomm$COD,names = c("Non-COD","COD"),ylab="Revenue",ylim=c(0,10000),main="Average Revenue v/s Payment Options",col=c("gold","grey"))

wilcox.test(ecomm$Revenue~ecomm$COD)

    Wilcoxon rank sum test with continuity correction

data:  ecomm$Revenue by ecomm$COD
W = 136670000, p-value < 2.2e-16
alternative hypothesis: true location shift is not equal to 0

We can conclude that the average revenue per order for the firm under with/without COD payment option is different.

Model 5: \(COD = \alpha+Price*\beta +\epsilon\)

Model 6: \(COD = \alpha+Revenue*\beta + \epsilon\)

d5<-ecomm[,c(2,5)]
Model5<-glm(COD ~.,family=binomial(link='logit'),data=d5)
anova(Model5, test="Chisq")
Analysis of Deviance Table

Model: binomial, link: logit

Response: COD

Terms added sequentially (first to last)

      Df Deviance Resid. Df Resid. Dev  Pr(>Chi)    
NULL                  34912      46513              
Price  1   71.334     34911      46442 < 2.2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
d6<-ecomm[,c(4,5)]
Model6<-glm(COD ~.,family=binomial(link='logit'),data=d6)
anova(Model6, test="Chisq")
Analysis of Deviance Table

Model: binomial, link: logit

Response: COD

Terms added sequentially (first to last)

        Df Deviance Resid. Df Resid. Dev Pr(>Chi)  
NULL                    34912      46513           
Revenue  1   4.0788     34911      46509  0.04343 *
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Deviance of model 2 is significantly lower. However at 1% significance we cannot reject null hypothesis of model 6 that Revenue and COD option are independent. Hence price is a more statistically significant variable than revenue.

Product Category

Different products have various price points and some products on an average have higher MRP

Different Products and their categories are as follows:

productprice<-aggregate(ecommrough$MRP,by=list(Product=ecommrough$SubCategory),FUN=mean)
productprice$PriceCategory<-ifelse(productprice$x>=1200,brandprice$PriceCategory<-"High",ifelse(productprice$x>=1000,productprice$PriceCategory<-"Medium",productprice$PriceCategory<-"Low"))
productprice$Frequency<-aggregate(ecommrough$SubCategory,by=list(Product=ecommrough$SubCategory),FUN=length)[,2]
productprice$Frequency<-ifelse(productprice$Frequency>=1500,brandprice$Frequency<-"High",ifelse(productprice$Frequency>=800,productprice$Frequency<-"Medium",productprice$Frequency<-"Low"))
productprice

Below two product categories are of both high price and high frequency purchase and hence of high value.

Highproduct<-subset(productprice,productprice$PriceCategory=="High"&productprice$Frequency=="High")
ecommrough$HotProducts<-ifelse(ecommrough$SubCategory=="CASUAL SHIRTS" | ecommrough$SubCategory=="DRESSES",ecommrough$HotProducts<-1,ecommrough$HotProducts<-0)
Highproduct

Effect of high value and frequently purchased products on the payment decision

Model 7:

\(COD = \alpha+ProductCategory*\beta +\epsilon\)

d1<-ecommrough[,c(20,32)]
Model7<-glm(COD ~.,family=binomial(link='logit'),data=d1)
anova(Model7, test="Chisq")
Analysis of Deviance Table

Model: binomial, link: logit

Response: COD

Terms added sequentially (first to last)

            Df Deviance Resid. Df Resid. Dev  Pr(>Chi)    
NULL                        45897      61256              
HotProducts  1   64.192     45896      61191 1.129e-15 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Hence, high value product categories do have a significant impact on the purchase decision

z2<-cbind(aggregate(ecommrough$COD,by=list(HighValueProducts=ecommrough$HotProducts),FUN=sum),aggregate(ecommrough$HotProducts,by=list(ecommrough$HotProducts),length)[,2])
z2$CODCustomer<-z2[,c(2)]*100/z2[,c(3)]
z2$HighValueProducts<-factor(z2$HighValueProducts,labels = c("Low Value","High Value"))
colnames(z2)<-c("Product Class", "COD Purchases", "Total Purchases", "% of COD Purchases")
z2

It can be noted that as the value of Brand increases COD preference is also increasing.

Billing & Shipping Address

If billing and shipping address aren’t the same, maybe the customer is buying it for someone as a gift and hence wouldn’t prefer COD. Below we test the same hypothesis

Model 8: \(COD = \alpha+AddressType*\beta +\epsilon\)

bs<-ecommrough[,c(20,34)]
model8 <- glm(COD ~.,family=binomial(link='logit'),data=bs)
anova(model8, test="Chisq")
Analysis of Deviance Table

Model: binomial, link: logit

Response: COD

Terms added sequentially (first to last)

        Df Deviance Resid. Df Resid. Dev  Pr(>Chi)    
NULL                    45897      61256              
address  1   16.191     45896      61239 5.728e-05 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Hence whether or not billing and shipping address is the same significantly impacts the payment mode choice.

z3<-cbind(aggregate(ecommrough$COD,by=list(AddressType=ecommrough$address),FUN=sum),aggregate(ecommrough$address,by=list(ecommrough$address),length)[,2])
z3$CODAddress<-z3[,c(2)]*100/z3[,c(3)]
z3$AddressType-factor(z3$AddressType,levels=c(0,1),labels = c("Not Same","Same"))
'-' not meaningful for factors
[1] NA NA
colnames(z3)<-c("Address Type", "COD Purchases", "Total Purchases", "% of COD Purchases")
z3

Contrary to expectation when the address type is not the same, COD is more preferred. This could mean that there are multiple users possibly of the samehousehold using a single account with different delivery addresses.

Metro

Model 9: \(COD = \alpha+CityType*\beta +\epsilon\)

metrocity<-ecommrough[,c(20,33)]
model9 <- glm(COD ~.,family=binomial(link='logit'),data=metrocity)
anova(model9, test="Chisq")
Analysis of Deviance Table

Model: binomial, link: logit

Response: COD

Terms added sequentially (first to last)

      Df Deviance Resid. Df Resid. Dev  Pr(>Chi)    
NULL                  45897      61256              
metro  1   788.61     45896      60467 < 2.2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
z4<-cbind(aggregate(ecommrough$COD,by=list(MetroCity=ecommrough$metro),FUN=sum),aggregate(ecommrough$metro,by=list(ecommrough$metro),length)[,2])
z4$CODmetro<-z4[,c(2)]*100/z4[,c(3)]
z4$MetroCity<-factor(z4$MetroCity,labels = c("Not Metro","Metro"))
colnames(z4)<-c("City Type", "COD Purchases", "Total Purchases", "% of COD Purchases")
z4

From both the statistical test and the table above it can be clearly observed that the incidence of COD as a choice of payment is much higher in non-metro cities than in metro cities.

Discounts

Model 10: \(COD = \alpha+HasVendorDiscount*\beta1+HasWebsiteDiscount*\beta2+HasVendorDiscount:HasWebsiteDiscount*\beta3 +\epsilon\)

Discountdata<-ecommrough[,c(17,18,20)]
Discountdata$Interaction<-Discountdata$HasVendorDiscount*Discountdata$HasWebsiteDiscount
model10 <- glm(COD ~.,family=binomial(link='logit'),data=Discountdata)
anova(model10, test="Chisq")
Analysis of Deviance Table

Model: binomial, link: logit

Response: COD

Terms added sequentially (first to last)

                   Df Deviance Resid. Df Resid. Dev Pr(>Chi)    
NULL                               45897      61256             
HasVendorDiscount   1     0.03     45896      61256  0.86724    
HasWebsiteDiscount  1   350.40     45895      60905  < 2e-16 ***
Interaction         1     3.14     45894      60902  0.07657 .  
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Hence only website discount alone affects the choice of COD payments.

Based on the above analysis below is the summary of our statiscal inferences:

Model1 : Brand affects the COD payment choice

Model2 : Brand Category(High/Medium/Low cost) affects the COD payment choice more significantly than the effect of the individual brand(Model1)

Model3 : Whether a customer is a repeat customer or not doesn’t affect their COD payment choice

Model4 : Repeat Customers have significantly lesser cart value than first time purchasers

Model5 : Final Price of the product affects the COD payment choices

Model6 : At 1% significance level revenue doesn’t affect COD payment choice

Model7 : High Value Product subcategories(High Costs & High frequency) are purchased more over COD

Model8 : Contrary to expectation, COD is more preferred when billing and shipping address is not the same

Model9 : Whether or not the shipping is to a metro city, significantly impacts the COD payment choice

Model10: Vendor Discount doesn’t affect COD only website discount without any interaction effect with vendor discount affects COD payment choice

A single model is created based on the above inferences and tested for its accuracy.

regressfcn<-ecommrough[,c(30,10,32,33,34,20,18)]
regressfcn$productcategory_metro<-regressfcn$HotProducts*regressfcn$metro
regressfcn$brandcategory_metro<-regressfcn$BrandCategory*regressfcn$metro
regressfcn$productcategory_websitediscount<-regressfcn$HotProducts*regressfcn$HasWebsiteDiscount
regressfcn$brandcategory_websitediscount<-regressfcn$BrandCategory*regressfcn$HasWebsiteDiscount
train <- regressfcn[c(1:15000),]
test <- regressfcn[c(15001:45898),]
model <- glm(COD ~.,family=binomial(link='logit'),data=train)
anova(model, test="Chisq")
Analysis of Deviance Table

Model: binomial, link: logit

Response: COD

Terms added sequentially (first to last)

                                Df Deviance Resid. Df Resid. Dev  Pr(>Chi)    
NULL                                            14999      20265              
BrandCategory                    1   35.208     14998      20230 2.962e-09 ***
FinalTotalPrice                  1  183.351     14997      20046 < 2.2e-16 ***
HotProducts                      1    0.618     14996      20046    0.4320    
metro                            1  290.742     14995      19755 < 2.2e-16 ***
address                          1   16.796     14994      19738 4.161e-05 ***
HasWebsiteDiscount               1   85.816     14993      19652 < 2.2e-16 ***
productcategory_metro            1    2.039     14992      19650    0.1533    
brandcategory_metro              1    0.107     14991      19650    0.7433    
productcategory_websitediscount  1    4.274     14990      19646    0.0387 *  
brandcategory_websitediscount    1    0.832     14989      19645    0.3616    
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Based on the significance level, the model is re-adjusted as follows: \(COD = \alpha+BrandCategory1*\beta1+BrandCategory2*\beta2+FinalTotalPrice*\beta3+CityType*\beta4+AddressType*\beta5+HasWebsiteDiscount*\beta6 +\epsilon\)

regressfcn<-ecommrough[,c(30,10,33,34,20,18)]
train <- regressfcn[c(1:15000),]
test <- regressfcn[c(15001:45898),]
model <- glm(COD ~.,family=binomial(link='logit'),data=train)
anova(model, test="Chisq")
Analysis of Deviance Table

Model: binomial, link: logit

Response: COD

Terms added sequentially (first to last)

                   Df Deviance Resid. Df Resid. Dev  Pr(>Chi)    
NULL                               14999      20265              
BrandCategory       1   35.208     14998      20230 2.962e-09 ***
FinalTotalPrice     1  183.351     14997      20046 < 2.2e-16 ***
metro               1  290.732     14996      19756 < 2.2e-16 ***
address             1   16.828     14995      19739 4.093e-05 ***
HasWebsiteDiscount  1   85.525     14994      19653 < 2.2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
fitted.results <- predict(model,test,type='response')
install.packages("ROCR")
Error in install.packages : Updating loaded packages
library(ROCR)
pred<-prediction(fitted.results,ecommrough$COD[c(15001:45898)])
plot(performance(pred,"acc"))

roc<-performance(pred,"tpr","fpr")
plot(roc,colorize=T,main="ROC Curve",ylab="Sensitivity",xlab="1-Specificity")
abline(a=0,b=1)
auc<-performance(pred,"auc")
auc<-unlist(slot(auc,"y.values"))
auc<-round(auc,4)
legend(0.6,0.2,auc,title = "AUC")

fitted.results <- predict(model,test,type='response')
fitted.results <- ifelse(fitted.results > 0.5,1,0)
misClasificError <- mean(fitted.results != test$COD)
print(paste('Accuracy',1-misClasificError))
[1] "Accuracy 0.623373681144411"

The model can hence with 62% accuracy predict if the customer would opt for COD or electronic mode of payment.

Key Managerial Implications:

  1. High price brand categories are usually bought through COD. Hence by offering some discount and mandating electronic payments, the firm can make more customers pay electronically.

  2. The firm needs to have targetted promotions in Tier-II cities so that these customers shift to electronic payments.

  3. Final Price affects the choice od mode of payment. This is typically because customer wants to see, touch and feel the product before the payment. Adding cutting edge features to website like CV based applications would instill confidence in the customers.

  4. More Website Discounts affect the payments more. The firm can discount on behalf of vendors and ask the vendors to appropriate the share as website discounts impact electronic payments positively.

  5. When billing and shipping address is not the same customer order increasingly through COD implying that multiple users might be using the same account. By giving incentives such as anniversary discounts, personalized suggestions or notifications website can drive more individual accounts increasing their user count as well

  6. High average price product categories which are also bought frequently such as Casual Shirts, Dresses etc do not impact customers COD choices implying customers do not mind spending extra without increasingly preferring COD. Hence these sub categories are of greater significance for the company

LS0tCnRpdGxlOiAiREFNIFByb2plY3Q6IEFuYWx5c2lzIG9mIEUtQ29tbWVyY2UgRGF0YSIKYXV0aG9yOiAiIERhcnNoYW4gfCBOaXNoYW50IHwgUmFteWEgfCBSb2hhbiB8IFN1cmJoaSB8IFZpdmVrICIKZGF0ZTogIkdyb3VwIDIiCm91dHB1dDogaHRtbF9ub3RlYm9vawoKLS0tCgoKT2JqZWN0aXZlIG9mIHRoZSBwcm9qZWN0IGlzIHRvIGFuYWx5emUgdGhlIGltcGFjdCBvZiBmYWN0b3JzIHN1Y2ggYXMgYnJhbmQsIHR5cGUgb2YgcHJvZHVjdCBldGMgb24gdGhlIG1vZGUgb2YgcGF5bWVudC4gQW5hbHl6aW5nIHRoZSBwcmljZSBvZiB0aGUgcHJvZHVjdCBhbG9uZyB0aGUgc2FtZSBmYWN0b3JzIGFsc28gaGVscHMgdGhlIG1hbmFnZW1lbnQgdG8gZGVkdWNlIGluc2lnaHRzIG9uIHRoZSBjdXN0b21lciBiZWhhdmlvci4KCiMjIFVuZGVyc3RhbmRpbmcgdGhlIGRhdGFzZXQKCgpUaGVyZSBhcmUgMjkgZGlmZmVyZW50IHZhcmlhYmxlcyBpbiB0aGUgZGF0YXNldCB3aXRoIDQ1ODk4IG9ic2VydmF0aW9ucy4gT25lIHNhbXBsZSBvYnNlcnZhdGlvbiBpcyBsaXN0ZWQgYmVsb3cKYGBge3J9CnNldHdkKCJ+L0Rvd25sb2FkcyIpCmVjb21tcm91Z2g8LXJlYWQuY3N2KCdQcm9tb3Rpb25EYXRhVjQuY3N2JykKY29sbmFtZXMoZWNvbW1yb3VnaCkKYGBgCgpVbmlxdWUgY291bnQgb2YgZGlmZmVyZW50IHZhcmlhYmxlcyBvZiBpbnRlcmVzdCBhcmUgYXMgYmVsb3c6CmBgYHtyfQp4PC1jKCJCcmFuZCIsIlByb2R1Y3QgQ2F0ZWdvcnkiLCJDdXN0b21lcnMiLCJPcmRlcnMiKQp5PC1jKGxlbmd0aCh1bmlxdWUoZWNvbW1yb3VnaCRCcmFuZCkpLGxlbmd0aCh1bmlxdWUoZWNvbW1yb3VnaCRTdWJDYXRlZ29yeSkpLGxlbmd0aCh1bmlxdWUoZWNvbW1yb3VnaCRDdXN0b21lcklEKSksbGVuZ3RoKHVuaXF1ZShlY29tbXJvdWdoJE9yZGVySUQpKSkKejwtcmJpbmQoeCx5KQp6CmBgYAoKIyMgQ2F0ZWdvcml6aW5nIEJyYW5kcwoKRGlmZmVyZW50IGJyYW5kcyBoYXZlIHZhcmlvdXMgcHJpY2UgcG9pbnRzLiBBcyBkZXBpY3RlZCBieSB0aGUgYmVsb3cgZ3JhcGgsIHNvbWUgYnJhbmRzIG9uIGFuIGF2ZXJhZ2UgaGF2ZSBoaWdoZXIgTVJQCmBgYHtyfQpicmFuZHByaWNlPC1hZ2dyZWdhdGUoZWNvbW1yb3VnaCRNUlAsYnk9bGlzdChCcmFuZD1lY29tbXJvdWdoJEJyYW5kKSxGVU49bWVhbikKQnJhbmRwbG90IDwtIHBsb3QoYnJhbmRwcmljZSRCcmFuZCxicmFuZHByaWNlJHgsdHlwZT0icCIseGxhYj0iQnJhbmRzIix5bGFiPSJNUlAiLE1haW49IkJyYW5kcyBhbmQgdGhlaXIgUHJpY2VzIixwY2g9NikKYGBgCkRpZmZlcmVudCBCcmFuZHMgYW5kIHRoZWlyIGNhdGVnb3JpZXMgYXJlIGFzIGZvbGxvd3M6CmBgYHtyfQoKYnJhbmRwcmljZSRUeXBlPC1pZmVsc2UoYnJhbmRwcmljZSR4Pj0xMjAwLGJyYW5kcHJpY2UkVHlwZTwtIkhpZ2giLGlmZWxzZShicmFuZHByaWNlJHg+PTEwMDAsYnJhbmRwcmljZSRUeXBlPC0iTWVkaXVtIixicmFuZHByaWNlJFR5cGU8LSJMb3ciKSkKZWNvbW1yb3VnaCRCcmFuZENhdGVnb3J5PC1pZmVsc2UoZWNvbW1yb3VnaCRCcmFuZD09IkF0aGVuYSIgfCBlY29tbXJvdWdoJEJyYW5kPT0iTUlTUyBDSEFTRSIgfCBlY29tbXJvdWdoJEJyYW5kPT0iTVIgQlVUVE9OIixlY29tbXJvdWdoJEJyYW5kQ2F0ZWdvcnk8LTIsaWZlbHNlKGVjb21tcm91Z2gkQnJhbmQ9PSJGQUJBTExFWSIgfCBlY29tbXJvdWdoJEJyYW5kPT0iSEFSUEEiIHwgZWNvbW1yb3VnaCRCcmFuZD09IlRIRSBWQU5DQSIsZWNvbW1yb3VnaCRCcmFuZENhdGVnb3J5PC0xLGVjb21tcm91Z2gkQnJhbmRDYXRlZ29yeTwtMCkpCmNvbG5hbWVzKGJyYW5kcHJpY2UpPC1jKCJCcmFuZCIsIkF2Zy5QcmljZSIsIlR5cGUiKQpicmFuZHByaWNlCmBgYAoKRWZmZWN0IG9mIEJyYW5kIG9uIE1SUDoKCk1vZGVsIDE6CiRDT0QgPSAgQlJBTkQxKlxiZXRhMSArIEJSQU5EMipcYmV0YTIrLi4uLi5CUkFORDEwKlxiZXRhMTArXGVwc2lsb24kCgpNb2RlbCAyOgokQ09EID0gIEJyYW5kQ2F0ZWdvcnkxKlxiZXRhMSArIEJyYW5kQ2F0ZWdvcnkyKlxiZXRhMitCcmFuZENhdGVnb3J5MypcYmV0YTMrXGVwc2lsb24kCgpgYGB7cn0KZDE8LWVjb21tcm91Z2hbLGMoNiwyMCldCk1vZGVsMTwtZ2xtKENPRCB+LixmYW1pbHk9Ymlub21pYWwobGluaz0nbG9naXQnKSxkYXRhPWQxKQphbm92YShNb2RlbDEsIHRlc3Q9IkNoaXNxIikKZDI8LWVjb21tcm91Z2hbLGMoMjAsMzApXQpNb2RlbDI8LWdsbShDT0Qgfi4sZmFtaWx5PWJpbm9taWFsKGxpbms9J2xvZ2l0JyksZGF0YT1kMikKYW5vdmEoTW9kZWwyLCB0ZXN0PSJDaGlzcSIpCmBgYApNb2RlbDIgaGFzIGxlc3NlciBkZXZpYXRpb24gYW5kIGlzIGhlbmNlIGEgYmV0dGVyIG1vZGVsLiBIZW5jZSByYXRoZXIgdGhhbiBjb25zaWRlcmluZyBpbmRlcGVuZGVudCBicmFuZHMgaXQgaXMgYmV0dGVyIHRvIGNvbnNpZGVyIGJyYW5kIGNhdGVnb3JpZXMgKGhpZ2gvbWVkaXVtL2xvdykKCmBgYHtyfQp6PC1jYmluZChhZ2dyZWdhdGUoZWNvbW1yb3VnaCRDT0QsYnk9bGlzdChlY29tbXJvdWdoJEJyYW5kQ2F0ZWdvcnkpLEZVTj1zdW0pLGFnZ3JlZ2F0ZShlY29tbXJvdWdoJEJyYW5kQ2F0ZWdvcnksYnk9bGlzdChlY29tbXJvdWdoJEJyYW5kQ2F0ZWdvcnkpLGxlbmd0aClbLDJdKQp6JENPRFNoYXJlPC16WyxjKDIpXSoxMDAvelssYygzKV0KY29sbmFtZXMoeik8LWMoIkJyYW5kIENhdGVnb3J5IiwgIkNPRCBQdXJjaGFzZXMiLCAiVG90YWwgUHVyY2hhc2VzIiwgIiUgb2YgQ09EIFB1cmNoYXNlcyIpCnoKYGBgCkl0IGNhbiBiZSBub3RlZCB0aGF0IGFzIHRoZSB2YWx1ZSBvZiBCcmFuZCBpbmNyZWFzZXMgQ09EIHByZWZlcmVuY2UgaXMgYWxzbyBpbmNyZWFzaW5nLkhlbmNlIGN1c3RvbWVycyBwcmVmZXIgQ09EIGZvciBtb3JlIGV4cGVuc2l2ZSBicmFuZHMKCiMjIENhdGVnb3JpemluZyBDdXN0b21lcnMKClRoZXJlIGFyZSB0d28gY2F0ZWdvcmllcyBvZiBjdXN0b21lciBiYXNlZCBvbiB0aGUgZnJlcXVlbmN5OiBhKSBSZXBlYXQgQ3VzdG9tZXIgYilOb24tUmVwZWF0aW5nIEN1c3RvbWVyLiBTaW5jZSB0aGUgZGF0YSBpcyBmb3IgYSBsaW1pdGVkIHBlcmlvZCwgaXQgaXMgbm90IG5lY2Vzc2FyeSB0aGF0IGEgbm9uLXJlcGVhdGluZyBjdXN0b21lciBpcyBhY3R1YWxseSBhIG5ldyBjdXN0b21lci4gCgpgYGB7cn0KeDwtZWNvbW1yb3VnaCRDdXN0b21lcklEW2R1cGxpY2F0ZWQoZWNvbW1yb3VnaCRDdXN0b21lcklEKV0KZWNvbW1yb3VnaCRSZXBlYXRDdXN0b21lcjwtaWZlbHNlKGlzLmVsZW1lbnQoZWNvbW1yb3VnaCRDdXN0b21lcklELHgpLDEsMCkKYm94cGxvdChlY29tbXJvdWdoJE1SUH5lY29tbXJvdWdoJFJlcGVhdEN1c3RvbWVyLHhsYWI9IlJlcGVhdCBDdXN0b21lciIseWxhYj0iTVJQIixNYWluPSIgUHJpY2VzIGFuZCBDdXN0b21lciBGcmVxdWVuY3kiLGNvbD0icG93ZGVyIGJsdWUiLHlsaW09YygwLDMwMDApKQpgYGAKCk1vZGVsIDM6CiRDT0QgPSAgXGFscGhhK1JlcGVhdEN1c3RvbWVyKlxiZXRhICtcZXBzaWxvbiQKCk1vZGVsIDQ6CiRNUlAgPSAgXGFscGhhK1JlcGVhdEN1c3RvbWVyKlxiZXRhICsgXGVwc2lsb24kCgpgYGB7cn0KZDM8LWVjb21tcm91Z2hbLGMoMjAsMzEpXQpNb2RlbDM8LWdsbShDT0Qgfi4sZmFtaWx5PWJpbm9taWFsKGxpbms9J2xvZ2l0JyksZGF0YT1kMykKYW5vdmEoTW9kZWwzLCB0ZXN0PSJDaGlzcSIpCmQ0PC1lY29tbXJvdWdoWyxjKDksMzEpXQpNb2RlbDQ8LWxtKE1SUH5SZXBlYXRDdXN0b21lcixkYXRhPWQ0KQpzdW1tYXJ5KE1vZGVsNCkKYGBgCkN1c3RvbWVyIFB1cmNoYXNlIEZyZXF1ZW5jeSBzaWduaWZpY2FudGx5IGltcGFjdHMgdGhlIHByaWNlIG9mIHByb2R1Y3QgcHVyY2hhc2VkLiBIb3dldmVyIHRoZSBjaG9pY2Ugb24gbW9kZSBvZiBwYXltZW50IGlzIGluZGVwZW5kZW50IG9mIGN1c3RvbWVyIHB1cmNoYXNlIGZyZXF1ZW5jeS4gVGhlIHNhbWUgaXMgaW5kaWNhdGVkIGJ5IHRoZSBzaGFyZSBvZiBDT0QgaW4gdG90YWwgcHVyY2hhc2VzIG9mIHJlcGVhdCB2L3MgbmV3IGN1c3RvbWVycy4KCmBgYHtyfQp6MTwtY2JpbmQoYWdncmVnYXRlKGVjb21tcm91Z2gkQ09ELGJ5PWxpc3QoQ3VzdG9tZXJGcmVxdWVuY3k9ZWNvbW1yb3VnaCRSZXBlYXRDdXN0b21lciksRlVOPXN1bSksYWdncmVnYXRlKGVjb21tcm91Z2gkUmVwZWF0Q3VzdG9tZXIsYnk9bGlzdChlY29tbXJvdWdoJFJlcGVhdEN1c3RvbWVyKSxsZW5ndGgpWywyXSkKejEkQ09EQ3VzdG9tZXI8LXoxWyxjKDIpXSoxMDAvejFbLGMoMyldCnoxJEN1c3RvbWVyRnJlcXVlbmN5PC1mYWN0b3IoejEkQ3VzdG9tZXJGcmVxdWVuY3ksbGFiZWxzID0gYygiTm9uLVJlcGVhdCIsIlJlcGVhdCIpKQpjb2xuYW1lcyh6MSk8LWMoIkN1c3RvbWVyIFR5cGUiLCAiQ09EIFB1cmNoYXNlcyIsICJUb3RhbCBQdXJjaGFzZXMiLCAiJSBvZiBDT0QgUHVyY2hhc2VzIikKejEKYGBgCiMjIFByaWNpbmcKCgpgYGB7cn0KcHJpY2U8LWFnZ3JlZ2F0ZShlY29tbXJvdWdoWzEwXSxieT1saXN0KGVjb21tcm91Z2gkT3JkZXJJRCksRlVOPXN1bSkKZGVtYW5kPC1hZ2dyZWdhdGUoZWNvbW1yb3VnaFsyXSxieT1saXN0KGVjb21tcm91Z2gkT3JkZXJJRCksRlVOPWxlbmd0aCkKZWNvbW08LW1lcmdlKHByaWNlLGRlbWFuZCwgYnkueD0iR3JvdXAuMSIsYnkueT0iR3JvdXAuMSIpCmVjb21tJHJldmVudWU8LWVjb21tJEZpbmFsVG90YWxQcmljZSplY29tbSRPcmRlcklECmNvbG5hbWVzKGVjb21tKTwtYygiT3JkZXIgSUQiLCAiUHJpY2UiLCAiRGVtYW5kIiwgIlJldmVudWUiKQpDT0Q8LWFnZ3JlZ2F0ZShlY29tbXJvdWdoWzIwXSxieT1saXN0KGVjb21tcm91Z2gkT3JkZXJJRCksRlVOPW1lYW4pCmVjb21tPC1tZXJnZShlY29tbSxDT0QsIGJ5Lng9Ik9yZGVyIElEIixieS55PSJHcm91cC4xIikKbGlicmFyeShncGxvdHMpCnBsb3RtZWFucyhlY29tbSRQcmljZX5lY29tbSRDT0QsIGxlZ2VuZHMgPSBjKCJOb24tQ09EIiwiQ09EIiksbWVhbi5sYWJlbHM9VFJVRSkKYGBgCmBgYHtyfQpzaGFwaXJvLnRlc3QoZWNvbW0kUHJpY2VbMTo1MDAwXSkKYGBgClRoZSBkYXRhIGlzIG5vdCBub3JtYWwKYGBge3J9CmJveHBsb3QoZWNvbW0kUHJpY2V+ZWNvbW0kQ09ELG5hbWVzID0gYygiTm9uLUNPRCIsIkNPRCIpLHlsYWI9IlByaWNlIixtYWluPSJBdmVyYWdlIFByaWNlIHYvcyBQYXltZW50IE9wdGlvbnMiLGNvbD1jKCJnb2xkIiwiZ3JleSIpLHlsaW09YygwLDMwMDApKQpgYGAKYGBge3J9CndpbGNveC50ZXN0KGVjb21tJFByaWNlfmVjb21tJENPRCkKYGBgCkhlbmNlIHdlIGNhbiBjb25jbHVkZSB0aGF0IHRoZXJlIGlzIHNpZ25pZmljYW50IGRpZmZlcmVuY2UgaW4gdGhlIGF2ZXJhZ2UgcHJvZHVjdCBwcmljZSBpbiBwYXltZW50cyB3aXRoL3dpdGhvdXQgQ09ELiBDT0QgcGF5bWVudHMgYXJlIG9mIGhpZ2hlciB2YWx1ZSAKCiMjIFJldmVudWUKYGBge3J9CmxpYnJhcnkoZ3Bsb3RzKQpwbG90bWVhbnMoZWNvbW0kUmV2ZW51ZX5lY29tbSRDT0QsIGxlZ2VuZHMgPSBjKCJOb24tQ09EIiwiQ09EIiksbWVhbi5sYWJlbHM9VFJVRSkKYGBgCgpgYGB7cn0Kc2hhcGlyby50ZXN0KGVjb21tJFJldmVudWVbMTo1MDAwXSkKYGBgClRoZSBkYXRhIGlzIG5vdCBub3JtYWwKYGBge3J9CmJveHBsb3QoZWNvbW0kUmV2ZW51ZX5lY29tbSRDT0QsbmFtZXMgPSBjKCJOb24tQ09EIiwiQ09EIikseWxhYj0iUmV2ZW51ZSIseWxpbT1jKDAsMTAwMDApLG1haW49IkF2ZXJhZ2UgUmV2ZW51ZSB2L3MgUGF5bWVudCBPcHRpb25zIixjb2w9YygiZ29sZCIsImdyZXkiKSkKYGBgCmBgYHtyfQp3aWxjb3gudGVzdChlY29tbSRSZXZlbnVlfmVjb21tJENPRCkKYGBgCldlIGNhbiBjb25jbHVkZSB0aGF0IHRoZSBhdmVyYWdlIHJldmVudWUgcGVyIG9yZGVyIGZvciB0aGUgZmlybSB1bmRlciB3aXRoL3dpdGhvdXQgQ09EIHBheW1lbnQgb3B0aW9uIGlzIGRpZmZlcmVudC4gCgpNb2RlbCA1OgokQ09EID0gIFxhbHBoYStQcmljZSpcYmV0YSArXGVwc2lsb24kCgpNb2RlbCA2OgokQ09EID0gIFxhbHBoYStSZXZlbnVlKlxiZXRhICsgXGVwc2lsb24kCgpgYGB7cn0KZDU8LWVjb21tWyxjKDIsNSldCk1vZGVsNTwtZ2xtKENPRCB+LixmYW1pbHk9Ymlub21pYWwobGluaz0nbG9naXQnKSxkYXRhPWQ1KQphbm92YShNb2RlbDUsIHRlc3Q9IkNoaXNxIikKCmQ2PC1lY29tbVssYyg0LDUpXQpNb2RlbDY8LWdsbShDT0Qgfi4sZmFtaWx5PWJpbm9taWFsKGxpbms9J2xvZ2l0JyksZGF0YT1kNikKYW5vdmEoTW9kZWw2LCB0ZXN0PSJDaGlzcSIpCmBgYAoKRGV2aWFuY2Ugb2YgbW9kZWwgMiBpcyBzaWduaWZpY2FudGx5IGxvd2VyLiBIb3dldmVyIGF0IDElIHNpZ25pZmljYW5jZSB3ZSBjYW5ub3QgcmVqZWN0IG51bGwgaHlwb3RoZXNpcyBvZiBtb2RlbCA2IHRoYXQgUmV2ZW51ZSBhbmQgQ09EIG9wdGlvbiBhcmUgaW5kZXBlbmRlbnQuIEhlbmNlIHByaWNlIGlzIGEgbW9yZSBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IHZhcmlhYmxlIHRoYW4gcmV2ZW51ZS4KCiMjIFByb2R1Y3QgQ2F0ZWdvcnkKCkRpZmZlcmVudCBwcm9kdWN0cyBoYXZlIHZhcmlvdXMgcHJpY2UgcG9pbnRzIGFuZCBzb21lIHByb2R1Y3RzIG9uIGFuIGF2ZXJhZ2UgaGF2ZSBoaWdoZXIgTVJQCgpEaWZmZXJlbnQgUHJvZHVjdHMgYW5kIHRoZWlyIGNhdGVnb3JpZXMgYXJlIGFzIGZvbGxvd3M6CmBgYHtyfQpwcm9kdWN0cHJpY2U8LWFnZ3JlZ2F0ZShlY29tbXJvdWdoJE1SUCxieT1saXN0KFByb2R1Y3Q9ZWNvbW1yb3VnaCRTdWJDYXRlZ29yeSksRlVOPW1lYW4pCnByb2R1Y3RwcmljZSRQcmljZUNhdGVnb3J5PC1pZmVsc2UocHJvZHVjdHByaWNlJHg+PTEyMDAsYnJhbmRwcmljZSRQcmljZUNhdGVnb3J5PC0iSGlnaCIsaWZlbHNlKHByb2R1Y3RwcmljZSR4Pj0xMDAwLHByb2R1Y3RwcmljZSRQcmljZUNhdGVnb3J5PC0iTWVkaXVtIixwcm9kdWN0cHJpY2UkUHJpY2VDYXRlZ29yeTwtIkxvdyIpKQpwcm9kdWN0cHJpY2UkRnJlcXVlbmN5PC1hZ2dyZWdhdGUoZWNvbW1yb3VnaCRTdWJDYXRlZ29yeSxieT1saXN0KFByb2R1Y3Q9ZWNvbW1yb3VnaCRTdWJDYXRlZ29yeSksRlVOPWxlbmd0aClbLDJdCnByb2R1Y3RwcmljZSRGcmVxdWVuY3k8LWlmZWxzZShwcm9kdWN0cHJpY2UkRnJlcXVlbmN5Pj0xNTAwLGJyYW5kcHJpY2UkRnJlcXVlbmN5PC0iSGlnaCIsaWZlbHNlKHByb2R1Y3RwcmljZSRGcmVxdWVuY3k+PTgwMCxwcm9kdWN0cHJpY2UkRnJlcXVlbmN5PC0iTWVkaXVtIixwcm9kdWN0cHJpY2UkRnJlcXVlbmN5PC0iTG93IikpCnByb2R1Y3RwcmljZQpgYGAKCkJlbG93IHR3byBwcm9kdWN0IGNhdGVnb3JpZXMgYXJlIG9mIGJvdGggaGlnaCBwcmljZSBhbmQgaGlnaCBmcmVxdWVuY3kgcHVyY2hhc2UgYW5kIGhlbmNlIG9mIGhpZ2ggdmFsdWUuCmBgYHtyfQpIaWdocHJvZHVjdDwtc3Vic2V0KHByb2R1Y3RwcmljZSxwcm9kdWN0cHJpY2UkUHJpY2VDYXRlZ29yeT09IkhpZ2giJnByb2R1Y3RwcmljZSRGcmVxdWVuY3k9PSJIaWdoIikKZWNvbW1yb3VnaCRIb3RQcm9kdWN0czwtaWZlbHNlKGVjb21tcm91Z2gkU3ViQ2F0ZWdvcnk9PSJDQVNVQUwgU0hJUlRTIiB8IGVjb21tcm91Z2gkU3ViQ2F0ZWdvcnk9PSJEUkVTU0VTIixlY29tbXJvdWdoJEhvdFByb2R1Y3RzPC0xLGVjb21tcm91Z2gkSG90UHJvZHVjdHM8LTApCkhpZ2hwcm9kdWN0CmBgYAoKCkVmZmVjdCBvZiBoaWdoIHZhbHVlIGFuZCBmcmVxdWVudGx5IHB1cmNoYXNlZCBwcm9kdWN0cyBvbiB0aGUgcGF5bWVudCBkZWNpc2lvbgoKTW9kZWwgNzoKCiRDT0QgPSAgXGFscGhhK1Byb2R1Y3RDYXRlZ29yeSpcYmV0YSArXGVwc2lsb24kCgpgYGB7cn0KZDE8LWVjb21tcm91Z2hbLGMoMjAsMzIpXQpNb2RlbDc8LWdsbShDT0Qgfi4sZmFtaWx5PWJpbm9taWFsKGxpbms9J2xvZ2l0JyksZGF0YT1kMSkKYW5vdmEoTW9kZWw3LCB0ZXN0PSJDaGlzcSIpCmBgYApIZW5jZSwgaGlnaCB2YWx1ZSBwcm9kdWN0IGNhdGVnb3JpZXMgZG8gaGF2ZSBhIHNpZ25pZmljYW50IGltcGFjdCBvbiB0aGUgcHVyY2hhc2UgZGVjaXNpb24gCmBgYHtyfQp6MjwtY2JpbmQoYWdncmVnYXRlKGVjb21tcm91Z2gkQ09ELGJ5PWxpc3QoSGlnaFZhbHVlUHJvZHVjdHM9ZWNvbW1yb3VnaCRIb3RQcm9kdWN0cyksRlVOPXN1bSksYWdncmVnYXRlKGVjb21tcm91Z2gkSG90UHJvZHVjdHMsYnk9bGlzdChlY29tbXJvdWdoJEhvdFByb2R1Y3RzKSxsZW5ndGgpWywyXSkKejIkQ09EQ3VzdG9tZXI8LXoyWyxjKDIpXSoxMDAvejJbLGMoMyldCnoyJEhpZ2hWYWx1ZVByb2R1Y3RzPC1mYWN0b3IoejIkSGlnaFZhbHVlUHJvZHVjdHMsbGFiZWxzID0gYygiTG93IFZhbHVlIiwiSGlnaCBWYWx1ZSIpKQpjb2xuYW1lcyh6Mik8LWMoIlByb2R1Y3QgQ2xhc3MiLCAiQ09EIFB1cmNoYXNlcyIsICJUb3RhbCBQdXJjaGFzZXMiLCAiJSBvZiBDT0QgUHVyY2hhc2VzIikKejIKYGBgCkl0IGNhbiBiZSBub3RlZCB0aGF0IGFzIHRoZSB2YWx1ZSBvZiBCcmFuZCBpbmNyZWFzZXMgQ09EIHByZWZlcmVuY2UgaXMgYWxzbyBpbmNyZWFzaW5nLgoKIyNCaWxsaW5nICYgU2hpcHBpbmcgQWRkcmVzcwoKSWYgYmlsbGluZyBhbmQgc2hpcHBpbmcgYWRkcmVzcyBhcmVuJ3QgdGhlIHNhbWUsIG1heWJlIHRoZSBjdXN0b21lciBpcyBidXlpbmcgaXQgZm9yIHNvbWVvbmUgYXMgYSBnaWZ0IGFuZCBoZW5jZSB3b3VsZG4ndCBwcmVmZXIgQ09ELiBCZWxvdyB3ZSB0ZXN0IHRoZSBzYW1lIGh5cG90aGVzaXMKYGBge3IsZWNobz1GQUxTRX0KZWNvbW1yb3VnaCRtZXRybzwtaWZlbHNlKGVjb21tcm91Z2gkU2hpcHBpbmdDaXR5ID09ICJDaGVubmFpIiwgZWNvbW1yb3VnaCRtZXRybzwtMSwgaWZlbHNlKGVjb21tcm91Z2gkU2hpcHBpbmdDaXR5ID09ICAiRGVsaGkiLGVjb21tcm91Z2gkbWV0cm88LTEsaWZlbHNlKGVjb21tcm91Z2gkU2hpcHBpbmdDaXR5ID09ICAiS29sa2F0YSIsZWNvbW1yb3VnaCRtZXRybzwtMSxpZmVsc2UoZWNvbW1yb3VnaCRTaGlwcGluZ0NpdHkgPT0gIkh5ZGVyYWJhZCIsZWNvbW1yb3VnaCRtZXRybzwtMSxpZmVsc2UoZWNvbW1yb3VnaCRTaGlwcGluZ0NpdHkgPT0gIlB1bmUiLGVjb21tcm91Z2gkbWV0cm88LTEsaWZlbHNlKGVjb21tcm91Z2gkU2hpcHBpbmdDaXR5ID09ICJBaG1lZGFiYWQiLGVjb21tcm91Z2gkbWV0cm88LTEsaWZlbHNlKGVjb21tcm91Z2gkU2hpcHBpbmdDaXR5ID09ICJNdW1iYWkiLGVjb21tcm91Z2gkbWV0cm88LTEsaWZlbHNlKGVjb21tcm91Z2gkU2hpcHBpbmdDaXR5ID09ICJOZXcgRGVsaGkiLGVjb21tcm91Z2gkbWV0cm88LTEsaWZlbHNlKGVjb21tcm91Z2gkU2hpcHBpbmdDaXR5ID09ICJOb2lkYSIsZWNvbW1yb3VnaCRtZXRybzwtMSxpZmVsc2UoZWNvbW1yb3VnaCRTaGlwcGluZ0NpdHkgPT0gIkd1cmdhb24iLGVjb21tcm91Z2gkbWV0cm88LTEsZWNvbW1yb3VnaCRtZXRybzwtMCkpKSkpKSkpKSkKZWNvbW1yb3VnaCRhZGRyZXNzPC1pZmVsc2UoZWNvbW1yb3VnaCRCaWxsaW5nUGluY29kZT09ZWNvbW1yb3VnaCRTaGlwcGluZ1BpbmNvZGUsMSwwKQoKYGBgCk1vZGVsIDg6CiRDT0QgPSAgXGFscGhhK0FkZHJlc3NUeXBlKlxiZXRhICtcZXBzaWxvbiQKCgpgYGB7cn0KYnM8LWVjb21tcm91Z2hbLGMoMjAsMzQpXQptb2RlbDggPC0gZ2xtKENPRCB+LixmYW1pbHk9Ymlub21pYWwobGluaz0nbG9naXQnKSxkYXRhPWJzKQphbm92YShtb2RlbDgsIHRlc3Q9IkNoaXNxIikKYGBgCkhlbmNlIHdoZXRoZXIgb3Igbm90IGJpbGxpbmcgYW5kIHNoaXBwaW5nIGFkZHJlc3MgaXMgdGhlIHNhbWUgc2lnbmlmaWNhbnRseSBpbXBhY3RzIHRoZSBwYXltZW50IG1vZGUgY2hvaWNlLgoKCmBgYHtyfQp6MzwtY2JpbmQoYWdncmVnYXRlKGVjb21tcm91Z2gkQ09ELGJ5PWxpc3QoQWRkcmVzc1R5cGU9ZWNvbW1yb3VnaCRhZGRyZXNzKSxGVU49c3VtKSxhZ2dyZWdhdGUoZWNvbW1yb3VnaCRhZGRyZXNzLGJ5PWxpc3QoZWNvbW1yb3VnaCRhZGRyZXNzKSxsZW5ndGgpWywyXSkKejMkQ09EQWRkcmVzczwtejNbLGMoMildKjEwMC96M1ssYygzKV0KY29sbmFtZXMoejMpPC1jKCJBZGRyZXNzIFR5cGUiLCAiQ09EIFB1cmNoYXNlcyIsICJUb3RhbCBQdXJjaGFzZXMiLCAiJSBvZiBDT0QgUHVyY2hhc2VzIikKejMKYGBgCkNvbnRyYXJ5IHRvIGV4cGVjdGF0aW9uIHdoZW4gdGhlIGFkZHJlc3MgdHlwZSBpcyBub3QgdGhlIHNhbWUsIENPRCBpcyBtb3JlIHByZWZlcnJlZC4gVGhpcyBjb3VsZCBtZWFuIHRoYXQgdGhlcmUgYXJlIG11bHRpcGxlIHVzZXJzIHBvc3NpYmx5IG9mIHRoZSBzYW1laG91c2Vob2xkIHVzaW5nIGEgc2luZ2xlIGFjY291bnQgd2l0aCBkaWZmZXJlbnQgZGVsaXZlcnkgYWRkcmVzc2VzLgoKIyNNZXRybwoKTW9kZWwgOToKJENPRCA9ICBcYWxwaGErQ2l0eVR5cGUqXGJldGEgK1xlcHNpbG9uJApgYGB7cn0KbWV0cm9jaXR5PC1lY29tbXJvdWdoWyxjKDIwLDMzKV0KbW9kZWw5IDwtIGdsbShDT0Qgfi4sZmFtaWx5PWJpbm9taWFsKGxpbms9J2xvZ2l0JyksZGF0YT1tZXRyb2NpdHkpCmFub3ZhKG1vZGVsOSwgdGVzdD0iQ2hpc3EiKQpgYGAKYGBge3J9Cno0PC1jYmluZChhZ2dyZWdhdGUoZWNvbW1yb3VnaCRDT0QsYnk9bGlzdChNZXRyb0NpdHk9ZWNvbW1yb3VnaCRtZXRybyksRlVOPXN1bSksYWdncmVnYXRlKGVjb21tcm91Z2gkbWV0cm8sYnk9bGlzdChlY29tbXJvdWdoJG1ldHJvKSxsZW5ndGgpWywyXSkKejQkQ09EbWV0cm88LXo0WyxjKDIpXSoxMDAvejRbLGMoMyldCno0JE1ldHJvQ2l0eTwtZmFjdG9yKHo0JE1ldHJvQ2l0eSxsYWJlbHMgPSBjKCJOb3QgTWV0cm8iLCJNZXRybyIpKQpjb2xuYW1lcyh6NCk8LWMoIkNpdHkgVHlwZSIsICJDT0QgUHVyY2hhc2VzIiwgIlRvdGFsIFB1cmNoYXNlcyIsICIlIG9mIENPRCBQdXJjaGFzZXMiKQp6NApgYGAKRnJvbSBib3RoIHRoZSBzdGF0aXN0aWNhbCB0ZXN0IGFuZCB0aGUgdGFibGUgYWJvdmUgaXQgY2FuIGJlIGNsZWFybHkgb2JzZXJ2ZWQgdGhhdCB0aGUgaW5jaWRlbmNlIG9mIENPRCBhcyBhIGNob2ljZSBvZiBwYXltZW50IGlzIG11Y2ggaGlnaGVyIGluIG5vbi1tZXRybyBjaXRpZXMgdGhhbiBpbiBtZXRybyBjaXRpZXMuIAoKIyNEaXNjb3VudHMKTW9kZWwgMTA6CiRDT0QgPSAgXGFscGhhK0hhc1ZlbmRvckRpc2NvdW50KlxiZXRhMStIYXNXZWJzaXRlRGlzY291bnQqXGJldGEyK0hhc1ZlbmRvckRpc2NvdW50Okhhc1dlYnNpdGVEaXNjb3VudCpcYmV0YTMgK1xlcHNpbG9uJAoKYGBge3J9CkRpc2NvdW50ZGF0YTwtZWNvbW1yb3VnaFssYygxNywxOCwyMCldCkRpc2NvdW50ZGF0YSRJbnRlcmFjdGlvbjwtRGlzY291bnRkYXRhJEhhc1ZlbmRvckRpc2NvdW50KkRpc2NvdW50ZGF0YSRIYXNXZWJzaXRlRGlzY291bnQKbW9kZWwxMCA8LSBnbG0oQ09EIH4uLGZhbWlseT1iaW5vbWlhbChsaW5rPSdsb2dpdCcpLGRhdGE9RGlzY291bnRkYXRhKQphbm92YShtb2RlbDEwLCB0ZXN0PSJDaGlzcSIpCmBgYApIZW5jZSBvbmx5IHdlYnNpdGUgZGlzY291bnQgYWxvbmUgYWZmZWN0cyB0aGUgY2hvaWNlIG9mIENPRCBwYXltZW50cy4KCkJhc2VkIG9uIHRoZSBhYm92ZSBhbmFseXNpcyBiZWxvdyBpcyB0aGUgc3VtbWFyeSBvZiBvdXIgc3RhdGlzY2FsIGluZmVyZW5jZXM6CgpNb2RlbDEgOiBCcmFuZCBhZmZlY3RzIHRoZSBDT0QgcGF5bWVudCBjaG9pY2UKCk1vZGVsMiA6IEJyYW5kIENhdGVnb3J5KEhpZ2gvTWVkaXVtL0xvdyBjb3N0KSBhZmZlY3RzIHRoZSBDT0QgcGF5bWVudCBjaG9pY2UgbW9yZSBzaWduaWZpY2FudGx5IHRoYW4gdGhlIGVmZmVjdCBvZiB0aGUgaW5kaXZpZHVhbCBicmFuZChNb2RlbDEpCgpNb2RlbDMgOiBXaGV0aGVyIGEgY3VzdG9tZXIgaXMgYSByZXBlYXQgY3VzdG9tZXIgb3Igbm90IGRvZXNuJ3QgYWZmZWN0IHRoZWlyIENPRCBwYXltZW50IGNob2ljZQoKTW9kZWw0IDogUmVwZWF0IEN1c3RvbWVycyBoYXZlIHNpZ25pZmljYW50bHkgbGVzc2VyIGNhcnQgdmFsdWUgdGhhbiBmaXJzdCB0aW1lIHB1cmNoYXNlcnMKCk1vZGVsNSA6IEZpbmFsIFByaWNlIG9mIHRoZSBwcm9kdWN0IGFmZmVjdHMgdGhlIENPRCBwYXltZW50IGNob2ljZXMKCk1vZGVsNiA6IEF0IDElIHNpZ25pZmljYW5jZSBsZXZlbCByZXZlbnVlIGRvZXNuJ3QgYWZmZWN0IENPRCBwYXltZW50IGNob2ljZQoKTW9kZWw3IDogSGlnaCBWYWx1ZSBQcm9kdWN0IHN1YmNhdGVnb3JpZXMoSGlnaCBDb3N0cyAmIEhpZ2ggZnJlcXVlbmN5KSBhcmUgcHVyY2hhc2VkIG1vcmUgb3ZlciBDT0QKCk1vZGVsOCA6IENvbnRyYXJ5IHRvIGV4cGVjdGF0aW9uLCBDT0QgaXMgbW9yZSBwcmVmZXJyZWQgd2hlbiBiaWxsaW5nIGFuZCBzaGlwcGluZyBhZGRyZXNzIGlzIG5vdCB0aGUgc2FtZQoKTW9kZWw5IDogV2hldGhlciBvciBub3QgdGhlIHNoaXBwaW5nIGlzIHRvIGEgbWV0cm8gY2l0eSwgc2lnbmlmaWNhbnRseSBpbXBhY3RzIHRoZSBDT0QgcGF5bWVudCBjaG9pY2UKCk1vZGVsMTA6IFZlbmRvciBEaXNjb3VudCBkb2Vzbid0IGFmZmVjdCBDT0Qgb25seSB3ZWJzaXRlIGRpc2NvdW50IHdpdGhvdXQgYW55IGludGVyYWN0aW9uIGVmZmVjdCB3aXRoIHZlbmRvciBkaXNjb3VudCBhZmZlY3RzIENPRCBwYXltZW50IGNob2ljZQoKQSBzaW5nbGUgbW9kZWwgaXMgY3JlYXRlZCBiYXNlZCBvbiB0aGUgYWJvdmUgaW5mZXJlbmNlcyBhbmQgdGVzdGVkIGZvciBpdHMgYWNjdXJhY3kuCmBgYHtyfQoKcmVncmVzc2ZjbjwtZWNvbW1yb3VnaFssYygzMCwxMCwzMiwzMywzNCwyMCwxOCldCnJlZ3Jlc3NmY24kcHJvZHVjdGNhdGVnb3J5X21ldHJvPC1yZWdyZXNzZmNuJEhvdFByb2R1Y3RzKnJlZ3Jlc3NmY24kbWV0cm8KcmVncmVzc2ZjbiRicmFuZGNhdGVnb3J5X21ldHJvPC1yZWdyZXNzZmNuJEJyYW5kQ2F0ZWdvcnkqcmVncmVzc2ZjbiRtZXRybwpyZWdyZXNzZmNuJHByb2R1Y3RjYXRlZ29yeV93ZWJzaXRlZGlzY291bnQ8LXJlZ3Jlc3NmY24kSG90UHJvZHVjdHMqcmVncmVzc2ZjbiRIYXNXZWJzaXRlRGlzY291bnQKcmVncmVzc2ZjbiRicmFuZGNhdGVnb3J5X3dlYnNpdGVkaXNjb3VudDwtcmVncmVzc2ZjbiRCcmFuZENhdGVnb3J5KnJlZ3Jlc3NmY24kSGFzV2Vic2l0ZURpc2NvdW50CnRyYWluIDwtIHJlZ3Jlc3NmY25bYygxOjE1MDAwKSxdCnRlc3QgPC0gcmVncmVzc2ZjbltjKDE1MDAxOjQ1ODk4KSxdCm1vZGVsIDwtIGdsbShDT0Qgfi4sZmFtaWx5PWJpbm9taWFsKGxpbms9J2xvZ2l0JyksZGF0YT10cmFpbikKYW5vdmEobW9kZWwsIHRlc3Q9IkNoaXNxIikKCmBgYApCYXNlZCBvbiB0aGUgc2lnbmlmaWNhbmNlIGxldmVsLCB0aGUgbW9kZWwgaXMgcmUtYWRqdXN0ZWQgYXMgZm9sbG93czoKJENPRCA9ICBcYWxwaGErQnJhbmRDYXRlZ29yeTEqXGJldGExK0JyYW5kQ2F0ZWdvcnkyKlxiZXRhMitGaW5hbFRvdGFsUHJpY2UqXGJldGEzK0NpdHlUeXBlKlxiZXRhNCtBZGRyZXNzVHlwZSpcYmV0YTUrSGFzV2Vic2l0ZURpc2NvdW50KlxiZXRhNiArXGVwc2lsb24kCgpgYGB7cn0KCnJlZ3Jlc3NmY248LWVjb21tcm91Z2hbLGMoMzAsMTAsMzMsMzQsMjAsMTgpXQp0cmFpbiA8LSByZWdyZXNzZmNuW2MoMToxNTAwMCksXQp0ZXN0IDwtIHJlZ3Jlc3NmY25bYygxNTAwMTo0NTg5OCksXQptb2RlbCA8LSBnbG0oQ09EIH4uLGZhbWlseT1iaW5vbWlhbChsaW5rPSdsb2dpdCcpLGRhdGE9dHJhaW4pCmFub3ZhKG1vZGVsLCB0ZXN0PSJDaGlzcSIpCgpgYGAKCgpgYGB7cn0KZml0dGVkLnJlc3VsdHMgPC0gcHJlZGljdChtb2RlbCx0ZXN0LHR5cGU9J3Jlc3BvbnNlJykKaW5zdGFsbC5wYWNrYWdlcygiUk9DUiIpCmxpYnJhcnkoUk9DUikKcHJlZDwtcHJlZGljdGlvbihmaXR0ZWQucmVzdWx0cyxlY29tbXJvdWdoJENPRFtjKDE1MDAxOjQ1ODk4KV0pCnBsb3QocGVyZm9ybWFuY2UocHJlZCwiYWNjIikpCmBgYApgYGB7cn0Kcm9jPC1wZXJmb3JtYW5jZShwcmVkLCJ0cHIiLCJmcHIiKQpwbG90KHJvYyxjb2xvcml6ZT1ULG1haW49IlJPQyBDdXJ2ZSIseWxhYj0iU2Vuc2l0aXZpdHkiLHhsYWI9IjEtU3BlY2lmaWNpdHkiKQphYmxpbmUoYT0wLGI9MSkKYXVjPC1wZXJmb3JtYW5jZShwcmVkLCJhdWMiKQphdWM8LXVubGlzdChzbG90KGF1YywieS52YWx1ZXMiKSkKYXVjPC1yb3VuZChhdWMsNCkKbGVnZW5kKDAuNiwwLjIsYXVjLHRpdGxlID0gIkFVQyIpCmBgYAoKYGBge3J9CmZpdHRlZC5yZXN1bHRzIDwtIGlmZWxzZShmaXR0ZWQucmVzdWx0cyA+IDAuNSwxLDApCm1pc0NsYXNpZmljRXJyb3IgPC0gbWVhbihmaXR0ZWQucmVzdWx0cyAhPSB0ZXN0JENPRCkKcHJpbnQocGFzdGUoJ0FjY3VyYWN5JywxLW1pc0NsYXNpZmljRXJyb3IpKQpgYGAKClRoZSBtb2RlbCBjYW4gaGVuY2Ugd2l0aCA2MiUgYWNjdXJhY3kgcHJlZGljdCBpZiB0aGUgY3VzdG9tZXIgd291bGQgb3B0IGZvciBDT0Qgb3IgZWxlY3Ryb25pYyBtb2RlIG9mIHBheW1lbnQuCgoKS2V5IE1hbmFnZXJpYWwgSW1wbGljYXRpb25zOgoKMSkgSGlnaCBwcmljZSBicmFuZCBjYXRlZ29yaWVzIGFyZSB1c3VhbGx5IGJvdWdodCB0aHJvdWdoIENPRC4gSGVuY2UgYnkgb2ZmZXJpbmcgc29tZSBkaXNjb3VudCBhbmQgbWFuZGF0aW5nIGVsZWN0cm9uaWMgcGF5bWVudHMsIHRoZSBmaXJtIGNhbiBtYWtlIG1vcmUgY3VzdG9tZXJzIHBheSBlbGVjdHJvbmljYWxseS4KCjIpIFRoZSBmaXJtIG5lZWRzIHRvIGhhdmUgdGFyZ2V0dGVkIHByb21vdGlvbnMgaW4gVGllci1JSSBjaXRpZXMgc28gdGhhdCB0aGVzZSBjdXN0b21lcnMgc2hpZnQgdG8gZWxlY3Ryb25pYyBwYXltZW50cy4KCjMpIEZpbmFsIFByaWNlIGFmZmVjdHMgdGhlIGNob2ljZSBvZCBtb2RlIG9mIHBheW1lbnQuIFRoaXMgaXMgdHlwaWNhbGx5IGJlY2F1c2UgY3VzdG9tZXIgd2FudHMgdG8gc2VlLCB0b3VjaCBhbmQgZmVlbCB0aGUgcHJvZHVjdCBiZWZvcmUgdGhlIHBheW1lbnQuIEFkZGluZyBjdXR0aW5nIGVkZ2UgZmVhdHVyZXMgdG8gd2Vic2l0ZSBsaWtlIENWIGJhc2VkIGFwcGxpY2F0aW9ucyB3b3VsZCBpbnN0aWxsIGNvbmZpZGVuY2UgaW4gdGhlIGN1c3RvbWVycy4KCjQpIE1vcmUgV2Vic2l0ZSBEaXNjb3VudHMgYWZmZWN0IHRoZSBwYXltZW50cyBtb3JlLiBUaGUgZmlybSBjYW4gZGlzY291bnQgb24gYmVoYWxmIG9mIHZlbmRvcnMgYW5kIGFzayB0aGUgdmVuZG9ycyB0byBhcHByb3ByaWF0ZSB0aGUgc2hhcmUgYXMgd2Vic2l0ZSBkaXNjb3VudHMgaW1wYWN0IGVsZWN0cm9uaWMgcGF5bWVudHMgcG9zaXRpdmVseS4KCjUpIFdoZW4gYmlsbGluZyBhbmQgc2hpcHBpbmcgYWRkcmVzcyBpcyBub3QgdGhlIHNhbWUgY3VzdG9tZXIgb3JkZXIgaW5jcmVhc2luZ2x5IHRocm91Z2ggQ09EIGltcGx5aW5nIHRoYXQgbXVsdGlwbGUgdXNlcnMgbWlnaHQgYmUgdXNpbmcgdGhlIHNhbWUgYWNjb3VudC4gQnkgZ2l2aW5nIGluY2VudGl2ZXMgc3VjaCBhcyBhbm5pdmVyc2FyeSBkaXNjb3VudHMsIHBlcnNvbmFsaXplZCBzdWdnZXN0aW9ucyBvciBub3RpZmljYXRpb25zIHdlYnNpdGUgY2FuIGRyaXZlIG1vcmUgaW5kaXZpZHVhbCBhY2NvdW50cyBpbmNyZWFzaW5nIHRoZWlyIHVzZXIgY291bnQgYXMgd2VsbAoKNikgSGlnaCBhdmVyYWdlIHByaWNlIHByb2R1Y3QgY2F0ZWdvcmllcyB3aGljaCBhcmUgYWxzbyBib3VnaHQgZnJlcXVlbnRseSBzdWNoIGFzIENhc3VhbCBTaGlydHMsIERyZXNzZXMgZXRjIGRvIG5vdCBpbXBhY3QgY3VzdG9tZXJzIENPRCBjaG9pY2VzIGltcGx5aW5nIGN1c3RvbWVycyBkbyBub3QgbWluZCBzcGVuZGluZyBleHRyYSB3aXRob3V0IGluY3JlYXNpbmdseSBwcmVmZXJyaW5nIENPRC4gSGVuY2UgdGhlc2Ugc3ViIGNhdGVnb3JpZXMgYXJlIG9mIGdyZWF0ZXIgc2lnbmlmaWNhbmNlIGZvciB0aGUgY29tcGFueQoK