Introduction

This tutorial is a quick introduction to R for programmers of other high-level languages. It shows those features of R that are familiar to most programmers so that they can get started programming right away. It is important to note that the programming approach presented here is generally not the most efficient nor most common approach. We show the “R way” whenever possible and simple enough to explain. But the goal of the tutorial is to get a programmers programming. This is especially useful to students in computer science courses that use R but who are new to R.

R is best suited for data projects: data loading, data transformation, databases, data analysis, data visualization, and data science. There is substantial support for statistical analysis, unsupervised data mining, supervised machine learning, and even interactive dashboards.

Often, programming tasks that take dozens of lines of code in most languages can be written with one statement or one line in R. While R is not the fastest language, for many vector processing and mathematical operations it generally outperforms most other high-level languages, particularly when vectorization hardware is present.

As of 2021, R is one of the top languages to learn and for any kind of data-related work it is critical (along with Python, Scala, and perhaps Go).

The tutorial is geared towards students in information science, data science, and database design. It demonstrates basic syntax in R that are most often used for data processing rather than statistics.

The R Language

R is a procedural language similar to C. It is not object-oriented and does not support objects, classes, inheritance, or polymorphism. It has little support for data encapsulation or abstraction, so no equivalent for class or struct in C/C++ or Java.

Programs is R are scripts. There is no “main function” or similar. R “programs” are collections of R statements that are interpreted when executed interactively. There is no compilation step. R does support reusable third-party code “libraries” in the form of packages.

Working in R

To write “programs” in R you will need Base R which you can download for Linux, MacOS, and Windows from R Project. This is the core language with an interactive console. Programs, or more aptly R scripts, can be built in any text editor (TextEdit, Notepad, vi, Sublime, JEdit, etc.).

Most programming is done with an IDE (Integrated Development Environment). The most common is R Studio downloadable from RStudio. There is a hosted version of R Studio available at rstudio.cloud.

Install R from R Project before installing R Studio.

The tutorial below explains how to get started with R Notebooks:

Execute chunks by clicking the Run button within the chunk or by placing your cursor inside it and pressing Ctrl+Shift+Enter. The code runs in the order in which the chunks are executed, so non-linear code execution is possible unless you instruct R Studio to run all chunks starting at the first chunk.

Add a new chunk by clicking the Insert Chunk button on the toolbar or by pressing Ctrl+Alt+I.

When you save the notebook, an HTML file containing the code and output will be saved alongside it (click the Preview button or press Ctrl+Shift+K to preview the HTML file).

The preview shows you a rendered HTML copy of the contents of the editor. Consequently, unlike Knit, Preview does not run any R code chunks. Instead, the output of the chunk when it was last run in the editor is displayed.

Projects in R Studio

Projects are a better way to manage code rather than creating individual R Notebooks, R Scripts, and other code files. Projects allows all files, including data files, to be managed as a single unit, shared, and version controlled using services such as git and GitHub.

The tutorial below demonstrates how to create a project in R Studio and add files to the project.

R Code Chunks

While you can also write R Scripts, we will concentrate on how to write R “programs” by composing an R Notebook in R Studio. This is the most common way to use R in data related projects where reproducability is paramount. Programs in R run from start to end. Each chunk should be a step in your analysis or data project. Name your code chunks, so you can quickly navigate to them.

In the chunk below, the variable cars passed to the built-in Base R function plot is one of the dozens of “built-in” data frames; a data frame being data arranged in rows and columns similar to a spreadsheet or CSV file.

Note that you call a function by using the function’s name followed by the arguments you wish to pass to the function. Of course, you need to follow the definition of the function. Many functions are simply “built-in” while others come from packages that you need to explicitly load into your program.

Note that there is no semicolon at the end of a line.

plot(cars)

Expressions

R can be directly used to solve simple or complex mathematical expressions.

# [1] in the above answer indicates the index of your results.
# R always shows the result with index for each row.

((2^3)*5)-1
## [1] 39
# sqrt and exp are built-in functions in R for finding Square root and exponential respectively.

sqrt(4)* exp(2)
## [1] 14.77811

Variables

Variables are not declared in R. When you use a variable for the first time, it is defined and the data type is based on what value you assign to the variable. So, R uses dynamic typing, which also means that when you assign a value of a different type to a previously used variable, it changes type. You can find the type of a variable using the functions typeof, class, and mode.

R supports the usual data types: integer, double, Boolean, and string. It also has pre-defined complex types, including vector, data frame, array, list, and matrix. There is also a Date data type and a few others.

The absence of a value is indicated in R using NA rather than nil, null or NULL. An NA means that there is no value for an integer, character, logical value, or numeric. On the other hand, NULL means that an object is “empty”, i.e. a reference to an object that does not exist.

Values are assigned to variables using either = or <-, the latter being more common but the former more familiar to programmers of other common languages.

a = 10                       # defines an integer
d = 9.9                      # defines a double
s = "some text"              # define a string of characters
g <- 'also text'             # single quotes are the same as double quotes

Text can be enclosed in single or double quotes. Which you use depends on preference or if you need to nest quotes.

z = "It's a quote."

To echo the value of a variable to the console, either use the variable on a line by itself or use the function print. If you need to echo multiple values, combine them with paste0.

d <- 123.99
d
## [1] 123.99
print(paste0("Value of d = ", d))
## [1] "Value of d = 123.99"

Missing Values: NA vs NULL

In R, NA and NULL are used to represent different types of missing data, and they serve different purposes:

  1. NA (Not Available):
    • NA is used to represent missing values in vectors, lists, or data frames. It acts as a placeholder for an element that does not have a value but is expected to have one.
    • NA can be of any data type like numeric, character, or logical, meaning you can have NA_integer_, NA_real_, NA_complex_, and NA_character_.
    • Operations involving NA generally result in NA. For example, 5 + NA results in NA.
    • A value of NA is a value and is counted, e.g., length(c(3,NA,4)) has the value 3.
  2. NULL:
    • NULL is used to represent the absence of a value or no value at all. It is typically used to denote that a variable is empty or uninitialized.
    • NULL is often used in list or data frame operations to remove elements or indicate that an element is absent.
    • NULL has a different behavior in operations compared to NA. For instance, adding NULL to another object or concatenating it generally results in the other object unchanged. For example, c(1, 2, NULL) results in c(1, 2).

Essentially, NA is used when an element of the data exists but its value is missing, whereas NULL is used when the data itself does not exist.

Many functions that return an object such as a data frame would return NULL if they could not generate the object.

In R, you can test for NA and NULL using specific functions designed for this purpose. Here’s how you can do it:

  1. Testing for NA:
    • Use the is.na() function, which checks for NA values in an object. It returns a logical vector of the same size as the input, with TRUE for elements that are NA and FALSE for those that are not.

    • Example:

      vec <- c(1, NA, 3, NA, 5)
      is.na(vec)
      # Output: FALSE  TRUE FALSE  TRUE FALSE
  2. Testing for NULL:
    • Use the is.null() function, which checks if an object is NULL. It returns TRUE if the object is NULL and FALSE otherwise.

    • Example:

      x <- NULL
      is.null(x)
      # Output: TRUE

These functions are useful in various programming scenarios, such as conditional execution of code depending on the presence of actual data, and handling missing values in data analysis and transformation tasks.

Naming Identifiers

The naming of identifiers, i.e., variable and function names, are the same as in most other languages, except that you can use the period as a valid identifier character. That can be confusing to Java and C++ programmers as they are used to using . as a method or object property access operator. In R, it’s just another character like a or _.

a.val = 10.5          # legal
a_val = 10.5          # legal
aVal1 = 10.5          # legal
a$val = 10.5          # not quite legal, $ is reserved for data frames

The last one is a bit tricky. a$val will actually create a list object. Let’s just not use it unless you are accessing columns in a data frame, but that’s for another tutorial.

The rules for naming an identifier (variable, function, or package name) for an object are as follows:

  • identifiers are case-sensitive and cannot contain spaces or special characters such as #, %, $, @, * , &, ^, !, ~

  • an identifier must start with a letter, but may contain any combination of letters and digits thereafter

  • special characters dot (.) and underscore (_) are allowed

The dot (.) is a regular character in R and that can be confusing as other languages (e.g., Java) use dot as an operator to designate property or method access, e.g, in Java x.val means that you are accessing the val property of the object x.

Some examples of legal variable names are: df, df2, df.txns, and df_all2017. These are some illegal variable names: 2df (cannot start with a digit), rs$all (cannot contain a $; the $ is used to access columns in a dataframe), rs# (only . and _ are allowed in addition to digits and letters).

It is considered good programming practice to give identifiers a sensible name that hints as to what is stored in the variable rather than using random name like x, val, or i33. Instead use anItem or annualTotal.

Identifiers should be named consistently. Many programmers use one of two styles:

  • underscores, e.g., interest_rate
  • camelCase, e.g., squareRoot, graphData, currentWorkingDirectory

Note that R is case sensitive which means that R treats the identifiers AP and ap as different objects.

As a side note, files may also be case sensitive but that depends on the operating system. MacOS and Linux are case sensitive, while Windows is case aware but not case sensitive. For example, on MacOS and Linux there is a difference between “AirPassengers.txt” and “airpassengers.txt” while on Windows there is not. SQL is also not case sensitive. It is a best practice to assume case sensitivity.

Expressions

As a language with roots in statistical analysis, R supports most mathematical operators, including many that are not supported through operators in most other languages.

Precedence is like other languages and can be (and should be) specified explicitly using parentheses.

a <- 99

b = a + 20                 # addition
b = a - 20                 # subtraction
b = a * 20                 # multiplication
b = a / 20                 # division -- b is now "double"
b = a ^ 3                  # exponentiation
b = a %% 2                 # modulus (mod)
b = a %/% 2                # integer division (div)

b = (a / 2) ^ 5            # force order of evaluation

There are also numerous built-in functions for mathematics and statistics, but those are beyond this tutorial on base syntax. For the sake of completeness, an example is shown below that calculates the z-score of a vector of numbers. In R, a vector is similar to an array; it contains primitives values (integer, double, Boolean, or string). Notice the automatic vector calculation even without a loop.

v = c(1,4,6,2,8,1,0,3)     # vector of integers

m = mean(v)                # mean of values in v
s = sd(v)                  # standard deviation
z = (m - v) / s            # z-score of each value in v

print(round(z,2))          # print rounded values
## [1]  0.77 -0.32 -1.05  0.41 -1.77  0.77  1.14  0.05

Boolean Variables and Logical Expressions

Boolean values are TRUE and FALSE; or T and F, respectively.

m = FALSE
w = TRUE

q = (m & w) | (!m & !w)

print(paste0("q is ", q))
## [1] "q is FALSE"

The Boolean operators are & for AND, | for OR, and ! for NOT. These operators perform logical operations on Boolean variables or vector of Boolean elements. Exclusive or (xor) is performed with the function xor, e.g., xor(a,b).

There are long forms && and || for programming control-flow and generally preferred for if statements.

Flow Control

The control flow statements provided by R are similar to those found in most other programming languages: loops and if statements.

Loops

R supports the three common types of loops: a counting loop (for), a top-tested loop (while), and a bottom-tested loop (repeat).

Counting Loop: for

The counting loop is actually more like an iterator in R, although it can be set up to mimic the behavior of a typical loop in C/C++, Java, etc., that loops from a low value to a high value. See the examples below.

n = 5
for (i in 1:n) {
  print(i)
}
## [1] 1
## [1] 2
## [1] 3
## [1] 4
## [1] 5

In the example above, i is the loop variable and it takes on the values in the vector 1:5, i.e., 1, 2, 3, 4, 5

To count down, it would be 5:1 or n:1 in the above code example.

Like other languages, R uses curly braces to enclose the body of the loop, i.e., the statements that are executed repeatedly, once for each value of i. Of course, the loop counter can be any properly named variable.

The example below accesses a vector using positional access, e.g., v[1] accesses the first element. Note that vector, data frames, lists, and arrays are indexed starting at 1 and not 0 as in C-based languages.

v = rnorm(5)      # vector of five random numbers
for (i in 1:length(v)) 
{
  v[i] = v[i] ^ 2
}

print(v)
## [1] 0.003630603 2.683820944 1.535107835 2.112020092 1.549035610

While you can use loops you actually do not need them. If you apply a mathematical operation to a vector, R automatically applies them to each element, but loops might be more natural in the beginning.

# note that you actually do not need loops in R
# this also squares each element in the vector v
v = v ^ 2

As already stated, looping in R is actually iteration over a set: a set of numbers as above or a set of any kind of primitive object, e.g., strings. Note that in the code below, k takes on each value in the vector over which the loop iterates.

s = c("one","two","three","four")

for (k in s) {
  print(k)
}
## [1] "one"
## [1] "two"
## [1] "three"
## [1] "four"

We could have written this using a non-iterator approach as well, which is more like what you’d do in C. Note that length returns the number of elements in a vector, i.e., its “length”.

s = c("one","two","three","four")

for (j in 1:length(s)) {
  print(s[j])
}
## [1] "one"
## [1] "two"
## [1] "three"
## [1] "four"
Iteration Continuation

Continuation of the loop to the next iteration and forgoing processing the remainder of the current iteration is done with next in R, similar to continue in C-based languages such as Java.

In the example below we are already reaching ahead to the if statement. The code fragment echoes only odd number. Of course, you could have done this differently by just iterating over the even numbers from one to twenty, but that would not have allowed us to share this example for using next.

for (i in 1:10) {
  if (!i %% 2) {
    next
  }
  print(i)
}
## [1] 1
## [1] 3
## [1] 5
## [1] 7
## [1] 9

But, just to show you how to iterate over just odd number, we can use the seq() function which generates a sequence of numbers in steps. No if and no break needed – much simpler.

for (i in seq(1, 10, 2)) {
  print(i)
}
## [1] 1
## [1] 3
## [1] 5
## [1] 7
## [1] 9

Or, more explicitly by specifying the parameters by name.

for (i in seq(from = 1, to = 10, by = 2)) {
  print(i)
}
## [1] 1
## [1] 3
## [1] 5
## [1] 7
## [1] 9

To stop the execution of the rest of a loop and to move immediately to the next statement after the loop is done with break in R which is identical to C, C++, Java, etc. In the code below we will find the position of the first occurrence of some number; x is the number we are looking for in v and p is the found position.

v = c(1, 3, 5, 7, 1, 9, 4)
x = 9
p = 0

for (i in 1:length(v)) {
  if (v[i] == x) {
    p = i
    break
  }
}

print(p)
## [1] 6

To be clear, there is a quicker and more efficient way to do this using the which function. This function does not exist is other languages and it shows the power of R. Also, using which is much faster. Incidentally, the code below finds all occurrences of x in v. Note, once again, the use of a vector variable to refer to all elements.

v = c(1, 3, 5, 7, 1, 9, 4)
x = 9

p = which(v == x)

print(p)
## [1] 6

Conditional Loops: while and repeat

Like many other languages, R supports top and bottom tested loops. In the example below we repeatedly ask for a number from the user and only exit the loop if the number is 42. Of course, the example really should be done with a bottom tested loop.

response <- as.integer(readline(prompt="Enter a number: "))

while (response != 42) {   
  print("Sorry, not correct");
  response <- as.integer(readline(prompt="Enter a number: "));
}

In the above example, we are using two new functions. readline is used to read input from the console, while as.integer coerces (or casts in C/C++ terminology) the input to an integer.

The code is above is not very efficient or elegant as it has the code for the user prompt twice. It is really better to ask first and then check the condition: we need a bottom-tested loop.

Let’s look at the same example, but with a repeat loop that runs until a condition is reached and the loop is explicitly exited with break. So, if you want to run the code at least once, use repeat; if the code is run zero or more times, use while. The repeat loop is identical to the do or do while loop found in many other programming languages.

repeat {   
  response <- as.integer(readline(prompt="Enter a number: "));
  if (response == 42) {
    break
  }
  print("Sorry, not correct");
}

There is no equivalent in R for the use of an infinite for loop as in C and C++, e.g., for(;;){ // do something indefinitely } that runs until a condition is reached and then uses break to exit the loop. The repeat loop construct is used instead. There is no testing of a condition in the repeat loop, so there’s no equivalent to the C-like construct do … while.

Alternation: if

The use of if to selectively execute a block of code based on a condition is the same in R as it is in other languages. We already saw an example and the same example is below:

for (i in 1:10) {
  if (!i %% 2) {
    next
  }
  print(i)
}
## [1] 1
## [1] 3
## [1] 5
## [1] 7
## [1] 9

Note that the condition is in parenthesis and that the block executed if the condition is true is in curly braces. This is identical to C, C++, Java, Python, etc.

A more complex example is shown below that squares all numbers in a vector that are less than 5 and cubes them if greater than 5. Not a useful example but one that allows us to show the use of if-else.

for (i in 1:10) {
  if (i < 5) {
    print(i^2)
  } else {
    print(i^3)
  }
}
## [1] 1
## [1] 4
## [1] 9
## [1] 16
## [1] 125
## [1] 216
## [1] 343
## [1] 512
## [1] 729
## [1] 1000

Functions

Code organization and reuse in R is done using functions. All objects are free methods and are not bound to an object or a class like in Java or C++. It’s the same way as in Python or C.

All functions in R can return a value, although they do not have to. So, R does not distinguish between functions and procedures and there is no void return type as in C, C++, and Java.

Defining a Function

The generic template for defining a function is:

function_name <- function(arg_1, arg_2, ...) {
   Function body 
}

The example below defines a function called findSmallest() which takes a vector of positive integers as an argument and returns the smallest element in the vector. While it can be solved in several ways, we will show a design that uses loops and should be familiar to programmers of most other languages.

Note that we are using the predefined value Inf with is the largest representable integer. There is also -Inf that is the smallest representable integer.

findSmallest = function(v)
{
  s = Inf
  for (i in 1:length(v))
  {
    if (v[i] < s) {
      s = v[i]
    }
  }
  return (s)
}

While you can use = to define a function, you should really get used to using the more common <- syntax. So, let’s try again:

findSmallest <- function(v)
{
  s = Inf
  for (i in 1:length(v))
  {
    if (v[i] < s) {
      s = v[i]
    }
  }
  return (s)
}

Just to be clear, in practice you would use the min() function to find the smallest element rather writing it yourself.

While there are several ways to return a value from a function, the way that is most congruent with other languages is the use of the return statement.

Note that the type of return value and the type of arguments are not declared. R uses a lazy evaluation mechanism and no type checking is performed until run-time.

Calling a Function

To call a function, you would invoke it with its name and its required arguments.

x = c(3,1,9,7,3,6)

w = findSmallest(x)
print(w)
## [1] 1

Function Parameters

If a function takes several arguments you generally pass them in the order declared; the approach that is used by all other languages. However, in R you can pass the arguments in any order as long as you specify the name of the argument.

Argument matching is a bit different in R compared to other languages. Firstly, R does all argument checking at run-time. Secondly, while arguments can be matched positionally like in other languages, arguments can also be matched by parameter name – a syntax not supported by most other languages.

For example, the built-in function seq generates a sequence of numbers and returns those numbers in a vector. The definition of the function is as follows: seq(to, from, by, length.out, along.with).

Here are examples of using it. Note that by, length.out, and along.with have default values and are therefore optional.

v = seq(1, 10, 2)    # integers from 1 to 10 in increments of 2
w = seq(1, 5)        # integers from 1 to 5 (by default in increments of 1)

# pass arguments in a different order but specify by name
w = seq(from = 5, by = -0.5, to = 1)

R also supports variable numbers of arguments but that is beyond the scope of this tutorial.

Default Arguments

R functions can have default values for arguments which are then optional when the function is called. When the argument is missing, then the default value is passed. In the example below, the start argument is the position at which the search for the smallest element will start.

findSmallest <- function(v, start = 1)
{
  s = Inf
  for (i in start:length(v))
  {
    if (v[i] < s) {
      s = v[i]
    }
  }
  return (s)
}
x = c(3,1,9,7,3,6)

w = findSmallest(x, 3)
print(w)
## [1] 3
w = findSmallest(x)
print(w)
## [1] 1

Local Variables

As in most other programming languages, R functions can define local variables that are not known outside the scope of the function. The scope boundaries in R are like other languages: a block enclosed in curly braces.

In the example below, local.var is local to the function and thus is not visible outside of the function. The code below produces the error: “Error in print(local.var) : object ‘local.var’ not found”.

findSmallest <- function(v, start = 1)
{
  local.var = Inf
  for (i in start:length(v))
  {
    if (v[i] < local.var) {
      local.var = v[i]
    }
  }
  return (local.var)
}

x = c(3,1,9,7,3,6)

w = findSmallest(x, 3)

# we cannot echo or access the local variable "s"
print(local.var)

Recursion

R functions can be called recursively. The example below calculates factorial using recursion rather than a loop.

fac <- function(x)
{
  if (x == 1) 
    return (1)
  else 
    return (x * fac(x-1))
}

print(fac(8))
## [1] 40320

If it hasn’t been obvious yet, just like in other languages, the placement of curly braces makes no difference. For single statement blocks, the curly braces can be omitted.

The parenthesis around the value for return are required.

As an exercise, try writing the above function to calculate factorial using a loop.

Type Coercion

Type coercion (or casting in C/C++ terminology) is done with type conversion functions in R and not through operators like in C, C++, and Java. The example below shows the most common type conversion functions. Note that in some situation you will lose information, just like in other languages.

s = "12.4"                 # string (character)
i = as.integer(s)          # convert to integer: 12
d = as.numeric(s)          # convert to double: 12.3

w = "$12.3"                # additional characters
k = as.integer(w)          # cannot be converted due to $
## Warning: NAs introduced by coercion

If a coercion is not successful the result in NA which indicates a null or missing value.

Vectors

Let’s talk more about vectors. In R, a vector is similar to a list or array in other programming languages. It is a collection of elements of the same basic type: numeric, character, or Boolean. A list in R is a collection of mixed data types. This tutorial applies to vectors only.

There are no specific packages required for these functions.

Creating a Vector

The code below creates an artificial vector of random integers for use in the tutorial. In practice, vectors are generally columns in data frames which are frequently the result of reading data from a CSV file or a database.

# vector of 50 random integers between 0 and 10

# set the seed for the random number generator to ensure same
# sequence of random numbers every time the code is run
set.seed(98788)
v <- round(runif(50, min = 0, max = 10),0)

# arguments do not have to be passed in the order that they are
# declared in the function definition as long as the names of the
# arguments are specified
v <- round(runif(n = 50, max = 10, min = 1),0)
v <- round(runif(max = 10, min = 1, n = 50),0)

print(v)
##  [1]  9  6  9  1  9  8 10  2  6  9  8  7  6  1  7 10  4  3  5  9  7  8  4  9  7
## [26]  4  6  5  1  4  4  2  7  9  9  6  3  2  3  7  8  6  3  9  4 10  7  1  4  2

Accessing Elements in a Vector

Elements are accessed positionally, although in R, the access index can be a vector of integers in which case all elements at those positions are retrieved. Positions are numbered from 1 to the number of elements in a vector. The number of elements (or length) of a vector can be obtained using the length() function.

In the example below, note that n:m generates a vector of integers from n to m, inclusive. The seq() generates a sequence of integers at an interval.

# access a single element at position 3
v[3]

# access element 10 through 15
v[10:15]

# access the last element
v[length(v)]

# access every other element
v[seq(from = 1, to = length(v), by = 2)]

# access specific elements at positions 2, 11, 19, and 28
i <- c(2,11,19,28)
v[i]

Testing Predicate Expressions

It is possible in R to apply a predicate expression to every element in a vector. This generates a “Boolean vector” of TRUE/FALSE values that indicate which element matches the predicate expression (TRUE) and which doesn’t (FALSE).

Predicate expressions are built with logical operators (<, >, <=, >=, ==, !=)

v < 5
##  [1] FALSE FALSE FALSE  TRUE FALSE FALSE FALSE  TRUE FALSE FALSE FALSE FALSE
## [13] FALSE  TRUE FALSE FALSE  TRUE  TRUE FALSE FALSE FALSE FALSE  TRUE FALSE
## [25] FALSE  TRUE FALSE FALSE  TRUE  TRUE  TRUE  TRUE FALSE FALSE FALSE FALSE
## [37]  TRUE  TRUE  TRUE FALSE FALSE FALSE  TRUE FALSE  TRUE FALSE FALSE  TRUE
## [49]  TRUE  TRUE
(v < 1 | v > 9)
##  [1] FALSE FALSE FALSE FALSE FALSE FALSE  TRUE FALSE FALSE FALSE FALSE FALSE
## [13] FALSE FALSE FALSE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [25] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [37] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE FALSE FALSE
## [49] FALSE FALSE
(v <= 7 & v != 3)
##  [1] FALSE  TRUE FALSE  TRUE FALSE FALSE FALSE  TRUE  TRUE FALSE FALSE  TRUE
## [13]  TRUE  TRUE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE
## [25]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE FALSE  TRUE
## [37] FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE FALSE  TRUE FALSE  TRUE  TRUE
## [49]  TRUE  TRUE
v != 5
##  [1]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
## [13]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE
## [25]  TRUE  TRUE  TRUE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
## [37]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
## [49]  TRUE  TRUE
l <- (v == 5)
print(l)
##  [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [13] FALSE FALSE FALSE FALSE FALSE FALSE  TRUE FALSE FALSE FALSE FALSE FALSE
## [25] FALSE FALSE FALSE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [37] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [49] FALSE FALSE

Finding Matches

The which() function returns the positions that are TRUE in a Boolean vector.

# returns positions of vector that matches predicate expression
which(v != 5)
##  [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 20 21 22 23 24 25 26
## [26] 27 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
# count the number of matches
length(which(v != 0))
## [1] 50
p <- which(v < 5)
print (v[p])
##  [1] 1 2 1 4 3 4 4 1 4 4 2 3 2 3 3 4 1 4 2
# or combine
x <- v[which(v < 5)]
print (x)
##  [1] 1 2 1 4 3 4 4 1 4 4 2 3 2 3 3 4 1 4 2
# find all that are not in vector
not.x <- v[-which(v < 5)]
print (x)
##  [1] 1 2 1 4 3 4 4 1 4 4 2 3 2 3 3 4 1 4 2

Determining Any Matches

To determine if there are any matches, i.e., at least one element in a vector matches the predicate expression, use the any() function. The function any() returns TRUE if there’s at least one match, FALSE otherwise.

any(v < 5)
## [1] TRUE

Dealing with Missing Values

Missing values in R are generally encoded with the special value NA. NA is not a number, not a character or text, and not a Boolean. Consequently, using == or != to check if a value is NA does not work and results in an error. You must use the function is.na() to check if a value is NA. This is similar to NULL in SQL and many programming languages.

# copy the vector of random numbers and then randomly 
# remove 6 values, i.e., set them to NA

v.na <- v

v.na[round(runif(6, min = 1, max = length(v.na)), 0)] = NA

print(v.na)
##  [1]  9  6  9  1  9  8 10  2 NA  9  8  7 NA  1  7 10  4  3  5  9  7 NA  4 NA  7
## [26]  4  6  5  1  4  4  2  7  9 NA  6  3  2  3  7 NA  6  3  9  4 10  7  1  4  2

Many of the functions in R do not work when a value in a vector is NA. Doing so results in a value of NA.

# cannot add values containing NA
sum(v.na)
## [1] NA
# when applying operators, NA remains NA
v.na + 5
##  [1] 14 11 14  6 14 13 15  7 NA 14 13 12 NA  6 12 15  9  8 10 14 12 NA  9 NA 12
## [26]  9 11 10  6  9  9  7 12 14 NA 11  8  7  8 12 NA 11  8 14  9 15 12  6  9  7

Some functions have a parameter that allows you to direct a function to ignore NA values. Check the documentation of functions before using them to see what parameters they support. Use ?sum to view the documentation of the sum function.

Accessing Rows, Columns, and Elements (Cells) of a Data Frame

Data frames are very similar to tables in relational databases and spreadsheets. They have rows and columns and the intersection of a row and column is a cell (or element). The order of access is row followed by column, e.g., the third element in the fourth row of the data frame mtcars is mtcars[4,3]. Note that this is reversed from the way Excel and other spreadsheets work.

The example code below uses the built-in data frame mtcars. You can find out more about its structure using str(mtcars) or displaying the first few rows with head(mtcars).

str(mtcars)
## 'data.frame':    32 obs. of  11 variables:
##  $ mpg : num  21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
##  $ cyl : num  6 6 4 6 8 6 8 4 4 6 ...
##  $ disp: num  160 160 108 258 360 ...
##  $ hp  : num  110 110 93 110 175 105 245 62 95 123 ...
##  $ drat: num  3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ...
##  $ wt  : num  2.62 2.88 2.32 3.21 3.44 ...
##  $ qsec: num  16.5 17 18.6 19.4 17 ...
##  $ vs  : num  0 0 1 1 0 1 0 1 1 1 ...
##  $ am  : num  1 1 1 0 0 0 0 0 0 0 ...
##  $ gear: num  4 4 4 3 3 3 3 4 4 4 ...
##  $ carb: num  4 4 1 1 2 1 4 2 2 4 ...
head(mtcars, 3)
##                mpg cyl disp  hp drat    wt  qsec vs am gear carb
## Mazda RX4     21.0   6  160 110 3.90 2.620 16.46  0  1    4    4
## Mazda RX4 Wag 21.0   6  160 110 3.90 2.875 17.02  0  1    4    4
## Datsun 710    22.8   4  108  93 3.85 2.320 18.61  1  1    4    1
v <- mtcars[4,3]
x = mtcars[4,3]

print(paste0("v = ",v," and x = ",x))
## [1] "v = 258 and x = 258"

Leaving out a dimension (row or column) accesses the entire row or column. The resultant is a data frame with a single row.

Often the values must be converted to a vector data type. Conversions of variables from one type to another is done with the family of as.xxxx functions, e.g., as.vector, as.numeric, or as.factor. Vectors can contain numeric or character data but all elements must be of the same type. In R, a list is similar to a vector but it may contain a mix of elements. A matrix is similar to a data frame but it can only contain numbers and it can have more than two dimensions.

Some functions expect data frames, some vectors, some lists. You need to read the documentation of a function to find out. Furthermore, some functions will automatically convert a variable from one type to the one it requires.

You can also access a column in data frame by its column name. For an entire column you either use the columns position or its name: df[,column] or df$columnName.

# all of row 4; the result is a data frame
r <- mtcars[4,]
sum(r)
## [1] 426.135
c <- mtcars[3,]
c[1,3]
## [1] 108
mtcars[c(1,4)]   # columns 1 and 4 as a new dataframe
##                      mpg  hp
## Mazda RX4           21.0 110
## Mazda RX4 Wag       21.0 110
## Datsun 710          22.8  93
## Hornet 4 Drive      21.4 110
## Hornet Sportabout   18.7 175
## Valiant             18.1 105
## Duster 360          14.3 245
## Merc 240D           24.4  62
## Merc 230            22.8  95
## Merc 280            19.2 123
## Merc 280C           17.8 123
## Merc 450SE          16.4 180
## Merc 450SL          17.3 180
## Merc 450SLC         15.2 180
## Cadillac Fleetwood  10.4 205
## Lincoln Continental 10.4 215
## Chrysler Imperial   14.7 230
## Fiat 128            32.4  66
## Honda Civic         30.4  52
## Toyota Corolla      33.9  65
## Toyota Corona       21.5  97
## Dodge Challenger    15.5 150
## AMC Javelin         15.2 150
## Camaro Z28          13.3 245
## Pontiac Firebird    19.2 175
## Fiat X1-9           27.3  66
## Porsche 914-2       26.0  91
## Lotus Europa        30.4 113
## Ford Pantera L      15.8 264
## Ferrari Dino        19.7 175
## Maserati Bora       15.0 335
## Volvo 142E          21.4 109
mtcars[,2]       # all of column 2
##  [1] 6 6 4 6 8 6 8 4 4 6 6 8 8 8 8 8 8 4 4 4 4 8 8 8 8 4 4 4 8 6 8 4
mtcars[5:7,]     # rows 5 to 7 as a new dataframe
##                    mpg cyl disp  hp drat   wt  qsec vs am gear carb
## Hornet Sportabout 18.7   8  360 175 3.15 3.44 17.02  0  0    3    2
## Valiant           18.1   6  225 105 2.76 3.46 20.22  1  0    3    1
## Duster 360        14.3   8  360 245 3.21 3.57 15.84  0  0    3    4
mtcars$cyl       # column named "cyl"
##  [1] 6 6 4 6 8 6 8 4 4 6 6 8 8 8 8 8 8 4 4 4 4 8 8 8 8 4 4 4 8 6 8 4
mtcars$cyl[2]    # 2nd row in the column "cyl"
## [1] 6
mtcars$cyl[3:9]  # rows 3 to 9 for column "cyl" as a vector
## [1] 4 6 8 6 8 4 4
w <- mtcars$mpg
mean(w)
## [1] 20.09062

Adding and Removing Columns from a Data Frame

To add a new column, you simply “access” the column or use a new name for the column. Note in the example below that you can operate on entire columns (as vectors) and the operation is applied to each pair of values in the two vectors in the operation. This is much more efficient than using loops as is necessary in other programming languages.

# copy the data frame mtcars to a new data frame df
df <- mtcars

# create a new column "dispcyl" which is the displacement per cylinder
df$dispcyl <- df$disp / df$cyl

head(df)
##                    mpg cyl disp  hp drat    wt  qsec vs am gear carb  dispcyl
## Mazda RX4         21.0   6  160 110 3.90 2.620 16.46  0  1    4    4 26.66667
## Mazda RX4 Wag     21.0   6  160 110 3.90 2.875 17.02  0  1    4    4 26.66667
## Datsun 710        22.8   4  108  93 3.85 2.320 18.61  1  1    4    1 27.00000
## Hornet 4 Drive    21.4   6  258 110 3.08 3.215 19.44  1  0    3    1 43.00000
## Hornet Sportabout 18.7   8  360 175 3.15 3.440 17.02  0  0    3    2 45.00000
## Valiant           18.1   6  225 105 2.76 3.460 20.22  1  0    3    1 37.50000

Create a New Data Frame

Data frames are created in various ways: use the <code<>data.frame function, load a CSV file, execute a SQL query, or as a result of many package functions.

Load a Data Frame from CSV

Quick note: Capitalization in path and file names does not matter in Windows, but does matter on MacOS and Linux. Furthermore, note that even in Windows the path delimiter is a forward slash / and not the usual backwards slash \. The \ is an “escape” character and used to inject non-printable characters into a string (text), e.g., “This string contains”quotes”.” which would be written in R as “this string contains \”quotes\“.”

The parameter header = F instructs read.csv not to interpret the first line as header labels. Of course, if there are no labels, then you need to define your own.

Aside from CSV files, R can also load a number of other file format using various packages, including XML, Excel, SPSS, MatLab, among many others.

df <- read.csv(file = "customertxndata.csv", header = F)
head(df)
##   V1 V2      V3     V4        V5
## 1  7  0 Android   Male    0.0000
## 2 20  1     iOS   <NA>  576.8668
## 3 22  1     iOS Female  850.0000
## 4 24  2     iOS Female 1050.0000
## 5  1  0 Android   Male    0.0000
## 6 13  1 Android   Male  460.0000
df <- read.csv(file = "customertxndata.csv", 
               header = F,
               col.names = c("numVisits","NumTxn","OS","Gender","TotSp"))
head(df)
##   numVisits NumTxn      OS Gender     TotSp
## 1         7      0 Android   Male    0.0000
## 2        20      1     iOS   <NA>  576.8668
## 3        22      1     iOS Female  850.0000
## 4        24      2     iOS Female 1050.0000
## 5         1      0 Android   Male    0.0000
## 6        13      1 Android   Male  460.0000

Note that the value of the ‘Male’ column in the first row is NA which is the way that R indicates a missing data value. It is not 0 or an empty string, it is unknown. So, statistical functions and algebraic operations would result in an NA as well.

Strings vs Factors

The factor data type encodes categorical data, e.g., the value of a variable is one of a fixed value set. Many statistical functions in R require categorical variables to be of type factor. However, often, during data processing, we need the actual text rather than having it encoded as a factor (which is actually stored in R as an integer for efficiency). So, when reading a CSV file you need to decide if you want text columns to be character strings or factors by setting the stringsAsFactors parameter.

You may use either F and T or FALSE and TRUE.

df <- read.csv(file = "customertxndata.csv", 
               header = F,
               stringsAsFactors = FALSE,
               col.names = c("numVisits","NumTxn","OS","Gender","TotSp"))
head(df)
##   numVisits NumTxn      OS Gender     TotSp
## 1         7      0 Android   Male    0.0000
## 2        20      1     iOS   <NA>  576.8668
## 3        22      1     iOS Female  850.0000
## 4        24      2     iOS Female 1050.0000
## 5         1      0 Android   Male    0.0000
## 6        13      1 Android   Male  460.0000

Create a new Data Frame

The code below creates a new data frame from column vectors. Notice how the column names are the names of the vectors. A new vector is created with the c function, e.g., v <- c(3,5,1,9).

df1 <- data.frame(state = c('Arizona','Georgia', 'New York','Indiana','Washington','Texas'),
                  code = as.factor(c('AZ','GA','NY','IN','WA','TX')),
                  score = c(62,47,55,74,31,85))

head(df1)
##        state code score
## 1    Arizona   AZ    62
## 2    Georgia   GA    47
## 3   New York   NY    55
## 4    Indiana   IN    74
## 5 Washington   WA    31
## 6      Texas   TX    85

Search Data Frames

There are two important functions for “searching” data frames: which and any. The code below uses the built-in Orange data frame which contains measurements of orange trees. It has three columns: the tree, the age of the tree (days since 1968/12/31), and circumference (in mm).

which

df <- Orange

head(df)
##   Tree  age circumference
## 1    1  118            30
## 2    1  484            58
## 3    1  664            87
## 4    1 1004           115
## 5    1 1231           120
## 6    1 1372           142
# find all rows where the circumference is more than 200mm
rs <- which(df$circumference > 200)

# display all rows where the circumference is more than 200mm
df[rs,]
##    Tree  age circumference
## 13    2 1372           203
## 14    2 1582           203
## 27    4 1372           209
## 28    4 1582           214
# compound conditions are possible with & (and), | (or), and ! (not)
rs2 <- which(df$circumference > 200 & df$age < 1500)
rs3 <- which(df$circumference < 200 | !(df$age < 1500))
rs4 <- which(df$circumference > 400 | df$age > 1500)

rs2
## [1] 13 27
rs3
##  [1]  1  2  3  4  5  6  7  8  9 10 11 12 14 15 16 17 18 19 20 21 22 23 24 25 26
## [26] 28 29 30 31 32 33 34 35
rs4
## [1]  7 14 21 28 35
mean(df[rs4,2])
## [1] 1582
mean(df$age[rs3])
## [1] 894.8788

In the above example rs <- which(df$circumference > 200) finds all rows in the data frame df where circumference > 200. The rows are saved in rs.

any

The any function returns \(TRUE\) or \(FALSE\) depending on whether any column (or row) in the dataframe satisfies a Boolean expression.

# is there any tree with age > 2000?
any(df$age > 25)
## [1] TRUE

Memory Management

R is similar to Python and other interpreted languages in terms of memory management. Objects and variables remain in memory until you restart R or explicitly delete them. This can sometimes cause conflicts during development. Adding this to the start of an R script or an R Notebook ensures that the program runs with an empty memory environment. This is critical for languages like R and Python, but is not needed for programming languages that run in separate processes such as Java and C++ programs.

Use the code below to find and then delete all objects, and reclaim memory. The function ls() lists all objects (variables) by name, while the rm() removes one or more objects from memory. Finally, the function gc() runs the garbage collector and returns freed memory to the usable memory pool for the process in which R is running.

rm(list = ls(all.names = TRUE))
gc()

Of course, rather than deleting all objects as in the code chunk above, you may wish to release large objects or unused objects selectively by their name, e.g., rm(“objName”).

Install Packages on Demand

To make your code portable and reproducible, install packages within your code:

# packages needed in R program
packages <- c("stringr", "RSQLite")

# install packages not yet installed
installed_packages <- packages %in% rownames(installed.packages())
if (any(installed_packages == FALSE)) {
  install.packages(packages[!installed_packages])
}

# load all packages by applying 'library' function
invisible(lapply(packages, library, character.only = TRUE))

Conclusion

As you saw, R is not a difficult language to learn as it is similar to other languages and for most language constructs that you are familiar with, there is an equivalent. But it is important that you go beyond this tutorial and learn the “R way” of programming using vectorized operations.


Files & Resources

All Files for Lesson 6.104

References

No references.

Errata

None collected yet. Let us know.

LS0tCnRpdGxlOiAiUXVpY2sgR3VpZGUgdG8gUiBGb3IgUHJvZ3JhbW1lcnMiCnBhcmFtczoKICBjYXRlZ29yeTogNgogIG51bWJlcjogMTA0CiAgdGltZTogNjAKICBsZXZlbDogYmVnaW5uZXIKICB0YWdzOiAicixwcmltZXIsbG9vcHMiCiAgZGVzY3JpcHRpb246ICJBIHF1aWNrIGd1aWRlIGZvciBwcm9ncmFtbWVycyB0cmFuc2l0aW9uaW5nIHRvIFIgZnJvbSAKICAgICAgICAgICAgICAgIEMsIEMrKywgSmF2YSwgSmF2YVNjcmlwdCwgUHl0aG9uLCAKICAgICAgICAgICAgICAgIGFuZCBvdGhlciBoaWdoLWxldmVsIGxhbmd1YWdlcy4gRXhwbGFpbnMga2V5IGNvbnRyb2wKICAgICAgICAgICAgICAgIHN0cnVjdHVyZXMgYW5kIHByb2dyYW1taW5nIHBhcmFkaWdtcyBmb3IgUi4iCmRhdGU6ICI8c21hbGw+YHIgU3lzLkRhdGUoKWA8L3NtYWxsPiIKYXV0aG9yOiAiPHNtYWxsPk1hcnRpbiBTY2hlZGxiYXVlcjwvc21hbGw+IgplbWFpbDogIm0uc2NoZWRsYmF1ZXJAbmV1LmVkdSIKYWZmaWxpdGF0aW9uOiAiTm9ydGhlYXN0ZXJuIFVuaXZlcnNpdHkiCm91dHB1dDogCiAgYm9va2Rvd246Omh0bWxfZG9jdW1lbnQyOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIGNvbGxhcHNlZDogZmFsc2UKICAgIG51bWJlcl9zZWN0aW9uczogZmFsc2UKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIHRoZW1lOiBzcGFjZWxhYgogICAgaGlnaGxpZ2h0OiB0YW5nbwotLS0KCi0tLQp0aXRsZTogIjxzbWFsbD5gciBwYXJhbXMkY2F0ZWdvcnlgLmByIHBhcmFtcyRudW1iZXJgPC9zbWFsbD48YnIvPjxzcGFuIHN0eWxlPSdjb2xvcjogIzJFNDA1MzsgZm9udC1zaXplOiAwLjllbSc+YHIgcm1hcmtkb3duOjptZXRhZGF0YSR0aXRsZWA8L3NwYW4+IgotLS0KCmBgYHtyIGNvZGU9eGZ1bjo6cmVhZF91dGY4KHBhc3RlMChoZXJlOjpoZXJlKCksJy9SL19pbnNlcnQyREIuUicpKSwgaW5jbHVkZSA9IEZBTFNFfQpgYGAKCiMjIEludHJvZHVjdGlvbgoKVGhpcyB0dXRvcmlhbCBpcyBhIHF1aWNrIGludHJvZHVjdGlvbiB0byBSIGZvciBwcm9ncmFtbWVycyBvZiBvdGhlciBoaWdoLWxldmVsIGxhbmd1YWdlcy4gSXQgc2hvd3MgdGhvc2UgZmVhdHVyZXMgb2YgUiB0aGF0IGFyZSBmYW1pbGlhciB0byBtb3N0IHByb2dyYW1tZXJzIHNvIHRoYXQgdGhleSBjYW4gZ2V0IHN0YXJ0ZWQgcHJvZ3JhbW1pbmcgcmlnaHQgYXdheS4gSXQgaXMgaW1wb3J0YW50IHRvIG5vdGUgdGhhdCB0aGUgcHJvZ3JhbW1pbmcgYXBwcm9hY2ggcHJlc2VudGVkIGhlcmUgaXMgZ2VuZXJhbGx5IG5vdCB0aGUgbW9zdCBlZmZpY2llbnQgbm9yIG1vc3QgY29tbW9uIGFwcHJvYWNoLiBXZSBzaG93IHRoZSAiUiB3YXkiIHdoZW5ldmVyIHBvc3NpYmxlIGFuZCBzaW1wbGUgZW5vdWdoIHRvIGV4cGxhaW4uIEJ1dCB0aGUgZ29hbCBvZiB0aGUgdHV0b3JpYWwgaXMgdG8gZ2V0IGEgcHJvZ3JhbW1lcnMgcHJvZ3JhbW1pbmcuIFRoaXMgaXMgZXNwZWNpYWxseSB1c2VmdWwgdG8gc3R1ZGVudHMgaW4gY29tcHV0ZXIgc2NpZW5jZSBjb3Vyc2VzIHRoYXQgdXNlIFIgYnV0IHdobyBhcmUgbmV3IHRvIFIuCgpSIGlzIGJlc3Qgc3VpdGVkIGZvciBkYXRhIHByb2plY3RzOiBkYXRhIGxvYWRpbmcsIGRhdGEgdHJhbnNmb3JtYXRpb24sIGRhdGFiYXNlcywgZGF0YSBhbmFseXNpcywgZGF0YSB2aXN1YWxpemF0aW9uLCBhbmQgZGF0YSBzY2llbmNlLiBUaGVyZSBpcyBzdWJzdGFudGlhbCBzdXBwb3J0IGZvciBzdGF0aXN0aWNhbCBhbmFseXNpcywgdW5zdXBlcnZpc2VkIGRhdGEgbWluaW5nLCBzdXBlcnZpc2VkIG1hY2hpbmUgbGVhcm5pbmcsIGFuZCBldmVuIGludGVyYWN0aXZlIGRhc2hib2FyZHMuCgpPZnRlbiwgcHJvZ3JhbW1pbmcgdGFza3MgdGhhdCB0YWtlIGRvemVucyBvZiBsaW5lcyBvZiBjb2RlIGluIG1vc3QgbGFuZ3VhZ2VzIGNhbiBiZSB3cml0dGVuIHdpdGggb25lIHN0YXRlbWVudCBvciBvbmUgbGluZSBpbiBSLiBXaGlsZSBSIGlzIG5vdCB0aGUgZmFzdGVzdCBsYW5ndWFnZSwgZm9yIG1hbnkgdmVjdG9yIHByb2Nlc3NpbmcgYW5kIG1hdGhlbWF0aWNhbCBvcGVyYXRpb25zIGl0IGdlbmVyYWxseSBvdXRwZXJmb3JtcyBtb3N0IG90aGVyIGhpZ2gtbGV2ZWwgbGFuZ3VhZ2VzLCBwYXJ0aWN1bGFybHkgd2hlbiB2ZWN0b3JpemF0aW9uIGhhcmR3YXJlIGlzIHByZXNlbnQuCgpBcyBvZiAyMDIxLCBSIGlzIG9uZSBvZiB0aGUgdG9wIGxhbmd1YWdlcyB0byBsZWFybiBhbmQgZm9yIGFueSBraW5kIG9mIGRhdGEtcmVsYXRlZCB3b3JrIGl0IGlzIGNyaXRpY2FsIChhbG9uZyB3aXRoIFB5dGhvbiwgU2NhbGEsIGFuZCBwZXJoYXBzIEdvKS4KClRoZSB0dXRvcmlhbCBpcyBnZWFyZWQgdG93YXJkcyBzdHVkZW50cyBpbiBpbmZvcm1hdGlvbiBzY2llbmNlLCBkYXRhIHNjaWVuY2UsIGFuZCBkYXRhYmFzZSBkZXNpZ24uIEl0IGRlbW9uc3RyYXRlcyBiYXNpYyBzeW50YXggaW4gUiB0aGF0IGFyZSBtb3N0IG9mdGVuIHVzZWQgZm9yIGRhdGEgcHJvY2Vzc2luZyByYXRoZXIgdGhhbiBzdGF0aXN0aWNzLgoKIyMgVGhlIFIgTGFuZ3VhZ2UKClIgaXMgYSBwcm9jZWR1cmFsIGxhbmd1YWdlIHNpbWlsYXIgdG8gQy4gSXQgaXMgbm90IG9iamVjdC1vcmllbnRlZCBhbmQgZG9lcyBub3Qgc3VwcG9ydCBvYmplY3RzLCBjbGFzc2VzLCBpbmhlcml0YW5jZSwgb3IgcG9seW1vcnBoaXNtLiBJdCBoYXMgbGl0dGxlIHN1cHBvcnQgZm9yIGRhdGEgZW5jYXBzdWxhdGlvbiBvciBhYnN0cmFjdGlvbiwgc28gbm8gZXF1aXZhbGVudCBmb3IgKmNsYXNzKiBvciAqc3RydWN0KiBpbiBDL0MrKyBvciBKYXZhLgoKUHJvZ3JhbXMgaXMgUiBhcmUgc2NyaXB0cy4gVGhlcmUgaXMgbm8gIm1haW4gZnVuY3Rpb24iIG9yIHNpbWlsYXIuIFIgInByb2dyYW1zIiBhcmUgY29sbGVjdGlvbnMgb2YgUiBzdGF0ZW1lbnRzIHRoYXQgYXJlIGludGVycHJldGVkIHdoZW4gZXhlY3V0ZWQgaW50ZXJhY3RpdmVseS4gVGhlcmUgaXMgbm8gY29tcGlsYXRpb24gc3RlcC4gUiBkb2VzIHN1cHBvcnQgcmV1c2FibGUgdGhpcmQtcGFydHkgY29kZSAibGlicmFyaWVzIiBpbiB0aGUgZm9ybSBvZiAqcGFja2FnZXMqLgoKIyMgV29ya2luZyBpbiBSCgpUbyB3cml0ZSAicHJvZ3JhbXMiIGluIFIgeW91IHdpbGwgbmVlZCBCYXNlIFIgd2hpY2ggeW91IGNhbiBkb3dubG9hZCBmb3IgTGludXgsIE1hY09TLCBhbmQgV2luZG93cyBmcm9tIFtSIFByb2plY3RdKGh0dHBzOi8vd3d3LnItcHJvamVjdC5vcmcvKS4gVGhpcyBpcyB0aGUgY29yZSBsYW5ndWFnZSB3aXRoIGFuIGludGVyYWN0aXZlIGNvbnNvbGUuIFByb2dyYW1zLCBvciBtb3JlIGFwdGx5IFIgc2NyaXB0cywgY2FuIGJlIGJ1aWx0IGluIGFueSB0ZXh0IGVkaXRvciAoVGV4dEVkaXQsIE5vdGVwYWQsIHZpLCBTdWJsaW1lLCBKRWRpdCwgZXRjLikuCgpNb3N0IHByb2dyYW1taW5nIGlzIGRvbmUgd2l0aCBhbiBJREUgKEludGVncmF0ZWQgRGV2ZWxvcG1lbnQgRW52aXJvbm1lbnQpLiBUaGUgbW9zdCBjb21tb24gaXMgUiBTdHVkaW8gZG93bmxvYWRhYmxlIGZyb20gW1JTdHVkaW9dKGh0dHBzOi8vd3d3LnJzdHVkaW8uY29tL3Byb2R1Y3RzL3JzdHVkaW8vZG93bmxvYWQvKS4gVGhlcmUgaXMgYSBob3N0ZWQgdmVyc2lvbiBvZiBSIFN0dWRpbyBhdmFpbGFibGUgYXQgW3JzdHVkaW8uY2xvdWRdKGh0dHA6Ly9yc3R1ZGlvLmNsb3VkKS4KCj4gSW5zdGFsbCBSIGZyb20gW1IgUHJvamVjdF0oaHR0cHM6Ly9jbG91ZC5yLXByb2plY3Qub3JnLykgKipiZWZvcmUqKiBpbnN0YWxsaW5nIFtSIFN0dWRpb10oaHR0cHM6Ly9yc3R1ZGlvLmNvbS9wcm9kdWN0cy9yc3R1ZGlvL2Rvd25sb2FkLykuCgpUaGUgdHV0b3JpYWwgYmVsb3cgZXhwbGFpbnMgaG93IHRvIGdldCBzdGFydGVkIHdpdGggUiBOb3RlYm9va3M6Cgo8aWZyYW1lIHNyYz0iaHR0cHM6Ly9ub3J0aGVhc3Rlcm4uaG9zdGVkLnBhbm9wdG8uY29tL1Bhbm9wdG8vUGFnZXMvRW1iZWQuYXNweD9pZD04MGMyY2YwMi0wMGQyLTQyN2MtOGZjZC1hYmUwMDBmMDZmMGQmYW1wO2F1dG9wbGF5PWZhbHNlJmFtcDtvZmZlcnZpZXdlcj10cnVlJmFtcDtzaG93dGl0bGU9dHJ1ZSZhbXA7c2hvd2JyYW5kPWZhbHNlJmFtcDtjYXB0aW9ucz1mYWxzZSZhbXA7aW50ZXJhY3Rpdml0eT1hbGwiIGhlaWdodD0iMTgwIiB3aWR0aD0iMzIwIiBzdHlsZT0iYm9yZGVyOiAxcHggc29saWQgIzQ2NDY0NjsiIGFsbG93ZnVsbHNjcmVlbiBhbGxvdz0iYXV0b3BsYXkiIGRhdGEtZXh0ZXJuYWw9IjEiPgoKPC9pZnJhbWU+CgpFeGVjdXRlIGNodW5rcyBieSBjbGlja2luZyB0aGUgKlJ1biogYnV0dG9uIHdpdGhpbiB0aGUgY2h1bmsgb3IgYnkgcGxhY2luZyB5b3VyIGN1cnNvciBpbnNpZGUgaXQgYW5kIHByZXNzaW5nICpDdHJsK1NoaWZ0K0VudGVyKi4gVGhlIGNvZGUgcnVucyBpbiB0aGUgb3JkZXIgaW4gd2hpY2ggdGhlIGNodW5rcyBhcmUgZXhlY3V0ZWQsIHNvIG5vbi1saW5lYXIgY29kZSBleGVjdXRpb24gaXMgcG9zc2libGUgdW5sZXNzIHlvdSBpbnN0cnVjdCBSIFN0dWRpbyB0byBydW4gYWxsIGNodW5rcyBzdGFydGluZyBhdCB0aGUgZmlyc3QgY2h1bmsuCgpBZGQgYSBuZXcgY2h1bmsgYnkgY2xpY2tpbmcgdGhlICpJbnNlcnQgQ2h1bmsqIGJ1dHRvbiBvbiB0aGUgdG9vbGJhciBvciBieSBwcmVzc2luZyAqQ3RybCtBbHQrSSouCgpXaGVuIHlvdSBzYXZlIHRoZSBub3RlYm9vaywgYW4gSFRNTCBmaWxlIGNvbnRhaW5pbmcgdGhlIGNvZGUgYW5kIG91dHB1dCB3aWxsIGJlIHNhdmVkIGFsb25nc2lkZSBpdCAoY2xpY2sgdGhlICpQcmV2aWV3KiBidXR0b24gb3IgcHJlc3MgKkN0cmwrU2hpZnQrSyogdG8gcHJldmlldyB0aGUgSFRNTCBmaWxlKS4KClRoZSBwcmV2aWV3IHNob3dzIHlvdSBhIHJlbmRlcmVkIEhUTUwgY29weSBvZiB0aGUgY29udGVudHMgb2YgdGhlIGVkaXRvci4gQ29uc2VxdWVudGx5LCB1bmxpa2UgKktuaXQqLCAqUHJldmlldyogZG9lcyBub3QgcnVuIGFueSBSIGNvZGUgY2h1bmtzLiBJbnN0ZWFkLCB0aGUgb3V0cHV0IG9mIHRoZSBjaHVuayB3aGVuIGl0IHdhcyBsYXN0IHJ1biBpbiB0aGUgZWRpdG9yIGlzIGRpc3BsYXllZC4KCiMjIyBQcm9qZWN0cyBpbiBSIFN0dWRpbwoKUHJvamVjdHMgYXJlIGEgYmV0dGVyIHdheSB0byBtYW5hZ2UgY29kZSByYXRoZXIgdGhhbiBjcmVhdGluZyBpbmRpdmlkdWFsIFIgTm90ZWJvb2tzLCBSIFNjcmlwdHMsIGFuZCBvdGhlciBjb2RlIGZpbGVzLiBQcm9qZWN0cyBhbGxvd3MgYWxsIGZpbGVzLCBpbmNsdWRpbmcgZGF0YSBmaWxlcywgdG8gYmUgbWFuYWdlZCBhcyBhIHNpbmdsZSB1bml0LCBzaGFyZWQsIGFuZCB2ZXJzaW9uIGNvbnRyb2xsZWQgdXNpbmcgc2VydmljZXMgc3VjaCBhcyAqZ2l0KiBhbmQgKkdpdEh1YiouCgpUaGUgdHV0b3JpYWwgYmVsb3cgZGVtb25zdHJhdGVzIGhvdyB0byBjcmVhdGUgYSBwcm9qZWN0IGluIFIgU3R1ZGlvIGFuZCBhZGQgZmlsZXMgdG8gdGhlIHByb2plY3QuCgpgYGB7PWh0bWx9CjxpZnJhbWUgc3JjPSJodHRwczovL3BsYXllci52aW1lby5jb20vdmlkZW8vNjA3NDUxMzc0P2g9MzA1NmU3MzA3MyIgd2lkdGg9IjQ4MCIgaGVpZ2h0PSIyNzAiIGZyYW1lYm9yZGVyPSIwIiBhbGxvdz0iYXV0b3BsYXk7IGZ1bGxzY3JlZW47IHBpY3R1cmUtaW4tcGljdHVyZSIgYWxsb3dmdWxsc2NyZWVuIGRhdGEtZXh0ZXJuYWw9IjEiPjwvaWZyYW1lPgpgYGAKIyMgUiBDb2RlIENodW5rcwoKV2hpbGUgeW91IGNhbiBhbHNvIHdyaXRlIFIgU2NyaXB0cywgd2Ugd2lsbCBjb25jZW50cmF0ZSBvbiBob3cgdG8gd3JpdGUgUiAicHJvZ3JhbXMiIGJ5IGNvbXBvc2luZyBhbiBSIE5vdGVib29rIGluIFIgU3R1ZGlvLiBUaGlzIGlzIHRoZSBtb3N0IGNvbW1vbiB3YXkgdG8gdXNlIFIgaW4gZGF0YSByZWxhdGVkIHByb2plY3RzIHdoZXJlIHJlcHJvZHVjYWJpbGl0eSBpcyBwYXJhbW91bnQuIFByb2dyYW1zIGluIFIgcnVuIGZyb20gc3RhcnQgdG8gZW5kLiBFYWNoIGNodW5rIHNob3VsZCBiZSBhIHN0ZXAgaW4geW91ciBhbmFseXNpcyBvciBkYXRhIHByb2plY3QuIE5hbWUgeW91ciBjb2RlIGNodW5rcywgc28geW91IGNhbiBxdWlja2x5IG5hdmlnYXRlIHRvIHRoZW0uCgpJbiB0aGUgY2h1bmsgYmVsb3csIHRoZSB2YXJpYWJsZSAqY2FycyogcGFzc2VkIHRvIHRoZSBidWlsdC1pbiBCYXNlIFIgZnVuY3Rpb24gPGNvZGU+cGxvdDwvY29kZT4gaXMgb25lIG9mIHRoZSBkb3plbnMgb2YgImJ1aWx0LWluIiBkYXRhIGZyYW1lczsgYSBkYXRhIGZyYW1lIGJlaW5nIGRhdGEgYXJyYW5nZWQgaW4gcm93cyBhbmQgY29sdW1ucyBzaW1pbGFyIHRvIGEgc3ByZWFkc2hlZXQgb3IgQ1NWIGZpbGUuCgpOb3RlIHRoYXQgeW91IGNhbGwgYSBmdW5jdGlvbiBieSB1c2luZyB0aGUgZnVuY3Rpb24ncyBuYW1lIGZvbGxvd2VkIGJ5IHRoZSBhcmd1bWVudHMgeW91IHdpc2ggdG8gcGFzcyB0byB0aGUgZnVuY3Rpb24uIE9mIGNvdXJzZSwgeW91IG5lZWQgdG8gZm9sbG93IHRoZSBkZWZpbml0aW9uIG9mIHRoZSBmdW5jdGlvbi4gTWFueSBmdW5jdGlvbnMgYXJlIHNpbXBseSAiYnVpbHQtaW4iIHdoaWxlIG90aGVycyBjb21lIGZyb20gcGFja2FnZXMgdGhhdCB5b3UgbmVlZCB0byBleHBsaWNpdGx5IGxvYWQgaW50byB5b3VyIHByb2dyYW0uCgpOb3RlIHRoYXQgdGhlcmUgaXMgbm8gc2VtaWNvbG9uIGF0IHRoZSBlbmQgb2YgYSBsaW5lLgoKYGBge3IgbmFtZWRDaHVua30KcGxvdChjYXJzKQpgYGAKCiMjIyBFeHByZXNzaW9ucwoKUiBjYW4gYmUgZGlyZWN0bHkgdXNlZCB0byBzb2x2ZSBzaW1wbGUgb3IgY29tcGxleCBtYXRoZW1hdGljYWwgZXhwcmVzc2lvbnMuCgpgYGB7cn0KIyBbMV0gaW4gdGhlIGFib3ZlIGFuc3dlciBpbmRpY2F0ZXMgdGhlIGluZGV4IG9mIHlvdXIgcmVzdWx0cy4KIyBSIGFsd2F5cyBzaG93cyB0aGUgcmVzdWx0IHdpdGggaW5kZXggZm9yIGVhY2ggcm93LgoKKCgyXjMpKjUpLTEKYGBgCgpgYGB7cn0KIyBzcXJ0IGFuZCBleHAgYXJlIGJ1aWx0LWluIGZ1bmN0aW9ucyBpbiBSIGZvciBmaW5kaW5nIFNxdWFyZSByb290IGFuZCBleHBvbmVudGlhbCByZXNwZWN0aXZlbHkuCgpzcXJ0KDQpKiBleHAoMikKYGBgCgojIyBWYXJpYWJsZXMKClZhcmlhYmxlcyBhcmUgbm90IGRlY2xhcmVkIGluIFIuIFdoZW4geW91IHVzZSBhIHZhcmlhYmxlIGZvciB0aGUgZmlyc3QgdGltZSwgaXQgaXMgZGVmaW5lZCBhbmQgdGhlIGRhdGEgdHlwZSBpcyBiYXNlZCBvbiB3aGF0IHZhbHVlIHlvdSBhc3NpZ24gdG8gdGhlIHZhcmlhYmxlLiBTbywgUiB1c2VzIGR5bmFtaWMgdHlwaW5nLCB3aGljaCBhbHNvIG1lYW5zIHRoYXQgd2hlbiB5b3UgYXNzaWduIGEgdmFsdWUgb2YgYSBkaWZmZXJlbnQgdHlwZSB0byBhIHByZXZpb3VzbHkgdXNlZCB2YXJpYWJsZSwgaXQgY2hhbmdlcyB0eXBlLiBZb3UgY2FuIGZpbmQgdGhlIHR5cGUgb2YgYSB2YXJpYWJsZSB1c2luZyB0aGUgZnVuY3Rpb25zIDxjb2RlPnR5cGVvZjwvY29kZT4sIDxjb2RlPmNsYXNzPC9jb2RlPiwgYW5kIDxjb2RlPm1vZGU8L2NvZGU+LgoKUiBzdXBwb3J0cyB0aGUgdXN1YWwgZGF0YSB0eXBlczogaW50ZWdlciwgZG91YmxlLCBCb29sZWFuLCBhbmQgc3RyaW5nLiBJdCBhbHNvIGhhcyBwcmUtZGVmaW5lZCBjb21wbGV4IHR5cGVzLCBpbmNsdWRpbmcgdmVjdG9yLCBkYXRhIGZyYW1lLCBhcnJheSwgbGlzdCwgYW5kIG1hdHJpeC4gVGhlcmUgaXMgYWxzbyBhICpEYXRlKiBkYXRhIHR5cGUgYW5kIGEgZmV3IG90aGVycy4KClRoZSBhYnNlbmNlIG9mIGEgdmFsdWUgaXMgaW5kaWNhdGVkIGluIFIgdXNpbmcgKk5BKiByYXRoZXIgdGhhbiAqbmlsKiwgKm51bGwqIG9yICpOVUxMKi4gQW4gKk5BKiBtZWFucyB0aGF0IHRoZXJlIGlzIG5vIHZhbHVlIGZvciBhbiBpbnRlZ2VyLCBjaGFyYWN0ZXIsIGxvZ2ljYWwgdmFsdWUsIG9yIG51bWVyaWMuIE9uIHRoZSBvdGhlciBoYW5kLCAqTlVMTCogbWVhbnMgdGhhdCBhbiBvYmplY3QgaXMgImVtcHR5IiwgKmkuZS4qIGEgcmVmZXJlbmNlIHRvIGFuIG9iamVjdCB0aGF0IGRvZXMgbm90IGV4aXN0LgoKVmFsdWVzIGFyZSBhc3NpZ25lZCB0byB2YXJpYWJsZXMgdXNpbmcgZWl0aGVyICo9KiBvciAqXDwtKiwgdGhlIGxhdHRlciBiZWluZyBtb3JlIGNvbW1vbiBidXQgdGhlIGZvcm1lciBtb3JlIGZhbWlsaWFyIHRvIHByb2dyYW1tZXJzIG9mIG90aGVyIGNvbW1vbiBsYW5ndWFnZXMuCgpgYGB7ciB2YXJpYWJsZXMsIGV2YWw9RkFMU0V9CmEgPSAxMCAgICAgICAgICAgICAgICAgICAgICAgIyBkZWZpbmVzIGFuIGludGVnZXIKZCA9IDkuOSAgICAgICAgICAgICAgICAgICAgICAjIGRlZmluZXMgYSBkb3VibGUKcyA9ICJzb21lIHRleHQiICAgICAgICAgICAgICAjIGRlZmluZSBhIHN0cmluZyBvZiBjaGFyYWN0ZXJzCmcgPC0gJ2Fsc28gdGV4dCcgICAgICAgICAgICAgIyBzaW5nbGUgcXVvdGVzIGFyZSB0aGUgc2FtZSBhcyBkb3VibGUgcXVvdGVzCmBgYAoKVGV4dCBjYW4gYmUgZW5jbG9zZWQgaW4gc2luZ2xlIG9yIGRvdWJsZSBxdW90ZXMuIFdoaWNoIHlvdSB1c2UgZGVwZW5kcyBvbiBwcmVmZXJlbmNlIG9yIGlmIHlvdSBuZWVkIHRvIG5lc3QgcXVvdGVzLgoKYGBge3IgdGV4dFdpdGhRdW90ZXMsIGV2YWw9RkFMU0V9CnogPSAiSXQncyBhIHF1b3RlLiIKYGBgCgpUbyBlY2hvIHRoZSB2YWx1ZSBvZiBhIHZhcmlhYmxlIHRvIHRoZSBjb25zb2xlLCBlaXRoZXIgdXNlIHRoZSB2YXJpYWJsZSBvbiBhIGxpbmUgYnkgaXRzZWxmIG9yIHVzZSB0aGUgZnVuY3Rpb24gPGNvZGU+cHJpbnQ8L2NvZGU+LiBJZiB5b3UgbmVlZCB0byBlY2hvIG11bHRpcGxlIHZhbHVlcywgY29tYmluZSB0aGVtIHdpdGggPGNvZGU+cGFzdGUwPC9jb2RlPi4KCmBgYHtyIHByaW50VmFyc30KZCA8LSAxMjMuOTkKZApwcmludChwYXN0ZTAoIlZhbHVlIG9mIGQgPSAiLCBkKSkKYGBgCgojIyBNaXNzaW5nIFZhbHVlczogTkEgdnMgTlVMTAoKSW4gUiwgYE5BYCBhbmQgYE5VTExgIGFyZSB1c2VkIHRvIHJlcHJlc2VudCBkaWZmZXJlbnQgdHlwZXMgb2YgbWlzc2luZyBkYXRhLCBhbmQgdGhleSBzZXJ2ZSBkaWZmZXJlbnQgcHVycG9zZXM6CgoxLiAgKipOQSAoTm90IEF2YWlsYWJsZSkqKjoKICAgIC0gICBgTkFgIGlzIHVzZWQgdG8gcmVwcmVzZW50IG1pc3NpbmcgdmFsdWVzIGluIHZlY3RvcnMsIGxpc3RzLCBvciBkYXRhIGZyYW1lcy4gSXQgYWN0cyBhcyBhIHBsYWNlaG9sZGVyIGZvciBhbiBlbGVtZW50IHRoYXQgZG9lcyBub3QgaGF2ZSBhIHZhbHVlIGJ1dCBpcyBleHBlY3RlZCB0byBoYXZlIG9uZS4KICAgIC0gICBgTkFgIGNhbiBiZSBvZiBhbnkgZGF0YSB0eXBlIGxpa2UgbnVtZXJpYywgY2hhcmFjdGVyLCBvciBsb2dpY2FsLCBtZWFuaW5nIHlvdSBjYW4gaGF2ZSBgTkFfaW50ZWdlcl9gLCBgTkFfcmVhbF9gLCBgTkFfY29tcGxleF9gLCBhbmQgYE5BX2NoYXJhY3Rlcl9gLgogICAgLSAgIE9wZXJhdGlvbnMgaW52b2x2aW5nIGBOQWAgZ2VuZXJhbGx5IHJlc3VsdCBpbiBgTkFgLiBGb3IgZXhhbXBsZSwgYDUgKyBOQWAgcmVzdWx0cyBpbiBgTkFgLgogICAgLSAgIEEgdmFsdWUgb2YgYE5BYCBpcyBhIHZhbHVlIGFuZCBpcyBjb3VudGVkLCAqZS5nLiosIGBsZW5ndGgoYygzLE5BLDQpKWAgaGFzIHRoZSB2YWx1ZSAzLgoyLiAgKipOVUxMKio6CiAgICAtICAgYE5VTExgIGlzIHVzZWQgdG8gcmVwcmVzZW50IHRoZSBhYnNlbmNlIG9mIGEgdmFsdWUgb3Igbm8gdmFsdWUgYXQgYWxsLiBJdCBpcyB0eXBpY2FsbHkgdXNlZCB0byBkZW5vdGUgdGhhdCBhIHZhcmlhYmxlIGlzIGVtcHR5IG9yIHVuaW5pdGlhbGl6ZWQuCiAgICAtICAgYE5VTExgIGlzIG9mdGVuIHVzZWQgaW4gbGlzdCBvciBkYXRhIGZyYW1lIG9wZXJhdGlvbnMgdG8gcmVtb3ZlIGVsZW1lbnRzIG9yIGluZGljYXRlIHRoYXQgYW4gZWxlbWVudCBpcyBhYnNlbnQuCiAgICAtICAgYE5VTExgIGhhcyBhIGRpZmZlcmVudCBiZWhhdmlvciBpbiBvcGVyYXRpb25zIGNvbXBhcmVkIHRvIGBOQWAuIEZvciBpbnN0YW5jZSwgYWRkaW5nIGBOVUxMYCB0byBhbm90aGVyIG9iamVjdCBvciBjb25jYXRlbmF0aW5nIGl0IGdlbmVyYWxseSByZXN1bHRzIGluIHRoZSBvdGhlciBvYmplY3QgdW5jaGFuZ2VkLiBGb3IgZXhhbXBsZSwgYGMoMSwgMiwgTlVMTClgIHJlc3VsdHMgaW4gYGMoMSwgMilgLgoKRXNzZW50aWFsbHksIGBOQWAgaXMgdXNlZCB3aGVuIGFuIGVsZW1lbnQgb2YgdGhlIGRhdGEgZXhpc3RzIGJ1dCBpdHMgdmFsdWUgaXMgbWlzc2luZywgd2hlcmVhcyBgTlVMTGAgaXMgdXNlZCB3aGVuIHRoZSBkYXRhIGl0c2VsZiBkb2VzIG5vdCBleGlzdC4KCk1hbnkgZnVuY3Rpb25zIHRoYXQgcmV0dXJuIGFuIG9iamVjdCBzdWNoIGFzIGEgZGF0YSBmcmFtZSB3b3VsZCByZXR1cm4gKk5VTEwqIGlmIHRoZXkgY291bGQgbm90IGdlbmVyYXRlIHRoZSBvYmplY3QuCgpJbiBSLCB5b3UgY2FuIHRlc3QgZm9yIGBOQWAgYW5kIGBOVUxMYCB1c2luZyBzcGVjaWZpYyBmdW5jdGlvbnMgZGVzaWduZWQgZm9yIHRoaXMgcHVycG9zZS4gSGVyZeKAmXMgaG93IHlvdSBjYW4gZG8gaXQ6CgoxLiAgKipUZXN0aW5nIGZvciBOQSoqOgogICAgLSAgIFVzZSB0aGUgYGlzLm5hKClgIGZ1bmN0aW9uLCB3aGljaCBjaGVja3MgZm9yIGBOQWAgdmFsdWVzIGluIGFuIG9iamVjdC4gSXQgcmV0dXJucyBhIGxvZ2ljYWwgdmVjdG9yIG9mIHRoZSBzYW1lIHNpemUgYXMgdGhlIGlucHV0LCB3aXRoIGBUUlVFYCBmb3IgZWxlbWVudHMgdGhhdCBhcmUgYE5BYCBhbmQgYEZBTFNFYCBmb3IgdGhvc2UgdGhhdCBhcmUgbm90LgoKICAgIC0gICBFeGFtcGxlOgoKICAgICAgICBgYGAgcgogICAgICAgIHZlYyA8LSBjKDEsIE5BLCAzLCBOQSwgNSkKICAgICAgICBpcy5uYSh2ZWMpCiAgICAgICAgIyBPdXRwdXQ6IEZBTFNFICBUUlVFIEZBTFNFICBUUlVFIEZBTFNFCiAgICAgICAgYGBgCjIuICAqKlRlc3RpbmcgZm9yIE5VTEwqKjoKICAgIC0gICBVc2UgdGhlIGBpcy5udWxsKClgIGZ1bmN0aW9uLCB3aGljaCBjaGVja3MgaWYgYW4gb2JqZWN0IGlzIGBOVUxMYC4gSXQgcmV0dXJucyBgVFJVRWAgaWYgdGhlIG9iamVjdCBpcyBgTlVMTGAgYW5kIGBGQUxTRWAgb3RoZXJ3aXNlLgoKICAgIC0gICBFeGFtcGxlOgoKICAgICAgICBgYGAgcgogICAgICAgIHggPC0gTlVMTAogICAgICAgIGlzLm51bGwoeCkKICAgICAgICAjIE91dHB1dDogVFJVRQogICAgICAgIGBgYAoKVGhlc2UgZnVuY3Rpb25zIGFyZSB1c2VmdWwgaW4gdmFyaW91cyBwcm9ncmFtbWluZyBzY2VuYXJpb3MsIHN1Y2ggYXMgY29uZGl0aW9uYWwgZXhlY3V0aW9uIG9mIGNvZGUgZGVwZW5kaW5nIG9uIHRoZSBwcmVzZW5jZSBvZiBhY3R1YWwgZGF0YSwgYW5kIGhhbmRsaW5nIG1pc3NpbmcgdmFsdWVzIGluIGRhdGEgYW5hbHlzaXMgYW5kIHRyYW5zZm9ybWF0aW9uIHRhc2tzLgoKIyMgTmFtaW5nIElkZW50aWZpZXJzCgpUaGUgbmFtaW5nIG9mIGlkZW50aWZpZXJzLCAqaS5lLiosIHZhcmlhYmxlIGFuZCBmdW5jdGlvbiBuYW1lcywgYXJlIHRoZSBzYW1lIGFzIGluIG1vc3Qgb3RoZXIgbGFuZ3VhZ2VzLCBleGNlcHQgdGhhdCB5b3UgY2FuIHVzZSB0aGUgcGVyaW9kIGFzIGEgdmFsaWQgaWRlbnRpZmllciBjaGFyYWN0ZXIuIFRoYXQgY2FuIGJlIGNvbmZ1c2luZyB0byBKYXZhIGFuZCBDKysgcHJvZ3JhbW1lcnMgYXMgdGhleSBhcmUgdXNlZCB0byB1c2luZyAqLiogYXMgYSBtZXRob2Qgb3Igb2JqZWN0IHByb3BlcnR5IGFjY2VzcyBvcGVyYXRvci4gSW4gUiwgaXQncyBqdXN0IGFub3RoZXIgY2hhcmFjdGVyIGxpa2UgKmEqIG9yICpcXyouCgpgYGB7ciBpZGVudGlmaWVycywgZWNobz1UUlVFLCBldmFsPUZBTFNFfQphLnZhbCA9IDEwLjUgICAgICAgICAgIyBsZWdhbAphX3ZhbCA9IDEwLjUgICAgICAgICAgIyBsZWdhbAphVmFsMSA9IDEwLjUgICAgICAgICAgIyBsZWdhbAphJHZhbCA9IDEwLjUgICAgICAgICAgIyBub3QgcXVpdGUgbGVnYWwsICQgaXMgcmVzZXJ2ZWQgZm9yIGRhdGEgZnJhbWVzCmBgYAoKVGhlIGxhc3Qgb25lIGlzIGEgYml0IHRyaWNreS4gPGNvZGU+YVwkdmFsPC9jb2RlPiB3aWxsIGFjdHVhbGx5IGNyZWF0ZSBhIGxpc3Qgb2JqZWN0LiBMZXQncyBqdXN0IG5vdCB1c2UgaXQgdW5sZXNzIHlvdSBhcmUgYWNjZXNzaW5nIGNvbHVtbnMgaW4gYSBkYXRhIGZyYW1lLCBidXQgdGhhdCdzIGZvciBhbm90aGVyIHR1dG9yaWFsLgoKVGhlIHJ1bGVzIGZvciBuYW1pbmcgYW4gaWRlbnRpZmllciAodmFyaWFibGUsIGZ1bmN0aW9uLCBvciBwYWNrYWdlIG5hbWUpIGZvciBhbiBvYmplY3QgYXJlIGFzIGZvbGxvd3M6CgotICAgaWRlbnRpZmllcnMgYXJlIGNhc2Utc2Vuc2l0aXZlIGFuZCBjYW5ub3QgY29udGFpbiBzcGFjZXMgb3Igc3BlY2lhbCBjaGFyYWN0ZXJzIHN1Y2ggYXMgIywgJSwgXCQsIFxALCBcKiAsICYsIFxeLCAhLCBcfgoKLSAgIGFuIGlkZW50aWZpZXIgbXVzdCBzdGFydCB3aXRoIGEgbGV0dGVyLCBidXQgbWF5IGNvbnRhaW4gYW55IGNvbWJpbmF0aW9uIG9mIGxldHRlcnMgYW5kIGRpZ2l0cyB0aGVyZWFmdGVyCgotICAgc3BlY2lhbCBjaGFyYWN0ZXJzIGRvdCAoLikgYW5kIHVuZGVyc2NvcmUgKFxfKSBhcmUgYWxsb3dlZAoKVGhlIGRvdCAoLikgaXMgYSByZWd1bGFyIGNoYXJhY3RlciBpbiBSIGFuZCB0aGF0IGNhbiBiZSBjb25mdXNpbmcgYXMgb3RoZXIgbGFuZ3VhZ2VzICgqZS5nLiosIEphdmEpIHVzZSBkb3QgYXMgYW4gb3BlcmF0b3IgdG8gZGVzaWduYXRlIHByb3BlcnR5IG9yIG1ldGhvZCBhY2Nlc3MsICplLmcqLCBpbiBKYXZhICp4LnZhbCogbWVhbnMgdGhhdCB5b3UgYXJlIGFjY2Vzc2luZyB0aGUgKnZhbCogcHJvcGVydHkgb2YgdGhlIG9iamVjdCAqeCouCgpTb21lIGV4YW1wbGVzIG9mIGxlZ2FsIHZhcmlhYmxlIG5hbWVzIGFyZTogKmRmKiwgKmRmMiosICpkZi50eG5zKiwgYW5kICpkZl9hbGwyMDE3Ki4gVGhlc2UgYXJlIHNvbWUgaWxsZWdhbCB2YXJpYWJsZSBuYW1lczogKjJkZiogKGNhbm5vdCBzdGFydCB3aXRoIGEgZGlnaXQpLCAqcnNcJGFsbCogKGNhbm5vdCBjb250YWluIGEgXCQ7IHRoZSBcJCBpcyB1c2VkIHRvIGFjY2VzcyBjb2x1bW5zIGluIGEgZGF0YWZyYW1lKSwgKnJzIyogKG9ubHkgLiBhbmQgXF8gYXJlIGFsbG93ZWQgaW4gYWRkaXRpb24gdG8gZGlnaXRzIGFuZCBsZXR0ZXJzKS4KCkl0IGlzIGNvbnNpZGVyZWQgZ29vZCBwcm9ncmFtbWluZyBwcmFjdGljZSB0byBnaXZlIGlkZW50aWZpZXJzIGEgc2Vuc2libGUgbmFtZSB0aGF0IGhpbnRzIGFzIHRvIHdoYXQgaXMgc3RvcmVkIGluIHRoZSB2YXJpYWJsZSByYXRoZXIgdGhhbiB1c2luZyByYW5kb20gbmFtZSBsaWtlICp4KiwgKnZhbCosIG9yICppMzMqLiBJbnN0ZWFkIHVzZSAqYW5JdGVtKiBvciAqYW5udWFsVG90YWwqLgoKSWRlbnRpZmllcnMgc2hvdWxkIGJlIG5hbWVkIGNvbnNpc3RlbnRseS4gTWFueSBwcm9ncmFtbWVycyB1c2Ugb25lIG9mIHR3byBzdHlsZXM6CgotICAgdW5kZXJzY29yZXMsICplLmcuKiwgKmludGVyZXN0X3JhdGUqCi0gICBjYW1lbENhc2UsICplLmcuKiwgKnNxdWFyZVJvb3QqLCAqZ3JhcGhEYXRhKiwgKmN1cnJlbnRXb3JraW5nRGlyZWN0b3J5KgoKTm90ZSB0aGF0IFIgaXMgY2FzZSBzZW5zaXRpdmUgd2hpY2ggbWVhbnMgdGhhdCBSIHRyZWF0cyB0aGUgaWRlbnRpZmllcnMgKkFQKiBhbmQgKmFwKiBhcyBkaWZmZXJlbnQgb2JqZWN0cy4KCkFzIGEgc2lkZSBub3RlLCBmaWxlcyBtYXkgYWxzbyBiZSBjYXNlIHNlbnNpdGl2ZSBidXQgdGhhdCBkZXBlbmRzIG9uIHRoZSBvcGVyYXRpbmcgc3lzdGVtLiBNYWNPUyBhbmQgTGludXggYXJlIGNhc2Ugc2Vuc2l0aXZlLCB3aGlsZSBXaW5kb3dzIGlzIGNhc2UgYXdhcmUgYnV0IG5vdCBjYXNlIHNlbnNpdGl2ZS4gRm9yIGV4YW1wbGUsIG9uIE1hY09TIGFuZCBMaW51eCB0aGVyZSBpcyBhIGRpZmZlcmVuY2UgYmV0d2VlbiAiQWlyUGFzc2VuZ2Vycy50eHQiIGFuZCAiYWlycGFzc2VuZ2Vycy50eHQiIHdoaWxlIG9uIFdpbmRvd3MgdGhlcmUgaXMgbm90LiBTUUwgaXMgYWxzbyBub3QgY2FzZSBzZW5zaXRpdmUuIEl0IGlzIGEgYmVzdCBwcmFjdGljZSB0byBhc3N1bWUgY2FzZSBzZW5zaXRpdml0eS4KCiMjIEV4cHJlc3Npb25zCgpBcyBhIGxhbmd1YWdlIHdpdGggcm9vdHMgaW4gc3RhdGlzdGljYWwgYW5hbHlzaXMsIFIgc3VwcG9ydHMgbW9zdCBtYXRoZW1hdGljYWwgb3BlcmF0b3JzLCBpbmNsdWRpbmcgbWFueSB0aGF0IGFyZSBub3Qgc3VwcG9ydGVkIHRocm91Z2ggb3BlcmF0b3JzIGluIG1vc3Qgb3RoZXIgbGFuZ3VhZ2VzLgoKUHJlY2VkZW5jZSBpcyBsaWtlIG90aGVyIGxhbmd1YWdlcyBhbmQgY2FuIGJlIChhbmQgc2hvdWxkIGJlKSBzcGVjaWZpZWQgZXhwbGljaXRseSB1c2luZyBwYXJlbnRoZXNlcy4KCmBgYHtyIG9wZXJhdG9ycywgZWNobz1UUlVFfQphIDwtIDk5CgpiID0gYSArIDIwICAgICAgICAgICAgICAgICAjIGFkZGl0aW9uCmIgPSBhIC0gMjAgICAgICAgICAgICAgICAgICMgc3VidHJhY3Rpb24KYiA9IGEgKiAyMCAgICAgICAgICAgICAgICAgIyBtdWx0aXBsaWNhdGlvbgpiID0gYSAvIDIwICAgICAgICAgICAgICAgICAjIGRpdmlzaW9uIC0tIGIgaXMgbm93ICJkb3VibGUiCmIgPSBhIF4gMyAgICAgICAgICAgICAgICAgICMgZXhwb25lbnRpYXRpb24KYiA9IGEgJSUgMiAgICAgICAgICAgICAgICAgIyBtb2R1bHVzIChtb2QpCmIgPSBhICUvJSAyICAgICAgICAgICAgICAgICMgaW50ZWdlciBkaXZpc2lvbiAoZGl2KQoKYiA9IChhIC8gMikgXiA1ICAgICAgICAgICAgIyBmb3JjZSBvcmRlciBvZiBldmFsdWF0aW9uCmBgYAoKVGhlcmUgYXJlIGFsc28gbnVtZXJvdXMgYnVpbHQtaW4gZnVuY3Rpb25zIGZvciBtYXRoZW1hdGljcyBhbmQgc3RhdGlzdGljcywgYnV0IHRob3NlIGFyZSBiZXlvbmQgdGhpcyB0dXRvcmlhbCBvbiBiYXNlIHN5bnRheC4gRm9yIHRoZSBzYWtlIG9mIGNvbXBsZXRlbmVzcywgYW4gZXhhbXBsZSBpcyBzaG93biBiZWxvdyB0aGF0IGNhbGN1bGF0ZXMgdGhlICp6Ki1zY29yZSBvZiBhIHZlY3RvciBvZiBudW1iZXJzLiBJbiBSLCBhIHZlY3RvciBpcyBzaW1pbGFyIHRvIGFuIGFycmF5OyBpdCBjb250YWlucyBwcmltaXRpdmVzIHZhbHVlcyAoaW50ZWdlciwgZG91YmxlLCBCb29sZWFuLCBvciBzdHJpbmcpLiBOb3RpY2UgdGhlIGF1dG9tYXRpYyB2ZWN0b3IgY2FsY3VsYXRpb24gZXZlbiB3aXRob3V0IGEgbG9vcC4KCmBgYHtyIGZ1bmNzfQp2ID0gYygxLDQsNiwyLDgsMSwwLDMpICAgICAjIHZlY3RvciBvZiBpbnRlZ2VycwoKbSA9IG1lYW4odikgICAgICAgICAgICAgICAgIyBtZWFuIG9mIHZhbHVlcyBpbiB2CnMgPSBzZCh2KSAgICAgICAgICAgICAgICAgICMgc3RhbmRhcmQgZGV2aWF0aW9uCnogPSAobSAtIHYpIC8gcyAgICAgICAgICAgICMgei1zY29yZSBvZiBlYWNoIHZhbHVlIGluIHYKCnByaW50KHJvdW5kKHosMikpICAgICAgICAgICMgcHJpbnQgcm91bmRlZCB2YWx1ZXMKYGBgCgojIyMgQm9vbGVhbiBWYXJpYWJsZXMgYW5kIExvZ2ljYWwgRXhwcmVzc2lvbnMKCkJvb2xlYW4gdmFsdWVzIGFyZSAqVFJVRSogYW5kICpGQUxTRSo7IG9yICpUKiBhbmQgKkYqLCByZXNwZWN0aXZlbHkuCgpgYGB7ciBib29sZWFuc30KbSA9IEZBTFNFCncgPSBUUlVFCgpxID0gKG0gJiB3KSB8ICghbSAmICF3KQoKcHJpbnQocGFzdGUwKCJxIGlzICIsIHEpKQpgYGAKClRoZSBCb29sZWFuIG9wZXJhdG9ycyBhcmUgKiYqIGZvciBBTkQsICpcfCogZm9yIE9SLCBhbmQgKiEqIGZvciBOT1QuIFRoZXNlIG9wZXJhdG9ycyBwZXJmb3JtIGxvZ2ljYWwgb3BlcmF0aW9ucyBvbiBCb29sZWFuIHZhcmlhYmxlcyBvciB2ZWN0b3Igb2YgQm9vbGVhbiBlbGVtZW50cy4gRXhjbHVzaXZlIG9yICgqeG9yKikgaXMgcGVyZm9ybWVkIHdpdGggdGhlIGZ1bmN0aW9uICp4b3IqLCAqZS5nLiosIDxjb2RlPnhvcihhLGIpPC9jb2RlPi4KClRoZXJlIGFyZSBsb25nIGZvcm1zIComJiogYW5kICpcfFx8KiBmb3IgcHJvZ3JhbW1pbmcgY29udHJvbC1mbG93IGFuZCBnZW5lcmFsbHkgcHJlZmVycmVkIGZvciAqaWYqIHN0YXRlbWVudHMuCgojIyBGbG93IENvbnRyb2wKClRoZSBjb250cm9sIGZsb3cgc3RhdGVtZW50cyBwcm92aWRlZCBieSBSIGFyZSBzaW1pbGFyIHRvIHRob3NlIGZvdW5kIGluIG1vc3Qgb3RoZXIgcHJvZ3JhbW1pbmcgbGFuZ3VhZ2VzOiBsb29wcyBhbmQgaWYgc3RhdGVtZW50cy4KCiMjIyBMb29wcwoKUiBzdXBwb3J0cyB0aGUgdGhyZWUgY29tbW9uIHR5cGVzIG9mIGxvb3BzOiBhIGNvdW50aW5nIGxvb3AgKCpmb3IqKSwgYSB0b3AtdGVzdGVkIGxvb3AgKCp3aGlsZSopLCBhbmQgYSBib3R0b20tdGVzdGVkIGxvb3AgKCpyZXBlYXQqKS4KCiMjIyMgQ291bnRpbmcgTG9vcDogKmZvcioKClRoZSBjb3VudGluZyBsb29wIGlzIGFjdHVhbGx5IG1vcmUgbGlrZSBhbiBpdGVyYXRvciBpbiBSLCBhbHRob3VnaCBpdCBjYW4gYmUgc2V0IHVwIHRvIG1pbWljIHRoZSBiZWhhdmlvciBvZiBhIHR5cGljYWwgbG9vcCBpbiBDL0MrKywgSmF2YSwgKmV0Yy4qLCB0aGF0IGxvb3BzIGZyb20gYSBsb3cgdmFsdWUgdG8gYSBoaWdoIHZhbHVlLiBTZWUgdGhlIGV4YW1wbGVzIGJlbG93LgoKYGBge3Igc2ltcGxlRm9yTG9vcH0KbiA9IDUKZm9yIChpIGluIDE6bikgewogIHByaW50KGkpCn0KYGBgCgpJbiB0aGUgZXhhbXBsZSBhYm92ZSwgKmkqIGlzIHRoZSBsb29wIHZhcmlhYmxlIGFuZCBpdCB0YWtlcyBvbiB0aGUgdmFsdWVzIGluIHRoZSB2ZWN0b3IgKjE6NSosICppLmUuLCogMSwgMiwgMywgNCwgNSBcZW0gb25lIGF0IGEgdGltZS4gCgpUbyBjb3VudCBkb3duLCBpdCB3b3VsZCBiZSAqNToxKiBvciAqbjoxKiBpbiB0aGUgYWJvdmUgY29kZSBleGFtcGxlLgoKTGlrZSBvdGhlciBsYW5ndWFnZXMsIFIgdXNlcyBjdXJseSBicmFjZXMgdG8gZW5jbG9zZSB0aGUgYm9keSBvZiB0aGUgbG9vcCwgKmkuZS4qLCB0aGUgc3RhdGVtZW50cyB0aGF0IGFyZSBleGVjdXRlZCByZXBlYXRlZGx5LCBvbmNlIGZvciBlYWNoIHZhbHVlIG9mICppKi4gT2YgY291cnNlLCB0aGUgbG9vcCBjb3VudGVyIGNhbiBiZSBhbnkgcHJvcGVybHkgbmFtZWQgdmFyaWFibGUuCgpUaGUgZXhhbXBsZSBiZWxvdyBhY2Nlc3NlcyBhIHZlY3RvciB1c2luZyBwb3NpdGlvbmFsIGFjY2VzcywgKmUuZy4qLCAqdlsxXSogYWNjZXNzZXMgdGhlIGZpcnN0IGVsZW1lbnQuIE5vdGUgdGhhdCB2ZWN0b3IsIGRhdGEgZnJhbWVzLCBsaXN0cywgYW5kIGFycmF5cyBhcmUgaW5kZXhlZCBzdGFydGluZyBhdCAxIGFuZCBub3QgMCBhcyBpbiBDLWJhc2VkIGxhbmd1YWdlcy4KCmBgYHtyIGxvb3BzQ2FsY3N9CnYgPSBybm9ybSg1KSAgICAgICMgdmVjdG9yIG9mIGZpdmUgcmFuZG9tIG51bWJlcnMKZm9yIChpIGluIDE6bGVuZ3RoKHYpKSAKewogIHZbaV0gPSB2W2ldIF4gMgp9CgpwcmludCh2KQpgYGAKCldoaWxlIHlvdSBjYW4gdXNlIGxvb3BzIHlvdSBhY3R1YWxseSBkbyBub3QgbmVlZCB0aGVtLiBJZiB5b3UgYXBwbHkgYSBtYXRoZW1hdGljYWwgb3BlcmF0aW9uIHRvIGEgdmVjdG9yLCBSIGF1dG9tYXRpY2FsbHkgYXBwbGllcyB0aGVtIHRvIGVhY2ggZWxlbWVudCwgYnV0IGxvb3BzIG1pZ2h0IGJlIG1vcmUgbmF0dXJhbCBpbiB0aGUgYmVnaW5uaW5nLgoKYGBge3IgdmVjdG9yUHJvY30KIyBub3RlIHRoYXQgeW91IGFjdHVhbGx5IGRvIG5vdCBuZWVkIGxvb3BzIGluIFIKIyB0aGlzIGFsc28gc3F1YXJlcyBlYWNoIGVsZW1lbnQgaW4gdGhlIHZlY3RvciB2CnYgPSB2IF4gMgpgYGAKCkFzIGFscmVhZHkgc3RhdGVkLCBsb29waW5nIGluIFIgaXMgYWN0dWFsbHkgaXRlcmF0aW9uIG92ZXIgYSBzZXQ6IGEgc2V0IG9mIG51bWJlcnMgYXMgYWJvdmUgb3IgYSBzZXQgb2YgYW55IGtpbmQgb2YgcHJpbWl0aXZlIG9iamVjdCwgKmUuZy4sKiBzdHJpbmdzLiBOb3RlIHRoYXQgaW4gdGhlIGNvZGUgYmVsb3csICprKiB0YWtlcyBvbiBlYWNoIHZhbHVlIGluIHRoZSB2ZWN0b3Igb3ZlciB3aGljaCB0aGUgbG9vcCBpdGVyYXRlcy4KCmBgYHtyIGl0ZXJhdGVPdmVyU3RyaW5nc30KcyA9IGMoIm9uZSIsInR3byIsInRocmVlIiwiZm91ciIpCgpmb3IgKGsgaW4gcykgewogIHByaW50KGspCn0KYGBgCgpXZSBjb3VsZCBoYXZlIHdyaXR0ZW4gdGhpcyB1c2luZyBhIG5vbi1pdGVyYXRvciBhcHByb2FjaCBhcyB3ZWxsLCB3aGljaCBpcyBtb3JlIGxpa2Ugd2hhdCB5b3UnZCBkbyBpbiBDLiBOb3RlIHRoYXQgPGNvZGU+bGVuZ3RoPC9jb2RlPiByZXR1cm5zIHRoZSBudW1iZXIgb2YgZWxlbWVudHMgaW4gYSB2ZWN0b3IsICppLmUuKiwgaXRzICJsZW5ndGgiLgoKYGBge3IgbG9vcE92ZXJTdHJpbmdzfQpzID0gYygib25lIiwidHdvIiwidGhyZWUiLCJmb3VyIikKCmZvciAoaiBpbiAxOmxlbmd0aChzKSkgewogIHByaW50KHNbal0pCn0KYGBgCgojIyMjIyBJdGVyYXRpb24gQ29udGludWF0aW9uCgpDb250aW51YXRpb24gb2YgdGhlIGxvb3AgdG8gdGhlIG5leHQgaXRlcmF0aW9uIGFuZCBmb3Jnb2luZyBwcm9jZXNzaW5nIHRoZSByZW1haW5kZXIgb2YgdGhlIGN1cnJlbnQgaXRlcmF0aW9uIGlzIGRvbmUgd2l0aCAqbmV4dCogaW4gUiwgc2ltaWxhciB0byAqY29udGludWUqIGluIEMtYmFzZWQgbGFuZ3VhZ2VzIHN1Y2ggYXMgSmF2YS4KCkluIHRoZSBleGFtcGxlIGJlbG93IHdlIGFyZSBhbHJlYWR5IHJlYWNoaW5nIGFoZWFkIHRvIHRoZSAqaWYqIHN0YXRlbWVudC4gVGhlIGNvZGUgZnJhZ21lbnQgZWNob2VzIG9ubHkgb2RkIG51bWJlci4gT2YgY291cnNlLCB5b3UgY291bGQgaGF2ZSBkb25lIHRoaXMgZGlmZmVyZW50bHkgYnkganVzdCBpdGVyYXRpbmcgb3ZlciB0aGUgZXZlbiBudW1iZXJzIGZyb20gb25lIHRvIHR3ZW50eSwgYnV0IHRoYXQgd291bGQgbm90IGhhdmUgYWxsb3dlZCB1cyB0byBzaGFyZSB0aGlzIGV4YW1wbGUgZm9yIHVzaW5nICpuZXh0Ki4KCmBgYHtyIG5leHRJbkZvcn0KZm9yIChpIGluIDE6MTApIHsKICBpZiAoIWkgJSUgMikgewogICAgbmV4dAogIH0KICBwcmludChpKQp9CmBgYAoKQnV0LCBqdXN0IHRvIHNob3cgeW91IGhvdyB0byBpdGVyYXRlIG92ZXIganVzdCBvZGQgbnVtYmVyLCB3ZSBjYW4gdXNlIHRoZSA8Y29kZT5zZXEoKTwvY29kZT4gZnVuY3Rpb24gd2hpY2ggZ2VuZXJhdGVzIGEgc2VxdWVuY2Ugb2YgbnVtYmVycyBpbiBzdGVwcy4gTm8gKmlmKiBhbmQgbm8gKmJyZWFrKiBuZWVkZWQgLS0gbXVjaCBzaW1wbGVyLgoKYGBge3IgbG9vcE92ZXJPZGRTZXF9CmZvciAoaSBpbiBzZXEoMSwgMTAsIDIpKSB7CiAgcHJpbnQoaSkKfQpgYGAKCk9yLCBtb3JlIGV4cGxpY2l0bHkgYnkgc3BlY2lmeWluZyB0aGUgcGFyYW1ldGVycyBieSBuYW1lLgoKYGBge3IgbG9vcE92ZXJPZGRTZXFXaXRoUGFybXN9CmZvciAoaSBpbiBzZXEoZnJvbSA9IDEsIHRvID0gMTAsIGJ5ID0gMikpIHsKICBwcmludChpKQp9CmBgYAoKVG8gc3RvcCB0aGUgZXhlY3V0aW9uIG9mIHRoZSByZXN0IG9mIGEgbG9vcCBhbmQgdG8gbW92ZSBpbW1lZGlhdGVseSB0byB0aGUgbmV4dCBzdGF0ZW1lbnQgYWZ0ZXIgdGhlIGxvb3AgaXMgZG9uZSB3aXRoICpicmVhayogaW4gUiB3aGljaCBpcyBpZGVudGljYWwgdG8gQywgQysrLCBKYXZhLCBldGMuIEluIHRoZSBjb2RlIGJlbG93IHdlIHdpbGwgZmluZCB0aGUgcG9zaXRpb24gb2YgdGhlIGZpcnN0IG9jY3VycmVuY2Ugb2Ygc29tZSBudW1iZXI7ICp4KiBpcyB0aGUgbnVtYmVyIHdlIGFyZSBsb29raW5nIGZvciBpbiAqdiogYW5kICpwKiBpcyB0aGUgZm91bmQgcG9zaXRpb24uCgpgYGB7ciBicmVha0Zvcn0KdiA9IGMoMSwgMywgNSwgNywgMSwgOSwgNCkKeCA9IDkKcCA9IDAKCmZvciAoaSBpbiAxOmxlbmd0aCh2KSkgewogIGlmICh2W2ldID09IHgpIHsKICAgIHAgPSBpCiAgICBicmVhawogIH0KfQoKcHJpbnQocCkKYGBgCgpUbyBiZSBjbGVhciwgdGhlcmUgaXMgYSBxdWlja2VyIGFuZCBtb3JlIGVmZmljaWVudCB3YXkgdG8gZG8gdGhpcyB1c2luZyB0aGUgPGNvZGU+d2hpY2g8L2NvZGU+IGZ1bmN0aW9uLiBUaGlzIGZ1bmN0aW9uIGRvZXMgbm90IGV4aXN0IGlzIG90aGVyIGxhbmd1YWdlcyBhbmQgaXQgc2hvd3MgdGhlIHBvd2VyIG9mIFIuIEFsc28sIHVzaW5nIDxjb2RlPndoaWNoPC9jb2RlPiBpcyBtdWNoIGZhc3Rlci4gSW5jaWRlbnRhbGx5LCB0aGUgY29kZSBiZWxvdyBmaW5kcyBhbGwgb2NjdXJyZW5jZXMgb2YgKngqIGluICp2Ki4gTm90ZSwgb25jZSBhZ2FpbiwgdGhlIHVzZSBvZiBhIHZlY3RvciB2YXJpYWJsZSB0byByZWZlciB0byBhbGwgZWxlbWVudHMuCgpgYGB7ciBmaW5kVmFsV2l0aFdoaWNofQp2ID0gYygxLCAzLCA1LCA3LCAxLCA5LCA0KQp4ID0gOQoKcCA9IHdoaWNoKHYgPT0geCkKCnByaW50KHApCmBgYAoKIyMjIyBDb25kaXRpb25hbCBMb29wczogKndoaWxlKiBhbmQgKnJlcGVhdCoKCkxpa2UgbWFueSBvdGhlciBsYW5ndWFnZXMsIFIgc3VwcG9ydHMgdG9wIGFuZCBib3R0b20gdGVzdGVkIGxvb3BzLiBJbiB0aGUgZXhhbXBsZSBiZWxvdyB3ZSByZXBlYXRlZGx5IGFzayBmb3IgYSBudW1iZXIgZnJvbSB0aGUgdXNlciBhbmQgb25seSBleGl0IHRoZSBsb29wIGlmIHRoZSBudW1iZXIgaXMgNDIuIE9mIGNvdXJzZSwgdGhlIGV4YW1wbGUgcmVhbGx5IHNob3VsZCBiZSBkb25lIHdpdGggYSBib3R0b20gdGVzdGVkIGxvb3AuCgpgYGB7ciB3aGlsZUxvb3AsIGV2YWw9Rn0KcmVzcG9uc2UgPC0gYXMuaW50ZWdlcihyZWFkbGluZShwcm9tcHQ9IkVudGVyIGEgbnVtYmVyOiAiKSkKCndoaWxlIChyZXNwb25zZSAhPSA0MikgeyAgIAogIHByaW50KCJTb3JyeSwgbm90IGNvcnJlY3QiKTsKICByZXNwb25zZSA8LSBhcy5pbnRlZ2VyKHJlYWRsaW5lKHByb21wdD0iRW50ZXIgYSBudW1iZXI6ICIpKTsKfQpgYGAKCkluIHRoZSBhYm92ZSBleGFtcGxlLCB3ZSBhcmUgdXNpbmcgdHdvIG5ldyBmdW5jdGlvbnMuIDxjb2RlPnJlYWRsaW5lPC9jb2RlPiBpcyB1c2VkIHRvIHJlYWQgaW5wdXQgZnJvbSB0aGUgY29uc29sZSwgd2hpbGUgPGNvZGU+YXMuaW50ZWdlcjwvY29kZT4gY29lcmNlcyAob3IgY2FzdHMgaW4gQy9DKysgdGVybWlub2xvZ3kpIHRoZSBpbnB1dCB0byBhbiBpbnRlZ2VyLgoKVGhlIGNvZGUgaXMgYWJvdmUgaXMgbm90IHZlcnkgZWZmaWNpZW50IG9yIGVsZWdhbnQgYXMgaXQgaGFzIHRoZSBjb2RlIGZvciB0aGUgdXNlciBwcm9tcHQgdHdpY2UuIEl0IGlzIHJlYWxseSBiZXR0ZXIgdG8gYXNrIGZpcnN0IGFuZCB0aGVuIGNoZWNrIHRoZSBjb25kaXRpb246IHdlIG5lZWQgYSBib3R0b20tdGVzdGVkIGxvb3AuCgpMZXQncyBsb29rIGF0IHRoZSBzYW1lIGV4YW1wbGUsIGJ1dCB3aXRoIGEgKnJlcGVhdCogbG9vcCB0aGF0IHJ1bnMgdW50aWwgYSBjb25kaXRpb24gaXMgcmVhY2hlZCBhbmQgdGhlIGxvb3AgaXMgZXhwbGljaXRseSBleGl0ZWQgd2l0aCAqYnJlYWsqLiBTbywgaWYgeW91IHdhbnQgdG8gcnVuIHRoZSBjb2RlIGF0IGxlYXN0IG9uY2UsIHVzZSAqcmVwZWF0KjsgaWYgdGhlIGNvZGUgaXMgcnVuIHplcm8gb3IgbW9yZSB0aW1lcywgdXNlICp3aGlsZSouIFRoZSAqcmVwZWF0KiBsb29wIGlzIGlkZW50aWNhbCB0byB0aGUgKmRvKiBvciAqZG8gd2hpbGUqIGxvb3AgZm91bmQgaW4gbWFueSBvdGhlciBwcm9ncmFtbWluZyBsYW5ndWFnZXMuCgpgYGB7ciByZXBlYXRMb29wLCBldmFsPUZ9CnJlcGVhdCB7ICAgCiAgcmVzcG9uc2UgPC0gYXMuaW50ZWdlcihyZWFkbGluZShwcm9tcHQ9IkVudGVyIGEgbnVtYmVyOiAiKSk7CiAgaWYgKHJlc3BvbnNlID09IDQyKSB7CiAgICBicmVhawogIH0KICBwcmludCgiU29ycnksIG5vdCBjb3JyZWN0Iik7Cn0KYGBgCgpUaGVyZSBpcyBubyBlcXVpdmFsZW50IGluIFIgZm9yIHRoZSB1c2Ugb2YgYW4gaW5maW5pdGUgKmZvciogbG9vcCBhcyBpbiBDIGFuZCBDKyssICplLmcuKiwgPGNvZGU+Zm9yKDs7KXsgLy8gZG8gc29tZXRoaW5nIGluZGVmaW5pdGVseSB9PC9jb2RlPiB0aGF0IHJ1bnMgdW50aWwgYSBjb25kaXRpb24gaXMgcmVhY2hlZCBhbmQgdGhlbiB1c2VzICpicmVhayogdG8gZXhpdCB0aGUgbG9vcC4gVGhlICpyZXBlYXQqIGxvb3AgY29uc3RydWN0IGlzIHVzZWQgaW5zdGVhZC4gVGhlcmUgaXMgbm8gdGVzdGluZyBvZiBhIGNvbmRpdGlvbiBpbiB0aGUgKnJlcGVhdCogbG9vcCwgc28gdGhlcmUncyBubyBlcXVpdmFsZW50IHRvIHRoZSBDLWxpa2UgY29uc3RydWN0ICpkbyAuLi4gd2hpbGUqLgoKIyMjIEFsdGVybmF0aW9uOiAqaWYqCgpUaGUgdXNlIG9mICppZiogdG8gc2VsZWN0aXZlbHkgZXhlY3V0ZSBhIGJsb2NrIG9mIGNvZGUgYmFzZWQgb24gYSBjb25kaXRpb24gaXMgdGhlIHNhbWUgaW4gUiBhcyBpdCBpcyBpbiBvdGhlciBsYW5ndWFnZXMuIFdlIGFscmVhZHkgc2F3IGFuIGV4YW1wbGUgYW5kIHRoZSBzYW1lIGV4YW1wbGUgaXMgYmVsb3c6CgpgYGB7ciBpZn0KZm9yIChpIGluIDE6MTApIHsKICBpZiAoIWkgJSUgMikgewogICAgbmV4dAogIH0KICBwcmludChpKQp9CmBgYAoKTm90ZSB0aGF0IHRoZSBjb25kaXRpb24gaXMgaW4gcGFyZW50aGVzaXMgYW5kIHRoYXQgdGhlIGJsb2NrIGV4ZWN1dGVkIGlmIHRoZSBjb25kaXRpb24gaXMgdHJ1ZSBpcyBpbiBjdXJseSBicmFjZXMuIFRoaXMgaXMgaWRlbnRpY2FsIHRvIEMsIEMrKywgSmF2YSwgUHl0aG9uLCBldGMuCgpBIG1vcmUgY29tcGxleCBleGFtcGxlIGlzIHNob3duIGJlbG93IHRoYXQgc3F1YXJlcyBhbGwgbnVtYmVycyBpbiBhIHZlY3RvciB0aGF0IGFyZSBsZXNzIHRoYW4gNSBhbmQgY3ViZXMgdGhlbSBpZiBncmVhdGVyIHRoYW4gNS4gTm90IGEgdXNlZnVsIGV4YW1wbGUgYnV0IG9uZSB0aGF0IGFsbG93cyB1cyB0byBzaG93IHRoZSB1c2Ugb2YgKmlmLWVsc2UqLgoKYGBge3IgaWZFbHNlfQpmb3IgKGkgaW4gMToxMCkgewogIGlmIChpIDwgNSkgewogICAgcHJpbnQoaV4yKQogIH0gZWxzZSB7CiAgICBwcmludChpXjMpCiAgfQp9CmBgYAoKIyMgRnVuY3Rpb25zCgpDb2RlIG9yZ2FuaXphdGlvbiBhbmQgcmV1c2UgaW4gUiBpcyBkb25lIHVzaW5nIGZ1bmN0aW9ucy4gQWxsIG9iamVjdHMgYXJlIGZyZWUgbWV0aG9kcyBhbmQgYXJlIG5vdCBib3VuZCB0byBhbiBvYmplY3Qgb3IgYSBjbGFzcyBsaWtlIGluIEphdmEgb3IgQysrLiBJdCdzIHRoZSBzYW1lIHdheSBhcyBpbiBQeXRob24gb3IgQy4KCkFsbCBmdW5jdGlvbnMgaW4gUiBjYW4gcmV0dXJuIGEgdmFsdWUsIGFsdGhvdWdoIHRoZXkgZG8gbm90IGhhdmUgdG8uIFNvLCBSIGRvZXMgbm90IGRpc3Rpbmd1aXNoIGJldHdlZW4gZnVuY3Rpb25zIGFuZCBwcm9jZWR1cmVzIGFuZCB0aGVyZSBpcyBubyAqdm9pZCogcmV0dXJuIHR5cGUgYXMgaW4gQywgQysrLCBhbmQgSmF2YS4KCiMjIyBEZWZpbmluZyBhIEZ1bmN0aW9uCgpUaGUgZ2VuZXJpYyB0ZW1wbGF0ZSBmb3IgZGVmaW5pbmcgYSBmdW5jdGlvbiBpczoKCmBgYHtyIGV2YWw9RkFMU0V9CmZ1bmN0aW9uX25hbWUgPC0gZnVuY3Rpb24oYXJnXzEsIGFyZ18yLCAuLi4pIHsKICAgRnVuY3Rpb24gYm9keSAKfQpgYGAKClRoZSBleGFtcGxlIGJlbG93IGRlZmluZXMgYSBmdW5jdGlvbiBjYWxsZWQgKmZpbmRTbWFsbGVzdCgpKiB3aGljaCB0YWtlcyBhIHZlY3RvciBvZiBwb3NpdGl2ZSBpbnRlZ2VycyBhcyBhbiBhcmd1bWVudCBhbmQgcmV0dXJucyB0aGUgc21hbGxlc3QgZWxlbWVudCBpbiB0aGUgdmVjdG9yLiBXaGlsZSBpdCBjYW4gYmUgc29sdmVkIGluIHNldmVyYWwgd2F5cywgd2Ugd2lsbCBzaG93IGEgZGVzaWduIHRoYXQgdXNlcyBsb29wcyBhbmQgc2hvdWxkIGJlIGZhbWlsaWFyIHRvIHByb2dyYW1tZXJzIG9mIG1vc3Qgb3RoZXIgbGFuZ3VhZ2VzLgoKTm90ZSB0aGF0IHdlIGFyZSB1c2luZyB0aGUgcHJlZGVmaW5lZCB2YWx1ZSAqSW5mKiB3aXRoIGlzIHRoZSBsYXJnZXN0IHJlcHJlc2VudGFibGUgaW50ZWdlci4gVGhlcmUgaXMgYWxzbyAqLUluZiogdGhhdCBpcyB0aGUgc21hbGxlc3QgcmVwcmVzZW50YWJsZSBpbnRlZ2VyLgoKYGBge3IgZnVuY3Rpb25EZWZ9CmZpbmRTbWFsbGVzdCA9IGZ1bmN0aW9uKHYpCnsKICBzID0gSW5mCiAgZm9yIChpIGluIDE6bGVuZ3RoKHYpKQogIHsKICAgIGlmICh2W2ldIDwgcykgewogICAgICBzID0gdltpXQogICAgfQogIH0KICByZXR1cm4gKHMpCn0KYGBgCgpXaGlsZSB5b3UgY2FuIHVzZSAqPSogdG8gZGVmaW5lIGEgZnVuY3Rpb24sIHlvdSBzaG91bGQgcmVhbGx5IGdldCB1c2VkIHRvIHVzaW5nIHRoZSBtb3JlIGNvbW1vbiAqXDwtKiBzeW50YXguIFNvLCBsZXQncyB0cnkgYWdhaW46CgpgYGB7ciBmdW5jdGlvbkRlZkJldHRlcn0KZmluZFNtYWxsZXN0IDwtIGZ1bmN0aW9uKHYpCnsKICBzID0gSW5mCiAgZm9yIChpIGluIDE6bGVuZ3RoKHYpKQogIHsKICAgIGlmICh2W2ldIDwgcykgewogICAgICBzID0gdltpXQogICAgfQogIH0KICByZXR1cm4gKHMpCn0KYGBgCgpKdXN0IHRvIGJlIGNsZWFyLCBpbiBwcmFjdGljZSB5b3Ugd291bGQgdXNlIHRoZSA8Y29kZT5taW4oKTwvY29kZT4gZnVuY3Rpb24gdG8gZmluZCB0aGUgc21hbGxlc3QgZWxlbWVudCByYXRoZXIgd3JpdGluZyBpdCB5b3Vyc2VsZi4KCldoaWxlIHRoZXJlIGFyZSBzZXZlcmFsIHdheXMgdG8gcmV0dXJuIGEgdmFsdWUgZnJvbSBhIGZ1bmN0aW9uLCB0aGUgd2F5IHRoYXQgaXMgbW9zdCBjb25ncnVlbnQgd2l0aCBvdGhlciBsYW5ndWFnZXMgaXMgdGhlIHVzZSBvZiB0aGUgKnJldHVybiogc3RhdGVtZW50LgoKTm90ZSB0aGF0IHRoZSB0eXBlIG9mIHJldHVybiB2YWx1ZSBhbmQgdGhlIHR5cGUgb2YgYXJndW1lbnRzIGFyZSBub3QgZGVjbGFyZWQuIFIgdXNlcyBhIGxhenkgZXZhbHVhdGlvbiBtZWNoYW5pc20gYW5kIG5vIHR5cGUgY2hlY2tpbmcgaXMgcGVyZm9ybWVkIHVudGlsIHJ1bi10aW1lLgoKIyMjIENhbGxpbmcgYSBGdW5jdGlvbgoKVG8gY2FsbCBhIGZ1bmN0aW9uLCB5b3Ugd291bGQgaW52b2tlIGl0IHdpdGggaXRzIG5hbWUgYW5kIGl0cyByZXF1aXJlZCBhcmd1bWVudHMuCgpgYGB7ciBjYWxsRnVuY30KeCA9IGMoMywxLDksNywzLDYpCgp3ID0gZmluZFNtYWxsZXN0KHgpCnByaW50KHcpCmBgYAoKIyMjIEZ1bmN0aW9uIFBhcmFtZXRlcnMKCklmIGEgZnVuY3Rpb24gdGFrZXMgc2V2ZXJhbCBhcmd1bWVudHMgeW91IGdlbmVyYWxseSBwYXNzIHRoZW0gaW4gdGhlIG9yZGVyIGRlY2xhcmVkOyB0aGUgYXBwcm9hY2ggdGhhdCBpcyB1c2VkIGJ5IGFsbCBvdGhlciBsYW5ndWFnZXMuIEhvd2V2ZXIsIGluIFIgeW91IGNhbiBwYXNzIHRoZSBhcmd1bWVudHMgaW4gYW55IG9yZGVyIGFzIGxvbmcgYXMgeW91IHNwZWNpZnkgdGhlIG5hbWUgb2YgdGhlIGFyZ3VtZW50LgoKQXJndW1lbnQgbWF0Y2hpbmcgaXMgYSBiaXQgZGlmZmVyZW50IGluIFIgY29tcGFyZWQgdG8gb3RoZXIgbGFuZ3VhZ2VzLiBGaXJzdGx5LCBSIGRvZXMgYWxsIGFyZ3VtZW50IGNoZWNraW5nIGF0IHJ1bi10aW1lLiBTZWNvbmRseSwgd2hpbGUgYXJndW1lbnRzIGNhbiBiZSBtYXRjaGVkIHBvc2l0aW9uYWxseSBsaWtlIGluIG90aGVyIGxhbmd1YWdlcywgYXJndW1lbnRzIGNhbiBhbHNvIGJlIG1hdGNoZWQgYnkgcGFyYW1ldGVyIG5hbWUgLS0gYSBzeW50YXggbm90IHN1cHBvcnRlZCBieSBtb3N0IG90aGVyIGxhbmd1YWdlcy4KCkZvciBleGFtcGxlLCB0aGUgYnVpbHQtaW4gZnVuY3Rpb24gPGNvZGU+c2VxPC9jb2RlPiBnZW5lcmF0ZXMgYSBzZXF1ZW5jZSBvZiBudW1iZXJzIGFuZCByZXR1cm5zIHRob3NlIG51bWJlcnMgaW4gYSB2ZWN0b3IuIFRoZSBkZWZpbml0aW9uIG9mIHRoZSBmdW5jdGlvbiBpcyBhcyBmb2xsb3dzOiA8Y29kZT5zZXEodG8sIGZyb20sIGJ5LCBsZW5ndGgub3V0LCBhbG9uZy53aXRoKTwvY29kZT4uCgpIZXJlIGFyZSBleGFtcGxlcyBvZiB1c2luZyBpdC4gTm90ZSB0aGF0ICpieSosICpsZW5ndGgub3V0KiwgYW5kICphbG9uZy53aXRoKiBoYXZlIGRlZmF1bHQgdmFsdWVzIGFuZCBhcmUgdGhlcmVmb3JlIG9wdGlvbmFsLgoKYGBge3Igc2VxUGFybVBhc3Npbmd9CnYgPSBzZXEoMSwgMTAsIDIpICAgICMgaW50ZWdlcnMgZnJvbSAxIHRvIDEwIGluIGluY3JlbWVudHMgb2YgMgp3ID0gc2VxKDEsIDUpICAgICAgICAjIGludGVnZXJzIGZyb20gMSB0byA1IChieSBkZWZhdWx0IGluIGluY3JlbWVudHMgb2YgMSkKCiMgcGFzcyBhcmd1bWVudHMgaW4gYSBkaWZmZXJlbnQgb3JkZXIgYnV0IHNwZWNpZnkgYnkgbmFtZQp3ID0gc2VxKGZyb20gPSA1LCBieSA9IC0wLjUsIHRvID0gMSkKYGBgCgpSIGFsc28gc3VwcG9ydHMgdmFyaWFibGUgbnVtYmVycyBvZiBhcmd1bWVudHMgYnV0IHRoYXQgaXMgYmV5b25kIHRoZSBzY29wZSBvZiB0aGlzIHR1dG9yaWFsLgoKIyMjIERlZmF1bHQgQXJndW1lbnRzCgpSIGZ1bmN0aW9ucyBjYW4gaGF2ZSBkZWZhdWx0IHZhbHVlcyBmb3IgYXJndW1lbnRzIHdoaWNoIGFyZSB0aGVuIG9wdGlvbmFsIHdoZW4gdGhlIGZ1bmN0aW9uIGlzIGNhbGxlZC4gV2hlbiB0aGUgYXJndW1lbnQgaXMgbWlzc2luZywgdGhlbiB0aGUgZGVmYXVsdCB2YWx1ZSBpcyBwYXNzZWQuIEluIHRoZSBleGFtcGxlIGJlbG93LCB0aGUgKnN0YXJ0KiBhcmd1bWVudCBpcyB0aGUgcG9zaXRpb24gYXQgd2hpY2ggdGhlIHNlYXJjaCBmb3IgdGhlIHNtYWxsZXN0IGVsZW1lbnQgd2lsbCBzdGFydC4KCmBgYHtyIGZ1bmN0aW9uRGVmQXJnfQpmaW5kU21hbGxlc3QgPC0gZnVuY3Rpb24odiwgc3RhcnQgPSAxKQp7CiAgcyA9IEluZgogIGZvciAoaSBpbiBzdGFydDpsZW5ndGgodikpCiAgewogICAgaWYgKHZbaV0gPCBzKSB7CiAgICAgIHMgPSB2W2ldCiAgICB9CiAgfQogIHJldHVybiAocykKfQpgYGAKCmBgYHtyfQp4ID0gYygzLDEsOSw3LDMsNikKCncgPSBmaW5kU21hbGxlc3QoeCwgMykKcHJpbnQodykKCncgPSBmaW5kU21hbGxlc3QoeCkKcHJpbnQodykKYGBgCgojIyMgTG9jYWwgVmFyaWFibGVzCgpBcyBpbiBtb3N0IG90aGVyIHByb2dyYW1taW5nIGxhbmd1YWdlcywgUiBmdW5jdGlvbnMgY2FuIGRlZmluZSBsb2NhbCB2YXJpYWJsZXMgdGhhdCBhcmUgbm90IGtub3duIG91dHNpZGUgdGhlIHNjb3BlIG9mIHRoZSBmdW5jdGlvbi4gVGhlIHNjb3BlIGJvdW5kYXJpZXMgaW4gUiBhcmUgbGlrZSBvdGhlciBsYW5ndWFnZXM6IGEgYmxvY2sgZW5jbG9zZWQgaW4gY3VybHkgYnJhY2VzLgoKSW4gdGhlIGV4YW1wbGUgYmVsb3csICpsb2NhbC52YXIqIGlzIGxvY2FsIHRvIHRoZSBmdW5jdGlvbiBhbmQgdGh1cyBpcyBub3QgdmlzaWJsZSBvdXRzaWRlIG9mIHRoZSBmdW5jdGlvbi4gVGhlIGNvZGUgYmVsb3cgcHJvZHVjZXMgdGhlIGVycm9yOiAiRXJyb3IgaW4gcHJpbnQobG9jYWwudmFyKSA6IG9iamVjdCAnbG9jYWwudmFyJyBub3QgZm91bmQiLgoKYGBge3IgbG9jYVZhcnMsIGVjaG89VFJVRSwgZXZhbD1GQUxTRX0KZmluZFNtYWxsZXN0IDwtIGZ1bmN0aW9uKHYsIHN0YXJ0ID0gMSkKewogIGxvY2FsLnZhciA9IEluZgogIGZvciAoaSBpbiBzdGFydDpsZW5ndGgodikpCiAgewogICAgaWYgKHZbaV0gPCBsb2NhbC52YXIpIHsKICAgICAgbG9jYWwudmFyID0gdltpXQogICAgfQogIH0KICByZXR1cm4gKGxvY2FsLnZhcikKfQoKeCA9IGMoMywxLDksNywzLDYpCgp3ID0gZmluZFNtYWxsZXN0KHgsIDMpCgojIHdlIGNhbm5vdCBlY2hvIG9yIGFjY2VzcyB0aGUgbG9jYWwgdmFyaWFibGUgInMiCnByaW50KGxvY2FsLnZhcikKYGBgCgojIyMgUmVjdXJzaW9uCgpSIGZ1bmN0aW9ucyBjYW4gYmUgY2FsbGVkIHJlY3Vyc2l2ZWx5LiBUaGUgZXhhbXBsZSBiZWxvdyBjYWxjdWxhdGVzIGZhY3RvcmlhbCB1c2luZyByZWN1cnNpb24gcmF0aGVyIHRoYW4gYSBsb29wLgoKYGBge3IgcmVjdXJzaXZlRnVuY3N9CmZhYyA8LSBmdW5jdGlvbih4KQp7CiAgaWYgKHggPT0gMSkgCiAgICByZXR1cm4gKDEpCiAgZWxzZSAKICAgIHJldHVybiAoeCAqIGZhYyh4LTEpKQp9CgpwcmludChmYWMoOCkpCmBgYAoKPiBJZiBpdCBoYXNuJ3QgYmVlbiBvYnZpb3VzIHlldCwganVzdCBsaWtlIGluIG90aGVyIGxhbmd1YWdlcywgdGhlIHBsYWNlbWVudCBvZiBjdXJseSBicmFjZXMgbWFrZXMgbm8gZGlmZmVyZW5jZS4gRm9yIHNpbmdsZSBzdGF0ZW1lbnQgYmxvY2tzLCB0aGUgY3VybHkgYnJhY2VzIGNhbiBiZSBvbWl0dGVkLgoKPiBUaGUgcGFyZW50aGVzaXMgYXJvdW5kIHRoZSB2YWx1ZSBmb3IgKnJldHVybiogYXJlIHJlcXVpcmVkLgoKQXMgYW4gZXhlcmNpc2UsIHRyeSB3cml0aW5nIHRoZSBhYm92ZSBmdW5jdGlvbiB0byBjYWxjdWxhdGUgZmFjdG9yaWFsIHVzaW5nIGEgbG9vcC4KCiMjIFR5cGUgQ29lcmNpb24KClR5cGUgY29lcmNpb24gKG9yIGNhc3RpbmcgaW4gQy9DKysgdGVybWlub2xvZ3kpIGlzIGRvbmUgd2l0aCB0eXBlIGNvbnZlcnNpb24gZnVuY3Rpb25zIGluIFIgYW5kIG5vdCB0aHJvdWdoIG9wZXJhdG9ycyBsaWtlIGluIEMsIEMrKywgYW5kIEphdmEuIFRoZSBleGFtcGxlIGJlbG93IHNob3dzIHRoZSBtb3N0IGNvbW1vbiB0eXBlIGNvbnZlcnNpb24gZnVuY3Rpb25zLiBOb3RlIHRoYXQgaW4gc29tZSBzaXR1YXRpb24geW91IHdpbGwgbG9zZSBpbmZvcm1hdGlvbiwganVzdCBsaWtlIGluIG90aGVyIGxhbmd1YWdlcy4KCmBgYHtyIHR5cGVDb252ZXJzaW9ufQpzID0gIjEyLjQiICAgICAgICAgICAgICAgICAjIHN0cmluZyAoY2hhcmFjdGVyKQppID0gYXMuaW50ZWdlcihzKSAgICAgICAgICAjIGNvbnZlcnQgdG8gaW50ZWdlcjogMTIKZCA9IGFzLm51bWVyaWMocykgICAgICAgICAgIyBjb252ZXJ0IHRvIGRvdWJsZTogMTIuMwoKdyA9ICIkMTIuMyIgICAgICAgICAgICAgICAgIyBhZGRpdGlvbmFsIGNoYXJhY3RlcnMKayA9IGFzLmludGVnZXIodykgICAgICAgICAgIyBjYW5ub3QgYmUgY29udmVydGVkIGR1ZSB0byAkCmBgYAoKSWYgYSBjb2VyY2lvbiBpcyBub3Qgc3VjY2Vzc2Z1bCB0aGUgcmVzdWx0IGluICpOQSogd2hpY2ggaW5kaWNhdGVzIGEgKm51bGwqIG9yIG1pc3NpbmcgdmFsdWUuCgojIyBWZWN0b3JzCgpMZXQncyB0YWxrIG1vcmUgYWJvdXQgdmVjdG9ycy4gSW4gUiwgYSB2ZWN0b3IgaXMgc2ltaWxhciB0byBhIGxpc3Qgb3IgYXJyYXkgaW4gb3RoZXIgcHJvZ3JhbW1pbmcgbGFuZ3VhZ2VzLiBJdCBpcyBhIGNvbGxlY3Rpb24gb2YgZWxlbWVudHMgb2YgdGhlIHNhbWUgYmFzaWMgdHlwZTogbnVtZXJpYywgY2hhcmFjdGVyLCBvciBCb29sZWFuLiBBIGxpc3QgaW4gUiBpcyBhIGNvbGxlY3Rpb24gb2YgbWl4ZWQgZGF0YSB0eXBlcy4gVGhpcyB0dXRvcmlhbCBhcHBsaWVzIHRvIHZlY3RvcnMgb25seS4KClRoZXJlIGFyZSBubyBzcGVjaWZpYyBwYWNrYWdlcyByZXF1aXJlZCBmb3IgdGhlc2UgZnVuY3Rpb25zLgoKIyMgQ3JlYXRpbmcgYSBWZWN0b3IKClRoZSBjb2RlIGJlbG93IGNyZWF0ZXMgYW4gYXJ0aWZpY2lhbCB2ZWN0b3Igb2YgcmFuZG9tIGludGVnZXJzIGZvciB1c2UgaW4gdGhlIHR1dG9yaWFsLiBJbiBwcmFjdGljZSwgdmVjdG9ycyBhcmUgZ2VuZXJhbGx5IGNvbHVtbnMgaW4gZGF0YSBmcmFtZXMgd2hpY2ggYXJlIGZyZXF1ZW50bHkgdGhlIHJlc3VsdCBvZiByZWFkaW5nIGRhdGEgZnJvbSBhIENTViBmaWxlIG9yIGEgZGF0YWJhc2UuCgpgYGB7ciBjcmVhdGVTYW1wbGVWZWN0b3J9CiMgdmVjdG9yIG9mIDUwIHJhbmRvbSBpbnRlZ2VycyBiZXR3ZWVuIDAgYW5kIDEwCgojIHNldCB0aGUgc2VlZCBmb3IgdGhlIHJhbmRvbSBudW1iZXIgZ2VuZXJhdG9yIHRvIGVuc3VyZSBzYW1lCiMgc2VxdWVuY2Ugb2YgcmFuZG9tIG51bWJlcnMgZXZlcnkgdGltZSB0aGUgY29kZSBpcyBydW4Kc2V0LnNlZWQoOTg3ODgpCnYgPC0gcm91bmQocnVuaWYoNTAsIG1pbiA9IDAsIG1heCA9IDEwKSwwKQoKIyBhcmd1bWVudHMgZG8gbm90IGhhdmUgdG8gYmUgcGFzc2VkIGluIHRoZSBvcmRlciB0aGF0IHRoZXkgYXJlCiMgZGVjbGFyZWQgaW4gdGhlIGZ1bmN0aW9uIGRlZmluaXRpb24gYXMgbG9uZyBhcyB0aGUgbmFtZXMgb2YgdGhlCiMgYXJndW1lbnRzIGFyZSBzcGVjaWZpZWQKdiA8LSByb3VuZChydW5pZihuID0gNTAsIG1heCA9IDEwLCBtaW4gPSAxKSwwKQp2IDwtIHJvdW5kKHJ1bmlmKG1heCA9IDEwLCBtaW4gPSAxLCBuID0gNTApLDApCgpwcmludCh2KQpgYGAKCiMjIEFjY2Vzc2luZyBFbGVtZW50cyBpbiBhIFZlY3RvcgoKRWxlbWVudHMgYXJlIGFjY2Vzc2VkIHBvc2l0aW9uYWxseSwgYWx0aG91Z2ggaW4gUiwgdGhlIGFjY2VzcyBpbmRleCBjYW4gYmUgYSB2ZWN0b3Igb2YgaW50ZWdlcnMgaW4gd2hpY2ggY2FzZSBhbGwgZWxlbWVudHMgYXQgdGhvc2UgcG9zaXRpb25zIGFyZSByZXRyaWV2ZWQuIFBvc2l0aW9ucyBhcmUgbnVtYmVyZWQgZnJvbSAxIHRvIHRoZSBudW1iZXIgb2YgZWxlbWVudHMgaW4gYSB2ZWN0b3IuIFRoZSBudW1iZXIgb2YgZWxlbWVudHMgKG9yIGxlbmd0aCkgb2YgYSB2ZWN0b3IgY2FuIGJlIG9idGFpbmVkIHVzaW5nIHRoZSA8Y29kZT5sZW5ndGgoKTwvY29kZT4gZnVuY3Rpb24uCgpJbiB0aGUgZXhhbXBsZSBiZWxvdywgbm90ZSB0aGF0IDxjb2RlPm46bTwvY29kZT4gZ2VuZXJhdGVzIGEgdmVjdG9yIG9mIGludGVnZXJzIGZyb20gKm4qIHRvICptKiwgaW5jbHVzaXZlLiBUaGUgPGNvZGU+c2VxKCk8L2NvZGU+IGdlbmVyYXRlcyBhIHNlcXVlbmNlIG9mIGludGVnZXJzIGF0IGFuIGludGVydmFsLgoKYGBge3Igc2ltcGxlVmVjdG9yQWNjZXNzLCBldmFsPUZ9CiMgYWNjZXNzIGEgc2luZ2xlIGVsZW1lbnQgYXQgcG9zaXRpb24gMwp2WzNdCgojIGFjY2VzcyBlbGVtZW50IDEwIHRocm91Z2ggMTUKdlsxMDoxNV0KCiMgYWNjZXNzIHRoZSBsYXN0IGVsZW1lbnQKdltsZW5ndGgodildCgojIGFjY2VzcyBldmVyeSBvdGhlciBlbGVtZW50CnZbc2VxKGZyb20gPSAxLCB0byA9IGxlbmd0aCh2KSwgYnkgPSAyKV0KCiMgYWNjZXNzIHNwZWNpZmljIGVsZW1lbnRzIGF0IHBvc2l0aW9ucyAyLCAxMSwgMTksIGFuZCAyOAppIDwtIGMoMiwxMSwxOSwyOCkKdltpXQpgYGAKCiMjIFRlc3RpbmcgUHJlZGljYXRlIEV4cHJlc3Npb25zCgpJdCBpcyBwb3NzaWJsZSBpbiBSIHRvIGFwcGx5IGEgcHJlZGljYXRlIGV4cHJlc3Npb24gdG8gZXZlcnkgZWxlbWVudCBpbiBhIHZlY3Rvci4gVGhpcyBnZW5lcmF0ZXMgYSAiQm9vbGVhbiB2ZWN0b3IiIG9mICpUUlVFL0ZBTFNFKiB2YWx1ZXMgdGhhdCBpbmRpY2F0ZSB3aGljaCBlbGVtZW50IG1hdGNoZXMgdGhlIHByZWRpY2F0ZSBleHByZXNzaW9uICgqVFJVRSopIGFuZCB3aGljaCBkb2Vzbid0ICgqRkFMU0UqKS4KClByZWRpY2F0ZSBleHByZXNzaW9ucyBhcmUgYnVpbHQgd2l0aCBsb2dpY2FsIG9wZXJhdG9ycyAoXDwsIFw+LCBcPD0sIFw+PSwgPT0sICE9KQoKYGBge3J9CnYgPCA1CgoodiA8IDEgfCB2ID4gOSkKCih2IDw9IDcgJiB2ICE9IDMpCgp2ICE9IDUKCmwgPC0gKHYgPT0gNSkKcHJpbnQobCkKYGBgCgojIyBGaW5kaW5nIE1hdGNoZXMKClRoZSA8Y29kZT53aGljaCgpPC9jb2RlPiBmdW5jdGlvbiByZXR1cm5zIHRoZSBwb3NpdGlvbnMgdGhhdCBhcmUgKlRSVUUqIGluIGEgQm9vbGVhbiB2ZWN0b3IuCgpgYGB7cn0KIyByZXR1cm5zIHBvc2l0aW9ucyBvZiB2ZWN0b3IgdGhhdCBtYXRjaGVzIHByZWRpY2F0ZSBleHByZXNzaW9uCndoaWNoKHYgIT0gNSkKCiMgY291bnQgdGhlIG51bWJlciBvZiBtYXRjaGVzCmxlbmd0aCh3aGljaCh2ICE9IDApKQpgYGAKCmBgYHtyfQpwIDwtIHdoaWNoKHYgPCA1KQpwcmludCAodltwXSkKCiMgb3IgY29tYmluZQp4IDwtIHZbd2hpY2godiA8IDUpXQpwcmludCAoeCkKCiMgZmluZCBhbGwgdGhhdCBhcmUgbm90IGluIHZlY3Rvcgpub3QueCA8LSB2Wy13aGljaCh2IDwgNSldCnByaW50ICh4KQpgYGAKCiMjIERldGVybWluaW5nIEFueSBNYXRjaGVzCgpUbyBkZXRlcm1pbmUgaWYgdGhlcmUgYXJlIGFueSBtYXRjaGVzLCAqaS5lLiosIGF0IGxlYXN0IG9uZSBlbGVtZW50IGluIGEgdmVjdG9yIG1hdGNoZXMgdGhlIHByZWRpY2F0ZSBleHByZXNzaW9uLCB1c2UgdGhlIDxjb2RlPmFueSgpPC9jb2RlPiBmdW5jdGlvbi4gVGhlIGZ1bmN0aW9uIDxjb2RlPmFueSgpPC9jb2RlPiByZXR1cm5zICpUUlVFKiBpZiB0aGVyZSdzIGF0IGxlYXN0IG9uZSBtYXRjaCwgKkZBTFNFKiBvdGhlcndpc2UuCgpgYGB7cn0KYW55KHYgPCA1KQpgYGAKCiMjIERlYWxpbmcgd2l0aCBNaXNzaW5nIFZhbHVlcwoKTWlzc2luZyB2YWx1ZXMgaW4gUiBhcmUgZ2VuZXJhbGx5IGVuY29kZWQgd2l0aCB0aGUgc3BlY2lhbCB2YWx1ZSAqKk5BKiouICoqTkEqKiBpcyBub3QgYSBudW1iZXIsIG5vdCBhIGNoYXJhY3RlciBvciB0ZXh0LCBhbmQgbm90IGEgQm9vbGVhbi4gQ29uc2VxdWVudGx5LCB1c2luZyAqPT0qIG9yICohPSogdG8gY2hlY2sgaWYgYSB2YWx1ZSBpcyAqKk5BKiogZG9lcyBub3Qgd29yayBhbmQgcmVzdWx0cyBpbiBhbiBlcnJvci4gWW91IG11c3QgdXNlIHRoZSBmdW5jdGlvbiA8Y29kZT5pcy5uYSgpPC9jb2RlPiB0byBjaGVjayBpZiBhIHZhbHVlIGlzICoqTkEqKi4gVGhpcyBpcyBzaW1pbGFyIHRvICoqTlVMTCoqIGluIFNRTCBhbmQgbWFueSBwcm9ncmFtbWluZyBsYW5ndWFnZXMuCgpgYGB7cn0KIyBjb3B5IHRoZSB2ZWN0b3Igb2YgcmFuZG9tIG51bWJlcnMgYW5kIHRoZW4gcmFuZG9tbHkgCiMgcmVtb3ZlIDYgdmFsdWVzLCBpLmUuLCBzZXQgdGhlbSB0byBOQQoKdi5uYSA8LSB2Cgp2Lm5hW3JvdW5kKHJ1bmlmKDYsIG1pbiA9IDEsIG1heCA9IGxlbmd0aCh2Lm5hKSksIDApXSA9IE5BCgpwcmludCh2Lm5hKQpgYGAKCk1hbnkgb2YgdGhlIGZ1bmN0aW9ucyBpbiBSIGRvIG5vdCB3b3JrIHdoZW4gYSB2YWx1ZSBpbiBhIHZlY3RvciBpcyAqKk5BKiouIERvaW5nIHNvIHJlc3VsdHMgaW4gYSB2YWx1ZSBvZiAqKk5BKiouCgpgYGB7cn0KIyBjYW5ub3QgYWRkIHZhbHVlcyBjb250YWluaW5nIE5BCnN1bSh2Lm5hKQoKIyB3aGVuIGFwcGx5aW5nIG9wZXJhdG9ycywgTkEgcmVtYWlucyBOQQp2Lm5hICsgNQpgYGAKClNvbWUgZnVuY3Rpb25zIGhhdmUgYSBwYXJhbWV0ZXIgdGhhdCBhbGxvd3MgeW91IHRvIGRpcmVjdCBhIGZ1bmN0aW9uIHRvIGlnbm9yZSAqKk5BKiogdmFsdWVzLiBDaGVjayB0aGUgZG9jdW1lbnRhdGlvbiBvZiBmdW5jdGlvbnMgYmVmb3JlIHVzaW5nIHRoZW0gdG8gc2VlIHdoYXQgcGFyYW1ldGVycyB0aGV5IHN1cHBvcnQuIFVzZSAqP3N1bSogdG8gdmlldyB0aGUgZG9jdW1lbnRhdGlvbiBvZiB0aGUgKnN1bSogZnVuY3Rpb24uCgojIyBBY2Nlc3NpbmcgUm93cywgQ29sdW1ucywgYW5kIEVsZW1lbnRzIChDZWxscykgb2YgYSBEYXRhIEZyYW1lCgpEYXRhIGZyYW1lcyBhcmUgdmVyeSBzaW1pbGFyIHRvIHRhYmxlcyBpbiByZWxhdGlvbmFsIGRhdGFiYXNlcyBhbmQgc3ByZWFkc2hlZXRzLiBUaGV5IGhhdmUgcm93cyBhbmQgY29sdW1ucyBhbmQgdGhlIGludGVyc2VjdGlvbiBvZiBhIHJvdyBhbmQgY29sdW1uIGlzIGEgY2VsbCAob3IgZWxlbWVudCkuIFRoZSBvcmRlciBvZiBhY2Nlc3MgaXMgcm93IGZvbGxvd2VkIGJ5IGNvbHVtbiwgKmUuZy4qLCB0aGUgdGhpcmQgZWxlbWVudCBpbiB0aGUgZm91cnRoIHJvdyBvZiB0aGUgZGF0YSBmcmFtZSA8Y29kZT5tdGNhcnM8L2NvZGU+IGlzIDxjb2RlPm10Y2Fyc1s0LDNdPC9jb2RlPi4gTm90ZSB0aGF0IHRoaXMgaXMgcmV2ZXJzZWQgZnJvbSB0aGUgd2F5IEV4Y2VsIGFuZCBvdGhlciBzcHJlYWRzaGVldHMgd29yay4KClRoZSBleGFtcGxlIGNvZGUgYmVsb3cgdXNlcyB0aGUgYnVpbHQtaW4gZGF0YSBmcmFtZSAqbXRjYXJzKi4gWW91IGNhbiBmaW5kIG91dCBtb3JlIGFib3V0IGl0cyBzdHJ1Y3R1cmUgdXNpbmcgPGNvZGU+c3RyKG10Y2Fycyk8L2NvZGU+IG9yIGRpc3BsYXlpbmcgdGhlIGZpcnN0IGZldyByb3dzIHdpdGggPGNvZGU+aGVhZChtdGNhcnMpPC9jb2RlPi4KCmBgYHtyfQpzdHIobXRjYXJzKQpoZWFkKG10Y2FycywgMykKYGBgCgpgYGB7cn0KdiA8LSBtdGNhcnNbNCwzXQp4ID0gbXRjYXJzWzQsM10KCnByaW50KHBhc3RlMCgidiA9ICIsdiwiIGFuZCB4ID0gIix4KSkKYGBgCgpMZWF2aW5nIG91dCBhIGRpbWVuc2lvbiAocm93IG9yIGNvbHVtbikgYWNjZXNzZXMgdGhlIGVudGlyZSByb3cgb3IgY29sdW1uLiBUaGUgcmVzdWx0YW50IGlzIGEgZGF0YSBmcmFtZSB3aXRoIGEgc2luZ2xlIHJvdy4KCk9mdGVuIHRoZSB2YWx1ZXMgbXVzdCBiZSBjb252ZXJ0ZWQgdG8gYSB2ZWN0b3IgZGF0YSB0eXBlLiBDb252ZXJzaW9ucyBvZiB2YXJpYWJsZXMgZnJvbSBvbmUgdHlwZSB0byBhbm90aGVyIGlzIGRvbmUgd2l0aCB0aGUgZmFtaWx5IG9mIDxjb2RlPmFzLnh4eHg8L2NvZGU+IGZ1bmN0aW9ucywgKmUuZy4qLCA8Y29kZT5hcy52ZWN0b3I8L2NvZGU+LCA8Y29kZT5hcy5udW1lcmljPC9jb2RlPiwgb3IgPGNvZGU+YXMuZmFjdG9yPC9jb2RlPi4gVmVjdG9ycyBjYW4gY29udGFpbiBudW1lcmljIG9yIGNoYXJhY3RlciBkYXRhIGJ1dCBhbGwgZWxlbWVudHMgbXVzdCBiZSBvZiB0aGUgc2FtZSB0eXBlLiBJbiBSLCBhIGxpc3QgaXMgc2ltaWxhciB0byBhIHZlY3RvciBidXQgaXQgbWF5IGNvbnRhaW4gYSBtaXggb2YgZWxlbWVudHMuIEEgbWF0cml4IGlzIHNpbWlsYXIgdG8gYSBkYXRhIGZyYW1lIGJ1dCBpdCBjYW4gb25seSBjb250YWluIG51bWJlcnMgYW5kIGl0IGNhbiBoYXZlIG1vcmUgdGhhbiB0d28gZGltZW5zaW9ucy4KClNvbWUgZnVuY3Rpb25zIGV4cGVjdCBkYXRhIGZyYW1lcywgc29tZSB2ZWN0b3JzLCBzb21lIGxpc3RzLiBZb3UgbmVlZCB0byByZWFkIHRoZSBkb2N1bWVudGF0aW9uIG9mIGEgZnVuY3Rpb24gdG8gZmluZCBvdXQuIEZ1cnRoZXJtb3JlLCBzb21lIGZ1bmN0aW9ucyB3aWxsIGF1dG9tYXRpY2FsbHkgY29udmVydCBhIHZhcmlhYmxlIGZyb20gb25lIHR5cGUgdG8gdGhlIG9uZSBpdCByZXF1aXJlcy4KCllvdSBjYW4gYWxzbyBhY2Nlc3MgYSBjb2x1bW4gaW4gZGF0YSBmcmFtZSBieSBpdHMgY29sdW1uIG5hbWUuIEZvciBhbiBlbnRpcmUgY29sdW1uIHlvdSBlaXRoZXIgdXNlIHRoZSBjb2x1bW5zIHBvc2l0aW9uIG9yIGl0cyBuYW1lOiA8Y29kZT5kZlssY29sdW1uXTwvY29kZT4gb3IgPGNvZGU+ZGZcJGNvbHVtbk5hbWU8L2NvZGU+LgoKYGBge3J9CiMgYWxsIG9mIHJvdyA0OyB0aGUgcmVzdWx0IGlzIGEgZGF0YSBmcmFtZQpyIDwtIG10Y2Fyc1s0LF0Kc3VtKHIpCgpjIDwtIG10Y2Fyc1szLF0KY1sxLDNdCgptdGNhcnNbYygxLDQpXSAgICMgY29sdW1ucyAxIGFuZCA0IGFzIGEgbmV3IGRhdGFmcmFtZQoKbXRjYXJzWywyXSAgICAgICAjIGFsbCBvZiBjb2x1bW4gMgptdGNhcnNbNTo3LF0gICAgICMgcm93cyA1IHRvIDcgYXMgYSBuZXcgZGF0YWZyYW1lCm10Y2FycyRjeWwgICAgICAgIyBjb2x1bW4gbmFtZWQgImN5bCIKbXRjYXJzJGN5bFsyXSAgICAjIDJuZCByb3cgaW4gdGhlIGNvbHVtbiAiY3lsIgoKbXRjYXJzJGN5bFszOjldICAjIHJvd3MgMyB0byA5IGZvciBjb2x1bW4gImN5bCIgYXMgYSB2ZWN0b3IKCncgPC0gbXRjYXJzJG1wZwptZWFuKHcpCmBgYAoKIyMgQWRkaW5nIGFuZCBSZW1vdmluZyBDb2x1bW5zIGZyb20gYSBEYXRhIEZyYW1lCgpUbyBhZGQgYSBuZXcgY29sdW1uLCB5b3Ugc2ltcGx5ICJhY2Nlc3MiIHRoZSBjb2x1bW4gb3IgdXNlIGEgbmV3IG5hbWUgZm9yIHRoZSBjb2x1bW4uIE5vdGUgaW4gdGhlIGV4YW1wbGUgYmVsb3cgdGhhdCB5b3UgY2FuIG9wZXJhdGUgb24gZW50aXJlIGNvbHVtbnMgKGFzIHZlY3RvcnMpIGFuZCB0aGUgb3BlcmF0aW9uIGlzIGFwcGxpZWQgdG8gZWFjaCBwYWlyIG9mIHZhbHVlcyBpbiB0aGUgdHdvIHZlY3RvcnMgaW4gdGhlIG9wZXJhdGlvbi4gVGhpcyBpcyBtdWNoIG1vcmUgZWZmaWNpZW50IHRoYW4gdXNpbmcgbG9vcHMgYXMgaXMgbmVjZXNzYXJ5IGluIG90aGVyIHByb2dyYW1taW5nIGxhbmd1YWdlcy4KCmBgYHtyfQojIGNvcHkgdGhlIGRhdGEgZnJhbWUgbXRjYXJzIHRvIGEgbmV3IGRhdGEgZnJhbWUgZGYKZGYgPC0gbXRjYXJzCgojIGNyZWF0ZSBhIG5ldyBjb2x1bW4gImRpc3BjeWwiIHdoaWNoIGlzIHRoZSBkaXNwbGFjZW1lbnQgcGVyIGN5bGluZGVyCmRmJGRpc3BjeWwgPC0gZGYkZGlzcCAvIGRmJGN5bAoKaGVhZChkZikKYGBgCgojIyBDcmVhdGUgYSBOZXcgRGF0YSBGcmFtZQoKRGF0YSBmcmFtZXMgYXJlIGNyZWF0ZWQgaW4gdmFyaW91cyB3YXlzOiB1c2UgdGhlIFw8Y29kZVw8XD5kYXRhLmZyYW1lPC9jb2RlPiBmdW5jdGlvbiwgbG9hZCBhIENTViBmaWxlLCBleGVjdXRlIGEgU1FMIHF1ZXJ5LCBvciBhcyBhIHJlc3VsdCBvZiBtYW55IHBhY2thZ2UgZnVuY3Rpb25zLgoKIyMjIExvYWQgYSBEYXRhIEZyYW1lIGZyb20gQ1NWCgpRdWljayBub3RlOiBDYXBpdGFsaXphdGlvbiBpbiBwYXRoIGFuZCBmaWxlIG5hbWVzIGRvZXMgbm90IG1hdHRlciBpbiBXaW5kb3dzLCBidXQgKipkb2VzIG1hdHRlcioqIG9uIE1hY09TIGFuZCBMaW51eC4gRnVydGhlcm1vcmUsIG5vdGUgdGhhdCBldmVuIGluIFdpbmRvd3MgdGhlIHBhdGggZGVsaW1pdGVyIGlzIGEgZm9yd2FyZCBzbGFzaCAvIGFuZCBub3QgdGhlIHVzdWFsIGJhY2t3YXJkcyBzbGFzaCBcXC4gVGhlIFxcIGlzIGFuICJlc2NhcGUiIGNoYXJhY3RlciBhbmQgdXNlZCB0byBpbmplY3Qgbm9uLXByaW50YWJsZSBjaGFyYWN0ZXJzIGludG8gYSBzdHJpbmcgKHRleHQpLCAqZS5nLiosICJUaGlzIHN0cmluZyBjb250YWlucyJxdW90ZXMiLiIgd2hpY2ggd291bGQgYmUgd3JpdHRlbiBpbiBSIGFzICJ0aGlzIHN0cmluZyBjb250YWlucyBcXCJxdW90ZXNcXCIuIgoKVGhlIHBhcmFtZXRlciA8Y29kZT5oZWFkZXIgPSBGPC9jb2RlPiBpbnN0cnVjdHMgPGNvZGU+cmVhZC5jc3Y8L2NvZGU+IG5vdCB0byBpbnRlcnByZXQgdGhlIGZpcnN0IGxpbmUgYXMgaGVhZGVyIGxhYmVscy4gT2YgY291cnNlLCBpZiB0aGVyZSBhcmUgbm8gbGFiZWxzLCB0aGVuIHlvdSBuZWVkIHRvIGRlZmluZSB5b3VyIG93bi4KCkFzaWRlIGZyb20gQ1NWIGZpbGVzLCBSIGNhbiBhbHNvIGxvYWQgYSBudW1iZXIgb2Ygb3RoZXIgZmlsZSBmb3JtYXQgdXNpbmcgdmFyaW91cyBwYWNrYWdlcywgaW5jbHVkaW5nIFhNTCwgRXhjZWwsIFNQU1MsIE1hdExhYiwgYW1vbmcgbWFueSBvdGhlcnMuCgpgYGB7cn0KZGYgPC0gcmVhZC5jc3YoZmlsZSA9ICJjdXN0b21lcnR4bmRhdGEuY3N2IiwgaGVhZGVyID0gRikKaGVhZChkZikKCmRmIDwtIHJlYWQuY3N2KGZpbGUgPSAiY3VzdG9tZXJ0eG5kYXRhLmNzdiIsIAogICAgICAgICAgICAgICBoZWFkZXIgPSBGLAogICAgICAgICAgICAgICBjb2wubmFtZXMgPSBjKCJudW1WaXNpdHMiLCJOdW1UeG4iLCJPUyIsIkdlbmRlciIsIlRvdFNwIikpCmhlYWQoZGYpCmBgYAoKPiBOb3RlIHRoYXQgdGhlIHZhbHVlIG9mIHRoZSAnTWFsZScgY29sdW1uIGluIHRoZSBmaXJzdCByb3cgaXMgKk5BKiB3aGljaCBpcyB0aGUgd2F5IHRoYXQgUiBpbmRpY2F0ZXMgYSBtaXNzaW5nIGRhdGEgdmFsdWUuIEl0IGlzIG5vdCAwIG9yIGFuIGVtcHR5IHN0cmluZywgaXQgaXMgdW5rbm93bi4gU28sIHN0YXRpc3RpY2FsIGZ1bmN0aW9ucyBhbmQgYWxnZWJyYWljIG9wZXJhdGlvbnMgd291bGQgcmVzdWx0IGluIGFuICpOQSogYXMgd2VsbC4KCiMjIyMgU3RyaW5ncyB2cyBGYWN0b3JzCgpUaGUgKmZhY3RvciogZGF0YSB0eXBlIGVuY29kZXMgY2F0ZWdvcmljYWwgZGF0YSwgKmUuZy4qLCB0aGUgdmFsdWUgb2YgYSB2YXJpYWJsZSBpcyBvbmUgb2YgYSBmaXhlZCB2YWx1ZSBzZXQuIE1hbnkgc3RhdGlzdGljYWwgZnVuY3Rpb25zIGluIFIgcmVxdWlyZSBjYXRlZ29yaWNhbCB2YXJpYWJsZXMgdG8gYmUgb2YgdHlwZSAqZmFjdG9yKi4gSG93ZXZlciwgb2Z0ZW4sIGR1cmluZyBkYXRhIHByb2Nlc3NpbmcsIHdlIG5lZWQgdGhlIGFjdHVhbCB0ZXh0IHJhdGhlciB0aGFuIGhhdmluZyBpdCBlbmNvZGVkIGFzIGEgKmZhY3RvciogKHdoaWNoIGlzIGFjdHVhbGx5IHN0b3JlZCBpbiBSIGFzIGFuIGludGVnZXIgZm9yIGVmZmljaWVuY3kpLiBTbywgd2hlbiByZWFkaW5nIGEgQ1NWIGZpbGUgeW91IG5lZWQgdG8gZGVjaWRlIGlmIHlvdSB3YW50IHRleHQgY29sdW1ucyB0byBiZSBjaGFyYWN0ZXIgc3RyaW5ncyBvciBmYWN0b3JzIGJ5IHNldHRpbmcgdGhlIDxjb2RlPnN0cmluZ3NBc0ZhY3RvcnM8L2NvZGU+IHBhcmFtZXRlci4KCllvdSBtYXkgdXNlIGVpdGhlciA8Y29kZT5GPC9jb2RlPiBhbmQgPGNvZGU+VDwvY29kZT4gb3IgPGNvZGU+RkFMU0U8L2NvZGU+IGFuZCA8Y29kZT5UUlVFPC9jb2RlPi4KCmBgYHtyfQpkZiA8LSByZWFkLmNzdihmaWxlID0gImN1c3RvbWVydHhuZGF0YS5jc3YiLCAKICAgICAgICAgICAgICAgaGVhZGVyID0gRiwKICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFLAogICAgICAgICAgICAgICBjb2wubmFtZXMgPSBjKCJudW1WaXNpdHMiLCJOdW1UeG4iLCJPUyIsIkdlbmRlciIsIlRvdFNwIikpCmhlYWQoZGYpCmBgYAoKIyMjIENyZWF0ZSBhIG5ldyBEYXRhIEZyYW1lCgpUaGUgY29kZSBiZWxvdyBjcmVhdGVzIGEgbmV3IGRhdGEgZnJhbWUgZnJvbSBjb2x1bW4gdmVjdG9ycy4gTm90aWNlIGhvdyB0aGUgY29sdW1uIG5hbWVzIGFyZSB0aGUgbmFtZXMgb2YgdGhlIHZlY3RvcnMuIEEgbmV3IHZlY3RvciBpcyBjcmVhdGVkIHdpdGggdGhlIDxjb2RlPmM8L2NvZGU+IGZ1bmN0aW9uLCBlLmcuLCA8Y29kZT52IFw8LSBjKDMsNSwxLDkpPC9jb2RlPi4KCmBgYHtyfQpkZjEgPC0gZGF0YS5mcmFtZShzdGF0ZSA9IGMoJ0FyaXpvbmEnLCdHZW9yZ2lhJywgJ05ldyBZb3JrJywnSW5kaWFuYScsJ1dhc2hpbmd0b24nLCdUZXhhcycpLAogICAgICAgICAgICAgICAgICBjb2RlID0gYXMuZmFjdG9yKGMoJ0FaJywnR0EnLCdOWScsJ0lOJywnV0EnLCdUWCcpKSwKICAgICAgICAgICAgICAgICAgc2NvcmUgPSBjKDYyLDQ3LDU1LDc0LDMxLDg1KSkKCmhlYWQoZGYxKQoKYGBgCgojIyBTZWFyY2ggRGF0YSBGcmFtZXMKClRoZXJlIGFyZSB0d28gaW1wb3J0YW50IGZ1bmN0aW9ucyBmb3IgInNlYXJjaGluZyIgZGF0YSBmcmFtZXM6IDxjb2RlPndoaWNoPC9jb2RlPiBhbmQgPGNvZGU+YW55PC9jb2RlPi4gVGhlIGNvZGUgYmVsb3cgdXNlcyB0aGUgYnVpbHQtaW4gWyoqT3JhbmdlKiogZGF0YSBmcmFtZV0oaHR0cHM6Ly93d3cucmRvY3VtZW50YXRpb24ub3JnL3BhY2thZ2VzL2RhdGFzZXRzL3ZlcnNpb25zLzMuNi4yL3RvcGljcy9PcmFuZ2UpIHdoaWNoIGNvbnRhaW5zIG1lYXN1cmVtZW50cyBvZiBvcmFuZ2UgdHJlZXMuIEl0IGhhcyB0aHJlZSBjb2x1bW5zOiB0aGUgdHJlZSwgdGhlICphZ2UqIG9mIHRoZSB0cmVlIChkYXlzIHNpbmNlIDE5NjgvMTIvMzEpLCBhbmQgKmNpcmN1bWZlcmVuY2UqIChpbiAqbW0qKS4KCiMjIyB3aGljaAoKYGBge3J9CmRmIDwtIE9yYW5nZQoKaGVhZChkZikKCiMgZmluZCBhbGwgcm93cyB3aGVyZSB0aGUgY2lyY3VtZmVyZW5jZSBpcyBtb3JlIHRoYW4gMjAwbW0KcnMgPC0gd2hpY2goZGYkY2lyY3VtZmVyZW5jZSA+IDIwMCkKCiMgZGlzcGxheSBhbGwgcm93cyB3aGVyZSB0aGUgY2lyY3VtZmVyZW5jZSBpcyBtb3JlIHRoYW4gMjAwbW0KZGZbcnMsXQoKIyBjb21wb3VuZCBjb25kaXRpb25zIGFyZSBwb3NzaWJsZSB3aXRoICYgKGFuZCksIHwgKG9yKSwgYW5kICEgKG5vdCkKcnMyIDwtIHdoaWNoKGRmJGNpcmN1bWZlcmVuY2UgPiAyMDAgJiBkZiRhZ2UgPCAxNTAwKQpyczMgPC0gd2hpY2goZGYkY2lyY3VtZmVyZW5jZSA8IDIwMCB8ICEoZGYkYWdlIDwgMTUwMCkpCnJzNCA8LSB3aGljaChkZiRjaXJjdW1mZXJlbmNlID4gNDAwIHwgZGYkYWdlID4gMTUwMCkKCnJzMgpyczMKcnM0CgptZWFuKGRmW3JzNCwyXSkKbWVhbihkZiRhZ2VbcnMzXSkKCmBgYAoKSW4gdGhlIGFib3ZlIGV4YW1wbGUgPGNvZGU+cnMgXDwtIHdoaWNoKGRmXCRjaXJjdW1mZXJlbmNlIFw+IDIwMCk8L2NvZGU+IGZpbmRzIGFsbCByb3dzIGluIHRoZSBkYXRhIGZyYW1lICpkZiogd2hlcmUgKmNpcmN1bWZlcmVuY2UgXD4gMjAwKi4gVGhlIHJvd3MgYXJlIHNhdmVkIGluICpycyouCgojIyMgYW55CgpUaGUgPGNvZGU+YW55PC9jb2RlPiBmdW5jdGlvbiByZXR1cm5zICRUUlVFJCBvciAkRkFMU0UkIGRlcGVuZGluZyBvbiB3aGV0aGVyIGFueSBjb2x1bW4gKG9yIHJvdykgaW4gdGhlIGRhdGFmcmFtZSBzYXRpc2ZpZXMgYSBCb29sZWFuIGV4cHJlc3Npb24uCgpgYGB7cn0KIyBpcyB0aGVyZSBhbnkgdHJlZSB3aXRoIGFnZSA+IDIwMDA/CmFueShkZiRhZ2UgPiAyNSkKYGBgCgojIyBNZW1vcnkgTWFuYWdlbWVudAoKUiBpcyBzaW1pbGFyIHRvIFB5dGhvbiBhbmQgb3RoZXIgaW50ZXJwcmV0ZWQgbGFuZ3VhZ2VzIGluIHRlcm1zIG9mIG1lbW9yeSBtYW5hZ2VtZW50LiBPYmplY3RzIGFuZCB2YXJpYWJsZXMgcmVtYWluIGluIG1lbW9yeSB1bnRpbCB5b3UgcmVzdGFydCBSIG9yIGV4cGxpY2l0bHkgZGVsZXRlIHRoZW0uIFRoaXMgY2FuIHNvbWV0aW1lcyBjYXVzZSBjb25mbGljdHMgZHVyaW5nIGRldmVsb3BtZW50LiBBZGRpbmcgdGhpcyB0byB0aGUgc3RhcnQgb2YgYW4gUiBzY3JpcHQgb3IgYW4gUiBOb3RlYm9vayBlbnN1cmVzIHRoYXQgdGhlIHByb2dyYW0gcnVucyB3aXRoIGFuIGVtcHR5IG1lbW9yeSBlbnZpcm9ubWVudC4gVGhpcyBpcyBjcml0aWNhbCBmb3IgbGFuZ3VhZ2VzIGxpa2UgUiBhbmQgUHl0aG9uLCBidXQgaXMgbm90IG5lZWRlZCBmb3IgcHJvZ3JhbW1pbmcgbGFuZ3VhZ2VzIHRoYXQgcnVuIGluIHNlcGFyYXRlIHByb2Nlc3NlcyBzdWNoIGFzIEphdmEgYW5kIEMrKyBwcm9ncmFtcy4KClVzZSB0aGUgY29kZSBiZWxvdyB0byBmaW5kIGFuZCB0aGVuIGRlbGV0ZSBhbGwgb2JqZWN0cywgYW5kIHJlY2xhaW0gbWVtb3J5LiBUaGUgZnVuY3Rpb24gPGNvZGU+bHMoKTwvY29kZT4gbGlzdHMgYWxsIG9iamVjdHMgKHZhcmlhYmxlcykgYnkgbmFtZSwgd2hpbGUgdGhlIDxjb2RlPnJtKCk8L2NvZGU+IHJlbW92ZXMgb25lIG9yIG1vcmUgb2JqZWN0cyBmcm9tIG1lbW9yeS4gRmluYWxseSwgdGhlIGZ1bmN0aW9uIDxjb2RlPmdjKCk8L2NvZGU+IHJ1bnMgdGhlIGdhcmJhZ2UgY29sbGVjdG9yIGFuZCByZXR1cm5zIGZyZWVkIG1lbW9yeSB0byB0aGUgdXNhYmxlIG1lbW9yeSBwb29sIGZvciB0aGUgcHJvY2VzcyBpbiB3aGljaCBSIGlzIHJ1bm5pbmcuCgpgYGB7ciBjbGVhbk1lbSwgZWNobz1ULCBldmFsPUZ9CnJtKGxpc3QgPSBscyhhbGwubmFtZXMgPSBUUlVFKSkKZ2MoKQpgYGAKCk9mIGNvdXJzZSwgcmF0aGVyIHRoYW4gZGVsZXRpbmcgYWxsIG9iamVjdHMgYXMgaW4gdGhlIGNvZGUgY2h1bmsgYWJvdmUsIHlvdSBtYXkgd2lzaCB0byByZWxlYXNlIGxhcmdlIG9iamVjdHMgb3IgdW51c2VkIG9iamVjdHMgc2VsZWN0aXZlbHkgYnkgdGhlaXIgbmFtZSwgKmUuZy4qLCA8Y29kZT5ybSgib2JqTmFtZSIpPC9jb2RlPi4KCiMjIEluc3RhbGwgUGFja2FnZXMgb24gRGVtYW5kCgpUbyBtYWtlIHlvdXIgY29kZSBwb3J0YWJsZSBhbmQgcmVwcm9kdWNpYmxlLCBpbnN0YWxsIHBhY2thZ2VzIHdpdGhpbiB5b3VyIGNvZGU6CgpgYGB7cn0KIyBwYWNrYWdlcyBuZWVkZWQgaW4gUiBwcm9ncmFtCnBhY2thZ2VzIDwtIGMoInN0cmluZ3IiLCAiUlNRTGl0ZSIpCgojIGluc3RhbGwgcGFja2FnZXMgbm90IHlldCBpbnN0YWxsZWQKaW5zdGFsbGVkX3BhY2thZ2VzIDwtIHBhY2thZ2VzICVpbiUgcm93bmFtZXMoaW5zdGFsbGVkLnBhY2thZ2VzKCkpCmlmIChhbnkoaW5zdGFsbGVkX3BhY2thZ2VzID09IEZBTFNFKSkgewogIGluc3RhbGwucGFja2FnZXMocGFja2FnZXNbIWluc3RhbGxlZF9wYWNrYWdlc10pCn0KCiMgbG9hZCBhbGwgcGFja2FnZXMgYnkgYXBwbHlpbmcgJ2xpYnJhcnknIGZ1bmN0aW9uCmludmlzaWJsZShsYXBwbHkocGFja2FnZXMsIGxpYnJhcnksIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkpCmBgYAoKIyMgQ29uY2x1c2lvbgoKQXMgeW91IHNhdywgUiBpcyBub3QgYSBkaWZmaWN1bHQgbGFuZ3VhZ2UgdG8gbGVhcm4gYXMgaXQgaXMgc2ltaWxhciB0byBvdGhlciBsYW5ndWFnZXMgYW5kIGZvciBtb3N0IGxhbmd1YWdlIGNvbnN0cnVjdHMgdGhhdCB5b3UgYXJlIGZhbWlsaWFyIHdpdGgsIHRoZXJlIGlzIGFuIGVxdWl2YWxlbnQuIEJ1dCBpdCBpcyBpbXBvcnRhbnQgdGhhdCB5b3UgZ28gYmV5b25kIHRoaXMgdHV0b3JpYWwgYW5kIGxlYXJuIHRoZSAiUiB3YXkiIG9mIHByb2dyYW1taW5nIHVzaW5nIHZlY3Rvcml6ZWQgb3BlcmF0aW9ucy4KCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyMgRmlsZXMgJiBSZXNvdXJjZXMKCmBgYHtyIHppcEZpbGVzLCBlY2hvPUZBTFNFfQp6aXBOYW1lID0gc3ByaW50ZigiTGVzc29uRmlsZXMtJXMtJXMuemlwIiwgCiAgICAgICAgICAgICAgICAgcGFyYW1zJGNhdGVnb3J5LAogICAgICAgICAgICAgICAgIHBhcmFtcyRudW1iZXIpCgp0ZXh0QUxpbmsgPSBwYXN0ZTAoIkFsbCBGaWxlcyBmb3IgTGVzc29uICIsIAogICAgICAgICAgICAgICBwYXJhbXMkY2F0ZWdvcnksIi4iLHBhcmFtcyRudW1iZXIpCgojIGRvd25sb2FkRmlsZXNMaW5rKCkgaXMgaW5jbHVkZWQgZnJvbSBfaW5zZXJ0MkRCLlIKa25pdHI6OnJhd19odG1sKGRvd25sb2FkRmlsZXNMaW5rKCIuIiwgemlwTmFtZSwgdGV4dEFMaW5rKSkKYGBgCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMjIFJlZmVyZW5jZXMKCk5vIHJlZmVyZW5jZXMuCgojIyBFcnJhdGEKCk5vbmUgY29sbGVjdGVkIHlldC4gTGV0IHVzIGtub3cuCgpgYGB7PWh0bWx9CjxzY3JpcHQgc3JjPSJodHRwczovL2Zvcm0uam90Zm9ybS5jb20vc3RhdGljL2ZlZWRiYWNrMi5qcyIgdHlwZT0idGV4dC9qYXZhc2NyaXB0Ij4KICBuZXcgSm90Zm9ybUZlZWRiYWNrKHsKICAgIGZvcm1JZDogIjIxMjE4NzA3Mjc4NDE1NyIsCiAgICBidXR0b25UZXh0OiAiRmVlZGJhY2siLAogICAgYmFzZTogImh0dHBzOi8vZm9ybS5qb3Rmb3JtLmNvbS8iLAogICAgYmFja2dyb3VuZDogIiNGNTkyMDIiLAogICAgZm9udENvbG9yOiAiI0ZGRkZGRiIsCiAgICBidXR0b25TaWRlOiAibGVmdCIsCiAgICBidXR0b25BbGlnbjogImNlbnRlciIsCiAgICB0eXBlOiBmYWxzZSwKICAgIHdpZHRoOiA3MDAsCiAgICBoZWlnaHQ6IDUwMCwKICAgIGlzQ2FyZEZvcm06IGZhbHNlCiAgfSk7Cjwvc2NyaXB0PgpgYGAKYGBge3IgY29kZT14ZnVuOjpyZWFkX3V0ZjgocGFzdGUwKGhlcmU6OmhlcmUoKSwnL1IvX2RlcGxveUtuaXQuUicpKSwgaW5jbHVkZSA9IEZBTFNFfQpgYGAK