Chapter 11 Writing functions >/h1>

11.1 The [function] command

Functions allow your code to be reused without having to copy and paste. It also allows other users to use your functions to carry out the same computations on their own data or objects.

Learn how to define and use arguments, how to return output from a function and how to specialize your functions in other ways.

11.1.1 Function Creation

Functions are created with the [function()] command. The standard format: functionname <- function(art1, arg2, arg3,…) { do any code in here when the function is called }

# fibonacci sequence
myfib<-function(){
  fib.a<-1
  fib.b<-1
  cat(fib.a,", ",fib.b,", ",sep=" ")
  repeat{
    temp <-fib.a+fib.b
    fib.a<-fib.b
    fib.b<-temp
    cat(fib.b,", ",sep=" ")
    if(fib.b>150){
      cat("break now...")
      break
    }
  }
}
ls()
 [1] "a"                    "b"                    "bar"                  "baz"                 
 [5] "char.mat"             "char.vec"             "counter"              "ctrl"                
 [9] "df.world_ports"       "dia.url"              "diamonds"             "fac.vec"             
[13] "fib.a"                "fib.b"                "flow.jok"             "flow.vat"            
[17] "foo"                  "full_form"            "Full_form"            "geocodes.world_ports"
[21] "html.world_ports"     "i"                    "ice.river"            "in_train"            
[25] "int_plot"             "j"                    "logic.mat"            "logic.vec"           
[29] "loop1.result"         "loop2.result"         "loopvec1"             "loopvec2"            
[33] "mnr_impute"           "mnr_tune"             "mydatafile"           "myfib"               
[37] "myfile"               "myitem"               "mylist"               "mylookup"            
[41] "mymat"                "mynum"                "mynumber"             "mystring"            
[45] "myval"                "myvec"                "new.myvec"            "newobect"            
[49] "num.mat1"             "num.mat2"             "num.vec1"             "num.vec2"            
[53] "opt.arg"              "ordfac.vec"           "prec"                 "predic"              
[57] "ptype"                "quux"                 "qux"                  "result"              
[61] "row.totals"           "row.totals2"          "scat"                 "scat_orig"           
[65] "small_form"           "small_tr_dat"         "somelist"             "temp"                
[69] "test_data"            "test_data3"           "train_data"           "wls"                 
[73] "x"                    "y"                   
myfib()
1 ,  1 , 2 , 3 , 5 , 8 , 13 , 21 , 34 , 55 , 89 , 144 , 233 , break now...

Let’s add a threshold of when to stop the fibonacci sequence

# fibonacci sequence
myfib<-function(threshold){
  fib.a<-1
  fib.b<-1
  cat(fib.a,", ",fib.b,", ",sep=" ")
  repeat{
    temp <-fib.a+fib.b
    fib.a<-fib.b
    fib.b<-temp
    cat(fib.b,", ",sep=" ")
    if(fib.b>threshold){
      cat("break now...")
      break
    }
  }
}
# check the myfib is now part of the workspace
ls()
 [1] "a"                    "b"                    "bar"                  "baz"                 
 [5] "char.mat"             "char.vec"             "counter"              "ctrl"                
 [9] "df.world_ports"       "dia.url"              "diamonds"             "fac.vec"             
[13] "fib.a"                "fib.b"                "flow.jok"             "flow.vat"            
[17] "foo"                  "full_form"            "Full_form"            "geocodes.world_ports"
[21] "html.world_ports"     "i"                    "ice.river"            "in_train"            
[25] "int_plot"             "j"                    "logic.mat"            "logic.vec"           
[29] "loop1.result"         "loop2.result"         "loopvec1"             "loopvec2"            
[33] "mnr_impute"           "mnr_tune"             "mydatafile"           "myfib"               
[37] "myfile"               "myitem"               "mylist"               "mylookup"            
[41] "mymat"                "mynum"                "mynumber"             "mystring"            
[45] "myval"                "myvec"                "new.myvec"            "newobect"            
[49] "num.mat1"             "num.mat2"             "num.vec1"             "num.vec2"            
[53] "opt.arg"              "ordfac.vec"           "prec"                 "predic"              
[57] "ptype"                "quux"                 "qux"                  "result"              
[61] "row.totals"           "row.totals2"          "scat"                 "scat_orig"           
[65] "small_form"           "small_tr_dat"         "somelist"             "temp"                
[69] "test_data"            "test_data3"           "train_data"           "wls"                 
[73] "x"                    "y"                   

Now run myfib with an argument inside:

myfib(2250)
1 ,  1 , 2 , 3 , 5 , 8 , 13 , 21 , 34 , 55 , 89 , 144 , 233 , 377 , 610 , 987 , 1597 , 2584 , break now...

You will note that the sequence now stops once the numbered sequence reached the threshold value.

Now use [return] to return the value of a function

myfib3<-function(threshold){
  fibseq<-c(1,1)
  counter<-2
  repeat{
    fibseq<-c(fibseq,fibseq[counter-1]+fibseq[counter])
    # increment counter
    counter <- counter +1
    # test for break condition
    if(fibseq[counter]>threshold){
      cat("break now...")
      break
    }
  }
  return(fibseq)
}
# now call the function
myfib3(500)
break now... [1]   1   1   2   3   5   8  13  21  34  55  89 144 233 377 610

YOu can assign the returnobject to a variable, suc a sfoo and foo is now just another R object in the global environment that you can manipulate.

11.1.2 Returning Results

If there is no return statement inside a function, it will end when the last line in the body code has been run. At this point, it will return the most recently assigned or created object in the function.

If nothing is created, the function returns NULL.

dummy1<-function(){
  aa <-2.5
  bb<-"string me along"
  cc<-"strem 'em up"
  dd<-4:8
}
dummy2<-function(){
  aa <-2.5
  bb<-"string me along"
  cc<-"strem 'em up"
  dd<-4:8
  return(dd)
}
# assign dummy1 output to foo
foo<-dummy1()
# assign dummy2 output to bar
bar<-dummy2()
# print out foo and bar
foo
[1] 4 5 6 7 8
bar
[1] 4 5 6 7 8

Notice that both bar and foo have the same contents…which is dd, which happens to be also the LAST object created by dummy1.

11.2 Arguments

Learn how R evaluates arguments. It takes a hammer and pounds the weakest one. You see how to write functions that hav default argument values. You learn how to make functions handle missing argument values, and how to pass extra arguments into an internal function all with ellipsis.

11.2.1 Lazy Evaluation

Lazy evaluation means that arguments are only evaluated when needed This is a sample function to search for objects in a supplied matrix. If no matrices are in the suplied list or if no appropriate matrices are present, the function should return a string.

# x is the matrix
# mat is the post multipling matrix
# str1 str2 is the string to return if no suitable mmembers
multiples1 <-function(x,mat,str1,str2)
  {
    # check if a matrix has been supplied 
    matrix.flags <-sapply(x,FUN=is.matrix)
      if(!any(matrix.flags))
        {
        return(str1)
        }
    indexes <-which(matrix.flags)
    counter <-0
    result <-list()
    for(i in indexes)
      {
      temp <-x[[i]]
        {
        if(ncol(temp)==nrow(mat))
          {
          counter<-counter+1
          result[[counter]]<-temp%*%mat
          }
        }
      if(counter==0){
      # matrix has no members
      return(str2)
      }else{
          # valid - so return the result.
          return(result)
      }
    }
}

Now let us test the function

# setup the lists
foo<-list(matrix(1:4,2,2),"not a matrix","definitely not a matrix",matrix(1:8,2,4),matrix(1:8,4,2))
bar <-list(1:4,"not a matrix",c(F,T,T,T),"??")
baz<-list(1:4,"not a matrix",c(F,T,T,T),"??",matrix(1:8,2,4))
foo
[[1]]
     [,1] [,2]
[1,]    1    3
[2,]    2    4

[[2]]
[1] "not a matrix"

[[3]]
[1] "definitely not a matrix"

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

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

[[2]]
[1] "not a matrix"

[[3]]
[1] FALSE  TRUE  TRUE  TRUE

[[4]]
[1] "??"
baz
[[1]]
[1] 1 2 3 4

[[2]]
[1] "not a matrix"

[[3]]
[1] FALSE  TRUE  TRUE  TRUE

[[4]]
[1] "??"

[[5]]
     [,1] [,2] [,3] [,4]
[1,]    1    3    5    7
[2,]    2    4    6    8
# now try out the function multiples1
multiples1(x=foo,mat=diag(2),str1="no matrices in 'x'",str2="matrices in 'x' but none of appropriate dimensions given 'mat'")
[[1]]
     [,1] [,2]
[1,]    1    3
[2,]    2    4

NOte: i am still confused. Why only one matrix for foo? As to the author’s point of lazy evaluation, notice that even if we did not specify str1 and str2, since it is not needed when x=foo, there will be no error message.

multiples1(x=foo,mat=diag(2))
[[1]]
     [,1] [,2]
[1,]    1    3
[2,]    2    4

However, if we set x=bar, since there is no matrix, R will need str1 and str2, now, there will be an error message

multiples1(x=bar,mat=diag(2))
Error in multiples1(x = bar, mat = diag(2)) : 
  argument "str1" is missing, with no default

11.2.2 Setting Defaults

Defaults are default values in arguments so even if you forget to specify them, a value will be assigned. Here is a re-write of the code to take in default values:

# x is the matrix
# mat is the post multipling matrix
# str1 str2 is the string to return if no suitable mmembers
# now we supply default values to the arguments
multiples2 <-function(x=baz,mat=diag(2),str1="no matrices in 'x'",str2="matrices in 'x' but none of appropriate dimensions given 'mat'")
  {
    # check if a matrix has been supplied 
    matrix.flags <-sapply(x,FUN=is.matrix)
      if(!any(matrix.flags))
        {
        return(str1)
        }
    indexes <-which(matrix.flags)
    counter <- 0
    result <-list()
    for(i in indexes)
      {
      temp <-x[[i]]
        {
        if(ncol(temp)==nrow(mat))
          {
          counter<-counter+1
          result[[counter]]<-temp%*%mat
          }
        }
      if(counter==0){
      # matrix has no members
      return(str2)
      }else{
          # valid - so return the result.
          return(result)
      }
    }
}
# now test it
multiples2()
[1] "matrices in 'x' but none of appropriate dimensions given 'mat'"
multiples2(x=foo)
[[1]]
     [,1] [,2]
[1,]    1    3
[2,]    2    4
multiples2(str2="fck off")
[1] "fck off"

11.2.3 Checking for Missing Arguments

The [missing] function checks the arguments of a function to see if all required arguments have been supplied. It takes an argument tag and returns a single logical value of TRUE if the specified argument isn’t found.

# x is the matrix
# mat is the post multipling matrix
# str1 str2 is the string to return if no suitable mmembers
# now we supply default values to the arguments
multiples3 <-function(x,mat,str1,str2){
    # check if a matrix has been supplied 
    matrix.flags <-sapply(x,FUN=is.matrix)
      if(!any(matrix.flags))
        # this is where we check for missing values using the missing function
        if(missing(str1)){
          return("str1 was missing so we used this instead")
        } else{
        return(str1)
        }
    indexes <-which(matrix.flags)
    counter <- 0
    result <-list()
    for(i in indexes)
      {
      temp <-x[[i]]
        {
        if(ncol(temp)==nrow(mat))
          {
          counter<-counter+1
          result[[counter]]<-temp%*%mat
          }
        }
      if(counter==0){
      # matrix has no members
        # check if str2 is missing
        if(missing(str2)){
          return("str2 was missing so we used this")
        } else {
              return(str2)
      }
      }else{
          # valid - so return the result.
          return(result)
      }
    }
    }
    
# now test it
multiples3(x=bar,diag(2))
[1] "str1 was missing so we used this instead"
multiples3(x=foo,diag(2))
[[1]]
     [,1] [,2]
[1,]    1    3
[2,]    2    4
multiples3(x=baz,diag(2))
[1] "str2 was missing so we used this"

11.2.4 Dealing with Ellipsis

Ellipsis allows you to pass in extra arguments without having to first define them in the argument list.

myfibplot<-function(threshold,plotit=TRUE,...){
  fibseq<-c(1,1)
  counter<-2
  repeat{
    fibseq<-c(fibseq,fibseq[counter-1]+fibseq[counter])
    # increment counter
    counter <- counter +1
    # test for break condition
    if(fibseq[counter]>threshold){
       break
    }
  }
if(plotit){
  plot(1:length(fibseq),fibseq,...)
} else {
  return(fibseq)
}
}
# now call the function
myfibplot(1500)

Now here is where the ellipsis come in We can pass additional parameters to the plot command

myfibplot(1500,type="b",pch=4,lty=2,main="Terms of Fibonacci Sequence",ylab="Fibonacci number", xlab="Term(n)")

You might want to unpack the arguments passed to it via the x<- list(…)

11.3 Specialized Functions

11.3.1 Helper Function

A helper funtion is a general term used to describe functions written and used specifically to facilitate the computations carried out by another function. They can be defined internally or externally.

A sample of externally defined helper function here:

multiples_helper_ext<- function(x,matrix.flags,mat){
  indexes <- which(matrix.flags)
  counter<-0
  result <- list()
  for(i in indexes){
    temp <-x[[i]]
    if(ncol(temp)==nrow(mat)){
      counter<-counter+1
      result[[counter]] <-temp%*%mat
      
    }
  }
  return(list(result,counter))
}
multiples4<-function(x,mat,str1="no valid matrix", str2="no valid member"){
  matrix.flags<-sapply(x,FUN=is.matrix)
  if(!any(matrix.flags)){
    return(str1)
  }
  
  helper.call <- multiples_helper_ext(x,matrix.flags, mat)
  result <-helper.call[[1]]
  counter <-helper.call[[2]]
  
  if(counter==0){
    return(str2)
    
  } else {
    return(result)
    
  }
}
# now we call the function
multiples4(x=foo,mat=diag(2))
[[1]]
     [,1] [,2]
[1,]    1    3
[2,]    2    4

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

For internally defined helper functions, they are defined within the lexical environment of the function that calls it.

multiples5<-function(x,mat,str1="no valid matrix", str2="no valid member"){
  matrix.flags<-sapply(x,FUN=is.matrix)
  if(!any(matrix.flags)){
    return(str1)
  }
  
  multiples_helper_int<- function(x,matrix.flags,mat){
  indexes <- which(matrix.flags)
  counter<-0
  result <- list()
  for(i in indexes){
    temp <-x[[i]]
    if(ncol(temp)==nrow(mat)){
      counter<-counter+1
      result[[counter]] <-temp%*%mat
      
    }
  }
  return(list(result,counter))
  }
  
  
  helper.call <- multiples_helper_int(x,matrix.flags, mat)
  result <-helper.call[[1]]
  counter <-helper.call[[2]]
  
  if(counter==0){
    return(str2)
    
  } else {
    return(result)
    
  }
}
# now we call the function
multiples5(x=foo,mat=diag(2))
[[1]]
     [,1] [,2]
[1,]    1    3
[2,]    2    4

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

11.3.2 Disposal Functions

Disposable (anonymous) functions allow a simple one line task that you define for use in a single instance without explicitly creating a new object in your global environment.

foo <-matrix(c(2,3,3,4,2,4,7,3,3,6,7,2),3,4)
foo
     [,1] [,2] [,3] [,4]
[1,]    2    4    7    6
[2,]    3    2    3    7
[3,]    3    4    3    2
# disposable function using apply
apply(foo,MARGIN=2,FUN=function(x){sort(rep(x,2))})
     [,1] [,2] [,3] [,4]
[1,]    2    2    3    2
[2,]    2    2    3    2
[3,]    3    4    3    6
[4,]    3    4    3    6
[5,]    3    4    7    7
[6,]    3    4    7    7

11.3.3 Recursive Functions

Recursive functions call themselves.

myfibrec <- function(n){
  if(n==1||n==2){
    return(1)
    
  }else {
    return(myfibrec(n-1)+myfibrec(n-2))
  }
}
# now call it
myfibrec(15)
[1] 610
LS0tDQp0aXRsZTogIkNoYXB0ZXIgMTEgV3JpdGluZyBGdW5jdGlvbnMiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQo8aDE+IENoYXB0ZXIgMTEgV3JpdGluZyBmdW5jdGlvbnMgPi9oMT4NCg0KPGgyPiAxMS4xIFRoZSBbZnVuY3Rpb25dIGNvbW1hbmQgPC9oMj4NCkZ1bmN0aW9ucyBhbGxvdyB5b3VyIGNvZGUgdG8gYmUgcmV1c2VkIHdpdGhvdXQgaGF2aW5nIHRvIGNvcHkgYW5kIHBhc3RlLg0KSXQgYWxzbyBhbGxvd3Mgb3RoZXIgdXNlcnMgdG8gdXNlIHlvdXIgZnVuY3Rpb25zIHRvIGNhcnJ5IG91dCB0aGUgc2FtZSBjb21wdXRhdGlvbnMgb24gdGhlaXIgb3duIGRhdGEgb3Igb2JqZWN0cy4NCg0KTGVhcm4gaG93IHRvIGRlZmluZSBhbmQgdXNlIGFyZ3VtZW50cywgaG93IHRvIHJldHVybiBvdXRwdXQgZnJvbSBhIGZ1bmN0aW9uIGFuZCBob3cgdG8gc3BlY2lhbGl6ZSB5b3VyIGZ1bmN0aW9ucyBpbiBvdGhlciB3YXlzLg0KDQoNCjxoMz4gMTEuMS4xIEZ1bmN0aW9uIENyZWF0aW9uIDwvaDM+DQpGdW5jdGlvbnMgYXJlIGNyZWF0ZWQgd2l0aCB0aGUgW2Z1bmN0aW9uKCldIGNvbW1hbmQuIA0KVGhlIHN0YW5kYXJkIGZvcm1hdDoNCmZ1bmN0aW9ubmFtZSA8LSBmdW5jdGlvbihhcnQxLCBhcmcyLCBhcmczLC4uLikNCnsNCmRvIGFueSBjb2RlIGluIGhlcmUgd2hlbiB0aGUgZnVuY3Rpb24gaXMgY2FsbGVkDQp9DQoNCmBgYHtyfQ0KIyBmaWJvbmFjY2kgc2VxdWVuY2UNCm15ZmliPC1mdW5jdGlvbigpew0KICBmaWIuYTwtMQ0KICBmaWIuYjwtMQ0KICBjYXQoZmliLmEsIiwgIixmaWIuYiwiLCAiLHNlcD0iICIpDQogIHJlcGVhdHsNCiAgICB0ZW1wIDwtZmliLmErZmliLmINCiAgICBmaWIuYTwtZmliLmINCiAgICBmaWIuYjwtdGVtcA0KICAgIGNhdChmaWIuYiwiLCAiLHNlcD0iICIpDQogICAgaWYoZmliLmI+MTUwKXsNCiAgICAgIGNhdCgiYnJlYWsgbm93Li4uIikNCiAgICAgIGJyZWFrDQogICAgfQ0KICB9DQp9DQojIGNoZWNrIHRoZSBteWZpYiBpcyBub3cgcGFydCBvZiB0aGUgd29ya3NwYWNlDQpscygpDQpgYGANCmBgYHtyfQ0KIyBjYWxsIHRoZSBteWZpYiBmdW5jdGlvbg0KbXlmaWIoKQ0KDQpgYGANCg0KTGV0J3MgYWRkIGEgdGhyZXNob2xkIG9mIHdoZW4gdG8gc3RvcCB0aGUgZmlib25hY2NpIHNlcXVlbmNlDQpgYGB7cn0NCiMgZmlib25hY2NpIHNlcXVlbmNlDQpteWZpYjwtZnVuY3Rpb24odGhyZXNob2xkKXsNCiAgZmliLmE8LTENCiAgZmliLmI8LTENCiAgY2F0KGZpYi5hLCIsICIsZmliLmIsIiwgIixzZXA9IiAiKQ0KICByZXBlYXR7DQogICAgdGVtcCA8LWZpYi5hK2ZpYi5iDQogICAgZmliLmE8LWZpYi5iDQogICAgZmliLmI8LXRlbXANCiAgICBjYXQoZmliLmIsIiwgIixzZXA9IiAiKQ0KICAgIGlmKGZpYi5iPnRocmVzaG9sZCl7DQogICAgICBjYXQoImJyZWFrIG5vdy4uLiIpDQogICAgICBicmVhaw0KICAgIH0NCiAgfQ0KfQ0KIyBjaGVjayB0aGUgbXlmaWIgaXMgbm93IHBhcnQgb2YgdGhlIHdvcmtzcGFjZQ0KbHMoKQ0KDQpgYGANCg0KTm93IHJ1biBteWZpYiB3aXRoIGFuIGFyZ3VtZW50IGluc2lkZToNCg0KYGBge3J9DQoNCm15ZmliKDIyNTApDQpgYGANCllvdSB3aWxsIG5vdGUgdGhhdCB0aGUgc2VxdWVuY2Ugbm93IHN0b3BzIG9uY2UgdGhlIG51bWJlcmVkIHNlcXVlbmNlIHJlYWNoZWQgdGhlIHRocmVzaG9sZCB2YWx1ZS4NCg0KTm93IHVzZSBbcmV0dXJuXSB0byByZXR1cm4gdGhlIHZhbHVlIG9mIGEgZnVuY3Rpb24NCg0KYGBge3J9DQpteWZpYjM8LWZ1bmN0aW9uKHRocmVzaG9sZCl7DQogIGZpYnNlcTwtYygxLDEpDQogIGNvdW50ZXI8LTINCiAgcmVwZWF0ew0KICAgIGZpYnNlcTwtYyhmaWJzZXEsZmlic2VxW2NvdW50ZXItMV0rZmlic2VxW2NvdW50ZXJdKQ0KICAgICMgaW5jcmVtZW50IGNvdW50ZXINCiAgICBjb3VudGVyIDwtIGNvdW50ZXIgKzENCiAgICAjIHRlc3QgZm9yIGJyZWFrIGNvbmRpdGlvbg0KICAgIGlmKGZpYnNlcVtjb3VudGVyXT50aHJlc2hvbGQpew0KICAgICAgY2F0KCJicmVhayBub3cuLi4iKQ0KICAgICAgYnJlYWsNCiAgICB9DQogIH0NCiAgcmV0dXJuKGZpYnNlcSkNCn0NCiMgbm93IGNhbGwgdGhlIGZ1bmN0aW9uDQoNCm15ZmliMyg1MDApDQoNCmBgYA0KWU91IGNhbiBhc3NpZ24gdGhlIHJldHVybm9iamVjdCB0byBhIHZhcmlhYmxlLCBzdWMgYSBzZm9vIGFuZCBmb28gaXMgbm93IGp1c3QgYW5vdGhlciBSIG9iamVjdCBpbiB0aGUgZ2xvYmFsIGVudmlyb25tZW50IHRoYXQgeW91IGNhbiBtYW5pcHVsYXRlLg0KDQoNCjxoMz4gMTEuMS4yIFJldHVybmluZyBSZXN1bHRzIDwvaDM+DQpJZiB0aGVyZSBpcyBubyByZXR1cm4gc3RhdGVtZW50IGluc2lkZSBhIGZ1bmN0aW9uLCBpdCB3aWxsIGVuZCB3aGVuIHRoZSBsYXN0IGxpbmUgaW4gdGhlIGJvZHkgY29kZSBoYXMgYmVlbiBydW4uIEF0IHRoaXMgcG9pbnQsIGl0IHdpbGwgcmV0dXJuIHRoZSBtb3N0IHJlY2VudGx5IGFzc2lnbmVkIG9yIGNyZWF0ZWQgb2JqZWN0IGluIHRoZSBmdW5jdGlvbi4NCg0KSWYgbm90aGluZyBpcyBjcmVhdGVkLCB0aGUgZnVuY3Rpb24gcmV0dXJucyBOVUxMLiANCmBgYHtyfQ0KZHVtbXkxPC1mdW5jdGlvbigpew0KICBhYSA8LTIuNQ0KICBiYjwtInN0cmluZyBtZSBhbG9uZyINCiAgY2M8LSJzdHJlbSAnZW0gdXAiDQogIGRkPC00OjgNCn0NCmR1bW15MjwtZnVuY3Rpb24oKXsNCiAgYWEgPC0yLjUNCiAgYmI8LSJzdHJpbmcgbWUgYWxvbmciDQogIGNjPC0ic3RyZW0gJ2VtIHVwIg0KICBkZDwtNDo4DQogIHJldHVybihkZCkNCn0NCg0KIyBhc3NpZ24gZHVtbXkxIG91dHB1dCB0byBmb28NCmZvbzwtZHVtbXkxKCkNCiMgYXNzaWduIGR1bW15MiBvdXRwdXQgdG8gYmFyDQpiYXI8LWR1bW15MigpDQojIHByaW50IG91dCBmb28gYW5kIGJhcg0KZm9vDQpiYXINCg0KYGBgDQpOb3RpY2UgdGhhdCBib3RoIGJhciBhbmQgZm9vIGhhdmUgdGhlIHNhbWUgY29udGVudHMuLi53aGljaCBpcyBkZCwgd2hpY2ggaGFwcGVucyB0byBiZSBhbHNvIHRoZSBMQVNUIG9iamVjdCBjcmVhdGVkIGJ5IGR1bW15MS4NCg0KDQo8aDI+IDExLjIgQXJndW1lbnRzIDwvaDI+IA0KTGVhcm4gaG93IFIgZXZhbHVhdGVzIGFyZ3VtZW50cy4NCkl0IHRha2VzIGEgaGFtbWVyIGFuZCBwb3VuZHMgdGhlIHdlYWtlc3Qgb25lLg0KWW91IHNlZSBob3cgdG8gd3JpdGUgZnVuY3Rpb25zIHRoYXQgaGF2IGRlZmF1bHQgYXJndW1lbnQgdmFsdWVzLg0KWW91IGxlYXJuIGhvdyB0byBtYWtlIGZ1bmN0aW9ucyBoYW5kbGUgbWlzc2luZyBhcmd1bWVudCB2YWx1ZXMsIGFuZCBob3cgdG8gcGFzcyBleHRyYSBhcmd1bWVudHMgaW50byBhbiBpbnRlcm5hbCBmdW5jdGlvbiBhbGwgd2l0aCBlbGxpcHNpcy4NCg0KDQo8aDM+IDExLjIuMSBMYXp5IEV2YWx1YXRpb24gPC9oMz4NCkxhenkgZXZhbHVhdGlvbiBtZWFucyB0aGF0IGFyZ3VtZW50cyBhcmUgb25seSBldmFsdWF0ZWQgd2hlbiBuZWVkZWQgDQpUaGlzIGlzIGEgc2FtcGxlIGZ1bmN0aW9uIHRvIHNlYXJjaCBmb3Igb2JqZWN0cyBpbiBhIHN1cHBsaWVkIG1hdHJpeC4gDQpJZiBubyBtYXRyaWNlcyBhcmUgaW4gdGhlIHN1cGxpZWQgbGlzdCBvciBpZiBubyBhcHByb3ByaWF0ZSBtYXRyaWNlcyBhcmUgcHJlc2VudCwgdGhlIGZ1bmN0aW9uIHNob3VsZCByZXR1cm4gYSBzdHJpbmcuDQoNCmBgYHtyfQ0KIyB4IGlzIHRoZSBtYXRyaXgNCiMgbWF0IGlzIHRoZSBwb3N0IG11bHRpcGxpbmcgbWF0cml4DQojIHN0cjEgc3RyMiBpcyB0aGUgc3RyaW5nIHRvIHJldHVybiBpZiBubyBzdWl0YWJsZSBtbWVtYmVycw0KDQptdWx0aXBsZXMxIDwtZnVuY3Rpb24oeCxtYXQsc3RyMSxzdHIyKQ0KICB7DQogICAgIyBjaGVjayBpZiBhIG1hdHJpeCBoYXMgYmVlbiBzdXBwbGllZCANCiAgICBtYXRyaXguZmxhZ3MgPC1zYXBwbHkoeCxGVU49aXMubWF0cml4KQ0KICAgICAgaWYoIWFueShtYXRyaXguZmxhZ3MpKQ0KICAgICAgICB7DQogICAgICAgIHJldHVybihzdHIxKQ0KICAgICAgICB9DQogICAgaW5kZXhlcyA8LXdoaWNoKG1hdHJpeC5mbGFncykNCiAgICBjb3VudGVyIDwtIDANCiAgICByZXN1bHQgPC1saXN0KCkNCiAgICBmb3IoaSBpbiBpbmRleGVzKQ0KICAgICAgew0KICAgICAgdGVtcCA8LXhbW2ldXQ0KICAgICAgICB7DQogICAgICAgIGlmKG5jb2wodGVtcCk9PW5yb3cobWF0KSkNCiAgICAgICAgICB7DQogICAgICAgICAgY291bnRlcjwtY291bnRlcisxDQogICAgICAgICAgcmVzdWx0W1tjb3VudGVyXV08LXRlbXAlKiVtYXQNCiAgICAgICAgICB9DQogICAgICAgIH0NCiAgICAgIGlmKGNvdW50ZXI9PTApew0KICAgICAgIyBtYXRyaXggaGFzIG5vIG1lbWJlcnMNCiAgICAgIHJldHVybihzdHIyKQ0KICAgICAgfWVsc2V7DQogICAgICAgICAgIyB2YWxpZCAtIHNvIHJldHVybiB0aGUgcmVzdWx0Lg0KICAgICAgICAgIHJldHVybihyZXN1bHQpDQogICAgICB9DQogICAgfQ0KfQ0KDQoNCmBgYA0KDQpOb3cgbGV0IHVzIHRlc3QgdGhlIGZ1bmN0aW9uDQoNCmBgYHtyfQ0KIyBzZXR1cCB0aGUgbGlzdHMNCmZvbzwtbGlzdChtYXRyaXgoMTo0LDIsMiksIm5vdCBhIG1hdHJpeCIsImRlZmluaXRlbHkgbm90IGEgbWF0cml4IixtYXRyaXgoMTo4LDIsNCksbWF0cml4KDE6OCw0LDIpKQ0KYmFyIDwtbGlzdCgxOjQsIm5vdCBhIG1hdHJpeCIsYyhGLFQsVCxUKSwiPz8iKQ0KYmF6PC1saXN0KDE6NCwibm90IGEgbWF0cml4IixjKEYsVCxULFQpLCI/PyIsbWF0cml4KDE6OCwyLDQpKQ0KZm9vDQpiYXINCmJheg0KDQojIG5vdyB0cnkgb3V0IHRoZSBmdW5jdGlvbiBtdWx0aXBsZXMxDQoNCm11bHRpcGxlczEoeD1mb28sbWF0PWRpYWcoMiksc3RyMT0ibm8gbWF0cmljZXMgaW4gJ3gnIixzdHIyPSJtYXRyaWNlcyBpbiAneCcgYnV0IG5vbmUgb2YgYXBwcm9wcmlhdGUgZGltZW5zaW9ucyBnaXZlbiAnbWF0JyIpDQoNCmBgYA0KTk90ZTogaSBhbSBzdGlsbCBjb25mdXNlZC4gV2h5IG9ubHkgb25lIG1hdHJpeCBmb3IgZm9vPw0KQXMgdG8gdGhlIGF1dGhvcidzIHBvaW50IG9mIGxhenkgZXZhbHVhdGlvbiwgbm90aWNlIHRoYXQgZXZlbiBpZiB3ZSBkaWQgbm90IHNwZWNpZnkgc3RyMSBhbmQgc3RyMiwgDQpzaW5jZSBpdCBpcyBub3QgbmVlZGVkIHdoZW4geD1mb28sIHRoZXJlIHdpbGwgYmUgbm8gZXJyb3IgbWVzc2FnZS4NCg0KYGBge3J9DQptdWx0aXBsZXMxKHg9Zm9vLG1hdD1kaWFnKDIpKQ0KYGBgDQpIb3dldmVyLCBpZiB3ZSBzZXQgeD1iYXIsIHNpbmNlIHRoZXJlIGlzIG5vIG1hdHJpeCwgUiB3aWxsIG5lZWQgc3RyMSBhbmQgc3RyMiwNCm5vdywgdGhlcmUgd2lsbCBiZSBhbiBlcnJvciBtZXNzYWdlDQoNCmBgYHtyfQ0KbXVsdGlwbGVzMSh4PWJhcixtYXQ9ZGlhZygyKSkNCmBgYA0KDQoNCjxoMz4gMTEuMi4yIFNldHRpbmcgRGVmYXVsdHMgPC9oMz4NCkRlZmF1bHRzIGFyZSBkZWZhdWx0IHZhbHVlcyBpbiBhcmd1bWVudHMgc28gZXZlbiBpZiB5b3UgZm9yZ2V0IHRvIHNwZWNpZnkgdGhlbSwgYSB2YWx1ZSB3aWxsIGJlIGFzc2lnbmVkLg0KSGVyZSBpcyBhIHJlLXdyaXRlIG9mIHRoZSBjb2RlIHRvIHRha2UgaW4gZGVmYXVsdCB2YWx1ZXM6DQoNCmBgYHtyfQ0KIyB4IGlzIHRoZSBtYXRyaXgNCiMgbWF0IGlzIHRoZSBwb3N0IG11bHRpcGxpbmcgbWF0cml4DQojIHN0cjEgc3RyMiBpcyB0aGUgc3RyaW5nIHRvIHJldHVybiBpZiBubyBzdWl0YWJsZSBtbWVtYmVycw0KIyBub3cgd2Ugc3VwcGx5IGRlZmF1bHQgdmFsdWVzIHRvIHRoZSBhcmd1bWVudHMNCg0KbXVsdGlwbGVzMiA8LWZ1bmN0aW9uKHg9YmF6LG1hdD1kaWFnKDIpLHN0cjE9Im5vIG1hdHJpY2VzIGluICd4JyIsc3RyMj0ibWF0cmljZXMgaW4gJ3gnIGJ1dCBub25lIG9mIGFwcHJvcHJpYXRlIGRpbWVuc2lvbnMgZ2l2ZW4gJ21hdCciKQ0KICB7DQogICAgIyBjaGVjayBpZiBhIG1hdHJpeCBoYXMgYmVlbiBzdXBwbGllZCANCiAgICBtYXRyaXguZmxhZ3MgPC1zYXBwbHkoeCxGVU49aXMubWF0cml4KQ0KICAgICAgaWYoIWFueShtYXRyaXguZmxhZ3MpKQ0KICAgICAgICB7DQogICAgICAgIHJldHVybihzdHIxKQ0KICAgICAgICB9DQogICAgaW5kZXhlcyA8LXdoaWNoKG1hdHJpeC5mbGFncykNCiAgICBjb3VudGVyIDwtIDANCiAgICByZXN1bHQgPC1saXN0KCkNCiAgICBmb3IoaSBpbiBpbmRleGVzKQ0KICAgICAgew0KICAgICAgdGVtcCA8LXhbW2ldXQ0KICAgICAgICB7DQogICAgICAgIGlmKG5jb2wodGVtcCk9PW5yb3cobWF0KSkNCiAgICAgICAgICB7DQogICAgICAgICAgY291bnRlcjwtY291bnRlcisxDQogICAgICAgICAgcmVzdWx0W1tjb3VudGVyXV08LXRlbXAlKiVtYXQNCiAgICAgICAgICB9DQogICAgICAgIH0NCiAgICAgIGlmKGNvdW50ZXI9PTApew0KICAgICAgIyBtYXRyaXggaGFzIG5vIG1lbWJlcnMNCiAgICAgIHJldHVybihzdHIyKQ0KICAgICAgfWVsc2V7DQogICAgICAgICAgIyB2YWxpZCAtIHNvIHJldHVybiB0aGUgcmVzdWx0Lg0KICAgICAgICAgIHJldHVybihyZXN1bHQpDQogICAgICB9DQogICAgfQ0KfQ0KDQojIG5vdyB0ZXN0IGl0DQptdWx0aXBsZXMyKCkNCm11bHRpcGxlczIoeD1mb28pDQptdWx0aXBsZXMyKHN0cjI9ImZjayBvZmYiKQ0KYGBgDQoNCjxoMz4gMTEuMi4zIENoZWNraW5nIGZvciBNaXNzaW5nIEFyZ3VtZW50cyA8L2gzPg0KVGhlIFttaXNzaW5nXSBmdW5jdGlvbiBjaGVja3MgdGhlIGFyZ3VtZW50cyBvZiBhIGZ1bmN0aW9uIHRvIHNlZSBpZiBhbGwgcmVxdWlyZWQgYXJndW1lbnRzIGhhdmUgYmVlbiBzdXBwbGllZC4NCkl0IHRha2VzIGFuIGFyZ3VtZW50IHRhZyBhbmQgcmV0dXJucyBhIHNpbmdsZSBsb2dpY2FsIHZhbHVlIG9mIFRSVUUgaWYgdGhlIHNwZWNpZmllZCBhcmd1bWVudCBpc24ndCBmb3VuZC4NCg0KYGBge3J9DQojIHggaXMgdGhlIG1hdHJpeA0KIyBtYXQgaXMgdGhlIHBvc3QgbXVsdGlwbGluZyBtYXRyaXgNCiMgc3RyMSBzdHIyIGlzIHRoZSBzdHJpbmcgdG8gcmV0dXJuIGlmIG5vIHN1aXRhYmxlIG1tZW1iZXJzDQojIG5vdyB3ZSBzdXBwbHkgZGVmYXVsdCB2YWx1ZXMgdG8gdGhlIGFyZ3VtZW50cw0KDQptdWx0aXBsZXMzIDwtZnVuY3Rpb24oeCxtYXQsc3RyMSxzdHIyKXsNCiAgICAjIGNoZWNrIGlmIGEgbWF0cml4IGhhcyBiZWVuIHN1cHBsaWVkIA0KICAgIG1hdHJpeC5mbGFncyA8LXNhcHBseSh4LEZVTj1pcy5tYXRyaXgpDQogICAgICBpZighYW55KG1hdHJpeC5mbGFncykpDQogICAgICAgICMgdGhpcyBpcyB3aGVyZSB3ZSBjaGVjayBmb3IgbWlzc2luZyB2YWx1ZXMgdXNpbmcgdGhlIG1pc3NpbmcgZnVuY3Rpb24NCiAgICAgICAgaWYobWlzc2luZyhzdHIxKSl7DQogICAgICAgICAgcmV0dXJuKCJzdHIxIHdhcyBtaXNzaW5nIHNvIHdlIHVzZWQgdGhpcyBpbnN0ZWFkIikNCiAgICAgICAgfSBlbHNlew0KICAgICAgICByZXR1cm4oc3RyMSkNCiAgICAgICAgfQ0KICAgIGluZGV4ZXMgPC13aGljaChtYXRyaXguZmxhZ3MpDQogICAgY291bnRlciA8LSAwDQogICAgcmVzdWx0IDwtbGlzdCgpDQogICAgZm9yKGkgaW4gaW5kZXhlcykNCiAgICAgIHsNCiAgICAgIHRlbXAgPC14W1tpXV0NCiAgICAgICAgew0KICAgICAgICBpZihuY29sKHRlbXApPT1ucm93KG1hdCkpDQogICAgICAgICAgew0KICAgICAgICAgIGNvdW50ZXI8LWNvdW50ZXIrMQ0KICAgICAgICAgIHJlc3VsdFtbY291bnRlcl1dPC10ZW1wJSolbWF0DQogICAgICAgICAgfQ0KICAgICAgICB9DQogICAgICBpZihjb3VudGVyPT0wKXsNCiAgICAgICMgbWF0cml4IGhhcyBubyBtZW1iZXJzDQogICAgICAgICMgY2hlY2sgaWYgc3RyMiBpcyBtaXNzaW5nDQogICAgICAgIGlmKG1pc3Npbmcoc3RyMikpew0KICAgICAgICAgIHJldHVybigic3RyMiB3YXMgbWlzc2luZyBzbyB3ZSB1c2VkIHRoaXMiKQ0KICAgICAgICB9IGVsc2Ugew0KICAgICAgICAgICAgICByZXR1cm4oc3RyMikNCiAgICAgIH0NCiAgICAgIH1lbHNlew0KICAgICAgICAgICMgdmFsaWQgLSBzbyByZXR1cm4gdGhlIHJlc3VsdC4NCiAgICAgICAgICByZXR1cm4ocmVzdWx0KQ0KICAgICAgfQ0KICAgIH0NCiAgICB9DQogICAgDQoNCiMgbm93IHRlc3QgaXQNCm11bHRpcGxlczMoeD1iYXIsZGlhZygyKSkNCm11bHRpcGxlczMoeD1mb28sZGlhZygyKSkNCm11bHRpcGxlczMoeD1iYXosZGlhZygyKSkNCmBgYA0KDQo8aDM+IDExLjIuNCBEZWFsaW5nIHdpdGggRWxsaXBzaXMgPC9oMz4NCkVsbGlwc2lzIGFsbG93cyB5b3UgdG8gcGFzcyBpbiBleHRyYSBhcmd1bWVudHMgd2l0aG91dCBoYXZpbmcgdG8gZmlyc3QgZGVmaW5lIHRoZW0gaW4gdGhlIGFyZ3VtZW50IGxpc3QuDQoNCmBgYHtyfQ0KbXlmaWJwbG90PC1mdW5jdGlvbih0aHJlc2hvbGQscGxvdGl0PVRSVUUsLi4uKXsNCiAgZmlic2VxPC1jKDEsMSkNCiAgY291bnRlcjwtMg0KICByZXBlYXR7DQogICAgZmlic2VxPC1jKGZpYnNlcSxmaWJzZXFbY291bnRlci0xXStmaWJzZXFbY291bnRlcl0pDQogICAgIyBpbmNyZW1lbnQgY291bnRlcg0KICAgIGNvdW50ZXIgPC0gY291bnRlciArMQ0KICAgICMgdGVzdCBmb3IgYnJlYWsgY29uZGl0aW9uDQogICAgaWYoZmlic2VxW2NvdW50ZXJdPnRocmVzaG9sZCl7DQogICAgICAgYnJlYWsNCiAgICB9DQogIH0NCg0KDQppZihwbG90aXQpew0KICBwbG90KDE6bGVuZ3RoKGZpYnNlcSksZmlic2VxLC4uLikNCn0gZWxzZSB7DQogIHJldHVybihmaWJzZXEpDQp9DQp9DQoNCg0KIyBub3cgY2FsbCB0aGUgZnVuY3Rpb24NCg0KbXlmaWJwbG90KDE1MDApDQoNCmBgYA0KDQpOb3cgaGVyZSBpcyB3aGVyZSB0aGUgZWxsaXBzaXMgY29tZSBpbiANCldlIGNhbiBwYXNzIGFkZGl0aW9uYWwgcGFyYW1ldGVycyB0byB0aGUgcGxvdCBjb21tYW5kDQoNCmBgYHtyfQ0KbXlmaWJwbG90KDE1MDAsdHlwZT0iYiIscGNoPTQsbHR5PTIsbWFpbj0iVGVybXMgb2YgRmlib25hY2NpIFNlcXVlbmNlIix5bGFiPSJGaWJvbmFjY2kgbnVtYmVyIiwgeGxhYj0iVGVybShuKSIpDQpgYGANCllvdSBtaWdodCB3YW50IHRvIHVucGFjayB0aGUgYXJndW1lbnRzIHBhc3NlZCB0byBpdCB2aWEgdGhlIA0KeDwtIGxpc3QoLi4uKQ0KDQo8aDI+IDExLjMgU3BlY2lhbGl6ZWQgRnVuY3Rpb25zIDwvaDI+DQo8aDM+IDExLjMuMSBIZWxwZXIgRnVuY3Rpb24gPC9oMz4NCkEgaGVscGVyIGZ1bnRpb24gaXMgYSBnZW5lcmFsIHRlcm0gdXNlZCB0byBkZXNjcmliZSBmdW5jdGlvbnMgd3JpdHRlbiBhbmQgdXNlZCBzcGVjaWZpY2FsbHkgdG8gZmFjaWxpdGF0ZSB0aGUgY29tcHV0YXRpb25zIGNhcnJpZWQgb3V0IGJ5IGFub3RoZXIgZnVuY3Rpb24uIFRoZXkgY2FuIGJlIGRlZmluZWQgaW50ZXJuYWxseSBvciBleHRlcm5hbGx5Lg0KDQpBIHNhbXBsZSBvZiBleHRlcm5hbGx5IGRlZmluZWQgaGVscGVyIGZ1bmN0aW9uIGhlcmU6DQoNCmBgYHtyfQ0KbXVsdGlwbGVzX2hlbHBlcl9leHQ8LSBmdW5jdGlvbih4LG1hdHJpeC5mbGFncyxtYXQpew0KICBpbmRleGVzIDwtIHdoaWNoKG1hdHJpeC5mbGFncykNCiAgY291bnRlcjwtMA0KICByZXN1bHQgPC0gbGlzdCgpDQogIGZvcihpIGluIGluZGV4ZXMpew0KICAgIHRlbXAgPC14W1tpXV0NCiAgICBpZihuY29sKHRlbXApPT1ucm93KG1hdCkpew0KICAgICAgY291bnRlcjwtY291bnRlcisxDQogICAgICByZXN1bHRbW2NvdW50ZXJdXSA8LXRlbXAlKiVtYXQNCiAgICAgIA0KICAgIH0NCiAgfQ0KICByZXR1cm4obGlzdChyZXN1bHQsY291bnRlcikpDQp9DQoNCm11bHRpcGxlczQ8LWZ1bmN0aW9uKHgsbWF0LHN0cjE9Im5vIHZhbGlkIG1hdHJpeCIsIHN0cjI9Im5vIHZhbGlkIG1lbWJlciIpew0KICBtYXRyaXguZmxhZ3M8LXNhcHBseSh4LEZVTj1pcy5tYXRyaXgpDQogIGlmKCFhbnkobWF0cml4LmZsYWdzKSl7DQogICAgcmV0dXJuKHN0cjEpDQogIH0NCiAgDQogIGhlbHBlci5jYWxsIDwtIG11bHRpcGxlc19oZWxwZXJfZXh0KHgsbWF0cml4LmZsYWdzLCBtYXQpDQogIHJlc3VsdCA8LWhlbHBlci5jYWxsW1sxXV0NCiAgY291bnRlciA8LWhlbHBlci5jYWxsW1syXV0NCiAgDQogIGlmKGNvdW50ZXI9PTApew0KICAgIHJldHVybihzdHIyKQ0KICAgIA0KICB9IGVsc2Ugew0KICAgIHJldHVybihyZXN1bHQpDQogICAgDQogIH0NCn0NCg0KIyBub3cgd2UgY2FsbCB0aGUgZnVuY3Rpb24NCm11bHRpcGxlczQoeD1mb28sbWF0PWRpYWcoMikpDQoNCmBgYA0KRm9yIGludGVybmFsbHkgZGVmaW5lZCBoZWxwZXIgZnVuY3Rpb25zLCB0aGV5IGFyZSBkZWZpbmVkIHdpdGhpbiB0aGUgbGV4aWNhbCBlbnZpcm9ubWVudCBvZiB0aGUgZnVuY3Rpb24gdGhhdCBjYWxscyBpdC4gDQoNCmBgYHtyfQ0KbXVsdGlwbGVzNTwtZnVuY3Rpb24oeCxtYXQsc3RyMT0ibm8gdmFsaWQgbWF0cml4Iiwgc3RyMj0ibm8gdmFsaWQgbWVtYmVyIil7DQogIG1hdHJpeC5mbGFnczwtc2FwcGx5KHgsRlVOPWlzLm1hdHJpeCkNCiAgaWYoIWFueShtYXRyaXguZmxhZ3MpKXsNCiAgICByZXR1cm4oc3RyMSkNCiAgfQ0KICANCiAgbXVsdGlwbGVzX2hlbHBlcl9pbnQ8LSBmdW5jdGlvbih4LG1hdHJpeC5mbGFncyxtYXQpew0KICBpbmRleGVzIDwtIHdoaWNoKG1hdHJpeC5mbGFncykNCiAgY291bnRlcjwtMA0KICByZXN1bHQgPC0gbGlzdCgpDQogIGZvcihpIGluIGluZGV4ZXMpew0KICAgIHRlbXAgPC14W1tpXV0NCiAgICBpZihuY29sKHRlbXApPT1ucm93KG1hdCkpew0KICAgICAgY291bnRlcjwtY291bnRlcisxDQogICAgICByZXN1bHRbW2NvdW50ZXJdXSA8LXRlbXAlKiVtYXQNCiAgICAgIA0KICAgIH0NCiAgfQ0KICByZXR1cm4obGlzdChyZXN1bHQsY291bnRlcikpDQogIH0NCiAgDQogIA0KICBoZWxwZXIuY2FsbCA8LSBtdWx0aXBsZXNfaGVscGVyX2ludCh4LG1hdHJpeC5mbGFncywgbWF0KQ0KICByZXN1bHQgPC1oZWxwZXIuY2FsbFtbMV1dDQogIGNvdW50ZXIgPC1oZWxwZXIuY2FsbFtbMl1dDQogIA0KICBpZihjb3VudGVyPT0wKXsNCiAgICByZXR1cm4oc3RyMikNCiAgICANCiAgfSBlbHNlIHsNCiAgICByZXR1cm4ocmVzdWx0KQ0KICAgIA0KICB9DQp9DQoNCiMgbm93IHdlIGNhbGwgdGhlIGZ1bmN0aW9uDQptdWx0aXBsZXM1KHg9Zm9vLG1hdD1kaWFnKDIpKQ0KDQpgYGANCg0KPGgzPiAxMS4zLjIgRGlzcG9zYWwgRnVuY3Rpb25zIDwvaDM+DQpEaXNwb3NhYmxlIChhbm9ueW1vdXMpIGZ1bmN0aW9ucyBhbGxvdyBhIHNpbXBsZSBvbmUgbGluZSB0YXNrIHRoYXQgeW91IGRlZmluZSBmb3IgdXNlIGluIGEgc2luZ2xlIGluc3RhbmNlIHdpdGhvdXQgZXhwbGljaXRseSBjcmVhdGluZyBhIG5ldyBvYmplY3QgaW4geW91ciBnbG9iYWwgZW52aXJvbm1lbnQuDQoNCmBgYHtyfQ0KZm9vIDwtbWF0cml4KGMoMiwzLDMsNCwyLDQsNywzLDMsNiw3LDIpLDMsNCkNCmZvbw0KDQoNCiMgZGlzcG9zYWJsZSBmdW5jdGlvbiBkZWZpbmVkIGRpcmVjdGx5IGluIHRoZSBjYWxsIHRvIGFwcGx5DQphcHBseShmb28sTUFSR0lOPTIsRlVOPWZ1bmN0aW9uKHgpe3NvcnQocmVwKHgsMikpfSkNCmBgYA0KDQo8aDM+IDExLjMuMyBSZWN1cnNpdmUgRnVuY3Rpb25zIDwvaDM+DQpSZWN1cnNpdmUgZnVuY3Rpb25zIGNhbGwgdGhlbXNlbHZlcy4NCg0KDQpgYGB7cn0NCm15ZmlicmVjIDwtIGZ1bmN0aW9uKG4pew0KICBpZihuPT0xfHxuPT0yKXsNCiAgICByZXR1cm4oMSkNCiAgICANCiAgfWVsc2Ugew0KICAgIHJldHVybihteWZpYnJlYyhuLTEpK215ZmlicmVjKG4tMikpDQogIH0NCn0NCg0KIyBub3cgY2FsbCBpdA0KbXlmaWJyZWMoMTUpDQpgYGANCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQo=