A good coding style is like using correct punctuation. You can manage without it, but it sure makes things easier to read. The following guide describes the style that I use. It is based on Google’s R style guide and “Advanced R, by Hadley Wickham”, with a few tweaks. The goal of the R Programming Style Guide is to make our R code easier to read, share, and verify.


Notation and naming


File names

File names should be meaningful and end in .R.

# Good
 fit-models.R
 utility_functions.R

# Bad
 foo.r
 stuff.r

If files need to be run in sequence, prefix them with numbers:

0-download.R
1-parse.R
2-explore.R

Object names

“There are only two hard things in Computer Science: cache invalidation and naming things.” - Phil Karlton

Variable and function names should be lowercase. Use an underscore (_) to separate words within a name. Generally, variable names should be nouns and function names should be verbs. Strive for names that are concise and meaningful (this is not easy!).

# Good
day_one
day_1
dayOne

# Bad
first_day_of_the_month
dayone
djm1

Where possible, avoid using names of existing functions and variables. Doing so will cause confusion for the readers of your code.

# Bad
T <- FALSE
c <- 10
mean <- function(x) sum(x)

Syntax


Spacing

Place spaces around all infix operators (=, +, -, <-, etc.). The same rule applies when using = in function calls. Always put a space after a comma, and never before (just like in regular English).

# Good
average <- mean(feet / 12 + inches, na.rm = TRUE)

# Bad
average<-mean(feet/12+inches,na.rm=TRUE)

There’s a small exception to this rule: :, :: and ::: don’t need spaces around them.

# Good
x <- 1:10
base::get

# Bad
x <- 1 : 10
base :: get

Place a space before left parentheses, except in a function call.

# Good
if (debug) do(x)
plot(x, y)

# Bad
if(debug)do(x)
plot (x, y)

Extra spacing (i.e., more than one space in a row) is ok if it improves alignment of equal signs or assignments (<-).

list(
  total = a + b + c, 
  mean  = (a + b + c) / n
)

Do not place spaces around code in parentheses or square brackets (unless there’s a comma, in which case see above).

# Good
if (debug) do(x)
diamonds[5, ]

# Bad
if ( debug ) do(x)  # No spaces around debug
x[1,]   # Needs a space after the comma
x[1 ,]  # Space goes after comma not before

Curly braces

An opening curly brace should never go on its own line and should always be followed by a new line. A closing curly brace should always go on its own line, unless it’s followed by else.

Always indent the code inside curly braces.

# Good

if (y < 0 && debug) {
  message("Y is negative")
}

if (y == 0) {
  log(x)
} else {
  y ^ x
}

# Bad

if (y < 0 && debug)
message("Y is negative")

if (y == 0) {
  log(x)
} 
  else {
  y ^ x
}

It’s ok to leave very short statements on the same line:

if (y < 0 && debug) message("Y is negative")

Line length

Strive to limit your code to 80 characters per line. This fits comfortably on a printed page with a reasonably sized font. If you find yourself running out of room, this is a good indication that you should encapsulate some of the work in a separate function.

Indentation

When indenting your code, use two spaces. Never use tabs or mix tabs and spaces.

The only exception is if a function definition runs over multiple lines. In that case, indent the second line to where the definition starts:

long_function_name <- function(a = "a long argument", 
                               b = "another argument",
                               c = "another long argument") {
  # As usual code is indented by two spaces.
}

Assignment

Use <-, not =, for assignment.

# Good
x <- 5
# Bad
x = 5

Organisation


Commenting guidelines

Comment your code. Each line of a comment should begin with the comment symbol and a single space: #. Comments should explain the why, not the what. Short comments can be placed after code preceded by two spaces, #, and then one space.

Use commented lines of - and = to break up your file into easily readable chunks.

# Load data ---------------------------

# Plot data ---------------------------

Function Definitions and Calls

Function definitions should first list arguments without default values, followed by those with default values.

In both function definitions and function calls, multiple arguments per line are allowed; line breaks are only allowed between assignments.

# Good
PredictCTR <- function(query, property, num.days,
                       show.plot = TRUE)
# Bad
PredictCTR <- function(query, property, num.days, show.plot =
                       TRUE)

Function Documentation

Functions should contain a comments section immediately below the function definition line. These comments should consist of a one-sentence description of the function; a list of the function’s arguments, denoted by Args:, with a description of each (including the data type); and a description of the return value, denoted by Returns:. The comments should be descriptive enough that a caller can use the function without reading any of the function’s code.

CalculateSampleCovariance <- function(x, y, verbose = TRUE) {
  # Computes the sample covariance between two vectors.
  #
  # Args:
  #   x: One of two vectors whose sample covariance is to be calculated.
  #   y: The other vector. x and y must have the same length, greater than one,
  #      with no missing values.
  #   verbose: If TRUE, prints sample covariance; if not, not. Default is TRUE.
  #
  # Returns:
  #   The sample covariance between x and y.
  n <- length(x)
  # Error handling
  if (n <= 1 || n != length(y)) {
    stop("Arguments x and y have different lengths: ",
         length(x), " and ", length(y), ".")
  }
  if (TRUE %in% is.na(x) || TRUE %in% is.na(y)) {
    stop(" Arguments x and y must not have missing values.")
  }
  covariance <- var(x, y)
  if (verbose)
    cat("Covariance = ", round(covariance, 4), ".\n", sep = "")
  return(covariance)
}

Enjoy R!

LS0tDQp0aXRsZTogIlIgQ29kaW5nIFN0eWxlIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KQSBnb29kIGNvZGluZyBzdHlsZSBpcyBsaWtlIHVzaW5nICoqY29ycmVjdCBwdW5jdHVhdGlvbioqLiBZb3UgY2FuIG1hbmFnZSB3aXRob3V0IGl0LCBidXQgaXQgc3VyZSBtYWtlcyB0aGluZ3MgKiplYXNpZXIgdG8gcmVhZCoqLiBUaGUgZm9sbG93aW5nIGd1aWRlIGRlc2NyaWJlcyB0aGUgc3R5bGUgdGhhdCBJIHVzZS4gSXQgaXMgYmFzZWQgb24gR29vZ2xlJ3MgUiBzdHlsZSBndWlkZSBhbmQgIkFkdmFuY2VkIFIsIGJ5IEhhZGxleSBXaWNraGFtIiwgd2l0aCBhIGZldyB0d2Vha3MuIFRoZSBnb2FsIG9mIHRoZSBSIFByb2dyYW1taW5nIFN0eWxlIEd1aWRlIGlzIHRvIG1ha2Ugb3VyIFIgY29kZSAqKmVhc2llciB0byByZWFkLCBzaGFyZSwgYW5kIHZlcmlmeSoqLiANCg0KKioqDQojI05vdGF0aW9uIGFuZCBuYW1pbmcNCioqKg0KIyMjRmlsZSBuYW1lcw0KDQpGaWxlIG5hbWVzIHNob3VsZCBiZSBtZWFuaW5nZnVsIGFuZCBlbmQgaW4gKiouUioqLg0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCiMgR29vZA0KIGZpdC1tb2RlbHMuUg0KIHV0aWxpdHlfZnVuY3Rpb25zLlINCg0KIyBCYWQNCiBmb28ucg0KIHN0dWZmLnINCg0KYGBgDQoNCklmIGZpbGVzIG5lZWQgdG8gYmUgcnVuIGluIHNlcXVlbmNlLCBwcmVmaXggdGhlbSB3aXRoIG51bWJlcnM6DQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KMC1kb3dubG9hZC5SDQoxLXBhcnNlLlINCjItZXhwbG9yZS5SDQoNCmBgYA0KDQojIyNPYmplY3QgbmFtZXMNCg0KPiJUaGVyZSBhcmUgb25seSB0d28gaGFyZCB0aGluZ3MgaW4gQ29tcHV0ZXIgU2NpZW5jZTogY2FjaGUgaW52YWxpZGF0aW9uIGFuZCBuYW1pbmcgdGhpbmdzLiINCi0gUGhpbCBLYXJsdG9uDQoNClZhcmlhYmxlIGFuZCBmdW5jdGlvbiBuYW1lcyBzaG91bGQgYmUgbG93ZXJjYXNlLiBVc2UgYW4gdW5kZXJzY29yZSAoXykgdG8gc2VwYXJhdGUgd29yZHMgd2l0aGluIGEgbmFtZS4gR2VuZXJhbGx5LCAqKnZhcmlhYmxlKiogbmFtZXMgc2hvdWxkIGJlICoqbm91bnMqKiBhbmQgKipmdW5jdGlvbioqIG5hbWVzIHNob3VsZCBiZSAqKnZlcmJzKiouIFN0cml2ZSBmb3IgbmFtZXMgdGhhdCBhcmUgY29uY2lzZSBhbmQgbWVhbmluZ2Z1bCAodGhpcyBpcyBub3QgZWFzeSEpLg0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCiMgR29vZA0KZGF5X29uZQ0KZGF5XzENCmRheU9uZQ0KDQojIEJhZA0KZmlyc3RfZGF5X29mX3RoZV9tb250aA0KZGF5b25lDQpkam0xDQoNCmBgYA0KDQpXaGVyZSBwb3NzaWJsZSwgYXZvaWQgdXNpbmcgbmFtZXMgb2YgZXhpc3RpbmcgZnVuY3Rpb25zIGFuZCB2YXJpYWJsZXMuIERvaW5nIHNvIHdpbGwgY2F1c2UgY29uZnVzaW9uIGZvciB0aGUgcmVhZGVycyBvZiB5b3VyIGNvZGUuDQoNCmBgYHtyfQ0KIyBCYWQNClQgPC0gRkFMU0UNCmMgPC0gMTANCm1lYW4gPC0gZnVuY3Rpb24oeCkgc3VtKHgpDQoNCmBgYA0KDQoqKioNCiMjU3ludGF4DQoqKioNCiMjI1NwYWNpbmcNCg0KUGxhY2Ugc3BhY2VzIGFyb3VuZCBhbGwgaW5maXggb3BlcmF0b3JzICg9LCArLCAtLCA8LSwgZXRjLikuIFRoZSBzYW1lIHJ1bGUgYXBwbGllcyB3aGVuIHVzaW5nID0gaW4gZnVuY3Rpb24gY2FsbHMuIEFsd2F5cyBwdXQgYSBzcGFjZSBhZnRlciBhIGNvbW1hLCBhbmQgbmV2ZXIgYmVmb3JlIChqdXN0IGxpa2UgaW4gcmVndWxhciBFbmdsaXNoKS4NCg0KYGBge3IsIGV2YWw9RkFMU0V9DQojIEdvb2QNCmF2ZXJhZ2UgPC0gbWVhbihmZWV0IC8gMTIgKyBpbmNoZXMsIG5hLnJtID0gVFJVRSkNCg0KIyBCYWQNCmF2ZXJhZ2U8LW1lYW4oZmVldC8xMitpbmNoZXMsbmEucm09VFJVRSkNCg0KYGBgDQoNClRoZXJlJ3MgYSBzbWFsbCBleGNlcHRpb24gdG8gdGhpcyBydWxlOiA6LCA6OiBhbmQgOjo6IGRvbid0IG5lZWQgc3BhY2VzIGFyb3VuZCB0aGVtLg0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCiMgR29vZA0KeCA8LSAxOjEwDQpiYXNlOjpnZXQNCg0KIyBCYWQNCnggPC0gMSA6IDEwDQpiYXNlIDo6IGdldA0KDQpgYGANCg0KUGxhY2UgYSBzcGFjZSBiZWZvcmUgbGVmdCBwYXJlbnRoZXNlcywgZXhjZXB0IGluIGEgZnVuY3Rpb24gY2FsbC4NCg0KYGBge3IsIGV2YWw9RkFMU0V9DQojIEdvb2QNCmlmIChkZWJ1ZykgZG8oeCkNCnBsb3QoeCwgeSkNCg0KIyBCYWQNCmlmKGRlYnVnKWRvKHgpDQpwbG90ICh4LCB5KQ0KDQpgYGANCg0KRXh0cmEgc3BhY2luZyAoaS5lLiwgbW9yZSB0aGFuIG9uZSBzcGFjZSBpbiBhIHJvdykgaXMgb2sgaWYgaXQgaW1wcm92ZXMgYWxpZ25tZW50IG9mIGVxdWFsIHNpZ25zIG9yIGFzc2lnbm1lbnRzICg8LSkuDQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KbGlzdCgNCiAgdG90YWwgPSBhICsgYiArIGMsIA0KICBtZWFuICA9IChhICsgYiArIGMpIC8gbg0KKQ0KYGBgDQoNCkRvIG5vdCBwbGFjZSBzcGFjZXMgYXJvdW5kIGNvZGUgaW4gcGFyZW50aGVzZXMgb3Igc3F1YXJlIGJyYWNrZXRzICh1bmxlc3MgdGhlcmUncyBhIGNvbW1hLCBpbiB3aGljaCBjYXNlIHNlZSBhYm92ZSkuDQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KIyBHb29kDQppZiAoZGVidWcpIGRvKHgpDQpkaWFtb25kc1s1LCBdDQoNCiMgQmFkDQppZiAoIGRlYnVnICkgZG8oeCkgICMgTm8gc3BhY2VzIGFyb3VuZCBkZWJ1Zw0KeFsxLF0gICAjIE5lZWRzIGEgc3BhY2UgYWZ0ZXIgdGhlIGNvbW1hDQp4WzEgLF0gICMgU3BhY2UgZ29lcyBhZnRlciBjb21tYSBub3QgYmVmb3JlDQpgYGANCg0KIyMjQ3VybHkgYnJhY2VzDQoNCkFuIG9wZW5pbmcgY3VybHkgYnJhY2Ugc2hvdWxkIG5ldmVyIGdvIG9uIGl0cyBvd24gbGluZSBhbmQgc2hvdWxkIGFsd2F5cyBiZSBmb2xsb3dlZCBieSBhIG5ldyBsaW5lLiBBIGNsb3NpbmcgY3VybHkgYnJhY2Ugc2hvdWxkIGFsd2F5cyBnbyBvbiBpdHMgb3duIGxpbmUsIHVubGVzcyBpdCdzIGZvbGxvd2VkIGJ5IGVsc2UuDQoNCkFsd2F5cyBpbmRlbnQgdGhlIGNvZGUgaW5zaWRlIGN1cmx5IGJyYWNlcy4NCg0KYGBge3IsIGV2YWw9RkFMU0V9DQoNCiMgR29vZA0KDQppZiAoeSA8IDAgJiYgZGVidWcpIHsNCiAgbWVzc2FnZSgiWSBpcyBuZWdhdGl2ZSIpDQp9DQoNCmlmICh5ID09IDApIHsNCiAgbG9nKHgpDQp9IGVsc2Ugew0KICB5IF4geA0KfQ0KDQojIEJhZA0KDQppZiAoeSA8IDAgJiYgZGVidWcpDQptZXNzYWdlKCJZIGlzIG5lZ2F0aXZlIikNCg0KaWYgKHkgPT0gMCkgew0KICBsb2coeCkNCn0gDQogIGVsc2Ugew0KICB5IF4geA0KfQ0KDQpgYGANCg0KSXQncyBvayB0byBsZWF2ZSB2ZXJ5IHNob3J0IHN0YXRlbWVudHMgb24gdGhlIHNhbWUgbGluZToNCg0KYGBge3IsIGV2YWw9RkFMU0V9DQppZiAoeSA8IDAgJiYgZGVidWcpIG1lc3NhZ2UoIlkgaXMgbmVnYXRpdmUiKQ0KYGBgDQoNCiMjI0xpbmUgbGVuZ3RoDQoNClN0cml2ZSB0byBsaW1pdCB5b3VyIGNvZGUgdG8gKio4MCBjaGFyYWN0ZXJzIHBlciBsaW5lKiouIFRoaXMgZml0cyBjb21mb3J0YWJseSBvbiBhIHByaW50ZWQgcGFnZSB3aXRoIGEgcmVhc29uYWJseSBzaXplZCBmb250LiBJZiB5b3UgZmluZCB5b3Vyc2VsZiBydW5uaW5nIG91dCBvZiByb29tLCB0aGlzIGlzIGEgZ29vZCBpbmRpY2F0aW9uIHRoYXQgeW91IHNob3VsZCBlbmNhcHN1bGF0ZSBzb21lIG9mIHRoZSB3b3JrIGluIGEgc2VwYXJhdGUgZnVuY3Rpb24uDQoNCiMjI0luZGVudGF0aW9uDQoNCldoZW4gaW5kZW50aW5nIHlvdXIgY29kZSwgdXNlICoqdHdvIHNwYWNlcyoqLiBOZXZlciB1c2UgdGFicyBvciBtaXggdGFicyBhbmQgc3BhY2VzLg0KDQpUaGUgb25seSBleGNlcHRpb24gaXMgaWYgYSBmdW5jdGlvbiBkZWZpbml0aW9uIHJ1bnMgb3ZlciBtdWx0aXBsZSBsaW5lcy4gSW4gdGhhdCBjYXNlLCBpbmRlbnQgdGhlIHNlY29uZCBsaW5lIHRvIHdoZXJlIHRoZSBkZWZpbml0aW9uIHN0YXJ0czoNCg0KYGBge3IsIGV2YWw9RkFMU0V9DQoNCmxvbmdfZnVuY3Rpb25fbmFtZSA8LSBmdW5jdGlvbihhID0gImEgbG9uZyBhcmd1bWVudCIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGIgPSAiYW5vdGhlciBhcmd1bWVudCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYyA9ICJhbm90aGVyIGxvbmcgYXJndW1lbnQiKSB7DQogICMgQXMgdXN1YWwgY29kZSBpcyBpbmRlbnRlZCBieSB0d28gc3BhY2VzLg0KfQ0KDQpgYGANCg0KIyMjQXNzaWdubWVudA0KDQpVc2UgPC0sIG5vdCA9LCBmb3IgYXNzaWdubWVudC4NCg0KYGBge3IsIGV2YWw9RkFMU0V9DQojIEdvb2QNCnggPC0gNQ0KIyBCYWQNCnggPSA1DQoNCmBgYA0KDQoqKioNCiMjT3JnYW5pc2F0aW9uDQoqKioNCiMjI0NvbW1lbnRpbmcgZ3VpZGVsaW5lcw0KDQpDb21tZW50IHlvdXIgY29kZS4gRWFjaCBsaW5lIG9mIGEgY29tbWVudCBzaG91bGQgYmVnaW4gd2l0aCB0aGUgY29tbWVudCBzeW1ib2wgYW5kIGEgc2luZ2xlIHNwYWNlOiAjLiAqKkNvbW1lbnRzIHNob3VsZCBleHBsYWluIHRoZSB3aHksIG5vdCB0aGUgd2hhdCoqLiBTaG9ydCBjb21tZW50cyBjYW4gYmUgcGxhY2VkIGFmdGVyIGNvZGUgcHJlY2VkZWQgYnkgdHdvIHNwYWNlcywgIywgYW5kIHRoZW4gb25lIHNwYWNlLg0KDQpVc2UgY29tbWVudGVkIGxpbmVzIG9mIC0gYW5kID0gdG8gYnJlYWsgdXAgeW91ciBmaWxlIGludG8gZWFzaWx5IHJlYWRhYmxlIGNodW5rcy4NCg0KYGBge3IsIGV2YWw9RkFMU0V9DQoNCiMgTG9hZCBkYXRhIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQojIFBsb3QgZGF0YSAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCmBgYA0KDQojIyNGdW5jdGlvbiBEZWZpbml0aW9ucyBhbmQgQ2FsbHMNCg0KRnVuY3Rpb24gZGVmaW5pdGlvbnMgc2hvdWxkIGZpcnN0IGxpc3QgYXJndW1lbnRzIHdpdGhvdXQgZGVmYXVsdCB2YWx1ZXMsIGZvbGxvd2VkIGJ5IHRob3NlIHdpdGggZGVmYXVsdCB2YWx1ZXMuDQoNCkluIGJvdGggZnVuY3Rpb24gZGVmaW5pdGlvbnMgYW5kIGZ1bmN0aW9uIGNhbGxzLCBtdWx0aXBsZSBhcmd1bWVudHMgcGVyIGxpbmUgYXJlIGFsbG93ZWQ7IGxpbmUgYnJlYWtzIGFyZSBvbmx5IGFsbG93ZWQgYmV0d2VlbiBhc3NpZ25tZW50cy4gDQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KDQojIEdvb2QNClByZWRpY3RDVFIgPC0gZnVuY3Rpb24ocXVlcnksIHByb3BlcnR5LCBudW0uZGF5cywNCiAgICAgICAgICAgICAgICAgICAgICAgc2hvdy5wbG90ID0gVFJVRSkNCiMgQmFkDQpQcmVkaWN0Q1RSIDwtIGZ1bmN0aW9uKHF1ZXJ5LCBwcm9wZXJ0eSwgbnVtLmRheXMsIHNob3cucGxvdCA9DQogICAgICAgICAgICAgICAgICAgICAgIFRSVUUpDQpgYGANCg0KIyMjRnVuY3Rpb24gRG9jdW1lbnRhdGlvbg0KDQpGdW5jdGlvbnMgc2hvdWxkIGNvbnRhaW4gYSBjb21tZW50cyBzZWN0aW9uIGltbWVkaWF0ZWx5IGJlbG93IHRoZSBmdW5jdGlvbiBkZWZpbml0aW9uIGxpbmUuIFRoZXNlIGNvbW1lbnRzIHNob3VsZCBjb25zaXN0IG9mIGEgb25lLXNlbnRlbmNlIGRlc2NyaXB0aW9uIG9mIHRoZSBmdW5jdGlvbjsgYSBsaXN0IG9mIHRoZSBmdW5jdGlvbidzIGFyZ3VtZW50cywgZGVub3RlZCBieSBBcmdzOiwgd2l0aCBhIGRlc2NyaXB0aW9uIG9mIGVhY2ggKGluY2x1ZGluZyB0aGUgZGF0YSB0eXBlKTsgYW5kIGEgZGVzY3JpcHRpb24gb2YgdGhlIHJldHVybiB2YWx1ZSwgZGVub3RlZCBieSBSZXR1cm5zOi4gVGhlIGNvbW1lbnRzIHNob3VsZCBiZSBkZXNjcmlwdGl2ZSBlbm91Z2ggdGhhdCBhIGNhbGxlciBjYW4gdXNlIHRoZSBmdW5jdGlvbiB3aXRob3V0IHJlYWRpbmcgYW55IG9mIHRoZSBmdW5jdGlvbidzIGNvZGUuDQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KDQpDYWxjdWxhdGVTYW1wbGVDb3ZhcmlhbmNlIDwtIGZ1bmN0aW9uKHgsIHksIHZlcmJvc2UgPSBUUlVFKSB7DQogICMgQ29tcHV0ZXMgdGhlIHNhbXBsZSBjb3ZhcmlhbmNlIGJldHdlZW4gdHdvIHZlY3RvcnMuDQogICMNCiAgIyBBcmdzOg0KICAjICAgeDogT25lIG9mIHR3byB2ZWN0b3JzIHdob3NlIHNhbXBsZSBjb3ZhcmlhbmNlIGlzIHRvIGJlIGNhbGN1bGF0ZWQuDQogICMgICB5OiBUaGUgb3RoZXIgdmVjdG9yLiB4IGFuZCB5IG11c3QgaGF2ZSB0aGUgc2FtZSBsZW5ndGgsIGdyZWF0ZXIgdGhhbiBvbmUsDQogICMgICAgICB3aXRoIG5vIG1pc3NpbmcgdmFsdWVzLg0KICAjICAgdmVyYm9zZTogSWYgVFJVRSwgcHJpbnRzIHNhbXBsZSBjb3ZhcmlhbmNlOyBpZiBub3QsIG5vdC4gRGVmYXVsdCBpcyBUUlVFLg0KICAjDQogICMgUmV0dXJuczoNCiAgIyAgIFRoZSBzYW1wbGUgY292YXJpYW5jZSBiZXR3ZWVuIHggYW5kIHkuDQogIG4gPC0gbGVuZ3RoKHgpDQogICMgRXJyb3IgaGFuZGxpbmcNCiAgaWYgKG4gPD0gMSB8fCBuICE9IGxlbmd0aCh5KSkgew0KICAgIHN0b3AoIkFyZ3VtZW50cyB4IGFuZCB5IGhhdmUgZGlmZmVyZW50IGxlbmd0aHM6ICIsDQogICAgICAgICBsZW5ndGgoeCksICIgYW5kICIsIGxlbmd0aCh5KSwgIi4iKQ0KICB9DQogIGlmIChUUlVFICVpbiUgaXMubmEoeCkgfHwgVFJVRSAlaW4lIGlzLm5hKHkpKSB7DQogICAgc3RvcCgiIEFyZ3VtZW50cyB4IGFuZCB5IG11c3Qgbm90IGhhdmUgbWlzc2luZyB2YWx1ZXMuIikNCiAgfQ0KICBjb3ZhcmlhbmNlIDwtIHZhcih4LCB5KQ0KICBpZiAodmVyYm9zZSkNCiAgICBjYXQoIkNvdmFyaWFuY2UgPSAiLCByb3VuZChjb3ZhcmlhbmNlLCA0KSwgIi5cbiIsIHNlcCA9ICIiKQ0KICByZXR1cm4oY292YXJpYW5jZSkNCn0NCmBgYA0KDQpFbmpveSBSIQ==