suppressPackageStartupMessages(library("tidyverse"))
package 㤼㸱tidyverse㤼㸲 was built under R version 3.6.3

1. Explore the distribution of each of the x, y, and z variables in diamonds. What do you learn? Think about a diamond and how you might decide which dimension is the length, width, and depth.

First, I’ll calculate summary statistics for these variables and plot their distributions.

summary(select(diamonds, x, y, z))
       x                y                z         
 Min.   : 0.000   Min.   : 0.000   Min.   : 0.000  
 1st Qu.: 4.710   1st Qu.: 4.720   1st Qu.: 2.910  
 Median : 5.700   Median : 5.710   Median : 3.530  
 Mean   : 5.731   Mean   : 5.735   Mean   : 3.539  
 3rd Qu.: 6.540   3rd Qu.: 6.540   3rd Qu.: 4.040  
 Max.   :10.740   Max.   :58.900   Max.   :31.800  
ggplot(diamonds) +
  geom_histogram(mapping = aes(x = x), binwidth = 0.01)


ggplot(diamonds) +
  geom_histogram(mapping = aes(x = y), binwidth = 0.01)


ggplot(diamonds) +
  geom_histogram(mapping = aes(x = z), binwidth = 0.01)

There several noticeable features of the distributions:

  1. x and y are larger than z,
  2. there are outliers,
  3. they are all right skewed, and
  4. they are multimodal or “spiky”.

The typical values of x and y are larger than z, with x and y having inter-quartile ranges of 4.7-5.7, while z has an inter-quartile range of 2.9-4.0.

There are two types of outliers in this data. Some diamonds have values of zero and some have abnormally large values of x, y, or z.

summary(select(diamonds, x, y, z))
       x                y                z         
 Min.   : 0.000   Min.   : 0.000   Min.   : 0.000  
 1st Qu.: 4.710   1st Qu.: 4.720   1st Qu.: 2.910  
 Median : 5.700   Median : 5.710   Median : 3.530  
 Mean   : 5.731   Mean   : 5.735   Mean   : 3.539  
 3rd Qu.: 6.540   3rd Qu.: 6.540   3rd Qu.: 4.040  
 Max.   :10.740   Max.   :58.900   Max.   :31.800  

These appear to be either data entry errors, or an undocumented convention in the dataset for indicating missing values. An alternative hypothesis would be that values of zero are the result of rounding values like 0.002 down, but since there are no diamonds with values of 0.01, that does not seem to be the case.

filter(diamonds, x == 0 | y == 0 | z == 0)

There are also some diamonds with values of y and z that are abnormally large. There are diamonds with y == 58.9 and y == 31.8, and one with z == 31.8. These are probably data errors since the values do not seem in line with the values of the other variables.

diamonds %>%
  arrange(desc(y)) %>%
  head()

diamonds %>%
  arrange(desc(z)) %>%
  head()

Initially, I only considered univariate outliers. However, to check the plausibility of those outliers I would informally consider how consistent their values are with the values of the other variables. In this case, scatter plots of each combination of x, y, and z shows these outliers much more clearly.

ggplot(diamonds, aes(x = x, y = y)) +
  geom_point()


ggplot(diamonds, aes(x = x, y = z)) +
  geom_point()


ggplot(diamonds, aes(x = y, y = z)) +
  geom_point()

Removing the outliers from x, y, and z makes the distribution easier to see. The right skewness of these distributions is unsurprising; there should be more smaller diamonds than larger ones and these values can never be negative. More interestingly, there are spikes in the distribution at certain values. These spikes often, but not exclusively, occur near integer values. Without knowing more about diamond cutting, I can’t say more about what these spikes represent. If you know, add a comment. I would guess that some diamond sizes are used more often than others, and these spikes correspond to those sizes. Also, I would guess that a diamond cut and carat value of a diamond imply values of x, y, and z. Since there are spikes in the distribution of carat sizes, and only a few different cuts, that could result in these spikes. I’ll leave it to you to figure out if that’s the case.

filter(diamonds, x > 0, x < 10) %>%
  ggplot() +
  geom_histogram(mapping = aes(x = x), binwidth = 0.01) +
  scale_x_continuous(breaks = 1:10)


filter(diamonds, y > 0, y < 10) %>%
  ggplot() +
  geom_histogram(mapping = aes(x = y), binwidth = 0.01) +
  scale_x_continuous(breaks = 1:10)


filter(diamonds, z > 0, z < 10) %>%
  ggplot() +
  geom_histogram(mapping = aes(x = z), binwidth = 0.01) +
  scale_x_continuous(breaks = 1:10)

According to the documentation for diamonds, x is length, y is width, and z is depth. If documentation were unavailable, I would compare the values of the variables to match them to the length, width, and depth. I would expect length to always be less than width, otherwise the length would be called the width. I would also search for the definitions of length, width, and depth with respect to diamond cuts. Depth can be expressed as a percentage of the length/width of the diamond, which means it should be less than both the length and the width.

summarise(diamonds, mean(x > y), mean(x > z), mean(y > z))

It appears that depth (z) is always smaller than length (x) or width (y), perhaps because a shallower depth helps when setting diamonds in jewelry and due to how it affect the reflection of light. Length is more than width in less than half the observations, the opposite of my expectations.

2. Explore the distribution of price. Do you discover anything unusual or surprising? (Hint: Carefully think about the binwidth and make sure you try a wide range of values.)

  • The price data has many spikes, but I can’t tell what each spike corresponds to. The following plots don’t show much difference in the distributions in the last one or two digits.
  • There are no diamonds with a price of $1,500 (between $1,450 and $1,550).
  • There’s a bulge in the distribution around $750.
ggplot(filter(diamonds, price < 2500), aes(x = price)) +
  geom_histogram(binwidth = 10, center = 0)


ggplot(filter(diamonds), aes(x = price)) +
  geom_histogram(binwidth = 100, center = 0)

Distribution of last digit

diamonds %>%
  mutate(ending = price %% 10) %>%
  ggplot(aes(x = ending)) +
  geom_histogram(binwidth = 1, center = 0)


diamonds %>%
  mutate(ending = price %% 100) %>%
  ggplot(aes(x = ending)) +
  geom_histogram(binwidth = 1)


diamonds %>%
  mutate(ending = price %% 1000) %>%
  filter(ending >= 500, ending <= 800) %>%
  ggplot(aes(x = ending)) +
  geom_histogram(binwidth = 1)

3. How many diamonds are 0.99 carat? How many are 1 carat? What do you think is the cause of the difference?

There are more than 70 times as many 1 carat diamonds as 0.99 carat diamond.

diamonds %>%
  filter(carat >= 0.99, carat <= 1) %>%
  count(carat)

I don’t know exactly the process behind how carats are measured, but some way or another some diamonds carat values are being “rounded up” Presumably there is a premium for a 1 carat diamond vs. a 0.99 carat diamond beyond the expected increase in price due to a 0.01 carat increase.

To check this intuition, we would want to look at the number of diamonds in each carat range to see if there is an unusually low number of 0.99 carat diamonds, and an abnormally large number of 1 carat diamonds.

diamonds %>%
  filter(carat >= 0.9, carat <= 1.1) %>%
  count(carat) %>%
  print(n = Inf)

4. Compare and contrast coord_cartesian() vs xlim() or ylim() when zooming in on a histogram. What happens if you leave binwidth unset? What happens if you try and zoom so only half a bar shows?

The coord_cartesian() function zooms in on the area specified by the limits, after having calculated and drawn the geoms. Since the histogram bins have already been calculated, it is unaffected.

ggplot(diamonds) +
  geom_histogram(mapping = aes(x = price)) +
  coord_cartesian(xlim = c(100, 5000), ylim = c(0, 3000))

However, the xlim() and ylim() functions influence actions before the calculation of the stats related to the histogram. Thus, any values outside the x- and y-limits are dropped before calculating bin widths and counts. This can influence how the histogram looks.

ggplot(diamonds) +
  geom_histogram(mapping = aes(x = price)) +
  xlim(100, 5000) +
  ylim(0, 3000)

LS0tDQp0aXRsZTogIkV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXM6IFZhcmlhdGlvbiINCm91dHB1dDogDQogIGh0bWxfbm90ZWJvb2s6DQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0OiB0cnVlDQotLS0NCg0KYGBge3IgbG9hZGxpYnJhcnl9DQpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMobGlicmFyeSgidGlkeXZlcnNlIikpDQpgYGANCg0KIyMjIDEuIEV4cGxvcmUgdGhlIGRpc3RyaWJ1dGlvbiBvZiBlYWNoIG9mIHRoZSBgeGAsIGB5YCwgYW5kIGB6YCB2YXJpYWJsZXMgaW4gYGRpYW1vbmRzYC4gV2hhdCBkbyB5b3UgbGVhcm4/IFRoaW5rIGFib3V0IGEgZGlhbW9uZCBhbmQgaG93IHlvdSBtaWdodCBkZWNpZGUgd2hpY2ggZGltZW5zaW9uIGlzIHRoZSBsZW5ndGgsIHdpZHRoLCBhbmQgZGVwdGguDQoNCkZpcnN0LCBJ4oCZbGwgY2FsY3VsYXRlIHN1bW1hcnkgc3RhdGlzdGljcyBmb3IgdGhlc2UgdmFyaWFibGVzIGFuZCBwbG90IHRoZWlyIGRpc3RyaWJ1dGlvbnMuDQoNCmBgYHtyfQ0Kc3VtbWFyeShzZWxlY3QoZGlhbW9uZHMsIHgsIHksIHopKQ0KDQpnZ3Bsb3QoZGlhbW9uZHMpICsNCiAgZ2VvbV9oaXN0b2dyYW0obWFwcGluZyA9IGFlcyh4ID0geCksIGJpbndpZHRoID0gMC4wMSkNCg0KZ2dwbG90KGRpYW1vbmRzKSArDQogIGdlb21faGlzdG9ncmFtKG1hcHBpbmcgPSBhZXMoeCA9IHkpLCBiaW53aWR0aCA9IDAuMDEpDQoNCmdncGxvdChkaWFtb25kcykgKw0KICBnZW9tX2hpc3RvZ3JhbShtYXBwaW5nID0gYWVzKHggPSB6KSwgYmlud2lkdGggPSAwLjAxKQ0KYGBgDQoNClRoZXJlIHNldmVyYWwgbm90aWNlYWJsZSBmZWF0dXJlcyBvZiB0aGUgZGlzdHJpYnV0aW9uczoNCg0KMS4gYHhgIGFuZCBgeWAgYXJlIGxhcmdlciB0aGFuIGB6YCwNCjIuIHRoZXJlIGFyZSBvdXRsaWVycywNCjMuIHRoZXkgYXJlIGFsbCByaWdodCBza2V3ZWQsIGFuZA0KNC4gdGhleSBhcmUgbXVsdGltb2RhbCBvciDigJxzcGlreeKAnS4NCg0KVGhlIHR5cGljYWwgdmFsdWVzIG9mIGB4YCBhbmQgYHlgIGFyZSBsYXJnZXIgdGhhbiBgemAsIHdpdGggYHhgIGFuZCBgeWAgaGF2aW5nIGludGVyLXF1YXJ0aWxlIHJhbmdlcyBvZiA0LjctNS43LCB3aGlsZSBgemAgaGFzIGFuIGludGVyLXF1YXJ0aWxlIHJhbmdlIG9mIDIuOS00LjAuDQoNClRoZXJlIGFyZSB0d28gdHlwZXMgb2Ygb3V0bGllcnMgaW4gdGhpcyBkYXRhLiBTb21lIGRpYW1vbmRzIGhhdmUgdmFsdWVzIG9mIHplcm8gYW5kIHNvbWUgaGF2ZSBhYm5vcm1hbGx5IGxhcmdlIHZhbHVlcyBvZiBgeGAsIGB5YCwgb3IgYHpgLg0KDQpgYGB7cn0NCnN1bW1hcnkoc2VsZWN0KGRpYW1vbmRzLCB4LCB5LCB6KSkNCmBgYA0KDQpUaGVzZSBhcHBlYXIgdG8gYmUgZWl0aGVyIGRhdGEgZW50cnkgZXJyb3JzLCBvciBhbiB1bmRvY3VtZW50ZWQgY29udmVudGlvbiBpbiB0aGUgZGF0YXNldCBmb3IgaW5kaWNhdGluZyBtaXNzaW5nIHZhbHVlcy4gQW4gYWx0ZXJuYXRpdmUgaHlwb3RoZXNpcyB3b3VsZCBiZSB0aGF0IHZhbHVlcyBvZiB6ZXJvIGFyZSB0aGUgcmVzdWx0IG9mIHJvdW5kaW5nIHZhbHVlcyBsaWtlIGAwLjAwMmAgZG93biwgYnV0IHNpbmNlIHRoZXJlIGFyZSBubyBkaWFtb25kcyB3aXRoIHZhbHVlcyBvZiAwLjAxLCB0aGF0IGRvZXMgbm90IHNlZW0gdG8gYmUgdGhlIGNhc2UuDQoNCmBgYHtyfQ0KZmlsdGVyKGRpYW1vbmRzLCB4ID09IDAgfCB5ID09IDAgfCB6ID09IDApDQpgYGANCg0KVGhlcmUgYXJlIGFsc28gc29tZSBkaWFtb25kcyB3aXRoIHZhbHVlcyBvZiBgeWAgYW5kIGB6YCB0aGF0IGFyZSBhYm5vcm1hbGx5IGxhcmdlLiBUaGVyZSBhcmUgZGlhbW9uZHMgd2l0aCBgeSA9PSA1OC45YCBhbmQgYHkgPT0gMzEuOGAsIGFuZCBvbmUgd2l0aCBgeiA9PSAzMS44YC4gVGhlc2UgYXJlIHByb2JhYmx5IGRhdGEgZXJyb3JzIHNpbmNlIHRoZSB2YWx1ZXMgZG8gbm90IHNlZW0gaW4gbGluZSB3aXRoIHRoZSB2YWx1ZXMgb2YgdGhlIG90aGVyIHZhcmlhYmxlcy4NCg0KYGBge3J9DQpkaWFtb25kcyAlPiUNCiAgYXJyYW5nZShkZXNjKHkpKSAlPiUNCiAgaGVhZCgpDQoNCmRpYW1vbmRzICU+JQ0KICBhcnJhbmdlKGRlc2MoeikpICU+JQ0KICBoZWFkKCkNCmBgYA0KDQpJbml0aWFsbHksIEkgb25seSBjb25zaWRlcmVkIHVuaXZhcmlhdGUgb3V0bGllcnMuIEhvd2V2ZXIsIHRvIGNoZWNrIHRoZSBwbGF1c2liaWxpdHkgb2YgdGhvc2Ugb3V0bGllcnMgSSB3b3VsZCBpbmZvcm1hbGx5IGNvbnNpZGVyIGhvdyBjb25zaXN0ZW50IHRoZWlyIHZhbHVlcyBhcmUgd2l0aCB0aGUgdmFsdWVzIG9mIHRoZSBvdGhlciB2YXJpYWJsZXMuIEluIHRoaXMgY2FzZSwgc2NhdHRlciBwbG90cyBvZiBlYWNoIGNvbWJpbmF0aW9uIG9mIGB4YCwgYHlgLCBhbmQgYHpgIHNob3dzIHRoZXNlIG91dGxpZXJzIG11Y2ggbW9yZSBjbGVhcmx5Lg0KDQpgYGB7cn0NCmdncGxvdChkaWFtb25kcywgYWVzKHggPSB4LCB5ID0geSkpICsNCiAgZ2VvbV9wb2ludCgpDQoNCmdncGxvdChkaWFtb25kcywgYWVzKHggPSB4LCB5ID0geikpICsNCiAgZ2VvbV9wb2ludCgpDQoNCmdncGxvdChkaWFtb25kcywgYWVzKHggPSB5LCB5ID0geikpICsNCiAgZ2VvbV9wb2ludCgpDQpgYGANCg0KUmVtb3ZpbmcgdGhlIG91dGxpZXJzIGZyb20gYHhgLCBgeWAsIGFuZCBgemAgbWFrZXMgdGhlIGRpc3RyaWJ1dGlvbiBlYXNpZXIgdG8gc2VlLiBUaGUgcmlnaHQgc2tld25lc3Mgb2YgdGhlc2UgZGlzdHJpYnV0aW9ucyBpcyB1bnN1cnByaXNpbmc7IHRoZXJlIHNob3VsZCBiZSBtb3JlIHNtYWxsZXIgZGlhbW9uZHMgdGhhbiBsYXJnZXIgb25lcyBhbmQgdGhlc2UgdmFsdWVzIGNhbiBuZXZlciBiZSBuZWdhdGl2ZS4gTW9yZSBpbnRlcmVzdGluZ2x5LCB0aGVyZSBhcmUgc3Bpa2VzIGluIHRoZSBkaXN0cmlidXRpb24gYXQgY2VydGFpbiB2YWx1ZXMuIFRoZXNlIHNwaWtlcyBvZnRlbiwgYnV0IG5vdCBleGNsdXNpdmVseSwgb2NjdXIgbmVhciBpbnRlZ2VyIHZhbHVlcy4gV2l0aG91dCBrbm93aW5nIG1vcmUgYWJvdXQgZGlhbW9uZCBjdXR0aW5nLCBJIGNhbuKAmXQgc2F5IG1vcmUgYWJvdXQgd2hhdCB0aGVzZSBzcGlrZXMgcmVwcmVzZW50LiBJZiB5b3Uga25vdywgYWRkIGEgY29tbWVudC4gSSB3b3VsZCBndWVzcyB0aGF0IHNvbWUgZGlhbW9uZCBzaXplcyBhcmUgdXNlZCBtb3JlIG9mdGVuIHRoYW4gb3RoZXJzLCBhbmQgdGhlc2Ugc3Bpa2VzIGNvcnJlc3BvbmQgdG8gdGhvc2Ugc2l6ZXMuIEFsc28sIEkgd291bGQgZ3Vlc3MgdGhhdCBhIGRpYW1vbmQgY3V0IGFuZCBjYXJhdCB2YWx1ZSBvZiBhIGRpYW1vbmQgaW1wbHkgdmFsdWVzIG9mIGB4YCwgYHlgLCBhbmQgYHpgLiBTaW5jZSB0aGVyZSBhcmUgc3Bpa2VzIGluIHRoZSBkaXN0cmlidXRpb24gb2YgY2FyYXQgc2l6ZXMsIGFuZCBvbmx5IGEgZmV3IGRpZmZlcmVudCBjdXRzLCB0aGF0IGNvdWxkIHJlc3VsdCBpbiB0aGVzZSBzcGlrZXMuIEnigJlsbCBsZWF2ZSBpdCB0byB5b3UgdG8gZmlndXJlIG91dCBpZiB0aGF04oCZcyB0aGUgY2FzZS4NCg0KYGBge3J9DQpmaWx0ZXIoZGlhbW9uZHMsIHggPiAwLCB4IDwgMTApICU+JQ0KICBnZ3Bsb3QoKSArDQogIGdlb21faGlzdG9ncmFtKG1hcHBpbmcgPSBhZXMoeCA9IHgpLCBiaW53aWR0aCA9IDAuMDEpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IDE6MTApDQoNCmZpbHRlcihkaWFtb25kcywgeSA+IDAsIHkgPCAxMCkgJT4lDQogIGdncGxvdCgpICsNCiAgZ2VvbV9oaXN0b2dyYW0obWFwcGluZyA9IGFlcyh4ID0geSksIGJpbndpZHRoID0gMC4wMSkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gMToxMCkNCg0KZmlsdGVyKGRpYW1vbmRzLCB6ID4gMCwgeiA8IDEwKSAlPiUNCiAgZ2dwbG90KCkgKw0KICBnZW9tX2hpc3RvZ3JhbShtYXBwaW5nID0gYWVzKHggPSB6KSwgYmlud2lkdGggPSAwLjAxKSArDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSAxOjEwKQ0KYGBgDQoNCkFjY29yZGluZyB0byB0aGUgZG9jdW1lbnRhdGlvbiBmb3IgW2RpYW1vbmRzXShodHRwczovL2dncGxvdDIudGlkeXZlcnNlLm9yZy9yZWZlcmVuY2UvZGlhbW9uZHMuaHRtbCksIGB4YCBpcyBsZW5ndGgsIGB5YCBpcyB3aWR0aCwgYW5kIGB6YCBpcyBkZXB0aC4gSWYgZG9jdW1lbnRhdGlvbiB3ZXJlIHVuYXZhaWxhYmxlLCBJIHdvdWxkIGNvbXBhcmUgdGhlIHZhbHVlcyBvZiB0aGUgdmFyaWFibGVzIHRvIG1hdGNoIHRoZW0gdG8gdGhlIGxlbmd0aCwgd2lkdGgsIGFuZCBkZXB0aC4gSSB3b3VsZCBleHBlY3QgbGVuZ3RoIHRvIGFsd2F5cyBiZSBsZXNzIHRoYW4gd2lkdGgsIG90aGVyd2lzZSB0aGUgbGVuZ3RoIHdvdWxkIGJlIGNhbGxlZCB0aGUgd2lkdGguIEkgd291bGQgYWxzbyBzZWFyY2ggZm9yIHRoZSBkZWZpbml0aW9ucyBvZiBsZW5ndGgsIHdpZHRoLCBhbmQgZGVwdGggd2l0aCByZXNwZWN0IHRvIGRpYW1vbmQgY3V0cy4gW0RlcHRoXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9EaWFtb25kX2N1dCkgY2FuIGJlIGV4cHJlc3NlZCBhcyBhIHBlcmNlbnRhZ2Ugb2YgdGhlIGxlbmd0aC93aWR0aCBvZiB0aGUgZGlhbW9uZCwgd2hpY2ggbWVhbnMgaXQgc2hvdWxkIGJlIGxlc3MgdGhhbiBib3RoIHRoZSBsZW5ndGggYW5kIHRoZSB3aWR0aC4NCg0KYGBge3J9DQpzdW1tYXJpc2UoZGlhbW9uZHMsIG1lYW4oeCA+IHkpLCBtZWFuKHggPiB6KSwgbWVhbih5ID4geikpDQpgYGANCg0KSXQgYXBwZWFycyB0aGF0IGRlcHRoIChgemApIGlzIGFsd2F5cyBzbWFsbGVyIHRoYW4gbGVuZ3RoIChgeGApIG9yIHdpZHRoIChgeWApLCBwZXJoYXBzIGJlY2F1c2UgYSBzaGFsbG93ZXIgZGVwdGggaGVscHMgd2hlbiBzZXR0aW5nIGRpYW1vbmRzIGluIGpld2VscnkgYW5kIGR1ZSB0byBob3cgaXQgYWZmZWN0IHRoZSByZWZsZWN0aW9uIG9mIGxpZ2h0LiBMZW5ndGggaXMgbW9yZSB0aGFuIHdpZHRoIGluIGxlc3MgdGhhbiBoYWxmIHRoZSBvYnNlcnZhdGlvbnMsIHRoZSBvcHBvc2l0ZSBvZiBteSBleHBlY3RhdGlvbnMuDQoNCiMjIyAyLiBFeHBsb3JlIHRoZSBkaXN0cmlidXRpb24gb2YgcHJpY2UuIERvIHlvdSBkaXNjb3ZlciBhbnl0aGluZyB1bnVzdWFsIG9yIHN1cnByaXNpbmc/IChIaW50OiBDYXJlZnVsbHkgdGhpbmsgYWJvdXQgdGhlIGBiaW53aWR0aGAgYW5kIG1ha2Ugc3VyZSB5b3UgdHJ5IGEgd2lkZSByYW5nZSBvZiB2YWx1ZXMuKQ0KDQogLSBUaGUgcHJpY2UgZGF0YSBoYXMgbWFueSBzcGlrZXMsIGJ1dCBJIGNhbuKAmXQgdGVsbCB3aGF0IGVhY2ggc3Bpa2UgY29ycmVzcG9uZHMgdG8uIFRoZSBmb2xsb3dpbmcgcGxvdHMgZG9u4oCZdCBzaG93IG11Y2ggZGlmZmVyZW5jZSBpbiB0aGUgZGlzdHJpYnV0aW9ucyBpbiB0aGUgbGFzdCBvbmUgb3IgdHdvIGRpZ2l0cy4NCiAtIFRoZXJlIGFyZSBubyBkaWFtb25kcyB3aXRoIGEgcHJpY2Ugb2YgJDEsNTAwIChiZXR3ZWVuICQxLDQ1MCBhbmQgJDEsNTUwKS4NCiAtIFRoZXJl4oCZcyBhIGJ1bGdlIGluIHRoZSBkaXN0cmlidXRpb24gYXJvdW5kICQ3NTAuDQoNCmBgYHtyfQ0KZ2dwbG90KGZpbHRlcihkaWFtb25kcywgcHJpY2UgPCAyNTAwKSwgYWVzKHggPSBwcmljZSkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAxMCwgY2VudGVyID0gMCkNCg0KZ2dwbG90KGZpbHRlcihkaWFtb25kcyksIGFlcyh4ID0gcHJpY2UpKSArDQogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMTAwLCBjZW50ZXIgPSAwKQ0KYGBgDQoNCkRpc3RyaWJ1dGlvbiBvZiBsYXN0IGRpZ2l0DQoNCmBgYHtyfQ0KZGlhbW9uZHMgJT4lDQogIG11dGF0ZShlbmRpbmcgPSBwcmljZSAlJSAxMCkgJT4lDQogIGdncGxvdChhZXMoeCA9IGVuZGluZykpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAxLCBjZW50ZXIgPSAwKQ0KDQpkaWFtb25kcyAlPiUNCiAgbXV0YXRlKGVuZGluZyA9IHByaWNlICUlIDEwMCkgJT4lDQogIGdncGxvdChhZXMoeCA9IGVuZGluZykpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAxKQ0KDQpkaWFtb25kcyAlPiUNCiAgbXV0YXRlKGVuZGluZyA9IHByaWNlICUlIDEwMDApICU+JQ0KICBmaWx0ZXIoZW5kaW5nID49IDUwMCwgZW5kaW5nIDw9IDgwMCkgJT4lDQogIGdncGxvdChhZXMoeCA9IGVuZGluZykpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAxKQ0KYGBgDQoNCiMjIyAzLiBIb3cgbWFueSBkaWFtb25kcyBhcmUgMC45OSBjYXJhdD8gSG93IG1hbnkgYXJlIDEgY2FyYXQ/IFdoYXQgZG8geW91IHRoaW5rIGlzIHRoZSBjYXVzZSBvZiB0aGUgZGlmZmVyZW5jZT8NCg0KVGhlcmUgYXJlIG1vcmUgdGhhbiA3MCB0aW1lcyBhcyBtYW55IDEgY2FyYXQgZGlhbW9uZHMgYXMgMC45OSBjYXJhdCBkaWFtb25kLg0KDQpgYGB7cn0NCmRpYW1vbmRzICU+JQ0KICBmaWx0ZXIoY2FyYXQgPj0gMC45OSwgY2FyYXQgPD0gMSkgJT4lDQogIGNvdW50KGNhcmF0KQ0KYGBgDQoNCkkgZG9u4oCZdCBrbm93IGV4YWN0bHkgdGhlIHByb2Nlc3MgYmVoaW5kIGhvdyBjYXJhdHMgYXJlIG1lYXN1cmVkLCBidXQgc29tZSB3YXkgb3IgYW5vdGhlciBzb21lIGRpYW1vbmRzIGNhcmF0IHZhbHVlcyBhcmUgYmVpbmcg4oCccm91bmRlZCB1cOKAnSBQcmVzdW1hYmx5IHRoZXJlIGlzIGEgcHJlbWl1bSBmb3IgYSAxIGNhcmF0IGRpYW1vbmQgdnMuIGEgMC45OSBjYXJhdCBkaWFtb25kIGJleW9uZCB0aGUgZXhwZWN0ZWQgaW5jcmVhc2UgaW4gcHJpY2UgZHVlIHRvIGEgMC4wMSBjYXJhdCBpbmNyZWFzZS4NCg0KVG8gY2hlY2sgdGhpcyBpbnR1aXRpb24sIHdlIHdvdWxkIHdhbnQgdG8gbG9vayBhdCB0aGUgbnVtYmVyIG9mIGRpYW1vbmRzIGluIGVhY2ggY2FyYXQgcmFuZ2UgdG8gc2VlIGlmIHRoZXJlIGlzIGFuIHVudXN1YWxseSBsb3cgbnVtYmVyIG9mIDAuOTkgY2FyYXQgZGlhbW9uZHMsIGFuZCBhbiBhYm5vcm1hbGx5IGxhcmdlIG51bWJlciBvZiAxIGNhcmF0IGRpYW1vbmRzLg0KDQpgYGB7cn0NCmRpYW1vbmRzICU+JQ0KICBmaWx0ZXIoY2FyYXQgPj0gMC45LCBjYXJhdCA8PSAxLjEpICU+JQ0KICBjb3VudChjYXJhdCkgJT4lDQogIHByaW50KG4gPSBJbmYpDQpgYGANCg0KDQojIyMgNC4gQ29tcGFyZSBhbmQgY29udHJhc3QgYGNvb3JkX2NhcnRlc2lhbigpYCB2cyBgeGxpbSgpYCBvciBgeWxpbSgpYCB3aGVuIHpvb21pbmcgaW4gb24gYSBoaXN0b2dyYW0uIFdoYXQgaGFwcGVucyBpZiB5b3UgbGVhdmUgYGJpbndpZHRoYCB1bnNldD8gV2hhdCBoYXBwZW5zIGlmIHlvdSB0cnkgYW5kIHpvb20gc28gb25seSBoYWxmIGEgYmFyIHNob3dzPw0KDQpUaGUgYGNvb3JkX2NhcnRlc2lhbigpYCBmdW5jdGlvbiB6b29tcyBpbiBvbiB0aGUgYXJlYSBzcGVjaWZpZWQgYnkgdGhlIGxpbWl0cywgYWZ0ZXIgaGF2aW5nIGNhbGN1bGF0ZWQgYW5kIGRyYXduIHRoZSBnZW9tcy4gU2luY2UgdGhlIGhpc3RvZ3JhbSBiaW5zIGhhdmUgYWxyZWFkeSBiZWVuIGNhbGN1bGF0ZWQsIGl0IGlzIHVuYWZmZWN0ZWQuDQoNCmBgYHtyfQ0KZ2dwbG90KGRpYW1vbmRzKSArDQogIGdlb21faGlzdG9ncmFtKG1hcHBpbmcgPSBhZXMoeCA9IHByaWNlKSkgKw0KICBjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IGMoMTAwLCA1MDAwKSwgeWxpbSA9IGMoMCwgMzAwMCkpDQpgYGANCg0KSG93ZXZlciwgdGhlIGB4bGltKClgIGFuZCBgeWxpbSgpYCBmdW5jdGlvbnMgaW5mbHVlbmNlIGFjdGlvbnMgYmVmb3JlIHRoZSBjYWxjdWxhdGlvbiBvZiB0aGUgc3RhdHMgcmVsYXRlZCB0byB0aGUgaGlzdG9ncmFtLiBUaHVzLCBhbnkgdmFsdWVzIG91dHNpZGUgdGhlIHgtIGFuZCB5LWxpbWl0cyBhcmUgZHJvcHBlZCBiZWZvcmUgY2FsY3VsYXRpbmcgYmluIHdpZHRocyBhbmQgY291bnRzLiBUaGlzIGNhbiBpbmZsdWVuY2UgaG93IHRoZSBoaXN0b2dyYW0gbG9va3MuDQoNCmBgYHtyfQ0KZ2dwbG90KGRpYW1vbmRzKSArDQogIGdlb21faGlzdG9ncmFtKG1hcHBpbmcgPSBhZXMoeCA9IHByaWNlKSkgKw0KICB4bGltKDEwMCwgNTAwMCkgKw0KICB5bGltKDAsIDMwMDApDQpgYGANCg0K