R The calculator
The simplest way to use R is as a calculator.
For example, the code below calculates \(1+1\). Click “run” (the green play button) to see:
[1] 2
Notice the part after “#” (inside a code chunk) is not executed because it as a comment. Write comments to remind yourself (or rather, your future self, who will read the code later) what the code does.
Here is another example. This code calculates \(2^3 + 4 \times 5 + \frac{5}{6}\):
2^3 + 4*5 + 5/6 # two to the third plus four times five plus five divided by six
[1] 28.83333
Checkpoint
Calculate \(2^2 \times 3^3\):
[1] 108
Calculate \(2/3 + 4/5 + 6/7\):
[1] 2.32381
Calculate \(2^3 + 4*5 + 6^7\):
[1] 279964
Objects
OK, we can use R to make calculations.
But what if we want to save the output of one calculation and use it in another calculation?
R has memory. What does it remember? Whatever you tell it to! This is called defining objects.
Suppose we want to calculate \(1+1\) and store it in an object. We have to give it a name. Let’s call it “x”:
Notice two things:
=
is the assignment operator. It says: "take 1+1 and assign its output to x
.
- When we run the code,
x = 1 + 1
, nothing spits out. That’s because the output is stored in x
.
What happens if we calculate \(x+2\)
[1] 4
It’s the same as calculating \((1+1)+2\).
Let’s create another object called “my_object” equal to \(x \times 4\):
Vectors
Vectors are objects with multiple values.
For example, here is a vector with the values \(1,2,3,4\) called “data_vector”:
my_vector = c(1,2,3,4) # create a vector
my_vector # then print it to the screen
[1] 1 2 3 4
We can multiply each value by 2:
[1] 2 4 6 8
and we multiply each value by 2 and create a new vector (e.g., “data_new_vector”):
data_new_vector = my_vector * 2
Vectors can also contain words – also referred to as “strings” or “characters”.
For instance, here is a vector with the words “hello” and “world”:
character_vector <- c("hello", "world") # make the vector
character_vector # view it!
[1] "hello" "world"
Functions
Objects are nouns. Functions are verbs, acting on those nouns. That is programming in R in a nutshell. You have a data set (object). You do things to that data set (e.g., analyze with functions).
All functions in R have parentheses: function()
. When we created a vector we used the function c()
.
If we have a vector of data, like data_new_vector
, we can calculate the sum with sum()
:
[1] 20
Or find the maximum value with max()
:
[1] 8
Or find the minimum value with min()
:
[1] 2
Or calculate the average or mean with mean()
:
[1] 5
Checkpoint
Recall that you create a vector with c()
and assign it with =
. For example, the chunk below creates a vector called “v” with values \(1,2,3\):
Create a vector called “x” with the values \(5, 9, 4, 8, 40, 22\):
Multiply x
by 2:
[1] 10 18 8 16 80 44
Calculate the sum of x
with the function sum()
:
[1] 88
Calculate the average of x
with mean()
:
[1] 14.66667
Calculate the median of x
with median()
:
[1] 8.5
Calculate the standard deviation of x
with sd()
:
[1] 13.99524
Dataframes
Dataframes – like what you see in an Excel sheet – are just vectors chained together.
Let’s load the tidyverse
:
and then load a built-in dataset called “diamonds” with prices of over 50,000 round cut diamonds:
data("diamonds") # use the function data() to load a built-in dataset
You can view the data inside the notebook like so:
or you can click on in the “Environment” window pane in the top-right corner of RStudio.
Notice the data contains a variety of data types, such as:
price
, carat
, depth
, table
: continuous, numerical variables (scale: ratio)
color
: categorical variable (scale: nominal, i.e. a classification with no ranking)
cut
: categorical variable (scale: ordinal, i.e. you can rank them)
Summarizing data
Suppose you wanted to calculate the average price of a diamond. You would
- take the data, THEN
- summarize it by calculating mean miles per gallon
In R those two steps are:
diamonds %>% # take the data, THEN
summarise(mean(price)) # summarize it by calculating average price
But not all diamonds are created equal! (According to De Beers.)
Let’s group diamonds by their cut
class
and then calculate the mean price:
diamonds %>% # take the data, THEN
group_by(cut) %>% # group the diamonds by cut, THEN
summarise(mean(price)) # summarize the data by calculating average price by cut
Checkpoint
Group the diamonds by clarity (clarity
) and then calculate average price:
diamonds %>%
group_by(clarity) %>%
summarise(mean(price))
Now group diamonds by cut
and calculate average (mean()
), median (median()
) and standard deviation (sd()
) price. Hint: you only need one call to summarise()
!
diamonds %>%
group_by(cut) %>%
summarise(mean(price), median(price), sd(price))
Visualizing data
One of the most important plots is the histogram. This tells you how observations are distributed. Understanding distributions is the bedrock of statistical modeling.
Let’s plot the distribution of prices:
ggplot(data = diamonds, aes(x = price)) +
geom_histogram()
The distribution is heavily skewed. Clearly the average price is not meaningful! Why? Because if you were to randomly draw from this distribution, you would not get a diamond close to the average.
To see this let’s re-plot the distribution but now with a vertical line at the average price:
ggplot(data = diamonds, aes(x = price)) +
geom_histogram() +
geom_vline(xintercept = 3932.8, color = "red")
Another key plot type is the scatter plot. Use this to study relationships.
Let’s make a scatter plot of cty
by hwy
:
Is there a relationship between a diamond’s carats (carat
) and its price?
We might think about a model in which carats determine prices (and not the other way round). That is, prices are a function of carats:
\[
\text{price} = f(\text{carats})
\] This model implies carat
should be on the x-axis and price
on the y-axis:
ggplot(data = diamonds, aes(x = carat, y = price)) +
geom_point()
Looks so!
Checkpoint
Plot the distribution of table
(another diamond attribute)L
ggplot(data = diamonds, aes(x = table)) +
geom_histogram()
Replicate the code above but now plot the distribution of depth
with geom_density()
so you have kernel density estimate (basically a smooth histogram):
ggplot(data = diamonds, aes(x = depth)) +
geom_density()
Based on this plot do you think the average depth of a diamond is meaningful?
Plots by category
Many times we care about outcomes conditional on some category.
Just like dplyr
makes it easy to ggplot
makes it very easy to plot by a grouping variables.
There are two approaches.
Fill and color
First, create a single panel, and fill
(histograms, boxplots, kernel densities) or color
(scatter plots) by the group:
ggplot(data = diamonds, aes(x = price, fill = cut)) +
geom_histogram()
and for a scatterplot:
ggplot(data = diamonds, aes(x = carat, y = price, color = cut)) +
geom_point()
Facetting
But these types of plots are usually hard to read
Instead you can put each group in its own panel with facet_wrap()
:
ggplot(data = diamonds, aes(x = price)) +
geom_histogram() +
facet_wrap(~cut)
ggplot(data = diamonds, aes(x = carat, y = price)) +
geom_point() +
facet_wrap(~cut) # note the "~" before the grouping variable
or you can even make a grid of plots by two categories using facet_grid()
:
ggplot(data = diamonds, aes(x = price)) +
geom_histogram() +
facet_grid(color~cut)
LS0tCnRpdGxlOiAiSW50cm9kdWN0aW9uIHRvIFIgKENvbXBsZXRlZCBOb3RlYm9vaykiCnN1YnRpdGxlOiAiUiBmb3IgRGF0YSBTY2llbmNlIgphdXRob3I6ICJMREciCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazoKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgdGhlbWU6IHJlYWRhYmxlCiAgICBoaWdobGlnaHQ6IHB5Z21lbnRzCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogCiAgICAgIGNvbGxhcHNlZDogeWVzCi0tLQoKIyBSIFRoZSBjYWxjdWxhdG9yCgpUaGUgc2ltcGxlc3Qgd2F5IHRvIHVzZSBSIGlzIGFzIGEgY2FsY3VsYXRvci4gCgpGb3IgZXhhbXBsZSwgdGhlIGNvZGUgYmVsb3cgY2FsY3VsYXRlcyAkMSsxJC4gQ2xpY2sgInJ1biIgKHRoZSBncmVlbiBwbGF5IGJ1dHRvbikgdG8gc2VlOgoKYGBge3IgY2FsYzF9CjErMSAjIGFkZCBvbmUgYW5kIG9uZQpgYGAKCk5vdGljZSB0aGUgcGFydCBhZnRlciAiIyIgKGluc2lkZSBhIGNvZGUgY2h1bmspIGlzIG5vdCBleGVjdXRlZCBiZWNhdXNlIGl0IGFzIGEgKipjb21tZW50LioqIFdyaXRlIGNvbW1lbnRzIHRvIHJlbWluZCB5b3Vyc2VsZiAob3IgcmF0aGVyLCB5b3VyIGZ1dHVyZSBzZWxmLCB3aG8gd2lsbCByZWFkIHRoZSBjb2RlIGxhdGVyKSB3aGF0IHRoZSBjb2RlIGRvZXMuCgpIZXJlIGlzIGFub3RoZXIgZXhhbXBsZS4gVGhpcyBjb2RlIGNhbGN1bGF0ZXMgJDJeMyArIDQgXHRpbWVzIDUgKyBcZnJhY3s1fXs2fSQ6CgpgYGB7ciBjYWxjMn0KMl4zICsgNCo1ICsgNS82ICMgdHdvIHRvIHRoZSB0aGlyZCBwbHVzIGZvdXIgdGltZXMgZml2ZSBwbHVzIGZpdmUgZGl2aWRlZCBieSBzaXgKYGBgCgojIyBDaGVja3BvaW50CgpDYWxjdWxhdGUgJDJeMiBcdGltZXMgM14zJDoKCmBgYHtyIGNoZWNrcG9pbnQgY2FsYzF9CjJeMiAqIDNeMwpgYGAKCkNhbGN1bGF0ZSAkMi8zICsgNC81ICsgNi83JDoKCmBgYHtyIGNoZWNrcG9pbnQgY2FsYzJ9CjIvMyArIDQvNSArIDYvNwpgYGAKCkNhbGN1bGF0ZSAkMl4zICsgNCo1ICsgNl43JDoKCmBgYHtyIGNoZWNrcG9pbnQgY2FsYzN9CjJeMyArIDQqNSArIDZeNwpgYGAKCiMjIE9iamVjdHMKCk9LLCB3ZSBjYW4gdXNlIFIgdG8gbWFrZSBjYWxjdWxhdGlvbnMuCgpCdXQgd2hhdCBpZiB3ZSB3YW50IHRvIHNhdmUgdGhlIG91dHB1dCBvZiBvbmUgY2FsY3VsYXRpb24gYW5kIHVzZSBpdCBpbiBhbm90aGVyIGNhbGN1bGF0aW9uPwoKUiBoYXMgbWVtb3J5LiBXaGF0IGRvZXMgaXQgcmVtZW1iZXI/IFdoYXRldmVyIHlvdSB0ZWxsIGl0IHRvISBUaGlzIGlzIGNhbGxlZCAqKmRlZmluaW5nIG9iamVjdHMqKi4KClN1cHBvc2Ugd2Ugd2FudCB0byBjYWxjdWxhdGUgJDErMSQgYW5kIHN0b3JlIGl0IGluIGFuIG9iamVjdC4gV2UgaGF2ZSB0byBnaXZlIGl0IGEgbmFtZS4gTGV0J3MgY2FsbCBpdCAieCI6CgpgYGB7ciBvYmplY3RzMX0KeCA9IDEgKyAxCmBgYAoKTm90aWNlIHR3byB0aGluZ3M6CgoxLiBgPWAgaXMgdGhlICoqYXNzaWdubWVudCBvcGVyYXRvcioqLiBJdCBzYXlzOiAidGFrZSAxKzEgYW5kIGFzc2lnbiBpdHMgKm91dHB1dCogdG8gYHhgLgoyLiBXaGVuIHdlIHJ1biB0aGUgY29kZSwgYHggPSAxICsgMWAsIG5vdGhpbmcgc3BpdHMgb3V0LiBUaGF0J3MgYmVjYXVzZSB0aGUgb3V0cHV0IGlzICoqc3RvcmVkKiogaW4gYHhgLgoKV2hhdCBoYXBwZW5zIGlmIHdlIGNhbGN1bGF0ZSAkeCsyJAoKYGBge3Igb2JqZWN0czJ9CnggKyAyCmBgYAoKSXQncyB0aGUgc2FtZSBhcyBjYWxjdWxhdGluZyAkKDErMSkrMiQuIAoKTGV0J3MgY3JlYXRlIGFub3RoZXIgb2JqZWN0IGNhbGxlZCAibXlfb2JqZWN0IiBlcXVhbCB0byAkeCBcdGltZXMgNCQ6CgpgYGB7ciBvYmplY3RzM30KbXlfb2JqZWN0ID0geCAqIDQKYGBgCgojIyBWZWN0b3JzCgpWZWN0b3JzIGFyZSBvYmplY3RzIHdpdGggbXVsdGlwbGUgdmFsdWVzLiAKCkZvciBleGFtcGxlLCBoZXJlIGlzIGEgdmVjdG9yIHdpdGggdGhlIHZhbHVlcyAkMSwyLDMsNCQgY2FsbGVkICJkYXRhX3ZlY3RvciI6CgpgYGB7ciB2ZWMxfQpteV92ZWN0b3IgPSBjKDEsMiwzLDQpICMgY3JlYXRlIGEgdmVjdG9yCm15X3ZlY3RvciAjIHRoZW4gcHJpbnQgaXQgdG8gdGhlIHNjcmVlbgpgYGAKCldlIGNhbiBtdWx0aXBseSBlYWNoIHZhbHVlIGJ5IDI6CgpgYGB7ciB2ZWMyfQpteV92ZWN0b3IgKiAyCmBgYAoKYW5kIHdlIG11bHRpcGx5IGVhY2ggdmFsdWUgYnkgMiBhbmQgY3JlYXRlIGEgbmV3IHZlY3RvciAoZS5nLiwgImRhdGFfbmV3X3ZlY3RvciIpOgoKYGBge3IgdmVjM30KZGF0YV9uZXdfdmVjdG9yID0gbXlfdmVjdG9yICogMgpgYGAKClZlY3RvcnMgY2FuIGFsc28gY29udGFpbiB3b3JkcyAtLSBhbHNvIHJlZmVycmVkIHRvIGFzICJzdHJpbmdzIiBvciAiY2hhcmFjdGVycyIuIAoKRm9yIGluc3RhbmNlLCBoZXJlIGlzIGEgdmVjdG9yIHdpdGggdGhlIHdvcmRzICJoZWxsbyIgYW5kICJ3b3JsZCI6CgpgYGB7ciB2ZWM0fQpjaGFyYWN0ZXJfdmVjdG9yIDwtIGMoImhlbGxvIiwgIndvcmxkIikgIyBtYWtlIHRoZSB2ZWN0b3IKY2hhcmFjdGVyX3ZlY3RvciAjIHZpZXcgaXQhCmBgYAoKCiMjIEZ1bmN0aW9ucwoKT2JqZWN0cyBhcmUgbm91bnMuIEZ1bmN0aW9ucyBhcmUgdmVyYnMsIGFjdGluZyBvbiB0aG9zZSBub3Vucy4gVGhhdCBpcyBwcm9ncmFtbWluZyBpbiBSIGluIGEgbnV0c2hlbGwuIFlvdSBoYXZlIGEgZGF0YSBzZXQgKG9iamVjdCkuIFlvdSBkbyB0aGluZ3MgdG8gdGhhdCBkYXRhIHNldCAoZS5nLiwgYW5hbHl6ZSB3aXRoIGZ1bmN0aW9ucykuCgpBbGwgZnVuY3Rpb25zIGluIFIgaGF2ZSBwYXJlbnRoZXNlczogYGZ1bmN0aW9uKClgLiBXaGVuIHdlIGNyZWF0ZWQgYSB2ZWN0b3Igd2UgdXNlZCB0aGUgZnVuY3Rpb24gYGMoKWAuCgpJZiB3ZSBoYXZlIGEgdmVjdG9yIG9mIGRhdGEsIGxpa2UgYGRhdGFfbmV3X3ZlY3RvcmAsIHdlIGNhbiBjYWxjdWxhdGUgdGhlIHN1bSB3aXRoIGBzdW0oKWA6CgpgYGB7ciBmdW5jdGlvbjF9CnN1bShkYXRhX25ld192ZWN0b3IpCmBgYAoKT3IgZmluZCB0aGUgbWF4aW11bSB2YWx1ZSB3aXRoIGBtYXgoKWA6CgpgYGB7ciBmdW5jdGlvbjJ9Cm1heChkYXRhX25ld192ZWN0b3IpCmBgYAoKT3IgZmluZCB0aGUgbWluaW11bSB2YWx1ZSB3aXRoIGBtaW4oKWA6CgpgYGB7ciBmdW5jdGlvbjN9Cm1pbihkYXRhX25ld192ZWN0b3IpCmBgYAoKT3IgY2FsY3VsYXRlIHRoZSBhdmVyYWdlIG9yIG1lYW4gd2l0aCBgbWVhbigpYDoKCmBgYHtyIGZ1bmN0aW9uNH0KbWVhbihkYXRhX25ld192ZWN0b3IpCmBgYAoKCiMjIENoZWNrcG9pbnQgCgpSZWNhbGwgdGhhdCB5b3UgY3JlYXRlIGEgdmVjdG9yIHdpdGggYGMoKWAgYW5kIGFzc2lnbiBpdCB3aXRoIGA9YC4gRm9yIGV4YW1wbGUsIHRoZSBjaHVuayBiZWxvdyBjcmVhdGVzIGEgdmVjdG9yIGNhbGxlZCAidiIgd2l0aCB2YWx1ZXMgJDEsMiwzJDoKCmBgYHtyfQp2ID0gYygxLDIsMykKYGBgCgpDcmVhdGUgYSB2ZWN0b3IgY2FsbGVkICJ4IiB3aXRoIHRoZSB2YWx1ZXMgJDUsIDksIDQsIDgsIDQwLCAyMiQ6CgpgYGB7ciBjaGVja3BvaW50IG9iamVjdHNfZnVuY3Rpb25zXzF9CnggPC0gYyg1LDksNCw4LDQwLDIyKQpgYGAKCk11bHRpcGx5IGB4YCBieSAyOgoKYGBge3IgY2hlY2twb2ludCBvYmplY3RzX2Z1bmN0aW9uc18yfQp4KjIKYGBgCgpDYWxjdWxhdGUgdGhlIHN1bSBvZiBgeGAgd2l0aCB0aGUgZnVuY3Rpb24gYHN1bSgpYDoKCmBgYHtyIGNoZWNrcG9pbnQgb2JqZWN0c19mdW5jdGlvbnNfM30Kc3VtKHgpCmBgYAoKQ2FsY3VsYXRlIHRoZSBhdmVyYWdlIG9mIGB4YCB3aXRoIGBtZWFuKClgOgoKYGBge3IgY2hlY2twb2ludCBvYmplY3RzX2Z1bmN0aW9uc180fQptZWFuKHgpCmBgYAoKQ2FsY3VsYXRlIHRoZSBtZWRpYW4gb2YgYHhgIHdpdGggYG1lZGlhbigpYDoKCmBgYHtyIGNoZWNrcG9pbnQgb2JqZWN0c19mdW5jdGlvbnNfNX0KbWVkaWFuKHgpCmBgYAoKQ2FsY3VsYXRlIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gb2YgYHhgIHdpdGggYHNkKClgOgoKYGBge3IgY2hlY2twb2ludCBvYmplY3RzX2Z1bmN0aW9uc182fQpzZCh4KQpgYGAKCiMgRGF0YWZyYW1lcwoKRGF0YWZyYW1lcyAtLSBsaWtlIHdoYXQgeW91IHNlZSBpbiBhbiBFeGNlbCBzaGVldCAtLSBhcmUganVzdCB2ZWN0b3JzIGNoYWluZWQgdG9nZXRoZXIuIAoKTGV0J3MgbG9hZCB0aGUgYHRpZHl2ZXJzZWA6CgpgYGB7ciBsb2FkIHRpZHl2ZXJzZSwgbWVzc2FnZT1GQUxTRX0KbGlicmFyeSh0aWR5dmVyc2UpCmBgYAoKYW5kIHRoZW4gbG9hZCBhIGJ1aWx0LWluIGRhdGFzZXQgY2FsbGVkICJkaWFtb25kcyIgd2l0aCBwcmljZXMgb2Ygb3ZlciA1MCwwMDAgcm91bmQgY3V0IGRpYW1vbmRzOgoKYGBge3IgbG9hZCBkaWFtb25kc30KZGF0YSgiZGlhbW9uZHMiKSAjIHVzZSB0aGUgZnVuY3Rpb24gZGF0YSgpIHRvIGxvYWQgYSBidWlsdC1pbiBkYXRhc2V0CmBgYAoKWW91IGNhbiB2aWV3IHRoZSBkYXRhIGluc2lkZSB0aGUgbm90ZWJvb2sgbGlrZSBzbzoKCmBgYHtyIHZpZXcgZGlhbW9uZHN9CmRpYW1vbmRzCmBgYAoKb3IgeW91IGNhbiBjbGljayBvbiBpbiB0aGUgIkVudmlyb25tZW50IiB3aW5kb3cgcGFuZSBpbiB0aGUgdG9wLXJpZ2h0IGNvcm5lciBvZiBSU3R1ZGlvLgoKTm90aWNlIHRoZSBkYXRhIGNvbnRhaW5zIGEgdmFyaWV0eSBvZiBkYXRhICoqdHlwZXMqKiwgc3VjaCBhczoKCiogYHByaWNlYCwgYGNhcmF0YCwgYGRlcHRoYCwgYHRhYmxlYDogY29udGludW91cywgbnVtZXJpY2FsIHZhcmlhYmxlcyAoc2NhbGU6IHJhdGlvKQoqIGBjb2xvcmA6IGNhdGVnb3JpY2FsIHZhcmlhYmxlIChzY2FsZTogbm9taW5hbCwgaS5lLiBhIGNsYXNzaWZpY2F0aW9uIHdpdGggbm8gcmFua2luZykKKiBgY3V0YDogY2F0ZWdvcmljYWwgdmFyaWFibGUgKHNjYWxlOiBvcmRpbmFsLCBpLmUuIHlvdSBjYW4gcmFuayB0aGVtKQoKIyMgU3VtbWFyaXppbmcgZGF0YQoKU3VwcG9zZSB5b3Ugd2FudGVkIHRvIGNhbGN1bGF0ZSB0aGUgYXZlcmFnZSBwcmljZSBvZiBhIGRpYW1vbmQuIFlvdSB3b3VsZAoKMS4gdGFrZSB0aGUgZGF0YSwgVEhFTgoyLiBzdW1tYXJpemUgaXQgYnkgY2FsY3VsYXRpbmcgbWVhbiBtaWxlcyBwZXIgZ2FsbG9uCgpJbiBSIHRob3NlIHR3byBzdGVwcyBhcmU6CgpgYGB7ciBkcGx5cjF9CmRpYW1vbmRzICU+JSAjIHRha2UgdGhlIGRhdGEsIFRIRU4KICBzdW1tYXJpc2UobWVhbihwcmljZSkpICMgc3VtbWFyaXplIGl0IGJ5IGNhbGN1bGF0aW5nIGF2ZXJhZ2UgcHJpY2UKYGBgCgpCdXQgbm90IGFsbCBkaWFtb25kcyBhcmUgY3JlYXRlZCBlcXVhbCEgKEFjY29yZGluZyB0byBEZSBCZWVycy4pCgpMZXQncyBncm91cCBkaWFtb25kcyBieSB0aGVpciBgY3V0YCBgY2xhc3NgIGFuZCB0aGVuIGNhbGN1bGF0ZSB0aGUgbWVhbiBwcmljZToKCmBgYHtyIGRwbHlyMiwgbWVzc2FnZT1GQUxTRX0KZGlhbW9uZHMgJT4lICMgdGFrZSB0aGUgZGF0YSwgVEhFTgogIGdyb3VwX2J5KGN1dCkgJT4lICAjIGdyb3VwIHRoZSBkaWFtb25kcyBieSBjdXQsIFRIRU4KICBzdW1tYXJpc2UobWVhbihwcmljZSkpICMgc3VtbWFyaXplIHRoZSBkYXRhIGJ5IGNhbGN1bGF0aW5nIGF2ZXJhZ2UgcHJpY2UgYnkgY3V0CmBgYAoKIyMjIENoZWNrcG9pbnQKCkdyb3VwIHRoZSBkaWFtb25kcyBieSBjbGFyaXR5IChgY2xhcml0eWApIGFuZCB0aGVuIGNhbGN1bGF0ZSBhdmVyYWdlIHByaWNlOgoKYGBge3IgY2hlY2twb2ludCBkcGx5cjEsIG1lc3NhZ2UgPSBGQUxTRX0KZGlhbW9uZHMgJT4lIAogIGdyb3VwX2J5KGNsYXJpdHkpICU+JSAKICBzdW1tYXJpc2UobWVhbihwcmljZSkpCmBgYAoKTm93IGdyb3VwIGRpYW1vbmRzIGJ5IGBjdXRgIGFuZCBjYWxjdWxhdGUgYXZlcmFnZSAoYG1lYW4oKWApLCBtZWRpYW4gKGBtZWRpYW4oKWApIGFuZCBzdGFuZGFyZCBkZXZpYXRpb24gKGBzZCgpYCkgcHJpY2UuIEhpbnQ6IHlvdSBvbmx5IG5lZWQgb25lIGNhbGwgdG8gYHN1bW1hcmlzZSgpYCEKCmBgYHtyIGNoZWNrcG9pbnQgZHBseXIyLCBtZXNzYWdlPUZBTFNFfQpkaWFtb25kcyAlPiUgCiAgZ3JvdXBfYnkoY3V0KSAlPiUgCiAgc3VtbWFyaXNlKG1lYW4ocHJpY2UpLCBtZWRpYW4ocHJpY2UpLCBzZChwcmljZSkpCmBgYAoKIyMgVmlzdWFsaXppbmcgZGF0YQoKT25lIG9mIHRoZSBtb3N0IGltcG9ydGFudCBwbG90cyBpcyB0aGUgKipoaXN0b2dyYW0qKi4gVGhpcyB0ZWxscyB5b3UgaG93IG9ic2VydmF0aW9ucyBhcmUgKipkaXN0cmlidXRlZCoqLiBVbmRlcnN0YW5kaW5nIGRpc3RyaWJ1dGlvbnMgaXMgdGhlIGJlZHJvY2sgb2Ygc3RhdGlzdGljYWwgbW9kZWxpbmcuCgpMZXQncyBwbG90IHRoZSAqKmRpc3RyaWJ1dGlvbioqIG9mIHByaWNlczoKCmBgYHtyIGdncGxvdDF9CmdncGxvdChkYXRhID0gZGlhbW9uZHMsIGFlcyh4ID0gcHJpY2UpKSArIAogIGdlb21faGlzdG9ncmFtKCkKYGBgCgpUaGUgZGlzdHJpYnV0aW9uIGlzIGhlYXZpbHkgc2tld2VkLiBDbGVhcmx5IHRoZSAqKmF2ZXJhZ2UgcHJpY2UqKiBpcyBub3QgbWVhbmluZ2Z1bCEgV2h5PyBCZWNhdXNlIGlmIHlvdSB3ZXJlIHRvIHJhbmRvbWx5IGRyYXcgZnJvbSB0aGlzIGRpc3RyaWJ1dGlvbiwgeW91IHdvdWxkIG5vdCBnZXQgYSBkaWFtb25kIGNsb3NlIHRvIHRoZSBhdmVyYWdlLgoKVG8gc2VlIHRoaXMgbGV0J3MgcmUtcGxvdCB0aGUgZGlzdHJpYnV0aW9uIGJ1dCBub3cgd2l0aCBhIHZlcnRpY2FsIGxpbmUgYXQgdGhlIGF2ZXJhZ2UgcHJpY2U6CgpgYGB7ciBnZ3Bsb3QxIGNvbnRpbnVlZH0KZ2dwbG90KGRhdGEgPSBkaWFtb25kcywgYWVzKHggPSBwcmljZSkpICsgCiAgZ2VvbV9oaXN0b2dyYW0oKSArIAogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDM5MzIuOCwgY29sb3IgPSAicmVkIikKYGBgCkFub3RoZXIga2V5IHBsb3QgdHlwZSBpcyB0aGUgKipzY2F0dGVyIHBsb3QqKi4gVXNlIHRoaXMgdG8gc3R1ZHkgKipyZWxhdGlvbnNoaXBzKiouCgpMZXQncyBtYWtlIGEgc2NhdHRlciBwbG90IG9mIGBjdHlgIGJ5IGBod3lgOgoKSXMgdGhlcmUgYSByZWxhdGlvbnNoaXAgYmV0d2VlbiBhIGRpYW1vbmQncyBjYXJhdHMgKGBjYXJhdGApIGFuZCBpdHMgcHJpY2U/CgpXZSBtaWdodCB0aGluayBhYm91dCBhIG1vZGVsIGluIHdoaWNoIGNhcmF0cyBkZXRlcm1pbmUgcHJpY2VzIChhbmQgbm90IHRoZSBvdGhlciB3YXkgcm91bmQpLiBUaGF0IGlzLCBwcmljZXMgYXJlIGEgKipmdW5jdGlvbioqIG9mIGNhcmF0czoKCiQkClx0ZXh0e3ByaWNlfSA9IGYoXHRleHR7Y2FyYXRzfSkKJCQKVGhpcyBtb2RlbCBpbXBsaWVzIGBjYXJhdGAgc2hvdWxkIGJlIG9uIHRoZSB4LWF4aXMgYW5kIGBwcmljZWAgb24gdGhlIHktYXhpczoKCmBgYHtyIGdncGxvdDJ9CmdncGxvdChkYXRhID0gZGlhbW9uZHMsIGFlcyh4ID0gY2FyYXQsIHkgPSBwcmljZSkpICsgCiAgZ2VvbV9wb2ludCgpCmBgYApMb29rcyBzbyEKCiMjIyBDaGVja3BvaW50CgpQbG90IHRoZSBkaXN0cmlidXRpb24gb2YgYHRhYmxlYCAoYW5vdGhlciBkaWFtb25kIGF0dHJpYnV0ZSlMCgpgYGB7ciBjaGVja3BvaW50IGdncGxvdCAxfQpnZ3Bsb3QoZGF0YSA9IGRpYW1vbmRzLCBhZXMoeCA9IHRhYmxlKSkgKyAKICBnZW9tX2hpc3RvZ3JhbSgpCmBgYAoKClJlcGxpY2F0ZSB0aGUgY29kZSBhYm92ZSBidXQgbm93IHBsb3QgdGhlIGRpc3RyaWJ1dGlvbiBvZiBgZGVwdGhgIHdpdGggYGdlb21fZGVuc2l0eSgpYCBzbyB5b3UgaGF2ZSBrZXJuZWwgZGVuc2l0eSBlc3RpbWF0ZSAoYmFzaWNhbGx5IGEgc21vb3RoIGhpc3RvZ3JhbSk6CgpgYGB7ciBjaGVja3BvaW50IGdncGxvdCAyfQpnZ3Bsb3QoZGF0YSA9IGRpYW1vbmRzLCBhZXMoeCA9IGRlcHRoKSkgKyAKICBnZW9tX2RlbnNpdHkoKQpgYGAKQmFzZWQgb24gdGhpcyBwbG90IGRvIHlvdSB0aGluayB0aGUgYXZlcmFnZSBkZXB0aCBvZiBhIGRpYW1vbmQgaXMgbWVhbmluZ2Z1bD8KCiMjIFBsb3RzIGJ5IGNhdGVnb3J5CgpNYW55IHRpbWVzIHdlIGNhcmUgYWJvdXQgb3V0Y29tZXMgY29uZGl0aW9uYWwgb24gc29tZSBjYXRlZ29yeS4gCgpKdXN0IGxpa2UgYGRwbHlyYCBtYWtlcyBpdCBlYXN5IHRvIGBnZ3Bsb3RgIG1ha2VzIGl0IHZlcnkgZWFzeSB0byBwbG90IGJ5IGEgZ3JvdXBpbmcgdmFyaWFibGVzLiAKClRoZXJlIGFyZSB0d28gYXBwcm9hY2hlcy4gCgojIyMgRmlsbCBhbmQgY29sb3IKCkZpcnN0LCBjcmVhdGUgYSBzaW5nbGUgcGFuZWwsIGFuZCBgZmlsbGAgKGhpc3RvZ3JhbXMsIGJveHBsb3RzLCBrZXJuZWwgZGVuc2l0aWVzKSBvciBgY29sb3JgIChzY2F0dGVyIHBsb3RzKSBieSB0aGUgZ3JvdXA6CgpgYGB7ciBnZ3Bsb3QgZmlsbH0KZ2dwbG90KGRhdGEgPSBkaWFtb25kcywgYWVzKHggPSBwcmljZSwgZmlsbCA9IGN1dCkpICsgCiAgZ2VvbV9oaXN0b2dyYW0oKQpgYGAKCmFuZCBmb3IgYSBzY2F0dGVycGxvdDoKCmBgYHtyIGdncGxvdCBjb2xvcn0KZ2dwbG90KGRhdGEgPSBkaWFtb25kcywgYWVzKHggPSBjYXJhdCwgeSA9IHByaWNlLCBjb2xvciA9IGN1dCkpICsgCiAgZ2VvbV9wb2ludCgpCmBgYAoKIyMjIEZhY2V0dGluZwoKQnV0IHRoZXNlIHR5cGVzIG9mIHBsb3RzIGFyZSB1c3VhbGx5IGhhcmQgdG8gcmVhZCAKCkluc3RlYWQgeW91IGNhbiBwdXQgZWFjaCBncm91cCBpbiBpdHMgb3duIHBhbmVsIHdpdGggYGZhY2V0X3dyYXAoKWA6CgpgYGB7ciBmYWNldCBoaXN0b2dyYW19CmdncGxvdChkYXRhID0gZGlhbW9uZHMsIGFlcyh4ID0gcHJpY2UpKSArIAogIGdlb21faGlzdG9ncmFtKCkgKyAKICBmYWNldF93cmFwKH5jdXQpCmBgYAoKCmBgYHtyIGZhY2V0IHNjYXR0ZXJwbG90fQpnZ3Bsb3QoZGF0YSA9IGRpYW1vbmRzLCBhZXMoeCA9IGNhcmF0LCB5ID0gcHJpY2UpKSArIAogIGdlb21fcG9pbnQoKSArIAogIGZhY2V0X3dyYXAofmN1dCkgIyBub3RlIHRoZSAifiIgYmVmb3JlIHRoZSBncm91cGluZyB2YXJpYWJsZQpgYGAKCm9yIHlvdSBjYW4gZXZlbiBtYWtlIGEgKipncmlkKiogb2YgcGxvdHMgYnkgdHdvIGNhdGVnb3JpZXMgdXNpbmcgYGZhY2V0X2dyaWQoKWA6CgpgYGB7ciBmYWNldF9ncmlkfQpnZ3Bsb3QoZGF0YSA9IGRpYW1vbmRzLCBhZXMoeCA9IHByaWNlKSkgKyAKICBnZW9tX2hpc3RvZ3JhbSgpICsgCiAgZmFjZXRfZ3JpZChjb2xvcn5jdXQpCmBgYAoK