gower/0000755000176200001440000000000014176740556011414 5ustar liggesusersgower/NAMESPACE0000644000176200001440000000017114176730663012630 0ustar liggesusers# Generated by roxygen2: do not edit by hand export(gower_dist) export(gower_topn) useDynLib(gower, .registration=TRUE) gower/man/0000755000176200001440000000000013452644704012161 5ustar liggesusersgower/man/gower-package.Rd0000644000176200001440000000040213452644704015160 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/gower-pkg.R \docType{package} \name{gower-package} \alias{gower-package} \title{Gower's distance/similarity measure.} \description{ A C-based implementation of Gower's distance. } gower/man/gower_topn.Rd0000644000176200001440000000376213671157664014652 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/gower.R \name{gower_topn} \alias{gower_topn} \title{Find the top-n matches} \usage{ gower_topn( x, y, pair_x = NULL, pair_y = NULL, n = 5, eps = 1e-08, weights = NULL, ignore_case = FALSE, nthread = getOption("gd_num_thread") ) } \arguments{ \item{x}{\code{[data.frame]}} \item{y}{\code{[data.frame]}} \item{pair_x}{\code{[numeric|character] (optional)} Columns in \code{x} used for comparison. See Details below.} \item{pair_y}{\code{[numeric|character] (optional)} Columns in \code{y} used for comparison. See Details below.} \item{n}{The top-n indices and distances to return.} \item{eps}{\code{[numeric] (optional)} Computed numbers (variable ranges) smaller than \code{eps} are treated as zero.} \item{weights}{\code{[numeric] (optional)} A vector of weights of length \code{ncol(x)} that defines the weight applied to each component of the gower distance.} \item{ignore_case}{\code{[logical]} Toggle ignore case when neither \code{pair_x} nor \code{pair_y} are user-defined.} \item{nthread}{Number of threads to use for parallelization. By default, for a dual-core machine, 2 threads are used. For any other machine n-1 cores are used so your machine doesn't freeze during a big computation. The maximum nr of threads are determined using \code{omp_get_max_threads} at C level.} } \value{ A \code{list} with two array elements: \code{index} and \code{distance}. Both have size \code{n X nrow(x)}. Each ith column corresponds to the top-n best matches of \code{x} with rows in \code{y}. When there are no columns to compare, a message is printed and both \code{distance} and \code{index} will be empty matrices; the list is then returned invisibly. } \description{ Find the top-n matches in \code{y} for each record in \code{x}. } \examples{ # find the top 4 best matches in the iris data set with itself. x <- iris[1:3,] lookup <- iris[1:10,] gower_topn(x=x,y=lookup,n=4) } \seealso{ \code{\link{gower_dist}} } gower/man/gower_dist.Rd0000644000176200001440000000504713671157664014633 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/gower.R \name{gower_dist} \alias{gower_dist} \title{Gower's distance} \usage{ gower_dist( x, y, pair_x = NULL, pair_y = NULL, eps = 1e-08, weights = NULL, ignore_case = FALSE, nthread = getOption("gd_num_thread") ) } \arguments{ \item{x}{\code{[data.frame]}} \item{y}{\code{[data.frame]}} \item{pair_x}{\code{[numeric|character] (optional)} Columns in \code{x} used for comparison. See Details below.} \item{pair_y}{\code{[numeric|character] (optional)} Columns in \code{y} used for comparison. See Details below.} \item{eps}{\code{[numeric] (optional)} Computed numbers (variable ranges) smaller than \code{eps} are treated as zero.} \item{weights}{\code{[numeric] (optional)} A vector of weights of length \code{ncol(x)} that defines the weight applied to each component of the gower distance.} \item{ignore_case}{\code{[logical]} Toggle ignore case when neither \code{pair_x} nor \code{pair_y} are user-defined.} \item{nthread}{Number of threads to use for parallelization. By default, for a dual-core machine, 2 threads are used. For any other machine n-1 cores are used so your machine doesn't freeze during a big computation. The maximum nr of threads are determined using \code{omp_get_max_threads} at C level.} } \value{ A \code{numeric} vector of length \code{max(nrow(x),nrow(y))}. When there are no columns to compare, a message is printed and both \code{numeric(0)} is returned invisibly. } \description{ Compute Gower's distance, pairwise between records in two data sets \code{x} and \code{y}. Records from the smallest data set are recycled over. } \section{Details}{ There are three ways to specify which columns of \code{x} should be compared with what columns of \code{y}. The first option is do give no specification. In that case columns with matching names will be used. The second option is to use only the \code{pairs_y} argument, specifying for each column in \code{x} in order, which column in \code{y} must be used to pair it with (use \code{0} to skip a column in \code{x}). The third option is to explicitly specify the columns to be matched using \code{pair_x} and \code{pair_y}. } \section{Note}{ Gower (1971) originally defined a similarity measure (\eqn{s}, say) with values ranging from 0 (completely dissimilar) to 1 (completely similar). The distance returned here equals \eqn{1-s}. } \references{ Gower, John C. "A general coefficient of similarity and some of its properties." Biometrics (1971): 857-871. } \seealso{ \code{\link{gower_topn}} } gower/DESCRIPTION0000644000176200001440000000150114176740556013117 0ustar liggesusersPackage: gower Maintainer: Mark van der Loo License: GPL-3 Title: Gower's Distance Type: Package LazyLoad: yes Authors@R: c( person("Mark", "van der Loo", role=c("aut","cre"),email="mark.vanderloo@gmail.com") , person("David", "Turner", role="ctb")) Description: Compute Gower's distance (or similarity) coefficient between records. Compute the top-n matches between records. Core algorithms are executed in parallel on systems supporting OpenMP. Version: 1.0.0 URL: https://github.com/markvanderloo/gower BugReports: https://github.com/markvanderloo/gower/issues Suggests: tinytest (>= 0.9.3), RoxygenNote: 7.1.1 NeedsCompilation: yes Packaged: 2022-02-03 10:43:02 UTC; mark Author: Mark van der Loo [aut, cre], David Turner [ctb] Repository: CRAN Date/Publication: 2022-02-03 11:50:06 UTC gower/build/0000755000176200001440000000000014176730666012514 5ustar liggesusersgower/build/vignette.rds0000644000176200001440000000032714176730666015055 0ustar liggesusersmPQ0 0QHLL $Cwaq#cŢ`dҤ]׾"\^߀;@HU`%QĜ9)U5i~%T?0v^ycs^s<,j#gR58^COZú^4hc/2jh\h_{gower/tests/0000755000176200001440000000000013465343632012550 5ustar liggesusersgower/tests/tinytest.R0000644000176200001440000000010513452644704014552 0ustar liggesuserslibrary(gower) if ( require(tinytest) ){ test_package("gower") } gower/src/0000755000176200001440000000000014176730666012204 5ustar liggesusersgower/src/Makevars0000644000176200001440000000011013452644704013661 0ustar liggesusers PKG_CFLAGS = $(SHLIB_OPENMP_CFLAGS) PKG_LIBS = $(SHLIB_OPENMP_CFLAGS) gower/src/R_register_native.c0000644000176200001440000000171513452644704016020 0ustar liggesusers#include #include #include // for NULL #include /* FIXME: Check these declarations against the C/Fortran source code. */ /* .Call calls */ extern SEXP R_get_max_threads(); extern SEXP R_get_thread_limit(); extern SEXP R_get_xy_range(SEXP, SEXP, SEXP); extern SEXP R_gower(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_gower_topn(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); static const R_CallMethodDef CallEntries[] = { {"R_get_max_threads", (DL_FUNC) &R_get_max_threads, 0}, {"R_get_thread_limit", (DL_FUNC) &R_get_thread_limit, 0}, {"R_get_xy_range", (DL_FUNC) &R_get_xy_range, 3}, {"R_gower", (DL_FUNC) &R_gower, 8}, {"R_gower_topn", (DL_FUNC) &R_gower_topn, 9}, {NULL, NULL, 0} }; void R_init_gower(DllInfo *dll) { R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); R_useDynamicSymbols(dll, FALSE); } gower/src/gower.c0000644000176200001440000004530414176720354013472 0ustar liggesusers/* gower - a C/R implementation of Gower's similarity (or distance) measure. * Copyright (C) 2016 Mark van der Loo * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * You can contact the author at: mark _dot_ vanderloo _at_ gmail _dot_ com * */ #ifdef _OPENMP #include #endif /* R-windows-oldrel (3.2.x) uses gcc 4.6.3 which we need to detect */ #ifdef __GNUC__ #if __GNUC__ <= 4 && __GNUC_MINOR__ <= 6 #else #define HAS_REDUCTION #endif #endif #include #include #include #define MAX(X,Y) ((X) > (Y) ? (X) : (Y)) #define MIN(X,Y) ((X) < (Y) ? (X) : (Y)) #define RECYCLE(N, K) ((N) + 1L < (K) ? (N) + 1L : 0L ) // determine when something is numerically zero. static double EPS = 1e-8; // set max nr of threads to use static int NTHREAD = 1L; // recycling in parallel region. static inline int recycle(int i, int nthreads, int ni){ i += nthreads; if ( i >= ni ) i = (nthreads < ni) ? (i - ni) : (i % ni); return i; } SEXP R_get_max_threads(){ SEXP out = allocVector(INTSXP, 1L); PROTECT(out); INTEGER(out)[0] = 1L; #ifdef _OPENMP INTEGER(out)[0] = omp_get_max_threads(); #endif UNPROTECT(1); return out; } SEXP R_get_num_procs(){ SEXP out = allocVector(INTSXP, 1L); PROTECT(out); INTEGER(out)[0] = 1L; #ifdef _OPENMP INTEGER(out)[0] = omp_get_num_procs(); #endif UNPROTECT(1); return out; } SEXP R_get_thread_limit(){ SEXP out = allocVector(INTSXP, 1L); PROTECT(out); INTEGER(out)[0] = 1L; #ifdef _OPENMP INTEGER(out)[0] = omp_get_thread_limit(); #endif UNPROTECT(1); return out; } // presence or absence of a character. x and y are 0 (FALSE) or 1 (TRUE) static inline void gower_logi(int *x, int nx, int *y, int ny , double *num, double *den, double weight) { #pragma omp parallel num_threads(NTHREAD) { int nt = MAX(nx,ny); double dijk, sijk; int i = 0, j = 0; double *inum = num, *iden=den; int ID = 0, num_threads=1; #ifdef _OPENMP ID = omp_get_thread_num(); num_threads = omp_get_num_threads(); i = recycle(ID-num_threads, num_threads, nx); j = recycle(ID-num_threads, num_threads, ny); inum += ID; iden += ID; #endif for ( int k = ID; k < nt; k += num_threads, inum += num_threads, iden += num_threads){ dijk = (double) ((x[i] | y[j]) & !((x[i] == NA_INTEGER) | (y[j] == NA_INTEGER))); sijk = (dijk == 1.0) ? (double) (x[i] * y[j]) : 0.0; *inum += weight * dijk * sijk; *iden += weight * dijk; i = recycle(i, num_threads, nx); j = recycle(j, num_threads, ny); } } // end parallel region. } // equality of categorical variables, encoded as x, y in {1,2,...,N}. static inline void gower_cat(int *x, int nx, int *y, int ny , double *num, double *den, double weight) { #pragma omp parallel num_threads(NTHREAD) { int nt = MAX(nx,ny); double dijk, sijk; int i = 0, j = 0; double *inum = num, *iden=den; int ID = 0, num_threads=1; #ifdef _OPENMP ID = omp_get_thread_num(); num_threads = omp_get_num_threads(); i = recycle(ID-num_threads, num_threads, nx); j = recycle(ID-num_threads, num_threads, ny); inum += ID; iden += ID; #endif for ( int k = ID; k < nt; k += num_threads, inum += num_threads, iden += num_threads){ dijk = (double) !(x[i] == NA_INTEGER || y[j] == NA_INTEGER); sijk = (dijk==1.0) ? (double) (x[i] == y[j]) : 0.0; *inum += weight * dijk * sijk; *iden += weight * dijk; i = recycle(i, num_threads, nx); j = recycle(j, num_threads, ny); } } // end parallel region. } // strings. Treated as categories. static inline void gower_str(SEXP x, int nx, SEXP y, int ny, double *num, double *den, double weight){ #pragma omp parallel num_threads(NTHREAD) { int nt = MAX(nx, ny); double dijk, sijk; int i=0, j=0; double *inum = num, *iden=den; SEXP xi, yj; int ID = 0, num_threads=1; #ifdef _OPENMP ID = omp_get_thread_num(); num_threads = omp_get_num_threads(); i = recycle(ID-num_threads, num_threads, nx); j = recycle(ID-num_threads, num_threads, ny); inum += ID; iden += ID; #endif for ( int k = ID; k < nt; k += num_threads, inum += num_threads, iden += num_threads){ xi = STRING_ELT(x,i); yj = STRING_ELT(y,j); dijk = (double) !(xi == NA_STRING || yj == NA_STRING); sijk = (dijk==1.0) ? (double) (CHAR(xi) == CHAR(yj)) : 0.0; *inum += weight * dijk * sijk; *iden += weight * dijk; i = recycle(i, num_threads, nx); j = recycle(j, num_threads, ny); } } // end of parallel region } // comparison of numerical variables, by absolute difference divided by range. static inline void gower_num(double *x, int nx, double *y, int ny,double R , double *num, double *den, double weight) { if ( !isfinite(R) || R < EPS ){ warning("skipping variable with zero or non-finite range."); return; } #pragma omp parallel num_threads(NTHREAD) { int nt = MAX(nx,ny); double dijk, sijk; int i = 0, j = 0; double *inum = num, *iden=den; int ID = 0, num_threads=1; #ifdef _OPENMP ID = omp_get_thread_num(); num_threads = omp_get_num_threads(); i = recycle(ID-num_threads, num_threads, nx); j = recycle(ID-num_threads, num_threads, ny); inum += ID; iden += ID; #endif for ( int k = ID; k < nt; k += num_threads, inum += num_threads, iden += num_threads){ dijk = (double) (isfinite(x[i]) & isfinite(y[j])); sijk = (dijk==1.0) ? (1.0-fabs(x[i]-y[j])/R) : 0.0; (*inum) += weight * dijk * sijk; (*iden) += weight * dijk; i = recycle(i, num_threads, nx); j = recycle(j, num_threads, ny); } } // end of parallel region } static inline void gower_dbl_int(double *x, int nx, int *y, int ny,double R , double *num, double *den, double weight) { if ( !isfinite(R) || R < EPS ){ warning("skipping variable with zero or non-finite range\n"); return; } #pragma omp parallel num_threads(NTHREAD) { int nt = MAX(nx, ny); double dijk, sijk; int i=0, j=0; double *inum = num, *iden=den; int ID = 0, num_threads=1; #ifdef _OPENMP ID = omp_get_thread_num(); num_threads = omp_get_num_threads(); i = recycle(ID-num_threads, num_threads, nx); j = recycle(ID-num_threads, num_threads, ny); inum += ID; iden += ID; #endif for ( int k = ID; k < nt; k += num_threads, inum += num_threads, iden += num_threads){ dijk = (double) (isfinite(x[i]) & (y[j] != NA_INTEGER)); sijk = (dijk==1.0) ? (1.0-fabs(x[i] - ((double) y[j]) )/R) : 0.0; *inum += weight * dijk * sijk; *iden += weight * dijk; i = recycle(i, num_threads, nx); j = recycle(j, num_threads, ny); } } // end of parallel region } static inline void gower_int(int *x, int nx, int *y, int ny, double R , double *num, double *den, double weight) { if ( !isfinite(R) || R == 0 ){ warning("skipping variable with zero or non-finite range\n"); return; } #pragma omp parallel num_threads(NTHREAD) { int nt = MAX(nx, ny); double dijk, sijk; int i=0, j=0; double *inum = num, *iden=den; int ID = 0, num_threads=1; #ifdef _OPENMP ID = omp_get_thread_num(); num_threads = omp_get_num_threads(); i = recycle(ID-num_threads, num_threads, nx); j = recycle(ID-num_threads, num_threads, ny); inum += ID; iden += ID; #endif for ( int k = ID; k < nt; k += num_threads, inum += num_threads, iden += num_threads){ dijk = (double) ( (x[i] !=NA_INTEGER) & (y[j] != NA_INTEGER)); sijk = (dijk==1.0) ? (1.0-fabs( ((double)x[i]) - ((double)y[j]) )/R) : 0.0; *inum += weight * dijk * sijk; *iden += weight * dijk; i = recycle(i, num_threads, nx); j = recycle(j, num_threads, ny); } } // end of parallel region } // range computations static void get_dbl_range(double *x, int nx, double *min, double *max){ double *ix = x; double imin=*ix, imax=*ix; for ( int i=0; i imax ) imax = x[i]; if ( x[i] < imin ) imin = x[i]; } } }// end parallel region *min = imin; *max = imax; } static void get_int_range(int *x, int nx, double *min, double *max){ int *ix = x; int imin = *ix , imax = *ix; for ( int i=0; i imax ) imax = x[i]; if ( x[i] < imin ) imin = x[i]; } } *min = (double) imin; *max = (double) imax; } static void get_range(SEXP x, double *min, double *max){ switch( TYPEOF(x) ){ case INTSXP : { get_int_range(INTEGER(x), length(x), min, max); break; } case REALSXP : { get_dbl_range(REAL(x), length(x), min, max); break; } } } static double get_xy_range(SEXP x, SEXP y){ double x_min = R_NegInf , x_max = R_PosInf , y_min = R_NegInf , y_max = R_PosInf , min, max; get_range(x, &x_min, &x_max); get_range(y, &y_min, &y_max); if ( isfinite(x_min) & isfinite(y_min) ){ min = MIN(x_min, y_min); } else if ( isfinite(x_min) & !(isfinite(y_min)) ){ min = x_min; } else if ( (!isfinite(x_min)) & isfinite(y_min) ) { min = y_min; } else { min = NA_REAL; } if ( isfinite(x_max) & isfinite(y_min) ){ max = MAX(x_max, y_max); } else if ( isfinite(x_max) & !isfinite(y_max) ){ max = x_max; } else if ( (!isfinite(x_max)) & isfinite(y_max) ){ max = y_max; } else { max = NA_REAL; } return max - min; } SEXP R_get_xy_range(SEXP x_, SEXP y_, SEXP nthread_){ NTHREAD = INTEGER(nthread_)[0]; SEXP out = allocVector(REALSXP,1L); PROTECT(out); REAL(out)[0] = get_xy_range(x_, y_); UNPROTECT(1); return out; } /* static void print_vec(double *x, int n){ for ( int i=0; ii; j-- ){ topn[j] = topn[j-1]; index[j] = index[j-1]; } topn[i] = x; index[i] = ind; break; // out of main loop } } } } /* For testing purposes SEXP R_pushdown(SEXP entry_, SEXP index_, SEXP values_, SEXP indices_){ double entry = REAL(entry_)[0]; int index = INTEGER(index_)[0]; double *values = REAL(values_); int *indices = INTEGER(indices_); int n = length(values_); push(entry, index, values, indices, n); return R_NilValue; } */ static inline void copyrec(SEXP into, SEXP from, int i){ int ncol = length(into); SEXP col_from, col_into; for ( int j = 0; j < ncol; j++){ col_from = VECTOR_ELT(from,j); col_into = VECTOR_ELT(into,j); switch(TYPEOF(col_from)){ case LGLSXP : { INTEGER(col_into)[0] = INTEGER(col_from)[i]; break;} case INTSXP : { INTEGER(col_into)[0] = INTEGER(col_from)[i]; break;} case REALSXP : { REAL(col_into)[0] = REAL(col_from)[i]; break;} case STRSXP : { SET_STRING_ELT(col_from, 0, STRING_ELT(col_from,i)); break;} } } } /* for testing purposes only void prvec(SEXP x){ for (int i=0; i>= options(prompt=" ") @ \newpage \section{Gower's distance measure} Gower's distance can be used to measure how different two records are. The records may contain combinations of logical, numerical, categorical or text data. The distance is always a number between 0 (identical) and 1 (maximally dissimilar). An easy to read specification of the measure is given in the original paper. Gower (1971) \href{http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.412.4155&rep=rep1&type=pdf}{A general coefficient of similarity and some of its properties}. \emph{Biometrics} **27** 857--874. In short, Gower's distance (or similarity) first computes distances between pairs of variables over two data sets and then combines those distances to a single value per record-pair. This package modifies Gower's original similarity measure in the following ways. \begin{itemize} \item{In stead of the original similarity $S$, the package returns the distance $1-S$.} \item{The original paper does not mention the concept of \code{NA}. Missing variables are skipped when computing the distance.} \item{The original paper does not mention character data. These are treated as categorical data.} \end{itemize} \section{Computing Gower's distance} The function \code{gower\_dist} computes pairwise-distances between records. <<>>= library(gower) dat1 <- iris[1:10,] dat2 <- iris[6:15,] gower_dist(dat1, dat2) @ If one data frame has less records than the other, the shortest one is recycled over (just like when you're adding two vectors of unequal length) <<>>= gower_dist(iris[1,], dat1) @ It is possible to control how columns from the two data sets are paired for comparison using the \code{pair\_x} and \code{pair\_y} arguments. This comes in handy when similar colums have different names accross datasets. By default, columns with matching names are paired. The behaviour is somewhat similar to that of base R's \code{merge} in that respect. <<>>= dat1 <- dat2 <- iris[1:10,] names(dat2) <- tolower(names(dat2)) gower_dist(dat1, dat2) # tell gower_dist to match columns 1..5 in dat1 with column 1..5 in dat2 gower_dist(dat1, dat2, pair_y=1:5) @ It is also possible to explicitly ignore case when matching columns by name. <<>>= gower_dist(dat1, dat2, ignore_case=TRUE) @ \section{Computing the top-n best matches} The function \code{gower\_topn} returns a list with two arrays. <<>>= dat1 <- iris[1:10,] L <- gower_topn(x=dat1, y=iris, n=3) L @ The first array is called \code{index}. Each column corresponds to one row of \code{x}. The entries of each column index the top $n$ best matches of that row in \code{x} with rows in \code{y}. In this example, the best match of the first row of \code{dat1} is record number \Sexpr{L$index[1,1]} from \code{iris} (this should be obvious, since they are the same record). The second best match is record number \Sexpr{L$index[2,1]} from \code{iris}. The second array is called \code{distance} and it contains the corresponding distances. \section{Using weights} Gower's distance is computed as an average over differences between variables. By setting \code{weights} you can compute the distance as a weighted average. <<>>= gower_dist(women[1,], women) gower_dist(women[1,], women, weights=c(2,3)) @ \section{Parallelization, memory usage} The underlying algorithm is implemented in C and parallelized using \href{http://www.openmp.org}{OpenMP}. OpenMP is available on most systems that can run R. Please see \href{https://cran.r-project.org/doc/manuals/r-release/R-exts.html#OpenMP-support}{this section} of the writing R extensions manual for up-to-details details on which systems are supported. At the time of writing (spring 2019), OSX is the only system not supporting OpenMP out of the box. You can still make it work by installing the gcc toolchain and compiling the package (and R). If OpenMP is not supported, the package will still work but the core algorithms will not be parallelized. This implementation makes no copies of the data in memory. When computing \code{gower\_dist}, two double precision arrays of size \code{max(nrow(x),nrow(y))} are kept in memory to store intermediate results. When computing the top-n matches, for $k$ cores, $k+2$ double precision arrays of length \code{nrow(y)} are created to store intermediate results at C level. \end{document} gower/NEWS0000644000176200001440000000245014176730621012104 0ustar liggesusersversion 1.0.0 - Fix: for integer vectors, the output would in some cases depend on the order of the input. (Thanks to Tobias Rockel for reporting). version 0.2.2 - Fix: for small numbers of records and high number of threads, the output would depend on 'nthreads'. (Thanks to Matt Austin for reporing). Gower now only paralellizes when more than 1000 records are presented. version 0.2.1 - moved test framework to 'tinytest' version 0.2.0 - gower_dist and gower_topn gain `weight` argument for weighted matching (thanks to David Turner) - gower_dist and gower_topn gain `ignore_case` argument for automatic column matching. - gower_dist now returns numeric(0) invisibly when there are no columns to compare. - gower_topn now returns a list with empty matrices when there are no columns to compare. - gower_topn now warns when n>nrow(y) and sets n=nrow(y) - bugfix: comparing factors with characters would cause a crash (thanks to Max Kuhn) version 0.1.2 - fixed valgrind warning - registered native routines, as now recommended by CRAN version 0.1.1 - gower_dist now issues warning when nr of rows on input do not divide (recycling) - Code now depends on gcc version for compatability with Windows + R<=3.2.x - Bugfix: bad range calculation caused faulty distance computation version 0.1.0 - First release gower/R/0000755000176200001440000000000014176730666011616 5ustar liggesusersgower/R/gower-pkg.R0000644000176200001440000000104513452644704013634 0ustar liggesusers#' Gower's distance/similarity measure. #' #' A C-based implementation of Gower's distance. #' #' @name gower-package #' @docType package #' @useDynLib gower, .registration=TRUE #' {} .onLoad <- function(libname, pkgname){ max_threads <- 1L max_threads <- .Call("R_get_max_threads") thread_limit <- .Call("R_get_thread_limit") max_threads <- min(max_threads, thread_limit) # leave one core for the user to control the machine. if (max_threads > 2) max_threads <- max_threads - 1L options(gd_num_thread = as.integer(max_threads)) } gower/R/gower.R0000644000176200001440000001571313671164253013063 0ustar liggesusers #' Gower's distance #' #' Compute Gower's distance, pairwise between records in two data sets \code{x} #' and \code{y}. Records from the smallest data set are recycled over. #' #' @section Details: #' There are three ways to specify which columns of \code{x} should be compared #' with what columns of \code{y}. The first option is do give no specification. #' In that case columns with matching names will be used. The second option #' is to use only the \code{pairs_y} argument, specifying for each column in \code{x} #' in order, which column in \code{y} must be used to pair it with (use \code{0} #' to skip a column in \code{x}). The third option is to explicitly specify the #' columns to be matched using \code{pair_x} and \code{pair_y}. #' #' #' @section Note: #' Gower (1971) originally defined a similarity measure (\eqn{s}, say) #' with values ranging from 0 (completely dissimilar) to 1 (completely similar). #' The distance returned here equals \eqn{1-s}. #' #' #' @param x \code{[data.frame]} #' @param y \code{[data.frame]} #' @param pair_x \code{[numeric|character] (optional)} Columns in \code{x} used for comparison. #' See Details below. #' @param pair_y \code{[numeric|character] (optional)} Columns in \code{y} used for comparison. #' See Details below. #' @param eps \code{[numeric] (optional)} Computed numbers (variable ranges) #' smaller than \code{eps} are treated as zero. #' @param weights \code{[numeric] (optional)} A vector of weights of length \code{ncol(x)} #' that defines the weight applied to each component of the gower distance. #' @param ignore_case \code{[logical]} Toggle ignore case when neither \code{pair_x} #' nor \code{pair_y} are user-defined. #' @param nthread Number of threads to use for parallelization. By default, #' for a dual-core machine, 2 threads are used. For any other machine #' n-1 cores are used so your machine doesn't freeze during a big computation. #' The maximum nr of threads are determined using \code{omp_get_max_threads} at C level. #' #' #' @return #' A \code{numeric} vector of length \code{max(nrow(x),nrow(y))}. #' When there are no columns to compare, a message is printed and both #' \code{numeric(0)} is returned invisibly. #' #' @seealso \code{\link{gower_topn}} #' #' @references #' Gower, John C. "A general coefficient of similarity and some of its #' properties." Biometrics (1971): 857-871. #' #' @export gower_dist <- function(x, y, pair_x=NULL, pair_y=NULL, eps = 1e-8, weights=NULL, ignore_case=FALSE, nthread=getOption("gd_num_thread")){ check_recycling(nrow(x),nrow(y)) gower_work(x=x,y=y,pair_x=pair_x,pair_y=pair_y , n=NULL, eps=eps, weights=weights, ignore_case=ignore_case, nthread=nthread) } #' Find the top-n matches #' #' @description #' #' Find the top-n matches in \code{y} for each record in \code{x}. #' #' @inheritParams gower_dist #' @param n The top-n indices and distances to return. #' #' @seealso \code{\link{gower_dist}} #' #' @return #' A \code{list} with two array elements: \code{index} #' and \code{distance}. Both have size \code{n X nrow(x)}. Each ith column #' corresponds to the top-n best matches of \code{x} with rows in \code{y}. #' When there are no columns to compare, a message is printed and both #' \code{distance} and \code{index} will be empty matrices; the list is #' then returned invisibly. #' #' @examples #' # find the top 4 best matches in the iris data set with itself. #' x <- iris[1:3,] #' lookup <- iris[1:10,] #' gower_topn(x=x,y=lookup,n=4) #' #' #' @export gower_topn <- function(x, y, pair_x=NULL, pair_y = NULL, n=5, eps=1e-8, weights = NULL, ignore_case=FALSE, nthread=getOption("gd_num_thread")){ gower_work(x=x,y=y,pair_x=pair_x,pair_y=pair_y , n=n, eps=eps, weights=weights, ignore_case=ignore_case, nthread=nthread) } gower_work <- function(x, y, pair_x, pair_y, n, eps, weights, ignore_case, nthread){ stopifnot(is.numeric(eps), eps>0) if (max(nrow(x), nrow(y)) <= 1000) nthread <- 1L if (is.null(pair_x) & is.null(pair_y)){ xnames <- if(ignore_case) toupper(names(x)) else names(x) ynames <- if(ignore_case) toupper(names(y)) else names(y) pair <- match(xnames, ynames, nomatch = 0L) } else if (is.null(pair_x)){ pair <- pair_y } else { if (is.character(pair_x) & is.character(pair_y)){ m <- match(names(x),pair_x,nomatch=0) pair_x <- pair_x[m] pair_y <- pair_y[m] } pair <- numeric(ncol(x)) pair[pair_x] <- pair_y } if ( !any(pair > 0) ){ message("Nothing to compare") return( if (is.null(n)){ # gower_dist invisible(numeric(0)) } else { # gower_topn invisible(list(distance=matrix(0)[0,0],index=matrix(0L)[0,0])) } ) } if ( !is.null(weights) && ( any( weights < 0 ) || !all(is.finite(weights)) ) ){ stop("At least one element of 'weights' is not a finite nonnegative number" , call. = FALSE) } if ( !is.null(weights) && length(weights) < length(pair) ){ msg <- sprintf("%d weights specified, expected %d" , length(weights), length(pair)) stop(msg, call. = FALSE) } # If the user didn't pass any weights, then weight all components of the # distance equally. if (is.null(weights)) weights <- rep(1, ncol(x)) # check column classes nthread <- as.integer(nthread) ranges <- numeric(length(pair)) for ( i in seq_along(pair)){ if (pair[i] == 0 ) next ranges[i] <- .Call("R_get_xy_range",x[[i]],y[[pair[i]]],nthread) } factor_x <- sapply(x,is.factor) factor_y <- sapply(y,is.factor) for ( i in seq_along(pair) ){ if ( pair[i] == 0 ) next iy <- pair[i] if (!factor_x[i] & !factor_y[iy]) next if ( factor_x[i] && !factor_y[iy] ){ stop("Column ", i, " of x is of class factor while matching column " , pair[i]," of y is of class ", class(y[[iy]]) ) } if ( !factor_x[i] && factor_y[iy] ){ stop("Column ", i, " of x is of class ", class(x[[i]]), " while matching column " , pair[i]," of y is of class factor" ) } if (factor_x[i] && factor_y[iy]){ if ( !isTRUE( all.equal( levels(x[[i]]), levels(y[[iy]]) ) ) ){ stop("Levels in column ", i, " of x do not match those of column ", pair[i], " in y.") } } } factor_pair <- as.integer(factor_x) eps <- as.double(eps) # translate to C-indices (base-0). pair <- as.integer(pair-1L) if (is.null(n)){ .Call("R_gower", x, y , ranges, pair, factor_pair, eps, weights, nthread) } else { L <- .Call("R_gower_topn", x, y, ranges, pair, factor_pair, as.integer(n), eps, weights, nthread) names(L) <- c("index","distance") dim(L$index) <- c(n,nrow(x)) dim(L$distance) <- dim(L$index) dimnames(L$index) <- list(topn=NULL,row=NULL) dimnames(L$distance) <- dimnames(L$index) L } } RECYCLEWARNING <- tryCatch(1:3+1:2,warning=function(e) e$message) check_recycling <- function(nx,ny){ mx <- max(nx,ny) mn <- min(nx,ny) if ((mx %% mn) != 0) warning(RECYCLEWARNING, call.=FALSE) } gower/MD50000644000176200001440000000202014176740556011716 0ustar liggesusers8d2955e24e739d894ee1a14c963ac246 *DESCRIPTION 83404f04f998736f089f40b74968e0a3 *NAMESPACE 8509c39b337006027cee5686d471eea3 *NEWS 2a15d8f245c2f6d3cd49f98d1c760bbd *R/gower-pkg.R b9e55d1c8f6e1a8f3d03fac3837796e8 *R/gower.R 56b02a814a641257bf78c477a12b4711 *build/vignette.rds b54853011026a0f34882fc97a62ac44b *inst/doc/intro.R b69562b9ebfbf47bbc317ec4ddc75bed *inst/doc/intro.Rnw dc07b683d9e25b0e88c7aacece25fb55 *inst/doc/intro.pdf a4cb8fda8f8f4c00ac14bb7c62f53fc7 *inst/tinytest/test_gh_issue_18.R e18ddf4bcf58a0d66741d97a2973a8f6 *inst/tinytest/test_gh_issue_8.R 03ea67ff7f254975bfd511ad8a395449 *inst/tinytest/test_gower.R 68b9193cbb24435b2ecb773b97b23ccb *man/gower-package.Rd b3113685003a6e17ee83b0a382c51f85 *man/gower_dist.Rd d23e7f8ba6fcb8599acd1f3aa61596ad *man/gower_topn.Rd 4e95da77024f1ca60e63ce4aabf063c1 *src/Makevars 9669dc7ac1254dc2a7933580cf561bb8 *src/R_register_native.c ec9d2cd5fa476df099ddbfdc6a07c8c9 *src/gower.c 4dbc149411df0021bb5e262551d45e28 *tests/tinytest.R b69562b9ebfbf47bbc317ec4ddc75bed *vignettes/intro.Rnw gower/inst/0000755000176200001440000000000014176730666012372 5ustar liggesusersgower/inst/doc/0000755000176200001440000000000014176730666013137 5ustar liggesusersgower/inst/doc/intro.pdf0000644000176200001440000035434514176730666015003 0ustar liggesusers%PDF-1.5 % 30 0 obj << /Length 505 /Filter /FlateDecode >> stream xڍMo0 jU"%KnX 0 ީm<'X#%3֏`f̗^QJlVfu6(w}Eي}iPVP[f9PV+vw)4⥣1pe%orBkr 1Ԣ r+$1Ǽq{jEw [LkVJ8/YHy AQ JAh#%j4Im4jv(bf *hRhQUJT&Y cLJrr~8̀tPd <أ< ^X8L"`ؿy?E_vyXq+W1@q/؟X!{G=`u=l%[xloH |qq8MM鋵uyԮ4!P.+5?N$ endstream endobj 42 0 obj << /Length 1799 /Filter /FlateDecode >> stream xڝnF୔2p-zIhf-Ѳmi'Bo!Gi7o߆*ZF*P2~x)#6+Ltie]EESW",Zj7*2:nt[bEsvC6thgw׿VijT,UUdr73%PKG.LN'8m8/Yb wOonZgڭ/o"ykN(pof,)l_HNP ڦ9xby!\G^wjcŭ P+z\춂`k\Hs8eEPi<N<^# , jŢqܦSrRZs##^ ^ng!]dJkl]xU6vt9wBl :ӯ+7[^EM5Y#9ޝ>8AFEǞ8J ԽW\<##06tB8!PZ s+XV{=}c_]O`{g‘֙=:*t]jR\pUEeē߯.wdi,. tUϯc0* Gʛ09yWϞ]{B֌Rρ74*gB d\IxtL-7\O6r|aj3R'5`j/&b.a*0&Z-rtj|Cq"Bhur)tVeB]duN ^Q'ΥuV|JީnL=U,S#~ j2͚<9Vv SS(2iQ1MЛ:;z'O._9NLaR|(,Nܲbl QNQ F)t/_@ɧ'Ʒ< jzTWUgP3_N=%N=eA+l`I!(/7Bm u1Bی IAG2@ ,8U1.Ec LDQ'Av Z%h&*PxR ΍>SzGAA>U>8/>.%lcs{%_[x{"!)N풚yeJ +c/0^ endstream endobj 53 0 obj << /Length 1139 /Filter /FlateDecode >> stream xXKoFWnW^R$E,Q@"ߙYX1ݝ|e dםI()r` D qLp5Qat*@_@"cKg 螞Q qϘS9n5&%}" e 2Vd9e;YVɫtv 9mi 1yRۓxNe@ɀRt!D7RFqlY7^/ ,EMXlb9D: Ƶ-=UjK&\W`ݾPqNXv,mݓu!uEfx_RC?6hBѝā;Ed?6l roH(iI@smzI8 φ,bLtUģVx]kj1DSX{ r~Wt*DZHK-2i|"gN]=B! CN8qQ;=\/Rlr/=GVaݛՅ:|,pum㊦.\d DFp;_ r;Z{dZÇ(75DFkJ4.O'a,2ϋMj9AHݘJGl0Y]W ga6׿HySQJIl IA;TYWk 7~ʶxduϵr*ox8؎ ,*Y`h 'f̛8~.Xn63z]O--{> stream xˎ8ޯa%Ym{ΞE&d&)wK-J;i{=(oRT"gۙ{!z[fJ -fJ[C=sV mr3q0060n>,Jh^(#lGcXhKP֫-_P0>,6HOAf ;)OA UF0*▱^a-5}5 +Z:z 䎜唩F모M ͫ ^p쬿/3)/fF錠 Uo<ٹ*RQ B3 G:FOD{B;PqΏRA~W`s(8?A gVV; IET e&E~J"UF)2xsSb}tfLk]F=p= #b)3EZJkQ;UʎAŨ `Wb\֣k{aߒruiCͣꤹBbnLД媗zF ӫiw_CRԁ;%`d索0- ۺ u'ڠ=YG!NXzaGw,u:" #YacG m1š93O NVCS:HwEmw_],"QqhPĽSJBWzGFF+sv$h(jeD= `O`PµDyђW2U#p`]i8 J+SAH]%G$ղiz6gB-qw<*^d.AV/)E^"(Q>Z-Vјg-VZnO ȉ  $m tZ#x)\JPF'X g_WT~QH)HH/Kؒ2HtK~)Nv%,*a*wBsAǡX66P;@~1'c kvһcr鉨k.]ZwUïm05؉V\Pype:LJm-SMCm/.am)E9&g} O1'6i[2+E})%|{)_*#\d!XfGv̋a鬸43MoR9 ma@a镐o\{۽Hs GF3: ;|37v%XR ^X(/_HdWǀAw?AngoB>- oWzzf£Oc.J61O1ʞ_3zͤ-dњԐ" 4ca!#7jz.+NuHj7@ FU?b\Lw3S Ux|/2 endstream endobj 63 0 obj << /Length 1484 /Filter /FlateDecode >> stream xڕWKo6W(Jzzh,Rm"+2,e(Jv)r83!WJWfVa =a^0JroJ-Wh5muzhD7"~vMCvO}DfQtTtIU`$ Oiݯ: u\xüY2 m3D-ыLWw 9XLHc4lJK,[Ы֐%~10c 2!ۀhЕl (Z_ɫ'o2,'HO*6ThCʨBi2P_6ّQD" O*o~٦`]ҙ?3 uß#\7n 'zqxXR1T?W}k"B.<#m猽>>;Ybc?/4ʶ7n=s+C51fZKRtgi h++B[*WE,gX@dVp2s̏.4')D7s nss Aʠ@$*Wt/^D i^'ryX&9P㋤tZTs ѣ^ _ʲ۰^;:k5<t^1# ^ `K /kM^' A!+#*.rQC#\LO6wY$;ߥӥEsmjoo eR_)0AEӐE$>3( pt9@rOEecSvovr^dNIûP jgj|'QÃYY5V]=~,0\ńGyhtahFL,03d,(a2J'V<~9&9%]鞅~o_[(KФE̅SQ!%&JեfTdu'H 7֩>gٻےGRXa@׮0Ṳ!P~2?P endstream endobj 77 0 obj << /Length1 1423 /Length2 6556 /Length3 0 /Length 7525 /Filter /FlateDecode >> stream xڍwT6ҤTNTI*]&!@(IH"wޛtAHtHrZ߷Vg3{?ϻpܾgįhԐ,?H(P@(Da :q8!e4 TXPh=r 1)%"R+B"`2e$ w{ r@|.04 FtX nG(`aXqbQR`m/pc0 vM`!`4 s8á0a Cp4u(7X7p пY B.(0a}5F1H\> wCp_j0n?ah8 ( UH!ٟ  S:!-;8P&# Eo= J K`Aƞ(د 77 ƀ`2o |3O ¡XfG: m q??ZYfD8{=TO *)!=B~!Q s j"쐀~;{vC? G]L/R4YewW7]Ξ8>dĉP3ol\;䠈Q$"c0{p,7m~M~ Cb?1, b8Ap C` Nr_ӆD>TPO h4ؓ w8K AKf!d?/ZB hN6qD2)[pm? }@Bk[dS X`{TG⍲2'K>wԬ\g?z/ղy𳩭ڳAb'.%x2ߙh{f*UEA*okcAWMקwN5qVL:fIo_ ͐~e=r< ZHK-vL^E97?MRgVZe:w,m#NaS6ǝ|TadžmqDh7c*4R*:7%v*;O.cڕx=[I+,Dsrkxv`.>xًobB[NZR^ ewΚ> 32Huh5+ nO%,| ZirCk^"ymmJUQhig' 7uд^. >U :}.B VTOR1-w*YcmJrN"[JO67zd:/{7MGz>]~kIqQ 7L4{ѵ,QKR--M\Wp姙zr=֠?h-it^sN k%$Ͽfn 31f`3of\"o(1̝&RCVy5C5~wpbǶЏfhr*;$SYq=nnֽ9> /A5gj}lb!;mC9;5=hRC8R.G& k&g/ӵU|;u L'9. .(9/-C)FӧN|Vѐ$`!"Jċ4DӧC'mI+kPL̲6'lƪ~KKtTg%񨚽,ۦ mE )>J-ޅj?噞z*jN[s=r`^2(FyH3Da0N6|ݮAfQ(S, %e"wP-'njǩ?0"r#gMzC_ ~̭ %8P4rU?''@3Tge> Eƚk&AѲIOyt787 2y?/厸Wl݉op"wu$[2:!$}օJkOMZBbs˫+ 疁CPSlz;ЉERG^rW)Q&Xm [+˓kzY`}{ThCVޜ#e xi޼=,|EC̞f2 .5z(,E/@}tt 5d&F9͔m YBKmw贗nSUV<ڟ_X}zNSϨ/S&+PZ(Yt:Zo,s!_ i5Sb~o#?{/g|xSKFI=N6W!+]wcͱ;ˉ|I@bX8movQ'~$̠E )WWM؂Qw G]x5N5s("!4^fjk^eU;}%9%3q1NUތ׏" x?a)lAAG:91{:tbřTd,tÜO5#03L"tf$2Dmǒ Pe0WəĘ>nRėּ^+䓠6>G;1\ROw<'S$/<+R"i?3ـZdb*[YxxB˯użb\-@\55+8JV]Q#5=./LH wy I_iܠfz;f Ta^hNyA!*#J硣]15y^CNf]NJ Wr "fr"s >S~y4z֘/'Yj]UoxJ^~$Xa/T*%*դDΔ=2z$%$pə+ZQ9rj}ٜݛTwR%jFaֺ@񯕏[F;I a.c*11(;;%\>$mӓGO<_҆k=HĠ^t?ACN9i-1Źñ>6G)Ar[xk_^q1Y|mPZYHX_͎"p]s†KfZcٍgcW&=ow0ZC|,^c5ׯn ,,^za݋eU1?y-s>>*|Lʻæ ;;%]4^M#{l0Q9vpp}&/zΰߪv[9|ZvhJ@F0V%|p:/xW wA+]w8Clhg_YL5|sq_hAB{?VYi7f9+q U-BVB. r1O}e]P` џϻ0M VAE` xe)[Q6+`VFvV&4UucۋDw.ڣ/bSsN*6 `,5*C^;@i.݆OcAO> 2 AdBϝN׆C4O,~+P砊@ m.5t85`]L2r;oIt~]bYr֫ewfW7>z]LhEj$TEbȻvWŔ?iN=~$Eq$+ɾ{={OXIbv)\z [C j)^h0^iZz-n,rվ@܄E4FeB>[SvɁqH ehGzycmNݶ}Aᅖhq|- ʻ .{IS㡏=M  bqo$LeC}Z5}õ5;I'g{:O% c<4il?#k]Hx;f EP\ӧ!);BDHrmmGk)$\*2ҵ's50,y su "Bcg-3OrViegб6?h3]+,g`LYګZo#(Pwr7hoR3d՞W=^fݍG[ @ m|y`5& x~H^`"׃Aa1_W-=L &O*_(yxc{6~-ۃTtX`ҡ.Izg`?>ޯNbhv@+!]oL݅̃˜!g~]>?HǨhElUۊݐ־%rg=`:5A垲Ȅyջ #Iw+hs_iX2%ȫpM޶,8/Jz_evMCUg^c1g^.OucY1^"|8u! Vx* 8)3 b}8/ BǏ$(ō(w $EQ`]ɷh|NS U_Xȯau$_S}ޏrϹ~XTK’&zEM^Td#{@yΛR5/;Ĥ|ӊO:̄ӎgb$aJ!_U^1?TI~Ŭn<$ |Mi3OQ}WZYƨ; + 6龌 w$#b=ȓvyx5[у0AWjESlcN5u2C/z.xg~мM۫z b:1UhfzHVE;'HW{b#fN&ϘŦ^REdqbK,f0b#kFK4RݪXN <C>d,$>$OᯆPRlySQg^20V>xb.}]s0XLqXԑvl7jz^59h6u2q9\Byd}L|Б uйqFƴ4xCЏc^HѠZrJ ]{ 4 f'lŒ e (qvklo<#"M o%i&{^EfA;oR}f?Sk[& ݿ>Ǹ9'$pJ=nM,ڗEGk_͸p*tOn*3+28?Ԅ]7^Oi@*0O+\onFKZݛфpeZV8dpy>B?\ԈgF~|0+MqRTKCvM`T7C#Zicq}qMG}JJ5*o'E,$awY[,OS\%5;ԧUh3gfs}1b-6u {l{$wc6ً'Yl$ DCMm{%"ىhw{'S|֝*J$_o="& ;a!t՚<ΓT=\v>J#d.W%Iv`i،wd&N@? ?rgƌ-+MWL56M SwYROr'WEx[{xAw="AD=5#̶0I7js@#,APq4G+쵡V5L97;yֲ\:( qٗLqRk,c%1:PL6TOZŸz}3bGQ,Hkkv*ag X͗̚vil\fex;4â3$* ZO3QQ2iR#[ R6Q7ZFe}JJK/zL+R F޷o묪ER=] u6c7o;khVm>;C~nbNÈ<ԦȉOcTN Tsʨہ}yYMci8v+}EGv2jT`I֥Z2B͐ViXfdћؗ67RY_SU V endstream endobj 79 0 obj << /Length1 1398 /Length2 6731 /Length3 0 /Length 7687 /Filter /FlateDecode >> stream xڍt46!0Dw D'!HD Ah]Q{ Eo$yy}kz}{_Ƭoħ"(>PI$CQ0_j)EA u`ԵA@H\JP($((/GR :u8pEB]Peur:pA⼿Á $ Q.`|Srz#β\@o(h _u?؀.P?z#0q w ŁF@=7^_wNWDP` NP͏Ap_`:;U  uCy{@aFUJWW՟2 qv_?}GxpG_C8z  \U!(08JomR_Op:] :A`/:BP@{3wk5||$h)x=P5pW@MEBٜ>@>A  dׇCj?b5Nn_{οg.]5j!@JPT?Cwῲo T=af v|r':k :G[5Pk"(a_#Cqԇ\`P8DW_kj9<~:Г=+ebZAXgV!l9#4,x(d;>$Cd^1i&7c-NFS#52a ܫgAN\^XEadѣ,!G ?]ktR?4mvzaBrpe#}(EqWUbsY\7[2zjR*hT&3 72tKÁ%3[ ~?{YStBCyp;dvWޭaA پMu`^!Gƌv>hrLSVf(d"[5c*=1Nпr.ZU4m4%@[2 .gNBHceF8(:?ħ 0Ir]+k|PD[BL[6FFGc U9{{=a ( A ${I&$Xv%S]Qu213>[_Y}\ܾxmOM>2"Q_ձ&HjZuW&JX7*Q%}iG/;0Yͺo[֮x1[iԾy윲}!Npnўksx/YQV kW,´pR2͵hwq5Ruk(Y(e5NrGkqD (geW%SY6l Czb;iz 9ؗEiЦz" ahf<ҲŸ_q%jk!*nVBEѼՎkT \bW38wCJ=kRuz^߄W|3!5 wfmEz%N?Os~'['Gl]3Bt,BN ZU:Œt!wIgJ,(ܦb—mdb2|e@_bǵ3 <2ES;fojʕ;e9 )6$oSA7g5h㾥{`cAvՁWX ͛v9A rI>NMf?&;Q өꃽhMz)m߿h(1r:bux:݂#=!%Tkc9OJ格Eaί[ݟgQ;R=6α?{h96gNN3WGRGX_E @{$M zI6x8ƥÉoI2hgZǑoa^ʍ1:j⒬Kd1gy8L;J ^UrOF`yC7O/NA+29hf}|[xDr{-%-+(t|Г>E сSPy- ߳YFa%2?|X_>p;?h҂OԨwRнɧMOy!wv6bҙ"qU{twZQ3;b̧)jl쳁[b$]ћ!O'{ҷh9nH-p5))-WK9i~##1GN,wzؒg J~ҽ'~ø-xrA!]7z 4Su&ß8w*Yk!]nZfɱpzjɜEPgI6jwx&/7c0ck/zMŶ搯RVx~_qGÚ>t?TKBci6[}lu G%qcq ͱb"Eg8aU]YDRLV[d'Gr>zQ:HݓYx~4nWQ%fQKH=Uf}\K<$S5jѴ-ܶ.Q`_r`ٹjUr鼀SljƗ,j%N:\VVUc*cm=`Vo܎Sc=#o/(qA+C=-4$\hLݺ/wKh2 ^+(#a3 νx<$VUIopsv^wKj94`As9C-ݛ)oT^nsl=±ˬv|zDw:#bz$i؄͵RnԋLrBB漢6^Q{aԤb²"-Mƚmh(/TOS`cNޕB3阊oH8.tTBװGՆ^dF-u=0s&d7F>W|*SUKu\9z{Fx6Lx9۳yZ*?=S tYqB;K=}׆m-sb7f3Xu(-ZݱQtVx':kN ,n^jk$3GY|p(;x0g"NZj]JZx^Hj%цb X?Y.wLxGTPĚ觼@n%ݼ {)&'.Y<&^br`=ֲUckK}csZK]S$ wN<3Yz}νॸ 4V7:DY$S&+~wmCKǷe7 Y7jߕ(+G.t:~x, >{$gSna׋3T6 Rtgnoe֜4'n0g,gXp.šm'k&,y}036'}zoTŕH_UtG'AԎjڣ1s[ҩ"{MyܖH$JNvN5B'/sRoF kK4ή"V=:Z8NƹKC(Fl %R2hɑi i/s:IxɨG ОtkxK@;GG]LH zY͕QD՜~U;8ȡV{ý?䌥TWuo=h,)s3 iqQUrh|c;n eϲ#BsXÛJA+1]vwMjhT .60C_I/$Y!n I2 |YPeasr\vG~4TWiRDNxilǜT[,n5 akVLӪv.9n,&!%Xdi1O)Ŷis2UsTH'(|X=Sec2sZ`F!NDbWL 7,}R^P=%46\T1a}<.(] %KҢ =jZq{G>4eh)9M~P:@`,m(v/T.+]XrE3;| ]K-73{^xA*ܙU>˞iXJE-Wy)]oX{z+[T3,&\&le٥[N?Iq,a)wpzOI.r~YGbzlqms ?ñ%^mLaLuЋNgM]uxݟpLs ?49\j>K9z5IlNH٧]c^weiHQdv墜d>*؎Ojz$ORc>$岢D᫼Ziq(LA 'Q ^O#7+*;tōʱRI[zR'IWxwl-p$ e D;)SI]$OZc? R鎅 D'b1xĞ}Mgwd+?0v$oJ tztb`b%K`hhbx4]jBl>AkLH(;︠)9HJ^GArP|a%}>OOOG|=w06K:(ƭ3uM0,IkF|k(-Y/TrK[QW";)P?G\RY7 x׻ܰ*|[BFW#R3/K+tokS7虰ޚZ)F/L92ۅrsT?$%~^M EewB*6I*w@0z{z $ɍ(͌Z-V1id+ endstream endobj 81 0 obj << /Length1 2091 /Length2 12186 /Length3 0 /Length 13467 /Filter /FlateDecode >> stream xڍuXkJ7Hw %]0! ]tt ( " ]gǹf{ZϽw5$ 93S aFױ8h@nv`gH, Pj v(y8x\\œnNN݄2vVUvF/ vq@3dp t-[4# ځ >Qqbprgو3 -;d6@ Osh[;U`k8AP'g+Pw9m+?ps?޿9l\,}mv ; pmh[xZ9ZXB * ' ݁nv.wvw;]r4 qG]?G r휭b¡lRTGf899 rRrCsA4?w O XlDAc( ƜPr8y2 ѕPfRR`o7'%o /WEgk0@zo͞! Pn ~qf_._doMrY0ead(= uPCbU*B,k!l6;/b;w9;ohM^;G;gU`?:׉;@U߬@XYqBI./>8؝ ahE!~?HB8tAB?HaqAv!<&? hI4%%NNտ 4%z@9OLhjk;Oп<Ah ? ؂e BZSBO0h,g'e+ h_jQCC@v2/;b(79\[и= BTă.8 :(_9 ^9@)猡zn ڤ8OЙ?Kp n_o%D[E?Jy^={P;n}Q#v(#ͿL˕6WL$r`GŋS!=fU8qKG@)uŕ!(v$ hoU U}I.􇺂c0` }hTR[%#xUs}R|A3hO?- ;Gl;_uv~`ػ`-^POs$lx|I-;nTW7uaȴG 9*U'Pv4?xwnjĜvQ|E(yqɖcgǤ9f $ Xh:Jz{8' VtD7xuise  }9@Y9cv -Ya`ߔϞjqI.2Ɇ JqP*6:dlIӉy=wgJL.j,l^Si؀rFvjt`F%K1 cAX8Y",U|ւ;-?Cl\ i8a% &V#;1"ϡ?umI06"Fhl!,A a4҉Qp?>/)%i /aTO:y0ߚ֮bi)7&ChñNߚ:'~h`V+Ұݺ3$V3T2;;y8N)+/#pw}m!d!pO,wFalBrh$dRe22|=~ͻ4~FMsWXʽ/{ogjǕg4HAQpo3moߗ]2l6IԪ6>FI$Hҫ/(z`wP*n~38D}q-#JKuGOk~Le{[rBuӈ,7i/F.>7pƇ 2DP)iXe,~D!s7`E>H > ?-&7v9lh!: <5)AME*5NCž"׋8/#x ISt,q=뎃o)7r%kt>bQ/z>#b UѼXB|E{hB(Dy|hO"va#S}-ě$+` exWt..(ݼ'`n8;qiydz5Ƃx *[%9O zG8jRM{SNR>7"=^ J}t}+.:>:+bz˗-hpRb*GNdbХl_Oa3,cP}ןp-Gdi<_i^f _-g2 )Rsͅw^6"khHW*xpaڱtq֡ Q}+>*RDx=ӬH['N$R(>PNhVglҊlGʀnHX;v,i~Q@MNQ{F~BIXzR,H9=}D6 /w9*1K5~0U %фh]gK}dNC8)BNԤc oG``dqN:NK=jn&0+؏zwIu #|Gp:Uq=ga%VYQF%Z}sM*jD#ٲ-:ï瘳&v?JZ[<c~ԺaG4nv~U=,AygeݻGtѧG쀹t2a^~WU <.lYb!ݢ=3J7U6*- CC0O1_6 釻 KƓھ,Gʟuc{Bu#.201܍(6Էq^ 琢E&W*x)RY8vik;雓;>AIϜ7ڙp!N #Vݵo):/Bѭ^u\hy?}i8ڽU1K:GX]¡8ÔSWbrbh$L.?Q!8EckӐ'cw!40]"m8}rc6$ٜIJ|:NT1zN֍7ts%xJ%O#Y"@ڕc0۷}mSmU|t;O%_ky[Jy"g?al%TX.Eeo736zpd'@_C#UJºE?f?`˽Ds r k>bIV0vl[ւk3Wˊ®_+dۃ㼉8JԘneYeZܗ"G=͹,Ty +8\/X 65 I6d<hY^@(Zb1>YD($ /'n ه҈5yc̈́߸V9CjF̓ft(<G,k CȌ45JC?^0MB2* ~kHiڲ/ΏxwOT |FC/0*U:O= *U LT ,~F8De)lֵ+r/Iҟ"1y1k iȓ~L˧U7OTOj9~]dSL<.9[:wÃGdq~+n_iޏ)'8)XI}S0BrMz%4jm"&Qij~$-A̲z;wSSе.¼=%"B>TZV\wL?Ͳv /$'ዏIztE#Hٍs1 pmqz~THi yhHq@znK$"FT8Eq{J t .UYj%Y9l+G,gez?}㵅ve% Qlx3d <[I';)sz!rs1VACuW=6o5;j+k bew@iI #&I*z"\HpDo;_5E/Hv(Q."Iz\gNM6B< "Re4Ai6b龉먕m_b>]'|HJS$5yqy| %"|;f,kn"gs猚C.dZIp/tG=e HNj$4pHhEҲN1r}FQ{9O#:o,u V)8ZKr=7c쥛O=}_XVQϦ lVj:l%j?*7bw/] {=5dSUw$"LswT,&lZ5^q r'\1[1-?V!D Y$+|ybݯEmrNJIx d9MU)tpKⴛ[9S*. SL{'sf@2 9~ jA@BU,K[ zlI7N?/CW=?7}Q(_:RBdfԯNZc)Ⱦz3N'VޜK4lDG(Vų1YSq~dgec1Nlʖ_PGsQP"7[Os(@tUB1#I[XRN)NrUUH=~]Q,8{p>xɩ1Yi^q澝h)L qdP'Wx> a_eLJͧ;6Bkw6[ D{cLl9foӌǞUkP@K* ojsj]aL1BCY7G˃ѐϭQ PѾIu>]FL;eL%{[=w*uNLr|^vIfWxB۵2bˡuQݻS15qy|R&D=`۷0 Ǝ:EJ^ٵsz| WԌT{j3y S7QNd ?\ K6~ӆ(bauܓzl?9JU 4T;|g&8;,/Y"ٚRo7QkNSi}·H+Ky>l2/pw>᫅ҳ"*yLeT(s=S4t~a VP0~ h׈'T`E1kF~Wa'?p}yFW3 m1}}U[aU(WOX"~zaIRLO;/;e~rI~iBʿ.RLc[E}AiM]"+%2ٛʶR=0~tpT¸?y5xjxXJOFvL{ VQyŅeXV감2>aŏԥҭ$QBt"d~CWEM2wED4K=K ~[ر",z#hy{ _ )zNr$|ߊ1!17WTٵ6xzyB]T.F؃iRH[h6/_K'T}fBqTRbw{Ȥ0i.%i$UB%$u|lײR1$;~l@1'4n|O%z<<)c3ڧ."$itVBi{Q6("ߘLoTxx6/|k*N2 vH#[Lsm͔ѠN˚-9A`* :ï>a$l07OvL=(}1:"{m|,Oo~/ tSCHR_ifoy-xvQW+[ɮ {)w])ĻSkGOmC,h폔j|WDWk(E{B*S*igeņ{broֳZCW'jbR{vnuMf5s6Yޡ-CBrEp9MnH bNCQR'a Y7["M`R"/v }`2Qk_zgPi(dt Pt`ؗ,o޲ϟ=8)!ղ"|WSh;UJyx'ϬӍeͮg.\E9 - [8cs }#UF[•)Tܫ@ޏ/넅Rfb pKWX2" _tC5u4 ߿H97P~$N~\]|V\؁Ğ& 6y-k#L-Oe! };LY v3vDvDAQy"$񥟎CDQپ*97;98>˗^FxCkFn5wx))]d64*HMt+y0éObٔ.'I^۹$;#roܿB(_s)y7X#-|Skg!CJbټ9*;!xk=ErNJ]CS~b2_]IBHta$ `O< c"7.|y`Y `v_4t[w?oDÞ?R晾.As7TfNR!VC̱5њ62D/Yߏlx.38$:s7fXzL&12? }\.!Q/UK_ Z :c J`AÇMqN*C@U3DY4uGo~J\X疐r9ԾdtX}LZb YfkGd}#Kn+c 90rQEEOLܓOi4?"p3.X*)~[@-2wEwʕ2< qUxwAް|i('fZ#j ~AǬpEXoXV"k6캎B'ӎ_ԝ"7"*nQdۿHl`,;hN7vAէv%$ /"U[qcVB$i{S}B\(/Q,:T֜[@\6H=0joڼ]&ӷ+\^[R'W.f3Ei,P.6僓r eH:bH'w!ZSt+®.J\ZO T ?Naxmfۉ-7b@&ut ,75v9r2^>ϯ2nX؍$&-ue$ȋ|d=^>b]7G~&} s%Gme %ibOk{ǟpU(S4]*a#^vkV⽙ų[^K|wGh2G7ߘ 5#'n3^x&_[Qs2g  0?h_NBsr8{^w&ؿM`.1lA2tHDCƊ/Ҡ,B'n=`uQM80k[( g "z\~pԌ\{/ހ1%#v7[;CLd?ԖZJK>ΒWl|mPWd޿~uc'w=+PI^4Ľ.|Q@P'#KW? lmt(i'K)۽*9S~ PMÆo7H p YVRY4JWQ]Mi&ڠ eEOTU~V!T|+8}b(>,q* 3 7\ d6j )BY+y7øUbrHuJrPֳ\z3r*ttyZEܢf4.va .{v]&!QN~_w񊝺jUY&,4~p*8Hv)$T "w>gpXY^eJ50d n|D')`FpAκ9Zn)b)/샨 Bփ͂i6,GGF = C  ic)RdDPEK `("/t* J_-t%ؖ҇Xq_JAfXctK7rb-\6,mm&ؠ`2J(ٛ}xˁ8ۥݦwK49)]4oSdp zǾCN&m}YAJ6r?;Y3.J4;w-Ŭħ2&[UY^ow~ylxPbt>v޳AIOk>l2e'*¡kڿ[!"m||zͦ-lԫ64H3M Լr6z&BS}>T]k~ި=ო5fZ~ߴ)׬_R4q%L2̏K"W>Rd/0xGk髂.yZ,o0Jÿ BUb8tKj諳3NJY)L!#][k0KO^x|>̬A*Y,O}AO+<?\ '-sULuưg%!?<蛍u'L^# bvGr !|)bpئU9e&ǩαw#{b[q 'hwг7٫FDtj ­HbC(YX a:+NJ$ճDb]P}\Uz9{=#qgYysˑ"jWcEmUPUJ[_u2# ~nKW 5 w}/5O}~u//F`rwypW ̧[ I(%K!3ցA[D,7K״ d\quJ72):q*0szu3#g| \*!5qS^w{/i) AC#w`|{O/y9}ukXyQ6lzSxyz?.o:EC. bH}&%z\؉)+V3[Eq@;^Ό\T;CCQBUatw[y _2 !uP*r#%]X̙ʪ+EBI!fU| cO΁B<۰>X3ҝ ʇ4K~8ʠP!G!0sLR IWe/ti/ՉfD>OЏ?֯C߽{ +)/!~ Uq4)**2 f4a/-Q*>Q~'uJr>Pgگ!*o gO3v/vXۯ\y_#]p=Vh>g9-$*RY/-IOb4̌r5:D >LT0pR @SzP[LǏP=Qr}ϳLk KOU;z`xY*@. o; բO4ZiC;%8+QiE*i;aXH=ZS5tjCa47,ˤ g&kr 6U*⩐$,9<6T޵,@$%uAJ8F>EKn i_Hi9`G KmwjY|ցz(5#CҔE]8(]{0~=eљjyvNJryƴ- ?E|.8\E|gVGVjK}1!9pc`m,'/FW\fbt1-9O3[>TΫk#Nςw >#+*A%?*]Ɛ%&ʍ %׀PK5S%@V>/~f?t>~@^nh4rI?9PoEdD.mnO%]GCK0%U^;qt\Id>E endstream endobj 83 0 obj << /Length1 2318 /Length2 12500 /Length3 0 /Length 13844 /Filter /FlateDecode >> stream xڍT6t#0tw 54Ht7HIw7HIwwJ{_k<~gAE$j6J휙ؘYlVVfVVv$**5 ?r$* l#"0vʃ2.667??++?`G~+  KgH|КxrAvycgK-$ @l :WZAKgg{~777fc['f0# l P:]f_-mƌDP9P;; hqq3: rE{r0!ollj 7sYA6@{gF/Cc'0dcl1tc2?9:읝@6zdB8h> #»;?õyabϢnrpJKc!Y\ԒW5w{_J_bH^`{9 d 8;sZ:Mfxp"t#]D<-JQk,i[%y\zv,]R9%,||JHgWՔ pƮ4'XH{I_M9 F+J&ʓ>7/62(JW."J>FTP ăT=V[#27؟׆u Inbg'LZ~06NQ?od^hfk^[ 2S,?mqVxZ?Hſ\;~sGraax(%'ydఛo[NBKvuS3V@n:;KtSvl@c!,AR9H+!lIް/ ԃ;HK{nİI&ϫ3X nqj4Q(o3XsYV>.?־П嚗WQ3HA-zjF0awh%x$8X>Ge"\VWd *__|Y<0C>wtZ4ް;!Ě]"T1vl]0k%-eP"%OAG`m:pc|@I\%3W9HQg<_lڱ r"1e]:!&!v-M[ yX/DA)Ȥ&Iuvc|JIf_jĆeSfyRCr`߮c^G,ÿkP}9g0:9ܙ᥹l&`m l}w&@7JmOR-|]-Φ'e#Wr['MކZ qG%Y^KE%21:8rl{0R Qx}۾rmt`%wn󏑢0HQ`Nn6W9"VO7+Y|vMD%Є:tX=8Sae w{.* S @ ]$X/AeGgQNooccq#4?9 _i^z2q4hps1q8(7_=IUaO-ڞɋ.݈h'" W5E+){Nf^u7o*)XIF)'lyqLvuƔ-]TyB:Vh&~7`cGg[D՚0VvAcЗё,hkvGA[wjy#ӈWǕq_z wZ6{ @^#Gn9C zFnY^{h #YbHq.Z\J48hv+͞e6\lq+DF%@G_ sGR#@sh'UxiJċlѪ ί8S;c0 ; tOra1aR@ՍB>%WS޹mtw{[bi6߁Ỹ= ?{vUHqg7PKp|̓F%˼*zx?|}AR A5xyT)qxY[?M-6Ứ k>+Α^H7JSʬ(Yn߻};Q^.R.e 2$lXkI/sYh*K:_?8.2=WD;yNHv5z*޼ZϤOv0(\:/F xG℣}W탌OjmHx ZKdgt5dFM/akTRܧ_l78^chI}Cj\n)0q?U9\% ;(ȅJ-*o9LYn%3o #%UϪ_fvXNvxI1_s~{w=pGZSqn̰1R!M)_U>)㷋|ly+6$Ʊyx^xv(h~z:D=7pJv~C:}0QUw8B v`iq.>[L :s;ad@C­GQrg:Q0\(yUǓ}wb˥Q}ZLm;݋]&ĶY H0gkuW$71aOur3Cpg &IJ[#uEE;2&Iw啴6uep?_ҍ6T5>H#shL2@WBha \V`1Bjl:=lUQ6Vtb;^= I@Je1_qHGA o,c&Q^qJfXӏoG|BuQɄc~ۤ&p P]8jVg{a,#z<ζf tFܖeHFo??FIU3C}$AqnhmbMA~zøpNP;CR4eΔ ,6ݘr' 9' ų ]mVzwtAr61ϸ}߅kOb7vp|%:9\ (_bq1قA/q]) |,mM[Ykck>ƈ-I}DZ=_3 S33%=$,#@#uFTf==mo{fI}чt7eQ-গtc (~cii+|"qhm"~z:|IMBv.q#1ln"PJyFvW.Y'% #gyH"Y33qRH?!kQӪ}C:'l `x09kDV+9sY7L<=̍) &CYtd@Si:F W}"5=9J1[BBs G`2vخ*q8L1o0n9"ˤ(of9z{qL:nBHD-n 0e#IRGg[CzHVXPJ&!.uw3ܠߡ05uw v}PmJ?Úrmn!݃$WVQ&K):q6=EëM k$/G|Mv~ЎQL/*RGbUo|13/Y>%K-ftGZGw?EߠM HJ?@^g]s:&)D#b̭6:7bBX7:s57hklKcjb3E`jXTazU:S`'/Y밐 PYB((~D4%TkWc[S3vV+ ޽:;\SS (=P=aָ#먍qiq&̃$8Nk]cq6+j]S_|F|pplٺ0"laT\u D)zĂ5#t~6@$0>wOxkąQ4?js㢧b,N04bp&`w0ߝ U40{1֮Y:ᐃH4:]3,BT:Oa3Hn؏-col*#86o{+~Rz|&jYj;wlHcf|6:5C5@ZdWW+Kx`~6vѠDZ/ԲA1Iz|}pt7(|, a!~mXu'1oN$7Cu>"'Ifl.<Qv萐 + "}-Ts zEi‘@M5˗m=@FD9! ]s(u[%LJoJ5޺ WI"WʹDΕ;#)RȄQՌ -?1B2=לEHQP >wgrwsv%dI>h:TbR =)ٶ!* \ngP gh`+Qip#b4dK∨+c˜ZF ]*2L%-7D&„&OxbGx}Vt);P1F?^6*D|TUf}.·VE1-a@ocwv7Y\d|e`} cmy JU~oIlj}쇶̀kwq.߿q}3;*J"İ)󮠧ML3Hcm!}v/BQL7'_V|1~c.E o| ,/^2RUz)rp "aG!aV9ASfP6M;dW4{fXxa# M|Zʗ['Yrt5 K'z~ L ҝsng.ʹ,yڜRt׈] SQ/jtR)l$/~ =@N U+m$ ?[ϥ.&{4FikiP0}Z~='`qBdu&PT:$Pxb^]ew^OG}xLf IP_5vP o^i1:δإ\Faz9_%9 җLPr͎kJ3G507$ (vb}uY_#j""2->iΠ>A@{}VP2W p/P g舔r٧qW1aɠ`)n"' \,ԇ-㕧VB룼Wy]U !m,Q3/\)/4b/V׸O;pfXx=jDkVgvmS8-xD~XU(dwAMR%'R qp Òxs]mă}汛N0|"S\#EښwTt\7=R~yh=/ʛ_J{=ڔ,K~A/id/3Ӂ{脋@@`};&WF,LfOSA0~M-"v6N#^Pwu`)xE%T˗#(P֯Px,Q^A_.JQT+#*.9(-g[/H S fG76h38{qVΘ1=f* Ya7I2aQ>5YDPHwD6$ nK/J[RX&RC$b;*ى'$mu NOAz7FD=΁J'>_Uy'NȌo a"bi^F69M,icH98 ;l舲l#VҖ`Rlc-A$%rN]~m`WLdf6iI:j]33]cqJ[⊤ܹ'6a o ;mgbW|_$T|FP`Q_~H-[lade?߀C<ё> ȵ:Or|R AiqEwzMˁз5cjea9"n߹П_(^w&rhT\7 )_q%~߀-TiǃyCumNjmchy^_Q2$gL5^`R״iUt:+E4BX}V,gT eU~$r';%ĵd+H.R(.`=͗X~LmxV:V}Vp=o#O Z*.TC`KTkXէߗ\_w.ICO L=[\mbfZ*!ŬCG;7pf}׬>P":,;\l*V_(m) ?0AŶ!1a;Dle#0ؽ_sďKaMK+E+0p =WXb.%S졣&GڑUЦ[{Aۢ"Jz{f n8ܛXvklg~O;ܧwJTCjXm0O2pۄ8?ʚ皌H~ JN_ ,Q)6I#kԗ=ŐI;ܭ57qvIn{8D\H Hysh!8\r8$w%JMV,I{|(毛إ-mG5p'Dpzbw@zʥ8d74scOׇme9B3>&7x?/ 'I<<W,3:kC9Mx@ߵɿ 0:͚`q" |CzgeÛN*QźL_CiS<#}%f n[.bm0u&*oezJ0V6@j|tvb<]̫́ &3 B;ݩ]+}ΰ򈻴t>c]OUY_4RHB{U FY%H’s!Q_?U\~QN R4Ƭ!?4c˹֕~Y:˝Igrcc+l01{N6Px93v0 (݇u pD.Tb4XP/7w a]Shy;YS>u7ewQz]k~W1YMtMXr~%r>ú6iJWKRޘ<="cz^aAd&s胿~M>5-UQTt4C4K2D#UO` :R~_rƂ:UVq-iҝ"F\g`~f} Ə. Lj/(Q6Fbb2N޷3 n{:smC=#Iw C4ld7eLy1m4/4֚ei:#숌6]#˦z5c;Hg^8u=? ,?ڴ﷛w^Ň}1}(N$TR !EqK8|ƴfY+[ӊ M(% 2I7<ҬT&Q};1hB0P$oȬl;'AIkw ڴ$[&$ݡ2߹(_hJaMsV,F:G΅;(=}-[-{ƪh")4a5z!}6/2Ģ>/VTV8,5sTr ߐ];Kd)17iIG]hnE2D*$O$ )YD54XD)=L@[2Z1O'x1o"Qȹ[ OazxXO%Lm>ĚH!.@`k! "PYwSS$`kڐVWbQNuVEoˆ2noVWų9P0yq;'C+qٹ xx1;٥]%?O2S93!z_ŋʶ&?\ m y‰īp'b> stream xڍTk6 R" H) 03034"ҥttt|9=}k֚ys{X4uxm`V` Ȫ @A^ PEtǎǢ# 0ؿp0Ɂ( Pqs EĀ@(" .Cljcx!vH9y[sEEEH;kBڃQ'Z:0k_)%H1>>^3{ `nr/ @ӡEz`C7 @Q~pC$ k8~^;G0zAv[6 ' rA@V( ZÿCX!.H/GiPcœP$w}r85w/^#@mla§LxH| ||rmFsآBl< @>v7@+Ovl'F8`Dɏ 0OHYU]믖v<><!~SSA*O2ZԘS_`k?8K.MB@k,WoE nNN$ g_ pݐ%PVT🛫9W B-4AB O&im^4' C@~-~ |vD(pQGCa6L@HA^x@>}{!c/DPlapTRoӟH$Sg7zx{Q(2_E (!fÇw*ۿ V*?`5Zk78u!`O5Z<ġ*Bڃg}rSDQGu2v⨫M)E_TaKjAOӖJH4UC잫;0 nH$9b-Z"KLW"e?nƢ;gsb錦{QF ^#S$p7]e{Q2 єW^&S{;;sTʅKCI)ɼU2(IW@c:- /6Y2 76/e2掍'ژ,UX(7xp̃QsӋ"VP-ǟ(~MD^j zT߽8r)f/kVCz:i_ =>!b.qѱC\ٖ[z& K8j+D%FF1/6}l~O=bưC $n^:"/ +WbA16dRorsڱ!zwŞMzWг$A3>Wr5l캝K<'R}׽`Rqk;4m LiJ3 ـT~?˺D ǵɭ jI1ÿ\er:*4f=RT2=wgۧgjSe&B᯲ 4^r^׫gY ju&h#_8vqi<[nYv5k݌m^ Y Zv o^{کW=>y-h@3D~3]yd͕n7IpNxbݹƈFq̔]hQq_`&`E<' ry#񝌍*7 hD6sUIY (OJxg5],&Z/{Mos)Q7<ӛfi;JT|&:7wq6q Y澧5 :KJ:r/1QzGGؒ:ݼwO"&ئR. ) 0G7Q{vrYs:^[F_ |%Uz(6ZkJ̳k&&_f}q,Mޞq|@z ÓF."Ĵ`$gެZV̸ehiG t[Pzf{po4kp4/|Be"4?}E:Ip#-cv{{4%?knnB,W!lEB}ʙj_~޵IFU#}u~G#Gan˥wV`gVebݹe˽`0@HROI%:(օ"!ftBot`]̰2]B#mfn%^V=OV0U&ұjG;x)7KAYG%H9P1'kw GxaŹ4 Q0ǎm9dY LN8oE*-tkf1=Fh׬)sosj<3ʔ bn0n\D?blBJ.C^"D#QX d [u'Rߌ2]".׹ludFEsQ,yb1E"fdE>s)|e@glf9V>۱T݇l[[nkY1ה/[zO=4\:A ׄO!lnkG'@TXI0IuTb Vƚ'1fhzAȏ6YrF9Ao5>(tKy @t6& OGZۛ$KSK?(kMaT^6|yg?vӈ2yhb##H"X~'Ebmxni3AUcB|6TG|?|~t0?O2>66s>^;ւp|8qlHǛ`*`ݎ`S?AHTMD]ԄJJ-+Yoޏ:?c8!t?IבJO5'pGm Y^~"αG2uB|z]簛6\kvLū3&VpX`lnQUeɃ΁y5#wfg sWɩCMG*ΟoN{>HXPV\"lAa|VDj&y^qI"TkϘXܫ\zȷywܞ=}`t)hИ"c>{Ju=.e}H8-KUI)lG-'dwU3% j<-C9Q\"!ZZ hn."QY {ose7@twBSO?if1idU\aK簭i˪ ` 6xەh61Um)G/Z%L>n>ɌHc A}t.oVh 6<._>z)[W>1|yG`dy"XG<~lw_y­L>*iBcY}Z|X;qm8x?D6&ŕs8M^i,H0aI^zbw#&G̎k)^Z},hGU\r)2%XL"_Je݉^emOϳT V ˔Dw߸g;j v,ϵP-5ꈬU;( JY!LJ`#erdG=$)y2 k*WnG=c#UӊYwe3%;S4m~BYtXQEŎ$d3oJoHV>?/b4*r]ʯ7ѯg¬WžBqOl?d¤w: d JƱH, g|(VbO°j; 5uRzqgF1!Uh$Pe4s{!澾托8:a"]&=Ko #efܼe³ S 6dc_lxj졉&Z,(uV"OΈi |\YnZVdy>$$KJ-ネ^RiY;ڞjCFh/"/T5oɜ pggjTf&iORpRV?,wxC50wLgx7.Vȗͫ_&ͦe7Ϭ]}3r~gabQ"m#GȷbO3z~gmuat!w-8jeaOtg NѩKvQ8< Wi{R:Ș=j#cUZ /HzlWS)| ҏ #0R{@2sy.m貁{IT5kOޱw=Z=I{TMoDq0q.<rp{!,ۮÑ XknmkI`+J PCOV9Ʃn5jkxnT+K}]ag ׿-6s*qovWwfW3n|6aEpG|Dp , R-LY-VN8mjr)f_0a㒬]&mЃ0{"rBnprN| kw@Ls 37Jk:Au';j6gK:wdOZmJyv>"; "/O#)|! QkL ~&ϘB-BZQLw8rX}MiR2LCyGL#P祼4䷌Ն ̕T(fN_"i[!ޯ)Ys4uЙ"y'6=BNs 4v%[]x=8qڮ@XjSY*1kS;g{{!;;a,M}{=D2G?ZAnyĞ[WSȀ D1|w:vvӓ9Uq$Rqh)40T.dY_}d(ELX9p%nQ'+= *Bow~L&AW̰Ӝy85]om(=&)5Iꓢ RTۚ9$8Ô9nX| 1Ғ3SDpԊz]ZQJR}WWISlͽq<*ϵ˞a%E '=+y"G~tFBqYKZyLy TZ%ϩ7bM ˤK̨ڟIf6 }'Cg{I>Sva'}:^` Ѳ X\40!0.p%tl%w2zG4’7}/gx򭄘p3j>dHAGS[;kdN3AŔE$lFK5 '#jc6̌hfdjG>}7y_ !yY]3,uы=r Gm'M 2ٺoǹݗ #dե oKeȤ)qm[u -i-}?ePqKԧK'D #(,d9"Vq,cz35 %ĎIx/ ՞3&0})Ay!zwx|I᫬vJ\Mz1mT:AcxnZ)riDϋ sx'\bL'OxQJ]=GJ,+D,Nsd ^Wケ\:D>ꮯVd\kמ|iZqonx'xKb1\yu0BZ0Țo=`?MiiJB_۹|J"ǪuǗ㵷#_s$SOd0A>KV̒.{JM1+ é9+9VI 7[ Oi&#M͎=4=~%G(r:er<G#2Cߧ|Vs8xϑUgyT1%l", 0Jf86k -ɓ^%+?}B?30o\xU2DGR׻^7Z(8F匣yzF*.?8LRñNZҡ28T ‡M=8jTWHt'9F:dY7;_E"9O8PAᧇKGYO/4avWz!% w{ 6K~1.QY sPjm˚XᑫKb ʯ o%͗-.Gb<QHӍ 3qjVq K&cQ u)#cȁWw3Dp4כf$Ef=;VGc%s ɾ+<jrwnM Ih dk|*fי_#G\amM)y2:E}#9Vv8_HK]*jXZ㺂L s8.}Ę[O%bz[gpUND9~Aˡ_R" "Z4EyJ;*, e8vvE lzK_ endstream endobj 87 0 obj << /Length1 1593 /Length2 7770 /Length3 0 /Length 8802 /Filter /FlateDecode >> stream xڍT6,"94twwI0H " ҍtt Hw#- s_֬53ώ{~i5u8V`y- Q y8a02B08$G lZ"ՠNeW ssqs  d- 5N2 `:{ vs `BBR`dPD؁OY:t _̢v0;# gaCvm0 s[~ Pt'#@ˡA[{vߧ:Ya:J g_ ٿ N-A '`q4U9v@K8>`iutKÿ`gq#/19Y@N8Ưd!00~\_dqՆ3$w̽ _-]`ׯt=_|67 @\:akB0e7mxp¬Nb.)=uCi5[SZp<hZB.T%'(@jOnK`7:^`:7;OX:ߊ]~ -!G qjUpP}_:W ay RN$.[kB ]צ9@P8rs~@^]#@P_k` Yzbpkx`2pq:A)|6PƯ;p)2FB. :.? y\v@>xxg̰? ? gv޷@0[#~`0cv yUe;ն7=|,o;Uqi Rҡ$͙cS>#&iKr=W`jk(@R:Q1xj~6*;|Y^E ot~)A{⒋J!4'&LQyB }fǥ2ɝ.pcNDŽl4H;'N'5铆Yy.R5[xꕩ%lô)~miev+K%:˺Qsq5Yx:)=q-ͷ\: moY3tY ֊e`|l4j6Tλ@1GAlzB+]aܛYm{эGQ5Qe BTfL F:)Y^lSjtVaqԘ1;^}JOVIe]A<-4yTNq6tSs=ZT;DVR}tUeH>8Z`=b"J&/𱈤 yl|KM:;j}% 4jt-Bش.,47njdgAwޡX?9f5)hO;Ue71rpS6Z;e7b?DI6,xm.*m TڬJ AEzhƨs+Ƽ@> ć=ZL꽒C$"oBt}CM9oC—$XTK߯ `tR]F":#yUJԳk]Hh0I,Bv2^\Tㆴ8.qơy.% 0hX6-eI 5ż:' ƫ8|ÔЇMu,:5A(e' O:_P\#q5Wͱ,3s%~ᄃq9]ʃ[gb b:dDmxMy}1表}$;ÂBSJk.۴v 懱XJ=j6ۆ{ |%URwRgV!C-xV[_xdɣp(6ƇrKx^^gWG?fy%*,4Zt&|,4LҊ;?̸P7sE$H* ŨKdV`*9f:i1wJ2uDqb>"vppmqndz3p1&Fm}ѧxeNFfl.&&KE6Ji@)\@vCn{{P{E+"%^OpV2 β{|wBܫ$?FEȾ[1?ŖZ(vXleݪ:"0'{n G+[+GՇ^ MŒh0Hk`E Y꾎/⨡ Ne )\v8ɱ8~CC/f$ aPDpupe|lv o']A%IT5 k>YлH>|)F.VWI V%,F|LCUKQ^ 4{%:tOdϧg;Qvڎ]*`,KzlъROL-]6KU`K%T!g݉$K+Yo?}b n1%]\AVͻ%XsI,;Vx'L5Ϧ]>9hhɀ?g"@zN y&e1йX4UZY/^%x P^ɌI6c\12 <&2=vgaer*iqZ ێ8ZF %Dn 7UPh|g!J{36(iEM*4qQѸV);;=nՕڍ*SzhMa:# r2S~u8EǍoIG/鬋/IK5-ZP\#f‚wu3w-DbDT3y7Q!}l+Դ_r7 qQ&>Bflk3ɓ;w]yʓTamQ/$D_h&Ƥu(Mi6MT ]̧kt誼1t ழucoP,fJϳiP(eT_$C6'^̂,٘H1Drf>@ڭꌁ6:Τ#8>B_/[.֭'p?!Sr˻ ů#uya:b'O5H܈bР+V0¤씽9:_vJ3de~DDuIVŵ xhOd7$NBs,[Ev'%} %33%뇶K]kWWGg?FxD=AqtI koʔR ˴w9Sۯk7G@ɼ"Q\p򨓼0>Lu El?^#+[Ċl6Igs"E TpF8[BsM&;&#Qmڻ!VU _h}4%ΐ6fw1 =f8]^]9%k[vVT>|0Wa%(U]Ak.u5ʻ)*mS=+v9@SjU.\zJֲ'/(|2* _C*z}.Y}2gǞn)_%oBlN-ɡz"Ȭl=}\(CC[]˫sE2\Kiۯ$XȨ _7P N+wLbIkғwtLjYr+Z,yb j-HCSw(|9Hi%zмN1X ZU$=>9_cFw?7Ǿ8yaMʚ5G(2LuByx .A#}-s:\}f_sp.m$YpX9Ore\ I̋cbU o5v|qniR&\m6#6f%M[!/l,%;y{4oA}=$7Jٛ?%R+ CŰ1Y3U?63RLX_KcT_K;?J95Q Pk= OeN#á1θy*r&~72~>-?NQ>sQ?7jRNJ{ M4Qv$l9lIKߪ/u5fn{},U~qt$J%syP)CH[;MZҴLFw3o8II>d 1A)^;/G1{ Z1&F^oo_ l[-o~#kӇ+HVyy-qy<hߋx/V̕Sफ़ ~W>=JP/ E Xdl \]"}T2ӱ1a% FAÆ"5Z+abk]sR?h[> 5sou-ʻsÃ9HfNaBi*:mBRiq`s 7Gd@0+#~`JV匊*¯QޅɓyNxF"r?] (X>gH]w2S!IV#1+9at72unIi~ňIͧMs/oEر0;sixwESiAxy N lF92XWxQr XYfj>]*sgp'i$ gKQG(YnH#"p7;eٿ7X̵H͡j-X{: xbIHQtsNKO 'ۙ:R$rvl/ϋƔ!9gx%$X:V}"cqS7 ˈXZJklW7 C,Bа,҂@gszQ#; zB<Ue-WeF 5x_Wq wip}9/gPSZJ+ìdԇٞbT}} xja*$Vہ0ԕHPlb(3I-}kk:8B[UU7;qƑ,/I1lx\q9Jd[_zx{x(dא'ҚU_OCk?jM/iyYlb\/4@rDH؊K1.Gsjns \}!lpIDqUp]VbBn,f,(Ȝrrefx1XVa:!˚C=kTmV븣}VK'|Yi%NHtS5F)۟?CP2hk/r-E7WU(Go1 _˪YBy!<{%G0 MlNisvsTvwo0PNtzr)ݚE K虅w›6&fq?`F%4 o ^ٲ@PlRYM0$Yb 7ك S3?'be8nr(<ʨjC8ۊWަ' ^f?%7DjQ)!?yJ™K"n =NN>X RukY2>a\Qkaު`t 3UʢXІU|Qq%~E4*_U-+1H тIEVStJ^}]Rc+]W_ax\ۣl)~8X8)> stream xڍteX. "%H R3twww8#104HKwwK t4%%w{><3w}:R0K<ɍ ȨH fdԅ9@~{!pW(I vCdn @ a    dPk'@qf9{ávnJ `b H9BP+@ fqDT;t`VP`sss;rO@ {@!ljеҁٸy8"ܝ!p>@GI q7@+` u@ yUN7/7v Că=P%W` ]Pg7WNWï)~A ?Y(b8yo @m~b̥uq(Bl!n> (@\/+;_Et!9Ä9|a(?  ??A 5 ` :aΎ0Cl^ B fYÜh.M#Yi -- r|@($;&O'*9B784XYVR! )he$?v:xAh j0V8/KקFlÿG uzA5nVvoޯs:A4a_ gV̿\wI9'+}p76 B,5/-8`nb8? V\2L!PEpiF|." ,#!տ[kN.? *_ಁzaF`?? z>oo"u"u  G,bi`#7;!C/f!Zc? ?7(\nvp'G!7"ѡ_c#^ҿ!࿞m b=7 y6G'Ƙ(aCnbs,^IDy vuiK4 ޼4۶43ȟ|/)f RHTQ$m{u_0rhz[GlUJ!kn,t7Ξ096HSϤSmN|C?43*P#h!표,/Bۼ2LB_K"=9lB/ ,Nn/7Ԋ ;kMߑΕ;U WQiЎ oPď%Opy; UZ2kaMKPN[ۓI~W%2L{)لL(R}f1MEgk|u5Cf ( v킫A/ƪH0=gX#<3v$ LV:񭣾I=)B":ao]$N8pz?`oh梜,|oW /Pi{5-8a}s;1%\T[Yh2 h>r> Î.Wk(uN|;'l[!]|XY 'Y8W&M?qê4A3]FDVFuÀ&U&ڟ.>SXL~ A5(p]f ?Za tA>XN8YЧ024 !+-$@%^ӤTKotϊ<0 …uwJ#ܹ<[~öإ"GЉD59!ν4P]u<҃`Rnv-F 4!iQ> v;&/ɨ0"5" wNCKC߅Q/މЌ y"Q[H3h;7'aDU+r~3Fl-2O&v/uz|L?O-'l=7S'fWj}OVռP,SE^Ś`^UgC' ]$Hk4+& I ̐hF9i1?PZ+Uq$j~Ґv$me$9.dFmQ J2p /HW,&=P/c%ph84Ad۠F~k"$tpTyp(AzdP\[2˒mpt@}AE/vu!zIUd&OpHf.ָ}&uwx'N0(A G4V?ëgf5}ruePNU[c=oɽk`wyCU6WBs8W L*BG&AVdŪ>+lt罋w~ߪbn8'KUfB⠍SސI]b-jj3Q"$D(W7 M='S-'_+0W]DsYsh 2:r QqMyt471?U{9N:\(ꓗӧ=99eIQu697%ۓQT٦:F⿘\Y< v'w"Irg`UA1XכO%OAkT>R,r:eT(aG:rӍ2k״o ['ϴ 8nml6sv&ˌOiR3~ֳ9 T eiMƪ^ M+R;6Ş(N59/ۢB?A +=^΁&;I-~R\ _[?t&Xxvve0tNgVύoPhŏX#{oE\WԮV@c42tXl ,` f,EM8qBjeN(ayDdu#zg*ŇWoH2ccZF[;DUzOYўԸ)I1']X&bq^TL"m*{?!ww{ V>ВՅN0>湟36(.בfx |ᵣHg&+ ̡xui7Ci5O5x@)cloJ-k '%U-]D;4Djٞԑu-]!cAt2OVQh|yyq1!vs+'s+~+UZI{nLڽxJ}oll- BYSSPh#2zY[2=]uxʎ_=MYeZZu6˷dU1Rz✹xIbi"SM#C#R>LJ٠uAy@BU*`IJ[^6/ͻ%,VpEx:N<}2%]${Fn}ünwh|יDƱYJug? Rs!7Lo-G&+uֆ/~5VF +hLgûny$xd%KN[Zdc 4a*_EZS|5?] yAyDŗy,\Uҕ(wEt-鷲wM_6EJ S -e=M{Z6:CYb˗w"JY 7 #L+:'>v\€eTiýջ-/Iu֊-IM~xqe.- UmZO5h_l!x!^m~[+_kR>z?qG#j TT]K{. `ǁ쬒F.kfER7aAagY9ZgH\(\kD=؏啝 ibr Zf܆Z K$ ^K!Ϸ,lvˮolKTTGk)(A+ād?Mԁ>~E4,*y3&d9RjٕW9|4;pjJ{lRԡ,nu!LIc]1AW'w5aȢwS)jzc[9DdO;-(-Y388%ު_'<5֚?t)YaOf*Y$Ɨho],fzL =3c|/pKf&%Ә/ЮV3}bG%z'h./ۆSϟ=m jPj:4%Zʫ)Rgsd8]yQLd \!N~xd!nJg3gyFzqqFwMm" ^yFPPagF{tG"8xwbwvx<.hsɻj\a~(=%:1hx;86fj;iGaogwwSJ d=7Dg}$˺5gm*flG\53fPQ%|&s vםmƷRwbj5^l,=tj^v9؟<qd[ln8eNEm>!fdazw9-wǐEPT /B|chnWcZ,lZWc=aqhڿ;e\^SB{Jc({1-m@*|# B&.gMp\eNBai00Q >v F|O3KvnZh82J~4+r ;7ι|F}k|"1x["AjYLBB꒣X qA񧃢%\.Bb'5ZHoj&]#ZۙȳnMp Rk$5#!}M@Q 5n$Ezײmnʞ[*vS/x7DMF|x<`IđWШ3| {LjY ͍mU.?نT9 ;֨kx"ѓ[ LT:˛YHۢ)0^J{ڕde:N㻸V$#LK;e[sK0ߵJX~ ^̌e $|0)2*~@@ԍQ$!XjygK=,-5U3:mdZ hݓ ]|eFyr=X&k >L9`=5KF(uBT_Z$e;' ~\ ń5Oӕ[{E.ڃQT35N2(SN&"4r~̺ϖ_gU}dlc?|+YwHwWwWvP|s'֧0o4 &UǟNtZ’@ARd4GA驞&8_|7C q^P+ҋJ (ktjkLl1V56txoQ0-LzZy Zsu:1gNyZQIYB.K>b8+vf@df-PNd{`ȁK'."%Tdª> qڍˍW0iYz+sHfmNj@|du[m4eCg}c23l*&ל6dNj7o͏K Qx=d{g k@lC1'8UUpTܾKϟ=d ^2,R;MTc "=lq⎌XOl]BIj+ܤjcRzG ȶ45`IdTXuNZ; {d_|DzJncWZ(y*jQuFo_l8lA&zQfwKI/q[kF)12KlH+oW5,^\ E< a u? ѥ[Z9_Dh~_1 7 N_YbW?*LB(IZ>$byu "N M&UO$MD\Kͻ3x`>j鞵Ƭu!@ z]mkg&6L֙05ǫa$\' O$GPŃέ$SLeGfEWs;%_&a7MsWx HMQ{^hµ% \Ӂ O%)zduKhabGFS&_Vl:K^*^MD>|_$_tӭdDO@$X2Q5>0FK;-оZz8iq—EEzQB1m85MTRey&{ e (ҍݰG% nBCpvS ?B_9W JҶ]!VfBn\09rJg#)w'SONt-ܾń6k5BlǤQڢ<9p?{#jw˪S 7.u_sX5^:H=pO gGs3,m+ُGDrXHro`0B}1?NTsDYђZ#fA#ҮՌSK邯$:b}yl *ӫ8;I49VGlHVv?zG/Mv/zO B/V^%iR\ʦ J=Kݧ}Eulˁ-$eL:8 |'+`f2nZߨUK(mYze/YMYB۔ t-TE‡ira+ ƃܟ I"\ EUtO;?&I5O4v6 f+#Žri0-eqz*xX4\y +wKYy[S MtB@07'ܵ[i{P,;$7FeK?GbC)[AYl&@d3ByR3/748wdm,zFKXGlHS$rI/-KQ.8vQW"Qӗ+/8߆b/ GGzj  S<ɺ ^|av 4N KUo[PR^R͈ͭZ5\PXxA(e겫Ͳ&zX]ʒIf@0S~z^j-0yte[Rp~:6s82ՑAu[\'MeTdǤK9N£:{:||'\/CIBܺyR|b㎷mF\m4:C<^ u>͗d"ﱣɠ w+ŵ /Ŋgʼ4}KBrn;5Q`=. <?/(&\daaQ#ZIl- kLVSdWS$ȒTPV=RNݠVKߐ;5׋јy}UYj{!8]1;ewlk̯ϢpI}RBY\AkIתF!8a<4Y]q&opWSFԧEd`*A:W32O>T  Q9Gm,q{[y[Y/ĦRcs=_A2OʝG)aUjmۯif+4NvEdS{=; !kn$iC JFT\1;uïqnZ4Z3#4_-z:=!ISv>WEcE09=(٤q ~Ƴz*L#17g aap ŘػI~ =йDW+&|HePa8b͔sYFϬɃAͼui@w#z&iUK' #6n$!@Twںw3CgkY8d2,k7/q G-S޸216;.횏eAW^3]0d1>pX0 P#Mvm{EQ/[ǩ;0beg~L3$6QO;-"TZpשFÕEp&Qz}|*C?oʇ$J;ePPTǬ'Ӄ1Aѣ+?}\8M1?vC<-F'zU[Vde8Q#XOFhOu:A SXZ)ezrC %)4yCNV V`n۩3'>i=ݯz\ yrqFcK{Xp=׾'ñ!hi:5qRƽ ػ6uӪV.]'b:O5q#4PK$,?ton<#8D%Hݑ[ymyGv %%l`nʻ@6VQ?x#(z)§3r˷*Y >c+}Q6Lb˲<(e/pwfŵWi['w9jw=XzSFr!$)s'/BXJ=,[^4qSW. l?ÎYWڇ4do/1>n#rEHF%vtܲ\4IA\c.mG+g~jvϋS]W :#Y)(cM|[kK fɨ/L:T~5)>&7> |@ xGydq+{$AqlT53nli+A̼LW`,:V e+$J\lZc:QRmܙvȖW~$g_D~~&I՗O78UdsqlUUG؝wk`JvbF_sʒanQ &qbfQ4IQm&Ŀq#6][K蝪j\JaroP@*c{BEKcѠ*3+ꗁ<}wQ*ؾ>!5f[99%|m8T1:s:ߛĝgs>w/ 7L8׍t`zj;y0(Zfċ\ź"GaVJdo endstream endobj 91 0 obj << /Length1 1500 /Length2 7129 /Length3 0 /Length 8124 /Filter /FlateDecode >> stream xڍwTTm׶0RRCI Ғ0C %HHIJ)H# t#ݍt}OZ߷fs}}> 3 # Q A ^3cluu!ȹB(@@0,(  _D(Pf"P7fgD aED8e0a:*Bz W Vq{$Yӓɍj' !큺P7i޸0?nVP Oǿ  H5'; $ P A>_Df;zy4Ue9o, %" !!߉`.*p[P65{)? \z@ HA}ϒS,{I 2O JH(h Po!րܝ۫B %k.0F" j CBPv_Cn_7T_>ԘAn$n(ivAQS p׸ \]F!56PbpHTՠ u@_HDQ y`( J<@~ ? *U+j_ BcXCEHY 'J8^ʙ/W;sdB^FZdXܡYS,sngʛNqݎ:vm$甚a~ݝ$YZ|;4-R6vz}Y*'<=(PR}Ѩ ]Z`{QYoxE'K֢S'ɚi j񞥄_zg:hZ#T=WBD bwK f\e{lX+HotM(ozV ƀ 6޻X *{s1sΐn7F1 *Гûp)rZl"~6+oÐPF8[fۧ'[CjښoW_Fp|hqf8z%̘b8]ij-Ĝu݆%yddEFsv9 <sy^lx \o]"xy_8sE__? N)=$iM#DPL|3;x&]I:A/ lK_Eu+V"~H wٔ.{.^^Xe s&SGuI*,k}ih)Vz?PV\Lg 8`1&`54YlYܗT #P1F'S6bѵ[t-9􏨸8>7 $wxgS2귕YާRc+\$I.խ)k{3NvŎ%#w^IwUG!Dz@5*^ ta'j<G+Y'YHZ<$߼Ք rKANH5tqgIuYbBi릭rHl[@%kvܛM8e[)^= % 'D84B{qh}@7դYHCG-TI2 _I*Y . 7(g{ Isyuޞߘ>ĺK5IȐ HOuͰT` fiKp;0}$ vTV5>Il*A`|aKJJh>?}7O5P PJKMe+|dr zqqsfKVCAnc'C|}bi{~$-kןCN6nd(n25`VAa%G*&%ʣwnk5!ʼB́u-t몘:Dn8׍ K3<;Ng}P?zLD:xĚ<*Ye /=bt"5;Mp`C*ЖlZyU R>>ѪHD&32 Δhkqtpn74k[@vPH<g#ڄ{;za֏N-kF,b&#.I7##R# qא_r:kHG:l*/%k5ηLrt)>Dntk<^htZk9{d_(=B*Fu5[I7~Pܦ6zL4VTSCy $Rk#F^:.h44\L1x'#Eݺ{NKEjgngo~Nڠ%'jzQ$=@xI]s9Jd ~۵T=Ñ,c3sv_,5濵4p>G8TU#*B_A?ΌuQʂBKwWr0wVn%/,H776'ži{*%Tm7eKJO@)Wi8ztDO&}^2/+?XVmL$y"/pv)3 f"~mNv=]pUdj7CW[v7yϺct([NMo[3""}+hIWwN5 4B@\.iшA|X9|.tl[^[HP^GT1$T2\nǡt-HJ-vySyxJTaA͇E<-ZZYGP5G۪SS/$Ktgߟn~6x=^RgnDLf)N4~/]_>dw'4X 6}ۏIܡ[)B),d}I|{k@:+ kҼ.ORūpdGaC6s]tD3 pҺϏAu$<+3I5Ff-w nI߱2A HD[}4h MTMWA%&C{'&ҫݫdEYF%4YL& }7~Yz{~SV-@.衽 i-_vM;f;e`Sԡfq~4=hڎ`GKMa˽8 !R:t 5-c2lЫ4cWCdj/w%HKUtd]RˣYtxk聐vLiRVZl: '<Чhdžm<|sguH.Ed.K$~͛z*IOjkċBr᠇ 2-e>5__whgQĻBzghExatZ=Aak;\!KbEXZEkFH>V89&9y).V6L!諸6ƩO~b۞KܵQMy@s@QWT3U{n!̞7#/^~吥ɤev. 5Kvůd߸s`6êf9>u:?b(=>1R*4Hy:daǩMPV3^V˱_p֤a I# Jdef8_y|x.qdK͡XQLR|=MO"Zt<| ގx_&HZNOQEl^8`*rD,}|0Sn?ZuPŀ`ƱAh{kԯjо㛍=nM)c&BCYn*l>2 %?Slră#U Mgmd3@ai"|X"S=vs͢s2gG>Xe}+p.9B8u.z}kbn$ U$Mz"]% WYI>osDSOTLYTt`J+'H)Rr BNDyk֘R+,ϢCd?p3w]](~a( ~tFD28/ ONnN,Q#0k %NjMTEz8H֓|e+[a'/& & jvԌ0s+g=k¼wLK֑*ce{[BC/gzhNVheIa"-¹Kз 17sҐ.칓~Dz|4eGXN|=M=N`{%oEoU{mgu}v9zvr r}ސ2k\|@V'9+Y"#@غ Ŀޖ؋Uf8WO.2I{l̯ 6`)#Ϭ/\q1Ɋ~62RҘ쬹05XyG!LlyR c4BmTc7wY"E{ m l,- /K=OS~Vl^p/h?q$jCctalAGp|)JpX#oS\'2ٍ@GҮ>;O7}d/&8[9=h6b*Z'bW7% Wb+YsW|^n#N+0ݓpa_ќ=Qxt_4zFΡhH|tN ZML;'(7E蠷PX֔@1 $RK &a1!NN`pWV^w,Ƌ'#Z~25W$$kO@R3*KNTvq>c6 :|3WdzIK&ntec.76шЎZb;r 1/ްNIN<,|F6{}H\ ;_>5zVBԝ>1p>ErD,|Lh[Zfׄ()LX`8BPq#<^[\{‡A ="r:QؒΰCܛXЇ&1ZIki o1ĿG=3"!YkO{nXt*vN@U\\tG*|}rK&y?T9 + 4e52+XB5T2+98g_xه(s x!SC4н凉儕irR52EbB5VKp|$h-Foe]~w&X\ C&~u. d_^aؖ1`Cq%'.@ )7" K V嘦%ξlbΡ6s{_˔?zO/n4g3i#^ھP$5ɕsɎr i5{GBSc` B_Ǚ;w?]'3-4U{F6+9 Yb %]H&&,41 K2x!PiAIFFdcS7~~]"=z7lBzjp>cBdN0k⚡U`Vm!l*BXnqI ,_Q:k=|y OV#FLAzpVTV;BH"D4.۷p\N7h)~0rzw8{X[ǟ1ţJIٗ,NLz`| b;tzqăP (LwRًO; Jt4uK 3 /cܬ4W6%G/yucU UF)wJiwP$ϒV\fKKћ w3pq0G}E13kcid]dmO#҆B~\cc ,ݘIDžk-qˣL؋ʁ`H@;TI$c/[l=A~.C7:^_(-EǮQO'ʉOknIbgɟ8DLxS%]5)6d OS?si~ʩkֻ4>Xƈ/53$8M2yژE1nS_nВmW9;gY>%2 O%ίAS~3[$5adYy ײ endstream endobj 93 0 obj << /Length1 1379 /Length2 5902 /Length3 0 /Length 6848 /Filter /FlateDecode >> stream xڍxTT6"̀t "90 % H()] JZ߷f=繮=6;1#Re]cK! M(o;> EGm*(4PhyB"!1)!q)  J DxHT콠]F+#}=N(to\ n8p tQ`7tE= `A(qFܥݐ'9n>7 0#^`Gzn? Lȿ @`PDxtu@ gsBBJ'W"(w=psBN|P|{/= @{Cahj{C<( 54mV;*#pW*P0ツ@᎐_c8z ¡<*0hmN`@()&&*?}@΂ ;3#@(G{(Op:8BA( wv k> ;k4p῏XPLr*)!|’~I1 @HHH .. g{>#VA$jO\ g.=`׿( /BgWݑ' ۻAahz*Eo9/nD٣ՠwB3__v(R v4@//p AGC ~ 5Ϻp؄EFDBhU:}~ (G!nP'Ahߚ} 9H:exe"71յ$hQ3glGJv54#O *"y/} Y(@ao(};}frD9M? =J6d$¶L5z @r(='aɠG+wa>da[C [>$I 44|MPꈣa5܁"'Eڽb5~Z,#)ɹZ-H %s$VH,;3EEyT++Ŧb4t-ԝA_X`.5>1_Iӱhb鱸yZe ?n}1u`;dIMn=Gjƣ*מGtr''cR~ 0ɚh&B\hB:owR*B1xR3Vt`[*$w {ݶIr8Ƴ.zlWǩmKV9[)PadK^a${׭ ņ 磌2_Ovroh4]c; K Eە? PƘZ tyBϾY]H qn;r^HI@F̹!)Q!MmBU~)Tx. i߄k/QY=i%mRw?>e@^ 5* Ue [_EDw-kG*m8іWN#[I,gG, Tun7lִU 4}i)v9;ðһN%|qQ)=5 ,Kf+?ۇ) OS{ҘreGlUu=d֜M=etpH9};PhF/j$ӕ*RԼ4l^&/us]|Ob 765lkW!",k; $NX}_`ja/TL%Y1Lz><7lZ+ְ'3.E4O-l P'NU(K9I1 iFs7Vg>OE W'(J1{N~z 񏚴!Uq~&Y䟕>;xz`1) T>]Y|1B$ZFv}W}YU s0'+ԟ]1e=²Zbٿj_؞yxj3ĚTقl#nÝb/؞spqa*ӘP:q;8_Q$KLIt eWX?1uQAn-3=50P0!Jtd?Zh8_IWq̎Vsh_+ Tm9>m_m}-?Gyp*f:%ԏ-1mL2`_yD!vFAv+/iUF4 Յ@(wR(ܺC<+{hC7v}ƘXH66︇:T-l8rV~ok&x+!H`Mm$5]_xib:6GG]|̯yAcJ rn+4pn9r''+PCĎ-(ɹ,".\̛,_-l+6d6,p-N/1o_ač3o+~j /#HM\b&;}T\ԗJxr+Ew`o^朑juΎ\4Pn;bU $('<-ȷn*TNzUǵf6e5V& 7[(=Yy$BPMӛ^yD'yoZAx@[-րͱtZOעޮ.*nD5n 0LB|E1m5GeNôɧG ۳oI~$Zy%H=?3vd܀ĬBK9Ka>K^_z5s`*:GDB. ሳNNIU0%Q\xH轧Q_ ʕrl?9LFCmG z.=s/*^1c=w)j#b0_*aQRP񜯳)GMOHvFE(ܵXLVo03m7A3望ɡVQ~=#tHٺ!NccIբv$Y'<۵Ģ"%jN3 󔲶7s˫:8!f^}2u 7)8iPݝS9 <ˬ?HT=;Bg}x@`aѴr]jcYiPY7[<#8[8}1F\ OA znO?<`y20"2:m}'Εz6e'}nIyg@&J/&UQ:Z8ٸOˌEx]h<NV,G9M`25Hx暣e(@fuEAJ4QMpLc_N}LN;mfaMRƣۙrDc]"rZ~*z:,X%xt \"c/1Oc46zU. :(P>Y]"`4[rCY߫>AZ jI^)cg(~; 3}j9+aRV3G]jSض?fIS{pi'sIvㄸlXAG'r䡺ydlr ~s=ēv]ڨc_')c0dr W} [JUճOTWPSKN ٮ^R} ϕuTqXTe2bj0eK+;>_˼=I['DrSFJG @29/֕fscpȵe&-⮟j)iێNhvByFd2} /^ME铧j_M/ X_iGFVuL[vU\xPGzlFi'W\7d\Iq0_f)>+NiH5xf ڴJcп;lr*Z 3:y\ߩm+jB{p յ 5ZbkF+PLClݑHew*4q.q(R`u=aWH)SK\$/dkm,H{?WwfED~>1B94sRImuJ)wb, 4 XLw[TX֛/Rd,bܽIm|󕭍qPzlC؉W/q6__zxvP0ĠVh!Bc{Ik;_:gnfizo9r|Uq|V+5V1S:{mÙp -LՔ^ABzmeZL@`H(qHEo5iIKukFSdh߭O}&qʢN8}$lQO8cP\KXXi˅U 2Qrc=no9jNLF$đ΋%f$efo;NKjA9żO6,^*th3Ҿp9)x[CJͲFzv }a!V35],|ˋIpý[V9~)l`eYѧFv\ I}序7宒k|>l3]JWCzq, ^cIl?P(߱{ss!Fg̠ NJexގ6/hg[箄I{}n1Gy+9M&w߼a8Igj>Tfd7ݣUEGHz&w8e|񹏝1{[hreu%+p'~*8EoYk-h×tgu0s@--Jcvrmz[T|`3iRY]j97hc4TܐPTVnCga7_}oҪ,9W/,L'Yd5_=SkŦ _fZ#x^7$~5˚0M}dv[0U;zQyAշ̧Cc[޳?|-ӎwg\(\#mbf+i'0C/t7G1mvRa4ud'y3"\V{\,Tnƾ CFo}f0¸"k d#*j{oVUK5M,KR|3);"мYO0> stream xڍP\ w ָ;w. 4n݃ Ƚޫckε)HTDL@v ,̼Qy55f33#33+<5?rx G' ;[Y:21󻡼-@`eef23Α t03dlANvfy6p9Zm@gs{Fc5@?!͝y6Nvf47 gs 2AMfnB  -AN..& G{v@d_􀿛`adoda3haak0%ݝ@[? Nv@W5ҁ e-읝,G6ۚ؀lOdw?&.L. imE@fffn6Vr76g#=O%w>^vw  Spvtx[`ba 0Y] 2 ;@}X|>a&vyLjRtS';w; o%USW]OOAX vs P3_,O3G1IX[G}n]w@}lŕX_3}DlͬH ' wX=)9YqX}oSzߝ(nklgǒrp@xIbxo !019L8RN?7IῈ V9<&"vw.!;:=' Rp6p !M0|o/^?}lC<;o[;;U3WEt\A*=Z޽ M띧?_YXz}*@ w11_e]p},ŮF ײc#2l2MuVHH/8 ذD'gx6i"p j{/ޟ [d(r\1%.*Us"<`V (3:K @ev=gX&8K{5asRթO}|A ΢WiqԆb63 #X 4:28O[=Sf"\֮=moE\:S77 |~0pG:yXXe7Ot9`\qw{ZfzYNϺ﹫v V &bf|`ׅi3[Pp~7-Fa4U,aDliU AȕS0R.[{O&,L1|]Ayޓ ]oPs_À~M 7RZL+;uyaE:cwHQ`RPpLt(?=^VK ˖}WU l~C,)'K\֫!Mמ^u  РӉ=ˤDom#!h Qy,X2LF箌I7EŎ7Һ4ci}K<^EbtŨ7b9ʧwTi=5x_">R#;ie}J6EԔb#qkCj|[4vh0Ȫr#_Z\(Efm6O]}6倖Kq{PϸO[y\.{hvfcpysc$7ݯ:?FFSV ̯#^i !M #J!!_xPIs/hbʼg~G>6Q}uZ.%Y|*GZ0L? ^_AP 䯗Y$OQ,fnwyLŹ9l]ۺ5\?G3,4_7ϯ"Z8%l-;Y;a1Xr²"z 5P'WRؤ?"Rn"Q eo*)xEI sl 1ckFSL/Zth 1w}k ;ikR" dj -ۊ/]3LNJj^Ը<]R sDự˭%&TFcFk)RĚ-8;~KhX $9&HFX_N.X#pdj\z}ZHH#phZ=1L6qK^ Fydj:& $?Y];:^këZ~3 ց*[Pq]᳨`pW#Nxyœ-xvMC;< -CdX,SJn FOFόn|O!vp8E䬬d`yL?=Ӄ[zWPȆ~!r%[.x̥~l|7 3̶Ye:}%*cXc}t*bY  ;Z$ LRiRowi6bAw+½ &m·Ma`=eH(n_t+mV;4kˡZ٧k(h#j!Rt{^QI󨥞ҋPunDϼNPzGDg^"Ho7yoI7PKa8F#<; &&dT9uhOIg< _!>TcT( DB R_5K(T:Ň~#蕲qB!^pSc1}ݦ$27;6DBj2{vlsc5<hoXZlsqwׂkeryj.v-k> c;č]1,4&OؑAdW0|mJz8#-*]ɭҐIB_nw>LM?/r{^_;kB܂1f ߨv'֜e!BkIEv&#hK6 Pxf&B|4bLj !9]o<] ㄍ", S:v !KŮ}@bQ=R5"? 1)쭺]䅎>JFCWAכf~iif-h򁑚g"1j"ޡZۯRPӝ~K?aX1s[ShcMzTڪ" Yoa;@ӣS#iJr*Mm$2cS>v(@I l5pΤKЪPݽm/^o1/t5xt9n`e_K^)utҮCuF ^W>;)~^8#:}l]ײ^x-f>-3OxHV#5G3|+<OOzsS:fO]Zڴ(2h-iE;\6}m\m_PM*k۰q:x'ΨfԨ6⛁f9/]4n| .T&5F [C!hZJnDx/lD`o4A#2WZCJDK*?Cqmɣ 6m> KhLіky GP*>l@Nh֨P{`OP:[y@7iC8T?~2+q\实tAﱇC!čjG'63IP#"1pu;?x)L~N`yІS{[^:Х)r@&=4N@8}Hڙ81nbaopI [5/Z]f5 "O+ uBIxo'r I H+bI@]A`c;b0ރIgyjOҾk5f=Qk_TX@ͩf<7kܴMO>j~,)*ޚڰ&plWaC~Mw J>MC`2X!bTxEᓖj LZ0m2<0.:+ ްKf J0sx8=ZZ!bcIBM\D+>h- cٞB@\79< 0dL$`< hx !}ä*1BSQq h("&y Akq p,BQVs3˂%J B-Ӂ#țc!S7OH@N"99E'&T*C^⩹RVp n(ipIqyCɣ,Q!U7-YO1#v7DS؍.MBv[ gIH&@,f? r&dk3`I)anhR;'i9KeAc1J5w1y;،ݎԣrx}~@9(|=ְthTft*T~EK5 7)+*z[ R |IUo{?ӕVaJhؚLh)A6Vf [qhۭa"(ͩa 鋳q"+8{">52mjDBI2-gdhS?}jY<Gͤ/'Ztܙ׼A hhSľ|E˰tPS&yɜ!7" ~m]~QWR,^*N6SzvF=خmތ-g>;^ӁP e\qNzn?O=5h FcPoIեT n(t⼮Qͳge~[bwl)-zĻAPYӦ }GmQ¾L(8uQS1V;@X-u: r[ز8Д^!MT4Ouԕ{^DGk. 0;(?GnknϜ:t!FGηq,G}Ff{g~Ug߭6o`{.\?"L] O;¬6f:OM#8._| H]1'X vGT)IP[td03B1H57s<05prfW5c2KAeLZfio^,-"i`9*SK~@hιCcña&pWGLD&׋K^gI|Z!?idR@@I?*-4u{NiI?ebR{s4:nFX jO@@ѣԌ^C޾7gY"@gV_|3`E<)Շ^_jUʰ[a9S;e:gqlPFi+!q%T՛7.^O'e n3gnãȏrTX~LD,'i*dkqq:6nM?ݩu7G?UޫG{zS "/3g1OmVo33l^u'K]_1e ܖl5$&FPil'_be40`П%huM($d{ԏIZ㤻3g?tvi~ZU^Lm"qi5mm,ܝVS}Gs+kݒ>:A;n&s=^!t#OfrdCՕ:4QM6huzO4MrT8R|$Y ;gG!Q ]2Ħ sl]\wF.R=}ȶIx%>PD֑2="#! D,bLR"MervL^LZrlGoO+g|Re#6OfJQSYe}HGJF\M?3T`QD-Cc lf{:4,Ej0U"v&Ԟ0w'i^a!%<ʦ(ev I&(\}zF'D3TD^Rl4ӘN).γ1☠y*,J/hR{U^`*pl'q2=m5xR I,~-[ϰKj4.jozJ_t Ў$z1y&}u⠻]\c n헇`_TDhy8șqŻ Įr둲kȰt, ~v½"h74^x2V)FU%?"Miݐm`}{X"\yO]U/)vj1 &}NOʬQO7 ",_I>K?°+C CiE%qvM*d:6 =T.', ݄;m7Շp{VBPW<%cK1 m #N q-XtOdA6 ,<3>lσ^R\{P}3Y4O~+n-.w]/TK% \JU߮ eEQr !k-F)K7Az@3\f͍Lcfm|i֔R^œ5i4@Է^⒂aҧuquU03\],b AR|ns%6g;[rA+/}t=㽦͈m{yJѩ}7#FT70I 9&^[}d=BqFY䅡#%1'$ x1h@۽TbXś%]XH& }ؐ鹴y|XHj D1yP ^95|f(A h`j C>^@oqHrGqT*{5ѺgiM|QOD gZh)7'Q׶dRϐ^sc cK͟NhB+]ֳgp ? gj;;D,~#xM3$ H 2,H,nЬ-S8=Ͽj \3y្j+8#j~YI?|x FY.,bU[tP!3jT=aP%) t׼;]WQ&@ 5i5ȇjP.F3UJVS嘧nYo/D x0#VTNP741EFZ #W܀ܫk76Kn$ېZMm"VҜ*hc2I&w%;x9b%O;:kn9wBVd&9DM,]LxYid?gߊffK _TawSQ~eI>.~=Kƕ8WO iHQQ(#$(`zFlZR{d$5@'Y4ׇ`XW>ۥt=j,0e-F +܇M/WT-R5wɨ~h ZU[*Z@QY)#H~9=f]y%&Ž7Nh7NW$>$if~!`pA2co`3,;>-^h YUVM8X 2kvA B1y %a}.XvEB1rK lXg/$].BoEHa)1eXhk_ AQ é7ڦ>,1Vulpz}kpCOdT; 2{3/*I<^ZѦzMG+џ-UXfq0K{iq߹ȸc>gr؋uL|ZhU,N x C[t!^An9}kGvw4/lDpU+MYY7XY_=fYP֫=EB >4> I4}`kQHrO'o5o&[2:v#pP|=H )IaqkF5YY:!!~kHʞ"@_FN)^ƍ?2*wV~_O&!XE谳Ş}%{;mӪҜ N 2a?mh>Faf_`#Y!-Ii#ު%RH͉[n1뱒ʇ}P g2' AےlV_R%#WTpI,ӵ:g).n;(b0Y\CxT^m!1](nvO::,}EŴ C"/z34B)Wmn&+W #zULTb5PjI8-#dCb% *4)b%#vڈ48-z43>!XNΐG %QV}5f(Kqh`͒ >;1'Z.ړQFW\G0_c%{A/E9D͕hnG <}˓j†*AR\m] 4T-Ug\1!=M< ~zCΝs4If wh~AG]) ) *f'EBr'Bæh[Ҋ!g)(=~0?qbsߴAhu36f64~@{rJeyfY{\cp&QSch;Ϙe|:QhH8L-$IW_ZF/}3R sNYRg# ?܏' B*=G ?IQ0f ?DYS͙Zz}NM%fr_秸6Fbq@J^WT5WfwhZ~ȃP+{UFբfʼҴpw.BBfiB/?_lZ~9s)+1Ջgnԓ62Yv„yH)[ oԉ&Ik<,A).e_Q\ɗ,",k7k]_nt >%It + YndIyM2O& ~9,Cgƴ6`W0[j !wٿN07a`:iB<6A1'#VT6U a#/;3z|RRoQP*T[vӕtN?Ai#s0Ԩv=&6(4q Γxa uQ;v^ʬGP!o-WY 5"e՚{V68v"tWJ蘨apïo[}EzQC9e*y@{2CPgRT)V:a˽;Lۓ TW GfxZCf)1FDWf)dAm76zO:+`:q\FoNd\72ͭ?X% mv!ġAC%e`k:?uGt$9TU@nȁZ Ax9j~BT?~q: W$2G`bŅvO`P!ϲuz-yُꈨPה8 endstream endobj 97 0 obj << /Length1 721 /Length2 6909 /Length3 0 /Length 7498 /Filter /FlateDecode >> stream xmwuTk5R5t 30 2tJ ]t4 HJIy}}׻ַ~>g?g=k8X5'TD@DPX`a/",##PCAAh,  " !!=Q0W4ۉo`A`0 G>9>}G( ]g P3Zih5 P>`8 s"<g$ '8!_x EsF!=*u5!S5iiGeN("U? sBPH/ߴH?0Ax@}pACQ}$B Ŀ, C s@0o X oϽC!0s$?G􍍁f|-euCL  ? >lZ῾#e"Dbqq hBA 3˿ߋAfNrn!E|㣎f|"s#G6^WS|_0I(Jy85nᲘ%jڨ6Ϝ(ݭ*Us,k'_y5?u̴M{G>tFrAZX5TIfuYx*h6h'gg~ʧd(MK~ 2@4KZ*,bfIvjA:7"I쮿eW3}ݔ0`o~ϔiRm.*2ua-ɗ!FYicD'jz>+dDBKx|'V6_x_w'ȽiB&Jw'M* {b#"߼p7)T)M¹hkXw6=Y,* ׷]ٌq or>+'~\"&3P"><_{3z `<,G/oM >+f4h,h3Ʈ V=6dEMo1dnhe>/ȍrf SN`f]ȃ)%IFڪڕEi,n]t!T>sffVx]ͭ](pxu8^\Efa }0iOO nMl: 9]%iL #ǥdOxԓ4Vu|K* eOtn>ʿ1ډ6fWqiڄ︯OBٛn0?tZUc7$GdXP*=kDɠyBe/r-r8wlt9*[ /{#NI53~rݡ0&xͮ >،}*6qDg%ҿG@j3KC 'eԩ 6짹3 '0wτ-}0|KH)'QAɸ nGCK=vrȐ޷?6j `#i9Iݝ“0u ^iV)g=qAp-`j*ǔAoS5ѝۆ>F:!jkTOTwq7OS7KD]a =Hh"xS#%o~+#+R:иa T<.l3_|V{{4.9jV Q^C)}RWG͖ P$a6]mM_42TUjj͆m~KNT]16RR q->hlsFcs~ ~OAɳ<z*}oLsGKa[@h;U1o9Uxqeb~gf/^$@:W=CZ J";K 8 EAgzE.M/1!ݑmН=<2+gեrPɛQh4c|& Ͼ'|aׇeޤ/ZEԌYk>!wn?Zʡ9l e/2@g;?z2$铵ЦO4~C.iJؔrIkRDP4*PWw+TO8!CՓ$S&O,o]ULUh2v͐N9Ռs&вĭMhc&WwڌRlu'~p晻 1g2p˒>(+4v$ pie`"!\3okWɥUT|NS?j K&?Rf ߠIeS[b[}{\w_SG'!Q31~XWΪwqjV cOtg[}i*`Aw9nd!.b :pr3oX!S1Qyez1H1;ۗ3>NN+ᭆld 6Ufi YB3VMZⷀga%ڵwL^O88 xP̷w-7;kKj},cv&ub:qD{qӦ95"  \YH${#)s`AXKn6Kݝ;c804rdYA74MAѡQ]$AJ'ݸ!􄕝M[KXeI͉tE"Tr}~is :u<1x=CmVyn25:A7|%55@x=dǍH>`ϱvBA}csoTur>KmY0s0G\ K-o9evVb*>䢻pKrZAf,LF ݄IՖ4;S)!Q޼񣮍@X=ah>c`"](umX^A"1Y2%L@ z߯wMK'ԎP&+b QLK /pb1Kk^1aaO145gZS瞍Q:Lc7slT6 Ҁ,1k3;KY6PvŷJY,L] D^\}K*̍bWQp [GCYgm9U2sd% FO;P/w wo"6{^Bgʨ$e%XP<֦mx4;5 ɱJռHg?:S0k.O=Œ7&I} +1{]o}yHwwK: wlyzMtg؏jx6[݆)Qƾ5-JzVansf8Gfϥaos/Q=e}ւc1T1˨ ߏ1`hWg@FLuyn %T]|,J9? -fZY0$atӫMG7<MNX2 +t0jАUU@5%)r`%6.tY29=E/wlaE ӤY&(Zuj>Y"l_я 1b}Tϓ)Ks,И nUoDnJTl~H 7z2UaӬm'a^kn~Yz?#4n.E/zMGR^Od,JJZΊ؉C-ا H5wk?\sutVrlm ;gפj 8߅}@9 (]jG2Ucًq|*1YݾfdE5läkFZ{1mDɝWjs3Ud4f5rv_JJi ď/<7ewt$|x >n{Ł#٥ 2?Z_iy\q^(P'6Х{+a8sY|:0Lx@ p}l^4)dh>`6A<3]oVŊ}%+ӟ=y[0 ." 3M-IY)^߫G{|+q"IbYLpp @Z-^: %4d L߉mcדm*}r<KwZ*_{f=uF\e&G'WfE ;R(nkK=$J0}]BuU~ ἅuֵiU;r .COvIM=*GE+ xOW-n"~_{z ?7 :Oԍ>~ZMMف9H~+yo* ƒ0n;)o.B춬u^# 8P˶8':wDO*3~6U'gs)>hN.{4|~Nc0FVhՎh&NB MٻȚl.cg+U1C,44#'`Lk)u*T/MFeIu:i8HQV$ 'ށOI@eBEwK2G?Z}N!V5W{ٟrf(Cm%ɧ Q v o%5akeO(kR![{Ma`s4s~L鲲>YQmyq3F6˒>v?eoJ]kfdU5  `7&b]rBYOm_Kv_Y}~7fŖ'‘Y S69v2~hu"^nRSm]7ٔ|޵ *Օ?ڱyg&mb|u_&> ӣfDt6rW\{t9Iܐt̺u_Uo nbVsnG թ9 C0]_ !<=ۼ a:q1aa7 T{Ү(kF3 2J,B*Kn> 3䑆Z-ZSGFJS endstream endobj 105 0 obj << /Producer (pdfTeX-1.40.20) /Author()/Title()/Subject()/Creator(LaTeX with hyperref)/Keywords() /CreationDate (D:20220203114302+01'00') /ModDate (D:20220203114302+01'00') /Trapped /False /PTEX.Fullbanner (This is pdfTeX, Version 3.14159265-2.6-1.40.20 (TeX Live 2019/Debian) kpathsea version 6.3.1) >> endobj 2 0 obj << /Type /ObjStm /N 87 /First 688 /Length 3428 /Filter /FlateDecode >> stream xZs8B37Gonݰw8(Z`N?mqv(_Gr;i ]e",eYf,sLL˄bB㢙IKƤ.d2L*hD3mS<`&-s@ j1=S 8.c0!IL2)O:.xXRj < SHJ+V.|JA[.3DptςZ(Jx2WTad2V^e J$ЦSL㚙TٞIBk5i54T gʠJp5a!Iaz^Tޒ5Pvo  %%؃>0nR{Yz@% Ha3t$aph35)I5J$[P|ddK*"+Ҁ| z2BOѸЎH mCOR.TDIqpT gWyƉ2N|T\MghrVQlV֗9}̫]e^mF#7MG-&BxGi(YտXgcF_:q^rW8rG ;% k:/z@Pb&y@ۛL 9D@$qbKfg+aj>hrhzƟgѩ7fp$h-KaD!h#=e#()D#h%[ِ>!@)Pʅ\,HmRM [߁$(H 2V6LV {^ 40gaM V{X4p{|c> ц,'94|K+m%RMFD=`biD e3h}"w-Ç v'3=8KLYg(>,'?ϰ$DO{024t\DUS.EnU% =w,}xZ!>E/SMRoVp/Vˈmk#]بI`emRҮZ]j[ִaQ>Z>ɰޤ hO'vO4d"6W6'n7KJ" 2mbOIQ^l|wK(49- ̹%[eɲ?IiY x՟㊗e>Ʋ:ǻ0b\W㿽 Gl:-ʺajoSeNնa)ޜnwRY\ͯ(x*  PdͰ!སLf pgẊށ$ۃhx y8Z8g@NXgDޓ k џjZoi7=az>WlF/8 `5eEX3Afo6(_0>r4T, -{,kxBz]|iN!mU:bEZNCkPL^>쮿fv GjEkG/k)( rE-7OøR1Ӵ-l>2]QZBC ]B"ИZTFePbFq:*$eTwO)C5ᤑ>|K}& vúi *b$)LƄp^sA*It 01-Z7Cgd&鵹 c(FށGFmBCK`%*Bedq.cB!UGߨSi 4ВgYxW&yJ#%>gObߦdk#-tH\TdAe: (ck%(;h[ 0QhzQ53⨔Ԑ:HMfibC-(4*E υJ9 YkE[y5(GӺ(ev=3Q1!FtWI+ {47{Հ(O~ʙٮx4؛\s`ί-{]3 ,e>Nd`iε8?fclUy߰92q^UOdv1/ńQ|J/?Ћȧy9*F_x2I|g!p 2 ˎ2۷dM"z} vov*S}l??-N`_;W5tS}imaG<ŬW8d3f`3pumynumrF2-)qe7haƑȠrEl#ޛfM8[m"Jr?̃ -9ϨyJRC뎘[%'_1m:'湜.Kmaڢ-#DQځ!~bf%0!qMNQVa jcn){$], PP\mVݻ7oir~c([6əl(߶@w5̪<[ׯޑ <3A92670DE2158B733765E2CA9433061D>] /Length 261 /Filter /FlateDecode >> stream x%7RAFaFX! . A@Sr5Wf&3,0%2A@=AĠ  J B)ġ A!%*a֠ 6`vZ\l-l,2l6@3eᣏ5B;Ȣ_kN营}zaa`F``\-ܗפ++=żrό״׌?7+y>{pp琗_ۻT t endstream endobj startxref 120544 %%EOF gower/inst/doc/intro.Rnw0000644000176200001440000001144113452644704014754 0ustar liggesusers%\VignetteIndexEntry{Introduction to the gower package} \documentclass[11pt]{article} \usepackage{enumitem} \setlist{nosep} \usepackage{hyperref} \hypersetup{ pdfborder={0 0 0} , colorlinks=true , urlcolor=red , linkcolor=blue } \renewcommand{\familydefault}{\sfdefault} \setlength{\parindent}{0pt} \setlength{\parskip}{2ex} \title{Introduction to the gower package} \author{Mark van der Loo} \newcommand{\code}[1]{\texttt{#1}} \newcommand{\pkg}[1]{\textbf{#1}} \begin{document} \maketitle{} \tableofcontents{} <>= options(prompt=" ") @ \newpage \section{Gower's distance measure} Gower's distance can be used to measure how different two records are. The records may contain combinations of logical, numerical, categorical or text data. The distance is always a number between 0 (identical) and 1 (maximally dissimilar). An easy to read specification of the measure is given in the original paper. Gower (1971) \href{http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.412.4155&rep=rep1&type=pdf}{A general coefficient of similarity and some of its properties}. \emph{Biometrics} **27** 857--874. In short, Gower's distance (or similarity) first computes distances between pairs of variables over two data sets and then combines those distances to a single value per record-pair. This package modifies Gower's original similarity measure in the following ways. \begin{itemize} \item{In stead of the original similarity $S$, the package returns the distance $1-S$.} \item{The original paper does not mention the concept of \code{NA}. Missing variables are skipped when computing the distance.} \item{The original paper does not mention character data. These are treated as categorical data.} \end{itemize} \section{Computing Gower's distance} The function \code{gower\_dist} computes pairwise-distances between records. <<>>= library(gower) dat1 <- iris[1:10,] dat2 <- iris[6:15,] gower_dist(dat1, dat2) @ If one data frame has less records than the other, the shortest one is recycled over (just like when you're adding two vectors of unequal length) <<>>= gower_dist(iris[1,], dat1) @ It is possible to control how columns from the two data sets are paired for comparison using the \code{pair\_x} and \code{pair\_y} arguments. This comes in handy when similar colums have different names accross datasets. By default, columns with matching names are paired. The behaviour is somewhat similar to that of base R's \code{merge} in that respect. <<>>= dat1 <- dat2 <- iris[1:10,] names(dat2) <- tolower(names(dat2)) gower_dist(dat1, dat2) # tell gower_dist to match columns 1..5 in dat1 with column 1..5 in dat2 gower_dist(dat1, dat2, pair_y=1:5) @ It is also possible to explicitly ignore case when matching columns by name. <<>>= gower_dist(dat1, dat2, ignore_case=TRUE) @ \section{Computing the top-n best matches} The function \code{gower\_topn} returns a list with two arrays. <<>>= dat1 <- iris[1:10,] L <- gower_topn(x=dat1, y=iris, n=3) L @ The first array is called \code{index}. Each column corresponds to one row of \code{x}. The entries of each column index the top $n$ best matches of that row in \code{x} with rows in \code{y}. In this example, the best match of the first row of \code{dat1} is record number \Sexpr{L$index[1,1]} from \code{iris} (this should be obvious, since they are the same record). The second best match is record number \Sexpr{L$index[2,1]} from \code{iris}. The second array is called \code{distance} and it contains the corresponding distances. \section{Using weights} Gower's distance is computed as an average over differences between variables. By setting \code{weights} you can compute the distance as a weighted average. <<>>= gower_dist(women[1,], women) gower_dist(women[1,], women, weights=c(2,3)) @ \section{Parallelization, memory usage} The underlying algorithm is implemented in C and parallelized using \href{http://www.openmp.org}{OpenMP}. OpenMP is available on most systems that can run R. Please see \href{https://cran.r-project.org/doc/manuals/r-release/R-exts.html#OpenMP-support}{this section} of the writing R extensions manual for up-to-details details on which systems are supported. At the time of writing (spring 2019), OSX is the only system not supporting OpenMP out of the box. You can still make it work by installing the gcc toolchain and compiling the package (and R). If OpenMP is not supported, the package will still work but the core algorithms will not be parallelized. This implementation makes no copies of the data in memory. When computing \code{gower\_dist}, two double precision arrays of size \code{max(nrow(x),nrow(y))} are kept in memory to store intermediate results. When computing the top-n matches, for $k$ cores, $k+2$ double precision arrays of length \code{nrow(y)} are created to store intermediate results at C level. \end{document} gower/inst/doc/intro.R0000644000176200001440000000304714176730666014421 0ustar liggesusers### R code from vignette source 'intro.Rnw' ################################################### ### code chunk number 1: intro.Rnw:34-35 ################################################### options(prompt=" ") ################################################### ### code chunk number 2: intro.Rnw:68-72 ################################################### library(gower) dat1 <- iris[1:10,] dat2 <- iris[6:15,] gower_dist(dat1, dat2) ################################################### ### code chunk number 3: intro.Rnw:77-78 ################################################### gower_dist(iris[1,], dat1) ################################################### ### code chunk number 4: intro.Rnw:87-92 ################################################### dat1 <- dat2 <- iris[1:10,] names(dat2) <- tolower(names(dat2)) gower_dist(dat1, dat2) # tell gower_dist to match columns 1..5 in dat1 with column 1..5 in dat2 gower_dist(dat1, dat2, pair_y=1:5) ################################################### ### code chunk number 5: intro.Rnw:97-98 ################################################### gower_dist(dat1, dat2, ignore_case=TRUE) ################################################### ### code chunk number 6: intro.Rnw:106-109 ################################################### dat1 <- iris[1:10,] L <- gower_topn(x=dat1, y=iris, n=3) L ################################################### ### code chunk number 7: intro.Rnw:125-127 ################################################### gower_dist(women[1,], women) gower_dist(women[1,], women, weights=c(2,3)) gower/inst/tinytest/0000755000176200001440000000000014176730666014255 5ustar liggesusersgower/inst/tinytest/test_gower.R0000644000176200001440000001022713460534474016556 0ustar liggesusers ## distance between logicals dL <- expand.grid(c(TRUE,FALSE),c(TRUE,FALSE)) x = data.frame(x=dL[,1]) y = data.frame(x=dL[,2]) expect_equal(c(0,1,1,NaN), gower_dist(x = x,y = y)) ## distance between factor variables bands <- c("Grand Magus","Skull Fist") dF <- expand.grid(bands,bands) expect_equal(gower_dist(data.frame(x=dF[,1]),data.frame(x=dF[,2])),c(0,1,1,0)) ## distance between numerical variables dN <- data.frame(x = as.numeric(1:4),y=as.numeric(c(1,1,2,3))) expect_equal(gower_dist(data.frame(x=dN[,1]),data.frame(x=dN[,2])),c(0,1/3,1/3,1/3)) ## distance between character variables dC <- data.frame(x=letters[1:3],y=letters[3:1],stringsAsFactors=FALSE) expect_equal(gower_dist( data.frame(x=dC[,1],stringsAsFactors=FALSE) , data.frame(x=dC[,2],stringsAsFactors=FALSE)),c(1,0,1)) ## multivariate dataset bands <- c("Grand Magus","Skull Fist") dL <- expand.grid(c(TRUE,FALSE),c(TRUE,FALSE)) dN <- data.frame(x = as.numeric(1:4),y=as.numeric(c(1,1,2,3))) dF <- expand.grid(bands,bands) dM1 <- data.frame(x=dL[,1],y=dF[,1],z=dN[,1]) dM2 <- data.frame(x=dL[,2],y=dF[,2],z=dN[,2]) expect_equal(gower_dist(x=dM1,y=dM2), c(0,7/9,7/9,1/6)) # check symmetry expect_equal(gower_dist(dM1,dM2),gower_dist(dM2,dM1)) # not counting NA's in the denominator dM1[array(c(2,3,4,1,2,3),dim=c(3,2))] <- NA expect_equal(gower_dist(dM1,dM2), c(0,3/4,3/4,0)) #auto-matching columns expect_equivalent(gower_dist(women, women[1]),rep(0,nrow(women))) ## ignoring column name cases",{ dat1 <- iris[1:6,] dat2 <- iris[1:6,] names(dat2) <- tolower(names(dat2)) expect_equal(gower_dist(dat1, dat2, ignore_case=TRUE),rep(0,6)) ## recycling expect_equal(length(gower_dist(x=iris[1,],y=iris)), nrow(iris)) expect_equal(length(gower_dist(x=iris,y=iris[1,])), nrow(iris)) expect_equal(length(gower_dist(x=iris[1:3,],y=iris)), nrow(iris)) expect_equal(length(gower_dist(x=iris,y=iris[1:3,])), nrow(iris)) ## weights expect_error(gower_topn(women, women, weights=-(1:4))) expect_error(gower_dist(women, women, weights=c(NA,1:3))) d1 <- women[1,] d2 <- women[2,] w <- c(1,2) r <- sapply(women, function(x) abs(diff(range(x)))) d12 <- (w[1]*abs(d1[1,1]-d2[1,1])/r[1] + w[2]*abs(d1[1,2]-d2[1,2])/r[2])/sum(w) wom2 <- women wom2[1:2,] <- wom2[2:1,] expect_equivalent(gower_dist(women,wom2, weights=w)[1], d12) ## edge cases and exceptions expect_warning(gower_dist( x = data.frame(x=c(1.2,1.2,1.2)) , y = data.frame(x=c(1.2,1.2,1.2)) )) expect_warning(gower_dist( x = data.frame(x=c(1.2,1.2,1.2)) , y = data.frame(x=c(1.2,1.2,1.3)) , eps=0.2 )) expect_warning(gower_dist(data.frame(x=rep(1,100)), data.frame(x=1,100))) expect_error(gower_dist( data.frame(a = letters[1:3], stringsAsFactors = TRUE), data.frame(a = letters[2:4], stringsAsFactors = TRUE) )) expect_error(gower_dist( data.frame(a = letters[1:3], stringsAsFactors = FALSE), data.frame(a = letters[2:4], stringsAsFactors = TRUE) )) suppressMessages(out <- gower_dist(data.frame(x=1:3), data.frame(y=1:3) )) expect_true(identical(out,numeric(0))) suppressMessages(out <- gower_topn(data.frame(x=1:3),data.frame(y=1:3)) ) expect_true( identical(out$distance, matrix(0)[0,0]) ) expect_true( identical(out$index, matrix(0L)[0,0]) ) ## Top-n ## gower_topn d1 <- iris[1:3,] d2 <- iris[1:7,] L <- gower_topn(d1,d2,n=4) expect_equal(length(L),2) expect_equal(dim(L[[1]]),c(4,3)) expect_equal(dim(L[[1]]),dim(L[[2]])) expect_equal(L[[1]][1,],1:3) expect_equal(L[[2]][1,],rep(0,3)) # case where n exceeds nr of records in the lookup table. L <- gower_topn(d1,d2,n=8) expect_equal(L[[1]][8,],rep(0,3)) expect_equal(L[[2]][8,],rep(Inf,3)) ## just to get code-coverage right dat1 <- data.frame( x = as.factor(sample(letters,2000,replace=TRUE)) ,y = sample(LETTERS,2000,replace=TRUE) ,z = as.integer(1:2000) ,w = sample(c(TRUE,FALSE),2000,replace=TRUE) , stringsAsFactors=FALSE ) i <- sample(2000) dat2 <- dat1[i,] gower_dist(dat1,dat2) ## warning on recycling expect_warning(gower_dist(iris[1:3,],iris[1:2,])) expect_warning(gower_dist(iris[1:2,],iris[1:3,])) ## regression tests ## topn w/n=1" dat <- data.frame(x = c(NA,2,4,5), y = c(6,7,NA,10)) L <- gower_topn(dat[c(1,3),],dat[c(2,4),],n=1) expect_equivalent(as.vector(L$index),c(1,2)) gower/inst/tinytest/test_gh_issue_8.R0000644000176200001440000000141513671163420017460 0ustar liggesusers if (at_home()){ dat1 <- iris[1:10,1:5,drop=FALSE] dat2 <- iris[6:15,1:5,drop=FALSE] nthrd1 <- gower_dist(dat1, dat2, nthread=1) nthrd2 <- gower_dist(dat1, dat2, nthread=2) nthrd4 <- gower_dist(dat1, dat2, nthread=4) nthrd7 <- gower_dist(dat1, dat2, nthread=7) expect_equal(nthrd1, nthrd2) expect_equal(nthrd1, nthrd4) expect_equal(nthrd1, nthrd7) # now with large numbers of records dat1 <- iris[rep(1:10,200),1:5,drop=FALSE] dat2 <- iris[rep(6:15,200),1:5,drop=FALSE] nthrd1 <- gower_dist(dat1, dat2, nthread=1) nthrd2 <- gower_dist(dat1, dat2, nthread=2) nthrd4 <- gower_dist(dat1, dat2, nthread=4) nthrd7 <- gower_dist(dat1, dat2, nthread=7) expect_equal(nthrd1, nthrd2) expect_equal(nthrd1, nthrd4) expect_equal(nthrd1, nthrd7) } gower/inst/tinytest/test_gh_issue_18.R0000644000176200001440000000026714176713717017560 0ustar liggesusersdf <- data.frame(X = c(4L, 0L, 10L)) obj <- data.frame(X = 5L) d1 <- gower_dist(obj, df) df2 <- df[c(2,3,1),,drop=FALSE] d2 <- gower_dist(obj, df2) expect_equal(d1,d2[c(3,1,2)])