When running R code in the Console the keyboard shortcut: CMD/Ctrl + Enter is very useful to run each R expression. When running R code in an Rnotebook the keyboard shortcut: Ctrl/Shift + Enter is useful to run each chunck of R code.
Here is the link to the RStudio Keyboard Shortcuts.
Continuing with the flights data.
library(tidyverse)
library(nycflights13)
flights
not_cancelled <- flights %>%
filter(!is.na(dep_delay), !is.na(arr_delay))
not_cancelled %>%
group_by(year, month, day) %>%
summarise(mean = mean(dep_delay))
Chapter 7 is about Exploratory Data Analysis (EDA).
EDA is an iterative cycle. You:
- Generate questions about your data.
- Search for answers by visualising, transforming, and modelling your data.
- Use what you learn to refine your questions and/or generate new questions.
A good quote that starts the Chapter:
“Far better an approximate answer to the right question, which is often vague, than an exact answer to the wrong question, which can always be made precise.” — John Tukey
Your goal during EDA is to develop an understanding of your data. EDA is fundamentally a creative process.
Exploring variation in the data using visualization.
Categorical variables.
In this Chapter the diamonds dataset is explored.
ggplot(data = diamonds) +
geom_bar(mapping = aes(x = cut))

diamonds %>%
count()
diamonds %>%
count(cut)
Continuous variables.
ggplot(data = diamonds) +
geom_histogram(mapping = aes(x = carat), binwidth = 0.5)

Count a continuous variable within intervals of equal length.
diamonds %>%
count(cut_width(carat, 0.5))
smaller <- diamonds %>%
filter(carat < 3)
ggplot(data = smaller, mapping = aes(x = carat)) +
geom_histogram(binwidth = 0.1)

ggplot(data = smaller, mapping = aes(x = carat, colour = cut)) +
geom_freqpoly(binwidth = 0.1)

Clusters in the data, round up!
ggplot(data = smaller, mapping = aes(x = carat)) +
geom_histogram(binwidth = 0.01)

Old Faithful data, another example of clusters.
ggplot(data = faithful, mapping = aes(x = eruptions)) +
geom_histogram(binwidth = 0.25)

Outliers:
ggplot(diamonds) +
geom_histogram(mapping = aes(x = y), binwidth = 0.5)

ggplot(diamonds) +
geom_histogram(mapping = aes(x = y), binwidth = 0.5) +
coord_cartesian(ylim = c(0, 50))

unusual <- diamonds %>%
filter(y < 3 | y > 20) %>%
select(price, x, y, z) %>%
arrange(y)
unusual
Replacing unusual values with missing values.
diamonds2 <- diamonds %>%
mutate(y = ifelse(y < 3 | y > 20, NA, y))
diamonds2
ggplot(data = diamonds2, mapping = aes(x = x, y = y)) +
geom_point()

Supress the warning.
ggplot(data = diamonds2, mapping = aes(x = x, y = y)) +
geom_point(na.rm = TRUE)

Categorical and Continuous variables.
ggplot(data = diamonds, mapping = aes(x = price)) +
geom_freqpoly(mapping = aes(colour = cut), binwidth = 500)

ggplot(diamonds) +
geom_bar(mapping = aes(x = cut))

Using a density plot.
ggplot(data = diamonds, mapping = aes(x = price, y = ..density..)) +
geom_freqpoly(mapping = aes(colour = cut), binwidth = 500)

ggplot(data = diamonds, mapping = aes(x = cut, y = price)) +
geom_boxplot()

ggplot(data = mpg, mapping = aes(x = class, y = hwy)) +
geom_boxplot()

ggplot(data = mpg) +
geom_boxplot(mapping = aes(x = reorder(class, hwy, FUN = median), y = hwy))

ggplot(data = mpg) +
geom_boxplot(mapping = aes(x = reorder(class, hwy, FUN = median), y = hwy)) +
coord_flip()

Two categorical variables. Covariation.
ggplot(data = diamonds) +
geom_count(mapping = aes(x = cut, y = color))

diamonds %>%
count(color, cut)
diamonds %>%
count(color, cut) %>%
ggplot(mapping = aes(x = color, y = cut)) +
geom_tile(mapping = aes(fill = n))

Two continuous variables.
ggplot(data = diamonds) +
geom_point(mapping = aes(x = carat, y = price))

ggplot(data = diamonds) +
geom_point(mapping = aes(x = carat, y = price), alpha = 1 / 100)

ggplot(data = smaller) +
geom_bin2d(mapping = aes(x = carat, y = price))

# install.packages("hexbin")
library(hexbin)
ggplot(data = smaller) +
geom_hex(mapping = aes(x = carat, y = price))

ggplot(data = smaller, mapping = aes(x = carat, y = price)) +
geom_boxplot(mapping = aes(group = cut_width(carat, 0.1)))

ggplot(data = smaller, mapping = aes(x = carat, y = price)) +
geom_boxplot(mapping = aes(group = cut_number(carat, 20)))

ggplot(data = diamonds) +
geom_point(mapping = aes(x = x, y = y)) +
coord_cartesian(xlim = c(4, 11), ylim = c(4, 11))

Back to Old Faithful. Seeing relationships between variables and using those relationships to build models.
ggplot(data = faithful) +
geom_point(mapping = aes(x = eruptions, y = waiting))

library(modelr)
mod <- lm(log(price) ~ log(carat), data = diamonds)
diamonds2 <- diamonds %>%
add_residuals(mod) %>%
mutate(resid = exp(resid))
ggplot(data = diamonds2) +
geom_point(mapping = aes(x = carat, y = resid))

ggplot(data = diamonds2) +
geom_boxplot(mapping = aes(x = cut, y = resid))

Same code, more consice.
ggplot(data = faithful, mapping = aes(x = eruptions)) +
geom_freqpoly(binwidth = 0.25)

ggplot(faithful, aes(eruptions)) +
geom_freqpoly(binwidth = 0.25)

Turn the end of a pipeline of data transformation into a plot. The value of the pipe.
diamonds %>%
count(cut, clarity) %>%
ggplot(aes(clarity, cut, fill = n)) +
geom_tile()

Chapter 8 is a short Chapter that introducts the getwd( ), setwd( ), and Projects. Try out Files to the right.
getwd()
[1] "/home/esuess/classes/2017-2018/Stat6864/Presentations/Chapter7"
ggplot(diamonds, aes(carat, price)) +
geom_hex()
ggsave("diamonds.pdf")
Saving 7.29 x 4.5 in image

write_csv(diamonds, "diamonds.csv")
Add a new chunk by clicking the Insert Chunk button on the toolbar or by pressing Ctrl+Alt+I.
When you save the notebook, an HTML file containing the code and output will be saved alongside it (click the Preview button or press Ctrl+Shift+K to preview the HTML file).
The preview shows you a rendered HTML copy of the contents of the editor. Consequently, unlike Knit, Preview does not run any R code chunks. Instead, the output of the chunk when it was last run in the editor is displayed.
LS0tCnRpdGxlOiAiQ29kZSBmcm9tIFIgZm9yIERhdGEgU2NpZW5jZSAtIENoYXB0ZXIgNiwgNyBhbmQgOCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKICBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQKLS0tCgpXaGVuIHJ1bm5pbmcgUiBjb2RlIGluIHRoZSBDb25zb2xlIHRoZSBrZXlib2FyZCBzaG9ydGN1dDogQ01EL0N0cmwgKyBFbnRlciBpcyB2ZXJ5IHVzZWZ1bCB0byBydW4gZWFjaCBSIGV4cHJlc3Npb24uICBXaGVuIHJ1bm5pbmcgUiBjb2RlIGluIGFuIFJub3RlYm9vayB0aGUga2V5Ym9hcmQgc2hvcnRjdXQ6IEN0cmwvU2hpZnQgKyBFbnRlciBpcyB1c2VmdWwgdG8gcnVuIGVhY2ggY2h1bmNrIG9mIFIgY29kZS4KCkhlcmUgaXMgdGhlIGxpbmsgdG8gdGhlIFtSU3R1ZGlvIEtleWJvYXJkIFNob3J0Y3V0c10oaHR0cHM6Ly9zdXBwb3J0LnJzdHVkaW8uY29tL2hjL2VuLXVzL2FydGljbGVzLzIwMDcxMTg1My1LZXlib2FyZC1TaG9ydGN1dHMpLgoKQ29udGludWluZyB3aXRoIHRoZSBmbGlnaHRzIGRhdGEuCiAKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KG55Y2ZsaWdodHMxMykKCmZsaWdodHMKCm5vdF9jYW5jZWxsZWQgPC0gZmxpZ2h0cyAlPiUgCiAgZmlsdGVyKCFpcy5uYShkZXBfZGVsYXkpLCAhaXMubmEoYXJyX2RlbGF5KSkKCm5vdF9jYW5jZWxsZWQgJT4lIAogIGdyb3VwX2J5KHllYXIsIG1vbnRoLCBkYXkpICU+JSAKICBzdW1tYXJpc2UobWVhbiA9IG1lYW4oZGVwX2RlbGF5KSkKYGBgCgoKKipDaGFwdGVyIDcqKiBpcyBhYm91dCBFeHBsb3JhdG9yeSBEYXRhIEFuYWx5c2lzIChFREEpLgoKRURBIGlzIGFuIGl0ZXJhdGl2ZSBjeWNsZS4gWW91OgoKMS4gR2VuZXJhdGUgcXVlc3Rpb25zIGFib3V0IHlvdXIgZGF0YS4KMi4gU2VhcmNoIGZvciBhbnN3ZXJzIGJ5IHZpc3VhbGlzaW5nLCB0cmFuc2Zvcm1pbmcsIGFuZCBtb2RlbGxpbmcgeW91ciBkYXRhLgozLiBVc2Ugd2hhdCB5b3UgbGVhcm4gdG8gcmVmaW5lIHlvdXIgcXVlc3Rpb25zIGFuZC9vciBnZW5lcmF0ZSBuZXcgcXVlc3Rpb25zLgoKQSBnb29kIHF1b3RlIHRoYXQgc3RhcnRzIHRoZSBDaGFwdGVyOgoK4oCcRmFyIGJldHRlciBhbiBhcHByb3hpbWF0ZSBhbnN3ZXIgdG8gdGhlIHJpZ2h0IHF1ZXN0aW9uLCB3aGljaCBpcyBvZnRlbiB2YWd1ZSwgdGhhbiBhbiBleGFjdCBhbnN3ZXIgdG8gdGhlIHdyb25nIHF1ZXN0aW9uLCB3aGljaCBjYW4gYWx3YXlzIGJlIG1hZGUgcHJlY2lzZS7igJ0g4oCUIEpvaG4gVHVrZXkKCllvdXIgZ29hbCBkdXJpbmcgRURBIGlzIHRvIGRldmVsb3AgYW4gdW5kZXJzdGFuZGluZyBvZiB5b3VyIGRhdGEuICBFREEgaXMgZnVuZGFtZW50YWxseSBhIGNyZWF0aXZlIHByb2Nlc3MuCgpFeHBsb3JpbmcgdmFyaWF0aW9uIGluIHRoZSBkYXRhIHVzaW5nIHZpc3VhbGl6YXRpb24uCgpDYXRlZ29yaWNhbCB2YXJpYWJsZXMuCgpJbiB0aGlzIENoYXB0ZXIgdGhlIGRpYW1vbmRzIGRhdGFzZXQgaXMgZXhwbG9yZWQuCgoKYGBge3J9CmdncGxvdChkYXRhID0gZGlhbW9uZHMpICsKICBnZW9tX2JhcihtYXBwaW5nID0gYWVzKHggPSBjdXQpKQpgYGAKCgpgYGB7cn0KZGlhbW9uZHMgJT4lIAogIGNvdW50KCkKCmRpYW1vbmRzICU+JSAKICBjb3VudChjdXQpCmBgYAoKCkNvbnRpbnVvdXMgdmFyaWFibGVzLgoKYGBge3J9CmdncGxvdChkYXRhID0gZGlhbW9uZHMpICsKICBnZW9tX2hpc3RvZ3JhbShtYXBwaW5nID0gYWVzKHggPSBjYXJhdCksIGJpbndpZHRoID0gMC41KQpgYGAKCkNvdW50IGEgY29udGludW91cyB2YXJpYWJsZSB3aXRoaW4gaW50ZXJ2YWxzIG9mIGVxdWFsIGxlbmd0aC4KCmBgYHtyfQpkaWFtb25kcyAlPiUgCiAgY291bnQoY3V0X3dpZHRoKGNhcmF0LCAwLjUpKQpgYGAKCmBgYHtyfQpzbWFsbGVyIDwtIGRpYW1vbmRzICU+JSAKICBmaWx0ZXIoY2FyYXQgPCAzKQogIApnZ3Bsb3QoZGF0YSA9IHNtYWxsZXIsIG1hcHBpbmcgPSBhZXMoeCA9IGNhcmF0KSkgKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMC4xKQpgYGAKCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IHNtYWxsZXIsIG1hcHBpbmcgPSBhZXMoeCA9IGNhcmF0LCBjb2xvdXIgPSBjdXQpKSArCiAgZ2VvbV9mcmVxcG9seShiaW53aWR0aCA9IDAuMSkKYGBgCgoKQ2x1c3RlcnMgaW4gdGhlIGRhdGEsIHJvdW5kIHVwIQoKYGBge3J9CmdncGxvdChkYXRhID0gc21hbGxlciwgbWFwcGluZyA9IGFlcyh4ID0gY2FyYXQpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAwLjAxKQpgYGAKCk9sZCBGYWl0aGZ1bCBkYXRhLCBhbm90aGVyIGV4YW1wbGUgb2YgY2x1c3RlcnMuCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBmYWl0aGZ1bCwgbWFwcGluZyA9IGFlcyh4ID0gZXJ1cHRpb25zKSkgKyAKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDAuMjUpCmBgYAoKT3V0bGllcnM6CgpgYGB7cn0KZ2dwbG90KGRpYW1vbmRzKSArIAogIGdlb21faGlzdG9ncmFtKG1hcHBpbmcgPSBhZXMoeCA9IHkpLCBiaW53aWR0aCA9IDAuNSkKYGBgCgpgYGB7cn0KZ2dwbG90KGRpYW1vbmRzKSArIAogIGdlb21faGlzdG9ncmFtKG1hcHBpbmcgPSBhZXMoeCA9IHkpLCBiaW53aWR0aCA9IDAuNSkgKwogIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygwLCA1MCkpCmBgYAoKCmBgYHtyfQp1bnVzdWFsIDwtIGRpYW1vbmRzICU+JSAKICBmaWx0ZXIoeSA8IDMgfCB5ID4gMjApICU+JSAKICBzZWxlY3QocHJpY2UsIHgsIHksIHopICU+JQogIGFycmFuZ2UoeSkKdW51c3VhbApgYGAKCgpSZXBsYWNpbmcgdW51c3VhbCB2YWx1ZXMgd2l0aCBtaXNzaW5nIHZhbHVlcy4KCmBgYHtyfQpkaWFtb25kczIgPC0gZGlhbW9uZHMgJT4lIAogIG11dGF0ZSh5ID0gaWZlbHNlKHkgPCAzIHwgeSA+IDIwLCBOQSwgeSkpCgpkaWFtb25kczIKYGBgCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBkaWFtb25kczIsIG1hcHBpbmcgPSBhZXMoeCA9IHgsIHkgPSB5KSkgKyAKICBnZW9tX3BvaW50KCkKYGBgCgpTdXByZXNzIHRoZSB3YXJuaW5nLgoKYGBge3J9CmdncGxvdChkYXRhID0gZGlhbW9uZHMyLCBtYXBwaW5nID0gYWVzKHggPSB4LCB5ID0geSkpICsgCiAgZ2VvbV9wb2ludChuYS5ybSA9IFRSVUUpCmBgYAoKCkNhdGVnb3JpY2FsIGFuZCBDb250aW51b3VzIHZhcmlhYmxlcy4KCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IGRpYW1vbmRzLCBtYXBwaW5nID0gYWVzKHggPSBwcmljZSkpICsgCiAgZ2VvbV9mcmVxcG9seShtYXBwaW5nID0gYWVzKGNvbG91ciA9IGN1dCksIGJpbndpZHRoID0gNTAwKQpgYGAKCmBgYHtyfQpnZ3Bsb3QoZGlhbW9uZHMpICsgCiAgZ2VvbV9iYXIobWFwcGluZyA9IGFlcyh4ID0gY3V0KSkKYGBgCgpVc2luZyBhIGRlbnNpdHkgcGxvdC4KCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IGRpYW1vbmRzLCBtYXBwaW5nID0gYWVzKHggPSBwcmljZSwgeSA9IC4uZGVuc2l0eS4uKSkgKyAKICBnZW9tX2ZyZXFwb2x5KG1hcHBpbmcgPSBhZXMoY29sb3VyID0gY3V0KSwgYmlud2lkdGggPSA1MDApCmBgYAoKCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IGRpYW1vbmRzLCBtYXBwaW5nID0gYWVzKHggPSBjdXQsIHkgPSBwcmljZSkpICsKICBnZW9tX2JveHBsb3QoKQpgYGAKCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBtcGcsIG1hcHBpbmcgPSBhZXMoeCA9IGNsYXNzLCB5ID0gaHd5KSkgKwogIGdlb21fYm94cGxvdCgpCmBgYAoKCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IG1wZykgKwogIGdlb21fYm94cGxvdChtYXBwaW5nID0gYWVzKHggPSByZW9yZGVyKGNsYXNzLCBod3ksIEZVTiA9IG1lZGlhbiksIHkgPSBod3kpKQpgYGAKCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IG1wZykgKwogIGdlb21fYm94cGxvdChtYXBwaW5nID0gYWVzKHggPSByZW9yZGVyKGNsYXNzLCBod3ksIEZVTiA9IG1lZGlhbiksIHkgPSBod3kpKSArCiAgY29vcmRfZmxpcCgpCmBgYAoKClR3byBjYXRlZ29yaWNhbCB2YXJpYWJsZXMuICBDb3ZhcmlhdGlvbi4KCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IGRpYW1vbmRzKSArCiAgZ2VvbV9jb3VudChtYXBwaW5nID0gYWVzKHggPSBjdXQsIHkgPSBjb2xvcikpCmBgYAoKYGBge3J9CmRpYW1vbmRzICU+JSAKICBjb3VudChjb2xvciwgY3V0KQpgYGAKCmBgYHtyfQpkaWFtb25kcyAlPiUgCiAgY291bnQoY29sb3IsIGN1dCkgJT4lICAKICBnZ3Bsb3QobWFwcGluZyA9IGFlcyh4ID0gY29sb3IsIHkgPSBjdXQpKSArCiAgICBnZW9tX3RpbGUobWFwcGluZyA9IGFlcyhmaWxsID0gbikpCmBgYAoKClR3byBjb250aW51b3VzIHZhcmlhYmxlcy4KCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IGRpYW1vbmRzKSArCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBjYXJhdCwgeSA9IHByaWNlKSkKYGBgCgoKYGBge3J9CmdncGxvdChkYXRhID0gZGlhbW9uZHMpICsgCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBjYXJhdCwgeSA9IHByaWNlKSwgYWxwaGEgPSAxIC8gMTAwKQpgYGAKCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBzbWFsbGVyKSArCiAgZ2VvbV9iaW4yZChtYXBwaW5nID0gYWVzKHggPSBjYXJhdCwgeSA9IHByaWNlKSkKCiMgaW5zdGFsbC5wYWNrYWdlcygiaGV4YmluIikKCmxpYnJhcnkoaGV4YmluKQoKZ2dwbG90KGRhdGEgPSBzbWFsbGVyKSArCiAgZ2VvbV9oZXgobWFwcGluZyA9IGFlcyh4ID0gY2FyYXQsIHkgPSBwcmljZSkpCmBgYAoKYGBge3J9CmdncGxvdChkYXRhID0gc21hbGxlciwgbWFwcGluZyA9IGFlcyh4ID0gY2FyYXQsIHkgPSBwcmljZSkpICsgCiAgZ2VvbV9ib3hwbG90KG1hcHBpbmcgPSBhZXMoZ3JvdXAgPSBjdXRfd2lkdGgoY2FyYXQsIDAuMSkpKQpgYGAKCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IHNtYWxsZXIsIG1hcHBpbmcgPSBhZXMoeCA9IGNhcmF0LCB5ID0gcHJpY2UpKSArIAogIGdlb21fYm94cGxvdChtYXBwaW5nID0gYWVzKGdyb3VwID0gY3V0X251bWJlcihjYXJhdCwgMjApKSkKYGBgCgoKYGBge3J9CmdncGxvdChkYXRhID0gZGlhbW9uZHMpICsKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IHgsIHkgPSB5KSkgKwogIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYyg0LCAxMSksIHlsaW0gPSBjKDQsIDExKSkKYGBgCgoKQmFjayB0byBPbGQgRmFpdGhmdWwuICBTZWVpbmcgcmVsYXRpb25zaGlwcyBiZXR3ZWVuIHZhcmlhYmxlcyBhbmQgdXNpbmcgdGhvc2UgcmVsYXRpb25zaGlwcyB0byBidWlsZCBtb2RlbHMuCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBmYWl0aGZ1bCkgKyAKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGVydXB0aW9ucywgeSA9IHdhaXRpbmcpKQpgYGAKCmBgYHtyfQpsaWJyYXJ5KG1vZGVscikKCm1vZCA8LSBsbShsb2cocHJpY2UpIH4gbG9nKGNhcmF0KSwgZGF0YSA9IGRpYW1vbmRzKQoKZGlhbW9uZHMyIDwtIGRpYW1vbmRzICU+JSAKICBhZGRfcmVzaWR1YWxzKG1vZCkgJT4lIAogIG11dGF0ZShyZXNpZCA9IGV4cChyZXNpZCkpCgpnZ3Bsb3QoZGF0YSA9IGRpYW1vbmRzMikgKyAKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGNhcmF0LCB5ID0gcmVzaWQpKQpgYGAKCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IGRpYW1vbmRzMikgKyAKICBnZW9tX2JveHBsb3QobWFwcGluZyA9IGFlcyh4ID0gY3V0LCB5ID0gcmVzaWQpKQpgYGAKClNhbWUgY29kZSwgbW9yZSBjb25zaWNlLgoKYGBge3J9CmdncGxvdChkYXRhID0gZmFpdGhmdWwsIG1hcHBpbmcgPSBhZXMoeCA9IGVydXB0aW9ucykpICsgCiAgZ2VvbV9mcmVxcG9seShiaW53aWR0aCA9IDAuMjUpCgpnZ3Bsb3QoZmFpdGhmdWwsIGFlcyhlcnVwdGlvbnMpKSArIAogIGdlb21fZnJlcXBvbHkoYmlud2lkdGggPSAwLjI1KQpgYGAKClR1cm4gdGhlIGVuZCBvZiBhIHBpcGVsaW5lIG9mIGRhdGEgdHJhbnNmb3JtYXRpb24gaW50byBhIHBsb3QuICBUaGUgdmFsdWUgb2YgdGhlIHBpcGUuCgpgYGB7cn0KZGlhbW9uZHMgJT4lIAogIGNvdW50KGN1dCwgY2xhcml0eSkgJT4lIAogIGdncGxvdChhZXMoY2xhcml0eSwgY3V0LCBmaWxsID0gbikpICsgCiAgICBnZW9tX3RpbGUoKQpgYGAKCioqQ2hhcHRlciA4KiogaXMgYSBzaG9ydCBDaGFwdGVyIHRoYXQgaW50cm9kdWN0cyB0aGUgKmdldHdkKCApKiwgKnNldHdkKCApKiwgYW5kIFByb2plY3RzLiAgVHJ5IG91dCBGaWxlcyB0byB0aGUgcmlnaHQuCgpgYGB7cn0KZ2V0d2QoKQpgYGAKCmBgYHtyfQpnZ3Bsb3QoZGlhbW9uZHMsIGFlcyhjYXJhdCwgcHJpY2UpKSArIAogIGdlb21faGV4KCkKZ2dzYXZlKCJkaWFtb25kcy5wZGYiKQoKd3JpdGVfY3N2KGRpYW1vbmRzLCAiZGlhbW9uZHMuY3N2IikKYGBgCgoKQWRkIGEgbmV3IGNodW5rIGJ5IGNsaWNraW5nIHRoZSAqSW5zZXJ0IENodW5rKiBidXR0b24gb24gdGhlIHRvb2xiYXIgb3IgYnkgcHJlc3NpbmcgKkN0cmwrQWx0K0kqLgoKV2hlbiB5b3Ugc2F2ZSB0aGUgbm90ZWJvb2ssIGFuIEhUTUwgZmlsZSBjb250YWluaW5nIHRoZSBjb2RlIGFuZCBvdXRwdXQgd2lsbCBiZSBzYXZlZCBhbG9uZ3NpZGUgaXQgKGNsaWNrIHRoZSAqUHJldmlldyogYnV0dG9uIG9yIHByZXNzICpDdHJsK1NoaWZ0K0sqIHRvIHByZXZpZXcgdGhlIEhUTUwgZmlsZSkuCgpUaGUgcHJldmlldyBzaG93cyB5b3UgYSByZW5kZXJlZCBIVE1MIGNvcHkgb2YgdGhlIGNvbnRlbnRzIG9mIHRoZSBlZGl0b3IuIENvbnNlcXVlbnRseSwgdW5saWtlICpLbml0KiwgKlByZXZpZXcqIGRvZXMgbm90IHJ1biBhbnkgUiBjb2RlIGNodW5rcy4gSW5zdGVhZCwgdGhlIG91dHB1dCBvZiB0aGUgY2h1bmsgd2hlbiBpdCB3YXMgbGFzdCBydW4gaW4gdGhlIGVkaXRvciBpcyBkaXNwbGF5ZWQuCg==