pax_global_header00006660000000000000000000000064141271237040014513gustar00rootroot0000000000000052 comment=0e3711faaa3dacf2cc844c45a3bfa4f84bb4150a r-cran-mclustcomp-0.3.3/000077500000000000000000000000001412712370400150645ustar00rootroot00000000000000r-cran-mclustcomp-0.3.3/DESCRIPTION000066400000000000000000000016231412712370400165740ustar00rootroot00000000000000Package: mclustcomp Type: Package Title: Measures for Comparing Clusters Version: 0.3.3 Authors@R: person("Kisung", "You", email = "kisungyou@outlook.com", role = c("aut", "cre")) Description: Given a set of data points, a clustering is defined as a disjoint partition where each pair of sets in a partition has no overlapping elements. This package provides 25 methods that play a role somewhat similar to distance or metric that measures similarity of two clusterings - or partitions. For a more detailed description, see Meila, M. (2005) . License: GPL (>= 3) Encoding: UTF-8 Imports: Rcpp, Rdpack LinkingTo: Rcpp, RcppArmadillo RoxygenNote: 7.1.1 RdMacros: Rdpack NeedsCompilation: yes Packaged: 2021-06-12 06:23:48 UTC; kisung Author: Kisung You [aut, cre] Maintainer: Kisung You Repository: CRAN Date/Publication: 2021-06-13 04:40:11 UTC r-cran-mclustcomp-0.3.3/MD5000066400000000000000000000022311412712370400153720ustar00rootroot000000000000005403d689f7460fef6bbd9398dfed467f *DESCRIPTION 269b36c2dec1439b14d921aca4cabcde *NAMESPACE c147cbffe47a64e9adc62bc60c08c806 *NEWS.md 338a3f860e9493c53b8d0721b0ec8bb7 *R/RcppExports.R 68ec5e4ade137d3adf3d9c783c097e87 *R/auxiliary.R 666e0c713303cff8571f9a062012dc43 *R/cat1_CountingPairs.R 27905cf601aea96839fb8d2b0e882460 *R/cat2_SetOverlap.R e8405e53f81634794f9be122ea12c4bc *R/cat3_InfoTheory.R cb68537838848838974bdfe92eb21604 *R/mclustcomp.R 56acee3ab4c78865386e24c1ed2ef666 *R/package-mclustcomp.R 5f53af20fa3432ed966f5357be133720 *README.md b67375ba1a03a975efc6175c13bd81bc *build/partial.rdb 5edcfe1b071040fed2a3ffce3ae01482 *inst/REFERENCES.bib acfc9740d5a382344e1906d91232591e *man/get.commsize.Rd 7d9057b671af23ab954834b26aaa9417 *man/get.confusion.Rd 0270fbdf9958607e4e5ff7c38de54b53 *man/get.pair.Rd 243c2874cc4b5c2afeab1a77c0b00fd3 *man/get.probs.Rd a14a38e1602ada256464df351a080791 *man/mclustcomp-package.Rd cae0331ccd4e1595db340ca8e8025207 *man/mclustcomp.Rd 1a740c5b07467409fdbb2f078123829a *src/Makevars 939998e93878fe298c4c0d5260db58b5 *src/Makevars.win 7fc53b7a1785e4d93d6a1c62c40d15f2 *src/RcppExports.cpp a15ae6aebcd209f67a10c2a914dfa525 *src/auxiliary.cpp r-cran-mclustcomp-0.3.3/NAMESPACE000066400000000000000000000001771412712370400163100ustar00rootroot00000000000000# Generated by roxygen2: do not edit by hand export(mclustcomp) import(Rdpack) importFrom(Rcpp,evalCpp) useDynLib(mclustcomp) r-cran-mclustcomp-0.3.3/NEWS.md000066400000000000000000000001501412712370400161560ustar00rootroot00000000000000# mclustcomp 0.3.3 * Change of maintainer's contact. # mclustcomp 0.3.2 * `NEWS` and `README` added. r-cran-mclustcomp-0.3.3/R/000077500000000000000000000000001412712370400152655ustar00rootroot00000000000000r-cran-mclustcomp-0.3.3/R/RcppExports.R000066400000000000000000000015061412712370400177030ustar00rootroot00000000000000# Generated by using Rcpp::compileAttributes() -> do not edit by hand # Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 #' Compute confusion matrix #' #' @keywords internal get.confusion <- function(x, y, ux, uy) { .Call('_mclustcomp_getconfusion', PACKAGE = 'mclustcomp', x, y, ux, uy) } #' Compute community size of a clustering #' #' @keywords internal get.commsize <- function(x, ux) { .Call('_mclustcomp_getcommsize', PACKAGE = 'mclustcomp', x, ux) } #' Comembership matrix of size \code{(2-by-2)} #' #' @keywords internal get.pair <- function(x, y) { .Call('_mclustcomp_getpair', PACKAGE = 'mclustcomp', x, y) } #' Compute confusion matrix #' #' @keywords internal get.probs <- function(confmat, scx, scy, n, threps) { .Call('_mclustcomp_getprobs', PACKAGE = 'mclustcomp', confmat, scx, scy, n, threps) } r-cran-mclustcomp-0.3.3/R/auxiliary.R000066400000000000000000000006331412712370400174210ustar00rootroot00000000000000# AUXILIARY FUNCTIONS # 1. conversion : input type conversion # 1. aux.conversion ------------------------------------------------------- #' @keywords internal #' @noRd aux.conversion <- function(x){ if (is.character(x)){ x = as.numeric(as.factor(unlist(strsplit(x,split="")))) } else if (is.factor(x)){ x = as.numeric(x) } else { x = as.numeric(as.factor(x)) } return(round(x)) } r-cran-mclustcomp-0.3.3/R/cat1_CountingPairs.R000066400000000000000000000115411412712370400211070ustar00rootroot00000000000000## CAT1 : Counting Pairs # 01. single01_chisq : Chi-Squared Coefficient # 02. single02_rand : Rand Index # 03. single03_adjrand : Adjusted Rand Index # 04. single04_fmi : Fowlkes-Mallows Index # 05. single05_mirkin : Mirkin Metric # 06. single06_jaccard : Jaccard Index # 07. single07_pd : Partition Difference # 16. single16_wallace1 : Wallace Criterion Type 1 # 17. single17_wallace2 : Wallace Criterion Type 2 # 18. single18_overlap : Overlap Coefficient # 19. single19_sdc : Sorensen-Dice Coefficient # 20. single20_smc : Simple Matching Coefficient # 22. single22_tversky : Tversky Index # 01. single01_chisq ------------------------------------------------------ #' @keywords internal #' @noRd single01_chisq <- function(confmat, scx, scy, n){ # 1. preliminary nx = length(scx) ny = length(scy) # 2. main computation output = 0 for (i in 1:nx){ for (j in 1:ny){ m_ij = confmat[i,j] e_ij = scx[i]*scy[j]/n output = output+ ((m_ij-e_ij)^2)/e_ij } } return(output) } # 02. single02_rand ------------------------------------------------------- #' @keywords internal #' @noRd single02_rand <- function(pairmat, n){ n11 = pairmat[2,2] n00 = pairmat[1,1] output = (2*(n00+n11))/(n*(n-1)) return(output) } # 03. single03_adjrand ---------------------------------------------------- #' @keywords internal #' @noRd single03_adjrand <- function(confmat,scx,scy,n){ # 1-1. preprocessing nk = length(scx) nl = length(scy) # 1-2. computing basic elements t1 = 0 for (i in 1:nk){ tx = scx[i] t1 = t1+ (tx*(tx-1))/2 } t2 = 0 for (j in 1:nl){ ty = scy[j] t2 = t2+ (ty*(ty-1))/2 } t3 = (2*t1*t2)/(n*(n-1)) summ = 0 for (i in 1:nk){ for (j in 1:nl){ tgt = confmat[i,j] summ = summ+(tgt*(tgt-1))/2 } } # 1-3. gathering up output = (summ-t3)/(((t1+t2)/2)-t3) return(output) } # 04. single04_fmi -------------------------------------------------------- #' @keywords internal #' @noRd single04_fmi <- function(pairmat){ # 4-1. separate n11 = pairmat[1,1] n01 = pairmat[2,1] n10 = pairmat[1,2] # 4-2. compute output = n11/sqrt((n11+n10)*(n11+n01)) return(output) } # 05. single05_mirkin ----------------------------------------------------- #' @keywords internal #' @noRd single05_mirkin <- function(confmat, scx, scy){ # 1. preliminary nk = length(scx) nl = length(scy) # 2. main iteration output = sum((scx^2)) + sum((scy^2)) for (i in 1:nk){ for (j in 1:nl){ tgt = confmat[i,j] output = output - (2*(tgt^2)) } } return(output) } # 06. single06_jaccard ---------------------------------------------------- #' @keywords internal #' @noRd single06_jaccard <- function(pairmat){ # 1. separate n11 = pairmat[1,1] n01 = pairmat[2,1] n10 = pairmat[1,2] # 2. compute output = n11/(n11+n10+n01) return(output) } # 07. single07_pd --------------------------------------------------------- #' @keywords internal #' @noRd single07_pd <- function(pairmat){ output = pairmat[2,2] return(output) } # 16. single16_wallace1 --------------------------------------------------- #' @keywords internal #' @noRd single16_wallace1 <- function(pairmat, scx){ n11 = pairmat[1,1] denom = sum((scx*(scx-1))/2) return(n11/denom) } # 17. single17_wallace2 --------------------------------------------------- #' @keywords internal #' @noRd single17_wallace2 <- function(pairmat, scy){ n11 = pairmat[1,1] denom = sum((scy*(scy-1))/2) return(n11/denom) } # 18. single18_overlap ---------------------------------------------------- #' @keywords internal #' @noRd single18_overlap <- function(pairmat){ x = pairmat[1,1]+pairmat[1,2] y = pairmat[1,1]+pairmat[2,1] output = pairmat[1,1]/min(x,y) return(output) } # 19. single19_sdc -------------------------------------------------------- #' @keywords internal #' @noRd single19_sdc <- function(pairmat){ TP = pairmat[1,1] FP = pairmat[1,2] FN = pairmat[2,1] output = (2*TP)/((2*TP)+FN+FP) return(output) } # 20. single20_smc -------------------------------------------------------- #' @keywords internal #' @noRd single20_smc <- function(pairmat){ output = (sum(diag(pairmat)))/(sum(pairmat)) return(output) } # 22. single22_tversky ---------------------------------------------------- # Tanimoto Coefficient is special case of Tversky Index with (alpha,beta)=(1,1) # alpha=0.5=beta : Dice's Coefficient / SDC # alpha=1=beta : Tanimoto Coefficient # sym=FALSE : original tversky # sym=TRUE : a variant introduced on Wikipedia #' @keywords internal #' @noRd single22_tversky <- function(pairmat,alpha,beta,sym){ TP = pairmat[1,1] FP = pairmat[1,2] FN = pairmat[2,1] if (!sym){ output = TP/(TP+(alpha*FP)+(beta*FN)) } else { a = min(FP,FN) b = max(FP,FN) output = TP/(TP+(beta*(alpha*a+(1-alpha)*b))) } return(output) } r-cran-mclustcomp-0.3.3/R/cat2_SetOverlap.R000066400000000000000000000031501412712370400204040ustar00rootroot00000000000000## CAT2 : Set Overlaps/Matching # 08. single08_f : F-Measure # 09. single09_mhm : Meila-Heckerman Measure # 10. single10_mmm : Maximum-Match Measure # 11. single11_vdm : Van Dongen Measure # 08. single08_f ---------------------------------------------------------- #' @keywords internal #' @noRd single08_f <- function(scx,scy,n){ # 1. preliminary kk = length(scx) ll = length(scy) # 2. computation output = 0 for (i in 1:kk){ tx = scx[i] vecvaly = (2*tx*scy)/(tx+scy) output = output + (tx*max(vecvaly)) } output = output/n return(output) } # 09. single09_mhm -------------------------------------------------------- #' @keywords internal #' @noRd single09_mhm <- function(confmat, n){ # 1. get size kk = dim(confmat)[1] # 2. compute output = 0 for (i in 1:kk){ output = output+max(confmat[i,]) } output = output/n return(output) } # 10. single10_mmm -------------------------------------------------------- #' @keywords internal #' @noRd single10_mmm <- function(confmat,n,nk,nl){ # 1. preprocessing minsize = min(nk,nl) # 2. iteration output = 0 for (i in 1:minsize){ output = output + max(confmat[i,]) } # 3. return output = output/n return(output) } # 11. single11_vdm -------------------------------------------------------- #' @keywords internal #' @noRd single11_vdm <- function(confmat,n){ # 1. preliminary nk = nrow(confmat) nl = ncol(confmat) # 2. iteration output = 2*n for (i in 1:nk){ output = output-max(confmat[i,]) } for (j in 1:nl){ output = output-max(confmat[,j]) } return(output) } r-cran-mclustcomp-0.3.3/R/cat3_InfoTheory.R000066400000000000000000000051071412712370400204130ustar00rootroot00000000000000## CAT3 : Information Theory # 12. single12_mi : Mutual Information # 13. single13_nmi1 : NMI by Strehl & Ghosh # 14. single14_nmi2 : NMI by Fred & Jain # 15. single15_vi : Variation of Information # 23. single23_jent : Joint Entropy # 24. single24_nmi3 : NMI by Danon # 25. single25_nvi : Normalized Variation of Information # 12. single12_mi --------------------------------------------------------- #' @keywords internal #' @noRd single12_mi <- function(Ixy){ return(Ixy) } # 13. single13_nmi1 ------------------------------------------------------- #' @keywords internal #' @noRd single13_nmi1 <- function(Ixy,Hx,Hy,threps){ correct = min(threps) altthr = c(threps,1e-10) denom = sqrt(Hx*Hy) if (denom(1-correct)){output = 1} return(output) } # 14. single14_nmi2 ------------------------------------------------------- #' @keywords internal #' @noRd single14_nmi2 <- function(Ixy,Hx,Hy,threps){ correct = min(threps) altthr = c(threps,1e-10) denom = Hx+Hy if (denom(1-correct)){output = 1} return(output) } # 15. single15_vi --------------------------------------------------------- #' @keywords internal #' @noRd single15_vi <- function(Ixy,Hx,Hy,threps){ correct = min(threps) # 1. prep altthr = c(threps,1e-10) if (Hx= 0.")} if (tversky.param$beta < 0){stop("* mclustcomp : tversky.param$beta should be >= 0.")} if (!is.logical(tversky.param$sym)){stop("* mclustcomp : tversky.param$sym should be a logical variable; FALSE for original Tversky index, TRUE for a variant.")} #------------------------------------------------------------------------ ## PRELIMINARY COMPUTATIONS ## Prelim1 : CONFUSION MATRIX of size(length(ux),length(uy)) confmat = get.confusion(x,y,ux,uy) ## Prelim2 : size of each cluster scx = get.commsize(x,ux) scy = get.commsize(y,uy) ## Prelim3 : comembership matrix of (2,2) pairmat = get.pair(x,y) ## Prelim4 : probability-related stuffs for Mutual Information threps = min(1e-10,10*(.Machine$double.eps)) probs = get.probs(confmat,scx,scy,n,threps) ## Control : type.out ## Case 1 : Single Argument ## {"all" or single name} ## Case 2 : a vector of names; c("f","rand") type_allnames = c("adjrand","chisq","f","fmi","jaccard","mhm","mirkin","mmm", "mi","nmi1","nmi2","overlap","pd","rand","sdc","smc","tanimoto", "tversky","vdm","vi","wallace1","wallace2","jent","nvi") type_out = unique(types) if ("all" %in% type_out){ type_test = sort(type_allnames) } else { type_test = sort(type_out) # this type test is the one we should generate again } #------------------------------------------------------------------------ ## MAIN COMPUTATION type_score = rep(0,length(type_test)) for (i in 1:length(type_test)){ type_score[i] = mclustsingle(n,x,y,ux,uy,scx,scy,confmat,pairmat,probs,threps,type_test[i],tversky.param) } #------------------------------------------------------------------------ ## RETURN RESULTS result = data.frame(types=type_test,scores=type_score) return(result) } # COMPUTE :: single measure branching ------------------------------------- ## Original Implementation of 19 methods mclustsingle <- function(n,x,y,ux,uy,scx,scy,confmat,pairmat,probs,threps,type,tversky.param){ # Missing parameters for score08_mmm nk = length(scx) nl = length(scy) # Sepearting probs for NMI and VIs Ixy = probs$Ixy Hx = probs$Hx Hy = probs$Hy Pxy = (confmat/n) # joint probability matrix + correction Pxy[(Pxy. #' #' @docType package #' @name mclustcomp-package #' @import Rdpack #' @importFrom Rcpp evalCpp #' @useDynLib mclustcomp NULL r-cran-mclustcomp-0.3.3/README.md000066400000000000000000000014151412712370400163440ustar00rootroot00000000000000 mclustcomp ========== [![CRAN\_Status\_Badge](http://www.r-pkg.org/badges/version/mclustcomp?color=green)](https://cran.r-project.org/package=mclustcomp) [![Travis-CI Build Status](https://travis-ci.org/kisungyou/mclustcomp.svg?branch=master)](https://travis-ci.org/kisungyou/mclustcomp) [![](https://cranlogs.r-pkg.org/badges/mclustcomp)](https://cran.r-project.org/package=mclustcomp) Installation ------------ You can install the released version of mclustcomp from [CRAN](https://CRAN.R-project.org) with: ``` r install.packages("mclustcomp") ``` or the development version from github: ``` r ## install.packages("devtools") ## library(devtools) devtools::install_github("kisungyou/mclustcomp") ``` r-cran-mclustcomp-0.3.3/build/000077500000000000000000000000001412712370400161635ustar00rootroot00000000000000r-cran-mclustcomp-0.3.3/build/partial.rdb000066400000000000000000000304631412712370400203160ustar00rootroot00000000000000}[sG&LDʦ,2I qUx($u ]D*@ xlF}ؘ}؈}KļLD?y?7OQ*@.}DɬbXW-) ?S?c?_r~eEPMdJLeu;$oݰ ͫ6|PT|,1ŵ֛-3g"T l^WU쎹s-\=O3-zȫ^ܣ+%j|7*[)D}?NU74Ū}sWM͍9f+G 3` E{vǖ/OH"U,FIUJT[5td"7K](qW6/b`&jltq~ "^Brɺq֖[Wxu+ ^Fڗyr=U4U<8?{r /InMŤ)&gQL!yp]8Dw٪tmoG.`1xtWӳ9F,3hy'8eֈ`?Pگ椔د5ղGFGEO =#5U,e]kgbMueԭꈗt68߸crR7(Aa9LKVh6LgF)T͏ EG$MKlBEWZւmZhrEϖ8yZ4LW"}Ubev!M)yLjWL:ޫJEe!QRr1f_C\Az%UHMs$'0 VX$d\)5}l)EgH? TDw}6s5&(mJ8tiǶiCi-PpŦSPDΗ|ںzvp+3Q<} !;w۰G: E+nZ@|; 3e7y?^y4tL)O#<#~"G4=_ ~ׁE:^:p!SV+z6:"A`U0Sf9E#~t1tF^][Z;!Y4.@.X6 S4LuOՙ0[@"7rVt!g}^ /rW@1aITɁbn ,ᱦcHCcdfC?:zw$O*f#?ı} W8K粊D32{#? AdiΤVaq #"=+Gi6?N"ҋ8K%< >DZXt@*zЙO`]˲g#> h?PNCF sL68 ۫3# vNK0E m8qi ;K=BL |!a 1t: Ϥ}xfw"L? 8Qm|c^T] ֹXO}D3)b|`q6N:yj{5Æb;YyMjQd.'H? [FAQ}UT@G>Yo9vyx0V% qֻRY<BTCtފ?2u=ڕ+Ql*UͰrc^3I4tTCM7ސL ݒGߏuR]j#ִzmaVIQ E5EsBDy9{Cul@5 9aWNg!H_5ǡ:gE"( A/XJLyVgc 8OU_8x+q*3=8HZ'!^+&+=J^~S bT|XN%Ѧ kO,R ;Hm1CCfhe8}L2f{&k;z/=h uE}Mzp.&$ xy"~CԖ->(}C!`h?0 q?xIJùj}#otx !N&D8HG b?0?v|/ 뛊bM-[ ٯ#>F඲t[tl|K 5RSc G,X7"Ri/pW40CTV  Jp',^n 8X[ݩO t㻁%PۧVbU45#n !/xED_m qi_z`wtf=W9+@Ԑ֢ }C$g_(bS^XdAˈg b{`?a8=#>DSh2?Ҿ9Ҿs M_ f[88KR?3\R}UNi_2bHon}HG ̟&Nc ?$TEzObdALrt̏Ն"+ h`,+^QԔpDsXG^u/ bK9`?a8\Rnm;WϜzt u5פt(`]었9su*b>V_r:o}o[j C9~ "Eҿ{}OC$e>ҋh(NbؕAn%A HGSADy=;d jB' bi_% Z`@Gz<I}-ڂ-{z[n ~. B-pD`y8i#_uYcyK~1"n"M|`!^|`|`C$a+N17F~UN?."Ģ~N\;sI5G AHoKb?]orǿIAg&Fh!]S6߸W40 ;`Ê{J'ދam(Nd}\;)!f_)FwGJ[5#>EWV\A* W?Gj[EHKȈp,#zGL_"2^W9KRpnVtd؆p'm"^?ǣkH_>!W?\ uD 1|#>GZ]EϣO &/B&~`5xIJgqvOjzc-Θq :=\M}~:bkxaLjv:!^d~`b8iJS?<#EOZ8pm\ekȼ¶NeJR r !&NF4A:} ietu,iZ8FuQ^i A!)i )g&;!b/>M;Sa_JLs[o:;'9?d]qrT2$< [ V ,F-PC8nha}O4lj\n[ 9DQV13'Ё5 Ǚ[kNo~P3}[֜B/Fg>֚֜mn r(wkSr~:Lz6r~a:tu@x8xi )pCtQXœc?*JuD pfa(r(.Kq 9"F~jUAy맄"xEQ^^#TՔCۧfI,5-'&fiq c؏s-l̍ScvU,a1 \UTKRXjqѨ"F tS GA^Ekĸa831 V:o)̟!>`ma?2˙1nsWԞޫIz0tTP3}vp:wtgc'`:w`ӹmNʝ==p {?֭qC"&6K`ǡ'Jk?@,10!^;WNaZi=k5 5|BG:E;ƶGxyvWyC)s%+s}1s<`ͻ;(os4O@ }HGk?6YEG` "[4 LGo#݁CUizI_Z/bUڂҀ}ViU0*-y|cK54` b)%,*0t2s/]b9bLɸI˰'&є]iHTPZzjɀzܫ2=^n>~ÆZXLi!xF^ƫ(lp+͇7PZںȻr(1sPJ(@IE#/nMp}}Guj*6e膞M@m*Jm"[́P942-7rㅻeߌsn:a ."ߎFW)2ꊍ6M-6.RԈ 쭜TX'`xԁ}k('B"43FpW1[*%aX#~NvaWS-{h}Ͼ IRٮ:"sP^xV^L\,]M.\02r}|!U+(U- 2h_8WittFs?NţX`{7qBYTP^:<^xS^:fTXP^[H_#<"cy-۳YLǰ *xF}ŃnLG4jOOsv,_ᮙ[GVT-wjaCuTȍ|Y*&B(i4Atz8FO;nQaw7S7 q3}#MH;|(,Nv'Lfs ޞl-no.1@1*)9h\ֵfONA8.<"#ԊQ yd)UeLdǺq%bQ1=4}R0L2ovUΞZeMҮ~^5) rY1vL6PJX<#,. UL}y' bd銓堷2'dr&HL;OHj2NLLd&OVt,om{|Cf:QqEsn1X+`Gʇi9R͙5z$^)]hUő[t\-oȪSMD xS ỉk6߰Hщʯc<ɳƢ9*' Z3^ˇ]Q1uENz1dj։g+p5;sQ8[afUA3L}NLNL'gA+ul{FKߴ"hp0HlQ hHJ c^US@5p<=0wJHl1ܦpY'XܐqP1풢y']rHuq+Wr܏gYEм56*\$"o:W )HMO%&S3qȤDde&^t:SS7n(澪PP ICcFZxUG1rߩR1~ΏzՂGW c(`&(HTanPUɶPE34Dk#y m5YEĪ]Ehm40Pqnn[,ȩ~ugkp}55uQ# #5`z?etjbRxEΉ(* :qE~Eg7(; PL)hr,)zeX F0"MWJel5[O$†LMkZ{KY4SHY$g@urƆi(;o>[^\\$:k>Sl Ԥ8[UֶJV"yp[݅uD53-^m(af%5t:T_LL$3ɩDd%J^߸X7(>v vR3T1њf3*?[r5#!Ejqhfފm`b'Mj۔C1v-y:^\UX侸K n V\(J˼R˴dU֑_,'GE $WԍFnߴ.]D~W2݊sQj6IM;#W?TZӜi?x퇋dE'kd}V7"b}mqLxI4Dy :b64cЉr89׈MW*u1NX Y|f8"jgSS%L*3}Z@:ֱXݸV]TfSI9K%(ң>WT'{jQ1 _*| Aۜ6h㙧uR)ն:vÃ3RE6HzO"M%ѲH-~.2W.k*;+4Mgmkpԕ}7lwxF}%dőlz"155 t&1=1+\#^ۍ+$Yu#oZutISL;ŲwRroє#HX.|wQ c3tJarhvV.㫦ȨE%fvڡbӗ6)hN3a%JFԨDS4D"y c gm+f gA-E27J<^X jr\rEyAmWljy^8?z)V\;SO8SəT*HMde ^u :iŐ{ ?V4Zp]ǯvvsVj>ޘ-6I?xvwtnjYiɮy%;geV*Ņ< p]y 7&=Ow<;p|#>s&'.Hj4NfYE$>D3tz'JW  XV :c'DY'q?GkFFKOKSx4#۫()y4wwY!"wAE>T2LRpY@!iP+;zFz88y:{0P`Sdď"=Цcxw4!E(Ǥ}eBu~veOU Pl'4g骏:mfM8޽ﻰ .$;v_bCj6LU[H:u|J+)9 +&a$q_9H Bzgjd zS!Gf޵hKJ4g@1WBF!\yvN|F>\߉o; y GpavM _)U-VI1mrHwIz,I=]iZd6j !Ñ&U5g ٢ eC#_}uBD[09;LI%zjjjffjF|WpZ=@qES.i=6_)PgӒD{&~ 0<vu#s>)|`̏ZR5Th*&[upNaUsEwD&N A]3'p?2{_a>)> I(g2zpAq+0ָΌ :i͕:tOm!GGsFx!8YSM<`B/*"y's&o"x:{r&giۊ'sZY9MRcˍDϪ)WMI'!uS8yg$9 l29H6LOSO1S@m7u|ʧ5EϩF; n%if@z"2*«Ӓa] 'ZߒGNcLPlSpҏY|kgB)r"@i*َїه/C<J:8t+6UKp}YI!J*\;[=قJ%+ڪwtb79r9p6VTw.7|qDZjvWnᱩ o[[Uٵlե|A?*D=gf{ ؕ|EC;QTY%ˆNPbu ݶ7V^̖Yp:Vכ-9[6lVTϫm}V{a-އ6rK[~f{lx(|N9ĐJ<ʳŐ*j ,߽zX:h ڝdg䝭i=7ˆbF-abwjY-oؼ$ s_?t|fY9ZQx&Ols4MnMVt1˳AUͪxT2#b6-߶sTjAS>oh6vۆ*dJ!VmsAK7)jZ:&z{p7 m3fh5ZSGl2ؤp&{Ukl1Iz-PۮQ^;Ëm gթ Nμ&3Y[٭hMhYy+wٶ̯Թ6kXC)t)I-P+.XYJ9>6Ζ_;?` ](a4dZ^1nfݹsg3Bpu̠~f43WX H9~92]d{)۳n0 0O?~_"v՚]kΏvZ|4^qt|qw8nU-jKMOrqoctjVIwi~"?1?8vˆX\yrdfZo}4lgcsfmx[HhמWWmSEoaNcᅢAw߹\i wx6 h T2V,2fMٿmԜA"}ׯ-ܚ^eh8唇mlL0+`1=d~iѻ8*ҫRTfŤrv>sINwQ$ X-Ng3c~AZ]>:l `ɱ/-m-}r[Yܚ\^^_c U'=+U9o&;092LpO<7Pc,Y) T9zϾN{kcѶG~WRj  jBc F5 q