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:
- Projects and Donations datasets are merged on Project ID column.
- Subset of first 10000 records from this dataset was taken to perform preprocessing.
- Data structure is checked and then the data type were changed as per the context of the data.
- Checked if there are any missing values and replaced them accordingly.
- Required columns were factorised and the necessary data type conversions have been done.
- Data was in a tidy format hence no actions were performed.
- New columns were mutated in the data frame.
- Missing values were removed using na.omit function.
- There were outliers in project funding balance which were dealt with using capping, after which the results were shown in a boxplot.
- Histogram of unnormalised data total project donated amount was shown before applying the transformation. We used boxcox transformation on project amount donated and showed the normalisation using histogram.
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:
- Project ID (chr)
- Donation ID(chr)
- Donation Included Optional Donation(factor)
- Donation Amount (num)
- Donation Received Date(Date)
- Project Type(factor)
- Project Title (chr)
- Project Grade Level Category (factor)
- Project Resource Category(factor)
- Project Cost (num)
- Project Posted Date (Date)
- Project Expiration Date (Date)
- Project Current Status( Ord Factor)
- Project Fully Funded Date (Date)
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")

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