E-commerce Project One.

By Priestam Murithi.

Project Overview This project analyzes an e-commerce dataset containing 300 transactions with customer details, product information, and transaction records. The goal is to uncover insights through data cleaning, exploratory analysis, statistical tests, and visualization. # Set a working directory.

Loading Libraries.

Importing the dataset.

Check the structure of the dataset.

spc_tbl_ [300 × 14] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
 $ TransactionID   : num [1:300] 1 2 3 4 5 6 7 8 9 10 ...
 $ CustomerID      : num [1:300] 207 253 110 256 274 52 191 165 18 169 ...
 $ ProductID       : num [1:300] 14 15 19 1 2 15 10 5 5 17 ...
 $ Quantity        : num [1:300] 5 1 5 3 5 2 1 5 4 2 ...
 $ PaymentMethod   : chr [1:300] "UPI" "Cash on Delivery" "Cash on Delivery" "Debit Card" ...
 $ TransactionDate : chr [1:300] "12/28/2023" "4/17/2023" "1/17/2023" "10/23/2023" ...
 $ ProductCategory : chr [1:300] "Clothing" "Electronics" "Clothing" "Home Appliances" ...
 $ Price           : num [1:300] 33.4 389 145.9 215 325.5 ...
 $ Rating          : num [1:300] 4.2 2.2 1.7 2.7 3.4 2.2 3.7 1.4 1.4 1.9 ...
 $ TotalAmount     : num [1:300] 167 389 729 645 1627 ...
 $ Age             : num [1:300] 50 19 37 50 24 50 40 37 25 53 ...
 $ Gender          : chr [1:300] "Male" "Female" "Female" "Male" ...
 $ Location        : chr [1:300] "Houston" "Chicago" "Houston" "Los Angeles" ...
 $ MembershipStatus: chr [1:300] "Basic" "Premium" "Basic" "Premium" ...
 - attr(*, "spec")=
  .. cols(
  ..   TransactionID = col_double(),
  ..   CustomerID = col_double(),
  ..   ProductID = col_double(),
  ..   Quantity = col_double(),
  ..   PaymentMethod = col_character(),
  ..   TransactionDate = col_character(),
  ..   ProductCategory = col_character(),
  ..   Price = col_double(),
  ..   Rating = col_double(),
  ..   TotalAmount = col_double(),
  ..   Age = col_double(),
  ..   Gender = col_character(),
  ..   Location = col_character(),
  ..   MembershipStatus = col_character()
  .. )
 - attr(*, "problems")=<externalptr> 

1. Handling Missing Values

Check for missing values

   TransactionID       CustomerID        ProductID         Quantity    PaymentMethod  TransactionDate  ProductCategory            Price 
               0                0                0                0                0                0                0                0 
          Rating      TotalAmount              Age           Gender         Location MembershipStatus 
               0                0                8               13                0                0 

Impute missing Age with median

  [1] 50 19 37 50 24 50 40 37 25 53 65 62 42 42 42 42 42 42 42 42 34 24 25 52 53 29 24 24 44 19 65 22 52 24 43 44 47 21 42 50 43 23 25
 [44] 27 18 35 42 53 34 49 63 27 49 18 62 43 41 41 52 44 31 43 37 50 26 24 36 24 28 62 61 50 37 52 38 25 25 65 49 44 63 59 24 41 56 56
 [87] 49 63 46 60 28 46 22 52 61 62 36 42 47 57 54 43 47 32 40 27 39 26 43 20 24 58 59 19 28 59 42 18 42 22 38 65 56 50 40 52 31 24 34
[130] 33 41 38 31 40 43 58 23 59 53 62 24 32 24 63 42 22 25 45 35 21 30 44 37 46 29 62 37 42 21 42 44 55 33 56 40 32 63 39 39 24 52 60
[173] 48 53 35 63 30 33 44 54 58 40 44 22 41 22 39 24 50 63 59 20 43 40 19 63 42 58 56 52 64 56 41 49 54 35 52 26 51 63 42 25 31 46 45
[216] 36 65 41 43 35 38 42 54 39 59 36 42 57 19 55 32 57 59 27 48 56 44 43 43 51 57 52 33 27 42 50 19 47 46 60 29 41 40 40 42 60 49 24
[259] 57 25 34 49 46 42 40 27 29 49 28 60 41 63 23 58 45 59 27 31 38 29 50 65 59 27 24 24 55 53 26 28 40 32 35 59 30 57 59 31 63 23

` ## handling missing value for gender # For Gender,replace with “male” category

  [1] "Male"   "Female" "Female" "Male"   "Male"   "Male"   "Male"   "Male"   "Female" "Female" "Male"   "Male"   "Male"   "Female"
 [15] "Male"   "Female" "Male"   "Male"   "Male"   "Female" "Female" "Male"   "Male"   "Male"   "Female" "Male"   "Male"   "Male"  
 [29] "Female" "Male"   "Female" "Female" "Male"   "Male"   "Female" "Male"   "Male"   "Male"   "Male"   "Female" "Male"   "Male"  
 [43] "Female" "Female" "Female" "Female" NA       NA       NA       NA       NA       NA       NA       NA       NA       NA      
 [57] NA       NA       NA       "Female" "Male"   "Female" "Female" "Male"   "Female" "Female" "Female" "Male"   "Female" "Female"
 [71] "Female" "Female" "Female" "Female" "Female" "Female" "Male"   "Female" "Female" "Female" "Female" "Male"   "Male"   "Male"  
 [85] "Male"   "Female" "Male"   "Female" "Female" "Female" "Female" "Female" "Female" "Male"   "Male"   "Female" "Male"   "Female"
 [99] "Male"   "Male"   "Male"   "Male"   "Female" "Female" "Female" "Male"   "Male"   "Male"   "Female" "Female" "Female" "Male"  
[113] "Male"   "Male"   "Female" "Male"   "Male"   "Male"   "Male"   "Male"   "Male"   "Male"   "Male"   "Male"   "Male"   "Female"
[127] "Male"   "Male"   "Female" "Female" "Male"   "Male"   "Female" "Female" "Male"   "Male"   "Male"   "Male"   "Male"   "Male"  
[141] "Male"   "Male"   "Male"   "Female" "Male"   "Female" "Male"   "Male"   "Female" "Male"   "Male"   "Female" "Female" "Female"
[155] "Female" "Female" "Male"   "Male"   "Male"   "Male"   "Male"   "Female" "Male"   "Male"   "Male"   "Female" "Male"   "Male"  
[169] "Male"   "Female" "Male"   "Male"   "Female" "Female" "Female" "Male"   "Male"   "Male"   "Male"   "Female" "Male"   "Male"  
[183] "Female" "Male"   "Male"   "Female" "Male"   "Male"   "Female" "Female" "Male"   "Female" "Female" "Female" "Female" "Female"
[197] "Female" "Female" "Female" "Male"   "Female" "Female" "Female" "Male"   "Male"   "Female" "Male"   "Female" "Female" "Female"
[211] "Female" "Female" "Male"   "Female" "Female" "Female" "Female" "Male"   "Female" "Female" "Male"   "Female" "Male"   "Male"  
[225] "Male"   "Female" "Female" "Female" "Male"   "Male"   "Female" "Female" "Male"   "Female" "Female" "Male"   "Male"   "Male"  
[239] "Male"   "Male"   "Female" "Female" "Female" "Female" "Male"   "Male"   "Male"   "Male"   "Female" "Male"   "Female" "Male"  
[253] "Female" "Male"   "Male"   "Female" "Male"   "Male"   "Male"   "Male"   "Male"   "Male"   "Female" "Male"   "Female" "Male"  
[267] "Female" "Male"   "Male"   "Female" "Male"   "Male"   "Female" "Female" "Male"   "Male"   "Male"   "Male"   "Male"   "Female"
[281] "Male"   "Male"   "Male"   "Male"   "Male"   "Male"   "Female" "Male"   "Male"   "Male"   "Male"   "Female" "Female" "Female"
[295] "Male"   "Male"   "Male"   "Male"   "Female" "Female"
   TransactionID       CustomerID        ProductID         Quantity    PaymentMethod  TransactionDate  ProductCategory            Price 
               0                0                0                0                0                0                0                0 
          Rating      TotalAmount              Age           Gender         Location MembershipStatus 
               0                0                0               13                0                0 

2. Handling Outliers

Outlier Detection

• Detect and handle outliers in numerical variables (e.g., Age, Price, TotalAmount) using methods like the IQR rule or Z-score.

check for outliers using IQR

Variable: TransactionID - Outliers found: 0 
Variable: CustomerID - Outliers found: 0 
Variable: ProductID - Outliers found: 0 
Variable: Quantity - Outliers found: 0 
Variable: Price - Outliers found: 0 
Variable: Rating - Outliers found: 0 
Variable: TotalAmount - Outliers found: 4 
Variable: Age - Outliers found: 0 

Visualize outliers with boxplot

Remove outliers

[1] "Number of outliers removed: 4"

3. Exploratory Data Analysis (EDA)

Perform univariate and bivariate analysis to understand the distribution of variables and relationships between them # Summary statistics

 TransactionID      CustomerID       ProductID        Quantity     PaymentMethod      TransactionDate    ProductCategory   
 Min.   :  1.00   Min.   :  4.00   Min.   : 1.00   Min.   :1.000   Length:296         Length:296         Length:296        
 1st Qu.: 74.75   1st Qu.: 76.75   1st Qu.: 6.00   1st Qu.:2.000   Class :character   Class :character   Class :character  
 Median :149.50   Median :156.50   Median :11.00   Median :3.000   Mode  :character   Mode  :character   Mode  :character  
 Mean   :149.80   Mean   :154.93   Mean   :10.64   Mean   :3.101                                                           
 3rd Qu.:224.25   3rd Qu.:230.25   3rd Qu.:15.25   3rd Qu.:4.000                                                           
 Max.   :300.00   Max.   :299.00   Max.   :20.00   Max.   :5.000                                                           
     Price            Rating       TotalAmount           Age           Gender            Location         MembershipStatus  
 Min.   : 33.36   Min.   :1.400   Min.   :  33.36   Min.   :18.00   Length:296         Length:296         Length:296        
 1st Qu.:145.89   1st Qu.:2.100   1st Qu.: 348.95   1st Qu.:31.00   Class :character   Class :character   Class :character  
 Median :215.02   Median :2.600   Median : 650.96   Median :42.00   Mode  :character   Mode  :character   Mode  :character  
 Mean   :250.65   Mean   :2.932   Mean   : 782.45   Mean   :41.81                                                           
 3rd Qu.:341.40   3rd Qu.:3.700   3rd Qu.:1087.23   3rd Qu.:52.00                                                           
 Max.   :466.49   Max.   :5.000   Max.   :2252.85   Max.   :65.00                                                           

Univariate Analysis

Age distribution

product category distribution

Histogram of price

Bivariate Analysis

Relationship between Age and Total Amount

Bivariate analysise

BoxPlot of TotalAmount by ProductCategory

Payment method distribution by gender

contigency table of payment method vs membership status

                  
                   Basic Gold Premium
  Cash on Delivery    24   34      21
  Credit Card         22   16      25
  Debit Card          22   20      23
  UPI                 35   23      31

4 REGRESSION MODEL

• Build a regression model to predict TotalAmount based on variables like Age, Price, Quantity, and Rating.


Call:
lm(formula = TotalAmount ~ Age + Price + Rating + Quantity, data = ecommerce_cleaned)

Residuals:
    Min      1Q  Median      3Q     Max 
-493.37  -98.03    8.40   99.71  447.75 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept) -725.30851   52.37741 -13.848   <2e-16 ***
Age            0.08560    0.74111   0.116    0.908    
Price          3.14353    0.08184  38.412   <2e-16 ***
Rating        -8.46592    9.18348  -0.922    0.357    
Quantity     238.95715    6.71914  35.564   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 166.5 on 291 degrees of freedom
Multiple R-squared:  0.9076,    Adjusted R-squared:  0.9063 
F-statistic: 714.4 on 4 and 291 DF,  p-value: < 2.2e-16

model diagnostics

     Age    Price   Rating Quantity 
1.003959 1.006389 1.015030 1.011156 

Visualize residuals

5. Correlation analysis

Analyze the correlation between numerical variables (e.g., Price vs. TotalAmount, Age vs. TotalAmount).

Hypothesis:H0:There is significant relationship between the variables H1:There is no significant Relationship in atleast one of the variables # Select numeric variables

               Quantity       Price      Rating TotalAmount         Age
Quantity     1.00000000  0.02973474 -0.09877651  0.65943058  0.02206473
Price        0.02973474  1.00000000 -0.06313723  0.70665706 -0.04423694
Rating      -0.09877651 -0.06313723  1.00000000 -0.12278622  0.03821019
TotalAmount  0.65943058  0.70665706 -0.12278622  1.00000000 -0.01488728
Age          0.02206473 -0.04423694  0.03821019 -0.01488728  1.00000000

Correlation matrix

##pearson Rank

                    Age       Price    Quantity      Rating TotalAmount
Age          1.00000000 -0.04423694  0.02206473  0.03821019 -0.01488728
Price       -0.04423694  1.00000000  0.02973474 -0.06313723  0.70665706
Quantity     0.02206473  0.02973474  1.00000000 -0.09877651  0.65943058
Rating       0.03821019 -0.06313723 -0.09877651  1.00000000 -0.12278622
TotalAmount -0.01488728  0.70665706  0.65943058 -0.12278622  1.00000000

spearman

                     Age        Price    Quantity       Rating  TotalAmount
Age          1.000000000 -0.042935951  0.01352312  0.026838550 -0.009588703
Price       -0.042935951  1.000000000  0.01763169 -0.001029652  0.685290962
Quantity     0.013523121  0.017631694  1.00000000 -0.066746308  0.689802071
Rating       0.026838550 -0.001029652 -0.06674631  1.000000000 -0.057914324
TotalAmount -0.009588703  0.685290962  0.68980207 -0.057914324  1.000000000

6. Statistical Tests

• Perform a t-test to compare the average TotalAmount spent by male and female customers. • Perform a chi-square test to check the association between ProductCategory and PaymentMethod. • Perform ANOVA to compare the average TotalAmount across different MembershipStatus levels.


    Welch Two Sample t-test

data:  TotalAmount by Gender
t = -2.4726, df = 274.83, p-value = 0.01402
alternative hypothesis: true difference in means between group Female and group Male is not equal to 0
95 percent confidence interval:
 -285.1822  -32.3603
sample estimates:
mean in group Female   mean in group Male 
            696.0371             854.8084 

Chi-squared test for product category and payment method


    Pearson's Chi-squared test

data:  table(ecommerce_cleaned$ProductCategory, ecommerce_cleaned$PaymentMethod)
X-squared = 2.2394, df = 6, p-value = 0.8964

ANOVA for TotalAmount across MembershipStatus

                  Df   Sum Sq Mean Sq F value Pr(>F)
MembershipStatus   2   451973  225986   0.762  0.467
Residuals        293 86840140  296383               
[1] "No significant difference found in Total Amount across Membership Status levels."

7. DATA VISUALIZATION

Histogram of TotalAmount

Pie chart of membership status

Bar Chart: Avg TotalAmount by Location

Donut Chart of Payment Methods

Scatter Plot: Price vs TotalAmount

Box Plot of Ratings by Product Category

Save the cleaned dataset

Conclusion

This project provided a comprehensive analysis of the e-commerce dataset, revealing insights into customer behavior, product performance, and spending patterns. Key findings include: - The average age of customers is around 35 years, with a significant portion being in the 25-34 age range. - The most popular product categories are Electronics and Fashion, with Electronics having the highest average spending. - Payment methods are predominantly Credit Card and PayPal, with Credit Card being the most common.

LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KIyBFLWNvbW1lcmNlIFByb2plY3QgT25lLg0KDQojIEJ5IFByaWVzdGFtIE11cml0aGkuDQoNCg0KUHJvamVjdCBPdmVydmlldw0KVGhpcyBwcm9qZWN0IGFuYWx5emVzIGFuIGUtY29tbWVyY2UgZGF0YXNldCBjb250YWluaW5nIDMwMCB0cmFuc2FjdGlvbnMgd2l0aCBjdXN0b21lciBkZXRhaWxzLCBwcm9kdWN0IGluZm9ybWF0aW9uLCBhbmQgdHJhbnNhY3Rpb24gcmVjb3Jkcy4gVGhlIGdvYWwgaXMgdG8gdW5jb3ZlciBpbnNpZ2h0cyB0aHJvdWdoIGRhdGEgY2xlYW5pbmcsIGV4cGxvcmF0b3J5IGFuYWx5c2lzLCBzdGF0aXN0aWNhbCB0ZXN0cywgYW5kIHZpc3VhbGl6YXRpb24uDQojIFNldCBhIHdvcmtpbmcgZGlyZWN0b3J5Lg0KYGBge3J9DQppbmNsdWRlPUZBTFNFDQprbml0cjo6b3B0c19rbml0JHNldChyb290LmRpciA9ICJDOi9Vc2Vycy9VU0VSL09uZURyaXZlL0RvY3VtZW50cy9SIFRSQUlOTklORyIpDQpgYGANCg0KIyBMb2FkaW5nIExpYnJhcmllcy4NCmBgYHtyfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShyZWFkcikNCmxpYnJhcnkocmVhZHhsKQ0KDQpgYGANCg0KIyBJbXBvcnRpbmcgdGhlIGRhdGFzZXQuDQpgYGB7cn0NCmVjb21tZXJjZSA8LSByZWFkX2NzdigiRS1jb21tZXJjZV9kYXRhLmNzdiIpDQpoZWFkKGVjb21tZXJjZSkNCmBgYA0KIyBDaGVjayB0aGUgc3RydWN0dXJlIG9mIHRoZSBkYXRhc2V0Lg0KYGBge3J9DQpzdHIoZWNvbW1lcmNlKQ0KYGBgDQoNCiMjIDEuIEhhbmRsaW5nIE1pc3NpbmcgVmFsdWVzDQojIENoZWNrIGZvciBtaXNzaW5nIHZhbHVlcw0KYGBge3J9DQpjb2xTdW1zKGlzLm5hKGVjb21tZXJjZSkpDQpgYGANCiMgSW1wdXRlIG1pc3NpbmcgQWdlIHdpdGggbWVkaWFuDQpgYGB7cn0NCmVjb21tZXJjZSRBZ2UgPC0gaWZlbHNlKGlzLm5hKGVjb21tZXJjZSRBZ2UpLCANCiAgICAgICAgICAgICAgICAgICAgICAgIG1lZGlhbihlY29tbWVyY2UkQWdlLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgICAgICAgICAgICAgZWNvbW1lcmNlJEFnZSkNCnByaW50KGVjb21tZXJjZSRBZ2UpDQpgYGANCg0KYA0KIyMgaGFuZGxpbmcgbWlzc2luZyB2YWx1ZSBmb3IgZ2VuZGVyDQojIEZvciBHZW5kZXIscmVwbGFjZSB3aXRoICJtYWxlIiBjYXRlZ29yeQ0KYGBge3J9DQplY29tbWVyY2UkR2VuZGVyIDwtIGlmZWxzZShlY29tbWVyY2UkR2VuZGVyID09ICIiLCAiTkEiLCBlY29tbWVyY2UkR2VuZGVyKQ0KcHJpbnQoZWNvbW1lcmNlJEdlbmRlcikNCmBgYA0KDQoNCmBgYHtyfQ0KY29sU3Vtcyhpcy5uYShlY29tbWVyY2UpKQ0KYGBgDQoNCiMgMi4gSGFuZGxpbmcgT3V0bGllcnMNCiMjIE91dGxpZXIgRGV0ZWN0aW9uDQrigKIJRGV0ZWN0IGFuZCBoYW5kbGUgb3V0bGllcnMgaW4gbnVtZXJpY2FsIHZhcmlhYmxlcyAoZS5nLiwgQWdlLCBQcmljZSwgVG90YWxBbW91bnQpIHVzaW5nIG1ldGhvZHMgbGlrZSB0aGUgSVFSIHJ1bGUgb3IgWi1zY29yZS4NCg0KIyMgY2hlY2sgZm9yIG91dGxpZXJzIHVzaW5nIElRUg0KYGBge3J9DQojIEZ1bmN0aW9uIHRvIGZpbmQgb3V0bGllciBpbmRpY2VzIHVzaW5nIHRoZSBJUVIgbWV0aG9kDQpmaW5kX291dGxpZXJzX2lxciA8LSBmdW5jdGlvbih4KSB7DQogIFExIDwtIHF1YW50aWxlKHgsIDAuMjUsIG5hLnJtID0gVFJVRSkNCiAgUTMgPC0gcXVhbnRpbGUoeCwgMC43NSwgbmEucm0gPSBUUlVFKQ0KICBJUVJfdmFsdWUgPC0gUTMgLSBRMQ0KICBsb3dlcl9ib3VuZCA8LSBRMSAtIDEuNSAqIElRUl92YWx1ZQ0KICB1cHBlcl9ib3VuZCA8LSBRMyArIDEuNSAqIElRUl92YWx1ZQ0KICByZXR1cm4od2hpY2goeCA8IGxvd2VyX2JvdW5kIHwgeCA+IHVwcGVyX2JvdW5kKSkNCn0NCg0KIyBJZGVudGlmeSBudW1lcmljIGNvbHVtbnMNCm51bWVyaWNfY29sdW1ucyA8LSBzYXBwbHkoZWNvbW1lcmNlLCBpcy5udW1lcmljKQ0KDQojIEFwcGx5IHRoZSBvdXRsaWVyIGRldGVjdGlvbiBmdW5jdGlvbiB0byBlYWNoIG51bWVyaWMgY29sdW1uDQpvdXRsaWVyX2luZGljZXNfbGlzdCA8LSBsYXBwbHkoZWNvbW1lcmNlWywgbnVtZXJpY19jb2x1bW5zLCBkcm9wID0gRkFMU0VdLCBmaW5kX291dGxpZXJzX2lxcikNCg0KIyBQcmludCBzdW1tYXJ5IG9mIG91dGxpZXJzIGZvciBlYWNoIG51bWVyaWMgdmFyaWFibGUNCmZvciAoY29sIGluIG5hbWVzKG91dGxpZXJfaW5kaWNlc19saXN0KSkgew0KICBudW1fb3V0bGllcnMgPC0gbGVuZ3RoKG91dGxpZXJfaW5kaWNlc19saXN0W1tjb2xdXSkNCiAgY2F0KCJWYXJpYWJsZToiLCBjb2wsICItIE91dGxpZXJzIGZvdW5kOiIsIG51bV9vdXRsaWVycywgIlxuIikNCn0NCmBgYA0KIyBWaXN1YWxpemUgb3V0bGllcnMgd2l0aCBib3hwbG90DQpgYGB7cn0NCmdncGxvdChlY29tbWVyY2UsIGFlcyh5ID0gVG90YWxBbW91bnQpKSArDQogIGdlb21fYm94cGxvdCgpICsNCiAgZ2d0aXRsZSgiQm94cGxvdCBvZiBUb3RhbCBBbW91bnQgU3BlbnQiKQ0KYGBgDQoNCiMgUmVtb3ZlIG91dGxpZXJzDQpgYGB7cn0NCiMgU3RlcCAxOiBDYWxjdWxhdGUgSVFSIGJvdW5kcyBmb3IgVG90YWxBbW91bnQNClExIDwtIHF1YW50aWxlKGVjb21tZXJjZSRUb3RhbEFtb3VudCwgMC4yNSwgbmEucm0gPSBUUlVFKQ0KUTMgPC0gcXVhbnRpbGUoZWNvbW1lcmNlJFRvdGFsQW1vdW50LCAwLjc1LCBuYS5ybSA9IFRSVUUpDQpJUVJfdmFsdWUgPC0gUTMgLSBRMQ0KbG93ZXJfYm91bmQgPC0gUTEgLSAxLjUgKiBJUVJfdmFsdWUNCnVwcGVyX2JvdW5kIDwtIFEzICsgMS41ICogSVFSX3ZhbHVlDQoNCiMgU3RlcCAyOiBGaWx0ZXIgdGhlIGRhdGFzZXQgdG8gcmVtb3ZlIG91dGxpZXJzDQplY29tbWVyY2VfY2xlYW5lZCA8LSBlY29tbWVyY2UgJT4lDQogIGZpbHRlcihUb3RhbEFtb3VudCA+PSBsb3dlcl9ib3VuZCAmIFRvdGFsQW1vdW50IDw9IHVwcGVyX2JvdW5kKQ0KDQojIFN0ZXAgMzogT3B0aW9uYWwgLSBDb3VudCBob3cgbWFueSByb3dzIHdlcmUgcmVtb3ZlZA0Kb3V0bGllcnNfcmVtb3ZlZCA8LSBucm93KGVjb21tZXJjZSkgLSBucm93KGVjb21tZXJjZV9jbGVhbmVkKQ0KcHJpbnQocGFzdGUoIk51bWJlciBvZiBvdXRsaWVycyByZW1vdmVkOiIsIG91dGxpZXJzX3JlbW92ZWQpKQ0KYGBgDQojIDMuIEV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMgKEVEQSkNClBlcmZvcm0gdW5pdmFyaWF0ZSBhbmQgYml2YXJpYXRlIGFuYWx5c2lzIHRvIHVuZGVyc3RhbmQgdGhlIGRpc3RyaWJ1dGlvbiBvZiB2YXJpYWJsZXMgYW5kIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiB0aGVtDQojIFN1bW1hcnkgc3RhdGlzdGljcw0KYGBge3J9DQpzdW1tYXJ5KGVjb21tZXJjZV9jbGVhbmVkKQ0KYGBgDQojIFVuaXZhcmlhdGUgQW5hbHlzaXMNCiMgQWdlIGRpc3RyaWJ1dGlvbg0KYGBge3J9DQpnZ3Bsb3QoZWNvbW1lcmNlX2NsZWFuZWQsIGFlcyh4ID0gQWdlKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDUsIGZpbGwgPSAiYmx1ZSIsIGNvbG9yID0gImJsYWNrIikgKw0KICBsYWJzKHRpdGxlID0gIkFnZSBEaXN0cmlidXRpb24gb2YgQ3VzdG9tZXJzIiwgeCA9ICJBZ2UiLCB5ID0gIkZyZXF1ZW5jeSIpDQpgYGANCg0KIyBwcm9kdWN0IGNhdGVnb3J5IGRpc3RyaWJ1dGlvbg0KYGBge3J9DQpnZ3Bsb3QoZWNvbW1lcmNlX2NsZWFuZWQsIGFlcyh4ID0gUHJvZHVjdENhdGVnb3J5LCBmaWxsID0gUHJvZHVjdENhdGVnb3J5KSkgKw0KICBnZW9tX2JhcigpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgKw0KICBnZ3RpdGxlKCJQcm9kdWN0IENhdGVnb3J5IERpc3RyaWJ1dGlvbiIpDQoNCmBgYA0KIyMgSGlzdG9ncmFtIG9mIHByaWNlDQpgYGB7cn0NCmhpc3QoZWNvbW1lcmNlX2NsZWFuZWQkUHJpY2UsbWFpbj0iSGlzdG9ncmFtIG9mIFByaWNlIix4bGFiPSJQcmljZSIsY29sPSdwaW5rJykNCmBgYA0KIyBCaXZhcmlhdGUgQW5hbHlzaXMNCiMgUmVsYXRpb25zaGlwIGJldHdlZW4gQWdlIGFuZCBUb3RhbCBBbW91bnQNCmBgYHtyfQ0KZ2dwbG90KGVjb21tZXJjZSwgYWVzKHggPSBBZ2UsIHkgPSBUb3RhbEFtb3VudCkpICsNCiAgZ2VvbV9wb2ludChjb2xvciA9ICJibHVlIiwgYWxwaGEgPSAwLjUpICsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgY29sb3IgPSAicmVkIikgKw0KICBsYWJzKHRpdGxlID0gIkFnZSB2cyBUb3RhbCBBbW91bnQgU3BlbnQiLCB4ID0gIkFnZSIsIHkgPSAiVG90YWwgQW1vdW50IikNCmBgYA0KDQojIEJpdmFyaWF0ZSBhbmFseXNpc2UNCiMgQm94UGxvdCBvZiBUb3RhbEFtb3VudCBieSBQcm9kdWN0Q2F0ZWdvcnkNCmBgYHtyfQ0KZ2dwbG90KGVjb21tZXJjZV9jbGVhbmVkLCBhZXMoeCA9IFByb2R1Y3RDYXRlZ29yeSwgeSA9IFRvdGFsQW1vdW50LCBmaWxsID0gUHJvZHVjdENhdGVnb3J5KSkgKw0KICBnZW9tX2JveHBsb3QoKSArDQogIGdndGl0bGUoIlRvdGFsIEFtb3VudCBieSBQcm9kdWN0IENhdGVnb3J5IikNCg0KYGBgDQojIFBheW1lbnQgbWV0aG9kIGRpc3RyaWJ1dGlvbiBieSBnZW5kZXINCmBgYHtyfQ0KZ2dwbG90KGVjb21tZXJjZV9jbGVhbmVkLCBhZXMoeCA9IFBheW1lbnRNZXRob2QsIGZpbGwgPSBHZW5kZXIpKSArDQogIGdlb21fYmFyKHBvc2l0aW9uID0gImRvZGdlIikgKw0KICBnZ3RpdGxlKCJQYXltZW50IE1ldGhvZCBieSBHZW5kZXIiKQ0KYGBgDQojIyBjb250aWdlbmN5IHRhYmxlIG9mIHBheW1lbnQgbWV0aG9kIHZzIG1lbWJlcnNoaXAgc3RhdHVzDQpgYGB7cn0NCmNvbnRpbmdlbmN5X3RhYmxlPC10YWJsZShlY29tbWVyY2VfY2xlYW5lZCRQYXltZW50TWV0aG9kLGVjb21tZXJjZV9jbGVhbmVkJE1lbWJlcnNoaXBTdGF0dXMpDQpwcmludChjb250aW5nZW5jeV90YWJsZSkNCmBgYA0KDQojIyA0IFJFR1JFU1NJT04gTU9ERUwNCuKAoglCdWlsZCBhIHJlZ3Jlc3Npb24gbW9kZWwgdG8gcHJlZGljdCBUb3RhbEFtb3VudCBiYXNlZCBvbiB2YXJpYWJsZXMgbGlrZSBBZ2UsIFByaWNlLCBRdWFudGl0eSwgYW5kIFJhdGluZy4NCg0KYGBge3J9DQptb2RlbDwtbG0oVG90YWxBbW91bnR+QWdlK1ByaWNlK1JhdGluZytRdWFudGl0eSxkYXRhPWVjb21tZXJjZV9jbGVhbmVkKQ0Kc3VtbWFyeShtb2RlbCkNCmBgYA0KDQojIyBtb2RlbCBkaWFnbm9zdGljcw0KYGBge3J9DQpsaWJyYXJ5KGNhcikNCnZpZl92YWx1ZXM9dmlmKG1vZGVsKQ0KcHJpbnQodmlmX3ZhbHVlcykNCmBgYA0KYGBge3J9DQojIENoZWNrIHJlc2lkdWFscw0KcGFyKG1mcm93PWMoMiwyKSkNCnBsb3QobW9kZWwpDQoNCiMgUmVzaWR1YWxzIHZzIEZpdHRlZA0KZ2dwbG90KGRhdGEgPSBtb2RlbCwgYWVzKHggPSAuZml0dGVkLCB5ID0gLnJlc2lkKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJyZWQiKSArDQogIGdndGl0bGUoIlJlc2lkdWFscyB2cyBGaXR0ZWQgVmFsdWVzIikgKw0KICB4bGFiKCJGaXR0ZWQgVmFsdWVzIikgKw0KICB5bGFiKCJSZXNpZHVhbHMiKQ0KYGBgDQojIFZpc3VhbGl6ZSByZXNpZHVhbHMNCmBgYHtyfQ0KZ2dwbG90KG1vZGVsLCBhZXMoeCA9IC5maXR0ZWQsIHkgPSAucmVzaWQpKSArDQogIGdlb21fcG9pbnQoKSArDQogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gInJlZCIpICsNCiAgZ2d0aXRsZSgiUmVzaWR1YWxzIHZzIEZpdHRlZCBWYWx1ZXMiKSArDQogIHhsYWIoIkZpdHRlZCBWYWx1ZXMiKSArDQogIHlsYWIoIlJlc2lkdWFscyIpDQpwbG90KG1vZGVsLCB3aGljaCA9IDEpDQpgYGANCiMgNS4gQ29ycmVsYXRpb24gYW5hbHlzaXMNCglBbmFseXplIHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIG51bWVyaWNhbCB2YXJpYWJsZXMgKGUuZy4sIFByaWNlIHZzLiBUb3RhbEFtb3VudCwgQWdlIHZzLiBUb3RhbEFtb3VudCkuDQoNCkh5cG90aGVzaXM6SDA6VGhlcmUgaXMgc2lnbmlmaWNhbnQgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIHZhcmlhYmxlcw0KICAgICAgICAgICBIMTpUaGVyZSBpcyBubyBzaWduaWZpY2FudCBSZWxhdGlvbnNoaXAgaW4gYXRsZWFzdCBvbmUgb2YgdGhlIHZhcmlhYmxlcw0KIyBTZWxlY3QgbnVtZXJpYyB2YXJpYWJsZXMNCmBgYHtyfQ0KbnVtZXJpY192YXJzIDwtIGVjb21tZXJjZV9jbGVhbmVkICU+JSANCiAgc2VsZWN0KFF1YW50aXR5LCBQcmljZSwgUmF0aW5nLCBUb3RhbEFtb3VudCwgQWdlKQ0KY29yKG51bWVyaWNfdmFycykNCmBgYA0KDQojIENvcnJlbGF0aW9uIG1hdHJpeA0KYGBge3J9DQpjb3JfbWF0cml4IDwtIGNvcihudW1lcmljX3ZhcnMpDQpjb3JycGxvdChjb3JfbWF0cml4LCBtZXRob2QgPSAiY2lyY2xlIikNCmBgYA0KIyNwZWFyc29uIFJhbmsNCmBgYHtyfQ0KIyNwZWFyc29uIFJhbmsNCmxpYnJhcnkoY29ycnBsb3QpDQpudW1fZGF0YV9jbGVhbjwtZWNvbW1lcmNlX2NsZWFuZWRbLGMoIkFnZSIsIlByaWNlIiwiUXVhbnRpdHkiLCJSYXRpbmciLCJUb3RhbEFtb3VudCIpXQ0KcGVhcnNvbl9tYXRyaXg8LWNvcihudW1fZGF0YV9jbGVhbixtZXRob2Q9InBlYXJzb24iKQ0KcGVhcnNvbl9tYXRyaXgNCmBgYA0KIyMgc3BlYXJtYW4NCmBgYHtyfQ0KIyMgc3BlYXJtYW4NCmxpYnJhcnkoY29ycnBsb3QpDQpudW1fZGF0YV9jbGVhbjwtZWNvbW1lcmNlX2NsZWFuZWRbLGMoIkFnZSIsIlByaWNlIiwiUXVhbnRpdHkiLCJSYXRpbmciLCJUb3RhbEFtb3VudCIpXQ0Kc3BlYXJtYW5fbWF0cml4PC1jb3IobnVtX2RhdGFfY2xlYW4sbWV0aG9kPSJzcGVhcm1hbiIpDQpzcGVhcm1hbl9tYXRyaXgNCmBgYA0KIyA2LiBTdGF0aXN0aWNhbCBUZXN0cw0K4oCiCVBlcmZvcm0gYSB0LXRlc3QgdG8gY29tcGFyZSB0aGUgYXZlcmFnZSBUb3RhbEFtb3VudCBzcGVudCBieSBtYWxlIGFuZCBmZW1hbGUgY3VzdG9tZXJzLg0K4oCiCVBlcmZvcm0gYSBjaGktc3F1YXJlIHRlc3QgdG8gY2hlY2sgdGhlIGFzc29jaWF0aW9uIGJldHdlZW4gUHJvZHVjdENhdGVnb3J5IGFuZCBQYXltZW50TWV0aG9kLg0K4oCiCVBlcmZvcm0gQU5PVkEgdG8gY29tcGFyZSB0aGUgYXZlcmFnZSBUb3RhbEFtb3VudCBhY3Jvc3MgZGlmZmVyZW50IE1lbWJlcnNoaXBTdGF0dXMgbGV2ZWxzLg0KDQpgYGB7cn0NCiMjIEhfMDpUaGVyZSBpcyBhIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSBiZXR3ZWVuIG1hbGUgYW5kIGZlbWFsZSBzcGVuZGluZy4iKQ0KIyMgSF8xOlRoZXJlIGlzIG5vIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSBiZXR3ZWVuIG1hbGUgYW5kIGZlbWFsZSBzcGVuZGluZy4iKSANCnQudGVzdChUb3RhbEFtb3VudCB+IEdlbmRlciwgZGF0YSA9IGVjb21tZXJjZV9jbGVhbmVkICU+JSBmaWx0ZXIoR2VuZGVyICVpbiUgYygiTWFsZSIsICJGZW1hbGUiKSkpDQoNCmBgYA0KDQojIENoaS1zcXVhcmVkIHRlc3QgZm9yIHByb2R1Y3QgY2F0ZWdvcnkgYW5kIHBheW1lbnQgbWV0aG9kDQpgYGB7cn0NCiMgSOKCgDogVGhlcmUgaXMgYW4gYXNzb2NpYXRpb24gYmV0d2VlbiBQcm9kdWN0IENhdGVnb3J5IGFuZCBQYXltZW50IE1ldGhvZA0KIyNIMTpUaGVyZSBpcyBubyBhc3NvY2lhdGlvbiBiZXR3ZWVuIFByb2R1Y3QgQ2F0ZWdvcnkgYW5kIFBheW1lbnQgTWV0aG9kDQoNCmNoaXNxLnRlc3QodGFibGUoZWNvbW1lcmNlX2NsZWFuZWQkUHJvZHVjdENhdGVnb3J5LCBlY29tbWVyY2VfY2xlYW5lZCRQYXltZW50TWV0aG9kKSkNCmBgYA0KIyBBTk9WQSBmb3IgVG90YWxBbW91bnQgYWNyb3NzIE1lbWJlcnNoaXBTdGF0dXMNCmBgYHtyfQ0KIyBI4oKAOiBUaGVyZSBpcyBubyBzaWduaWZpY2FudCBkaWZmZXJlbmNlIGluIFRvdGFsIEFtb3VudCBhY3Jvc3MgZGlmZmVyZW50IE1lbWJlcnNoaXAgU3RhdHVzIGxldmVscw0KYW5vdmFfbW9kZWwgPC0gYW92KFRvdGFsQW1vdW50IH4gTWVtYmVyc2hpcFN0YXR1cywgZGF0YSA9IGVjb21tZXJjZV9jbGVhbmVkKQ0Kc3VtbWFyeShhbm92YV9tb2RlbCkNCg0KIyBQb3N0LWhvYyB0ZXN0IGlmIEFOT1ZBIGlzIHNpZ25pZmljYW50DQppZiAoc3VtbWFyeShhbm92YV9tb2RlbClbWzFdXVtbIlByKD5GKSJdXVsxXSA8IDAuMDUpIHsNCiAgcG9zdGhvYyA8LSBUdWtleUhTRChhbm92YV9tb2RlbCkNCiAgcHJpbnQocG9zdGhvYykNCn0gZWxzZSB7DQogIHByaW50KCJObyBzaWduaWZpY2FudCBkaWZmZXJlbmNlIGZvdW5kIGluIFRvdGFsIEFtb3VudCBhY3Jvc3MgTWVtYmVyc2hpcCBTdGF0dXMgbGV2ZWxzLiIpDQp9DQpgYGANCg0KIyA3LiBEQVRBIFZJU1VBTElaQVRJT04NCiMgSGlzdG9ncmFtIG9mIFRvdGFsQW1vdW50DQpgYGB7cn0NCmdncGxvdChlY29tbWVyY2VfY2xlYW5lZCwgYWVzKHggPSBUb3RhbEFtb3VudCkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDMwLCBmaWxsID0gInN0ZWVsYmx1ZSIpICsNCiAgZ2d0aXRsZSgiRGlzdHJpYnV0aW9uIG9mIFRvdGFsIEFtb3VudCBTcGVudCIpDQpgYGANCg0KIyBQaWUgY2hhcnQgb2YgbWVtYmVyc2hpcCBzdGF0dXMNCmBgYHtyfQ0KbWVtYmVyc2hpcF9jb3VudHMgPC0gZWNvbW1lcmNlX2NsZWFuZWQgJT4lIA0KICBjb3VudChNZW1iZXJzaGlwU3RhdHVzKSAlPiUgDQogIG11dGF0ZShwZXJjID0gbiAvIHN1bShuKSkNCm1lbWJlcnNoaXBfY291bnRzJE1lbWJlcnNoaXBTdGF0dXMgPC0gZmFjdG9yKG1lbWJlcnNoaXBfY291bnRzJE1lbWJlcnNoaXBTdGF0dXMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IG1lbWJlcnNoaXBfY291bnRzJE1lbWJlcnNoaXBTdGF0dXMpDQpnZ3Bsb3QobWVtYmVyc2hpcF9jb3VudHMsIGFlcyh4ID0gIiIsIHkgPSBwZXJjLCBmaWxsID0gTWVtYmVyc2hpcFN0YXR1cykpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMSkgKw0KICBjb29yZF9wb2xhcigieSIsIHN0YXJ0ID0gMCkgKw0KICBnZ3RpdGxlKCJNZW1iZXJzaGlwIFN0YXR1cyBEaXN0cmlidXRpb24iKSArDQogIHRoZW1lX3ZvaWQoKSArDQogIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkNCmBgYA0KDQojIEJhciBDaGFydDogQXZnIFRvdGFsQW1vdW50IGJ5IExvY2F0aW9uDQpgYGB7cn0NCmVjb21tZXJjZV9jbGVhbmVkICU+JSANCiAgZ3JvdXBfYnkoTG9jYXRpb24pICU+JSANCiAgc3VtbWFyaXNlKGF2Z19hbW91bnQgPSBtZWFuKFRvdGFsQW1vdW50KSkgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSByZW9yZGVyKExvY2F0aW9uLCBhdmdfYW1vdW50KSwgeSA9IGF2Z19hbW91bnQsIGZpbGwgPSBMb2NhdGlvbikpICsNCiAgZ2VvbV9jb2woKSArDQogIGNvb3JkX2ZsaXAoKSArDQogIGdndGl0bGUoIkF2ZXJhZ2UgVG90YWwgQW1vdW50IGJ5IExvY2F0aW9uIikgKw0KICB4bGFiKCJMb2NhdGlvbiIpICsNCiAgeWxhYigiQXZlcmFnZSBUb3RhbCBBbW91bnQiKQ0KYGBgDQoNCiMgRG9udXQgQ2hhcnQgb2YgUGF5bWVudCBNZXRob2RzDQpgYGB7cn0NCnBheW1lbnRfY291bnRzIDwtIGVjb21tZXJjZV9jbGVhbmVkICU+JSANCiAgY291bnQoUGF5bWVudE1ldGhvZCkgJT4lIA0KICBtdXRhdGUocGVyYyA9IG4gLyBzdW0obikpDQpnZ3Bsb3QocGF5bWVudF9jb3VudHMsIGFlcyh4ID0gMiwgeSA9IHBlcmMsIGZpbGwgPSBQYXltZW50TWV0aG9kKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5Iiwgd2lkdGggPSAxKSArDQogIGNvb3JkX3BvbGFyKHRoZXRhID0gInkiLCBzdGFydCA9IDApICsNCiAgeGxpbSgwLjUsIDIuNSkgKw0KICBnZ3RpdGxlKCJQYXltZW50IE1ldGhvZCBEaXN0cmlidXRpb24iKSArDQogIHRoZW1lX3ZvaWQoKSArDQogIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkNCmBgYA0KDQojIFNjYXR0ZXIgUGxvdDogUHJpY2UgdnMgVG90YWxBbW91bnQNCmBgYHtyfQ0KZ2dwbG90KGVjb21tZXJjZV9jbGVhbmVkLCBhZXMoeCA9IFByaWNlLCB5ID0gVG90YWxBbW91bnQpKSArDQogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjYpICsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIikgKw0KICBnZ3RpdGxlKCJQcmljZSB2cyBUb3RhbCBBbW91bnQgU3BlbnQiKQ0KYGBgDQoNCiMgQm94IFBsb3Qgb2YgUmF0aW5ncyBieSBQcm9kdWN0IENhdGVnb3J5DQpgYGB7cn0NCmdncGxvdChlY29tbWVyY2VfY2xlYW5lZCwgYWVzKHggPSBQcm9kdWN0Q2F0ZWdvcnksIHkgPSBSYXRpbmcsIGZpbGwgPSBQcm9kdWN0Q2F0ZWdvcnkpKSArDQogIGdlb21fYm94cGxvdCgpICsNCiAgZ2d0aXRsZSgiUHJvZHVjdCBSYXRpbmdzIGJ5IENhdGVnb3J5IikNCmBgYA0KIyBTYXZlIHRoZSBjbGVhbmVkIGRhdGFzZXQNCmBgYHtyfQ0Kd3JpdGVfY3N2KGVjb21tZXJjZV9jbGVhbmVkLCAiZWNvbW1lcmNlX2NsZWFuZWQuY3N2IikNCmBgYA0KDQojIENvbmNsdXNpb24NClRoaXMgcHJvamVjdCBwcm92aWRlZCBhIGNvbXByZWhlbnNpdmUgYW5hbHlzaXMgb2YgdGhlIGUtY29tbWVyY2UgZGF0YXNldCwgcmV2ZWFsaW5nIGluc2lnaHRzIGludG8gY3VzdG9tZXIgYmVoYXZpb3IsIHByb2R1Y3QgcGVyZm9ybWFuY2UsIGFuZCBzcGVuZGluZyBwYXR0ZXJucy4gS2V5IGZpbmRpbmdzIGluY2x1ZGU6DQotIFRoZSBhdmVyYWdlIGFnZSBvZiBjdXN0b21lcnMgaXMgYXJvdW5kIDM1IHllYXJzLCB3aXRoIGEgc2lnbmlmaWNhbnQgcG9ydGlvbiBiZWluZyBpbiB0aGUgMjUtMzQgYWdlIHJhbmdlLg0KLSBUaGUgbW9zdCBwb3B1bGFyIHByb2R1Y3QgY2F0ZWdvcmllcyBhcmUgRWxlY3Ryb25pY3MgYW5kIEZhc2hpb24sIHdpdGggRWxlY3Ryb25pY3MgaGF2aW5nIHRoZSBoaWdoZXN0IGF2ZXJhZ2Ugc3BlbmRpbmcuDQotIFBheW1lbnQgbWV0aG9kcyBhcmUgcHJlZG9taW5hbnRseSBDcmVkaXQgQ2FyZCBhbmQgUGF5UGFsLCB3aXRoIENyZWRpdCBDYXJkIGJlaW5nIHRoZSBtb3N0IGNvbW1vbi4NCg0KDQoNCg0KDQoNCg0KDQoNCg==