The ggplot2 package is based on the principle that all plots consist of a few basic components: data, a coordinate system and a visual representation of the data. In ggplot2, you built plots incrementally, starting with the data and coordinates you want to use and then specifying the graphical features: lines, points, bars, color, etc.

We will be using three datasets in this tutorial. First is our main dataset on phage host interaction, second is the diamond dataset given by the ggplot package, lastly is the carbon dioxide dataset given by R.

For a list of preconfigured datasets, simply type data().

data()
dataset <- read.delim("phages.tsv")

Base R Plotting

Before we begin, load the ggplot2 package for R. ggplot2 is a graphics package that provides powerful plotting capabilities beyond R’s base plotting functions. We won’t actually get into ggplot2 itself quite yet. This will be a basic introduction to plotting in R.

library(ggplot2)
dataset

Histograms

A histogram is a univariate plot (a plot that displays one variable) that groups a numeric variable into bins and displays the number of observations that fall within each bin. A histogram is a useful tool for getting a sense of the distribution of a numeric variable.

hist(dataset$Positive.Strand....)

Note: When you create a plot in a local RStudio environment, it will appear in the bottom right pane under the “plots” tab. Use the left and right arrows to cycle through the plots you’ve created.

Box Plots

Boxplots are another type of univariate plot for summarizing distributions of numeric data graphically.

boxplot(dataset$molGC...)

The central box of the boxplot represents the middle 50% of the observations, the central bar is the median and the bars at the end of the dotted lines encapsulate the great majority of the observations. Circles that lie beyond the end of the whiskers are data points that may be outliers.

One of the most useful features of the boxplot() function is the ability to make side-by-side boxplots. A side-by-side boxplot takes a numeric variable and splits it on based on some categorical variable, drawing a different boxplot for each level of the categorical variable.

boxplot(dataset$molGC... ~ dataset$Molecule) # Plot GC content split based on molecular type

Density Plots

A density plot shows the distribution of a numeric variable with a continuous curve. It is similar to a histogram but without discrete bins, a density plot gives a better picture of the underlying shape of a distribution.

plot(density(dataset$molGC...))

Bar Plots

Barplots are graphs that visually display counts of categorical variables.

dataset$Jumbophage <- ifelse(dataset$Jumbophage, "Jumbophage", "Not Jumbophage")
dataset$Jumbophage
   [1] "Jumbophage"     "Jumbophage"     "Jumbophage"     "Jumbophage"     "Jumbophage"     "Jumbophage"     "Jumbophage"     "Jumbophage"     "Jumbophage"    
  [10] "Jumbophage"     "Jumbophage"     "Jumbophage"     "Jumbophage"     "Jumbophage"     "Jumbophage"     "Jumbophage"     "Jumbophage"     "Jumbophage"    
  [19] "Jumbophage"     "Jumbophage"     "Jumbophage"     "Jumbophage"     "Jumbophage"     "Jumbophage"     "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
  [28] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
  [37] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
  [46] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
  [55] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
  [64] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
  [73] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
  [82] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
  [91] "Not Jumbophage" "Jumbophage"     "Not Jumbophage" "Jumbophage"     "Jumbophage"     "Jumbophage"     "Jumbophage"     "Jumbophage"     "Not Jumbophage"
 [100] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [109] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [118] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [127] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [136] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [145] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [154] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [163] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [172] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [181] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [190] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [199] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [208] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [217] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [226] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [235] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [244] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [253] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [262] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [271] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [280] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [289] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [298] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [307] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [316] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [325] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [334] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [343] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [352] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [361] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [370] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [379] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [388] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [397] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [406] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [415] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [424] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [433] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [442] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [451] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [460] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [469] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [478] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [487] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [496] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [505] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [514] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Jumbophage"    
 [523] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [532] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [541] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [550] "Jumbophage"     "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [559] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [568] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [577] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [586] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [595] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [604] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [613] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [622] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [631] "Jumbophage"     "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [640] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [649] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [658] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Jumbophage"     "Not Jumbophage"
 [667] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [676] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [685] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [694] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [703] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Jumbophage"     "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [712] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [721] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [730] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Jumbophage"     "Jumbophage"     "Jumbophage"     "Jumbophage"     "Jumbophage"     "Not Jumbophage"
 [739] "Jumbophage"     "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [748] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [757] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [766] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [775] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [784] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [793] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [802] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [811] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [820] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [829] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [838] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [847] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [856] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [865] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Jumbophage"     "Jumbophage"     "Jumbophage"     "Jumbophage"     "Not Jumbophage" "Not Jumbophage"
 [874] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Jumbophage"     "Jumbophage"     "Not Jumbophage" "Not Jumbophage"
 [883] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [892] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [901] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [910] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [919] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Jumbophage"     "Not Jumbophage" "Jumbophage"    
 [928] "Not Jumbophage" "Jumbophage"     "Jumbophage"     "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [937] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [946] "Not Jumbophage" "Jumbophage"     "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [955] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Jumbophage"     "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [964] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [973] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [982] "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
 [991] "Not Jumbophage" "Jumbophage"     "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage" "Not Jumbophage"
[1000] "Not Jumbophage"
 [ reached getOption("max.print") -- omitted 17406 entries ]
barplot(table(dataset$Molecule))

barplot(table(dataset$Jumbophage, dataset$Molecule),
        legend = levels(dataset$Jumbophage)
)

A grouped barplot is an alternative to a stacked barplot that gives each stacked section its own bar. To make a grouped barplot, create a stacked barplot and add the extra argument beside = TRUE.

barplot(table(dataset$Jumbophage, dataset$Molecule),
        legend = levels(dataset$Jumbophage),
        beside = TRUE
) # Group instead of stacking

Scatterplots

Scatterplots are bivariate (two variable) plots that take two numeric variables and plot data points on the x/y plane.

plot(dataset$molGC..., dataset$Positive.Strand....)

plot(dataset$molGC...,
        dataset$Positive.Strand....,
        col = rgb(red = 0, green = 0, blue = 0, alpha = 0.1)
)

Illustrating how we can make our different plots look more presentable.

barplot(table(dataset$Jumbophage, dataset$Molecule),
        legend = levels(dataset$Jumbophage),
        beside = TRUE,
        xlab = "Molecular Type",
        ylab = "Jumbophage",
        main = "Molecular Type, Grouped by Jumbophage",
        col = c(
                "#FFFFFF", "#F5FCC2", "#E0ED87", "#CCDE57", # Add color*
                "#B3C732", "#94A813", "#718200"
        )
)

Using ggplot()

The ggplot() function creates plots incrementally in layers. Every ggplot starts with the same basic syntax. Every ggplot starts with a call to the ggplot() function along with an argument specifying the data set to be used and aesthetic mappings from variables in the data set to visual properties of the plot, such as x and y position.

# install.packages("tidyverse")
library(tidyverse)

We are not going to spend much time learning about qplot() since learning the ggplot() syntax is at the heart of the package. Let’s look at one qplot for illustrative purposes and then move on.

library(ggplot2)

qplot(
        x = carat, # x variable
        y = price, # y variable
        data = diamonds, # Data set
        geom = "point", # Plot type
        color = clarity, # Color points by variable clarity
        xlab = "Carat Weight", # x label
        ylab = "Price", # y label
        main = "Diamond Carat vs. Price"
)
Warning: `qplot()` was deprecated in ggplot2 3.4.0.

# Title
ggplot(
        dataset,
        aes(Accession, molGC....)
) +
        geom_point()

In the code above, we specify the data we want to work with and then assign the variables of interest, Accession and GC Content, to the x and y values of the plot. “aes()” is an aesthetics wrapper used in ggplot to map variables to visual properties. When you want a visual property to change based on the value of a variable, that specification belongs inside an aes() wrapper. If you are setting a fixed value that doesn’t change based a variable, it belongs outside of aes().

Note: Add a new element to a plot by putting a “+” after the preceding element.

The layers you add determine the type of plot you create. In this case, we used geom_point() which simply draws the data as points at the specified x and y coordinates, creating a scatterplot. ggplot2 has a wide range of geoms to create different types of plots. Here is a list of geoms for all the plot types we covered in the last lesson, plus a few more

geom_histogram() # histogram
geom_bar: na.rm = FALSE, orientation = NA
stat_bin: binwidth = NULL, bins = NULL, na.rm = FALSE, orientation = NA, pad = FALSE
position_stack 
geom_density() # density plot
geom_density: na.rm = FALSE, orientation = NA, outline.type = upper
stat_density: na.rm = FALSE, orientation = NA
position_identity 
geom_boxplot() # boxplot
geom_boxplot: outliers = TRUE, outlier.colour = NULL, outlier.fill = NULL, outlier.shape = 19, outlier.size = 1.5, outlier.stroke = 0.5, outlier.alpha = NULL, notch = FALSE, notchwidth = 0.5, staplewidth = 0, varwidth = FALSE, na.rm = FALSE, orientation = NA
stat_boxplot: na.rm = FALSE, orientation = NA
position_dodge2 
geom_violin() # violin plot (combination of boxplot and density plot)
geom_violin: draw_quantiles = NULL, na.rm = FALSE, orientation = NA
stat_ydensity: trim = TRUE, scale = area, na.rm = FALSE, orientation = NA, bounds = c(-Inf, Inf)
position_dodge 
geom_bar() # bar graph
geom_bar: just = 0.5, width = NULL, na.rm = FALSE, orientation = NA
stat_count: width = NULL, na.rm = FALSE, orientation = NA
position_stack 
geom_point() # scatterplot
geom_point: na.rm = FALSE
stat_identity: na.rm = FALSE
position_identity 
geom_jitter() # scatterplot with points randomly perturbed to reduce overlap
geom_point: na.rm = FALSE
stat_identity: na.rm = FALSE
position_jitter 
geom_line() # line graph
geom_line: na.rm = FALSE, orientation = NA
stat_identity: na.rm = FALSE
position_identity 
geom_errorbar() # Add error bar
geom_errorbar: na.rm = FALSE, orientation = NA
stat_identity: na.rm = FALSE
position_identity 
geom_smooth() # Add a best-fit line
geom_smooth: na.rm = FALSE, orientation = NA, se = TRUE
stat_smooth: na.rm = FALSE, orientation = NA, se = TRUE
position_identity 
geom_abline() # Add a line with specified slope and intercept
mapping: intercept = ~intercept, slope = ~slope 
geom_abline: na.rm = FALSE
stat_identity: na.rm = FALSE
position_identity 

Notice the scatterplot we made above didn’t have a nice coloring. We can attribute the colors of the points to its Molecular type.

ggplot(dataset, aes(Accession, molGC...., colour = Molecule)) +
        geom_point(alpha = 0.5)

ggplot(dataset, aes(Accession, molGC....)) +
        geom_point(aes(color = Molecule), alpha = 0.2)

We pass alpha in as an argument outside of the aes() mapping because we are setting alpha to a fixed value instead of mapping it to a variable.

By setting alpha to 0.1, each data point has 90% transparency. At such high transparency, single data points are hard to see, but it lets us focus on high density areas.

dataset %>%
        ggplot(aes(Genome.Length..bp., molGC....)) +
        geom_point(aes(colour = Molecule), alpha = 0.5) +
        labs(x = "Genome Length", y = "GC Content")

Geosmooth

Illustrating the use of geosmooth using a built in dataset in R.

In ggplot2, the geom_smooth() function is used to add a smooth line or curve to a plot. It is commonly used to visualize the trend or relationship between variables.

sample_DataSet <- CO2
sample_DataSet
Grouped Data: uptake ~ conc | Plant
   Plant        Type  Treatment conc uptake
1    Qn1      Quebec nonchilled   95   16.0
2    Qn1      Quebec nonchilled  175   30.4
3    Qn1      Quebec nonchilled  250   34.8
4    Qn1      Quebec nonchilled  350   37.2
5    Qn1      Quebec nonchilled  500   35.3
6    Qn1      Quebec nonchilled  675   39.2
7    Qn1      Quebec nonchilled 1000   39.7
8    Qn2      Quebec nonchilled   95   13.6
9    Qn2      Quebec nonchilled  175   27.3
10   Qn2      Quebec nonchilled  250   37.1
11   Qn2      Quebec nonchilled  350   41.8
12   Qn2      Quebec nonchilled  500   40.6
13   Qn2      Quebec nonchilled  675   41.4
14   Qn2      Quebec nonchilled 1000   44.3
15   Qn3      Quebec nonchilled   95   16.2
16   Qn3      Quebec nonchilled  175   32.4
17   Qn3      Quebec nonchilled  250   40.3
18   Qn3      Quebec nonchilled  350   42.1
19   Qn3      Quebec nonchilled  500   42.9
20   Qn3      Quebec nonchilled  675   43.9
21   Qn3      Quebec nonchilled 1000   45.5
22   Qc1      Quebec    chilled   95   14.2
23   Qc1      Quebec    chilled  175   24.1
24   Qc1      Quebec    chilled  250   30.3
25   Qc1      Quebec    chilled  350   34.6
26   Qc1      Quebec    chilled  500   32.5
27   Qc1      Quebec    chilled  675   35.4
28   Qc1      Quebec    chilled 1000   38.7
29   Qc2      Quebec    chilled   95    9.3
30   Qc2      Quebec    chilled  175   27.3
31   Qc2      Quebec    chilled  250   35.0
32   Qc2      Quebec    chilled  350   38.8
33   Qc2      Quebec    chilled  500   38.6
34   Qc2      Quebec    chilled  675   37.5
35   Qc2      Quebec    chilled 1000   42.4
36   Qc3      Quebec    chilled   95   15.1
37   Qc3      Quebec    chilled  175   21.0
38   Qc3      Quebec    chilled  250   38.1
39   Qc3      Quebec    chilled  350   34.0
40   Qc3      Quebec    chilled  500   38.9
41   Qc3      Quebec    chilled  675   39.6
42   Qc3      Quebec    chilled 1000   41.4
43   Mn1 Mississippi nonchilled   95   10.6
44   Mn1 Mississippi nonchilled  175   19.2
45   Mn1 Mississippi nonchilled  250   26.2
46   Mn1 Mississippi nonchilled  350   30.0
47   Mn1 Mississippi nonchilled  500   30.9
48   Mn1 Mississippi nonchilled  675   32.4
49   Mn1 Mississippi nonchilled 1000   35.5
50   Mn2 Mississippi nonchilled   95   12.0
51   Mn2 Mississippi nonchilled  175   22.0
52   Mn2 Mississippi nonchilled  250   30.6
53   Mn2 Mississippi nonchilled  350   31.8
54   Mn2 Mississippi nonchilled  500   32.4
55   Mn2 Mississippi nonchilled  675   31.1
56   Mn2 Mississippi nonchilled 1000   31.5
57   Mn3 Mississippi nonchilled   95   11.3
58   Mn3 Mississippi nonchilled  175   19.4
59   Mn3 Mississippi nonchilled  250   25.8
60   Mn3 Mississippi nonchilled  350   27.9
61   Mn3 Mississippi nonchilled  500   28.5
62   Mn3 Mississippi nonchilled  675   28.1
63   Mn3 Mississippi nonchilled 1000   27.8
64   Mc1 Mississippi    chilled   95   10.5
65   Mc1 Mississippi    chilled  175   14.9
66   Mc1 Mississippi    chilled  250   18.1
67   Mc1 Mississippi    chilled  350   18.9
68   Mc1 Mississippi    chilled  500   19.5
69   Mc1 Mississippi    chilled  675   22.2
70   Mc1 Mississippi    chilled 1000   21.9
71   Mc2 Mississippi    chilled   95    7.7
72   Mc2 Mississippi    chilled  175   11.4
73   Mc2 Mississippi    chilled  250   12.3
74   Mc2 Mississippi    chilled  350   13.0
75   Mc2 Mississippi    chilled  500   12.5
76   Mc2 Mississippi    chilled  675   13.7
77   Mc2 Mississippi    chilled 1000   14.4
78   Mc3 Mississippi    chilled   95   10.6
79   Mc3 Mississippi    chilled  175   18.0
80   Mc3 Mississippi    chilled  250   17.9
81   Mc3 Mississippi    chilled  350   17.9
82   Mc3 Mississippi    chilled  500   17.9
83   Mc3 Mississippi    chilled  675   18.9
84   Mc3 Mississippi    chilled 1000   19.9
ggplot(sample_DataSet, aes(conc, uptake, colour = Treatment)) +
        geom_point(size = 3, alpha = 0.5) +
        geom_smooth(method = lm, se = F)

If you want to classify it further into types based on your data, use facet_wrap().

ggplot(sample_DataSet, aes(conc, uptake, colour = Treatment)) +
        geom_point(size = 3, alpha = 0.5) +
        geom_smooth(method = lm, se = F) +
        facet_wrap(~Type) +
        labs(title = "Concentration of CO2") +
        theme_bw()

More Plot Examples

Now that we know the basics of creating plots with ggplot(), let’s remake some of the plots we created last time and see how they look in ggplot2, starting with a histogram.

Histograms

ggplot(data = dataset, aes(x = molGC....)) +
        geom_histogram(
                fill = "skyblue",
                col = "black"
        ) +
        labs(x = "GC Content")

Box Plots

ggplot(dataset, aes(Molecule, Genome.Length..bp.)) +
        geom_jitter(
                alpha = 0.05, # Add jittered data points
                color = "yellow"
        ) +
        geom_boxplot() +
        labs(
                title = "Genome Length of Different Molecular Types",
                y = "Genome Length"
        )

Density Plot

ggplot(data = dataset, aes(x = molGC....)) +
        geom_density(
                position = "stack", # Create a stacked density chart
                aes(fill = Molecule), # Fill based on cut
                alpha = 0.5
        ) # Set transparency

Multidimensional Plotting and Faceting

One of the most powerful aspects of plots is the ability to visually illustrate relationships between 3 or more variables. When we create a plot, each different dimension (variable) needs to map to a different perceptual feature (aesthetic) such as x position, y position, symbol, size or color. Making use of several of these aesthetics at once lets us make plots involving many dimensions. We’ve already seen some examples of multidimensional plots, such as the first scatterplot in this lesson that displayed carat weight and price colored by clarity.

Faceting is another way to add an extra dimension to a plot. Faceting breaks a plot up based on a factor variable and draws a different plot for each level of the factor. You can create a faceted plot in ggplot2 by adding a facet_wrap() layer.

ggplot(data = diamonds, aes(x = carat, y = price)) + # Initialize plot

        geom_point(aes(color = color), # Color based on diamond color
                alpha = 0.5
        ) +
        facet_wrap(~clarity) + # Facet on clarity

        geom_smooth() + # Add an estimated fit line*

        theme(legend.position = c(0.85, 0.16)) # Set legend position

Scales

Scales are parameters in ggplot2 that determine how a plot maps values to visual properties (aesthetics.). If you don’t specify a scale for an aesthetic the plot will use a default scale. For instance, the plots we split on color all used a default color scale. You can specify custom scales by adding scale elements to your plot. Scale elements have the following structure:

scale_aesthetic_scaletype()

We already saw an example of a scale when made the grouped barplot above. In that case we wanted to manually set the fill color scale for the bars, so the scale we used was:

scale_fill_manual()

Let’s make a new scatterplot with several aesthetic properties and alter some of the scales.

ggplot(data = diamonds, aes(x = carat, y = price)) + # Initialize plot

        geom_point(aes(
                size = carat, # Size points based on carat
                color = color, # Color based on diamond color
                alpha = clarity
        )) + # Set transparency based on clarity

        scale_color_manual(values = c(
                "#FFFFFF", "#F5FCC2", # Use manual color values
                "#E0ED87", "#CCDE57",
                "#B3C732", "#94A813",
                "#718200"
        )) +
        scale_alpha_manual(values = c(
                0.1, 0.15, 0.2, # Use manual alpha values
                0.3, 0.4, 0.6,
                0.8, 1
        )) +
        scale_size_identity() + # Set size values to the actual values of carat*

        xlim(0, 2.5) + # Limit x-axis

        theme(panel.background = element_rect(fill = "#7FB2B8")) + # Change background color

        theme(legend.key = element_rect(fill = "#7FB2B8")) # Change legend background color


  1. De La Salle University, Manila, Philippines, ↩︎

LS0tDQp0aXRsZTogIkZ1bmRhbWVudGFscyBvZiBEYXRhIFZpc3VhbGl6YXRpb24gd2l0aCBgZ2dwbG90MmAiDQphdXRob3I6IERhcGhuZSBKYW5lbHluIEwuIEdvXltEZSBMYSBTYWxsZSBVbml2ZXJzaXR5LCBNYW5pbGEsIFBoaWxpcHBpbmVzLCBkYXBobmVfamFuZWx5bl9nb0BkbHN1LmVkdS5waF0NCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNClRoZSBnZ3Bsb3QyIHBhY2thZ2UgaXMgYmFzZWQgb24gdGhlIHByaW5jaXBsZSB0aGF0IGFsbCBwbG90cyBjb25zaXN0IG9mIGEgZmV3IGJhc2ljIGNvbXBvbmVudHM6IGRhdGEsIGEgY29vcmRpbmF0ZSBzeXN0ZW0gYW5kIGEgdmlzdWFsIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBkYXRhLiBJbiBnZ3Bsb3QyLCB5b3UgYnVpbHQgcGxvdHMgaW5jcmVtZW50YWxseSwgc3RhcnRpbmcgd2l0aCB0aGUgZGF0YSBhbmQgY29vcmRpbmF0ZXMgeW91IHdhbnQgdG8gdXNlIGFuZCB0aGVuIHNwZWNpZnlpbmcgdGhlIGdyYXBoaWNhbCBmZWF0dXJlczogbGluZXMsIHBvaW50cywgYmFycywgY29sb3IsIGV0Yy4NCg0KV2Ugd2lsbCBiZSB1c2luZyB0aHJlZSBkYXRhc2V0cyBpbiB0aGlzIHR1dG9yaWFsLiAqKkZpcnN0IGlzIG91ciBtYWluIGRhdGFzZXQgb24gcGhhZ2UgaG9zdCBpbnRlcmFjdGlvbiwgc2Vjb25kIGlzIHRoZSBkaWFtb25kIGRhdGFzZXQgZ2l2ZW4gYnkgdGhlIGdncGxvdCBwYWNrYWdlLCBsYXN0bHkgaXMgdGhlIGNhcmJvbiBkaW94aWRlIGRhdGFzZXQgZ2l2ZW4gYnkgUi4qKg0KDQpGb3IgYSBsaXN0IG9mIHByZWNvbmZpZ3VyZWQgZGF0YXNldHMsIHNpbXBseSB0eXBlICoqZGF0YSgpKiouDQoNCmBgYHtyfQ0KZGF0YSgpDQpgYGANCg0KYGBge3J9DQpkYXRhc2V0IDwtIHJlYWQuZGVsaW0oInBoYWdlcy50c3YiKQ0KYGBgDQoNCiMjIEJhc2UgUiBQbG90dGluZw0KDQpCZWZvcmUgd2UgYmVnaW4sIGxvYWQgdGhlIGdncGxvdDIgcGFja2FnZSBmb3IgUi4gZ2dwbG90MiBpcyBhIGdyYXBoaWNzIHBhY2thZ2UgdGhhdCBwcm92aWRlcyBwb3dlcmZ1bCBwbG90dGluZyBjYXBhYmlsaXRpZXMgYmV5b25kIFIncyBiYXNlIHBsb3R0aW5nIGZ1bmN0aW9ucy4gV2Ugd29uJ3QgYWN0dWFsbHkgZ2V0IGludG8gZ2dwbG90MiBpdHNlbGYgcXVpdGUgeWV0LiBUaGlzIHdpbGwgYmUgYSBiYXNpYyBpbnRyb2R1Y3Rpb24gdG8gcGxvdHRpbmcgaW4gUi4NCg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQpgYGANCg0KYGBge3J9DQpkYXRhc2V0DQpgYGANCg0KIyMgSGlzdG9ncmFtcw0KDQpBIGhpc3RvZ3JhbSBpcyBhIHVuaXZhcmlhdGUgcGxvdCAoYSBwbG90IHRoYXQgZGlzcGxheXMgb25lIHZhcmlhYmxlKSB0aGF0IGdyb3VwcyBhIG51bWVyaWMgdmFyaWFibGUgaW50byBiaW5zIGFuZCBkaXNwbGF5cyB0aGUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyB0aGF0IGZhbGwgd2l0aGluIGVhY2ggYmluLiBBIGhpc3RvZ3JhbSBpcyBhIHVzZWZ1bCB0b29sIGZvciBnZXR0aW5nIGEgc2Vuc2Ugb2YgdGhlIGRpc3RyaWJ1dGlvbiBvZiBhIG51bWVyaWMgdmFyaWFibGUuDQoNCmBgYHtyfQ0KaGlzdChkYXRhc2V0JFBvc2l0aXZlLlN0cmFuZC4uLi4pDQpgYGANCg0KTm90ZTogV2hlbiB5b3UgY3JlYXRlIGEgcGxvdCBpbiBhIGxvY2FsIFJTdHVkaW8gZW52aXJvbm1lbnQsIGl0IHdpbGwgYXBwZWFyIGluIHRoZSBib3R0b20gcmlnaHQgcGFuZSB1bmRlciB0aGUgInBsb3RzIiB0YWIuIFVzZSB0aGUgbGVmdCBhbmQgcmlnaHQgYXJyb3dzIHRvIGN5Y2xlIHRocm91Z2ggdGhlIHBsb3RzIHlvdSd2ZSBjcmVhdGVkLg0KDQojIyBCb3ggUGxvdHMNCg0KQm94cGxvdHMgYXJlIGFub3RoZXIgdHlwZSBvZiB1bml2YXJpYXRlIHBsb3QgZm9yIHN1bW1hcml6aW5nIGRpc3RyaWJ1dGlvbnMgb2YgbnVtZXJpYyBkYXRhIGdyYXBoaWNhbGx5Lg0KDQpgYGB7cn0NCmJveHBsb3QoZGF0YXNldCRtb2xHQy4uLikNCmBgYA0KDQpUaGUgY2VudHJhbCBib3ggb2YgdGhlIGJveHBsb3QgcmVwcmVzZW50cyB0aGUgbWlkZGxlIDUwJSBvZiB0aGUgb2JzZXJ2YXRpb25zLCB0aGUgY2VudHJhbCBiYXIgaXMgdGhlIG1lZGlhbiBhbmQgdGhlIGJhcnMgYXQgdGhlIGVuZCBvZiB0aGUgZG90dGVkIGxpbmVzIGVuY2Fwc3VsYXRlIHRoZSBncmVhdCBtYWpvcml0eSBvZiB0aGUgb2JzZXJ2YXRpb25zLiBDaXJjbGVzIHRoYXQgbGllIGJleW9uZCB0aGUgZW5kIG9mIHRoZSB3aGlza2VycyBhcmUgZGF0YSBwb2ludHMgdGhhdCBtYXkgYmUgb3V0bGllcnMuDQoNCk9uZSBvZiB0aGUgbW9zdCB1c2VmdWwgZmVhdHVyZXMgb2YgdGhlIGJveHBsb3QoKSBmdW5jdGlvbiBpcyB0aGUgYWJpbGl0eSB0byBtYWtlIHNpZGUtYnktc2lkZSBib3hwbG90cy4gQSBzaWRlLWJ5LXNpZGUgYm94cGxvdCB0YWtlcyBhIG51bWVyaWMgdmFyaWFibGUgYW5kIHNwbGl0cyBpdCBvbiBiYXNlZCBvbiBzb21lIGNhdGVnb3JpY2FsIHZhcmlhYmxlLCBkcmF3aW5nIGEgZGlmZmVyZW50IGJveHBsb3QgZm9yIGVhY2ggbGV2ZWwgb2YgdGhlIGNhdGVnb3JpY2FsIHZhcmlhYmxlLg0KDQpgYGB7cn0NCmJveHBsb3QoZGF0YXNldCRtb2xHQy4uLiB+IGRhdGFzZXQkTW9sZWN1bGUpICMgUGxvdCBHQyBjb250ZW50IHNwbGl0IGJhc2VkIG9uIG1vbGVjdWxhciB0eXBlDQpgYGANCg0KIyMgRGVuc2l0eSBQbG90cw0KDQpBIGRlbnNpdHkgcGxvdCBzaG93cyB0aGUgZGlzdHJpYnV0aW9uIG9mIGEgbnVtZXJpYyB2YXJpYWJsZSB3aXRoIGEgY29udGludW91cyBjdXJ2ZS4gSXQgaXMgc2ltaWxhciB0byBhIGhpc3RvZ3JhbSBidXQgd2l0aG91dCBkaXNjcmV0ZSBiaW5zLCBhIGRlbnNpdHkgcGxvdCBnaXZlcyBhIGJldHRlciBwaWN0dXJlIG9mIHRoZSB1bmRlcmx5aW5nIHNoYXBlIG9mIGEgZGlzdHJpYnV0aW9uLg0KDQpgYGB7cn0NCnBsb3QoZGVuc2l0eShkYXRhc2V0JG1vbEdDLi4uKSkNCmBgYA0KDQojIyBCYXIgUGxvdHMNCg0KQmFycGxvdHMgYXJlIGdyYXBocyB0aGF0IHZpc3VhbGx5IGRpc3BsYXkgY291bnRzIG9mIGNhdGVnb3JpY2FsIHZhcmlhYmxlcy4NCg0KYGBge3J9DQpkYXRhc2V0JEp1bWJvcGhhZ2UgPC0gaWZlbHNlKGRhdGFzZXQkSnVtYm9waGFnZSwgIkp1bWJvcGhhZ2UiLCAiTm90IEp1bWJvcGhhZ2UiKQ0KYGBgDQoNCmBgYHtyfQ0KZGF0YXNldCRKdW1ib3BoYWdlDQpgYGANCg0KYGBge3J9DQpiYXJwbG90KHRhYmxlKGRhdGFzZXQkTW9sZWN1bGUpKQ0KYGBgDQoNCmBgYHtyfQ0KYmFycGxvdCh0YWJsZShkYXRhc2V0JEp1bWJvcGhhZ2UsIGRhdGFzZXQkTW9sZWN1bGUpLA0KICAgICAgICBsZWdlbmQgPSBsZXZlbHMoZGF0YXNldCRKdW1ib3BoYWdlKQ0KKQ0KYGBgDQoNCkEgZ3JvdXBlZCBiYXJwbG90IGlzIGFuIGFsdGVybmF0aXZlIHRvIGEgc3RhY2tlZCBiYXJwbG90IHRoYXQgZ2l2ZXMgZWFjaCBzdGFja2VkIHNlY3Rpb24gaXRzIG93biBiYXIuIFRvIG1ha2UgYSBncm91cGVkIGJhcnBsb3QsIGNyZWF0ZSBhIHN0YWNrZWQgYmFycGxvdCBhbmQgYWRkIHRoZSBleHRyYSBhcmd1bWVudCBiZXNpZGUgPSBUUlVFLg0KDQpgYGB7cn0NCmJhcnBsb3QodGFibGUoZGF0YXNldCRKdW1ib3BoYWdlLCBkYXRhc2V0JE1vbGVjdWxlKSwNCiAgICAgICAgbGVnZW5kID0gbGV2ZWxzKGRhdGFzZXQkSnVtYm9waGFnZSksDQogICAgICAgIGJlc2lkZSA9IFRSVUUNCikgIyBHcm91cCBpbnN0ZWFkIG9mIHN0YWNraW5nDQpgYGANCg0KIyMgU2NhdHRlcnBsb3RzDQoNClNjYXR0ZXJwbG90cyBhcmUgYml2YXJpYXRlICh0d28gdmFyaWFibGUpIHBsb3RzIHRoYXQgdGFrZSB0d28gbnVtZXJpYyB2YXJpYWJsZXMgYW5kIHBsb3QgZGF0YSBwb2ludHMgb24gdGhlIHgveSBwbGFuZS4NCg0KYGBge3J9DQpwbG90KGRhdGFzZXQkbW9sR0MuLi4sIGRhdGFzZXQkUG9zaXRpdmUuU3RyYW5kLi4uLikNCmBgYA0KDQpgYGB7cn0NCnBsb3QoZGF0YXNldCRtb2xHQy4uLiwNCiAgICAgICAgZGF0YXNldCRQb3NpdGl2ZS5TdHJhbmQuLi4uLA0KICAgICAgICBjb2wgPSByZ2IocmVkID0gMCwgZ3JlZW4gPSAwLCBibHVlID0gMCwgYWxwaGEgPSAwLjEpDQopDQpgYGANCg0KSWxsdXN0cmF0aW5nIGhvdyB3ZSBjYW4gbWFrZSBvdXIgZGlmZmVyZW50IHBsb3RzIGxvb2sgbW9yZSBwcmVzZW50YWJsZS4NCg0KYGBge3J9DQpiYXJwbG90KHRhYmxlKGRhdGFzZXQkSnVtYm9waGFnZSwgZGF0YXNldCRNb2xlY3VsZSksDQogICAgICAgIGxlZ2VuZCA9IGxldmVscyhkYXRhc2V0JEp1bWJvcGhhZ2UpLA0KICAgICAgICBiZXNpZGUgPSBUUlVFLA0KICAgICAgICB4bGFiID0gIk1vbGVjdWxhciBUeXBlIiwNCiAgICAgICAgeWxhYiA9ICJKdW1ib3BoYWdlIiwNCiAgICAgICAgbWFpbiA9ICJNb2xlY3VsYXIgVHlwZSwgR3JvdXBlZCBieSBKdW1ib3BoYWdlIiwNCiAgICAgICAgY29sID0gYygNCiAgICAgICAgICAgICAgICAiI0ZGRkZGRiIsICIjRjVGQ0MyIiwgIiNFMEVEODciLCAiI0NDREU1NyIsICMgQWRkIGNvbG9yKg0KICAgICAgICAgICAgICAgICIjQjNDNzMyIiwgIiM5NEE4MTMiLCAiIzcxODIwMCINCiAgICAgICAgKQ0KKQ0KYGBgDQoNCiMjIFVzaW5nIGdncGxvdCgpDQoNClRoZSBnZ3Bsb3QoKSBmdW5jdGlvbiBjcmVhdGVzIHBsb3RzIGluY3JlbWVudGFsbHkgaW4gbGF5ZXJzLiBFdmVyeSBnZ3Bsb3Qgc3RhcnRzIHdpdGggdGhlIHNhbWUgYmFzaWMgc3ludGF4LiBFdmVyeSBnZ3Bsb3Qgc3RhcnRzIHdpdGggYSBjYWxsIHRvIHRoZSBnZ3Bsb3QoKSBmdW5jdGlvbiBhbG9uZyB3aXRoIGFuIGFyZ3VtZW50IHNwZWNpZnlpbmcgdGhlIGRhdGEgc2V0IHRvIGJlIHVzZWQgYW5kIGFlc3RoZXRpYyBtYXBwaW5ncyBmcm9tIHZhcmlhYmxlcyBpbiB0aGUgZGF0YSBzZXQgdG8gdmlzdWFsIHByb3BlcnRpZXMgb2YgdGhlIHBsb3QsIHN1Y2ggYXMgeCBhbmQgeSBwb3NpdGlvbi4NCg0KYGBge3J9DQojIGluc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmBgYA0KDQpXZSBhcmUgbm90IGdvaW5nIHRvIHNwZW5kIG11Y2ggdGltZSBsZWFybmluZyBhYm91dCBxcGxvdCgpIHNpbmNlIGxlYXJuaW5nIHRoZSBnZ3Bsb3QoKSBzeW50YXggaXMgYXQgdGhlIGhlYXJ0IG9mIHRoZSBwYWNrYWdlLiBMZXQncyBsb29rIGF0IG9uZSBxcGxvdCBmb3IgaWxsdXN0cmF0aXZlIHB1cnBvc2VzIGFuZCB0aGVuIG1vdmUgb24uDQoNCmBgYHtyfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KDQpxcGxvdCgNCiAgICAgICAgeCA9IGNhcmF0LCAjIHggdmFyaWFibGUNCiAgICAgICAgeSA9IHByaWNlLCAjIHkgdmFyaWFibGUNCiAgICAgICAgZGF0YSA9IGRpYW1vbmRzLCAjIERhdGEgc2V0DQogICAgICAgIGdlb20gPSAicG9pbnQiLCAjIFBsb3QgdHlwZQ0KICAgICAgICBjb2xvciA9IGNsYXJpdHksICMgQ29sb3IgcG9pbnRzIGJ5IHZhcmlhYmxlIGNsYXJpdHkNCiAgICAgICAgeGxhYiA9ICJDYXJhdCBXZWlnaHQiLCAjIHggbGFiZWwNCiAgICAgICAgeWxhYiA9ICJQcmljZSIsICMgeSBsYWJlbA0KICAgICAgICBtYWluID0gIkRpYW1vbmQgQ2FyYXQgdnMuIFByaWNlIg0KKQ0KIyBUaXRsZQ0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KA0KICAgICAgICBkYXRhc2V0LA0KICAgICAgICBhZXMoQWNjZXNzaW9uLCBtb2xHQy4uLi4pDQopICsNCiAgICAgICAgZ2VvbV9wb2ludCgpDQpgYGANCg0KSW4gdGhlIGNvZGUgYWJvdmUsIHdlIHNwZWNpZnkgdGhlIGRhdGEgd2Ugd2FudCB0byB3b3JrIHdpdGggYW5kIHRoZW4gYXNzaWduIHRoZSB2YXJpYWJsZXMgb2YgaW50ZXJlc3QsIEFjY2Vzc2lvbiBhbmQgR0MgQ29udGVudCwgdG8gdGhlIHggYW5kIHkgdmFsdWVzIG9mIHRoZSBwbG90LiAiYWVzKCkiIGlzIGFuIGFlc3RoZXRpY3Mgd3JhcHBlciB1c2VkIGluIGdncGxvdCB0byBtYXAgdmFyaWFibGVzIHRvIHZpc3VhbCBwcm9wZXJ0aWVzLiBXaGVuIHlvdSB3YW50IGEgdmlzdWFsIHByb3BlcnR5IHRvIGNoYW5nZSBiYXNlZCBvbiB0aGUgdmFsdWUgb2YgYSB2YXJpYWJsZSwgdGhhdCBzcGVjaWZpY2F0aW9uIGJlbG9uZ3MgaW5zaWRlIGFuIGFlcygpIHdyYXBwZXIuIElmIHlvdSBhcmUgc2V0dGluZyBhIGZpeGVkIHZhbHVlIHRoYXQgZG9lc24ndCBjaGFuZ2UgYmFzZWQgYSB2YXJpYWJsZSwgaXQgYmVsb25ncyBvdXRzaWRlIG9mIGFlcygpLg0KDQpfTm90ZTogQWRkIGEgbmV3IGVsZW1lbnQgdG8gYSBwbG90IGJ5IHB1dHRpbmcgYSAiKyIgYWZ0ZXIgdGhlIHByZWNlZGluZyBlbGVtZW50Ll8NCg0KVGhlIGxheWVycyB5b3UgYWRkIGRldGVybWluZSB0aGUgdHlwZSBvZiBwbG90IHlvdSBjcmVhdGUuIEluIHRoaXMgY2FzZSwgd2UgdXNlZCBnZW9tX3BvaW50KCkgd2hpY2ggc2ltcGx5IGRyYXdzIHRoZSBkYXRhIGFzIHBvaW50cyBhdCB0aGUgc3BlY2lmaWVkIHggYW5kIHkgY29vcmRpbmF0ZXMsIGNyZWF0aW5nIGEgc2NhdHRlcnBsb3QuIGdncGxvdDIgaGFzIGEgd2lkZSByYW5nZSBvZiBnZW9tcyB0byBjcmVhdGUgZGlmZmVyZW50IHR5cGVzIG9mIHBsb3RzLiBIZXJlIGlzIGEgbGlzdCBvZiBnZW9tcyBmb3IgYWxsIHRoZSBwbG90IHR5cGVzIHdlIGNvdmVyZWQgaW4gdGhlIGxhc3QgbGVzc29uLCBwbHVzIGEgZmV3IG1vcmUNCg0KYGBge3J9DQpnZW9tX2hpc3RvZ3JhbSgpICMgaGlzdG9ncmFtDQpnZW9tX2RlbnNpdHkoKSAjIGRlbnNpdHkgcGxvdA0KZ2VvbV9ib3hwbG90KCkgIyBib3hwbG90DQpnZW9tX3Zpb2xpbigpICMgdmlvbGluIHBsb3QgKGNvbWJpbmF0aW9uIG9mIGJveHBsb3QgYW5kIGRlbnNpdHkgcGxvdCkNCmdlb21fYmFyKCkgIyBiYXIgZ3JhcGgNCmdlb21fcG9pbnQoKSAjIHNjYXR0ZXJwbG90DQpnZW9tX2ppdHRlcigpICMgc2NhdHRlcnBsb3Qgd2l0aCBwb2ludHMgcmFuZG9tbHkgcGVydHVyYmVkIHRvIHJlZHVjZSBvdmVybGFwDQpnZW9tX2xpbmUoKSAjIGxpbmUgZ3JhcGgNCmdlb21fZXJyb3JiYXIoKSAjIEFkZCBlcnJvciBiYXINCmdlb21fc21vb3RoKCkgIyBBZGQgYSBiZXN0LWZpdCBsaW5lDQpnZW9tX2FibGluZSgpICMgQWRkIGEgbGluZSB3aXRoIHNwZWNpZmllZCBzbG9wZSBhbmQgaW50ZXJjZXB0DQpgYGANCg0KTm90aWNlIHRoZSBzY2F0dGVycGxvdCB3ZSBtYWRlIGFib3ZlIGRpZG4ndCBoYXZlIGEgbmljZSBjb2xvcmluZy4gV2UgY2FuIGF0dHJpYnV0ZSB0aGUgY29sb3JzIG9mIHRoZSBwb2ludHMgdG8gaXRzIE1vbGVjdWxhciB0eXBlLg0KDQpgYGB7cn0NCmdncGxvdChkYXRhc2V0LCBhZXMoQWNjZXNzaW9uLCBtb2xHQy4uLi4sIGNvbG91ciA9IE1vbGVjdWxlKSkgKw0KICAgICAgICBnZW9tX3BvaW50KGFscGhhID0gMC41KQ0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KGRhdGFzZXQsIGFlcyhBY2Nlc3Npb24sIG1vbEdDLi4uLikpICsNCiAgICAgICAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBNb2xlY3VsZSksIGFscGhhID0gMC4yKQ0KYGBgDQoNCldlIHBhc3MgYWxwaGEgaW4gYXMgYW4gYXJndW1lbnQgb3V0c2lkZSBvZiB0aGUgYWVzKCkgbWFwcGluZyBiZWNhdXNlIHdlIGFyZSAqKnNldHRpbmcgYWxwaGEgdG8gYSBmaXhlZCB2YWx1ZSBpbnN0ZWFkIG9mIG1hcHBpbmcgaXQgdG8gYSB2YXJpYWJsZSoqLg0KDQpCeSBzZXR0aW5nIGFscGhhIHRvIDAuMSwgZWFjaCBkYXRhIHBvaW50IGhhcyA5MCUgdHJhbnNwYXJlbmN5LiBBdCBzdWNoIGhpZ2ggdHJhbnNwYXJlbmN5LCBzaW5nbGUgZGF0YSBwb2ludHMgYXJlIGhhcmQgdG8gc2VlLCBidXQgaXQgbGV0cyB1cyBmb2N1cyBvbiBoaWdoIGRlbnNpdHkgYXJlYXMuDQoNCmBgYHtyfQ0KZGF0YXNldCAlPiUNCiAgICAgICAgZ2dwbG90KGFlcyhHZW5vbWUuTGVuZ3RoLi5icC4sIG1vbEdDLi4uLikpICsNCiAgICAgICAgZ2VvbV9wb2ludChhZXMoY29sb3VyID0gTW9sZWN1bGUpLCBhbHBoYSA9IDAuNSkgKw0KICAgICAgICBsYWJzKHggPSAiR2Vub21lIExlbmd0aCIsIHkgPSAiR0MgQ29udGVudCIpDQpgYGANCg0KKipHZW9zbW9vdGgqKiANCg0KSWxsdXN0cmF0aW5nIHRoZSB1c2Ugb2YgZ2Vvc21vb3RoIHVzaW5nIGEgYnVpbHQgaW4gZGF0YXNldCBpbiBSLg0KDQpJbiBnZ3Bsb3QyLCB0aGUgZ2VvbV9zbW9vdGgoKSBmdW5jdGlvbiBpcyB1c2VkIHRvIGFkZCBhIHNtb290aCBsaW5lIG9yIGN1cnZlIHRvIGEgcGxvdC4gSXQgaXMgY29tbW9ubHkgdXNlZCB0byB2aXN1YWxpemUgdGhlIHRyZW5kIG9yIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHZhcmlhYmxlcy4NCg0KYGBge3J9DQpzYW1wbGVfRGF0YVNldCA8LSBDTzINCnNhbXBsZV9EYXRhU2V0DQpgYGANCg0KYGBge3J9DQpnZ3Bsb3Qoc2FtcGxlX0RhdGFTZXQsIGFlcyhjb25jLCB1cHRha2UsIGNvbG91ciA9IFRyZWF0bWVudCkpICsNCiAgICAgICAgZ2VvbV9wb2ludChzaXplID0gMywgYWxwaGEgPSAwLjUpICsNCiAgICAgICAgZ2VvbV9zbW9vdGgobWV0aG9kID0gbG0sIHNlID0gRikNCmBgYA0KDQpJZiB5b3Ugd2FudCB0byBjbGFzc2lmeSBpdCBmdXJ0aGVyIGludG8gdHlwZXMgYmFzZWQgb24geW91ciBkYXRhLCB1c2UgKipmYWNldF93cmFwKCkqKi4NCg0KYGBge3J9DQpnZ3Bsb3Qoc2FtcGxlX0RhdGFTZXQsIGFlcyhjb25jLCB1cHRha2UsIGNvbG91ciA9IFRyZWF0bWVudCkpICsNCiAgICAgICAgZ2VvbV9wb2ludChzaXplID0gMywgYWxwaGEgPSAwLjUpICsNCiAgICAgICAgZ2VvbV9zbW9vdGgobWV0aG9kID0gbG0sIHNlID0gRikgKw0KICAgICAgICBmYWNldF93cmFwKH5UeXBlKSArDQogICAgICAgIGxhYnModGl0bGUgPSAiQ29uY2VudHJhdGlvbiBvZiBDTzIiKSArDQogICAgICAgIHRoZW1lX2J3KCkNCmBgYA0KDQojIyBNb3JlIFBsb3QgRXhhbXBsZXMNCg0KTm93IHRoYXQgd2Uga25vdyB0aGUgYmFzaWNzIG9mIGNyZWF0aW5nIHBsb3RzIHdpdGggZ2dwbG90KCksIGxldCdzIHJlbWFrZSBzb21lIG9mIHRoZSBwbG90cyB3ZSBjcmVhdGVkIGxhc3QgdGltZSBhbmQgc2VlIGhvdyB0aGV5IGxvb2sgaW4gZ2dwbG90Miwgc3RhcnRpbmcgd2l0aCBhIGhpc3RvZ3JhbS4NCg0KIyMjIEhpc3RvZ3JhbXMNCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBkYXRhc2V0LCBhZXMoeCA9IG1vbEdDLi4uLikpICsNCiAgICAgICAgZ2VvbV9oaXN0b2dyYW0oDQogICAgICAgICAgICAgICAgZmlsbCA9ICJza3libHVlIiwNCiAgICAgICAgICAgICAgICBjb2wgPSAiYmxhY2siDQogICAgICAgICkgKw0KICAgICAgICBsYWJzKHggPSAiR0MgQ29udGVudCIpDQpgYGANCg0KIyMjIEJveCBQbG90cw0KYGBge3J9DQpnZ3Bsb3QoZGF0YXNldCwgYWVzKE1vbGVjdWxlLCBHZW5vbWUuTGVuZ3RoLi5icC4pKSArDQogICAgICAgIGdlb21faml0dGVyKA0KICAgICAgICAgICAgICAgIGFscGhhID0gMC4wNSwgIyBBZGQgaml0dGVyZWQgZGF0YSBwb2ludHMNCiAgICAgICAgICAgICAgICBjb2xvciA9ICJ5ZWxsb3ciDQogICAgICAgICkgKw0KICAgICAgICBnZW9tX2JveHBsb3QoKSArDQogICAgICAgIGxhYnMoDQogICAgICAgICAgICAgICAgdGl0bGUgPSAiR2Vub21lIExlbmd0aCBvZiBEaWZmZXJlbnQgTW9sZWN1bGFyIFR5cGVzIiwNCiAgICAgICAgICAgICAgICB5ID0gIkdlbm9tZSBMZW5ndGgiDQogICAgICAgICkNCmBgYA0KDQojIyMgRGVuc2l0eSBQbG90DQpgYGB7cn0NCmdncGxvdChkYXRhID0gZGF0YXNldCwgYWVzKHggPSBtb2xHQy4uLi4pKSArDQogICAgICAgIGdlb21fZGVuc2l0eSgNCiAgICAgICAgICAgICAgICBwb3NpdGlvbiA9ICJzdGFjayIsICMgQ3JlYXRlIGEgc3RhY2tlZCBkZW5zaXR5IGNoYXJ0DQogICAgICAgICAgICAgICAgYWVzKGZpbGwgPSBNb2xlY3VsZSksICMgRmlsbCBiYXNlZCBvbiBjdXQNCiAgICAgICAgICAgICAgICBhbHBoYSA9IDAuNQ0KICAgICAgICApICMgU2V0IHRyYW5zcGFyZW5jeQ0KYGBgDQoNCiMjIE11bHRpZGltZW5zaW9uYWwgUGxvdHRpbmcgYW5kIEZhY2V0aW5nDQoNCk9uZSBvZiB0aGUgbW9zdCBwb3dlcmZ1bCBhc3BlY3RzIG9mIHBsb3RzIGlzIHRoZSBhYmlsaXR5IHRvIHZpc3VhbGx5IGlsbHVzdHJhdGUgcmVsYXRpb25zaGlwcyBiZXR3ZWVuIDMgb3IgbW9yZSB2YXJpYWJsZXMuIFdoZW4gd2UgY3JlYXRlIGEgcGxvdCwgZWFjaCBkaWZmZXJlbnQgZGltZW5zaW9uICh2YXJpYWJsZSkgbmVlZHMgdG8gbWFwIHRvIGEgZGlmZmVyZW50IHBlcmNlcHR1YWwgZmVhdHVyZSAoYWVzdGhldGljKSBzdWNoIGFzIHggcG9zaXRpb24sIHkgcG9zaXRpb24sIHN5bWJvbCwgc2l6ZSBvciBjb2xvci4gTWFraW5nIHVzZSBvZiBzZXZlcmFsIG9mIHRoZXNlIGFlc3RoZXRpY3MgYXQgb25jZSBsZXRzIHVzIG1ha2UgcGxvdHMgaW52b2x2aW5nIG1hbnkgZGltZW5zaW9ucy4gV2UndmUgYWxyZWFkeSBzZWVuIHNvbWUgZXhhbXBsZXMgb2YgbXVsdGlkaW1lbnNpb25hbCBwbG90cywgc3VjaCBhcyB0aGUgZmlyc3Qgc2NhdHRlcnBsb3QgaW4gdGhpcyBsZXNzb24gdGhhdCBkaXNwbGF5ZWQgY2FyYXQgd2VpZ2h0IGFuZCBwcmljZSBjb2xvcmVkIGJ5IGNsYXJpdHkuDQoNCkZhY2V0aW5nIGlzIGFub3RoZXIgd2F5IHRvIGFkZCBhbiBleHRyYSBkaW1lbnNpb24gdG8gYSBwbG90LiBGYWNldGluZyBicmVha3MgYSBwbG90IHVwIGJhc2VkIG9uIGEgZmFjdG9yIHZhcmlhYmxlIGFuZCBkcmF3cyBhIGRpZmZlcmVudCBwbG90IGZvciBlYWNoIGxldmVsIG9mIHRoZSBmYWN0b3IuIFlvdSBjYW4gY3JlYXRlIGEgZmFjZXRlZCBwbG90IGluIGdncGxvdDIgYnkgYWRkaW5nIGEgZmFjZXRfd3JhcCgpIGxheWVyLg0KDQpgYGB7cn0NCmdncGxvdChkYXRhID0gZGlhbW9uZHMsIGFlcyh4ID0gY2FyYXQsIHkgPSBwcmljZSkpICsgIyBJbml0aWFsaXplIHBsb3QNCg0KICAgICAgICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGNvbG9yKSwgIyBDb2xvciBiYXNlZCBvbiBkaWFtb25kIGNvbG9yDQogICAgICAgICAgICAgICAgYWxwaGEgPSAwLjUNCiAgICAgICAgKSArDQogICAgICAgIGZhY2V0X3dyYXAofmNsYXJpdHkpICsgIyBGYWNldCBvbiBjbGFyaXR5DQoNCiAgICAgICAgZ2VvbV9zbW9vdGgoKSArICMgQWRkIGFuIGVzdGltYXRlZCBmaXQgbGluZSoNCg0KICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKDAuODUsIDAuMTYpKSAjIFNldCBsZWdlbmQgcG9zaXRpb24NCmBgYA0KDQojIyBTY2FsZXMNCg0KU2NhbGVzIGFyZSBwYXJhbWV0ZXJzIGluIGdncGxvdDIgdGhhdCBkZXRlcm1pbmUgaG93IGEgcGxvdCBtYXBzIHZhbHVlcyB0byB2aXN1YWwgcHJvcGVydGllcyAoYWVzdGhldGljcy4pLiBJZiB5b3UgZG9uJ3Qgc3BlY2lmeSBhIHNjYWxlIGZvciBhbiBhZXN0aGV0aWMgdGhlIHBsb3Qgd2lsbCB1c2UgYSBkZWZhdWx0IHNjYWxlLiBGb3IgaW5zdGFuY2UsIHRoZSBwbG90cyB3ZSBzcGxpdCBvbiBjb2xvciBhbGwgdXNlZCBhIGRlZmF1bHQgY29sb3Igc2NhbGUuIFlvdSBjYW4gc3BlY2lmeSBjdXN0b20gc2NhbGVzIGJ5IGFkZGluZyBzY2FsZSBlbGVtZW50cyB0byB5b3VyIHBsb3QuIFNjYWxlIGVsZW1lbnRzIGhhdmUgdGhlIGZvbGxvd2luZyBzdHJ1Y3R1cmU6DQoNCnNjYWxlX2Flc3RoZXRpY19zY2FsZXR5cGUoKQ0KDQpXZSBhbHJlYWR5IHNhdyBhbiBleGFtcGxlIG9mIGEgc2NhbGUgd2hlbiBtYWRlIHRoZSBncm91cGVkIGJhcnBsb3QgYWJvdmUuIEluIHRoYXQgY2FzZSB3ZSB3YW50ZWQgdG8gbWFudWFsbHkgc2V0IHRoZSBmaWxsIGNvbG9yIHNjYWxlIGZvciB0aGUgYmFycywgc28gdGhlIHNjYWxlIHdlIHVzZWQgd2FzOg0KDQpzY2FsZV9maWxsX21hbnVhbCgpDQoNCkxldCdzIG1ha2UgYSBuZXcgc2NhdHRlcnBsb3Qgd2l0aCBzZXZlcmFsIGFlc3RoZXRpYyBwcm9wZXJ0aWVzIGFuZCBhbHRlciBzb21lIG9mIHRoZSBzY2FsZXMuDQoNCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBkaWFtb25kcywgYWVzKHggPSBjYXJhdCwgeSA9IHByaWNlKSkgKyAjIEluaXRpYWxpemUgcGxvdA0KDQogICAgICAgIGdlb21fcG9pbnQoYWVzKA0KICAgICAgICAgICAgICAgIHNpemUgPSBjYXJhdCwgIyBTaXplIHBvaW50cyBiYXNlZCBvbiBjYXJhdA0KICAgICAgICAgICAgICAgIGNvbG9yID0gY29sb3IsICMgQ29sb3IgYmFzZWQgb24gZGlhbW9uZCBjb2xvcg0KICAgICAgICAgICAgICAgIGFscGhhID0gY2xhcml0eQ0KICAgICAgICApKSArICMgU2V0IHRyYW5zcGFyZW5jeSBiYXNlZCBvbiBjbGFyaXR5DQoNCiAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoDQogICAgICAgICAgICAgICAgIiNGRkZGRkYiLCAiI0Y1RkNDMiIsICMgVXNlIG1hbnVhbCBjb2xvciB2YWx1ZXMNCiAgICAgICAgICAgICAgICAiI0UwRUQ4NyIsICIjQ0NERTU3IiwNCiAgICAgICAgICAgICAgICAiI0IzQzczMiIsICIjOTRBODEzIiwNCiAgICAgICAgICAgICAgICAiIzcxODIwMCINCiAgICAgICAgKSkgKw0KICAgICAgICBzY2FsZV9hbHBoYV9tYW51YWwodmFsdWVzID0gYygNCiAgICAgICAgICAgICAgICAwLjEsIDAuMTUsIDAuMiwgIyBVc2UgbWFudWFsIGFscGhhIHZhbHVlcw0KICAgICAgICAgICAgICAgIDAuMywgMC40LCAwLjYsDQogICAgICAgICAgICAgICAgMC44LCAxDQogICAgICAgICkpICsNCiAgICAgICAgc2NhbGVfc2l6ZV9pZGVudGl0eSgpICsgIyBTZXQgc2l6ZSB2YWx1ZXMgdG8gdGhlIGFjdHVhbCB2YWx1ZXMgb2YgY2FyYXQqDQoNCiAgICAgICAgeGxpbSgwLCAyLjUpICsgIyBMaW1pdCB4LWF4aXMNCg0KICAgICAgICB0aGVtZShwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiIzdGQjJCOCIpKSArICMgQ2hhbmdlIGJhY2tncm91bmQgY29sb3INCg0KICAgICAgICB0aGVtZShsZWdlbmQua2V5ID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiIzdGQjJCOCIpKSAjIENoYW5nZSBsZWdlbmQgYmFja2dyb3VuZCBjb2xvcg0KYGBg