Data Focus
Modules and Zoom Notes 2–6 cover topics that are part of the data
analysis journey and are all interrelated. Each module will introduce
new content and expand on the material covered in previous modules. For
example, in Module 2 we introduce the basics of the R plotting systems.
Subsequent sessions include more advanced plotting options and
techniques.
Associated material:
Module: Module 02 - Visualising
Data
Readings:
Topics
Tabular data
- Edit in Excel
- Export to plain csv (not UTF-8)
- Column headers in first row for every column
- One row for each data record
Folder setup
- Eventually, use Projects to allow RStudio to manage metadata
- Separate folders for data files, images, scripts, Rmd, etc.
Importing a data file
- read.csv
- Set stringsAsFactors = TRUE to import categorical variables
correctly
- After we meet the tidyverse, can also use read_csv
Checking your imported data
- head
- tail
- str
- Confirm that each column is of the correct type
Selecting and using columns of data
- Select an individual column with the $ operator
Base R plots
- hist for frequency distributions
- boxplots show central tendency and variability
- formulas have the form dependent variable
~ linear model of independent variables
Plotting with ggplot
- Use function
ggplot
contained in library (and package)
ggplot2
- Complex syntax based on Grammar of Graphics (from computer
science)
- Plots built in layers
Building a graph
- All plots begin with call to ggplot, passing in a data frame
- Mappings define relationships between elements of the data and
visual features on the plot
- Use function
aes
to define a mapping
- Assign column names to
aes
arguments x
and
y
to define graph axes
- Many available arguments to
aes
; part of the ggplot
syntax
- Select a geometry to determine the kind of plot
(e.g. bar graph, scatterplot, line graph, etc.)
- Additional layers define axes labels, title, legends, and fonts
- Combine ggplot layer sub-commands with
+
Practice Exercises
To practice what we have learned in Module 02, we will use “Palmer’s
Penguins”, a real data set from the Palmer Station Long Term Ecological
Research program (https://allisonhorst.github.io/palmerpenguins/articles/intro.html).
These data are size measurements for three penguin species – Chinstrap,
Gentoo and Adelie – on three islands in Antarctica.
Install the package that contains the data (code shown below). Then
work through each of the exercises. If you have any questions, email us
or send us a message in MS Teams.
Access the data as shown below. These commands initialise an object
called penguins, which is a tibble, an
enhanced data frame. The additional features of tibbles will be
discussed during the next module. For these exercises simply treat
object penguins as a normal data frame.
# Install the package (do once on any computer)
install.packages("palmerpenguins")
# Load the library (do at the start of every RStudio session)
library(palmerpenguins)
# Check the data - the data frame name is penguins
str(penguins)
#> tibble [344 × 8] (S3: tbl_df/tbl/data.frame)
#> $ species : Factor w/ 3 levels "Adelie","Chinstrap",..: 1 1 1 1 1 1 1 1 1 1 ...
#> $ island : Factor w/ 3 levels "Biscoe","Dream",..: 3 3 3 3 3 3 3 3 3 3 ...
#> $ bill_length_mm : num [1:344] 39.1 39.5 40.3 NA 36.7 39.3 38.9 39.2 34.1 42 ...
#> $ bill_depth_mm : num [1:344] 18.7 17.4 18 NA 19.3 20.6 17.8 19.6 18.1 20.2 ...
#> $ flipper_length_mm: int [1:344] 181 186 195 NA 193 190 181 195 193 190 ...
#> $ body_mass_g : int [1:344] 3750 3800 3250 NA 3450 3650 3625 4675 3475 4250 ...
#> $ sex : Factor w/ 2 levels "female","male": 2 1 1 NA 1 2 1 2 NA NA ...
#> $ year : int [1:344] 2007 2007 2007 2007 2007 2007 2007 2007 2007 2007 ...
The output from str(penguins
) indicates that three of
the columns in the data frame are Factors. In R, a
factor is a categorical variable, usually corresponding to an
experimental factor. Although factors look like strings, a factor is
restricted to a specific set of legal values, which R infers when the
data are loaded. The legal values are called levels,
and correspond to the different groups or conditions represented by the
factor. For example, column penguins$sex
is a factor with
levels “female” and “male”.
When our data sets have factors, we often use functions
levels
and table
. Use Google or your favourite
text book to explore these functions. Use them to solve the next two
exercises.
What are the three different levels of the
species factor? What are the three different levels of
the island factor?
How many observations are there in the data frame for each of the
three species? How many observations are there in the data frame for
each of the three islands?
Using base R, generate a histogram showing the distribution of
body mass, collapsed across island, species and sex. How would you
describe the distribution?
Using ggplot, generate a scatterplot illustrating the
relationship between bill length and body mass, collapsed across
species, island and sex. Remember to load the library with
library(ggplot2)
before first use. How would you describe
the pattern?
Modify your plot from Exercise 4 so that penguins from the
different islands are drawn in different colours. Which island seems to
have the heaviest penguins? Without looking any further at the data,
formulate at least two possible explanations for the pattern.
Using ggplot, generate a boxplot comparing body mass for the
three different species of penguin, and having each of the three boxes
drawn in a different colour. What information is missing from this
figure that was provided in Exercise 5? What information is easier to
see in this figure than in Exercise 5?
Using ggplot, duplicate this figure. You will need to research
geometry function geom_bar
.
LS0tCnRpdGxlOiAiWm9vbSBOb3RlcyAwMjogVmlzdWFsaXNpbmcgRGF0YSIKZGF0ZTogIlNlbWVzdGVyIDIsIDIwMjIiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIHRvY19kZXB0aDogMwogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBzaG93Ci0tLQogIApgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KbGlicmFyeShnZ3Bsb3QyKQoKbGlicmFyeShrbml0cikKCmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICBjb21tZW50ID0gIiM+IiwKICBmaWcucGF0aCA9ICJmaWd1cmVzLzAyLyIsICMgdXNlIG9ubHkgZm9yIHNpbmdsZSBSbWQgZmlsZXMKICBjb2xsYXBzZSA9IFRSVUUsCiAgZWNobyA9IFRSVUUKKQpgYGAKCj4gIyMjIyBEYXRhIEZvY3VzCiAgPgogID4gTW9kdWxlcyBhbmQgWm9vbSBOb3RlcyAyLS02IGNvdmVyIHRvcGljcyB0aGF0IGFyZSBwYXJ0IG9mIHRoZSBkYXRhIGFuYWx5c2lzIGpvdXJuZXkgYW5kIGFyZSBhbGwgaW50ZXJyZWxhdGVkLiBFYWNoIG1vZHVsZSB3aWxsIGludHJvZHVjZSBuZXcgY29udGVudCBhbmQgZXhwYW5kIG9uIHRoZSBtYXRlcmlhbCBjb3ZlcmVkIGluIHByZXZpb3VzIG1vZHVsZXMuIEZvciBleGFtcGxlLCBpbiBNb2R1bGUgMiB3ZSBpbnRyb2R1Y2UgdGhlIGJhc2ljcyBvZiB0aGUgUiBwbG90dGluZyBzeXN0ZW1zLiBTdWJzZXF1ZW50IHNlc3Npb25zIGluY2x1ZGUgbW9yZSBhZHZhbmNlZCBwbG90dGluZyBvcHRpb25zIGFuZCB0ZWNobmlxdWVzLgoKXAoKXAoKPiAjIyMjIEFzc29jaWF0ZWQgbWF0ZXJpYWw6Cj4KPiBNb2R1bGU6IFtNb2R1bGUgMDIgLSBWaXN1YWxpc2luZyBEYXRhXSgwMi12aXN1YWxpc2UuaHRtbCkKPiAKPiBSZWFkaW5nczoKPiAgIAo+IC0gW1IgZm9yIERhdGEgU2NpZW5jZSAtIENoYXB0ZXIgMTJdKGh0dHBzOi8vcjRkcy5oYWQuY28ubnovdGlkeS1kYXRhLmh0bWwpCj4gLSBbUiBmb3IgRGF0YSBTY2llbmNlIC0gQ2hhcHRlciAxMV0oaHR0cHM6Ly9yNGRzLmhhZC5jby5uei9kYXRhLWltcG9ydC5odG1sKQo+IC0gW1IgZm9yIERhdGEgU2NpZW5jZSAtIENoYXB0ZXIgM10oaHR0cHM6Ly9yNGRzLmhhZC5jby5uei9kYXRhLXZpc3VhbGlzYXRpb24uaHRtbCkKCgojIFRvcGljcwoKIyMgVGFidWxhciBkYXRhCgotIEVkaXQgaW4gRXhjZWwKLSBFeHBvcnQgdG8gcGxhaW4gY3N2IChub3QgVVRGLTgpCi0gQ29sdW1uIGhlYWRlcnMgaW4gZmlyc3Qgcm93IGZvciBldmVyeSBjb2x1bW4KLSBPbmUgcm93IGZvciBlYWNoIGRhdGEgcmVjb3JkCgojIyBGb2xkZXIgc2V0dXAKCi0gRXZlbnR1YWxseSwgdXNlIFByb2plY3RzIHRvIGFsbG93IFJTdHVkaW8gdG8gbWFuYWdlIG1ldGFkYXRhCi0gU2VwYXJhdGUgZm9sZGVycyBmb3IgZGF0YSBmaWxlcywgaW1hZ2VzLCBzY3JpcHRzLCBSbWQsIGV0Yy4KCiMjIEltcG9ydGluZyBhIGRhdGEgZmlsZQoKLSByZWFkLmNzdgotIFNldCBzdHJpbmdzQXNGYWN0b3JzID0gVFJVRSB0byBpbXBvcnQgY2F0ZWdvcmljYWwgdmFyaWFibGVzIGNvcnJlY3RseQotIEFmdGVyIHdlIG1lZXQgdGhlIHRpZHl2ZXJzZSwgY2FuIGFsc28gdXNlIHJlYWRfY3N2CgojIyBDaGVja2luZyB5b3VyIGltcG9ydGVkIGRhdGEKCi0gaGVhZAotIHRhaWwKLSBzdHIKLSBDb25maXJtIHRoYXQgZWFjaCBjb2x1bW4gaXMgb2YgdGhlIGNvcnJlY3QgdHlwZQoKIyMgU2VsZWN0aW5nIGFuZCB1c2luZyBjb2x1bW5zIG9mIGRhdGEKCi0gU2VsZWN0IGFuIGluZGl2aWR1YWwgY29sdW1uIHdpdGggdGhlICQgb3BlcmF0b3IKCiMjIEJhc2UgUiBwbG90cwoKLSBoaXN0IGZvciBmcmVxdWVuY3kgZGlzdHJpYnV0aW9ucwotIGJveHBsb3RzIHNob3cgY2VudHJhbCB0ZW5kZW5jeSBhbmQgdmFyaWFiaWxpdHkKLSBmb3JtdWxhcyBoYXZlIHRoZSBmb3JtICpkZXBlbmRlbnQgdmFyaWFibGUqICoqfioqICpsaW5lYXIgbW9kZWwgb2YgaW5kZXBlbmRlbnQgdmFyaWFibGVzKgoKIyMgUGxvdHRpbmcgd2l0aCBnZ3Bsb3QKCi0gVXNlIGZ1bmN0aW9uIGBnZ3Bsb3RgIGNvbnRhaW5lZCBpbiBsaWJyYXJ5IChhbmQgcGFja2FnZSkgZ2dwbG90MgotIENvbXBsZXggc3ludGF4IGJhc2VkIG9uIEdyYW1tYXIgb2YgR3JhcGhpY3MgKGZyb20gY29tcHV0ZXIgc2NpZW5jZSkKLSBQbG90cyBidWlsdCBpbiBsYXllcnMKCiMjIEJ1aWxkaW5nIGEgZ3JhcGgKCi0gQWxsIHBsb3RzIGJlZ2luIHdpdGggY2FsbCB0byBnZ3Bsb3QsIHBhc3NpbmcgaW4gYSBkYXRhIGZyYW1lCi0gTWFwcGluZ3MgZGVmaW5lIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiBlbGVtZW50cyBvZiB0aGUgZGF0YSBhbmQgdmlzdWFsIGZlYXR1cmVzIG9uIHRoZSBwbG90Ci0gVXNlIGZ1bmN0aW9uIGBhZXNgIHRvIGRlZmluZSBhIG1hcHBpbmcKLSBBc3NpZ24gY29sdW1uIG5hbWVzIHRvIGBhZXNgIGFyZ3VtZW50cyBgeGAgYW5kIGB5YCB0byBkZWZpbmUgZ3JhcGggYXhlcwotIE1hbnkgYXZhaWxhYmxlIGFyZ3VtZW50cyB0byBgYWVzYDsgcGFydCBvZiB0aGUgZ2dwbG90IHN5bnRheAotIFNlbGVjdCBhICoqZ2VvbWV0cnkqKiB0byBkZXRlcm1pbmUgdGhlIGtpbmQgb2YgcGxvdCAoZS5nLiBiYXIgZ3JhcGgsIHNjYXR0ZXJwbG90LCBsaW5lIGdyYXBoLCBldGMuKQotIEFkZGl0aW9uYWwgbGF5ZXJzIGRlZmluZSBheGVzIGxhYmVscywgdGl0bGUsIGxlZ2VuZHMsIGFuZCBmb250cwotIENvbWJpbmUgZ2dwbG90IGxheWVyIHN1Yi1jb21tYW5kcyB3aXRoIGArYAoKIyBQcmFjdGljZSBFeGVyY2lzZXMKClRvIHByYWN0aWNlIHdoYXQgd2UgaGF2ZSBsZWFybmVkIGluIE1vZHVsZSAwMiwgd2Ugd2lsbCB1c2UgIlBhbG1lcidzIFBlbmd1aW5zIiwgYSByZWFsIGRhdGEgc2V0IGZyb20gdGhlIFBhbG1lciBTdGF0aW9uIExvbmcgVGVybSBFY29sb2dpY2FsIFJlc2VhcmNoIHByb2dyYW0gKGh0dHBzOi8vYWxsaXNvbmhvcnN0LmdpdGh1Yi5pby9wYWxtZXJwZW5ndWlucy9hcnRpY2xlcy9pbnRyby5odG1sKS4gVGhlc2UgZGF0YSBhcmUgc2l6ZSBtZWFzdXJlbWVudHMgZm9yIHRocmVlIHBlbmd1aW4gc3BlY2llcyAtLSBDaGluc3RyYXAsIEdlbnRvbyBhbmQgQWRlbGllIC0tIG9uIHRocmVlIGlzbGFuZHMgaW4gQW50YXJjdGljYS4KCkluc3RhbGwgdGhlIHBhY2thZ2UgdGhhdCBjb250YWlucyB0aGUgZGF0YSAoY29kZSBzaG93biBiZWxvdykuIFRoZW4gd29yayB0aHJvdWdoIGVhY2ggb2YgdGhlIGV4ZXJjaXNlcy4gSWYgeW91IGhhdmUgYW55IHF1ZXN0aW9ucywgZW1haWwgdXMgb3Igc2VuZCB1cyBhIG1lc3NhZ2UgaW4gTVMgVGVhbXMuCgpBY2Nlc3MgdGhlIGRhdGEgYXMgc2hvd24gYmVsb3cuIFRoZXNlIGNvbW1hbmRzIGluaXRpYWxpc2UgYW4gb2JqZWN0IGNhbGxlZCAqKnBlbmd1aW5zKiosIHdoaWNoIGlzIGEgKip0aWJibGUqKiwgYW4gZW5oYW5jZWQgZGF0YSBmcmFtZS4gVGhlIGFkZGl0aW9uYWwgZmVhdHVyZXMgb2YgdGliYmxlcyB3aWxsIGJlIGRpc2N1c3NlZCBkdXJpbmcgdGhlIG5leHQgbW9kdWxlLiBGb3IgdGhlc2UgZXhlcmNpc2VzIHNpbXBseSB0cmVhdCBvYmplY3QgKipwZW5ndWlucyoqIGFzIGEgbm9ybWFsIGRhdGEgZnJhbWUuCgpgYGB7ciBpbnN0YWxsLCBldmFsPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQoKIyBJbnN0YWxsIHRoZSBwYWNrYWdlIChkbyBvbmNlIG9uIGFueSBjb21wdXRlcikKaW5zdGFsbC5wYWNrYWdlcygicGFsbWVycGVuZ3VpbnMiKQpgYGAKCmBgYHtyIGxvYWR9CiMgTG9hZCB0aGUgbGlicmFyeSAoZG8gYXQgdGhlIHN0YXJ0IG9mIGV2ZXJ5IFJTdHVkaW8gc2Vzc2lvbikKbGlicmFyeShwYWxtZXJwZW5ndWlucykKCiMgQ2hlY2sgdGhlIGRhdGEgLSB0aGUgZGF0YSBmcmFtZSBuYW1lIGlzIHBlbmd1aW5zCnN0cihwZW5ndWlucykKYGBgCgpUaGUgb3V0cHV0IGZyb20gYHN0cihwZW5ndWluc2ApIGluZGljYXRlcyB0aGF0IHRocmVlIG9mIHRoZSBjb2x1bW5zIGluIHRoZSBkYXRhIGZyYW1lIGFyZSAqKkZhY3RvcnMqKi4gSW4gUiwgYSBmYWN0b3IgaXMgYSBjYXRlZ29yaWNhbCB2YXJpYWJsZSwgdXN1YWxseSBjb3JyZXNwb25kaW5nIHRvIGFuIGV4cGVyaW1lbnRhbCBmYWN0b3IuIEFsdGhvdWdoIGZhY3RvcnMgbG9vayBsaWtlIHN0cmluZ3MsIGEgZmFjdG9yIGlzIHJlc3RyaWN0ZWQgdG8gYSBzcGVjaWZpYyBzZXQgb2YgbGVnYWwgdmFsdWVzLCB3aGljaCBSIGluZmVycyB3aGVuIHRoZSBkYXRhIGFyZSBsb2FkZWQuIFRoZSBsZWdhbCB2YWx1ZXMgYXJlIGNhbGxlZCAqKmxldmVscyoqLCBhbmQgY29ycmVzcG9uZCB0byB0aGUgZGlmZmVyZW50IGdyb3VwcyBvciBjb25kaXRpb25zIHJlcHJlc2VudGVkIGJ5IHRoZSBmYWN0b3IuIEZvciBleGFtcGxlLCBjb2x1bW4gYHBlbmd1aW5zJHNleGAgaXMgYSBmYWN0b3Igd2l0aCBsZXZlbHMgImZlbWFsZSIgYW5kICJtYWxlIi4gCgpXaGVuIG91ciBkYXRhIHNldHMgaGF2ZSBmYWN0b3JzLCB3ZSBvZnRlbiB1c2UgZnVuY3Rpb25zIGBsZXZlbHNgIGFuZCBgdGFibGVgLiBVc2UgR29vZ2xlIG9yIHlvdXIgZmF2b3VyaXRlIHRleHQgYm9vayB0byBleHBsb3JlIHRoZXNlIGZ1bmN0aW9ucy4gVXNlIHRoZW0gdG8gc29sdmUgdGhlIG5leHQgdHdvIGV4ZXJjaXNlcy4KCjEuIFdoYXQgYXJlIHRoZSB0aHJlZSBkaWZmZXJlbnQgbGV2ZWxzIG9mIHRoZSAqKnNwZWNpZXMqKiBmYWN0b3I/IFdoYXQgYXJlIHRoZSB0aHJlZSBkaWZmZXJlbnQgbGV2ZWxzIG9mIHRoZSAqKmlzbGFuZCoqIGZhY3Rvcj8KCmBgYHtyIGxldmVscywgZWNobz1GQUxTRSwgZXZhbD1GQUxTRX0KbGV2ZWxzKHBlbmd1aW5zJHNwZWNpZXMpCmxldmVscyhwZW5ndWlucyRpc2xhbmQpCmBgYAoKMi4gIEhvdyBtYW55IG9ic2VydmF0aW9ucyBhcmUgdGhlcmUgaW4gdGhlIGRhdGEgZnJhbWUgZm9yIGVhY2ggb2YgdGhlIHRocmVlIHNwZWNpZXM/IEhvdyBtYW55IG9ic2VydmF0aW9ucyBhcmUgdGhlcmUgaW4gdGhlIGRhdGEgZnJhbWUgZm9yIGVhY2ggb2YgdGhlIHRocmVlIGlzbGFuZHM/CgpgYGB7ciB0YWJsZSwgZWNobz1GQUxTRSwgZXZhbD1GQUxTRX0KdGFibGUocGVuZ3VpbnMkc3BlY2llcykKdGFibGUocGVuZ3VpbnMkaXNsYW5kKQpgYGAKCjMuIFVzaW5nIGJhc2UgUiwgZ2VuZXJhdGUgYSBoaXN0b2dyYW0gc2hvd2luZyB0aGUgZGlzdHJpYnV0aW9uIG9mIGJvZHkgbWFzcywgY29sbGFwc2VkIGFjcm9zcyBpc2xhbmQsIHNwZWNpZXMgYW5kIHNleC4gSG93IHdvdWxkIHlvdSBkZXNjcmliZSB0aGUgZGlzdHJpYnV0aW9uPwoKYGBge3IgaGlzdCwgZWNobz1GQUxTRSwgZXZhbD1GQUxTRX0KaGlzdChwZW5ndWlucyRib2R5X21hc3NfZykKYGBgCgo0LiBVc2luZyBnZ3Bsb3QsIGdlbmVyYXRlIGEgc2NhdHRlcnBsb3QgaWxsdXN0cmF0aW5nIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBiaWxsIGxlbmd0aCBhbmQgYm9keSBtYXNzLCBjb2xsYXBzZWQgYWNyb3NzIHNwZWNpZXMsIGlzbGFuZCBhbmQgc2V4LiBSZW1lbWJlciB0byBsb2FkIHRoZSBsaWJyYXJ5IHdpdGggYGxpYnJhcnkoZ2dwbG90MilgIGJlZm9yZSBmaXJzdCB1c2UuIEhvdyB3b3VsZCB5b3UgZGVzY3JpYmUgdGhlIHBhdHRlcm4/CgpgYGB7ciBzY2F0dGVycGxvdCwgZWNobz1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KCmxpYnJhcnkoZ2dwbG90MikKCmdncGxvdChkYXRhID0gcGVuZ3VpbnMpICsKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGJpbGxfbGVuZ3RoX21tLCB5ID0gYm9keV9tYXNzX2cpKQoKYGBgCgo1LiBNb2RpZnkgeW91ciBwbG90IGZyb20gRXhlcmNpc2UgNCBzbyB0aGF0IHBlbmd1aW5zIGZyb20gdGhlIGRpZmZlcmVudCBpc2xhbmRzIGFyZSBkcmF3biBpbiBkaWZmZXJlbnQgY29sb3Vycy4gV2hpY2ggaXNsYW5kIHNlZW1zIHRvIGhhdmUgdGhlIGhlYXZpZXN0IHBlbmd1aW5zPyBXaXRob3V0IGxvb2tpbmcgYW55IGZ1cnRoZXIgYXQgdGhlIGRhdGEsIGZvcm11bGF0ZSBhdCBsZWFzdCB0d28gcG9zc2libGUgZXhwbGFuYXRpb25zIGZvciB0aGUgcGF0dGVybi4KCmBgYHtyIGNvbG9yLCBlY2hvPUZBTFNFLCBldmFsPUZBTFNFfQpnZ3Bsb3QoZGF0YSA9IHBlbmd1aW5zKSArCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBiaWxsX2xlbmd0aF9tbSwgeSA9IGJvZHlfbWFzc19nLCBjb2xvciA9IGlzbGFuZCkpCgojIFBvc3NpYmxlIGV4cGxhbmF0aW9uczogMSkgTW9yZSBmb29kIG9uIHRoYXQgaXNsYW5kIDIpIEJpZ2dlciBzcGVjaWVzIG9mIHBlbmd1aW4gb24gdGhhdCBpc2xhbmQKCmBgYAoKNi4gVXNpbmcgZ2dwbG90LCBnZW5lcmF0ZSBhIGJveHBsb3QgY29tcGFyaW5nIGJvZHkgbWFzcyBmb3IgdGhlIHRocmVlIGRpZmZlcmVudCBzcGVjaWVzIG9mIHBlbmd1aW4sIGFuZCBoYXZpbmcgZWFjaCBvZiB0aGUgdGhyZWUgYm94ZXMgZHJhd24gaW4gYSBkaWZmZXJlbnQgY29sb3VyLiBXaGF0IGluZm9ybWF0aW9uIGlzIG1pc3NpbmcgZnJvbSB0aGlzIGZpZ3VyZSB0aGF0IHdhcyBwcm92aWRlZCBpbiAgRXhlcmNpc2UgNT8gV2hhdCBpbmZvcm1hdGlvbiBpcyBlYXNpZXIgdG8gc2VlIGluIHRoaXMgZmlndXJlIHRoYW4gaW4gRXhlcmNpc2UgNT8KCmBgYHtyIGdncGxvdF9ib3hwbG90LCBlY2hvPUZBTFNFLCBldmFsPUZBTFNFfQpnZ3Bsb3QoZGF0YSA9IHBlbmd1aW5zKSArCiAgZ2VvbV9ib3hwbG90KG1hcHBpbmcgPSBhZXMoeCA9IGlzbGFuZCAsIHkgPSBib2R5X21hc3NfZywgY29sb3VyID0gaXNsYW5kKSkKCmBgYAoKNy4gVXNpbmcgZ2dwbG90LCBkdXBsaWNhdGUgdGhpcyBmaWd1cmUuIFlvdSB3aWxsIG5lZWQgdG8gcmVzZWFyY2ggZ2VvbWV0cnkgZnVuY3Rpb24gYGdlb21fYmFyYC4KCmBgYHtyIGJhcnBsb3Rfd2l0aF9maWxsX2FuZF9kb2RnZSwgZWNobz1GQUxTRX0KZ2dwbG90KGRhdGEgPSBwZW5ndWlucykgKwogIGdlb21fYmFyKG1hcHBpbmcgPSBhZXMoeCA9IGlzbGFuZCwgZmlsbD1zcGVjaWVzKSwgcG9zaXRpb249ImRvZGdlIikKYGBgCgpcCg==