magrittr/0000755000176200001440000000000014174264634012116 5ustar liggesusersmagrittr/NAMESPACE0000644000176200001440000000163514174204546013336 0ustar liggesusers# Generated by roxygen2: do not edit by hand S3method("[",fseq) S3method("[[",fseq) S3method(print,fseq) export("%!>%") export("%$%") export("%<>%") export("%>%") export("%T>%") export("n'est pas") export(add) export(and) export(debug_fseq) export(debug_pipe) export(divide_by) export(divide_by_int) export(equals) export(extract) export(extract2) export(freduce) export(functions) export(inset) export(inset2) export(is_greater_than) export(is_in) export(is_less_than) export(is_weakly_greater_than) export(is_weakly_less_than) export(mod) export(multiply_by) export(multiply_by_matrix) export(not) export(or) export(pipe_eager_lexical) export(pipe_lazy_masking) export(pipe_nested) export(raise_to_power) export(set_attr) export(set_attributes) export(set_class) export(set_colnames) export(set_names) export(set_rownames) export(subtract) export(undebug_fseq) export(use_series) useDynLib(magrittr, .registration = TRUE) magrittr/LICENSE0000644000176200001440000000010413701613614013105 0ustar liggesusersYEAR: 2019 COPYRIGHT HOLDER: Stefan Milton Bache and Hadley Wickham magrittr/README.md0000644000176200001440000001060014174203262013360 0ustar liggesusers # magrittr [![CRAN status](https://www.r-pkg.org/badges/version/magrittr)](https://cran.r-project.org/package=magrittr) [![Codecov test coverage](https://codecov.io/gh/tidyverse/magrittr/branch/master/graph/badge.svg)](https://app.codecov.io/gh/tidyverse/magrittr?branch=master) [![R build status](https://github.com/tidyverse/magrittr/workflows/R-CMD-check/badge.svg)](https://github.com/tidyverse/magrittr/actions) ## Overview The magrittr package offers a set of operators which make your code more readable by: - structuring sequences of data operations left-to-right (as opposed to from the inside and out), - avoiding nested function calls, - minimizing the need for local variables and function definitions, and - making it easy to add steps anywhere in the sequence of operations. The operators pipe their left-hand side values forward into expressions that appear on the right-hand side, i.e. one can replace `f(x)` with `x %>% f()`, where `%>%` is the (main) pipe-operator. When coupling several function calls with the pipe-operator, the benefit will become more apparent. Consider this pseudo example: ``` r the_data <- read.csv('/path/to/data/file.csv') %>% subset(variable_a > x) %>% transform(variable_c = variable_a/variable_b) %>% head(100) ``` Four operations are performed to arrive at the desired data set, and they are written in a natural order: the same as the order of execution. Also, no temporary variables are needed. If yet another operation is required, it is straightforward to add to the sequence of operations wherever it may be needed. If you are new to magrittr, the best place to start is the [pipes chapter](https://r4ds.had.co.nz/pipes.html) in R for data science. ## Installation ``` r # The easiest way to get magrittr is to install the whole tidyverse: install.packages("tidyverse") # Alternatively, install just magrittr: install.packages("magrittr") # Or the development version from GitHub: # install.packages("devtools") devtools::install_github("tidyverse/magrittr") ``` ## Usage ### Basic piping - `x %>% f` is equivalent to `f(x)` - `x %>% f(y)` is equivalent to `f(x, y)` - `x %>% f %>% g %>% h` is equivalent to `h(g(f(x)))` Here, “equivalent” is not technically exact: evaluation is non-standard, and the left-hand side is evaluated before passed on to the right-hand side expression. However, in most cases this has no practical implication. ### The argument placeholder - `x %>% f(y, .)` is equivalent to `f(y, x)` - `x %>% f(y, z = .)` is equivalent to `f(y, z = x)` ### Re-using the placeholder for attributes It is straightforward to use the placeholder several times in a right-hand side expression. However, when the placeholder only appears in a nested expressions magrittr will still apply the first-argument rule. The reason is that in most cases this results more clean code. `x %>% f(y = nrow(.), z = ncol(.))` is equivalent to `f(x, y = nrow(x), z = ncol(x))` The behavior can be overruled by enclosing the right-hand side in braces: `x %>% {f(y = nrow(.), z = ncol(.))}` is equivalent to `f(y = nrow(x), z = ncol(x))` ### Building (unary) functions Any pipeline starting with the `.` will return a function which can later be used to apply the pipeline to values. Building functions in magrittr is therefore similar to building other values. ``` r f <- . %>% cos %>% sin # is equivalent to f <- function(.) sin(cos(.)) ``` ### Pipe with exposition of variables Many functions accept a data argument, e.g. `lm` and `aggregate`, which is very useful in a pipeline where data is first processed and then passed into such a function. There are also functions that do not have a data argument, for which it is useful to expose the variables in the data. This is done with the `%$%` operator: ``` r iris %>% subset(Sepal.Length > mean(Sepal.Length)) %$% cor(Sepal.Length, Sepal.Width) #> [1] 0.3361992 data.frame(z = rnorm(100)) %$% ts.plot(z) ``` ![](man/figures/exposition-1.png) ## Code of Conduct Please note that the magrittr project is released with a [Contributor Code of Conduct](https://magrittr.tidyverse.org/CODE_OF_CONDUCT.html). By contributing to this project, you agree to abide by its terms. magrittr/man/0000755000176200001440000000000014174203034012654 5ustar liggesusersmagrittr/man/tee.Rd0000644000176200001440000000151113706043053013721 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/pipe.R \name{\%T>\%} \alias{\%T>\%} \title{Tee pipe} \usage{ lhs \%T>\% rhs } \arguments{ \item{lhs}{A value or the magrittr placeholder.} \item{rhs}{A function call using the magrittr semantics.} } \description{ Pipe a value forward into a function- or call expression and return the original value instead of the result. This is useful when an expression is used for its side-effect, say plotting or printing. } \details{ The tee pipe works like \code{\link{\%>\%}}, except the return value is \code{lhs} itself, and not the result of \code{rhs} function/expression. } \examples{ rnorm(200) \%>\% matrix(ncol = 2) \%T>\% plot \%>\% # plot usually does not return anything. colSums } \seealso{ \code{\link{\%>\%}}, \code{\link{\%<>\%}}, \code{\link{\%$\%}} } magrittr/man/magrittr-package.Rd0000644000176200001440000000433113754722326016403 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/magrittr.R \docType{package} \name{magrittr-package} \alias{magrittr} \alias{magrittr-package} \title{magrittr - Ceci n'est pas un pipe} \description{ The magrittr package offers a set of operators which promote semantics that will improve your code by \itemize{ \item structuring sequences of data operations left-to-right (as opposed to from the inside and out), \item avoiding nested function calls, \item minimizing the need for local variables and function definitions, and \item making it easy to add steps anywhere in the sequence of operations. } The operators pipe their left-hand side values forward into expressions that appear on the right-hand side, i.e. one can replace \code{f(x)} with \code{x \%>\% f}, where \code{\%>\%} is the (main) pipe-operator. } \details{ Consider the example below. Four operations are performed to arrive at the desired data set, and they are written in a natural order: the same as the order of execution. Also, no temporary variables are needed. If yet another operation is required, it is straight-forward to add to the sequence of operations whereever it may be needed. For a more detailed introduction see the vignette (\code{vignette("magrittr")}) or the documentation pages for the available operators:\cr \tabular{ll}{ \code{\link{\%>\%}} \tab pipe.\cr \code{\link{\%T>\%}} \tab tee pipe.\cr \code{\link{\%<>\%}} \tab assignment pipe.\cr \code{\link{\%$\%}} \tab exposition pipe.\cr } } \examples{ \dontrun{ the_data <- read.csv('/path/to/data/file.csv') \%>\% subset(variable_a > x) \%>\% transform(variable_c = variable_a/variable_b) \%>\% head(100) } } \seealso{ Useful links: \itemize{ \item \url{https://magrittr.tidyverse.org} \item \url{https://github.com/tidyverse/magrittr} \item Report bugs at \url{https://github.com/tidyverse/magrittr/issues} } } \author{ \strong{Maintainer}: Lionel Henry \email{lionel@rstudio.com} Authors: \itemize{ \item Stefan Milton Bache \email{stefan@stefanbache.dk} (Original author and creator of magrittr) [copyright holder] \item Hadley Wickham \email{hadley@rstudio.com} } Other contributors: \itemize{ \item RStudio [copyright holder, funder] } } \keyword{internal} magrittr/man/compound.Rd0000644000176200001440000000247113706043103014772 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/pipe.R \name{\%<>\%} \alias{\%<>\%} \title{Assignment pipe} \usage{ lhs \%<>\% rhs } \arguments{ \item{lhs}{An object which serves both as the initial value and as target.} \item{rhs}{a function call using the magrittr semantics.} } \description{ Pipe an object forward into a function or call expression and update the \code{lhs} object with the resulting value. } \details{ The assignment pipe, \code{\%<>\%}, is used to update a value by first piping it into one or more \code{rhs} expressions, and then assigning the result. For example, \code{some_object \%<>\% foo \%>\% bar} is equivalent to \code{some_object <- some_object \%>\% foo \%>\% bar}. It must be the first pipe-operator in a chain, but otherwise it works like \code{\link{\%>\%}}. } \examples{ iris$Sepal.Length \%<>\% sqrt x <- rnorm(100) x \%<>\% abs \%>\% sort is_weekend <- function(day) { # day could be e.g. character a valid representation day \%<>\% as.Date result <- day \%>\% format("\%u") \%>\% as.numeric \%>\% is_greater_than(5) if (result) message(day \%>\% paste("is a weekend!")) else message(day \%>\% paste("is not a weekend!")) invisible(result) } } \seealso{ \code{\link{\%>\%}}, \code{\link{\%T>\%}}, \code{\link{\%$\%}} } magrittr/man/freduce.Rd0000644000176200001440000000076313701613606014573 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/freduce.R \name{freduce} \alias{freduce} \title{Apply a list of functions sequentially} \usage{ freduce(value, function_list) } \arguments{ \item{value}{initial value.} \item{function_list}{a list of functions.} } \value{ The result after applying each function in turn. } \description{ This function applies the first function to \code{value}, then the next function to the result of the previous function call, etc. } magrittr/man/pipe_eager_lexical.Rd0000644000176200001440000000101614174202267016751 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/pipe.R \name{pipe_eager_lexical} \alias{pipe_eager_lexical} \alias{pipe_lazy_masking} \alias{pipe_nested} \title{Lazy and eager pipes} \usage{ pipe_eager_lexical(lhs, rhs) pipe_lazy_masking(lhs, rhs) pipe_nested(lhs, rhs) } \arguments{ \item{lhs}{A value or the magrittr placeholder.} \item{rhs}{A function call using the magrittr semantics.} } \description{ Assign these pipe variants to an infix symbol like \verb{\%>\%}. } \keyword{internal} magrittr/man/debug_fseq.Rd0000644000176200001440000000074713701613606015264 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/debug_pipe.R \name{debug_fseq} \alias{debug_fseq} \alias{undebug_fseq} \title{Debugging function for functional sequences.} \usage{ debug_fseq(fseq, ...) undebug_fseq(fseq) } \arguments{ \item{fseq}{a functional sequence.} \item{...}{indices of functions to debug.} } \value{ \code{invisible(NULL)}. } \description{ This is a utility function for marking functions in a functional sequence for debbuging. } magrittr/man/exposition.Rd0000644000176200001440000000171213706043022015344 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/pipe.R \name{\%$\%} \alias{\%$\%} \title{Exposition pipe} \usage{ lhs \%$\% rhs } \arguments{ \item{lhs}{A list, environment, or a data.frame.} \item{rhs}{An expression where the names in lhs is available.} } \description{ Expose the names in \code{lhs} to the \code{rhs} expression. This is useful when functions do not have a built-in data argument. } \details{ Some functions, e.g. \code{lm} and \code{aggregate}, have a data argument, which allows the direct use of names inside the data as part of the call. This operator exposes the contents of the left-hand side object to the expression on the right to give a similar benefit, see the examples. } \examples{ iris \%>\% subset(Sepal.Length > mean(Sepal.Length)) \%$\% cor(Sepal.Length, Sepal.Width) data.frame(z = rnorm(100)) \%$\% ts.plot(z) } \seealso{ \code{\link{\%>\%}}, \code{\link{\%<>\%}}, \code{\link{\%T>\%}} } magrittr/man/functions.Rd0000644000176200001440000000071113701613606015157 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/functions.R \name{functions} \alias{functions} \title{Extract the function list from a functional sequence.} \usage{ functions(fseq) } \arguments{ \item{fseq}{A functional sequence ala magrittr.} } \value{ a list of functions } \description{ This can be used to extract the list of functions inside a functional sequence created with a chain like \code{. \%>\% foo \%>\% bar}. } magrittr/man/pipe-eager.Rd0000644000176200001440000000335014174203034015162 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/pipe.R \name{pipe-eager} \alias{pipe-eager} \alias{\%!>\%} \title{Eager pipe} \usage{ lhs \%!>\% rhs } \arguments{ \item{lhs}{A value or the magrittr placeholder.} \item{rhs}{A function call using the magrittr semantics.} } \description{ Whereas \verb{\%>\%} is lazy and only evaluates the piped expressions when needed, \verb{\%!>\%} is eager and evaluates the piped input at each step. This produces more intuitive behaviour when functions are called for their side effects, such as displaying a message. Note that you can also solve this by making your function strict. Call \code{force()} on the first argument in your function to force sequential evaluation, even with the lazy \verb{\%>\%} pipe. See the examples section. } \examples{ f <- function(x) { message("foo") x } g <- function(x) { message("bar") x } h <- function(x) { message("baz") invisible(x) } # The following lazy pipe sequence is equivalent to `h(g(f()))`. # Given R's lazy evaluation behaviour,`f()` and `g()` are lazily # evaluated when `h()` is already running. This causes the messages # to appear in reverse order: NULL \%>\% f() \%>\% g() \%>\% h() # Use the eager pipe to fix this: NULL \%!>\% f() \%!>\% g() \%!>\% h() # Or fix this by calling `force()` on the function arguments f <- function(x) { force(x) message("foo") x } g <- function(x) { force(x) message("bar") x } h <- function(x) { force(x) message("baz") invisible(x) } # With strict functions, the arguments are evaluated sequentially NULL \%>\% f() \%>\% g() \%>\% h() # Instead of forcing, you can also check the type of your functions. # Type-checking also has the effect of making your function lazy. } magrittr/man/figures/0000755000176200001440000000000014024414613014321 5ustar liggesusersmagrittr/man/figures/logo.png0000644000176200001440000007115713701613614016005 0ustar liggesusersPNG  IHDRX?gAMA a cHRMz&u0`:pQ<bKGD pHYs!7!73XztIME ;Τ|q^IDATxw|Uו{u{G;q؉xL2$͛̋qbN\bc^D$w鶳 @~>${>g뷖Mb*,uBq>=7.F qGjEi֥H xKj EG̞>U7.mF"&bR]pn ?#ħX3 T==}n:ۀ0 FѬ&cDRĴlxGCYJ3pKqAԞ>7gMD[Ь&PHkj0R'rXn2 ,7=1Oa[zH)r C5JkE4[ӗ p(4cm11RgN!>wlU煢k=}nڀۀ{9 gC37"fR{)_2B(G7;)% PT)uHW u B(f6 EDZs{z8ܴۀ{!Utfi-g7BB<|#SLuP $&ކۀ{ gC35`5ףGHHCTw5)Oy8tʍϜ\E&u.cJ)R ZV\F!/fve8 lL:Goj2w FOEQ:sfGlcM3E%ѽ>QC,Q ~j.m5OGizIƱiZ&Nժ|-[vqj:V\_ojng_C:q6nƶkB6C%ګHc:\abٰaU@U*+9t8;v#V j]!R$T:?O]!~pp7t4Lm )!>Q=cʕYr)aHai'6"vǨFU;5K)B.5kPTqp7`4͌nA8u? ؅zb=u\)Mf =M|BVYƀ{y;Xssپ}/Gc DBZ+)- L6`,gz<ߞMd̩lܸ#Q.w`XHMMc˖]\d2uv}b-l 8uw0#;'4 UU5j6aIxzpGU8q"۾"M@v֭n&[4f:Ol tDv .Opputa29̞=())u8!n.[|u^t?=jOֻ^gjd\֭{AtQƚum۾$;>8vMpp;+38۾i``ԉlzj c$jmEQL&3.\/vzq/o"/koKzځۀ㰚2?H<9\GcÆU̞= oo^g 5u$=ŗ_!7@g"x_-?E3c5;B.EEEjRVXDXX0r[qk?JYY-v7nnO輤toV`hՈf5(.& Y̓]REEH=ӗm<|j !hk~߲ X2ƃS-jvc>`p.Mi&퉺y4web..e,FL%x9d~OA=2.o(B}]O$mWde:-jcSb33ƢY^b;z25k̯\wa9b٢Y*#L)uke~X}^pTf֯\*[B)E2{rE1`G7?_X5\Ʋq&LmI܎ooÖe4H>{-[w:B.̾0`Ѥ xHl5WܰyfMl;wwlM3)Ï#/>^kgOb2O,bGh.[ܹs޽+ e~Vx^tlq׊pB{;d~!ß^ƎŦM2~̌,:?B^awu/uncDvNe-~$5kPtxFp0dO_r19s2c#[65k=V+[Gb?-74y.yzy2s6nZm qWen.\Hd2JkE}enwe~xX72?7rYmslQyG4l &kDZ-]#[-s*t[{{SRR*oP?uC-cvuuǏ̟2d~e~ng]![8a&q@F!g}ܥ2W3fl:Uqq.lM\p-[vb٢cMsĀ܈\qo06l\YqsioKnn>"٢P,]mѥh52pV^  vn\=wD*leHl&!Y@7,\-sӥ8*fdf)[lղNS ,MIcٴqu3]vx[vRbU~PMJԹv؀(GDVn&[СyEٺ-vF3Y<{cc$Յ21wlЉ^%[lwכsd~i7?7{e_z٢bw}&v"<͝X7M2?7}6be GeUτf5uo MDv:Hq.-s0T?.[8cmq,ui-=z+i}l(^'̙ٸq #Qw[/wliN_C)ޡ2gp/-sOhmvb=''˽de>[}!>j.[TTG])d~QYK&qk!$%wJٳ7{vl1h4ļICH7uk2hP4RڃWB̡ݸH Кs>NHeEf1-R~J\" +3v 7nz1nw6ֽ^sl.[|G̛4 d@GtW7 ` ,_"5Z[#ߕ-a.-l1oRlVV-bmM!l]sNE7)V͟;v mP]i7]qlq>N>A٢(k;e~ǰiJ& ۈg͹+[Le=]ol|W7'ׯ`޼i]i7}6Ώ)[<|;_lߎzmzV\DDDkF즯u\cA?F}}#X=r4i&K\va6 nϭM+1p`4ֳ=MK69z!E. 7n.t4MCQ:]$m"ubȝc馯л&^x4ύ=.5sIntKE39Pngz3 zyb/5` 7xW d7^  d7KK }jPad˶QajH$PQTEQyҴ8whL9TNpWjrrΣ55V<<I\\,C6dq4ȺInnee444EXXC $.nQQxX5cw^eE~~1GhDRo y3?aa!hQ7M_¡MơC'r9*f h^#88qFl<Ə=}xط//易6 n> \k9x8n#~ylgyO+DQ붿mhhd߾D23sx6m/:8*_yĈa̜1KN@Q ՛r9X,]Nee5&`0x Ɂ|;eҡ!4Â2/H)9v,n>hXQ%%rrmdC＀gߛ]s9z 1յ.y.E߾!OfN-~z̀46y͜?7av#-I {%<,g]ٶ.űs\WAsSմL}k\NQKF;>o=:#GN?&iMx4TWڷD͕[bL6oL|roi,>VTVzZL&KE֭"^+B^^![ln v,Z8c Ba2}M}"sL#6v >֓DZI;jeUU8w2bnn/o_"[5^OOk.eƕmf'**Gx>hǎ%x#TULN:ʕz$%_Sjk8y22{zj5qqC(;s^ᱼg6m"=.tHH 1̞=ScY,v>YSE"ݨfjkps ^~y?$~~hڃVIcoƍ-bٳǶ5i-:th-]TlGT,f311xo_"Gn4XeҤ}wwSju:aKTVU?pLwEB°^5BwAŋW}Uwڥlxr:=|`5MכWLEE\qf=85W!ǎ%=40䒒2f~79}:&B8}&81b(V -G)mƎ믿HPP`jX8}:FcOA'lpbZpM>|(6Do{&I}y >=rrF .t** w$^ƿo&MtWQAA17oR_n9& mj՘2ek,i5ۥ}%٭gp[rn8b|‚9ޏi 6ghRJ2`2Z9BW݁)EQohd׮?;;BrrnQ[[s(vxl ˖#::g!7/Ͼ݀+jq̤Ic:hRU3',|vIUu;=EQ/ⷿ37/!lqH)ɻUآW&%L0-B$aL0[,oӻ7[ Fc oZILL}6I ںGps\aȂ6𶄢(hFRE~7yOn__9cZ)+-o3NeD°NLkRJJK]cuu-iAG-NjgqLccSGLGYJa6c'UUwO_8p&cw-+uu -~'"<ξH#"B;b{&&LfK)//N(IK7jb1[:Y7^?3 '/C G`vv.z]?Gz g?)5˃#-%b0:/%tjgj'c1[:p{4qEJ's!Xn)f>I]]}gMq3\Md%ZР>7A+kzG)%k^¶4J.E}j-b !0TU״xCz=Cw_2RJ<<<3kO_#.n8ǓE0TTVӹAEe5&O&#7&$$W=ڀ]ř oVMM-))&0ot:ٵl>h+_|gM0 W,F6^eƄ ij2RTtqj/B4MWHr%80^ѢgfP޶W[֜|%UU \hFyyǎ';rJc}-ףڹꪔVƄ YpwjUU[[ϖ{9|@}}#8(Neݺe ݮ_ g/qCʬn23s[ԯ㨪Bee5|s.ӫ=k2Gsz=7IϮ?d2rZ5 -xMZBJ6ԅU RR؋C(,Y< gV]I W?w:ͻ/Ucd0ͯrpBQQ)/t"iiש /׸SROZW24 ^ziӦMwt"&%)FsJ.eŊXJe/f۶<ȭ޸q% |: M8iiXtnz3""¸r%C-a?6l7y_*Ο_|ǟ|C'ɹES߅2$=e DGS\\Jee:c RWKHO" Ȱ1өGuM-YY,[_`qb6+СS|6b7ɗ(-i3SRZ9S\ܹ+;(j6n\K >u FMM7nً\JAA1F!1ͤgx/MdŊ?qj:)r>el ֭RJ|}}xկΝ1;.tن OܳR/tknPQQI8fjK nVW 6s$ƒm$hr1mfOXx6=0gds]7ڕ0JMe^y1c"mŅ W]"dPFv:KilK~R+כo} v_Dk[qsX`&:WU:$ܹSö-)+ l7lԩwP^NeD2v\W-fE,+\pg/qz5aJg,UU֞ߎr$zL8X>ɶ/_i!r>II3k;6UU%*Dױ={rd2oڅ dۦlt:bb7ČrXkjjɼٳp {Z>G"C{$k :KeId^!5YYy:[:7a 1 G7oooL&[Fiuu^ 1c"gMmכ3inˑ];vf_nq ~5kpJWfr+4I 41c3nHQ6=rBz$."M=`ZYf)?7{nRd&jE4eoE")+ڵ$%] r:wb6uڋA0otV,vǶ3r6L˫8{<*Νg;V+MMF0Ll^^x{{hl4_DJ&_ƍZEiѓIQ=+2exn#YV~8y2/Q֫ft:aKjjHMMlERRzo^DG1a(f̘ȑ87i2s$o1v<ۥ.q|$]W0b( ellޏ-earWav5>> 6i&0e8 /րǑfr F9pUUU!4413c$ƍK ,,N_wcj3k2e_l'[m|pj&k,aʞ(#vϱ{`LM+2VsEKQ. F<ƌ;9r/z€'WTT=4y0jh&Oo>Wɱ#X5 ^|q#ӦgIJr]Jfcc{%5O_βer*g><0'2ah"G ̨\HJ~z+]8fQw]Of붽rYjG9yL0mVX̨b0jX'=n7`lF?JrƎK `TotMf™UpV!fiZII4ڤ̨kIJ`xXS}OȡI#vD /ǖ8ukzz .3^= ge,_6VWjڵ;DJJWF1c$FsZF f̀Ep5devI0jȐxĭ[EPTt&3z=~DGG0xp Du:*Ugv>Lii9B-Q82͝SOfAYF|;RUU%PTUq+r= fh@HHJv5b>f22T7ر$OTWbFaK #>~MgIQEd2q%6,Į8F0s$TݘLNHHk `0`ZɹѣI>JQ5 {.P&N͢92NuVAn^ٷڙ(~o0jQ̼/%brt ?ŵk70NT4**8t)W/^͌[,חq99ز+?KCCZbV-b%9A4ΟBS]bt*ر'RRRnd2W@nnGfjkQն_ꅚqr99X~9_{fM_q5PUUˁپ}?EwZ}M` <F&9 ˵)%Mml`0j=3`(df?|E{G^s;vWSDа`|}nI{3?}s;`BCC#}J^{yz k m/];Ci*ϛ,FRUZҴ>#v(\Ư#/?w|/pL!-ic6}{u>Hn F d mʌBȻ}} ^>7;bmǡ'C,VF`˖cDGGt:?{?gM4d8Q3GdF)մL~{D!Ho^c޼ijMmQh^ϋ/l W gL>vdFiƖ-{ط/)i[Q.㄄KzU+( u =rWh[&]tL4g GE[jF||,}|VJK&n`M oSnۿ[fm}.VLHHG5kn3``?wuDFо$qEQ8s&[bj-ܭiYD^aXod2Zi|}?̛7ܬæIMwseg86D,]:Օ352rmWf`4mgd=xm//Og&-2i 3Oo&ݚ!˓8oOf*jjZoi+̙2yQx &KHI3)\VA}}~Q{.߾Sٻ/jTUqYǛ fiJ AJ$cIJIDD(QQa͌#)$&y ]QF9SIHF`Pԑ˩r9?p){g׹|:BRv cǒHO[vɼ㇢ݻ-SxbB>hgΤx EQ~&GW*vN<_&;;%k>Ǟ1 <M^r/)Bkپ@$~<*xb! cر ,]:cǒ/[ i{2o4pP#[2H j:,[6^} ݯCO_w?eޣ-i:|%KFHKwsLzgg՞ aڥ|b!!!FEpU2Zq"6{{{r"#yw_:?ϭ{J KOAvέV3Ok>O`#]0U#ߗoYf͚C( yy\,[Y}%/3NegYh?_s d2s9ƖzzxϰpGzĉ^":RJΜNǻ;4Ʌi45LJIxx(/@679,ޏhū=&1s;~_PV^ U||,?WOÈú{&IOrV,ҥsu\Uc_EBwI m9-~.d™bmhxl>d[RBnحwS bwA dpp+V,`ڥDD9 y | hv@}džqi ya:7ndܸ=:}ĀmofMpu!fNf׮Cv?+)-ۚR kؿ8w째ĥ)z'3k3zxQ޴D"ƚ1jpԡk4W7uʸ: :wMY0`ılk1RITTx ACC#UU5 ݥW<ͻ|ٵ)ظ -w@4!ܛ.`Ԩx NQ=z8wh%PZZlqk ;\K)  ۫mڋ22m0-7@KmL}ÇOR[[Y,Æ +80Ϲ˭]W6t:=R^uuX,Vz= `2[a}: >>-~i&Klݺ[ ].T]'g0yX? dnWӀ^߅uPp>c{KXZrlmU"\;6Ol.RR.l[螲6떱||x1^JW;B-ӳh3lSUfsMۊlE+J޾]ʎطS <;wO=aC](g+M- UE[x[}n`0xx>aR/MMķoRUUCTTXY(w={I)1<Z=c29q"͟ry $M_FQhi&Z5n r ij2I{քK vl_Ka?( ٭nSعTJEQ(--磏q :q~:S֦/# ::pJ5tL9dⅫDEExLOdbI)uFOd2s"F6C'1 8tȟ/Ϯ]]Λ7ҋ @J!1<( 7oܹ*gdz9^cA=' C1 - UUx*G"'k !˭ƌѩuS?Lԇۊ#H54v?W}ѣ;?{\R3 QطnKqqIXAMM=_||g@"!=>}ƀG`n4m\5*\·nd?&MV7r9{qJ~ voM2EfjkdBf3mig- gF'22ǽi <ɓǶܹSʛ~3g. g^WoKqK4&t<=yr?EQ6u<w^{>I ̝3.!8r4}CJJPUU?oa=sOO ` ^ʕ 9{9`3"?NJ Xd.Dw֐6{ ݑcrB<=;ں㽿͒s 育6}M:t0Mc-sV\Ics4:Ү`IpYz~VɓG2iҘ^1}ʀ5Mc,]:[( յl޼CN7x{{Ham(+p}KH)Y0&h1͂3شket:떑rD`ao\fذAEe57o擛OccS/˾iJ|}}z}>f:UM+IO"-z+'WRZZWn9$_I'f@$z͚bl=fN8W=zޚkX#++–d!k,aı^5MJ""x爊zxGqGoHH~9bb\R:uĈam:[hh0x)~~̜9Syz[4ExVyZR5̞SOvI⍫=g4Mc qíiL:%ǕRuзprY8_y'LYނNֳrBpݖiL2|뽮cGshR2kdTU}bޭajDEګ3otߤeq[ܓiN%!!`Μ)xz>BEJ~9<= ySI3̼w+0xƌI?}snmcqSruSF} D1t͛?oͧԭ{5Kظq%~i{$&adh4-[3 f,^4IRJz˖c)WT!5IHhZ[ի3zpv:)U8Zk'ޤIcYv)cnj%ℏ7kV/a\ WΣ&[CgUU4İa4q c%}3ix{{9 khEkr+W2(,MMmHDCTT8F3eX Ts5 o@ϟ9SihhF,V+:U _ۀJc;aC~2jk멭dt.o|}}`08^ƀ4㍯}: Zn1JPP|xmN3H)mM3'ݸqcmnaMmnaz Ar?qUF"[y#=sMB[Q7ngl#%'_/g]ǂ3zzB~Mo̠AqRgQm˔ill AL8e6hRR_߀W9lg| zԅBpi6_^o} o?bBʺ~>r]㨫P<'466uSGG߷ڣf'1mڄGk+BN->p+O< fPSSGccu.Ju5OpJohH4MccTTTix<\oMk$ 76=V{ޤBPUUlF2*+:4Fw++l< A,Ed2SS[j1A 1leYj`{v>DUU K;*b߾Wx;(R>cyS^^IMm狿=ކ(ܾ]}<))1+*j{v#QU.^t6x)\6nx9wK`2[x>|hn)#)5: fj{2nHbc:/6_,*+8a4/__X+CORXpIǰp{~W(dff|ի@CCY,_>gl蘢؊qBөm d29֑W`wi[~K۷I!''wկ޵7Oժx,ʤ pq~?QVV544Ŗ~_w1nd_[ܼgwqN)g3B>ESG2MVncI)sjؾ}?.\eޣÕ+mvaE_]z}.^j?}AZ{;##/|tp~{l޼EQ=k O$sҵ{ϿًX>Χ\3qqI2eSsw^:Fc0x4{*sD2Q̚9 vRJ%{! 7gWUPWWOLLTOQjjj9r4Ig/bZ80"jk5j8<{~;wʘ?B^/ƹM<ן_*QKs&yq_/v;^͠AL&3w/َhbҹL1?/]g9v ogƏųϮCJɛ~_)+Bw_"444c/8X;ɗ_vJ4jHbÓ+/ì\%!,Y2^܈x|)S]z5l&;ih32 :5EΜx;w >rJo7?#22qUfΘsw:T&NMpV)2f}1ދv|@N-Zȑ|ɗ wcǒi|N.\ Ϥ7t9EַRjŷsL Bqq e;˗_`TVTeACc#[V~5wיVYrgŊ+ Ӣ)`2s$xm (>d;0 "*2rrHTT8ɭ"j-!`)3jd ΆcpJ&UU5L<2-l|7YL8 FiVf+ϤMM&=Ô)h*+kp*C_ pd2u^ f):mWXb <U7ׇK…@QQ V{DŽt:֭[FpP wHzq=37|#1w4**}Xpfq #6l0sbcaX9v,aamhhȤc1<)92/NN!$8ү`0}HOw&ϞDhh0QQH)1̜:} AlF}=N2m9߹SʹsL00n.֭BO^pgVBPWs>ƮIddf7ƪYnbb#/ж[2Yeo~FU,+$9gOq06mRQQŕ+L:Ƶ;َ tnȥsR/"<,oY=+G4'\xz(((fDGϘ1 x{{98ւWf2mx(--tfΘMMFn3xPX~p* pWUۚ,_6^755(ddfS_1#Oz nTTTr FsN9cƌ@UUL&  <,%\p//O&O "g/2nl3֭B.]JclL/hj2Ș1cpJUU5̝; ^¹T #t+ܹT] PskGN1s$bbxWQ^^SV, `N:dbr;P9#(µTTT1cDTU+W20cg2p*99mL0𛄄,8Ov>fmK-++IRTTq MPAVV.55uL:$jllb/*CamBB\!##Ç剢*[;f&B$u[-n*$ddcxzɄb0¾#G9/?*DJeƍM ""-JK+;6v)jj?n$zb~#""B bĈDGGiV?'¢;DF7ߣ[̘1:NL&.n=uu[El߱:4-Q#6t} G#`%};ܹS[l)#\J``8KFV.A¾|Uˡ'IMFUU ? 99 FݳᡧM?Jf3Yl|x3L\nk-( Y|0V.&(8?iۛ3ϬeÓ+PU&v8jqL&35p9>l'x3$v Bފ)!^ͤ)S#Ғr||m3MJUJkdԨ8~=7"/!TVV۸w0xHflr>>><~9:J]]Tmg@=. VUL<ƌ}NǏ~MTU??/0LDD8]ط/\^zq# Τ BޭB^{y&Oj0i=?0jd< $%]n!3#1Q_ іH1}w% :w~ z`VYҪd uvuv_K̀(n=Ig/y.OU7gƎqOcOܰ!|;_߶ YۿcRfഴ,X8_zz9ͧA6+0Mx{{d۷Kr~ϰt\"#ٶm/?EPPǏf͜SV_hRfܸ6jʕ lX[S0pP4[g?53ObԨisryGsJյodf8x"i~G&;+ƍmYAsbAI)[լX>(VZDamږ/^ Oݫ frD2'N$3g'D}])'OC$>>^,]2^Mhhp>:ϟN쐘nPyb5oZYf)?7;Cuxyy:]9z_""BAee5ř}tJ۶כz Xիgߟhb,[6Sǡ9p8'O_ $Yĉdεm8k``޼xyy▕Uu^ΞHTT/8{Ls3|ѣj"z }-[ߗU+?2vl=UvdwMHǸxyɊ7.gqěֽ$UU>>p+ψfyӎ|sŊ^Bw~1g^~yRQQŨQxzRd33 `>:;>[V~8y2֢ ӧSؾc? >>ŋf1yX<= nR|}4h Ab@J zh:`K*qak~55 BVӨ{?P|%{+#̿7-?qFۂ nw̞5|f˽i3ֻǻ=ܭA{~ZΝcEUjm2|P@>`4RJ)x- lXh0"}!-ٺ98s?76Dkojr)#:tp(ˋ/l۳]}5V4sl-=7hъea 0f+߾]ʊ;-+H)9u<~̘1]3I)L0ʙ7_%u7$xyy~~ 㥕zիZ 2uk:;z܀ݴEQK=o?}?((5< ~e6>bTU+:֫Wm} Uэ7mnal7pz_ !44{7n\ٳ+h=2O~,^42xP4R>~P7nG썬\r'N$]qr8 b%,]2g37nܴG2MdޣL; ؁C2rd<7>nt%PWξ]L6i̜9 ad"ڕㆢ(X,RSٲu.\d2w0$*Qڹdo!''g/R]UKTt8~==Fn:nqnn~?y y: !NC@H{OJQl뤤\`VnRjkT:۱Š XrBdMWDر UZ@@_+_,FEёx߼KMPn3dU)2R v :l`֯_yeJܸi/PYYáC'ٹ Em B(JZ!ѤUk__0m$jXwoR>ut4MC3q6mZɄuc7}EQ0MNe=]jv] w4kSDyq4JÂ#uj^ %@6je<~ۭvӗP9lݶ3gRhll6JkE4HP Ο:YPYb[ϧV@/ڵn٢1fe.k̶~!ěB5ЬF҆uCϱYǙ )_C;r<:8&&5ktlMyH)B(_JZמuCUph4bDQ 5| 7m|n٢n52{CwR U8uy+q _X5ik-[tV@5υS~3rH0A ׁ ؁c}, !LȲXf #Nn:cf-`M 9'솬I=9XXh~L7!-+d};M7B_HRm[reZuz:R>vx;6MW2eX<dޣTUtM BNŸ_FUCbr:%=6.=fr + nh,Rj%)a p n9:Ŝ={;wʈ#((3nz Aթ\'34v;v >nM'%g?nvPXx3ۅP~}$5s=jz܀W\ MJkPtALE`2~=TFDGӮz}nzLfTUe׮CVp,._ɠM+ѣ#͛w?j3ZRc)Y85 aC#5QjK`.[[[Oj5._`0ۭŘL&8~<"Ǝի?񱤧ghdQ;>sNq}g,w(B1s]n+ڧ\8-j&`LLR]ء)ٸi%cnj@u{p&"EEwX`[ch@R~2Vk7HJorRd~ ߞ~_UOð+kBJJEl$сnWHRE+ #0П^.4_BFz&'* od!p! 9s|;!+RZKt_NnaiOC>"7!@x{(Hz ΟŢ^ۭNTUp)\$88__|HBc}<(_J EHbttn.ÑEuN)G!zmi0p-|9@f nqE7?3CB(R+ w1p{ߥӲlq[ EAQr عgOh2s-: an*$>.CQ^޵2?U͑3==4_{e#$w]![76V2e[45IMjeР LMu-'Ol~2PhhhlR{fSu t٢TB\{ElH)Bp4 V"# '+;_@n^ 6m^^\zte~E4`+dOXJlEO0[,\K&LEHH0۷c9DG# V;wᓝY_̯Apl]X ESzT4224PVVɭB#¸|9s#+O/3gNߗZvva_wѯ #;'u?l1vn٢ GsUU%jN8GII9'O#f@ot\4y=$$ C3.#ci5ڨ}{\]k%ۻ-*^Y pw[w``LTU|M+- XKxy}Ggu^N>#~fE@h4w憦 N݇4 LpP&&<<^ǰQU>l')W_wlqR3,ۃ[5/qr:H(ڵ zHK$55|XrIg/DCo`c8y22d~).[YpǶ> R񏞜hm]< 0xKܼEpp !j\7/i??v8ә5k dxfLDqq B0M$'w>f箃TTTvp+B(?w*^{x.׫ڀ8Nl%:+[۲E!97oQ]]Chh0#$$C1b(WfRRR qm De~?rp[$5$Xu[tGoʕ /(M}G#ߏY&¶mvk׮svk{?g+`H$߇ [no{xkx*ii&22^+jBc^'E><1c8{"̙3@MNu Өk茻| !JrJ(IU=r[qp+Wl3dRg?" 8vn;9;wJIJȭ[쬤H)Qۜ:u8"#0x8x0 NcArJ&{#r(uA|,ܜ/j']jm>bP],[%:geBt:l?Fl@Ү3rdF!++&0 :l,̯pp+*gҗ/nAZ҅`K iϱHKNʅ ˳[jUFV.7oũ)TVVh$6v opv)˗c̘r~ycRR.wR\/.#Ŀ E4t_M븃X`QH ÅqnAh{(?~^1Ȩp6l;wdӦ EJ9>JB(jVSG] mG W ٢7sfwl6[J?KMFU̝3-[PPPo|ь7]g˖=mBboe~݅ۅ@)gw3zA*l6ٳoh$::?zMӸz5^OfF6ϤIMM-&%>~^^ "((;wJf23`qTQuoJk&;{+E,7SC)jA()Uloۍc6l0O>ysݡ>PW~&CcbjTVU_ ިJyEd΃u [!Of)EѤsc9E'[R7 'ETBC8ssNۋǓdݺeDGGlԩvW7 8mѰbً)#sv TWբaıөLff3>uk7E趸 3ESE!l߾NӃА`.]Jߏ!DD;+d~/TJ倔?2½`+Jo!+@LG>|(7<ٓgIAii;wg]GCC#:U%!aյ=z;td~|(5KP(g{oSۀj csu t[:xۢ(TVVs!͛F||,MMFΟ–{HMn~xbIPtnF,:M3(zYb+{;uxVF`?fe wK:^ٷ>N8iA !~-TdQr6 -rTG\vR,Cpp Hɝr=ʞG)))B)*|lqpph4҄*^Eʗh7w-i2n~N]!5Hn%8-z n:m`@dgBn~Uٗn~ 2Ou}}sg#$Sl4t? % V46nI6"dΘ83OEP|1Ŀ (>/ % (>P苦;3ie|{g蹪X-2s=+WQ+]L6O w[C{_F qb Uvz?Zb1@/zcs>~if,ӈUSjF 1_Mjbuݠpamhmçϙ>a\+5%QKFkm}ۖ?ޚD\!~6,-7SثŜvķ5Z;[rmS5{yDyH}r9|-ăFAJjI.[/]mK 7KRDrYQO-Q||6 (0 MXd(@h2_f<:”_δ*d>e\c?~,7?& ك^2Iq2"y@g|U\ @IDATx%E 0 !H JEeu= L%)Q8% $g #! a4|{[:W9{;TW} =ȜHHHHH%tHHHH2$@$@$@$@m7F$@$@$@$@:@$@$@$@$* Vq`$@$@$@$@$@$@$@$@m7F$@$@$@$@:@$@$@$@$* Vq`$@$@$@$@$@$@$@$@m7F$@$@$@$@:@$@$@$@$* Vq`$@$@$@$@$@$@$@$@m7F$@$@$@$@:@$@$@$@$* Vq`$@$@$@$@$@$@$@$@m7F$@$@$@$@:@$@$@$@$* Vq`$@$@$@$@$@$@$@$@m7F$@$@$@$@:@$@$@$@$* Vq`$@$@$@$@$@$@$@$@m7F$@$@$@$@:@$@$@$@$* Vq`$@$@$@$@$@$@$@$@m7F$@$@$@$@:@$@$@$@$* Vq`$@$@$@$@$@$@$@$@m7F$@$@$@$@:@$@$@$@$* Vq`$@$@$@$@$@$@$@$@m7F$@$@$@$@:@$@$@$@$* Vq`$@$@$@$@$@$@$@$@m7F$@$@$@$@:@$@$@$@$* Vq`$@$@$@$@$@$@$@$@m7F$@$@$@$@:@$@$@$@$* Vq`$@$@$@$@$@$@$@$@m7F$@$@$@$@:@$@$@$@$* Vq`$@$@$@$@$@$@$@$@m7F$@$@$@$@:@$@$@$@$* Vq`$@$@$@$@$@$@$@$@m7F$@$@$@$@:@$@$@$@$* Vq`$@$@$@$@$@$@$@$@m7F$@$@$@$@:@$@$@$@$* Vq`$@$@$@$@$@$@$@$@m7F$@$@$@$@:@$@$@$@$* Vq`$@$@$@$@$@$@$@$@m7F$@$@$@$@:@$@$@$@$* Vq`$@$@$@$@$@$@$@$@m7F$@$@$@$@:@$@$@$@$* Vq`$@$@$@$@㈠ՒK.Y.E$@$@$@ XdE__|b'FzX6xcuSW3$@$@$=mVzjѦhɢ7nZb%fmV2F$@$@$@4iR# ё Pp- @(@kHHHH(@|HHHHf5et$@$@$@$@~~>\K$@$@$@$P3 К2:    ? P?%   h@ @qz7=H$@d1$@$/[nݯL17$@NN4\A$@$ٳg^z8$@xx  y PV"CT* Jt֬Y&"h@ @qh-΍{@(@S-9HzD &iӦN8Gԙhwyd  H;Է- @ (@k(HHxk Dc kcH )IK$@$oeY&~###,Z&@2pHH`,_]-^2%oV$)a2H }!s@$@I@ϯƏK@$P z82  E]T-r_,K!y/ -sF$@I7j0XH j7 @EP_dEԫZ1ܝHuHHS"@coKRvZ[xKI2$@$()4/R3&;.qSC$@CG@h(]d"@XFKNଳR7߰c`@OP a HI+M'0a @A.d <"@^zl#LLc@`uW$Sxz׻E4zĤE4bjI "@V/3g*8} e|_K"A<H&xk hu}̥ ؛wgW/TO=pC܏3$@ OZ\PkHA կ~U=;7bƖ :J`haZ yE.@i!՜,n;d񚹦hJŴ@"T#8".@1p m) ^©"ח^zIm&/wOh%t@DbD^Pp@S/~O.@a.4#}/O6?QW2 !4kL)@<,:Zs={)@c$(2Ek4gD7I*514Ra*ok])\88bo3>YSf {W}^xv -ZeU+n.cwD#*o 8q):hGڋ:W+GXaTɓ3`aV!@ڛdF@4z }@GK/Dq"b( 8&LHE -ޮm+cIιO뮻/2qro6аRw߶[4?َ 9g y59#ZPւ1D(&gO-HPh1:1NÄ1~ijԣ>dք4C!ђp??X4 h9h}ŔrZ_}c[xG>F2 n߲vS-p CPϘ1Cnlb8T8MmҬYilh ..ALD[W̹շhxp|rE.1; [[&!@Ju饗ڲыe"@9zqBd` OjMh~Gļ:`xpA_}ub (SIJ}1!=^;0m)R\{ /pLq4lI o,;8j{ cv۩gyƻ1XB怊c м?wƥ{g}27~4iRuYӟt~gV_||s 7w]~7[oUlAz7LDsV=5cŪ^rpW~:J4怢'&I/。UW]Յ6=ɮx@b/Rb\̰~_ '0DgCS)SDɗZSO}J8x3I,ZDo\plRkW\qE&F%x({M*vwBTnE歮!@`Xzz4 hY[Fm(L1sLoQ;.V\qE14 iK P>8p6;8u+tt3aW1W>?9dĔwӓDW'%X 碋.C@c>ۃ# ^м8o]vY_J<(nwHVh^]$ LFM̪ "{@xL$!fzw(}؊)eBb\rIW'\gi/:`Z%` O|ݎfکJV¡vm'!;+R D{p$,Db+sJY5#'@EУ ~"@P'ʻi=G ؆G*uW]uU 9 К90 (7?%1 PL) }!xRw. @+M P8yTw@Sj*_^]yg.oh."nEz /1$@:u4M%ǮT敿K( _M +.zG4-wH}h)@0uY's0_',獵oiӦ| XX0Lp` *",]䶐m @CFLne>WWxxj֗,h0*n%EZ/7͐5&ˢM|bn"@u)92I{JAMWST& >:+X߷}[^~(@q}l(Bn8&;s4q ̂ tф]ςXl"@">QhG}:ؚ2HMunoS_]4q|D1Ǚܛbɴ5Gb $d{[i}xT_/ *!Ʋu {YU.]K+4IwBPn.u6/_] 9Fj'?ZkI/Z02 P7e5 1{W暣YBkӬsECB8.MNYGepMD\8l 6jב@l/Y1^ Mi1 ]&AH'tg}Bьn~xyO.WJ0郐i_]OAT` *u_]qrF9f0:F s\+1^Ls\Ja)@c,8>G)1TO"bw@QbqWq@z]11 mϥۣM0IQ4 PeJht~E&@J"|&ȇ> cH+H\/u< Eb4S돖^S7tEMHBo((2B̚3Ϩ &@_9k{FKML'@.}q@}uot@"xIF;xcӺ뮫\pQ*}3VŔ47,Sq@1m@Ϝ9tx[qt=9/ZfexՕ 'C+xN'<;"Pb%y<ۖ2eJVx0}!>}cpAjǼK/tvaŃa7((ltR_OJ)@X&PM.6r8ޜc>`M>KwcqVR7p Pm59 )@G`_} 4D쀾k'%Ga &k)y0)RWnS^{ۚ}u&H[nE_w[*$.js@co. /u6S"Y?VX! Vq`e u@]fH4MVoMLh< .*@u U`6.jM7H|m4&xԡٳggz=;輒`\EL$ƒƺ%@ VwS3f(0)*@%\Pel(6l3us߹!lHx[<YMfas@cz}ĹjMf{0A̺!uc>9in)R6A8;Mo[qꆹ . \,-ƌ+ߨzcLhyRv@ۺK/U{ghcv@ѷLvM:(~ 7T7tr5@ anMU+m5ۚiiz%E}3u8$J~)lO)4RIq5Fhch&&4RpPq@o7YꀢnH?PeE(E3&xE8Tbu@m}ʃkz)?3e HdcТ\;7,@]"ͬwu,_m+.O:Jt ~@_X/p?wuW_= o k'u e?n '-{9srƩ[j}P^ .PDO?PFgMhy8;MvS.DO?;C𠀷!|B"mU怢 :b>>(k r P;7:XpxFr 8CHsL7WSxb\{1MI6);XZzHmYjA>g&|"s(6K/(@=ͫL1 Pyʒ׌ڂ@}ol( ߊڂضKqyF:ELEwB]e]n;Qt|RzIA`̅} ;&&䘛)Swn # >ǪNr 8`c3+o2JkT4ԷM$);uJch>2 HO 6;@ɗ|DܐW_=ȑ7+T8.P7 ct@1;„ P 0(@<1:\/<$G@|h샐jκа Pɇ&*PtU&Mғn+Z)-' %R6I eޔsB'NwePFʍH PG?Q 0 @gu/")s/B&>ms{45ez+W[] 9 })מ< ڑ2&⋷BlZE3jZ >T\.ԥ2\rWmښSm8wp,*@cs@|5m¶VWlۥ N7Z>RvHݼ4 M.2Yc _v}lB[҅Auu P}K7Q8u6N>mut.) S0M>Åߑ[])&)δSIq5FZySO=U8y7ؘ.x fg ~yg 1SOPAi~sw~e%=*SfGOCd]Mu: BcEB׋"ymK:HtEJksrWEp%]vlPhB~beČLdUcTVDE@$_= y){|( b}u)ןB 2@)c=_582ʹy7q) .)#]v  6!qw)VQ|͗%?4UhQm P#PWoOmR&k,b_.QE)MBh@5ܰ]Wzjn뇀GrݘUWwUU4<2&UGl` .1j!0?c|i s@.@[efJ :3T> AޠCDO8m븁Y 7.@8(7 z&3TYΥ٦ m:h1K):ڲ.|*iեj(@[nVut)(S]f͚m}l zK/]u #j<;tW ҇H\nOGVC[)@"C(~{u׎Rh|^D97gΜ)?;,JglI:ȣ3$ϦP!ل85H 744,\%d^I|(ꀚ4 q3k 2KfZj?6.eTkYe7 a=6 UVYוyѿͺǙw:G:ȣpJ%M9xM})6OB IWr PWuZdP)~.rPQÙp1?y!EpNꨣo B^0ùO[Mty\;|(@ElIs ٯ(&mpq@q(Bn捹1>D5EcȧJhhc.1rP\ 97m P#rlC'΢B;Ɍ f-"]uUՌ3lQ㵢py3u#8(@S* Ic8fITD+="@8y7/3mt"9W܌]!|iCpSGА.4eWw7# @`"SuG^D|G}3XıDꅞ|Eu@͇3:Xrou(q9e(*)ԧ>7//yz^aД /n"|h\> R!"B5ɦ쀢n&@!w^ymgvQsLvu@SK-7o!kXS  ~q M70p@0)!|AO!4D6IEW iIkzmT!+=m9RG\Ph:iBhh<1Y޵͗ʺr\Ȳ?͖S5U ִ7ިvabGXS9vi(7z\}P+;|Yq Gxp(xۼ!4 8x6tBy# [cRw@uN)*T-(߯ꮻ2G,^K۪Ƙe17t,Ԑ4v.)~4g8MLOU6}y@({dhnw gU&L]ϔ(2 "^H0/}u@u?*)r 81@gsE b4L:ՌeGK"R4\SOJ"2paBА _M٫M(&'_>eCn`u]hN2AF޾.W%uZMι(йSl7댯Gr s~K  A" (Ekp]u; io/!02"`pO^p D;f\z󫹮Á80DHBhߛhhm[EbGoh9U_jۉ g AB40e.W,oIw4)sۄdBD?W 6 &x5n $5o$!e*@!].WtʣaX6-EJEڣ>9]4}9%ۦRRK̿qDfxq@gc*"VESބ?DvM-^} _r&|>h}1]e1fÖ! MǾ !(}y!MӦEz#˻?S):ˆe~kH)N ЈJ OM6BˋSQ]:ppрp u M!Μt@;!T̸E&!F_yz!,b:X<:EԎK7 OLSF@Rt@pS/ &yG>9uE2uP0RGYS/t2>1F]s мAHwqZs5Qi} M@oVO>.!n5 gu+v: ;S~\D(&P\}ebSDžVͰH(blܔot=P?t::BjE(&'qz<8(@8eB֨y:E(utlmu gc%sT 4 TD^d?Seж́E}>[nݭG#] PA(!O\G?Q<JӡB _^t@!"!DbYlc>`Yc eo[o~al[G^W !nz٪(nEo5stUVQ3g,\PֽJ|7<4%@Њ-m߯~W[5%̏Ah>f;ҝ'@q}AHdMtٶs@!5PSL}%T4ê/Tu@~{u饗1f]/~1qY@t,-ucVõ$I3Ϩ#u#%$$x4$; 79tUꢢ3u6}בCl7OQsy}LO;4ug7[BP$SΧǏu{ б%_#4tMiՄ r37d`.կ(Gэ"сo`^Ly~ IKlѸK1$g]^W %seDQOWI-'Iry)` .s9'phO)2Ē+nEg\q7JPͼwSKWhƢL9VMmM ZB^>xAzC_tq'x\7_?=;:"燍O]uln>b ]}]ֽ\pC}"mw+z|;AbA+U~ Tu]DSyкT@ E/kCS<5X#_馛/{W\z넊Be̸H&[$\ve St`+nrar< B*µrSMQ4Cehh}@u??Plf[o=:2w ]<*c=VKgH^|O<]uX p#!L z%I>+>XKx >*E]#P8궠-zA yE6*B  3:-R8_W zh(.hn^3ta?z]hkUg,Qվ(D^z5ר3<3;~YK\S0jkExpoCh|Mбs@,b 1 1hyM7xcw9趰+gwUu@MqW >v7JhPmq)@YE]b•7\W5.@qkgY& RvI^Gd3usz:h }5ѯ;׳@3E_-Ja$|˽."cw@qSMLRE꺑LO^:@ 5Tm1NReYUɘo!ԵJ՛ߑi2!8 ]tEK_/p|1Y 4.UVQwt`HL׈:rÓ|u@M'Us}[?fJ, =y߅g]£-ꀺνև86reVh By!uՙxXr7hYNW.bYϐaՀs0vMBr@C.N]#E\ZϽ:I/[8d2Ux4C .hy@M~[Zϫ~8D;l:G u=@"(yi]Co|Eh:uhMHLE+M XyXBqqI 8߂ S \P 5Opsu>"En`UMY^Y&WRjMӱEֹ:d"y锛^w@{վGͫUG^y[%3CPs}!m(D?~nIRO̤kEByH}*P`"v̥ ?$@LCat@ul~`LL3 8 UHXYbr<^Q\7+8yp ̀ \8 !Myu:6A-@rqA `t}r5DEy& ȁТ]yCAVU)a(G|S P為Z_%@qԎ;8&E *of"&*禙aMY P sWlO4CnqU#myi.L4U.fq@}7 QY0h>`h}@q,W3! uP.rh+/v퀺-͜(wvSye!1CI:48bTh$<)]n|B`ٿgn**/?uOY0Kr\yk(!XP9"tMv@q}}G>[5/>&P9eM</9sE?#{4 &Tw=.wԛg0?quf=!j兦P|fEPSYB&W MwuP%"k@IDATP[W ^,@ ">f*h&xC?k<CR_WGa=|Q46*'2GZĝ/Єs@Wu}Q?Ֆ[n9M 6P]Tu@PL%lUY5c0]&xt1qe*"3&~eQ4~٥>̕˭MIYHuǶXYre}ӟrqpMb-'> u '8](ZZ_Uǥ-C}(@g\p0ojh&N2Z4Ȼ^s9dq&Ps~̮6ċ+:Wg4OHVw1 |5PW|ބ_e;hGߞ GuWꍲ?!3,P7 s*1 P< Pc7TP8< /\mvc\Tp *2;s@駟?ѐcڴ*sb+T_Ī:EE0//ꀚ6 $٥z==ۆ| 4αx}  GO=Tu{E&ߑ9uyA;8!]@Ssti^3$6>>s\f&l waTTǏZ<[$LY[lu:mFb+C8Gx(+SLUhL½-]!E~z )>oCa +B}6)OZ#i M\!u܋6hYbDEЧMuXore!aJc9ƙaԙk{(d> )Z(~wt s8kλOBp@-֣MXw6".NA׆=̏ͽ-rA4]6oTgZ^.aТMubWܤ8.kl7MӟEF#-5BnbP"&?"_ s POS P=  GyDhYb Θ1y*+D< TD^[mE(TbkhjY}0#@уwfhP[)Pč7`P^, żmD{fxS"NW6IkJپ J鲔ic_!@QR*ei`_CKh]m)y.+@F@NK<7*؎+@`TBtq %yhAH49I~Jp!.js/lSL"q˾6.BD7<yb¼a6!@CИh,( 6O+5[\, q@ el~Dz.hރ+7!HO٭ޚHxCbh鬨\qq,t@E<Ъ#%y^65=iI%"Cᅿ/a7{ M P߃5OLeD&P6+BT2iL>E` Nm<0Ru@m㫁Aдwx•W^YY4>񤨊}qqp`Q'Wu@P[3ywȐH.KcBnj4-@]NOKa P䵍&x'2#`4&@t@o/ * a:]w5{eg}|4E*~UEF4784h+P}Pb*XPiֳ1A9p! Mhn{r n>;+_D)sMAlR 'uֳ ɈnB`:K}_WP>l68\8_h '|r`dE։{k(.>)ۂ)@m/-~"2[a瀂+.Sv@YU?L{hP_WKVYW ^p:oyվu F!=a'^D}7m֐i6חsɓՉ'8&G}t&D2K%@CODT;"-/OUu\l:BZe+nf-U $i,M(qشEZdy噷h#礴F}mw _w==uwsOk>O.Ⱥ p9y#刺ZhPߍ.7 m< e)^pPuw:F倚h<'(HVy[-)H_(\]M;kܭGm^Ү"Kg\:oS~ksd8v Ъ(۴mo<\4&x4Bۺd5`feBYTUDl5,s: yb|c˧K7b at:%n#T u P!VV!"f6yN W'm`?35t[Σۚr@9 p@bo. 2nÁYX2׹~}yeP]4V%"@ylBYm/YgA_J]+Ϣ be߼.Ocu]÷-߱mW<7meO47C1Wo>7-#@MJ, <Էԧ:&Eo!샐'&2 BP<5S3MIkti(J][:#z`nߛȓ~NI|7|sfvmhtE_(@#-"MWp#!m3" T?n"[81\OАxc6f5yV8/0 >zp96ybBY6~"-t. ; p!@CM`2 =k;!VI yppzсߺ?sJ>sա8 Y4ن=餓)Fa|ALj>ٟ)@9~7(\o`Twp@WOQ_CܹPE\8rӘw#ou{{C݆rM*YEgѴoClO~N`_SGqD69g=hPg?p|EM8Q{챹AGo)@#-=S@:nppc(B(Bj4UeຩʧNjk~q(n|xufYǹg;-pb|y*bSJd2"Kbz뮻N+Eﲖ@4o N|>̊N_*%5[s˶nQFZ ))mg#uچ/~Q]}ެyAE9me+{L6]s~^ jsm^u1C.@9#-#@e@|pLD$ٳggͩcv@o[!,r@mu+"@%=f=5 TG~hwW 9odئj3.@嘸m8 YiN:ETLZŠ%^|jM7U}{caDVF,aiv6cY\3,;>2R-EPɐfnTm8! u50] .P/.l'ySenĠ2LɄ Ͳ)ڔJZ&^ڐz#i ?i`s_m+?яu[Ҕ]uUՌ3 j .`|u@OOxVh@P_.Oݽmzg;0lI;*\bbsBU.%@}B8^hS}@r@Eoȷ4~ׯ!XP4Հњ"ll"ɼ9k2:uj65\߱cMym / ADL8jR "@]"Ǘܤ ̏>hu׫[otOO/X&xqqCUu@qMy q2f^ EuCZ]Ax캳V[d9*N;Y_= !)x-ά=tZ'Qz{R$ćdpbZGS,~9>HؘMƲCT 7W_}`S8P*f/=M Pkq]67yp(@#-]!T\;X' Xl'(%}|Mu)fy@@qq@m)$ ý64)_\POW^Min.XmTnٔ-TʓWr`Cj<!e08^ \0Ѯj=4 vAq맾SUy@/lc%ζ/("[8Ip3+%@HH[,(%.xp&'?IvsΕVF !ꨛ"u;!O7#m:nhe o/*|&@gE1? f6{?ߚ,F.MͣjLj7tS6 lMw!YPt̀ۖqA?ͩ,Ep5J(?[ff]l3i P߹YW~R4L+WW6p@^Iħ뽸6څ w7Wq@;iӦeΖ+Xn:pp$Isl!H뛚K'p@Q7 0qEȺzc M9Sڗ& 7Paz_h%IG9XSov0nB] MJ rH&0:C&@]7PWϦ(9AO9ܗ wީP;=]|O mNCoybV0m.c-]w@CLcpj'N^.sKs. ЈkI&E M"]v٘4qٔQ'pBҬꮻ5ۚL6)@.d%SO?6ִtJ(6%@EOLP}>P49v|P9'a|ѐuo.[s PF\pC|,(Pxꢋ.R s'{G/{]$nxmKh $Ɵ=M PpĀc=VZ?Bhjhڤ6Ų&"@uOP=B:%/=^W]$ BB\f?ЦYtǺ-h%3']6'&L{/b3Ai$M½nҒɦFK! 7 ̀pnf6ۄ6EP'ږWٸHEh}@h4uݖ0uݶnۉ*gL8?ϨO>P"PDf P߹Y=ܘ4BM/&TpA<}+}s:t9&xͿ>!(27it[Zk4'ZW6u PU43 7#/@5-@d{쑵R3м;M}GB t@t)@l:_'i4Up>33'fsI(Jh[,=MDt(:#m_ԿK?И_A+BGZCCV}@M He&>P4#?}@ L-[+k e =n_d'O</dfs~҇6x~E X9&xW߶?hhfPݥIYB w}{QǺv@2 }^H|㪇EhL(5Z 2]Awi njKk /maPG0Ntm[O v=~܃G$xA9T="Oh{͑.*guD([U9{yɡPN!}H,~E(DB,}@`$m;v L;d *$Њ0[oi;lH쇷OM39Vʟ)^iGnȏ?xZWyj{Ot!91 P4_~Ѽ~YE\Ea\A[SÌ8U! a+H_`z&i5fvw%@Q1/:H?&2E$z3p=Ȑ"  ;ΘAR&T( ]!b UТ~A`O!7</TF]@ iLPr=)@[7F`c b P` X q@}<] ~_pP;߾3&A% }v<dZx24tpVPA!wE)3m4L]ElǗmIKs90Oit7Yj(SkeT[J+e87,"@q{'8' }q@mMB'd~# ~K裏;МoyTw Bk껞NS<ڎY ~h7ːep@!dB+m{ך" 9W0 $'@ќ~>!x=\:n-{"MOC"MЛn)[ngYJTeClMx hS}@逦VSZWR^Db D{8/5ad7 I&u^&`.~=y;jl{.ou)<h.=D5^%Eu@91B}ښQk(L-J[o=u뭷I> \5KN~CR7x¨G*.dʜ `X҆'GyD-P؂-i9?s@f<؂ ~7WgunyezjSuꩧIpIeg=yt@(gSG}g>S+﮺ꪠ•%F8ZN!a޷&_Lz@?Azh` @՝E=ξ P?$n`TPSlM Pq@a0Cӳswm~G!@09F:?( Z빔7] ya#;tno P\fԝSfGs!؛:1 #x1 P+$K(@Ti#:mڴ\gh=K ̛(;d.(ѕ#S Hx:b{fx S6ǖ1$6d} >z)rl)MEJ:]і"}@~"?J " > eus P&DC E7Sn!E;oPdb }Xc o }|B1;Eu1V-!:*hy@?>Ț O4|4{#6OyC,1]D,^ }P6_3 "k ïJ6,O^s5c2ɓ',KEJ:]q Sp0,(yТSOe/AahLcI:lI6ZK%~7 ?k]Lz1<;}y]E(_0ðPK7NWyʭ-Ǎ{5@ Up6S]bGjo]E(*+BBٳgg}?)N ~̙ hC`mq?>ȩ4sRr=b sn!L! aq@ ޕ_F#,첄 2rRu@[mu(ǻMb%~Em.P  0C#N;G}4o3/I$8V?PqPMZ(=t@aK I !8xFE.r_JO/tuYmռpeyqϚ /2:%*8zhűu4&xePx&xW;E03- hyt@on PL|9n"@8wo'P: @ HE:~eZh1he!}@}(Fc^:&&k"RIe" EB7&fo-~~rhD_i4dk_|gAPh! &iӦe-'7'kZ>3FJYĬ4?lO ^E1#}p@QpD $$~6{9 бՉKHu#]耺 rӈA2TLm P(ЛAHh s? hhRMa5Qt7!-ey@s^q E-6(hHSut@u=6(2(j>O7N?YKD_! #h'yP:6*õ,?TFڤkǶE"On/'hyL+Ə Ԋ c'\1 P8U!R$@;<5eʔ tGwǞG65 OЙ3gAH^h1,YL^$q@e$|??mI"PP"- HՋИOԌXT (@KAN$@)#B@wA~m%.O8o:L<1@Bufut9R7 ~orM*'xe&P2it7h*H(@`t@QM]2h_l84(x.&hhy|t@y ҅}@$@Mm*,Mhitoy"tCPMu8liL@(@,&Zn!}9]. $ +igP_M: *Jo&]|$^ +Љ*4vt 6P 3}1ˀ)ha܁H h (nq@GFFٳKO5Njy&E]:'Nl"ĹN;) 4bҳ>۫7!I!&f2֒e{I=M]Z!*W_}5xp @Uq JZ;d"h(E1W^}<hKy"8PQL?ʷ o(2mKh< "@yH -;4Ihtӈ[(OԇGW~p@C((*$@*t@h'$A}<}s!P!!HHNud\ ͟}@+L68}/RJĄ@(@-L,w=:fEO_z4S(q @eqm m2 @#AkFÄ@:(@)H)С(fo&Ev1(щI:(h $:@$P' :i2VF|h[ 5 t֬YM( O+f#@] wwKbuT* dE JHj!@Z FFR:uL;.Ͻ,.iC>(qyb* (N83 : M(.`Z|k>h(xd$h3DP~A It @1?$lOvh2:E?qPLU t@]<. (@TFU%^L7|}@[llWl: 2(@P>ڤ"*#N<WP$' @]###Nx "@4j*"@jC}/դIr47 (A IzgUW]5{con1YA4f9MhV @ΚA^A"$!Uy +2򗿜xR'|ZsJDž[ k];x2(~lgM @r r)jvR]vYS;igU耶;֣A C׽ty̋/8)2<6 @zO>@:F{95aۧWLqF@޺oZT(BWtH[M1n…$@ $O]}co~S}W}7f=C7dtl>Ԏ @s@1Tp;?ϩS<32[e]VmB~i֬Yq(W0p˟'/~~aӤ7+~G?Q)+Bncr#cdh/ڼ3$@$g PQGWƔ /}zKnWb)HH%Z/%:]IHHy3 `Ђ9 $F7FW^9"`rMt@M"M$@$@"(xƏMd.M̘b  (B7hLs۸ |:  J*A_;:#e$@$@$ Ш:$@$@$o.$sy@,6&HH PmiHH!@ wC}@=pHHz@ط,Q -P߲ !@j8||tE @-(@kH$hT C4`JA( h7Mؘh  &@Eh[y  h7yTq@^xaV\E$@$@$* TK,2k$@$@$0(@3fP-z_]~o<`>vAyjߘ[J7:S_q>v]<>  !+pfHHH&@u $@$@$@$0d(@]   h% gvIHHHk]O$@$@$@CFt %   p"JoA={6߄C P;7H壯&xK|'դIMoBYf'ƛRFTFI$@$@$@$&&x7!   hhP%  א 4@HHHHM͆kHHHH @TFI$@$@$@$&@f5$@$@$@$@ m*$   pu    P6Q P4g܄ru˧;yw9}6'|gϞz-"o7HWRX0w}:K/;ţP:juU /Zfe~fΜoX^8:quש_]ԑGV_}{o5k֬m>죖]vY5qD/Y=3;묳6l[l1&kv`=4C倲Y|ջ.۫?309v}wu衇9VHY>4GU3@9O|b䮻93G\G?C.bX#tȜȩz7oftb|WGV]uլсDva#ȕW^9u'O2eȜvQ/7xcdW#*G~ߍ{#sFxt~>~h丞Ẇn;hrw#K-{R} ~F.8c=K/ne)>Y^h:2]Sw?s\O5a'Y9GI&9bHg}v]e6R5~"{wLG<ݴ۷o+: ioh In? ߾999פs2;waJ}ƍxʍ6hiiǏP$Slt_n[7}Δ^#F}Č@mk[v{nsWr}Ih$z˶ֶ]t\vM.ն@tEOVڀ?NHm=?}dx2e U+WJIIIɧnx /.:K***l[6MH5zK733[M/{i)=V^ysƌaXwЦDteކK߿oqx4'Q OoC c?4"Ǯ^;wGmYZZjG%LO\ gYKuz444e˖^-ۿ;zՇid&V6Eˁ:hz ^\tŠ^tK^ݓ &E;LE?ǥb~̕Ǵpm|n:R8OBrv̙̕3vz 7īG:{㳺;d;˗/ VIn¤]uyL-ƍΧNIvlAgϞϛۿv#Go߾MߎnKq3,+G Ɏj(|1} 1ooA1W滗ɧi.nĺ(=տcC?iX&w#EkG:iymכf4X>WZܪ^^7J.p줊XDs4%# R,N@@H@d@@ $ ;F@  Ξ@@X 2T@N48{JF@b)@˰Si@@ 8)@ h,N@@H@d@@ $ ;F@  Ξ@@X 2T@N48{JF@b)@˰Si@@ 8)@ h,N@@H@d@@ $ ;F@  Ξ@@X 2T@N48{JF@b)@˰Si@@ 8)@ h,N@@H@d[$##?ۚ=Z?ZS@k@ gϖK.yuuuАlر21c.3 @\23ŵH}©5ݲl$-(E @/^,555v=z$,2f)))ijjEINNl߾]>|T .Ȝ9sdԨQ2|{5i !  y=gϤV۷oY|,X@+5kdݺu2o<ѫ/^*ĉe6mJaaJ}}3 @h Y߿dRO:;;m'cǎݻVy=zTСCR^^.իWK{{ٳG֮]k vаGCH y9s_b,77W޼yc?}TYÇ:SL+W6;;[  VаFBX?ޫ?i-|EE,qF&0a  kd/@bWNQ:) 04>"F`v{ݞ8slǥ?~ !&v4i_v@:yQuٵk?|p@!!@:$N"Ο?ojnݺU6l *P$S>~('N^b hC" |Im@@ >D   -hœ    }A@@ Z$ъ'A@B/@  @H@Oj ^4!b@@h F+@ hC"  V<   zЇD@%@xR@@ $; DK4Z6  @H@C"v@ hIm@@ >D   -hœ    }A@@ Z$ъ'A@B/@  @tIENDB`magrittr/man/aliases.Rd0000644000176200001440000000511613701613606014574 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/aliases.R \name{extract} \alias{extract} \alias{extract2} \alias{use_series} \alias{add} \alias{subtract} \alias{multiply_by} \alias{multiply_by_matrix} \alias{divide_by} \alias{divide_by_int} \alias{raise_to_power} \alias{and} \alias{or} \alias{mod} \alias{is_in} \alias{equals} \alias{is_greater_than} \alias{is_weakly_greater_than} \alias{is_less_than} \alias{is_weakly_less_than} \alias{not} \alias{n'est pas} \alias{set_colnames} \alias{set_rownames} \alias{set_names} \alias{set_class} \alias{inset} \alias{inset2} \alias{set_attr} \alias{set_attributes} \title{Aliases} \description{ magrittr provides a series of aliases which can be more pleasant to use when composing chains using the \code{\%>\%} operator. } \details{ Currently implemented aliases are \tabular{ll}{ \code{extract} \tab \code{`[`} \cr \code{extract2} \tab \code{`[[`} \cr \code{inset} \tab \code{`[<-`} \cr \code{inset2} \tab \code{`[[<-`} \cr \code{use_series} \tab \code{`$`} \cr \code{add} \tab \code{`+`} \cr \code{subtract} \tab \code{`-`} \cr \code{multiply_by} \tab \code{`*`} \cr \code{raise_to_power} \tab \code{`^`} \cr \code{multiply_by_matrix} \tab \code{`\%*\%`} \cr \code{divide_by} \tab \code{`/`} \cr \code{divide_by_int} \tab \code{`\%/\%`} \cr \code{mod} \tab \code{`\%\%`} \cr \code{is_in} \tab \code{`\%in\%`} \cr \code{and} \tab \code{`&`} \cr \code{or} \tab \code{`|`} \cr \code{equals} \tab \code{`==`} \cr \code{is_greater_than} \tab \code{`>`} \cr \code{is_weakly_greater_than} \tab \code{`>=`} \cr \code{is_less_than} \tab \code{`<`} \cr \code{is_weakly_less_than} \tab \code{`<=`} \cr \code{not} (\code{`n'est pas`}) \tab \code{`!`} \cr \code{set_colnames} \tab \code{`colnames<-`} \cr \code{set_rownames} \tab \code{`rownames<-`} \cr \code{set_names} \tab \code{`names<-`} \cr \code{set_class} \tab \code{`class<-`} \cr \code{set_attributes} \tab \code{`attributes<-`} \cr \code{set_attr } \tab \code{`attr<-`} \cr } } \examples{ iris \%>\% extract(, 1:4) \%>\% head good.times <- Sys.Date() \%>\% as.POSIXct \%>\% seq(by = "15 mins", length.out = 100) \%>\% data.frame(timestamp = .) good.times$quarter <- good.times \%>\% use_series(timestamp) \%>\% format("\%M") \%>\% as.numeric \%>\% divide_by_int(15) \%>\% add(1) } magrittr/man/pipe.Rd0000644000176200001440000001175214174202267014115 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/pipe.R \name{\%>\%} \alias{\%>\%} \title{Pipe} \usage{ lhs \%>\% rhs } \arguments{ \item{lhs}{A value or the magrittr placeholder.} \item{rhs}{A function call using the magrittr semantics.} } \description{ Pipe an object forward into a function or call expression. } \details{ \subsection{Using \verb{\%>\%} with unary function calls}{ When functions require only one argument, \code{x \%>\% f} is equivalent to \code{f(x)} (not exactly equivalent; see technical note below.) } \subsection{Placing \code{lhs} as the first argument in \code{rhs} call}{ The default behavior of \verb{\%>\%} when multiple arguments are required in the \code{rhs} call, is to place \code{lhs} as the first argument, i.e. \code{x \%>\% f(y)} is equivalent to \code{f(x, y)}. } \subsection{Placing \code{lhs} elsewhere in \code{rhs} call}{ Often you will want \code{lhs} to the \code{rhs} call at another position than the first. For this purpose you can use the dot (\code{.}) as placeholder. For example, \code{y \%>\% f(x, .)} is equivalent to \code{f(x, y)} and \code{z \%>\% f(x, y, arg = .)} is equivalent to \code{f(x, y, arg = z)}. } \subsection{Using the dot for secondary purposes}{ Often, some attribute or property of \code{lhs} is desired in the \code{rhs} call in addition to the value of \code{lhs} itself, e.g. the number of rows or columns. It is perfectly valid to use the dot placeholder several times in the \code{rhs} call, but by design the behavior is slightly different when using it inside nested function calls. In particular, if the placeholder is only used in a nested function call, \code{lhs} will also be placed as the first argument! The reason for this is that in most use-cases this produces the most readable code. For example, \code{iris \%>\% subset(1:nrow(.) \%\% 2 == 0)} is equivalent to \code{iris \%>\% subset(., 1:nrow(.) \%\% 2 == 0)} but slightly more compact. It is possible to overrule this behavior by enclosing the \code{rhs} in braces. For example, \code{1:10 \%>\% {c(min(.), max(.))}} is equivalent to \code{c(min(1:10), max(1:10))}. } \subsection{Using \verb{\%>\%} with call- or function-producing \code{rhs}}{ It is possible to force evaluation of \code{rhs} before the piping of \code{lhs} takes place. This is useful when \code{rhs} produces the relevant call or function. To evaluate \code{rhs} first, enclose it in parentheses, i.e. \code{a \%>\% (function(x) x^2)}, and \code{1:10 \%>\% (call("sum"))}. Another example where this is relevant is for reference class methods which are accessed using the \code{$} operator, where one would do \code{x \%>\% (rc$f)}, and not \code{x \%>\% rc$f}. } \subsection{Using lambda expressions with \verb{\%>\%}}{ Each \code{rhs} is essentially a one-expression body of a unary function. Therefore defining lambdas in magrittr is very natural, and as the definitions of regular functions: if more than a single expression is needed one encloses the body in a pair of braces, \code{\{ rhs \}}. However, note that within braces there are no "first-argument rule": it will be exactly like writing a unary function where the argument name is "\code{.}" (the dot). } \subsection{Using the dot-place holder as \code{lhs}}{ When the dot is used as \code{lhs}, the result will be a functional sequence, i.e. a function which applies the entire chain of right-hand sides in turn to its input. See the examples. } } \section{Technical notes}{ The magrittr pipe operators use non-standard evaluation. They capture their inputs and examines them to figure out how to proceed. First a function is produced from all of the individual right-hand side expressions, and then the result is obtained by applying this function to the left-hand side. For most purposes, one can disregard the subtle aspects of magrittr's evaluation, but some functions may capture their calling environment, and thus using the operators will not be exactly equivalent to the "standard call" without pipe-operators. Another note is that special attention is advised when using non-magrittr operators in a pipe-chain (\verb{+, -, $,} etc.), as operator precedence will impact how the chain is evaluated. In general it is advised to use the aliases provided by magrittr. } \examples{ # Basic use: iris \%>\% head # Use with lhs as first argument iris \%>\% head(10) # Using the dot place-holder "Ceci n'est pas une pipe" \%>\% gsub("une", "un", .) # When dot is nested, lhs is still placed first: sample(1:10) \%>\% paste0(LETTERS[.]) # This can be avoided: rnorm(100) \%>\% {c(min(.), mean(.), max(.))} \%>\% floor # Lambda expressions: iris \%>\% { size <- sample(1:10, size = 1) rbind(head(., size), tail(., size)) } # renaming in lambdas: iris \%>\% { my_data <- . size <- sample(1:10, size = 1) rbind(head(my_data, size), tail(my_data, size)) } # Building unary functions with \%>\% trig_fest <- . \%>\% tan \%>\% cos \%>\% sin 1:10 \%>\% trig_fest trig_fest(1:10) } \seealso{ \code{\link{\%<>\%}}, \code{\link{\%T>\%}}, \code{\link{\%$\%}} } magrittr/man/debug_pipe.Rd0000644000176200001440000000060413701613606015253 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/debug_pipe.R \name{debug_pipe} \alias{debug_pipe} \title{Debugging function for magrittr pipelines.} \usage{ debug_pipe(x) } \arguments{ \item{x}{a value} } \value{ x } \description{ This function is a wrapper around \code{browser}, which makes it easier to debug at certain places in a magrittr pipe chain. } magrittr/man/faq-pipe-gender.Rd0000644000176200001440000000113413753166743016127 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/pipe.R \name{faq-pipe-gender} \alias{faq-pipe-gender} \title{FAQ: What is the gender of the pipe?} \description{ In Magritte's original quote "Ceci n'est pas une pipe," the word "pipe" is feminine. However the magrittr package quotes it as "Ceci n'est pas un pipe," with a masculine "pipe." This lighthearted misappropriation is intentional. Whereas the object represented in Magritte's painting (a pipe that you can smoke) is feminine in the French language, a computer pipe (which is an Anglicism in French) is masculine. } magrittr/man/print.fseq.Rd0000644000176200001440000000054213701613606015242 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/functions.R \name{print.fseq} \alias{print.fseq} \title{Print method for functional sequence.} \usage{ \method{print}{fseq}(x, ...) } \arguments{ \item{x}{A functional sequence object} \item{...}{not used.} } \value{ x } \description{ Print method for functional sequence. } magrittr/man/fseq.Rd0000644000176200001440000000116313701613606014107 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/getters.R \name{[[.fseq} \alias{[[.fseq} \alias{[.fseq} \title{Extract function(s) from a functional sequence.} \usage{ \method{[[}{fseq}(x, ...) \method{[}{fseq}(x, ...) } \arguments{ \item{x}{A functional sequence} \item{...}{index/indices. For double brackets, the index must be of length 1.} } \value{ A function or functional sequence. } \description{ Functional sequences can be subset using single or double brackets. A single-bracket subset results in a new functional sequence, and a double-bracket subset results in a single function. } magrittr/DESCRIPTION0000644000176200001440000000324614174264634013631 0ustar liggesusersType: Package Package: magrittr Title: A Forward-Pipe Operator for R Version: 2.0.2 Authors@R: c(person(given = "Stefan Milton", family = "Bache", role = c("aut", "cph"), email = "stefan@stefanbache.dk", comment = "Original author and creator of magrittr"), person(given = "Hadley", family = "Wickham", role = "aut", email = "hadley@rstudio.com"), person(given = "Lionel", family = "Henry", role = "cre", email = "lionel@rstudio.com"), person(given = "RStudio", role = c("cph", "fnd"))) Description: Provides a mechanism for chaining commands with a new forward-pipe operator, %>%. This operator will forward a value, or the result of an expression, into the next function call/expression. There is flexible support for the type of right-hand side expressions. For more information, see package vignette. To quote Rene Magritte, "Ceci n'est pas un pipe." License: MIT + file LICENSE URL: https://magrittr.tidyverse.org, https://github.com/tidyverse/magrittr BugReports: https://github.com/tidyverse/magrittr/issues Suggests: covr, knitr, rlang, rmarkdown, testthat VignetteBuilder: knitr ByteCompile: Yes Encoding: UTF-8 RoxygenNote: 7.1.2 Config/Needs/website: tidyverse/tidytemplate NeedsCompilation: yes Packaged: 2022-01-26 10:19:52 UTC; lionel Author: Stefan Milton Bache [aut, cph] (Original author and creator of magrittr), Hadley Wickham [aut], Lionel Henry [cre], RStudio [cph, fnd] Maintainer: Lionel Henry Repository: CRAN Date/Publication: 2022-01-26 15:32:44 UTC magrittr/build/0000755000176200001440000000000014174220110013172 5ustar liggesusersmagrittr/build/vignette.rds0000644000176200001440000000035014174220110015527 0ustar liggesusersuM0ˏ( 8!1nqᶱbΓ#($.:u^B|E@ p/9.%ZN ĄE:84B˚Lk6oqF+ŦQye껭CKg'Ȥo是&sjC982 ouliFTelGM-AeݤvYNҶs\aeYqZHziVmagrittr/tests/0000755000176200001440000000000014174220110013235 5ustar liggesusersmagrittr/tests/testthat/0000755000176200001440000000000014174264634015120 5ustar liggesusersmagrittr/tests/testthat/test-multiple-arguments.r0000644000176200001440000000245513701613614022113 0ustar liggesuserscontext("%>%: multi-argument functions on right-hand side") test_that("placement of lhs is correct in different situations", { # When not to be placed in first position and in the presence of # non-placeholder dots, e.g. in formulas. case0a <- lm(Sepal.Length ~ ., data = iris) %>% coef case1a <- iris %>% lm(Sepal.Length ~ ., .) %>% coef case2a <- iris %>% lm(Sepal.Length ~ ., data = .) %>% coef expect_that(case1a, is_equivalent_to(case0a)) expect_that(case2a, is_equivalent_to(case0a)) # In first position and used in arguments case0b <- transform(iris, Species = substring(Species, 1, 1)) case1b <- iris %>% transform(Species = Species %>% substr(1, 1)) case2b <- iris %>% transform(., Species = Species %>% substr(., 1, 1)) expect_that(case1b, is_equivalent_to(case0b)) expect_that(case2b, is_equivalent_to(case0b)) # LHS function values case0c <- aggregate(. ~ Species, iris, function(x) mean(x >= 5)) case1c <- (function(x) mean(x >= 5)) %>% aggregate(. ~ Species, iris, .) expect_that(case1c, is_equivalent_to(case0c)) # several placeholder dots expect_true(iris %>% identical(., .)) # "indirect" function expressions expect_that(1:100 %>% iris[., ], is_identical_to(iris[1:100, ])) }) magrittr/tests/testthat/test-tee.r0000644000176200001440000000050113701613614017020 0ustar liggesuserscontext("tee pipe") test_that("Tee pipe related functionality works.", { dim_message <- function(data.) message(sprintf("Data has dimension %d x %d", NROW(data.), NCOL(data.))) expect_that(iris %T>% dim_message, shows_message(dim_message(iris))) expect_that(iris %T>% dim_message, is_identical_to(iris)) }) magrittr/tests/testthat/test-freduce.R0000644000176200001440000000021613754711044017627 0ustar liggesusers test_that("freduce() supports long lists (kcf-jackson/sketch#5)", { fns <- rep(list(identity), 1000) expect_equal(freduce(1, fns), 1) }) magrittr/tests/testthat/test-aliases.R0000644000176200001440000000366613106333523017640 0ustar liggesuserscontext("magrittr aliases") test_that("the provided aliases work as intended.", { expect_that(iris %>% extract(, 1:2), is_identical_to(iris[, 1:2])) expect_that(iris %>% extract2(1), is_identical_to(iris[[1]])) expect_that(iris %>% use_series(Species), is_identical_to(iris$Species)) expect_that(1:10 %>% add(10:1), is_identical_to(1:10 + 10:1)) expect_that(1:10 %>% subtract(10:1), is_identical_to(1:10 - 10:1)) expect_that(1:10 %>% multiply_by(10:1), is_identical_to(1:10 * 10:1)) A <- matrix(1:16, 4, 4) expect_that(A %>% multiply_by_matrix(A), is_identical_to(A %*% A)) expect_that(1:10 %>% raise_to_power(10:1), is_identical_to((1:10)^(10:1))) expect_that(1:10 %>% divide_by(10:1), is_identical_to(1:10 / 10:1)) expect_that(1:10 %>% divide_by_int(10:1), is_identical_to(1:10 %/% 10:1)) expect_that(1:10 %>% mod(3), is_identical_to((1:10) %% 3)) expect_that(((1:10) > 5) %>% and((1:10) > 7), is_identical_to(((1:10) > 5) & (1:10) > 7)) expect_that(((1:10) > 5) %>% or((1:10) > 7), is_identical_to(((1:10) > 5) | (1:10) > 7)) expect_that(1:10 %>% (magrittr::equals)(5) %>% sum, is_identical_to(1L)) expect_that(1:10 %>% is_greater_than(5) %>% sum, is_identical_to(5L)) expect_that(1:10 %>% is_weakly_greater_than(5) %>% sum, is_identical_to(6L)) expect_that(1:10 %>% (magrittr::is_less_than)(5) %>% sum, is_identical_to(4L)) expect_that(1:10 %>% is_weakly_less_than(5) %>% sum, is_identical_to(5L)) expect_that(iris %>% set_colnames(LETTERS[1:ncol(iris)]), is_identical_to(`colnames<-`(iris, LETTERS[1:ncol(iris)]))) expect_that(1:10 %>% set_names(LETTERS[1:10]), is_identical_to(`names<-`(1:10, LETTERS[1:10]))) expect_that(diag(3) %>% set_rownames(c("x", "y", "z")), is_identical_to(`rownames<-`(diag(3), c("x", "y", "z")))) expect_that(1:10 %>% is_greater_than(5) %>% not, is_identical_to(1:10 %>% is_weakly_less_than(5))) }) magrittr/tests/testthat/test-pipe.R0000644000176200001440000000700414174202566017152 0ustar liggesusers test_that("exposition operator wraps `with()`", { out <- mtcars %>% identity() %$% (head(cyl) / mean(am)) expect_identical(out, head(mtcars$cyl) / mean(mtcars$am)) }) test_that("compound operator works with fancy pipes", { data <- mtcars data %<>% identity %$% (head(cyl) / mean(am)) data expect_identical(data, head(mtcars$cyl) / mean(mtcars$am)) }) test_that("eager pipe expressions are evaluated in the current environment", { rlang::local_bindings(`%>%` = pipe_eager_lexical) fn <- function(...) parent.frame() out <- NULL %>% identity() %>% fn() expect_identical(out, environment()) fn <- function() { NULL %>% identity() %>% { return(TRUE) } FALSE } expect_true(fn()) }) test_that("`.` is restored", { 1 %>% identity() expect_error(., "not found") . <- "foo" 1 %>% identity() expect_identical(., "foo") }) test_that("lazy pipe evaluates expressions lazily (#120)", { out <- stop("foo") %>% identity() %>% tryCatch(error = identity) expect_true(inherits(out, "simpleError")) ignore <- function(...) NA out <- stop("foo") %>% identity() %>% ignore() expect_identical(out, NA) out <- stop("foo") %T>% identity() %>% ignore() expect_identical(out, NA) out %<>% stop() %>% ignore() expect_identical(out, NA) }) test_that("lazy pipe evaluates `.` in correct environments", { out <- NA %>% list(.) %>% list(.) %>% list(.) expect_identical(out, list(list(list(NA)))) }) test_that("nested pipe can't use multiple placeholders", { rlang::local_bindings(`%>%` = pipe_nested) expect_error( 1 %>% list(., .), "multiple" ) }) test_that("can splice magrittr input (#191)", { out <- 1:3 %>% rlang::list2(!!!.) exp <- rlang::list2(!!!1:3) expect_identical(out, exp) }) test_that("allow trailing return for backward compatibility", { expect_error(1 %>% { return(.) }) expect_identical(1 %>% return(), 1) f <- function() 1 %>% identity() %>% return() expect_identical(f(), 1) }) test_that("visibility is forwarded", { expect_equal( withVisible(mtcars %>% { identity(.$cyl) }), list(value = mtcars$cyl, visible = TRUE) ) expect_equal( withVisible(mtcars %$% cyl), list(value = mtcars$cyl, visible = TRUE) ) expect_equal( withVisible(mtcars %T>% identity() %>% { identity(.$cyl) }), list(value = mtcars$cyl, visible = TRUE) ) expect_equal( withVisible(mtcars %>% { invisible(.$cyl) }), list(value = mtcars$cyl, visible = FALSE) ) expect_equal( withVisible(mtcars %$% invisible(cyl)), list(value = mtcars$cyl, visible = FALSE) ) expect_equal( withVisible(mtcars %T>% identity() %>% { invisible(.$cyl) }), list(value = mtcars$cyl, visible = FALSE) ) }) test_that("`%<>%` always returns invisibly", { foo <- 1 expect_equal( withVisible(foo %<>% add(1) %>% identity()), list(value = 2, visible = FALSE) ) expect_equal( withVisible(foo %<>% add(1) %>% invisible()), list(value = 3, visible = FALSE) ) }) test_that("internal parameters are not looked up beyond private envs of the pipes (#233)", { nested <- "not looked up" # Fails because of the duplicate placeholder if nested transformation is performed expect_equal(1 %>% list(., .), list(1, 1)) }) test_that("eager pipe evaluates sequentially", { local_edition(3) f <- function(x) { message("foo") x } g <- function(x) { message("bar") x } h <- function(x) { message("baz") invisible(x) } expect_snapshot({ NULL %>% f() %>% g() %>% h() NULL %!>% f() %!>% g() %!>% h() }) }) magrittr/tests/testthat/test-single-argument.r0000644000176200001440000000142613106333523021350 0ustar liggesuserscontext("%>%: one-argument function alternatives.") test_that("%>% works as expected with and without parentheses and placeholder", { expect_that(1:100 %>% sin %>% abs, is_identical_to(abs(sin(1:100)))) expect_that(1:100 %>% sin() %>% abs(), is_identical_to(abs(sin(1:100)))) expect_that(1:100 %>% sin(.) %>% abs(.), is_identical_to(abs(sin(1:100)))) expect_that(iris %>% head, is_identical_to(head(iris))) dnormsd <- function(sd) function(x) dnorm(x, sd = sd) some_x <- rnorm(20) expect_that(some_x %>% dnormsd(5)(.), is_identical_to(dnormsd(5)(some_x))) expect_that(some_x %>% (dnormsd(5)), is_identical_to(dnormsd(5)(some_x))) expect_that(some_x %>% dnormsd(5), throws_error()) expect_that(some_x %>% function(x) {x} %>% sin, throws_error()) }) magrittr/tests/testthat/_snaps/0000755000176200001440000000000014174202566016377 5ustar liggesusersmagrittr/tests/testthat/_snaps/pipe.md0000644000176200001440000000036514174202566017662 0ustar liggesusers# eager pipe evaluates sequentially Code NULL %>% f() %>% g() %>% h() Message baz bar foo Code NULL %!>% f() %!>% g() %!>% h() Message foo bar baz magrittr/tests/testthat/test-fseq.r0000644000176200001440000000030212472002651017175 0ustar liggesuserscontext("functional sequences") test_that("fseq functions work", { a <- . %>% cos %>% sin %>% tan b <- function(x) tan(sin(cos(x))) expect_that(a(1:10), is_identical_to(b(1:10))) }) magrittr/tests/testthat/test-compound.R0000644000176200001440000000116113712024462020031 0ustar liggesuserscontext("assignment pipe") test_that("Assignment pipe works", { x <- y <- 1:10 x[1:5] <- sin(cos(x[1:5])) y[1:5] %<>% cos %>% sin expect_that(x, is_identical_to(y)) somedata <- iris somedata$Sepal.Length %<>% add(10) iris$Sepal.Length <- iris$Sepal.Length + 10 expect_that(somedata, is_identical_to(iris)) z <- 1:10 z %<>% add(2) %T>% plot expect_that(z, is_identical_to(as.numeric(3:12))) }) test_that("can't assign to non-assignment expression", { msg <- conditionMessage(tryCatch(error = identity, identity(1) <- NULL)) expect_error( 1 %>% identity() %<>% identity(), msg ) }) magrittr/tests/testthat/test-anonymous-functions.r0000644000176200001440000000330513701624704022310 0ustar liggesuserscontext("%>%: anonymous functions on right-hand side") test_that("%>% handles anonymous functions in GlobalEnv", { # Simple vectorized function a <- (function(x) 1 + x^2/2 + x^3/9 + x^4/16)(1:100) b <- 1:100 %>% (function(x) 1 + x^2/2 + x^3/9 + x^4/16) # in principle, the dot should also work: c <- 1:100 %>% (function(x) 1 + x^2/2 + x^3/9 + x^4/16)(.) expect_that(a, is_identical_to(b)) expect_that(a, is_identical_to(c)) # Same using preferred magrittr syntax a <- (function(x) 1 + x^2/2 + x^3/9 + x^4/16)(1:100) b <- 1:100 %>% {1 + .^2/2 + .^3/9 + .^4/16} expect_that(a, is_identical_to(b)) # Simple data.frame functions ht1 <- iris %>% (function(x) rbind(head(x), tail(x))) ht2 <- rbind(head(iris), tail(iris)) expect_that(ht1, is_identical_to(ht2)) df1 <- iris[iris$Species == "setosa", 1:4] df2 <- iris %>% (function(x) x[x$Species == "setosa", 1:4]) expect_that(df1, is_identical_to(df2)) }) test_that("%>% handles anonymous functions in other situations.", { # Anonymous functions when %>% used in arguments. df1 <- transform(iris, test = (function(x) x^2)(Sepal.Length)) df2 <- iris %>% transform(test = Sepal.Length %>% (function(x) x^2)) expect_that(df1, is_identical_to(df2)) a <- sin(abs(1:10)) b <- sin(1:10 %>% (function(x) abs(x))) expect_that(a, is_identical_to(b)) # Nested anonymous functions. a <- iris %>% (function(x) x[, 1] %>% (function(y) max(y))) b <- max(iris[, 1]) expect_that(a, is_identical_to(b)) }) test_that("%>% throws error with anonymous functions when not parenthesized.", { expect_that(iris %>% function(x) { head(x) }, throws_error()) }) magrittr/tests/testthat.R0000644000176200001440000000007413701613614015233 0ustar liggesuserslibrary(testthat) library(magrittr) test_check("magrittr") magrittr/src/0000755000176200001440000000000014174220110012662 5ustar liggesusersmagrittr/src/utils.c0000644000176200001440000000574413754514563014225 0ustar liggesusers#define R_NO_REMAP #include SEXP syms_delayed_assign = NULL; void r_env_bind_lazy(SEXP env, SEXP sym, SEXP expr, SEXP eval_env) { SEXP prom = PROTECT(Rf_allocSExp(PROMSXP)); SET_PRENV(prom, eval_env); SET_PRCODE(prom, expr); SET_PRVALUE(prom, R_UnboundValue); Rf_defineVar(sym, prom, env); UNPROTECT(1); return; SEXP call = PROTECT(Rf_lang5(syms_delayed_assign, sym, expr, eval_env, env)); Rf_eval(call, R_BaseEnv); UNPROTECT(1); } // For `R_removeVarFromFrame()` compatibility SEXP syms_envir = NULL; SEXP syms_inherits = NULL; SEXP syms_list = NULL; SEXP syms_rm = NULL; #include #if (R_VERSION < R_Version(4, 0, 0)) void r__env_unbind(SEXP env, SEXP sym) { // Check if binding exists to avoid `rm()` warning if (Rf_findVar(sym, env) != R_UnboundValue) { SEXP nm = PROTECT(Rf_allocVector(STRSXP, 1)); SET_STRING_ELT(nm, 0, PRINTNAME(sym)); // remove(list = y, envir = x, inherits = z) SEXP args = Rf_cons(Rf_ScalarLogical(0), R_NilValue); SET_TAG(args, syms_inherits); args = Rf_cons(env, args); SET_TAG(args, syms_envir); args = Rf_cons(nm, args); SET_TAG(args, syms_list); SEXP call = Rf_lcons(syms_rm, args); PROTECT(call); Rf_eval(call, R_BaseEnv); UNPROTECT(2); } } #endif #include static void abort_parse(SEXP code, const char* why) { if (Rf_GetOption1(Rf_install("rlang__verbose_errors")) != R_NilValue) { Rf_PrintValue(code); } Rf_error("Internal error in `r_parse()`: %s", why); } SEXP r_parse(const char* str) { SEXP str_ = PROTECT(Rf_mkString(str)); ParseStatus status; SEXP out = PROTECT(R_ParseVector(str_, -1, &status, R_NilValue)); if (status != PARSE_OK) { abort_parse(str_, "Parsing failed."); } if (Rf_length(out) != 1) { abort_parse(str_, "Expected a single expression."); } out = VECTOR_ELT(out, 0); UNPROTECT(2); return out; } SEXP r_parse_eval(const char* str, SEXP env) { SEXP out = Rf_eval(PROTECT(r_parse(str)), env); UNPROTECT(1); return out; } static SEXP new_env_call = NULL; static SEXP new_env__parent_node = NULL; static SEXP new_env__size_node = NULL; #if 0 SEXP r_new_environment(SEXP parent, R_len_t size) { parent = parent ? parent : R_EmptyEnv; SETCAR(new_env__parent_node, parent); size = size ? size : 29; SETCAR(new_env__size_node, Rf_ScalarInteger(size)); SEXP env = Rf_eval(new_env_call, R_BaseEnv); // Free for gc SETCAR(new_env__parent_node, R_NilValue); return env; } #endif void magrittr_init_utils(SEXP ns) { syms_delayed_assign = Rf_install("delayedAssign"); syms_envir = Rf_install("envir"); syms_inherits = Rf_install("inherits"); syms_list = Rf_install("list"); syms_rm = Rf_install("rm"); new_env_call = r_parse_eval("as.call(list(new.env, TRUE, NULL, NULL))", R_BaseEnv); R_PreserveObject(new_env_call); new_env__parent_node = CDDR(new_env_call); new_env__size_node = CDR(new_env__parent_node); } magrittr/src/utils.h0000644000176200001440000000171713754517471014227 0ustar liggesusers#ifndef MAGRITTR_UTILS_H #define MAGRITTR_UTILS_H #include void r_env_bind_lazy(SEXP env, SEXP sym, SEXP expr, SEXP eval_env); static inline void r_env_unbind(SEXP env, SEXP sym) { #if (R_VERSION < R_Version(4, 0, 0)) void r__env_unbind(SEXP, SEXP); r__env_unbind(env, sym); #else R_removeVarFromFrame(sym, env); #endif } SEXP r_parse(const char* str); SEXP r_parse_eval(const char* str, SEXP env); static inline SEXP r_new_environment(SEXP parent) { SEXP env = Rf_allocSExp(ENVSXP); SET_ENCLOS(env, parent); return env; } static inline SEXP r_env_get(SEXP env, SEXP sym) { SEXP obj = PROTECT(Rf_findVarInFrame3(env, sym, FALSE)); // Force lazy loaded bindings if (TYPEOF(obj) == PROMSXP) { obj = Rf_eval(obj, R_BaseEnv); } UNPROTECT(1); return obj; } #if defined(RLIB_DEBUG) SEXP R_inspect(SEXP x); SEXP R_inspect3(SEXP x, int deep, int pvec); #endif #endif magrittr/src/pipe.c0000644000176200001440000002507314066305611014004 0ustar liggesusers#include #define R_NO_REMAP #include #include #include #include "utils.h" #define export attribute_visible extern enum pipe_kind { PIPE_KIND_none = 0, PIPE_KIND_magrittr, PIPE_KIND_compound, PIPE_KIND_tee, PIPE_KIND_dollar }; // Helper structures for unwind-protection of `.` restoration struct pipe_info { SEXP exprs; SEXP env; }; struct cleanup_info { SEXP old; SEXP env; }; // Initialised at load time static SEXP magrittr_ns_env = NULL; static SEXP syms_lhs = NULL; static SEXP syms_rhs = NULL; static SEXP syms_kind = NULL; static SEXP syms_env = NULL; static SEXP syms_lazy = NULL; static SEXP syms_assign = NULL; static SEXP syms_bang = NULL; static SEXP syms_curly = NULL; static SEXP syms_dot = NULL; static SEXP syms_nested = NULL; static SEXP syms_new_lambda = NULL; static SEXP syms_paren = NULL; static SEXP syms_pipe = NULL; static SEXP syms_pipe_compound = NULL; static SEXP syms_pipe_dollar = NULL; static SEXP syms_pipe_tee = NULL; static SEXP syms_return = NULL; static SEXP syms_sym = NULL; static SEXP calls_base_with = NULL; static SEXP chrs_dot = NULL; static void clean_pipe(void* data); static SEXP eval_pipe(void* data); static SEXP eval_pipe_lazy(SEXP exprs, SEXP env); static SEXP pipe_unroll(SEXP lhs, SEXP rhs, SEXP env, enum pipe_kind kind, SEXP pipe_sym, SEXP* p_assign); static SEXP pipe_nest(SEXP exprs); static SEXP as_pipe_call(SEXP x); static SEXP add_dot(SEXP x); static inline SEXP as_pipe_tee_call(SEXP x); static inline SEXP as_pipe_dollar_call(SEXP x); static SEXP new_lambda(SEXP exprs, SEXP env); static inline bool is_return(SEXP x); // [[ register() ]] SEXP magrittr_pipe(SEXP call, SEXP op, SEXP args, SEXP rho) { args = CDR(args); SEXP lhs = PROTECT(Rf_eval(syms_lhs, rho)); SEXP rhs = PROTECT(Rf_eval(syms_rhs, rho)); SEXP kind = PROTECT(Rf_eval(syms_kind, rho)); SEXP env = PROTECT(Rf_eval(syms_env, rho)); SEXP pipe_sym = r_env_get(rho, syms_sym); if (pipe_sym == R_UnboundValue) { pipe_sym = syms_pipe; } PROTECT(pipe_sym); enum pipe_kind c_kind = INTEGER(kind)[0]; SEXP assign = R_NilValue; SEXP exprs = PROTECT(pipe_unroll(lhs, rhs, env, c_kind, pipe_sym, &assign)); // Create a magrittr lambda when first expression is a `.` if (CAR(exprs) == syms_dot) { SEXP lambda = new_lambda(CDR(exprs), env); UNPROTECT(6); return lambda; } bool use_nested = r_env_get(rho, syms_nested) != R_UnboundValue; if (use_nested) { SEXP call = PROTECT(pipe_nest(exprs)); SEXP out = Rf_eval(call, env); UNPROTECT(7); return out; } bool use_lazy = r_env_get(rho, syms_lazy) != R_UnboundValue; SEXP out = R_NilValue; if (use_lazy) { out = eval_pipe_lazy(exprs, env); } else { SEXP old = PROTECT(r_env_get(env, syms_dot)); struct pipe_info pipe_info = { .exprs = exprs, .env = env }; struct cleanup_info cleanup_info = { .old = old, .env = env }; out = R_ExecWithCleanup(eval_pipe, &pipe_info, &clean_pipe, &cleanup_info); UNPROTECT(1); } if (assign != R_NilValue) { PROTECT(out); SEXP call = PROTECT(Rf_lang3(syms_assign, assign, out)); Rf_eval(call, env); UNPROTECT(2); } UNPROTECT(6); return out; } static SEXP eval_pipe(void* data) { struct pipe_info* info = (struct pipe_info*) data; SEXP exprs = info->exprs; SEXP env = info->env; SEXP out = R_NilValue; while (exprs != R_NilValue) { out = PROTECT(Rf_eval(CAR(exprs), env)); Rf_defineVar(syms_dot, out, env); UNPROTECT(1); exprs = CDR(exprs); } return out; } static SEXP eval_pipe_lazy(SEXP exprs, SEXP env) { SEXP prev_mask = env; PROTECT_INDEX mask_pi; PROTECT_WITH_INDEX(R_NilValue, &mask_pi); SEXP rest = exprs; while ((rest = CDR(exprs)) != R_NilValue) { SEXP mask = r_new_environment(env); REPROTECT(mask, mask_pi); // Lazily bind current pipe expression to `.` in the new // mask. Evaluation occurs in the previous mask environment. // The promise is protected by `mask` and protects `prev_mask`. r_env_bind_lazy(mask, syms_dot, CAR(exprs), prev_mask); exprs = rest; prev_mask = mask; } // For compatibility, allow last expression to be `return()`. // Substitute it with `.` to avoid an error. SEXP last = CAR(exprs); if (is_return(last)) { last = syms_dot; } // Evaluate last expression in the very last mask. This triggers a // recursive evaluation of `.` bindings in the different masks. SEXP out = Rf_eval(last, prev_mask); UNPROTECT(1); return out; } static inline bool is_return(SEXP x) { return TYPEOF(x) == LANGSXP && CAR(x) == syms_return; } static void clean_pipe(void* data) { struct cleanup_info* info = (struct cleanup_info*) data; if (info->old == R_UnboundValue) { r_env_unbind(info->env, syms_dot); } else { Rf_defineVar(syms_dot, info->old, info->env); } } static enum pipe_kind parse_pipe_call(SEXP x, SEXP pipe_sym); static SEXP pipe_unroll(SEXP lhs, SEXP rhs, SEXP env, enum pipe_kind kind, SEXP pipe_sym, SEXP* p_assign) { PROTECT_INDEX out_pi; SEXP out = R_NilValue; PROTECT_WITH_INDEX(out, &out_pi); PROTECT_INDEX rhs_pi; PROTECT_WITH_INDEX(rhs, &rhs_pi); while (true) { if (kind != PIPE_KIND_dollar && TYPEOF(rhs) == LANGSXP && CAR(rhs) == syms_paren) { rhs = Rf_eval(rhs, env); REPROTECT(rhs, rhs_pi); } switch (kind) { case PIPE_KIND_compound: { // Technically we want to give `%<>%` the same precedence as `<-`. // In practice, since we only support one top-level `%<>%, we // can just interpret it as `%>%` and communicate the assignment // variable via `p_assign`. *p_assign = lhs; rhs = as_pipe_call(rhs); break; } case PIPE_KIND_magrittr: rhs = as_pipe_call(rhs); break; case PIPE_KIND_tee: rhs = as_pipe_tee_call(rhs); break; case PIPE_KIND_dollar: rhs = as_pipe_dollar_call(rhs); break; case PIPE_KIND_none: Rf_error("Internal error in `pipe_unroll()`: Unexpected state."); } out = Rf_cons(rhs, out); REPROTECT(out, out_pi); if ((kind = parse_pipe_call(lhs, pipe_sym))) { if (TYPEOF(lhs) != LANGSXP) { Rf_error("Internal error in `pipe_unroll()`: Expected LHS call."); } SEXP args = CDR(lhs); lhs = CAR(args); rhs = CADR(args); continue; } break; } out = Rf_cons(lhs, out); UNPROTECT(2); return out; } static enum pipe_kind parse_pipe_call(SEXP x, SEXP pipe_sym) { if (TYPEOF(x) != LANGSXP) { return PIPE_KIND_none; } SEXP car = CAR(x); if (car == pipe_sym) { return PIPE_KIND_magrittr; } if (car == syms_pipe_compound) { return PIPE_KIND_compound; } if (car == syms_pipe_tee) { return PIPE_KIND_tee; } if (car == syms_pipe_dollar) { return PIPE_KIND_dollar; } return PIPE_KIND_none; } static SEXP as_pipe_call(SEXP x) { // Transform `foo` into `foo()` if (TYPEOF(x) != LANGSXP) { x = Rf_lcons(x, R_NilValue); } PROTECT(x); // Transform `foo()` into `foo(.)` x = add_dot(x); UNPROTECT(1); return x; } static inline SEXP as_pipe_dollar_call(SEXP x) { return Rf_lang3(calls_base_with, syms_dot, x); } static inline SEXP as_pipe_tee_call(SEXP x) { x = PROTECT(as_pipe_call(x)); SEXP out = Rf_lang3(syms_curly, x, syms_dot); UNPROTECT(1); return out; } static inline bool is_bang(SEXP x) { return TYPEOF(x) == LANGSXP && CAR(x) == syms_bang; } static bool is_spliced_dot(SEXP x) { if (!is_bang(x)) { return false; } x = CADR(x); if (!is_bang(x)) { return false; } x = CADR(x); if (!is_bang(x)) { return false; } return CADR(x) == syms_dot; } static SEXP add_dot(SEXP x) { if (TYPEOF(x) != LANGSXP) { return x; } SEXP args = CDR(x); while (args != R_NilValue) { SEXP arg = CAR(args); if (arg == syms_dot || is_spliced_dot(arg)) { return x; } args = CDR(args); } return Rf_lcons(CAR(x), Rf_cons(syms_dot, CDR(x))); } static SEXP pipe_nest(SEXP exprs) { SEXP expr = CAR(exprs); SEXP prev = expr; exprs = CDR(exprs); PROTECT_INDEX expr_pi; PROTECT_WITH_INDEX(expr, &expr_pi); while (exprs != R_NilValue) { expr = Rf_shallow_duplicate(CAR(exprs)); REPROTECT(expr, expr_pi); bool found_placeholder = false; SEXP curr = CDR(expr); while (curr != R_NilValue) { if (CAR(curr) == syms_dot) { if (found_placeholder) { Rf_errorcall(R_NilValue, "Can't use multiple placeholders."); } found_placeholder = true; SETCAR(curr, prev); prev = expr; } curr = CDR(curr); } if (!found_placeholder) { Rf_error("Internal error in `pipe_nest()`: Can't find placeholder."); } exprs = CDR(exprs); } UNPROTECT(1); return expr; } static SEXP new_lambda(SEXP exprs, SEXP env) { SEXP call = PROTECT(Rf_lang3(syms_new_lambda, exprs, env)); SEXP out = Rf_eval(call, magrittr_ns_env); UNPROTECT(1); return out; } // Initialisation ---------------------------------------------------- void magrittr_init_utils(SEXP ns); SEXP magrittr_init(SEXP ns) { magrittr_ns_env = ns; magrittr_init_utils(ns); syms_lhs = Rf_install("lhs"); syms_rhs = Rf_install("rhs"); syms_kind = Rf_install("kind"); syms_env = Rf_install("env"); syms_lazy = Rf_install("lazy"); syms_assign = Rf_install("<-"); syms_bang = Rf_install("!"); syms_curly = Rf_install("{"); syms_dot = Rf_install("."); syms_nested = Rf_install("nested"); syms_new_lambda = Rf_install("new_lambda"); syms_paren = Rf_install("("); syms_pipe = Rf_install("%>%"); syms_pipe_compound = Rf_install("%<>%"); syms_pipe_dollar = Rf_install("%$%"); syms_pipe_tee = Rf_install("%T>%"); syms_return = Rf_install("return"); syms_sym = Rf_install("sym"); chrs_dot = Rf_allocVector(STRSXP, 1); R_PreserveObject(chrs_dot); SET_STRING_ELT(chrs_dot, 0, Rf_mkChar(".")); calls_base_with = Rf_lang3(Rf_install("::"), Rf_install("base"), Rf_install("with")); R_PreserveObject(calls_base_with); MARK_NOT_MUTABLE(calls_base_with); return R_NilValue; } static const R_CallMethodDef call_entries[] = { {"magrittr_init", (DL_FUNC) magrittr_init, 1}, {NULL, NULL, 0} }; static const R_ExternalMethodDef ext_entries[] = { {"magrittr_pipe", (DL_FUNC) magrittr_pipe, 0}, {NULL, NULL, 0} }; export void R_init_magrittr(DllInfo *dll) { R_registerRoutines(dll, NULL, call_entries, NULL, ext_entries); R_useDynamicSymbols(dll, FALSE); } magrittr/vignettes/0000755000176200001440000000000014174220110014103 5ustar liggesusersmagrittr/vignettes/tradeoffs.Rmd0000644000176200001440000004106513750274524016553 0ustar liggesusers--- title: "Design tradeoffs" author: - "Hadley Wickham" - "Lionel Henry" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Design tradeoffs} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>", eval = FALSE ) library(rlang) fail <- function() "\u274c" pass <- function() "\u2705" ``` There are many different ways that magrittr could implement the pipe. The goal of this document is to elucidate the variations, and the various pros and cons of each approach. This document is primarily aimed at the magrittr developers (so we don't forget about important considerations), but will be of interest to anyone who wants to understand pipes better, or to create their own pipe that makes different tradeoffs ## Code transformation There are three main options for how we might transform a pipeline in base R expressions. Here they are illustrated with `x %>% foo() %>% bar()`: - **Nested** ```{r} bar(foo(x)) ``` - **Eager (mask)**, masking environment This is essentially how `%>%` has been implemented prior to magrittr 2.0: ```{r} local({ . <- x . <- foo(.) bar(.) }) ``` - **Eager (mask-num)**: masking environment, numbered placeholder ```{r} local({ ...1 <- x ...2 <- foo(...1) bar(...2) }) ``` - **Eager (lexical)**: lexical environment This variant assigns pipe expressions to the placeholder `.` in the current environment. This assignment is temporary: once the pipe has returned, the placeholder binding is reset to its previous state. ```{r} with_dot_cleanup <- function(expr) { # Initialises `.` in the caller environment and resets it on exit. # (We use `:=` instead of `=` to avoid partial matching.) rlang::local_bindings(. := NULL, .env = parent.frame()) expr } with_dot_cleanup({ . <- x . <- foo(.) bar(.) }) ``` - **Lazy (mask)**: masking environments ```{r} mask1 <- new.env(parent = env) mask2 <- new.env(parent = env) delayedAssign(".", x, mask1) delayedAssign(".", foo(.), mask2) with(mask2, bar(.)) ``` - **Lazy (mask-num)**: masking environment, numbered placeholder ```{r} local({ delayedAssign("...1", x) delayedAssign("...2", foo(...1)) bar(...2) }) ``` - **Lazy (lexical-num)**: lexical environment, numbered placeholder ```{r} delayedAssign("...1", x) delayedAssign("...2", foo(.)) bar(...2) ``` We'll first explore the desired properties we might want a pipe to possess and then see how each of the three variants does. ## Desired properties These are the properties that we might want a pipe to possess, roughly ordered from most important to least important. * **Visibility**: the visibility of the final function in the pipe should be preserved. This is important so that pipes that end in a side-effect function (which generally returns its first argument invisibly) do not print. * **Multiple placeholders**: each component of the pipe should only be evaluated once even when there are multiple placeholders, so that `sample(10) %>% cbind(., .)` yields two columns with the same value. Relatedly, `sample(10) %T>% print() %T>% print()` must print the same values twice. * **Lazy evaluation**: steps of the pipe should only be evaluated when actually needed. This is a useful property as it means that pipes can handle code like `stop("!") %>% try()`, making pipes capable of capturing a wider range of R expressions. On the other hand, it might have surprising effects. For instance if a function that suppresses warnings is added to the end of a pipeline, the suppression takes effect for the whole pipeline. * **Persistence of piped values**: arguments are not necessarily evaluated right away by the piped function. Sometimes they are evaluated long after the pipeline has returned, for example when a function factory is piped. With persistent piped values, the constructed function can be called at any time: ```r factory <- function(x) function() x fn <- NA %>% factory() fn() #> [1] NA ``` * **Refcount neutrality**: the return value of the pipeline should have a reference count of 1 so it can be mutated in place in further manipulations. * **Eager unbinding**: pipes are often used with large data objects, so intermediate objects in the pipeline should be unbound as soon as possible so they are available for garbage collection. * **Progressive stack**: using the pipe should add as few entries to the call stack as possible, so that `traceback()` is maximally useful. * **Lexical side effects**: side effects should occur in the current lexical environment. This way, `NA %>% { foo <- . }` assigns the piped value in the current environment and `NA %>% { return(.) }` returns from the function that contains the pipeline. * **Continuous stack**: the pipe should not affect the chain of parent frames. This is important for tree representations of the call stack. It is possible to have proper visibility and a neutral impact on refcounts with all implementations by being a bit careful, so we'll only consider the other properties: | | Nested | Eager
(mask) | Eager
(mask-num) | Eager
(lexical) | Lazy
(mask) | Lazy
(mask-num) | Lazy
(lexical-num) | |-----------------------|:----------:|:---------------:|:-------------------:|:------------------:|:--------------:|:------------------:|:---------------------:| | Multiple placeholders | `r fail()` | `r pass()` | `r pass()` | `r pass()` | `r pass()` | `r pass()` | `r pass()` | | Lazy evaluation | `r pass()` | `r fail()` | `r fail()` | `r fail()` | `r pass()` | `r pass()` | `r pass()` | | Persistence | `r pass()` | `r fail()` | `r pass()` | `r fail()` | `r pass()` | `r pass()` | `r pass()` | | Eager unbinding | `r pass()` | `r pass()` | `r fail()` | `r pass()` | `r pass()` | `r fail()` | `r fail()` | | Progressive stack | `r fail()` | `r pass()` | `r pass()` | `r pass()` | `r fail()` | `r fail()` | `r fail()` | | Lexical effects | `r pass()` | `r fail()` | `r fail()` | `r pass()` | `r fail()` | `r fail()` | `r pass()` | | Continuous stack | `r pass()` | `r fail()` | `r fail()` | `r pass()` | `r fail()` | `r fail()` | `r pass()` | ### Implications of design decisions Some properties are a direct reflection of the high level design decisions. #### Placeholder binding The nested pipe does not assign piped expressions to a placeholder. All the other variants perform this assignment. This means that with a nested rewrite approach, it isn't possible to have multiple placeholders unless the piped expression is pasted multiple times. This would cause multiple evaluations with deleterious effects: ```{r} sample(10) %>% list(., .) # Becomes list(sample(10), sample(10)) ``` Assigning to the placeholder within an argument would preserve the nestedness and lazyness. However that wouldn't work properly because there's no guarantee that the first argument will be evaluated before the second argument. ```{r} sample(10) %>% foo(., .) foo(. <- sample(10), .) ``` For these reasons, the nested pipe does not support multiple placeholders. By contrast, all the other variants assign the result of pipe expressions to the placeholder. There are variations in how the placeholder binding is created (lazily or eagerly, in a mask or in the current environment, with numbered symbols or with a unique symbol) but all these variants allow multiple placeholders. #### Masking environment Because the local variants of the pipe evaluate in a mask, they do not have lexical effects or a continuous stack. This is unlike the lexical variants that evaluate in the current environment. #### Laziness Unlike the lazy variants, all eager versions implementing the pipe with iterated evaluation do not pass the lazy evaluation criterion. Secondly, no lazy variant passes the progressive stack criterion. By construction, lazy evaluation requires pushing all the pipe expressions on the stack before evaluation starts. Conversely, all eager variants have a progressive stack. #### Numbered placeholders None of the variants that use numbered placeholders can unbind piped values eagerly. This is how they achieve persistence of these bindings. ## Three implementations The GNU R team is considering implementing the nested approach in base R with a parse-time code transformation (just like `->` is transformed to `<-` by the parser). We have implemented three approaches in magrittr: - The nested pipe - The eager lexical pipe - The lazy masking pipe These approaches have complementary strengths and weaknesses. ### Nested pipe ```{r, eval = TRUE} `%|>%` <- magrittr::pipe_nested ``` #### Multiple placeholders `r fail()` The nested pipe does not bind expressions to a placeholder and so can't support multiple placeholders. ```{r, eval = TRUE, error = TRUE} "foo" %|>% list(., .) ``` #### Lazy evaluation `r pass()` Because it relies on the usual rules of argument application, the nested pipe is lazy. ```{r, eval = TRUE} { stop("oh no") %|>% try(silent = TRUE) "success" } ``` #### Persistence and eager unbinding `r pass()` The pipe expressions are binded as promises within the execution environment of each function. This environment persists as long as a promise holds onto it. Evaluating the promise discards the reference to the environment which becomes available for garbage collection. For instance, here is a function factory that creates a function. The constructed function returns the value supplied at the time of creation: ```{r, eval = TRUE} factory <- function(x) function() x fn <- factory(TRUE) fn() ``` This does not cause any issue with the nested pipe: ```{r} fn <- TRUE %|>% factory() fn() ``` #### Progressive stack `r fail()` Because the piped expressions are lazily evaluated, the whole pipeline is pushed on the stack before execution starts. This results in a more complex backtrace than necessary: ```{r} faulty <- function() stop("tilt") f <- function(x) x + 1 g <- function(x) x + 2 h <- function(x) x + 3 faulty() %|>% f() %|>% g() %|>% h() #> Error in faulty() : tilt traceback() #> 7: stop("tilt") #> 6: faulty() #> 5: f(faulty()) #> 4: g(f(faulty())) #> 3: h(g(f(faulty()))) #> 2: .External2(magrittr_pipe) at pipe.R#181 #> 1: faulty() %|>% f() %|>% g() %|>% h() ``` Also note how the expressions in the backtrace look different from the actual code. This is because of the nested rewrite of the pipeline. #### Lexical effects `r pass()` This is a benefit of using the normal R rules of evaluation. Side effects occur in the correct environment: ```{r, eval = TRUE} foo <- FALSE TRUE %|>% assign("foo", .) foo ``` Control flow has the correct behaviour: ```{r, eval = TRUE} fn <- function() { TRUE %|>% return() FALSE } fn() ``` #### Continuous stack `r pass()` Because evaluation occurs in the current environment, the stack is continuous. Let's instrument errors with a structured backtrace to see what that means: ```{r} options(error = rlang::entrace) ``` The tree representation of the backtrace correctly represents the hierarchy of execution frames: ```{r} foobar <- function(x) x %|>% quux() quux <- function(x) x %|>% stop() "tilt" %|>% foobar() #> Error in x %|>% stop() : tilt rlang::last_trace() #> #> tilt #> Backtrace: #> █ #> 1. ├─"tilt" %|>% foobar() #> 2. └─global::foobar("tilt") #> 3. ├─x %|>% quux() #> 4. └─global::quux(x) #> 5. └─x %|>% stop() ``` ### Eager lexical pipe ```{r, eval = TRUE} `%!>%` <- magrittr::pipe_eager_lexical ``` #### Multiple placeholders `r pass()` Pipe expressions are eagerly assigned to the placeholder. This makes it possible to use the placeholder multiple times without causing multiple evaluations. ```{r, eval = TRUE} "foo" %!>% list(., .) ``` #### Lazy evaluation `r fail()` Assignment forces eager evaluation of each step. ```{r, eval = TRUE, error = TRUE} { stop("oh no") %!>% try(silent = TRUE) "success" } ``` #### Persistence: `r fail()` Because we're updating the value of `.` at each step, the piped expressions are not persistent. This has subtle effects when the piped expressions are not evaluated right away. With the eager pipe we get rather confusing results with the factory function if we try to call the constructed function in the middle of the pipeline. In the following snippet the placeholder `.` is binded to the constructed function itself rather than the initial value `TRUE`, by the time the function is called: ```{r, eval = TRUE} fn <- TRUE %!>% factory() %!>% { .() } fn() ``` Also, since we're binding `.` in the current environment, we need to clean it up once the pipeline has returned. At that point, the placeholder no longer exists: ```{r, eval = TRUE, error = TRUE} fn <- TRUE %!>% factory() fn() ``` Or it has been reset to its previous value, if any: ```{r, eval = TRUE} . <- "wrong" fn <- TRUE %!>% factory() fn() ``` #### Eager unbinding: `r pass()` This is the flip side of updating the value of the placeholder at each step. The previous intermediary values can be collected right away. #### Progressive stack: `r pass()` Since pipe expressions are evaluated one by one as they come, only the relevant part of the pipeline is on the stack when an error is thrown: ```{r} faulty <- function() stop("tilt") f <- function(x) x + 1 g <- function(x) x + 2 h <- function(x) x + 3 faulty() %!>% f() %!>% g() %!>% h() #> Error in faulty() : tilt traceback() #> 4: stop("tilt") #> 3: faulty() #> 2: .External2(magrittr_pipe) at pipe.R#163 #> 1: faulty() %!>% f() %!>% g() %!>% h() ``` #### Lexical effects and continuous stack: `r pass()` Evaluating in the current environment rather than in a mask produces the correct side effects: ```{r, eval = TRUE} foo <- FALSE NA %!>% { foo <- TRUE; . } foo ``` ```{r, eval = TRUE} fn <- function() { TRUE %!>% return() FALSE } fn() ``` ### Lazy masking pipe ```{r, eval = TRUE} `%?>%` <- magrittr::pipe_lazy_masking ``` #### Multiple placeholders `r pass()` Pipe expressions are lazily assigned to the placeholder. This makes it possible to use the placeholder multiple times without causing multiple evaluations. ```{r, eval = TRUE} "foo" %?>% list(., .) ``` #### Lazy evaluation `r pass()` Arguments are assigned with `delayedAssign()` and lazily evaluated: ```{r, eval = TRUE} { stop("oh no") %?>% try(silent = TRUE) "success" } ``` #### Persistence: `r pass()` The lazy masking pipe uses one masking environment per pipe expression. This allows persistence of the intermediary values and out of order evaluation. The factory function works as expected for instance: ```{r, eval = TRUE} fn <- TRUE %?>% factory() fn() ``` #### Eager unbinding: `r pass()` Because we use one mask environment per pipe expression, the intermediary values can be collected as soon as they are no longer needed. #### Progressive stack: `r fail()` With a lazy pipe the whole pipeline is pushed onto the stack before evaluation. ```{r} faulty <- function() stop("tilt") f <- function(x) x + 1 g <- function(x) x + 2 h <- function(x) x + 3 faulty() %?>% f() %?>% g() %?>% h() #> Error in faulty() : tilt traceback() #> 7: stop("tilt") #> 6: faulty() #> 5: f(.) #> 4: g(.) #> 3: h(.) #> 2: .External2(magrittr_pipe) at pipe.R#174 #> 1: faulty() %?>% f() %?>% g() %?>% h() ``` Note however how the backtrace is less cluttered than with the nested pipe approach, thanks to the placeholder. #### Lexical effects `r fail()` The lazy pipe evaluates in a mask. This causes lexical side effects to occur in the incorrect environment. ```{r, eval = TRUE} foo <- FALSE TRUE %?>% assign("foo", .) foo ``` Stack-sensitive functions like `return()` function cannot find the proper frame environment: ```{r, eval = TRUE, error = TRUE} fn <- function() { TRUE %?>% return() FALSE } fn() ``` #### Continuous stack `r fail()` The masking environment causes a discontinuous stack tree: ```{r} foobar <- function(x) x %?>% quux() quux <- function(x) x %?>% stop() "tilt" %?>% foobar() #> Error in x %?>% stop() : tilt rlang::last_trace() #> #> tilt #> Backtrace: #> █ #> 1. ├─"tilt" %?>% foobar() #> 2. ├─global::foobar(.) #> 3. │ └─x %?>% quux() #> 4. └─global::quux(.) #> 5. └─x %?>% stop() ``` magrittr/vignettes/magrittr.Rmd0000644000176200001440000001741113753167712016430 0ustar liggesusers--- title: "Introducing magrittr" author: Stefan Milton Bache date: November, 2014 output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Introducing magrittr} %\VignetteEngine{knitr::rmarkdown} %\usepackage[utf8]{inputenc} --- ```{r include = FALSE} library(magrittr) options(scipen = 3) knitr::opts_chunk$set(comment = "#>", collapse = TRUE) ``` # Abstract The *magrittr* (to be pronounced with a sophisticated french accent) package has two aims: decrease development time and improve readability and maintainability of code. Or even shortr: make your code smokin' (puff puff)! To achieve its humble aims, *magrittr* (remember the accent) provides a new "pipe"-like operator, `%>%`, with which you may pipe a value forward into an expression or function call; something along the lines of ` x %>% f `, rather than ` f(x)`. This is not an unknown feature elsewhere; a prime example is the `|>` operator used extensively in `F#` (to say the least) and indeed this -- along with Unix pipes -- served as a motivation for developing the magrittr package. This vignette describes the main features of *magrittr* and demonstrates some features which have been added since the initial release. # Introduction and basics At first encounter, you may wonder whether an operator such as `%>%` can really be all that beneficial; but as you may notice, it semantically changes your code in a way that makes it more intuitive to both read and write. Consider the following example, in which the `mtcars` dataset shipped with R is munged a little: ```{r} library(magrittr) car_data <- mtcars %>% subset(hp > 100) %>% aggregate(. ~ cyl, data = ., FUN = . %>% mean %>% round(2)) %>% transform(kpl = mpg %>% multiply_by(0.4251)) %>% print ``` We start with a value, here `mtcars` (a `data.frame`). From there, we extract a subset, aggregate the information based on the number of cylinders, and then transform the dataset by adding a variable for kilometers per liter as a supplement to miles per gallon. Finally we print the result before assigning it. Note how the code is arranged in the logical order of how you think about the task: data->transform->aggregate, which is also the same order as the code will execute. It's like a recipe -- easy to read, easy to follow! A horrific alternative would be to write: ```{r} car_data <- transform(aggregate(. ~ cyl, data = subset(mtcars, hp > 100), FUN = function(x) round(mean(x), 2)), kpl = mpg*0.4251) ``` There is a lot more clutter with parentheses, and the mental task of deciphering the code is more challenging---particularly if you did not write it yourself. Note also how "building" a function on the fly for use in `aggregate` is very simple in *magrittr*: rather than an actual value as the left-hand side in the pipeline, just use the placeholder. This is also very useful in R's `*apply` family of functions. Granted, you may make the second example better, perhaps throw in a few temporary variables (which is often avoided to some degree when using *magrittr*), but one often sees cluttered lines like the ones presented. And here is another selling point: suppose I want to quickly add another step somewhere in the process. This is very easy to do in the pipeline version, but a little more challenging in the "standard" example. The combined example shows a few neat features of the pipe (which it is not): 1. By default the left-hand side (LHS) will be *piped in* as the first argument of the function appearing on the right-hand side (RHS). This is the case in the `subset` and `transform` expressions. 2. `%>%` may be used in a nested fashion, e.g. it may appear in expressions within arguments. This is illustrated in the `mpg` to `kpl` conversion. 3. When the LHS is needed at a position other than the first, one can use the dot,`'.'`, as placeholder. This is shown in the `aggregate` expression. 4. The dot in e.g. a formula is *not* confused with a placeholder, which is utilized in the `aggregate` expression. 5. Whenever only *one* argument (the LHS) is needed, one can omit the empty parentheses. This is shown in the call to `print` (which also returns its argument). Here, `LHS %>% print()`, or even `LHS %>% print(.)` would also work. 6. A pipeline with a dot (`.`) as the LHS will create a unary function. This is used to define the aggregator function. One feature, which was not demonstrated above is piping into *anonymous functions*, or *lambdas*. This is possible using standard function definitions, e.g.: ```{r, eval = FALSE} car_data %>% (function(x) { if (nrow(x) > 2) rbind(head(x, 1), tail(x, 1)) else x }) ``` However, *magrittr* also allows a short-hand notation: ```{r} car_data %>% { if (nrow(.) > 0) rbind(head(., 1), tail(., 1)) else . } ``` Since all right-hand sides are really "body expressions" of unary functions, this is only the natural extension of the simple right-hand side expressions. Of course, longer and more complex functions can be made using this approach. In the first example, the anonymous function is enclosed in parentheses. Whenever you want to use a function- or call-generating statement as right-hand side, parentheses are used to evaluate the right-hand side before piping takes place. Another, less useful example is: ```{r} 1:10 %>% (substitute(f(), list(f = sum))) ``` # Additional pipe operators *magrittr* also provides three related pipe operators. These are not as common as `%>%` but they become useful in special cases. The "tee" pipe, `%T>%` works like `%>%`, except it returns the left-hand side value, and not the result of the right-hand side operation. This is useful when a step in a pipeline is used for its side-effect (printing, plotting, logging, etc.). As an example (where the actual plot is omitted here): ```{r, fig.keep='none'} rnorm(200) %>% matrix(ncol = 2) %T>% plot %>% # plot usually does not return anything. colSums ``` The "exposition" pipe, `%$%` exposes the names within the left-hand side object to the right-hand side expression. Essentially, it is a short-hand for using the `with` functions (and the same left-hand side objects are accepted). This operator is handy when functions do not themselves have a data argument, as for example `lm` and `aggregate` do. Here are a few examples as illustration: ```{r, eval = FALSE} iris %>% subset(Sepal.Length > mean(Sepal.Length)) %$% cor(Sepal.Length, Sepal.Width) data.frame(z = rnorm(100)) %$% ts.plot(z) ``` Finally, the "assignment" pipe `%<>%` can be used as the first pipe in a chain. The effect will be that the result of the pipeline is assigned to the left-hand side object, rather than returning the result as usual. It is essentially shorthand notation for expressions like `foo <- foo %>% bar %>% baz`, which boils down to `foo %<>% bar %>% baz`. Another example is: ```{r, eval = FALSE} iris$Sepal.Length %<>% sqrt ``` The `%<>%` can be used whenever `expr <- ...` makes sense, e.g. * `x %<>% foo %>% bar` * `x[1:10] %<>% foo %>% bar` * `x$baz %<>% foo %>% bar` # Aliases In addition to the `%>%`-operator, *magrittr* provides some aliases for other operators which make operations such as addition or multiplication fit well into the *magrittr*-syntax. As an example, consider: ```{r} rnorm(1000) %>% multiply_by(5) %>% add(5) %>% { cat("Mean:", mean(.), "Variance:", var(.), "\n") head(.) } ``` which could be written in more compact form as: ```{r, results = 'hide'} rnorm(100) %>% `*`(5) %>% `+`(5) %>% { cat("Mean:", mean(.), "Variance:", var(.), "\n") head(.) } ``` To see a list of the aliases, execute e.g. `?multiply_by`. # Development The *magrittr* package is also available in a development version at the GitHub development page: [github.com/tidyverse/magrittr](https://github.com/tidyverse/magrittr). magrittr/vignettes/magrittr.jpg0000644000176200001440000027021013106333523016447 0ustar liggesusersJFIFU  }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?k<( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (?l+Ki,^Vk5{7]%ھ_ݗg.CwӁXx_gRs$gRI;mhE+7+;Lj~zu 7op|Kf CɤwL ]2=,\(/ĝ7UNis.LJxKT1isjwP[_ͫ}xS>[JӇ5Ri8N1-*N][X Elrw[$y'8# eɦsd к~u|-ֵ3ZuzK%CZ k*KvxO4ɱ9w0Vye ݔ\[wbvR|3DIim/mּP ( ( (>Hm?/㧉{?xA[;CլhW7 t wjα{h:wv_ N_Wa}II$T3i.ױq/S;)&3)tisxĿtW:Χ$wa-RŧͩAm6XnRILTm+NMJQ8I;eunbKX%[k6]l )F׉'&}͐ď^:3o$Z"xB)#NKwro4R[mURj5m}VַKYJyIFA]-VXOPd7B}֣yZb4i/3] SM-D)h7N-[k.yW<&h7eZ1/jvQqn23Jj]%5OZB ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (c{Yi֗7s [;H^yP*+fRi%;秕ο7?n/ڧōKRԧMy_}"[mmx]}I,wfHOpPa)I**u撼y]Q#خ<ӕIgx,zkne-VީFOo7U|9C1ωԣxT🄼c;YYx^h,|{em&m ƾ4GP(Vxgw PIFKGdSqjw?iO~!p]+Sӵ_}u-<gޝ>i/yg:mvƙgro~ޕ\>cU"L>"N2](Ilx65fp5*SIJ.֎|JIk:XGGdp8/N _]ozusCgtB}5n7HdSo$I0Kժsvs$zXN\{KGn}k\ ( ]#=I> Me|gMCÞFak0x/Fݥ[hZյjэGF4mSOҭZpX{[ ~&~Ԃr;!Vi;ifYWrRvO~[n}S 5~P|NZ|ׄ>5XwOԧћIu]Wm?P?\MkM>T}|-S=,F4gzi)U}\Y Q/ߗNm-~ߴ_hYw ]xYScwQXO=-m_L7>ƚ̊>Gؼ%a WGW;+ҳmJR8짉{_ϧmto݌~+.+AWR2#ר篆t  (+_Yv7qis}w;൳.g 1¢< Vm/yZ{ϣzy[? /cx~ XԵ-Jj;᫉K_ 7/%m,Vڇ>%Ϯjqkkk4 $^i+ΫWU?݊s˭9TwWǭֶ^mgw[xß?n~?iF~ '3/Go߈>oy.\ָK}s ?нjW/ R?\v]q9A}eC~3Wi{M9wn[^r߷,95}}m6i r#ܿ Iͳ_m?gߟdk[R彭oeJ=81|M}oV/ulû-~]<ݾ_gϵ}7};x+ohz 'z(O*GH|-"x{ jMk ԋ牡K[k_LT孆ikXxsYrR*h&.XޗGKnSv>}~/(?a)YY՗|woׂ9-]=dҮn?5e6z,qL~iMVvMJm>YJWvҕ4yulo^ P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P{=RL-⼰m.l/'A$Vwp#覆GIdfJ8OOuVO+yCcÿeտu| 2G2i)k7n[x;ɧxL^{6?-a)֋^EBMuR~%^MX:Un/MV];gѷ"Y//>#<7.>=h>_<]V7cs A-q71}\&Yw3.N_:rw8JM]Ss9A+twge 5-FwOO#jx|=7')>ה6yIi+Nnuev)I-X}},c?<5S{,ox>3,Oj7顄{tlA0żn2'T;;9{8ZuOk;#ԧJqH}^O5 BI;M7Lm.u GQ.a-!{ۉ#Inf8`7WTVai6mWrvi(ܤwIsOZ[vuocj OZ5o=u=_VӮn`I$Y5dV#JzUբJ*SsKKiOiE?J_izuH€9x/q}I.XIiַ)vEu"{-1 %[ ԣ6oP=/ӹN*/G˶UxrP{=RL-⼰m.l/'A$Vwp#覆GIdfJ8OOuVO+yCcÿeտu| 2G2i)k7n[x;ɧxL^{6?-a)֋^EBMuR~%^MX:Un/MV];gѷ"Y//>#<7.>=h>_<]V7cs A-q71}\&Yw3.N_:rw8JM]Ss9A+twge 5-FwOO#jx|=7')>ה6yIi+Nnuev)I-X}},c?<5S{,ox>3,Oj7顄{tlA0żn2'T;;9{8ZuOk;#ԧJqH}^O5 BI;M7Lm.u GQ.a-!{ۉ#Inf8`7WTVai6mWrvi(ܤwIsOZ[vuocj OZ5o=u=_VӮn`I$Y5dV#JzUբJ*SsKKiOiE?J_izuH€ ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (>DaißmQG|;sχj䵼`+e4 bVδZeΧ]^h=ՇN\;K%RNN<]\ZnI8JUkFU'r?nK)I,4xi !EIoi^ --8#f]?Qm2 tq.Kagy]:J0%*7N)Y+K R:A-~N.ѳfݿ/> ?cj&KJ~<-mSBns#Qh,Bk_.%/eTZX\-yQv%웽Փ3Mw8v[߽}+~I%}ߍ~o/ڧU+¿i. z,|Cz9MxQ. gKXE |Gi<6kw\i1 B8jz)EQFn|/f+$S9J++IRVH w_ >2<æ̻ lmvKOG1^]ZºZ\EkJF:sZsSSWHyn3OTj.Y$ן^On_7Ǿ}S߰׊$\|zG-}=R>7_|ceuK?X&X_]js1R*MݵkpkÚ.R8 \,oGz[񗂼eڿ K^W>&.;[tۇt) "3}L*B#RR(W(K>k4Z2dת]=oO ׼'h)𮷫c5x@ԯtmwAcF魵 /To`P-XÒHg 'FIJ-5iBQwM5MYE&f4k]VZ9|hJ7lo^{p;IiK;kC VK_".!R5xc'fnj6TzS&ޮ.m(ꥊҤyk+G[޼]E? {_GHu\ozcr w5X4CQ[I,">|BLK7w:ߊ<5'RҼZ[jqˤGo-.̺~e7?e\T!Tϖu!ta*JUo;ʜRWvWtR[ɦ]gͻ~?-_|sg7q<~MŞ+x[ڧ"=6)/x}mF|s棬xUZ_oluih<ӿ<;e%777Klm&+obpX rpQ'RФZM7e*nn9NmFNUhi{rK_A'W=q ?> Eu7~'խ|][Ηysֱx<y{ Qtx4m&^>c3<&p'U'R SO^-FWjI'نR2sW"Vw}WKyaa@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P|x~  {|:}giyj7-/ci.gtVI-KԵ)-\،MXӕZ&[_ %(sI?=?IAw ׉ټS+[~xT}$Dfޓ;/妞V }GPEL? b*kS B]iH8m7\ܳj7nMn~v?QkcJmWKt_\}MΨu?xȖm'J-چԝ],Lլ+ 2KVN6"VF<8/ğ gO >7>+'-4|Hľ-)ԡŏ<Юd6iجwWZw4jU` W7ȷt'>zZFu]e''y=eKZ6yuXixS m߲^/>xfYhOx7lmJk74wKDաuCkk}5׭iκo/bq% &n'؎YJPەSi\%Y F>Կk-]~}g8J/iMW/?Zi< x:Z#]ivicioscqwmZGo^_ |sᇃ&LJx?~ ơEn>.k-VknyYaoթZթVirެRvW劔M}5knĔU]I~יԀP@P@_QO߰?_ωn_xc~ҵM[xO'ӵ;k+F$wZ>)8˱ ^Ns:SWJa]zӋv ]USqnKٯG-n3hm,xH |@Rc׊$#M7nmcյl;?^ZNummSE{]]}ῄl|4 bӥY UHe}\W#pRejnmi_eExtzω>|M?gx>ww=fQԬV+bW=Geew=SK&+Q,)PJpœٹr$;]7RV՚n:>^ToC࡟꿷<~h|/+}bo|Svt_ gA1躗|Sk+Xխ΁/ YCoRiWk/RnJWT)M.XEBqi{yD(?Ivz_mhc|x~  {|:}giyj7-/ci.gtVI-KԵ)-\ Ս=9U+h*zRj1չIm%(sI?=?IAw ׉ټS+[~xT}$Dfޓ;/妞V }GPEL? b*kS B]iH8m7\ܳj7nMn~v?QkcJmWKt_\}MΨu?xȖm'J-چԝ],Lլ+ 2KVN6"VF<8/ğ gO >7>+'-4|Hľ-)ԡŏ<Юd6iجwWZw4jU` W7ȷt'>zZFu]e''y=eKZ6yuXixS m߲^/>xfYhOx7lmJk74wKDաuCkk}5׭iκo/bq% &n'؎YJPەSi\%Y F>Կk-]~}g8J/iMW/?Zi< x:Z#]ivicioscqwmZGo^_ |sᇃ&LJx?~ ơEn>.k-VknyYaoթZթVirެRvW劔M}5knĔU]I~יԀP@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@PC Կ@M#Ǿ~w_MҵCM5+}PӵMWN+m5R8Ӯ W7VQ:M\н=╴W5u:ef.6Z}7Ti].OQW7TRWI~*E#5?IDڍZ[j_hMޗbx:&婈MҦ6]WK^h?䗚-<oO#G<-C)E, C\skj\5e5S_|-"ۇ!ofX(s(asgx%VQ{~OIC Fa?9{=^ܮV]~>SZ&~^9o3]՞~ 2j Z\xȐޜ,Ul/ծӣEݶQKNu(0E^3Z*_Tmrj*C]n. {˪[w\zhfh'txwSִiօi)yj>kX] ͝O 4sC*HVu(.Q$e{٩/jmޞѫ O/o>04xKö Gu};дUs:ޫsgiv#IF95rۖ);QQR]t6j)nދ|7}SOl4xmu}+&sxsG&mX^ VR(nSnO&6kRiY'd*7&k^-m4xet_`oKS6"_ O? D6K5j ֡j~8M_ z~owڏ c4?Cnֱ׋oxPx:Yom6c}w)I"l?gG OOrJt+1SvM-ZHRM^qqes%7g56k^15Y|Gˣ&w5Ǎ ]i_FAZ-:?]jɛeRc dU5eUKFڷ,߽t:&~%uhZ}G'u;-kAahZƙrvꖱ_iڕ ʹG42`OR^MQq/I&m ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (?Fo3XH|4Yp[!𦩮, `W8cXT)*؊mZwt>YKMtz+_);FN+Ꭳݿ9]߇5}]xE^t`Kba+<(fSU VєN[+y1Doy&dO3<> |q;,W𯀼h&e Q_ckiC2}炼9gŧVZkUn@ծ4xvv{a"a>G7 mե7Fm2vN3zy(MYG5uoK~/[֯W ]{C_m;T{VmKd$s^n-MG$CJ4s*ҊҤiֶה拟{t߳ FM-c?d+6 Ie(Y^86I$`gwv`3IPg<KOڇrڭυ5tdžo[{g5^A_ #zݍjzk0xT_ IyvpZYJ,ԣ GW>Xo¾}{t~׿Opx?>%59? 0 !Tk/%ΣYkW5KqhxS$`&mcqJ~Kin^jOWqGGn=[ῂ[ ^p$%S’9oziW6~ u=YV^.اf; T(Ria-/N},<)KzGUYշ?_k6 (<f?/?ńO7O #JH/axfԶBH_ΑkZl+*M-ޑ}ƕhױèڭޛwk$K]zp%BjS|ӽq,ZѴzђRiYywv70YXA5ZZF\\L ’K4ҼqlʪMJMmY%輿!_a^&_MN{? ;9^]?V5_].{Co\Ddt+ Z+<XBjYOG(1Py6cMNj8)kK^V u_Mwz$Y׌$Ӆ] A{oz4m03XiZ>W.5&*RNIS4Si-[+s=IEJyw%|=NcV_.~ok5 (o`9g>#ji^]nu S !k";45$׺9y+Φ=bz?弴rɯTds`j%G5Gkhu׋|gw,eY58 X>u nS%>&~ܾ9ğ3B՞~3iw_Ex#ɐ-ޢ//J:/!խ"dEoKNt3IZ0ZW_VM+rn.ܗcAnN {ϫ[\zjft wLt.giZ>kZ@ [A pFU~u)JNR&ܥ'+ݹ?nmѫW ]g~2)s~/k[~xnP|E xN5{ hZxm]n*-*T'Nt6:8LUhהaOUJ0{MIi}7*u&Sm읛n'i_/ρ k;5Zim<:Cx\._2ϯxTt[Iۻ}|V O׭N5VըEsJ`';$7|%Zln~+_j9CkvMזj >ӴkJ1W#j<;,EETwktڔ"ۏؤKk#ݽ_},իH|o|5^π$%Lφkyn& 3C-lm-InyK,/9άRRrԜ'gIIj$KP  ( (mx|y≥վ:!֡$4<A$"׋D4Ώia)]cO }vCӍ8qsPZw9~k_w9>VniAs)/zT_{[s+m?ڣC/5Og~.ϪRuˋ5Χ|>e]cWUY<;wiwhT0\N IbhSeR*gZ{J)LS^o};Qi꿴< o!x"_=u ?~!dk_|0σ`R[\*]b#waootJqe9v~Ҏ6=ڼ9[Z6rV' ,eߛFmJo$ۗ>Aּ&hZxwBM.k跂|92E3i^!ugE6ڵZ(_6`iΝFx+F UJ։nX?zMےt(:Ayz+~˚OU-O д=.Z.2Eд}2,+GbӴ Hakh!UbH Υ)IR۔}'6m-5`P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@|I@6aڋS^5|:'/5q~2mo:KI|Q㟆Z]#Hz֩c;UH0? hb 8JJ#US7f2JS}oYus |F|U_'zt7|dIo,'~.QG d4V7EwtiS;/gό[{-dx‘j(ћ]a4Uլm*gye猨IS-.Jk5xsYu+" +]vw6LQEopAp i0ċQE8@#X0@UP@PGP@P@P@ : ~,gxCž+g w$}clW>[haV'^7c'Z;U˦W}"綏wO_s;W?kB-l/}>PjөRIB%{7vJϫ̓i( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (.n>/| ۿ+;o3Vloa-?|iÚ}I#_=m6so4s|N!BQmYӧ(kݜX5*TSy[vu|C/Ygx {]iw-gE𦕦jvj׶KY -7Wg^gթ(T'gZ)ؤ?@P@_ߎ~~_> Cwx㧀|!!<'4 t/xK&{P|1}%Oy 2e{s |;B#^+B*Ba8s)F \8])^7NR0ƕni]Ko~_<]S%"xY<_3޵o_0{oZu[z"}R; pRqU"{Yl4ۧ3qWnXP@b:\ 7ґE|[tύ}>txzQnmkkyf 4R"Js?gRN*BP^\ڧ+So[hOTԗtsa@8cIcRߟI ߶ л,R#)#bG$o FWg~?qM[#Cx 'q~YJQ}} ݽ͍]זhENtgR)HJkkT%umm)4MIwNW:P@|~'5[ e_u+[&hƗu5eӵ-> +![{7A0TJ2JQ0՜e+49ZkTգ('Z:M}⯅|/߃$x+V{Ҽ_/h~0&{>~<=}7ocmscxr5)yS:JpREtZ8]jzFzum ( (|:~ >o^ou/-xRW׵+M{Y!(5*4VqNڌayS+ݍI-c>5~7D| { 2mr -Ǻ행ougcs[p^Z}ڄiJl&*SѦ*uhri*SvNM Oɧ{f0 ( (VG@>+׿_3 [NP9_~0_oGk5;«l҇ivמjP@5տ ]>ZnO|3ԫ%}*n>9rLk ( (>!~߲?\+5>2wwǂOiiB..txM t[4Y"/uVRbjB)ҡV$բ\SWZEeJPd{gABѼQmoH/|Gk+=gC״MV+3Wѵ}:[?T+) -fi#('B\%%(ŧfM6[]Ɲ1P@P@P@P@P@P@P@P@P@P@0O6Ss.g&.qgzfښ捨ff:AtW6l~ ,]Woe&)>E\UԹ%#EuÞ.7gFZó> /O]5+BͷJN _.јAs_eȿ{G=?}}myGrMKYGku}w}_|B?nc߆Ziuo^4"k=;FO ZogjBh:f}ZayV% t+M7w))W8srl\K|},~g-侽?o>>e~*mcw^x ZaM觗|X>'RAPh9ь2I9ƤF/&nWk{'J7uggwiEk ?j(c мE.m~ᶇ 4 ߦ}&x<kWGaI~"^}'jbJ0A)eʡKߴ'̝H$QϑG\ܼoOM=6zb~ͿnVcEbH"O!5?hZ֢o~ W%Dl Ma|eGaÊeFJ[cRd(TiʗzŹ&XSI=t~Ӭծߏo]__O_ZKZ(l%7]E5#0Ӽ5_V:~n1ZWKK=wD0GNt$%-jMыJ'd)KDJ2IJ 7w-|1֣B6i7jbXqc}o $7`;ӦT9N&sCv3;%W_?sG>*}>i_M=7%梗 mTSU\rT+^˗is^tcWeֿm(I׼IM;RimKnKw>+xE&]3H,/pK/0-w+rZ)rхe=-ddכ%nzϙz_hHEk$4IFH_TldRiό }JTy~_L6i?(3:6ִ~lu/kV/DnA(3L-8§ԣQnFIy3N ԥ7̞K^mct۾+EmZ8}g?-t_Cm[=:cCKQir\+,Cyd~ 'I3e*M ֋zrZ95dޅojgk(I|_^%XgUy Ŵz5I'OuoVtFl&7 =Ǽ|T1NJ6RB.R~/gGiT?/5F+.I jk:g=:XЧmCV[>&6l^'W&[kuτ#ѴV)< 6h2ㅥ&-(8*2KƖ?w嵯'hH]#{lGyei_ mCw3yh־|B4;_$|iԒo`̗~fTIN5h;[T{6RneR~[l|3W~ΥC6?iO$ė_<zO [hö~+o/PGῇiPv'Kmﮇ`a<58ӟ*yiIKP|9Ԛm*i9,熜=2wvu8<Lgjߵleޗb? |\eúq?"mVnmg›ɾa1XY{\OjtyIǚIZt%Ks4e&ڜU54)YVwq????ijU^1  ?.B~0x@?l0a}?rclˈ_`$a.{? \kwܚXokMKZnܷWζwfΑJ'u[#])d\.lr%ws +G > ԙ xsŖo|ICvIxcZT{womïV:Υ:~?_82,.[Bj'8>Z\;{Ju1!'$yd'Щ[ޫ&E+6׻m~m? o_ZOh jUѮCEφzQ/4KVX5m|Ƶ'6Z0AѫJt?qJ/էRu})^Is5Q*xK+Ҕҽ4+d?|p~0m%W?GDx>*xa{kMsVtWdO66iO_3>+VJUF:3R%4/Ϳu-r"Mfm_{={kSzSO|/~? kxRO o>רh>ݦmؿ|S_xfW-xbb=jOg'/{PL BVl]Q,'1Bq}E?.ਟHOv߀?,jM +E۾ 3_>~/i5eYJ{8Fw嵽7~UR|Wukemݯ& ȯA*O#Ӓ=(1i();;ijM w"wejo;XVa VdnXe.}R8iQOVT~?eS-~^TµU4嵹?)oC C 3 go _x\_;}?"/?ۡ02OS-cio{+[k[CZ((S|ד[o>ܿiǿlC?n|<׏?z>+^2_n~ѷؠˋo+ʟ;(riwV.G(~ӗFy9_uuF/(Z[/?>IۇB#-wA{W?sNg?d٧/ ?Wv]@ls>jMa{HÚ~i_/KWq5^QUeu)[r曔m#qϥ++p~+~f -n#S#CH5O/ZuNѴG|+Xd{)s{*RN\O˕I;4MH꿭{Y͛%U;Pf,g'q}E? ?Kxύ>9xC)S~g OHu_i^_?`x`}uo?Fydif۹{_eNk\fTg5ʒKo?_Gk[/?+~,'1B^}E?N??GwĿᦼE3+_-[ֿǿk?dݤ`j' Cs sJTi}R4=GSU},_ʝR:ƞ7E ŷ̭k[( c9~1>Ohֺ.56'ZHuAlT൵]Hyf"uktyq>IZ+K;ε/mg ;tZǿsflOMGOk7Oxs[?7{vmԼIxN&.*aks4\L'$g>{ʢҗM+{5%_,d߃<|KMNZ[+h?a9mgSxtB-/sS BO+hVЄ֖8/zn0JҔRMfiмe.fW_Q vorxk? X~,񍮱wn}BF?G'!|Kd>(ЗĩxPh.MJ_>$R&|Ư:U|NUjTJFKTTӔ"Et4$ݡ8La[4Jrz;[M,Wk5:0 ( ( ( ( ( ( ( ( ( ( G]őH@i~pFpxʑ'cP|4ek+^ς<K<;SZn#mG]׵Kc\'_jZtW*֭'R6{nTB (%ʕgtb$UÿNjxAU~]|GA*Bt KG``e}GL./YCZkw?nO^ ZSNOFהcIOwIᢝjk.m7'{H!bo9ek;ch2QUW _#6s,w.j).f?O(͂ ( } ^ZzVeHZOo`HEN6轁3_pSk/K?#|-?W/< 8ǍVτO g߄ھxm6y%Pm{r|;Sžգִ˫9Mr2ʲzٔXBtЧͤ]KNZݦ+G [֯ JF_+>l|G᷂>|?w߆'_:1i$z~İħh qw;/2^j:֡{43'ԫRI֫'RudR[IӪѥRIZ+Dր A?g/ý.ovZmqZZŅׁ!c_/P#e?*,wk߱ee#pQM*SoOln,e$jY)lw1~VO+/xoG5zg%x@P@_g]+Gox?_ ~ µ>$V4|Wk|3g\_Smkesx#ucz4jdcoka`|ʹ{yؗjÛе}o˦ɴ~*zG3,m~&:xJ|_|%oT}s>iC]x{7LJ&5 _?gK'=4*Zr,4sj.P7\.罞TeN ( /_w_Y88q& ȯA*O#Ӓ;#= {o0|?{5#7`( Qٽ6~ָ3_c*(my@P_[ '+%7?J"WOp~$0 ( # (M]?_-???'!RHm;+.Q_>.T-3ƺ.x+HqoioZP'?qf8<ʷ$*cӌ!:qoԖ4T.UgQn.Pө[)M;Ngmy-y_OG[|}3~҂^oM\ha_/.uMAiaife+[ZU{_zSv 4K]zqiX+G}v{b0 ( V ϰ[/ ,_/ ϰ[/ i[~P@P@P@P@P@P@P@P@?O7m} o ʱŎXg/inB/GocnȇR ?켯e8oKG_vΗ&GK?~$_ r?o@aзLҴ6c8χQ9J-J2yy\&q8(ٽovRh@bwNyدZݥ(֮6[iڗpNL|!Fy._i%gf}&vMZ4ӳnEho]=:_/7Q??|A^wޯ{9+_?i+: D?oX3ٟS?LÈq8'O~L (?:H'e-}g ?ǎ!_C_g/" ?Ы?8WNH~ (|g9PVӔlgWL/GifQZe[4Gݵ皅P@ o&O lۓ *_g?yOܓ?ø( (*_75w2T?g/n:7ĿG^=?.?ߚӨ( ( ( ( ( ( ( ( ( ( (i~xýZVl]/ Wci :]մC6O=ok* E7Fl|ve J6{GFk.ѭe#]g%Wko [N@ _3?>6_AiWo?>\xGU]2}JM_xJl6⁥\ VҴ53b;VfQ7*wKtʥV,)VJ߮n~xZ'ğ߉aO|{//^h(ѮMR g}:@kYҩN\R2(MIzݨϧD2iM?5#l?[kR /Pu)h_W~*t 3¿|aףk˛ҭ<]G[k%cx[mo.Y)aQ\?Q\5y_湹j%zh# m}[n> f5!ks[j:yVZp.]TWĺ|_ŎP˲슚F+jmV~ܟ/GR"\,.&;6K/?&?nI|UD_ G [x+ƚž}'ƞӭ%׃4k0F#4S[ZGwzۚ¾k煣Rb=N<96(Eۙ.ByFn6/Ꮜ,Ta/ |Fntq>C=O5旤x{7éuɴZy 硃zUsWS[(5R$ UN7MT-ŷm;|Gg%~ŸWԵWx'U5[x`x⇃E𵾝-WH}' ӧ~<@ޭڍL)ӟ,)_WMKޕGI(zx2PJyo~j+'QF//0|ޯ{9у J񎃅G?>x?X;4Kĺ]KmV`oZ[]7SZie楪_oww6(ԯVhέI(ӂݺeo&dz( vKw*3{q@O 0c?+eo?Yٗ//nIL:Bx;ĺ3 ?ƗN%~7~g`.G~PX9%7RT}NT{9gV仳KW_J:a??_5 W~? ?fu|@>%-kgZѼQCIⴵ&~Ogyw)a'+QSt(Iӟ4S%(eujFjw[=J#a@S%j9~Z#fxb?m.l/t=C>Fa\ؼW7ZZ6WVW6q[_Y7v)qt JMԡOGJQnti>h*IJK7E)U1g9WQ>_7߶//|zl&+] z?‘|pYCB(ƛfաVZnTv}|MJu"gF[+}m??L|C/~ xw]ӿKЗatO :fg6W?fY\ZͰIo<2H%l6zX4:%Fӳnn:#$粊dޱ]O*3GŒ'4>jo_߀&:F$&\ixvZ^hmyg{n5 &/lnx3{U'FNJIŦR]4e+5$k Ƣ]K_Gf{dPP/w??mس?OEm?ĝK aP~$: [)Sk ;fhm!h :iI:UU,ܔnP|j:)jYׇ(u|߅I,?eޖ.I|u /z|QI0H|ošԗ6kB}&Ax O5{I$P:s7 k+ae}P cq.l4i:d~G='~Os6KضYsc; WT]^|)GoZ~ ^]xėVxkfAЕlqi{&9j2J_tkcTa[jݴO}]Xm;xoy\tcSpAk<6imm0@c_[v&ҿu}$Zj`8C  uV L xP~qn|5NzilZCռ/wMROP$U*T^V/iF3JR|&M]qJJq^;}v%Xr"5ؿ5k-GR]&,OwOisx%<}Zok*6iz2]_}rOU<"-+aʤR6Srݬף GKHu? ~eoƭ:_ֿ:xK_ @𦍨oW%`AkEP{ Og µFQ~ֲ[Μ$SqZs\qdeK)M0ؼN:3շ] j;=(FqMyu?|U>C=g[pɪ~6լfL|qiV6JT=GGY_TJ%(IoᄣӓEei GcGGÿx_^ !B+-.fGt;K+Mkˋb$wYevjTVSVsRJue6kMk$})$J;%? o5 o/^1 ֕Oj3ƣ|Qt}?3=3OcK;RB+(F!0RWt\[=팰ܜnmiֿ T_?~:4+ [K-ͭgm$K"d{)yViixGr*toR쥤Z~F5'ߧ}\f@|<{S>%+TR/u:=EciWr_Iqi# ;%]:(TRE:r%?~ Z{Qijzk߲_jאh~;sGQ-'haR|mVu].hk|IKZ^O2. aj) + x87uԭnJdrҌX+IF)1KW_7wv%K^m¸bS̙.x#dQ8j.YpzpB1?So2&źo v܍~& |ʸ}nҤC$Z _tHzgxIR]<_⟆l|cz%ׇWE47..m5 %H5=2R4Kk{P fVYJqITDҚi~eÉ_k#ς8Og1?ia%UѬ>g> ? _?>O_É_k#ς8Oga&&_%WF`?5>ɥɟr7x3U8|4x[]ץ6ioikaG>31䋒X'eF1JMٸ_y3hӌ{GU€?>h%_ R|J0rt|G4;X=+x&]^ Yijz|y}PHu9lo%>m){ >%”[qB+Z4S\vT)|妷kYr*u-}޷[? Eg8J?֜| G4R>?M_ps x_C5 ?;I{ƶo.'ԩ:*άo~:ɥ7͢Q&(Y}[@€ ~|w>/<'+zeu Ft8h5IkOI6ir:5َK)ҩW':u"8M4qw5+WhqRVMv vĒkK|nnՖmB;>y~XIvxkdQccdѽ\OӅV:owxZmsC2~7߇m^&^%wLOCi/.~ᇌVO--^/aUx3k KTJtER5WnPXZjZOR^'?I%VQ~Ͽ>|7ltOE/8o6m:/>lv%F 2(,4:xӉU9)(9(RyW-J.4 ɾi7|1K+]]PV /`ߵ?ZXhw-)x&J ٱvDž4NSl5Ჰ߷ cTr7NEysQͣm9QQQվ?ĿJ5]qA G0Kq/d?Qg L?KY|?h|'8}S43/g ~e O/]M۽Wލwww|J|9,'P_:b)Μm¢䒍49+QiFQХjVk_oC,( ( ( ( ( ( ( ( ( ( ( ( ( ( ( k˹m$i$FweE&'um$ylI/@;߷M3O'71,Xx u |F3'Ju>m;Qg9u?Wo xKjrLejZ,)Կ5*nQqQCYۚ\EY4|<5G<_W{g | hz52 ǯPu跡fw~O.%{JM Ze+^ʚ,F1Ue3Ġ ( ( ( ( ( ( ( ( ( ( ( ( ([ql#uP}s8a Ǫ+(Kj$k]8B}MnWĭDP@P@P@P@P@P@P@P@P@P?:ثy#x^W=NFHֿ!Ij~&mm.lCD樰zF7.*>):rtk>hՔy3MI&墕jufOu(nדZtݟO/$f#ӛb?VRzWOũֺK㬺m݅f5_[mIy[;[{\Aa2 ZM:eRZBM]J[NRW͟_?+m}xZH>➻g㵸񿉢DWNؼ5(šEMVoGOf9+2ޕ^4쒗GRZEsr(FN/Zj}s2  ( ( ( ( ( ( ( ( ( ( ( ( ( (z'd`ۀ=j\WWJ$%P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@ ^pP@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P@P\\Ak 7Smo4\\:C 1I,2hg!51ܝ۲M9oV77m审ep༲uWh١i"++vՔ(2N>T女5PP@P@P@P@P@P@P@P@P@P@P@P@P@P@ ?3E}>+|1~ j tψ> >%:UzU׋4*PР}F)$Mno*Csm$ FЫ 5p(8QMMsYm5RܒwQi$ԯiEJ;5kmz#iuP@P@P@P@P@P@P@P@P@y% J/m/ZJ|y_i{).l|/CvxRH6q4cg5(gԔ]Z* Pnգ5:s&fqT*qcv}K-I=Wy>?ҿQ.G.~|{x84Z|'SS[*FNc<2,K-r*NSfNkRuRMʥG7fܚQӚR>;տAo/~z/⦣uxR~? ?G#ZLZ7IDx巸EȒ2Ѽ42ɝJS7ɫh/,$*Fy5íRP@P@P@P@|[tݿ`/w?o! Gmuo뗂YHcI획2j$9ώGUN!*\ϕ!g;M\Z¨.GRu].WjьS)JRIE$'Ũ;{>&-_[xMmVĺf4i-٩Ŵڎ]J8% evehGdK[s]wtV0 ( ( ( (l>˒0z {O9Y]MvѻKG!P@P@. Ǿ~ދ0ߧjW뾿֗x:g;w9Zϳj !8[[𧉴mZz毠k:^x{U4]?Z&K wT 5TV9Ǟ%85(qm4ީV7 JQbVmY;UjZM#O?~5h/43G ǯj玿/mK?xA{(;\6aY hvʟCg1G {>HFZ+F O%ͻ`N*BudRRy`|׳J_7r?/'Ark׺ezk ǯ}N(_Zol'?Ӏ}Kitpip>S^vKߠiGQZ9_m8?縡.M/;۰iN;בwmS#~%P@P@P@P@P@P@P@yߊ#_<ǣx?5kWSFMo,ڇ IwNYL0*۔s| ):JNӞRT\猤scqtXZQۋh-FN{>V)/O%?Q~ԟ|9p~ag%{݂hYhb[M +8o \ z"ʤTRM')jPbƜT}~b)op"r]-rr=&j7:VizEnbדXYI%h72E]_+_aNz4VThԩUqfRNR䬓nY~SK^bI$; OLͪx_ /> O// Vk]OLy"o!{tK2C_b>8UNrT%RՕޑRnъzBXuAQv~Ό*ъqZ9>f&ah9F( Z-Wf6v,['j*5gRr匛j)hch`Y%H!_jRbw[uN'v:.J|9izEƋZjU6P{[["oFLB)ԣ9SNtj.^jU!(TӒiKM5tMKd4|L~ȟ}O k~I-2H_fK-Ͱ[{e/ 'zֆ*TT߹QG3Iߕ~i&ӲFuFJNJ^>{ ~7b;UC,mRpiGIeٳJ7R-.]I%~*Y"bO}vuP@y 2 J"CY[Rkk;u-O7 k=/OCoOg4~ξT?>8|7ky>#J7-u&CID`:ؔM^.,-iA6ڔ5>U)FQZi/{]E:e5+zkug/_/m??<+7I]bT/;q/"CsM*3 p-z2wehM' I]5y4TW_ 赘w:鵏kz?tw9MwS4^fK}=o+Jc(Ӕ߹Jr|]֚|厡aZZ]^ŕ7Wv kunA42),R:0XN.)&o:;k|VY(>!4iz^Ȳ<9ejW/%Ɇʼr]#~Wdo(,#^\Vחk*T]&dT[m6Օ;_Oً Կ𶀱<;}&AamzG,v-PiWW+q~" m8V9s9T,-i)NS-{i>R'QBPMm\o~kDCOk~(]9.cEizw};MV T+O*@빶<]']qpn[m'gm. 8f5Ei^Ib`6ōA #p,E:*qIGF1rycהrU(QNR"mɷ[$c} w߳~Yxv5OeOA@Ƶyᨴ 4\L|?,2^fZy2JptqNiF2q58UMƵJiY/bUlbrHݦ'mtS;_߈-xXU>M @jX2CNPnMA%jfO죏H)K[\Ki)'ﭗ m 5~ u<Ae?ZkwVVבE%kJEazI$QѾj##6e82K}cy%k[UܯxT_cyjzn}:սM5ԑ[[%YcE*>l>:VjӜvZvi!J<'A4Ҏޖ۲gw/,GcK 2k?޻f0k3K|9ӿt}m S,n_B_RM>WRjY_ezpvm4T\_.cO)Fum&;Z&[g㧇>#H~o2]I/>P#I]J kWZF^&Hn`a3%bp45.x.iaǙHV|ғ(=Ij:prBm)6rZKVtMo|1rM(U/\u-gD/}Z'дgBƨ`ˠxH찗\ST5Ie/)7S.X ,BI.uVWN.VPWO ^'Fot6hM.MZugJ׵ﹴ5! ^\w9km*ul`U%q Ѵ-|;qnRj2qO~TM뭮ܯe}]ߟSg  'kZOq}wö>&oWf%'zw'irk4}6-*_L__iϷTM4Q偓sܷ,F+ .qTj׭iQp3sU(&v2c1QFN4g9{.k5)&phOK ?t,4Oط Ix]+7O!Z k-e].@DCӯmh?;dY\ry['*\*>;攔uxBQթAsba)Fl$ӏ,c[WSj~㳌⿤S>O=9K>K+-,k,ƿe $L .&䵲^[_׮ҦBfȕ5Ølqӧzjt)SU'8(ԩ)ƛSiN3ss)ObGBRZvd!{iF2挒/Aw|xAqoWѠuAEmfO*-En|~#G^4(SUg''ʵ֭VsӥV}+[o-=QtLuoRѴmV}Nmt/Kme5[8&6`S4((J!J R+$vݨv,S*cBJӿ%(JbzvI>-[i+r<; &;Y7~%z5=*-gRt_L&Ѵ -t^=BOYV|¬JkW* T5'(YJ.h|9U*]%cJ^ ˷3rN|{֍4?pn?fWD־bԼ?_? sJ$ x[^K3kvAX"G pŸ 𔾭VZR*Ug(ӌ\RI{SьƪnUI4`F2hII7dܚG/ %wJtύ?5;J>0oIɧyIlkk;-VtK[8%˭ SՋ\iQSmi7mTeSP=I ĦN/ZߙhӼvHԼq&+x!A/,p31$SV:VJU:PqfҿNQ ԛQ8sЊrIV=oƺũe&G.~ w|9k4$],js7:w$dvSI-꿥 xJrNTwJҌ$4|LsQN92+kdI6*|C 'pI!@P@P@P@P@P@P@P?)~xSo/K⟌YtFdhV{}G[I  ̋|:O [Tgx{ zsvRK^'̭8?bxi56ܩS[_ݵK+_I?ي]xj{{SOh|U0\:-jw}N`vMQ$J|&mqxSQU*NnV"smyhF1TbbRIz%d~W|Q ?d/%\Iχmc mx=c#2xmbUW"ɫ繅, :QwW({XQ,g8sJzYFk%&҅4)&YF-M%{7MG?\xx-WIPEhZA &{?WN)usyݟl"aax qV3<^ Kv.$ѫNR+B2hťctOw_ſ\KīRHmWRϋ~U]_Դ+5-*[YM{*Jxmai`,- 2[J =w惡t嘉c֢= >qRIB7䊜fT#yJ&Pp[5w^⋓Mz]e׫~)zզwWuOFrz~Et{{FL=+G->ԢZg/3VilvZWt{yMhO!B-\m<Zv&XxҒTI'WFNM~n{Je/:35tۋ"Ğ3շXV7["jP#rM[6Sj8+FQIFSΜkFfzmq 9SRV Sݽt+N. Tݽr/̿!Gi?'/?_ zƣkhu; 5֝#Gm(Qb1X<6 ӣF$ZЍ׮5wttpV󪤜MM5ngwGsl(#įy^=Ko4 xPR4L1Owu3c{,{Z&*=GdJF7I(i%%)(E]??3o[ ?{,? ]K(m}WA|_{aMŚ*lCJyoej8cJ:9yKuI%QJ4i]IC˨/B)=y5Y8N*1v|IV؏Wwrf;ψ^9"MK-yj54O iv:4څiחU-+6V5o|i#5ޏVЯ]+- ~ ӝV7\$,GR:fܷrg'ԨDՔs6I]$Jь]QKo)j? @5{C|9<;+?x?,m]FÝZYu4;+{'p.ʦ+ZbwSKZݼxngX}<4tFMʒmhMg+Z1Q[HsG΍W:3kcp̬0Č~dXL&'Q#F5NoG)7)^ 9F7>HQ:dNr/%odnMm#`-ҟV_gǟٗ—?a>Ɵi&mH֠׵"uZ M|8hbj`'GO1ic.(ѫV4ԭF3 v~V__S4_Rn4+4aSnqIEsiJRG~f|rU:!_Q4 ZnVtӠ WI'B^<j{z>C'RtHwٵt)$~XnkWYf|}]cUڕ֓|VaW񇋼Ea,Oij ;I`n"c*1\RicqjanT-rQjݵ(F:>e)(RP_,1y5Voܴ ?us;^6ro r|$ைχď i4gq|#"݊]Bo/kz^-|Gg}5i"as1kK:NS9$ TcOu7qizl-ҝ~hB-I\/LѬ-tMtZ[p.Jmgkp[œh ,&zVyJukTZjMԛQ\{Y-֔RRKV_tK4!Jo|?/u7F񆃨wQ|/xoVv[Kuc}jP+pʈNʳVt*Ƭ,NkXZ'&zN 8M;4M=WToceѿd?3x"Rյ n{~=湭_ [\w_Y[Țn"OBSu9UiNY[ZNk~?L3>kG_𗄴}6_O#ԅ{wK\gOQϲE3z8Z89Ƶ9+BU%N-=>UPgfux')GF0aQIk>iKsn8Ú<gf]o_/~-k{JWx'ڜ:Ƨ[}ŷwwv(T 0eٕ|^Tj^HsqN0IєTR3m7`ףAR&G本eCൿo}Oso mW[α^ѳʑ9DT$!51u!VXPq*RRu$٧.Iq^-xh洣NRҝ7)s|#ew/їm&|2~SF׉d9jVNk]/i_MvwXIxjq*J܊\rJ:r[\ /?ƗWOS ۯ+o/Œjn%ys OqFȌ2_u_m7wk;Cn}+9:\ IZ^~Ț௉߶_|QxMvգ4dk5HD(5 9PS8<#J( Jmх wMF[7{{8\R|ѫ i/%km6k-ѥ"HgH8]Jc?y+5ùxRI*)Js,#EJ򔚌TRҎҔ`()6ܚI$n$mWgM OGu SWc SmO`6Z?ku5jWzyx[Kbu^?ⷊ#KO$m7ANi $$RxOE(kMGxI2֔&FqN3I>T(JI71 4okfҋqo]c%+p3[J` <[O>+ S⇇<k>έkYo:Y8{=41][4c)C`ؗ8ѯBjJq.>#k>ԣiĿ|RWg]mMƷH۪B8CܿҤC/gntJ;IsJҩ+oky=],m:ƭFwVZjw-4/HQ/'l6vJ\%ЂjӍ:P:%>i)NRJiJMEnՅsR\q˖)˖+ޓI)Yo Eo? |4_kp_u7AiuLwj:[,WWyPv?iyv qPD*F1PI-9Ui+AS\"y[tq Qr%6=j~'/W6xOD}GͭE` y5M'kdNp٦oX䧃7Z4ESTQ8ԽiP|˞RНFʬЌiҝYJ5>EWiԒ;]o_YOsQ~Agk}Q?O> x.g4_ [ OhڅBE8IǗŸ}T֞U/fV[ouOO*%m |?'G㱶Ҵح]:8 Va'.u[Q%fgoqucu+TVi:qnU&߳Z88H/gN*M^0\򾍨i9;7vrw~#o/g>8 |AzDi᷀ӝy(DO$prC^X -?WT8**}R999Mܪ7vx*پ2&#Q4T n(A($:Wr1)5~ {ik=Y *}C=m%KyűsQwxH yQ[8NhmTpFWwN'4,S|n7P_\R6vǚ*.)N˞k45ƊTPBT(03_wt7&މ>kig%6Kc>%iZKmF$>heq q|FmM&K Mp? ԰2FNhNsjNnr7hFU*¥774㈪Tt%VrXB%'FRdpM6s!_+?7 c_w E}x/G/4+I-*ݤ`=:(>ix1Ŝ[_5JJ9=#(΢4ctW,8J+m8?vIr[m7.|Qiwcz/z_qgklw0!/Gx <-ҵў^ \ENUWU'RN*(TR]% F.QR1 [5QqJNmKT7,ۋqk> Ÿu]U 5֡n.x3N&^C:]O*CWc#S2NexAiVΖ[ͶRmZsrivt}wC3v~_;o/tZ`4"=O֝)|C]AmhݼNVt*up0595*QpS4&Nr5bʑN|uIbq<>zم:4g$f䓔$eAfo wz'OV4œR:8Ctz-Ȼڋ:Req.\ʞ3*Zq)TrœM(Y/2~M+ocͧƍ9J2 V#rZ5>WyI4^OڻᧄfGDӤߎ4 ZbMoR58KWHq]蚆LWikpUkb8Y2`F2 Ur>W*xq\O1O9ɋrE (.m#g7ZW?ScoGyE[xC0 ( ( (g6IJ.rx\%YJL˗I5ʯi$OjL՝;koj( ( (*ꚦiƱ}iZe{*ZYFO)U(Y،`vөZQJJ&ҍ:krvRQ M薉©R*%B*򔝒^%vKVn۾R|4/ !JjgŞ񯈚KGco ~% O$B}3|V4 ݛmy!e?,')x:Y:_,K7{'RVZNQMY;%o)ya)ᩨ›<b$g$rsYݮg7X+?ҿ`%߆.fD-7EŶ_xjqxHd/9?ndkƟ}wepbg5eRh˾UUJ]Ph3J0xL#V\ܪRn)Z7i^|X'k7$2 >goYtxwI׼I-}/o(NjK2$ )5ۈO \љbjd9F'C:xB*Qks7()݂J2oXq98E(-."we>uxCӼK_iNjujuڅ 7H9 >J*Fu!$ԎiJ-%u+-QUiSNTNRkTVi4M5|ry0| \=է/o;1s{4+}\]\44횝rZYYX ⵵ :e&I>i;՞ֽ,ԺTFܪM:Jܥ$)4%{X],࠿R/ Xk|;idT5}WN_it[4 xZ#2Goz.eYk.RO(4Ԩ҄U*8k 4Պiʴs'9xUqќ9a%+ukK%X=>| Gt oK`t8-PDIBk%772Ks!2K!o%'99I9ۓn5ݫhע=Vrog]LA@2{+-, -#h--W{ywheFfGFVBn-J-Qi~kךOF &OFޭ߇ֵ<)-`4-OSxmɶ [+Y q"EGW6RHAJRrWT6aNJ䝣'm R+m%ԞY/XQd:_H?-=0Tb+l_l]__eYE>2R+1NғԛRmr9]=U,ֽE SRkVK(5U_ddyw}IqGۯiKt*%*srrqM$W(iYೋxsAԿcػAOiYj~"Ki|2PO:٥X56z4 U'J}TFuf9;9IuV  BҦ*N=E(ʓN\'$Ӈ*M? +xjONEkgH|K~-; Q"V 'g\GkF>SQ'zSHr8FW{FqyLXpj))Ɯ=vIiYEg~Ɵ_?Eğ ~ԧկt'Z>U+t[zޟKz KtۛbۢbL8ΨSB(hSRIq4I>^nmyaƒx:߼UsT5iwzjӊ=~~f|-aoOiхfԼ]!<_Oyhod);߮[zJVC / uLxæݽ xKȂK{ xU:L^ɬHR =˧g .dQ8-5$ԥ-corYV&%8T((;?}i*Qkf7Ko ^x[k׮/SRGox>6mJmt42$̇ݝHVj> i߳;Aៅ<9pYV]P˝nmBiY&i%|*\S^qu8.iv}j"[(zs %t&e~5 OtSqOo4 exY U|3k&i巃.*f0*W :< ӫFu&ԩԥ ojB#qF.PH(*G>*!%MzSR9ZJMg? x$_X#<]AjZhyZͯ-ζ[vxx42bseL~%beҝ^S_q)O./Q5Z} iBR%Tp uȹc)'tw*ij-zL] /xF2m7Em7mX~ɩJ`j5B*Ig J3N)ŸOS7:CissZ9d;86tu~5y>0k_ ?9<=|`>r{Ě\xm\Ǝx$I!E/76Tq*MUn?TSqrRt饆Ib!A¥())+8{&s_C?wO爖Ŀo/>-xhD[m@.]YDld Z+o2?28NWB0NRiJbIQ./^ӗƷ}Vv_Ty's1xt)>;КD ]]yτ~j8X-iVYޘSԵ Q^"_+x֮>c6 R4IZjMFjuS哧h>>m:x&Uj-J߹G^_hZN3%%ܺo ?qK<_Mx-ī; -#6z@Žȕgy b1.q3Jqu*>ҫm{s-:iW{GNf읽!u(ҥUNm(SSF2rPLsA<$x/]9o;m> y<5k--PX.e(c_²7S"px<<L~:*jPYO9:ҫSN׽5;B*u#r} r%ڌ8NRS'nFug:|sgwoM _'NkT־ >ͭl-CVh{tGQAuey=KV?GfAejեba 6"WgzVیI|NIc \0J9ܰ_&}pz~ʹUn[+fI4xrtOj09 Fi:\xԢhXzwjҼ'P%9Cr½JR\PI K)'QƜeUܯ(-Fpu{ݦk ?+H:/#H \k,dt5Rh?{6q,#%iue:RR|Ѕ8IYMkMҠɥmkfzeDfK0ZIaIw2oqsm4fx%TcV֝9FgQQQ94uuJrFQu):NәÛi^5vT=zo2>•K%![/9? ?>/rYg[`wˍR)KնsxSv?2^#.XRp\Ө}Ȼk{Uœ'5ˍ}W izT5wѴU7hB.RI#F>0࡞=7xg.SZIe{9'khw4 k`i-[+ OBrP(QKR%9r˝rӦe):o7'Teխ9__)#nX*߸X/:_8[_¯9; WpZDDž"q%հ̙78 .XN(Uar3RRZrܩ79Ԍ*USQ$TRVi/qi}qoayoYև%.ɼ 6LM4\;$ImFYqpԣ 1M8JV-qm].dGU՞.7d.O~;vZ?V|-af:?5eOxy;Mn,AKǿeA!:*cqV,,jJ81TBj|ybRoxTˁZ8{JsMRy^sRTSn?wS:$~~V fWlğ$Vج_ |sw.d.c6~gڱH f0̅K 9Ҧ)B3`-)JO߻_(C ڂ"KK_dOkM?V3_;m|U>%4T*|'ZR(4Ihl_^0?k3-3QgMkK&Kkku4$w0AٶʚUC_ SjXwNՍ\i$j1Jk+%&1F9GXnܪ6<_z5xƒ[Kzcexk[{ɡtK쨐( :T+ԥR(T.j}ئo4~n1iQRQm^Wm;;\슑G~u6׾A@zG2˦m!u={_p @ ( ( (B;@.w9f#*NN^S[ﵿڠ ( ( (̡䟕) ' FʶpxzJ6z^NݵV'j35_j?M؊ž#៎Wvdwյ- ؝{Ry5X~_/_9].&u6Qr )˒iWrm/ztO5bYF6zΚ%_(W[MFoV▿jGѣz6]Pҋ[Iss>d 8U!*RR|ZJ:)?yY;O-aa8Ty}N.ZYM=ѿ`?ۇoþ-/l5/Г⇁n?K)izĺJgjyL ]_K~SxWZeB=,Kj5wihNVm._}ץ]t&cIE5y7(},A<jZIee59iQK4ԫ8ӧ ԩ?vS'&'זͯ"[QMɤ%ވ?ିW_fs?gDiTuIb?c^Ӧ沙B;w'#2b1o*U09z|F"ybӓS;5wQ3c?iiKXzNOٿQpJ&O٣}υ^#/I޿Eݧ{mWLsM~ɷ =hV68C*O_(-j$$\Қ撌~)4G 2TR.wM;ek,aN ^F~8_4k֦WGyŚEoqpiB䙚C;NJi[1θs 1UhII7\c$_ m$9~8nUXxsv~"֬4xTZX:ԫ=G_/|TX|Ѧ8W|~iUvVINHKr+7wfխf֗J>n.7 (m9~~_fǿḱ^l\/Zbx]|D OKۙ?s#_rld,ƍ:|,Nڛ9E)*s\$ Y.iRJ$go:J j.nINԜF6+$ҔeN9{Jf?ػI;M7]~*x-4(crU{mg+tfK#9::RueRRoj)+>mծRW-nt;ǚo_Q\Ϧ|+/ks BKF/~0L\ZL$*ƻ~ׂ]'gp)̡Ν9F\J5e(ԌG5 NU%S`V :N즹䤹 7ȟg)%h# ^?ec_w x? > GSּSֿ:׈b/m43C}FP/'&y#Odj*e8*m^XՕhΛ)5nIKJQN>,%hUUt[?t̪Xe`Y\` CpbM馝kXMKN?$-M~)/e?Z/^6*|Amvw)-tIq۷?hH5NMUp52ʒiZZڜe>Ug0PRe)rCxl5,lqX4qTkхU kI?/VkoO;о1x {kZ?+xDQY_h≥^Ѯ/{#V_ lȴ9#CUKy>ۅ|!egĐqiWmrTu)TwpwFQXml3Ԋus:39s'P9jBsY͹A%M9U>?kjo >:i.QYRKK~ks=}J?Q[}OXx|AY~]/iVtܰ?u(*rW+&Ӌ<<#BPp*\J*77>y'y)Hp?oo oQS~Ծ/<n >ǩuu xS $iijHخYpC(rJX<5g9CRĪ3I sINβV<\c$z˚.<Ѫ״ӛZI)F/Wt}~[s5*t|ͪiZy|5-+ំ^ мJkشkyn}N̒4׷s$3oq别SRGvܴK&vI{oOyF1J0cW*]lI.gs_W_(7 k?ռu^i߇-|Kqo :dWhƟm4o/lVN[1}e\.qϲYMjprS)Ɗ;*RQRaFexNl3(rs\b4/X@?Qo/)o(~w_z֟uz7m[Bm;xukSyqF<hSĺ~+n1e|#RU0NN+⥤yy(A˪e7 >ZbO' H%Bt7;+ΜVMss]ӄyo_CeGeI_96x\оѬy4__}˧tftQygJ8F2M)J"Tڄԧ:7xFƌuwj|<\47+'kdkW(N|eW(b־6]c[>r]ު1Տ+$IVɶ\YLqc}l'^X湬RxIh%;&\wPZc{jCw=x=?Ú]k|E"MovkDjWy~/XOKGJTQnqҝ7xp匒Sp(`.HS8R^<ܜmK+^|%|`~>%xKJEx@]]5 n49]i/|E?_9ɱئT8Y*g*[u**n+*q%_SR*RFrN\$I׌9\Q\Y8I?W|~xr?^?:{Gn|Gq?;Ge73r4c:1jjKIrœzqn ss֝q/9oQSݻEtQ.H^5Ai3H|eS~Q# Ykz(xsX|Iz/tnFh>5t$:iYH[%aZ6J4NW%8ܔT"Z<&2jz/g8ڔꦥ4쮤n(YBߴ߄g-E/1N6K}";Z+Y(5 7SV/zܪ_Ji6VPnǕUug# 㗰Tzs+ +FkE5x)~ϕmJ+EǬ~U??f-Vƛ:|WaexOĺXMqq}5sv/e$F5,cxSFJ5e9RJSi:K/u;E5wʄ0*p$eM{qv^D73_/ j6Zo-"6?ϩ~!`O.9GνO' RR[' Sj2+{5+)FShFХB 1N1ZB>TcOT_k؃G ZW~1cwk]R䔝NMNSIss kpeC+)5eJ,MI)(.rp EQ!:(r*Sj)+OkwM_ Z~şc  _ 5?G߉MRv?$5]?P}z)A4$:i5 -r6eBjJUVy}J~TRQoJx~USt3ܤi]K[rIC 1ۺ[_궟>>_|><Yo~/LJy[K{4׼.moep'YajSnPܜdͭ5)JRrm uV_v9{>tEZ+K%edPݿײikgmZso;MF 'm&p<=k]I㾞H`ȼu J8!QBO>P*r5HTMIԅu5iu0f-IRO2Td(|6:wl%GrfxgV4on1TRDԬc<3RUkFZ6Y*8R p,b,_.U$Х4N6V]gW+7OO Şm M^&F&jvEI[=IV$3ݠ}f\14ԣNsR^FPRqR+^牛´4T)NP(ǟhF|;VRj՟>|R9| ,|<s{owk6iOm/O+;b[BT.P/[ӯ+JTpѪ QM)snJ3IAOsQ2aaS &)JJ.2NIDk߇?Qo wƽ}cđoO_5/'hu9&nV 0^<^Mvm҄rkpnUҜU9΋)a^F)F1٨(`~6]ZP5r5(άⒽDZM;FRwQU//iǀ|K5 ce|,,(Vɭc廞+i;=кHcpoo8{!"+b*5#VUT8ҕTBt)ԛ|[^R嚍ZJ>,^Ҳ?P~gſs⮱aOz'h|nHׅ<wx6mtHVX,YH2<¼#&G9GYEB p\R圽8Fhey|Z7s5 67GXkޯGZSJ^үWK|OJEs?:݅nO;j 6ףpT_9:QR%75&s%'q߳\;;r;4JJ\'#n8@{sojOij]mӫH//A5tx~-yu=fÖ {{ 6;{IK즒dS e8.ôraK#SU Pef/i x^N|0昜F"R̜RMwh{-)rI / x:t:NZsbVh5c ~>r̅&kg? a\ƶ..nz:Pt*k㋔ckWQхZ2Oߕӎf<ͦjN'?WZR|b?5U&?/]xϫxO-?k:Z|ᴛD#UC}< t.M{~`hS1 qJTkӤ:mA{ = ]T4_ĜWMOV[BH  1<E9|vq7zjݗf|Z&ߡ~D[3'_?Z{_rC?^ ռ_ ;\\|UskH ϑ%Y[Gl 2"YU ѕ?m "jּڌ$SaNrڵqVjS4=HB"ӝܭ}&}O~n}?HJb ( ( ( ( ( (8|2s/x~tquh4x, ͭq:d9Nu7 %׭:q:tnJs7N6VIFM$ҽ-ҖZSUSrʢTvr3WIٶ]W/ߴ|QvZj V76|<^i<+-i[mv,̱Y>28HZj?糯 Qq*nt۴ 8)N5Mh^.IUFS ~|}x=$0^_TڏV/4Zd6RZ4koquq,#yOpm⩺ UUG$Ռjui]*Pѧ/MTI5>MZM,K.|#c㷉4ij>3Դ+ Y/–o07$B|҆@lGpXr 1&,buZj2^nwo{sYoMCCǏj7>tfտ>G(7͠OL`,:2:HZ΄yfY(Cpo[5(ҋ(qԽtu.1^T{t]OV|]xAG?o); ?N񷅬NOuKFo|?J[OncmEoO^/~$thզ𶙧kwciaؾ!J^/3lRVPٹN*ټuzҍyU:oRMnk?o>|I61 )d+iNaO.;F4kZ"c.o/BDn/8kbj/u:%.TSqM ʗ3W}Z҅(*1ZY|ޭ~O|S)x Tߎ+AW#=} \nin%JRO)y~?13#ZT]9OZַ+׼fE1AGF*ʹXg?#g_~3|^~(2 k5y6;+E]Fѧr4DRm~1]QXX>nZMCcNij⮢(=|€ ( *~%h/j&~i֋ۍ7ĺi-[ȑjvM:41c eAʰxhp[MՇO߃Ş:5֑h?4_Cl$Nr$2`Ύ fxܺsPOU w抜ud/GR/9ҧU8Fn9E7=߲?He5? ѼI$P?m0Kknc|l`;8T5 IM.iTnZ]FNI1taF6}^qP_=@ּ+MG^hi:Γ@fat[^YBżr)/X|N# 8WQJIҋMŤ'}TqT?+k ~ QGuk/|3f0Gj:p)[܄cou/wC ෻[{a9" hdXb),2R)WH*%7(-4ӕx%kTe4ItWVjG6kw{]r/}-^>)<:P|+ӴO[tgݢGfy2o8.X*Qteov8I nD9V7+rwrwWw{~vi:NcgZ]iuZ~@֖66Q0qDj[wzۻow[>%߲-޷xJ^(е :%-1-ŝŴƗP\~-^SyKN, hӧVj(s5;FN A4ۊPtr0K|*ni4Ҕ&նlɿOW'ԠÚW^w>B͎[Ë-=e-/t{g #+Ɏ1ٌUsNe.Kǚߔﮎ\I&,=::]3+%6}\Kg~ |:_/~(&xci.$Xn4ӭC]_\[+ٖeճ\e­U>I%tQJ8Ũr?zJ.mg^0Vcm#g&۲I6zuo +AI(ڷ#~յ&xŸO>w|Z8{'9E<:^yhY?Dlm,Od4W%<<%M9:tജtܹ&9ORrgR+MFUg6S*r|\*:&nTQIh]\tH ghk[Dz&xbE,3F" GS;Jt'N4$e~՚MiI֏I=E(a(% QFR8E*/ʠswyJMRnSiWm[{ik42[mo-E< &%ܱcpfg"P5q%(QpqvjQ^앗2o+iz5.][=2dyqFncĶhVYU*ںmemdk٭o."5Nw"..Xc=UrppADVvQ} Hr_ɵ;x˹%7>2D9:YS&Iɷ[zc.X1]_r%P@P@iK4bG# @$1"8ϊWK~zj֕K)t['*tӅ5IiwAD;w1-@U`[ (/sRnRr-99KI.ozMRzY$V)%in2 (F2"wv 37TIuMFscrcEsc&I]Mdn%{+u?o4V?-֡\u |]}%l-~Y5"Ya6Ikqmi 2_ PV-G 0J1*Z mhA+G˨*i7,L%MFRQQM]sm_V Xa+kkxc` QFEjhTU Wnmmm~=H)`4cIb),r22e%XH&OK[NVO5'}ﮝpOυ׷:hm'ӥIg3ӴeA 01Ni[FJᄎrN˧INK|)_S,;gte]]Xp@9;6WPmwhU0bQi|6\\RI)sI(Ek+;}nw]wztj[e!O4b4|mt{MZm%-+[9=%?h7 O:KԩB:v)OANsԹU r\6Ibecqbjӄ$w5VIF*Ҽ"G~͚/3|&ǂ<3kxjk/O+wqh6Eւ#EY*̯H1ycqu'kRnT.uY%&-/m]Ss?hGӿ_?}ZWS=;ѵMc\<7z׈d}XӴ}>T'JC.kwz)+N!F*Ra:)FSҌSI%-"Vohv۲Zݒ}^ =}3T+躿? ( ( (.x=9*$ `Q_-VIofw%  ( ( ( ( ( ( ( ( ( ( _|n~^/uCÞ/.Kco.[jFki,;cm\OC(ӧ Se)EɪiIFJqq\ydڒB~{))-WQkTR ,|gwj~uMs[5 5k_kOQ8$#Fe|Φmҍ598]^rv˫TiF5^E%^K]MP@P@P@P@P@PƟP/h.)rĿZψ~ x[msŚ-ayon-/Om牪cp(MOU9gc-y!ͼe%r`Cs9E^ 8t9r2V{_[V_w=)( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (WNNhIm,Jb (>\tmZ_^-_@GϷ83ס+}'?ߟLBP@P@P@P@P@P@F!u9_2 ɿXp_3?lNQˈ?+&œo;aϬWKF!u9GC. q>_ /\3oD o)?4pbL!_?2 ɿXp_b_LVVrAw `K)>̧ } _OC D7gr\AAY7 }b_?1&gۯ ?qdSp8/i?Cn6?'(eN7+˃#f 蜣!VM8wÂX.C D7gr\AAY7 }b_?1&gۯ ?qdSp8/i?Cn6?'(eN7+˃#f 蜣!VM8wÂX.C D7gr\AAY7 }b_?1&gۯ ?qdSp8/i?Cn6?'(eN7+˃#f 蜣!VM8wÂX.C D7gr\AAY7 }b_?1&gۯ ?qdSp8/i?Cn6?'(eN7+˃#f 蜣!VM8wÂX.C D7gr\AAY7 }b_?1&gۯ ?qdSp8/i?Cn6?'(eN7+˃#f 蜣!VM8wÂX.C D7gr\AAY7 }b_?1&gۯ ?qdSp8/i?Cn6?'(eN7+˃#f 蜣!VM8wÂX.C D7gr\AAY7 }b_?1&gۯ ?qdSp8/i?Cn6?'(eN7+˃#f 蜣!VM8wÂX.C D7gr\AAY7 }b_?1&gۯ ?qdSp8/i?Cn6?'(eN7+˃#f 蜣!VM8wÂX.C D7gr\AAY7 }b_?1&gۯ ?qdSp8/i?Cn6?'(eN7+˃#f 蜣!VM8wÂX.C D7gr\AAY7 }b_?1&gۯ ?qdSp8/i?Cn6?'(eN7+˃#f 蜣!VM8wÂX.C D7gr\AAY7 }b_?1&gۯ ?qdSp8/i?Cn6?'(eN7+˃#f 蜣!VM8wÂX.C D7gr\AAY7 }b_?1&gۯ ?qdSp8/i?Cn6?'(eN7+˃#f 蜣!VM8wÂX.C D7gr\AAY7 }b_?1&gۯ ?qdSp8/i?Cn6?'(eN7+˃#f 蜣!VM8wÂX.C D7gr\AAY7 }b_?1&gۯ ?qdSp8/i?Cn6?'(eN7+˃#f 蜣!VM8wÂX.C D7gr\AAY7 }b_?1&gۯ ?qdSp8/i?Cn6?'(eN7+˃#f 蜣!VM8wÂX.C D7gr\AAY7 }b_?1&o۫ 9\^Oc_8/)?1&o۫  s ?+#f 蜣!}AyGc?x3oD/\AAY7 }b_?1&gۯ ?qdSp8/i?Cn6?'(eN7+˃#f 蜣!VM8wÂX.C D7gr\AAY7 }b_?1&gۯ ?qdSp8/i?Cn6?'(eN7+˃#f 蜣!VM8wÂX.C D7gr\AAY7 }b_?1&gۯ ?qdSp8/i?Cn6?'(eN7+˃#f 蜣!VM8wÂX.C D7gr\AAY7 }b_?1&gۯ ?qdSp8/i?Cn6?'(eN7+˃#f 蜣!VM8wÂX.C D7gr\AAY7 }b_OC D7grC(8/)?Cn6?'(c^Q`>_/^7oD s ?+#f 蜣!}AyGc?xbL!W?1Ͽ/(Œo0ÂX/#f 蜣!AyGc }b _?1&gۯ _ o)?4pbL!_?2 ɿXp_3?lNQˈ?+&œo;aϬWKF!u9GC. q>_ /\3oD o)?4pbL!_?2 ɿXp_3?lNQˈ?+&œo;aϬWKmagrittr/R/0000755000176200001440000000000014174203034012302 5ustar liggesusersmagrittr/R/magrittr.R0000644000176200001440000000337113712024462014265 0ustar liggesusers#' magrittr - Ceci n'est pas un pipe #' #' The magrittr package offers a set of operators which promote semantics #' that will improve your code by #' \itemize{ #' \item structuring sequences of data operations left-to-right #' (as opposed to from the inside and out), #' \item avoiding nested function calls, #' \item minimizing the need for local variables and function definitions, and #' \item making it easy to add steps anywhere in the sequence of operations. #' } #' The operators pipe their left-hand side values forward into expressions that #' appear on the right-hand side, i.e. one can replace `f(x)` with #' \code{x \%>\% f}, where \code{\%>\%} is the (main) pipe-operator. #' #' Consider the example below. Four operations are performed to #' arrive at the desired data set, and they are written in a natural order: #' the same as the order of execution. Also, no temporary variables are needed. #' If yet another operation is required, it is straight-forward to add to the #' sequence of operations whereever it may be needed. #' #' For a more detailed introduction see the vignette #' (`vignette("magrittr")`) or the documentation pages for the #' available operators:\cr #' \tabular{ll}{ #' \code{\link{\%>\%}} \tab pipe.\cr #' \code{\link{\%T>\%}} \tab tee pipe.\cr #' \code{\link{\%<>\%}} \tab assignment pipe.\cr #' \code{\link{\%$\%}} \tab exposition pipe.\cr #' } #' #' @useDynLib magrittr, .registration = TRUE #' @examples #' \dontrun{ #' #' the_data <- #' read.csv('/path/to/data/file.csv') %>% #' subset(variable_a > x) %>% #' transform(variable_c = variable_a/variable_b) %>% #' head(100) #' } #' @keywords internal "_PACKAGE" .onLoad <- function(lib, pkg) { .Call(magrittr_init, asNamespace("magrittr")) } magrittr/R/functions.R0000644000176200001440000000162013701613606014441 0ustar liggesusers#' Extract the function list from a functional sequence. #' #' This can be used to extract the list of functions inside a functional #' sequence created with a chain like \code{. \%>\% foo \%>\% bar}. #' #' @param fseq A functional sequence ala magrittr. #' @return a list of functions #' #' @export functions <- function(fseq) { if (!"fseq" %in% class(fseq)) stop("Object is not a functional sequence.", call. = FALSE) environment(fseq)[["_function_list"]] } #' Print method for functional sequence. #' #' @param x A functional sequence object #' @param ... not used. #' @return x #' #' @export print.fseq <- function(x, ...) { flist <- functions(x) cat("Functional sequence with the following components:\n\n") lapply(seq_along(flist), function(i) cat(" ", i, ". ", deparse(body(flist[[i]])), "\n", sep = "")) cat("\nUse 'functions' to extract the individual functions.", "\n") x } magrittr/R/getters.R0000644000176200001440000000127213106333523014105 0ustar liggesusers#' Extract function(s) from a functional sequence. #' #' Functional sequences can be subset using single or double brackets. #' A single-bracket subset results in a new functional sequence, and #' a double-bracket subset results in a single function. #' #' @rdname fseq #' @param x A functional sequence #' @param ... index/indices. For double brackets, the index must be of length 1. #' @return A function or functional sequence. #' @export `[[.fseq` <- function(x, ...) { functions(x)[[...]] } #' @rdname fseq #' @export `[.fseq` <- function(x, ...) { y <- x environment(y) <- new.env(parent = parent.env(environment(x))) environment(y)[["_function_list"]] <- functions(x)[...] y } magrittr/R/debug_pipe.R0000644000176200001440000000212614174200546014536 0ustar liggesusers#' Debugging function for magrittr pipelines. #' #' This function is a wrapper around `browser`, which makes it #' easier to debug at certain places in a magrittr pipe chain. #' #' @param x a value #' @return x #' #' @export debug_pipe <- function(x) { browser() x } #' Debugging function for functional sequences. #' #' This is a utility function for marking functions in a functional #' sequence for debbuging. #' #' @param fseq a functional sequence. #' @param ... indices of functions to debug. #' @return `invisible(NULL)`. #' #' @export debug_fseq <- function(fseq, ...) { is_valid_index <- function(i) i %in% seq_along(functions(fseq)) indices <- list(...) if (!any(vapply(indices, is.numeric, logical(1L))) || !any(vapply(indices, is_valid_index, logical(1L)))) stop("Index or indices invalid.", call. = FALSE) invisible(lapply(indices, function(i) debug(functions(fseq)[[i]]))) } #' @rdname debug_fseq #' @export undebug_fseq <- function(fseq) { for (i in seq_along(functions(fseq))) if (isdebugged(functions(fseq)[[i]])) undebug(functions(fseq)[[i]]) } magrittr/R/freduce.R0000644000176200001440000000121413754711147014054 0ustar liggesusers#' Apply a list of functions sequentially #' #' This function applies the first function to `value`, then the #' next function to the result of the previous function call, etc. #' #' @param value initial value. #' @param function_list a list of functions. #' @return The result after applying each function in turn. #' #' #' @export freduce <- function(value, function_list) { k <- length(function_list) if (k > 1) { for (i in 1:(k - 1L)) { value <- function_list[[i]](value) } } value <- withVisible(function_list[[k]](value)) if (value[["visible"]]) { value[["value"]] } else { invisible(value[["value"]]) } } magrittr/R/pipe.R0000644000176200001440000002716414174203034013374 0ustar liggesusers#' Pipe #' #' Pipe an object forward into a function or call expression. #' #' @param lhs A value or the magrittr placeholder. #' @param rhs A function call using the magrittr semantics. #' @details #' \subsection{Using `%>%` with unary function calls}{ #' #' When functions require only one argument, `x %>% f` is equivalent #' to `f(x)` (not exactly equivalent; see technical note below.) #' #' } #' \subsection{Placing `lhs` as the first argument in `rhs` call}{ #' #' The default behavior of `%>%` when multiple arguments are required #' in the `rhs` call, is to place `lhs` as the first argument, i.e. #' `x %>% f(y)` is equivalent to `f(x, y)`. #' } #' \subsection{Placing `lhs` elsewhere in `rhs` call}{ #' #' Often you will want `lhs` to the `rhs` call at another position than the first. #' For this purpose you can use the dot (`.`) as placeholder. For example, #' `y %>% f(x, .)` is equivalent to `f(x, y)` and #' `z %>% f(x, y, arg = .)` is equivalent to `f(x, y, arg = z)`. #' } #' #' \subsection{Using the dot for secondary purposes}{ #' #' Often, some attribute or property of `lhs` is desired in the `rhs` call in #' addition to the value of `lhs` itself, e.g. the number of rows or columns. #' It is perfectly valid to use the dot placeholder several times in the `rhs` #' call, but by design the behavior is slightly different when using it inside #' nested function calls. In particular, if the placeholder is only used #' in a nested function call, `lhs` will also be placed as the first argument! #' The reason for this is that in most use-cases this produces the most readable #' code. For example, `iris %>% subset(1:nrow(.) %% 2 == 0)` is #' equivalent to `iris %>% subset(., 1:nrow(.) %% 2 == 0)` but #' slightly more compact. It is possible to overrule this behavior by enclosing #' the `rhs` in braces. For example, `1:10 %>% {c(min(.), max(.))}` is #' equivalent to `c(min(1:10), max(1:10))`. #' } #' #' \subsection{Using `%>%` with call- or function-producing `rhs`}{ #' #' It is possible to force evaluation of `rhs` before the piping of `lhs` takes #' place. This is useful when `rhs` produces the relevant call or function. #' To evaluate `rhs` first, enclose it in parentheses, i.e. #' `a %>% (function(x) x^2)`, and `1:10 %>% (call("sum"))`. #' Another example where this is relevant is for reference class methods #' which are accessed using the `$` operator, where one would do #' `x %>% (rc$f)`, and not `x %>% rc$f`. #' } #' #' \subsection{Using lambda expressions with `%>%`}{ #' #' Each `rhs` is essentially a one-expression body of a unary function. #' Therefore defining lambdas in magrittr is very natural, and as #' the definitions of regular functions: if more than a single expression #' is needed one encloses the body in a pair of braces, \code{\{ rhs \}}. #' However, note that within braces there are no "first-argument rule": #' it will be exactly like writing a unary function where the argument name is #' "`.`" (the dot). #' #' } #' \subsection{Using the dot-place holder as `lhs`}{ #' #' When the dot is used as `lhs`, the result will be a functional sequence, #' i.e. a function which applies the entire chain of right-hand sides in turn #' to its input. See the examples. #' } #' #' @section Technical notes: #' The magrittr pipe operators use non-standard evaluation. They capture #' their inputs and examines them to figure out how to proceed. First a function #' is produced from all of the individual right-hand side expressions, and #' then the result is obtained by applying this function to the left-hand side. #' For most purposes, one can disregard the subtle aspects of magrittr's #' evaluation, but some functions may capture their calling environment, #' and thus using the operators will not be exactly equivalent to the #' "standard call" without pipe-operators. #' #' #' Another note is that special attention is advised when using non-magrittr #' operators in a pipe-chain (`+, -, $,` etc.), as operator precedence will impact how the #' chain is evaluated. In general it is advised to use the aliases provided #' by magrittr. #' #' @seealso \code{\link{\%<>\%}}, \code{\link{\%T>\%}}, \code{\link{\%$\%}} #' #' @examples #' # Basic use: #' iris %>% head #' #' # Use with lhs as first argument #' iris %>% head(10) #' #' # Using the dot place-holder #' "Ceci n'est pas une pipe" %>% gsub("une", "un", .) #' #' # When dot is nested, lhs is still placed first: #' sample(1:10) %>% paste0(LETTERS[.]) #' #' # This can be avoided: #' rnorm(100) %>% {c(min(.), mean(.), max(.))} %>% floor #' #' # Lambda expressions: #' iris %>% #' { #' size <- sample(1:10, size = 1) #' rbind(head(., size), tail(., size)) #' } #' #' # renaming in lambdas: #' iris %>% #' { #' my_data <- . #' size <- sample(1:10, size = 1) #' rbind(head(my_data, size), tail(my_data, size)) #' } #' #' # Building unary functions with %>% #' trig_fest <- . %>% tan %>% cos %>% sin #' #' 1:10 %>% trig_fest #' trig_fest(1:10) #' #' @rdname pipe #' @export `%>%` <- function(lhs, rhs) { lhs <- substitute(lhs) rhs <- substitute(rhs) kind <- 1L env <- parent.frame() lazy <- TRUE .External2(magrittr_pipe) } #' Lazy and eager pipes #' #' Assign these pipe variants to an infix symbol like `%>%`. #' #' @inheritParams %>% #' @keywords internal #' @export pipe_eager_lexical <- function(lhs, rhs) { lhs <- substitute(lhs) rhs <- substitute(rhs) kind <- 1L env <- parent.frame() sym <- sys.call()[[1]] .External2(magrittr_pipe) } #' @rdname pipe_eager_lexical #' @export pipe_lazy_masking <- function(lhs, rhs) { lhs <- substitute(lhs) rhs <- substitute(rhs) kind <- 1L env <- parent.frame() lazy <- TRUE sym <- sys.call()[[1]] .External2(magrittr_pipe) } #' @rdname pipe_eager_lexical #' @export pipe_nested <- function(lhs, rhs) { lhs <- substitute(lhs) rhs <- substitute(rhs) kind <- 1L env <- parent.frame() nested <- TRUE sym <- sys.call()[[1]] .External2(magrittr_pipe) } #' Assignment pipe #' #' Pipe an object forward into a function or call expression and update the #' `lhs` object with the resulting value. #' #' @param lhs An object which serves both as the initial value and as target. #' @param rhs a function call using the magrittr semantics. #' #' @details The assignment pipe, \code{\%<>\%}, is used to #' update a value by first piping it into one or more `rhs` expressions, and #' then assigning the result. For example, \code{some_object \%<>\% #' foo \%>\% bar} is equivalent to \code{some_object <- some_object \%>\% foo #' \%>\% bar}. It must be the first pipe-operator in a chain, but otherwise it #' works like \code{\link{\%>\%}}. #' #' @seealso \code{\link{\%>\%}}, \code{\link{\%T>\%}}, \code{\link{\%$\%}} #' #' @examples #' iris$Sepal.Length %<>% sqrt #' #' x <- rnorm(100) #' #' x %<>% abs %>% sort #' #' is_weekend <- function(day) #' { #' # day could be e.g. character a valid representation #' day %<>% as.Date #' #' result <- day %>% format("%u") %>% as.numeric %>% is_greater_than(5) #' #' if (result) #' message(day %>% paste("is a weekend!")) #' else #' message(day %>% paste("is not a weekend!")) #' #' invisible(result) #' } #' #' @rdname compound #' @export `%<>%` <- function(lhs, rhs) { lhs <- substitute(lhs) rhs <- substitute(rhs) kind <- 2L lazy <- TRUE env <- parent.frame() .External2(magrittr_pipe) } #' Tee pipe #' #' Pipe a value forward into a function- or call expression and return the #' original value instead of the result. This is useful when an expression #' is used for its side-effect, say plotting or printing. #' #' @param lhs A value or the magrittr placeholder. #' @param rhs A function call using the magrittr semantics. #' #' @details The tee pipe works like \code{\link{\%>\%}}, except the #' return value is `lhs` itself, and not the result of `rhs` function/expression. #' #' @seealso \code{\link{\%>\%}}, \code{\link{\%<>\%}}, \code{\link{\%$\%}} #' #' @examples #' rnorm(200) %>% #' matrix(ncol = 2) %T>% #' plot %>% # plot usually does not return anything. #' colSums #' #' @rdname tee #' @export `%T>%` <- function(lhs, rhs) { lhs <- substitute(lhs) rhs <- substitute(rhs) kind <- 3L lazy <- TRUE env <- parent.frame() .External2(magrittr_pipe) } #' Exposition pipe #' #' Expose the names in `lhs` to the `rhs` expression. This is useful when functions #' do not have a built-in data argument. #' #' @param lhs A list, environment, or a data.frame. #' @param rhs An expression where the names in lhs is available. #' #' @details Some functions, e.g. `lm` and `aggregate`, have a #' data argument, which allows the direct use of names inside the data as part #' of the call. This operator exposes the contents of the left-hand side object #' to the expression on the right to give a similar benefit, see the examples. #' @seealso \code{\link{\%>\%}}, \code{\link{\%<>\%}}, \code{\link{\%T>\%}} #' #' @examples #' iris %>% #' subset(Sepal.Length > mean(Sepal.Length)) %$% #' cor(Sepal.Length, Sepal.Width) #' #' data.frame(z = rnorm(100)) %$% #' ts.plot(z) #' #' @rdname exposition #' @export `%$%` <- function(lhs, rhs) { lhs <- substitute(lhs) rhs <- substitute(rhs) kind <- 4L lazy <- TRUE env <- parent.frame() .External2(magrittr_pipe) } new_lambda <- function(exprs, env) { `_function_list` <- lapply(exprs, as_pipe_fn, env) structure( function(value) freduce(value, `_function_list`), class = c("fseq", "function") ) } lambda_fmls <- as.pairlist(alist(. = )) as_pipe_fn <- function(expr, env) { eval(call("function", lambda_fmls, expr), env) } #' FAQ: What is the gender of the pipe? #' #' In Magritte's original quote "Ceci n'est pas une pipe," the word #' "pipe" is feminine. However the magrittr package quotes it as #' "Ceci n'est pas un pipe," with a masculine "pipe." This #' lighthearted misappropriation is intentional. Whereas the #' object represented in Magritte's painting (a pipe that you can #' smoke) is feminine in the French language, a computer pipe #' (which is an Anglicism in French) is masculine. #' #' @name faq-pipe-gender NULL #' Eager pipe #' #' @description #' Whereas `%>%` is lazy and only evaluates the piped expressions when #' needed, `%!>%` is eager and evaluates the piped input at each step. #' This produces more intuitive behaviour when functions are called #' for their side effects, such as displaying a message. #' #' Note that you can also solve this by making your function #' strict. Call `force()` on the first argument in your function to #' force sequential evaluation, even with the lazy `%>%` pipe. #' See the examples section. #' #' @inheritParams %>% #' #' @examples #' f <- function(x) { #' message("foo") #' x #' } #' g <- function(x) { #' message("bar") #' x #' } #' h <- function(x) { #' message("baz") #' invisible(x) #' } #' #' # The following lazy pipe sequence is equivalent to `h(g(f()))`. #' # Given R's lazy evaluation behaviour,`f()` and `g()` are lazily #' # evaluated when `h()` is already running. This causes the messages #' # to appear in reverse order: #' NULL %>% f() %>% g() %>% h() #' #' # Use the eager pipe to fix this: #' NULL %!>% f() %!>% g() %!>% h() #' #' # Or fix this by calling `force()` on the function arguments #' f <- function(x) { #' force(x) #' message("foo") #' x #' } #' g <- function(x) { #' force(x) #' message("bar") #' x #' } #' h <- function(x) { #' force(x) #' message("baz") #' invisible(x) #' } #' #' # With strict functions, the arguments are evaluated sequentially #' NULL %>% f() %>% g() %>% h() #' #' # Instead of forcing, you can also check the type of your functions. #' # Type-checking also has the effect of making your function lazy. #' #' @name pipe-eager #' @export `%!>%` <- pipe_eager_lexical magrittr/R/aliases.R0000644000176200001440000000767313701613606014070 0ustar liggesusers#' Aliases #' #' magrittr provides a series of aliases which can be more pleasant to use #' when composing chains using the \code{\%>\%} operator. #' #' Currently implemented aliases are #' \tabular{ll}{ #' \code{extract} \tab \code{`[`} \cr #' \code{extract2} \tab \code{`[[`} \cr #' \code{inset} \tab \code{`[<-`} \cr #' \code{inset2} \tab \code{`[[<-`} \cr #' \code{use_series} \tab \code{`$`} \cr #' \code{add} \tab \code{`+`} \cr #' \code{subtract} \tab \code{`-`} \cr #' \code{multiply_by} \tab \code{`*`} \cr #' \code{raise_to_power} \tab \code{`^`} \cr #' \code{multiply_by_matrix} \tab \code{`\%*\%`} \cr #' \code{divide_by} \tab \code{`/`} \cr #' \code{divide_by_int} \tab \code{`\%/\%`} \cr #' \code{mod} \tab \code{`\%\%`} \cr #' \code{is_in} \tab \code{`\%in\%`} \cr #' \code{and} \tab \code{`&`} \cr #' \code{or} \tab \code{`|`} \cr #' \code{equals} \tab \code{`==`} \cr #' \code{is_greater_than} \tab \code{`>`} \cr #' \code{is_weakly_greater_than} \tab \code{`>=`} \cr #' \code{is_less_than} \tab \code{`<`} \cr #' \code{is_weakly_less_than} \tab \code{`<=`} \cr #' \code{not} (\code{`n'est pas`}) \tab \code{`!`} \cr #' \code{set_colnames} \tab \code{`colnames<-`} \cr #' \code{set_rownames} \tab \code{`rownames<-`} \cr #' \code{set_names} \tab \code{`names<-`} \cr #' \code{set_class} \tab \code{`class<-`} \cr #' \code{set_attributes} \tab \code{`attributes<-`} \cr #' \code{set_attr } \tab \code{`attr<-`} \cr #' } #' #' @usage NULL #' @export #' @rdname aliases #' @name extract #' @examples #' iris %>% #' extract(, 1:4) %>% #' head #' #' good.times <- #' Sys.Date() %>% #' as.POSIXct %>% #' seq(by = "15 mins", length.out = 100) %>% #' data.frame(timestamp = .) #' #' good.times$quarter <- #' good.times %>% #' use_series(timestamp) %>% #' format("%M") %>% #' as.numeric %>% #' divide_by_int(15) %>% #' add(1) extract <- `[` #' @rdname aliases #' @usage NULL #' @export extract2 <- `[[` #' @rdname aliases #' @usage NULL #' @export use_series <- `$` #' @rdname aliases #' @usage NULL #' @export add <- `+` #' @rdname aliases #' @usage NULL #' @export subtract <- `-` #' @rdname aliases #' @usage NULL #' @export multiply_by <- `*` #' @rdname aliases #' @usage NULL #' @export multiply_by_matrix <- `%*%` #' @rdname aliases #' @usage NULL #' @export divide_by <- `/` #' @rdname aliases #' @usage NULL #' @export divide_by_int <- `%/%` #' @rdname aliases #' @usage NULL #' @export raise_to_power <- `^` #' @rdname aliases #' @usage NULL #' @export and <- `&` #' @rdname aliases #' @usage NULL #' @export or <- `|` #' @rdname aliases #' @usage NULL #' @export mod <- `%%` #' @rdname aliases #' @usage NULL #' @export is_in <- `%in%` #' @rdname aliases #' @usage NULL #' @export equals <- `==` #' @rdname aliases #' @usage NULL #' @export is_greater_than <- `>` #' @rdname aliases #' @usage NULL #' @export is_weakly_greater_than <- `>=` #' @rdname aliases #' @usage NULL #' @export is_less_than <- `<` #' @rdname aliases #' @usage NULL #' @export is_weakly_less_than <- `<=` #' @rdname aliases #' @usage NULL #' @export not <- `!` #' @rdname aliases #' @usage NULL #' @export `n'est pas` <- `!` #' @rdname aliases #' @usage NULL #' @export set_colnames <- `colnames<-` #' @rdname aliases #' @usage NULL #' @export set_rownames <- `rownames<-` #' @rdname aliases #' @usage NULL #' @export set_names <- `names<-` #' @rdname aliases #' @usage NULL #' @export set_class <- `class<-` #' @rdname aliases #' @usage NULL #' @export inset <- `[<-` #' @rdname aliases #' @usage NULL #' @export inset2 <- `[[<-` #' @rdname aliases #' @usage NULL #' @export set_attr <- `attr<-` #' @rdname aliases #' @usage NULL #' @export set_attributes <- `attributes<-` magrittr/NEWS.md0000644000176200001440000001453314174206236013214 0ustar liggesusers# magrittr 2.0.2 * New eager pipe `%!>%` for sequential evaluation (#247). Consider using `force()` in your functions instead to make them strict, if sequentiality is required. See the examples in `?"pipe-eager"`. * Fixed an issue that could cause pipe invocations to fail in versions of R built with `--enable-strict-barrier`. (#239, @kevinushey) # magrittr 2.0.1 * Fixed issue caused by objects with certain names being present in the calling environment (#233). * Fixed regression in `freduce()` with long lists (kcf-jackson/sketch#5). # magrittr 2.0.0 ## Fast and lean implementation of the pipe The pipe has been rewritten in C with the following goals in mind: - Minimal performance cost. - Minimal impact on backtraces. - No impact on reference counts. As part of this rewrite we have changed the behaviour of the pipe to make it closer to the implementation that will likely be included in a future version of R. The pipe now evaluates piped expressions lazily (#120). The main consequence of this change is that warnings and errors can now be handled by trailing pipe calls: ```r stop("foo") %>% try() warning("bar") %>% suppressWarnings() ``` ## Breaking changes The pipe rewrite should generally not affect your code. We have checked magrittr on 2800 CRAN packages and found only a dozen of failures. The development version of magrittr has been advertised on social media for a 3 months trial period, and no major issues were reported. However, there are some corner cases that might require updating your code. Below is a report of the backward incompatibilities we found in real code to help you transition, should you find an issue in your code. ### Behaviour of `return()` in a pipeline In previous versions of magrittr, the behaviour of `return()` within pipe expressions was undefined. Should it return from the current pipe expression, from the whole pipeline, or from the enclosing function? The behaviour that makes the most sense is to return from the enclosing function. However, we can't make this work easily with the new implementation, and so calling `return()` is now an error. ```r my_function <- function(x) { x %>% { if (.) return("true") "false" } } my_function(TRUE) #> Error: no function to return from, jumping to top level ``` In magrittr 1.5, `return()` used to return from the current pipe expression. You can rewrite this to the equivalent: ```r my_function <- function(x) { x %>% { if (.) { "true" } else { "false" } } } my_function(TRUE) #> [1] "true" ``` For backward-compatibility we have special-cased trailing `return()` calls as this is a common occurrence in packages: ```r 1 %>% identity() %>% return() ``` Note however that this only returns from the pipeline, not the enclosing function (which is the historical behaviour): ```r my_function <- function() { "value" %>% identity() %>% return() "wrong value" } my_function() #> [1] "wrong value" ``` It is generally best to avoid using `return()` in a pipeline, even if trailing. ### Failures caused by laziness With the new lazy model for the evaluation of pipe expressions, earlier parts of a pipeline are not yet evaluated when the last pipe expression is called. They only get evaluated when the last function actually uses the piped arguments: ```r ignore <- function(x) "return value" stop("never called") %>% ignore() #> [1] "return value" ``` This should generally not cause problems. However we found some functions with special behaviour, written under the assumption that earlier parts of the pipeline were already evaluated and had already produced side effects. This is generally incorrect behaviour because that means that these functions do not work properly when called with the nested form, e.g. `f(g(1))` instead of `1 %>% g() %>% f()`. The solution to fix this is to call `force()` on the inputs to force evaluation, and only then check for side effects: ```r my_function <- function(data) { force(data) peek_side_effect() } ``` Another issue caused by laziness is that if any function in a pipeline returns invisibly, than the whole pipeline returns invisibly as well. ```r 1 %>% identity() %>% invisible() 1 %>% invisible() %>% identity() 1 %>% identity() %>% invisible() %>% identity() ``` This is consistent with the equivalent nested code. This behaviour can be worked around in two ways. You can force visibility by wrapping the pipeline in parentheses: ```r my_function <- function(x) { (x %>% invisible() %>% identity()) } ``` Or by assigning the result to a variable and return it: ```r my_function <- function(x) { out <- x %>% invisible() %>% identity() out } ``` ### Incorrect call stack introspection The magrittr expressions are no longer evaluated in frames that can be inspected by `sys.frames()` or `sys.parent()`. Using these functions for implementing actual functionality (as opposed as debugging tools) is likely to produce bugs. Instead, you should generally use `parent.frame()` which works even when R code is called from non-inspectable frames. This happens with e.g. `do.call()` and the new C implementation of magrittr. ### Incorrect assumptions about magrittr internals Some packages were depending on how magrittr was internally structured. Robust code should only use the documented and exported API of other packages. ## Bug fixes * Can now use the placeholder `.` with the splicing operator `!!!` from rlang (#191). * Piped arguments are now persistent. They can be evaluated after the pipeline has returned, which fixes subtle issues with function factories (#159, #195). # magrittr 1.5 ## New features ### Functional sequences. A pipeline, or a "functional sequence", need not be applied to a left-hand side value instantly. Instead it can serve as a function definition. A pipeline where the left-most left-hand side is the magrittr placeholder (the dot `.`) will thus create a function, which applies each right-hand side in sequence to its argument, e.g. `f <- . %>% abs %>% mean(na.rm = TRUE)`. ### New operators Three new operators are introduced for some special cases * Assignment pipe: `%<>%` * Tee pipe: `%T>%` * Exposition pipe: `%$%` For more information see the documentation, e.g. `?%T>%`. ### Lambdas Lambdas can now be made by enclosing several statements in curly braces, and is a unary function of the dot argument. For more information and examples, see the updated vignette, and help files. magrittr/MD50000644000176200001440000000574414174264634012440 0ustar liggesusersc0671668f2469eaa7a760edcdefb659b *DESCRIPTION b1e40687f249a5e3b384b410b621f40a *LICENSE 6947759fe41ccdda4f5fd4759f68a4a8 *NAMESPACE 0aebd0a7b90095c554020f4cb05c0494 *NEWS.md 0dd7466a6ea2104983d2230d14af6517 *R/aliases.R 69feb260d9d9596cff7279727b7194ff *R/debug_pipe.R 316e23f4777296ee8dfe469684f244cb *R/freduce.R a45c20797cf0f44b148a253a6d8a338a *R/functions.R a6e5e9ab01efeaa0e1d03a78f668d706 *R/getters.R 33c7b4d774c39ca299ebb21e684e6c92 *R/magrittr.R c77c8b2e5b0b76bb7501ee0439c7c26d *R/pipe.R b355c081f7dc2aced5ca65e9020a75ba *README.md 084078aa68b48964d1edd278e8860b0b *build/vignette.rds 786d5e98d2db43ca57b1b05b6c98e262 *inst/doc/magrittr.R ae2a5f945966923225eb4b7fd50e7834 *inst/doc/magrittr.Rmd b0dd0c1c6f9dae077ae2c37df675a0e7 *inst/doc/magrittr.html e6000bf0b0354a95dd0de7a3768c0ad0 *inst/doc/tradeoffs.R ade5c863f8b1f237fcf3642076c00d3e *inst/doc/tradeoffs.Rmd e5ae03d258982177a89340517e2ef13e *inst/doc/tradeoffs.html 320671fcbeb26a1ad31a8be1b8259db1 *inst/logo-hex.png 49d0817fc5a43e2c1593194ab84fc1d1 *inst/logo-hex.svg d874c14ccdcddaeae92f28cd7c8097ca *inst/logo.png 9c8e1ed8c5dad58b4f422ed25cb4bf6c *inst/logo.svg d6201baf5e138c57361b9b1967215845 *man/aliases.Rd 4fa184155b60d0b52276216ae391479e *man/compound.Rd b54749212b910263c3c801a002ae9406 *man/debug_fseq.Rd f167a1631d3dffb9205ec94886301b29 *man/debug_pipe.Rd b5d5f05a8e8832bdf970bcff87fb738d *man/exposition.Rd 832875909ce77c2efda116437eac8129 *man/faq-pipe-gender.Rd fd4ab3e55d76f18a21681c9d90e0a8de *man/figures/exposition-1.png 2a60de702f54976c2e9de39fa44a72f4 *man/figures/logo.png 1b42ebf4f0f9985208454a1f9c6f800a *man/freduce.Rd 2528e04ada11d08d8da41baaa3d479f7 *man/fseq.Rd 74c85cb379ef50b8f1c7b8186efb1e81 *man/functions.Rd 86e5ff38030fc24d1786d61d48951988 *man/magrittr-package.Rd 426c1d05f7211bd8cb7adf3cc9304525 *man/pipe-eager.Rd c6cef1f6258a3061fb862eb045dcc83e *man/pipe.Rd 447ded028c32a4bcdd7f5334b8acc99a *man/pipe_eager_lexical.Rd adc2d8bbc2bf764e31a81697036b84db *man/print.fseq.Rd 6831d192911395cd3b279c65676efea7 *man/tee.Rd e1fe3803652bf3494b0828a9c9ff4f26 *src/pipe.c f805d279bd107cd19da7f3fa8fb4b574 *src/utils.c edbdd325f4ab34f277befd07c0f7b460 *src/utils.h 5e09eabe3f9582bc4a32ca84f35d8a9b *tests/testthat.R 30319b5105d94ffc98d12192ed8afc9d *tests/testthat/_snaps/pipe.md 7d5896a8b77e28f7e25163f1e73b3dab *tests/testthat/test-aliases.R 64337bd67479693182ac3f5b08fea829 *tests/testthat/test-anonymous-functions.r 0ea1983d5b233cb1307a327e3b6a92a0 *tests/testthat/test-compound.R f6e1913c08e715fc9e15d984f45e94b0 *tests/testthat/test-freduce.R 68f6eb8ce9c54a6b2e3a15846f94b4c8 *tests/testthat/test-fseq.r e8780a5936700ff4965f160284c2e40b *tests/testthat/test-multiple-arguments.r b2947ccf703a58273791a50a8d248829 *tests/testthat/test-pipe.R a5f494991871eb8076d4a0dea09d5004 *tests/testthat/test-single-argument.r 0383040641b84042c281763473cda3f6 *tests/testthat/test-tee.r ae2a5f945966923225eb4b7fd50e7834 *vignettes/magrittr.Rmd 561cc58e6362ebd922d69884e825c808 *vignettes/magrittr.jpg ade5c863f8b1f237fcf3642076c00d3e *vignettes/tradeoffs.Rmd magrittr/inst/0000755000176200001440000000000014174220110013050 5ustar liggesusersmagrittr/inst/logo.png0000644000176200001440000006540713701613606014545 0ustar liggesusersPNG  IHDRjsBIT|d pHYs""*tEXtSoftwarewww.inkscape.org< IDATxw\Gǟ]z/" 6D6@ hL+j51j,Q[,'{5Jł(" &a=?y?<󛙧gff`  B NP( ErBP(  BH BP$ABP(BP(IPP($P( ET@( " *  B BH BP$ABP(BP(Ir@!!!q<VD!Q( H &&S:) ׮А.! %&&Cbb2`eeA,-ʜ4K,iģ{LBh90{rVIQȵk!x֬eڊXQBয়W׮(v>A3f.f 5<s,gCC#l͙wRQ1o޼ VHTT ڰa'uP(d۶{ow=B[// ю:R(rsF()Aׂf@?Frr*,^UGf:YfJ* E.޾M@˖md ׊0_S~bgRF`ff΁~^BļDg^ƫVoa6mܸ2\9L8~^dd'D}?Ncc#hUj.pKK3R<$'qo (6ϟǡݻ2#F7B{ y?]W#j@ÐSw4ɬ,ȑvm[ M#h]̋gؓ --, [յ!67\ I9&''Q&G <=݅&B=]Ck 6ZMBRf!S tMǜ9s_|0 E;g_ש&I;;[GӅ=3 jԥB-Gi/b({:9s GFFڵssEMI8| ~=Tm, u̞תUB}Uҥ CÆʶ?&+;?]q'w+u sNZh]Jkhhw711RpO^^>f:[G#2гg'a0z\̓HF20ЇypĶ?@?Rr ٽ&__bф89/I>^%3T& %+W,,$>++95aeeeR88^Q8N055fL<4OV,͙Iki'N\Sq_%eX{NGʚ5Ȋs8}I?vY/ޠUW2>>8Wy+:B_r>tuuaY\ݺ99$~Jz_N1ږfJ% /^BR׾5*(Iΐ,l۲e>ϩ}_#FNg8(Kdd5k:Ͷkt &4SQroš( 'AhфYۀ6mZ=z|!sBC)V""srra̘?埄JmoBNݶ;vl+tVH\ZBB20q K񇄆)X*HJJtqi 72r}f"aOwxىq<}X!b;⏁&l5Ӄ6mZ.)',mѹ4~\v)BEvӦ :ILLUfm;\w,(K'KW׆ϹGOL([i%ccc-<çWn)f^S޽KM]dmW (~*(R$8D5k&~c^!r$E$cՐXTZ ѱOMMSpd޾*)mJMp;8f:{Q,ZRR{}}=Q^6۶2[Jl;n?bDjjb b$+KqwybffJˇ;1ߌ坔TQ"RmP[\M͌e21775\SpdkIh%%u5( !)X.ϛO8ETZ4Ubn.>05U}P^a\tiHMM[ ӗ! HtI%QCH!?2y!),Xa3a\62R5](ŃXٟ a}M,bK(1EBijsswW!ӿ÷kR"88Gvݺ ͮ>LLAtH:;]]]Z[Q[X9ADCC(^zzdkB}">M?H1P@~R6f&Y㿼o C1Fcn&1++:<$V$n];_խ[S;99.~bŋWoLf7RHdQ/)1r֟IIIXqH,TVY=<5v|Sn'WoE. Ru3$X|wU!:G %r0 Sظq רQ=E޽ȑ[ӈ 0?erWsl#$T 8X$\YzQrS\11},o!!Z~fY.i5PkiʕD&D} I-s-8P4k&˗QX}O4pS|&.roڷm[ߵK{A顏߳rk+M$F|EE=x6ݾ.ڶ|bnݚHv9CO3b31ФI 9Ɋ&M׭SQš7~+1RE{QO9 t簺P {!d 7'DJNݺ5Ɇ Jj'Icє _Wma3,4l,z~=GGkQٻwIܹ+maCg²:x# $[\UHV*ik3S+t}ۊ|o֊>B̙Kx4sВ(Y+!VWD!VRYw+/(J@ܤ} ^UWYGҚJ[0f/WQʜ+Vnbg6&%*{bІvݶ=C$ٗHn% 66IZҙ>yOm^D$ڼeleeAիSa'X4q!XuuƎn޼Oc`mf b'S~jsaImggKjp|7qC]d7$M[`S37 ~q%+5׷R 0а3 _qo[PRx{&jUPffb$33]|G=~\\XAc5r/gdd~~#Dfk|%WF?֮`TȤ|.)8!Cޕ-_OOw^(mL8*޵Q*Y;Vq5| !)3Np5x ʼnxy5jתN-ڒ`!))%$$ËP`P0 i^=;+5qUy>F #J}{Oao'.붫Ķ |eugsfMmA*w +p E I1i/ߵk mۊ1WHsvQzdYP/eid}Ν_EB`eSEֈ,^4@@7F$ NOЪ'enn ,h3߼y]'OqHG++ }\B˖MIg())Es%//n ÷oc'\!B ,E%Yd&|- 'O㸸7H__,,/FX<}ME7prJ^ͶRHbb l޼Ҩe5iB&LWwMzB~~AeZ2xP~Ȑ111/њۘHŋkڎd|E6n#TqD- B~A8NÕǎ$y#[ ܋D`F?W냫Tɒ5Ph۶eVzz\r_ D!?+۟\;o޼IM-[3uΝFrG#G~<VۮbkCƌ$nZjIMM˗~Aѣ'mB-k޼ AI?|Y,-/ uKׯ`? t],׀062;W盘TEG 陰u~K/banF ۷+_TdI:wz, AA!?S3\ sǯzzˌ/\ <{] oKN&Tɒxz6'^^ͅ.N%&BΝ_  %]UXlÇOКۘO{U#&*NO[8 z \ֆxz/悳smꃟ V[&LwA.1/_F!!л$)()1Rq`eeA,>9i8;_ tz%Sτ|U^?w8(i#P,B^VY<6Fw I(11SPbb k+KҨq=Rclht/_|''.^:  [9 ! >>_C~~XwRRņ  Gx_y!116n\VcEhUak[?o٢i9ׯ@/_+Ҷ!{ ڕ ==^pDDlpDzRt%UIH=nݟkM7n`cc @TYA] Q#gҳg'emG0n޺#38lݚ؉ ?`x߾+Cà_={~)0 ,ª~~8$M툷A*WVmS)B}p`-\֗ ڶm!oY2kׯ2n˿,GG{2y/ڂ>++ gP9b |"{k(}}=h&xxn IELV*w)$ B:~FÑg/HcU`hhB{OI* / %! t/ļPc\5 > G7hrrraCѣ%ajj #GضB޼y>eݽAZr-UW{ w[xڵݮ f6NJ\>ƥ4ٗYIOπ˗o`? |U>B\\жm D{T8n~A0OBM1ii.0 |uGa^d >\ B-`G|| JBܻWoጌLT$^HOπ[3g^V|IJ,ɸCOOw"@X}ceeAڵkE(.r) 11/g_C񉊼RσQhj/ 7oB&LWQ"ILaf">!4mpIHHBא5T p9C)-0p@wO.Qۄᱱʬ,5h3\*Z- YY~A8CE:3~߸_.$s IDATт(UȤ|&.Tzz&\Z "m!!>Bv-.֭;/ݸlggK?k-xPg8!!кQC3fMO^^>ܸЭ[ክ`G|[ ֶRmBDի7pz:uS\>^% YYp|B~$FOahִi!xv=~aJdJC{3|b Mݰ,nnoҺuqEH||":r >sbc3"m0 aȐ*M.|-:t4p1}UB׫C|| 2+j0. oE׳J 8QBb2$&$҂XYt>~@__"11/њۘHE?ʼnL4Q^ǣ[e3y|[`_LOAbbm<1[Qeh ('ڵm)x ikAq`m|'STѱڇ6QE$''v<=vVe5 155oF;bPP0yZFIWvYVPNo[޽H$fU:l.iӜۗߞEaB`9lT,p!&Vq/OwҡCNLPP0(ޱ0:x#JW60/OwChִAt8!VYA툧gs6B*a""ѷ$ H3…y>&9%Um޽0tH/@-AQ-ģw0nݑ},5Iy'-do\)m,nOҪU3AOOB)mF]::,Y8+4cR: ܃jos+WK}'Zh׶(gxdSvvq3;?}c? 4n`GɁl܎d-5IJJKcNNW",>Zn;kş:<=݅qc*YjdiҶoOۧ5[ 2++ش9sFwxʔἍwM@*XG /,3w+g$ݻŋsuډV^HJJf.]*6d!|M5:o*URm[ZCv->rEJJ̚>h%3yGjZi۲ H5**T?}O_.-״|E*28~ElcZc4O&M uS0 eϲ 6$>>BVrDLK4󇥌gŒKy?NiZLq̾}%">g* E3g.eeUV00e/QQ3eiŗ 07Q}<1/֭}$ۮ_ 3\3$o޾gmۙ88iĶ7o>QvZ c --䩼qfJV>67?pW]PJS$'T*&&FhO,-͉@Rr $'Wת:t4nЙj؉T޼yoyS%Hlɤ<{$lF T^XZK+s`0I)ު4rÌK'Ҥq}> / {SI]+}h۶жM iSkgꕛ?yM{qMtp:9$:Я_7_߮mp$:?!kRh۶иqOEE=CW~~Ae(lܸbe6x&99 SE]ۖ˜1E,\=V 3guJ;%H^P~ 7Fda|ժU*o&a߲eguh%5*{c/ӂoy%0T+,f0sum(Y >d/޽DZgTTniVVdB6-hh /S0=k߰$a}K/Sݻb% I]ɓ~5YG1+[_n-}ơ[yGa t.c a'sJ~ժU!kVϗ,x/;[bŜ2 z ݼȝ J:tڣY=O"tuu`ޏSJ^8=iMOî߰Ck6,ƎL'ڨNGz88B>B.^ ÇsEŋG^¶+;w">BR 2 sfOԙ_ò,̝;766$r zRh fQE=ɺw H=zJeȐWDB(o] GLg8xhٲur_nT#55l0۶`NT~ }:i ֶ)%8'%5 (@*-a<#c'7$?*>Wsa:Q b (*X5sF2L (fg刾1Gl+v6FJHMS 0aܽ1 ,ˀl5tde~5W8173%ii^zHM9f̓={2:-aO€y]]VV RJ%v$DZX)fSūR}zzrsKdf phÆ۷ sI4mB&MUߓR IJJ)JIQPtTxb&./_Ak%qoDM2aXyWX%H_W~  33zݚth b+geeCRR {Iĉm#Y7 !wekQX1q"|YmAŗ AA׮}xmΣ?u!wIEє}UH33r Y&J=.ݻ$lFFlAH9prI&O坜R:%FCwhєLpQͩ ' uj;^}e~~=D$YA 5nvg0>|ig@- yG\PMF {Ev!ʹLM ǎo,ݼuGX j̒/ޭmVwց*hjj:9{Y}/"EDDJ)JDN AJcÇ099RuDtF6B\] fviEϭjժfq?K?OQ֖^Rd;w]ahҤ:mBN%-->+22K:ʹ nذ9uOJWW o޴kEQ9Ji&&lhh[&QR!@E=v9ܿ_ʙRʆE1RAyčFr\ɖ-p~%lsU7mDGǪݶSR`򍒪6k@q:W6q<,\QwS+61_K̮n]_;~Nڒ8w2ht⌐:4Ottoয়0YY+oBKcٶCnN_~&a$$$?f5q %ْ2]ˤg•+75=; ۶.缼+(G__:tޠeՑD~ńptF\\Qk>}𺺺^~X;%A5k1{L&[i/^|Դ_mBn聼áhXVZXUV8~w1'Vd`ssS[4::M2UE X`5stGm%Ҿlʨkejj Nɯ^5SJ> ETlMڷv x 2e2T3g9/%i۶"OV@"H/-4a\vݺ>#0t} rvN g/wVضuE_~Es нL=f="&55>>-,̠f biiN,,@GGS ))^~?Sr;ܷa55_bA__ ճ/2:p-(Brr*$>IlmmI4a )9Q\[[$_* `ee3gfYΪwrr*$C}y^ԨUhkU?n`ccEO"&ӾϟJe$꫎B֮>B+AEvdd_`(+I5b\ٚw܂T<(%MCJenݚdOA=C45 ̝;ӓ{(R鸴,vnYεjLkE~9wv5sΙK E$T@ރY&prv'ä|u;E>:k5G6n\яӓC,sLMLJhrekEvqP 38SSi4I]7!_|Ne277ߏW)M,)څ5?o*bf|V{| T^#u51bFُ/#sgaJJvҨQ=rBa]00uH_nZ5ߩ}Uz|AA^a`c޽:+zôfիM֮YM<76֎+P#YGֶbl[WW~;IZ}>9Aq/<4{ J$==fZ>|*k .8w2׼yLx%5LWpނ6)Kbb 0k)D޲`dd?-kԨv! IqT@J ''6n͜>sItw@UhO}7EQnrrra-bOUؐ!Cz >N?222ao;eqrI}7WZBDhLddFV9cc#:'߭[*쪊DS()224 #9:ujm~^D$Zn;ӈ) ޗc[4Q !Nm? / }ffʎP cTaڵ0lh/^I D+8 6|TqeccM<=H 9"ɩpex GEU@5gsұc[jm* *ݻ$x Ĥjӝj.ԭ[L, <;p (:W%^W VҶ܂bkɐ!1)僕++ bBsR|oۉɐxo`mmI,ڂ=dCBP(HHʌ/ B BH BP$ABP(BP(IPP($P( ET@( " *  B BH BP$ABP(BP(IPP($P( ET@( " 655;{  BRSs={q^ȓ{0 BVW/_G?}B[R( E -BPABP(BP(IPP($P( ET@( " *  B BH BP$ABP(BP(IPP($P( ET@( " *  B BH BJ$ CC#GgjժN4BQ !1}Jƚ-{ukW/ Ӧ-vO") |ӟAAbb29thA= u% c>/(8U9sȉܶm S0۷SxUiggz+UD֖f6>--]{{#lnnff&(//<{bb^ׯKe0|x_]VXWWzϟ[j1111C{16Pi$_a#)լ\]kׂKxkkKtGDD$ٳ߭[{\n-Ԯ]k|%B ߽[e6;֮͛^zS[߻8EEt~zzz0s8UfFe8&%8q.'F@QmpG; <_|,YA5JC^矷s!>na, w=;GOZ&Mec/e`ʔLQsry[( plu!lpvQ2mWtXbDWW  " (==]Xw>==Cmc266[J(66uMx  @kժj԰GйsWU*WFMejvpdĉsOsƍ32Jwׯ;{唔T7o'׃6n\?wɩKlmmt>*pMaٲ@-Zǥ@b4cXa0>-77ը:w.57W]DA=00f|o ?opӧ/梢}xͻwIxzzz*QL:q,Y/zKK ˗f[l?% 5j#gͰS>]?lp |Jv8^9:VCÇXXB7zz|lN(&YbӇHSssSX~!ۥݼR {c\x4޿oS7:::С']y3L(i`aذL>]0ސ~&cYLL!99U$Ѫ+8+\N PyIrs_cJ!ÆaA;w644a.Ձ޽;c{յ!4oyzs箔xpqqB;cI 7o%](044ŋ;_zKV߽ѣuB344efիۡ ;̍wڵӦfS]]HII-fܸ!B=pX2EȑB@^^>,X};|88T{Qcb^}^4_*//l?~mmmE__:ujT_&%% {D||^\!L+UVF{ݴT0a.B@ E ˗D^^>\*͛w>pÍCo&OOwaz²?J*8}ܻYXѿ…ةKHŽȱ֬Y^g\o&g{ZqqaW_5o_KX?պPwj Úo ܓY8{rW[4`W!ܿ[ (! M~nɎPZ|6knn ֭[Cb<<s'#G~uk5aaj9n6i~Qfp'N\-N׮?ȨggW8'. _ۻ5꫎ܹ+ŋ-(tY5@jUP9g*rСoϗ|U,BF'r۫Wo= OD! On(^s>o ,,cҥ=E/}? hM렛7Äve}53sbȿ Y_\Z5ÏGm+_`B)51557o≟_`5ypgXsfva)"M Ec/ML4L,)$?&$jbLLb,PPl";s/3ή"b\a̹JBYY]3_QQ ݻw}8@PYT<,!!Vz9hb "14GXYee#Rb}5j szt)@M5=zJg0{h=2Y3{?/C~lRJ2,(Lh`&Zt9s{ kɛs(ml;/)Ac.#iCJL8kΜP{AAAllj xD uz-u@ך0).w!B yC"< j6iհyvEr.]'_}Jv1Phh0jaXK^^!/9ySll UUu*i}ҥxO:kh40otoI&Nyfqn Xo9XrOEwTpR"P(**6V򨮮6I" 4X{wI#BKkOO7ԯ_/\]k6ʤkJHH0Z2N0ֳM/ 9 ǻw%%I3xnyzyy^EڷT!,! &&yAA)h׮52zصK>k4BB͍J;"-HO7T6h`ӧOfLw*/k">>*cPm[{uBSR4xIᓼZ2W Csb@}w2Cճg/ W Je$/}nD1`2N0ɹD} ސ -Qwoz{ :ݿwr/Tdd/ZHF|)mO|_ʙԶmٳ3Os)'11ͭ!rt@Rpf4tsVyRs5y1Ŵ\*y>s@]q\\$ 7jQh!lTSSXNNɧ==z(%0!y/**&ɑ8HO7U-y{{"h;##Sv# `^9p`F7˲0{묻dTt3WsBV[ NNxg!CSj99Hrztp}{0th --Sg$RòeExV@q^a+[T|T*Q_D:#"UaHTQQ f-ԛS̱,#:APtn|| JL:VXϥ[a*}NVE#վ WƸH1)mڴD |mcҵk,VUPYYewtԀ Q/+mEABcaΜ7_?s?qÒ .667B|OUBɥe0ba)]ASf:dH*`Ѣ!K?~(0 ,[+-e yQǧ125+WJLj#qqXZ/.fz@fYRU0cF eeivUD ZM#b 5dղY澨^f(:޵+U 8gr/۷VWt^yӦM}S/7h ȑ0u2 RS3d' @Pɩ wF:t9dѢo89Wyb$)i86H~$..^<\'fMc"̛3~Q!Vԩ9Mscr|˖-fMq͘1JϞ@f^4ϯ)1djN!a / BvvPUu\z:Kkךwi4u3^n>TW~F1qժ8jkkZm5B $xȰ^ y&)@Fhwi{1z F}h4z_5'}e9zٲѴ}8{:J_x);;w1#$%ʛ1dBEEE%Zo8Qz[j뉨tZͳ""B0Zz*66<7o_|q%AAE5>-1v`ns}uN!޼y7 K3q0Ra>)mݶmj2)Ѵi+櫌܀ `1AIH-yM 0'' 8k7/[ΤvK'>w?1xΝ˭BoMh6> ,U9ʵk7Z\bQh޼gg'(,B-TWޞb[ @}Aݩ4@'Nv^tp›oNd Xt|"54I%TRoļz7,4/))%ӧpeeиۻ7l!6v::󻤿/WKxyߟʬX)3ҥqr`- ׵VBB'LG\!>!-Z"WW#@ȑ af_iMgpwoMHM)yR9T&^pX=i|^]pxx بeQ9:j`޼錇G#tN̘xرJen. 9 ӳM9!H`` 4z@ܼѣnǏgc bsOcԳg'V!?$')':>>#yѧ\ڵ pBCpܷob;R)mݺF:bE ?:5 hVNb6 6,)iikқ$9U} +LtxIIYlPh`d;/"6ٓfPHٳ`CCݻB;Mq]O^{mI6 kzk"sg*Ytj.!C:|vjB}ׯ%d9Kc;<=_Fc|nݺ\MY˗c5A[,Ytf)$$t=INnnmR`%*.\#'ϨB&66WTTSr%ãJH脺tUE$77~`}^AҘx%ΑcInNxλiiG*jժUrqqBr|.9q"HeeW8>>;::@EE%ݛ?M5FݺGOإ _{vvV=͚5A˗gMm"Vx:裷v8>U%Rmѭ[,>`ٲզ`J3 B$2yQR]] {/A+* \]]`@Aqq y(< a^NF~n5 }bY22NOd?}N1U]m%_kLee,X۶o>$$y{{ z:ٳiRt:% subset(hp > 100) %>% aggregate(. ~ cyl, data = ., FUN = . %>% mean %>% round(2)) %>% transform(kpl = mpg %>% multiply_by(0.4251)) %>% print ## ----------------------------------------------------------------------------- car_data <- transform(aggregate(. ~ cyl, data = subset(mtcars, hp > 100), FUN = function(x) round(mean(x), 2)), kpl = mpg*0.4251) ## ---- eval = FALSE------------------------------------------------------------ # car_data %>% # (function(x) { # if (nrow(x) > 2) # rbind(head(x, 1), tail(x, 1)) # else x # }) ## ----------------------------------------------------------------------------- car_data %>% { if (nrow(.) > 0) rbind(head(., 1), tail(., 1)) else . } ## ----------------------------------------------------------------------------- 1:10 %>% (substitute(f(), list(f = sum))) ## ---- fig.keep='none'--------------------------------------------------------- rnorm(200) %>% matrix(ncol = 2) %T>% plot %>% # plot usually does not return anything. colSums ## ---- eval = FALSE------------------------------------------------------------ # iris %>% # subset(Sepal.Length > mean(Sepal.Length)) %$% # cor(Sepal.Length, Sepal.Width) # # data.frame(z = rnorm(100)) %$% # ts.plot(z) ## ---- eval = FALSE------------------------------------------------------------ # iris$Sepal.Length %<>% sqrt ## ----------------------------------------------------------------------------- rnorm(1000) %>% multiply_by(5) %>% add(5) %>% { cat("Mean:", mean(.), "Variance:", var(.), "\n") head(.) } ## ---- results = 'hide'-------------------------------------------------------- rnorm(100) %>% `*`(5) %>% `+`(5) %>% { cat("Mean:", mean(.), "Variance:", var(.), "\n") head(.) } magrittr/inst/doc/tradeoffs.Rmd0000644000176200001440000004106513750274524016265 0ustar liggesusers--- title: "Design tradeoffs" author: - "Hadley Wickham" - "Lionel Henry" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Design tradeoffs} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>", eval = FALSE ) library(rlang) fail <- function() "\u274c" pass <- function() "\u2705" ``` There are many different ways that magrittr could implement the pipe. The goal of this document is to elucidate the variations, and the various pros and cons of each approach. This document is primarily aimed at the magrittr developers (so we don't forget about important considerations), but will be of interest to anyone who wants to understand pipes better, or to create their own pipe that makes different tradeoffs ## Code transformation There are three main options for how we might transform a pipeline in base R expressions. Here they are illustrated with `x %>% foo() %>% bar()`: - **Nested** ```{r} bar(foo(x)) ``` - **Eager (mask)**, masking environment This is essentially how `%>%` has been implemented prior to magrittr 2.0: ```{r} local({ . <- x . <- foo(.) bar(.) }) ``` - **Eager (mask-num)**: masking environment, numbered placeholder ```{r} local({ ...1 <- x ...2 <- foo(...1) bar(...2) }) ``` - **Eager (lexical)**: lexical environment This variant assigns pipe expressions to the placeholder `.` in the current environment. This assignment is temporary: once the pipe has returned, the placeholder binding is reset to its previous state. ```{r} with_dot_cleanup <- function(expr) { # Initialises `.` in the caller environment and resets it on exit. # (We use `:=` instead of `=` to avoid partial matching.) rlang::local_bindings(. := NULL, .env = parent.frame()) expr } with_dot_cleanup({ . <- x . <- foo(.) bar(.) }) ``` - **Lazy (mask)**: masking environments ```{r} mask1 <- new.env(parent = env) mask2 <- new.env(parent = env) delayedAssign(".", x, mask1) delayedAssign(".", foo(.), mask2) with(mask2, bar(.)) ``` - **Lazy (mask-num)**: masking environment, numbered placeholder ```{r} local({ delayedAssign("...1", x) delayedAssign("...2", foo(...1)) bar(...2) }) ``` - **Lazy (lexical-num)**: lexical environment, numbered placeholder ```{r} delayedAssign("...1", x) delayedAssign("...2", foo(.)) bar(...2) ``` We'll first explore the desired properties we might want a pipe to possess and then see how each of the three variants does. ## Desired properties These are the properties that we might want a pipe to possess, roughly ordered from most important to least important. * **Visibility**: the visibility of the final function in the pipe should be preserved. This is important so that pipes that end in a side-effect function (which generally returns its first argument invisibly) do not print. * **Multiple placeholders**: each component of the pipe should only be evaluated once even when there are multiple placeholders, so that `sample(10) %>% cbind(., .)` yields two columns with the same value. Relatedly, `sample(10) %T>% print() %T>% print()` must print the same values twice. * **Lazy evaluation**: steps of the pipe should only be evaluated when actually needed. This is a useful property as it means that pipes can handle code like `stop("!") %>% try()`, making pipes capable of capturing a wider range of R expressions. On the other hand, it might have surprising effects. For instance if a function that suppresses warnings is added to the end of a pipeline, the suppression takes effect for the whole pipeline. * **Persistence of piped values**: arguments are not necessarily evaluated right away by the piped function. Sometimes they are evaluated long after the pipeline has returned, for example when a function factory is piped. With persistent piped values, the constructed function can be called at any time: ```r factory <- function(x) function() x fn <- NA %>% factory() fn() #> [1] NA ``` * **Refcount neutrality**: the return value of the pipeline should have a reference count of 1 so it can be mutated in place in further manipulations. * **Eager unbinding**: pipes are often used with large data objects, so intermediate objects in the pipeline should be unbound as soon as possible so they are available for garbage collection. * **Progressive stack**: using the pipe should add as few entries to the call stack as possible, so that `traceback()` is maximally useful. * **Lexical side effects**: side effects should occur in the current lexical environment. This way, `NA %>% { foo <- . }` assigns the piped value in the current environment and `NA %>% { return(.) }` returns from the function that contains the pipeline. * **Continuous stack**: the pipe should not affect the chain of parent frames. This is important for tree representations of the call stack. It is possible to have proper visibility and a neutral impact on refcounts with all implementations by being a bit careful, so we'll only consider the other properties: | | Nested | Eager
(mask) | Eager
(mask-num) | Eager
(lexical) | Lazy
(mask) | Lazy
(mask-num) | Lazy
(lexical-num) | |-----------------------|:----------:|:---------------:|:-------------------:|:------------------:|:--------------:|:------------------:|:---------------------:| | Multiple placeholders | `r fail()` | `r pass()` | `r pass()` | `r pass()` | `r pass()` | `r pass()` | `r pass()` | | Lazy evaluation | `r pass()` | `r fail()` | `r fail()` | `r fail()` | `r pass()` | `r pass()` | `r pass()` | | Persistence | `r pass()` | `r fail()` | `r pass()` | `r fail()` | `r pass()` | `r pass()` | `r pass()` | | Eager unbinding | `r pass()` | `r pass()` | `r fail()` | `r pass()` | `r pass()` | `r fail()` | `r fail()` | | Progressive stack | `r fail()` | `r pass()` | `r pass()` | `r pass()` | `r fail()` | `r fail()` | `r fail()` | | Lexical effects | `r pass()` | `r fail()` | `r fail()` | `r pass()` | `r fail()` | `r fail()` | `r pass()` | | Continuous stack | `r pass()` | `r fail()` | `r fail()` | `r pass()` | `r fail()` | `r fail()` | `r pass()` | ### Implications of design decisions Some properties are a direct reflection of the high level design decisions. #### Placeholder binding The nested pipe does not assign piped expressions to a placeholder. All the other variants perform this assignment. This means that with a nested rewrite approach, it isn't possible to have multiple placeholders unless the piped expression is pasted multiple times. This would cause multiple evaluations with deleterious effects: ```{r} sample(10) %>% list(., .) # Becomes list(sample(10), sample(10)) ``` Assigning to the placeholder within an argument would preserve the nestedness and lazyness. However that wouldn't work properly because there's no guarantee that the first argument will be evaluated before the second argument. ```{r} sample(10) %>% foo(., .) foo(. <- sample(10), .) ``` For these reasons, the nested pipe does not support multiple placeholders. By contrast, all the other variants assign the result of pipe expressions to the placeholder. There are variations in how the placeholder binding is created (lazily or eagerly, in a mask or in the current environment, with numbered symbols or with a unique symbol) but all these variants allow multiple placeholders. #### Masking environment Because the local variants of the pipe evaluate in a mask, they do not have lexical effects or a continuous stack. This is unlike the lexical variants that evaluate in the current environment. #### Laziness Unlike the lazy variants, all eager versions implementing the pipe with iterated evaluation do not pass the lazy evaluation criterion. Secondly, no lazy variant passes the progressive stack criterion. By construction, lazy evaluation requires pushing all the pipe expressions on the stack before evaluation starts. Conversely, all eager variants have a progressive stack. #### Numbered placeholders None of the variants that use numbered placeholders can unbind piped values eagerly. This is how they achieve persistence of these bindings. ## Three implementations The GNU R team is considering implementing the nested approach in base R with a parse-time code transformation (just like `->` is transformed to `<-` by the parser). We have implemented three approaches in magrittr: - The nested pipe - The eager lexical pipe - The lazy masking pipe These approaches have complementary strengths and weaknesses. ### Nested pipe ```{r, eval = TRUE} `%|>%` <- magrittr::pipe_nested ``` #### Multiple placeholders `r fail()` The nested pipe does not bind expressions to a placeholder and so can't support multiple placeholders. ```{r, eval = TRUE, error = TRUE} "foo" %|>% list(., .) ``` #### Lazy evaluation `r pass()` Because it relies on the usual rules of argument application, the nested pipe is lazy. ```{r, eval = TRUE} { stop("oh no") %|>% try(silent = TRUE) "success" } ``` #### Persistence and eager unbinding `r pass()` The pipe expressions are binded as promises within the execution environment of each function. This environment persists as long as a promise holds onto it. Evaluating the promise discards the reference to the environment which becomes available for garbage collection. For instance, here is a function factory that creates a function. The constructed function returns the value supplied at the time of creation: ```{r, eval = TRUE} factory <- function(x) function() x fn <- factory(TRUE) fn() ``` This does not cause any issue with the nested pipe: ```{r} fn <- TRUE %|>% factory() fn() ``` #### Progressive stack `r fail()` Because the piped expressions are lazily evaluated, the whole pipeline is pushed on the stack before execution starts. This results in a more complex backtrace than necessary: ```{r} faulty <- function() stop("tilt") f <- function(x) x + 1 g <- function(x) x + 2 h <- function(x) x + 3 faulty() %|>% f() %|>% g() %|>% h() #> Error in faulty() : tilt traceback() #> 7: stop("tilt") #> 6: faulty() #> 5: f(faulty()) #> 4: g(f(faulty())) #> 3: h(g(f(faulty()))) #> 2: .External2(magrittr_pipe) at pipe.R#181 #> 1: faulty() %|>% f() %|>% g() %|>% h() ``` Also note how the expressions in the backtrace look different from the actual code. This is because of the nested rewrite of the pipeline. #### Lexical effects `r pass()` This is a benefit of using the normal R rules of evaluation. Side effects occur in the correct environment: ```{r, eval = TRUE} foo <- FALSE TRUE %|>% assign("foo", .) foo ``` Control flow has the correct behaviour: ```{r, eval = TRUE} fn <- function() { TRUE %|>% return() FALSE } fn() ``` #### Continuous stack `r pass()` Because evaluation occurs in the current environment, the stack is continuous. Let's instrument errors with a structured backtrace to see what that means: ```{r} options(error = rlang::entrace) ``` The tree representation of the backtrace correctly represents the hierarchy of execution frames: ```{r} foobar <- function(x) x %|>% quux() quux <- function(x) x %|>% stop() "tilt" %|>% foobar() #> Error in x %|>% stop() : tilt rlang::last_trace() #> #> tilt #> Backtrace: #> █ #> 1. ├─"tilt" %|>% foobar() #> 2. └─global::foobar("tilt") #> 3. ├─x %|>% quux() #> 4. └─global::quux(x) #> 5. └─x %|>% stop() ``` ### Eager lexical pipe ```{r, eval = TRUE} `%!>%` <- magrittr::pipe_eager_lexical ``` #### Multiple placeholders `r pass()` Pipe expressions are eagerly assigned to the placeholder. This makes it possible to use the placeholder multiple times without causing multiple evaluations. ```{r, eval = TRUE} "foo" %!>% list(., .) ``` #### Lazy evaluation `r fail()` Assignment forces eager evaluation of each step. ```{r, eval = TRUE, error = TRUE} { stop("oh no") %!>% try(silent = TRUE) "success" } ``` #### Persistence: `r fail()` Because we're updating the value of `.` at each step, the piped expressions are not persistent. This has subtle effects when the piped expressions are not evaluated right away. With the eager pipe we get rather confusing results with the factory function if we try to call the constructed function in the middle of the pipeline. In the following snippet the placeholder `.` is binded to the constructed function itself rather than the initial value `TRUE`, by the time the function is called: ```{r, eval = TRUE} fn <- TRUE %!>% factory() %!>% { .() } fn() ``` Also, since we're binding `.` in the current environment, we need to clean it up once the pipeline has returned. At that point, the placeholder no longer exists: ```{r, eval = TRUE, error = TRUE} fn <- TRUE %!>% factory() fn() ``` Or it has been reset to its previous value, if any: ```{r, eval = TRUE} . <- "wrong" fn <- TRUE %!>% factory() fn() ``` #### Eager unbinding: `r pass()` This is the flip side of updating the value of the placeholder at each step. The previous intermediary values can be collected right away. #### Progressive stack: `r pass()` Since pipe expressions are evaluated one by one as they come, only the relevant part of the pipeline is on the stack when an error is thrown: ```{r} faulty <- function() stop("tilt") f <- function(x) x + 1 g <- function(x) x + 2 h <- function(x) x + 3 faulty() %!>% f() %!>% g() %!>% h() #> Error in faulty() : tilt traceback() #> 4: stop("tilt") #> 3: faulty() #> 2: .External2(magrittr_pipe) at pipe.R#163 #> 1: faulty() %!>% f() %!>% g() %!>% h() ``` #### Lexical effects and continuous stack: `r pass()` Evaluating in the current environment rather than in a mask produces the correct side effects: ```{r, eval = TRUE} foo <- FALSE NA %!>% { foo <- TRUE; . } foo ``` ```{r, eval = TRUE} fn <- function() { TRUE %!>% return() FALSE } fn() ``` ### Lazy masking pipe ```{r, eval = TRUE} `%?>%` <- magrittr::pipe_lazy_masking ``` #### Multiple placeholders `r pass()` Pipe expressions are lazily assigned to the placeholder. This makes it possible to use the placeholder multiple times without causing multiple evaluations. ```{r, eval = TRUE} "foo" %?>% list(., .) ``` #### Lazy evaluation `r pass()` Arguments are assigned with `delayedAssign()` and lazily evaluated: ```{r, eval = TRUE} { stop("oh no") %?>% try(silent = TRUE) "success" } ``` #### Persistence: `r pass()` The lazy masking pipe uses one masking environment per pipe expression. This allows persistence of the intermediary values and out of order evaluation. The factory function works as expected for instance: ```{r, eval = TRUE} fn <- TRUE %?>% factory() fn() ``` #### Eager unbinding: `r pass()` Because we use one mask environment per pipe expression, the intermediary values can be collected as soon as they are no longer needed. #### Progressive stack: `r fail()` With a lazy pipe the whole pipeline is pushed onto the stack before evaluation. ```{r} faulty <- function() stop("tilt") f <- function(x) x + 1 g <- function(x) x + 2 h <- function(x) x + 3 faulty() %?>% f() %?>% g() %?>% h() #> Error in faulty() : tilt traceback() #> 7: stop("tilt") #> 6: faulty() #> 5: f(.) #> 4: g(.) #> 3: h(.) #> 2: .External2(magrittr_pipe) at pipe.R#174 #> 1: faulty() %?>% f() %?>% g() %?>% h() ``` Note however how the backtrace is less cluttered than with the nested pipe approach, thanks to the placeholder. #### Lexical effects `r fail()` The lazy pipe evaluates in a mask. This causes lexical side effects to occur in the incorrect environment. ```{r, eval = TRUE} foo <- FALSE TRUE %?>% assign("foo", .) foo ``` Stack-sensitive functions like `return()` function cannot find the proper frame environment: ```{r, eval = TRUE, error = TRUE} fn <- function() { TRUE %?>% return() FALSE } fn() ``` #### Continuous stack `r fail()` The masking environment causes a discontinuous stack tree: ```{r} foobar <- function(x) x %?>% quux() quux <- function(x) x %?>% stop() "tilt" %?>% foobar() #> Error in x %?>% stop() : tilt rlang::last_trace() #> #> tilt #> Backtrace: #> █ #> 1. ├─"tilt" %?>% foobar() #> 2. ├─global::foobar(.) #> 3. │ └─x %?>% quux() #> 4. └─global::quux(.) #> 5. └─x %?>% stop() ``` magrittr/inst/doc/magrittr.Rmd0000644000176200001440000001741113753167712016142 0ustar liggesusers--- title: "Introducing magrittr" author: Stefan Milton Bache date: November, 2014 output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Introducing magrittr} %\VignetteEngine{knitr::rmarkdown} %\usepackage[utf8]{inputenc} --- ```{r include = FALSE} library(magrittr) options(scipen = 3) knitr::opts_chunk$set(comment = "#>", collapse = TRUE) ``` # Abstract The *magrittr* (to be pronounced with a sophisticated french accent) package has two aims: decrease development time and improve readability and maintainability of code. Or even shortr: make your code smokin' (puff puff)! To achieve its humble aims, *magrittr* (remember the accent) provides a new "pipe"-like operator, `%>%`, with which you may pipe a value forward into an expression or function call; something along the lines of ` x %>% f `, rather than ` f(x)`. This is not an unknown feature elsewhere; a prime example is the `|>` operator used extensively in `F#` (to say the least) and indeed this -- along with Unix pipes -- served as a motivation for developing the magrittr package. This vignette describes the main features of *magrittr* and demonstrates some features which have been added since the initial release. # Introduction and basics At first encounter, you may wonder whether an operator such as `%>%` can really be all that beneficial; but as you may notice, it semantically changes your code in a way that makes it more intuitive to both read and write. Consider the following example, in which the `mtcars` dataset shipped with R is munged a little: ```{r} library(magrittr) car_data <- mtcars %>% subset(hp > 100) %>% aggregate(. ~ cyl, data = ., FUN = . %>% mean %>% round(2)) %>% transform(kpl = mpg %>% multiply_by(0.4251)) %>% print ``` We start with a value, here `mtcars` (a `data.frame`). From there, we extract a subset, aggregate the information based on the number of cylinders, and then transform the dataset by adding a variable for kilometers per liter as a supplement to miles per gallon. Finally we print the result before assigning it. Note how the code is arranged in the logical order of how you think about the task: data->transform->aggregate, which is also the same order as the code will execute. It's like a recipe -- easy to read, easy to follow! A horrific alternative would be to write: ```{r} car_data <- transform(aggregate(. ~ cyl, data = subset(mtcars, hp > 100), FUN = function(x) round(mean(x), 2)), kpl = mpg*0.4251) ``` There is a lot more clutter with parentheses, and the mental task of deciphering the code is more challenging---particularly if you did not write it yourself. Note also how "building" a function on the fly for use in `aggregate` is very simple in *magrittr*: rather than an actual value as the left-hand side in the pipeline, just use the placeholder. This is also very useful in R's `*apply` family of functions. Granted, you may make the second example better, perhaps throw in a few temporary variables (which is often avoided to some degree when using *magrittr*), but one often sees cluttered lines like the ones presented. And here is another selling point: suppose I want to quickly add another step somewhere in the process. This is very easy to do in the pipeline version, but a little more challenging in the "standard" example. The combined example shows a few neat features of the pipe (which it is not): 1. By default the left-hand side (LHS) will be *piped in* as the first argument of the function appearing on the right-hand side (RHS). This is the case in the `subset` and `transform` expressions. 2. `%>%` may be used in a nested fashion, e.g. it may appear in expressions within arguments. This is illustrated in the `mpg` to `kpl` conversion. 3. When the LHS is needed at a position other than the first, one can use the dot,`'.'`, as placeholder. This is shown in the `aggregate` expression. 4. The dot in e.g. a formula is *not* confused with a placeholder, which is utilized in the `aggregate` expression. 5. Whenever only *one* argument (the LHS) is needed, one can omit the empty parentheses. This is shown in the call to `print` (which also returns its argument). Here, `LHS %>% print()`, or even `LHS %>% print(.)` would also work. 6. A pipeline with a dot (`.`) as the LHS will create a unary function. This is used to define the aggregator function. One feature, which was not demonstrated above is piping into *anonymous functions*, or *lambdas*. This is possible using standard function definitions, e.g.: ```{r, eval = FALSE} car_data %>% (function(x) { if (nrow(x) > 2) rbind(head(x, 1), tail(x, 1)) else x }) ``` However, *magrittr* also allows a short-hand notation: ```{r} car_data %>% { if (nrow(.) > 0) rbind(head(., 1), tail(., 1)) else . } ``` Since all right-hand sides are really "body expressions" of unary functions, this is only the natural extension of the simple right-hand side expressions. Of course, longer and more complex functions can be made using this approach. In the first example, the anonymous function is enclosed in parentheses. Whenever you want to use a function- or call-generating statement as right-hand side, parentheses are used to evaluate the right-hand side before piping takes place. Another, less useful example is: ```{r} 1:10 %>% (substitute(f(), list(f = sum))) ``` # Additional pipe operators *magrittr* also provides three related pipe operators. These are not as common as `%>%` but they become useful in special cases. The "tee" pipe, `%T>%` works like `%>%`, except it returns the left-hand side value, and not the result of the right-hand side operation. This is useful when a step in a pipeline is used for its side-effect (printing, plotting, logging, etc.). As an example (where the actual plot is omitted here): ```{r, fig.keep='none'} rnorm(200) %>% matrix(ncol = 2) %T>% plot %>% # plot usually does not return anything. colSums ``` The "exposition" pipe, `%$%` exposes the names within the left-hand side object to the right-hand side expression. Essentially, it is a short-hand for using the `with` functions (and the same left-hand side objects are accepted). This operator is handy when functions do not themselves have a data argument, as for example `lm` and `aggregate` do. Here are a few examples as illustration: ```{r, eval = FALSE} iris %>% subset(Sepal.Length > mean(Sepal.Length)) %$% cor(Sepal.Length, Sepal.Width) data.frame(z = rnorm(100)) %$% ts.plot(z) ``` Finally, the "assignment" pipe `%<>%` can be used as the first pipe in a chain. The effect will be that the result of the pipeline is assigned to the left-hand side object, rather than returning the result as usual. It is essentially shorthand notation for expressions like `foo <- foo %>% bar %>% baz`, which boils down to `foo %<>% bar %>% baz`. Another example is: ```{r, eval = FALSE} iris$Sepal.Length %<>% sqrt ``` The `%<>%` can be used whenever `expr <- ...` makes sense, e.g. * `x %<>% foo %>% bar` * `x[1:10] %<>% foo %>% bar` * `x$baz %<>% foo %>% bar` # Aliases In addition to the `%>%`-operator, *magrittr* provides some aliases for other operators which make operations such as addition or multiplication fit well into the *magrittr*-syntax. As an example, consider: ```{r} rnorm(1000) %>% multiply_by(5) %>% add(5) %>% { cat("Mean:", mean(.), "Variance:", var(.), "\n") head(.) } ``` which could be written in more compact form as: ```{r, results = 'hide'} rnorm(100) %>% `*`(5) %>% `+`(5) %>% { cat("Mean:", mean(.), "Variance:", var(.), "\n") head(.) } ``` To see a list of the aliases, execute e.g. `?multiply_by`. # Development The *magrittr* package is also available in a development version at the GitHub development page: [github.com/tidyverse/magrittr](https://github.com/tidyverse/magrittr). magrittr/inst/doc/tradeoffs.R0000644000176200001440000001552514174220110015725 0ustar liggesusers## ----setup, include = FALSE--------------------------------------------------- knitr::opts_chunk$set( collapse = TRUE, comment = "#>", eval = FALSE ) library(rlang) fail <- function() "\u274c" pass <- function() "\u2705" ## ----------------------------------------------------------------------------- # bar(foo(x)) ## ----------------------------------------------------------------------------- # local({ # . <- x # . <- foo(.) # bar(.) # }) ## ----------------------------------------------------------------------------- # local({ # ...1 <- x # ...2 <- foo(...1) # bar(...2) # }) ## ----------------------------------------------------------------------------- # with_dot_cleanup <- function(expr) { # # Initialises `.` in the caller environment and resets it on exit. # # (We use `:=` instead of `=` to avoid partial matching.) # rlang::local_bindings(. := NULL, .env = parent.frame()) # expr # } # with_dot_cleanup({ # . <- x # . <- foo(.) # bar(.) # }) ## ----------------------------------------------------------------------------- # mask1 <- new.env(parent = env) # mask2 <- new.env(parent = env) # # delayedAssign(".", x, mask1) # delayedAssign(".", foo(.), mask2) # with(mask2, bar(.)) ## ----------------------------------------------------------------------------- # local({ # delayedAssign("...1", x) # delayedAssign("...2", foo(...1)) # bar(...2) # }) ## ----------------------------------------------------------------------------- # delayedAssign("...1", x) # delayedAssign("...2", foo(.)) # bar(...2) ## ----------------------------------------------------------------------------- # sample(10) %>% list(., .) # # # Becomes # list(sample(10), sample(10)) ## ----------------------------------------------------------------------------- # sample(10) %>% foo(., .) # foo(. <- sample(10), .) ## ---- eval = TRUE------------------------------------------------------------- `%|>%` <- magrittr::pipe_nested ## ---- eval = TRUE, error = TRUE----------------------------------------------- "foo" %|>% list(., .) ## ---- eval = TRUE------------------------------------------------------------- { stop("oh no") %|>% try(silent = TRUE) "success" } ## ---- eval = TRUE------------------------------------------------------------- factory <- function(x) function() x fn <- factory(TRUE) fn() ## ----------------------------------------------------------------------------- # fn <- TRUE %|>% factory() # fn() ## ----------------------------------------------------------------------------- # faulty <- function() stop("tilt") # f <- function(x) x + 1 # g <- function(x) x + 2 # h <- function(x) x + 3 # # faulty() %|>% f() %|>% g() %|>% h() # #> Error in faulty() : tilt # # traceback() # #> 7: stop("tilt") # #> 6: faulty() # #> 5: f(faulty()) # #> 4: g(f(faulty())) # #> 3: h(g(f(faulty()))) # #> 2: .External2(magrittr_pipe) at pipe.R#181 # #> 1: faulty() %|>% f() %|>% g() %|>% h() ## ---- eval = TRUE------------------------------------------------------------- foo <- FALSE TRUE %|>% assign("foo", .) foo ## ---- eval = TRUE------------------------------------------------------------- fn <- function() { TRUE %|>% return() FALSE } fn() ## ----------------------------------------------------------------------------- # options(error = rlang::entrace) ## ----------------------------------------------------------------------------- # foobar <- function(x) x %|>% quux() # quux <- function(x) x %|>% stop() # # "tilt" %|>% foobar() # #> Error in x %|>% stop() : tilt # # rlang::last_trace() # #> # #> tilt # #> Backtrace: # #> █ # #> 1. ├─"tilt" %|>% foobar() # #> 2. └─global::foobar("tilt") # #> 3. ├─x %|>% quux() # #> 4. └─global::quux(x) # #> 5. └─x %|>% stop() ## ---- eval = TRUE------------------------------------------------------------- `%!>%` <- magrittr::pipe_eager_lexical ## ---- eval = TRUE------------------------------------------------------------- "foo" %!>% list(., .) ## ---- eval = TRUE, error = TRUE----------------------------------------------- { stop("oh no") %!>% try(silent = TRUE) "success" } ## ---- eval = TRUE------------------------------------------------------------- fn <- TRUE %!>% factory() %!>% { .() } fn() ## ---- eval = TRUE, error = TRUE----------------------------------------------- fn <- TRUE %!>% factory() fn() ## ---- eval = TRUE------------------------------------------------------------- . <- "wrong" fn <- TRUE %!>% factory() fn() ## ----------------------------------------------------------------------------- # faulty <- function() stop("tilt") # f <- function(x) x + 1 # g <- function(x) x + 2 # h <- function(x) x + 3 # # faulty() %!>% f() %!>% g() %!>% h() # #> Error in faulty() : tilt # # traceback() # #> 4: stop("tilt") # #> 3: faulty() # #> 2: .External2(magrittr_pipe) at pipe.R#163 # #> 1: faulty() %!>% f() %!>% g() %!>% h() ## ---- eval = TRUE------------------------------------------------------------- foo <- FALSE NA %!>% { foo <- TRUE; . } foo ## ---- eval = TRUE------------------------------------------------------------- fn <- function() { TRUE %!>% return() FALSE } fn() ## ---- eval = TRUE------------------------------------------------------------- `%?>%` <- magrittr::pipe_lazy_masking ## ---- eval = TRUE------------------------------------------------------------- "foo" %?>% list(., .) ## ---- eval = TRUE------------------------------------------------------------- { stop("oh no") %?>% try(silent = TRUE) "success" } ## ---- eval = TRUE------------------------------------------------------------- fn <- TRUE %?>% factory() fn() ## ----------------------------------------------------------------------------- # faulty <- function() stop("tilt") # f <- function(x) x + 1 # g <- function(x) x + 2 # h <- function(x) x + 3 # # faulty() %?>% f() %?>% g() %?>% h() # #> Error in faulty() : tilt # # traceback() # #> 7: stop("tilt") # #> 6: faulty() # #> 5: f(.) # #> 4: g(.) # #> 3: h(.) # #> 2: .External2(magrittr_pipe) at pipe.R#174 # #> 1: faulty() %?>% f() %?>% g() %?>% h() ## ---- eval = TRUE------------------------------------------------------------- foo <- FALSE TRUE %?>% assign("foo", .) foo ## ---- eval = TRUE, error = TRUE----------------------------------------------- fn <- function() { TRUE %?>% return() FALSE } fn() ## ----------------------------------------------------------------------------- # foobar <- function(x) x %?>% quux() # quux <- function(x) x %?>% stop() # # "tilt" %?>% foobar() # #> Error in x %?>% stop() : tilt # # rlang::last_trace() # #> # #> tilt # #> Backtrace: # #> █ # #> 1. ├─"tilt" %?>% foobar() # #> 2. ├─global::foobar(.) # #> 3. │ └─x %?>% quux() # #> 4. └─global::quux(.) # #> 5. └─x %?>% stop() magrittr/inst/doc/magrittr.html0000644000176200001440000007223514174220110016345 0ustar liggesusers Introducing magrittr

Introducing magrittr

Stefan Milton Bache

November, 2014

Abstract

The magrittr (to be pronounced with a sophisticated french accent) package has two aims: decrease development time and improve readability and maintainability of code. Or even shortr: make your code smokin’ (puff puff)!

To achieve its humble aims, magrittr (remember the accent) provides a new “pipe”-like operator, %>%, with which you may pipe a value forward into an expression or function call; something along the lines of x %>% f, rather than f(x). This is not an unknown feature elsewhere; a prime example is the |> operator used extensively in F# (to say the least) and indeed this – along with Unix pipes – served as a motivation for developing the magrittr package.

This vignette describes the main features of magrittr and demonstrates some features which have been added since the initial release.

Introduction and basics

At first encounter, you may wonder whether an operator such as %>% can really be all that beneficial; but as you may notice, it semantically changes your code in a way that makes it more intuitive to both read and write.

Consider the following example, in which the mtcars dataset shipped with R is munged a little:

library(magrittr)

car_data <- 
  mtcars %>%
  subset(hp > 100) %>%
  aggregate(. ~ cyl, data = ., FUN = . %>% mean %>% round(2)) %>%
  transform(kpl = mpg %>% multiply_by(0.4251)) %>%
  print
#>   cyl   mpg   disp     hp drat   wt  qsec   vs   am gear carb       kpl
#> 1   4 25.90 108.05 111.00 3.94 2.15 17.75 1.00 1.00 4.50 2.00 11.010090
#> 2   6 19.74 183.31 122.29 3.59 3.12 17.98 0.57 0.43 3.86 3.43  8.391474
#> 3   8 15.10 353.10 209.21 3.23 4.00 16.77 0.00 0.14 3.29 3.50  6.419010

We start with a value, here mtcars (a data.frame). From there, we extract a subset, aggregate the information based on the number of cylinders, and then transform the dataset by adding a variable for kilometers per liter as a supplement to miles per gallon. Finally we print the result before assigning it. Note how the code is arranged in the logical order of how you think about the task: data->transform->aggregate, which is also the same order as the code will execute. It’s like a recipe – easy to read, easy to follow!

A horrific alternative would be to write:

car_data <- 
  transform(aggregate(. ~ cyl, 
                      data = subset(mtcars, hp > 100), 
                      FUN = function(x) round(mean(x), 2)), 
            kpl = mpg*0.4251)

There is a lot more clutter with parentheses, and the mental task of deciphering the code is more challenging—particularly if you did not write it yourself.

Note also how “building” a function on the fly for use in aggregate is very simple in magrittr: rather than an actual value as the left-hand side in the pipeline, just use the placeholder. This is also very useful in R’s *apply family of functions.

Granted, you may make the second example better, perhaps throw in a few temporary variables (which is often avoided to some degree when using magrittr), but one often sees cluttered lines like the ones presented.

And here is another selling point: suppose I want to quickly add another step somewhere in the process. This is very easy to do in the pipeline version, but a little more challenging in the “standard” example.

The combined example shows a few neat features of the pipe (which it is not):

  1. By default the left-hand side (LHS) will be piped in as the first argument of the function appearing on the right-hand side (RHS). This is the case in the subset and transform expressions.
  2. %>% may be used in a nested fashion, e.g. it may appear in expressions within arguments. This is illustrated in the mpg to kpl conversion.
  3. When the LHS is needed at a position other than the first, one can use the dot,'.', as placeholder. This is shown in the aggregate expression.
  4. The dot in e.g. a formula is not confused with a placeholder, which is utilized in the aggregate expression.
  5. Whenever only one argument (the LHS) is needed, one can omit the empty parentheses. This is shown in the call to print (which also returns its argument). Here, LHS %>% print(), or even LHS %>% print(.) would also work.
  6. A pipeline with a dot (.) as the LHS will create a unary function. This is used to define the aggregator function.

One feature, which was not demonstrated above is piping into anonymous functions, or lambdas. This is possible using standard function definitions, e.g.:

car_data %>%
(function(x) {
  if (nrow(x) > 2) 
    rbind(head(x, 1), tail(x, 1))
  else x
})

However, magrittr also allows a short-hand notation:

car_data %>%
{ 
  if (nrow(.) > 0)
    rbind(head(., 1), tail(., 1))
  else .
}
#>   cyl  mpg   disp     hp drat   wt  qsec vs   am gear carb      kpl
#> 1   4 25.9 108.05 111.00 3.94 2.15 17.75  1 1.00 4.50  2.0 11.01009
#> 3   8 15.1 353.10 209.21 3.23 4.00 16.77  0 0.14 3.29  3.5  6.41901

Since all right-hand sides are really “body expressions” of unary functions, this is only the natural extension of the simple right-hand side expressions. Of course, longer and more complex functions can be made using this approach.

In the first example, the anonymous function is enclosed in parentheses. Whenever you want to use a function- or call-generating statement as right-hand side, parentheses are used to evaluate the right-hand side before piping takes place.

Another, less useful example is:

1:10 %>% (substitute(f(), list(f = sum)))
#> [1] 55

Additional pipe operators

magrittr also provides three related pipe operators. These are not as common as %>% but they become useful in special cases.

The “tee” pipe, %T>% works like %>%, except it returns the left-hand side value, and not the result of the right-hand side operation. This is useful when a step in a pipeline is used for its side-effect (printing, plotting, logging, etc.). As an example (where the actual plot is omitted here):

rnorm(200) %>%
matrix(ncol = 2) %T>%
plot %>% # plot usually does not return anything. 
colSums
#> [1] 12.59340 14.67222

The “exposition” pipe, %$% exposes the names within the left-hand side object to the right-hand side expression. Essentially, it is a short-hand for using the with functions (and the same left-hand side objects are accepted). This operator is handy when functions do not themselves have a data argument, as for example lm and aggregate do. Here are a few examples as illustration:

iris %>%
  subset(Sepal.Length > mean(Sepal.Length)) %$%
  cor(Sepal.Length, Sepal.Width)
   
data.frame(z = rnorm(100)) %$% 
  ts.plot(z)

Finally, the “assignment” pipe %<>% can be used as the first pipe in a chain. The effect will be that the result of the pipeline is assigned to the left-hand side object, rather than returning the result as usual. It is essentially shorthand notation for expressions like foo <- foo %>% bar %>% baz, which boils down to foo %<>% bar %>% baz. Another example is:

iris$Sepal.Length %<>% sqrt

The %<>% can be used whenever expr <- ... makes sense, e.g. 

  • x %<>% foo %>% bar
  • x[1:10] %<>% foo %>% bar
  • x$baz %<>% foo %>% bar

Aliases

In addition to the %>%-operator, magrittr provides some aliases for other operators which make operations such as addition or multiplication fit well into the magrittr-syntax. As an example, consider:

rnorm(1000)    %>%
multiply_by(5) %>%
add(5)         %>%
{ 
   cat("Mean:", mean(.), 
       "Variance:", var(.), "\n")
   head(.)
}
#> Mean: 4.803946 Variance: 24.78496
#> [1]  0.02983414 11.61674243  8.36449261 14.22637778  8.51670817 12.71260160

which could be written in more compact form as:

rnorm(100) %>% `*`(5) %>% `+`(5) %>% 
{
  cat("Mean:", mean(.), "Variance:", var(.),  "\n")
  head(.)
}

To see a list of the aliases, execute e.g. ?multiply_by.

Development

The magrittr package is also available in a development version at the GitHub development page: github.com/tidyverse/magrittr.

magrittr/inst/doc/tradeoffs.html0000644000176200001440000016767314174220110016504 0ustar liggesusers Design tradeoffs

Design tradeoffs

Hadley Wickham

Lionel Henry

There are many different ways that magrittr could implement the pipe. The goal of this document is to elucidate the variations, and the various pros and cons of each approach. This document is primarily aimed at the magrittr developers (so we don’t forget about important considerations), but will be of interest to anyone who wants to understand pipes better, or to create their own pipe that makes different tradeoffs

Code transformation

There are three main options for how we might transform a pipeline in base R expressions. Here they are illustrated with x %>% foo() %>% bar():

  • Nested

    bar(foo(x))
  • Eager (mask), masking environment

    This is essentially how %>% has been implemented prior to magrittr 2.0:

    local({
      . <- x
      . <- foo(.)
      bar(.)
    })
  • Eager (mask-num): masking environment, numbered placeholder

    local({
      ...1 <- x
      ...2 <- foo(...1)
      bar(...2)
    })
  • Eager (lexical): lexical environment

    This variant assigns pipe expressions to the placeholder . in the current environment. This assignment is temporary: once the pipe has returned, the placeholder binding is reset to its previous state.

    with_dot_cleanup <- function(expr) {
      # Initialises `.` in the caller environment and resets it on exit.
      # (We use `:=` instead of `=` to avoid partial matching.)
      rlang::local_bindings(. := NULL, .env = parent.frame())
      expr
    }
    with_dot_cleanup({
      . <- x
      . <- foo(.)
      bar(.)
    })
  • Lazy (mask): masking environments

    mask1 <- new.env(parent = env)
    mask2 <- new.env(parent = env)
    
    delayedAssign(".", x, mask1)
    delayedAssign(".", foo(.), mask2)
    with(mask2, bar(.))
  • Lazy (mask-num): masking environment, numbered placeholder

    local({
      delayedAssign("...1", x)
      delayedAssign("...2", foo(...1))
      bar(...2)
    })
  • Lazy (lexical-num): lexical environment, numbered placeholder

    delayedAssign("...1", x)
    delayedAssign("...2", foo(.))
    bar(...2)

We’ll first explore the desired properties we might want a pipe to possess and then see how each of the three variants does.

Desired properties

These are the properties that we might want a pipe to possess, roughly ordered from most important to least important.

  • Visibility: the visibility of the final function in the pipe should be preserved. This is important so that pipes that end in a side-effect function (which generally returns its first argument invisibly) do not print.

  • Multiple placeholders: each component of the pipe should only be evaluated once even when there are multiple placeholders, so that sample(10) %>% cbind(., .) yields two columns with the same value. Relatedly, sample(10) %T>% print() %T>% print() must print the same values twice.

  • Lazy evaluation: steps of the pipe should only be evaluated when actually needed. This is a useful property as it means that pipes can handle code like stop("!") %>% try(), making pipes capable of capturing a wider range of R expressions.

    On the other hand, it might have surprising effects. For instance if a function that suppresses warnings is added to the end of a pipeline, the suppression takes effect for the whole pipeline.

  • Persistence of piped values: arguments are not necessarily evaluated right away by the piped function. Sometimes they are evaluated long after the pipeline has returned, for example when a function factory is piped. With persistent piped values, the constructed function can be called at any time:

    factory <- function(x) function() x
    fn <- NA %>% factory()
    fn()
    #> [1] NA
  • Refcount neutrality: the return value of the pipeline should have a reference count of 1 so it can be mutated in place in further manipulations.

  • Eager unbinding: pipes are often used with large data objects, so intermediate objects in the pipeline should be unbound as soon as possible so they are available for garbage collection.

  • Progressive stack: using the pipe should add as few entries to the call stack as possible, so that traceback() is maximally useful.

  • Lexical side effects: side effects should occur in the current lexical environment. This way, NA %>% { foo <- . } assigns the piped value in the current environment and NA %>% { return(.) } returns from the function that contains the pipeline.

  • Continuous stack: the pipe should not affect the chain of parent frames. This is important for tree representations of the call stack.

It is possible to have proper visibility and a neutral impact on refcounts with all implementations by being a bit careful, so we’ll only consider the other properties:

Nested Eager
(mask)
Eager
(mask-num)
Eager
(lexical)
Lazy
(mask)
Lazy
(mask-num)
Lazy
(lexical-num)
Multiple placeholders
Lazy evaluation
Persistence
Eager unbinding
Progressive stack
Lexical effects
Continuous stack

Implications of design decisions

Some properties are a direct reflection of the high level design decisions.

Placeholder binding

The nested pipe does not assign piped expressions to a placeholder. All the other variants perform this assignment. This means that with a nested rewrite approach, it isn’t possible to have multiple placeholders unless the piped expression is pasted multiple times. This would cause multiple evaluations with deleterious effects:

sample(10) %>% list(., .)

# Becomes
list(sample(10), sample(10))

Assigning to the placeholder within an argument would preserve the nestedness and lazyness. However that wouldn’t work properly because there’s no guarantee that the first argument will be evaluated before the second argument.

sample(10) %>% foo(., .)
foo(. <- sample(10), .)

For these reasons, the nested pipe does not support multiple placeholders. By contrast, all the other variants assign the result of pipe expressions to the placeholder. There are variations in how the placeholder binding is created (lazily or eagerly, in a mask or in the current environment, with numbered symbols or with a unique symbol) but all these variants allow multiple placeholders.

Masking environment

Because the local variants of the pipe evaluate in a mask, they do not have lexical effects or a continuous stack. This is unlike the lexical variants that evaluate in the current environment.

Laziness

Unlike the lazy variants, all eager versions implementing the pipe with iterated evaluation do not pass the lazy evaluation criterion.

Secondly, no lazy variant passes the progressive stack criterion. By construction, lazy evaluation requires pushing all the pipe expressions on the stack before evaluation starts. Conversely, all eager variants have a progressive stack.

Numbered placeholders

None of the variants that use numbered placeholders can unbind piped values eagerly. This is how they achieve persistence of these bindings.

Three implementations

The GNU R team is considering implementing the nested approach in base R with a parse-time code transformation (just like -> is transformed to <- by the parser).

We have implemented three approaches in magrittr:

  • The nested pipe
  • The eager lexical pipe
  • The lazy masking pipe

These approaches have complementary strengths and weaknesses.

Nested pipe

`%|>%` <- magrittr::pipe_nested

Multiple placeholders ❌

The nested pipe does not bind expressions to a placeholder and so can’t support multiple placeholders.

"foo" %|>% list(., .)
#> Error: Can't use multiple placeholders.

Lazy evaluation ✅

Because it relies on the usual rules of argument application, the nested pipe is lazy.

{
  stop("oh no") %|>% try(silent = TRUE)
  "success"
}
#> [1] "success"

Persistence and eager unbinding ✅

The pipe expressions are binded as promises within the execution environment of each function. This environment persists as long as a promise holds onto it. Evaluating the promise discards the reference to the environment which becomes available for garbage collection.

For instance, here is a function factory that creates a function. The constructed function returns the value supplied at the time of creation:

factory <- function(x) function() x
fn <- factory(TRUE)
fn()
#> [1] TRUE

This does not cause any issue with the nested pipe:

fn <- TRUE %|>% factory()
fn()

Progressive stack ❌

Because the piped expressions are lazily evaluated, the whole pipeline is pushed on the stack before execution starts. This results in a more complex backtrace than necessary:

faulty <- function() stop("tilt")
f <- function(x) x + 1
g <- function(x) x + 2
h <- function(x) x + 3

faulty() %|>% f() %|>% g() %|>% h()
#> Error in faulty() : tilt

traceback()
#> 7: stop("tilt")
#> 6: faulty()
#> 5: f(faulty())
#> 4: g(f(faulty()))
#> 3: h(g(f(faulty())))
#> 2: .External2(magrittr_pipe) at pipe.R#181
#> 1: faulty() %|>% f() %|>% g() %|>% h()

Also note how the expressions in the backtrace look different from the actual code. This is because of the nested rewrite of the pipeline.

Lexical effects ✅

This is a benefit of using the normal R rules of evaluation. Side effects occur in the correct environment:

foo <- FALSE
TRUE %|>% assign("foo", .)
foo
#> [1] TRUE

Control flow has the correct behaviour:

fn <- function() {
  TRUE %|>% return()
  FALSE
}
fn()
#> [1] TRUE

Continuous stack ✅

Because evaluation occurs in the current environment, the stack is continuous. Let’s instrument errors with a structured backtrace to see what that means:

options(error = rlang::entrace)

The tree representation of the backtrace correctly represents the hierarchy of execution frames:

foobar <- function(x) x %|>% quux()
quux <- function(x) x %|>% stop()

"tilt" %|>% foobar()
#> Error in x %|>% stop() : tilt

rlang::last_trace()
#> <error/rlang_error>
#> tilt
#> Backtrace:
#>     █
#>  1. ├─"tilt" %|>% foobar()
#>  2. └─global::foobar("tilt")
#>  3.   ├─x %|>% quux()
#>  4.   └─global::quux(x)
#>  5.     └─x %|>% stop()

Eager lexical pipe

`%!>%` <- magrittr::pipe_eager_lexical

Multiple placeholders ✅

Pipe expressions are eagerly assigned to the placeholder. This makes it possible to use the placeholder multiple times without causing multiple evaluations.

"foo" %!>% list(., .)
#> [[1]]
#> [1] "foo"
#> 
#> [[2]]
#> [1] "foo"

Lazy evaluation ❌

Assignment forces eager evaluation of each step.

{
  stop("oh no") %!>% try(silent = TRUE)
  "success"
}
#> Error in stop("oh no") %!>% try(silent = TRUE): oh no

Persistence: ❌

Because we’re updating the value of . at each step, the piped expressions are not persistent. This has subtle effects when the piped expressions are not evaluated right away.

With the eager pipe we get rather confusing results with the factory function if we try to call the constructed function in the middle of the pipeline. In the following snippet the placeholder . is binded to the constructed function itself rather than the initial value TRUE, by the time the function is called:

fn <- TRUE %!>% factory() %!>% { .() }
fn()
#> function() x
#> <bytecode: 0x7fe2f5af6fd8>
#> <environment: 0x7fe2f5a5a860>

Also, since we’re binding . in the current environment, we need to clean it up once the pipeline has returned. At that point, the placeholder no longer exists:

fn <- TRUE %!>% factory()
fn()
#> Error in fn(): object '.' not found

Or it has been reset to its previous value, if any:

. <- "wrong"
fn <- TRUE %!>% factory()
fn()
#> [1] "wrong"

Eager unbinding: ✅

This is the flip side of updating the value of the placeholder at each step. The previous intermediary values can be collected right away.

Progressive stack: ✅

Since pipe expressions are evaluated one by one as they come, only the relevant part of the pipeline is on the stack when an error is thrown:

faulty <- function() stop("tilt")
f <- function(x) x + 1
g <- function(x) x + 2
h <- function(x) x + 3

faulty() %!>% f() %!>% g() %!>% h()
#> Error in faulty() : tilt

traceback()
#> 4: stop("tilt")
#> 3: faulty()
#> 2: .External2(magrittr_pipe) at pipe.R#163
#> 1: faulty() %!>% f() %!>% g() %!>% h()

Lexical effects and continuous stack: ✅

Evaluating in the current environment rather than in a mask produces the correct side effects:

foo <- FALSE
NA %!>% { foo <- TRUE; . }
#> [1] NA

foo
#> [1] TRUE
fn <- function() {
  TRUE %!>% return()

  FALSE
}
fn()
#> [1] TRUE

Lazy masking pipe

`%?>%` <- magrittr::pipe_lazy_masking

Multiple placeholders ✅

Pipe expressions are lazily assigned to the placeholder. This makes it possible to use the placeholder multiple times without causing multiple evaluations.

"foo" %?>% list(., .)
#> [[1]]
#> [1] "foo"
#> 
#> [[2]]
#> [1] "foo"

Lazy evaluation ✅

Arguments are assigned with delayedAssign() and lazily evaluated:

{
  stop("oh no") %?>% try(silent = TRUE)
  "success"
}
#> [1] "success"

Persistence: ✅

The lazy masking pipe uses one masking environment per pipe expression. This allows persistence of the intermediary values and out of order evaluation. The factory function works as expected for instance:

fn <- TRUE %?>% factory()
fn()
#> [1] TRUE

Eager unbinding: ✅

Because we use one mask environment per pipe expression, the intermediary values can be collected as soon as they are no longer needed.

Progressive stack: ❌

With a lazy pipe the whole pipeline is pushed onto the stack before evaluation.

faulty <- function() stop("tilt")
f <- function(x) x + 1
g <- function(x) x + 2
h <- function(x) x + 3

faulty() %?>% f() %?>% g() %?>% h()
#> Error in faulty() : tilt

traceback()
#> 7: stop("tilt")
#> 6: faulty()
#> 5: f(.)
#> 4: g(.)
#> 3: h(.)
#> 2: .External2(magrittr_pipe) at pipe.R#174
#> 1: faulty() %?>% f() %?>% g() %?>% h()

Note however how the backtrace is less cluttered than with the nested pipe approach, thanks to the placeholder.

Lexical effects ❌

The lazy pipe evaluates in a mask. This causes lexical side effects to occur in the incorrect environment.

foo <- FALSE
TRUE %?>% assign("foo", .)
foo
#> [1] FALSE

Stack-sensitive functions like return() function cannot find the proper frame environment:

fn <- function() {
  TRUE %?>% return()
  FALSE
}
fn()
#> [1] FALSE

Continuous stack ❌

The masking environment causes a discontinuous stack tree:

foobar <- function(x) x %?>% quux()
quux <- function(x) x %?>% stop()

"tilt" %?>% foobar()
#> Error in x %?>% stop() : tilt

rlang::last_trace()
#> <error/rlang_error>
#> tilt
#> Backtrace:
#>     █
#>  1. ├─"tilt" %?>% foobar()
#>  2. ├─global::foobar(.)
#>  3. │ └─x %?>% quux()
#>  4. └─global::quux(.)
#>  5.   └─x %?>% stop()
magrittr/inst/logo.svg0000644000176200001440000005347013701613606014555 0ustar liggesusers image/svg+xml magrittr/inst/logo-hex.svg0000644000176200001440000005367513701613606015346 0ustar liggesusers image/svg+xml magrittr/inst/logo-hex.png0000644000176200001440000004004113701613606015312 0ustar liggesusersPNG  IHDR6sBIT|d pHYs  DtEXtSoftwarewww.inkscape.org< IDATxw@SgƟlPNP\"nm[+Yq[kVWb]ܸ%QP+BI & s_{< QPXnMaW em dNM#wQf)P?PjP8сAlJ/>dNM烠vv1< Y-&2LQ [O3ŷ"sjeW͔C AHIIS !%T(:u²%s1zB44,ǎ}N.ͣT װI\5ޝac<@w+*(`Μ/1gd(tY]ݻpuDyE% #lDlqDb@ujG+$Aatۮ ::tGAAܮI,&( 6Gnʠ r mg۷ݦ( /9 ddI-Eqjssڊ@;!ΝtfQ cny/x U+T[<Ҧ]8kp ݶ1g;o :m^`^(/ނڦڰ8`<ݶ FÊ󠩩Ay)))Ņ7q#Io?eF%a\Iגg&PK˾XtׯqEDFJ|NqmSNmcc#B,]o׉6,1c6-1Bbp;޽T.;ؖR\یS;ZA"鶭ٳlYT8.}p eeĦtoIVLzABjGR7b>44Zc-p…}\m !̍ VRB7P} &&o48o޼K&ޮp5FI @u%s0nӭ8lJqmRʩ[ AP@mUUe̝33fL[-=빫(*H+ Էљ%a\ZS;7qwKBd`xG,^<jtnSUo\~7!een\66:*S[j %[Y[`ʅ066ts"Bb$a \;$h)&F")#w8 ux"n8q22H;R\֦6 <vtVSU9>YT\EE<-D!5ncKP@JǍ%s.IIii9\#xE栨tĝԬ-y6ّg]E@@$̗~EN=x2 ”nYm8tX߀/1n0Hȩmzs)L۶ f``2i/l $\BQ$O(P3hLz):ScbX4**4- *+eےI 06ĥVCS;::Q%YK%jem5`hOi9{ERv(* U۩[&~/ݻaʯ0P7bc_IV@2bS`T]̈ 0EEMMN cʔ`0dqsk6en|@q7Ƽ~)B;u=AsJ&M̈́,nnX,xzޅTUWm^Ʃ8uJ 0dPk^ݮ ʐ0yy8  PB7Nȩ4L8`XA3c8ZzmZy  x2Ec@ac@LF@s6ԒlEfbGY܎( 8En_Wjcӭ2a*t.nz;Ҟm*byWx]%*A*ȩ?`DHƚUN+?>U ۼ9pCkF]8WFp^~6-.nHHHAP䆧1YdLmmM89͐2ԋO]B ) dR[kbМʯ ě9ƴ:b,.];eVF;%c/ܠ]\6 @M3.xAS3'&>2d5s٩kL`2>SUUy!._%r3'ZM|dk*Sħ99,DiTWs&A!J3'zqXk$/i_$ťcBCSݺ`P+8.r0$d"? /N ;$QY֭G+S/[6Nnа?}!Xr!:uxҁ$Is箢XaI&)SI,9!б=C*+꼀0bE0a]Ñ!yy}A$% Μ%qWʊCuIi~i] N:Ñ!o޼oʡSXXT@}dv-MQݯA^^MwX2D }.ݴCp)9ص(L4:N}YZ]]=O=Q];е${]m-A;O1:kj9:u]9yW$Iq:E#bri1+qHN]BrJzݻ¼'44Q^Q,HH滎\Q]GqNfi*z}_GG`g7tii9/\۵^^w|?`o?f2Vr֟]Ŀ}JJ'Fw%q-+wᴪ=p6o盨mn%sn]tSR-y"S߾={0.^e%̈́6tQ^Q ˷蛷9g&S͛w<[nP6'NtС<ߓք1>>Qd]ػERR%>.`V b|hMErꨨ<_72҇-om_Mz\+< ΢( b͸#G+D.=Acb\˱1Ѽ# Drׯy/ B^&ܹq_e%׎/*@sXvhtz;lH u$HN]RR=LDH^-,#WOcRR3av;&rpKQSRUUݺ5nTbbI+F"}XWӵ:]:aXH͛tf<F$.b| %S<\ѕ9U3\n6_F˖nAAv>~idcVg.ᳱ&'l߯cZUo6`ePT_!::Wl3 ~wBmx55|"9&P!>Np$^$T^?q pŕ+wb_-sx!*M>y<&**V-#Sap&!!Q<'XZZڞb?ax˻w_KD Tz0OH|1sI S[Z\-(*.׵B٪͝wE4jgbɴ e$:]5V=Iibܸ{ix HߔJGŷ/J?{ ex]07l_uJJ,Q(z4;G5\jlz̮BB#8t N ^Xn h' w}q&a0 -- #;C FO?z<,6 >&N ]tD&-++LJ܏_nPheff8u2wݻ~]ļ3&&w ^L{򗛛{P\R ^R[jbosoDR|bp8Mع{2WɓrAAUU۷0E^^z6y\ܻy7/$CQ*+Y ƄPP] Чƍs@QQ _e($&@Ԑ6k uUڵsyn|5{HJJ+)**$|H$LS{().ERhe|OG"""g<Lp JJ}*1M쪝JC"}̠LH#//Q!55މůӥx_RR `8S=2!iAa ANNNM``ݺ%049׫(+޽LiӊFdu5 B K˾8ׯ߇5Cb9s'c)Ic&lmmahgӬprЋ .iL !8 Oi_buKwEEB2|RiѻWN0wd88 c\,{*__0֭] &t!'e0a=w1M:7ANfb ˺9."#cg!Q"!Rhҫx(((F褭.];c+ ? > ͔)cnblIhh4uma֭Z9q(Dxs$%0E訤Nlm*k'|O4L0``E2ePsjAX?g FZZXaogƣw3͖fջEJG,rSǵ ׯ$~!bwPWWa>uh!HA)/@HHwS0 c1cca9̀@9r/ŲWVV'Q oX"UC@@OyyX[[`ᰵk  **O)vY>ƎǸqáA(Iw6.<ԴLl;FU %̮BXh ?hK[[o:urJ?<.0Əh2`A`:npc*IO^`y3ƞv$%zS;v8)YYo4 >> CMUÇƘ107Zk*cE;v8>+|n-Eػ>źuahIMPwS&Ɖ6F``M,[AS,@@`8mP[kc-!'GkgVI8twܾ{] Ϋ~ƤIcl^Ά0ݻbCUUCXaܘ`e.NN$ɀ&iYrITVVYn>Q%e8GĎ6èQh۠V$Id@]]݅%''MZ unݒf[T+ dmmQ#~PRu5EEPPThA"S$AjZѣa(5j=B@`8bDaAQIN NZ<CпV.KڶӁes& ^RR뷉5GaHۺU ! 0^4;ˣlm0=%T(S'jptŨQE |w9.>oIw]grU["6%>WhSXº~Hѣ0j B$;w|p͋o|Uu5^ٸrlla͚ء9 6X,sϞE 3ƦvbX6w/3"WkNyNGk uU8ѣЧYpc^7RR+ʕ?by9sP6PNmbb 01 XèvfwRRR_~ُWM5EQ}5'4\.IPM4K7I3i fѣacݏ*ԛ9?Eשc̟rj=0aoz>f5*laع;7;I8|22bXn)x+ Pk/_[^;=vv|+M;j+ իw+EՏiY6+D+G]iqZBbq L&]ӲcX:Y1C?k"?=1p`?38.v>BC =DEhf0:uH{ G.כP21 ɰlxx܆mkeerW9<>9'!|] ?[`00y?G^LL^$$"%iX,.\ /bmdԢ_/j==++s;񸢂={?𬆹wM9Sjֽ{~<_WUUƮ] $hjj}w&Aq 44Km+whqCp0}V$ICtZ:/ ~!"Q*XE%Uy̘{M3:iS3?ҭ[v܌NH iY|;lvƏѠ>Qh4T:>>2&ƍu9xnK6 niӝVNN3q^~],-4Q?*ov!Z>Cݻo'&&G3`@__Tcټa"}{@C]*BaAH|dM͌D٣1O.R#BPIJs1vpZIbޒ3 !G¢%:@OZ^vu+nS0 L<Kiy%|>_Ku灅IDATkRqjs3l ~ҩz" E',{b-jJ|lI;+(]Jũ54#.as>W:m۪pZ8U9 mya&Z;JMM4|šZX^P>Wϵ%((Kn͛vh 0f=Ξ_\s~ kc_do.h٤)SL}R11 >L&"-(‘#t٭a*hh-ۮ ܰ+666P3?\]^f" :utn}rW8~lWmKk+ ޝيqKl%er{ T  b=g-39wwrPJ pJ0| =f~AKֈzup q|ط<!w'?{|cʣGڵM6p8v ^wyQ _~1Jz&hnWڵ~jdB\.[#$Jl7BbxodEwjeb-|G$\N^@`PfϞ-͕U 44.jHuPQm_Tvyy9̙3 Oj<'x,6m0uʸEx4= 5ȊW*!! `}P$W${=3gE-i3tB6n\Mv}E ((rrLkUjVa'O[[l]쯰F̦H /[׊iѯJB5ϟCһ)V,q rh uKRXZ*T 1yJkPWŗ_n2sgaab]0mxL4[**MH3K_ 5 ?3%U ˊ11x +HLQB֯_.]:ᴀ*][h"N GAG>l۷֯[ S}OׯK# ΝYGmCG:F-GG%E,]2KFbR^LACQQhwtﮇ|h;>Z2dHShwȜZFC229vmNmwCpH$]&eArrr=-:Z:((Ç!((2 ))-(Ktt(tiPT\ sWq㲖Ja0ĺSaϟ'e3~j,w:3)ĺS_t묚Hly G#F |a(--EX,Vcw}ammKnbƌ <!<<ք rsqTضm#;"22CS<MaOĺtOuǜ9swL ܊"::׮GYy:u¯f4Pxoo[yW=,iiYp |q;1kD#yN;uqq)za˨(ʯ9$EQl }EΩOV[!5-q76c )C"߱d&O7QQ/`ddӡCBdx u|l~ӧڵkQ\r> 79.\]=ԌIpp{-:4)cŵfWc01鎷ޭ_$$ ;lv9ƥ˷s}tൔ 9soi&]s_#~޺cOJJy Q N8:k57166 ѳc_0c GֽKlشF)ǎ bw );U"6%UqF_xIIȈXD=ڮuFO`G\zPOųI|iš/nP$;ų0x% н\{b>PQV&?_`yAg`@8,())ҲOݓ59% ͫf㻍ah;*Ӏ0 'm@$: 558 3g}ehss&a]z py٩C"1d(o-Z>owҪ/ w  p{&L̺s22Ը\?03¡ݰJmHoJ™WʯPRZgׯ^U]G]'OmpUTWsi&b]:wƴi«W.z0 B ܾ={~@DDX,qзY]5}u5!@M3>@Ʉk}N.v,'DŽ+cDl:@MOMM5t{=$%c usZf5U.!2*_N)d#9%z Qɩ9HID&|!IvE>ff|fB[L6]vFZ8ѱ˗o \XYUN>}ٳk¡ |bc BYi9n'&|Khi!(fy26KM=ȑ`0'ڍuOK˾ ~(/vPWWE׮XҒr WE%E8ƭ[`5EťI=>>Q`i/n ԩcAD͏&8= >x!^%)i9:ֽ$Cm¶X 4QQŽaaK."9uPpXl6 }.6g^EEE%,AQq)""0~_`h;5Uxs $&&5%]a04ԇyM蘄F5o:kU>] c6 o͇ؼy%r =6W 6e3 # m{̀]UgQ7tHM˄o&O }Nc@&mPw}1X,""IFFuuϢ7O%11 e%3F >44 u7,$&aا@QQ1u$IW/%e <,FxD,V . U ?vjN/){`TܿM@MUa]| Yk;0(cyJ&]Fp ZZ2esoTT0ܞ EQPSSwp$fxb_`h;zzN]T\ n5?g˄QȺʹj"ѳ (uFOAAMroQZZ~GÅK@Nj<"8Xi֩ pM̙3n>ċuܺ$IOXW`2`6[rIxy݅yO$ s:<DԤ;uYNJM˄y/0 TT=Q.稨Gq ?x~ݻHx 歇 V~PZVu,eوŊe5M;vT*:駵xOϰu!>bA_0B#wVO];ǟDYY9ع7n>@\\"ع eè<}}]xzޅUo(uT-~)XP'YQQj/ /г1RR31gXX߿] `@,AL $$#;*0_~=1JZa=Й9/_v5Z0 Ew  fyNN.Ν7NccemP\\az0Ƌ$ $J׋f!..K /_&Kgp% {~]:50ɡS'-;9&~x)vmToolXV.nz7 '0sjjL ukۍaao7;C]]A@OÖ́vA`PSW7|ee꣸sL٧fQfF 1C֛w011e6ݺ 0q#@QQjx<UXl. Al<1Ә:u,LlwrsK7qM\z>u<6S`@8RS3;ADY3kWVVtN5EE01uk "*+Y9r-J ƍC1atGpp!''3fLĔɂ V DX%eriiPª9`PRR_b[|[H5RR3~otPr`;8%%Eln%mcGJJF\5UX>9r /uC"aٿoqhx(Æ ʡ_FPP$A8X,RR2>^Տ0,^wұoV~à .SgX0P=}{- Ԭaيt@}?ӳ1W9E/aOFd#0(Lee I LIipqqGBBԵ j5ey8z>>A"@MO(mNqq).^YN v*-ZSUHt***b/}]]ݻpuDy y&j&=vΝtm'vwFhX skY\(27Ǧ&jf̷he2$,=X6"m Dz H&)⻠toz K6@͖ UvD] 0|`-$ pwY.E\*w~jj>ܭ6ԵKq] :mZ0]w҆]U7[t$\ }2>iXIڰ8`pktOԤF=̌j!Wpq/i?2TӪmV8Hd2~E} No&//\=%7se[].ic|N]IOtڭΙ{oS/nmSG+1Ku;Hq* XL9`2bP؊of$SӃS?hjGmSHƩV‰%%TZȜZ13P=hBU|^Iqh2 п5`ý NcP:)P39d?oZ҆ _IENDB`