About

R is a language and environment for statistical computing and graphics. R provides a wide variety of statistical (linear and nonlinear modelling, classical statistical tests, time-series analysis, classification, clustering, .) and graphical techniques, and is highly extensible.

This notebook is a tutorial on how to use R.

Setup

Remember to always set your working directory to the source file location. Go to ‘Session’, scroll down to ‘Set Working Directory’, and click ‘To Source File Location’. Read carefully the below and follow the instructions to complete the tasks and answer any questions. Submit your work to RPubs as detailed in previous notes.

Note

For your assignment you may be using different data sets than what is included here. Always read carefully the instructions on Sakai. For clarity, tasks/questions to be completed/answered are highlighted in red color and numbered according to their particular placement in the task section. Quite often you will need to add your own code chunk.

Execute all code chunks, preview, publish, and submit link on Sakai.


Basics Operations

First we will begin with a few basic operations.

Variable assignment

We assign values to variables using the assignment operator ‘=’. Another form of assignment, more general, is the ‘<-’ operator. A variable allows you to store values or an object (e.g. a function).

x = 128
y = 16
z <- 5
vars = c(2,4,8,16,32) # Creates a vector list using the generic combine function 'c' 
x # display value of variable x
[1] 128
z # displays value of variable z
[1] 5
vars[1] #This calls the first value in the vector vars
[1] 2
vars[2] #This calls the second value in the vector vars
[1] 4
vars[1:3] #This calls the first through third values in the vector vars
[1] 2 4 8
vars #This calls the vector list
[1]  2  4  8 16 32

Common Arithmetic Operations

Below shows some simple arithmetic operations.

12*6
[1] 72
128/16
[1] 8
9^2
[1] 81

Basic Data Types

R works with numerous data types. Some of the most basic types are: numeric,integers, logical (Boolean-TRUE/FALSE) and characters (string-"TEXT").

#Type: Character                   
#Example:"TRUE",'23.4'
v = "TRUE"                       
class(v)                           
[1] "character"
#Type: Numeric                
#Example: 12.3,5
v = 23.5                  
class(v)                   
[1] "numeric"
              
#Type: Logical    
#Example: TRUE,FALSE
v = TRUE
class(v)
[1] "logical"
#Type: Factor (nominal, categorical)
#Example: m f m f m
v = as.factor(c("m", "f", "m"))
class(v)
[1] "factor"

Functions

R Functions are invoked by its name, followed by the parenthesis, and zero or more arguments.

# The following applies the function 'c' (seen earlier) to combine three numeric values into a vector 
c(1,2,3)
[1] 1 2 3
# Example of function mean() to calcule the mean of three values
mean(c(5,6,7))
[1] 6
# Square root of a number
sqrt(99)
[1] 9.949874

Importing Data and Variable Assignment

# Here we are reading a file of type csv (comma seperated values) typical of many Excel files
il_income = read.csv(file = "data/il_income.csv")
top_il_income = read.csv(file = "data/top_il_income.csv")

Arithmetic Operations with Data

We can extract values from the dataset to perform calculations by referencing the proper elements of a list

DuPage = top_il_income$per_capita_income[1]
Lake = top_il_income$per_capita_income[2]
DuPage-Lake
[1] 472
DuPage+Lake
[1] 77390
(DuPage+Lake)/2
[1] 38695

##### 1) Repeat here the above arithmetic operations code chunk by referencing instead the list elements for McHenry and Sangamon counties

McHenry = top_il_income$per_capita_income[3]
Sangmon = top_il_income$per_capita_income[10]
McHenry-Sangmon
[1] 2524
McHenry+Sangmon
[1] 63712
(McHenry+Sangmon)/2
[1] 31856

Basic Statistics

mean(il_income$per_capita_income)
[1] 25164.14
median(il_income$per_capita_income)
[1] 24808.5
quantile(il_income$per_capita_income)
      0%      25%      50%      75%     100% 
14052.00 22666.00 24808.50 26899.75 38931.00 
# Summary 
summary(il_income)
      rank              county   per_capita_income   population          region     
 Min.   :  1.00   Adams    : 1   Min.   :14052     Min.   :   4135   Min.   :1.000  
 1st Qu.: 26.25   Alexander: 1   1st Qu.:22666     1st Qu.:  14284   1st Qu.:3.000  
 Median : 51.50   Bond     : 1   Median :24809     Median :  26610   Median :4.000  
 Mean   : 51.50   Boone    : 1   Mean   :25164     Mean   : 126078   Mean   :3.735  
 3rd Qu.: 76.75   Brown    : 1   3rd Qu.:26900     3rd Qu.:  53319   3rd Qu.:5.000  
 Max.   :102.00   Bureau   : 1   Max.   :38931     Max.   :5238216   Max.   :5.000  
                  (Other)  :96                                                      

##### 2) Repeat here the above basic statistics code chunk using instead the data from the file top_il_income

mean(top_il_income$per_capita_income)
[1] 32918.5
median(top_il_income$per_capita_income)
[1] 31430
quantile(top_il_income$per_capita_income)
      0%      25%      50%      75%     100% 
30594.00 30743.75 31430.00 33103.25 38931.00 
# Summary 
summary(top_il_income)
      rank           county  per_capita_income   population         region   
 Min.   : 2.00   DuPage :1   Min.   :30594     Min.   :  7032   Min.   :2.0  
 1st Qu.: 4.25   Kane   :1   1st Qu.:30744     1st Qu.: 36921   1st Qu.:2.0  
 Median :12.00   Kendall:1   Median :31430     Median :194782   Median :3.0  
 Mean   :27.10   Lake   :1   Mean   :32919     Mean   :334866   Mean   :3.2  
 3rd Qu.:41.00   McHenry:1   3rd Qu.:33103     3rd Qu.:648159   3rd Qu.:4.0  
 Max.   :90.00   McLean :1   Max.   :38931     Max.   :933736   Max.   :5.0  
                 (Other):4                                                   

Vectors

Defining a Vector

A sequence of data elements of the same basic type is defined as a vector.

# vector of numeric values
c(2, 3, 5, 8)
[1] 2 3 5 8
# vector of logical values.
c(TRUE, FALSE, TRUE)
[1]  TRUE FALSE  TRUE
# vector of character strings.
c("A", "B", "B-", "C", "D")
[1] "A"  "B"  "B-" "C"  "D" 

Lists

Defining a List

Lists, as opposed to vectors, can hold components of different types.

scores = c(80, 75, 55)  # vector of numeric values                   
grades = c("B", "C", "D-")  # vector of character strings.          
office_hours = c(TRUE, FALSE, FALSE) # vector of logical values.
student = list(scores,grades,office_hours) # list of vectors
student
[[1]]
[1] 80 75 55

[[2]]
[1] "B"  "C"  "D-"

[[3]]
[1]  TRUE FALSE FALSE

List Slicing

We can retrieve components of the list with the single square bracket [] operator.

student[1]     
student[2]
student[3]

# first two components of the list
student[1:2]

Member Reference

Using the double square bracket [[]] operator we can reference a member of the list directly. Using one bracket [] would still reference the list but will not allow you to extract a particular member of the list.

student[[1]] # Components of the Scores Vector
[1] 80 75 55

First element of the Scores vector

student[[1]][1]
[1] 80

First three elements of the Scores vector

student[[1]][1:3]
[1] 80 75 55

##### 3) Repeat here the above code chunk to extract instead the second element of the grades vector

student[[2]] # Components of the grades Vector
[1] "B"  "C"  "D-"

Second element of the grades vector

student[[2]][2]
[1] "C"

Named List Members

It’s possible to assign names to list members and reference them by names instead of by numeric indexes.

student = list(myscores = scores, mygrades = grades , myoffice_hours = office_hours) 
student
$`myscores`
[1] 80 75 55

$mygrades
[1] "B"  "C"  "D-"

$myoffice_hours
[1]  TRUE FALSE FALSE
student$myscores
[1] 80 75 55
student$mygrades
[1] "B"  "C"  "D-"
student$myoffice_hours
[1]  TRUE FALSE FALSE

Matrices

All columns in a matrix must have the same data type and the same length.

Create a numeric matrix of 5 rows and 4 columns made of sequential numbers 1:20

x_mat = matrix(1:20, nrow=5, ncol=4)
x_mat
     [,1] [,2] [,3] [,4]
[1,]    1    6   11   16
[2,]    2    7   12   17
[3,]    3    8   13   18
[4,]    4    9   14   19
[5,]    5   10   15   20

Retrieve the 4th column of matrix

x_mat[,4]
[1] 16 17 18 19 20

Retrieve the 3rd row of matrix

x_mat[3,]
[1]  3  8 13 18

Retrieve rows 2,3,4 of columns 1,2,3

x_mat[2:4,1:3]
     [,1] [,2] [,3]
[1,]    2    7   12
[2,]    3    8   13
[3,]    4    9   14

##### 4) Repeat here the above code chunk to extract instead the third row and third column of the matrix

x_mat = matrix(1:20, nrow=5, ncol=4)
x_mat
     [,1] [,2] [,3] [,4]
[1,]    1    6   11   16
[2,]    2    7   12   17
[3,]    3    8   13   18
[4,]    4    9   14   19
[5,]    5   10   15   20
x_mat[,3]
[1] 11 12 13 14 15

Retrieve the 3rd row of matrix

x_mat[3,]
[1]  3  8 13 18

Retrieve rows 2,3,4 of columns 1,2,3

x_mat[2:4,1:3]
     [,1] [,2] [,3]
[1,]    2    7   12
[2,]    3    8   13
[3,]    4    9   14

Data Frames

A data frame is more general than a matrix, in that different columns can have different data types (numeric, character, logic, factor). It is a powerful way to work with mixed data structures.

Defining a Data Frame

When we need to store data in table form, we use data frames, which are created by combining lists of vectors of equal length. The variables of a data set are the columns and the observations are the rows.

The str() function helps us to display the internal structure of any R data structure or object to make sure that it’s correct.

str(il_income)
'data.frame':   102 obs. of  5 variables:
 $ rank             : int  1 2 3 4 5 6 7 8 9 10 ...
 $ county           : Factor w/ 102 levels "Adams","Alexander",..: 16 22 49 99 45 60 101 64 86 10 ...
 $ per_capita_income: int  30468 38931 38459 30791 30645 23937 24802 30728 23279 26087 ...
 $ population       : int  5238216 933736 703910 687263 530847 307343 287078 266209 264052 208861 ...
 $ region           : int  1 2 2 2 2 2 2 5 5 3 ...

Creating a Data Frame

Snapshot of the solar system.

name = c("Earth", "Mars", "Jupiter")
type = c("Terrestrial","Terrestrial", "Gas giant")
diameter = c(1, 0.532, 11.209)
rotation = c(1, 1.03, 0.41)
rings = c(FALSE, FALSE, TRUE)

Now, by combining the vectors of equal size, we can create a data frame object.

planets_df = data.frame(name,type,diameter,rotation,rings)
planets_df

Suggested Exercises & Resources

Exercises

Data Sources

Data samples used in this worksheet were downloaded from the U.S. Census Bureau American FactFinder site.

LS0tDQp0aXRsZTogIkJTQUQzNDMgRmFsbCAyMDE4IExhYiBXb3Jrc2hlZXQgMDEiDQphdXRob3I6ICJZaSBQYW4iDQpkYXRlOiAiMDktMTItMjAxOCINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdA0Kc3VidGl0bGU6IEludHJvZHVjdGlvbiB0byBSIChic2FkLWxhYjAxKQ0KLS0tDQoNCiMjIyBBYm91dA0KDQpSIGlzIGEgbGFuZ3VhZ2UgYW5kIGVudmlyb25tZW50IGZvciBzdGF0aXN0aWNhbCBjb21wdXRpbmcgYW5kIGdyYXBoaWNzLiBSIHByb3ZpZGVzIGEgd2lkZSB2YXJpZXR5IG9mIHN0YXRpc3RpY2FsIChsaW5lYXIgYW5kIG5vbmxpbmVhciBtb2RlbGxpbmcsIGNsYXNzaWNhbCBzdGF0aXN0aWNhbCB0ZXN0cywgdGltZS1zZXJpZXMgYW5hbHlzaXMsIGNsYXNzaWZpY2F0aW9uLCBjbHVzdGVyaW5nLCAuKSBhbmQgZ3JhcGhpY2FsIHRlY2huaXF1ZXMsIGFuZCBpcyBoaWdobHkgZXh0ZW5zaWJsZS4gDQoNClRoaXMgbm90ZWJvb2sgaXMgYSB0dXRvcmlhbCBvbiBob3cgdG8gdXNlIFIuDQoNCg0KIyMjIFNldHVwDQoNClJlbWVtYmVyIHRvIGFsd2F5cyBzZXQgeW91ciB3b3JraW5nIGRpcmVjdG9yeSB0byB0aGUgc291cmNlIGZpbGUgbG9jYXRpb24uIEdvIHRvICdTZXNzaW9uJywgc2Nyb2xsIGRvd24gdG8gJ1NldCBXb3JraW5nIERpcmVjdG9yeScsIGFuZCBjbGljayAnVG8gU291cmNlIEZpbGUgTG9jYXRpb24nLiBSZWFkIGNhcmVmdWxseSB0aGUgYmVsb3cgYW5kIGZvbGxvdyB0aGUgaW5zdHJ1Y3Rpb25zIHRvIGNvbXBsZXRlIHRoZSB0YXNrcyBhbmQgYW5zd2VyIGFueSBxdWVzdGlvbnMuICBTdWJtaXQgeW91ciB3b3JrIHRvIFJQdWJzIGFzIGRldGFpbGVkIGluIHByZXZpb3VzIG5vdGVzLiANCg0KIyMjIE5vdGUNCg0KRm9yIHlvdXIgYXNzaWdubWVudCB5b3UgbWF5IGJlIHVzaW5nIGRpZmZlcmVudCBkYXRhIHNldHMgdGhhbiB3aGF0IGlzIGluY2x1ZGVkIGhlcmUuIEFsd2F5cyByZWFkIGNhcmVmdWxseSB0aGUgaW5zdHJ1Y3Rpb25zIG9uIFNha2FpLiAgRm9yIGNsYXJpdHksIHRhc2tzL3F1ZXN0aW9ucyB0byBiZSBjb21wbGV0ZWQvYW5zd2VyZWQgYXJlIGhpZ2hsaWdodGVkIGluIHJlZCBjb2xvciBhbmQgbnVtYmVyZWQgYWNjb3JkaW5nIHRvIHRoZWlyIHBhcnRpY3VsYXIgcGxhY2VtZW50IGluIHRoZSB0YXNrIHNlY3Rpb24uICBRdWl0ZSBvZnRlbiB5b3Ugd2lsbCBuZWVkIHRvIGFkZCB5b3VyIG93biBjb2RlIGNodW5rLg0KDQpFeGVjdXRlIGFsbCBjb2RlIGNodW5rcywgcHJldmlldywgcHVibGlzaCwgYW5kIHN1Ym1pdCBsaW5rIG9uIFNha2FpLg0KDQotLS0tLS0tLS0tDQoNCiFbXShpbWdzL2ltZzAxLnBuZykNCg0KDQojIEJhc2ljcyBPcGVyYXRpb25zIA0KRmlyc3Qgd2Ugd2lsbCBiZWdpbiB3aXRoIGEgZmV3IGJhc2ljIG9wZXJhdGlvbnMuIA0KDQojIyBWYXJpYWJsZSBhc3NpZ25tZW50DQpXZSBhc3NpZ24gdmFsdWVzIHRvIHZhcmlhYmxlcyB1c2luZyB0aGUgYXNzaWdubWVudCBvcGVyYXRvciAnPScuIEFub3RoZXIgZm9ybSBvZiBhc3NpZ25tZW50LCBtb3JlIGdlbmVyYWwsIGlzIHRoZSAnPC0nIG9wZXJhdG9yLiANCkEgdmFyaWFibGUgYWxsb3dzIHlvdSB0byBzdG9yZSB2YWx1ZXMgb3IgYW4gb2JqZWN0IChlLmcuIGEgZnVuY3Rpb24pLg0KDQpgYGB7cn0NCnggPSAxMjgNCnkgPSAxNg0KeiA8LSA1DQp2YXJzID0gYygyLDQsOCwxNiwzMikgIyBDcmVhdGVzIGEgdmVjdG9yIGxpc3QgdXNpbmcgdGhlIGdlbmVyaWMgY29tYmluZSBmdW5jdGlvbiAnYycgDQpgYGANCg0KYGBge3J9DQp4ICMgZGlzcGxheSB2YWx1ZSBvZiB2YXJpYWJsZSB4DQp6ICMgZGlzcGxheXMgdmFsdWUgb2YgdmFyaWFibGUgeg0KYGBgDQoNCmBgYHtyfQ0KdmFyc1sxXSAjVGhpcyBjYWxscyB0aGUgZmlyc3QgdmFsdWUgaW4gdGhlIHZlY3RvciB2YXJzDQpgYGANCg0KYGBge3J9DQp2YXJzWzJdICNUaGlzIGNhbGxzIHRoZSBzZWNvbmQgdmFsdWUgaW4gdGhlIHZlY3RvciB2YXJzDQpgYGANCg0KYGBge3J9DQp2YXJzWzE6M10gI1RoaXMgY2FsbHMgdGhlIGZpcnN0IHRocm91Z2ggdGhpcmQgdmFsdWVzIGluIHRoZSB2ZWN0b3IgdmFycw0KYGBgDQoNCmBgYHtyfQ0KdmFycyAjVGhpcyBjYWxscyB0aGUgdmVjdG9yIGxpc3QNCmBgYA0KDQojIyBDb21tb24gQXJpdGhtZXRpYyBPcGVyYXRpb25zDQpCZWxvdyBzaG93cyBzb21lIHNpbXBsZSBhcml0aG1ldGljIG9wZXJhdGlvbnMuDQpgYGB7cixldmFsPVRSVUV9DQoxMio2DQoxMjgvMTYNCjleMg0KYGBgDQoNCiMjIEJhc2ljIERhdGEgVHlwZXMNClIgd29ya3Mgd2l0aCBudW1lcm91cyBkYXRhIHR5cGVzLiBTb21lIG9mIHRoZSBtb3N0IGJhc2ljIHR5cGVzIGFyZTogbnVtZXJpYyxpbnRlZ2VycywgbG9naWNhbCAoQm9vbGVhbi1gVFJVRS9GQUxTRWApIGFuZCBjaGFyYWN0ZXJzIChzdHJpbmctYCJURVhUImApLg0KDQpgYGB7cixldmFsPVRSVUV9DQojVHlwZTogQ2hhcmFjdGVyICAgICAgICAgICAgICAgICAgIA0KI0V4YW1wbGU6IlRSVUUiLCcyMy40Jw0KDQp2ID0gIlRSVUUiICAgICAgICAgICAgICAgICAgICAgICANCmNsYXNzKHYpICAgICAgICAgICAgICAgICAgICAgICAgICAgDQoNCiNUeXBlOiBOdW1lcmljICAgICAgICAgICAgICAgIA0KI0V4YW1wbGU6IDEyLjMsNQ0KDQp2ID0gMjMuNSAgICAgICAgICAgICAgICAgIA0KY2xhc3ModikgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgIA0KI1R5cGU6IExvZ2ljYWwgICAgDQojRXhhbXBsZTogVFJVRSxGQUxTRQ0KDQp2ID0gVFJVRQ0KY2xhc3ModikNCg0KI1R5cGU6IEZhY3RvciAobm9taW5hbCwgY2F0ZWdvcmljYWwpDQojRXhhbXBsZTogbSBmIG0gZiBtDQoNCnYgPSBhcy5mYWN0b3IoYygibSIsICJmIiwgIm0iKSkNCmNsYXNzKHYpDQpgYGANCg0KIyMgIEZ1bmN0aW9ucw0KDQpSIEZ1bmN0aW9ucyBhcmUgaW52b2tlZCBieSBpdHMgbmFtZSwgZm9sbG93ZWQgYnkgdGhlIHBhcmVudGhlc2lzLCBhbmQgemVybyBvciBtb3JlIGFyZ3VtZW50cy4gDQpgYGB7cn0NCiMgVGhlIGZvbGxvd2luZyBhcHBsaWVzIHRoZSBmdW5jdGlvbiAnYycgKHNlZW4gZWFybGllcikgdG8gY29tYmluZSB0aHJlZSBudW1lcmljIHZhbHVlcyBpbnRvIGEgdmVjdG9yIA0KYygxLDIsMykNCg0KIyBFeGFtcGxlIG9mIGZ1bmN0aW9uIG1lYW4oKSB0byBjYWxjdWxlIHRoZSBtZWFuIG9mIHRocmVlIHZhbHVlcw0KbWVhbihjKDUsNiw3KSkNCg0KIyBTcXVhcmUgcm9vdCBvZiBhIG51bWJlcg0Kc3FydCg5OSkNCmBgYA0KDQojIyBJbXBvcnRpbmcgRGF0YSBhbmQgVmFyaWFibGUgQXNzaWdubWVudA0KDQpgYGB7cixldmFsPVRSVUV9DQojIEhlcmUgd2UgYXJlIHJlYWRpbmcgYSBmaWxlIG9mIHR5cGUgY3N2IChjb21tYSBzZXBlcmF0ZWQgdmFsdWVzKSB0eXBpY2FsIG9mIG1hbnkgRXhjZWwgZmlsZXMNCmlsX2luY29tZSA9IHJlYWQuY3N2KGZpbGUgPSAiZGF0YS9pbF9pbmNvbWUuY3N2IikNCnRvcF9pbF9pbmNvbWUgPSByZWFkLmNzdihmaWxlID0gImRhdGEvdG9wX2lsX2luY29tZS5jc3YiKQ0KYGBgDQoNCg0KIyMgQXJpdGhtZXRpYyBPcGVyYXRpb25zIHdpdGggRGF0YQ0KDQpXZSBjYW4gZXh0cmFjdCB2YWx1ZXMgZnJvbSB0aGUgZGF0YXNldCB0byBwZXJmb3JtIGNhbGN1bGF0aW9ucyBieSByZWZlcmVuY2luZyB0aGUgcHJvcGVyIGVsZW1lbnRzIG9mIGEgbGlzdA0KYGBge3IsZXZhbD1UUlVFfQ0KRHVQYWdlID0gdG9wX2lsX2luY29tZSRwZXJfY2FwaXRhX2luY29tZVsxXQ0KTGFrZSA9IHRvcF9pbF9pbmNvbWUkcGVyX2NhcGl0YV9pbmNvbWVbMl0NCkR1UGFnZS1MYWtlDQpEdVBhZ2UrTGFrZQ0KKER1UGFnZStMYWtlKS8yDQpgYGANCg0KPHNwYW4gc3R5bGU9ImNvbG9yOnJlZCI+DQojIyMjIyAxKSBSZXBlYXQgaGVyZSB0aGUgYWJvdmUgYXJpdGhtZXRpYyBvcGVyYXRpb25zIGNvZGUgY2h1bmsgYnkgcmVmZXJlbmNpbmcgaW5zdGVhZCB0aGUgbGlzdCBlbGVtZW50cyBmb3IgTWNIZW5yeSBhbmQgU2FuZ2Ftb24gY291bnRpZXMgDQo8L3NwYW4+DQpgYGB7cixldmFsPVRSVUV9DQpNY0hlbnJ5ID0gdG9wX2lsX2luY29tZSRwZXJfY2FwaXRhX2luY29tZVszXQ0KU2FuZ21vbiA9IHRvcF9pbF9pbmNvbWUkcGVyX2NhcGl0YV9pbmNvbWVbMTBdDQpNY0hlbnJ5LVNhbmdtb24NCk1jSGVucnkrU2FuZ21vbg0KKE1jSGVucnkrU2FuZ21vbikvMg0KYGBgDQoNCiMjIEJhc2ljIFN0YXRpc3RpY3MNCg0KYGBge3IsZXZhbD1UUlVFfQ0KbWVhbihpbF9pbmNvbWUkcGVyX2NhcGl0YV9pbmNvbWUpDQptZWRpYW4oaWxfaW5jb21lJHBlcl9jYXBpdGFfaW5jb21lKQ0KcXVhbnRpbGUoaWxfaW5jb21lJHBlcl9jYXBpdGFfaW5jb21lKQ0KIyBTdW1tYXJ5IA0Kc3VtbWFyeShpbF9pbmNvbWUpDQpgYGANCg0KPHNwYW4gc3R5bGU9ImNvbG9yOnJlZCI+DQojIyMjIyAyKSBSZXBlYXQgaGVyZSB0aGUgYWJvdmUgYmFzaWMgc3RhdGlzdGljcyBjb2RlIGNodW5rIHVzaW5nIGluc3RlYWQgdGhlIGRhdGEgZnJvbSB0aGUgZmlsZSB0b3BfaWxfaW5jb21lDQo8L3NwYW4+DQpgYGB7cixldmFsPVRSVUV9DQptZWFuKHRvcF9pbF9pbmNvbWUkcGVyX2NhcGl0YV9pbmNvbWUpDQptZWRpYW4odG9wX2lsX2luY29tZSRwZXJfY2FwaXRhX2luY29tZSkNCnF1YW50aWxlKHRvcF9pbF9pbmNvbWUkcGVyX2NhcGl0YV9pbmNvbWUpDQojIFN1bW1hcnkgDQpzdW1tYXJ5KHRvcF9pbF9pbmNvbWUpDQpgYGANCg0KIyBWZWN0b3JzDQoNCiMjIERlZmluaW5nIGEgVmVjdG9yDQoNCkEgc2VxdWVuY2Ugb2YgZGF0YSBlbGVtZW50cyBvZiB0aGUgc2FtZSBiYXNpYyB0eXBlIGlzIGRlZmluZWQgYXMgYSB2ZWN0b3IuDQpgYGB7cixldmFsPVRSVUV9DQojIHZlY3RvciBvZiBudW1lcmljIHZhbHVlcw0KYygyLCAzLCA1LCA4KQ0KDQojIHZlY3RvciBvZiBsb2dpY2FsIHZhbHVlcy4NCmMoVFJVRSwgRkFMU0UsIFRSVUUpDQoNCiMgdmVjdG9yIG9mIGNoYXJhY3RlciBzdHJpbmdzLg0KYygiQSIsICJCIiwgIkItIiwgIkMiLCAiRCIpDQpgYGANCg0KIyBMaXN0cw0KDQojIyBEZWZpbmluZyBhIExpc3QNCg0KTGlzdHMsIGFzIG9wcG9zZWQgdG8gdmVjdG9ycywgY2FuIGhvbGQgY29tcG9uZW50cyBvZiBkaWZmZXJlbnQgdHlwZXMuDQoNCmBgYHtyLGV2YWw9VFJVRX0NCnNjb3JlcyA9IGMoODAsIDc1LCA1NSkgICMgdmVjdG9yIG9mIG51bWVyaWMgdmFsdWVzICAgICAgICAgICAgICAgICAgIA0KZ3JhZGVzID0gYygiQiIsICJDIiwgIkQtIikgICMgdmVjdG9yIG9mIGNoYXJhY3RlciBzdHJpbmdzLiAgICAgICAgICANCg0Kb2ZmaWNlX2hvdXJzID0gYyhUUlVFLCBGQUxTRSwgRkFMU0UpICMgdmVjdG9yIG9mIGxvZ2ljYWwgdmFsdWVzLg0Kc3R1ZGVudCA9IGxpc3Qoc2NvcmVzLGdyYWRlcyxvZmZpY2VfaG91cnMpICMgbGlzdCBvZiB2ZWN0b3JzDQpzdHVkZW50DQpgYGANCg0KIyMgTGlzdCBTbGljaW5nIA0KDQpXZSBjYW4gcmV0cmlldmUgY29tcG9uZW50cyBvZiB0aGUgbGlzdCB3aXRoIHRoZSBzaW5nbGUgc3F1YXJlIGJyYWNrZXQgYFtdYCBvcGVyYXRvci4NCg0KDQpgYGB7cixldmFsPVRSVUV9DQpzdHVkZW50WzFdICAgICANCnN0dWRlbnRbMl0NCnN0dWRlbnRbM10NCg0KIyBmaXJzdCB0d28gY29tcG9uZW50cyBvZiB0aGUgbGlzdA0Kc3R1ZGVudFsxOjJdDQpgYGANCg0KIyMgTWVtYmVyIFJlZmVyZW5jZQ0KDQpVc2luZyB0aGUgZG91YmxlIHNxdWFyZSBicmFja2V0IGBbW11dYCBvcGVyYXRvciB3ZSBjYW4gcmVmZXJlbmNlIGEgbWVtYmVyIG9mIHRoZSBsaXN0IGRpcmVjdGx5LiBVc2luZyBvbmUgYnJhY2tldCBbXSB3b3VsZCBzdGlsbCByZWZlcmVuY2UgdGhlIGxpc3QgYnV0IHdpbGwgbm90IGFsbG93IHlvdSB0byBleHRyYWN0IGEgcGFydGljdWxhciBtZW1iZXIgb2YgdGhlIGxpc3QuDQoNCmBgYHtyLGV2YWw9VFJVRX0NCnN0dWRlbnRbWzFdXSAjIENvbXBvbmVudHMgb2YgdGhlIFNjb3JlcyBWZWN0b3INCmBgYA0KDQoqRmlyc3QgZWxlbWVudCBvZiB0aGUgU2NvcmVzIHZlY3RvcioNCg0KYGBge3IsZXZhbD1UUlVFfQ0Kc3R1ZGVudFtbMV1dWzFdDQpgYGANCg0KDQoqRmlyc3QgdGhyZWUgZWxlbWVudHMgb2YgdGhlIFNjb3JlcyB2ZWN0b3IqDQoNCmBgYHtyLGV2YWw9VFJVRX0NCnN0dWRlbnRbWzFdXVsxOjNdDQpgYGANCg0KPHNwYW4gc3R5bGU9ImNvbG9yOnJlZCI+DQojIyMjIyAzKSBSZXBlYXQgaGVyZSB0aGUgYWJvdmUgY29kZSBjaHVuayB0byBleHRyYWN0IGluc3RlYWQgdGhlIHNlY29uZCBlbGVtZW50IG9mIHRoZSBncmFkZXMgdmVjdG9yDQo8L3NwYW4+DQpgYGB7cixldmFsPVRSVUV9DQpzdHVkZW50W1syXV0gIyBDb21wb25lbnRzIG9mIHRoZSBncmFkZXMgVmVjdG9yDQpgYGANCg0KKlNlY29uZCBlbGVtZW50IG9mIHRoZSBncmFkZXMgdmVjdG9yKg0KDQpgYGB7cixldmFsPVRSVUV9DQpzdHVkZW50W1syXV1bMl0NCmBgYA0KDQoNCiMjIE5hbWVkIExpc3QgTWVtYmVycw0KDQpJdCdzIHBvc3NpYmxlIHRvIGFzc2lnbiBuYW1lcyB0byBsaXN0IG1lbWJlcnMgYW5kIHJlZmVyZW5jZSB0aGVtIGJ5IG5hbWVzIGluc3RlYWQgb2YgYnkgbnVtZXJpYyBpbmRleGVzLg0KDQpgYGB7cixldmFsPVRSVUV9DQpzdHVkZW50ID0gbGlzdChteXNjb3JlcyA9IHNjb3JlcywgbXlncmFkZXMgPSBncmFkZXMgLCBteW9mZmljZV9ob3VycyA9IG9mZmljZV9ob3VycykgDQoNCnN0dWRlbnQNCnN0dWRlbnQkbXlzY29yZXMNCnN0dWRlbnQkbXlncmFkZXMNCnN0dWRlbnQkbXlvZmZpY2VfaG91cnMNCmBgYA0KDQojIE1hdHJpY2VzDQoNCkFsbCBjb2x1bW5zIGluIGEgbWF0cml4IG11c3QgaGF2ZSB0aGUgc2FtZSBkYXRhIHR5cGUgYW5kIHRoZSBzYW1lIGxlbmd0aC4NCg0KKkNyZWF0ZSBhIG51bWVyaWMgbWF0cml4IG9mIDUgcm93cyBhbmQgNCBjb2x1bW5zIG1hZGUgb2Ygc2VxdWVudGlhbCBudW1iZXJzIDE6MjAqDQpgYGB7cn0NCnhfbWF0ID0gbWF0cml4KDE6MjAsIG5yb3c9NSwgbmNvbD00KQ0KeF9tYXQNCmBgYA0KDQoqUmV0cmlldmUgdGhlIDR0aCBjb2x1bW4gb2YgbWF0cml4Kg0KYGBge3J9DQp4X21hdFssNF0NCmBgYA0KDQoNCipSZXRyaWV2ZSB0aGUgM3JkIHJvdyBvZiBtYXRyaXgqDQpgYGB7cn0NCnhfbWF0WzMsXQ0KYGBgDQoNCipSZXRyaWV2ZSByb3dzIDIsMyw0IG9mIGNvbHVtbnMgMSwyLDMqDQpgYGB7cn0NCnhfbWF0WzI6NCwxOjNdDQpgYGANCg0KPHNwYW4gc3R5bGU9ImNvbG9yOnJlZCI+DQojIyMjIyA0KSBSZXBlYXQgaGVyZSB0aGUgYWJvdmUgY29kZSBjaHVuayB0byBleHRyYWN0IGluc3RlYWQgdGhlIHRoaXJkIHJvdyBhbmQgdGhpcmQgY29sdW1uIG9mIHRoZSBtYXRyaXgNCjwvc3Bhbj4NCmBgYHtyfQ0KeF9tYXQgPSBtYXRyaXgoMToyMCwgbnJvdz01LCBuY29sPTQpDQp4X21hdA0KYGBgDQoNCmBgYHtyfQ0KeF9tYXRbLDNdDQpgYGANCg0KDQoqUmV0cmlldmUgdGhlIDNyZCByb3cgb2YgbWF0cml4Kg0KYGBge3J9DQp4X21hdFszLF0NCmBgYA0KDQoqUmV0cmlldmUgcm93cyAyLDMsNCBvZiBjb2x1bW5zIDEsMiwzKg0KYGBge3J9DQp4X21hdFsyOjQsMTozXQ0KYGBgDQoNCg0KIyBEYXRhIEZyYW1lcw0KDQpBIGRhdGEgZnJhbWUgaXMgbW9yZSBnZW5lcmFsIHRoYW4gYSBtYXRyaXgsIGluIHRoYXQgZGlmZmVyZW50IGNvbHVtbnMgY2FuIGhhdmUgZGlmZmVyZW50IGRhdGEgdHlwZXMgKG51bWVyaWMsIGNoYXJhY3RlciwgbG9naWMsIGZhY3RvcikuIEl0IGlzIGEgcG93ZXJmdWwgd2F5IHRvIHdvcmsgd2l0aCBtaXhlZCBkYXRhIHN0cnVjdHVyZXMuDQoNCiMjIERlZmluaW5nIGEgRGF0YSBGcmFtZQ0KDQpXaGVuIHdlIG5lZWQgdG8gc3RvcmUgZGF0YSBpbiB0YWJsZSBmb3JtLCB3ZSB1c2UgZGF0YSBmcmFtZXMsIHdoaWNoIGFyZSBjcmVhdGVkIGJ5IGNvbWJpbmluZyBsaXN0cyBvZiB2ZWN0b3JzIG9mIGVxdWFsIGxlbmd0aC4gVGhlIHZhcmlhYmxlcyBvZiBhIGRhdGEgc2V0IGFyZSB0aGUgY29sdW1ucyBhbmQgdGhlIG9ic2VydmF0aW9ucyBhcmUgdGhlIHJvd3MuIA0KDQoNClRoZSBgc3RyKClgIGZ1bmN0aW9uIGhlbHBzIHVzIHRvIGRpc3BsYXkgdGhlIGludGVybmFsIHN0cnVjdHVyZSBvZiBhbnkgUiBkYXRhIHN0cnVjdHVyZSBvciBvYmplY3QgdG8gbWFrZSBzdXJlIHRoYXQgaXQncyBjb3JyZWN0Lg0KDQoNCmBgYHtyLGV2YWw9VFJVRX0NCnN0cihpbF9pbmNvbWUpDQpgYGANCg0KIyMgQ3JlYXRpbmcgYSBEYXRhIEZyYW1lDQoNClNuYXBzaG90IG9mIHRoZSBzb2xhciBzeXN0ZW0uDQoNCmBgYHtyLCBldmFsPVRSVUV9DQpuYW1lID0gYygiRWFydGgiLCAiTWFycyIsICJKdXBpdGVyIikNCnR5cGUgPSBjKCJUZXJyZXN0cmlhbCIsIlRlcnJlc3RyaWFsIiwgIkdhcyBnaWFudCIpDQpkaWFtZXRlciA9IGMoMSwgMC41MzIsIDExLjIwOSkNCnJvdGF0aW9uID0gYygxLCAxLjAzLCAwLjQxKQ0KcmluZ3MgPSBjKEZBTFNFLCBGQUxTRSwgVFJVRSkNCmBgYA0KDQpOb3csIGJ5IGNvbWJpbmluZyB0aGUgdmVjdG9ycyBvZiBlcXVhbCBzaXplLCB3ZSBjYW4gY3JlYXRlIGEgZGF0YSBmcmFtZSBvYmplY3QuDQoNCmBgYHtyLCBldmFsPVRSVUV9DQpwbGFuZXRzX2RmID0gZGF0YS5mcmFtZShuYW1lLHR5cGUsZGlhbWV0ZXIscm90YXRpb24scmluZ3MpDQpwbGFuZXRzX2RmDQoNCmBgYA0KDQojIFN1Z2dlc3RlZCBFeGVyY2lzZXMgJiBSZXNvdXJjZXMNCg0KIyMgRXhlcmNpc2VzDQoNCiogRGF0YWNhbXAgLSBMZWFybiBEYXRhIFNjaWVuY2UgZnJvbSB5b3VyIGJyb3dzZXI6IA0KaHR0cHM6Ly93d3cuZGF0YWNhbXAuY29tL2NvdXJzZXMvZnJlZS1pbnRyb2R1Y3Rpb24tdG8tcg0KDQoqIFItdHV0b3IgLSBBbiBSIGludHJvIHRvIHN0YXRzIHRoYXQgZXhwbGFpbnMgYmFzaWMgUiBjb25jZXB0czoNCmh0dHA6Ly93d3cuci10dXRvci5jb20vci1pbnRyb2R1Y3Rpb24NCg0KIyMgRGF0YSBTb3VyY2VzDQpEYXRhIHNhbXBsZXMgdXNlZCBpbiB0aGlzIHdvcmtzaGVldCB3ZXJlIGRvd25sb2FkZWQgZnJvbSB0aGUgVS5TLiBDZW5zdXMgQnVyZWF1IEFtZXJpY2FuIEZhY3RGaW5kZXIgc2l0ZS4NCg0KKiAiU0VMRUNURUQgRUNPTk9NSUMgQ0hBUkFDVEVSSVNUSUNTIDIwMDYtMjAxMCBBbWVyaWNhbiBDb21tdW5pdHkgU3VydmV5IDUtWWVhciBFc3RpbWF0ZXMiIC0gVS5TLiBDZW5zdXMgQnVyZWF1LiBSZXRyaWV2ZWQgMjAxNi0wOS0wOToNCmh0dHBzOi8vZmFjdGZpbmRlci5jZW5zdXMuZ292L2ZhY2VzL25hdi9qc2YvcGFnZXMvaW5kZXgueGh0bWwNCg==