For general computations routinely performed in the scientific setting, the statistical programming language R has become a powerful option. [@R-base] This programming environment (a) is available on all major platforms (Mac, PC, unix, linux), (b) has many easy-to-use (and many not-so-easy-to-use) built-in functions for plotting data, generating curves, manipulating matrices, etc., and best of all (c) is freely available for download over the internet.

The Console Window and Simple Calculations

After installing R (and, perhaps, Rstudio) on your system and initializing,

34 + 17
[1] 51
sqrt(49)
[1] 7
besselI(0.25,1)
[1] 0.1259791
pi
[1] 3.141593

Calculations with Variables and Functions

Define variables and perform calculations…

E0 = 938; W = 8000
sqrt( 1 - (E0/(E0+W))^2 )
[1] 0.994478
# or, define a variable:
beta = sqrt( 1 - (E0/(E0+W))^2 )
# just typing the name of the variable displays its value:
beta
[1] 0.994478

Create a function as follows:

beta = function(x){ sqrt( 1 - (E0/(E0+x))^2 ) }
beta(8000)
[1] 0.994478

Make a list of numbers and perform a calculation on all of them

x = c(0,2,5,9,23)
beta(x)
[1] 0.0000000 0.0651981 0.1028413 0.1375393 0.2174718

Round off our answers to 3 digits

round(beta(x),3)
[1] 0.000 0.065 0.103 0.138 0.217

Saving/Resurrecting the Workspace

Variables and their values can be saved for future use:

save(list=ls(all.names=TRUE),file="vars.Rdata")

Once saved, the workspace can be cleared, using the command:

rm(list=ls())
ls()    # list all the variables in the work environment
character(0)

The data just saved can be re-loaded into the working environment:

load("vars.Rdata")
ls()    # list all the variables in the work environment
[1] "beta" "E0"   "W"    "x"   

Making Simple Plots

x = c(0,1,2,3,4,5,6,7,8,9)
y = beta(x)
plot(x,y)

Plot a curve of a function

curve(beta,0,10)

Plot the points, and add a curve to the same plot; also, add some new labels to the axes

plot(x,y,
   xlab="proton kinetic energy [MeV]", ylab="v/c", main="Velocity vs. Kinetic Energy")
curve(beta, 0, 10, add=TRUE, col="blue")

Creating Random Distributions

# Uniform Distribution of Npts points between 0 and 1
Npts = 500
rnum = runif(Npts,0,1)
plot(rnum)

hist(rnum)

# Normal (Gaussian) Distribution of Npts points, with mean=0, sigma=sig
sig=2
set.seed(231)  # set the random number seed to get same results each run
rnum = rnorm(Npts,0,sig)
plot(rnum)

plot(rnum,pch=".") # use "dots" instead of the default "circles"

hist(rnum)
curve(Npts/(sqrt(2*pi)*sig)*exp(-x^2/(2*sig^2)), add=TRUE, col="blue")

Decisions and Loops

imax=10
x = array(c(1:imax))
x
 [1]  1  2  3  4  5  6  7  8  9 10
i = 1
while (i<imax){
  x[i+1] = x[i] + 12
  i = i+1
}
x
 [1]   1  13  25  37  49  61  73  85  97 109

Can use ifelse(test,yes,no) to perform tests and make decisions

imax=10
x = runif(imax,-1,1)
round(x,2)
 [1] -0.17  0.29 -0.56  0.82 -0.32 -0.25 -0.25  0.24 -0.70  0.50
i = 1
while (i<imax+1){
  x[i] = ifelse(x[i]<0, abs(x[i]), x[i])
  i = i+1
}
round(x,2)
 [1] 0.17 0.29 0.56 0.82 0.32 0.25 0.25 0.24 0.70 0.50

R as a Vector Language

As the reader may have surmized by now, the inner workings of the R language are tailored to the use of vectors. Each variable is thought of as an ordered list of possible values and simple functions operate on theses values separately, by default. So, if x is a vector, then sin(x) will create a vector where the sine function is applied to each value of x:

x = c(0,1,2,3,4,5,6,7,8,9)
y = sin(x)
y
 [1]  0.0000000  0.8414710  0.9092974  0.1411200 -0.7568025 -0.9589243
 [7] -0.2794155  0.6569866  0.9893582  0.4121185
x*y
 [1]  0.000000  0.841471  1.818595  0.423360 -3.027210 -4.794621 -1.676493
 [8]  4.598906  7.914866  3.709066

Note that x*y takes each element of x and multiplies it by the corresponding element of y. (If the two vectors do not have the same length, an error is produced.) Of course vector functions such as inner products and cross products can be performed as well, though special syntax and symbols must be used to perform the desired calculation. We will see examples of this below.

On the other hand, this syntax can be very useful at times. Consider the series \[ f(x) = \sum_{n=1}^{N} \frac{c_n}{n}\sin(nx) \] where the \(c_n\) are provided and the sum needs to be produced for a specific value of \(x\). One often would write a chunk of code that loops over a variable n, say, and sums up the terms then breaks out of the loop after N iterations, etc. This operation can now be written in single line of code

N = 32
x0 = 2
c_n = runif(N,-1,1) # just for illustration
fcn = sum( c_n/c(1:N)*sin(c(1:N)*x0) ) # <--- one line!
fcn
[1] 0.3568438

Matrix Manipulations

A matrix is essentially an ordered list; so, create a list of numbers and tell R where to break the list into rows or columns.

M = matrix( c(1,2,3,4), ncol=2, byrow=TRUE)
M
     [,1] [,2]
[1,]    1    2
[2,]    3    4

Nice to type the input this way, to visually emphasize the arrangement:

A = matrix( c(1, 2,
              3, 4  ), ncol=2, byrow=TRUE)
A
     [,1] [,2]
[1,]    1    2
[2,]    3    4
B = matrix( c(5, 6,
              7, 8  ), ncol=2, byrow=TRUE)
B
     [,1] [,2]
[1,]    5    6
[2,]    7    8

Multiply matrices – but be careful! If you write A * B, this will take each element of A (say a11) and multiply by the corresponding element in B (say b11). What we want is a real matrix multiply – performed using the %*% operator:

C = A * B
C
     [,1] [,2]
[1,]    5   12
[2,]   21   32

WRONG!!

Here’s the right way (in R ):

C = A %*% B
C
     [,1] [,2]
[1,]   19   22
[2,]   43   50

Take the transpose using t(), determinant using det()

t(A)
     [,1] [,2]
[1,]    1    3
[2,]    2    4
det(A)
[1] -2

To find the inverse of a matrix, we use the solve() function:

solve(A)
     [,1] [,2]
[1,] -2.0  1.0
[2,]  1.5 -0.5

Check:

  A      %*% solve(A)
     [,1]         [,2]
[1,]    1 1.110223e-16
[2,]    0 1.000000e+00
solve(A) %*%   A
     [,1]         [,2]
[1,]    1 4.440892e-16
[2,]    0 1.000000e+00

The function solve(A,B) solves the equation \(A\vec{x} = B\) for \(\vec{x}\). If \(B\) is missing in the solve() command, it is taken to be the identity and the inverse of \(A\) is returned.

Multiply a vector by a matrix to get a new vector; still use the operator %*%

x = c(2,1)
x
[1] 2 1
t(t(x))  # trick, to see it in a "usual" (up/down) vector format
     [,1]
[1,]    2
[2,]    1
A
     [,1] [,2]
[1,]    1    2
[2,]    3    4
A %*% x
     [,1]
[1,]    4
[2,]   10

Reading/Writing Data

Write a set of numbers to a file, and read them back in…

x = runif(500,3,9)
y = rnorm(500,2,6)
write.table(cbind(x,y), file="data.txt", row.names=FALSE)
data = read.table("data.txt", header = TRUE)
head(data)  # shows the first few lines...
xx = data[,1]  # first column
yy = data[,2]  # second column
plot(xx,yy)
abline(h=c(mean(yy),mean(yy)+c(-1,1)*sd(yy)),
   lty=c(1,2,2),lwd=2,col=c("red","blue","blue"))
abline(v=mean(xx),lty=1,lwd=2,col="green")

Note: The abline() function adds either horizontal, vertical, or general (\(y = a + bx\)) lines to an existing plot. The argument “lty” depicts the style of the line (solid, dotted, etc.).

Dataframes

Often times we wish to create or maybe read in a table of data, perhaps from measurements that were taken or from the results of a computer simulation, and take a quick look at the numbers, make simple plots, or pursue other manipulations. Above we read in data from a file and then identified new variables for each of the two columns of numbers. Actually, the read.table command will create a “data frame” in R which makes many new options available for our use. Below we generate some data and write it to a file; then read it back in, treating it as a data frame.

# Create some sample data and write to a file, with a header line
x = rnorm(50,0,2)
y = rnorm(50,0,5)
p = (y/5*2-5*x)/10
z = 2-(x+runif(50,-2,2))/2
filename = "data2.txt"
write.table(cbind(x,y,z,p), file=filename, row.names = FALSE)

Next, we read the file back in, creating a dataframe named “data2”.

filename = "data2.txt"
data2 = read.table(file=filename,header=TRUE,sep="")
# What have we created?
attributes(data2)
$names
[1] "x" "y" "z" "p"

$class
[1] "data.frame"

$row.names
 [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
[25] 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
[49] 49 50
head(data2)  # look at first few lines of the dataframe

Note that the names of the columns in our dataframe are taken from the header (first line) of the text file we read in. To access the data for one of the variables (columns) from our dataframe data we use the dollar sign:

# number of entries for "x"
length(data2$x) 
[1] 50
 # value of 23rd entry for "x"
data2$x[23]    
[1] 0.9182747
# perform calculation on all values of "x"
print(sqrt(abs(data2$x)))  
 [1] 0.6084816 0.8739309 1.4903011 1.9915934 1.4277139 1.6439511 1.2164426
 [8] 1.4701206 1.7993016 0.5850132 1.8616033 0.4317011 1.0924151 1.6296967
[15] 0.2154265 1.6189016 1.4255884 1.4386191 0.3784294 0.9138128 0.5334032
[22] 1.3422886 0.9582665 1.9949085 1.4001613 0.4762613 1.3154949 1.2312756
[29] 1.6939402 1.3210473 0.5674360 0.5617848 0.9786093 1.3660924 0.6112916
[36] 1.1206362 1.3710219 1.8047939 0.9928415 1.9122926 1.2847397 0.8249718
[43] 1.3083360 1.6665517 1.3239432 0.1611211 1.7620906 1.9686507 1.6027884
[50] 1.9826357
# create plots of each varialble vs. every other variable
pairs(data2)    

# plot one variable vs. another variable
plot(data2$x,data2$p)  

You can create a subset of your data set:

# find subset where abs(x)<0.8 AND abs(y)<1:
data.sub = subset(data2, subset=( abs(data2$x)<4 & abs(data2$y)<1) )
head(data.sub)
plot(data.sub$x,data.sub$p)  # plot one variable vs. another variable

#  note: a & b     "a is true AND b is true" (intersection)
#        a | b     "a is true OR  b is true"    (union)
#         !a            "a is NOT true"        (negation)
#      other logical options:  a< b  a<=b  a==b  a>=b   a!=b   

Next, we take our plot and fit the data to a linear model, finding the intercept and slope, and adding the corresponding line to the plot

fitparams = lm(p ~ x, data.sub)
fitparams

Call:
lm(formula = p ~ x, data = data.sub)

Coefficients:
(Intercept)            x  
     0.0067      -0.4989  
plot(data.sub$x,data.sub$p)
abline(fitparams,lty=2,col="red")

You can also add columns to your data frame using the already existing data if required. An example:

data2$a = sqrt(data2$x^2 + data2$y^2)
head(data2)

And Much, Much More

text manipulations; complex plotting control; optimizations; complex statistical analyses and modeling; …

visit https://www.r-project.org/ for more information.

Documenting Results

blah blah blah blah blah

Notebooks, rmarkdown and bookdown

blah blah blah blah blah

discuss options, how this web page was created using rmarkdown within an R notebook, now to download the full .Rmd document (at top of the web page), and how bookdown has been used to create full web sites for the courses

LS0tCnRpdGxlOiAiRXNzZW50aWFsICoqUioqIGZvciBiYXNpYyBzY2llbnRpZmljIGNvbXB1dGF0aW9ucyIKb3V0cHV0OiAKICAgaHRtbF9ub3RlYm9vazoKICAgICAgdGhlbWU6IHVuaXRlZAogICAgICB0b2M6IHllcwotLS0KCgpgYGB7ciBvcHRpb25zLCBlY2hvPUZBTFNFLCBldmFsPVRSVUV9CmxpYnJhcnkoa25pdHIpCmxpYnJhcnkoZ2dwbG90MikKa25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG89VFJVRSwgZXZhbD1UUlVFLCBjYWNoZSA9IFRSVUUsCiAgcmVzdWx0cyA9ICdodG1sJywgZmlnLnNob3c9J2FzaXMnLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFKQpgYGAKCkZvciBnZW5lcmFsIGNvbXB1dGF0aW9ucyByb3V0aW5lbHkgcGVyZm9ybWVkIGluIHRoZSBzY2llbnRpZmljIHNldHRpbmcsIHRoZSBzdGF0aXN0aWNhbCBwcm9ncmFtbWluZyBsYW5ndWFnZSAqKlIqKiBoYXMgYmVjb21lIGEgcG93ZXJmdWwgb3B0aW9uLiBbQFItYmFzZV0gICBUaGlzIHByb2dyYW1taW5nIGVudmlyb25tZW50IChhKSBpcyBhdmFpbGFibGUgb24gYWxsIG1ham9yIHBsYXRmb3JtcyAoTWFjLCBQQywgdW5peCwgbGludXgpLCAoYikgaGFzIG1hbnkgZWFzeS10by11c2UgKGFuZCBtYW55IG5vdC1zby1lYXN5LXRvLXVzZSkgYnVpbHQtaW4gZnVuY3Rpb25zIGZvciBwbG90dGluZyBkYXRhLCBnZW5lcmF0aW5nIGN1cnZlcywgbWFuaXB1bGF0aW5nIG1hdHJpY2VzLCAqZXRjLiosIGFuZCBiZXN0IG9mIGFsbCAoYykgaXMgZnJlZWx5IGF2YWlsYWJsZSBmb3IgZG93bmxvYWQgb3ZlciB0aGUgaW50ZXJuZXQuIAoKIyMgVGhlIENvbnNvbGUgV2luZG93IGFuZCBTaW1wbGUgQ2FsY3VsYXRpb25zCgpBZnRlciBpbnN0YWxsaW5nICoqUioqIChhbmQsIHBlcmhhcHMsICoqUnN0dWRpbyoqKSBvbiB5b3VyIHN5c3RlbSBhbmQgaW5pdGlhbGl6aW5nLAoKLSBpbiB0aGUgQ29uc29sZSB3aW5kb3csIHR5cGUgY29tbWFuZHMgYW5kIGhpdCAqUmV0dXJuKjoKYGBge3Igc3RhcnRvdXQwMSwgZWNobz1UUlVFfQozNCArIDE3CnNxcnQoNDkpCmJlc3NlbEkoMC4yNSwxKQpwaQpgYGAKCi0gaW4gdGhlIFNvdXJjZSB3aW5kb3csIHNlbGVjdCBsaW5lcyB0aGF0IHlvdSB3aXNoIHRvIGV4ZWN1dGUgYW5kIChhKSBoaXQgKlJ1biosIG9yIChiKSBoaXQgKkNvbW1hbmQtUmV0dXJuKiAoTUFDKSBvciAqQ29udHJvbC1SZXR1cm4qIChQQykKLSBpbiB0aGUgY29uc29sZSB3aW5kb3csIHR5cGUgYHNvdXJjZSgiL2Rpci9maWxlbmFtZSIpYCAocXVvdGF0aW9uIG1hcmtzIG11c3QgYmUgaW5jbHVkZWQpIGFuZCBoaXQgKlJldHVybiogdG8gZXhlY3V0ZSAqKlIqKiBjb21tYW5kcyBzdG9yZWQgaW4gYSB0ZXh0IGZpbGUgbG9jYXRlZCBpbiBkaXJlY3RvcnkgYW5kIGZpbGUgKi9kaXIvZmlsZW5hbWUqIAoKCiMjIENhbGN1bGF0aW9ucyB3aXRoIFZhcmlhYmxlcyBhbmQgRnVuY3Rpb25zCgpEZWZpbmUgdmFyaWFibGVzIGFuZCBwZXJmb3JtIGNhbGN1bGF0aW9ucy4uLgoKYGBge3IgY2FsY3MwMX0KRTAgPSA5Mzg7IFcgPSA4MDAwCnNxcnQoIDEgLSAoRTAvKEUwK1cpKV4yICkKIyBvciwgZGVmaW5lIGEgdmFyaWFibGU6CmJldGEgPSBzcXJ0KCAxIC0gKEUwLyhFMCtXKSleMiApCiMganVzdCB0eXBpbmcgdGhlIG5hbWUgb2YgdGhlIHZhcmlhYmxlIGRpc3BsYXlzIGl0cyB2YWx1ZToKYmV0YQpgYGAKCkNyZWF0ZSBhIGZ1bmN0aW9uIGFzIGZvbGxvd3M6CgpgYGB7ciBjYWxjczAyfQpiZXRhID0gZnVuY3Rpb24oeCl7IHNxcnQoIDEgLSAoRTAvKEUwK3gpKV4yICkgfQpiZXRhKDgwMDApCmBgYAoKTWFrZSBhIGxpc3Qgb2YgbnVtYmVycyBhbmQgcGVyZm9ybSBhIGNhbGN1bGF0aW9uIG9uIGFsbCBvZiB0aGVtCmBgYHtyIGNhbGNzMDN9CnggPSBjKDAsMiw1LDksMjMpCmJldGEoeCkKYGBgCgpSb3VuZCBvZmYgb3VyIGFuc3dlcnMgdG8gMyBkaWdpdHMKYGBge3IgY2FsY3MwNH0Kcm91bmQoYmV0YSh4KSwzKQpgYGAKCiMjIyBTYXZpbmcvUmVzdXJyZWN0aW5nIHRoZSBXb3Jrc3BhY2UKClZhcmlhYmxlcyBhbmQgdGhlaXIgdmFsdWVzIGNhbiBiZSBzYXZlZCBmb3IgZnV0dXJlIHVzZToKCmBgYHtyfQpzYXZlKGxpc3Q9bHMoYWxsLm5hbWVzPVRSVUUpLGZpbGU9InZhcnMuUmRhdGEiKQpgYGAKCk9uY2Ugc2F2ZWQsIHRoZSB3b3Jrc3BhY2UgY2FuIGJlIGNsZWFyZWQsIHVzaW5nIHRoZSBjb21tYW5kOgoKYGBge3J9CnJtKGxpc3Q9bHMoKSkKbHMoKSAgICAjIGxpc3QgYWxsIHRoZSB2YXJpYWJsZXMgaW4gdGhlIHdvcmsgZW52aXJvbm1lbnQKYGBgCgpUaGUgZGF0YSBqdXN0IHNhdmVkIGNhbiBiZSByZS1sb2FkZWQgaW50byB0aGUgd29ya2luZyBlbnZpcm9ubWVudDoKCmBgYHtyfQpsb2FkKCJ2YXJzLlJkYXRhIikKbHMoKSAgICAjIGxpc3QgYWxsIHRoZSB2YXJpYWJsZXMgaW4gdGhlIHdvcmsgZW52aXJvbm1lbnQKYGBgCgoKIyMgTWFraW5nIFNpbXBsZSBQbG90cwpgYGB7ciBwbG90czAwfQp4ID0gYygwLDEsMiwzLDQsNSw2LDcsOCw5KQp5ID0gYmV0YSh4KQpwbG90KHgseSkKYGBgCgpQbG90IGEgY3VydmUgb2YgYSBmdW5jdGlvbgpgYGB7ciBwbG90czAxfQpjdXJ2ZShiZXRhLDAsMTApCmBgYAoKUGxvdCB0aGUgcG9pbnRzLCBhbmQgYWRkIGEgY3VydmUgdG8gdGhlIHNhbWUgcGxvdDsgYWxzbywgYWRkIHNvbWUgbmV3IGxhYmVscyB0byB0aGUgYXhlcwpgYGB7ciBwbG90czAyfQpwbG90KHgseSwKICAgeGxhYj0icHJvdG9uIGtpbmV0aWMgZW5lcmd5IFtNZVZdIiwgeWxhYj0idi9jIiwgbWFpbj0iVmVsb2NpdHkgdnMuIEtpbmV0aWMgRW5lcmd5IikKY3VydmUoYmV0YSwgMCwgMTAsIGFkZD1UUlVFLCBjb2w9ImJsdWUiKQpgYGAKCiMjIENyZWF0aW5nIFJhbmRvbSBEaXN0cmlidXRpb25zCmBgYHtyIHJhbmRvbXN9CiMgVW5pZm9ybSBEaXN0cmlidXRpb24gb2YgTnB0cyBwb2ludHMgYmV0d2VlbiAwIGFuZCAxCk5wdHMgPSA1MDAKcm51bSA9IHJ1bmlmKE5wdHMsMCwxKQpwbG90KHJudW0pCmhpc3Qocm51bSkKIyBOb3JtYWwgKEdhdXNzaWFuKSBEaXN0cmlidXRpb24gb2YgTnB0cyBwb2ludHMsIHdpdGggbWVhbj0wLCBzaWdtYT1zaWcKc2lnPTIKc2V0LnNlZWQoMjMxKSAgIyBzZXQgdGhlIHJhbmRvbSBudW1iZXIgc2VlZCB0byBnZXQgc2FtZSByZXN1bHRzIGVhY2ggcnVuCnJudW0gPSBybm9ybShOcHRzLDAsc2lnKQpwbG90KHJudW0pCnBsb3Qocm51bSxwY2g9Ii4iKSAjIHVzZSAiZG90cyIgaW5zdGVhZCBvZiB0aGUgZGVmYXVsdCAiY2lyY2xlcyIKaGlzdChybnVtKQpjdXJ2ZShOcHRzLyhzcXJ0KDIqcGkpKnNpZykqZXhwKC14XjIvKDIqc2lnXjIpKSwgYWRkPVRSVUUsIGNvbD0iYmx1ZSIpCmBgYAoKIyMgRGVjaXNpb25zIGFuZCBMb29wcwoKYGBge3IgbG9vcHMwMX0KaW1heD0xMAp4ID0gYXJyYXkoYygxOmltYXgpKQp4CmkgPSAxCndoaWxlIChpPGltYXgpewogIHhbaSsxXSA9IHhbaV0gKyAxMgogIGkgPSBpKzEKfQp4CmBgYAoKQ2FuIHVzZSBgaWZlbHNlKHRlc3QseWVzLG5vKWAgdG8gcGVyZm9ybSB0ZXN0cyBhbmQgbWFrZSBkZWNpc2lvbnMKYGBge3IgbG9vcHMwMn0KaW1heD0xMAp4ID0gcnVuaWYoaW1heCwtMSwxKQpyb3VuZCh4LDIpCmkgPSAxCndoaWxlIChpPGltYXgrMSl7CiAgeFtpXSA9IGlmZWxzZSh4W2ldPDAsIGFicyh4W2ldKSwgeFtpXSkKICBpID0gaSsxCn0Kcm91bmQoeCwyKQpgYGAKCgojIyAqKlIqKiBhcyBhIFZlY3RvciBMYW5ndWFnZQoKQXMgdGhlIHJlYWRlciBtYXkgaGF2ZSBzdXJtaXplZCBieSBub3csIHRoZSBpbm5lciB3b3JraW5ncyBvZiB0aGUgKipSKiogbGFuZ3VhZ2UgYXJlIHRhaWxvcmVkIHRvIHRoZSB1c2Ugb2YgdmVjdG9ycy4gIEVhY2ggdmFyaWFibGUgaXMgdGhvdWdodCBvZiBhcyBhbiBvcmRlcmVkIGxpc3Qgb2YgcG9zc2libGUgdmFsdWVzIGFuZCBzaW1wbGUgZnVuY3Rpb25zIG9wZXJhdGUgb24gdGhlc2VzIHZhbHVlcyBzZXBhcmF0ZWx5LCBieSBkZWZhdWx0LiAgU28sIGlmIGB4YCBpcyBhIHZlY3RvciwgdGhlbiBgc2luKHgpYCB3aWxsIGNyZWF0ZSBhIHZlY3RvciB3aGVyZSB0aGUgc2luZSBmdW5jdGlvbiBpcyBhcHBsaWVkIHRvIGVhY2ggdmFsdWUgb2YgYHhgOgoKYGBge3J9CnggPSBjKDAsMSwyLDMsNCw1LDYsNyw4LDkpCnkgPSBzaW4oeCkKeQp4KnkKYGBgCgpOb3RlIHRoYXQgYHgqeWAgdGFrZXMgZWFjaCBlbGVtZW50IG9mIGB4YCBhbmQgbXVsdGlwbGllcyBpdCBieSB0aGUgY29ycmVzcG9uZGluZyBlbGVtZW50IG9mIGB5YC4gIChJZiB0aGUgdHdvIHZlY3RvcnMgZG8gbm90IGhhdmUgdGhlIHNhbWUgbGVuZ3RoLCBhbiBlcnJvciBpcyBwcm9kdWNlZC4pICBPZiBjb3Vyc2UgdmVjdG9yIGZ1bmN0aW9ucyBzdWNoIGFzIGlubmVyIHByb2R1Y3RzIGFuZCBjcm9zcyBwcm9kdWN0cyBjYW4gYmUgcGVyZm9ybWVkIGFzIHdlbGwsIHRob3VnaCBzcGVjaWFsIHN5bnRheCBhbmQgc3ltYm9scyBtdXN0IGJlIHVzZWQgdG8gcGVyZm9ybSB0aGUgZGVzaXJlZCBjYWxjdWxhdGlvbi4gIFdlIHdpbGwgc2VlIGV4YW1wbGVzIG9mIHRoaXMgYmVsb3cuCgpPbiB0aGUgb3RoZXIgaGFuZCwgdGhpcyBzeW50YXggY2FuIGJlIHZlcnkgdXNlZnVsIGF0IHRpbWVzLiAgQ29uc2lkZXIgdGhlIHNlcmllcwokJApmKHgpID0gXHN1bV97bj0xfV57Tn0gXGZyYWN7Y19ufXtufVxzaW4obngpCiQkCndoZXJlIHRoZSAkY19uJCBhcmUgcHJvdmlkZWQgYW5kIHRoZSBzdW0gbmVlZHMgdG8gYmUgcHJvZHVjZWQgZm9yIGEgc3BlY2lmaWMgdmFsdWUgb2YgJHgkLiAgT25lIG9mdGVuIHdvdWxkIHdyaXRlIGEgY2h1bmsgb2YgY29kZSB0aGF0IGxvb3BzIG92ZXIgYSB2YXJpYWJsZSBgbmAsIHNheSwgYW5kIHN1bXMgdXAgdGhlIHRlcm1zIHRoZW4gYnJlYWtzIG91dCBvZiB0aGUgbG9vcCBhZnRlciBgTmAgaXRlcmF0aW9ucywgZXRjLiAgVGhpcyBvcGVyYXRpb24gY2FuIG5vdyBiZSB3cml0dGVuIGluIHNpbmdsZSBsaW5lIG9mIGNvZGUKYGBge3J9Ck4gPSAzMgp4MCA9IDIKY19uID0gcnVuaWYoTiwtMSwxKSAjIGp1c3QgZm9yIGlsbHVzdHJhdGlvbgpmY24gPSBzdW0oIGNfbi9jKDE6Tikqc2luKGMoMTpOKSp4MCkgKSAjIDwtLS0gb25lIGxpbmUhCmZjbgpgYGAKCgoKIyMgTWF0cml4IE1hbmlwdWxhdGlvbnMKCkEgbWF0cml4IGlzIGVzc2VudGlhbGx5IGFuIG9yZGVyZWQgbGlzdDsgc28sIGNyZWF0ZSBhIGxpc3Qgb2YgbnVtYmVycyBhbmQgdGVsbCAqKlIqKiB3aGVyZSB0byBicmVhayB0aGUgbGlzdCBpbnRvIHJvd3Mgb3IgY29sdW1ucy4KYGBge3IgbWF0cmljZXMwMX0KTSA9IG1hdHJpeCggYygxLDIsMyw0KSwgbmNvbD0yLCBieXJvdz1UUlVFKQpNCmBgYApOaWNlIHRvIHR5cGUgdGhlIGlucHV0ICp0aGlzKiB3YXksIHRvIHZpc3VhbGx5IGVtcGhhc2l6ZSB0aGUgYXJyYW5nZW1lbnQ6CmBgYHtyIG1hdHJpY2VzMDJ9CkEgPSBtYXRyaXgoIGMoMSwgMiwKICAgICAgICAgICAgICAzLCA0ICApLCBuY29sPTIsIGJ5cm93PVRSVUUpCkEKYGBgCmBgYHtyIG1hdHJpY2VzMDN9CkIgPSBtYXRyaXgoIGMoNSwgNiwKICAgICAgICAgICAgICA3LCA4ICApLCBuY29sPTIsIGJ5cm93PVRSVUUpCkIKYGBgCgpNdWx0aXBseSBtYXRyaWNlcyAtLSBidXQgYmUgY2FyZWZ1bCEgIElmIHlvdSB3cml0ZSBgQSAqIEJgLCB0aGlzIHdpbGwgdGFrZSBlYWNoIGVsZW1lbnQgb2YgQSAoc2F5IGExMSkgYW5kIG11bHRpcGx5IGJ5IHRoZSBjb3JyZXNwb25kaW5nIGVsZW1lbnQgaW4gQiAoc2F5IGIxMSkuICBXaGF0IF93ZV8gd2FudCBpcyBhIHJlYWwgbWF0cml4IG11bHRpcGx5IC0tIHBlcmZvcm1lZCB1c2luZyB0aGUgYCUqJWAgb3BlcmF0b3I6IApgYGB7ciBtYXRyaWNlczA0YX0KQyA9IEEgKiBCCkMKYGBgCgoqKldST05HISEqKgoKSGVyZSdzIHRoZSByaWdodCB3YXkgKGluICoqUioqICk6CmBgYHtyIG1hdHJpY2VzMDRifQpDID0gQSAlKiUgQgpDCmBgYAoKVGFrZSB0aGUgKnRyYW5zcG9zZSogdXNpbmcgYHQoKWAsICpkZXRlcm1pbmFudCogdXNpbmcgYGRldCgpYApgYGB7ciBtYXRyaWNlczA1fQp0KEEpCmRldChBKQpgYGAKVG8gZmluZCB0aGUgaW52ZXJzZSBvZiBhIG1hdHJpeCwgd2UgdXNlIHRoZSBgc29sdmUoKWAgZnVuY3Rpb246CmBgYHtyIG1hdHJpY2VzMDVifQpzb2x2ZShBKQpgYGAKCkNoZWNrOgpgYGB7ciBtYXRyaWNlczA1Y30KICBBICAgICAgJSolIHNvbHZlKEEpCnNvbHZlKEEpICUqJSAgIEEKYGBgCgpUaGUgZnVuY3Rpb24gYHNvbHZlKEEsQilgIHNvbHZlcyB0aGUgZXF1YXRpb24gJEFcdmVje3h9ID0gQiQgZm9yICRcdmVje3h9JC4gIElmICRCJCBpcyBtaXNzaW5nIGluIHRoZSBgc29sdmUoKWAgY29tbWFuZCwgaXQgaXMgdGFrZW4gdG8gYmUgdGhlIGlkZW50aXR5IGFuZCB0aGUgaW52ZXJzZSBvZiAkQSQgaXMgcmV0dXJuZWQuCgpNdWx0aXBseSBhIHZlY3RvciBieSBhIG1hdHJpeCB0byBnZXQgYSBuZXcgdmVjdG9yOyBzdGlsbCB1c2UgdGhlIG9wZXJhdG9yIGAlKiVgLi4uCmBgYHtyIG1hdHJpY2VzMDZ9CnggPSBjKDIsMSkKeAp0KHQoeCkpICAjIHRyaWNrLCB0byBzZWUgaXQgaW4gYSAidXN1YWwiICh1cC9kb3duKSB2ZWN0b3IgZm9ybWF0CkEKQSAlKiUgeApgYGAKCiMjIFJlYWRpbmcvV3JpdGluZyBEYXRhCldyaXRlIGEgc2V0IG9mIG51bWJlcnMgdG8gYSBmaWxlLCBhbmQgcmVhZCB0aGVtIGJhY2sgaW4uLi4KYGBge3IgaW5vdXR9CnggPSBydW5pZig1MDAsMyw5KQp5ID0gcm5vcm0oNTAwLDIsNikKd3JpdGUudGFibGUoY2JpbmQoeCx5KSwgZmlsZT0iZGF0YS50eHQiLCByb3cubmFtZXM9RkFMU0UpCgpkYXRhID0gcmVhZC50YWJsZSgiZGF0YS50eHQiLCBoZWFkZXIgPSBUUlVFKQpoZWFkKGRhdGEpICAjIHNob3dzIHRoZSBmaXJzdCBmZXcgbGluZXMuLi4KCnh4ID0gZGF0YVssMV0gICMgZmlyc3QgY29sdW1uCnl5ID0gZGF0YVssMl0gICMgc2Vjb25kIGNvbHVtbgoKcGxvdCh4eCx5eSkKYWJsaW5lKGg9YyhtZWFuKHl5KSxtZWFuKHl5KStjKC0xLDEpKnNkKHl5KSksCiAgIGx0eT1jKDEsMiwyKSxsd2Q9Mixjb2w9YygicmVkIiwiYmx1ZSIsImJsdWUiKSkKYWJsaW5lKHY9bWVhbih4eCksbHR5PTEsbHdkPTIsY29sPSJncmVlbiIpCmBgYAoKTm90ZTogIFRoZSBgYWJsaW5lKClgIGZ1bmN0aW9uIGFkZHMgZWl0aGVyIGhvcml6b250YWwsIHZlcnRpY2FsLCBvciBnZW5lcmFsICgkeSA9IGEgKyBieCQpIGxpbmVzIHRvIGFuIGV4aXN0aW5nIHBsb3QuICBUaGUgYXJndW1lbnQgImx0eSIgZGVwaWN0cyB0aGUgc3R5bGUgb2YgdGhlIGxpbmUgKHNvbGlkLCBkb3R0ZWQsIGV0Yy4pLgoKIyMgRGF0YWZyYW1lcwoKT2Z0ZW4gdGltZXMgd2Ugd2lzaCB0byBjcmVhdGUgb3IgbWF5YmUgcmVhZCBpbiBhIHRhYmxlIG9mIGRhdGEsIHBlcmhhcHMgZnJvbSBtZWFzdXJlbWVudHMgdGhhdCB3ZXJlIHRha2VuIG9yIGZyb20gdGhlIHJlc3VsdHMgb2YgYSBjb21wdXRlciBzaW11bGF0aW9uLCBhbmQgdGFrZSBhIHF1aWNrIGxvb2sgYXQgdGhlIG51bWJlcnMsIG1ha2Ugc2ltcGxlIHBsb3RzLCBvciBwdXJzdWUgb3RoZXIgbWFuaXB1bGF0aW9ucy4gIEFib3ZlIHdlIHJlYWQgaW4gZGF0YSBmcm9tIGEgZmlsZSBhbmQgdGhlbiBpZGVudGlmaWVkIG5ldyB2YXJpYWJsZXMgZm9yIGVhY2ggb2YgdGhlIHR3byBjb2x1bW5zIG9mIG51bWJlcnMuICBBY3R1YWxseSwgdGhlIGByZWFkLnRhYmxlYCBjb21tYW5kIHdpbGwgY3JlYXRlIGEgImRhdGEgZnJhbWUiIGluICoqUioqIHdoaWNoIG1ha2VzIG1hbnkgbmV3IG9wdGlvbnMgYXZhaWxhYmxlIGZvciBvdXIgdXNlLiAgQmVsb3cgd2UgZ2VuZXJhdGUgc29tZSBkYXRhIGFuZCB3cml0ZSBpdCB0byBhIGZpbGU7IHRoZW4gcmVhZCBpdCBiYWNrIGluLCB0cmVhdGluZyBpdCBhcyBhIGRhdGEgZnJhbWUuCgpgYGB7ciBtYWtlZGF0YX0KIyBDcmVhdGUgc29tZSBzYW1wbGUgZGF0YSBhbmQgd3JpdGUgdG8gYSBmaWxlLCB3aXRoIGEgaGVhZGVyIGxpbmUKeCA9IHJub3JtKDUwLDAsMikKeSA9IHJub3JtKDUwLDAsNSkKcCA9ICh5LzUqMi01KngpLzEwCnogPSAyLSh4K3J1bmlmKDUwLC0yLDIpKS8yCgpmaWxlbmFtZSA9ICJkYXRhMi50eHQiCndyaXRlLnRhYmxlKGNiaW5kKHgseSx6LHApLCBmaWxlPWZpbGVuYW1lLCByb3cubmFtZXMgPSBGQUxTRSkKYGBgCgpOZXh0LCB3ZSByZWFkIHRoZSBmaWxlIGJhY2sgaW4sIGNyZWF0aW5nIGEgZGF0YWZyYW1lIG5hbWVkICJkYXRhMiIuCmBgYHtyIG1ha2VmcmFtZX0KZmlsZW5hbWUgPSAiZGF0YTIudHh0IgpkYXRhMiA9IHJlYWQudGFibGUoZmlsZT1maWxlbmFtZSxoZWFkZXI9VFJVRSxzZXA9IiIpCiMgV2hhdCBoYXZlIHdlIGNyZWF0ZWQ/CmF0dHJpYnV0ZXMoZGF0YTIpCmhlYWQoZGF0YTIpICAjIGxvb2sgYXQgZmlyc3QgZmV3IGxpbmVzIG9mIHRoZSBkYXRhZnJhbWUKYGBgCgpOb3RlIHRoYXQgdGhlIG5hbWVzIG9mIHRoZSBjb2x1bW5zIGluIG91ciBkYXRhZnJhbWUgYXJlIHRha2VuIGZyb20gdGhlIGhlYWRlciAoZmlyc3QgbGluZSkgb2YgdGhlIHRleHQgZmlsZSB3ZSByZWFkIGluLiAgVG8gYWNjZXNzIHRoZSBkYXRhIGZvciBvbmUgb2YgdGhlIHZhcmlhYmxlcyAoY29sdW1ucykgZnJvbSBvdXIgZGF0YWZyYW1lIGBkYXRhYCB3ZSB1c2UgdGhlIGRvbGxhciBzaWduOgoKYGBge3IgeH0KIyBudW1iZXIgb2YgZW50cmllcyBmb3IgIngiCmxlbmd0aChkYXRhMiR4KSAKICMgdmFsdWUgb2YgMjNyZCBlbnRyeSBmb3IgIngiCmRhdGEyJHhbMjNdICAgIAojIHBlcmZvcm0gY2FsY3VsYXRpb24gb24gYWxsIHZhbHVlcyBvZiAieCIKcHJpbnQoc3FydChhYnMoZGF0YTIkeCkpKSAgCiMgY3JlYXRlIHBsb3RzIG9mIGVhY2ggdmFyaWFsYmxlIHZzLiBldmVyeSBvdGhlciB2YXJpYWJsZQpwYWlycyhkYXRhMikgICAgCiMgcGxvdCBvbmUgdmFyaWFibGUgdnMuIGFub3RoZXIgdmFyaWFibGUKcGxvdChkYXRhMiR4LGRhdGEyJHApICAKYGBgCgpZb3UgY2FuIGNyZWF0ZSBhIGBzdWJzZXRgIG9mIHlvdXIgZGF0YSBzZXQ6CgpgYGB7ciBhdHRhY2hmcmFtZX0KIyBmaW5kIHN1YnNldCB3aGVyZSBhYnMoeCk8MC44IEFORCBhYnMoeSk8MToKZGF0YS5zdWIgPSBzdWJzZXQoZGF0YTIsIHN1YnNldD0oIGFicyhkYXRhMiR4KTw0ICYgYWJzKGRhdGEyJHkpPDEpICkKaGVhZChkYXRhLnN1YikKcGxvdChkYXRhLnN1YiR4LGRhdGEuc3ViJHApICAjIHBsb3Qgb25lIHZhcmlhYmxlIHZzLiBhbm90aGVyIHZhcmlhYmxlCiMgIG5vdGU6IGEgJiBiICAgICAiYSBpcyB0cnVlIEFORCBiIGlzIHRydWUiIChpbnRlcnNlY3Rpb24pCiMgICAgICAgIGEgfCBiICAgICAiYSBpcyB0cnVlIE9SICBiIGlzIHRydWUiICAgICh1bmlvbikKIyAgICAgICAgICFhICAgICAgICAgICAgImEgaXMgTk9UIHRydWUiICAgICAgICAobmVnYXRpb24pCiMgICAgICBvdGhlciBsb2dpY2FsIG9wdGlvbnM6ICBhPCBiICBhPD1iICBhPT1iICBhPj1iICAgYSE9YiAgIApgYGAKCk5leHQsIHdlIHRha2Ugb3VyIHBsb3QgYW5kIGZpdCB0aGUgZGF0YSB0byBhIGxpbmVhciBtb2RlbCwgZmluZGluZyB0aGUgaW50ZXJjZXB0IGFuZCBzbG9wZSwgYW5kIGFkZGluZyB0aGUgY29ycmVzcG9uZGluZyBsaW5lIHRvIHRoZSBwbG90CgpgYGB7ciBsaW5maXR9CmZpdHBhcmFtcyA9IGxtKHAgfiB4LCBkYXRhLnN1YikKZml0cGFyYW1zCgpwbG90KGRhdGEuc3ViJHgsZGF0YS5zdWIkcCkKYWJsaW5lKGZpdHBhcmFtcyxsdHk9Mixjb2w9InJlZCIpCmBgYAoKWW91IGNhbiBhbHNvIGFkZCBjb2x1bW5zIHRvIHlvdXIgZGF0YSBmcmFtZSB1c2luZyB0aGUgYWxyZWFkeSBleGlzdGluZyBkYXRhIGlmIHJlcXVpcmVkLiAgQW4gZXhhbXBsZToKCmBgYHtyIGFkZDJmcmFtZX0KZGF0YTIkYSA9IHNxcnQoZGF0YTIkeF4yICsgZGF0YTIkeV4yKQpoZWFkKGRhdGEyKQpgYGAKCiMjIyBBbmQgTXVjaCwgTXVjaCBNb3JlCgp0ZXh0IG1hbmlwdWxhdGlvbnM7IGNvbXBsZXggcGxvdHRpbmcgY29udHJvbDsgb3B0aW1pemF0aW9uczsgY29tcGxleCBzdGF0aXN0aWNhbCBhbmFseXNlcyBhbmQgbW9kZWxpbmc7IC4uLgoKdmlzaXQgIGh0dHBzOi8vd3d3LnItcHJvamVjdC5vcmcvIGZvciBtb3JlIGluZm9ybWF0aW9uLgoKCiMjIERvY3VtZW50aW5nIFJlc3VsdHMKCmJsYWggYmxhaCBibGFoIGJsYWggYmxhaCAKCiMjIyBOb3RlYm9va3MsIGBybWFya2Rvd25gIGFuZCBgYm9va2Rvd25gCgpibGFoIGJsYWggYmxhaCBibGFoIGJsYWggCgpkaXNjdXNzIG9wdGlvbnMsIGhvdyB0aGlzIHdlYiBwYWdlIHdhcyBjcmVhdGVkIHVzaW5nIHJtYXJrZG93biB3aXRoaW4gYW4gUiBub3RlYm9vaywgbm93IHRvIGRvd25sb2FkIHRoZSBmdWxsIC5SbWQgZG9jdW1lbnQgKGF0IHRvcCBvZiB0aGUgd2ViIHBhZ2UpLCBhbmQgaG93IGJvb2tkb3duIGhhcyBiZWVuIHVzZWQgdG8gY3JlYXRlIGZ1bGwgd2ViIHNpdGVzIGZvciB0aGUgY291cnNlcwoKCgo=