For Loop

> for(i in 1:3){
+ print(i)
+ }
[1] 1
[1] 2
[1] 3
> counter <- 0
> items <- 4:8
> for (i in items){
+   counter <- counter+1
+   cat("Now in loop",counter,"and item is",i,"\n")
+ }
Now in loop 1 and item is 4 
Now in loop 2 and item is 5 
Now in loop 3 and item is 6 
Now in loop 4 and item is 7 
Now in loop 5 and item is 8 
> ind <- c(0.4, 3.2, 5.9, 1000)
> counter <- 0
> for (i in ind){
+   counter <- counter+1
+   cat("Index value in loop",counter,"is",i,"\n")
+ }
Index value in loop 1 is 0.4 
Index value in loop 2 is 3.2 
Index value in loop 3 is 5.9 
Index value in loop 4 is 1000 

The previous code can be written in the following way also-

> ind <- c(0.4, 3.2, 5.9, 1000)
> for (i in 1:length(ind)){
+   cat("Index value in loop",i,"is",ind[i],"\n")
+ }
Index value in loop 1 is 0.4 
Index value in loop 2 is 3.2 
Index value in loop 3 is 5.9 
Index value in loop 4 is 1000 

Expert solutions to R Studio statistics assignments.

(OPTIONAL PART) Example of a complicated code to find whether the objects in a list is matrix or not and if that is matrix then calculating the number of rows and columns and data types of that matrix.
Here is the list-

> mix <- list(obj1=c(3.4,1),
+             obj2=matrix(1:4,2,2),
+             obj3=matrix(c(T,T,F,T,F,F),3,2),
+             obj4="string here",
+             obj5=matrix(c("red","green","blue","yellow")))
> print(mix)
$obj1
[1] 3.4 1.0

$obj2
     [,1] [,2]
[1,]    1    3
[2,]    2    4

$obj3
      [,1]  [,2]
[1,]  TRUE  TRUE
[2,]  TRUE FALSE
[3,] FALSE FALSE

$obj4
[1] "string here"

$obj5
     [,1]    
[1,] "red"   
[2,] "green" 
[3,] "blue"  
[4,] "yellow"

Creating space for the results with NA-

> name <- names(mix)
> is.mat <- rep(NA,length(mix))
> nr <- rep(NA,length(mix))
> nc <- rep(NA,length(mix))
> data.type <- rep(NA,length(mix))

Code for calculation-

> for (i in 1:length(mix)){
+   obj <- mix[[i]]
+   if(is.matrix(obj)){
+     is.mat[i] <- "YES"
+     nr[i] <- nrow(obj)
+     nc[i] <- ncol(obj)
+     data.type[i] <- class(as.vector(obj))
+   }else{
+     is.mat[i] <- "NO"
+   }
+ }

Showing the results using data frame-

> data.frame(name,is.mat,nr,nc,data.type,stringsAsFactors=FALSE)
  name is.mat nr nc data.type
1 obj1     NO NA NA      <NA>
2 obj2    YES  2  2   integer
3 obj3    YES  3  2   logical
4 obj4     NO NA NA      <NA>
5 obj5    YES  4  1 character

While Loop

> counter <- 1
> while (counter <=5){
+   cat("Loop",counter,"...\n")
+   counter <- counter+1
+   cat(ifelse(test = counter <=5, 
+              yes = "Will continue the loop\n\n", 
+              no = "Condition is false and will end loop\n---X---"))
+ }
Loop 1 ...
Will continue the loop

Loop 2 ...
Will continue the loop

Loop 3 ...
Will continue the loop

Loop 4 ...
Will continue the loop

Loop 5 ...
Condition is false and will end loop
---X---

Loop using Apply

The following code cycles through each row and stores the sum in row.sum-

> emat <- matrix(1:12,4,3)
> emat
     [,1] [,2] [,3]
[1,]    1    5    9
[2,]    2    6   10
[3,]    3    7   11
[4,]    4    8   12
> row.sum <- rep(NA, nrow(emat))
> for (i in 1:nrow(emat)){
+   row.sum[i] <- sum(emat[i,])
+ }
> row.sum
[1] 15 18 21 24

The following code using apply is equivalent to the previous one and much simpler-

> apply(X=emat, MARGIN=1, FUN=sum)
[1] 15 18 21 24
> apply(emat,1,mean)
[1] 5 6 7 8

The MARGIN index follows the positional order of the dimension for matrices and arrays.
Here -

  • 1 means rows
  • 2 means columns
  • 3 means layers
  • 4 means blocks, and so on.
> emat
     [,1] [,2] [,3]
[1,]    1    5    9
[2,]    2    6   10
[3,]    3    7   11
[4,]    4    8   12
> apply(emat,2,sum)
[1] 10 26 42

The following code finds the diagonals of the arrays-

> arr <- array(1:18,dim=c(3,3,2))
> arr
, , 1

     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8
[3,]    3    6    9

, , 2

     [,1] [,2] [,3]
[1,]   10   13   16
[2,]   11   14   17
[3,]   12   15   18
> apply(arr,3, diag)
     [,1] [,2]
[1,]    1   10
[2,]    5   14
[3,]    9   18
> rmat <- matrix(round(runif(9,min=1,max=30)),3,3)
> rmat
     [,1] [,2] [,3]
[1,]   27   17    4
[2,]    2   30    6
[3,]    1   23   27
> apply(rmat, 2, sort, decreasing=F)
     [,1] [,2] [,3]
[1,]    1   17    4
[2,]    2   23    6
[3,]   27   30   27

tapply

tapply performs operations on subsets of the object of interest-

> df <- data.frame(age=c(22,20,NA,24,19),
+                  sex=factor(c("M","F","F","M","M")),
+                  stringsAsFactors=FALSE)
> df
  age sex
1  22   M
2  20   F
3  NA   F
4  24   M
5  19   M
> tapply(X=df$age, INDEX=df$sex, FUN=mean, na.rm=T)
       F        M 
20.00000 21.66667 

lapply and sapply

lapply can operate object by object on a list-

> arr <- list(obj1=c(3.4,1),
+             obj2=matrix(1:4,2,2),
+             obj3=matrix(c(T,T,F,T,F,F),3,2),
+             obj4="string here",
+             obj5=matrix(c("red","green","blue","yellow")))
> unlist(lapply(arr, FUN=is.matrix))
 obj1  obj2  obj3  obj4  obj5 
FALSE  TRUE  TRUE FALSE  TRUE 

sapply does the same work as previous but shows the output in a simpler way-

> sapply(arr,is.matrix)
 obj1  obj2  obj3  obj4  obj5 
FALSE  TRUE  TRUE FALSE  TRUE 

What sapply actually do is, it tries to simplify the output of lapply when possible. If the result is a list where every element is a vector of the same length then it returns a vector(when length=1)/matrix(length>1) ,and if not then it returns a list just like lapply.

> unlist(lapply(arr, FUN=is.matrix))
 obj1  obj2  obj3  obj4  obj5 
FALSE  TRUE  TRUE FALSE  TRUE 

In FUN argument, custom functions can also be defined -

> sapply(arr, function(x) ifelse(is.matrix(x), "Matrix", "Not Specified"))
           obj1            obj2            obj3            obj4            obj5 
"Not Specified"        "Matrix"        "Matrix" "Not Specified"        "Matrix" 

mapply

mapply() applies a Function to Multiple List or multiple Vector Arguments -

> set.seed(0)
> mapply(FUN = function(...) round(runif(...)),
+        n=c(1,5,3), min=c(1,2,9), max=10
+        )
[[1]]
[1] 9

[[2]]
[1] 4 5 7 9 4

[[3]]
[1] 10 10 10
> word <- function(C, k) paste(rep(C, times = k), collapse = "")
> mapply(word, C=LETTERS[1:6], k=6:1, SIMPLIFY = T)
       A        B        C        D        E        F 
"AAAAAA"  "BBBBB"   "CCCC"    "DDD"     "EE"      "F" 

rapply

There are cases when lapply doesnโ€™t work fine. Using rapply we can specify a function to operate only in a specific class -

> list1 <- list(matrix1 = matrix(5:8,nrow=2,ncol=2),
+               matrix2 = matrix(1:16, nrow = 4, ncol = 4),
+               character = "sample one",
+               a_df = data.frame(X = c(1,2,3), Y = c(12,13,10))
+               )
> rapply(list1, nchar, "character")
character 
       10 

Unlist is default argument for how -

> rapply(list1, diag, "array", how = "unlist")
matrix11 matrix12 matrix21 matrix22 matrix23 matrix24 
       5        8        1        6       11       16 

Using list, we can get a similar output like lapply -

> rapply(list1, diag, "array", how = "list")
$matrix1
[1] 5 8

$matrix2
[1]  1  6 11 16

$character
NULL

$a_df
$a_df$X
NULL

$a_df$Y
NULL

Replacing the output to the supplied object -

> rapply(list1, diag, "array", how = "replace")
$matrix1
[1] 5 8

$matrix2
[1]  1  6 11 16

$character
[1] "sample one"

$a_df
  X  Y
1 1 12
2 2 13
3 3 10

We can apply a function to any types of object by default -

> rapply(list1, is.matrix, classes = "ANY")
  matrix1   matrix2 character    a_df.X    a_df.Y 
     TRUE      TRUE     FALSE     FALSE     FALSE 

Repeat

Repeat does the work of repeating of a program until the execution of break command -

> counter <- 0
> repeat{
+   counter <- counter + 1
+   print(paste("Repeating line",counter))
+   if(counter >=10) break
+ }
[1] "Repeating line 1"
[1] "Repeating line 2"
[1] "Repeating line 3"
[1] "Repeating line 4"
[1] "Repeating line 5"
[1] "Repeating line 6"
[1] "Repeating line 7"
[1] "Repeating line 8"
[1] "Repeating line 9"
[1] "Repeating line 10"

Example with next and break -

> counter <- 0
> repeat{
+   counter <- counter + 1
+   if (counter < 5){
+     print("Going to step")
+     next
+     # this next will take the code to the next loop
+     print(counter) # this won't execute because next has already been executed
+   }else if(counter > 10) {
+     print("Executing break")
+     break
+     # this break statemend will kill the loop
+   }else{
+     print(counter)
+   }
+ }
[1] "Going to step"
[1] "Going to step"
[1] "Going to step"
[1] "Going to step"
[1] 5
[1] 6
[1] 7
[1] 8
[1] 9
[1] 10
[1] "Executing break"

This is an example of repeat-

> num1 <- 1
> num2 <- 1
> n <- 1000
> cat("== Showing Fibonacci numbers upto",n,"==\n")
== Showing Fibonacci numbers upto 1000 ==
> repeat{
+   feb <- num1+num2
+   if (feb>=n){
+     cat("break executed...")
+     break
+   }
+   num1 <- num2
+   num2 <- feb
+   cat(feb," ")
+   
+ }
2  3  5  8  13  21  34  55  89  144  233  377  610  987  break executed...

The repetition continues until the execution of any break statement.

split()

Returns a list splitting the observations of a vector x(or data frame) according to given f -

> df <- data.frame(gender = c(rep("boy",3),
+                           rep("girl",4),
+                           rep("unknown",2)),
+                  freq = c(7,7,1,6,5,2,4,8,9))
> split(x = df$freq, f = df$gender) 
$boy
[1] 7 7 1

$girl
[1] 6 5 2 4

$unknown
[1] 8 9

So it basically loops through the vectors pairwise and assigns elements of x to respective f in list, which comes handy in some cases.

LS0tDQp0aXRsZTogIkxvb3BzIg0KYXV0aG9yOiAiTUQgQUhTQU5VTCBJU0xBTSINCm91dHB1dDogDQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgdGhlbWU6IGNlcnVsZWFuDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KLS0tDQoNCmBgYHtyLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KA0KICBjb21tZW50ID0gIiIsIHByb21wdCA9IFRSVUUsIG1lc3NhZ2U9Riwgd2FybmluZyA9Rg0KKQ0KYGBgDQoNCmBgYHtjc3MsIGVjaG89RkFMU0V9DQoucHVsbC1yaWdodCB7DQogICAgZmxvYXQ6IHVuc2V0IWltcG9ydGFudDsNCn0NCmhyew0KICBtYXJnaW46IDJlbSBhdXRvOw0KICBib3JkZXItdG9wOiAycHggc29saWQ7DQp9DQpoMSwgaDQgew0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQpoMiwgaDMgew0KICBjb2xvcjogYmxhY2s7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBwYWRkaW5nLWxlZnQ6IDFlbTsNCiAgYm9yZGVyLWxlZnQ6IDhweCBzb2xpZCBEb2RnZXJCbHVlOw0KICBib3JkZXItcmFkaXVzOiA3cHg7DQogIGxpbmUtaGVpZ2h0OiAyZW07DQogIGJhY2tncm91bmQtY29sb3I6IExhdmVuZGVyOw0KfQ0KaDJ7Zm9udC1zaXplOjIwcHg7fQ0KaDN7Zm9udC1zaXplOjE2cHg7bGluZS1oZWlnaHQ6MS41ZW07fQ0KYGBgDQoNCi0tLQ0KDQojIyBGb3IgTG9vcA0KDQpgYGB7cn0NCmZvcihpIGluIDE6Myl7DQpwcmludChpKQ0KfQ0KYGBgDQoNCmBgYHtyfQ0KY291bnRlciA8LSAwDQppdGVtcyA8LSA0OjgNCmZvciAoaSBpbiBpdGVtcyl7DQogIGNvdW50ZXIgPC0gY291bnRlcisxDQogIGNhdCgiTm93IGluIGxvb3AiLGNvdW50ZXIsImFuZCBpdGVtIGlzIixpLCJcbiIpDQp9DQpgYGANCg0KYGBge3J9DQppbmQgPC0gYygwLjQsIDMuMiwgNS45LCAxMDAwKQ0KY291bnRlciA8LSAwDQpmb3IgKGkgaW4gaW5kKXsNCiAgY291bnRlciA8LSBjb3VudGVyKzENCiAgY2F0KCJJbmRleCB2YWx1ZSBpbiBsb29wIixjb3VudGVyLCJpcyIsaSwiXG4iKQ0KfQ0KYGBgDQoNClRoZSBwcmV2aW91cyBjb2RlIGNhbiBiZSB3cml0dGVuIGluIHRoZSBmb2xsb3dpbmcgd2F5IGFsc28tDQpgYGB7cn0NCmluZCA8LSBjKDAuNCwgMy4yLCA1LjksIDEwMDApDQpmb3IgKGkgaW4gMTpsZW5ndGgoaW5kKSl7DQogIGNhdCgiSW5kZXggdmFsdWUgaW4gbG9vcCIsaSwiaXMiLGluZFtpXSwiXG4iKQ0KfQ0KYGBgDQoNCi0tLQ0KDQpFeHBlcnQgc29sdXRpb25zIHRvIFtSIFN0dWRpbyBzdGF0aXN0aWNzIGFzc2lnbm1lbnRzXShodHRwczovL3d3dy5ob21ld29ya2hlbHBvbmxpbmUubmV0L3Byb2dyYW1taW5nL3ItcHJvZ3JhbW1pbmcgIlIgU3R1ZGlvIHN0YXRpc3RpY3MgaGVscCIpLg0KDQooT1BUSU9OQUwgUEFSVCkNCkV4YW1wbGUgb2YgYSBjb21wbGljYXRlZCBjb2RlIHRvIGZpbmQgd2hldGhlciB0aGUgb2JqZWN0cyBpbiBhIGxpc3QgaXMgbWF0cml4IG9yIG5vdCBhbmQgaWYgdGhhdCBpcyBtYXRyaXggdGhlbiBjYWxjdWxhdGluZyB0aGUgbnVtYmVyIG9mIHJvd3MgYW5kIGNvbHVtbnMgYW5kIGRhdGEgdHlwZXMgb2YgdGhhdCBtYXRyaXguICAgDQpIZXJlIGlzIHRoZSBsaXN0LQ0KYGBge3J9DQptaXggPC0gbGlzdChvYmoxPWMoMy40LDEpLA0KICAgICAgICAgICAgb2JqMj1tYXRyaXgoMTo0LDIsMiksDQogICAgICAgICAgICBvYmozPW1hdHJpeChjKFQsVCxGLFQsRixGKSwzLDIpLA0KICAgICAgICAgICAgb2JqND0ic3RyaW5nIGhlcmUiLA0KICAgICAgICAgICAgb2JqNT1tYXRyaXgoYygicmVkIiwiZ3JlZW4iLCJibHVlIiwieWVsbG93IikpKQ0KcHJpbnQobWl4KQ0KYGBgDQoNCkNyZWF0aW5nIHNwYWNlIGZvciB0aGUgcmVzdWx0cyB3aXRoIGBOQWAtDQpgYGB7cn0NCm5hbWUgPC0gbmFtZXMobWl4KQ0KaXMubWF0IDwtIHJlcChOQSxsZW5ndGgobWl4KSkNCm5yIDwtIHJlcChOQSxsZW5ndGgobWl4KSkNCm5jIDwtIHJlcChOQSxsZW5ndGgobWl4KSkNCmRhdGEudHlwZSA8LSByZXAoTkEsbGVuZ3RoKG1peCkpDQpgYGANCg0KQ29kZSBmb3IgY2FsY3VsYXRpb24tDQpgYGB7cn0NCmZvciAoaSBpbiAxOmxlbmd0aChtaXgpKXsNCiAgb2JqIDwtIG1peFtbaV1dDQogIGlmKGlzLm1hdHJpeChvYmopKXsNCiAgICBpcy5tYXRbaV0gPC0gIllFUyINCiAgICBucltpXSA8LSBucm93KG9iaikNCiAgICBuY1tpXSA8LSBuY29sKG9iaikNCiAgICBkYXRhLnR5cGVbaV0gPC0gY2xhc3MoYXMudmVjdG9yKG9iaikpDQogIH1lbHNlew0KICAgIGlzLm1hdFtpXSA8LSAiTk8iDQogIH0NCn0NCmBgYA0KDQpTaG93aW5nIHRoZSByZXN1bHRzIHVzaW5nIGBkYXRhIGZyYW1lYC0NCmBgYHtyfQ0KZGF0YS5mcmFtZShuYW1lLGlzLm1hdCxucixuYyxkYXRhLnR5cGUsc3RyaW5nc0FzRmFjdG9ycz1GQUxTRSkNCmBgYA0KDQojIyBXaGlsZSBMb29wDQoNCmBgYHtyfQ0KY291bnRlciA8LSAxDQp3aGlsZSAoY291bnRlciA8PTUpew0KICBjYXQoIkxvb3AiLGNvdW50ZXIsIi4uLlxuIikNCiAgY291bnRlciA8LSBjb3VudGVyKzENCiAgY2F0KGlmZWxzZSh0ZXN0ID0gY291bnRlciA8PTUsIA0KICAgICAgICAgICAgIHllcyA9ICJXaWxsIGNvbnRpbnVlIHRoZSBsb29wXG5cbiIsIA0KICAgICAgICAgICAgIG5vID0gIkNvbmRpdGlvbiBpcyBmYWxzZSBhbmQgd2lsbCBlbmQgbG9vcFxuLS0tWC0tLSIpKQ0KfQ0KYGBgDQoNCiMjIExvb3AgdXNpbmcgQXBwbHkNCg0KVGhlIGZvbGxvd2luZyBjb2RlIGN5Y2xlcyB0aHJvdWdoIGVhY2ggcm93IGFuZCBzdG9yZXMgdGhlIHN1bSBpbiByb3cuc3VtLQ0KYGBge3J9DQplbWF0IDwtIG1hdHJpeCgxOjEyLDQsMykNCmVtYXQNCnJvdy5zdW0gPC0gcmVwKE5BLCBucm93KGVtYXQpKQ0KZm9yIChpIGluIDE6bnJvdyhlbWF0KSl7DQogIHJvdy5zdW1baV0gPC0gc3VtKGVtYXRbaSxdKQ0KfQ0Kcm93LnN1bQ0KYGBgDQoNClRoZSBmb2xsb3dpbmcgY29kZSB1c2luZyBgYXBwbHlgIGlzIGVxdWl2YWxlbnQgdG8gdGhlIHByZXZpb3VzIG9uZSBhbmQgbXVjaCBzaW1wbGVyLQ0KYGBge3J9DQphcHBseShYPWVtYXQsIE1BUkdJTj0xLCBGVU49c3VtKQ0KYXBwbHkoZW1hdCwxLG1lYW4pDQpgYGANClRoZSBNQVJHSU4gaW5kZXggZm9sbG93cyB0aGUgcG9zaXRpb25hbCBvcmRlciBvZiB0aGUgZGltZW5zaW9uIGZvcg0KbWF0cmljZXMgYW5kIGFycmF5cy4gICAgDQpIZXJlIC0gICANCg0KKiAxIG1lYW5zIHJvd3MgICAgDQoqIDIgbWVhbnMgY29sdW1ucyAgICAgDQoqIDMgbWVhbnMgbGF5ZXJzICAgDQoqIDQgbWVhbnMgYmxvY2tzLCBhbmQgc28gb24uICAgDQpgYGB7cn0NCmVtYXQNCmFwcGx5KGVtYXQsMixzdW0pDQpgYGANClRoZSBmb2xsb3dpbmcgY29kZSBmaW5kcyB0aGUgZGlhZ29uYWxzIG9mIHRoZSBhcnJheXMtDQpgYGB7cn0NCmFyciA8LSBhcnJheSgxOjE4LGRpbT1jKDMsMywyKSkNCmFycg0KYXBwbHkoYXJyLDMsIGRpYWcpDQpgYGANCmBgYHtyfQ0Kcm1hdCA8LSBtYXRyaXgocm91bmQocnVuaWYoOSxtaW49MSxtYXg9MzApKSwzLDMpDQpybWF0DQphcHBseShybWF0LCAyLCBzb3J0LCBkZWNyZWFzaW5nPUYpDQpgYGANCg0KIyMjIHRhcHBseQ0KDQpgdGFwcGx5YCBwZXJmb3JtcyBvcGVyYXRpb25zIG9uIHN1YnNldHMgb2YgdGhlIG9iamVjdCBvZiBpbnRlcmVzdC0NCmBgYHtyfQ0KZGYgPC0gZGF0YS5mcmFtZShhZ2U9YygyMiwyMCxOQSwyNCwxOSksDQogICAgICAgICAgICAgICAgIHNleD1mYWN0b3IoYygiTSIsIkYiLCJGIiwiTSIsIk0iKSksDQogICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UpDQpkZg0KdGFwcGx5KFg9ZGYkYWdlLCBJTkRFWD1kZiRzZXgsIEZVTj1tZWFuLCBuYS5ybT1UKQ0KYGBgDQoNCg0KIyMjIGxhcHBseSBhbmQgc2FwcGx5DQoNCmBsYXBwbHlgIGNhbiBvcGVyYXRlIG9iamVjdCBieSBvYmplY3Qgb24gYSBsaXN0LQ0KYGBge3J9DQphcnIgPC0gbGlzdChvYmoxPWMoMy40LDEpLA0KICAgICAgICAgICAgb2JqMj1tYXRyaXgoMTo0LDIsMiksDQogICAgICAgICAgICBvYmozPW1hdHJpeChjKFQsVCxGLFQsRixGKSwzLDIpLA0KICAgICAgICAgICAgb2JqND0ic3RyaW5nIGhlcmUiLA0KICAgICAgICAgICAgb2JqNT1tYXRyaXgoYygicmVkIiwiZ3JlZW4iLCJibHVlIiwieWVsbG93IikpKQ0KdW5saXN0KGxhcHBseShhcnIsIEZVTj1pcy5tYXRyaXgpKQ0KYGBgDQoNCmBzYXBwbHlgIGRvZXMgdGhlIHNhbWUgd29yayBhcyBwcmV2aW91cyBidXQgc2hvd3MgdGhlIG91dHB1dCBpbiBhIHNpbXBsZXIgd2F5LQ0KYGBge3J9DQpzYXBwbHkoYXJyLGlzLm1hdHJpeCkNCmBgYA0KDQpXaGF0IHNhcHBseSBhY3R1YWxseSBkbyBpcywgaXQgdHJpZXMgdG8gc2ltcGxpZnkgdGhlIG91dHB1dCBvZiBsYXBwbHkgd2hlbiBwb3NzaWJsZS4gSWYgdGhlIHJlc3VsdCBpcyBhIGxpc3Qgd2hlcmUgZXZlcnkgZWxlbWVudCBpcyBhIHZlY3RvciBvZiB0aGUgc2FtZSBsZW5ndGggdGhlbiBpdCByZXR1cm5zIGEgdmVjdG9yKHdoZW4gbGVuZ3RoPTEpL21hdHJpeChsZW5ndGg+MSkgLGFuZCBpZiBub3QgdGhlbiBpdCByZXR1cm5zIGEgbGlzdCBqdXN0IGxpa2UgbGFwcGx5Lg0KDQpgYGB7cn0NCnVubGlzdChsYXBwbHkoYXJyLCBGVU49aXMubWF0cml4KSkNCmBgYA0KDQpJbiBGVU4gYXJndW1lbnQsIGN1c3RvbSBmdW5jdGlvbnMgY2FuIGFsc28gYmUgZGVmaW5lZCAtIA0KYGBge3J9DQpzYXBwbHkoYXJyLCBmdW5jdGlvbih4KSBpZmVsc2UoaXMubWF0cml4KHgpLCAiTWF0cml4IiwgIk5vdCBTcGVjaWZpZWQiKSkNCmBgYA0KDQojIyMgbWFwcGx5DQoNCm1hcHBseSgpIGFwcGxpZXMgYSBGdW5jdGlvbiB0byBNdWx0aXBsZSBMaXN0IG9yIG11bHRpcGxlIFZlY3RvciBBcmd1bWVudHMgLQ0KDQpgYGB7cn0NCnNldC5zZWVkKDApDQptYXBwbHkoRlVOID0gZnVuY3Rpb24oLi4uKSByb3VuZChydW5pZiguLi4pKSwNCiAgICAgICBuPWMoMSw1LDMpLCBtaW49YygxLDIsOSksIG1heD0xMA0KICAgICAgICkNCmBgYA0KDQoNCmBgYHtyfQ0Kd29yZCA8LSBmdW5jdGlvbihDLCBrKSBwYXN0ZShyZXAoQywgdGltZXMgPSBrKSwgY29sbGFwc2UgPSAiIikNCm1hcHBseSh3b3JkLCBDPUxFVFRFUlNbMTo2XSwgaz02OjEsIFNJTVBMSUZZID0gVCkNCmBgYA0KDQojIyMgcmFwcGx5DQoNClRoZXJlIGFyZSBjYXNlcyB3aGVuIGxhcHBseSBkb2Vzbid0IHdvcmsgZmluZS4gVXNpbmcgcmFwcGx5IHdlIGNhbiBzcGVjaWZ5IGEgZnVuY3Rpb24gdG8gb3BlcmF0ZSBvbmx5IGluIGEgc3BlY2lmaWMgY2xhc3MgLSANCg0KYGBge3J9DQpsaXN0MSA8LSBsaXN0KG1hdHJpeDEgPSBtYXRyaXgoNTo4LG5yb3c9MixuY29sPTIpLA0KICAgICAgICAgICAgICBtYXRyaXgyID0gbWF0cml4KDE6MTYsIG5yb3cgPSA0LCBuY29sID0gNCksDQogICAgICAgICAgICAgIGNoYXJhY3RlciA9ICJzYW1wbGUgb25lIiwNCiAgICAgICAgICAgICAgYV9kZiA9IGRhdGEuZnJhbWUoWCA9IGMoMSwyLDMpLCBZID0gYygxMiwxMywxMCkpDQogICAgICAgICAgICAgICkNCnJhcHBseShsaXN0MSwgbmNoYXIsICJjaGFyYWN0ZXIiKQ0KYGBgDQoNClVubGlzdCBpcyBkZWZhdWx0IGFyZ3VtZW50IGZvciBgaG93YCAtIA0KYGBge3J9DQpyYXBwbHkobGlzdDEsIGRpYWcsICJhcnJheSIsIGhvdyA9ICJ1bmxpc3QiKQ0KYGBgDQoNClVzaW5nIGxpc3QsIHdlIGNhbiBnZXQgYSBzaW1pbGFyIG91dHB1dCBsaWtlIGxhcHBseSAtDQpgYGB7cn0NCnJhcHBseShsaXN0MSwgZGlhZywgImFycmF5IiwgaG93ID0gImxpc3QiKQ0KYGBgDQoNClJlcGxhY2luZyB0aGUgb3V0cHV0IHRvIHRoZSBzdXBwbGllZCBvYmplY3QgLSANCmBgYHtyfQ0KcmFwcGx5KGxpc3QxLCBkaWFnLCAiYXJyYXkiLCBob3cgPSAicmVwbGFjZSIpDQpgYGANCg0KV2UgY2FuIGFwcGx5IGEgZnVuY3Rpb24gdG8gYW55IHR5cGVzIG9mIG9iamVjdCBieSBkZWZhdWx0IC0gDQpgYGB7cn0NCg0KcmFwcGx5KGxpc3QxLCBpcy5tYXRyaXgsIGNsYXNzZXMgPSAiQU5ZIikNCmBgYA0KDQojIyBSZXBlYXQNCg0KUmVwZWF0IGRvZXMgdGhlIHdvcmsgb2YgcmVwZWF0aW5nIG9mIGEgcHJvZ3JhbSB1bnRpbCB0aGUgZXhlY3V0aW9uIG9mIGJyZWFrIGNvbW1hbmQgLSANCmBgYHtyfQ0KY291bnRlciA8LSAwDQpyZXBlYXR7DQogIGNvdW50ZXIgPC0gY291bnRlciArIDENCiAgcHJpbnQocGFzdGUoIlJlcGVhdGluZyBsaW5lIixjb3VudGVyKSkNCiAgaWYoY291bnRlciA+PTEwKSBicmVhaw0KfQ0KYGBgDQoNCkV4YW1wbGUgd2l0aCBgbmV4dGAgYW5kIGBicmVha2AgLSANCmBgYHtyfQ0KY291bnRlciA8LSAwDQpyZXBlYXR7DQogIGNvdW50ZXIgPC0gY291bnRlciArIDENCiAgaWYgKGNvdW50ZXIgPCA1KXsNCiAgICBwcmludCgiR29pbmcgdG8gc3RlcCIpDQogICAgbmV4dA0KICAgICMgdGhpcyBuZXh0IHdpbGwgdGFrZSB0aGUgY29kZSB0byB0aGUgbmV4dCBsb29wDQogICAgcHJpbnQoY291bnRlcikgIyB0aGlzIHdvbid0IGV4ZWN1dGUgYmVjYXVzZSBuZXh0IGhhcyBhbHJlYWR5IGJlZW4gZXhlY3V0ZWQNCiAgfWVsc2UgaWYoY291bnRlciA+IDEwKSB7DQogICAgcHJpbnQoIkV4ZWN1dGluZyBicmVhayIpDQogICAgYnJlYWsNCiAgICAjIHRoaXMgYnJlYWsgc3RhdGVtZW5kIHdpbGwga2lsbCB0aGUgbG9vcA0KICB9ZWxzZXsNCiAgICBwcmludChjb3VudGVyKQ0KICB9DQp9DQpgYGANCg0KDQpUaGlzIGlzIGFuIGV4YW1wbGUgb2YgYHJlcGVhdGAtDQpgYGB7cn0NCm51bTEgPC0gMQ0KbnVtMiA8LSAxDQpuIDwtIDEwMDANCmNhdCgiPT0gU2hvd2luZyBGaWJvbmFjY2kgbnVtYmVycyB1cHRvIixuLCI9PVxuIikNCnJlcGVhdHsNCiAgZmViIDwtIG51bTErbnVtMg0KICBpZiAoZmViPj1uKXsNCiAgICBjYXQoImJyZWFrIGV4ZWN1dGVkLi4uIikNCiAgICBicmVhaw0KICB9DQogIG51bTEgPC0gbnVtMg0KICBudW0yIDwtIGZlYg0KICBjYXQoZmViLCIgIikNCiAgDQp9DQpgYGANClRoZSByZXBldGl0aW9uIGNvbnRpbnVlcyB1bnRpbCB0aGUgZXhlY3V0aW9uIG9mIGFueSBicmVhayBzdGF0ZW1lbnQuICAgICANCg0KDQojIyBzcGxpdCgpDQoNClJldHVybnMgYSBsaXN0IHNwbGl0dGluZyB0aGUgb2JzZXJ2YXRpb25zIG9mIGEgdmVjdG9yIHgob3IgZGF0YSBmcmFtZSkgYWNjb3JkaW5nIHRvIGdpdmVuIGYgLSANCmBgYHtyfQ0KZGYgPC0gZGF0YS5mcmFtZShnZW5kZXIgPSBjKHJlcCgiYm95IiwzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwKCJnaXJsIiw0KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwKCJ1bmtub3duIiwyKSksDQogICAgICAgICAgICAgICAgIGZyZXEgPSBjKDcsNywxLDYsNSwyLDQsOCw5KSkNCnNwbGl0KHggPSBkZiRmcmVxLCBmID0gZGYkZ2VuZGVyKSANCmBgYA0KDQpTbyBpdCBiYXNpY2FsbHkgbG9vcHMgdGhyb3VnaCB0aGUgdmVjdG9ycyBwYWlyd2lzZSBhbmQgYXNzaWducyBlbGVtZW50cyBvZiB4IHRvIHJlc3BlY3RpdmUgZiBpbiBsaXN0LCB3aGljaCBjb21lcyBoYW5keSBpbiBzb21lIGNhc2VzLiA=