Required packages

library("readr")
library("magrittr")
library("dplyr")
library("forecast")

Executive Summary

Please find below the list of actions taken as part of this assignment:

Data

A clear description of data sets, their sources, and variable descriptions should be provided. In this section, you must also provide the R codes with outputs (head of data sets) that you used to import/read/scrape the data set. You need to fulfil the minimum requirement #1 and merge at least two data sets to create the one you are going to work on. In addition to the R codes and outputs, you need to explain the steps that you have taken.

The data has been taken from metadata located at https://www.kaggle.com/donorschoose/io, we have considered the datasets Donations and Projects from the metadata for performing pre-processing activities. We are using the following columns for this assignment:

donations <- read_csv("Donations.csv") %>% as.data.frame()
projects <- read_csv("Projects.csv") %>% as.data.frame()

par(mfcol=c(1,2))
head(donations)
head(projects)

Selecting necessary columns for pre-processing from Projects and Donations dataset

projects <- within(projects,rm("School ID","Teacher ID","Project Essay","Project Short Description",
                               "Project Need Statement","Project Subject Category Tree","Project Subject Subcategory Tree",
                               "Teacher Project Posted Sequence"))
donations <- within (donations,rm("Donor ID","Donor Cart Sequence"))

Merged donations and projects using left merge and named the new data set as project_donations

project_donations <- merge(donations,projects,"Project ID",all.x=T)

Took a subset of first 10000 records from this dataset and named it as project_donations_final

project_donations_final <- project_donations[1:10000,]
head(project_donations_final)

Understand

From the output of structure below, we have idenified that columns Donation Included Optional Donation,Project Type,Project Grade Level Category,Project Resource Category,Project Current Status are supposed to be as factors and ’Donation Received Date` is supposed to be a date

str(project_donations_final)
'data.frame':   10000 obs. of  14 variables:
 $ Project ID                         : chr  "000009891526c0ade7180f8423792063" "000009891526c0ade7180f8423792063" "000009891526c0ade7180f8423792063" "000009891526c0ade7180f8423792063" ...
 $ Donation ID                        : chr  "38d2744bf9138b0b57ed581c76c0e2da" "dcf1071da3aa3561f91ac689d1f73dee" "688729120858666221208529ee3fc18e" "8cea27f0cc03f41f66aab96b284ae6a1" ...
 $ Donation Included Optional Donation: chr  "Yes" "Yes" "No" "Yes" ...
 $ Donation Amount                    : num  25 25 178 15 25 ...
 $ Donation Received Date             : POSIXct, format: "2016-05-15 10:23:04" "2016-06-06 20:05:23" "2016-08-23 13:15:57" "2016-06-04 17:58:55" ...
 $ Project Type                       : chr  "Teacher-Led" "Teacher-Led" "Teacher-Led" "Teacher-Led" ...
 $ Project Title                      : chr  "OHMS Musician Chair Cart" "OHMS Musician Chair Cart" "OHMS Musician Chair Cart" "OHMS Musician Chair Cart" ...
 $ Project Grade Level Category       : chr  "Grades 6-8" "Grades 6-8" "Grades 6-8" "Grades 6-8" ...
 $ Project Resource Category          : chr  "Other" "Other" "Other" "Other" ...
 $ Project Cost                       : num  530 530 530 530 530 ...
 $ Project Posted Date                : Date, format: "2016-05-13" "2016-05-13" "2016-05-13" "2016-05-13" ...
 $ Project Expiration Date            : Date, format: "2016-09-12" "2016-09-12" "2016-09-12" "2016-09-12" ...
 $ Project Current Status             : chr  "Fully Funded" "Fully Funded" "Fully Funded" "Fully Funded" ...
 $ Project Fully Funded Date          : Date, format: "2016-08-23" "2016-08-23" "2016-08-23" "2016-08-23" ...

To identify the levels of all the factor columns we have used the distinct function as shown below

project_donations_final %>% distinct(`Donation Included Optional Donation`)
project_donations_final %>% distinct(`Project Type`)
project_donations_final %>% distinct(`Project Grade Level Category`)
project_donations_final %>% distinct(`Project Resource Category`)
project_donations_final %>% distinct(`Project Current Status`)

As we can see that there are missing values in the above columns, we have replaced the missing values as ‘Others’

project_donations_final$`Project Type`[is.na(project_donations_final$`Project Type`)] <- "Other"
project_donations_final$`Project Resource Category`[is.na(project_donations_final$`Project Resource Category`)] <- "Other"
project_donations_final$`Project Current Status`[is.na(project_donations_final$`Project Current Status`)] <- "Other"
project_donations_final$`Project Grade Level Category`[is.na(project_donations_final$`Project Grade Level Category`)] <- "Other"

As noted below, we have replaced the NA values as ‘Others’

project_donations_final %>% distinct(`Donation Included Optional Donation`)
project_donations_final %>% distinct(`Project Type`)
project_donations_final %>% distinct(`Project Grade Level Category`)
project_donations_final %>% distinct(`Project Resource Category`)
project_donations_final %>% distinct(`Project Current Status`)

All the columns have been factorised

project_donations_final$`Donation Included Optional Donation` <- project_donations_final$`Donation Included Optional Donation` %>% factor(levels = c("Yes","No"))
project_donations_final$`Project Type` <- project_donations_final$`Project Type` %>%
  factor(levels = c("Teacher-Led","Other","Professional Development","Student-Led"))
project_donations_final$`Project Grade Level Category` <- project_donations_final$`Project Grade Level Category` %>%
  factor(levels = c("Grades 6-8","Grades PreK-2","Grades 3-5","Grades 9-12","Other"))
project_donations_final$`Project Resource Category` <- project_donations_final$`Project Resource Category` %>% factor(levels = c("Other","Technology","Supplies","Books","Classroom Basics","Art Supplies","Musical Instruments","Computers & Tablets","Instructional Technology","Trips","Lab Equipment","Flexible Seating","Educational Kits & Games","Food, Clothing & Hygiene","Reading Nooks, Desks & Storage","Sports & Exercise Equipment","Visitors"))
project_donations_final$`Project Current Status`<- project_donations_final$`Project Current Status` %>% factor(levels = c("Fully Funded","Live","Expired","Other"),ordered = T)

Converting donation received date attribute as date

project_donations_final$`Donation Received Date` <- as.Date(project_donations_final$`Donation Received Date`)

As per below output, we can see that the necessary data type conversions have been done

str(project_donations_final)
'data.frame':   10000 obs. of  14 variables:
 $ Project ID                         : chr  "000009891526c0ade7180f8423792063" "000009891526c0ade7180f8423792063" "000009891526c0ade7180f8423792063" "000009891526c0ade7180f8423792063" ...
 $ Donation ID                        : chr  "38d2744bf9138b0b57ed581c76c0e2da" "dcf1071da3aa3561f91ac689d1f73dee" "688729120858666221208529ee3fc18e" "8cea27f0cc03f41f66aab96b284ae6a1" ...
 $ Donation Included Optional Donation: Factor w/ 2 levels "Yes","No": 1 1 2 1 1 1 1 1 1 1 ...
 $ Donation Amount                    : num  25 25 178 15 25 ...
 $ Donation Received Date             : Date, format: "2016-05-15" "2016-06-06" "2016-08-23" "2016-06-04" ...
 $ Project Type                       : Factor w/ 4 levels "Teacher-Led",..: 1 1 1 1 1 1 1 1 1 1 ...
 $ Project Title                      : chr  "OHMS Musician Chair Cart" "OHMS Musician Chair Cart" "OHMS Musician Chair Cart" "OHMS Musician Chair Cart" ...
 $ Project Grade Level Category       : Factor w/ 5 levels "Grades 6-8","Grades PreK-2",..: 1 1 1 1 1 1 1 1 1 1 ...
 $ Project Resource Category          : Factor w/ 17 levels "Other","Technology",..: 1 1 1 1 1 1 2 2 2 2 ...
 $ Project Cost                       : num  530 530 530 530 530 ...
 $ Project Posted Date                : Date, format: "2016-05-13" "2016-05-13" "2016-05-13" "2016-05-13" ...
 $ Project Expiration Date            : Date, format: "2016-09-12" "2016-09-12" "2016-09-12" "2016-09-12" ...
 $ Project Current Status             : Ord.factor w/ 4 levels "Fully Funded"<..: 1 1 1 1 1 1 1 1 1 1 ...
 $ Project Fully Funded Date          : Date, format: "2016-08-23" "2016-08-23" "2016-08-23" "2016-08-23" ...

Tidy & Manipulate Data I

Our data is in tidy format. Hence, no action taken.

Tidy & Manipulate Data II

Created a new data frame with total donated amounts grouped by project titles and named it as donation_by_title

donation_by_title <- aggregate(project_donations_final$`Donation Amount`,list(project_donations_final$`Project Title`),sum)
donation_by_title %>% as.data.frame()

Renamed the column name of donation by title dataframe

colnames(donation_by_title) <- c("Project Title","Total Project donated amount")
head(donation_by_title)

Joined this data frame onto project_donation_final data frame by using left merge

project_donations_final <- merge(project_donations_final,donation_by_title,"Project Title",all.x=T)

Mutated the project donations final data frame by creating a new column called project_funding_balance

project_donations_final <- mutate(project_donations_final,Project_funding_balance= project_donations_final$`Project Cost`-project_donations_final$`Total Project donated amount`)
head(project_donations_final)

Scan I

In the context of this dataset, removing the missing values was appropriate. Hence we used the na.omit function to remove the missing values

project_donations_final <- na.omit(project_donations_final)

All the missing values have been removed as per below

sum(is.na(project_donations_final))
[1] 0

Scan II

As per the boxplot there are outliers in project funding balance which will be dealt with in the next step

boxplot(project_donations_final$Project_funding_balance,ylab="Amount",main="Pending Fund Balance boxplot before Removing Outliers")

Cap function has been created to identify and update the outliers to the nearest quartile

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}

Outliers for project funding attribute have been dealt with using capping

project_donations_final$Project_funding_balance <- project_donations_final$Project_funding_balance %>% cap()

Boxplot after dealing with the outliers

boxplot(project_donations_final$Project_funding_balance,ylab="Amount",main="Pending Fund Balance boxplot after Removing Outliers")

Transform

Histogram of total project donated amount before transformation (data is not normalised)

hist(project_donations_final$`Total Project donated amount`,main = "Total amount donated to projects",xlab = "Amount donated")

Applying boxcox transformation on project amount donated

boxcox_tot_don_amt <- BoxCox(project_donations_final$`Total Project donated amount`,lambda = "auto") 

Histogram after transformation (data is normalised)

hist(boxcox_tot_don_amt,main = "Donation amount after transformation",xlab = "Amount donated")



LS0tDQp0aXRsZTogIk1BVEgyMzQ5IFNlbWVzdGVyIDIsIDIwMTgiDQphdXRob3I6ICJTYXJhdGggQ2hhbmRyYSBLIChzMzcwNDAwOSksIE1vaGFtbWVkIE11amVlciAoczM3NDA1ODcpLCBVbWFpciBIYXNobWkoczM2OTk1NzEpIg0Kc3VidGl0bGU6IEFzc2lnbm1lbnQgMw0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOiBkZWZhdWx0DQogIHBkZl9kb2N1bWVudDogZGVmYXVsdA0KICBodG1sX2RvY3VtZW50Og0KICAgIGRmX3ByaW50OiBwYWdlZA0KLS0tDQoNCiMjIFJlcXVpcmVkIHBhY2thZ2VzIA0KDQoNCmBgYHtyfQ0KbGlicmFyeSgicmVhZHIiKQ0KbGlicmFyeSgibWFncml0dHIiKQ0KbGlicmFyeSgiZHBseXIiKQ0KbGlicmFyeSgiZm9yZWNhc3QiKQ0KYGBgDQoNCg0KIyMgRXhlY3V0aXZlIFN1bW1hcnkgDQoNClBsZWFzZSBmaW5kIGJlbG93IHRoZSBsaXN0IG9mIGFjdGlvbnMgdGFrZW4gYXMgcGFydCBvZiB0aGlzIGFzc2lnbm1lbnQ6DQoNCiogUHJvamVjdHMgYW5kIERvbmF0aW9ucyBkYXRhc2V0cyBhcmUgbWVyZ2VkIG9uIFByb2plY3QgSUQgY29sdW1uLg0KKiBTdWJzZXQgb2YgZmlyc3QgMTAwMDAgcmVjb3JkcyBmcm9tIHRoaXMgZGF0YXNldCB3YXMgdGFrZW4gdG8gcGVyZm9ybSBwcmVwcm9jZXNzaW5nLiANCiogRGF0YSBzdHJ1Y3R1cmUgaXMgY2hlY2tlZCBhbmQgdGhlbiB0aGUgZGF0YSB0eXBlIHdlcmUgY2hhbmdlZCBhcyBwZXIgdGhlIGNvbnRleHQgb2YgdGhlIGRhdGEuIA0KKiBDaGVja2VkIGlmIHRoZXJlIGFyZSBhbnkgbWlzc2luZyB2YWx1ZXMgYW5kIHJlcGxhY2VkIHRoZW0gYWNjb3JkaW5nbHkuIA0KKiBSZXF1aXJlZCBjb2x1bW5zIHdlcmUgZmFjdG9yaXNlZCBhbmQgdGhlIG5lY2Vzc2FyeSBkYXRhIHR5cGUgY29udmVyc2lvbnMgaGF2ZSBiZWVuIGRvbmUuIA0KKiBEYXRhIHdhcyBpbiBhIHRpZHkgZm9ybWF0IGhlbmNlIG5vIGFjdGlvbnMgd2VyZSBwZXJmb3JtZWQuIA0KKiBOZXcgY29sdW1ucyB3ZXJlIG11dGF0ZWQgaW4gdGhlIGRhdGEgZnJhbWUuDQoqIE1pc3NpbmcgdmFsdWVzIHdlcmUgcmVtb3ZlZCB1c2luZyBuYS5vbWl0IGZ1bmN0aW9uLiANCiogVGhlcmUgd2VyZSBvdXRsaWVycyBpbiBwcm9qZWN0IGZ1bmRpbmcgYmFsYW5jZSB3aGljaCB3ZXJlIGRlYWx0IHdpdGggdXNpbmcgY2FwcGluZywgYWZ0ZXIgd2hpY2ggdGhlIHJlc3VsdHMgd2VyZSBzaG93biBpbiBhIGJveHBsb3QuIA0KKiBIaXN0b2dyYW0gb2YgdW5ub3JtYWxpc2VkIGRhdGEgdG90YWwgcHJvamVjdCBkb25hdGVkIGFtb3VudCB3YXMgc2hvd24gYmVmb3JlIGFwcGx5aW5nIHRoZSB0cmFuc2Zvcm1hdGlvbi4gV2UgdXNlZCBib3hjb3ggdHJhbnNmb3JtYXRpb24gb24gcHJvamVjdCBhbW91bnQgZG9uYXRlZCBhbmQgc2hvd2VkIHRoZSBub3JtYWxpc2F0aW9uIHVzaW5nIGhpc3RvZ3JhbS4NCg0KDQojIyBEYXRhIA0KDQpBIGNsZWFyIGRlc2NyaXB0aW9uIG9mIGRhdGEgc2V0cywgdGhlaXIgc291cmNlcywgYW5kIHZhcmlhYmxlIGRlc2NyaXB0aW9ucyBzaG91bGQgYmUgcHJvdmlkZWQuIEluIHRoaXMgc2VjdGlvbiwgeW91IG11c3QgYWxzbyBwcm92aWRlIHRoZSBSIGNvZGVzIHdpdGggb3V0cHV0cyAoaGVhZCBvZiBkYXRhIHNldHMpIHRoYXQgeW91IHVzZWQgdG8gaW1wb3J0L3JlYWQvc2NyYXBlIHRoZSBkYXRhIHNldC4gWW91IG5lZWQgdG8gZnVsZmlsIHRoZSBtaW5pbXVtIHJlcXVpcmVtZW50ICMxIGFuZCBtZXJnZSBhdCBsZWFzdCB0d28gZGF0YSBzZXRzIHRvIGNyZWF0ZSB0aGUgb25lIHlvdSBhcmUgZ29pbmcgdG8gd29yayBvbi4gSW4gYWRkaXRpb24gdG8gdGhlIFIgY29kZXMgYW5kIG91dHB1dHMsIHlvdSBuZWVkIHRvIGV4cGxhaW4gdGhlIHN0ZXBzIHRoYXQgeW91IGhhdmUgdGFrZW4uDQoNClRoZSBkYXRhIGhhcyBiZWVuIHRha2VuIGZyb20gbWV0YWRhdGEgbG9jYXRlZCBhdCBodHRwczovL3d3dy5rYWdnbGUuY29tL2Rvbm9yc2Nob29zZS9pbywgd2UgaGF2ZSBjb25zaWRlcmVkIHRoZSBkYXRhc2V0cyBEb25hdGlvbnMgYW5kIFByb2plY3RzIGZyb20gdGhlIG1ldGFkYXRhIGZvciBwZXJmb3JtaW5nIHByZS1wcm9jZXNzaW5nIGFjdGl2aXRpZXMuIFdlIGFyZSB1c2luZyB0aGUgZm9sbG93aW5nIGNvbHVtbnMgZm9yIHRoaXMgYXNzaWdubWVudDoNCg0KKiBQcm9qZWN0IElEIChjaHIpDQoqIERvbmF0aW9uIElEKGNocikNCiogRG9uYXRpb24gSW5jbHVkZWQgT3B0aW9uYWwgRG9uYXRpb24oZmFjdG9yKQ0KKiBEb25hdGlvbiBBbW91bnQgKG51bSkNCiogRG9uYXRpb24gUmVjZWl2ZWQgRGF0ZShEYXRlKQ0KKiBQcm9qZWN0IFR5cGUoZmFjdG9yKQ0KKiBQcm9qZWN0IFRpdGxlIChjaHIpDQoqIFByb2plY3QgR3JhZGUgTGV2ZWwgQ2F0ZWdvcnkgKGZhY3RvcikNCiogUHJvamVjdCBSZXNvdXJjZSBDYXRlZ29yeShmYWN0b3IpDQoqIFByb2plY3QgQ29zdCAobnVtKQ0KKiBQcm9qZWN0IFBvc3RlZCBEYXRlIChEYXRlKQ0KKiBQcm9qZWN0IEV4cGlyYXRpb24gRGF0ZSAoRGF0ZSkNCiogUHJvamVjdCBDdXJyZW50IFN0YXR1cyggT3JkIEZhY3RvcikNCiogUHJvamVjdCBGdWxseSBGdW5kZWQgRGF0ZSAoRGF0ZSkNCg0KDQpgYGB7cn0NCmRvbmF0aW9ucyA8LSByZWFkX2NzdigiRG9uYXRpb25zLmNzdiIpICU+JSBhcy5kYXRhLmZyYW1lKCkNCnByb2plY3RzIDwtIHJlYWRfY3N2KCJQcm9qZWN0cy5jc3YiKSAlPiUgYXMuZGF0YS5mcmFtZSgpDQoNCnBhcihtZmNvbD1jKDEsMikpDQpoZWFkKGRvbmF0aW9ucykNCmhlYWQocHJvamVjdHMpDQoNCmBgYA0KDQpTZWxlY3RpbmcgbmVjZXNzYXJ5IGNvbHVtbnMgZm9yIHByZS1wcm9jZXNzaW5nIGZyb20gUHJvamVjdHMgYW5kIERvbmF0aW9ucyBkYXRhc2V0DQpgYGB7cn0NCnByb2plY3RzIDwtIHdpdGhpbihwcm9qZWN0cyxybSgiU2Nob29sIElEIiwiVGVhY2hlciBJRCIsIlByb2plY3QgRXNzYXkiLCJQcm9qZWN0IFNob3J0IERlc2NyaXB0aW9uIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUHJvamVjdCBOZWVkIFN0YXRlbWVudCIsIlByb2plY3QgU3ViamVjdCBDYXRlZ29yeSBUcmVlIiwiUHJvamVjdCBTdWJqZWN0IFN1YmNhdGVnb3J5IFRyZWUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUZWFjaGVyIFByb2plY3QgUG9zdGVkIFNlcXVlbmNlIikpDQoNCmRvbmF0aW9ucyA8LSB3aXRoaW4gKGRvbmF0aW9ucyxybSgiRG9ub3IgSUQiLCJEb25vciBDYXJ0IFNlcXVlbmNlIikpDQpgYGANCg0KTWVyZ2VkIGRvbmF0aW9ucyBhbmQgcHJvamVjdHMgdXNpbmcgbGVmdCBtZXJnZSBhbmQgbmFtZWQgdGhlIG5ldyBkYXRhIHNldCBhcyBwcm9qZWN0X2RvbmF0aW9ucw0KYGBge3J9DQpwcm9qZWN0X2RvbmF0aW9ucyA8LSBtZXJnZShkb25hdGlvbnMscHJvamVjdHMsIlByb2plY3QgSUQiLGFsbC54PVQpDQoNCmBgYA0KDQpUb29rIGEgc3Vic2V0IG9mIGZpcnN0IDEwMDAwIHJlY29yZHMgZnJvbSB0aGlzIGRhdGFzZXQgYW5kIG5hbWVkIGl0IGFzIHByb2plY3RfZG9uYXRpb25zX2ZpbmFsDQpgYGB7cn0NCnByb2plY3RfZG9uYXRpb25zX2ZpbmFsIDwtIHByb2plY3RfZG9uYXRpb25zWzE6MTAwMDAsXQ0KaGVhZChwcm9qZWN0X2RvbmF0aW9uc19maW5hbCkNCmBgYA0KDQoNCiMjIFVuZGVyc3RhbmQgDQoNCkZyb20gdGhlIG91dHB1dCBvZiBzdHJ1Y3R1cmUgYmVsb3csIHdlIGhhdmUgaWRlbmlmaWVkIHRoYXQgY29sdW1ucyBgRG9uYXRpb24gSW5jbHVkZWQgT3B0aW9uYWwgRG9uYXRpb25gLGBQcm9qZWN0IFR5cGVgLGBQcm9qZWN0IEdyYWRlIExldmVsIENhdGVnb3J5YCxgUHJvamVjdCBSZXNvdXJjZSBDYXRlZ29yeWAsYFByb2plY3QgQ3VycmVudCBTdGF0dXNgIGFyZSBzdXBwb3NlZCB0byBiZSBhcyBmYWN0b3JzIGFuZCAnRG9uYXRpb24gUmVjZWl2ZWQgRGF0ZWAgaXMgc3VwcG9zZWQgdG8gYmUgYSBkYXRlIA0KYGBge3J9DQpzdHIocHJvamVjdF9kb25hdGlvbnNfZmluYWwpDQoNCmBgYA0KDQpUbyBpZGVudGlmeSB0aGUgbGV2ZWxzIG9mIGFsbCB0aGUgZmFjdG9yIGNvbHVtbnMgd2UgaGF2ZSB1c2VkIHRoZSBkaXN0aW5jdCBmdW5jdGlvbiBhcyBzaG93biBiZWxvdw0KYGBge3J9DQpwcm9qZWN0X2RvbmF0aW9uc19maW5hbCAlPiUgZGlzdGluY3QoYERvbmF0aW9uIEluY2x1ZGVkIE9wdGlvbmFsIERvbmF0aW9uYCkNCnByb2plY3RfZG9uYXRpb25zX2ZpbmFsICU+JSBkaXN0aW5jdChgUHJvamVjdCBUeXBlYCkNCnByb2plY3RfZG9uYXRpb25zX2ZpbmFsICU+JSBkaXN0aW5jdChgUHJvamVjdCBHcmFkZSBMZXZlbCBDYXRlZ29yeWApDQpwcm9qZWN0X2RvbmF0aW9uc19maW5hbCAlPiUgZGlzdGluY3QoYFByb2plY3QgUmVzb3VyY2UgQ2F0ZWdvcnlgKQ0KcHJvamVjdF9kb25hdGlvbnNfZmluYWwgJT4lIGRpc3RpbmN0KGBQcm9qZWN0IEN1cnJlbnQgU3RhdHVzYCkNCg0KYGBgDQoNCkFzIHdlIGNhbiBzZWUgdGhhdCB0aGVyZSBhcmUgbWlzc2luZyB2YWx1ZXMgaW4gdGhlIGFib3ZlIGNvbHVtbnMsIHdlIGhhdmUgcmVwbGFjZWQgdGhlIG1pc3NpbmcgdmFsdWVzIGFzICdPdGhlcnMnDQpgYGB7cn0NCnByb2plY3RfZG9uYXRpb25zX2ZpbmFsJGBQcm9qZWN0IFR5cGVgW2lzLm5hKHByb2plY3RfZG9uYXRpb25zX2ZpbmFsJGBQcm9qZWN0IFR5cGVgKV0gPC0gIk90aGVyIg0KDQpwcm9qZWN0X2RvbmF0aW9uc19maW5hbCRgUHJvamVjdCBSZXNvdXJjZSBDYXRlZ29yeWBbaXMubmEocHJvamVjdF9kb25hdGlvbnNfZmluYWwkYFByb2plY3QgUmVzb3VyY2UgQ2F0ZWdvcnlgKV0gPC0gIk90aGVyIg0KDQpwcm9qZWN0X2RvbmF0aW9uc19maW5hbCRgUHJvamVjdCBDdXJyZW50IFN0YXR1c2BbaXMubmEocHJvamVjdF9kb25hdGlvbnNfZmluYWwkYFByb2plY3QgQ3VycmVudCBTdGF0dXNgKV0gPC0gIk90aGVyIg0KDQpwcm9qZWN0X2RvbmF0aW9uc19maW5hbCRgUHJvamVjdCBHcmFkZSBMZXZlbCBDYXRlZ29yeWBbaXMubmEocHJvamVjdF9kb25hdGlvbnNfZmluYWwkYFByb2plY3QgR3JhZGUgTGV2ZWwgQ2F0ZWdvcnlgKV0gPC0gIk90aGVyIg0KYGBgDQoNCkFzIG5vdGVkIGJlbG93LCB3ZSBoYXZlIHJlcGxhY2VkIHRoZSBOQSB2YWx1ZXMgYXMgJ090aGVycycNCmBgYHtyfQ0KcHJvamVjdF9kb25hdGlvbnNfZmluYWwgJT4lIGRpc3RpbmN0KGBEb25hdGlvbiBJbmNsdWRlZCBPcHRpb25hbCBEb25hdGlvbmApDQpwcm9qZWN0X2RvbmF0aW9uc19maW5hbCAlPiUgZGlzdGluY3QoYFByb2plY3QgVHlwZWApDQpwcm9qZWN0X2RvbmF0aW9uc19maW5hbCAlPiUgZGlzdGluY3QoYFByb2plY3QgR3JhZGUgTGV2ZWwgQ2F0ZWdvcnlgKQ0KcHJvamVjdF9kb25hdGlvbnNfZmluYWwgJT4lIGRpc3RpbmN0KGBQcm9qZWN0IFJlc291cmNlIENhdGVnb3J5YCkNCnByb2plY3RfZG9uYXRpb25zX2ZpbmFsICU+JSBkaXN0aW5jdChgUHJvamVjdCBDdXJyZW50IFN0YXR1c2ApDQpgYGANCg0KQWxsIHRoZSBjb2x1bW5zIGhhdmUgYmVlbiBmYWN0b3Jpc2VkDQpgYGB7cn0NCnByb2plY3RfZG9uYXRpb25zX2ZpbmFsJGBEb25hdGlvbiBJbmNsdWRlZCBPcHRpb25hbCBEb25hdGlvbmAgPC0gcHJvamVjdF9kb25hdGlvbnNfZmluYWwkYERvbmF0aW9uIEluY2x1ZGVkIE9wdGlvbmFsIERvbmF0aW9uYCAlPiUgZmFjdG9yKGxldmVscyA9IGMoIlllcyIsIk5vIikpDQoNCnByb2plY3RfZG9uYXRpb25zX2ZpbmFsJGBQcm9qZWN0IFR5cGVgIDwtIHByb2plY3RfZG9uYXRpb25zX2ZpbmFsJGBQcm9qZWN0IFR5cGVgICU+JQ0KICBmYWN0b3IobGV2ZWxzID0gYygiVGVhY2hlci1MZWQiLCJPdGhlciIsIlByb2Zlc3Npb25hbCBEZXZlbG9wbWVudCIsIlN0dWRlbnQtTGVkIikpDQoNCnByb2plY3RfZG9uYXRpb25zX2ZpbmFsJGBQcm9qZWN0IEdyYWRlIExldmVsIENhdGVnb3J5YCA8LSBwcm9qZWN0X2RvbmF0aW9uc19maW5hbCRgUHJvamVjdCBHcmFkZSBMZXZlbCBDYXRlZ29yeWAgJT4lDQogIGZhY3RvcihsZXZlbHMgPSBjKCJHcmFkZXMgNi04IiwiR3JhZGVzIFByZUstMiIsIkdyYWRlcyAzLTUiLCJHcmFkZXMgOS0xMiIsIk90aGVyIikpDQoNCnByb2plY3RfZG9uYXRpb25zX2ZpbmFsJGBQcm9qZWN0IFJlc291cmNlIENhdGVnb3J5YCA8LSBwcm9qZWN0X2RvbmF0aW9uc19maW5hbCRgUHJvamVjdCBSZXNvdXJjZSBDYXRlZ29yeWAgJT4lIGZhY3RvcihsZXZlbHMgPSBjKCJPdGhlciIsIlRlY2hub2xvZ3kiLCJTdXBwbGllcyIsIkJvb2tzIiwiQ2xhc3Nyb29tIEJhc2ljcyIsIkFydCBTdXBwbGllcyIsIk11c2ljYWwgSW5zdHJ1bWVudHMiLCJDb21wdXRlcnMgJiBUYWJsZXRzIiwiSW5zdHJ1Y3Rpb25hbCBUZWNobm9sb2d5IiwiVHJpcHMiLCJMYWIgRXF1aXBtZW50IiwiRmxleGlibGUgU2VhdGluZyIsIkVkdWNhdGlvbmFsIEtpdHMgJiBHYW1lcyIsIkZvb2QsIENsb3RoaW5nICYgSHlnaWVuZSIsIlJlYWRpbmcgTm9va3MsIERlc2tzICYgU3RvcmFnZSIsIlNwb3J0cyAmIEV4ZXJjaXNlIEVxdWlwbWVudCIsIlZpc2l0b3JzIikpDQoNCnByb2plY3RfZG9uYXRpb25zX2ZpbmFsJGBQcm9qZWN0IEN1cnJlbnQgU3RhdHVzYDwtIHByb2plY3RfZG9uYXRpb25zX2ZpbmFsJGBQcm9qZWN0IEN1cnJlbnQgU3RhdHVzYCAlPiUgZmFjdG9yKGxldmVscyA9IGMoIkZ1bGx5IEZ1bmRlZCIsIkxpdmUiLCJFeHBpcmVkIiwiT3RoZXIiKSxvcmRlcmVkID0gVCkNCg0KYGBgDQoNCkNvbnZlcnRpbmcgZG9uYXRpb24gcmVjZWl2ZWQgZGF0ZSBhdHRyaWJ1dGUgYXMgZGF0ZQ0KYGBge3J9DQpwcm9qZWN0X2RvbmF0aW9uc19maW5hbCRgRG9uYXRpb24gUmVjZWl2ZWQgRGF0ZWAgPC0gYXMuRGF0ZShwcm9qZWN0X2RvbmF0aW9uc19maW5hbCRgRG9uYXRpb24gUmVjZWl2ZWQgRGF0ZWApDQpgYGANCg0KQXMgcGVyIGJlbG93IG91dHB1dCwgd2UgY2FuIHNlZSB0aGF0IHRoZSBuZWNlc3NhcnkgZGF0YSB0eXBlIGNvbnZlcnNpb25zIGhhdmUgYmVlbiBkb25lDQpgYGB7cn0NCnN0cihwcm9qZWN0X2RvbmF0aW9uc19maW5hbCkNCmBgYA0KDQoNCiMjCVRpZHkgJiBNYW5pcHVsYXRlIERhdGEgSSANCg0KDQpPdXIgZGF0YSBpcyBpbiB0aWR5IGZvcm1hdC4gSGVuY2UsIG5vIGFjdGlvbiB0YWtlbi4NCg0KIyMJVGlkeSAmIE1hbmlwdWxhdGUgRGF0YSBJSSANCg0KDQpDcmVhdGVkIGEgbmV3IGRhdGEgZnJhbWUgd2l0aCB0b3RhbCBkb25hdGVkIGFtb3VudHMgZ3JvdXBlZCBieSBwcm9qZWN0IHRpdGxlcyBhbmQgbmFtZWQgaXQgYXMgZG9uYXRpb25fYnlfdGl0bGUNCmBgYHtyfQ0KZG9uYXRpb25fYnlfdGl0bGUgPC0gYWdncmVnYXRlKHByb2plY3RfZG9uYXRpb25zX2ZpbmFsJGBEb25hdGlvbiBBbW91bnRgLGxpc3QocHJvamVjdF9kb25hdGlvbnNfZmluYWwkYFByb2plY3QgVGl0bGVgKSxzdW0pDQoNCmRvbmF0aW9uX2J5X3RpdGxlICU+JSBhcy5kYXRhLmZyYW1lKCkNCg0KDQoNCmBgYA0KDQpSZW5hbWVkIHRoZSBjb2x1bW4gbmFtZSBvZiBkb25hdGlvbiBieSB0aXRsZSBkYXRhZnJhbWUNCmBgYHtyfQ0KY29sbmFtZXMoZG9uYXRpb25fYnlfdGl0bGUpIDwtIGMoIlByb2plY3QgVGl0bGUiLCJUb3RhbCBQcm9qZWN0IGRvbmF0ZWQgYW1vdW50IikNCmhlYWQoZG9uYXRpb25fYnlfdGl0bGUpDQpgYGANCg0KDQpKb2luZWQgdGhpcyBkYXRhIGZyYW1lIG9udG8gcHJvamVjdF9kb25hdGlvbl9maW5hbCBkYXRhIGZyYW1lIGJ5IHVzaW5nIGxlZnQgbWVyZ2UNCmBgYHtyfQ0KcHJvamVjdF9kb25hdGlvbnNfZmluYWwgPC0gbWVyZ2UocHJvamVjdF9kb25hdGlvbnNfZmluYWwsZG9uYXRpb25fYnlfdGl0bGUsIlByb2plY3QgVGl0bGUiLGFsbC54PVQpDQpgYGANCg0KTXV0YXRlZCB0aGUgcHJvamVjdCBkb25hdGlvbnMgZmluYWwgZGF0YSBmcmFtZSBieSBjcmVhdGluZyBhIG5ldyBjb2x1bW4gY2FsbGVkIHByb2plY3RfZnVuZGluZ19iYWxhbmNlDQpgYGB7cn0NCnByb2plY3RfZG9uYXRpb25zX2ZpbmFsIDwtIG11dGF0ZShwcm9qZWN0X2RvbmF0aW9uc19maW5hbCxQcm9qZWN0X2Z1bmRpbmdfYmFsYW5jZT0gcHJvamVjdF9kb25hdGlvbnNfZmluYWwkYFByb2plY3QgQ29zdGAtcHJvamVjdF9kb25hdGlvbnNfZmluYWwkYFRvdGFsIFByb2plY3QgZG9uYXRlZCBhbW91bnRgKQ0KaGVhZChwcm9qZWN0X2RvbmF0aW9uc19maW5hbCkNCmBgYA0KDQojIwlTY2FuIEkgDQoNCg0KSW4gdGhlIGNvbnRleHQgb2YgdGhpcyBkYXRhc2V0LCByZW1vdmluZyB0aGUgbWlzc2luZyB2YWx1ZXMgd2FzIGFwcHJvcHJpYXRlLiBIZW5jZSB3ZSB1c2VkIHRoZSBuYS5vbWl0IGZ1bmN0aW9uIHRvIHJlbW92ZSB0aGUgbWlzc2luZyB2YWx1ZXMNCmBgYHtyfQ0KcHJvamVjdF9kb25hdGlvbnNfZmluYWwgPC0gbmEub21pdChwcm9qZWN0X2RvbmF0aW9uc19maW5hbCkNCmBgYA0KDQpBbGwgdGhlIG1pc3NpbmcgdmFsdWVzIGhhdmUgYmVlbiByZW1vdmVkIGFzIHBlciBiZWxvdw0KYGBge3J9DQpzdW0oaXMubmEocHJvamVjdF9kb25hdGlvbnNfZmluYWwpKQ0KYGBgDQoNCiMjCVNjYW4gSUkNCg0KDQoNCkFzIHBlciB0aGUgYm94cGxvdCB0aGVyZSBhcmUgb3V0bGllcnMgaW4gcHJvamVjdCBmdW5kaW5nIGJhbGFuY2Ugd2hpY2ggd2lsbCBiZSBkZWFsdCB3aXRoIGluIHRoZSBuZXh0IHN0ZXANCmBgYHtyfQ0KYm94cGxvdChwcm9qZWN0X2RvbmF0aW9uc19maW5hbCRQcm9qZWN0X2Z1bmRpbmdfYmFsYW5jZSx5bGFiPSJBbW91bnQiLG1haW49IlBlbmRpbmcgRnVuZCBCYWxhbmNlIGJveHBsb3QgYmVmb3JlIFJlbW92aW5nIE91dGxpZXJzIikNCmBgYA0KDQpDYXAgZnVuY3Rpb24gaGFzIGJlZW4gY3JlYXRlZCB0byBpZGVudGlmeSBhbmQgdXBkYXRlIHRoZSBvdXRsaWVycyB0byB0aGUgbmVhcmVzdCBxdWFydGlsZQ0KYGBge3J9DQpjYXAgPC0gZnVuY3Rpb24oeCl7DQogIHF1YW50aWxlcyA8LSBxdWFudGlsZSggeCwgYyguMDUsIDAuMjUsIDAuNzUsIC45NSApKQ0KICB4WyB4IDwgcXVhbnRpbGVzWzJdIC0gMS41KklRUih4KSBdIDwtIHF1YW50aWxlc1sxXQ0KICB4WyB4ID4gcXVhbnRpbGVzWzNdICsgMS41KklRUih4KSBdIDwtIHF1YW50aWxlc1s0XQ0KICB4fQ0KYGBgDQoNCk91dGxpZXJzIGZvciBwcm9qZWN0IGZ1bmRpbmcgYXR0cmlidXRlIGhhdmUgYmVlbiBkZWFsdCB3aXRoIHVzaW5nIGNhcHBpbmcNCmBgYHtyfQ0KcHJvamVjdF9kb25hdGlvbnNfZmluYWwkUHJvamVjdF9mdW5kaW5nX2JhbGFuY2UgPC0gcHJvamVjdF9kb25hdGlvbnNfZmluYWwkUHJvamVjdF9mdW5kaW5nX2JhbGFuY2UgJT4lIGNhcCgpDQpgYGANCg0KQm94cGxvdCBhZnRlciBkZWFsaW5nIHdpdGggdGhlIG91dGxpZXJzDQpgYGB7cn0NCmJveHBsb3QocHJvamVjdF9kb25hdGlvbnNfZmluYWwkUHJvamVjdF9mdW5kaW5nX2JhbGFuY2UseWxhYj0iQW1vdW50IixtYWluPSJQZW5kaW5nIEZ1bmQgQmFsYW5jZSBib3hwbG90IGFmdGVyIFJlbW92aW5nIE91dGxpZXJzIikNCg0KYGBgDQoNCg0KIyMJVHJhbnNmb3JtIA0KDQoNCkhpc3RvZ3JhbSBvZiB0b3RhbCBwcm9qZWN0IGRvbmF0ZWQgYW1vdW50IGJlZm9yZSB0cmFuc2Zvcm1hdGlvbiAoZGF0YSBpcyBub3Qgbm9ybWFsaXNlZCkNCmBgYHtyfQ0KaGlzdChwcm9qZWN0X2RvbmF0aW9uc19maW5hbCRgVG90YWwgUHJvamVjdCBkb25hdGVkIGFtb3VudGAsbWFpbiA9ICJUb3RhbCBhbW91bnQgZG9uYXRlZCB0byBwcm9qZWN0cyIseGxhYiA9ICJBbW91bnQgZG9uYXRlZCIpDQpgYGANCg0KQXBwbHlpbmcgYm94Y294IHRyYW5zZm9ybWF0aW9uIG9uIHByb2plY3QgYW1vdW50IGRvbmF0ZWQNCmBgYHtyfQ0KYm94Y294X3RvdF9kb25fYW10IDwtIEJveENveChwcm9qZWN0X2RvbmF0aW9uc19maW5hbCRgVG90YWwgUHJvamVjdCBkb25hdGVkIGFtb3VudGAsbGFtYmRhID0gImF1dG8iKSANCmBgYA0KDQpIaXN0b2dyYW0gYWZ0ZXIgdHJhbnNmb3JtYXRpb24gKGRhdGEgaXMgbm9ybWFsaXNlZCkNCmBgYHtyfQ0KaGlzdChib3hjb3hfdG90X2Rvbl9hbXQsbWFpbiA9ICJEb25hdGlvbiBhbW91bnQgYWZ0ZXIgdHJhbnNmb3JtYXRpb24iLHhsYWIgPSAiQW1vdW50IGRvbmF0ZWQiKQ0KYGBgDQoNCg0KDQoNCjxicj4NCjxicj4NCg==