4. Plotting in R

Plot basics

Making a Scatter Plot

  • If given a single vector as an argument, the function plot() will make a scatter plot with the values of the vector on the y axis, and indices in the x axis
    • e.g. it puts a point at:
      • x = 1, y = 70.8
      • x = 2, y = 67.9 etc…
  • We are going to be using the patients data frame, read using the following command
patients <- read.delim("patient-info.txt")

Remember that $ can be used to access a particular column. The result is a vector, which is the most-basic type of data used in plotting

patients$Weight
  • R tries to guess the most appropriate way to visualise the data, according to the type and dimensions of the object(s) provided
plot(patients$Weight)
  • Axis limits, labels, titles are inferred from the data
    • We can modify these as we wish, by specifying arguments
  • We can give two arguments to plot():
    • In order to visualise the relationship between two variables
    • It will put the values from the first argument in the x axis, and values from the second argument on the y axis
patients$Age
plot(patients$Age, patients$Weight)

Making a barplot

  • Other types of visualisation are available:
    • These are often just special cases of using the plot() function
    • One such function is barplot()
barplot(patients$Age)
  • It is more usual to display count data in a barplot
    • e.g. the counts of a particular categorical variable
barplot(summary(patients$Sex))

Plotting a distribution: Histogram

  • A histogram is a popular way of visualising a distribution of continuous data:
    • You can change the width of bins
    • The y-axis can be either frequency of density
hist(patients$Weight)

Plotting a distribution: Boxplot

  • The boxplot is commonly used in statistics to visualise a distribution:
boxplot(patients$Weight)
  • The black solid line is the median
  • The top and bottom of the box are the 75th and 25th percentiles
    • Hence, the distance between these is a reflection of the spread of the data; the Inter-Quartile Range (IQR)
  • Whiskers are drawn at 1.5 x IQR and -1.5 x IQR

  • Sometimes we want to compare distributions between different categories in our data
  • For this we need to use the ‘formula’ syntax
    • For now, y ~ x means put continuous variable y on the y axis and categorical x on the x axis
boxplot(patients$Weight ~ patients$Sex)
  • Other alternatives to consider:
    • example(dotchart)
    • example(stripchart)
    • example(vioplot) # From vioplot library
    • example(beeswarm) # From beeswarm library

Exercise: Exercise 4a

  1. Read these data into R using read.csv or read.delim as described in the previous section
    • you will need to choose which is appropriate for the file type
  2. What data types are present? Try to think of ways to create the following plots from the data
    • Scatter plot two variables. e.g. Solar Radiation against Ozone
    • A histogram. e.g. Wind Speed
    • Boxplot of a continuous variable against a categorical variable. e.g. Ozone level per month
### Your Answer Here ###

Simple customisations

  • plot() comes with a large collection of arguments that can be set when we call the function:
    • See ?plot and ?par
  • Recall that, unless specified, arguments have a default value
  • We can choose to draw lines on the plot rather than points
    • The rest of the plot remains the same
plot(patients$Weight, type = "l")
  • We can also have both lines and points:
plot(patients$Weight, type = "b")
  • Add an informative title to the plot using the main argument:
plot(patients$Age, patients$Weight,
     main = "Relationship between Weight and Age")
  • Adding the x-axis label:
plot(patients$Age, patients$Weight, xlab = "Age")
  • Adding the y-axis label:
plot(patients$Age, patients$Weight, ylab = "Weight")
  • We can specifiy multiple arguments at once:
    • here ylim and xlim are used to specify axis limits
plot(patients$Age,patients$Weight,
     ylab="Weight",
     xlab="Age",
     main="Relationship between Weight and Age",
     xlim=c(10,70),
     ylim=c(60,80))

Defining a colour

  • R can recognise various strings, such as "red", "orange","green","blue","yellow"
  • Or more exotic ones like paleturquoise3, lightpink1, mediumseagreen, lightblue1, snow3, gray78, snow4, pink4
    • See colours()
  • See http://www.stat.columbia.edu/~tzheng/files/Rcolor.pdf
  • Can also use Red Green Blue and hexadecimal values:

    • rgb(0.7, 0.7, 0.7) → A light grey in RGB format`
    • "#B3B3B3" → The same light grey in hexadecimal
    • "#0000FF88"→ A semi-transparent blue, in hexadecimal
      • The hexadecimal system is the native colour system for screen visualisation (e.g. webs). It indicates the intensity of Red, Green and Blue by using two digits for each colour, in a scale from 0-9 and A-F (0 meaning no intensity and F meaning most intense)

Changing the col argument to plot() changes the colour that the points are plotted in:

plot(patients$Age, patients$Weight, col = "red")

Plotting characters

  • R can use a variety of plotting characters
  • Each of which has a numeric code
plot(patients$Age, patients$Weight, pch = 16)
  • Or you can specify a character:
plot(patients$Age, patients$Weight, pch = "X")

Size of points

Character expansion: Make the size of points 3 times larger than the default

plot(patients$Age, patients$Weight, cex = 3)

or 20% of the original size

plot(patients$Age, patients$Weight, cex = 0.2)

Colours and characters as vectors

  • Previously we have used a vector of length 1 as our value of colour and character
  • We can use a vector of any length:
    • the values will get recycled (re-used) so that each point gets assigned a value
  • We can use a pre-defined colour palette (see later)
plot(patients$Age, patients$Weight, 
     col = c("red","blue"))

Other plots use the same arguments

  • Other plotting functions use the same arguments as plot()
    • technical explanation: the arguments are ‘inherited’
boxplot(patients$Weight~patients$Sex,
        xlab = "Sex",
        ylab = "Weight",
        main = "Relationship between Weight and Gender",
        col  = c("blue","yellow"))

Exercise: exercise4b

  • Can you re-create the following plots? Hint:
    • See the breaks and freq arguments to hist (?hist) to create 20 bins and display density rather than frequency
    • For third plot, see the rainbow function (?rainbow)
    • Don’t worry too much about getting the colours exactly correct
    • The las argument changes the label orientation. See ?par.
    • look at the arguments to boxplot to see how to change the names printed under each box
### Your Answer Here ###

More on colours

  • The rainbow() function is used to create a vector of colours for the boxplot; in other words a palette:
    • Red, Orange, Yellow, Green, Blue, Indigo, Violet, etc.
    • Other palette functions available: heat.colors(), terrain.colors(), topo.colors(), cm.colors()
    • Red, Orange, Yellow, Green, Blue, Indigo, Violet….etc
  • More aesthetically-pleasing palettes are provided by the RColorBrewer package:
    • can also check for palettes that are accepted for those with colour-blindness
  • You may need to install RColorBrewer with the following line of code
    • remember, you only need to do this once
install.packages("RColorBrewer")
library(RColorBrewer)
display.brewer.all()
display.brewer.all(colorblindFriendly = TRUE)
weather <- read.csv("ozone.csv")
boxplot(weather$Temp ~ weather$Month,col=brewer.pal(5,"Set1"))

End of Day 1

To come tomorrow…

  • More customisation of plots
  • Statistics
  • Further manipulation of data
  • Report writing
LS0tCnRpdGxlOiAiSW50cm9kdWN0aW9uIHRvIFNvbHZpbmcgQmlvbG9naWNhbCBQcm9ibGVtcyBVc2luZyBSIC0gRGF5IDEiCmF1dGhvcjogTWFyayBEdW5uaW5nLCBTdXJhaiBNZW5vbiBhbmQgQWlvcmEgWmFiYWxhLiBPcmlnaW5hbCBtYXRlcmlhbCBieSBSb2JlcnQgU3Rvam5pxIcsCiAgTGF1cmVudCBHYXR0bywgUm9iIEZveSwgSm9obiBEYXZleSwgRMOhdmlkIE1vbG7DoXIgYW5kIElhbiBSb2JlcnRzCmRhdGU6ICdgciBmb3JtYXQoU3lzLnRpbWUoKSwgIkxhc3QgbW9kaWZpZWQ6ICVkICViICVZIilgJwpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwotLS0KCgoKIyA0LiBQbG90dGluZyBpbiBSCgojI1Bsb3QgYmFzaWNzCgotIEFzIHdlIGhhdmUgaGVhcmQsIFIgaGFzIGV4dGVuc2l2ZSBncmFwaGljYWwgY2FwYWJpbGl0aWVzCi0gLi4uYnV0IHdlIG5lZWQgdG8gc3RhcnQgc2ltcGxlCi0gV2Ugd2lsbCBkZXNjcmliZSAqYmFzZSogZ3JhcGhpY3MgaW4gUjogdGhlIHBsb3RzIGF2YWlsYWJsZSB3aXRoIGFueSBzdGFuZGFyZCBSIGluc3RhbGxhdGlvbgogICAgKyBvdGhlciBtb3JlIGFkdmFuY2VkIGFsdGVybmF0aXZlcyBhcmUsIGUuZy4sIGBsYXR0aWNlYCwgYGdncGxvdDJgCiAgICArIFNlZSBvdXIgW2ludGVybWVkaWF0ZSBSIGNvdXJzZV0oaHR0cDovL2Jpb2luZm9ybWF0aWNzLWNvcmUtc2hhcmVkLXRyYWluaW5nLmdpdGh1Yi5pby9yLWludGVybWVkaWF0ZS8pIGZvciBmYW5jeSBncmFwaGljcwotIFBsb3R0aW5nIGluIFIgaXMgYSAqdmFzdCogdG9waWM6CiAgICArIFdlIGNhbm5vdCBjb3ZlciBldmVyeXRoaW5nCiAgICArIFlvdSBjYW4gdGlua2VyIHdpdGggcGxvdHMgdG8geW91ciBoZWFydHMgY29udGVudAogICAgKyBCZXN0IHRvIGxlYXJuIGZyb20gZXhhbXBsZXM7IGUuZy4gW1RoZSBSIEdyYXBoIEdhbGxlcnldKGh0dHA6Ly93d3cuci1ncmFwaC1nYWxsZXJ5LmNvbS8pCi0gKioqWW91IG5lZWQgdG8gdGhpbmsgYWJvdXQgaG93IGJlc3QgdG8gdmlzdWFsaXNlIHlvdXIgZGF0YSoqKiAKICAgICsgaHR0cDovL3d3dy5iaW9pbmZvcm1hdGljcy5iYWJyYWhhbS5hYy51ay90cmFpbmluZy5odG1sI2ZpZ3VyZWRlc2lnbgotIFIgY2Fubm90IHByZXZlbnQgeW91IGZyb20gY3JlYXRpbmcgYSBwbG90dGluZyBkaXNhc3RlcjogCiAgICArIGh0dHA6Ly93d3cuYnVzaW5lc3NpbnNpZGVyLmNvbS90aGUtMjctd29yc3QtY2hhcnRzLW9mLWFsbC10aW1lLTIwMTMtNj9vcD0xJklSPVQKICAgIAojI01ha2luZyBhIFNjYXR0ZXIgUGxvdAoKLSBJZiBnaXZlbiBhIHNpbmdsZSB2ZWN0b3IgYXMgYW4gYXJndW1lbnQsIHRoZSBmdW5jdGlvbiAqKmBwbG90KClgKiogd2lsbCBtYWtlIGEgc2NhdHRlciBwbG90IHdpdGggdGhlICp2YWx1ZXMqIG9mIHRoZSB2ZWN0b3Igb24gdGhlICp5KiBheGlzLCBhbmQgKmluZGljZXMqIGluIHRoZSAqeCogYXhpcwogICAgKyBlLmcuIGl0IHB1dHMgYSBwb2ludCBhdDoKICAgICAgICArIHggPSAxLCB5ID0gNzAuOAogICAgICAgICsgeCA9IDIsIHkgPSA2Ny45IGV0Yy4uLgotIFdlIGFyZSBnb2luZyB0byBiZSB1c2luZyB0aGUgcGF0aWVudHMgZGF0YSBmcmFtZSwgcmVhZCB1c2luZyB0aGUgZm9sbG93aW5nIGNvbW1hbmQKCmBgYHtyfQpwYXRpZW50cyA8LSByZWFkLmRlbGltKCJwYXRpZW50LWluZm8udHh0IikKYGBgCgpSZW1lbWJlciB0aGF0IGAkYCBjYW4gYmUgdXNlZCB0byBhY2Nlc3MgYSBwYXJ0aWN1bGFyIGNvbHVtbi4gVGhlIHJlc3VsdCBpcyBhIHZlY3Rvciwgd2hpY2ggaXMgdGhlIG1vc3QtYmFzaWMgdHlwZSBvZiBkYXRhIHVzZWQgaW4gcGxvdHRpbmcKICAgICAgICAKYGBge3J9CnBhdGllbnRzJFdlaWdodApgYGAKCgotIFIgdHJpZXMgdG8gZ3Vlc3MgdGhlIG1vc3QgYXBwcm9wcmlhdGUgd2F5IHRvIHZpc3VhbGlzZSB0aGUgZGF0YSwgYWNjb3JkaW5nIHRvIHRoZSB0eXBlIGFuZCBkaW1lbnNpb25zIG9mIHRoZSBvYmplY3QocykgcHJvdmlkZWQKCgpgYGB7cn0KcGxvdChwYXRpZW50cyRXZWlnaHQpCmBgYAoKLSBBeGlzIGxpbWl0cywgbGFiZWxzLCB0aXRsZXMgYXJlIGluZmVycmVkIGZyb20gdGhlIGRhdGEKICAgICsgV2UgY2FuIG1vZGlmeSB0aGVzZSBhcyB3ZSB3aXNoLCBieSBzcGVjaWZ5aW5nICoqKmFyZ3VtZW50cyoqKgoKLSBXZSBjYW4gZ2l2ZSB0d28gYXJndW1lbnRzIHRvIGBwbG90KClgOgogICAgKyBJbiBvcmRlciB0byB2aXN1YWxpc2UgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHR3byB2YXJpYWJsZXMKICAgICsgSXQgd2lsbCBwdXQgdGhlIHZhbHVlcyBmcm9tIHRoZSAqZmlyc3QqIGFyZ3VtZW50IGluIHRoZSAqeCogYXhpcywgYW5kIHZhbHVlcyBmcm9tIHRoZSAqc2Vjb25kKiBhcmd1bWVudCBvbiB0aGUgKnkqIGF4aXMKCmBgYHtyfQpwYXRpZW50cyRBZ2UKcGxvdChwYXRpZW50cyRBZ2UsIHBhdGllbnRzJFdlaWdodCkKYGBgCgojI01ha2luZyBhIGJhcnBsb3QKCi0gT3RoZXIgdHlwZXMgb2YgdmlzdWFsaXNhdGlvbiBhcmUgYXZhaWxhYmxlOgogICAgKyBUaGVzZSBhcmUgb2Z0ZW4ganVzdCBzcGVjaWFsIGNhc2VzIG9mIHVzaW5nIHRoZSBgcGxvdCgpYCBmdW5jdGlvbgogICAgKyBPbmUgc3VjaCBmdW5jdGlvbiBpcyBgYmFycGxvdCgpYAogICAgCiAgICAKYGBge3J9CmJhcnBsb3QocGF0aWVudHMkQWdlKQpgYGAKCgotIEl0IGlzIG1vcmUgdXN1YWwgdG8gZGlzcGxheSBjb3VudCBkYXRhIGluIGEgYmFycGxvdAogICAgKyBlLmcuIHRoZSBjb3VudHMgb2YgYSBwYXJ0aWN1bGFyICoqKmNhdGVnb3JpY2FsKioqIHZhcmlhYmxlCgpgYGB7cn0KYmFycGxvdChzdW1tYXJ5KHBhdGllbnRzJFNleCkpCmBgYAoKIyNQbG90dGluZyBhIGRpc3RyaWJ1dGlvbjogSGlzdG9ncmFtCgotIEEgaGlzdG9ncmFtIGlzIGEgcG9wdWxhciB3YXkgb2YgdmlzdWFsaXNpbmcgYSBkaXN0cmlidXRpb24gb2YgKioqY29udGludW91cyoqKiBkYXRhOgogICAgKyBZb3UgY2FuIGNoYW5nZSB0aGUgd2lkdGggb2YgYmlucwogICAgKyBUaGUgeS1heGlzIGNhbiBiZSBlaXRoZXIgZnJlcXVlbmN5IG9mIGRlbnNpdHkKCmBgYHtyfQpoaXN0KHBhdGllbnRzJFdlaWdodCkKYGBgCgoKCiMjUGxvdHRpbmcgYSBkaXN0cmlidXRpb246IEJveHBsb3QKCi0gVGhlIGJveHBsb3QgaXMgY29tbW9ubHkgdXNlZCBpbiBzdGF0aXN0aWNzIHRvIHZpc3VhbGlzZSBhIGRpc3RyaWJ1dGlvbjoKYGBge3J9CmJveHBsb3QocGF0aWVudHMkV2VpZ2h0KQpgYGAKCi0gVGhlIGJsYWNrIHNvbGlkIGxpbmUgaXMgdGhlICoqKm1lZGlhbioqKgotIFRoZSB0b3AgYW5kIGJvdHRvbSBvZiB0aGUgYm94IGFyZSB0aGUgNzV0aCBhbmQgMjV0aCBwZXJjZW50aWxlcwogICAgICsgSGVuY2UsIHRoZSBkaXN0YW5jZSBiZXR3ZWVuIHRoZXNlIGlzIGEgcmVmbGVjdGlvbiBvZiB0aGUgKnNwcmVhZCogb2YgdGhlIGRhdGE7IHRoZSBJbnRlci1RdWFydGlsZSBSYW5nZSAoKioqSVFSKioqKQotIFdoaXNrZXJzIGFyZSBkcmF3biBhdCAxLjUgeCBJUVIgYW5kIC0xLjUgeCBJUVIKCgotIFNvbWV0aW1lcyB3ZSB3YW50IHRvIGNvbXBhcmUgZGlzdHJpYnV0aW9ucyBiZXR3ZWVuIGRpZmZlcmVudCBjYXRlZ29yaWVzIGluIG91ciBkYXRhCi0gRm9yIHRoaXMgd2UgbmVlZCB0byB1c2UgdGhlICcqZm9ybXVsYSonIHN5bnRheAogICAgKyBGb3Igbm93LCBgeSB+IHhgIG1lYW5zIHB1dCBjb250aW51b3VzIHZhcmlhYmxlIGB5YCBvbiB0aGUgKnkqIGF4aXMgYW5kIGNhdGVnb3JpY2FsIGB4YCBvbiB0aGUgeCBheGlzCmBgYHtyfQpib3hwbG90KHBhdGllbnRzJFdlaWdodCB+IHBhdGllbnRzJFNleCkKCmBgYAoKLSBPdGhlciBhbHRlcm5hdGl2ZXMgdG8gY29uc2lkZXI6CiAgICAtIGBleGFtcGxlKGRvdGNoYXJ0KWAKICAgIC0gYGV4YW1wbGUoc3RyaXBjaGFydClgCiAgICAtIGBleGFtcGxlKHZpb3Bsb3QpICAjIEZyb20gdmlvcGxvdCBsaWJyYXJ5YAogICAgLSBgZXhhbXBsZShiZWVzd2FybSkgIyBGcm9tIGJlZXN3YXJtIGxpYnJhcnlgCgojIyBFeGVyY2lzZTogRXhlcmNpc2UgNGEKCi0gSW4gdGhlIGNvdXJzZSBmb2xkZXIgeW91IHdpbGwgZmluZCB0aGUgZmlsZSBgb3pvbmUuY3N2YDoKICAgICsgRGF0YSBkZXNjcmliaW5nIHdlYXRoZXIgY29uZGl0aW9ucyBpbiBOZXcgWW9yayBDaXR5IGluIDE5NzMsIG9idGFpbmVkIGZyb20gdGhlIFtzdXBwbGVtZW50YXJ5IGRhdGFdKGh0dHA6Ly9mYWN1bHR5Lndhc2hpbmd0b24uZWR1L2hlYWdlcnR5L0Jvb2tzL0Jpb3N0YXRpc3RpY3MvaW5kZXgtY2hhcHRlci5odG1sKSB0byAqQmlvc3RhdGlzdGljczogQSBNZXRob2RvbG9neSBmb3IgdGhlIEhlYWx0aCBTY2llbmNlcyoKICAgICsgRnVsbCBkZXNjcmlwdGlvbiBoZXJlOiBodHRwOi8vZmFjdWx0eS53YXNoaW5ndG9uLmVkdS9oZWFnZXJ0eS9Cb29rcy9CaW9zdGF0aXN0aWNzL0RBVEEvb3pvbmVkb2MudHh0CjEuIFJlYWQgdGhlc2UgZGF0YSBpbnRvIFIgdXNpbmcgYHJlYWQuY3N2YCBvciBgcmVhZC5kZWxpbWAgYXMgZGVzY3JpYmVkIGluIHRoZSBwcmV2aW91cyBzZWN0aW9uCiAgICArIHlvdSB3aWxsIG5lZWQgdG8gY2hvb3NlIHdoaWNoIGlzIGFwcHJvcHJpYXRlIGZvciB0aGUgZmlsZSB0eXBlCjIuIFdoYXQgZGF0YSB0eXBlcyBhcmUgcHJlc2VudD8gVHJ5IHRvIHRoaW5rIG9mIHdheXMgdG8gY3JlYXRlIHRoZSBmb2xsb3dpbmcgcGxvdHMgZnJvbSB0aGUgZGF0YQogICAgKyBTY2F0dGVyIHBsb3QgdHdvIHZhcmlhYmxlcy4gZS5nLiBTb2xhciBSYWRpYXRpb24gYWdhaW5zdCBPem9uZQogICAgKyBBIGhpc3RvZ3JhbS4gZS5nLiBXaW5kIFNwZWVkCiAgICArIEJveHBsb3Qgb2YgYSBjb250aW51b3VzIHZhcmlhYmxlIGFnYWluc3QgYSBjYXRlZ29yaWNhbCB2YXJpYWJsZS4gZS5nLiBPem9uZSBsZXZlbCBwZXIgbW9udGgKICAgIAohW10oaW1hZ2VzL2V4ZXJjaXNlNGEucG5nKQoKCgpgYGB7cn0KIyMjIFlvdXIgQW5zd2VyIEhlcmUgIyMjCgoKCmBgYAoKCiMjIFNpbXBsZSBjdXN0b21pc2F0aW9ucwoKLSBgcGxvdCgpYCBjb21lcyB3aXRoIGEgbGFyZ2UgY29sbGVjdGlvbiBvZiBhcmd1bWVudHMgdGhhdCBjYW4gYmUgc2V0IHdoZW4gd2UgY2FsbCB0aGUgZnVuY3Rpb246CiAgICArIFNlZSBgP3Bsb3RgIGFuZCBgP3BhcmAKLSBSZWNhbGwgdGhhdCwgdW5sZXNzIHNwZWNpZmllZCwgYXJndW1lbnRzIGhhdmUgYSBkZWZhdWx0IHZhbHVlCi0gV2UgY2FuIGNob29zZSB0byBkcmF3IGxpbmVzIG9uIHRoZSBwbG90IHJhdGhlciB0aGFuIHBvaW50cwogICAgKyBUaGUgcmVzdCBvZiB0aGUgcGxvdCByZW1haW5zIHRoZSBzYW1lCgpgYGB7cn0KcGxvdChwYXRpZW50cyRXZWlnaHQsIHR5cGUgPSAibCIpCmBgYAoKCi0gV2UgY2FuIGFsc28gaGF2ZSBib3RoIGxpbmVzIGFuZCBwb2ludHM6CgpgYGB7cn0KcGxvdChwYXRpZW50cyRXZWlnaHQsIHR5cGUgPSAiYiIpCmBgYAoKCi0gQWRkIGFuIGluZm9ybWF0aXZlIHRpdGxlIHRvIHRoZSBwbG90IHVzaW5nIHRoZSBgbWFpbmAgYXJndW1lbnQ6CgpgYGB7cn0KcGxvdChwYXRpZW50cyRBZ2UsIHBhdGllbnRzJFdlaWdodCwKICAgICBtYWluID0gIlJlbGF0aW9uc2hpcCBiZXR3ZWVuIFdlaWdodCBhbmQgQWdlIikKYGBgCgoKCi0gQWRkaW5nIHRoZSB4LWF4aXMgbGFiZWw6CmBgYHtyfQpwbG90KHBhdGllbnRzJEFnZSwgcGF0aWVudHMkV2VpZ2h0LCB4bGFiID0gIkFnZSIpCmBgYAoKLSBBZGRpbmcgdGhlIHktYXhpcyBsYWJlbDoKCmBgYHtyfQpwbG90KHBhdGllbnRzJEFnZSwgcGF0aWVudHMkV2VpZ2h0LCB5bGFiID0gIldlaWdodCIpCmBgYAoKLSBXZSBjYW4gc3BlY2lmaXkgbXVsdGlwbGUgYXJndW1lbnRzIGF0IG9uY2U6CiAgICArIGhlcmUgYHlsaW1gIGFuZCBgeGxpbWAgYXJlIHVzZWQgdG8gc3BlY2lmeSBheGlzIGxpbWl0cwpgYGB7cn0KcGxvdChwYXRpZW50cyRBZ2UscGF0aWVudHMkV2VpZ2h0LAogICAgIHlsYWI9IldlaWdodCIsCiAgICAgeGxhYj0iQWdlIiwKICAgICBtYWluPSJSZWxhdGlvbnNoaXAgYmV0d2VlbiBXZWlnaHQgYW5kIEFnZSIsCiAgICAgeGxpbT1jKDEwLDcwKSwKICAgICB5bGltPWMoNjAsODApKQoKYGBgCgojI0RlZmluaW5nIGEgY29sb3VyCgotIFIgY2FuIHJlY29nbmlzZSB2YXJpb3VzIHN0cmluZ3MsIHN1Y2ggYXMgYCJyZWQiYCwgYCJvcmFuZ2UiYCxgImdyZWVuImAsYCJibHVlImAsYCJ5ZWxsb3ciYC4uLgotIE9yIG1vcmUgZXhvdGljIG9uZXMgbGlrZSBgYHIgc2FtcGxlKGNvbG91cnMoKSw4KWBgLi4uCiAgICAgICArIFNlZSBgY29sb3VycygpYAotIFNlZSBodHRwOi8vd3d3LnN0YXQuY29sdW1iaWEuZWR1L350emhlbmcvZmlsZXMvUmNvbG9yLnBkZgotIENhbiBhbHNvIHVzZSAqKlIqKmVkICoqRyoqcmVlbiAqKkIqKmx1ZSBhbmQgaGV4YWRlY2ltYWwgdmFsdWVzOgoKICAgICAgICsgYHJnYigwLjcsIDAuNywgMC43KWAg4oaSIEEgbGlnaHQgZ3JleSBpbiBSR0IgZm9ybWF0YAogICAgICAgKyBgIiNCM0IzQjMiYCDihpIgIFRoZSBzYW1lIGxpZ2h0IGdyZXkgaW4gaGV4YWRlY2ltYWwKICAgICAgICsgYCIjMDAwMEZGODgiYOKGkiBBIHNlbWktdHJhbnNwYXJlbnQgYmx1ZSwgaW4gaGV4YWRlY2ltYWwKICAgICAgICAgICsgVGhlIGhleGFkZWNpbWFsIHN5c3RlbSBpcyB0aGUgbmF0aXZlIGNvbG91ciBzeXN0ZW0gZm9yIHNjcmVlbiB2aXN1YWxpc2F0aW9uIChlLmcuIHdlYnMpLiBJdCBpbmRpY2F0ZXMgdGhlIGludGVuc2l0eSBvZiBSZWQsIEdyZWVuIGFuZCBCbHVlIGJ5IHVzaW5nIHR3byBkaWdpdHMgZm9yIGVhY2ggY29sb3VyLCBpbiBhIHNjYWxlIGZyb20gMC05IGFuZCBBLUYgKDAgbWVhbmluZyBubyBpbnRlbnNpdHkgYW5kIEYgbWVhbmluZyBtb3N0IGludGVuc2UpCgoKQ2hhbmdpbmcgdGhlIGBjb2xgIGFyZ3VtZW50IHRvIGBwbG90KClgIGNoYW5nZXMgdGhlIGNvbG91ciB0aGF0IHRoZSBwb2ludHMgYXJlIHBsb3R0ZWQgaW46CgpgYGB7cn0KcGxvdChwYXRpZW50cyRBZ2UsIHBhdGllbnRzJFdlaWdodCwgY29sID0gInJlZCIpCmBgYAoKCiMjUGxvdHRpbmcgY2hhcmFjdGVycwoKLSBSIGNhbiB1c2UgYSB2YXJpZXR5IG9mICoqcCoqbG90dGluZyAqKmNoKiphcmFjdGVycwotIEVhY2ggb2Ygd2hpY2ggaGFzIGEgbnVtZXJpYyAqY29kZSogCgohW10oaW1hZ2VzL3BjaC5wbmcpCgpgYGB7cn0KcGxvdChwYXRpZW50cyRBZ2UsIHBhdGllbnRzJFdlaWdodCwgcGNoID0gMTYpCmBgYAoKCgotIE9yIHlvdSBjYW4gc3BlY2lmeSBhIGNoYXJhY3RlcjoKCmBgYHtyfQpwbG90KHBhdGllbnRzJEFnZSwgcGF0aWVudHMkV2VpZ2h0LCBwY2ggPSAiWCIpCmBgYAoKCiMjU2l6ZSBvZiBwb2ludHMKCioqQyoqaGFyYWN0ZXIgKipleCoqcGFuc2lvbjogTWFrZSB0aGUgc2l6ZSBvZiBwb2ludHMgMyB0aW1lcyBsYXJnZXIgdGhhbiB0aGUgZGVmYXVsdAoKYGBge3J9CnBsb3QocGF0aWVudHMkQWdlLCBwYXRpZW50cyRXZWlnaHQsIGNleCA9IDMpCmBgYAoKb3IgMjAlIG9mIHRoZSBvcmlnaW5hbCBzaXplCgpgYGB7cn0KcGxvdChwYXRpZW50cyRBZ2UsIHBhdGllbnRzJFdlaWdodCwgY2V4ID0gMC4yKQpgYGAKCiMjQ29sb3VycyBhbmQgY2hhcmFjdGVycyBhcyB2ZWN0b3JzCgotIFByZXZpb3VzbHkgd2UgaGF2ZSB1c2VkIGEgKnZlY3Rvciogb2YgbGVuZ3RoIDEgYXMgb3VyIHZhbHVlIG9mIGNvbG91ciBhbmQgY2hhcmFjdGVyCi0gV2UgY2FuIHVzZSBhIHZlY3RvciBvZiBhbnkgbGVuZ3RoOgogICAgKyB0aGUgdmFsdWVzIHdpbGwgZ2V0ICpyZWN5Y2xlZCogKHJlLXVzZWQpIHNvIHRoYXQgZWFjaCBwb2ludCBnZXRzIGFzc2lnbmVkIGEgdmFsdWUKLSBXZSBjYW4gdXNlIGEgcHJlLWRlZmluZWQgKioqY29sb3VyIHBhbGV0dGUqKiogKHNlZSBsYXRlcikKCmBgYHtyfQpwbG90KHBhdGllbnRzJEFnZSwgcGF0aWVudHMkV2VpZ2h0LCAKICAgICBjb2wgPSBjKCJyZWQiLCJibHVlIikpCmBgYAoKIyNPdGhlciBwbG90cyB1c2UgdGhlIHNhbWUgYXJndW1lbnRzCgotIE90aGVyIHBsb3R0aW5nIGZ1bmN0aW9ucyB1c2UgdGhlIHNhbWUgYXJndW1lbnRzIGFzIGBwbG90KClgCiAgICArIHRlY2huaWNhbCBleHBsYW5hdGlvbjogdGhlIGFyZ3VtZW50cyBhcmUgKidpbmhlcml0ZWQnKgoKYGBge3J9CmJveHBsb3QocGF0aWVudHMkV2VpZ2h0fnBhdGllbnRzJFNleCwKICAgICAgICB4bGFiID0gIlNleCIsCiAgICAgICAgeWxhYiA9ICJXZWlnaHQiLAogICAgICAgIG1haW4gPSAiUmVsYXRpb25zaGlwIGJldHdlZW4gV2VpZ2h0IGFuZCBHZW5kZXIiLAogICAgICAgIGNvbCAgPSBjKCJibHVlIiwieWVsbG93IikpCmBgYAoKCiMjRXhlcmNpc2U6IGV4ZXJjaXNlNGIKCi0gQ2FuIHlvdSByZS1jcmVhdGUgdGhlIGZvbGxvd2luZyBwbG90cz8gSGludDoKICAgICsgU2VlIHRoZSBgYnJlYWtzYCBhbmQgYGZyZXFgIGFyZ3VtZW50cyB0byBoaXN0IChgP2hpc3RgKSB0byBjcmVhdGUgMjAgYmlucyBhbmQgZGlzcGxheSBkZW5zaXR5IHJhdGhlciB0aGFuIGZyZXF1ZW5jeQogICAgKyBGb3IgdGhpcmQgcGxvdCwgc2VlIHRoZSByYWluYm93IGZ1bmN0aW9uIChgP3JhaW5ib3dgKQogICAgKyBEb24ndCB3b3JyeSB0b28gbXVjaCBhYm91dCBnZXR0aW5nIHRoZSBjb2xvdXJzIGV4YWN0bHkgY29ycmVjdAogICAgKyBUaGUgYGxhc2AgYXJndW1lbnQgY2hhbmdlcyB0aGUgbGFiZWwgb3JpZW50YXRpb24uIFNlZSBgP3BhcmAuCiAgICArIGxvb2sgYXQgdGhlIGFyZ3VtZW50cyB0byBgYm94cGxvdGAgdG8gc2VlIGhvdyB0byBjaGFuZ2UgdGhlIG5hbWVzIHByaW50ZWQgdW5kZXIgZWFjaCBib3gKICAgIAohW10oaW1hZ2VzL2V4ZXJjaXNlNGIucG5nKQoKYGBge3J9CiMjIyBZb3VyIEFuc3dlciBIZXJlICMjIwoKCmBgYAoKIyMgTW9yZSBvbiBjb2xvdXJzCgotIFRoZSAqKmByYWluYm93KClgKiogZnVuY3Rpb24gaXMgdXNlZCB0byBjcmVhdGUgYSB2ZWN0b3Igb2YgY29sb3VycyBmb3IgdGhlIGJveHBsb3Q7IGluIG90aGVyIHdvcmRzIGEgKioqcGFsZXR0ZSoqKjoKICAgICsgUmVkLCBPcmFuZ2UsIFllbGxvdywgR3JlZW4sIEJsdWUsIEluZGlnbywgVmlvbGV0LCBldGMuCiAgICArIE90aGVyIHBhbGV0dGUgZnVuY3Rpb25zIGF2YWlsYWJsZTogYGhlYXQuY29sb3JzKCksIHRlcnJhaW4uY29sb3JzKCksIHRvcG8uY29sb3JzKCksIGNtLmNvbG9ycygpYAogICAgKyBSZWQsIE9yYW5nZSwgWWVsbG93LCBHcmVlbiwgQmx1ZSwgSW5kaWdvLCBWaW9sZXQuLi4uZXRjCgogICAgCgoKLSBNb3JlIGFlc3RoZXRpY2FsbHktcGxlYXNpbmcgcGFsZXR0ZXMgYXJlIHByb3ZpZGVkIGJ5IHRoZSAqKmBSQ29sb3JCcmV3ZXJgKiogcGFja2FnZToKICAgICsgY2FuIGFsc28gY2hlY2sgZm9yIHBhbGV0dGVzIHRoYXQgYXJlIGFjY2VwdGVkIGZvciB0aG9zZSB3aXRoIGNvbG91ci1ibGluZG5lc3MKLSAgWW91IG1heSBuZWVkIHRvICppbnN0YWxsKiBgUkNvbG9yQnJld2VyYCB3aXRoIHRoZSBmb2xsb3dpbmcgbGluZSBvZiBjb2RlCiAgICArIHJlbWVtYmVyLCB5b3Ugb25seSBuZWVkIHRvIGRvIHRoaXMgb25jZSAKICAgIApgYGB7ciBldmFsPUZBTFNFfQppbnN0YWxsLnBhY2thZ2VzKCJSQ29sb3JCcmV3ZXIiKQpgYGAKCgpgYGB7cn0KbGlicmFyeShSQ29sb3JCcmV3ZXIpCmRpc3BsYXkuYnJld2VyLmFsbCgpCmRpc3BsYXkuYnJld2VyLmFsbChjb2xvcmJsaW5kRnJpZW5kbHkgPSBUUlVFKQpgYGAKCmBgYHtyfQp3ZWF0aGVyIDwtIHJlYWQuY3N2KCJvem9uZS5jc3YiKQpib3hwbG90KHdlYXRoZXIkVGVtcCB+IHdlYXRoZXIkTW9udGgsY29sPWJyZXdlci5wYWwoNSwiU2V0MSIpKQpgYGAKCgojRW5kIG9mIERheSAxCgojIyBUbyBjb21lIHRvbW9ycm93Li4uCi0gTW9yZSBjdXN0b21pc2F0aW9uIG9mIHBsb3RzCi0gU3RhdGlzdGljcwotIEZ1cnRoZXIgbWFuaXB1bGF0aW9uIG9mIGRhdGEKLSBSZXBvcnQgd3JpdGluZwo=