Data Focus

Modules and Zoom Notes 2–7 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.

  1. What are the three different levels of the species factor? What are the three different levels of the island factor?

  2. 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?

  3. Using base R, generate a histogram showing the distribution of body mass, collapsed across island, species and sex. How would you describe the distribution?

  4. 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?

  5. 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.

  6. 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?

  7. Using ggplot, duplicate this figure. You will need to research geometry function geom_bar.


LS0tCnRpdGxlOiAiWm9vbSBOb3RlcyAwMjogVmlzdWFsaXNpbmcgRGF0YSIKZGF0ZTogIlNlbWVzdGVyIDIsIDIwMjMiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIHRvY19kZXB0aDogMwogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBzaG93Ci0tLQogIApgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KbGlicmFyeShnZ3Bsb3QyKQoKbGlicmFyeShrbml0cikKCmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICBjb21tZW50ID0gIiM+IiwKICBmaWcucGF0aCA9ICJmaWd1cmVzLzAyLyIsICMgdXNlIG9ubHkgZm9yIHNpbmdsZSBSbWQgZmlsZXMKICBjb2xsYXBzZSA9IFRSVUUsCiAgZWNobyA9IFRSVUUKKQpgYGAKCj4gIyMjIyBEYXRhIEZvY3VzCiAgPgogID4gTW9kdWxlcyBhbmQgWm9vbSBOb3RlcyAyLS03IGNvdmVyIHRvcGljcyB0aGF0IGFyZSBwYXJ0IG9mIHRoZSBkYXRhIGFuYWx5c2lzIGpvdXJuZXkgYW5kIGFyZSBhbGwgaW50ZXJyZWxhdGVkLiBFYWNoIG1vZHVsZSB3aWxsIGludHJvZHVjZSBuZXcgY29udGVudCBhbmQgZXhwYW5kIG9uIHRoZSBtYXRlcmlhbCBjb3ZlcmVkIGluIHByZXZpb3VzIG1vZHVsZXMuIEZvciBleGFtcGxlLCBpbiBNb2R1bGUgMiB3ZSBpbnRyb2R1Y2UgdGhlIGJhc2ljcyBvZiB0aGUgUiBwbG90dGluZyBzeXN0ZW1zLiBTdWJzZXF1ZW50IHNlc3Npb25zIGluY2x1ZGUgbW9yZSBhZHZhbmNlZCBwbG90dGluZyBvcHRpb25zIGFuZCB0ZWNobmlxdWVzLgoKXAoKXAoKPiAjIyMjIEFzc29jaWF0ZWQgbWF0ZXJpYWw6Cj4KPiBNb2R1bGU6IFtNb2R1bGUgMDIgLSBWaXN1YWxpc2luZyBEYXRhXSgwMi12aXN1YWxpc2UuaHRtbCkKPiAKPiBSZWFkaW5nczoKPiAgIAo+IC0gW1IgZm9yIERhdGEgU2NpZW5jZSAtIENoYXB0ZXIgMTJdKGh0dHBzOi8vcjRkcy5oYWQuY28ubnovdGlkeS1kYXRhLmh0bWwpCj4gLSBbUiBmb3IgRGF0YSBTY2llbmNlIC0gQ2hhcHRlciAxMV0oaHR0cHM6Ly9yNGRzLmhhZC5jby5uei9kYXRhLWltcG9ydC5odG1sKQo+IC0gW1IgZm9yIERhdGEgU2NpZW5jZSAtIENoYXB0ZXIgM10oaHR0cHM6Ly9yNGRzLmhhZC5jby5uei9kYXRhLXZpc3VhbGlzYXRpb24uaHRtbCkKCgojIFRvcGljcwoKIyMgVGFidWxhciBkYXRhCgotIEVkaXQgaW4gRXhjZWwKLSBFeHBvcnQgdG8gcGxhaW4gY3N2IChub3QgVVRGLTgpCi0gQ29sdW1uIGhlYWRlcnMgaW4gZmlyc3Qgcm93IGZvciBldmVyeSBjb2x1bW4KLSBPbmUgcm93IGZvciBlYWNoIGRhdGEgcmVjb3JkCgojIyBGb2xkZXIgc2V0dXAKCi0gRXZlbnR1YWxseSwgdXNlIFByb2plY3RzIHRvIGFsbG93IFJTdHVkaW8gdG8gbWFuYWdlIG1ldGFkYXRhCi0gU2VwYXJhdGUgZm9sZGVycyBmb3IgZGF0YSBmaWxlcywgaW1hZ2VzLCBzY3JpcHRzLCBSbWQsIGV0Yy4KCiMjIEltcG9ydGluZyBhIGRhdGEgZmlsZQoKLSByZWFkLmNzdgotIFNldCBzdHJpbmdzQXNGYWN0b3JzID0gVFJVRSB0byBpbXBvcnQgY2F0ZWdvcmljYWwgdmFyaWFibGVzIGNvcnJlY3RseQotIEFmdGVyIHdlIG1lZXQgdGhlIHRpZHl2ZXJzZSwgY2FuIGFsc28gdXNlIHJlYWRfY3N2CgojIyBDaGVja2luZyB5b3VyIGltcG9ydGVkIGRhdGEKCi0gaGVhZAotIHRhaWwKLSBzdHIKLSBDb25maXJtIHRoYXQgZWFjaCBjb2x1bW4gaXMgb2YgdGhlIGNvcnJlY3QgdHlwZQoKIyMgU2VsZWN0aW5nIGFuZCB1c2luZyBjb2x1bW5zIG9mIGRhdGEKCi0gU2VsZWN0IGFuIGluZGl2aWR1YWwgY29sdW1uIHdpdGggdGhlICQgb3BlcmF0b3IKCiMjIEJhc2UgUiBwbG90cwoKLSBoaXN0IGZvciBmcmVxdWVuY3kgZGlzdHJpYnV0aW9ucwotIGJveHBsb3RzIHNob3cgY2VudHJhbCB0ZW5kZW5jeSBhbmQgdmFyaWFiaWxpdHkKLSBmb3JtdWxhcyBoYXZlIHRoZSBmb3JtICpkZXBlbmRlbnQgdmFyaWFibGUqICoqfioqICpsaW5lYXIgbW9kZWwgb2YgaW5kZXBlbmRlbnQgdmFyaWFibGVzKgoKIyMgUGxvdHRpbmcgd2l0aCBnZ3Bsb3QKCi0gVXNlIGZ1bmN0aW9uIGBnZ3Bsb3RgIGNvbnRhaW5lZCBpbiBsaWJyYXJ5IChhbmQgcGFja2FnZSkgZ2dwbG90MgotIENvbXBsZXggc3ludGF4IGJhc2VkIG9uIEdyYW1tYXIgb2YgR3JhcGhpY3MgKGZyb20gY29tcHV0ZXIgc2NpZW5jZSkKLSBQbG90cyBidWlsdCBpbiBsYXllcnMKCiMjIEJ1aWxkaW5nIGEgZ3JhcGgKCi0gQWxsIHBsb3RzIGJlZ2luIHdpdGggY2FsbCB0byBnZ3Bsb3QsIHBhc3NpbmcgaW4gYSBkYXRhIGZyYW1lCi0gTWFwcGluZ3MgZGVmaW5lIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiBlbGVtZW50cyBvZiB0aGUgZGF0YSBhbmQgdmlzdWFsIGZlYXR1cmVzIG9uIHRoZSBwbG90Ci0gVXNlIGZ1bmN0aW9uIGBhZXNgIHRvIGRlZmluZSBhIG1hcHBpbmcKLSBBc3NpZ24gY29sdW1uIG5hbWVzIHRvIGBhZXNgIGFyZ3VtZW50cyBgeGAgYW5kIGB5YCB0byBkZWZpbmUgZ3JhcGggYXhlcwotIE1hbnkgYXZhaWxhYmxlIGFyZ3VtZW50cyB0byBgYWVzYDsgcGFydCBvZiB0aGUgZ2dwbG90IHN5bnRheAotIFNlbGVjdCBhICoqZ2VvbWV0cnkqKiB0byBkZXRlcm1pbmUgdGhlIGtpbmQgb2YgcGxvdCAoZS5nLiBiYXIgZ3JhcGgsIHNjYXR0ZXJwbG90LCBsaW5lIGdyYXBoLCBldGMuKQotIEFkZGl0aW9uYWwgbGF5ZXJzIGRlZmluZSBheGVzIGxhYmVscywgdGl0bGUsIGxlZ2VuZHMsIGFuZCBmb250cwotIENvbWJpbmUgZ2dwbG90IGxheWVyIHN1Yi1jb21tYW5kcyB3aXRoIGArYAoKIyBQcmFjdGljZSBFeGVyY2lzZXMKClRvIHByYWN0aWNlIHdoYXQgd2UgaGF2ZSBsZWFybmVkIGluIE1vZHVsZSAwMiwgd2Ugd2lsbCB1c2UgIlBhbG1lcidzIFBlbmd1aW5zIiwgYSByZWFsIGRhdGEgc2V0IGZyb20gdGhlIFBhbG1lciBTdGF0aW9uIExvbmcgVGVybSBFY29sb2dpY2FsIFJlc2VhcmNoIHByb2dyYW0gKGh0dHBzOi8vYWxsaXNvbmhvcnN0LmdpdGh1Yi5pby9wYWxtZXJwZW5ndWlucy9hcnRpY2xlcy9pbnRyby5odG1sKS4gVGhlc2UgZGF0YSBhcmUgc2l6ZSBtZWFzdXJlbWVudHMgZm9yIHRocmVlIHBlbmd1aW4gc3BlY2llcyAtLSBDaGluc3RyYXAsIEdlbnRvbyBhbmQgQWRlbGllIC0tIG9uIHRocmVlIGlzbGFuZHMgaW4gQW50YXJjdGljYS4KCkluc3RhbGwgdGhlIHBhY2thZ2UgdGhhdCBjb250YWlucyB0aGUgZGF0YSAoY29kZSBzaG93biBiZWxvdykuIFRoZW4gd29yayB0aHJvdWdoIGVhY2ggb2YgdGhlIGV4ZXJjaXNlcy4gSWYgeW91IGhhdmUgYW55IHF1ZXN0aW9ucywgZW1haWwgdXMgb3Igc2VuZCB1cyBhIG1lc3NhZ2UgaW4gTVMgVGVhbXMuCgpBY2Nlc3MgdGhlIGRhdGEgYXMgc2hvd24gYmVsb3cuIFRoZXNlIGNvbW1hbmRzIGluaXRpYWxpc2UgYW4gb2JqZWN0IGNhbGxlZCAqKnBlbmd1aW5zKiosIHdoaWNoIGlzIGEgKip0aWJibGUqKiwgYW4gZW5oYW5jZWQgZGF0YSBmcmFtZS4gVGhlIGFkZGl0aW9uYWwgZmVhdHVyZXMgb2YgdGliYmxlcyB3aWxsIGJlIGRpc2N1c3NlZCBkdXJpbmcgdGhlIG5leHQgbW9kdWxlLiBGb3IgdGhlc2UgZXhlcmNpc2VzIHNpbXBseSB0cmVhdCBvYmplY3QgKipwZW5ndWlucyoqIGFzIGEgbm9ybWFsIGRhdGEgZnJhbWUuCgpgYGB7ciBpbnN0YWxsLCBldmFsPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQoKIyBJbnN0YWxsIHRoZSBwYWNrYWdlIChkbyBvbmNlIG9uIGFueSBjb21wdXRlcikKaW5zdGFsbC5wYWNrYWdlcygicGFsbWVycGVuZ3VpbnMiKQpgYGAKCmBgYHtyIGxvYWR9CiMgTG9hZCB0aGUgbGlicmFyeSAoZG8gYXQgdGhlIHN0YXJ0IG9mIGV2ZXJ5IFJTdHVkaW8gc2Vzc2lvbikKbGlicmFyeShwYWxtZXJwZW5ndWlucykKCiMgQ2hlY2sgdGhlIGRhdGEgLSB0aGUgZGF0YSBmcmFtZSBuYW1lIGlzIHBlbmd1aW5zCnN0cihwZW5ndWlucykKYGBgCgpUaGUgb3V0cHV0IGZyb20gYHN0cihwZW5ndWluc2ApIGluZGljYXRlcyB0aGF0IHRocmVlIG9mIHRoZSBjb2x1bW5zIGluIHRoZSBkYXRhIGZyYW1lIGFyZSAqKkZhY3RvcnMqKi4gSW4gUiwgYSBmYWN0b3IgaXMgYSBjYXRlZ29yaWNhbCB2YXJpYWJsZSwgdXN1YWxseSBjb3JyZXNwb25kaW5nIHRvIGFuIGV4cGVyaW1lbnRhbCBmYWN0b3IuIEFsdGhvdWdoIGZhY3RvcnMgbG9vayBsaWtlIHN0cmluZ3MsIGEgZmFjdG9yIGlzIHJlc3RyaWN0ZWQgdG8gYSBzcGVjaWZpYyBzZXQgb2YgbGVnYWwgdmFsdWVzLCB3aGljaCBSIGluZmVycyB3aGVuIHRoZSBkYXRhIGFyZSBsb2FkZWQuIFRoZSBsZWdhbCB2YWx1ZXMgYXJlIGNhbGxlZCAqKmxldmVscyoqLCBhbmQgY29ycmVzcG9uZCB0byB0aGUgZGlmZmVyZW50IGdyb3VwcyBvciBjb25kaXRpb25zIHJlcHJlc2VudGVkIGJ5IHRoZSBmYWN0b3IuIEZvciBleGFtcGxlLCBjb2x1bW4gYHBlbmd1aW5zJHNleGAgaXMgYSBmYWN0b3Igd2l0aCBsZXZlbHMgImZlbWFsZSIgYW5kICJtYWxlIi4gCgpXaGVuIG91ciBkYXRhIHNldHMgaGF2ZSBmYWN0b3JzLCB3ZSBvZnRlbiB1c2UgZnVuY3Rpb25zIGBsZXZlbHNgIGFuZCBgdGFibGVgLiBVc2UgR29vZ2xlIG9yIHlvdXIgZmF2b3VyaXRlIHRleHQgYm9vayB0byBleHBsb3JlIHRoZXNlIGZ1bmN0aW9ucy4gVXNlIHRoZW0gdG8gc29sdmUgdGhlIG5leHQgdHdvIGV4ZXJjaXNlcy4KCjEuIFdoYXQgYXJlIHRoZSB0aHJlZSBkaWZmZXJlbnQgbGV2ZWxzIG9mIHRoZSAqKnNwZWNpZXMqKiBmYWN0b3I/IFdoYXQgYXJlIHRoZSB0aHJlZSBkaWZmZXJlbnQgbGV2ZWxzIG9mIHRoZSAqKmlzbGFuZCoqIGZhY3Rvcj8KCmBgYHtyIGxldmVscywgZWNobz1GQUxTRSwgZXZhbD1GQUxTRX0KbGV2ZWxzKHBlbmd1aW5zJHNwZWNpZXMpCmxldmVscyhwZW5ndWlucyRpc2xhbmQpCmBgYAoKMi4gIEhvdyBtYW55IG9ic2VydmF0aW9ucyBhcmUgdGhlcmUgaW4gdGhlIGRhdGEgZnJhbWUgZm9yIGVhY2ggb2YgdGhlIHRocmVlIHNwZWNpZXM/IEhvdyBtYW55IG9ic2VydmF0aW9ucyBhcmUgdGhlcmUgaW4gdGhlIGRhdGEgZnJhbWUgZm9yIGVhY2ggb2YgdGhlIHRocmVlIGlzbGFuZHM/CgpgYGB7ciB0YWJsZSwgZWNobz1GQUxTRSwgZXZhbD1GQUxTRX0KdGFibGUocGVuZ3VpbnMkc3BlY2llcykKdGFibGUocGVuZ3VpbnMkaXNsYW5kKQpgYGAKCjMuIFVzaW5nIGJhc2UgUiwgZ2VuZXJhdGUgYSBoaXN0b2dyYW0gc2hvd2luZyB0aGUgZGlzdHJpYnV0aW9uIG9mIGJvZHkgbWFzcywgY29sbGFwc2VkIGFjcm9zcyBpc2xhbmQsIHNwZWNpZXMgYW5kIHNleC4gSG93IHdvdWxkIHlvdSBkZXNjcmliZSB0aGUgZGlzdHJpYnV0aW9uPwoKYGBge3IgaGlzdCwgZWNobz1GQUxTRSwgZXZhbD1GQUxTRX0KaGlzdChwZW5ndWlucyRib2R5X21hc3NfZykKYGBgCgo0LiBVc2luZyBnZ3Bsb3QsIGdlbmVyYXRlIGEgc2NhdHRlcnBsb3QgaWxsdXN0cmF0aW5nIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBiaWxsIGxlbmd0aCBhbmQgYm9keSBtYXNzLCBjb2xsYXBzZWQgYWNyb3NzIHNwZWNpZXMsIGlzbGFuZCBhbmQgc2V4LiBSZW1lbWJlciB0byBsb2FkIHRoZSBsaWJyYXJ5IHdpdGggYGxpYnJhcnkoZ2dwbG90MilgIGJlZm9yZSBmaXJzdCB1c2UuIEhvdyB3b3VsZCB5b3UgZGVzY3JpYmUgdGhlIHBhdHRlcm4/CgpgYGB7ciBzY2F0dGVycGxvdCwgZWNobz1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KCmxpYnJhcnkoZ2dwbG90MikKCmdncGxvdChkYXRhID0gcGVuZ3VpbnMpICsKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGJpbGxfbGVuZ3RoX21tLCB5ID0gYm9keV9tYXNzX2cpKQoKYGBgCgo1LiBNb2RpZnkgeW91ciBwbG90IGZyb20gRXhlcmNpc2UgNCBzbyB0aGF0IHBlbmd1aW5zIGZyb20gdGhlIGRpZmZlcmVudCBpc2xhbmRzIGFyZSBkcmF3biBpbiBkaWZmZXJlbnQgY29sb3Vycy4gV2hpY2ggaXNsYW5kIHNlZW1zIHRvIGhhdmUgdGhlIGhlYXZpZXN0IHBlbmd1aW5zPyBXaXRob3V0IGxvb2tpbmcgYW55IGZ1cnRoZXIgYXQgdGhlIGRhdGEsIGZvcm11bGF0ZSBhdCBsZWFzdCB0d28gcG9zc2libGUgZXhwbGFuYXRpb25zIGZvciB0aGUgcGF0dGVybi4KCmBgYHtyIGNvbG9yLCBlY2hvPUZBTFNFLCBldmFsPUZBTFNFfQpnZ3Bsb3QoZGF0YSA9IHBlbmd1aW5zKSArCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBiaWxsX2xlbmd0aF9tbSwgeSA9IGJvZHlfbWFzc19nLCBjb2xvciA9IGlzbGFuZCkpCgojIFBvc3NpYmxlIGV4cGxhbmF0aW9uczogMSkgTW9yZSBmb29kIG9uIHRoYXQgaXNsYW5kIDIpIEJpZ2dlciBzcGVjaWVzIG9mIHBlbmd1aW4gb24gdGhhdCBpc2xhbmQKCmBgYAoKNi4gVXNpbmcgZ2dwbG90LCBnZW5lcmF0ZSBhIGJveHBsb3QgY29tcGFyaW5nIGJvZHkgbWFzcyBmb3IgdGhlIHRocmVlIGRpZmZlcmVudCBzcGVjaWVzIG9mIHBlbmd1aW4sIGFuZCBoYXZpbmcgZWFjaCBvZiB0aGUgdGhyZWUgYm94ZXMgZHJhd24gaW4gYSBkaWZmZXJlbnQgY29sb3VyLiBXaGF0IGluZm9ybWF0aW9uIGlzIG1pc3NpbmcgZnJvbSB0aGlzIGZpZ3VyZSB0aGF0IHdhcyBwcm92aWRlZCBpbiAgRXhlcmNpc2UgNT8gV2hhdCBpbmZvcm1hdGlvbiBpcyBlYXNpZXIgdG8gc2VlIGluIHRoaXMgZmlndXJlIHRoYW4gaW4gRXhlcmNpc2UgNT8KCmBgYHtyIGdncGxvdF9ib3hwbG90LCBlY2hvPUZBTFNFLCBldmFsPUZBTFNFfQpnZ3Bsb3QoZGF0YSA9IHBlbmd1aW5zKSArCiAgZ2VvbV9ib3hwbG90KG1hcHBpbmcgPSBhZXMoeCA9IGlzbGFuZCAsIHkgPSBib2R5X21hc3NfZywgY29sb3VyID0gaXNsYW5kKSkKCmBgYAoKNy4gVXNpbmcgZ2dwbG90LCBkdXBsaWNhdGUgdGhpcyBmaWd1cmUuIFlvdSB3aWxsIG5lZWQgdG8gcmVzZWFyY2ggZ2VvbWV0cnkgZnVuY3Rpb24gYGdlb21fYmFyYC4KCmBgYHtyIGJhcnBsb3Rfd2l0aF9maWxsX2FuZF9kb2RnZSwgZWNobz1GQUxTRX0KZ2dwbG90KGRhdGEgPSBwZW5ndWlucykgKwogIGdlb21fYmFyKG1hcHBpbmcgPSBhZXMoeCA9IGlzbGFuZCwgZmlsbD1zcGVjaWVzKSwgcG9zaXRpb249ImRvZGdlIikKYGBgCgpcCg==