lifecycle/0000755000176200001440000000000013520557775012231 5ustar liggesuserslifecycle/NAMESPACE0000644000176200001440000000037213516776321013445 0ustar liggesusers# Generated by roxygen2: do not edit by hand S3method(print,lifecycle_warning_deprecated) export(badge) export(deprecate_soft) export(deprecate_stop) export(deprecate_warn) export(deprecated) export(last_warning) export(last_warnings) import(rlang) lifecycle/README.md0000644000176200001440000000305713516014563013501 0ustar liggesusers # lifecycle [![Travis build status](https://travis-ci.org/r-lib/lifecycle.svg?branch=master)](https://travis-ci.org/r-lib/lifecycle) [![Codecov test coverage](https://codecov.io/gh/r-lib/lifecycle/branch/master/graph/badge.svg)](https://codecov.io/gh/r-lib/lifecycle?branch=master) [![CRAN status](https://www.r-pkg.org/badges/version/lifecycle)](https://CRAN.R-project.org/package=lifecycle) [![Lifecycle: maturing](https://img.shields.io/badge/lifecycle-maturing-blue.svg)](https://www.tidyverse.org/lifecycle/#maturing) lifecycle provides a set of tools and conventions to manage the life cycle of your exported functions. ## Installation Install the development version of lifecycle from GitHub with: ``` remotes::install_github("r-lib/lifecycle") ``` ## Usage Use lifecycle to document the status of your exported functions and arguments: * Choose one of the 7 lifecycle stages a function or argument can be in. You can choose from 4 development stages (experimental, maturing, stable, and questining) and 3 deprecation stages (soft-deprecated, deprecated, and defunct). * If the function or argument is deprecated, make sure your users know about by calling `deprecate_soft()`, `deprecate_warn()`, or `deprecate_stop()`. These functions try to be informative without being too verbose, with increasing levels of verbosity as the deprecation stage advances. * Include the relevant lifecycle badge in your documentation. Consult the usage vignette to learn about the workflow: `vignette("usage", package = "lifecycle")`. lifecycle/man/0000755000176200001440000000000013516014452012765 5ustar liggesuserslifecycle/man/lifecycle-package.Rd0000644000176200001440000000213213516776060016614 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/lifecycle-package.R \docType{package} \name{lifecycle-package} \alias{lifecycle} \alias{lifecycle-package} \title{lifecycle: Manage the Life Cycle of your Package Functions} \description{ Manage the life cycle of your exported functions with shared conventions, documentation badges, and non-invasive deprecation warnings. The 'lifecycle' package defines four development stages (experimental, maturing, stable, and questioning) and three deprecation stages (soft-deprecated, deprecated, and defunct). It makes it easy to insert badges corresponding to these stages in your documentation. Usage of deprecated functions are signalled with increasing levels of non-invasive verbosity. } \seealso{ Useful links: \itemize{ \item \url{https://github.com/r-lib/lifecycle} \item Report bugs at \url{https://github.com/r-lib/lifecycle/issues} } } \author{ \strong{Maintainer}: Lionel Henry \email{lionel@rstudio.com} Other contributors: \itemize{ \item RStudio [copyright holder] } } \keyword{internal} lifecycle/man/macros/0000755000176200001440000000000013514370224014251 5ustar liggesuserslifecycle/man/macros/lifecycle.Rd0000644000176200001440000000012313514370224016473 0ustar liggesusers \newcommand{\lifecycle}{\Sexpr[results=rd, stage=render]{lifecycle::badge("#1")}} lifecycle/man/verbosity.Rd0000644000176200001440000000327413515611214015306 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/verbosity.R \name{verbosity} \alias{verbosity} \title{Control the verbosity of deprecation signals} \description{ There are 3 levels of verbosity for deprecated functions: silence, warning, and error. Since the lifecycle package avoids disruptive warnings, the default level of verbosity depends on the lifecycle stage of the deprecated function, on the context of the caller (global environment or testthat unit tests cause more warnings), and whether the warning was already issued (see the help for \link[=deprecate_soft]{deprecation functions}). You can control the level of verbosity with the global option \code{lifecycle_verbosity}. It can be set to: \itemize{ \item \code{"default"} or \code{NULL} for the default non-disruptive settings. \item \code{"quiet"}, \code{"warning"} or \code{"error"} to force silence, warnings or errors for deprecated functions. } Note that functions calling \code{\link[=deprecate_stop]{deprecate_stop()}} invariably throw errors. } \examples{ if (rlang::is_installed("testthat")) { library(testthat) mytool <- function() { deprecate_soft("1.0.0", "mytool()") 10 * 10 } # Forcing the verbosity level is useful for unit testing. You can # force errors to test that the function is indeed deprecated: test_that("mytool is deprecated", { rlang::with_options(lifecycle_verbosity = "error", { expect_error(mytool(), class = "defunctError") }) }) # Or you can enforce silence to safely test that the function # still works: test_that("mytool still works", { rlang::with_options(lifecycle_verbosity = "quiet", { expect_equal(mytool(), 100) }) }) } } lifecycle/man/figures/0000755000176200001440000000000013515611230014425 5ustar liggesuserslifecycle/man/figures/lifecycle-defunct.svg0000644000176200001440000000170413514370224020541 0ustar liggesuserslifecyclelifecycledefunctdefunct lifecycle/man/figures/lifecycle-maturing.svg0000644000176200001440000000170613514370224020741 0ustar liggesuserslifecyclelifecyclematuringmaturing lifecycle/man/figures/lifecycle-archived.svg0000644000176200001440000000170713514370224020701 0ustar liggesusers lifecyclelifecyclearchivedarchived lifecycle/man/figures/lifecycle-soft-deprecated.svg0000644000176200001440000000172613514370224022166 0ustar liggesuserslifecyclelifecyclesoft-deprecatedsoft-deprecated lifecycle/man/figures/lifecycle-questioning.svg0000644000176200001440000000171413514370224021457 0ustar liggesuserslifecyclelifecyclequestioningquestioning lifecycle/man/figures/lifecycle-stable.svg0000644000176200001440000000167413514370224020371 0ustar liggesuserslifecyclelifecyclestablestable lifecycle/man/figures/lifecycle-experimental.svg0000644000176200001440000000171613514370224021611 0ustar liggesuserslifecyclelifecycleexperimentalexperimental lifecycle/man/figures/lifecycle-deprecated.svg0000644000176200001440000000171213514370224021210 0ustar liggesuserslifecyclelifecycledeprecateddeprecated lifecycle/man/figures/lifecycle-retired.svg0000644000176200001440000000170513514370224020550 0ustar liggesusers lifecyclelifecycleretiredretired lifecycle/man/deprecated.Rd0000644000176200001440000000260413515611466015365 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/arg.R \name{deprecated} \alias{deprecated} \title{Mark an argument as deprecated} \usage{ deprecated() } \description{ Signal deprecated argument by using self-documenting sentinel \code{deprecated()} as default argument. It returns \code{\link[rlang:missing_arg]{rlang::missing_arg()}}, so you can test whether the user supplied the argument with \code{\link[rlang:is_missing]{rlang::is_missing()}} (see examples). } \section{Magical defaults}{ We recommend importing \code{lifecycle::deprecated()} in your namespace and use it without the namespace qualifier. In general, we \href{https://principles.tidyverse.org/def-magical.html}{advise against} such magical defaults, i.e. defaults that cannot be evaluated by the user. In the case of \code{deprecated()}, the trade-off is worth it because the meaning of this default is obvious and there is no reason for the user to call \code{deprecated()} themselves. } \examples{ foobar_adder <- function(foo, bar, baz = deprecated()) { # Check if user has supplied `baz` instead of `bar` if (!rlang::is_missing(baz)) { # Signal the deprecation to the user deprecate_warn("1.0.0", "foo::bar_adder(baz = )", "foo::bar_adder(bar = )") # Deal with the deprecated argument for compatibility bar <- baz } foo + bar } foobar_adder(1, 2) foobar_adder(1, baz = 2) } lifecycle/man/last_warnings.Rd0000644000176200001440000000252213515626544016142 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/warning.R \name{last_warnings} \alias{last_warnings} \alias{last_warning} \title{Display last deprecation warnings} \usage{ last_warnings() last_warning() } \description{ Call these helpers to see the last deprecation warnings along with their backtrace: \itemize{ \item \code{last_warnings()} returns a list of all warnings that occurred during the last top-level R command. \item \code{last_warning()} returns only the last. } If you call these in the console, these warnings are printed with a backtrace. Pass the \code{simplify} argument to control the verbosity of the backtrace. It supports one of \code{"branch"} (the default), \code{"collapse"}, and \code{"none"} (in increasing order of verbosity). } \examples{ # These examples are not run because `last_warnings()` does not # work well within knitr and pkgdown \dontrun{ f <- function() invisible(g()) g <- function() list(h(), i()) h <- function() deprecate_warn("1.0.0", "this()") i <- function() deprecate_warn("1.0.0", "that()") f() # Print all the warnings that occurred during the last command: last_warnings() # Print only the last one: last_warning() # By default, the backtraces are printed in their simplified form. # Use `simplify` to control the verbosity: print(last_warnings(), simplify = "none") } } lifecycle/man/badge.Rd0000644000176200001440000000376713516776060014345 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/badge.R \name{badge} \alias{badge} \title{Embed a lifecycle badge in documentation} \usage{ badge(stage) } \arguments{ \item{stage}{A lifecycle stage as a string, one of: \code{"experimental"}, \code{"maturing"}, \code{"stable"}, \code{"questioning"}, \code{"archived"}, \code{"soft-deprecated"}, \code{"deprecated"}, \code{"defunct"}.} } \value{ An \code{Rd} expression describing the lifecycle stage. } \description{ Call \code{usethis::use_lifecycle()} to import the badges in your package. Then use the \code{lifecycle} Rd macro to insert a lifecycle badges in your documentation, with the relevant lifecycle stage as argument:\preformatted{\lifecycle{experimental} \lifecycle{soft-deprecated} } The badge is displayed as image in the HTML version of the documentation and as text otherwise. If the deprecated feature is a function, a good place for this badge is at the top of the topic description (if the deprecated function is documented with other functions, it might be a good idea to extract it in its own documentation topic to prevent confusion). If it is an argument, you can put the badge in the argument description. } \details{ The \code{lifecycle{}} macro is made available by adding this field to DESCRIPTION (this is done automatically by \code{usethis::use_lifecycle()}):\preformatted{RdMacros: lifecycle } The macro expands to this expression:\preformatted{\Sexpr[results=rd, stage=render]{lifecycle::badge("experimental")} } } \section{Badges}{ \itemize{ \item \verb{\lifecycle{experimental}}: \lifecycle{experimental} \item \verb{\lifecycle{maturing}}: \lifecycle{maturing} \item \verb{\lifecycle{stable}}: \lifecycle{stable} \item \verb{\lifecycle{questioning}}: \lifecycle{questioning} \item \verb{\lifecycle{archived}}: \lifecycle{archived} \item \verb{\lifecycle{soft-deprecated}}: \lifecycle{soft-deprecated} \item \verb{\lifecycle{deprecated}}: \lifecycle{deprecated} \item \verb{\lifecycle{defunct}}: \lifecycle{defunct} } } lifecycle/man/deprecate_soft.Rd0000644000176200001440000000622713516776060016264 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/signal.R \name{deprecate_soft} \alias{deprecate_soft} \alias{deprecate_warn} \alias{deprecate_stop} \title{Deprecate functions and arguments} \usage{ deprecate_soft(when, what, with = NULL, details = NULL, id = NULL, env = caller_env(2)) deprecate_warn(when, what, with = NULL, details = NULL, id = NULL, env = caller_env(2)) deprecate_stop(when, what, with = NULL, details = NULL) } \arguments{ \item{when}{The package version when function/argument was deprecated.} \item{what}{If the deprecated feature is a whole function, the function name: \code{"foo()"}. If it's an argument that is being deprecated, the function call should include the argument: \code{"foo(arg = )"}. You can optionally supply the namespace: \code{"ns::foo()"}. If not supplied, it is inferred from the caller environment.} \item{with}{An optional replacement for the deprecated feature. This should be a string of the same form as \code{what}.} \item{details}{The deprecation message is generated from \code{when}, \code{what}, and \code{with}. You can additionally supply a string \code{details} to be appended to the message.} \item{id}{The id of the deprecation. A warning is issued only once for each \code{id}. Defaults to the generated message, but you should give a unique ID when the message in \code{details} is built programmatically and depends on inputs, or when you'd like to deprecate multiple functions but warn only once for all of them.} \item{env}{The environment in which the deprecated function was called. A warning is issued if called from the global environment. If testthat is running, a warning is also called if the deprecated function was called from the package being tested. This typically doesn't need to be specified, unless you call \code{deprecate_soft()} or \code{deprecate_warn()} from an internal helper. In that case, you need to forward the calling environment.} } \value{ \code{NULL}, invisibly. } \description{ These functions provide three levels of verbosity for deprecated functions. \itemize{ \item \code{deprecate_soft()} warns only if the deprecated function is called from the global environment (so the user can change their script) or from the package currently being tested (so the package developer can fix the package). Use for soft-deprecated functions. \item \code{deprecate_warn()} warns unconditionally. Use for deprecated functions. \item \code{deprecate_stop()} fails unconditionally. Use for defunct functions. } Warnings are only issued once per session to avoid overwhelming the user. See the \link[=verbosity]{verbosity option} to control this behaviour. } \examples{ # A deprecated function `foo`: deprecate_warn("1.0.0", "foo()") # A deprecated argument `arg`: deprecate_warn("1.0.0", "foo(arg = )") # A deprecated function with a function replacement: deprecate_warn("1.0.0", "foo()", "bar()") # A deprecated function with a function replacement from a # different package: deprecate_warn("1.0.0", "foo()", "otherpackage::bar()") # A deprecated function with an argument replacement: deprecate_warn("1.0.0", "foo()", "foo(bar = )") } \seealso{ \code{\link[=lifecycle]{lifecycle()}} } lifecycle/DESCRIPTION0000644000176200001440000000244513520557775013744 0ustar liggesusersPackage: lifecycle Title: Manage the Life Cycle of your Package Functions Version: 0.1.0 Authors@R: c( person(given = "Lionel", family = "Henry", role = c("aut", "cre"), email = "lionel@rstudio.com"), person(given = "RStudio", role = "cph") ) Description: Manage the life cycle of your exported functions with shared conventions, documentation badges, and non-invasive deprecation warnings. The 'lifecycle' package defines four development stages (experimental, maturing, stable, and questioning) and three deprecation stages (soft-deprecated, deprecated, and defunct). It makes it easy to insert badges corresponding to these stages in your documentation. Usage of deprecated functions are signalled with increasing levels of non-invasive verbosity. License: GPL-3 Encoding: UTF-8 LazyData: true Depends: R (>= 3.2) Imports: glue, rlang (>= 0.4.0) Suggests: covr, crayon, knitr, rmarkdown, testthat (>= 2.1.0) RoxygenNote: 6.1.1 URL: https://github.com/r-lib/lifecycle BugReports: https://github.com/r-lib/lifecycle/issues VignetteBuilder: knitr NeedsCompilation: no Packaged: 2019-07-27 07:28:35 UTC; lionel Author: Lionel Henry [aut, cre], RStudio [cph] Maintainer: Lionel Henry Repository: CRAN Date/Publication: 2019-08-01 12:50:05 UTC lifecycle/build/0000755000176200001440000000000013516776442013327 5ustar liggesuserslifecycle/build/vignette.rds0000644000176200001440000000030613516776442015665 0ustar liggesusersb```b`fcd`b2 1# 'LKMLI MAKI!ter# t0X X%gwI-HK î?"5lP5,n@@ ,s\ܠL t7`~΢r=xA$Gs=ʕXVr7Dlifecycle/build/lifecycle.pdf0000644000176200001440000026350713516776440015774 0ustar liggesusers%PDF-1.5 % 37 0 obj << /Length 1158 /Filter /FlateDecode >> stream xW[o6~ϯl y)5)ZC9}Nh["y$Mr { @9;߹63b}",0iG<40GpfwCL쏲쐕wZG J%qjUK8q|'%Fc$ a5! d&:59Z Uc'8;V}ZuOnqMu#L{N_5U=Q$I3.Ob9!@Nrǝ%\fثh5Rٱ"}-ʦ}($`f3/wh3;/F# 1y5z)٥4v?k:0hAzjlʋuoĶZN̂s%W1\?' V%[z(,w>U8;ے1gåUKi<sሗcLި=)rRm ䷪uD5UeJETw*ɅsZ.uk tKع:Ay7.IGB'7]l,cXuHNu4s~`j ;Qkf}.'CWҿSN` Zv=SOqǏWE/oӏnNu;i)4ID imoˆQbLۼà $t T`'M-JUCPW*8>wymJa\Vijcsk#WÖO^}>ZcYL U?h3$K+/̹ a[vOf[eT~>BBŬmPO"vޣ<}> stream xڝX[o6~$1KR.iaKR Dl˕Asx%GhEX-<}^"/!ICo6$Ȁ{ܻWqDA&KBApء8 pӰ}e?$*6˫#OАDa&g{YB^|^ {Mc$Ws+AFI(QN rq9qSx%SYs=d+e~1Yl7/Zm)ʍ7@f@ ,0vSuVV!\{Т6]LMͮVͲSXӢrK%̰p:D"Xo˪u7Ke6=f`2;47](2gKe)sɧN1A*Hq_YU2^Vz{L&Zp˹Tp4'_4KiiT qMȯɜ5: I1V:}&Nz?Bj[G}B;1O^fmQ[plXΖs Wۄ+*}hntqof qSU٢7m?́F}QC:($aDa~U*{N7gMfC.圗SXzrkrkI9{5mC%(4Qe.Sh;*ҨvY/7_ecĀu*ƕ^_f H)Z+"<""jULca#]Vn;AXhX;',H;I|nXh&DJ6 l6oشN$1>=8mƸҕfjAVn-WQC^.\vXqe\ځ_wRP7ĩ;߳b&$ bG~> Q@kŭ1CDBb(n H3 paМ i*ɘ84"Ș f6\U:M #`ɬM-\rme~{?~wT:٪1N&taآ`~s,>}0T?5-P/x?!t<4- Rn*:KRfx?t^Cmn@nԯܘJö:3}_T?q'OW;uBJ\lk= öP3duE[k -JZh+L,7Ys ?k7r.{"}KYh?6C>>q|k66mJBŭI,Qs,ym.De[85QK,ÉtZu<-6o˲hI<5'XYzF6P7hO<d׎o#LtvH},牸1gB)TێMrz]Fmw endstream endobj 70 0 obj << /Length 1601 /Filter /FlateDecode >> stream xڵXo6_u/2V")QRl ak=E&˴-T\}$͆㑲d+A2t(R>~wG:^ཹ0R*ǃPy X$wk}htuzxkvb Jd.>_p e2ŷ,wkX^9C t齻uw:BA1kl&[K,%k>-" cLK#kCfMWiӍRH)B)Iۗ͛u5h$j< a1WYlt~Qy Gn{QĆήnYn5H'u4{4 (U2U:ND}E>n[" 9 ouļkb_D%{#[FWϊ rj!.13=`-EbvYG$qU[ze4ȿZkf=X?rreB" g Fq,eJx^dk Mߢ;;;Ѹ{*4vd o12hiAWXAno]^ubkUMcm~S7?T]͔Tu5&LȧXA#Tgޠ -~"NXi{eK_U8 dmz5zfGAqW9^1zN`|2hj_Mi5ބW;[xhjjke諒`*-0l[LigH6Qw<m,?DpzaJZ m9LndH\J,UyGVT骁<r1-ׇ'B%UI!hjih6_$҈R5t_2JC끯*]yRr".2'"t@Juj:k-9J5>KX~—@OGx.'`/OY endstream endobj 86 0 obj << /Length 1824 /Filter /FlateDecode >> stream xXKoFW"zg\)R=N")J\IDh1;3HR춗°73+VXp;7 eݯz*pÈU:b^'}2p.C1rnhhcͦk)Sֵ;71(z[eʫ0UIxn$K0H 6UAHUǤ±x12C?CMd%ф@r&¹?m#?snɚQ=f`*5.N"u4ݛ8M8sq3Bv Z;]}ҐM0* $0S/hh:tF)3❙{ g7LQOg@l:m'Tk{ 9*_i_פ #2!ž@b!R_ ( t&/z9i߉pEٖTŀ|sw'̌B2Ǫ+2>],4΁xLӒ|*6279' q(q rOS-bZ׺zge^/H QgxH+>#|?k;B?r!Qy % Nw`-3$k[#@jɺPJ9_˂=lZz@ƀK=_e y4Ʃ dcf!/ZMuhһ;P)T@!mTɻdk JAdv2CFNA]hSCMPzl.8f1$ glh6۱sy&hji0/{l7L2\RPpJ__ڻR"7xi:tL0t( ~i@یnѦ\ot%R6iJS <-L5w5 5Ͻ-0sҪIYv,esRW9A F"NViSĹRilMw'!e4K◠> stream xWKs6Wpԋ4cHimwC'mSI)8wIڙX,.v?boamz)J#yG0FAyq **k%LemV?_`c#G-L̰=t}+lT<7^K`sk'Ob0cꛥ0^|o7Y {s"LvpX;/4*B&S1e%@!ƍRaf#@3<'Wƕ9\@I?m hdr{{4 u- /@Xv;ԲM\ytu&G8>e)N'{tQn6\,˶PݎKgIL^z2|ޮf=gF(W"\ i Aq^U>l^cQH<`Pp7EiBk~SiS3Sx-x0AP‘I$E%oߨXhj{\ ftIPf2N@Lwjl\WBeȰjIVzkuZS45NBތܰ5ا#(F(.'X@#rO$VW6jJ.F`eN9R׫~Yj7vK̏N4~ŗ-, [p{of7}^؇Ie.?ߠ^SQDi?D G".N`&Zl4Yu/ZnEšL@3}7vxڪtfYf>+8{mv(ITjK4TGAJ+A'򯓢B5HMȵhdT%wQhM#dm5 %:kn>Ũ+H7:St5qGsQUYSfWŔv|PЅҖ%U3! nk 0"Dѧa$0XٲFd=l2sUS[Bcŵp`ΡS=b(9^&Fv 5 Pj> stream xڥXY6~X3"sѾ ZCVBdu3 !Pb㜆3ײhH>n[0R jg7Ee]Gj^5^,O0bbyȚ6ЇqF8v{nnXu/۫}Ym\H5`j(hR]Y K-F pCE$$$+#rxH($\ŖRy]M]0y>/0V)x;ǕgZgg^ Zj^&}eY&7wO G`S*[&]]3LY[ԕޔŦJ,@~ JD#U"g!)UVw MA(wGT،RYh XmG D]ۆ>QFe۾$1R4SYD5ТC ٶWY+Kٶn̪S8B Mf6X)=oH͓VG}RHW kO 1 ʝf9H5.|1)rC+tpкSvnV1*Ŷh,aKEb|v(} U]YT_@e]R!t*@7!BR~if=hu<%~\ŏr`?L~|$:铐ʠQgjAL8Za;Itcë7/_a @,*Nq l@[^'8m1)""T~_/(FϨ3jt115(0bk$LQbIVhk7U]*/Avz/H%NT9$ݸIXfƓWXT6].&gpnZʶGK}?a 7T}y 75nƄvco>g0] 9:&0P4\S&הY.䲨ACRԶ5*9zv)}5G䵬Af0N?,{8{p[sRVS3OV3P_SȍYb[H '10/}=̦Jbz]Jb1Ť'.m)YI3k['ZJg)iG(}i\O~N.D&ѥ5g_.>D.1upܓth$ҍ шyxLfwvk)e5<n>o_uYOux >uguׄ endstream endobj 113 0 obj << /Length 143 /Filter /FlateDecode >> stream xU 1E|-w$׌i#XSV`ΏspaU#GdBdIK;_ۣ֕-A~Hl|E[|ld96VFr幡PvdrEU/, endstream endobj 132 0 obj << /Length 505 /Filter /FlateDecode >> stream xn@<,Te&jB6^=SʸôXЙ|2)Jft| Mc #5ah@K uQp8y{q4)J2EؔC8(L}/tǯf1y*g21;-Wy_.fG# "2 J7ASxOT1&P ءUŰ*dɋ+g҂—c`1LL*ř[NZ ڊSʹ"_:L^ EWM}nAjExQ ¨e] ۼQ՛4q?9gA"W.\jb[91xZնL8sN]2ɦE]-T]=J0:\^WL_1@I<\mr1"N~+ۧId&Nwfw(vE;Cv6!9&F)H[~jE" endstream endobj 2 0 obj << /Type /ObjStm /N 100 /First 796 /Length 1999 /Filter /FlateDecode >> stream xZn9}W1~6%0 vv&,waɐڻϩV[dӶ{HTm2Έ D!PbCK1o 7>F\_&8Њ OPW\F5? \FV%$j(2"X`0iexF]>H@BE]EECQxD=3\Ob*TNDXl0t.0<&(k/0i#Sf꽩0/繽_^ՖN̏?^7']z2n['Þj/`6^5mju__hwoXnukwzsO#̙Ns;=U_צu|U7+D zYN.?7)M>i`|qѻ~3/0GܣMp֍_7apۜvzNΫW犯q9W|DؠRRzHG)67 Ƭ1zszP4żz_^}i몺6_n.dZ0^Tz}2O fyŨB<;1$jZԫCPyL;ȩE..Ze95--R6x7f?2[ַ9,NygA"<C Tz2bj7,AD6ʖ1CưELw$=d ofȋkYV@#Cˢ?oAVoL1wHhk-NFb5Շ[Ou{T,a^DA!g@ M$p"@|x`)6~x9:P/YjK+!l<[ZAFVD:|I'1(r\|C=vA8-|aD GV<Z-g_Qxyէhu*`a8aELo( tՂ> G͈$, % ?(IXO/tdz=W^~G9byU]֟:N3:;!Xz˶0<ۂmв uDP<~pY*#/ .tN=lӋ.}2[/9 Ir̰66S1kP՘rTrMӈEҳutfmқE7Q4%%D%vkw!0.¸<'-R,GV(Ll^uFczD;Xmn"ܽ%=l| 鉧"u˃ iXw$&foGV%W@##9 3$\r mz05=s#Y@囓~!y0Sz [?`q{g š$="Mh/= {~{~[Ck7u#!ﺖwmGVV;Ĝ#󡶭XIH'N0#*<>QovCXZ2#erv{/ ʜPT;- v(~ö%<<Q0X GW>CM+"Yj?MIʑ!ĺҞ "$[RD+68biw*~wcT8ʅ2q.Ta< X@ 0UH^+G ǀ)Qc[4tÐsO\?{B' endstream endobj 144 0 obj << /Length1 2648 /Length2 21347 /Length3 0 /Length 22672 /Filter /FlateDecode >> stream xڜvT]%4{ܽCCp]k;u_I{3kVUsG+*25&Qs{S=؅كmM\L9TA&N5VND**uk[H rr/2qyHI9Y@V^d@d P2qr!R;x:Y[Z~Кѽ^&V5oN.`;?D,Lm7BV{Vl_=lddg+_?[9AٜdJon f 3 69d ^Gi0iR dZ8g3B:bI [LA`D=_kd,M\=z@f (ݕ^ `QRUdoT`bpy<'U1eo)<?Gw*%{h>hzSKF?V2tO¬|c"TOgO?THsSR&vֶ[kzjYGPe]L^[mvXY,LlAkՌ5blEz$8nemf9;k 6$_7[8&NN& fX2y@Y.!W :!u8,,b7E7HFɿ7"(F,+oʢ7yeQ^/߈qX4~WNkv+竜AN6]^K2^]LMl_uo5d$4ۀ\͟om7|Uw+i_S~o_$U&vļj|u=N<@?<^mY_\ۿ{?yY~sXvd}mwQ`˯9^~t0qm^z[Z}=Tׁ8غQ3wrt}+juvuF!{wBye=lfgvz_'| _@N3Wש z [Xv  qZoD ݙY-$2K߈j$O߇wkY Fx({170W*~:;1gp[@46 (:hLm;t F޸}V\zPxt Bj׍!@a,fCpRRVX.1ЌT vS:$|n>RFAAVnU[G1.|r*"~ۤԒ0RTYݦI?Ӣ+²plH8`taIEn믾Kgc-F,,\,~O(z5ӊYMp*8S0F9砩D\C8 #uΗT5IKvR.쪅f&3 ' &iS#l.,-jYɀչ:*qmױT'ljWyn(ȹaJ(-(k¬o}!+p9~v3u5ݪx(bX/jt+7dc1#xDLG a7d?2VVvf@$< 5 ^ndjԎ:>3󣧲$ikhcН7Y:yƠԙ,ϋ̦b{\!`Hd8uM,c3e>ԎF㜵`uMȷ2n1}ncyK)uH})M{Ui(Qh<-ёM"ؓrd;u7i@Wd2T{o#i]L5a+|@VgL^dd\ Tѷu*(}Ҡ +^]*Q\Ϋ=BI-q]g15x@x<`{#۬ (ge}D>JmkvV a7XG;q1&;t^>tKi!:Vru {S=o]\|hpM5;c= |1ф XL@iy!dnAbLYXbzb#Ek@Ӝ]F= ͚cՎyލ(GS.n)_ 5 dG^`(Ɖm|7ᗫ&Sg) ́UuN(ʕV:xP.U;Ѐ%-޻" x= a09aSꃉ~6drf,]̻;6GS]*ï?0:A3(f 1y1D[o\-IU7 hF'}|h'83(ɴ7 Ssa9_1ke9Rz!YYGF bq:}ur/$&jATN X POuH= F{ť,s/NB 䄱gDY^8bSڽimK8 n4L^-1kḌY ~H˰f` Ul)dvjoW„ro-Od赛~i05OG>8EoP4 W>}<3$a$sO\j A093:Fo.A5a&k I"5@z'QatXa'2JKEև>eK.*خ0{w4"c)d tT u+ؔYUTLJʭ"87wl5+/;f $zlvNHE35sxZ!])>=b5DTd* OkX Le'^nvs\VZ?zƱ,N^N.5/W"! + ډBoSaI&wȮvQ@UU_!Fah9}9N'R^ uy7#o>|lrPH7uQ)Sl' k\[,R!ӧR_MiXO+Ǡ6үQNr<1V[~Uαskk%6pzכAhJ$VKŕ}7v[5lh#}F%ȫ+q4ZOأڢ2-?!'H6jsi,|Ӥ/0ZiNy[NoF@E8"x"9!s|{I)Li k^߻K!&.)#9Ptg3y2>\aR䓈Esa[U{Y5[Bů=c݌VY#U.-0MMk: *ү +C >z9Y}G~1YZN-%VF)_cc(PyC9BRۑ5̢Ǘ{&mB>۞|Kdh{T ^O[ }d@e-"B]Y"nҚU"a60B c}]HUJR7}``v5 'sYw[ YMoN5}>JcIucxsLA90"}I(LĹǛ (tm ᳆E`hs%xr(F[ⶦ̲8|7 ;blM葖:.Uߠ_;6)ꍘzU;к=saГm:Wմ#[F: H ɓQq'V$1^/~wH0MD<lL9x+kxFA MVj-ϖBwJ N)\a#P0~&L3a|x6:jJd:?ULSؼc #ĩGVoH޳ PI^.z)T~3/a siNuT wOnC]`C|3z%Aik\@`xwt9˩H://$HfIuc"mȷɈBr/-m$Fzȡz!3JMJjifq2MdL*:w`x8 GOj80pu:Q*P50Y3L%RsReF4I, hWGل%\`kN R.pjB7Rt}( L? ى7 meĦVh=^oV -;Ek(K |7q"]e=octɠYioqz߱n)LvcMtB8([11@ C`w,5m 60T}[ֹ(y\՜.,~@EMS;B_`eӤQ!Mt?JҦ|Pȏ;;mR ka}W@#vPdNȡN ye툍xڥ|+*D#N l%r$P7rI†TG\|t T1-.sbŋyjh-ha%|.u[o7 lAAGr!r;E hIQ:^>)v&fήf$͖J :7wq]N>wml5SxI8B9ȶ5ijÔ9 KlH!sIbMk!_>s^sPCO_zXyYE6оҷ**/A% R?q粆G?50cށ6@gWab;k1[l-ٱi,XVa?xrǾk%g/D5CF} R~'bp *n ,Nۮ#L r1EGY=UxZLj46Va2n?9ؓz^v4SFYf\dHw 2䬭H\HuBMՇXI̶GJ,㡯{[ CU_<:5hBiQ 2(_dGxģupUz's"#}\.ɥUc{m*C,w&4|ʧ& )(b'Pt%龨*5VЁ=٭Jlu },xΤP{5'srT<ORO iV@ta 5JYI9pL$#yeB_10V3`Y;ȑ-~Ӽ rq~[Mo[vIts 6x.d͕gy)6W+ЋHq.n̸ɮnCW}% $ܧj/N(vtDDn mI0 k)\t[#VIVRf@z@ }r) e#F.4nv |V@c/Uѧ6O6&eu'{r;/ aCT{y<- PP؉umv 2TMN7Ű\"~(LfEh@Y!' .H/'uuE@l+p|xӃ+wsaAh}bJ](S(~gdwBAWۖ<0YrnWِRg=}.N4uû\; 39ǵ* ԜC^@ z~Zi1R1d!hͤLg'a0߬z5'慖=, &qg68X U1f'ĘQ)t7Sj &cݢpKS,h_hs!% u"hx}G:wurjs12]"ioG^]IȢVQqof>`jt\gE5|a~ɒAc|Fr-cwg";'T`=%C-Q̟ID_I:V@c6ac,7i+EGs)aÙ#3 $5fP[iSM1Μhr.3ʈ>jpgHKӪpxf! F F,uE WuK(ލuU¢ >ɸ0sŨN|b;o-Zzzp$xZ1a_InY]8(TtV62eEfDp_r][˳ɴ,0̪so('k-s}b^TZ`&<Zĥ<\7QW׋Ҍ4~sG"Y]nnܩQv5u=?`FF}NBNҰ)}Q&G*J4":, [A6 f$eE~qኄNM >KΗãՉ|CSrISc#kw:-9`@GGJSiPy[?C /y໱,AdI]790GT _0>qP2+KĸHzP7ٲ% u*ԙ5Q+cɢF]y [AX꿚7+|DܻEch[0mxv'e.x2% hP_c)̓u{g~nPs*@_п][eȘrX]xgsbl4 w|-¼x97hK{ij,`k(@`s|2V\ˇsXB q2^ ӟ,SA"Hy;`9,]вq[ DdsRرuD1.~KL b%y֐K*ҏyJ 5rmLPh^R:GFlbOpyX :'WC~9=C-3A-{~WCݍҐxM81K@L:f'Y{pK/_1\p9o0 ޼9B~PJiJ>{Ύ*gi]>#MȆ"s`hqNn8OMLdHT7^ i]xԂ6֌ORiÙFes?•́18Lc*.%NXZ}ͤ(Sbfc8I-񛡣 p _jk8߬K˃zsvanf'ߦ,Q3Ok$wR*?Y/P[OĤ B$yU{o@yF}hzϘ~A8he㓎җ:+^(J,(fwH*32Y҆ɮbzȿ-ǥR0=lg4k.7e1z7:q l:(Nݏ~=4gi1gۻU0ӈY 8Y?V}\҈ZDe:kbj7}f7zrI'_a8_EI0TTJRo ڮf٢dt&/0k>I>ь蘡GӻδYq{=HΎnDUltȵ5 q<;}ƙeh1 2ǧW> 8 6);(&_IFAw% 8N`h#P5n™4O7/za+vƔU& zXKO"dSI=ӟ_yA E%Ԩ+;Nt0 /W)_C Y]`u YkB}y/YY9q۟gN?я@3MYKU!zqcY;,SɌh{g9F//qNjYH4/rVX!~]09?Q;7Ltf? Bl`x[;[gxTXmttlrN37-'3oew{{# JE]ߑ,u/Vw?pEεvHi4WxMPhUN¡Ŕ\=~rdaƮC }1 =#j6żfo և"~!cI`Vp/D?髯Qh*:#7k>FG( _rҤ.\9ŕ`$\|`2=\(Qv˫<1t73Rd2IQ^*^.؃}r(! Mf dp/N/w. '͑ %a{E\8MjS5/5 \G,MqL T6 rBgiNP'w o|%f=f`ăvNBp= h3>y壛Ia3@@퉈=!Z7͋څY#N2A_Z1*$6tN.w džLU)&sQYsRdH,Fgщ|;:M㻖wfB_AԴvt3Ӏ{1WtVdM/?t`0|IXA0d &lVs IԷWq)73@r +-Hcqgu@m郼2x80QMs义e45H*~DtŤ@h މsqsXaM؅R3_ m2 ZW(G@XH"H;%-I^TE_>ʫ2>fR:)8z:&5%+s?Y(\x%æ"^ Y\OgjywmDtT&DGHr?,G P=t/𶐨"ҠcZBixZHOkë,?pVe+9d[Miߢa!\H`RQ0Z?$1`CK;ŜqڨTܰ$VyNKSʨ[&aH F\H(/ <ݬ1dg>u~9?IK( ]%%%*31q݄]`te.r)Q3dbhjV@͞]O;O(annn5_A}PEp^l\4x Հþ @ FBBhkkY֒M+۴Yӑl<2_tڭ (X̿T2yda"'hҁs$Ɖ&+0` 5|Rj7n`ĵy95Pgx2̬)ATU3 9^7$5fzrtkkHiA5X#X-Qd=*KdV<˩+] R-%^~#ɍ/c@lq"4 YIj=uQU\9 )KRӏO`My:2cw^!Yu}M뷳:" T$\G5cvh]jpYL5Yv3 P {ysT.B9D&?a @c$4 25_DFXbԀ uwBǟ)֝LԠg."ӟ&`;SIJ&{ί/\C0UGz̀:=&ih$edUiU~&sR>3޻=Fɯs uODhS<|L´ o׿WSs0vM>6{"x@8KYuqaB=m˰G_X;삠$#a?D2s3iNC5޲l1ND iXrAbyC  a"ESAz.֫̍VU!ԡ|b UdYZjKb#Х ZBsl*0ؕ KCК1Q|.-OQY}l)B7rDǖs7Z9/@[pT!a,@5>4$0HE5= ׵g+W6dzp&ezl4{iuiMHsڇNkAlmZ)d3bZ̳ nRi4g"Y KVxH45PׄQ~Ն:i-̴zϠ ~6sT-βţǑK9N{+FP/MqZ:c4R`O oznO&(9D?2xDpn%O`SNQ B; 6M}˞(H3>$>9 ]U''7|X4]acmّ&TO٪oJ bH6FFTu53}-MnrsBwr6X$ {mlTLN* gVʇHE,Y< (V} 5*l ӑ;j/E ,ԛ掆D U؉-9/W^"}|^ꬸᵘ t\4IaP2 &r4o$fx}:bFL$hcݰ䍿äadz{Bi!F"a?jӠP;edIkg$jp5w {1_<\/:YR vY\zrcݨqVi#'HT;T*Qx9v Wk۴n QAaPzFMkqJn](#}B͵s m;q-: "3Y=\gZdi\Xϕ4N.rx$k#!m@RRtvF,EWMzLL8<+ܞVɭ_zAV+}wIfm rE=u9#Z%+i}} "KgEڥ끮8#7쁑BY#T[d,Tov `~=,EU-_P" It \3LүtZ41΄F=F'BQXʃ?hQǒg'Al1k=d0w.Mu%*ƵSlHo=%7<`:`j<nI1x_{aobCuDPb:sK3ÉS6V7Wإ N8q.Fy4{4L=TCRcCiZ[f<'ΒCQy[̒I,w?^&neYyL$.oq=͵wŕl|I9}1p>U°Vg?6 N["^:P-#|!^vs#b"EI\A5:[v 9`񐚔]hipB8 _͢->evdc-Za6j(=ܢ?^O55WZhV'GbLz1%ų>yc$0݉\ .[𝿮}V%CJN+d}M95>SR٩~5[Q4CH~sra4 ˷8N_'(EoRs2联܇̢5Gmڑ3A J 2:0[=m O{&[+MZ ה:G^S{.=eܗw]wx\%* .2Q6.mGdfhLG`jzgsdumySzc2%j(+=&f+A63|R$(Hk,Բ= VĆOH;\䤫U] a7z'oBW2p#`3EZ/KI^1 {äA Btu*ve/s^5[ˁM.hgYoaW),uȴ$Kw[hWX.a|s=^' z7(R9vQ"86M*T zΣ $2hipL^ ; O6.e&M#CXDGDbM+2[&l!wAg.Kg iF;FB1~S`*AYӚe]__<|:P"|F5aRmeOi,}jM߽tup$ j!CC<$ʴ#;#ôCv872)6J7]qz!f7h|j]yOahRet1oDqAбׅK7.~T1S܏B;K =ɮ7mQ"1 !d05dC30"@Ziة44K9F &::o^xʎʧUԩv7ĂUpȏYt1e[hNKeךWX)ExnV0 dmd*a oAdLEN)J@h{>Sç  []?;{Hf ah lN`hv=){PvT OLL#=E$j6#bk?g{hꎜ;/Za#Э":<-+uƊ$h٥'Y{>gϡ?162+yudL-eޭM 򈛝b$.k^jV`qR?d;hzF +PH4 78-7>hD?BLT,>B&1їr>94dnWp|3FTV?4k")i)̅?L,|-Tȕ%[F Oڸһ8f6C~Wx7)!SwCNo{_+$=_4=EF+H m<˒:5CvA7N^˖Z'%`)ڔ}iH}̚p?a#E^ƈ4dPlcnt~OB(P89KQkfZ;rr{N"w{O]/'TzR}DB"%VwQē zb~TH/u7e mLegO4Bi|ðȪSDB:^۬D~=/t V@(ZqV#1,y6U['p8Hi &:%뚏jX t]_ 't ߄i=ۑDS:G0jۘEt80۟9i"qMKmx;8R 9Y-~JJgn-xV)16dO1W쥔xO/@i;vR,C`69,GSьf_g7-(zRȌ _;ά"RąuųTf E.OQffBAG mC`O i{f׍򃕪n̵N4~G3Nϋ<7?jgpz@eWrvn\_K=%sg.\XO!S}8sPQMPuU{E> u|-_Â̖4'[z9q6L}:87ro/nkX&ZJ,>DhBC`?C\@s ܓJuk.rÁst,>Hk$@w(U k,GaaA»-6|5@a|99ÐW8Zec}{1z H\PmJ!왼w=q*s"t:'iKUgH?ٛ%"|6UHzAg+лڮDѶ`-RbCUڈ(((w6xfܢBՓ4s"ZPSD Gȑ/0`^T Ep70irJ6 ZS?R)*|=KB[Jak 8|mW[%P=,mOGf~tz)9ߍ1[]@;S^M,x-L8EH SE` 0{T >Ѫv$aW]f۔@[v|/:䦭hcC? .KfuԢW=ڔ?,VCT-A)4W4RZ$(s/dFW8yw5?+o:kKH!{ӹ[a W S UZV.Sn;G&* CaQێ!A&FwJ&||Xn$$Dڬ/f3x~qث&A5+I䒎* uwm&8M_&ą M^L'hФйcIR:~s Y*UmBa I^Ƚ(-gD[OK' a =[c`_K%/w/b ?9^`*Rt`9 [s6 A',tJ%u` JTdU3}༏gӻ,5l+`@)P\( 2Lph@-^Wb*߇-lTT\8TI-A\] 0 ֬ߤ7.i+Uea)  i V" )Σ"`)mȠ-H`ؓX/>_ |[xK5Y@@ld3\41~HF]Kz"uhy$!(sd>><+ gg4)qYG\4c*/XÑhmW+A^9j-ɞ\JCԩIJ"tl`)rPEi eb=iP /Z3谍(*c#9h&6<-5G{T㍎hhQ6wRXC/GBS\6H٠Yۜs.G7MDu,i.мA;SUxZ& 44)j aFiSq"Di2ep**?ӁE2 _~\D I༊MO<( 1"|eƧ1kʑJT29NXD Ç耪FAvP~/SaS}銴+s 4thܔ`!$DG6~'ZSd3r//E[i{& wԳb V!^b.e`d\Hdc7xrv3/fɏjaC* 0B сl0yZde'gv q9iyS v_Sv8med0{nԨX z,W-=x OG$y NoFolR$}>^^ywW}Ϛz>[RGsrg2%hyhće>u6a[?w,$\c E#4/ʾ7F2e!nt)[[f qmosb!"={n"һVG@[ uÍ&N#XLqm endstream endobj 146 0 obj << /Length1 1144 /Length2 1528 /Length3 0 /Length 2250 /Filter /FlateDecode >> stream xuSyQa"AXHx\dDg"B+1+|&WY#]AĆ#t rt&TA>Z4s:¢gBvP#X4L,SB ]3i̜!>@͝[q?,fδ6Ptw'alPXp+c62@gH4Lx`Ѹp;џb B;E`B !@5|SGa5 V ku^(o>H0fn_T06x)"o1WB;Blľ  îWALd3Ep?5wO-47˝dq\xӽsiiWsYw! 10uL 2)5,fμ87 `px.1"`P @7C0sN0aB0 Q̯4xf.=eςAp+P/AIg'ϐc0nYXm,Zn+t^fD6r)m`9o9L{c" j湥i0=gCT~Ф5EkcϝWFWO;T&#񺓛Qz|%1͏(u#%[҅S.x^Ѡ[ꨂJvU}E*&6޼d(۴dzt̬]ӣ뫻5S^ّX}Dkm60dx0t~zli^Kɚv󶞆{k'֩#%ILf=?x$6wjVurhu(237k<]iu4Mтָ'" ^&?S^PZo#fn=q-ޞ'IS 6Ɖg'v5+:+E-%F#/7삯O$1w_H\W8PAݓҨ@BT9>2hZJ?U7[qf*L&\꺪#oXl-Aih\Fѹw)}ʭDءx5{b 2+: M%w:~uxe[ؤ=j*/ާ z:V]q[e"Y)sa@&YDtd[~Lwp[:eMY1uX|ƹڪ~9qluL,a$+o[{$mr>[4|x~p7>Qi\XZT< 0\8e@<2}llDUޭ\Q=D-)p#1ve9k|U\3)J)}AؾގWuЉ<گ4kli3[}!FW7=81&A[%E R9etI犓%?Hd)g֍{}:drވ>~s@ҞhReQ? {#nq69WxKKԇn7r겜p=*VmI.xu$ #c|?M>ՙe:Y`{Yt2C eͺiۍ{6i8U捞5 K֭^]%+ ڍ#VE\~E"Pk~%lLs+ęyoj UVHF`iͶ8QO 6kKZ$M sSC] ąhv~B1Ja:`:>LcKRa-4&w([nR(UK}5*a㧬'R4>o R:`4V̷(2語rnxjo \s͓T҅ اPPhy`#qRãvEjA fR[SiNuC%eNy՝թsG9޷h{cdE>!Gm,)hi|-M7Q21dՈDZêhEm 쩒\h endstream endobj 148 0 obj << /Length1 1626 /Length2 12030 /Length3 0 /Length 12871 /Filter /FlateDecode >> stream xڭteTے-A7܂ l 55]=YjZj̢f&@){3G~ ENɁOYhfxs!QS;AV ?@hl|||HqGg+ KNCU韖B&ytмmwuYV@gemY%i@ht6(MlL V@{ =`\XޱD]G{ trqyX,A39Mmfx;M=r1urޫ*KH'Wmw7=WKa޽ c+{ `fhk^o`+{2`8-l..0M}[Ǝg;_@.@[s$6VH튬?f`_;CN`4GbUrTfo"E?qUvBKmmo 13_ J1%k&ll' 2~Ż,Y>h"e4SZ̍m] lke|>~_p7WRMU^RJA  uwnъspx2q98;!>^CɿyV49[tw/0f}.ߗ<@;iqT :1% T7"XP[Wl\R31{#ǰ;ЁgK<"\iag5(@M:y6戊A3X33/k/խ#iBO#[ڞ "q #jWGWGAܢ8/ڦdEUnR-+;Ÿ/?n%TSN0==$QEQw [ \r% t-:`&)w*7Wiͥ,dl/wuon)O' ɚy0(OHb:B&WDL,8k_Z&y9keKֈHcVKs8IkZ%̫oDoX g&O^Ł7$I~;83Y,styb &j;W!7hr3OΰtJW19?[ae/{SZ{? &j>;#ٰ4|)c!~W?a!֚(2*i%aphh;6/QS e=}+e&A(REHoI#3`7rle>"8c~ y[jT94F1DnpUʟpK WVDŽ!ڋSvf5»&'NoDӁKFp&nn|]MHO 9ܢ*DԖX;߈yrB!n &@:دkx}yy"h7[5lt5IKGKXrP;l[BEbrw1uLՍQ0St-OOLYL }'|0m\Uﵣw0 aިEbfM?*{Hu p #Z>,{l zX'qӨ8e NkY]te\jY+SKe^<+WU _c^ȣ6 w }L@dn&p1yj3|SUhBy9Im` X^D@~qet,="mTZ;=Lb JYhT@b(N\zn`t>HxzBt_Ã9pb"`pJie񵻩?Kt!F( fS}>+%dx <8OO*$1טpe-4YVWH-zuN=W9deVGd։:حNg?+fW +{U^ MxZn5M#|о{[s |C;t |+[4I{adR߶LkFe*A^K3[FU$jyq-ē+s_x K357NN1o=eek7WȽZS#0]`:|}K-ީ$g/Yb@kG=ODqN4 ~^r+9K}M槨1j`ڳ3Z`כ\Αya?n-U$,/r6$3 FXK!WciksB7VTs]&xmƯ,b `"ŕo' 8hDeTI: s'{/jκ{{"6J͌_oK~+%W3E:z}mYz-!7uh @0m:6N8NHF[Fcu9k.ݸ%c߼{=BYI =AnC(t@W.s~)6i9 ! =0Pΐ~0.hCVIG)Z! B9`TbĜ'7IϑݽG ղ5c\\g7A4c,]Zsdy햹`AߒFHn筗G>/%Os@6yeyW0_P8(m<ݫg_?ֆ L)^`|qS.LG2ScLrj|uͨ἞ ]) ;Ɍ? (r$O<3ef7t+bj0@ WY.Y _܅1Xtzju6;{f]Drs_bI[I`xrڃN3,y3r $|<9Wkp#֏DacЌA8"AtlPpm p|e>s>Pלd|l yf 4o| Di~tOwۥce[<=TKt{YP" dw (nwX' _j&Z/Z/8OybXҷGnʣ* Ƨ2Z 0{%IR9^+ (pp^g]>+5 L7j[BaMYY,!izc,[s}*Pc.CBr5/DQ3% J\IK]^-S5O]ɐUd $)V{ˎ9\՚uɣH5EvBCD"v6aX`X¡XvlK<{9iB&TdX|+$3 2Lw A#,&JWeCo^)ߘ;<;L!F)9șr-OdZIГ}9 ҽOca+m^5;t~_ '=d] Kne^CKtaYsUhvpgWzL,o,6t-?[Qd7cge-lG+VaIz/IM #=A]Yh[=v;ۖjl_)g[^ /xv D /K>Z޺6H{ ^ṇ\ɯ7[zdϚ1~h)iQ㨢+R*K'[G쥈a*K鼮-1}_m0, 𽍕bLlpՎ4ۏdc/!TO\Ǿ qKi&aD`ݤZ(@z%#Uf?o~ЊHreUQU/E wz\3`9'׽>_nkWhP#SAsJ[Ys.p.ħL ާӃ "ǼcM,O%#^TObhx{0d*L-l/[~#e_oY,X:,4BbW&*gӷY@ȈA 饤]dKUv3h,`KJfȤ7L` Fޫ rEN1J {Mh >fWrWc%׎׼bto[TbVm>?oDF8NlkF۔n'ay,jBcA3% -ŮkփNrNk/$B,9@aYtBlY50e._n9d+ϩsB۞BWWoຐPS>^@, ܇ u5Dj7Ks ^9'T\c^ߋg˪m 3 0MƏ{9W]u_),8k ַD1x~gٕZ-l`M]K?#l8K<0z(QpmNEURIs9B(W\m+]{\12a&Mg{x%wCR6B9k$ZhG:'azxI")DwMϕOhC*D˃<`:5-'/&#)(_R"#*)dլ5~hCGVi$hR϶=SuX$rKvӗbR6(TgȤ@|/2jtWx$Y~Jcla:y g:Kj(|<4JE1x0+O ɲ1+9qeOhy_0hHÞGaRq k-4+Mbʫ/h?f;E?6XP*yBQ{3[]֗R8m49xΩYU*5:>phK@oYQc'xCtB[O HK>IH}O}ȩ"7fd,ꆥJx9?*cx P:v?- UAD F5U;_p&G cSA25hy@P E'{R-it 1q4n%cSz{aIw!= ElD0uΩWV0KyJyEB :30cD{נwX n0<߱Nx])AV9:J>T=!GѨA! Ӿkꭴ=!YO \4"_unQr3J]RyVw)⥀-4g?eO;E4S l>Ih@;鹗Ay yBp፥+-U8/閶9 01FYJ8P7JIx1fV2 IOJ{3>xJB{!} H I@<‰%/;{ alQ皆cMXq*I:}2nnc tP68ZrdܘOmb`"Ξ YY@ ;k,C[u}s4jt';z~-P44>{h^E/)jR=3؉E*E8:*#s3] 4}JpB %G Q%#㙬R(z=2`J:W7I< 8HR= ޲0wm&*5b$ Y%̐bn]iƎ_Mf=#L΄* %f>T?(sgB\;*7|MLt0>A/fexG;!GG~TXSE;Os)4JA VjXj{-փ7[=!t#<ʼngN)Ódd6e Z^Eȭ=`Iv=OHx, F"5<2ݥfphڛW\>jBƹ[!lH;KSD;ݏ"[yfZsLXs%A(ǟ$ NjR*UpDD_[[reu5v+sN &txWa psir"TK D;4 1 N#p)N6tQ :ewt%w_۽.]Qto|G<#$U>?$l8ݨXyE>U8NSV _p|tc!bF9TⲰQQV/O.:Z.FJ]ۜ'Cs;IFݕdѫ{: <ѝ~ZQwXdsPzP%oJngSEHʗ>/?ߞTpiVd`g2'7ǃ;[HQy_heg1GqU"x㣯Iʾd2~->C[3¿ ZQ(n s;F6I#B4 :8+N!ƏgqcÝyCbvT t؈c78.9TCaM_1Τƽh\nϥC&6 PnTt܋)Dp"R| ud3`R[7֯O^bW%0L*Čt<:DLw*i 9_( abwvYHAOiw]c"1[ )Ia^cӶ,L53Fo&W,kԍT=G'+{^Wau5 _¥c!82@SU^JuAyQx۠)N]̸VLV8ݎu1xOxCF ݴ|Byj&aDٹA2SjVm8ͮ#+{CIQk-Rԧ<0SŒic!*Ǻ*Q+|Yko4dD6"WJx*sХ%(:Eq_܂ ,iOJ&wkW9_LMvLAltдU3iZEgbB Y: )j,NA4p;'>Pe!z$Ƥ R@P}=PwFK̏6|$4ZP$nՌa=͞0:D*R Ԕ)P: k&IuV)Ydf@%X.Ճo Jm-QtnY#/i4krpSj_fi6㠲GV^zV:ǰU/!i:|D ϑ9%?+ȥJzWyU~:;#@)<&^i1}$;$^¾i?-E-zB4vc(qLܲ"(Ԥ!nhFh[/&$ehl,<r_2g0b]rZT W0?"ڛ,̟g( ߅R˵ⲉRe a1 bD>w[}p bU*DE)᭩H ͭ@Q*IkJXfs릱{'5YSd˷Kf5;VRJ)^mDh m -٨tT Z+.Uq0_#j&?T`7Æ@#&y05Έ(.ZA_ \ryW^oVORt7EF'=XŃ9z$86  j:_+g&um"}0Yˑ؅!KۚyzV7=gIafiEAM&#Ǧ~H)&ntN#]^ׅh/թR/ԝWVbs0uKil).(wۼ'~;t79Ñ߄lhw_MˤhgljimrZ)\'&dR3HN Hhd]K@YTf%9I)ɠ:Qf1%W㨍#@USC488]s+gNJ뼃]/<5"³8sl OpK'FSENϰvլɰ2-O(Dy=TAM`ҪڢR?Tc ]Zo/܉ .f" q$[+:!2N9uT‰L16K16Uď.꣪:6=xxsh kK gL:d8%XarK z$8EwwDa'9 WY?$&4G(=PI w  ܮ8#<.G)i,Lbc}QZ5ͭ1:]RZ,㕈\'\T`}Q{ QZj|l~F`vݴѥ݊g?ެE4H~lpP$C_=*b/7nhBmN b=6$Ƃ WvCN4D V*ZZkTԅ1%7nWaQ64)T?2OʤU`Wi)CKnGQ=Wp>z)VЍ? ~sׁRͼhn)Lhɔr*Ay,ršhW1vu]ayKƁ?۲pٙ\̵~Z{yjS*lY#˘]pqZW zv 搳y wg9Ežc=G+Y_1E[+QW)[/s8XA ~+e4ԟh Ù'BRSr(ʃJ2ˇlINdn*=&/%n3$zw:8vG_#|Ws^;D0leqF<z$6#W$6(cQb !q]/I y 8 `ls0VDޣQj_(S:DoD>ElteS= HG i,ʫI(+:hqhRn\Dp05k) Tɹzc]\\}GuA{LƒrTc.Θᓮؖ0O.Z!)P路:f gdNL'*i_/>\D3 !`xB"Lrln ]!̻ AvZWjǝu itTջѪ~*9ٚƒ]mXȤ;j·?6#/?墌@hzpD\n7}vsUDD#RHԂ"b n#IZ$u6Q24Ͱ +IWQs" T3"6=M)c]*ɮ|l*X#lc\1:;63Eտ }Eog0qK"I3EVPw?OpOѧ)wf\"WkƆKی`@ѵԩSՋL7c4ݙM-*>eq5'D^p =Eu+f PGeQnGkoHKsޏq#FQ>;85 @m?ܧe+y7 usǶ/u(PSFഫqwDgkw[&"}_p+BCn2XRM^\Ą-FQ5,2.LҫF[Qq"*a.>2|/Y'OP}U;hMk\Jqd,&cٜL-c:)$"e}Z?\SP72构F';bq4Z~-4jDh\8R\ eD,́;2L|dD9qMN=caR?b:q8x* hW8IGF7olq8L q=%@{$<=,졤>`z}::C[Kl kn85oĻ!l5NVˡ nVRPB&>FɯV d-|l TGZh9K |ހ@-\GAKK'lW kX3w F@b3Fڞ*tA'n*Q‰յ$19V }nK" t q-(b&`vx|6"oOnG0dưn+l owY zP Us1ꬣ̯X7&l endstream endobj 150 0 obj << /Length1 1630 /Length2 16095 /Length3 0 /Length 16939 /Filter /FlateDecode >> stream xڬct]%'ܱm۶T|Ǯb۶mWlۨضz޷O}~\c\{a.̵HQNLLD 5vqR㒥S63w89[E͸fQ333 bghin TS֠O?&ct4ۚB_;-?,m" ZRJ y5blci41:Q~9l}M-)͉/dofb-? `htg;%+!{Gu휜L-*;Og #b;YU~43q:Yf26Z:y_i8Y3Z_t?/x_V3Kg'3Lc8mn egV?L_ gf&adjes@2 B -bc#odwcwd,#Zk;߶RHoߞK45s_m11252 4Uddi7 _Yon9;yFXE cd{& / <9;Zt'#43gtT Q8:%_ oqܛ.ٙZf9b M0ٗ4VuJ Ua^D8xj/M}0҃aCѝlvMB՛IAsϠ_vu Ψ~3_?sDKFhcRމR[pzFpH10:<4}ٻK'(Օér1E9AmɅ!*S qeHhx~Z1iUi%z~ThK$l[ꔂ qꌜHiJZ|u8db;EQ0|] UuYgtC|tQLnZVgЯe8`ɛVsCMѿkd.X^C%7m #r~%tJc0>k)ށhҒ)-Ú}`\3Hq7]89;}7?xŊK*<n0=X"= ``hs"]ӡ9/\,xe/ 6r2o?]]3cssI~,~4y%bj7oLBe'Z[Tk$CNVj-squWzT3%ӈI]%aJR9KH6K/ ȽI=!_EDu$x'tQ\E b je$f+Zs@[" dq2[bD yƬZ|?W*4BbYWA₎ek/ȷQ ̧KrcyNLH74m}_1?ڒ `) V7$)2e >r[n&θ?06@kf` V1Ǿ+X<1zzW\F4jaI&GETy0LwhZOrʇ ~!0^A|Z(bG?쮙 `n3=4pAdէE֭)T}&ύk48wl mSJ[ @:#Vb[o(q'9t= _0X\3<޵A;8>-eDFv| H1bhJ3z7Ns,4rR'cvu1N|Nqƾ#/ku'֨ ";i3`НPޢ9БL hZˋ=VIU.Bzb/ҩ>_h-!H9]3|Fw4:{-3(u˯E>n)L$M=TџC9H.+\c'~S#/"֢; o=Q,|PsgxG;6|8o33Idw5ƶW&%A6Hj). eOt)bs h&+]c;r675 @fKmߐ1oW6%~C": y-.yaB(ݣ+ÿN93koj> w9pKЂ%eu|"Y2l%VV|~vT,{.'; IU)maDڣQ`&bueWg!t'7F_+;av\N܎LO ,vC:lp͡HSB<ꀁq~(\oRO6 }}fd=-S\zup^m,7l 8 Pw ].Аr0 =$O\,=~`Vʇjդ"ƀ 1{pyҫ+ [ O!7>BYQ?ʀ;}B% j8XoKP 6Rwpaz. ?,ҋ-21ԇP؝ ]9-d[&٦8 ]9$}FV7dx;l%E4LH24"cL\*عv鉧l]'BONWǎAJU iIT"ښ2W/mqe ~_Iı{)GxQ&Hc`**t4 :s|& WQOUz]Y^AB#8YpHb{=x̧ HW(iU0Ճ3?mn]~AF4=c)sF6 ({jپtq8W^!κ,V_t֌:' ڽ` źP9 `L,7up̖-Ze9;h>R4$V9:_MWꈑ[+YUb/aQ㖀Jgz@P6uEՒ'g eص@o- H6߽3G*;R533ɝ&e$xjR<tW,FHt簤o-J@w/s:SDߵ6ΜT/*v+~nmDZ1D0"ckO8*L||d. W ;`(O*Y 1 Uh;o.zxlg$fVԾjVkɅYy8)G0:-k|fjG3//a]Oka؀5aZ<K/e)nHԂ ]#j! :iu}<#{[ΰymzM+h/}lVR$A(8s:)(lzl]t $5 Jȳ=L:cCd3=CƢH_9dR3nBh/I|g" z{żiD.&ӔQQ4ŕ UaeE׼NEtnz eYpNj05 ;.x%~6/" "熔bnYP,4kRRPXV#Oc,;5buܛcwMa&Zmo 4Z@gyҌ7p#vw[QDIBA4!z"$P>k*'ss[wPG{O9tZU7@%>T7 i/A Cf 4Kͳ`!lÂԲ;c\+%KlXmDzhD1T" J5<ٷ'srȱ|UE,c+EPEtW]g }[3ϟETǕs3;)i7 ր?X$, f`Q_lL)qi`jxk/LWX5Ӿ;:S}`uORLďj:DIY[Eaʏ`{y`"_)ԈmI)W *Ƕ?t\l\Yb1MfSqvZs?ݢm)t2zh*1َܳx*oװK< wqkB\䆍 hO(1"+ȍ ݇AB7jD_j$BL~@~Į8_e0bp>#]!EySe"aX[)2gSUVg!r }DQB4oP/L _3:j%RNu3[-PZ/7 7q4ǰg;qkzȿMkJ2wpz;aĝ젤6J'Hw^7_ȢJX%Z|ö$P_; WK!){hcg lY[(8#1"<,ZK[$KʇL AA܎O XmA!!"P? &Ŋ#>m}hi,yL-dgkRjiB~tWI"R_ pyb ݩ_M¦ƶ%==7Qߏ掃Ay\7[^\r׻F j (}>VѲd9F}_d"(M=燣%SίqJkW3Kׅq(zp`(o7uXFuG WC'邭Ixl:ն%|9Z؂da;Qri}&=Fc*`͐隨?,\zwrD}O)n9~qǧ&oȐOtVOqԶ%)DzI h#ɸib~NV j %r#yn}hU ĩ"7c{Ԁ6A}OqHRo,$X[t LuݼmWEĐXNŠG7ϪG{r>3<ՎȲgٿ( PX/*;4Jfd`܋FjMүm]Ğ.F`tut4qńpI[}h_% TOE7醁Edkz0oQ!ڹ2;KOfg,׺OYVyt6I5 ȕ$81!YPmr̈́v7OPxe4N=a9MidX{T0J3 |‡<&ut솫>' Ne>@[ŗtt^V"ks~Ӏ-=V!3A Pd}@ L@|8S+uѮNjVLoⶋ-{0U; Ll5qDSy9R{0жȂ]k7Z:H6؟|~2~*C@ }4L&];=$_)haFpY4SrpѴ>SqTcyk>}ci見gyJ63J߬X?PpTpzmb=}3s{Df{S e|t 8 ^VCIDߤӬ_ZKI;^ c[SxVmb,=i&#~:X緋1$ZNH fa(p0fsѓ<^f$¤Bg\[yMTm)7aejLdC^Cbޞ8A(ӾЙ8IdÌ Kְts|(1{XG>e8ҧ_2,qg՘bl{OY=]ر !9 u'0x0 2F[^?t;|P|"'`zvHV߽3'XM($~*_z$3Aa.j 7x MqPd}!Y_I,sjzE$Q8[ڕ pK;ifyJR bn`h5m&wa'E awZm>LSBr*?jq,O$tV B(Ԙ 2+^A5CDg9>z4O)mCL_CN~ .-+Ke+L~uRn9i jG(Iʜ:ʢA 66Bo;w.s=αFkm/AJ:.:5kbϡ>Dd R+& /ї ՜JEJ~PNn "AJ}x Zh3Q"Q)TJK0B!',ըFMT JPv*j 6|ʛ01}|';+ lfӢ6,Buր}"1 77'7h#j "kEH5)Xtvs^ _=gq A !˻,[E?CyH&5bBE5Q&i;9/7ͣs._T֓fNPzӇcMPǽZbTc+އW Kd'B~~' 1;r`’hx?cuv}ՂE-/eVLWV=сhqʄ#mqj[a0 1 ˦Xad-!]2-+͟Q|;Q5;3*#u#j&xn$&j^4#z9Egԝ-"G GDOֶ҃`=? Ѐ? $3>Vm~g* *>➢˘`x3؎EM̐bNCY"u43 vQ-[@B -')9TN5%Sw{YN7|s cMM*$ЇdU&O!$kCz|XC}QE8y852 1'LgMvur}|稅s /l2\|_Tox;]j8,+M:3*A&A`PkW{d[e%O-zmEe\ƫ!兤:#$<]Y Qaswߒ 4 uP2Cq߅cS㚠ܜ%WPn]+ڒpmU- |U0D!ʯ^ZQn jT{_$L˜eRDLn$RZqn0JrUUd:hJB[OHCM YݰLe>YQm˜'! jʦs`j:*m,^^߄ 3|C x̆-#9^-e^hx~NC~g}Do?7:@\cTÏYPr]I.m'JjHd<`z)A縞u?}`%MN/*{ٸ' !va+_6Jn'Ykƥ%&w9O3}k/ ath9 {0vrK1ISxYn>O>$槅/[VQ*AGOatJ|W%E 85WI,bI'Z3ʉjF ɓ3d`V BfL;s;<䥶 q_~4c&ɩXo~ vM P-CaM纘4j?YeңǡczFz5A CƇ#"]A8}>ϿA l#',< P*2\ի]t]OopPB( f@x<9BcJlzB=yMQbHE&P6sw2PUuY< 㛚!av\Fw@Un3SN}^*ZYf\1%D@< 6z*)/I)7MT8v?RК r^,SJKrAVӞ \~fD81C,7=hֳC׃0 dvP+NY-!E0%}) 8G6rIpǦ|"K} +tNd`tsCR"rG˄f, 0+8f(᧫y nu>hd Z+7^2C~81lv7& kC9K73 ^xת"Έ˞ ](FQ߾f\F)6mڦtȓ{*g=pE WK[s^LQϖ>|vcZ9ɉ8f})#ӷj¶Q8Z|dC.=lӀaӮ}#4J(BဒcԸ\ @m,/:٣5mkfFp\L/E'|uԇȻnKmX8kMiTaY+_~z恶c`xrzjIH~6zSTL G} ]V[;`d@ȑZvy*~.Ө"2 H8?JtAtFCúNj_v VoOi%3T9 ]]TdzCݍ7*?D7f/ m8ܵ9L݀q>ף·l+AXy0dph$½;4̩/bxxM" \N08(,lHcmD,9y!0}Vv jSE;QFeZ(6bjRMS3kYwV^?BN9, A!T<J/.w< ~˱]&j!neݿbtDMDJ0vrق.Kmpv5~jMf"#w; ;ѣ;r>i|_ }}VdR.dkLߧ?3z.X8P-S  :@]5@JeoК&MgTr$nnިطd迚KI C`;ṿN@ `=O%GdB+i5~?ZZ .j(O| w,%0"8{exlc5> ֮Ge%GLmكJ[M\#J^i`~Uk7VX]A{'W<4ϝPh;'J<7_j89=#2.% \P^8{9F2\,z4IZʒ/on9ϓ >nqSzt3Z|?2$8-& YKq@h0YzRX 蚯x.0*q>x ! {x\r0 Ƃm rdZ]ZHڢ,`ڿ,`dxx0:5J~+/k!"*B׊\ NXR:Ӆ>M3 r3 T :QZ9|Bc +Gd3sQ)3{-X OMeN"],q}dW.:YFp9o̐*wY[i4:jC\qyUJOF"YvFy1M# (_ɤK<ؘqdCSXȟyH(PE­fYjCb61 w ?+>^(*:߭_FFg"lLe?H7\;ӹ ~z #*LjF#Kf= x1(_Li=# #9c'{;t Ҷo'DJ|~ӴI4?ԝgpt1G4#jXI"onT<%j[:VJ zO~MKC~坶k(9TnX_9Pł jo⦇r$V?>' 4sx +6ǵ=˄g%fN z8RJQ28G.CZ+$ZGhfd6NI2DKqI&=2*QgR{jE0Yw2};b;BwaP'4謙slٖTH]w`X^dx9!~xka73lOQ8!vjKO1>ʾ9r\f1L74ۆgW=bf7 qOj֧TAl8vD0g=yV`o6w4a|1Lb$j#0 EYYuUjjE._a[unp/T8"bJp;zg~ě*+۽zz]fr }( :{< ~0iI0e]LA@ۚ㡠1/=6ſseʠeF(WA.M[YQt:9ua؉!f&9OUU272fvR`tӄR0TG߀?Ljo6 z?_1$rhƈ+FMtssܖHBJSJRF |MiXܑb(ϼ?ݜ9#R؈ۚ|:ClBRk;ڒǝc(V:rakG̮)/a~D40hꃦ1]8,tA>sRYdޛn/Y/cXk;Cg<ٸt7>(|L&02;Elz@Z HTPG;Fxk%f6A;1o. hll_XP#4{'vط݈ ނFu ; JwA[go^f{QVrTI5mJ8ieYRRzVZCj_TTT \}UGV6JԧS{)_^/jK-qǢp=NN/CZ.r+xJP/C E/? B$/iR(e>~D}Roeya|'y_ƿ=\MEbY:`QYĉ ó;GZ_51 MT ۄ+q80"']@Qsz! \'9t EJ>@k3fhbq˩ F$.mbHҰ4hg˹ښ%C1n '4fk%Kty8-2ptN̝j[郞ȃˎ'u8WcR ˲d؀Qc<}$ FbZG/'>_Ûv]Bh+$Dw~c[$-˓8&ٍ6Tts ĕ8#uԍ-!^U5cfblwK=ܑFsP-Q'|cQ\u-f8B 7$?^h*EDk㯑ҞuSuWN1HcOxrMYVtOc9o1NƱyDDVꋀpεOEȗyx9dU2XLfj> stream xڭweXܖ5Nq+m{ n]'@(@Sxq'CRJq+^PXS;C{͟+9{}0?؀\n @luqtUۻ삸n`k` 2]`n{@׈럖?W6ƇD^EYH|_h.?f?ۃ+.!tD enYw'?VZ_TXXy0&v=P1Iڑ >ȧ{U@&#E)AQiB?VGtt-Jn:gd(|t#M#H܀BZS˒u~;4k3'Yܚ?eY2C^9lTMdC{=4v ^uWf&N < /(Qgq}Uڏ/v -I!_e~lUF2 .ߑɨNg%T yEuL $DžjidjʓWec,8-5ޡՠm5Q**TN*mW3,a:QgG2¸/@X=[JЙM;PZ!W01@_E$zbL@t,_dtQ@ARY`41Z%jqU]*l@P/jQ7{.GN="kb|ET&-ꐦyζzcږ ?ÏrNkNet"-T_PsC{E]A@Eeۿ_t/)רߜ:64Vľ J(meu?TǸExT3~M&g{Qkъ*>x[+OFQTvN8?9: tt\4_'j9€qZPQ ]Vjw CC]!j&+4cSz70fh%N ûLK{{_өu7~h^)Ni!i2eM7WEA9VG$d$xrB1{xِف:Zt γ+^ vUJ^aވSV (/(r:ixFTnP, YN_ۍg\!qDU煌)*!GJ)>Ho2mE2N;1D4Pd;?:ݻ$} j/qTax]M}HnwLc%ZbJI9,V @Gf@̏FlP&oi~Z:0}<~[NH\'A?,]Eln4ޡM"ĩ2P̞7[dr@|^]PFCi/Đu aM0H8$FN!kߟlN1"΋;QS&9KRl<׳;>;:oN⯄h$zؖSӇe> 4LMye %OTuvF*,[]sƯRSۻi Y iwZe2劌v s.x>YP[b7 giEUZW#WhkKJQPn195OKzF/Fq! Gbͨ)\qw1 VdU'XJ]^XxoH9 M UL%xމN&5'fﮏ3knW}\#Mg"<#- M^$1BΝ袀5Zq(0J)fp(k}u'ధ k ߉-VN%j103?MӲ/VmK"t_s4 2wͅ]s[q j?J;zrl]ӒϯH9&px(bv4J^x<.lKg>h;28{*vj6.ۏȗrXi9_4 h9?٤ԏ(̭+tWd DZru=б{^[v^Qrb/}wec~ge_GQg,bͺx3L]q%!9m>c$|.F{tʾVӫdµї FH2*4&6i U}{~{pT[rK:Bk$b$ٖmh8;kMY_%i_|uaXND/V:*y1Zj#۲fRot`p{PW>6ڭTO(Q4`^蓭"}H$6gdݍ҅ UO%!?$,ug3WJx֫ C?]gm Lio7>G!Wg_ʓ:MT,'O2\JiO0/L[Bg%F6rbzh jK,@]\^ܽ?}^RS~q:ETfüxعygZ@0_iHb1]*ʴQh/ߪ=}RC~ZJЛp3 maL;]wVDNvuO8SAk #-o}E.N\8 Mp^㳸]"']A""<˥(kݞNQƧfxgYGx$-|'E/y/Kԗ]*297wX\bbpa\#gb tvr>i(0FoN*qULʯI": FCo 䂮p-< [/¹hjG'3v{WEv`l,ښld?lk*9=efk3*y ޑvxv eoeߒ\N*N &1RirշUU9Im4Aрz|U~"v, 7T1aU1j/YnwrQJRU;.PbA?;υ9smWJWo߄daa6.|G7z j zVI#@2kWW*HVLփPF wse(dtN@Kmꑧy0,X&鑊Fz=XOm^(=X4I XCb|.O2Hx*!/k̺ *L%O!VV$'JuʸGHWz > ZOJӽڛ# LF̒V q.q/MqJa1?-WBVRT7,ȹ9N|+g_f_}XFtq6˭@3xΖޗ0RtIKZ;-GHTj8:BM<1h1lyQ9~M9\7Wa3I(zNH wv߭3g I}.+UkNmϏZG~J]ix}Zsk%T1yۣǔ zCjS[z%:_Q`uD~9:k2XqJ5v =>AӰst)" l, '\څTlIՄ2-^6eB\Z&< Kp삹ft` 9#jI75}겖oPK{cc밂jL-z7w @I(}ݠDx2%[*orq6˹U+Qp&G6Y}4&TN^50:| Y/뎶9jl˄7ӹ-D(̋!&YI]&+DMw_+ɩeCԠ<ʩ7Ni 1R疈M]ު*SO6z-:\mZ=w h MbhaSw隩Vyա76"Wbd+arOsߩRJ+J0z䶎92ɍS>yږ6%|k2vcu'/t跣Qlkbhf?qX]?pWIv*5iCZi<d<%97ERm2mS+A1r< t$+gC+ êY. S8{LTK>} t0g9hz[OMPC]/R4+$&jƏ;׻,@#u t-䖳~@[{69U\v/LzDO=EEddS{RCJۗ:;,-Md5]>)?QE^N[XEt.8 = =pPJi7T3b6$XoL _Ye(~i)v7hK#`jZ!s#y>!nj 9p#3^~i48.+a:0X8I.G.|.=sߞFvy\_t\jpQ ZJG/9JL = o*AZCtnd?}Y!1cP0(u}AmЂ>5 XReRRd)VWs߇xds"Y37*DR[.qbҫ73W-vZ|Fܑݢ)XmvF4l@ Ht-u-mp|YB-FZFc N}@1ɑ*6ti2dی‚i(}nB]^#8ѷ\ooUt)C {_D {/o۲dS$;UMZ7H/aW ۨ_ 6i=4V14oc r;UM$.r318.?o5:> endstream endobj 154 0 obj << /Length1 1647 /Length2 10163 /Length3 0 /Length 11012 /Filter /FlateDecode >> stream xڭveTܒ-i ;!@pܽFkK ]wΝuߛ?GS.uj52P abcf(ll>1)!V7 Jhـ !@>: 4>}BuCJt u`OdP!ocGe 1LAV@WEMiI*@ڿhd2ȁ` `l47.a!h zs:m@{ko`fobMJnjwB6o7߰72E=x(&)RN;,`W]j,zey[~ߊ$%]G& uÎ/^Z‘z77%'&{[:o޸ol=WF5cVCagQtwl0F"S}6$;$_U?|qDuBsIxvSۈVN޳{6]vZ0fu=2xJq(08|>nAF5廆u/4w Zci tuC NJKI7"jqfA{3~|(D?DXwڗuSAvN{89Q*U6e~%W Lp(Z/hTTE@P567$Wބ^7Qy74OFTi) h~ܰ/|:B<5MYgA>Lr6cO#ti#~ue;h#܍4X`-,JL|4s5 ChiOB2K\u@䅍Zuw#y\1Kv9vwBD 3M4X{Tt FyIS#'(å2et4J~ oXgz:͏Ì ;%mj?FeNBbMiWB\F:k1}sMA%.%$;JerL<0zΪ:@Y e # bb^:٫ DdGW} qLTnIsðvXXӢ1+> T`fE#1o"'U8u4+a+X6;Q.}4Ad&sK*j L YQl/\OצL ?wS(ig.̂v%7q~Y7V  ْ v~Ba56\f+Nܨ{7"z+Uhҷ *)X: \ 1Y6HA<,uOxw8@AE52l!d*/ܚ;~RұzZR}yB»E+#~sL*y*Zhad7AΘ([K FsBE[7BQ@І8du!6n?BABs2Ld,_Gufs=Avl{(yϽga3 v`fƳ~{'U~娓q J~|e=GX<1>@>nt..6qAJ O2iNs9p_Ĵ.בޱáM@׫rpjN*J '1SplPU-v^rz/:ly臏gGD `niϬLx7aL,5xEZ$o>^^.y' XU^|".8F̗:S͊=Db4D`.GNʘC->˰!C@ n¾2a|5d>~%JƃB y| '7qȏCI:yEZi(ÅRX$S)tn!?tq=콗A|QtJkцbm)w)wNBW5|X^fxV'L^quNKX5q<)6XĘ.rRCq"-0)ƕu|l@X"|p,_PyB_{ŽН }.]E7[~O͕B KQgDcdᗊKeΝփJ #v37_l.i}n}g,TI#5MO-<)m#^HUͷ>OzD9y|wkrVʱ O fT#ZF*4idtD{4儭.ϥB~O`<wwHV hc}ƕ=m?$G!+ Eg8䜻Y٥#UNS`rő˵!kZʸ&&%s0|SNv«TQsKQ)PT\b{#䷳est#),vE$F3'!SiDIv̅-#@Lq Z*6zC QNL)?*bK%+)2M&FdcD:zm>@m­"W^"t S)O] B~%䗇 r*/c#[/`/ p$P?8xeJSbr·9lhJ5[8٥/6[y׬rc'ڂXQ=QX䋱*b0RhFrz|pLC. %*!PЧ$Bժv +?1ޛ19eveH:U=3"krBrB=Ytr+i__Xmn`mr6 CCE9@s{ J+ObRj  y(R8]@:Ā9']bWh7S '̜%죳ais };  Qml咑%\ZS'e>YZ\h7Oi$ШԠ2 e,G;_BņYXeav7^[EĚ^Oqp,'{8( dU]1 a%03Q>wS89Gr(BO\MBOf#zk9L=ANg*t9aЩJGaȔ7K1sطhyP1R K$x`(@BVjt:\ucZ1X $^϶9Cښ3g{F-cUZ~5сDӜ QX_]u!µǃɿB=6bҁ"gNݼa51;"6yθ~яvg/Յ_020Qaͺ! ^!|=av-rBzkN:8*,hs. Zyu3&Cm LsOVTPIf{}0A4R#P2χl'HK PY5&BjpϰYgVL +$NzrŤ:.Հn|1KflMe7sE 6Oے1! {N"%$,ZDb؇ra%x5)xs r:WT$7Pk;Htz`/1Dq?u䄦*qځTZE4Xhy`*T\&ɂx3#dަ7iJb6&~6'BhQw F4l?|hLDk$$WƋ1r7œT!*9&n a?xJ)(9cs"MϋYf +b`h,.qmiX>ʹs>_󯴆deN_Qzd f*.eT=;4 1x"k&&iYW6ߔ_ G:_z֎ݿ';̪F]݉&1~-hNs@nsTzb)hFYU :+%e|{~hܤwzMg Eb0B뵈 31/hGV^P䛐D ma~#n9g.rVmU=aRPZ1=ǯkK)(^ƌSK-?) lL铹Ht[EbIC"@dZb{ I\La>W{N&q~ق.v/T%"iK&?j(o;>Y}a*E[.$H?0>Jl6Q/{M6ES0@Z jUV:d>ڮNQ06,x4c-* H.H L`20)J{>#'G9^|Rg8% Ɠ<) ce/gޫix:,#}S)X *?qt8J<`B܅.*ׅ 60ir;mN% 'xI~nnDjzwb<*mahr˸d5DvpsXm (ϕ)R><Ԭ:٢]8$SƷlP }S)lCjT[GNFs-b ;:sl%[/ |׺3DLR;)}[{܊-mzruM% 8~C5H"XO};dRFPՆ3(mXGa(? N=T4M?*҆p~,)BW[u:,5q̓Cac)#_LC//lwAA6cq[GeJIa*z;+|)*.52 &S͇miѓčڦ^-BI{X9k5! ?)& p0qo6a)ղF:6YD}3h'Dyݾ(f2a7ifܪ7"n-nF\r \!hkxrt%7^Ւz2w C~} G-f%8s  #IYjLbE 2R[\%@sfKK"Ð?}JoMƱ=]`|=<553L+ϭ5Nb/OϔX. Na63 ,I4)+=.ܮm eSvv[]g=XTthAFaNq`y8X_PU>$_ϒk0Fڃd4 [ƏIO("3/[ SQʤWf=;_g}~7X7DDqBjl9wQDoEu +/"?Zlz. tlB7' F((O:حғyۄ-Q9~3R(37ql6ͣvׄA3->C0AƱ")8.L߳v|A/r?{Ů񾋙ɋS /ZpÃV+o0펣,B M!3Im!o+9ATE8oo\/(bZ7E脌XaLLDU҉Ysg$dcTk&0b^ +*meWE5[.W/ZNwG8/F`P0|>ʒ3s' SA +ZXM[Kn|%bǾQoq`ɯKRBϘ?{0/!ϙF7,Kڶa&\%2ރH(fW"'qD^?"ߦrihG-Y {j"(Z7MX swK6F8}(SAr8+9/.ZQwE=䣰rѱywiHO2_YNOqS F|麒&$5+hn-bm諆ĝpdfX#ܡέӨӻ UQ w:Gu"-Rx'-#hҢRKm32wHwKTpl߆$%)Y R綮V+wӗc]8 x-GXK|6րZ z GO]MXmXjTkn ?DTI @^q.qF8VDVнb&o"!橂f4a^zS"M".6%GVJ}s]ݎ:LZ--|,g{78'u9y_2Z<~mFzj}#9;ti-$̲)ko A4'l@Tk~UpL4:ҖP0rW1ñpH3~H2塈g;%-px`6dq`@G`dx!93/'N3yPEC>a=[2H?ު/;bʾaAyx_jZۛfЇ89LC@ϹA+Y~ Pb9jZ`h|+M7u/lIyiLݏ~4ʠA”Ek1[TOgBĒ3?7KG<`]9Ene^&}AkNԼ25qz SvlNQh%i?nY#(!+V|.GOYd:בvi9_}!ҊݦhG<?`w0Z7n?.cy 0 x{67%(FA/ #gucf3)/q%` rԌv -1E(pdpٔnJ r㍱ Q{j8j=deY2 F$.Hq5HjxFZGH$WSK鿳%YXn&+z.A 70Y(j,PO+&MGo0M*F3O昻LGڀw'cT_mC ב# 6:7E}HQ@E?SQ]gxiwu8|%FDVMoLV=gi$IC?zڱD;ڿZ")7~^&"q~lFޑ#/u= Ge\ڤXE[Jհu95't,Al!.rF4~;G*-#5Wxoܭ;RJe =f'm\#7})T:Y}@Jۗ?W9'vwٺ+U֢+B1ҏ$4- endstream endobj 172 0 obj << /Author()/Title()/Subject()/Creator(LaTeX with hyperref package)/Producer(pdfTeX-1.40.17)/Keywords() /CreationDate (D:20190727092830+02'00') /ModDate (D:20190727092830+02'00') /Trapped /False /PTEX.Fullbanner (This is pdfTeX, Version 3.14159265-2.6-1.40.17 (TeX Live 2016) kpathsea version 6.2.2) >> endobj 133 0 obj << /Type /ObjStm /N 55 /First 459 /Length 2664 /Filter /FlateDecode >> stream xZYs8~ׯcS.$RSq'9ڢ%XfErA 8;ٗht}I0…!\ %:"BaD*I$Q$I"HbpmL"\&@6@qhchq';(:D ñ2b"DH(^DYb1(!L%I&J8 b8P&!<F\-`Z &"hHLjVH@hIU)' 7$fp׌Rfx5습b;Nv"0L+t՚$2QH!@W)\2$hAc$1WǏz0Հ-/+7>I^LlqJs:㊜(V$0B`:¼DŽ<zH-ҩ=/dH! Zn1}2d<.Cp$2ĘsDZb2_fh9c>/"z6; ֛y8hP7~oG?oxSj?-9PvhHȟ}uoTAw>A6}a[:OX[Y<ބ7A91]m&>},qn/\G`qxcZRpc2xe=whC 3k+yvvEUYAǵ 8nB>NՐih.nz\ =~uxyr\d*/Uz+Ã?gi~͢.g)iIzǓ'b !,(f6Oů6^珫tәYeoށCy oG>O!}F }I_}Cҏ4iY"+?Kz?E:3{UսY'[Яt9{s ~^3jƳ^)K zMvN3̖%s:_\ڢ̦s|n.qWi ]̖%L?/N.g%eh%KCV[{~EW( yrԭoG?n.Y:?qh\0mD^0J s # .JΣR{zWj߼K;ɶuhKJ/fCkw`tcᄃ}߁^ι:\rp)/Υ\v) #iB$(CǑѧ] R: ]$pQRG;Pa ש| FߓЏ`U[/U$@:"… ~|9AK&m*?hJ u=p;D4zDyBML1~F*|KI'iiU'ݸ^(+ #Г4&u>:FXvc>%خ/&M pǶ+ܮ'}B@@6#duЗOò0bʾFm3b~Ųk8JP}#?@@57ܮԖpK,0.Hw}M𲭿A% &q ]ÙqƞG܏7[^/\ϥԊ;77hTn6fpEA; q+A!VlɎk h[>.>"A.[>l$`:p;D!ΤEof6v*+?:gUZT{ȣ|xNvy/r[M좰c(ɆlXW&w#ηRT8$ѓ&zRnulKŹp7I5AyZ^{Ę%,';6ب, hp{L9+G}2hӢ e^f="6L; =BtUpN}C52(&lIw/I0pL%T XQ ͚0/ˣ`"_ݸ*&$9JsrnM">gD!OOIfm;(jx5q_ڎ"=㏆#$R%~LgmƶmN*UHYau_aYUC[@ aP*ΦYeW{%{aeGFW'sEϺ:, 0x]u PP.VuWS WC[e>miW녝8hk{ endstream endobj 173 0 obj << /Type /XRef /Index [0 174] /Size 174 /W [1 3 1] /Root 171 0 R /Info 172 0 R /ID [ ] /Length 420 /Filter /FlateDecode >> stream xIRQ̢VdhdDAQI@A w^;" "UWUeOs87!׬* *GvH*kmT \BD[e~SU7QUvs*>QUޣA +992 ?C ^@AGܷ<|C-E0 endstream endobj startxref 91300 %%EOF lifecycle/tests/0000755000176200001440000000000013514370224013354 5ustar liggesuserslifecycle/tests/testthat/0000755000176200001440000000000013520557775015233 5ustar liggesuserslifecycle/tests/testthat/helper-lifecycle.R0000644000176200001440000000063713514370224020561 0ustar liggesusers expect_defunct <- function(object, ...) { expect_error(object, class = "defunctError") } expect_no_warning <- function(...) { expect_warning(regexp = NA, ...) } try2 <- function(expr) { cat(paste0("\n", as_label2(substitute(expr)), ":\n\n")) cat(catch_cnd(expr, classes = "error")$message, "\n\n") } cat_ruler <- function(title) { cat(paste0("\n\n", title, "\n", strrep("=", nchar(title)), "\n\n")) } lifecycle/tests/testthat/test-verbosity.R0000644000176200001440000000044613515611214020344 0ustar liggesuserscontext("verbosity") test_that("verbosity option is validated", { opt <- with_options(lifecycle_verbosity = NULL, lifecycle_verbosity()) expect_identical(opt, "default") expect_error( with_options(lifecycle_verbosity = NA, lifecycle_verbosity()), "must be set to one of" ) }) lifecycle/tests/testthat/test-warning.R0000644000176200001440000000200013515533200017745 0ustar liggesusers test_that("deprecation warning is displayed with backtrace", { skip_on_cran() skip_on_os("windows") init_warnings() scoped_options( rlang_trace_top_env = current_env(), rlang_trace_format_srcrefs = FALSE, crayon.enabled = FALSE ) f <- function() g() g <- function() h() h <- function() deprecate_warn("1.0.0", "trace()") expect_warning(f(), class = "lifecycle_warning_deprecated") expect_known_output(file = test_path("output", "test-warning-backtrace.txt"), { cat_ruler("default") print(last_warning()) cat_ruler("full") print(last_warning(), simplify = "none") }) }) test_that("deprecation warnings are not recorded unless they are handled", { init_warnings() f <- function() list(g(), catch_cnd(h())) g <- function() deprecate_warn("1.0.0", "recorded()") h <- function() deprecate_warn("1.0.0", "not_recorded()") expect_warning(f()) wrns <- last_warnings() expect_length(wrns, 1) expect_match(wrns[[1]]$message, "`recorded()`", fixed = TRUE) }) lifecycle/tests/testthat/output/0000755000176200001440000000000013514370224016554 5ustar liggesuserslifecycle/tests/testthat/output/test-signal-message-non-syntactic.txt0000644000176200001440000000030113514370224025752 0ustar liggesusers Non-syntactic function name and non-syntactic parameter name ============================================================ The `qu-ux` argument of ``foo-fy`()` is deprecated as of bar 1.0.0. lifecycle/tests/testthat/output/test-warning-backtrace.txt0000644000176200001440000000171313514370224023656 0ustar liggesusers default ======= message: `trace()` is deprecated as of lifecycle 1.0.0. This warning is displayed once per session. Call `lifecycle::last_warnings()` to see where this warning was generated. backtrace: 1. testthat::expect_warning(f(), class = "lifecycle_warning_deprecated") 6. lifecycle:::f() 7. lifecycle:::g() 8. lifecycle:::h() full ==== message: `trace()` is deprecated as of lifecycle 1.0.0. This warning is displayed once per session. Call `lifecycle::last_warnings()` to see where this warning was generated. backtrace: █ 1. ├─testthat::expect_warning(f(), class = "lifecycle_warning_deprecated") 2. │ └─testthat:::quasi_capture(enquo(object), label, capture_warnings) 3. │ ├─testthat:::.capture(...) 4. │ │ └─base::withCallingHandlers(...) 5. │ └─rlang::eval_bare(get_expr(.quo), get_env(.quo)) 6. └─lifecycle:::f() 7. └─lifecycle:::g() 8. └─lifecycle:::h() lifecycle/tests/testthat/output/test-signal-message.txt0000644000176200001440000000156113514370224023174 0ustar liggesusers Inferred package name (here it is base b/c of testthat's eval env) ================================================================== `foo()` is deprecated as of base 1.0.0. Overridden package name ======================= `foo()` is deprecated as of mypkg 1.0.0. Replacement function ==================== `foo()` is deprecated as of base 1.0.0. Please use `bar()` instead. Replacement function with overridden package names (1) ====================================================== `quux()` is deprecated as of foo 1.0.0. Please use `foofy()` instead. Replacement function with overridden package names (2) ====================================================== `quux()` is deprecated as of foo 1.0.0. Please use `bar::foofy()` instead. Details ======= `foo()` is deprecated as of base 1.0.0. Please use `bar()` instead. # Before: foo() # After: bar() lifecycle/tests/testthat/output/test-signal-message-args.txt0000644000176200001440000000205513514370224024125 0ustar liggesusers Deprecated argument =================== The `quux` argument of `foo()` is deprecated as of base 1.0.0. Deprecated argument with function replacement ============================================= The `quux` argument of `foo()` is deprecated as of base 1.0.0. Please use `bar()` instead. Deprecated argument with argument replacement (same function) ============================================================= The `quux` argument of `foo()` is deprecated as of base 1.0.0. Please use the `foofy` argument instead. Deprecated argument with argument replacement (different function) ================================================================== The `quux` argument of `foo()` is deprecated as of base 1.0.0. Please use the `foofy` argument of `bar()` instead. Deprecated argument with argument replacement (different function, different package) ===================================================================================== The `quux` argument of `foo()` is deprecated as of aaa 1.0.0. Please use the `foofy` argument of `zzz::bar()` instead. lifecycle/tests/testthat/test-signal.R0000644000176200001440000000673113515611214017576 0ustar liggesuserscontext("signal") test_that("signallers require function call syntax for `what`", { expect_error(deprecate_stop("1.0.0", "foo"), "must have function call syntax") expect_error(deprecate_stop("1.0.0", "foo()()"), "must refer to a function name") expect_error(deprecate_stop("1.0.0", "foo(arg = , arg = )"), "more than one argument") expect_error(deprecate_stop("1.0.0", "foo(arg)"), "in the LHS") expect_error(deprecate_stop("1.0.0", "foo(arg = arg)"), "in the LHS") }) test_that("deprecation messages are constructed for functions", { expect_known_output(file = test_path("output", "test-signal-message.txt"), { cat_ruler("Inferred package name (here it is base b/c of testthat's eval env)") cat_line(lifecycle_build_message("1.0.0", "foo()", signaller = "deprecate_stop")) cat_ruler("Overridden package name") cat_line(lifecycle_build_message("1.0.0", "mypkg::foo()", signaller = "deprecate_stop")) cat_ruler("Replacement function") cat_line(lifecycle_build_message("1.0.0", "foo()", "bar()", signaller = "deprecate_stop")) cat_ruler("Replacement function with overridden package names (1)") cat_line(lifecycle_build_message("1.0.0", "foo::quux()", "foofy()", signaller = "deprecate_stop")) cat_ruler("Replacement function with overridden package names (2)") cat_line(lifecycle_build_message("1.0.0", "foo::quux()", "bar::foofy()", signaller = "deprecate_stop")) cat_ruler("Details") details <- glue::glue( " # Before: foo() # After: bar() " ) cat_line(lifecycle_build_message("1.0.0", "foo()", "bar()", details = details, signaller = "deprecate_stop")) }) }) test_that("deprecation messages are constructed for arguments", { expect_known_output(file = test_path("output", "test-signal-message-args.txt"), { cat_ruler("Deprecated argument") cat_line(lifecycle_build_message("1.0.0", "foo(quux = )", signaller = "deprecate_stop")) cat_ruler("Deprecated argument with function replacement") cat_line(lifecycle_build_message("1.0.0", "foo(quux = )", "bar()", signaller = "deprecate_stop")) cat_ruler("Deprecated argument with argument replacement (same function)") cat_line(lifecycle_build_message("1.0.0", "foo(quux = )", "foo(foofy = )", signaller = "deprecate_stop")) cat_ruler("Deprecated argument with argument replacement (different function)") cat_line(lifecycle_build_message("1.0.0", "foo(quux = )", "bar(foofy = )", signaller = "deprecate_stop")) cat_ruler("Deprecated argument with argument replacement (different function, different package)") cat_line(lifecycle_build_message("1.0.0", "aaa::foo(quux = )", "zzz::bar(foofy = )", signaller = "deprecate_stop")) }) }) test_that("non-syntactic names are handled gracefully", { expect_known_output(file = test_path("output", "test-signal-message-non-syntactic.txt"), { cat_ruler("Non-syntactic function name and non-syntactic parameter name") cat_line(lifecycle_build_message("1.0.0", "bar::`foo-fy`(`qu-ux` = )", signaller = "deprecate_stop")) }) }) test_that("defunct errors inherit from lifecycle subclass", { expect_error(deprecate_stop("1.0.0", "foo()"), class = "lifecycle_error_deprecated") }) test_that("warning conditions are signaled only once if warnings are suppressed", { scoped_options(lifecycle_verbosity = "warning") x <- 0L suppressWarnings(withCallingHandlers( warning = function(...) x <<- x + 1L, deprecate_warn("1.0.0", "foo()") )) expect_identical(x, 1L) }) lifecycle/tests/testthat/test-arg.R0000644000176200001440000000025313514370224017065 0ustar liggesuserscontext("arg") test_that("deprecated() returns the missing argument", { fn <- function(foo = deprecated()) is_missing(foo) expect_true(fn()) expect_false(fn(1)) }) lifecycle/tests/testthat/test-lifecycle.R0000644000176200001440000000506113515611214020253 0ustar liggesuserscontext("lifecycle") test_that("deprecate_soft() warns when called from global env", { old <- Sys.getenv("TESTTHAT_PKG") Sys.setenv("TESTTHAT_PKG" = "") on.exit(Sys.setenv("TESTTHAT_PKG" = old)) fn <- function(id) deprecate_soft("1.0.0", "foo()", id = id) scoped_bindings(.env = global_env(), fn = fn) locally( expect_no_warning(fn("called from local env")) ) with_options(lifecycle_verbosity = "default", { with_env(global_env(), { expect_warning(fn("called from global env"), "foo") }) }) }) test_that("deprecate_soft() warns when called from package being tested", { old <- Sys.getenv("NOT_CRAN") on.exit(Sys.setenv("NOT_CRAN" = old)) Sys.setenv("NOT_CRAN" = "true") retired <- function() deprecate_soft("1.0.0", "foo()") expect_warning(retired(), "is deprecated") }) test_that("deprecate_soft() warns when option is set", { retired <- function(id) deprecate_soft("1.0.0", "foo()", id = id) with_options(lifecycle_verbosity = "warning", { expect_warning(retired("rlang_test5"), "is deprecated") }) }) test_that("deprecate_warn() repeats warnings when option is set", { scoped_options(lifecycle_verbosity = "warning") retired1 <- function() deprecate_soft("1.0.0", "foo()", id = "signal repeat") retired2 <- function() deprecate_warn("1.0.0", "foo()", id = "warn repeat") expect_warning(retired1(), "is deprecated") expect_warning(retired2(), "is deprecated") expect_warning(retired1(), "is deprecated") expect_warning(retired2(), "is deprecated") }) test_that("can promote lifecycle warnings to errors", { scoped_options(lifecycle_verbosity = "error") expect_defunct(deprecate_soft("1.0.0", "foo()"), "is deprecated") expect_defunct(deprecate_warn("1.0.0", "foo()"), "is deprecated") }) test_that("soft-deprecation warnings are issued when called from child of global env as well", { fn <- function() deprecate_soft("1.0.0", "foo()", id = "child of global env") expect_warning(eval_bare(call2(fn), env(global_env())), "is deprecated") }) test_that("once-per-session note is not displayed on repeated warnings", { wrn <- catch_cnd(deprecate_warn("1.0.0", "foo()", id = "once-per-session-note")) expect_true(grepl("once per session", wrn$message)) scoped_options(lifecycle_verbosity = "warning") wrn <- catch_cnd(deprecate_warn("1.0.0", "foo()", id = "once-per-session-no-note")) expect_false(grepl("once per session", wrn$message)) }) test_that("the topenv of the empty env is not the global env", { expect_silent(deprecate_soft("1.0.0", "foo()", env = empty_env(), id = "topenv of empty env")) }) lifecycle/tests/testthat.R0000644000176200001440000000007613514370224015342 0ustar liggesuserslibrary(testthat) library(lifecycle) test_check("lifecycle") lifecycle/vignettes/0000755000176200001440000000000013516776443014241 5ustar liggesuserslifecycle/vignettes/figures/0000755000176200001440000000000013515611230015662 5ustar liggesuserslifecycle/vignettes/figures/lifecycle-defunct.svg0000644000176200001440000000170413515611214021774 0ustar liggesuserslifecyclelifecycledefunctdefunct lifecycle/vignettes/figures/lifecycle-maturing.svg0000644000176200001440000000170613515611214022174 0ustar liggesuserslifecyclelifecyclematuringmaturing lifecycle/vignettes/figures/lifecycle-archived.svg0000644000176200001440000000170713515611214022134 0ustar liggesusers lifecyclelifecyclearchivedarchived lifecycle/vignettes/figures/lifecycle-soft-deprecated.svg0000644000176200001440000000172613515611214023421 0ustar liggesuserslifecyclelifecyclesoft-deprecatedsoft-deprecated lifecycle/vignettes/figures/lifecycle-questioning.svg0000644000176200001440000000171413515611214022712 0ustar liggesuserslifecyclelifecyclequestioningquestioning lifecycle/vignettes/figures/lifecycle-stable.svg0000644000176200001440000000167413515611214021624 0ustar liggesuserslifecyclelifecyclestablestable lifecycle/vignettes/figures/lifecycle-experimental.svg0000644000176200001440000000171613515611214023044 0ustar liggesuserslifecyclelifecycleexperimentalexperimental lifecycle/vignettes/figures/example-badge.png0000644000176200001440000003056213515611214021073 0ustar liggesusersPNG  IHDR m4 iCCPICC ProfileHTtZBUJFHBJ AŮ,ZKW`aTAu],Pyy͝{̙9@3`U2E9 _FBb? @4PnhnXOqyRP$)\)'sĒo$G<-($h(wM02oD!@ >dgrh#ʶ"P2e/(̚S)l6_{fT^ T StਉzN U(en =M@;_ssæ8URaL1O=Œ(ETsْ麲X_c) b8W7wѡ1~ D' {/ks1牘9 ޸ 0g|@ $E Hl;@9p$8 .{@s0ށ1BZ>dYA+@aP%C|Hɠz*ʡP-3 .Ch^C`&4X6gî0c0Ά|x3\W‡&,|sxBG kC"$$ BD6ȑG C00L0&dcVa6a15&y fK`X6.`KUFlvqf8\0.[ۄۃkzqQ<{#l| ?@P" $PJ8D8MNxB#M"xFF"Hf$OR )TF'] 'QRR2TrS$TZTtTҀG:ْG^@7;7 ŔCIP6Sj)()6,ej &/U*&*LE*y**UP%UWVRU٩EemR;vY:^T=@~@ QzA G3hi"Z7mDC]Q#NcF) 9Y 1z? gϸ>LMMfff'-VV6fmKyKj_~16c&gfc3::Q:utuw}GK+;7O`02yƈA`Aa:F$#WTc}puwM&&&&MLM76>54cՙ7{gWߴYZ[豄-,׬`+g+YYnD*gݲ&[3sl6a6lm^64{_ml3l޳S [gfҞc_aӁڡᕣ#qm'S/.zacd.\i\/a|Vt~OktCO98gГSJKm~cy´`13_J|}kG bGcCb8ZHKʐGaap8<$|{&sEs#@+b{ăH_EΫ8.jETg45zqw11[bŚb;Tƽ/'NXp5Q;QؒOKJ0N /4[tEڋ2Zx269>Pgv=Jٝ29c:?arbw# jZ4,h$vy5bKI4Nm9M:zLޙvq;K8wB/\x\'%K'/_nzզ._~mvnrǭwNq&վ}o-%ͽNƝWws[s{҇:+A,?5?(ѽAߥLy\DIS'{6\|Ej~iğ>v$ ֛귎o;F#G|7և;?z23s/m_C%oRA j(v@51ifФF?fT0TE dtA1>vpP4~2UotE2>>g| ۑ;gOj á_4Gԥ5 #ɿeiTXtXML:com.adobe.xmp 269 109 d$IDATx]|TRHB !J 4?]"(iR(MDPADzfEҫH@ j%߆=^ w.x;?r}qnV MFFm,i4z"h4v!]p@#](R |dilߵ~ZUki]B7=Z6m !4$##qI=~F iDҕ ’_WRBB*W( hkШP4Ə7Ok~F~';Hw?:z,iO92}FP` &,{~,^,(YP A!bW"AL;*/++_<{4%G/ؔq5m7LYѹ;oޔ=}&RN +]rRD4~P܈G5SE,dϚU6%b4i۱`Wț;>9f~3iiI"eA ݺur fͱhk֨Z5{sDt:/p}T1ޭC;53jͼrX*fɊ:/ӛmQ晒ȟ7\?g>:ԭUa!U6pxɧpwG-_ a_Ͷ>@x ^AUju&rr!O7~/ZeQC~ڸC"((\\=HF21|vTfϝo*gFYjth#+\LysFݒ_6'NE;ȑ=3AXEQ"zy<_YhPɓ.`NGK7лGWY/k'ُ"Ӎ;a0)NaqtY@lgХ{,؁b89/]!P}$uW,Wc?"ǪQ>vLGU1R_-v6@-].hbe߶c)Mj#% ^#qXׄ`#_}{t.ɬڿ^qK6:P CdiܽkWdYz .w+ű{5:Foxݪ:bPqmnJAh*^H} Ò+My6sQ9ؿ[/5>w_[˱e}zˉ^׮_gQIr~Ytq _Fg w MMŲ\m!Qx"9)e {Y8< qqI'2~ χz8r,߁I}AdXfx@1EbT<[rqFJ<{u=7 >s>LF]U7&j$1%0qa Ѳ^)c(a Yhjz?aw~=9i2#~=Sj F^Z4cR)y1␞h#nϐ!1jqDLCFHҬ !He'LϴMē$xRa!m߽GQxqWeJin߾-D;wIuk0f-aJKl*|>D_ieb{ZP[q7{mץNs1TŤڃN6[siES,kh-RHČq*yr'٘{/*B2ʊ=VaN$YVz3@jլt$ Wh_KK?I &WU:!֑sθ+8!yi9xNxXw-R$qB{/^dțn=P5G!+=q \ 6Vz[X>+?nl)1K)ψ`5ڰtqgY5'FVmTNDKCFLF^_BaN3։Sf T1lYä͂1);cf=T7*W %4Z6m,LBK>MvdKhmZh7Z}zI{x2X/eS>.Rtcj<B8iOqM)58vYfCnF<2<Ƃ5)ah>}cRҝp^;cHE܎~5bޘmƢRr)Ku_ܓ6g#ufeMxD99hO#ڜ(lO:}ZޒwuqO+}q"ʑԴKY":K( {\4ir'F tr@~(ykN "WEPFr8niEI* y/ J[nEŗdՌȰc ;!y@{0]試_D!"M_ e,HY\E9ɕu1 '^a^ lb4!nc9}%qq3JnuPD8Px*YBFia f5&:Hf(b C{k`O.yHU'fioker<5RRR3) !#Byxl޻ (S$m,cT+,R~y/ƍ K濷I-%#P)l'17SMB〈 H~"ќh01\h G'0 +7Wiqb.X@ & 'ʤSwwI{2 l; Ӹ+ILe_Ѩe E g16835ҁH'"߷x(Cm7ǃǒvf7.aEMq#xP{C| 罱m[nCWb~>7[=LX63 ĕY|GpEb*eda|yp>:]JŔ6-Cmk,踔sD a$LSNJc^Z߫P{~q.:r.rQRKTN~Z l uNg{7nd!nS"n\nߔeS"#MyJaY0FqBq4Fס8?}VBF B A7A#JhJ۪ppAMZhhj-4`t44Z'@@ '+!+nF B A7A#JhJ۪ppAMZhhj-4`t44Z'@@ '+!+nF B A7A#JhJ۪ppAMZhhj-4`t44Z'@@ '+!+nF B A7A#JHqw#OFD b1٩?6Bh ȎhtH$џMF `yh\FW[+M-vh9W_&֨V&4:[_|9 QBc]G&uQ? +GԩYeJO#o\4KU) HSPAL3a!(\mӯ_r,꛹?l˙=;J?Sr:A#l<ЈQQ_]I4i$KW8p_pW#\)LvhЄ8vGf/ ¬z\25?{JMa}*9y?`{tPha7;n'3C̙lX#|p0hG #Q'ԅKM&L"EF)xdA3#48DvSH>=0aMn$r)@Q-4qZ/Ƥå?3pBm$ر{ò;mpbRCQ#Z{)8!4kzΗ',y$bI# #$'GGFIA.M#OCxzzcgJ'#Չa,ghX,mpA?7m*WB[;EǓO#Nc'Oi?o^4_B,dϒ`*>J)ͤ]:H+hyOu2iΉUfs[v̙3^znjEWJR◚2eʠR_gKk_,뫒*dB"OP}X}F~r8 V}ai+VϼOHH#Gзo_"_|3ď7{T<;?e5.8վ)ra\OɤWN746{O4΄Ug f͚aɒ%h߾=įSq9t9svk׮Ν;%5kD&Mׯ'zƍůƪU`^_~jT3CQ̿<7OQ?Wkg*a}rlY~E p,JC],7ZP.L87D9>֓+= Dn"8s~eԇy{UjBf>wV񳉇FCΝ{n&2i$ݻ D-ЧO;v М9pUիWKӇf1/w@1yCnx}vm!! u,-=# _^"/Xgf&W^s` UQI"[ Ǝ#ז79ӛ xD}pZ4U7t;:@KȒ%4M*W @5j$5ҥK֭ŋ"#+VN:?˗-7u2UT)xp"l4DV6>^,^J!SL8qh~ۇhiw\)h>МAťM>K{'O>P/+ϗݢ쫊_)vy?;;S^Tjw0vӇ8uoWjZ0ߔF Čג蓔OE Lf@={`/y]8I0Tp&i';/]$صk C4C2fhƒP,]mڴAPP4eX NU(u]Nb9gIhw:{5 ̈zAL.'6¿廯IP.TQi۪I#LX\\SVϧN1F߃#SG[Vo}lifecyclelifecycledeprecateddeprecated lifecycle/vignettes/figures/lifecycle-retired.svg0000644000176200001440000000170513515611214022003 0ustar liggesusers lifecyclelifecycleretiredretired lifecycle/vignettes/lifecycle.Rmd0000644000176200001440000002277713516020753016645 0ustar liggesusers--- title: "Usage of the lifecycle package" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{lifecycle} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ``` ```{r setup} library(lifecycle) ``` Use lifecycle to document the status of your exported functions and arguments: * Choose one of the 7 lifecycle stages a function or argument can be in. You can choose from 4 development stages (experimental, maturing, stable, and questining) and 3 deprecation stages (soft-deprecated, deprecated, and defunct). * If the function or argument is deprecated, make sure your users know about by calling `deprecate_soft()`, `deprecate_warn()`, or `deprecate_stop()`. These functions try to be informative without being too verbose, with increasing levels of verbosity as the deprecation stage advances. * Include the relevant lifecycle badge in your documentation. ### Stages The lifecycle stages for functions and arguments closely mirror the [lifecycle stages for packages](https://www.tidyverse.org/lifecycle/). There are 4 __development__ stages. 1. Experimental This is a new feature that is in the very early stage of development. It is exported so users can start to use it and report feedback, but its interface and/or behaviour is likely to change in the future. It is generally best to avoid depending on experimental features. 1. Maturing The interface and behaviour of a maturing feature has been roughed out, but finer details are likely to change. It still needs more feedback to find the optimal API. 1. Stable A feature is considered stable when the author is happy with its interface and behaviour. Major changes are unlikely, and breaking changes will occur gradually, through a deprecation process. 1. Questioning The author is no longer convinced that the feature is the optimal approach. However, there are no recommended alternatives yet. Once the decision of discontinuing a feature has been made, it goes through 3 __deprecation__ stages. 1. Soft deprecated The author is no longer happy with a feature because they consider it sub-optimal compared to some other approach, or simply because they no longer have the time to maintain it. A soft-deprecated feature can still be used without hassle, but users should consider switching to an alternative approach. 1. Deprecated The feature is likely to be discontinued in the next major release. Users should switch to an alternative approach as soon as possible. 1. Defunct The feature can no longer be used. A defunct function is still exported, and a defunct argument is still part of the signature. This way an informative error can be thrown. Finally, when a feature is no longer exposed or mentioned in the released version of the package, it is said to be __archived__. ### Badges {#rd-badges} Make sure your users know what stage a feature is by adding badges in the help topics of your functions. badge * Call `usethis::use_lifecycle()` to import the badges in your package. * Use the `lifecycle` Rd macro to insert a badge: ``` #' \lifecycle{experimental} #' \lifecycle{soft-deprecated} ``` This badge renders as text in non-HTML documentation. To document the status of a whole function, a good place to include the badge is at the top of the `@description` block. To document an argument, you can put the badge in the argument description. * For functions in development, you typically don't need to advertise the status if it is the same as the package as a whole. For instance, if your package is [maturing](https://www.tidyverse.org/lifecycle/#maturing), only signal functions in the experimental, stable, and questioning stages. ### Verbosity of deprecation lifecycle offers three levels of verbosity corresponding to the three deprecation stages. * __Soft deprecation__: At this stage, call `deprecate_soft()` to start warning users about the deprecation in the least disruptive way. This function only warns (a) users who try the feature from the global workspace, and (b) developers who directly use the feature, when they run unit tests with testthat. No warning is issued outside of unit tests, or when the deprecated feature is called from another package then ther own. When a warning does get issued, users only see it once per session rather than at each invokation. * __Deprecation__: At this stage, call `deprecate_warn()` to warn unconditionally about the deprecated feature. The warning is issued only once per session. * __Defunct__: The feature is discontinued. Call `deprecate_stop()` to fail with an error. ### Deprecating functions These functions take the version number starting from which the feature is considered deprecated (it should remain the same across all deprecation stages), and a feature descriptor: ```{r} deprecate_warn("1.0.0", "mypkg::foo()") ``` You can optionally provide a replacement: ```{r} deprecate_warn("1.0.0", "mypkg::foo()", "new()") ``` For the purpose of these examples we explicitly mentioned the namespace with `mypkg::`, however you can typically omit it because lifecycle infers the namespace from the calling environment. Specifying the namespace is mostly useful when the replacement is implemented in a different package. ```{r} # The new replacement foobar_adder <- function(foo, bar) { foo + bar } # The old function still exported for compatibility foobaz_adder <- function(foo, bar) { deprecate_warn("1.0.0", "foobaz_adder()", "foobar_adder()") foobar_adder(foo, bar) } ``` ### Deprecating arguments The syntax for deprecating argument is based on the syntax for deprecating functions: ```{r} deprecate_warn("1.0.0", "mypkg::foo(arg = )") deprecate_warn("1.0.0", "mypkg::foo(arg = )", "mypkg::foo(new = )") ``` lifecycle also provides the `deprecated()` sentinel to use as default argument. This provides self-documentation for your users, and makes it possible for external tools to determine which arguments are deprecated. This sentinel is simply the missing argument, so you can test whether the argument was supplied with `rlang::is_missing()`: ```{r} foobar_adder <- function(foo, bar, baz = deprecated()) { # Check if user has supplied `baz` instead of `bar` if (!rlang::is_missing(baz)) { # Signal the deprecation to the user deprecate_warn("1.0.0", "foobar_adder(baz = )", "foobar_adder(bar = )") # Deal with the deprecated argument for compatibility bar <- baz } foo + bar } ``` ### Workflow #### Where do these deprecation warnings come from? Call `lifecycle::last_warnings()` to see backtraces for all the deprecation warnings that were issued during the last top-level command. #### Bumping deprecation stage Some manual search and replace is needed to bump the status of deprecated features. We recommend starting with defunct features and work your way up: 1. Search for `deprecate_stop()` and remove the feature from the package. The feature is now archived. 1. Search for `deprecate_warn()` and replace with `deprecate_stop()`. 1. Search for `deprecate_soft()` and replace with `deprecate_warn()`. 1. Call `deprecate_soft()` from newly deprecated functions. Don't forget to update the badges in the documentation topics. #### Find out what deprecated features you rely on Test whether your package depends on deprecated features directly or indirectly by setting the verbosity option in the `tests/testthat.R` file just before `test_check()` is called: ```{r, eval = FALSE} library(testthat) library(mypackage) options(lifecycle_verbosity = "error") test_check("mypackage") ``` This forces all deprecated features to fail. You can also set the relevant options manually to force warnings or errors in your session: ```{r, eval = FALSE} # Force silence options(lifecycle_verbosity = "quiet") # Force warnings options(lifecycle_verbosity = "warning") # Force errors options(lifecycle_verbosity = "error") ``` Forcing warnings can be useful in conjuction with `last_warnings()`, which prints backtraces for all the deprecation warnings issued during the last top-level command. #### Test deprecated features Test whether a deprecated feature still works by disabling the warnings with `scoped_lifecycle_silence()`: ```{r, eval = FALSE} test_that("`baz` argument of `foobar_adder()` still works", { withr::local_options(list(lifecycle_verbosity = "quiet")) foobar_adder(1, baz = 2) }) ``` Test that a feature is correctly deprecated by forcing warnings and checking the class `"lifecycle_warning_deprecated"`: ```{r, eval = FALSE} test_that("`baz` argument of `foobar_adder()` is deprecated", { withr::local_options(list(lifecycle_verbosity = "warning")) expect_warning(foobar_adder(1, baz = 2), class = "lifecycle_warning_deprecated") }) ``` Defunct features throw errors of class `"lifecycle_error_deprecated"`: ```{r, eval = FALSE} test_that("`foo()` is defunct", { expect_error(foo(), class = "lifecycle_error_deprecated") }) ``` lifecycle/R/0000755000176200001440000000000013516776053012427 5ustar liggesuserslifecycle/R/lifecycle-package.R0000644000176200001440000000137113516551340016072 0ustar liggesusers#' @keywords internal #' @import rlang "_PACKAGE" # The following block is used by usethis to automatically manage # roxygen namespace tags. Modify with care! ## usethis namespace: start ## usethis namespace: end NULL # For R 3.2 support strrep <- function(x, times) { x <- as.character(x) if (length(x) == 0L) { return(x) } unlist(.mapply(function(x, times) { if (is.na(x) || is.na(times)) { return(NA_character_) } if (times <= 0L) { return("") } paste0(replicate(times, x), collapse = "") }, list(x = x, times = times), MoreArgs = list()), use.names = FALSE) } sexp_address <- NULL .onLoad <- function(lib, pkg) { # FIXME: Export from rlang sexp_address <<- env_get(ns_env("rlang"), "sexp_address") } lifecycle/R/utils.R0000644000176200001440000000227413514370224013703 0ustar liggesusers has_colour <- function() is_installed("crayon") && crayon::has_color() silver <- function(x) if (has_colour()) crayon::silver(x) else x upcase1 <- function(x) { substr(x, 1, 1) <- toupper(substr(x, 1, 1)) x } cat_line <- function(...) { cat(paste0(..., "\n", collapse = "")) } paste_line <- function(...) { paste(chr(...), collapse = "\n") } has_crayon <- function() { is_installed("crayon") && crayon::has_color() } red <- function(x) if (has_crayon()) crayon::red(x) else x blue <- function(x) if (has_crayon()) crayon::blue(x) else x green <- function(x) if (has_crayon()) crayon::green(x) else x yellow <- function(x) if (has_crayon()) crayon::yellow(x) else x magenta <- function(x) if (has_crayon()) crayon::magenta(x) else x cyan <- function(x) if (has_crayon()) crayon::cyan(x) else x blurred <- function(x) if (has_crayon()) crayon::blurred(x) else x silver <- function(x) if (has_crayon()) crayon::silver(x) else x bold <- function(x) if (has_crayon()) crayon::bold(x) else x italic <- function(x) if (has_crayon()) crayon::italic(x) else x underline <- function(x) if (has_crayon()) crayon::underline(x) else x lifecycle/R/badge.R0000644000176200001440000000527313516776032013620 0ustar liggesusers#' Embed a lifecycle badge in documentation #' #' @description #' #' Call `usethis::use_lifecycle()` to import the badges in your #' package. Then use the `lifecycle` Rd macro to insert a lifecycle #' badges in your documentation, with the relevant lifecycle stage as #' argument: #' #' ``` #' \lifecycle{experimental} #' \lifecycle{soft-deprecated} #' ``` #' #' The badge is displayed as image in the HTML version of the #' documentation and as text otherwise. #' #' If the deprecated feature is a function, a good place for this #' badge is at the top of the topic description (if the deprecated #' function is documented with other functions, it might be a good #' idea to extract it in its own documentation topic to prevent #' confusion). If it is an argument, you can put the badge in the #' argument description. #' #' @section Badges: #' * \verb{\lifecycle{experimental}}: \lifecycle{experimental} #' * \verb{\lifecycle{maturing}}: \lifecycle{maturing} #' * \verb{\lifecycle{stable}}: \lifecycle{stable} #' * \verb{\lifecycle{questioning}}: \lifecycle{questioning} #' * \verb{\lifecycle{archived}}: \lifecycle{archived} #' * \verb{\lifecycle{soft-deprecated}}: \lifecycle{soft-deprecated} #' * \verb{\lifecycle{deprecated}}: \lifecycle{deprecated} #' * \verb{\lifecycle{defunct}}: \lifecycle{defunct} #' #' @details #' #' The `lifecycle{}` macro is made available by adding this field to #' DESCRIPTION (this is done automatically by #' `usethis::use_lifecycle()`): #' #' ``` #' RdMacros: lifecycle #' ``` #' #' The macro expands to this expression: #' #' ``` #' \Sexpr[results=rd, stage=render]{lifecycle::badge("experimental")} #' ``` #' #' @param stage A lifecycle stage as a string, one of: #' `"experimental"`, `"maturing"`, `"stable"`, `"questioning"`, #' `"archived"`, `"soft-deprecated"`, `"deprecated"`, `"defunct"`. #' @return An `Rd` expression describing the lifecycle stage. #' #' @export badge <- function(stage) { url <- paste0("https://www.tidyverse.org/lifecycle/#", stage) img <- lifecycle_img(stage, url) sprintf("\\ifelse{html}{%s}{\\strong{%s}}", img, upcase1(stage)) } lifecycle_img <- function(stage, url) { file <- sprintf("lifecycle-%s.svg", stage) stage_alt <- upcase1(stage) switch(stage, experimental = , maturing = , stable = , questioning = , retired = , archived = sprintf( "\\out{%s lifecycle}", url, file.path("figures", file), stage_alt ) , `soft-deprecated` = , deprecated = , defunct = sprintf( "\\figure{%s}{options: alt='%s lifecycle'}", file, stage_alt ), abort(sprintf("Unknown lifecycle stage `%s`", stage)) ) } lifecycle/R/signal.R0000644000176200001440000002353213516776053014034 0ustar liggesusers#' Deprecate functions and arguments #' #' @description #' #' These functions provide three levels of verbosity for deprecated #' functions. #' #' * `deprecate_soft()` warns only if the deprecated function is #' called from the global environment (so the user can change their #' script) or from the package currently being tested (so the #' package developer can fix the package). Use for soft-deprecated #' functions. #' #' * `deprecate_warn()` warns unconditionally. Use for deprecated functions. #' #' * `deprecate_stop()` fails unconditionally. Use for defunct functions. #' #' Warnings are only issued once per session to avoid overwhelming the #' user. See the [verbosity option][verbosity] to control this #' behaviour. #' #' @param when The package version when function/argument was deprecated. #' @param what If the deprecated feature is a whole function, the #' function name: `"foo()"`. If it's an argument that is being #' deprecated, the function call should include the argument: #' `"foo(arg = )"`. #' #' You can optionally supply the namespace: `"ns::foo()"`. If not #' supplied, it is inferred from the caller environment. #' @param with An optional replacement for the deprecated feature. #' This should be a string of the same form as `what`. #' @param details The deprecation message is generated from `when`, #' `what`, and `with`. You can additionally supply a string #' `details` to be appended to the message. #' @param id The id of the deprecation. A warning is issued only once #' for each `id`. Defaults to the generated message, but you should #' give a unique ID when the message in `details` is built #' programmatically and depends on inputs, or when you'd like to #' deprecate multiple functions but warn only once for all of them. #' @param env The environment in which the deprecated function #' was called. A warning is issued if called from the global #' environment. If testthat is running, a warning is also called if #' the deprecated function was called from the package being tested. #' #' This typically doesn't need to be specified, unless you call #' `deprecate_soft()` or `deprecate_warn()` from an internal helper. #' In that case, you need to forward the calling environment. #' @return `NULL`, invisibly. #' #' @seealso [lifecycle()] #' #' @examples #' # A deprecated function `foo`: #' deprecate_warn("1.0.0", "foo()") #' #' # A deprecated argument `arg`: #' deprecate_warn("1.0.0", "foo(arg = )") #' #' # A deprecated function with a function replacement: #' deprecate_warn("1.0.0", "foo()", "bar()") #' #' # A deprecated function with a function replacement from a #' # different package: #' deprecate_warn("1.0.0", "foo()", "otherpackage::bar()") #' #' # A deprecated function with an argument replacement: #' deprecate_warn("1.0.0", "foo()", "foo(bar = )") #' #' @export deprecate_soft <- function(when, what, with = NULL, details = NULL, id = NULL, env = caller_env(2)) { verbosity <- lifecycle_verbosity() if (verbosity == "quiet") { return(invisible(NULL)) } if (verbosity %in% c("warning", "error") || env_inherits_global(env)) { deprecate_warn(when, what, with = with, details = details, id = id) return(invisible(NULL)) } if (from_testthat(env)) { # Warn repeatedly in unit tests scoped_options(lifecycle_verbosity = "warning") deprecate_warn(when, what, with = with, details = details, id = id) return(invisible(NULL)) } msg <- lifecycle_build_message(when, what, with, details, "deprecate_warn") signal(msg, "lifecycle_soft_deprecated") } # TRUE if we are in unit tests and the package being tested is the # same as the package that called from_testthat <- function(env) { tested_package <- Sys.getenv("TESTTHAT_PKG") # Test for environment names rather than reference/contents because # testthat clones the namespace nzchar(tested_package) && identical(Sys.getenv("NOT_CRAN"), "true") && env_name(topenv(env)) == env_name(ns_env(tested_package)) } #' @rdname deprecate_soft #' @export deprecate_warn <- function(when, what, with = NULL, details = NULL, id = NULL, env = caller_env(2)) { msg <- lifecycle_build_message(when, what, with, details, "deprecate_warn") verbosity <- lifecycle_verbosity() id <- id %||% msg stopifnot(is_string(id)) if (verbosity == "quiet") { return(invisible(NULL)) } if (verbosity == "default" && env_has(deprecation_env, id) && !from_testthat(env)) { return(invisible(NULL)) } env_poke(deprecation_env, id, TRUE); if (verbosity == "error") { deprecate_stop(when, what, with = with, details = details) } else { if (verbosity == "default") { msg <- paste_line( msg, silver("This warning is displayed once per session."), silver("Call `lifecycle::last_warnings()` to see where this warning was generated.") ) } trace <- trace_back(bottom = caller_env()) wrn <- new_deprecated_warning(msg, trace) # Record muffled warnings if testthat is running because it # muffles all warnings but we still want to examine them after a # run of `devtools::test()` maybe_push_warning <- function() { if (Sys.getenv("TESTTHAT_PKG") != "") { push_warning(wrn) } } withRestarts(muffleWarning = maybe_push_warning, { signalCondition(wrn) push_warning(wrn) warning(wrn) }) } } #' @rdname deprecate_soft #' @export deprecate_stop <- function(when, what, with = NULL, details = NULL) { msg <- lifecycle_build_message(when, what, with, details, "deprecate_stop") stop(cnd( c("lifecycle_error_deprecated", "defunctError", "error", "condition"), old = NULL, new = NULL, package = NULL, message = msg )) } env_inherits_global <- function(env) { # `topenv(emptyenv())` returns the global env. Return `FALSE` in # that case to allow passing the empty env when the # soft-deprecation should not be promoted to deprecation based on # the caller environment. if (is_reference(env, empty_env())) { return(FALSE) } is_reference(topenv(env), global_env()) } lifecycle_validate_message <- function(msg) { stopifnot(is_character(msg)) paste0(msg, collapse = "\n") } lifecycle_build_message <- function(when, what, with = NULL, details = chr(), signaller) { details <- details %||% chr() stopifnot( is_string(when), is_string(what), is_null(with) || is_string(with), is_character(details) ) what <- signal_validate_what(what, "what", signaller) fn <- signal_validate_fn(what$call) arg <- signal_validate_arg(what$call, signaller) if (is_null(what$pkg)) { env <- topenv(caller_env(2)) pkg <- signal_validate_pkg(env) } else { pkg <- what$pkg } if (is_null(arg)) { msg <- glue::glue("`{ fn }()` is deprecated as of { pkg } { when }.") } else { msg <- glue::glue("The `{ arg }` argument of `{ fn }()` is deprecated as of { pkg } { when }.") } if (!is_null(with)) { with <- signal_validate_what(with, "with", signaller) with_fn <- signal_validate_fn(with$call) with_arg <- signal_validate_arg(with$call, signaller) with_pkg <- with$pkg %||% pkg if (!is_null(with_pkg) && pkg != with_pkg) { with_fn <- glue::glue("{ with_pkg }::{ with_fn }") } if (is_null(with_arg)) { please <- glue::glue("Please use `{ with_fn }()` instead.") } else if (fn == with_fn) { please <- glue::glue("Please use the `{ with_arg }` argument instead.") } else { please <- glue::glue("Please use the `{ with_arg }` argument of `{ with_fn }()` instead.") } msg <- paste0(msg, "\n", please) } paste_line(msg, details) } signal_validate_what <- function(what, arg, signaller) { call <- parse_expr(what) if (!is_call(call)) { abort(glue::glue( " Internal error: `what` must have function call syntax. # Good: { signaller }({ what } = \"myfunction()\") # Bad: { signaller }({ what } = \"myfunction\") " )) } head <- node_car(call) if (is_call(head, "::")) { pkg <- as_string(node_cadr(head)) call[[1]] <- node_cadr(node_cdr(head)) } else { pkg <- NULL } list(pkg = pkg, call = call) } signal_validate_fn <- function(call) { fn <- node_car(call) if (!is_symbol(fn)) { abort("Internal error: `what` must refer to a function name.") } # Deparse so non-syntactic names are backticked expr_deparse(fn) } signal_validate_arg <- function(call, signaller) { arg <- node_cdr(call) if (is_null(arg)) { return(NULL) } if (length(arg) != 1L) { abort("Internal error: `what` can't refer to more than one argument.") } if (is_null(node_tag(arg)) || !is_missing(node_car(arg))) { abort(glue::glue( " Internal error: `what` must refer to arguments in the LHS of `=`. # Good: { signaller }(what = \"myfunction(arg = )\") # Bad: { signaller }(what = \"myfunction(arg)\") " )) } as_string(node_tag(arg)) } signal_validate_pkg <- function(env) { if (is_reference(env, global_env())) { # Convenient for experimenting interactively return("") } if(is_namespace(env)) { return(ns_env_name(env)) } abort(glue::glue( " Internal error: Can't detect the package of the deprecated function. Please mention the namespace: # Good: { signaller }(what = \"namespace::myfunction()\") # Bad: { signaller }(what = \"myfunction()\") " )) } lifecycle/R/arg.R0000644000176200001440000000243613515611465013322 0ustar liggesusers#' Mark an argument as deprecated #' #' Signal deprecated argument by using self-documenting sentinel #' `deprecated()` as default argument. It returns #' [rlang::missing_arg()], so you can test whether the user supplied #' the argument with [rlang::is_missing()] (see examples). #' #' @section Magical defaults: #' #' We recommend importing `lifecycle::deprecated()` in your namespace #' and use it without the namespace qualifier. #' #' In general, we [advise #' against](https://principles.tidyverse.org/def-magical.html) such #' magical defaults, i.e. defaults that cannot be evaluated by the #' user. In the case of `deprecated()`, the trade-off is worth it #' because the meaning of this default is obvious and there is no #' reason for the user to call `deprecated()` themselves. #' #' @examples #' foobar_adder <- function(foo, bar, baz = deprecated()) { #' # Check if user has supplied `baz` instead of `bar` #' if (!rlang::is_missing(baz)) { #' #' # Signal the deprecation to the user #' deprecate_warn("1.0.0", "foo::bar_adder(baz = )", "foo::bar_adder(bar = )") #' #' # Deal with the deprecated argument for compatibility #' bar <- baz #' } #' #' foo + bar #' } #' #' foobar_adder(1, 2) #' foobar_adder(1, baz = 2) #' #' @export deprecated <- function() { missing_arg() } lifecycle/R/verbosity.R0000644000176200001440000000400613515611214014562 0ustar liggesusers#' Control the verbosity of deprecation signals #' #' @description #' #' There are 3 levels of verbosity for deprecated functions: silence, #' warning, and error. Since the lifecycle package avoids disruptive #' warnings, the default level of verbosity depends on the lifecycle #' stage of the deprecated function, on the context of the caller #' (global environment or testthat unit tests cause more warnings), #' and whether the warning was already issued (see the help for #' [deprecation functions][deprecate_soft]). #' #' You can control the level of verbosity with the global option #' `lifecycle_verbosity`. It can be set to: #' #' * `"default"` or `NULL` for the default non-disruptive settings. #' #' * `"quiet"`, `"warning"` or `"error"` to force silence, warnings or #' errors for deprecated functions. #' #' Note that functions calling [deprecate_stop()] invariably throw #' errors. #' #' @examples #' if (rlang::is_installed("testthat")) { #' library(testthat) #' #' mytool <- function() { #' deprecate_soft("1.0.0", "mytool()") #' 10 * 10 #' } #' #' # Forcing the verbosity level is useful for unit testing. You can #' # force errors to test that the function is indeed deprecated: #' test_that("mytool is deprecated", { #' rlang::with_options(lifecycle_verbosity = "error", { #' expect_error(mytool(), class = "defunctError") #' }) #' }) #' #' # Or you can enforce silence to safely test that the function #' # still works: #' test_that("mytool still works", { #' rlang::with_options(lifecycle_verbosity = "quiet", { #' expect_equal(mytool(), 100) #' }) #' }) #' } #' #' @name verbosity NULL lifecycle_verbosity <- function() { opt <- peek_option("lifecycle_verbosity") %||% "default" if (!is_string(opt, c("quiet", "default", "warning", "error"))) { options(lifecycle_verbosity = "default") abort(glue::glue( " The `lifecycle_verbosity` option must be set to one of: \"quiet\", \"default\", \"warning\", or \"error\". " )) } opt } lifecycle/R/warning.R0000644000176200001440000000504313515626536014220 0ustar liggesusers#' Display last deprecation warnings #' #' @description #' #' Call these helpers to see the last deprecation warnings along with #' their backtrace: #' #' * `last_warnings()` returns a list of all warnings that occurred #' during the last top-level R command. #' #' * `last_warning()` returns only the last. #' #' If you call these in the console, these warnings are printed with a #' backtrace. Pass the `simplify` argument to control the verbosity of #' the backtrace. It supports one of `"branch"` (the default), #' `"collapse"`, and `"none"` (in increasing order of verbosity). #' #' @examples #' # These examples are not run because `last_warnings()` does not #' # work well within knitr and pkgdown #' \dontrun{ #' #' f <- function() invisible(g()) #' g <- function() list(h(), i()) #' h <- function() deprecate_warn("1.0.0", "this()") #' i <- function() deprecate_warn("1.0.0", "that()") #' f() #' #' # Print all the warnings that occurred during the last command: #' last_warnings() #' #' # Print only the last one: #' last_warning() #' #' #' # By default, the backtraces are printed in their simplified form. #' # Use `simplify` to control the verbosity: #' print(last_warnings(), simplify = "none") #' #' } #' @export last_warnings <- function() { warnings_env$warnings } #' @rdname last_warnings #' @export last_warning <- function() { n <- length(warnings_env$warnings) if (n) { warnings_env$warnings[[n]] } else { NULL } } new_deprecated_warning <- function(msg, trace) { warning_cnd( "lifecycle_warning_deprecated", message = msg, trace = trace ) } #' @export print.lifecycle_warning_deprecated <- function(x, ..., simplify = c("branch", "collapse", "none")) { cat_line(bold("")) message <- x$message if (is_string(message) && nzchar(message)) { cat_line(sprintf("message: %s", italic(message))) } trace <- x$trace if (!is_null(trace)) { cat_line("backtrace:") cat_line(red(format(trace, ..., simplify = simplify))) } invisible(x) } warnings_env <- env(empty_env()) init_warnings <- function() { warnings_env$last_top_frame <- NULL warnings_env$warnings <- list() } init_warnings() push_warning <- function(wrn) { current <- sexp_address(sys.frame(1)) if (identical(warnings_env$last_top_frame, current)) { warnings_env$warnings <- c(warnings_env$warnings, list(wrn)) } else { warnings_env$last_top_frame <- current warnings_env$warnings <- list(wrn) } } # Contains unique IDs of deprecated features so we don't warn multiple times deprecation_env <- env(empty_env()) lifecycle/NEWS.md0000644000176200001440000000166613516014532013320 0ustar liggesusers # lifecycle 0.1.0 * Deprecated functions under the control of the developer now warn repeatedly in unit tests. * Deprecation warnings now record a backtrace. Call `lifecycle::last_warnings()` and `lifecycle::last_warning()` to print the warnings that occurred during the last command, along with their backtraces. * The naming scheme of signaller functions has been simplified: - `signal_soft_deprecated()` is now `deprecate_soft()`. - `warn_deprecated()` is now `deprecate_warn()`. - `stop_defunct()` is now `deprecate_stop()`. * The signaller functions now take a version and two descriptors for the deprecated feature and its replacement (the latter is optional). The deprecation message is built from these components. You can pass a `details` argument to append additional information to the generated deprecation message. * Helpers from rlang's `compat-lifecycle.R` drop-in file are now exported in this package. lifecycle/MD50000644000176200001440000000647013520557775012550 0ustar liggesusers4b097c399d36bc5eda89f6bde1c3f249 *DESCRIPTION 856f9de5f3891c08ec3f1b962a24063d *NAMESPACE 2f96b858c59aa90bb0ad6c07afb04334 *NEWS.md 0a0118c5f4862d02ec3b2375053f3882 *R/arg.R dc76d7eeeddaf8a5c28bd154ddbad28a *R/badge.R 058261e2473844f66d9cad04a0b2320e *R/lifecycle-package.R 8f74f094edad8f1c1bdbff7307ce2449 *R/signal.R 146fe9ccd8556e8b55c450a45eaa5f2d *R/utils.R 53e767fc6175e30947e9843509beda9a *R/verbosity.R 5c7388dddc1e394a87d3c537991a7e6d *R/warning.R c994c604f2c640c7614e65059fa0bee0 *README.md f85c5a7416079f543307284b43ab73ea *build/lifecycle.pdf eaa3023e06b0691baeebecee612e9bc7 *build/vignette.rds 6d160114335ac8a1b4dda72c9f1a433e *inst/doc/lifecycle.R 4d78ebd68db57cbcd7084c76ee09892a *inst/doc/lifecycle.Rmd 81a17deb1288234ee13ad5481cc80711 *inst/doc/lifecycle.html d7730abd51d6727f6e588d1f1107979f *man/badge.Rd 9bc8c47855625adeea1b3c6a0806f3b4 *man/deprecate_soft.Rd 44565efeeb8f5b62b0a2942c32a02335 *man/deprecated.Rd cb1e46f469cfbbbde29c8b5113e1d789 *man/figures/lifecycle-archived.svg c0d2e5a54f1fa4ff02bf9533079dd1f7 *man/figures/lifecycle-defunct.svg a1b8c987c676c16af790f563f96cbb1f *man/figures/lifecycle-deprecated.svg c3978703d8f40f2679795335715e98f4 *man/figures/lifecycle-experimental.svg 952b59dc07b171b97d5d982924244f61 *man/figures/lifecycle-maturing.svg 27b879bf3677ea76e3991d56ab324081 *man/figures/lifecycle-questioning.svg 46de21252239c5a23d400eae83ec6b2d *man/figures/lifecycle-retired.svg 6902bbfaf963fbc4ed98b86bda80caa2 *man/figures/lifecycle-soft-deprecated.svg 53b3f893324260b737b3c46ed2a0e643 *man/figures/lifecycle-stable.svg 5939f6c264cd5734e176c739b9a0039d *man/last_warnings.Rd 95cd9ef083c9a36c09497cd41f746159 *man/lifecycle-package.Rd 155bedac3338ac2404018d81751c5b18 *man/macros/lifecycle.Rd 4f170b39904f2bd532010064fc7d1761 *man/verbosity.Rd ed81c7165f2a80934e2a76d4262b843a *tests/testthat.R 4b19a0bb17bd3c8fcda02903d6927cbf *tests/testthat/helper-lifecycle.R dcb2f62a473c00e11f027c178cdeb576 *tests/testthat/output/test-signal-message-args.txt 11746c8e61c7cc36dcf3856d32c918bf *tests/testthat/output/test-signal-message-non-syntactic.txt b81647e3e018672d509b2c7385d24672 *tests/testthat/output/test-signal-message.txt da2ec4773ddcd3d3007a799c334fe7cc *tests/testthat/output/test-warning-backtrace.txt b7ea0d3ac4150d7540045a9624db7c2f *tests/testthat/test-arg.R cfb96aa83a05bf46faf6d2f7eb51a3fb *tests/testthat/test-lifecycle.R 2a10c007db323d0f99b74446669abe35 *tests/testthat/test-signal.R 899f5616f04705985fab641e8e878267 *tests/testthat/test-verbosity.R f370662de24887a7b9e73f8c376dd90d *tests/testthat/test-warning.R d69e6099d540152a9c6f9ffde982c0e4 *vignettes/figures/example-badge.png cb1e46f469cfbbbde29c8b5113e1d789 *vignettes/figures/lifecycle-archived.svg c0d2e5a54f1fa4ff02bf9533079dd1f7 *vignettes/figures/lifecycle-defunct.svg a1b8c987c676c16af790f563f96cbb1f *vignettes/figures/lifecycle-deprecated.svg c3978703d8f40f2679795335715e98f4 *vignettes/figures/lifecycle-experimental.svg 952b59dc07b171b97d5d982924244f61 *vignettes/figures/lifecycle-maturing.svg 27b879bf3677ea76e3991d56ab324081 *vignettes/figures/lifecycle-questioning.svg 46de21252239c5a23d400eae83ec6b2d *vignettes/figures/lifecycle-retired.svg 6902bbfaf963fbc4ed98b86bda80caa2 *vignettes/figures/lifecycle-soft-deprecated.svg 53b3f893324260b737b3c46ed2a0e643 *vignettes/figures/lifecycle-stable.svg 4d78ebd68db57cbcd7084c76ee09892a *vignettes/lifecycle.Rmd lifecycle/inst/0000755000176200001440000000000013516776442013205 5ustar liggesuserslifecycle/inst/doc/0000755000176200001440000000000013516776442013752 5ustar liggesuserslifecycle/inst/doc/lifecycle.R0000644000176200001440000000507213516776441016037 0ustar liggesusers## ---- include = FALSE---------------------------------------------------- knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ## ----setup--------------------------------------------------------------- library(lifecycle) ## ------------------------------------------------------------------------ deprecate_warn("1.0.0", "mypkg::foo()") ## ------------------------------------------------------------------------ deprecate_warn("1.0.0", "mypkg::foo()", "new()") ## ------------------------------------------------------------------------ # The new replacement foobar_adder <- function(foo, bar) { foo + bar } # The old function still exported for compatibility foobaz_adder <- function(foo, bar) { deprecate_warn("1.0.0", "foobaz_adder()", "foobar_adder()") foobar_adder(foo, bar) } ## ------------------------------------------------------------------------ deprecate_warn("1.0.0", "mypkg::foo(arg = )") deprecate_warn("1.0.0", "mypkg::foo(arg = )", "mypkg::foo(new = )") ## ------------------------------------------------------------------------ foobar_adder <- function(foo, bar, baz = deprecated()) { # Check if user has supplied `baz` instead of `bar` if (!rlang::is_missing(baz)) { # Signal the deprecation to the user deprecate_warn("1.0.0", "foobar_adder(baz = )", "foobar_adder(bar = )") # Deal with the deprecated argument for compatibility bar <- baz } foo + bar } ## ---- eval = FALSE------------------------------------------------------- # library(testthat) # library(mypackage) # # options(lifecycle_verbosity = "error") # test_check("mypackage") ## ---- eval = FALSE------------------------------------------------------- # # Force silence # options(lifecycle_verbosity = "quiet") # # # Force warnings # options(lifecycle_verbosity = "warning") # # # Force errors # options(lifecycle_verbosity = "error") ## ---- eval = FALSE------------------------------------------------------- # test_that("`baz` argument of `foobar_adder()` still works", { # withr::local_options(list(lifecycle_verbosity = "quiet")) # foobar_adder(1, baz = 2) # }) ## ---- eval = FALSE------------------------------------------------------- # test_that("`baz` argument of `foobar_adder()` is deprecated", { # withr::local_options(list(lifecycle_verbosity = "warning")) # expect_warning(foobar_adder(1, baz = 2), class = "lifecycle_warning_deprecated") # }) ## ---- eval = FALSE------------------------------------------------------- # test_that("`foo()` is defunct", { # expect_error(foo(), class = "lifecycle_error_deprecated") # }) lifecycle/inst/doc/lifecycle.Rmd0000644000176200001440000002277713516020753016357 0ustar liggesusers--- title: "Usage of the lifecycle package" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{lifecycle} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ``` ```{r setup} library(lifecycle) ``` Use lifecycle to document the status of your exported functions and arguments: * Choose one of the 7 lifecycle stages a function or argument can be in. You can choose from 4 development stages (experimental, maturing, stable, and questining) and 3 deprecation stages (soft-deprecated, deprecated, and defunct). * If the function or argument is deprecated, make sure your users know about by calling `deprecate_soft()`, `deprecate_warn()`, or `deprecate_stop()`. These functions try to be informative without being too verbose, with increasing levels of verbosity as the deprecation stage advances. * Include the relevant lifecycle badge in your documentation. ### Stages The lifecycle stages for functions and arguments closely mirror the [lifecycle stages for packages](https://www.tidyverse.org/lifecycle/). There are 4 __development__ stages. 1. Experimental This is a new feature that is in the very early stage of development. It is exported so users can start to use it and report feedback, but its interface and/or behaviour is likely to change in the future. It is generally best to avoid depending on experimental features. 1. Maturing The interface and behaviour of a maturing feature has been roughed out, but finer details are likely to change. It still needs more feedback to find the optimal API. 1. Stable A feature is considered stable when the author is happy with its interface and behaviour. Major changes are unlikely, and breaking changes will occur gradually, through a deprecation process. 1. Questioning The author is no longer convinced that the feature is the optimal approach. However, there are no recommended alternatives yet. Once the decision of discontinuing a feature has been made, it goes through 3 __deprecation__ stages. 1. Soft deprecated The author is no longer happy with a feature because they consider it sub-optimal compared to some other approach, or simply because they no longer have the time to maintain it. A soft-deprecated feature can still be used without hassle, but users should consider switching to an alternative approach. 1. Deprecated The feature is likely to be discontinued in the next major release. Users should switch to an alternative approach as soon as possible. 1. Defunct The feature can no longer be used. A defunct function is still exported, and a defunct argument is still part of the signature. This way an informative error can be thrown. Finally, when a feature is no longer exposed or mentioned in the released version of the package, it is said to be __archived__. ### Badges {#rd-badges} Make sure your users know what stage a feature is by adding badges in the help topics of your functions. badge * Call `usethis::use_lifecycle()` to import the badges in your package. * Use the `lifecycle` Rd macro to insert a badge: ``` #' \lifecycle{experimental} #' \lifecycle{soft-deprecated} ``` This badge renders as text in non-HTML documentation. To document the status of a whole function, a good place to include the badge is at the top of the `@description` block. To document an argument, you can put the badge in the argument description. * For functions in development, you typically don't need to advertise the status if it is the same as the package as a whole. For instance, if your package is [maturing](https://www.tidyverse.org/lifecycle/#maturing), only signal functions in the experimental, stable, and questioning stages. ### Verbosity of deprecation lifecycle offers three levels of verbosity corresponding to the three deprecation stages. * __Soft deprecation__: At this stage, call `deprecate_soft()` to start warning users about the deprecation in the least disruptive way. This function only warns (a) users who try the feature from the global workspace, and (b) developers who directly use the feature, when they run unit tests with testthat. No warning is issued outside of unit tests, or when the deprecated feature is called from another package then ther own. When a warning does get issued, users only see it once per session rather than at each invokation. * __Deprecation__: At this stage, call `deprecate_warn()` to warn unconditionally about the deprecated feature. The warning is issued only once per session. * __Defunct__: The feature is discontinued. Call `deprecate_stop()` to fail with an error. ### Deprecating functions These functions take the version number starting from which the feature is considered deprecated (it should remain the same across all deprecation stages), and a feature descriptor: ```{r} deprecate_warn("1.0.0", "mypkg::foo()") ``` You can optionally provide a replacement: ```{r} deprecate_warn("1.0.0", "mypkg::foo()", "new()") ``` For the purpose of these examples we explicitly mentioned the namespace with `mypkg::`, however you can typically omit it because lifecycle infers the namespace from the calling environment. Specifying the namespace is mostly useful when the replacement is implemented in a different package. ```{r} # The new replacement foobar_adder <- function(foo, bar) { foo + bar } # The old function still exported for compatibility foobaz_adder <- function(foo, bar) { deprecate_warn("1.0.0", "foobaz_adder()", "foobar_adder()") foobar_adder(foo, bar) } ``` ### Deprecating arguments The syntax for deprecating argument is based on the syntax for deprecating functions: ```{r} deprecate_warn("1.0.0", "mypkg::foo(arg = )") deprecate_warn("1.0.0", "mypkg::foo(arg = )", "mypkg::foo(new = )") ``` lifecycle also provides the `deprecated()` sentinel to use as default argument. This provides self-documentation for your users, and makes it possible for external tools to determine which arguments are deprecated. This sentinel is simply the missing argument, so you can test whether the argument was supplied with `rlang::is_missing()`: ```{r} foobar_adder <- function(foo, bar, baz = deprecated()) { # Check if user has supplied `baz` instead of `bar` if (!rlang::is_missing(baz)) { # Signal the deprecation to the user deprecate_warn("1.0.0", "foobar_adder(baz = )", "foobar_adder(bar = )") # Deal with the deprecated argument for compatibility bar <- baz } foo + bar } ``` ### Workflow #### Where do these deprecation warnings come from? Call `lifecycle::last_warnings()` to see backtraces for all the deprecation warnings that were issued during the last top-level command. #### Bumping deprecation stage Some manual search and replace is needed to bump the status of deprecated features. We recommend starting with defunct features and work your way up: 1. Search for `deprecate_stop()` and remove the feature from the package. The feature is now archived. 1. Search for `deprecate_warn()` and replace with `deprecate_stop()`. 1. Search for `deprecate_soft()` and replace with `deprecate_warn()`. 1. Call `deprecate_soft()` from newly deprecated functions. Don't forget to update the badges in the documentation topics. #### Find out what deprecated features you rely on Test whether your package depends on deprecated features directly or indirectly by setting the verbosity option in the `tests/testthat.R` file just before `test_check()` is called: ```{r, eval = FALSE} library(testthat) library(mypackage) options(lifecycle_verbosity = "error") test_check("mypackage") ``` This forces all deprecated features to fail. You can also set the relevant options manually to force warnings or errors in your session: ```{r, eval = FALSE} # Force silence options(lifecycle_verbosity = "quiet") # Force warnings options(lifecycle_verbosity = "warning") # Force errors options(lifecycle_verbosity = "error") ``` Forcing warnings can be useful in conjuction with `last_warnings()`, which prints backtraces for all the deprecation warnings issued during the last top-level command. #### Test deprecated features Test whether a deprecated feature still works by disabling the warnings with `scoped_lifecycle_silence()`: ```{r, eval = FALSE} test_that("`baz` argument of `foobar_adder()` still works", { withr::local_options(list(lifecycle_verbosity = "quiet")) foobar_adder(1, baz = 2) }) ``` Test that a feature is correctly deprecated by forcing warnings and checking the class `"lifecycle_warning_deprecated"`: ```{r, eval = FALSE} test_that("`baz` argument of `foobar_adder()` is deprecated", { withr::local_options(list(lifecycle_verbosity = "warning")) expect_warning(foobar_adder(1, baz = 2), class = "lifecycle_warning_deprecated") }) ``` Defunct features throw errors of class `"lifecycle_error_deprecated"`: ```{r, eval = FALSE} test_that("`foo()` is defunct", { expect_error(foo(), class = "lifecycle_error_deprecated") }) ``` lifecycle/inst/doc/lifecycle.html0000644000176200001440000015021713516776442016605 0ustar liggesusers Usage of the lifecycle package

Usage of the lifecycle package

Use lifecycle to document the status of your exported functions and arguments:

  • Choose one of the 7 lifecycle stages a function or argument can be in. You can choose from 4 development stages (experimental, maturing, stable, and questining) and 3 deprecation stages (soft-deprecated, deprecated, and defunct).

  • If the function or argument is deprecated, make sure your users know about by calling deprecate_soft(), deprecate_warn(), or deprecate_stop(). These functions try to be informative without being too verbose, with increasing levels of verbosity as the deprecation stage advances.

  • Include the relevant lifecycle badge in your documentation.

Stages

The lifecycle stages for functions and arguments closely mirror the lifecycle stages for packages.

There are 4 development stages.

  1. Experimental This is a new feature that is in the very early stage of development. It is exported so users can start to use it and report feedback, but its interface and/or behaviour is likely to change in the future. It is generally best to avoid depending on experimental features.

  2. Maturing The interface and behaviour of a maturing feature has been roughed out, but finer details are likely to change. It still needs more feedback to find the optimal API.

  3. Stable A feature is considered stable when the author is happy with its interface and behaviour. Major changes are unlikely, and breaking changes will occur gradually, through a deprecation process.

  4. Questioning The author is no longer convinced that the feature is the optimal approach. However, there are no recommended alternatives yet.

Once the decision of discontinuing a feature has been made, it goes through 3 deprecation stages.

  1. Soft deprecated The author is no longer happy with a feature because they consider it sub-optimal compared to some other approach, or simply because they no longer have the time to maintain it. A soft-deprecated feature can still be used without hassle, but users should consider switching to an alternative approach.

  2. Deprecated The feature is likely to be discontinued in the next major release. Users should switch to an alternative approach as soon as possible.

  3. Defunct The feature can no longer be used. A defunct function is still exported, and a defunct argument is still part of the signature. This way an informative error can be thrown.

Finally, when a feature is no longer exposed or mentioned in the released version of the package, it is said to be archived.

Badges

Make sure your users know what stage a feature is by adding badges in the help topics of your functions.

badge

  • Call usethis::use_lifecycle() to import the badges in your package.

  • Use the lifecycle Rd macro to insert a badge:

    #' \lifecycle{experimental}
    #' \lifecycle{soft-deprecated}

    This badge renders as text in non-HTML documentation. To document the status of a whole function, a good place to include the badge is at the top of the @description block. To document an argument, you can put the badge in the argument description.

  • For functions in development, you typically don’t need to advertise the status if it is the same as the package as a whole. For instance, if your package is maturing, only signal functions in the experimental, stable, and questioning stages.

Verbosity of deprecation

lifecycle offers three levels of verbosity corresponding to the three deprecation stages.

  • Soft deprecation: At this stage, call deprecate_soft() to start warning users about the deprecation in the least disruptive way.

    This function only warns (a) users who try the feature from the global workspace, and (b) developers who directly use the feature, when they run unit tests with testthat. No warning is issued outside of unit tests, or when the deprecated feature is called from another package then ther own.

    When a warning does get issued, users only see it once per session rather than at each invokation.

  • Deprecation: At this stage, call deprecate_warn() to warn unconditionally about the deprecated feature. The warning is issued only once per session.

  • Defunct: The feature is discontinued. Call deprecate_stop() to fail with an error.

Deprecating functions

These functions take the version number starting from which the feature is considered deprecated (it should remain the same across all deprecation stages), and a feature descriptor:

You can optionally provide a replacement:

For the purpose of these examples we explicitly mentioned the namespace with mypkg::, however you can typically omit it because lifecycle infers the namespace from the calling environment. Specifying the namespace is mostly useful when the replacement is implemented in a different package.

Workflow

Where do these deprecation warnings come from?

Call lifecycle::last_warnings() to see backtraces for all the deprecation warnings that were issued during the last top-level command.

Bumping deprecation stage

Some manual search and replace is needed to bump the status of deprecated features. We recommend starting with defunct features and work your way up:

  1. Search for deprecate_stop() and remove the feature from the package. The feature is now archived.

  2. Search for deprecate_warn() and replace with deprecate_stop().

  3. Search for deprecate_soft() and replace with deprecate_warn().

  4. Call deprecate_soft() from newly deprecated functions.

Don’t forget to update the badges in the documentation topics.

Find out what deprecated features you rely on

Test whether your package depends on deprecated features directly or indirectly by setting the verbosity option in the tests/testthat.R file just before test_check() is called:

This forces all deprecated features to fail. You can also set the relevant options manually to force warnings or errors in your session:

Forcing warnings can be useful in conjuction with last_warnings(), which prints backtraces for all the deprecation warnings issued during the last top-level command.

Test deprecated features

Test whether a deprecated feature still works by disabling the warnings with scoped_lifecycle_silence():

Test that a feature is correctly deprecated by forcing warnings and checking the class "lifecycle_warning_deprecated":

Defunct features throw errors of class "lifecycle_error_deprecated":