What is R?

An interactive programming language and environment focusing on statistics.

How does it work?

At its most basic level, you can open up R at the terminal and type commands.


2+2
[1] 4
sin(pi/2)
[1] 1
cos(pi/2)
[1] 6.123032e-17
(1:10) + 100
 [1] 101 102 103 104 105 106 107 108 109 110

Think of it like a calculator with a lot more features.

We’re going to learn some of those features today.

Why R?

Built around statistics and data analysis(especially omics and bioinformatics), and is one of the most popular languages for this purpose.

  • There are other options that offer drag & drop statistics
    • SPSS
    • STATA
    • Prism
  • But…
    • These platforms lack many statistical features
    • They are not scriptable
      • less reproducible
      • harder to verify results
      • manually repetitive
    • Require clean datasets
    • Cost money
  • R isn’t just a point & click stats program. It’s an open source programming language built by a global community, and gives users access to a huge and constantly growing set of modern statistical tools.

Programming in the age of AI

You do not need to be an expert programmer to use R.

Large Language Models (LLMs) like ChatGPT and Claude can help generate, explain, and debug code quickly – with caveats.

Where AI helps

  • Build simple apps quickly
  • Explain tricky code
  • Suggest syntax
  • Debug errors

Where AI can fail

  • Incorrect code
  • Deleted or changed files
  • Leaked confidential data
  • Overconfidence

By the end of this week, you will know enough R to do simple tasks yourself and more complex tasks with LLM support.

Getting started with R:

There are three parts.

  • R console
    • The place where the code is executed
  • Text editor
    • The place to write your code
  • Where to go for help
    • ‘?’ read the manuals
    • use an AI chatbot

R is a command line program, just like python. You can open it up from your terminal and start coding, but there are better ways to go about this.

Even though it’s possible to work directly in the R console, most people write their code in a separate file using a text editor that at least has syntax highlighting.

Up until very recently, most people learned R by following tutorials, and consulting the built in help documentation. This semester we’re trying a more modern approach utilizing AI.

Installing R

If you want to work locally, you’ll first need to install the R console on your computer.

Choose the appropriate option based on your operating system.

Using R

There are a number of ways to interact with R.

  • You can open R and type directly into the console.

  • You can work with a text editor of your choice and copy/paste lines into the R console.

  • You can use an IDE (Integrated Development Environment ) that automatically links a text editor with the R console.

    • Rstudio is the most popular choice.
  • You can use a cloud based IDE

    • Google Colab. This has everything that a local IDE does, but works on your browser using cloud resources instead of your local computer.

You have to choose one of these to use R, I suggest Rstudio

R packages

Programmers and Data Analysts write code to perform a task or solve a problem. If you encounter the same task again, you shouldn’t have to write everything again.

  • What is the idea?

    • wrap everything needed to perform a task into a collection of files

    • make it easy for you or someone else to use that collection

    • provide documentation on how to use your code

What is an R package?

Packages are the main strength of R! It’s not the fastest language, or easiest to write in, but R has one of the largest ecosystems of statistical and data science libraries of any programming language, with tens of thousands of packages available through open source repositories. (~23k on CRAN, ~2500 on Bioconductor).

How to use them?

  • install them once
  • load them when you need them
install.packages(YOURPACKAGE)

library(YOURPACKAGE)

Files and Folders Basics

What are files?

A file is a saved item on your computer.

Examples of files include:

  • A Word document
  • A photo
  • A spreadsheet
  • A PDF
  • An R script

In R, you may work with files such as:

  • .R files
  • .csv files
  • .xlsx files
  • .txt files

A file usually has a name and a file extension.

Example:

homework1.R

Here:

  • homework1 is the file name
  • .R is the file extension

The file extension tells the computer what kind of file it is.


What are folders?

A folder is a place where files are stored.

Folders help keep your work organized.

For example, you might have a folder called:

R_Projects

Inside that folder, you might have files like:

data.csv
homework1.R
results.txt

Folders can also contain other folders.

For example:

R_Projects
  Week_1
  Week_2
  Data
  Figures

This helps you keep related files together.


Why organization matters

When using R, it is important to know where your files are saved.

R often needs to find files on your computer.

For example, you might ask R to open a data file:

data.csv

But R needs to know where that file is located.

If R cannot find the file, you may get an error.

A common beginner problem is saving a file in one folder, but R is looking in a different folder.

Good organization makes R easier to use.


Saving files

When you save a file, you choose:

  • The file name
  • The folder where it will be stored
  • The file type

For example, when saving an R script, you might save it as:

week1_notes.R

You should save it inside the folder for your class or project.

Example folder:

Documents/R_Class/Week_1

It is helpful to use simple file names.

Good file names:

week1_notes.R
data_cleaning.R
survey_data.csv

Avoid file names like:

My File!!!!.R
data final final version 2.csv
homework#1.R

Simple names without spaces or special characters are easier to use in R.


Moving files around

You can move files from one folder to another.

For example, you might move:

data.csv

from your Downloads folder into your R project folder.

This is often a good idea.

Files downloaded from the internet usually go to the Downloads folder first.

But if you are using the file for an R project, move it into the project folder.

Example:

Before:

Downloads/data.csv

After:

Documents/R_Class/Week_1/data.csv

This makes it easier for R to find the file.


What is the current working directory?

The current working directory is the folder where R is currently looking for files.

You can think of it as R’s current location on your computer.

If R is currently working inside this folder:

Documents/R_Class/Week_1

then R will look there first when you ask it to open a file.

For example:

read.csv("data.csv")

R will look for data.csv inside the current working directory.

If data.csv is not there, R may give an error.


Checking the current working directory

In R, you can check the current working directory with:

getwd()

This means “get working directory.”

It tells you the folder where R is currently looking.

Example output:

"/Users/name/Documents/R_Class/Week_1"

This means R is currently working inside the Week_1 folder.


Setting the working directory

You can change the working directory if needed.

One way is with:

setwd("/Users/name/Documents/R_Class/Week_1")

This tells R to use that folder as the current working directory.

However, beginners should be careful with setwd() because the folder path may be different on different computers.

Simple rule for beginners

Keep related files together.

For each class, homework, or project, create one folder.

Put your R scripts and data files in that folder.

Example:

Homework_1
  homework1.R
  data.csv

Then open the R script in Rstudio and make sure it’s using the proper working directory with getwd() and setwd().


Common beginner errors

Error: R cannot find my file.

Possible reasons:

  • The file is saved in a different folder
  • The file name is spelled differently
  • The file extension is missing or wrong
  • R is using a different working directory
  • The file is still in Downloads

Things to check:

  • Where is the file saved?
  • What is the exact file name?
  • What does getwd() say?
  • Is the file inside the folder R is using?

Key takeaways

A file is a saved item on your computer.

A folder is a place where files are stored.

Files should be named clearly.

Related files should be kept together.

The current working directory is the folder where R is currently looking for files.

Use getwd() to check the current working directory.

The main goal is simple:

Know where your files are, and keep your project files together.

Rstudio Basics

This IDE has a lot of useful features but can be overwhelming at first.

We’re going to spend some time on a live demo to introduce some of the features.

  • Key Points
    • Where is the text editor?
    • Where is the R console?
    • How do you send text from the editor to the console?
    • How do you make a new file?
      • so many options, which to choose?
    • What’s the Environment tab/panel in the top right corner?
    • What’s the panel in the bottom right corner?
      • Files
      • Plots
      • Packages
    • How do you set the current working directory?

Coding Basics

R is a complete programming language. Though it was designed specifically for statistical computing, it can do everything the other complete languages like c++ and python can do.

  • Essential for this course
    • assignments (save stuff into variables)
    • variable access (use the data you’ve stored)
    • mathematical operations (calculator work)
    • reading/writing files (work with permanent storage)
    • visualization (plot your data)
    • calling functions (doing the work)
  • Helpful for real world R use
    • writing functions (organize operations into a reusable form)
    • control (perform operations based on conditions)
    • loops (repeat operations)

We’ll now go through these things in detail.

Assignments

A way to capture the output of an operation so you can use it again.

A result can be stored into a variable with the <- (assignment) or = (equals) operator.

x <-  3848.2834 / 19283.2 + 3762.09271
print(x)
[1] 3762.292
y = x + 100 
print(y)
[1] 3862.292
myname <- "SuperlongFirstnameAndLastName"
print(myname)
[1] "SuperlongFirstnameAndLastName"

type

Variables have a class that represents the type of data they contain. You can find out the type of a variable by using the class() function.

class(x)
[1] "numeric"
class(myname)
[1] "character"

The common types you should be familiar with are

numeric
  • a number
    • a patient’s blood pressure reading (mmHg)
    • a patients weight (in lbs)
integer
  • a whole number
    • a patient’s age (in years)
    • how many children they have
character
  • a string
    • name
    • description of their symptoms
factor
  • a category with a predefined set of levels.
    • place of residence (urban,rural,suburb)
    • their smoking status (never, former, current)
logical
  • a true/false
    • hypertension (yes/no)

vector

R allows you to store a collection of variables of the same type into something called a vector with the c (combine) command.

mynums <- c(1,2,3,4,5)
class(mynums)
[1] "numeric"
print(mynums)
[1] 1 2 3 4 5
mynames <- c("me", "you", "we", "them", "they")
class(mynames)
[1] "character"
print(mynames)
[1] "me"   "you"  "we"   "them" "they"

list

R allows you to store a collection of variables of different types into something called a list


mylist <- list(1,"me", 2, "we", 3)
class(mylist)
[1] "list"
print(mylist)
[[1]]
[1] 1

[[2]]
[1] "me"

[[3]]
[1] 2

[[4]]
[1] "we"

[[5]]
[1] 3

data.frame

R allows you to store a collection of lists or vectors into something called a data.frame.

Think of this like a spreadsheet were each observation gets own row and the variables are stored in the columns. You use the data.frame() function and pass in the vectors or lists that store your data and the column names you want them to appear as.

In the example below, the vector that we made earlier mynums is going to become the first column of the new data.frame and mynames the 2nd column. These 2 columns will be called nums and names in the data.frame. The whole thing is saved into a new variable called mydata.


mydata <- data.frame(nums=mynums, names=mynames)
print(mydata)
  nums names
1    1    me
2    2   you
3    3    we
4    4  them
5    5  they

matrix

A matrix is just like a data.frame except all elements are the same type. When constructing a matrix with the matrix() function, you can specify its dimensions with the ncol and/or nrow parameters.

myvec = c(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16)
print(myvec)
 [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16
mymat = matrix(myvec, ncol=4)
print(mymat)
     [,1] [,2] [,3] [,4]
[1,]    1    5    9   13
[2,]    2    6   10   14
[3,]    3    7   11   15
[4,]    4    8   12   16

naming

You can also assign names to the rows and columns of your vectors, lists, and data.frames and matrices with the names() function. This can make things easier for you while you code and interpret your results.


print(mynums)
[1] 1 2 3 4 5
names(mynums) <- c("a", "b", "c", "d", "e")
print(mynums)
a b c d e 
1 2 3 4 5 
print(mydata)
  nums names
1    1    me
2    2   you
3    3    we
4    4  them
5    5  they
rownames(mydata) <- c("first", "second", "third", "fourth", "fifth")
print(mydata)
       nums names
first     1    me
second    2   you
third     3    we
fourth    4  them
fifth     5  they
rownames(mydata)
[1] "first"  "second" "third"  "fourth" "fifth" 
colnames(mydata)
[1] "nums"  "names"

Variable access

vectors & lists

Now that we know how to store our results, how do we access them?

The elements of a vector can be accessed with [] (single brackets)

mynums
a b c d e 
1 2 3 4 5 
mynums[3]
c 
3 

The elements of a list can be accessed with [[]] (double brackets)

mylist
[[1]]
[1] 1

[[2]]
[1] "me"

[[3]]
[1] 2

[[4]]
[1] "we"

[[5]]
[1] 3
mylist[[3]]
[1] 2
  • gotcha: a list can be a collection of anything, including other lists. If you use single brackets [] on a list, it will return the specified element as a list. This is probably not what you want.
mylist[3]
[[1]]
[1] 2
class(mylist[3])
[1] "list"
mylist[[3]]
[1] 2
class(mylist[[3]])
[1] "numeric"

data.frames

You can access elements of data.frames by their rows and columns with [i,j] single brackets. The i before the , is the row, the j after the , is the column.

mydata

# the 4th row and 2nd column
mydata[4,2]
[1] "them"

You can also specify the location as a combination of numbers and row/col names

mydata["fourth",2]
[1] "them"
mydata[4,"names"]
[1] "them"
mydata["fourth", "names"]
[1] "them"
multiple elements

If you want to get an entire row, leave off the j in the [i,j] command

#get the 3rd row
mydata[3,]

If you want an entire column, leave off the i in the [i,j] command

#get the 2nd column
mydata[,2]
[1] "me"   "you"  "we"   "them" "they"

You can also get columns by using their specific column names with the $ or by using [[]] double brackets.

mydata$nums
[1] 1 2 3 4 5
mydata[["nums"]]
[1] 1 2 3 4 5

In addition to single elements, you can also specify ranges when accessing your data. The : command is shorthand notation for a range.
The command a:b returns a vector starting from a and ending on b. You can use this notation within the [] command to access contiguous ranges of a data.frame or vector.

1:5
[1] 1 2 3 4 5
5:9
[1] 5 6 7 8 9
#first 3 rows, first 2 columns
mydata[1:3, 1:2]

You can specify non contiguous ranges by using a vector within the [] command

#this returns the first 2 columns of the  first and third row
mydata[c(1,3), 1:2]

#this does the same thing
mydata[c("first", "third"), 1:2]

#what does this do?
mydata[c("third", "first"), 1:2]

If you want to remove rows or columns you can put a - (minus) before the accessor indices


#this will return the first two columns of the data.frame, but will skip the first row
mydata[-1, 1:2]
#this will return the first two columns of the data.frame, but will skip the 2nd row
mydata[-2, 1:2]
#this will return the first two columns of the data.frame, but will skip the first 2 rows
mydata[-(1:2), 1:2]

Mathematical Operations

Every language needs support for basic mathematical operations like +, -, *, etc. In R we have support for vector operations which apply the operator across every element of a vector.

Math on a single number

var1 = 5
(var1 * 2)/.3842
[1] 26.02811

Math on a vector of numbers

vec1 = c(1,2,3,4,5)
vec2 = (vec1 * 2)/.3842
vec2
[1]  5.205622 10.411244 15.616866 20.822488 26.028110

R also has support for operations like & logical AND, | logical OR, ! logical NOT and comparisions < less than, >= greater than or equals to, etc…


#which values of vec2 are less than 20?
ix = vec2 < 20
#the result of the comparisons is saved in a logical vector
ix
[1]  TRUE  TRUE  TRUE FALSE FALSE

Often times we will access certain rows of a data.frame based on the result of a logical operation

mydata 
#give me all the rows that are TRUE from the comparison above
mydata[ix,]

You can even call logical operators on the fly within the [i,j] accessors. Combining operators and accessors allows you to perform more interesting and useful commands than just using them alone.

mydata

#give me the `names` column of the rows that have a `num` greater than 2
mydata[mydata$num > 2,"names"]
[1] "we"   "them" "they"

Reading/Writing files

data.frames are the most common form of data you’ll be using in R. If your data comes from a spreadsheet with observations along the rows and the variables along the columns, then it is very straightforward mapping to an R data.frame.

If you want to save a data.frame into a comma separated values(.csv) file, it can be done with write.csv(). This is a function that has 2 main arguments

  • file: The place you want to save it
  • x: the data.frame you want to save
write.csv(file="mydata.csv", x=mydata)

Reading can be done from a .csv with read.csv(). The main argument to this function is:

  • file: The place you want to read the file from

The read.csv()function returns the data.frame that you just read in. You need to remember to save it to a variable.

mydata2 = read.csv(file="mydata.csv")
print(mydata2)
       X nums names
1  first    1    me
2 second    2   you
3  third    3    we
4 fourth    4  them
5  fifth    5  they

Visualization

R is one of the most popular environments for making publication quality graphics today.

Most visualization procedures operate on a data.frame and have some way to tell it which columns you want to look at.

We’ll be dealing with this more in the next lectures, but here is an example of how to call the pairs() function, which shows a scatterplot of every combination of the columns in a data.frame.

pairs(iris[, 1:4], col = iris$Species, pch=19)

Functions

Think of these as a reusable sets of instructions. You give a function it a set of inputs, it applies a procedure, then gives you an output.

It’s a way of organizing your code, so you don’t have to keep copy/pasting the same lines of code and making slight variations in text.

Most of the work you do in R will be done through using functions already implemented in base R or by package developers and loaded through a library() call.

Functions are called by name, with arguments passed between a set of () parentheses. The interesting thing about R is that you can specify the arguments by name or by order, and the environment can figure out which is which.

  • It’s usually best to pass arguments explicitly for clarity.
foo <- function(a, b, c){
  (a + b)/c
}

foo(3,6,1)
[1] 9
foo(a=3,b=6,c=1)
[1] 9
foo(b=6,c=1, 3)
[1] 9
foo(b=3,c=6, 1)
[1] 0.6666667

Control

If statement

Programming often involves the execution of code dependent on the result of an upstream process.

R has control operations that allows us to do this.

The most straightforward to use are the if/else statements.

result <- 7
if (result < 3){
    print("you win")
}else{
    print("you lose")
}
[1] "you lose"

ifelse() function

You can use the ifelse() function return a result that is conditional on the elements of a logical vector.

  • The function takes 3 parameters:
    • test: a logical vector
    • yes: the value to return for true elements of test
    • no: return values for false
vals = c(123,453,233,54,1223,12)
ifelse(vals < 100, "small", "large")
[1] "large" "large" "large" "small" "large" "small"

Loops

for

We’ve already seen that we can wrap up a series of operations into a function.
What if we wanted to apply this function to a 100 columns in a dataset? Would we have to make 100 function calls?

R let’s us run commands over a set of inputs or range using a structure known as a for loop.

for (i in 1:100){
    if (i %% 2==0){
        print("even")
    } else{
        print("odd")
    }
    
}
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"

apply

Another common way of applying a function over the rows or columns of a data.frame is with the apply function.

  • apply is a function that has 3 parameters arguments
    • X: the data.frame you want to work with
    • MARGIN: either 1 or 2.
      • 1 means you want to apply over all the rows.
      • 2 means to apply over all columns
    • FUN: the function you want to apply

sum is a built-in function that adds up all the elements of a vector. Below we’re computing the sum over all the rows and all the columns using apply.


mymat
     [,1] [,2] [,3] [,4]
[1,]    1    5    9   13
[2,]    2    6   10   14
[3,]    3    7   11   15
[4,]    4    8   12   16
#apply over all the rows
apply(mymat, 1, sum)
[1] 28 32 36 40
#apply over all the columns
apply(mymat, 2, sum)
[1] 10 26 42 58

sapply

a function can be applied to each element of a vector with the sapply function.

  • sapply has 2 arguments
    • X: the vector
    • FUN: the function you want to apply
#here we're making a function that returns the negative value of its input.
sillyfunc1 <- function(val){
    -val
}

mydata$nums
[1] 1 2 3 4 5
sapply(mydata$nums, sillyfunc1)
[1] -1 -2 -3 -4 -5

anonymous functions

In any of the apply-style loops you can also define a function on the fly with the anonymous function construct

sapply(mydata$nums, function(val){
    -val
})
[1] -1 -2 -3 -4 -5

by

You can apply a function across a splitting variable with the by function

  • by has 3 arguments
    • data: the values you want to run the function over
    • INDICES: the splitting variable
    • FUN: the function you want to apply
mydata
by(mydata$nums, mydata$nums < 3, sum)
mydata$nums < 3: FALSE
[1] 12
------------------------------------------------------------------------------------ 
mydata$nums < 3: TRUE
[1] 3

Tying it all together with an example:

A statistics instructor wants to know whether students who used chatGPT scored differently on a quiz than students who studied using regular notes.

  • The dataset r_ttest_50_observations.csv contains quiz scores from 50 students:
    • id: a unique identifier for each student
    • group: whether the student used chatgpt or notes
      • control: regular notes
      • treatment: chatgpt
    • value: the student’s quiz score

The research question is:

Is there a statistically significant difference in average quiz scores between the two groups?

Summary

R is great for data analysis.

  • pros:
    • more statistics: a proper test is almost always available through packages
    • more features: especially for visualization
    • scriptable: automate repetitive tasks ensure analysis is reproduceable
  • cons:
    • Not as easy as the drag&drop apps like Prism

How do we deal with the cons?

  • Learn the basics of the language
  • Practice with the homeworks
  • Use AI to get help

What do you need to learn R?

Once you have the right environment setup, learning the language (and statistics) comes smoothly.

  • Locally
    • The R console (install it)
    • A place to write code (Rstudio)
    • A place to get help with code (chatgpt)
  • Cloud based
    • Google Colab does this all in one place.

It’s hard to figure everything out on your own without direction or help. That’s what this first week is for.

Today’s Cheat Sheet

Inspecting objects

Function Purpose Example
print(x) Displays an object in the R console. print(mydata)
class(x) Shows the type or class of an object. class(mynums)

Creating and organizing data

Function Purpose Example
c(...) Combines values into a vector. c(1, 2, 3)
list(...) Creates a list that can contain different types of objects. list(1, "me", 2)
data.frame(...) Creates a table-like data frame. data.frame(nums = mynums, names = mynames)
matrix(...) Creates a matrix whose elements are all the same type. matrix(myvec, ncol = 4)
names(x) Gets or assigns names to the elements of an object. names(mynums) <- c("a", "b", "c")
rownames(x) Gets or assigns row names. rownames(mydata)
colnames(x) Gets or assigns column names. colnames(mydata)

Packages

Function Purpose Example
install.packages() Downloads and installs an R package. This usually only needs to be done once. install.packages("ggplot2")
library() Loads an installed package for the current R session. library(ggplot2)

Files and folders

Function Purpose Example
getwd() Displays R’s current working directory. getwd()
setwd() Changes R’s current working directory. setwd("Documents/R_Class")
read.csv() Reads a CSV file and returns a data frame. read.csv("mydata.csv")
write.csv() Saves a data frame as a CSV file. write.csv(mydata, "mydata.csv")

Writing your own functions

Function or syntax Purpose Example
function(...) Defines a reusable set of instructions. function(x) { x + 1 }

Conditional operations

Function or structure Purpose Example
if / else Runs different code depending on whether a condition is true or false. if (x > 0) print("positive")
ifelse() Returns different values for the TRUE and FALSE elements of a logical vector. ifelse(vals < 100, "small", "large")

Repeating operations

Function or structure Purpose Example
for Repeats code for each value in a sequence or collection. for (i in 1:10) print(i)
apply() Applies a function to each row or column of a matrix or data frame. apply(mymat, 1, sum)
sapply() Applies a function to each element and tries to simplify the result into a vector or matrix. sapply(mynums, sqrt)
by() Applies a function to groups defined by another variable. by(mydata$nums, mydata$group, mean)
sum() Adds together the values in a vector. sum(mynums)

Important indexing syntax

These are operators rather than functions, but they are commonly used throughout R code.

Syntax Purpose Example
[i] Selects one or more elements. mynums[3]
[[i]] Extracts a single element, commonly from a list. mylist[[3]]
[i, j] Selects rows and columns from a data frame or matrix. mydata[4, 2]
$ Selects a data-frame column by name. mydata$nums
: Creates a consecutive sequence of numbers. 1:10
<- Assigns a value to a variable. x <- 5

Common logical operators

Operator Meaning Example
< Less than x < 10
> Greater than x > 10
<= Less than or equal to x <= 10
>= Greater than or equal to x >= 10
== Equal to x == 10
!= Not equal to x != 10
& Logical AND (x > 0) & (x < 10)
| Logical OR (x < 0) | (x > 10)
! Logical NOT !is.na(x)
LS0tDQp0aXRsZTogIkludHJvIHRvIFIiDQpvdXRwdXQ6IA0KICBodG1sX25vdGVib29rOg0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19kZXB0aDogNQ0KICAgIHRvY19mbG9hdDoNCiAgICAgIGNvbGxhcHNlZDogZmFsc2UNCi0tLQ0KDQojIyBXaGF0IGlzIFI/DQoNCkFuIGludGVyYWN0aXZlIHByb2dyYW1taW5nIGxhbmd1YWdlIGFuZCBlbnZpcm9ubWVudCBmb2N1c2luZyBvbiBzdGF0aXN0aWNzLg0KDQojIyMgSG93IGRvZXMgaXQgd29yaz8NCg0KQXQgaXRzIG1vc3QgYmFzaWMgbGV2ZWwsIHlvdSBjYW4gb3BlbiB1cCBSIGF0IHRoZSB0ZXJtaW5hbCBhbmQgdHlwZSBjb21tYW5kcy4NCg0KYGBge3J9DQoNCjIrMg0Kc2luKHBpLzIpDQpjb3MocGkvMikNCigxOjEwKSArIDEwMA0KDQoNCmBgYA0KDQpUaGluayBvZiBpdCBsaWtlIGEgY2FsY3VsYXRvciB3aXRoIGEgbG90IG1vcmUgZmVhdHVyZXMuDQoNCldlJ3JlIGdvaW5nIHRvIGxlYXJuIHNvbWUgb2YgdGhvc2UgZmVhdHVyZXMgdG9kYXkuDQoNCiMjIFdoeSBSPw0KDQpCdWlsdCBhcm91bmQgc3RhdGlzdGljcyBhbmQgZGF0YSBhbmFseXNpcyhlc3BlY2lhbGx5IG9taWNzIGFuZCBiaW9pbmZvcm1hdGljcyksIGFuZCBpcyBvbmUgb2YgdGhlIG1vc3QgcG9wdWxhciBsYW5ndWFnZXMgZm9yIHRoaXMgcHVycG9zZS4NCg0KLSBUaGVyZSBhcmUgb3RoZXIgb3B0aW9ucyB0aGF0IG9mZmVyIGRyYWcgJiBkcm9wIHN0YXRpc3RpY3MNCiAgLSBTUFNTDQogIC0gU1RBVEENCiAgLSBQcmlzbQ0KLSBCdXQuLi4NCiAgLSBUaGVzZSBwbGF0Zm9ybXMgbGFjayBtYW55IHN0YXRpc3RpY2FsIGZlYXR1cmVzDQogIC0gVGhleSBhcmUgbm90IHNjcmlwdGFibGUNCiAgICAtIGxlc3MgcmVwcm9kdWNpYmxlDQogICAgLSBoYXJkZXIgdG8gdmVyaWZ5IHJlc3VsdHMNCiAgICAtIG1hbnVhbGx5IHJlcGV0aXRpdmUNCiAgLSBSZXF1aXJlIGNsZWFuIGRhdGFzZXRzDQogIC0gQ29zdCBtb25leQ0KLSBSIGlzbuKAmXQganVzdCBhIHBvaW50ICYgY2xpY2sgc3RhdHMgcHJvZ3JhbS4gSXTigJlzIGFuIG9wZW4gc291cmNlIHByb2dyYW1taW5nIGxhbmd1YWdlIGJ1aWx0IGJ5IGEgZ2xvYmFsIGNvbW11bml0eSwgYW5kIGdpdmVzIHVzZXJzIGFjY2VzcyB0byBhIGh1Z2UgYW5kIGNvbnN0YW50bHkgZ3Jvd2luZyBzZXQgb2YgbW9kZXJuIHN0YXRpc3RpY2FsIHRvb2xzLg0KDQojIyBQcm9ncmFtbWluZyBpbiB0aGUgYWdlIG9mIEFJDQoNCllvdSBkbyBub3QgbmVlZCB0byBiZSBhbiBleHBlcnQgcHJvZ3JhbW1lciB0byB1c2UgUi4NCg0KTGFyZ2UgTGFuZ3VhZ2UgTW9kZWxzIChMTE1zKSBsaWtlIENoYXRHUFQgYW5kIENsYXVkZSBjYW4gaGVscCBnZW5lcmF0ZSwgZXhwbGFpbiwgYW5kIGRlYnVnIGNvZGUgcXVpY2tseSAtLSB3aXRoIGNhdmVhdHMuDQoNCiMjIyBXaGVyZSBBSSBoZWxwcw0KDQotIEJ1aWxkIHNpbXBsZSBhcHBzIHF1aWNrbHkNCi0gRXhwbGFpbiB0cmlja3kgY29kZQ0KLSBTdWdnZXN0IHN5bnRheA0KLSBEZWJ1ZyBlcnJvcnMNCg0KIyMjIFdoZXJlIEFJIGNhbiBmYWlsDQoNCi0gSW5jb3JyZWN0IGNvZGUNCi0gRGVsZXRlZCBvciBjaGFuZ2VkIGZpbGVzDQotIExlYWtlZCBjb25maWRlbnRpYWwgZGF0YQ0KLSBPdmVyY29uZmlkZW5jZQ0KDQpCeSB0aGUgZW5kIG9mIHRoaXMgd2VlaywgeW91IHdpbGwga25vdyBlbm91Z2ggUiB0byBkbyBzaW1wbGUgdGFza3MgeW91cnNlbGYgYW5kIG1vcmUgY29tcGxleCB0YXNrcyB3aXRoIExMTSBzdXBwb3J0Lg0KDQojIyBHZXR0aW5nIHN0YXJ0ZWQgd2l0aCBSOg0KDQpUaGVyZSBhcmUgdGhyZWUgcGFydHMuDQoNCi0gUiBjb25zb2xlDQogIC0gVGhlIHBsYWNlIHdoZXJlIHRoZSBjb2RlIGlzIGV4ZWN1dGVkDQotIFRleHQgZWRpdG9yDQogIC0gVGhlIHBsYWNlIHRvIHdyaXRlIHlvdXIgY29kZQ0KLSBXaGVyZSB0byBnbyBmb3IgaGVscA0KICAtICc/JyByZWFkIHRoZSBtYW51YWxzDQogIC0gdXNlIGFuIEFJIGNoYXRib3QNCg0KUiBpcyBhIGNvbW1hbmQgbGluZSBwcm9ncmFtLCBqdXN0IGxpa2UgcHl0aG9uLiBZb3UgY2FuIG9wZW4gaXQgdXAgZnJvbSB5b3VyIHRlcm1pbmFsIGFuZCBzdGFydCBjb2RpbmcsIGJ1dCB0aGVyZSBhcmUgYmV0dGVyIHdheXMgdG8gZ28gYWJvdXQgdGhpcy4NCg0KRXZlbiB0aG91Z2ggaXQncyBwb3NzaWJsZSB0byB3b3JrIGRpcmVjdGx5IGluIHRoZSBSIGNvbnNvbGUsIG1vc3QgcGVvcGxlIHdyaXRlIHRoZWlyIGNvZGUgaW4gYSBzZXBhcmF0ZSBmaWxlIHVzaW5nIGEgdGV4dCBlZGl0b3IgdGhhdCBhdCBsZWFzdCBoYXMgc3ludGF4IGhpZ2hsaWdodGluZy4NCg0KVXAgdW50aWwgdmVyeSByZWNlbnRseSwgbW9zdCBwZW9wbGUgbGVhcm5lZCBSIGJ5IGZvbGxvd2luZyB0dXRvcmlhbHMsIGFuZCBjb25zdWx0aW5nIHRoZSBidWlsdCBpbiBoZWxwIGRvY3VtZW50YXRpb24uIFRoaXMgc2VtZXN0ZXIgd2UncmUgdHJ5aW5nIGEgbW9yZSBtb2Rlcm4gYXBwcm9hY2ggdXRpbGl6aW5nIEFJLg0KDQojIyBJbnN0YWxsaW5nIFINCg0KSWYgeW91IHdhbnQgdG8gd29yayBsb2NhbGx5LCB5b3UnbGwgZmlyc3QgbmVlZCB0byBpbnN0YWxsIHRoZSBSIGNvbnNvbGUgb24geW91ciBjb21wdXRlci4NCg0KLSBbUiB3ZWJzaXRlXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy8pDQoNCkNob29zZSB0aGUgYXBwcm9wcmlhdGUgb3B0aW9uIGJhc2VkIG9uIHlvdXIgb3BlcmF0aW5nIHN5c3RlbS4NCg0KIyMgVXNpbmcgUg0KDQpUaGVyZSBhcmUgYSBudW1iZXIgb2Ygd2F5cyB0byBpbnRlcmFjdCB3aXRoIFIuDQoNCi0gWW91IGNhbiBvcGVuIFIgYW5kIHR5cGUgZGlyZWN0bHkgaW50byB0aGUgY29uc29sZS4NCg0KLSBZb3UgY2FuIHdvcmsgd2l0aCBhIHRleHQgZWRpdG9yIG9mIHlvdXIgY2hvaWNlIGFuZCBjb3B5L3Bhc3RlIGxpbmVzIGludG8gdGhlIFIgY29uc29sZS4NCg0KLSBZb3UgY2FuIHVzZSBhbiBJREUgKEludGVncmF0ZWQgRGV2ZWxvcG1lbnQgRW52aXJvbm1lbnQgKSB0aGF0IGF1dG9tYXRpY2FsbHkgbGlua3MgYSB0ZXh0IGVkaXRvciB3aXRoIHRoZSBSIGNvbnNvbGUuDQoNCiAgLSBbUnN0dWRpb10oaHR0cHM6Ly9kb2NzLnBvc2l0LmNvL2lkZS91c2VyLyNyc3R1ZGlvLWlkZS1vc3MtZG93bmxvYWRzKSBpcyB0aGUgbW9zdCBwb3B1bGFyIGNob2ljZS4NCg0KLSBZb3UgY2FuIHVzZSBhIGNsb3VkIGJhc2VkIElERQ0KDQogIC0gW0dvb2dsZSBDb2xhYl0oaHR0cHM6Ly9jb2xhYi5yZXNlYXJjaC5nb29nbGUuY29tLykuIFRoaXMgaGFzIGV2ZXJ5dGhpbmcgdGhhdCBhIGxvY2FsIElERSBkb2VzLCBidXQgd29ya3Mgb24geW91ciBicm93c2VyIHVzaW5nIGNsb3VkIHJlc291cmNlcyBpbnN0ZWFkIG9mIHlvdXIgbG9jYWwgY29tcHV0ZXIuDQoNCllvdSBoYXZlIHRvIGNob29zZSBvbmUgb2YgdGhlc2UgdG8gdXNlIFIsIEkgc3VnZ2VzdCAqKlJzdHVkaW8qKg0KDQojIyBSIHBhY2thZ2VzDQoNClByb2dyYW1tZXJzIGFuZCBEYXRhIEFuYWx5c3RzIHdyaXRlIGNvZGUgdG8gcGVyZm9ybSBhIHRhc2sgb3Igc29sdmUgYSBwcm9ibGVtLiBJZiB5b3UgZW5jb3VudGVyIHRoZSBzYW1lIHRhc2sgYWdhaW4sIHlvdSBzaG91bGRuJ3QgaGF2ZSB0byB3cml0ZSBldmVyeXRoaW5nIGFnYWluLg0KDQotIFdoYXQgaXMgdGhlIGlkZWE/DQoNCiAgLSB3cmFwIGV2ZXJ5dGhpbmcgbmVlZGVkIHRvIHBlcmZvcm0gYSB0YXNrIGludG8gYSBjb2xsZWN0aW9uIG9mIGZpbGVzDQoNCiAgLSBtYWtlIGl0IGVhc3kgZm9yIHlvdSBvciBzb21lb25lIGVsc2UgdG8gdXNlIHRoYXQgY29sbGVjdGlvbg0KDQogIC0gcHJvdmlkZSBkb2N1bWVudGF0aW9uIG9uIGhvdyB0byB1c2UgeW91ciBjb2RlDQoNCiMjIyBXaGF0IGlzIGFuIFIgcGFja2FnZT8NCg0KUGFja2FnZXMgYXJlIHRoZSBtYWluIHN0cmVuZ3RoIG9mIFIhIEl0J3Mgbm90IHRoZSBmYXN0ZXN0IGxhbmd1YWdlLCBvciBlYXNpZXN0IHRvIHdyaXRlIGluLCBidXQgUiBoYXMgb25lIG9mIHRoZSBsYXJnZXN0IGVjb3N5c3RlbXMgb2Ygc3RhdGlzdGljYWwgYW5kIGRhdGEgc2NpZW5jZSBsaWJyYXJpZXMgb2YgYW55IHByb2dyYW1taW5nIGxhbmd1YWdlLCB3aXRoIHRlbnMgb2YgdGhvdXNhbmRzIG9mIHBhY2thZ2VzIGF2YWlsYWJsZSB0aHJvdWdoIG9wZW4gc291cmNlIHJlcG9zaXRvcmllcy4gKFx+MjNrIG9uIENSQU4sIFx+MjUwMCBvbiBCaW9jb25kdWN0b3IpLg0KDQojIyMjIEhvdyB0byB1c2UgdGhlbT8NCg0KLSBpbnN0YWxsIHRoZW0gb25jZQ0KLSBsb2FkIHRoZW0gd2hlbiB5b3UgbmVlZCB0aGVtDQoNCmBgYHtyLCBldmFsPUZ9DQoNCmluc3RhbGwucGFja2FnZXMoWU9VUlBBQ0tBR0UpDQoNCmxpYnJhcnkoWU9VUlBBQ0tBR0UpDQpgYGANCg0KIyMgRmlsZXMgYW5kIEZvbGRlcnMgQmFzaWNzDQoNCiMjIyBXaGF0IGFyZSBmaWxlcz8NCg0KQSBmaWxlIGlzIGEgc2F2ZWQgaXRlbSBvbiB5b3VyIGNvbXB1dGVyLg0KDQpFeGFtcGxlcyBvZiBmaWxlcyBpbmNsdWRlOg0KDQotIEEgV29yZCBkb2N1bWVudA0KLSBBIHBob3RvDQotIEEgc3ByZWFkc2hlZXQNCi0gQSBQREYNCi0gQW4gUiBzY3JpcHQNCg0KSW4gUiwgeW91IG1heSB3b3JrIHdpdGggZmlsZXMgc3VjaCBhczoNCg0KLSBgLlJgIGZpbGVzDQotIGAuY3N2YCBmaWxlcw0KLSBgLnhsc3hgIGZpbGVzDQotIGAudHh0YCBmaWxlcw0KDQpBIGZpbGUgdXN1YWxseSBoYXMgYSBuYW1lIGFuZCBhIGZpbGUgZXh0ZW5zaW9uLg0KDQpFeGFtcGxlOg0KDQpgaG9tZXdvcmsxLlJgDQoNCkhlcmU6DQoNCi0gYGhvbWV3b3JrMWAgaXMgdGhlIGZpbGUgbmFtZQ0KLSBgLlJgIGlzIHRoZSBmaWxlIGV4dGVuc2lvbg0KDQpUaGUgZmlsZSBleHRlbnNpb24gdGVsbHMgdGhlIGNvbXB1dGVyIHdoYXQga2luZCBvZiBmaWxlIGl0IGlzLg0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KIyMjIFdoYXQgYXJlIGZvbGRlcnM/DQoNCkEgZm9sZGVyIGlzIGEgcGxhY2Ugd2hlcmUgZmlsZXMgYXJlIHN0b3JlZC4NCg0KRm9sZGVycyBoZWxwIGtlZXAgeW91ciB3b3JrIG9yZ2FuaXplZC4NCg0KRm9yIGV4YW1wbGUsIHlvdSBtaWdodCBoYXZlIGEgZm9sZGVyIGNhbGxlZDoNCg0KYFJfUHJvamVjdHNgDQoNCkluc2lkZSB0aGF0IGZvbGRlciwgeW91IG1pZ2h0IGhhdmUgZmlsZXMgbGlrZToNCg0KYGBgIHRleHQNCmRhdGEuY3N2DQpob21ld29yazEuUg0KcmVzdWx0cy50eHQNCmBgYA0KDQpGb2xkZXJzIGNhbiBhbHNvIGNvbnRhaW4gb3RoZXIgZm9sZGVycy4NCg0KRm9yIGV4YW1wbGU6DQoNCmBgYCB0ZXh0DQpSX1Byb2plY3RzDQogIFdlZWtfMQ0KICBXZWVrXzINCiAgRGF0YQ0KICBGaWd1cmVzDQpgYGANCg0KVGhpcyBoZWxwcyB5b3Uga2VlcCByZWxhdGVkIGZpbGVzIHRvZ2V0aGVyLg0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KIyMjIFdoeSBvcmdhbml6YXRpb24gbWF0dGVycw0KDQpXaGVuIHVzaW5nIFIsIGl0IGlzIGltcG9ydGFudCB0byBrbm93IHdoZXJlIHlvdXIgZmlsZXMgYXJlIHNhdmVkLg0KDQpSIG9mdGVuIG5lZWRzIHRvIGZpbmQgZmlsZXMgb24geW91ciBjb21wdXRlci4NCg0KRm9yIGV4YW1wbGUsIHlvdSBtaWdodCBhc2sgUiB0byBvcGVuIGEgZGF0YSBmaWxlOg0KDQpgZGF0YS5jc3ZgDQoNCkJ1dCBSIG5lZWRzIHRvIGtub3cgd2hlcmUgdGhhdCBmaWxlIGlzIGxvY2F0ZWQuDQoNCklmIFIgY2Fubm90IGZpbmQgdGhlIGZpbGUsIHlvdSBtYXkgZ2V0IGFuIGVycm9yLg0KDQpBIGNvbW1vbiBiZWdpbm5lciBwcm9ibGVtIGlzIHNhdmluZyBhIGZpbGUgaW4gb25lIGZvbGRlciwgYnV0IFIgaXMgbG9va2luZyBpbiBhIGRpZmZlcmVudCBmb2xkZXIuDQoNCkdvb2Qgb3JnYW5pemF0aW9uIG1ha2VzIFIgZWFzaWVyIHRvIHVzZS4NCg0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCiMjIyBTYXZpbmcgZmlsZXMNCg0KV2hlbiB5b3Ugc2F2ZSBhIGZpbGUsIHlvdSBjaG9vc2U6DQoNCi0gVGhlIGZpbGUgbmFtZQ0KLSBUaGUgZm9sZGVyIHdoZXJlIGl0IHdpbGwgYmUgc3RvcmVkDQotIFRoZSBmaWxlIHR5cGUNCg0KRm9yIGV4YW1wbGUsIHdoZW4gc2F2aW5nIGFuIFIgc2NyaXB0LCB5b3UgbWlnaHQgc2F2ZSBpdCBhczoNCg0KYHdlZWsxX25vdGVzLlJgDQoNCllvdSBzaG91bGQgc2F2ZSBpdCBpbnNpZGUgdGhlIGZvbGRlciBmb3IgeW91ciBjbGFzcyBvciBwcm9qZWN0Lg0KDQpFeGFtcGxlIGZvbGRlcjoNCg0KYERvY3VtZW50cy9SX0NsYXNzL1dlZWtfMWANCg0KSXQgaXMgaGVscGZ1bCB0byB1c2Ugc2ltcGxlIGZpbGUgbmFtZXMuDQoNCkdvb2QgZmlsZSBuYW1lczoNCg0KYGBgIHRleHQNCndlZWsxX25vdGVzLlINCmRhdGFfY2xlYW5pbmcuUg0Kc3VydmV5X2RhdGEuY3N2DQpgYGANCg0KQXZvaWQgZmlsZSBuYW1lcyBsaWtlOg0KDQpgYGAgdGV4dA0KTXkgRmlsZSEhISEuUg0KZGF0YSBmaW5hbCBmaW5hbCB2ZXJzaW9uIDIuY3N2DQpob21ld29yayMxLlINCmBgYA0KDQpTaW1wbGUgbmFtZXMgd2l0aG91dCBzcGFjZXMgb3Igc3BlY2lhbCBjaGFyYWN0ZXJzIGFyZSBlYXNpZXIgdG8gdXNlIGluIFIuDQoNCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQojIyMgTW92aW5nIGZpbGVzIGFyb3VuZA0KDQpZb3UgY2FuIG1vdmUgZmlsZXMgZnJvbSBvbmUgZm9sZGVyIHRvIGFub3RoZXIuDQoNCkZvciBleGFtcGxlLCB5b3UgbWlnaHQgbW92ZToNCg0KYGRhdGEuY3N2YA0KDQpmcm9tIHlvdXIgRG93bmxvYWRzIGZvbGRlciBpbnRvIHlvdXIgUiBwcm9qZWN0IGZvbGRlci4NCg0KVGhpcyBpcyBvZnRlbiBhIGdvb2QgaWRlYS4NCg0KRmlsZXMgZG93bmxvYWRlZCBmcm9tIHRoZSBpbnRlcm5ldCB1c3VhbGx5IGdvIHRvIHRoZSBEb3dubG9hZHMgZm9sZGVyIGZpcnN0Lg0KDQpCdXQgaWYgeW91IGFyZSB1c2luZyB0aGUgZmlsZSBmb3IgYW4gUiBwcm9qZWN0LCBtb3ZlIGl0IGludG8gdGhlIHByb2plY3QgZm9sZGVyLg0KDQpFeGFtcGxlOg0KDQpCZWZvcmU6DQoNCmBEb3dubG9hZHMvZGF0YS5jc3ZgDQoNCkFmdGVyOg0KDQpgRG9jdW1lbnRzL1JfQ2xhc3MvV2Vla18xL2RhdGEuY3N2YA0KDQpUaGlzIG1ha2VzIGl0IGVhc2llciBmb3IgUiB0byBmaW5kIHRoZSBmaWxlLg0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KIyMjIFdoYXQgaXMgdGhlIGN1cnJlbnQgd29ya2luZyBkaXJlY3Rvcnk/DQoNClRoZSBjdXJyZW50IHdvcmtpbmcgZGlyZWN0b3J5IGlzIHRoZSBmb2xkZXIgd2hlcmUgUiBpcyBjdXJyZW50bHkgbG9va2luZyBmb3IgZmlsZXMuDQoNCllvdSBjYW4gdGhpbmsgb2YgaXQgYXMgUuKAmXMgY3VycmVudCBsb2NhdGlvbiBvbiB5b3VyIGNvbXB1dGVyLg0KDQpJZiBSIGlzIGN1cnJlbnRseSB3b3JraW5nIGluc2lkZSB0aGlzIGZvbGRlcjoNCg0KYERvY3VtZW50cy9SX0NsYXNzL1dlZWtfMWANCg0KdGhlbiBSIHdpbGwgbG9vayB0aGVyZSBmaXJzdCB3aGVuIHlvdSBhc2sgaXQgdG8gb3BlbiBhIGZpbGUuDQoNCkZvciBleGFtcGxlOg0KDQpgYGAgcg0KcmVhZC5jc3YoImRhdGEuY3N2IikNCmBgYA0KDQpSIHdpbGwgbG9vayBmb3IgYGRhdGEuY3N2YCBpbnNpZGUgdGhlIGN1cnJlbnQgd29ya2luZyBkaXJlY3RvcnkuDQoNCklmIGBkYXRhLmNzdmAgaXMgbm90IHRoZXJlLCBSIG1heSBnaXZlIGFuIGVycm9yLg0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KIyMjIENoZWNraW5nIHRoZSBjdXJyZW50IHdvcmtpbmcgZGlyZWN0b3J5DQoNCkluIFIsIHlvdSBjYW4gY2hlY2sgdGhlIGN1cnJlbnQgd29ya2luZyBkaXJlY3Rvcnkgd2l0aDoNCg0KYGBgIHINCmdldHdkKCkNCmBgYA0KDQpUaGlzIG1lYW5zIOKAnGdldCB3b3JraW5nIGRpcmVjdG9yeS7igJ0NCg0KSXQgdGVsbHMgeW91IHRoZSBmb2xkZXIgd2hlcmUgUiBpcyBjdXJyZW50bHkgbG9va2luZy4NCg0KRXhhbXBsZSBvdXRwdXQ6DQoNCmBgYCB0ZXh0DQoiL1VzZXJzL25hbWUvRG9jdW1lbnRzL1JfQ2xhc3MvV2Vla18xIg0KYGBgDQoNClRoaXMgbWVhbnMgUiBpcyBjdXJyZW50bHkgd29ya2luZyBpbnNpZGUgdGhlIGBXZWVrXzFgIGZvbGRlci4NCg0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCiMjIyBTZXR0aW5nIHRoZSB3b3JraW5nIGRpcmVjdG9yeQ0KDQpZb3UgY2FuIGNoYW5nZSB0aGUgd29ya2luZyBkaXJlY3RvcnkgaWYgbmVlZGVkLg0KDQpPbmUgd2F5IGlzIHdpdGg6DQoNCmBgYCByDQpzZXR3ZCgiL1VzZXJzL25hbWUvRG9jdW1lbnRzL1JfQ2xhc3MvV2Vla18xIikNCmBgYA0KDQpUaGlzIHRlbGxzIFIgdG8gdXNlIHRoYXQgZm9sZGVyIGFzIHRoZSBjdXJyZW50IHdvcmtpbmcgZGlyZWN0b3J5Lg0KDQpIb3dldmVyLCBiZWdpbm5lcnMgc2hvdWxkIGJlIGNhcmVmdWwgd2l0aCBgc2V0d2QoKWAgYmVjYXVzZSB0aGUgZm9sZGVyIHBhdGggbWF5IGJlIGRpZmZlcmVudCBvbiBkaWZmZXJlbnQgY29tcHV0ZXJzLg0KDQojIyMgU2ltcGxlIHJ1bGUgZm9yIGJlZ2lubmVycw0KDQpLZWVwIHJlbGF0ZWQgZmlsZXMgdG9nZXRoZXIuDQoNCkZvciBlYWNoIGNsYXNzLCBob21ld29yaywgb3IgcHJvamVjdCwgY3JlYXRlIG9uZSBmb2xkZXIuDQoNClB1dCB5b3VyIFIgc2NyaXB0cyBhbmQgZGF0YSBmaWxlcyBpbiB0aGF0IGZvbGRlci4NCg0KRXhhbXBsZToNCg0KYGBgIHRleHQNCkhvbWV3b3JrXzENCiAgaG9tZXdvcmsxLlINCiAgZGF0YS5jc3YNCmBgYA0KDQpUaGVuIG9wZW4gdGhlIFIgc2NyaXB0IGluIFJzdHVkaW8gYW5kIG1ha2Ugc3VyZSBpdCdzIHVzaW5nIHRoZSBwcm9wZXIgd29ya2luZyBkaXJlY3Rvcnkgd2l0aCBgZ2V0d2QoKWAgYW5kIGBzZXR3ZCgpYC4NCg0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCiMjIyBDb21tb24gYmVnaW5uZXIgZXJyb3JzDQoNCkVycm9yOiBSIGNhbm5vdCBmaW5kIG15IGZpbGUuDQoNClBvc3NpYmxlIHJlYXNvbnM6DQoNCi0gVGhlIGZpbGUgaXMgc2F2ZWQgaW4gYSBkaWZmZXJlbnQgZm9sZGVyDQotIFRoZSBmaWxlIG5hbWUgaXMgc3BlbGxlZCBkaWZmZXJlbnRseQ0KLSBUaGUgZmlsZSBleHRlbnNpb24gaXMgbWlzc2luZyBvciB3cm9uZw0KLSBSIGlzIHVzaW5nIGEgZGlmZmVyZW50IHdvcmtpbmcgZGlyZWN0b3J5DQotIFRoZSBmaWxlIGlzIHN0aWxsIGluIERvd25sb2Fkcw0KDQpUaGluZ3MgdG8gY2hlY2s6DQoNCi0gV2hlcmUgaXMgdGhlIGZpbGUgc2F2ZWQ/DQotIFdoYXQgaXMgdGhlIGV4YWN0IGZpbGUgbmFtZT8NCi0gV2hhdCBkb2VzIGBnZXR3ZCgpYCBzYXk/DQotIElzIHRoZSBmaWxlIGluc2lkZSB0aGUgZm9sZGVyIFIgaXMgdXNpbmc/DQoNCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQojIyMgS2V5IHRha2Vhd2F5cw0KDQpBIGZpbGUgaXMgYSBzYXZlZCBpdGVtIG9uIHlvdXIgY29tcHV0ZXIuDQoNCkEgZm9sZGVyIGlzIGEgcGxhY2Ugd2hlcmUgZmlsZXMgYXJlIHN0b3JlZC4NCg0KRmlsZXMgc2hvdWxkIGJlIG5hbWVkIGNsZWFybHkuDQoNClJlbGF0ZWQgZmlsZXMgc2hvdWxkIGJlIGtlcHQgdG9nZXRoZXIuDQoNClRoZSBjdXJyZW50IHdvcmtpbmcgZGlyZWN0b3J5IGlzIHRoZSBmb2xkZXIgd2hlcmUgUiBpcyBjdXJyZW50bHkgbG9va2luZyBmb3IgZmlsZXMuDQoNClVzZSBgZ2V0d2QoKWAgdG8gY2hlY2sgdGhlIGN1cnJlbnQgd29ya2luZyBkaXJlY3RvcnkuDQoNClRoZSBtYWluIGdvYWwgaXMgc2ltcGxlOg0KDQoqKktub3cgd2hlcmUgeW91ciBmaWxlcyBhcmUsIGFuZCBrZWVwIHlvdXIgcHJvamVjdCBmaWxlcyB0b2dldGhlci4qKg0KDQojIyBSc3R1ZGlvIEJhc2ljcw0KDQpUaGlzIElERSBoYXMgYSBsb3Qgb2YgdXNlZnVsIGZlYXR1cmVzIGJ1dCBjYW4gYmUgb3ZlcndoZWxtaW5nIGF0IGZpcnN0Lg0KDQpXZSdyZSBnb2luZyB0byBzcGVuZCBzb21lIHRpbWUgb24gYSBsaXZlIGRlbW8gdG8gaW50cm9kdWNlIHNvbWUgb2YgdGhlIGZlYXR1cmVzLg0KDQotIEtleSBQb2ludHMNCiAgLSBXaGVyZSBpcyB0aGUgdGV4dCBlZGl0b3I/DQogIC0gV2hlcmUgaXMgdGhlIFIgY29uc29sZT8NCiAgLSBIb3cgZG8geW91IHNlbmQgdGV4dCBmcm9tIHRoZSBlZGl0b3IgdG8gdGhlIGNvbnNvbGU/DQogIC0gSG93IGRvIHlvdSBtYWtlIGEgbmV3IGZpbGU/DQogICAgLSBzbyBtYW55IG9wdGlvbnMsIHdoaWNoIHRvIGNob29zZT8NCiAgLSBXaGF0J3MgdGhlIEVudmlyb25tZW50IHRhYi9wYW5lbCBpbiB0aGUgdG9wIHJpZ2h0IGNvcm5lcj8NCiAgLSBXaGF0J3MgdGhlIHBhbmVsIGluIHRoZSBib3R0b20gcmlnaHQgY29ybmVyPw0KICAgIC0gRmlsZXMNCiAgICAtIFBsb3RzDQogICAgLSBQYWNrYWdlcw0KICAtIEhvdyBkbyB5b3Ugc2V0IHRoZSBjdXJyZW50IHdvcmtpbmcgZGlyZWN0b3J5Pw0KDQohW10ocGljX3JzdHVkaW8ucG5nKQ0KDQojIyBDb2RpbmcgQmFzaWNzDQoNClIgaXMgYSAqKmNvbXBsZXRlKiogcHJvZ3JhbW1pbmcgbGFuZ3VhZ2UuIFRob3VnaCBpdCB3YXMgZGVzaWduZWQgc3BlY2lmaWNhbGx5IGZvciBzdGF0aXN0aWNhbCBjb21wdXRpbmcsIGl0IGNhbiBkbyBldmVyeXRoaW5nIHRoZSBvdGhlciAqKmNvbXBsZXRlKiogbGFuZ3VhZ2VzIGxpa2UgYysrIGFuZCBweXRob24gY2FuIGRvLg0KDQotIEVzc2VudGlhbCBmb3IgdGhpcyBjb3Vyc2UNCiAgLSBhc3NpZ25tZW50cyAoc2F2ZSBzdHVmZiBpbnRvIHZhcmlhYmxlcykNCiAgLSB2YXJpYWJsZSBhY2Nlc3MgKHVzZSB0aGUgZGF0YSB5b3UndmUgc3RvcmVkKQ0KICAtIG1hdGhlbWF0aWNhbCBvcGVyYXRpb25zIChjYWxjdWxhdG9yIHdvcmspDQogIC0gcmVhZGluZy93cml0aW5nIGZpbGVzICh3b3JrIHdpdGggcGVybWFuZW50IHN0b3JhZ2UpDQogIC0gdmlzdWFsaXphdGlvbiAocGxvdCB5b3VyIGRhdGEpDQogIC0gY2FsbGluZyBmdW5jdGlvbnMgKGRvaW5nIHRoZSB3b3JrKQ0KLSBIZWxwZnVsIGZvciByZWFsIHdvcmxkIFIgdXNlDQogIC0gd3JpdGluZyBmdW5jdGlvbnMgKG9yZ2FuaXplIG9wZXJhdGlvbnMgaW50byBhIHJldXNhYmxlIGZvcm0pDQogIC0gY29udHJvbCAocGVyZm9ybSBvcGVyYXRpb25zIGJhc2VkIG9uIGNvbmRpdGlvbnMpDQogIC0gbG9vcHMgKHJlcGVhdCBvcGVyYXRpb25zKQ0KDQpXZSdsbCBub3cgZ28gdGhyb3VnaCB0aGVzZSB0aGluZ3MgaW4gZGV0YWlsLg0KDQojIyMgQXNzaWdubWVudHMNCg0KQSB3YXkgdG8gY2FwdHVyZSB0aGUgb3V0cHV0IG9mIGFuIG9wZXJhdGlvbiBzbyB5b3UgY2FuIHVzZSBpdCBhZ2Fpbi4NCg0KQSByZXN1bHQgY2FuIGJlIHN0b3JlZCBpbnRvIGEgKnZhcmlhYmxlKiB3aXRoIHRoZSBgPC1gIChhc3NpZ25tZW50KSBvciBgPWAgKGVxdWFscykgb3BlcmF0b3IuDQoNCmBgYHtyfQ0KeCA8LSAgMzg0OC4yODM0IC8gMTkyODMuMiArIDM3NjIuMDkyNzENCnByaW50KHgpDQp5ID0geCArIDEwMCANCnByaW50KHkpDQoNCm15bmFtZSA8LSAiU3VwZXJsb25nRmlyc3RuYW1lQW5kTGFzdE5hbWUiDQpwcmludChteW5hbWUpDQpgYGANCg0KIyMjIyB0eXBlDQoNClZhcmlhYmxlcyBoYXZlIGEgKmNsYXNzKiB0aGF0IHJlcHJlc2VudHMgdGhlICp0eXBlKiBvZiBkYXRhIHRoZXkgY29udGFpbi4gWW91IGNhbiBmaW5kIG91dCB0aGUgKnR5cGUqIG9mIGEgdmFyaWFibGUgYnkgdXNpbmcgdGhlIGBjbGFzcygpYCBmdW5jdGlvbi4NCg0KYGBge3J9DQpjbGFzcyh4KQ0KY2xhc3MobXluYW1lKQ0KYGBgDQoNClRoZSBjb21tb24gdHlwZXMgeW91IHNob3VsZCBiZSBmYW1pbGlhciB3aXRoIGFyZQ0KDQojIyMjIyBudW1lcmljDQoNCi0gYSBudW1iZXINCiAgLSBhIHBhdGllbnQncyBibG9vZCBwcmVzc3VyZSByZWFkaW5nIChtbUhnKQ0KICAtIGEgcGF0aWVudHMgd2VpZ2h0IChpbiBsYnMpDQoNCiMjIyMjIGludGVnZXINCg0KLSBhIHdob2xlIG51bWJlcg0KICAtIGEgcGF0aWVudCdzIGFnZSAoaW4geWVhcnMpDQogIC0gaG93IG1hbnkgY2hpbGRyZW4gdGhleSBoYXZlDQoNCiMjIyMjIGNoYXJhY3Rlcg0KDQotIGEgc3RyaW5nDQogIC0gbmFtZQ0KICAtIGRlc2NyaXB0aW9uIG9mIHRoZWlyIHN5bXB0b21zDQoNCiMjIyMjIGZhY3Rvcg0KDQotIGEgY2F0ZWdvcnkgd2l0aCBhIHByZWRlZmluZWQgc2V0IG9mIGxldmVscy4NCiAgLSBwbGFjZSBvZiByZXNpZGVuY2UgKHVyYmFuLHJ1cmFsLHN1YnVyYikNCiAgLSB0aGVpciBzbW9raW5nIHN0YXR1cyAobmV2ZXIsIGZvcm1lciwgY3VycmVudCkNCg0KIyMjIyMgbG9naWNhbA0KDQotIGEgdHJ1ZS9mYWxzZQ0KICAtIGh5cGVydGVuc2lvbiAoeWVzL25vKQ0KDQojIyMjIHZlY3Rvcg0KDQpSIGFsbG93cyB5b3UgdG8gc3RvcmUgYSBjb2xsZWN0aW9uIG9mIHZhcmlhYmxlcyBvZiB0aGUgc2FtZSB0eXBlIGludG8gc29tZXRoaW5nIGNhbGxlZCBhICp2ZWN0b3IqIHdpdGggdGhlIGBjYCAoY29tYmluZSkgY29tbWFuZC4NCg0KYGBge3IsIGVjaG8gPSBULCBjb2xsYXBzZT1UfQ0KbXludW1zIDwtIGMoMSwyLDMsNCw1KQ0KY2xhc3MobXludW1zKQ0KcHJpbnQobXludW1zKQ0KDQpteW5hbWVzIDwtIGMoIm1lIiwgInlvdSIsICJ3ZSIsICJ0aGVtIiwgInRoZXkiKQ0KY2xhc3MobXluYW1lcykNCnByaW50KG15bmFtZXMpDQoNCmBgYA0KDQojIyMjIGxpc3QNCg0KUiBhbGxvd3MgeW91IHRvIHN0b3JlIGEgY29sbGVjdGlvbiBvZiB2YXJpYWJsZXMgb2YgZGlmZmVyZW50IHR5cGVzIGludG8gc29tZXRoaW5nIGNhbGxlZCBhICpsaXN0Kg0KDQpgYGB7cn0NCg0KbXlsaXN0IDwtIGxpc3QoMSwibWUiLCAyLCAid2UiLCAzKQ0KY2xhc3MobXlsaXN0KQ0KcHJpbnQobXlsaXN0KQ0KDQpgYGANCg0KIyMjIyBkYXRhLmZyYW1lDQoNClIgYWxsb3dzIHlvdSB0byBzdG9yZSBhIGNvbGxlY3Rpb24gb2YgbGlzdHMgb3IgdmVjdG9ycyBpbnRvIHNvbWV0aGluZyBjYWxsZWQgYSAqZGF0YS5mcmFtZSouDQoNClRoaW5rIG9mIHRoaXMgbGlrZSBhIHNwcmVhZHNoZWV0IHdlcmUgZWFjaCBvYnNlcnZhdGlvbiBnZXRzIG93biByb3cgYW5kIHRoZSB2YXJpYWJsZXMgYXJlIHN0b3JlZCBpbiB0aGUgY29sdW1ucy4gWW91IHVzZSB0aGUgYGRhdGEuZnJhbWUoKWAgZnVuY3Rpb24gYW5kIHBhc3MgaW4gdGhlIHZlY3RvcnMgb3IgbGlzdHMgdGhhdCBzdG9yZSB5b3VyIGRhdGEgYW5kIHRoZSBjb2x1bW4gbmFtZXMgeW91IHdhbnQgdGhlbSB0byBhcHBlYXIgYXMuDQoNCkluIHRoZSBleGFtcGxlIGJlbG93LCB0aGUgdmVjdG9yIHRoYXQgd2UgbWFkZSBlYXJsaWVyIGBteW51bXNgIGlzIGdvaW5nIHRvIGJlY29tZSB0aGUgZmlyc3QgY29sdW1uIG9mIHRoZSBuZXcgZGF0YS5mcmFtZSBhbmQgYG15bmFtZXNgIHRoZSAybmQgY29sdW1uLiBUaGVzZSAyIGNvbHVtbnMgd2lsbCBiZSBjYWxsZWQgYG51bXNgIGFuZCBgbmFtZXNgIGluIHRoZSBkYXRhLmZyYW1lLiBUaGUgd2hvbGUgdGhpbmcgaXMgc2F2ZWQgaW50byBhIG5ldyB2YXJpYWJsZSBjYWxsZWQgYG15ZGF0YWAuDQoNCmBgYHtyfQ0KDQpteWRhdGEgPC0gZGF0YS5mcmFtZShudW1zPW15bnVtcywgbmFtZXM9bXluYW1lcykNCnByaW50KG15ZGF0YSkNCg0KYGBgDQoNCiMjIyMgbWF0cml4DQoNCkEgKiptYXRyaXgqKiBpcyBqdXN0IGxpa2UgYSBkYXRhLmZyYW1lIGV4Y2VwdCBhbGwgZWxlbWVudHMgYXJlIHRoZSBzYW1lIHR5cGUuIFdoZW4gY29uc3RydWN0aW5nIGEgKiptYXRyaXgqKiB3aXRoIHRoZSBgbWF0cml4KClgIGZ1bmN0aW9uLCB5b3UgY2FuIHNwZWNpZnkgaXRzIGRpbWVuc2lvbnMgd2l0aCB0aGUgYG5jb2xgIGFuZC9vciBgbnJvd2AgcGFyYW1ldGVycy4NCg0KYGBge3J9DQpteXZlYyA9IGMoMSwyLDMsNCw1LDYsNyw4LDksMTAsMTEsMTIsMTMsMTQsMTUsMTYpDQpwcmludChteXZlYykNCg0KbXltYXQgPSBtYXRyaXgobXl2ZWMsIG5jb2w9NCkNCnByaW50KG15bWF0KQ0KDQoNCmBgYA0KDQojIyMjIG5hbWluZw0KDQpZb3UgY2FuIGFsc28gYXNzaWduIG5hbWVzIHRvIHRoZSByb3dzIGFuZCBjb2x1bW5zIG9mIHlvdXIgdmVjdG9ycywgbGlzdHMsIGFuZCBkYXRhLmZyYW1lcyBhbmQgbWF0cmljZXMgd2l0aCB0aGUgYG5hbWVzKClgIGZ1bmN0aW9uLiBUaGlzIGNhbiBtYWtlIHRoaW5ncyBlYXNpZXIgZm9yIHlvdSB3aGlsZSB5b3UgY29kZSBhbmQgaW50ZXJwcmV0IHlvdXIgcmVzdWx0cy4NCg0KYGBge3J9DQoNCnByaW50KG15bnVtcykNCm5hbWVzKG15bnVtcykgPC0gYygiYSIsICJiIiwgImMiLCAiZCIsICJlIikNCnByaW50KG15bnVtcykNCg0KcHJpbnQobXlkYXRhKQ0Kcm93bmFtZXMobXlkYXRhKSA8LSBjKCJmaXJzdCIsICJzZWNvbmQiLCAidGhpcmQiLCAiZm91cnRoIiwgImZpZnRoIikNCnByaW50KG15ZGF0YSkNCnJvd25hbWVzKG15ZGF0YSkNCmNvbG5hbWVzKG15ZGF0YSkNCmBgYA0KDQojIyMgVmFyaWFibGUgYWNjZXNzDQoNCiMjIyMgdmVjdG9ycyAmIGxpc3RzDQoNCk5vdyB0aGF0IHdlIGtub3cgaG93IHRvIHN0b3JlIG91ciByZXN1bHRzLCBob3cgZG8gd2UgYWNjZXNzIHRoZW0/DQoNClRoZSBlbGVtZW50cyBvZiBhICoqdmVjdG9yKiogY2FuIGJlIGFjY2Vzc2VkIHdpdGggYFtdYCAoc2luZ2xlIGJyYWNrZXRzKQ0KDQpgYGB7cn0NCm15bnVtcw0KbXludW1zWzNdDQoNCmBgYA0KDQpUaGUgZWxlbWVudHMgb2YgYSAqKmxpc3QqKiBjYW4gYmUgYWNjZXNzZWQgd2l0aCBgW1tdXWAgKGRvdWJsZSBicmFja2V0cykNCg0KYGBge3J9DQpteWxpc3QNCm15bGlzdFtbM11dDQpgYGANCg0KLSAqKmdvdGNoYToqKiBhICoqbGlzdCoqIGNhbiBiZSBhIGNvbGxlY3Rpb24gb2YgYW55dGhpbmcsIGluY2x1ZGluZyBvdGhlciBsaXN0cy4gSWYgeW91IHVzZSBzaW5nbGUgYnJhY2tldHMgYFtdYCBvbiBhIGxpc3QsIGl0IHdpbGwgcmV0dXJuIHRoZSBzcGVjaWZpZWQgZWxlbWVudCBhcyBhIGxpc3QuIFRoaXMgaXMgcHJvYmFibHkgbm90IHdoYXQgeW91IHdhbnQuDQoNCmBgYHtyfQ0KbXlsaXN0WzNdDQpjbGFzcyhteWxpc3RbM10pDQoNCm15bGlzdFtbM11dDQpjbGFzcyhteWxpc3RbWzNdXSkNCg0KYGBgDQoNCiMjIyMgZGF0YS5mcmFtZXMNCg0KWW91IGNhbiBhY2Nlc3MgZWxlbWVudHMgb2YgKipkYXRhLmZyYW1lcyoqIGJ5IHRoZWlyIHJvd3MgYW5kIGNvbHVtbnMgd2l0aCBgW2ksal1gIHNpbmdsZSBicmFja2V0cy4gVGhlIGBpYCBiZWZvcmUgdGhlIGAsYCBpcyB0aGUgcm93LCB0aGUgYGpgIGFmdGVyIHRoZSBgLGAgaXMgdGhlIGNvbHVtbi4NCg0KYGBge3J9DQpteWRhdGENCg0KIyB0aGUgNHRoIHJvdyBhbmQgMm5kIGNvbHVtbg0KbXlkYXRhWzQsMl0NCmBgYA0KDQpZb3UgY2FuIGFsc28gc3BlY2lmeSB0aGUgbG9jYXRpb24gYXMgYSBjb21iaW5hdGlvbiBvZiBudW1iZXJzIGFuZCByb3cvY29sIG5hbWVzDQoNCmBgYHtyfQ0KbXlkYXRhWyJmb3VydGgiLDJdDQpteWRhdGFbNCwibmFtZXMiXQ0KbXlkYXRhWyJmb3VydGgiLCAibmFtZXMiXQ0KYGBgDQoNCiMjIyMjIG11bHRpcGxlIGVsZW1lbnRzDQoNCklmIHlvdSB3YW50IHRvIGdldCBhbiBlbnRpcmUgcm93LCBsZWF2ZSBvZmYgdGhlIGBqYCBpbiB0aGUgYFtpLGpdYCBjb21tYW5kDQoNCmBgYHtyfQ0KI2dldCB0aGUgM3JkIHJvdw0KbXlkYXRhWzMsXQ0KYGBgDQoNCklmIHlvdSB3YW50IGFuIGVudGlyZSBjb2x1bW4sIGxlYXZlIG9mZiB0aGUgYGlgIGluIHRoZSBgW2ksal1gIGNvbW1hbmQNCg0KYGBge3J9DQojZ2V0IHRoZSAybmQgY29sdW1uDQpteWRhdGFbLDJdDQpgYGANCg0KWW91IGNhbiBhbHNvIGdldCBjb2x1bW5zIGJ5IHVzaW5nIHRoZWlyIHNwZWNpZmljIGNvbHVtbiBuYW1lcyB3aXRoIHRoZSBgJGAgb3IgYnkgdXNpbmcgYFtbXV1gIGRvdWJsZSBicmFja2V0cy4NCg0KYGBge3J9DQpteWRhdGEkbnVtcw0KbXlkYXRhW1sibnVtcyJdXQ0KYGBgDQoNCkluIGFkZGl0aW9uIHRvIHNpbmdsZSBlbGVtZW50cywgeW91IGNhbiBhbHNvIHNwZWNpZnkgcmFuZ2VzIHdoZW4gYWNjZXNzaW5nIHlvdXIgZGF0YS4gVGhlIGA6YCBjb21tYW5kIGlzIHNob3J0aGFuZCBub3RhdGlvbiBmb3IgYSByYW5nZS5cDQpUaGUgY29tbWFuZCBgYTpiYCByZXR1cm5zIGEgdmVjdG9yIHN0YXJ0aW5nIGZyb20gYGFgIGFuZCBlbmRpbmcgb24gYGJgLiBZb3UgY2FuIHVzZSB0aGlzIG5vdGF0aW9uIHdpdGhpbiB0aGUgYFtdYCBjb21tYW5kIHRvIGFjY2VzcyBjb250aWd1b3VzIHJhbmdlcyBvZiBhIGRhdGEuZnJhbWUgb3IgdmVjdG9yLg0KDQpgYGB7cn0NCjE6NQ0KNTo5DQoNCiNmaXJzdCAzIHJvd3MsIGZpcnN0IDIgY29sdW1ucw0KbXlkYXRhWzE6MywgMToyXQ0KYGBgDQoNCllvdSBjYW4gc3BlY2lmeSBub24gY29udGlndW91cyByYW5nZXMgYnkgdXNpbmcgYSBgdmVjdG9yYCB3aXRoaW4gdGhlIGBbXWAgY29tbWFuZA0KDQpgYGB7cn0NCiN0aGlzIHJldHVybnMgdGhlIGZpcnN0IDIgY29sdW1ucyBvZiB0aGUgIGZpcnN0IGFuZCB0aGlyZCByb3cNCm15ZGF0YVtjKDEsMyksIDE6Ml0NCg0KI3RoaXMgZG9lcyB0aGUgc2FtZSB0aGluZw0KbXlkYXRhW2MoImZpcnN0IiwgInRoaXJkIiksIDE6Ml0NCg0KI3doYXQgZG9lcyB0aGlzIGRvPw0KbXlkYXRhW2MoInRoaXJkIiwgImZpcnN0IiksIDE6Ml0NCmBgYA0KDQpJZiB5b3Ugd2FudCB0byByZW1vdmUgcm93cyBvciBjb2x1bW5zIHlvdSBjYW4gcHV0IGEgYC1gIChtaW51cyopKiBiZWZvcmUgdGhlIGFjY2Vzc29yIGluZGljZXMNCg0KYGBge3J9DQoNCiN0aGlzIHdpbGwgcmV0dXJuIHRoZSBmaXJzdCB0d28gY29sdW1ucyBvZiB0aGUgZGF0YS5mcmFtZSwgYnV0IHdpbGwgc2tpcCB0aGUgZmlyc3Qgcm93DQpteWRhdGFbLTEsIDE6Ml0NCiN0aGlzIHdpbGwgcmV0dXJuIHRoZSBmaXJzdCB0d28gY29sdW1ucyBvZiB0aGUgZGF0YS5mcmFtZSwgYnV0IHdpbGwgc2tpcCB0aGUgMm5kIHJvdw0KbXlkYXRhWy0yLCAxOjJdDQojdGhpcyB3aWxsIHJldHVybiB0aGUgZmlyc3QgdHdvIGNvbHVtbnMgb2YgdGhlIGRhdGEuZnJhbWUsIGJ1dCB3aWxsIHNraXAgdGhlIGZpcnN0IDIgcm93cw0KbXlkYXRhWy0oMToyKSwgMToyXQ0KYGBgDQoNCiMjIyBNYXRoZW1hdGljYWwgT3BlcmF0aW9ucw0KDQpFdmVyeSBsYW5ndWFnZSBuZWVkcyBzdXBwb3J0IGZvciBiYXNpYyBtYXRoZW1hdGljYWwgb3BlcmF0aW9ucyBsaWtlIGArYCwgYC1gLCBgKmAsIGV0Yy4gSW4gUiB3ZSBoYXZlIHN1cHBvcnQgZm9yICoqdmVjdG9yKiogb3BlcmF0aW9ucyB3aGljaCBhcHBseSB0aGUgb3BlcmF0b3IgYWNyb3NzIGV2ZXJ5IGVsZW1lbnQgb2YgYSB2ZWN0b3IuDQoNCiMjIyMgTWF0aCBvbiBhIHNpbmdsZSBudW1iZXINCg0KYGBge3J9DQp2YXIxID0gNQ0KKHZhcjEgKiAyKS8uMzg0Mg0KYGBgDQoNCiMjIyMgTWF0aCBvbiBhIHZlY3RvciBvZiBudW1iZXJzDQoNCmBgYHtyfQ0KdmVjMSA9IGMoMSwyLDMsNCw1KQ0KdmVjMiA9ICh2ZWMxICogMikvLjM4NDINCnZlYzINCg0KDQpgYGANCg0KUiBhbHNvIGhhcyBzdXBwb3J0IGZvciBvcGVyYXRpb25zIGxpa2UgYCZgICoqbG9naWNhbCBBTkQqKiwgYHxgICoqbG9naWNhbCBPUioqLCBgIWAgKipsb2dpY2FsIE5PVCoqIGFuZCBjb21wYXJpc2lvbnMgYDxgICoqbGVzcyB0aGFuKiosIGA+PWAgKipncmVhdGVyIHRoYW4gb3IgZXF1YWxzIHRvKiosIGV0Yy4uLg0KDQpgYGB7cn0NCg0KI3doaWNoIHZhbHVlcyBvZiB2ZWMyIGFyZSBsZXNzIHRoYW4gMjA/DQppeCA9IHZlYzIgPCAyMA0KI3RoZSByZXN1bHQgb2YgdGhlIGNvbXBhcmlzb25zIGlzIHNhdmVkIGluIGEgbG9naWNhbCB2ZWN0b3INCml4DQoNCmBgYA0KDQpPZnRlbiB0aW1lcyB3ZSB3aWxsIGFjY2VzcyBjZXJ0YWluIHJvd3Mgb2YgYSBkYXRhLmZyYW1lIGJhc2VkIG9uIHRoZSByZXN1bHQgb2YgYSBsb2dpY2FsIG9wZXJhdGlvbg0KDQpgYGB7cn0NCm15ZGF0YSANCiNnaXZlIG1lIGFsbCB0aGUgcm93cyB0aGF0IGFyZSBUUlVFIGZyb20gdGhlIGNvbXBhcmlzb24gYWJvdmUNCm15ZGF0YVtpeCxdDQpgYGANCg0KWW91IGNhbiBldmVuIGNhbGwgbG9naWNhbCBvcGVyYXRvcnMgKm9uIHRoZSBmbHkqIHdpdGhpbiB0aGUgYFtpLGpdYCBhY2Nlc3NvcnMuIENvbWJpbmluZyBvcGVyYXRvcnMgYW5kIGFjY2Vzc29ycyBhbGxvd3MgeW91IHRvIHBlcmZvcm0gbW9yZSBpbnRlcmVzdGluZyBhbmQgdXNlZnVsIGNvbW1hbmRzIHRoYW4ganVzdCB1c2luZyB0aGVtIGFsb25lLg0KDQpgYGB7cn0NCm15ZGF0YQ0KDQojZ2l2ZSBtZSB0aGUgYG5hbWVzYCBjb2x1bW4gb2YgdGhlIHJvd3MgdGhhdCBoYXZlIGEgYG51bWAgZ3JlYXRlciB0aGFuIDINCm15ZGF0YVtteWRhdGEkbnVtID4gMiwibmFtZXMiXQ0KYGBgDQoNCiMjIyBSZWFkaW5nL1dyaXRpbmcgZmlsZXMNCg0KKipkYXRhLmZyYW1lcyoqIGFyZSB0aGUgbW9zdCBjb21tb24gZm9ybSBvZiBkYXRhIHlvdSdsbCBiZSB1c2luZyBpbiBSLiBJZiB5b3VyIGRhdGEgY29tZXMgZnJvbSBhIHNwcmVhZHNoZWV0IHdpdGggb2JzZXJ2YXRpb25zIGFsb25nIHRoZSByb3dzIGFuZCB0aGUgdmFyaWFibGVzIGFsb25nIHRoZSBjb2x1bW5zLCB0aGVuIGl0IGlzIHZlcnkgc3RyYWlnaHRmb3J3YXJkIG1hcHBpbmcgdG8gYW4gUiBkYXRhLmZyYW1lLg0KDQpJZiB5b3Ugd2FudCB0byBzYXZlIGEgKipkYXRhLmZyYW1lKiogaW50byBhIGNvbW1hIHNlcGFyYXRlZCB2YWx1ZXMoLmNzdikgZmlsZSwgaXQgY2FuIGJlIGRvbmUgd2l0aCBgd3JpdGUuY3N2KClgLiBUaGlzIGlzIGEgZnVuY3Rpb24gdGhhdCBoYXMgMiBtYWluIGFyZ3VtZW50cw0KDQoNCi0gZmlsZTogVGhlIHBsYWNlIHlvdSB3YW50IHRvIHNhdmUgaXQNCi0geDogdGhlIGRhdGEuZnJhbWUgeW91IHdhbnQgdG8gc2F2ZQ0KDQpgYGB7cn0NCndyaXRlLmNzdihmaWxlPSJteWRhdGEuY3N2IiwgeD1teWRhdGEpDQoNCmBgYA0KDQpSZWFkaW5nIGNhbiBiZSBkb25lIGZyb20gYSAuY3N2IHdpdGggYHJlYWQuY3N2KClgLiBUaGUgbWFpbiBhcmd1bWVudCB0byB0aGlzIGZ1bmN0aW9uIGlzOg0KDQotIGZpbGU6IFRoZSBwbGFjZSB5b3Ugd2FudCB0byByZWFkIHRoZSBmaWxlIGZyb20NCg0KVGhlIGByZWFkLmNzdigpYGZ1bmN0aW9uIHJldHVybnMgdGhlIGRhdGEuZnJhbWUgdGhhdCB5b3UganVzdCByZWFkIGluLiBZb3UgbmVlZCB0byByZW1lbWJlciB0byBzYXZlIGl0IHRvIGEgdmFyaWFibGUuDQoNCmBgYHtyfQ0KbXlkYXRhMiA9IHJlYWQuY3N2KGZpbGU9Im15ZGF0YS5jc3YiKQ0KcHJpbnQobXlkYXRhMikNCmBgYA0KDQojIyMgVmlzdWFsaXphdGlvbg0KDQpSIGlzIG9uZSBvZiB0aGUgbW9zdCBwb3B1bGFyIGVudmlyb25tZW50cyBmb3IgbWFraW5nIHB1YmxpY2F0aW9uIHF1YWxpdHkgZ3JhcGhpY3MgdG9kYXkuDQoNCk1vc3QgdmlzdWFsaXphdGlvbiBwcm9jZWR1cmVzIG9wZXJhdGUgb24gYSAqZGF0YS5mcmFtZSogYW5kIGhhdmUgc29tZSB3YXkgdG8gdGVsbCBpdCB3aGljaCBjb2x1bW5zIHlvdSB3YW50IHRvIGxvb2sgYXQuDQoNCldlJ2xsIGJlIGRlYWxpbmcgd2l0aCB0aGlzIG1vcmUgaW4gdGhlIG5leHQgbGVjdHVyZXMsIGJ1dCBoZXJlIGlzIGFuIGV4YW1wbGUgb2YgaG93IHRvIGNhbGwgdGhlIGBwYWlycygpYCBmdW5jdGlvbiwgd2hpY2ggc2hvd3MgYSBzY2F0dGVycGxvdCBvZiBldmVyeSBjb21iaW5hdGlvbiBvZiB0aGUgY29sdW1ucyBpbiBhIGRhdGEuZnJhbWUuDQoNCmBgYHtyfQ0KcGFpcnMoaXJpc1ssIDE6NF0sIGNvbCA9IGlyaXMkU3BlY2llcywgcGNoPTE5KQ0KYGBgDQoNCiMjIyBGdW5jdGlvbnMNCg0KVGhpbmsgb2YgdGhlc2UgYXMgYSByZXVzYWJsZSBzZXRzIG9mIGluc3RydWN0aW9ucy4gWW91IGdpdmUgYSBmdW5jdGlvbiBpdCBhIHNldCBvZiBpbnB1dHMsIGl0IGFwcGxpZXMgYSBwcm9jZWR1cmUsIHRoZW4gZ2l2ZXMgeW91IGFuIG91dHB1dC4NCg0KSXQncyBhIHdheSBvZiBvcmdhbml6aW5nIHlvdXIgY29kZSwgc28geW91IGRvbid0IGhhdmUgdG8ga2VlcCBjb3B5L3Bhc3RpbmcgdGhlIHNhbWUgbGluZXMgb2YgY29kZSBhbmQgbWFraW5nIHNsaWdodCB2YXJpYXRpb25zIGluIHRleHQuDQoNCk1vc3Qgb2YgdGhlIHdvcmsgeW91IGRvIGluIFIgd2lsbCBiZSBkb25lIHRocm91Z2ggdXNpbmcgZnVuY3Rpb25zIGFscmVhZHkgaW1wbGVtZW50ZWQgaW4gYmFzZSBSIG9yIGJ5IHBhY2thZ2UgZGV2ZWxvcGVycyBhbmQgbG9hZGVkIHRocm91Z2ggYSBgbGlicmFyeSgpYCBjYWxsLg0KDQpGdW5jdGlvbnMgYXJlIGNhbGxlZCBieSBuYW1lLCB3aXRoIGFyZ3VtZW50cyBwYXNzZWQgYmV0d2VlbiBhIHNldCBvZiBgKClgIHBhcmVudGhlc2VzLiBUaGUgaW50ZXJlc3RpbmcgdGhpbmcgYWJvdXQgUiBpcyB0aGF0IHlvdSBjYW4gc3BlY2lmeSB0aGUgYXJndW1lbnRzIGJ5IG5hbWUgb3IgYnkgb3JkZXIsIGFuZCB0aGUgZW52aXJvbm1lbnQgY2FuIGZpZ3VyZSBvdXQgd2hpY2ggaXMgd2hpY2guDQoNCi0gSXQncyB1c3VhbGx5IGJlc3QgdG8gcGFzcyBhcmd1bWVudHMgZXhwbGljaXRseSBmb3IgY2xhcml0eS4NCg0KYGBge3J9DQpmb28gPC0gZnVuY3Rpb24oYSwgYiwgYyl7DQogIChhICsgYikvYw0KfQ0KDQpmb28oMyw2LDEpDQpmb28oYT0zLGI9NixjPTEpDQpmb28oYj02LGM9MSwgMykNCmZvbyhiPTMsYz02LCAxKQ0KDQpgYGANCg0KIyMjIH5+Q29udHJvbH5+DQoNCiMjIyMgYElmYCBzdGF0ZW1lbnQNCg0KUHJvZ3JhbW1pbmcgb2Z0ZW4gaW52b2x2ZXMgdGhlIGV4ZWN1dGlvbiBvZiBjb2RlIGRlcGVuZGVudCBvbiB0aGUgcmVzdWx0IG9mIGFuIHVwc3RyZWFtIHByb2Nlc3MuDQoNClIgaGFzIGNvbnRyb2wgb3BlcmF0aW9ucyB0aGF0IGFsbG93cyB1cyB0byBkbyB0aGlzLg0KDQpUaGUgbW9zdCBzdHJhaWdodGZvcndhcmQgdG8gdXNlIGFyZSB0aGUgKmlmL2Vsc2UqIHN0YXRlbWVudHMuDQoNCmBgYHtyfQ0KcmVzdWx0IDwtIDcNCmlmIChyZXN1bHQgPCAzKXsNCiAgICBwcmludCgieW91IHdpbiIpDQp9ZWxzZXsNCiAgICBwcmludCgieW91IGxvc2UiKQ0KfQ0KYGBgDQoNCiMjIyMgYGlmZWxzZSgpYCBmdW5jdGlvbg0KDQpZb3UgY2FuIHVzZSB0aGUgYGlmZWxzZSgpYCBmdW5jdGlvbiByZXR1cm4gYSByZXN1bHQgdGhhdCBpcyBjb25kaXRpb25hbCBvbiB0aGUgZWxlbWVudHMgb2YgYSBsb2dpY2FsIHZlY3Rvci4NCg0KLSBUaGUgZnVuY3Rpb24gdGFrZXMgMyBwYXJhbWV0ZXJzOg0KICAtIHRlc3Q6IGEgbG9naWNhbCB2ZWN0b3INCiAgLSB5ZXM6IHRoZSB2YWx1ZSB0byByZXR1cm4gZm9yIHRydWUgZWxlbWVudHMgb2YgdGVzdA0KICAtIG5vOiByZXR1cm4gdmFsdWVzIGZvciBmYWxzZQ0KDQpgYGB7cn0NCnZhbHMgPSBjKDEyMyw0NTMsMjMzLDU0LDEyMjMsMTIpDQppZmVsc2UodmFscyA8IDEwMCwgInNtYWxsIiwgImxhcmdlIikNCmBgYA0KDQojIyMgfn5Mb29wc35+DQoNCiMjIyMgZm9yDQoNCldlJ3ZlIGFscmVhZHkgc2VlbiB0aGF0IHdlIGNhbiB3cmFwIHVwIGEgc2VyaWVzIG9mIG9wZXJhdGlvbnMgaW50byBhIGZ1bmN0aW9uLlwNCldoYXQgaWYgd2Ugd2FudGVkIHRvIGFwcGx5IHRoaXMgZnVuY3Rpb24gdG8gYSAxMDAgY29sdW1ucyBpbiBhIGRhdGFzZXQ/IFdvdWxkIHdlIGhhdmUgdG8gbWFrZSAxMDAgZnVuY3Rpb24gY2FsbHM/DQoNClIgbGV0J3MgdXMgcnVuIGNvbW1hbmRzIG92ZXIgYSBzZXQgb2YgaW5wdXRzIG9yIHJhbmdlIHVzaW5nIGEgc3RydWN0dXJlIGtub3duIGFzIGEgYGZvciBsb29wYC4NCg0KYGBge3J9DQpmb3IgKGkgaW4gMToxMDApew0KICAgIGlmIChpICUlIDI9PTApew0KICAgICAgICBwcmludCgiZXZlbiIpDQogICAgfSBlbHNlew0KICAgICAgICBwcmludCgib2RkIikNCiAgICB9DQogICAgDQp9DQpgYGANCg0KIyMjIyBhcHBseQ0KDQpBbm90aGVyIGNvbW1vbiB3YXkgb2YgYXBwbHlpbmcgYSBmdW5jdGlvbiBvdmVyIHRoZSByb3dzIG9yIGNvbHVtbnMgb2YgYSBkYXRhLmZyYW1lIGlzIHdpdGggdGhlIGBhcHBseWAgZnVuY3Rpb24uDQoNCi0gYGFwcGx5YCBpcyBhIGZ1bmN0aW9uIHRoYXQgaGFzIDMgcGFyYW1ldGVycyBhcmd1bWVudHMNCiAgLSBYOiB0aGUgZGF0YS5mcmFtZSB5b3Ugd2FudCB0byB3b3JrIHdpdGgNCiAgLSBNQVJHSU46IGVpdGhlciAxIG9yIDIuDQogICAgLSAxIG1lYW5zIHlvdSB3YW50IHRvIGFwcGx5IG92ZXIgYWxsIHRoZSByb3dzLlwNCiAgICAtIDIgbWVhbnMgdG8gYXBwbHkgb3ZlciBhbGwgY29sdW1ucw0KICAtIEZVTjogdGhlIGZ1bmN0aW9uIHlvdSB3YW50IHRvIGFwcGx5DQoNCmBzdW1gIGlzIGEgYnVpbHQtaW4gZnVuY3Rpb24gdGhhdCBhZGRzIHVwIGFsbCB0aGUgZWxlbWVudHMgb2YgYSB2ZWN0b3IuIEJlbG93IHdlJ3JlIGNvbXB1dGluZyB0aGUgc3VtIG92ZXIgYWxsIHRoZSByb3dzIGFuZCBhbGwgdGhlIGNvbHVtbnMgdXNpbmcgYGFwcGx5YC4NCg0KYGBge3J9DQoNCm15bWF0DQojYXBwbHkgb3ZlciBhbGwgdGhlIHJvd3MNCmFwcGx5KG15bWF0LCAxLCBzdW0pDQojYXBwbHkgb3ZlciBhbGwgdGhlIGNvbHVtbnMNCmFwcGx5KG15bWF0LCAyLCBzdW0pDQpgYGANCg0KIyMjIyBzYXBwbHkNCg0KYSBmdW5jdGlvbiBjYW4gYmUgYXBwbGllZCB0byBlYWNoIGVsZW1lbnQgb2YgYSB2ZWN0b3Igd2l0aCB0aGUgYHNhcHBseWAgZnVuY3Rpb24uDQoNCi0gYHNhcHBseWAgaGFzIDIgYXJndW1lbnRzDQogIC0gWDogdGhlIHZlY3Rvcg0KICAtIEZVTjogdGhlIGZ1bmN0aW9uIHlvdSB3YW50IHRvIGFwcGx5DQoNCmBgYHtyfQ0KI2hlcmUgd2UncmUgbWFraW5nIGEgZnVuY3Rpb24gdGhhdCByZXR1cm5zIHRoZSBuZWdhdGl2ZSB2YWx1ZSBvZiBpdHMgaW5wdXQuDQpzaWxseWZ1bmMxIDwtIGZ1bmN0aW9uKHZhbCl7DQogICAgLXZhbA0KfQ0KDQpteWRhdGEkbnVtcw0Kc2FwcGx5KG15ZGF0YSRudW1zLCBzaWxseWZ1bmMxKQ0KDQoNCmBgYA0KDQojIyMjIGFub255bW91cyBmdW5jdGlvbnMNCg0KSW4gYW55IG9mIHRoZSAqYXBwbHkqLXN0eWxlIGxvb3BzIHlvdSBjYW4gYWxzbyBkZWZpbmUgYSBmdW5jdGlvbiBvbiB0aGUgZmx5IHdpdGggdGhlICphbm9ueW1vdXMgZnVuY3Rpb24qIGNvbnN0cnVjdA0KDQpgYGB7cn0NCnNhcHBseShteWRhdGEkbnVtcywgZnVuY3Rpb24odmFsKXsNCiAgICAtdmFsDQp9KQ0KYGBgDQoNCiMjIyMgYnkNCg0KWW91IGNhbiBhcHBseSBhIGZ1bmN0aW9uIGFjcm9zcyBhIHNwbGl0dGluZyB2YXJpYWJsZSB3aXRoIHRoZSBgYnlgIGZ1bmN0aW9uDQoNCi0gYGJ5YCBoYXMgMyBhcmd1bWVudHMNCiAgLSBkYXRhOiB0aGUgdmFsdWVzIHlvdSB3YW50IHRvIHJ1biB0aGUgZnVuY3Rpb24gb3Zlcg0KICAtIElORElDRVM6IHRoZSBzcGxpdHRpbmcgdmFyaWFibGUNCiAgLSBGVU46IHRoZSBmdW5jdGlvbiB5b3Ugd2FudCB0byBhcHBseQ0KDQpgYGB7cn0NCm15ZGF0YQ0KYnkobXlkYXRhJG51bXMsIG15ZGF0YSRudW1zIDwgMywgc3VtKQ0KYGBgDQoNCiMjIFR5aW5nIGl0IGFsbCB0b2dldGhlciB3aXRoIGFuIGV4YW1wbGU6DQoNCkEgc3RhdGlzdGljcyBpbnN0cnVjdG9yIHdhbnRzIHRvIGtub3cgd2hldGhlciBzdHVkZW50cyB3aG8gdXNlZCBjaGF0R1BUIHNjb3JlZCBkaWZmZXJlbnRseSBvbiBhIHF1aXogdGhhbiBzdHVkZW50cyB3aG8gc3R1ZGllZCB1c2luZyByZWd1bGFyIG5vdGVzLg0KDQotIFRoZSBkYXRhc2V0IHJfdHRlc3RfNTBfb2JzZXJ2YXRpb25zLmNzdiBjb250YWlucyBxdWl6IHNjb3JlcyBmcm9tIDUwIHN0dWRlbnRzOg0KICAtIGlkOiBhIHVuaXF1ZSBpZGVudGlmaWVyIGZvciBlYWNoIHN0dWRlbnQNCiAgLSBncm91cDogd2hldGhlciB0aGUgc3R1ZGVudCB1c2VkIGNoYXRncHQgb3Igbm90ZXMNCiAgICAtIGNvbnRyb2w6IHJlZ3VsYXIgbm90ZXMNCiAgICAtIHRyZWF0bWVudDogY2hhdGdwdA0KICAtIHZhbHVlOiB0aGUgc3R1ZGVudCdzIHF1aXogc2NvcmUNCg0KVGhlIHJlc2VhcmNoIHF1ZXN0aW9uIGlzOg0KDQpJcyB0aGVyZSBhIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSBpbiBhdmVyYWdlIHF1aXogc2NvcmVzIGJldHdlZW4gdGhlIHR3byBncm91cHM/DQoNCiMjIFN1bW1hcnkNCg0KUiBpcyBncmVhdCBmb3IgZGF0YSBhbmFseXNpcy4NCg0KLSBwcm9zOg0KICAtIG1vcmUgc3RhdGlzdGljczogYSBwcm9wZXIgdGVzdCBpcyBhbG1vc3QgYWx3YXlzIGF2YWlsYWJsZSB0aHJvdWdoIHBhY2thZ2VzDQogIC0gbW9yZSBmZWF0dXJlczogZXNwZWNpYWxseSBmb3IgdmlzdWFsaXphdGlvbg0KICAtIHNjcmlwdGFibGU6IGF1dG9tYXRlIHJlcGV0aXRpdmUgdGFza3MgZW5zdXJlIGFuYWx5c2lzIGlzIHJlcHJvZHVjZWFibGUNCi0gY29uczoNCiAgLSBOb3QgYXMgZWFzeSBhcyB0aGUgZHJhZyZkcm9wIGFwcHMgbGlrZSBQcmlzbQ0KDQojIyBIb3cgZG8gd2UgZGVhbCB3aXRoIHRoZSBjb25zPw0KDQotIExlYXJuIHRoZSBiYXNpY3Mgb2YgdGhlIGxhbmd1YWdlDQotIFByYWN0aWNlIHdpdGggdGhlIGhvbWV3b3Jrcw0KLSBVc2UgQUkgdG8gZ2V0IGhlbHANCg0KIyMgV2hhdCBkbyB5b3UgbmVlZCB0byBsZWFybiBSPw0KDQpPbmNlIHlvdSBoYXZlIHRoZSByaWdodCBlbnZpcm9ubWVudCBzZXR1cCwgbGVhcm5pbmcgdGhlIGxhbmd1YWdlIChhbmQgc3RhdGlzdGljcykgY29tZXMgc21vb3RobHkuDQoNCi0gTG9jYWxseQ0KICAtIFRoZSBSIGNvbnNvbGUgKGluc3RhbGwgaXQpDQogIC0gQSBwbGFjZSB0byB3cml0ZSBjb2RlIChSc3R1ZGlvKQ0KICAtIEEgcGxhY2UgdG8gZ2V0IGhlbHAgd2l0aCBjb2RlIChjaGF0Z3B0KQ0KLSBDbG91ZCBiYXNlZA0KICAtIEdvb2dsZSBDb2xhYiBkb2VzIHRoaXMgYWxsIGluIG9uZSBwbGFjZS4NCg0KSXQncyBoYXJkIHRvIGZpZ3VyZSBldmVyeXRoaW5nIG91dCBvbiB5b3VyIG93biB3aXRob3V0IGRpcmVjdGlvbiBvciBoZWxwLiBUaGF0J3Mgd2hhdCB0aGlzIGZpcnN0IHdlZWsgaXMgZm9yLg0KDQojIyBUb2RheSdzIENoZWF0IFNoZWV0DQoNCiMjIyBJbnNwZWN0aW5nIG9iamVjdHMNCg0KfCBGdW5jdGlvbiAgIHwgUHVycG9zZSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IEV4YW1wbGUgICAgICAgICB8DQp8LS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLXwNCnwgYHByaW50KHgpYCB8IERpc3BsYXlzIGFuIG9iamVjdCBpbiB0aGUgUiBjb25zb2xlLiAgfCBgcHJpbnQobXlkYXRhKWAgfA0KfCBgY2xhc3MoeClgIHwgU2hvd3MgdGhlIHR5cGUgb3IgY2xhc3Mgb2YgYW4gb2JqZWN0LiB8IGBjbGFzcyhteW51bXMpYCB8DQoNCiMjIyBDcmVhdGluZyBhbmQgb3JnYW5pemluZyBkYXRhDQoNCnwgRnVuY3Rpb24gfCBQdXJwb3NlIHwgRXhhbXBsZSB8DQp8LS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18DQp8IGBjKC4uLilgIHwgQ29tYmluZXMgdmFsdWVzIGludG8gYSB2ZWN0b3IuIHwgYGMoMSwgMiwgMylgIHwNCnwgYGxpc3QoLi4uKWAgfCBDcmVhdGVzIGEgbGlzdCB0aGF0IGNhbiBjb250YWluIGRpZmZlcmVudCB0eXBlcyBvZiBvYmplY3RzLiB8IGBsaXN0KDEsICJtZSIsIDIpYCB8DQp8IGBkYXRhLmZyYW1lKC4uLilgIHwgQ3JlYXRlcyBhIHRhYmxlLWxpa2UgZGF0YSBmcmFtZS4gfCBgZGF0YS5mcmFtZShudW1zID0gbXludW1zLCBuYW1lcyA9IG15bmFtZXMpYCB8DQp8IGBtYXRyaXgoLi4uKWAgfCBDcmVhdGVzIGEgbWF0cml4IHdob3NlIGVsZW1lbnRzIGFyZSBhbGwgdGhlIHNhbWUgdHlwZS4gfCBgbWF0cml4KG15dmVjLCBuY29sID0gNClgIHwNCnwgYG5hbWVzKHgpYCB8IEdldHMgb3IgYXNzaWducyBuYW1lcyB0byB0aGUgZWxlbWVudHMgb2YgYW4gb2JqZWN0LiB8IGBuYW1lcyhteW51bXMpIDwtIGMoImEiLCAiYiIsICJjIilgIHwNCnwgYHJvd25hbWVzKHgpYCB8IEdldHMgb3IgYXNzaWducyByb3cgbmFtZXMuIHwgYHJvd25hbWVzKG15ZGF0YSlgIHwNCnwgYGNvbG5hbWVzKHgpYCB8IEdldHMgb3IgYXNzaWducyBjb2x1bW4gbmFtZXMuIHwgYGNvbG5hbWVzKG15ZGF0YSlgIHwNCg0KIyMjIFBhY2thZ2VzDQoNCnwgRnVuY3Rpb24gfCBQdXJwb3NlIHwgRXhhbXBsZSB8DQp8LS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tfA0KfCBgaW5zdGFsbC5wYWNrYWdlcygpYCB8IERvd25sb2FkcyBhbmQgaW5zdGFsbHMgYW4gUiBwYWNrYWdlLiBUaGlzIHVzdWFsbHkgb25seSBuZWVkcyB0byBiZSBkb25lIG9uY2UuIHwgYGluc3RhbGwucGFja2FnZXMoImdncGxvdDIiKWAgfA0KfCBgbGlicmFyeSgpYCB8IExvYWRzIGFuIGluc3RhbGxlZCBwYWNrYWdlIGZvciB0aGUgY3VycmVudCBSIHNlc3Npb24uIHwgYGxpYnJhcnkoZ2dwbG90MilgIHwNCg0KIyMjIEZpbGVzIGFuZCBmb2xkZXJzDQoNCnwgRnVuY3Rpb24gfCBQdXJwb3NlIHwgRXhhbXBsZSB8DQp8LS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfA0KfCBgZ2V0d2QoKWAgfCBEaXNwbGF5cyBSJ3MgY3VycmVudCB3b3JraW5nIGRpcmVjdG9yeS4gfCBgZ2V0d2QoKWAgfA0KfCBgc2V0d2QoKWAgfCBDaGFuZ2VzIFIncyBjdXJyZW50IHdvcmtpbmcgZGlyZWN0b3J5LiB8IGBzZXR3ZCgiRG9jdW1lbnRzL1JfQ2xhc3MiKWAgfA0KfCBgcmVhZC5jc3YoKWAgfCBSZWFkcyBhIENTViBmaWxlIGFuZCByZXR1cm5zIGEgZGF0YSBmcmFtZS4gfCBgcmVhZC5jc3YoIm15ZGF0YS5jc3YiKWAgfA0KfCBgd3JpdGUuY3N2KClgIHwgU2F2ZXMgYSBkYXRhIGZyYW1lIGFzIGEgQ1NWIGZpbGUuIHwgYHdyaXRlLmNzdihteWRhdGEsICJteWRhdGEuY3N2IilgIHwNCg0KIyMjIFdyaXRpbmcgeW91ciBvd24gZnVuY3Rpb25zDQoNCnwgRnVuY3Rpb24gb3Igc3ludGF4IHwgUHVycG9zZSB8IEV4YW1wbGUgfA0KfC0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tfA0KfCBgZnVuY3Rpb24oLi4uKWAgfCBEZWZpbmVzIGEgcmV1c2FibGUgc2V0IG9mIGluc3RydWN0aW9ucy4gfCBgZnVuY3Rpb24oeCkgeyB4ICsgMSB9YCB8DQoNCiMjIyBDb25kaXRpb25hbCBvcGVyYXRpb25zDQoNCnwgRnVuY3Rpb24gb3Igc3RydWN0dXJlIHwgUHVycG9zZSB8IEV4YW1wbGUgfA0KfC0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tfA0KfCBgaWZgIC8gYGVsc2VgIHwgUnVucyBkaWZmZXJlbnQgY29kZSBkZXBlbmRpbmcgb24gd2hldGhlciBhIGNvbmRpdGlvbiBpcyB0cnVlIG9yIGZhbHNlLiB8IGBpZiAoeCA+IDApIHByaW50KCJwb3NpdGl2ZSIpYCB8DQp8IGBpZmVsc2UoKWAgfCBSZXR1cm5zIGRpZmZlcmVudCB2YWx1ZXMgZm9yIHRoZSBUUlVFIGFuZCBGQUxTRSBlbGVtZW50cyBvZiBhIGxvZ2ljYWwgdmVjdG9yLiB8IGBpZmVsc2UodmFscyA8IDEwMCwgInNtYWxsIiwgImxhcmdlIilgIHwNCg0KIyMjIFJlcGVhdGluZyBvcGVyYXRpb25zDQoNCnwgRnVuY3Rpb24gb3Igc3RydWN0dXJlIHwgUHVycG9zZSB8IEV4YW1wbGUgfA0KfC0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLXwNCnwgYGZvcmAgfCBSZXBlYXRzIGNvZGUgZm9yIGVhY2ggdmFsdWUgaW4gYSBzZXF1ZW5jZSBvciBjb2xsZWN0aW9uLiB8IGBmb3IgKGkgaW4gMToxMCkgcHJpbnQoaSlgIHwNCnwgYGFwcGx5KClgIHwgQXBwbGllcyBhIGZ1bmN0aW9uIHRvIGVhY2ggcm93IG9yIGNvbHVtbiBvZiBhIG1hdHJpeCBvciBkYXRhIGZyYW1lLiB8IGBhcHBseShteW1hdCwgMSwgc3VtKWAgfA0KfCBgc2FwcGx5KClgIHwgQXBwbGllcyBhIGZ1bmN0aW9uIHRvIGVhY2ggZWxlbWVudCBhbmQgdHJpZXMgdG8gc2ltcGxpZnkgdGhlIHJlc3VsdCBpbnRvIGEgdmVjdG9yIG9yIG1hdHJpeC4gfCBgc2FwcGx5KG15bnVtcywgc3FydClgIHwNCnwgYGJ5KClgIHwgQXBwbGllcyBhIGZ1bmN0aW9uIHRvIGdyb3VwcyBkZWZpbmVkIGJ5IGFub3RoZXIgdmFyaWFibGUuIHwgYGJ5KG15ZGF0YSRudW1zLCBteWRhdGEkZ3JvdXAsIG1lYW4pYCB8DQp8IGBzdW0oKWAgfCBBZGRzIHRvZ2V0aGVyIHRoZSB2YWx1ZXMgaW4gYSB2ZWN0b3IuIHwgYHN1bShteW51bXMpYCB8DQoNCiMjIyBJbXBvcnRhbnQgaW5kZXhpbmcgc3ludGF4DQoNClRoZXNlIGFyZSBvcGVyYXRvcnMgcmF0aGVyIHRoYW4gZnVuY3Rpb25zLCBidXQgdGhleSBhcmUgY29tbW9ubHkgdXNlZCB0aHJvdWdob3V0IFIgY29kZS4NCg0KfCBTeW50YXggfCBQdXJwb3NlIHwgRXhhbXBsZSB8DQp8LS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tfA0KfCBgW2ldYCB8IFNlbGVjdHMgb25lIG9yIG1vcmUgZWxlbWVudHMuIHwgYG15bnVtc1szXWAgfA0KfCBgW1tpXV1gIHwgRXh0cmFjdHMgYSBzaW5nbGUgZWxlbWVudCwgY29tbW9ubHkgZnJvbSBhIGxpc3QuIHwgYG15bGlzdFtbM11dYCB8DQp8IGBbaSwgal1gIHwgU2VsZWN0cyByb3dzIGFuZCBjb2x1bW5zIGZyb20gYSBkYXRhIGZyYW1lIG9yIG1hdHJpeC4gfCBgbXlkYXRhWzQsIDJdYCB8DQp8IGAkYCB8IFNlbGVjdHMgYSBkYXRhLWZyYW1lIGNvbHVtbiBieSBuYW1lLiB8IGBteWRhdGEkbnVtc2AgfA0KfCBgOmAgfCBDcmVhdGVzIGEgY29uc2VjdXRpdmUgc2VxdWVuY2Ugb2YgbnVtYmVycy4gfCBgMToxMGAgfA0KfCBgPC1gIHwgQXNzaWducyBhIHZhbHVlIHRvIGEgdmFyaWFibGUuIHwgYHggPC0gNWAgfA0KDQojIyMgQ29tbW9uIGxvZ2ljYWwgb3BlcmF0b3JzDQoNCnwgT3BlcmF0b3IgfCBNZWFuaW5nICAgICAgICAgICAgICAgICAgfCBFeGFtcGxlICAgICAgICAgICAgICB8DQp8LS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tfA0KfCBgPGAgICAgICB8IExlc3MgdGhhbiAgICAgICAgICAgICAgICB8IGB4IDwgMTBgICAgICAgICAgICAgIHwNCnwgYD5gICAgICAgfCBHcmVhdGVyIHRoYW4gICAgICAgICAgICAgfCBgeCA+IDEwYCAgICAgICAgICAgICB8DQp8IGA8PWAgICAgIHwgTGVzcyB0aGFuIG9yIGVxdWFsIHRvICAgIHwgYHggPD0gMTBgICAgICAgICAgICAgfA0KfCBgPj1gICAgICB8IEdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byB8IGB4ID49IDEwYCAgICAgICAgICAgIHwNCnwgYD09YCAgICAgfCBFcXVhbCB0byAgICAgICAgICAgICAgICAgfCBgeCA9PSAxMGAgICAgICAgICAgICB8DQp8IGAhPWAgICAgIHwgTm90IGVxdWFsIHRvICAgICAgICAgICAgIHwgYHggIT0gMTBgICAgICAgICAgICAgfA0KfCBgJmAgICAgICB8IExvZ2ljYWwgQU5EICAgICAgICAgICAgICB8IGAoeCA+IDApICYgKHggPCAxMClgIHwNCnwgYHxgICAgICAgfCBMb2dpY2FsIE9SICAgICAgICAgICAgICAgfCBgKHggPCAwKSB8ICh4ID4gMTApYCB8DQp8IGAhYCAgICAgIHwgTG9naWNhbCBOT1QgICAgICAgICAgICAgIHwgYCFpcy5uYSh4KWAgICAgICAgICAgfA0K