library(MASS)
Attaching package: 'MASS'
The following object is masked from 'package:dplyr':
select
In this lecture we will look at:
What is R?
Basic R syntax
Use of R via RStudio.
What is R?
R is a statistical software system.
R is a programming language that has many “inbuilt” statistical
commands (e.g. to fit a linear regression).
R started life as a quasi-clone of commercial package S-Plus, but
development of R and S-Plus now slowly diverging.
Advantages over other statistics packages include flexibility,
power, and quality of graphical display.
R is open-source software, and part of GNU project. It can be
downloaded from http://cran.r-project.org/ and used for
free.
There are versions of R for all common operating systems —
Windows, Linux, and MacOS.
A Little R History
Ross Ihaka (left) and Robert Gentleman.
R is a New Zealand invention!
R originally developed by Ross Ihaka and Robert Gentleman in the
Department of Statistics, University of Auckland.
First (test) version of R released in public domain in
1995.
R Development Core Team took over supervision of R in
1997.
This Team includes about 20 statisticians worldwide.
Starting R in the Computing Labs
- Start R for the first time via the Start menu (or desktop icon if
available).
- Select R (version 4) from the appropriate program group.
- RGui (R Graphical User
Interface) should appear as displayed.
RGUI v3.3.0
N.B. Check the version number. Ideally we want to be sure that we are
running the latest version, but do not change versions partway through
the semester unless it is truly necessary.
Starting RStudio in the Computing Labs
- Start RStudio for the first time via the Start menu (or desktop icon
if available).
- You should see the window split into sub-windows. Please note that
RStudio is undergoing constant development. Your version may not look
quite like the image displayed below.
RStudio using R 3.4.1
N.B. the contents of the RGUI are all available in RStudio. We will
work in RStudio because it offers many extra features.
Working directory
When you quit R you will get a pop-up asking “Save workspace
image?”.
If you click yes, then the R workspace that you have
created will be saved in your working directory.
You can find out where your working directory is by typing the
command getwd() at the R prompt.
The working directory can be changed using the Change dir…
command from the R File menu.
Note the command getwd() is in typewriter font. This
font is used in lectures for R input and output (amongst other things).
The parentheses are included to show you that this is a command; typing
getwd alone will not give you what you want!
Save your work using scripts!
Please get into the habit of writing all your R commands in a
R script before you run it in the console.
An R script is a text file containing code which can be run
directly by highlighting then hitting CTRL-R.
- Comments following
# symbols in script files are not
executed.
To create a new script use the New script command from the R File
menu or New File>R Script from the RStudio File menu.
To save your script, click on the scripts pane, and then go to
File > Save As in the menu bar.
Scripts allow you to rerun your entire analysis without
re-writing all the commands, it also helps editing and proofreading your
code.
Managing Your Code
Screen shot of R Script in R
Screen shot of R Script in RStudio
An even better way
Putting your R commands into the file that becomes your end-use
document will make your workflow even more efficient. When we use
RStudio, we can make use of the extensive features to create these
documents.
Look out for the tutorial sheets introducing you to what we call
R markdown documents. The lecture material you
are viewing now was produced using R markdown.
More on this later…
A First Dip into R
Expressions and Assignments
Elementary commands are either expressions or
assignments.
An expression simply displays result of a calculation;
not retained in the computer’s memory.
An assignment passes the result of a calculation to a
variable name (or ‘object’) which is stored; the result is not
displayed.
Examples (for you to try)
3 + 4
[1] 7
x <- 3 + 4
x
[1] 7
- The
<- is called the “left assignment” operator
which assigns from right (3+4) to left
(x)
- Yes, it takes two keys to get it; there cannot be space between the
< and the - and it is best practice to put
space on either side of <- in your work.
- It is equivalent to
x=3+4, but many R users prefer the
<- because it always means something is created in your
workspace. (not always true for =)
- A right assignment operator also exists but is not commonly
used.
R Objects
x <- 8
y <- 3.1415
ls()
[1] "i" "MoneyStock"
[3] "MoneyStock_lm1" "Outfile"
[5] "seoul_above" "seoul_acf_limit"
[7] "seoul_acf_values" "seoul_daily"
[9] "seoul_diagnostics" "seoul_dw"
[11] "seoul_dw_denominator" "seoul_dw_numerator"
[13] "seoul_gls" "seoul_ljung_box"
[15] "seoul_lm" "seoul_mean"
[17] "seoul_median" "seoul_n"
[19] "seoul_n_above" "seoul_n_below"
[21] "seoul_normalized_residuals" "seoul_phi"
[23] "seoul_run" "seoul_run_data"
[25] "seoul_run_model" "seoul_run_normalised_r"
[27] "seoul_run_ols_r" "seoul_run_residuals"
[29] "seoul_runs" "seoul_runs_expected"
[31] "seoul_runs_observed" "seoul_trend"
[33] "tourism" "tourism_acf_comparison"
[35] "tourism_acf_limit" "tourism_gls"
[37] "tourism_lb_gls" "tourism_lb_ols"
[39] "tourism_lm" "tourism_normalised"
[41] "tourism_normalised_r" "tourism_ols_r"
[43] "tourism_phi" "tourism_raw"
[45] "tourism_raw_r" "tourism_se_ratio"
[47] "tourism_trend" "x"
[49] "y"
rm(x)
objects()
[1] "i" "MoneyStock"
[3] "MoneyStock_lm1" "Outfile"
[5] "seoul_above" "seoul_acf_limit"
[7] "seoul_acf_values" "seoul_daily"
[9] "seoul_diagnostics" "seoul_dw"
[11] "seoul_dw_denominator" "seoul_dw_numerator"
[13] "seoul_gls" "seoul_ljung_box"
[15] "seoul_lm" "seoul_mean"
[17] "seoul_median" "seoul_n"
[19] "seoul_n_above" "seoul_n_below"
[21] "seoul_normalized_residuals" "seoul_phi"
[23] "seoul_run" "seoul_run_data"
[25] "seoul_run_model" "seoul_run_normalised_r"
[27] "seoul_run_ols_r" "seoul_run_residuals"
[29] "seoul_runs" "seoul_runs_expected"
[31] "seoul_runs_observed" "seoul_trend"
[33] "tourism" "tourism_acf_comparison"
[35] "tourism_acf_limit" "tourism_gls"
[37] "tourism_lb_gls" "tourism_lb_ols"
[39] "tourism_lm" "tourism_normalised"
[41] "tourism_normalised_r" "tourism_ols_r"
[43] "tourism_phi" "tourism_raw"
[45] "tourism_raw_r" "tourism_se_ratio"
[47] "tourism_trend" "y"
R Syntax
R commands, e.g. ls(), rm(), are
followed by parentheses which may contain additional information for the
function.
Writing a command name without parentheses returns the R source
code for the function. Try one…
Vectors in R
- The command
c() (for concatenate) creates
vectors.
x <- c(2.3, 1.2, 2.4)
x
[1] 2.3 1.2 2.4
c(x, 9, x)
[1] 2.3 1.2 2.4 9.0 2.3 1.2 2.4
Regular Sequences
The expression 1:n denotes the
sequence 1, 2,… n.
The expression seq(i,j,by=k) is a sequence from
i) to j in steps of k.
1:5
[1] 1 2 3 4 5
y <- seq(3, 10, by = 2)
y
[1] 3 5 7 9
Vector Arithmetic in R
R uses +, -, * and
/ for the basic arithmetic operations, and ^
for exponentiation (raising to a power).
- Vector operations are done element by element, with recycling of
short vectors if required.
x <- c(2, 3)
y <- c(1, 4, 5, 6)
2 * x
[1] 4 6
2 + x
[1] 4 5
y^2
[1] 1 16 25 36
x + y
[1] 3 7 7 9
Types of vector
All the vectors we have seen so far have been numeric;
some were integer which is a special type of number.
R also understands vectors of:
- characters: letters, numerals, spaces, and other text.
- logical values `TRUE` and `FALSE`; abbreviations `T`, `F` are often used.
- factors (i.e. categorical variables); these may "look" like characters.
MyWords <- c("This", "is", "a", "character")
MyWords
[1] "This" "is" "a" "character"
c(F, T, F, F)
[1] FALSE TRUE FALSE FALSE
factor(c("Low", "Low", "Medium", "High", "High"))
[1] Low Low Medium High High
Levels: High Low Medium
N.B. All of these data types can be used in linear models, although
character values are usually converted to factors.
Logical Comparisons
Numerical vectors can be compared by inequalities.
== denotes equality; the = states what
something is.
!= denotes ‘not equal’.
>, >= etc. for
inequalities.
(1:5) == (5:1)
[1] FALSE FALSE TRUE FALSE FALSE
(1:5) > (5:1)
[1] FALSE FALSE FALSE TRUE TRUE
You might like to play with these comparisons. Testing the need for
the brackets is worth testing.
Indexing Vectors
x <- c(1.1, 3.2, 4.3, 7.4)
x[c(2, 4)]
[1] 3.2 7.4
x[-2]
[1] 1.1 4.3 7.4
x[x > 3.5]
[1] 4.3 7.4
which(x > 3.5)
[1] 3 4
Data Frames
A data frame is a collection of column vectors each of the same
length.
The vectors may be numeric, factor, or whatever.
Each particular column and row of a data frame is given a name
which can be chosen by the user, or assigned a default by R.
employee <- c("Dilbert", "Wally", "Catbert", "TheBoss")
job <- factor(c("Engineer", "Engineer", "Manager", "Manager"))
x <- c(8, 1, NA, -2)
dilbert <- data.frame(employee, job, competence = x)
dilbert
employee job competence
1 Dilbert Engineer 8
2 Wally Engineer 1
3 Catbert Manager NA
4 TheBoss Manager -2
Attaching and Detaching
rm(employee, job, x)
dilbert$competence
[1] 8 1 NA -2
job
Error:
! object 'job' not found
attach(dilbert)
job
[1] Engineer Engineer Manager Manager
Levels: Engineer Manager
detach(dilbert)
N.B. Using attach() without detach() can
lead to trouble. All is fine when things are done correctly, but the
consequences of not using these commands correctly is seldom seen at the
time they are used. When the errors come up it will be difficult to
diagnose the problem. It is quite unusual to need to use these commands
if you use modern ways of working. It is important to know how the
attach() and detach() commands work, but do
look to avoid their use.
Importing Data
The scan() command reads in text from a file as a
single variable. You should use this command very infrequently.
The read.table() command is more flexible, importing
data in tabular form and storing the result as a data frame.
other commands exist for importing csv files, and a
host of other file formats.
The comma separated values (csv) file format is extremely common
and is used often in the course. You should not need to use
scan() or read.table().
## IBM <- scan(file = "ibm.txt")
ibm
Error:
! object 'ibm' not found
IBM
[1] 64.37 62.50 63.50 63.37 63.12 67.37 65.37 67.50 67.00
[10] 66.87 70.12 70.00 69.25 69.62 69.00 69.00 71.25 70.62
[19] 70.12 71.00 70.37 70.37 68.62 69.37 69.12 69.62 68.37
[28] 67.12 67.25 66.75 68.87 69.37 68.12 67.62 67.62 67.00
[37] 67.25 66.25 66.00 65.12 65.00 62.00 63.37 63.50 62.75
[46] 63.25 62.00 61.12 61.00 61.62 62.25 61.37 60.12 59.87
[55] 59.12 59.62 58.87 58.25 56.75 54.12 54.75 53.00 57.50
[64] 55.87 55.75 54.87 55.50 54.87 54.87 53.37 53.50 54.62
[73] 54.25 53.50 53.00 52.00 51.12 51.25 51.25 51.25 53.87
[82] 53.50 53.75 55.37 54.50 54.87 54.87 54.37 54.00 55.37
[91] 54.87 55.12 53.87 52.12 52.25 53.25 53.00 52.50 53.00
[100] 53.37 52.75 52.87 53.75 54.75 54.75 55.25 56.37 54.37
[109] 55.37 56.00 56.37 58.12 57.00 57.12 56.75 57.50 58.00
[118] 58.00 58.87 60.37 58.87 59.62 57.87 57.87 58.87 59.37
[127] 59.75 59.25 59.75 58.75 59.50 60.62 61.12 61.12 62.00
[136] 61.75 61.50 61.62 62.75 65.00 63.75 64.25 65.62 65.12
[145] 66.00 65.12 64.87 64.75 64.37 65.00 65.12 65.50 65.25
[154] 65.12 64.75 64.25 65.62 65.75 65.25 66.75 66.75 66.75
[163] 68.87 68.75 66.37 66.00 66.87 67.50 67.37 67.12 66.75
[172] 65.87 65.00 65.50 65.50 66.12 67.50 66.62 66.50 64.25
[181] 66.12 65.75 66.37 65.87 66.12 65.62 67.25 66.50 67.00
[190] 68.12 66.87 67.50 66.12 64.62 63.75 64.12 65.62 65.37
[199] 66.25 68.00 67.75 70.00 70.12 69.25 70.50 69.75 70.37
[208] 68.62 68.00 68.50 68.00 67.75 65.87 66.62 66.12 66.62
[217] 65.50 65.12 66.62 67.50 67.50 68.50 66.50 67.12 67.25
[226] 67.12 70.87 71.25 71.62 71.62 72.00 71.37 72.00 70.37
[235] 70.37 69.50 68.75 68.75 68.12 66.50 67.87 68.00 68.37
[244] 67.50 66.37 66.12 63.75 64.50 6575.00 64.50
N.B. R is case sensitive so ibm is different to
IBM. Windows is not case sensitive so the filename can be
misspecified without any trouble; other operating systems are case
sensitive though.
Life <- read.csv(file = "../../data/life.csv", header = TRUE)
head(Life) # shows only the first six rows
LifeExp People.per.TV People.per.Dr LifeExp.Male LifeExp.Female
1 70.5 4.0 370 74 67
2 53.5 315.0 6166 53 54
3 65.0 4.0 684 68 62
4 76.5 1.7 449 80 73
5 70.0 8.0 643 72 68
6 71.0 5.6 1551 74 68
The ../../data/ in this command is called a relative
file path. The .. means to look up one level from the
current working directory; the file requested is in a subfolder called
data; the / is how we separate folders from
subfolders or filenames. This may seem strange to Windows users who want
to use a backslash instead. Get used to using the forward slash in R
because it works for all operating systems.
The read.csv() command makes a number of assumptions
about the way the file is formatted. A csv file is actually
plain text with commas between values. Some people think it is a MS
Excel file, but csv files existed long before Excel.
Editing Data
Can edit by reassigning elements of a vector or data
frame.
For data frame or matrix, A[i,j] is the
i,jth element (row i, column j) of
the data frame A.
IBM[5]
[1] 63.12
IBM[5] <- 65.12
IBM[5]
[1] 65.12
Life[2, ]
LifeExp People.per.TV People.per.Dr LifeExp.Male LifeExp.Female
2 53.5 315 6166 53 54
Life[2, 4]
[1] 53
Life[2, 4] <- 7166
R Packages
R objects (functions, data etc.) are organized in
libraries/packages.
Some are loaded by default when R starts each time.
- E.g. function
ls() is part of the base
package that is automatically loaded,
Some packages need loading, using either the
library() or require() command.
mvrnorm(1, mu = 0, Sigma = 1)
[1] -0.8503098
library(MASS)
mvrnorm(1, mu = 0, Sigma = 1)
[1] 2.320559
Some R Functions to Get You Started
help() accesses R’s help system;
e.g. help(ls). A quicker way is to use
?ls
mean(), sd(), min(),
max() and range() give mean, standard
deviation, minimum, maximum and range respectively for a vector
argument. N.B. range() tells you the minimum and maximum as
a pair, not the difference between them.
var() returns variance of a vector argument, or the
covariance (dispersion) matrix for a matrix argument.
summary() returns summary information dependent on
argument type.
plot() produces a plot on the current graphics tool.
The type of plot depends on the type of argument. The simplest use is
plot(x,y) which produces a scatter-plot of vectors
x and y.
Practice is the key when learning R.
Your First R Exercise
Use R to calculate
- 3456-789
- \(23\times{}34\)
- 133
Write (efficient) code to create the following sequences:
2, 4, 6, … 100; that is, the even numbers up to 100
1,2,3,4,5,4,3,2,1
Use the command y <- rnorm(100) to store 100
simulated standard normal random variables in the vector
y.
Find the mean and standard deviation of y.
Find the largest simulated value. Which number simulation is this
e.g. 54th, 23rd?
LS0tDQp0aXRsZTogIkxlY3R1cmUgNDE6IEFwcGVuZGl4OiBJbnRyb2R1Y3Rpb24gdG8gUiBhbmQgUlN0dWRpbyINCnN1YnRpdGxlOiAxNjEuMjUxIFJlZ3Jlc3Npb24gTW9kZWxsaW5nDQphdXRob3I6ICJQcmVzZW50ZWQgYnkgSm9uYXRoYW4gR29kZnJleSA8YS5qLmdvZGZyZXlAbWFzc2V5LmFjLm56PiIgIA0KZGF0ZTogIldlZWsgMCBvZiBTZW1lc3RlciAyLCBgciBsdWJyaWRhdGU6OnllYXIobHVicmlkYXRlOjpub3coKSlgIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICB0aGVtZTogeWV0aQ0KICAgIGhpZ2hsaWdodF9zdHlsZTogcHlnbWVudHMNCiAgaHRtbF9ub3RlYm9vazoNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgdGhlbWU6IHlldGkNCiAgICBoaWdobGlnaHRfc3R5bGU6IHB5Z21lbnRzDQogIGlvc2xpZGVzX3ByZXNlbnRhdGlvbjoNCiAgICB3aWRlc2NyZWVuOiB0cnVlDQogICAgc21hbGxlcjogdHJ1ZQ0KICB3b3JkX2RvY3VtZW50OiBkZWZhdWx0DQogIHNsaWR5X3ByZXNlbnRhdGlvbjogDQogICAgdGhlbWU6IHlldGkNCiAgICBoaWdobGlnaHRfc3R5bGU6IHB5Z21lbnRzDQogIHBkZl9kb2N1bWVudDogZGVmYXVsdA0KLS0tDQoNCg0KDQoNCjwhLS0tIERhdGEgaXMgb24NCmh0dHBzOi8vci1yZXNvdXJjZXMubWFzc2V5LmFjLm56L2RhdGEvMTYxMjUxLw0KLS0tPg0KDQpgYGB7ciBzZXR1cCwgcHVybD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0NCmxpYnJhcnkoa25pdHIpDQpvcHRzX2NodW5rJHNldChkZXY9YygicG5nIiwgInBkZiIpKQ0Kb3B0c19jaHVuayRzZXQoZmlnLmhlaWdodD02LCBmaWcud2lkdGg9NywgZmlnLnBhdGg9IkZpZ3VyZXMvIiwgZmlnLmFsdD0idW5sYWJlbGxlZCIpDQpvcHRzX2NodW5rJHNldChjb21tZW50PSIiLCBmaWcuYWxpZ249ImNlbnRlciIsIHRpZHk9VFJVRSkNCm9wdGlvbnMoa25pdHIua2FibGUuTkEgPSAnJykNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShicm9vbSkNCmBgYA0KDQoNCjwhLS0tIERvIG5vdCBlZGl0IGFueXRoaW5nIGFib3ZlIHRoaXMgbGluZS4gLS0tPg0KDQpgYGB7ciBleHRyYUxpYnN9DQpsaWJyYXJ5KE1BU1MpDQpgYGANCg0KDQpJbiB0aGlzIGxlY3R1cmUgd2Ugd2lsbCBsb29rIGF0Og0KDQogIC0gV2hhdCBpcyBSPw0KDQogIC0gQmFzaWMgUiBzeW50YXgNCg0KLSBVc2Ugb2YgUiB2aWEgUlN0dWRpby4NCg0KDQojIyBXaGF0IGlzIFI/DQoNCiAgLSBSIGlzIGEgc3RhdGlzdGljYWwgc29mdHdhcmUgc3lzdGVtLg0KDQogIC0gUiBpcyBhIHByb2dyYW1taW5nIGxhbmd1YWdlIHRoYXQgaGFzIG1hbnkgImluYnVpbHQiIHN0YXRpc3RpY2FsDQogICAgY29tbWFuZHMgKGUuZy4gdG8gZml0IGEgbGluZWFyIHJlZ3Jlc3Npb24pLg0KDQogIC0gUiBzdGFydGVkIGxpZmUgYXMgYSBxdWFzaS1jbG9uZSBvZiBjb21tZXJjaWFsIHBhY2thZ2UgUy1QbHVzLCBidXQNCiAgICBkZXZlbG9wbWVudCBvZiBSIGFuZCBTLVBsdXMgbm93IHNsb3dseSBkaXZlcmdpbmcuDQoNCiAgLSBBZHZhbnRhZ2VzIG92ZXIgb3RoZXIgc3RhdGlzdGljcyBwYWNrYWdlcyBpbmNsdWRlIGZsZXhpYmlsaXR5LA0KICAgIHBvd2VyLCBhbmQgcXVhbGl0eSBvZiBncmFwaGljYWwgZGlzcGxheS4NCg0KICAtIFIgaXMgb3Blbi1zb3VyY2Ugc29mdHdhcmUsIGFuZCBwYXJ0IG9mIEdOVSBwcm9qZWN0LiBJdCBjYW4gYmUNCiAgICBkb3dubG9hZGVkIGZyb20gYGh0dHA6Ly9jcmFuLnItcHJvamVjdC5vcmcvYCBhbmQgdXNlZCBmb3IgZnJlZS4NCg0KICAtIFRoZXJlIGFyZSB2ZXJzaW9ucyBvZiBSIGZvciBhbGwgY29tbW9uIG9wZXJhdGluZyBzeXN0ZW1zIC0tLSBXaW5kb3dzLCBMaW51eCwgYW5kIE1hY09TLg0KDQojIyBBIExpdHRsZSBSIEhpc3RvcnkNCg0KfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KfCA6LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS06IHwgOi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLTogfA0KfCAhW3Bob3RvIG9mIFJvc3MgSWhha2FdKC4uL2dyYXBoaWNzL2loYWthLmpwZykgfCAhW3Bob3RvIG9mIFJvYmVydCBHZW50bGVtYW5dKC4uL2dyYXBoaWNzL2dlbnRsZW1hbi5qcGcpIHwNCg0KICANCiBSb3NzIEloYWthIChsZWZ0KSBhbmQgUm9iZXJ0IEdlbnRsZW1hbi4NCg0KICAtIFIgaXMgYSBOZXcgWmVhbGFuZCBpbnZlbnRpb25cIQ0KDQogIC0gUiBvcmlnaW5hbGx5IGRldmVsb3BlZCBieSBSb3NzIEloYWthIGFuZCBSb2JlcnQgR2VudGxlbWFuIGluIHRoZQ0KICAgIERlcGFydG1lbnQgb2YgU3RhdGlzdGljcywgVW5pdmVyc2l0eSBvZiBBdWNrbGFuZC4NCg0KICAtIEZpcnN0ICh0ZXN0KSB2ZXJzaW9uIG9mIFIgcmVsZWFzZWQgaW4gcHVibGljIGRvbWFpbiBpbiAxOTk1Lg0KDQogIC0gUiBEZXZlbG9wbWVudCBDb3JlIFRlYW0gdG9vayBvdmVyIHN1cGVydmlzaW9uIG9mIFIgaW4gMTk5Ny4NCg0KIC0gVGhpcyBUZWFtIGluY2x1ZGVzIGFib3V0IDIwIHN0YXRpc3RpY2lhbnMgd29ybGR3aWRlLg0KDQojIyBTdGFydGluZyBSIGluIHRoZSBDb21wdXRpbmcgTGFicw0KDQotIFN0YXJ0IFIgZm9yIHRoZSBmaXJzdCB0aW1lIHZpYSB0aGUgU3RhcnQgbWVudSAob3IgZGVza3RvcCBpY29uIGlmIGF2YWlsYWJsZSkuDQotIFNlbGVjdCBSICh2ZXJzaW9uIGByIHZlcnNpb24kbWFqb3JgKSBmcm9tIHRoZSBhcHByb3ByaWF0ZSBwcm9ncmFtIGdyb3VwLg0KLSBSR3VpICgqKlIgRyoqcmFwaGljYWwgKipVKipzZXIgKipJKipudGVyZmFjZSkgc2hvdWxkIGFwcGVhciBhcyBkaXNwbGF5ZWQuDQoNCiFbUkdVSSB2My4zLjBdKC4uL2dyYXBoaWNzL1JHdWkuanBnKQ0KDQpOLkIuIENoZWNrIHRoZSB2ZXJzaW9uIG51bWJlci4gSWRlYWxseSB3ZSB3YW50IHRvIGJlIHN1cmUgdGhhdCB3ZSBhcmUgcnVubmluZyB0aGUgbGF0ZXN0IHZlcnNpb24sIGJ1dCBkbyBub3QgY2hhbmdlIHZlcnNpb25zIHBhcnR3YXkgdGhyb3VnaCB0aGUgc2VtZXN0ZXIgdW5sZXNzIGl0IGlzIHRydWx5IG5lY2Vzc2FyeS4NCg0KIyMgU3RhcnRpbmcgUlN0dWRpbyBpbiB0aGUgQ29tcHV0aW5nIExhYnMNCg0KLSBTdGFydCBSU3R1ZGlvIGZvciB0aGUgZmlyc3QgdGltZSB2aWEgdGhlIFN0YXJ0IG1lbnUgKG9yIGRlc2t0b3AgaWNvbiBpZiBhdmFpbGFibGUpLg0KLSBZb3Ugc2hvdWxkIHNlZSB0aGUgd2luZG93IHNwbGl0IGludG8gc3ViLXdpbmRvd3MuIFBsZWFzZSBub3RlIHRoYXQgUlN0dWRpbyBpcyB1bmRlcmdvaW5nIGNvbnN0YW50IGRldmVsb3BtZW50LiBZb3VyIHZlcnNpb24gbWF5IG5vdCBsb29rIHF1aXRlIGxpa2UgdGhlIGltYWdlICBkaXNwbGF5ZWQgYmVsb3cuDQoNCg0KIVtSU3R1ZGlvIHVzaW5nIFIgMy40LjFdKC4uL2dyYXBoaWNzL1JTdHVkaW8ucG5nKSANCg0KTi5CLiB0aGUgY29udGVudHMgb2YgdGhlIFJHVUkgYXJlIGFsbCBhdmFpbGFibGUgaW4gUlN0dWRpby4gV2Ugd2lsbCB3b3JrIGluIFJTdHVkaW8gYmVjYXVzZSBpdCBvZmZlcnMgbWFueSBleHRyYSBmZWF0dXJlcy4NCg0KDQojIyBXb3JraW5nIGRpcmVjdG9yeQ0KDQogIC0gV2hlbiB5b3UgcXVpdCBSIHlvdSB3aWxsIGdldCBhIHBvcC11cCBhc2tpbmcgIlNhdmUgd29ya3NwYWNlDQogICAgaW1hZ2U/Ii4NCg0KICAtIElmIHlvdSBjbGljayB5ZXMsIHRoZW4gdGhlICpSIHdvcmtzcGFjZSogdGhhdCB5b3UgaGF2ZQ0KICAgIGNyZWF0ZWQgd2lsbCBiZSBzYXZlZCBpbiB5b3VyICp3b3JraW5nIGRpcmVjdG9yeSouDQoNCiAgLSBZb3UgY2FuIGZpbmQgb3V0IHdoZXJlIHlvdXIgd29ya2luZyBkaXJlY3RvcnkgaXMgYnkgdHlwaW5nIHRoZQ0KICAgIGNvbW1hbmQgYGdldHdkKClgIGF0IHRoZSBSIHByb21wdC4NCg0KICAtIFRoZSB3b3JraW5nIGRpcmVjdG9yeSBjYW4gYmUgY2hhbmdlZCB1c2luZyB0aGUgQ2hhbmdlDQogICAgZGlyLi4uIGNvbW1hbmQgZnJvbSB0aGUgUiBGaWxlIG1lbnUuDQoNCk5vdGUgdGhlIGNvbW1hbmQgYGdldHdkKClgIGlzIGluIHR5cGV3cml0ZXIgZm9udC4gVGhpcyBmb250DQppcyB1c2VkIGluIGxlY3R1cmVzIGZvciBSIGlucHV0IGFuZCBvdXRwdXQgKGFtb25nc3Qgb3RoZXIgdGhpbmdzKS4gVGhlIHBhcmVudGhlc2VzIGFyZSBpbmNsdWRlZCB0byBzaG93IHlvdSB0aGF0IHRoaXMgaXMgYSBjb21tYW5kOyB0eXBpbmcgYGdldHdkYCBhbG9uZSB3aWxsIG5vdCBnaXZlIHlvdSB3aGF0IHlvdSB3YW50IQ0KDQojIyBTYXZlIHlvdXIgd29yayB1c2luZyBzY3JpcHRzIQ0KDQogIC0gUGxlYXNlIGdldCBpbnRvIHRoZSBoYWJpdCBvZiB3cml0aW5nIGFsbCB5b3VyIFIgY29tbWFuZHMgaW4gYQ0KICAgICpSIHNjcmlwdCogYmVmb3JlIHlvdSBydW4gaXQgaW4gdGhlIGNvbnNvbGUuDQoNCiAgLSBBbiBSIHNjcmlwdCBpcyBhIHRleHQgZmlsZSBjb250YWluaW5nIGNvZGUgd2hpY2ggY2FuIGJlIHJ1biBkaXJlY3RseQ0KICAgIGJ5IGhpZ2hsaWdodGluZyB0aGVuIGhpdHRpbmcgYENUUkwtUmAuDQogICAgDQogICAgICAtIENvbW1lbnRzIGZvbGxvd2luZyBgI2Agc3ltYm9scyBpbiBzY3JpcHQgZmlsZXMgYXJlIG5vdCBleGVjdXRlZC4NCg0KICAtIFRvIGNyZWF0ZSBhIG5ldyBzY3JpcHQgdXNlIHRoZSBOZXcgc2NyaXB0IGNvbW1hbmQgZnJvbQ0KICAgIHRoZSBSIEZpbGUgbWVudSBvciBOZXcgRmlsZVw+UiBTY3JpcHQgZnJvbQ0KICAgIHRoZSBSU3R1ZGlvIEZpbGUgbWVudS4NCg0KICAtIFRvIHNhdmUgeW91ciBzY3JpcHQsIGNsaWNrIG9uIHRoZSBzY3JpcHRzIHBhbmUsIGFuZCB0aGVuIGdvIHRvDQogICAgRmlsZSBcPiBTYXZlIEFzIGluIHRoZSBtZW51IGJhci4NCg0KICAtIFNjcmlwdHMgYWxsb3cgeW91IHRvIHJlcnVuIHlvdXIgZW50aXJlIGFuYWx5c2lzIHdpdGhvdXQgcmUtd3JpdGluZw0KICAgIGFsbCB0aGUgY29tbWFuZHMsIGl0IGFsc28gaGVscHMgZWRpdGluZyBhbmQgcHJvb2ZyZWFkaW5nIHlvdXIgY29kZS4NCg0KIyMgTWFuYWdpbmcgWW91ciBDb2RlDQoNCg0KDQohW1NjcmVlbiBzaG90IG9mIFIgU2NyaXB0IGluIFJdKC4uL2dyYXBoaWNzL1JzY3JpcHQuanBnKQ0KDQoNCg0KIVtTY3JlZW4gc2hvdCBvZiBSIFNjcmlwdCBpbiBSU3R1ZGlvXSguLi9ncmFwaGljcy9SU3R1ZGlvc2NyaXB0LnBuZykNCg0KDQojIyBBbiBldmVuIGJldHRlciB3YXkNCg0KUHV0dGluZyB5b3VyIFIgY29tbWFuZHMgaW50byB0aGUgZmlsZSB0aGF0IGJlY29tZXMgeW91ciBlbmQtdXNlIGRvY3VtZW50IHdpbGwgbWFrZSB5b3VyIHdvcmtmbG93IGV2ZW4gbW9yZSBlZmZpY2llbnQuIFdoZW4gd2UgdXNlIFJTdHVkaW8sIHdlIGNhbiBtYWtlIHVzZSBvZiB0aGUgZXh0ZW5zaXZlIGZlYXR1cmVzIHRvIGNyZWF0ZSB0aGVzZSBkb2N1bWVudHMuDQoNCkxvb2sgb3V0IGZvciB0aGUgdHV0b3JpYWwgc2hlZXRzIGludHJvZHVjaW5nIHlvdSB0byB3aGF0IHdlIGNhbGwgKioqUiBtYXJrZG93bioqKiBkb2N1bWVudHMuIFRoZSBsZWN0dXJlIG1hdGVyaWFsIHlvdSBhcmUgdmlld2luZyBub3cgd2FzIHByb2R1Y2VkIHVzaW5nIFIgbWFya2Rvd24uIA0KDQpNb3JlIG9uIHRoaXMgbGF0ZXIuLi4NCg0KIA0KDQojIyBBIEZpcnN0IERpcCBpbnRvIFINCg0KIyMjIEV4cHJlc3Npb25zIGFuZCBBc3NpZ25tZW50cw0KDQpFbGVtZW50YXJ5IGNvbW1hbmRzIGFyZSBlaXRoZXIgKmV4cHJlc3Npb25zKiBvcg0KKmFzc2lnbm1lbnRzKi4NCg0KICAtIEFuICpleHByZXNzaW9uKiBzaW1wbHkgZGlzcGxheXMgcmVzdWx0IG9mIGENCiAgICBjYWxjdWxhdGlvbjsgbm90IHJldGFpbmVkIGluIHRoZSBjb21wdXRlcidzIG1lbW9yeS4NCg0KICAtIEFuICphc3NpZ25tZW50KiBwYXNzZXMgdGhlIHJlc3VsdCBvZiBhIGNhbGN1bGF0aW9uIHRvIGENCiAgICB2YXJpYWJsZSBuYW1lIChvciAnb2JqZWN0Jykgd2hpY2ggaXMgc3RvcmVkOyB0aGUgcmVzdWx0IGlzIG5vdA0KICAgIGRpc3BsYXllZC4NCg0KDQojIyMgRXhhbXBsZXMgKGZvciB5b3UgdG8gdHJ5KQ0KDQpgYGB7cn0NCjMrNA0KYGBgDQoNCi0gVGhlIHN5bWJvbCBgPmAgaXMgdGhlIGNvbW1hbmQgcHJvbXB0LiBUaGlzIGlzIHdoZXJlIHlvdSB3b3VsZCB0eXBlIHRoZSBgMys0YC4gVGhlIGFuc3dlciB3aWxsIGNvbWUgYmFjayB3aGVuIHlvdSBoaXQgdGhlIGA8RW50ZXI+YCBrZXkuDQoNCi0gRG9uJ3Qgd29ycnkgdG9vIG11Y2ggYXQgdGhpcyBzdGFnZSBhYm91dCB0aGUgYFsxXWAuDQoNCmBgYHtyfQ0KeCA8LSAzICsgNA0KeA0KYGBgDQoNCi0gVGhlIGA8LWAgaXMgY2FsbGVkIHRoZSAibGVmdCBhc3NpZ25tZW50IiBvcGVyYXRvciB3aGljaCBhc3NpZ25zIGZyb20gcmlnaHQgKGAzKzRgKSB0byBsZWZ0IChgeGApDQotIFllcywgaXQgdGFrZXMgdHdvIGtleXMgdG8gZ2V0IGl0OyB0aGVyZSBjYW5ub3QgYmUgc3BhY2UgYmV0d2VlbiB0aGUgYDxgIGFuZCB0aGUgYC1gIGFuZCBpdCBpcyBiZXN0IHByYWN0aWNlIHRvIHB1dCBzcGFjZSBvbiBlaXRoZXIgc2lkZSBvZiBgPC1gIGluIHlvdXIgd29yay4NCi0gSXQgaXMgZXF1aXZhbGVudCB0byBgeD0zKzRgLCBidXQgbWFueSBSIHVzZXJzIHByZWZlciB0aGUgYDwtYCBiZWNhdXNlIGl0IGFsd2F5cyBtZWFucyBzb21ldGhpbmcgaXMgY3JlYXRlZCBpbiB5b3VyIHdvcmtzcGFjZS4gKG5vdCBhbHdheXMgdHJ1ZSBmb3IgYD1gKQ0KLSBBIHJpZ2h0IGFzc2lnbm1lbnQgb3BlcmF0b3IgYWxzbyBleGlzdHMgYnV0IGlzIG5vdCBjb21tb25seSB1c2VkLg0KDQojIyBSIE9iamVjdHMNCg0KICAtIEFsbCBhc3NpZ25lZCB2YXJpYWJsZXMgKG9yIGFueSBvdGhlciBSICpvYmplY3RzKikgYXJlDQogICAgc3RvcmVkIHVudGlsIG92ZXJ3cml0dGVuIG9yIGV4cGxpY2l0bHkgcmVtb3ZlZCAoZGVsZXRlZCkgYnkgdGhlDQogICAgY29tbWFuZCBgcm0oKWAuDQoNCiAgLSBUbyBsaXN0IHN0b3JlZCBvYmplY3RzIHR5cGUgYGxzKClgIG9yIGBvYmplY3RzKClgLg0KDQpgYGB7cn0NCnggPC0gOA0KeSA8LSAzLjE0MTUNCmxzKCkNCnJtKHgpDQpvYmplY3RzKCkNCmBgYA0KDQojIyBSIFN5bnRheA0KDQogIC0gUiBjb21tYW5kcywgZS5nLiBgbHMoKWAsIGBybSgpYCwgYXJlIGZvbGxvd2VkIGJ5IHBhcmVudGhlc2VzIHdoaWNoIG1heQ0KICAgIGNvbnRhaW4gYWRkaXRpb25hbCBpbmZvcm1hdGlvbiBmb3IgdGhlIGZ1bmN0aW9uLg0KDQogIC0gV3JpdGluZyBhIGNvbW1hbmQgbmFtZSB3aXRob3V0IHBhcmVudGhlc2VzIHJldHVybnMgdGhlIFIgc291cmNlIGNvZGUNCiAgICBmb3IgdGhlIGZ1bmN0aW9uLiBUcnkgb25lLi4uDQoNCg0KIyMgVmVjdG9ycyBpbiBSDQoNCiAgLSBUaGUgY29tbWFuZCBgYygpYCAoZm9yICpjb25jYXRlbmF0ZSopIGNyZWF0ZXMgdmVjdG9ycy4NCg0KYGBge3J9DQp4IDwtIGMoMi4zLDEuMiwyLjQpDQp4DQpjKHgsOS4wLHgpDQpgYGANCg0KIyMjIFJlZ3VsYXIgU2VxdWVuY2VzDQoNCiAgLSBUaGUgZXhwcmVzc2lvbiBgMTpuYCBkZW5vdGVzIHRoZSAqKnNlcXVlbmNlKioNCjEsIDIsLi4uICpuKi4gDQoNCiAgLSBUaGUgZXhwcmVzc2lvbiBgc2VxKGksaixieT1rKWAgaXMgYSBzZXF1ZW5jZSBmcm9tICppKikgdG8gKmoqIGluDQogICAgc3RlcHMgb2YgKmsqLg0KDQpgYGB7cn0NCjE6NQ0KeSA8LSBzZXEoMywxMCxieT0yKQ0KeQ0KYGBgDQojIyBWZWN0b3IgQXJpdGhtZXRpYyBpbiBSDQoNCi0gUiB1c2VzIGArYCwgYC1gLCBgKmAgYW5kIGAvYCBmb3IgdGhlIGJhc2ljIGFyaXRobWV0aWMNCiAgICBvcGVyYXRpb25zLCBhbmQgYF5gIGZvciBleHBvbmVudGlhdGlvbiAocmFpc2luZyB0byBhIHBvd2VyKS4NCg0KICAtIFZlY3RvciBvcGVyYXRpb25zIGFyZSBkb25lIGVsZW1lbnQgYnkgZWxlbWVudCwgd2l0aA0KICAgIHJlY3ljbGluZyBvZiBzaG9ydCB2ZWN0b3JzIGlmIHJlcXVpcmVkLg0KDQoNCmBgYHtyfQ0KeCA8LSBjKDIsMykNCnkgPC0gYygxLDQsNSw2KQ0KMip4DQoyICsgeA0KeV4yDQp4ICsgeQ0KYGBgDQoNCiMjIFR5cGVzIG9mIHZlY3Rvcg0KDQogIC0gQWxsIHRoZSB2ZWN0b3JzIHdlIGhhdmUgc2VlbiBzbyBmYXIgaGF2ZSBiZWVuDQogICAgKm51bWVyaWMqOyBzb21lIHdlcmUgKmludGVnZXIqIHdoaWNoIGlzIGEgc3BlY2lhbCB0eXBlIG9mIG51bWJlci4NCg0KLSBSIGFsc28gdW5kZXJzdGFuZHMgdmVjdG9ycyBvZjoNCiAgICANCiAgICAgIC0gY2hhcmFjdGVyczogbGV0dGVycywgbnVtZXJhbHMsIHNwYWNlcywgYW5kIG90aGVyIHRleHQuDQogICAgICAtIGxvZ2ljYWwgdmFsdWVzIGBUUlVFYCBhbmQgYEZBTFNFYDsgYWJicmV2aWF0aW9ucyBgVGAsIGBGYCBhcmUgb2Z0ZW4gdXNlZC4NCiAgICAgIC0gZmFjdG9ycyAoaS5lLiBjYXRlZ29yaWNhbCB2YXJpYWJsZXMpOyB0aGVzZSBtYXkgImxvb2siIGxpa2UgY2hhcmFjdGVycy4NCg0KYGBge3J9DQpNeVdvcmRzIDwtIGMoIlRoaXMiLCJpcyIsImEiLCJjaGFyYWN0ZXIiKQ0KTXlXb3Jkcw0KYyhGLFQsRixGKQ0KZmFjdG9yKGMoIkxvdyIsIkxvdyIsIk1lZGl1bSIsIkhpZ2giLCJIaWdoIikpDQpgYGANCg0KTi5CLiBBbGwgb2YgdGhlc2UgZGF0YSB0eXBlcyBjYW4gYmUgdXNlZCBpbiBsaW5lYXIgbW9kZWxzLCBhbHRob3VnaCBjaGFyYWN0ZXIgdmFsdWVzIGFyZSB1c3VhbGx5IGNvbnZlcnRlZCB0byBmYWN0b3JzLg0KDQojIyBMb2dpY2FsIENvbXBhcmlzb25zDQoNCiAgLSBOdW1lcmljYWwgdmVjdG9ycyBjYW4gYmUgY29tcGFyZWQgYnkgaW5lcXVhbGl0aWVzLg0KDQogIC0gYD09YCBkZW5vdGVzIGVxdWFsaXR5OyB0aGUgYD1gIHN0YXRlcyB3aGF0IHNvbWV0aGluZyBpcy4NCg0KICAtIGAhPWAgZGVub3RlcyAnbm90IGVxdWFsJy4NCg0KICAtIGA+YCwgYD49YCBldGMuIGZvciBpbmVxdWFsaXRpZXMuDQoNCg0KYGBge3J9DQooMTo1KSA9PSAoNToxKQ0KKDE6NSkgPiAoNToxKQ0KYGBgDQoNCllvdSBtaWdodCBsaWtlIHRvIHBsYXkgd2l0aCB0aGVzZSBjb21wYXJpc29ucy4gVGVzdGluZyB0aGUgbmVlZCBmb3IgdGhlIGJyYWNrZXRzIGlzICB3b3J0aCB0ZXN0aW5nLg0KDQojIyBJbmRleGluZyBWZWN0b3JzDQoNCiAgLSBUbyBpbmRleCBjb21wb25lbnRzIG9mIGEgdmVjdG9yIGB4YCwgdXNlIHRoZSBmb3JtDQogICAgYHhbLi4uXWAuDQoNCiAgLSBUaGUgc3F1YXJlIGJyYWNrZXRzIGNhbiBjb250YWluOg0KICAgIA0KICAgICAgLSBudW1lcmljIHZlY3RvciBzcGVjaWZ5aW5nIGVsZW1lbnRzOw0KICAgIA0KICAgICAgLSBsb2dpY2FsIHZlY3Rvcjogb25seSBgVFJVRWAgZWxlbWVudHMgcmVxdWlyZWQuDQoNCg0KYGBge3J9DQp4IDwtIGMoMS4xLDMuMiw0LjMsNy40KQ0KeFtjKDIsNCldDQp4Wy0yXQ0KeFt4ID4gMy41XQ0Kd2hpY2goeCA+IDMuNSkNCmBgYA0KDQojIyBEYXRhIEZyYW1lcw0KDQogIC0gQSBkYXRhIGZyYW1lIGlzIGEgY29sbGVjdGlvbiBvZiBjb2x1bW4gdmVjdG9ycyBlYWNoIG9mDQogICAgdGhlIHNhbWUgbGVuZ3RoLg0KDQogIC0gVGhlIHZlY3RvcnMgbWF5IGJlIG51bWVyaWMsIGZhY3Rvciwgb3Igd2hhdGV2ZXIuDQoNCiAgLSBFYWNoIHBhcnRpY3VsYXIgY29sdW1uIGFuZCByb3cgb2YgYSBkYXRhIGZyYW1lIGlzIGdpdmVuIGEgbmFtZSB3aGljaA0KICAgIGNhbiBiZSBjaG9zZW4gYnkgdGhlIHVzZXIsIG9yIGFzc2lnbmVkIGEgZGVmYXVsdCBieSBSLg0KDQoNCmBgYHtyfQ0KZW1wbG95ZWUgPC0gYygiRGlsYmVydCIsICJXYWxseSIsICJDYXRiZXJ0IiwgIlRoZUJvc3MiKQ0Kam9iPC1mYWN0b3IoYygiRW5naW5lZXIiLCJFbmdpbmVlciIsIk1hbmFnZXIiLCJNYW5hZ2VyIikpDQp4IDwtIGMoOCwxLE5BLC0yKQ0KZGlsYmVydCA8LSBkYXRhLmZyYW1lKGVtcGxveWVlLCBqb2IsIGNvbXBldGVuY2U9eCkNCmRpbGJlcnQNCmBgYA0KDQojIyMgQXR0YWNoaW5nIGFuZCBEZXRhY2hpbmcNCg0KICAtIFRvIGFjY2VzcyB2YXJpYWJsZXMgKGNvbHVtbnMpIG9mIGEgZGF0YSBmcmFtZToNCiAgICANCiAgICAgIC0gRmlyc3QgYGF0dGFjaGAgZGF0YSBmcmFtZTsgb3INCiAgICANCiAgICAgIC0gVXNlIGBkYXRhLmZyYW1lJHZhcmlhYmxlYCBzeW50YXguDQoNCmBgYHtyIHNob3dBdHRhY2gsIGVycm9yPVRSVUV9DQpybShlbXBsb3llZSxqb2IseCkgDQpkaWxiZXJ0JGNvbXBldGVuY2UgDQpqb2INCmF0dGFjaChkaWxiZXJ0KQ0Kam9iDQpkZXRhY2goZGlsYmVydCkNCmBgYA0KDQoNCk4uQi4gVXNpbmcgYGF0dGFjaCgpYCB3aXRob3V0IGBkZXRhY2goKWAgY2FuIGxlYWQgdG8gdHJvdWJsZS4gQWxsIGlzIGZpbmUgd2hlbiB0aGluZ3MgYXJlIGRvbmUgY29ycmVjdGx5LCBidXQgdGhlIGNvbnNlcXVlbmNlcyBvZiBub3QgdXNpbmcgdGhlc2UgY29tbWFuZHMgY29ycmVjdGx5IGlzIHNlbGRvbSBzZWVuIGF0IHRoZSB0aW1lIHRoZXkgYXJlIHVzZWQuIFdoZW4gdGhlIGVycm9ycyBjb21lIHVwIGl0IHdpbGwgYmUgZGlmZmljdWx0IHRvIGRpYWdub3NlIHRoZSBwcm9ibGVtLiBJdCBpcyBxdWl0ZSB1bnVzdWFsIHRvIG5lZWQgdG8gdXNlIHRoZXNlIGNvbW1hbmRzIGlmIHlvdSB1c2UgbW9kZXJuIHdheXMgb2Ygd29ya2luZy4gSXQgaXMgaW1wb3J0YW50IHRvIGtub3cgaG93IHRoZSBgYXR0YWNoKClgIGFuZCBgZGV0YWNoKClgIGNvbW1hbmRzIHdvcmssIGJ1dCBkbyBsb29rIHRvIGF2b2lkIHRoZWlyIHVzZS4NCg0KIyMgSW1wb3J0aW5nIERhdGENCg0KLSBUaGUgYHNjYW4oKWAgY29tbWFuZCByZWFkcyBpbiB0ZXh0IGZyb20gYSBmaWxlIGFzIGEgc2luZ2xlIHZhcmlhYmxlLiBZb3Ugc2hvdWxkIHVzZSB0aGlzIGNvbW1hbmQgdmVyeSBpbmZyZXF1ZW50bHkuDQoNCi0gVGhlIGByZWFkLnRhYmxlKClgIGNvbW1hbmQgaXMgbW9yZSBmbGV4aWJsZSwgaW1wb3J0aW5nIGRhdGEgaW4gdGFidWxhciBmb3JtIGFuZCBzdG9yaW5nIHRoZSByZXN1bHQgYXMgYSBkYXRhIGZyYW1lLg0KDQotIG90aGVyIGNvbW1hbmRzIGV4aXN0IGZvciBpbXBvcnRpbmcgYGNzdmAgZmlsZXMsIGFuZCBhIGhvc3Qgb2Ygb3RoZXIgZmlsZSBmb3JtYXRzLg0KDQoNCi0gVGhlIGNvbW1hIHNlcGFyYXRlZCB2YWx1ZXMgKGNzdikgZmlsZSBmb3JtYXQgaXMgZXh0cmVtZWx5IGNvbW1vbiBhbmQgaXMgdXNlZCBvZnRlbiBpbiB0aGUgY291cnNlLiBZb3Ugc2hvdWxkIG5vdCBuZWVkIHRvIHVzZSBgc2NhbigpYCBvciBgcmVhZC50YWJsZSgpYC4NCg0KYGBge3IgZ2V0SUJNRGF0YSwgZXJyb3I9VFJVRSwgZWNobz0tMSwgZXZhbD0tMn0NCklCTSA8LSBzY2FuKGZpbGU9Ii4uLy4uL2RhdGEvaWJtLnR4dCIpDQpJQk0gPC0gc2NhbihmaWxlPSJpYm0udHh0IikNCmlibQ0KSUJNDQpgYGANCg0KTi5CLiBSIGlzIGNhc2Ugc2Vuc2l0aXZlIHNvIGBpYm1gIGlzIGRpZmZlcmVudCB0byBgSUJNYC4gV2luZG93cyBpcyBub3QgY2FzZSBzZW5zaXRpdmUgc28gdGhlIGZpbGVuYW1lIGNhbiBiZSBtaXNzcGVjaWZpZWQgd2l0aG91dCBhbnkgdHJvdWJsZTsgb3RoZXIgb3BlcmF0aW5nIHN5c3RlbXMgYXJlIGNhc2Ugc2Vuc2l0aXZlIHRob3VnaC4gDQoNCg0KYGBge3IgZ2V0TGlmZURhdGEsIGVycm9yPVRSVUV9DQpMaWZlIDwtIHJlYWQuY3N2KGZpbGU9Ii4uLy4uL2RhdGEvbGlmZS5jc3YiLCBoZWFkZXI9VFJVRSkNCmhlYWQoTGlmZSkgIyBzaG93cyBvbmx5IHRoZSBmaXJzdCBzaXggcm93cw0KYGBgDQoNClRoZSBgLi4vLi4vZGF0YS9gIGluIHRoaXMgY29tbWFuZCBpcyBjYWxsZWQgYSByZWxhdGl2ZSBmaWxlIHBhdGguIFRoZSBgLi5gIG1lYW5zIHRvIGxvb2sgdXAgb25lIGxldmVsIGZyb20gdGhlIGN1cnJlbnQgd29ya2luZyBkaXJlY3Rvcnk7IHRoZSAgZmlsZSByZXF1ZXN0ZWQgaXMgaW4gYSBzdWJmb2xkZXIgY2FsbGVkIGBkYXRhYDsgdGhlIGAvYCBpcyBob3cgd2Ugc2VwYXJhdGUgZm9sZGVycyBmcm9tIHN1YmZvbGRlcnMgb3IgZmlsZW5hbWVzLiBUaGlzIG1heSBzZWVtIHN0cmFuZ2UgdG8gV2luZG93cyB1c2VycyB3aG8gd2FudCB0byB1c2UgYSBiYWNrc2xhc2ggaW5zdGVhZC4gR2V0IHVzZWQgdG8gdXNpbmcgdGhlIGZvcndhcmQgc2xhc2ggaW4gUiBiZWNhdXNlIGl0IHdvcmtzIGZvciBhbGwgb3BlcmF0aW5nIHN5c3RlbXMuDQoNClRoZSBgcmVhZC5jc3YoKWAgY29tbWFuZCBtYWtlcyBhIG51bWJlciBvZiBhc3N1bXB0aW9ucyBhYm91dCB0aGUgd2F5IHRoZSBmaWxlIGlzIGZvcm1hdHRlZC4gQSBgY3N2YCBmaWxlIGlzIGFjdHVhbGx5IHBsYWluIHRleHQgd2l0aCBjb21tYXMgYmV0d2VlbiB2YWx1ZXMuIFNvbWUgcGVvcGxlIHRoaW5rIGl0IGlzIGEgTVMgRXhjZWwgZmlsZSwgYnV0IGNzdiBmaWxlcyBleGlzdGVkIGxvbmcgYmVmb3JlIEV4Y2VsLg0KIA0KIyMgRWRpdGluZyBEYXRhDQoNCiAgLSBDYW4gZWRpdCBieSByZWFzc2lnbmluZyBlbGVtZW50cyBvZiBhIHZlY3RvciBvciBkYXRhIGZyYW1lLg0KDQogIC0gRm9yIGRhdGEgZnJhbWUgb3IgbWF0cml4LCBgQVtpLGpdYCBpcyB0aGUgKmksaipedGheIGVsZW1lbnQgKHJvdw0KICAgICppKiwgY29sdW1uICpqKikgb2YgdGhlIGRhdGEgZnJhbWUgYEFgLg0KDQoNCg0KYGBge3J9DQpJQk1bNV0NCklCTVs1XSA8LSA2NS4xMg0KSUJNWzVdDQpMaWZlWzIsXQ0KTGlmZVsyLDRdDQpMaWZlWzIsNF0gPC0gNzE2Ng0KYGBgDQoNCiMjIFIgUGFja2FnZXMNCg0KICAtIFIgb2JqZWN0cyAoZnVuY3Rpb25zLCBkYXRhIGV0Yy4pIGFyZSBvcmdhbml6ZWQgaW4NCiAgICBsaWJyYXJpZXMvcGFja2FnZXMuDQoNCiAgLSBTb21lIGFyZSBsb2FkZWQgYnkgZGVmYXVsdCB3aGVuIFIgc3RhcnRzIGVhY2ggdGltZS4NCiAgICANCiAgICAgIC0gRS5nLiBmdW5jdGlvbiBgbHMoKWAgaXMgcGFydCBvZiB0aGUgYGJhc2VgIHBhY2thZ2UgdGhhdCBpcw0KICAgICAgICBhdXRvbWF0aWNhbGx5IGxvYWRlZCwNCg0KICAtIFNvbWUgcGFja2FnZXMgbmVlZCBsb2FkaW5nLCB1c2luZyBlaXRoZXIgdGhlIGBsaWJyYXJ5KClgIG9yIGByZXF1aXJlKClgIGNvbW1hbmQuDQoNCmBgYHtyIHNob3dNaXNzaW5nRnVuLCBlcnJvcj1UUlVFfQ0KbXZybm9ybSgxLG11PTAsU2lnbWE9MSkNCmxpYnJhcnkoTUFTUykNCm12cm5vcm0oMSxtdT0wLFNpZ21hPTEpDQpgYGANCg0KIyMgU29tZSBSIEZ1bmN0aW9ucyB0byBHZXQgWW91IFN0YXJ0ZWQNCg0KICAtIGBoZWxwKClgIGFjY2Vzc2VzIFIncyBoZWxwIHN5c3RlbTsgZS5nLiBgaGVscChscylgLiBBIHF1aWNrZXIgd2F5IGlzIHRvIHVzZSBgP2xzYA0KDQogIC0gYG1lYW4oKWAsIGBzZCgpYCwgYG1pbigpYCwgYG1heCgpYCBhbmQgYHJhbmdlKClgIGdpdmUgbWVhbiwgc3RhbmRhcmQNCiAgICBkZXZpYXRpb24sIG1pbmltdW0sIG1heGltdW0gYW5kIHJhbmdlIHJlc3BlY3RpdmVseSBmb3IgYSB2ZWN0b3INCiAgICBhcmd1bWVudC4gTi5CLiBgcmFuZ2UoKWAgdGVsbHMgeW91IHRoZSBtaW5pbXVtIGFuZCBtYXhpbXVtIGFzIGEgcGFpciwgbm90IHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlbS4NCg0KICAtIGB2YXIoKWAgcmV0dXJucyB2YXJpYW5jZSBvZiBhIHZlY3RvciBhcmd1bWVudCwgb3IgdGhlIGNvdmFyaWFuY2UNCiAgICAoZGlzcGVyc2lvbikgbWF0cml4IGZvciBhIG1hdHJpeCBhcmd1bWVudC4NCg0KICAtIGBzdW1tYXJ5KClgIHJldHVybnMgc3VtbWFyeSBpbmZvcm1hdGlvbiBkZXBlbmRlbnQgb24gYXJndW1lbnQgdHlwZS4NCg0KICAtIGBwbG90KClgIHByb2R1Y2VzIGEgcGxvdCBvbiB0aGUgY3VycmVudCBncmFwaGljcyB0b29sLiBUaGUgdHlwZSBvZg0KICAgIHBsb3QgZGVwZW5kcyBvbiB0aGUgdHlwZSBvZiBhcmd1bWVudC4gVGhlIHNpbXBsZXN0IHVzZSBpcyBgcGxvdCh4LHkpYCB3aGljaA0KICAgIHByb2R1Y2VzIGEgc2NhdHRlci1wbG90IG9mIHZlY3RvcnMgYHhgIGFuZCBgeWAuDQoNClByYWN0aWNlIGlzIHRoZSBrZXkgd2hlbiBsZWFybmluZyBSLg0KDQojIyBZb3VyIEZpcnN0IFIgRXhlcmNpc2UNCg0KMS4gIFVzZSBSIHRvIGNhbGN1bGF0ZSAgIA0KICAgIChpKSAzNDU2LTc4OQ0KICAgIChpaSkgJDIzXHRpbWVze30zNCQNCiAgICAoaWlpKSAxM14zXg0KDQoyLiAgV3JpdGUgKGVmZmljaWVudCkgY29kZSB0byBjcmVhdGUgdGhlIGZvbGxvd2luZyBzZXF1ZW5jZXM6DQogICAgDQogICAgKGkpIDIsIDQsIDYsIC4uLiAxMDA7IHRoYXQgaXMsIHRoZSBldmVuIG51bWJlcnMgdXAgdG8gMTAwDQogICAgDQogICAgKGlpKSAxLDIsMyw0LDUsNCwzLDIsMQ0KDQozLiAgVXNlIHRoZSBjb21tYW5kIGB5IDwtIHJub3JtKDEwMClgIHRvIHN0b3JlIDEwMCBzaW11bGF0ZWQNCiAgICBzdGFuZGFyZCBub3JtYWwgcmFuZG9tIHZhcmlhYmxlcyBpbiB0aGUgdmVjdG9yIGB5YC4NCiAgICANCiAgICAoaSkgRmluZCB0aGUgbWVhbiBhbmQgc3RhbmRhcmQgZGV2aWF0aW9uIG9mIGB5YC4NCiAgICANCiAgICAoaWkpIEZpbmQgdGhlIGxhcmdlc3Qgc2ltdWxhdGVkIHZhbHVlLiBXaGljaCBudW1iZXIgc2ltdWxhdGlvbiBpcyB0aGlzIGUuZy4gNTRedGheLCAyM15yZF4/DQo=