Remember, before you can use the tidyverse, you need to load the package.

library(tidyverse)

Coding Basics

R as a Calculator 1

(Taken form R4DS)

  1. Create a sequence using the seq() function starting at 0 and ending at 100 assigning the output to an object called integers
  2. Create a new vector squares which contains the square of every value in integers. Remember most mathematical functions in R act on each element individually. You might want to use the ^ operator.
  3. Create a data frame with these two vectors as columns by running tibble(integers, squares). Assign the output to an object called squares_df
  4. Use ggplot() to produce either a scatter or line plot of these two variables (or both at the same time if you’re feeling brave!)

R as a Calculator 2

  1. Create a new sequence called x containing 1000 numbers spaced uniformly between -6 and 6. You can do this by adding the length.out parameter to seq() and setting it to 1000 (this parameter must be specified by name, inside of the brackets)
  2. Calculate the sine of each value in x using sin() and assign the value to an object called y
  3. Create a dataframe as before and plot a line graph
  4. Change the line colour to any one of your choosing, set the linetype to 2 (dashed), and size to 1.5

Specifying Parameters by Position

  1. Which parameters from the following code can you use without specifying their name?
ggplot(data = mpg) +
  geom_point(mapping = aes(x = displ, y = hwy, colour = factor(class)))

Reading CSVs

The ‘People’ Dataset

  1. Read the people.csv file from this session’s data folder. Make sure you specify that sex and race are factors (categorical variables) and that earn and age are integers.
  2. How does level of education affect salary? Make a scatter plot to find out. You should set position = 'jitter' in the geom_point() function to avoid over-plotting and perhaps also set transparency to 0.5.
  3. Facet the above plot by sex, colouring the points too. Make sure you hide the legend with show.legend = FALSE
  4. Label the plot using the labs() function (see end of exercise sheet one)
  5. Create a new plot showing how earnings change with age. Use geom_smooth() to show the general trend
  6. Set the colour aesthetic in the above plot to represent the race variable. Include errors and set the thickness of each line to 2

In-line CSVs

  1. Read the following in-line CSV into R (Unknown is used here to represent a missing value)
"
Employee Database Version 3

name, age, job
John, 34, Analyst
Ann, 44, Consultant
Barry, 24, Unknown
Freya, Unknown, Developer"
  1. Read the following in-line CSV into R. The columns of this dataset are City, Area, Population. Make sure you don’t try to read the comment line
"
Shanghai, 6341, 24183300
Tokyo, 627, 13515271
Seoul, 605, 9806000
>> Note: Mumbai was previously called Bombai
Mumbai, 438, 12442373"

Datasets from the Web

  1. Go to the following webpage - https://gist.github.com/tiangechen/b68782efa49a16edaf07dc2cdaa855ea - which contains data on the top grossing movies between 2007 and 2011
  2. Select download ZIP extract the CSV file (if this is causing difficulties just use the copy in the data folder)
  3. Import this dataset into R
  4. Run this code to clean up the dataset (we’ll learn how to make code like this next week)
movies <- movies %>%
  mutate(Genre = ifelse(Genre %in% c('Comdy', 'comedy'), 'Comedy', Genre)) %>%
  mutate(Genre = ifelse(Genre %in% c('Romence', 'romance'), 'Romance', Genre)) %>%
  mutate(`Worldwide Gross` = as.double(str_replace(`Worldwide Gross`, '\\$', '')))
  1. Make a scatter plot of Worldwide Gross against Audience score % coloured by Genre. When using a column name with a space you need to surround the name with back-ticks (`)

Line geometries

Groups

  1. Take a look at the built in ChickWeight dataset. What do the columns represent?
  2. Make a line plot of chick weight against time. Group by chick and colour by diet
  3. What happens if you forget to group by chick?
  4. The graph in (2) is very busy. Instead of using geom_line, use geom_smooth with the colour aesthetic set to Diet. There is no need to specify the group in this case - why? Hide the error regions with se=FALSE
  5. Overlay the data points coloured by diet also. Add a jitter to prevent over-fitting and reduce transparency so this doesn’t distract from the trend lines
  6. Label the plot

Smoothing Methods

  1. Create a plot of sepal length against sepal width for each observation in the iris dataset colouring by species
  2. Add a geom_smooth layer with colour mapped to Species still. Inside this call specify method = 'lm'. This tells geom_smooth to use a linear model (straight line) for smoothing.
  3. Other methods include loess and gam. See what these look like
  4. If no method is specified or method = 'auto' is included, a method is chosen automatically. In this case, which method is used?

Going Beyond

Theming Graphs

  1. Using the mpg dataset create any graph of your choosing
  2. Label the graph by adding a title, caption, and axis labels
  3. Add a new layer to the graph using the function theme_minimal()
  4. Try using other themes. Type theme_ and look at the various auto-complete options

ggplot Objects

  1. Run the following code
p <- ggplot(iris, aes(x = Petal.Length, y = Sepal.Length, col = Species)) +
  geom_point()
  1. What do you think this did? What will happen if we type p? Give it a go
  2. Type the following code
p +
  geom_smooth(se = FALSE, method = 'lm')
  1. What did that do? How can you use this to re-use code?

Scripting

  1. In RStudio, select File > New File > R Script
  2. A new panel should open. Type the code required to generate any plot of the Orange dataset (Perhaps circumference against age coloured by tree. Add a trend curve if feeling confident)
  3. On the top bar of the script panel select source > source. What does this do?
  4. Use File > Save to save this script somewhere. (Feel free to delete it after)
LS0tDQp0aXRsZTogIkludG8gdGhlIFRpZHl2ZXJzZSINCnN1YnRpdGxlOiAiU2Vzc2lvbiBUd28gRXhlcmNpc2VzIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KUmVtZW1iZXIsIGJlZm9yZSB5b3UgY2FuIHVzZSB0aGUgdGlkeXZlcnNlLCB5b3UgbmVlZCB0byBsb2FkIHRoZSBwYWNrYWdlLg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpgYGANCg0KIyMgQ29kaW5nIEJhc2ljcw0KDQojIyMgUiBhcyBhIENhbGN1bGF0b3IgMQ0KDQooKipUYWtlbiBmb3JtIFI0RFMqKikNCg0KMS4gQ3JlYXRlIGEgc2VxdWVuY2UgdXNpbmcgdGhlIGBzZXEoKWAgZnVuY3Rpb24gc3RhcnRpbmcgYXQgMCBhbmQgZW5kaW5nIGF0IDEwMCBhc3NpZ25pbmcgdGhlIG91dHB1dCB0byBhbiBvYmplY3QgY2FsbGVkIGBpbnRlZ2Vyc2ANCjIuIENyZWF0ZSBhIG5ldyB2ZWN0b3IgYHNxdWFyZXNgIHdoaWNoIGNvbnRhaW5zIHRoZSBzcXVhcmUgb2YgZXZlcnkgdmFsdWUgaW4gYGludGVnZXJzYC4gUmVtZW1iZXIgbW9zdCBtYXRoZW1hdGljYWwgZnVuY3Rpb25zIGluIFIgYWN0IG9uIGVhY2ggZWxlbWVudCBpbmRpdmlkdWFsbHkuIFlvdSBtaWdodCB3YW50IHRvIHVzZSB0aGUgYF5gIG9wZXJhdG9yLg0KMy4gQ3JlYXRlIGEgZGF0YSBmcmFtZSB3aXRoIHRoZXNlIHR3byB2ZWN0b3JzIGFzIGNvbHVtbnMgYnkgcnVubmluZyBgdGliYmxlKGludGVnZXJzLCBzcXVhcmVzKWAuIEFzc2lnbiB0aGUgb3V0cHV0IHRvIGFuIG9iamVjdCBjYWxsZWQgYHNxdWFyZXNfZGZgDQo0LiBVc2UgYGdncGxvdCgpYCB0byBwcm9kdWNlIGVpdGhlciBhIHNjYXR0ZXIgb3IgbGluZSBwbG90IG9mIHRoZXNlIHR3byB2YXJpYWJsZXMgKG9yIGJvdGggYXQgdGhlIHNhbWUgdGltZSBpZiB5b3UncmUgZmVlbGluZyBicmF2ZSEpDQoNCiMjIyBSIGFzIGEgQ2FsY3VsYXRvciAyDQoNCjEuIENyZWF0ZSBhIG5ldyBzZXF1ZW5jZSBjYWxsZWQgYHhgIGNvbnRhaW5pbmcgMTAwMCBudW1iZXJzIHNwYWNlZCB1bmlmb3JtbHkgYmV0d2VlbiAtNiBhbmQgNi4gWW91IGNhbiBkbyB0aGlzIGJ5IGFkZGluZyB0aGUgYGxlbmd0aC5vdXRgIHBhcmFtZXRlciB0byBgc2VxKClgIGFuZCBzZXR0aW5nIGl0IHRvIGAxMDAwYCAodGhpcyBwYXJhbWV0ZXIgbXVzdCBiZSBzcGVjaWZpZWQgYnkgbmFtZSwgaW5zaWRlIG9mIHRoZSBicmFja2V0cykNCjIuIENhbGN1bGF0ZSB0aGUgc2luZSBvZiBlYWNoIHZhbHVlIGluIGB4YCB1c2luZyBgc2luKClgIGFuZCBhc3NpZ24gdGhlIHZhbHVlIHRvIGFuIG9iamVjdCBjYWxsZWQgYHlgDQozLiBDcmVhdGUgYSBkYXRhZnJhbWUgYXMgYmVmb3JlIGFuZCBwbG90IGEgbGluZSBncmFwaA0KNC4gQ2hhbmdlIHRoZSBsaW5lIGNvbG91ciB0byBhbnkgb25lIG9mIHlvdXIgY2hvb3NpbmcsIHNldCB0aGUgYGxpbmV0eXBlYCB0byBgMmAgKGRhc2hlZCksIGFuZCBgc2l6ZWAgdG8gMS41DQoNCiMjIyBTcGVjaWZ5aW5nIFBhcmFtZXRlcnMgYnkgUG9zaXRpb24NCg0KMS4gV2hpY2ggcGFyYW1ldGVycyBmcm9tIHRoZSBmb2xsb3dpbmcgY29kZSBjYW4geW91IHVzZSB3aXRob3V0IHNwZWNpZnlpbmcgdGhlaXIgbmFtZT8gDQoNCmBgYHtyIGV2YWw9RkFMU0V9DQpnZ3Bsb3QoZGF0YSA9IG1wZykgKw0KICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5LCBjb2xvdXIgPSBmYWN0b3IoY2xhc3MpKSkNCmBgYA0KDQojIyBSZWFkaW5nIENTVnMNCg0KIyMjIFRoZSAnUGVvcGxlJyBEYXRhc2V0DQoNCjEuIFJlYWQgdGhlIGBwZW9wbGUuY3N2YCBmaWxlIGZyb20gdGhpcyBzZXNzaW9uJ3MgYGRhdGFgIGZvbGRlci4gTWFrZSBzdXJlIHlvdSBzcGVjaWZ5IHRoYXQgYHNleGAgYW5kIGByYWNlYCBhcmUgZmFjdG9ycyAoY2F0ZWdvcmljYWwgdmFyaWFibGVzKSBhbmQgdGhhdCBgZWFybmAgYW5kIGBhZ2VgIGFyZSBpbnRlZ2Vycy4NCjIuIEhvdyBkb2VzIGxldmVsIG9mIGVkdWNhdGlvbiBhZmZlY3Qgc2FsYXJ5PyBNYWtlIGEgc2NhdHRlciBwbG90IHRvIGZpbmQgb3V0LiBZb3Ugc2hvdWxkIHNldCBgcG9zaXRpb24gPSAnaml0dGVyJ2AgaW4gdGhlIGBnZW9tX3BvaW50KClgIGZ1bmN0aW9uIHRvIGF2b2lkIG92ZXItcGxvdHRpbmcgYW5kIHBlcmhhcHMgYWxzbyBzZXQgdHJhbnNwYXJlbmN5IHRvIGAwLjVgLg0KMy4gRmFjZXQgdGhlIGFib3ZlIHBsb3QgYnkgYHNleGAsIGNvbG91cmluZyB0aGUgcG9pbnRzIHRvby4gTWFrZSBzdXJlIHlvdSBoaWRlIHRoZSBsZWdlbmQgd2l0aCBgc2hvdy5sZWdlbmQgPSBGQUxTRWANCjQuIExhYmVsIHRoZSBwbG90IHVzaW5nIHRoZSBgbGFicygpYCBmdW5jdGlvbiAoc2VlIGVuZCBvZiBleGVyY2lzZSBzaGVldCBvbmUpDQo1LiBDcmVhdGUgYSBuZXcgcGxvdCBzaG93aW5nIGhvdyBlYXJuaW5ncyBjaGFuZ2Ugd2l0aCBhZ2UuIFVzZSBgZ2VvbV9zbW9vdGgoKWAgdG8gc2hvdyB0aGUgZ2VuZXJhbCB0cmVuZCANCjYuIFNldCB0aGUgY29sb3VyIGFlc3RoZXRpYyBpbiB0aGUgYWJvdmUgcGxvdCB0byByZXByZXNlbnQgdGhlIGByYWNlYCB2YXJpYWJsZS4gSW5jbHVkZSBlcnJvcnMgYW5kIHNldCB0aGUgdGhpY2tuZXNzIG9mIGVhY2ggbGluZSB0byBgMmANCg0KIyMjIEluLWxpbmUgQ1NWcw0KDQoxLiBSZWFkIHRoZSBmb2xsb3dpbmcgaW4tbGluZSBDU1YgaW50byBSIChVbmtub3duIGlzIHVzZWQgaGVyZSB0byByZXByZXNlbnQgYSBtaXNzaW5nIHZhbHVlKQ0KDQpgYGB7ciBldmFsPUZBTFNFfQ0KIg0KRW1wbG95ZWUgRGF0YWJhc2UgVmVyc2lvbiAzDQoNCm5hbWUsIGFnZSwgam9iDQpKb2huLCAzNCwgQW5hbHlzdA0KQW5uLCA0NCwgQ29uc3VsdGFudA0KQmFycnksIDI0LCBVbmtub3duDQpGcmV5YSwgVW5rbm93biwgRGV2ZWxvcGVyIg0KYGBgDQoNCjIuIFJlYWQgdGhlIGZvbGxvd2luZyBpbi1saW5lIENTViBpbnRvIFIuIFRoZSBjb2x1bW5zIG9mIHRoaXMgZGF0YXNldCBhcmUgYENpdHlgLCBgQXJlYWAsIGBQb3B1bGF0aW9uYC4gTWFrZSBzdXJlIHlvdSBkb24ndCB0cnkgdG8gcmVhZCB0aGUgY29tbWVudCBsaW5lDQoNCmBgYHtyIGV2YWw9RkFMU0V9DQoiDQpTaGFuZ2hhaSwgNjM0MSwgMjQxODMzMDANClRva3lvLCA2MjcsIDEzNTE1MjcxDQpTZW91bCwgNjA1LCA5ODA2MDAwDQo+PiBOb3RlOiBNdW1iYWkgd2FzIHByZXZpb3VzbHkgY2FsbGVkIEJvbWJhaQ0KTXVtYmFpLCA0MzgsIDEyNDQyMzczIg0KYGBgDQoNCiMjIyBEYXRhc2V0cyBmcm9tIHRoZSBXZWINCg0KMS4gR28gdG8gdGhlIGZvbGxvd2luZyB3ZWJwYWdlIC0gaHR0cHM6Ly9naXN0LmdpdGh1Yi5jb20vdGlhbmdlY2hlbi9iNjg3ODJlZmE0OWExNmVkYWYwN2RjMmNkYWE4NTVlYSAtIHdoaWNoIGNvbnRhaW5zIGRhdGEgb24gdGhlIHRvcCBncm9zc2luZyBtb3ZpZXMgYmV0d2VlbiAyMDA3IGFuZCAyMDExDQoyLiBTZWxlY3QgYGRvd25sb2FkIFpJUGAgZXh0cmFjdCB0aGUgQ1NWIGZpbGUgKGlmIHRoaXMgaXMgY2F1c2luZyBkaWZmaWN1bHRpZXMganVzdCB1c2UgdGhlIGNvcHkgaW4gdGhlIGBkYXRhYCBmb2xkZXIpDQozLiBJbXBvcnQgdGhpcyBkYXRhc2V0IGludG8gUg0KNC4gUnVuIHRoaXMgY29kZSB0byBjbGVhbiB1cCB0aGUgZGF0YXNldCAod2UnbGwgbGVhcm4gaG93IHRvIG1ha2UgY29kZSBsaWtlIHRoaXMgbmV4dCB3ZWVrKQ0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCm1vdmllcyA8LSBtb3ZpZXMgJT4lDQogIG11dGF0ZShHZW5yZSA9IGlmZWxzZShHZW5yZSAlaW4lIGMoJ0NvbWR5JywgJ2NvbWVkeScpLCAnQ29tZWR5JywgR2VucmUpKSAlPiUNCiAgbXV0YXRlKEdlbnJlID0gaWZlbHNlKEdlbnJlICVpbiUgYygnUm9tZW5jZScsICdyb21hbmNlJyksICdSb21hbmNlJywgR2VucmUpKSAlPiUNCiAgbXV0YXRlKGBXb3JsZHdpZGUgR3Jvc3NgID0gYXMuZG91YmxlKHN0cl9yZXBsYWNlKGBXb3JsZHdpZGUgR3Jvc3NgLCAnXFwkJywgJycpKSkNCmBgYA0KDQo1LiBNYWtlIGEgc2NhdHRlciBwbG90IG9mIGBXb3JsZHdpZGUgR3Jvc3NgIGFnYWluc3QgYEF1ZGllbmNlIHNjb3JlICVgIGNvbG91cmVkIGJ5IGBHZW5yZWAuIFdoZW4gdXNpbmcgYSBjb2x1bW4gbmFtZSB3aXRoIGEgc3BhY2UgeW91IG5lZWQgdG8gc3Vycm91bmQgdGhlIG5hbWUgd2l0aCBiYWNrLXRpY2tzIChcYCkNCg0KIyMgTGluZSBnZW9tZXRyaWVzDQoNCiMjIyBHcm91cHMNCg0KMS4gVGFrZSBhIGxvb2sgYXQgdGhlIGJ1aWx0IGluIGBDaGlja1dlaWdodGAgZGF0YXNldC4gV2hhdCBkbyB0aGUgY29sdW1ucyByZXByZXNlbnQ/DQoyLiBNYWtlIGEgbGluZSBwbG90IG9mIGNoaWNrIHdlaWdodCBhZ2FpbnN0IHRpbWUuIEdyb3VwIGJ5IGNoaWNrIGFuZCBjb2xvdXIgYnkgZGlldA0KMy4gV2hhdCBoYXBwZW5zIGlmIHlvdSBmb3JnZXQgdG8gZ3JvdXAgYnkgY2hpY2s/DQo0LiBUaGUgZ3JhcGggaW4gKDIpIGlzIHZlcnkgYnVzeS4gSW5zdGVhZCBvZiB1c2luZyBgZ2VvbV9saW5lYCwgdXNlIGBnZW9tX3Ntb290aGAgd2l0aCB0aGUgY29sb3VyIGFlc3RoZXRpYyBzZXQgdG8gYERpZXRgLiBUaGVyZSBpcyBubyBuZWVkIHRvIHNwZWNpZnkgdGhlIGdyb3VwIGluIHRoaXMgY2FzZSAtIHdoeT8gSGlkZSB0aGUgZXJyb3IgcmVnaW9ucyB3aXRoIGBzZT1GQUxTRWANCjUuIE92ZXJsYXkgdGhlIGRhdGEgcG9pbnRzIGNvbG91cmVkIGJ5IGRpZXQgYWxzby4gQWRkIGEgaml0dGVyIHRvIHByZXZlbnQgb3Zlci1maXR0aW5nIGFuZCByZWR1Y2UgdHJhbnNwYXJlbmN5IHNvIHRoaXMgZG9lc24ndCBkaXN0cmFjdCBmcm9tIHRoZSB0cmVuZCBsaW5lcw0KNi4gTGFiZWwgdGhlIHBsb3QNCg0KIyMjIFNtb290aGluZyBNZXRob2RzDQoNCjEuIENyZWF0ZSBhIHBsb3Qgb2Ygc2VwYWwgbGVuZ3RoIGFnYWluc3Qgc2VwYWwgd2lkdGggZm9yIGVhY2ggb2JzZXJ2YXRpb24gaW4gdGhlIGBpcmlzYCBkYXRhc2V0IGNvbG91cmluZyBieSBzcGVjaWVzDQoyLiBBZGQgYSBgZ2VvbV9zbW9vdGhgIGxheWVyIHdpdGggY29sb3VyIG1hcHBlZCB0byBTcGVjaWVzIHN0aWxsLiBJbnNpZGUgdGhpcyBjYWxsIHNwZWNpZnkgYG1ldGhvZCA9ICdsbSdgLiBUaGlzIHRlbGxzIGBnZW9tX3Ntb290aGAgdG8gdXNlIGEgKipsKippbmVhciAqKm1vZGVsKiogKHN0cmFpZ2h0IGxpbmUpIGZvciBzbW9vdGhpbmcuDQozLiBPdGhlciBtZXRob2RzIGluY2x1ZGUgYGxvZXNzYCBhbmQgYGdhbWAuIFNlZSB3aGF0IHRoZXNlIGxvb2sgbGlrZQ0KNC4gSWYgbm8gbWV0aG9kIGlzIHNwZWNpZmllZCBvciBgbWV0aG9kID0gJ2F1dG8nYCBpcyBpbmNsdWRlZCwgYSBtZXRob2QgaXMgY2hvc2VuIGF1dG9tYXRpY2FsbHkuIEluIHRoaXMgY2FzZSwgd2hpY2ggbWV0aG9kIGlzIHVzZWQ/DQoNCiMjIEdvaW5nIEJleW9uZA0KDQojIyMgVGhlbWluZyBHcmFwaHMNCg0KMS4gVXNpbmcgdGhlIGBtcGdgIGRhdGFzZXQgY3JlYXRlIGFueSBncmFwaCBvZiB5b3VyIGNob29zaW5nDQoyLiBMYWJlbCB0aGUgZ3JhcGggYnkgYWRkaW5nIGEgdGl0bGUsIGNhcHRpb24sIGFuZCBheGlzIGxhYmVscw0KMy4gQWRkIGEgbmV3IGxheWVyIHRvIHRoZSBncmFwaCB1c2luZyB0aGUgZnVuY3Rpb24gYHRoZW1lX21pbmltYWwoKWANCjQuIFRyeSB1c2luZyBvdGhlciB0aGVtZXMuIFR5cGUgYHRoZW1lX2AgYW5kIGxvb2sgYXQgdGhlIHZhcmlvdXMgYXV0by1jb21wbGV0ZSBvcHRpb25zDQoNCiMjIyBnZ3Bsb3QgT2JqZWN0cw0KDQoxLiBSdW4gdGhlIGZvbGxvd2luZyBjb2RlDQoNCmBgYHtyIGV2YWw9RkFMU0V9DQpwIDwtIGdncGxvdChpcmlzLCBhZXMoeCA9IFBldGFsLkxlbmd0aCwgeSA9IFNlcGFsLkxlbmd0aCwgY29sID0gU3BlY2llcykpICsNCiAgZ2VvbV9wb2ludCgpDQpgYGANCg0KMi4gV2hhdCBkbyB5b3UgdGhpbmsgdGhpcyBkaWQ/IFdoYXQgd2lsbCBoYXBwZW4gaWYgd2UgdHlwZSBgcGA/IEdpdmUgaXQgYSBnbw0KMy4gVHlwZSB0aGUgZm9sbG93aW5nIGNvZGUNCg0KYGBge3IgZXZhbD1GQUxTRX0NCnAgKw0KICBnZW9tX3Ntb290aChzZSA9IEZBTFNFLCBtZXRob2QgPSAnbG0nKQ0KYGBgDQoNCjQuIFdoYXQgZGlkIHRoYXQgZG8/IEhvdyBjYW4geW91IHVzZSB0aGlzIHRvIHJlLXVzZSBjb2RlPw0KDQojIyMgU2NyaXB0aW5nDQoNCjEuIEluIFJTdHVkaW8sIHNlbGVjdCBgRmlsZSA+IE5ldyBGaWxlID4gUiBTY3JpcHRgDQoyLiBBIG5ldyBwYW5lbCBzaG91bGQgb3Blbi4gVHlwZSB0aGUgY29kZSByZXF1aXJlZCB0byBnZW5lcmF0ZSBhbnkgcGxvdCBvZiB0aGUgYE9yYW5nZWAgZGF0YXNldCAoUGVyaGFwcyBjaXJjdW1mZXJlbmNlIGFnYWluc3QgYWdlIGNvbG91cmVkIGJ5IHRyZWUuIEFkZCBhIHRyZW5kIGN1cnZlIGlmIGZlZWxpbmcgY29uZmlkZW50KQ0KMy4gT24gdGhlIHRvcCBiYXIgb2YgdGhlIHNjcmlwdCBwYW5lbCBzZWxlY3QgYHNvdXJjZSA+IHNvdXJjZWAuIFdoYXQgZG9lcyB0aGlzIGRvPyANCjQuIFVzZSBgRmlsZSA+IFNhdmVgIHRvIHNhdmUgdGhpcyBzY3JpcHQgc29tZXdoZXJlLiAoRmVlbCBmcmVlIHRvIGRlbGV0ZSBpdCBhZnRlcikNCg==