In this case study, we are going to analyse a dataset containing bodyweight measurements of mice receiving two different diets, the standard “chow” diet and a high-fat diet. We also have the gender of the mice, but we will save that variable for next case study. Our hypothesis is that the high-fat diet has an effect on the weight of the mice.

These case studies will all follow more or less the same structure:

  • Read the data into R
  • Tidy the data with tibble and dplyr
  • Plot the data with ggplot2
  • Fit models to the data

Although we don’t need to tidy this dataset.

First, we install some packages we will need, if we don’t have them installed already. The “tidyverse” package installs several packages in the “tidyverse” ecosystem, including “tibble”, “readr” and “ggplot2”.

install.packages('tidyverse')  # Installs several packages from the tidyverse ecosystem.
install.packages('magrittr')
install.packages('devtools')

Next, we load the packages we need.

library(readr)  # For reading data.
library(tibble)  # The "tibble" datastructure.
library(dplyr)  # Working with the tibble datastructure.
library(ggplot2)  # Plotting.
library(magrittr)  # Need this for the %>% (pipe) operator.
library(devtools)  # For printing the session info at the end of the notebook.

Read and pre-process data

The data we need is available on the web, so we are just going to download it directly to our working directory with an R command. The download.file() function takes an URL, downloads the file that URL points to, and saves it in the current directory with the file name we specify.

# Download CSV file into current directory.
url <- 'https://raw.githubusercontent.com/genomicsclass/dagdata/master/inst/extdata/mice_pheno.csv'
download.file(url, 'mice_pheno.csv')
trying URL 'https://raw.githubusercontent.com/genomicsclass/dagdata/master/inst/extdata/mice_pheno.csv'
Content type 'text/plain; charset=utf-8' length 10108 bytes
==================================================
downloaded 10108 bytes

We read the data from the CSV file we just downloaded. Below, we pass the relative path to the read_csv() function; in this case, the file is in our current working directory.

# Read CSV file into a tibble.
mice <- read_csv('mice_pheno.csv')

The read_csv() function reads the CSV file and stores the data in a tibble object which we name mice. The data is stored in the memory of the computer, and any changes made to data are only stored in memory. If you want to save the changes you make to the data, write the data to disk using, for example, the write_csv() function.

Below, we use the head() function to inspect the first few rows of the data. We also see the column names (such as “Sex” and “Diet”) and the data type (such as <chr> and <dbl>).

head(mice)

Because we are lazy, we are going to simplify the column names a bit, as we are going to be writing these a lot. We do this using the rename() function. Note that we could use the syntax rename(mice, "new variable name" = "old variable name"), but instead we are using the syntax mice %>% rename("new variable name" = "old variable name"), where %>% is the pipe operator from the magrittr package.

# Change column names.
mice <- mice %>% rename('sex' = 'Sex', 'diet' = 'Diet', 'weight' = 'Bodyweight')

We are not going to use all of the columns in the data, so we drop all the unused columns. We do this using the select() function, supplying the names of the columns we want to retain.

mice <- mice %>% select("diet", "weight")
Error: Unknown column `diet` 
Call `rlang::last_error()` to see a backtrace

Next, we will use the mutate() function to convert the diet variable from characters to factors. Below, we use as.factor() to convert the diet variable, and use mutate() to overwrite the existing diet variable.

# Convert the diet variable from character to factor.
mice <- mice %>% mutate(diet=as.factor(diet))

We print the head of the dataset again, just to show that changes have been made.

head(mice)

Exploratory data analysis

In this section, we will visualize the data, in order to get an overview of the data, check assumptions, and possibly pre-process the data further if necessary. For this first case study, we will make a histogram, a box plot and a QQ-plot of each of our variables.

First, however, let’s quickly look at some summary stats for the data, using the summary() function. Note that the weight variable has five NA values, meaning that there is missing data. Because the diet variable is a factor, summary() counts the occurrence of each level, which is quite useful.

summary(mice)
   diet         weight     
 chow:449   Min.   :15.51  
 hf  :397   1st Qu.:24.04  
            Median :28.19  
            Mean   :28.85  
            3rd Qu.:32.95  
            Max.   :54.08  
            NA's   :5      

A different way to count occurrences in any vector is using the table() function, and below we first pull the diet variable from the tibble, and then pass that to table().

mice %>% pull(diet) %>% table()
.
chow   hf 
 449  397 

We use ggplot2 to plot our data. The ggplot(mice, aes(weight)) statement below tells R that we want to plot the weight variable in the mice dataset. Then we further say that we want to make a histogram out of this data with 15 bins. We make a title for the plot as well. Note that we simply “add” more functionality on top of the plot with the + operator. ggplot2 will not know how to deal with the NA values, and will give us a warning if we pass it NA values. To ignore this warning we use the na.rm=TRUE argument.

ggplot(mice, aes(weight)) +
  geom_histogram(na.rm=TRUE, bins=15) +
  labs(title='Histogram of mice weights')

Actually, we aren’t interested in the distribution of mice weights in general. What we are interested in is the two populations, or groups, receiving the chow and high-fat diets. There are many ways we could split this into two plots. Below, we’ve decided to do it using the facet_grid() function, receiving a variable name with which to split the data. We will discuss the ~ operator when we get to the modelling part, later in this case study.

ggplot(mice, aes(weight)) +
  geom_histogram(na.rm=TRUE, bins=15) +
  labs(title='Histogram of mice weights') +
  facet_grid(~ diet)

geom_boxplot() will split the data according to the x variable, so there is no need to use facet_grid() below.

ggplot(mice, aes(diet, weight)) +
  geom_boxplot(na.rm=TRUE) +
  labs(title='Box plot of mice weights')

Next, we are going to make QQ-plots of our variables. The QQ-plot is a good way to check whether data is normally distributed. It computes theoretical quantiles based on summary statistics of the data and assuming it is normally distributed, and then compares these with the actual quantiles. The closer the points match the QQ-line, the more accurately the normal distribution represents the data.

Below we use stat_qq() to add the points, representing the theoretical and actual (“sample”) quantiles, and stat_qq_line() to add the QQ-line, ignoring NA values with na.rm=TRUE. Note that we pass the variable to ggplot() as aes(sample=weight) this time, as the stat_qq() and stat_qq_line() functions will look in this keyword for the data.

Note that in both groups, the lower end of the distributions veer upwards. This indicates that the lower end of the distribution is heavy tailed. Other than that, the data seems reasonably well approximated by a normal distribution.

ggplot(mice, aes(sample=weight)) +
  stat_qq(na.rm=TRUE) + stat_qq_line(na.rm=TRUE) +
  labs(title='QQ-plot of mice weights') +
  facet_grid(~ diet)

Modelling

Below, we use a t test to test the difference in the mean weight in two groups, the chow and the hf groups, specifying the mice dataset. The weight ~ diet syntax, using the ~ operator, is common in modelling in R. This is a formula relating the variable of interest (the reponse) on the left-hand-side (in this case weight) to the explanatory variables on the right-hand-side. This way of thinking about it will make more sense when we get to the linear models, in the next case study.

model <- t.test(weight ~ diet, data=mice)
model

    Welch Two Sample t-test

data:  weight by diet
t = -7.1932, df = 735.02, p-value = 1.563e-12
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -3.906857 -2.231533
sample estimates:
mean in group chow   mean in group hf 
          27.41281           30.48201 

We see that the test is highly significant. The 95% confidence interval for the difference in mean is somewhat broad if what we wanted was a precise estimate of this difference. However, if we just want to know whether there is a difference, what we can note is that the confidence interval does not include zero, not by far. So we can be quite confident that this difference is real, provided that the original experiment sampled the populations correctly.

To conclude this R notebook, we use the devtools::sessions_info() function to print information about this R session, including R version and packages loaded. This improves the reproducibility of this analysis, as without this information, package versions in particular, the code may not perform the way it is supposed to, and either produce incorrect results or not work at all. If you are asking for help when something isn’t working, whether it is from colleagues or online, this information is also very useful.

devtools::session_info()
─ Session info ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
 setting  value                       
 version  R version 3.4.4 (2018-03-15)
 os       Ubuntu 16.04.6 LTS          
 system   x86_64, linux-gnu           
 ui       RStudio                     
 language en_US                       
 collate  en_US.UTF-8                 
 ctype    en_US.UTF-8                 
 tz       Atlantic/Faroe              
 date     2019-08-25                  

─ Packages ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
 package      * version date       lib source        
 assertthat     0.2.1   2019-03-21 [1] CRAN (R 3.4.4)
 backports      1.1.4   2019-04-10 [1] CRAN (R 3.4.4)
 base64enc      0.1-3   2015-07-28 [1] CRAN (R 3.4.4)
 callr          3.3.1   2019-07-18 [1] CRAN (R 3.4.4)
 cli            1.1.0   2019-03-19 [1] CRAN (R 3.4.4)
 codetools      0.2-15  2016-10-05 [4] CRAN (R 3.3.1)
 colorspace     1.4-1   2019-03-18 [1] CRAN (R 3.4.4)
 crayon         1.3.4   2017-09-16 [1] CRAN (R 3.4.4)
 desc           1.2.0   2018-05-01 [1] CRAN (R 3.4.4)
 devtools     * 2.1.0   2019-07-06 [1] CRAN (R 3.4.4)
 digest         0.6.20  2019-07-04 [1] CRAN (R 3.4.4)
 dplyr        * 0.8.3   2019-07-04 [1] CRAN (R 3.4.4)
 evaluate       0.14    2019-05-28 [1] CRAN (R 3.4.4)
 foreach      * 1.4.7   2019-07-27 [1] CRAN (R 3.4.4)
 fs             1.3.1   2019-05-06 [1] CRAN (R 3.4.4)
 ggplot2      * 3.2.1   2019-08-10 [1] CRAN (R 3.4.4)
 glue           1.3.1   2019-03-12 [1] CRAN (R 3.4.4)
 gtable         0.3.0   2019-03-25 [1] CRAN (R 3.4.4)
 hms            0.5.1   2019-08-23 [1] CRAN (R 3.4.4)
 htmltools      0.3.6   2017-04-28 [1] CRAN (R 3.4.4)
 iterators    * 1.0.12  2019-07-26 [1] CRAN (R 3.4.4)
 itertools    * 0.1-3   2014-03-12 [1] CRAN (R 3.4.4)
 jsonlite       1.6     2018-12-07 [1] CRAN (R 3.4.4)
 knitr          1.24    2019-08-08 [1] CRAN (R 3.4.4)
 labeling       0.3     2014-08-23 [1] CRAN (R 3.4.4)
 lazyeval       0.2.2   2019-03-15 [1] CRAN (R 3.4.4)
 lubridate    * 1.7.4   2018-04-11 [1] CRAN (R 3.4.4)
 magrittr     * 1.5     2014-11-22 [1] CRAN (R 3.4.4)
 memoise        1.1.0   2017-04-21 [1] CRAN (R 3.4.4)
 missForest   * 1.4     2013-12-31 [1] CRAN (R 3.4.4)
 munsell        0.5.0   2018-06-12 [1] CRAN (R 3.4.4)
 pillar         1.4.2   2019-06-29 [1] CRAN (R 3.4.4)
 pkgbuild       1.0.4   2019-08-05 [1] CRAN (R 3.4.4)
 pkgconfig      2.0.2   2018-08-16 [1] CRAN (R 3.4.4)
 pkgload        1.0.2   2018-10-29 [1] CRAN (R 3.4.4)
 plyr           1.8.4   2016-06-08 [1] CRAN (R 3.4.4)
 prettyunits    1.0.2   2015-07-13 [1] CRAN (R 3.4.4)
 processx       3.4.1   2019-07-18 [1] CRAN (R 3.4.4)
 ps             1.3.0   2018-12-21 [1] CRAN (R 3.4.4)
 purrr          0.3.2   2019-03-15 [1] CRAN (R 3.4.4)
 R6             2.4.0   2019-02-14 [1] CRAN (R 3.4.4)
 randomForest * 4.6-14  2018-03-25 [1] CRAN (R 3.4.4)
 Rcpp           1.0.2   2019-07-25 [1] CRAN (R 3.4.4)
 readr        * 1.3.1   2018-12-21 [1] CRAN (R 3.4.4)
 remotes        2.1.0   2019-06-24 [1] CRAN (R 3.4.4)
 reshape2       1.4.3   2017-12-11 [1] CRAN (R 3.4.4)
 rlang          0.4.0   2019-06-25 [1] CRAN (R 3.4.4)
 rmarkdown      1.15    2019-08-21 [1] CRAN (R 3.4.4)
 rprojroot      1.3-2   2018-01-03 [1] CRAN (R 3.4.4)
 rstudioapi     0.10    2019-03-19 [1] CRAN (R 3.4.4)
 scales         1.0.0   2018-08-09 [1] CRAN (R 3.4.4)
 sessioninfo    1.1.1   2018-11-05 [1] CRAN (R 3.4.4)
 stringi        1.4.3   2019-03-12 [1] CRAN (R 3.4.4)
 stringr        1.4.0   2019-02-10 [1] CRAN (R 3.4.4)
 testthat       2.2.1   2019-07-25 [1] CRAN (R 3.4.4)
 tibble       * 2.1.3   2019-06-06 [1] CRAN (R 3.4.4)
 tidyselect     0.2.5   2018-10-11 [1] CRAN (R 3.4.4)
 usethis      * 1.5.1   2019-07-04 [1] CRAN (R 3.4.4)
 vctrs          0.2.0   2019-07-05 [1] CRAN (R 3.4.4)
 withr          2.1.2   2018-03-15 [1] CRAN (R 3.4.4)
 xfun           0.9     2019-08-21 [1] CRAN (R 3.4.4)
 yaml           2.2.0   2018-07-25 [1] CRAN (R 3.4.4)
 zeallot        0.1.0   2018-01-28 [1] CRAN (R 3.4.4)

[1] /home/olavur/R/x86_64-pc-linux-gnu-library/3.4
[2] /usr/local/lib/R/site-library
[3] /usr/lib/R/site-library
[4] /usr/lib/R/library
LS0tCnRpdGxlOiAiQ2FzZSAxLjEgLSBTaW1wbGUgc3RhdGlzdGljcyB3b3JrZmxvdyBpbiBSIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCi0tLQoKCkluIHRoaXMgY2FzZSBzdHVkeSwgd2UgYXJlIGdvaW5nIHRvIGFuYWx5c2UgYSBkYXRhc2V0IGNvbnRhaW5pbmcgYm9keXdlaWdodCBtZWFzdXJlbWVudHMgb2YgbWljZSByZWNlaXZpbmcgdHdvIGRpZmZlcmVudCBkaWV0cywgdGhlIHN0YW5kYXJkICJjaG93IiBkaWV0IGFuZCBhIGhpZ2gtZmF0IGRpZXQuIFdlIGFsc28gaGF2ZSB0aGUgZ2VuZGVyIG9mIHRoZSBtaWNlLCBidXQgd2Ugd2lsbCBzYXZlIHRoYXQgdmFyaWFibGUgZm9yIG5leHQgY2FzZSBzdHVkeS4gT3VyIGh5cG90aGVzaXMgaXMgdGhhdCB0aGUgaGlnaC1mYXQgZGlldCBoYXMgYW4gZWZmZWN0IG9uIHRoZSB3ZWlnaHQgb2YgdGhlIG1pY2UuCgpUaGVzZSBjYXNlIHN0dWRpZXMgd2lsbCBhbGwgZm9sbG93IG1vcmUgb3IgbGVzcyB0aGUgc2FtZSBzdHJ1Y3R1cmU6CgoqIFJlYWQgdGhlIGRhdGEgaW50byBSCiogVGlkeSB0aGUgZGF0YSB3aXRoIGB0aWJibGVgIGFuZCBgZHBseXJgCiogUGxvdCB0aGUgZGF0YSB3aXRoIGBnZ3Bsb3QyYAoqIEZpdCBtb2RlbHMgdG8gdGhlIGRhdGEKCkFsdGhvdWdoIHdlIGRvbid0IG5lZWQgdG8gdGlkeSB0aGlzIGRhdGFzZXQuCgpGaXJzdCwgd2UgaW5zdGFsbCBzb21lIHBhY2thZ2VzIHdlIHdpbGwgbmVlZCwgaWYgd2UgZG9uJ3QgaGF2ZSB0aGVtIGluc3RhbGxlZCBhbHJlYWR5LiBUaGUgInRpZHl2ZXJzZSIgcGFja2FnZSBpbnN0YWxscyBzZXZlcmFsIHBhY2thZ2VzIGluIHRoZSAidGlkeXZlcnNlIiBlY29zeXN0ZW0sIGluY2x1ZGluZyAidGliYmxlIiwgInJlYWRyIiBhbmQgImdncGxvdDIiLgoKYGBge3IgZXZhbD1GQUxTRX0KaW5zdGFsbC5wYWNrYWdlcygndGlkeXZlcnNlJykgICMgSW5zdGFsbHMgc2V2ZXJhbCBwYWNrYWdlcyBmcm9tIHRoZSB0aWR5dmVyc2UgZWNvc3lzdGVtLgppbnN0YWxsLnBhY2thZ2VzKCdtYWdyaXR0cicpCmluc3RhbGwucGFja2FnZXMoJ2RldnRvb2xzJykKYGBgCgpOZXh0LCB3ZSBsb2FkIHRoZSBwYWNrYWdlcyB3ZSBuZWVkLgoKYGBge3IgbWVzc2FnZT1GQUxTRX0KbGlicmFyeShyZWFkcikgICMgRm9yIHJlYWRpbmcgZGF0YS4KbGlicmFyeSh0aWJibGUpICAjIFRoZSAidGliYmxlIiBkYXRhc3RydWN0dXJlLgpsaWJyYXJ5KGRwbHlyKSAgIyBXb3JraW5nIHdpdGggdGhlIHRpYmJsZSBkYXRhc3RydWN0dXJlLgpsaWJyYXJ5KGdncGxvdDIpICAjIFBsb3R0aW5nLgpsaWJyYXJ5KG1hZ3JpdHRyKSAgIyBOZWVkIHRoaXMgZm9yIHRoZSAlPiUgKHBpcGUpIG9wZXJhdG9yLgpsaWJyYXJ5KGRldnRvb2xzKSAgIyBGb3IgcHJpbnRpbmcgdGhlIHNlc3Npb24gaW5mbyBhdCB0aGUgZW5kIG9mIHRoZSBub3RlYm9vay4KYGBgCgojIFJlYWQgYW5kIHByZS1wcm9jZXNzIGRhdGEKClRoZSBkYXRhIHdlIG5lZWQgaXMgYXZhaWxhYmxlIG9uIHRoZSB3ZWIsIHNvIHdlIGFyZSBqdXN0IGdvaW5nIHRvIGRvd25sb2FkIGl0IGRpcmVjdGx5IHRvIG91ciB3b3JraW5nIGRpcmVjdG9yeSB3aXRoIGFuIFIgY29tbWFuZC4gVGhlIGBkb3dubG9hZC5maWxlKClgIGZ1bmN0aW9uIHRha2VzIGFuIFVSTCwgZG93bmxvYWRzIHRoZSBmaWxlIHRoYXQgVVJMIHBvaW50cyB0bywgYW5kIHNhdmVzIGl0IGluIHRoZSBjdXJyZW50IGRpcmVjdG9yeSB3aXRoIHRoZSBmaWxlIG5hbWUgd2Ugc3BlY2lmeS4KCmBgYHtyfQojIERvd25sb2FkIENTViBmaWxlIGludG8gY3VycmVudCBkaXJlY3RvcnkuCnVybCA8LSAnaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2dlbm9taWNzY2xhc3MvZGFnZGF0YS9tYXN0ZXIvaW5zdC9leHRkYXRhL21pY2VfcGhlbm8uY3N2Jwpkb3dubG9hZC5maWxlKHVybCwgJ21pY2VfcGhlbm8uY3N2JykKYGBgCgpXZSByZWFkIHRoZSBkYXRhIGZyb20gdGhlIENTViBmaWxlIHdlIGp1c3QgZG93bmxvYWRlZC4gQmVsb3csIHdlIHBhc3MgdGhlIHJlbGF0aXZlIHBhdGggdG8gdGhlIGByZWFkX2NzdigpYCBmdW5jdGlvbjsgaW4gdGhpcyBjYXNlLCB0aGUgZmlsZSBpcyBpbiBvdXIgY3VycmVudCB3b3JraW5nIGRpcmVjdG9yeS4KCmBgYHtyIG1lc3NhZ2U9RkFMU0V9CiMgUmVhZCBDU1YgZmlsZSBpbnRvIGEgdGliYmxlLgptaWNlIDwtIHJlYWRfY3N2KCdtaWNlX3BoZW5vLmNzdicpCmBgYAoKVGhlIGByZWFkX2NzdigpYCBmdW5jdGlvbiByZWFkcyB0aGUgQ1NWIGZpbGUgYW5kIHN0b3JlcyB0aGUgZGF0YSBpbiBhIHRpYmJsZSBvYmplY3Qgd2hpY2ggd2UgbmFtZSBgbWljZWAuIFRoZSBkYXRhIGlzIHN0b3JlZCBpbiB0aGUgbWVtb3J5IG9mIHRoZSBjb21wdXRlciwgYW5kIGFueSBjaGFuZ2VzIG1hZGUgdG8gYGRhdGFgIGFyZSBvbmx5IHN0b3JlZCBpbiBtZW1vcnkuIElmIHlvdSB3YW50IHRvIHNhdmUgdGhlIGNoYW5nZXMgeW91IG1ha2UgdG8gdGhlIGRhdGEsIHdyaXRlIHRoZSBkYXRhIHRvIGRpc2sgdXNpbmcsIGZvciBleGFtcGxlLCB0aGUgYHdyaXRlX2NzdigpYCBmdW5jdGlvbi4KCkJlbG93LCB3ZSB1c2UgdGhlIGBoZWFkKClgIGZ1bmN0aW9uIHRvIGluc3BlY3QgdGhlIGZpcnN0IGZldyByb3dzIG9mIHRoZSBkYXRhLiBXZSBhbHNvIHNlZSB0aGUgY29sdW1uIG5hbWVzIChzdWNoIGFzICJTZXgiIGFuZCAiRGlldCIpIGFuZCB0aGUgZGF0YSB0eXBlIChzdWNoIGFzIGA8Y2hyPmAgYW5kIGA8ZGJsPmApLgoKYGBge3J9CmhlYWQobWljZSkKYGBgCgpCZWNhdXNlIHdlIGFyZSBsYXp5LCB3ZSBhcmUgZ29pbmcgdG8gc2ltcGxpZnkgdGhlIGNvbHVtbiBuYW1lcyBhIGJpdCwgYXMgd2UgYXJlIGdvaW5nIHRvIGJlIHdyaXRpbmcgdGhlc2UgYSBsb3QuIFdlIGRvIHRoaXMgdXNpbmcgdGhlIGByZW5hbWUoKWAgZnVuY3Rpb24uIE5vdGUgdGhhdCB3ZSBjb3VsZCB1c2UgdGhlIHN5bnRheCBgcmVuYW1lKG1pY2UsICJuZXcgdmFyaWFibGUgbmFtZSIgPSAib2xkIHZhcmlhYmxlIG5hbWUiKWAsIGJ1dCBpbnN0ZWFkIHdlIGFyZSB1c2luZyB0aGUgc3ludGF4IGBtaWNlICU+JSByZW5hbWUoIm5ldyB2YXJpYWJsZSBuYW1lIiA9ICJvbGQgdmFyaWFibGUgbmFtZSIpYCwgd2hlcmUgYCU+JWAgaXMgdGhlICpwaXBlKiBvcGVyYXRvciBmcm9tIHRoZSBgbWFncml0dHJgIHBhY2thZ2UuCgpgYGB7cn0KIyBDaGFuZ2UgY29sdW1uIG5hbWVzLgptaWNlIDwtIG1pY2UgJT4lIHJlbmFtZSgnc2V4JyA9ICdTZXgnLCAnZGlldCcgPSAnRGlldCcsICd3ZWlnaHQnID0gJ0JvZHl3ZWlnaHQnKQpgYGAKCldlIGFyZSBub3QgZ29pbmcgdG8gdXNlIGFsbCBvZiB0aGUgY29sdW1ucyBpbiB0aGUgZGF0YSwgc28gd2UgZHJvcCBhbGwgdGhlIHVudXNlZCBjb2x1bW5zLiBXZSBkbyB0aGlzIHVzaW5nIHRoZSBgc2VsZWN0KClgIGZ1bmN0aW9uLCBzdXBwbHlpbmcgdGhlIG5hbWVzIG9mIHRoZSBjb2x1bW5zIHdlIHdhbnQgdG8gcmV0YWluLiAKCmBgYHtyfQojIFN1YnNldCB0aGUgY29sdW1ucyBpbiB0aGUgZGF0YS4KbWljZSA8LSBtaWNlICU+JSBzZWxlY3QoImRpZXQiLCAid2VpZ2h0IikKYGBgCgpOZXh0LCB3ZSB3aWxsIHVzZSB0aGUgYG11dGF0ZSgpYCBmdW5jdGlvbiB0byBjb252ZXJ0IHRoZSBgZGlldGAgdmFyaWFibGUgZnJvbSBjaGFyYWN0ZXJzIHRvIGZhY3RvcnMuIEJlbG93LCB3ZSB1c2UgYGFzLmZhY3RvcigpYCB0byBjb252ZXJ0IHRoZSBgZGlldGAgdmFyaWFibGUsIGFuZCB1c2UgYG11dGF0ZSgpYCB0byBvdmVyd3JpdGUgdGhlIGV4aXN0aW5nIGBkaWV0YCB2YXJpYWJsZS4KCmBgYHtyfQojIENvbnZlcnQgdGhlIGRpZXQgdmFyaWFibGUgZnJvbSBjaGFyYWN0ZXIgdG8gZmFjdG9yLgptaWNlIDwtIG1pY2UgJT4lIG11dGF0ZShkaWV0PWFzLmZhY3RvcihkaWV0KSkKYGBgCgpXZSBwcmludCB0aGUgaGVhZCBvZiB0aGUgZGF0YXNldCBhZ2FpbiwganVzdCB0byBzaG93IHRoYXQgY2hhbmdlcyBoYXZlIGJlZW4gbWFkZS4KCmBgYHtyfQpoZWFkKG1pY2UpCmBgYAoKCiMgRXhwbG9yYXRvcnkgZGF0YSBhbmFseXNpcwoKSW4gdGhpcyBzZWN0aW9uLCB3ZSB3aWxsIHZpc3VhbGl6ZSB0aGUgZGF0YSwgaW4gb3JkZXIgdG8gZ2V0IGFuIG92ZXJ2aWV3IG9mIHRoZSBkYXRhLCBjaGVjayBhc3N1bXB0aW9ucywgYW5kIHBvc3NpYmx5IHByZS1wcm9jZXNzIHRoZSBkYXRhIGZ1cnRoZXIgaWYgbmVjZXNzYXJ5LiBGb3IgdGhpcyBmaXJzdCBjYXNlIHN0dWR5LCB3ZSB3aWxsIG1ha2UgYSBoaXN0b2dyYW0sIGEgYm94IHBsb3QgYW5kIGEgUVEtcGxvdCBvZiBlYWNoIG9mIG91ciB2YXJpYWJsZXMuCgpGaXJzdCwgaG93ZXZlciwgbGV0J3MgcXVpY2tseSBsb29rIGF0IHNvbWUgc3VtbWFyeSBzdGF0cyBmb3IgdGhlIGRhdGEsIHVzaW5nIHRoZSBgc3VtbWFyeSgpYCBmdW5jdGlvbi4gTm90ZSB0aGF0IHRoZSBgd2VpZ2h0YCB2YXJpYWJsZSBoYXMgZml2ZSBgTkFgIHZhbHVlcywgbWVhbmluZyB0aGF0IHRoZXJlIGlzIG1pc3NpbmcgZGF0YS4gQmVjYXVzZSB0aGUgYGRpZXRgIHZhcmlhYmxlIGlzIGEgZmFjdG9yLCBgc3VtbWFyeSgpYCBjb3VudHMgdGhlIG9jY3VycmVuY2Ugb2YgZWFjaCBsZXZlbCwgd2hpY2ggaXMgcXVpdGUgdXNlZnVsLgoKYGBge3J9CnN1bW1hcnkobWljZSkKYGBgCgpBIGRpZmZlcmVudCB3YXkgdG8gY291bnQgb2NjdXJyZW5jZXMgaW4gYW55IHZlY3RvciBpcyB1c2luZyB0aGUgYHRhYmxlKClgIGZ1bmN0aW9uLCBhbmQgYmVsb3cgd2UgZmlyc3QgKnB1bGwqIHRoZSBgZGlldGAgdmFyaWFibGUgZnJvbSB0aGUgdGliYmxlLCBhbmQgdGhlbiBwYXNzIHRoYXQgdG8gYHRhYmxlKClgLgoKYGBge3J9Cm1pY2UgJT4lIHB1bGwoZGlldCkgJT4lIHRhYmxlKCkKYGBgCgoKV2UgdXNlIGBnZ3Bsb3QyYCB0byBwbG90IG91ciBkYXRhLiBUaGUgYGdncGxvdChtaWNlLCBhZXMod2VpZ2h0KSlgIHN0YXRlbWVudCBiZWxvdyB0ZWxscyBSIHRoYXQgd2Ugd2FudCB0byBwbG90IHRoZSBgd2VpZ2h0YCB2YXJpYWJsZSBpbiB0aGUgYG1pY2VgIGRhdGFzZXQuIFRoZW4gd2UgZnVydGhlciBzYXkgdGhhdCB3ZSB3YW50IHRvIG1ha2UgYSBoaXN0b2dyYW0gb3V0IG9mIHRoaXMgZGF0YSB3aXRoIDE1IGJpbnMuIFdlIG1ha2UgYSB0aXRsZSBmb3IgdGhlIHBsb3QgYXMgd2VsbC4gTm90ZSB0aGF0IHdlIHNpbXBseSAiYWRkIiBtb3JlIGZ1bmN0aW9uYWxpdHkgb24gdG9wIG9mIHRoZSBwbG90IHdpdGggdGhlIGArYCBvcGVyYXRvci4gYGdncGxvdDJgIHdpbGwgbm90IGtub3cgaG93IHRvIGRlYWwgd2l0aCB0aGUgTkEgdmFsdWVzLCBhbmQgd2lsbCBnaXZlIHVzIGEgd2FybmluZyBpZiB3ZSBwYXNzIGl0IE5BIHZhbHVlcy4gVG8gaWdub3JlIHRoaXMgd2FybmluZyB3ZSB1c2UgdGhlIGBuYS5ybT1UUlVFYCBhcmd1bWVudC4KCmBgYHtyIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD01fQpnZ3Bsb3QobWljZSwgYWVzKHdlaWdodCkpICsKICBnZW9tX2hpc3RvZ3JhbShuYS5ybT1UUlVFLCBiaW5zPTE1KSArCiAgbGFicyh0aXRsZT0nSGlzdG9ncmFtIG9mIG1pY2Ugd2VpZ2h0cycpCmBgYAoKQWN0dWFsbHksIHdlIGFyZW4ndCBpbnRlcmVzdGVkIGluIHRoZSBkaXN0cmlidXRpb24gb2YgbWljZSB3ZWlnaHRzIGluIGdlbmVyYWwuIFdoYXQgd2UgYXJlIGludGVyZXN0ZWQgaW4gaXMgdGhlIHR3byBwb3B1bGF0aW9ucywgb3IgZ3JvdXBzLCByZWNlaXZpbmcgdGhlIGNob3cgYW5kIGhpZ2gtZmF0IGRpZXRzLiBUaGVyZSBhcmUgbWFueSB3YXlzIHdlIGNvdWxkIHNwbGl0IHRoaXMgaW50byB0d28gcGxvdHMuIEJlbG93LCB3ZSd2ZSBkZWNpZGVkIHRvIGRvIGl0IHVzaW5nIHRoZSBgZmFjZXRfZ3JpZCgpYCBmdW5jdGlvbiwgcmVjZWl2aW5nIGEgdmFyaWFibGUgbmFtZSB3aXRoIHdoaWNoIHRvIHNwbGl0IHRoZSBkYXRhLiBXZSB3aWxsIGRpc2N1c3MgdGhlIGB+YCBvcGVyYXRvciB3aGVuIHdlIGdldCB0byB0aGUgbW9kZWxsaW5nIHBhcnQsIGxhdGVyIGluIHRoaXMgY2FzZSBzdHVkeS4KCmBgYHtyIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD01fQpnZ3Bsb3QobWljZSwgYWVzKHdlaWdodCkpICsKICBnZW9tX2hpc3RvZ3JhbShuYS5ybT1UUlVFLCBiaW5zPTE1KSArCiAgbGFicyh0aXRsZT0nSGlzdG9ncmFtIG9mIG1pY2Ugd2VpZ2h0cycpICsKICBmYWNldF9ncmlkKH4gZGlldCkKYGBgCgpgZ2VvbV9ib3hwbG90KClgIHdpbGwgc3BsaXQgdGhlIGRhdGEgYWNjb3JkaW5nIHRvIHRoZSBgeGAgdmFyaWFibGUsIHNvIHRoZXJlIGlzIG5vIG5lZWQgdG8gdXNlIGBmYWNldF9ncmlkKClgIGJlbG93LgoKYGBge3IgZmlnLndpZHRoPTUsIGZpZy5oZWlnaHQ9NX0KZ2dwbG90KG1pY2UsIGFlcyhkaWV0LCB3ZWlnaHQpKSArCiAgZ2VvbV9ib3hwbG90KG5hLnJtPVRSVUUpICsKICBsYWJzKHRpdGxlPSdCb3ggcGxvdCBvZiBtaWNlIHdlaWdodHMnKQpgYGAKCk5leHQsIHdlIGFyZSBnb2luZyB0byBtYWtlIFFRLXBsb3RzIG9mIG91ciB2YXJpYWJsZXMuIFRoZSBRUS1wbG90IGlzIGEgZ29vZCB3YXkgdG8gY2hlY2sgd2hldGhlciBkYXRhIGlzIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLiBJdCBjb21wdXRlcyB0aGVvcmV0aWNhbCBxdWFudGlsZXMgYmFzZWQgb24gc3VtbWFyeSBzdGF0aXN0aWNzIG9mIHRoZSBkYXRhIGFuZCBhc3N1bWluZyBpdCBpcyBub3JtYWxseSBkaXN0cmlidXRlZCwgYW5kIHRoZW4gY29tcGFyZXMgdGhlc2Ugd2l0aCB0aGUgYWN0dWFsIHF1YW50aWxlcy4gVGhlIGNsb3NlciB0aGUgcG9pbnRzIG1hdGNoIHRoZSBRUS1saW5lLCB0aGUgbW9yZSBhY2N1cmF0ZWx5IHRoZSBub3JtYWwgZGlzdHJpYnV0aW9uIHJlcHJlc2VudHMgdGhlIGRhdGEuCgpCZWxvdyB3ZSB1c2UgYHN0YXRfcXEoKWAgdG8gYWRkIHRoZSBwb2ludHMsIHJlcHJlc2VudGluZyB0aGUgdGhlb3JldGljYWwgYW5kIGFjdHVhbCAoInNhbXBsZSIpIHF1YW50aWxlcywgYW5kIGBzdGF0X3FxX2xpbmUoKWAgdG8gYWRkIHRoZSBRUS1saW5lLCBpZ25vcmluZyBOQSB2YWx1ZXMgd2l0aCBgbmEucm09VFJVRWAuIE5vdGUgdGhhdCB3ZSBwYXNzIHRoZSB2YXJpYWJsZSB0byBgZ2dwbG90KClgIGFzIGBhZXMoc2FtcGxlPXdlaWdodClgIHRoaXMgdGltZSwgYXMgdGhlIGBzdGF0X3FxKClgIGFuZCBgc3RhdF9xcV9saW5lKClgIGZ1bmN0aW9ucyB3aWxsIGxvb2sgaW4gdGhpcyBrZXl3b3JkIGZvciB0aGUgZGF0YS4KCk5vdGUgdGhhdCBpbiBib3RoIGdyb3VwcywgdGhlIGxvd2VyIGVuZCBvZiB0aGUgZGlzdHJpYnV0aW9ucyB2ZWVyIHVwd2FyZHMuIFRoaXMgaW5kaWNhdGVzIHRoYXQgdGhlIGxvd2VyIGVuZCBvZiB0aGUgZGlzdHJpYnV0aW9uIGlzIGhlYXZ5IHRhaWxlZC4gT3RoZXIgdGhhbiB0aGF0LCB0aGUgZGF0YSBzZWVtcyByZWFzb25hYmx5IHdlbGwgYXBwcm94aW1hdGVkIGJ5IGEgbm9ybWFsIGRpc3RyaWJ1dGlvbi4KCmBgYHtyIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD01fQpnZ3Bsb3QobWljZSwgYWVzKHNhbXBsZT13ZWlnaHQpKSArCiAgc3RhdF9xcShuYS5ybT1UUlVFKSArIHN0YXRfcXFfbGluZShuYS5ybT1UUlVFKSArCiAgbGFicyh0aXRsZT0nUVEtcGxvdCBvZiBtaWNlIHdlaWdodHMnKSArCiAgZmFjZXRfZ3JpZCh+IGRpZXQpCmBgYAoKCiMgTW9kZWxsaW5nCgpCZWxvdywgd2UgdXNlIGEgdCB0ZXN0IHRvIHRlc3QgdGhlIGRpZmZlcmVuY2UgaW4gdGhlIG1lYW4gYHdlaWdodGAgaW4gdHdvIGdyb3VwcywgdGhlIGBjaG93YCBhbmQgdGhlIGBoZmAgZ3JvdXBzLCBzcGVjaWZ5aW5nIHRoZSBgbWljZWAgZGF0YXNldC4gVGhlIGB3ZWlnaHQgfiBkaWV0YCBzeW50YXgsIHVzaW5nIHRoZSBgfmAgb3BlcmF0b3IsIGlzIGNvbW1vbiBpbiBtb2RlbGxpbmcgaW4gUi4gVGhpcyBpcyBhIGZvcm11bGEgcmVsYXRpbmcgdGhlIHZhcmlhYmxlIG9mIGludGVyZXN0ICh0aGUgcmVwb25zZSkgb24gdGhlIGxlZnQtaGFuZC1zaWRlIChpbiB0aGlzIGNhc2UgYHdlaWdodGApIHRvIHRoZSBleHBsYW5hdG9yeSB2YXJpYWJsZXMgb24gdGhlIHJpZ2h0LWhhbmQtc2lkZS4gVGhpcyB3YXkgb2YgdGhpbmtpbmcgYWJvdXQgaXQgd2lsbCBtYWtlIG1vcmUgc2Vuc2Ugd2hlbiB3ZSBnZXQgdG8gdGhlIGxpbmVhciBtb2RlbHMsIGluIHRoZSBuZXh0IGNhc2Ugc3R1ZHkuCgpgYGB7cn0KbW9kZWwgPC0gdC50ZXN0KHdlaWdodCB+IGRpZXQsIGRhdGE9bWljZSkKbW9kZWwKYGBgCgpXZSBzZWUgdGhhdCB0aGUgdGVzdCBpcyBoaWdobHkgc2lnbmlmaWNhbnQuIFRoZSA5NSUgY29uZmlkZW5jZSBpbnRlcnZhbCBmb3IgdGhlIGRpZmZlcmVuY2UgaW4gbWVhbiBpcyBzb21ld2hhdCBicm9hZCBpZiB3aGF0IHdlIHdhbnRlZCB3YXMgYSBwcmVjaXNlIGVzdGltYXRlIG9mIHRoaXMgZGlmZmVyZW5jZS4gSG93ZXZlciwgaWYgd2UganVzdCB3YW50IHRvIGtub3cgd2hldGhlciB0aGVyZSAqaXMqIGEgZGlmZmVyZW5jZSwgd2hhdCB3ZSBjYW4gbm90ZSBpcyB0aGF0IHRoZSBjb25maWRlbmNlIGludGVydmFsIGRvZXMgbm90IGluY2x1ZGUgemVybywgbm90IGJ5IGZhci4gU28gd2UgY2FuIGJlIHF1aXRlIGNvbmZpZGVudCB0aGF0IHRoaXMgZGlmZmVyZW5jZSBpcyByZWFsLCBwcm92aWRlZCB0aGF0IHRoZSBvcmlnaW5hbCBleHBlcmltZW50IHNhbXBsZWQgdGhlIHBvcHVsYXRpb25zIGNvcnJlY3RseS4KCgpUbyBjb25jbHVkZSB0aGlzIFIgbm90ZWJvb2ssIHdlIHVzZSB0aGUgYGRldnRvb2xzOjpzZXNzaW9uc19pbmZvKClgIGZ1bmN0aW9uIHRvIHByaW50IGluZm9ybWF0aW9uIGFib3V0IHRoaXMgUiBzZXNzaW9uLCBpbmNsdWRpbmcgUiB2ZXJzaW9uIGFuZCBwYWNrYWdlcyBsb2FkZWQuIFRoaXMgaW1wcm92ZXMgdGhlIHJlcHJvZHVjaWJpbGl0eSBvZiB0aGlzIGFuYWx5c2lzLCBhcyB3aXRob3V0IHRoaXMgaW5mb3JtYXRpb24sIHBhY2thZ2UgdmVyc2lvbnMgaW4gcGFydGljdWxhciwgdGhlIGNvZGUgbWF5IG5vdCBwZXJmb3JtIHRoZSB3YXkgaXQgaXMgc3VwcG9zZWQgdG8sIGFuZCBlaXRoZXIgcHJvZHVjZSBpbmNvcnJlY3QgcmVzdWx0cyBvciBub3Qgd29yayBhdCBhbGwuIElmIHlvdSBhcmUgYXNraW5nIGZvciBoZWxwIHdoZW4gc29tZXRoaW5nIGlzbid0IHdvcmtpbmcsIHdoZXRoZXIgaXQgaXMgZnJvbSBjb2xsZWFndWVzIG9yIG9ubGluZSwgdGhpcyBpbmZvcm1hdGlvbiBpcyBhbHNvIHZlcnkgdXNlZnVsLgoKYGBge3J9CmRldnRvb2xzOjpzZXNzaW9uX2luZm8oKQpgYGAKCg==