Chapter 9 Calling Functions

9.1 Scoping

Understand R’s scoping rules which determine how the language compartmentalizes object and retrieves them in a given session.

9.1.1 Environments

R Enforces rules with virtual environments. Think of each environment as a separate compatment where data tructures and functions are saved.

They allor R to distinguish between identical names that are associated with different scopes and therfore stored in different envirnments.

Global. Global envirnment is set aside for user-defined objects. Every object you’ve created or overwritten so far has resided in the global envirnoment of your current R session.

Use the ls() function to show th contents of the global environment

ls()
 [1] "bar"                  "baz"                  "char.mat"             "char.vec"            
 [5] "ctrl"                 "df.world_ports"       "dia.url"              "diamonds"            
 [9] "fac.vec"              "flow.jok"             "flow.vat"             "foo"                 
[13] "full_form"            "Full_form"            "geocodes.world_ports" "html.world_ports"    
[17] "ice.river"            "in_train"             "int_plot"             "logic.mat"           
[21] "logic.vec"            "mnr_impute"           "mnr_tune"             "mydatafile"          
[25] "newobect"             "num.mat1"             "num.mat2"             "num.vec1"            
[29] "num.vec2"             "opt.arg"              "ordfac.vec"           "prec"                
[33] "predic"               "ptype"                "quux"                 "qux"                 
[37] "scat"                 "scat_orig"            "small_form"           "small_tr_dat"        
[41] "somelist"             "temp"                 "test_data"            "test_data3"          
[45] "train_data"           "wls"                  "x"                    "y"                   

Package Environment and Namespaces Refers to the items made available by each package in R. In fact, the structure of R packages in terms of scoping is a bit more complicated. Each package environment actually represnets several environments that control different aspects of a search for a given object.

A package can have visible functions that a user is able to use and invisible functions that provide internal support to the visible functions.

ls("package:graphics")
 [1] "abline"          "arrows"          "assocplot"       "axis"            "Axis"            "axis.Date"      
 [7] "axis.POSIXct"    "axTicks"         "barplot"         "barplot.default" "box"             "boxplot"        
[13] "boxplot.default" "boxplot.matrix"  "bxp"             "cdplot"          "clip"            "close.screen"   
[19] "co.intervals"    "contour"         "contour.default" "coplot"          "curve"           "dotchart"       
[25] "erase.screen"    "filled.contour"  "fourfoldplot"    "frame"           "grconvertX"      "grconvertY"     
[31] "grid"            "hist"            "hist.default"    "identify"        "image"           "image.default"  
[37] "layout"          "layout.show"     "lcm"             "legend"          "lines"           "lines.default"  
[43] "locator"         "matlines"        "matplot"         "matpoints"       "mosaicplot"      "mtext"          
[49] "pairs"           "pairs.default"   "panel.smooth"    "par"             "persp"           "pie"            
[55] "plot"            "plot.default"    "plot.design"     "plot.function"   "plot.new"        "plot.window"    
[61] "plot.xy"         "points"          "points.default"  "polygon"         "polypath"        "rasterImage"    
[67] "rect"            "rug"             "screen"          "segments"        "smoothScatter"   "spineplot"      
[73] "split.screen"    "stars"           "stem"            "strheight"       "stripchart"      "strwidth"       
[79] "sunflowerplot"   "symbols"         "text"            "text.default"    "title"           "xinch"          
[85] "xspline"         "xyinch"          "yinch"          

Local Environments Local Environment is created each time a function is called in R. Sometimes called “Lexical environment”. This contains all the objects and variables created in and avisible to the function, including any arguments you’ve supplied to the function upon execution. This allows identical argument names to co-exist in a given workspace.

For example:

youthspeak<-matrix(data=c("OMG","LOL","WTF","YOLO"),nrow=2,ncol=2)
youthspeak
     [,1]  [,2]  
[1,] "OMG" "WTF" 
[2,] "LOL" "YOLO"

A local environment is created containing the data vector when this function is called. It begins by looking for data in this local environment. So R isn’t confused by other objects orr functions named data in other environments.

If a required item isn’t in the local environment, only then does R begin to widen its search for that item. Once the function has completed, this local environment is automatically removed.

9.1.2 Search Paths

The path followed by R to access data structures and fucntions from environments other than the immediate global environment.

search()
 [1] ".GlobalEnv"        "tools:rstudio"     "package:stats"     "package:graphics"  "package:grDevices"
 [6] "package:utils"     "package:datasets"  "package:methods"   "Autoloads"         "package:base"     

Order is read from left to right then down to the next line.

You can find out the environment by using the environment() function

environment(seq)
<environment: namespace:base>
environment(arrows)
<environment: namespace:graphics>

To find the parent or hierarchical order:

library("car")
search()
 [1] ".GlobalEnv"        "package:car"       "tools:rstudio"     "package:stats"     "package:graphics" 
 [6] "package:grDevices" "package:utils"     "package:datasets"  "package:methods"   "Autoloads"        
[11] "package:base"     

You can see that the parent of package:stats is package:graphics R will stop searching at the first match or when it has exhaused the entire search path and reached the empty environment.

9.1.3 Reserved and Protected Names

The following identifiers are reserved:
  • if else for while in function repeat break next TRUE FALSE Inf -Inf NA Nan NULL
  • If you try to assign a value to any of these reserved names, an error occurs

    if <-c(1,2,3)
    Error: unexpected assignment in "if <-"

    NOte: since R is case sensitive, nan, na, true, false will work.

    9.2 Argument Matching

    Argument matching conditions allow you to provide arguments to functions either with abbrieviated names or without names at all.

    9.2.1 Exact Matching

    Each argument tag is written out in full. This is the most exhaustive way to call a function. Exact matching is less prone to mis-specification of arguments compared to other matching sytles. It is also useful when a function has many possible arguments but you want to specify only a few. Drawbacks: It can be cumbersome for relatively simple operations. Exact matching requires the user to remember or lookup the full, case-sensitive tags.

    bar<-matrix(data=1:9,nrow=3,ncol=3, 
                dimnames=list(c("a","b","c"),c("d","e","f")))
    bar
      d e f
    a 1 4 7
    b 2 5 8
    c 3 6 9
    # you can switch around the arguments and it will still work bec of exact matching
    bar<-matrix(ncol=3, 
                dimnames=list(c("a","b","c"),
                              c("d","e","f")),
                              data=1:9,nrow=3)
    bar
      d e f
    a 1 4 7
    b 2 5 8
    c 3 6 9

    9.2.2 Partial Matching

    Partial Matching lets you use arguments with an abbreviated tag. For partial matching there is NO set number of letters you have to provide As long as each argument is still uniquely identifiable.

    This shortens your code and still lets you provide arguments in any order.

    bar<-matrix(dat=1:9,nr=3,nc=3, 
                di=list(c("a","b","c"),c("d","e","f")))
    bar
      d e f
    a 1 4 7
    b 2 5 8
    c 3 6 9

    9.2.3 Positional Matching

    Positional matching is when you supply arguments without tags and R interprets them based solely on their order.

    # first find out the exact order of the arguments
    args(matrix)
    function (data = NA, nrow = 1, ncol = 1, byrow = FALSE, dimnames = NULL) 
    NULL
    # then write out the function using the arguments in order
    bar <-matrix(1:9,3,3,F,list(c("a","b","c"),c("d","e","f")))
    bar
      d e f
    a 1 4 7
    b 2 5 8
    c 3 6 9

    Positional matching has shorter, cleaner code, particulary for routine tasks No need to remember specific argument tags.

    9.2.4 Mixed Matching

    You can mix and match any of the above matching styles in a single functaion call.

    bar<-matrix(1:9,3,3,dim=list(c("a","b","c"),c("d","e","f")))
    bar
      d e f
    a 1 4 7
    b 2 5 8
    c 3 6 9

    9.2.5 Use of Ellipsis

    Many functions exhibit variadic behavior. They can accept any number of arguments and its up to the user to decide how many to use.

    The flexibility is achieved in R by use of the special dot-dot-dot designations (…) also called the ellipsis There are 2 groups of functions that use ellipsis: 1. functions such as c, data.frame and list where the ellipsis always represent the main ingredient 2. functions such as plot where the ellipsis is meant as a supplementary or potential repository of optional arguments.

    # example of first group
    args(data.frame)
    function (..., row.names = NULL, check.rows = FALSE, check.names = TRUE, 
        fix.empty.names = TRUE, stringsAsFactors = default.stringsAsFactors()) 
    NULL
    # example of second group
    args(plot)
    function (x, y, ...) 
    NULL
    LS0tDQp0aXRsZTogIkNoYXB0ZXIgOSBDYWxsaW5nIEZ1bmN0aW9ucyINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCjxoMT4gQ2hhcHRlciA5IENhbGxpbmcgRnVuY3Rpb25zIDwvaDE+DQoNCjxoMj4gOS4xIFNjb3Bpbmc8L2gyPg0KVW5kZXJzdGFuZCBSJ3Mgc2NvcGluZyBydWxlcyB3aGljaCBkZXRlcm1pbmUgaG93IHRoZSBsYW5ndWFnZSBjb21wYXJ0bWVudGFsaXplcyBvYmplY3QgYW5kIHJldHJpZXZlcyB0aGVtIGluIGEgZ2l2ZW4gc2Vzc2lvbi4NCg0KDQo8aDM+IDkuMS4xIEVudmlyb25tZW50cyA8L2gzPg0KUiBFbmZvcmNlcyBydWxlcyB3aXRoIHZpcnR1YWwgZW52aXJvbm1lbnRzLiBUaGluayBvZiBlYWNoIGVudmlyb25tZW50IGFzIGEgc2VwYXJhdGUgY29tcGF0bWVudCB3aGVyZSBkYXRhIHRydWN0dXJlcyBhbmQgZnVuY3Rpb25zIGFyZSBzYXZlZC4NCg0KVGhleSBhbGxvciBSIHRvIGRpc3Rpbmd1aXNoIGJldHdlZW4gaWRlbnRpY2FsIG5hbWVzIHRoYXQgYXJlIGFzc29jaWF0ZWQgd2l0aCBkaWZmZXJlbnQgc2NvcGVzIGFuZCB0aGVyZm9yZSBzdG9yZWQgaW4gZGlmZmVyZW50IGVudmlybm1lbnRzLg0KDQo8Yj5HbG9iYWwuPC9iPg0KR2xvYmFsIGVudmlybm1lbnQgaXMgc2V0IGFzaWRlIGZvciB1c2VyLWRlZmluZWQgb2JqZWN0cy4gRXZlcnkgb2JqZWN0IHlvdSd2ZSBjcmVhdGVkIG9yIG92ZXJ3cml0dGVuIHNvIGZhciBoYXMgcmVzaWRlZCBpbiB0aGUgZ2xvYmFsIGVudmlybm9tZW50IG9mIHlvdXIgY3VycmVudCBSIHNlc3Npb24uDQoNClVzZSB0aGUgbHMoKSBmdW5jdGlvbiB0byBzaG93IHRoIGNvbnRlbnRzIG9mIHRoZSBnbG9iYWwgZW52aXJvbm1lbnQNCg0KYGBge3J9DQpscygpDQpgYGANCg0KPGI+IFBhY2thZ2UgRW52aXJvbm1lbnQgYW5kIE5hbWVzcGFjZXMgPC9iPg0KUmVmZXJzIHRvIHRoZSBpdGVtcyBtYWRlIGF2YWlsYWJsZSBieSBlYWNoIHBhY2thZ2UgaW4gUi4gSW4gZmFjdCwgdGhlIHN0cnVjdHVyZSBvZiBSIHBhY2thZ2VzIGluIHRlcm1zIG9mIHNjb3BpbmcgaXMgYSBiaXQgbW9yZSBjb21wbGljYXRlZC4gRWFjaCBwYWNrYWdlIGVudmlyb25tZW50IGFjdHVhbGx5IHJlcHJlc25ldHMgc2V2ZXJhbCBlbnZpcm9ubWVudHMgdGhhdCBjb250cm9sIGRpZmZlcmVudCBhc3BlY3RzIG9mIGEgc2VhcmNoIGZvciBhIGdpdmVuIG9iamVjdC4gDQoNCkEgcGFja2FnZSBjYW4gaGF2ZSB2aXNpYmxlIGZ1bmN0aW9ucyB0aGF0IGEgdXNlciBpcyBhYmxlIHRvIHVzZSBhbmQgaW52aXNpYmxlIGZ1bmN0aW9ucyB0aGF0IHByb3ZpZGUgaW50ZXJuYWwgc3VwcG9ydCB0byB0aGUgdmlzaWJsZSBmdW5jdGlvbnMuIA0KDQpgYGB7cn0NCmxzKCJwYWNrYWdlOmdyYXBoaWNzIikNCmBgYA0KDQoNCjxiPkxvY2FsIEVudmlyb25tZW50cyA8L2I+DQpMb2NhbCBFbnZpcm9ubWVudCBpcyBjcmVhdGVkIGVhY2ggdGltZSBhIGZ1bmN0aW9uIGlzIGNhbGxlZCBpbiBSLiBTb21ldGltZXMgY2FsbGVkICJMZXhpY2FsIGVudmlyb25tZW50Ii4gVGhpcyBjb250YWlucyBhbGwgdGhlIG9iamVjdHMgYW5kIHZhcmlhYmxlcyBjcmVhdGVkIGluIGFuZCBhdmlzaWJsZSB0byB0aGUgZnVuY3Rpb24sIGluY2x1ZGluZyBhbnkgYXJndW1lbnRzIHlvdSd2ZSBzdXBwbGllZCB0byB0aGUgZnVuY3Rpb24gdXBvbiBleGVjdXRpb24uICBUaGlzIGFsbG93cyBpZGVudGljYWwgYXJndW1lbnQgbmFtZXMgdG8gY28tZXhpc3QgaW4gYSBnaXZlbiB3b3Jrc3BhY2UuDQoNCkZvciBleGFtcGxlOg0KYGBge3J9DQp5b3V0aHNwZWFrPC1tYXRyaXgoZGF0YT1jKCJPTUciLCJMT0wiLCJXVEYiLCJZT0xPIiksbnJvdz0yLG5jb2w9MikNCnlvdXRoc3BlYWsNCg0KYGBgDQoNCkEgbG9jYWwgZW52aXJvbm1lbnQgaXMgY3JlYXRlZCBjb250YWluaW5nIHRoZSBkYXRhIHZlY3RvciB3aGVuIHRoaXMgZnVuY3Rpb24gaXMgY2FsbGVkLg0KSXQgYmVnaW5zIGJ5IGxvb2tpbmcgZm9yIGRhdGEgaW4gdGhpcyBsb2NhbCBlbnZpcm9ubWVudC4NClNvIFIgaXNuJ3QgY29uZnVzZWQgYnkgb3RoZXIgb2JqZWN0cyBvcnIgZnVuY3Rpb25zIG5hbWVkIGRhdGEgaW4gb3RoZXIgZW52aXJvbm1lbnRzLiANCg0KSWYgYSByZXF1aXJlZCBpdGVtIGlzbid0IGluIHRoZSBsb2NhbCBlbnZpcm9ubWVudCwgb25seSB0aGVuIGRvZXMgUiBiZWdpbiB0byB3aWRlbiBpdHMgc2VhcmNoIGZvciB0aGF0IGl0ZW0uIA0KT25jZSB0aGUgZnVuY3Rpb24gaGFzIGNvbXBsZXRlZCwgdGhpcyBsb2NhbCBlbnZpcm9ubWVudCBpcyBhdXRvbWF0aWNhbGx5IHJlbW92ZWQuIA0KDQoNCg0KPGgzPiA5LjEuMiBTZWFyY2ggUGF0aHMgPC9oMz4NClRoZSBwYXRoIGZvbGxvd2VkIGJ5IFIgdG8gYWNjZXNzIGRhdGEgc3RydWN0dXJlcyBhbmQgZnVjbnRpb25zIGZyb20gZW52aXJvbm1lbnRzIG90aGVyIHRoYW4gdGhlIGltbWVkaWF0ZSBnbG9iYWwgZW52aXJvbm1lbnQuDQoNCmBgYHtyfQ0Kc2VhcmNoKCkNCmBgYA0KDQpPcmRlciBpcyByZWFkIGZyb20gbGVmdCB0byByaWdodCB0aGVuIGRvd24gdG8gdGhlIG5leHQgbGluZS4NCg0KWW91IGNhbiBmaW5kIG91dCB0aGUgZW52aXJvbm1lbnQgYnkgdXNpbmcgdGhlIGVudmlyb25tZW50KCkgZnVuY3Rpb24NCg0KYGBge3J9DQplbnZpcm9ubWVudChzZXEpDQplbnZpcm9ubWVudChhcnJvd3MpDQpgYGANCg0KVG8gZmluZCB0aGUgcGFyZW50IG9yIGhpZXJhcmNoaWNhbCBvcmRlcjoNCg0KYGBge3J9DQpsaWJyYXJ5KCJjYXIiKQ0Kc2VhcmNoKCkNCg0KYGBgDQpZb3UgY2FuIHNlZSB0aGF0IHRoZSBwYXJlbnQgb2YgcGFja2FnZTpzdGF0cyBpcyBwYWNrYWdlOmdyYXBoaWNzDQpSIHdpbGwgc3RvcCBzZWFyY2hpbmcgYXQgdGhlIGZpcnN0IG1hdGNoIG9yIHdoZW4gaXQgaGFzIGV4aGF1c2VkIHRoZSBlbnRpcmUgc2VhcmNoIHBhdGggYW5kIHJlYWNoZWQgdGhlIGVtcHR5IGVudmlyb25tZW50LiANCg0KPGgzPiA5LjEuMyBSZXNlcnZlZCBhbmQgUHJvdGVjdGVkIE5hbWVzPC9oMz4NClRoZSBmb2xsb3dpbmcgaWRlbnRpZmllcnMgYXJlIHJlc2VydmVkOg0KPGxpPg0KaWYgDQplbHNlDQpmb3INCndoaWxlDQppbg0KZnVuY3Rpb24NCnJlcGVhdA0KYnJlYWsNCm5leHQNClRSVUUgDQpGQUxTRQ0KSW5mIA0KLUluZg0KTkENCk5hbg0KTlVMTA0KPC9saT4NCg0KSWYgeW91IHRyeSB0byBhc3NpZ24gYSB2YWx1ZSB0byBhbnkgb2YgdGhlc2UgcmVzZXJ2ZWQgbmFtZXMsIGFuIGVycm9yIG9jY3Vycw0KDQpgYGB7cn0NCmlmIDwtYygxLDIsMykNCk5hTiA8LTUNCg0KYGBgDQoNCk5PdGU6IHNpbmNlIFIgaXMgY2FzZSBzZW5zaXRpdmUsIG5hbiwgbmEsIHRydWUsIGZhbHNlIHdpbGwgd29yay4gDQoNCg0KPGgyPiA5LjIgQXJndW1lbnQgTWF0Y2hpbmc8L2gyPg0KQXJndW1lbnQgbWF0Y2hpbmcgY29uZGl0aW9ucyBhbGxvdyB5b3UgdG8gcHJvdmlkZSBhcmd1bWVudHMgdG8gZnVuY3Rpb25zIGVpdGhlciB3aXRoIGFiYnJpZXZpYXRlZCBuYW1lcyBvciB3aXRob3V0IG5hbWVzIGF0IGFsbC4gDQoNCjxoMz4gOS4yLjEgRXhhY3QgTWF0Y2hpbmc8L2gzPg0KRWFjaCBhcmd1bWVudCB0YWcgaXMgd3JpdHRlbiBvdXQgaW4gZnVsbC4gVGhpcyBpcyB0aGUgbW9zdCBleGhhdXN0aXZlIHdheSB0byBjYWxsIGEgZnVuY3Rpb24uDQpFeGFjdCBtYXRjaGluZyBpcyBsZXNzIHByb25lIHRvIG1pcy1zcGVjaWZpY2F0aW9uIG9mIGFyZ3VtZW50cyBjb21wYXJlZCB0byBvdGhlciBtYXRjaGluZyBzeXRsZXMuDQpJdCBpcyBhbHNvIHVzZWZ1bCB3aGVuIGEgZnVuY3Rpb24gaGFzIG1hbnkgcG9zc2libGUgYXJndW1lbnRzIGJ1dCB5b3Ugd2FudCB0byBzcGVjaWZ5IG9ubHkgYSBmZXcuIA0KRHJhd2JhY2tzOg0KSXQgY2FuIGJlIGN1bWJlcnNvbWUgZm9yIHJlbGF0aXZlbHkgc2ltcGxlIG9wZXJhdGlvbnMuDQpFeGFjdCBtYXRjaGluZyByZXF1aXJlcyB0aGUgdXNlciB0byByZW1lbWJlciBvciBsb29rdXAgdGhlIGZ1bGwsIGNhc2Utc2Vuc2l0aXZlIHRhZ3MuDQoNCmBgYHtyfQ0KYmFyPC1tYXRyaXgoZGF0YT0xOjksbnJvdz0zLG5jb2w9MywgDQogICAgICAgICAgICBkaW1uYW1lcz1saXN0KGMoImEiLCJiIiwiYyIpLGMoImQiLCJlIiwiZiIpKSkNCmJhcg0KDQpgYGANCg0KYGBge3J9DQojIHlvdSBjYW4gc3dpdGNoIGFyb3VuZCB0aGUgYXJndW1lbnRzIGFuZCBpdCB3aWxsIHN0aWxsIHdvcmsgYmVjIG9mIGV4YWN0IG1hdGNoaW5nDQoNCmJhcjwtbWF0cml4KG5jb2w9MywgDQogICAgICAgICAgICBkaW1uYW1lcz1saXN0KGMoImEiLCJiIiwiYyIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBjKCJkIiwiZSIsImYiKSksDQogICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGE9MTo5LG5yb3c9MykNCmJhcg0KDQpgYGANCg0KDQoNCjxoMz4gOS4yLjIgUGFydGlhbCBNYXRjaGluZzwvaDM+DQoNClBhcnRpYWwgTWF0Y2hpbmcgbGV0cyB5b3UgdXNlIGFyZ3VtZW50cyB3aXRoIGFuIGFiYnJldmlhdGVkIHRhZy4NCkZvciBwYXJ0aWFsIG1hdGNoaW5nIHRoZXJlIGlzIE5PIHNldCBudW1iZXIgb2YgbGV0dGVycyB5b3UgaGF2ZSB0byBwcm92aWRlDQpBcyBsb25nIGFzIGVhY2ggYXJndW1lbnQgaXMgc3RpbGwgdW5pcXVlbHkgaWRlbnRpZmlhYmxlLg0KDQpUaGlzIHNob3J0ZW5zIHlvdXIgY29kZSBhbmQgc3RpbGwgbGV0cyB5b3UgcHJvdmlkZSBhcmd1bWVudHMgaW4gYW55IG9yZGVyLg0KYGBge3J9DQpiYXI8LW1hdHJpeChkYXQ9MTo5LG5yPTMsbmM9MywgDQogICAgICAgICAgICBkaT1saXN0KGMoImEiLCJiIiwiYyIpLGMoImQiLCJlIiwiZiIpKSkNCmJhcg0KDQpgYGANCg0KDQo8aDM+IDkuMi4zIFBvc2l0aW9uYWwgTWF0Y2hpbmc8L2gzPg0KUG9zaXRpb25hbCBtYXRjaGluZyBpcyB3aGVuIHlvdSBzdXBwbHkgYXJndW1lbnRzIHdpdGhvdXQgdGFncyBhbmQgUiBpbnRlcnByZXRzIHRoZW0gYmFzZWQgIHNvbGVseSBvbiB0aGVpciBvcmRlci4NCg0KYGBge3J9DQojIGZpcnN0IGZpbmQgb3V0IHRoZSBleGFjdCBvcmRlciBvZiB0aGUgYXJndW1lbnRzDQphcmdzKG1hdHJpeCkNCiMgdGhlbiB3cml0ZSBvdXQgdGhlIGZ1bmN0aW9uIHVzaW5nIHRoZSBhcmd1bWVudHMgaW4gb3JkZXINCmJhciA8LW1hdHJpeCgxOjksMywzLEYsbGlzdChjKCJhIiwiYiIsImMiKSxjKCJkIiwiZSIsImYiKSkpDQpiYXINCmBgYA0KDQpQb3NpdGlvbmFsIG1hdGNoaW5nIGhhcyBzaG9ydGVyLCBjbGVhbmVyIGNvZGUsIHBhcnRpY3VsYXJ5IGZvciByb3V0aW5lIHRhc2tzDQpObyBuZWVkIHRvIHJlbWVtYmVyIHNwZWNpZmljIGFyZ3VtZW50IHRhZ3MuDQoNCjxoMz4gOS4yLjQgTWl4ZWQgTWF0Y2hpbmc8L2gzPg0KWW91IGNhbiBtaXggYW5kIG1hdGNoIGFueSBvZiB0aGUgYWJvdmUgbWF0Y2hpbmcgc3R5bGVzIGluIGEgc2luZ2xlIGZ1bmN0YWlvbiBjYWxsLiANCmBgYHtyfQ0KYmFyPC1tYXRyaXgoMTo5LDMsMyxkaW09bGlzdChjKCJhIiwiYiIsImMiKSxjKCJkIiwiZSIsImYiKSkpDQpiYXINCg0KYGBgDQoNCg0KPGgzPiA5LjIuNSBVc2Ugb2YgRWxsaXBzaXM8L2gzPg0KTWFueSBmdW5jdGlvbnMgZXhoaWJpdCB2YXJpYWRpYyBiZWhhdmlvci4gVGhleSBjYW4gYWNjZXB0IGFueSBudW1iZXIgb2YgYXJndW1lbnRzIGFuZCBpdHMgdXAgdG8gdGhlIHVzZXIgdG8gZGVjaWRlIGhvdyBtYW55IHRvIHVzZS4gDQoNClRoZSBmbGV4aWJpbGl0eSBpcyBhY2hpZXZlZCBpbiBSIGJ5IHVzZSBvZiB0aGUgc3BlY2lhbCBkb3QtZG90LWRvdCBkZXNpZ25hdGlvbnMgKC4uLikgIGFsc28gY2FsbGVkIHRoZSBlbGxpcHNpcw0KVGhlcmUgYXJlIDIgZ3JvdXBzIG9mIGZ1bmN0aW9ucyB0aGF0IHVzZSBlbGxpcHNpczoNCjEuIGZ1bmN0aW9ucyBzdWNoIGFzIGMsIGRhdGEuZnJhbWUgYW5kIGxpc3Qgd2hlcmUgdGhlIGVsbGlwc2lzIGFsd2F5cyByZXByZXNlbnQgdGhlIG1haW4gaW5ncmVkaWVudA0KMi4gZnVuY3Rpb25zIHN1Y2ggYXMgcGxvdCB3aGVyZSB0aGUgZWxsaXBzaXMgaXMgbWVhbnQgYXMgYSBzdXBwbGVtZW50YXJ5IG9yIHBvdGVudGlhbCByZXBvc2l0b3J5IG9mIG9wdGlvbmFsIGFyZ3VtZW50cy4NCg0KYGBge3J9DQojIGV4YW1wbGUgb2YgZmlyc3QgZ3JvdXANCmFyZ3MoZGF0YS5mcmFtZSkNCg0KDQpgYGANCmBgYHtyfQ0KIyBleGFtcGxlIG9mIHNlY29uZCBncm91cA0KYXJncyhwbG90KQ0KYGBgDQoNCg==