R Markdown

R Markdown is a tool for literate programming. Literate programming is a paradigm where execuatable code blocks are mixed with an explanation of how the code works. Although it’s possible to achieve some degree of literate programming by just including comments in your code, tools like R Markdown and Jupyter notebooks allow programmers to include richer content (like images and clickable hyperlinks) in their explanatory content.

Viewing R Markdown in RStudio

This document is itself an R Markdown Notebook. To download it, go to this page.

Right click on the Raw button and select Save link as .... Save the notebook somewhere where you can find it. In R Studio, click the Open button or select the Open File option from the File menu. Navigate to the place where you saved the file and open it.

When you load the notebook into the editor pane of RStudio, you see the Markdown document markup, which isn’t that easy to read. However, you can render the Markdown in a viewer pane.

Selecting Preview in Viewer Pane

Selecting Preview in Viewer Pane

Drop down the little gear icon to the right of the Preview button and select Preview in Viewer Pant. If necessary, click the Preview button. You should see the pretty version of the text in the Viewer pane at the right.

When viewing an R Markdown notebook, the editor pane and Viewer pane are expanded to make them easier to see and the Environment and Console panes are collapsed. If you want to expand them to see what’s going on there, click on the expand icon at the right of their header.

Running code in an R Markdown notebook

To execute a code chunk, click on the Run button (triangle) at the right of the chunk, or place the cursor in the chunk and hold Command+Shift then press Return on Mac or hold Ctrl+Shift then press Enter on Windows. To execute a single line, place the cursor on the line and press Command Return (Ctrl Enter) without pressing the Shift key.

When you execute code within the notebook, the results appear beneath the code. Try executing this example.

animal <- c("frog", "spider", "worm", "bee")
animal[1]

If configured correctly, R Markdown can also execute chunks of Python code:

string = 'hey dude!'
print(string)

and console commands:

ls *.Rmd

The type of command is indicated after the triple backticks above the code block.

Separate chunks of R code “remember”" what’s in the environment from the execution of a previous chunk. If I’ve previously run the chunk above that assigns values to animal, I can recall a value when I run this chunk:

animal[3]

You can edit the code in a chunk and re-run it to see the effect of your changes. (If you are used to Jupyter notebooks, this behavior is similar to the behavior of code cells in a notebook.)

To clear the output of one or all chunks, go to the Edit menu and select Clear Output or Clear All Output.

To add a new chunk, click the Insert button on the toolbar and select R.

To refresh the preview of the code in the Viewer pane, click the Preview button again.

R data basics

Categorizing objects in R

There are two main ways of categorizing objects in R. Obhects can be categorized by their mode, which represents how they are stored. Common modes are: numeric, character, list, and functions. We can find the mode of an object using the mode() function:

pet <- "rover"
pie <- 3.14159
animal <- c("frog", "spider", "worm", "bee")
mode(pet)
mode(pie)
mode(animal)

Objects can also be characterized by their class, which determines how R will process those objects.

Sequences

You can generate a sequence of numbers like this:

1:5

Using this simple notation the sequence steps by ones. You can have the sequence count down by putting the larger number in front of the colon:

10:-2

If you are used to Python, you should notice that the sequence does not end at one value before the final number as it does in Python ranges.

R data structures

R has a number of data structures that vary by the kinds of things that can be stored in them and their dimensionality (1 dimensional, 2 dimensional, etc.). We’ll learn about four: vectors, lists, data frames, and tibbles.

Vectors

Diagram of a vector

Diagram of a vector

A vector is a one-dimensional data structure consisting of items of the same mode. In R, all data structures are “one based” (counting starts with one) as opposed to “zero-based” languages like Python.

Here’s how to assign values to a vector using the “construct” function:

animal <- c("frog", "spider", "worm", "bee")

Expand the Environment pane so that you can see the values in the vector. Note: in R, it is conventional to use double quotes to define string literals, although single quotes are allowed.

You can also create a vector of numbers:

myNumbers <- c(1, 3, 6, 10, 15)

When you create a sequence using the colon notation, the result is a vector that is the same as if you used the construct function:

firstVector <- 1:5
secondVector <- c(1:5)

firstVector
secondVector

To find the number of items in a vector, use the length() function:

length(animal)

To append another item to a vector, include the previous vector in the construct function:

animal <- c(animal,"monkey")

animal
length(animal)

To replace a particular item, reference it by its index:

animal[2] <- "arachnid"

You can refer to part of a vector using a subvector reference like this:

animal[2:4]

The items in the vector that you are extracting are specified by the sequence you put in the square brackets. (Aside for Python users: unlike Python slices, the last number in the sequence is included in the subvector. Also remember that that the first item in the vector is 1, not 0 as in Python.)

You can explicitly construct the sequence of items by listing the item numbers. You can also assign the sequence to a variable and specifiy the items to be extracted with it.

animal[c(4, 1, 3)]
indexSequence <- 4:1
animal[indexSequence]

One somewhat surprising thing about R is that individual items are actually vectors with lengths of one. The result is the same whether the item is assigned directly to a variable or assigned by the construct function.

thingOne <- c("thing")
thingTwo <- "thing"

thingOne
thingOne[1]
thingTwo
thingTwo[1]

length(thingOne)
length(thingOne[1])
length(thingTwo)

R has two built-in values to indicate that something is wrong: NA and NULL.

NA is used for missing values. It is an indicator that a value is missing and it can be assigned to a vector as a value. It has a length of one and you can think of it as a sort of empty item.

animal[2] <- NA
animal

NULL is used to indicate that there is no value. It can’t be assigned to a vector as a value. It has a length of zero and and you can think of it as the case of an item that isn’t there.

animal[3] <- NULL
animal

Lists

Diagram of a list

Diagram of a list

A list is also a one-dimensional data structure, like a vector. However, the items in a list can be heterogeneous (different modes of items). In the example above, the list contains two character strings, one number, and one vector.

Assuming that the animal vector is in your environment, the following command will create the list diagrammed above:

thing <- list(fruitKind="apple", euler=2.71828, vectorData=animal, curse="!@#$%")

Notice that in this list I’ve assigned the items to the list by name. (It is also possbile to assign names to vector items but that is less common.)

Because the list is complicated, the items composing it are not shown in the Environment pane. To see all of the list’s parts, I can either click on the thing entry in the Environment pane, or issue the command:

View(thing)

When I view the list, the description opens as a new tabl in the same pane as the editor.

Items in a list can viewed by either their position or their name. In contrast to vectors, the index is put in double square brackets.

thing[[3]]
thing[["euler"]]

A commonly used shorthand method for referring to list items by their names is by separating the list from the name by a dollar sign:

thing$euler
thing$vectorData

Factors

A factor is a data structure for categorizing data. Its origin comes from experimental design terminology. In an experiment, each category into which an experimental trial can fall is called a level. A factor consists of all of the possible levels that are used to group trials based on that factor. Here is an example of an experiment where plants were grown in wet or dry soil:

water factor height (cm)
wet 25
wet 21
dry 14
wet 13
dry 10
wet 18

We can create a vector containing all of the water conditions and another vector containing the heights:

waterConditions <- c("wet", "wet", "dry", "wet", "dry", "wet")
height <- c(25, 21, 14, 13, 10, 18)

waterConditions
height

To convert the weatherConditions vector into a factor, use the factor() function:

waterFactor <- factor(waterConditions)

waterFactor

When we run the code chunk above, we can see two ways that waterFactor is different from waterConditions:

  • the waterFactor items are not in quotation marks
  • below the list of items is a summary of the levels, showing that there are only two different categories into which the experimental trials can be grouped.
Factor vs. vector in the Environment

Factor vs. vector in the Environment

We can also see by looking at the Environment pane that waterConditions is identified as a vector of character strings, while waterFactor is identified as a Factor with two levels.

Factors are stored and processed more efficiently than characters and play a special role as grouping variables in statistical tests that require the data to be placed into categorical groups.

Data frames

Structure of a data frame

Structure of a data frame

Data frames are two dimensional data structures and are one of the most widely used data types in R. One can think of a data frame as a table with rows and columns, with the top row containing column headers that are names describing what’s in the columns.

It is helpful to think of a data frame as a sort of combination of lists and vectors. The values in a particular column are like a vector, with the column header for that column containing the vector’s name. The set of columns is like a list whose items are vectors.

We can actually create a data frame by first constructing a vector for each column:

group <- c("reptile", "arachnid", "annelid", "insect")  # vector of strings
animal <- c("frog", "spider", "worm", "bee")
numberLegs <- c(4,8,0,6)  # vector of numbers

then loading the vectors into the data frame:

organismInfo <- data.frame(group, animal, numberLegs)

organismInfo

By default, R will use the name of each vector as the name for the column in the data frame. Expand the Environment pane to see what happened when you created the vectors and data frame, and click on the data frame listing to see its structure.

We can refer to a particular cell in the table by listing its row followed by its column in brackets, like this:

organismInfo[2,1]

Because the columns of a data frame behave somewhat like list items, the notation for referring to list items by name (dollar sign followed by name) can also be used to refer to columns in a data frame:

organismInfo$animal

and items in that column can be referred to by their position from the top of the column:

organismInfo$animal[4]

One thing that you may have noticed is that when we list values in the data frame that came from the vector of character strings, they are not in quotes and have levels listed below them. This is because when character data vectors are loaded into a data frame, they are automatically converted to factors. We can see this by asking about the class of the objects we have been working with:

class(organismInfo)
class(organismInfo$animal)
class(organismInfo$numberLegs)

We can also see that the values of the factor are actually not stored as strings, but as numbers:

organismInfo[2,1]
class(organismInfo[2,1])
mode(organismInfo[2,1])

By storing the factors as numbers, they can be ordered. The order of the factors is important in some analyses.

Tibbles

More recently, the use of R has expanded far beyond statistics, so automatically trasforming character data into a form that is optimal for statistics (i.e. factors) is no longer necessarily desirable in every case. Another two-dimensional data structure, called a tibble, was developed to broaden the use of data frames. When data are read into a tibble, there is never a conversion of data types (strings remain strings).

Tibbles are not part of the standard R distribution, so to use them you need to load a library called tidyverse. You can create a tibble using the tibble() function:

library(tidyverse)
organismTibble <- tibble(group, animal, numberLegs)

organismTibble

If you compare the output of the organismTibble tibble with the output of the organismInfo data frame, the column type listed below the column header is chr for the tibble and fctr for the data frame. So we can see that when the vectors were loaded into the tibble, their class was NOT changed.

class(organismTibble)
class(organismTibble$animal)
class(organismTibble$numberLegs)

The class of the tibble is listed as both tbl (tibble) and data.frame (data frame) because a tibble is considered a special kind of data frame. You can also see that the animal column remained characters and was not converted to a factor as was the case when we created the data frame.

Applying functions

A function is like a machine that transforms what we put into it into something different that comes out. We pass arguments into the function and the function returns values.

Nykamp DQ, “Function machine f.” From Math Insight. http://mathinsight.org/image/function_machine_f CC BY-NC-SA

Nykamp DQ, “Function machine f.” From Math Insight. http://mathinsight.org/image/function_machine_f CC BY-NC-SA

There are many built-in functions in R. For example, I can take the square root of a number by passing it into the sqrt() function.

x <- 2
sqrt(x)

In this case, I passed a single numeric value into the function and got out a single value. However, recall that in R a variable containing a single value is the same as a vector with a length of one. What that means is that for many functions, I can pass in a vector containing many items and the function will be applied to every item in the vector. The output returned from the function is also a vector whose items are in the same order as the input vector.

sqrt(organismInfo$numberLegs)

Other functions may expect a vector input, but output only a single number. The mean() function takes the average of the items in a vector and returns a single value.

mean(organismInfo$numberLegs)

R differs from some other languages like Python in that it can automatically perform functions on an entire vector of values without requiring that the code iterate through each item in the vector.

Here is another example using the nchar() function that counts the number of characters in a string:

# list the words in the animal column
organismTibble$animal

# list the count of characters in each word in the column
nchar(organismTibble$animal)
LS0tDQp0aXRsZTogIkxlc3NvbiAyOiBEYXRhIHN0cnVjdHVyZXMiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQojIFIgTWFya2Rvd24NCg0KKlIgTWFya2Rvd24qIGlzIGEgdG9vbCBmb3IgKmxpdGVyYXRlIHByb2dyYW1taW5nKi4gTGl0ZXJhdGUgcHJvZ3JhbW1pbmcgaXMgYSBwYXJhZGlnbSB3aGVyZSBleGVjdWF0YWJsZSBjb2RlIGJsb2NrcyBhcmUgbWl4ZWQgd2l0aCBhbiBleHBsYW5hdGlvbiBvZiBob3cgdGhlIGNvZGUgd29ya3MuICBBbHRob3VnaCBpdCdzIHBvc3NpYmxlIHRvIGFjaGlldmUgc29tZSBkZWdyZWUgb2YgbGl0ZXJhdGUgcHJvZ3JhbW1pbmcgYnkganVzdCBpbmNsdWRpbmcgY29tbWVudHMgaW4geW91ciBjb2RlLCB0b29scyBsaWtlIFIgTWFya2Rvd24gYW5kIEp1cHl0ZXIgbm90ZWJvb2tzIGFsbG93IHByb2dyYW1tZXJzIHRvIGluY2x1ZGUgcmljaGVyIGNvbnRlbnQgKGxpa2UgaW1hZ2VzIGFuZCBjbGlja2FibGUgaHlwZXJsaW5rcykgaW4gdGhlaXIgZXhwbGFuYXRvcnkgY29udGVudC4gIA0KDQojIyBWaWV3aW5nIFIgTWFya2Rvd24gaW4gUlN0dWRpbw0KDQpUaGlzIGRvY3VtZW50IGlzIGl0c2VsZiBhbiBbUiBNYXJrZG93bl0oaHR0cDovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbSkgTm90ZWJvb2suIFRvIGRvd25sb2FkIGl0LCBnbyB0byBbdGhpcyBwYWdlXShodHRwczovL2dpdGh1Yi5jb20vSGVhcmRMaWJyYXJ5L2RpZ2l0YWwtc2Nob2xhcnNoaXAvYmxvYi9tYXN0ZXIvY29kZS9yL2xlc3NvbjIuUm1kKS4NCg0KIVtdKGh0dHBzOi8vZ2l0aHViLmNvbS9IZWFyZExpYnJhcnkvZGlnaXRhbC1zY2hvbGFyc2hpcC9yYXcvZ2gtcGFnZXMvc2NyaXB0L3IvaW1hZ2VzL3ItbWFya2Rvd24tbm90ZWJvb2stZG93bmxvYWQucG5nKSANCg0KUmlnaHQgY2xpY2sgb24gdGhlIGBSYXdgIGJ1dHRvbiBhbmQgc2VsZWN0IGBTYXZlIGxpbmsgYXMgLi4uYC4gU2F2ZSB0aGUgbm90ZWJvb2sgc29tZXdoZXJlIHdoZXJlIHlvdSBjYW4gZmluZCBpdC4gIEluIFIgU3R1ZGlvLCBjbGljayB0aGUgT3BlbiBidXR0b24gb3Igc2VsZWN0IHRoZSBgT3BlbiBGaWxlYCBvcHRpb24gZnJvbSB0aGUgYEZpbGVgIG1lbnUuIE5hdmlnYXRlIHRvIHRoZSBwbGFjZSB3aGVyZSB5b3Ugc2F2ZWQgdGhlIGZpbGUgYW5kIG9wZW4gaXQuDQoNCldoZW4geW91IGxvYWQgdGhlIG5vdGVib29rIGludG8gdGhlIGVkaXRvciBwYW5lIG9mIFJTdHVkaW8sIHlvdSBzZWUgdGhlIE1hcmtkb3duIGRvY3VtZW50IG1hcmt1cCwgd2hpY2ggaXNuJ3QgdGhhdCBlYXN5IHRvIHJlYWQuICBIb3dldmVyLCB5b3UgY2FuIHJlbmRlciB0aGUgTWFya2Rvd24gaW4gYSB2aWV3ZXIgcGFuZS4gIA0KDQohW1NlbGVjdGluZyBQcmV2aWV3IGluIFZpZXdlciBQYW5lXShodHRwczovL2dpdGh1Yi5jb20vSGVhcmRMaWJyYXJ5L2RpZ2l0YWwtc2Nob2xhcnNoaXAvcmF3L2doLXBhZ2VzL3NjcmlwdC9yL2ltYWdlcy9wcmV2aWV3LWluLXZpZXdlci5wbmcpIA0KDQpEcm9wIGRvd24gdGhlIGxpdHRsZSBnZWFyIGljb24gdG8gdGhlIHJpZ2h0IG9mIHRoZSBgUHJldmlld2AgYnV0dG9uIGFuZCBzZWxlY3QgYFByZXZpZXcgaW4gVmlld2VyIFBhbnRgLiAgSWYgbmVjZXNzYXJ5LCBjbGljayB0aGUgYFByZXZpZXdgIGJ1dHRvbi4gIFlvdSBzaG91bGQgc2VlIHRoZSBwcmV0dHkgdmVyc2lvbiBvZiB0aGUgdGV4dCBpbiB0aGUgVmlld2VyIHBhbmUgYXQgdGhlIHJpZ2h0LiAgDQoNCjxpbWcgc3JjPSJodHRwczovL2dpdGh1Yi5jb20vSGVhcmRMaWJyYXJ5L2RpZ2l0YWwtc2Nob2xhcnNoaXAvcmF3L2doLXBhZ2VzL3NjcmlwdC9yL2ltYWdlcy9jbGljay10by1leHBhbmQucG5nIiBzdHlsZT0iYm9yZGVyOjFweCBzb2xpZCBibGFjayIgLz4NCg0KV2hlbiB2aWV3aW5nIGFuIFIgTWFya2Rvd24gbm90ZWJvb2ssIHRoZSBlZGl0b3IgcGFuZSBhbmQgVmlld2VyIHBhbmUgYXJlIGV4cGFuZGVkIHRvIG1ha2UgdGhlbSBlYXNpZXIgdG8gc2VlIGFuZCB0aGUgRW52aXJvbm1lbnQgYW5kIENvbnNvbGUgcGFuZXMgYXJlIGNvbGxhcHNlZC4gIElmIHlvdSB3YW50IHRvIGV4cGFuZCB0aGVtIHRvIHNlZSB3aGF0J3MgZ29pbmcgb24gdGhlcmUsIGNsaWNrIG9uIHRoZSBleHBhbmQgaWNvbiBhdCB0aGUgcmlnaHQgb2YgdGhlaXIgaGVhZGVyLg0KDQojIyBSdW5uaW5nIGNvZGUgaW4gYW4gUiBNYXJrZG93biBub3RlYm9vaw0KDQpUbyBleGVjdXRlIGEgY29kZSBjaHVuaywgY2xpY2sgb24gdGhlIGBSdW5gIGJ1dHRvbiAodHJpYW5nbGUpIGF0IHRoZSByaWdodCBvZiB0aGUgY2h1bmssIG9yIHBsYWNlIHRoZSBjdXJzb3IgaW4gdGhlIGNodW5rIGFuZCBob2xkIGBDb21tYW5kYCtgU2hpZnRgIHRoZW4gcHJlc3MgYFJldHVybmAgb24gTWFjIG9yIGhvbGQgYEN0cmxgK2BTaGlmdGAgdGhlbiBwcmVzcyBgRW50ZXJgIG9uIFdpbmRvd3MuICBUbyBleGVjdXRlIGEgc2luZ2xlIGxpbmUsIHBsYWNlIHRoZSBjdXJzb3Igb24gdGhlIGxpbmUgYW5kIHByZXNzIGBDb21tYW5kYCBgUmV0dXJuYCAoYEN0cmxgIGBFbnRlcmApIHdpdGhvdXQgcHJlc3NpbmcgdGhlIGBTaGlmdGAga2V5LiAgDQoNCldoZW4geW91IGV4ZWN1dGUgY29kZSB3aXRoaW4gdGhlIG5vdGVib29rLCB0aGUgcmVzdWx0cyBhcHBlYXIgYmVuZWF0aCB0aGUgY29kZS4gVHJ5IGV4ZWN1dGluZyB0aGlzIGV4YW1wbGUuDQoNCmBgYHtyfQ0KYW5pbWFsIDwtIGMoImZyb2ciLCAic3BpZGVyIiwgIndvcm0iLCAiYmVlIikNCmFuaW1hbFsxXQ0KYGBgDQoNCklmIGNvbmZpZ3VyZWQgY29ycmVjdGx5LCBSIE1hcmtkb3duIGNhbiBhbHNvIGV4ZWN1dGUgY2h1bmtzIG9mIFB5dGhvbiBjb2RlOg0KDQpgYGB7cHl0aG9ufQ0Kc3RyaW5nID0gJ2hleSBkdWRlIScNCnByaW50KHN0cmluZykNCmBgYA0KDQphbmQgY29uc29sZSBjb21tYW5kczoNCg0KYGBge2Jhc2h9DQpscyAqLlJtZA0KYGBgDQoNClRoZSB0eXBlIG9mIGNvbW1hbmQgaXMgaW5kaWNhdGVkIGFmdGVyIHRoZSB0cmlwbGUgYmFja3RpY2tzIGFib3ZlIHRoZSBjb2RlIGJsb2NrLiAgDQoNClNlcGFyYXRlIGNodW5rcyBvZiBSIGNvZGUgInJlbWVtYmVyIiIgd2hhdCdzIGluIHRoZSBlbnZpcm9ubWVudCBmcm9tIHRoZSBleGVjdXRpb24gb2YgYSBwcmV2aW91cyBjaHVuay4gIElmIEkndmUgcHJldmlvdXNseSBydW4gdGhlIGNodW5rIGFib3ZlIHRoYXQgYXNzaWducyB2YWx1ZXMgdG8gYGFuaW1hbGAsIEkgY2FuIHJlY2FsbCBhIHZhbHVlIHdoZW4gSSBydW4gdGhpcyBjaHVuazoNCg0KYGBge3J9DQphbmltYWxbM10NCmBgYA0KDQpZb3UgY2FuIGVkaXQgdGhlIGNvZGUgaW4gYSBjaHVuayBhbmQgcmUtcnVuIGl0IHRvIHNlZSB0aGUgZWZmZWN0IG9mIHlvdXIgY2hhbmdlcy4gKElmIHlvdSBhcmUgdXNlZCB0byBKdXB5dGVyIG5vdGVib29rcywgdGhpcyBiZWhhdmlvciBpcyBzaW1pbGFyIHRvIHRoZSBiZWhhdmlvciBvZiBjb2RlIGNlbGxzIGluIGEgbm90ZWJvb2suKQ0KDQpUbyBjbGVhciB0aGUgb3V0cHV0IG9mIG9uZSBvciBhbGwgY2h1bmtzLCBnbyB0byB0aGUgYEVkaXRgIG1lbnUgYW5kIHNlbGVjdCBgQ2xlYXIgT3V0cHV0YCBvciBgQ2xlYXIgQWxsIE91dHB1dGAuDQoNClRvIGFkZCBhIG5ldyBjaHVuaywgY2xpY2sgdGhlIGBJbnNlcnRgIGJ1dHRvbiBvbiB0aGUgdG9vbGJhciBhbmQgc2VsZWN0IGBSYC4NCg0KVG8gcmVmcmVzaCB0aGUgcHJldmlldyBvZiB0aGUgY29kZSBpbiB0aGUgVmlld2VyIHBhbmUsIGNsaWNrIHRoZSBgUHJldmlld2AgYnV0dG9uIGFnYWluLg0KDQojIFIgZGF0YSBiYXNpY3MNCg0KIyMgQ2F0ZWdvcml6aW5nIG9iamVjdHMgaW4gUg0KDQpUaGVyZSBhcmUgdHdvIG1haW4gd2F5cyBvZiBjYXRlZ29yaXppbmcgb2JqZWN0cyBpbiBSLiAgT2JoZWN0cyBjYW4gYmUgY2F0ZWdvcml6ZWQgYnkgdGhlaXIgbW9kZSwgd2hpY2ggcmVwcmVzZW50cyBob3cgdGhleSBhcmUgc3RvcmVkLiAgQ29tbW9uIG1vZGVzIGFyZTogbnVtZXJpYywgY2hhcmFjdGVyLCBsaXN0LCBhbmQgZnVuY3Rpb25zLiBXZSBjYW4gZmluZCB0aGUgbW9kZSBvZiBhbiBvYmplY3QgdXNpbmcgdGhlIGBtb2RlKClgIGZ1bmN0aW9uOg0KDQpgYGB7cn0NCnBldCA8LSAicm92ZXIiDQpwaWUgPC0gMy4xNDE1OQ0KYW5pbWFsIDwtIGMoImZyb2ciLCAic3BpZGVyIiwgIndvcm0iLCAiYmVlIikNCm1vZGUocGV0KQ0KbW9kZShwaWUpDQptb2RlKGFuaW1hbCkNCmBgYA0KDQpPYmplY3RzIGNhbiBhbHNvIGJlIGNoYXJhY3Rlcml6ZWQgYnkgdGhlaXIgY2xhc3MsIHdoaWNoIGRldGVybWluZXMgaG93IFIgd2lsbCBwcm9jZXNzIHRob3NlIG9iamVjdHMuICANCg0KIyMgU2VxdWVuY2VzDQoNCllvdSBjYW4gZ2VuZXJhdGUgYSBzZXF1ZW5jZSBvZiBudW1iZXJzIGxpa2UgdGhpczoNCg0KYGBge3J9DQoxOjUNCmBgYA0KDQpVc2luZyB0aGlzIHNpbXBsZSBub3RhdGlvbiB0aGUgc2VxdWVuY2Ugc3RlcHMgYnkgb25lcy4gIFlvdSBjYW4gaGF2ZSB0aGUgc2VxdWVuY2UgY291bnQgZG93biBieSBwdXR0aW5nIHRoZSBsYXJnZXIgbnVtYmVyIGluIGZyb250IG9mIHRoZSBjb2xvbjoNCg0KYGBge3J9DQoxMDotMg0KYGBgDQoNCklmIHlvdSBhcmUgdXNlZCB0byBQeXRob24sIHlvdSBzaG91bGQgbm90aWNlIHRoYXQgdGhlIHNlcXVlbmNlIGRvZXMgbm90IGVuZCBhdCBvbmUgdmFsdWUgYmVmb3JlIHRoZSBmaW5hbCBudW1iZXIgYXMgaXQgZG9lcyBpbiBQeXRob24gcmFuZ2VzLg0KDQojIFIgZGF0YSBzdHJ1Y3R1cmVzDQoNClIgaGFzIGEgbnVtYmVyIG9mIGRhdGEgc3RydWN0dXJlcyB0aGF0IHZhcnkgYnkgdGhlIGtpbmRzIG9mIHRoaW5ncyB0aGF0IGNhbiBiZSBzdG9yZWQgaW4gdGhlbSBhbmQgdGhlaXIgZGltZW5zaW9uYWxpdHkgKDEgZGltZW5zaW9uYWwsIDIgZGltZW5zaW9uYWwsIGV0Yy4pLiAgV2UnbGwgbGVhcm4gYWJvdXQgZm91cjogdmVjdG9ycywgbGlzdHMsIGRhdGEgZnJhbWVzLCBhbmQgdGliYmxlcy4NCg0KIyMgVmVjdG9ycw0KDQohW0RpYWdyYW0gb2YgYSB2ZWN0b3JdKGh0dHBzOi8vaGVhcmRsaWJyYXJ5LmdpdGh1Yi5pby9kaWdpdGFsLXNjaG9sYXJzaGlwL3NjcmlwdC9yL2ltYWdlcy92ZWN0b3ItZGlhZ3JhbS5wbmcpDQoNCkEgKnZlY3RvciogaXMgYSBvbmUtZGltZW5zaW9uYWwgZGF0YSBzdHJ1Y3R1cmUgY29uc2lzdGluZyBvZiBpdGVtcyBvZiB0aGUgc2FtZSBtb2RlLiAgSW4gUiwgYWxsIGRhdGEgc3RydWN0dXJlcyBhcmUgIm9uZSBiYXNlZCIgKGNvdW50aW5nIHN0YXJ0cyB3aXRoIG9uZSkgYXMgb3Bwb3NlZCB0byAiemVyby1iYXNlZCIgbGFuZ3VhZ2VzIGxpa2UgUHl0aG9uLg0KDQpIZXJlJ3MgaG93IHRvIGFzc2lnbiB2YWx1ZXMgdG8gYSB2ZWN0b3IgdXNpbmcgdGhlICJjb25zdHJ1Y3QiIGZ1bmN0aW9uOg0KDQpgYGB7cn0NCmFuaW1hbCA8LSBjKCJmcm9nIiwgInNwaWRlciIsICJ3b3JtIiwgImJlZSIpDQpgYGANCg0KRXhwYW5kIHRoZSBFbnZpcm9ubWVudCBwYW5lIHNvIHRoYXQgeW91IGNhbiBzZWUgdGhlIHZhbHVlcyBpbiB0aGUgdmVjdG9yLiAgTm90ZTogaW4gUiwgaXQgaXMgY29udmVudGlvbmFsIHRvIHVzZSBkb3VibGUgcXVvdGVzIHRvIGRlZmluZSBzdHJpbmcgbGl0ZXJhbHMsIGFsdGhvdWdoIHNpbmdsZSBxdW90ZXMgYXJlIGFsbG93ZWQuIA0KDQpZb3UgY2FuIGFsc28gY3JlYXRlIGEgdmVjdG9yIG9mIG51bWJlcnM6DQoNCmBgYHtyfQ0KbXlOdW1iZXJzIDwtIGMoMSwgMywgNiwgMTAsIDE1KQ0KYGBgDQoNCldoZW4geW91IGNyZWF0ZSBhIHNlcXVlbmNlIHVzaW5nIHRoZSBjb2xvbiBub3RhdGlvbiwgdGhlIHJlc3VsdCBpcyBhIHZlY3RvciB0aGF0IGlzIHRoZSBzYW1lIGFzIGlmIHlvdSB1c2VkIHRoZSBjb25zdHJ1Y3QgZnVuY3Rpb246DQoNCmBgYHtyfQ0KZmlyc3RWZWN0b3IgPC0gMTo1DQpzZWNvbmRWZWN0b3IgPC0gYygxOjUpDQoNCmZpcnN0VmVjdG9yDQpzZWNvbmRWZWN0b3INCmBgYA0KDQpUbyBmaW5kIHRoZSBudW1iZXIgb2YgaXRlbXMgaW4gYSB2ZWN0b3IsIHVzZSB0aGUgYGxlbmd0aCgpYCBmdW5jdGlvbjoNCg0KYGBge3J9DQpsZW5ndGgoYW5pbWFsKQ0KYGBgDQoNCg0KVG8gYXBwZW5kIGFub3RoZXIgaXRlbSB0byBhIHZlY3RvciwgaW5jbHVkZSB0aGUgcHJldmlvdXMgdmVjdG9yIGluIHRoZSBjb25zdHJ1Y3QgZnVuY3Rpb246DQoNCmBgYHtyfQ0KYW5pbWFsIDwtIGMoYW5pbWFsLCJtb25rZXkiKQ0KDQphbmltYWwNCmxlbmd0aChhbmltYWwpDQpgYGANCg0KVG8gcmVwbGFjZSBhIHBhcnRpY3VsYXIgaXRlbSwgcmVmZXJlbmNlIGl0IGJ5IGl0cyBpbmRleDoNCg0KYGBge3J9DQphbmltYWxbMl0gPC0gImFyYWNobmlkIg0KYGBgDQoNCllvdSBjYW4gcmVmZXIgdG8gcGFydCBvZiBhIHZlY3RvciB1c2luZyBhIHN1YnZlY3RvciByZWZlcmVuY2UgbGlrZSB0aGlzOg0KDQpgYGB7cn0NCmFuaW1hbFsyOjRdDQpgYGANCg0KVGhlIGl0ZW1zIGluIHRoZSB2ZWN0b3IgdGhhdCB5b3UgYXJlIGV4dHJhY3RpbmcgYXJlIHNwZWNpZmllZCBieSB0aGUgc2VxdWVuY2UgeW91IHB1dCBpbiB0aGUgc3F1YXJlIGJyYWNrZXRzLiAgKEFzaWRlIGZvciBQeXRob24gdXNlcnM6IHVubGlrZSBQeXRob24gc2xpY2VzLCB0aGUgbGFzdCBudW1iZXIgaW4gdGhlIHNlcXVlbmNlIGlzIGluY2x1ZGVkIGluIHRoZSBzdWJ2ZWN0b3IuICBBbHNvIHJlbWVtYmVyIHRoYXQgdGhhdCB0aGUgZmlyc3QgaXRlbSBpbiB0aGUgdmVjdG9yIGlzIDEsIG5vdCAwIGFzIGluIFB5dGhvbi4pDQoNCllvdSBjYW4gZXhwbGljaXRseSBjb25zdHJ1Y3QgdGhlIHNlcXVlbmNlIG9mIGl0ZW1zIGJ5IGxpc3RpbmcgdGhlIGl0ZW0gbnVtYmVycy4gIFlvdSBjYW4gYWxzbyBhc3NpZ24gdGhlIHNlcXVlbmNlIHRvIGEgdmFyaWFibGUgYW5kIHNwZWNpZml5IHRoZSBpdGVtcyB0byBiZSBleHRyYWN0ZWQgd2l0aCBpdC4NCg0KYGBge3J9DQphbmltYWxbYyg0LCAxLCAzKV0NCmluZGV4U2VxdWVuY2UgPC0gNDoxDQphbmltYWxbaW5kZXhTZXF1ZW5jZV0NCmBgYA0KDQpPbmUgc29tZXdoYXQgc3VycHJpc2luZyB0aGluZyBhYm91dCBSIGlzIHRoYXQgaW5kaXZpZHVhbCBpdGVtcyBhcmUgYWN0dWFsbHkgdmVjdG9ycyB3aXRoIGxlbmd0aHMgb2Ygb25lLiBUaGUgcmVzdWx0IGlzIHRoZSBzYW1lIHdoZXRoZXIgdGhlIGl0ZW0gaXMgYXNzaWduZWQgZGlyZWN0bHkgdG8gYSB2YXJpYWJsZSBvciBhc3NpZ25lZCBieSB0aGUgY29uc3RydWN0IGZ1bmN0aW9uLiAgDQoNCmBgYHtyfQ0KdGhpbmdPbmUgPC0gYygidGhpbmciKQ0KdGhpbmdUd28gPC0gInRoaW5nIg0KDQp0aGluZ09uZQ0KdGhpbmdPbmVbMV0NCnRoaW5nVHdvDQp0aGluZ1R3b1sxXQ0KDQpsZW5ndGgodGhpbmdPbmUpDQpsZW5ndGgodGhpbmdPbmVbMV0pDQpsZW5ndGgodGhpbmdUd28pDQpgYGANCg0KUiBoYXMgdHdvIGJ1aWx0LWluIHZhbHVlcyB0byBpbmRpY2F0ZSB0aGF0IHNvbWV0aGluZyBpcyB3cm9uZzogYE5BYCBhbmQgYE5VTExgLiAgDQoNCmBOQWAgaXMgdXNlZCBmb3IgbWlzc2luZyB2YWx1ZXMuICBJdCBpcyBhbiBpbmRpY2F0b3IgdGhhdCBhIHZhbHVlIGlzIG1pc3NpbmcgYW5kIGl0IGNhbiBiZSBhc3NpZ25lZCB0byBhIHZlY3RvciBhcyBhIHZhbHVlLiAgSXQgaGFzIGEgbGVuZ3RoIG9mIG9uZSBhbmQgeW91IGNhbiB0aGluayBvZiBpdCBhcyBhIHNvcnQgb2YgZW1wdHkgaXRlbS4gDQoNCmBgYHtyfQ0KYW5pbWFsWzJdIDwtIE5BDQphbmltYWwNCmBgYA0KDQpgTlVMTGAgaXMgdXNlZCB0byBpbmRpY2F0ZSB0aGF0IHRoZXJlIGlzIG5vIHZhbHVlLiAgSXQgY2FuJ3QgYmUgYXNzaWduZWQgdG8gYSB2ZWN0b3IgYXMgYSB2YWx1ZS4gIEl0IGhhcyBhIGxlbmd0aCBvZiB6ZXJvIGFuZCBhbmQgeW91IGNhbiB0aGluayBvZiBpdCBhcyB0aGUgY2FzZSBvZiBhbiBpdGVtIHRoYXQgaXNuJ3QgdGhlcmUuDQoNCmBgYHtyfQ0KYW5pbWFsWzNdIDwtIE5VTEwNCmFuaW1hbA0KYGBgDQoNCiMjIExpc3RzDQoNCiFbRGlhZ3JhbSBvZiBhIGxpc3RdKGh0dHBzOi8vaGVhcmRsaWJyYXJ5LmdpdGh1Yi5pby9kaWdpdGFsLXNjaG9sYXJzaGlwL3NjcmlwdC9yL2ltYWdlcy9saXN0LWRpYWdyYW0ucG5nKQ0KDQpBICpsaXN0KiBpcyBhbHNvIGEgb25lLWRpbWVuc2lvbmFsIGRhdGEgc3RydWN0dXJlLCBsaWtlIGEgdmVjdG9yLiBIb3dldmVyLCB0aGUgaXRlbXMgaW4gYSBsaXN0IGNhbiBiZSBoZXRlcm9nZW5lb3VzIChkaWZmZXJlbnQgbW9kZXMgb2YgaXRlbXMpLiAgSW4gdGhlIGV4YW1wbGUgYWJvdmUsIHRoZSBsaXN0IGNvbnRhaW5zIHR3byBjaGFyYWN0ZXIgc3RyaW5ncywgb25lIG51bWJlciwgYW5kIG9uZSB2ZWN0b3IuIA0KDQpBc3N1bWluZyB0aGF0IHRoZSBgYW5pbWFsYCB2ZWN0b3IgaXMgaW4geW91ciBlbnZpcm9ubWVudCwgIHRoZSBmb2xsb3dpbmcgY29tbWFuZCB3aWxsIGNyZWF0ZSB0aGUgbGlzdCBkaWFncmFtbWVkIGFib3ZlOg0KDQpgYGB7cn0NCnRoaW5nIDwtIGxpc3QoZnJ1aXRLaW5kPSJhcHBsZSIsIGV1bGVyPTIuNzE4MjgsIHZlY3RvckRhdGE9YW5pbWFsLCBjdXJzZT0iIUAjJCUiKQ0KYGBgDQoNCk5vdGljZSB0aGF0IGluIHRoaXMgbGlzdCBJJ3ZlIGFzc2lnbmVkIHRoZSBpdGVtcyB0byB0aGUgbGlzdCBieSBuYW1lLiAoSXQgaXMgYWxzbyBwb3NzYmlsZSB0byBhc3NpZ24gbmFtZXMgdG8gdmVjdG9yIGl0ZW1zIGJ1dCB0aGF0IGlzIGxlc3MgY29tbW9uLikNCg0KQmVjYXVzZSB0aGUgbGlzdCBpcyBjb21wbGljYXRlZCwgdGhlIGl0ZW1zIGNvbXBvc2luZyBpdCBhcmUgbm90IHNob3duIGluIHRoZSBFbnZpcm9ubWVudCBwYW5lLiAgVG8gc2VlIGFsbCBvZiB0aGUgbGlzdCdzIHBhcnRzLCBJIGNhbiBlaXRoZXIgY2xpY2sgb24gdGhlIGB0aGluZ2AgZW50cnkgaW4gdGhlIEVudmlyb25tZW50IHBhbmUsIG9yIGlzc3VlIHRoZSBjb21tYW5kOg0KDQpgYGB7cn0NClZpZXcodGhpbmcpDQpgYGANCg0KV2hlbiBJIHZpZXcgdGhlIGxpc3QsIHRoZSBkZXNjcmlwdGlvbiBvcGVucyBhcyBhIG5ldyB0YWJsIGluIHRoZSBzYW1lIHBhbmUgYXMgdGhlIGVkaXRvci4NCg0KSXRlbXMgaW4gYSBsaXN0IGNhbiB2aWV3ZWQgYnkgZWl0aGVyIHRoZWlyIHBvc2l0aW9uIG9yIHRoZWlyIG5hbWUuICBJbiBjb250cmFzdCB0byB2ZWN0b3JzLCB0aGUgaW5kZXggaXMgcHV0IGluIGRvdWJsZSBzcXVhcmUgYnJhY2tldHMuDQoNCmBgYHtyfQ0KdGhpbmdbWzNdXQ0KdGhpbmdbWyJldWxlciJdXQ0KYGBgDQoNCkEgY29tbW9ubHkgdXNlZCBzaG9ydGhhbmQgbWV0aG9kIGZvciByZWZlcnJpbmcgdG8gbGlzdCBpdGVtcyBieSB0aGVpciBuYW1lcyBpcyBieSBzZXBhcmF0aW5nIHRoZSBsaXN0IGZyb20gdGhlIG5hbWUgYnkgYSBkb2xsYXIgc2lnbjoNCg0KYGBge3J9DQp0aGluZyRldWxlcg0KdGhpbmckdmVjdG9yRGF0YQ0KYGBgDQoNCiMjIEZhY3RvcnMNCg0KQSAqZmFjdG9yKiBpcyBhIGRhdGEgc3RydWN0dXJlIGZvciBjYXRlZ29yaXppbmcgZGF0YS4gSXRzIG9yaWdpbiBjb21lcyBmcm9tIGV4cGVyaW1lbnRhbCBkZXNpZ24gdGVybWlub2xvZ3kuICBJbiBhbiBleHBlcmltZW50LCBlYWNoIGNhdGVnb3J5IGludG8gd2hpY2ggYW4gZXhwZXJpbWVudGFsIHRyaWFsIGNhbiBmYWxsIGlzIGNhbGxlZCBhICpsZXZlbCouIEEgZmFjdG9yIGNvbnNpc3RzIG9mIGFsbCBvZiB0aGUgcG9zc2libGUgbGV2ZWxzIHRoYXQgYXJlIHVzZWQgdG8gZ3JvdXAgdHJpYWxzIGJhc2VkIG9uIHRoYXQgZmFjdG9yLiBIZXJlIGlzIGFuIGV4YW1wbGUgb2YgYW4gZXhwZXJpbWVudCB3aGVyZSBwbGFudHMgd2VyZSBncm93biBpbiB3ZXQgb3IgZHJ5IHNvaWw6DQoNCnwgd2F0ZXIgZmFjdG9yIHwgaGVpZ2h0IChjbSkgfA0KfC0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS18DQp8IHdldCAgICAgICAgICB8IDI1ICAgICAgICAgIHwNCnwgd2V0ICAgICAgICAgIHwgMjEgICAgICAgICAgfA0KfCBkcnkgICAgICAgICAgfCAxNCAgICAgICAgICB8DQp8IHdldCAgICAgICAgICB8IDEzICAgICAgICAgIHwNCnwgZHJ5ICAgICAgICAgIHwgMTAgICAgICAgICAgfA0KfCB3ZXQgICAgICAgICAgfCAxOCAgICAgICAgICB8DQoNCldlIGNhbiBjcmVhdGUgYSB2ZWN0b3IgY29udGFpbmluZyBhbGwgb2YgdGhlIHdhdGVyIGNvbmRpdGlvbnMgYW5kIGFub3RoZXIgdmVjdG9yIGNvbnRhaW5pbmcgdGhlIGhlaWdodHM6DQoNCmBgYHtyfQ0Kd2F0ZXJDb25kaXRpb25zIDwtIGMoIndldCIsICJ3ZXQiLCAiZHJ5IiwgIndldCIsICJkcnkiLCAid2V0IikNCmhlaWdodCA8LSBjKDI1LCAyMSwgMTQsIDEzLCAxMCwgMTgpDQoNCndhdGVyQ29uZGl0aW9ucw0KaGVpZ2h0DQpgYGANCg0KVG8gY29udmVydCB0aGUgYHdlYXRoZXJDb25kaXRpb25zYCB2ZWN0b3IgaW50byBhIGZhY3RvciwgdXNlIHRoZSBgZmFjdG9yKClgIGZ1bmN0aW9uOg0KDQpgYGB7cn0NCndhdGVyRmFjdG9yIDwtIGZhY3Rvcih3YXRlckNvbmRpdGlvbnMpDQoNCndhdGVyRmFjdG9yDQpgYGANCg0KV2hlbiB3ZSBydW4gdGhlIGNvZGUgY2h1bmsgYWJvdmUsIHdlIGNhbiBzZWUgdHdvIHdheXMgdGhhdCBgd2F0ZXJGYWN0b3JgIGlzIGRpZmZlcmVudCBmcm9tIGB3YXRlckNvbmRpdGlvbnNgOg0KDQotIHRoZSBgd2F0ZXJGYWN0b3JgIGl0ZW1zIGFyZSBub3QgaW4gcXVvdGF0aW9uIG1hcmtzDQotIGJlbG93IHRoZSBsaXN0IG9mIGl0ZW1zIGlzIGEgc3VtbWFyeSBvZiB0aGUgbGV2ZWxzLCBzaG93aW5nIHRoYXQgdGhlcmUgYXJlIG9ubHkgdHdvIGRpZmZlcmVudCBjYXRlZ29yaWVzIGludG8gd2hpY2ggdGhlIGV4cGVyaW1lbnRhbCB0cmlhbHMgY2FuIGJlIGdyb3VwZWQuDQoNCiFbRmFjdG9yIHZzLiB2ZWN0b3IgaW4gdGhlIEVudmlyb25tZW50XShodHRwczovL2hlYXJkbGlicmFyeS5naXRodWIuaW8vZGlnaXRhbC1zY2hvbGFyc2hpcC9zY3JpcHQvci9pbWFnZXMvZmFjdG9yLXZzLXZlY3Rvci5wbmcpDQoNCldlIGNhbiBhbHNvIHNlZSBieSBsb29raW5nIGF0IHRoZSBFbnZpcm9ubWVudCBwYW5lIHRoYXQgYHdhdGVyQ29uZGl0aW9uc2AgaXMgaWRlbnRpZmllZCBhcyBhIHZlY3RvciBvZiBjaGFyYWN0ZXIgc3RyaW5ncywgd2hpbGUgYHdhdGVyRmFjdG9yYCBpcyBpZGVudGlmaWVkIGFzIGEgRmFjdG9yIHdpdGggdHdvIGxldmVscy4gIA0KDQpGYWN0b3JzIGFyZSBzdG9yZWQgYW5kIHByb2Nlc3NlZCBtb3JlIGVmZmljaWVudGx5IHRoYW4gY2hhcmFjdGVycyBhbmQgcGxheSBhIHNwZWNpYWwgcm9sZSBhcyAqZ3JvdXBpbmcgdmFyaWFibGVzKiBpbiBzdGF0aXN0aWNhbCB0ZXN0cyB0aGF0IHJlcXVpcmUgdGhlIGRhdGEgdG8gYmUgcGxhY2VkIGludG8gY2F0ZWdvcmljYWwgZ3JvdXBzLg0KDQojIyBEYXRhIGZyYW1lcw0KDQohW1N0cnVjdHVyZSBvZiBhIGRhdGEgZnJhbWVdKGh0dHBzOi8vaGVhcmRsaWJyYXJ5LmdpdGh1Yi5pby9kaWdpdGFsLXNjaG9sYXJzaGlwL3NjcmlwdC9yL2ltYWdlcy9kYXRhLWZyYW1lLWRpYWdyYW0ucG5nKQ0KDQoqRGF0YSBmcmFtZXMqIGFyZSB0d28gZGltZW5zaW9uYWwgZGF0YSBzdHJ1Y3R1cmVzIGFuZCBhcmUgb25lIG9mIHRoZSBtb3N0IHdpZGVseSB1c2VkIGRhdGEgdHlwZXMgaW4gUi4gT25lIGNhbiB0aGluayBvZiBhIGRhdGEgZnJhbWUgYXMgYSB0YWJsZSB3aXRoIHJvd3MgYW5kIGNvbHVtbnMsIHdpdGggdGhlIHRvcCByb3cgY29udGFpbmluZyBjb2x1bW4gaGVhZGVycyB0aGF0IGFyZSBuYW1lcyBkZXNjcmliaW5nIHdoYXQncyBpbiB0aGUgY29sdW1ucy4NCg0KSXQgaXMgaGVscGZ1bCB0byB0aGluayBvZiBhIGRhdGEgZnJhbWUgYXMgYSBzb3J0IG9mIGNvbWJpbmF0aW9uIG9mIGxpc3RzIGFuZCB2ZWN0b3JzLiBUaGUgdmFsdWVzIGluIGEgcGFydGljdWxhciBjb2x1bW4gYXJlIGxpa2UgYSB2ZWN0b3IsIHdpdGggdGhlIGNvbHVtbiBoZWFkZXIgZm9yIHRoYXQgY29sdW1uIGNvbnRhaW5pbmcgdGhlIHZlY3RvcidzIG5hbWUuIFRoZSBzZXQgb2YgY29sdW1ucyBpcyBsaWtlIGEgbGlzdCB3aG9zZSBpdGVtcyBhcmUgdmVjdG9ycy4NCg0KV2UgY2FuIGFjdHVhbGx5IGNyZWF0ZSBhIGRhdGEgZnJhbWUgYnkgZmlyc3QgY29uc3RydWN0aW5nIGEgdmVjdG9yIGZvciBlYWNoIGNvbHVtbjoNCg0KYGBge3J9DQpncm91cCA8LSBjKCJyZXB0aWxlIiwgImFyYWNobmlkIiwgImFubmVsaWQiLCAiaW5zZWN0IikgICMgdmVjdG9yIG9mIHN0cmluZ3MNCmFuaW1hbCA8LSBjKCJmcm9nIiwgInNwaWRlciIsICJ3b3JtIiwgImJlZSIpDQpudW1iZXJMZWdzIDwtIGMoNCw4LDAsNikgICMgdmVjdG9yIG9mIG51bWJlcnMNCmBgYA0KDQp0aGVuIGxvYWRpbmcgdGhlIHZlY3RvcnMgaW50byB0aGUgZGF0YSBmcmFtZToNCg0KYGBge3J9DQpvcmdhbmlzbUluZm8gPC0gZGF0YS5mcmFtZShncm91cCwgYW5pbWFsLCBudW1iZXJMZWdzKQ0KDQpvcmdhbmlzbUluZm8NCmBgYA0KDQpCeSBkZWZhdWx0LCBSIHdpbGwgdXNlIHRoZSBuYW1lIG9mIGVhY2ggdmVjdG9yIGFzIHRoZSBuYW1lIGZvciB0aGUgY29sdW1uIGluIHRoZSBkYXRhIGZyYW1lLiBFeHBhbmQgdGhlIEVudmlyb25tZW50IHBhbmUgdG8gc2VlIHdoYXQgaGFwcGVuZWQgd2hlbiB5b3UgY3JlYXRlZCB0aGUgdmVjdG9ycyBhbmQgZGF0YSBmcmFtZSwgYW5kIGNsaWNrIG9uIHRoZSBkYXRhIGZyYW1lIGxpc3RpbmcgdG8gc2VlIGl0cyBzdHJ1Y3R1cmUuDQoNCldlIGNhbiByZWZlciB0byBhIHBhcnRpY3VsYXIgY2VsbCBpbiB0aGUgdGFibGUgYnkgbGlzdGluZyBpdHMgcm93IGZvbGxvd2VkIGJ5IGl0cyBjb2x1bW4gaW4gYnJhY2tldHMsIGxpa2UgdGhpczoNCg0KYGBge3J9DQpvcmdhbmlzbUluZm9bMiwxXQ0KYGBgDQoNCkJlY2F1c2UgdGhlIGNvbHVtbnMgb2YgYSBkYXRhIGZyYW1lIGJlaGF2ZSBzb21ld2hhdCBsaWtlIGxpc3QgaXRlbXMsIHRoZSBub3RhdGlvbiBmb3IgcmVmZXJyaW5nIHRvIGxpc3QgaXRlbXMgYnkgbmFtZSAoZG9sbGFyIHNpZ24gZm9sbG93ZWQgYnkgbmFtZSkgY2FuIGFsc28gYmUgdXNlZCB0byByZWZlciB0byBjb2x1bW5zIGluIGEgZGF0YSBmcmFtZToNCg0KYGBge3J9DQpvcmdhbmlzbUluZm8kYW5pbWFsDQpgYGANCg0KYW5kIGl0ZW1zIGluIHRoYXQgY29sdW1uIGNhbiBiZSByZWZlcnJlZCB0byBieSB0aGVpciBwb3NpdGlvbiBmcm9tIHRoZSB0b3Agb2YgdGhlIGNvbHVtbjoNCg0KYGBge3J9DQpvcmdhbmlzbUluZm8kYW5pbWFsWzRdDQpgYGANCg0KT25lIHRoaW5nIHRoYXQgeW91IG1heSBoYXZlIG5vdGljZWQgaXMgdGhhdCB3aGVuIHdlIGxpc3QgdmFsdWVzIGluIHRoZSBkYXRhIGZyYW1lIHRoYXQgY2FtZSBmcm9tIHRoZSB2ZWN0b3Igb2YgY2hhcmFjdGVyIHN0cmluZ3MsIHRoZXkgYXJlIG5vdCBpbiBxdW90ZXMgYW5kIGhhdmUgbGV2ZWxzIGxpc3RlZCBiZWxvdyB0aGVtLiAgVGhpcyBpcyBiZWNhdXNlIHdoZW4gY2hhcmFjdGVyIGRhdGEgdmVjdG9ycyBhcmUgbG9hZGVkIGludG8gYSBkYXRhIGZyYW1lLCB0aGV5IGFyZSBhdXRvbWF0aWNhbGx5IGNvbnZlcnRlZCB0byBmYWN0b3JzLiAgV2UgY2FuIHNlZSB0aGlzIGJ5IGFza2luZyBhYm91dCB0aGUgY2xhc3Mgb2YgdGhlIG9iamVjdHMgd2UgaGF2ZSBiZWVuIHdvcmtpbmcgd2l0aDoNCg0KYGBge3J9DQpjbGFzcyhvcmdhbmlzbUluZm8pDQpjbGFzcyhvcmdhbmlzbUluZm8kYW5pbWFsKQ0KY2xhc3Mob3JnYW5pc21JbmZvJG51bWJlckxlZ3MpDQpgYGANCg0KV2UgY2FuIGFsc28gc2VlIHRoYXQgdGhlIHZhbHVlcyBvZiB0aGUgZmFjdG9yIGFyZSBhY3R1YWxseSBub3Qgc3RvcmVkIGFzIHN0cmluZ3MsIGJ1dCBhcyBudW1iZXJzOg0KDQpgYGB7cn0NCm9yZ2FuaXNtSW5mb1syLDFdDQpjbGFzcyhvcmdhbmlzbUluZm9bMiwxXSkNCm1vZGUob3JnYW5pc21JbmZvWzIsMV0pDQpgYGANCg0KQnkgc3RvcmluZyB0aGUgZmFjdG9ycyBhcyBudW1iZXJzLCB0aGV5IGNhbiBiZSBvcmRlcmVkLiAgVGhlIG9yZGVyIG9mIHRoZSBmYWN0b3JzIGlzIGltcG9ydGFudCBpbiBzb21lIGFuYWx5c2VzLg0KDQojIyBUaWJibGVzDQoNCk1vcmUgcmVjZW50bHksIHRoZSB1c2Ugb2YgUiBoYXMgZXhwYW5kZWQgZmFyIGJleW9uZCBzdGF0aXN0aWNzLCBzbyBhdXRvbWF0aWNhbGx5IHRyYXNmb3JtaW5nIGNoYXJhY3RlciBkYXRhIGludG8gYSBmb3JtIHRoYXQgaXMgb3B0aW1hbCBmb3Igc3RhdGlzdGljcyAoaS5lLiBmYWN0b3JzKSBpcyBubyBsb25nZXIgbmVjZXNzYXJpbHkgZGVzaXJhYmxlIGluIGV2ZXJ5IGNhc2UuIEFub3RoZXIgdHdvLWRpbWVuc2lvbmFsIGRhdGEgc3RydWN0dXJlLCBjYWxsZWQgYSB0aWJibGUsIHdhcyBkZXZlbG9wZWQgdG8gYnJvYWRlbiB0aGUgdXNlIG9mIGRhdGEgZnJhbWVzLiBXaGVuIGRhdGEgYXJlIHJlYWQgaW50byBhIHRpYmJsZSwgdGhlcmUgaXMgbmV2ZXIgYSBjb252ZXJzaW9uIG9mIGRhdGEgdHlwZXMgKHN0cmluZ3MgcmVtYWluIHN0cmluZ3MpLiANCg0KVGliYmxlcyBhcmUgbm90IHBhcnQgb2YgdGhlIHN0YW5kYXJkIFIgZGlzdHJpYnV0aW9uLCBzbyB0byB1c2UgdGhlbSB5b3UgbmVlZCB0byBsb2FkIGEgbGlicmFyeSBjYWxsZWQgYHRpZHl2ZXJzZWAuICBZb3UgY2FuIGNyZWF0ZSBhIHRpYmJsZSB1c2luZyB0aGUgYHRpYmJsZSgpYCBmdW5jdGlvbjoNCg0KYGBge3J9DQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCm9yZ2FuaXNtVGliYmxlIDwtIHRpYmJsZShncm91cCwgYW5pbWFsLCBudW1iZXJMZWdzKQ0KDQpvcmdhbmlzbVRpYmJsZQ0KYGBgDQoNCklmIHlvdSBjb21wYXJlIHRoZSBvdXRwdXQgb2YgdGhlIGBvcmdhbmlzbVRpYmJsZWAgdGliYmxlIHdpdGggdGhlIG91dHB1dCBvZiB0aGUgYG9yZ2FuaXNtSW5mb2AgZGF0YSBmcmFtZSwgdGhlIGNvbHVtbiB0eXBlIGxpc3RlZCBiZWxvdyB0aGUgY29sdW1uIGhlYWRlciBpcyBgY2hyYCBmb3IgdGhlIHRpYmJsZSBhbmQgYGZjdHJgIGZvciB0aGUgZGF0YSBmcmFtZS4gIFNvIHdlIGNhbiBzZWUgdGhhdCB3aGVuIHRoZSB2ZWN0b3JzIHdlcmUgbG9hZGVkIGludG8gdGhlIHRpYmJsZSwgdGhlaXIgY2xhc3Mgd2FzIE5PVCBjaGFuZ2VkLiAgDQoNCmBgYHtyfQ0KY2xhc3Mob3JnYW5pc21UaWJibGUpDQpjbGFzcyhvcmdhbmlzbVRpYmJsZSRhbmltYWwpDQpjbGFzcyhvcmdhbmlzbVRpYmJsZSRudW1iZXJMZWdzKQ0KYGBgDQoNClRoZSBjbGFzcyBvZiB0aGUgdGliYmxlIGlzIGxpc3RlZCBhcyBib3RoIGB0YmxgICh0aWJibGUpIGFuZCBgZGF0YS5mcmFtZWAgKGRhdGEgZnJhbWUpIGJlY2F1c2UgYSB0aWJibGUgaXMgY29uc2lkZXJlZCBhIHNwZWNpYWwga2luZCBvZiBkYXRhIGZyYW1lLiBZb3UgY2FuIGFsc28gc2VlIHRoYXQgdGhlIGFuaW1hbCBjb2x1bW4gcmVtYWluZWQgY2hhcmFjdGVycyBhbmQgd2FzIG5vdCBjb252ZXJ0ZWQgdG8gYSBmYWN0b3IgYXMgd2FzIHRoZSBjYXNlIHdoZW4gd2UgY3JlYXRlZCB0aGUgZGF0YSBmcmFtZS4NCg0KIyBBcHBseWluZyBmdW5jdGlvbnMNCg0KQSBmdW5jdGlvbiBpcyBsaWtlIGEgbWFjaGluZSB0aGF0IHRyYW5zZm9ybXMgd2hhdCB3ZSBwdXQgaW50byBpdCBpbnRvIHNvbWV0aGluZyBkaWZmZXJlbnQgdGhhdCBjb21lcyBvdXQuICBXZSBwYXNzICphcmd1bWVudHMqIGludG8gdGhlIGZ1bmN0aW9uIGFuZCB0aGUgZnVuY3Rpb24gcmV0dXJucyB2YWx1ZXMuDQoNCiFbTnlrYW1wIERRLCAiRnVuY3Rpb24gbWFjaGluZSBmLiIgRnJvbaBNYXRoIEluc2lnaHQuoGh0dHA6Ly9tYXRoaW5zaWdodC5vcmcvaW1hZ2UvZnVuY3Rpb25fbWFjaGluZV9mICBDQyBCWS1OQy1TQV0oaHR0cHM6Ly9tYXRoaW5zaWdodC5vcmcvbWVkaWEvaW1hZ2UvaW1hZ2UvZnVuY3Rpb25fbWFjaGluZV9mLnBuZykNCg0KVGhlcmUgYXJlIG1hbnkgYnVpbHQtaW4gZnVuY3Rpb25zIGluIFIuIEZvciBleGFtcGxlLCBJIGNhbiB0YWtlIHRoZSBzcXVhcmUgcm9vdCBvZiBhIG51bWJlciBieSBwYXNzaW5nIGl0IGludG8gdGhlIGBzcXJ0KClgIGZ1bmN0aW9uLiANCg0KYGBge3J9DQp4IDwtIDINCnNxcnQoeCkNCmBgYA0KSW4gdGhpcyBjYXNlLCBJIHBhc3NlZCBhIHNpbmdsZSBudW1lcmljIHZhbHVlIGludG8gdGhlIGZ1bmN0aW9uIGFuZCBnb3Qgb3V0IGEgc2luZ2xlIHZhbHVlLiAgSG93ZXZlciwgcmVjYWxsIHRoYXQgaW4gUiBhIHZhcmlhYmxlIGNvbnRhaW5pbmcgYSBzaW5nbGUgdmFsdWUgaXMgdGhlIHNhbWUgYXMgYSB2ZWN0b3Igd2l0aCBhIGxlbmd0aCBvZiBvbmUuICBXaGF0IHRoYXQgbWVhbnMgaXMgdGhhdCBmb3IgbWFueSBmdW5jdGlvbnMsIEkgY2FuIHBhc3MgaW4gYSB2ZWN0b3IgY29udGFpbmluZyBtYW55IGl0ZW1zIGFuZCB0aGUgZnVuY3Rpb24gd2lsbCBiZSBhcHBsaWVkIHRvIGV2ZXJ5IGl0ZW0gaW4gdGhlIHZlY3Rvci4gIFRoZSBvdXRwdXQgcmV0dXJuZWQgZnJvbSB0aGUgZnVuY3Rpb24gaXMgYWxzbyBhIHZlY3RvciB3aG9zZSBpdGVtcyBhcmUgaW4gdGhlIHNhbWUgb3JkZXIgYXMgdGhlIGlucHV0IHZlY3Rvci4NCg0KYGBge3J9DQpzcXJ0KG9yZ2FuaXNtSW5mbyRudW1iZXJMZWdzKQ0KYGBgDQoNCk90aGVyIGZ1bmN0aW9ucyBtYXkgZXhwZWN0IGEgdmVjdG9yIGlucHV0LCBidXQgb3V0cHV0IG9ubHkgYSBzaW5nbGUgbnVtYmVyLiBUaGUgYG1lYW4oKWAgZnVuY3Rpb24gdGFrZXMgdGhlIGF2ZXJhZ2Ugb2YgdGhlIGl0ZW1zIGluIGEgdmVjdG9yIGFuZCByZXR1cm5zIGEgc2luZ2xlIHZhbHVlLg0KDQpgYGB7cn0NCm1lYW4ob3JnYW5pc21JbmZvJG51bWJlckxlZ3MpDQpgYGANCg0KUiBkaWZmZXJzIGZyb20gc29tZSBvdGhlciBsYW5ndWFnZXMgbGlrZSBQeXRob24gaW4gdGhhdCBpdCBjYW4gYXV0b21hdGljYWxseSBwZXJmb3JtIGZ1bmN0aW9ucyBvbiBhbiBlbnRpcmUgdmVjdG9yIG9mIHZhbHVlcyB3aXRob3V0IHJlcXVpcmluZyB0aGF0IHRoZSBjb2RlIGl0ZXJhdGUgdGhyb3VnaCBlYWNoIGl0ZW0gaW4gdGhlIHZlY3Rvci4NCg0KSGVyZSBpcyBhbm90aGVyIGV4YW1wbGUgdXNpbmcgdGhlIGBuY2hhcigpYCBmdW5jdGlvbiB0aGF0IGNvdW50cyB0aGUgbnVtYmVyIG9mIGNoYXJhY3RlcnMgaW4gYSBzdHJpbmc6DQoNCmBgYHtyfQ0KIyBsaXN0IHRoZSB3b3JkcyBpbiB0aGUgYW5pbWFsIGNvbHVtbg0Kb3JnYW5pc21UaWJibGUkYW5pbWFsDQoNCiMgbGlzdCB0aGUgY291bnQgb2YgY2hhcmFjdGVycyBpbiBlYWNoIHdvcmQgaW4gdGhlIGNvbHVtbg0KbmNoYXIob3JnYW5pc21UaWJibGUkYW5pbWFsKQ0KYGBgDQoNCg==