Goals

Preliminaries

Load required packages.

library(tidyverse)
library(googlesheets)

Load data and examine

The survey data are stored in a Google Sheet. We’ll use the googlesheets package to open it and create a data frame. Documentation about the package can be found here.

There are some idiosyncrasies in using the googlesheets package in an R Markdown document because it requires interaction with the console, so I created a separate R script, Get_bootcamp_googlesheet.R to extract the survey data. If you try to execute the next chunk, it may give you an error, or it may ask you to allow googlesheets to access information in your Google profile.

# Set eval=FALSE so I can render non-notebook formats
survey_url <- "https://docs.google.com/spreadsheets/d/1Ay56u6g4jyEEdlmV2NHxTLBlcjI2gHavta-Ik0kGrpg/edit?usp=sharing"
bootcamp_by_url <- survey_url %>%
  extract_key_from_url() %>%
  gs_key()
Auto-refreshing stale OAuth token.
Sheet successfully identified: "PSU Psychology R Bootcamp Survey (Responses)"
bootcamp_sheets <- gs_ws_ls(bootcamp_by_url)
boot_data <- bootcamp_by_url %>%
  gs_read(bootcamp_sheets[1])
Accessing worksheet titled 'Form Responses 1'.

Downloading: 700 B     
Downloading: 700 B     
Downloading: 710 B     
Downloading: 710 B     
Downloading: 710 B     
Downloading: 710 B     
Downloading: 710 B     
Downloading: 710 B     
Parsed with column specification:
cols(
  Timestamp = col_character(),
  `Your current level of experience/expertise with R` = col_character(),
  `Your enthusiasm for Game of Thrones` = col_integer(),
  `Age in years` = col_integer(),
  `Preferred number of hours spent sleeping/day` = col_character(),
  `Favorite day of the week` = col_character(),
  `Are your data tidy?` = col_character()
)
          
write_csv(boot_data, path="../data/survey.csv")

This script downloads the data file saves it to a CSV under data/survey.csv.We can then load this file.

I also created a test data file, data/survey-test.csv so I could see how everything worked before y’all filled out your responses. The R/Make_test_survey.R file shows how I did this. It’s a great, reproducible practice to simulate the data you expect, then run it through your pipeline.


# Created test data set for testing.
# survey <- read_csv("../data/survey-test.csv")
# Or choose data from respondents
survey <- read_csv("../data/survey.csv")
Parsed with column specification:
cols(
  Timestamp = col_character(),
  `Your current level of experience/expertise with R` = col_character(),
  `Your enthusiasm for Game of Thrones` = col_integer(),
  `Age in years` = col_integer(),
  `Preferred number of hours spent sleeping/day` = col_character(),
  `Favorite day of the week` = col_character(),
  `Are your data tidy?` = col_character()
)
survey

The str() or ‘structure’ command is also a great way to see what you’ve got.

str(survey)
Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   39 obs. of  7 variables:
 $ Timestamp                                        : chr  NA "8/13/2017 23:29:24" "8/14/2017 12:01:12" "8/15/2017 12:42:09" ...
 $ Your current level of experience/expertise with R: chr  NA "some" "some" "some" ...
 $ Your enthusiasm for Game of Thrones              : int  NA 10 10 10 10 10 10 3 9 10 ...
 $ Age in years                                     : int  NA 28 22 24 28 24 23 25 37 25 ...
 $ Preferred number of hours spent sleeping/day     : chr  NA "8!!!" "7" "10" ...
 $ Favorite day of the week                         : chr  NA "Friday" "Friday" "Saturday" ...
 $ Are your data tidy?                              : chr  NA "Yes" "That's a personal question" "No" ...
 - attr(*, "spec")=List of 2
  ..$ cols   :List of 7
  .. ..$ Timestamp                                        : list()
  .. .. ..- attr(*, "class")= chr  "collector_character" "collector"
  .. ..$ Your current level of experience/expertise with R: list()
  .. .. ..- attr(*, "class")= chr  "collector_character" "collector"
  .. ..$ Your enthusiasm for Game of Thrones              : list()
  .. .. ..- attr(*, "class")= chr  "collector_integer" "collector"
  .. ..$ Age in years                                     : list()
  .. .. ..- attr(*, "class")= chr  "collector_integer" "collector"
  .. ..$ Preferred number of hours spent sleeping/day     : list()
  .. .. ..- attr(*, "class")= chr  "collector_character" "collector"
  .. ..$ Favorite day of the week                         : list()
  .. .. ..- attr(*, "class")= chr  "collector_character" "collector"
  .. ..$ Are your data tidy?                              : list()
  .. .. ..- attr(*, "class")= chr  "collector_character" "collector"
  ..$ default: list()
  .. ..- attr(*, "class")= chr  "collector_guess" "collector"
  ..- attr(*, "class")= chr "col_spec"

Clearly, we need to do some cleaning before we can do anything with this.

Let’s start by renaming variables.

names(survey) <- c("Timestamp",
                  "R_exp",
                  "GoT",
                  "Age_yrs",
                  "Sleep_hrs",
                  "Fav_day",
                  "Tidy_data")
# complete.cases() drops NAs
survey <- survey[complete.cases(survey),]
survey

Now, lets make sure we have numbers where we expect them. That person who really likes 8 hours (“8!!!”) is a problem (for me, not them).

survey$Sleep_hrs <- readr::parse_number(survey$Sleep_hrs)
survey

Looks good. Let’s save that cleaned file so we don’t have to do this again.

write_csv(survey, path="../data/survey_clean.csv")

We may want to make the R_exp variable ordered.

(survey_responses <- unique(survey$R_exp))
[1] "some"    "none"    "limited" "pro"    

This shows us the different survey response values.

survey$R_exp <- ordered(survey$R_exp, levels=c("none",
                                               "limited",
                                               "some",
                                               "lots",
                                               "pro"))

Visualization

Now, we follow Mike Meyer’s advice: “Plot your data!”

Descriptive plots

R_exp_hist <- survey %>%
  ggplot() +
  aes(x=R_exp) +
  geom_histogram(stat = "count") # R_exp is discrete
Ignoring unknown parameters: binwidth, bins, pad
R_exp_hist

Sleep_hrs_hist <- survey %>%
  ggplot() +
  aes(x=Sleep_hrs) +
  geom_histogram() # Sleep_hrs is continuous
Sleep_hrs_hist

Got_hist <- survey %>%
  ggplot() +
  aes(x=GoT) +
  geom_histogram()
Got_hist

Looks like we are of two minds about GoT.

Does R experience have any relation to GoT enthusiasm?

GoT_vs_r_exp <- survey %>%
  ggplot() +
  aes(x=GoT, y=Age_yrs) +
  facet_grid(. ~ R_exp) +
  geom_point()
  # + stat_smooth()
GoT_vs_r_exp

tidy_hist <- survey %>%
  ggplot() +
  aes(x=Tidy_data) +
  geom_histogram(stat = "count")
tidy_hist

Analysis

I could use a document like this to plan out my analysis plan before I conduct it. If I used simulated data, I could make sure that my workflow will run when I get real (cleaned) data. I could even preregister my analysis plan before I conduct it. That doesn’t preclude later exploratory analyses, but it does hold me and my collaborators accountable for what I predicted in advance.

Notes

Notice that I sometimes put a label like got-vs-r-exp in the brackets for a given ‘chunk’ of R code. The main reasons to do this are:

LS0tCnRpdGxlOiAiQW5hbHlzaXMgb2YgYm9vdGNhbXAgc3VydmV5IgphdXRob3I6ICJSaWNrIEdpbG1vcmUiCmRhdGU6ICdgciBTeXMudGltZSgpYCcKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKICBnaXRodWJfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiAzCiAgcGRmX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogMwogIHdvcmRfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiAzCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkKYGBgCgojIyBHb2FscwoKLSBEb3dubG9hZCBhbmQgY2xlYW4gZGF0YSBmcm9tIDIwMTcgUiBCb290Y2FtcCBTdXJ2ZXkKLSBWaXN1YWxpemUgZGF0YQotIFByZXBhcmUgcmVwb3J0cyBpbiBgaW9zbGlkZXNfcHJlc2VudGF0aW9uYCwgYHBkZl9kb2N1bWVudGAsIGFuZCBgd29yZF9kb2N1bWVudGAgZm9ybWF0cwoKIyMgUHJlbGltaW5hcmllcwoKTG9hZCByZXF1aXJlZCBwYWNrYWdlcy4KCmBgYHtyIGxvYWQtcGFja2FnZXN9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGdvb2dsZXNoZWV0cykKCmBgYAoKIyMgTG9hZCBkYXRhIGFuZCBleGFtaW5lClRoZSBzdXJ2ZXkgZGF0YSBhcmUgc3RvcmVkIGluIGEgW0dvb2dsZSBTaGVldF0oaHR0cHM6Ly9kb2NzLmdvb2dsZS5jb20vc3ByZWFkc2hlZXRzL2QvMUF5NTZ1Nmc0anlFRWRsbVYyTkh4VExCbGNqSTJnSGF2dGEtSWswa0dycGcvZWRpdCNnaWQ9ODk2NDQ3MDYzKS4gV2UnbGwgdXNlIHRoZSBgZ29vZ2xlc2hlZXRzYCBwYWNrYWdlIHRvIG9wZW4gaXQgYW5kIGNyZWF0ZSBhIGRhdGEgZnJhbWUuIERvY3VtZW50YXRpb24gYWJvdXQgdGhlIHBhY2thZ2UgY2FuIGJlIGZvdW5kIFtoZXJlXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvZ29vZ2xlc2hlZXRzL3ZpZ25ldHRlcy9iYXNpYy11c2FnZS5odG1sKS4KClRoZXJlIGFyZSBzb21lIGlkaW9zeW5jcmFzaWVzIGluIHVzaW5nIHRoZSBgZ29vZ2xlc2hlZXRzYCBwYWNrYWdlIGluIGFuIFIgTWFya2Rvd24gZG9jdW1lbnQgYmVjYXVzZSBpdCByZXF1aXJlcyBpbnRlcmFjdGlvbiB3aXRoIHRoZSBjb25zb2xlLCBzbyBJIGNyZWF0ZWQgYSBzZXBhcmF0ZSBSIHNjcmlwdCwgYEdldF9ib290Y2FtcF9nb29nbGVzaGVldC5SYCB0byBleHRyYWN0IHRoZSBzdXJ2ZXkgZGF0YS4KSWYgeW91IHRyeSB0byBleGVjdXRlIHRoZSBuZXh0IGNodW5rLCBpdCBtYXkgZ2l2ZSB5b3UgYW4gZXJyb3IsIG9yIGl0IG1heSBhc2sgeW91IHRvIGFsbG93IGBnb29nbGVzaGVldHNgIHRvIGFjY2VzcyBpbmZvcm1hdGlvbiBpbiB5b3VyIEdvb2dsZSBwcm9maWxlLgoKYGBge3IgdXBkYXRlLXN1cnZleS1kYXRhLWZyb20tZ29vZ2xlLXNoZWV0fQojIFNldCBldmFsPUZBTFNFIHNvIEkgY2FuIHJlbmRlciBub24tbm90ZWJvb2sgZm9ybWF0cwpzdXJ2ZXlfdXJsIDwtICJodHRwczovL2RvY3MuZ29vZ2xlLmNvbS9zcHJlYWRzaGVldHMvZC8xQXk1NnU2ZzRqeUVFZGxtVjJOSHhUTEJsY2pJMmdIYXZ0YS1JazBrR3JwZy9lZGl0P3VzcD1zaGFyaW5nIgoKYm9vdGNhbXBfYnlfdXJsIDwtIHN1cnZleV91cmwgJT4lCiAgZXh0cmFjdF9rZXlfZnJvbV91cmwoKSAlPiUKICBnc19rZXkoKQoKYm9vdGNhbXBfc2hlZXRzIDwtIGdzX3dzX2xzKGJvb3RjYW1wX2J5X3VybCkKCmJvb3RfZGF0YSA8LSBib290Y2FtcF9ieV91cmwgJT4lCiAgZ3NfcmVhZChib290Y2FtcF9zaGVldHNbMV0pCiAgICAgICAgICAKd3JpdGVfY3N2KGJvb3RfZGF0YSwgcGF0aD0iLi4vZGF0YS9zdXJ2ZXkuY3N2IikKYGBgCgpUaGlzIHNjcmlwdCBkb3dubG9hZHMgdGhlIGRhdGEgZmlsZSBzYXZlcyBpdCB0byBhIENTViB1bmRlciBgZGF0YS9zdXJ2ZXkuY3N2YC5XZSBjYW4gdGhlbiBsb2FkIHRoaXMgZmlsZS4KCkkgYWxzbyBjcmVhdGVkIGEgdGVzdCBkYXRhIGZpbGUsIGBkYXRhL3N1cnZleS10ZXN0LmNzdmAgc28gSSBjb3VsZCBzZWUgaG93IGV2ZXJ5dGhpbmcgd29ya2VkIGJlZm9yZSB5J2FsbCBmaWxsZWQgb3V0IHlvdXIgcmVzcG9uc2VzLgpUaGUgW2BSL01ha2VfdGVzdF9zdXJ2ZXkuUmBdKC4uL1IvTWFrZV90ZXN0X3N1cnZleS5SKSBmaWxlIHNob3dzIGhvdyBJIGRpZCB0aGlzLgpJdCdzIGEgZ3JlYXQsIHJlcHJvZHVjaWJsZSBwcmFjdGljZSB0byAqKnNpbXVsYXRlIHRoZSBkYXRhIHlvdSBleHBlY3QqKiwgdGhlbiBydW4gaXQgdGhyb3VnaCB5b3VyIHBpcGVsaW5lLgoKLS0tCgpgYGB7ciBsb2FkLWRhdGF9CiMgQ3JlYXRlZCB0ZXN0IGRhdGEgc2V0IGZvciB0ZXN0aW5nLgojIHN1cnZleSA8LSByZWFkX2NzdigiLi4vZGF0YS9zdXJ2ZXktdGVzdC5jc3YiKQojIE9yIGNob29zZSBkYXRhIGZyb20gcmVzcG9uZGVudHMKc3VydmV5IDwtIHJlYWRfY3N2KCIuLi9kYXRhL3N1cnZleS5jc3YiKQpgYGAKCmBgYHtyfQpzdXJ2ZXkKYGBgCgpUaGUgYHN0cigpYCBvciAnc3RydWN0dXJlJyBjb21tYW5kIGlzIGFsc28gYSBncmVhdCB3YXkgdG8gc2VlIHdoYXQgeW91J3ZlIGdvdC4KCmBgYHtyfQpzdHIoc3VydmV5KQpgYGAKCkNsZWFybHksIHdlIG5lZWQgdG8gZG8gc29tZSBjbGVhbmluZyBiZWZvcmUgd2UgY2FuIGRvIGFueXRoaW5nIHdpdGggdGhpcy4KCkxldCdzIHN0YXJ0IGJ5IHJlbmFtaW5nIHZhcmlhYmxlcy4KCmBgYHtyIHJlbmFtZS12YXJzfQpuYW1lcyhzdXJ2ZXkpIDwtIGMoIlRpbWVzdGFtcCIsCiAgICAgICAgICAgICAgICAgICJSX2V4cCIsCiAgICAgICAgICAgICAgICAgICJHb1QiLAogICAgICAgICAgICAgICAgICAiQWdlX3lycyIsCiAgICAgICAgICAgICAgICAgICJTbGVlcF9ocnMiLAogICAgICAgICAgICAgICAgICAiRmF2X2RheSIsCiAgICAgICAgICAgICAgICAgICJUaWR5X2RhdGEiKQpgYGAKCgpgYGB7ciBjbGVhbi1zdXJ2ZXl9CiMgY29tcGxldGUuY2FzZXMoKSBkcm9wcyBOQXMKc3VydmV5IDwtIHN1cnZleVtjb21wbGV0ZS5jYXNlcyhzdXJ2ZXkpLF0Kc3VydmV5CmBgYAoKTm93LCBsZXRzIG1ha2Ugc3VyZSB3ZSBoYXZlIG51bWJlcnMgd2hlcmUgd2UgZXhwZWN0IHRoZW0uIApUaGF0IHBlcnNvbiB3aG8gcmVhbGx5IGxpa2VzIDggaG91cnMgKCI4ISEhIikgaXMgYSBwcm9ibGVtIChmb3IgbWUsIG5vdCB0aGVtKS4KCmBgYHtyIG1ha2UtbnVtYmVyc30Kc3VydmV5JFNsZWVwX2hycyA8LSByZWFkcjo6cGFyc2VfbnVtYmVyKHN1cnZleSRTbGVlcF9ocnMpCnN1cnZleQpgYGAKCkxvb2tzIGdvb2QuIExldCdzIHNhdmUgdGhhdCBjbGVhbmVkIGZpbGUgc28gd2UgZG9uJ3QgaGF2ZSB0byBkbyB0aGlzIGFnYWluLgoKYGBge3IgfQp3cml0ZV9jc3Yoc3VydmV5LCBwYXRoPSIuLi9kYXRhL3N1cnZleV9jbGVhbi5jc3YiKQpgYGAKCldlIG1heSB3YW50IHRvIG1ha2UgdGhlIGBSX2V4cGAgdmFyaWFibGUgb3JkZXJlZC4KCmBgYHtyIG1vZGlmeS1yLWV4cH0KKHN1cnZleV9yZXNwb25zZXMgPC0gdW5pcXVlKHN1cnZleSRSX2V4cCkpCmBgYAoKVGhpcyBzaG93cyB1cyB0aGUgZGlmZmVyZW50IHN1cnZleSByZXNwb25zZSB2YWx1ZXMuCgpgYGB7cn0Kc3VydmV5JFJfZXhwIDwtIG9yZGVyZWQoc3VydmV5JFJfZXhwLCBsZXZlbHM9Yygibm9uZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImxpbWl0ZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJzb21lIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibG90cyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBybyIpKQpgYGAKCiMjIFZpc3VhbGl6YXRpb24KCk5vdywgd2UgZm9sbG93IE1pa2UgTWV5ZXIncyBhZHZpY2U6ICJQbG90IHlvdXIgZGF0YSEiCgojIyMgRGVzY3JpcHRpdmUgcGxvdHMKCmBgYHtyIFItZXhwLWhpc3QsIGZpZy5jYXA9IkRpc3RyaWJ1dGlvbiBvZiBwcmlvciBSIGV4cGVyaWVuY2UifQpSX2V4cF9oaXN0IDwtIHN1cnZleSAlPiUKICBnZ3Bsb3QoKSArCiAgYWVzKHg9Ul9leHApICsKICBnZW9tX2hpc3RvZ3JhbShzdGF0ID0gImNvdW50IikgIyBSX2V4cCBpcyBkaXNjcmV0ZQpSX2V4cF9oaXN0CmBgYAoKYGBge3IgU2xlZXBfaHJzX2hpc3QsIGZpZy5jYXA9IkRpc3RyaWJ1dGlvbiBvZiBwcmVmZXJyZWQgc2xlZXAgaHJzL2RheSJ9ClNsZWVwX2hyc19oaXN0IDwtIHN1cnZleSAlPiUKICBnZ3Bsb3QoKSArCiAgYWVzKHg9U2xlZXBfaHJzKSArCiAgZ2VvbV9oaXN0b2dyYW0oKSAjIFNsZWVwX2hycyBpcyBjb250aW51b3VzClNsZWVwX2hyc19oaXN0CmBgYAoKYGBge3IsIGZpZy5jYXA9IkRpc3RyaWJ1dGlvbiBvZiBHb1QgRW50aHVzaWFzbSJ9CkdvdF9oaXN0IDwtIHN1cnZleSAlPiUKICBnZ3Bsb3QoKSArCiAgYWVzKHg9R29UKSArCiAgZ2VvbV9oaXN0b2dyYW0oKQpHb3RfaGlzdApgYGAKCi0tLQoKTG9va3MgbGlrZSB3ZSBhcmUgb2YgdHdvIG1pbmRzIGFib3V0IEdvVC4KCiFbXShodHRwczovL3N0YXRpYy5pbmRlcGVuZGVudC5jby51ay9zM2ZzLXB1YmxpYy9zdHlsZXMvYXJ0aWNsZV9zbWFsbC9wdWJsaWMvdGh1bWJuYWlscy9pbWFnZS8yMDE3LzAzLzE3LzA4L3Rocm9uZXMtZHJhZ29uLmpwZykKCkRvZXMgUiBleHBlcmllbmNlIGhhdmUgYW55IHJlbGF0aW9uIHRvIEdvVCBlbnRodXNpYXNtPwoKYGBge3IgR29ULXZzLXItZXhwfQpHb1RfdnNfcl9leHAgPC0gc3VydmV5ICU+JQogIGdncGxvdCgpICsKICBhZXMoeD1Hb1QsIHk9QWdlX3lycykgKwogIGZhY2V0X2dyaWQoLiB+IFJfZXhwKSArCiAgZ2VvbV9wb2ludCgpCiAgIyArIHN0YXRfc21vb3RoKCkKR29UX3ZzX3JfZXhwCmBgYAoKYGBge3IgdGlkeS1kYXRhLCBjYWNoZT1UUlVFfQp0aWR5X2hpc3QgPC0gc3VydmV5ICU+JQogIGdncGxvdCgpICsKICBhZXMoeD1UaWR5X2RhdGEpICsKICBnZW9tX2hpc3RvZ3JhbShzdGF0ID0gImNvdW50IikKdGlkeV9oaXN0CmBgYAoKCgojIyBBbmFseXNpcwoKSSBjb3VsZCB1c2UgYSBkb2N1bWVudCBsaWtlIHRoaXMgdG8gcGxhbiBvdXQgbXkgYW5hbHlzaXMgcGxhbiAqKmJlZm9yZSoqIEkgY29uZHVjdCBpdC4KSWYgSSB1c2VkIHNpbXVsYXRlZCBkYXRhLCBJIGNvdWxkIG1ha2Ugc3VyZSB0aGF0IG15IHdvcmtmbG93IHdpbGwgcnVuIHdoZW4gSSBnZXQgcmVhbCAoY2xlYW5lZCkgZGF0YS4KSSBjb3VsZCBldmVuIHByZXJlZ2lzdGVyIG15IGFuYWx5c2lzIHBsYW4gYmVmb3JlIEkgY29uZHVjdCBpdC4KVGhhdCBkb2Vzbid0IHByZWNsdWRlIGxhdGVyIGV4cGxvcmF0b3J5IGFuYWx5c2VzLCBidXQgaXQgZG9lcyBob2xkIG1lIGFuZCBteSBjb2xsYWJvcmF0b3JzIGFjY291bnRhYmxlIGZvciB3aGF0IEkgcHJlZGljdGVkIGluIGFkdmFuY2UuCgojIyBOb3RlcwoKTm90aWNlIHRoYXQgSSBzb21ldGltZXMgcHV0IGEgbGFiZWwgbGlrZSBgZ290LXZzLXItZXhwYCBpbiB0aGUgYnJhY2tldHMgZm9yIGEgZ2l2ZW4gJ2NodW5rJyBvZiBSIGNvZGUuIFRoZSBtYWluIHJlYXNvbnMgdG8gZG8gdGhpcyBhcmU6CgotIEl0IHNvbWV0aW1lcyBtYWtlcyBpdCBlYXNpZXIgdG8gZGVidWcgeW91ciBjb2RlLgotIEluIHNvbWUgY2FzZXMsIHlvdSBjYW4gaGF2ZSB0aGlzICdjaHVuaycgbmFtZSBzZXJ2ZSBhcyB0aGUgZmlsZSBuYW1lIGZvciBhIGZpZ3VyZSB5b3UgZ2VuZXJhdGUgd2l0aGluIGEgY2h1bmsuCi0gSW4gYSBiaXQsIHdlJ2xsIHNlZSBob3cgdGhlc2UgY2h1bmsgbmFtZXMgYXJlIHVzZWZ1bCBmb3IgbWFraW5nIHRhYmxlcywgZmlndXJlcywgYW5kIGVxdWF0aW9ucyB0aGF0IGdlbmVyYXRlIHRoZWlyIG93biBudW1iZXJzLg==