Required packages

library(dplyr)
library(tidyr)

Executive Summary

The data pre-processing is carried out on datasets from the retail domain. There are three datasets which are joined using left join. The final joined data is composed of variables with numeric, character and logical data types.

Conversion of data type for a few variables had to be carried out. Four variables were converted to factory type and one variable which represented date, was in character data type and was converted into Date format. A numeric variable is also categorized into a new variable with three levels which is an ordered factor. The data was checked for tidiness. There were five variables which were present as column names which were worthy of being combined into a single variable using gather function. A new binary variable was created as an indicator of missing values.

The variables were checked for missing values and outlier, where boxplots were used for outlier checking. Only two variables had missing values, one which was of type factor and the other numeric. The missing values for the numeric variable were replaced by the median value of the variable. The numeric variables which had outliers were modified by capping the outlier values to the upper or lower value from the boxplot which is not an outlier itself.

Finally, a variable which had left skew was transformed using square transformation in order to make it approximately normal.

Data

The data used for this assignment is a Retail Analytics Dataset that is sourced form Kaggle.

The datasets are available at the following link: https://www.kaggle.com/manjeetsingh/retaildataset/data

The data description is available at the following link: https://www.kaggle.com/manjeetsingh/retaildataset

The datasets are released under CC0: Public Domain.

There are three datasets Stores, Features and Sales. All three datasets are available in .csv format. The description of the data are as follows:

Stores : This dataset contains 45 stores of a company, with the type and size of the store. The stores data is anonymized. There are 45 observations and the variables of this data set are as follows (as present in original form):

Variable Type Levels Description
Store Numeric - Store Number
Type Character A,B,C Type of Store
Size Numeric - Size of the Store

Sales: This is the Sales data for each store by department from 5/2/2010 to 1/11/2012. There are 421570 observations and the variables in this data set are:

Variable Type Levels Description
Store Numeric - Store Number
Dept Numeric - Department Number
Date Character - Representing Week
Weekly_Sales Numeric - Weekly Sales for given store and dept
IsHoliday Logical - If the week has special Holiday

Features: Data related to the store and other activity for the dates. There are 8190 rows and the variables are as follows:

Variable Type Levels Description
Store Numeric - Store Number
Date Character - Representing Week
Temperature Numeric - Avg Temperature in Region of Store
Fuel Price Numeric - Fuel price in Region of Store
Markdown1-5 Numeric - Promotional Markdowns Type and Amnts
CPI Numeric - Consumer Price Index
Unemployment Numeric - Unemployment Rate
IsHoliday Logical - If the week has special Holiday

We first read in the individual datasets.

# Step 1: Reading in Store
stores = read.csv(file = "E:/RMIT/Course Content/MATH 2349 - Data Preprocessing/Assessments/Assessment 3/Assignment/stores data-set.csv",stringsAsFactors = FALSE)
# Step 2: Check if Store data set has been read in properly
head(stores)
dim(stores)
[1] 45  3
# Step 3: Reading in Sales
sales = read.csv(file = "E:/RMIT/Course Content/MATH 2349 - Data Preprocessing/Assessments/Assessment 3/Assignment/sales data-set.csv",stringsAsFactors = FALSE)
# Step 4: Check head and dim of Sales Data
head(sales)
dim(sales)
[1] 421570      5
# Step 5: Reading in Feature data set
features = read.csv(file = "E:/RMIT/Course Content/MATH 2349 - Data Preprocessing/Assessments/Assessment 3/Assignment/Features data set.csv",stringsAsFactors = FALSE)
# Step 6: Checking head and dim of Features Data 
head(features)
dim(features)
[1] 8190   12
# Step 7: Left Join Stores and Sales Dataset by Store
storeData = stores %>% left_join(y = sales,by = "Store")
# Step 8:  Checking Head and Dim of storeData
head(storeData)
dim(storeData)
[1] 421570      7
# Step 9: Left Join storeData with features by Store and Date 
storeData = storeData %>% left_join(y = features,by = c("Store","Date"))
# Step 10: Checking Head and Dim of storeData
head(storeData)
dim(storeData)
[1] 421570     17

Step 1: Read in Stores Data : In this step we first read in the store data using read.csv function and save as stores.
Step 2: Check Head and Dimension of Store Data : Check the head of the imported stores data to see if the import is proper and check the dimension of the read in data.The stores data has been read in properly and has 45 observations and 3 variables as expected.
Step 3: Read in Sales Data : The Sales data set is read into R using the read.csv function and saved as sales.
Step 4: Check Head and Dimension of Sales Data : The sales data is read into R properly and has 421570 observations and 5 variables as expected.
Step 5: Read in Features Data : The Features data set is read into R using the read.csv function and saved as features.
Step 6: Check Head and Dimension of Features Data : Check the head and dimensions of the Features data set. The features data set is read into R and it has 8190 observations and 12 variables.
Step 7: Left Join Stores and Sales Dataset : We left join the Sales dataset with the Stores dataset on the variable Store and save the dataset as storeData.
Step 8: Check Head and Dimension of storeData Dataset: The head function and dim function are used to check the head and dimensions of the joined dataset. It has 421570 observations and 7 variables as required.
Step 9: Left Join StoreData and Features Dataset : The features dataset is left joined with storeData created above on the variables Store and Date and stored again as storeData.
Step 10: Check Head and Dimension of storeData Dataset : The head and dimension of the storeData after joining the three tables is checked. There are 421570 observations and 17 rows as expected.

Understand

# Step 1: Check class of storeData
class(storeData)
[1] "data.frame"
# Step 2: Check Data Types of storeData
str(storeData)
'data.frame':   421570 obs. of  17 variables:
 $ Store       : int  1 1 1 1 1 1 1 1 1 1 ...
 $ Type        : chr  "A" "A" "A" "A" ...
 $ Size        : int  151315 151315 151315 151315 151315 151315 151315 151315 151315 151315 ...
 $ Dept        : int  1 1 1 1 1 1 1 1 1 1 ...
 $ Date        : chr  "05/02/2010" "12/02/2010" "19/02/2010" "26/02/2010" ...
 $ Weekly_Sales: num  24925 46039 41596 19404 21828 ...
 $ IsHoliday.x : logi  FALSE TRUE FALSE FALSE FALSE FALSE ...
 $ Temperature : num  42.3 38.5 39.9 46.6 46.5 ...
 $ Fuel_Price  : num  2.57 2.55 2.51 2.56 2.62 ...
 $ MarkDown1   : num  NA NA NA NA NA NA NA NA NA NA ...
 $ MarkDown2   : num  NA NA NA NA NA NA NA NA NA NA ...
 $ MarkDown3   : num  NA NA NA NA NA NA NA NA NA NA ...
 $ MarkDown4   : num  NA NA NA NA NA NA NA NA NA NA ...
 $ MarkDown5   : num  NA NA NA NA NA NA NA NA NA NA ...
 $ CPI         : num  211 211 211 211 211 ...
 $ Unemployment: num  8.11 8.11 8.11 8.11 8.11 ...
 $ IsHoliday.y : logi  FALSE TRUE FALSE FALSE FALSE FALSE ...
# Step 3: Check Both IsHoliday Variable for Similarity
summary(storeData$IsHoliday.x == storeData$IsHoliday.y)
   Mode    TRUE 
logical  421570 
# Step 4: Dropping IsHoliday.y Variable 
storeData = storeData %>% select(... = -IsHoliday.y )
# Step 5: Renaming IsHoliday.x to IsHoliday
storeData = storeData %>% rename(IsHoliday = IsHoliday.x)
head(storeData)
# Step 6: Changing Data Type of Store, Type, Dept & IsHoliday Variable to Factor
storeData[,c(1,2,4,7)] = lapply(storeData[,c(1,2,4,7)],as.factor)
# Step 7: Check Change of Data Type 
str(storeData)
'data.frame':   421570 obs. of  16 variables:
 $ Store       : Factor w/ 45 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
 $ Type        : Factor w/ 3 levels "A","B","C": 1 1 1 1 1 1 1 1 1 1 ...
 $ Size        : int  151315 151315 151315 151315 151315 151315 151315 151315 151315 151315 ...
 $ Dept        : Factor w/ 81 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
 $ Date        : chr  "05/02/2010" "12/02/2010" "19/02/2010" "26/02/2010" ...
 $ Weekly_Sales: num  24925 46039 41596 19404 21828 ...
 $ IsHoliday   : Factor w/ 2 levels "FALSE","TRUE": 1 2 1 1 1 1 1 1 1 1 ...
 $ Temperature : num  42.3 38.5 39.9 46.6 46.5 ...
 $ Fuel_Price  : num  2.57 2.55 2.51 2.56 2.62 ...
 $ MarkDown1   : num  NA NA NA NA NA NA NA NA NA NA ...
 $ MarkDown2   : num  NA NA NA NA NA NA NA NA NA NA ...
 $ MarkDown3   : num  NA NA NA NA NA NA NA NA NA NA ...
 $ MarkDown4   : num  NA NA NA NA NA NA NA NA NA NA ...
 $ MarkDown5   : num  NA NA NA NA NA NA NA NA NA NA ...
 $ CPI         : num  211 211 211 211 211 ...
 $ Unemployment: num  8.11 8.11 8.11 8.11 8.11 ...
# Step 8: Converting Date from Character to Date Format
storeData$Date = as.Date(storeData$Date,format = "%d/%m/%Y")
# Step 9: Check Conversion of All Variables 
head(storeData)
# Step 10: Create New Variable for Categorizing Size
sizeDisc = vector(mode = "character",length = dim(storeData)[1])
storeData = cbind(storeData,sizeDisc)
# Step 11: Find Q1 and Q3 to discretize Size Variable
q1 = quantile(x = storeData$Size,probs = c(0.25))
q3 = quantile(x = storeData$Size,probs = c(0.75))
# Step 12: Discretize Size Variable into A New Variable
storeData$sizeDisc =  ifelse(test = storeData$Size < q1,yes = "Small",no = storeData$sizeDisc)
storeData$sizeDisc =  ifelse(test = storeData$Size > q3,yes = "Big",no = storeData$sizeDisc)
storeData$sizeDisc =  ifelse(test = storeData$Size > q1 & storeData$Size < q3 ,yes = "Medium",no = storeData$sizeDisc)
# Step 13: Creating SizeDisc as Ordered Factor
storeData$sizeDisc = factor(storeData$sizeDisc,levels = c("Small","Medium","Big"),ordered = TRUE)
# Step 14: Checking Type of SizeDisc
str(storeData$sizeDisc)
 Ord.factor w/ 3 levels "Small"<"Medium"<..: 2 2 2 2 2 2 2 2 2 2 ...
# Step 15: Dropping Variable Size
storeData = storeData %>% select(-Size)

Step 1: Check Class of storeData : The first step is to check the data structure of the dataset storeData. The dataset has a data structure Data Frame.

Step 2: Data Types of storeData: We check the different data types of variables using the str function. This is a convenient method to check the data types of all variables together. There variables are of mix type with 2 variables of character type, two of logical type (which could be same variable) and the rest are of numeric data type. We can also immediately see some issues. For e.g. the variable Date represents Date’s but its type is character.

Step 3: Check Both IsHoliday Variable For Similarity: We compare the IsHoliday.x and IsHoliday.y variables to check if they are similar and then use summary function to get the result. We get all 421570 as TRUE which inidicates that they are same variable.

Step 4: Dropping IsHoliday.y Variable : The IsHoliday.y variable is dropped because it is similar to the IsHoliday.x Variable.

Step 5: Renaming IsHoliday.x to IsHoliday : The IsHoliday.x variable is renamed as IsHoliday and stored in storeData and we print the head of the dataset to confirm.

Step 6: Changing Data Type of Store, Type & Dept Variable to Factor : The variables Store and Dept are just identifier variables but were originally in numeric type. Thus, we convert it from numeric data type to factor. The variable Type is of data type character & IsHoliday is logical, hence we change these also to factor type.

Step 7: Check Change of Data Type : We check if the data types have been changed to factor type by using the str function. We see for these variables the data types have been changed to factor.

Step 8: Converting Date from Character to Date Format: We convert the Date variable which is in Character type to Date Format with the as.date function using the format “%d/%m/%Y” .

Step 9: Check Conversion of All Variables : Print the head of the dataset to check conversion of data types of all variables. We see that all the variables are converted to required type.

Step 10: Create New Variable for Categorizing Size : We would like to categorize the variable size into Small, Medium and Big. To do this we create a new variable called sizeDisc. We bind this new variable with the storeData dataset.

Step 11: Find Q1 and Q3 to discretize Size Variable : To categorize the size variable we will use the 1st quartile and 3rd quartile. Any values below 1st quartile are labelled Small, values of Size between 1st and 3rd quartile are labelled Medium and values above 3rd quartile are labelled Big. Here we calculate the 1st and 3rd quartiles.

Step 12: Discretize Size Variable into A New Variable : Based on the 1st and 3rd quartiles we add categorized values into the new variable sizeDisc from size.

Step 13: Creating SizeDisc as Ordered Factor : The new created variable sizeDisc is based on the values of Size which is numeric. Since the values Small, Medium and Big are ordinal we change the type of the sizeDisc variable to ordered factor.

Step 14: Checking Type of SizeDisc : We check the structure of the variable sizeDisc to check if the conversion to ordered factor has taken place. It has been converted to ordered factor with three levels.

Step 15: Dropping Variable Size : We have categorized the variable Size into a new variable SizeDisc. Hence, we drop the variable size from the dataset.

In Summary in this section we checked the data types of the different variables which were a mix of logical, numeric and character. We then converted Store, Dept, Type and IsHoliday variables to data type factor and converted Date to date format. Finally, we categorized Size variable into SizeDisc variable and converted the SizeDisc variable into an ordered factor.

Tidy & Manipulate Data I

For data to be tidy we need the following rules to be adhered:

The tidy rule which is a problem for this dataset is that there are 5 Markdown prices as variables named MarkDown1 to Markdown5. These variables are just types of Markdown and should be combined into one variable which indicates the types of Markdown. Another variable will indicate the value which these Markdowns take for each observation. We can use the gather function to do this.

# Step 1: Combine Markdown into One Variable Using Gather
storeData = storeData %>% gather(key = "MarkdownType",value = "MarkdownAmnt" ,... = c(MarkDown1,MarkDown2,MarkDown3,MarkDown4,MarkDown5))
# Step 2: Check Head of Gathered Data
head(storeData)
# Step 3: Convert MarkDownType to Factor Type 
storeData$MarkdownType = as.factor(storeData$MarkdownType)

Step 1: Combine Markdown into One Variable Using Gather: We combine the different Markdown variables into one variable using gather function. The new variable that holds the type of markdown is MarkdownType and MarkdownAmnt holds the values for each of these Markdowns for each observations.

Step 2: Check Head of Gathered Data: We check the head of the gathered data to see if it has worked. The five variables have been gathered into the two variables as required.

Step 3: Convert MarkDownType to Factor Type: The variable MarkDownType which is created is of character type. So we change it to data type of factor.

Tidy & Manipulate Data II

The data has Weekly Sales for each Store and Dept by Week. Also it shows the different types of Markdown Types for each week and its value. From Step 1 below we see that the MarkdownAmnt variable we created has a lot of missing values. One way of dealing with this is to use imputation. For predictive analytics if a variable has a large number of missing values one way of dealing with this is to create a binary variable indicating if each observation is missing or not for that variable. In some cases whether the original variable is missing or not may be correlated with the target variable (Kelleher, et al., 2015)1. When such a variable is created usually the original variable is dropped. Here we create the new variable but do not drop the old variable for the moment since the data is only being pre processed. We create a new binary variable markdownMissing to indicate if the MarkdownAmnt is missing or not.

1: Kelleher, J. D., Namee, B. M. & D’Arcy, A., 2015. Data Exploration. In: Fundamentals Of Machine Learning For Predictive Data Analytics: Algorithms, Worked Examples, and Case Studies. London: MIT Press, p. 121.

# Step 1: Find Percent of Missing Values in MarkdownAmnt
storeData %>% filter(is.na(MarkdownAmnt)) %>% summarise(Percent = (n()/dim(storeData)[1])*100) 
# Step 2: Create Variable markdownMissing using Mutate
storeData = storeData %>% mutate(markdownMissing = if_else(condition = is.na(MarkdownAmnt),true = 1,false = 0))
# Step 3: Check Creation of markdownMissing
str(storeData$markdownMissing)
 num [1:2107850] 1 1 1 1 1 1 1 1 1 1 ...
# Step 4: Convert markDownMissing to Factor
storeData$markdownMissing = factor(storeData$markdownMissing)
# Step 5: Check Structure 
str(storeData$markdownMissing)
 Factor w/ 2 levels "0","1": 2 2 2 2 2 2 2 2 2 2 ...

Step 2: Create Variable markdownMissing using Mutate: Using mutate we create the new variable markdownMissing which takes on 1 if MarkdownAmnt is missing and 0 if MarkdownAmnt is not missing.

Step 3: Check Creation of markdownMissing : We check if the markdownMissing variable has been created by checking the structure of the data.

Step 4: Convert markDownMissing to Factor: The markdownMissing can take on only two values 0 and 1. Hence, it is converted to a factor data type.

Step 5: Check Structure: We check if the conversion of markdownMissing to data type factor is successful. It is a factor with two levels 0 and 1.

Scan I

# Step 1: Checking for Missing Values in All Variables
colSums(is.na(storeData))
          Store            Type            Dept            Date 
              0               0               0               0 
   Weekly_Sales       IsHoliday     Temperature      Fuel_Price 
              0               0               0               0 
            CPI    Unemployment        sizeDisc    MarkdownType 
              0               0           98330               0 
   MarkdownAmnt markdownMissing 
        1422431               0 
# Step 2: Finding Median of MarkdownAmnt 
markmedian = median(storeData$MarkdownAmnt,na.rm = TRUE)
# Step 3: Replacing Missing Values with Median
storeData$MarkdownAmnt =  replace_na(data = storeData$MarkdownAmnt,replace = markmedian)
# Step 4: Check Replacement
sum(is.na(storeData$MarkdownAmnt))
[1] 0
# Step 5: Subset Numeric Variables
numeric = select_if(storeData,is.numeric)
# Step 6: Summary of Numeric Variables
summary(numeric)
  Weekly_Sales     Temperature       Fuel_Price         CPI       
 Min.   : -4989   Min.   : -2.06   Min.   :2.472   Min.   :126.1  
 1st Qu.:  2080   1st Qu.: 46.68   1st Qu.:2.933   1st Qu.:132.0  
 Median :  7612   Median : 62.09   Median :3.452   Median :182.3  
 Mean   : 15981   Mean   : 60.09   Mean   :3.361   Mean   :171.2  
 3rd Qu.: 20206   3rd Qu.: 74.28   3rd Qu.:3.738   3rd Qu.:212.4  
 Max.   :693099   Max.   :100.14   Max.   :4.468   Max.   :227.2  
  Unemployment     MarkdownAmnt     
 Min.   : 3.879   Min.   :  -265.8  
 1st Qu.: 6.891   1st Qu.:  1562.9  
 Median : 7.866   Median :  1562.9  
 Mean   : 7.960   Mean   :  2391.5  
 3rd Qu.: 8.572   3rd Qu.:  1562.9  
 Max.   :14.313   Max.   :141630.6  
# Step 7: Replacing Inconsistent Value in Weekly_Sales
storeData %>%filter(Weekly_Sales < 0) %>% count()
storeData$Weekly_Sales = ifelse(test = storeData$Weekly_Sales < 0,yes = NA,no = storeData$Weekly_Sales)
# Step 8: Replacing Inconsistent Value in MarkdownAmnt
storeData %>%filter(MarkdownAmnt < 0) %>% count()
storeData$MarkdownAmnt = ifelse(test = storeData$MarkdownAmnt < 0,yes = NA,no = storeData$MarkdownAmnt)

Step 1: Checking for Missing Values in All Variables: We use colSums and is.na to check for missing values in the variables. There are only two variables with missing values, the sizeDisc variable we created from size which is a factor variable, and MarkdownAmnt which is numeric. For sizeDisc we leave the unknown values as NA’s.

Step 2: Finding Median of MarkdownAmnt: Do deal replace missing values in MarkdownAmnt we find the median so that we can replace missing values with imputed median.

Step 3: Replacing Missing Values with Median: We replace missing values in MarkdownAmnt with the median values. This is just done for demonstration but for real analysis this would not be done because the variable has too many missing values and replacing with mean or median changes the distribution.

Step 4: Check Replacement: We check replacement of the missing values in the variable markdownAmnt

Step 5 & 6: Subset & Summary of Numeric Variables: We subset only the numeric variables and check their summary to find if any variables have inconsistent values. Both weekly Sales and markdownAmnt has negative values which we replace.

Step 7 & 8: Replacing Inconsistent Value in Weekly_Sales & markDownAmnt : The inconsistent values of less than 0 have to be replaced in both the variables. We see that Weekly Sales has 6425 values below 0 and markDownAmnt has 1568 such values. We could replace with mean or median, but due to high no of such values we just replace it with NA.

Scan II

# Step 1: Finding Variables with Outliers
bx1 = boxplot(storeData$Weekly_Sales,main = "Boxplot of Weekly Sales")

bx2 = boxplot(storeData$Temperature,main = "Boxplot of Temperature")

bx3 = boxplot(storeData$Fuel_Price,storeData$Unemployment,main = "Boxplot of Fuel Price & Unemployment")

bx4 = boxplot(storeData$CPI,main = "Boxplot of CPI")

# Step 2: Capping Outlier in Weekly Sales
storeData$Weekly_Sales = ifelse(test = storeData$Weekly_Sales > bx1$stats[5],yes = bx1$stats[5],no = storeData$Weekly_Sales)
# Step 3: Capping Outlier in Temperature
storeData$Temperature = ifelse(test = storeData$Temperature < bx2$stats[1],yes = bx2$stats[1],no = storeData$Temperature)
#Step 4: Capping Outlier in Unemployment
# For lower outliers
storeData$Unemployment = ifelse(test = storeData$Unemployment < bx3$stats[1,2],yes = bx3$stats[1,2],no = storeData$Unemployment)
# For higher outliers
storeData$Unemployment = ifelse(test = storeData$Unemployment > bx3$stats[5,2],yes = bx3$stats[5,2],no = storeData$Unemployment)
# Step 5: Boxplot to Check Capping 
boxplot(storeData$Weekly_Sales,main = "Boxplot of Weekly Sales after Capping")

boxplot(storeData$Temperature,storeData$Unemployment,main = "Boxplot of Temperature and Unemployment after Capping")


Step 1: Finding Variables with Outliers: We plot the boxplot of numeric variables to see if there are any outliers. Only Weekly_Sales, Temperature and Unemployment have outliers. CPI and Fuel price variable do not have outliers.
Weekly Sales has outliers on the higher side, temperature on the lower side and Unemployment both on the higher side and lower side. We find the minimum and maximum value from the boxplot which are not outliers for the variables Weekly Sales , Temperature and Unemployment. These represent the whiskers at the top and bottom of the boxplot. We find this in stats of the boxplot object. We use these min and max values for capping outliers.

Step 2: Capping Outlier in Weekly Sales : We cap the outliers of the variable Weekly Sales to the max value from boxplot which is not an outlier.

Step 3: Capping Outlier in Temperature : The temperature variable has outlier on the lower side. We cap these outliers to the min value from boxplot which is not an outlier.

Step 4: Capping Outlier in Unemployment: Unemployment has outliers both at the higher and lower end. We cap higher outliers to the max value from boxplot which is not an outlier and similarly lower outliers are capped to the lower value from boxplot which is not an outlier.

Step 5: Boxplot to Check Capping: We plot the boxplot of the three variables again to check capping. There are no outliers present.

Transform

# Step 1: Checking Distribution of Variable Unemployment
hist(storeData$Unemployment,main = "Histogram of Unemployment",xlab = "Unemployment")

# Step 2: Creating Sqr & Cube Data
unemloy.sqr = storeData$Unemployment^2
unemploy.cube = storeData$Unemployment^3
# Step 3: Plotting histogram of Transformed Data
hist(unemloy.sqr,main = "Histogram of Squared Unemployment",xlab = "Unemployment")

hist(unemploy.cube,main = "Histogram of Unemployment Raised to 3",xlab = "Unemployment")

# Step 4: Transforming the Unemployment Variable in Dataset
storeData = storeData %>% mutate(unemploymentTrans = Unemployment^2)

Step 1: Checking Distribution of Variable Unemployment: The variable Unemployment needs to be transformed to reduce skewness and make it approximately normal. In this step we check the distribution of the variable. We see that the variable is slightly left skewed.

Step 2: Creating Sqr & Cube Data: From the previous step we know there is slightly left skew. For left skewed data, power of 2,3 etc work well for reducing skewness. Here we create the square and cube of data.

Step 3: Plotting histogram of Transformed Data: We plot the histogram of the transformed data to see if there is a change in the distribution.

Step 4: Transforming the Unemployment Variable in Dataset: From the plot of transformed data we see that the square transformtion works best. Here we mutate the Unemployment variable in the data to create the new variable unemploymentTrans which contains the squared data.



LS0tDQp0aXRsZTogIk1BVEgyMzQ5IFNlbWVzdGVyIDEsIDIwMTgiDQphdXRob3I6ICJSdXNoaWwgUiBTaXJ1ciAtIHMzNTU3MTM0Ig0Kc3VidGl0bGU6IEFzc2lnbm1lbnQgMw0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOiBkZWZhdWx0DQotLS0NCg0KIyMgUmVxdWlyZWQgcGFja2FnZXMgDQoNCg0KYGBge3IscmVzdWx0cz0naGlkZSd9DQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeSh0aWR5cikNCmBgYA0KDQoNCiMjIEV4ZWN1dGl2ZSBTdW1tYXJ5IA0KDQoNClRoZSBkYXRhIHByZS1wcm9jZXNzaW5nIGlzIGNhcnJpZWQgb3V0IG9uIGRhdGFzZXRzIGZyb20gdGhlIHJldGFpbCBkb21haW4uIFRoZXJlIGFyZSB0aHJlZSBkYXRhc2V0cyB3aGljaCBhcmUgam9pbmVkIHVzaW5nIGxlZnQgam9pbi4gVGhlIGZpbmFsIGpvaW5lZCBkYXRhIGlzIGNvbXBvc2VkIG9mIHZhcmlhYmxlcyB3aXRoIG51bWVyaWMsIGNoYXJhY3RlciBhbmQgbG9naWNhbCBkYXRhIHR5cGVzLiAgICAgDQoNCkNvbnZlcnNpb24gb2YgZGF0YSB0eXBlIGZvciBhIGZldyB2YXJpYWJsZXMgaGFkIHRvIGJlIGNhcnJpZWQgb3V0LiBGb3VyIHZhcmlhYmxlcyB3ZXJlIGNvbnZlcnRlZCB0byBmYWN0b3J5IHR5cGUgYW5kIG9uZSB2YXJpYWJsZSB3aGljaCByZXByZXNlbnRlZCBkYXRlLCB3YXMgaW4gY2hhcmFjdGVyIGRhdGEgdHlwZSBhbmQgd2FzIGNvbnZlcnRlZCBpbnRvIERhdGUgZm9ybWF0LiBBIG51bWVyaWMgdmFyaWFibGUgaXMgYWxzbyBjYXRlZ29yaXplZCBpbnRvIGEgbmV3IHZhcmlhYmxlIHdpdGggdGhyZWUgbGV2ZWxzIHdoaWNoIGlzIGFuIG9yZGVyZWQgZmFjdG9yLiANClRoZSBkYXRhIHdhcyBjaGVja2VkIGZvciB0aWRpbmVzcy4gVGhlcmUgd2VyZSBmaXZlIHZhcmlhYmxlcyB3aGljaCB3ZXJlIHByZXNlbnQgYXMgY29sdW1uIG5hbWVzIHdoaWNoIHdlcmUgd29ydGh5IG9mIGJlaW5nIGNvbWJpbmVkIGludG8gYSBzaW5nbGUgdmFyaWFibGUgdXNpbmcgZ2F0aGVyIGZ1bmN0aW9uLiBBIG5ldyBiaW5hcnkgdmFyaWFibGUgd2FzIGNyZWF0ZWQgYXMgYW4gaW5kaWNhdG9yIG9mIG1pc3NpbmcgdmFsdWVzLiAgICAgDQoNClRoZSB2YXJpYWJsZXMgd2VyZSBjaGVja2VkIGZvciBtaXNzaW5nIHZhbHVlcyBhbmQgb3V0bGllciwgd2hlcmUgYm94cGxvdHMgd2VyZSB1c2VkIGZvciBvdXRsaWVyIGNoZWNraW5nLiBPbmx5IHR3byB2YXJpYWJsZXMgaGFkIG1pc3NpbmcgdmFsdWVzLCBvbmUgd2hpY2ggd2FzIG9mIHR5cGUgZmFjdG9yIGFuZCB0aGUgb3RoZXIgbnVtZXJpYy4gVGhlIG1pc3NpbmcgdmFsdWVzIGZvciB0aGUgbnVtZXJpYyB2YXJpYWJsZSB3ZXJlIHJlcGxhY2VkIGJ5IHRoZSBtZWRpYW4gdmFsdWUgb2YgdGhlIHZhcmlhYmxlLiBUaGUgbnVtZXJpYyB2YXJpYWJsZXMgd2hpY2ggaGFkIG91dGxpZXJzIHdlcmUgbW9kaWZpZWQgYnkgY2FwcGluZyB0aGUgb3V0bGllciB2YWx1ZXMgdG8gdGhlIHVwcGVyIG9yIGxvd2VyIHZhbHVlIGZyb20gdGhlIGJveHBsb3Qgd2hpY2ggaXMgbm90IGFuIG91dGxpZXIgaXRzZWxmLiAgICAgDQoNCkZpbmFsbHksIGEgdmFyaWFibGUgd2hpY2ggaGFkIGxlZnQgc2tldyB3YXMgdHJhbnNmb3JtZWQgdXNpbmcgc3F1YXJlIHRyYW5zZm9ybWF0aW9uIGluIG9yZGVyIHRvIG1ha2UgaXQgYXBwcm94aW1hdGVseSBub3JtYWwuIA0KDQoNCiMjIERhdGEgDQoNClRoZSBkYXRhIHVzZWQgZm9yIHRoaXMgYXNzaWdubWVudCBpcyBhIFJldGFpbCBBbmFseXRpY3MgRGF0YXNldCB0aGF0IGlzIHNvdXJjZWQgZm9ybSBLYWdnbGUuIA0KDQpUaGUgZGF0YXNldHMgYXJlIGF2YWlsYWJsZSBhdCB0aGUgZm9sbG93aW5nIGxpbms6IGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vbWFuamVldHNpbmdoL3JldGFpbGRhdGFzZXQvZGF0YQ0KDQpUaGUgZGF0YSBkZXNjcmlwdGlvbiBpcyBhdmFpbGFibGUgYXQgdGhlIGZvbGxvd2luZyBsaW5rOiANCmh0dHBzOi8vd3d3LmthZ2dsZS5jb20vbWFuamVldHNpbmdoL3JldGFpbGRhdGFzZXQNCg0KVGhlIGRhdGFzZXRzIGFyZSByZWxlYXNlZCB1bmRlciBDQzA6IFB1YmxpYyBEb21haW4uIA0KDQoNClRoZXJlIGFyZSB0aHJlZSBkYXRhc2V0cyBTdG9yZXMsIEZlYXR1cmVzIGFuZCBTYWxlcy4gQWxsIHRocmVlIGRhdGFzZXRzIGFyZSBhdmFpbGFibGUgaW4gLmNzdiBmb3JtYXQuIFRoZSBkZXNjcmlwdGlvbiBvZiB0aGUgZGF0YSBhcmUgYXMgZm9sbG93czogDQoNCg0KKipTdG9yZXMqKiA6IFRoaXMgZGF0YXNldCBjb250YWlucyA0NSBzdG9yZXMgb2YgYSBjb21wYW55LCB3aXRoIHRoZSB0eXBlIGFuZCBzaXplIG9mIHRoZSBzdG9yZS4gVGhlIHN0b3JlcyBkYXRhIGlzIGFub255bWl6ZWQuIFRoZXJlIGFyZSA0NSBvYnNlcnZhdGlvbnMgYW5kIHRoZSB2YXJpYWJsZXMgb2YgdGhpcyBkYXRhIHNldCBhcmUgYXMgZm9sbG93cyAoYXMgcHJlc2VudCBpbiBvcmlnaW5hbCBmb3JtKTogDQoNClZhcmlhYmxlfFR5cGV8TGV2ZWxzfERlc2NyaXB0aW9uDQotLS0tLS0tLXwtLS0tfC0tLS0tLXwtLS0tLS0tLS0tLQ0KU3RvcmV8TnVtZXJpY3wtfFN0b3JlIE51bWJlcg0KVHlwZXxDaGFyYWN0ZXJ8QSxCLEN8VHlwZSBvZiBTdG9yZQ0KU2l6ZXxOdW1lcmljfC18U2l6ZSBvZiB0aGUgU3RvcmUNCg0KDQoqKlNhbGVzKio6IFRoaXMgaXMgdGhlIFNhbGVzIGRhdGEgZm9yIGVhY2ggc3RvcmUgYnkgZGVwYXJ0bWVudCBmcm9tIDUvMi8yMDEwIHRvIDEvMTEvMjAxMi4gVGhlcmUgYXJlIDQyMTU3MCBvYnNlcnZhdGlvbnMgYW5kIHRoZSB2YXJpYWJsZXMgaW4gdGhpcyBkYXRhIHNldCBhcmU6IA0KDQoNClZhcmlhYmxlfFR5cGV8TGV2ZWxzfERlc2NyaXB0aW9uDQotLS0tLS0tLXwtLS0tfC0tLS0tLXwtLS0tLS0tLS0tLQ0KU3RvcmV8TnVtZXJpY3wtfFN0b3JlIE51bWJlcg0KRGVwdHxOdW1lcmljfC18RGVwYXJ0bWVudCBOdW1iZXINCkRhdGV8Q2hhcmFjdGVyfC18UmVwcmVzZW50aW5nIFdlZWsNCldlZWtseV9TYWxlc3xOdW1lcmljfC18V2Vla2x5IFNhbGVzIGZvciBnaXZlbiBzdG9yZSBhbmQgZGVwdA0KSXNIb2xpZGF5fExvZ2ljYWx8LXxJZiB0aGUgd2VlayBoYXMgc3BlY2lhbCBIb2xpZGF5DQoNCg0KKipGZWF0dXJlcyoqOiBEYXRhIHJlbGF0ZWQgdG8gdGhlIHN0b3JlIGFuZCBvdGhlciBhY3Rpdml0eSBmb3IgdGhlIGRhdGVzLiBUaGVyZSBhcmUgODE5MCByb3dzIGFuZCB0aGUgdmFyaWFibGVzIGFyZSBhcyBmb2xsb3dzOg0KDQpWYXJpYWJsZXxUeXBlfExldmVsc3xEZXNjcmlwdGlvbg0KLS0tLS0tLS18LS0tLXwtLS0tLS18LS0tLS0tLS0tLS0NClN0b3JlfE51bWVyaWN8LXxTdG9yZSBOdW1iZXINCkRhdGV8Q2hhcmFjdGVyfC18UmVwcmVzZW50aW5nIFdlZWsNClRlbXBlcmF0dXJlfE51bWVyaWN8LXxBdmcgVGVtcGVyYXR1cmUgaW4gUmVnaW9uIG9mIFN0b3JlDQpGdWVsIFByaWNlfE51bWVyaWN8LXxGdWVsIHByaWNlIGluIFJlZ2lvbiBvZiBTdG9yZQ0KTWFya2Rvd24xLTV8TnVtZXJpY3wtfFByb21vdGlvbmFsIE1hcmtkb3ducyBUeXBlIGFuZCBBbW50cw0KQ1BJfE51bWVyaWN8LXxDb25zdW1lciBQcmljZSBJbmRleA0KVW5lbXBsb3ltZW50fE51bWVyaWN8LXxVbmVtcGxveW1lbnQgUmF0ZQ0KSXNIb2xpZGF5fExvZ2ljYWx8LXxJZiB0aGUgd2VlayBoYXMgc3BlY2lhbCBIb2xpZGF5DQoNCg0KDQpXZSBmaXJzdCByZWFkIGluIHRoZSBpbmRpdmlkdWFsIGRhdGFzZXRzLiAgDQoNCg0KYGBge3J9DQoNCg0KIyBTdGVwIDE6IFJlYWRpbmcgaW4gU3RvcmUNCnN0b3JlcyA9IHJlYWQuY3N2KGZpbGUgPSAiRTovUk1JVC9Db3Vyc2UgQ29udGVudC9NQVRIIDIzNDkgLSBEYXRhIFByZXByb2Nlc3NpbmcvQXNzZXNzbWVudHMvQXNzZXNzbWVudCAzL0Fzc2lnbm1lbnQvc3RvcmVzIGRhdGEtc2V0LmNzdiIsc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQ0KDQojIFN0ZXAgMjogQ2hlY2sgaWYgU3RvcmUgZGF0YSBzZXQgaGFzIGJlZW4gcmVhZCBpbiBwcm9wZXJseQ0KaGVhZChzdG9yZXMpDQpkaW0oc3RvcmVzKQ0KDQojIFN0ZXAgMzogUmVhZGluZyBpbiBTYWxlcw0Kc2FsZXMgPSByZWFkLmNzdihmaWxlID0gIkU6L1JNSVQvQ291cnNlIENvbnRlbnQvTUFUSCAyMzQ5IC0gRGF0YSBQcmVwcm9jZXNzaW5nL0Fzc2Vzc21lbnRzL0Fzc2Vzc21lbnQgMy9Bc3NpZ25tZW50L3NhbGVzIGRhdGEtc2V0LmNzdiIsc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQ0KDQojIFN0ZXAgNDogQ2hlY2sgaGVhZCBhbmQgZGltIG9mIFNhbGVzIERhdGENCmhlYWQoc2FsZXMpDQpkaW0oc2FsZXMpDQoNCg0KIyBTdGVwIDU6IFJlYWRpbmcgaW4gRmVhdHVyZSBkYXRhIHNldA0KZmVhdHVyZXMgPSByZWFkLmNzdihmaWxlID0gIkU6L1JNSVQvQ291cnNlIENvbnRlbnQvTUFUSCAyMzQ5IC0gRGF0YSBQcmVwcm9jZXNzaW5nL0Fzc2Vzc21lbnRzL0Fzc2Vzc21lbnQgMy9Bc3NpZ25tZW50L0ZlYXR1cmVzIGRhdGEgc2V0LmNzdiIsc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQ0KDQoNCiMgU3RlcCA2OiBDaGVja2luZyBoZWFkIGFuZCBkaW0gb2YgRmVhdHVyZXMgRGF0YSANCmhlYWQoZmVhdHVyZXMpDQpkaW0oZmVhdHVyZXMpDQoNCiMgU3RlcCA3OiBMZWZ0IEpvaW4gU3RvcmVzIGFuZCBTYWxlcyBEYXRhc2V0IGJ5IFN0b3JlDQpzdG9yZURhdGEgPSBzdG9yZXMgJT4lIGxlZnRfam9pbih5ID0gc2FsZXMsYnkgPSAiU3RvcmUiKQ0KDQojIFN0ZXAgODogIENoZWNraW5nIEhlYWQgYW5kIERpbSBvZiBzdG9yZURhdGENCmhlYWQoc3RvcmVEYXRhKQ0KZGltKHN0b3JlRGF0YSkNCg0KIyBTdGVwIDk6IExlZnQgSm9pbiBzdG9yZURhdGEgd2l0aCBmZWF0dXJlcyBieSBTdG9yZSBhbmQgRGF0ZSANCnN0b3JlRGF0YSA9IHN0b3JlRGF0YSAlPiUgbGVmdF9qb2luKHkgPSBmZWF0dXJlcyxieSA9IGMoIlN0b3JlIiwiRGF0ZSIpKQ0KDQojIFN0ZXAgMTA6IENoZWNraW5nIEhlYWQgYW5kIERpbSBvZiBzdG9yZURhdGENCmhlYWQoc3RvcmVEYXRhKQ0KZGltKHN0b3JlRGF0YSkNCg0KYGBgDQoNCioqU3RlcCAxOiBSZWFkIGluIFN0b3JlcyBEYXRhKiogOiBJbiB0aGlzIHN0ZXAgd2UgZmlyc3QgcmVhZCBpbiB0aGUgc3RvcmUgZGF0YSB1c2luZyByZWFkLmNzdiBmdW5jdGlvbiBhbmQgc2F2ZSBhcyBzdG9yZXMuICAgDQoqKlN0ZXAgMjogQ2hlY2sgSGVhZCBhbmQgRGltZW5zaW9uIG9mIFN0b3JlIERhdGEqKiA6IENoZWNrIHRoZSBoZWFkIG9mIHRoZSBpbXBvcnRlZCBzdG9yZXMgZGF0YSB0byBzZWUgaWYgdGhlIGltcG9ydCBpcyBwcm9wZXIgYW5kIGNoZWNrIHRoZSBkaW1lbnNpb24gb2YgdGhlIHJlYWQgaW4gZGF0YS5UaGUgc3RvcmVzIGRhdGEgaGFzIGJlZW4gcmVhZCBpbiBwcm9wZXJseSBhbmQgaGFzIDQ1IG9ic2VydmF0aW9ucyBhbmQgMyB2YXJpYWJsZXMgYXMgZXhwZWN0ZWQuICAgICANCioqU3RlcCAzOiBSZWFkIGluIFNhbGVzIERhdGEqKiA6IFRoZSBTYWxlcyBkYXRhIHNldCBpcyByZWFkIGludG8gUiB1c2luZyB0aGUgcmVhZC5jc3YgZnVuY3Rpb24gYW5kIHNhdmVkIGFzIHNhbGVzLiAgICAgDQoqKlN0ZXAgNDogQ2hlY2sgSGVhZCBhbmQgRGltZW5zaW9uIG9mIFNhbGVzIERhdGEqKiA6IFRoZSBzYWxlcyBkYXRhIGlzIHJlYWQgaW50byBSIHByb3Blcmx5IGFuZCBoYXMgNDIxNTcwIG9ic2VydmF0aW9ucyBhbmQgNSB2YXJpYWJsZXMgYXMgZXhwZWN0ZWQuICAgICANCioqU3RlcCA1OiBSZWFkIGluIEZlYXR1cmVzIERhdGEqKiA6IFRoZSBGZWF0dXJlcyBkYXRhIHNldCBpcyByZWFkIGludG8gUiB1c2luZyB0aGUgcmVhZC5jc3YgZnVuY3Rpb24gYW5kIHNhdmVkIGFzIGZlYXR1cmVzLiAgICANCioqU3RlcCA2OiBDaGVjayBIZWFkIGFuZCBEaW1lbnNpb24gb2YgRmVhdHVyZXMgRGF0YSoqIDogQ2hlY2sgdGhlIGhlYWQgYW5kIGRpbWVuc2lvbnMgb2YgdGhlIEZlYXR1cmVzIGRhdGEgc2V0LiBUaGUgZmVhdHVyZXMgZGF0YSBzZXQgaXMgcmVhZCBpbnRvIFIgYW5kIGl0IGhhcyA4MTkwIG9ic2VydmF0aW9ucyBhbmQgMTIgdmFyaWFibGVzLiAgICAgICANCioqU3RlcCA3OiBMZWZ0IEpvaW4gU3RvcmVzIGFuZCBTYWxlcyBEYXRhc2V0KiogOiBXZSBsZWZ0IGpvaW4gdGhlIFNhbGVzIGRhdGFzZXQgd2l0aCB0aGUgU3RvcmVzIGRhdGFzZXQgb24gdGhlIHZhcmlhYmxlIFN0b3JlIGFuZCBzYXZlIHRoZSBkYXRhc2V0IGFzIHN0b3JlRGF0YS4gICAgDQoqKlN0ZXAgODogQ2hlY2sgSGVhZCBhbmQgRGltZW5zaW9uIG9mIHN0b3JlRGF0YSBEYXRhc2V0Kio6IFRoZSBoZWFkIGZ1bmN0aW9uIGFuZCBkaW0gZnVuY3Rpb24gYXJlIHVzZWQgdG8gY2hlY2sgdGhlIGhlYWQgYW5kIGRpbWVuc2lvbnMgb2YgdGhlIGpvaW5lZCBkYXRhc2V0LiBJdCBoYXMgNDIxNTcwIG9ic2VydmF0aW9ucyBhbmQgNyB2YXJpYWJsZXMgYXMgcmVxdWlyZWQuICAgICANCioqU3RlcCA5OiBMZWZ0IEpvaW4gU3RvcmVEYXRhIGFuZCBGZWF0dXJlcyBEYXRhc2V0KiogOiBUaGUgZmVhdHVyZXMgZGF0YXNldCBpcyBsZWZ0IGpvaW5lZCB3aXRoIHN0b3JlRGF0YSBjcmVhdGVkIGFib3ZlIG9uIHRoZSB2YXJpYWJsZXMgU3RvcmUgYW5kIERhdGUgYW5kIHN0b3JlZCBhZ2FpbiBhcyBzdG9yZURhdGEuICAgICANCioqU3RlcCAxMDogQ2hlY2sgSGVhZCBhbmQgRGltZW5zaW9uIG9mIHN0b3JlRGF0YSBEYXRhc2V0KiogOiBUaGUgaGVhZCBhbmQgZGltZW5zaW9uIG9mIHRoZSBzdG9yZURhdGEgYWZ0ZXIgam9pbmluZyB0aGUgdGhyZWUgdGFibGVzIGlzIGNoZWNrZWQuIFRoZXJlIGFyZSA0MjE1NzAgb2JzZXJ2YXRpb25zIGFuZCAxNyByb3dzIGFzIGV4cGVjdGVkLiANCg0KDQoNCg0KDQoNCg0KIyMgVW5kZXJzdGFuZCANCg0KDQoNCmBgYHtyfQ0KIyBTdGVwIDE6IENoZWNrIGNsYXNzIG9mIHN0b3JlRGF0YQ0KY2xhc3Moc3RvcmVEYXRhKQ0KDQojIFN0ZXAgMjogQ2hlY2sgRGF0YSBUeXBlcyBvZiBzdG9yZURhdGENCnN0cihzdG9yZURhdGEpDQoNCiMgU3RlcCAzOiBDaGVjayBCb3RoIElzSG9saWRheSBWYXJpYWJsZSBmb3IgU2ltaWxhcml0eQ0Kc3VtbWFyeShzdG9yZURhdGEkSXNIb2xpZGF5LnggPT0gc3RvcmVEYXRhJElzSG9saWRheS55KQ0KDQojIFN0ZXAgNDogRHJvcHBpbmcgSXNIb2xpZGF5LnkgVmFyaWFibGUgDQpzdG9yZURhdGEgPSBzdG9yZURhdGEgJT4lIHNlbGVjdCguLi4gPSAtSXNIb2xpZGF5LnkgKQ0KDQojIFN0ZXAgNTogUmVuYW1pbmcgSXNIb2xpZGF5LnggdG8gSXNIb2xpZGF5DQpzdG9yZURhdGEgPSBzdG9yZURhdGEgJT4lIHJlbmFtZShJc0hvbGlkYXkgPSBJc0hvbGlkYXkueCkNCmhlYWQoc3RvcmVEYXRhKQ0KDQojIFN0ZXAgNjogQ2hhbmdpbmcgRGF0YSBUeXBlIG9mIFN0b3JlLCBUeXBlLCBEZXB0ICYgSXNIb2xpZGF5IFZhcmlhYmxlIHRvIEZhY3Rvcg0Kc3RvcmVEYXRhWyxjKDEsMiw0LDcpXSA9IGxhcHBseShzdG9yZURhdGFbLGMoMSwyLDQsNyldLGFzLmZhY3RvcikNCg0KIyBTdGVwIDc6IENoZWNrIENoYW5nZSBvZiBEYXRhIFR5cGUgDQpzdHIoc3RvcmVEYXRhKQ0KDQojIFN0ZXAgODogQ29udmVydGluZyBEYXRlIGZyb20gQ2hhcmFjdGVyIHRvIERhdGUgRm9ybWF0DQpzdG9yZURhdGEkRGF0ZSA9IGFzLkRhdGUoc3RvcmVEYXRhJERhdGUsZm9ybWF0ID0gIiVkLyVtLyVZIikNCg0KIyBTdGVwIDk6IENoZWNrIENvbnZlcnNpb24gb2YgQWxsIFZhcmlhYmxlcyANCmhlYWQoc3RvcmVEYXRhKQ0KDQojIFN0ZXAgMTA6IENyZWF0ZSBOZXcgVmFyaWFibGUgZm9yIENhdGVnb3JpemluZyBTaXplDQpzaXplRGlzYyA9IHZlY3Rvcihtb2RlID0gImNoYXJhY3RlciIsbGVuZ3RoID0gZGltKHN0b3JlRGF0YSlbMV0pDQpzdG9yZURhdGEgPSBjYmluZChzdG9yZURhdGEsc2l6ZURpc2MpDQoNCiMgU3RlcCAxMTogRmluZCBRMSBhbmQgUTMgdG8gZGlzY3JldGl6ZSBTaXplIFZhcmlhYmxlDQpxMSA9IHF1YW50aWxlKHggPSBzdG9yZURhdGEkU2l6ZSxwcm9icyA9IGMoMC4yNSkpDQpxMyA9IHF1YW50aWxlKHggPSBzdG9yZURhdGEkU2l6ZSxwcm9icyA9IGMoMC43NSkpDQoNCg0KIyBTdGVwIDEyOiBEaXNjcmV0aXplIFNpemUgVmFyaWFibGUgaW50byBBIE5ldyBWYXJpYWJsZQ0Kc3RvcmVEYXRhJHNpemVEaXNjID0gIGlmZWxzZSh0ZXN0ID0gc3RvcmVEYXRhJFNpemUgPCBxMSx5ZXMgPSAiU21hbGwiLG5vID0gc3RvcmVEYXRhJHNpemVEaXNjKQ0Kc3RvcmVEYXRhJHNpemVEaXNjID0gIGlmZWxzZSh0ZXN0ID0gc3RvcmVEYXRhJFNpemUgPiBxMyx5ZXMgPSAiQmlnIixubyA9IHN0b3JlRGF0YSRzaXplRGlzYykNCnN0b3JlRGF0YSRzaXplRGlzYyA9ICBpZmVsc2UodGVzdCA9IHN0b3JlRGF0YSRTaXplID4gcTEgJiBzdG9yZURhdGEkU2l6ZSA8IHEzICx5ZXMgPSAiTWVkaXVtIixubyA9IHN0b3JlRGF0YSRzaXplRGlzYykNCg0KDQojIFN0ZXAgMTM6IENyZWF0aW5nIFNpemVEaXNjIGFzIE9yZGVyZWQgRmFjdG9yDQpzdG9yZURhdGEkc2l6ZURpc2MgPSBmYWN0b3Ioc3RvcmVEYXRhJHNpemVEaXNjLGxldmVscyA9IGMoIlNtYWxsIiwiTWVkaXVtIiwiQmlnIiksb3JkZXJlZCA9IFRSVUUpDQoNCiMgU3RlcCAxNDogQ2hlY2tpbmcgVHlwZSBvZiBTaXplRGlzYw0Kc3RyKHN0b3JlRGF0YSRzaXplRGlzYykNCg0KIyBTdGVwIDE1OiBEcm9wcGluZyBWYXJpYWJsZSBTaXplDQpzdG9yZURhdGEgPSBzdG9yZURhdGEgJT4lIHNlbGVjdCgtU2l6ZSkNCg0KYGBgDQoNCg0KKioqKg0KDQoqKlN0ZXAgMTogQ2hlY2sgQ2xhc3Mgb2Ygc3RvcmVEYXRhKiogOiBUaGUgZmlyc3Qgc3RlcCBpcyB0byBjaGVjayB0aGUgZGF0YSBzdHJ1Y3R1cmUgb2YgdGhlIGRhdGFzZXQgc3RvcmVEYXRhLiBUaGUgZGF0YXNldCBoYXMgYSBkYXRhIHN0cnVjdHVyZSBEYXRhIEZyYW1lLiAgICAgDQoNCg0KKipTdGVwIDI6IERhdGEgVHlwZXMgb2Ygc3RvcmVEYXRhKio6IFdlIGNoZWNrIHRoZSBkaWZmZXJlbnQgZGF0YSB0eXBlcyBvZiB2YXJpYWJsZXMgdXNpbmcgdGhlIHN0ciBmdW5jdGlvbi4gVGhpcyBpcyBhIGNvbnZlbmllbnQgbWV0aG9kIHRvIGNoZWNrIHRoZSBkYXRhIHR5cGVzIG9mIGFsbCB2YXJpYWJsZXMgdG9nZXRoZXIuIFRoZXJlIHZhcmlhYmxlcyBhcmUgb2YgbWl4IHR5cGUgd2l0aCAyIHZhcmlhYmxlcyBvZiBjaGFyYWN0ZXIgdHlwZSwgdHdvIG9mIGxvZ2ljYWwgdHlwZSAod2hpY2ggY291bGQgYmUgc2FtZSB2YXJpYWJsZSkgYW5kIHRoZSByZXN0IGFyZSBvZiBudW1lcmljIGRhdGEgdHlwZS4gV2UgY2FuIGFsc28gaW1tZWRpYXRlbHkgc2VlIHNvbWUgaXNzdWVzLiBGb3IgZS5nLiB0aGUgdmFyaWFibGUgRGF0ZSByZXByZXNlbnRzIERhdGUncyBidXQgaXRzIHR5cGUgaXMgY2hhcmFjdGVyLiAgICANCg0KDQoqKlN0ZXAgMzogQ2hlY2sgQm90aCBJc0hvbGlkYXkgVmFyaWFibGUgRm9yIFNpbWlsYXJpdHkqKjogV2UgY29tcGFyZSB0aGUgSXNIb2xpZGF5LnggYW5kIElzSG9saWRheS55IHZhcmlhYmxlcyB0byBjaGVjayBpZiB0aGV5IGFyZSBzaW1pbGFyIGFuZCB0aGVuIHVzZSBzdW1tYXJ5IGZ1bmN0aW9uIHRvIGdldCB0aGUgcmVzdWx0LiBXZSBnZXQgYWxsIDQyMTU3MCBhcyBUUlVFIHdoaWNoIGluaWRpY2F0ZXMgdGhhdCB0aGV5IGFyZSBzYW1lIHZhcmlhYmxlLiAgDQoNCg0KKipTdGVwIDQ6IERyb3BwaW5nIElzSG9saWRheS55IFZhcmlhYmxlKiogOiBUaGUgSXNIb2xpZGF5LnkgdmFyaWFibGUgaXMgZHJvcHBlZCBiZWNhdXNlIGl0IGlzIHNpbWlsYXIgdG8gdGhlIElzSG9saWRheS54IFZhcmlhYmxlLiAgDQoNCioqU3RlcCA1OiBSZW5hbWluZyBJc0hvbGlkYXkueCB0byBJc0hvbGlkYXkqKiA6IFRoZSBJc0hvbGlkYXkueCB2YXJpYWJsZSBpcyByZW5hbWVkIGFzIElzSG9saWRheSBhbmQgc3RvcmVkIGluIHN0b3JlRGF0YSBhbmQgd2UgcHJpbnQgdGhlIGhlYWQgb2YgdGhlIGRhdGFzZXQgdG8gY29uZmlybS4gDQoNCioqU3RlcCA2OiBDaGFuZ2luZyBEYXRhIFR5cGUgb2YgU3RvcmUsIFR5cGUgJiBEZXB0IFZhcmlhYmxlIHRvIEZhY3RvcioqIDogVGhlIHZhcmlhYmxlcyBTdG9yZSBhbmQgRGVwdCBhcmUganVzdCBpZGVudGlmaWVyIHZhcmlhYmxlcyBidXQgd2VyZSBvcmlnaW5hbGx5IGluIG51bWVyaWMgdHlwZS4gVGh1cywgd2UgY29udmVydCBpdCBmcm9tIG51bWVyaWMgZGF0YSB0eXBlIHRvIGZhY3Rvci4gVGhlIHZhcmlhYmxlIFR5cGUgaXMgb2YgZGF0YSB0eXBlIGNoYXJhY3RlciAmIElzSG9saWRheSBpcyBsb2dpY2FsLCBoZW5jZSB3ZSBjaGFuZ2UgdGhlc2UgYWxzbyB0byBmYWN0b3IgdHlwZS4gDQoNCioqU3RlcCA3OiBDaGVjayBDaGFuZ2Ugb2YgRGF0YSBUeXBlKiogOiBXZSBjaGVjayBpZiB0aGUgZGF0YSB0eXBlcyBoYXZlIGJlZW4gY2hhbmdlZCB0byBmYWN0b3IgdHlwZSBieSB1c2luZyB0aGUgc3RyIGZ1bmN0aW9uLiBXZSBzZWUgZm9yIHRoZXNlIHZhcmlhYmxlcyB0aGUgZGF0YSB0eXBlcyBoYXZlIGJlZW4gY2hhbmdlZCB0byBmYWN0b3IuIA0KDQoqKlN0ZXAgODogQ29udmVydGluZyBEYXRlIGZyb20gQ2hhcmFjdGVyIHRvIERhdGUgRm9ybWF0Kio6IFdlIGNvbnZlcnQgdGhlIERhdGUgdmFyaWFibGUgd2hpY2ggaXMgaW4gQ2hhcmFjdGVyIHR5cGUgdG8gRGF0ZSBGb3JtYXQgd2l0aCB0aGUgYXMuZGF0ZSBmdW5jdGlvbiB1c2luZyB0aGUgZm9ybWF0ICIlZC8lbS8lWSIgLg0KDQoqKlN0ZXAgOTogQ2hlY2sgQ29udmVyc2lvbiBvZiBBbGwgVmFyaWFibGVzICoqOiBQcmludCB0aGUgaGVhZCBvZiB0aGUgZGF0YXNldCB0byBjaGVjayBjb252ZXJzaW9uIG9mIGRhdGEgdHlwZXMgb2YgYWxsIHZhcmlhYmxlcy4gV2Ugc2VlIHRoYXQgYWxsIHRoZSB2YXJpYWJsZXMgYXJlIGNvbnZlcnRlZCB0byByZXF1aXJlZCB0eXBlLg0KDQoqKlN0ZXAgMTA6IENyZWF0ZSBOZXcgVmFyaWFibGUgZm9yIENhdGVnb3JpemluZyBTaXplKiogOiBXZSB3b3VsZCBsaWtlIHRvIGNhdGVnb3JpemUgdGhlIHZhcmlhYmxlIHNpemUgaW50byBTbWFsbCwgTWVkaXVtIGFuZCBCaWcuIFRvIGRvIHRoaXMgd2UgY3JlYXRlIGEgbmV3IHZhcmlhYmxlIGNhbGxlZCBzaXplRGlzYy4gV2UgYmluZCB0aGlzIG5ldyB2YXJpYWJsZSB3aXRoIHRoZSBzdG9yZURhdGEgZGF0YXNldC4gDQoNCg0KKipTdGVwIDExOiBGaW5kIFExIGFuZCBRMyB0byBkaXNjcmV0aXplIFNpemUgVmFyaWFibGUqKiA6IFRvIGNhdGVnb3JpemUgdGhlIHNpemUgdmFyaWFibGUgd2Ugd2lsbCB1c2UgdGhlIDFzdCBxdWFydGlsZSBhbmQgM3JkIHF1YXJ0aWxlLiBBbnkgdmFsdWVzIGJlbG93IDFzdCBxdWFydGlsZSBhcmUgbGFiZWxsZWQgU21hbGwsIHZhbHVlcyBvZiBTaXplIGJldHdlZW4gMXN0IGFuZCAzcmQgcXVhcnRpbGUgYXJlIGxhYmVsbGVkIE1lZGl1bSBhbmQgdmFsdWVzIGFib3ZlIDNyZCBxdWFydGlsZSBhcmUgbGFiZWxsZWQgQmlnLiBIZXJlIHdlIGNhbGN1bGF0ZSB0aGUgMXN0IGFuZCAzcmQgcXVhcnRpbGVzLiANCg0KKipTdGVwIDEyOiBEaXNjcmV0aXplIFNpemUgVmFyaWFibGUgaW50byBBIE5ldyBWYXJpYWJsZSoqIDogQmFzZWQgb24gdGhlIDFzdCBhbmQgM3JkIHF1YXJ0aWxlcyB3ZSBhZGQgY2F0ZWdvcml6ZWQgdmFsdWVzIGludG8gdGhlIG5ldyB2YXJpYWJsZSBzaXplRGlzYyBmcm9tIHNpemUuIA0KDQoNCioqU3RlcCAxMzogQ3JlYXRpbmcgU2l6ZURpc2MgYXMgT3JkZXJlZCBGYWN0b3IqKiA6IFRoZSBuZXcgY3JlYXRlZCB2YXJpYWJsZSBzaXplRGlzYyBpcyBiYXNlZCBvbiB0aGUgdmFsdWVzIG9mIFNpemUgd2hpY2ggaXMgbnVtZXJpYy4gU2luY2UgdGhlIHZhbHVlcyBTbWFsbCwgTWVkaXVtIGFuZCBCaWcgYXJlIG9yZGluYWwgd2UgY2hhbmdlIHRoZSB0eXBlIG9mIHRoZSBzaXplRGlzYyB2YXJpYWJsZSB0byBvcmRlcmVkIGZhY3Rvci4gIA0KDQoNCioqU3RlcCAxNDogQ2hlY2tpbmcgVHlwZSBvZiBTaXplRGlzYyoqIDogV2UgY2hlY2sgdGhlIHN0cnVjdHVyZSBvZiB0aGUgdmFyaWFibGUgc2l6ZURpc2MgdG8gY2hlY2sgaWYgdGhlIGNvbnZlcnNpb24gdG8gb3JkZXJlZCBmYWN0b3IgaGFzIHRha2VuIHBsYWNlLiBJdCBoYXMgYmVlbiBjb252ZXJ0ZWQgdG8gb3JkZXJlZCBmYWN0b3Igd2l0aCB0aHJlZSBsZXZlbHMuIA0KDQoqKlN0ZXAgMTU6IERyb3BwaW5nIFZhcmlhYmxlIFNpemUqKiA6IFdlIGhhdmUgY2F0ZWdvcml6ZWQgdGhlIHZhcmlhYmxlIFNpemUgaW50byBhIG5ldyB2YXJpYWJsZSBTaXplRGlzYy4gSGVuY2UsIHdlIGRyb3AgdGhlIHZhcmlhYmxlIHNpemUgZnJvbSB0aGUgZGF0YXNldC4gDQoNCg0KSW4gU3VtbWFyeSBpbiB0aGlzIHNlY3Rpb24gd2UgY2hlY2tlZCB0aGUgZGF0YSB0eXBlcyBvZiB0aGUgZGlmZmVyZW50IHZhcmlhYmxlcyB3aGljaCB3ZXJlIGEgbWl4IG9mIGxvZ2ljYWwsIG51bWVyaWMgYW5kIGNoYXJhY3Rlci4gV2UgdGhlbiBjb252ZXJ0ZWQgU3RvcmUsIERlcHQsIFR5cGUgYW5kIElzSG9saWRheSB2YXJpYWJsZXMgdG8gZGF0YSB0eXBlIGZhY3RvciBhbmQgY29udmVydGVkIERhdGUgdG8gZGF0ZSBmb3JtYXQuIEZpbmFsbHksIHdlIGNhdGVnb3JpemVkIFNpemUgdmFyaWFibGUgaW50byBTaXplRGlzYyB2YXJpYWJsZSBhbmQgY29udmVydGVkIHRoZSBTaXplRGlzYyB2YXJpYWJsZSBpbnRvIGFuIG9yZGVyZWQgZmFjdG9yLiANCg0KDQoNCg0KDQoNCg0KIyMJVGlkeSAmIE1hbmlwdWxhdGUgRGF0YSBJIA0KDQoNCkZvciBkYXRhIHRvIGJlIHRpZHkgd2UgbmVlZCB0aGUgZm9sbG93aW5nIHJ1bGVzIHRvIGJlIGFkaGVyZWQ6IA0KDQoqIEVhY2ggdmFyaWFibGUgbXVzdCBiZSBpbiBhIGNvbHVtbg0KKiBFYWNoIG9ic2VydmF0aW9uIG11c3QgYmUgaW4gYSByb3cNCiogRWFjaCB2YWx1ZSBtdXN0IGJlIGluIGEgY2VsbA0KDQoNClRoZSB0aWR5IHJ1bGUgd2hpY2ggaXMgYSBwcm9ibGVtIGZvciB0aGlzIGRhdGFzZXQgaXMgdGhhdCB0aGVyZSBhcmUgNSBNYXJrZG93biBwcmljZXMgYXMgdmFyaWFibGVzIG5hbWVkIE1hcmtEb3duMSB0byBNYXJrZG93bjUuIFRoZXNlIHZhcmlhYmxlcyBhcmUganVzdCB0eXBlcyBvZiBNYXJrZG93biBhbmQgc2hvdWxkIGJlIGNvbWJpbmVkIGludG8gb25lIHZhcmlhYmxlIHdoaWNoIGluZGljYXRlcyB0aGUgdHlwZXMgb2YgTWFya2Rvd24uIEFub3RoZXIgdmFyaWFibGUgd2lsbCBpbmRpY2F0ZSB0aGUgdmFsdWUgd2hpY2ggdGhlc2UgTWFya2Rvd25zIHRha2UgZm9yIGVhY2ggb2JzZXJ2YXRpb24uIFdlIGNhbiB1c2UgdGhlIGdhdGhlciBmdW5jdGlvbiB0byBkbyB0aGlzLiANCg0KDQpgYGB7cn0NCiMgU3RlcCAxOiBDb21iaW5lIE1hcmtkb3duIGludG8gT25lIFZhcmlhYmxlIFVzaW5nIEdhdGhlcg0Kc3RvcmVEYXRhID0gc3RvcmVEYXRhICU+JSBnYXRoZXIoa2V5ID0gIk1hcmtkb3duVHlwZSIsdmFsdWUgPSAiTWFya2Rvd25BbW50IiAsLi4uID0gYyhNYXJrRG93bjEsTWFya0Rvd24yLE1hcmtEb3duMyxNYXJrRG93bjQsTWFya0Rvd241KSkNCg0KIyBTdGVwIDI6IENoZWNrIEhlYWQgb2YgR2F0aGVyZWQgRGF0YQ0KaGVhZChzdG9yZURhdGEpDQoNCiMgU3RlcCAzOiBDb252ZXJ0IE1hcmtEb3duVHlwZSB0byBGYWN0b3IgVHlwZSANCnN0b3JlRGF0YSRNYXJrZG93blR5cGUgPSBhcy5mYWN0b3Ioc3RvcmVEYXRhJE1hcmtkb3duVHlwZSkNCg0KYGBgDQoNCioqKioNCg0KKipTdGVwIDE6IENvbWJpbmUgTWFya2Rvd24gaW50byBPbmUgVmFyaWFibGUgVXNpbmcgR2F0aGVyKio6IFdlIGNvbWJpbmUgdGhlIGRpZmZlcmVudCBNYXJrZG93biB2YXJpYWJsZXMgaW50byBvbmUgdmFyaWFibGUgdXNpbmcgZ2F0aGVyIGZ1bmN0aW9uLiBUaGUgbmV3IHZhcmlhYmxlIHRoYXQgaG9sZHMgdGhlIHR5cGUgb2YgbWFya2Rvd24gaXMgTWFya2Rvd25UeXBlIGFuZCBNYXJrZG93bkFtbnQgaG9sZHMgdGhlIHZhbHVlcyBmb3IgZWFjaCBvZiB0aGVzZSBNYXJrZG93bnMgZm9yIGVhY2ggb2JzZXJ2YXRpb25zLiANCg0KKipTdGVwIDI6IENoZWNrIEhlYWQgb2YgR2F0aGVyZWQgRGF0YSoqOiBXZSBjaGVjayB0aGUgaGVhZCBvZiB0aGUgZ2F0aGVyZWQgZGF0YSB0byBzZWUgaWYgaXQgaGFzIHdvcmtlZC4gVGhlIGZpdmUgdmFyaWFibGVzIGhhdmUgYmVlbiBnYXRoZXJlZCBpbnRvIHRoZSB0d28gdmFyaWFibGVzIGFzIHJlcXVpcmVkLiANCg0KKipTdGVwIDM6IENvbnZlcnQgTWFya0Rvd25UeXBlIHRvIEZhY3RvciBUeXBlKio6IFRoZSB2YXJpYWJsZSBNYXJrRG93blR5cGUgd2hpY2ggaXMgY3JlYXRlZCBpcyBvZiBjaGFyYWN0ZXIgdHlwZS4gU28gd2UgY2hhbmdlIGl0IHRvIGRhdGEgdHlwZSBvZiBmYWN0b3IuDQoNCg0KDQoNCg0KDQoNCiMjCVRpZHkgJiBNYW5pcHVsYXRlIERhdGEgSUkgDQoNCg0KVGhlIGRhdGEgaGFzIFdlZWtseSBTYWxlcyBmb3IgZWFjaCBTdG9yZSBhbmQgRGVwdCBieSBXZWVrLiBBbHNvIGl0IHNob3dzIHRoZSBkaWZmZXJlbnQgdHlwZXMgb2YgTWFya2Rvd24gVHlwZXMgZm9yIGVhY2ggd2VlayBhbmQgaXRzIHZhbHVlLiBGcm9tIFN0ZXAgMSBiZWxvdyB3ZSBzZWUgdGhhdCB0aGUgTWFya2Rvd25BbW50IHZhcmlhYmxlIHdlIGNyZWF0ZWQgaGFzIGEgbG90IG9mIG1pc3NpbmcgdmFsdWVzLiBPbmUgd2F5IG9mIGRlYWxpbmcgd2l0aCB0aGlzIGlzIHRvIHVzZSBpbXB1dGF0aW9uLiBGb3IgcHJlZGljdGl2ZSBhbmFseXRpY3MgaWYgYSB2YXJpYWJsZSBoYXMgYSBsYXJnZSBudW1iZXIgb2YgbWlzc2luZyB2YWx1ZXMgb25lIHdheSBvZiBkZWFsaW5nIHdpdGggdGhpcyBpcyB0byBjcmVhdGUgYSBiaW5hcnkgdmFyaWFibGUgaW5kaWNhdGluZyBpZiBlYWNoIG9ic2VydmF0aW9uIGlzIG1pc3Npbmcgb3Igbm90IGZvciB0aGF0IHZhcmlhYmxlLiBJbiBzb21lIGNhc2VzIHdoZXRoZXIgdGhlIG9yaWdpbmFsIHZhcmlhYmxlIGlzIG1pc3Npbmcgb3Igbm90IG1heSBiZSBjb3JyZWxhdGVkIHdpdGggdGhlIHRhcmdldCB2YXJpYWJsZSAoS2VsbGVoZXIsIGV0IGFsLiwgMjAxNSleMV4uIFdoZW4gc3VjaCBhIHZhcmlhYmxlIGlzIGNyZWF0ZWQgdXN1YWxseSB0aGUgb3JpZ2luYWwgdmFyaWFibGUgaXMgZHJvcHBlZC4gSGVyZSB3ZSBjcmVhdGUgdGhlIG5ldyB2YXJpYWJsZSBidXQgZG8gbm90IGRyb3AgdGhlIG9sZCB2YXJpYWJsZSBmb3IgdGhlIG1vbWVudCBzaW5jZSB0aGUgZGF0YSBpcyBvbmx5IGJlaW5nIHByZSBwcm9jZXNzZWQuIFdlIGNyZWF0ZSBhIG5ldyBiaW5hcnkgdmFyaWFibGUgbWFya2Rvd25NaXNzaW5nIHRvIGluZGljYXRlIGlmIHRoZSBNYXJrZG93bkFtbnQgaXMgbWlzc2luZyBvciBub3QuIA0KDQoqKl4xXioqOiBLZWxsZWhlciwgSi4gRC4sIE5hbWVlLCBCLiBNLiAmIEQnQXJjeSwgQS4sIDIwMTUuIERhdGEgRXhwbG9yYXRpb24uIEluOiBGdW5kYW1lbnRhbHMgT2YgTWFjaGluZSBMZWFybmluZyBGb3IgUHJlZGljdGl2ZSBEYXRhIEFuYWx5dGljczogQWxnb3JpdGhtcywgV29ya2VkIEV4YW1wbGVzLCBhbmQgQ2FzZSBTdHVkaWVzLiBMb25kb246IE1JVCBQcmVzcywgcC4gMTIxLg0KDQoNCmBgYHtyfQ0KIyBTdGVwIDE6IEZpbmQgUGVyY2VudCBvZiBNaXNzaW5nIFZhbHVlcyBpbiBNYXJrZG93bkFtbnQNCnN0b3JlRGF0YSAlPiUgZmlsdGVyKGlzLm5hKE1hcmtkb3duQW1udCkpICU+JSBzdW1tYXJpc2UoUGVyY2VudCA9IChuKCkvZGltKHN0b3JlRGF0YSlbMV0pKjEwMCkgDQoNCiMgU3RlcCAyOiBDcmVhdGUgVmFyaWFibGUgbWFya2Rvd25NaXNzaW5nIHVzaW5nIE11dGF0ZQ0Kc3RvcmVEYXRhID0gc3RvcmVEYXRhICU+JSBtdXRhdGUobWFya2Rvd25NaXNzaW5nID0gaWZfZWxzZShjb25kaXRpb24gPSBpcy5uYShNYXJrZG93bkFtbnQpLHRydWUgPSAxLGZhbHNlID0gMCkpDQoNCiMgU3RlcCAzOiBDaGVjayBDcmVhdGlvbiBvZiBtYXJrZG93bk1pc3NpbmcNCnN0cihzdG9yZURhdGEkbWFya2Rvd25NaXNzaW5nKQ0KDQojIFN0ZXAgNDogQ29udmVydCBtYXJrRG93bk1pc3NpbmcgdG8gRmFjdG9yDQpzdG9yZURhdGEkbWFya2Rvd25NaXNzaW5nID0gZmFjdG9yKHN0b3JlRGF0YSRtYXJrZG93bk1pc3NpbmcpDQoNCiMgU3RlcCA1OiBDaGVjayBTdHJ1Y3R1cmUgDQpzdHIoc3RvcmVEYXRhJG1hcmtkb3duTWlzc2luZykNCg0KDQpgYGANCg0KKipTdGVwIDI6IENyZWF0ZSBWYXJpYWJsZSBtYXJrZG93bk1pc3NpbmcgdXNpbmcgTXV0YXRlKio6IFVzaW5nIG11dGF0ZSB3ZSBjcmVhdGUgdGhlIG5ldyB2YXJpYWJsZSBtYXJrZG93bk1pc3Npbmcgd2hpY2ggdGFrZXMgb24gMSBpZiBNYXJrZG93bkFtbnQgaXMgbWlzc2luZyBhbmQgMCBpZiBNYXJrZG93bkFtbnQgaXMgbm90IG1pc3NpbmcuIA0KDQoNCioqU3RlcCAzOiBDaGVjayBDcmVhdGlvbiBvZiBtYXJrZG93bk1pc3NpbmcqKiA6IFdlIGNoZWNrIGlmIHRoZSBtYXJrZG93bk1pc3NpbmcgdmFyaWFibGUgaGFzIGJlZW4gY3JlYXRlZCBieSBjaGVja2luZyB0aGUgc3RydWN0dXJlIG9mIHRoZSBkYXRhLg0KDQoqKlN0ZXAgNDogQ29udmVydCBtYXJrRG93bk1pc3NpbmcgdG8gRmFjdG9yKio6IFRoZSBtYXJrZG93bk1pc3NpbmcgY2FuIHRha2Ugb24gb25seSB0d28gdmFsdWVzIDAgYW5kIDEuIEhlbmNlLCBpdCBpcyBjb252ZXJ0ZWQgdG8gYSBmYWN0b3IgZGF0YSB0eXBlLiANCg0KKipTdGVwIDU6IENoZWNrIFN0cnVjdHVyZSoqOiBXZSBjaGVjayBpZiB0aGUgY29udmVyc2lvbiBvZiBtYXJrZG93bk1pc3NpbmcgdG8gZGF0YSB0eXBlIGZhY3RvciBpcyBzdWNjZXNzZnVsLiBJdCBpcyBhIGZhY3RvciB3aXRoIHR3byBsZXZlbHMgMCBhbmQgMS4gDQoNCg0KDQoNCiMjCVNjYW4gSSANCg0KDQpgYGB7cn0NCiMgU3RlcCAxOiBDaGVja2luZyBmb3IgTWlzc2luZyBWYWx1ZXMgaW4gQWxsIFZhcmlhYmxlcw0KY29sU3Vtcyhpcy5uYShzdG9yZURhdGEpKQ0KDQojIFN0ZXAgMjogRmluZGluZyBNZWRpYW4gb2YgTWFya2Rvd25BbW50IA0KbWFya21lZGlhbiA9IG1lZGlhbihzdG9yZURhdGEkTWFya2Rvd25BbW50LG5hLnJtID0gVFJVRSkNCg0KIyBTdGVwIDM6IFJlcGxhY2luZyBNaXNzaW5nIFZhbHVlcyB3aXRoIE1lZGlhbg0Kc3RvcmVEYXRhJE1hcmtkb3duQW1udCA9ICByZXBsYWNlX25hKGRhdGEgPSBzdG9yZURhdGEkTWFya2Rvd25BbW50LHJlcGxhY2UgPSBtYXJrbWVkaWFuKQ0KDQojIFN0ZXAgNDogQ2hlY2sgUmVwbGFjZW1lbnQNCnN1bShpcy5uYShzdG9yZURhdGEkTWFya2Rvd25BbW50KSkNCg0KIyBTdGVwIDU6IFN1YnNldCBOdW1lcmljIFZhcmlhYmxlcw0KbnVtZXJpYyA9IHNlbGVjdF9pZihzdG9yZURhdGEsaXMubnVtZXJpYykNCg0KIyBTdGVwIDY6IFN1bW1hcnkgb2YgTnVtZXJpYyBWYXJpYWJsZXMNCnN1bW1hcnkobnVtZXJpYykNCg0KIyBTdGVwIDc6IFJlcGxhY2luZyBJbmNvbnNpc3RlbnQgVmFsdWUgaW4gV2Vla2x5X1NhbGVzDQpzdG9yZURhdGEgJT4lZmlsdGVyKFdlZWtseV9TYWxlcyA8IDApICU+JSBjb3VudCgpDQpzdG9yZURhdGEkV2Vla2x5X1NhbGVzID0gaWZlbHNlKHRlc3QgPSBzdG9yZURhdGEkV2Vla2x5X1NhbGVzIDwgMCx5ZXMgPSBOQSxubyA9IHN0b3JlRGF0YSRXZWVrbHlfU2FsZXMpDQoNCiMgU3RlcCA4OiBSZXBsYWNpbmcgSW5jb25zaXN0ZW50IFZhbHVlIGluIE1hcmtkb3duQW1udA0Kc3RvcmVEYXRhICU+JWZpbHRlcihNYXJrZG93bkFtbnQgPCAwKSAlPiUgY291bnQoKQ0Kc3RvcmVEYXRhJE1hcmtkb3duQW1udCA9IGlmZWxzZSh0ZXN0ID0gc3RvcmVEYXRhJE1hcmtkb3duQW1udCA8IDAseWVzID0gTkEsbm8gPSBzdG9yZURhdGEkTWFya2Rvd25BbW50KQ0KDQpgYGANCg0KKipTdGVwIDE6IENoZWNraW5nIGZvciBNaXNzaW5nIFZhbHVlcyBpbiBBbGwgVmFyaWFibGVzKio6IFdlIHVzZSBjb2xTdW1zIGFuZCBpcy5uYSB0byBjaGVjayBmb3IgbWlzc2luZyB2YWx1ZXMgaW4gdGhlIHZhcmlhYmxlcy4gVGhlcmUgYXJlIG9ubHkgdHdvIHZhcmlhYmxlcyB3aXRoIG1pc3NpbmcgdmFsdWVzLCB0aGUgc2l6ZURpc2MgdmFyaWFibGUgd2UgY3JlYXRlZCBmcm9tIHNpemUgd2hpY2ggaXMgYSBmYWN0b3IgdmFyaWFibGUsIGFuZCBNYXJrZG93bkFtbnQgd2hpY2ggaXMgbnVtZXJpYy4gRm9yIHNpemVEaXNjIHdlIGxlYXZlIHRoZSB1bmtub3duIHZhbHVlcyBhcyBOQSdzLiAgDQoNCioqU3RlcCAyOiBGaW5kaW5nIE1lZGlhbiBvZiBNYXJrZG93bkFtbnQqKjogRG8gZGVhbCByZXBsYWNlIG1pc3NpbmcgdmFsdWVzIGluIE1hcmtkb3duQW1udCB3ZSBmaW5kIHRoZSBtZWRpYW4gc28gdGhhdCB3ZSBjYW4gcmVwbGFjZSBtaXNzaW5nIHZhbHVlcyB3aXRoIGltcHV0ZWQgbWVkaWFuLiANCg0KKipTdGVwIDM6IFJlcGxhY2luZyBNaXNzaW5nIFZhbHVlcyB3aXRoIE1lZGlhbioqOiBXZSByZXBsYWNlIG1pc3NpbmcgdmFsdWVzIGluIE1hcmtkb3duQW1udCB3aXRoIHRoZSBtZWRpYW4gdmFsdWVzLiBUaGlzIGlzIGp1c3QgZG9uZSBmb3IgZGVtb25zdHJhdGlvbiBidXQgZm9yIHJlYWwgYW5hbHlzaXMgdGhpcyB3b3VsZCBub3QgYmUgZG9uZSBiZWNhdXNlIHRoZSB2YXJpYWJsZSBoYXMgdG9vIG1hbnkgbWlzc2luZyB2YWx1ZXMgYW5kIHJlcGxhY2luZyB3aXRoIG1lYW4gb3IgbWVkaWFuIGNoYW5nZXMgdGhlIGRpc3RyaWJ1dGlvbi4gDQoNCioqU3RlcCA0OiBDaGVjayBSZXBsYWNlbWVudCoqOiBXZSBjaGVjayByZXBsYWNlbWVudCBvZiB0aGUgbWlzc2luZyB2YWx1ZXMgaW4gdGhlIHZhcmlhYmxlIG1hcmtkb3duQW1udA0KDQoqKlN0ZXAgNSAmIDY6IFN1YnNldCAmIFN1bW1hcnkgb2YgTnVtZXJpYyBWYXJpYWJsZXMqKjogV2Ugc3Vic2V0IG9ubHkgdGhlIG51bWVyaWMgdmFyaWFibGVzIGFuZCBjaGVjayB0aGVpciBzdW1tYXJ5IHRvIGZpbmQgaWYgYW55IHZhcmlhYmxlcyBoYXZlIGluY29uc2lzdGVudCB2YWx1ZXMuIEJvdGggd2Vla2x5IFNhbGVzIGFuZCBtYXJrZG93bkFtbnQgaGFzIG5lZ2F0aXZlIHZhbHVlcyB3aGljaCB3ZSByZXBsYWNlLiANCg0KKipTdGVwIDcgJiA4OiBSZXBsYWNpbmcgSW5jb25zaXN0ZW50IFZhbHVlIGluIFdlZWtseV9TYWxlcyAmIG1hcmtEb3duQW1udCAqKjogVGhlIGluY29uc2lzdGVudCB2YWx1ZXMgb2YgbGVzcyB0aGFuIDAgaGF2ZSB0byBiZSByZXBsYWNlZCBpbiBib3RoIHRoZSB2YXJpYWJsZXMuIFdlIHNlZSB0aGF0IFdlZWtseSBTYWxlcyBoYXMgNjQyNSB2YWx1ZXMgYmVsb3cgMCBhbmQgbWFya0Rvd25BbW50IGhhcyAxNTY4IHN1Y2ggdmFsdWVzLiBXZSBjb3VsZCByZXBsYWNlIHdpdGggbWVhbiBvciBtZWRpYW4sIGJ1dCBkdWUgdG8gaGlnaCBubyBvZiBzdWNoIHZhbHVlcyB3ZSBqdXN0IHJlcGxhY2UgaXQgd2l0aCBOQS4gDQoNCg0KDQoNCiMjCVNjYW4gSUkNCg0KDQoNCmBgYHtyfQ0KIyBTdGVwIDE6IEZpbmRpbmcgVmFyaWFibGVzIHdpdGggT3V0bGllcnMNCmJ4MSA9IGJveHBsb3Qoc3RvcmVEYXRhJFdlZWtseV9TYWxlcyxtYWluID0gIkJveHBsb3Qgb2YgV2Vla2x5IFNhbGVzIikNCmJ4MiA9IGJveHBsb3Qoc3RvcmVEYXRhJFRlbXBlcmF0dXJlLG1haW4gPSAiQm94cGxvdCBvZiBUZW1wZXJhdHVyZSIpDQpieDMgPSBib3hwbG90KHN0b3JlRGF0YSRGdWVsX1ByaWNlLHN0b3JlRGF0YSRVbmVtcGxveW1lbnQsbWFpbiA9ICJCb3hwbG90IG9mIEZ1ZWwgUHJpY2UgJiBVbmVtcGxveW1lbnQiKQ0KYng0ID0gYm94cGxvdChzdG9yZURhdGEkQ1BJLG1haW4gPSAiQm94cGxvdCBvZiBDUEkiKQ0KDQojIFN0ZXAgMjogQ2FwcGluZyBPdXRsaWVyIGluIFdlZWtseSBTYWxlcw0Kc3RvcmVEYXRhJFdlZWtseV9TYWxlcyA9IGlmZWxzZSh0ZXN0ID0gc3RvcmVEYXRhJFdlZWtseV9TYWxlcyA+IGJ4MSRzdGF0c1s1XSx5ZXMgPSBieDEkc3RhdHNbNV0sbm8gPSBzdG9yZURhdGEkV2Vla2x5X1NhbGVzKQ0KDQojIFN0ZXAgMzogQ2FwcGluZyBPdXRsaWVyIGluIFRlbXBlcmF0dXJlDQpzdG9yZURhdGEkVGVtcGVyYXR1cmUgPSBpZmVsc2UodGVzdCA9IHN0b3JlRGF0YSRUZW1wZXJhdHVyZSA8IGJ4MiRzdGF0c1sxXSx5ZXMgPSBieDIkc3RhdHNbMV0sbm8gPSBzdG9yZURhdGEkVGVtcGVyYXR1cmUpDQoNCiNTdGVwIDQ6IENhcHBpbmcgT3V0bGllciBpbiBVbmVtcGxveW1lbnQNCiMgRm9yIGxvd2VyIG91dGxpZXJzDQpzdG9yZURhdGEkVW5lbXBsb3ltZW50ID0gaWZlbHNlKHRlc3QgPSBzdG9yZURhdGEkVW5lbXBsb3ltZW50IDwgYngzJHN0YXRzWzEsMl0seWVzID0gYngzJHN0YXRzWzEsMl0sbm8gPSBzdG9yZURhdGEkVW5lbXBsb3ltZW50KQ0KIyBGb3IgaGlnaGVyIG91dGxpZXJzDQpzdG9yZURhdGEkVW5lbXBsb3ltZW50ID0gaWZlbHNlKHRlc3QgPSBzdG9yZURhdGEkVW5lbXBsb3ltZW50ID4gYngzJHN0YXRzWzUsMl0seWVzID0gYngzJHN0YXRzWzUsMl0sbm8gPSBzdG9yZURhdGEkVW5lbXBsb3ltZW50KQ0KDQojIFN0ZXAgNTogQm94cGxvdCB0byBDaGVjayBDYXBwaW5nIA0KYm94cGxvdChzdG9yZURhdGEkV2Vla2x5X1NhbGVzLG1haW4gPSAiQm94cGxvdCBvZiBXZWVrbHkgU2FsZXMgYWZ0ZXIgQ2FwcGluZyIpDQpib3hwbG90KHN0b3JlRGF0YSRUZW1wZXJhdHVyZSxzdG9yZURhdGEkVW5lbXBsb3ltZW50LG1haW4gPSAiQm94cGxvdCBvZiBUZW1wZXJhdHVyZSBhbmQgVW5lbXBsb3ltZW50IGFmdGVyIENhcHBpbmciKQ0KDQpgYGANCioqKioNCg0KKipTdGVwIDE6IEZpbmRpbmcgVmFyaWFibGVzIHdpdGggT3V0bGllcnMqKjogV2UgcGxvdCB0aGUgYm94cGxvdCBvZiBudW1lcmljIHZhcmlhYmxlcyB0byBzZWUgaWYgdGhlcmUgYXJlIGFueSBvdXRsaWVycy4gT25seSBXZWVrbHlfU2FsZXMsIFRlbXBlcmF0dXJlIGFuZCBVbmVtcGxveW1lbnQgaGF2ZSBvdXRsaWVycy4gQ1BJIGFuZCBGdWVsIHByaWNlIHZhcmlhYmxlIGRvIG5vdCBoYXZlIG91dGxpZXJzLiAgIA0KV2Vla2x5IFNhbGVzIGhhcyBvdXRsaWVycyBvbiB0aGUgaGlnaGVyIHNpZGUsIHRlbXBlcmF0dXJlIG9uIHRoZSBsb3dlciBzaWRlIGFuZCBVbmVtcGxveW1lbnQgYm90aCBvbiB0aGUgaGlnaGVyIHNpZGUgYW5kIGxvd2VyIHNpZGUuIFdlIGZpbmQgdGhlIG1pbmltdW0gYW5kIG1heGltdW0gdmFsdWUgZnJvbSB0aGUgYm94cGxvdCB3aGljaCBhcmUgbm90IG91dGxpZXJzIGZvciB0aGUgdmFyaWFibGVzIFdlZWtseSBTYWxlcyAsIFRlbXBlcmF0dXJlIGFuZCBVbmVtcGxveW1lbnQuIFRoZXNlIHJlcHJlc2VudCB0aGUgd2hpc2tlcnMgYXQgdGhlIHRvcCBhbmQgYm90dG9tIG9mIHRoZSBib3hwbG90LiBXZSBmaW5kIHRoaXMgaW4gc3RhdHMgb2YgdGhlIGJveHBsb3Qgb2JqZWN0LiBXZSB1c2UgdGhlc2UgbWluIGFuZCBtYXggdmFsdWVzIGZvciBjYXBwaW5nIG91dGxpZXJzLiANCg0KKipTdGVwIDI6IENhcHBpbmcgT3V0bGllciBpbiBXZWVrbHkgU2FsZXMqKiA6IFdlIGNhcCB0aGUgb3V0bGllcnMgb2YgdGhlIHZhcmlhYmxlIFdlZWtseSBTYWxlcyB0byB0aGUgbWF4IHZhbHVlIGZyb20gYm94cGxvdCB3aGljaCBpcyBub3QgYW4gb3V0bGllci4gDQoNCg0KKipTdGVwIDM6IENhcHBpbmcgT3V0bGllciBpbiBUZW1wZXJhdHVyZSoqIDogVGhlIHRlbXBlcmF0dXJlIHZhcmlhYmxlIGhhcyBvdXRsaWVyIG9uIHRoZSBsb3dlciBzaWRlLiBXZSBjYXAgdGhlc2Ugb3V0bGllcnMgdG8gdGhlIG1pbiB2YWx1ZSBmcm9tIGJveHBsb3Qgd2hpY2ggaXMgbm90IGFuIG91dGxpZXIuIA0KDQoqKlN0ZXAgNDogQ2FwcGluZyBPdXRsaWVyIGluIFVuZW1wbG95bWVudCoqOiBVbmVtcGxveW1lbnQgaGFzIG91dGxpZXJzIGJvdGggYXQgdGhlIGhpZ2hlciBhbmQgbG93ZXIgZW5kLiBXZSBjYXAgaGlnaGVyIG91dGxpZXJzIHRvIHRoZSBtYXggdmFsdWUgZnJvbSBib3hwbG90IHdoaWNoIGlzIG5vdCBhbiBvdXRsaWVyIGFuZCBzaW1pbGFybHkgbG93ZXIgb3V0bGllcnMgYXJlIGNhcHBlZCB0byB0aGUgbG93ZXIgdmFsdWUgZnJvbSBib3hwbG90IHdoaWNoIGlzIG5vdCBhbiBvdXRsaWVyLiANCg0KKipTdGVwIDU6IEJveHBsb3QgdG8gQ2hlY2sgQ2FwcGluZyoqOiBXZSBwbG90IHRoZSBib3hwbG90IG9mIHRoZSB0aHJlZSB2YXJpYWJsZXMgYWdhaW4gdG8gY2hlY2sgY2FwcGluZy4gVGhlcmUgYXJlIG5vIG91dGxpZXJzIHByZXNlbnQuIA0KDQoNCg0KIyMJVHJhbnNmb3JtIA0KDQoNCmBgYHtyfQ0KIyBTdGVwIDE6IENoZWNraW5nIERpc3RyaWJ1dGlvbiBvZiBWYXJpYWJsZSBVbmVtcGxveW1lbnQNCmhpc3Qoc3RvcmVEYXRhJFVuZW1wbG95bWVudCxtYWluID0gIkhpc3RvZ3JhbSBvZiBVbmVtcGxveW1lbnQiLHhsYWIgPSAiVW5lbXBsb3ltZW50IikNCg0KIyBTdGVwIDI6IENyZWF0aW5nIFNxciAmIEN1YmUgRGF0YQ0KdW5lbWxveS5zcXIgPSBzdG9yZURhdGEkVW5lbXBsb3ltZW50XjINCnVuZW1wbG95LmN1YmUgPSBzdG9yZURhdGEkVW5lbXBsb3ltZW50XjMNCg0KIyBTdGVwIDM6IFBsb3R0aW5nIGhpc3RvZ3JhbSBvZiBUcmFuc2Zvcm1lZCBEYXRhDQpoaXN0KHVuZW1sb3kuc3FyLG1haW4gPSAiSGlzdG9ncmFtIG9mIFNxdWFyZWQgVW5lbXBsb3ltZW50Iix4bGFiID0gIlVuZW1wbG95bWVudCIpDQpoaXN0KHVuZW1wbG95LmN1YmUsbWFpbiA9ICJIaXN0b2dyYW0gb2YgVW5lbXBsb3ltZW50IFJhaXNlZCB0byAzIix4bGFiID0gIlVuZW1wbG95bWVudCIpDQoNCiMgU3RlcCA0OiBUcmFuc2Zvcm1pbmcgdGhlIFVuZW1wbG95bWVudCBWYXJpYWJsZSBpbiBEYXRhc2V0DQpzdG9yZURhdGEgPSBzdG9yZURhdGEgJT4lIG11dGF0ZSh1bmVtcGxveW1lbnRUcmFucyA9IFVuZW1wbG95bWVudF4yKQ0KDQpgYGANCg0KDQoqKlN0ZXAgMTogQ2hlY2tpbmcgRGlzdHJpYnV0aW9uIG9mIFZhcmlhYmxlIFVuZW1wbG95bWVudCoqOiBUaGUgdmFyaWFibGUgVW5lbXBsb3ltZW50IG5lZWRzIHRvIGJlIHRyYW5zZm9ybWVkIHRvIHJlZHVjZSBza2V3bmVzcyBhbmQgbWFrZSBpdCBhcHByb3hpbWF0ZWx5IG5vcm1hbC4gSW4gdGhpcyBzdGVwIHdlIGNoZWNrIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIHZhcmlhYmxlLiBXZSBzZWUgdGhhdCB0aGUgdmFyaWFibGUgaXMgc2xpZ2h0bHkgbGVmdCBza2V3ZWQuIA0KDQoqKlN0ZXAgMjogQ3JlYXRpbmcgU3FyICYgQ3ViZSBEYXRhKio6IEZyb20gdGhlIHByZXZpb3VzIHN0ZXAgd2Uga25vdyB0aGVyZSBpcyBzbGlnaHRseSBsZWZ0IHNrZXcuIEZvciBsZWZ0IHNrZXdlZCBkYXRhLCBwb3dlciBvZiAyLDMgZXRjIHdvcmsgd2VsbCBmb3IgcmVkdWNpbmcgc2tld25lc3MuIEhlcmUgd2UgY3JlYXRlIHRoZSBzcXVhcmUgYW5kIGN1YmUgb2YgZGF0YS4gDQoNCg0KKipTdGVwIDM6IFBsb3R0aW5nIGhpc3RvZ3JhbSBvZiBUcmFuc2Zvcm1lZCBEYXRhKio6IFdlIHBsb3QgdGhlIGhpc3RvZ3JhbSBvZiB0aGUgdHJhbnNmb3JtZWQgZGF0YSB0byBzZWUgaWYgdGhlcmUgaXMgYSBjaGFuZ2UgaW4gdGhlIGRpc3RyaWJ1dGlvbi4gDQoNCg0KKipTdGVwIDQ6IFRyYW5zZm9ybWluZyB0aGUgVW5lbXBsb3ltZW50IFZhcmlhYmxlIGluIERhdGFzZXQqKjogRnJvbSB0aGUgcGxvdCBvZiB0cmFuc2Zvcm1lZCBkYXRhIHdlIHNlZSB0aGF0IHRoZSBzcXVhcmUgdHJhbnNmb3JtdGlvbiB3b3JrcyBiZXN0LiBIZXJlIHdlIG11dGF0ZSB0aGUgVW5lbXBsb3ltZW50IHZhcmlhYmxlIGluIHRoZSBkYXRhIHRvIGNyZWF0ZSB0aGUgbmV3IHZhcmlhYmxlIHVuZW1wbG95bWVudFRyYW5zIHdoaWNoIGNvbnRhaW5zIHRoZSBzcXVhcmVkIGRhdGEuIA0KDQo8YnI+DQo8YnI+DQo=