1.Quantiles in R

Quantiles are points that split a dataset into groups of equal size. For example, let’s say you just took a test and wanted to know whether you’re in the top 10% of the class. One way to determine this would be to split the data into ten groups with an equal number of datapoints in each group and see which group you fall into.

knitr::include_graphics("C:/Users/kuoan/Desktop/R Code/Quantiles1.png")

There are nine values that split the dataset into ten groups of equal size — each group has 3 different test scores in it.

Those nine values that split the data are quantiles! Specifically, they are the 10-quantiles, or deciles.

You can find any number of quantiles. For example, if you split the dataset into 100 groups of equal size, the 99 values that split the data are the 100-quantiles, or percentiles.

The quartiles are some of the most commonly used quantiles. The quartiles split the data into four groups of equal size.

In this lesson, we’ll show you how to calculate quantiles using R and discuss some of the most commonly used quantiles.

Instructions

We’ve imported a dataset of song lengths (measured in seconds). We’ve drawn a few histograms showing different quantiles.

What do you think a histogram that shows the 100-quantiles would look like?

# load libraries
library(ggplot2)
# load song data
load("songs.Rda")
錯誤發生在 readChar(con, 5L, useBytes = TRUE): 無法開啟連接
knitr::include_graphics("C:/Users/kuoan/Desktop/R Code/Quantiles2.png")

knitr::include_graphics("C:/Users/kuoan/Desktop/R Code/Quantiles3.png")

knitr::include_graphics("C:/Users/kuoan/Desktop/R Code/Quantiles4.png")

2.Quantiles in R

Base R has a function named quantile() that will quickly calculate the quantiles of a dataset for you.

quantile() takes two parameters. The first is the dataset that you are using. The second parameter is a single number or a vector of numbers between 0 and 1. These numbers represent the places in the data where you want to split.

For example, if you only wanted the value that split the first 10% of the data apart from the remaining 90%, you could use this code:

dataset <- c(5, 10, -20, 42, -9, 10)
ten_percent <- quantile(dataset, 0.10)
ten_percent
  10% 
-14.5 

ten_percent now holds the value -14.5. This result technically isn’t a quantile, because it isn’t splitting the dataset into groups of equal sizes — this value splits the data into one group with 10% of the data and another with 90%.

However, it would still be useful if you were curious about whether a data point was in the bottom 10% of the dataset.

Instructions

[1] “The value that splits 23% of the data is 171.7812924”

3.Many Quantiles

In the last exercise, we found a single “quantile” — we split the first 23% of the data away from the remaining 77%.

However, quantiles are usually a set of values that split the data into groups of equal size. For example, you wanted to get the 5-quantiles, or the four values that split the data into five groups of equal size, you could use this code:

dataset <- c(5, 10, -20, 42, -9, 10)
ten_percent <- quantile(dataset, c(0.2, 0.4, 0.6, 0.8))
ten_percent
20% 40% 60% 80% 
 -9   5  10  10 

Note that we had to do a little math in our head to make sure that the values c(0.2, 0.4, 0.6, 0.8) split the data into groups of equal size. Each group has 20% of the data.

knitr::include_graphics("C:/Users/kuoan/Desktop/R Code/Quantile5.png")

If we used the values c(0.2, 0.4, 0.7, 0.8), the function would return the four values at those split points. However, those values wouldn’t split the data into five equally sized groups. One group would only have 10% of the data and another group would have 30% of the data!

knitr::include_graphics("C:/Users/kuoan/Desktop/R Code/Quantiles6.png")

Instuctions

1.Create a variable named quartiles that contains the quartiles of the songs dataset.

The quartiles of a dataset split the data into four groups of equal size. Each group should have 25% of the data, so you’ll want to use c(0.25, 0.5, 0.75) as the second parameter to the quantile() function.

 25%      50%      75% 

175.9342 222.8240 275.4738

2.Create a variable named deciles. deciles should store the values that split the dataset into ten groups of equal size. Each group should have 10% of the data.

The first value should be at 10% of the data. The next value should be at 20% of the data. The final value should be at 90% of the data.

# define deciles here:
deciles <- quantile(songs, c(0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9))
deciles
 10%      20%      30%      40%      50%      60%      70%      80% 

135.1519 165.3755 185.9914 204.8152 222.8240 240.2216 262.4779 290.9514

 90% 

348.4939

3.Look at the printout of the deciles. If you had a song that was 170 seconds long, what tenth of the dataset would it fall in?

Create a variable named tenth and set it equal to the 1 if you think the 170 second song would fall in the first tenth of the data. Set it equal to 2 if you think the song would fall in the second tenth of the data. If you think the song would fall in the final tenth of the data, set tenth equal to 10.

# ignore the code below here:

tryCatch(print(paste(c("The quartiles are",quartiles,collapse=" "))), error=function(e) {print("You haven't defined quartiles.")})

tryCatch(print(paste(c("The deciles are",deciles,collapse=" "))), error=function(e) {print("You haven't defined deciles.")})

[1] “The quartiles are” “175.93424” “222.82404”

[4] “275.47383” ” ”

[1] “The deciles are” “135.151876” “165.375546” “185.99138”

[5] “204.815222” “222.82404” “240.22159” “262.47791”

4.Common Quantiles

One of the most common quantiles is the 2-quantile. This value splits the data into two groups of equal size. Half the data will be above this value, and half the data will be below it. This is also known as the median!

knitr::include_graphics("C:/Users/kuoan/Desktop/R Code/Quantiles7.png")

The 4-quantiles, or the quartiles, split the data into four groups of equal size. We found the quartiles in the previous exercise.

knitr::include_graphics("C:/Users/kuoan/Desktop/R Code/Quantiles8.png")

Finally, the percentiles, or the values that split the data into 100 groups, are commonly used to compare new data points to the dataset. You might hear statements like “You are above the 80th percentile in height”. This means that your height is above whatever value splits the first 80% of the data from the remaining 20%.

Instructions

1.We won’t make you calculate all 99 percentiles, but let’s take a look at one. Find the value that separates the first 32% of the data from the rest.

Store that value in a variable named percentile.

# define percentile and answer here:
percentile <- quantile(songs, 0.32)
錯誤: 找不到物件 'songs'
 32% 

189.9359

2.Look at the printout. If you had a song that was exactly three minutes long, is that song above or below the 32nd percentile?

Create a variable named answer and set it equal to either “above” or “below”. Don’t forget to include the quotes!

[1] “Your percentile is 189.93587”

5.Quantiles Review

Nice work! Here are some of the major takeaways about quantiles:

1.Quantiles are values that split a dataset into groups of equal size.

2.If you have n quantiles, the dataset will be split into n+1 groups of equal size.

3.The median is a quantile. It is the only 2-quantile. Half the data falls below the median and half falls above the median.

4.Quartiles and percentiles are other common quantiles. Quartiles split the data into 4 groups while percentiles split the data into 100 groups.

Instructions

To the right, we’ve shown three different histograms along with the deciles. Each histogram shows the SAT scores of the students that a fake university has accepted.

If you had an SAT score of 1350, which tenth of the data would you be in for each school? Which schools should you apply to? Would any of the schools be unrealistic options?

knitr::include_graphics("C:/Users/kuoan/Desktop/R Code/Quantiles9.png")

knitr::include_graphics("C:/Users/kuoan/Desktop/R Code/Quantiles10.png")

knitr::include_graphics("C:/Users/kuoan/Desktop/R Code/Quantiles11.png")

LS0tDQp0aXRsZTogIlF1YW50aWxlcyINCmF1dGhvcjogIkFubmFiZWwgS3VvIg0KZGF0ZTogImByIGZvcm1hdChTeXMudGltZSgpLCAnJVktJW0tJWQgJUg6JU0nKWAiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQojIDEuUXVhbnRpbGVzIGluIFINCg0KUXVhbnRpbGVzIGFyZSBwb2ludHMgdGhhdCBzcGxpdCBhIGRhdGFzZXQgaW50byBncm91cHMgb2YgZXF1YWwgc2l6ZS4gRm9yIGV4YW1wbGUsIGxldOKAmXMgc2F5IHlvdSBqdXN0IHRvb2sgYSB0ZXN0IGFuZCB3YW50ZWQgdG8ga25vdyB3aGV0aGVyIHlvdeKAmXJlIGluIHRoZSB0b3AgMTAlIG9mIHRoZSBjbGFzcy4gT25lIHdheSB0byBkZXRlcm1pbmUgdGhpcyB3b3VsZCBiZSB0byBzcGxpdCB0aGUgZGF0YSBpbnRvIHRlbiBncm91cHMgd2l0aCBhbiBlcXVhbCBudW1iZXIgb2YgZGF0YXBvaW50cyBpbiBlYWNoIGdyb3VwIGFuZCBzZWUgd2hpY2ggZ3JvdXAgeW91IGZhbGwgaW50by4NCg0KYGBge3IgUXVhbnRpbGVzMSwgb3V0LndpZHRoPSI2MCUifQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoIkM6L1VzZXJzL2t1b2FuL0Rlc2t0b3AvUiBDb2RlL1F1YW50aWxlczEucG5nIikNCmBgYA0KDQpUaGVyZSBhcmUgbmluZSB2YWx1ZXMgdGhhdCBzcGxpdCB0aGUgZGF0YXNldCBpbnRvIHRlbiBncm91cHMgb2YgZXF1YWwgc2l6ZSDigJQgZWFjaCBncm91cCBoYXMgMyBkaWZmZXJlbnQgdGVzdCBzY29yZXMgaW4gaXQuDQoNClRob3NlIG5pbmUgdmFsdWVzIHRoYXQgc3BsaXQgdGhlIGRhdGEgYXJlIHF1YW50aWxlcyEgU3BlY2lmaWNhbGx5LCB0aGV5IGFyZSB0aGUgMTAtcXVhbnRpbGVzLCBvciBkZWNpbGVzLg0KDQpZb3UgY2FuIGZpbmQgYW55IG51bWJlciBvZiBxdWFudGlsZXMuIEZvciBleGFtcGxlLCBpZiB5b3Ugc3BsaXQgdGhlIGRhdGFzZXQgaW50byAxMDAgZ3JvdXBzIG9mIGVxdWFsIHNpemUsIHRoZSA5OSB2YWx1ZXMgdGhhdCBzcGxpdCB0aGUgZGF0YSBhcmUgdGhlIDEwMC1xdWFudGlsZXMsIG9yIHBlcmNlbnRpbGVzLg0KDQpUaGUgcXVhcnRpbGVzIGFyZSBzb21lIG9mIHRoZSBtb3N0IGNvbW1vbmx5IHVzZWQgcXVhbnRpbGVzLiBUaGUgcXVhcnRpbGVzIHNwbGl0IHRoZSBkYXRhIGludG8gZm91ciBncm91cHMgb2YgZXF1YWwgc2l6ZS4NCg0KSW4gdGhpcyBsZXNzb24sIHdl4oCZbGwgc2hvdyB5b3UgaG93IHRvIGNhbGN1bGF0ZSBxdWFudGlsZXMgdXNpbmcgUiBhbmQgZGlzY3VzcyBzb21lIG9mIHRoZSBtb3N0IGNvbW1vbmx5IHVzZWQgcXVhbnRpbGVzLg0KDQojIyBJbnN0cnVjdGlvbnMNCg0KV2XigJl2ZSBpbXBvcnRlZCBhIGRhdGFzZXQgb2Ygc29uZyBsZW5ndGhzIChtZWFzdXJlZCBpbiBzZWNvbmRzKS4gV2XigJl2ZSBkcmF3biBhIGZldyBoaXN0b2dyYW1zIHNob3dpbmcgZGlmZmVyZW50IHF1YW50aWxlcy4NCg0KV2hhdCBkbyB5b3UgdGhpbmsgYSBoaXN0b2dyYW0gdGhhdCBzaG93cyB0aGUgMTAwLXF1YW50aWxlcyB3b3VsZCBsb29rIGxpa2U/DQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIGxvYWQgbGlicmFyaWVzDQpsaWJyYXJ5KGdncGxvdDIpDQpgYGANCg0KYGBge3J9DQojIGxvYWQgc29uZyBkYXRhDQpsb2FkKCJzb25ncy5SZGEiKQ0KYGBgDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIGVjaG89RkFMU0V9DQojIDQgcXVhbnRpbGVzDQpoaXN0IDwtIHFwbG90KHNvbmdzLA0KICAgICAgICAgICAgICBnZW9tPSJoaXN0b2dyYW0iLA0KICAgICAgICAgICAgICBtYWluID0gJzQtUXVhbnRpbGVzJywNCiAgICAgICAgICAgICAgeGxhYiA9ICdTb25nIExlbmd0aCAoU2Vjb25kcyknLA0KICAgICAgICAgICAgICB5bGFiID0gJ0NvdW50JywNCiAgICAgICAgICAgICAgZmlsbD1JKCJibHVlIiksDQogICAgICAgICAgICAgIGNvbD1JKCJyZWQiKSwNCiAgICAgICAgICAgICAgYWxwaGE9SSguMikpICsNCiAgICAgICAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1xdWFudGlsZShzb25ncywwLjI1KSwNCiAgICAgICAgICAgICAgICAgICAgICAgY29sb3I9SSgiYmx1ZSIpKSwNCiAgICAgICAgICAgICAgICAgICBsaW5ldHlwZT0ic29saWQiLA0KICAgICAgICAgICAgICAgICAgIHNpemU9MSwNCiAgICAgICAgICAgICAgICAgICBzaG93LmxlZ2VuZD1UKSArDQoJCQkJZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1xdWFudGlsZShzb25ncywwLjUpLA0KICAgICAgICAgICAgICAgICAgICAgICBjb2xvcj1JKCJibHVlIikpLA0KICAgICAgICAgICAgICAgICAgIGxpbmV0eXBlPSJzb2xpZCIsDQogICAgICAgICAgICAgICAgICAgc2l6ZT0xLA0KICAgICAgICAgICAgICAgICAgIHNob3cubGVnZW5kPVQpICsNCiAgCQkJZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1xdWFudGlsZShzb25ncywwLjc1KSwNCiAgICAgICAgICAgICAgICAgICAgICAgY29sb3I9SSgiYmx1ZSIpKSwNCiAgICAgICAgICAgICAgICAgICBsaW5ldHlwZT0ic29saWQiLA0KICAgICAgICAgICAgICAgICAgIHNpemU9MSwNCiAgICAgICAgICAgICAgICAgICBzaG93LmxlZ2VuZD1UKQ0KDQpoaXN0DQpgYGANCg0KYGBge3IgUXVhbnRpbGVzMiwgb3V0LndpZHRoPSI2MCUifQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoIkM6L1VzZXJzL2t1b2FuL0Rlc2t0b3AvUiBDb2RlL1F1YW50aWxlczIucG5nIikNCmBgYA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCBlY2hvPUZBTFNFfQ0KIyA1IHF1YW50aWxlcw0KaGlzdCA8LSBxcGxvdChzb25ncywNCiAgICAgICAgICAgICAgZ2VvbT0iaGlzdG9ncmFtIiwNCiAgICAgICAgICAgICAgbWFpbiA9ICc1LVF1YW50aWxlcycsDQogICAgICAgICAgICAgIHhsYWIgPSAnU29uZyBMZW5ndGggKFNlY29uZHMpJywNCiAgICAgICAgICAgICAgeWxhYiA9ICdDb3VudCcsDQogICAgICAgICAgICAgIGZpbGw9SSgiYmx1ZSIpLA0KICAgICAgICAgICAgICBjb2w9SSgicmVkIiksDQogICAgICAgICAgICAgIGFscGhhPUkoLjIpKSArDQogICAgICAgIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9cXVhbnRpbGUoc29uZ3MsMC4yKSwNCiAgICAgICAgICAgICAgICAgICAgICAgY29sb3I9SSgiYmx1ZSIpKSwNCiAgICAgICAgICAgICAgICAgICBsaW5ldHlwZT0ic29saWQiLA0KICAgICAgICAgICAgICAgICAgIHNpemU9MSwNCiAgICAgICAgICAgICAgICAgICBzaG93LmxlZ2VuZD1UKSArDQoJCQkJZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1xdWFudGlsZShzb25ncywwLjQpLA0KICAgICAgICAgICAgICAgICAgICAgICBjb2xvcj1JKCJibHVlIikpLA0KICAgICAgICAgICAgICAgICAgIGxpbmV0eXBlPSJzb2xpZCIsDQogICAgICAgICAgICAgICAgICAgc2l6ZT0xLA0KICAgICAgICAgICAgICAgICAgIHNob3cubGVnZW5kPVQpICsNCiAgCQkJZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1xdWFudGlsZShzb25ncywwLjYpLA0KICAgICAgICAgICAgICAgICAgICAgICBjb2xvcj1JKCJibHVlIikpLA0KICAgICAgICAgICAgICAgICAgIGxpbmV0eXBlPSJzb2xpZCIsDQogICAgICAgICAgICAgICAgICAgc2l6ZT0xLA0KICAgICAgICAgICAgICAgICAgIHNob3cubGVnZW5kPVQpICsNCiAgCQkJZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1xdWFudGlsZShzb25ncywwLjgpLA0KICAgICAgICAgICAgICAgICAgICAgICBjb2xvcj1JKCJibHVlIikpLA0KICAgICAgICAgICAgICAgICAgIGxpbmV0eXBlPSJzb2xpZCIsDQogICAgICAgICAgICAgICAgICAgc2l6ZT0xLA0KICAgICAgICAgICAgICAgICAgIHNob3cubGVnZW5kPVQpDQoNCmhpc3QNCmBgYA0KDQpgYGB7ciBRdWFudGlsZXMzLCBvdXQud2lkdGg9IjYwJSJ9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiQzovVXNlcnMva3VvYW4vRGVza3RvcC9SIENvZGUvUXVhbnRpbGVzMy5wbmciKQ0KYGBgDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIGVjaG89RkFMU0V9DQojIDEwIHF1YW50aWxlcw0KaGlzdCA8LSBxcGxvdChzb25ncywNCiAgICAgICAgICAgICAgZ2VvbT0iaGlzdG9ncmFtIiwNCiAgICAgICAgICAgICAgbWFpbiA9ICcxMC1RdWFudGlsZXMnLA0KICAgICAgICAgICAgICB4bGFiID0gJ1NvbmcgTGVuZ3RoIChTZWNvbmRzKScsDQogICAgICAgICAgICAgIHlsYWIgPSAnQ291bnQnLA0KICAgICAgICAgICAgICBmaWxsPUkoImJsdWUiKSwNCiAgICAgICAgICAgICAgY29sPUkoInJlZCIpLA0KICAgICAgICAgICAgICBhbHBoYT1JKC4yKSkgKw0KICAgICAgICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PXF1YW50aWxlKHNvbmdzLDAuMSksDQogICAgICAgICAgICAgICAgICAgICAgIGNvbG9yPUkoImJsdWUiKSksDQogICAgICAgICAgICAgICAgICAgbGluZXR5cGU9InNvbGlkIiwNCiAgICAgICAgICAgICAgICAgICBzaXplPTEsDQogICAgICAgICAgICAgICAgICAgc2hvdy5sZWdlbmQ9VCkgKw0KCQkJCWdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9cXVhbnRpbGUoc29uZ3MsMC4yKSwNCiAgICAgICAgICAgICAgICAgICAgICAgY29sb3I9SSgiYmx1ZSIpKSwNCiAgICAgICAgICAgICAgICAgICBsaW5ldHlwZT0ic29saWQiLA0KICAgICAgICAgICAgICAgICAgIHNpemU9MSwNCiAgICAgICAgICAgICAgICAgICBzaG93LmxlZ2VuZD1UKSArDQogIAkJCWdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9cXVhbnRpbGUoc29uZ3MsMC4zKSwNCiAgICAgICAgICAgICAgICAgICAgICAgY29sb3I9SSgiYmx1ZSIpKSwNCiAgICAgICAgICAgICAgICAgICBsaW5ldHlwZT0ic29saWQiLA0KICAgICAgICAgICAgICAgICAgIHNpemU9MSwNCiAgICAgICAgICAgICAgICAgICBzaG93LmxlZ2VuZD1UKSArDQogIAkJCWdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9cXVhbnRpbGUoc29uZ3MsMC40KSwNCiAgICAgICAgICAgICAgICAgICAgICAgY29sb3I9SSgiYmx1ZSIpKSwNCiAgICAgICAgICAgICAgICAgICBsaW5ldHlwZT0ic29saWQiLA0KICAgICAgICAgICAgICAgICAgIHNpemU9MSwNCiAgICAgICAgICAgICAgICAgICBzaG93LmxlZ2VuZD1UKSArDQogICAgICAgIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9cXVhbnRpbGUoc29uZ3MsMC41KSwNCiAgICAgICAgICAgICAgICAgICAgICAgY29sb3I9SSgiYmx1ZSIpKSwNCiAgICAgICAgICAgICAgICAgICBsaW5ldHlwZT0ic29saWQiLA0KICAgICAgICAgICAgICAgICAgIHNpemU9MSwNCiAgICAgICAgICAgICAgICAgICBzaG93LmxlZ2VuZD1UKSArDQoJCQkJZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1xdWFudGlsZShzb25ncywwLjYpLA0KICAgICAgICAgICAgICAgICAgICAgICBjb2xvcj1JKCJibHVlIikpLA0KICAgICAgICAgICAgICAgICAgIGxpbmV0eXBlPSJzb2xpZCIsDQogICAgICAgICAgICAgICAgICAgc2l6ZT0xLA0KICAgICAgICAgICAgICAgICAgIHNob3cubGVnZW5kPVQpICsNCiAgCQkJZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1xdWFudGlsZShzb25ncywwLjcpLA0KICAgICAgICAgICAgICAgICAgICAgICBjb2xvcj1JKCJibHVlIikpLA0KICAgICAgICAgICAgICAgICAgIGxpbmV0eXBlPSJzb2xpZCIsDQogICAgICAgICAgICAgICAgICAgc2l6ZT0xLA0KICAgICAgICAgICAgICAgICAgIHNob3cubGVnZW5kPVQpICsNCiAgCQkJZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1xdWFudGlsZShzb25ncywwLjgpLA0KICAgICAgICAgICAgICAgICAgICAgICBjb2xvcj1JKCJibHVlIikpLA0KICAgICAgICAgICAgICAgICAgIGxpbmV0eXBlPSJzb2xpZCIsDQogICAgICAgICAgICAgICAgICAgc2l6ZT0xLA0KICAgICAgICAgICAgICAgICAgIHNob3cubGVnZW5kPVQpICsNCiAgCQkJZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1xdWFudGlsZShzb25ncywwLjkpLA0KICAgICAgICAgICAgICAgICAgICAgICBjb2xvcj1JKCJibHVlIikpLA0KICAgICAgICAgICAgICAgICAgIGxpbmV0eXBlPSJzb2xpZCIsDQogICAgICAgICAgICAgICAgICAgc2l6ZT0xLA0KICAgICAgICAgICAgICAgICAgIHNob3cubGVnZW5kPVQpDQoNCmhpc3QNCmBgYA0KDQpgYGB7ciBRdWFudGlsZXM0LCBvdXQud2lkdGg9IjYwJSJ9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiQzovVXNlcnMva3VvYW4vRGVza3RvcC9SIENvZGUvUXVhbnRpbGVzNC5wbmciKQ0KYGBgDQoNCiMgMi5RdWFudGlsZXMgaW4gUg0KDQpCYXNlIFIgaGFzIGEgZnVuY3Rpb24gbmFtZWQgcXVhbnRpbGUoKSB0aGF0IHdpbGwgcXVpY2tseSBjYWxjdWxhdGUgdGhlIHF1YW50aWxlcyBvZiBhIGRhdGFzZXQgZm9yIHlvdS4NCg0KcXVhbnRpbGUoKSB0YWtlcyB0d28gcGFyYW1ldGVycy4gVGhlIGZpcnN0IGlzIHRoZSBkYXRhc2V0IHRoYXQgeW91IGFyZSB1c2luZy4gVGhlIHNlY29uZCBwYXJhbWV0ZXIgaXMgYSBzaW5nbGUgbnVtYmVyIG9yIGEgdmVjdG9yIG9mIG51bWJlcnMgYmV0d2VlbiAwIGFuZCAxLiBUaGVzZSBudW1iZXJzIHJlcHJlc2VudCB0aGUgcGxhY2VzIGluIHRoZSBkYXRhIHdoZXJlIHlvdSB3YW50IHRvIHNwbGl0Lg0KDQpGb3IgZXhhbXBsZSwgaWYgeW91IG9ubHkgd2FudGVkIHRoZSB2YWx1ZSB0aGF0IHNwbGl0IHRoZSBmaXJzdCAxMCUgb2YgdGhlIGRhdGEgYXBhcnQgZnJvbSB0aGUgcmVtYWluaW5nIDkwJSwgeW91IGNvdWxkIHVzZSB0aGlzIGNvZGU6DQoNCmBgYHtyfQ0KZGF0YXNldCA8LSBjKDUsIDEwLCAtMjAsIDQyLCAtOSwgMTApDQp0ZW5fcGVyY2VudCA8LSBxdWFudGlsZShkYXRhc2V0LCAwLjEwKQ0KdGVuX3BlcmNlbnQNCmBgYA0KDQp0ZW5fcGVyY2VudCBub3cgaG9sZHMgdGhlIHZhbHVlIC0xNC41LiBUaGlzIHJlc3VsdCB0ZWNobmljYWxseSBpc27igJl0IGEgcXVhbnRpbGUsIGJlY2F1c2UgaXQgaXNu4oCZdCBzcGxpdHRpbmcgdGhlIGRhdGFzZXQgaW50byBncm91cHMgb2YgZXF1YWwgc2l6ZXMg4oCUIHRoaXMgdmFsdWUgc3BsaXRzIHRoZSBkYXRhIGludG8gb25lIGdyb3VwIHdpdGggMTAlIG9mIHRoZSBkYXRhIGFuZCBhbm90aGVyIHdpdGggOTAlLg0KDQpIb3dldmVyLCBpdCB3b3VsZCBzdGlsbCBiZSB1c2VmdWwgaWYgeW91IHdlcmUgY3VyaW91cyBhYm91dCB3aGV0aGVyIGEgZGF0YSBwb2ludCB3YXMgaW4gdGhlIGJvdHRvbSAxMCUgb2YgdGhlIGRhdGFzZXQuDQoNCiMjIEluc3RydWN0aW9ucw0KDQpgYGB7cn0NCiMgZGVmaW5lIHR3ZW50eV90aGlyZF9wZXJjZW50aWxlIGhlcmU6DQp0d2VudHlfdGhpcmRfcGVyY2VudGlsZSA8LSBxdWFudGlsZShzb25ncywgMC4yMykNCmBgYA0KDQpgYGB7cn0NCiMgaWdub3JlIHRoZSBjb2RlIGJlbG93IGhlcmU6DQoNCnRyeUNhdGNoKHByaW50KHBhc3RlKCJUaGUgdmFsdWUgdGhhdCBzcGxpdHMgMjMlIG9mIHRoZSBkYXRhIGlzIix0d2VudHlfdGhpcmRfcGVyY2VudGlsZSkpLCBlcnJvcj1mdW5jdGlvbihlKSB7cHJpbnQoIllvdSBoYXZlbid0IGRlZmluZWQgdHdlbnR5X3RoaXJkX3BlcmNlbnRpbGUuIil9KQ0KYGBgDQoNClsxXSAiVGhlIHZhbHVlIHRoYXQgc3BsaXRzIDIzJSBvZiB0aGUgZGF0YSBpcyAxNzEuNzgxMjkyNCINCg0KIyAzLk1hbnkgUXVhbnRpbGVzDQoNCkluIHRoZSBsYXN0IGV4ZXJjaXNlLCB3ZSBmb3VuZCBhIHNpbmdsZSDigJxxdWFudGlsZeKAnSDigJQgd2Ugc3BsaXQgdGhlIGZpcnN0IDIzJSBvZiB0aGUgZGF0YSBhd2F5IGZyb20gdGhlIHJlbWFpbmluZyA3NyUuDQoNCkhvd2V2ZXIsIHF1YW50aWxlcyBhcmUgdXN1YWxseSBhIHNldCBvZiB2YWx1ZXMgdGhhdCBzcGxpdCB0aGUgZGF0YSBpbnRvIGdyb3VwcyBvZiBlcXVhbCBzaXplLiBGb3IgZXhhbXBsZSwgeW91IHdhbnRlZCB0byBnZXQgdGhlIDUtcXVhbnRpbGVzLCBvciB0aGUgZm91ciB2YWx1ZXMgdGhhdCBzcGxpdCB0aGUgZGF0YSBpbnRvIGZpdmUgZ3JvdXBzIG9mIGVxdWFsIHNpemUsIHlvdSBjb3VsZCB1c2UgdGhpcyBjb2RlOg0KDQpgYGB7cn0NCmRhdGFzZXQgPC0gYyg1LCAxMCwgLTIwLCA0MiwgLTksIDEwKQ0KdGVuX3BlcmNlbnQgPC0gcXVhbnRpbGUoZGF0YXNldCwgYygwLjIsIDAuNCwgMC42LCAwLjgpKQ0KdGVuX3BlcmNlbnQNCmBgYA0KTm90ZSB0aGF0IHdlIGhhZCB0byBkbyBhIGxpdHRsZSBtYXRoIGluIG91ciBoZWFkIHRvIG1ha2Ugc3VyZSB0aGF0IHRoZSB2YWx1ZXMgYygwLjIsIDAuNCwgMC42LCAwLjgpIHNwbGl0IHRoZSBkYXRhIGludG8gZ3JvdXBzIG9mIGVxdWFsIHNpemUuIEVhY2ggZ3JvdXAgaGFzIDIwJSBvZiB0aGUgZGF0YS4NCg0KYGBge3IgUXVhbnRpbGU1LCBvdXQud2lkdGg9IjYwJSJ9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiQzovVXNlcnMva3VvYW4vRGVza3RvcC9SIENvZGUvUXVhbnRpbGU1LnBuZyIpDQpgYGANCg0KDQpJZiB3ZSB1c2VkIHRoZSB2YWx1ZXMgYygwLjIsIDAuNCwgMC43LCAwLjgpLCB0aGUgZnVuY3Rpb24gd291bGQgcmV0dXJuIHRoZSBmb3VyIHZhbHVlcyBhdCB0aG9zZSBzcGxpdCBwb2ludHMuIEhvd2V2ZXIsIHRob3NlIHZhbHVlcyB3b3VsZG7igJl0IHNwbGl0IHRoZSBkYXRhIGludG8gZml2ZSBlcXVhbGx5IHNpemVkIGdyb3Vwcy4gT25lIGdyb3VwIHdvdWxkIG9ubHkgaGF2ZSAxMCUgb2YgdGhlIGRhdGEgYW5kIGFub3RoZXIgZ3JvdXAgd291bGQgaGF2ZSAzMCUgb2YgdGhlIGRhdGEhDQoNCmBgYHtyIFF1YW50aWxlczYsIG91dC53aWR0aD0iNjAlIn0NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJDOi9Vc2Vycy9rdW9hbi9EZXNrdG9wL1IgQ29kZS9RdWFudGlsZXM2LnBuZyIpDQpgYGANCg0KIyMgSW5zdHVjdGlvbnMNCg0KMS5DcmVhdGUgYSB2YXJpYWJsZSBuYW1lZCBxdWFydGlsZXMgdGhhdCBjb250YWlucyB0aGUgcXVhcnRpbGVzIG9mIHRoZSBzb25ncyBkYXRhc2V0Lg0KDQpUaGUgcXVhcnRpbGVzIG9mIGEgZGF0YXNldCBzcGxpdCB0aGUgZGF0YSBpbnRvIGZvdXIgZ3JvdXBzIG9mIGVxdWFsIHNpemUuIEVhY2ggZ3JvdXAgc2hvdWxkIGhhdmUgMjUlIG9mIHRoZSBkYXRhLCBzbyB5b3XigJlsbCB3YW50IHRvIHVzZSBjKDAuMjUsIDAuNSwgMC43NSkgYXMgdGhlIHNlY29uZCBwYXJhbWV0ZXIgdG8gdGhlIHF1YW50aWxlKCkgZnVuY3Rpb24uDQoNCmBgYHtyfQ0KIyBkZWZpbmUgcXVhcnRpbGVzIGhlcmU6DQpxdWFydGlsZXMgPC0gcXVhbnRpbGUoc29uZ3MsIGMoMC4yNSwgMC41MCwgMC43NSkpDQpxdWFydGlsZXMNCmBgYA0KDQogICAgIDI1JSAgICAgIDUwJSAgICAgIDc1JSANCjE3NS45MzQyIDIyMi44MjQwIDI3NS40NzM4IA0KDQoyLkNyZWF0ZSBhIHZhcmlhYmxlIG5hbWVkIGRlY2lsZXMuIGRlY2lsZXMgc2hvdWxkIHN0b3JlIHRoZSB2YWx1ZXMgdGhhdCBzcGxpdCB0aGUgZGF0YXNldCBpbnRvIHRlbiBncm91cHMgb2YgZXF1YWwgc2l6ZS4gRWFjaCBncm91cCBzaG91bGQgaGF2ZSAxMCUgb2YgdGhlIGRhdGEuDQoNClRoZSBmaXJzdCB2YWx1ZSBzaG91bGQgYmUgYXQgMTAlIG9mIHRoZSBkYXRhLiBUaGUgbmV4dCB2YWx1ZSBzaG91bGQgYmUgYXQgMjAlIG9mIHRoZSBkYXRhLiBUaGUgZmluYWwgdmFsdWUgc2hvdWxkIGJlIGF0IDkwJSBvZiB0aGUgZGF0YS4NCg0KYGBge3J9DQojIGRlZmluZSBkZWNpbGVzIGhlcmU6DQpkZWNpbGVzIDwtIHF1YW50aWxlKHNvbmdzLCBjKDAuMSwgMC4yLCAwLjMsIDAuNCwgMC41LCAwLjYsIDAuNywgMC44LCAwLjkpKQ0KZGVjaWxlcw0KYGBgDQoNCiAgICAgMTAlICAgICAgMjAlICAgICAgMzAlICAgICAgNDAlICAgICAgNTAlICAgICAgNjAlICAgICAgNzAlICAgICAgODAlIA0KMTM1LjE1MTkgMTY1LjM3NTUgMTg1Ljk5MTQgMjA0LjgxNTIgMjIyLjgyNDAgMjQwLjIyMTYgMjYyLjQ3NzkgMjkwLjk1MTQgDQoNCiAgICAgOTAlIA0KMzQ4LjQ5MzkgDQoNCjMuTG9vayBhdCB0aGUgcHJpbnRvdXQgb2YgdGhlIGRlY2lsZXMuIElmIHlvdSBoYWQgYSBzb25nIHRoYXQgd2FzIDE3MCBzZWNvbmRzIGxvbmcsIHdoYXQgdGVudGggb2YgdGhlIGRhdGFzZXQgd291bGQgaXQgZmFsbCBpbj8NCg0KQ3JlYXRlIGEgdmFyaWFibGUgbmFtZWQgdGVudGggYW5kIHNldCBpdCBlcXVhbCB0byB0aGUgMSBpZiB5b3UgdGhpbmsgdGhlIDE3MCBzZWNvbmQgc29uZyB3b3VsZCBmYWxsIGluIHRoZSBmaXJzdCB0ZW50aCBvZiB0aGUgZGF0YS4gU2V0IGl0IGVxdWFsIHRvIDIgaWYgeW91IHRoaW5rIHRoZSBzb25nIHdvdWxkIGZhbGwgaW4gdGhlIHNlY29uZCB0ZW50aCBvZiB0aGUgZGF0YS4gSWYgeW91IHRoaW5rIHRoZSBzb25nIHdvdWxkIGZhbGwgaW4gdGhlIGZpbmFsIHRlbnRoIG9mIHRoZSBkYXRhLCBzZXQgdGVudGggZXF1YWwgdG8gMTAuDQoNCmBgYHtyfQ0KIyBkZWZpbmUgdGVudGggaGVyZToNCnRlbnRoIDwtIDMNCmBgYA0KDQpgYGB7cn0NCiMgaWdub3JlIHRoZSBjb2RlIGJlbG93IGhlcmU6DQoNCnRyeUNhdGNoKHByaW50KHBhc3RlKGMoIlRoZSBxdWFydGlsZXMgYXJlIixxdWFydGlsZXMsY29sbGFwc2U9IiAiKSkpLCBlcnJvcj1mdW5jdGlvbihlKSB7cHJpbnQoIllvdSBoYXZlbid0IGRlZmluZWQgcXVhcnRpbGVzLiIpfSkNCg0KdHJ5Q2F0Y2gocHJpbnQocGFzdGUoYygiVGhlIGRlY2lsZXMgYXJlIixkZWNpbGVzLGNvbGxhcHNlPSIgIikpKSwgZXJyb3I9ZnVuY3Rpb24oZSkge3ByaW50KCJZb3UgaGF2ZW4ndCBkZWZpbmVkIGRlY2lsZXMuIil9KQ0KYGBgDQoNClsxXSAiVGhlIHF1YXJ0aWxlcyBhcmUiICIxNzUuOTM0MjQiICAgICAgICAgIjIyMi44MjQwNCIgICAgICAgDQoNCls0XSAiMjc1LjQ3MzgzIiAgICAgICAgICIgIiAgICAgICAgICAgICAgICANCg0KDQpbMV0gIlRoZSBkZWNpbGVzIGFyZSIgIjEzNS4xNTE4NzYiICAgICAgIjE2NS4zNzU1NDYiICAgICAgIjE4NS45OTEzOCIgICAgIA0KDQpbNV0gIjIwNC44MTUyMjIiICAgICAgIjIyMi44MjQwNCIgICAgICAgIjI0MC4yMjE1OSIgICAgICAgIjI2Mi40Nzc5MSIgIA0KDQoNCiMgNC5Db21tb24gUXVhbnRpbGVzDQoNCk9uZSBvZiB0aGUgbW9zdCBjb21tb24gcXVhbnRpbGVzIGlzIHRoZSAyLXF1YW50aWxlLiBUaGlzIHZhbHVlIHNwbGl0cyB0aGUgZGF0YSBpbnRvIHR3byBncm91cHMgb2YgZXF1YWwgc2l6ZS4gSGFsZiB0aGUgZGF0YSB3aWxsIGJlIGFib3ZlIHRoaXMgdmFsdWUsIGFuZCBoYWxmIHRoZSBkYXRhIHdpbGwgYmUgYmVsb3cgaXQuIFRoaXMgaXMgYWxzbyBrbm93biBhcyB0aGUgbWVkaWFuIQ0KDQoNCmBgYHtyIFF1YW50aWxlczcsIG91dC53aWR0aD0iNjAlIn0NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJDOi9Vc2Vycy9rdW9hbi9EZXNrdG9wL1IgQ29kZS9RdWFudGlsZXM3LnBuZyIpDQpgYGAgICAgICAgICAgICANCg0KVGhlIDQtcXVhbnRpbGVzLCBvciB0aGUgcXVhcnRpbGVzLCBzcGxpdCB0aGUgZGF0YSBpbnRvIGZvdXIgZ3JvdXBzIG9mIGVxdWFsIHNpemUuIFdlIGZvdW5kIHRoZSBxdWFydGlsZXMgaW4gdGhlIHByZXZpb3VzIGV4ZXJjaXNlLg0KDQpgYGB7ciBRdWFudGlsZXM4LCBvdXQud2lkdGg9IjYwJSJ9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiQzovVXNlcnMva3VvYW4vRGVza3RvcC9SIENvZGUvUXVhbnRpbGVzOC5wbmciKQ0KYGBgIA0KDQpGaW5hbGx5LCB0aGUgcGVyY2VudGlsZXMsIG9yIHRoZSB2YWx1ZXMgdGhhdCBzcGxpdCB0aGUgZGF0YSBpbnRvIDEwMCBncm91cHMsIGFyZSBjb21tb25seSB1c2VkIHRvIGNvbXBhcmUgbmV3IGRhdGEgcG9pbnRzIHRvIHRoZSBkYXRhc2V0LiBZb3UgbWlnaHQgaGVhciBzdGF0ZW1lbnRzIGxpa2Ug4oCcWW91IGFyZSBhYm92ZSB0aGUgODB0aCBwZXJjZW50aWxlIGluIGhlaWdodOKAnS4gVGhpcyBtZWFucyB0aGF0IHlvdXIgaGVpZ2h0IGlzIGFib3ZlIHdoYXRldmVyIHZhbHVlIHNwbGl0cyB0aGUgZmlyc3QgODAlIG9mIHRoZSBkYXRhIGZyb20gdGhlIHJlbWFpbmluZyAyMCUuDQoNCiMjIEluc3RydWN0aW9ucw0KDQoxLldlIHdvbuKAmXQgbWFrZSB5b3UgY2FsY3VsYXRlIGFsbCA5OSBwZXJjZW50aWxlcywgYnV0IGxldOKAmXMgdGFrZSBhIGxvb2sgYXQgb25lLiBGaW5kIHRoZSB2YWx1ZSB0aGF0IHNlcGFyYXRlcyB0aGUgZmlyc3QgMzIlIG9mIHRoZSBkYXRhIGZyb20gdGhlIHJlc3QuDQoNClN0b3JlIHRoYXQgdmFsdWUgaW4gYSB2YXJpYWJsZSBuYW1lZCBwZXJjZW50aWxlLg0KDQpgYGB7cn0NCiMgZGVmaW5lIHBlcmNlbnRpbGUgYW5kIGFuc3dlciBoZXJlOg0KcGVyY2VudGlsZSA8LSBxdWFudGlsZShzb25ncywgMC4zMikNCnBlcmNlbnRpbGUNCmBgYA0KDQogICAgIDMyJSANCjE4OS45MzU5IA0KDQoyLkxvb2sgYXQgdGhlIHByaW50b3V0LiBJZiB5b3UgaGFkIGEgc29uZyB0aGF0IHdhcyBleGFjdGx5IHRocmVlIG1pbnV0ZXMgbG9uZywgaXMgdGhhdCBzb25nIGFib3ZlIG9yIGJlbG93IHRoZSAzMm5kIHBlcmNlbnRpbGU/DQoNCkNyZWF0ZSBhIHZhcmlhYmxlIG5hbWVkIGFuc3dlciBhbmQgc2V0IGl0IGVxdWFsIHRvIGVpdGhlciAiYWJvdmUiIG9yICJiZWxvdyIuIERvbuKAmXQgZm9yZ2V0IHRvIGluY2x1ZGUgdGhlIHF1b3RlcyENCg0KYGBge3J9DQphbnN3ZXIgPC0gImJlbG93Ig0KYGBgDQoNCmBgYHtyfQ0KIyBpZ25vcmUgdGhlIGNvZGUgYmVsb3cgaGVyZToNCg0KdHJ5Q2F0Y2gocHJpbnQocGFzdGUoIllvdXIgcGVyY2VudGlsZSBpcyIscGVyY2VudGlsZSkpLCBlcnJvcj1mdW5jdGlvbihlKSB7cHJpbnQoIllvdSBoYXZlbid0IGRlZmluZWQgcGVyY2VudGlsZSIpfSkNCmBgYA0KDQpbMV0gIllvdXIgcGVyY2VudGlsZSBpcyAxODkuOTM1ODciDQoNCiMgNS5RdWFudGlsZXMgUmV2aWV3DQoNCk5pY2Ugd29yayEgSGVyZSBhcmUgc29tZSBvZiB0aGUgbWFqb3IgdGFrZWF3YXlzIGFib3V0IHF1YW50aWxlczoNCg0KMS5RdWFudGlsZXMgYXJlIHZhbHVlcyB0aGF0IHNwbGl0IGEgZGF0YXNldCBpbnRvIGdyb3VwcyBvZiBlcXVhbCBzaXplLg0KDQoyLklmIHlvdSBoYXZlIG4gcXVhbnRpbGVzLCB0aGUgZGF0YXNldCB3aWxsIGJlIHNwbGl0IGludG8gbisxIGdyb3VwcyBvZiBlcXVhbCBzaXplLg0KDQozLlRoZSBtZWRpYW4gaXMgYSBxdWFudGlsZS4gSXQgaXMgdGhlIG9ubHkgMi1xdWFudGlsZS4gSGFsZiB0aGUgZGF0YSBmYWxscyBiZWxvdyB0aGUgbWVkaWFuIGFuZCBoYWxmIGZhbGxzIGFib3ZlIHRoZSBtZWRpYW4uDQoNCjQuUXVhcnRpbGVzIGFuZCBwZXJjZW50aWxlcyBhcmUgb3RoZXIgY29tbW9uIHF1YW50aWxlcy4gUXVhcnRpbGVzIHNwbGl0IHRoZSBkYXRhIGludG8gNCBncm91cHMgd2hpbGUgcGVyY2VudGlsZXMgc3BsaXQgdGhlIGRhdGEgaW50byAxMDAgZ3JvdXBzLg0KDQojIyBJbnN0cnVjdGlvbnMNCg0KVG8gdGhlIHJpZ2h0LCB3ZeKAmXZlIHNob3duIHRocmVlIGRpZmZlcmVudCBoaXN0b2dyYW1zIGFsb25nIHdpdGggdGhlIGRlY2lsZXMuIEVhY2ggaGlzdG9ncmFtIHNob3dzIHRoZSBTQVQgc2NvcmVzIG9mIHRoZSBzdHVkZW50cyB0aGF0IGEgZmFrZSB1bml2ZXJzaXR5IGhhcyBhY2NlcHRlZC4NCg0KSWYgeW91IGhhZCBhbiBTQVQgc2NvcmUgb2YgMTM1MCwgd2hpY2ggdGVudGggb2YgdGhlIGRhdGEgd291bGQgeW91IGJlIGluIGZvciBlYWNoIHNjaG9vbD8gV2hpY2ggc2Nob29scyBzaG91bGQgeW91IGFwcGx5IHRvPyBXb3VsZCBhbnkgb2YgdGhlIHNjaG9vbHMgYmUgdW5yZWFsaXN0aWMgb3B0aW9ucz8NCg0KYGBge3IgUXVhbnRpbGVzOSwgb3V0LndpZHRoPSI2MCUifQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoIkM6L1VzZXJzL2t1b2FuL0Rlc2t0b3AvUiBDb2RlL1F1YW50aWxlczkucG5nIikNCmBgYA0KYGBge3IgUXVhbnRpbGVzMTAsIG91dC53aWR0aD0iNjAlIn0NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJDOi9Vc2Vycy9rdW9hbi9EZXNrdG9wL1IgQ29kZS9RdWFudGlsZXMxMC5wbmciKQ0KYGBgDQpgYGB7ciBRdWFudGlsZXMxMSwgb3V0LndpZHRoPSI2MCUifQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoIkM6L1VzZXJzL2t1b2FuL0Rlc2t0b3AvUiBDb2RlL1F1YW50aWxlczExLnBuZyIpDQpgYGA=