Introduction and preliminaries

1.1. The R environment

"R is an integrated suite of software facilities for data manipulation, calculation and graphical display. Among other thing it has

  • an effective data handling and storage facility,
  • a suite of operators for calculations on arrays, in particular matrices,
  • a large, coherent, integrated collection of intermediate tools for data analysis,
  • graphical facilities for data analysis and display either directly at the computer or on hard-copy, and
  • a well developed, simple and effective programming languaged (called ‘S’) which includes conditionals, loops, user defined recursive functions and input and output facilities. (Indeed most of the system supplied functions are themselves written in the S language.)

It is referred to as the R environment to reflect that it is a fully planned and coherent system, rather than a part of a larger system or piece to be used in conjunction with other data analysis software to reach the eventual goal.

1.3 R and statistics

Not traditionally meant for statistics, it is now used by many for statistics and while it does not include all of the packages required to perform varying types of statistical analylsis many can be found at https://CRAN.R-project.org and elsehwere.

1.4 R and the window system

“The most convenient way to use R is at a graphics workstation running a windowing system.”

1.5 Using R interactively

‘>’ Indicates the R program is ready for input commands.

1.6 An introductory session

Appendix A A sample Session

help.start()
## Start the HTML interface to on-line help (using a web browser available at your machine. You should breifly explore the features of this facility with the mouse. Iconify the help window and move on to the next part.
## Generate two pseudo-random normal vectors of x- and y-coordinates.
x = rnorm(50)
y = rnorm (x)
#Plot the points in the plane. A graphics window will appear automatically.
plot(x,y)

## See which objects are now in the R workspace.
ls()
[1] "x" "y"
## Remove objects no longer needed (clean up).
rm(x,y)
## Make x = (1,2,...,20).
x = 1:20
## Make w a 'weight' vector of standard deviations.
w = 1 + sqrt(x)/2
## Make a data frame of two columns, x and y, and look at it.
dummy = data.frame(x=x, y=x+rnorm(x)*w)
dummy
## Fit a simple linear regression and look at the analysis. With y to the left of the tilde, we are modelling y dependent on x.
fm = lm(y~x,data=dummy)
summary(fm)

Call:
lm(formula = y ~ x, data = dummy)

Residuals:
    Min      1Q  Median      3Q     Max 
-3.6925 -1.9183  0.1055  1.4652  4.2479 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) -1.40447    1.12166  -1.252    0.227    
x            1.05081    0.09363  11.222 1.47e-09 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 2.415 on 18 degrees of freedom
Multiple R-squared:  0.875, Adjusted R-squared:  0.868 
F-statistic: 125.9 on 1 and 18 DF,  p-value: 1.472e-09
## Since we know the standard deviations, we can do a weighted regression.
fm1 = lm(y~x, data=dummy, weight=1/w^2)
summary(fm1)

Call:
lm(formula = y ~ x, data = dummy, weights = 1/w^2)

Weighted Residuals:
     Min       1Q   Median       3Q      Max 
-1.24313 -0.70306  0.00271  0.57434  1.67073 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) -0.97279    0.80134  -1.214     0.24    
x            1.01075    0.08171  12.370 3.09e-10 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.8855 on 18 degrees of freedom
Multiple R-squared:  0.8947,    Adjusted R-squared:  0.8889 
F-statistic:   153 on 1 and 18 DF,  p-value: 3.09e-10
## Make the columns in the data frame visible as variables.
attach(dummy)
The following object is masked _by_ .GlobalEnv:

    x
## Make a nonparametric local regression function.
lrf = lowess(x,y)
plot(x,y) ## Standard point plot.
lines(x,lrf$y) ## Add in the local regression.
abline(0,1,lty=3) ## The true regression line: (intercept 0, slope 1).
abline(coef(fm)) ## Unweighted regression line.
abline(coef(fm1),col="red") ## Weighted regression line.

detach() ## Remove data from the search path.
## A standard regression diagnostic plot to check for heteroscedasticity. Can you see it?
plot(fitted(fm),resid(fm),
     xlab="Fitted values",
     ylab="Residuals",
     main="Residuals vs Fitted")

## A normal scores plot to check for skewness, kurtosis and outliers. (Not very useful here.)
qqnorm(resid(fm),main="Residuals Rankit Plot")

rm(fm,fm1,lrf,x,dummy) ## Clean up again.

The next section will look at data from the classical experiment of Michelson to measure the speed of light. This dataset is available in the morley object, but we will read it to illustrate the read.table function.

## Get the path to the data file.
filepath <- system.file("data","morley.tab",package="datasets")
filepath
[1] "/Library/Frameworks/R.framework/Resources/library/datasets/data/morley.tab"
## Optional. Look at the file.
file.show(filepath)
## Read in the Michelson data as a data frame, and look at it. There are five experminents (column Expt) and each has 20 runs (column Run) and s1 is the recorded speed of light, suitably coded.
mm <- read.table(filepath)
mm
## Change Expt and Run into factors.
mm$Expt=factor(mm$Expt)
mm$Run=factor(mm$Run)
## Make the data frame visible at position 2 (the default).
attach(mm)
## Compare the five experiments with simple boxplots.
plot(Expt,Speed,main="Speed of Light Data",xlab="Experiment No.")

## Analyze as a randomized block, with 'runs' and 'experiments' as factors.
fm=aov(Speed~Run+Expt,data=mm)
summary(fm)
            Df Sum Sq Mean Sq F value  Pr(>F)   
Run         19 113344    5965   1.105 0.36321   
Expt         4  94514   23629   4.378 0.00307 **
Residuals   76 410166    5397                   
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
## Fit the sub-model omitting 'runs', and compare using a formal analysis of variance.
fm0=update(fm,.~.-Run)
anova(fm0,fm)
Analysis of Variance Table

Model 1: Speed ~ Expt
Model 2: Speed ~ Run + Expt
  Res.Df    RSS Df Sum of Sq      F Pr(>F)
1     95 523510                           
2     76 410166 19    113344 1.1053 0.3632
## Clean up before moving on.
detach()
rm(fm,fm0)

We can now look at some more graphical features: contour and image plots.

x <- seq(-pi,pi,len=50) ## x is a vector of 50 equally spaced values between -pi and pi
y <- x ## y is the same.
f=outer(x,y,function(x,y)cos(y)/(1+x^2)) ## f is a square matrix, with rows and columns indexed by x and y respectively, of values of the function cos(y)/(1+x^2).
oldpar=par(no.readonly=TRUE)
par(pty="s") ## Save the plotting paramaters and set the plotting region to "square".
contour(x,y,f)
contour(x,y,f,nlevels=15,add=TRUE) ## Make a contour map of f; add in more lines for more detail.

fa=(f-t(f))/2 ## fa is the "asymmetric part" of f. (t() is transpose).
contour(x,y,fa,nlevels=15) ## Make a contour plot, ...
par(oldpar) ## ... and restore the old graphics parameters.

image(x,y,f)

image(x,y,fa) ## Make some high density image plots, (of which you can get hardcopies if you wish), ...

objects(); rm(x,y,f,fa) ## ... and clean up before moving on.
[1] "f"        "fa"       "filepath" "mm"       "oldpar"   "w"        "x"       
[8] "y"       

R can do complex arithmetic, also.

th <- seq(-pi,pi,len=100)
z <- exp(1i*th) ## 1i is used for the complex number i.
par(pty="s")
plot(z,type="l") ## Plotting complex arguments means plot imaginary versus real parts. This should be a circle.

w=rnorm(100)+rnorm(100)*1i ## Suppose we want to sample points within the unit circle. One method would be to take complex numbers with standard normal real and imaginary parts...
w=ifelse(Mod(w)>1,1/w,w) ## and to map any outside the circle onto their reciprocal.
plot(w,xlim=c(-1,1),ylim=c(-1,1),pch="+",xlab="x",ylab="y")
lines(z) ## All points are inside the unit circle, but the distribution is not uniform.

w=sqrt(runif(100))*exp(2*pi*runif(100)*1i)
plot(w,xlim=c(-1,1),ylim=c(-1,1),pch="+",xlab="x",ylab="y")
lines(z) ## The second method uses the uniform distribution. The points should now look more evenly spaced over the disc.

rm(th,w,z) ## Clean up again.
q() ## Quit the R program. You will be asked if you want to save the R workspace.

End of Appendix A Sample Session

1.7 Getting help with functions and features

R has an inbuilt help facility similar to the man facility of UNIX. To get more information on any specific named function, for example “solve”, the command is

help(solve) or ?solve

1.8 R commands, case sensitivity, etc.

R is case sensitive.

Elementary commands consist of either expressions or assignmnts.

Commands are separated either by a semi-colon (‘;’), or by a newline. Elementary commands can be grouped together into one compound expression by braces (‘{’} and ‘}’). Comments can be put almost anywhere, starting with a hasmhark (‘#’), everything to the end of the line is a comment.

If a command is not complete at the end of a line, R will give a different prompt, by default ‘+’ on second and subsequent lines and continue to read input until the command is syntactically complete.

1.9 Recall and correction of previous commands

The vertical arrow keys on the keyboard can be used to scroll forward and backward through a command history.

The recall and editing capabilities under UNIX are highly customizable. You can find out how to do this by reading the manual entry for the readline library.

1.10 Executing commands from or diverting output to a file

If commands are stored in an external file, say commands.R in the working directory work, they may be executed at any time in an R session with the command source(“commands.R”)

For Windows Source is also available on the File menu. The function sink, sink(“record.lis”) will divert all subsequent output from the console to an external file, record.lis. The command sink() restores it to the console once again.

1.11 Data permanency and removing objects

The entities that R creates and maniputes are known as objects. These may be variables, arrays of numbers, character strings functions, or more general structures built from such components.

During an R session, objects are created and stored by name. The R commands objects() (alternatively, ls()) can be used to display the names of (most of) the objects which are currently stored within R. The collections of objects currently stored is called the workspace.

To remove objects the function rm is available.

For example: rm(x,y,z,ink,junk,temp,foo,bar)

All objects created during an R session can be stored permanently in a file for use in future R sessions At the end of each R session you are given the opportunity to save all the currently available objects. If you indicate that you want to do this, the objects are written to a file called .RData in the current directory, and the command lines used in the session are saved to a file called .Rhistory.

When R is started at later time from the same directory it reloads the workspace from this file. At the same time the associated commands history is reloaded.

It is recommended that you should use separate working directories for analyses conducted with R. It is quite common for objects with names x and y to be created during an analysis. Names like this are often meaningful in the context of a single analysis, but it can be quite hard to decide what they might be when the several analyses have been conducted in the same directory.

LS0tCnRpdGxlOiAiQ2hhcHRlciAxOiBJbnRyb2R1Y3Rpb24gYW5kIFByZWxpbWluYXJpZXMiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KIyBJbnRyb2R1Y3Rpb24gYW5kIHByZWxpbWluYXJpZXMKCiMjIDEuMS4gX19UaGUgUiBlbnZpcm9ubWVudF9fCgoiUiBpcyBhbiBpbnRlZ3JhdGVkIHN1aXRlIG9mIHNvZnR3YXJlIGZhY2lsaXRpZXMgZm9yIGRhdGEgbWFuaXB1bGF0aW9uLCBjYWxjdWxhdGlvbiBhbmQgZ3JhcGhpY2FsIGRpc3BsYXkuIEFtb25nIG90aGVyIHRoaW5nIGl0IGhhcwoKKiBhbiBlZmZlY3RpdmUgZGF0YSBoYW5kbGluZyBhbmQgc3RvcmFnZSBmYWNpbGl0eSwKKiBhIHN1aXRlIG9mIG9wZXJhdG9ycyBmb3IgY2FsY3VsYXRpb25zIG9uIGFycmF5cywgaW4gcGFydGljdWxhciBtYXRyaWNlcywKKiBhIGxhcmdlLCBjb2hlcmVudCwgaW50ZWdyYXRlZCBjb2xsZWN0aW9uIG9mIGludGVybWVkaWF0ZSB0b29scyBmb3IgZGF0YSBhbmFseXNpcywKKiBncmFwaGljYWwgZmFjaWxpdGllcyBmb3IgZGF0YSBhbmFseXNpcyBhbmQgZGlzcGxheSBlaXRoZXIgZGlyZWN0bHkgYXQgdGhlIGNvbXB1dGVyIG9yIG9uIGhhcmQtY29weSwgYW5kCiogYSB3ZWxsIGRldmVsb3BlZCwgc2ltcGxlIGFuZCBlZmZlY3RpdmUgcHJvZ3JhbW1pbmcgbGFuZ3VhZ2VkIChjYWxsZWQgJ1MnKSB3aGljaCBpbmNsdWRlcyBjb25kaXRpb25hbHMsIGxvb3BzLCB1c2VyIGRlZmluZWQgcmVjdXJzaXZlIGZ1bmN0aW9ucyBhbmQgaW5wdXQgYW5kIG91dHB1dCBmYWNpbGl0aWVzLiAoSW5kZWVkIG1vc3Qgb2YgdGhlIHN5c3RlbSBzdXBwbGllZCBmdW5jdGlvbnMgYXJlIHRoZW1zZWx2ZXMgd3JpdHRlbiBpbiB0aGUgUyBsYW5ndWFnZS4pCgpJdCBpcyByZWZlcnJlZCB0byBhcyB0aGUgKl9fUiBlbnZpcm9ubWVudF9fKiB0byByZWZsZWN0IHRoYXQgaXQgaXMgYSBmdWxseSBwbGFubmVkIGFuZCBjb2hlcmVudCBzeXN0ZW0sIHJhdGhlciB0aGFuIGEgcGFydCBvZiBhIGxhcmdlciBzeXN0ZW0gb3IgcGllY2UgdG8gYmUgdXNlZCBpbiBjb25qdW5jdGlvbiB3aXRoIG90aGVyIGRhdGEgYW5hbHlzaXMgc29mdHdhcmUgdG8gcmVhY2ggdGhlIGV2ZW50dWFsIGdvYWwuCgojIyBfXzEuMiBSZWxhdGVkIHNvZnR3YXJlIGFuZCBkb2N1bWVudGF0aW9uX18KSXQgb3JpZ2luYXRlZCBmcm9tIHRoZSBTIGxhbmd1YWdlCgpGb3IgZnVydGhlciBpbmZvcm1hdGlvbiBzZWU6CgoqICpUaGUgTmV3IFMgTGFuZ3VhZ2U6IEEgUHJvZ3JhbW1pbmcgRW52aXJvbm1lbnQgZm9yIERhdGEgQW5hbHlzaXMgYW5kIEdyYXBoaWNzKiBieSBSaWNoYXJkIEEuIEJlY2tlciwgSm9obiBNLiBDaGFtYmVycyBhbmQgQWxsYW4gUi4gV2lsa3MKKiAqU3RhdGlzdGljYWwgTW9kZWxzIGluIFMqIGJ5IEpvaG4gTS4gQ2hhbWJlcnMgYW5kIFRyZXZvciBKLiBIYXN0aWUsIGFuZCBmb3IgdGhlIGZvcm1hbCBtZXRob2RzIGFuZCBjbGFzc2VzIG9mIHRoZSBfX21ldGhvZHNfXyBwYWNrYWdlIHNlZQoqICpQcm9ncmFtbWluZyB3aXRoIERhdGEqIGJ5IEpvaG4gTS4gQ2hhbWJlcnMKCiMjIF9fMS4zIFIgYW5kIHN0YXRpc3RpY3NfXwpOb3QgdHJhZGl0aW9uYWxseSBtZWFudCBmb3Igc3RhdGlzdGljcywgaXQgaXMgbm93IHVzZWQgYnkgbWFueSBmb3Igc3RhdGlzdGljcyBhbmQgd2hpbGUgaXQgZG9lcyBub3QgaW5jbHVkZSBhbGwgb2YgdGhlIHBhY2thZ2VzIHJlcXVpcmVkIHRvIHBlcmZvcm0gdmFyeWluZyB0eXBlcyBvZiBzdGF0aXN0aWNhbCBhbmFseWxzaXMgbWFueSBjYW4gYmUgZm91bmQgYXQgaHR0cHM6Ly9DUkFOLlItcHJvamVjdC5vcmcgYW5kIGVsc2Vod2VyZS4KCiMjIF9fMS40IFIgYW5kIHRoZSB3aW5kb3cgc3lzdGVtX18KIlRoZSBtb3N0IGNvbnZlbmllbnQgd2F5IHRvIHVzZSBSIGlzIGF0IGEgZ3JhcGhpY3Mgd29ya3N0YXRpb24gcnVubmluZyBhIHdpbmRvd2luZyBzeXN0ZW0uIgoKIyMgX18xLjUgVXNpbmcgUiBpbnRlcmFjdGl2ZWx5X18KCic+JyBJbmRpY2F0ZXMgdGhlIFIgcHJvZ3JhbSBpcyByZWFkeSBmb3IgaW5wdXQgY29tbWFuZHMuCgojIyBfXzEuNiBBbiBpbnRyb2R1Y3Rvcnkgc2Vzc2lvbl9fCl9fQXBwZW5kaXggQSBBIHNhbXBsZSBTZXNzaW9uX18KCmBgYHtyfQojIyBTdGFydCB0aGUgSFRNTCBpbnRlcmZhY2UgdG8gb24tbGluZSBoZWxwICh1c2luZyBhIHdlYiBicm93c2VyIGF2YWlsYWJsZSBhdCB5b3VyIG1hY2hpbmUuIFlvdSBzaG91bGQgYnJlaWZseSBleHBsb3JlIHRoZSBmZWF0dXJlcyBvZiB0aGlzIGZhY2lsaXR5IHdpdGggdGhlIG1vdXNlLiBJY29uaWZ5IHRoZSBoZWxwIHdpbmRvdyBhbmQgbW92ZSBvbiB0byB0aGUgbmV4dCBwYXJ0LgpoZWxwLnN0YXJ0KCkKYGBgCgpgYGB7cn0KIyMgR2VuZXJhdGUgdHdvIHBzZXVkby1yYW5kb20gbm9ybWFsIHZlY3RvcnMgb2YgeC0gYW5kIHktY29vcmRpbmF0ZXMuCnggPSBybm9ybSg1MCkKeSA9IHJub3JtICh4KQpgYGAKCmBgYHtyfQojIyBQbG90IHRoZSBwb2ludHMgaW4gdGhlIHBsYW5lLiBBIGdyYXBoaWNzIHdpbmRvdyB3aWxsIGFwcGVhciBhdXRvbWF0aWNhbGx5LgpwbG90KHgseSkKYGBgCgpgYGB7cn0KIyMgU2VlIHdoaWNoIG9iamVjdHMgYXJlIG5vdyBpbiB0aGUgUiB3b3Jrc3BhY2UuCmxzKCkKYGBgCgpgYGB7cn0KIyMgUmVtb3ZlIG9iamVjdHMgbm8gbG9uZ2VyIG5lZWRlZCAoY2xlYW4gdXApLgpybSh4LHkpCmBgYAoKYGBge3J9CiMjIE1ha2UgeCA9ICgxLDIsLi4uLDIwKS4KeCA9IDE6MjAKYGBgCgpgYGB7cn0KIyMgTWFrZSB3IGEgJ3dlaWdodCcgdmVjdG9yIG9mIHN0YW5kYXJkIGRldmlhdGlvbnMuCncgPSAxICsgc3FydCh4KS8yCmBgYAoKYGBge3J9CiMjIE1ha2UgYSBkYXRhIGZyYW1lIG9mIHR3byBjb2x1bW5zLCB4IGFuZCB5LCBhbmQgbG9vayBhdCBpdC4KZHVtbXkgPSBkYXRhLmZyYW1lKHg9eCwgeT14K3Jub3JtKHgpKncpCmR1bW15CmBgYAoKYGBge3J9CiMjIEZpdCBhIHNpbXBsZSBsaW5lYXIgcmVncmVzc2lvbiBhbmQgbG9vayBhdCB0aGUgYW5hbHlzaXMuIFdpdGggeSB0byB0aGUgbGVmdCBvZiB0aGUgdGlsZGUsIHdlIGFyZSBtb2RlbGxpbmcgeSBkZXBlbmRlbnQgb24geC4KZm0gPSBsbSh5fngsZGF0YT1kdW1teSkKc3VtbWFyeShmbSkKYGBgCgpgYGB7cn0KIyMgU2luY2Ugd2Uga25vdyB0aGUgc3RhbmRhcmQgZGV2aWF0aW9ucywgd2UgY2FuIGRvIGEgd2VpZ2h0ZWQgcmVncmVzc2lvbi4KZm0xID0gbG0oeX54LCBkYXRhPWR1bW15LCB3ZWlnaHQ9MS93XjIpCnN1bW1hcnkoZm0xKQpgYGAKCmBgYHtyfQojIyBNYWtlIHRoZSBjb2x1bW5zIGluIHRoZSBkYXRhIGZyYW1lIHZpc2libGUgYXMgdmFyaWFibGVzLgphdHRhY2goZHVtbXkpCmBgYAoKYGBge3J9CiMjIE1ha2UgYSBub25wYXJhbWV0cmljIGxvY2FsIHJlZ3Jlc3Npb24gZnVuY3Rpb24uCmxyZiA9IGxvd2Vzcyh4LHkpCmBgYAoKYGBge3J9CnBsb3QoeCx5KSAjIyBTdGFuZGFyZCBwb2ludCBwbG90LgpsaW5lcyh4LGxyZiR5KSAjIyBBZGQgaW4gdGhlIGxvY2FsIHJlZ3Jlc3Npb24uCmFibGluZSgwLDEsbHR5PTMpICMjIFRoZSB0cnVlIHJlZ3Jlc3Npb24gbGluZTogKGludGVyY2VwdCAwLCBzbG9wZSAxKS4KYWJsaW5lKGNvZWYoZm0pKSAjIyBVbndlaWdodGVkIHJlZ3Jlc3Npb24gbGluZS4KYWJsaW5lKGNvZWYoZm0xKSxjb2w9InJlZCIpICMjIFdlaWdodGVkIHJlZ3Jlc3Npb24gbGluZS4KYGBgCgpgYGB7cn0KZGV0YWNoKCkgIyMgUmVtb3ZlIGRhdGEgZnJvbSB0aGUgc2VhcmNoIHBhdGguCmBgYAoKYGBge3J9CiMjIEEgc3RhbmRhcmQgcmVncmVzc2lvbiBkaWFnbm9zdGljIHBsb3QgdG8gY2hlY2sgZm9yIGhldGVyb3NjZWRhc3RpY2l0eS4gQ2FuIHlvdSBzZWUgaXQ/CnBsb3QoZml0dGVkKGZtKSxyZXNpZChmbSksCiAgICAgeGxhYj0iRml0dGVkIHZhbHVlcyIsCiAgICAgeWxhYj0iUmVzaWR1YWxzIiwKICAgICBtYWluPSJSZXNpZHVhbHMgdnMgRml0dGVkIikKYGBgCgpgYGB7cn0KIyMgQSBub3JtYWwgc2NvcmVzIHBsb3QgdG8gY2hlY2sgZm9yIHNrZXduZXNzLCBrdXJ0b3NpcyBhbmQgb3V0bGllcnMuIChOb3QgdmVyeSB1c2VmdWwgaGVyZS4pCnFxbm9ybShyZXNpZChmbSksbWFpbj0iUmVzaWR1YWxzIFJhbmtpdCBQbG90IikKYGBgCgpgYGB7cn0Kcm0oZm0sZm0xLGxyZix4LGR1bW15KSAjIyBDbGVhbiB1cCBhZ2Fpbi4KYGBgCgpUaGUgbmV4dCBzZWN0aW9uIHdpbGwgbG9vayBhdCBkYXRhIGZyb20gdGhlIGNsYXNzaWNhbCBleHBlcmltZW50IG9mIE1pY2hlbHNvbiB0byBtZWFzdXJlIHRoZSBzcGVlZCBvZiBsaWdodC4gVGhpcyBkYXRhc2V0IGlzIGF2YWlsYWJsZSBpbiB0aGUgX19tb3JsZXlfXyBvYmplY3QsIGJ1dCB3ZSB3aWxsIHJlYWQgaXQgdG8gaWxsdXN0cmF0ZSB0aGUgX19yZWFkLnRhYmxlX18gZnVuY3Rpb24uCgpgYGB7cn0KIyMgR2V0IHRoZSBwYXRoIHRvIHRoZSBkYXRhIGZpbGUuCmZpbGVwYXRoIDwtIHN5c3RlbS5maWxlKCJkYXRhIiwibW9ybGV5LnRhYiIscGFja2FnZT0iZGF0YXNldHMiKQpmaWxlcGF0aApgYGAKCmBgYHtyfQojIyBPcHRpb25hbC4gTG9vayBhdCB0aGUgZmlsZS4KZmlsZS5zaG93KGZpbGVwYXRoKQpgYGAKCmBgYHtyfQojIyBSZWFkIGluIHRoZSBNaWNoZWxzb24gZGF0YSBhcyBhIGRhdGEgZnJhbWUsIGFuZCBsb29rIGF0IGl0LiBUaGVyZSBhcmUgZml2ZSBleHBlcm1pbmVudHMgKGNvbHVtbiBFeHB0KSBhbmQgZWFjaCBoYXMgMjAgcnVucyAoY29sdW1uIFJ1bikgYW5kIHMxIGlzIHRoZSByZWNvcmRlZCBzcGVlZCBvZiBsaWdodCwgc3VpdGFibHkgY29kZWQuCm1tIDwtIHJlYWQudGFibGUoZmlsZXBhdGgpCm1tCmBgYAoKYGBge3J9CiMjIENoYW5nZSBFeHB0IGFuZCBSdW4gaW50byBmYWN0b3JzLgptbSRFeHB0PWZhY3RvcihtbSRFeHB0KQptbSRSdW49ZmFjdG9yKG1tJFJ1bikKYGBgCgpgYGB7cn0KIyMgTWFrZSB0aGUgZGF0YSBmcmFtZSB2aXNpYmxlIGF0IHBvc2l0aW9uIDIgKHRoZSBkZWZhdWx0KS4KYXR0YWNoKG1tKQpgYGAKCmBgYHtyfQojIyBDb21wYXJlIHRoZSBmaXZlIGV4cGVyaW1lbnRzIHdpdGggc2ltcGxlIGJveHBsb3RzLgpwbG90KEV4cHQsU3BlZWQsbWFpbj0iU3BlZWQgb2YgTGlnaHQgRGF0YSIseGxhYj0iRXhwZXJpbWVudCBOby4iKQpgYGAKCmBgYHtyfQojIyBBbmFseXplIGFzIGEgcmFuZG9taXplZCBibG9jaywgd2l0aCAncnVucycgYW5kICdleHBlcmltZW50cycgYXMgZmFjdG9ycy4KZm09YW92KFNwZWVkflJ1bitFeHB0LGRhdGE9bW0pCnN1bW1hcnkoZm0pCmBgYAoKYGBge3J9CiMjIEZpdCB0aGUgc3ViLW1vZGVsIG9taXR0aW5nICdydW5zJywgYW5kIGNvbXBhcmUgdXNpbmcgYSBmb3JtYWwgYW5hbHlzaXMgb2YgdmFyaWFuY2UuCmZtMD11cGRhdGUoZm0sLn4uLVJ1bikKYW5vdmEoZm0wLGZtKQpgYGAKCmBgYHtyfQojIyBDbGVhbiB1cCBiZWZvcmUgbW92aW5nIG9uLgpkZXRhY2goKQpybShmbSxmbTApCmBgYAoKV2UgY2FuIG5vdyBsb29rIGF0IHNvbWUgbW9yZSBncmFwaGljYWwgZmVhdHVyZXM6IGNvbnRvdXIgYW5kIGltYWdlIHBsb3RzLgoKYGBge3J9CnggPC0gc2VxKC1waSxwaSxsZW49NTApICMjIHggaXMgYSB2ZWN0b3Igb2YgNTAgZXF1YWxseSBzcGFjZWQgdmFsdWVzIGJldHdlZW4gLXBpIGFuZCBwaQp5IDwtIHggIyMgeSBpcyB0aGUgc2FtZS4KZj1vdXRlcih4LHksZnVuY3Rpb24oeCx5KWNvcyh5KS8oMSt4XjIpKSAjIyBmIGlzIGEgc3F1YXJlIG1hdHJpeCwgd2l0aCByb3dzIGFuZCBjb2x1bW5zIGluZGV4ZWQgYnkgeCBhbmQgeSByZXNwZWN0aXZlbHksIG9mIHZhbHVlcyBvZiB0aGUgZnVuY3Rpb24gY29zKHkpLygxK3heMikuCm9sZHBhcj1wYXIobm8ucmVhZG9ubHk9VFJVRSkKcGFyKHB0eT0icyIpICMjIFNhdmUgdGhlIHBsb3R0aW5nIHBhcmFtYXRlcnMgYW5kIHNldCB0aGUgcGxvdHRpbmcgcmVnaW9uIHRvICJzcXVhcmUiLgpjb250b3VyKHgseSxmKQpjb250b3VyKHgseSxmLG5sZXZlbHM9MTUsYWRkPVRSVUUpICMjIE1ha2UgYSBjb250b3VyIG1hcCBvZiBmOyBhZGQgaW4gbW9yZSBsaW5lcyBmb3IgbW9yZSBkZXRhaWwuCmZhPShmLXQoZikpLzIgIyMgZmEgaXMgdGhlICJhc3ltbWV0cmljIHBhcnQiIG9mIGYuICh0KCkgaXMgdHJhbnNwb3NlKS4KY29udG91cih4LHksZmEsbmxldmVscz0xNSkgIyMgTWFrZSBhIGNvbnRvdXIgcGxvdCwgLi4uCnBhcihvbGRwYXIpICMjIC4uLiBhbmQgcmVzdG9yZSB0aGUgb2xkIGdyYXBoaWNzIHBhcmFtZXRlcnMuCmltYWdlKHgseSxmKQppbWFnZSh4LHksZmEpICMjIE1ha2Ugc29tZSBoaWdoIGRlbnNpdHkgaW1hZ2UgcGxvdHMsIChvZiB3aGljaCB5b3UgY2FuIGdldCBoYXJkY29waWVzIGlmIHlvdSB3aXNoKSwgLi4uCm9iamVjdHMoKTsgcm0oeCx5LGYsZmEpICMjIC4uLiBhbmQgY2xlYW4gdXAgYmVmb3JlIG1vdmluZyBvbi4KYGBgCgpSIGNhbiBkbyBjb21wbGV4IGFyaXRobWV0aWMsIGFsc28uCgpgYGB7cn0KdGggPC0gc2VxKC1waSxwaSxsZW49MTAwKQp6IDwtIGV4cCgxaSp0aCkgIyMgMWkgaXMgdXNlZCBmb3IgdGhlIGNvbXBsZXggbnVtYmVyIGkuCnBhcihwdHk9InMiKQpwbG90KHosdHlwZT0ibCIpICMjIFBsb3R0aW5nIGNvbXBsZXggYXJndW1lbnRzIG1lYW5zIHBsb3QgaW1hZ2luYXJ5IHZlcnN1cyByZWFsIHBhcnRzLiBUaGlzIHNob3VsZCBiZSBhIGNpcmNsZS4KYGBgCgpgYGB7cn0Kdz1ybm9ybSgxMDApK3Jub3JtKDEwMCkqMWkgIyMgU3VwcG9zZSB3ZSB3YW50IHRvIHNhbXBsZSBwb2ludHMgd2l0aGluIHRoZSB1bml0IGNpcmNsZS4gT25lIG1ldGhvZCB3b3VsZCBiZSB0byB0YWtlIGNvbXBsZXggbnVtYmVycyB3aXRoIHN0YW5kYXJkIG5vcm1hbCByZWFsIGFuZCBpbWFnaW5hcnkgcGFydHMuLi4Kdz1pZmVsc2UoTW9kKHcpPjEsMS93LHcpICMjIGFuZCB0byBtYXAgYW55IG91dHNpZGUgdGhlIGNpcmNsZSBvbnRvIHRoZWlyIHJlY2lwcm9jYWwuCnBsb3Qodyx4bGltPWMoLTEsMSkseWxpbT1jKC0xLDEpLHBjaD0iKyIseGxhYj0ieCIseWxhYj0ieSIpCmxpbmVzKHopICMjIEFsbCBwb2ludHMgYXJlIGluc2lkZSB0aGUgdW5pdCBjaXJjbGUsIGJ1dCB0aGUgZGlzdHJpYnV0aW9uIGlzIG5vdCB1bmlmb3JtLgpgYGAKCmBgYHtyfQp3PXNxcnQocnVuaWYoMTAwKSkqZXhwKDIqcGkqcnVuaWYoMTAwKSoxaSkKcGxvdCh3LHhsaW09YygtMSwxKSx5bGltPWMoLTEsMSkscGNoPSIrIix4bGFiPSJ4Iix5bGFiPSJ5IikKbGluZXMoeikgIyMgVGhlIHNlY29uZCBtZXRob2QgdXNlcyB0aGUgdW5pZm9ybSBkaXN0cmlidXRpb24uIFRoZSBwb2ludHMgc2hvdWxkIG5vdyBsb29rIG1vcmUgZXZlbmx5IHNwYWNlZCBvdmVyIHRoZSBkaXNjLgpgYGAKCmBgYHtyfQpybSh0aCx3LHopICMjIENsZWFuIHVwIGFnYWluLgpgYGAKCmBgYHtyfQpxKCkgIyMgUXVpdCB0aGUgUiBwcm9ncmFtLiBZb3Ugd2lsbCBiZSBhc2tlZCBpZiB5b3Ugd2FudCB0byBzYXZlIHRoZSBSIHdvcmtzcGFjZS4KYGBgCgpFbmQgb2YgQXBwZW5kaXggQSBTYW1wbGUgU2Vzc2lvbgoKIyMgMS43IF9fR2V0dGluZyBoZWxwIHdpdGggZnVuY3Rpb25zIGFuZCBmZWF0dXJlc19fCgpSIGhhcyBhbiBpbmJ1aWx0IGhlbHAgZmFjaWxpdHkgc2ltaWxhciB0byB0aGUgbWFuIGZhY2lsaXR5IG9mIFVOSVguIFRvIGdldCBtb3JlIGluZm9ybWF0aW9uIG9uIGFueSBzcGVjaWZpYyBuYW1lZCBmdW5jdGlvbiwgZm9yIGV4YW1wbGUgInNvbHZlIiwgdGhlIGNvbW1hbmQgaXMgCgpoZWxwKHNvbHZlKSBvciA/c29sdmUKCiMjIF9fMS44IFIgY29tbWFuZHMsIGNhc2Ugc2Vuc2l0aXZpdHksIGV0Yy5fXwoKUiBpcyAqY2FzZSBzZW5zaXRpdmUqLgoKRWxlbWVudGFyeSBjb21tYW5kcyBjb25zaXN0IG9mIGVpdGhlciAqZXhwcmVzc2lvbnMqIG9yICphc3NpZ25tbnRzKi4KCkNvbW1hbmRzIGFyZSBzZXBhcmF0ZWQgZWl0aGVyIGJ5IGEgc2VtaS1jb2xvbiAoJzsnKSwgb3IgYnkgYSBuZXdsaW5lLiBFbGVtZW50YXJ5IGNvbW1hbmRzIGNhbiBiZSBncm91cGVkIHRvZ2V0aGVyIGludG8gb25lIGNvbXBvdW5kIGV4cHJlc3Npb24gYnkgYnJhY2VzICgneyd9IGFuZCAnfScpLiAqQ29tbWVudHMqIGNhbiBiZSBwdXQgYWxtb3N0IGFueXdoZXJlLCBzdGFydGluZyB3aXRoIGEgaGFzbWhhcmsgKCcjJyksIGV2ZXJ5dGhpbmcgdG8gdGhlIGVuZCBvZiB0aGUgbGluZSBpcyBhIGNvbW1lbnQuCgpJZiBhIGNvbW1hbmQgaXMgbm90IGNvbXBsZXRlIGF0IHRoZSBlbmQgb2YgYSBsaW5lLCBSIHdpbGwgZ2l2ZSBhIGRpZmZlcmVudCBwcm9tcHQsIGJ5IGRlZmF1bHQgJysnIG9uIHNlY29uZCBhbmQgc3Vic2VxdWVudCBsaW5lcyBhbmQgY29udGludWUgdG8gcmVhZCBpbnB1dCB1bnRpbCB0aGUgY29tbWFuZCBpcyBzeW50YWN0aWNhbGx5IGNvbXBsZXRlLgoKIyMgX18xLjkgUmVjYWxsIGFuZCBjb3JyZWN0aW9uIG9mIHByZXZpb3VzIGNvbW1hbmRzX18KClRoZSB2ZXJ0aWNhbCBhcnJvdyBrZXlzIG9uIHRoZSBrZXlib2FyZCBjYW4gYmUgdXNlZCB0byBzY3JvbGwgZm9yd2FyZCBhbmQgYmFja3dhcmQgdGhyb3VnaCBhICpjb21tYW5kIGhpc3RvcnkqLgoKVGhlIHJlY2FsbCBhbmQgZWRpdGluZyBjYXBhYmlsaXRpZXMgdW5kZXIgVU5JWCBhcmUgaGlnaGx5IGN1c3RvbWl6YWJsZS4gWW91IGNhbiBmaW5kIG91dCBob3cgdG8gZG8gdGhpcyBieSByZWFkaW5nIHRoZSBtYW51YWwgZW50cnkgZm9yIHRoZSBfX3JlYWRsaW5lX18gbGlicmFyeS4KCiMjIF9fMS4xMCBFeGVjdXRpbmcgY29tbWFuZHMgZnJvbSBvciBkaXZlcnRpbmcgb3V0cHV0IHRvIGEgZmlsZV9fCgo+IElmIGNvbW1hbmRzIGFyZSBzdG9yZWQgaW4gYW4gZXh0ZXJuYWwgZmlsZSwgc2F5ICpjb21tYW5kcy5SKiBpbiB0aGUgd29ya2luZyBkaXJlY3RvcnkgKndvcmsqLCB0aGV5IG1heSBiZSBleGVjdXRlZCBhdCBhbnkgdGltZSBpbiBhbiBSIHNlc3Npb24gd2l0aCB0aGUgY29tbWFuZCBfX3NvdXJjZSgiY29tbWFuZHMuUiIpX18KCkZvciBXaW5kb3dzIF9fU291cmNlX18gaXMgYWxzbyBhdmFpbGFibGUgb24gdGhlIF9fRmlsZV9fIG1lbnUuIFRoZSBmdW5jdGlvbiAqc2luayosIF9fc2luaygicmVjb3JkLmxpcyIpX18gd2lsbCBkaXZlcnQgYWxsIHN1YnNlcXVlbnQgb3V0cHV0IGZyb20gdGhlIGNvbnNvbGUgdG8gYW4gZXh0ZXJuYWwgZmlsZSwgKnJlY29yZC5saXMqLiBUaGUgY29tbWFuZCBfX3NpbmsoKV9fIHJlc3RvcmVzIGl0IHRvIHRoZSBjb25zb2xlIG9uY2UgYWdhaW4uCgojIyBfXzEuMTEgRGF0YSBwZXJtYW5lbmN5IGFuZCByZW1vdmluZyBvYmplY3RzX18KCj4gVGhlIGVudGl0aWVzIHRoYXQgUiBjcmVhdGVzIGFuZCBtYW5pcHV0ZXMgYXJlIGtub3duIGFzICpvYmplY3RzKi4gVGhlc2UgbWF5IGJlIHZhcmlhYmxlcywgYXJyYXlzIG9mIG51bWJlcnMsIGNoYXJhY3RlciBzdHJpbmdzIGZ1bmN0aW9ucywgb3IgbW9yZSBnZW5lcmFsIHN0cnVjdHVyZXMgYnVpbHQgZnJvbSBzdWNoIGNvbXBvbmVudHMuCgo+IER1cmluZyBhbiBSIHNlc3Npb24sIG9iamVjdHMgYXJlIGNyZWF0ZWQgYW5kIHN0b3JlZCBieSBuYW1lLiBUaGUgUiBjb21tYW5kcyBfX29iamVjdHMoKV9fIChhbHRlcm5hdGl2ZWx5LCBfX2xzKClfXykgY2FuIGJlIHVzZWQgdG8gZGlzcGxheSB0aGUgbmFtZXMgb2YgKG1vc3Qgb2YpIHRoZSBvYmplY3RzIHdoaWNoIGFyZSBjdXJyZW50bHkgc3RvcmVkIHdpdGhpbiBSLiBUaGUgY29sbGVjdGlvbnMgb2Ygb2JqZWN0cyBjdXJyZW50bHkgc3RvcmVkIGlzIGNhbGxlZCB0aGUgKndvcmtzcGFjZSouCgpUbyByZW1vdmUgb2JqZWN0cyB0aGUgZnVuY3Rpb24gX19ybV9fIGlzIGF2YWlsYWJsZS4KCkZvciBleGFtcGxlOgpfX3JtKHgseSx6LGluayxqdW5rLHRlbXAsZm9vLGJhcilfXwoKPiBBbGwgb2JqZWN0cyBjcmVhdGVkIGR1cmluZyBhbiBSIHNlc3Npb24gY2FuIGJlIHN0b3JlZCBwZXJtYW5lbnRseSBpbiBhIGZpbGUgZm9yIHVzZSBpbiBmdXR1cmUgUiBzZXNzaW9ucyBBdCB0aGUgZW5kIG9mIGVhY2ggUiBzZXNzaW9uIHlvdSBhcmUgZ2l2ZW4gdGhlIG9wcG9ydHVuaXR5IHRvIHNhdmUgYWxsIHRoZSBjdXJyZW50bHkgYXZhaWxhYmxlIG9iamVjdHMuIElmIHlvdSBpbmRpY2F0ZSB0aGF0IHlvdSB3YW50IHRvIGRvIHRoaXMsIHRoZSBvYmplY3RzIGFyZSB3cml0dGVuIHRvIGEgZmlsZSBjYWxsZWQgX18qLlJEYXRhKl9fIGluIHRoZSBjdXJyZW50IGRpcmVjdG9yeSwgYW5kIHRoZSBjb21tYW5kIGxpbmVzIHVzZWQgaW4gdGhlIHNlc3Npb24gYXJlIHNhdmVkIHRvIGEgZmlsZSBjYWxsZWQgX18qLlJoaXN0b3J5Kl9fLgoKPldoZW4gUiBpcyBzdGFydGVkIGF0IGxhdGVyIHRpbWUgZnJvbSB0aGUgc2FtZSBkaXJlY3RvcnkgaXQgcmVsb2FkcyB0aGUgd29ya3NwYWNlIGZyb20gdGhpcyBmaWxlLiBBdCB0aGUgc2FtZSB0aW1lIHRoZSBhc3NvY2lhdGVkIGNvbW1hbmRzIGhpc3RvcnkgaXMgcmVsb2FkZWQuCgo+SXQgaXMgcmVjb21tZW5kZWQgdGhhdCB5b3Ugc2hvdWxkIHVzZSBzZXBhcmF0ZSB3b3JraW5nIGRpcmVjdG9yaWVzIGZvciBhbmFseXNlcyBjb25kdWN0ZWQgd2l0aCBSLiBJdCBpcyBxdWl0ZSBjb21tb24gZm9yIG9iamVjdHMgd2l0aCBuYW1lcyAqeCogYW5kICp5KiB0byBiZSBjcmVhdGVkIGR1cmluZyBhbiBhbmFseXNpcy4gTmFtZXMgbGlrZSB0aGlzIGFyZSBvZnRlbiBtZWFuaW5nZnVsIGluIHRoZSBjb250ZXh0IG9mIGEgc2luZ2xlIGFuYWx5c2lzLCBidXQgaXQgY2FuIGJlIHF1aXRlIGhhcmQgdG8gZGVjaWRlIHdoYXQgdGhleSBtaWdodCBiZSB3aGVuIHRoZSBzZXZlcmFsIGFuYWx5c2VzIGhhdmUgYmVlbiBjb25kdWN0ZWQgaW4gdGhlIHNhbWUgZGlyZWN0b3J5Lg==