Required packages

The following packages were used during the course of this assignment.


library(readr)
library(lubridate)
library(dplyr)
library(tidyr)
library(magrittr)
library(MVN)

Executive Summary

Data preprocessing is a cruical step in data anaylsis. It prepares the data for further statistical analysis to obtain accurate results by ensuring that the data is clean and tidy. For this report, the following data preprocessing steps were taken:

Data

The two datasets used in the report are the Brazilian E-Commerce Datasets by Olist taken from:
Olist order Items Dataset: https://www.kaggle.com/olistbr/brazilian-ecommerce?select=olist_order_items_dataset.csv
Olist Sellers Dataset: https://www.kaggle.com/olistbr/brazilian-ecommerce?select=olist_sellers_dataset.csv

The accompanying datasets have data of orders made at Olist, the biggest retail chain in Brazilian commercial centers. Olist interfaces little organizations from all over Brazil to channels without trouble and with a solitary agreement. When a client buys from Olist, the dealer gets educated to satisfy that order.It comprises of 100k requests from 2016 to 2018 made at various commercial centers in Brazil.

The first dataset used is “Olist Order Items Dataset”. It provides data about items purchased within each order. This dataset consist of 112650 observations and the following 7 variables:

The second dataset used is “Olist Sellers Dataset”. This dataset incorporates data about the sellers that finished requests made at Olist. There are 3095 observations and 4 variables:

The two datasets were merged into one, by the common attribute ‘seller_id’ to show information about items in each order and its seller. The resultant dataset had 2 numeric variables, namely, ‘price’ and ‘freight_value’.


#Reading the Order Items Dataset
order_items<- read_csv("olist_order_items_dataset.csv")
Parsed with column specification:
cols(
  order_id = col_character(),
  order_item_id = col_double(),
  product_id = col_character(),
  seller_id = col_character(),
  shipping_limit_date = col_character(),
  price = col_double(),
  freight_value = col_double()
)
head(order_items)

#Reading the Sellers Dataset
seller<-read_csv("olist_sellers_dataset.csv")
Parsed with column specification:
cols(
  seller_id = col_character(),
  seller_zip_code_prefix = col_double(),
  seller_city = col_character(),
  seller_state = col_character()
)
head(seller)

#Merging the datasets Olist Order Items and Olist Sellers 
join<- order_items %>% left_join(seller, by= "seller_id")
head(join)
NA

Understand


#Checking dimension of 'join'
dim(join)
[1] 112650     10
#Subsetting with first 5000 observations
seller_order_list<- join[1:5000,]
dim(seller_order_list)
[1] 5000   10
str(seller_order_list)
tibble [5,000 x 10] (S3: tbl_df/tbl/data.frame)
 $ order_id              : chr [1:5000] "00010242fe8c5a6d1ba2dd792cb16214" "00018f77f2f0320c557190d7a144bdd3" "000229ec398224ef6ca0657da4fc703e" "00024acbcdf0a6daa1e931b038114c75" ...
 $ order_item_id         : num [1:5000] 1 1 1 1 1 1 1 1 1 1 ...
 $ product_id            : chr [1:5000] "4244733e06e7ecb4970a6e2683c13e61" "e5f2d52b802189ee658865ca93d83a8f" "c777355d18b72b67abbeef9df44fd0fd" "7634da152a4610f1595efa32f14722fc" ...
 $ seller_id             : chr [1:5000] "48436dade18ac8b2bce089ec2a041202" "dd7ddc04e1b6c2c614352b383efe2d36" "5b51032eddd242adc84c38acab88f23d" "9d7a1d34a5052409006425275ba1c2b4" ...
 $ shipping_limit_date   : chr [1:5000] "19-09-2017 09:45" "03-05-2017 11:05" "18-01-2018 14:48" "15-08-2018 10:10" ...
 $ price                 : num [1:5000] 58.9 239.9 199 13 199.9 ...
 $ freight_value         : num [1:5000] 13.3 19.9 17.9 12.8 18.1 ...
 $ seller_zip_code_prefix: num [1:5000] 27277 3471 37564 14403 87900 ...
 $ seller_city           : chr [1:5000] "volta redonda" "sao paulo" "borda da mata" "franca" ...
 $ seller_state          : chr [1:5000] "SP" "SP" "MG" "SP" ...
#Checking the data types of all 10 variables
class(seller_order_list$order_id)
[1] "character"
class(seller_order_list$order_item_id)
[1] "numeric"
class(seller_order_list$product_id)
[1] "character"
class(seller_order_list$seller_id)
[1] "character"
class(seller_order_list$shipping_limit_date)
[1] "character"
class(seller_order_list$price)
[1] "numeric"
class(seller_order_list$freight_value)
[1] "numeric"
class(seller_order_list$seller_zip_code_prefix)
[1] "numeric"
class(seller_order_list$seller_city)
[1] "character"
class(seller_order_list$seller_state)
[1] "character"
#Type conversions
#Converting 'seller_state' to a fctor variable
seller_order_list$seller_state<- factor(seller_order_list$seller_state, 
                                        levels = c("AC","AM","BA","CE","DF","ES","GO","MA","MG","MS","MT","PA","PB","PE","PI","PR","RJ","RN","RO","RS","SC","SE","SP"))
levels(seller_order_list$seller_state)
 [1] "AC" "AM" "BA" "CE" "DF" "ES" "GO" "MA" "MG" "MS" "MT" "PA" "PB" "PE" "PI"
[16] "PR" "RJ" "RN" "RO" "RS" "SC" "SE" "SP"
class(seller_order_list$seller_state)
[1] "factor"
#Converting 'seller_zip_code_prefix' to a character variable
seller_order_list$seller_zip_code_prefix<- as.character(seller_order_list$seller_zip_code_prefix)
class(seller_order_list$seller_zip_code_prefix)
[1] "character"

Tidy & Manipulate Data I


#Separating the 'shipping_limit_date' into two columns
seller_order_list<-separate(seller_order_list,shipping_limit_date, into = c("Shipping Date", "Shipping Time"), sep = " ")
seller_order_list %>% head(10)

#Converting 'Shipping Date' to date format
seller_order_list$`Shipping Date`<- format(as.Date(seller_order_list$`Shipping Date`, format = "%d-%m-%Y"), "%d-%m-%Y")
seller_order_list$`Shipping Date` %>% head(10)
 [1] "19-09-2017" "03-05-2017" "18-01-2018" "15-08-2018" "13-02-2017"
 [6] "23-05-2017" "14-12-2017" "10-07-2018" "26-03-2018" "06-07-2018"

Tidy & Manipulate Data II


#Mutating total price column
seller_order_list<- seller_order_list %>% group_by(order_id) %>%
  mutate(total_order_value= (price * length(order_id)+(freight_value * length(order_id))))

seller_order_list$total_order_value %>% head(10)
 [1]  72.19 259.83 216.87  25.78 218.04  34.59  31.75 880.75 157.60  65.39

Scan I


#Scanning for missing values
colSums(is.na(seller_order_list))
              order_id          order_item_id             product_id 
                     0                      0                      0 
             seller_id          Shipping Date          Shipping Time 
                     0                      0                      0 
                 price          freight_value seller_zip_code_prefix 
                     0                      0                      0 
           seller_city           seller_state      total_order_value 
                     0                      0                      0 
#Scanning for special values
sub<- seller_order_list %>% select(price, freight_value, total_order_value)
Adding missing grouping variables: `order_id`
seller_order_sub<- sub[,2:4]

special_values <- function(x){
  if (is.numeric(x)) (is.infinite(x) | is.nan(x))
}

sp_values<-sapply(seller_order_sub, FUN = special_values)
sapply(seller_order_sub, function(x){if (is.numeric(x)) sum(special_values(x))})
            price     freight_value total_order_value 
                0                 0                 0 
##Scanning for inconsistencies or obvious errors 
nonnegative<- function(x){x<0}
nonnegative_price<-sapply(seller_order_sub, FUN = nonnegative)
colSums(nonnegative_price)
            price     freight_value total_order_value 
                0                 0                 0 

Scan II


# Mahanabolis Outlier detection method
seller_order_outliers <- mvn(data = seller_order_sub, multivariateOutlierMethod = "quan", showOutliers = TRUE)
The covariance matrix has become singular during
the iterations of the MCD algorithm.
There are 3893 observations (in the entire dataset of 5000 obs.) lying
on the plane with equation 0.57735 (x_i1-m_1) + 0.57735 (x_i2-m_2) +
-0.57735 (x_i3-m_3) = 0 with (m_1,m_2) the mean of these observations.

#Checking locations of the outliers
seller_order_outliers$multivariateOutliers

#Capping
cap <- function(x){
  quantiles <- quantile( x, c(.05, 0.25, 0.75, .95 ) )
  x[ x < quantiles[2] - 1.5*IQR(x) ] <- quantiles[1]
  x[ x > quantiles[3] + 1.5*IQR(x) ] <- quantiles[4]
  x
}

#Descriptive statistics of the subset
summary(seller_order_sub)
     price         freight_value    total_order_value 
 Min.   :   3.49   Min.   :  0.00   Min.   :   13.38  
 1st Qu.:  39.99   1st Qu.: 13.11   1st Qu.:   66.25  
 Median :  77.90   Median : 16.41   Median :  114.92  
 Mean   : 124.36   Mean   : 20.28   Mean   :  198.56  
 3rd Qu.: 138.00   3rd Qu.: 21.64   3rd Qu.:  191.67  
 Max.   :6735.00   Max.   :375.28   Max.   :13664.08  
#Applying cap() to the numeric variables
price_capped<- seller_order_list$price %>% cap()
freight_value_capped<- seller_order_list$freight_value %>% cap()
total_price_capped<- seller_order_list$total_order_value %>% cap()

#Checking the summary statistics again
seller_order_capped<- sapply(seller_order_sub, FUN = cap)
summary(seller_order_capped)
     price        freight_value   total_order_value
 Min.   :  3.49   Min.   : 1.09   Min.   : 13.38   
 1st Qu.: 39.99   1st Qu.:13.11   1st Qu.: 66.25   
 Median : 77.90   Median :16.41   Median :114.92   
 Mean   :104.66   Mean   :19.29   Mean   :157.57   
 3rd Qu.:138.00   3rd Qu.:21.64   3rd Qu.:191.67   
 Max.   :350.44   Max.   :46.41   Max.   :514.40   

Transform


# Checking the distribution of total_price_capped
hist(total_price_capped, main = "Histogram for total_order_value", xlab = "total_order_value")


#Applying natural log transformation
ln_total<- log(total_price_capped)
hist(ln_total,main = "Log Transformation of Total Price", xlab = "Total Price")


# Checking the distribution of price_capped
hist(price_capped, main = "Histogram for price", xlab = "Price of the order item")


#Applying natural log transformation
ln_price<- log(price_capped)
hist(ln_price,main = "Log Transformation of Price", xlab = "Price of the order item")


# Checking the distribution of freight_value_capped
hist(freight_value_capped, main = "Histogram for freight_value", xlab = "Freight value")


#Applying square root transformation
sqrt_total<- sqrt(freight_value_capped)
hist(sqrt_total, main = "Square Root Transformation of  freight_value", xlab = "Freight value")



LS0tDQp0aXRsZTogIk1BVEgyMzQ5IFNlbWVzdGVyIDEsIDIwMjAiDQphdXRob3I6ICJBbnVzaGthIFNoYXJtYSAzODE3MDA0Ig0Kc3VidGl0bGU6IEFzc2lnbm1lbnQgMg0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOiBkZWZhdWx0DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgZGZfcHJpbnQ6IHBhZ2VkDQotLS0NCg0KIyMgUmVxdWlyZWQgcGFja2FnZXMgDQoNCg0KVGhlIGZvbGxvd2luZyBwYWNrYWdlcyB3ZXJlIHVzZWQgZHVyaW5nIHRoZSBjb3Vyc2Ugb2YgdGhpcyBhc3NpZ25tZW50Lg0KDQpgYGB7cn0NCg0KbGlicmFyeShyZWFkcikNCmxpYnJhcnkobHVicmlkYXRlKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkodGlkeXIpDQpsaWJyYXJ5KG1hZ3JpdHRyKQ0KbGlicmFyeShNVk4pDQoNCmBgYA0KDQoNCiMjIEV4ZWN1dGl2ZSBTdW1tYXJ5IA0KDQpEYXRhIHByZXByb2Nlc3NpbmcgaXMgYSBjcnVpY2FsIHN0ZXAgaW4gZGF0YSBhbmF5bHNpcy4gSXQgcHJlcGFyZXMgdGhlIGRhdGEgZm9yIGZ1cnRoZXIgc3RhdGlzdGljYWwgYW5hbHlzaXMgdG8gb2J0YWluIGFjY3VyYXRlIHJlc3VsdHMgYnkgZW5zdXJpbmcgdGhhdCB0aGUgZGF0YSBpcyBjbGVhbiBhbmQgdGlkeS4gRm9yIHRoaXMgcmVwb3J0LCB0aGUgZm9sbG93aW5nIGRhdGEgcHJlcHJvY2Vzc2luZyBzdGVwcyB3ZXJlIHRha2VuOg0KDQoqIFRoZSBkYXRhc2V0cyB3ZXJlIGltcG9ydGVkIGludG8gUiBzdHVkaW8gdXNpbmcgcmVhZHIgbGlicmFyeSBmdW5jdGlvbiBhbmQgd2VyZSBtZXJnZWQgYmFzZWQgb24gdGhlIGNvbW1vbiBhdHRyaWJ1dGUuDQoqIE9uY2UgaW1wb3J0ZWQsYSBzdWJzZXQgb2YgdGhlIG9yaWdpbmFsIGRhdGFzZXQgd2FzIGNyZWF0ZWQgZm9yIGZ1cnRoZXIgb3BlcmF0aW9ucyB0aGF0IGluY2x1ZGVzIHRoZSBmcmlzdCA1MDAwIG9ic2VydmF0aW9ucy4gVGhlIGRpbWVuc2lvbmFsaXR5IGFuZCBzdHJ1Y3R1cmUgb2YgdGhlIGRhdGFzZXQgd2FzIGNoZWNrZWQgYWxvbmcgd2l0aCB1bmRlcnN0YW5kaW5nIHRoZSBzZW1hbnRpY3Mgb2YgdGhlIHZhcmlhYmxlcy4gTmVjZXNzYXJ5IHR5cGUgY29udmVyc2lvbnMgd2VyZSBtYWRlIGluIG9yZGVyIHRvIHByZXNlcnZlIHRoZSBtZWFuaW5nIG9mIHRoZSB2YXJpYWJsZXMuDQoqIFRoZSBkYXRhc2V0cyB3ZXJlIGV4YW1pbmVkIHRvIHNlZSBpZiB0aGV5IHdlcmUgdW50aWR5IGFuZCBvbmUgb2YgdGhlIGRhdGFzZXQgd2FzIG1lc3N5IGFzIG9uZSBvZiBpdHMgY29sdW1ucyBjb21wcmlzZWQgb2YgbXVsdGlwbGUgdmFyaWFibGVzLiBUaGUgcmVzcGVjdGl2ZSBkYXRhc2V0IHdhcyB0aGVuIHRpZGllZCB1c2luZyBzZXBhcmF0ZSgpIGZ1bmN0aW9uLg0KKiBPbmNlIHRpZHksIGEgbmV3IHZhcmlhYmxlIHdhcyBhZGRlZCB0byB0aGUgZGF0YXNldCB1c2luZyBtdXRhdGUoKSBmdW5jdGlvbiB0aGF0IHdhcyBjcmVhdGVkIGZyb20gdGhlIGFscmVhZHkgZXhpc3RpbmcgdmFyaWFibGVzLg0KKiBUaGUgbmV4dCBzdGVwIHdhcyB0byBzY2FuIHRoZSBkYXRhc2V0IGZvciBtaXNzaW5nIHZhbHVlcyBhbG9uZyB3aXRoIHNwZWNpYWwgYW5kIGluY29uc2lzdGVudCB2YWx1ZXMuIE5vIHN1Y2ggdmFsdWVzIHdlcmUgZm91bmQgaW4gdGhlIGRhdGFzZXQuDQoqIEFmdGVyIGxvb2tpbmcgZm9yIG1pc3NpbmcgdmFsdWVzLCBwcmVzZW5jZSBvZiBvdXRsaWVycyBpbiBudW1lcmljIHZhcmlhYmxlcyB3ZXJlIGRldGVjdGVkIHVzaW5nIE1WTiBwYWNrYWdlIGFuZCB3ZXJlIGRlYWx0IGJ5IGNhcHBpbmcgb3Igd2luc29yaXNpbmcuDQoqIEZpbmFsbHksIGRpc3RyaWJ1dGlvbnMgb2YgdGhlIG51bWVyaWMgdmFyaWFibGVzIHdlcmUgY2hlY2tlZCB1c2luZyBoaXN0b2dyYW0gcGxvdHMgYW5kIGFwcHJvcHJpYXRlIHRyYW5zZm9ybWF0aW9ucyB3ZXJlIGFwcGxpZWQgdG8gcmVkdWNlIHRoZSBza2V3bmVzcy4NCg0KIyMgRGF0YSANCg0KVGhlIHR3byBkYXRhc2V0cyB1c2VkIGluIHRoZSByZXBvcnQgYXJlIHRoZSBCcmF6aWxpYW4gRS1Db21tZXJjZSBEYXRhc2V0cyBieSBPbGlzdCB0YWtlbiBmcm9tOg0KPGJyPg0KT2xpc3Qgb3JkZXIgSXRlbXMgRGF0YXNldDogaHR0cHM6Ly93d3cua2FnZ2xlLmNvbS9vbGlzdGJyL2JyYXppbGlhbi1lY29tbWVyY2U/c2VsZWN0PW9saXN0X29yZGVyX2l0ZW1zX2RhdGFzZXQuY3N2DQo8YnI+DQpPbGlzdCBTZWxsZXJzIERhdGFzZXQ6IA0KaHR0cHM6Ly93d3cua2FnZ2xlLmNvbS9vbGlzdGJyL2JyYXppbGlhbi1lY29tbWVyY2U/c2VsZWN0PW9saXN0X3NlbGxlcnNfZGF0YXNldC5jc3YNCjxicj4NCg0KVGhlIGFjY29tcGFueWluZyBkYXRhc2V0cyBoYXZlIGRhdGEgb2Ygb3JkZXJzIG1hZGUgYXQgT2xpc3QsIHRoZSBiaWdnZXN0IHJldGFpbCBjaGFpbiBpbiBCcmF6aWxpYW4gY29tbWVyY2lhbCBjZW50ZXJzLiBPbGlzdCBpbnRlcmZhY2VzIGxpdHRsZSBvcmdhbml6YXRpb25zIGZyb20gYWxsIG92ZXIgQnJhemlsIHRvIGNoYW5uZWxzIHdpdGhvdXQgdHJvdWJsZSBhbmQgd2l0aCBhIHNvbGl0YXJ5IGFncmVlbWVudC4gV2hlbiBhIGNsaWVudCBidXlzIGZyb20gT2xpc3QsIHRoZSBkZWFsZXIgZ2V0cyBlZHVjYXRlZCB0byBzYXRpc2Z5IHRoYXQgb3JkZXIuSXQgY29tcHJpc2VzIG9mIDEwMGsgcmVxdWVzdHMgZnJvbSAyMDE2IHRvIDIwMTggbWFkZSBhdCB2YXJpb3VzIGNvbW1lcmNpYWwgY2VudGVycyBpbiBCcmF6aWwuIA0KPGJyPg0KDQpUaGUgZmlyc3QgZGF0YXNldCB1c2VkIGlzICJPbGlzdCBPcmRlciBJdGVtcyBEYXRhc2V0Ii4gSXQgcHJvdmlkZXMgZGF0YSBhYm91dCBpdGVtcyBwdXJjaGFzZWQgd2l0aGluIGVhY2ggb3JkZXIuIFRoaXMgZGF0YXNldCBjb25zaXN0IG9mIDExMjY1MCBvYnNlcnZhdGlvbnMgYW5kIHRoZSBmb2xsb3dpbmcgNyB2YXJpYWJsZXM6DQoNCiogT3JkZXJfaWQgOiBJRCBvZiBvcmRlciB3aGljaCBpcyB1bmlxdWUgZm9yIGVhY2ggb3JkZXINCg0KKiBPcmRlcl9pdGVtX2lkIDogVGhlIG51bWJlciBvZiBpdGVtcyBpbiBhIHBhcnRpY3VsYXIgb3JkZXIsIHJlcHJlc2VudGVkIHNlcXVlbnRpYWxseQ0KDQoqIFByb2R1Y3RfaWQgOiBJRCBvZiBwcm9kdWN0IHdoaWNoIGlzIHVuaXF1ZSBmb3IgZWFjaCBwcm9kdWN0DQoNCiogU2VsbGVyX2lkIDogSUQgb2Ygc2VsbGVyIHdoaWNoIGlzIHVuaXF1ZSBmb3IgZWFjaCBzZWxsZXINCg0KKiBTaGlwcGluZ19saW1pdF9kYXRlIDogUmVwcmVzZW50cyB0aGUgc2hpcHBpbmcgZGF0ZSBhbmQgdGltZSBieSB0aGUgc2VsbGVyIHRvIGhhbmRsZSBvdmVyIHRoZSBwcm9kdWN0cyB0byB0aGUgbG9naXN0aWMgcGFydG5lcnMNCg0KKiBQcmljZSA6IFByaWNlIG9mIHRoZSBpdGVtDQoNCiogRnJlaWdodF92YWx1ZSA6IEZyZWlnaHQgdmFsdWUgb2YgaXRlbQ0KDQoNClRoZSBzZWNvbmQgZGF0YXNldCB1c2VkIGlzICJPbGlzdCBTZWxsZXJzIERhdGFzZXQiLiBUaGlzIGRhdGFzZXQgaW5jb3Jwb3JhdGVzIGRhdGEgYWJvdXQgdGhlIHNlbGxlcnMgdGhhdCBmaW5pc2hlZCByZXF1ZXN0cyBtYWRlIGF0IE9saXN0LiBUaGVyZSBhcmUgMzA5NSBvYnNlcnZhdGlvbnMgYW5kIDQgdmFyaWFibGVzOg0KDQoqIFNlbGxlcl9pZCA6IFVuaXF1ZSBzZWxsZXIgaWRlbnRpZmllcg0KDQoqIFNlbGxlcl96aXBfY29kZV9wcmVmaXggOiBUaGUgZmlyc3QgZml2ZSBkaWdpdHMgb2Ygc2VsbGVyJ3MgemlwIGNvZGUNCg0KKiBTZWxsZXJfY2l0eSA6IFNlbGxlcidzIGNpdHkgbmFtZQ0KDQoqIFNlbGxlcl9zdGF0ZSA6IFN0YXRlIG9mIHRoZSBTZWxsZXINCg0KVGhlIHR3byBkYXRhc2V0cyB3ZXJlIG1lcmdlZCBpbnRvIG9uZSwgYnkgdGhlIGNvbW1vbiBhdHRyaWJ1dGUgJ3NlbGxlcl9pZCcgdG8gc2hvdyBpbmZvcm1hdGlvbiBhYm91dCBpdGVtcyBpbiBlYWNoIG9yZGVyIGFuZCBpdHMgc2VsbGVyLiBUaGUgcmVzdWx0YW50IGRhdGFzZXQgaGFkIDIgbnVtZXJpYyB2YXJpYWJsZXMsIG5hbWVseSwgJ3ByaWNlJyBhbmQgJ2ZyZWlnaHRfdmFsdWUnLg0KDQoqIFRoZSBkYXRhc2V0cyB3ZXJlIHJlYWQgaW4gUiBzdHVkaW8gdXNpbmcgcmVhZF9jc3YoKSBmdW5jdGlvbiBmcm9tICdyZWFkcicgcGFja2FnZS4NCiogaGVhZCgpIGZ1bmN0aW9uIHdhcyB1c2VkIHRvIGRpc3BsYXkgaW5pdGlhbCBvYnNlcnZhdGlvbnMgb2YgdGhlIGRhdGFzZXRzIGFsb25nIHdpdGggdGhlIGhlYWRlci4NCiogbGVmdF9qb2luKCkgZnVuY3Rpb24gd2FzIHVzZWQgdG8gam9pbiB0aGUgdHdvIGRhdGFzZXRzIGJ5IHRoZSB2YXJpYWJsZSAnc2VsbGVyX2lkJyB0byBkaXNwbGF5IGFsbCB0aGUgb3JkZXIgaXRlbXMgaW5mb3JtYXRpb24gYWxvbmcgd2l0aCB0aGVpciByZXNwZWN0aXZlIHNlbGxlcidzIGRldGFpbHMuIEl0IHdhcyB0aGVuIGRpc3BsYXllZCB1c2luZyBoZWFkKCkgZnVuY3Rpb24uDQoNCmBgYHtyfQ0KDQojUmVhZGluZyB0aGUgT3JkZXIgSXRlbXMgRGF0YXNldA0Kb3JkZXJfaXRlbXM8LSByZWFkX2Nzdigib2xpc3Rfb3JkZXJfaXRlbXNfZGF0YXNldC5jc3YiKQ0KaGVhZChvcmRlcl9pdGVtcykNCg0KI1JlYWRpbmcgdGhlIFNlbGxlcnMgRGF0YXNldA0Kc2VsbGVyPC1yZWFkX2Nzdigib2xpc3Rfc2VsbGVyc19kYXRhc2V0LmNzdiIpDQpoZWFkKHNlbGxlcikNCg0KI01lcmdpbmcgdGhlIGRhdGFzZXRzIE9saXN0IE9yZGVyIEl0ZW1zIGFuZCBPbGlzdCBTZWxsZXJzIA0Kam9pbjwtIG9yZGVyX2l0ZW1zICU+JSBsZWZ0X2pvaW4oc2VsbGVyLCBieT0gInNlbGxlcl9pZCIpDQpoZWFkKGpvaW4pDQoNCmBgYA0KDQojIyBVbmRlcnN0YW5kIA0KDQoqIE9uY2UgdGhlIGRhdGFzZXRzIHdlcmUgbWVyZ2VkLCB0aGUgZGltZW5zaW9ucyB3YXMgY2hlY2tlZCB1c2luZyBkaW0oKSBmdW5jdGlvbnMuDQoqIFRoZSBuZXcgZGF0YXNldCAnam9pbicgaGFkIDExMjY1MCBvYnNlcnZhdGlvbnMgYW5kIHRvdGFsIG9mIDEwIHZhcmlhYmxlcy4gU2luY2UgdGhlIG51bWJlciBvZiBvYnNlcnZhdGlvbnMgd2VyZSBsYXJnZSBhbmQgc29tZSBwYWNrYWdlcyBsaWtlIE1WTiwgd29yayB3aXRoIDUwMDAgb2JzZXJ2YXRpb25zIG9yIGxlc3MsIGEgc3Vic2V0IG9mIHRoZSBkYXRhIHdhcyBnZW5lcmF0ZWQgYXMgJ3NlbGxlcl9vcmRlcl9saXN0JyB3aGljaCBjb25zaXN0cyBvZiB0aGUgZmlyc3QgNTAwMCBlbnRyaWVzIGZyb20gdGhlIG9yaWdpbmFsIG1lcmdlZCBkYXRhc2V0LiANCiogU3RydWN0dXJlIG9mIHRoZSBzdWJzZXQgd2FzIGNoZWNrZWQgdXNpbmcgc3RyKCkgZnVuY3Rpb24uDQoqIERhdGEgdHlwZXMgb2YgYWxsIHRoZSAxMCB2YXJpYWJsZXMgd2VyZSBjaGVja2VkIHdpdGggdGhlIGhlbHAgb2YgY2xhc3MoKSBmdW5jdGlvbi4gVGhlIGRhdGFzZXQgY29uc2lzdHMgb2Ygc2V2ZXJhbCBjaGFyYWN0ZXIsIG51bWVyaWMgdmFyaWFibGVzLg0KKiBUaGUgJ3NlbGxlcl9zdGF0ZScgdmFyaWFibGUgd2FzIGNvbnZlcnRlZCB0byBhIGZhY3RvciB1c2luZyBmYWN0b3IoKSBmdW5jdGlvbiBhbmQgaXRzIGxldmVscyB3ZXJlIHNldC4NCiogVGhlICdzZWxsZXJfemlwX2NvZGVfcHJlZml4JyB2YXJpYWJsZSB3YXMgY29udmVydGVkIGZyb20gbnVtZXJpYyB0byBjaGFyYWN0ZXIgYmVjYXVzZSBaSVAgY29kZSBpcyBub3QgdHJlYXRlZCBhcyBhIG51bWJlciB0aGF0IHJlcXVpcmVzIGFueSBjb21wdXRhdGlvbnMuDQoNCg0KYGBge3J9DQoNCiNDaGVja2luZyBkaW1lbnNpb24gb2YgJ2pvaW4nDQpkaW0oam9pbikNCg0KI1N1YnNldHRpbmcgd2l0aCBmaXJzdCA1MDAwIG9ic2VydmF0aW9ucw0Kc2VsbGVyX29yZGVyX2xpc3Q8LSBqb2luWzE6NTAwMCxdDQpkaW0oc2VsbGVyX29yZGVyX2xpc3QpDQpzdHIoc2VsbGVyX29yZGVyX2xpc3QpDQoNCiNDaGVja2luZyB0aGUgZGF0YSB0eXBlcyBvZiBhbGwgMTAgdmFyaWFibGVzDQpjbGFzcyhzZWxsZXJfb3JkZXJfbGlzdCRvcmRlcl9pZCkNCmNsYXNzKHNlbGxlcl9vcmRlcl9saXN0JG9yZGVyX2l0ZW1faWQpDQpjbGFzcyhzZWxsZXJfb3JkZXJfbGlzdCRwcm9kdWN0X2lkKQ0KY2xhc3Moc2VsbGVyX29yZGVyX2xpc3Qkc2VsbGVyX2lkKQ0KY2xhc3Moc2VsbGVyX29yZGVyX2xpc3Qkc2hpcHBpbmdfbGltaXRfZGF0ZSkNCmNsYXNzKHNlbGxlcl9vcmRlcl9saXN0JHByaWNlKQ0KY2xhc3Moc2VsbGVyX29yZGVyX2xpc3QkZnJlaWdodF92YWx1ZSkNCmNsYXNzKHNlbGxlcl9vcmRlcl9saXN0JHNlbGxlcl96aXBfY29kZV9wcmVmaXgpDQpjbGFzcyhzZWxsZXJfb3JkZXJfbGlzdCRzZWxsZXJfY2l0eSkNCmNsYXNzKHNlbGxlcl9vcmRlcl9saXN0JHNlbGxlcl9zdGF0ZSkNCg0KI1R5cGUgY29udmVyc2lvbnMNCiNDb252ZXJ0aW5nICdzZWxsZXJfc3RhdGUnIHRvIGEgZmN0b3IgdmFyaWFibGUNCnNlbGxlcl9vcmRlcl9saXN0JHNlbGxlcl9zdGF0ZTwtIGZhY3RvcihzZWxsZXJfb3JkZXJfbGlzdCRzZWxsZXJfc3RhdGUsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIkFDIiwiQU0iLCJCQSIsIkNFIiwiREYiLCJFUyIsIkdPIiwiTUEiLCJNRyIsIk1TIiwiTVQiLCJQQSIsIlBCIiwiUEUiLCJQSSIsIlBSIiwiUkoiLCJSTiIsIlJPIiwiUlMiLCJTQyIsIlNFIiwiU1AiKSkNCmxldmVscyhzZWxsZXJfb3JkZXJfbGlzdCRzZWxsZXJfc3RhdGUpDQpjbGFzcyhzZWxsZXJfb3JkZXJfbGlzdCRzZWxsZXJfc3RhdGUpDQoNCiNDb252ZXJ0aW5nICdzZWxsZXJfemlwX2NvZGVfcHJlZml4JyB0byBhIGNoYXJhY3RlciB2YXJpYWJsZQ0Kc2VsbGVyX29yZGVyX2xpc3Qkc2VsbGVyX3ppcF9jb2RlX3ByZWZpeDwtIGFzLmNoYXJhY3RlcihzZWxsZXJfb3JkZXJfbGlzdCRzZWxsZXJfemlwX2NvZGVfcHJlZml4KQ0KY2xhc3Moc2VsbGVyX29yZGVyX2xpc3Qkc2VsbGVyX3ppcF9jb2RlX3ByZWZpeCkNCg0KYGBgDQoNCg0KIyMJVGlkeSAmIE1hbmlwdWxhdGUgRGF0YSBJIA0KDQoqIFRoZSBvbGlzdF9vcmRlcl9pdGVtc19kYXRhc2V0IHdhcyBtZXNzeSBiZWNhdXNlIHRoZSB2YXJpYWJsZSAnc2hpcHBpbmdfbGltaXRfZGF0ZScgc3RvcmVzIHRoZSBkYXRlIGFuZCB0aW1lIG9mIHNoaXBwaW5nLiBJbiB0aGlzIGNhc2UsIG11dGxpcGxlIHZhcmlhYmxlcyBhcmUgc3RvcmVkIGluIG9uZSBjb2x1bW4gYW5kIG1ha2VzIHRoZSBkYXRhc2V0IHVudGlkeS4NCiogVGhlICdzaGlwcGluZ19saW1pdF9kYXRlJyB2YXJpYWJsZSBpcyB0aGVuIHNwbGl0IGludG8gdHdvIGNvbHVtbnMsICdTaGlwcGluZyBEYXRlJyBhbmQgJ1NoaXBwaW5nIFRpbWUnIHVzaW5nIHNlcGFyYXRlKCkgZnVuY3Rpb24gZnJvbSB0aWR5ciBwYWNrYWdlLCBieSBzcGFjZSBhcyBhIHNlcGFyYXRvci4gDQoqIE9uY2Ugc2VwYXJhdGUsIHRoZSAnU2hpcHBpbmcgRGF0ZScgdmFyaWFibGUgd2FzIHRoZW4gY29ycmVjdGx5IGNvbnZlcnRlZCBhcyBhIGRhdGUgdXNpbmcgQmFzZSBSIGFzLkRhdGUoKSBmdW5jdGlvbiBhbmQgd2FzIGZvcm1hdHRlZCBhcyB0aGUgb3JpZ2luYWwgREQtTU0tWVlZIGZvcm1hdCB1c2luZyBmb3JtYXQoKSBmdW5jdGlvbi4NCg0KDQpgYGB7cn0NCg0KI1NlcGFyYXRpbmcgdGhlICdzaGlwcGluZ19saW1pdF9kYXRlJyBpbnRvIHR3byBjb2x1bW5zDQpzZWxsZXJfb3JkZXJfbGlzdDwtc2VwYXJhdGUoc2VsbGVyX29yZGVyX2xpc3Qsc2hpcHBpbmdfbGltaXRfZGF0ZSwgaW50byA9IGMoIlNoaXBwaW5nIERhdGUiLCAiU2hpcHBpbmcgVGltZSIpLCBzZXAgPSAiICIpDQpzZWxsZXJfb3JkZXJfbGlzdCAlPiUgaGVhZCgxMCkNCg0KI0NvbnZlcnRpbmcgJ1NoaXBwaW5nIERhdGUnIHRvIGRhdGUgZm9ybWF0DQpzZWxsZXJfb3JkZXJfbGlzdCRgU2hpcHBpbmcgRGF0ZWA8LSBmb3JtYXQoYXMuRGF0ZShzZWxsZXJfb3JkZXJfbGlzdCRgU2hpcHBpbmcgRGF0ZWAsIGZvcm1hdCA9ICIlZC0lbS0lWSIpLCAiJWQtJW0tJVkiKQ0Kc2VsbGVyX29yZGVyX2xpc3QkYFNoaXBwaW5nIERhdGVgICU+JSBoZWFkKDEwKQ0KDQpgYGANCg0KIyMJVGlkeSAmIE1hbmlwdWxhdGUgRGF0YSBJSSANCg0KKiBUaGUgb2xpc3Rfb3JkZXJfaXRlbXNfZGF0YXNldCBjb25zaXN0cyBkZXRhaWxzIGFib3V0IGVhY2ggb3JkZXIgd2l0aCBhbiBvcmRlciBJRC4gSXQgd2FzIG9ic2VydmVkIHRoYXQgc29tZSBvcmRlcnMgaGFkIG11bHRpcGxlIGl0ZW1zLCB3aGVyZSB0aGUgcHJpY2UgYW5kIGZyZWlnaHQgdmFsdWUgd2FzIHNwbGl0IGJldHdlZW4gdGhlIGl0ZW1zLiANCiogJ29yZGVyX2l0ZW1faWQnIGlzIGEgc2VxdWVudGlhbCBudW1iZXIgaWRlbnRpZnlpbmcgbnVtYmVyIG9mIGl0ZW1zIGluY2x1ZGVkIGluIHRoZSBzYW1lIG9yZGVyLg0KKiBBIG5ldyB2YXJpYWJsZSAndG90YWxfb3JkZXJfdmFsdWUnIHdhcyBjcmVhdGVkIHRoYXQgY29tcHV0ZXMgdGhlIHRvdGFsIHByaWNlIG9mIHRoZSBvcmRlciwgaS5lLiBUb3RhbCBvcmRlciB2YWx1ZSA9IHByaWNlICsgZnJlaWdodCB2YWx1ZS4NCiogbXV0YXRlKCkgZnVuY3Rpb24gd2FzIHVzZWQgdG8gYWRkIHRoZSAndG90YWxfb3JkZXJfdmFsdWUnIGNvbHVtbiB0byB0aGUgZGF0YSBhZnRlciBncm91cGluZyBieSB0aGUgb3JkZXJfaWQgYW5kIGFkZGluZyB0aGUgcHJpY2UgYW5kIGZyZWlnaHQgdmFsdWUuDQoqIFRoZSBwcmljZSBhbmQgZnJlaWdodCB2YWx1ZSBmb3IgZWFjaCBvcmRlciB3YXMgY2FsY3VsYXRlZCBieSBtdWx0aXBseWluZyB0aGUgcHJpY2UgYW5kIGZyZWlnaHQgdmFsdWUgd2l0aCB0aGUgbnVtYmVyIG9mIGl0ZW1zIGluIGVhY2ggb3JkZXIgdXNpbmcgbGVuZ3RoKG9yZGVyX2lkKS4NCiogRm9yIGV4YW1wbGU6IFRoZSBvcmRlciB3aXRoIG9yZGVyX2lkID0gMDAxNDNkMGY4NmQ2ZmJkOWY5YjM4YWI0NDBhYzE2ZjUgaGFzIDMgaXRlbXMuIFRvIGdldCB0aGUgdG90YWwgb3JkZXIgdmFsdWUgZm9yIGVhY2ggb3JkZXIganVzdCBzdW0gbmVlZHMgdG8gYmUgY2FsY3VsYXRlZCBhczogDQogICAgLSBUaGUgdG90YWwgb3JkZXIgcHJpY2UgdmFsdWUgaXM6IDIxLjMzICogMyA9IDYzLjk5IA0KICAgIC0gVGhlIHRvdGFsIGZyZWlnaHQgdmFsdWUgaXM6IDE1LjEwICogMyA9IDQ1LjMwDQogICAgLSBUaGVyZWZvcmUsIHRoZSB0b3RhbCBvcmRlciB2YWx1ZSAocHJpY2UgKyBmcmVpZ2h0KSBpczogNDUuMzAgKyA2My45OSA9IDEwOS4yOQ0KDQoNCmBgYHtyfQ0KDQojTXV0YXRpbmcgdG90YWwgcHJpY2UgY29sdW1uDQpzZWxsZXJfb3JkZXJfbGlzdDwtIHNlbGxlcl9vcmRlcl9saXN0ICU+JSBncm91cF9ieShvcmRlcl9pZCkgJT4lDQogIG11dGF0ZSh0b3RhbF9vcmRlcl92YWx1ZT0gKHByaWNlICogbGVuZ3RoKG9yZGVyX2lkKSsoZnJlaWdodF92YWx1ZSAqIGxlbmd0aChvcmRlcl9pZCkpKSkNCg0Kc2VsbGVyX29yZGVyX2xpc3QkdG90YWxfb3JkZXJfdmFsdWUgJT4lIGhlYWQoMTApDQoNCmBgYA0KDQoNCiMjCVNjYW4gSSANCg0KKiBUaGUgZGF0YSB3YXMgc2Nhbm5lZCBmb3IgbWlzc2luZyB2YWx1ZXMgdXNpbmcgaXMubmEoKSBmdW5jdGlvbiBhbmQgdGhlIHRvdGFsIG51bWJlciBvZiBtaXNzaW5nIHZhbHVlcyBpbiBlYWNoIGNvbHVtbiB3YXMgY2hlY2tlZCB1c2luZyBjb2xTdW1zKCkgZnVuY3Rpb24uIEl0IHdhcyBvYnNlcnZlZCB0aGF0IHRoZXJlIGFyZSBubyBtaXNzaW5nIHZhbHVlcyBpbiB0aGUgdXNlZCBkYXRhc2V0IHNpbmNlIHRoZSB0b3RhbCBtaXNzaW5nIHZhbHVlcyBmb3IgZWFjaCBjb2x1bW4gY29tZXMgb3V0IHRvIGJlIDAuDQoqIEV2ZXJ5IG51bWVyaWNhbCBjb2x1bW4gaW4gdGhlIGRhdGFzZXQsIHdhcyB0aGVuIHNjYW5uZWQgZm9yIHNwZWNpYWwgdmFsdWVzIHN1Y2ggYXMgLUluZiwgSW5mIGFuZCBOYU4uIA0KICAgIC0gRmlyc3RseSwgYSBzdWJzZXQgb2YgdGhlIG51bWVyaWMgY29sdW1ucyBpLmUuIHByaWNlLCBmcmVpZ2h0X3ZhbHVlIGFuZCB0b3RhbF9vcmRlcl92YWx1ZSB3YXMgY3JlYXRlZCB1c2luZyBzZWxlY3QoKSBmdW5jdGlvbiBhbmQgdGhlbiBzZWxlY3RpbmcganVzdCB0aGUgbnVtZXJpYyBjb2x1bW5zLiBUaGlzIHZhcmlhYmxlIHdhcyBuYW1lZCAnc2VsbGVyX29yZGVyX3N1YicuDQogICAgLSBUbyBjaGVjayBmb3Igc3BlY2lhbCB2YWx1ZXMsIGEgZnVuY3Rpb24gY2FsbGVkIHNwZWNpYWxfdmFsdWVzKCkgd2FzIGNyZWF0ZWQuDQogICAgLSBVc2luZyBzYXBwbHkoKSwgdGhlIHNwZWNpYWxfdmFsdWVzKCkgZnVuY3Rpb24gd2FzIGFwcGxpZWQgdG8gJ3NlbGxlcl9vcmRlcl9zdWInLiBUaGUgcmVzdWx0IHdhcyBxdWl0ZSBub24taW5mb3JtYXRpdmUgc2luY2UgaXQgd2FzIGxvbmcsIHRoZXJlZm9yZSBzdW0oKSB3YXMgYWRkZWQgdG9nZXRoZXIgd2l0aCBzcGVjaWFsX3ZhbHVlcyBmdW5jdGlvbiB0byBjYWxjdWxhdGUgdGhlIHRvdGFsIHNwZWNpYWwgdmFsdWVzIGZvciBlYWNoIGNvbHVtbi4NCiAgICAtIFRoZXJlIHdlcmUgbm8gc3BlY2lhbCB2YWx1ZXMgb2JzZXJ2ZWQgaW4gdGhlIG51bWVyaWNhbCBjb2x1bW5zLg0KKiBUaGUgZGF0YXNldCByZXByZXNlbnRzIHByaWNlIG9mIHZhcmlvdXMgb3JkZXJzIGFsb25nIHdpdGggdGhlIGZyZWlnaHQgdmFsdWUuIEluIHJlYWwgd29ybGQgc2l0dWF0aW9uLCB0aGVzZSB2YWx1ZXMgY2Fubm90IGJlIG5lZ2F0aXZlLiBUaGVyZWZvcmUsIGVhY2ggbnVtZXJpYyBwcmljZSB2YXJpYWJsZXMgd2VyZSBjaGVja2VkIGZvciBvYnZpb3VzIGluY29uc2lzdGVuY3kgb3IgZXJyb3IuIA0KICAgIC0gQSBuZXcgZnVuY3Rpb24gY2FsbGVkIG5vbm5lZ2F0aXZlKCkgd2FzIGNyZWF0ZWQgdGhhdCBjaGVja3MgaWYgdGhlIHZhbHVlIGFyZSBsZXNzIHRoYW4gemVyby4gSXQgd2FzIHRoZW4gYXBwbGllZCB0byB0aGUgbnVtZXJpYyB2YWx1ZXMgc3Vic2V0IHVzaW5nIHNhcHBseSgpLiANCiAgICAtIFRvIGNoZWNrIHRoZSB0b3RhbCBudW1iZXIgb2YgaW5jb25zaXN0ZW50IHZhbHVlcyBpbiBlYWNoIGNvbHVtbiwgY29sU3VtcygpIHdhcyB1c2VkIGFuZCBpdCByZXN1bHRlZCBpbiAwIGluY29uc2lzdGVudCB2YWx1ZXMgZm9yIGVhY2ggY29sdW1uLg0KDQoNCmBgYHtyfQ0KDQojU2Nhbm5pbmcgZm9yIG1pc3NpbmcgdmFsdWVzDQpjb2xTdW1zKGlzLm5hKHNlbGxlcl9vcmRlcl9saXN0KSkNCg0KI1NjYW5uaW5nIGZvciBzcGVjaWFsIHZhbHVlcw0Kc3ViPC0gc2VsbGVyX29yZGVyX2xpc3QgJT4lIHNlbGVjdChwcmljZSwgZnJlaWdodF92YWx1ZSwgdG90YWxfb3JkZXJfdmFsdWUpDQpzZWxsZXJfb3JkZXJfc3ViPC0gc3ViWywyOjRdDQoNCnNwZWNpYWxfdmFsdWVzIDwtIGZ1bmN0aW9uKHgpew0KICBpZiAoaXMubnVtZXJpYyh4KSkgKGlzLmluZmluaXRlKHgpIHwgaXMubmFuKHgpKQ0KfQ0KDQpzcF92YWx1ZXM8LXNhcHBseShzZWxsZXJfb3JkZXJfc3ViLCBGVU4gPSBzcGVjaWFsX3ZhbHVlcykNCnNhcHBseShzZWxsZXJfb3JkZXJfc3ViLCBmdW5jdGlvbih4KXtpZiAoaXMubnVtZXJpYyh4KSkgc3VtKHNwZWNpYWxfdmFsdWVzKHgpKX0pDQoNCiMjU2Nhbm5pbmcgZm9yIGluY29uc2lzdGVuY2llcyBvciBvYnZpb3VzIGVycm9ycyANCm5vbm5lZ2F0aXZlPC0gZnVuY3Rpb24oeCl7eDwwfQ0Kbm9ubmVnYXRpdmVfcHJpY2U8LXNhcHBseShzZWxsZXJfb3JkZXJfc3ViLCBGVU4gPSBub25uZWdhdGl2ZSkNCmNvbFN1bXMobm9ubmVnYXRpdmVfcHJpY2UpDQoNCmBgYA0KDQoNCiMjCVNjYW4gSUkNCg0KKiBUaGUgZGF0YXNldCB3YXMgbm93IHNjYW5uZWQgZm9yIHBvc3NpYmxlIG91dGxpZXJzLiBUaGUgZGF0YSBjb250YWluZWQgdGhyZWUgbnVtZXJpYyB2YXJpYWJsZXMgYW5kIHdpdGggdGhlIGhlbHAgb2YgdGhlIE1haGFsYW5vYmlzIGRpc3RhbmNlIG1ldGhvZCB0aGUgb3V0bGllcnMgd2VyZSBkZXRlY3RlZCBmb3IgbXVsdGl2YXJpYXRlIHNldHRpbmcuIA0KKiBVc2luZyB0aGUgbXZuKCkgZnVuY3Rpb24gb24gJ3NlbGxlcl9vcmRlcl9zdWInIGZyb20gdGhlIE1WTiBwYWNrYWdlLCBtdWx0aXZhcmlhdGUgb3V0bGllcnMgd2VyZSBkZXRlY3RlZCB3aXRoIFFRIHBsb3QuIFRoZSBzaG93T3V0bGllcnMgPSBUUlVFIGFyZ3VtZW50IGRlcGljdHMgdGhlIG11bHRpdmFyaWF0ZSBvdXRsaWVycyBhbmQgc2hvdyB0aGVtIG9uIFFRIHBsb3QuDQoqIFRoZSBRUSBwbG90IHN1Z2dlc3RzIGV4aXN0ZW5jZSBvZiA2OCBvdXRsaWVycyBmb3IgdGhpcyBzdWJzZXQuIA0KKiBUaGUgbG9jYXRpb24gb2Ygb3V0bGllcnMgaW4gdGhlIGRhdGFzZXQgd2VyZSBkZXRlY3RlZCB1c2luZyBzZWxsZXJfb3JkZXJfb3V0bGllcnMkbXVsdGl2YXJpYXRlT3V0bGllcnMuDQoqIE9uY2UgdGhlIHByZXNlbmNlIG9mIG91dGxpZXJzIGluIHRoZSBzdWJzZXQgb2YgZGF0YXNldCB3YXMgZGV0ZWN0ZWQsIHRoZSBuZXh0IHN0ZXAgd2FzIHRvIGhhbmRsZSB0aGVtLg0KKiBDYXBwaW5nIG9yIHdpbnNvcmlzaW5nIHdhcyBwZXJmb3JtZWQgaW4gb3JkZXIgdG8gZGVhbCB3aXRoIHRoZSBvdXRsaWVycywgaW5zdGVhZCBvZiByZW1vdmluZyB0aGVtLiBUaGlzIGlzIGJlY2F1c2UgdGhlIG91dGxpZXJzIGluIHRoaXMgY2FzZSBtYXkgbm90IG5lY2Vzc2FyaWx5IG1lYW4gdGhhdCB0aGUgdmFsdWVzIHJlcG9ydGVkIGFyZSBkdWUgdG8gc29tZSBlcnJvcnMuIFNvbWV0aW1lcyBvdXRsaWVycyBjYW4gYmUgbGVnaXRpbWF0ZSBvYnNlcnZhdGlvbnMuIEEgaGlnaCB0b3RhbCBvcmRlciB2YWx1ZSBjYW4gZWl0aGVyIG1lYW4gdGhlIG51bWJlciBvZiBpdGVtcyBpbiB0aGUgb3JkZXIgYXJlIGxhcmdlIG9yIHRoZSBpdGVtIHByaWNlIGFsb25nIHdpdGggZnJlaWdodCB2YWx1ZSBhcmUgaGlnaC4gDQoqIGNhcCgpIGZ1bmN0aW9uIHdhcyBjcmVhdGVkIHRvIHJlcGxhY2UgdGhvc2UgZGF0YSBwb2ludHMgbHlpbmcgb3V0c2lkZSB0aGUgbG93ZXIgbGltaXQgYW5kIGFib3ZlIHRoZSB1cHBlciBsaW1pdCB3aXRoIHRoZSB2YWx1ZSBvZiA1dGggcGVyY2VudGlsZSBhbmQgOTV0aCBwZXJjZW50aWxlLg0KKiBCZWZvcmUgY2FwcGluZywgZGVzY3JpcHRpdmUgc3RhdGlzdGljcyBvZiB0aGUgc3Vic2V0IHdhcyBwcm9kdWNlZCB1c2luZyBzdW1tYXJ5KCkuDQoqIEVhY2ggbnVtZXJpYyB2YXJpYWJsZSB3YXMgdGhlbiBjYXBwZWQgdXNpbmcgY2FwKCkgZnVuY3Rpb24gYW5kIHRoZSByZXN1bHRzIHdlcmUgc3RvcmVkIGluIHRoZSB2YXJpYWJsZXMgJ3ByaWNlX2NhcHBlZCcsICdmcmVpZ2h0X3ZhbHVlX2NhcHBlZCcgYW5kICd0b3RhbF9wcmljZV9jYXBwZWQnLg0KKiBTdW1tYXJ5IHN0YXRpc3RpY3Mgb2YgdGhlIGNhcHBlZCBzdWJzZXQgd2FzIGNvbXB1dGVkIHVzaW5nIHN1bW1hcnkoKS4NCg0KDQpgYGB7cn0NCg0KIyBNYWhhbmFib2xpcyBPdXRsaWVyIGRldGVjdGlvbiBtZXRob2QNCnNlbGxlcl9vcmRlcl9vdXRsaWVycyA8LSBtdm4oZGF0YSA9IHNlbGxlcl9vcmRlcl9zdWIsIG11bHRpdmFyaWF0ZU91dGxpZXJNZXRob2QgPSAicXVhbiIsIHNob3dPdXRsaWVycyA9IFRSVUUpDQoNCiNDaGVja2luZyBsb2NhdGlvbnMgb2YgdGhlIG91dGxpZXJzDQpzZWxsZXJfb3JkZXJfb3V0bGllcnMkbXVsdGl2YXJpYXRlT3V0bGllcnMNCg0KI0NhcHBpbmcNCmNhcCA8LSBmdW5jdGlvbih4KXsNCiAgcXVhbnRpbGVzIDwtIHF1YW50aWxlKCB4LCBjKC4wNSwgMC4yNSwgMC43NSwgLjk1ICkgKQ0KICB4WyB4IDwgcXVhbnRpbGVzWzJdIC0gMS41KklRUih4KSBdIDwtIHF1YW50aWxlc1sxXQ0KICB4WyB4ID4gcXVhbnRpbGVzWzNdICsgMS41KklRUih4KSBdIDwtIHF1YW50aWxlc1s0XQ0KICB4DQp9DQoNCiNEZXNjcmlwdGl2ZSBzdGF0aXN0aWNzIG9mIHRoZSBzdWJzZXQNCnN1bW1hcnkoc2VsbGVyX29yZGVyX3N1YikNCg0KI0FwcGx5aW5nIGNhcCgpIHRvIHRoZSBudW1lcmljIHZhcmlhYmxlcw0KcHJpY2VfY2FwcGVkPC0gc2VsbGVyX29yZGVyX2xpc3QkcHJpY2UgJT4lIGNhcCgpDQpmcmVpZ2h0X3ZhbHVlX2NhcHBlZDwtIHNlbGxlcl9vcmRlcl9saXN0JGZyZWlnaHRfdmFsdWUgJT4lIGNhcCgpDQp0b3RhbF9wcmljZV9jYXBwZWQ8LSBzZWxsZXJfb3JkZXJfbGlzdCR0b3RhbF9vcmRlcl92YWx1ZSAlPiUgY2FwKCkNCg0KI0NoZWNraW5nIHRoZSBzdW1tYXJ5IHN0YXRpc3RpY3MgYWdhaW4NCnNlbGxlcl9vcmRlcl9jYXBwZWQ8LSBzYXBwbHkoc2VsbGVyX29yZGVyX3N1YiwgRlVOID0gY2FwKQ0Kc3VtbWFyeShzZWxsZXJfb3JkZXJfY2FwcGVkKQ0KDQpgYGANCg0KDQojIwlUcmFuc2Zvcm0gDQoNCiogVGhlICd0b3RhbF9wcmljZV9jYXBwZWQnLCAncHJpY2VfY2FwcGVkJyByZXByZXNlbnRzIHRoZSB0b3RhbF9vcmRlcl92YWx1ZSBhbmQgcHJpY2UgYWZ0ZXIgY2FwcGluZyB0aGUgb3V0bGllcnMuIE9uIHByb2R1Y2luZyBhIGhpc3RvZ3JhbSBmb3IgYm90aCB0aGUgdmFyaWFibGVzLCBpdCB3YXMgb2JzZXJ2ZWQgdGhhdCB0aGV5IGhhZCByaWdodC1za2V3ZWQgZGlzdHJpYnV0aW9ucy4NCiogU2V2ZXJhbCBtZXRob2RzLCBmb3IgaW5zdGFuY2UsIGxvZzEwIHRyYW5zZm9ybWF0aW9uLCBzcXVhcmUgcm9vdCB0cmFuc2Zvcm1hdGlvbiwgcmVjaXByb2NhbCB0cmFuc2Zvcm1hdGlvbiBhbmQgQm94Q294IHRyYW5zZm9ybWF0aW9uIHdhcyBhcHBsaWVkIHRvIHJlZHVjZSB0aGUgc2tld25lc3MgYnV0IHRoZSBiZXN0IHJlc3VsdHMgd2VyZSBvYnRhaW5lZCB1c2luZyBuYXR1cmFsIGxvZ2FyaXRobSB0cmFuc2Zvcm1hdGlvbi4NCiogU2luY2UgdGhlIHZhcmlhYmxlcyBoYWQgbm8gemVybyBvciBuZWdhdGl2ZSB2YWx1ZXMsIGxvZygpIGZ1bmN0aW9uIHdhcyB1c2VkIHRvIHRyYW5mb3JtIHRoZSAndG90YWxfcHJpY2VfY2FwcGVkJyBhbmQgJ3ByaWNlX2NhcHBlZCcgdmFyaWFibGUgdG8gcHJvZHVjZSBhIG1vcmUgc3ltbWV0cmljYWwgZGlzdHJpYnV0aW9uLg0KKiBUaGUgJ2ZyZWlnaHRfdmFsdWVfY2FwcGVkJyB2YXJpYWJsZSBpcyBvYnNlcnZlZCB0byBiZSBtaWxkbHkgcmlnaHQgc2tld2VkIGFmdGVyIGNoZWNraW5nIGl0cyBoaXN0b2dyYW0uDQoqIFRvIHJlZHVjZSB0aGUgc2tld2VuZXNzLCBzZXZlcmFsIHRyYW5zZm9ybWF0aW9uIHRlY2huaXF1ZXMgd2VyZSBhcHBsaWVkIGFuZCB0aGUgYmVzdCByZXN1bHRzIHdlcmUgb2J0YWluZWQgYnkgdXNpbmcgc3F1YXJlIHJvb3QgdHJhbnNmb3JtYXRpb24sIHVzaW5nIHNxcnQoKSBmdW5jdGlvbi4NCiogSGlzdG9ncmFtcyBvZiBhbGwgdGhyZWUgdmFyaWFibGVzIHdlcmUgcGxvdCB0byBjaGVjayB0aGUgdHJhbnNmb3JtYXRpb24gcmVzdWx0cyB1c2luZyBoaXN0KCkgZnVuY3Rpb24uDQoNCg0KYGBge3J9DQoNCiMgQ2hlY2tpbmcgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0b3RhbF9wcmljZV9jYXBwZWQNCmhpc3QodG90YWxfcHJpY2VfY2FwcGVkLCBtYWluID0gIkhpc3RvZ3JhbSBmb3IgdG90YWxfb3JkZXJfdmFsdWUiLCB4bGFiID0gInRvdGFsX29yZGVyX3ZhbHVlIikNCg0KI0FwcGx5aW5nIG5hdHVyYWwgbG9nIHRyYW5zZm9ybWF0aW9uDQpsbl90b3RhbDwtIGxvZyh0b3RhbF9wcmljZV9jYXBwZWQpDQpoaXN0KGxuX3RvdGFsLG1haW4gPSAiTG9nIFRyYW5zZm9ybWF0aW9uIG9mIFRvdGFsIFByaWNlIiwgeGxhYiA9ICJUb3RhbCBQcmljZSIpDQoNCiMgQ2hlY2tpbmcgdGhlIGRpc3RyaWJ1dGlvbiBvZiBwcmljZV9jYXBwZWQNCmhpc3QocHJpY2VfY2FwcGVkLCBtYWluID0gIkhpc3RvZ3JhbSBmb3IgcHJpY2UiLCB4bGFiID0gIlByaWNlIG9mIHRoZSBvcmRlciBpdGVtIikNCg0KI0FwcGx5aW5nIG5hdHVyYWwgbG9nIHRyYW5zZm9ybWF0aW9uDQpsbl9wcmljZTwtIGxvZyhwcmljZV9jYXBwZWQpDQpoaXN0KGxuX3ByaWNlLG1haW4gPSAiTG9nIFRyYW5zZm9ybWF0aW9uIG9mIFByaWNlIiwgeGxhYiA9ICJQcmljZSBvZiB0aGUgb3JkZXIgaXRlbSIpDQoNCiMgQ2hlY2tpbmcgdGhlIGRpc3RyaWJ1dGlvbiBvZiBmcmVpZ2h0X3ZhbHVlX2NhcHBlZA0KaGlzdChmcmVpZ2h0X3ZhbHVlX2NhcHBlZCwgbWFpbiA9ICJIaXN0b2dyYW0gZm9yIGZyZWlnaHRfdmFsdWUiLCB4bGFiID0gIkZyZWlnaHQgdmFsdWUiKQ0KDQojQXBwbHlpbmcgc3F1YXJlIHJvb3QgdHJhbnNmb3JtYXRpb24NCnNxcnRfdG90YWw8LSBzcXJ0KGZyZWlnaHRfdmFsdWVfY2FwcGVkKQ0KaGlzdChzcXJ0X3RvdGFsLCBtYWluID0gIlNxdWFyZSBSb290IFRyYW5zZm9ybWF0aW9uIG9mICBmcmVpZ2h0X3ZhbHVlIiwgeGxhYiA9ICJGcmVpZ2h0IHZhbHVlIikNCg0KYGBgDQoNCjxicj4NCjxicj4NCg==