Intro and Overview
This document has a set of exercises for training your R programming
skills using the tidyverse packages to process and analyses example
datasets.
You will need:
- to have been introduced to R and tidyverse
- R and RStudio installed
- the tidyverse package installed
Datasets:
- Exercises will use built-in datasets
- built-in datasets are already loaded in R and ready to use
- you should read help pages of the datasets you analyze
- The titanic dataset is not built-in but it will be accessible by an
URL
Solution to exercises can be revealed by clicking on the
[Code] buttons displayed at the right-hand side of the
exercises.
Preparation
Load the tidyverse package.
Datasets
Built-in dataset:
trees
This data set provides measurements of the diameter, height and
volume of timber in 31 felled black cherry trees. Note that the diameter
(in inches) is erroneously labelled Girth in the data. It is measured at
4 ft 6 in above the ground.
- Show the head of table trees
- Create trees2 variable by copying
trees and
- Renaming column Girth to
Diameter
- Converting Diameter and Height to
centimeters (1 inch = 2,54 cm)
- Converting Volume in cubic meters (1 cibic foot = 0,0283168 cubic
meter)
trees2 <- trees %>%
rename(Diameter=Girth) %>%
mutate(Diameter=Diameter*2.54, Height=Height*2.54) %>%
mutate(Volume=Volume*0.0283168)
- Show the head of table trees2
- Calculate the mean value of each column
trees2 %>%
summarise(
mean.diameter=mean(Diameter),
mean.height=mean(Height),
mean.vol=mean(Volume)
)
- Save in variable trees2.plot a scatter plot of the
diameter vs height
- color points by Volume
- add a title to the plot using ggtitle()
trees2.plot <- trees2 %>%
ggplot(aes(x=Diameter, y=Height, color=Volume)) +
geom_point() +
ggtitle("Scatter Plot")
- save the plot in a PNG image file on your computer
- use ggsave(trees2.plot, filename = ‘your_file.png’,
…) with appropriate parameters for ggsave
- read the help of the function to create a 10x10cm plot named
“trees2.plot.png”
ggsave(trees2.plot, filename = "scatterplot.png", width = 10, height = 10, units = "cm")
Built-in dataset:
PlantGrowth
Results from an experiment to compare yields (as measured by dried
weight of plants) obtained under a control and two different treatment
conditions.
- Show a summary of the table using summary(TABLE)
(not a tidyverse’s function)
weight group
Min. :3.590 ctrl:10
1st Qu.:4.550 trt1:10
Median :5.155 trt2:10
Mean :5.073
3rd Qu.:5.530
Max. :6.310
- Show a density plot of the weight values divided by
group in a single plot
PlantGrowth %>%
ggplot(aes(x=weight, fill=group)) +
geom_density()
- Tuning the plots is sometimes as simple as using a special parameter
to a ggplot layer
- replot the same plot with the following setting in
geom_density() to set the transparency:
alpha=0.2
- alpha can take values from 0 to 1, test alpha=0.5
and alpha=0.8
PlantGrowth %>%
ggplot(aes(x=weight, fill=group)) +
geom_density(alpha=0.2)
PlantGrowth %>%
ggplot(aes(x=weight, fill=group)) +
geom_density(alpha=0.5)
PlantGrowth %>%
ggplot(aes(x=weight, fill=group)) +
geom_density(alpha=0.8)
Built-in dataset:
CO2
The CO2 data frame has 84 rows and 5 columns of data from an
experiment on the cold tolerance of the grass species Echinochloa
crus-galli.
- read the documentation of the CO2 dataset to
understand the columns
- show a summary of the table
Plant Type Treatment conc uptake
Qn1 : 7 Quebec :42 nonchilled:42 Min. : 95 Min. : 7.70
Qn2 : 7 Mississippi:42 chilled :42 1st Qu.: 175 1st Qu.:17.90
Qn3 : 7 Median : 350 Median :28.30
Qc1 : 7 Mean : 435 Mean :27.21
Qc3 : 7 3rd Qu.: 675 3rd Qu.:37.12
Qc2 : 7 Max. :1000 Max. :45.50
(Other):42
- Calculate the minimum and maximum uptake per geographical place of
origin
CO2 %>%
group_by(Type) %>%
summarise(
min=min(uptake),
max=max(uptake),
)
- Create a line graph showing uptake by concentration for each
plant
CO2 %>%
ggplot(aes(x=conc, y=uptake, color=Plant)) +
geom_line() +
geom_point()
Built-in dataset:
WorldPhones
The number of telephones in various regions of the world (in
thousands).
- show the matrix WorldPhones
N.Amer Europe Asia S.Amer Oceania Africa Mid.Amer
1951 45939 21574 2876 1815 1646 89 555
1956 60423 29990 4708 2568 2366 1411 733
1957 64721 32510 5230 2695 2526 1546 773
1958 68484 35218 6662 2845 2691 1663 836
1959 71799 37598 6856 3000 2868 1769 911
1960 76036 40341 8220 3145 3054 1905 1008
1961 79831 43173 9053 3338 3224 2005 1076
- Convert the matrix into a tibble named phones and
show the tibble
- adapt the following template: as_tibble(MATRIX,
rownames=“year”)
- Parameter rownames is needed because by default row
names are not kept by as_tibble()
phones <- as_tibble(WorldPhones, rownames="year")
phones
- Tidy up the tibble in order to make an observation a geographical
area in a year
phones <- phones %>%
gather(N.Amer:Mid.Amer, key="area", value="phones")
phones
- Create a plot to show the number of phones by year in each
geographical area
- use facets and colors for the areas
phones %>%
ggplot(aes(x=year, y=phones, color=area)) +
geom_point() +
facet_wrap(vars(area))
Built-in dataset:
mtcars
The data was extracted from the 1974 Motor Trend US magazine, and
comprises fuel consumption and 10 aspects of automobile design and
performance for 32 automobiles (1973–74 models).
- read the related help page to understand the columns
- show the head of the data frame
- To compare engine types (vs), calculate mean gross horsepower and
mean time per 1/4 mile
mtcars %>%
group_by(vs) %>%
summarise(mean.power=mean(hp), mean.time=mean(qsec))
- create a boxplot to compare the weight per engine type (1 plot with
2 boxes)
- Hint: the x axis of a boxplot should not be a numeric column
mtcars %>%
mutate(vs=as.character(vs)) %>%
ggplot(aes(x=vs, y=wt)) +
geom_boxplot()
- fastest car per category
- a category is defined by a particular combination of engine (vs) and
transmission (am)
- calculate the fastest car in each category
- the data frame’s rownames must be first transformed as a normal
column using rownames_to_column(“car”)
mtcars %>%
rownames_to_column("car") %>%
group_by(vs, am) %>%
filter(qsec==max(qsec))
- fastest car per category
- reproduce the result above using the slice_max
dplyr’s function
- adapt the following template: slice_max(COLUMN,
n=1)
mtcars %>%
rownames_to_column("car") %>%
group_by(vs, am) %>%
slice_max(qsec)
Titanic dataset
Prepare the
data
- Load the titanic dataset into variable
titanic.source from the following URL:
http://cbdm-01.zdv.uni-mainz.de/~stalbrec/RcourseData/titanic.tsv
titanic.source <- read_tsv("http://cbdm-01.zdv.uni-mainz.de/~stalbrec/RcourseData/titanic.tsv")
- observe the 20 first rows using head() function
(see help page to see how to define number of rows). Would it be
possible after some processing to derive a numerical age value for each
row?
titanic.source %>% head(n=20)
- create variable titanic with a copy of
titanic.source
- filter the table to keep rows that contains a possible value for
age
- tidy up the table in order to have a numerical column for
Age
- remove any temporary column created during this task, if
relevant
- show the head of the new table
titanic <- titanic.source %>%
filter(Age!="Not Available") %>%
separate(Age, into = c("Age", "rest"), sep=", ") %>%
mutate(Age=as.numeric(Age)) %>%
select(-rest)
titanic %>% head()
Survival
status
- Display a bar plot with numbers of survived and died passengers in
each class
- use titanic table
- use aes() with parameter x and
fill
- Tuning plots can get complicated: add the following ggplot layer
after geom_bar() to show numbers in bars:
stat_count(geom = "text", colour = "white", aes(label = ..count..), position=position_stack(vjust=0.5))
titanic %>%
ggplot(aes(x=Class, fill=SurvivalStatus)) +
geom_bar() +
stat_count(geom = "text", colour = "white", aes(label = ..count..), position=position_stack(vjust=0.5))
- In a new table titanic.stats, calculate numbers of
survived and died passengers in each class
- use titanic table
- hint: use summarise(n=n()) where function
n() counts number of rows
titanic.stats <- titanic %>%
group_by(Class, SurvivalStatus) %>%
summarise(n=n())
`summarise()` has grouped output by 'Class'. You can override using the `.groups` argument.
- tidy the titanic.stats table to make a class an
observation, resulting in a new table with 3 columns (Class, died,
survived)
titanic.stats <- titanic.stats %>%
spread(SurvivalStatus, n)
titanic.stats
- Using the titanic.stats table, calculate the
frequency for male or female passengers to die in each class
titanic.stats %>%
mutate(freq=died/(died+survived))
Distribution of
age
- Calculate the mean age in each class for male and female passengers
using summarise()
- use titanic table
- Note that the setting na.rm=TRUE for the
mean() function prevents the calculation to fail in
cases of missing values. As we filtered out missing values earlier it
should not be necessary. Also applies to sum, min and
max functions.
titanic %>%
group_by(Class, Sex) %>%
summarise(avg=mean(Age, na.rm=TRUE))
`summarise()` has grouped output by 'Class'. You can override using the `.groups` argument.
- plot the distribution of age in each class for male and female
passengers using boxplots
- use parameters x, y and
fill in aes()
titanic %>%
ggplot(aes(y=Age, x=Sex, fill=Class)) +
geom_boxplot()
- Create subplots of the previous plot by survival status
titanic %>%
ggplot(aes(y=Age, x=Sex, fill=Class)) +
geom_boxplot() +
facet_wrap(vars(SurvivalStatus))
LS0tDQp0aXRsZTogIkRhdGEgYW5hbHlzaXMgd2l0aCBSIGFuZCB0aGUgdGlkeXZlcnNlIg0Kb3V0cHV0OiANCiAgaHRtbF9ub3RlYm9vazoNCiAgICB0aGVtZTogcmVhZGFibGUNCiAgICBoaWdobGlnaHQ6IHRhbmdvDQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlDQogICAgdG9jOiB0cnVlDQogICAgdG9jX2RlcHRoOiAyDQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQotLS0NCg0KPCEtLSAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIC0tPg0KPCEtLSAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIC0tPg0KIyBJbnRybyBhbmQgT3ZlcnZpZXcNCjwhLS0gIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyAtLT4NCjwhLS0gIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyAtLT4NCg0KVGhpcyBkb2N1bWVudCBoYXMgYSBzZXQgb2YgZXhlcmNpc2VzIGZvciB0cmFpbmluZyB5b3VyIFIgcHJvZ3JhbW1pbmcgc2tpbGxzIA0KdXNpbmcgdGhlIHRpZHl2ZXJzZSBwYWNrYWdlcyB0byBwcm9jZXNzIGFuZCBhbmFseXNlcyBleGFtcGxlIGRhdGFzZXRzLg0KDQpZb3Ugd2lsbCBuZWVkOg0KDQoqIHRvIGhhdmUgYmVlbiBpbnRyb2R1Y2VkIHRvIFIgYW5kIHRpZHl2ZXJzZQ0KKiBSIGFuZCBSU3R1ZGlvIGluc3RhbGxlZA0KKiB0aGUgdGlkeXZlcnNlIHBhY2thZ2UgaW5zdGFsbGVkDQoNCkRhdGFzZXRzOg0KDQoqIEV4ZXJjaXNlcyB3aWxsIHVzZSBidWlsdC1pbiBkYXRhc2V0cw0KKiBidWlsdC1pbiBkYXRhc2V0cyBhcmUgYWxyZWFkeSBsb2FkZWQgaW4gUiBhbmQgcmVhZHkgdG8gdXNlDQoqIHlvdSBzaG91bGQgcmVhZCBoZWxwIHBhZ2VzIG9mIHRoZSBkYXRhc2V0cyB5b3UgYW5hbHl6ZSANCiogVGhlIHRpdGFuaWMgZGF0YXNldCBpcyBub3QgYnVpbHQtaW4gYnV0IGl0IHdpbGwgYmUgYWNjZXNzaWJsZSBieSBhbiBVUkwNCg0KU29sdXRpb24gdG8gZXhlcmNpc2VzIGNhbiBiZSByZXZlYWxlZCBieSBjbGlja2luZyBvbiB0aGUgKipbQ29kZV0qKiBidXR0b25zIGRpc3BsYXllZCANCmF0IHRoZSByaWdodC1oYW5kIHNpZGUgb2YgdGhlIGV4ZXJjaXNlcy4gDQoNCg0KPCEtLSAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIC0tPg0KIyBQcmVwYXJhdGlvbg0KPCEtLSAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIC0tPg0KDQpMb2FkIHRoZSB0aWR5dmVyc2UgcGFja2FnZS4NCg0KYGBge3IgY2xhc3Muc291cmNlID0gJ2ZvbGQtc2hvdyd9DQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmBgYA0KDQoNCmBgYHtyIGluY2x1ZGU9RkFMU0V9DQojIGRhdGEoKQ0Kcm9jaw0Kc3RhdGUueDc3DQphaXJxdWFsaXR5DQpPcmFuZ2UNCg0KDQojIHRyYWluLmRhdGEgPC0gcmVhZF90c3YoImh0dHBzOi8vd3d3LndvbGZyYW1jbG91ZC5jb20vb2JqZWN0cy84YmJlOTc1Yy00OGE5LTRkMzYtYTM1OC0xZGRlN2M1YzU3MmEiKQ0KIyB0cmFpbi5kYXRhICU+JSBtdXRhdGUoQWdlID0gc3RyX3JlcGxhY2UoQWdlLCAiUXVhbnRpdHlcXFsiLCAiIikpICU+JSANCiMgICBtdXRhdGUoQWdlID0gc3RyX3JlcGxhY2UoQWdlLCAiTWlzc2luZ1xcWyIsICIiKSkgJT4lICANCiMgICBtdXRhdGUoQWdlID0gc3RyX3JlcGxhY2UoQWdlLCAiXFxdIiwgIiIpKSAlPiUgDQojICAgbXV0YXRlKEFnZSA9IHN0cl9yZXBsYWNlX2FsbChBZ2UsICciJywgIiIpKSAlPiUgDQojICAgbXV0YXRlKEFnZSA9IHN0cl9yZXBsYWNlKEFnZSwgIlxcLiwiLCAiLjAsIikpICAlPiUgDQojICAgd3JpdGVfdHN2KCJ0aXRhbmljLnRzdiIpDQojIHRpdGFuaWMgJT4lIGhlYWQobj0yMCkNCmBgYA0KDQoNCjwhLS0gIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyAtLT4NCjwhLS0gIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyAtLT4NCiMgRGF0YXNldHMNCjwhLS0gIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyAtLT4NCjwhLS0gIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyAtLT4NCg0KPCEtLSAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIC0tPg0KIyMgQnVpbHQtaW4gZGF0YXNldDogdHJlZXMNCjwhLS0gIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyAtLT4NCg0KVGhpcyBkYXRhIHNldCBwcm92aWRlcyBtZWFzdXJlbWVudHMgb2YgdGhlIGRpYW1ldGVyLCBoZWlnaHQgYW5kIHZvbHVtZSBvZiB0aW1iZXIgaW4gMzEgZmVsbGVkIGJsYWNrIGNoZXJyeSB0cmVlcy4gTm90ZSB0aGF0IHRoZSBkaWFtZXRlciAoaW4gaW5jaGVzKSBpcyBlcnJvbmVvdXNseSBsYWJlbGxlZCBHaXJ0aCBpbiB0aGUgZGF0YS4gSXQgaXMgbWVhc3VyZWQgYXQgNCBmdCA2IGluIGFib3ZlIHRoZSBncm91bmQuDQoNCiogU2hvdyB0aGUgaGVhZCBvZiB0YWJsZSAqKnRyZWVzKiogDQpgYGB7cn0NCnRyZWVzICU+JSBoZWFkKCkNCmBgYA0KDQoqIENyZWF0ZSAqKnRyZWVzMioqIHZhcmlhYmxlIGJ5IGNvcHlpbmcgKip0cmVlcyoqIGFuZA0KICAgICogUmVuYW1pbmcgY29sdW1uICoqR2lydGgqKiB0byAqKkRpYW1ldGVyKioNCiAgICAqIENvbnZlcnRpbmcgKipEaWFtZXRlcioqIGFuZCAqKkhlaWdodCoqIHRvIGNlbnRpbWV0ZXJzICgxIGluY2ggPSAyLDU0IGNtKQ0KICAgICogQ29udmVydGluZyBWb2x1bWUgaW4gY3ViaWMgbWV0ZXJzICgxIGNpYmljIGZvb3QgPSAwLDAyODMxNjggY3ViaWMgbWV0ZXIpDQpgYGB7cn0NCnRyZWVzMiA8LSB0cmVlcyAlPiUgDQogIHJlbmFtZShEaWFtZXRlcj1HaXJ0aCkgJT4lIA0KICBtdXRhdGUoRGlhbWV0ZXI9RGlhbWV0ZXIqMi41NCwgSGVpZ2h0PUhlaWdodCoyLjU0KSAlPiUgDQogIG11dGF0ZShWb2x1bWU9Vm9sdW1lKjAuMDI4MzE2OCkNCmBgYA0KDQoqIFNob3cgdGhlIGhlYWQgb2YgdGFibGUgKip0cmVlczIqKiANCmBgYHtyfQ0KdHJlZXMyICU+JSBoZWFkKCkNCmBgYA0KDQoqIENhbGN1bGF0ZSB0aGUgbWVhbiB2YWx1ZSBvZiBlYWNoIGNvbHVtbiANCmBgYHtyfQ0KdHJlZXMyICU+JSANCiAgc3VtbWFyaXNlKA0KICAgIG1lYW4uZGlhbWV0ZXI9bWVhbihEaWFtZXRlciksDQogICAgbWVhbi5oZWlnaHQ9bWVhbihIZWlnaHQpLA0KICAgIG1lYW4udm9sPW1lYW4oVm9sdW1lKQ0KICAgICkNCmBgYA0KDQoqIFNhdmUgaW4gdmFyaWFibGUgKip0cmVlczIucGxvdCoqIGEgc2NhdHRlciBwbG90IG9mIHRoZSBkaWFtZXRlciB2cyBoZWlnaHQgDQogICAgKiBjb2xvciBwb2ludHMgYnkgKipWb2x1bWUqKg0KICAgICogYWRkIGEgdGl0bGUgdG8gdGhlIHBsb3QgdXNpbmcgKipnZ3RpdGxlKCkqKiAgIA0KYGBge3J9DQp0cmVlczIucGxvdCA8LSB0cmVlczIgJT4lIA0KICBnZ3Bsb3QoYWVzKHg9RGlhbWV0ZXIsIHk9SGVpZ2h0LCBjb2xvcj1Wb2x1bWUpKSArDQogIGdlb21fcG9pbnQoKSArIA0KICBnZ3RpdGxlKCJTY2F0dGVyIFBsb3QiKQ0KYGBgDQoNCg0KKiBzYXZlIHRoZSBwbG90IGluIGEgUE5HIGltYWdlIGZpbGUgb24geW91ciBjb21wdXRlcg0KICAgICogdXNlICoqZ2dzYXZlKHRyZWVzMi5wbG90LCBmaWxlbmFtZSA9ICd5b3VyX2ZpbGUucG5nJywgLi4uKSoqIHdpdGggYXBwcm9wcmlhdGUgcGFyYW1ldGVycyBmb3IgKipnZ3NhdmUqKg0KICAgICogcmVhZCB0aGUgaGVscCBvZiB0aGUgZnVuY3Rpb24gdG8gY3JlYXRlIGEgMTB4MTBjbSBwbG90IG5hbWVkICoqInRyZWVzMi5wbG90LnBuZyIqKg0KYGBge3J9DQpnZ3NhdmUodHJlZXMyLnBsb3QsIGZpbGVuYW1lID0gInNjYXR0ZXJwbG90LnBuZyIsIHdpZHRoID0gMTAsIGhlaWdodCA9IDEwLCB1bml0cyA9ICJjbSIpDQpgYGANCg0KPCEtLSAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIC0tPg0KIyMgQnVpbHQtaW4gZGF0YXNldDogUGxhbnRHcm93dGgNCjwhLS0gIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyAtLT4NCg0KUmVzdWx0cyBmcm9tIGFuIGV4cGVyaW1lbnQgdG8gY29tcGFyZSB5aWVsZHMgKGFzIG1lYXN1cmVkIGJ5IGRyaWVkIHdlaWdodCBvZiANCnBsYW50cykgb2J0YWluZWQgdW5kZXIgYSBjb250cm9sIGFuZCB0d28gZGlmZmVyZW50IHRyZWF0bWVudCBjb25kaXRpb25zLg0KDQoqIFNob3cgYSBzdW1tYXJ5IG9mIHRoZSB0YWJsZSB1c2luZyAqKnN1bW1hcnkoVEFCTEUpKiogKG5vdCBhIHRpZHl2ZXJzZSdzIGZ1bmN0aW9uKQ0KYGBge3J9DQpzdW1tYXJ5KFBsYW50R3Jvd3RoKQ0KYGBgDQoNCiogU2hvdyBhIGRlbnNpdHkgcGxvdCBvZiB0aGUgKip3ZWlnaHQqKiB2YWx1ZXMgZGl2aWRlZCBieSAqKmdyb3VwKiogaW4gYSBzaW5nbGUgcGxvdA0KYGBge3J9DQpQbGFudEdyb3d0aCAlPiUgDQogIGdncGxvdChhZXMoeD13ZWlnaHQsIGZpbGw9Z3JvdXApKSArDQogIGdlb21fZGVuc2l0eSgpDQpgYGANCiogVHVuaW5nIHRoZSBwbG90cyBpcyBzb21ldGltZXMgYXMgc2ltcGxlIGFzIHVzaW5nIGEgc3BlY2lhbCBwYXJhbWV0ZXIgdG8gYSBnZ3Bsb3QgbGF5ZXINCiAgICAqIHJlcGxvdCB0aGUgc2FtZSBwbG90IHdpdGggdGhlIGZvbGxvd2luZyBzZXR0aW5nIGluICoqZ2VvbV9kZW5zaXR5KCkqKiB0byBzZXQgdGhlIHRyYW5zcGFyZW5jeTogKiphbHBoYT0wLjIqKg0KICAgICogYWxwaGEgY2FuIHRha2UgdmFsdWVzIGZyb20gMCB0byAxLCB0ZXN0ICoqYWxwaGE9MC41KiogYW5kICoqYWxwaGE9MC44KioNCmBgYHtyfQ0KUGxhbnRHcm93dGggJT4lIA0KICBnZ3Bsb3QoYWVzKHg9d2VpZ2h0LCBmaWxsPWdyb3VwKSkgKw0KICBnZW9tX2RlbnNpdHkoYWxwaGE9MC4yKQ0KUGxhbnRHcm93dGggJT4lIA0KICBnZ3Bsb3QoYWVzKHg9d2VpZ2h0LCBmaWxsPWdyb3VwKSkgKw0KICBnZW9tX2RlbnNpdHkoYWxwaGE9MC41KQ0KUGxhbnRHcm93dGggJT4lIA0KICBnZ3Bsb3QoYWVzKHg9d2VpZ2h0LCBmaWxsPWdyb3VwKSkgKw0KICBnZW9tX2RlbnNpdHkoYWxwaGE9MC44KQ0KYGBgDQoNCjwhLS0gIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyAtLT4NCiMjIEJ1aWx0LWluIGRhdGFzZXQ6IENPMg0KPCEtLSAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIC0tPg0KDQpUaGUgQ08yIGRhdGEgZnJhbWUgaGFzIDg0IHJvd3MgYW5kIDUgY29sdW1ucyBvZiBkYXRhIGZyb20gYW4gZXhwZXJpbWVudCBvbiB0aGUgY29sZCB0b2xlcmFuY2Ugb2YgdGhlIGdyYXNzIHNwZWNpZXMgRWNoaW5vY2hsb2EgY3J1cy1nYWxsaS4NCg0KKiByZWFkIHRoZSBkb2N1bWVudGF0aW9uIG9mIHRoZSAqKkNPMioqIGRhdGFzZXQgdG8gdW5kZXJzdGFuZCB0aGUgY29sdW1ucw0KKiBzaG93IGEgc3VtbWFyeSBvZiB0aGUgdGFibGUNCmBgYHtyfQ0Kc3VtbWFyeShDTzIpDQpgYGANCg0KKiBDYWxjdWxhdGUgdGhlIG1pbmltdW0gYW5kIG1heGltdW0gdXB0YWtlIHBlciBnZW9ncmFwaGljYWwgcGxhY2Ugb2Ygb3JpZ2luDQpgYGB7cn0NCkNPMiAlPiUgDQogIGdyb3VwX2J5KFR5cGUpICU+JSANCiAgc3VtbWFyaXNlKA0KICAgIG1pbj1taW4odXB0YWtlKSwNCiAgICBtYXg9bWF4KHVwdGFrZSksDQogICkNCmBgYA0KDQoqIENyZWF0ZSBhIGxpbmUgZ3JhcGggc2hvd2luZyB1cHRha2UgYnkgY29uY2VudHJhdGlvbiBmb3IgZWFjaCBwbGFudA0KYGBge3J9DQpDTzIgJT4lIA0KICBnZ3Bsb3QoYWVzKHg9Y29uYywgeT11cHRha2UsIGNvbG9yPVBsYW50KSkgKw0KICBnZW9tX2xpbmUoKSArDQogIGdlb21fcG9pbnQoKQ0KYGBgDQoNCg0KPCEtLSAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIC0tPg0KIyMgQnVpbHQtaW4gZGF0YXNldDogV29ybGRQaG9uZXMNCjwhLS0gIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyAtLT4NCg0KVGhlIG51bWJlciBvZiB0ZWxlcGhvbmVzIGluIHZhcmlvdXMgcmVnaW9ucyBvZiB0aGUgd29ybGQgKGluIHRob3VzYW5kcykuDQoNCiogc2hvdyB0aGUgbWF0cml4ICoqV29ybGRQaG9uZXMqKg0KYGBge3J9DQpXb3JsZFBob25lcw0KYGBgDQoNCiogQ29udmVydCB0aGUgbWF0cml4IGludG8gYSB0aWJibGUgbmFtZWQgKipwaG9uZXMqKiBhbmQgc2hvdyB0aGUgdGliYmxlDQogICAgKiBhZGFwdCB0aGUgZm9sbG93aW5nIHRlbXBsYXRlOiAqKmFzX3RpYmJsZShNQVRSSVgsIHJvd25hbWVzPSJ5ZWFyIikqKg0KICAgICogUGFyYW1ldGVyICoqcm93bmFtZXMqKiBpcyBuZWVkZWQgYmVjYXVzZSBieSBkZWZhdWx0IHJvdyBuYW1lcyBhcmUgbm90IGtlcHQgYnkgKiphc190aWJibGUoKSoqDQoNCmBgYHtyfQ0KcGhvbmVzIDwtIGFzX3RpYmJsZShXb3JsZFBob25lcywgcm93bmFtZXM9InllYXIiKQ0KcGhvbmVzDQpgYGANCg0KKiBUaWR5IHVwIHRoZSB0aWJibGUgaW4gb3JkZXIgdG8gbWFrZSBhbiBvYnNlcnZhdGlvbiBhIGdlb2dyYXBoaWNhbCBhcmVhIGluIGEgeWVhciANCmBgYHtyfQ0KcGhvbmVzIDwtIHBob25lcyAlPiUgDQogIGdhdGhlcihOLkFtZXI6TWlkLkFtZXIsIGtleT0iYXJlYSIsIHZhbHVlPSJwaG9uZXMiKQ0KcGhvbmVzDQpgYGANCg0KKiBDcmVhdGUgYSBwbG90IHRvIHNob3cgdGhlIG51bWJlciBvZiBwaG9uZXMgYnkgeWVhciBpbiBlYWNoIGdlb2dyYXBoaWNhbCBhcmVhDQogICAgKiB1c2UgZmFjZXRzIGFuZCBjb2xvcnMgZm9yIHRoZSBhcmVhcyANCmBgYHtyIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD02fQ0KcGhvbmVzICU+JSANCiAgZ2dwbG90KGFlcyh4PXllYXIsIHk9cGhvbmVzLCBjb2xvcj1hcmVhKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBmYWNldF93cmFwKHZhcnMoYXJlYSkpDQpgYGANCg0KDQo8IS0tICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMgLS0+DQojIyBCdWlsdC1pbiBkYXRhc2V0OiBtdGNhcnMNCjwhLS0gIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyAtLT4NCg0KVGhlIGRhdGEgd2FzIGV4dHJhY3RlZCBmcm9tIHRoZSAxOTc0IE1vdG9yIFRyZW5kIFVTIG1hZ2F6aW5lLCBhbmQgY29tcHJpc2VzIGZ1ZWwgY29uc3VtcHRpb24gYW5kIDEwIGFzcGVjdHMgb2YgYXV0b21vYmlsZSBkZXNpZ24gYW5kIHBlcmZvcm1hbmNlIGZvciAzMiBhdXRvbW9iaWxlcyAoMTk3M+KAkzc0IG1vZGVscykuDQoNCiogcmVhZCB0aGUgcmVsYXRlZCBoZWxwIHBhZ2UgdG8gdW5kZXJzdGFuZCB0aGUgY29sdW1ucw0KKiBzaG93IHRoZSBoZWFkIG9mIHRoZSBkYXRhIGZyYW1lDQpgYGB7cn0NCm10Y2FycyAlPiUgaGVhZCgpDQpgYGANCg0KKiBUbyBjb21wYXJlIGVuZ2luZSB0eXBlcyAodnMpLCBjYWxjdWxhdGUgbWVhbiBncm9zcyBob3JzZXBvd2VyIGFuZCBtZWFuIHRpbWUgcGVyIDEvNCBtaWxlDQpgYGB7cn0NCm10Y2FycyAlPiUNCiAgZ3JvdXBfYnkodnMpICU+JSANCiAgc3VtbWFyaXNlKG1lYW4ucG93ZXI9bWVhbihocCksIG1lYW4udGltZT1tZWFuKHFzZWMpKQ0KYGBgDQoNCg0KKiBjcmVhdGUgYSBib3hwbG90IHRvIGNvbXBhcmUgdGhlIHdlaWdodCBwZXIgZW5naW5lIHR5cGUgKDEgcGxvdCB3aXRoIDIgYm94ZXMpDQogICAgKiBIaW50OiB0aGUgeCBheGlzIG9mIGEgYm94cGxvdCBzaG91bGQgbm90IGJlIGEgbnVtZXJpYyBjb2x1bW4NCg0KYGBge3J9DQptdGNhcnMgJT4lIA0KICBtdXRhdGUodnM9YXMuY2hhcmFjdGVyKHZzKSkgJT4lIA0KICBnZ3Bsb3QoYWVzKHg9dnMsIHk9d3QpKSArDQogIGdlb21fYm94cGxvdCgpDQpgYGANCiogZmFzdGVzdCBjYXIgcGVyIGNhdGVnb3J5DQogICAgKiBhIGNhdGVnb3J5IGlzIGRlZmluZWQgYnkgYSBwYXJ0aWN1bGFyIGNvbWJpbmF0aW9uIG9mIGVuZ2luZSAodnMpIGFuZCB0cmFuc21pc3Npb24gKGFtKQ0KICAgICogY2FsY3VsYXRlIHRoZSBmYXN0ZXN0IGNhciBpbiBlYWNoIGNhdGVnb3J5IA0KICAgICAgICAqIHRoZSBkYXRhIGZyYW1lJ3Mgcm93bmFtZXMgbXVzdCBiZSBmaXJzdCB0cmFuc2Zvcm1lZCBhcyBhIG5vcm1hbCBjb2x1bW4gdXNpbmcgKipyb3duYW1lc190b19jb2x1bW4oImNhciIpKioNCiAgICAgICAgDQpgYGB7cn0NCm10Y2FycyAlPiUgDQogIHJvd25hbWVzX3RvX2NvbHVtbigiY2FyIikgJT4lIA0KICBncm91cF9ieSh2cywgYW0pICU+JSANCiAgZmlsdGVyKHFzZWM9PW1heChxc2VjKSkNCmBgYA0KKiBmYXN0ZXN0IGNhciBwZXIgY2F0ZWdvcnkNCiAgICAqIHJlcHJvZHVjZSB0aGUgcmVzdWx0IGFib3ZlIHVzaW5nIHRoZSAqKnNsaWNlX21heCoqIGRwbHlyJ3MgZnVuY3Rpb24NCiAgICAgICAgKiBhZGFwdCB0aGUgZm9sbG93aW5nIHRlbXBsYXRlOiAqKnNsaWNlX21heChDT0xVTU4sIG49MSkqKg0KYGBge3J9DQptdGNhcnMgJT4lIA0KICByb3duYW1lc190b19jb2x1bW4oImNhciIpICU+JSANCiAgZ3JvdXBfYnkodnMsIGFtKSAlPiUgDQogIHNsaWNlX21heChxc2VjKQ0KYGBgDQoNCg0KDQo8IS0tICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMgLS0+DQojIyBUaXRhbmljIGRhdGFzZXQNCjwhLS0gIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyAtLT4NCg0KIyMjIFByZXBhcmUgdGhlIGRhdGENCg0KKiBMb2FkIHRoZSB0aXRhbmljIGRhdGFzZXQgaW50byB2YXJpYWJsZSAqKnRpdGFuaWMuc291cmNlKiogZnJvbSB0aGUgZm9sbG93aW5nIFVSTDogIGBodHRwOi8vY2JkbS0wMS56ZHYudW5pLW1haW56LmRlL35zdGFsYnJlYy9SY291cnNlRGF0YS90aXRhbmljLnRzdmANCmBgYHtyIG1lc3NhZ2U9RkFMU0V9DQp0aXRhbmljLnNvdXJjZSA8LSByZWFkX3RzdigiaHR0cDovL2NiZG0tMDEuemR2LnVuaS1tYWluei5kZS9+c3RhbGJyZWMvUmNvdXJzZURhdGEvdGl0YW5pYy50c3YiKSAgDQpgYGANCg0KKiBvYnNlcnZlIHRoZSAyMCBmaXJzdCByb3dzIHVzaW5nICoqaGVhZCgpKiogZnVuY3Rpb24gKHNlZSBoZWxwIHBhZ2UgdG8gc2VlIGhvdyANCnRvIGRlZmluZSBudW1iZXIgb2Ygcm93cykuIFdvdWxkIGl0IGJlIHBvc3NpYmxlIGFmdGVyIHNvbWUgcHJvY2Vzc2luZyB0byBkZXJpdmUgDQphIG51bWVyaWNhbCBhZ2UgdmFsdWUgZm9yIGVhY2ggcm93Pw0KYGBge3J9DQp0aXRhbmljLnNvdXJjZSAlPiUgaGVhZChuPTIwKQ0KYGBgDQoNCiogY3JlYXRlIHZhcmlhYmxlICoqdGl0YW5pYyoqIHdpdGggYSBjb3B5IG9mICoqdGl0YW5pYy5zb3VyY2UqKg0KICAgICogZmlsdGVyIHRoZSB0YWJsZSB0byBrZWVwIHJvd3MgdGhhdCBjb250YWlucyBhIHBvc3NpYmxlIHZhbHVlIGZvciBhZ2UNCiAgICAqIHRpZHkgdXAgdGhlIHRhYmxlIGluIG9yZGVyIHRvIGhhdmUgYSBudW1lcmljYWwgY29sdW1uIGZvciAqKkFnZSoqDQogICAgKiByZW1vdmUgYW55IHRlbXBvcmFyeSBjb2x1bW4gY3JlYXRlZCBkdXJpbmcgdGhpcyB0YXNrLCBpZiByZWxldmFudA0KKiBzaG93IHRoZSBoZWFkIG9mIHRoZSBuZXcgdGFibGUNCg0KYGBge3J9DQp0aXRhbmljIDwtIHRpdGFuaWMuc291cmNlICU+JSANCiAgZmlsdGVyKEFnZSE9Ik5vdCBBdmFpbGFibGUiKSAlPiUgDQogIHNlcGFyYXRlKEFnZSwgaW50byA9IGMoIkFnZSIsICJyZXN0IiksIHNlcD0iLCAiKSAlPiUgDQogIG11dGF0ZShBZ2U9YXMubnVtZXJpYyhBZ2UpKSAlPiUgDQogIHNlbGVjdCgtcmVzdCkgDQp0aXRhbmljICU+JSBoZWFkKCkNCmBgYA0KDQoNCiMjIyBTdXJ2aXZhbCBzdGF0dXMNCg0KKiBEaXNwbGF5IGEgYmFyIHBsb3Qgd2l0aCBudW1iZXJzIG9mIHN1cnZpdmVkIGFuZCBkaWVkIHBhc3NlbmdlcnMgaW4gZWFjaCBjbGFzcw0KICAgICogdXNlICoqdGl0YW5pYyoqIHRhYmxlDQogICAgKiB1c2UgKiphZXMoKSoqIHdpdGggcGFyYW1ldGVyICoqeCoqIGFuZCAqKmZpbGwqKg0KKiBUdW5pbmcgcGxvdHMgY2FuIGdldCBjb21wbGljYXRlZDogYWRkIHRoZSBmb2xsb3dpbmcgZ2dwbG90IGxheWVyIGFmdGVyICoqZ2VvbV9iYXIoKSoqIHRvIHNob3cgbnVtYmVycyBpbiBiYXJzOg0KICAgICogYHN0YXRfY291bnQoZ2VvbSA9ICJ0ZXh0IiwgY29sb3VyID0gIndoaXRlIiwgYWVzKGxhYmVsID0gLi5jb3VudC4uKSwgcG9zaXRpb249cG9zaXRpb25fc3RhY2sodmp1c3Q9MC41KSlgDQoNCmBgYHtyfQ0KdGl0YW5pYyAlPiUgDQogIGdncGxvdChhZXMoeD1DbGFzcywgZmlsbD1TdXJ2aXZhbFN0YXR1cykpICsNCiAgZ2VvbV9iYXIoKSArDQogIHN0YXRfY291bnQoZ2VvbSA9ICJ0ZXh0IiwgY29sb3VyID0gIndoaXRlIiwgYWVzKGxhYmVsID0gLi5jb3VudC4uKSwgcG9zaXRpb249cG9zaXRpb25fc3RhY2sodmp1c3Q9MC41KSkNCmBgYA0KDQoqIEluIGEgbmV3IHRhYmxlICoqdGl0YW5pYy5zdGF0cyoqLCBjYWxjdWxhdGUgbnVtYmVycyBvZiBzdXJ2aXZlZCBhbmQgZGllZCBwYXNzZW5nZXJzIGluIGVhY2ggY2xhc3MgDQogICAgKiB1c2UgKip0aXRhbmljKiogdGFibGUNCiAgICAqIGhpbnQ6IHVzZSAqKnN1bW1hcmlzZShuPW4oKSkqKiB3aGVyZSBmdW5jdGlvbiAqKm4oKSoqIGNvdW50cyBudW1iZXIgb2Ygcm93cw0KDQpgYGB7cn0NCnRpdGFuaWMuc3RhdHMgPC0gdGl0YW5pYyAlPiUNCiAgZ3JvdXBfYnkoQ2xhc3MsIFN1cnZpdmFsU3RhdHVzKSAlPiUgDQogIHN1bW1hcmlzZShuPW4oKSkNCnRpdGFuaWMuc3RhdHMNCmBgYA0KDQoqIHRpZHkgdGhlICoqdGl0YW5pYy5zdGF0cyoqIHRhYmxlIHRvIG1ha2UgYSBjbGFzcyBhbiBvYnNlcnZhdGlvbiwgcmVzdWx0aW5nIGluIGEgbmV3IHRhYmxlIHdpdGggMyBjb2x1bW5zIChDbGFzcywgZGllZCwgc3Vydml2ZWQpDQpgYGB7cn0NCnRpdGFuaWMuc3RhdHMgPC0gdGl0YW5pYy5zdGF0cyAlPiUgDQogIHNwcmVhZChTdXJ2aXZhbFN0YXR1cywgbikNCnRpdGFuaWMuc3RhdHMNCmBgYA0KDQoqIFVzaW5nIHRoZSAqKnRpdGFuaWMuc3RhdHMqKiB0YWJsZSwgY2FsY3VsYXRlIHRoZSBmcmVxdWVuY3kgZm9yIG1hbGUgb3IgZmVtYWxlIHBhc3NlbmdlcnMgdG8gZGllIGluIGVhY2ggY2xhc3MNCg0KYGBge3J9DQp0aXRhbmljLnN0YXRzICU+JSANCiAgbXV0YXRlKGZyZXE9ZGllZC8oZGllZCtzdXJ2aXZlZCkpDQpgYGANCg0KDQojIyMgRGlzdHJpYnV0aW9uIG9mIGFnZQ0KDQoqIENhbGN1bGF0ZSB0aGUgbWVhbiBhZ2UgaW4gZWFjaCBjbGFzcyBmb3IgbWFsZSBhbmQgZmVtYWxlIHBhc3NlbmdlcnMgdXNpbmcgKipzdW1tYXJpc2UoKSoqDQogICAgKiB1c2UgdGl0YW5pYyB0YWJsZQ0KICAgICogTm90ZSB0aGF0IHRoZSBzZXR0aW5nICoqbmEucm09VFJVRSoqIGZvciB0aGUgKiptZWFuKCkqKiBmdW5jdGlvbiBwcmV2ZW50cyB0aGUgY2FsY3VsYXRpb24gdG8gZmFpbCBpbiBjYXNlcyBvZiBtaXNzaW5nIHZhbHVlcy4gQXMgd2UgZmlsdGVyZWQgb3V0IG1pc3NpbmcgdmFsdWVzIGVhcmxpZXIgaXQgc2hvdWxkIG5vdCBiZSBuZWNlc3NhcnkuIEFsc28gYXBwbGllcyB0byAqKnN1bSwgbWluIGFuZCBtYXgqKiBmdW5jdGlvbnMuICANCmBgYHtyfQ0KdGl0YW5pYyAlPiUgDQogIGdyb3VwX2J5KENsYXNzLCBTZXgpICU+JSANCiAgc3VtbWFyaXNlKGF2Zz1tZWFuKEFnZSwgbmEucm09VFJVRSkpDQpgYGANCg0KKiBwbG90IHRoZSBkaXN0cmlidXRpb24gb2YgYWdlIGluIGVhY2ggY2xhc3MgZm9yIG1hbGUgYW5kIGZlbWFsZSBwYXNzZW5nZXJzIHVzaW5nIGJveHBsb3RzDQogICAgKiB1c2UgcGFyYW1ldGVycyAqKngqKiwgKip5KiogYW5kICoqZmlsbCoqIGluICoqYWVzKCkqKg0KYGBge3J9DQp0aXRhbmljICU+JSANCiAgZ2dwbG90KGFlcyh5PUFnZSwgeD1TZXgsIGZpbGw9Q2xhc3MpKSArDQogIGdlb21fYm94cGxvdCgpDQpgYGANCiogQ3JlYXRlIHN1YnBsb3RzIG9mIHRoZSBwcmV2aW91cyBwbG90IGJ5IHN1cnZpdmFsIHN0YXR1cw0KYGBge3J9DQp0aXRhbmljICU+JSANCiAgZ2dwbG90KGFlcyh5PUFnZSwgeD1TZXgsIGZpbGw9Q2xhc3MpKSArDQogIGdlb21fYm94cGxvdCgpICsNCiAgZmFjZXRfd3JhcCh2YXJzKFN1cnZpdmFsU3RhdHVzKSkNCmBgYA0K