Load packages
library(tidyverse)
library(openintro)
head(fastfood)
## # A tibble: 6 x 17
## restaurant item calories cal_fat total_fat sat_fat trans_fat cholesterol
## <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Mcdonalds Arti~ 380 60 7 2 0 95
## 2 Mcdonalds Sing~ 840 410 45 17 1.5 130
## 3 Mcdonalds Doub~ 1130 600 67 27 3 220
## 4 Mcdonalds Gril~ 750 280 31 10 0.5 155
## 5 Mcdonalds Cris~ 920 410 45 12 0.5 120
## 6 Mcdonalds Big ~ 540 250 28 10 1 80
## # ... with 9 more variables: sodium <dbl>, total_carb <dbl>, fiber <dbl>,
## # sugar <dbl>, protein <dbl>, vit_a <dbl>, vit_c <dbl>, calcium <dbl>,
## # salad <chr>
mcdonalds <- fastfood %>%
filter(restaurant == "Mcdonalds")
dairy_queen <- fastfood %>%
filter(restaurant == "Dairy Queen")
Exercise 1
ggplot(mcdonalds, aes(x=cal_fat)) + geom_histogram(binwidth = 40) + labs(x="calories from fat", y="items on menu", title ="McDonalds")

McDonalds has a much larger spread to its data with significant outliers. The IQR looks to be within to 100-400 calorie range. There is a definable center to the data around 200-300 calorie value. The shape appears somewhat symmetrical and bell curved although there is second peak nearer to 100 calories.
ggplot(dairy_queen, aes(x=cal_fat)) + geom_histogram(binwidth = 40) + labs(x="calories from fat", y="items on menu", title="Dairy Queen")

Dairy Queen has a center around 150 with some skew to the left. The data also appears somewhat bell curved and symmetrical around its center.
Exercise 2
dqmean <- mean(dairy_queen$cal_fat)
dqsd <- sd(dairy_queen$cal_fat)
ggplot(data = dairy_queen, aes(x = cal_fat)) +
geom_blank() +
geom_histogram(aes(y = ..density..)) +
stat_function(fun = dnorm, args = c(mean = dqmean, sd = dqsd), col = "tomato")
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

The density function appears to have a fairly flat but undeniable unimodal shape where its peak has greatest density. I would agree that this data is normally distributed.
ggplot(data = dairy_queen, aes(sample = cal_fat)) +
geom_line(stat = "qq")

sim_norm <- rnorm(n = nrow(dairy_queen), mean = dqmean, sd = dqsd)
Exercise 3
qqnorm(sim_norm)
qqline(sim_norm)

Not all the points fall entirely on the line as this is randomized simulated data; the residuals look to be very small however which makes sense since this is simulated normally distributed data.
qqnorm(dairy_queen$cal_fat,main="QQ Plot: DQ - Calories from Fat")
qqline(dairy_queen$cal_fat)
In the probability plot of the real data, the datapoints do adhere to a linear pattern indicating normal distribution but lift upward and away from the theoretical line. This indicates that the actual values are much greater than the expected values if this data were perfectly and normally symmetrical. The lift indicates that this is skewed to the right - most data points are distributed on the left with a long tail of extreme values to the right. This lines up with what we saw in the histogram of the same data.
Exercise 4
qqnormsim(sample = cal_fat, data = dairy_queen)

Yes, the actual real data looks pretty similar to the simulations. The lift at the far right is still noticeably different than the normally distributed simulations - that deviation indicates some deviation away from being symmetrically distributed.
Exercise 5
The points show a more noticeable curve rather than a straight line in this qq plot. The lift at the top right is much more pronounced - the deviation away from linearity indicates deviation away from the data being normally distributed.
Again, the lift of actual data vs the expected indicates the data is again skewed to the right. This curve is more pronounced in McDonald’s menu items than in DQ’s. McDonalds has more extreme values is its tail to the right than DQ has.
ggplot(data = mcdonalds, aes(sample = cal_fat)) +
geom_line(stat = "qq")

qqnormsim(sample = cal_fat, data = mcdonalds)

mcdmean <- mean(mcdonalds$cal_fat)
mcdsd <- sd(mcdonalds$cal_fat)
sim_norm_mcd <- rnorm(n = nrow(mcdonalds), mean = mcdmean, sd = mcdsd)
qqnorm(sim_norm_mcd)
qqline(sim_norm_mcd)

qqnorm(mcdonalds$cal_fat, main="QQ Plot: McD - Calories from Fat")
qqline(mcdonalds$cal_fat)

Exercise 6
Let’s say I am looking to start eating healthier, starting with choosing more healthier menu items when eating fastfood. Since the recommended amount of calories from fat is about 600 (or 30% of a traditional 2000), I’m only looking for menu items that are will account for roughly 1/3 of this total daily amount. I want to know what the probability is that an menu item that either mcd’s or dq offers will be within 150 to 250 calories from fat. Enough fat to taste, but not enough for heartburn :)
Theoretical probability that menu item from Dairy Queen is between 150 to 250 calories:
round(pnorm(q = 250, mean = dqmean, sd = dqsd) -
pnorm(q = 150, mean = dqmean, sd = dqsd),3)
## [1] 0.233
Empirical probability that menu item from Dairy Queen is between 150 to 250 calories:
dairy_queen %>%
filter(cal_fat >= 150 & cal_fat <= 250) %>%
summarise(percent = n() / nrow(dairy_queen))
## # A tibble: 1 x 1
## percent
## <dbl>
## 1 0.381
Theoretical probability that menu item from McDonalds is between 150 to 250 calories:
round(pnorm(q = 250, mean = mcdmean, sd = mcdsd) -
pnorm(q = 150, mean = mcdmean, sd = mcdsd),3)
## [1] 0.166
Empirical probability that menu item from McDonalds is between 150 to 250 calories:
mcdonalds %>%
filter(cal_fat >= 150 & cal_fat <= 250) %>%
summarise(percent = n() / nrow(mcdonalds))
## # A tibble: 1 x 1
## percent
## <dbl>
## 1 0.368
The theoretical probability (based on assumption of normal distribution) gave a much slimmer probability of a menu item being within the range of 150 and 250 calories, respectively 23% and 16.7%. When looking at the means and standard deviation of the 2 distributions, this makes sense that 100 calorie range below mean would net these values.
However - unsurprisingly since we viewed the data visually and know that majority of the distribution for both Dairy Queen and McDonalds is skewed to the right - the empirical probabilities in both cases is much greater.
There is a 38% empirical probability of a menu item having between 150 and 250 calories from fat in the case of DQ, and a 36.8% probability in the case of McDonalds. The right tails of both distributions indicate that there are extreme values distorting the average of this dataset, suggesting a center much farther to the right than actually exists.
Of the two, DQ had a closer predicted theoretical probability - 15% off (38 - 23) than McDonalds - 20% off (36.8 - 16.7). This is also unsurprising given that we the more significant lift in the QQ plot of McDonalds, indicating that McDonald’s had more extreme values than did DQ, and therefore more greatly distorting the actual center and spread.
Exercise 7
Evaluating for Normal Distribution in Sodium by Restaurant:
On review of the QQ plots of each restaurant, it appears that Arby’s, Burger King, and Taco Bell most clearly mirror a normal distribution. There was some curvature in Chick-Fil-A, Sonic, and Subway; the most pronounced lift (indicating right skew) appears in Dairy Queen and McDonalds.
Histograms of Sodium Distribution
ggplot(fastfood, aes(x=sodium)) + geom_histogram(binwidth = 60) + labs(x="sodium", y="items on menu", title="Sodium Amount per Item") +
facet_wrap(~fastfood$restaurant)

Normal Probability Plots for Sodium Distribution
ggplot(data = fastfood, aes(sample = sodium))+
geom_line(stat = "qq") +
facet_wrap(~fastfood$restaurant)

Creating Indvl QQ-Plots of Sodium Distribution
restaurants <- fastfood %>% distinct(restaurant)
chick_fil_a <- fastfood %>%
filter(restaurant == "Chick Fil-A")
sonic <- fastfood %>%
filter(restaurant == "Sonic")
arbys <- fastfood %>%
filter(restaurant == "Arbys")
burger_king <- fastfood %>%
filter(restaurant == "Burger King")
subway <- fastfood %>%
filter(restaurant == "Subway")
taco_bell <- fastfood %>%
filter(restaurant == "Taco Bell")
Sonic
qqnorm(sonic$sodium,main="QQ Plot: Sonic - Sodium Distrbution")
qqline(sonic$sodium)

qqnormsim(sample = sodium, data = sonic)

Arbys
qqnorm(arbys$sodium,main="QQ Plot: Arbys - Sodium Distribution")
qqline(arbys$sodium)

qqnormsim(sample = sodium, data = arbys)

Taco Bell
qqnorm(taco_bell$sodium,main="QQ Plot: Taco Bell - Sodium Distribution")
qqline(taco_bell$sodium)

qqnormsim(sample = sodium, data = taco_bell)

Burger King
qqnorm(burger_king$sodium,main="QQ Plot: Burger King - Sodium Distribution")
qqline(burger_king$sodium)

qqnormsim(sample = sodium, data = burger_king)

Subway
qqnorm(subway$sodium,main="QQ Plot: Subway - Sodium Distribution")
qqline(subway$sodium)

qqnormsim(sample = sodium, data = subway)

Chick-Fil A
qqnorm(chick_fil_a$sodium,main="QQ Plot: Chick Fil-A - Sodium Distribution")
qqline(chick_fil_a$sodium)

qqnormsim(sample = sodium, data = chick_fil_a)

McDonalds
qqnorm(mcdonalds$sodium,main="QQ Plot: McDonalds - Sodium Distribution")
qqline(mcdonalds$sodium)

qqnormsim(sample = sodium, data = mcdonalds)

Dairy Queen
qqnorm(mcdonalds$sodium,main="QQ Plot: Dairy Queen - Sodium Distribution")
qqline(dairy_queen$sodium)

qqnormsim(sample = sodium, data = dairy_queen)

Exercise 8
Stepwise patterns exist when there are repeating values. Many of the menu offerings likely have similar sodium levels to them.
Exercise 9
Looking at McDonald’s QQ plot, it appears the total carb distribution is for the most part normally distributed but with a slight right skew where some extreme values exist in the sample. This is confirmed by looking at the histogram.
ggplot(data = mcdonalds, aes(sample = total_carb))+
geom_line(stat = "qq")

qqnormsim(sample = total_carb, data = mcdonalds)

qqnorm(mcdonalds$total_carb,main="QQ Plot: McDonalds - Carb Distribution")
qqline(mcdonalds$total_carb)

ggplot(mcdonalds, aes(x=total_carb)) + geom_histogram(binwidth = 5) + labs(x="total carbohydrates", y="items on menu", title="Carbohydrates per Item")

LS0tDQp0aXRsZTogIkxhYiA0IC0gTm9ybWFsIERpc3RyaWJ1dGlvbiINCmF1dGhvcjogIkNhc3NhbmRyYSBCb3lsYW4iDQpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiDQpvdXRwdXQ6IG9wZW5pbnRybzo6bGFiX3JlcG9ydA0KLS0tDQoNCiMjIyBMb2FkIHBhY2thZ2VzDQpgYGB7ciBsb2FkLWRhdGEsIG1lc3NhZ2U9RkFMU0V9DQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkob3BlbmludHJvKQ0KaGVhZChmYXN0Zm9vZCkNCmBgYA0KDQpgYGB7ciBzdWJzZXQtYnktcmVzdGFydXJhbnR9DQptY2RvbmFsZHMgPC0gZmFzdGZvb2QgJT4lDQogIGZpbHRlcihyZXN0YXVyYW50ID09ICJNY2RvbmFsZHMiKQ0KDQpkYWlyeV9xdWVlbiA8LSBmYXN0Zm9vZCAlPiUNCiAgZmlsdGVyKHJlc3RhdXJhbnQgPT0gIkRhaXJ5IFF1ZWVuIikNCmBgYA0KDQojIyMgRXhlcmNpc2UgMQ0KYGBge3IgcGxvdC1tY2R9DQpnZ3Bsb3QobWNkb25hbGRzLCBhZXMoeD1jYWxfZmF0KSkgKyBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDQwKSArIGxhYnMoeD0iY2Fsb3JpZXMgZnJvbSBmYXQiLCB5PSJpdGVtcyBvbiBtZW51IiwgdGl0bGUgPSJNY0RvbmFsZHMiKQ0KYGBgDQoNCk1jRG9uYWxkcyBoYXMgYSBtdWNoIGxhcmdlciBzcHJlYWQgdG8gaXRzIGRhdGEgd2l0aCBzaWduaWZpY2FudCBvdXRsaWVycy4gVGhlIElRUiBsb29rcyB0byBiZSB3aXRoaW4gdG8gMTAwLTQwMCBjYWxvcmllIHJhbmdlLiBUaGVyZSBpcyBhIGRlZmluYWJsZSBjZW50ZXIgdG8gdGhlIGRhdGEgYXJvdW5kIDIwMC0zMDAgY2Fsb3JpZSB2YWx1ZS4gIFRoZSBzaGFwZSBhcHBlYXJzIHNvbWV3aGF0IHN5bW1ldHJpY2FsIGFuZCBiZWxsIGN1cnZlZCBhbHRob3VnaCB0aGVyZSBpcyBzZWNvbmQgcGVhayBuZWFyZXIgdG8gMTAwIGNhbG9yaWVzLg0KICANCmBgYHtyIHBsb3QtZHF9DQpnZ3Bsb3QoZGFpcnlfcXVlZW4sIGFlcyh4PWNhbF9mYXQpKSArIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gNDApICsgbGFicyh4PSJjYWxvcmllcyBmcm9tIGZhdCIsIHk9Iml0ZW1zIG9uIG1lbnUiLCB0aXRsZT0iRGFpcnkgUXVlZW4iKQ0KYGBgDQogIA0KRGFpcnkgUXVlZW4gaGFzIGEgY2VudGVyIGFyb3VuZCAxNTAgd2l0aCBzb21lIHNrZXcgdG8gdGhlIGxlZnQuICBUaGUgZGF0YSBhbHNvIGFwcGVhcnMgc29tZXdoYXQgYmVsbCBjdXJ2ZWQgYW5kIHN5bW1ldHJpY2FsIGFyb3VuZCBpdHMgY2VudGVyLg0KDQoNCiMjIyBFeGVyY2lzZSAyDQoNCmBgYHtyIGRxLW1lYXN1cmVzLW9mLWNlbnRlci1jYWxvcmllc30NCmRxbWVhbiA8LSBtZWFuKGRhaXJ5X3F1ZWVuJGNhbF9mYXQpDQpkcXNkICAgPC0gc2QoZGFpcnlfcXVlZW4kY2FsX2ZhdCkNCmBgYA0KDQpgYGB7ciBoaXN0LWRxfQ0KZ2dwbG90KGRhdGEgPSBkYWlyeV9xdWVlbiwgYWVzKHggPSBjYWxfZmF0KSkgKw0KICAgICAgICBnZW9tX2JsYW5rKCkgKw0KICAgICAgICBnZW9tX2hpc3RvZ3JhbShhZXMoeSA9IC4uZGVuc2l0eS4uKSkgKw0KICAgICAgICBzdGF0X2Z1bmN0aW9uKGZ1biA9IGRub3JtLCBhcmdzID0gYyhtZWFuID0gZHFtZWFuLCBzZCA9IGRxc2QpLCBjb2wgPSAidG9tYXRvIikNCmBgYA0KDQpUaGUgZGVuc2l0eSBmdW5jdGlvbiBhcHBlYXJzIHRvIGhhdmUgYSBmYWlybHkgZmxhdCBidXQgdW5kZW5pYWJsZSB1bmltb2RhbCBzaGFwZSB3aGVyZSBpdHMgcGVhayBoYXMgZ3JlYXRlc3QgZGVuc2l0eS4gIEkgd291bGQgYWdyZWUgdGhhdCB0aGlzIGRhdGEgaXMgbm9ybWFsbHkgZGlzdHJpYnV0ZWQuDQoNCmBgYHtyIHFxfQ0KZ2dwbG90KGRhdGEgPSBkYWlyeV9xdWVlbiwgYWVzKHNhbXBsZSA9IGNhbF9mYXQpKSArIA0KICBnZW9tX2xpbmUoc3RhdCA9ICJxcSIpDQpgYGANCg0KYGBge3Igc2ltLW5vcm19DQpzaW1fbm9ybSA8LSBybm9ybShuID0gbnJvdyhkYWlyeV9xdWVlbiksIG1lYW4gPSBkcW1lYW4sIHNkID0gZHFzZCkNCmBgYA0KDQojIyMgRXhlcmNpc2UgMw0KDQpgYGB7cn0NCnFxbm9ybShzaW1fbm9ybSkNCnFxbGluZShzaW1fbm9ybSkNCmBgYA0KDQpOb3QgYWxsIHRoZSBwb2ludHMgZmFsbCBlbnRpcmVseSBvbiB0aGUgbGluZSBhcyB0aGlzIGlzIHJhbmRvbWl6ZWQgc2ltdWxhdGVkIGRhdGE7IHRoZSByZXNpZHVhbHMgbG9vayB0byBiZSB2ZXJ5IHNtYWxsIGhvd2V2ZXIgd2hpY2ggbWFrZXMgc2Vuc2Ugc2luY2UgdGhpcyBpcyBzaW11bGF0ZWQgbm9ybWFsbHkgZGlzdHJpYnV0ZWQgZGF0YS4NCg0KYGBge3J9DQpxcW5vcm0oZGFpcnlfcXVlZW4kY2FsX2ZhdCxtYWluPSJRUSBQbG90OiBEUSAtIENhbG9yaWVzIGZyb20gRmF0IikNCnFxbGluZShkYWlyeV9xdWVlbiRjYWxfZmF0KQ0KYGBgDQpJbiB0aGUgcHJvYmFiaWxpdHkgcGxvdCBvZiB0aGUgcmVhbCBkYXRhLCB0aGUgZGF0YXBvaW50cyBkbyBhZGhlcmUgdG8gYSBsaW5lYXIgcGF0dGVybiBpbmRpY2F0aW5nIG5vcm1hbCBkaXN0cmlidXRpb24gYnV0IGxpZnQgdXB3YXJkIGFuZCBhd2F5IGZyb20gdGhlIHRoZW9yZXRpY2FsIGxpbmUuICBUaGlzIGluZGljYXRlcyB0aGF0IHRoZSBhY3R1YWwgdmFsdWVzIGFyZSBtdWNoIGdyZWF0ZXIgdGhhbiB0aGUgZXhwZWN0ZWQgdmFsdWVzIGlmIHRoaXMgZGF0YSB3ZXJlIHBlcmZlY3RseSBhbmQgbm9ybWFsbHkgc3ltbWV0cmljYWwuICBUaGUgbGlmdCBpbmRpY2F0ZXMgdGhhdCB0aGlzIGlzIHNrZXdlZCB0byB0aGUgcmlnaHQgLSBtb3N0IGRhdGEgcG9pbnRzIGFyZSBkaXN0cmlidXRlZCBvbiB0aGUgbGVmdCB3aXRoIGEgbG9uZyB0YWlsIG9mIGV4dHJlbWUgdmFsdWVzIHRvIHRoZSByaWdodC4gIFRoaXMgbGluZXMgdXAgd2l0aCB3aGF0IHdlIHNhdyBpbiB0aGUgaGlzdG9ncmFtIG9mIHRoZSBzYW1lIGRhdGEuDQoNCiMjIyBFeGVyY2lzZSA0DQpgYGB7ciBxcW5vcm1zaW19DQpxcW5vcm1zaW0oc2FtcGxlID0gY2FsX2ZhdCwgZGF0YSA9IGRhaXJ5X3F1ZWVuKQ0KYGBgDQoNClllcywgdGhlIGFjdHVhbCByZWFsIGRhdGEgbG9va3MgcHJldHR5IHNpbWlsYXIgdG8gdGhlIHNpbXVsYXRpb25zLiAgVGhlIGxpZnQgYXQgdGhlIGZhciByaWdodCBpcyBzdGlsbCBub3RpY2VhYmx5IGRpZmZlcmVudCB0aGFuIHRoZSBub3JtYWxseSBkaXN0cmlidXRlZCBzaW11bGF0aW9ucyAtIHRoYXQgZGV2aWF0aW9uIGluZGljYXRlcyBzb21lIGRldmlhdGlvbiBhd2F5IGZyb20gYmVpbmcgc3ltbWV0cmljYWxseSBkaXN0cmlidXRlZC4NCg0KIyMjIEV4ZXJjaXNlIDUNClRoZSBwb2ludHMgc2hvdyBhIG1vcmUgbm90aWNlYWJsZSBjdXJ2ZSByYXRoZXIgdGhhbiBhIHN0cmFpZ2h0IGxpbmUgaW4gdGhpcyBxcSBwbG90LiAgVGhlIGxpZnQgYXQgdGhlIHRvcCByaWdodCBpcyBtdWNoIG1vcmUgcHJvbm91bmNlZCAtIHRoZSBkZXZpYXRpb24gYXdheSBmcm9tIGxpbmVhcml0eSBpbmRpY2F0ZXMgZGV2aWF0aW9uIGF3YXkgZnJvbSB0aGUgZGF0YSBiZWluZyBub3JtYWxseSBkaXN0cmlidXRlZC4gIA0KICANCkFnYWluLCB0aGUgbGlmdCBvZiBhY3R1YWwgZGF0YSB2cyB0aGUgZXhwZWN0ZWQgaW5kaWNhdGVzIHRoZSBkYXRhIGlzIGFnYWluIHNrZXdlZCB0byB0aGUgcmlnaHQuIFRoaXMgY3VydmUgaXMgbW9yZSBwcm9ub3VuY2VkIGluIE1jRG9uYWxkJ3MgbWVudSBpdGVtcyB0aGFuIGluIERRJ3MuICAgTWNEb25hbGRzIGhhcyBtb3JlIGV4dHJlbWUgdmFsdWVzIGlzIGl0cyB0YWlsIHRvIHRoZSByaWdodCB0aGFuIERRIGhhcy4NCmBgYHtyIHFxLXBsb3RzfQ0KZ2dwbG90KGRhdGEgPSBtY2RvbmFsZHMsIGFlcyhzYW1wbGUgPSBjYWxfZmF0KSkgKyANCiAgZ2VvbV9saW5lKHN0YXQgPSAicXEiKQ0KDQpxcW5vcm1zaW0oc2FtcGxlID0gY2FsX2ZhdCwgZGF0YSA9IG1jZG9uYWxkcykNCmBgYA0KDQpgYGB7ciBtY2QtbWVhc3VyZXMtb2YtY2VudGVyfQ0KbWNkbWVhbiA8LSBtZWFuKG1jZG9uYWxkcyRjYWxfZmF0KQ0KbWNkc2QgICA8LSBzZChtY2RvbmFsZHMkY2FsX2ZhdCkNCmBgYA0KDQpgYGB7ciBzaW0tbm9ybS1tY2R9DQpzaW1fbm9ybV9tY2QgPC0gcm5vcm0obiA9IG5yb3cobWNkb25hbGRzKSwgbWVhbiA9IG1jZG1lYW4sIHNkID0gbWNkc2QpDQpgYGANCg0KYGBge3J9DQpxcW5vcm0oc2ltX25vcm1fbWNkKQ0KcXFsaW5lKHNpbV9ub3JtX21jZCkNCmBgYA0KDQpgYGB7cn0NCnFxbm9ybShtY2RvbmFsZHMkY2FsX2ZhdCwgbWFpbj0iUVEgUGxvdDogTWNEIC0gQ2Fsb3JpZXMgZnJvbSBGYXQiKQ0KcXFsaW5lKG1jZG9uYWxkcyRjYWxfZmF0KQ0KYGBgDQoNCiMjIyBFeGVyY2lzZSA2DQoNCkxldCdzIHNheSBJIGFtIGxvb2tpbmcgdG8gc3RhcnQgZWF0aW5nIGhlYWx0aGllciwgc3RhcnRpbmcgd2l0aCBjaG9vc2luZyBtb3JlIGhlYWx0aGllciBtZW51IGl0ZW1zIHdoZW4gZWF0aW5nIGZhc3Rmb29kLiAgU2luY2UgdGhlIHJlY29tbWVuZGVkIGFtb3VudCBvZiBjYWxvcmllcyBmcm9tIGZhdCBpcyBhYm91dCA2MDAgKG9yIDMwJSBvZiBhIHRyYWRpdGlvbmFsIDIwMDApLCBJJ20gb25seSBsb29raW5nIGZvciBtZW51IGl0ZW1zIHRoYXQgYXJlIHdpbGwgYWNjb3VudCBmb3Igcm91Z2hseSAxLzMgb2YgdGhpcyB0b3RhbCBkYWlseSBhbW91bnQuIEkgd2FudCB0byBrbm93IHdoYXQgdGhlIHByb2JhYmlsaXR5IGlzIHRoYXQgYW4gbWVudSBpdGVtIHRoYXQgZWl0aGVyIG1jZCdzIG9yIGRxIG9mZmVycyB3aWxsIGJlIHdpdGhpbiAxNTAgdG8gMjUwIGNhbG9yaWVzIGZyb20gZmF0LiAgRW5vdWdoIGZhdCB0byB0YXN0ZSwgYnV0IG5vdCBlbm91Z2ggZm9yIGhlYXJ0YnVybiA6KQ0KDQoqKlRoZW9yZXRpY2FsIHByb2JhYmlsaXR5IHRoYXQgbWVudSBpdGVtIGZyb20gRGFpcnkgUXVlZW4gaXMgYmV0d2VlbiAxNTAgdG8gMjUwIGNhbG9yaWVzOioqDQpgYGB7cn0NCnJvdW5kKHBub3JtKHEgPSAyNTAsIG1lYW4gPSBkcW1lYW4sIHNkID0gZHFzZCkgLSANCiAgcG5vcm0ocSA9IDE1MCwgbWVhbiA9IGRxbWVhbiwgc2QgPSBkcXNkKSwzKQ0KYGBgDQogIA0KKipFbXBpcmljYWwgcHJvYmFiaWxpdHkgdGhhdCBtZW51IGl0ZW0gZnJvbSBEYWlyeSBRdWVlbiBpcyBiZXR3ZWVuIDE1MCB0byAyNTAgY2Fsb3JpZXM6KioNCmBgYHtyIHByb2JhYmlsaXR5LWRxIGNhbG9yaWVzfQ0KZGFpcnlfcXVlZW4gJT4lIA0KICBmaWx0ZXIoY2FsX2ZhdCA+PSAxNTAgJiBjYWxfZmF0IDw9IDI1MCkgJT4lDQogIHN1bW1hcmlzZShwZXJjZW50ID0gbigpIC8gbnJvdyhkYWlyeV9xdWVlbikpDQpgYGANCg0KKipUaGVvcmV0aWNhbCBwcm9iYWJpbGl0eSB0aGF0IG1lbnUgaXRlbSBmcm9tIE1jRG9uYWxkcyBpcyBiZXR3ZWVuIDE1MCB0byAyNTAgY2Fsb3JpZXM6KioNCmBgYHtyfQ0Kcm91bmQocG5vcm0ocSA9IDI1MCwgbWVhbiA9IG1jZG1lYW4sIHNkID0gbWNkc2QpIC0gDQogIHBub3JtKHEgPSAxNTAsIG1lYW4gPSBtY2RtZWFuLCBzZCA9IG1jZHNkKSwzKQ0KYGBgDQogIA0KKipFbXBpcmljYWwgcHJvYmFiaWxpdHkgdGhhdCBtZW51IGl0ZW0gZnJvbSBNY0RvbmFsZHMgaXMgYmV0d2VlbiAxNTAgdG8gMjUwIGNhbG9yaWVzOioqDQpgYGB7ciBwcm9iYWJpbGl0eS1tY2QgY2Fsb3JpZXN9DQptY2RvbmFsZHMgJT4lIA0KICBmaWx0ZXIoY2FsX2ZhdCA+PSAxNTAgJiBjYWxfZmF0IDw9IDI1MCkgJT4lDQogIHN1bW1hcmlzZShwZXJjZW50ID0gbigpIC8gbnJvdyhtY2RvbmFsZHMpKQ0KYGBgDQoNClRoZSB0aGVvcmV0aWNhbCBwcm9iYWJpbGl0eSAoYmFzZWQgb24gYXNzdW1wdGlvbiBvZiBub3JtYWwgZGlzdHJpYnV0aW9uKSBnYXZlIGEgbXVjaCBzbGltbWVyIHByb2JhYmlsaXR5IG9mIGEgbWVudSBpdGVtIGJlaW5nIHdpdGhpbiB0aGUgcmFuZ2Ugb2YgMTUwIGFuZCAyNTAgY2Fsb3JpZXMsIHJlc3BlY3RpdmVseSAyMyUgYW5kIDE2LjclLiAgV2hlbiBsb29raW5nIGF0IHRoZSBtZWFucyBhbmQgc3RhbmRhcmQgZGV2aWF0aW9uIG9mIHRoZSAyIGRpc3RyaWJ1dGlvbnMsIHRoaXMgbWFrZXMgc2Vuc2UgdGhhdCAxMDAgY2Fsb3JpZSByYW5nZSBiZWxvdyBtZWFuIHdvdWxkIG5ldCB0aGVzZSB2YWx1ZXMuICANCg0KSG93ZXZlciAtIHVuc3VycHJpc2luZ2x5IHNpbmNlIHdlIHZpZXdlZCB0aGUgZGF0YSB2aXN1YWxseSBhbmQga25vdyB0aGF0IG1ham9yaXR5IG9mIHRoZSBkaXN0cmlidXRpb24gZm9yIGJvdGggRGFpcnkgUXVlZW4gYW5kIE1jRG9uYWxkcyBpcyBza2V3ZWQgdG8gdGhlIHJpZ2h0IC0gdGhlIGVtcGlyaWNhbCBwcm9iYWJpbGl0aWVzIGluIGJvdGggY2FzZXMgaXMgbXVjaCBncmVhdGVyLiAgIA0KDQpUaGVyZSBpcyBhIDM4JSBlbXBpcmljYWwgcHJvYmFiaWxpdHkgb2YgYSBtZW51IGl0ZW0gaGF2aW5nIGJldHdlZW4gMTUwIGFuZCAyNTAgY2Fsb3JpZXMgZnJvbSBmYXQgaW4gdGhlIGNhc2Ugb2YgRFEsIGFuZCBhIDM2LjglIHByb2JhYmlsaXR5IGluIHRoZSBjYXNlIG9mIE1jRG9uYWxkcy4gVGhlIHJpZ2h0IHRhaWxzIG9mIGJvdGggZGlzdHJpYnV0aW9ucyBpbmRpY2F0ZSB0aGF0IHRoZXJlIGFyZSBleHRyZW1lIHZhbHVlcyBkaXN0b3J0aW5nIHRoZSBhdmVyYWdlIG9mIHRoaXMgZGF0YXNldCwgc3VnZ2VzdGluZyBhIGNlbnRlciBtdWNoIGZhcnRoZXIgdG8gdGhlIHJpZ2h0IHRoYW4gYWN0dWFsbHkgZXhpc3RzLiAgDQoNCk9mIHRoZSB0d28sIERRIGhhZCBhIGNsb3NlciBwcmVkaWN0ZWQgdGhlb3JldGljYWwgcHJvYmFiaWxpdHkgLSAxNSUgb2ZmICgzOCAtIDIzKSB0aGFuIE1jRG9uYWxkcyAtIDIwJSBvZmYgKDM2LjggLSAxNi43KS4gIFRoaXMgaXMgYWxzbyB1bnN1cnByaXNpbmcgZ2l2ZW4gdGhhdCB3ZSB0aGUgbW9yZSBzaWduaWZpY2FudCBsaWZ0IGluIHRoZSBRUSBwbG90IG9mIE1jRG9uYWxkcywgaW5kaWNhdGluZyB0aGF0IE1jRG9uYWxkJ3MgaGFkIG1vcmUgZXh0cmVtZSB2YWx1ZXMgdGhhbiBkaWQgRFEsIGFuZCB0aGVyZWZvcmUgbW9yZSBncmVhdGx5IGRpc3RvcnRpbmcgdGhlIGFjdHVhbCBjZW50ZXIgYW5kIHNwcmVhZC4NCg0KIyMjIEV4ZXJjaXNlIDcNCkV2YWx1YXRpbmcgZm9yIE5vcm1hbCBEaXN0cmlidXRpb24gaW4gU29kaXVtIGJ5IFJlc3RhdXJhbnQ6DQogIA0KT24gcmV2aWV3IG9mIHRoZSBRUSBwbG90cyBvZiBlYWNoIHJlc3RhdXJhbnQsIGl0IGFwcGVhcnMgdGhhdCBBcmJ5J3MsIEJ1cmdlciBLaW5nLCBhbmQgVGFjbyBCZWxsIG1vc3QgY2xlYXJseSBtaXJyb3IgYSBub3JtYWwgZGlzdHJpYnV0aW9uLiAgVGhlcmUgd2FzIHNvbWUgY3VydmF0dXJlIGluIENoaWNrLUZpbC1BLCBTb25pYywgYW5kIFN1YndheTsgdGhlIG1vc3QgcHJvbm91bmNlZCBsaWZ0IChpbmRpY2F0aW5nIHJpZ2h0IHNrZXcpIGFwcGVhcnMgaW4gRGFpcnkgUXVlZW4gYW5kIE1jRG9uYWxkcy4gIA0KICANCioqSGlzdG9ncmFtcyBvZiBTb2RpdW0gRGlzdHJpYnV0aW9uKiogICAgDQpgYGB7ciBwbG90LWhpc3QtYWxsLXJlc3RhdXJhbnRzfQ0KZ2dwbG90KGZhc3Rmb29kLCBhZXMoeD1zb2RpdW0pKSArIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gNjApICsgbGFicyh4PSJzb2RpdW0iLCB5PSJpdGVtcyBvbiBtZW51IiwgdGl0bGU9IlNvZGl1bSBBbW91bnQgcGVyIEl0ZW0iKSArDQogIGZhY2V0X3dyYXAofmZhc3Rmb29kJHJlc3RhdXJhbnQpDQpgYGANCg0KKipOb3JtYWwgUHJvYmFiaWxpdHkgUGxvdHMgZm9yIFNvZGl1bSBEaXN0cmlidXRpb24qKg0KYGBge3IgcXEtcGxvdC1hbGwtcmVzdGF1cmFudHN9DQpnZ3Bsb3QoZGF0YSA9IGZhc3Rmb29kLCBhZXMoc2FtcGxlID0gc29kaXVtKSkrIA0KICBnZW9tX2xpbmUoc3RhdCA9ICJxcSIpICsgIA0KICBmYWNldF93cmFwKH5mYXN0Zm9vZCRyZXN0YXVyYW50KQ0KYGBgDQoNCioqQ3JlYXRpbmcgSW5kdmwgUVEtUGxvdHMgb2YgU29kaXVtIERpc3RyaWJ1dGlvbioqDQpgYGB7ciBzdWJzZXQgZWFjaCBzYW1wbGUgb2JzZXJ2YXRpb25zIGJ5IHJlc3RhdXJhbnR9DQpyZXN0YXVyYW50cyA8LSBmYXN0Zm9vZCAlPiUgZGlzdGluY3QocmVzdGF1cmFudCkNCg0KY2hpY2tfZmlsX2EgPC0gZmFzdGZvb2QgJT4lDQogIGZpbHRlcihyZXN0YXVyYW50ID09ICJDaGljayBGaWwtQSIpDQoNCnNvbmljIDwtIGZhc3Rmb29kICU+JQ0KICBmaWx0ZXIocmVzdGF1cmFudCA9PSAiU29uaWMiKQ0KDQphcmJ5cyA8LSBmYXN0Zm9vZCAlPiUNCiAgZmlsdGVyKHJlc3RhdXJhbnQgPT0gIkFyYnlzIikNCg0KYnVyZ2VyX2tpbmcgPC0gZmFzdGZvb2QgJT4lDQogIGZpbHRlcihyZXN0YXVyYW50ID09ICJCdXJnZXIgS2luZyIpDQoNCnN1YndheSA8LSBmYXN0Zm9vZCAlPiUNCiAgZmlsdGVyKHJlc3RhdXJhbnQgPT0gIlN1YndheSIpDQoNCnRhY29fYmVsbCA8LSBmYXN0Zm9vZCAlPiUNCiAgZmlsdGVyKHJlc3RhdXJhbnQgPT0gIlRhY28gQmVsbCIpDQoNCmBgYA0KICAgIA0KKipTb25pYyoqDQpgYGB7ciBxcS1wbG90cy1zb25pYyB9DQpxcW5vcm0oc29uaWMkc29kaXVtLG1haW49IlFRIFBsb3Q6IFNvbmljIC0gU29kaXVtIERpc3RyYnV0aW9uIikNCnFxbGluZShzb25pYyRzb2RpdW0pDQpxcW5vcm1zaW0oc2FtcGxlID0gc29kaXVtLCBkYXRhID0gc29uaWMpDQpgYGANCiAgDQoqKkFyYnlzKioNCmBgYHtyIHFxLXBsb3RzLWFyYnlzfQ0KcXFub3JtKGFyYnlzJHNvZGl1bSxtYWluPSJRUSBQbG90OiBBcmJ5cyAtIFNvZGl1bSBEaXN0cmlidXRpb24iKQ0KcXFsaW5lKGFyYnlzJHNvZGl1bSkNCnFxbm9ybXNpbShzYW1wbGUgPSBzb2RpdW0sIGRhdGEgPSBhcmJ5cykNCmBgYA0KDQoqKlRhY28gQmVsbCoqDQpgYGB7ciBxcS1wbG90cy10YWNvLWJlbGx9DQpxcW5vcm0odGFjb19iZWxsJHNvZGl1bSxtYWluPSJRUSBQbG90OiBUYWNvIEJlbGwgLSBTb2RpdW0gRGlzdHJpYnV0aW9uIikNCnFxbGluZSh0YWNvX2JlbGwkc29kaXVtKQ0KcXFub3Jtc2ltKHNhbXBsZSA9IHNvZGl1bSwgZGF0YSA9IHRhY29fYmVsbCkNCmBgYA0KDQoqKkJ1cmdlciBLaW5nKioNCmBgYHtyIHFxLXBsb3RzLWJ1cmdlci1raW5nfQ0KcXFub3JtKGJ1cmdlcl9raW5nJHNvZGl1bSxtYWluPSJRUSBQbG90OiBCdXJnZXIgS2luZyAtIFNvZGl1bSBEaXN0cmlidXRpb24iKQ0KcXFsaW5lKGJ1cmdlcl9raW5nJHNvZGl1bSkNCnFxbm9ybXNpbShzYW1wbGUgPSBzb2RpdW0sIGRhdGEgPSBidXJnZXJfa2luZykNCmBgYA0KDQoqKlN1YndheSoqDQpgYGB7ciBxcS1wbG90cy1zdWJ3YXl9DQpxcW5vcm0oc3Vid2F5JHNvZGl1bSxtYWluPSJRUSBQbG90OiBTdWJ3YXkgLSBTb2RpdW0gRGlzdHJpYnV0aW9uIikNCnFxbGluZShzdWJ3YXkkc29kaXVtKQ0KcXFub3Jtc2ltKHNhbXBsZSA9IHNvZGl1bSwgZGF0YSA9IHN1YndheSkNCmBgYA0KDQoqKkNoaWNrLUZpbCBBKioNCmBgYHtyIHFxLXBsb3RzLWNoaWNrLWZpbC1hfQ0KcXFub3JtKGNoaWNrX2ZpbF9hJHNvZGl1bSxtYWluPSJRUSBQbG90OiBDaGljayBGaWwtQSAtIFNvZGl1bSBEaXN0cmlidXRpb24iKQ0KcXFsaW5lKGNoaWNrX2ZpbF9hJHNvZGl1bSkNCnFxbm9ybXNpbShzYW1wbGUgPSBzb2RpdW0sIGRhdGEgPSBjaGlja19maWxfYSkNCmBgYA0KDQoqKk1jRG9uYWxkcyoqDQpgYGB7ciBxcS1wbG90cy1tY2R9DQpxcW5vcm0obWNkb25hbGRzJHNvZGl1bSxtYWluPSJRUSBQbG90OiBNY0RvbmFsZHMgLSBTb2RpdW0gRGlzdHJpYnV0aW9uIikNCnFxbGluZShtY2RvbmFsZHMkc29kaXVtKQ0KcXFub3Jtc2ltKHNhbXBsZSA9IHNvZGl1bSwgZGF0YSA9IG1jZG9uYWxkcykNCmBgYA0KDQoqKkRhaXJ5IFF1ZWVuKioNCmBgYHtyIHFxLXBsb3RzLWRxfQ0KcXFub3JtKG1jZG9uYWxkcyRzb2RpdW0sbWFpbj0iUVEgUGxvdDogRGFpcnkgUXVlZW4gLSBTb2RpdW0gRGlzdHJpYnV0aW9uIikNCnFxbGluZShkYWlyeV9xdWVlbiRzb2RpdW0pDQpxcW5vcm1zaW0oc2FtcGxlID0gc29kaXVtLCBkYXRhID0gZGFpcnlfcXVlZW4pDQpgYGANCg0KIyMjIEV4ZXJjaXNlIDgNCg0KU3RlcHdpc2UgcGF0dGVybnMgZXhpc3Qgd2hlbiB0aGVyZSBhcmUgcmVwZWF0aW5nIHZhbHVlcy4gIE1hbnkgb2YgdGhlIG1lbnUgb2ZmZXJpbmdzIGxpa2VseSBoYXZlIHNpbWlsYXIgc29kaXVtIGxldmVscyB0byB0aGVtLg0KDQojIyMgRXhlcmNpc2UgOQ0KDQpMb29raW5nIGF0IE1jRG9uYWxkJ3MgUVEgcGxvdCwgaXQgYXBwZWFycyB0aGUgdG90YWwgY2FyYiBkaXN0cmlidXRpb24gaXMgZm9yIHRoZSBtb3N0IHBhcnQgbm9ybWFsbHkgZGlzdHJpYnV0ZWQgYnV0IHdpdGggYSBzbGlnaHQgcmlnaHQgc2tldyB3aGVyZSBzb21lIGV4dHJlbWUgdmFsdWVzIGV4aXN0IGluIHRoZSBzYW1wbGUuICBUaGlzIGlzIGNvbmZpcm1lZCBieSBsb29raW5nIGF0IHRoZSBoaXN0b2dyYW0uDQpgYGB7cn0NCmdncGxvdChkYXRhID0gbWNkb25hbGRzLCBhZXMoc2FtcGxlID0gdG90YWxfY2FyYikpKyANCiAgZ2VvbV9saW5lKHN0YXQgPSAicXEiKQ0KDQpxcW5vcm1zaW0oc2FtcGxlID0gdG90YWxfY2FyYiwgZGF0YSA9IG1jZG9uYWxkcykNCnFxbm9ybShtY2RvbmFsZHMkdG90YWxfY2FyYixtYWluPSJRUSBQbG90OiBNY0RvbmFsZHMgLSBDYXJiIERpc3RyaWJ1dGlvbiIpDQpxcWxpbmUobWNkb25hbGRzJHRvdGFsX2NhcmIpDQoNCmdncGxvdChtY2RvbmFsZHMsIGFlcyh4PXRvdGFsX2NhcmIpKSArIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gNSkgKyBsYWJzKHg9InRvdGFsIGNhcmJvaHlkcmF0ZXMiLCB5PSJpdGVtcyBvbiBtZW51IiwgdGl0bGU9IkNhcmJvaHlkcmF0ZXMgcGVyIEl0ZW0iKQ0KYGBgDQo=