statnet.common/0000755000176200001440000000000014433433333013226 5ustar liggesusersstatnet.common/NAMESPACE0000644000176200001440000000721714427313311014450 0ustar liggesusers# Generated by roxygen2: do not edit by hand S3method("$",control.list) S3method("[",term_list) S3method("[",wmatrix) S3method("[<-",wmatrix) S3method("lrowweights<-",linwmatrix) S3method("lrowweights<-",logwmatrix) S3method("lrowweights<-",matrix) S3method("rowweights<-",linwmatrix) S3method("rowweights<-",logwmatrix) S3method("rowweights<-",matrix) S3method(as.control.list,control.list) S3method(as.control.list,list) S3method(as.linwmatrix,linwmatrix) S3method(as.linwmatrix,logwmatrix) S3method(as.linwmatrix,matrix) S3method(as.logwmatrix,linwmatrix) S3method(as.logwmatrix,logwmatrix) S3method(as.logwmatrix,matrix) S3method(as.term_list,default) S3method(as.term_list,term_list) S3method(c,term_list) S3method(compress_rows,data.frame) S3method(compress_rows,linwmatrix) S3method(compress_rows,logwmatrix) S3method(decompress_rows,compressed_rows_df) S3method(decompress_rows,wmatrix) S3method(diff,control.list) S3method(lrowweights,linwmatrix) S3method(lrowweights,logwmatrix) S3method(order,data.frame) S3method(order,default) S3method(order,matrix) S3method(print,control.list) S3method(print,diff.control.list) S3method(print,linwmatrix) S3method(print,logwmatrix) S3method(print,term_list) S3method(print,wmatrix) S3method(rowweights,linwmatrix) S3method(rowweights,logwmatrix) S3method(sort,data.frame) S3method(split,array) S3method(split,matrix) S3method(trim_env,default) S3method(trim_env,environment) S3method(update,Welford) export("EVL<-") export("NVL<-") export("lrowweights<-") export("rowweights<-") export("ult<-") export(.Deprecate_method) export(.Deprecate_once) export(COLLATE_ALL_MY_CONTROLS_EXPR) export(ERRVL) export(EVL) export(EVL2) export(EVL3) export(NVL) export(NVL2) export(NVL3) export(UPDATE_MY_SCTRL_EXPR) export(Welford) export(all_identical) export(append.rhs.formula) export(append_rhs.formula) export(as.control.list) export(as.linwmatrix) export(as.logwmatrix) export(as.term_list) export(attr) export(base_env) export(check.control.class) export(colMeans.mcmc.list) export(collate_controls) export(compress_rows) export(control.remap) export(deInf) export(decompress_rows) export(default_options) export(despace) export(empty_env) export(eval_lhs.formula) export(filter_rhs.formula) export(fixed.pval) export(forkTimeout) export(handle.controls) export(is.SPD) export(is.linwmatrix) export(is.logwmatrix) export(is.wmatrix) export(lapply.mcmc.list) export(linwmatrix) export(list_rhs.formula) export(list_summands.call) export(locate_function) export(locate_prefixed_function) export(log_mean_exp) export(log_sum_exp) export(logwmatrix) export(lrowweights) export(lweighted.cov) export(lweighted.mean) export(lweighted.var) export(message_print) export(nonsimp.update.formula) export(nonsimp_update.formula) export(once) export(opttest) export(order) export(paste.and) export(persistEval) export(persistEvalQ) export(rowweights) export(sandwich_solve) export(sandwich_ssolve) export(set.control.class) export(sginv) export(simplify_simple) export(snctrl) export(snctrl_names) export(snearPD) export(srcond) export(ssolve) export(statnet.cite.foot) export(statnet.cite.head) export(statnet.cite.pkg) export(statnetStartupMessage) export(sweep.mcmc.list) export(sweep_cols.matrix) export(term.list.formula) export(term_list) export(trim_env) export(ult) export(unused_dots_warning) export(unwhich) export(update_snctrl) export(vector.namesmatch) export(xAxT) export(xTAx) export(xTAx_qrsolve) export(xTAx_qrssolve) export(xTAx_solve) export(xTAx_ssolve) importFrom(coda,as.mcmc) importFrom(coda,as.mcmc.list) importFrom(methods,is) importFrom(stats,as.formula) importFrom(utils,capture.output) importFrom(utils,getAnywhere) importFrom(utils,modifyList) useDynLib(statnet.common) statnet.common/LICENSE0000644000176200001440000000311314364112224014225 0ustar liggesusers-------------------------------------------------- License for the 'statnet' component package 'statnet.common' -------------------------------------------------- This software is distributed under the GPL-3 license. It is free, open source, and has the following attribution requirements (GPL Section 7): (a) you agree to retain in 'statnet.common' and any modifications to 'statnet.common' the copyright, author attribution and URL information as provided at http://statnet.org/attribution (b) you agree that 'statnet.common' and any modifications to 'statnet.common' will, when used, display the attribution: Based on 'statnet' project software (http://statnet.org). For license and citation information see http://statnet.org/attribution -------------------------------------------------- What does this mean? ==================== If you are modifying 'statnet.common' or adopting any source code from 'statnet.common' for use in another application, you must ensure that the copyright and attributions mentioned in the license above appear in the code of your modified version or application. These attributions must also appear when the package is loaded (e.g., via 'library' or 'require'). Enjoy! Mark S. Handcock, University of California - Los Angeles David R. Hunter, Penn State University Carter T. Butts, University of California - Irvine Steven M. Goodreau, University of Washington Pavel N. Krivitsky, University of New South Wales Michał Bojanowski, Kozminski University Martina Morris, University of Washington The 'statnet' development team Copyright 2007-2023 statnet.common/man/0000755000176200001440000000000014427313310013774 5ustar liggesusersstatnet.common/man/vector.namesmatch.Rd0000644000176200001440000000212613416034725017714 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/misc.utilities.R \name{vector.namesmatch} \alias{vector.namesmatch} \title{reorder vector v into order determined by matching the names of its elements to a vector of names} \usage{ vector.namesmatch(v, names, errname = NULL) } \arguments{ \item{v}{a vector (or list) with named elements, to be reorderd} \item{names}{a character vector of element names, corresponding to names of \code{v}, specificying desired orering of \code{v}} \item{errname}{optional, name to be reported in any error messages. default to \code{deparse(substitute(v))}} } \value{ returns \code{v}, with elements reordered } \description{ A helper function to reorder vector \code{v} (if named) into order specified by matching its names to the argument \code{names} } \details{ does some checking of appropriateness of arguments, and reorders v by matching its names to character vector \code{names} } \note{ earlier versions of this function did not order as advertiased } \examples{ test<-list(c=1,b=2,a=3) vector.namesmatch(test,names=c('a','c','b')) } statnet.common/man/handle.controls.Rd0000644000176200001440000000324214050632700017360 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/control.utilities.R \name{handle.controls} \alias{handle.controls} \title{Handle standard \verb{control.*()} function semantics.} \usage{ handle.controls(myname, ...) } \arguments{ \item{myname}{the name of the calling function.} \item{...}{the \code{...} argument of the control function, if present.} } \value{ a list with formal arguments of the calling function. } \description{ This function takes the arguments of its caller (whose name should be passed explicitly), plus any \code{...} arguments and produces a control list based on the standard semantics of \verb{control.*()} functions, including handling deprecated arguments, identifying undefined arguments, and handling arguments that should be passed through \code{\link[=match.arg]{match.arg()}}. } \details{ The function behaves based on the information it acquires from the calling function. Specifically, \itemize{ \item The values of formal arguments (except \code{...}, if present) are taken from the environment of the calling function and stored in the list. \item If the calling function has a \code{...} argument \emph{and} defines an \code{old.controls} variable in its environment, then it remaps the names in \code{...} to their new names based on \code{old.controls}. In addition, if the value is a list with two elements, \code{action} and \code{message}, the standard deprecation message will have \code{message} appended to it and then be called with \code{action()}. \item If the calling function has a \code{match.arg.pars} in its environment, the arguments in that list are processed through \code{\link[=match.arg]{match.arg()}}. } } statnet.common/man/sweep_cols.matrix.Rd0000644000176200001440000000157413416034725017747 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/logspace.utils.R \name{sweep_cols.matrix} \alias{sweep_cols.matrix} \title{Suptract a elements of a vector from respective columns of a matrix} \usage{ sweep_cols.matrix(x, STATS, disable_checks = FALSE) } \arguments{ \item{x}{a numeric matrix;} \item{STATS}{a numeric vector whose length equals to the number of columns of \code{x}.} \item{disable_checks}{if \code{TRUE}, do not check that \code{x} is a numeric matrix and its number of columns matches the length of \code{STATS}; set in production code for a significant speed-up.} } \value{ A matrix of the same attributes as \code{x}. } \description{ An optimized function equivalent to \code{sweep(x, 2, STATS)} for a matrix \code{x}. } \examples{ x <- matrix(runif(1000), ncol=4) s <- 1:4 stopifnot(all.equal(sweep_cols.matrix(x, s), sweep(x, 2, s))) } statnet.common/man/set.control.class.Rd0000644000176200001440000000173713622373301017653 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/control.utilities.R \name{set.control.class} \alias{set.control.class} \title{Set the class of the control list} \usage{ set.control.class( myname = as.character(ult(sys.calls(), 2)[[1L]]), control = get("control", pos = parent.frame()) ) } \arguments{ \item{myname}{Name of the class to set.} \item{control}{Control list. Defaults to the \code{control} variable in the calling function.} } \value{ The control list with class set. } \description{ This function sets the class of the control list, with the default being the name of the calling function. } \note{ In earlier versions, \code{OKnames} and \code{myname} were autodetected. This capability has been deprecated and results in a warning issued once per session. They now need to be set explicitly. } \seealso{ \code{\link[=check.control.class]{check.control.class()}}, \code{\link[=print.control.list]{print.control.list()}} } \keyword{utilities} statnet.common/man/empty_env.Rd0000644000176200001440000000144014014171552016272 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/formula.utilities.R \name{empty_env} \alias{empty_env} \alias{base_env} \title{Replace an object's environment with a simple, static environment.} \usage{ empty_env(object) base_env(object) } \arguments{ \item{object}{An object with the \verb{environment()<-} method.} } \value{ An object of the same type as \code{object}, with updated environment. } \description{ Replace an object's environment with a simple, static environment. } \examples{ f <- y~x environment(f) # GlobalEnv environment(empty_env(f)) # EmptyEnv \dontshow{ stopifnot(identical(environment(empty_env(f)), emptyenv())) } environment(base_env(f)) # base package environment \dontshow{ stopifnot(identical(environment(base_env(f)), baseenv())) } } statnet.common/man/wmatrix.Rd0000644000176200001440000000726113727604572016003 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/wmatrix.R \name{wmatrix} \alias{wmatrix} \alias{logwmatrix} \alias{linwmatrix} \alias{is.wmatrix} \alias{is.logwmatrix} \alias{is.linwmatrix} \alias{as.linwmatrix} \alias{as.logwmatrix} \alias{as.linwmatrix.linwmatrix} \alias{as.linwmatrix.logwmatrix} \alias{as.logwmatrix.logwmatrix} \alias{as.logwmatrix.linwmatrix} \alias{as.linwmatrix.matrix} \alias{as.logwmatrix.matrix} \alias{print.wmatrix} \alias{print.logwmatrix} \alias{print.linwmatrix} \alias{compress_rows.logwmatrix} \alias{compress_rows.linwmatrix} \alias{decompress_rows.wmatrix} \alias{[.wmatrix} \alias{[<-.wmatrix} \title{A data matrix with row weights} \usage{ logwmatrix( data = NA, nrow = 1, ncol = 1, byrow = FALSE, dimnames = NULL, w = NULL ) linwmatrix( data = NA, nrow = 1, ncol = 1, byrow = FALSE, dimnames = NULL, w = NULL ) is.wmatrix(x) is.logwmatrix(x) is.linwmatrix(x) as.linwmatrix(x, ...) as.logwmatrix(x, ...) \method{as.linwmatrix}{linwmatrix}(x, ...) \method{as.linwmatrix}{logwmatrix}(x, ...) \method{as.logwmatrix}{logwmatrix}(x, ...) \method{as.logwmatrix}{linwmatrix}(x, ...) \method{as.linwmatrix}{matrix}(x, w = NULL, ...) \method{as.logwmatrix}{matrix}(x, w = NULL, ...) \method{print}{wmatrix}(x, ...) \method{print}{logwmatrix}(x, ...) \method{print}{linwmatrix}(x, ...) \method{compress_rows}{logwmatrix}(x, ...) \method{compress_rows}{linwmatrix}(x, ...) \method{decompress_rows}{wmatrix}(x, target.nrows = NULL, ...) \method{[}{wmatrix}(x, i, j, ..., drop = FALSE) \method{[}{wmatrix}(x, i, j, ...) <- value } \arguments{ \item{data, nrow, ncol, byrow, dimnames}{passed to \code{\link{matrix}}.} \item{w}{row weights on the appropriate scale.} \item{x}{an object to be coerced or tested.} \item{...}{extra arguments, currently unused.} \item{target.nrows}{the approximate number of rows the uncompressed matrix should have; if not achievable exactly while respecting proportionality, a matrix with a slightly different number of rows will be constructed.} \item{i, j, value}{rows and columns and values for extraction or replacement; as \code{\link{matrix}}.} \item{drop}{Used for consistency with the generic. Ignored, and always treated as \code{FALSE}.} } \value{ An object of class \code{linwmatrix}/\code{logwmatrix} and \code{wmatrix}, which is a \code{\link{matrix}} but also has an attribute \code{w} containing row weights on the linear or the natural-log-transformed scale. } \description{ A representation of a numeric matrix with row weights, represented on either linear (\code{linwmatrix}) or logarithmic (\code{logwmatrix}) scale. } \note{ Note that \code{wmatrix} itself is an "abstract" class: you cannot instantiate it. Note that at this time, \code{wmatrix} is designed as, first and foremost, as class for storing compressed data matrices, so most methods that operate on matrices may not handle the weights correctly and may even cause them to be lost. } \examples{ (m <- matrix(1:3, 2, 3, byrow=TRUE)) (m <- rbind(m, 3*m, 2*m, m)) (mlog <- as.logwmatrix(m)) (mlin <- as.linwmatrix(m)) (cmlog <- compress_rows(mlog)) (cmlin <- compress_rows(mlin)) stopifnot(all.equal(as.linwmatrix(cmlog),cmlin)) cmlog[2,] <- 1:3 (cmlog <- compress_rows(cmlog)) stopifnot(sum(rowweights(cmlog))==nrow(m)) (m3 <- matrix(c(1:3,(1:3)*2,(1:3)*3), 3, 3, byrow=TRUE)) (rowweights(m3) <- c(4, 2, 2)) stopifnot(all.equal(compress_rows(as.logwmatrix(m)), as.logwmatrix(m3),check.attributes=FALSE)) stopifnot(all.equal(rowweights(compress_rows(as.logwmatrix(m))), rowweights(as.logwmatrix(m3)),check.attributes=FALSE)) } \seealso{ \code{\link{rowweights}}, \code{\link{lrowweights}}, \code{\link{compress_rows}} } statnet.common/man/forkTimeout.Rd0000644000176200001440000000362613577042065016615 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/misc.utilities.R \name{forkTimeout} \alias{forkTimeout} \title{Evaluate an \R expression with a hard time limit by forking a process} \usage{ forkTimeout( expr, timeout, unsupported = c("warning", "error", "message", "silent"), onTimeout = NULL ) } \arguments{ \item{expr}{expression to be evaluated.} \item{timeout}{number of seconds to wait for the expression to evaluate.} \item{unsupported}{a character vector of length 1 specifying how to handle a platform that does not support #ifndef windows \code{\link[parallel:mcparallel]{parallel::mcparallel()}}, #endif #ifdef windows \code{parallel::mcparallel()}, #endif \describe{ \item{\code{"warning"} or \code{"message"}}{Issue a warning or a message, respectively, then evaluate the expression without the time limit enforced.} \item{\code{"error"}}{Stop with an error.} \item{\code{"silent"}}{Evaluate the expression without the time limit enforced, without any notice.} } Partial matching is used.} \item{onTimeout}{Value to be returned on time-out.} } \value{ Result of evaluating \code{expr} if completed, \code{onTimeout} otherwise. } \description{ This function uses #ifndef windows \code{\link[parallel:mcparallel]{parallel::mcparallel()}}, #endif #ifdef windows \code{parallel::mcparallel()}, #endif so the time limit is not enforced on Windows. However, unlike functions using \code{\link[=setTimeLimit]{setTimeLimit()}}, the time limit is enforced even on native code. } \note{ \code{onTimeout} can itself be an expression, so it is, for example, possible to stop with an error by passing \code{onTimeout=stop()}. Note that this function is not completely transparent: side-effects may behave in unexpected ways. In particular, RNG state will not be updated. } \examples{ forkTimeout({Sys.sleep(1); TRUE}, 2) # TRUE forkTimeout({Sys.sleep(1); TRUE}, 0.5) # NULL (except on Windows) } statnet.common/man/snctrl.Rd0000644000176200001440000000210014264770641015576 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/control.utilities.R \name{snctrl} \alias{snctrl} \title{Statnet Control} \usage{ snctrl(...) } \arguments{ \item{...}{The parameter list is updated dynamically as packages are loaded and unloaded. Their current list is given below.} } \description{ A utility to facilitate argument completion of control lists. } \details{ In and of itself, \code{snctrl} copies its named arguments into a list. However, its argument list is updated dynamically as packages are loaded, as are those of its reexports from other packages. This is done using an API provided by helper functions. (See \code{API?snctrl}.) } \note{ You may see messages along the lines of \if{html}{\out{
}}\preformatted{The following object is masked from 'package:PKG': snctrl }\if{html}{\out{
}} when loading packages. They are benign. } \section{Currently recognised control parameters}{ This list is updated as packages are loaded and unloaded. \Sexpr[results=rd,stage=render]{statnet.common::snctrl_names()} } statnet.common/man/is.SPD.Rd0000644000176200001440000000070014427313307015326 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/matrix.utils.R \name{is.SPD} \alias{is.SPD} \title{Test if the object is a matrix that is symmetric and positive definite} \usage{ is.SPD(x, tol = .Machine$double.eps) } \arguments{ \item{x}{the object to be tested.} \item{tol}{the tolerance for the reciprocal condition number.} } \description{ Test if the object is a matrix that is symmetric and positive definite } statnet.common/man/attr.Rd0000644000176200001440000000113514054035110015230 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/misc.utilities.R \name{attr} \alias{attr} \title{A wrapper for base::attr which defaults to exact matching.} \usage{ attr(x, which, exact = TRUE) } \arguments{ \item{x, which, exact}{as in \code{base::attr}, but with \code{exact} defaulting to \code{TRUE} in this implementation} } \value{ as in \code{base::attr} } \description{ A wrapper for base::attr which defaults to exact matching. } \examples{ x <- list() attr(x, "name") <- 10 base::attr(x, "n") stopifnot(is.null(attr(x, "n"))) base::attr(x, "n", exact = TRUE) } statnet.common/man/snctrl-API.Rd0000644000176200001440000000562314306106355016212 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/control.utilities.R \docType{data} \name{snctrl_names} \alias{snctrl_names} \alias{snctrl-API} \alias{update_snctrl} \alias{collate_controls} \alias{UPDATE_MY_SCTRL_EXPR} \alias{COLLATE_ALL_MY_CONTROLS_EXPR} \title{Helper functions used by packages to facilitate \code{\link{snctrl}} updating.} \format{ \code{UPDATE_MY_SCTRL_EXPR} is a quoted expression meant to be passed directly to \code{\link[=eval]{eval()}}. \code{COLLATE_ALL_MY_CONTROLS_EXPR} is a quoted expression meant to be passed directly to \code{\link[=eval]{eval()}}. } \usage{ snctrl_names() update_snctrl(myname, arglists = NULL, callback = NULL) collate_controls(x = NULL, ...) UPDATE_MY_SCTRL_EXPR COLLATE_ALL_MY_CONTROLS_EXPR } \arguments{ \item{myname}{Name of the package defining the arguments.} \item{arglists}{A named list of argument name-default pairs. If the list is not named, it is first passed through \code{\link[=collate_controls]{collate_controls()}}.} \item{callback}{A function with no arguments that updates the packages own copy of \code{\link[=snctrl]{snctrl()}}.} \item{x}{Either a function, a list of functions, or an environment. If \code{x} is an environment, all functions starting with dQuote(\code{control.}) are obtained.} \item{...}{Additional functions or lists of functions.} } \value{ \code{update_snctrl()} has no return value and is used for its side-effects. \code{collate_controls()} returns the combined list of name-default pairs of each function. } \description{ Helper functions used by packages to facilitate \code{\link{snctrl}} updating. } \section{Functions}{ \itemize{ \item \code{snctrl_names()}: Typeset the currently defined list of argument names by package and control function. \item \code{update_snctrl()}: Typically called from \code{\link[=.onLoad]{.onLoad()}}, Update the argument list of \code{\link[=snctrl]{snctrl()}} to include additional argument names associated with the package, and set a callback for the package to update its own copy. \item \code{collate_controls()}: Obtain and concatenate the argument lists of specified functions or all functions starting with dQuote(\code{control.}) in the environment. \item \code{UPDATE_MY_SCTRL_EXPR}: A stored expression that, if evaluated, will create a callback function \code{update_my_snctrl()} that will update the client package's copy of \code{\link[=snctrl]{snctrl()}}. \item \code{COLLATE_ALL_MY_CONTROLS_EXPR}: A stored expression that, if evaluated on loading, will add arguments of the package's \verb{control.*()} functions to \code{\link[=snctrl]{snctrl()}} and set the callback. }} \examples{ \dontrun{ # In the client package (outside any function): eval(UPDATE_MY_SCTRL_EXPR) } \dontrun{ # In the client package: .onLoad <- function(libame, pkgname){ # ... other code ... eval(statnet.common::COLLATE_ALL_MY_CONTROLS_EXPR) # ... other code ... } } } \keyword{datasets} statnet.common/man/ult.Rd0000644000176200001440000000211713423722362015076 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/misc.utilities.R \name{ult} \alias{ult} \alias{ult<-} \title{Extract or replace the \emph{ult}imate (last) element of a vector or a list, or an element counting from the end.} \usage{ ult(x, i = 1L) ult(x, i = 1L) <- value } \arguments{ \item{x}{a vector or a list.} \item{i}{index from the end of the list to extract or replace (where 1 is the last element, 2 is the penultimate element, etc.).} \item{value}{Replacement value for the \code{i}th element from the end.} } \value{ An element of \code{x}. } \description{ Extract or replace the \emph{ult}imate (last) element of a vector or a list, or an element counting from the end. } \note{ Due to the way in which assigning to a function is implemented in R, \code{ult(x) <- e} may be less efficient than \code{x[[length(x)]] <- e}. } \examples{ x <- 1:5 (last <- ult(x)) (penultimate <- ult(x, 2)) # 2nd last. \dontshow{ stopifnot(last==5) stopifnot(penultimate==4) } (ult(x) <- 6) (ult(x, 2) <- 7) # 2nd last. x \dontshow{ stopifnot(all(x == c(1:3, 7L, 6L))) } } statnet.common/man/logspace.utils.Rd0000644000176200001440000000630314376774271017245 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/logspace.utils.R \name{logspace.utils} \alias{logspace.utils} \alias{log_sum_exp} \alias{log_mean_exp} \alias{lweighted.mean} \alias{lweighted.var} \alias{lweighted.cov} \title{Utilities for performing calculations on logarithmic scale.} \usage{ log_sum_exp(logx, use_ldouble = FALSE) log_mean_exp(logx, use_ldouble = FALSE) lweighted.mean(x, logw) lweighted.var(x, logw) lweighted.cov(x, y, logw) } \arguments{ \item{logx}{Numeric vector of \eqn{\log(x)}, the natural logarithms of the values to be summed or averaged.} \item{use_ldouble}{Whether to use \code{long double} precision in the calculation. If \code{TRUE}, 's C built-in \code{logspace_sum()} is used. If \code{FALSE}, the package's own implementation based on it is used, using \code{double} precision, which is (on most systems) several times faster, at the cost of precision.} \item{x, y}{Numeric vectors or matrices of \eqn{x} and \eqn{y}, the (raw) values to be summed, averaged, or whose variances and covariances are to be calculated.} \item{logw}{Numeric vector of \eqn{\log(w)}, the natural logarithms of the weights.} } \value{ The functions return the equivalents of the R expressions given below, but faster and with less loss of precision. } \description{ A small suite of functions to compute sums, means, and weighted means on logarithmic scale, minimizing loss of precision. } \section{Functions}{ \itemize{ \item \code{log_sum_exp()}: \code{log(sum(exp(logx)))} \item \code{log_mean_exp()}: \code{log(mean(exp(logx)))} \item \code{lweighted.mean()}: weighted mean of \code{x}: \code{sum(x*exp(logw))/sum(exp(logw))} for \code{x} scalar and \code{colSums(x*exp(logw))/sum(exp(logw))} for \code{x} matrix \item \code{lweighted.var()}: weighted variance of \code{x}: \code{crossprod(x-lweighted.mean(x,logw)*exp(logw/2))/sum(exp(logw))} \item \code{lweighted.cov()}: weighted covariance between \code{x} and \code{y}: \code{crossprod(x-lweighted.mean(x,logw)*exp(logw/2), y-lweighted.mean(y,logw)*exp(logw/2))/sum(exp(logw))} }} \examples{ x <- rnorm(1000) stopifnot(all.equal(log_sum_exp(x), log(sum(exp(x))), check.attributes=FALSE)) stopifnot(all.equal(log_mean_exp(x), log(mean(exp(x))), check.attributes=FALSE)) logw <- rnorm(1000) stopifnot(all.equal(m <- sum(x*exp(logw))/sum(exp(logw)),lweighted.mean(x, logw))) stopifnot(all.equal(sum((x-m)^2*exp(logw))/sum(exp(logw)), lweighted.var(x, logw), check.attributes=FALSE)) x <- cbind(x, rnorm(1000)) stopifnot(all.equal(mx <- colSums(x*exp(logw))/sum(exp(logw)), lweighted.mean(x, logw), check.attributes=FALSE)) stopifnot(all.equal(crossprod(t(t(x)-mx)*exp(logw/2))/sum(exp(logw)), lweighted.var(x, logw), check.attributes=FALSE)) y <- cbind(x, rnorm(1000)) my <- colSums(y*exp(logw))/sum(exp(logw)) stopifnot(all.equal(crossprod(t(t(x)-mx)*exp(logw/2), t(t(y)-my)*exp(logw/2))/sum(exp(logw)), lweighted.cov(x, y, logw), check.attributes=FALSE)) stopifnot(all.equal(crossprod(t(t(y)-my)*exp(logw/2), t(t(x)-mx)*exp(logw/2))/sum(exp(logw)), lweighted.cov(y, x, logw), check.attributes=FALSE)) } \author{ Pavel N. Krivitsky } \keyword{arith} statnet.common/man/diff.control.list.Rd0000644000176200001440000000250214306106355017630 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/control.utilities.R \name{diff.control.list} \alias{diff.control.list} \alias{print.diff.control.list} \title{Identify and the differences between two control lists.} \usage{ \method{diff}{control.list}(x, y = eval(call(class(x)[[1L]])), ignore.environment = TRUE, ...) \method{print}{diff.control.list}(x, ..., indent = "") } \arguments{ \item{x}{a \code{control.list}} \item{y}{a reference \code{control.list}; defaults to the default settings for \code{x}.} \item{ignore.environment}{whether environment for environment-bearing parameters (such as formulas and functions) should be considered when comparing.} \item{...}{Additional arguments to methods.} \item{indent}{an argument for recursive calls, to facilitate indentation of nested lists.} } \value{ An object of class \code{diff.control.list}: a named list with an element for each non-identical setting. The element is either itself a \code{diff.control.list} (if the setting is a control list) or a named list with elements \code{x} and \code{y}, containing \code{x}'s and \code{y}'s values of the parameter for that setting. } \description{ Identify and the differences between two control lists. } \section{Methods (by generic)}{ \itemize{ \item \code{print(diff.control.list)}: A print method. }} statnet.common/man/statnet.cite.Rd0000644000176200001440000000241313416034725016677 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/cite.utilities.R \name{statnet.cite} \alias{statnet.cite} \alias{statnet.cite.head} \alias{statnet.cite.foot} \alias{statnet.cite.pkg} \title{\code{CITATION} file utilities for Statnet packages (DEPRECATED)} \usage{ statnet.cite.head(pkg) statnet.cite.foot(pkg) statnet.cite.pkg(pkg) } \arguments{ \item{pkg}{Name of the package whose citation is being generated.} } \value{ For \code{statnet.cite.head} and \code{statnet.cite.foot}, an object of type \code{citationHeader} and \code{citationFooter}, respectively, understood by the \code{\link{citation}} function, with package name substituted into the template. For \code{statnet.cite.pkg}, an object of class \code{\link{bibentry}} containing a 'software manual' citation for the package constructed from the current version and author information in the \code{DESCRIPTION} and a template. } \description{ These functions automate citation generation for Statnet Project packages. They no longer appear to work with CRAN and are thus deprecated. } \examples{ \dontrun{ statnet.cite.head("statnet.common") statnet.cite.pkg("statnet.common") statnet.cite.foot("statnet.common") } } \seealso{ citation, citHeader, citFooter, bibentry } \keyword{utilities} statnet.common/man/unused_dots_warning.Rd0000644000176200001440000000231214364112224020343 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/misc.utilities.R \name{unused_dots_warning} \alias{unused_dots_warning} \title{An error handler for \code{\link[rlang:check_dots_used]{rlang::check_dots_used()}} that issues a warning that only lists argument names.} \usage{ unused_dots_warning(e) } \arguments{ \item{e}{a \link{condition} object, typically not passed by the end-user; see example below.} } \description{ This handler parses the error message produced by \code{\link[rlang:check_dots_used]{rlang::check_dots_used()}}, extracting the names of the unused arguments, and formats them into a more gentle warning message. It relies on \CRANpkg{rlang} maintaining its current format. } \examples{ \dontshow{ o <- options(warn=1, useFancyQuotes=FALSE) } g <- function(b=NULL, ...){ invisible(force(b)) } f <- function(...){ rlang::check_dots_used(error = unused_dots_warning) g(...) } f() # OK f(b=2) # OK f(a=1, b=2, c=3) # Warning about a and c but not about b \dontshow{ # Test: stopifnot(grepl("Argument(s) 'a' and 'c' were not recognized or used. Did you mistype an argument name?", tryCatch(f(a=1, b=2, c=3), warning = function(e) e$message), fixed=TRUE)) options(o) } } statnet.common/man/statnetStartupMessage.Rd0000644000176200001440000000272514057310034020642 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/startup.utilities.R \name{statnetStartupMessage} \alias{statnetStartupMessage} \title{Construct a "standard" startup message to be printed when the package is loaded.} \usage{ statnetStartupMessage(pkgname, friends = c(), nofriends = c()) } \arguments{ \item{pkgname}{Name of the package whose information is used.} \item{friends, nofriends}{No longer used.} } \value{ A string containing the startup message, to be passed to the \code{\link[=packageStartupMessage]{packageStartupMessage()}} call or \code{NULL}, if policy prescribes printing default startup message. (Thus, if \code{\link[=statnetStartupMessage]{statnetStartupMessage()}} returns \code{NULL}, the calling package should not call \code{\link[=packageStartupMessage]{packageStartupMessage()}} at all.) } \description{ This function uses information returned by \code{\link[=packageDescription]{packageDescription()}} to construct a standard package startup message according to the policy of the Statnet Project. } \note{ Earlier versions of this function printed a more expansive message. This may change again as the Statnet Project policy evolves. } \examples{ \dontrun{ .onAttach <- function(lib, pkg){ sm <- statnetStartupMessage("ergm") if(!is.null(sm)) packageStartupMessage(sm) } } } \seealso{ \code{\link[=packageDescription]{packageDescription()}}, \code{\link[=packageStartupMessage]{packageStartupMessage()}} } \keyword{utilities} statnet.common/man/unwhich.Rd0000644000176200001440000000125213416034725015737 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/misc.utilities.R \name{unwhich} \alias{unwhich} \title{Construct a logical vector with \code{TRUE} in specified positions.} \usage{ unwhich(which, n) } \arguments{ \item{which}{a numeric vector of indices to set to \code{TRUE}.} \item{n}{total length of the output vector.} } \value{ A logical vector of length \code{n} whose elements listed in \code{which} are set to \code{TRUE}, and whose other elements are set to \code{FALSE}. } \description{ This function is basically an inverse of \code{\link{which}}. } \examples{ x <- as.logical(rbinom(10,1,0.5)) stopifnot(all(x == unwhich(which(x), 10))) } statnet.common/man/compress_rows.data.frame.Rd0000644000176200001440000000333213727604572021211 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/misc.utilities.R \name{compress_rows.data.frame} \alias{compress_rows.data.frame} \alias{decompress_rows.compressed_rows_df} \title{"Compress" a data frame.} \usage{ \method{compress_rows}{data.frame}(x, ...) \method{decompress_rows}{compressed_rows_df}(x, ...) } \arguments{ \item{x}{For \code{compress_rows.data.frame} a \code{\link{data.frame}} to be compressed. For \code{decompress_rows.compress_rows_df} a \code{\link{list}} as returned by \code{compress_rows.data.frame}.} \item{...}{Additional arguments, currently unused.} } \value{ For \code{compress_rows.data.frame}, a \code{\link{list}} with three elements: \item{rows }{Unique rows of \code{x}} \item{frequencies }{A vector of the same length as the number or rows, giving the number of times the corresponding row is repeated } \item{ordering}{A vector such that if \code{c} is the compressed data frame, \code{c$rows[c$ordering,,drop=FALSE]} equals the original data frame, except for row names} \item{rownames}{Row names of \code{x}} For \code{decompress_rows.compressed_rows_df}, the original data frame. } \description{ \code{compress_rows.data.frame} "compresses" a data frame, returning unique rows and a tally of the number of times each row is repeated, as well as a permutation vector that can reconstruct the original data frame. \code{decompress_rows.compressed_rows_df} reconstructs the original data frame. } \examples{ (x <- data.frame(V1=sample.int(3,30,replace=TRUE), V2=sample.int(2,30,replace=TRUE), V3=sample.int(4,30,replace=TRUE))) (c <- compress_rows(x)) stopifnot(all(decompress_rows(c)==x)) } \seealso{ \code{\link{data.frame}} } \keyword{manip} statnet.common/man/locate_function.Rd0000644000176200001440000000464314306106355017453 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/locator.R \name{locate_function} \alias{locate_function} \alias{locate_prefixed_function} \title{Locate a function with a given name and return it and its environment.} \usage{ locate_function(name, env = globalenv(), ...) locate_prefixed_function( name, prefix, errname, env = globalenv(), ..., call. = FALSE ) } \arguments{ \item{name}{a character string giving the function's name.} \item{env}{an \code{\link{environment}} where it should search first.} \item{...}{additional arguments to the warning and error warning messages. See Details.} \item{prefix}{a character string giving the prefix, so the searched-for function is \code{prefix.name}.} \item{errname}{a character string; if given, if the function is not found an error is raised, with \code{errname} prepended to the error message.} \item{call.}{a logical, whether the call (\code{locate_prefixed_function}) should be a part of the error message; defaults to \code{FALSE} (which is different from \code{\link[=stop]{stop()}}'s default).} } \value{ If the function is found, an unevaluated call of the form \code{ENVNAME:::FUNNAME}, which can then be used to call the function even if it is unexported. If the environment does not have a name, or is \code{GlobalEnv}, only \code{FUNNAME} is returned. Otherwise, \code{NULL} is returned. } \description{ These functions first search the given environment, then search all loaded environments, including those where the function is not exported. If found, they return an unambiguous reference to the function. } \details{ If the initial search fails, a search using \code{\link[=getAnywhere]{getAnywhere()}} is attempted, with exported ("visible") functions with the specified name preferred over those that are not. When multiple equally qualified functions are available, a warning is printed and an arbitrary one is returned. Because \code{\link[=getAnywhere]{getAnywhere()}} can be slow, past searches are cached. } \section{Functions}{ \itemize{ \item \code{locate_function()}: a low-level function returning the reference to the function named \code{name}, or \code{NULL} if not found. \item \code{locate_prefixed_function()}: a helper function that searches for a function of the form \code{prefix.name} and produces an informative error message if not found. }} \examples{ # Locate a random function in base. locate_function(".row_names_info") } statnet.common/man/fixed.pval.Rd0000644000176200001440000000270614046234371016336 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/string.utilities.R \name{fixed.pval} \alias{fixed.pval} \title{Format a p-value in fixed notation.} \usage{ fixed.pval( pv, digits = max(1, getOption("digits") - 2), eps = 10^-digits, na.form = "NA", ... ) } \arguments{ \item{pv, digits, eps, na.form, ...}{see \code{\link[=format.pval]{format.pval()}}.} } \value{ A character vector. } \description{ This is a thin wrapper around \code{\link[=format.pval]{format.pval()}} that guarantees fixed (not scientific) notation, links (by default) the \code{eps} argument to the \code{digits} argument and vice versa, and sets \code{nsmall} to equal \code{digits}. } \examples{ pvs <- 10^((0:-12)/2) # Jointly: fpf <- fixed.pval(pvs, digits = 3) fpf format.pval(pvs, digits = 3) # compare \dontshow{ stopifnot(all(fpf == c("1.000", "0.316", "0.100", "0.032", "0.010", "0.003", "0.001", "<0.001", "<0.001", "<0.001", "<0.001", "<0.001", "<0.001"))) } # Individually: fpf <- sapply(pvs, fixed.pval, digits = 3) fpf sapply(pvs, format.pval, digits = 3) # compare \dontshow{ stopifnot(all(fpf == c("1.000", "0.316", "0.100", "0.032", "0.010", "0.003", "0.001", "<0.001", "<0.001", "<0.001", "<0.001", "<0.001", "<0.001"))) } # Control eps: fpf <- sapply(pvs, fixed.pval, eps = 1e-3) fpf \dontshow{ stopifnot(all(fpf == c("1.000", "0.316", "0.100", "0.032", "0.010", "0.003", "0.001", "<0.001", "<0.001", "<0.001", "<0.001", "<0.001", "<0.001"))) } } statnet.common/man/default_options.Rd0000644000176200001440000000177013754644650017507 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/startup.utilities.R \name{default_options} \alias{default_options} \title{Set \code{\link[=options]{options()}} according to a named list, skipping those already set.} \usage{ default_options(...) } \arguments{ \item{...}{see \code{\link[=options]{options()}}: either a list of \code{name=value} pairs or a single unnamed argument giving a named list of options to set.} } \value{ The return value is same as that of \code{\link[=options]{options()}} (omitting options already set). } \description{ This function can be useful for setting default options, which do not override options set elsewhere. } \examples{ options(onesetting=1) default_options(onesetting=2, anothersetting=3) stopifnot(getOption("onesetting")==1) # Still 1. stopifnot(getOption("anothersetting")==3) default_options(list(yetanothersetting=5, anothersetting=4)) stopifnot(getOption("anothersetting")==3) # Still 3. stopifnot(getOption("yetanothersetting")==5) } statnet.common/man/split.array.Rd0000644000176200001440000000243513646210041016536 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/misc.utilities.R \name{split.array} \alias{split.array} \alias{split.matrix} \title{A \code{\link[=split]{split()}} method for \code{\link{array}} and \code{\link{matrix}} types on a margin.} \usage{ \method{split}{array}(x, f, drop = FALSE, margin = NULL, ...) \method{split}{matrix}(x, f, drop = FALSE, margin = NULL, ...) } \arguments{ \item{x}{A \code{\link{matrix}} or an \code{\link{array}}.} \item{f, drop}{See help for \code{\link[=split]{split()}}. Note that \code{drop} here is \emph{not} for array dimensions: these are always preserved.} \item{margin}{Which margin of the array to split along. \code{NULL} splits as \code{\link{split.default}}, dropping dimensions.} \item{...}{Additional arguments to \code{\link[=split]{split()}}.} } \description{ These methods split an \code{\link{array}} and \code{\link{matrix}} into a list of arrays or matrices with the same number of dimensions according to the specified margin. } \examples{ x <- diag(5) f <- rep(1:2, c(2,3)) split(x, f, margin=1) # Split rows. split(x, f, margin=2) # Split columns. # This is similar to how data frames are split: stopifnot(identical(split(x, f, margin=1), lapply(lapply(split(as.data.frame(x), f), as.matrix), unname))) } statnet.common/man/xTAx.Rd0000644000176200001440000000270214427313306015155 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/matrix.utils.R \name{xTAx} \alias{xTAx} \alias{xAxT} \alias{xTAx_solve} \alias{xTAx_qrsolve} \alias{sandwich_solve} \title{Common quadratic forms} \usage{ xTAx(x, A) xAxT(x, A) xTAx_solve(x, A, ...) xTAx_qrsolve(x, A, tol = 1e-07, ...) sandwich_solve(A, B, ...) } \arguments{ \item{x}{a vector} \item{A}{a square matrix} \item{...}{additional arguments to subroutines} \item{tol}{tolerance argument passed to the relevant subroutine} \item{B}{a square matrix} } \description{ Common quadratic forms } \details{ These are somewhat inspired by emulator::quad.form.inv() and others. } \section{Functions}{ \itemize{ \item \code{xTAx()}: Evaluate \eqn{x'Ax} for vector \eqn{x} and square matrix \eqn{A}. \item \code{xAxT()}: Evaluate \eqn{xAx'} for vector \eqn{x} and square matrix \eqn{A}. \item \code{xTAx_solve()}: Evaluate \eqn{x'A^{-1}x} for vector \eqn{x} and invertible matrix \eqn{A} using \code{\link[=solve]{solve()}}. \item \code{xTAx_qrsolve()}: Evaluate \eqn{x'A^{-1}x} for vector \eqn{x} and matrix \eqn{A} using QR decomposition and confirming that \eqn{x} is in the span of \eqn{A} if \eqn{A} is singular; returns \code{rank} and \code{nullity} as attributes just in case subsequent calculations (e.g., hypothesis test degrees of freedom) are affected. \item \code{sandwich_solve()}: Evaluate \eqn{A^{-1}B(A')^{-1}} for \eqn{B} a square matrix and \eqn{A} invertible. }} statnet.common/man/deprecation-utilities.Rd0000644000176200001440000000276414057310034020601 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/deprecation_utils.R \name{deprecation-utilities} \alias{deprecation-utilities} \alias{.Deprecate_once} \alias{.Deprecate_method} \title{Utilities to help with deprecating functions.} \usage{ .Deprecate_once(...) .Deprecate_method(generic, class) } \arguments{ \item{...}{arguments passed to \code{\link[=.Deprecated]{.Deprecated()}}.} \item{generic, class}{strings giving the generic function name and class name of the function to be deprecated.} } \description{ \code{.Deprecate_once} calls \code{\link[=.Deprecated]{.Deprecated()}}, passing all its arguments through, but only the first time it's called. \code{.Deprecate_method} calls \code{\link[=.Deprecated]{.Deprecated()}}, but only if a method has been called by name, i.e., \code{\var{METHOD}.\var{CLASS}}. Like \code{.Deprecate_once} it only issues a warning the first time. } \examples{ \dontrun{ options(warn=1) # Print warning immediately after the call. f <- function(){ .Deprecate_once("new_f") } f() # Deprecation warning f() # No deprecation warning } \dontrun{ options(warn=1) # Print warning immediately after the call. summary.packageDescription <- function(object, ...){ .Deprecate_method("summary", "packageDescription") invisible(object) } summary(packageDescription("statnet.common")) # No warning. summary.packageDescription(packageDescription("statnet.common")) # Warning. summary.packageDescription(packageDescription("statnet.common")) # No warning. } } statnet.common/man/mcmc-utilities.Rd0000644000176200001440000000420013416034725017216 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/mcmc-utils.R \name{mcmc-utilities} \alias{mcmc-utilities} \alias{colMeans.mcmc.list} \alias{sweep.mcmc.list} \alias{lapply.mcmc.list} \title{Utility operations for \code{\link{mcmc.list}} objects} \usage{ colMeans.mcmc.list(x, ...) sweep.mcmc.list(x, STATS, FUN = "-", check.margin = TRUE, ...) lapply.mcmc.list(X, FUN, ...) } \arguments{ \item{x}{a \code{\link{mcmc.list}} object.} \item{\dots}{additional arguments to \code{\link{colMeans}} or \code{\link{sweep}}.} \item{STATS, FUN, check.margin}{See help for \code{\link{sweep}}.} \item{X}{An \code{\link{mcmc.list}} object.} } \value{ \code{colMeans.mcmc} returns a vector with length equal to the number of mcmc chains in \code{x} with the mean value for each chain. \code{sweep.mcmc.list} returns an appropriately modified version of \code{x} \code{lapply.mcmc.list} returns an \code{\link{mcmc.list}} each of whose chains had been passed through \code{FUN}. } \description{ \code{colMeans.mcmc.list} is a "method" for (non-generic) \code{\link{colMeans}} applicable to \code{\link{mcmc.list}} objects. \code{sweep.mcmc.list} is a "method" for (non-generic) \code{\link{sweep}} applicable to \code{\link{mcmc.list}} objects. \code{lapply.mcmc.list} is a "method" for (non-generic) \code{\link{lapply}} applicable to \code{\link{mcmc.list}} objects. } \examples{ data(line, package="coda") summary(line) # coda colMeans.mcmc.list(line) # "Method" \dontshow{ stopifnot(isTRUE(all.equal(summary(line)$statistics[,"Mean"],colMeans.mcmc.list(line)))) } data(line, package="coda") colMeans.mcmc.list(line)-1:3 colMeans.mcmc.list(sweep.mcmc.list(line, 1:3)) \dontshow{ stopifnot(isTRUE(all.equal(colMeans.mcmc.list(sweep.mcmc.list(line, 1:3)), colMeans.mcmc.list(line)-1:3))) } data(line, package="coda") colMeans.mcmc.list(line)[c(2,3,1)] colMeans.mcmc.list(lapply.mcmc.list(line, `[`,,c(2,3,1))) \dontshow{ stopifnot(isTRUE(all.equal(colMeans.mcmc.list(line)[c(2,3,1)],colMeans.mcmc.list(lapply.mcmc.list(line, `[`,,c(2,3,1)))))) } } \seealso{ \code{\link{colMeans}}, \code{\link{mcmc.list}} \code{\link{sweep}} \code{\link{lapply}} } statnet.common/man/once.Rd0000644000176200001440000000506013472461363015223 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/misc.utilities.R \name{once} \alias{once} \title{Evaluate a function once for a given input.} \usage{ once(f, expire_after = Inf, max_entries = Inf) } \arguments{ \item{f}{A function to modify.} \item{expire_after}{The number of seconds since it was added to the database before a particular configuration is "forgotten". This can be used to periodically remind the user without overwhelming them.} \item{max_entries}{The number of distinct configurations to remember. If not \code{Inf}, \emph{earliest-inserted} configurations will be removed from the database when capacity is exceeded. (This exact behavior may change in the future.)} } \description{ This is a \code{purrr}-style adverb that checks if a given function has already been called with a given configuration of arguments and skips it if it has. } \details{ Each modified function instance returned by \code{once()} maintains a database of previous argument configurations. They are not in any way compressed, so this database may grow over time. Thus, this wrapper should be used with caution if arguments are large objects. This may be replaced with hashing in the future. In the meantime, you may want to set the \code{max_entries} argument to be safe. Different instances of a modified function do not share databases, even if the function is the same. This means that if you, say, modify a function within another function, the modified function will call once per call to the outer function. Modified functions defined at package level count as the same "instance", however. See example. } \note{ Because the function needs to test whether a particular configuration of arguments have already been used, do not rely on lazy evaluation behaviour. } \examples{ msg <- once(message) msg("abc") # Prints. msg("abc") # Silent. msg <- once(message) # Starts over. msg("abc") # Prints. f <- function(){ innermsg <- once(message) innermsg("efg") # Prints once per call to f(). innermsg("efg") # Silent. msg("abcd") # Prints only the first time f() is called. msg("abcd") # Silent. } f() # Prints "efg" and "abcd". f() # Prints only "efg". msg3 <- once(message, max_entries=3) msg3("a") # 1 remembered. msg3("a") # Silent. msg3("b") # 2 remembered. msg3("a") # Silent. msg3("c") # 3 remembered. msg3("a") # Silent. msg3("d") # "a" forgotten. msg3("a") # Printed. msg2s <- once(message, expire_after=2) msg2s("abc") # Prints. msg2s("abc") # Silent. Sys.sleep(1) msg2s("abc") # Silent after 1 sec. Sys.sleep(1.1) msg2s("abc") # Prints after 2.1 sec. } statnet.common/man/NVL.Rd0000644000176200001440000000632414306106355014734 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/misc.utilities.R \name{NVL} \alias{NVL} \alias{NVL2} \alias{NVL3} \alias{EVL} \alias{EVL2} \alias{EVL3} \alias{NVL<-} \alias{EVL<-} \title{Convenience functions for handling \code{\link{NULL}} objects.} \usage{ NVL(...) NVL2(test, notnull, null = NULL) NVL3(test, notnull, null = NULL) EVL(...) EVL2(test, notnull, null = NULL) EVL3(test, notnull, null = NULL) NVL(x) <- value EVL(x) <- value } \arguments{ \item{\dots, test}{expressions to be tested.} \item{notnull}{expression to be returned if \code{test} is not \code{NULL}.} \item{null}{expression to be returned if \code{test} is \code{NULL}.} \item{x}{an object to be overwritten if \code{\link{NULL}}.} \item{value}{new value for \code{x}.} } \description{ Convenience functions for handling \code{\link{NULL}} objects. } \section{Functions}{ \itemize{ \item \code{NVL()}: Inspired by SQL function \code{NVL}, returns the first argument that is not \code{NULL}, or \code{NULL} if all arguments are \code{NULL}. \item \code{NVL2()}: Inspired by Oracle SQL function \code{NVL2}, returns the second argument if the first argument is not \code{NULL} and the third argument if the first argument is \code{NULL}. The third argument defaults to \code{NULL}, so \code{NVL2(a, b)} can serve as shorthand for \code{(if(!is.null(a)) b)}. \item \code{NVL3()}: Inspired by Oracle SQL \code{NVL2} function and \code{magittr} \code{\%>\%} operator, behaves as \code{NVL2} but \code{.}s in the second argument are substituted with the first argument. \item \code{EVL()}: As \code{NVL}, but for any objects of length 0 (\emph{E}mpty) rather than just \code{NULL}. Note that if no non-zero-length arguments are given, \code{NULL} is returned. \item \code{EVL2()}: As \code{NVL2}, but for any objects of length 0 (\emph{E}mpty) rather than just \code{NULL}. \item \code{EVL3()}: As \code{NVL3}, but for any objects of length 0 (\emph{E}mpty) rather than just \code{NULL}. \item \code{NVL(x) <- value}: Assigning to \code{NVL} overwrites its first argument if that argument is \code{\link{NULL}}. Note that it will \emph{always} return the right-hand-side of the assignment (\code{value}), regardless of what \code{x} is. \item \code{EVL(x) <- value}: As assignment to \code{NVL}, but for any objects of length 0 (\emph{E}mpty) rather than just \code{NULL}. }} \note{ Whenever possible, these functions use lazy evaluation, so, for example \code{NVL(1, stop("Error!"))} will never evaluate the \code{\link{stop}} call and will not produce an error, whereas \code{NVL(NULL, stop("Error!"))} would. } \examples{ a <- NULL a # NULL NVL(a,0) # 0 b <- 1 b # 1 NVL(b,0) # 1 # Here, object x does not exist, but since b is not NULL, x is # never evaluated, so the statement finishes. NVL(b,x) # 1 # Also, NVL(NULL,1,0) # 1 NVL(NULL,0,1) # 0 NVL(NULL,NULL,0) # 0 NVL(NULL,NULL,NULL) # NULL NVL2(a, "not null!", "null!") # "null!" NVL2(b, "not null!", "null!") # "not null!" NVL3(a, "not null!", "null!") # "null!" NVL3(b, .+1, "null!") # 2 NVL(NULL*2, 1) # numeric(0) is not NULL EVL(NULL*2, 1) # 1 NVL(a) <- 2 a # 2 NVL(b) <- 2 b # still 1 } \seealso{ \code{\link{NULL}}, \code{\link[base]{is.null}}, \code{\link[base]{if}} } \keyword{utilities} statnet.common/man/paste.and.Rd0000644000176200001440000000167713416034725016162 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/string.utilities.R \name{paste.and} \alias{paste.and} \title{Concatenates the elements of a vector (optionaly enclosing them in quotation marks or parentheses) adding appropriate punctuation and conjunctions.} \usage{ paste.and(x, oq = "", cq = "", con = "and") } \arguments{ \item{x}{A vector.} \item{oq}{Opening quotation symbol. (Defaults to none.)} \item{cq}{Closing quotation symbol. (Defaults to none.)} \item{con}{Conjunction to be used if \code{length(x)>1}. (Defaults to "and".)} } \value{ A string with the output. } \description{ A vector \code{x} becomes "\code{x[1]}", "\code{x[1]} and \code{x[2]}", or "\code{x[1]}, \code{x[2]}, and \code{x[3]}", depending on the langth of \code{x}. } \examples{ print(paste.and(c())) print(paste.and(1)) print(paste.and(1:2)) print(paste.and(1:3)) print(paste.and(1:4,con='or')) } \seealso{ paste, cat } \keyword{utilities} statnet.common/man/term_list.Rd0000644000176200001440000000401514265207276016302 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/formula.utilities.R \name{term_list} \alias{term_list} \alias{as.term_list} \alias{as.term_list.term_list} \alias{as.term_list.default} \alias{c.term_list} \alias{[.term_list} \alias{print.term_list} \title{A helper class for list of terms in an formula} \usage{ term_list(x, sign = +1, env = NULL) as.term_list(x, ...) \method{as.term_list}{term_list}(x, ...) \method{as.term_list}{default}(x, sign = +1, env = NULL, ...) \method{c}{term_list}(x, ...) \method{[}{term_list}(x, i, ...) \method{print}{term_list}(x, ...) } \arguments{ \item{x}{a list of terms or a term; a \code{term_list}} \item{sign}{a vector specifying the signs associated with each term (\code{-1} and \code{+1})} \item{env}{a list specifying the environments, or NULL} \item{...}{additional arguments to methods} \item{i}{list index} } \description{ Typically generated by \code{\link[=list_rhs.formula]{list_rhs.formula()}}, it contains, in addition to a list of \code{\link[=call]{call()}} or similar objects, attributes \code{"sign"} and \code{"env"}, containing, respectively a vector of signs that the terms had in the original formula and a list of environments of the formula from which the term has been extracted. Indexing and concatenation methods preserve these. } \examples{ e1 <- new.env() f1 <- a~b+c environment(f1) <- e1 f2 <- ~-NULL+1 (l1 <- list_rhs.formula(f1)) (l2 <- list_rhs.formula(f2)) (l <- c(l1,l2)) \dontshow{ stopifnot(identical(c(unclass(l)), alist(b, c, NULL, 1))) stopifnot(identical(attr(l, "sign"), c(1,1,-1,1))) stopifnot(identical(attr(l, "env"), rep(list(e1, globalenv()), each=2))) } (l <- c(l2[1], l1[2], l1[1], l1[1], l2[2])) \dontshow{ stopifnot(identical(c(unclass(l)), alist(NULL, c, b, b, 1))) stopifnot(identical(attr(l, "sign"), c(-1,1,1,1,1))) stopifnot(identical(attr(l, "env"), list(globalenv(), e1, e1, e1, globalenv()))) } } \seealso{ \code{\link[=list_rhs.formula]{list_rhs.formula()}}, \code{\link[=list_summands.call]{list_summands.call()}} } statnet.common/man/ssolve.Rd0000644000176200001440000000415014427313306015603 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/matrix.utils.R \name{ssolve} \alias{ssolve} \alias{sginv} \alias{srcond} \alias{snearPD} \alias{xTAx_ssolve} \alias{xTAx_qrssolve} \alias{sandwich_ssolve} \title{Wrappers around matrix algebra functions that pre-\emph{s}cale their arguments} \usage{ ssolve(a, b, ..., snnd = TRUE) sginv(X, ..., snnd = TRUE) srcond(x, ..., snnd = TRUE) snearPD(x, ...) xTAx_ssolve(x, A, ...) xTAx_qrssolve(x, A, tol = 1e-07, ...) sandwich_ssolve(A, B, ...) } \arguments{ \item{snnd}{assume that the matrix is symmetric non-negative definite (SNND). If it's "obvious" that it's not (e.g., negative diagonal elements), an error is raised.} \item{x, a, b, X, A, B, tol, ...}{corresponding arguments of the wrapped functions.} } \description{ Covariance matrices of variables with very different orders of magnitude can have very large ratios between their greatest and their least eigenvalues, causing them to appear to the algorithms to be near-singular when they are actually very much SPD. These functions first scale the matrix's rows and/or columns by its diagonal elements and then undo the scaling on the result. } \details{ \code{ssolve()}, \code{sginv()}, and \code{snearPD()} wrap \code{\link[=solve]{solve()}}, \code{\link[MASS:ginv]{MASS::ginv()}}, and \code{\link[Matrix:nearPD]{Matrix::nearPD()}}, respectively. \code{srcond()} returns the reciprocal condition number of \code{\link[=rcond]{rcond()}} net of the above scaling. \code{xTAx_ssolve}, \code{xTAx_qrssolve}, and \code{sandwich_ssolve} wrap the corresponding \pkg{statnet.common} functions. } \examples{ x <- rnorm(2, sd=c(1,1e12)) x <- c(x, sum(x)) A <- matrix(c(1, 0, 1, 0, 1e24, 1e24, 1, 1e24, 1e24), 3, 3) stopifnot(all.equal( xTAx_qrssolve(x,A), structure(drop(x\%*\%sginv(A)\%*\%x), rank = 2L, nullity = 1L) )) x <- rnorm(2, sd=c(1,1e12)) x <- c(x, rnorm(1, sd=1e12)) A <- matrix(c(1, 0, 1, 0, 1e24, 1e24, 1, 1e24, 1e24), 3, 3) stopifnot(try(xTAx_qrssolve(x,A), silent=TRUE) == "Error in xTAx_qrssolve(x, A) : x is not in the span of A\n") } statnet.common/man/compress_rows.Rd0000644000176200001440000000141613727604572017211 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/wmatrix.R \name{compress_rows} \alias{compress_rows} \alias{decompress_rows} \title{A generic function to compress a row-weighted table} \usage{ compress_rows(x, ...) decompress_rows(x, ...) } \arguments{ \item{x}{a weighted matrix or data frame.} \item{...}{extra arguments for methods.} } \value{ For \code{compress_rows} A weighted matrix or data frame of the same type with duplicated rows removed and weights updated appropriately. } \description{ Compress a matrix or a data frame with duplicated rows, updating row weights to reflect frequencies, or reverse the process, reconstructing a matrix like the one compressed (subject to permutation of rows and weights not adding up to an integer). } statnet.common/man/deInf.Rd0000644000176200001440000000130013577042065015315 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/misc.utilities.R \name{deInf} \alias{deInf} \title{Truncate values of high magnitude in a vector.} \usage{ deInf(x, replace = 1/.Machine$double.eps) } \arguments{ \item{x}{a numeric or integer vector.} \item{replace}{a number or a string \code{"maxint"} or \code{"intmax"}.} } \value{ Returns \code{x} with elements whose magnitudes exceed \code{replace} replaced replaced by \code{replace} (or its negation). If \code{replace} is \code{"maxint"} or \code{"intmax"}, \code{.Machine$integer.max} is used instead. \code{NA} and \code{NAN} values are preserved. } \description{ Truncate values of high magnitude in a vector. } statnet.common/man/opttest.Rd0000644000176200001440000000220413577042065015776 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/misc.utilities.R \name{opttest} \alias{opttest} \title{Optionally test code depending on environment variable.} \usage{ opttest( expr, testname = NULL, testvar = "ENABLE_statnet_TESTS", yesvals = c("y", "yes", "t", "true", "1"), lowercase = TRUE ) } \arguments{ \item{expr}{An expression to be evaluated only if \code{testvar} is set to a non-empty value.} \item{testname}{Optional name of the test. If given, and the test is skipped, will print a message to that end, including the name of the test, and instructions on how to enable it.} \item{testvar}{Environment variable name. If set to one of the \code{yesvals}, \code{expr} is run. Otherwise, an optional message is printed.} \item{yesvals}{A character vector of strings considered affirmative values for \code{testvar}.} \item{lowercase}{Whether to convert the value of \code{testvar} to lower case before comparing it to \code{yesvals}.} } \description{ A convenience wrapper to run code based on whether an environment variable is defined. } \keyword{debugging} \keyword{environment} \keyword{utilities} statnet.common/man/check.control.class.Rd0000644000176200001440000000435513772063421020141 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/control.utilities.R \name{check.control.class} \alias{check.control.class} \title{Ensure that the class of the control list is one of those that can be used by the calling function} \usage{ check.control.class( OKnames = as.character(ult(sys.calls(), 2)[[1L]]), myname = as.character(ult(sys.calls(), 2)[[1L]]), control = get("control", pos = parent.frame()) ) } \arguments{ \item{OKnames}{List of control function names which are acceptable.} \item{myname}{Name of the calling function (used in the error message).} \item{control}{The control list or a list to be converted to a control list using \code{control.myname()}. Defaults to the \code{control} variable in the calling function. See Details for detailed behavior.} } \value{ A valid control list for the function in which it is to be used. If \code{control} argument is missing, it will also overwrite the variable \code{control} in the calling environment with it. } \description{ This function converts an ordinary \code{list} into a control list (if needed) and checks that the control list passed is appropriate for the function to be controlled. } \details{ \code{check.control.class()} performs the check by looking up the class of the \code{control} argument (defaulting to the \code{control} variable in the calling function) and checking if it matches a list of acceptable given by \code{OKnames}. Before performing any checks, the \code{control} argument (including the default) will be converted to a control list by calling \code{\link[=as.control.list]{as.control.list()}} on it with the first element of \code{OKnames} to construct the control function. If \code{control} is missing, it will be assumed that the user wants to modify it in place, and a variable with that name in the parent environment will be overwritten. } \note{ In earlier versions, \code{OKnames} and \code{myname} were autodetected. This capability has been deprecated and results in a warning issued once per session. They now need to be set explicitly. } \seealso{ \code{\link[=set.control.class]{set.control.class()}}, \code{\link[=print.control.list]{print.control.list()}}, \code{\link[=as.control.list]{as.control.list()}} } \keyword{utilities} statnet.common/man/persistEval.Rd0000644000176200001440000000406213577042065016601 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/misc.utilities.R \name{persistEval} \alias{persistEval} \alias{persistEvalQ} \title{Evaluate an expression, restarting on error} \usage{ persistEval( expr, retries = NVL(getOption("eval.retries"), 5), beforeRetry, envir = parent.frame(), enclos = if (is.list(envir) || is.pairlist(envir)) parent.frame() else baseenv(), verbose = FALSE ) persistEvalQ( expr, retries = NVL(getOption("eval.retries"), 5), beforeRetry, envir = parent.frame(), enclos = if (is.list(envir) || is.pairlist(envir)) parent.frame() else baseenv(), verbose = FALSE ) } \arguments{ \item{expr}{an expression to be retried; note the difference between \code{\link[=eval]{eval()}} and \code{\link[=evalq]{evalq()}}.} \item{retries}{number of retries to make; defaults to \code{"eval.retries"} option, or 5.} \item{beforeRetry}{if given, an expression that will be evaluated before each retry if the initial attempt fails; it is evaluated in the same environment and with the same quoting semantics as \code{expr}, but its errors are not handled.} \item{envir, enclos}{see \code{\link[=eval]{eval()}}.} \item{verbose}{Whether to output retries.} } \value{ Results of evaluating \code{expr}, including side-effects such as variable assignments, if successful in \code{retries} retries. } \description{ A pair of functions paralleling \code{\link[=eval]{eval()}} and \code{\link[=evalq]{evalq()}} that make multiple attempts at evaluating an expression, retrying on error up to a specified number of attempts, and optionally evaluating another expression before restarting. } \note{ If \code{expr} returns a \code{"try-error"} object (returned by \code{\link[=try]{try()}}), it will be treated as an error. This behavior may change in the future. } \examples{ x <- 0 persistEvalQ({if((x<-x+1)<3) stop("x < 3") else x}, beforeRetry = {cat("Will try incrementing...\n")}) x <- 0 e <- quote(if((x<-x+1)<3) stop("x < 3") else x) persistEval(e, beforeRetry = quote(cat("Will try incrementing...\n"))) } statnet.common/man/despace.Rd0000644000176200001440000000057613577042065015712 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/string.utilities.R \name{despace} \alias{despace} \title{A one-line function to strip whitespace from its argument.} \usage{ despace(s) } \arguments{ \item{s}{a character vector.} } \description{ A one-line function to strip whitespace from its argument. } \examples{ stopifnot(despace("\n \t ")=="") } statnet.common/man/ERRVL.Rd0000644000176200001440000000271613416034725015172 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/misc.utilities.R \name{ERRVL} \alias{ERRVL} \title{Return the first argument passed (out of any number) that is not a \code{try-error} (result of \code{\link[base]{try}} encountering an error.} \usage{ ERRVL(...) } \arguments{ \item{\dots}{Expressions to be tested; usually outputs of \code{\link[base]{try}}.} } \value{ The first argument that is not a \code{try-error}. Stops with an error if all are. } \description{ This function is inspired by \code{\link{NVL}}, and simply returns the first argument that is not a \code{try-error}, raising an error if all arguments are \code{try-error}s. } \note{ This function uses lazy evaluation, so, for example \code{ERRVL(1, stop("Error!"))} will never evaluate the \code{\link{stop}} call and will not produce an error, whereas \code{ERRVL(try(solve(0)), stop("Error!"))} would. In addition, all expressions after the first may contain a \code{.}, which is substituted with the \code{try-error} object returned by the previous expression. } \examples{ print(ERRVL(1,2,3)) # 1 print(ERRVL(try(solve(0)),2,3)) # 2 print(ERRVL(1, stop("Error!"))) # No error \dontrun{ # Error: print(ERRVL(try(solve(0), silent=TRUE), stop("Error!"))) # Error with an elaborate message: print(ERRVL(try(solve(0), silent=TRUE), stop("Stopped with an error: ", .))) } } \seealso{ \code{\link[base]{try}}, \code{\link[base]{inherits}} } \keyword{utilities} statnet.common/man/control.remap.Rd0000644000176200001440000000155013416034725017056 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/control.utilities.R \name{control.remap} \alias{control.remap} \title{Overwrite control parameters of one configuration with another.} \usage{ control.remap(control, from, to) } \arguments{ \item{control}{An object of class \code{control.list}.} \item{from}{Prefix of the source of control parameters.} \item{to}{Prefix of the destination of control parameters.} } \value{ An \code{control.list} object. } \description{ Given a \code{control.list}, and two prefixes, \code{from} and \code{to}, overwrite the elements starting with \code{to} with the corresponding elements starting with \code{from}. } \examples{ (l <- set.control.class("test", list(a.x=1, a.y=2))) control.remap(l, "a", "b") } \seealso{ \code{\link{print.control.list}} } \author{ Pavel N. Krivitsky } \keyword{utilities} statnet.common/man/message_print.Rd0000644000176200001440000000140613416034725017133 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/string.utilities.R \name{message_print} \alias{message_print} \title{\code{\link{print}} objects to the \code{\link{message}} output.} \usage{ message_print(..., messageArgs = NULL) } \arguments{ \item{...}{arguments to \code{\link{print}}.} \item{messageArgs}{a list of arguments to be passed directly to \code{\link{message}}.} } \description{ A thin wrapper around \code{\link{print}} that captures its output and prints it as a \code{\link{message}}, usually to STDERR. } \examples{ cat(1:5) print(1:5) message_print(1:5) # Looks the same (though may be in a different color on some frontends). suppressMessages(print(1:5)) # Still prints suppressMessages(message_print(1:5)) # Silenced } statnet.common/man/simplify_simple.Rd0000644000176200001440000000410414005764736017505 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/misc.utilities.R \name{simplify_simple} \alias{simplify_simple} \title{Convert a list to an atomic vector if it consists solely of atomic elements of length 1.} \usage{ simplify_simple( x, toNA = c("null", "empty", "keep"), empty = c("keep", "unlist"), ... ) } \arguments{ \item{x}{an R \code{\link{list}} to be simplified.} \item{toNA}{a character string indicating whether \code{NULL} entries (if \code{"null"}) or 0-length entries including \code{NULL} (if \code{"empty"}) should be replaced with \code{NA}s before attempting conversion; specifying \code{keep} or \code{FALSE} leaves them alone (typically preventing conversion).} \item{empty}{a character string indicating how empty lists should be handled: either \code{"keep"}, in which case they are unchanged or \code{"unlist"}, in which cases they are unlisted (typically to \code{NULL}).} \item{...}{additional arguments passed to \code{\link[=unlist]{unlist()}}.} } \value{ an atomic vector or a list of the same length as \code{x}. } \description{ This behaviour is not dissimilar to that of \code{\link[=simplify2array]{simplify2array()}}, but it offers more robust handling of empty or NULL elements and never promotes to a matrix or an array, making it suitable to be a column of a \code{\link{data.frame}}. } \examples{ (x <- as.list(1:5)) stopifnot(identical(simplify_simple(x), 1:5)) x[3] <- list(NULL) # Put a NULL in place of 3. x stopifnot(identical(simplify_simple(x, FALSE), x)) # Can't be simplified without replacing the NULL. stopifnot(identical(simplify_simple(x), c(1L,2L,NA,4L,5L))) # NULL replaced by NA and simplified. x[[3]] <- integer(0) x stopifnot(identical(simplify_simple(x), x)) # A 0-length vector is not replaced by default, stopifnot(identical(simplify_simple(x, "empty"), c(1L,2L,NA,4L,5L))) # but can be. (x <- lapply(1:5, function(i) c(i,i+1L))) # Elements are vectors of equal length. simplify2array(x) # simplify2array() creates a matrix, stopifnot(identical(simplify_simple(x), x)) # but simplify_simple() returns a list. } statnet.common/man/sort.data.frame.Rd0000644000176200001440000000330713416034725017265 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/misc.utilities.R \name{order} \alias{order} \alias{order.default} \alias{order.data.frame} \alias{order.matrix} \alias{sort.data.frame} \title{Implement the \code{\link{sort}} and \code{\link{order}} methods for \code{\link{data.frame}} and \code{\link{matrix}}, sorting it in lexicographic order.} \usage{ order(..., na.last = TRUE, decreasing = FALSE) \method{order}{default}(..., na.last = TRUE, decreasing = FALSE) \method{order}{data.frame}(..., na.last = TRUE, decreasing = FALSE) \method{order}{matrix}(..., na.last = TRUE, decreasing = FALSE) \method{sort}{data.frame}(x, decreasing = FALSE, ...) } \arguments{ \item{\dots}{Ignored for \code{sort}. For \code{order}, first argument is the data frame to be ordered. (This is needed for compatibility with \code{\link[base]{order}}.)} \item{na.last}{See \code{\link[base]{order}} documentation.} \item{decreasing}{Whether to sort in decreasing order.} \item{x}{A \code{\link{data.frame}} to sort.} } \value{ For \code{sort}, a data frame, sorted lexicographically. For \code{order}, a permutation \code{I} (of a vector \code{1:nrow(x)}) such that \code{x[I,,drop=FALSE]} equals \code{x} ordered lexicographically. } \description{ These function return a data frame sorted in lexcographic order or a permutation that will rearrange it into lexicographic order: first by the first column, ties broken by the second, remaining ties by the third, etc.. } \examples{ data(iris) head(iris) head(order(iris)) head(sort(iris)) stopifnot(identical(sort(iris),iris[order(iris),])) } \seealso{ \code{\link{data.frame}}, \code{\link{sort}}, \code{\link{order}}, \code{\link{matrix}} } \keyword{manip} statnet.common/man/wmatrix_weights.Rd0000644000176200001440000000375313416034725017527 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/wmatrix.R \name{wmatrix_weights} \alias{wmatrix_weights} \alias{rowweights} \alias{rowweights.linwmatrix} \alias{rowweights.logwmatrix} \alias{lrowweights} \alias{lrowweights.logwmatrix} \alias{lrowweights.linwmatrix} \alias{rowweights<-} \alias{rowweights<-.linwmatrix} \alias{rowweights<-.logwmatrix} \alias{lrowweights<-} \alias{lrowweights<-.linwmatrix} \alias{lrowweights<-.logwmatrix} \alias{rowweights<-.matrix} \alias{lrowweights<-.matrix} \title{Set or extract weighted matrix row weights} \usage{ rowweights(x, ...) \method{rowweights}{linwmatrix}(x, ...) \method{rowweights}{logwmatrix}(x, ...) lrowweights(x, ...) \method{lrowweights}{logwmatrix}(x, ...) \method{lrowweights}{linwmatrix}(x, ...) rowweights(x, ...) <- value \method{rowweights}{linwmatrix}(x, update = TRUE, ...) <- value \method{rowweights}{logwmatrix}(x, update = TRUE, ...) <- value lrowweights(x, ...) <- value \method{lrowweights}{linwmatrix}(x, update = TRUE, ...) <- value \method{lrowweights}{logwmatrix}(x, update = TRUE, ...) <- value \method{rowweights}{matrix}(x, ...) <- value \method{lrowweights}{matrix}(x, ...) <- value } \arguments{ \item{x}{a \code{\link{linwmatrix}}, a \code{\link{logwmatrix}}, or a \code{\link{matrix}}; a \code{\link{matrix}} is coerced to a weighted matrix of an appropriate type.} \item{...}{extra arguments for methods.} \item{value}{weights to set, on the appropriate scale.} \item{update}{if \code{TRUE} (the default), the old weights are updated with the new weights (i.e., corresponding weights are multiplied on linear scale or added on on log scale); otherwise, they are overwritten.} } \value{ For the accessor functions, the row weights or the row log-weights; otherwise, a weighted matrix with modified weights. The type of weight (linear or logarithmic) is converted to the required type and the type of weighting of the matrix is preserved. } \description{ Set or extract weighted matrix row weights } statnet.common/man/all_identical.Rd0000644000176200001440000000104513416034725017056 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/misc.utilities.R \name{all_identical} \alias{all_identical} \title{Test if all items in a vector or a list are identical.} \usage{ all_identical(x) } \arguments{ \item{x}{a vector or a list} } \value{ \code{TRUE} if all elements of \code{x} are identical to each other. } \description{ Test if all items in a vector or a list are identical. } \examples{ stopifnot(!all_identical(1:3)) stopifnot(all_identical(list("a", "a", "a"))) } \seealso{ \code{\link{identical}} } statnet.common/man/trim_env.Rd0000644000176200001440000000244414306106355016117 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/formula.utilities.R \name{trim_env} \alias{trim_env} \alias{trim_env.environment} \alias{trim_env.default} \title{Make a copy of an environment with just the selected objects.} \usage{ trim_env(object, keep = NULL, ...) \method{trim_env}{environment}(object, keep = NULL, ...) \method{trim_env}{default}(object, keep = NULL, ...) } \arguments{ \item{object}{An \code{\link{environment}} or an object with \code{\link[=environment]{environment()}} and \verb{environment()<-} methods.} \item{keep}{A character vector giving names of variables in the environment (including its ancestors) to copy over, defaulting to dropping all. Variables that cannot be resolved are silently ignored.} \item{...}{Additional arguments, passed on to lower-level methods.} } \value{ An object of the same type as \code{object}, with updated environment. } \description{ Make a copy of an environment with just the selected objects. } \section{Methods (by class)}{ \itemize{ \item \code{trim_env(environment)}: A method for environment objects. \item \code{trim_env(default)}: Default method, for objects such as \code{\link{formula}} and \code{\link{function}} that have \code{\link[=environment]{environment()}} and \verb{environment()<-} methods. }} statnet.common/man/formula.utilities.Rd0000644000176200001440000001714714306544510017760 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/formula.utilities.R \name{formula.utilities} \alias{formula.utilities} \alias{append_rhs.formula} \alias{append.rhs.formula} \alias{filter_rhs.formula} \alias{nonsimp_update.formula} \alias{nonsimp.update.formula} \alias{term.list.formula} \alias{list_summands.call} \alias{list_rhs.formula} \alias{eval_lhs.formula} \title{Functions for Querying, Validating and Extracting from Formulas} \usage{ append_rhs.formula( object = NULL, newterms, keep.onesided = FALSE, env = if (is.null(object)) NULL else environment(object) ) append.rhs.formula(object, newterms, keep.onesided = FALSE) filter_rhs.formula(object, f, ...) nonsimp_update.formula(object, new, ..., from.new = FALSE) nonsimp.update.formula(object, new, ..., from.new = FALSE) term.list.formula(rhs, sign = +1) list_summands.call(object) list_rhs.formula(object) eval_lhs.formula(object) } \arguments{ \item{object}{formula object to be updated or evaluated} \item{newterms}{a \code{\link{term_list}} object, or any list of terms (names or calls) to append to the formula, or a formula whose RHS terms will be used; its \code{"sign"} attribute vector can give the sign of each term (\code{+1} or \code{-1}), and its \code{"env"} attribute vector will be used to set its environment, with the first available being used and subsequent ones producing a warning.} \item{keep.onesided}{if the initial formula is one-sided, keep it whether to keep it one-sided or whether to make the initial formula the new LHS} \item{env}{an environment for the new formula, if \code{object} is \code{NULL}} \item{f}{a function whose first argument is the term and whose additional arguments are forwarded from \code{...} that returns either \code{TRUE} or \code{FALSE}, for whether that term should be kept.} \item{\dots}{Additional arguments. Currently unused.} \item{new}{new formula to be used in updating} \item{from.new}{logical or character vector of variable names. controls how environment of formula gets updated.} \item{rhs, sign}{Arguments to the deprecated \code{term.list.formula}.} } \value{ \code{append_rhs.formula} each return an updated formula object; if \code{object} is \code{NULL} (the default), a one-sided formula containing only the terms in \code{newterms} will be returned. \code{nonsimp_update.formula} each return an updated formula object \code{list_summands.call} returns an object of type \code{\link{term_list}}; its \code{"env"} attribute is set to a list of \code{NULL}s, however. \code{list_rhs.formula} returns an object of type \code{\link{term_list}}. \code{eval_lhs.formula} an object of whatever type the LHS evaluates to. } \description{ A suite of utilities for handling model formulas of the style used in Statnet packages. } \section{Functions}{ \itemize{ \item \code{append_rhs.formula()}: \code{append_rhs.formula} appends a list of terms to the RHS of a formula. If the formula is one-sided, the RHS becomes the LHS, if \code{keep.onesided==FALSE} (the default). \item \code{append.rhs.formula()}: \code{append.rhs.formula} has been renamed to \code{append_rhs.formula}. \item \code{filter_rhs.formula()}: \code{filter_rhs.formula} filters through the terms in the RHS of a formula, returning a formula without the terms for which function \code{f(term, ...)} is \code{FALSE}. Terms inside another term (e.g., parentheses or an operator other than + or -) will be unaffected. \item \code{nonsimp_update.formula()}: \code{nonsimp_update.formula} is a reimplementation of \code{\link{update.formula}} that does not simplify. Note that the resulting formula's environment is set as follows. If \code{from.new==FALSE}, it is set to that of object. Otherwise, a new sub-environment of object, containing, in addition, variables in new listed in from.new (if a character vector) or all of new (if TRUE). \item \code{nonsimp.update.formula()}: \code{nonsimp.update.formula} has been renamed to \code{nonsimp_update.formula}. \item \code{term.list.formula()}: \code{term.list.formula} is an older version of \code{list_rhs.formula} that required the RHS call, rather than the formula itself. \item \code{list_summands.call()}: \code{list_summands.call}, given an unevaluated call or expression containing the sum of one or more terms, returns an object of class \code{\link{term_list}} with the terms being summed, handling \code{+} and \code{-} operators and parentheses, and keeping track of whether a term has a plus or a minus sign. \item \code{list_rhs.formula()}: \code{list_rhs.formula} returns an object of type \code{\link{term_list}}, containing terms in a given formula, handling \code{+} and \code{-} operators and parentheses, and keeping track of whether a term has a plus or a minus sign. \item \code{eval_lhs.formula()}: \code{eval_lhs.formula} extracts the LHS of a formula, evaluates it in the formula's environment, and returns the result. }} \examples{ ## append_rhs.formula (f1 <- append_rhs.formula(y~x,list(as.name("z1"),as.name("z2")))) (f2 <- append_rhs.formula(~y,list(as.name("z")))) (f3 <- append_rhs.formula(~y+x,structure(list(as.name("z")),sign=-1))) (f4 <- append_rhs.formula(~y,list(as.name("z")),TRUE)) (f5 <- append_rhs.formula(y~x,~z1-z2)) (f6 <- append_rhs.formula(NULL,list(as.name("z")))) (f7 <- append_rhs.formula(NULL,structure(list(as.name("z")),sign=-1))) fe <- ~z2+z3 environment(fe) <- new.env() (f8 <- append_rhs.formula(NULL, fe)) # OK (f9 <- append_rhs.formula(y~x, fe)) # Warning (f10 <- append_rhs.formula(y~x, fe, env=NULL)) # No warning, environment from fe. (f11 <- append_rhs.formula(fe, ~z1)) # Warning, environment from fe \dontshow{ stopifnot(f1 == (y~x+z1+z2)) stopifnot(f2 == (y~z)) stopifnot(f3 == (y+x~-z)) stopifnot(f4 == (~y+z)) stopifnot(f5 == (y~x+z1-z2)) stopifnot(f6 == (~z)) stopifnot(f7 == (~-z)) stopifnot(f8 == (~z2+z3), identical(environment(f8), environment(fe))) stopifnot(f9 == (y~x+z2+z3), identical(environment(f9), globalenv())) stopifnot(f10 == (y~x+z2+z3), identical(environment(f10), environment(fe))) stopifnot(f11 == (z2+z3~z1), identical(environment(f11), environment(fe))) } ## filter_rhs.formula (f1 <- filter_rhs.formula(~a-b+c, `!=`, "a")) (f2 <- filter_rhs.formula(~-a+b-c, `!=`, "a")) (f3 <- filter_rhs.formula(~a-b+c, `!=`, "b")) (f4 <- filter_rhs.formula(~-a+b-c, `!=`, "b")) (f5 <- filter_rhs.formula(~a-b+c, `!=`, "c")) (f6 <- filter_rhs.formula(~-a+b-c, `!=`, "c")) (f7 <- filter_rhs.formula(~c-a+b-c(a), function(x) (if(is.call(x)) x[[1]] else x)!="c")) \dontshow{ stopifnot(f1 == ~-b+c) stopifnot(f2 == ~b-c) stopifnot(f3 == ~a+c) stopifnot(f4 == ~-a-c) stopifnot(f5 == ~a-b) stopifnot(f6 == ~-a+b) stopifnot(f7 == ~-a+b) } stopifnot(identical(list_rhs.formula(a~b), structure(alist(b), sign=1, env=list(globalenv()), class="term_list"))) stopifnot(identical(list_rhs.formula(~b), structure(alist(b), sign=1, env=list(globalenv()), class="term_list"))) stopifnot(identical(list_rhs.formula(~b+NULL), structure(alist(b, NULL), sign=c(1,1), env=rep(list(globalenv()), 2), class="term_list"))) stopifnot(identical(list_rhs.formula(~-b+NULL), structure(alist(b, NULL), sign=c(-1,1), env=rep(list(globalenv()), 2), class="term_list"))) stopifnot(identical(list_rhs.formula(~+b-NULL), structure(alist(b, NULL), sign=c(1,-1), env=rep(list(globalenv()), 2), class="term_list"))) stopifnot(identical(list_rhs.formula(~+b-(NULL+c)), structure(alist(b, NULL, c), sign=c(1,-1,-1), env=rep(list(globalenv()), 3), class="term_list"))) ## eval_lhs.formula (result <- eval_lhs.formula((2+2)~1)) stopifnot(identical(result,4)) } statnet.common/man/as.control.list.Rd0000644000176200001440000000356514306106355017335 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/control.utilities.R \name{as.control.list} \alias{as.control.list} \alias{as.control.list.control.list} \alias{as.control.list.list} \title{Convert to a control list.} \usage{ as.control.list(x, ...) \method{as.control.list}{control.list}(x, ...) \method{as.control.list}{list}(x, FUN = NULL, unflat = TRUE, ...) } \arguments{ \item{x}{An object, usually a \code{\link{list}}, to be converted to a control list.} \item{...}{Additional arguments to methods.} \item{FUN}{Either a \verb{control.*()} function or its name or suffix (to which \code{"control."} will be prepended); defaults to taking the nearest (in the call traceback) function that does not begin with \code{"as.control.list"}, and prepending \code{"control."} to it. (This is typically the function that called \code{as.control.list()} in the first place.)} \item{unflat}{Logical, indicating whether an attempt should be made to detect whether some of the arguments are appropriate for a lower-level control function and pass them down.} } \value{ a \code{control.list} object. } \description{ Convert to a control list. } \section{Methods (by class)}{ \itemize{ \item \code{as.control.list(control.list)}: Idempotent method for control lists. \item \code{as.control.list(list)}: The method for plain lists, which runs them through \code{FUN}. }} \examples{ myfun <- function(..., control=control.myfun()){ as.control.list(control) } control.myfun <- function(a=1, b=a+1){ list(a=a,b=b) } myfun() myfun(control = list(a=2)) myfun2 <- function(..., control=control.myfun2()){ as.control.list(control) } control.myfun2 <- function(c=3, d=c+2, myfun=control.myfun()){ list(c=c,d=d,myfun=myfun) } myfun2() # Argument to control.myfun() (i.e., a) gets passed to it, and a # warning is issued for unused argument e. myfun2(control = list(c=3, a=2, e=3)) } statnet.common/man/print.control.list.Rd0000644000176200001440000000126513622373301020056 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/control.utilities.R \name{print.control.list} \alias{print.control.list} \title{Pretty print the control list} \usage{ \method{print}{control.list}(x, ..., indent = "") } \arguments{ \item{x}{A list generated by a \code{control.*} function.} \item{\dots}{Additional argument to print methods for individual settings.} \item{indent}{an argument for recursive calls, to facilitate indentation of nested lists.} } \description{ This function prints the control list, including what it can control and the elements. } \seealso{ \code{\link{check.control.class}}, \code{\link{set.control.class}} } \keyword{utilities} statnet.common/man/Welford.Rd0000644000176200001440000000364314306106355015700 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/Welford.R \name{Welford} \alias{Welford} \alias{update.Welford} \title{A Welford accumulator for sample mean and variance} \usage{ Welford(dn, means, vars) \method{update}{Welford}(object, newdata, ...) } \arguments{ \item{dn, means, vars}{initialization of the Welford object: if \code{means} and \code{vars} are given, they are treated as the running means and variances, and \code{dn} is their associated sample size, and if not, \code{dn} is the dimension of the vector (with sample size 0).} \item{object}{a \code{Welford} object.} \item{newdata}{either a numeric vector of length \code{d}, a numeric matrix with \code{d} columns for a group update, or another \code{Welford} object with the same \code{d}.} \item{...}{additional arguments to methods.} } \value{ an object of type \code{Welford}: a list with four elements: \enumerate{ \item \code{n}: Running number of observations \item \code{means}: Running mean for each variable \item \code{SSDs}: Running sum of squared deviations from the mean for each variable \item \code{vars}: Running variance of each variable } } \description{ A simple class for keeping track of the running mean and the sum of squared deviations from the mean for a vector. } \section{Methods (by generic)}{ \itemize{ \item \code{update(Welford)}: Update a \code{Welford} object with new data. }} \examples{ X <- matrix(rnorm(200), 20, 10) w0 <- Welford(10) w <- update(w0, X) stopifnot(isTRUE(all.equal(w$means, colMeans(X)))) stopifnot(isTRUE(all.equal(w$vars, apply(X,2,var)))) w <- update(w0, X[1:12,]) w <- update(w, X[13:20,]) stopifnot(isTRUE(all.equal(w$means, colMeans(X)))) stopifnot(isTRUE(all.equal(w$vars, apply(X,2,var)))) w <- Welford(12, colMeans(X[1:12,]), apply(X[1:12,], 2, var)) w <- update(w, X[13:20,]) stopifnot(isTRUE(all.equal(w$means, colMeans(X)))) stopifnot(isTRUE(all.equal(w$vars, apply(X,2,var)))) } statnet.common/man/control.list.accessor.Rd0000644000176200001440000000172013416034725020525 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/control.utilities.R \name{control.list.accessor} \alias{control.list.accessor} \alias{$.control.list} \title{Named element accessor for ergm control lists} \usage{ \method{$}{control.list}(object, name) } \arguments{ \item{object}{list-coearceable object with elements to be searched} \item{name}{literal character name of list element to search for and return} } \value{ Returns the named list element exactly matching \code{name}, or \code{NULL} if no matching elements found } \description{ Utility method that overrides the standard `$' list accessor to disable partial matching for ergm \code{control.list} objects } \details{ Executes \code{\link[base]{getElement}} instead of \code{\link[base]{$}} so that element names must match exactly to be returned and partially matching names will not return the wrong object. } \seealso{ see \code{\link{getElement}} } \author{ Pavel N. Krivitsky } statnet.common/DESCRIPTION0000644000176200001440000000240414433433333014734 0ustar liggesusersPackage: statnet.common Version: 4.9.0 Date: 2023-05-24 Title: Common R Scripts and Utilities Used by the Statnet Project Software Authors@R: c( person(c("Pavel", "N."), "Krivitsky", role=c("aut","cre"), email="pavel@statnet.org", comment=c(ORCID="0000-0002-9101-3362", affiliation="University of New South Wales")), person("Skye", "Bender-deMoll", role=c("ctb"), email="skyebend@uw.edu"), person("Chad", "Klumb", role=c("ctb"), email="cklumb@gmail.com", comment=c(affiliation="University of Washington"))) Description: Non-statistical utilities used by the software developed by the Statnet Project. They may also be of use to others. Depends: R (>= 3.5) Imports: utils, methods, coda, parallel, tools BugReports: https://github.com/statnet/statnet.common/issues License: GPL-3 + file LICENSE URL: https://statnet.org RoxygenNote: 7.2.3 Encoding: UTF-8 Suggests: covr, rlang (>= 1.1.1), MASS, Matrix NeedsCompilation: yes Packaged: 2023-05-24 06:07:22 UTC; pavel Author: Pavel N. Krivitsky [aut, cre] (, University of New South Wales), Skye Bender-deMoll [ctb], Chad Klumb [ctb] (University of Washington) Maintainer: Pavel N. Krivitsky Repository: CRAN Date/Publication: 2023-05-24 16:10:02 UTC statnet.common/build/0000755000176200001440000000000014433324632014326 5ustar liggesusersstatnet.common/build/statnet.common.pdf0000644000176200001440000101551214433324632017777 0ustar liggesusers%PDF-1.5 % 2 0 obj << /Type /ObjStm /N 100 /First 828 /Length 1560 /Filter /FlateDecode >> stream xڵXn:+l) 4(Elg䄲\RyfZ̙92y,`Rq᳄0`c"LĂq|\Lb,,cfEQDb<=H| 1=1~0 !WD1 >LJ0)C k I^U/L CE1_܉19^x @"E텸 `q@][!x ߥ!~ S B'0hN$2^LƁ-$Yqh2 fK=EH!Cļˏj`#3__ D} ,T#6r@-B~ l>@ d_q'PC&d6Lz8bR (K)Ē.E~_q%JNvP s dDd)X 9$ފ+|zp]),J A _ >O|` pʎ vq.moZv񙽻*uZU].s2K5>~\n=KipoICNAٴFmA; 4 d;՛gWZu4'VeY l51oءNںȐ}{pm4tƮO8^d:Ou.Vo„'˖Y3E$,meIh^%8.^i7ܦ(׆Qg"UzԴt6֌@awƨ>5bObW7ǎK|m8|êv;U?U]:Jp7q3&ζ[Ϫy;ZZ'<1uWűc7ɦwjp|G(}|V6ȝe>4g("8V}zY̽V{@<Kשn(KָRrrhڵN{=יODr[pp<(Սy֥Nu_998^;6;;%zdZz^$SϫEp^ڭ_QXΉV?iߔƉטaedUz8өa[feFkUX}v }[[KU8WX/ZYNfpN|xcfr+Hemnz|tgNs^ endstream endobj 226 0 obj << /Length 1077 /Filter /FlateDecode >> stream xY[o6~ϯ,,yu)k) CJE ߏ)J./@} 7gl: = Aa-JRأqbz{?잭` 'HTDU[zRl4%@xz? jqx&#s'i#$@1a od!tOH?iB8hiԯL!8Iw6L< 9!kYхICbE"9Bw\!"@Q!hжS+j#5hm(Z[e"gna +K^wR]k#TՌ?s襛ΌWxFNWZo?Λ:ypZH=pkū" &;B{ss Џ]B!.]Q]]_"!0RӅ)50HW鋙j8\Vo/IΝk1|+D.s) _snEDQC`wod8 |ZqNLԜ[~DZ:ǦdG Э(tB ~h4:C! a{\H#QD!BPbSdExxb앵3u\V4-WC;f۪$-}w  ikՈc B#J5~@xY89-dkNDV2Y- fQm.]c i<'z ge*nЏ24>o7'`Y|q$I@7b_x'HB=e϶Tw}dx$#观h<z;plŖ{3cW!cFz8(lw}_ \F endstream endobj 283 0 obj << /Length 948 /Filter /FlateDecode >> stream x[Mo6W(ĥH֢E(F{-AHɿ/iǍ(Ht.0hIxo4ސ">"͇OGKAEE)!e" &m})sX\ d4ÌPwӐ<"(yF]PNfNV56q^x*ʾ|?HBg}xn,zDþ {3Ǚv)(VG[=esRFB[Mv9u7 Z*,̚RcY]e' ߰-> stream xV]o0}ϯ0D=GÀ i& "H2ljnt*w}|E`住sA9r 0< [?L,M[|qr&8hvy,=,~xX <J ҥw zFFWr N@P9>ovǖE0bB=6ZMp%$UUͨZV6\93Ti]&F;g^R҃m~úQd1R%QUiYryɹr I?)V:p49&i, >CF; }E (ݾ5uUtGLcvDqU}6_ucW2oæbЈusv67lƣM0aNwM1D95!Ay+,rߓu(kz$[؀2ktA ym;{mKփ:~+c&4Rw6A'UexB&6^x=Yv=t| m!id!=I8P/,avp5SylOWo>Q endstream endobj 345 0 obj << /Length 1291 /Filter /FlateDecode >> stream xڵWKoDWDepxl," l(=Iu c[<;Lb.\\߅"FqHf #b.Owp}D()*sgu.\`To`7n%޾=ʢ;9"ZXw߼(D1M\{/4Wf֭'3V!L3Nĉr04߭4_a% (C&1WCTɓ,R*]XTT݉6W֨S OYx֫ʦ.U"[|>K#X@]U]Hiʑ:A(RzLṶxo ']:m wL;wsȔ#3_5O,108gY֮: 1*h=S3/+F@TW3D1CZ 'H-vh ?{-Ů)4 UQ艦ScCkNGJl{̺݁^rQH1bũntSF&c>yRrfc¹?)-*Iu8:5j dsbcfDA?~_y+'Ch8~la>Gk4Mt0U [Hrpӳ}4  4K~XgJs4*S| {?eioflj=1jߐg15j ,lr `XarގOJB`R}(f]N&𰎆w(\ο{~ >֏OPU|]+7Kʬ] E  \.PXk;^hX {9Lb-4x 3vxb twlm>gyE݁KHHO־ԎwZ{\qX:ٯ ڛtc3S!zH^Fɪ"(쎘 B_}։mv^RZHn;kvs+<7 endstream endobj 354 0 obj << /Length 1007 /Filter /FlateDecode >> stream xڽVK6W{C =@Z HWmJrwg%E v$cr87"/͋7I2 &n(!G%b3+M owo_D7"'%k qw7DhU$1f@issKPoe)7'$ Wr5#2N E"N1' =7]b8Kue1 Ɓl[ٍ};٫/Uy,s{ j  d>ؿ'9;e}+6 9|^ZJq8^~U}ޕP6 MTmiS-xz*G~BJU9GnVagY4zyPa|ּd|XR-<nc;YYpZ.??\6} םp>"/Atkh#NU>K_HұQ-?F1c?LRaΩ:,w.p\̠A7i:Gkh앀kXzjNmte9$, 3꬞Se-33dR?KR0v=mڵ*A7o0QzS]򤮌%6ygP6i}LesUi &Y4':' fP dtXȏ*M=tMJ3^?w!O`@oGnnAr[֤k^K 6⠩쉮+Np/Y;wtU1$-]}3++䲪Ƒ?& xrYm\7yswf:q]00"U`tx ie-ǕB#= k2:*]F~a9zuem|{+J onօ+d3MM$o1<׮ - ԃn·I״])Bk[WP~toqǂ~ "(;O /x6?>CdL77[XG{{i栌+wocne/6w{GvJ5Ne~`0|p< endstream endobj 203 0 obj << /Type /ObjStm /N 100 /First 886 /Length 2142 /Filter /FlateDecode >> stream xڽZQo~_GK gB$Pk8zp#Թ3~t+Z\?3ɣD!Jf(Z` -4T&C_[5̗a얂j0^FA+Zq l, `!4> `tCbj}ւY0Y#7` k¼3iZ|=0_!T<`p^x@wb欪^^xM &)3%UBK䓚3=bXY<8B1筡Cn ?Rd^O1X(96 ݾۆ|sw)>KJm̿}Ŧ& Wrt: ?}^ ?l7fw%WÛt}9o ˼ *.֗۵ܫf Uz.s/KezY{QGNVw4^/Fdz/&'>]x18it'NWrë||?/~>_e>~5n.wvj}pJdmuxn`^||QFǗ%iWl^2[ *pȣs/!q^o1ENP"B>W0<$aCbw~^ z!7,1)c'`)wl-'PjDCPxxd} X1G%!䈐Ys[QҌC<Bǀ/ӮO>ӮO>볮Ϻ>볮Ϻ>볮ϺfcN,aENd_ª5V[ fP$bǠmcd^ĦbՙĖey wY'v`) ey H3APӊP О"ckAS*V'vPDPLPbǨ'[ &dl |x( ۠I*۠9Iˇ5jޛA <HB i oBDSli m&P"L쀽Xm3sGaM LsvX>:H՘'0J'reP LU#8 }bh:g i[3A=e)1I} *V $j!ߌd I&;$|:d]PmsvX>J"a8J:Cd(IA3 xA;H|$ 2ܰvsvX>NkurÒY1dWMqq|_knP2g _Pj e'Tb)W `La*+v>9˞_ONcrgLv,}9 {3iI+VsiMF[y؟KÄaV@a$f.j endstream endobj 371 0 obj << /Length 1831 /Filter /FlateDecode >> stream xڝXK6 ў><&Mci%thf#KD_dI+N4A y軻w/ߦIT"it Ι(wUox4Q%q2~J麿f-չC;MƲ^x#3Tīv-t0Ͽ/|smD"~LYʊ\d;ȄMڦé.mjھyrOMݚ(Kstz[6S`&h +8<3ΞaUe%>:gm`h /7wܣ9;?lV?\CE~տk5-Oӟԡ<'6J1f{iFG.E/Ƃe\bލ1"l8,ޘ }K^c)365J!RxЂPbx"Bi`:=vz\3a㴭1ΏǽE)Vn^%$! O2eI&{ІK?PMGVV>sbLhpѴ`,Uil5)V'vNǹnKMV\>W r9=dIdOݏv.@#uCUbM*q 5\Tv?waz{P>A;PDc !b &{31G F87J8sY 2ǁ.s!G1}]BOؑuK(hg&j\b:]%1BsUEoô24 4p.I8MVZ(MC#NiwVG0PXض`p@B/0nB[뜩3&qc]ȕNJfY|{+|Pu/pѫT2~"31*7g÷/qȅo$!jnX#YA_qʼnBq#.*4_ lS2iA< <פ-(U c U8ӽT+bb'@[5 L_-5c)ʖjbp4k5XL;b!1V=5&X3p+.+bIyR\C?bN[[ x=.{1-U(!:_5SLU(XҺi^Dw|!gQj]Anivxx?>dzK8r5 +X6 w!Hdgnz endstream endobj 389 0 obj << /Length 1437 /Filter /FlateDecode >> stream xXQo6~%%Q!ۚ^֤{ɊBhG-\'~G)[:"@twʣ_fooD%$ػ[zRF'#qxwwgf[\Wien71?ј8j?Q%|{}L亞3vUMo&Ko$Ikpc;ELٙ^V8ڤm]<\Ծd -z, @ĸ!rԜq) #;d gFUIvQd{~ީQVuJ\|킝^BY?ξ!K, }}=_at=rAr5_0F%d"~g`&tڧE`u"Kqmdo!9a4I |]2?f nu3y}»Ǻ$6O{^A ӍE" A^{~%q<\ G5#fSOWiMPu44xZ=ƁEDg`*[$C]5Y]lۢ*$dyk?Awi-U :C&+-K bˢ\]Y|5z92Щc~fFԙ?љaHLBVs4m(`"\g[lX'8(;Js̎;W5Jn&V՛]ScdiȪi]f8hߓ.VEW9mXRѮ.fΗcD!w:mpS* W N Elҕ<$/dԿ BN[!#@D`FLp,7Y8 Ԅ|/pC9}Bȅ!s4 t N#POLH ar> <CJi6zMS.*?4wh +ωNIȎ7ڭiuP!&λ+0^(>P2ųg5`]4p~DRY/O#~riZ%8ӽw mHK}>LvW8^3_{yr|r$~+R(2h<j&(Ae$<7bT‡J_#T~{"F[ Ya܇A{]VN0J^rVMF z5wFG9_uW~V6嶛Mo8~B $HA }\Zs`ՕV=nvZ*mb|`y6v%RtuT{ZOc%d4\.s*{/7޾4z2PN@L׍K:~ӟ;lI%2m?BB[?‰x~8|N!V,ͅWN./4n_w/=:"/ԯ endstream endobj 405 0 obj << /Length 1133 /Filter /FlateDecode >> stream xڝW[o6~%)Q`ytV[-:Fmm^$[Ez>O ~ k7E?Bz574og\z.޺i7@I(ݲ\;h۹R׼p]-vl4&V'G41g%AQ$2hlVn՝ qX7xo)0}{e[ W޳<:E,@H]ƿ (ϳSh @cZ8gh&!8\lLŝӡsev3 Yu\uJ8ʙ(XH(=?<& "25yqIߏ;)q'l"͋N ϸK&<ؿ<[>!.;|-^OJkrBIm endstream endobj 424 0 obj << /Length 859 /Filter /FlateDecode >> stream xڭV]o0}ϯHkl>dZ[l/mh&l2ݿ56ReTUc=>" R0fPR,f t3) jlw [/DH0Kd@!AhW=VK(Q8C׃ !$("Hp視 ˘|25j,զ[\(@epJ^MOg(j`e*"n ̃SQûԜ>l+?PZhwMR4_&=L)MH` ErV_RM/jу}BU/5_Ѷ@gW,US_:Kv.I[‰sT1mr*['!ȅr;RMO}th%ZUMwupK"A9}nN%Su-jLY.a~WT\( JcLciƒl^Ӽ7UH7hЙn/`t 5oͪ(m麹|>cF|z1?`w}_OSj1 |M3]i`1*~k;o47xWvY?%M`T(P?˵7w[vЀu>-c;3ٳ \ :^I=u!' endstream endobj 436 0 obj << /Length 1090 /Filter /FlateDecode >> stream xڽW[o6~ =@͈7]abaɒ'Qnw(e^tE;|“Q~ZnD8h+D3- 1 훘dicJ?S_96 iȀfaV- : %6<KκJW< P=Z)jOJL9?,T+;=((&?T:Jg YJU>ÍB91XOb 糵2Td!jj/A[6P"+yJoٕFꮩ|oOtk gvyzذ$nLܨWS*䔆 Q~̶RO/ 8u%] #ZXP"_,G(GyP !_2;F7ghuS+8lpRڣꍹ}TῳýVeig5t"ؙ՗3~Z1M7/ ⊦`%'E 1?ДᘑMQzޜ-B vաmzcg۬*jT-2P !F_?6<*ќJѷ9=%7n` L>|kri?\]|*}Qwr~&-AfrS^ײH%N"*=xnnՍyλ¿Cs^S_?ǂ',),x1`IB }+ endstream endobj 453 0 obj << /Length 1372 /Filter /FlateDecode >> stream xW[4~ϯ``U-[faa@]tlg; ;Qm˲t.';+;?LM>K"'EilQNBԙ-oj>ZQhoOt9% ,]%l|ڡ#,Bw/ ,΁7 C&z+n0DxX/؉vA]mo,uwCJn1 =B9 w(ig>wSʜZZ8-B#Cu1ek(@C+T'oh[=2J# W+Wzr-ysP`>6(Pz%oN5E=*$=Yw1^9Ցzr-Ii9<;Si&k =gH.DI=նtڮf@+zuU"`MkfET8쓱TKRGBíMFOr^) }2+!GFGw@zy5Kb(!v2H OfT_cTt z o(k!:^x4ga笜Κ7nb1%*CfįVk dB#l D)9rs`M94z0Y\e,:I<ΡSNy8Hݱ,^>cOAꥁ W:&< M[#e;E0H5EBt'^#%@K!jy`slFrwŢGքb x%n?yY}]zPo˯81iU$;o*bLp#N ( 9-[^롂LuH0]Aop4ɶ|n9[n3Г}z7+\|<6 T-8Pӆ5nEh߃o'_d#dHԸ#cSN46Pb&]۬-yUQhN#L Ii endstream endobj 364 0 obj << /Type /ObjStm /N 100 /First 878 /Length 1689 /Filter /FlateDecode >> stream xYn7}W}ȹm(<5ڛ#3+95HAÙC-F%<8dƫR%v%YBnNk){tL*h`r(-2[ ?&7`6"Y& YX&`*0b"f-(aA-Pš(7F#rʠ !H[0[,&4V W`X0Uk:&p#xP4a⣫ |Ԃ7 _km"wnq&1u 6/+B1/Ӊ ;ٷX:tTH1̌V *dlp jTi"޻*qlu`|km4mMCYB,h¿j0>C ,?{cCx%X]ZqK %!>ƓU8fJ(LO$H vJp/0cul,gw&ZᅵL_,r24y8/Nѵ XQqd@D~|t0qf#eJby6_KL9*>&W Α6OS1 V%obҚFCu1jThaw,fD*EAz,Fɥ"Vޒy S{ZYKVVuj]j$s^P+s*FΥl5(HI1ױPKf1S{nՇ Ҙb9pf[k>*9[ ©CNHT]`N0i f&cqQr=Wŏk$Eޕ?Zܡ(>~bxtfT*Nr8 "U =sx>tbIVTxKB GJLf takrbFF$=l;Q[{jKD ݫ*n6 {BOʝ4-u,]rlFj>~NnH SӅ6E m !<5Q_>B#buywMh@I_Ui,R㋈xȲM.N*swVqk>報+.5 L U67ש(Se{SUʔIJϚSN,+%F x%g( >|x5\,j8ݡPA_ߵHQ(pl> stream xWn6+6fH(,rHѤhX])Vmt}"eK$@=pO~]L.o#$((X,1, bBPD`wS^ƬgIyB&/O(i6v.o]?a /sU6Ohf+YSlLQo/IZ];b9x _j7Fjlh<$(!mިR7ogYLXG+QL Dִ 3 eu ;QHAT0%tt=Ok%e-*0ݨ w܂fܬ0=͌նʠ38߂(;AQ.DQb!E0'E}9 }\Fm a'38hȒaFƺK{_Cp~o=b8C ;Rl6ifd3§23u3|zn\&njSJzjԦC ޗ6XX{`^|')' \]]\ #y  YM>'b乬r_ kOx@l_Lzf'eW9;_:m| G ;D\{yLlq9re+ݭf]y %>dec18vO1Gx8: 4A4)s~`-Ǐ.'7\A>m2ֻ;kbF"VV~B?=Y#ӳ2ʇnB>s4%ׅ 8i0 9sAH"~7upD#gke}X+ȥ4ݖ] 5.u:F-<0Ҫ'!>Eǭ4N(@"ᖜ(:5TXD`ьA+q(ǮN|)|>nfd*#UHmzږW~t}z[ݽt5. [i;=P_O> stream xڝVM6ϯ*CUF@"˦v|3vfz 0zOnu$]Y~ CycP df| ա*8|l޽~ĉbR5I =v%(CY>$t71"Y*wwk;-/eٌ)HcDx6d-v;U%*(("<~RɃڍJUrwuk=̝]UWb E.KS}_T{ քq$AsoUNHv }*B֠;Uw PI!!>x| n~H˕0M+W~[@bAzXՇ_0$`@1s\Z=Q50nN҇;96,+' O*T`bk=1 h UEu*h'>k`M:pɽJ YV8l e1Nvo?޴zJ¿4YwmX\YfGjͬc˶hq\78JQ֡ܡ-l]kxD1T ݨԿw0;@脍z{E!!> stream xڽWK6W "%1E) urIsmz–\Q_Z+v  (j8oq|Q !őKHw HF@i#3)?Ԣ# L磿G8 8IE܍| >~H 'L+?Z}OF1#ADy:wNQ$R⃙ɺ$$7.ĘVcCUۍGIdvRr9.\#.fo%sr7cߋȐ[WljruѶL+T Ps65Ҡz r4 ^jXĽ,eSԲʋ'k8+\3ȉ&7 B @<$<&ղu^#I HQuS,xc + x[7=q-c^ޚˊFvL£} ȝ0(7@8I X6TuX*t#Ag }v$p_e5|>mnFRow (wr"]M( M'=A]߹> F*p@1 e`JA_ץ}.{KёSS_[$ 3\ʔ$R~ (k-O.Nc:%t0e(v#bc]C^oni21~Z0!:T%6hWrLyM eZ( tVZc gC@ajw;Ƚ]AT';ݏED`;:ڃ9 ~j084L\6.p-w󗺃F-z6)a#+!%Q|CoR/OuKḟƃDzٮ M#6l=x[ v kiz9:-h˲ӔR䔨z=e^a/7DRByZ^=^ xL""AH?/te/47"Gt!y8&']3v3VM-/1}/\u=VZS.P1&մz{Cv>j;j6 s w9:ź \WW`mUSroC|/٧y!j/jƄ? ]ھ+&'lQVzژ\Xғ]di⌧6f}猠+3Qn ?Ji9 endstream endobj 515 0 obj << /Length 945 /Filter /FlateDecode >> stream xڭV[o6~  ^DJ*lkC;/m%UlQ. E}BFY\\\%1p&D`KP%в@Oې@݅L ?//8ҍ I FdAFW [ދLbeg xSoVtb$9+j %XI`bLTւpB2trR"ۨ! rKvv%KP7ʦ<qS]Xr.mPϻ5=^h"0){@&[ boj[ݹk5ۺ=NQF{aM,63 OO2+,)bUǐJ K]ʭG+2% 7=i9簡8bA܅yPJAtu_J,%~hwB ͣ Gr.u99sv ˮ̵YF^E\I\)NEoTU=u;(x&8˲1 ,iMʼn"&Wk=>|Nc ֓>)vwn?zD B_ܲQ=wǵn.ϜA9r 37y(c9+ T^ c]4t(wٙru?<$#lw#4J$ {!skCP`Fx846C\?,\:b`?Dȇ x U+c`s *IU/ߑAB^Bz l"(>/uSCur_0_hծ|~?Cc#δ*?{jt/gضElZig.]YX}.@C>OoM=tM0~"^ïӢ endstream endobj 528 0 obj << /Length 1555 /Filter /FlateDecode >> stream xڭXK6 X3DRZt&v$4LȒ+RqA{JZi |̓ޝG?.<T[m^=y䃝`d1U~ú \.0;z b$^zkX|RxuqPb#ۋ_kC3%3O#,8Ά$Mzîdei,˜YPk#%" 2uҗJuw uR5Ҡ:bWhVTw ~ kxB| >2𡙿H7^pa3/,j[(0ڴU$*u$^suÛS,9q>kӧAc لHI5WF5[ vVT`W\tgևj]a sa3pqܓ),ecB߷UY|e:[V,ghB"B;&^+O)Flp2ƺbtq\Ĺ^KuEtl AhQw*D}H18cƺl&~pexAٵR~_7A'7.YS[/pR6Mv*JYKYYuʡ7^F6`AhOa]IOCm0<ŻD.PN S]#?drH`$)|vw tWɼju<)}]CmDC%rVrF bg5wXc˼ܻ[̈P'u)q.é}i@h6n3Z*3 yscs=b9O3ȗ$ { nxJt[lqJgR-0U 'N4a/nX^!]eL)9G ׾g; IkRWNǎO&/FC3),#2|k Zҥ@(<DŽҡA!fKl>D (Q~DIn P=H.rLdG95Jn|7E ,gc̠)kO#uT]'p9LQaq}!JFR4o`@PW'p֧bui})!{PѧSS9/ky 7~ S=IIDSnCrJza[ KCr 2[pmpe(f;Jشϔw62>3reo =0.Ŗ&G®ۑ ]/Cн`1wRP! >UkC w.sn63oQaT(YXÂw\cޤ-s l%.h*oNmMחu>lU8G|&n]^%p\!Q$~ RȜ_swC`-ߩ~ endstream endobj 541 0 obj << /Length 1457 /Filter /FlateDecode >> stream xڵW_o6$1KJ"%aC%@t/]6ms%W$Qaxw6gon$I."oF):nfߕZUVI=r͍'HTs2NیlP!RAha][y >H4a^wS?%"a9YzA y"g覫V+=_D(;滪sF+Kk Rw vroոi ]݀,X[%dOgpS-XJԫF])Y,XFDfO^NNG} wN9ײ8,v{馝_U-Jvq(V_E) ?$uIǟDq8j4qM9EL ̌[z\W;t{{e[c+7*ԕjȻy{{w=)PV VT]Y3H;nV=jcFba bSVޕ5ba?hJpIƍg =;˗,E›zO`{)CIt{rVQƃ{x񚬊z//+? Ƴi l}бuiҋӁMM=蜰xx=u2I8\im~bb" 7sҮ\x2>BЇdO|H_bVƆ/P$9`{&,c!L8H fN|IhF]ԸAh,U?]Oؘ4Qȓ0t8WwSE:>lkpy]{8p-l0?Yu endstream endobj 563 0 obj << /Length 2357 /Filter /FlateDecode >> stream xڵYKsWc@R{ؤdSMWK6ȡ<ߧ{x䊖]: 0iu+^=_ͻ%W)IS1B4Dtu[+߷wh%$Tf_ǮHE-ob0HƆ 0 ܉"L6TԊ qUeV7LQVi=tGS Yo8tu g+ߘ*?POzfd^ʍƫʸ3ˇk/j_WGrEo플GmYm[_TFfۺa> : ~)F:Ve[WE~9TєkGOy]xMS`5 ܀#R:m#>ƪ['+{)tʧ^ hNiE?fXF^0@3-jӐP43a5o¤KKO<?K$OR=es ƾ,I@VNe/ɤD^C@\)C@w1dgJM)Ȩ\C ̺ pgVMyfMe1=u= al+ҎH p W37?&pIWU>}9k+򜷇k݋<>xj[R'އ% ,@OP )q ԋ #ac> ,t/Aȸ 2[ rm4.hxJ/˔XzyLCknc`*|DkQB^S"J.ǡIbRac#m)$h՗/+Ǚņ' z~muh Pbn ٸ2i*mc׆iUP}Q ڻƱ+֪n F+ #$ƓDWY& `i 캣b#"LMHZk|{s̷pn[dMrk]ٱ <{vvH)y!zoii59#2ҽx i>7'$2È{>a {2'h80jz/xJՌղREKЋnp skSy\) [G"ELf :" _Kk`Bע:ƙF|E+vAt )B]!*lK@]X< ;f X ~ _g,G-R$ λӯDJ9gŠYh]_444Omƾ]t$cdG5Iu2+OkŰWGŎ7ln endstream endobj 463 0 obj << /Type /ObjStm /N 100 /First 872 /Length 1681 /Filter /FlateDecode >> stream xYn[7߯2P gHF<@ZQuP*[, O#Yta_>ἇJ]pI"\RqQQQG)ULeǜ- W0$$Ґ29`viE\fW].kr/ՄKv1$LBȐ  $kR#GjPY $bJ RƈpRX(\'jDaU%`*Wv+)[H:٠4H2"g6F_F`?uFbr%S vmV $` ev!MPl#$ a\0XUc BRL3BbJFH5L53+X.&̠7mL4FL02H+M5  ')]rb|cLE @hV[錃.!]1n; ) A2TCw5!ᚌ8PRL)nB2Z\іCaggt ;FtpO.0,+g-9G;Jҹ3A-JXk Wekf7MQ ȵ2[F qEݫxG|%éH 0Ԓs'NfaНfO\;Q]`$&^/ʗնvxZdXԾV_^}{~k}ћ?jz0z>_, OuCܖC=YLo*هT{Xƍ~$hñ_.>=6mb'r[)ƄNK`Z"~`2J#-G-%a8I.Kq:dTXx{R#{y(>K$d zߓtyz(5G/N>2``c"" &mm`TCGscfN6P5-%*t库B~NjOJ :q\PK3 pVv]h'gt'VMrp,ܕh{{an 2Lպ(} 6S gLЍHmF"e1:Oф)"yn,ŌE(pel2{s7hzD (nYTDd?=MI$.(L0'Mү`/ =fAsXmrE;`PoICn'w>pc֍邙9n'= jXe!-"B,Ϧ֐<`/Q:m?"@Ri- w[V| h=&$e='~LL>)*.*\%i!ȓBBF&zhr2j,;j3>x9ilAzkCcqI|Vó' c]j$ _~@ endstream endobj 571 0 obj << /Length 825 /Filter /FlateDecode >> stream xXo0~_AӗVoeR;i:iJ H!l,8kUwww)s)_'P\ZL#uRlI^IXE0 .&_n,h mFe&TP:(f{zr&eT9]n 8ԙeYXDf]ҏ?,940tLhdV۵Y$1Yl9!bqOtMɀo_cr0W)FUpA{uw!N~_ekVt`gĻ}kliw*S}3~}FP~Icp |M:7 VIlU`ΠGh{eNCVFx@7Ygy 8cIDRHĈ//Ul (I1d1eN<;>ZZ+F(6՜dxH^<2dgs psHL',g3:CD/sw i8.d;-<$؇M5l:BqhspS4cnmKiF4_KLǨ/"\ endstream endobj 580 0 obj << /Length 1577 /Filter /FlateDecode >> stream xڵXKs6ϯ$FRU.I#[\[) K~{ZH5*岑~}u8{ "Lj2H:emH/oK6IypOTY.[s`;1o޳8PpR0s2G#"a >̉"˫Hruæ7v \!0CD =nnA/AZc[_ͯgo8Fk(g/Ti}~On#c&I2lf+B9b,.Qܟ؟+ ˏqn;+0iVʙ@J9۴)N:SgN\JCт OYŀ@;vN*?O]7O~`V>\fv|NIn-b}*GB$`H殐Hcza3'seph;;K :yҽpvW !7*y3B)T"* kL[,#:,>ĻUab檩N?6ןNfOM sfSBF=t fzg/tY}'9!Vsrx^Y UR1؆Uf/np!%[ad:,o.)u"lI~3\$hvfy I_oQSj̦ǭS8XP]>t'b0)ϽNU:xv$&5ϖ4?ukx Q C 1yL/ܕSպx ^ESW~Ms^^ޫn|eM[)Ą|-)>32Q!J`kD̞BXՔ*[ _ 2z-5U S٬1^.fݦHJ竢rΉ+@c"@z4&ۄ,l9vl# CnV#Md@]=('%7=X}&"=^!yGFRGc#_)YVxVԦ;Rb;B Cdtm2wӊu%'E&_ "F.:KB;.SR+/zH:b$pc?j‹'E*ڬ)ZKDd=rhT}X/R5ty51k)RmHީFj*J\}侶/W ؏.m &rޟ+:dLZ;OnЪS endstream endobj 592 0 obj << /Length 1094 /Filter /FlateDecode >> stream xڽVK6WP 1D=l Ү{JBhLERg l8<838A~Yܦ 8O#RD9ZW'Z|~6H3BqA,ZdEwտ+ $At1է/U|ga= G,Fw?F{upSFQgt 1gua \ hrAt {P# )7R`KQWVDtVњ0ˆw/b0/4"R/Y ֜/Y{$tLpL x-/T7)6 vOG1+&#n5九 QkWwfF,rÄWǮCFxkBokXջ ucV4~Zͦx%&pj([&Z{(MoP| 5z8pn@4ΰ wu)jr؁+p>#Bx59h׮ELRd,Rj}?>k'n~{7 Wn@g?/v)*ʎ7mm{~S촢A7|3vȑ,&qqlT2dvhM_1lxDS`i2خH@euP9X9Ie]\-s$t$΄@BG QO>N2NB̪ p=tm5U`)BIP!G,M{&:n^G 9sxa`h] endstream endobj 607 0 obj << /Length 1793 /Filter /FlateDecode >> stream xڥXo6_!t{HѤؐeؚtm2 %Wu~wB̾*30fB$`G)f#3ź6/UU ~->Qu]ʵ1X^f+YˬU5ny^͗4!6㡫S я+E²+6J7- W] Q9rUNeިYb+ hsAN`{cGvZmTP=G8Z5|Pl/$p@dQrw&v( e>{7dPVl=z?}0q0VjVUW,H?$UF-)%Z 85 |݅ZθʮhLm\uNF*Vd87 ,rVeKe]MAӘ~KV\I̋%IgaZv1@#l,A>>9b1'T+S8@~͹*Xi:f$A{:l@Wz[اWw7(Mpu@z=%놮ɇ_HsEP?*T zBM0 gиnj =xHx`"Ug .*eP+Vt0 I3#ᇮnГ;E5em"A_ Lx֘HbGS7! ~{l;X(os26|ue>gA8g!§:B8ې92X8pY1Ԃwu1y_uQ^w:yEp  \LFX8pCpWlVh]|aByOtyӗUŒBC Ms9ê!#^rAbGrդGojegNͼĕe;/]'pv cQzڣ '`ڃ4|O^\,QîႠ]-7ϹlԮ#>L+VW{vs{Гۓ'\7:C"'[|9 UtVO];d3C ɟGػWy, #E'x}'w΄⸃pEZDz{H8v2gǃ^`>~(8/LSYx7nf$[uc}VTպgV7x <(Y qV+∦EJzBZgF1!VsVT2|zMFw; gx> stream xڽX[6~_΢ ȴi'e2mz`V`ߣ 0:>xtsgxw0(T@BB`l0u,/~`D唩%7*gS}2[o>%_+{x'J"H)C1IO^0u'[_Wsn+?~QHF.VPmCVY:)gާ9L2XN]C =S6I)еM0`Ä4D X3ݚ[eZ5+fW%1XýʚͶ|OA9IaIДf~iwۭ|+v(xŜK96dU\ !!-sPdd7P*"sU[U4qX4024]4ޏ + ;,fB5!nAWsνڨL-UwY`ϩ2fTzh!Cv*[s1_2_~?BC`GP믚*NyɶTԠm fYy 5T|`ԥ0q]2…Q$)\otf&Zem u#Nh&ںK0J{QRj`Cޘ=KVb/?x2,̈́"^h4H)j1‘q@sA꒘SRB)J@4.lSJYzUs)E$ͰvmprW~S6Fk%EjkmҕmEwv Uƣ`^WS.ɋ+s O+pк md[GڻAo<Q}ѸV+o+RŞy$H% &忻pư +ߙReR׽uWa27>\GP5ֺ/ J+%f./mH?iO]`.CHb"M-x(NKcVUx"WB0[h+CŪlx_V&S(dKS, z&fkR^)֏v34((nHktSy"| }mNвw9f.Pu1Y¸ 4.t$e:|mjKNHZw"nBଛOvN75ë)Uw9n|s?JꀒF%-g#Sगyw *tcvm&>3gD qrecڢlRJ@ ܶ!ХL *BFㄬc0|sգlJ}L= Uemϕ防?>mysHԭr2@1$@fk_=7yVEY.1|VE٨I#hm&'ePt#ӏ(i3F n^fۓL4, &%JN]R۴F(1 Fm/Ow5:2+\5'"}c,?":A endstream endobj 651 0 obj << /Length 1245 /Filter /FlateDecode >> stream xWmo6_!ST _2)0lV;Cd魒~G%Es&E"%Ex;bkca|:"#%9̷k˯_n\Găc-ieϰQruñ停ÕMq`"Nƛk ~x{i I71a$PPeֲzwsڠb|#_;Tu^wY^$A6HGXUUZ}<;m7Pkʖ+*Z1dʎE(\G?Uj,/xpOʓ6ĕ1u ns_qݿr#x~xtxZX;go3-ѓ`a.0}5Yfkjq`03'bgGG@`N, )$8;\o NoH&*fwW˰@9huej_dq>wP(zgx[>r} ߡ6ThpQ)"B ā.RYG{3Qq噽,㰋B1Hk!9L:(8 VC= CSр4m@Yq\D18"@c1vWe($O_~m1^_: q m*p7ml$y=B7Q -˅'pa_ *n8lY~}q*:ˏQU84k(x٦2&5yu :GCC}He:@xƅXU 1zg vN?ց n|ۏJA\=3 2ƵH# j6ȉQU'W$;:&=4Ouv9<d#`K΃d+JNQAt)mtk*) ˻,FyhːRImӕ41Y nU]:Q!0Չ!,P9h,m~2!BD B#<dFmހS ٹMpEf xe214__0rSJ=0sn8zvB `an ?9}@HSXqX":*&̓anx Ѐ4=#:!? endstream endobj 674 0 obj << /Length 1011 /Filter /FlateDecode >> stream xڭVMo8Wً X,)R_zȢ&lv,(!ͿCdˎ.|L o;[;~_} 8gqƈ AU煐o?Uw0Aa+{m^sԸ p=/sY_Fȩ_yb3aIpLLؤoC<}4FO:Kk:a3hW$EL6 E xcgyUg'퐄;/\DG}A̎(M7o<ۉ1W<")S~Dmqc6d[~|v y̯Sdό%Q*9I1[c'E`8ri0PɐQΝ_'١T#!?OkZvKG>QG_T|W$4۔v|Q(~ G6U۠3co_3DտB&uV5Y qXU.WN}S /j3ݥY13XFnq tym«A5fڰl&9ғzmt@Ք 0PֺlyLQ`ܭ>^"k  eÒhlr'!d.][i&>NI^+-sx_im9cî~O a?}ZDvUB}ќK`ܘqz|]gťNtQ[i"!F>~=g8Y ph wGϦui~F,I3 fUyAnJǃ5Prs3f#jT =IYʲ]#vTX7%۪7 k> stream xY]o}_K08 hCZ2uʻjR%V#i X&{<Q1tG*:11B# ‚c2L. B1O.03Ao40iJ gNU̜S ۡBTI ZeJ 1AOC4\@XD?,1= kNaLySV'GBl}=t4 ?u:yJP(~P"fRό3,SqƮj"I+aV.Tjxb!dE(b~ۅ_WEXƱ^6t30Ͱ 'a6NXiXm`}p9C?~=;,sxcM;-N[MFXVnq/CS(+BjT'ݛ:Y-o>s۟vbz˰Kw˿,:n/'Rc-n5@eMXyvpzUp=5nppKa= aP(UۣT ' kI' S* =IFROs?@F5K%-9zf \>'/"&+%Jc# 3Pi0&DFXsڠr=| ^9mRuVOŜAڮ/gt5jFxdٳRx >Q/W~u $rd0*X`,z]4MݒLZL{"^ fӄ"H3 ?0[aW84a$ʟ[+Zk{*Dȣy"& 2q837Ty,/I}b\uw{8U゜ձckc[ƶ5-8ASRHzؒl`ZMfgv`%ωJXeN _8ExՃP?-Ԗohi<)LP(FpN0̘hBTpD qPx>,6 JTŧA ED9WP7,%RGExS ԱHk"G4`/A%PrVp"a/: cjGCjlͳ+xtF-P0@ѣ:3_loYRàx_-ߒ|<9peDދory0C/[i_IiU٘(grkswD%BJKS)9Cɯ^$v gMun籼@FQ-f^J)Q7}NA՜Y]  kt?z`{x3 Ѯ.w0Qr/' K٥e$t4>L_=SCAtx*2=kR~>(LӦ K_ܭmo endstream endobj 690 0 obj << /Length 1500 /Filter /FlateDecode >> stream xXn6}߯PûĢ-N HKл ֒+im_ߡHQsouP(-99sf$#|5yRH!%#1b\F !H2]S*g^?L i3 !7*f3V~RitL8pm~_9{N0DR(D gHk(R)iK8,Rӱ <49O`=6S 'B;@tx+ax ->}յHX`HLO-0gA@8b4r=bzougz_VRHHɇ@ypq4FX#tL~륯en#}TB-E ϭY M~sLmV69t^߿{cmgL%(wؓv΅5j7F'iYf"u7w̭  %JMWDB,!Fc|b&T.pj*cUHC<K:-AEҌF =-|šax-h,QQJk^WֲKfVg`{;IYC u=o]󲁑vPm-Zk)wۺ; ]ޝ`*¹Ψs~,sٖJغv6EYoH/J'Ɖ.;?䝢O M|Ȟ+ a`j@S+ aTHrD wㅥ HDXvnVV J9);r:V4ҙ @)+#h=F29.U]v]ݶY*֘' &PX(F$̇nOA_SR\V7#sqQh2=e.ɦط|:ԍ.>F/*ĤTA8V~cmQkIm5pp2u^ߺ,bN3Ojt7>rB]rSҦ|Q S~~TjcGU6h ~dp{8T`ej$mQ > stream xڵWKs6W0EJM;3r;O( IIr}R|L'oar啈%fx A%&{?7]^'a=F -rv B&@# B*$_(W(k4ARv?.CFcm%ZI""ZIƭ21^/]lNbIœ]궩bk\fo&,`30Ywec1[atViWΩfnCxP ?_D b! ap&$T"S_q<Ўi~P'H@>Sa];z,s_ -uXQU5f"!VM%Nm;t^vX?$JCf&ȑD I'!R dc$Q\ev|ܓ\"ɣVy?OPF;J5h-9U7!d&ԅ3JMn>"#A%P; uA3NC2PmrUם;=!z+ w~x!P$h+ՓH@QV_\ǚC z2!*ODB8j6;jʼnZbkE;j=lYjHD- J;n[mB`Ä!\5E  A2}TȨW;74A8OګB-irp=/K:W:2LV~&+ -~dgN@ZiK3.pڔ1ϕ|$GG՚+HWi-;Vs 2¦0nRJ d Nʷ ,DcZ\<oL4Pץ7_"G:@a869gE/6*b1ve+tL`[Bۢ)M}RxmaE؂ GCd$~*3AʥA?}ZCd #2G"kY3 uta R ̔cV76k쐍Ϲ)O=_zЬe,>XڸPGf4o(WۿrY ܎M0xFyC9$%3\ijʝw6Z?xsG?|N4 nd/ %UFDפbe'閦tz n, endstream endobj 718 0 obj << /Length 1663 /Filter /FlateDecode >> stream xڝXY6~/2V$R'>$Ȧh(% Z-5:\ڍ;álɫ]db^yfz.b;۽Iyl %ᄒgx| MV];)!ox K`ӭɏM2F hPkU|'8k3ߋ#g)z,A~Gk] MQ(՚E.]li\\d{)H*]>񾉹P#"OC/&[ uC#[V[D}vv g8u}9?8E>v:H](lfU PV  Оt ܶ5gܚvhRt&ȶ:~V.>2f-0-lI/'4~?珔I/2X'-YnVg endstream endobj 727 0 obj << /Length 804 /Filter /FlateDecode >> stream xڽV[O0~ϯK+Qc;F&(OP%Rdvi߱$-Ovsc#h|9G",@` PH)Rt9*_Ͼ~#SeXMDvIcoX-WqDvH3"Ҭn!L4F_R+GYDm1x`>,$EFN`"1HYvJ) 2hޡ^ endstream endobj 741 0 obj << /Length 1434 /Filter /FlateDecode >> stream xWK6WCe`Pԓz "EY=$Ai[.Ew%urŤp7Cm=6{Nb"[mcFJBg?_^QO2-ӈ5Jl/„4ނm" W-ɚoR) Ʊ;VG`L7Ǚ8Op{枋|p㧥^P`eK- @#w%ײ@7GP*E# kEa?~4A4"uU$>;y]o!~Xy`rSfVlCbH ] $}+Zrh 3C ^=Yɬ#Ip+Q/jV!+ a'HQLS,s$pn{wlDQF[fxZg4y/MDpM0e8^c/Uh\HWe > u~W> stream xXmo6_)/``ҝN4mͶ@nc$$!դϣ׶|sʭ"#fs%q[zg(%I8Y}Nk r=Ц%Q"#\ٶY%<.1.<^m72)mSAm;]|v>4dgLsszդPys{SBh2Ä8^A8+C(6[KMHaL4 W̬D\KRe.6bEOjǁ3)FK`BL ;xVꩃH*r&eQnޢr]E~g*8fqDfG9Ӯz~`O6u%ŐsI+đ7r @&%:{PE"E:M$flAj7:cnqw$U  g{wGUv8`UZAωO"^$;D. gAXA12Whf GHUZ:}*: DO 3ƹqJFy7[=p0o?VEN!V4+ߕ2(#7~#?$ytj<9x6mF |2".|`]Z=3qq: 4p~sG5UVE_k7>(ri'j5Ʌ:pr}[ $HOt!YU_Sк=bSm0h@{Po;&c6̣YrF ewb<1렽Aq<OVGES6΃z!Oʸ]%*C2͢e:*> S5y>2dhG#CE < ¶y>!iэeb45 b ^lƷs *ɽaDpv+U 깎U]I=͠sc>DIXMO ɜKƚ{RTҤahH ,'6,BmF;0jl .4'}EGY$$w NȀ0vg4E㗅Q|Y 龵)im!B (#mG| wtqMvO>(aW]w4(?oqͥrⲀkKˆ2IYiHVyA9[2 =Xo2CSۍB.ub4(9 pW3~2MZWj}7->m^*DzX鈶CO9p#jr yIcxy0pT>۸,O$M~f蟷vߪT-j(C6by(rlj5qz/- endstream endobj 774 0 obj << /Length 909 /Filter /FlateDecode >> stream xUKo8W,z,CX[8#,@ΐ+j6i C&%7o#//SM Z"%-QRqNSY y"eF2h e:cww˲FE3`c\ Е %L#7s9-<ϓl;[5\۰s&lڃ`.BF,(2s^S<ޙcSmrwg͝Wt!!A_64VӂAU<$gA ui81,D&STrh7jX/>-81ݥ2d_ BT9EDAf ݪy[|13*NT^{fO(̇HPP eVDfKUD/؆6Q:Y2Od% 053d!`~c΁O.ҕ]llPi?زM39;2l߾<)H)cGHХG GAE9Z ~zE/R0w CG/N8§f]S,Ι}-xQ *5 ;1L:Lkmml5{GV<ژazv2&SI\HX nfl",{vƽ×g:!΂!=o禹v4[[@]I*E~[$jVW=!3|oߢtOqBH}s(7aw]Sgܽ3E(WW!MT WI\k_k5?pIp endstream endobj 685 0 obj << /Type /ObjStm /N 100 /First 881 /Length 1662 /Filter /FlateDecode >> stream xYMo7౽P gi$)AM"hbRoV"rvF C|;j(G Bf4k)9h2k;jqTCfS 0Mr\#Aa4Jș QL`aV&;,_I3q=04aъVzV̖JZ%udsge!>`4ρUp1Z*Xjm&l\&lpN= C=Ya ))fTxߔzק.o)FuVtzXb9\B`H( .̒B0|$ߐ C|B_#Ea !3iTPLif trB)\ "n <LJH0 24A3[ 38 MFKޙw蝉U-Vķ9ƣ3ȃ 3ܳǐyO-G~;A}{uGGQ8Q0xDvr ;|ݽ{sAj5N 0sӅpt&džSWe5'뺁_8|OU*j&-I> stream xڭXK6WΡrb(RO4=hRI!Ah,9EKcAEy|P:m8pRF$rn71Aľ":=4(+%*y+Vox" ;8j r`,H sToYv{Vv{|"CA(rL*G(MU4V V~Nֶ6s5φGV̋|"a rf7{*CH#s!(z]V!?Y zVG(.:1=S MNhBE*D$`U~z3 J;>OPl#_ c?wRzǰsc3Z_p A0u˚mꆽs.w KI43 cqrN2G,H]W࿬2 ,Q=iuQy&*.xfg“fLЄG q~~S|We$loFvxSWaL5bgv?sZlUVY;+@U$> IhW/b5Mֳq) t;Vw_e}Ef]7p5%IrwǚuݲˍzcfL-u'6$ĥhR"1fŦ b/hL`P:qG8tNmy눪lI>8=ȁ4Hy5i6x͢GB`l(uY N1pq<}`mYB7G1g_:UQRZQK+]?򴄕@jttť=Z~|3xb)%@& |zӠRȁ|4g\ 6^#+6z|[z~>R3~NS29^S{~Uu')G04qҽ@ĊJgacw(&(n8?U"`k[nYeBT&iDЭK=џ1b`(K1 ڼHLLnl{c9/^g45w$AwX֞g;l.ϺT?uՅo$WA^B 9t=r)ZbąP\4 Q /$MB7پ\tREVEw?IbfKIʹ$_SW?47&z= qS~´&x71wpIj{iZ`,HF#Wzl@`kelovK.2ѷARDH{K #kHw endstream endobj 805 0 obj << /Length 925 /Filter /FlateDecode >> stream xڽVˎ6+$`̐Ǣ4i',hʒKʙs%A8YC|9!v~[Z|@EjM #V!Iz] N$GSc(ѡm:֨R;Gexw// 5q/D_ժ]|S;[O0T$5[E؆ JӺsGo"oj߂[<1E#6\"C+Y1_3 xB0ES6β|d!O^tnX̰N(aa[ۅR6 b@aK9)e؆FRVǮj % }Sq=5bf[)C= h(`HHTun6"8䧺;kQ50 ^4V͑# ȹs1 ^z`j#Ǟ6R~ڍjQ^oU]ug;s¥G)J^6@GnȐB]*wM_]R'.M?j-J3 k0?۽Օ&[=}m؁XWe(e!EWkJB0> stream xڥXo6_!(!Qlmʒ'ɍGɒ&. "{k{oz:^b-w|Y >A.O:l%篵ga<@+nyu{ߕ$*&n>}Kyv֓ B(s*!y_ 3-}OZ|W!,Ve1|Tt$!jДCƦf)Lڔʍ\Z50iV.WLn(65J|[S =cnu!gVq/qf44 *5o#)bQMVlg徢%OeVW. jKZ. m꫉qgvU-S4=AmTفȢnA;MBEޯ(݃z5'c0O|-8O.Gu2iy̑2f>H(VqNfa0I$-5 9ƌ֔nswRq]zF+/1kD(?3Tb_`jarc`\Bڑzn*I TC?e2KoLyC+c{`y!n0 kX,T'3z5qԱ|KWM1wYVN #xKʧ&mX0XJb+vޅ;呎ZK-(/f'q>r1?B-%+[ǐN>V.ə[B:,*?5 +;B7q,Yګ1ʏvSYWu:Y|x5;ʋ!fT, -OIn;;XUR[ 㫐 NkީaЭc}O?BǪ?~?7%*uz mƫ`;Ї՘ C}'\}͓qN'D8k<!ge4 Q 54t3ny_=cIjhJ8 굈N*}*U}.V EfBG!-#9*M@ 2O" PC<B4.#5}Pۥ]R1jB1);ɖ6BC;iZГviJ }q /~Ì f[߳bR: Y(da/!ov:$֗pƭyZ5iLjХ[mG hW/MVExy'#[{_h0V/CZ0D3z!G[D1?&>\JSNa;}Fˤ aIB*Ə=/[$Q@4 N Cا{Zj?ajF$ _#c3L-ZSq NY :W" endstream endobj 830 0 obj << /Length 1244 /Filter /FlateDecode >> stream xڭWmo6_!&c6#J^C6]"6WYT%*<Ҷ%}HHxk/N~ZL.$O[<$/$Q-G?J]f$ tuJM{exHb}`Ԝ)#(\m=2 YLL(8xt_,II3N>~ %lB,$3ΨnJ7#W}9B2c, 4K(4 IQ Uj,_ZӘz". vxs !a/yWѬDpd2`ENR Wj %q\M)V ʊvJ3Z@I)5ƾY"@9rb`49aΡ߻bG#yړUMGBa7Xhu^_6O5!MOb~SŖ+Rg g}o]]luW; Y+ӫuXEm'}C1Z8cnq Ƶ̿RsK^I-&>MU.ӆ͑ j. `KBBRVB#5ū@arՈSMQ^lyYB; Ƈ9iU}qP!ei1ePȍ.e*T]X*{n-nJ1?2 Ɉ '-eǸw^ۦdwNVjh{ۆW vc^kGhB5S(WdtϕG;OK2 +(22@\Yq]u-:iZo䶰l˻J:樍]n<€fG-<1eU;CM$^8{uu $ n"r׷#9αqL Qڟn>}W; u;! ź&0O endstream endobj 846 0 obj << /Length 1495 /Filter /FlateDecode >> stream xXms8_GNoSn j7|J7ÈCQ f=Ϭ;^$z{U٨}3v$~KveJoyI˵S9#sX 9eOŝ~%m^:q <׼I|'>(oŒǜe[rwpijpgE'a4| ~H E$&juBt @Q ~!_Ol K`{=r|b+mziRi* q^Zm]RvG=gw\Z].ox9"r)ΖK!:D@Y-Sxeۜi_(LOE aH5jxíV1)EZR (:`KӅ>y( 7wz7i8հRpXJ] i7uLgJP cEc8Sw;!P+O /ۍ/+5bŐj7I&maF{ ՜OZ턗z:$ Z iH8H鈞x06Rv8j;1j\rY% `oT=RҬ[Gݤ]'PQxF ='yL^b<7Hwv114U'0Uf& ]w_,?P endstream endobj 875 0 obj << /Length 1722 /Filter /FlateDecode >> stream xXmo6_!*5IC&i"ɎPY$9M0dɑ;6h<{ZXilsbxdx"fVp5*KkeG|yn}g"Jp B ̹ܡ]>qe[)ۈnNOIW>? |P.-M@z~HA `?Ý߿=]՛`0.;dkK%1sUTRշa NCΛeܵ0[c3ШLpuh}7aUO6hsz#ll,= 8anTj#-lUQjxzumX/v#UØ ڐhWk | ys1"xNSЛwˋ. 1Ǒ]qDh@mq[q "l DzZ`vV1įd|akh0V]ZWw @mn\I.NJ>gx8PMȂIr 9y dd}\eI5+8@,G#hY/^'.փr(gRXHͺsT Q/hb]Wil&A_2!܅CLXp@YCAvg>~RS#+, +#"__JzOjDуt*REcp|ǺBڋ4'Q#$(vh7d A 8&UTzP7ݳۤ ƃxD' a~P.9 :gsG|ufgzfiYN=QWf4&Di.`^gYTe^$e+RW.7Nf6UCEEҳM>~۹M+̞giJgC* ?gaeJ-غT{9P9].k%}b&q}wo<}5A?OWg%Xz>N ԫ?j Ƃ0jzZbTp{Az`A /c!ٶV0`X  ynR}O*Itwd+ݾWzo\RB9. qgm46#'LǃӜ/mWolPSqTHS qf%,Q uef1?<)CO00/h>ݦF;IVU20TNY/PA9=$ayBTxdI_<\g>xNIR*M876opL;t qch.S!Y endstream endobj 784 0 obj << /Type /ObjStm /N 100 /First 886 /Length 1994 /Filter /FlateDecode >> stream xZo7 ~_E(bڢۀ>l %Ե;~ϗKz=$OԹZ)J%ԖBV\k %19pPM@J OZB#ơUSP2/Gd4*c La:3aT62 2qR.E6La hh#4Jf4 O,'4؂eŘ2ڰJ'X.dj` PJ53A%2'A&!4{0^3Ʃ{|I+|IJ^UWJ` Q2DޣhTc&CCЃg:1d*vϠn- & Kq3a3 H;p90́,490!4FGhޣA3TdcA .]h`#(F(axSy2؆>JņM {Vٰ PWYps4WYF-1S@Gyd<TJ ~Ya<%6tx;Nj O )o_{|s{PI 6`߁Y¤OY_7 Ly"L?mo>d  k2}5?Y'v]?ϏgOW#Q;H-.Xr/+ uqcqzkz JdMwx~2}ZݔOgqX|!fxjn-&7Jr~_7ջe3[|j($PPjQ#7od_%Pٓ.J0\9vD.+Iwج?_n҅yQ%Үyu3D> 0YE0a ϯÄ d|Yvhb0 +&*]f[ˮ͒\'6OHlV{"mz2"ebJPq_N/:k~>b".f''#Lذg/F~ j\#j­TgDҢ3L, r@}\//8>\CϟٻfaD#GX |x0@fa$S82 }uru@iy[^.m<&3c ؅⨦腦'8J4[gGCcKU eX(Q$f߭gc2Ģ^jRjlt7DMBJvb8]DmYSesu#g 0aa$7M)f(L1q(܍®p)v+tDv/:3CE_g0a4i "LD 6p .`fv35/Ly둏iݵXNGH.{d䒌L\aN%\m> E;rA׶7^A՝2l]JJbWd#!$⧿ _".)o瘳sL~N mYYUc)Be&ȖrEv~~{+Z\͎U1TN _2wY"XYCy?w%gh0#o/K/-Zd 2ɇFy^-Gj#rG~#_83>lC}(97>e|A̿M?Xv֤і= 0"EY-8edm"DI5>А|+ӘG0DW0dTtdMr W H~N@^1msG<qm8P5]8f$s,E!IIDٗzWՏ-[ֈbvhnv !%y&P뿞ipxȮ"Po> stream xڝWK6W2qEI9v"=iA$AA˴,@ֻ3J+v3ߐ(^omx[m=,N^9[ęx}c~΅_W_]Er.ΪBtSb2y }̑mzK0\<.`8Cy %qSK(B?#!˄X_=WKZqWezhZl^];pۃaAU_7Og;ծ4$ )벒&]K=PNhY+g#rًt6LQMWLcJ#?I#4 Oa#?kr7 YigoVo3 =>69\xy=56 !`qV4Akv#ᾋ{,ɤIASM"-Гi]R5b'ofCs۫ Tkm]6ξ%+%i<$A+@v7eS5"Ů>^sӪh5D6n:w ,-WF;_.~uKVȻ^V#)M {uHpHZQH@oXvI/"*q[ZT:ZFmI\d{0@qOnv\cK[ L=0;eWʱHl?x` endstream endobj 907 0 obj << /Length 1271 /Filter /FlateDecode >> stream xWo6~_!( KR(˃׸C6)-fl-Pr;,Ų Gt񈝥GF>83sg A;s2<9gI?Pe:sQyZ %=yG94z;FGb1\٣ ?b-ɏi<1=$nLcp Ea|$_ RaHhQLJKȑ3ڣRtql5oF%oL1<&k-e==ݧ<RxJsAރ-YVyi>Iy.:  Vr^c1Ѩȼ{4z% <iiY ii$s`po`ϷMn E˼` iͣqYCM>];;f-A .ݴ`Vt:)T|j)J)R6_ZnٌhrWl``҃w|ҦBԝ”!!y#ms}uye`"^ݙ4ȸiq76ƫNBPs?] endstream endobj 928 0 obj << /Length 1455 /Filter /FlateDecode >> stream xڭWɎF+` {a98L89lsd2ꅛD,' ^*bO֋7sBw[`;Y'Gn]UMUut/ֿ谇 ܬOyDmY`+ 0̑?!u& 5oeex'G<^D;%3>w'"GTn˲C~W`n\/7}k^H5iY jFP$]yv^Hpv@DECP 97K`V[HfK+ܶ,{<' ?8By}0՝6 !ضENXfgGguSLnҦmdbҢ)F+"҉_Y80B:W0yLA,:1i8`DVt#zW*+̻.c+#˂4'}0E8_|ry[s Msdt1%2pAϴPB00Su(!rTDՒ 7yfj# r%H̽fRqznx_kݶ֣xIy#gimY ɑA`>A\lc HxgdWHKt[;mC©FOi&*ٴU}]EҞ,,P|0@GfbBF"6BLExAnQUjܶ e_fihьU=l3aRGY$Qlz*˶Jefy]잢|rWstb9k),X C}@ - ve$F$)c)++{E" 肎vOh:+ endstream endobj 945 0 obj << /Length 1227 /Filter /FlateDecode >> stream xڵWK6WEV IE[K\+P$Vv zX3ofﶋׁo(h`m^`zg{taHn\₞NFs^}LL5uzGX+ó96]◲S##! "ul,ҡo-oZe!N`{9Bm4 Wu$vzgJ(/kV\?x_2KgΕSe|Hk DBms`rv EV-_ b- =IVG0h&{(9mtuV?؜3?ƆR`ɫ˫3LS@#(6NϗLqew qץb4,9*o4)+o7Wj=ȫ)ñ2TzC4)KoR6ZRWC^ vJ6(>XT1z ]b FP+>`kA9rȺDs˃ =IZYv61E$Fza4@ٺiLe3]y;V}|[tC ;]Yϣq_Těi' ~U뀂΂( 0 ;@z vɑ'BVO]i%C*.;~nPUlY{5Q22h-Q*!:Ӫ?T!ͱp>{7 g# "D=oHGxLjb$M T:o"77o3Xª,7 ])]"7:wԲ9fV {wRƴ_@}/vj6"'7e:t.J( O &Y0LـkQ7$Q:!| 3qܵNʝvcʆ"={i -C;f Ea8ߗ1boՈGEc'XW9_6ױ9cȣDOaRnb^@͆bF:єUrYR7FmYnСP?!?o7: endstream endobj 961 0 obj << /Length 1127 /Filter /FlateDecode >> stream xWY6~ Hբ[ u+ Yr%y!r]apH 3Fy 4bZ%sR-stt|)uo߼ƒ P' r nXfu9{F$aFmf7#Oi, 8=]~VAG(tBa3Xv2&j`! UnU謔mU׬TK+7<(afWJ444e@c!\@8kު6ku5`ȩ4A FpXӧ> \[@xR:-n˗㚻h{ 8'y%/Kv$KpG%&Vq*Oudk[y=rTZ}`^5s띻5+' fQ~ш#`0Lѱm_ Hx0@`ڿ)l]TQosJp׹v $C`o:}JR2+v:ʸsR CDȿIE8ՔC R&Zq`rAp5bc'1=u^CƔgUj s7u,P2ӵ5Wf;O;0ls/Qg|F՞6| endstream endobj 981 0 obj << /Length 1060 /Filter /FlateDecode >> stream xڭV[o6~ ЇYhĐu=dh3`u#ѶZZ$9Y_w(RN2A<9mA/~[-/ ,"QBp#S@U{׫?/c> (;LS/8Yq>P|b`+w{26GIhm)!!_|;oS`'*tNUYT{kZyl,ӻw{YFƲXy|5^cgj'XaS+ߙ~0#^98 tv@fhvgAA+Ocꚠ 6DZ@0QzI $5(„%#O'#EEBS~(0Y$CZYv]6å%ݸ˛}=n:*mTl|\DΖ >S68#oTVb6Ǥ4fe kZ <&0gߟjQO/W$MjS1xd5ꕕqm9dD-xWøOVd =(3Bc2ӘoDpD&!y򠛹W.*t{Bܴ ziw]B'ڠn/}\1waz%:*lmmv>L 3l@Az6"#zً7AeJˎYUf\ݕ`pJ-~LP*³K|7`5/6V;x[[#!\n+/V[BƒkvM"Շ̙Ei"U5`K*Hز)x_Wi3T#|2m] dURk1@QJ2:[8(J7Qs+UBqCV]C5AoR3;rex4ʙ]Cۜk&Lfԥ;+#K_A[#} AQ m[\FÃ$r'I/v6}: S[? H endstream endobj 885 0 obj << /Type /ObjStm /N 100 /First 876 /Length 1704 /Filter /FlateDecode >> stream xYKo7W\(rfp[;NB!AJr#ڃ$[pT-W:I]dt qSNJqe'x*.JqW.xv9r~u%X_]I%+hk kZAhOCv1Ԍhf(VS9łrDjN694FG40(4Fj#1FFQ* ( hcv50axEk! A `z@ tS9%B=eF6q ⌸A+1kآ++O%: j#@eĎMp)OB ?j hd` C)F0OI6u(j#><G% P"EW+XJ !UR+@o ֊KւR%[G3jgm6 F*lD@OKpFM3)@IPj0RM,(8++4ZNkBNJ J b\~9/Pb2{=AA L1\NwCȚxgeGЪj^*^םbv0yl:<-܉=8two wGx1<_èYUz|z1歿hތNǃWopp3 fҸ*@A!Ь]+kc7pb7#F\|z\'e'p.hy\kr"xE( Hul):iCqH|s^:nѬ]2|$#9H#*<9f>×H]黩É<;tu$ #H{ICxhyy|y|}(ѯfDz7b6׌dQO;D- c[9͆* et]5]v3RN`[`Rp IF0roؽGToyEKOZ=y\O;@gWSAazYZp,fw>T<@3|sag&|+]2!M;B'cx+ `4绕֍@J(@Sx1-.ߌsvH #AQ#V~Ӌy\kӌ*YBav!b8@.,NT;&0k8sX!ͬfґ" 4Zҭ!Ѐ*re QZGys0eVuDEM4hyºn|Ϧ:k5ɘ{8m[7g8ʞ7YƏ!siZ7Ic endstream endobj 993 0 obj << /Length 1282 /Filter /FlateDecode >> stream xڥWKo6WEb."E.Cd ,$Ar–SINC E=8 H1oO ~|;%C*]R"b$%Lp n~dhLI4iQ'9O`M߲z[VќKSI|I @x#e0g${VŴwEXy2/rWlnic4&˟`4Dc8_JdE?٢Jp BIӛeJ7<}GL^eP#KK V#biAi͑Lrbl~sitB N%D0uESbN(6Fgi͈0;_\IbceHRFdJ$iL(q> HA]j^39BQE$b;{69 b3-XorCDC%*f M %=>ԥ(]4Ve$0{ޤ 7u6T+͓P%%YM u@a5JM w+\Lqx231ÛmC9a"&RZ8,EO(n_oGN@KY+GnUSEB uZQL;ˆ4#i5)#'WMǸ.ֈ.ѶFZw;n>by̍!lm#Vl*}Nv7G8#Iiז@Ԝ bϾ́%s<,m{@V%Nzv8ljɔbA xݶjs'u7#/5\J_IknǮEuN !Vq[„M~Ո-Ȏ.W 6c>\U=x%j30hBf}ezSD>. nayy}&^NHcW!t|͛ocb͂ _7w\ _׹})+ɟ~Nʍַl9}s1.n8 zͩaGo$`HJA2 <ހ1YUa$B+EQWo1kLdp?m^{k޷>T|zcCjZ߶4Hm>ڌtYz"}tm|sZS\^P[Tm'Bv:WN6ezrA}ɇIduQUZ endstream endobj 1012 0 obj << /Length 913 /Filter /FlateDecode >> stream xڝUێ6}W "uI4 )8f$VKMAË˫&!pxÙ3cgœ@)N#QBp#S0E]ZB/D~z|-̋ҜzyNVj?ClS.n8xK7̋n\nk ehg?ԗ_ >LdzoZ}lVy?? endstream endobj 1022 0 obj << /Length 1323 /Filter /FlateDecode >> stream xڵWKo8Wh1˷D`{&`m^ؒW e+ij8o>iJhnu*C:]&R"NRƈ&]$q]o:.)#i> گn'L4ab*"E4YdɣۺM$J&8w<:%=Q%Kʈ;NLƢU5͹ztU/<آ/?] ŷtTV^eERn~aWeWm2^ 75uac LŹ7OMC| ,K,#)uz7pZ,-Fv=<]$Dz62X?%*w'PcpǠ0Kbh̙1K!Z Wv40%pBul(VFɆ\6E3DTC URMY qy{H\,l|Wۮ_$)I&i% Q"W=KN+CO.2V+:uI@GAN? 曽/w9 cuI:L h;2~`HV#PzuۍE,ش P.è&L=.ՌdY_ys8BgFq$!B΂хכW ܠd. Ƥ{FR{@3P {}yqFGTe?Dx[ml{>WabAqV W7M$ ٫/zi 6*mWeUw8o(x@> stream xڭXK6Wȡ2`3HR=hRECWmvpDy7ɯ-{۞4y~3tmu8Ran<cm}i|8 K39n(6ukES:dI_De&G& &p4@4tGZ$Wu),D ]}S ?7KC)Vk +^喩`hܑGfOveu\/;ZƬiYųox֊fY[74($smMa["Z濖i ^FR3u=:mƲ(J^5I;KBWەs笊$Z{ݾ BN](YWN enn %;s'\͛yBLg"NDfeB? ڿ(n&\K'bC&L2sZldz/&@ } ,фt |FfWKX@Vtt$h..,tᛒqeG;"i=ңFjqt3=bR'أ!HH\b?K&1&r^Yv(ph#K4PmjW EQ5Mҙ6ISw15ro%D30FVpݨu=,1؛iw+PgsM]3эLCs.$WzV 9 m fddD?,}$@G=gfetu͈Q 3XPNP#[iϔqV`rm# F2PD4̜'/@  k!-JowjY#aM̫ dܠlܽJՙ4VuT0NqM?f aNsz!@hffAH|Տ(N@άu ︍i,CGiTR4Xr6/>3D"}{Q0vqsaIoI~ FWݩ~6Dʂ&.ceY]JS ~SGjS!s8'݀T(U?~-fi> stream xWn6+l_z0h)&)PdidA۴B$ǓC8]8*one1Aad]tm9 aY'eWVv6$BAd}e6QşjY>x9nE"a b5P(j̮&3FXI\T:v*:x3^ m\zluj HD>lcdt./TcYyVpqq(ԆL1{X)9ڳf&S.pEzYX=.|~/9>2[~BJiϱ#UΥڪX4EL2 ~۪n0eK-4~86 NAU|}xT/a v(,P#(Bt}x~>]JÍ$A ub` ̓U1aۿ'e]bOO%GrE$'#+X#Dk.[o]V>//|[n棯#GMʰe:z| >Diq!\ݏ~;ь^PTGܭ}jGAQ_m^.&sTViln =!"u~eJyPB {ڱsFQ RT_Ǝ,2Ӗ24$F^.op?3% ;81i.l8T iSgL`ĩ*|]N%fbOMMN A5Z  @s)5|3 'EtRn~ZflY{>>^OϦ;5s2hL0[^ ڮ4)Hʇ Ip2`ʺ endstream endobj 1083 0 obj << /Length 419 /Filter /FlateDecode >> stream xo0My޷7v8 nrFʁ1Dرh$ Nl"/OR~PT0CY %_ph0jvb}.~DR@0˯K*)?5 +.N}KXJxrd6ֲ~^̎[s 2XmLɺZ+$#p\@[J]5BD2M|JR,+۪Lx_)Dg }> ՈQmLڴ $(j=APkВS(םOucS:v2J;?FVH m.ڣ`RYA۽ً&שׇ endstream endobj 1093 0 obj << /Length 1445 /Filter /FlateDecode >> stream xXKo6W@P(J`Mݠ`dV EoCu %}E"73 ' |'LncDd£%4.&0x~JG crӔs sQ?yv6gOoVҬJA^s~l#ƣޡ1nCV=Sz =%k%`;sUmlߵzl`ν!xu9`atQF' (M$y!v?]_"5Zmz\]^߼ZnJJ5X3pAs*ʭ p$ԳOW[Fӣs("qbaChm*~^U-* 8< B D. ҉Bo@2Bsgழ=dEU?I˂tfΨGY`Zl u!LhrQu0ZOAu s!=ȕy?nl\\7YĦOFss|5;khhĽ瞊y/ m *blBfe_ܷw0ȴXZDBSq_ZIVZhX(_1)T-f ZcЪfghJa9?RjG׎St.ږeQQB2$sB!<;r}QDhU*U=~aaSEk]׌'G"q#ee'ݣQ~ugR]uZEl/Zi8@.J[؍C0+8r! `jXi"(oL gಥ`pHKJHnlyögƾ15ǰA?w1bNZ8" ev'Ni-mk@x`eO d]b[2E(?ZV&aA`G -^+߮ɲYFt]U[Ccq72|qi=n ׯ 6>Xxzq9y}{t3) endstream endobj 990 0 obj << /Type /ObjStm /N 100 /First 958 /Length 1541 /Filter /FlateDecode >> stream xYN\7}߯cP_{ nՀ$vïnT Q&O02==>=~Ip-?oͦ ᆭlԶ@R9 'U09VIlɇxgpnxl /&ד>Lda{r2;''NW?M޻]$#9J=ٟCup SfXe;{j{^qG6hf4<&f* ? Owcsc*U,^UdKKf6[\wa[lW;qSV?8RWg9GyS.'J?d|6}}\vx\ǵ6b/8q~{\g  =Q,<ΙLQNUArwqF$ AM,DמUnY{ӺU̘;9ʅp(`({}F'|9׏'7~&L^>x % G8KJ@H>|\W/U,|)p&ox7{V9lnl4f+pxwhno췿y7lzx?~}I!z^8x6,7Fs<]ցVُӽњyk,S:hh/ IO7LKeV-U6\e]@+Y7g߇Gk> stream xVo0篰ԇ*iɤi/[ҧ()Ȓ1@KIƾwA`d|X3r8`q0B2CrXM狙h;T2/h }KUfUZTL~C]o1<, ]FwdĴlF,*~KTk}+Kwŷ˩O:# ZAn^6Z/ޑ.qqݣɳ#Z;& F(}v'ZqWqɋtݭB q Çm^A8x"k;Q๠hdLՓ9L3e%vWA]*QΉUo=ӟN$)A[˲" QJ;ޒ܇v[d|:8WdQ)myʦa{ $cLƃ'3A8 HkRІ{`W&2c07rܘ)0`"!4}I3 "6ZCѾLlTR})cjXDd3:*u9Dh| 6E;G^{0AzQED 5=:@{NKāgeyU+jFٙW}. tw2eZ0hyD4YJ), ;R煔~amw7R endstream endobj 1127 0 obj << /Length 1110 /Filter /FlateDecode >> stream xXK6Wȡ2m-[$AZJCd APo {;{~ݬnKQl=1ba%ަ>:eqy}MCLPQVYag>݀q#oެcmuo>oe2:NLOB?ɪ̢QɠPPeca8aO (M @(9=' yY//vټE2?~%+BPJ5kvfh岋TWkłA18O ~M8K"B;q(bڼSk^פ$Dmb`7'|6 C3 >aߟyICtvɗp85idOvS9s];Gu0{V ]겳P(!iX¦΀ah׀FovjjZ% GjAWF59±{bM"ث̅ 1"Gw}@u16uwhډYtur@e鴛l[`WL.,&~!}kO}M,X##S͠?Xhk =3AM tcJ7o]ԅwPOn*qQhi˶G`\ȁD쳹"DYQ+Ѭ49 vHTd'n!u@G_dߋ-41Í)|.̠ex]Y};} j^ӻ'gX.p0i<+#zXőo8V9vipEAUSOSsmq  aoLX=`n;8\9*C%s;aXsG{ _ %RmbcYNV'⢞ڂ"OL]:jeAmV+b?'PXIzy{lB; !$ԴQzV]|q1,c`:,Ng_g}g)eQu#6̟I#^B&s.W> stream xWKo6Whk_RtS.(ʒǮ;%YÏt($||3w˻'re‘ Agv~qI$< 8qt8j;\xWe= [eMO wm9 g;B4.=R-˫<(K^Bk6Zy,Dͱ<kP0YVI Px*O _5"s m˽J'|.kj %(!;8}q Uf=Uky;'v2̔yއESou(Mlէ"-+_,D巚sI 0YE!s+vxbzFd?~0U?"qv]I;t_y.%!׽U8r?eX(E<D@%G(C dH-#o)X[H= -T\mb9V \RK.F%bM;A JWE_Dc1b$y ԍ-`9x'$~(Da9ɂ2N=cܠю@ީ$cVok'_AgE_b9FUO@Gɶf !4iw@dVNh*5=yQf囔|]_c׻} FD$"I8,*8< ҋYYh* Ym/mU40clǔUtg]u]DڢuA7yZ_+1L'rn:w7l Ժ_ Ma{w)PB1Wzj`[U0@Y'ǼEgd> stream xZKoFWЃ T}%M Pp &W2QuKIZr%M`٠뛙]=:?/Ξ)XyB@(8@P-"uO/~泗z>c巠7c T=|z'!3A!ڔ0z3̿$[ TNIQKf/q"55?@zypՙw= clC3>VB:(.F*P2 63wE0 n0 nHhVkUTirpoELU*C_ y6AoG 6WE̳(r=c_7[H=6ʇNU\( Pc56[,y0 L)9cV:~T&UPkL8[U5]{yu| "j}u-myR|=Yh46(ABe6S}IkEUZ^iLBiF::iKOUZ^3$j w7bХ P{| t~Q}@F۬T!yg LAmDY: }hDl5]L4` Akdil[D%hf*RNf@pwyT__{TPXhoն% %o8x0vl ' jJtҪj&yOG&.*9VT7.%Xt\vMT#;C_5ԗvMcδ ܢ)ah(9OϴpaA1@F$82sI5zW OvXe. zsqL- s/哺AbSaZd;KbFsQ<>ۛ(σχQqja!Dgb ~kC0'ˤJMK{VÓ}a rDL oBnIzró\|Ӎ,"fƷ}Od>b>نWI%&(R%f?6. Sooӵ}PSՍۘ5oļzxd \y3ȸiSX޻Aj6aPwcna_gS|woWv5p  AnY:z3c؅FT, vfjdOM"1ԯ!L] 9'؄}-YwZՐKqN?- 1ķM뀉L)~ak*0* WQ|8(G9(j.6 J^2O|9Y Em|5摗Lэ/d6kA!SvtNTh{h2ZM8Gi]4;Q3@ŜH@"B@'3g].l[Q1)zN:Z^yCPKv^@Ej5x}nALb `7*`pڷ_* endstream endobj 1099 0 obj << /Type /ObjStm /N 100 /First 986 /Length 2271 /Filter /FlateDecode >> stream xZ[o\~ׯc%B#@m0l?5:[ר5$v}v$+b9܇!)P_A>M9K8sֶ6gehϨxרȜ1@V*S削@Ϡ& RL'%)$PR(o!ĕQ0X)s)\\ ҆%*'l ߣ3 \pez$Bh ʑ!wKZWrET-IYVԋR6Qk߮JRߊDՖA՞uZj2 M5ek>l6Qj}Ʃ;:8MC6eVJW0nR5Y%|hZ5O %_ℚo.Fyq_+i,4 Qa>-?)uW/Rѣ͋ߦͷgg˓|wϓw/ ~/|8<۾L/97X2A,4ks#07o|H͋~~=|egD/vl/O޽n)M7>|]sϷE 588l fѿFe (8WwĘ[av$? 8D8(.\ ,<+~3 =ASD_JECQ)*oR^ 1* wg.Bнޮ ΟaAEй} 8 s :/'_; f;p4Ph8=htw^ Fq[Q>nkF7oV̓*mK鿶wu/W?7ZU&FVڡ=__1b>Iq *duI"S_H]b['"U4[&i%kT % WH%l/Df^ࣺ7k&n j'qYn`;(:<_AU[@l<ث~]TTެ Q zZh+R£ V?"RIŶ[wuO:[`^ T+ZˣVFC-#jmιW,n #4I=كq5/(z^Ī B?"~Wy:'q"+ls"0FQO S6r&pt6Ti D+WR8m%:#2w[”GSF9AA~fL gt1KLЗܴ}8y endstream endobj 1331 0 obj << /Length 1828 /Filter /FlateDecode >> stream x[Qo6~ϯc,HCbC:tMV CG,y~,9BQEm2EB:ww<~w^> 􇿯}'qFS>o;*/_^Skb)Er_AAQpl7'x/ 6*P;xV'wQ&k 'C4 =[j)k#}#r&qt# 5E8n3}bD9`2>LԠ@Rٜ<՞wal0$ 5a`t!16_VGǷ9I6\"@!E8 [""NI1> ?2[;M e+0ƫ d}HHa$} =ˇKQ!C}1<̟Nu8<980*#Fq!yfL\&ZBl0NؙOt#Eꖯ$^%Y$ldՑNmTTuv50E%:,JL=S"C-1wE75އ8kN\-ki)w_|n,NWtN@lK<ջQ:UAsse/mnWsn6H~!MeX*^ۣz!V^ttx8Nک(9@2jH@(moe x~<uʟf˦֪{MCXM{Z Owo{(}F,N|^Z#Ͼ$q8&vۉEXԷ`&ekK73$0 LW'AIk&syc l6o…(wQ'ᮛjoK&0V<B;YV=̙HlC*QjKx-=K(cFgV搛bNSDF=jܜ#2gH \{wt:t]a%vuKH6rIQ< gxd^al%w_ȱlbgdX܂0[s3YYaTk3p{'OBa<>@f !dxU=y}IMKw$uK>NuHDyWG=>=Ri"5|E-Le晑I7`Y0t.g|ؠ1!UT֘orˮ;2zc=<~}W*w blC|go>f-NqfozB+ Jbtk@ϚH %Z Jm;@[D/͖"E32QUSMDPlF&\|\,*élwD>> stream xڽ[]}_яKa-=(LsNZ+Hk@Μ9S]7C 9d,F *9.Jb\HֹƼ(r~.BprIhݸ-wn+deMBƹKVL*56Euur*=XS[FoQ5ORB-@:b&cPd,56檅:dCKu1BH < whM+fA"+yaC=z1>M{2u#t+g`{5^g9@höQxIɈ#wJà@SG nW FoѕQS$SμoHK(C%Td,(TuFUm:SA!)JNSkna+Bܕl[!Ln}]6enϦ$ 6Ix4l`[8ӘJǟ#oXhNRhT/zLCs<۷.?~ׇ?廇w?ݿ{ҫ˟/|2w|/UJhjq@T5GmW}< O/iï}E R[N6B5ը5u$T$v@-T-v(QH-$x8Hcp$ET*vH:9$vuCApeNrwC#R$l`)j$IKLT1"}b+B9$P@HdQ3G9fq`v9$aYcAtD!'(8R+ȉ(27Vm$zD1vD*|E7B"}3JS, 6w}ҽ@Dpnr2C!#hVJi \?T`Kcr|}/=o.ϟ> }>s{v !1.Iy~AH]|X)2NI0XHEH9>7~|NlecO[Q省pb: ݦ6=ˁtkp?sM #}(,dphGT[*bS*;*xLdaFu6kgN֮1DzM$WhM_!nu7D7D8>Đ8xtp& R&ZK]OfNk?G|a f:7adkv$vN1ewF[>'v2syn: $0٥$s @/Giq;h՜&3ƛӕ$Qќld;vkW-Xe49T -pƒ^.{GqJ}?6[mtDr[4=ίj[Y~j6lc!Y<]~FY/6;Ol`#zM jYdْO~6Y=bgϨ}|X77P8e@nYzE~ D!LoW'wi$WP '*qD_*Iě$7;7I H,9`Qj9a_z?v(m endstream endobj 1404 0 obj << /Length 1531 /Filter /FlateDecode >> stream xZmo6_03H-Iѡ-:t ؊#/,YQ(ђ`#s<>w<{wZ0O!ye'0FUx}}՗~~HH?3}~ʳ?Z!M.,MvXoCe(>%y};'U7c8'v856Nf@ ʍ8CBq;*8'Xm A:piNA) j"t "@] O]HuB\J:ZN>\揱 (.ܟ&æ12V _~HDcƍd)L[4S$(39̣Iv$C}e:m N̾ ZPd?`'CH2 @N; !͒)JړPPZѰN4f {(",aMЪs@,'Y:7,oc`tseB/[2ծE]w ɽgTԸ-kp-bc'@Wk-1dpM85:J{5q\i{KN"5{Ǖ sWif8j:tJǨVwM勗$4"t‘]85l1whRԥrfvmlS"Džb$]E :Ft`E) 'vMY5Ҝ//|3Cl \sIP3Br[ԏe`BҾxiO_gQm>u43a>|N.n`;kÔ!.zmP˶l dD lٌ'ֻ a&uX86m;("] v,by)vF,oPz?gCe-q jN()EtJydp r*m!Vh뿏0(y#y)+g~9 Pu& dڀ])ydf:sߖTC6TU`r~ WcK 14:J2'{i?e+w qjnɠ|ܻYKY `THK{1F2Yz_>k4,価(Ek(v줨;`xئ s_\nӼ";A+*Wͭa,^{nHS@ՉNW0z|渔xRㄪ( EVVphǤ IgAjawnbU@7ww(ww^5]my j@<]:n endstream endobj 1333 0 obj << /Type /ObjStm /N 100 /First 1018 /Length 2693 /Filter /FlateDecode >> stream xڽ[Me2ܧ*U$ `@=$, &fڌw/|_ ֫{Th)'.IJBsQR K^OE暺-IUO"=?HLQl+͝+|[ -ْ47*TjR%-MI] ϐ E$i+AB6>W,|x*܌UbƧARyH4< qħL2& Zɢ}|籯cĔ͞g5ymZ.R,EVp2 B/UMa6Rx{|S[Wi.VRsNKO^7򧧷OUOqSc[fA]fpDX2ԓ0\vb8} C戕VհQ چxtw?^ apC,>y Іe5or ͏a% }lLǁ.bQN &bXz ;CzwۼSِ2B8 ":>ʨn<`!Cڬ "}?r؂B%Yn'7D]yF[:P9s'f3 $K#@rI H KP*%l1'0Txݩ2)qƇ˗xO?l<_>~8~4*DSͷivƃG3xF/(6>1ssm\\\mJ)٦dmJ)٧d}J)٧d}J)٧䘒cJ)9䘒cJ)9䘒cJSr\:%)NuJSr۔ܦ6%)MmJnSr۔ܦ>%)O}JSrܧ>%]<W׸ 5hkOt#x@6# /\"ZNl -rTHE&ea1؄s+$ B@L-AY "0Nu.Xo baW1.St{al/92& VRoEؗ8 v;$x05c%3Vȑ$$~y[a^\FsߪIoewO: i✿ 2Cx+K-t g 4t̟U칫 [*Y줆1olmvʼvEdmڳv]p^?avEd}P;=gctΕ/o xyY;u`{ O=jЫTF* E(s#zԓnNS V^0k{GKObo@%rkϰo7FfLqAOE:kP:Tr=s@>/q%EꡬQV:Y>/Do/#j9wb"xWωlp1KGj%C Psm̟zbeH]zhO!<4R>&}s%oqXe7 8< endstream endobj 1424 0 obj << /Length1 3077 /Length2 22123 /Length3 0 /Length 23643 /Filter /FlateDecode >> stream xڜT][% \ !Hp nI%S%`˙k/>Jf&@ {Wzf& :cf#'WrOZp@g+{EƮ +L 709yX8x@,LQtp[ZmΎ@8rQG/g+ KWߏ*Sj!=Țbh [a@enjold5AʖqFQi?Β)_\ fb4sf)hp7:T栾l@{3f/IddePY:023ub`teXLh02u-RqdƮV]&&&fӯA0s*.QLF\UDED<>LzfNN;7OJV&PfnIPkt !wؙLA?K4=l?g3::{z5F_:==L@qosK*Bkmg{F 7[M!͟3s!alge؀L[Sɑꟃ*j b%loaEhdjj 07u%W=P׋Lufiejctqho_Aͬ-,cggc/8&2|V O'(6#+3ܯ-`0 8"'Q7-o `q2%~#fo`XҿQ7q@\~#E7qQq(F .ʿoF .ohF .#no`bjeejlfVfl,Į@g+N@L~# hK-pK)h⿶omf[_MF ;_;ߵ`fo ퟜA7bΝ@of2*d H Rtn  (fhHf$8@A##%;;ȗ=Unv&E?(14ȧV̠Db8;6K}VG3m*ǿdV{*1$N܀.zcb!HG?A)vJhgdtI '.=]Qs]Ԍ?T&W? @>~(.-S?k jD㏥9zA}\ nΠFs tk[& h 8`b]q_+A3a'Ez徚/׎t@2mS\\#Ѩx:Sۀ`uuȳ;S'}C YP(*V|5W_G hbPI2~'`D.Q-&݆N )VE?)G6E1)sHIA#I7N??<㎈}cODa܁g\n|Yri[%Js۶n%K3q?/%pG:-1R`[. + Syn`?)yh>s nQII+?Rq H1H$EɦmđtYn1;rLtEP)hE{7?b]rGMU  l-g1 V%]j7Z 1gzxpÖvh{U*@MG3[4W%'< ;`V]lwVz2;:%N^ ؅- Ddԙ&(&;8s/"bzzXlYΉ2oIEv"?ܕ4;0uwݤ!MEF [Y۔]G 5dg8YEH7npV=(I'Ť=6V3J#a;z"}7X5X:F/esb4Z84Ww{@-sV5yT r* {lܾį ܋+R$>~7 iƿ<]-Q@ID@uƧ&WТ|Z}W'Z |H#@Ԣ[)xF5K ipatVV@+2^|~YC]>NgQm O)++H˚#/4=x[aixOᘄ#t}lP&}`;8}503.L?. 2(JXDwF}7CŐB+:Է|YVa`b:mcR&reU nEW%W:`\\ʘ>ŋ] ߖvDD+v0۸,#ӣ"Ŵ 4);|-J4֚Gg1/, C)✽6[:CsVCy^Hd~IȲk*qc>{._$ ;~9Pgzfd绷٤Ye5bP9=;$1r-XiyT-_pn5ϾJj6-\cP9@AsFoΦI[hh?fV9N-N%`׊{(cSh:cY@唩30B%u#nǽa|1JYQ O:jAM{)?`<\no')-Yl]ꦵ |B/ )ktH(0%C \` B 6%~ZR+R޸ɏu(Mjb#3J `ox9!HR>׍YauZż7y'2$uQmj,EH 1P}%+颶M ݴu',aO Cp ʔ{gd6]mIgީ.])^H|z+vslh=c:@-ZV|A+x J;5nQ}z:P K' Up`|bڸiy2,f*W4mϭ/tz4j.L- KCG!>28e .޶b|,u&[hjvXBJ/\\)ʳo9>龍,|=UO t*xj+\LnEci QeZ\Qjdv&Wń7OIn&]eTX O ܷ%&xo'#녯8[')a-ϱ~;'xoRH䧯=r U,k)rDތN#G-oo3zJ0 Hzޮ?>@1'ӗ>EDj144], ay'åQ.暷hrɳio=Zt%%4qūk^# z,IUĞ}=vvIC8>/xW)e[PgSucaF~UwLkGL&gGU ~%8V˄4!#"#$ ,&9O=b0 S|}룑IM&Vw#VYA՞- eDe<#v#-5K]7BaM`ݸq)Q)}r; 4ߣ{g^<ێ$eL9,K)cc{\O}-ٰrwc>!!f~/a*t1u [̕"w٩o2E7Q|+z52`L0rKܫ+&@R ?IE&>>|Πĉ|FEw욁4>@ܮWx6]+8g>E\O!krQ?: HEDNRbOlum<)M|(~qV; m4$ ϫ4-Lc H8T$A_=%h}LjVdܘ)0hǶ tV^U_=\[!lVm=p_f-e,T\%'Z 48Qy "0*-HQbHnzӍ*ՇGqZfh!ܐ^aj;ލMi8 - &FTYW,7"<]Χw PE) 0d(8v(ЦP-I2^x('.)^Zrss٪jh\;K[b7"dl5 l ^FmEm0M79;'MD"AU E2S.IQ+06e\)!"F9>6ñ%~IAd&S6gLWPUc=Gf7D.gVa'KͻMcB"!Y4C[A&o] =X.r]#akdO}ȟc썰xM%1%ZN~iEHy}uPW0WV,0y9[c9Z@L&tHʓQa^Hgm32r7m vͶuxuC=M>I~N?^چ0UVFVPG! GR ]S|XMn'F:<†n{\dmV%;HPݝd]㩉)Mxvo ^Z*E)D#Ln( >ץz$f>1̗ƬFyqw(+5d{uː9E {7ΡeͲ ⿼vڔ L.)ٷ+:+f-Jd%ڄ}z},|+}lޤd\h\YД5CB`&v!qH)R9i5$_EkBb]Pue7.Dޓ SGU lN0,9X*,ۆ7!\5yn"F=UbIm!G[INW?- ZQ煨 fodݐ:"P}7iz??'] gTV-u6HM! ( X'_qhyfD`\ %>ge:U4M4W *2t$læ z5.~Osٸ5N5Jp3NaeFr7V3, ?h(-:.( 2d GOt`Y0eyxHOŭ;8"uU\Ima4n>] ̝,ȜHN8~(s}?2c=WhomPpEQ\djvun`SlG}C1t+ dAn㞻M:5[tuـ :Zc9sgZ+Q*iU T0aǒQ&\xqdbSSzN 8ߣTCR$X]#mY.vT1#ԏ@|- /F&x^ rA&K5VN!xh,?2go~e`ݼlɳ:Alr #ӻ^\w`ukmŰƒ9Q} * bpaMˈ|1d,)̛ՙ.;tocb#J׭`#qei%[sΠhm7E]T"E\]W+D쁘7Wf'pDa“exA7\-3y 5ndGQ_hYXZpV~vF 6fԗ,|DHbRWMmu%Tc"K'F*8a$J`Lk3h,-g+}s(03ցߣu[`/Bƅ*Qܴ4/?>>G{&tSvաX_LC׶|b>i7:N",6YMX!S͜Em}oWsdşQ{в^,oW\N? ip FSTyDXN|= äTͭ~;a9$@Xe-pe »w9_L[aMu -P;g-9e0J#zXh kbBŞ36 Yfu*pKDs(ѮHIɍfbS\R}LeQ͒̀?AoxTZ9a1 sTܸV`!×_Phnا_uB?}p4*0(7I}~T{Q Jzy?u5CuxN]dAԎ7YHuۮJFj̅z{0ߵ2YV!Ͻx& S{kŸ8ٚ`$Z^l%N7}F:+~*Ϟ\YqD5S~R.!'YtQ_a3Eݱ8Le,.c\4¶)}!s*_pGVdcT$e4U{Ql$O@*s8V4tA1^\ތIh(xBۋ5 ƉN\fg:9,f~\cr^v!Kv v3 Q;^?N]Ghzwb> !"S$&=iR6ㆢ3- bCR˜5&F|b^Jj%C%pYس@JBil"xykˬ_{:ew%֫G@gޱKf鹿yEQQa?G; Ԍa I:]\=bdAj+d] ڳG*Lm"AZQ^aU:Oig̅޷xٽ춉1&[{6=Ҵ>nU<ӊB] LY)^.yaѿVPA>p!"=t02E-7c܉Zu/ a}NiVNg5.+> [M-\Fl˚1S#cxe8 }d2ַ),#FieM]fA&Vw)Zmѝ}6 g]+BB]Y}bM?mx7R L. ws ¾y+sEMF?&{Vlj0U³%CSM$!,Q_JQTP6\8G wyrRngB1.'Tj/Z!HukyK'WՕ??jw>' %q]|`kVd'JqPڧIn@2/mfw#'l8.)z긄ϱʼ~HZ(~ ~I YOP; yn+-¸K$̑ނDms|솒%MG:Zv2n SdߥV<%e>YAH]XCu[&×yRM"(E s& s#V^3QFByoZB.CpؐLwϊa\Q{H' Og o p -h>j]GQW]cwUqB(Jc[b 2> V{{W9c|a:քϫ1:>M, uIq(F+ јZQs~(up;,h`e=]μ#Gf//4b")۴1;&S&ZJ<6bca3 ^YmJ?rRhw8Q2HYRMůqOA|)!/34ʄBI[X켕r /*+>d^EEΆl͖2vmbLE`V}/.4 P?5MG@y'QZ cGrUnJbuהT} ?Q\US@ʒQwRMAq[}m@qQbeji4Z(>$YW/)C]zw^:ܞC]\ȏHڍd-7>A"ArqA";";+8GA|_IܲuTr\3I[dӷ$T!0th, j+ 1-As u1Lpp~jSdt;K+kyB|2ՠ|QNB2bP+`w'<~ԭI9*4 @/|^P~9âa:μ28WC-J cj%y wZ* cF]͓Q n}.Kkri{t4s%4Ix̭9fCL8:68nEU@df 额r=Ʊ1saH,jx\Ns+x@\1LJ ܲ{ruK=d#<@NKVnA+tY~)uMov. x"cOВíJ5&&JoPl;k,C3R`j_}VLwqųb ()][Rw2Ki[8@Vȶ/~Uk*{"3\#'):%^FYYwb9m,#-)1DEՍ5k>n+rÂ`2c'3QwB]@ʵ[~Z E=<Ȼa^p1n_W(NȖ·8put"G-\Wj3g-U]A1aZv]ΚWX3Ԫ u_@8/!&i녽Ў8Ǝ~I= 94 P(]5q튟 4JF%k?E*^܈ÖXX<"$SN?,{5d05xD' #"jV@\$ մe)LrZMp[(gx_*34f(6$4&8NL@9<'х$jY.sTq,C06aeyPC "Ъ\S89X& L. +?5YNiR-yV`pj|^wD)e6Rr|BL#m)y1aW $J; 1;/.D^xueu_TM}Y1N>g<b^c ($~Y/z7gȤ*fEtSo10@Z 7 |*D!"B=ν}-YG5wY}ĪH/\% ryΡ"cjDãjSϊ/4iMv6 FZ *ŗ1ƙ>Tp,籋icHPQTw8 Lu Nhy;>%V?[=pVa9Ositj.k"YӾЭ5\ˤi.Fm .&Lsk5[#1yf灤O.4f}܄HZ51 GOn ",ϑ{!}Ux{zage2!.J[$tjX!2{Z̈́c09bGt-[b <zL7t 4S}8K#yZ,ci~guRXߴaeG "<=[ <]g ;KofuIIc '.c ^|xC mn'<FR AҰ{Xj4'ۯӍ&}*6To!{5VwN/e2ԹtΈ;uD]$OE(,$s~UYJn8j9kT2ܐbZV"\efcm!{y cĈwٵٖ2j4-J(&fXL*Ift(ԷuXjvHZYc XZGe(|I7qKrRS6 =9Xa<1Ywv}f)fਣŷG sZsiLjoS{#gޟYem 9̘}BlbzG7 H\W& !A*#G d 6D9gva#ag<;d $3Ɵ ~q'LhGSnX:M͆7yEJ5O7B&]6' ?*@`OI6?\`@=[Jt cGC.S|6TLq 3g]>;6daP5&8q C7br֊MeM `/\Atr˛8#>gBrtr =z9▯! kmqy|F&[vѼj=Ǘn#Ǐ$[ >5C=TUa geguER::htܒ蓘dSW)Džg֔LEGfϑ.ѤxhNԊuWLz3y|Idd|cRf0xmڨU ~kW'<Ɍ$@֕-|G'l._$#6щjB! 3yOEZ K?oJ4Tu>/D: “ El?zzf)&9v_*%&CXV 2W+\x?NiS(/^l6ⱲXF3fOÍEՋݚAΊ+@e*~ {:_l Ȁr#,xU`я#|e>vmEf##tߛnh9yˢE>wgY @8|[R{"Q_Cȓw ?M7bJen+-s yNCѭ;h 78rѱ 5[zqidnǦ 0Ov{9a ͐ |"eeK2xo̝لߝ& 3=OUdHYiU \DG\9M^r`'v<㼖){rt~HݐjT.F[ɱ`= ot-p$Īyȅg%ҽVجMA59WqEHVo;5KP=+է3kD7bϡY]ZR~g(Ï^}O(Q]?k-8Um듴PqEKL&멺w_&k:mhiDƥ[g,D|2 ;=]}$3`JC~#ECⶏv9L䎬2$Mr2ZnٽCi-1S^C9 )o`츋}$"=r=T"<|Z:uڶM*47z;-YJ\?}' [=GOKGX5`[i-lt+\tPݙ"}%.nS7M^yUVm4 㧩u g;ydgm2c\ jbsD[_«M덣X]$` M`ti+?CEt DLs"7b|rX>mh /r2U`~|/M^ wFVbϧiZ8ƞ[YmYM[('Q(RSAHU=vTv(i`E57to_ N<|(G׏Po8gU-i?Y}+ɶI.+C<Ǘ~AGA!ÕI`ұx Y/r|!oS9G.10pjy >oJ]Kݩ^P$ ;VpCZО@w~l7AZ3JsMmǑB{7 $ Xe]..=6yLd$+nAG>R~CތGm}g)9]!SlLzU|| 'ÞpiIvpƪJtCR$_!1?|rk@/1"kk{=J_ !ZR. 4mĩU~lW-ʹ@oWM.>ɟ#,$dڢ8:xW!Kjπ_MRNcݾ=N@C$+q{猃xkU4r.M -Ԅ6%b9mbz;"۶PcnQMEF6,{c_S+ @S>e趨6k. &fZ+׼WP]LޘxԩϥH:_Q[G BZoeƅAM2=wGg^o@fj(uk|F5'_GK.ӷxq0'g$/;vm&PNg""t>UyxjLŀM) bz7RUV!£I\hW%~Ԑþy.kN|Fdhhj%VQXnznP pz4jGk1,M8GCǕaaE~F;[jkuSCS8-Jp?®U(f\kQ} = ] f,N _ ć93 1R.!7 HN̛&E/~ı9X2o%!Р{/"ͬ_ yCAٽ\?6r;'<-X?z! Eca@m!%ud[ k SUἕh *l> Ar@iH_ 엋Ziݻη]lS<&zR&Wi)o;mqcH 1h^˪z T(0_?&MTR>rcow*DٚϘkP<;2H UC"qA&9d>=UIK' ZONɔs->5r?k fe5&OpFFX AvdBQ[v{FcWƴ;(⡟1=iN/5,,&L6e:;݉a<)F )2C kP<xҷ+6vј@ep&Ío -$A@faKQ]U MɴGC(蓆TNB;[2htU6^3)ij&YVͭج(c[;0-KI?lf!v.!mJ K+o .rM5n ~TVƺtbtx'5xpOQN@ЪY60q :Tгd ` Zl5&2i~Z9As@T֙tЉVx\biX413 *x\F[2zLοwLIKn^]VeJ4 5]皢n5h)a/Um채# AH4vt"ц45XJ ebPޠߘ(FU% ΪvXY"D0X82#1iXS:)޷G>6ٲYAۍ18]]A,FNykC/Pi#gپ;NMKѥ8Mu4l &bۤ^aB֞[3`TMr.%()CO1_9S),Q<ҙǡ`C['V<+(L<#8b:c^vm ܫRGex{,]#)l6Vc'Ѳ6"D빿zOM|i2?5g|Tphl3Ս.8!T7]?r34LjMi+k$bxT}弢DN!PۀMZudB.g @񜏷N ,G@ԑH6f/Cih9K"9tm Ԧ+0Rw9u>\Z Uz=>ΰ@O #{hpNfBV r0c2f$`]#j%_@?X\T}QY$Y=W)o?tmOocQNI?󯡭LON@+%/Q0St hBr4 +269&MHJ'{v[8%`ssUcnP YVֶ5x+`;lF5ƀ&s,l1 uc8ג2 ]>ᡫԨ}>K/[vEw3O+́}>o+Q"B"PK$g1DI^llkIM9cUٚK-wb&Ͱvve"f2تha{a03_B. 7?I[en)}ya^ȹ?.5`{b6\ȮՔ.`~ꆭi 5L^Y+XP)m>bn*(yqh(~%C|iBiaKo׀k|.]̜Q:u)&Cw%sW}eaʝ n<՛ 嚛>^aVa f/wP[e:&}c53# 4;HZ =D6~8՟ ݣcr椗 h,``XEj_4J+*,!,_ثP.I±rW;uʈ?xvDeͿp 6BS~0 A]7L YBй$t`q:b-UyZ!Ks\ 8uzޑ)1q [t#W?; NiQȍư_1!oʝ,}5377M"#t_fǶ@g:h4[$<{{ee/@;5SPgWQoتuH|V|Oi b Wa$c!l:6H!~iuڤx(rW(]7뭖 #|/C@)]))P F߯J8m'܇nqۀm_x@BBl $~lo!gUpyMh'?$3h| =\3*ch2]B2]% A,^Z 0Eͻ3P,`ezȸiCZ5v:~ , (6DjߨkCM1֗JJLg_* &7fCWbi+^W 3,&;i۪rME6}l#WYGjlR O5$AtmӋx4ϖ>%dPb%_,$o( q;JasRhIXGXC"dRDvAsf!bxI yYHN#ʠ{ $*})F m,,t숪\b25_vd$d L &;`y2!VŞ ϖ%B1Ov]+D.{ T*;QP3ޯ MJ]"?],*51{LMhU+kZHsU *dxW3G!3{qgF-lEY;[$h4 ]\i-Ѝ^ -R{xԳ$𙮄w$v w^NW.^ƚ*T ףN ƣ :EE1Rj{Q2g۵zg,f (?LdY-;oY2T&+z9ȦucLq\Q]]0B>tf:VwqWfA틾f:xJ8k<5jZ#9%8()ݰ|sd;p_FvA[=atm_sl0 -]YtSSDkD3 (,kG }Hp'\((hn:8=U}sjȌmz2.; P($ 0&-V0Tpev{BYs)tD.c f5|amCe0CsUJ0kt7%١ݟt5-^ePVsБd[QEJ4 7žǒϥRyuW=Hrp޹rMt>i@; pز3vm 4C &\ĤK29CfS$C߸$fv6f> stream xڍwT6 KG{cH  $$ MzoJޛTT) H{w{f=白ް<疵[C047/H @< >  [bAp 0VF503+$+,@ ѿp@h0 EBBзٰxEE~d] H  .;ڀp(lh4B xH{)v.Ѓ Hw-W- xYPԟ}nP u U5OƟ._W~;ml.0 A!m% ' Q[; N Po+> @xPP_5=fE<CEBln Ws`pߒfk [7uu*U[gAA""+iK}[ݖAn_>(;FA|O ` A!Pߪ!vʷGB=[@of 9{@MucUοJQN p qtп_U+د|o"_g0--u!3 $?濢Lܜ?v /-uзc C!ή&VU4vda [(O75pPDbn@N5&0vпK?PmMDo+ |xo  u#5ZHS%@oٸ!)m˿/b?3 q iY-K>* h.Oqr%A?;kVTiW±SKgC:z/n&M{&雓;> I1^=+Fa0FvI鳐Q9уDIX-M$KA=t_\^F=Ox.qQE<048O&SdPWe42}'ZBfǶl=gցC.a$hogdyJ4d^F\N8VӀT)ʨ'v Zxdz6.o~ ,1vaT)rReogvΞ?a 43Ish3* i xBOM4$6|Whr-p갣Cuֵ* C\7Q|&&Zeķs\c^W"}Yl4\ z32$ވq%ZyeGTm%;W;-|D7v}qN{W}R3\7?ZS\dA#Wz->ZEVBn4ִeH)b(u^D.FOO~'l+ }5kߞ0KɴÒny_`?h^#ﴘkٙo[J(x=[h7*R ~s}&mkxVۗtZwd}:bw{٘k`{ǧHso }Ŋ̏q=m7m_L[; xmn;-c 2Uu޾)P&؁L0%/,2[pár8{cdwH7 !Y Yeϱ:<>ԝ2(t;f F9/֨i "kOG*Nm6 7($Z=w|lc~Z{OȽK}R`~kuQuRPiǩxɈmF}G ffE#fstUuj'34:>)(aycrf} Gp¾|ϫy1Յ?$[tuhtaIJ:bv |W#cbE ?A&exu{3_H^8zcɫGes.$0zO%P|m+,]/ [C}&cyU]KQr9jۯ>TR,<e GĽX`ɘŲLg4./P("x0ptL5BfkHݥ|LWAcs((6 [P)Mv#Uj,!6K棟ѡ Z;a|6Pʉ{dw* n_&=(4w8z#xJ Es Ɉ!&[~qXBԃAFTo͍"w<lK|Q1NN͜(Ӛ![5Znx˱7ۉ`MDbG,hnQ#~<\p`.!S8dwRyϏإ~SX0$`gi4ѵQ ӌh9;j=* HݓF]g4~@QA'o4/#Ӌ%zehI#00D%_y2ݛ"J&&pNclm( ߃MJKC#t[muSTzL>PnR櫙$Mbr }=ϟy͠υ-B:pZvo˙-hUN<&=8ox]e.2Tqqs-ܳ)$*[ b ΃GfWoIB}y$i\ zz68nIVzvLmv4\O[]]#``CBM#&Z>!Bh7;TcO'-!hBCoWd} ;e"]i1~hD}ϲS`K NgAcJ?F̴9A.Vc=8T4}͍U~x3$л=ed{yP@UY05@>g|Md O8JhMd]*fڗ&sj{ӒӟTrtFAKԂ̢eNtr1A\&L*bb p'^zͺkۡ%h-ݟg,vzV^8 Qcnul8@ޮi䀕Zi݋k"s!zχr+C:,NJ-t('dZYV:t9 h7,Gmf;7{V߾7t x3cKp'զ:'(6?jo;Ue@D'ʠ,z*ćheG%|6s qpn< XЭn%_zvbG5?2.lmл/z{J+Җ!deUݔ}-'C'WyLl3kHH)O,+Ʀk>|d8*TfvҏDht(FB#'^;E(+:LnJS,W[%gʈF=Lh$ RH;>5V[M1)VyΗ!UMӕp%"s+'PbLUk2P,QE93P7)^uy?- +(+_\NUY2LYU !NP|[`le}@ m`5~xoPQٍ{gT5FtZ,Dӆ O J|^\2Vڹֆ|C!7nHKNr,l%3G(B^ZV(B1nID9-~҄VPrYЇ)k xE <9De̵خ_ }xyb_Jbs pSH}lK;z139IQ{?vh39$ }<% ŴQ3,ķdQ{ۖض{{l#wG )Bz]8ir;3{[[l/Z;Xڹlawv5,lQ9G|i܈H=֫G%uRqv${ΗfTP.dÔkDM^~B- OZDmVSJ. ƬR(]+:ӵ I:oޔ1iĔɬto$n633Y8#͘M?E=;_L _c7p`Z!Oe * Eq!bታS LpD\/>CXUL߃7[Ս ЭD$#:?M~x!(AF?WH.=WҸ{pʞyAUn/[Ⱥ12 7U5OV02DMs%1D"NC6q$ϒr[Dp>$ʼ<왷>Vx*nCQZX3 m 5ZEڑu՗hpPPKIx)ڹ}QD,7$oI8SƵEdFh^xYpIzZFwbyѵRH7QnvUD:T:x#/{.E7)dV$=P0܏jQ6@<aiNe"ٕ@x$sPq7|+qDh 6S74%ju[ld^wxI yĝqR_IˮMQnv(%rUcwNV^%?Em/YX5bM Vb8d=㟶*8?5, "Hsbw\S ͗FnQ]]oA22̬zs0 eΧ]ùr5Kے͸#e"/w:'aTvTԝ1zJMe3"97U׿GIz`'d`zD|]3WwF.saOoJ69ak:s 0Fɟ8d <ܳ҉򴕴$wS^8qgv(ڇ-^{mm"*h{#'y?g~wlL^TF d\XN;Z3dl]Jx¢aMc=Q/oPC=|ux4.Ӂ+2YC>׆a6^Nm!0,N5z ML~^ɽ\", %DbVmazloIÞ@*0."jO5?L@j\@fryC}q &Eg C\ٌ͝> I7b.c®ˠ帗:dytGßw{*KRUC댵 9"Þ)>,)Cn]EA>Q~Z6|IǦZ3InkNKT[o s6o93_' j%fDw9\rPGΐi&EإXMp8~> stream xڍtT/! H %%- 1 0CwH7HHt( {sZY?xvH.i aHvn.!7ȨABF= /i'0yɀvpP r q qqyewʀ\ @UFN[;5:X܂%N+ BځoAp+!EH!NNWWW=d+ A `WeF A{ 0kr P X/{w8 ;f @@u99m"  79(' wy+'@;}eap{{0 Oo;_} <l 0kEX;;p `EM!?- `7+;uܿ =@"rN`oO X!`[ O{l|?|'И{@߿Le A13_NmU mY*NJ ddr&?h |a6p_޷_M濗! \o ENH f? {o{:#@~6`kkEBFBր b_-B`` 8Yߏte@S |9y, n{x '';~Г~nH .6p'rs9mc/{r-sA6PѿF?$_' v[VA*?KR0'{N959_>|Rt*vYDbsᛆ8/W^1ZC_[T(u$ּn_ף~Sbtt~Mt.VQ42VƯ}]4aq12mNJ7zr:B1pGގ4Zyw11WÃh&g 7"B?!z)d³ osҭ^$&<)epXm[KW &NZbs':u/Dr`6Rsz-6>PN WGmյx^U9|d? pS}[x8+7qP "dZ>X`π˧K\\F/1P{)w2yT}]%Y~Kn+kœ"6k>IS\=XĹXB!SN7yŐBQmu'$Յ`Ǯ^hMڕpjnvS덥OH~.K\CzzU/$/<Ȓ~GGʅ־6 O_Gr9y #Sޔj/7^S2ym$HߞT43ϽcL]A7o;}*EsMﱈ61ܷLchZbE{P/" vb/hA9"&n^Uj @M>Ìƣ5_Qz벸=ɢq3(')r3Fx27gJIϝ>+zRǗ;\-Yp .?oC=$?‹7v?7w0UsbM&Xcv4O]o|.K8/$f]aiTS\Q'&rXٓ`@uөnoڷKꏅZ2rM%b^Z$o=lϊ[9iK61jd QIhKpIK,AK=4c37L`0cQQ^zjMc Zu0YJ*{U͉G>,R4=v_QݸYntB`IsoeqS'-[ᩪN w5x Db>"]|kU+?ԓҗ^c~0=!?qO4\dzQFFʃ!?dzO53hܝf^ߟ:N? t򵋻s&=`z>:kGK<}r #1Gi􉛚h+,J/Ds&/醞dVc_cRuEƗ/?Snf.J-^*˝dY^%|eږM[Dm%0yszs^^<`,N6] #aIz8J;"'찼@5 *gq?aP~w7JԫEni媿$;? ~^}n:Q4Տ?=9_xKN yv~dUCR!o,qhV4t.)Jq0~=cfDQVaw%R|fp0uu#'4\ɖnđRf'WL-%嶘}q̶QlS`C5ҔSZD2%6?ziK)'e4:ji;`2p]Hℙޣ+dbc1'H*3 &Jը<f^Xη6}Hw,TrLf@Yס.K{* k/⎹|%v[;aF I_D Ͼ#N)Ė1X4O8}j׸-m C&e)TD= ÃxTܸiOap/p i^!QMF1h#&Qě6TPK\{@2[)ڇsUGڦ>hI%PG4 i.\ar8s s ~ $^glj x*Ѝ|2.t#|3.]z'b4'~zi^&sT \]KʌJK Vi9a&T ^Cw_J)| 8_/vLez[n<ӧ.Z4gTX׋T-i|=1eHy 1 #䔀o~ ozUz)A|U2so tD{WZ~?_8]$ڑ6쏄Hs~8L;zpKk5ShpP{дyy?)%Nze>fnhr;) ߀üXf&Aa %F#e/#uu`h$DEU5\- Wfܰʓ-ۦJU4>4kh;ݺcԂ")M=1D! [b~ 8ONk Qx&AD6Xh/+xt.,^d}:!8fhE#ŢV<{Y EB[YFc %\ɲ^yoDݽqY`8݊6m#!r@vONoޅ]t %L647קյuՑf~h+a1 xST璅[o:K`zX7$m'ϗ$MvCeGɠ*?v$I__P>j*aJGA ^/( UE"4wv:dDg|6lYhh nK5EZnʲ%NKgYÄo+66wڛ9ӱKm\%_,k!̯3̥`u_Trz_o1IŊ7B{(0FL6P?X6#[!触TW+JVj(hO{N>tFYPy]űrreAԧ*w ~MC&Gcx2.]YaڬLޙ\>yw3bv1wim9w ,JFmͦVЎ겠TbObl^^Tfk֗+N{6 bֹæaBC'_T2'BQqH-,K ܞAяwXdʱA:ʅ W۞@%4p Ǯ wT>)6[U{{Q73x,F~1dk)6[oHvX 7StZ8K=zPMC2>Qi6O˙>te"~f\o1W6=i 6'c r zBU_7=I7w\0V\O2QQbu/whUu\)[- [-w \~|43~K2~gM0Lt8ݣȩ=l7m@+2Dڈ .ꊊ.YѺmO^F(PHN8L6ktT+Ruw|pbcĶY:s`h %tW|A9aj a&j- }ǃ4:B;r{Ojq|[ozaS/'Sk51Yb1N syjV'K2(z\vmh=m6L"wno YD=1Oqk DM g2z$/;ϯmB>{*v-ԣg~#6/ȪM:RmB9Iǫ;y"j;|PE6:%^n^+K-QQEWye$vRetye/7hkE@CWpwNX6QXMј}VI޽}mlvQqJɸkTJRCRi2 : x7 HN 2m1|0=#nvʸXhGˬ6`y`K%jdQ:]x{jίƹ3B, V`+f IXDrSIGH^ȳ'N%),8C쯀&?x7a/+OijJ3^>ThyRFc^!7횎aF<78JJ{wXNV9Gm +~jWޯ)W9و\z5beo?NTZ3WP(En$FT|jKES=p@[?J^)jytL8l?W7whƸajġWyZɛQ)a 2;L*y+dD ק*X}G5z {FI.;_=n;d}&w n5k-ĿUۦv0`K?Be4fCzD{Ēe름tDwf_ν4 ?==pccY:XI%BthS]QUVMvU9;vveXn@4GˬM>}kw*@)GXymH[=bbm ؚJit|Rܗr1L514|4[U{1YV`U^^y#+-78/3L͂ a3@ف9 :ZC-)'늈ضvy;vS\C CϼPFO}+\ ^N/FGS ?'V7T=g۫)R7^N@/&Vdq'F;NJj)h!a a$Hr)քʏsgF afWkYl'UCQMxM岷^3(؛c >CrpXPbع7f9'W m YeXc+ QԠ *b'+DM`7IXQߺ.icV.GPhCE'LP&hkFt~XGf8 eW$iu䦞= _ι9{sf4ycPܳ|}nSh#2یB^2Դ)49|#,h11IYR%}xaLõ@Ewz|n0Q(c4am?1_s2Ɉ;tPO nOMK |4<;iU:U$0)8&tsRxkL&*C{G힐MiUݘEXk$4 l젧|ו>Ȑ |!JaO|¯uQ ǩNvMӋtQHgA ޟd.Vl=ycq''SZRwcA/b*_Va-^<5YEv hu 1옆 ۠E| O!t!o+ʼcJ3Dlrc)!s5kU3نgx,7l'^YĖPIѤ蛍lB~Zy74&idG\lkx@5f/MiC u>͗/,^a]fw'qe̋~{̈́+_1ԫ0Ϥg 0򩎞״y)֛ *bM`7h$g#e#Sxi /FFTݝz "xnytE-uaEDήMSV4"?_\SVFز#T =" ["b.3VNUtMɍST`j#ǎ endstream endobj 1430 0 obj << /Length1 1357 /Length2 5946 /Length3 0 /Length 6879 /Filter /FlateDecode >> stream xڍVT۲I HG~)JOBޫT)B PHQ MQK'"MJQ HE=w{kV|3g|^>oj!qA`8ID 46W )D$,ly#XAX?$pM,#ڴ`81 {P*UP@iD_ @R kb|Hw-(UTTX$a8x" X`H.)Dxp>J`p`` 'JH`C`v 1)0`caX@4x#1ij }#菃P)+;cP>0t0!U#)\N]9¼0xX s!:.訛0bu"}p~R~H_!^6UB!8?ЯXxcBc?k7$W >`+4rDA |D+e7e&naH7 ?w (pEq hF'E!DAȯϿWDnb.X@Hw440A^RZP4@\3) Wcn@O[WM_/ae!2Mp{Ni;c,oߨ/0;/Wj#Wc+>FԀ:ߗA!\M8[70!=($*#7 Gj_꒖`X,,D1q'D"~3K18b@l/ p`A)/#X,QVO<_F p~˛*y%J'M Tiϳfi=LEv&bRC͇AoWhx%-ՖB}CEzד_b0g "M[4[z.oH{T^U}dpQNJ$V0K)A8(lL!nVhȧ~\B\v|;,.5V 8>K Fe>8膏(\ F&_zM~~}Z m]/ZB7b2ұD 2#NN _KK' {0<ϭs1 {{2_e_w+| ߌ^U8 :#--pYږ2cU#ѸH8Wᢐpr,spp^-Q:Ly5p͖%'ՈNzRЪEq))飷Y[ȋhxu/%9߱{V޾gBO.֧VMyJ9uњiNH>~[ҥ y\iƈ< +PvQ)ݵVWrg6r+Q j-ZO mSuѦ= EaNB_kŌ5ಳp [. j-j2ٿry?g3畦1Y"s6|4~qjhiY!}SU,)+ׂڃkjӯGXf ="6O*{OVTbjL¸4LAیyy>HJʙs<;ߍDyfV5~`lsVUʫ)"Ž%M`kuu܏'t}ZGm6p5pQa5+ t4BmIw?57>pܘEa8㗺 vnYںM~:YW9OFU&5ZV(S7 ;~Ig,H!,B{=X@ 6_XPUmKog~|J2/:H{}{R \Ń(q^D:2wQ97K.VSU+(kMzVؙ<1  lP=!f!*7B6G qaQ<:Y] yO+QW9z\≀v%F]%f8& O:d 6M5=S'u E[!.òi6s>-p;bW.c<-rHrB*lsH:'n9ŗj>Űmܽp-$+!{ϷLsrvJ.j#ɽ]џ򹜑_.A[h*YH^ęう8vD# <+s-1{S%ޟt#PՔgWQO"Ǭ$hȘu=9U}Nc ;eMZ=d2[剦ܮ)j+(ȨfoG]nqJYތ$? )/(\c#/}H^VD_TnQϭgeW>h|gjƭILdfDHY3e Le-9SKs$ \UX ٫;>}O43uF})b t]aTnHpi/mC7)Ӟ `N;xubȃ]e^S׿2o={M5nC6ژyZ=Wo1WGF[1ϧ  c4M*be>ހFˢ\Fa#;A(T9e1^zmKeKrוu5#_ 0o=@qe,BvrPSʕe:Y(sMgeB \k>4su_f&Ukz9 ;Z\oipTlw^-]Y廦Z$-}l,q9+m̐x|Y(Q=˳sVzm2wAM2kMƈGm\M+ԫ/=Ż滺SRo-9 61^+ Fv0xz`t9 R]i^rf Vy\S G"-c&f:ƁG +2{R:N|6y:a5ɘUFC.Q.Hn`{{> -QMPTڪ7t0 >3Z4rƾF68JPSDxO_)Py7a)jN6v'"ldhz!ծ/l[:G&ԪlhFG>A*^M;ժ 7ZCHщk]1]z:҆4~z_w&n0!-(",adg#Llm' [qto_7/NNsUaj{[F>ʰ~,jn(WWX"&^ॠNadΓb\d\.4Itzy4p'-̉pus&k@) ^$}kK"/ NEBc}~ӗ^ӈ/|OOC>PîuԸ_CpT+F2 )Em9Qq(>Χ։'uHyg<'R q?K947-D.rZGf5f5#ǵzW ҂1Zbk-* ҮfnZURCyz.,vj Oj2+ӖZwWQ`g?Lf12Χ}Q5Ѵc%\&~tU-7cKKUA:_wզjuuxK 1V[/1"kMSɁO]1{CwJwa'%oM-kٜq+DQ}*EF_O{ǎ.F0 ^|R-hxv#Ua عyFbgCRn!!%VXpK}>n)-)``uGܟ{vaIc̐Kȑ.!cuQ%[2HytI) M *kO?mfRtV &:wFR2VGL6za˴48S]e'''MJnfzBesc.7)$]c@q+)/sBcE&B.>}jX@{KtV.v}${P7mTeK=>iOb0Ib21"1M;0bI<:7tg9%f.Ht[ lz+G3iv_Y = ݔq3EKe f]Z4}F6+5Gh7L VNr+*PZŸ4ҦC8u}}y4+3кx9.p9s>ǩ>۔2wN'(tw |cꂝI$eW5.0)<ۅ"mxҵ &6 N*Q i>+ù;8 X)|8j~I9)É>%w|TwﲿU ǖ! &jHЅ/`^wعbԇHxpWu@gw7U5շ\\"F +-8ku >;o3{|2~)h~?_G1dMj}gVVeiv0!<,/qNCLudSV6bb^d;fTrÐƌ䔀S=rS)A]Jat'@jY5v?YaY+S%cNҽ՞eW;Z?$,ZL<M3(2Ŕ[3ti5 [>3Jh2̝W\֫Q6ZRlA=G'[S. f"X+ʝ$@"_}$ gswVh7oUݶT`rZLBIi5b<1 BƳMCݴ%DT٬،4C|ޖsKuntd“مW#5,ݧ+o1D4pĔ:}i05j0ugMi8o50]n,gS z2޵?٬P?p XXϳ[&F\857Yw<)>gWBu4 gS,"8AV+BÊ);AŖ$|?ɽ+V%V~bCSE"^Ε/jQJ{ Թ>yXVUȭh;dtW?.$AKY?xɁŤVq^_~<7AV/=U"Jc3rB{7`B{p?CkGW7IsO gŋ {sM> `Sqf]sUE'ZxS o<`9jޏ1fޡPvySO\X4d{!"D]#MR6grh0A ɢvl( 8`Oe V}oJM}oDksKOQ2N1Wx]Rdg`\30@B@QMl/:oW1 endstream endobj 1432 0 obj << /Length1 1386 /Length2 6039 /Length3 0 /Length 6990 /Filter /FlateDecode >> stream xڍxTSۺ5Ҥ#H7 & wAjHB$t^7J](]zQA^x}kk͹d30T`($F$[ PT!4c$f04 T,PD@4HBRQU C!ahN% III(<0 8ܰ!`0H#K {{{ B('y^7 0a^0(=hB$g8/1 C!H(0Ðul$W?ѿ#p #H/ Fa^`8n PW2 cBh8׌¿`Y UA4ɯT0v}+{GBt6Ex´T`&ۜ`PJ\\ =| ¿ ~;31`pG 0@tsEps#Ik9ƞ`0( 7 iݷ43(@PJ@ 1@?X-# W}e?#^?s顰̅xMtk;_YWwGo?_v#| `UjPs_ՅAn€jPB:a-+Vp /e77 3@0( |XA\w4]0YW AAMDL`|~ ,Da!쌁GɯؙhW98rLV{[0 B2?Ȅ8UbP欁gՈ" zX]tQeg: MqDmLПg'Dl* XG.d44Zxzl.˞#wN+-n"7Z^w D8N$Ytfom%7k2SiCu&'NwiW`O4(4zgGl)ð {x1)QMmX㸅ȣc7RՙݵwۍF=UsRպ\RfAd'dPYcBA{hۊQK,Uw ^4mu gxš? D?|p{jn+Aݥң"ę7Ej:"v"7[Q$[>S 7;<Qdnef&NJ[DVҡ5r=gUw8(BJ3{9Πsuwo!!|_mTEQkWM%i݈{1:O;̴LVAOE;747LE?!һ$}MaR4͕zWd'~ 3C?~ՖSv[&-Nn䃼@jie5{左[F׽Ts UIȧFr):]JZY4%P!M?WșhϏ$ءaSzGQ4cQ˚]WV?X[t8 4"Se =y<#0lZp\7.E{:pU"U^hzzIǶHaITX>oxYPb'yq)F~Oi7&lT?ˮge(l~90qV9]\|>\*Zdxv]W}[?+gM)e Pjo}q}G.Aj`{ƴ5=G3WC*IDzZ3+W- u˳m7fHqw0LgJ+hR7RI[<]6C3WILggdgltyͱJR%5j0[0r'm>8i(s>{meǏlp|in|;ԙvgn]I0S? !0j)n-R}E:/!#G㨛U9:o۴?5f>b?^\sNMܥb=!ڌ8wnc\6΂'2,Uϼr`}Ʀk^%]q[9NJ [x;N&"- 5z.6B<{5B޾K~'\}BЄeG4lz}]g$-!JXo*T2.?`gl`)V !d~oѣnW?wݑH ]@ O7}oz]y)1X R|[727r4UE]zaEi-U'U7yYhc-b0kx'8tx.Dѳkx%{@! f njuɁby蕋Iv|Ho J8 3$%ͽl˾&wIbpa[rfR cG(]S6!bs~P^Ξ}<ѐ&A$㰓[v²s&>'+Su oR!Oωm") gK[A!ţըC~moC| [P輱:Rǯ.n"cd67wK6Ù_'Sp|,F|a.2))9 \++ĺ| ,"bBnUhME3ƢQ/~;XT悔 MqwQ,;[П!%7QM9J0XHtvdK.8JpS\dYiہQļ J)N|[!=͚QbY%F~=Q?cґF՛^gl᦭*Ҫd_-Ei;·'Mc]L]ecgz z 6R kSHXܕj^TQ J̐e4>c V/cbje`rbqؙaΌ O`kn_EkV2BDKW i7Y͎rK%ȑ/ɷkhԵW{|Czn,)v_-vwı{ e yѼ5OR d;, ]kA\8]vn>&אY8Ca"r7q֚啢s;<5 Ll@.Or%Ռǣ==+䂓6sS/n2~ }URڈV0fo0pj22fm˨@.g^pdt,Pb쎆DY0g+*mռ?sngS~)nFXN`fLe鳨N}t2m `^uyu'cS]0 `%O)Ĕ J(RK0)a䫌  "MO-5Y@+횃-aF $O8fh1*N>niȩ.38Ep:Z=g\P_kn+:Xh߄oqʑxXv:#-"]SY 4{r#}1E(BuY0ՊcyOB4/rky8H»rCo 27n'EPf^X|;8Ԃ&Q`YKFY4@F3nfyXܤE)b /c=u1r5|!*x]m:1LJukgsC:!a\ ݅xVfO^z3z:G/NT+t kNQg7ʯ62OWNm7w|PlU((?=$F_d2R^_EU\UE"||wp_*IA؅ӊ)AĨq\ݱD?jTI?"+!r S ;/B،1ПKfv#{POlduk"'r OP5KֺAyY9XbiD*NQz)hrM3Sv{COEW=U#sSc/$.gK!Aj Cb%\cV 1B&m.T 2@"fUR_B>kqQy'E w؋,%t=/齗AA]ޣߑRFɓfab<Șp[Ci$q6qnyQ 7(%CYFXfr9bR3ȓPW@яPHVrJU͋7p,lk_*Oh}'yIk|N-LKR}şua sjR8Ė8w_noUmNf S`{*js,W|ƩI)i"flvX=5S]j}1w,oPN5b* ]*"KzKM%)։u.MCI.LDb#P3pAk˪kSE]u.z_|>M`qX>u"9=zڳaz s}%p^5`,hoN~Jxd~;B jwgTFCVclSd,iRоTsIXa-s*:EG-t>ğJX"[ss=d_SK hǧ'y~{j2K` ÍexlTI&yʞZԁ~᪸ nUmV}BWQ9MD`Ͼqn /ο`i$TעKr3ݬk-=mxA] Hb`#b\ ^y)Dgw06|bNmP`f&2E%{ E{S0d3)Fy!Pש݆mO/O&h@*-.>͍$lmKPYg5PCk-Ǧ *\Z&_&FLX?o-X=8~8 .+"=`Yδߜ7W@Ce+37q㼮Tw;?Fz0| /|;ܘ:o) Ds =K-a鴨\gWE > stream xڍtT.(0HHw#]030 ݍtJH ")! 19߹w{׬>}cc呶FXApO k$'bcӃa"6}(/, F190 SG*n$,=ȁau^ u%bE8{!av(6zp@8GDNH;A0PN!`G.QCr=< s[ ;`s a(W^WʠOYn-prQD!{ܬm~ a | AR0[( HXXPu@=!v__0z?g3=fEݡ \@kD6G<&|h|~~3Cwd4L <@臈(?em'Wn<-ձ_p5'4hB)KwMῪD )9:sa/-Z7 M51:Qemi-Z< A^>?8U ւ v$j08T mAgW /m+ _HF"^D|h9 |@hCZC=+#PzF? IZ@'@k茄 nH$s%n_B=)q}Uh i/CxK+⍺"P/}3]d, j}~>6umӴ-+h1E)!ߵ&sēwyf eFێ>[#?Lfmic `GHfFfMG'@W2TtN.V Ȕ,i榧t'V4,B1k$.a7+Uj;pJ:*o:,:W vo:/b;UMY:ŌҰHDmƱA~^q^x/$n5"5X^Xd۫?yb͗d]kvnѝvEh#[WQ˛m aBrcƳsjU$ ИOvt)(s<6ܘP< g5}C~dEJI$rC 7rj9gتV~% p1/^=$FBwo8:z@J-()»/cլUm`.1Ր=Ju24_{T>veʷQ+H 4X(˺}M1{Nȹp@R{>ϑ XgQ6;Woi 7wтPD[|twg2a9Q^5hfΦYZs>Rړ{bm^||eO` d<85u~M 09Uyo,`R[P7Ei/O :spagt6'RQ T3tWF*`I Yˋp!SqPD* I$;K触$]|A;cګEMF%U+ v nqSb}*fRajB^o:ĪtMA\Ҟp?q!pQv}L|CΑC.* ),. Lo7sIzW~>5^fLσH/> n%ڲjKs56 2%Gr4w&Wo GtqpЎ X3.+rB@sdU3QNK&~k"?IgbE \ss$/+bc.g~,wY~M\zP9Ζ=)Gķwڝ9TɆt=hYkKW>2,T T﨤|qy̸#t$SS*aLZհ|'|)߯gl}{+*-V8&S>OOl8*uw9oӪ2( aI_39Aӽpn s`J?}GK~v6; AC2A3!mv7^FW!DHG$ZƯucƤ#q9#|Weܙ](!1si[Gqz 4e8.IT0dZl6"K}.) /J)=uOς۸#o`MˇT׿#3k=ڌX|cpnⳞ@ ȍl'Ati{I.)M_b7MP .L 7LgN 'I1;#a(Sܨ[E`\C}F !I3oִn"a8bl=}%t 9Y1?#hIľIQ<*Zaca{,`#;xmC]'g!K8ucnx\7VՆeF.?Mt ērhn]5x9o4,N2dj*IurDd SӬtq K ;}ǵ*K܎*-iwI/yr6ugC.!xY;niVU+w[/0q#?ҽ#mYN%fb2:O;츴?M_/"]tf!2\qi EW!w:ʯ7HiJM,'[FMar ?OfL Y7bOnEg EJ Lmѫ¥ s yĬ( >1zz9|SIJ#,icP^ nb!uh LX{"U R$kߙ;P{v[0I;BZ`w.%m2J\h,.]8:Kذj4V#&,lK#&tκJ]1B}w%e[4./sd$x>^(ϸn9LdT%49Hb]}BnuIYNiäls c61ɖ-ƐOSl:U[nDN5{"ǫYw[k_uuF& |n`NR𷕲zsvfٓm\0a7Yfa# oEfaM[Ԥ*vH6vWg\(Jjc2_DpN!KK5 0K^WG,h&G+aZ=~ IviKXFu1uWK .>3ISۥ pNTit$z#pƋ3t^b%B5h>`9T(fP3ZR%V8pCAM̷yC| ލGЯ*U.ehS:ҩ{| \<)xǫ-o`3fHLc*#Nz/! 5lZ$*9"fN o̰;$_7UJT#@/(x:k'?k>޼̠:`5^TMg&;nzuLɴ'+Qy6EHup / f'1TOpHנSQzx7|qnMp2Mh#A.r]=C^?upj˼/@UD;$O'g;1y%ݕu,!?|14tnO?F1C+ ;iǙJ.*U_!:EH"h:Az{hMX(ܛ*\*]FYdA0_ag9fcuU83X:ߞXtyJ^[IØGBJ~.e]R̋v偷]ádu}ӡ2wa K"8+z Q߬ޥ v7S?-lKrQ~T"?f/!99%c$x֐Ǵ}p?=xZyZVfQv>'Q(6'-4B?QYo*ixYHq*\''AGy@}%N[6ocsͤjK9ίg #)DY]οA+,˪³he*_+D+՘|u2э\g5 %*#NTJ$bkLW7*]-m؜l}ʭ*{Ir?Jٱ-O:+W5y4J/q1+ײ[TwG8V쟓09VB|MȆkGF̂_ʲΛM:A3]:>I,wG(hxiCydC;o^| bR/.>p&E䈬:ؠ__S [QJu.=aŷfMGֳr#pa'$j֊!fd e/j{lHs*)&Bf_Y4*)ޙl<'USӰL!|m78P=zhW]enIB"'{aAiG{X,U*gI;)e;Ǡ@$xұ17yۘij`U&%ZQj,EE=lRͩc5c>(A"aqzMvFvf':L)G\N:y=.yi @ )>z"ry֓ݳIR,c 8߱83 hϫH҆7娇,NjX)ǻoRskUO~3@tVTU %h q]dK̳i&f[5q r>~(mG!KX737Ώ;I $[UNu~dfmr2`dŒ+tNμKzŰhWmO|*No($6IUSI?w$1g7t=57Q32-Oe)JH]T^  BψRqb|Nvݞ[Sh+7^ z͕'7-7fr]T-V[/y>o?.zc3F nQLa!/K)1;FmSĎ Q,:ӟЊ)_ڞvz]# 3Uh kҼod@3%}vXzm2_Igvxm'b0Y85p`Vp/\r|QHP|VNNm(()6O%B(exo4G]idњ*m=4xǁ֚X=ۓ4Fy}HHjog?7ut^:SgjC.+Qz{X endstream endobj 1436 0 obj << /Length1 725 /Length2 14862 /Length3 0 /Length 15411 /Filter /FlateDecode >> stream xmspe-mc6;ضmtl[ӱm[;~{[ﭯ?SO1֪z(H$A.j@Ff^333 B hbe7v4fUOwttP;а56rhڻYZ܄ݜ]\9 \,s+[ @LQI[FA @-Nƶ%W[+S) ;lLAfVo 7?̝j" j 1&511 'q3?@SMGp,'`fe0ZXś Srif@]mmj1{;W@ {w'"-5-?2.!>%'ﴒ_,U.NV]fI_-[%*j ``qq}\SW'' ߤ3 ¯.ٛXUITBL-|[EmifxpH4h"s-sBjD<!_.!|U.xi03Uq\[ R`=u,@b1*BJXISg|"jPg,C LwWw) - +u .tf9kFڊ]KZsL8^iqw}Hϐ J9%)w4Z^2UnJ;C"P5"ҦާRtqM+;tVb,ke^)lFI Z,!&rgGa|n$뷦_7O\4x{ػDi_(,beQ Kc iUa7׻y3mI0k (_9 3Uh@S;Ců⓻O0d6*D|ĐȰA.Y2Y 'sK>Nnt$ [_fhIsze69`&wzt|7 bӼ"ƕȮE媙f iӯ?= ∜`nCh1y>w,v%nVɺI/g>ą ;4--C1ޡebDuyUWLO4QʩJеjt_d/LH 3ڥ$!NLrhB67g׏ ֿZj^f25B0F~߶5 ه$?x{4LeG0G^vPهH=X{j2ޙW֭ :d9Wh% v)qm w:?;7ҼK &WNras;y DFbqyɐv&?EVpK@z43ǧګHcb_%76~ohͥzz'=6>%X8 duN,&S*F`+~ ?$m89弸'g{Y0-B(N$!ʰuu+q[C=Я ta/)S^r=0[#*ge`&,}4m<÷c,e.Э% q>Gj ΁tj:Z M8mQUKn@F^;L)'$s[l_wEA6DF!X*m~J5&gn悩SMhXa<^<è@b_!vO+ZKCGz9=b3R4S:ޮ@ 0DÂyCkuzbn) T9v|" Dqѕzy@GrD<1uJ$V`y^({?nΓ²]P8:`Ț3>* :+sg t-FOw+{?5kKCI3.w#D`I raN ɗ>В) 8\{e}rϤo +$C\Ål q4&5Brc['zɞJHx]ZlU#V9=!&.RJTфioSg5{v3Ls<8/+>uFyɾ3KL_煷 ܗ$\P4=^%d86B#\ztt g\Qqi!+y[᪮W"I4MNy9 "߲"g 8p[\e}b ڠL6HV R_lo$vbhh[Wy˜w^]&C<\}ER'Vv8U75E(`V,Q_bk0Ƚ*ٌĄWջYF.q4y& -qc`k=~Xi!VC }xMwWf|,^LV9@#JR1}2$w:~MQrOyn ZF#ydo`j6n>jMEL.%riaȸNZu 5{2d)f}#s$T`s"{.}b1Ϗ,c,:!DYqד~D;Ni.o1 XXi$R h[J-amٚs!KЇ'\ЪwcRf̘Iwz:L˒N&ѠAQxIζJޔ¬tL^A\/7%t8}FJp9FMh, 5gn7ЁSBdc;lrzNj:hƈ7CEwhgfzAB_ c.smo@S֊hڮ؀60ϳ{:;ӌ'XKt^˅.`chtڋ^#1ZNQ`|! ϐd5N5;S]Y[De\I 7 ҜۤAE&FqQV+֋jWަZvzoX\1/a\:6CKNu'ycܑ9͈r<*qܦr)L#B"!JZCʼns2ŁFE)MkR[FITߑo&)8o#TDEpl?E, VbW^\mYg$&+c) ?ذF!7^aUSzrUfKJLMf$FiZqQoxkiUV+L\ER]J҇%"aW_|}i7Lb8{Kd8):|#X'wwVCKW.R*n E'E \| ɀ  |2R0ΒyZ72=1L¼z\u` `Yk{{TdBߪTՏZ>$6c?gεřSWN+{0A6±2yax)Q,=A>d  Io%5Ħϵe[vx]Sc}tEL9Ca['t3)!n.h@v%^|uqiC/t!Q`/i\_Àp1uI~H؃ ;9{Ѥ8s*M}}r{vêel?g&_>h܃[$\~QPzl8-a6R^aqmM!woo>8uu܎E tBkƴk\,YlP&POx<.#O+;LԆ)Zx1lqxTǿ\V,OXQLA/ӚIp%S[WM7+YcC/(AB.%)2׬,'G7`i \(>h+Ry5cʌu=mfYnʡe cLG{˟(375 HITʡEL:lf,,+A{*a &e(6OuWjӌf0gA;]KشAC)v ^Wt\Wq[c^Lf~[d펶7#Bpd&&͔6V-7HG#K8aPNleoH_1G5,BG?5-Z-78 .C>V-;^nZj? cGjp&(49'^7\mS37Մ4votB5W.@ qunL4kVG PH' kPwiWRcX7@ӎM˧"WUA,<:/p]"k|ѵnB0&R}H7#ja|BTmPs?sY(S@8]!53W]V[(j,?C);OGWMgz0QF ABuʘ)ל'Tޱ=y{JpʖK5D&Y^IkLg2O$q59F8FJ 9+=OCWm2pveǐ{6r~JSi|؈MNJfs7 6T.z= cͭ (l\L(gr ϒr;]?a7dfFOj:ש} dwP;uBJ9z8OQ{jCNL#nV\,y I'O6SKT}gUUfv޾*#JRfA7` 2U i;낒jAG*Ϥ:U(b)|ݫ88ʰ5u^{vx_IC4Se,.A2̃Hšt Vy)9k= G"K/μb>*E u9kO#41`9X*Jw?/g?$sR X뒉_aH|* -T ~u{0F܊% "FW |cY/U_6Q1P٦eʃw[*M"<ßR@F6DF1/k0IJ"󫈏 Fg7,NTl. 1vǰ[xp16<="&p7z. qҹ aҀ>#@[ I ̒W9M?He;¬wyC= %Shm#?"ײ{Q[5EiUپoUwǬ%O\Q*-l% i> ˸@ ׏0#F|{Vy1S3LO *QкjLVU)g5ZcaQ9EjL])q ;an4`{dWؾPRKHXe*wmћF% n%ӫ'W1a20V]6F6SWr;=5RcjWtY5\P5Q\r:˹)mۯOj IHYR4]2:3a]hƶfc\lչ!K:N5v'1PnWσ4Us>ffv`c<Ǯ?3H>N2p1Eܵd}!Ln$2^`Tdh=BWss-04KELbn~ӽI^ r@*dO~,拵w 5cAi?Ⱥș{^:Hkw+`L8kS?Ea?1mcʸ-T0v(Ov2P/<1ֲrV'$T %EF4g(sS@A^<|b0(7@ĿKB+k(|a8}}N7Q 3b˝O%뾵-1YA“=@mUAŕB9Z#VM;%]`ҘJQk[ZpYBW=dEF.y-)lۭio#-3am2jzX@1 Qjj.oaԃtJjfI^-U+%9@I=PՄ\tIt3C ;vbXQ&9p}_qe]{rY|A Cx)B '9,+L qA\}Z^^f~ra8ͱ{i3\2ET@ bA{=MOUSC+-zXd ŅR_3t p_[HǎPxaRkmQoj*EB?MB<#"+;BÿIIK_jWL󩈥[B"|>Lw#ʹ߆N?xwv6 {83{&n)+MJCswr(!sG>X?+%j}cw ь:. 81M,K}YMf_9%Ԏ44Ad{s;nvXd+!<,h[솰~ WwڬdԶĞ_|֢ {_T-qSeX""jJ6OJD;Bx  s:`+<-L'[#K`S#cќBAGT"S+wǦT 5ɝT3yʕBy]*RA;ɌM׌@ѹ cЖD(Oq۰fj2@#~^HAn0 9ӫq9si=[Op&ʁ~J 9,fO+y ۖrkI?G`X5B \[UOBhhZy3)weK"`."6[a=`H8'1 m<߼έUIJheowZ}=.})z{ ZB*ĎJ:ȵYߖn)NTq;\W -Xwd1]S$9%܏jLֺ$qrj-M;*k*ȹH9]w YoG *߉ީ Ln;kP@7@lCg E,@]&#Y}.DuS?𖌦OisXSQ]rE?Þ.ȸrH?ww2QŊTaďP}DfE`qJK:c.̐Zs@T}Uë9o~\m|g g=H%0$rTIj꤈/3=gϊn_xO.ỽjL4mFyAGB7uIѩj ҿ=9`;6c\L5{u_SwSL=U|xnPTzy ASxJ-1;3ddikއ@Vi/ot[\Wg lUŦ}kRj!V}s%x@GC!=l4Ԭq@54(H%wrLwf0*>\0Ca$+= $zY=ˤ8[O0`{ ӵ;NI^x9E\N/gjN!EL(*6Z*z /L7%Up3^Q+cdaVL);gpy3)r %1ܣtb`:j:kuuVbGbAur,az+v>Oo5gæeP.&ڪ1Ze.-' 7 gBZ-v׮Q~xoݲ-TQ(V]XYUo-Ya6N_GD5nl.n>L:P^ڝ_ݷ @\2MK.>$#.dz}Nyиa)Q9m’8S[8;TL_戮'+_J2,ƌEC;ӷbmuɑ6G{l+"DR4.~LT:({uxNНdYKKᾒ"L`F?Vӿ?n!Z V\H5Ȋ츬 ԫfF'oǦ\tX7 )ZU[#7`*B3["zu#]?{Gѩ̆NP7h_z1a-œU{q~l+I.Ҵ4cgq W`THo̢2Q4'nc't9m1o kϻϤVVWmR3j&5fۯbcw;T鳜\чT{+ڎ)U5ܻ~:#f&6qdjr-[FԑFn37u1ܒ#pANoF{Iz-{L0;Y7YK7J|A\+Bo,wKa IҮsdu0YT K#zh3@U' 5F 40rM16?Xz@ zNH9\ėG=2"dPv p{iîT4U{L"*g&׵6{Qj#aDʋ 5hDrIǃn_s7ތ:4" [:+9נbwn4r{ݖ_>S/I nbĪSpa:[(Op\k5UB"oAԔv#}ˠu>~Ƃ8aYbzl9u[ef@3C(uߺ(匿βx[⯋:>hڻ)ֱl3[n H+i)_jeU6a.K( ]rTfXLg"&tK_pU~>u'p\h:.m&%ۼG fuv@PLeۮ'~БLj,s€Ip8A=;8\g<rJ++]kG>sk/B[dl,s'J!o֗{',EPuٙ!᪦i?ڴ^0xL2eiOwPG?[ҬD@= S@mR0sGE\bgV#kv1s!8Z?E!n;IBŷ/[>m+BtIm =5㘸r8ͱ'> 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 1440 0 obj << /Length1 1626 /Length2 11624 /Length3 0 /Length 12465 /Filter /FlateDecode >> stream xڭweP\.` @c4N%8A;9S3Ԯ]ߥZzWզ"W`&6fV~2U SdRZor.d** v4:@K$`CH<]@6?%=S vP}N@G[V { @BEUONY@+:]n " X]8,Jse~% 0:-@on@ _*F ]!o= G {7˿ɭrrY8ނ]!. '-?pBl v`7KK_%{ 󦅘]\@%-[0'0\ADpZX]]¼;ߪ7sraA\Vlo9- oA,͊܁.7{af vXY> [Gr.}nfox[2f=Ph/3_u@+W%bo2Cry-UA 9Z]A7^n)_t6 ;ǿ hߨ<\6T}(E l_ˆ=ظyLlow 7@l<+A\@Y?%р9ZM R[?<@^[|MH Iv;iwmU>U3OxS\fSS7.~B hpA:pǦqBHiǨPSpxD{C?248u߳MĐJ 7<irUg5/$gКdUFP˼$@HqbI52pM?Ibbo p#7S<\,55ʹXPLdp #^B\I}w;zCNҽt.ȢiBSsh ~@э0.X+;Od ygj?:m$_$k;{#m)I(\-gbj8㬕tp̛r=lzױkLxiqqE?*;3z݊GtEp@6 }ɋU0SJ⫺kSv& GN*o/˦u>Mze/ҙ$r|%q]&mXf9pv*$4ḁ@x v\ ԓ-6x6xOx~݋e^hdgBH;5"?QF)F\?z:|Xu{C[TK?u#cM]K,<-wMPIb<UAN/~eqcē/j2q5J?TH JϠ qqnBF= ԣ=>}׏gGt!_d툂4{he5"XYr Rn0g˃>F.o*{";ᣪd,pqy*_-a#V(đ)$rwћ_V|›pN|}{51DlÕ&ꇕPHg6=*+?5#J}'ߣ( g<;3-qtN֋Ӡb.0oXRNa~O)]ބR?L;m drt/"d 9$Y8yH @+}mѠWq /ʵ@<P_&%O5ŻR|E!W|maǪZ[pD.Hi(7uD)j! Sϒo(\b_194-VtUF Lzh+ԕos߇@rH+S]D@FR܌W>-/_HFsֶIr{j*t8v}Ȳ"荌MFʃ=I]}c/C!ĉ0*PE12sOIֆs?!mg|" dM;MSm[asM~s=y^vtZ)Фׂ#4M**qtw&e'ZBzNkaow_Ί}I#GxبUm颜Q`E*Q{/-Y {/.LbJ1{%M,QK?rs"L& 6|wrUو7kxSn/>\Y$Tr~a$+)M3"(7GhS`{/Npm^P]s6VLY4sK.p+6Oשe#5KUğvf#ZHSq7nLO}''];NB+T ~ԫ ƃt(FaތlRLyaa0*| jYDq鿌L{XsjFwb#<{mPHwW9>ZɮSHlanDU,L!BRZsTd-5*05/Y;5/Y >p׼r\m}LcFhm:A 雘D<{-QҺM2xi3%IS]ɩ)/Rh&C=Xɇ`VƢva$2֦!!S*A­F)4O4';^J0LOsQt"[(`D|;%HOԎg10Q*`Կ\Z辯8#ne5n.LX:>1H#qف_Ieڻ 5O@UUئj]ȷL>VA;l5_|Mp@IV5&_Ǧ0}f?/6esVο]NL HYL$/C d 6L+sXle^B#-ڙ6%z8B]Kb혹Pо'|N @Q;ۭѱxIJ~b<ׇJՠ: }**q /7 =슄R yLZY]' /5WCKl˲fPM? Dlʂ muG.^lvb$ӡ%Ot9W5 hI}ʥ@%2G21 I26ۃ_ p:GQ?"Ȍ%5 IT#љ+6.җSwWIr@6(;C.<4*U$*>( D #u_&NO' " JA%DUƻfe̤Ҵoj{8GQwdGA3p7A~_ % ~PR?Lr5 4sEr{\ᬓp]фà 8{~H FGbUDgmƸ$Ra]Ȯ?V=Թ2T/,_f!8j?~CCxj9.?y9ɁĄ%7s1k^1ߤP8^sMUIUb푉eq o_Q(N17s,>SuwE'Dc0%ϝ6}8 O_G#̐Gi%ép9sTr7Oŵ.Z0^cS)841&a4/m;Չ{I}E2m [Z[JE~pVZ@j^;r:*–A*cH.7yx}'ڽ-n1 tr;f(.{~Ĩ}ӹOGd=*>K4XDoB, `fu=B #XsF)*gYa#J* 3%8-49o|g+daVd1}4"=B\R3LCZ͐Jgh\\(ވªJgT_-lzeg,)lc[}`XVЫ|k^G+I5|pͿǓƔI2攐S)nNCE'ՕF5J8}}u F <=ߝ$b=iϗ>2[mZl~ wY(~>+[>q UakVgQ!}UCH|a e.AiiM4!xHK q0gRv\CnоI@_QӵhX^:i۽vȖu2Ri/?WEM цƺ R#f#k 0K+ zȭ}$ ԚhHfcp`;bU!^i:,y<"pk`1PWvхqh”aBz+E %'=B|ƒ̏Y]ls+:O_h)G'iЃwNGw2P; ,RUڡ{'˳NՒnU};YC)ԙrdm@E#w%ןGW<˟6Ohݸ`n[Knl8b{$UXsy'٬lM[L8Uw>LYP0) 4{d#WhR\@iaނZl2_X'2h:8UG|/S??;)(7*.2u~ElG_ʫreUS%Nm^!n {GM^DbcqD5@4VoAKU`d^(<u҇ۼpuI]f&DŰ&!*B'EDsĜ?$-ރhu+y0V8R7y8t1.+/acު9mllnPS W]C{8u2;1\&a>qMxyf4ye7c-V2C;tݖ ˟Sg 0 p”efipr5-Ko@)1LXz_ܣԥ>ǧD,gUyn ύ3羦Zu#yBpwVt ROwi?]@:0Xt8BBˀ|I)Z;LR|D[<(og];Еnj()Y;YJgi^+ Q "Qc>ߜT>BV1@]cJMV8wz'95@a"v,&{ߤp[YzԶK7r7Y u*e7:H?ͻBѫR]0 7asu0#< x)uܫ4RRԜ1A'R;~uޟ8bkq}Z{13@Ů% ;d/6='W<ǽMY6@''MX6_T> hGa\~nISgƮoL>a&VsIx04N(̧~CܟLWAB5 *uVTHHN+*6 T^HZܣ `KF΋;] ?%>$k\e/2}Z笉5~Gv #7 4IuN37LCScڒ t=ܚk4Ӗo;yAYh|.htٲs-wyv|b MՃ'[4h,pq~DTBBBu~@g2R=k,KL5 /~j#W?T (V w$S1$0a]W (0b[c\^pK.(d5 %5xs,!*?42\QI+*]t؉FjKGOCy\SfYb_we|K#ܟ|LHB#)E8\XEtԓ6`X\oNjI-# G "g MGъ*!6 {~YZvz0mTOn,{~w3>tHߵF~2խٲFssrSS `Va.lԴi5)?0~`AĢUmutOTvgr])ډw."ݛvWzfPCϴ5Z8h+Zcauhu_0![-`!rwyLuKL BQzB-5%HD 3pIwfYL 8( aa4ڊ-)+6~1^]U\:qJ-]Ԃ lxSg0پ!f5{fjkgRP>X!dŜsw $»E\ӵV N-~Req{ s(Fq*7Wqxc dM-1>6G'b v|r(}qnMd;w=yAx-8wm\7aKI截8ru}~@˳ab)sR]H~3nWP`T7 6_V鯴IWJ6fc?1&p.fKY;is{eY@#`BSʭO3 Uִ7A,%F^eaG+"hQ [ڠ^vM^\;m5G΂?^ʹb >-K2#=G[q !U=)Gkn)CŬK?ޏ(4h!_ ,?/ kjTBqh#3hкlƍ!NgaaģbY'9:x'3W𪥝XmJga:67ƛ"C=kЏ:pƲ;B2*ɗT@[ K >-NQL/h#"j#׎(r0xu s>Rߺ o JzgSQB x A[b)o,a9 me _5qbyj_l79/̰Vvwlk+P]̼ n D$7rltI*"V^y p;*ubMQIbn"W\]F!%Ȥ2 sf*?:?8\ȷ3d~*mb}uN}cTaƨ.@/<0h! ~? zլŤ :<@I$FE>x%;UI+QfVrpz]~iX[vEdkҹ َAçU #9 Vɇ %_Y~N){;Y9w`ť/**xt2%Ui (yT$5#ao&XXkja&ЋC=Uh n~gǗL{ x58{<-)dXBA'y{LVvcF+n*_5 B.b; F_|YPӓR8QFG Q*iT H!ᘨz^.vr.9X>xu[8K ; Ը_SbeH̩ԙ?AQpu`sZ(^ Z|t* Mw͗ٮwaomgP%T7MT(m6F,B'e6S讚=iu,ۿBg᠔'7sΆYlP`VӜR/#r Z&y$%ݎѕ&*&DQ&ɸP[MGg"{3vQH V,ƥخ4Ēi^U:l#h` -@#P?luՊ =% ZvߙCҳTzAB<&SN,9Pi}%pmzpe, 3&T:ƣ "2' tkTt=9yrbWyiv\NPx&]9?cR1T }: ěO4?7h/vaؘsH`?Yz/Z{DJ-Q9]?UUJo騌9PyʯH[jwuec[WqɎb|UER&zg:zquPs.ϵ pd.+9dx#ƍxn.癧tK/(: 蓾^ 1UNшԍ9$C.>B}-ܽirYf24DN A^\kgHsĩ^Uv'C3AyH"]Hn ֋zurcDDw|,*: S +FP'X}.ם}B sXq;UTaW U71XeŜQvmM a(OJ͈̖OOwߣyˑƪ2qAa0%21W† @8(~8lw"ڻ|CUÀq?|~݉=/F&-ny^s Ӽ)y-'Q.&:\>SFZ,^] M9?w Y:t˻MWVbdnGXcD8#eu}qИ(8fέ+}_(1PP#{ -=ՄM.;]#v?-L8<'VN>X=<"(*F]é>*QE%+N8o)6StRc%ty.R+ 1f)2l>8Lͽff&|\s9lꠙ9fA³_&fg;͓iS_"0e}]!BJpĽr;m/O'ƔU-e^QӌsD$p| Ԥ&@p7&CBgz!o?_?l?& 7Z\KL·@$};r/s~[&ʕd֪0YDǬrÝ= PIfkЅ#?*#/+ H{foxGRA>SET7,<$8pl*s"R@k^S2]=Cvf'HaIj^~ddDD ߻/ Bbӡ`?ˌf[ )zøY: K1.>;sy9;^r> stream xڬctem&vv*ضm۶m;ضmfŬW|Ϗ=ƺ'ksMJ$D#`lgh"jgL@K 1tqR㐦Q41s 98[ 8pL&FFF )@@FAEELdaf jbmgocbQln06kHȊdUb&&yCk # `Ҝhb 8 N&FL܍LQQMm,>,f{l5v1'rS%dh/3oTyalnOl'j_Kc;#J/_X&c '{k;Z+ ' [̀hbfhlm/?:KڔoL#翱,la [S;.s5qWIZ{MLad߱LG-FBX[%c` gҀ_LLo[lRCOKo9o%W56q5 a/:es #+H`VO'$".MY2;s?0v/Vv #;7!FfM1YnzU?~y/0"FviF.I[5&&&F0+vF\iu#SZ} #!E5v~i!M3_gGc}?{SL|) :٨tKբw4YUuK> g:)] H|RлP O~ ނRAr`&%9{;>4}9U-g 'y⾯<2_2} I]2%RN*KwHhL\㈵=nZK#.bBV%Z e,Jώ3\G*‹_?^_CT6X}.O3cJpMϯaJyX˷ύՄ!X1mY0ɗۍ\&uu@,eD-Kz}ګݓ&ȧ?gIdʣqDCL 7V6ϗ9YaɰvZ+D{7C0%7u? ?t͌Oʧ2i;\"9GgFo}*YԌ2mxɏ3\ބzQItk"#?vu\˭F'>&X vkJԘ/ֶoLߜuH7/23WKFUVh-wuuW~R3&U3&To(fA - qwREzruGcx,gp<# # \T@d6V W1Γ V{ GW*|xlgn-qaoI{PdDԟ/b[ <.s*}v$|v_$N!ї+NQAc;awj@ fvz-1%T'Ut6}g/[U#6'K^-d@;A#;z PGB U.bcr/J,*˝,;jF6V͎O77fi` >'&t3 PK<9l(:*4u6,AHQ!+^.>bÙ ?'OA5 1X;}4"Ù R>"ٻtMF-w'zĽ0xݔGD*ܜG 5X)گuthh%R\rxYŜMM MOLa}vL'A#.nz,lr[ΧbTxG@7䉷SŔK#A]x'+!mߢ6ShPx=@yWٺ8x&_idSn#Ԭ+5%VሢW;4fcU[7{FTc g8Gַ=4 xwޅd?+,7Y>m%&/! =|WKY9?A>UHyתċQ L:t{ B g6S硄昦Q>ې;&L+OrU@mXbg[q7OkG-}nTB+se gnkz?sBN+`Ԩ~VM^Sw2ՉJ9e!RU?S7\n\:*S k.^]:,>_0nVGYAB5ߝ7W'#xZh kD2m*S${LIPfa=,E_.fty7Ku@)1geA![mO~"40K&i*S;2~ϱc,?3DV 2e JU3*+gE|v UXdFT88Z9(vؚ_XqvS@Me;lkg;j$N6>鵟Cbƣy%ձ_AK:kPm3s*?~Z͙/3cx2?xpvs|7,gjP"ӺqO8OYLw!2E6HO[~.{-h >9&ޘ{){iC;k̤*\o֓|j!qAK||xN]Mо{JQ}`ivrI|zq .'emy8M@6l,-u)9F"%h)?%D=v270T[UDE#ms |SR3'_(6:vk,$uZ/Q3RDŽb21+5qhJ-#ed2;,Sg 'p˃/Pw/EFb}tGhQ >2z8OdK$Ū+=]MS}m0>BZ#Ż(O$j;65xa IJG'_jVdx7,j-&?4OPmm ,9޼,g>)2="U?YK03u=p p) *HUzb;Sz&~ݬ. ayx!B}̂O#K>,"«aKx횠%˵vP.x޷:ˊ01Zh1*b'8jބEe½Ó>Z59!+wQer.rs.[+dqpDח"?LQߥ:CXJR"OqdrD3%)pmceQhOjO֟bdBԊfmH!ye\o1%Gu1 C!R햺S eH9 v˼:NQ2`ډ[+YOn釉ITcQFчL< ܚߘn]^zjBod'/1ݤ\U0FI޾-c:\E;lâ${=}m{/Ẉ#wYIM2a(\.l? KC$^}1N!|1<̼>Ix]P`|Ty0YE,Dj'5s:6P|mt=OGg:嫳/t/?z~ܷL9NGQ/hˢG^HZ [2sȋxĆr2̺s㹩eUphĦauJjU^hs? 55p2 0L}a]!pSm1c}{[!@`06 i.Jr mtB1a,K. 3|F{[K^YZN~'.SsKশB_n$x)C0,~|0y(vI qV@Xx!F1{LhP{?|ӷ:8N:w~H,s>p[_+|;1z5Ulu'VTuƟ-?YvJ{`$KYI*)=/ƺ8(%@FuGg5<5O^[XimC9Ɇ% &MA3s9}S R᠕w9HфD0SF![;14(~< IXiG\ͱQuCpY!lvY #:?讔sJٹ:iѤXj%EmD}VkSW;yӳ431VZx]yw9\cÂ?MdDž#ŗo WdN< YxRi{4>Aʟi`I7fJkJjP%}$30QW@ xXgسDF'O۪6O9^T;p{1 bPcCӢ-Qi& HI[2$I~f{#@"$^;?F>@z+Oðni&,\.Ire- h|Ȕ NÕr.Sus ̻9Y„e8KF2I'1~V|9-;L\Q$?{)A { 2v՟8'6/xƣǩͻE.b}RW5!Umﮃ[$Hj>=@7x1dL.翌ƶj|O Mj5ߛ識-a VuHSF&+]k-Y| 錵V>Z:; nf rO܃>i$EcAq?EהexόW1& \[0| 0Fu$AҤ$Q5ñ2kYcCE D4+ch'5 /.WHA!~N䞶‖!^aMHe(`J W Gk`)e1^KFH=^F,*ilսfw)ߖeD"LmFEr;gM7Q/,Y -; >^3\tAsu /{GiiۏeiĂXj-AxM^j_ )^rriםQJKrT .G} :iei|C-hݲdL< oZE2<ZC.?uw4X5i@} uؼuFb7ءơ7XEDX^dec7R76 jAv)-!"A?1Jf˺e`*1TTM: -B> dJn\{:&э/f_5Mud((!EFIl<& XB R;-Ieیc -d}؈yLQ#*'9j$Z4{r 6nlw.^WVEr@r7#R:Us|/$k#Ɯ2 iimX*߳<_! ";03H[ `d#ߐaD&kn;ha)N"4JX+r*1׻g$iL27Z*ZV93@ J1ڂJX1$w@1٭Z!x"Sz L/aT{)6w`g/v29!`ק LC q]^D*vx~t&D\A|缆ͰJ^{WYϫ{ JP 0z&y6ڮ' Y3&y=w^,~)έ݃ q;ş@*ʟ_<=n(7ݒӽfG=>h4=v'^Jsaq :*ͷ>c,m ~"*zG^񌚿dQorL܊B#5o>;"Bk{hpmeT@};wl3Or|\_[l(Q|'Php/k;/w%wE'1Ų4S]Fϣ9Ys6/^6hNeu)ad!3%jt)|\Λb$Z~vk%T M? Y+kk;D2s2 xb:ßEU!ZĘ bo7P<^n|MC&]gc÷ Rl_e}(C*m swC,ю\]X3hgSHŀa0Wdb74Z5+ڥ#ցj66tC^oer(UfJ¸j6bI8[-~>6SDWjRnZN|gw^VSgw Rx/x_XXbõ27m|B CZm^t8M4= ޒ㸀?lQEZ G Q 3lX-(ڡUqY "̖a\ $?)LPP&nvǻXA DWGDVq.՟*Yc *qDl/*qjF Ħb)ua"OV(dyJ/3|_,[iPU |D<$KŜDxMu`HX[aT{~VH9|yA*! 78{풢۲MhʃLh7M8f,* #N-IptXĜVmQWx8mqRZjӸPU\u^`sv}Z[2v؂qȺR*jo-𕧳V<降 /&e_ۣ^+G=S{<]~"?xC>Ĺr3 hr* 5o,7SDVB;B΄z }65~՜pjg>X٧lu)$'3K(@v$0LƠ*dۯtWMPf8MN/֥>k]!MX#3*#Ht%M!H>HTzkɿb-P?wչzψPZI{𳂬ñC۶|RXZ2xm VW.ӅugV$zx"N:G.])Ul8?(mrl'" xAI,iwQO#ušBhظ{T%F}{"A#G!qruԸp!\uudftQ~F?YGRFc|~xC>a1ްًE&MS-M4@K3?w2D pgaLW ogfUG~M\".}cËx..J-Lk &):?jbS(*jc`>s'q tAb\tɃ[ eua)@Þ?Ck]X0A5Fn 1. (W dS" bULK >Ճ{53ٲ JY<2uۊZ0՝wQL BOϰv>6" ⍐ ?QI\E5 ?ׯF|;֞ߺ7GUY/4y(~:lGs1b6OQ{46_ᥑ:Zf /\ks53_Foj;S"IJ ف>/yqnVW^ ͽ3q[FJ}!9]'⠾ z!GX'J;54怴>8v^Hq} 7^>έ=Ѳ4Y_LR:Tv=w8Y^t?vc sZJRץ8c 7ZB2{jAЂڔ٫kJS5 vZ<7k\$: vC{(e~C<)L螪^#L[.e+#Uߜ#4mҽP%D@psi7+3ǯG[)XO. ~ˏk?DfC80BZ:0 3si@ަɿ{̿83q7nlР~H-; dR܆cg @[Ә]W@8қv? p=#\cӾCۢbI_%wb7=l6;qS .$/q""\{UҹP-9%krj1Kʉ aOq s>R|ĸQG e5=+ $DzC=ẽ"K`1-g1Cĺi@_0 H )?5?W;-y2QU9´ڈ=\bLEwϰfoq5iIoXJGx+ފS2@g&{AWg;* C *݊t>E.h͘(*F5|f`v_FxU5o!xFB<:|Tyfl?>RBthC::BbzUAB(XGwu[Qc" ē? I*#j~f^-~~ G0ːWOs؀aLPc8$Z^/UK"Y;=Ix/[ۘ)u|.ʤ?Fu c*VDxCvPYnn\=}7酡Lz yOK%xGW'rkLY_ǵM5=H1FM`^ IKC>/aK+ ?6ua\" Τ;s {L]~̨PG/eT3|R)M!3ˢ$B(Ea ퟭN;޵&^2#}\b&4r#/zg:FP{hCv!,g+cEg]vyLJo9*_p_Ec]|AfcRC0bZ\<[_D1j-[a1 CW60ЂհfAk*5I0W"_(T$XLgQ̈IX©iKe6d ̕}Ò$c*T#uwΜN BGpd~M͒u}8~C~ΉQN=R~ڍ>&~0W 8[]olCEaξr-7ttX;%2O,ۭLdՍUZ7k $2-ACӁwgiq"|~7(sba6xG-\.}]y&gReFT<0t™3΍~dn<щ d؈Kya떿R󂁡ҠQTX2+>mE`j4@StPXh;m$]9'!~™hzr.WMt$܄唳2,z\a$ʛ@>fY6ZϴI"vL1h"!rd^|ͭ`mj|#pPj/e.qڏS>THÌMJi\ۿ(}%;o^XcW+'}Z|ꁹ(ӃIc3WVJQ@BUP||wP0`Hb-M`\I1#t wY }짣[hVMℐT49`!`peeP4 /&5rpbEFW*KL & 6eNMt}OH8Q)13+I#VO(]!ЙZJab3*Dgy%ͅNZ([dux8wUԾo3/s@v,_"K=l1ǿ#YPNP5op1JX=)CGҡM; XE3.(iE G #׌ (&x,5a~*5G ]~7󂽕PZKhNIW u hG4PQ(op8e $8)_22/!),=V*&sK$ޡKrh^k^q1vLR=eO+]bx+/˾ 񁿖4P@ϵN03L( bl̐F>㄄WY{><zXk0}gOx5HsUbc _.h@o205{kkf;# gN(j"a6--R09 }(ŠIeɆ(ɽ'f˩o~Si2d dp-ff YzZcӲ1NK'[acH5|9̌"k Yst?K-+юS/6|JDi&331Ljsϰ%[`=VU>sOQvh9V܍}P4 f+qgNz+dMz!%*Z=Aw3O e׫_^2Ѵ y~: lt >D@W5IvS8cL r&&ƫ Epim,yCoPɳLUpV~>L { {OH -yʍRPE  {{nXQT"3/`luY.Pt?,PIudҹ'Od8SNZJ s ׀ :|L?ꚋsp Ъ׆!;>W&m \%0HMw¬KHF'-j*-x&t :vNC<'X΂QO'4hYzʺ~!Mr3Lr6!>R VsQp,YPc&ɶx~;|J %zfa$bGpxP4 S (W+_)oP}XL_Cb@E2W^r2]d5\ rkG 2,!)`"㣏‘@\v|:1Ĵ??b3fBi/ox#盉Ydqݬk~K^Sb>ȥj%[zS.p*.ĕm=F #H;غGQz gDBcHqvsB|"u/om< a`w Qg-gk5ho/֦*uQWq(T: Rh7\7J7vW?\IJu ΢rj!FYD4wxܿqMH#\+o,'Ď,KN?oXdG2Z 4Ce0%Q3t8kc5lշx/7ҮHKmUeUD,$1¸bn(OIhcf2:Z?6H>HKOCXaa}l'K['0aLEvƅ7E5}0xGtSGM8&6[t~v+(Yb~ DN]Y1~_ Je"禞ٌ IZLsxeňG?ds֦opp-Φ4~çv 2*  -g6m1Ur6cQC_FgG2v&n,ۀ~a8W>cZLrzZjbذ +<_ 2Y%Q Uh1b30OLcf粹B Cr6jmZy|i2; .y>gC*-=ZAH8ۤuD{%>}Npsx^L?èwgRx"ԯ C c55OJ` 9~E6S_\gJM&`4]gmTHV݇4WS'$6"KZiE[Ӗ8Is]W2`G 1i>+KdT(-GVw!)zCL6*|}VIOB;pO4ϨF٘N۸TFA )uy{'}reH^Tm<w&97cxbb| v;'b\o<[6 &$v֞>rT/}/Ei!.|Mũ)@=إhCHr#y2a:foTERE,n@J|v L}s޺xe6r-l݇,WfFnzί6]ɽv@;hTlH1Ҏ_D:K &a7fjlʏ(BFU~L{^1…X񒄲5)7ˣEOb?ii{ٝg77B~+f]Ɏa1az,]M}j C^Gu!;VߪiIpI>g@,X=,,bJ@lL|AT{y.*C tckhu_P> qU}ƒa&|Â?\ЌqI])Qsb0G7@1C[Ny%$pXL܉-DnS euc\m zO`da yuw^ڀҧ [C1Ғ@/]bwƔv.z)^6[V4 Q(M$Tgb\eet[kck~_Wd+˴U|3)@{\F72w!&lWIT &eX q=kmT٫cgn o )d=z58V-bf5CZ|+!00*9 G4M*g=1ino !8CH:Rkvd 픰.`~|>g6a@T>G;PLi%2s?edF,cD11A;Uϫzn 2a9?D$\ES;d;0'CTDƧY2Ί҇gs]E^&|誎0<$ Kj-Bp8 f $|NZ}g}< t!ˆ/` 2W9B%ot`I׏)ceܫu|}#baV}N %z> i@mPdv;qM%>hNN~&]ޝCkE0rvP1&֢QSDS/;8OD' ~oɻx>W6Rޮ2"fL8mP <&eif4IJSw+,Il$V$Wu?D%,;2 ԍY<ë e%B4vLh.#|_,>1|3u{Q.SV(Ayӆ?J"  35r UX޼6'By Žm?XyZXh晋E+*4Y܀ɋcb7{<<~akóZ IvO")Nyqxj+X(EFhnl1G(z@E&¨H1g)$d Ƥ`%HAHcf-$GǶzm(~UYUf˘`r`ޅ>o qzAXub,E4H"FJbH['ep-'m.-gn NYIyQ.88A+<zeu tԇs\&t+-N-ZNGF%;?My@5M ‰!L,8“>&_8O_߶8nіAn+:)8و⶝Mg!g? 1 U^U" uV08a#ހg rqbT6.2"& v k%T(։YwLUC ޹Pt7=&L3Z k!AjX[VaŸahxZ?JhXHTLM0N͇^2||+nC2rȡfhv2GZܙ\vC*xVr'tg$*;e"7/j ru[Tk~0z11~V=V\´ <ұ`tyc`8" U!lrhd>nfr{6 dça o*=9<-!Yd_z.,MKH9QT~OJ^hj#zK> stream xڭueXݲ%NMpwwww%w.kpw dw;ϙ?3WkR3Z8L,|%# nDwA` @hqG'/5@MKO_Wf^{T܁vN@;:[ ; @\YEWVI@# :]L*nfv s X:u;:X% 0:An@Os_t\V. s;7 -I;N v5w9QU$'7+8Zߴp4w[?;; 69@OXf@=; 4\AVhebatu}y۝Tod?3hgɄ wVd,,[9tA4g= S G;/Y@2 "SK)ڿv }ɘ: @wؙo> ;׿+ ,-V02q J<* 5o5,.v ໾o5^Żd) +O/YFua3fX5O[? =>\<F6/!?DuV4<,L,,YOh$-:}6wsqyu^y@'qiќ?&-3\;0&z ĩ^ ڱsZ&o VN/rt{C?p쨻SgD~=kT{F%ӏ}g6`XTՌ=O|8 w/sB7O@k)}LtxGsxpg>'odM+;k\Vv5z7y7RMLSv7Qy8yPXD!I 9ڎyE:!4EX~CԼty+L -tU](InZaJI!(-v.*cA4c G䍳M(qZGTZXM,pZcl'wJ'0t5Rh\kF]igM&zm}Е:(GUw2kA?`0M,%;k;8pw΁M.213e&Cn֘يHZ߮oY)igYy|^g ռV(*J_w̹*lN`>_!qu8է;Ne[Wk@bj u6y{jخ)d:(}黫-+t?+dKTqڣ -5uBs rb-PaP4I^i?T}„dAZlAY)-ô|?KTf̫z=p`w5vplEz]ŭX #mK:UB+)\I]m.*ҊdH33a)gtu<`X0hut.&^#_{Kl-= J/]dex*ڙPLK]oytq ċןKQoRߖyh$yOVle9rW$Uirs\<=yHg6Cpef]YW 5aC0O>UIid ߩ(*B!TNB>d%JL(dvt XaMH0Hîd/\[m$o[OB(~Ni I 7SߙBʤ~KB'XZ #B%7q9 LIG֧>OyV+,F$ F)taJ($ +50f2 j4݌'a1TaʌQWT>K}7M>'y՘Mp^>$#Jc ;YU'@Ox8呹Ja&; NL 97YBhT NfcrD^prn#*dv٨l%p9%t9^d>QѸPd1TǾ71{>4hu'n%u4UĢiƖNݻ<iҫ21{N-43um"*>)!6 \+4fv%0}Y Mk4vnm͐M;klޞjMpY,c\&6KiQżBؓ㲄w3$ T3\9;sCe _6cQ2#emJߏ/d%ث%ϭƇAP6.(?2¸k9U l4V>T?P=ܷwH*a}KZף!CT]am8daU@+0씧 6邳݅=TLafg!f3_V?9/TĖ䠤J3trkj҅`W.|Í&66^&raߦ~~S֩7{b]\zC ںr{HO!\N1. &h?$Z&(2~9sMmT>& HhyP@+aOu{^1m Hя=QR)nH2di9^bVstmDOFR 0m^VQa 3{aD_gHT9S ~t~LQո1,iY f%`YSXmxEFUj7wa"|^ol<3(FڅI0sdEd RYߪj s:uhO?&#%$45:oK  ikKM$: *߯m/8 G_0Pъ}"z2Hud?9#rEYKbէRдrPO4oS6@0zb*3fZ'Zjp&ڻ<~JP#0ȯE&fUN`.JOB*vr_qHͬE(!z<WǗ?Rb@B\96)~="& 3鷌- KzN*|V*Qk8qLb~+_O*0N㖡cDj߬ᘘ5çWa9/hqt@"?$_ cnPi ä8~`"hTH;o p8,b6IC&dїMFən'ÆdVby4vԶ*\L/dhU~jhjCHq)TS~{,h~4"4g1 eҪ]# J%3AwYeQڤn;h(4yMj5"&YZ!݆ tbwťPc+/K=7]WD5`,Tq-b&` [Dtա?Z@XY_<ڷ-c:-QwvR<f'caqE u }EsD%D+#\^lzXwۥ ^uݳA\$p O ٚk6Z6]a⠺R(AHCr[gt;q? jl$WT%67"D $(*[5=v6NQUh/"[͋WdW<{#oƼ臮aa6M?q]VO f=HMM7M)Ei]7EakVً# #w7{;Bl hqC2RauڢZ#\o紼sf\X9E~N&3%3g)}gK*AkIhn^x{C8&_+53d3ɮ)=w#euF)Mz?(x S~3"|^_&G=]Nyu]3Yߤ۾CYVlmT(FJ㴘x*6sGz(.ϴh*FMQt%q<Ʃ([t@S4I[⏐V(1Yԉ<i=Oj$:K|$#%s5A v߀A4{BׯAZm;IYE! ԶYyOMr,<=+<`|R索 b?FhQ̌S"Ney:[KvS kc+Y<2hkcgP1p n>) QfLT!\+ H%.\p7^jWH}OY}y:ZV 4Ӱ=nty@uEB| H066|n)j0y$D<ܠ٬q UfY%㵽:^b;),;`fOJ$-ŧ 1yH]C1 zw .:=4᳃6hE$Y:lhaV'4e1jLzdN<ėy *D{HdFC*c~{܃<&jCiפ*IяYvB,z)#04 ,Eל^5[Q̒p]Wfgbw%8ǹNE__^TxV$DKU&MH+|"]A^.!U%G˺&5<헚ё\<TD"8,C9W*mĞ R䲰"}8Qr"Av8cttf~Z9>VD$AĺsvMIIєX;xe%%MHmLs˭w( [ ϢD3*i6YM=[A YeZ]v"vr2d`6ysq&vEGy9kCGD0UplrI!/v#Q@:u{436d,/ +!u1Z&_Zat'HYh?}ݽuPi%JP{GNL2I͝_/']-M{99Tꉌƍn!r$& rA+JG})פeGiZ;_r}nR?7s|^tl(#HT\ 6&N s0Z= -p+fFc7[<ٹr^uyzkHOBU,>ii@pǕA{o8"ٕ̩AmOTYI rFdfQ3W;͚X9%Aڡu:yehs߀sH9|m.KcDQc+GAjͥ'DDj*/^#]CoYw^K0ݿo+-j *c ;pMiRP6)`ĂrɞBYBtـu|_Y'"׎g:lSqD}-8$@@İ}i AbCF$,Zڑ*gT$(+B5¥&1ӌjhWt:"H?]9r-FP}ƸCY#;rˣUy.噇tꆂ^;53"blϳغd5kNH\su?rB%C$w3.٦JY5]z~VRy;>it*}ؗAr/ai! ȣX4垿!t%#u3*3R@$O,#G*V*p?<z` pNBJ4u?yrɄ2'^h*/+X(څCOHbH#,2S )V([ΟkAWB}ߞ 3!WMQeDDVk@cmht~%qLha $8ٳyLZKp$ Αf4/SCȯٷCZ7 蔐ŮmO8ˋP`E&^:p#,//8BH_ITJ5~k\S|pgٝ֬FA#.WI̥#crУѮ 7!g9D] .gXeoK__Jקv T7~( h(JRTk~>j&f jD@fig+rG]$`GjV(Z*17kxw ._>caiq&'4'RBQC!~tmg⽀)Fw|C}i_Tr¬/ԉ'dr.eBLmtl-!Z 0[@JcAGwf0dW;S|qטpІ} ʙS`_ aJ$7A?CZ]49NlRoj9yٰeĿr$vU"\k4#+Ju|2iihRC8Қ5dV@RC%.qML5W&ؼ|Z@ ϝ96' BH7}E&v@ceKhJon]AT84B7ӋyZ5uy|~͑ό:UoS _a24*bp W(9G*Pe. -vQLbe'~69ݸ>,z8b Y ȌO+zOq')EMuJ[O{,vMMT4TAb(h1 Q#-6~D9' gĽrH -An<1D醒n (~=U p@-/٤kiFʪ({ַ ONPPHl`|G^&*Xk2 1i#{WZ2_|u243߁٫|"L? zhYV"r9kBήʲAY먬ȵ "})EVO社| =&iؒ([КDž{D{|mo+g1QA"sW;/AgsĬӧ2aѴW6ᖈ.h*&}.y IqD,Φ55mjx?QB??izzgte+>W$dU!SȐ v I8 {$h羈;A;~9vkfJw@pplcI\Rba}dJ)ud;lc^Cy.?cF3_ZR[ᣄ8) w~֚!d,n J4`]}|Q3}9"0+wexWYn+Xmˤ]&.M;AxvrQu*Yq^y rsZtYwCsI#3$;}O3ׯL y0B,6ŀ{e)K0F3c_&}'e]#l׉ \ "}v>R_cMGMj_ކ#.y>}Bs6e$kԳti־+= JDSW&i 6O_h#=}5. n9iz`5k(Ȩ0q30b٬@ :n,UyVq_ߓWˡ|z]΀c~PwgMp! öV|y;/)?%f Sb ϼPs(/2i7Y{)O.GpmL8cܖ}Sl85ENs;3 ~ֲ;(:9\j#90oYuv7C8+p2+L{@wQ]8%ihh@*?]-{BSvU~qg?o(hPJԍ6Ln UW2?[ʸ:mv'޺n@hZe܎%ڧh's3"ϔӎ ~. OPxRޤK7Ez٧ƚ >gEtEX՘m6h0$!LfB6ܟHm+w ];K**qQwD-=OO?)4[h]w?T[Q]QLrWq(yOGFvag<q"'wi!sP2_;-A͌kFu'qarңXMXZ0*s{d4$[&/q8U NLvDw#<0.iZ2-ބ ӹ2xVOu*s4[6Q#NԮOoYtC)~ EU evI^l t|&g=2E}БBÃj*y :q^-TwipWu-QsT;~J $/ K-^,m.˭se!W,;'^[>߳R6S)5 jv"*"9iA澿mh9wշn0/]<]h>Q3rpNi 0M`3# w9?֩ endstream endobj 1446 0 obj << /Length1 1647 /Length2 15022 /Length3 0 /Length 15862 /Filter /FlateDecode >> stream xڭc$\%\ʲe۶m۶eu6lm}ܹ7g\ybG8;N$#RP472scgY:+s)J1V22a'SCK{;CS. @ ldinTURO?.#@#-?LmlM\)MM.3KS8R\N njg݄1@ٔ `f`logbOk\Cw?-7`dh}.K;cW 'ooLUADuX؛}{ҿoobO.#Swo2'ligL LlLito`hy,]Mma~|4vmniϼHڙm7qu_DP}ahbog 015awN SO[oM_s31| eccgXB m-mN1%G$`9b+O?S} ƨv;W?uD@FgZ#` x>.MN4!_)Q}'+;7j+Iqpˏʎ)TUFF{ a^@8^{OX-Iq5~"#^jFFCJ %sƹǭaE :~&򣐫b?Zb^PLw aMtoC(E["D6D$3MWs'!je3Ӻ| ՟^~SJh]ysz>7 O-L"FwG[Xe9kl3Ul rxޒNccw: ޢ32|­|F s*aP2x&Բ~#m V8#hE-X,0ޓ/qK"|\X~Frg!<Fh𼠰Q9եė+_ Jt\}w)Xp-YޏPM0.@|\U [U~97 G!%XԠ0v1Ϡ77R3QjEC&^e!&Rg  oc0; zW\z NzCͥJ^ٍ qڶy`4=Kqڅ_X7ϒ%+(;ٸmG,0ސ'n1Y0#0\8.IML@ #OKO lc;6l<}WV%TDZ@%xN$J9al:?,\z^ 钯Y#jrfO?]Grtd4")exVQ)KAܔ(#4 Sh׃eS \IlB?@ 2AXS:=x/fYFLL+. & X!zi+r(qu?_ܬpϒK']^ݚ>0J L"ޫ`NQ9bG_JM͘3ili@juhRE"W=EDs2QȤ`bC1fqחtpN7Ԡ^7Z09ԡLStЕwx}'<;t"[aY@=8ǗGNyAaЯhegWlZ"˘]W6S /1C˫.4,}~V-;J/gݫK7EHf> t+/V%'Vt JB;*Tܧ j!ʄ߈ 3k._=$$=뵬">%dS{Fizdipj M?)b8prP S7c!k׳e߂K LҊ42= 03AKIF/:y4 h2ݗ(R 2%1IݡﬡKTےƾ-.*.1DF4SLwf3FS~VoF5Mszrf&I~kΌDgo~=ܿ%ތׂ=aBLBxABȉmWj*Ȼ#L8/ eQ xY@:f{>QHdf_,ѣ;|FiAf&-Lu%~'@Tmgљ@?v%}\JdJs' 9{pBS^U3/#Dۗ~MWl# _#(HU˻Z(~=״β{JjeBuciI+Td"<yxV:c yr|TB9-"U.ߙDFn=.o*{@{C"sAR|H#9~,ƾml4t3OhZE+ye8fr!z5B8r'}bGs1py댝8eCUŰ9+%fAJbc j3N?A0*O(P~=Tsܨi;@顩<ǠVxښuff4E.ÿJ+ay+Yi'&BU6"n9׿Wڻ\0hBB!7Kb9|E05vF \Q8 M7MgW50* VN)?0Yn1tBA(q4ZӐ:V$s`$wAW*\,zŠ,-U2[ HEABD3(4nz'jd_ʼ[/iY5j=<"ʰɄkpi}r=h]g;+06j:#6$VVk(UK N/ %L7ƪJ Spb0=!4j ^r<[ÓuHSu>|SrZm.hJD6cuIW? YəIa.Iफ)B@N.:?51Jw-Z^c-diQSnԈlfV1װi}eڅ_f[P'2M&Ҫ¹FAY@*x!*J{0x5G宲]$0֠@ǮP@38qX6S( FZZsn$+$T`_A;dkk68!!-qyuA&BN4^L$ [{J{ivЅwx>~RviDHcKj"6D%PeP 4;5Uauφ1"6XhJb(Nv6~-L|bDW[bJtF\/%<&\_f}1 8ަ k'dk:gLL\ֿR6$̕U.% ў0I& XxKwl4/n C.|c}~s\q~\6(=tRtoD2Q)tv^CFH8ruAJM#*[ 4WM/89fOR-Z"1#'+u [O,NpF n:~+4plhp:N2ؐՇ)um)ZD_h4T.UhY]ٵ GېH׸.<[ =LcyZU[ 'i8/c6 w``YW j!-ƭC{ܩ>; }J?LJc-49#:z44:zA[q = K˄_(&(. Rt j\Ɠ&0OUkVrOOtc^e b 90Ovxeelub|ɖHOf̸m`y/3$naSViQG+L+>#^~@l U0 b̝EVb- 7ڶ&7L\w.ք`z#Ǹ*:[ A◨(n6vC EZϻQƬ$ v1?jҨ^HaX! ,uyR_{吐.ɲO)%1.Ah_*Զmd/zs`tQ[277TNN)r[}`\ Z2AIR( G4>ޘ*yi$)CtKت0{*mSfCޅXU4 ^B$\#ӆA/PKFͱ#:c);En Ր\y*ףk#0p'1Clr]ɮ(ϻ#'N"o$8KAe佦o# ݑޙXq&sw?ِlG{ dzXYl[G@kyVҽ5oVZ"ažH'XwxUcׇ KAg/Wk&L/` ~$vK;P~HeTu 7S|Vb;,_@šdP}{B v x1~Pzډt!6H}$%wV"\w '9}8d! _(Oxt=e4^c-,hAk8@[[ os!b ~BIĕ+sqBDR2>4{"띋` ۪Xf΀W ePZakVpd}ؽI{'e.L-M@J8Gh 4}AYNG 6[YbkRqgt\-- IȘSq@(^CYcNʰ1K0@RU>|ʼK⁖,)Vk1I \M"tONjqWA@]t-79P[v%/a+?O ;R;/cJxgقCrƄhi6t`4:S-9C@ݬs@Hf¯6)Ag?F,cqrdSiz Nُ㬓4؝w 7¯;cœJ2A g~ n@S?# z6e]9ß+7pD^aBj0]86鍲ڻLϐUw7f$#1sB|IU}֮~A2`N1_D ZGBUȵCM*4']A+(ҳ` ܚym Nuy\$]3 ,m"(>JgOwWFtVm(- _!3$VC7W/EwZҰ@#w UVm0geh;AQr)Ѕxlɡ/›MmC ;G/f /_5 L(;`2{ƘWg;!:Bm uQ7 )]ZQp_IH6ޞinkI2͜UWp0O}K!FžH j fe0\"Pݮq ?ڑ)B,o:xҵŠ:|9GiK UX.b/ɋ؝_&g^%xoaTpvQ!xdwIM= dk wEۉQSX:x ̟h2 [F!7 V':!_Vbt8nGKJ9BڿmsFYRЯ𲩱a'IlrzF҈QlgJK#"1\MlF2@o:DTfRa3x <ǖëy!1§sj=:O%> TsGT>hϏ <93 ,QxŪ4_Aycr]Y;HmSuiTI ,MdHfߍbt @L@{veyY= OVNJj#㿨ͧpY965WZ5bc'1#JN`JxդN -q0Hz2.yUQc n42nx(50)gZӫUX({%T%<\ŶsT=`ؑªm֚kn6nkTc搋:.Pk"ڰGPdؓQ(n, I(^ C61'\]ޏ g KHX-(l _B:Ng~xKԾb?B ˩#km'~Ґn od͋7gR׼aGh6&~Ą[t W1_XԜ)`ͪ\e誼ř܍dIII.%ͧW0a@GGCElsՆyLCL.B♊Oyu,|]r_'bG<ʔh !`i9V~KJttO7[IBCVPt+r> yLPZD@3?zّ&v/Ƿ2$;fׅ=,\4Ɲz%&)9A ;Ǜ9^Km" x<Ixua:$ 6s.-A~̺3&8BX{O]~v/w~Yڅ޿䇭#QTo&,#q EqkU*l+ ^d9O4y= rkx :{,Mql](χڶgsԢy]eE%ǢgЍdf mUz'ag8Bp]V#O}!̍JtXFRa GŒq=fN1̂c5gBS"g[C%Y(-Ot,/!k.zh{Kb(. p64XNN2~JSBW]BQ,c ߟϹRl)Bp^b:bϛ6_7@zC,D~/75۟V,X#`-AkЎsӁ{QigGo ̛v.{k&I18Vm!yr({O9JPhA~o-G~>Ll<@i~T#V2[| =e(L6V^h.sh/rFDx|ZJř9spCu6,xZ^{s$G1qV!JU}cM'9-#1IzD^$&B@S&E g|C8C9̐ВqX[-l'Nf!jt.<+TOU(|P`Į"8ҩFf̖$'%:B8O  7`0Ț#ೃ,o,R;^'O^Q;fr zh^Gnus<,nOp;蔂B<>WKb4׏[ .j@/ 'zB\m@',/5G0 s dGZc!2!\Fne1v"PX?])UktiYM먺iJBFmXuGˢ~YV%xSKftr_} 9QŶQkN!/OKN# ^o1ۮ O5ձ眆J51 i?h:Ӵzd}(kw5.P`ǙԎI,!r Q~/j;~p5w?xJrLd%$cSvTg# <#QZ*6pAczI3ٿ' -1 !sU_=}`ԯ$AyǹgHXʑdx^jđb*GգB:b\; 4Xۃj4 #MS^?H'9tB$ߧqA`k\ ΁+ֵ?kԻ!mfͨх쟻qݴC㕋HNx{.%PupEq;ؗ^X1{$)eZՔX+ϮD Oij$RDgUF@N3}wo”  ZZY})2H-apuEO ڣ"&ҹ/ [k#KUHW0:'m=0U_2l,]M6<%Ȟ#^f&-֔lk\ {[9sghxb]xƚkI)Bxr+:,my;0f&CohASBWhg%B &*=&(X #C6teHcK G .m 3aWaBך4 1h}0+0Cj} !Պ`%by.q|4EZ]aJN^?2/HS3=eEqjo qq 5ROIxYU広Knz[xq{7O<ͷ6Q_jj'4G~k=d le# ~L4ɰ y30L2}w'n>,FjoA d+4{RC ~Slye)x@8=!Mi.@K7!dM"U\6úk_,l=CFؚ;RW9]N!50w;/nݩ4>AFdDg^ _y$a]#V݀*@ sd͓u1ADU-ĪcJ<c}4VF-ۓtm4;Yeܤe%b=AIV SX5E49{}SFwjA Bxr"'z&XtK{RiijnJcUČ[2 e7|sXSE׶g`y]H8f И<=hvrJ&. ˽l 1˛-e ^Ţ^2{BƀR2\X[6؃ϓn^2睂m?R0fzŲYИe.V"U9^bQ}R8XyJ~[юs~1b10Ms:IO԰Įv.4*y:8lTL$~^ܘ~%J¬sА]jC#pkv2{HS=j GX0jd{ G9+EX &$!AL[ɪ_p޷TLp<6s8,S2͋Q;@\NZ֣X`n!v~D$`n3Vs`M/K? Q .4Ģ^mt賿j0jZMjQ!H:DdJgW`Hެ)PD^'">Bq`'!ICOR_w@W6p0wc/ލxl%bVD_ '>"+8-OW,EZx%%eE|`p1l4ت.3G~dy fl:Jǭh%jD͏IF9d1M~[N tۏykhZ oljޥ.l\gE t]׌w"aɇٶ1mKBk8׾Ԝ鴡IN<+J5]E]5b;75NްƒRT,<:?dص{1iPuvķ科c$@";Þ/g^:ja7C~3= ʭVYL4 7Wt2UkNjc9< pKǾ m5HdA`J,;PM`23 ecEcR@T f'!a5v[}x1@}_iq(l%9@DZkiN yq,)Q(iPvOx䶖Qh5^: rmVN3kw᳅C :xvlim1hkP“U>h%z)M"NZC nvѯJB9h$?/=輿x^!8 S4#Oųl7f}ԝ H2iRE uxCO+WF"i Hq8h ;Yw6J^L0+ɁхYU]B+\sO-ÜZ\`6&{cxa ROKq^$8p da}k?4 r9  ?d\+~$ ȝuP\[qhǙ@K^X|^<@~`!_ :s:Eu6 YŠ*5|V1uďD;3׫ QwF2 vHȃ\ؘl !,jc%B ?ICJc@>c?pmKmwk.FH!9yOٶAO)<mQvkFID>%dx"j&R͵XC[`-0*gRSIvQN/ӵl7`Yvw;n\'9.p^\6шnRGq↺v(Ȯq:o{s0 'W9^^Wi5.P'InxX3FlcEQFIzy-GG(S~Ɇc$c@n!.X Cͫ'˔&}L"Q@0$i (ѺiL3S>iRY\#ɃOxi|50aeI\,ǝRٻr4[~Cj:l^ٻcz߅eOoErX/ 9w({RըzZ!g2J81m{$>\< qG g>)vi٦ t# exrO$O@z 4s(8RI endstream endobj 1448 0 obj << /Length 696 /Filter /FlateDecode >> stream xmTMo0Wx$ ! 8l[jWHL7IPV=M̼ su;Uٛ=w]yil;<[[j<=?׾+v`&ߴț<^*;~&Q>MS >_P{=s@dkx;`VY`s4JaQܡn.Uu9\Y6><ٴ.Z.4>Dӗ}~r:-d0VWk,8yLһʮӮђ[*mLr?q 5F8@=@)& 8Rx uD\j2HV0CzL] bctI g$`htы0\F0s jd< I6zg W qȐ+#k .bsrbmXK7ǵH7Gnb>&jؐu1VljOu$՟qWS/%1{\xB!K(hHTЖ枃Jρϯv=k2UKς_:~$/ ~E+7ˢ/ l(/} -+ZXukoԝE?ZKq endstream endobj 1449 0 obj << /Length 739 /Filter /FlateDecode >> stream xmUMo0WxvHUdCmU^!1H#x?gx]OTm$|͜s_Iss :L;<Sz==׾f`*_`ɫڟk3'iѴ}=M;7rfnj-eSӵOLg~8 )ok A8 $`I\3`Af<Z]! xNky"7 _㓧q H`nḱRONH=CpB:# =%888QA~!*zƜАT?!~> tw8y*sύ }nFE>7*QύR>7G];~<6OIyktg>O:yұϓN|I/|yIg>O:y҅ϓ.}2 L> stream xmUMo0WxvH UdC۪TBb B8߯{ .@=/ۙڽs{K;K.k6/k+[M'ҷ>dyӔKe'$cS`vfSfK}fƁVGGf\bu<19w|擬CTAW $rG]IyMsh$aW7y̟u? sK-`θtJ!'c83?NaO<Dg!;IX 0z)rЃ@kpBQ]^Z7! / U <ɉ#W m/%]cX! gȀhID8QN~ACT/sQQRs 穅ύ>7: F+}n4eE=zG~<6OɈy2kLd>O&y2ϓQ>OfdV>OF<dR'<>O)yJS*}𗏿tx>z{O->tՍ]*3>cC~ endstream endobj 1451 0 obj << /Length 900 /Filter /FlateDecode >> stream xmUMo:W5?$R. d9M eCkmCp;;w~>|3E_?O]5߶w]Occ]=~?}Oyh9%?۹׬B|Ɯ>);vw%g43>\ 6 EJ78 1{~`W(-;]%=xe_,b+-O;q\L}UI--=BKE1p[! Mߊyu>.N5K)Wb٬8i[_uʕMzQ)V(Txޢjy!Z2P="Zd0\ÃGR\).2*Шa!U,H`+j.5Nα@VK-x%3%AYӀzΚ>kP#5m0Woþj.ZT$X/)n)#Wo(oRZ $Kp4Z-b\1ܰJ P"GXQi/8k^Zq:Zs9dB )sL-7xJ`aɽ)f$1 dъcCZC<73JgznHȰYɚTa,_-O87}KԴܗLloK+gJ.GZyVc48Wt]:P~`rZq.n1] S/Pu7Ue:?&?!d&1yHn5)yғBx#1ޞ]Go׏M?X endstream endobj 1452 0 obj << /Length 900 /Filter /FlateDecode >> stream xmUMo:W5?$R. d9M eCkmCp;;w~>|3E_?O]5߶w]Occ]=~?}Oyh9%?۹׬B|Ɯ>);vw7{>oaI> ѲH8U/RǾ0ñ_x0ӅxBiE.͏S=/b_ixމbc4fi|8EXD_R4.GRQhV̪xvqڎXJfUıkM;rͭSlҏ֋jU,N2@ ",   T[<5 1"àcvG@mg K | +T|5flxZ1YP^ꠦdb}[ה_Q>kUbw88]k|'%Ǿjց{ g䈏rsqk:n87xIue.Aft0!?4ɳ4mFtӔ^z1?z .~lP}L endstream endobj 1453 0 obj << /Length 665 /Filter /FlateDecode >> stream xmTMk0WhFG*! miʲVZCcYy#9햅ļ{3񸟤e&Oo]&C]]Mq>zwt߉Ǯ)n.pCx?nڽVgx=itO"i [\l\WM}'ԭ̚t4pXeȉeU oq yM\-CnCW_Ey}wP dZz891euB)] W-\v\]~[S!8&+Zce"'2Ɍ5I@|"B2AQhSlLء28a}ɑFq5ҍnnbfǮCG= Wܢe$g;A,:sx l=NOTƘ$0_س/vЧQ%~Zx pX2]$^qnaK??q FqMyc0=) &l(mi,3|d &\c ]͹&ӈ9w{d-tx\ \cΜekqLJs?<@>qhx .׷8wl~1V<*m"mmDa endstream endobj 1454 0 obj << /Length 664 /Filter /FlateDecode >> stream xmTMo0WxvB+8l[jWHL7RI;onDo3ތ?n~<&Y$ŝK_IsE77E[^N\5sߖ;7|[lzmS_*7F?h3΃;mc-bB`ew\_7oK׽;(2Z.ETz}ܟ~o9V^MVK7-\f\S}[S!pcSs|TXo1/ȡ aeuC> stream xmTMo0WxvB+8l[+ML7RI;onDo3ތ?n~<&YվI|/ŋ;t硋nn\3<:Wj\=?-wn6pGۦ|Tnʽgxté7~qzxKlqrnX7UޞMjuSAxHiQ,'wͱ 1}hW7q{UEݥ-rG*F>NNL7u]tNhWS;wE )b,#TTHy=)9>*QKr7P:MȡQ^s$LD6aȑ*s.$S56`>ƄmÁ#TL 5kd}WXssc*zRh/#? bE$L|ږ8^y>eSQc̯bV̯cNa'_OAJ195kd3EH@8ܰ%~As*=F 0`{RLPh33Y$LƹǬ oqMsȼ tx\ \cΜ-eksL ?"@>qhx ׷=l~1֍>*]!MBa endstream endobj 1456 0 obj << /Length 665 /Filter /FlateDecode >> stream xmTn0C6U@"mTt@;olvR3ތm~<&YվI|+œ;t羋<]3;Wj|{}[ mmᆂMv{Kt=c_~B?zxoBS6wBJ)X7UaMuSxHiQV,4$O;nC-bD/OCnC_n^ѻs׽9X2Z.ET~{~ʶrn_~߼h!R,6ew*ؔb%k e+Kӄ$a"1x*s.$S56P>Ƅm„A Fs 5577vرϾ+uaя6R:!,əCxg+ѧy*JcL|*m:fvuiWUꧏɩ\g%<Ϛ"sÖ0_:3x0kjhyIYx0aCnOg3$cx0<<v5O#ܵu7A 6*sZ ZcΜ-ܠeYksL ?"@>qh|tngk;dGGM@c endstream endobj 1406 0 obj << /Type /ObjStm /N 100 /First 949 /Length 3154 /Filter /FlateDecode >> stream xZioV_ᏭP|MBIJhi6z5e0 sg 3C]}zuF nH0 pqO\cB$hrD"DP[ F:2ڢ pԞ *PO#c& ͓K0xj Abh!Vx[M-4lXO[ "18 q@M‚:YxҢ-l-QAP E-`ْ8o`6R`6%QDQ0)A)Rr`6<fi00k,*Ff EI =fA/[ J(YG#c$y5aǻ ;˾L p9'?j8E"+D^R(ޗQ zڦb]>V4n^|j(-> bXSTŮ[;(5ʕm=GK@+QRZ'TJ̡{±Z$&^кōPT3Cg_"GS:{jT;*A-F(Mq^(0<܊$$3viGhsh7N816/@Rm69ew+E4{^p"{mY_V*2K YCrr+4m45mqn]YaH%;dY/ b=tj 2DF ,Z匇*-ƔmeR(iHI)<)* c4Mjft xzu_!eotqA>~'' '_sl,4m8ڍ'+\FZz6e#ݕs[KHO\dEeEBhE\NJiob Q]3 ֵ,SY"iNIGmVV+-ܴ>RkMS{( ֫MK-IڴjzGȉo{ KT#bdY4P ݴageKw\ģhRvYi i(|쫭@ոrM>Q&Ӧ\^)i_U=,Vқ}#n6pT|8ѳrt;ΤwOiC{q;;/Oյl0I{޹w+&^}6ez:ޖõq}w3Þ]ٯK;d{͎석3v.]댻yGi'y&9F#fםq35bףN7e&5"MfEGu~nͰE,4X!ݲQv,gzxl ci:!}g "H@ic}fI|Ivs+qN*O/tlBqHV(d&w,c?lʦ@Gd__ow6\~; -)WvW9xի:ֶɶ̷lM^k[PgŶ^dJ;YnN*TO *4B|PuذR[p7qӳC-QRD!壈Vhˢ&|YN/WLd*)g#AoBWS~gr7'DwEVXIE ǐk~Q3* Ę?_*S&ھuS2-KVp:t2sl/.^?9igpsqDjXLȦ`񵶘jt̤3R5;j {qvd?WMB0a/-r LmW )+bU1qPǍҠouiڡƴ 6Ew7Y._i!J_iW6:Ү-k6JmuvU}=5 *bz.V?f̂\3鍒-i3ZNP:^VvYolZa*|;эËK4JB% /uIXC8i72eϩKͤUP;)BBe>JQED;Xt%78@ufJF)zeHThYwzJ 2Lv!@X] (`ը*9!TeVB8-DW^7| +!SHBSc)UN?5,s쬲YoRIvL9rsvJqy! `YŠ=bf$ojkELԱCjD~錳s|+?Wgh<%oN"$o&w◔q|s|1|SD haK01XFTꠍ~0yLI5%N <ٴo" KoUl >e\[d;Ejs!SaehJf94 |eъ)׃l!R7.vn'Av?$t endstream endobj 1457 0 obj << /Length 665 /Filter /FlateDecode >> stream xmTn0C6U@"mTt@;olvR3ތm~<&YվI|+œ;t羋<]3;Wj|{}[ mmᆂMv{Kt=cߚ~B?zxoBS6wBJ)X7UaMuSxHiQV,4$O;nC-bD/OCnC_n^ѻs׽9X2Z.ET~{~ʶrn_~߼h!R,6ew*ؔb%k e+Kӄ$a"1x*s.$S56P>Ƅm„A Fs 5577vرϾ+uaя6R:!,əCxg+ѧy*JcL|*m:fvuiWUꧏɩ\g%<Ϛ"sÖ0_:3x0kjhyIYx0aCnOg3$cx0<<v5O#ܵu7A 6*sZ ZcΜ-ܠeYksL ?"@>qh|tngk;dGGMc endstream endobj 1459 0 obj << /Length 799 /Filter /FlateDecode >> stream xuUn@+HɁkc{!5&Q^ үル!zya/W7/~jyld}{9}N=C'u\W;oέO*k`~?''3Ɖt3\;WS]Q?SVk ]{9FSѤoG^ 32j$WC0h޼O~wC4Sy<&>U]Rn·ÛB~,{_=ڰfhm_}4zu|sH]Wb MLD!E!B FAC\dQQ(%T<#h^QqKƊL0cF F͌a._Q mPG9'+X38)+ι7\'~5:r%%Β뤧$1$܋a %aN*Atg&W̡`92/X[B|fAlI)dKdgI$[d$[H$[hv-|9~ddK%[w-t--d ~)BO)Rd dK|ɖNK)K)++Ζ]Rd]Oz͜|x8?<ᤥNO]?p@}_:h? endstream endobj 1460 0 obj << /Length 720 /Filter /FlateDecode >> stream x}TMo0+J6*ħöUSEj9߯ IVcf͏睟ݛ{)^؝}]u:vzyu|CW$nmmΑmq5)M{`qjS5M2үxO%r^q &\TƦkR@YwDoYia) SZM5_$$>kxq4|;o4vhwqB؝Bf#j{p7P_?{+4}+VYu}e}n.ˍggfjj{k:lF #QhJq  HQ/e.!Pp #]gQtVTv)#l-g!7'uӾ:[sI r.39uf *gQNxEqV11V啣Yq:54kDCZ+)]Ws8:а/9R\Qrz\8Ç]按Sp/ d8D(B!4׳030 =;fzÞJmw&^0C~/nS0GKW皠NdzG5cC)!=E^K<3Iò8ȿ q3NOg{ACt~Qn~ɸ\ %1.: *4hH`<4̶E hS endstream endobj 1461 0 obj << /Length 550 /Filter /FlateDecode >> stream xmSˎ0+$1$#8h@Bܰp`~ +8*=SJ]sCM&ESݮ`w z\ħmbo'ޚr028~}uHXz_z.XA_`1o"xR:bct\$7҈٘TmH@ ]W0ywznͩV+1r]oś}X 6g1ͭnm{!^ ' bނP48YhC`୤\UY=0ZĎiơ 7([4r;"A"e"qDgs"2dK$#В%#KDDNs5&]J[/G endstream endobj 1458 0 obj << /Type /ObjStm /N 100 /First 916 /Length 3405 /Filter /FlateDecode >> stream xZr6}WѪTĝTRXΖ7MRNj$V8 ~6 {y؇ѷiP ̔0"eJrW*e\gdY ȩt /3MƸO UfL30%3?0p+Ɍ̍Ry^e~gZ q KE GJ9S'JMR1 … Kah@ <\fGD(D !B%+9k c lrcS/&$94C2g*$ yΤuUR<ؤ( X\Ȥ;s!vKDdفdQ$ȕ?IcRG9!P xpANä`}B'f ƠRKGei+օ5,v0c Eh$E%i Tpk5#`h7 %jV B9 PZ-v܍V- v K88`g.2ʬ~^e_gDQ)tاMsV#]1#Fph爑ÈQј)}dňQ `l PƨtLW9)}}ZYz X/B}h"̨8X8ˈ p})qgz*DQ}2N}$lc56XuJzהMCc>e~hήtgh6`Pʺ_RGZ}f^Ƈ긜H- uY ^EXi2V#e9LeyRYQ e?ceq V&#eR2VceeH$I`xL`(t@@t)t@P@T)T@@d(d@@D )D@@D (xx)x`X)X#@ i9@ 4G|2R8M27"_{7"^wY7"]s7"\oݦ6"[kզ6"ZgͦY6"YcŦ6"X_5"W[5"VWY5"US5"TO4"SK4"RGY4"QC4"P?}3"O;uGKB$f5ٶn*ѥjX)%OȨ$ƈ}-8 /u 'C?y9;ԛFnF'Wbq^ozY j.pYfݬaIbM Caj.`r =%6Ŧe ɍ>}qŅ{=z}q~,4 Grd^\]B)Q(n㧞C<vHDCAH*щ;U=HtE>A,c"SǬ/+|ZHfG&'3"#xiGi8۪bUV։L'69 ;Dر W;lu@7aP%.o85J^?vŲv; !%z2e3TClPh.7196/r W Co0^"k #w,n>I̻K*ѕt3U5TdEDc\d'\%e㝮lj|,gQ*Z-o^lQ'!!2bڂc\sĉ -_vIɘ@W1Od۞0R˜}YZEz1E-Dˉ"wM U[e<^ *}<9rY}CkG3/ׅd([5"[U3 x"AUG8ͭ  vdo_L)X'|ב43R.".no9d4/(ngg@`>Oz1a&CI`~ƞVIvI(Զ YAnyj: S"OxUOOЩh&",!# Lvw٦c.(/ 'hHSUtf?ݽ݀lsc6 \:"f ߑ( Y|<ґy W4=52ڋ8[f'559Z/Ξsbyד!f jbDwJ6O9 ;pU޸ gٳB栃Yo~/ Es KNnd!5G0M$|l_PntaQ|g3 8}dpnAEdLp0epo_*9l< +V;H80#a l7m`=x%i_4*2 sgtw4''u;I4sh»r:?x9k`w9)`3~W|MӅ0 篪$3Z p;D7x<:-&`0c@ | endstream endobj 1589 0 obj << /Producer (pdfTeX-1.40.24) /Author(\376\377\000P\000a\000v\000e\000l\000\040\000N\000.\000\040\000K\000r\000i\000v\000i\000t\000s\000k\000y)/Title(\376\377\000s\000t\000a\000t\000n\000e\000t\000.\000c\000o\000m\000m\000o\000n\000:\000\040\000C\000o\000m\000m\000o\000n\000\040\000R\000\040\000S\000c\000r\000i\000p\000t\000s\000\040\000a\000n\000d\000\040\000U\000t\000i\000l\000i\000t\000i\000e\000s\000\040\000U\000s\000e\000d\000\040\000b\000y\000\040\000t\000h\000e\000\040\000S\000t\000a\000t\000n\000e\000t\000\040\000P\000r\000o\000j\000e\000c\000t\000\040\000S\000o\000f\000t\000w\000a\000r\000e)/Subject()/Creator(LaTeX with hyperref)/Keywords() /CreationDate (D:20230524160722+10'00') /ModDate (D:20230524160722+10'00') /Trapped /False /PTEX.Fullbanner (This is pdfTeX, Version 3.141592653-2.6-1.40.24 (TeX Live 2022/Debian) kpathsea version 6.3.4) >> endobj 1498 0 obj << /Type /ObjStm /N 91 /First 942 /Length 3906 /Filter /FlateDecode >> stream xڕ[Q~\ FRiE<wONJ]H͊>ə|3ܕ! 8lqH,,I e ES)!?ޤ8Xǹo}͈ 3fBOvp,aCsɬăc}˜{!9LhLS'xlB/! @Fu<0'#w\2Ȏ3W.7Wo?7No߯a&CVlW3Yǥ4^>Ix[mykY4s;ErKZxxwӒڗ𘇘j[׻qx|ޮ{y}2"dKbmG44GQI6qj5Xji(Y gERC;fBFݴRr-|>1?|^v]:)rRhCXlz8Pm6cަqCHz_ߝ{ҖݐB..;bվt|>L#{%fTSdj]ij5!'a1j6Esѝ/TU4\a/ٟ[n?3R޴Z҅q17]ܻ{X=h-\elv/cO3#ؒgN9ISҁIb$K;yϊʺaf^$DjOkIԒCg=k]1LRP}!@H $5B]rl< LS$ԠO05`6B $hf=k-t.zNg YHj$ˀ1)]1ѻyHK$5^.BRz,fYi,8͂158pL SCE0Ya@15:tLSMN<:bֳڲax<6GAddkiQBƕ= 9"jWl (7]#j\`cͶoosv4.[l4uUpa)qBKXZ &%fNlmj{xHKĈ+b%d: &1/[ժ| @ %NH{V@hڤ6I@sjpbI&V,i5=A)2;`F;9 MEEP0+X Vk[ `m~؏d!XmCB(89Ct c c Pwq3" i@+>@|s3@{};hM up@6ǡc~k #NA'QME'Q:7nTD$OTdQ2h;豁X%Eݨ?/ Kr(̨cJtk8t8A&S:ԀIEhF͢,W\3xz5-k;ȘR\YʘxN.v.VI]ω&C1w Θ;u&uH9ΘUfy$vxΖ6.q躑1'mn\J*1>cr83 ^nn;t83梧Ϙ67c#ϘP:ϘQ~7|cnU :-*ĤE]Z7 T{P}h.S鵉:~(u">ZXS95ɥD5fj7rhGEg s-qMo`8W8-u 4B*Amdnxjdg-u) AMg}),0K)统.ŬG V&n[¬ŭP܊ŭU)!粋3?}Xte,^e,be% .8}2(E)K1kiݜ6Mjw^c_fDd3_6/-iK5%G:[CYy)^՜hW}X0S<0Ń9\R\Lcݶmݶi)ֿS;\[Wpto"we.Wp WpPW?'繊TTC7naxA *^PA=m7IēhJϋ뢞:l]b` endstream endobj 1590 0 obj << /Type /XRef /Index [0 1591] /Size 1591 /W [1 3 1] /Root 1588 0 R /Info 1589 0 R /ID [<8FB8989BDBEDE514509CE04097B07D8C> <8FB8989BDBEDE514509CE04097B07D8C>] /Length 3713 /Filter /FlateDecode >> stream x%Y-U{]o}D!%}AD%bAFA \0TLrUJ+1<o5^k}c̦(~:VcE*?E{i:yQ,- 0Eyͩ0m$vNs:[ vVs&[+vFs6+vZs.;)vJs> n\ \k.X7U2X.6[lBs[*vTs&vDs +Ju^a Q!My=V;vnf|xݚC٢bvj;-3!Plf qwb!H\!ibab;6k΋ ^,Q\ ~bL; V;#r߁b 5}7ba0~JGX,7lm[ aRRWZX +-|ŢHRw쫧1D\(&Hv)FKvHvHvHvHvHvXmbD}m膦Yem,|w@t!9?p Pk[iIҲ%rK-Z~i尖Zl▽[o%D+SZ)ʭV=mL+[ҪhUVVP+ZZ*T^SqPܺ-pM>oe, <4`H\< Vn87 r۟fbM CR1Ci>g>|AH/Rò.[${E3LXSSlil.5bʊ9j,6؆x^f+`+l#vߌW X晏q1 Ohn–T<ݰ~8>8 \+p&Rq})8 gm?pc߽7܆;pxЄ ˏI*Nx7{ygM/ލ#Y7?`:XS:2v4hѼQku Rq t'tb B.VV4~],!6ot$֦)tݩ;"wD,1[t ZhѼ[?G#>q߅#rGN-N';Jw ]阦 a xSwQ~wXcPZ1RG5P~Ne*~k}0h y9Ffht XR1Z<1<<6zX_{]`9ZX+kM+C!*V ֓; VlAܐ%y&é3_ Q^ ͣ`98q ,'Ni8g p.eW<'CwrnIn܅{p`4 1!%FPjx- ~o~c;lK}j3vM%*5oԼQ z),3UU5GQA"_ݯ7FRӷޜ?J|8:\RV _M7"MJpulmԱjM՚5#^N\RsI%5\R$7)NMR~ T|k2:僚j>~' Q~aN)>Kw?㍚7FXQ26Tbg|0, 0% `6̃0%6fB?^`5 `c*v obˆ]XF*:8#p&> Ğ= N?]+`66lЁm؜ - V[x|ۯ#<[309 BXF?ZYҸw?4ckQ|2{#$HVYgWXRz_"|5 T,P@4B`┦}-Z ԯ_Q"|EU**g, qT;*fhYmIiClQCU,+@lbw7 3T;=U1W*T\RqI%-JU٢}W z W7zr?҉? ={4iӼNO={Wz'|O={8}¨}}ͥogߦt@;{]''78L~H43`&JrX`NJ;1BXa ,eV*X k`- 6 `cJ)~r;쀝^)=a( ~q26|yN)3py\+pu7܆;p}x<'sx/!n58U ,탓8h7ohXah89P~CpIsP~C 7oP~C 7oP~C 7oP~C 7oP~C 7o0F ,J !L9 }@8)M6Yx*A/r!9Kshi6-(إ4K+t]*E[,HK_:f.IJe?~m`7[S\u鈺0rCc%HaQHa? ᷥ4ߝ~K\ȍи 0N94 7)׆f7qu+Ʈ;/F\Mc_Wا4eq |\=LW/ ?^do|uO#|#Fۻ#tGc|ol/UbRVLƋx{$}O𼓞w&`W3&a2~&m3L2d, 4ؓ0 0U4^kx+!n#2Gd9"sDY=lՃdO=yٓg Y=AVzՃd Y=AVzՃd Y=V0+YyȪ@V*U dU YȪ@V*U dU YȪ@V*U3g̟>|&|&|&|&|&|&|&|&|&|&|&|&|&|&|&|&|&|&|&|&|&|~E2[l endstream endobj startxref 265156 %%EOF statnet.common/build/stage23.rdb0000644000176200001440000000576114433324627016304 0ustar liggesusers\ s(RԑOYRb5>dJɸ),IX !ոO__dXP=};7ArB~)kL)=K>p?2KWoLF&~k!bTͦ_eC|vk^xl4A귥CHjj:"l^~~ u0;ܸWBUh,\0BÖ6#.(;]h~)#+l#|5^moQlVG#DA-CMZ(ޮٝnN~k꟔[w޽w5m NLcN?Pcﲱe7HйPh88+▎d yAb XBÆb`6^ulMl Yz ,pJ_N > 6 /`/7 0QDUS`J-H: {a(OuK@4\k#w "KYB%^׼\Adt)?(= FMnX8ګ  pO4˔7mĐȣ.]>Kn"_KB;)y~Sh#FxZ8eOF/HI!RpE&&fW;m$ve62E]lQDGVeMu'쒠t!w_6cY%@Ht CU$Ji8IJľR-mbx?&aPz>:1v>OU*!Ce}E͖[jό2[Mil5z^>ZSOؔʓ< ɖ#wυ" fUT#eUS,ԺlOWK>MWph Cܦ&h2m!$&u>:NqzTd(VY vĎ-2u;Ȣ $myH5gL9_<~>=v'a", @CőNx=P=ѽpŽ5wš9>( ̒A^Ž#u"#W긤5c4!pz8ĺ鲊7%[\`eo_w^[E,H)s: .͎l0I e0xP# lN=|v7:f;6,#H2/[)=h75oS V} aOpwE4屛swH dh-#iE@Hi#B7ͫπK).A4]yڮy'dm" "Jؿ`%Y( ͑O%qЎۥ"DOz9FaNĸ.I0SqD43 Q@B-otA|N|%BJe4=>FѤc 1+OG>n\W?_AfLdncr#D ´,4P|o%WA16 3n&+ iﲊTeQ6+)/uw[a"}M:Z=w-7Zt0-d=YwXgb\RXSF'8m貃dѐ[Z1Y# Ĩ9ZU؉P!#^ .gT LȠჍعj2dFhN|сG紲"9)h>пl嘬bM3X2ܗSBU$GbQX$E|bgDŎuf0`b,bbHy=&Nfh]twYh{sжRѱĊudDu>L "@ل$;\e! ",^hFfؤϝ>x+T̳chkt-XMUY}$/RD]Ǡ6u3@T ۔¯--Estatnet.common/src/0000755000176200001440000000000014433324632014016 5ustar liggesusersstatnet.common/src/logspace_utils.c0000644000176200001440000001520014376774271017213 0ustar liggesusers/* File src/logspace_utils.c in package statnet.common, part of the * Statnet suite of packages for network analysis, https://statnet.org . * * This software is distributed under the GPL-3 license. It is free, * open source, and has the attribution requirements (GPL Section 7) at * https://statnet.org/attribution . * * Copyright 2007-2023 Statnet Commons */ #include #include #include /* * Compute log sum x given log(x) values logx * * log (sum_i exp (logx[i]) ) = * log (e^M * sum_i e^(logx[i] - M) ) = * M + log( sum_i e^(logx[i] - M) * * without causing overflows or throwing much accuracy. * * Based on logspace_sum in pgamma.c in R; unlike that implementation, * it does not use the long double type, sacrificing precision for a * speed gain. */ double log_sum_exp(const double *logx, int n){ if(n == 1) return logx[0]; if(n == 2) return logspace_add(logx[0], logx[1]); // else (n >= 3) : int i; // Mx := max_i log(x_i) double Mx = logx[0]; for(i = 1; i < n; i++) if(Mx < logx[i]) Mx = logx[i]; double s = 0.; for(i = 0; i < n; i++) s += exp(logx[i] - Mx); return Mx + log(s); } SEXP log_sum_exp_wrapper(SEXP logx, SEXP long_double){ long_double = PROTECT(coerceVector(long_double, LGLSXP)); logx = PROTECT(coerceVector(logx, REALSXP)); int n = length(logx); SEXP out = PROTECT(allocVector(REALSXP, 1)); if(LOGICAL(long_double)[0]) REAL(out)[0] = logspace_sum(REAL(logx), n); else REAL(out)[0] = log_sum_exp(REAL(logx), n); UNPROTECT(3); return(out); } /* * Compute a weighted mean of x given log-weights lw * * log (sum_i exp (logx[i]) ) = * log (e^M * sum_i e^(logx[i] - M) ) = * M + log( sum_i e^(logx[i] - M) * * without causing overflows or throwing much accuracy. * Based on logspace_sum in pgamma.c in R. */ double logspace_wmean (const double *x, const double* logw, int n){ if(n == 1) return x[0]; // else (n >= 2) : int i; // Mw := max_i log(w_i) double Mw = logw[0]; for(i = 1; i < n; i++) if(Mw < logw[i]) Mw = logw[i]; double sw = 0., sxw = 0.; for(i = 0; i < n; i++){ double w = exp(logw[i] - Mw); sw += w; sxw += w*x[i]; } return (double) sxw/sw; } SEXP logspace_wmean_wrapper(SEXP x, SEXP logw){ x = PROTECT(coerceVector(x, REALSXP)); logw = PROTECT(coerceVector(logw, REALSXP)); int n = length(x); if(n != length(logw)) error("Lengths of value and log-weight vectors differ."); SEXP out = PROTECT(allocVector(REALSXP, 1)); REAL(out)[0] = logspace_wmean(REAL(x), REAL(logw), n); UNPROTECT(3); return(out); } /* Matrix version of logspace_wmean */ void logspace_wmeans (const double *xm, const double* logw, int n, int p, double *out){ if(n == 1){ memcpy(out, xm, p*sizeof(double)); return; } // else (n >= 2) : int i; // Mw := max_i log(w_i) double Mw = logw[0]; for(i = 1; i < n; i++) if(Mw < logw[i]) Mw = logw[i]; memset(out, 0, p*sizeof(double)); double sw = 0.; for(i = 0; i < n; i++){ double w = exp(logw[i] - Mw); sw += w; for(unsigned int j = 0; j < p; j++) out[j] += w*xm[i + j*n]; } for(unsigned int j = 0; j < p; j++) out[j] /= sw; } SEXP logspace_wmeans_wrapper(SEXP xm, SEXP logw){ int *xdim = INTEGER(PROTECT(getAttrib(xm, R_DimSymbol))); int n = xdim[0], p = xdim[1]; xm = PROTECT(coerceVector(xm, REALSXP)); logw = PROTECT(coerceVector(logw, REALSXP)); if(n != length(logw)) error("Number of rows in the value matrix differs from the length of the log-weights vector."); SEXP out = PROTECT(allocVector(REALSXP, p)); logspace_wmeans(REAL(xm), REAL(logw), n, p, REAL(out)); UNPROTECT(4); return(out); } SEXP sweep2m(SEXP xm, SEXP stats){ int *xdim = INTEGER(PROTECT(getAttrib(xm, R_DimSymbol))); int n = xdim[0], p = xdim[1]; SEXP out = PROTECT(allocMatrix(REALSXP, n, p)); xm = PROTECT(coerceVector(xm, REALSXP)); stats = PROTECT(coerceVector(stats, REALSXP)); /* if(p != length(stats)) error("Number of columns in the value matrix differs from the length of the STATS vector."); */ unsigned int pos = 0; for(unsigned int i=0; i= 2) : int i; // Mw := max_i log(w_i) double Mw = logw[0]; for(i = 1; i < n; i++) if(Mw < logw[i]) Mw = logw[i]; memset(out, 0, p*p*sizeof(double)); double sw = 0.; for(i = 0; i < n; i++){ double w = exp(logw[i] - Mw); sw += w; for(unsigned int j = 0; j < p; j++) for(unsigned int k = 0; k <= j; k++) out[j + k*p] += w*xm[i + j*n]*xm[i + k*n]; } for(unsigned int j = 0; j < p; j++) for(unsigned int k = 0; k <= j; k++){ out[j + k*p] /= sw; out[k + j*p] = out[j + k*p]; } } SEXP logspace_wmean2_wrapper(SEXP xm, SEXP logw){ int *xdim = INTEGER(PROTECT(getAttrib(xm, R_DimSymbol))); int n = xdim[0], p = xdim[1]; xm = PROTECT(coerceVector(xm, REALSXP)); logw = PROTECT(coerceVector(logw, REALSXP)); if(n != length(logw)) error("Number of rows in the value matrix differs from the length of the log-weights vector."); SEXP out = PROTECT(allocMatrix(REALSXP, p, p)); logspace_wmean2(REAL(xm), REAL(logw), n, p, REAL(out)); UNPROTECT(4); return(out); } void logspace_wxmean (const double *xm, const double *ym, const double* logw, int n, int p, int q, double *out) { // else (n >= 2) : int i; // Mw := max_i log(w_i) double Mw = logw[0]; for(i = 1; i < n; i++) if(Mw < logw[i]) Mw = logw[i]; memset(out, 0, p*q*sizeof(double)); double sw = 0.; for(i = 0; i < n; i++){ double w = exp(logw[i] - Mw); sw += w; for(unsigned int j = 0; j < p; j++) for(unsigned int k = 0; k < q; k++) out[j + k*p] += w*xm[i + j*n]*ym[i + k*n]; } for(unsigned int j = 0; j < p; j++) for(unsigned int k = 0; k < q; k++) out[j + k*p] /= sw; } SEXP logspace_wxmean_wrapper(SEXP xm, SEXP ym, SEXP logw){ int *xdim = INTEGER(PROTECT(getAttrib(xm, R_DimSymbol))); int n = xdim[0], p = xdim[1]; int *ydim = INTEGER(PROTECT(getAttrib(ym, R_DimSymbol))); if(n != ydim[0]) error("Numbers of rows in the value matrices differ."); int q = ydim[1]; xm = PROTECT(coerceVector(xm, REALSXP)); ym = PROTECT(coerceVector(ym, REALSXP)); logw = PROTECT(coerceVector(logw, REALSXP)); if(n != length(logw)) error("Number of rows in the value matrices differs from the length of the log-weights vector."); SEXP out = PROTECT(allocMatrix(REALSXP, p, q)); logspace_wxmean(REAL(xm), REAL(ym), REAL(logw), n, p, q, REAL(out)); UNPROTECT(6); return(out); } statnet.common/src/init.c0000644000176200001440000000271614430356203015127 0ustar liggesusers/* File src/init.c in package statnet.common, part of the * Statnet suite of packages for network analysis, https://statnet.org . * * This software is distributed under the GPL-3 license. It is free, * open source, and has the attribution requirements (GPL Section 7) at * https://statnet.org/attribution . * * Copyright 2007-2023 Statnet Commons */ #include #include #include // for NULL #include /* FIXME: Check these declarations against the C/Fortran source code. */ /* .Call calls */ extern SEXP log_sum_exp_wrapper(SEXP, SEXP); extern SEXP logspace_wmean_wrapper(SEXP, SEXP); extern SEXP logspace_wmean2_wrapper(SEXP, SEXP); extern SEXP logspace_wmeans_wrapper(SEXP, SEXP); extern SEXP logspace_wxmean_wrapper(SEXP, SEXP, SEXP); extern SEXP sweep2m(SEXP, SEXP); static const R_CallMethodDef CallEntries[] = { {"log_sum_exp_wrapper", (DL_FUNC) &log_sum_exp_wrapper, 2}, {"logspace_wmean_wrapper", (DL_FUNC) &logspace_wmean_wrapper, 2}, {"logspace_wmean2_wrapper", (DL_FUNC) &logspace_wmean2_wrapper, 2}, {"logspace_wmeans_wrapper", (DL_FUNC) &logspace_wmeans_wrapper, 2}, {"logspace_wxmean_wrapper", (DL_FUNC) &logspace_wxmean_wrapper, 3}, {"sweep2m", (DL_FUNC) &sweep2m, 2}, {NULL, NULL, 0} }; void R_init_statnet_common(DllInfo *dll) { R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); R_useDynamicSymbols(dll, FALSE); } statnet.common/NEWS0000644000176200001440000002403714433314054013731 0ustar liggesusersstatnet.common 4.9.0 ==================== New utilities ------------- - A new function,`lweighted.cov()`, to compute weighted covariance between two matrices or vectors. - New linear algebra utilities, `is.SPD()`, `sandwich_solve()`, `sandwich_ssolve()`, `sginv()`, `snearPD()`, `srcond()`, `ssolve()`, `xAxT()`, `xTAx()`, `xTAx_qrsolve()`, `xTAx_qrssolve()`, `xTAx_solve()`, and `xTAx_ssolve()` moved from `ergm` and documented. Bug fixes --------- - In `handle.controls()`, arguments that are `match.arg()`-ed are now evaluated in the correct frame. statnet.common 4.8.0 ==================== New utilities ------------- - A helper function `unused_dots_warning()` is exported that works with `rlang::check_dots_used()` to print an informative message. statnet.common 4.7.0 ==================== New utilities ------------- - An S3 class `term_list` for storing terms extracted from a formula, by `list_rhs.formula()` and others, containing information about each term's sign and environment. Concatenation, indexing, and print methods are implemented. Bug fixes --------- - `list_rhs.formula()` can now handle `NULL` terms on the RHS. statnet.common 4.6.0 ==================== New utilities ------------- - An implementation of Welford's online algorithm for calculating sample mean and variance has been added as a class `Welford` that implements method `update()` and maintains elements `$n`, `$means`, `$SSDs`, and `$vars`. Bug fixes --------- - `snctrl()` was issuing a warning twice when called with a misspelled argument. - `deInf()` now handles `NULL` input. - in `locate_function()` a subtle bug has been fixed in handling of visible as opposed to invisible objects. statnet.common 4.5.0 ==================== New utilities ------------- - `ergm`'s term locator functions (`locate_function()` and `locate_prefixed_function()`) have been moved from `ergm`. - A new function, `default_options()`, a wrapper around `options()` that drops options already set. - A new function, `as.control.list()` generic and methods which take an R list and call an appropriate `control.*()` function on it. - `check.control.class()` now first runs the control argument through `as.control.list()` and overwrites, so `control=` arguments to many functions can be plain lists. - A new function, `simplify_simple()`, which takes a list and returns an atomic vector if the elements of the list are atomic and of length 1, with particular handling for `NULL` and empty (0-length) elements. - A new function, `snctrl()` (StatNet ConTRoL), designed so that argument completion will complete all available control functions. Looking up its help (`?snctrl`) produces a dynamic list of all control parameters and their packages and control functions that is updated as packages are loaded and unloaded. - A new function, `handle.controls()`, that performs the most normal functions in a `control.*()` function. - Two trivial helper functions, `base_env()` and `empty_env()`, to replace an object's environment with `baseenv()` and `emptyenv()`, respectively. - A new function, `fixed.pval()` that wraps `base::format.pval()` with better default arguments. - A reimplementation of `attr()` is exported, which disables partial matching by default. Enhancements to existing utilities ---------------------------------- - `statnetStartupMessage()` now first looks for a `comment=(affil=...)` for the contributor's affiliation, before using e-mail. - Improved output formatting for `.Deprecate_once()`. - `append_rhs.formula()` now accepts NULL as the first argument, in which case it creates a new formula, and takes an additonal argument `env=`, which is used as this new formula's environment. Miscellaneous changes --------------------- - `rle` utilities are no longer reexported. - `statnet.common` no longer depends on `purrr`. - `statnetStartupMessage()` has been simplified. statnet.common 4.4.0 ==================== `rle` utilities have been moved to a separate package, `rle` ------------------------------------------------------------ - Major methods are reexported, for now. New utilities ------------- - `split()` methods for matrices and arrays, to split them along a margin. - `trim_env()`, a generic that will replace an environment (possibly attached to another object) with a sub-environment containing only objects whose names are specified. - A `diff()` method for control lists and a `print()` method for the resulting differences. - `deInf()`, to replace `.deinf()` in package `ergm`. - A `compress()` generic, a `compress()` method for RLEs, and a `doNotCompress` argument to `rep.rle()`. Both `compact.rle()` and the `doNotCompact` argument to `rep.rle()` are now deprecated. Enhancements to existing utilities ---------------------------------- - Various optimizations have been made to RLEs. - `nonsimp_update.formula()` now handles both one and two sided formulas; it also now copies all names except `...` when `from.new = TRUE`. Bug fixes --------- - `str.rle()` now works despite the overridden `length()` method. statnet.common 4.3.0 ==================== New utilities ------------- - `EVL()`, a family of functions like `NVL()`, that treat any object of length 0 as `NULL`. - `once()`, a `purrr`-style adverb that wraps a function to only evaluate the first time it's called with a given configuration of arguments. - `persistEval()` and `persistEvalQ()` to retry evaluating a given expression a specified number of times. Bug fixes --------- - In `forkTimeout()`, don't collect a process twice. Thanks to Tomas Kalibera for suggesting the fix. statnet.common 4.2.0 ==================== New utilities ------------- - `.Deprecate_once()` calls `.Deprecated()`, passing all its arguments through, but only the first time it's called. - `.Deprecate_method()` calls `.Deprecated()`, but only if a method has been called by name, i.e., `METHOD.CLASS`. - `forkTimeout()` evaluates an R expression with a hard time limit (except on Windows) by forking a process. Unlike `setTimeLimit()`, it enforces the limit even on native code. - `ult()` is a convenience function that extracts or replaces elements of a list indexed from the end. Miscellaneous ------------- - `statnet.common` now depends on R \>= 3.5 due to what appears to be a method dispatching bug in earlier versions. - The package no longer Enhances `coda`. statnet.common 4.1.4 ==================== New utilities ------------- - `despace()` removes whitespace from a string. - Pseudo-methods `colMeans.mcmc.list()`, `sweep.mcmc.list()`, and `lapply.mcmc.list()` (migrated from the `ergm` package). - `filter_rhs.formula()` selectively deletes terms in on the RHS of a formula. - `eval_lhs.formula()` extracts the LHS of the formula and evaluates it in the specified environment. - `NVL2()` and `NVL3()` for flexible substitution of null values. - `message_print()` formats its arguments as if for `print()` or `show()` methods, but then prints to stderr like `message()`. Enhancements to existing utilities ---------------------------------- - `paste.and()` now takes an additional `con=` argument, allowing a conjunction other than "and" to be used. - `ERRVL()` now uses lazy evaluation and lets the user dot-substitute the previous argument's try-error into the next argument. Bug fixes --------- - Printing for control lists now works for function arguments. - A number of improvements to `rle` methods. Miscellaneous ------------- - A number of functions have been renamed for consistency: - `term.list.formula()` → `list_rhs.formula()` - `append.rhs.formula()` → `append_rhs.formula()` - `nonsimp.update.formula()` → `nonsimp_update.formula()` - Citation utilities have been deprecated, since CRAN's structure makes them unusable. statnet.common 4.0.0 ==================== - The package now uses `Roxygen` for documentation. - `term.list.formula()` output format has been changed, since support of attributes on symbols is being deprecated. - A library of methods has been added for the base `rle` class, implementing concatenation, compaction, and a number of binary operations. - `all_same()` has been moved from ergm and renamed to `all_identical()`. - A new assignment method `NVL()<-` overwrites a variable if its value is NULL. - A set of classes and functions for manipulating and efficiently performing calculations on dense matrices or vectors with weighted rows or elements (possibly on the log scale) has been added. - New control parameter helper function, control.remap() has been added. Autodetection of function names by `set.control.class()` and `check.control.class()` has been deprecated and now results in a warning. - Improvements to the compressed data frame code, including an order() generic. - Miscellaneous robustifications added. - Native routine registration has been added. statnet.common 3.3.0 ==================== - `append.rhs.formula()`, `vectors.namesmatch()`, `term.list.formula()`, and `ergm.update.formula()` (renamed to `nosimp.update.formula()`) moved from `ergm`. - Skye Bender-deMoll has been added as a contributor. statnet.common 3.2.3 ==================== - `ERRVL()` moved from `ergm`. - Some `NAMESPACE` and other fixes to pass CRAN checks. statnet.common 3.2.2 ==================== - control class improvements and bug fixes. statnet.common 3.1.1 ==================== - Updated e-mail address - Some improvements to opttest. statnet.common 3.1.0 ==================== - Initial release, incorporating the control class framework (`set.control.class()`, `check.control.class()`, `print.control.list()`); startup message framework; `NVL()`; `sort.data.frame()`; `compress.data.frame()`; `paste.and()`; citation utilities framework; and `opttest()` framework. statnet.common/R/0000755000176200001440000000000014433324632013430 5ustar liggesusersstatnet.common/R/logspace.utils.R0000644000176200001440000001430514376774271016530 0ustar liggesusers# File R/logspace.utils.R in package statnet.common, part of the # Statnet suite of packages for network analysis, https://statnet.org . # # This software is distributed under the GPL-3 license. It is free, # open source, and has the attribution requirements (GPL Section 7) at # https://statnet.org/attribution . # # Copyright 2007-2023 Statnet Commons ################################################################################ #' Utilities for performing calculations on logarithmic scale. #' #' A small suite of functions to compute sums, means, and weighted means on #' logarithmic scale, minimizing loss of precision. #' #' @param logx Numeric vector of \eqn{\log(x)}, the natural logarithms of the #' values to be summed or averaged. #' #' @param x,y Numeric vectors or matrices of \eqn{x} and \eqn{y}, the (raw) values #' to be summed, averaged, or whose variances and covariances are to #' be calculated. #' #' @param logw Numeric vector of \eqn{\log(w)}, the natural logarithms of the #' weights. #' @param use_ldouble Whether to use \code{long double} precision in the #' calculation. If \code{TRUE}, 's C built-in \code{logspace_sum()} is used. If #' \code{FALSE}, the package's own implementation based on it is used, using #' \code{double} precision, which is (on most systems) several times faster, at #' the cost of precision. #' @return The functions return the equivalents of the R expressions given below, #' but faster and with less loss of precision. #' @author Pavel N. Krivitsky #' @keywords arith #' @examples #' x <- rnorm(1000) #' stopifnot(all.equal(log_sum_exp(x), log(sum(exp(x))), check.attributes=FALSE)) #' stopifnot(all.equal(log_mean_exp(x), log(mean(exp(x))), check.attributes=FALSE)) #' #' logw <- rnorm(1000) #' stopifnot(all.equal(m <- sum(x*exp(logw))/sum(exp(logw)),lweighted.mean(x, logw))) #' stopifnot(all.equal(sum((x-m)^2*exp(logw))/sum(exp(logw)), #' lweighted.var(x, logw), check.attributes=FALSE)) #' #' x <- cbind(x, rnorm(1000)) #' stopifnot(all.equal(mx <- colSums(x*exp(logw))/sum(exp(logw)), #' lweighted.mean(x, logw), check.attributes=FALSE)) #' stopifnot(all.equal(crossprod(t(t(x)-mx)*exp(logw/2))/sum(exp(logw)), #' lweighted.var(x, logw), check.attributes=FALSE)) #' #' #' y <- cbind(x, rnorm(1000)) #' my <- colSums(y*exp(logw))/sum(exp(logw)) #' stopifnot(all.equal(crossprod(t(t(x)-mx)*exp(logw/2), t(t(y)-my)*exp(logw/2))/sum(exp(logw)), #' lweighted.cov(x, y, logw), check.attributes=FALSE)) #' stopifnot(all.equal(crossprod(t(t(y)-my)*exp(logw/2), t(t(x)-mx)*exp(logw/2))/sum(exp(logw)), #' lweighted.cov(y, x, logw), check.attributes=FALSE)) #' @name logspace.utils #' @useDynLib statnet.common NULL #' @describeIn logspace.utils `log(sum(exp(logx)))` #' @export log_sum_exp <- function(logx, use_ldouble=FALSE){ if(length(logx)==0) -Inf else .Call("log_sum_exp_wrapper", logx, use_ldouble, PACKAGE="statnet.common") } #' @describeIn logspace.utils `log(mean(exp(logx)))` #' @export log_mean_exp <- function(logx, use_ldouble=FALSE){ if(length(logx)==0) NaN else .Call("log_sum_exp_wrapper", logx, use_ldouble, PACKAGE="statnet.common") - log(length(logx)) } #' @describeIn logspace.utils weighted mean of `x`: #' `sum(x*exp(logw))/sum(exp(logw))` for `x` scalar and #' `colSums(x*exp(logw))/sum(exp(logw))` for `x` matrix #' @export lweighted.mean <- function(x, logw){ d <- dim(x) if(is.null(d)){ # Vector if(length(x)==0) NaN else if(length(x)!=length(logw)) stop("x and logw must have the same length") else .Call("logspace_wmean_wrapper", x, logw, PACKAGE="statnet.common") }else if(length(d)>2){ stop("Arrays of 3 or more dimensions are not supported at this time.") }else{ # Matrix if(d[1L]==0) rep(NaN, d[2L]) else if(d[1L]!=length(logw)) stop("logw must have the same length as the number of rows in x") else .Call("logspace_wmeans_wrapper", x, logw, PACKAGE="statnet.common") } } #' @describeIn logspace.utils weighted variance of `x`: `crossprod(x-lweighted.mean(x,logw)*exp(logw/2))/sum(exp(logw))` #' @export lweighted.var <- function(x, logw){ E <- lweighted.mean(x, logw) if(is.null(dim(x))){ if(length(x)<2) return(NA) x <- x - E lweighted.mean(x*x, logw) }else{ if(nrow(x)<2) return(matrix(NA, 1, ncol(x))) .Call("logspace_wmean2_wrapper", sweep_cols.matrix(x, E), logw, PACKAGE="statnet.common") } } #' @describeIn logspace.utils weighted covariance between `x` and `y`: `crossprod(x-lweighted.mean(x,logw)*exp(logw/2), y-lweighted.mean(y,logw)*exp(logw/2))/sum(exp(logw))` #' @export lweighted.cov <- function(x, y, logw){ xdim <- dim(x) E <- lweighted.mean(x, logw) x <- if(is.null(xdim)) x - E else sweep_cols.matrix(x, E) ydim <- dim(y) E <- lweighted.mean(y, logw) y <- if(is.null(ydim)) y - E else sweep_cols.matrix(y, E) if(is.null(xdim) || is.null(ydim)){ if(length(x)<2) return(NA) o <- lweighted.mean(x*y, logw) if(!is.null(xdim)) cbind(o) else if(!is.null(xdim)) rbind(o) else o }else{ if(nrow(x)<2) matrix(NA, ncol(x), ncol(y)) else .Call("logspace_wxmean_wrapper", x, y, logw, PACKAGE="statnet.common") } } #' Suptract a elements of a vector from respective columns of a matrix #' #' An optimized function equivalent to \code{sweep(x, 2, STATS)} for a matrix #' \code{x}. #' #' #' @param x a numeric matrix; #' @param STATS a numeric vector whose length equals to the number of columns #' of \code{x}. #' @param disable_checks if \code{TRUE}, do not check that \code{x} is a #' numeric matrix and its number of columns matches the length of \code{STATS}; #' set in production code for a significant speed-up. #' @return A matrix of the same attributes as \code{x}. #' @examples #' #' x <- matrix(runif(1000), ncol=4) #' s <- 1:4 #' #' stopifnot(all.equal(sweep_cols.matrix(x, s), sweep(x, 2, s))) #' #' @export sweep_cols.matrix <- function(x, STATS, disable_checks=FALSE){ if(!disable_checks) if(!is.matrix(x) || mode(x)!="numeric" || ncol(x)!=length(STATS)) stop("Argument ",sQuote("x")," must be a numeric matrix variable (not an expression that evaluates to a numeric matrix).") o <- .Call("sweep2m", x, STATS, PACKAGE="statnet.common") attributes(o) <- attributes(x) o } statnet.common/R/locator.R0000644000176200001440000001232514364112224015214 0ustar liggesusers# File R/locator.R in package statnet.common, part of the # Statnet suite of packages for network analysis, https://statnet.org . # # This software is distributed under the GPL-3 license. It is free, # open source, and has the attribution requirements (GPL Section 7) at # https://statnet.org/attribution . # # Copyright 2007-2023 Statnet Commons ################################################################################ #' A simple dictionary to cache recent InitFunction lookups. #' #' @param name function name. #' @param env the environment name for the function; if `NULL`, look #' up in cache, otherwise insert or overwrite. #' #' @return A character string giving the name of the environment #' containing the function, or `NULL` if not in cache. #' @noRd locate_function_cache <- local({ cache <- list() watchlist <- character(0) # Packages being watched for unloading. pkglist <- character(0) # Current list of packages. # Reset the cache and update the list of watched packages. reset <- function(...){ pkglist <<- .packages() new <- setdiff(pkglist, watchlist) for(pkg in new){ setHook(packageEvent(pkg, "detach"), reset) setHook(packageEvent(pkg, "onUnload"), reset) } watchlist <<- c(watchlist, new) cache <<- list() } # Check if new namespaces have been added. checknew <- function(){ if(!setequal(.packages(), pkglist)) reset() } function(name, env=NULL){ checknew() if(is.null(env)){ cache[[name]] }else{ cache[[name]] <<- env } } }) #' Locate a function with a given name and return it and its environment. #' #' These functions first search the given environment, then search all #' loaded environments, including those where the function is not #' exported. If found, they return an unambiguous reference to the #' function. #' #' @name locate_function NULL #' @describeIn locate_function a low-level function returning the #' reference to the function named `name`, or `NULL` if not found. #' #' @param name a character string giving the function's name. #' @param env an [`environment`] where it should search first. #' @param ... additional arguments to the warning and error warning messages. See Details. #' #' @return If the function is found, an unevaluated call of the form #' `ENVNAME:::FUNNAME`, which can then be used to call the function #' even if it is unexported. If the environment does not have a #' name, or is `GlobalEnv`, only `FUNNAME` is returned. Otherwise, #' `NULL` is returned. #' #' @details If the initial search fails, a search using #' [getAnywhere()] is attempted, with exported ("visible") functions #' with the specified name preferred over those that are not. When #' multiple equally qualified functions are available, a warning is #' printed and an arbitrary one is returned. #' #' Because [getAnywhere()] can be slow, past searches are cached. #' #' @examples #' #' # Locate a random function in base. #' locate_function(".row_names_info") #' #' @export locate_function <- function(name, env = globalenv(), ...){ if(is.call(name)) name <- name[[1]] name <- as.character(name) # Try the given environment... if(!is.null(obj<-get0(name, mode='function', envir=env))){ env <- environment(obj) envname <- environmentName(env) # Check that environment name is not blank or globalenv(), and # that the detected environment actually contains the object. if(! NVL(envname,"") %in% c("", "R_GlobalEnv") && exists(name, mode='function', envir=env, inherits=FALSE)) return(call(":::",as.name(envname),as.name(name))) else return(as.name(name)) } # Try the cache... envname <- locate_function_cache(name) if(!is.null(envname)) return(call(":::",as.name(envname),as.name(name))) # Use getAnywhere()... #' @importFrom utils getAnywhere m <- getAnywhere(name) if(length(m$objs)){ ## Prioritise visible over not: if(any(m$visible)){ m <- lapply(unclass(m)[-1], "[", m$visible) } if(length(m$objs)>1) warning("Name ",name," matched by multiple objects; using the first one on the list.", ...) envname <- environmentName(environment(m$objs[[1]])) locate_function_cache(name, envname) return(call(":::",as.name(envname),as.name(name))) } NULL } #' @describeIn locate_function a helper function that searches for a #' function of the form `prefix.name` and produces an informative #' error message if not found. #' #' @param prefix a character string giving the prefix, so the #' searched-for function is `prefix.name`. #' @param errname a character string; if given, if the function is not #' found an error is raised, with `errname` prepended to the error #' message. #' @param call. a logical, whether the call #' (`locate_prefixed_function`) should be a part of the error #' message; defaults to `FALSE` (which is different from [stop()]'s #' default). #' #' @export locate_prefixed_function <- function(name, prefix, errname, env = globalenv(), ..., call.=FALSE){ if(is.call(name)) name <- name[[1]] name <- as.character(name) fname <- paste(prefix,name,sep=".") f <- locate_function(fname, env, ...) if(is.null(f) && !is.null(errname)) stop(errname,' ', sQuote(name), " function ", sQuote(fname), " not found.", ..., call.=call.) else f } statnet.common/R/zzz.R0000644000176200001440000000100214364112224014374 0ustar liggesusers# File R/zzz.R in package statnet.common, part of the # Statnet suite of packages for network analysis, https://statnet.org . # # This software is distributed under the GPL-3 license. It is free, # open source, and has the attribution requirements (GPL Section 7) at # https://statnet.org/attribution . # # Copyright 2007-2023 Statnet Commons ################################################################################ .onUnload <- function(libpath){ library.dynam.unload("statnet.common",libpath) } statnet.common/R/deprecation_utils.R0000644000176200001440000000553614364112224017274 0ustar liggesusers# File R/deprecation_utils.R in package statnet.common, part of the # Statnet suite of packages for network analysis, https://statnet.org . # # This software is distributed under the GPL-3 license. It is free, # open source, and has the attribution requirements (GPL Section 7) at # https://statnet.org/attribution . # # Copyright 2007-2023 Statnet Commons ################################################################################ #' @name deprecation-utilities #' @rdname deprecation-utilities #' @title Utilities to help with deprecating functions. #' NULL #' @rdname deprecation-utilities #' #' @description `.Deprecate_once` calls [.Deprecated()], passing all its arguments #' through, but only the first time it's called. #' #' @param ... arguments passed to [.Deprecated()]. #' #' @examples #' \dontrun{ #' options(warn=1) # Print warning immediately after the call. #' f <- function(){ #' .Deprecate_once("new_f") #' } #' f() # Deprecation warning #' f() # No deprecation warning #' } #' @importFrom utils modifyList #' @export .Deprecate_once <- local({ warned <- c() function(...){ me <- sys.call(-1) myname <- format(me[[1L]]) if(! myname%in%warned){ do.call(".Deprecated", modifyList(list(old=myname),list(...))) warned <<- c(warned, myname) } } }) #' @rdname deprecation-utilities #' @description `.Deprecate_method` calls #' [.Deprecated()], but only if a method has been called by name, #' i.e., \code{\var{METHOD}.\var{CLASS}}. Like `.Deprecate_once` it #' only issues a warning the first time. #' #' @param generic,class strings giving the generic function name and #' class name of the function to be deprecated. #' #' @examples #' \dontrun{ #' options(warn=1) # Print warning immediately after the call. #' summary.packageDescription <- function(object, ...){ #' .Deprecate_method("summary", "packageDescription") #' invisible(object) #' } #' #' summary(packageDescription("statnet.common")) # No warning. #' summary.packageDescription(packageDescription("statnet.common")) # Warning. #' summary.packageDescription(packageDescription("statnet.common")) # No warning. #' } #' @export .Deprecate_method <- local({ warned <- c() function(generic, class){ fullname <- paste(generic,class,sep=".") if(! fullname%in%warned){ me <- sys.call(-1)[[1L]] if(length(me)>1 && me[[1L]]=="::") me <- me[[3L]] parent <- sys.call(-2)[[1L]] if(length(parent)>1 && parent[[1L]]=="::") parent <- parent[[3L]] if(me==fullname && NVL(parent,"")!=generic){ do.call(".Deprecated", list(msg=paste0("You appear to be calling ", fullname,"() directly. ", fullname,"() is a method, and will not be exported in a future version of ", sQuote("ergm"),". Use ", generic, "() instead, or getS3method() if absolutely necessary."), old=fullname)) warned <<- c(warned, fullname) } } } }) statnet.common/R/formula.utilities.R0000644000176200001440000004577314364112224017245 0ustar liggesusers# File R/formula.utilities.R in package statnet.common, part of the # Statnet suite of packages for network analysis, https://statnet.org . # # This software is distributed under the GPL-3 license. It is free, # open source, and has the attribution requirements (GPL Section 7) at # https://statnet.org/attribution . # # Copyright 2007-2023 Statnet Commons ################################################################################ ################################################################### ## This file has utilities whose primary purpose is examining or ## ## manipulating ERGM formulas. ## ################################################################### #' @title Functions for Querying, Validating and Extracting from Formulas #' #' @description A suite of utilities for handling model formulas of the style used in Statnet packages. #' #' @name formula.utilities NULL #' @describeIn formula.utilities #' #' \code{append_rhs.formula} appends a list of terms to the RHS of a #' formula. If the formula is one-sided, the RHS becomes the LHS, if #' \code{keep.onesided==FALSE} (the default). #' #' @param object formula object to be updated or evaluated #' @param newterms a [`term_list`] object, or any list of terms (names #' or calls) to append to the formula, or a formula whose RHS terms #' will be used; its `"sign"` attribute vector can give the sign of #' each term (`+1` or `-1`), and its `"env"` attribute #' vector will be used to set its environment, with the first #' available being used and subsequent ones producing a warning. #' @param keep.onesided if the initial formula is one-sided, keep it #' whether to keep it one-sided or whether to make the initial #' formula the new LHS #' @param env an environment for the new formula, if `object` is #' `NULL` #' @param \dots Additional arguments. Currently unused. #' @return \code{append_rhs.formula} each return an updated formula #' object; if `object` is `NULL` (the default), a one-sided formula #' containing only the terms in `newterms` will be returned. #' @examples #' #' ## append_rhs.formula #' #' (f1 <- append_rhs.formula(y~x,list(as.name("z1"),as.name("z2")))) #' (f2 <- append_rhs.formula(~y,list(as.name("z")))) #' (f3 <- append_rhs.formula(~y+x,structure(list(as.name("z")),sign=-1))) #' (f4 <- append_rhs.formula(~y,list(as.name("z")),TRUE)) #' (f5 <- append_rhs.formula(y~x,~z1-z2)) #' (f6 <- append_rhs.formula(NULL,list(as.name("z")))) #' (f7 <- append_rhs.formula(NULL,structure(list(as.name("z")),sign=-1))) #' #' fe <- ~z2+z3 #' environment(fe) <- new.env() #' (f8 <- append_rhs.formula(NULL, fe)) # OK #' (f9 <- append_rhs.formula(y~x, fe)) # Warning #' (f10 <- append_rhs.formula(y~x, fe, env=NULL)) # No warning, environment from fe. #' (f11 <- append_rhs.formula(fe, ~z1)) # Warning, environment from fe #' #' \dontshow{ #' stopifnot(f1 == (y~x+z1+z2)) #' stopifnot(f2 == (y~z)) #' stopifnot(f3 == (y+x~-z)) #' stopifnot(f4 == (~y+z)) #' stopifnot(f5 == (y~x+z1-z2)) #' stopifnot(f6 == (~z)) #' stopifnot(f7 == (~-z)) #' stopifnot(f8 == (~z2+z3), identical(environment(f8), environment(fe))) #' stopifnot(f9 == (y~x+z2+z3), identical(environment(f9), globalenv())) #' stopifnot(f10 == (y~x+z2+z3), identical(environment(f10), environment(fe))) #' stopifnot(f11 == (z2+z3~z1), identical(environment(f11), environment(fe))) #' } #' #' @export append_rhs.formula <- function(object = NULL, newterms, keep.onesided = FALSE, env = if(is.null(object)) NULL else environment(object)){ force(env) if(is.null(object)) keep.onesided <- TRUE if(inherits(newterms,"formula")) newterms <- list_rhs.formula(newterms) for(i in seq_along(newterms)){ newterm <- newterms[[i]] termsign <- if(NVL(attr(newterms, "sign")[i], +1)>0) "+" else "-" if(length(object)==0){ if(termsign == "-") newterm <- call(termsign, newterm) object <- as.formula(call("~", newterm)) }else if(length(object)==3) object[[3L]]<-call(termsign,object[[3L]],newterm) else if(keep.onesided) object[[2L]]<-call(termsign,object[[2L]],newterm) else object[[3L]]<- if(termsign=="+") newterm else call(termsign,newterm) NVL(env) <- termenv <- attr(newterms, "env")[[i]] if(!is.null(termenv) && !identical(env, termenv)) warning(sQuote(paste0("newterms[[",i,"]]")), " has an environment that differs from the specified environment or another term's environment.") } environment(object) <- env object } #' @describeIn formula.utilities #' #' \code{append.rhs.formula} has been renamed to \code{append_rhs.formula}. #' @export append.rhs.formula<-function(object,newterms,keep.onesided=FALSE){ .Deprecate_once("append_rhs.formula") append_rhs.formula(object,newterms,keep.onesided) } #' @describeIn formula.utilities #' #' \code{filter_rhs.formula} filters through the terms in the RHS of a #' formula, returning a formula without the terms for which function #' `f(term, ...)` is `FALSE`. Terms inside another term (e.g., #' parentheses or an operator other than + or -) will be unaffected. #' #' #' @examples #' ## filter_rhs.formula #' (f1 <- filter_rhs.formula(~a-b+c, `!=`, "a")) #' (f2 <- filter_rhs.formula(~-a+b-c, `!=`, "a")) #' (f3 <- filter_rhs.formula(~a-b+c, `!=`, "b")) #' (f4 <- filter_rhs.formula(~-a+b-c, `!=`, "b")) #' (f5 <- filter_rhs.formula(~a-b+c, `!=`, "c")) #' (f6 <- filter_rhs.formula(~-a+b-c, `!=`, "c")) #' (f7 <- filter_rhs.formula(~c-a+b-c(a), #' function(x) (if(is.call(x)) x[[1]] else x)!="c")) #' #' #' \dontshow{ #' stopifnot(f1 == ~-b+c) #' stopifnot(f2 == ~b-c) #' stopifnot(f3 == ~a+c) #' stopifnot(f4 == ~-a-c) #' stopifnot(f5 == ~a-b) #' stopifnot(f6 == ~-a+b) #' stopifnot(f7 == ~-a+b) #' } #' #' @param f a function whose first argument is the term and whose #' additional arguments are forwarded from `...` that returns either #' `TRUE` or `FALSE`, for whether that term should be kept. #' @export filter_rhs.formula <- function(object, f, ...){ rhs <- ult(object) SnD <- function(x){ if(!f(x, ...)) return(NULL) if(is(x, "call")){ op <- x[[1L]] if(! as.character(op)%in%c("+","-")) return(x) else if(length(x)==2){ arg <- SnD(x[[2L]]) if(is.null(arg)) return(NULL) else return(call(as.character(op), arg)) }else if(length(x)==3){ arg1 <- SnD(x[[2L]]) arg2 <- SnD(x[[3L]]) if(is.null(arg2)) return(arg1) else if(is.null(arg1)){ if(as.character(op)=="+") return(arg2) else return(call(as.character(op), arg2)) } else return(call(as.character(op), arg1, arg2)) }else stop("Unsupported type of formula passed.") }else return(x) } rhs <- SnD(rhs) ult(object) <- rhs object } #' @describeIn formula.utilities #' #' \code{nonsimp_update.formula} is a reimplementation of #' \code{\link{update.formula}} that does not simplify. Note that the #' resulting formula's environment is set as follows. If #' \code{from.new==FALSE}, it is set to that of object. Otherwise, a new #' sub-environment of object, containing, in addition, variables in new listed #' in from.new (if a character vector) or all of new (if TRUE). #' #' @param new new formula to be used in updating #' @param from.new logical or character vector of variable names. controls how #' environment of formula gets updated. #' @return #' \code{nonsimp_update.formula} each return an #' updated formula object #' @importFrom stats as.formula #' @export nonsimp_update.formula<-function (object, new, ..., from.new=FALSE){ old.lhs <- if(length(object)==2) NULL else object[[2L]] old.rhs <- if(length(object)==2) object[[2L]] else object[[3L]] new.lhs <- if(length(new)==2) NULL else new[[2L]] new.rhs <- if(length(new)==2) new[[2L]] else new[[3L]] sub.dot <- function(c, dot){ if(is.name(c) && c==".") dot # If it's a dot, return substitute. else if(is.call(c)) as.call(c(list(c[[1L]]), lapply(c[-1], sub.dot, dot))) # If it's a call, construct a call consisting of the call and each of the arguments with the substitution performed, recursively. else c # If it's anything else, just return it. } deparen<- function(c, ops = c("+","*")){ if(is.call(c)){ if(as.character(c[[1L]]) %in% ops){ op <- as.character(c[[1L]]) if(length(c)==2 && is.call(c[[2L]]) && c[[2L]][[1L]]==op) return(deparen(c[[2L]], ops)) else if(length(c)==3 && is.call(c[[3L]]) && c[[3L]][[1L]]==op){ if(length(c[[3L]])==3) return(call(op, call(op, deparen(c[[2L]],ops), deparen(c[[3L]][[2L]],ops)), deparen(c[[3L]][[3L]],ops))) else return(call(op, deparen(c[[2L]],ops), deparen(c[[3L]][[2L]],ops))) } } return(as.call(c(list(c[[1L]]), lapply(c[-1], deparen, ops)))) # If it's a non-reducible call, construct a call consisting of the call and each of the arguments with the substitution performed, recursively. }else return(c) } # This is using some argument alchemy to handle the situation in # which object is one-sided but new is two sided with a dot in the # LHS. quote(expr=) creates a missing argument object that gets # substituted in place of a dot. The next statement then checks if # the resulting LHS *is* a missing object (as it is when the # arguments are ~a and .~.) removes the LHS if it is. out <- if(length(new)==2) call("~", deparen(sub.dot(new.rhs, old.rhs))) else if(length(object)==2) call("~", deparen(sub.dot(new.lhs, quote(expr=))), deparen(sub.dot(new.rhs, old.rhs))) else call("~", deparen(sub.dot(new.lhs, old.lhs)), deparen(sub.dot(new.rhs, old.rhs))) if(identical(out[[2]], quote(expr=))) out <- out[-2] # a new sub-environment for the formula, containing both # the variables from the old formula and the new. if(identical(from.new,FALSE)){ # The new formula will use the environment of the original formula (the default). e <- environment(object) }else{ # Create a sub-environment also containing variables from environment of new. e <- new.env(parent=environment(object)) if(identical(from.new,TRUE)) from.new <- setdiff(ls(pos=environment(new), all.names=TRUE), "...") # If TRUE, copy all of them but the dots (dangerous!). for(name in from.new) assign(name, get(name, pos=environment(new)), pos=e) } as.formula(out, env = e) } #' @describeIn formula.utilities #' #' \code{nonsimp.update.formula} has been renamed to \code{nonsimp_update.formula}. #' @export nonsimp.update.formula<-function (object, new, ..., from.new=FALSE){ .Deprecate_once("nonsimp_update.formula") nonsimp_update.formula(object, new, ..., from.new=from.new) } #' A helper class for list of terms in an formula #' #' Typically generated by [list_rhs.formula()], it contains, in #' addition to a list of [call()] or similar objects, attributes #' `"sign"` and `"env"`, containing, respectively a vector of #' signs that the terms had in the original formula and a list of #' environments of the formula from which the term has been #' extracted. Indexing and concatenation methods preserve these. #' #' @param x a list of terms or a term; a `term_list` #' @param sign a vector specifying the signs associated with each term (`-1` and `+1`) #' @param env a list specifying the environments, or NULL #' @param i list index #' @param ... additional arguments to methods #' #' @seealso [list_rhs.formula()], [list_summands.call()] #' #' @examples #' #' e1 <- new.env() #' f1 <- a~b+c #' environment(f1) <- e1 #' f2 <- ~-NULL+1 #' #' (l1 <- list_rhs.formula(f1)) #' (l2 <- list_rhs.formula(f2)) #' #' (l <- c(l1,l2)) #' \dontshow{ #' stopifnot(identical(c(unclass(l)), alist(b, c, NULL, 1))) #' stopifnot(identical(attr(l, "sign"), c(1,1,-1,1))) #' stopifnot(identical(attr(l, "env"), rep(list(e1, globalenv()), each=2))) #' } #' #' (l <- c(l2[1], l1[2], l1[1], l1[1], l2[2])) #' \dontshow{ #' stopifnot(identical(c(unclass(l)), alist(NULL, c, b, b, 1))) #' stopifnot(identical(attr(l, "sign"), c(-1,1,1,1,1))) #' stopifnot(identical(attr(l, "env"), list(globalenv(), e1, e1, e1, globalenv()))) #' } #' #' @export term_list <- function(x, sign = +1, env = NULL){ if(!is.list(x)) x <- list(x) if(!is.list(env)) env <- list(env) structure(x, sign = rep(sign, length.out=length(x)), env = rep(env, length.out=length(x)), class = "term_list") } #' @rdname term_list #' @export as.term_list <- function(x, ...) UseMethod("as.term_list") #' @rdname term_list #' @export as.term_list.term_list <- function(x, ...) x #' @rdname term_list #' @export as.term_list.default <- function(x, sign = +1, env = NULL, ...) term_list(x, sign=sign, env=env) #' @rdname term_list #' @export c.term_list <- function(x, ...){ xl <- c(list(as.term_list(x)), lapply(list(...), as.term_list)) structure( c(unclass(x), ...), sign = unlist(lapply(xl, attr, "sign"), use.names=FALSE), env = unlist(lapply(xl, attr, "env"), recursive=FALSE, use.names=FALSE), class = "term_list" ) } #' @rdname term_list #' @export `[.term_list` <- function(x, i, ...){ term_list(NextMethod(), sign = attr(x, "sign")[i], env = attr(x, "env")[i]) } #' @rdname term_list #' @export print.term_list <- function(x, ...){ signstr <- ifelse(attr(x, "sign")>=0, "+", "-") envstr <- sapply(attr(x, "env"), format) termstr <- lapply(lapply(x, format), paste0, collapse="\n") cat("Term List:\n") cat(paste(signstr, termstr, envstr, collapse="\n")) cat("\n") } .recurse_summation <- function(x, sign){ if(length(x)==1) term_list(x, sign) else if(length(x)==2 && x[[1L]]=="+") .recurse_summation(x[[2L]],sign) else if(length(x)==2 && x[[1L]]=="-") .recurse_summation(x[[2L]],-sign) else if(length(x)==3 && x[[1L]]=="+") c(.recurse_summation(x[[2L]],sign), .recurse_summation(x[[3L]],sign)) else if(length(x)==3 && x[[1L]]=="-") c(.recurse_summation(x[[2L]],sign), .recurse_summation(x[[3L]],-sign)) else if(length(x[[1]]) && x[[1L]]=="(") .recurse_summation(x[[2L]], sign) else term_list(x, sign) } #' @describeIn formula.utilities #' #' \code{term.list.formula} is an older version of \code{list_rhs.formula} that required the RHS call, rather than the formula itself. #' #' @param rhs,sign Arguments to the deprecated `term.list.formula`. #' #' @export term.list.formula<-function(rhs, sign=+1){ .Deprecate_once("list_rhs.formula") .recurse_summation(rhs, sign) } #' @describeIn formula.utilities #' #' \code{list_summands.call}, given an unevaluated call or expression #' containing the sum of one or more terms, returns an object of class [`term_list`] with the #' terms being summed, handling \code{+} and \code{-} operators and #' parentheses, and keeping track of whether a term has a plus or a #' minus sign. #' #' @return \code{list_summands.call} returns an object of type #' [`term_list`]; its `"env"` attribute is set to a list of #' `NULL`s, however. #' #' @export list_summands.call<-function(object){ .recurse_summation(object, sign=+1) } #' @describeIn formula.utilities #' #' \code{list_rhs.formula} returns an object of type [`term_list`], #' containing terms in a given formula, handling \code{+} and \code{-} #' operators and parentheses, and keeping track of whether a term has #' a plus or a minus sign. #' #' @return #' \code{list_rhs.formula} returns an object of type [`term_list`]. #' #' @examples #' stopifnot(identical(list_rhs.formula(a~b), #' structure(alist(b), sign=1, env=list(globalenv()), class="term_list"))) #' stopifnot(identical(list_rhs.formula(~b), #' structure(alist(b), sign=1, env=list(globalenv()), class="term_list"))) #' stopifnot(identical(list_rhs.formula(~b+NULL), #' structure(alist(b, NULL), #' sign=c(1,1), env=rep(list(globalenv()), 2), class="term_list"))) #' stopifnot(identical(list_rhs.formula(~-b+NULL), #' structure(alist(b, NULL), #' sign=c(-1,1), env=rep(list(globalenv()), 2), class="term_list"))) #' stopifnot(identical(list_rhs.formula(~+b-NULL), #' structure(alist(b, NULL), #' sign=c(1,-1), env=rep(list(globalenv()), 2), class="term_list"))) #' stopifnot(identical(list_rhs.formula(~+b-(NULL+c)), #' structure(alist(b, NULL, c), #' sign=c(1,-1,-1), env=rep(list(globalenv()), 3), class="term_list"))) #' #' @export list_rhs.formula<-function(object){ if (!is(object, "formula")) stop("Invalid formula of class ",sQuote(class(object)),".") o <- .recurse_summation(ult(object), sign=+1) structure(o, env = rep(list(environment(object)), length(o))) } #' @describeIn formula.utilities #' #' \code{eval_lhs.formula} extracts the LHS of a formula, evaluates it in the formula's environment, and returns the result. #' #' @return #' \code{eval_lhs.formula} an object of whatever type the LHS evaluates to. #' @examples #' ## eval_lhs.formula #' #' (result <- eval_lhs.formula((2+2)~1)) #' #' stopifnot(identical(result,4)) #' @export eval_lhs.formula <- function(object){ if (!is(object, "formula")) stop("Invalid formula of class ",sQuote(class(object)),".") if(length(object)<3) stop("Formula given is one-sided.") eval(object[[2L]],envir=environment(object)) } #' Make a copy of an environment with just the selected objects. #' #' @param object An [`environment`] or an object with #' [`environment()`] and `environment()<-` methods. #' @param ... Additional arguments, passed on to lower-level methods. #' #' @param keep A character vector giving names of variables in the #' environment (including its ancestors) to copy over, defaulting to #' dropping all. Variables that cannot be resolved are silently #' ignored. #' #' @return An object of the same type as `object`, with updated environment. #' @export trim_env <- function(object, keep=NULL, ...){ UseMethod("trim_env") } #' @describeIn trim_env A method for environment objects. #' @export trim_env.environment <- function(object, keep=NULL, ...){ # NB: The parent should be baseenv(), not emptyenv(), because :: and # ::: are defined in baseenv(), so PKG:::NAME calls won't work. e <- new.env(parent=baseenv()) for(vn in keep){ try(assign(vn, get(vn, envir=object), envir=e), silent=TRUE) } e } #' @describeIn trim_env Default method, for objects such as [`formula`] and [`function`] that have [`environment()`] and `environment()<-` methods. #' @export trim_env.default <- function(object, keep=NULL, ...){ environment(object) <- trim_env(environment(object), keep, ...) object } #' Replace an object's environment with a simple, static environment. #' #' @param object An object with the `environment()<-` method. #' #' @return An object of the same type as `object`, with updated environment. #' #' @examples #' f <- y~x #' environment(f) # GlobalEnv #' #' environment(empty_env(f)) # EmptyEnv #' #' \dontshow{ #' stopifnot(identical(environment(empty_env(f)), emptyenv())) #' } #' @export empty_env <- function(object){ environment(object) <- emptyenv() object } #' @rdname empty_env #' @examples #' #' environment(base_env(f)) # base package environment #' #' \dontshow{ #' stopifnot(identical(environment(base_env(f)), baseenv())) #' } #' @export base_env <- function(object){ environment(object) <- baseenv() object } statnet.common/R/startup.utilities.R0000644000176200001440000000727214364112224017272 0ustar liggesusers# File R/startup.utilities.R in package statnet.common, part of the # Statnet suite of packages for network analysis, https://statnet.org . # # This software is distributed under the GPL-3 license. It is free, # open source, and has the attribution requirements (GPL Section 7) at # https://statnet.org/attribution . # # Copyright 2007-2023 Statnet Commons ################################################################################ ## .who.loaded.me <- function(){ ## top.call <- sys.calls()[[1L]] # Grab the top-level call. ## top.fn <- as.character(top.call[[1L]]) ## if(length(top.fn)!=1 || !(top.fn %in% c("library","require"))) return(NULL) ## top.call <- match.call(get(as.character(top.call[[1L]]),baseenv(),mode="function"),top.call) # Expand the arguments. ## top.call <- as.list(top.call) # Turn the call into a list. ## top.pkg <- top.call$package ## if(!NVL(top.call$character.only,FALSE)) ## as.character(top.pkg) ## else top.pkg ## } #' Construct a "standard" startup message to be printed when the package is #' loaded. #' #' This function uses information returned by [packageDescription()] #' to construct a standard package startup message according to the #' policy of the Statnet Project. #' #' @param pkgname Name of the package whose information is used. #' @param friends,nofriends No longer used. #' #' #' @return A string containing the startup message, to be passed to the #' [packageStartupMessage()] call or `NULL`, if policy #' prescribes printing default startup message. (Thus, if #' [statnetStartupMessage()] returns `NULL`, the calling package should #' not call [packageStartupMessage()] at all.) #' #' @note Earlier versions of this function printed a more expansive #' message. This may change again as the Statnet Project policy #' evolves. #' @seealso [packageDescription()], [packageStartupMessage()] #' @keywords utilities #' @examples #' #' \dontrun{ #' .onAttach <- function(lib, pkg){ #' sm <- statnetStartupMessage("ergm") #' if(!is.null(sm)) packageStartupMessage(sm) #' } #' } #' @export statnetStartupMessage <- function(pkgname, friends = c(), nofriends = c()) { desc <- utils::packageDescription(pkgname) paste0("\n", sQuote(desc$Package), " ", desc$Version, " (", desc$Date, "), part of the Statnet Project\n", "* ", sQuote(paste0("news(package=\"", desc$Package, "\")")), " for changes since last version\n", "* ", sQuote(paste0("citation(\"", desc$Package, "\")"))," for citation information\n", "* ", sQuote("https://statnet.org"), " for help, support, and other information\n") } #' Set [options()] according to a named list, skipping those already #' set. #' #' This function can be useful for setting default options, which do #' not override options set elsewhere. #' #' @param ... see [options()]: either a list of `name=value` pairs or #' a single unnamed argument giving a named list of options to set. #' #' @return The return value is same as that of [options()] (omitting #' options already set). #' #' @examples #' options(onesetting=1) #' #' default_options(onesetting=2, anothersetting=3) #' stopifnot(getOption("onesetting")==1) # Still 1. #' stopifnot(getOption("anothersetting")==3) #' #' default_options(list(yetanothersetting=5, anothersetting=4)) #' stopifnot(getOption("anothersetting")==3) # Still 3. #' stopifnot(getOption("yetanothersetting")==5) #' @export default_options <- function(...){ x <- list(...) if(is.null(names(x))){ if(length(x)==1) x <- x[[1]] else stop("invalid argument") } if(all(names(x)=="")) stop("list argument has no valid names") if(any(names(x)=="")) stop("invalid argument") toset <- setdiff(names(x), names(options())) do.call(options, x[toset]) } statnet.common/R/cite.utilities.R0000644000176200001440000001020114364112224016476 0ustar liggesusers# File R/cite.utilities.R in package statnet.common, part of the # Statnet suite of packages for network analysis, https://statnet.org . # # This software is distributed under the GPL-3 license. It is free, # open source, and has the attribution requirements (GPL Section 7) at # https://statnet.org/attribution . # # Copyright 2007-2023 Statnet Commons ################################################################################ # ---- BEGIN STATNET CITATION FUNCTIONS ---- #' \code{CITATION} file utilities for Statnet packages (DEPRECATED) #' #' These functions automate citation generation for Statnet Project #' packages. They no longer appear to work with CRAN and are thus #' deprecated. #' #' #' @param pkg Name of the package whose citation is being generated. #' @return For \code{statnet.cite.head} and \code{statnet.cite.foot}, an object #' of type \code{citationHeader} and \code{citationFooter}, respectively, #' understood by the \code{\link{citation}} function, with package name #' substituted into the template. #' #' For \code{statnet.cite.pkg}, an object of class \code{\link{bibentry}} #' containing a 'software manual' citation for the package constructed from the #' current version and author information in the \code{DESCRIPTION} and a #' template. #' @seealso citation, citHeader, citFooter, bibentry #' @keywords utilities #' @name statnet.cite #' @examples #' #' \dontrun{ #' statnet.cite.head("statnet.common") #' #' statnet.cite.pkg("statnet.common") #' #' statnet.cite.foot("statnet.common") #' } NULL # A header function for ensuring that all the statnet packages provide consistent messaging #' @rdname statnet.cite #' @export statnet.cite.head <- function(pkg){ .Deprecated("No longer usable.") utils::citHeader( paste("`",pkg,"` is part of the Statnet suite of packages. ", "If you are using the `",pkg,"` package for research that will be published, ", "we request that you acknowledge this by citing the following.\n", 'For BibTeX format, use toBibtex(citation("',pkg,'")).', sep="") ) } # A footer function for ensuring that all the statnet packages provide consistent messaging #' @rdname statnet.cite #' @export statnet.cite.foot <- function(pkg){ .Deprecated("No longer usable.") # the 'meta' variable should be provided by R's CITATION processing script # instead of using packageDescription(). But if this code is called in another context # use packageDescription() to assign meta if(!exists("meta") || is.null(meta)){ meta <- utils::packageDescription(pkg) } utils::citFooter("We have invested a lot of time and effort in creating the", "Statnet suite of packages for use by other researchers.", "Please cite it in all papers where it is used. The package",pkg," is made distributed under the terms of the license:",meta$License ) } # generates a consistent bibentry citation for the software manual of the package #' @rdname statnet.cite #' @export statnet.cite.pkg <- function(pkg){ .Deprecated("No longer usable.") # the 'meta' variable should be provided by R's CITATION processing script # instead of using packageDescription(). But if this code is called in another context # use packageDescription() to assign meta if(!exists("meta") || is.null(meta)){ meta <- utils::packageDescription(pkg) } projhomepage <- "http://www.statnet.org" # compute the list of authors auts <- eval(parse(text=meta$`Authors@R`)) auts <- auts[sapply(auts, function(aut) "aut" %in% aut$role)] # create a citation entry for a "software manual" for this version of the software # it will be appended with any specific articles defineded inthe package citation file utils::bibentry("Manual", author = auts, title = paste(meta$Package,": ", meta$Title, sep=""), organization = paste("The Statnet Project (\\url{", projhomepage, "})",sep=""), year = substr(meta$Date,1,4), note = paste("R package version ", meta$Version, sep=""), url = paste("CRAN.R-project.org/package=",meta$Package,sep="") ) } # ---- END STATNET CITATION FUNCTIONS ---- statnet.common/R/misc.utilities.R0000644000176200001440000007325414430356203016527 0ustar liggesusers# File R/misc.utilities.R in package statnet.common, part of the # Statnet suite of packages for network analysis, https://statnet.org . # # This software is distributed under the GPL-3 license. It is free, # open source, and has the attribution requirements (GPL Section 7) at # https://statnet.org/attribution . # # Copyright 2007-2023 Statnet Commons ################################################################################ #' reorder vector v into order determined by matching the names of its elements #' to a vector of names #' #' A helper function to reorder vector \code{v} (if named) into order specified #' by matching its names to the argument \code{names} #' #' does some checking of appropriateness of arguments, and reorders v by #' matching its names to character vector \code{names} #' #' @param v a vector (or list) with named elements, to be reorderd #' @param names a character vector of element names, corresponding to names of #' \code{v}, specificying desired orering of \code{v} #' @param errname optional, name to be reported in any error messages. default #' to \code{deparse(substitute(v))} #' @return returns \code{v}, with elements reordered #' @note earlier versions of this function did not order as advertiased #' @examples #' #' test<-list(c=1,b=2,a=3) #' vector.namesmatch(test,names=c('a','c','b')) #' @export vector.namesmatch<-function(v,names,errname=NULL){ if(is.null(errname)) errname <- deparse(substitute(v)) if (is.null(names(v))){ if(length(v) == length(names)){ names(v) <- names }else stop('Length of "', errname, '" is ', length(v), " but should be ", length(names),".") }else{ if(length(v) == length(names) && length(unique(names(v)))==length(v) && length(unique(names))==length(names) && all(sort(names(v)) == sort(names))){ namesmatch <- match(names, names(v)) v <- v[namesmatch] }else stop('Name mismatch in "', errname,'". Specify by position.') } v } #' "Compress" a data frame. #' #' \code{compress_rows.data.frame} "compresses" a data frame, returning unique rows #' and a tally of the number of times each row is repeated, as well as a #' permutation vector that can reconstruct the original data frame. #' \code{decompress_rows.compressed_rows_df} reconstructs the original data frame. #' #' #' @param x For \code{compress_rows.data.frame} a \code{\link{data.frame}} to be #' compressed. For \code{decompress_rows.compress_rows_df} a \code{\link{list}} as #' returned by \code{compress_rows.data.frame}. #' @param ... Additional arguments, currently unused. #' @return For \code{compress_rows.data.frame}, a \code{\link{list}} with three #' elements: \item{rows }{Unique rows of \code{x}} \item{frequencies }{A vector #' of the same length as the number or rows, giving the number of times the #' corresponding row is repeated } \item{ordering}{A vector such that if #' \code{c} is the compressed data frame, \code{c$rows[c$ordering,,drop=FALSE]} #' equals the original data frame, except for row names} \item{rownames}{Row #' names of \code{x}} #' #' For \code{decompress_rows.compressed_rows_df}, the original data frame. #' @seealso \code{\link{data.frame}} #' @keywords manip #' @examples #' #' (x <- data.frame(V1=sample.int(3,30,replace=TRUE), #' V2=sample.int(2,30,replace=TRUE), #' V3=sample.int(4,30,replace=TRUE))) #' #' (c <- compress_rows(x)) #' #' stopifnot(all(decompress_rows(c)==x)) #' #' @export compress_rows.data.frame<-function(x, ...){ r <- rownames(x) o <- order.data.frame(x) x <- x[o, , drop=FALSE] firsts<-which(!duplicated(x)) freqs<-diff(c(firsts,nrow(x)+1)) x<-x[firsts, , drop=FALSE] structure(x, frequencies=freqs, ordering=order(o), rownames=r, class=c("compressed_rows_df", class(x))) # Note that x[order(x)][order(order(x))]==x. } #' @rdname compress_rows.data.frame #' @export decompress_rows.compressed_rows_df<-function(x, ...){ r <- x rn <- attr(x, "rownames") f <- attr(x, "frequencies") o <- attr(x, "ordering") out <- r[rep.int(seq_along(f), f),, drop=FALSE][o,, drop=FALSE] rownames(out) <- rn out } #' @rdname sort.data.frame #' @export order <- function(..., na.last = TRUE, decreasing = FALSE) UseMethod("order") #' @rdname sort.data.frame #' @export order.default <- function(..., na.last = TRUE, decreasing = FALSE) base::order(..., na.last=na.last, decreasing=decreasing) #' @rdname sort.data.frame #' @export order.data.frame<-function(..., na.last = TRUE, decreasing=FALSE){ x <- list(...)[[1L]] do.call(base::order,c(unname(x), na.last=na.last, decreasing=decreasing)) } #' @rdname sort.data.frame #' @export order.matrix<-function(..., na.last = TRUE, decreasing=FALSE){ x <- list(...)[[1L]] do.call(base::order,c(lapply(seq_len(ncol(x)), function(i) x[,i]), na.last=na.last, decreasing=decreasing)) } #' Implement the \code{\link{sort}} and \code{\link{order}} methods for #' \code{\link{data.frame}} and \code{\link{matrix}}, sorting it in #' lexicographic order. #' #' These function return a data frame sorted in lexcographic order or a #' permutation that will rearrange it into lexicographic order: first by the #' first column, ties broken by the second, remaining ties by the third, etc.. #' #' #' @param x A \code{\link{data.frame}} to sort. #' @param \dots Ignored for \code{sort}. For \code{order}, first argument is #' the data frame to be ordered. (This is needed for compatibility with #' \code{\link[base]{order}}.) #' @param decreasing Whether to sort in decreasing order. #' @param na.last See \code{\link[base]{order}} documentation. #' @return For \code{sort}, a data frame, sorted lexicographically. For #' \code{order}, a permutation \code{I} (of a vector \code{1:nrow(x)}) such #' that \code{x[I,,drop=FALSE]} equals \code{x} ordered lexicographically. #' @seealso \code{\link{data.frame}}, \code{\link{sort}}, \code{\link{order}}, #' \code{\link{matrix}} #' @keywords manip #' @examples #' #' data(iris) #' #' head(iris) #' #' head(order(iris)) #' #' head(sort(iris)) #' #' stopifnot(identical(sort(iris),iris[order(iris),])) #' @export sort.data.frame<-function(x, decreasing=FALSE, ...){ x[order(x,decreasing=decreasing),,drop=FALSE] } #' Convenience functions for handling [`NULL`] objects. #' #' #' @param \dots,test expressions to be tested. #' #' @name NVL #' #' @note Whenever possible, these functions use lazy evaluation, so, #' for example `NVL(1, stop("Error!"))` will never evaluate the #' [`stop`] call and will not produce an error, whereas `NVL(NULL, stop("Error!"))` would. #' #' @seealso [`NULL`], \code{\link[base]{is.null}}, \code{\link[base]{if}} #' @keywords utilities #' NULL #' @describeIn NVL #' #' Inspired by SQL function \code{NVL}, returns the first argument #' that is not \code{NULL}, or \code{NULL} if all arguments are #' `NULL`. #' #' @examples #' a <- NULL #' #' a # NULL #' NVL(a,0) # 0 #' #' b <- 1 #' #' b # 1 #' NVL(b,0) # 1 #' #' # Here, object x does not exist, but since b is not NULL, x is #' # never evaluated, so the statement finishes. #' NVL(b,x) # 1 #' #' # Also, #' NVL(NULL,1,0) # 1 #' NVL(NULL,0,1) # 0 #' NVL(NULL,NULL,0) # 0 #' NVL(NULL,NULL,NULL) # NULL #' @export NVL <- function(...){ for(e in eval(substitute(alist(...)))){ # Lazy evaluate. (See http://adv-r.had.co.nz/Computing-on-the-language.html .) x <- eval(e, parent.frame()) if(!is.null(x)) break } x } #' @describeIn NVL #' #' Inspired by Oracle SQL function `NVL2`, returns the second argument #' if the first argument is not `NULL` and the third argument if the #' first argument is `NULL`. The third argument defaults to `NULL`, so #' `NVL2(a, b)` can serve as shorthand for `(if(!is.null(a)) b)`. #' #' @param notnull expression to be returned if `test` is not `NULL`. #' @param null expression to be returned if `test` is `NULL`. #' #' @examples #' #' NVL2(a, "not null!", "null!") # "null!" #' NVL2(b, "not null!", "null!") # "not null!" #' @export NVL2 <- function(test, notnull, null = NULL){ if(is.null(test)) null else notnull } #' @describeIn NVL #' #' Inspired by Oracle SQL `NVL2` function and `magittr` \code{\%>\%} #' operator, behaves as `NVL2` but `.`s in the second argument are #' substituted with the first argument. #' #' @examples #' #' NVL3(a, "not null!", "null!") # "null!" #' NVL3(b, .+1, "null!") # 2 #' @export NVL3 <- function(test, notnull, null = NULL){ if(is.null(test)) null else{ e <- substitute(notnull) eval(do.call(substitute, list(e, list(.=test))), parent.frame()) } } #' @describeIn NVL #' #' As `NVL`, but for any objects of length 0 (*E*mpty) rather than just `NULL`. Note that if no non-zero-length arguments are given, `NULL` is returned. #' #' @examples #' #' NVL(NULL*2, 1) # numeric(0) is not NULL #' EVL(NULL*2, 1) # 1 #' #' @export EVL <- function(...){ o <- NULL for(e in eval(substitute(alist(...)))){ # Lazy evaluate. (See http://adv-r.had.co.nz/Computing-on-the-language.html .) x <- eval(e, parent.frame()) if(length(x)){ o <- x; break } } o } #' @describeIn NVL #' #' As `NVL2`, but for any objects of length 0 (*E*mpty) rather than just `NULL`. #' #' @export EVL2 <- function(test, notnull, null = NULL){ if(length(test)) notnull else null } #' @describeIn NVL #' #' As `NVL3`, but for any objects of length 0 (*E*mpty) rather than just `NULL`. #' #' @export EVL3 <- function(test, notnull, null = NULL){ if(length(test)==0) null else{ e <- substitute(notnull) eval(do.call(substitute, list(e, list(.=test))), parent.frame()) } } #' @describeIn NVL #' #' Assigning to `NVL` overwrites its first argument if that argument #' is [`NULL`]. Note that it will *always* return the right-hand-side #' of the assignment (`value`), regardless of what `x` is. #' #' @param x an object to be overwritten if [`NULL`]. #' @param value new value for `x`. #' #' @examples #' #' NVL(a) <- 2 #' a # 2 #' NVL(b) <- 2 #' b # still 1 #' @export `NVL<-` <- function(x, value){ if(is.null(x)) value else x } #' @describeIn NVL #' #' As assignment to `NVL`, but for any objects of length 0 (*E*mpty) rather than just `NULL`. #' #' @export `EVL<-` <- function(x, value){ if(length(x)) x else value } #' Return the first argument passed (out of any number) that is not a #' \code{try-error} (result of \code{\link[base]{try}} encountering an error. #' #' This function is inspired by \code{\link{NVL}}, and simply returns the first #' argument that is not a \code{try-error}, raising an error if all arguments #' are \code{try-error}s. #' #' #' @param \dots Expressions to be tested; usually outputs of #' \code{\link[base]{try}}. #' @return The first argument that is not a \code{try-error}. Stops #' with an error if all are. #' @note This function uses lazy evaluation, so, for example `ERRVL(1, #' stop("Error!"))` will never evaluate the [`stop`] call and will #' not produce an error, whereas `ERRVL(try(solve(0)), #' stop("Error!"))` would. #' #' In addition, all expressions after the first may contain a `.`, #' which is substituted with the `try-error` object returned by the #' previous expression. #' #' @seealso \code{\link[base]{try}}, \code{\link[base]{inherits}} #' @keywords utilities #' @examples #' #' print(ERRVL(1,2,3)) # 1 #' print(ERRVL(try(solve(0)),2,3)) # 2 #' print(ERRVL(1, stop("Error!"))) # No error #' #' \dontrun{ #' # Error: #' print(ERRVL(try(solve(0), silent=TRUE), #' stop("Error!"))) #' #' # Error with an elaborate message: #' print(ERRVL(try(solve(0), silent=TRUE), #' stop("Stopped with an error: ", .))) #' } #' @export ERRVL <- function(...){ x <- NULL for(e in eval(substitute(alist(...)))){ # Lazy evaluate. (See http://adv-r.had.co.nz/Computing-on-the-language.html .) x <- eval(if(inherits(x, "try-error")) do.call(substitute, list(e, list(.=x))) else e, parent.frame()) if(!inherits(x, "try-error")) return(x) } stop("No non-error expressions passed.") } #' Optionally test code depending on environment variable. #' #' A convenience wrapper to run code based on whether an environment variable #' is defined. #' #' #' @param expr An expression to be evaluated only if \code{testvar} is set to a #' non-empty value. #' @param testname Optional name of the test. If given, and the test is #' skipped, will print a message to that end, including the name of the test, #' and instructions on how to enable it. #' @param testvar Environment variable name. If set to one of the #' \code{yesvals}, \code{expr} is run. Otherwise, an optional message is #' printed. #' @param yesvals A character vector of strings considered affirmative values #' for \code{testvar}. #' @param lowercase Whether to convert the value of \code{testvar} to lower #' case before comparing it to \code{yesvals}. #' @keywords utilities environment debugging #' @export opttest <- function(expr, testname=NULL, testvar="ENABLE_statnet_TESTS", yesvals=c("y","yes","t","true","1"), lowercase=TRUE){ testval <- Sys.getenv(testvar) if(lowercase) testval <- tolower(testval) if(testval %in% yesvals) eval.parent(expr) else if(!is.null(testname)) message(testname," test(s) skipped. Set ",testvar," environment variable to run.") } #' Test if all items in a vector or a list are identical. #' #' @param x a vector or a list #' #' @return `TRUE` if all elements of `x` are identical to each other. #' #' @seealso [`identical`] #' #' @examples #' #' stopifnot(!all_identical(1:3)) #' #' stopifnot(all_identical(list("a", "a", "a"))) #' @export all_identical <- function(x){ if(length(x)==0) return(TRUE) v0 <- x[[1L]] for(v in x[-1]) if(!identical(v0,v)) return(FALSE) return(TRUE) } #' Construct a logical vector with `TRUE` in specified positions. #' #' This function is basically an inverse of [`which`]. #' #' @param which a numeric vector of indices to set to `TRUE`. #' @param n total length of the output vector. #' #' @return A logical vector of length `n` whose elements listed in #' `which` are set to `TRUE`, and whose other elements are set to #' `FALSE`. #' #' @examples #' #' x <- as.logical(rbinom(10,1,0.5)) #' stopifnot(all(x == unwhich(which(x), 10))) #' @export unwhich <- function(which, n){ o <- logical(n) if(length(which)) o[which] <- TRUE o } #' Evaluate an \R expression with a hard time limit by forking a process #' #' This function uses #' #ifndef windows #' [parallel::mcparallel()], #' #endif #' #ifdef windows #' `parallel::mcparallel()`, #' #endif #' so the time limit is not #' enforced on Windows. However, unlike functions using [setTimeLimit()], the time #' limit is enforced even on native code. #' #' @param expr expression to be evaluated. #' @param timeout number of seconds to wait for the expression to #' evaluate. #' @param unsupported a character vector of length 1 specifying how to #' handle a platform that does not support #' #ifndef windows #' [parallel::mcparallel()], #' #endif #' #ifdef windows #' `parallel::mcparallel()`, #' #endif #' \describe{ #' #' \item{`"warning"` or `"message"`}{Issue a warning or a message, #' respectively, then evaluate the expression without the time limit #' enforced.} #' #' \item{`"error"`}{Stop with an error.} #' #' \item{`"silent"`}{Evaluate the expression without the time limit #' enforced, without any notice.} #' #' } Partial matching is used. #' @param onTimeout Value to be returned on time-out. #' #' @return Result of evaluating `expr` if completed, `onTimeout` #' otherwise. #' #' @note `onTimeout` can itself be an expression, so it is, for #' example, possible to stop with an error by passing #' `onTimeout=stop()`. #' #' @note Note that this function is not completely transparent: #' side-effects may behave in unexpected ways. In particular, RNG #' state will not be updated. #' #' @examples #' #' forkTimeout({Sys.sleep(1); TRUE}, 2) # TRUE #' forkTimeout({Sys.sleep(1); TRUE}, 0.5) # NULL (except on Windows) #' @export forkTimeout <- function(expr, timeout, unsupported = c("warning","error","message","silent"), onTimeout = NULL){ loadNamespace("parallel") loadNamespace("tools") env <- parent.frame() if(!exists("mcparallel", where=asNamespace("parallel"), mode="function")){ # fork() is not available on the system. unsupported <- match.arg(unsupported) warnmsg <- "Your platform (probably Windows) does not have fork() capabilities. Time limit will not be enforced." errmsg <- "Your platform (probably Windows) does not have fork() capabilities." switch(unsupported, message = message(warnmsg), warning = warning(warnmsg), error = stop(errmsg)) out <- eval(expr, env) }else{ # fork() is available on the system. child <- parallel::mcparallel(eval(expr, env), mc.interactive=NA) out <- parallel::mccollect(child, wait=FALSE, timeout=timeout) if(is.null(out)){ # Timed out with no result: kill. tools::pskill(child$pid) out <- onTimeout suppressWarnings(parallel::mccollect(child)) # Clean up. }else{ out <- out[[1L]] } } out } #' Extract or replace the *ult*imate (last) element of a vector or a list, or an element counting from the end. #' #' @param x a vector or a list. #' @param i index from the end of the list to extract or replace (where 1 is the last element, 2 is the penultimate element, etc.). #' #' @return An element of `x`. #' #' @examples #' x <- 1:5 #' (last <- ult(x)) #' (penultimate <- ult(x, 2)) # 2nd last. #' #' \dontshow{ #' stopifnot(last==5) #' stopifnot(penultimate==4) #' } #' #' @export ult <- function(x, i=1L){ x[[length(x)-i+1L]] } #' @rdname ult #' #' @param value Replacement value for the `i`th element from the end. #' #' @note Due to the way in which assigning to a function is #' implemented in R, `ult(x) <- e` may be less efficient than #' `x[[length(x)]] <- e`. #' #' @examples #' (ult(x) <- 6) #' (ult(x, 2) <- 7) # 2nd last. #' x #' #' \dontshow{ #' stopifnot(all(x == c(1:3, 7L, 6L))) #' } #' #' @export `ult<-` <- function(x, i=1L, value){ x[[length(x)-i+1L]] <- value x } #' Evaluate a function once for a given input. #' #' This is a `purrr`-style adverb that checks if a given function has #' already been called with a given configuration of arguments and #' skips it if it has. #' #' @param f A function to modify. #' @param expire_after The number of seconds since it was added to the #' database before a particular configuration is "forgotten". This #' can be used to periodically remind the user without overwhelming #' them. #' @param max_entries The number of distinct configurations to #' remember. If not `Inf`, *earliest-inserted* configurations will #' be removed from the database when capacity is exceeded. (This #' exact behavior may change in the future.) #' #' @details Each modified function instance returned by `once()` #' maintains a database of previous argument configurations. They #' are not in any way compressed, so this database may grow over #' time. Thus, this wrapper should be used with caution if arguments #' are large objects. This may be replaced with hashing in the #' future. In the meantime, you may want to set the `max_entries` #' argument to be safe. #' #' Different instances of a modified function do not share #' databases, even if the function is the same. This means that if #' you, say, modify a function within another function, the modified #' function will call once per call to the outer function. Modified #' functions defined at package level count as the same "instance", #' however. See example. #' #' @note Because the function needs to test whether a particular #' configuration of arguments have already been used, do not rely on #' lazy evaluation behaviour. #' #' @examples #' msg <- once(message) #' msg("abc") # Prints. #' msg("abc") # Silent. #' #' msg <- once(message) # Starts over. #' msg("abc") # Prints. #' #' f <- function(){ #' innermsg <- once(message) #' innermsg("efg") # Prints once per call to f(). #' innermsg("efg") # Silent. #' msg("abcd") # Prints only the first time f() is called. #' msg("abcd") # Silent. #' } #' f() # Prints "efg" and "abcd". #' f() # Prints only "efg". #' #' msg3 <- once(message, max_entries=3) #' msg3("a") # 1 remembered. #' msg3("a") # Silent. #' msg3("b") # 2 remembered. #' msg3("a") # Silent. #' msg3("c") # 3 remembered. #' msg3("a") # Silent. #' msg3("d") # "a" forgotten. #' msg3("a") # Printed. #' #' msg2s <- once(message, expire_after=2) #' msg2s("abc") # Prints. #' msg2s("abc") # Silent. #' Sys.sleep(1) #' msg2s("abc") # Silent after 1 sec. #' Sys.sleep(1.1) #' msg2s("abc") # Prints after 2.1 sec. #' #' @export once <- function(f, expire_after=Inf, max_entries=Inf){ local({ prev <- list() prev.time <- c() function(...){ # If using expire_after, expire old entries. if(is.finite(expire_after)){ expired <- Sys.time() - prev.time > expire_after prev <<- prev[!expired] prev.time <<- prev.time[!expired] } sig <- list(...) if(! list(sig)%in%prev){ prev <<- c(prev, list(sig)) prev.time <<- c(prev.time, Sys.time()) if(length(prev) > max_entries){ prev <<- prev[-1] prev.time <<- prev.time[-1] } f(...) } } }) } #' Evaluate an expression, restarting on error #' #' A pair of functions paralleling [eval()] and [evalq()] that make #' multiple attempts at evaluating an expression, retrying on error up #' to a specified number of attempts, and optionally evaluating #' another expression before restarting. #' #' @param expr an expression to be retried; note the difference #' between [eval()] and [evalq()]. #' @param retries number of retries to make; defaults to #' `"eval.retries"` option, or 5. #' @param beforeRetry if given, an expression that will be evaluated #' before each retry if the initial attempt fails; it is evaluated #' in the same environment and with the same quoting semantics as #' `expr`, but its errors are not handled. #' @param envir,enclos see [eval()]. #' @param verbose Whether to output retries. #' #' @note If `expr` returns a `"try-error"` object (returned by #' [try()]), it will be treated as an error. This behavior may #' change in the future. #' #' @return Results of evaluating `expr`, including side-effects such #' as variable assignments, if successful in `retries` retries. #' #' @examples #' x <- 0 #' persistEvalQ({if((x<-x+1)<3) stop("x < 3") else x}, #' beforeRetry = {cat("Will try incrementing...\n")}) #' #' x <- 0 #' e <- quote(if((x<-x+1)<3) stop("x < 3") else x) #' persistEval(e, #' beforeRetry = quote(cat("Will try incrementing...\n"))) #' @export persistEval <- function(expr, retries=NVL(getOption("eval.retries"), 5), beforeRetry, envir = parent.frame(), enclos = if (is.list(envir) || is.pairlist(envir)) parent.frame() else baseenv(), verbose=FALSE){ for(attempt in seq_len(retries)){ out <- try(eval(expr, envir=envir, enclos=enclos), silent=TRUE) #' @importFrom methods is if(!is(out, "try-error")) return(out) else{ if(!missing(beforeRetry)) eval(beforeRetry, envir=envir, enclos=enclos) if(verbose) message("Retrying: retry ", attempt, ".") } } out <- eval(expr, envir=envir, enclos=enclos) } #' @rdname persistEval #' @export persistEvalQ <- function(expr, retries=NVL(getOption("eval.retries"), 5), beforeRetry, envir = parent.frame(), enclos = if (is.list(envir) || is.pairlist(envir)) parent.frame() else baseenv(), verbose=FALSE){ expr <- substitute(expr) beforeRetry <- substitute(beforeRetry) envir <- force(envir) enclos <- force(enclos) persistEval(expr=expr, retries=retries, beforeRetry=beforeRetry, envir=envir, enclos=enclos, verbose=verbose) } #' Truncate values of high magnitude in a vector. #' #' @param x a numeric or integer vector. #' @param replace a number or a string `"maxint"` or `"intmax"`. #' #' @return Returns `x` with elements whose magnitudes exceed `replace` #' replaced replaced by `replace` (or its negation). If `replace` is #' `"maxint"` or `"intmax"`, `.Machine$integer.max` is used instead. #' #' `NA` and `NAN` values are preserved. #' #' @export deInf <- function(x, replace=1/.Machine$double.eps){ NVL(x) <- integer(0) if(tolower(replace) %in% c("maxint","intmax")) replace <- .Machine$integer.max ifelse(is.nan(x) | abs(x) length(d)) stop(sQuote("margin"), " must be between 1 and the dimensionality of ", sQuote("x"), ".") args <- c(list(x), rep(TRUE, length(d)), list(drop=FALSE)) ind_call <- function(ind){ args[[margin+1L]] <- ind do.call(`[`, args) } lapply(split(x = seq_len(dim(x)[margin]), f = f, drop = drop, ...), ind_call) } #' @rdname split.array #' @export split.matrix <- split.array #' Convert a list to an atomic vector if it consists solely of atomic elements of length 1. #' #' This behaviour is not dissimilar to that of [simplify2array()], but #' it offers more robust handling of empty or NULL elements and never #' promotes to a matrix or an array, making it suitable to be a column #' of a [`data.frame`]. #' #' @param x an R [`list`] to be simplified. #' @param toNA a character string indicating whether `NULL` entries #' (if `"null"`) or 0-length entries including `NULL` (if `"empty"`) #' should be replaced with `NA`s before attempting conversion; #' specifying `keep` or `FALSE` leaves them alone (typically #' preventing conversion). #' @param empty a character string indicating how empty lists should #' be handled: either `"keep"`, in which case they are unchanged or #' `"unlist"`, in which cases they are unlisted (typically to #' `NULL`). #' @param ... additional arguments passed to [unlist()]. #' #' @return an atomic vector or a list of the same length as `x`. #' @examples #' #' (x <- as.list(1:5)) #' stopifnot(identical(simplify_simple(x), 1:5)) #' #' x[3] <- list(NULL) # Put a NULL in place of 3. #' x #' stopifnot(identical(simplify_simple(x, FALSE), x)) # Can't be simplified without replacing the NULL. #' #' stopifnot(identical(simplify_simple(x), c(1L,2L,NA,4L,5L))) # NULL replaced by NA and simplified. #' #' x[[3]] <- integer(0) #' x #' stopifnot(identical(simplify_simple(x), x)) # A 0-length vector is not replaced by default, #' stopifnot(identical(simplify_simple(x, "empty"), c(1L,2L,NA,4L,5L))) # but can be. #' #' (x <- lapply(1:5, function(i) c(i,i+1L))) # Elements are vectors of equal length. #' simplify2array(x) # simplify2array() creates a matrix, #' stopifnot(identical(simplify_simple(x), x)) # but simplify_simple() returns a list. #' #' @export simplify_simple <- function(x, toNA = c("null","empty","keep"), empty = c("keep", "unlist"), ...){ if(isFALSE(toNA)) toNA <- "keep" toNA <- match.arg(toNA) empty <- match.arg(empty) if(is.atomic(x)) return(x) x <- switch(toNA, keep = x, null = lapply(x, NVL, NA), empty = lapply(x, EVL, NA)) if(length(x)==0) switch(empty, keep=x, unlist=unlist(x, recursive=FALSE, ...)) else if(all(lengths(x)==1L) && all(vapply(x, is.atomic, logical(1)))) unlist(x, recursive=FALSE, ...) else x } #' A wrapper for base::attr which defaults to exact matching. #' #' @param x,which,exact as in \code{base::attr}, but with \code{exact} #' defaulting to \code{TRUE} in this implementation #' #' @return as in \code{base::attr} #' @examples #' #' x <- list() #' attr(x, "name") <- 10 #' #' base::attr(x, "n") #' #' stopifnot(is.null(attr(x, "n"))) #' #' base::attr(x, "n", exact = TRUE) #' @export attr <- function(x, which, exact = TRUE) { base::attr(x, which, exact) } #' An error handler for [rlang::check_dots_used()] that issues a #' warning that only lists argument names. #' #' This handler parses the error message produced by #' [rlang::check_dots_used()], extracting the names of the unused #' arguments, and formats them into a more gentle warning message. It #' relies on \CRANpkg{rlang} maintaining its current format. #' #' @param e a [condition][condition] object, typically not passed by #' the end-user; see example below. #' #' @examples #' #' \dontshow{ #' o <- options(warn=1, useFancyQuotes=FALSE) #' } #' #' g <- function(b=NULL, ...){ #' invisible(force(b)) #' } #' #' f <- function(...){ #' rlang::check_dots_used(error = unused_dots_warning) #' g(...) #' } #' #' f() # OK #' f(b=2) # OK #' f(a=1, b=2, c=3) # Warning about a and c but not about b #' #' \dontshow{ #' # Test: #' stopifnot(grepl("Argument(s) 'a' and 'c' were not recognized or used. Did you mistype an argument name?", tryCatch(f(a=1, b=2, c=3), warning = function(e) e$message), fixed=TRUE)) #' options(o) #' } #' @export unused_dots_warning <- function(e){ v <- lapply(parse(text = e$body[names(e$body)=="*"]), `[[`, 2) rlang::warn(sprintf("Argument(s) %s were not recognized or used. Did you mistype an argument name?", paste.and(sQuote(v)))) } statnet.common/R/wmatrix.R0000644000176200001440000002251114364112224015242 0ustar liggesusers# File R/wmatrix.R in package statnet.common, part of the # Statnet suite of packages for network analysis, https://statnet.org . # # This software is distributed under the GPL-3 license. It is free, # open source, and has the attribution requirements (GPL Section 7) at # https://statnet.org/attribution . # # Copyright 2007-2023 Statnet Commons ################################################################################ #' A data matrix with row weights #' #' A representation of a numeric matrix with row weights, represented #' on either linear (`linwmatrix`) or logarithmic (`logwmatrix`) #' scale. #' #' @param x an object to be coerced or tested. #' @param data,nrow,ncol,byrow,dimnames passed to [`matrix`]. #' @param w row weights on the appropriate scale. #' @param target.nrows see [`decompress_rows`]. #' @param i,j,value rows and columns and values for extraction or #' replacement; as [`matrix`]. #' @param drop Used for consistency with the generic. Ignored, and #' always treated as `FALSE`. #' @param ... extra arguments, currently unused. #' #' @note Note that `wmatrix` itself is an "abstract" class: you cannot #' instantiate it. #' #' @note Note that at this time, `wmatrix` is designed as, first and #' foremost, as class for storing compressed data matrices, so most #' methods that operate on matrices may not handle the weights #' correctly and may even cause them to be lost. #' #' @return An object of class `linwmatrix`/`logwmatrix` and `wmatrix`, #' which is a [`matrix`] but also has an attribute `w` containing #' row weights on the linear or the natural-log-transformed scale. #' #' @seealso [`rowweights`], [`lrowweights`], [`compress_rows`] #' #' @name wmatrix #' #' @examples #' (m <- matrix(1:3, 2, 3, byrow=TRUE)) #' (m <- rbind(m, 3*m, 2*m, m)) #' (mlog <- as.logwmatrix(m)) #' (mlin <- as.linwmatrix(m)) #' (cmlog <- compress_rows(mlog)) #' (cmlin <- compress_rows(mlin)) #' #' stopifnot(all.equal(as.linwmatrix(cmlog),cmlin)) #' #' cmlog[2,] <- 1:3 #' (cmlog <- compress_rows(cmlog)) #' stopifnot(sum(rowweights(cmlog))==nrow(m)) #' #' (m3 <- matrix(c(1:3,(1:3)*2,(1:3)*3), 3, 3, byrow=TRUE)) #' (rowweights(m3) <- c(4, 2, 2)) #' #' stopifnot(all.equal(compress_rows(as.logwmatrix(m)), as.logwmatrix(m3),check.attributes=FALSE)) #' stopifnot(all.equal(rowweights(compress_rows(as.logwmatrix(m))), #' rowweights(as.logwmatrix(m3)),check.attributes=FALSE)) NULL #' @rdname wmatrix #' @export logwmatrix <- function(data = NA, nrow = 1, ncol = 1, byrow = FALSE, dimnames = NULL, w = NULL){ x <- matrix(data, nrow, ncol, byrow, dimnames) as.logwmatrix(x, w) } #' @rdname wmatrix #' @export linwmatrix <- function(data = NA, nrow = 1, ncol = 1, byrow = FALSE, dimnames = NULL, w = NULL){ x <- matrix(data, nrow, ncol, byrow, dimnames) as.linwmatrix(x, w) } #' @rdname wmatrix #' @export is.wmatrix <- function(x) inherits(x, "wmatrix") #' @rdname wmatrix #' @export is.logwmatrix <- function(x) inherits(x, "logwmatrix") #' @rdname wmatrix #' @export is.linwmatrix <- function(x) inherits(x, "linwmatrix") #' @rdname wmatrix #' @export as.linwmatrix <- function(x, ...) UseMethod("as.linwmatrix") #' @rdname wmatrix #' @export as.logwmatrix <- function(x, ...) UseMethod("as.logwmatrix") #' @rdname wmatrix #' @export as.linwmatrix.linwmatrix <- function(x, ...) x #' @rdname wmatrix #' @export as.linwmatrix.logwmatrix <- function(x, ...){ attr(x, "w") <- exp(attr(x, "w")) class(x)[class(x)=="logwmatrix"] <- "linwmatrix" x } #' @rdname wmatrix #' @export as.logwmatrix.logwmatrix <- function(x, ...) x #' @rdname wmatrix #' @export as.logwmatrix.linwmatrix <- function(x, ...){ attr(x, "w") <- log(attr(x, "w")) class(x)[class(x)=="linwmatrix"] <- "logwmatrix" x } #' @rdname wmatrix #' @export as.linwmatrix.matrix <- function(x, w=NULL, ...){ attr(x, "w") <- NVL(w, rep(1, nrow(x))) class(x) <- c("linwmatrix", "wmatrix", class(x)) x } #' @rdname wmatrix #' @export as.logwmatrix.matrix <- function(x, w=NULL, ...){ attr(x, "w") <- NVL(w, rep(0, nrow(x))) class(x) <- c("logwmatrix", "wmatrix", class(x)) x } #' @rdname wmatrix #' @export print.wmatrix <- function(x, ...){ x <- cbind(unclass(x), Weight = attr(x, "w")) print(x, ...) } #' @rdname wmatrix #' @export print.logwmatrix <- function(x, ...){ cat("A row-weighted matrix with natural-log-scaled weights:\n") NextMethod("print") } #' @rdname wmatrix #' @export print.linwmatrix <- function(x, ...){ cat("A row-weighted matrix with linear-scaled weights:\n") NextMethod("print") } #' Set or extract weighted matrix row weights #' #' @param x a [`linwmatrix`], a [`logwmatrix`], or a [`matrix`]; a #' [`matrix`] is coerced to a weighted matrix of an appropriate #' type. #' @param value weights to set, on the appropriate scale. #' @param update if `TRUE` (the default), the old weights are updated #' with the new weights (i.e., corresponding weights are multiplied #' on linear scale or added on on log scale); otherwise, they are #' overwritten. #' @param ... extra arguments for methods. #' #' @return For the accessor functions, the row weights or the row #' log-weights; otherwise, a weighted matrix with modified #' weights. The type of weight (linear or logarithmic) is converted #' to the required type and the type of weighting of the matrix is #' preserved. #' #' @name wmatrix_weights NULL #' @rdname wmatrix_weights #' @export rowweights <- function(x, ...) UseMethod("rowweights") #' @rdname wmatrix_weights #' @export rowweights.linwmatrix <- function(x, ...) attr(x, "w") #' @rdname wmatrix_weights #' @export rowweights.logwmatrix <- function(x, ...) exp(attr(x, "w")) #' @rdname wmatrix_weights #' @export lrowweights <- function(x, ...) UseMethod("lrowweights") #' @rdname wmatrix_weights #' @export lrowweights.logwmatrix <- function(x, ...) attr(x, "w") #' @rdname wmatrix_weights #' @export lrowweights.linwmatrix <- function(x, ...) log(attr(x, "w")) #' @rdname wmatrix_weights #' @export `rowweights<-` <- function(x, ..., value) UseMethod("rowweights<-") #' @rdname wmatrix_weights #' @export `rowweights<-.linwmatrix` <- function(x, update=TRUE, ..., value){ attr(x, "w") <- value * if(update) attr(x, "w") else 1 x } #' @rdname wmatrix_weights #' @export `rowweights<-.logwmatrix` <- function(x, update=TRUE,..., value){ attr(x, "w") <- log(value) + if(update) log(attr(x, "w")) else 0 x } #' @rdname wmatrix_weights #' @export `lrowweights<-` <- function(x, ..., value) UseMethod("lrowweights<-") #' @rdname wmatrix_weights #' @export `lrowweights<-.linwmatrix` <- function(x, update=TRUE, ..., value){ attr(x, "w") <- exp(value + if(update) log(attr(x, "w")) else 0) x } #' @rdname wmatrix_weights #' @export `lrowweights<-.logwmatrix` <- function(x, update=TRUE,..., value){ attr(x, "w") <- value + if(update) attr(x, "w") else 0 x } #' @rdname wmatrix_weights #' @export `rowweights<-.matrix` <- function(x, ..., value){ attr(x, "w") <- value class(x) <- c("linwmatrix", "wmatrix", class(x)) x } #' @rdname wmatrix_weights #' @export `lrowweights<-.matrix` <- function(x, ..., value){ attr(x, "w") <- value class(x) <- c("logwmatrix", "wmatrix", class(x)) x } #' A generic function to compress a row-weighted table #' #' Compress a matrix or a data frame with duplicated rows, updating row weights #' to reflect frequencies, or reverse the process, reconstructing a matrix like #' the one compressed (subject to permutation of rows and weights not adding up #' to an integer). #' #' @param x a weighted matrix or data frame. #' @param ... extra arguments for methods. #' @return For \code{compress_rows} A weighted matrix or data frame of the same #' type with duplicated rows removed and weights updated appropriately. #' @export compress_rows <- function(x, ...) UseMethod("compress_rows") #' @rdname wmatrix #' @export compress_rows.logwmatrix <- function(x, ...){ o <- order.matrix(x) x <- x[o, , drop=FALSE] firsts <- !duplicated(x) groups <- cumsum(firsts) cx <- x[firsts, , drop=FALSE] attr(cx, "w") <- c(tapply(attr(x, "w"), list(groups), log_sum_exp), use.names=FALSE) cx } #' @rdname wmatrix #' @export compress_rows.linwmatrix <- function(x, ...){ o <- order.matrix(x) x <- x[o, , drop=FALSE] firsts <- !duplicated(x) groups <- cumsum(firsts) cx<-x[firsts, , drop=FALSE] attr(cx, "w") <- c(tapply(attr(x, "w"), list(groups), sum), use.names=FALSE) cx } #' @rdname compress_rows #' @export decompress_rows <- function(x, ...) UseMethod("decompress_rows") #' @rdname wmatrix #' @param target.nrows the approximate number of rows the uncompressed matrix #' should have; if not achievable exactly while respecting proportionality, a #' matrix with a slightly different number of rows will be constructed. #' @export decompress_rows.wmatrix <- function(x, target.nrows=NULL, ...){ w <- rowweights(x) if(is.null(target.nrows)) target.nrows <- sum(w) n <- round(w/sum(w)*target.nrows) # Number of replications of each row rowweights(x) <- 1/n x[rep(seq_along(n), n),] } #' @rdname wmatrix #' @export `[.wmatrix` <- function(x, i, j, ..., drop=FALSE){ if(drop) warning("Row-weighted matrices cannot drop dimensions.") o <- unclass(x)[i,j,...,drop=FALSE] attr(o, "w") <- attr(x, "w")[i] class(o) <- class(x) o } #' @rdname wmatrix #' @export `[<-.wmatrix` <- function(x, i, j, ..., value){ o <- unclass(x) o[i,j,...] <- value attr(o, "w") <- attr(x, "w") class(o) <- class(x) o } statnet.common/R/control.utilities.R0000644000176200001440000005303014427313311017241 0ustar liggesusers# File R/control.utilities.R in package statnet.common, part of the # Statnet suite of packages for network analysis, https://statnet.org . # # This software is distributed under the GPL-3 license. It is free, # open source, and has the attribution requirements (GPL Section 7) at # https://statnet.org/attribution . # # Copyright 2007-2023 Statnet Commons ################################################################################ .autodetect_dep_warn <- local({ warned <- c() function(caller = as.character(ult(sys.calls(),3)[[1L]])){ if(!caller %in% warned) warning("In ",sQuote(caller),": Autodetection of acceptable control parameter generators and of the calling function name has been deprecated and will be removed in a future version. They must be set explicitly.", call.=FALSE) warned <<- c(warned, caller) } }) #' Ensure that the class of the control list is one of those that can #' be used by the calling function #' #' This function converts an ordinary `list` into a control list (if #' needed) and checks that the control list passed is appropriate for #' the function to be controlled. #' #' @param OKnames List of control function names which are acceptable. #' @param myname Name of the calling function (used in the error #' message). #' @param control The control list or a list to be converted to a #' control list using `control.myname()`. Defaults to the #' \code{control} variable in the calling function. See Details for #' detailed behavior. #' #' @note In earlier versions, `OKnames` and `myname` were #' autodetected. This capability has been deprecated and results in #' a warning issued once per session. They now need to be set #' explicitly. #' #' @details `check.control.class()` performs the check by looking up #' the class of the `control` argument (defaulting to the `control` #' variable in the calling function) and checking if it matches a #' list of acceptable given by `OKnames`. #' #' Before performing any checks, the `control` argument (including #' the default) will be converted to a control list by calling #' [as.control.list()] on it with the first element of `OKnames` to #' construct the control function. #' #' If `control` is missing, it will be assumed that the user wants #' to modify it in place, and a variable with that name in the #' parent environment will be overwritten. #' #' @return A valid control list for the function in which it is to be #' used. If `control` argument is missing, it will also overwrite #' the variable `control` in the calling environment with it. #' #' @seealso [set.control.class()], [print.control.list()], [as.control.list()] #' @keywords utilities #' @export check.control.class <- function(OKnames=as.character(ult(sys.calls(),2)[[1L]]), myname=as.character(ult(sys.calls(),2)[[1L]]), control=get("control",pos=parent.frame())){ overwrite_control <- missing(control) control <- as.control.list(control, OKnames[1]) if(missing(OKnames) || missing(myname)) .autodetect_dep_warn() funs <- paste("control", OKnames, sep=".") # Control missing: overwrite default name in parent. if(overwrite_control) assign("control", control, pos=parent.frame()) if(inherits(control, funs[1L])) return(control) for(fun in funs[-1]) # If there is only one, that's a null vector, so it just terminates. if(inherits(control, fun)){ warning("Using ", fun,"(...) as the control parameter of ",myname,"(...) is suboptimal and may overwrite some settings that should be preserved. Use ",funs[1L],"(...) instead.") return(control) } stop("Invalid control parameters for ",myname,"(...): ",class(control)[1L],"(...). Use ",funs[1L],"(...) to construct them instead.", call.=FALSE) } #' Set the class of the control list #' #' This function sets the class of the control list, with the default being the #' name of the calling function. #' #' #' @param myname Name of the class to set. #' @param control Control list. Defaults to the \code{control} variable in the #' calling function. #' @return The control list with class set. #' @note In earlier versions, `OKnames` and `myname` were autodetected. This capability has been deprecated and results in a warning issued once per session. They now need to be set explicitly. #' @seealso [check.control.class()], [print.control.list()] #' @keywords utilities #' @export set.control.class <- function(myname=as.character(ult(sys.calls(),2)[[1L]]), control=get("control",pos=parent.frame())){ if(missing(myname)) .autodetect_dep_warn() class(control) <- c(myname, "control.list", "list") control } #' Handle standard `control.*()` function semantics. #' #' This function takes the arguments of its caller (whose name should #' be passed explicitly), plus any `...` arguments and produces a #' control list based on the standard semantics of `control.*()` #' functions, including handling deprecated arguments, identifying #' undefined arguments, and handling arguments that should be passed #' through [match.arg()]. #' #' @param myname the name of the calling function. #' @param ... the `...` argument of the control function, if present. #' #' @details The function behaves based on the information it acquires from the calling function. Specifically, #' #' * The values of formal arguments (except `...`, if present) are #' taken from the environment of the calling function and stored in #' the list. #' #' * If the calling function has a `...` argument *and* defines an #' `old.controls` variable in its environment, then it remaps the #' names in `...` to their new names based on `old.controls`. In #' addition, if the value is a list with two elements, `action` and #' `message`, the standard deprecation message will have `message` #' appended to it and then be called with `action()`. #' #' * If the calling function has a `match.arg.pars` in its #' environment, the arguments in that list are processed through #' [match.arg()]. #' #' @return a list with formal arguments of the calling function. #' @export handle.controls <- function(myname, ...){ formal.args <- formals(sys.function(-1)) if(has.dots <- "..." %in% names(formal.args)) formal.args[["..."]] <- NULL control <- list() for(arg in names(formal.args)) control[arg] <- list(get(arg, parent.frame())) if(has.dots){ old.controls <- if(exists("old.controls", parent.frame())) get("old.controls", parent.frame()) else list() for(arg in names(list(...))){ if(is.null(newarg <- old.controls[[arg]])){ stop("Unrecognized control parameter for ", sQuote(paste0(myname, "()")), ": ", sQuote(arg), ".", call.=FALSE) }else if(is.list(newarg)){ newarg$action("Control parameter ",sQuote(paste0(arg,"=..."))," to ", sQuote(paste0(myname, "()")), " is no longer used.", newarg$message, call.=FALSE) }else{ warning("Passing ",sQuote(paste0(arg,"=..."))," to ", sQuote(paste0(myname, "()")), " is deprecated and may be removed in a future version. Specify it as ", sQuote(paste0(myname, "(", old.controls[[arg]], "=...)")), " instead.", call.=FALSE) control[old.controls[[arg]]]<-list(list(...)[[arg]]) } } } if(exists("match.arg.pars", parent.frame())) for(arg in get("match.arg.pars", parent.frame())) control[arg] <- list(match.arg(control[[arg]][1], eval(formal.args[[arg]], parent.frame()))) control } #' Pretty print the control list #' #' This function prints the control list, including what it can control and the #' elements. #' #' #' @param x A list generated by a \code{control.*} function. #' @param \dots Additional argument to print methods for individual settings. #' @param indent an argument for recursive calls, to facilitate indentation of nested lists. #' @seealso \code{\link{check.control.class}}, \code{\link{set.control.class}} #' @keywords utilities #' @export print.control.list <- function(x, ..., indent=""){ cat("Control parameter list generated by", sQuote(class(x)[1L]), "or equivalent. Non-empty parameters:\n") for(name in names(x)){ if(length(x[[name]])){ cat(indent, name,": ",sep="") if(is.list(x[[name]])) {print(x[[name]], ..., indent=paste0(indent," "))} else cat(paste(deparse(x[[name]]), collapse=" "),"\n", sep="") } } } #' Named element accessor for ergm control lists #' #' Utility method that overrides the standard `$' list accessor to disable #' partial matching for ergm \code{control.list} objects #' #' Executes \code{\link[base]{getElement}} instead of \code{\link[base]{$}} so #' that element names must match exactly to be returned and partially matching #' names will not return the wrong object. #' #' @param object list-coearceable object with elements to be searched #' @param name literal character name of list element to search for and return #' @return Returns the named list element exactly matching \code{name}, or #' \code{NULL} if no matching elements found #' @author Pavel N. Krivitsky #' @seealso see \code{\link{getElement}} #' @name control.list.accessor #' @export `$.control.list` <- function(object, name) object[[name, exact = TRUE]] #' Overwrite control parameters of one configuration with another. #' #' Given a \code{control.list}, and two prefixes, \code{from} and \code{to}, #' overwrite the elements starting with \code{to} with the corresponding #' elements starting with \code{from}. #' #' #' @param control An object of class \code{control.list}. #' @param from Prefix of the source of control parameters. #' @param to Prefix of the destination of control parameters. #' @return An \code{control.list} object. #' @author Pavel N. Krivitsky #' @seealso \code{\link{print.control.list}} #' @keywords utilities #' @examples #' #' (l <- set.control.class("test", list(a.x=1, a.y=2))) #' control.remap(l, "a", "b") #' #' @export control.remap <- function(control, from, to){ from <- paste0("^",from,"\\.") to <- paste0(to,"\\.") nfrom <- grep(from, names(control), value=TRUE) nto <- sub(from, to, nfrom) for(i in seq_along(nfrom)) control[[nto[i]]] <- control[[nfrom[i]]] control } #' Identify and the differences between two control lists. #' @param x a `control.list` #' @param y a reference `control.list`; defaults to the default #' settings for `x`. #' @param ignore.environment whether environment for #' environment-bearing parameters (such as formulas and functions) #' should be considered when comparing. #' @param ... Additional arguments to methods. #' #' @return An object of class `diff.control.list`: a named list with #' an element for each non-identical setting. The element is either #' itself a `diff.control.list` (if the setting is a control list) #' or a named list with elements `x` and `y`, containing `x`'s and #' `y`'s values of the parameter for that setting. #' @export diff.control.list <- function(x, y=eval(call(class(x)[[1L]])), ignore.environment=TRUE, ...){ d <- list() for(name in union(names(x),names(y))){ d[[name]] <- if(is(x[[name]], "control.list") && is(y[[name]], "control.list")) EVL(diff(x[[name]], y[[name]])) else if(!identical(x[[name]],y[[name]],ignore.environment=ignore.environment)) list(x=x[[name]], y=y[[name]]) } structure(d, class=c("diff.control.list", "list"), xclass=c(class(x)[1L])) } #' @describeIn diff.control.list A print method. #' @param indent an argument for recursive calls, to facilitate #' indentation of nested lists. #' @export print.diff.control.list <- function(x, ..., indent = ""){ if(length(x)==0) cat("No difference between parameter lists generated by", sQuote(attr(x,"xclass")), "or equivalent.\n") else{ cat("Difference between parameter lists generated by", sQuote(attr(x,"xclass")), "or equivalent. Differences:\n") for(name in names(x)){ if(length(x[[name]])){ cat(indent, name,": ",sep="") if(is(x[[name]],"diff.control.list")) print(x[[name]], ..., indent=paste0(indent," ")) else if(is.list(x[[name]]$x)){ print(x[[name]]$x, ..., indent=paste0(indent," ")) cat("versus") print(x[[name]]$y, ..., indent=paste0(indent," ")) }else{ cat(paste(deparse(x[[name]]$x), collapse=" "), " versus ", paste(deparse(x[[name]]$y), collapse=" "), "\n", sep="") } } } } } #' Convert to a control list. #' #' @param x An object, usually a [`list`], to be converted to a #' control list. #' @param ... Additional arguments to methods. #' @return a `control.list` object. #' #' @examples #' myfun <- function(..., control=control.myfun()){ #' as.control.list(control) #' } #' control.myfun <- function(a=1, b=a+1){ #' list(a=a,b=b) #' } #' #' myfun() #' myfun(control = list(a=2)) #' @export as.control.list <- function(x, ...) UseMethod("as.control.list") #' @describeIn as.control.list Idempotent method for control lists. #' @export as.control.list.control.list <- function(x, ...) x #' @describeIn as.control.list The method for plain lists, which runs #' them through `FUN`. #' @param FUN Either a `control.*()` function or its name or suffix #' (to which `"control."` will be prepended); defaults to taking the #' nearest (in the call traceback) function that does not begin with #' `"as.control.list"`, and prepending `"control."` to it. (This is #' typically the function that called `as.control.list()` in the #' first place.) #' @param unflat Logical, indicating whether an attempt should be made #' to detect whether some of the arguments are appropriate for a #' lower-level control function and pass them down. #' @examples #' myfun2 <- function(..., control=control.myfun2()){ #' as.control.list(control) #' } #' control.myfun2 <- function(c=3, d=c+2, myfun=control.myfun()){ #' list(c=c,d=d,myfun=myfun) #' } #' #' myfun2() #' # Argument to control.myfun() (i.e., a) gets passed to it, and a #' # warning is issued for unused argument e. #' myfun2(control = list(c=3, a=2, e=3)) #' @export as.control.list.list <- function(x, FUN=NULL, unflat=TRUE, ...){ if(is.null(FUN)){ FUN <- ult( Filter(function(x) !startsWith(x, "as.control.list"), vapply( lapply(sys.calls(), # Obtain the traceback. `[[`, 1L), # Extract the function names as names. as.character, character(1)) # Convert to character vectors. ) # Drop those that begin with "as.control.list". ) # Take the last one. } if(is.character(FUN) && !startsWith(FUN, "control.")) FUN <- paste0("control.", FUN) FUN <- match.fun(FUN) if(unflat){ xnames_unused <- names(x) unflat <- function(f){ args <- formals(f) anames <- setdiff(names(args), "...") l <- list() for(aname in names(args)) if(aname %in% names(x)){ # Present in the input list: copy. l[aname] <- list(x[[aname]]) xnames_unused <<- setdiff(xnames_unused, aname) }else if(is.call(aval <- args[[aname]]) && startsWith(as.character(aval[[1]]), "control.")){ # A control list not supplied directly: process recursively. l[aname] <- list(unflat(get(as.character(aval[[1]]), pos=environment(f), mode="function"))) } # Otherwise, leave blank. l } x <- unflat(FUN) if(length(xnames_unused)) warning("Control arguments ", paste.and(sQuote(xnames_unused)), " not used in any of the control functions.", call.=FALSE, immediate.=TRUE) } do.call(FUN, x, envir=parent.frame()) } #' Statnet Control #' #' A utility to facilitate argument completion of control lists. #' #' In and of itself, `snctrl` copies its named arguments into a #' list. However, its argument list is updated dynamically as packages #' are loaded, as are those of its reexports from other packages. This #' is done using an API provided by helper functions. (See `API?snctrl`.) #' #' @param ... The parameter list is updated dynamically as packages #' are loaded and unloaded. Their current list is given below. #' #' @section Currently recognised control parameters: #' This list is updated as packages are loaded and unloaded. #' #' \Sexpr[results=rd,stage=render]{statnet.common::snctrl_names()} #' #' @note You may see messages along the lines of #' ``` #' The following object is masked from 'package:PKG': #' snctrl #' ``` #' when loading packages. They are benign. #' #' @export snctrl <- function(...){ control <- list(...) # NB: The results of snctrl() will eventually get passed to # as.control.list.list(), which will check for misspelled names, so # we don't need to do that here. if(any(names(control)=="")) stop("All arguments to ",sQuote("snctrl")," must be named.", call.=FALSE) formal.args<-formals(sys.function()) formal.args[["..."]] <- NULL for(arg in names(formal.args)){ if(arg=="") stop("All arguments to ",sQuote("snctrl")," must be named.", call.=FALSE) if(!do.call(missing, list(arg))) control[arg] <- list(get(arg)) } control } #' @describeIn snctrl-API Typeset the currently defined list of #' argument names by package and control function. #' #' @export snctrl_names <- function(){ a <- argnames() pkgs <- sapply(names(a), function(pkg){ funs <- lapply(names(a[[pkg]]), function(ctrl){ ctrll <- nchar(ctrl) args <- names(a[[pkg]][[ctrl]]) paste0("\\item{\\code{\\link[",pkg,":",ctrl,"]{",ctrl,"}}}{\\code{", paste0(strwrap(paste0(args,collapse=", "),simplify=TRUE,exdent=ctrll+1),collapse="\n"), "}}") }) paste0("\\subsection{Package \\pkg{",pkg,"}}{\\describe{", paste0(funs,collapse="\n"),"}}") }) paste0(pkgs,collapse="\n") } argnames <- local({ cache <- list() delpkg <- function(pkgname,pkgpath){ cache[[pkgname]] <<- NULL update_snctrl() } function(pkg, arglists){ if(missing(pkg)) cache else{ cache[[pkg]] <<- arglists setHook(packageEvent(pkg, "onUnload"), delpkg) } } }) callbacks <- local({ cache <- list() delpkg <- function(pkgname,pkgpath){ cache[[pkgname]] <<- NULL } function(pkg, callback){ if(missing(pkg)) cache else{ cache[[pkg]] <<- callback setHook(packageEvent(pkg, "onUnload"), delpkg) } } }) #' @name snctrl-API #' @title Helper functions used by packages to facilitate [`snctrl`] updating. #' NULL #' @describeIn snctrl-API Typically called from [.onLoad()], Update the #' argument list of [snctrl()] to include additional argument names #' associated with the package, and set a callback for the package #' to update its own copy. #' #' @param myname Name of the package defining the arguments. #' @param arglists A named list of argument name-default pairs. If the #' list is not named, it is first passed through #' [collate_controls()]. #' @param callback A function with no arguments that updates the #' packages own copy of [snctrl()]. #' #' @return `update_snctrl()` has no return value and is used for its side-effects. #' @export update_snctrl <- function(myname, arglists=NULL, callback=NULL){ if(length(arglists) && all(names(arglists)=="")) arglists <- do.call(collate_controls, arglists) # Make a copy and replace the arglist. tmp <- snctrl if(!missing(myname)){ argnames(myname, arglists) if(!is.null(callback)) callbacks(myname, callback) } arglists <- c(argnames(),list(list(formals(tmp)[1]))) arglist <- unlist(unlist(lapply(unname(arglists), unname), recursive=FALSE), recursive=FALSE) argnames <- sort(unique(names(arglist))) arglist <- structure(rep(list(substitute()), length(argnames)), # For now, leave all default arguments blank. names = argnames) formals(tmp) <- arglist # Replace the original function with the copy. unlockBinding("snctrl", environment(snctrl)) snctrl <<- tmp lockBinding("snctrl", environment(snctrl)) for(callback in callbacks()) callback() invisible() } #' @describeIn snctrl-API Obtain and concatenate the argument lists of #' specified functions or all functions starting with dQuote(`control.`) in #' the environment. #' #' @param x Either a function, a list of functions, or an #' environment. If `x` is an environment, all functions starting #' with dQuote(`control.`) are obtained. #' @param ... Additional functions or lists of functions. #' #' @return `collate_controls()` returns the combined list of name-default pairs of each function. #' @export collate_controls <- function(x=NULL, ...){ l <- if(is.environment(x)) lapply(grep("^control\\.*", ls(pos=x), value=TRUE), mget, x, mode="function", ifnotfound=list(NULL)) else list(x) l <- unlist(c(list(...), l)) arglists <- lapply(l, formals) } #' @describeIn snctrl-API A stored expression that, if evaluated, will #' create a callback function `update_my_snctrl()` that will update #' the client package's copy of [snctrl()]. #' @format `UPDATE_MY_SCTRL_EXPR` is a quoted expression meant to be passed directly to [eval()]. #' @examples #' \dontrun{ #' # In the client package (outside any function): #' eval(UPDATE_MY_SCTRL_EXPR) #' } #' @export UPDATE_MY_SCTRL_EXPR <- quote( update_my_snctrl <- function(){ unlockBinding("snctrl", environment(update_my_snctrl)) snctrl <<- statnet.common::snctrl lockBinding("snctrl", environment(update_my_snctrl)) } ) #' @describeIn snctrl-API A stored expression that, if evaluated on #' loading, will add arguments of the package's `control.*()` #' functions to [snctrl()] and set the callback. #' @format `COLLATE_ALL_MY_CONTROLS_EXPR` is a quoted expression meant to be passed directly to [eval()]. #' @examples #' \dontrun{ #' # In the client package: #' .onLoad <- function(libame, pkgname){ #' # ... other code ... #' eval(statnet.common::COLLATE_ALL_MY_CONTROLS_EXPR) #' # ... other code ... #' } #' } #' @export COLLATE_ALL_MY_CONTROLS_EXPR <- quote( statnet.common::update_snctrl(pkgname, list(environment(.onLoad)), update_my_snctrl) ) statnet.common/R/matrix.utils.R0000644000176200001440000001466314430356203016224 0ustar liggesusers# File R/matrix.utils.R in package statnet.common, part of the # Statnet suite of packages for network analysis, https://statnet.org . # # This software is distributed under the GPL-3 license. It is free, # open source, and has the attribution requirements (GPL Section 7) at # https://statnet.org/attribution . # # Copyright 2007-2023 Statnet Commons ################################################################################ #' Test if the object is a matrix that is symmetric and positive definite #' #' @param x the object to be tested. #' @param tol the tolerance for the reciprocal condition number. #' #' @export is.SPD <- function(x, tol = .Machine$double.eps) { is.matrix(x) && nrow(x) == ncol(x) && all(x == t(x)) && rcond(x) >= tol && all(eigen(x, symmetric=TRUE, only.values=TRUE)$values > 0) } #' Common quadratic forms #' #' @name xTAx #' #' @details These are somewhat inspired by emulator::quad.form.inv() #' and others. NULL #' @describeIn xTAx Evaluate \eqn{x'Ax} for vector \eqn{x} and square #' matrix \eqn{A}. #' #' @param x a vector #' @param A a square matrix #' #' @export xTAx <- function(x, A) { drop(crossprod(crossprod(A, x), x)) } #' @describeIn xTAx Evaluate \eqn{xAx'} for vector \eqn{x} and square #' matrix \eqn{A}. #' #' @export xAxT <- function(x, A) { drop(x %*% tcrossprod(A, x)) } #' @describeIn xTAx Evaluate \eqn{x'A^{-1}x} for vector \eqn{x} and #' invertible matrix \eqn{A} using [solve()]. #' #' @export xTAx_solve <- function(x, A, ...) { drop(crossprod(x, solve(A, x, ...))) } #' @describeIn xTAx Evaluate \eqn{x'A^{-1}x} for vector \eqn{x} and #' matrix \eqn{A} using QR decomposition and confirming that \eqn{x} #' is in the span of \eqn{A} if \eqn{A} is singular; returns `rank` #' and `nullity` as attributes just in case subsequent calculations #' (e.g., hypothesis test degrees of freedom) are affected. #' #' @param tol tolerance argument passed to the relevant subroutine #' #' @export xTAx_qrsolve <- function(x, A, tol = 1e-07, ...) { Aqr <- qr(A, tol=tol, ...) nullity <- NCOL(A) - Aqr$rank if(nullity && !all(abs(crossprod(qr.Q(Aqr)[,-seq_len(Aqr$rank), drop=FALSE], x)) sqrt() if(anyNA(d)) stop("Matrix x has negative elements on the diagonal.") dd <- rep(d, each = length(d)) * d Aqr <- qr(A*dd, tol=tol, ...) nullity <- NCOL(A) - Aqr$rank if(nullity && !all(abs(crossprod(qr.Q(Aqr)[,-seq_len(Aqr$rank), drop=FALSE], x*d)) dn is sample size. stop("Either both ", sQuote("mean"), " and ", sQuote("var"), " should be passed or neither."), # One of the two -> error. structure(list(n = 0L, means = numeric(dn), SSDs = numeric(dn), vars = numeric(dn)), class = "Welford") # Neither means nor vars -> dn is dimension. ) } #' @describeIn Welford Update a `Welford` object with new #' data. #' #' @param object a `Welford` object. #' @param newdata either a numeric vector of length `d`, a numeric #' matrix with `d` columns for a group update, or another `Welford` #' object with the same `d`. #' @param ... additional arguments to methods. #' #' @export update.Welford <- function(object, newdata, ...){ l <- object x <- newdata if(is(x, "Welford")){ # Multielement update: newdata is a Welford object. if(length(l[[2]]) != length(x[[2]])) stop(sQuote("newdata"), " must have the same dimension as ", sQuote("object")) l.n <- l[[1]]; x.n <- x[[1]]; l[[1]] <- n.new <- l.n + x.n l.m <- l[[2]]; x.m <- x[[2]] d <- x.m - l.m # In our application, n for x and n for l are going to be similar, so we use weighted average. l[[2]] <- (l.n*l.m + x.n*x.m)/n.new l[[3]] <- l[[3]] + x[[3]] + d*d*l.n*x.n/n.new }else if(is.numeric(x)){ # Either a vector or a matrix with statistics in rows. xm <- rbind(x) if(length(l[[2]]) != ncol(xm)) stop(sQuote("newdata"), " must have the same dimension as ", sQuote("object")) for(r in seq_len(nrow(xm))){ x <- xm[r,] n.prev <- l[[1]] l[[1]] <- n.new <- n.prev + 1 m.prev <- l[[2]] l[[2]] <- m.new <- m.prev + (x-m.prev)/n.new l[[3]] <- l[[3]] + (x-m.prev)*(x-m.new) } }else stop(sQuote("newdata"), " must be either another Welford object, a scalar of correct length, or a matrix with statistics in rows.") l[[4]] <- l[[3]]/(l[[1]]-1) l } statnet.common/R/mcmc-utils.R0000644000176200001440000000546014364112224015630 0ustar liggesusers# File R/mcmc-utils.R in package statnet.common, part of the # Statnet suite of packages for network analysis, https://statnet.org . # # This software is distributed under the GPL-3 license. It is free, # open source, and has the attribution requirements (GPL Section 7) at # https://statnet.org/attribution . # # Copyright 2007-2023 Statnet Commons ################################################################################ #' @name mcmc-utilities #' @title Utility operations for [`mcmc.list`] objects #' #' @description \code{colMeans.mcmc.list} is a "method" for (non-generic) [`colMeans`] applicable to [`mcmc.list`] objects. #' #' @param x a \code{\link{mcmc.list}} object. #' @param \dots additional arguments to \code{\link{colMeans}} or #' \code{\link{sweep}}. #' @return \code{colMeans.mcmc} returns a vector with length equal to #' the number of mcmc chains in \code{x} with the mean value for #' each chain. #' @seealso [`colMeans`], [`mcmc.list`] #' @examples #' data(line, package="coda") #' summary(line) # coda #' colMeans.mcmc.list(line) # "Method" #' \dontshow{ #' stopifnot(isTRUE(all.equal(summary(line)$statistics[,"Mean"],colMeans.mcmc.list(line)))) #' } #' @export colMeans.mcmc.list colMeans.mcmc.list<-function(x,...) colMeans(as.matrix(x),...) #' @rdname mcmc-utilities #' #' @description \code{sweep.mcmc.list} is a "method" for (non-generic) #' [`sweep`] applicable to [`mcmc.list`] objects. #' #' @param STATS,FUN,check.margin See help for [`sweep`]. #' @return \code{sweep.mcmc.list} returns an appropriately modified #' version of \code{x} #' @seealso [`sweep`] #' @examples #' data(line, package="coda") #' colMeans.mcmc.list(line)-1:3 #' colMeans.mcmc.list(sweep.mcmc.list(line, 1:3)) #' \dontshow{ #' stopifnot(isTRUE(all.equal(colMeans.mcmc.list(sweep.mcmc.list(line, 1:3)), colMeans.mcmc.list(line)-1:3))) #' } #' @export sweep.mcmc.list sweep.mcmc.list<-function(x, STATS, FUN="-", check.margin=TRUE, ...){ for(chain in seq_along(x)){ x[[chain]] <- sweep(x[[chain]], 2, STATS, FUN, check.margin, ...) } x } #' @rdname mcmc-utilities #' #' @description \code{lapply.mcmc.list} is a "method" for (non-generic) #' [`lapply`] applicable to [`mcmc.list`] objects. #' #' @param X An [`mcmc.list`] object. #' @return `lapply.mcmc.list` returns an [`mcmc.list`] each of #' whose chains had been passed through `FUN`. #' @seealso [`lapply`] #' @examples #' data(line, package="coda") #' colMeans.mcmc.list(line)[c(2,3,1)] #' colMeans.mcmc.list(lapply.mcmc.list(line, `[`,,c(2,3,1))) #' \dontshow{ #' stopifnot(isTRUE(all.equal(colMeans.mcmc.list(line)[c(2,3,1)],colMeans.mcmc.list(lapply.mcmc.list(line, `[`,,c(2,3,1)))))) #' } #' @importFrom coda as.mcmc.list as.mcmc #' @export lapply.mcmc.list lapply.mcmc.list<-function(X, FUN, ...){ as.mcmc.list(lapply(lapply(X, FUN, ...), as.mcmc)) } statnet.common/R/string.utilities.R0000644000176200001440000000773314364112224017100 0ustar liggesusers# File R/string.utilities.R in package statnet.common, part of the # Statnet suite of packages for network analysis, https://statnet.org . # # This software is distributed under the GPL-3 license. It is free, # open source, and has the attribution requirements (GPL Section 7) at # https://statnet.org/attribution . # # Copyright 2007-2023 Statnet Commons ################################################################################ #' Concatenates the elements of a vector (optionaly enclosing them in quotation #' marks or parentheses) adding appropriate punctuation and conjunctions. #' #' A vector \code{x} becomes "\code{x[1]}", "\code{x[1]} and \code{x[2]}", or #' "\code{x[1]}, \code{x[2]}, and \code{x[3]}", depending on the langth of #' \code{x}. #' #' #' @param x A vector. #' @param oq Opening quotation symbol. (Defaults to none.) #' @param cq Closing quotation symbol. (Defaults to none.) #' @param con Conjunction to be used if `length(x)>1`. (Defaults to "and".) #' @return A string with the output. #' @seealso paste, cat #' @keywords utilities #' @examples #' #' print(paste.and(c())) #' #' print(paste.and(1)) #' #' print(paste.and(1:2)) #' #' print(paste.and(1:3)) #' #' print(paste.and(1:4,con='or')) #' @export paste.and <- function(x, oq='', cq='', con='and'){ x <- paste(oq, x, cq, sep='') if(length(x)==0) return('') if(length(x)==1) return(x) if(length(x)==2) return(paste(x[1L],con,x[2L])) if(length(x)>=3) return(paste0(paste(x[-length(x)], collapse=", "),', ',con,' ',ult(x))) } #' [`print`] objects to the [`message`] output. #' #' A thin wrapper around [`print`] that captures its output and prints #' it as a [`message`], usually to STDERR. #' #' @param ... arguments to [`print`]. #' @param messageArgs a list of arguments to be passed directly to [`message`]. #' #' @examples #' cat(1:5) #' #' print(1:5) #' message_print(1:5) # Looks the same (though may be in a different color on some frontends). #' #' suppressMessages(print(1:5)) # Still prints #' suppressMessages(message_print(1:5)) # Silenced #' @export message_print <- function(..., messageArgs=NULL){ #' @importFrom utils capture.output do.call(message, c(list(paste(capture.output(print(...)),collapse="\n")), messageArgs)) } #' A one-line function to strip whitespace from its argument. #' @param s a character vector. #' @examples #' stopifnot(despace("\n \t ")=="") #' @export despace <- function(s) gsub("[[:space:]]", "", s) #' Format a p-value in fixed notation. #' #' This is a thin wrapper around [format.pval()] that guarantees fixed #' (not scientific) notation, links (by default) the `eps` argument to #' the `digits` argument and vice versa, and sets `nsmall` to equal #' `digits`. #' #' @param pv,digits,eps,na.form,... see [format.pval()]. #' #' @return A character vector. #' #' @examples #' pvs <- 10^((0:-12)/2) #' #' # Jointly: #' fpf <- fixed.pval(pvs, digits = 3) #' fpf #' format.pval(pvs, digits = 3) # compare #' \dontshow{ #' stopifnot(all(fpf == c("1.000", "0.316", "0.100", "0.032", "0.010", "0.003", "0.001", "<0.001", "<0.001", "<0.001", "<0.001", "<0.001", "<0.001"))) #' } #' # Individually: #' fpf <- sapply(pvs, fixed.pval, digits = 3) #' fpf #' sapply(pvs, format.pval, digits = 3) # compare #' \dontshow{ #' stopifnot(all(fpf == c("1.000", "0.316", "0.100", "0.032", "0.010", "0.003", "0.001", "<0.001", "<0.001", "<0.001", "<0.001", "<0.001", "<0.001"))) #' } #' # Control eps: #' fpf <- sapply(pvs, fixed.pval, eps = 1e-3) #' fpf #' \dontshow{ #' stopifnot(all(fpf == c("1.000", "0.316", "0.100", "0.032", "0.010", "0.003", "0.001", "<0.001", "<0.001", "<0.001", "<0.001", "<0.001", "<0.001"))) #' } #' @export fixed.pval <- function(pv, digits = max(1, getOption("digits") - 2), eps = 10^-digits, na.form = "NA", ...) { if (missing(digits) && !missing(eps)) { digits <- ceiling(-log10(eps)) } o <- options(scipen = 200) on.exit(options(o)) format.pval(round(pv, digits), digits, eps = eps, na.form = na.form, nsmall = digits, ...) } statnet.common/NEWS.md0000644000176200001440000002173014433314054014325 0ustar liggesusers# statnet.common 4.9.0 ## New utilities * A new function,`lweighted.cov()`, to compute weighted covariance between two matrices or vectors. * New linear algebra utilities, `is.SPD()`, `sandwich_solve()`, `sandwich_ssolve()`, `sginv()`, `snearPD()`, `srcond()`, `ssolve()`, `xAxT()`, `xTAx()`, `xTAx_qrsolve()`, `xTAx_qrssolve()`, `xTAx_solve()`, and `xTAx_ssolve()` moved from `ergm` and documented. ## Bug fixes * In `handle.controls()`, arguments that are `match.arg()`-ed are now evaluated in the correct frame. # statnet.common 4.8.0 ## New utilities * A helper function `unused_dots_warning()` is exported that works with `rlang::check_dots_used()` to print an informative message. # statnet.common 4.7.0 ## New utilities * An S3 class `term_list` for storing terms extracted from a formula, by `list_rhs.formula()` and others, containing information about each term's sign and environment. Concatenation, indexing, and print methods are implemented. ## Bug fixes * `list_rhs.formula()` can now handle `NULL` terms on the RHS. # statnet.common 4.6.0 ## New utilities * An implementation of Welford's online algorithm for calculating sample mean and variance has been added as a class `Welford` that implements method `update()` and maintains elements `$n`, `$means`, `$SSDs`, and `$vars`. ## Bug fixes * `snctrl()` was issuing a warning twice when called with a misspelled argument. * `deInf()` now handles `NULL` input. * in `locate_function()` a subtle bug has been fixed in handling of visible as opposed to invisible objects. # statnet.common 4.5.0 ## New utilities * `ergm`'s term locator functions (`locate_function()` and `locate_prefixed_function()`) have been moved from `ergm`. * A new function, `default_options()`, a wrapper around `options()` that drops options already set. * A new function, `as.control.list()` generic and methods which take an R list and call an appropriate `control.*()` function on it. * `check.control.class()` now first runs the control argument through `as.control.list()` and overwrites, so `control=` arguments to many functions can be plain lists. * A new function, `simplify_simple()`, which takes a list and returns an atomic vector if the elements of the list are atomic and of length 1, with particular handling for `NULL` and empty (0-length) elements. * A new function, `snctrl()` (StatNet ConTRoL), designed so that argument completion will complete all available control functions. Looking up its help (`?snctrl`) produces a dynamic list of all control parameters and their packages and control functions that is updated as packages are loaded and unloaded. * A new function, `handle.controls()`, that performs the most normal functions in a `control.*()` function. * Two trivial helper functions, `base_env()` and `empty_env()`, to replace an object's environment with `baseenv()` and `emptyenv()`, respectively. * A new function, `fixed.pval()` that wraps `base::format.pval()` with better default arguments. * A reimplementation of `attr()` is exported, which disables partial matching by default. ## Enhancements to existing utilities * `statnetStartupMessage()` now first looks for a `comment=(affil=...)` for the contributor's affiliation, before using e-mail. * Improved output formatting for `.Deprecate_once()`. * `append_rhs.formula()` now accepts NULL as the first argument, in which case it creates a new formula, and takes an additonal argument `env=`, which is used as this new formula's environment. ## Miscellaneous changes * `rle` utilities are no longer reexported. * `statnet.common` no longer depends on `purrr`. * `statnetStartupMessage()` has been simplified. # statnet.common 4.4.0 ## `rle` utilities have been moved to a separate package, `rle` * Major methods are reexported, for now. ## New utilities * `split()` methods for matrices and arrays, to split them along a margin. * `trim_env()`, a generic that will replace an environment (possibly attached to another object) with a sub-environment containing only objects whose names are specified. * A `diff()` method for control lists and a `print()` method for the resulting differences. * `deInf()`, to replace `.deinf()` in package `ergm`. * A `compress()` generic, a `compress()` method for RLEs, and a `doNotCompress` argument to `rep.rle()`. Both `compact.rle()` and the `doNotCompact` argument to `rep.rle()` are now deprecated. ## Enhancements to existing utilities * Various optimizations have been made to RLEs. * `nonsimp_update.formula()` now handles both one and two sided formulas; it also now copies all names except `...` when `from.new = TRUE`. ## Bug fixes * `str.rle()` now works despite the overridden `length()` method. # statnet.common 4.3.0 ## New utilities * `EVL()`, a family of functions like `NVL()`, that treat any object of length 0 as `NULL`. * `once()`, a `purrr`-style adverb that wraps a function to only evaluate the first time it's called with a given configuration of arguments. * `persistEval()` and `persistEvalQ()` to retry evaluating a given expression a specified number of times. ## Bug fixes * In `forkTimeout()`, don't collect a process twice. Thanks to Tomas Kalibera for suggesting the fix. # statnet.common 4.2.0 ## New utilities * `.Deprecate_once()` calls `.Deprecated()`, passing all its arguments through, but only the first time it's called. * `.Deprecate_method()` calls `.Deprecated()`, but only if a method has been called by name, i.e., `METHOD.CLASS`. * `forkTimeout()` evaluates an R expression with a hard time limit (except on Windows) by forking a process. Unlike `setTimeLimit()`, it enforces the limit even on native code. * `ult()` is a convenience function that extracts or replaces elements of a list indexed from the end. ## Miscellaneous * `statnet.common` now depends on R >= 3.5 due to what appears to be a method dispatching bug in earlier versions. * The package no longer Enhances `coda`. # statnet.common 4.1.4 ## New utilities * `despace()` removes whitespace from a string. * Pseudo-methods `colMeans.mcmc.list()`, `sweep.mcmc.list()`, and `lapply.mcmc.list()` (migrated from the `ergm` package). * `filter_rhs.formula()` selectively deletes terms in on the RHS of a formula. * `eval_lhs.formula()` extracts the LHS of the formula and evaluates it in the specified environment. * `NVL2()` and `NVL3()` for flexible substitution of null values. * `message_print()` formats its arguments as if for `print()` or `show()` methods, but then prints to stderr like `message()`. ## Enhancements to existing utilities * `paste.and()` now takes an additional `con=` argument, allowing a conjunction other than "and" to be used. * `ERRVL()` now uses lazy evaluation and lets the user dot-substitute the previous argument's try-error into the next argument. ## Bug fixes * Printing for control lists now works for function arguments. * A number of improvements to `rle` methods. ## Miscellaneous * A number of functions have been renamed for consistency: * `term.list.formula()` → `list_rhs.formula()` * `append.rhs.formula()` → `append_rhs.formula()` * `nonsimp.update.formula()` → `nonsimp_update.formula()` * Citation utilities have been deprecated, since CRAN's structure makes them unusable. # statnet.common 4.0.0 * The package now uses `Roxygen` for documentation. * `term.list.formula()` output format has been changed, since support of attributes on symbols is being deprecated. * A library of methods has been added for the base `rle` class, implementing concatenation, compaction, and a number of binary operations. * `all_same()` has been moved from ergm and renamed to `all_identical()`. * A new assignment method `NVL()<-` overwrites a variable if its value is NULL. * A set of classes and functions for manipulating and efficiently performing calculations on dense matrices or vectors with weighted rows or elements (possibly on the log scale) has been added. * New control parameter helper function, control.remap() has been added. Autodetection of function names by `set.control.class()` and `check.control.class()` has been deprecated and now results in a warning. * Improvements to the compressed data frame code, including an order() generic. * Miscellaneous robustifications added. * Native routine registration has been added. # statnet.common 3.3.0 * `append.rhs.formula()`, `vectors.namesmatch()`, `term.list.formula()`, and `ergm.update.formula()` (renamed to `nosimp.update.formula()`) moved from `ergm`. * Skye Bender-deMoll has been added as a contributor. # statnet.common 3.2.3 * `ERRVL()` moved from `ergm`. * Some `NAMESPACE` and other fixes to pass CRAN checks. # statnet.common 3.2.2 * control class improvements and bug fixes. # statnet.common 3.1.1 * Updated e-mail address * Some improvements to opttest. # statnet.common 3.1.0 * Initial release, incorporating the control class framework (`set.control.class()`, `check.control.class()`, `print.control.list()`); startup message framework; `NVL()`; `sort.data.frame()`; `compress.data.frame()`; `paste.and()`; citation utilities framework; and `opttest()` framework. statnet.common/MD50000644000176200001440000000754614433433333013552 0ustar liggesusersd1f55477ee15a9e41a6cd8a8473df8c9 *DESCRIPTION aa3950230c13d9b9be7f6bdac6ac4391 *LICENSE 3271eba7a5449d29691d7daa1c1a810f *NAMESPACE 0404a24fab06607d3019358eaa2386e1 *NEWS 0bc9210c7613f007aa2c0274399d27a3 *NEWS.md b443a32a0bc4b1807b7e1cac7ab1626f *R/Welford.R 7b8008a0a0e98a2d473c9a8785200980 *R/cite.utilities.R 87c9081759233e092709fbbcfb4f2d2d *R/control.utilities.R 655025815d8c8c5bf7da1d78f229e5b1 *R/deprecation_utils.R 80f92588f96c5fd80eb2921bebc8b07d *R/formula.utilities.R ea6d899b81631a0ee2dda98811948732 *R/locator.R 4f18ecfe758532eef24fb43731df4ddb *R/logspace.utils.R 022917f58af46f23a95c36c1bc6e9dad *R/matrix.utils.R 7acbdd238db68be1cabb875b129b9a02 *R/mcmc-utils.R acbe0ac4c2e9586080af74854d4d900c *R/misc.utilities.R 10d13981bf54fc1a19a94f844abb661b *R/startup.utilities.R 541fbdfda2070f7566d2eb1395110a6d *R/string.utilities.R 430bf625cd3ced0801b3ed85134a78a5 *R/wmatrix.R f947972f31c5420f86fb9483b32b33f8 *R/zzz.R d2b0a2792e76122926c68ed1fea6e0f5 *build/stage23.rdb 6e42f467aa565c55acb24fdd8abdc03a *build/statnet.common.pdf 9ea1c669a9119733ec1d0af4c7aeb5e0 *inst/CITATION 78fe80c3107cf324601c1ce5660b2424 *inst/templates/snctrl.R 7f2a94a498a5dc05b0503c5a31ab87b5 *man/ERRVL.Rd 3ff13be4f722b95759d48982ef49331a *man/NVL.Rd 34de3ab4201a3cc30d57218b24164e0b *man/Welford.Rd b8da6a5b1e1749ebb1e2bd91fee52ae4 *man/all_identical.Rd bd39d31ab0f9e15408974ab420daf507 *man/as.control.list.Rd 3ba4d22fcc4e1337155a6718b5b96629 *man/attr.Rd 0a20ec0d0489a2fefd8888af5b0325fe *man/check.control.class.Rd 3d6c6870ce2f5e58298725cd06a2fe31 *man/compress_rows.Rd 9db58d7b6e6813c0ff3c304a6ea6814b *man/compress_rows.data.frame.Rd 69e165465cfe137f151e88da25d2c547 *man/control.list.accessor.Rd 3fdf8a833fede8838180c050d6cebf86 *man/control.remap.Rd c3be3a9476df5c0d8918f01dec3ccf18 *man/deInf.Rd 4fc9c8b806ec2ba21e3817d25a3e8250 *man/default_options.Rd fa99d54928bf41d5f6406879f140fc51 *man/deprecation-utilities.Rd 9855a7006964b42b31a34bc9419328d1 *man/despace.Rd 5bcee973fe48b49b4fe18d7140ad15c1 *man/diff.control.list.Rd cca9ecb70068bacf3dba0ebd3fabf32c *man/empty_env.Rd c7885722ddb46ab915a286cae1f096e4 *man/fixed.pval.Rd c9a722d71b353491bb1c93fdc0b228fe *man/forkTimeout.Rd d2bbaea746e24c2d6b9a225c494af84a *man/formula.utilities.Rd c4c4fd04ad2eb3987c562ee6725f7863 *man/handle.controls.Rd fb6b61e978b717e1ff51be23ad2229a6 *man/is.SPD.Rd 7ac45e4ba0e24a75670c19060379d76f *man/locate_function.Rd ab620fb78fd21cf3fea357ef44e2a196 *man/logspace.utils.Rd 2ec7bf6e6ec0694f6281ee30066fec43 *man/mcmc-utilities.Rd c4e645b96228c6f88533cf55dde327c6 *man/message_print.Rd 9a2a60603a701952ab439e01e0ab7316 *man/once.Rd b3f30472590e0c88122bae0f2fa585a7 *man/opttest.Rd 7f1cd031b808ff7070fcdba16ee1f164 *man/paste.and.Rd e99354e1d54c6d52f4991b071e15e5de *man/persistEval.Rd 55282e11ef7613fc90d2ddd222c9920c *man/print.control.list.Rd d12dde635ec286bc0a93b352aceb544f *man/set.control.class.Rd 740f941781269918f51d2162fddb38f1 *man/simplify_simple.Rd 9e3c3a3de6d2bbf3965184810705bb7f *man/snctrl-API.Rd 3d8dbbbec4df017419dd5c970a98b582 *man/snctrl.Rd a8de5de83cb42976a7fe04718debec89 *man/sort.data.frame.Rd 23afa368f513c4b3b06fad2aa62d4ef5 *man/split.array.Rd 4536022eff6beb057385f10355621e21 *man/ssolve.Rd 9bbf055f43b721dac1b7c1077ae89537 *man/statnet.cite.Rd 893ba4da7f56b1f754582e0eebe430e1 *man/statnetStartupMessage.Rd e39f236ad480f70fa99a9619806380bd *man/sweep_cols.matrix.Rd 8185268c388657b21290d1eb38b37536 *man/term_list.Rd 1dff4b12e5b5728d1289e5fc36ccaa64 *man/trim_env.Rd 32710045b53e1d71ddf2812bb93e4a83 *man/ult.Rd 76a21eabe2d29ac33723ebd37714cc78 *man/unused_dots_warning.Rd c3e0ca540da380a53d3d6d2f871f6932 *man/unwhich.Rd acf1f0b58218004dc025eb1a475d4ea1 *man/vector.namesmatch.Rd 3039ecb65762e63a9a0522855a1bd0be *man/wmatrix.Rd 127255b6fa25823caad8378cb7865bdd *man/wmatrix_weights.Rd f502a246f757f14f0f7f781b4c8b1d98 *man/xTAx.Rd 7b9120f0c5d722b6ad04d863d2b3eeae *src/init.c 18e0039c7f8b2427c37d00a7ce40e135 *src/logspace_utils.c statnet.common/inst/0000755000176200001440000000000014433314050014175 5ustar liggesusersstatnet.common/inst/templates/0000755000176200001440000000000014364112224016175 5ustar liggesusersstatnet.common/inst/templates/snctrl.R0000644000176200001440000000326014364112224017626 0ustar liggesusers# File inst/templates/snctrl.R in package statnet.common, part of the # Statnet suite of packages for network analysis, https://statnet.org . # # This software is distributed under the GPL-3 license. It is free, # open source, and has the attribution requirements (GPL Section 7) at # https://statnet.org/attribution . # # Copyright 2007-2023 Statnet Commons ################################################################################ # This document provides a template for exporting a package's # control.* functions to be visible to snctrl() and providing a # sensible help document. Currently, the packages have to be updated # manually when the template changes. ## Usage: # 1. Add the following line: # "eval(statnet.common::COLLATE_ALL_MY_CONTROLS_EXPR)" to the # .onLoad() function. It is important that the function's arguments # have their standard names ("libname" and "pkgname"). # # 2. Add the following text block to provide help. Note that the NULL is important, because otherwise, Roxygen will create an unsightly usage statement. # # 3. Run roxygen. # TODO: Figure out some automatic way to keep this in sync with statnet.common. ## BEGIN text block #' @name snctrl #' #' @title Statnet Control #' #' @description A utility `snctrl(...)`, to facilitate argument completion of control lists, reexported from `statnet.common`. #' #' @section Currently recognised control parameters: #' This list is updated as packages are loaded and unloaded. #' #' \Sexpr[results=rd,stage=render]{statnet.common::snctrl_names()} #' #' @seealso [statnet.common::snctrl()] #' @docType import NULL #' @export snctrl <- statnet.common::snctrl eval(UPDATE_MY_SCTRL_EXPR) # END text block statnet.common/inst/CITATION0000644000176200001440000000342114433314050015332 0ustar liggesusers#' statnet: statnet.cite.head("statnet.common") # ---- BEGIN AUTOGENERATED STATNET CITATION ---- citHeader(paste0(sQuote("statnet.common"), " is part of the Statnet suite of packages. ", "If you are using the ", sQuote("statnet.common"), " package for research that will be published, ", "we request that you acknowledge this by citing the following.\n", "For BibTeX format, use toBibtex(citation(\"", "statnet.common", "\")).")) # ---- END AUTOGENERATED STATNET CITATION ---- #' statnet: statnet.cite.pkg("statnet.common") # ---- BEGIN AUTOGENERATED STATNET CITATION ---- bibentry("Manual", author = structure(list(list(given = c("Pavel", "N."), family = "Krivitsky", role = c("aut", "cre"), email = "pavel@statnet.org", comment = c(ORCID = "0000-0002-9101-3362", affiliation = "University of New South Wales" ))), class = "person"), title = paste("statnet.common", ": ", gsub("\n", " ", "Common R Scripts and Utilities Used by the Statnet Project Software", fixed = TRUE), sep = ""), organization = paste0("The Statnet Project (\\url{", "https://statnet.org", "})"), year = substr("2023-05-24", 1, 4), note = paste("R package version ", "4.9.0", sep = ""), url = paste0("https://CRAN.R-project.org/package=", "statnet.common")) # ---- END AUTOGENERATED STATNET CITATION ---- #' statnet: statnet.cite.foot("statnet.common") # ---- BEGIN AUTOGENERATED STATNET CITATION ---- citFooter(paste0("We have invested a lot of time and effort in creating the ", "Statnet suite of packages for use by other researchers. ", "Please cite it in all papers where it is used. The package ", sQuote("statnet.common"), " is distributed under the terms of the license ", "GPL-3 + file LICENSE", ".")) # ---- END AUTOGENERATED STATNET CITATION ----