View the latest recording of this lecture

library(MASS)

Attaching package: 'MASS'
The following object is masked from 'package:dplyr':

    select

In this lecture we will look at:

What is R?

A Little R History

photo of Ross Ihaka photo of Robert Gentleman

Ross Ihaka (left) and Robert Gentleman.

Starting R in the Computing Labs

RGUI v3.3.0
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

RStudio using R 3.4.1
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

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!

Managing Your Code

Screen shot of R Script in R
Screen shot of R Script in R
Screen shot of R Script in RStudio
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
  • The symbol > is the command prompt. This is where you would type the 3+4. The answer will come back when you hit the <Enter> key.

  • Don’t worry too much at this stage about the [1].

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] "A"               "A.mat"           "B.mat"           "Caffeine"       
  [5] "Caffeine.bt"     "Caffeine.lm"     "Caffeine.lm0"    "Caffeine.lm2"   
  [9] "Caffeine.lv"     "Caffeine.M0"     "Caffeine.M1"     "climate"        
 [13] "Climate"         "climate.full"    "Climate.lm0"     "Climate.lm00"   
 [17] "climate.lm1"     "Climate.lm1"     "Climate.lm1.sum" "climate.lm2"    
 [21] "Climate.lm2"     "climate.lm3"     "Climate.lm3"     "climate.lm4"    
 [25] "Climate.lm4"     "climate.lm5"     "Climate.lm5"     "climate.lm6"    
 [29] "Climate.lm6"     "climate.null"    "climate.s1"      "climate.s2"     
 [33] "climate.step"    "climate.step2"   "Coeffs"          "Cows"           
 [37] "Cows.lm.1"       "Cows.lm.2"       "cps.wls"         "cps.wls2"       
 [41] "CPS5"            "cps5.lm"         "CPS5grouped"     "CPS5weighted"   
 [45] "D.mat"           "dat"             "e"               "elec.lm1"       
 [49] "elec.lm2"        "elec.lm3"        "elec.lm4"        "elec.lm5"       
 [53] "electric"        "electric.lm0"    "English"         "English.lm1"    
 [57] "English.lm2"     "f"               "Fat"             "Fat.lm.0"       
 [61] "Fat.lm.1"        "Fat.lm.2"        "Fev"             "Fev.lm.4"       
 [65] "Fev.lm.5"        "Fev.lm.6"        "Fev.lm.poly"     "Fev.lm4"        
 [69] "Fev.lm6"         "Fev.pce1"        "grouped.lm"      "Hills"          
 [73] "Hills.lm"        "Hospital"        "Hospital.lm"     "i"              
 [77] "Indy"            "Indy.pce0"       "Indy.pce1"       "Indy.pce2"      
 [81] "k"               "Knot1"           "Knot2"           "Lions"          
 [85] "Lions.lm1"       "Lions.lm2"       "lm.cor"          "lm.uncor"       
 [89] "lm1"             "lm2"             "lm3"             "lm4"            
 [93] "lm5"             "lm6"             "MyTable"         "newdat"         
 [97] "NSrent"          "Outfile"         "PrettyPVal"      "PulseData"      
[101] "Rat"             "Rat.lm.1"        "Rat.lm.2"        "RatDiet"        
[105] "RatDiet.lm"      "Samara"          "Samara.lm"       "Samara.lm.m0"   
[109] "Samara.lm.m1"    "Samara.lm.m2"    "Samara.lm2"      "SAP"            
[113] "SAP.lm"          "SAP.lm2"         "SAP.lm3"         "SAPA.lm"        
[117] "scope"           "sim"             "sim_final"       "sim_rand"       
[121] "sup.lm"          "sup.wls"         "supervisors"     "TG"             
[125] "tmc"             "Tooth.lm.0"      "Tooth.lm.1"      "ToothGrowth"    
[129] "Tourism"         "Tourism.gls"     "Tourism.lm"      "Tourism.lm.2"   
[133] "x"               "X1"              "X2"              "y"              
[137] "y1"              "y2"              "y3"              "y4"             
[141] "Z1"              "z2"              "z3"             
rm(x)
objects()
  [1] "A"               "A.mat"           "B.mat"           "Caffeine"       
  [5] "Caffeine.bt"     "Caffeine.lm"     "Caffeine.lm0"    "Caffeine.lm2"   
  [9] "Caffeine.lv"     "Caffeine.M0"     "Caffeine.M1"     "climate"        
 [13] "Climate"         "climate.full"    "Climate.lm0"     "Climate.lm00"   
 [17] "climate.lm1"     "Climate.lm1"     "Climate.lm1.sum" "climate.lm2"    
 [21] "Climate.lm2"     "climate.lm3"     "Climate.lm3"     "climate.lm4"    
 [25] "Climate.lm4"     "climate.lm5"     "Climate.lm5"     "climate.lm6"    
 [29] "Climate.lm6"     "climate.null"    "climate.s1"      "climate.s2"     
 [33] "climate.step"    "climate.step2"   "Coeffs"          "Cows"           
 [37] "Cows.lm.1"       "Cows.lm.2"       "cps.wls"         "cps.wls2"       
 [41] "CPS5"            "cps5.lm"         "CPS5grouped"     "CPS5weighted"   
 [45] "D.mat"           "dat"             "e"               "elec.lm1"       
 [49] "elec.lm2"        "elec.lm3"        "elec.lm4"        "elec.lm5"       
 [53] "electric"        "electric.lm0"    "English"         "English.lm1"    
 [57] "English.lm2"     "f"               "Fat"             "Fat.lm.0"       
 [61] "Fat.lm.1"        "Fat.lm.2"        "Fev"             "Fev.lm.4"       
 [65] "Fev.lm.5"        "Fev.lm.6"        "Fev.lm.poly"     "Fev.lm4"        
 [69] "Fev.lm6"         "Fev.pce1"        "grouped.lm"      "Hills"          
 [73] "Hills.lm"        "Hospital"        "Hospital.lm"     "i"              
 [77] "Indy"            "Indy.pce0"       "Indy.pce1"       "Indy.pce2"      
 [81] "k"               "Knot1"           "Knot2"           "Lions"          
 [85] "Lions.lm1"       "Lions.lm2"       "lm.cor"          "lm.uncor"       
 [89] "lm1"             "lm2"             "lm3"             "lm4"            
 [93] "lm5"             "lm6"             "MyTable"         "newdat"         
 [97] "NSrent"          "Outfile"         "PrettyPVal"      "PulseData"      
[101] "Rat"             "Rat.lm.1"        "Rat.lm.2"        "RatDiet"        
[105] "RatDiet.lm"      "Samara"          "Samara.lm"       "Samara.lm.m0"   
[109] "Samara.lm.m1"    "Samara.lm.m2"    "Samara.lm2"      "SAP"            
[113] "SAP.lm"          "SAP.lm2"         "SAP.lm3"         "SAPA.lm"        
[117] "scope"           "sim"             "sim_final"       "sim_rand"       
[121] "sup.lm"          "sup.wls"         "supervisors"     "TG"             
[125] "tmc"             "Tooth.lm.0"      "Tooth.lm.1"      "ToothGrowth"    
[129] "Tourism"         "Tourism.gls"     "Tourism.lm"      "Tourism.lm.2"   
[133] "X1"              "X2"              "y"               "y1"             
[137] "y2"              "y3"              "y4"              "Z1"             
[141] "z2"              "z3"             

R Syntax

Vectors in R

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

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

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

(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

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

  • To access variables (columns) of a data frame:

    • First attach data frame; or

    • Use data.frame$variable syntax.

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

## 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

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

mvrnorm(1, mu = 0, Sigma = 1)
[1] 0.2727256
library(MASS)
mvrnorm(1, mu = 0, Sigma = 1)
[1] -0.9755279

Some R Functions to Get You Started

Practice is the key when learning R.

Your First R Exercise

  1. Use R to calculate

    1. 3456-789
    2. \(23\times{}34\)
    3. 133
  2. Write (efficient) code to create the following sequences:

    1. 2, 4, 6, … 100; that is, the even numbers up to 100

    2. 1,2,3,4,5,4,3,2,1

  3. Use the command y <- rnorm(100) to store 100 simulated standard normal random variables in the vector y.

    1. Find the mean and standard deviation of y.

    2. Find the largest simulated value. Which number simulation is this e.g. 54th, 23rd?

LS0tDQp0aXRsZTogIkxlY3R1cmUgNDE6IEFwcGVuZGl4OiBJbnRyb2R1Y3Rpb24gdG8gUiBhbmQgUlN0dWRpbyINCnN1YnRpdGxlOiAxNjEuMjUxIFJlZ3Jlc3Npb24gTW9kZWxsaW5nDQphdXRob3I6ICJQcmVzZW50ZWQgYnkgSm9uYXRoYW4gR29kZnJleSA8YS5qLmdvZGZyZXlAbWFzc2V5LmFjLm56PiIgIA0KZGF0ZTogIldlZWsgMSBvZiBTZW1lc3RlciAyLCBgciBsdWJyaWRhdGU6OnllYXIobHVicmlkYXRlOjpub3coKSlgIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICB0aGVtZTogeWV0aQ0KICAgIGhpZ2hsaWdodDogdGFuZ28NCiAgaHRtbF9ub3RlYm9vazoNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgdGhlbWU6IHlldGkNCiAgICBoaWdobGlnaHQ6IHRhbmdvDQogIGlvc2xpZGVzX3ByZXNlbnRhdGlvbjoNCiAgICB3aWRlc2NyZWVuOiB0cnVlDQogICAgc21hbGxlcjogdHJ1ZQ0KICB3b3JkX2RvY3VtZW50OiBkZWZhdWx0DQogIHNsaWR5X3ByZXNlbnRhdGlvbjogDQogICAgdGhlbWU6IHlldGkNCiAgICBoaWdobGlnaHQ6IHRhbmdvDQogIHBkZl9kb2N1bWVudDogZGVmYXVsdA0KLS0tDQoNCg0KDQoNCg0KW1ZpZXcgdGhlIGxhdGVzdCByZWNvcmRpbmcgb2YgdGhpcyBsZWN0dXJlXShodHRwczovL1ItUmVzb3VyY2VzLm1hc3NleS5hYy5uei92aWRlb3MvMjUxTDMzLm1wNCkNCjwhLS0tIERhdGEgaXMgb24NCmh0dHBzOi8vci1yZXNvdXJjZXMubWFzc2V5LmFjLm56L2RhdGEvMTYxMjUxLw0KLS0tPg0KDQpgYGB7ciBzZXR1cCwgcHVybD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0NCmxpYnJhcnkoa25pdHIpDQpvcHRzX2NodW5rJHNldChkZXY9YygicG5nIiwgInBkZiIpKQ0Kb3B0c19jaHVuayRzZXQoZmlnLmhlaWdodD02LCBmaWcud2lkdGg9NywgZmlnLnBhdGg9IkZpZ3VyZXMvIiwgZmlnLmFsdD0idW5sYWJlbGxlZCIpDQpvcHRzX2NodW5rJHNldChjb21tZW50PSIiLCBmaWcuYWxpZ249ImNlbnRlciIsIHRpZHk9VFJVRSkNCm9wdGlvbnMoa25pdHIua2FibGUuTkEgPSAnJykNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShicm9vbSkNCmBgYA0KDQoNCjwhLS0tIERvIG5vdCBlZGl0IGFueXRoaW5nIGFib3ZlIHRoaXMgbGluZS4gLS0tPg0KDQpgYGB7ciBleHRyYUxpYnN9DQpsaWJyYXJ5KE1BU1MpDQpgYGANCg0KDQpJbiB0aGlzIGxlY3R1cmUgd2Ugd2lsbCBsb29rIGF0Og0KDQogIC0gV2hhdCBpcyBSPw0KDQogIC0gQmFzaWMgUiBzeW50YXgNCg0KLSBVc2Ugb2YgUiB2aWEgUlN0dWRpby4NCg0KDQojIyBXaGF0IGlzIFI/DQoNCiAgLSBSIGlzIGEgc3RhdGlzdGljYWwgc29mdHdhcmUgc3lzdGVtLg0KDQogIC0gUiBpcyBhIHByb2dyYW1taW5nIGxhbmd1YWdlIHRoYXQgaGFzIG1hbnkgImluYnVpbHQiIHN0YXRpc3RpY2FsDQogICAgY29tbWFuZHMgKGUuZy4gdG8gZml0IGEgbGluZWFyIHJlZ3Jlc3Npb24pLg0KDQogIC0gUiBzdGFydGVkIGxpZmUgYXMgYSBxdWFzaS1jbG9uZSBvZiBjb21tZXJjaWFsIHBhY2thZ2UgUy1QbHVzLCBidXQNCiAgICBkZXZlbG9wbWVudCBvZiBSIGFuZCBTLVBsdXMgbm93IHNsb3dseSBkaXZlcmdpbmcuDQoNCiAgLSBBZHZhbnRhZ2VzIG92ZXIgb3RoZXIgc3RhdGlzdGljcyBwYWNrYWdlcyBpbmNsdWRlIGZsZXhpYmlsaXR5LA0KICAgIHBvd2VyLCBhbmQgcXVhbGl0eSBvZiBncmFwaGljYWwgZGlzcGxheS4NCg0KICAtIFIgaXMgb3Blbi1zb3VyY2Ugc29mdHdhcmUsIGFuZCBwYXJ0IG9mIEdOVSBwcm9qZWN0LiBJdCBjYW4gYmUNCiAgICBkb3dubG9hZGVkIGZyb20gYGh0dHA6Ly9jcmFuLnItcHJvamVjdC5vcmcvYCBhbmQgdXNlZCBmb3IgZnJlZS4NCg0KICAtIFRoZXJlIGFyZSB2ZXJzaW9ucyBvZiBSIGZvciBhbGwgY29tbW9uIG9wZXJhdGluZyBzeXN0ZW1zIC0tLSBXaW5kb3dzLCBMaW51eCwgYW5kIE1hY09TLg0KDQojIyBBIExpdHRsZSBSIEhpc3RvcnkNCg0KfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KfCA6LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS06IHwgOi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLTogfA0KfCAhW3Bob3RvIG9mIFJvc3MgSWhha2FdKC4uL2dyYXBoaWNzL2loYWthLmpwZykgfCAhW3Bob3RvIG9mIFJvYmVydCBHZW50bGVtYW5dKC4uL2dyYXBoaWNzL2dlbnRsZW1hbi5qcGcpIHwNCg0KICANCiBSb3NzIEloYWthIChsZWZ0KSBhbmQgUm9iZXJ0IEdlbnRsZW1hbi4NCg0KICAtIFIgaXMgYSBOZXcgWmVhbGFuZCBpbnZlbnRpb25cIQ0KDQogIC0gUiBvcmlnaW5hbGx5IGRldmVsb3BlZCBieSBSb3NzIEloYWthIGFuZCBSb2JlcnQgR2VudGxlbWFuIGluIHRoZQ0KICAgIERlcGFydG1lbnQgb2YgU3RhdGlzdGljcywgVW5pdmVyc2l0eSBvZiBBdWNrbGFuZC4NCg0KICAtIEZpcnN0ICh0ZXN0KSB2ZXJzaW9uIG9mIFIgcmVsZWFzZWQgaW4gcHVibGljIGRvbWFpbiBpbiAxOTk1Lg0KDQogIC0gUiBEZXZlbG9wbWVudCBDb3JlIFRlYW0gdG9vayBvdmVyIHN1cGVydmlzaW9uIG9mIFIgaW4gMTk5Ny4NCg0KIC0gVGhpcyBUZWFtIGluY2x1ZGVzIGFib3V0IDIwIHN0YXRpc3RpY2lhbnMgd29ybGR3aWRlLg0KDQojIyBTdGFydGluZyBSIGluIHRoZSBDb21wdXRpbmcgTGFicw0KDQotIFN0YXJ0IFIgZm9yIHRoZSBmaXJzdCB0aW1lIHZpYSB0aGUgU3RhcnQgbWVudSAob3IgZGVza3RvcCBpY29uIGlmIGF2YWlsYWJsZSkuDQotIFNlbGVjdCBSICh2ZXJzaW9uIGByIHZlcnNpb24kbWFqb3JgKSBmcm9tIHRoZSBhcHByb3ByaWF0ZSBwcm9ncmFtIGdyb3VwLg0KLSBSR3VpICgqKlIgRyoqcmFwaGljYWwgKipVKipzZXIgKipJKipudGVyZmFjZSkgc2hvdWxkIGFwcGVhciBhcyBkaXNwbGF5ZWQuDQoNCiFbUkdVSSB2My4zLjBdKC4uL2dyYXBoaWNzL1JHdWkuanBnKQ0KDQpOLkIuIENoZWNrIHRoZSB2ZXJzaW9uIG51bWJlci4gSWRlYWxseSB3ZSB3YW50IHRvIGJlIHN1cmUgdGhhdCB3ZSBhcmUgcnVubmluZyB0aGUgbGF0ZXN0IHZlcnNpb24sIGJ1dCBkbyBub3QgY2hhbmdlIHZlcnNpb25zIHBhcnR3YXkgdGhyb3VnaCB0aGUgc2VtZXN0ZXIgdW5sZXNzIGl0IGlzIHRydWx5IG5lY2Vzc2FyeS4NCg0KIyMgU3RhcnRpbmcgUlN0dWRpbyBpbiB0aGUgQ29tcHV0aW5nIExhYnMNCg0KLSBTdGFydCBSU3R1ZGlvIGZvciB0aGUgZmlyc3QgdGltZSB2aWEgdGhlIFN0YXJ0IG1lbnUgKG9yIGRlc2t0b3AgaWNvbiBpZiBhdmFpbGFibGUpLg0KLSBZb3Ugc2hvdWxkIHNlZSB0aGUgd2luZG93IHNwbGl0IGludG8gc3ViLXdpbmRvd3MuIFBsZWFzZSBub3RlIHRoYXQgUlN0dWRpbyBpcyB1bmRlcmdvaW5nIGNvbnN0YW50IGRldmVsb3BtZW50LiBZb3VyIHZlcnNpb24gbWF5IG5vdCBsb29rIHF1aXRlIGxpa2UgdGhlIGltYWdlICBkaXNwbGF5ZWQgYmVsb3cuDQoNCg0KIVtSU3R1ZGlvIHVzaW5nIFIgMy40LjFdKC4uL2dyYXBoaWNzL1JTdHVkaW8ucG5nKSANCg0KTi5CLiB0aGUgY29udGVudHMgb2YgdGhlIFJHVUkgYXJlIGFsbCBhdmFpbGFibGUgaW4gUlN0dWRpby4gV2Ugd2lsbCB3b3JrIGluIFJTdHVkaW8gYmVjYXVzZSBpdCBvZmZlcnMgbWFueSBleHRyYSBmZWF0dXJlcy4NCg0KDQojIyBXb3JraW5nIGRpcmVjdG9yeQ0KDQogIC0gV2hlbiB5b3UgcXVpdCBSIHlvdSB3aWxsIGdldCBhIHBvcC11cCBhc2tpbmcgIlNhdmUgd29ya3NwYWNlDQogICAgaW1hZ2U/Ii4NCg0KICAtIElmIHlvdSBjbGljayB5ZXMsIHRoZW4gdGhlICpSIHdvcmtzcGFjZSogdGhhdCB5b3UgaGF2ZQ0KICAgIGNyZWF0ZWQgd2lsbCBiZSBzYXZlZCBpbiB5b3VyICp3b3JraW5nIGRpcmVjdG9yeSouDQoNCiAgLSBZb3UgY2FuIGZpbmQgb3V0IHdoZXJlIHlvdXIgd29ya2luZyBkaXJlY3RvcnkgaXMgYnkgdHlwaW5nIHRoZQ0KICAgIGNvbW1hbmQgYGdldHdkKClgIGF0IHRoZSBSIHByb21wdC4NCg0KICAtIFRoZSB3b3JraW5nIGRpcmVjdG9yeSBjYW4gYmUgY2hhbmdlZCB1c2luZyB0aGUgQ2hhbmdlDQogICAgZGlyLi4uIGNvbW1hbmQgZnJvbSB0aGUgUiBGaWxlIG1lbnUuDQoNCk5vdGUgdGhlIGNvbW1hbmQgYGdldHdkKClgIGlzIGluIHR5cGV3cml0ZXIgZm9udC4gVGhpcyBmb250DQppcyB1c2VkIGluIGxlY3R1cmVzIGZvciBSIGlucHV0IGFuZCBvdXRwdXQgKGFtb25nc3Qgb3RoZXIgdGhpbmdzKS4gVGhlIHBhcmVudGhlc2VzIGFyZSBpbmNsdWRlZCB0byBzaG93IHlvdSB0aGF0IHRoaXMgaXMgYSBjb21tYW5kOyB0eXBpbmcgYGdldHdkYCBhbG9uZSB3aWxsIG5vdCBnaXZlIHlvdSB3aGF0IHlvdSB3YW50IQ0KDQojIyBTYXZlIHlvdXIgd29yayB1c2luZyBzY3JpcHRzIQ0KDQogIC0gUGxlYXNlIGdldCBpbnRvIHRoZSBoYWJpdCBvZiB3cml0aW5nIGFsbCB5b3VyIFIgY29tbWFuZHMgaW4gYQ0KICAgICpSIHNjcmlwdCogYmVmb3JlIHlvdSBydW4gaXQgaW4gdGhlIGNvbnNvbGUuDQoNCiAgLSBBbiBSIHNjcmlwdCBpcyBhIHRleHQgZmlsZSBjb250YWluaW5nIGNvZGUgd2hpY2ggY2FuIGJlIHJ1biBkaXJlY3RseQ0KICAgIGJ5IGhpZ2hsaWdodGluZyB0aGVuIGhpdHRpbmcgYENUUkwtUmAuDQogICAgDQogICAgICAtIENvbW1lbnRzIGZvbGxvd2luZyBgI2Agc3ltYm9scyBpbiBzY3JpcHQgZmlsZXMgYXJlIG5vdCBleGVjdXRlZC4NCg0KICAtIFRvIGNyZWF0ZSBhIG5ldyBzY3JpcHQgdXNlIHRoZSBOZXcgc2NyaXB0IGNvbW1hbmQgZnJvbQ0KICAgIHRoZSBSIEZpbGUgbWVudSBvciBOZXcgRmlsZVw+UiBTY3JpcHQgZnJvbQ0KICAgIHRoZSBSU3R1ZGlvIEZpbGUgbWVudS4NCg0KICAtIFRvIHNhdmUgeW91ciBzY3JpcHQsIGNsaWNrIG9uIHRoZSBzY3JpcHRzIHBhbmUsIGFuZCB0aGVuIGdvIHRvDQogICAgRmlsZSBcPiBTYXZlIEFzIGluIHRoZSBtZW51IGJhci4NCg0KICAtIFNjcmlwdHMgYWxsb3cgeW91IHRvIHJlcnVuIHlvdXIgZW50aXJlIGFuYWx5c2lzIHdpdGhvdXQgcmUtd3JpdGluZw0KICAgIGFsbCB0aGUgY29tbWFuZHMsIGl0IGFsc28gaGVscHMgZWRpdGluZyBhbmQgcHJvb2ZyZWFkaW5nIHlvdXIgY29kZS4NCg0KIyMgTWFuYWdpbmcgWW91ciBDb2RlDQoNCg0KDQohW1NjcmVlbiBzaG90IG9mIFIgU2NyaXB0IGluIFJdKC4uL2dyYXBoaWNzL1JzY3JpcHQuanBnKQ0KDQoNCg0KIVtTY3JlZW4gc2hvdCBvZiBSIFNjcmlwdCBpbiBSU3R1ZGlvXSguLi9ncmFwaGljcy9SU3R1ZGlvc2NyaXB0LnBuZykNCg0KDQojIyBBbiBldmVuIGJldHRlciB3YXkNCg0KUHV0dGluZyB5b3VyIFIgY29tbWFuZHMgaW50byB0aGUgZmlsZSB0aGF0IGJlY29tZXMgeW91ciBlbmQtdXNlIGRvY3VtZW50IHdpbGwgbWFrZSB5b3VyIHdvcmtmbG93IGV2ZW4gbW9yZSBlZmZpY2llbnQuIFdoZW4gd2UgdXNlIFJTdHVkaW8sIHdlIGNhbiBtYWtlIHVzZSBvZiB0aGUgZXh0ZW5zaXZlIGZlYXR1cmVzIHRvIGNyZWF0ZSB0aGVzZSBkb2N1bWVudHMuDQoNCkxvb2sgb3V0IGZvciB0aGUgdHV0b3JpYWwgc2hlZXRzIGludHJvZHVjaW5nIHlvdSB0byB3aGF0IHdlIGNhbGwgKioqUiBtYXJrZG93bioqKiBkb2N1bWVudHMuIFRoZSBsZWN0dXJlIG1hdGVyaWFsIHlvdSBhcmUgdmlld2luZyBub3cgd2FzIHByb2R1Y2VkIHVzaW5nIFIgbWFya2Rvd24uIA0KDQpNb3JlIG9uIHRoaXMgbGF0ZXIuLi4NCg0KIA0KDQojIyBBIEZpcnN0IERpcCBpbnRvIFINCg0KIyMjIEV4cHJlc3Npb25zIGFuZCBBc3NpZ25tZW50cw0KDQpFbGVtZW50YXJ5IGNvbW1hbmRzIGFyZSBlaXRoZXIgKmV4cHJlc3Npb25zKiBvcg0KKmFzc2lnbm1lbnRzKi4NCg0KICAtIEFuICpleHByZXNzaW9uKiBzaW1wbHkgZGlzcGxheXMgcmVzdWx0IG9mIGENCiAgICBjYWxjdWxhdGlvbjsgbm90IHJldGFpbmVkIGluIHRoZSBjb21wdXRlcidzIG1lbW9yeS4NCg0KICAtIEFuICphc3NpZ25tZW50KiBwYXNzZXMgdGhlIHJlc3VsdCBvZiBhIGNhbGN1bGF0aW9uIHRvIGENCiAgICB2YXJpYWJsZSBuYW1lIChvciAnb2JqZWN0Jykgd2hpY2ggaXMgc3RvcmVkOyB0aGUgcmVzdWx0IGlzIG5vdA0KICAgIGRpc3BsYXllZC4NCg0KDQojIyMgRXhhbXBsZXMgKGZvciB5b3UgdG8gdHJ5KQ0KDQpgYGB7cn0NCjMrNA0KYGBgDQoNCi0gVGhlIHN5bWJvbCBgPmAgaXMgdGhlIGNvbW1hbmQgcHJvbXB0LiBUaGlzIGlzIHdoZXJlIHlvdSB3b3VsZCB0eXBlIHRoZSBgMys0YC4gVGhlIGFuc3dlciB3aWxsIGNvbWUgYmFjayB3aGVuIHlvdSBoaXQgdGhlIGA8RW50ZXI+YCBrZXkuDQoNCi0gRG9uJ3Qgd29ycnkgdG9vIG11Y2ggYXQgdGhpcyBzdGFnZSBhYm91dCB0aGUgYFsxXWAuDQoNCmBgYHtyfQ0KeCA8LSAzICsgNA0KeA0KYGBgDQoNCi0gVGhlIGA8LWAgaXMgY2FsbGVkIHRoZSAibGVmdCBhc3NpZ25tZW50IiBvcGVyYXRvciB3aGljaCBhc3NpZ25zIGZyb20gcmlnaHQgKGAzKzRgKSB0byBsZWZ0IChgeGApDQotIFllcywgaXQgdGFrZXMgdHdvIGtleXMgdG8gZ2V0IGl0OyB0aGVyZSBjYW5ub3QgYmUgc3BhY2UgYmV0d2VlbiB0aGUgYDxgIGFuZCB0aGUgYC1gIGFuZCBpdCBpcyBiZXN0IHByYWN0aWNlIHRvIHB1dCBzcGFjZSBvbiBlaXRoZXIgc2lkZSBvZiBgPC1gIGluIHlvdXIgd29yay4NCi0gSXQgaXMgZXF1aXZhbGVudCB0byBgeD0zKzRgLCBidXQgbWFueSBSIHVzZXJzIHByZWZlciB0aGUgYDwtYCBiZWNhdXNlIGl0IGFsd2F5cyBtZWFucyBzb21ldGhpbmcgaXMgY3JlYXRlZCBpbiB5b3VyIHdvcmtzcGFjZS4gKG5vdCBhbHdheXMgdHJ1ZSBmb3IgYD1gKQ0KLSBBIHJpZ2h0IGFzc2lnbm1lbnQgb3BlcmF0b3IgYWxzbyBleGlzdHMgYnV0IGlzIG5vdCBjb21tb25seSB1c2VkLg0KDQojIyBSIE9iamVjdHMNCg0KICAtIEFsbCBhc3NpZ25lZCB2YXJpYWJsZXMgKG9yIGFueSBvdGhlciBSICpvYmplY3RzKikgYXJlDQogICAgc3RvcmVkIHVudGlsIG92ZXJ3cml0dGVuIG9yIGV4cGxpY2l0bHkgcmVtb3ZlZCAoZGVsZXRlZCkgYnkgdGhlDQogICAgY29tbWFuZCBgcm0oKWAuDQoNCiAgLSBUbyBsaXN0IHN0b3JlZCBvYmplY3RzIHR5cGUgYGxzKClgIG9yIGBvYmplY3RzKClgLg0KDQpgYGB7cn0NCnggPC0gOA0KeSA8LSAzLjE0MTUNCmxzKCkNCnJtKHgpDQpvYmplY3RzKCkNCmBgYA0KDQojIyBSIFN5bnRheA0KDQogIC0gUiBjb21tYW5kcywgZS5nLiBgbHMoKWAsIGBybSgpYCwgYXJlIGZvbGxvd2VkIGJ5IHBhcmVudGhlc2VzIHdoaWNoIG1heQ0KICAgIGNvbnRhaW4gYWRkaXRpb25hbCBpbmZvcm1hdGlvbiBmb3IgdGhlIGZ1bmN0aW9uLg0KDQogIC0gV3JpdGluZyBhIGNvbW1hbmQgbmFtZSB3aXRob3V0IHBhcmVudGhlc2VzIHJldHVybnMgdGhlIFIgc291cmNlIGNvZGUNCiAgICBmb3IgdGhlIGZ1bmN0aW9uLiBUcnkgb25lLi4uDQoNCg0KIyMgVmVjdG9ycyBpbiBSDQoNCiAgLSBUaGUgY29tbWFuZCBgYygpYCAoZm9yICpjb25jYXRlbmF0ZSopIGNyZWF0ZXMgdmVjdG9ycy4NCg0KYGBge3J9DQp4IDwtIGMoMi4zLDEuMiwyLjQpDQp4DQpjKHgsOS4wLHgpDQpgYGANCg0KIyMjIFJlZ3VsYXIgU2VxdWVuY2VzDQoNCiAgLSBUaGUgZXhwcmVzc2lvbiBgMTpuYCBkZW5vdGVzIHRoZSAqKnNlcXVlbmNlKioNCjEsIDIsLi4uICpuKi4gDQoNCiAgLSBUaGUgZXhwcmVzc2lvbiBgc2VxKGksaixieT1rKWAgaXMgYSBzZXF1ZW5jZSBmcm9tICppKikgdG8gKmoqIGluDQogICAgc3RlcHMgb2YgKmsqLg0KDQpgYGB7cn0NCjE6NQ0KeSA8LSBzZXEoMywxMCxieT0yKQ0KeQ0KYGBgDQojIyBWZWN0b3IgQXJpdGhtZXRpYyBpbiBSDQoNCi0gUiB1c2VzIGArYCwgYC1gLCBgKmAgYW5kIGAvYCBmb3IgdGhlIGJhc2ljIGFyaXRobWV0aWMNCiAgICBvcGVyYXRpb25zLCBhbmQgYF5gIGZvciBleHBvbmVudGlhdGlvbiAocmFpc2luZyB0byBhIHBvd2VyKS4NCg0KICAtIFZlY3RvciBvcGVyYXRpb25zIGFyZSBkb25lIGVsZW1lbnQgYnkgZWxlbWVudCwgd2l0aA0KICAgIHJlY3ljbGluZyBvZiBzaG9ydCB2ZWN0b3JzIGlmIHJlcXVpcmVkLg0KDQoNCmBgYHtyfQ0KeCA8LSBjKDIsMykNCnkgPC0gYygxLDQsNSw2KQ0KMip4DQoyICsgeA0KeV4yDQp4ICsgeQ0KYGBgDQoNCiMjIFR5cGVzIG9mIHZlY3Rvcg0KDQogIC0gQWxsIHRoZSB2ZWN0b3JzIHdlIGhhdmUgc2VlbiBzbyBmYXIgaGF2ZSBiZWVuDQogICAgKm51bWVyaWMqOyBzb21lIHdlcmUgKmludGVnZXIqIHdoaWNoIGlzIGEgc3BlY2lhbCB0eXBlIG9mIG51bWJlci4NCg0KLSBSIGFsc28gdW5kZXJzdGFuZHMgdmVjdG9ycyBvZjoNCiAgICANCiAgICAgIC0gY2hhcmFjdGVyczogbGV0dGVycywgbnVtZXJhbHMsIHNwYWNlcywgYW5kIG90aGVyIHRleHQuDQogICAgICAtIGxvZ2ljYWwgdmFsdWVzIGBUUlVFYCBhbmQgYEZBTFNFYDsgYWJicmV2aWF0aW9ucyBgVGAsIGBGYCBhcmUgb2Z0ZW4gdXNlZC4NCiAgICAgIC0gZmFjdG9ycyAoaS5lLiBjYXRlZ29yaWNhbCB2YXJpYWJsZXMpOyB0aGVzZSBtYXkgImxvb2siIGxpa2UgY2hhcmFjdGVycy4NCg0KYGBge3J9DQpNeVdvcmRzIDwtIGMoIlRoaXMiLCJpcyIsImEiLCJjaGFyYWN0ZXIiKQ0KTXlXb3Jkcw0KYyhGLFQsRixGKQ0KZmFjdG9yKGMoIkxvdyIsIkxvdyIsIk1lZGl1bSIsIkhpZ2giLCJIaWdoIikpDQpgYGANCg0KTi5CLiBBbGwgb2YgdGhlc2UgZGF0YSB0eXBlcyBjYW4gYmUgdXNlZCBpbiBsaW5lYXIgbW9kZWxzLCBhbHRob3VnaCBjaGFyYWN0ZXIgdmFsdWVzIGFyZSB1c3VhbGx5IGNvbnZlcnRlZCB0byBmYWN0b3JzLg0KDQojIyBMb2dpY2FsIENvbXBhcmlzb25zDQoNCiAgLSBOdW1lcmljYWwgdmVjdG9ycyBjYW4gYmUgY29tcGFyZWQgYnkgaW5lcXVhbGl0aWVzLg0KDQogIC0gYD09YCBkZW5vdGVzIGVxdWFsaXR5OyB0aGUgYD1gIHN0YXRlcyB3aGF0IHNvbWV0aGluZyBpcy4NCg0KICAtIGAhPWAgZGVub3RlcyAnbm90IGVxdWFsJy4NCg0KICAtIGA+YCwgYD49YCBldGMuIGZvciBpbmVxdWFsaXRpZXMuDQoNCg0KYGBge3J9DQooMTo1KSA9PSAoNToxKQ0KKDE6NSkgPiAoNToxKQ0KYGBgDQoNCllvdSBtaWdodCBsaWtlIHRvIHBsYXkgd2l0aCB0aGVzZSBjb21wYXJpc29ucy4gVGVzdGluZyB0aGUgbmVlZCBmb3IgdGhlIGJyYWNrZXRzIGlzICB3b3J0aCB0ZXN0aW5nLg0KDQojIyBJbmRleGluZyBWZWN0b3JzDQoNCiAgLSBUbyBpbmRleCBjb21wb25lbnRzIG9mIGEgdmVjdG9yIGB4YCwgdXNlIHRoZSBmb3JtDQogICAgYHhbLi4uXWAuDQoNCiAgLSBUaGUgc3F1YXJlIGJyYWNrZXRzIGNhbiBjb250YWluOg0KICAgIA0KICAgICAgLSBudW1lcmljIHZlY3RvciBzcGVjaWZ5aW5nIGVsZW1lbnRzOw0KICAgIA0KICAgICAgLSBsb2dpY2FsIHZlY3Rvcjogb25seSBgVFJVRWAgZWxlbWVudHMgcmVxdWlyZWQuDQoNCg0KYGBge3J9DQp4IDwtIGMoMS4xLDMuMiw0LjMsNy40KQ0KeFtjKDIsNCldDQp4Wy0yXQ0KeFt4ID4gMy41XQ0Kd2hpY2goeCA+IDMuNSkNCmBgYA0KDQojIyBEYXRhIEZyYW1lcw0KDQogIC0gQSBkYXRhIGZyYW1lIGlzIGEgY29sbGVjdGlvbiBvZiBjb2x1bW4gdmVjdG9ycyBlYWNoIG9mDQogICAgdGhlIHNhbWUgbGVuZ3RoLg0KDQogIC0gVGhlIHZlY3RvcnMgbWF5IGJlIG51bWVyaWMsIGZhY3Rvciwgb3Igd2hhdGV2ZXIuDQoNCiAgLSBFYWNoIHBhcnRpY3VsYXIgY29sdW1uIGFuZCByb3cgb2YgYSBkYXRhIGZyYW1lIGlzIGdpdmVuIGEgbmFtZSB3aGljaA0KICAgIGNhbiBiZSBjaG9zZW4gYnkgdGhlIHVzZXIsIG9yIGFzc2lnbmVkIGEgZGVmYXVsdCBieSBSLg0KDQoNCmBgYHtyfQ0KZW1wbG95ZWUgPC0gYygiRGlsYmVydCIsICJXYWxseSIsICJDYXRiZXJ0IiwgIlRoZUJvc3MiKQ0Kam9iPC1mYWN0b3IoYygiRW5naW5lZXIiLCJFbmdpbmVlciIsIk1hbmFnZXIiLCJNYW5hZ2VyIikpDQp4IDwtIGMoOCwxLE5BLC0yKQ0KZGlsYmVydCA8LSBkYXRhLmZyYW1lKGVtcGxveWVlLCBqb2IsIGNvbXBldGVuY2U9eCkNCmRpbGJlcnQNCmBgYA0KDQojIyMgQXR0YWNoaW5nIGFuZCBEZXRhY2hpbmcNCg0KICAtIFRvIGFjY2VzcyB2YXJpYWJsZXMgKGNvbHVtbnMpIG9mIGEgZGF0YSBmcmFtZToNCiAgICANCiAgICAgIC0gRmlyc3QgYGF0dGFjaGAgZGF0YSBmcmFtZTsgb3INCiAgICANCiAgICAgIC0gVXNlIGBkYXRhLmZyYW1lJHZhcmlhYmxlYCBzeW50YXguDQoNCmBgYHtyIHNob3dBdHRhY2gsIGVycm9yPVRSVUV9DQpybShlbXBsb3llZSxqb2IseCkgDQpkaWxiZXJ0JGNvbXBldGVuY2UgDQpqb2INCmF0dGFjaChkaWxiZXJ0KQ0Kam9iDQpkZXRhY2goZGlsYmVydCkNCmBgYA0KDQoNCk4uQi4gVXNpbmcgYGF0dGFjaCgpYCB3aXRob3V0IGBkZXRhY2goKWAgY2FuIGxlYWQgdG8gdHJvdWJsZS4gQWxsIGlzIGZpbmUgd2hlbiB0aGluZ3MgYXJlIGRvbmUgY29ycmVjdGx5LCBidXQgdGhlIGNvbnNlcXVlbmNlcyBvZiBub3QgdXNpbmcgdGhlc2UgY29tbWFuZHMgY29ycmVjdGx5IGlzIHNlbGRvbSBzZWVuIGF0IHRoZSB0aW1lIHRoZXkgYXJlIHVzZWQuIFdoZW4gdGhlIGVycm9ycyBjb21lIHVwIGl0IHdpbGwgYmUgZGlmZmljdWx0IHRvIGRpYWdub3NlIHRoZSBwcm9ibGVtLiBJdCBpcyBxdWl0ZSB1bnVzdWFsIHRvIG5lZWQgdG8gdXNlIHRoZXNlIGNvbW1hbmRzIGlmIHlvdSB1c2UgbW9kZXJuIHdheXMgb2Ygd29ya2luZy4gSXQgaXMgaW1wb3J0YW50IHRvIGtub3cgaG93IHRoZSBgYXR0YWNoKClgIGFuZCBgZGV0YWNoKClgIGNvbW1hbmRzIHdvcmssIGJ1dCBkbyBsb29rIHRvIGF2b2lkIHRoZWlyIHVzZS4NCg0KIyMgSW1wb3J0aW5nIERhdGENCg0KLSBUaGUgYHNjYW4oKWAgY29tbWFuZCByZWFkcyBpbiB0ZXh0IGZyb20gYSBmaWxlIGFzIGEgc2luZ2xlIHZhcmlhYmxlLiBZb3Ugc2hvdWxkIHVzZSB0aGlzIGNvbW1hbmQgdmVyeSBpbmZyZXF1ZW50bHkuDQoNCi0gVGhlIGByZWFkLnRhYmxlKClgIGNvbW1hbmQgaXMgbW9yZSBmbGV4aWJsZSwgaW1wb3J0aW5nIGRhdGEgaW4gdGFidWxhciBmb3JtIGFuZCBzdG9yaW5nIHRoZSByZXN1bHQgYXMgYSBkYXRhIGZyYW1lLg0KDQotIG90aGVyIGNvbW1hbmRzIGV4aXN0IGZvciBpbXBvcnRpbmcgYGNzdmAgZmlsZXMsIGFuZCBhIGhvc3Qgb2Ygb3RoZXIgZmlsZSBmb3JtYXRzLg0KDQoNCi0gVGhlIGNvbW1hIHNlcGFyYXRlZCB2YWx1ZXMgKGNzdikgZmlsZSBmb3JtYXQgaXMgZXh0cmVtZWx5IGNvbW1vbiBhbmQgaXMgdXNlZCBvZnRlbiBpbiB0aGUgY291cnNlLiBZb3Ugc2hvdWxkIG5vdCBuZWVkIHRvIHVzZSBgc2NhbigpYCBvciBgcmVhZC50YWJsZSgpYC4NCg0KYGBge3IgZ2V0SUJNRGF0YSwgZXJyb3I9VFJVRSwgZWNobz0tMSwgZXZhbD0tMn0NCklCTSA8LSBzY2FuKGZpbGU9Ii4uLy4uL2RhdGEvaWJtLnR4dCIpDQpJQk0gPC0gc2NhbihmaWxlPSJpYm0udHh0IikNCmlibQ0KSUJNDQpgYGANCg0KTi5CLiBSIGlzIGNhc2Ugc2Vuc2l0aXZlIHNvIGBpYm1gIGlzIGRpZmZlcmVudCB0byBgSUJNYC4gV2luZG93cyBpcyBub3QgY2FzZSBzZW5zaXRpdmUgc28gdGhlIGZpbGVuYW1lIGNhbiBiZSBtaXNzcGVjaWZpZWQgd2l0aG91dCBhbnkgdHJvdWJsZTsgb3RoZXIgb3BlcmF0aW5nIHN5c3RlbXMgYXJlIGNhc2Ugc2Vuc2l0aXZlIHRob3VnaC4gDQoNCg0KYGBge3IgZ2V0TGlmZURhdGEsIGVycm9yPVRSVUV9DQpMaWZlIDwtIHJlYWQuY3N2KGZpbGU9Ii4uLy4uL2RhdGEvbGlmZS5jc3YiLCBoZWFkZXI9VFJVRSkNCmhlYWQoTGlmZSkgIyBzaG93cyBvbmx5IHRoZSBmaXJzdCBzaXggcm93cw0KYGBgDQoNClRoZSBgLi4vLi4vZGF0YS9gIGluIHRoaXMgY29tbWFuZCBpcyBjYWxsZWQgYSByZWxhdGl2ZSBmaWxlIHBhdGguIFRoZSBgLi5gIG1lYW5zIHRvIGxvb2sgdXAgb25lIGxldmVsIGZyb20gdGhlIGN1cnJlbnQgd29ya2luZyBkaXJlY3Rvcnk7IHRoZSAgZmlsZSByZXF1ZXN0ZWQgaXMgaW4gYSBzdWJmb2xkZXIgY2FsbGVkIGBkYXRhYDsgdGhlIGAvYCBpcyBob3cgd2Ugc2VwYXJhdGUgZm9sZGVycyBmcm9tIHN1YmZvbGRlcnMgb3IgZmlsZW5hbWVzLiBUaGlzIG1heSBzZWVtIHN0cmFuZ2UgdG8gV2luZG93cyB1c2VycyB3aG8gd2FudCB0byB1c2UgYSBiYWNrc2xhc2ggaW5zdGVhZC4gR2V0IHVzZWQgdG8gdXNpbmcgdGhlIGZvcndhcmQgc2xhc2ggaW4gUiBiZWNhdXNlIGl0IHdvcmtzIGZvciBhbGwgb3BlcmF0aW5nIHN5c3RlbXMuDQoNClRoZSBgcmVhZC5jc3YoKWAgY29tbWFuZCBtYWtlcyBhIG51bWJlciBvZiBhc3N1bXB0aW9ucyBhYm91dCB0aGUgd2F5IHRoZSBmaWxlIGlzIGZvcm1hdHRlZC4gQSBgY3N2YCBmaWxlIGlzIGFjdHVhbGx5IHBsYWluIHRleHQgd2l0aCBjb21tYXMgYmV0d2VlbiB2YWx1ZXMuIFNvbWUgcGVvcGxlIHRoaW5rIGl0IGlzIGEgTVMgRXhjZWwgZmlsZSwgYnV0IGNzdiBmaWxlcyBleGlzdGVkIGxvbmcgYmVmb3JlIEV4Y2VsLg0KIA0KIyMgRWRpdGluZyBEYXRhDQoNCiAgLSBDYW4gZWRpdCBieSByZWFzc2lnbmluZyBlbGVtZW50cyBvZiBhIHZlY3RvciBvciBkYXRhIGZyYW1lLg0KDQogIC0gRm9yIGRhdGEgZnJhbWUgb3IgbWF0cml4LCBgQVtpLGpdYCBpcyB0aGUgKmksaipedGheIGVsZW1lbnQgKHJvdw0KICAgICppKiwgY29sdW1uICpqKikgb2YgdGhlIGRhdGEgZnJhbWUgYEFgLg0KDQoNCg0KYGBge3J9DQpJQk1bNV0NCklCTVs1XSA8LSA2NS4xMg0KSUJNWzVdDQpMaWZlWzIsXQ0KTGlmZVsyLDRdDQpMaWZlWzIsNF0gPC0gNzE2Ng0KYGBgDQoNCiMjIFIgUGFja2FnZXMNCg0KICAtIFIgb2JqZWN0cyAoZnVuY3Rpb25zLCBkYXRhIGV0Yy4pIGFyZSBvcmdhbml6ZWQgaW4NCiAgICBsaWJyYXJpZXMvcGFja2FnZXMuDQoNCiAgLSBTb21lIGFyZSBsb2FkZWQgYnkgZGVmYXVsdCB3aGVuIFIgc3RhcnRzIGVhY2ggdGltZS4NCiAgICANCiAgICAgIC0gRS5nLiBmdW5jdGlvbiBgbHMoKWAgaXMgcGFydCBvZiB0aGUgYGJhc2VgIHBhY2thZ2UgdGhhdCBpcw0KICAgICAgICBhdXRvbWF0aWNhbGx5IGxvYWRlZCwNCg0KICAtIFNvbWUgcGFja2FnZXMgbmVlZCBsb2FkaW5nLCB1c2luZyBlaXRoZXIgdGhlIGBsaWJyYXJ5KClgIG9yIGByZXF1aXJlKClgIGNvbW1hbmQuDQoNCmBgYHtyIHNob3dNaXNzaW5nRnVuLCBlcnJvcj1UUlVFfQ0KbXZybm9ybSgxLG11PTAsU2lnbWE9MSkNCmxpYnJhcnkoTUFTUykNCm12cm5vcm0oMSxtdT0wLFNpZ21hPTEpDQpgYGANCg0KIyMgU29tZSBSIEZ1bmN0aW9ucyB0byBHZXQgWW91IFN0YXJ0ZWQNCg0KICAtIGBoZWxwKClgIGFjY2Vzc2VzIFIncyBoZWxwIHN5c3RlbTsgZS5nLiBgaGVscChscylgLiBBIHF1aWNrZXIgd2F5IGlzIHRvIHVzZSBgP2xzYA0KDQogIC0gYG1lYW4oKWAsIGBzZCgpYCwgYG1pbigpYCwgYG1heCgpYCBhbmQgYHJhbmdlKClgIGdpdmUgbWVhbiwgc3RhbmRhcmQNCiAgICBkZXZpYXRpb24sIG1pbmltdW0sIG1heGltdW0gYW5kIHJhbmdlIHJlc3BlY3RpdmVseSBmb3IgYSB2ZWN0b3INCiAgICBhcmd1bWVudC4gTi5CLiBgcmFuZ2UoKWAgdGVsbHMgeW91IHRoZSBtaW5pbXVtIGFuZCBtYXhpbXVtIGFzIGEgcGFpciwgbm90IHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlbS4NCg0KICAtIGB2YXIoKWAgcmV0dXJucyB2YXJpYW5jZSBvZiBhIHZlY3RvciBhcmd1bWVudCwgb3IgdGhlIGNvdmFyaWFuY2UNCiAgICAoZGlzcGVyc2lvbikgbWF0cml4IGZvciBhIG1hdHJpeCBhcmd1bWVudC4NCg0KICAtIGBzdW1tYXJ5KClgIHJldHVybnMgc3VtbWFyeSBpbmZvcm1hdGlvbiBkZXBlbmRlbnQgb24gYXJndW1lbnQgdHlwZS4NCg0KICAtIGBwbG90KClgIHByb2R1Y2VzIGEgcGxvdCBvbiB0aGUgY3VycmVudCBncmFwaGljcyB0b29sLiBUaGUgdHlwZSBvZg0KICAgIHBsb3QgZGVwZW5kcyBvbiB0aGUgdHlwZSBvZiBhcmd1bWVudC4gVGhlIHNpbXBsZXN0IHVzZSBpcyBgcGxvdCh4LHkpYCB3aGljaA0KICAgIHByb2R1Y2VzIGEgc2NhdHRlci1wbG90IG9mIHZlY3RvcnMgYHhgIGFuZCBgeWAuDQoNClByYWN0aWNlIGlzIHRoZSBrZXkgd2hlbiBsZWFybmluZyBSLg0KDQojIyBZb3VyIEZpcnN0IFIgRXhlcmNpc2UNCg0KMS4gIFVzZSBSIHRvIGNhbGN1bGF0ZSAgIA0KICAgIChpKSAzNDU2LTc4OQ0KICAgIChpaSkgJDIzXHRpbWVze30zNCQNCiAgICAoaWlpKSAxM14zXg0KDQoyLiAgV3JpdGUgKGVmZmljaWVudCkgY29kZSB0byBjcmVhdGUgdGhlIGZvbGxvd2luZyBzZXF1ZW5jZXM6DQogICAgDQogICAgKGkpIDIsIDQsIDYsIC4uLiAxMDA7IHRoYXQgaXMsIHRoZSBldmVuIG51bWJlcnMgdXAgdG8gMTAwDQogICAgDQogICAgKGlpKSAxLDIsMyw0LDUsNCwzLDIsMQ0KDQozLiAgVXNlIHRoZSBjb21tYW5kIGB5IDwtIHJub3JtKDEwMClgIHRvIHN0b3JlIDEwMCBzaW11bGF0ZWQNCiAgICBzdGFuZGFyZCBub3JtYWwgcmFuZG9tIHZhcmlhYmxlcyBpbiB0aGUgdmVjdG9yIGB5YC4NCiAgICANCiAgICAoaSkgRmluZCB0aGUgbWVhbiBhbmQgc3RhbmRhcmQgZGV2aWF0aW9uIG9mIGB5YC4NCiAgICANCiAgICAoaWkpIEZpbmQgdGhlIGxhcmdlc3Qgc2ltdWxhdGVkIHZhbHVlLiBXaGljaCBudW1iZXIgc2ltdWxhdGlvbiBpcyB0aGlzIGUuZy4gNTRedGheLCAyM15yZF4/DQo=