Let’s create a data frame using data.frame():

> df <- data.frame(person=c("Ripon","Mina","Meghla","Ridoy","Saad"),
+                  age=c(22,20,17,24,19),
+                  gender=factor(c("M","F","F","M","M")))
> df
  person age gender
1  Ripon  22      M
2   Mina  20      F
3 Meghla  17      F
4  Ridoy  24      M
5   Saad  19      M

Structure

To get the structure of data frame use str():

> str(df)
'data.frame':   5 obs. of  3 variables:
 $ person: chr  "Ripon" "Mina" "Meghla" "Ridoy" ...
 $ age   : num  22 20 17 24 19
 $ gender: Factor w/ 2 levels "F","M": 2 1 1 2 2

Summary Statistics

To know the summary statistics of the data frame use summary():

> summary(df)
    person               age       gender
 Length:5           Min.   :17.0   F:2   
 Class :character   1st Qu.:19.0   M:3   
 Mode  :character   Median :20.0         
                    Mean   :20.4         
                    3rd Qu.:22.0         
                    Max.   :24.0         

Dimension, number of row and number of column

> dim(df)
[1] 5 3
> nrow(df)
[1] 5
> ncol(df)
[1] 3

Change Factor Values

To change the factor values of a colum-
Let’s change F to Female and M to Male. Here we can see gender has two levels:

> df$gender
[1] M F F M M
Levels: F M
> levels(df$gender)
[1] "F" "M"

Now simply replace the levels as desired:

> levels(df$gender) <- c("Female","Male")

Let’s see the result:

> df
  person age gender
1  Ripon  22   Male
2   Mina  20 Female
3 Meghla  17 Female
4  Ridoy  24   Male
5   Saad  19   Male

Column Selection

Select as vector

> df$age
[1] 22 20 17 24 19
> df[,'age']   # notice comma ( df[row,col] )
[1] 22 20 17 24 19
> df[,2]
[1] 22 20 17 24 19

Select as data frame

> df[2] # no comma for selecting 2nd column
  age
1  22
2  20
3  17
4  24
5  19
> df['age']
  age
1  22
2  20
3  17
4  24
5  19

Selecting multiple columns

> df[c('person','age')] # notice: no comma
  person age
1  Ripon  22
2   Mina  20
3 Meghla  17
4  Ridoy  24
5   Saad  19
> df[c(1,2)]
  person age
1  Ripon  22
2   Mina  20
3 Meghla  17
4  Ridoy  24
5   Saad  19

Row Selection

> df[2,]  # Selecting single row
  person age gender
2   Mina  20 Female
> df[c(3:5),] # notice: comma
  person age gender
3 Meghla  17 Female
4  Ridoy  24   Male
5   Saad  19   Male

Conditional Selection

Selecting observations with age greater than 18:

> df[df$age > 18,]  # notice comma
  person age gender
1  Ripon  22   Male
2   Mina  20 Female
4  Ridoy  24   Male
5   Saad  19   Male

Selecting only Males:

> df[df$gender == 'M',]
[1] person age    gender
<0 rows> (or 0-length row.names)

Selecting Males and age greater than 18:

> df[df$gender == 'M' & df$age > 18,]
[1] person age    gender
<0 rows> (or 0-length row.names)

Selecting Males and age greater than 18 and removing the gender column:

> df[df$gender == 'M' & df$age > 18,-3]
[1] person age   
<0 rows> (or 0-length row.names)

subset() function

Selecting Males and age greater than 18 and removing the gender column using subset():

> subset(x= df, gender=='M', select=-gender)
[1] person age   
<0 rows> (or 0-length row.names)
> subset(x= df, age>18 & gender=='M', select=-gender)
[1] person age   
<0 rows> (or 0-length row.names)

Another clever way to do this is using column names by names():

> names(df)
[1] "person" "age"    "gender"
> names(df) %in% 'gender' #checks which col. name matches 'gender'
[1] FALSE FALSE  TRUE
> !names(df) %in% 'gender'
[1]  TRUE  TRUE FALSE
> df[df$age > 18, !(names(df) %in% 'gender')] #selects only the TRUE columns
  person age
1  Ripon  22
2   Mina  20
4  Ridoy  24
5   Saad  19

Column Bind (cbind)

cbind() can be used to bind two different datasets by column.
Let’s make two data frames d1 and d2 with same number of rows:

> SL<-1:6
> name<-c('Abdul','Rafiq','Selim','Ataur','Moin','Lara')
> d1<-data.frame(SL,name)
> d1
  SL  name
1  1 Abdul
2  2 Rafiq
3  3 Selim
4  4 Ataur
5  5  Moin
6  6  Lara
> marks<-c(67,78,80,70,30,80)
> posi<-c(4,2,1,3,5,1)
> d2<-data.frame(marks,posi)
> d2
  marks posi
1    67    4
2    78    2
3    80    1
4    70    3
5    30    5
6    80    1

Now simply bind these two data frames using cbind():

> cb<-cbind(d1,d2)
> cb
  SL  name marks posi
1  1 Abdul    67    4
2  2 Rafiq    78    2
3  3 Selim    80    1
4  4 Ataur    70    3
5  5  Moin    30    5
6  6  Lara    80    1

Let’s see the class of cb:

> class(cb)
[1] "data.frame"

Again let’s say we have the following vectors

> person <- c("Ripon","Mina","Chris","Shad")
> age <- c(22,20,24,19)
> gender <- c("Male","Female","Male","Male")

In this case we can use cbind (column bind) to bind these vectors into a metrix and then converting them using as.data.frame() into a data frame:

> dfm<-cbind(person,age,gender)
> dfm
     person  age  gender  
[1,] "Ripon" "22" "Male"  
[2,] "Mina"  "20" "Female"
[3,] "Chris" "24" "Male"  
[4,] "Shad"  "19" "Male"  
> class(dfm)
[1] "matrix" "array" 

So the result comes out as a 2D array. Using as.data.frame():

> dfm<-as.data.frame(dfm)
> dfm
  person age gender
1  Ripon  22   Male
2   Mina  20 Female
3  Chris  24   Male
4   Shad  19   Male
> class(dfm)
[1] "data.frame"

Row Bind (Row Bind)

rbind can be used in binding different data frames with same number of columns.
Let’s make two data frame:

> SL<-1:3
> name<-c('Abdul','Rafiq','Selim')
> marks<-c(67,78,80)
> posi<-c(4,2,1)
> df_from_source_1<-data.frame(SL,name,marks,posi)
> df_from_source_1
  SL  name marks posi
1  1 Abdul    67    4
2  2 Rafiq    78    2
3  3 Selim    80    1
> SL<-4:6
> name<-c('Ataur','Moin','Lara')
> marks<-c(70,30,80)
> posi<-c(3,5,1)
> df_from_source_2<-data.frame(SL,name,marks,posi)
> df_from_source_2
  SL  name marks posi
1  4 Ataur    70    3
2  5  Moin    30    5
3  6  Lara    80    1

“Notice that the columns name must match and the number of columns must be equal”
Now bind these data frames by row using rbind():

> rdf<- rbind(df_from_source_1,df_from_source_2)
> rdf
  SL  name marks posi
1  1 Abdul    67    4
2  2 Rafiq    78    2
3  3 Selim    80    1
4  4 Ataur    70    3
5  5  Moin    30    5
6  6  Lara    80    1

Add column names to search path

Using the function attach() this can be done. For example take the data frame rdf that we created above -

> rdf
  SL  name marks posi
1  1 Abdul    67    4
2  2 Rafiq    78    2
3  3 Selim    80    1
4  4 Ataur    70    3
5  5  Moin    30    5
6  6  Lara    80    1

If we want to select a column as vector we would need to do it using dataframename$columnname -

> rdf$name
[1] "Abdul" "Rafiq" "Selim" "Ataur" "Moin"  "Lara" 

If we run only name we will get an Error saying “Error: object ‘name’ not found”.

By attaching the data frame we can do the work easily-

> attach(rdf)
> name
[1] "Ataur" "Moin"  "Lara" 
> marks
[1] 70 30 80

Using search we can see everything that is in the current search path of the global environment -

> search()
 [1] ".GlobalEnv"        "rdf"               "package:stats"    
 [4] "package:graphics"  "package:grDevices" "package:utils"    
 [7] "package:datasets"  "package:methods"   "Autoloads"        
[10] "package:base"     

To detach anything from the search path, for example say the rdf data frame -

> detach("rdf", unload=T)

Now rdf is not in the search path -

> search()
[1] ".GlobalEnv"        "package:stats"     "package:graphics" 
[4] "package:grDevices" "package:utils"     "package:datasets" 
[7] "package:methods"   "Autoloads"         "package:base"     

And we cannot call any column by the column name only. We have to use $ this method again.


Joining two data frames - merge

Let’s create two data frames:

> # data frame 1
> df1 = data.frame(CustomerId = c(1:6), 
+                  Product = c("Oven","Television","Mobile","WashingMachine","Lightings","Ipad"))
> df1 
  CustomerId        Product
1          1           Oven
2          2     Television
3          3         Mobile
4          4 WashingMachine
5          5      Lightings
6          6           Ipad
> # data frame 2
> df2 = data.frame(CustomerId = c(1, 4, 6, 8), 
+                  State = c("California","Santiago","Texas","Indiana")) 
> df2 
  CustomerId      State
1          1 California
2          4   Santiago
3          6      Texas
4          8    Indiana

Inner Join

Joins all the observations that match in both data frames by CustomerId

> merge(x=df1, y=df2, by="CustomerId")
  CustomerId        Product      State
1          1           Oven California
2          4 WashingMachine   Santiago
3          6           Ipad      Texas

Outer Join

Joins all the observations by CustomerId

> merge(x=df1, y=df2, by="CustomerId", all=TRUE)
  CustomerId        Product      State
1          1           Oven California
2          2     Television       <NA>
3          3         Mobile       <NA>
4          4 WashingMachine   Santiago
5          5      Lightings       <NA>
6          6           Ipad      Texas
7          8           <NA>    Indiana

Left Join

Joins all the observations of df1 to df2 by CustomerId

> merge(x=df1, y=df2, by="CustomerId", all.x=TRUE)
  CustomerId        Product      State
1          1           Oven California
2          2     Television       <NA>
3          3         Mobile       <NA>
4          4 WashingMachine   Santiago
5          5      Lightings       <NA>
6          6           Ipad      Texas

Right Join

Joins df1 to all the observations of df2 by CustomerId

> merge(x=df1,y=df2,by="CustomerId",all.y=TRUE)
  CustomerId        Product      State
1          1           Oven California
2          4 WashingMachine   Santiago
3          6           Ipad      Texas
4          8           <NA>    Indiana

Cross join in R

A Cross Join (also sometimes known as a Cartesian Join) results in every row of one table being joined to every row of another table

> merge(x = df1, y = df2, by=NULL)
   CustomerId.x        Product CustomerId.y      State
1             1           Oven            1 California
2             2     Television            1 California
3             3         Mobile            1 California
4             4 WashingMachine            1 California
5             5      Lightings            1 California
6             6           Ipad            1 California
7             1           Oven            4   Santiago
8             2     Television            4   Santiago
9             3         Mobile            4   Santiago
10            4 WashingMachine            4   Santiago
11            5      Lightings            4   Santiago
12            6           Ipad            4   Santiago
13            1           Oven            6      Texas
14            2     Television            6      Texas
15            3         Mobile            6      Texas
16            4 WashingMachine            6      Texas
17            5      Lightings            6      Texas
18            6           Ipad            6      Texas
19            1           Oven            8    Indiana
20            2     Television            8    Indiana
21            3         Mobile            8    Indiana
22            4 WashingMachine            8    Indiana
23            5      Lightings            8    Indiana
24            6           Ipad            8    Indiana

Know joining and merging in data frames using dplyr package from here

> df3 <- data.frame(SL = 1:5,
+                   CustomerId = 1:5,
+                   Product = c("Oven","Television","Mobile","WashingMachine","Lightings"))
> df4 <- data.frame(SL = 392:396,
+                   CustomerId = 1:5, 
+                   Location = c("California","Santiago","Texas","Indiana","New York"))
> 
> merge(x = df3 , y = df4, by = "CustomerId")
  CustomerId SL.x        Product SL.y   Location
1          1    1           Oven  392 California
2          2    2     Television  393   Santiago
3          3    3         Mobile  394      Texas
4          4    4 WashingMachine  395    Indiana
5          5    5      Lightings  396   New York
> merge(x = df3 , y = df4, by = "CustomerId", suffixes = c("df3","df4"))
  CustomerId SLdf3        Product SLdf4   Location
1          1     1           Oven   392 California
2          2     2     Television   393   Santiago
3          3     3         Mobile   394      Texas
4          4     4 WashingMachine   395    Indiana
5          5     5      Lightings   396   New York

Calculations in data frame

colMeans

Calculate mean column wise -

> set.seed(0)
> df1 <- data.frame(a = 1:10,
+                   b = round(rnorm(10, 5, 1),1))
> df1
    a   b
1   1 6.3
2   2 4.7
3   3 6.3
4   4 6.3
5   5 5.4
6   6 3.5
7   7 4.1
8   8 4.7
9   9 5.0
10 10 7.4
> colMeans(df1) 
   a    b 
5.50 5.37 

Add the means to the data frame -

> temp <- df1
> temp["MeanGen",] <- colMeans(df1)  # adding a new column with column wise means 
> temp
           a    b
1        1.0 6.30
2        2.0 4.70
3        3.0 6.30
4        4.0 6.30
5        5.0 5.40
6        6.0 3.50
7        7.0 4.10
8        8.0 4.70
9        9.0 5.00
10      10.0 7.40
MeanGen  5.5 5.37

rowMeans

Calculate mean row wise -

> rowMeans(df1)
 [1] 3.65 3.35 4.65 5.15 5.20 4.75 5.55 6.35 7.00 8.70

Add the means to the data frame -

> temp <- df1
> temp["MeanGen"] <- rowMeans(df1)  # adding a new row with row wise means 
> temp
    a   b MeanGen
1   1 6.3    3.65
2   2 4.7    3.35
3   3 6.3    4.65
4   4 6.3    5.15
5   5 5.4    5.20
6   6 3.5    4.75
7   7 4.1    5.55
8   8 4.7    6.35
9   9 5.0    7.00
10 10 7.4    8.70

Creating a new column can be done using the mutate function from dplyr package -

> library(dplyr)
> df1 %>% 
+   mutate(a,b,MeanDpl = rowMeans(df1))
    a   b MeanDpl
1   1 6.3    3.65
2   2 4.7    3.35
3   3 6.3    4.65
4   4 6.3    5.15
5   5 5.4    5.20
6   6 3.5    4.75
7   7 4.1    5.55
8   8 4.7    6.35
9   9 5.0    7.00
10 10 7.4    8.70

apply

> apply(df1, 2, FUN=mean)  # applies function 'mean' to 2nd dimension (columns)
   a    b 
5.50 5.37 
> apply(df1, 1, FUN=mean)  # applies function to 1st dimension (rows)
 [1] 3.65 3.35 4.65 5.15 5.20 4.75 5.55 6.35 7.00 8.70
> sapply(df1, FUN=mean)  # also takes mean of columns, treating data frame like list of vectors
   a    b 
5.50 5.37 
> lapply(df1, FUN=mean)  # returns a list with column wise means
$a
[1] 5.5

$b
[1] 5.37

Complete rows

> df2 <- data.frame(
+   a = rep(10,5),
+   b = round(rnorm(5,10,3)),
+   c = c(2,4,NA,8,NA)
+ )
> df2
   a  b  c
1 10 12  2
2 10  8  4
3 10  7 NA
4 10  9  8
5 10  9 NA

The above data frame has two NA/ uncomplete rows. To get the data frame with complete rows run the following command -

> df2[complete.cases(df2),]
   a  b c
1 10 12 2
2 10  8 4
4 10  9 8

Fill missing values

tidyr/fill

> df5 <- data.frame(SL = 1:10,
+                   vals = c("a",NA,NA,"b",NA,NA,NA,"c",NA,NA))
> df5
   SL vals
1   1    a
2   2 <NA>
3   3 <NA>
4   4    b
5   5 <NA>
6   6 <NA>
7   7 <NA>
8   8    c
9   9 <NA>
10 10 <NA>
> df5n <- tidyr::fill(data = df5, vals, .direction = "down")
> cbind(df5, vals_filled = df5n$vals)
   SL vals vals_filled
1   1    a           a
2   2 <NA>           a
3   3 <NA>           a
4   4    b           b
5   5 <NA>           b
6   6 <NA>           b
7   7 <NA>           b
8   8    c           c
9   9 <NA>           c
10 10 <NA>           c

Replacing with something

> df5[is.na(df5$vals),"vals"] <- 0
> df5
   SL vals
1   1    a
2   2    0
3   3    0
4   4    b
5   5    0
6   6    0
7   7    0
8   8    c
9   9    0
10 10    0

Multiple Response to Dummy Variable Creation

Let’s see the data -

> Data <- read.table("multiple reponse.txt", header = T, fill = T)
> Data
   ID Response
1   1      a,b
2   2         
3   3      b,c
4   4      a,d
5   5      a,c
6   6      a,b
7   7      a,b
8   8      b,d
9   9         
10 10        a
11 11      a,b
12 12      b,c

Creating dummy variables from this column -

> Data$Responses <- as.character(Data$Response)
> # splitting the responses
> resp.split <- strsplit(Data$Responses, split = ",")
> lev <- unique(unlist(resp.split))  # taking unique values for column
> # creating dummy
> resp.dummy <- t(sapply(resp.split, 
+                        FUN = function(x) table(factor(x,
+                                                       levels=lev))))
> # assigning it to a data frame
> Data2 <- with(Data, cbind(Responses, data.frame(resp.dummy)))
> Data2
   Responses a b c d
1        a,b 1 1 0 0
2            0 0 0 0
3        b,c 0 1 1 0
4        a,d 1 0 0 1
5        a,c 1 0 1 0
6        a,b 1 1 0 0
7        a,b 1 1 0 0
8        b,d 0 1 0 1
9            0 0 0 0
10         a 1 0 0 0
11       a,b 1 1 0 0
12       b,c 0 1 1 0

This solution of dummy variable creation from multiple responses is taken from here.

LS0tDQp0aXRsZTogIkRhdGEgRnJhbWUiDQphdXRob3I6ICJNRCBBSFNBTlVMIElTTEFNIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0OiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICB0aGVtZTogcmVhZGFibGUNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCi0tLQ0KYGBge3IsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoDQogIGNvbW1lbnQgPSAiIiwgcHJvbXB0ID0gVFJVRSwgbWVzc2FnZT1GLCB3YXJuaW5nPUYNCikNCmBgYA0KDQotLS0NCg0KTGV0J3MgY3JlYXRlIGEgZGF0YSBmcmFtZSB1c2luZyBgZGF0YS5mcmFtZSgpYDoNCmBgYHtyfQ0KZGYgPC0gZGF0YS5mcmFtZShwZXJzb249YygiUmlwb24iLCJNaW5hIiwiTWVnaGxhIiwiUmlkb3kiLCJTYWFkIiksDQogICAgICAgICAgICAgICAgIGFnZT1jKDIyLDIwLDE3LDI0LDE5KSwNCiAgICAgICAgICAgICAgICAgZ2VuZGVyPWZhY3RvcihjKCJNIiwiRiIsIkYiLCJNIiwiTSIpKSkNCmRmDQpgYGAgICANCg0KDQotLS0NCg0KIyMjIFN0cnVjdHVyZQ0KVG8gZ2V0IHRoZSBzdHJ1Y3R1cmUgb2YgZGF0YSBmcmFtZSB1c2UgYHN0cigpYDoNCmBgYHtyfQ0Kc3RyKGRmKQ0KYGBgDQoNCi0tLQ0KDQojIyMgU3VtbWFyeSBTdGF0aXN0aWNzDQpUbyBrbm93IHRoZSBzdW1tYXJ5IHN0YXRpc3RpY3Mgb2YgdGhlIGRhdGEgZnJhbWUgdXNlIGBzdW1tYXJ5KClgOg0KYGBge3J9DQpzdW1tYXJ5KGRmKQ0KYGBgDQoNCi0tLQ0KDQojIyMgRGltZW5zaW9uLCBudW1iZXIgb2Ygcm93IGFuZCBudW1iZXIgb2YgY29sdW1uDQpgYGB7cn0NCmRpbShkZikNCm5yb3coZGYpDQpuY29sKGRmKQ0KYGBgDQoNCi0tLQ0KDQojIyMgQ2hhbmdlIEZhY3RvciBWYWx1ZXMNClRvIGNoYW5nZSB0aGUgZmFjdG9yIHZhbHVlcyBvZiBhIGNvbHVtLSAgIA0KTGV0J3MgY2hhbmdlIEYgdG8gRmVtYWxlIGFuZCBNIHRvIE1hbGUuIEhlcmUgd2UgY2FuIHNlZSBnZW5kZXIgaGFzIHR3byBsZXZlbHM6DQpgYGB7cn0NCmRmJGdlbmRlcg0KbGV2ZWxzKGRmJGdlbmRlcikNCmBgYA0KDQpOb3cgc2ltcGx5IHJlcGxhY2UgdGhlIGxldmVscyBhcyBkZXNpcmVkOiANCg0KYGBge3J9DQpsZXZlbHMoZGYkZ2VuZGVyKSA8LSBjKCJGZW1hbGUiLCJNYWxlIikNCmBgYA0KDQpMZXQncyBzZWUgdGhlIHJlc3VsdDogIA0KDQpgYGB7cn0NCmRmDQpgYGANCg0KLS0tDQoNCg0KIyMjIENvbHVtbiBTZWxlY3Rpb24NCg0KIyMjIyBTZWxlY3QgYXMgdmVjdG9yDQoNCmBgYHtyfQ0KZGYkYWdlDQpkZlssJ2FnZSddICAgIyBub3RpY2UgY29tbWEgKCBkZltyb3csY29sXSApDQpkZlssMl0NCmBgYA0KDQojIyMjIFNlbGVjdCBhcyBkYXRhIGZyYW1lDQoNCmBgYHtyfQ0KZGZbMl0gIyBubyBjb21tYSBmb3Igc2VsZWN0aW5nIDJuZCBjb2x1bW4NCmRmWydhZ2UnXQ0KYGBgDQoNCg0KIyMjIFNlbGVjdGluZyBtdWx0aXBsZSBjb2x1bW5zDQoNCmBgYHtyfQ0KZGZbYygncGVyc29uJywnYWdlJyldICMgbm90aWNlOiBubyBjb21tYQ0KZGZbYygxLDIpXQ0KYGBgDQoNCi0tLQ0KDQojIyMgUm93IFNlbGVjdGlvbg0KDQpgYGB7cn0NCmRmWzIsXSAgIyBTZWxlY3Rpbmcgc2luZ2xlIHJvdw0KZGZbYygzOjUpLF0gIyBub3RpY2U6IGNvbW1hDQpgYGANCg0KLS0tDQoNCiMjIyBDb25kaXRpb25hbCBTZWxlY3Rpb24NCg0KU2VsZWN0aW5nIG9ic2VydmF0aW9ucyB3aXRoIGFnZSBncmVhdGVyIHRoYW4gMTg6DQpgYGB7cn0NCmRmW2RmJGFnZSA+IDE4LF0gICMgbm90aWNlIGNvbW1hDQpgYGANClNlbGVjdGluZyBvbmx5IE1hbGVzOg0KDQpgYGB7cn0NCmRmW2RmJGdlbmRlciA9PSAnTScsXQ0KYGBgDQoNClNlbGVjdGluZyBNYWxlcyBhbmQgYWdlIGdyZWF0ZXIgdGhhbiAxODoNCg0KYGBge3J9DQpkZltkZiRnZW5kZXIgPT0gJ00nICYgZGYkYWdlID4gMTgsXQ0KYGBgDQoNClNlbGVjdGluZyBNYWxlcyBhbmQgYWdlIGdyZWF0ZXIgdGhhbiAxOCBhbmQgcmVtb3ZpbmcgdGhlIGBnZW5kZXJgIGNvbHVtbjoNCg0KYGBge3J9DQpkZltkZiRnZW5kZXIgPT0gJ00nICYgZGYkYWdlID4gMTgsLTNdDQpgYGANCg0KIyMjIyBzdWJzZXQoKSBmdW5jdGlvbg0KDQpTZWxlY3RpbmcgTWFsZXMgYW5kIGFnZSBncmVhdGVyIHRoYW4gMTggYW5kIHJlbW92aW5nIHRoZSBgZ2VuZGVyYCBjb2x1bW4gdXNpbmcgYHN1YnNldCgpYDoNCmBgYHtyfQ0Kc3Vic2V0KHg9IGRmLCBnZW5kZXI9PSdNJywgc2VsZWN0PS1nZW5kZXIpDQpzdWJzZXQoeD0gZGYsIGFnZT4xOCAmIGdlbmRlcj09J00nLCBzZWxlY3Q9LWdlbmRlcikNCmBgYA0KDQpBbm90aGVyIGNsZXZlciB3YXkgdG8gZG8gdGhpcyBpcyB1c2luZyBjb2x1bW4gbmFtZXMgYnkgYG5hbWVzKClgOg0KDQpgYGB7cn0NCm5hbWVzKGRmKQ0KbmFtZXMoZGYpICVpbiUgJ2dlbmRlcicgI2NoZWNrcyB3aGljaCBjb2wuIG5hbWUgbWF0Y2hlcyAnZ2VuZGVyJw0KIW5hbWVzKGRmKSAlaW4lICdnZW5kZXInDQpkZltkZiRhZ2UgPiAxOCwgIShuYW1lcyhkZikgJWluJSAnZ2VuZGVyJyldICNzZWxlY3RzIG9ubHkgdGhlIFRSVUUgY29sdW1ucw0KYGBgDQoNCi0tLQ0KDQojIyMgQ29sdW1uIEJpbmQgKGNiaW5kKQ0KDQpgY2JpbmRgKCkgY2FuIGJlIHVzZWQgdG8gYmluZCB0d28gZGlmZmVyZW50IGRhdGFzZXRzIGJ5IGNvbHVtbi4gICANCkxldCdzIG1ha2UgdHdvIGRhdGEgZnJhbWVzIGQxIGFuZCBkMiB3aXRoIF9zYW1lIG51bWJlciBvZiByb3dzXzoNCmBgYHtyfQ0KU0w8LTE6Ng0KbmFtZTwtYygnQWJkdWwnLCdSYWZpcScsJ1NlbGltJywnQXRhdXInLCdNb2luJywnTGFyYScpDQpkMTwtZGF0YS5mcmFtZShTTCxuYW1lKQ0KZDENCg0KbWFya3M8LWMoNjcsNzgsODAsNzAsMzAsODApDQpwb3NpPC1jKDQsMiwxLDMsNSwxKQ0KZDI8LWRhdGEuZnJhbWUobWFya3MscG9zaSkNCmQyDQpgYGANCg0KTm93IHNpbXBseSBiaW5kIHRoZXNlIHR3byBkYXRhIGZyYW1lcyB1c2luZyBgY2JpbmQoKWA6DQpgYGB7cn0NCmNiPC1jYmluZChkMSxkMikNCmNiDQpgYGANCg0KTGV0J3Mgc2VlIHRoZSBjbGFzcyBvZiBjYjoNCmBgYHtyfQ0KY2xhc3MoY2IpDQpgYGANCg0KLS0tDQoNCkFnYWluIGxldCdzIHNheSB3ZSBoYXZlIHRoZSBmb2xsb3dpbmcgdmVjdG9ycw0KDQpgYGB7cn0NCnBlcnNvbiA8LSBjKCJSaXBvbiIsIk1pbmEiLCJDaHJpcyIsIlNoYWQiKQ0KYWdlIDwtIGMoMjIsMjAsMjQsMTkpDQpnZW5kZXIgPC0gYygiTWFsZSIsIkZlbWFsZSIsIk1hbGUiLCJNYWxlIikNCmBgYA0KDQpJbiB0aGlzIGNhc2Ugd2UgY2FuIHVzZSBgY2JpbmRgIChjb2x1bW4gYmluZCkgdG8gYmluZCB0aGVzZSB2ZWN0b3JzIGludG8gYSBtZXRyaXggYW5kIHRoZW4gY29udmVydGluZyB0aGVtIHVzaW5nIGBhcy5kYXRhLmZyYW1lKClgIGludG8gYSBkYXRhIGZyYW1lOg0KDQpgYGB7cn0NCmRmbTwtY2JpbmQocGVyc29uLGFnZSxnZW5kZXIpDQpkZm0NCmNsYXNzKGRmbSkNCmBgYA0KDQpTbyB0aGUgcmVzdWx0IGNvbWVzIG91dCBhcyBhIDJEIGFycmF5LiBVc2luZyBgYXMuZGF0YS5mcmFtZSgpYDoNCg0KYGBge3J9DQpkZm08LWFzLmRhdGEuZnJhbWUoZGZtKQ0KZGZtDQpjbGFzcyhkZm0pDQpgYGANCg0KLS0tDQoNCiMjIyBSb3cgQmluZCAoUm93IEJpbmQpIA0KDQpgcmJpbmRgIGNhbiBiZSB1c2VkIGluIGJpbmRpbmcgZGlmZmVyZW50IGRhdGEgZnJhbWVzIHdpdGggX3NhbWUgbnVtYmVyIG9mIGNvbHVtbnNfLiAgIA0KTGV0J3MgbWFrZSB0d28gZGF0YSBmcmFtZToNCmBgYHtyfQ0KU0w8LTE6Mw0KbmFtZTwtYygnQWJkdWwnLCdSYWZpcScsJ1NlbGltJykNCm1hcmtzPC1jKDY3LDc4LDgwKQ0KcG9zaTwtYyg0LDIsMSkNCmRmX2Zyb21fc291cmNlXzE8LWRhdGEuZnJhbWUoU0wsbmFtZSxtYXJrcyxwb3NpKQ0KZGZfZnJvbV9zb3VyY2VfMQ0KDQpTTDwtNDo2DQpuYW1lPC1jKCdBdGF1cicsJ01vaW4nLCdMYXJhJykNCm1hcmtzPC1jKDcwLDMwLDgwKQ0KcG9zaTwtYygzLDUsMSkNCmRmX2Zyb21fc291cmNlXzI8LWRhdGEuZnJhbWUoU0wsbmFtZSxtYXJrcyxwb3NpKQ0KZGZfZnJvbV9zb3VyY2VfMg0KYGBgDQoiTm90aWNlIHRoYXQgdGhlIGNvbHVtbnMgbmFtZSBtdXN0IG1hdGNoIGFuZCB0aGUgbnVtYmVyIG9mIGNvbHVtbnMgbXVzdCBiZSBlcXVhbCIgICANCk5vdyBiaW5kIHRoZXNlIGRhdGEgZnJhbWVzIGJ5IHJvdyB1c2luZyBgcmJpbmQoKWA6DQpgYGB7cn0NCnJkZjwtIHJiaW5kKGRmX2Zyb21fc291cmNlXzEsZGZfZnJvbV9zb3VyY2VfMikNCnJkZg0KYGBgDQoNCg0KLS0tDQoNCiMjIyBBZGQgY29sdW1uIG5hbWVzIHRvIHNlYXJjaCBwYXRoDQoNClVzaW5nIHRoZSBmdW5jdGlvbiBgYXR0YWNoKClgIHRoaXMgY2FuIGJlIGRvbmUuIEZvciBleGFtcGxlIHRha2UgdGhlIGRhdGEgZnJhbWUgYHJkZmAgdGhhdCB3ZSBjcmVhdGVkIGFib3ZlIC0gDQpgYGB7cn0NCnJkZg0KYGBgDQpJZiB3ZSB3YW50IHRvIHNlbGVjdCBhIGNvbHVtbiBhcyB2ZWN0b3Igd2Ugd291bGQgbmVlZCB0byBkbyBpdCB1c2luZyBgZGF0YWZyYW1lbmFtZSRjb2x1bW5uYW1lYCAtDQpgYGB7cn0NCnJkZiRuYW1lDQpgYGANCklmIHdlIHJ1biBvbmx5IGBuYW1lYCB3ZSB3aWxsIGdldCBhbiBFcnJvciBzYXlpbmcgIkVycm9yOiBvYmplY3QgJ25hbWUnIG5vdCBmb3VuZCIuICANCg0KQnkgYXR0YWNoaW5nIHRoZSBkYXRhIGZyYW1lIHdlIGNhbiBkbyB0aGUgd29yayBlYXNpbHktDQpgYGB7cn0NCmF0dGFjaChyZGYpDQpuYW1lDQptYXJrcw0KYGBgDQoNClVzaW5nIHNlYXJjaCB3ZSBjYW4gc2VlIGV2ZXJ5dGhpbmcgdGhhdCBpcyBpbiB0aGUgY3VycmVudCBzZWFyY2ggcGF0aCBvZiB0aGUgZ2xvYmFsIGVudmlyb25tZW50IC0NCmBgYHtyfQ0Kc2VhcmNoKCkNCmBgYA0KDQpUbyBkZXRhY2ggYW55dGhpbmcgZnJvbSB0aGUgc2VhcmNoIHBhdGgsIGZvciBleGFtcGxlIHNheSB0aGUgcmRmIGRhdGEgZnJhbWUgLSANCmBgYHtyfQ0KZGV0YWNoKCJyZGYiLCB1bmxvYWQ9VCkNCmBgYA0KDQpOb3cgcmRmIGlzIG5vdCBpbiB0aGUgc2VhcmNoIHBhdGggLSANCmBgYHtyfQ0Kc2VhcmNoKCkNCmBgYA0KQW5kIHdlIGNhbm5vdCBjYWxsIGFueSBjb2x1bW4gYnkgdGhlIGNvbHVtbiBuYW1lIG9ubHkuIFdlIGhhdmUgdG8gdXNlICQgdGhpcyBtZXRob2QgYWdhaW4uDQoNCi0tLQ0KDQoNCiMjIyBKb2luaW5nIHR3byBkYXRhIGZyYW1lcyAtIG1lcmdlDQoNCkxldCdzIGNyZWF0ZSB0d28gZGF0YSBmcmFtZXM6DQpgYGB7cn0NCiMgZGF0YSBmcmFtZSAxDQpkZjEgPSBkYXRhLmZyYW1lKEN1c3RvbWVySWQgPSBjKDE6NiksIA0KICAgICAgICAgICAgICAgICBQcm9kdWN0ID0gYygiT3ZlbiIsIlRlbGV2aXNpb24iLCJNb2JpbGUiLCJXYXNoaW5nTWFjaGluZSIsIkxpZ2h0aW5ncyIsIklwYWQiKSkNCmRmMSANCg0KIyBkYXRhIGZyYW1lIDINCmRmMiA9IGRhdGEuZnJhbWUoQ3VzdG9tZXJJZCA9IGMoMSwgNCwgNiwgOCksIA0KICAgICAgICAgICAgICAgICBTdGF0ZSA9IGMoIkNhbGlmb3JuaWEiLCJTYW50aWFnbyIsIlRleGFzIiwiSW5kaWFuYSIpKSANCmRmMiANCmBgYA0KDQotLS0NCg0KIyMjIyBJbm5lciBKb2luDQpKb2lucyBhbGwgdGhlIG9ic2VydmF0aW9ucyB0aGF0IG1hdGNoIGluIGJvdGggZGF0YSBmcmFtZXMgYnkgYEN1c3RvbWVySWRgDQpgYGB7cn0NCm1lcmdlKHg9ZGYxLCB5PWRmMiwgYnk9IkN1c3RvbWVySWQiKQ0KYGBgDQoNCi0tLQ0KDQojIyMjIE91dGVyIEpvaW4NCkpvaW5zIGFsbCB0aGUgb2JzZXJ2YXRpb25zIGJ5IGBDdXN0b21lcklkYA0KYGBge3J9DQptZXJnZSh4PWRmMSwgeT1kZjIsIGJ5PSJDdXN0b21lcklkIiwgYWxsPVRSVUUpDQpgYGANCg0KLS0tDQoNCiMjIyMgTGVmdCBKb2luDQpKb2lucyBhbGwgdGhlIG9ic2VydmF0aW9ucyBvZiBgZGYxYCB0byBgZGYyYCBieSBgQ3VzdG9tZXJJZGAgDQpgYGB7cn0NCm1lcmdlKHg9ZGYxLCB5PWRmMiwgYnk9IkN1c3RvbWVySWQiLCBhbGwueD1UUlVFKQ0KYGBgDQoNCi0tLQ0KDQojIyMjIFJpZ2h0IEpvaW4NCkpvaW5zIGBkZjFgIHRvIGFsbCB0aGUgb2JzZXJ2YXRpb25zIG9mIGBkZjJgIGJ5IGBDdXN0b21lcklkYCANCmBgYHtyfQ0KbWVyZ2UoeD1kZjEseT1kZjIsYnk9IkN1c3RvbWVySWQiLGFsbC55PVRSVUUpDQpgYGANCg0KLS0tDQoNCiMjIyMgQ3Jvc3Mgam9pbiBpbiBSDQpBIENyb3NzIEpvaW4gKGFsc28gc29tZXRpbWVzIGtub3duIGFzIGEgQ2FydGVzaWFuIEpvaW4pIHJlc3VsdHMgaW4gZXZlcnkgcm93IG9mIG9uZSB0YWJsZSBiZWluZyBqb2luZWQgdG8gZXZlcnkgcm93IG9mIGFub3RoZXIgdGFibGUNCg0KYGBge3J9DQptZXJnZSh4ID0gZGYxLCB5ID0gZGYyLCBieT1OVUxMKQ0KYGBgDQoNCg0KS25vdyBqb2luaW5nIGFuZCBtZXJnaW5nIGluIGRhdGEgZnJhbWVzIHVzaW5nIGBkcGx5cmAgcGFja2FnZSBmcm9tICoqW2hlcmVdKGh0dHA6Ly93d3cuZGF0YXNjaWVuY2VtYWRlc2ltcGxlLmNvbS9qb2luLWluLXItbWVyZ2UtaW4tci8pKiogICANCg0KYGBge3J9DQpkZjMgPC0gZGF0YS5mcmFtZShTTCA9IDE6NSwNCiAgICAgICAgICAgICAgICAgIEN1c3RvbWVySWQgPSAxOjUsDQogICAgICAgICAgICAgICAgICBQcm9kdWN0ID0gYygiT3ZlbiIsIlRlbGV2aXNpb24iLCJNb2JpbGUiLCJXYXNoaW5nTWFjaGluZSIsIkxpZ2h0aW5ncyIpKQ0KZGY0IDwtIGRhdGEuZnJhbWUoU0wgPSAzOTI6Mzk2LA0KICAgICAgICAgICAgICAgICAgQ3VzdG9tZXJJZCA9IDE6NSwgDQogICAgICAgICAgICAgICAgICBMb2NhdGlvbiA9IGMoIkNhbGlmb3JuaWEiLCJTYW50aWFnbyIsIlRleGFzIiwiSW5kaWFuYSIsIk5ldyBZb3JrIikpDQoNCm1lcmdlKHggPSBkZjMgLCB5ID0gZGY0LCBieSA9ICJDdXN0b21lcklkIikNCm1lcmdlKHggPSBkZjMgLCB5ID0gZGY0LCBieSA9ICJDdXN0b21lcklkIiwgc3VmZml4ZXMgPSBjKCJkZjMiLCJkZjQiKSkNCmBgYA0KDQoNCi0tLQ0KDQojIyMgQ2FsY3VsYXRpb25zIGluIGRhdGEgZnJhbWUNCg0KIyMjIyBjb2xNZWFucyANCg0KQ2FsY3VsYXRlIG1lYW4gY29sdW1uIHdpc2UgLSANCmBgYHtyfQ0Kc2V0LnNlZWQoMCkNCmRmMSA8LSBkYXRhLmZyYW1lKGEgPSAxOjEwLA0KICAgICAgICAgICAgICAgICAgYiA9IHJvdW5kKHJub3JtKDEwLCA1LCAxKSwxKSkNCmRmMQ0KY29sTWVhbnMoZGYxKSANCmBgYA0KDQpBZGQgdGhlIG1lYW5zIHRvIHRoZSBkYXRhIGZyYW1lIC0gDQpgYGB7cn0NCnRlbXAgPC0gZGYxDQp0ZW1wWyJNZWFuR2VuIixdIDwtIGNvbE1lYW5zKGRmMSkgICMgYWRkaW5nIGEgbmV3IGNvbHVtbiB3aXRoIGNvbHVtbiB3aXNlIG1lYW5zIA0KdGVtcA0KYGBgDQoNCiMjIyMgcm93TWVhbnMNCg0KQ2FsY3VsYXRlIG1lYW4gcm93IHdpc2UgLSANCmBgYHtyfQ0Kcm93TWVhbnMoZGYxKQ0KYGBgDQoNCkFkZCB0aGUgbWVhbnMgdG8gdGhlIGRhdGEgZnJhbWUgLSANCmBgYHtyfQ0KdGVtcCA8LSBkZjENCnRlbXBbIk1lYW5HZW4iXSA8LSByb3dNZWFucyhkZjEpICAjIGFkZGluZyBhIG5ldyByb3cgd2l0aCByb3cgd2lzZSBtZWFucyANCnRlbXANCmBgYA0KDQpDcmVhdGluZyBhIG5ldyBjb2x1bW4gY2FuIGJlIGRvbmUgdXNpbmcgdGhlIG11dGF0ZSBmdW5jdGlvbiBmcm9tIGRwbHlyIHBhY2thZ2UgLSANCmBgYHtyfQ0KbGlicmFyeShkcGx5cikNCmRmMSAlPiUgDQogIG11dGF0ZShhLGIsTWVhbkRwbCA9IHJvd01lYW5zKGRmMSkpDQpgYGANCg0KIyMjIyBhcHBseSANCg0KYGBge3J9DQphcHBseShkZjEsIDIsIEZVTj1tZWFuKSAgIyBhcHBsaWVzIGZ1bmN0aW9uICdtZWFuJyB0byAybmQgZGltZW5zaW9uIChjb2x1bW5zKQ0KDQphcHBseShkZjEsIDEsIEZVTj1tZWFuKSAgIyBhcHBsaWVzIGZ1bmN0aW9uIHRvIDFzdCBkaW1lbnNpb24gKHJvd3MpDQoNCnNhcHBseShkZjEsIEZVTj1tZWFuKSAgIyBhbHNvIHRha2VzIG1lYW4gb2YgY29sdW1ucywgdHJlYXRpbmcgZGF0YSBmcmFtZSBsaWtlIGxpc3Qgb2YgdmVjdG9ycw0KIA0KbGFwcGx5KGRmMSwgRlVOPW1lYW4pICAjIHJldHVybnMgYSBsaXN0IHdpdGggY29sdW1uIHdpc2UgbWVhbnMNCmBgYA0KDQojIyMgQ29tcGxldGUgcm93cw0KDQpgYGB7cn0NCmRmMiA8LSBkYXRhLmZyYW1lKA0KICBhID0gcmVwKDEwLDUpLA0KICBiID0gcm91bmQocm5vcm0oNSwxMCwzKSksDQogIGMgPSBjKDIsNCxOQSw4LE5BKQ0KKQ0KZGYyDQpgYGANCg0KVGhlIGFib3ZlIGRhdGEgZnJhbWUgaGFzIHR3byBOQS8gdW5jb21wbGV0ZSByb3dzLiBUbyBnZXQgdGhlIGRhdGEgZnJhbWUgd2l0aCBjb21wbGV0ZSByb3dzIHJ1biB0aGUgZm9sbG93aW5nIGNvbW1hbmQgLSANCmBgYHtyfQ0KZGYyW2NvbXBsZXRlLmNhc2VzKGRmMiksXQ0KYGBgDQoNCiMjIyBGaWxsIG1pc3NpbmcgdmFsdWVzDQoNCiMjIyMgdGlkeXIvZmlsbA0KYGBge3J9DQpkZjUgPC0gZGF0YS5mcmFtZShTTCA9IDE6MTAsDQogICAgICAgICAgICAgICAgICB2YWxzID0gYygiYSIsTkEsTkEsImIiLE5BLE5BLE5BLCJjIixOQSxOQSkpDQpkZjUNCmBgYA0KDQpgYGB7cn0NCmRmNW4gPC0gdGlkeXI6OmZpbGwoZGF0YSA9IGRmNSwgdmFscywgLmRpcmVjdGlvbiA9ICJkb3duIikNCmNiaW5kKGRmNSwgdmFsc19maWxsZWQgPSBkZjVuJHZhbHMpDQpgYGANCg0KIyMjIyBSZXBsYWNpbmcgd2l0aCBzb21ldGhpbmcNCg0KYGBge3J9DQpkZjVbaXMubmEoZGY1JHZhbHMpLCJ2YWxzIl0gPC0gMA0KZGY1DQpgYGANCg0KIyMjIE11bHRpcGxlIFJlc3BvbnNlIHRvIER1bW15IFZhcmlhYmxlIENyZWF0aW9uDQoNCkxldCdzIHNlZSB0aGUgZGF0YSAtDQpgYGB7cn0NCkRhdGEgPC0gcmVhZC50YWJsZSgibXVsdGlwbGUgcmVwb25zZS50eHQiLCBoZWFkZXIgPSBULCBmaWxsID0gVCkNCkRhdGENCmBgYA0KDQpDcmVhdGluZyBkdW1teSB2YXJpYWJsZXMgZnJvbSB0aGlzIGNvbHVtbiAtIA0KYGBge3J9DQpEYXRhJFJlc3BvbnNlcyA8LSBhcy5jaGFyYWN0ZXIoRGF0YSRSZXNwb25zZSkNCiMgc3BsaXR0aW5nIHRoZSByZXNwb25zZXMNCnJlc3Auc3BsaXQgPC0gc3Ryc3BsaXQoRGF0YSRSZXNwb25zZXMsIHNwbGl0ID0gIiwiKQ0KbGV2IDwtIHVuaXF1ZSh1bmxpc3QocmVzcC5zcGxpdCkpICAjIHRha2luZyB1bmlxdWUgdmFsdWVzIGZvciBjb2x1bW4NCiMgY3JlYXRpbmcgZHVtbXkNCnJlc3AuZHVtbXkgPC0gdChzYXBwbHkocmVzcC5zcGxpdCwgDQogICAgICAgICAgICAgICAgICAgICAgIEZVTiA9IGZ1bmN0aW9uKHgpIHRhYmxlKGZhY3Rvcih4LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzPWxldikpKSkNCiMgYXNzaWduaW5nIGl0IHRvIGEgZGF0YSBmcmFtZQ0KRGF0YTIgPC0gd2l0aChEYXRhLCBjYmluZChSZXNwb25zZXMsIGRhdGEuZnJhbWUocmVzcC5kdW1teSkpKQ0KRGF0YTINCmBgYA0KDQpUaGlzIHNvbHV0aW9uIG9mIGR1bW15IHZhcmlhYmxlIGNyZWF0aW9uIGZyb20gbXVsdGlwbGUgcmVzcG9uc2VzIGlzIHRha2VuIGZyb20gW2hlcmVdKGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vYS81NjI2NDk2NC8xMzMyMzQxMykuDQoNCg==