Myra Hallman
Marketing Analytics
24 Feb 2019
library(ggplot2)
library(scales)
library(dplyr)
library(tidyverse)
sales.df <- read.csv("LaptopSales.csv")
sales.df <- na.omit(sales.df)
View(sales.df)
Price Questions
• At what price are the laptops actually selling?
The prices range from under $200 to over $750, and the number sold is approximately normally distributed. The average retail price of laptops sold falls around just under $500.
ggplot(sales.df) +
geom_histogram(aes(x=Retail.Price), binwidth=20) +
labs(title = "Sell Price of Laptops", x="Retail Price", y="Number Sold")

• Does price change with time? (Hint: Make sure that the date column is recognized as such. The software should then enable different temporal aggregation choices, e.g., plotting the data by weekly or monthly aggregates, or even by day of week.)
As seen in the smoothed line graph below, you can see that price of laptops does change over time. Peak sales happen between July and August. The sales drop dramatically in April. This suggests a seasonality for the demand of laptops.
ggplot(sales.df) +
geom_smooth(aes(x=as.Date(Date), y=Retail.Price)) +
labs(title = "Price by Date", x="Month", y="Retail Price")

• Are prices consistent across retail outlets?
The prices are close, but not entirely consistent overall. As noted in the graph below, you can see that the majority of stores have a mean price of approximately $520. Five of the stores, however, sell laptops at a deeply discounted rate of approximately $470.
pricegroup.df <- group_by(sales.df, Store.Postcode)
price.by.postcode.df <- summarize(pricegroup.df, mean_price=mean(Retail.Price),
max_price=max(Retail.Price), min_price=min(Retail.Price))
ggplot(price.by.postcode.df) +
geom_point (aes(x=Store.Postcode, y=mean_price)) +
labs(title = "Mean Price by Store Location", x="Store Postcode", y="Mean Price")

• How does price change with configuration?
According to the data, and visualized in the graph below, the configuration number and retail price are closely related. As the configuration number increases, so then does the retail price.
ggplot(sales.df) +
geom_smooth(aes(x=Retail.Price, y=Configuration)) +
labs(title = "Price Compared to Configuration", x="Retail Price", y="Configuration Number")

Revenue Questions
• How do the sales volume in each store relate to Acell’s revenues?
In the table below, you can see the relationship between each store’s revenue and Acell’s overall revenue. There is a column that shows each store’s revenue, and another column that gives the percentage that revenue is of Acell’s overall revenue. Each store contributes at very different levels. There is also a bar graph below that shows each store code and it’s contributions to the overall revenue.
totalrevenuegroup.df <- group_by(sales.df, Store.Postcode)
revenue.by.business.df <- summarize(totalrevenuegroup.df,
Total_Revenue=sum(Retail.Price),
percentage_rows=n()/nrow(totalrevenuegroup.df)*100)
(revenue.by.business.df)
ggplot(revenue.by.business.df) +
geom_bar (aes(x=Store.Postcode, y=percentage_rows), stat="identity") +
labs(title = "Store Revenue", x="Store Postcode", y="Percent of Acell's Total Revenue")

• How does this relationship depend on the configuration?
You can see in the bar graph below that the configurations related to store postcode look very close to the graph above. It can be deduced from this that the greater percentage of Acell’s revenue comes from stores that sell higher configuration numbers primarily. The data is very consistent with this conclusion.
ggplot(sales.df) +
geom_bar (aes(x=Store.Postcode, y=Configuration), stat="identity") +
labs(title = "Store Compared to Configuration", x="Store.Postcode", y="Configuration")

Below is another graph that shows retail price related to store postcode.
sales.df <- mutate(sales.df, Configuration.Small=round(Configuration/100))
ggplot(sales.df) +
geom_bar(aes(x=Store.Postcode, y=Retail.Price, fill=factor(Configuration.Small)), stat="summary",
fun.y='sum', position = 'fill') +
labs(title = "Retail Price and Store Postcode", x="Store Postcode", y="Retail Price")

Configuration Questions
• What are the details of each configuration? How does this relate to price?
Below are three examples of how different configurations are related to screensize, battery life, and RAM. You can see that it is consistent with the increase in price as the configuration number grows. With higher configuration, the features tend to also improve. Not all features improve at once, but with at least one increased feature, the price will expect to rise as well.
The bar graph below shows the relationship to screen size based on configuration. There are two different screen sizes, and the larger screen size can be found in the configurations with higher numbers.
Screensize.df <- summarize(group_by(sales.df, Configuration), mean.screen.size.inches=mean(Screen.Size..Inches., na.rm = TRUE))
ggplot(Screensize.df) +
geom_bar(aes(x=Configuration, y=mean.screen.size.inches), stat="identity") +
labs(title = "Screen Size and Configuration", x="Configuration", y="Mean Screen Size in Inches")

Battery life is available in 4, 5, or 6 hour lifespans. You can see there is steady growth as configurations rise, and then the battery life drops back to 4 hours once it reaches the mazimum of 6 hours.
battery.life.df <- summarize(group_by(sales.df, Configuration), mean.battery.life=mean(Battery.Life..Hours., na.rm = TRUE))
ggplot(battery.life.df) +
geom_bar(aes(x=Configuration, y=mean.battery.life), stat="identity") +
labs(title = "Battery Life and Configuration", x="Configuration", y="Mean Battery Life in Hours")

RAM size comes in three phases as well. There is 1 GB, 2 GB and 4 GB. These also grow incremintally as the configuration grows. You can see that they cycle through the options 6 different times as the configuration grows.
RAMsize.df <- summarize(group_by(sales.df, Configuration), mean.RAM.GB=mean(RAM..GB., na.rm = TRUE))
ggplot(RAMsize.df) +
geom_bar(aes(x=Configuration, y=mean.RAM.GB), stat="identity") +
labs(title = "RAM Size and Configuration", x="Configuration", y="Mean RAM Size in GB")

• Do all stores sell all configurations?
Yes, all stores sell all configurations. You can see on the list below that the stores do sell all configurations. The differences lie with the number of each configuration available through each store.
configurationsgroup.df <- group_by(sales.df, Store.Postcode, Configuration)
configurations.by.business.df <- summarize(configurationsgroup.df,
count_rows=n(),
percentage_rows=n()/nrow(configurationsgroup.df)*100)
(configurations.by.business.df)
```
END
Worked with Jannika, Kaisa, Kia
LS0tDQp0aXRsZTogIk1pbmkgUHJvamVjdCAxIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCk15cmEgSGFsbG1hbg0KDQpNYXJrZXRpbmcgQW5hbHl0aWNzDQoNCjI0IEZlYiAyMDE5DQoNCmBgYHtyfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShzY2FsZXMpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpzYWxlcy5kZiA8LSByZWFkLmNzdigiTGFwdG9wU2FsZXMuY3N2IikNCnNhbGVzLmRmIDwtIG5hLm9taXQoc2FsZXMuZGYpDQpWaWV3KHNhbGVzLmRmKQ0KYGBgDQoNCg0KI1ByaWNlIFF1ZXN0aW9ucw0KDQrigKIJQXQgd2hhdCBwcmljZSBhcmUgdGhlIGxhcHRvcHMgYWN0dWFsbHkgc2VsbGluZz8NCg0KVGhlIHByaWNlcyByYW5nZSBmcm9tIHVuZGVyICQyMDAgdG8gb3ZlciAkNzUwLCBhbmQgdGhlIG51bWJlciBzb2xkIGlzIGFwcHJveGltYXRlbHkgbm9ybWFsbHkgZGlzdHJpYnV0ZWQuIFRoZSBhdmVyYWdlIHJldGFpbCBwcmljZSBvZiBsYXB0b3BzIHNvbGQgZmFsbHMgYXJvdW5kIGp1c3QgdW5kZXIgJDUwMC4gDQoNCmBgYHtyfQ0KZ2dwbG90KHNhbGVzLmRmKSArDQogIGdlb21faGlzdG9ncmFtKGFlcyh4PVJldGFpbC5QcmljZSksIGJpbndpZHRoPTIwKSArDQogIGxhYnModGl0bGUgPSAiU2VsbCBQcmljZSBvZiBMYXB0b3BzIiwgeD0iUmV0YWlsIFByaWNlIiwgeT0iTnVtYmVyIFNvbGQiKQ0KYGBgDQoNCg0KDQoNCuKAoglEb2VzIHByaWNlIGNoYW5nZSB3aXRoIHRpbWU/IChIaW50OiBNYWtlIHN1cmUgdGhhdCB0aGUgZGF0ZSBjb2x1bW4gaXMgcmVjb2duaXplZCBhcyBzdWNoLiBUaGUgc29mdHdhcmUgc2hvdWxkIHRoZW4gZW5hYmxlIGRpZmZlcmVudCB0ZW1wb3JhbCBhZ2dyZWdhdGlvbiBjaG9pY2VzLCBlLmcuLCBwbG90dGluZyB0aGUgZGF0YSBieSB3ZWVrbHkgb3IgbW9udGhseSBhZ2dyZWdhdGVzLCBvciBldmVuIGJ5IGRheSBvZiB3ZWVrLikNCg0KQXMgc2VlbiBpbiB0aGUgc21vb3RoZWQgbGluZSBncmFwaCBiZWxvdywgeW91IGNhbiBzZWUgdGhhdCBwcmljZSBvZiBsYXB0b3BzIGRvZXMgY2hhbmdlIG92ZXIgdGltZS4gUGVhayBzYWxlcyBoYXBwZW4gYmV0d2VlbiBKdWx5IGFuZCBBdWd1c3QuIFRoZSBzYWxlcyBkcm9wIGRyYW1hdGljYWxseSBpbiBBcHJpbC4gVGhpcyBzdWdnZXN0cyBhIHNlYXNvbmFsaXR5IGZvciB0aGUgZGVtYW5kIG9mIGxhcHRvcHMuIA0KDQpgYGB7cn0NCmdncGxvdChzYWxlcy5kZikgKw0KICBnZW9tX3Ntb290aChhZXMoeD1hcy5EYXRlKERhdGUpLCB5PVJldGFpbC5QcmljZSkpICsNCiAgbGFicyh0aXRsZSA9ICJQcmljZSBieSBEYXRlIiwgeD0iTW9udGgiLCB5PSJSZXRhaWwgUHJpY2UiKSANCmBgYA0KDQoNCg0K4oCiCUFyZSBwcmljZXMgY29uc2lzdGVudCBhY3Jvc3MgcmV0YWlsIG91dGxldHM/DQoNClRoZSBwcmljZXMgYXJlIGNsb3NlLCBidXQgbm90IGVudGlyZWx5IGNvbnNpc3RlbnQgb3ZlcmFsbC4gQXMgbm90ZWQgaW4gdGhlIGdyYXBoIGJlbG93LCB5b3UgY2FuIHNlZSB0aGF0IHRoZSBtYWpvcml0eSBvZiBzdG9yZXMgaGF2ZSBhIG1lYW4gcHJpY2Ugb2YgYXBwcm94aW1hdGVseSAkNTIwLiBGaXZlIG9mIHRoZSBzdG9yZXMsIGhvd2V2ZXIsIHNlbGwgbGFwdG9wcyBhdCBhIGRlZXBseSBkaXNjb3VudGVkIHJhdGUgb2YgYXBwcm94aW1hdGVseSAkNDcwLiANCg0KDQpgYGB7cn0NCnByaWNlZ3JvdXAuZGYgPC0gZ3JvdXBfYnkoc2FsZXMuZGYsIFN0b3JlLlBvc3Rjb2RlKSANCnByaWNlLmJ5LnBvc3Rjb2RlLmRmIDwtIHN1bW1hcml6ZShwcmljZWdyb3VwLmRmLCBtZWFuX3ByaWNlPW1lYW4oUmV0YWlsLlByaWNlKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4X3ByaWNlPW1heChSZXRhaWwuUHJpY2UpLCBtaW5fcHJpY2U9bWluKFJldGFpbC5QcmljZSkpIA0KZ2dwbG90KHByaWNlLmJ5LnBvc3Rjb2RlLmRmKSArDQogIGdlb21fcG9pbnQgKGFlcyh4PVN0b3JlLlBvc3Rjb2RlLCB5PW1lYW5fcHJpY2UpKSArDQogIGxhYnModGl0bGUgPSAiTWVhbiBQcmljZSBieSBTdG9yZSBMb2NhdGlvbiIsIHg9IlN0b3JlIFBvc3Rjb2RlIiwgeT0iTWVhbiBQcmljZSIpIA0KYGBgDQoNCg0KDQoNCuKAoglIb3cgZG9lcyBwcmljZSBjaGFuZ2Ugd2l0aCBjb25maWd1cmF0aW9uPw0KDQpBY2NvcmRpbmcgdG8gdGhlIGRhdGEsIGFuZCB2aXN1YWxpemVkIGluIHRoZSBncmFwaCBiZWxvdywgdGhlIGNvbmZpZ3VyYXRpb24gbnVtYmVyIGFuZCByZXRhaWwgcHJpY2UgYXJlIGNsb3NlbHkgcmVsYXRlZC4gQXMgdGhlIGNvbmZpZ3VyYXRpb24gbnVtYmVyIGluY3JlYXNlcywgc28gdGhlbiBkb2VzIHRoZSByZXRhaWwgcHJpY2UuIA0KDQoNCmBgYHtyfQ0KZ2dwbG90KHNhbGVzLmRmKSArDQogIGdlb21fc21vb3RoKGFlcyh4PVJldGFpbC5QcmljZSwgeT1Db25maWd1cmF0aW9uKSkgKw0KICBsYWJzKHRpdGxlID0gIlByaWNlIENvbXBhcmVkIHRvIENvbmZpZ3VyYXRpb24iLCB4PSJSZXRhaWwgUHJpY2UiLCB5PSJDb25maWd1cmF0aW9uIE51bWJlciIpDQpgYGANCg0KDQojIFJldmVudWUgUXVlc3Rpb25zDQoNCg0K4oCiCUhvdyBkbyB0aGUgc2FsZXMgdm9sdW1lIGluIGVhY2ggc3RvcmUgcmVsYXRlIHRvIEFjZWxs4oCZcyByZXZlbnVlcz8NCg0KSW4gdGhlIHRhYmxlIGJlbG93LCB5b3UgY2FuIHNlZSB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gZWFjaCBzdG9yZSdzIHJldmVudWUgYW5kIEFjZWxsJ3Mgb3ZlcmFsbCByZXZlbnVlLiBUaGVyZSBpcyBhIGNvbHVtbiB0aGF0IHNob3dzIGVhY2ggc3RvcmUncyByZXZlbnVlLCBhbmQgYW5vdGhlciBjb2x1bW4gdGhhdCBnaXZlcyB0aGUgcGVyY2VudGFnZSB0aGF0IHJldmVudWUgaXMgb2YgQWNlbGwncyBvdmVyYWxsIHJldmVudWUuIEVhY2ggc3RvcmUgY29udHJpYnV0ZXMgYXQgdmVyeSBkaWZmZXJlbnQgbGV2ZWxzLiBUaGVyZSBpcyBhbHNvIGEgYmFyIGdyYXBoIGJlbG93IHRoYXQgc2hvd3MgZWFjaCBzdG9yZSBjb2RlIGFuZCBpdCdzIGNvbnRyaWJ1dGlvbnMgdG8gdGhlIG92ZXJhbGwgcmV2ZW51ZS4gDQoNCg0KYGBge3J9DQp0b3RhbHJldmVudWVncm91cC5kZiA8LSBncm91cF9ieShzYWxlcy5kZiwgU3RvcmUuUG9zdGNvZGUpIA0KcmV2ZW51ZS5ieS5idXNpbmVzcy5kZiA8LSBzdW1tYXJpemUodG90YWxyZXZlbnVlZ3JvdXAuZGYsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUb3RhbF9SZXZlbnVlPXN1bShSZXRhaWwuUHJpY2UpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBlcmNlbnRhZ2Vfcm93cz1uKCkvbnJvdyh0b3RhbHJldmVudWVncm91cC5kZikqMTAwKQ0KDQoocmV2ZW51ZS5ieS5idXNpbmVzcy5kZikNCg0KDQpgYGANCmBgYHtyfQ0KZ2dwbG90KHJldmVudWUuYnkuYnVzaW5lc3MuZGYpICsNCiAgZ2VvbV9iYXIgKGFlcyh4PVN0b3JlLlBvc3Rjb2RlLCB5PXBlcmNlbnRhZ2Vfcm93cyksIHN0YXQ9ImlkZW50aXR5IikgICsNCiAgbGFicyh0aXRsZSA9ICJTdG9yZSBSZXZlbnVlIiwgeD0iU3RvcmUgUG9zdGNvZGUiLCB5PSJQZXJjZW50IG9mIEFjZWxsJ3MgVG90YWwgUmV2ZW51ZSIpDQpgYGANCg0KDQoNCg0K4oCiCUhvdyBkb2VzIHRoaXMgcmVsYXRpb25zaGlwIGRlcGVuZCBvbiB0aGUgY29uZmlndXJhdGlvbj8NCg0KWW91IGNhbiBzZWUgaW4gdGhlIGJhciBncmFwaCBiZWxvdyB0aGF0IHRoZSBjb25maWd1cmF0aW9ucyByZWxhdGVkIHRvIHN0b3JlIHBvc3Rjb2RlIGxvb2sgdmVyeSBjbG9zZSB0byB0aGUgZ3JhcGggYWJvdmUuIEl0IGNhbiBiZSBkZWR1Y2VkIGZyb20gdGhpcyB0aGF0IHRoZSBncmVhdGVyIHBlcmNlbnRhZ2Ugb2YgQWNlbGwncyByZXZlbnVlIGNvbWVzIGZyb20gc3RvcmVzIHRoYXQgc2VsbCBoaWdoZXIgY29uZmlndXJhdGlvbiBudW1iZXJzIHByaW1hcmlseS4gVGhlIGRhdGEgaXMgdmVyeSBjb25zaXN0ZW50IHdpdGggdGhpcyBjb25jbHVzaW9uLiAgDQoNCmBgYHtyfQ0KZ2dwbG90KHNhbGVzLmRmKSArDQogIGdlb21fYmFyIChhZXMoeD1TdG9yZS5Qb3N0Y29kZSwgeT1Db25maWd1cmF0aW9uKSwgc3RhdD0iaWRlbnRpdHkiKSAgKw0KICBsYWJzKHRpdGxlID0gIlN0b3JlIENvbXBhcmVkIHRvIENvbmZpZ3VyYXRpb24iLCB4PSJTdG9yZS5Qb3N0Y29kZSIsIHk9IkNvbmZpZ3VyYXRpb24iKQ0KYGBgDQoNCg0KDQoNCkJlbG93IGlzIGFub3RoZXIgZ3JhcGggdGhhdCBzaG93cyByZXRhaWwgcHJpY2UgcmVsYXRlZCB0byBzdG9yZSBwb3N0Y29kZS4gDQoNCg0KYGBge3J9DQpzYWxlcy5kZiA8LSBtdXRhdGUoc2FsZXMuZGYsIENvbmZpZ3VyYXRpb24uU21hbGw9cm91bmQoQ29uZmlndXJhdGlvbi8xMDApKQ0KDQpnZ3Bsb3Qoc2FsZXMuZGYpICsNCiAgZ2VvbV9iYXIoYWVzKHg9U3RvcmUuUG9zdGNvZGUsIHk9UmV0YWlsLlByaWNlLCBmaWxsPWZhY3RvcihDb25maWd1cmF0aW9uLlNtYWxsKSksIHN0YXQ9InN1bW1hcnkiLA0KICAgICAgICAgICBmdW4ueT0nc3VtJywgcG9zaXRpb24gPSAnZmlsbCcpICsNCiAgbGFicyh0aXRsZSA9ICJSZXRhaWwgUHJpY2UgYW5kIFN0b3JlIFBvc3Rjb2RlIiwgeD0iU3RvcmUgUG9zdGNvZGUiLCB5PSJSZXRhaWwgUHJpY2UiKQ0KYGBgDQoNCg0KDQojIENvbmZpZ3VyYXRpb24gUXVlc3Rpb25zDQoNCg0K4oCiCVdoYXQgYXJlIHRoZSBkZXRhaWxzIG9mIGVhY2ggY29uZmlndXJhdGlvbj8gSG93IGRvZXMgdGhpcyByZWxhdGUgdG8gcHJpY2U/DQoNCkJlbG93IGFyZSB0aHJlZSBleGFtcGxlcyBvZiBob3cgZGlmZmVyZW50IGNvbmZpZ3VyYXRpb25zIGFyZSByZWxhdGVkIHRvIHNjcmVlbnNpemUsIGJhdHRlcnkgbGlmZSwgYW5kIFJBTS4gWW91IGNhbiBzZWUgdGhhdCBpdCBpcyBjb25zaXN0ZW50IHdpdGggdGhlIGluY3JlYXNlIGluIHByaWNlIGFzIHRoZSBjb25maWd1cmF0aW9uIG51bWJlciBncm93cy4gV2l0aCBoaWdoZXIgY29uZmlndXJhdGlvbiwgdGhlIGZlYXR1cmVzIHRlbmQgdG8gYWxzbyBpbXByb3ZlLiBOb3QgYWxsIGZlYXR1cmVzIGltcHJvdmUgYXQgb25jZSwgYnV0IHdpdGggYXQgbGVhc3Qgb25lIGluY3JlYXNlZCBmZWF0dXJlLCB0aGUgcHJpY2Ugd2lsbCBleHBlY3QgdG8gcmlzZSBhcyB3ZWxsLiANCg0KDQoNClRoZSBiYXIgZ3JhcGggYmVsb3cgc2hvd3MgdGhlIHJlbGF0aW9uc2hpcCB0byBzY3JlZW4gc2l6ZSBiYXNlZCBvbiBjb25maWd1cmF0aW9uLiBUaGVyZSBhcmUgdHdvIGRpZmZlcmVudCBzY3JlZW4gc2l6ZXMsIGFuZCB0aGUgbGFyZ2VyIHNjcmVlbiBzaXplIGNhbiBiZSBmb3VuZCBpbiB0aGUgY29uZmlndXJhdGlvbnMgd2l0aCBoaWdoZXIgbnVtYmVycy4NCg0KDQpgYGB7cn0NClNjcmVlbnNpemUuZGYgPC0gc3VtbWFyaXplKGdyb3VwX2J5KHNhbGVzLmRmLCBDb25maWd1cmF0aW9uKSwgbWVhbi5zY3JlZW4uc2l6ZS5pbmNoZXM9bWVhbihTY3JlZW4uU2l6ZS4uSW5jaGVzLiwgbmEucm0gPSBUUlVFKSkNCg0KZ2dwbG90KFNjcmVlbnNpemUuZGYpICsNCmdlb21fYmFyKGFlcyh4PUNvbmZpZ3VyYXRpb24sIHk9bWVhbi5zY3JlZW4uc2l6ZS5pbmNoZXMpLCBzdGF0PSJpZGVudGl0eSIpICsNCiAgbGFicyh0aXRsZSA9ICJTY3JlZW4gU2l6ZSBhbmQgQ29uZmlndXJhdGlvbiIsIHg9IkNvbmZpZ3VyYXRpb24iLCB5PSJNZWFuIFNjcmVlbiBTaXplIGluIEluY2hlcyIpDQoNCmBgYA0KDQoNCg0KQmF0dGVyeSBsaWZlIGlzIGF2YWlsYWJsZSBpbiA0LCA1LCBvciA2IGhvdXIgbGlmZXNwYW5zLiBZb3UgY2FuIHNlZSB0aGVyZSBpcyBzdGVhZHkgZ3Jvd3RoIGFzIGNvbmZpZ3VyYXRpb25zIHJpc2UsIGFuZCB0aGVuIHRoZSBiYXR0ZXJ5IGxpZmUgZHJvcHMgYmFjayB0byA0IGhvdXJzIG9uY2UgaXQgcmVhY2hlcyB0aGUgbWF6aW11bSBvZiA2IGhvdXJzLiANCg0KDQoNCmBgYHtyfQ0KYmF0dGVyeS5saWZlLmRmIDwtIHN1bW1hcml6ZShncm91cF9ieShzYWxlcy5kZiwgQ29uZmlndXJhdGlvbiksIG1lYW4uYmF0dGVyeS5saWZlPW1lYW4oQmF0dGVyeS5MaWZlLi5Ib3Vycy4sIG5hLnJtID0gVFJVRSkpDQoNCmdncGxvdChiYXR0ZXJ5LmxpZmUuZGYpICsNCiAgZ2VvbV9iYXIoYWVzKHg9Q29uZmlndXJhdGlvbiwgeT1tZWFuLmJhdHRlcnkubGlmZSksIHN0YXQ9ImlkZW50aXR5IikgKw0KICBsYWJzKHRpdGxlID0gIkJhdHRlcnkgTGlmZSBhbmQgQ29uZmlndXJhdGlvbiIsIHg9IkNvbmZpZ3VyYXRpb24iLCB5PSJNZWFuIEJhdHRlcnkgTGlmZSBpbiBIb3VycyIpDQpgYGANCg0KDQpSQU0gc2l6ZSBjb21lcyBpbiB0aHJlZSBwaGFzZXMgYXMgd2VsbC4gVGhlcmUgaXMgMSBHQiwgMiBHQiBhbmQgNCBHQi4gVGhlc2UgYWxzbyBncm93IGluY3JlbWludGFsbHkgYXMgdGhlIGNvbmZpZ3VyYXRpb24gZ3Jvd3MuIFlvdSBjYW4gc2VlIHRoYXQgdGhleSBjeWNsZSB0aHJvdWdoIHRoZSBvcHRpb25zIDYgZGlmZmVyZW50IHRpbWVzIGFzIHRoZSBjb25maWd1cmF0aW9uIGdyb3dzLiANCg0KDQpgYGB7cn0NClJBTXNpemUuZGYgPC0gc3VtbWFyaXplKGdyb3VwX2J5KHNhbGVzLmRmLCBDb25maWd1cmF0aW9uKSwgbWVhbi5SQU0uR0I9bWVhbihSQU0uLkdCLiwgbmEucm0gPSBUUlVFKSkNCg0KZ2dwbG90KFJBTXNpemUuZGYpICsNCmdlb21fYmFyKGFlcyh4PUNvbmZpZ3VyYXRpb24sIHk9bWVhbi5SQU0uR0IpLCBzdGF0PSJpZGVudGl0eSIpICsNCiAgbGFicyh0aXRsZSA9ICJSQU0gU2l6ZSBhbmQgQ29uZmlndXJhdGlvbiIsIHg9IkNvbmZpZ3VyYXRpb24iLCB5PSJNZWFuIFJBTSBTaXplIGluIEdCIikNCmBgYA0KDQoNCg0KDQrigKIJRG8gYWxsIHN0b3JlcyBzZWxsIGFsbCBjb25maWd1cmF0aW9ucz8NCg0KWWVzLCBhbGwgc3RvcmVzIHNlbGwgYWxsIGNvbmZpZ3VyYXRpb25zLiBZb3UgY2FuIHNlZSBvbiB0aGUgbGlzdCBiZWxvdyB0aGF0IHRoZSBzdG9yZXMgZG8gc2VsbCBhbGwgY29uZmlndXJhdGlvbnMuIFRoZSBkaWZmZXJlbmNlcyBsaWUgd2l0aCB0aGUgbnVtYmVyIG9mIGVhY2ggY29uZmlndXJhdGlvbiBhdmFpbGFibGUgdGhyb3VnaCBlYWNoIHN0b3JlLiANCg0KDQoNCmBgYHtyfQ0KY29uZmlndXJhdGlvbnNncm91cC5kZiA8LSBncm91cF9ieShzYWxlcy5kZiwgU3RvcmUuUG9zdGNvZGUsIENvbmZpZ3VyYXRpb24pIA0KY29uZmlndXJhdGlvbnMuYnkuYnVzaW5lc3MuZGYgPC0gc3VtbWFyaXplKGNvbmZpZ3VyYXRpb25zZ3JvdXAuZGYsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvdW50X3Jvd3M9bigpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBlcmNlbnRhZ2Vfcm93cz1uKCkvbnJvdyhjb25maWd1cmF0aW9uc2dyb3VwLmRmKSoxMDApDQoNCihjb25maWd1cmF0aW9ucy5ieS5idXNpbmVzcy5kZikNCg0KYGBgDQoNCg0KDQpgYGANCg0KDQojRU5EDQpXb3JrZWQgd2l0aCBKYW5uaWthLCBLYWlzYSwgS2lh