GPArotation/0000755000176200001440000000000015174331613012445 5ustar liggesusersGPArotation/tests/0000755000176200001440000000000015174250607013612 5ustar liggesusersGPArotation/tests/Revelle.R0000644000176200001440000000072214323662112015325 0ustar liggesusers# This tests fix for an error caused by an exact initial setting. # (from William Revelle) require("GPArotation") f3 <- structure(c(0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0,0), .Dim = c(6L, 3L), .Dimnames = list(NULL, c("PC1", "PC2", "PC3"))) f3 # PC1 PC2 PC3 #[1,] 0 0 1 #[2,] 0 1 0 #[3,] 1 0 0 #[4,] 0 0 1 #[5,] 0 1 0 #[6,] 1 0 0 # These previously gave object 'VgQt' not found GPForth(f3) Varimax(f3) GPArotation/tests/vgQtestOldVsNew.R0000644000176200001440000002672315164770065017032 0ustar liggesusers# vgQtestOldVsNew.R # Regression tests: new vgQ functions vs original implementations. # f and Gq are compared within tolerance to allow for floating point # differences due to different order of arithmetic operations. # Method strings are not compared --- changes are intentional improvements. # A real bug (mccammon Gq) was detected by these tests in 2026.4-1. require("GPArotation") source("vgQOLD.R") all.ok <- TRUE tol <- 1e-10 set.seed(123) L8x2 <- matrix(rnorm(16), nrow = 8, ncol = 2) L10x3 <- matrix(rnorm(30), nrow = 10, ncol = 3) L15x4 <- matrix(rnorm(60), nrow = 15, ncol = 4) L20x5 <- matrix(rnorm(100), nrow = 20, ncol = 5) matrices <- list(L8x2, L10x3, L15x4, L20x5) # Helper: check structural contract check_contract <- function(res, name) { ok <- TRUE if (!all(c("f", "Gq", "Method") %in% names(res))) { cat("FAILED:", name, "- missing list elements\n") ok <- FALSE } if (!is.numeric(res$f) || length(res$f) != 1) { cat("FAILED:", name, "- f is not a scalar numeric\n") ok <- FALSE } if (!is.character(res$Method) || length(res$Method) != 1) { cat("FAILED:", name, "- Method is not a scalar character\n") ok <- FALSE } ok } # Helper: check new vs old within tolerance # Method strings are not compared --- changes are intentional check_values <- function(new, old, name, tol = 1e-10) { ok <- TRUE if (max(abs(new$f - old$f)) > tol) { cat("FAILED:", name, "- f differs beyond tolerance\n") cat(" max diff:", max(abs(new$f - old$f)), "\n") ok <- FALSE } if (max(abs(new$Gq - old$Gq)) > tol) { cat("FAILED:", name, "- Gq differs beyond tolerance\n") cat(" max diff:", max(abs(new$Gq - old$Gq)), "\n") ok <- FALSE } ok } # ------------------------------------------------------------------- # oblimin --- gam = 0, 0.25, 0.5 # ------------------------------------------------------------------- for (L in matrices) { for (gam in c(0, 0.25, 0.5)) { nm <- paste("vgQ.oblimin gam=", gam, dim(L)[1], "x", dim(L)[2]) new <- GPArotation:::vgQ.oblimin(L, gam = gam) old <- vgQOLD.oblimin(L, gam = gam) all.ok <- all.ok & check_contract(new, nm) all.ok <- all.ok & check_values(new, old, nm) } } # ------------------------------------------------------------------- # quartimin # ------------------------------------------------------------------- for (L in matrices) { nm <- paste("vgQ.quartimin", dim(L)[1], "x", dim(L)[2]) new <- GPArotation:::vgQ.quartimin(L) old <- vgQOLD.quartimin(L) all.ok <- all.ok & check_contract(new, nm) all.ok <- all.ok & check_values(new, old, nm) } # ------------------------------------------------------------------- # target --- with and without NA # ------------------------------------------------------------------- set.seed(456) for (L in matrices) { Target <- matrix(rnorm(length(L)), nrow = nrow(L), ncol = ncol(L)) nm <- paste("vgQ.target", dim(L)[1], "x", dim(L)[2]) new <- GPArotation:::vgQ.target(L, Target = Target) old <- vgQOLD.target(L, Target = Target) all.ok <- all.ok & check_contract(new, nm) all.ok <- all.ok & check_values(new, old, nm) } # target with NA Target_na <- matrix(c(rep(NA, 4), rep(0, 4)), nrow = 8, ncol = 2) new <- GPArotation:::vgQ.target(L8x2, Target = Target_na) old <- vgQOLD.target(L8x2, Target = Target_na) all.ok <- all.ok & check_contract(new, "vgQ.target with NA") all.ok <- all.ok & check_values(new, old, "vgQ.target with NA") # ------------------------------------------------------------------- # pst # ------------------------------------------------------------------- set.seed(789) for (L in matrices) { W <- matrix(sample(0:1, length(L), replace = TRUE), nrow = nrow(L), ncol = ncol(L)) Target <- matrix(0, nrow = nrow(L), ncol = ncol(L)) nm <- paste("vgQ.pst", dim(L)[1], "x", dim(L)[2]) new <- GPArotation:::vgQ.pst(L, W = W, Target = Target) old <- vgQOLD.pst(L, W = W, Target = Target) all.ok <- all.ok & check_contract(new, nm) all.ok <- all.ok & check_values(new, old, nm) } # ------------------------------------------------------------------- # oblimax # ------------------------------------------------------------------- for (L in matrices) { nm <- paste("vgQ.oblimax", dim(L)[1], "x", dim(L)[2]) new <- GPArotation:::vgQ.oblimax(L) old <- vgQOLD.oblimax(L) all.ok <- all.ok & check_contract(new, nm) all.ok <- all.ok & check_values(new, old, nm) } # ------------------------------------------------------------------- # entropy # ------------------------------------------------------------------- for (L in matrices) { nm <- paste("vgQ.entropy", dim(L)[1], "x", dim(L)[2]) new <- GPArotation:::vgQ.entropy(L) old <- vgQOLD.entropy(L) all.ok <- all.ok & check_contract(new, nm) all.ok <- all.ok & check_values(new, old, nm) } # ------------------------------------------------------------------- # quartimax # ------------------------------------------------------------------- for (L in matrices) { nm <- paste("vgQ.quartimax", dim(L)[1], "x", dim(L)[2]) new <- GPArotation:::vgQ.quartimax(L) old <- vgQOLD.quartimax(L) all.ok <- all.ok & check_contract(new, nm) all.ok <- all.ok & check_values(new, old, nm) } # ------------------------------------------------------------------- # varimax # ------------------------------------------------------------------- for (L in matrices) { nm <- paste("vgQ.varimax", dim(L)[1], "x", dim(L)[2]) new <- GPArotation:::vgQ.varimax(L) old <- vgQOLD.varimax(L) all.ok <- all.ok & check_contract(new, nm) all.ok <- all.ok & check_values(new, old, nm) } # ------------------------------------------------------------------- # simplimax --- default k and custom k # ------------------------------------------------------------------- for (L in matrices) { for (k in c(nrow(L), floor(nrow(L) / 2))) { nm <- paste("vgQ.simplimax k=", k, dim(L)[1], "x", dim(L)[2]) new <- GPArotation:::vgQ.simplimax(L, k = k) old <- vgQOLD.simplimax(L, k = k) all.ok <- all.ok & check_contract(new, nm) all.ok <- all.ok & check_values(new, old, nm) } } # ------------------------------------------------------------------- # bentler # ------------------------------------------------------------------- for (L in matrices) { nm <- paste("vgQ.bentler", dim(L)[1], "x", dim(L)[2]) new <- GPArotation:::vgQ.bentler(L) old <- vgQOLD.bentler(L) all.ok <- all.ok & check_contract(new, nm) all.ok <- all.ok & check_values(new, old, nm) } # ------------------------------------------------------------------- # tandemI # ------------------------------------------------------------------- for (L in matrices) { nm <- paste("vgQ.tandemI", dim(L)[1], "x", dim(L)[2]) new <- GPArotation:::vgQ.tandemI(L) old <- vgQOLD.tandemI(L) all.ok <- all.ok & check_contract(new, nm) all.ok <- all.ok & check_values(new, old, nm) } # ------------------------------------------------------------------- # tandemII # ------------------------------------------------------------------- for (L in matrices) { nm <- paste("vgQ.tandemII", dim(L)[1], "x", dim(L)[2]) new <- GPArotation:::vgQ.tandemII(L) old <- vgQOLD.tandemII(L) all.ok <- all.ok & check_contract(new, nm) all.ok <- all.ok & check_values(new, old, nm) } # ------------------------------------------------------------------- # geomin --- default and custom delta # ------------------------------------------------------------------- for (L in matrices) { for (delta in c(0.01, 0.001)) { nm <- paste("vgQ.geomin delta=", delta, dim(L)[1], "x", dim(L)[2]) new <- GPArotation:::vgQ.geomin(L, delta = delta) old <- vgQOLD.geomin(L, delta = delta) all.ok <- all.ok & check_contract(new, nm) all.ok <- all.ok & check_values(new, old, nm) } } # ------------------------------------------------------------------- # bigeomin # ------------------------------------------------------------------- for (L in matrices) { nm <- paste("vgQ.bigeomin", dim(L)[1], "x", dim(L)[2]) new <- GPArotation:::vgQ.bigeomin(L) old <- vgQOLD.bigeomin(L) all.ok <- all.ok & check_contract(new, nm) all.ok <- all.ok & check_values(new, old, nm) } # ------------------------------------------------------------------- # cf --- kappa = 0, 0.3, 1 # ------------------------------------------------------------------- for (L in matrices) { for (kappa in c(0, 0.3, 1)) { nm <- paste("vgQ.cf kappa=", kappa, dim(L)[1], "x", dim(L)[2]) new <- GPArotation:::vgQ.cf(L, kappa = kappa) old <- vgQOLD.cf(L, kappa = kappa) all.ok <- all.ok & check_contract(new, nm) all.ok <- all.ok & check_values(new, old, nm) } } # ------------------------------------------------------------------- # infomax # ------------------------------------------------------------------- for (L in matrices) { nm <- paste("vgQ.infomax", dim(L)[1], "x", dim(L)[2]) new <- GPArotation:::vgQ.infomax(L) old <- vgQOLD.infomax(L) all.ok <- all.ok & check_contract(new, nm) all.ok <- all.ok & check_values(new, old, nm) } # ------------------------------------------------------------------- # mccammon # ------------------------------------------------------------------- for (L in matrices) { nm <- paste("vgQ.mccammon", dim(L)[1], "x", dim(L)[2]) new <- GPArotation:::vgQ.mccammon(L) old <- vgQOLD.mccammon(L) all.ok <- all.ok & check_contract(new, nm) all.ok <- all.ok & check_values(new, old, nm) } # ------------------------------------------------------------------- # bifactor --- first column of Gq must be zero # ------------------------------------------------------------------- for (L in matrices) { nm <- paste("vgQ.bifactor", dim(L)[1], "x", dim(L)[2]) new <- GPArotation:::vgQ.bifactor(L) old <- vgQOLD.bifactor(L) all.ok <- all.ok & check_contract(new, nm) all.ok <- all.ok & check_values(new, old, nm) if (!all(new$Gq[, 1] == 0)) { cat("FAILED:", nm, "- first column of Gq not zero\n") all.ok <- FALSE } } # ------------------------------------------------------------------- # varimin # ------------------------------------------------------------------- for (L in matrices) { nm <- paste("vgQ.varimin", dim(L)[1], "x", dim(L)[2]) new <- GPArotation:::vgQ.varimin(L) old <- vgQOLD.varimin(L) all.ok <- all.ok & check_contract(new, nm) all.ok <- all.ok & check_values(new, old, nm) } # ------------------------------------------------------------------- # lp.wls # ------------------------------------------------------------------- set.seed(321) for (L in matrices) { W <- matrix(runif(length(L)), nrow = nrow(L), ncol = ncol(L)) nm <- paste("vgQ.lp.wls", dim(L)[1], "x", dim(L)[2]) new <- GPArotation:::vgQ.lp.wls(L, W = W) old <- vgQOLD.lp.wls(L, W = W) all.ok <- all.ok & check_contract(new, nm) all.ok <- all.ok & check_values(new, old, nm) } # ------------------------------------------------------------------- # Gq dimensions match L for all criteria # ------------------------------------------------------------------- criteria <- c("oblimin", "quartimin", "oblimax", "entropy", "quartimax", "varimax", "simplimax", "bentler", "tandemI", "tandemII", "geomin", "bigeomin", "infomax", "mccammon", "bifactor", "varimin") for (crit in criteria) { fn <- get(paste("vgQ", crit, sep = "."), envir = asNamespace("GPArotation")) for (L in matrices) { res <- fn(L) if (!identical(dim(res$Gq), dim(L))) { cat("FAILED: vgQ.", crit, "Gq dimensions do not match L:", dim(L), "vs", dim(res$Gq), "\n") all.ok <- FALSE } } } cat("vgQ regression tests completed.\n") if (!all.ok) stop("some tests FAILED")GPArotation/tests/lp.R0000644000176200001440000001350314763342661014357 0ustar liggesusers Sys.getenv("R_LIBS") library() require("GPArotation") search() Sys.info() #sortFac <- function(x){ # Based on Fungible faSort # vx <- order(colSums(x$loadings^2), decreasing = TRUE) # Dsgn <- diag(sign(colSums(x$loadings^3))) [ , vx] # x$Th <- x$Th %*% Dsgn # x$loadings <- x$loadings %*% Dsgn # if ("Phi" %in% names(x)) { # x$Phi <- diag(1/diag(Dsgn)) %*% x$Phi %*% Dsgn # } # x #} sortFac <- function(x){ # Based on Fungible faSort vx <- order(colSums(x$loadings^2), decreasing = TRUE) Dsgn <- diag(sign(colSums(x$loadings^3))) [ , vx] x$Th <- x$Th %*% Dsgn x$loadings <- x$loadings %*% Dsgn if ("Phi" %in% names(x)) { x$Phi <- diag(1/diag(Dsgn)) %*% x$Phi %*% Dsgn } x } fuzz <- 1e-5 # using eps=1e-5 these tests do not do better than this all.ok <- TRUE ####################################### ####################################### #test 1 L <- rbind(diag(3),diag(3),diag(3),diag(3),diag(3),diag(3),diag(3),diag(3),diag(3),diag(3)) True_rot<-matrix(c(1,0.02079577,0.5024378, 0,0.99978374,0.2635086, 0,0,0.8234801),3,3,byrow=TRUE) L1 <- L%*%t(True_rot) r1 <- lpQ(L1,diag(3),maxit=1000) tst <- t(matrix(c( 9.990889e-01, 6.082765e-05, 0.0018180081, 5.911473e-05, 9.997556e-01, 0.0008914537, 1.819385e-03, 8.932991e-04, 0.9988458881, 9.990889e-01, 6.082765e-05, 0.0018180081, 5.911473e-05, 9.997556e-01, 0.0008914537, 1.819385e-03, 8.932991e-04, 0.9988458881, 9.990889e-01, 6.082765e-05, 0.0018180081, 5.911473e-05, 9.997556e-01, 0.0008914537, 1.819385e-03, 8.932991e-04, 0.9988458881, 9.990889e-01, 6.082765e-05, 0.0018180081, 5.911473e-05, 9.997556e-01, 0.0008914537, 1.819385e-03, 8.932991e-04, 0.9988458881, 9.990889e-01, 6.082765e-05, 0.0018180081, 5.911473e-05, 9.997556e-01, 0.0008914537, 1.819385e-03, 8.932991e-04, 0.9988458881, 9.990889e-01, 6.082765e-05, 0.0018180081, 5.911473e-05, 9.997556e-01, 0.0008914537, 1.819385e-03, 8.932991e-04, 0.9988458881, 9.990889e-01, 6.082765e-05, 0.0018180081, 5.911473e-05, 9.997556e-01, 0.0008914537, 1.819385e-03, 8.932991e-04, 0.9988458881, 9.990889e-01, 6.082765e-05, 0.0018180081, 5.911473e-05, 9.997556e-01, 0.0008914537, 1.819385e-03, 8.932991e-04, 0.9988458881, 9.990889e-01, 6.082765e-05, 0.0018180081, 5.911473e-05, 9.997556e-01, 0.0008914537, 1.819385e-03, 8.932991e-04, 0.9988458881, 9.990889e-01, 6.082765e-05, 0.0018180081, 5.911473e-05, 9.997556e-01, 0.0008914537, 1.819385e-03, 8.932991e-04, 0.9988458881 ), 3, 30)) if( fuzz < max(abs(r1$loadings - tst ))) { cat("irls: Calculated value is not the same as test value in test test 1. Value:\n") print(r1$loadings, digits=18) cat("difference:\n") print(r1$loadings - tst, digits=18) all.ok <- FALSE } # test 2 set.seed(1001) r2 <- lpQ(L1,p=1,randomStarts=10) tst <- t(matrix(c( 6.068202e-05, 9.990904e-01, 0.0018150388, 9.997560e-01, 5.852987e-05, 0.0008900377, 8.933085e-04, 1.819065e-03, 0.9988460399, 6.068202e-05, 9.990904e-01, 0.0018150388, 9.997560e-01, 5.852987e-05, 0.0008900377, 8.933085e-04, 1.819065e-03, 0.9988460399, 6.068202e-05, 9.990904e-01, 0.0018150388, 9.997560e-01, 5.852987e-05, 0.0008900377, 8.933085e-04, 1.819065e-03, 0.9988460399, 6.068202e-05, 9.990904e-01, 0.0018150388, 9.997560e-01, 5.852987e-05, 0.0008900377, 8.933085e-04, 1.819065e-03, 0.9988460399, 6.068202e-05, 9.990904e-01, 0.0018150388, 9.997560e-01, 5.852987e-05, 0.0008900377, 8.933085e-04, 1.819065e-03, 0.9988460399, 6.068202e-05, 9.990904e-01, 0.0018150388, 9.997560e-01, 5.852987e-05, 0.0008900377, 8.933085e-04, 1.819065e-03, 0.9988460399, 6.068202e-05, 9.990904e-01, 0.0018150388, 9.997560e-01, 5.852987e-05, 0.0008900377, 8.933085e-04, 1.819065e-03, 0.9988460399, 6.068202e-05, 9.990904e-01, 0.0018150388, 9.997560e-01, 5.852987e-05, 0.0008900377, 8.933085e-04, 1.819065e-03, 0.9988460399, 6.068202e-05, 9.990904e-01, 0.0018150388, 9.997560e-01, 5.852987e-05, 0.0008900377, 8.933085e-04, 1.819065e-03, 0.9988460399, 6.068202e-05, 9.990904e-01, 0.0018150388, 9.997560e-01, 5.852987e-05, 0.0008900377, 8.933085e-04, 1.819065e-03, 0.9988460399 ), 3, 30)) if( fuzz < max(abs(sortFac(r2)$loadings - tst ))) { cat("irls Calculated value is not the same as test value in test 2. Value:\n") print(r2$loadings, digits=18) cat("difference:\n") print(r2$loadings - tst, digits=18) all.ok <- FALSE } #test 3 data("WansbeekMeijer", package="GPArotation") fa.unrotated <- factanal(factors = 2, covmat=NetherlandsTV, rotation="none") set.seed(100102) r3 <- lpQ(fa.unrotated$loadings, p=0.75, randomStarts = 50) tst <- t(matrix(c( -0.002173496, 0.792259797, 0.100607850, 0.781465993, 0.002154186, 0.772058937, 0.617379876, 0.138657906, 0.707274693, 0.090566478, 0.822845923, -0.009242103, 0.725228135, 0.002691264 ), 2, 7)) if( fuzz < max(abs(sortFac(r3)$loadings - tst ))) { cat("irls: Calculated value is not the same as test value in test 3. Value:\n") print(r3$loadings, digits=18) cat("difference:\n") print(r3$loadings - tst, digits=18) all.ok <- FALSE } #test 4 data("WansbeekMeijer", package="GPArotation") fa.unrotated <- factanal(factors = 3, covmat=NetherlandsTV, rotation="none") set.seed(100102) r4 <- lpT(fa.unrotated$loadings, p=0.75, randomStarts = 50) tst <- t(matrix(c( 0.4231105, 0.669080641, 0.0078944327, 0.5205654, 0.659289508, -0.0008080892, 0.4202373, 0.648462232, -0.0127761636, 0.7171426, 0.100648821, -0.0888999851, 0.7436880, 0.086465344, 0.0308002902, 0.8111649, -0.001129993, -0.0001462372, 0.7373292, -0.000421333, 0.6718224963 ), 3, 7)) if( fuzz < max(abs(sortFac(r4)$loadings - tst ))) { cat("irls: Calculated value is not the same as test value in test 4. Value:\n") print(r4$loadings, digits=18) cat("difference:\n") print(r4$loadings - tst, digits=18) all.ok <- FALSE } if (! all.ok) stop("some tests FAILED") GPArotation/tests/Thurstone.R0000644000176200001440000003353114323662112015726 0ustar liggesusers#Example from: Gradient Projection Algorithms and Software for # Arbitrary Rotation Criteria in Factor Analysis. # by Coen A. Bernaards and Robert I. Jennrich # Website: http://www.stat.ucla.edu/research Sys.getenv("R_LIBS") library() require("GPArotation") search() Sys.info() data("Thurstone", package="GPArotation") if (!exists("box20")) stop("Test data not found. Testing stopped.") fuzz <- 1e-5 all.ok <- TRUE # Thurstone's box problem. (1947, p. 136) # The matrix box20 is the initial loading matrix from Thurstone's box problem. # This takes a lot of iterations to converge at a higher tolerance qbox20 <- quartimax(box20, eps=1e-5) qbox20G <- GPForth(box20, Tmat=diag(1,3), method="quartimax", eps=1e-5) if( fuzz < max(abs(qbox20$loadings - qbox20G$loadings))) { cat("Calculated value is not the same as test value in test Thurstone 1. Value:\n") print(qbox20$loadings - qbox20G$loadings, digits=18) cat("difference:\n") print(qbox20$loadings - tst, digits=18) all.ok <- FALSE } #qbox20$Th - qbox20G$Th # These values compare with those in: # http://www.stat.ucla.edu/research/web.pdf tst <- t(matrix(c( 0.0104916072210123716, -0.993396087928394733, -0.089861775335686706, 0.1584646383898045685, -0.167305085570175344, -0.967087879524061056, 0.9822741057703969769, -0.094961339079248266, -0.081938545344928893, 0.1249962020162782989, -0.597065497283680413, -0.789290657131387352, 0.8695614167874907707, -0.471622450093366785, -0.090438968384549553, 0.8757114893176747294, -0.141012080768234127, -0.452333925937943637, 0.0679423211019681700, -0.811411071716238719, -0.588554936857709099, 0.4066768108416509708, -0.907862149146695163, -0.115673202040957226, 0.5770808894249742638, -0.142370726163931066, -0.806527261406603468, 0.1012712863762783577, -0.723336747696182614, -0.694640249329106285, 0.5000928657774492692, -0.949746569049947253, -0.046846346456817907, 0.7412589798326677526, -0.140350561965914555, -0.663578062154924320, 0.0055655501003109590, -0.983847100401775698, -0.120037109608235590, 0.2142330103903098415, -0.119429100752156334, -0.947421187831809397, 0.9550804066106526324, -0.108275659756619305, -0.039227521113362487, 0.7823218737697450464, -0.405437596810190704, -0.439275358874331168, 0.3626971102221024923, -0.753122462957226402, -0.546281394544768872, 0.0162483298780003657, -0.966230359337758582, -0.052114148464710915, 0.1076692386876715729, -0.206734953950642314, -0.934620775424686911, 0.9744239420161749932, -0.092650552854598708, -0.090828719474599584 ), 3, 20)) if( fuzz < max(abs(qbox20$loadings - tst ))) { cat("Calculated value is not the same as test value in test Thurstone 2. Value:\n") print(qbox20$loadings, digits=18) cat("difference:\n") print(qbox20$loadings - tst, digits=18) all.ok <- FALSE } tst <- t(matrix(c( 0.57232345894276127, -0.60751194947821441, -0.55079496147384377, 0.60249460283341838, 0.76716797198365361, -0.22012168525406509, 0.55627880770383020, -0.20587018726291534, 0.80509089803322043 ), 3, 3)) if( fuzz < max(abs(qbox20$Th - tst ))) { cat("Calculated value is not the same as test value in test Thurstone 3. Value:\n") print(qbox20$Th, digits=18) cat("difference:\n") print(qbox20$Th - tst, digits=18) all.ok <- FALSE } # sorted absolute loading plots. sal <- abs(c(loadings(qbox20)))[order(abs(c(loadings(qbox20))))] plot(seq(length(sal)), sal) #compare quartimax rotation of the initial loading matrix box20. if( fuzz < max(abs(loadings(qbox20) - box20 %*% qbox20$Th ))) { cat("Calculated value is not the same as test value in test Thurstone 4. Value:\n") print(loadings(qbox20), digits=18) cat("difference:\n") print(loadings(qbox20) - box20 %*% qbox20$Th, digits=18) all.ok <- FALSE } qminbox20G <- GPFoblq(box20, Tmat=diag(1,3), method="quartimin", eps=1e-5) qminbox20 <- quartimin(box20, eps=1e-5) if( fuzz < max(abs(loadings(qminbox20) - qminbox20G$loadings))) { cat("Calculated value is not the same as test value in test Thurstone 5. Value:\n") print(qminbox20G$loadings , digits=18) cat("difference:\n") print(loadings(qminbox20) - qminbox20G$loadings, digits=18) all.ok <- FALSE } #qminbox20$Th - quartimin(box20)$Th # These values compare with those in: # http://www.stat.ucla.edu/research/web.pdf tst <- t(matrix(c( -0.099561899210599963, -1.0236437309424475384, 0.017110338313848200, -0.007103778102200991, 0.0427848301281630802, -1.009962780073245581, 1.012864497258948226, 0.0331727792925069487, 0.050367710973030555, -0.054843850612513692, -0.4493155290974688021, -0.772334543778026350, 0.856287122381722998, -0.3740197232441037078, 0.069350368268248391, 0.835580575619599641, 0.0487450425576793633, -0.360381644212301344, -0.102893671454670210, -0.7226715938020771279, -0.537456650126404090, 0.322103633211960838, -0.8816846447967544576, 0.031159743715387874, 0.462799683447739529, 0.0852338438217692257, -0.783762970578423479, -0.076585435689138226, -0.6043060025891554554, -0.658295846696152820, 0.427772530893690217, -0.9288687512327726825, 0.122866182561916254, 0.659408232467282085, 0.0772080094990600374, -0.607348040513722709, -0.108761719100651882, -1.0079608432113262850, -0.017378089000366713, 0.059518597564186392, 0.0955950614351480238, -0.986779686330629513, 0.989890866913205381, 0.0071520817823045348, 0.094691644950703049, 0.713733277219835149, -0.2427293600063723522, -0.328268187306521242, 0.220344503737931546, -0.6353746612195683152, -0.459661643730432223, -0.084703580704062989, -1.0022284232457450148, 0.055740317456252478, -0.059151779416785115, -0.0113377397453605679, -0.976867596293413132, 1.003360458549731771, 0.0365098037316876067, 0.039427150580815938 ), 3, 20)) if( fuzz < max(abs(qminbox20G$loadings - tst ))) { cat("Calculated value is not the same as test value in test Thurstone 6. Value:\n") print(qminbox20G$loadings, digits=18) cat("difference:\n") print(qminbox20G$loadings - tst, digits=18) all.ok <- FALSE } tst <- t(matrix(c( 1.00000000000000000, -0.25676300454795098, -0.32155119431295237, -0.25676300454795098, 1.00000000000000000, 0.33656790396842257, -0.32155119431295237, 0.33656790396842257, 1.00000000000000000 ), 3, 3)) if( fuzz < max(abs(qminbox20G$Phi - tst ))) { cat("Calculated value is not the same as test value in test Thurstone 7. Value:\n") print(qminbox20G$Phi, digits=18) cat("difference:\n") print(qminbox20G$Phi - tst, digits=18) all.ok <- FALSE } #To fuzz precision the rotated loading matrix and the factor cor- #relation matrix phi are identical to those produced using the oblique GP #algorithm with exact derivatives. if( fuzz < max(abs(qminbox20G$Phi - t(qminbox20G$Th )%*% qminbox20G$Th ))) { cat("Calculated value is not the same as test value in test Thurstone 8. Value:\n") print(qminbox20G$Phi, digits=18) cat("difference:\n") print(qminbox20G$Phi - t(qminbox20G$Th )%*% qminbox20G$Th, digits=18) all.ok <- FALSE } #compare quartimin rotation of the initial loading matrix box20. if( fuzz < max(abs(qminbox20G$loadings - box20 %*% solve(t(qminbox20G$Th))))) { cat("Calculated value is not the same as test value in test Thurstone 9. Value:\n") print(qminbox20G$loadings, digits=18) cat("difference:\n") print(qminbox20G$loadings - box20 %*% solve(t(qminbox20G$Th)), digits=18) all.ok <- FALSE } data("box26", package="GPArotation") if (!exists("box26")) stop("Test data box26 not found. Testing stopped.") qbox26 <- GPForth(box26, Tmat=diag(1,3), method="quartimax", eps=1e-5) tst <- t(matrix(c( 0.6245197355925140581, -0.2708954695931116152, 0.7151983951389878635, 0.7386116884036847408, 0.6266342260884526505, -0.0617439911892987553, 0.7803093788467402314, -0.3830982859243221017, -0.4578886072022986253, 0.8540550453155928423, 0.2886436985992582027, 0.4062915145925659610, 0.8810593765418006651, -0.4428658074662961130, 0.1233946983666596581, 0.9084731768740617053, 0.1540526132602804965, -0.3723026715563940159, 0.8150592858039771293, 0.0441965358534676597, 0.5600768044145943980, 0.8466584455973064083, 0.4551177395514792168, 0.1889929089788950356, 0.8156808837280125069, -0.4090629943132625956, 0.3690652552112651530, 0.9629492340906220527, -0.4781483041690369196, -0.0866081507974762743, 0.8731366884896356595, 0.3451069860590937899, -0.2914969834947889749, 0.8921854600753849063, -0.0276323108621970258, -0.4257376659710629951, -0.0938760381595044741, -0.7873218033841372643, 0.6012450975895150540, 0.0938760381595044741, 0.7873218033841372643, -0.6012450975895150540, -0.0986092863860908303, 0.1513605567468480073, 0.9692559984337008050, 0.0986092863860908303, -0.1513605567468480073, -0.9692559984337008050, -0.0189573629854957251, 0.9527983290277913797, 0.2944078167958268377, 0.0189573629854957251, -0.9527983290277913797, -0.2944078167958268377, 0.8394181189595459891, 0.3631767908642606346, 0.3398717995655929913, 0.8703065201362156778, -0.4691145408161159214, 0.0770980453920554615, 0.9141063746617547059, 0.1583184861345137973, -0.3535658252020681958, 0.8348118627305495254, 0.3535663452183119837, 0.3271666140872500073, 0.8541352373790773722, -0.4476738735312740247, 0.0569042988261160704, 0.9034738474019414767, 0.1663655738425987851, -0.3227406124130587362, 0.9861758757457432800, 0.0103496363116840455, 0.0635926656567585569, 0.9643516568468981642, 0.0660181478622221818, -0.0304218028637989850 ), 3, 26)) if( fuzz < max(abs(qbox26$loadings - tst ))) { cat("Calculated value is not the same as test value in test Thurstone 10. Value:\n") print(qbox26$loadings, digits=18) cat("difference:\n") print(qbox26$loadings - tst, digits=18) all.ok <- FALSE } tst <- t(matrix(c( 0.9996572020207266096, 0.0216275672176080257, 0.0147555679097727491, -0.0158190757965277796, 0.9480178905874908635, -0.3178235925273457108, -0.0208622934749700742, 0.3174812237948764770, 0.9480350400953921897 ), 3, 3)) if( fuzz < max(abs(qbox26$Th - tst ))) { cat("Calculated value is not the same as test value in test Thurstone 11. Value:\n") print(qbox26$Th, digits=18) cat("difference:\n") print(qbox26$Th - tst, digits=18) all.ok <- FALSE } qminbox26 <- GPFoblq(box26, Tmat=diag(1,3), method="quartimin", eps=1e-5) tst <- t(matrix(c( 0.6088436426802223966, -0.2567107018725688361, 0.7213648290819488773, 0.7318447535507376367, 0.6298398026581654152, -0.0549983771960348838, 0.7973321695017724364, -0.3855960314746548212, -0.4504478973568259437, 0.8392144987741166906, 0.2994932968625432235, 0.4143558581243267924, 0.8833452352200144020, -0.4361046712803113290, 0.1319331147095905710, 0.9161366872228343672, 0.1535557844336666034, -0.3638337328539109072, 0.7993355454002614158, 0.0571270784641514026, 0.5678963531379384033, 0.8354288250614068101, 0.4626764152757318893, 0.1968789749765105790, 0.8109923806202916641, -0.3989909333845649830, 0.3770226870580207779, 0.9712737747877250305, -0.4740722765307348041, -0.0773243882106463137, 0.8761501947960563808, 0.3456235893514668089, -0.2834183138879167174, 0.9036601763684347643, -0.0290211959776035672, -0.4173652812159966974, -0.0995525797764766768, -0.7788574612781464790, 0.6007791331268093060, 0.0995525797764766768, 0.7788574612781464790, -0.6007791331268093060, -0.1264036712449473909, 0.1653130238928011975, 0.9684661160120416890, 0.1264036712449473909, -0.1653130238928011975, -0.9684661160120416890, -0.0392946742598458687, 0.9571059478962877787, 0.2939285303852590125, 0.0392946742598458687, -0.9571059478962877787, -0.2939285303852590125, 0.8253744379910458173, 0.3729516010405902748, 0.3477554718030251846, 0.8741734789142978634, -0.4631063486451737488, 0.0855349365396926159, 0.9212130243051569467, 0.1581334796580046720, -0.3450412531516501846, 0.8212340853954427367, 0.3631252613622908965, 0.3350076577679809153, 0.8582635618771776720, -0.4420579024138228674, 0.0651757040961165046, 0.9096561314838297330, 0.1665824736284239604, -0.3143133889989875307, 0.9840845767693481294, 0.0168070160966761091, 0.0729425956763933708, 0.9640420478016114014, 0.0709475796833391181, -0.0213192081807395371 ), 3, 26)) if( fuzz < max(abs(qminbox26$loadings - tst ))) { cat("Calculated value is not the same as test value in test Thurstone 12. Value:\n") print(qminbox26$loadings, digits=18) cat("difference:\n") print(qminbox26$loadings - tst, digits=18) all.ok <- FALSE } tst <- t(matrix(c( 1.000000000000000 , 0.00767934084449363279, 0.0170654511973979163, 0.00767934084449363279, 1.000000000000000 , -0.0144994900961642244, 0.01706545119739791630, -0.01449949009616422445, 1.000000000000000 ), 3, 3)) if( fuzz < max(abs(qminbox26$Phi - tst ))) { cat("Calculated value is not the same as test value in test Thurstone 13. Value:\n") print(qminbox26$Phi, digits=18) cat("difference:\n") print(qminbox26$Phi - tst, digits=18) all.ok <- FALSE } tst <- t(matrix(c( 0.9993401424148040668, 0.0347479564402226465, 0.0408645923859655008, -0.0179660947915933414, 0.9476477730670300748, -0.3324117322929439067, -0.0315673755054017430, 0.3174212937474846785, 0.9422486536594960604 ), 3, 3)) if( fuzz < max(abs(qminbox26$Th - tst ))) { cat("Calculated value is not the same as test value in test Thurstone 14. Value:\n") print(qminbox26$Th, digits=18) cat("difference:\n") print(qminbox26$Th - tst, digits=18) all.ok <- FALSE } cat("tests completed.\n") if (! all.ok) stop("some tests FAILED") cat("tests completed.\n") if (! all.ok) stop("some tests FAILED") GPArotation/tests/Harman.R0000644000176200001440000001261514323662112015141 0ustar liggesusers#Example from: Gradient Projection Algorithms and Software for # Arbitrary Rotation Criteria in Factor Analysis. # by Coen A. Bernaards and Robert I. Jennrich # Website: http://www.stat.ucla.edu/research Sys.getenv("R_LIBS") library() require("GPArotation") search() Sys.info() fuzz <- 1e-5 # using eps=1e-5 these tests do not do better than this all.ok <- TRUE # quartimax (orthogonal) rotation of Harman's 8 physical variables. data("Harman", package="GPArotation") qHarman <- GPForth(Harman8, Tmat=diag(2), method="quartimax") qHarman2 <- quartimax(Harman8) if( fuzz < max(abs(qHarman$loadings - qHarman2$loadings))) { cat("Calculated value is not the same as test value in test Harman 1. Value:\n") print(qHarman$loadings, digits=18) cat("difference:\n") print(qHarman$loadings - qHarman2$loadings, digits=18) all.ok <- FALSE } #qHarman$Th - qHarman2$Th # with eps=1e-8 # tst <- t(matrix(c( # 0.898754567491920398, 0.194823580226859222, # 0.933943406208487592, 0.129748657024604030, # 0.902131483644799892, 0.103864268239045668, # 0.876508251941102934, 0.171284220753554678, # 0.315572019798302239, 0.876476069451083251, # 0.251123191235179066, 0.773488941629975613, # 0.198007116064591759, 0.714678376605717203, # 0.307857241091366252, 0.659334451631046314 # ), 2, 8)) # with eps=1e-5 tst <- t(matrix(c( 0.898755404698461491, 0.194819718009510034, 0.933943963768413821, 0.129744643590955028, 0.902131929972106672, 0.103860391510923730, 0.876508987992224209, 0.171280454135453869, 0.315575786273609882, 0.876474713336210853, 0.251126515144778573, 0.773487862471829213, 0.198010187248201075, 0.714677525703678707, 0.307860074444663512, 0.659333128670876345 ), 2, 8)) if( fuzz < max(abs(qHarman$loadings - tst ))) { cat("Calculated value is not the same as test value in test Harman 2. Value:\n") print(qHarman$loadings, digits=18) cat("difference:\n") print(qHarman$loadings - tst, digits=18) all.ok <- FALSE } # with eps=1e-8 # tst <- t(matrix(c( # 0.790828307905322436, 0.612038060430562525, # -0.612038060430562525, 0.790828307905322214 # ), 2, 2)) # with eps=1e-5 tst <- t(matrix(c( 0.790830938007507367, 0.612034662000581764, -0.612034662000581764, 0.790830938007507145 ), 2, 2)) if( fuzz < max(abs(qHarman$Th - tst ))) { cat("Calculated value is not the same as test value in test Harman 3. Value:\n") print(qHarman$Th, digits=18) cat("difference:\n") print(qHarman$Th - tst, digits=18) all.ok <- FALSE } # quartimin (oblique) rotation of Harman's 8 physical variables. qminHarman <- GPFoblq(Harman8, Tmat=diag(2), method="quartimin") qminHarman2 <- quartimin(Harman8) if( fuzz < max(abs(qminHarman$loadings - qminHarman2$loadings))) { cat("Calculated value is not the same as test value in test Harman 4. Value:\n") print(qminHarman$loadings, digits=18) cat("difference:\n") print(qminHarman$loadings - qminHarman2$loadings, digits=18) all.ok <- FALSE } # with eps=1e-8 # tst <- t(matrix(c( # 0.8918217697289939627, 0.0560146456758183961, # 0.9536799985772628219, -0.0232460005406671701, # 0.9291498623396581280, -0.0465027396531852502, # 0.8766828510822184395, 0.0336582451338717017, # 0.0136988312985193428, 0.9250013826349388069, # -0.0172668087945964319, 0.8212535444941218010, # -0.0524468998178311899, 0.7649536381341245361, # 0.0858880630098148856, 0.6831160953442911854 # ),2, 8)) # with eps=1e-5 tst <- t(matrix(c( 0.8918219293548808047, 0.0560145122875230911, 0.9536799846795966928, -0.0232460559140742311, 0.9291497958388006406, -0.0465027685653178480, 0.8766829604751505967, 0.0336581364763500201, 0.0137008854716444972, 0.9250004106413580729, -0.0172649861805529957, 0.8212526839806429946, -0.0524452035885302342, 0.7649528396536503516, 0.0858895830186393733, 0.6831153711863455769 ),2, 8)) if( fuzz < max(abs(qminHarman$loadings - tst ))) { cat("Calculated value is not the same as test value in test Harman 5. Value:\n") print(qminHarman$loadings, digits=18) cat("difference:\n") print(qminHarman$loadings - tst, digits=18) all.ok <- FALSE } # with eps=1e-8 # tst <- t(matrix(c( # 1.000000000000000000, 0.472747617396915065, # 0.472747617396915065, 1.000000000000000000 # ),2, 2)) # with eps=1e-5 tst <- t(matrix(c( 1.000000000000000222, 0.472745958387102538, 0.472745958387102538, 1.000000000000000000 ),2, 2)) if( fuzz < max(abs(qminHarman$Phi - tst ))) { cat("Calculated value is not the same as test value in test Harman 6. Value:\n") print(qminHarman$Phi, digits=18) cat("difference:\n") print(qminHarman$Phi - tst, digits=18) all.ok <- FALSE } # with eps=1e-8 # tst <- t(matrix(c( # 0.878125245495924522, 0.836723841642554422, # -0.478430823863515542, 0.547625065922776710 # ),2, 2)) # with eps=1e-5 tst <- t(matrix(c( 0.878125280760480686, 0.836722770276292271, -0.478430759137962514, 0.547626702874473570 ),2, 2)) if( fuzz < max(abs(qminHarman$Th - tst ))) { cat("Calculated value is not the same as test value in test Harman 7. Value:\n") print(qminHarman$Th, digits=18) cat("difference:\n") print(qminHarman$Th - tst, digits=18) all.ok <- FALSE } cat("tests completed.\n") if (! all.ok) stop("some tests FAILED") GPArotation/tests/vgQOLD.R0000644000176200001440000003011115165335742015031 0ustar liggesusers# legacy vgQ functions ########################################### ########################################### ### ### OBLIMIN ### ########################################### ########################################### vgQOLD.oblimin <- function(L, gam=0){ X <- L^2 %*% (!diag(TRUE,ncol(L))) if (0 != gam) { p <- nrow(L) X <- (diag(1,p) - matrix(gam/p,p,p)) %*% X } list(Gq=L*X, f=sum(L^2 * X)/4, Method= if (gam == 0) "Oblimin Quartimin" else if (gam == .5) "Oblimin Biquartimin" else paste("Oblimin g=", gam,sep="") ) } # original # vgQOLD.oblimin <- function(L, gam=0){ # Method <- paste("Oblimin g=",gam,sep="") # if (gam == 0) Method <- "Oblimin Quartimin" # if (gam == .5) Method <- "Oblimin Biquartimin" # if (gam == 1) Method <- "Oblimin Covarimin" # k <- ncol(L) # p <- nrow(L) # N <- matrix(1,k,k)-diag(k) # f <- sum(L^2 * (diag(p)-gam*matrix(1/p,p,p)) %*% L^2 %*% N)/4 # Gq <- L * ((diag(p)-gam*matrix(1/p,p,p)) %*% L^2 %*% N) # return(list(Gq=Gq,f=f,Method=Method)) # } ########################################### ########################################### ### ### QUARTIMIN ### ########################################### ########################################### vgQOLD.quartimin <- function(L){ X <- L^2 %*% (!diag(TRUE,ncol(L))) list(Gq= L*X, f= sum(L^2 * X)/4, Method= "Quartimin" ) } #original #vgQOLD.quartimin <- function(L){ # Method="Quartimin" # L2 <- L^2 # k <- ncol(L) # M <- matrix(1,k,k)-diag(k) # f <- sum(L2 * (L2 %*% M))/4 # Gq <- L * (L2 %*% M) # return(list(Gq=Gq,f=f,Method=Method)) #} ########################################### ########################################### ### ### TARGET ROTATION ### required argument is a ### target matrix 'Target' ### ########################################### ########################################### vgQOLD.target <- function(L, Target=NULL){ if(is.null(Target)) stop("argument Target must be specified.") # e.g. Target <- matrix(c(rep(NA,4),rep(0,8),rep(NA,4)),8) # approximates Michael Brown approach Gq <- 2 * (L - Target) Gq[is.na(Gq)] <- 0 #missing elements in target do not affect the first derivative list(Gq=Gq, f=sum((L-Target)^2, na.rm=TRUE), Method="Target rotation") #The target rotation ? option in Michael Browne's algorithm should be NA } ########################################### ########################################### ### ### PARTIALLY SPECIFIED TARGET ROTATION ### required arguments are a ### target matrix 'Target' and ### weight matrix 'W' ### ########################################### ########################################### vgQOLD.pst <- function(L, W=NULL, Target=NULL){ if(is.null(W)) stop("argument W must be specified.") if(is.null(Target)) stop("argument Target must be specified.") # Needs weight matrix W with 1's at specified values, 0 otherwise # e.g. W = matrix(c(rep(1,4),rep(0,8),rep(1,4)),8). # When W has only 1's this is procrustes rotation # Needs a Target matrix Target with hypothesized factor loadings. # e.g. Target = matrix(0,8,2) Btilde <- W * Target list(Gq= 2*(W*L-Btilde), f = sum((W*L-Btilde)^2), Method="Partially specified target") } ########################################### ########################################### ### ### OBLIMAX ### ########################################### ########################################### vgQOLD.oblimax <- function(L){ list(Gq= -(4*L^3/(sum(L^4))-4*L/(sum(L^2))), f= -(log(sum(L^4))-2*log(sum(L^2))), Method="Oblimax") } ########################################### ########################################### ### ### MINIMUM ENTROPY ### ########################################### ########################################### vgQOLD.entropy <- function(L){ list(Gq= -(L*log(L^2 + (L^2==0)) + L), f= -sum(L^2*log(L^2 + (L^2==0)))/2, Method="Minimum entropy") } ########################################### ########################################### ### ### QUARTIMAX ### ########################################### ########################################### vgQOLD.quartimax <- function(L){ list(Gq= -L^3, f= -sum(diag(crossprod(L^2)))/4, Method="Quartimax") } ########################################### ########################################### ### ### VARIMAX ### ########################################### ########################################### vgQOLD.varimax <- function(L){ QL <- sweep(L^2,2,colMeans(L^2),"-") list(Gq= -L * QL, f= -sqrt(sum(diag(crossprod(QL))))^2/4, Method="varimax") } ########################################### ########################################### ### ### SIMPLIMAX ### argument: # close to zero loadings 'k' ### ########################################### ########################################### vgQOLD.simplimax <- function(L, k=nrow(L)){ # k: Number of close to zero loadings Imat <- sign(L^2 <= sort(L^2)[k]) list(Gq= 2*Imat*L, f= sum(Imat*L^2), Method="Simplimax") } ########################################### ########################################### ### ### BENTLER'S INVARIANT PATTERN SIMPLICITY ### ########################################### ########################################### vgQOLD.bentler <- function(L){ L2 <- L^2 M <- crossprod(L2) D <- diag(diag(M)) list(Gq= -L * (L2 %*% (solve(M)-solve(D))), f= -(log(det(M))-log(det(D)))/4, Method="Bentler's criterion") } ########################################### ########################################### ### ### TANDEM CRITERIA ### ########################################### ########################################### #vgQOLD.tandemI <- function(L){ # Tandem Criterion, Comrey, 1967. # Method <- "Tandem I" # LL <- (L %*% t(L)) # LL2 <- LL^2 # f <- -sum(diag(crossprod(L^2, LL2 %*% L^2))) # Gq1 <- 4 * L *(LL2 %*% L^2) # Gq2 <- 4 * (LL * (L^2 %*% t(L^2))) %*% L # Gq <- -Gq1 - Gq2 # return(list(Gq=Gq,f=f,Method=Method)) #} vgQOLD.tandemI <- function(L){ # Tandem Criterion, Comrey, 1967. LL <- (L %*% t(L)) LL2 <- LL^2 Gq1 <- 4 * L *(LL2 %*% L^2) Gq2 <- 4 * (LL * (L^2 %*% t(L^2))) %*% L Gq <- -Gq1 - Gq2 list(Gq=Gq, f= -sum(diag(crossprod(L^2, LL2 %*% L^2))), Method="Tandem I") } vgQOLD.tandemII <- function(L){ # Tandem Criterion, Comrey, 1967. LL <- (L %*% t(L)) LL2 <- LL^2 f <- sum(diag(crossprod(L^2, (1-LL2) %*% L^2))) Gq1 <- 4 * L *((1-LL2) %*% L^2) Gq2 <- 4 * (LL * (L^2 %*% t(L^2))) %*% L Gq <- Gq1 - Gq2 list(Gq=Gq, f=f, Method="Tandem II") } ########################################### ########################################### ### ### GEOMIN ### ########################################### ########################################### vgQOLD.geomin <- function(L, delta=.01){ k <- ncol(L) p <- nrow(L) L2 <- L^2 + delta pro <- exp(rowSums(log(L2))/k) list(Gq=(2/k)*(L/L2)*matrix(rep(pro,k),p), f= sum(pro), Method="Geomin") } ########################################### ########################################### ### ### BI-GEOMIN ### ########################################### ########################################### vgQOLD.bigeomin <- function(L, delta = 0.01){ Lg <- L[ , -1, drop = FALSE] out <- vgQOLD.geomin(Lg, delta = delta) list(Gq=cbind(0, out$Gq), f= out$f, Method="Bi-Geomin") } ########################################### ########################################### ### ### CRAWFORD FERGUSON FAMILY ### needs kappa parameter ### ### EQUAMAX PARSIMAX ### ########################################### ########################################### vgQOLD.cf <- function(L, kappa=0){ k <- ncol(L) p <- nrow(L) # kappa <- 0 # quartimax # kappa <- 1/p # varimax # kappa <- k/(2*p) # equamax # kappa <- (k-1)/(p+k-2) # parsimax # kappa <- 1 # factor parsimony N <- matrix(1,k,k)-diag(k) M <- matrix(1,p,p)-diag(p) L2 <- L^2 f1 <- (1-kappa)*sum(diag(crossprod(L2,L2 %*% N)))/4 f2 <- kappa*sum(diag(crossprod(L2,M %*% L2)))/4 list(Gq= (1-kappa) * L * (L2 %*% N) + kappa * L * (M %*% L2), f= f1 + f2, Method= if (kappa == 0) "Crawford-Ferguson Quartimax/Quartimin" else if (kappa == 1/p) "Crawford-Ferguson Varimax" else if (kappa == k/(2*p)) "Equamax" else if (kappa == (k-1)/(p+k-2)) "Parsimax" else if (kappa == 1) "Factor Parsimony" else paste("Crawford-Ferguson:k=",kappa,sep="")) } ########################################### ########################################### ### ### INFOMAX ### ########################################### ########################################### vgQOLD.infomax <- function(L){ k <- ncol(L) p <- nrow(L) S <- L^2 s <- sum(S) s1 <- rowSums(S) s2 <- colSums(S) E <- S/s e1 <- s1/s e2 <- s2/s Q0 <- sum(-E * log(E)) Q1 <- sum(-e1 * log(e1)) Q2 <- sum(-e2 * log(e2)) f <- log(k) + Q0 - Q1 - Q2 H <- -(log(E) + 1) alpha <- sum(S * H)/s^2 G0 <- H/s - alpha * matrix(1, p, k) h1 <- -(log(e1) + 1) alpha1 <- s1 %*% h1/s^2 G1 <- matrix(rep(h1,k), p)/s - as.vector(alpha1) * matrix(1, p, k) h2 <- -(log(e2) + 1) alpha2 <- h2 %*% s2/s^2 G2 <- matrix(rep(h2,p), ncol=k, byrow=T)/s - as.vector(alpha2) * matrix(1, p, k) Gq <- 2 * L * (G0 - G1 - G2) list(f = f, Gq=Gq, Method="Infomax") } ########################################### ########################################### ### ### MCCAMMON ENTROPY ### ########################################### ########################################### vgQOLD.mccammon <- function(L){ k <- ncol(L) p <- nrow(L) S <- L^2 M <- matrix(1,p,p) s2 <- colSums(S) P <- S / matrix(rep(s2,p),ncol=k,byrow=T) Q1 <- -sum(P * log(P)) H <- -(log(P) + 1) R <- M %*% S G1 <- H/R - M %*% (S*H/R^2) s <- sum(S) p2 <- s2/s Q2 <- -sum(p2 * log(p2)) h <- -(log(p2) + 1) alpha <- h %*% p2 G2 <- rep(1,p) %*% t(h)/s - as.vector(alpha)*matrix(1,p,k) Gq <- 2*L*(G1/Q1 - G2/Q2) f <- log(Q1) - log(Q2) list(f = f, Gq = Gq, Method = "McCammon entropy") } ########################################### ########################################### ### ### BIFACTOR BIQUARTIMIN ### ########################################### ########################################### vgQOLD.bifactor <- function(L){ k <- ncol(L) Lt <- L[,2:k] Lt2 <- Lt^2 N <- matrix(1, nrow=k-1, ncol=k-1) - diag(k-1) f <- sum(Lt2 * (Lt2 %*% N)) Gt <- 4 * Lt * (Lt2 %*% N) G <- cbind(0, Gt) list(f = f, Gq = G, Method = "Bifactor Biquartimin") } ########################################### ########################################### ### ### VARIMIN ### ########################################### ########################################### vgQOLD.varimin <- function (L){ QL <- sweep(L^2, 2, colMeans(L^2), "-") list(Gq = L * QL, f = sqrt(sum(diag(crossprod(QL))))^2/4, Method = "varimin") } ########################################### ########################################### ### ### Lp rotation ### ########################################### ########################################### # for lpT and lpQ functions see the file lp.R vgQOLD.lp.wls<-function(L, W) { list( Gq = 2 * W * L/nrow(L), f = sum(W * L * L)/nrow(L), Method = "Weighted least squares for Lp rotation" # Method description ) } ########################################### ########################################### ### ### PROMAX ### (not in use) ### ########################################### ########################################### # promax is already defined in the stats (previously mva) package # #GPromax <- function(A,pow=3){ # method <- "Promax" # # Initial rotation: Standardized Varimax # require(statsa) # xx <- promax(A,pow) # Lh <- xx$loadings # Th <- xx$rotmat # orthogonal <- F # Table <- NULL #return(list(loadings=Lh,Th=Th,Table=NULL,method,orthogonal=orthogonal)) #} GPArotation/tests/varimaxVarimax.R0000644000176200001440000000250614336234075016737 0ustar liggesusers# Also see the first test in rotations.R # compares varimax to Varimax to 0.001 discrepancy Sys.getenv("R_LIBS") library() require("GPArotation") search() Sys.info() ### note that this is a slightly lower bar than other tests ### to correct for the built-in varimax function working differently ### than GPA, and to ensure Varimax convergence ### these are differences in the 4th decimal or better fuzz <- 1e-4 ### all.ok <- TRUE sortFac <- function(x){ # Based on Fungible faSort vx <- order(colSums(x$loadings^2), decreasing = TRUE) Dsgn <- diag(sign(colSums(x$loadings^3))) [ , vx] x$Th <- x$Th %*% Dsgn x$loadings <- x$loadings %*% Dsgn if ("Phi" %in% names(x)) { x$Phi <- diag(1/diag(Dsgn)) %*% x$Phi %*% Dsgn } x } data(Thurstone, package="GPArotation") yv1 <- varimax(box20, normalize = FALSE, eps = 1e-7) #built-in R names(yv1) <- c("loadings","Th") yv1 <- sortFac(yv1) yv2 <- sortFac(Varimax(box20, normalize = FALSE, maxit = 10000, eps = 1e-7)) #GPArotation version # yv.diff <- unclass(yv1$loadings) - unclass(yv2$loadings) # max(abs(yv.diff)) if( fuzz < max(abs(yv1$loadings - yv2$loadings))) { cat("Calculated varimax is not the same as Varimax:\n") # print(yv2$loadings, digits=18) cat("difference:\n") print(yv1$loadings - yv2$loadings, digits=18) all.ok <- FALSE } GPArotation/tests/Jennrich2002.R0000644000176200001440000001062514337257176016015 0ustar liggesusers# test by William Revelle # from Jennrich, Psychometrika, 2002, solution for the Thurstone 20 box problem. # Specifying 27 elements to be 0 as discussed in that article (Table 1 at # page 12) and using vgQ.target as revised or vgQ.pst with a W matrix # and Target as specified does not yield the reported solution. # The solution is almost identical for the high loadings but differs slightly # for the small loadings. The two models have a factor congruence of .99 for # all three factors, but do not agree completely. # Jennrich (2002) apparently was using the oblique rotation option. # When running TargetQ the results are fine, or when running # the vgQ.pst function with GPFoblq. # This a good test case for both TargetQ # (It could also be adapted for pst but there is already a test for it.) require("GPArotation") data(Thurstone) #the 20 box problem #solution reported in Jennrich 2002 browne <- t(matrix(c( 0.013, 0.994, 0.007, 0.991, 0.012, 0.001, 0.018, 0.003, 0.986, 0.772, 0.477, 0.002, 0.003, 0.393, 0.874, 0.409, 0.003, 0.816, 0.548, 0.730, -0.020, 0.023, 0.870, 0.405, 0.799, -0.024, 0.453, 0.664, 0.621, -0.005, -0.058, 0.915, 0.512, 0.639, -0.018, 0.644, 0.046, 0.980, -0.003, 0.971, -0.038, 0.060, -0.026, 0.025, 0.965, 0.380, 0.281, 0.726, 0.490, 0.652, 0.286, -0.025, 0.971, 0.019, 0.957, 0.061, -0.045, 0.028, 0.000, 0.976), 3,20,dimnames = list(c("B1", "B2", "B3"), NULL))) #a simplified target matrix, with NAs for ? and 0 for 0s. # (compare to pst appproach) Target <- t(matrix(c( 0, NA, 0, NA, 0, 0, 0, 0, NA, NA, NA, 0, 0, NA, NA, NA, 0, NA, NA, NA, 0, 0, NA, NA, NA, 0, NA, NA, NA, 0, 0, NA, NA, NA, 0, NA, 0, NA, 0, NA, 0, 0, 0, 0, NA, NA, NA, NA, NA, NA, NA, 0, NA, 0, NA, 0, 0, 0, 0, NA), 3, 20, dimnames = list(c("T1", "T2", "T3"), NULL))) v <- targetQ(box20,Target=Target)$loadings # THIS ONE WORKS #v <- GPFoblq(box20, method ="target", methodArgs = list(Target=Target))$loadings all.ok <- TRUE #slightly larger fuzz for comparison with published value. # note max(abs(v) - abs(browne))rather than max(abs(v - browne)) # as sign change is possible if( 10e-4 < max(abs(v) - abs(browne))) { cat("Calculated value is not the same as test value in Jennrich2002. Value:\n") print(v, digits=18) cat("difference:\n") print(v - browne, digits=18) all.ok <- FALSE } good <- t(matrix(c( 0.01324194563970146343, -0.99360765277094842407, 0.007265459960371034587, 0.99121314541487770544, -0.01178320700232154961, 0.000654586020267855506, 0.01798447315534307256, -0.00266076852016330911, 0.985581004768931734361, 0.77198435084052174915, -0.47723548341238952730, 0.001547735983967568618, 0.00334198654247502835, -0.39290416948063611180, 0.874043793719835537814, 0.40934347835281348349, -0.00274610551094590233, 0.815649888720176186041, 0.54757055519984310088, -0.72951044925148011977, -0.020211353947714422175, 0.02292379053779741716, -0.87011712730189194609, 0.404542252780873523577, 0.79911058029224457666, 0.02416810475294199623, 0.452727043944761764482, 0.66393502364020362538, -0.62149665012300570055, -0.005186928343372421146, -0.05839790682548451350, -0.91517931889838155524, 0.511521949806932663130, 0.63924406199386740735, 0.01841750353525576159, 0.643544196342115570886, 0.04597086497418309547, -0.97980801598321454193, -0.002918643110053173451, 0.97103389549392915558, 0.03847065084578840666, 0.060066450372699808913, -0.02622776344285615568, -0.02482060086975104718, 0.965272709232911085842, 0.37998105522582992233, -0.28073835673932595602, 0.726047993725112084107, 0.48985182554738604388, -0.65226812910595410866, 0.285738966726349907788, -0.02451057644240206557, -0.97122042802717223342, 0.019132901654980147277, 0.95708220223038309449, -0.06086293722346142188, -0.045050942196376064786, 0.02797903728304645954, 0.00036458752733534161, 0.976083771686937051726), 3,20,dimnames = list(c("B1", "B2", "B3"), NULL))) #tighter fuzz for numerical comparison with previous test value if( 10e-12 < max(abs(v - good))) { cat("Calculated value is not the same as previous test value. Value:\n") print(v, digits=18) cat("difference:\n") print(v - good, digits=18) all.ok <- FALSE } cat("tests completed.\n") if (! all.ok) stop("some tests FAILED") GPArotation/tests/tableTests.r0000644000176200001440000000310315162007446016102 0ustar liggesusers# The 2026 spring clean up has made a fundamental change to the building # of the results Table. These tests are included to ensure that they don't # cause trouble library(GPArotation) # Helper: a simple loading matrix for testing A <- matrix(c(0.9, 0.8, 0.7, 0.1, 0.2, 0.1, 0.1, 0.2, 0.1, 0.9, 0.8, 0.7), nrow = 6, ncol = 2) # --- Test 1: Table has correct column names --- res <- GPForth(A, method = "quartimax") stopifnot(identical(colnames(res$Table), c("iter", "f", "log10(s)", "alpha"))) # --- Test 2: Table has no NA rows (trimming worked) --- stopifnot(!anyNA(res$Table)) # --- Test 3: Table first column is sequential from 0 --- stopifnot(res$Table[, 1] == 0:(nrow(res$Table) - 1)) # --- Test 4: Converged result has s < eps in final row --- eps <- 1e-5 s_final <- 10^res$Table[nrow(res$Table), 3] stopifnot(s_final < eps) # --- Test 5: Non-converged case raises a warning --- A_slow <- matrix(c(0.5, 0.4, 0.6, 0.3, 0.5, 0.4, 0.4, 0.5, 0.3, 0.5, 0.4, 0.6, 0.3, 0.6, 0.4, 0.5, 0.3, 0.5), nrow = 6, ncol = 3) res_nc <- suppressWarnings(GPForth(A_slow, method = "quartimax", maxit = 2)) if (res_nc$convergence) stop("Test 5 failed: expected non-convergence with maxit = 2") if (nrow(res_nc$Table) != 3) stop("Test 5 failed: expected 3 rows in Table, got ", nrow(res_nc$Table)) # --- Test 6: Already-converged initial solution — Table has exactly 1 row --- Tmat_exact <- diag(ncol(A)) res_exact <- GPForth(A, Tmat = Tmat_exact, method = "quartimax", maxit = 0) stopifnot(nrow(res_exact$Table) >= 1)GPArotation/tests/KaiserNormalization.R0000644000176200001440000000726314524252342017726 0ustar liggesusers# tests using normalization # All tests below use Kaiser normalization # A few other tests also use normalization when comparing varimax and Varimax # Following examples are from SPSS # See https://psych.unl.edu/psycrs/statpage/pc_rot.pdf Sys.getenv("R_LIBS") library() require("GPArotation") search() Sys.info() require("stats") require("GPArotation") fuzz <- 1e-3 #less strict; differences in 4rd decimal compared to SPSS all.ok <- TRUE # unrotated matrix L <- matrix(c(.758, .413, 1.164E-03, .693, .489, -.199, .362, .656, -.204, .826, 6.589E-02, .235, .540, -.510, .441, .654, -.335, .507, -.349, .539, .669, -.580, .450, .551), byrow=T, ncol=3) # quartimax, Kaiser normalization # uses the print command to get the right order of factors v <- print(quartimax(L, normalize = TRUE, eps = 1e-6))$loadings tst <- matrix(c(.814, .285, -4.99E-02, .856, 8.321E-02, -.135, .746, -.203, 7.244E-02, .576, .634, -8.73E-02, -6.10E-02, .850, -.142, .129, .882, -3.86E-02, 2.063E-02, -4.15E-02, .927, -.181, -.220, .873), byrow=T, ncol=3) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 1. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } # oblimin, Kaiser normalization # Pattern Matrix vw <- print(oblimin(L, normalize = TRUE, eps = 1e-7)) v <- vw$loadings tst <- matrix(c(.241, .787, -1.36E-02, 1.783E-02, .848, -.119, -.240, .779, 6.824E-02, .608, .507, -2.52E-02, .858, -.163, -7.26E-02, .896, 3.050E-02, 3.954E-02, 9.405E-02, 7.397E-02, .949, -8.61E-02, -.113, .875), byrow=T, ncol=3) tst <- tst %*% matrix(c(0,1,0,1,0,0,0,0,1), 3) # Needed to line up factors correctly fuzz <- 3e-3 #less strict; differences in 4th decimal compared to SPSS; 0.003 or smaller diff if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 1. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } # oblimin, Kaiser normalization # Structure Matrix v <- vw$loadings %*% vw$Phi tst <- matrix(c(.379, .829, -.146, .191, .862, -.203, -.123, .731, .051, .701, .613, -.218, .847, -.010, -.261, .891, .180, -.176, -.118, .000, .919, -.313, -.211, .906), byrow=T, ncol=3) tst <- tst %*% matrix(c(0,1,0,1,0,0,0,0,1), 3) # Needed to line up factors correctly fuzz <- 4e-3 #less strict; differences in 4th decimal compared to SPSS; 0.004 or smaller diff if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 1. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } ################################################################# # # Confirmation that a row of zeroes will not break the normalization function # Normalizing with a column of zeroes was not affected # based on example from Kim-Laura Speck (25 October 2023) # Only affects Normalize=TRUE settings fuzz <- 1e-6 D <- matrix(c(0,0,0, 1,2,3, 2,3,4, 5,2,5, 1,2,1, 3,4,5),ncol=3,byrow=T) set.seed(1000) #set seed becasuse some variance is observed in converged values v <- geominQ(D, normalize = TRUE, maxit = 10000)$loadings tst <- matrix(c( 0.00000000, 0.00000000, 0.00000000, -0.36979732, -0.13603325, 3.99622380, 0.03102554, 0.76678245, 4.68896063, 3.28926158, 0.01317821, 5.35447764, -0.02755956, 2.40311582, 0.06247234, 0.43184841, 1.66959816, 5.38169746), ncol = 3, byrow = TRUE) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 1. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } GPArotation/tests/rotationsRS.R0000644000176200001440000004350014763337751016237 0ustar liggesusers# Tests here only compare against values computed previously with this code, # to ensure there was no accidental change. It would be better to have # comparisons with known correct values. # Test for oblimax is commented out as it appears to be unstable. Sys.getenv("R_LIBS") library() require("GPArotation") search() Sys.info() require("stats") require("GPArotation") fuzz <- 1e-6 all.ok <- TRUE sortFac <- function(x){ # Based on Fungible faSort vx <- order(colSums(x$loadings^2), decreasing = TRUE) Dsgn <- diag(sign(colSums(x$loadings^3))) [ , vx] x$Th <- x$Th %*% Dsgn x$loadings <- x$loadings %*% Dsgn if ("Phi" %in% names(x)) { x$Phi <- diag(1/diag(Dsgn)) %*% x$Phi %*% Dsgn } x } data(ability.cov) L <- loadings(factanal(factors = 2, covmat=ability.cov)) set.seed(100) tst <- sortFac(Varimax(L, normalize=FALSE, randomStarts = 100))$loadings if( 0.001 < max(abs(varimax(L, normalize=FALSE)$loadings - tst))){ cat("Calculated difference exceeds tolerance\n") cat("difference:\n") print(varimax(L, normalize=FALSE)$loadings - tst, digits=18) all.ok <- FALSE } set.seed(100) tst <- sortFac(Varimax(L, normalize=TRUE, randomStarts = 100))$loadings if( 0.01 < max(abs(varimax(L, normalize=TRUE)$loadings - tst))) { cat("Calculated difference exceeds tolerance\n") cat("difference:\n") print(varimax(L, normalize=TRUE)$loadings - tst, digits=18) all.ok <- FALSE } set.seed(99) v <- sortFac(oblimin(L, eps=1e-8, randomStarts = 100))$loadings tst <- t(matrix(c( 0.3863615904740822504, 0.4745127741495974161, -0.0110059418769087539, 0.6458720769633764514, -0.0262926272350604423, 0.8961141105684561348, -0.0180200526810754824, 0.4882928281695405048, 0.9900944939102318543, -0.0370718282544326011, 0.7905657274265397438, 0.0526109550054999417 ), 2, 6)) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 1. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } set.seed(98) v <- sortFac(quartimin(L, eps=1e-8, randomStarts = 100))$loadings tst <- t(matrix(c( 0.3863615904740822504, 0.4745127741495974161, -0.0110059418769087539, 0.6458720769633764514, -0.0262926272350604423, 0.8961141105684561348, -0.0180200526810754824, 0.4882928281695405048, 0.9900944939102318543, -0.0370718282544326011, 0.7905657274265397438, 0.0526109550054999417 ), 2, 6)) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 2. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } # # This fails with the old Random.Start # set.seed(97) # v <- sortFac(targetT(L, Target=matrix(c(rep(1,3),rep(0,6),rep(1,3)), 6,2), # eps=1e-5, randomStarts = 100))$loadings # tst <- t(matrix(c( # 0.551529228817982942, 0.4905002767031292898, # 0.217748645523411000, 0.6027046291262584399, # 0.291173432863349457, 0.8348885228488550636, # 0.154994397662456290, 0.4544843569140373241, # 0.969702339393929247, 0.0850652965070581996, # 0.803390575440818822, 0.1448091121037717866 # ), 2, 6)) # # if( fuzz < max(abs(v - tst))) { # cat("Calculated value is not the same as test value in test rotations 3. Value:\n") # print(v, digits=18) # cat("difference:\n") # print(v - tst, digits=18) # all.ok <- FALSE # } # # This fails with the old Random.Start # Random starts get to a lower f value (1.8) which is a mismatch to the tst matrix # generated without random starts. Its f value is 5.6 # removed the test # set.seed(96) # v <- sortFac(targetQ(L, Target=matrix(c(rep(1,3),rep(0,6),rep(1,3)), 6,2), # eps=1e-5, randomStarts = 100))$loadings # tst <- t(matrix(c( # 0.735795682866631218, 0.565351705145453853, # 0.433590223819374398, 0.664644550038417159, # 0.589924557708411568, 0.920006940799857786, # 0.317543426981046928, 0.500590650032113116, # 1.021758247914384077, 0.155121528590726393, # 0.872521244896209747, 0.208735706420634437 # ), 2, 6)) # # if( fuzz < max(abs(v - tst))) { # cat("Calculated value is not the same as test value in test rotations 4. Value:\n") # print(v, digits=18) # cat("difference:\n") # print(v - tst, digits=18) # all.ok <- FALSE # } # oblimax # this is test value on one computer # tst <- t(matrix(c( # -8111059.94622692652, 8111060.62253121007, # 1495036.43465861562, -1495035.79614594672, # 2331634.63904705830, -2331633.75893370388, # 1356735.91680212389, -1356735.43916810025, # -23187491.19758165255, 23187491.68068471923, # -18357040.58573083207, 18357041.05348757654 # ), 2, 6)) # # this is test value on another computer # tst <- t(matrix(c( # 2694770.06630349346, -2694769.38999920478, # -496701.45733913727, 496702.09585180727, # -774647.63529061736, 774648.51540397422, # -450753.43529273639, 450753.91292676108, # 7703672.48495316971, -7703672.00185009185, # 6098832.71036116872, -6098832.24260441773 # ), 2, 6)) # # this does not converge on all platforms and has large differences possible a mistake ??? # v <- oblimax(L, eps=1e-5)$loadings # if( fuzz < max(abs(v - tst))) { # cat("Calculated value is not the same as test value in test rotations 7. Value:\n") # print(v, digits=18) # cat("difference:\n") # print(v - tst, digits=18) # all.ok <- FALSE # } v <- sortFac(entropy(L, maxit=3000, eps=1e-5, randomStarts = 100))$loadings tst <- t(matrix(c( 0.528292107548243184, 0.515443945340967824, 0.189686511729033253, 0.612116304198454975, 0.252311894464850861, 0.847442931117894815, 0.133843268148035738, 0.461156452364903380, 0.964740133927989407, 0.129750551769587635, 0.795847094000000532, 0.181751199795689433 ), 2, 6)) if( 0.01 < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 8. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } fuzz <- 1e-4 # 4th decimal differences set.seed(110) v <- sortFac(quartimax(L, eps=1e-7, randomStarts = 100))$loadings tst <- t(matrix(c( 0.534714740804540178, 0.508778102568043678, 0.197348140750149392, 0.609689309353509956, 0.262919828098457153, 0.844212045390758559, 0.139616102327241837, 0.459441658926639795, 0.966291466215733252, 0.117641548844535412, 0.798063848020893585, 0.171756193883937508 ), 2, 6)) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 9. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } set.seed(110) v <- sortFac(GPFRSorth(L, eps = 1e-7, method = "quartimax", randomStarts = 100))$loadings if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 9-GPFRSorth. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } set.seed(90) v <- sortFac(Varimax(L, eps=1e-8, randomStarts = 100))$loadings tst <- t(matrix(c( 0.515866523962843160, 0.527879475961036904, 0.175054634278874244, 0.616460231981747930, 0.232057748479543163, 0.853211588623112749, 0.122822468397975171, 0.464213243286899446, 0.961376376417989453, 0.152689863976982837, 0.791292800869773050, 0.200653429940987366 ), 2, 6)) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 10. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } set.seed(90) v <- sortFac(GPFRSorth(L, eps = 1e-7, method = "varimax", randomStarts = 100))$loadings if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 10-GPFRSorth. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } set.seed(89) v <- sortFac(simplimax(L, eps=1e-5, randomStarts = 100))$loadings tst <- t(matrix(c( 0.3384175759313114429, 0.508414890494446547464, -0.0654601124161610648, 0.670992229004664153535, -0.1016231721735353366, 0.930535379393095940515, -0.0589933707274080121, 0.506904360351960181497, 0.9733094402675376289, 0.000234046050254643859, 0.7702037184085044341, 0.085651123319384916965 ), 2, 6)) if( fuzz < max(abs(v - tst[,2:1]))) { cat("Calculated value is not the same as test value in test rotations 11. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } set.seed(89) v <- sortFac(GPFRSoblq(L, eps = 1e-5, method = "simplimax", randomStarts = 100))$loadings if( fuzz < max(abs(v - tst[,2:1]))) { cat("Calculated value is not the same as test value in test rotations 11-GPFRSoblq. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } set.seed(88) v <- sortFac(bentlerT(L, eps=1e-8, randomStarts = 100))$loadings tst <- t(matrix(c( 0.523583611303327312, 0.520226117818945788, 0.184113022124463677, 0.613815719643687197, 0.244596116053327067, 0.849702038129718673, 0.129644684715025493, 0.462354355134084738, 0.963520501269179652, 0.138517057902201340, 0.794161628656258278, 0.188979901644201559 ), 2, 6)) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 12. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } set.seed(88) v <- sortFac(GPFRSorth(L, eps = 1e-7, method = "bentler", randomStarts = 100))$loadings if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 12-GPFRSorth. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } set.seed(97) v <- sortFac(bentlerQ(L, eps=1e-8, randomStarts = 100))$loadings tst <- t(matrix(c( 0.3801726240258240241, 0.4741208368044214638, -0.0223632969057368826, 0.6514196922540864687, -0.0421105927111659756, 0.9039359851665277334, -0.0266594447192576613, 0.4925968005718689424, 0.9961524457620027917, -0.0485973498906049697, 0.7939648477384558811, 0.0440983921679098251 ), 2, 6)) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 13. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } fuzz <- 1e-5 set.seed(85) v <- sortFac(tandemI(L, eps=1e-6, maxit = 1000, randomStarts = 100))$loadings tst <- t(matrix(c( 0.615424480780047745, 0.4074649925368262759, 0.300894306348887419, 0.5658002819054848143, 0.406455233467338028, 0.7852483408305571677, 0.217785179074990981, 0.4279590047675180808, 0.971977129465111611, -0.0530960591067626969, 0.815800376450207976, 0.0295946184147908228 ), 2, 6)) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 14. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } fuzz <- 1e-5 set.seed(84) v <- sortFac(tandemII(L, eps=1e-5, randomStarts = 100))$loadings tst <- t(matrix(c( 0.512160139332842212, 0.531476249107136312, 0.170736763115044710, 0.617670057812827134, 0.226081850628144149, 0.854814488884392154, 0.119571200821562001, 0.465061309851099225, 0.960284416460420398, 0.159413208985883820, 0.789869387186175276, 0.206185467095899383 ), 2, 6)) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 15. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } fuzz <- 1e-6 set.seed(81) v <- sortFac(geominT(L, eps=1e-5, randomStarts = 100))$loadings tst <- t(matrix(c( 0.572197044101002361, 0.4662247895688098054, 0.243573415560656120, 0.5927388411683653935, 0.326956608263186954, 0.8215352639437966120, 0.174476792179181994, 0.4473668997335142894, 0.972471249855535680, 0.0431091626026945812, 0.808894688433769660, 0.1099794466209375043 ), 2, 6)) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 16. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } fuzz <- 1e-6 set.seed(80) v <- sortFac(geominQ(L, eps=1e-5, randomStarts = 100))$loadings tst <- t(matrix(c( 0.39672053553904490508, 0.4713295988080449250, 0.00424452688463150020, 0.6389466007374070555, -0.00510976786312981532, 0.8864521406378518265, -0.00646959173137159373, 0.4830101828530461994, 0.98709860078485589518, -0.0318959930081098297, 0.79011178369962709045, 0.0558689642678330683 ), 2, 6)) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 17. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } set.seed(70) v <- sortFac(cfT(L, eps=1e-8, randomStarts = 100))$loadings tst <- t(matrix(c( 0.534721263659975854, 0.508771247100584523, 0.197355957387199576, 0.609686779159006154, 0.262930651479430233, 0.844208674501022327, 0.139621992686633722, 0.459439868910532512, 0.966292974385164483, 0.117629160286744874, 0.798066049992627313, 0.171745962120156664 ), 2, 6)) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 18. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } set.seed(60) v <- sortFac(cfQ(L, eps=1e-8, randomStarts = 100))$loadings tst <- t(matrix(c( 0.3863615904740822504, 0.4745127741495974161, -0.0110059418769087539, 0.6458720769633764514, -0.0262926272350604423, 0.8961141105684561348, -0.0180200526810754824, 0.4882928281695405048, 0.9900944939102318543, -0.0370718282544326011, 0.7905657274265397438, 0.0526109550054999417 ), 2, 6)) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 19. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } fuzz <- 1e-5 set.seed(55) v <- sortFac(infomaxT(L, eps=1e-5, randomStarts = 100))$loadings tst <- t(matrix(c( 0.495330443338021176, 0.547195361446864537, 0.151384273205308784, 0.622695868320644275, 0.199304253086364791, 0.861451466010626055, 0.105004533733904976, 0.468565194910632365, 0.954843809781045660, 0.189293503899924942, 0.783052579543945471, 0.230726576980168713 ), 2, 6)) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 20. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } fuzz <- 1e-5 set.seed(50) v <- sortFac(infomaxQ(L, eps=1e-5, randomStarts = 100))$loadings tst <- t(matrix(c( 0.39327554287862442894, 0.4693137508305071925, -0.00319802321222481794, 0.6422985517185823001, -0.01549245038490981718, 0.8912279460026399924, -0.01214605901641467763, 0.4856544522916727002, 0.99260028929193111491, -0.0433225495465055510, 0.79356458059567791530, 0.0471559021503157039 ), 2, 6)) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 21. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } set.seed(40) v <- sortFac(mccammon(L, eps=1e-5, randomStarts = 100))$loadings tst <- t(matrix(c( 0.4293472299617892007, 0.600363196582340275, 0.0790140496845253004, 0.635943490060206229, 0.0992523811009183854, 0.878618107277518656, 0.0506062164774049028, 0.477512622702450096, 0.9268544198491108776, 0.297488850382792269, 0.7514463663627769519, 0.318958389348199534 ), 2, 6)) tst <- tst[, 2:1] if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 22. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } set.seed(35) v <- sortFac(oblimax(Harman8, eps=1e-5, randomStarts = 100))$loadings tst <- t(matrix(c( 0.93395421734409445058, -0.0302013026726007383, 0.99243032312927881300, -0.1121899246869615951, 0.96509469978483286567, -0.1322258547171115683, 0.91647702431117861188, -0.0502569243958834178, 0.08441855308346873921, 0.8875309317276611765, 0.04427084251510177149, 0.7907585046311147448, 0.00332736511424391868, 0.7399752420126202157, 0.14133359391312094733, 0.6483050831171799366 ), 2, 8)) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 22. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } cat("tests completed.\n") if (! all.ok) stop("some tests FAILED") GPArotation/tests/WansbeekMeijer.R0000644000176200001440000000606314323662112016626 0ustar liggesusers Sys.getenv("R_LIBS") library() require("GPArotation") search() Sys.info() fuzz <- 1e-6 all.ok <- TRUE data(WansbeekMeijer, package="GPArotation") fa.none <- factanal(factors=2, covmat=NetherlandsTV, rotation="none") tst <- t(matrix(c( 0.6972803, -0.3736554, 0.7774628, -0.3184149, 0.6832300, -0.3620428, 0.6612198, 0.2361132, 0.6972393, 0.3026050, 0.7100285, 0.4059509, 0.6353584, 0.3526947 ), 2, 7)) if( fuzz < max(abs(fa.none$loadings - tst))) { cat("Calculated value is not the same as test value in test WansbeekMeijer 1. Value:\n") print(fa.none$loadings, digits=18) cat("difference:\n") print(fa.none$loadings - tst, digits=18) all.ok <- FALSE } fa.varimax <- GPFoblq(fa.none$loadings, method="varimax", normalize=TRUE) # with eps=1e-8 # tst <- t(matrix(c( # 0.229695829694226694, -0.757005882905721683, # 0.325474298411086493, -0.774533969509160203, # 0.227951538606475851, -0.738861531224136225, # 0.634850649690308022, -0.299876110481063607, # 0.707312661165822032, -0.278246783076943283, # 0.789359884149245072, -0.214120439603779994, # 0.698885205896135120, -0.199081171877497243 # ), 2, 7)) # with eps=1e-5 tst <- t(matrix(c( 0.229698038368303409, -0.757005212686898243, 0.325476558225504142, -0.774533019824047542, 0.227953694341768043, -0.738860866094951829, 0.634851524619887475, -0.299874258087383661, 0.707313472988376213, -0.278244719250824557, 0.789360508873491518, -0.214118136377292989, 0.698885786741510029, -0.199079132641678647 ), 2, 7)) if( fuzz < max(abs(fa.varimax$loadings - tst))) { cat("Calculated value is not the same as test value in test WansbeekMeijer 2. Value:\n") print(fa.varimax$loadings, digits=18) cat("difference:\n") print(fa.varimax$loadings - tst, digits=18) all.ok <- FALSE } fa.oblimin <- GPFoblq(fa.none$loadings, method="oblimin", normalize=TRUE) # with eps=1e-8 # tst <- t(matrix(c( # -0.0244898894997362740, -0.8055076884898763057, # 0.0821776433220552660, -0.7883517482514345032, # -0.0194442483441249758, -0.7847120136813017233, # 0.6350106056917923514, -0.1038114236654337219, # 0.7293893902400611085, -0.0495156037400738894, # 0.8517915457391848078, 0.0588983480418694277, # 0.7504355940804637859, 0.0408946221245683056 # ), 2, 7)) # with eps=1e-5 tst <- t(matrix(c( -0.0244886312423446446, -0.8055069385602275922, 0.0821788889356081659, -0.7883509906546982693, -0.0194430219824419312, -0.7847112821295906260, 0.6350108529538124325, -0.1038111848933331444, 0.7293895650539216069, -0.0495153948664520185, 0.8517915670863017708, 0.0588984825074335624, 0.7504356301074717184, 0.0408947509009953206 ), 2, 7)) if( fuzz < max(abs(fa.oblimin$loadings - tst))) { cat("Calculated value is not the same as test value in test WansbeekMeijer 3. Value:\n") print(fa.oblimin$loadings, digits=18) cat("difference:\n") print(fa.oblimin$loadings - tst, digits=18) all.ok <- FALSE } cat("tests completed.\n") if (! all.ok) stop("some tests FAILED") GPArotation/tests/legacyVsNew.R0000644000176200001440000002071615164226612016170 0ustar liggesusers# Regression tests: GPForth and GPFoblq against legacy implementations. # Tests that the 2026.4-1 updates produce exactly identical results # to the original 2008 implementations. # Uses identical() for exact equality — no numerical tolerance. require("GPArotation") all.ok <- TRUE # Test matrices data(Harman, package = "GPArotation") data(Thurstone, package = "GPArotation") A2 <- Harman8 # 8 x 2 A3 <- box26 # 26 x 3 # --- Test 1: GPForth vs GPForth.legacy, varimax, identity start --- r1 <- GPForth(A2, method = "varimax") r1L <- GPArotation:::GPForth.legacy(A2, method = "varimax") if (!identical(r1$loadings, r1L$loadings)) { cat("Test 1 failed: GPForth varimax loadings not identical to legacy\n") cat("max difference:", max(abs(r1$loadings - r1L$loadings)), "\n") all.ok <- FALSE } if (!identical(r1$Th, r1L$Th)) { cat("Test 1 failed: GPForth varimax Th not identical to legacy\n") cat("max difference:", max(abs(r1$Th - r1L$Th)), "\n") all.ok <- FALSE } if (!identical(r1$convergence, r1L$convergence)) { cat("Test 1 failed: GPForth varimax convergence not identical to legacy\n") all.ok <- FALSE } # --- Test 2: GPForth vs GPForth.legacy, quartimax, 3 factors --- r2 <- GPForth(A3, method = "quartimax") r2L <- GPArotation:::GPForth.legacy(A3, method = "quartimax") if (!identical(r2$loadings, r2L$loadings)) { cat("Test 2 failed: GPForth quartimax loadings not identical to legacy\n") cat("max difference:", max(abs(r2$loadings - r2L$loadings)), "\n") all.ok <- FALSE } if (!identical(r2$Th, r2L$Th)) { cat("Test 2 failed: GPForth quartimax Th not identical to legacy\n") cat("max difference:", max(abs(r2$Th - r2L$Th)), "\n") all.ok <- FALSE } if (!identical(r2$convergence, r2L$convergence)) { cat("Test 2 failed: GPForth quartimax convergence not identical to legacy\n") all.ok <- FALSE } # --- Test 3: GPForth vs GPForth.legacy, random start --- set.seed(42) Tmat2 <- Random.Start(2) r3 <- GPForth(A2, Tmat = Tmat2, method = "varimax") set.seed(42) Tmat2 <- Random.Start(2) r3L <- GPArotation:::GPForth.legacy(A2, Tmat = Tmat2, method = "varimax") if (!identical(r3$loadings, r3L$loadings)) { cat("Test 3 failed: GPForth random start loadings not identical to legacy\n") cat("max difference:", max(abs(r3$loadings - r3L$loadings)), "\n") all.ok <- FALSE } if (!identical(r3$Th, r3L$Th)) { cat("Test 3 failed: GPForth random start Th not identical to legacy\n") cat("max difference:", max(abs(r3$Th - r3L$Th)), "\n") all.ok <- FALSE } # --- Test 4: GPForth vs GPForth.legacy, with normalization --- r4 <- GPForth(A2, method = "varimax", normalize = TRUE) r4L <- GPArotation:::GPForth.legacy(A2, method = "varimax", normalize = TRUE) if (!identical(r4$loadings, r4L$loadings)) { cat("Test 4 failed: GPForth normalized loadings not identical to legacy\n") cat("max difference:", max(abs(r4$loadings - r4L$loadings)), "\n") all.ok <- FALSE } if (!identical(r4$Th, r4L$Th)) { cat("Test 4 failed: GPForth normalized Th not identical to legacy\n") cat("max difference:", max(abs(r4$Th - r4L$Th)), "\n") all.ok <- FALSE } # --- Test 5: GPForth vs GPForth.legacy, methodArgs --- r5 <- GPForth(A2, method = "cf", methodArgs = list(kappa = 0.3)) r5L <- GPArotation:::GPForth.legacy(A2, method = "cf", methodArgs = list(kappa = 0.3)) if (!identical(r5$loadings, r5L$loadings)) { cat("Test 5 failed: GPForth cf kappa=0.3 loadings not identical to legacy\n") cat("max difference:", max(abs(r5$loadings - r5L$loadings)), "\n") all.ok <- FALSE } if (!identical(r5$Th, r5L$Th)) { cat("Test 5 failed: GPForth cf kappa=0.3 Th not identical to legacy\n") cat("max difference:", max(abs(r5$Th - r5L$Th)), "\n") all.ok <- FALSE } # --- Test 6: GPFoblq vs GPFoblq.legacy, quartimin, identity start --- r6 <- GPFoblq(A2, method = "quartimin") r6L <- GPArotation:::GPFoblq.legacy(A2, method = "quartimin") if (!identical(r6$loadings, r6L$loadings)) { cat("Test 6 failed: GPFoblq quartimin loadings not identical to legacy\n") cat("max difference:", max(abs(r6$loadings - r6L$loadings)), "\n") all.ok <- FALSE } if (!identical(r6$Phi, r6L$Phi)) { cat("Test 6 failed: GPFoblq quartimin Phi not identical to legacy\n") cat("max difference:", max(abs(r6$Phi - r6L$Phi)), "\n") all.ok <- FALSE } if (!identical(r6$Th, r6L$Th)) { cat("Test 6 failed: GPFoblq quartimin Th not identical to legacy\n") cat("max difference:", max(abs(r6$Th - r6L$Th)), "\n") all.ok <- FALSE } if (!identical(r6$convergence, r6L$convergence)) { cat("Test 6 failed: GPFoblq quartimin convergence not identical to legacy\n") all.ok <- FALSE } # --- Test 7: GPFoblq vs GPFoblq.legacy, oblimin, 3 factors --- r7 <- GPFoblq(A3, method = "oblimin") r7L <- GPArotation:::GPFoblq.legacy(A3, method = "oblimin") if (!identical(r7$loadings, r7L$loadings)) { cat("Test 7 failed: GPFoblq oblimin loadings not identical to legacy\n") cat("max difference:", max(abs(r7$loadings - r7L$loadings)), "\n") all.ok <- FALSE } if (!identical(r7$Phi, r7L$Phi)) { cat("Test 7 failed: GPFoblq oblimin Phi not identical to legacy\n") cat("max difference:", max(abs(r7$Phi - r7L$Phi)), "\n") all.ok <- FALSE } if (!identical(r7$convergence, r7L$convergence)) { cat("Test 7 failed: GPFoblq oblimin convergence not identical to legacy\n") all.ok <- FALSE } # --- Test 8: GPFoblq vs GPFoblq.legacy, random start --- set.seed(42) Tmat3 <- Random.Start(3) r8 <- GPFoblq(A3, Tmat = Tmat3, method = "quartimin") set.seed(42) Tmat3 <- Random.Start(3) r8L <- GPArotation:::GPFoblq.legacy(A3, Tmat = Tmat3, method = "quartimin") if (!identical(r8$loadings, r8L$loadings)) { cat("Test 8 failed: GPFoblq random start loadings not identical to legacy\n") cat("max difference:", max(abs(r8$loadings - r8L$loadings)), "\n") all.ok <- FALSE } if (!identical(r8$Phi, r8L$Phi)) { cat("Test 8 failed: GPFoblq random start Phi not identical to legacy\n") cat("max difference:", max(abs(r8$Phi - r8L$Phi)), "\n") all.ok <- FALSE } if (!identical(r8$Th, r8L$Th)) { cat("Test 8 failed: GPFoblq random start Th not identical to legacy\n") cat("max difference:", max(abs(r8$Th - r8L$Th)), "\n") all.ok <- FALSE } # --- Test 9: GPFoblq vs GPFoblq.legacy, with normalization --- r9 <- GPFoblq(A2, method = "quartimin", normalize = TRUE) r9L <- GPArotation:::GPFoblq.legacy(A2, method = "quartimin", normalize = TRUE) if (!identical(r9$loadings, r9L$loadings)) { cat("Test 9 failed: GPFoblq normalized loadings not identical to legacy\n") cat("max difference:", max(abs(r9$loadings - r9L$loadings)), "\n") all.ok <- FALSE } if (!identical(r9$Phi, r9L$Phi)) { cat("Test 9 failed: GPFoblq normalized Phi not identical to legacy\n") cat("max difference:", max(abs(r9$Phi - r9L$Phi)), "\n") all.ok <- FALSE } # --- Test 10: convergence indicators agree --- if (!identical(r1$convergence, r1L$convergence)) { cat("Test 10 failed: GPForth convergence indicator not identical to legacy\n") all.ok <- FALSE } if (!identical(r6$convergence, r6L$convergence)) { cat("Test 10 failed: GPFoblq convergence indicator not identical to legacy\n") all.ok <- FALSE } # --- Test 11: Table structure for non-converged case --- # Uses a matrix that requires many iterations with maxit = 3 # to verify Table trimming produces same result as rbind growth r11 <- GPForth(A3, method = "simplimax", maxit = 3) r11L <- GPArotation:::GPForth.legacy(A3, method = "simplimax", maxit = 3) if (!identical(nrow(r11$Table), nrow(r11L$Table))) { cat("Test 11 failed: GPForth Table nrow not identical to legacy\n") cat("new:", nrow(r11$Table), "legacy:", nrow(r11L$Table), "\n") all.ok <- FALSE } if (!identical(unname(r11$Table[nrow(r11$Table), 2]), unname(r11L$Table[nrow(r11L$Table), 2]))) { cat("Test 11 failed: GPForth Table last row f value not identical to legacy\n") all.ok <- FALSE } # --- Test 12: Table structure for non-converged oblique case --- r12 <- GPFoblq(A3, method = "simplimax", maxit = 3) r12L <- GPArotation:::GPFoblq.legacy(A3, method = "simplimax", maxit = 3) if (!identical(nrow(r12$Table), nrow(r12L$Table))) { cat("Test 12 failed: GPFoblq Table nrow not identical to legacy\n") cat("new:", nrow(r12$Table), "legacy:", nrow(r12L$Table), "\n") all.ok <- FALSE } if (!identical(unname(r12$Table[nrow(r12$Table), 2]), unname(r12L$Table[nrow(r12L$Table), 2]))) { cat("Test 12 failed: GPFoblq Table last row f value not identical to legacy\n") all.ok <- FALSE } cat("Legacy regression tests completed.\n") if (!all.ok) stop("some tests FAILED") GPArotation/tests/print-GPArotation.R0000644000176200001440000001314415162061370017253 0ustar liggesusers# Tests for random starts and factor ordering/sorting. # Verifies that: # 1. Different random starts produce different raw output (before sorting) # 2. Sorting produces identical output regardless of starting point # 3. factanal built-in rotation agrees with GPArotation two-step (R >= 4.5.1) Sys.getenv("R_LIBS") library() require("GPArotation") search() Sys.info() require("stats") require("GPArotation") fuzz <- 1e-5 all.ok <- TRUE athl <- matrix(c( .73, -.07, .50, .82, -.01, .27, .77, -.46, -.22, .78, .17, .03, .77, .41, .13, .81, -.01, .27, .71, -.45, -.30, .82, .12, -.11, .66, -.15, -.45, .39, .76, -.40), byrow = TRUE, ncol = 3) # Seeds 238 and 46 were chosen because they converge to the same local # minimum, allowing us to test that sorting produces identical output # regardless of starting point. set.seed(238) z1 <- quartimin(athl, Tmat = Random.Start(3)) set.seed(46) z2 <- quartimin(athl, Tmat = Random.Start(3)) # --- Before sorting: z1 and z2 should differ --- if (fuzz > max(abs(z1$loadings - z2$loadings))) { cat("Random starts test failed: loadings should differ before sorting\n") all.ok <- FALSE } if (fuzz > max(abs(z1$Th - z2$Th))) { cat("Random starts test failed: Th should differ before sorting\n") all.ok <- FALSE } if (fuzz > max(abs(z1$Phi - z2$Phi))) { cat("Random starts test failed: Phi should differ before sorting\n") all.ok <- FALSE } if (!all.ok) stop("some tests FAILED before sorting") # --- After sorting: z1 and z2 should agree --- z1s <- print(z1, sortLoadings = TRUE, rotateMat = TRUE, Table = TRUE) z2s <- print(z2, sortLoadings = TRUE, rotateMat = TRUE, Table = TRUE) all.ok <- TRUE if (fuzz < max(abs(z1s$loadings - z2s$loadings))) { cat("Sorting test failed: loadings should agree after sorting\n") cat("difference:\n") print(z1s$loadings - z2s$loadings, digits = 18) all.ok <- FALSE } if (fuzz < max(abs(z1s$Th - z2s$Th))) { cat("Sorting test failed: Th should agree after sorting\n") cat("difference:\n") print(z1s$Th - z2s$Th, digits = 18) all.ok <- FALSE } if (fuzz < max(abs(z1s$Phi - z2s$Phi))) { cat("Sorting test failed: Phi should agree after sorting\n") cat("difference:\n") print(z1s$Phi - z2s$Phi, digits = 18) all.ok <- FALSE } if (!all.ok) stop("some tests FAILED after sorting") # --- factanal regression test (R >= 4.5.1) --- # Prior to R 4.5.1, factanal had a bug in factor reordering after rotation. # This was reported by Bernaards and others and fixed by the R core team. # The two-step procedure (factanal rotation="none" + GPArotation) is always # correct regardless of R version. data(ability.cov) set.seed(134) Tmat <- Random.Start(3) fa_unrotated <- factanal(factors = 3, covmat = ability.cov, rotation = "none") gpa <- oblimin(loadings(fa_unrotated), Tmat = Tmat) gpa_sorted <- print(gpa, sortLoadings = TRUE) if (getRversion() >= "4.5.1") { set.seed(134) fa_rotated <- factanal(factors = 3, covmat = ability.cov, rotation = "oblimin", control = list(rotate = list(Tmat = Tmat))) # Use abs() to account for differing sign correction heuristics between # base R and GPArotation if (1e-4 < max(abs(abs(fa_rotated$loadings) - abs(gpa_sorted$loadings)))) { cat("factanal regression test failed: loadings disagree\n") cat("difference:\n") print(abs(fa_rotated$loadings) - abs(gpa_sorted$loadings), digits = 18) all.ok <- FALSE } if (1e-4 < max(abs(fa_rotated$Phi - gpa_sorted$Phi))) { cat("factanal regression test failed: Phi disagrees\n") cat("difference:\n") print(fa_rotated$Phi - gpa_sorted$Phi, digits = 18) all.ok <- FALSE } } else { cat("Skipping factanal ordering test — requires R >= 4.5.1\n") cat("Use the two-step procedure (factanal rotation='none' + GPArotation) for correct results.\n") } cat("tests completed.\n") if (!all.ok) stop("some tests FAILED") #> z1 #Oblique rotation method Quartimin converged. #Loadings: # [,1] [,2] [,3] # [1,] 0.9451 -0.0535 -0.18033 # [2,] 0.7725 0.1431 0.01187 # [3,] 0.1323 0.8617 -0.12847 # [4,] 0.5377 0.2050 0.28753 # [5,] 0.6888 -0.0555 0.44072 # [6,] 0.7665 0.1386 0.00987 # [7,] 0.0150 0.8967 -0.08931 # [8,] 0.4047 0.3792 0.32647 # [9,] -0.1056 0.7915 0.24071 #[10,] -0.0155 -0.0165 0.94994 # # [,1] [,2] [,3] #SS loadings 3.034 2.405 1.401 #Proportion Var 0.303 0.240 0.140 #Cumulative Var 0.303 0.544 0.684 # #Phi: # [,1] [,2] [,3] #[1,] 1.000 0.554 0.259 #[2,] 0.554 1.000 0.186 #[3,] 0.259 0.186 1.000 #> z2 #Oblique rotation method Quartimin converged. #Loadings: # [,1] [,2] [,3] # [1,] 0.9451 -0.0535 -0.18033 # [2,] 0.7725 0.1431 0.01187 # [3,] 0.1323 0.8617 -0.12847 # [4,] 0.5377 0.2050 0.28753 # [5,] 0.6888 -0.0555 0.44072 # [6,] 0.7665 0.1386 0.00987 # [7,] 0.0150 0.8967 -0.08930 # [8,] 0.4047 0.3792 0.32647 # [9,] -0.1056 0.7915 0.24071 #[10,] -0.0155 -0.0165 0.94994 # # [,1] [,2] [,3] #SS loadings 3.034 2.405 1.401 #Proportion Var 0.303 0.240 0.140 #Cumulative Var 0.303 0.544 0.684 # #Phi: # [,1] [,2] [,3] #[1,] 1.000 0.554 0.259 #[2,] 0.554 1.000 0.186 #[3,] 0.259 0.186 1.000 ########################################################## # RUNNING A PRINT WITHOUT ERRORS ########################################################## # data(ability.cov) # L <- loadings(factanal(factors = 2, covmat=ability.cov)) # #v <- GPFRSoblq(L, eps = 1e-7, method = "oblimin", methodArgs = list(gam = .5), randomStarts = 100) #GPArotation:::print.GPArotation(v, rotateMat = T, Table = T) #print(v, rotateMat = T, Table = T) # #GPArotation:::summary.GPArotation(v) #summary(v) GPArotation/tests/errormessages.R0000644000176200001440000000350415162010245016605 0ustar liggesusers# Tests to ensure single-factor models produce appropriate errors. Sys.getenv("R_LIBS") library() require("GPArotation") search() Sys.info() all.ok <- TRUE expected_msg <- "Rotation does not make sense for single-factor models." # 1-factor model as a vector xv <- runif(5) # --- Test 1: wrapper function rejects a vector --- y <- try(GPArotation::quartimin(xv), silent = TRUE) if (!inherits(y, "try-error")) { cat("Error messages: test 1 failed\n") all.ok <- FALSE } # --- Test 2: GPForth rejects a vector --- y <- try(GPForth(xv, method = "quartimax"), silent = TRUE) if (!inherits(y, "try-error")) { cat("Error messages: test 2 failed\n") all.ok <- FALSE } # --- Test 3: GPFoblq rejects a vector --- y <- try(GPFoblq(xv, method = "quartimin"), silent = TRUE) if (!inherits(y, "try-error")) { cat("Error messages: test 3 failed\n") all.ok <- FALSE } # 1-factor model as a single-column matrix xw <- matrix(xv) # --- Test 4: GPForth rejects a single-column matrix with correct message --- y <- try(GPForth(xw, method = "quartimax"), silent = TRUE) if (!inherits(y, "try-error") || !grepl(expected_msg, attr(y, "condition")$message)) { cat("Error messages: test 4 failed\n") all.ok <- FALSE } # --- Test 5: GPFoblq rejects a single-column matrix with correct message --- y <- try(GPFoblq(xw, method = "quartimin"), silent = TRUE) if (!inherits(y, "try-error") || !grepl(expected_msg, attr(y, "condition")$message)) { cat("Error messages: test 5 failed\n") all.ok <- FALSE } # --- Test 6: wrapper rejects a single-column matrix with correct message --- y <- try(GPArotation::quartimin(xw), silent = TRUE) if (!inherits(y, "try-error") || !grepl(expected_msg, attr(y, "condition")$message)) { cat("Error messages: test 6 failed\n") all.ok <- FALSE } cat("tests completed.\n") if (!all.ok) stop("some tests FAILED")GPArotation/tests/MASSoblimin.R0000644000176200001440000000447614323662112016056 0ustar liggesusers Sys.getenv("R_LIBS") library() require("GPArotation") search() Sys.info() #require("stats") fuzz <- 1e-6 all.ok <- TRUE # test MASS 4th ed. p 322-324 data(ability.cov) ability.cov ability.FA <- factanal(factors = 1, covmat=ability.cov) (ability.FA <- update(ability.FA, factors = 2)) # ability.FA2 <- factanal(factors = 2, covmat = ability.cov) # max(abs(ability.FA2$loadings - ability.FA$loadings)) # summary(ability.FA) MASS ed.4 p 323 seems to be print not summary in R 2.0.1 ability.FA # this is default varimax rotation. There are 3rd+ digit differences with MASS tst <- t(matrix(c( 0.499437829039896530, 0.54344904693111962, 0.156070079431279873, 0.62153798991197484, 0.205786989958578748, 0.85992588538426895, 0.108530754440558652, 0.46776101732283504, 0.956242470279811574, 0.18209631992182243, 0.784768183877880943, 0.22482213687364205 ), 2, 6)) if( fuzz < max(abs(loadings(ability.FA) - tst))) { cat("Calculated value is not the same as test value in test 1. Value:\n") #print(loadings(ability.FA), digits=18) this truncates print(unclass(ability.FA$loadings), digits=18) cat("difference:\n") print(unclass(ability.FA$loadings) - tst, digits=18) all.ok <- FALSE } # differences with MASS here are a bit more than might be expected, # but there is already a difference before rotation. (oblirot <- oblimin(loadings(ability.FA))) obli2 <- factanal(factors = 2, covmat = ability.cov, rotation="oblimin") max(abs(loadings(oblirot) - loadings(obli2))) # factanal(factors = 2, covmat = ability.cov, scores = Bartlett, rotation="oblimin") tst <- t(matrix(c( 0.3863637969729337152, 0.4745113977203344047, -0.0110032278171669998, 0.6458708261423832253, -0.0262888675561207576, 0.8961123879025085781, -0.0180180060207963122, 0.4882918937716873575, 0.9900948712271664398, -0.0370729040114848238, 0.7905663749272058283, 0.0526099352008769991 ), 2, 6)) if( fuzz < max(abs(loadings(oblirot) - tst ))) { cat("Calculated value is not the same as test value in test 2. Value:\n") print(loadings(oblirot), digits=18) cat("difference:\n") print(loadings(oblirot) - tst, digits=18) all.ok <- FALSE } cat("tests completed.\n") if (! all.ok) stop("some tests FAILED") GPArotation/tests/rotations.R0000644000176200001440000007202414570431011015751 0ustar liggesusers# Tests here only compare against values computed previously with this code, # to ensure there was no accidental change. It would be better to have # comparisons with known correct values. # Test for oblimax is commented out as it appears to be unstable. Sys.getenv("R_LIBS") library() require("GPArotation") search() Sys.info() require("stats") require("GPArotation") fuzz <- 1e-6 all.ok <- TRUE data(ability.cov) L <- loadings(factanal(factors = 2, covmat=ability.cov)) if( 0.001 < max(abs(varimax(L, normalize=FALSE)$loadings - Varimax(L, normalize=FALSE)$loadings))) { cat("Calculated difference exceeds tolerance\n") cat("difference:\n") print(varimax(L, normalize=FALSE)$loadings - Varimax(L, normalize=FALSE)$loadings, digits=18) all.ok <- FALSE } if( 0.01 < max(abs(varimax(L, normalize=TRUE)$loadings - Varimax(L, normalize=TRUE, eps=1e-5)$loadings))) { cat("Calculated difference exceeds tolerance\n") cat("difference:\n") print(varimax(L, normalize=TRUE)$loadings - Varimax(L, normalize=TRUE, eps=1e-5)$loadings, digits=18) all.ok <- FALSE } v <- oblimin(L, eps=1e-8)$loadings tst <- t(matrix(c( 0.3863615904740822504, 0.4745127741495974161, -0.0110059418769087539, 0.6458720769633764514, -0.0262926272350604423, 0.8961141105684561348, -0.0180200526810754824, 0.4882928281695405048, 0.9900944939102318543, -0.0370718282544326011, 0.7905657274265397438, 0.0526109550054999417 ), 2, 6)) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 1. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } v <- oblimin(L, gam = 1, eps=1e-8)$loadings tst <- t(matrix(c( 0.2160827, 0.5403732, -0.4787025, 1.0224006, -0.6800410, 1.4244177, -0.3758706, 0.7781390, 1.4517362, -0.5873946, 1.1002585, -0.3396290 ), 2, 6)) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 1-gam=1. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } v <- oblimin(L, gam = .1, eps=1e-8)$loadings tst <- t(matrix(c( 0.37893531, 0.47408606, -0.02465543, 0.65257986, -0.04530330, 0.90557045, -0.02840333, 0.49349573, 0.99740452, -0.05088932, 0.79467442, 0.04241284 ), 2, 6)) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 1-gam=.1. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } v <- quartimin(L, eps=1e-8)$loadings tst <- t(matrix(c( 0.3863615904740822504, 0.4745127741495974161, -0.0110059418769087539, 0.6458720769633764514, -0.0262926272350604423, 0.8961141105684561348, -0.0180200526810754824, 0.4882928281695405048, 0.9900944939102318543, -0.0370718282544326011, 0.7905657274265397438, 0.0526109550054999417 ), 2, 6)) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 2. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } v <- targetT(L, Target=matrix(c(rep(1,3),rep(0,6),rep(1,3)), 6,2), eps=1e-5)$loadings tst <- t(matrix(c( 0.551529228817982942, 0.4905002767031292898, 0.217748645523411000, 0.6027046291262584399, 0.291173432863349457, 0.8348885228488550636, 0.154994397662456290, 0.4544843569140373241, 0.969702339393929247, 0.0850652965070581996, 0.803390575440818822, 0.1448091121037717866 ), 2, 6)) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 3. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } v <- targetT(L = L, Target=matrix(c(rep(1,3),rep(0,6),rep(1,3)), 6,2), eps=1e-5)$loadings if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 3L. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } v <- targetQ(L, Target=matrix(c(rep(1,3),rep(0,6),rep(1,3)), 6,2), eps=1e-5)$loadings tst <- t(matrix(c( 0.735795682866631218, 0.565351705145453853, 0.433590223819374398, 0.664644550038417159, 0.589924557708411568, 0.920006940799857786, 0.317543426981046928, 0.500590650032113116, 1.021758247914384077, 0.155121528590726393, 0.872521244896209747, 0.208735706420634437 ), 2, 6)) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 4. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } v <- targetQ(L = L, Target=matrix(c(rep(1,3),rep(0,6),rep(1,3)), 6,2), eps=1e-5)$loadings if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 4L. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } # Does not converge even with maxit=10000, but the loadings matrix is not # changing. Possibly the gradient is extremely large even very close to opt. v <- pstT(L, W = matrix(c(rep(.4,6),rep(.6,6)), 6,2), Target= matrix(c(rep(1,3),rep(0,6),rep(1,3)), 6,2), maxit=1000, eps=1e-5)$loadings tst <- t(matrix(c( 0.37067889993474656407, 0.638257130653133720, 0.01855112570739854416, 0.640564749523800270, 0.01576132191496706567, 0.884065831441111172, 0.00524531003824213384, 0.480158078874985073, 0.89458633399812259590, 0.383762977265515448, 0.71793428958051475064, 0.388556883222951677 ), 2, 6)) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 5. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } v <- pstT(L = L, W = matrix(c(rep(.4,6),rep(.6,6)), 6,2), Target= matrix(c(rep(1,3),rep(0,6),rep(1,3)), 6,2), maxit=1000, eps=1e-5)$loadings if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 5L. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } # Does not converge even with maxit=10000, but the loadings matrix is not # changing. Possibly the gradient is extremely large even very close to opt. v <- pstQ(L, W = matrix(c(rep(.4,6),rep(.6,6)), 6,2), Target= matrix(c(rep(1,3),rep(0,6),rep(1,3)), 6,2), maxit=1000, eps=1e-5)$loadings tst <- t(matrix(c( 0.573125161748393785, 0.700868331877288475, 0.214899397066479453, 0.681727425525818886, 0.286558275327103040, 0.940272379393286339, 0.152257795885557295, 0.510481967637567036, 1.029289798076480578, 0.462598702071116141, 0.850691132520651205, 0.456859727346562328 ), 2, 6)) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 6. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } v <- pstQ(L = L, W = matrix(c(rep(.4,6),rep(.6,6)), 6,2), Target= matrix(c(rep(1,3),rep(0,6),rep(1,3)), 6,2), maxit=1000, eps=1e-5)$loadings if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 6L. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } # oblimax # this is test value on one computer # tst <- t(matrix(c( # -8111059.94622692652, 8111060.62253121007, # 1495036.43465861562, -1495035.79614594672, # 2331634.63904705830, -2331633.75893370388, # 1356735.91680212389, -1356735.43916810025, # -23187491.19758165255, 23187491.68068471923, # -18357040.58573083207, 18357041.05348757654 # ), 2, 6)) # # this is test value on another computer # tst <- t(matrix(c( # 2694770.06630349346, -2694769.38999920478, # -496701.45733913727, 496702.09585180727, # -774647.63529061736, 774648.51540397422, # -450753.43529273639, 450753.91292676108, # 7703672.48495316971, -7703672.00185009185, # 6098832.71036116872, -6098832.24260441773 # ), 2, 6)) # # this does not converge on all platforms and has large differences possible a mistake ??? # v <- oblimax(L, eps=1e-5)$loadings # if( fuzz < max(abs(v - tst))) { # cat("Calculated value is not the same as test value in test rotations 7. Value:\n") # print(v, digits=18) # cat("difference:\n") # print(v - tst, digits=18) # all.ok <- FALSE # } v <- entropy(L, maxit=3000, eps=1e-5)$loadings tst <- t(matrix(c( 0.528292107548243184, 0.515443945340967824, 0.189686511729033253, 0.612116304198454975, 0.252311894464850861, 0.847442931117894815, 0.133843268148035738, 0.461156452364903380, 0.964740133927989407, 0.129750551769587635, 0.795847094000000532, 0.181751199795689433 ), 2, 6)) if( 0.01 < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 8. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } v <- quartimax(L, eps=1e-5)$loadings tst <- t(matrix(c( 0.534714740804540178, 0.508778102568043678, 0.197348140750149392, 0.609689309353509956, 0.262919828098457153, 0.844212045390758559, 0.139616102327241837, 0.459441658926639795, 0.966291466215733252, 0.117641548844535412, 0.798063848020893585, 0.171756193883937508 ), 2, 6)) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 9. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } v <- Varimax(L, eps=1e-8)$loadings tst <- t(matrix(c( 0.515866523962843160, 0.527879475961036904, 0.175054634278874244, 0.616460231981747930, 0.232057748479543163, 0.853211588623112749, 0.122822468397975171, 0.464213243286899446, 0.961376376417989453, 0.152689863976982837, 0.791292800869773050, 0.200653429940987366 ), 2, 6)) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 10. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } v <- simplimax(L, eps=1e-5)$loadings tst <- t(matrix(c( 0.3384175759313114429, 0.508414890494446547464, -0.0654601124161610648, 0.670992229004664153535, -0.1016231721735353366, 0.930535379393095940515, -0.0589933707274080121, 0.506904360351960181497, 0.9733094402675376289, 0.000234046050254643859, 0.7702037184085044341, 0.085651123319384916965 ), 2, 6)) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 11. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } v <- bentlerT(L, eps=1e-8)$loadings tst <- t(matrix(c( 0.523583611303327312, 0.520226117818945788, 0.184113022124463677, 0.613815719643687197, 0.244596116053327067, 0.849702038129718673, 0.129644684715025493, 0.462354355134084738, 0.963520501269179652, 0.138517057902201340, 0.794161628656258278, 0.188979901644201559 ), 2, 6)) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 12. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } v <- bentlerQ(L, eps=1e-8)$loadings tst <- t(matrix(c( 0.3801726240258240241, 0.4741208368044214638, -0.0223632969057368826, 0.6514196922540864687, -0.0421105927111659756, 0.9039359851665277334, -0.0266594447192576613, 0.4925968005718689424, 0.9961524457620027917, -0.0485973498906049697, 0.7939648477384558811, 0.0440983921679098251 ), 2, 6)) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 13. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } v <- tandemI(L, eps=1e-5)$loadings tst <- t(matrix(c( 0.615424480780047745, 0.4074649925368262759, 0.300894306348887419, 0.5658002819054848143, 0.406455233467338028, 0.7852483408305571677, 0.217785179074990981, 0.4279590047675180808, 0.971977129465111611, -0.0530960591067626969, 0.815800376450207976, 0.0295946184147908228 ), 2, 6)) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 14. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } v <- tandemII(L, eps=1e-5)$loadings tst <- t(matrix(c( 0.512160139332842212, 0.531476249107136312, 0.170736763115044710, 0.617670057812827134, 0.226081850628144149, 0.854814488884392154, 0.119571200821562001, 0.465061309851099225, 0.960284416460420398, 0.159413208985883820, 0.789869387186175276, 0.206185467095899383 ), 2, 6)) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 15. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } v <- geominT(L, eps=1e-5)$loadings tst <- t(matrix(c( 0.572197044101002361, 0.4662247895688098054, 0.243573415560656120, 0.5927388411683653935, 0.326956608263186954, 0.8215352639437966120, 0.174476792179181994, 0.4473668997335142894, 0.972471249855535680, 0.0431091626026945812, 0.808894688433769660, 0.1099794466209375043 ), 2, 6)) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 16. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } v <- geominQ(L, eps=1e-5)$loadings tst <- t(matrix(c( 0.39672053553904490508, 0.4713295988080449250, 0.00424452688463150020, 0.6389466007374070555, -0.00510976786312981532, 0.8864521406378518265, -0.00646959173137159373, 0.4830101828530461994, 0.98709860078485589518, -0.0318959930081098297, 0.79011178369962709045, 0.0558689642678330683 ), 2, 6)) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 17. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } v <- bigeominT(L, eps = 1e-5, delta = 0.01)$loadings tst <- t(matrix(c( 0.735864675930537948, 0.0572554836159610558, 0.537832587849186305, 0.3484299786828288781, 0.736693622718023078, 0.4889819217894930681, 0.398234350199199783, 0.2683070932862005598, 0.823835376232448180, -0.5185113350380095021, 0.727481839163037991, -0.3703731487890759011 ), 2, 6)) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 16-bigeominT. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } v <- bigeominQ(L, eps = 1e-5, delta = 0.01)$loadings tst <- t(matrix(c( 0.735864459785110725, 0.0572566968425438083, 0.537831272508815683, 0.3484308654124375071, 0.736691776787216535, 0.4889831363831567135, 0.398233337326754422, 0.2683077498589007681, 0.823837333630433988, -0.5185099767738823306, 0.727483237333638733, -0.3703719493837349663 ), 2, 6)) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 17-bigeominQ. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } v <- cfT(L, eps=1e-8)$loadings tst <- t(matrix(c( 0.534721263659975854, 0.508771247100584523, 0.197355957387199576, 0.609686779159006154, 0.262930651479430233, 0.844208674501022327, 0.139621992686633722, 0.459439868910532512, 0.966292974385164483, 0.117629160286744874, 0.798066049992627313, 0.171745962120156664 ), 2, 6)) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 18. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } v <- cfQ(L, eps=1e-8)$loadings tst <- t(matrix(c( 0.3863615904740822504, 0.4745127741495974161, -0.0110059418769087539, 0.6458720769633764514, -0.0262926272350604423, 0.8961141105684561348, -0.0180200526810754824, 0.4882928281695405048, 0.9900944939102318543, -0.0370718282544326011, 0.7905657274265397438, 0.0526109550054999417 ), 2, 6)) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 19. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } v <- infomaxT(L, eps=1e-5)$loadings tst <- t(matrix(c( 0.495330443338021176, 0.547195361446864537, 0.151384273205308784, 0.622695868320644275, 0.199304253086364791, 0.861451466010626055, 0.105004533733904976, 0.468565194910632365, 0.954843809781045660, 0.189293503899924942, 0.783052579543945471, 0.230726576980168713 ), 2, 6)) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 20. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } v <- infomaxQ(L, eps=1e-5)$loadings tst <- t(matrix(c( 0.39327554287862442894, 0.4693137508305071925, -0.00319802321222481794, 0.6422985517185823001, -0.01549245038490981718, 0.8912279460026399924, -0.01214605901641467763, 0.4856544522916727002, 0.99260028929193111491, -0.0433225495465055510, 0.79356458059567791530, 0.0471559021503157039 ), 2, 6)) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 21. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } v <- mccammon(L, eps=1e-5)$loadings tst <- t(matrix(c( 0.4293472299617892007, 0.600363196582340275, 0.0790140496845253004, 0.635943490060206229, 0.0992523811009183854, 0.878618107277518656, 0.0506062164774049028, 0.477512622702450096, 0.9268544198491108776, 0.297488850382792269, 0.7514463663627769519, 0.318958389348199534 ), 2, 6)) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 22. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } ###### ADDED IN NOVEMBER 2022 FOR EQUAMAX, PARSIMAX, VARIMIN, OBLIMAX data(Thurstone) v <- equamax(box26, eps=1e-5)$loadings tst <- t(matrix(c( 0.511813618717971597, 0.1252460667724786814, 0.835031881099661200, 0.211275278125612587, 0.9469860693462274215, 0.024701038786419674, 0.923671387190205140, 0.1861505968810791833, -0.278366886980007111, 0.414270797796799317, 0.7243752493532077397, 0.530526346393166759, 0.927099794400001564, 0.1710560637343615797, 0.314400690653154735, 0.685509679739711331, 0.6873945075387188908, -0.212674093365320949, 0.500975325417812756, 0.4985944480056956341, 0.693100497576226382, 0.350251174602310256, 0.8631423492204841619, 0.303299191676876356, 0.809196181501955492, 0.1468111894018074293, 0.540855816747015439, 1.051940508364259674, 0.2023337382785123650, 0.126016765617061266, 0.528246625368315792, 0.8145581663496035407, -0.154555803579673606, 0.791784749686200273, 0.5353191515116044741, -0.254010464723911089, 0.283760830721282831, -0.7132278971933163625, 0.633221728633476699, -0.283760830721282831, 0.7132278971933163625, -0.633221728633476699, -0.351981708826951678, 0.0145585781278812498, 0.920862598031950474, 0.351981708826951678, -0.0145585781278812498, -0.920862598031950474, -0.641238077659381234, 0.7340358583767647715, 0.211813801195267382, 0.641238077659381234, -0.7340358583767647715, -0.211813801195267382, 0.370916272566192251, 0.7781992933002486179, 0.457012011497068604, 0.943267697340363864, 0.1458935486092693412, 0.269085717994103968, 0.683769139477491628, 0.6932804480935084168, -0.193612975261152009, 0.375506314902942506, 0.7683789003013250518, 0.444462454027040654, 0.921697465732450816, 0.1542330203892136042, 0.244709944799956780, 0.664806997738585315, 0.6918110118942031317, -0.165931249557543792, 0.748952844572093657, 0.5985308972371030656, 0.239842451746804020, 0.716556890444816297, 0.6343221919993241587, 0.139425892477791219 ), 3, 26)) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 22. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } ### SAME FOR CRAWFORD FERGUSON WITH KAPPA = m / (2 * p) = 3 / (2 * 26) v <- cfT(box26, kappa = (3 / (2 * 26)), eps=1e-5)$loadings if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 22. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } v <- parsimax(box26, eps=1e-5)$loadings tst <- t(matrix(c( 0.7201835790622810318, -0.2820790149262949464, 0.6137467244615277817, -0.0679423851913938670, 0.6010788795762025405, 0.7590243822315081434, 0.6707172136894012926, 0.7174085874409354968, -0.0277909684381195121, 0.3564975652920873705, 0.2169149780725644350, 0.8964682806594965747, 0.8905375652375422391, 0.2961288407436278303, 0.3269136806262873951, 0.3419238671745732927, 0.8395902605853544642, 0.4072361273101923196, 0.5551801796495600128, 0.0181442676741417341, 0.8193941381745735164, 0.1791815177720131602, 0.4232257028261393605, 0.8651329309165379788, 0.8735154515073240145, 0.0707778916688399651, 0.4481498031114935499, 0.9254209439635597834, 0.5018907196720771013, 0.2347334274887991901, 0.1871266535649374341, 0.7975561080494565358, 0.5434380093797205324, 0.4642991413806251688, 0.8329607560592182658, 0.2619421428072832847, 0.6793187635833454197, -0.7070938474525871875, -0.1694942722875707464, -0.6793187635833454197, 0.7070938474525871875, 0.1694942722875707464, 0.0126413340577520572, -0.7959999181796318934, 0.5816488003350992475, -0.0126413340577520572, 0.7959999181796318934, -0.5816488003350992475, -0.7005089039174136056, -0.0349340740508546910, 0.7091733821870598309, 0.7005089039174136056, 0.0349340740508546910, -0.7091733821870598309, 0.2764675266718980007, 0.2782887989292237019, 0.8933946782281918519, 0.8957285854821546156, 0.3212930506383097073, 0.2790825626255922787, 0.3455615085575033385, 0.8287155760723180498, 0.4236528505493507568, 0.2788032457489866833, 0.2837361452757249936, 0.8779069142135194070, 0.8654448252950356357, 0.3331277242202841382, 0.2706070467039994321, 0.3390107603224090660, 0.7999236919074760310, 0.4396564471388281214, 0.5855440811683275681, 0.5029973433114328651, 0.6171108503586539840, 0.5106729412991620753, 0.5782224406112924653, 0.5832066153589001711 ), 3, 26)) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 22. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } ### SAME FOR CRAWFORD FERGUSON WITH KAPPA = (m - 1) / (p + m - 2) = (3 -1) / (26 + 3 - 2) v <- cfT(box26, kappa=( (3-1)/(26+3-2) ), eps=1e-5)$loadings if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 22. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } data(Harman, package= "GPArotation") v <- varimin(Harman8, eps=1e-5)$loadings tst <- t(matrix(c( 0.800626657046876855, -0.452452158825595752, 0.783606930490612252, -0.524447498313301397, 0.742635936060292656, -0.522609669324872517, 0.768357486963803682, -0.455227165519225097, 0.818696625686402668, 0.444445536696790211, 0.702064973637186673, 0.410429985249392060, 0.623283524595303340, 0.401857745935120247, 0.668480210595655877, 0.287458184858228272 ), 2, 8)) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 22. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } v <- oblimax(Harman8, eps=1e-5)$loadings tst <- t(matrix(c( 0.93395421734409445058, -0.0302013026726007383, 0.99243032312927881300, -0.1121899246869615951, 0.96509469978483286567, -0.1322258547171115683, 0.91647702431117861188, -0.0502569243958834178, 0.08441855308346873921, 0.8875309317276611765, 0.04427084251510177149, 0.7907585046311147448, 0.00332736511424391868, 0.7399752420126202157, 0.14133359391312094733, 0.6483050831171799366 ), 2, 8)) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 22. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } # TAKEN FROM THE EXAMPLES IN THE DOCUMENTATION OF echelon data(WansbeekMeijer) fa.unrotated <- factanal(factors = 2, covmat=NetherlandsTV, rotation="none") v <- echelon(fa.unrotated$loadings)$loadings tst <- matrix(c( 0.7910866, 0.000000000, 0.8356693, 0.086562877, 0.7732175, 0.003599155, 0.4712891, 0.520430204, 0.4716313, 0.596050663, 0.4340904, 0.693182608, 0.3934293, 0.610972389 ), ncol = 2, nrow = 7, byrow=7) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 23. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } # TAKEN FROM THE EXAMPLES IN THE DOCUMENTATION OF eiv v <- eiv(fa.unrotated$loadings)$loadings tst <- matrix(c( 1.0000000, 0.0000000, 0.0000000, 1.0000000, 0.9334902, 0.0415785, -5.7552381, 6.0121639, -6.6776277, 6.8857539, -7.9104168, 8.0078509, -6.9585766, 7.0581340 ), ncol = 2, nrow = 7, byrow=7) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations 24. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } # BIFACTOR data(WansbeekMeijer) fa.unrotated <- factanal(factors = 3, covmat=NetherlandsTV, rotation="none") v <- bifactorT(fa.unrotated$loadings)$loadings tst <- matrix(c( 0.605259846207760410, 0.50926282550276680272, -0.0326441696928007064, 0.674848533008883589, 0.49892997353743967492, 0.0360559565502543422, 0.585307624074672961, 0.50452427555859225006, -0.0116655363009391944, 0.569143997010692737, 0.07907134469847305891, 0.4496106087464453172, 0.639591951170676909, -0.00317621525167442742, 0.3903956610664964244, 0.644285080202307459, -0.06194060671151470354, 0.4889273316625122323, 0.894466584777320994, -0.44135797428894490979, -0.0115183403900823399 ), ncol = 3, nrow = 7, byrow=7) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations bifactorT. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } v <- bifactorQ(fa.unrotated$loadings)$loadings tst <- matrix(c( 0.639628269247016989, 0.4617887681341789063, -0.03408526722627130967, 0.708202536330854282, 0.4531948277009248405, 0.03509478386512845938, 0.619356995328652293, 0.4604997427039814184, -0.01303680319918767982, 0.572539420889668138, 0.0819716834028682007, 0.45225086629811012129, 0.637128483915923693, -0.0107264127434737802, 0.39334646255480443244, 0.637511978242973232, -0.0601392817604798208, 0.49259101012935263553, 0.861232867683719872, -0.5044079449050349329, -0.00751942773799910234 ), ncol = 3, nrow = 7, byrow=7) if( fuzz < max(abs(v - tst))) { cat("Calculated value is not the same as test value in test rotations bifactorQ. Value:\n") print(v, digits=18) cat("difference:\n") print(v - tst, digits=18) all.ok <- FALSE } cat("tests completed.\n") if (! all.ok) stop("some tests FAILED") GPArotation/MD50000644000176200001440000000615715174331613012766 0ustar liggesusersd6b9bb402463fc8d96b5144c8b213a52 *DESCRIPTION 0c9449c2019d4f4edac3ed2d7f50ef24 *NAMESPACE fe57123c64f54ec094f05d913505bb42 *NEWS e934bec21a17f9a410339b167aca9725 *R/GPF.R ad71bea84f0150061d05d975326c97c3 *R/GPFRS.R 5d8724cecc6a9238f170d22b16aacaa8 *R/NormalizingWeight.R 155e773e0a2f738ba22507ab35fb1a06 *R/RandomStart.R b1f7933b2f25386768593ef3dc82606c *R/echelon.R 2764be0f9d533d4488f9a91590025227 *R/eiv.R 77489e12f00e11011ca6905eefa32c34 *R/lp.R f96ba17fecf377689829ef8ac76b52d5 *R/printsummary.R 03f9251a03d50368f3bf3972fa033159 *R/rotations.R 59cd1eb34c3be0026628d2958bd51aaf *build/vignette.rds 1310019dc1b57ac1a61c698fe5cf4386 *data/CCAI.rda ece2cdf2ec84c3c226045ec1edf1d990 *data/Harman.rda 1f218e36ca05bd6e16c50d212aebd6df *data/Thurstone.rda 4001603e105238f1709d8acde27d7b4d *data/WansbeekMeijer.rda e8a386c68402ae9d8f05c7a9bea60c51 *inst/CITATION 4477a3574c8195125cf0d130a9ec1990 *inst/doc/GPA1guide.R b9f9d238be30d011e8c97f741346ef78 *inst/doc/GPA1guide.Stex 463be621ea74f69823a2e62e3f9a9686 *inst/doc/GPA1guide.pdf 7f68f13a082666a0b885798a4cf4e50d *inst/doc/GPA2local.R c7a1519bee2b6f8de58a8e23d4b05d40 *inst/doc/GPA2local.Stex 789cd6b21d0f9059e8f3b98af4d34595 *inst/doc/GPA2local.pdf dc3824e1b47881b205418652e91df443 *inst/doc/GPA3bifactor.R 504f8b67507c6078daeccc0750f14f51 *inst/doc/GPA3bifactor.Stex a3c1d5fee2a55449340d4472de0e488f *inst/doc/GPA3bifactor.pdf a27aa6697f3bc643435b01ba125bbcc5 *man/00.GPArotation.Rd 760b2f303b5b0234d55da9be0da70dc1 *man/CCAI.Rd aa66b9b277bcfd4922aa633d96653b7a *man/GPA.Rd b48c13d8a890676fba28398b9954fac7 *man/Harman.Rd 13a6a47551529efd961de0163da9f4ae *man/NormalizingWeight.Rd acf58b9fcbfe2668b15522ea71f8dece *man/Random.Start.Rd 697a76428c52471916adb8e182676def *man/Thurstone.Rd 76187eef58a57b164d56ea87b97045b3 *man/WansbeekMeijer.Rd f4db23338032f19e61629559b35f9a59 *man/echelon.Rd a2fe6f58da34953ef64372f60cc8dc47 *man/eiv.Rd 959d1213cb2dbf91eaeca6cbb54249c7 *man/lp.Rd b0f67304cca43801674e355177c77d1d *man/print.GPArotation.Rd 4738b5134474889cc70be7f6e1258007 *man/rotations.Rd c2ff9b869276b20c98ea7ac32797e00e *man/vgQ.Rd 676d839d54d47a340f6ba36a5934221b *tests/Harman.R 9f69c980178c705014f0b982c1200f0f *tests/Jennrich2002.R b23cf38f1863aec555c6f4c910c41d66 *tests/KaiserNormalization.R 781b18f963b96896b8db5224e710ebd1 *tests/MASSoblimin.R 46d697ec9edc75bcc1822dbdae7c3f0f *tests/Revelle.R 4a45741f72f718179f8070cf11681727 *tests/Thurstone.R 721c8721d216481c1af1e14680c61627 *tests/WansbeekMeijer.R f58c767e00d02c257421ebcd3fdef92a *tests/errormessages.R 7eb465c23e5aa98b3d50767c8fa0084b *tests/legacyVsNew.R 00f65da9bb5c6ee3fe919a4ab8c87932 *tests/lp.R 54b7e913dbcfdf36201fd9dd1419d101 *tests/print-GPArotation.R 9af15ef32c1722d36e97e4ae5b17ee71 *tests/rotations.R ec436c7f4294c7c4b79b9d3967443df6 *tests/rotationsRS.R 8a93759ea459a1adff7140c54d543231 *tests/tableTests.r 0ff9640302263cb72e34844d7a090dcd *tests/varimaxVarimax.R beafc3e93910b515b1672c82423cf6a7 *tests/vgQOLD.R 7d4cc64321014d420754ea287e9dd7d4 *tests/vgQtestOldVsNew.R b9f9d238be30d011e8c97f741346ef78 *vignettes/GPA1guide.Stex c7a1519bee2b6f8de58a8e23d4b05d40 *vignettes/GPA2local.Stex 504f8b67507c6078daeccc0750f14f51 *vignettes/GPA3bifactor.Stex GPArotation/R/0000755000176200001440000000000015174250607012651 5ustar liggesusersGPArotation/R/NormalizingWeight.R0000644000176200001440000000237515160632010016427 0ustar liggesusers# Kaiser normalization #NormalizingWeight <- function(A, normalize=FALSE){ # if ("function" == mode(normalize)) normalize <- normalize(A) # if (is.logical(normalize)){ # if (normalize) normalize <- sqrt(rowSums(A^2)) # else return(array(1, dim(A))) # } # if (is.vector(normalize)) # {if(nrow(A) != length(normalize)) # stop("normalize length wrong in NormalizingWeight") # return(array(normalize, dim(A))) # } # stop("normalize argument not recognized in NormalizingWeight") #} # # # Version below submitted by Kim-Laura Speck, Uni Kassel, 25 October 2023 # # avoid NaNs in matrix A by adding machine precision values to zeros NormalizingWeight <- function(A, normalize = FALSE) { if (is.function(normalize)) normalize <- normalize(A) if (is.logical(normalize)) { if (normalize) { # Use pmax to ensure we never have a true zero (avoids NaNs) normalize <- pmax(sqrt(rowSums(A^2)), .Machine$double.eps) } else { return(array(1, dim(A))) } } if (is.vector(normalize)) { if (nrow(A) != length(normalize)) stop("normalize length wrong") # Return a matrix of the weights for easy element-wise division return(matrix(normalize, nrow(A), ncol(A))) } stop("normalize argument not recognized") }GPArotation/R/GPF.R0000644000176200001440000002674215162063646013425 0ustar liggesusersGPForth <- function(A, Tmat = diag(ncol(A)), normalize = FALSE, eps = 1e-05, maxit = 1000, method = "varimax", methodArgs = NULL) { # Gradient Projection Algorithm for orthogonal rotation (Bernaards & Jennrich, 2005). # # Args: # A : Unrotated factor loading matrix (p x k) # Tmat : Initial rotation matrix (default: identity) # normalize : Kaiser normalization - logical or weight matrix # eps : Convergence tolerance on gradient norm (default 1e-5) # maxit : Maximum iterations (default 1000) # method : Rotation criterion, e.g. "varimax", "quartimin" (default "varimax") # methodArgs : Additional arguments passed to the vgQ criterion function # # Returns: # A GPArotation object with: # loadings - rotated loading matrix # Th - final rotation matrix # Table - iteration history (iter, f, log10(gradient norm), alpha) # method - method label from criterion function # orthogonal - TRUE (orthogonal rotation) # convergence - TRUE if converged within maxit # Gq - final gradient matrix # --- Kaiser normalization --- if ((!is.logical(normalize)) || normalize) { W <- NormalizingWeight(A, normalize = normalize) normalize <- TRUE A <- A / W } if (ncol(A) < 2) stop("Rotation does not make sense for single-factor models.") # --- Initialization --- vgQfun <- paste("vgQ", method, sep = ".") alpha <- 1 L <- A %*% Tmat VgQ <- do.call(vgQfun, append(list(L), methodArgs)) f <- VgQ$f G <- crossprod(A, VgQ$Gq) VgQt <- do.call(vgQfun, append(list(L), methodArgs)) # guards against exact initial solution Table <- matrix(NA_real_, nrow = maxit + 1, ncol = 4, dimnames = list(NULL, c("iter", "f", "log10(s)", "alpha"))) # --- Main loop --- for (iter in 0:maxit) { # Projected gradient onto orthogonal manifold M <- crossprod(Tmat, G) S <- (M + t(M)) / 2 Gp <- G - Tmat %*% S s <- sqrt(sum(diag(crossprod(Gp)))) Table[iter + 1, ] <- c(iter, f, log10(s), alpha) if (s < eps) break # Line search: halve step size until sufficient decrease alpha <- 2 * alpha for (i in 0:10) { X <- Tmat - alpha * Gp UDV <- svd(X) Tmatt <- UDV$u %*% t(UDV$v) L <- A %*% Tmatt VgQt <- do.call(vgQfun, append(list(L), methodArgs)) if (VgQt$f < (f - 0.5 * s^2 * alpha)) break alpha <- alpha / 2 } Tmat <- Tmatt f <- VgQt$f G <- crossprod(A, VgQt$Gq) } # --- Convergence check --- convergence <- (s < eps) if (iter == maxit && !convergence) warning("Convergence not obtained in GPForth. ", maxit, " iterations used.") # --- Trim unused rows from Table --- Table <- Table[1:(iter + 1), , drop = FALSE] # --- Undo normalization --- if (normalize) L <- L * W dimnames(L) <- dimnames(A) # --- Return --- r <- list( loadings = L, Th = Tmat, Table = Table, method = VgQ$Method, orthogonal = TRUE, convergence = convergence, Gq = VgQt$Gq ) class(r) <- "GPArotation" r } GPFoblq <- function(A, Tmat = diag(ncol(A)), normalize = FALSE, eps = 1e-05, maxit = 1000, method = "quartimin", methodArgs = NULL) { # Gradient Projection Algorithm for oblique rotation (Bernaards & Jennrich, 2005). # # Args: # A : Unrotated factor loading matrix (p x k) # Tmat : Initial transformation matrix (default: identity) # normalize : Kaiser normalization - logical or weight matrix # eps : Convergence tolerance on gradient norm (default 1e-5) # maxit : Maximum iterations (default 1000) # method : Rotation criterion, e.g. "quartimin" (default "quartimin") # methodArgs : Additional arguments passed to the vgQ criterion function # # Returns: # A GPArotation object with: # loadings - rotated loading matrix # Phi - factor correlation matrix (t(Tmat) %*% Tmat) # Th - final transformation matrix # Table - iteration history (iter, f, log10(gradient norm), alpha) # method - method label from criterion function # orthogonal - FALSE (oblique rotation) # convergence - TRUE if converged within maxit # Gq - final gradient matrix if (ncol(A) < 2) stop("Rotation does not make sense for single-factor models.") # --- Kaiser normalization --- if ((!is.logical(normalize)) || normalize) { W <- NormalizingWeight(A, normalize = normalize) normalize <- TRUE A <- A / W } # --- Initialization --- vgQfun <- paste("vgQ", method, sep = ".") alpha <- 1 L <- A %*% t(solve(Tmat)) VgQ <- do.call(vgQfun, append(list(L), methodArgs)) f <- VgQ$f G <- -t(t(L) %*% VgQ$Gq %*% solve(Tmat)) VgQt <- do.call(vgQfun, append(list(L), methodArgs)) # guards against exact initial solution Table <- matrix(NA_real_, nrow = maxit + 1, ncol = 4, dimnames = list(NULL, c("iter", "f", "log10(s)", "alpha"))) # --- Main loop --- for (iter in 0:maxit) { # Projected gradient onto oblique manifold Gp <- G - Tmat %*% diag(c(rep(1, nrow(G)) %*% (Tmat * G))) s <- sqrt(sum(diag(crossprod(Gp)))) Table[iter + 1, ] <- c(iter, f, log10(s), alpha) if (s < eps) break # Line search: halve step size until sufficient decrease alpha <- 2 * alpha for (i in 0:10) { X <- Tmat - alpha * Gp v <- 1 / sqrt(c(rep(1, nrow(X)) %*% X^2)) Tmatt <- X %*% diag(v) L <- A %*% t(solve(Tmatt)) VgQt <- do.call(vgQfun, append(list(L), methodArgs)) if ((f - VgQt$f) > 0.5 * s^2 * alpha) break alpha <- alpha / 2 } Tmat <- Tmatt f <- VgQt$f G <- -t(t(L) %*% VgQt$Gq %*% solve(Tmatt)) } # --- Convergence check --- convergence <- (s < eps) if (iter == maxit && !convergence) warning("Convergence not obtained in GPFoblq. ", maxit, " iterations used.") # --- Trim unused rows from Table --- Table <- Table[1:(iter + 1), , drop = FALSE] # --- Undo normalization --- if (normalize) L <- L * W dimnames(L) <- dimnames(A) # --- Return --- # N.B. renaming Lh to loadings in specific rotations # relies on loadings being the first element of the list r <- list( loadings = L, Phi = t(Tmat) %*% Tmat, Th = Tmat, Table = Table, method = VgQ$Method, orthogonal = FALSE, convergence = convergence, Gq = VgQt$Gq ) class(r) <- "GPArotation" r } ########################################################################### # Legacy functions - retained for historical reference and reproducibility. # Original implementations from Bernaards & Jennrich (2005). # Superseded by the updated GPForth and GPFoblq above (GPArotation 2026.4-1). # Note: commented-out lines are preserved intentionally as part of the # original development history. ########################################################################### GPForth.legacy <- function(A, Tmat = diag(ncol(A)), normalize = FALSE, eps = 1e-05, maxit = 1000, method = "varimax", methodArgs = NULL) { # Legacy implementation of GPForth (Bernaards & Jennrich, 2005). # Retained for historical reference and reproducibility. # Superseded by GPForth in GPArotation 2026.4-1. if((!is.logical(normalize)) || normalize) { W <- NormalizingWeight(A, normalize=normalize) normalize <- TRUE A <- A/W } if(1 >= ncol(A)) stop("rotation does not make sense for single factor models.") al <- 1 L <- A %*% Tmat #Method <- get(paste("vgQ",method,sep=".")) #VgQ <- Method(L, ...) Method <- paste("vgQ",method,sep=".") VgQ <- do.call(Method, append(list(L), methodArgs)) G <- crossprod(A,VgQ$Gq) f <- VgQ$f Table <- NULL #set initial value for the unusual case of an exact initial solution VgQt <- do.call(Method, append(list(L), methodArgs)) for (iter in 0:maxit){ M <- crossprod(Tmat,G) S <- (M + t(M))/2 Gp <- G - Tmat %*% S s <- sqrt(sum(diag(crossprod(Gp)))) Table <- rbind(Table, c(iter, f, log10(s), al)) if (s < eps) break al <- 2*al for (i in 0:10){ X <- Tmat - al * Gp UDV <- svd(X) Tmatt <- UDV$u %*% t(UDV$v) L <- A %*% Tmatt #VgQt <- Method(L, ...) VgQt <- do.call(Method, append(list(L), methodArgs)) if (VgQt$f < (f - 0.5*s^2*al)) break al <- al/2 } Tmat <- Tmatt f <- VgQt$f G <- crossprod(A,VgQt$Gq) } convergence <- (s < eps) if ((iter == maxit) & !convergence) warning("convergence not obtained in GPForth. ", maxit, " iterations used.") if(normalize) L <- L * W dimnames(L) <- dimnames(A) r <- list(loadings=L, Th=Tmat, Table=Table, method=VgQ$Method, orthogonal=TRUE, convergence=convergence, Gq=VgQt$Gq) class(r) <- "GPArotation" r } GPFoblq.legacy <- function(A, Tmat = diag(ncol(A)), normalize = FALSE, eps = 1e-05, maxit = 1000, method = "quartimin", methodArgs = NULL) { # Legacy implementation of GPFoblq (Bernaards & Jennrich, 2005). # Retained for historical reference and reproducibility. # Superseded by GPFoblq in GPArotation 2026.4-1. if(1 >= ncol(A)) stop("rotation does not make sense for single factor models.") if((!is.logical(normalize)) || normalize) { W <- NormalizingWeight(A, normalize=normalize) normalize <- TRUE A <- A/W } al <- 1 L <- A %*% t(solve(Tmat)) #Method <- get(paste("vgQ",method,sep=".")) #VgQ <- Method(L, ...) Method <- paste("vgQ",method,sep=".") VgQ <- do.call(Method, append(list(L), methodArgs)) G <- -t(t(L) %*% VgQ$Gq %*% solve(Tmat)) f <- VgQ$f Table <- NULL #Table <- c(-1,f,log10(sqrt(sum(diag(crossprod(G))))),al) #set initial value for the unusual case of an exact initial solution VgQt <- do.call(Method, append(list(L), methodArgs)) for (iter in 0:maxit){ Gp <- G - Tmat %*% diag(c(rep(1,nrow(G)) %*% (Tmat*G))) s <- sqrt(sum(diag(crossprod(Gp)))) Table <- rbind(Table,c(iter,f,log10(s),al)) if (s < eps) break al <- 2*al for (i in 0:10){ X <- Tmat - al*Gp v <- 1/sqrt(c(rep(1,nrow(X)) %*% X^2)) Tmatt <- X %*% diag(v) L <- A %*% t(solve(Tmatt)) #VgQt <- Method(L, ...) VgQt <- do.call(Method, append(list(L), methodArgs)) improvement <- f - VgQt$f if (improvement > 0.5*s^2*al) break al <- al/2 } Tmat <- Tmatt f <- VgQt$f G <- -t(t(L) %*% VgQt$Gq %*% solve(Tmatt)) } convergence <- (s < eps) if ((iter == maxit) & !convergence) warning("convergence not obtained in GPFoblq. ", maxit, " iterations used.") if(normalize) L <- L * W dimnames(L) <- dimnames(A) # N.B. renaming Lh to loadings in specificific rotations # uses fact that Lh is first. r <- list(loadings=L, Phi=t(Tmat) %*% Tmat, Th=Tmat, Table=Table, method=VgQ$Method, orthogonal=FALSE, convergence=convergence, Gq=VgQt$Gq) class(r) <- "GPArotation" r }GPArotation/R/lp.R0000644000176200001440000001667115162262251013415 0ustar liggesusers# Iterative re-weighted least squares for Lp rotation. # Functions provided by Xinyi Liu, with random start integration by Coen Bernaards (February 2025). # # Each rotation uses an inner loop (GPA) and an outer loop (IRWLS). # Random starts add a third outer loop. # # Note: lpQ and lpT exist as separate random-start wrappers rather than using # .GPA_RS_engine because the Lp rotation calls GPFoblq.lp and GPForth.lp # rather than GPFoblq and GPForth. Integrating with .GPA_RS_engine would # require changes to the core GP algorithms, which was intentionally avoided. # # 4 functions: # lpQ - oblique Lp rotation wrapper (with optional random starts) # GPFoblq.lp - main oblique Lp GP function # lpT - orthogonal Lp rotation wrapper (with optional random starts) # GPForth.lp - main orthogonal Lp GP function # --- OBLIQUE Lp ROTATION --- lpQ <- function(A, Tmat = diag(ncol(A)), p = 1, normalize = FALSE, eps = 1e-05, maxit = 1000, randomStarts = 0, gpaiter = 5) { if (normalize) message("Normalization is not recommended for Lp rotation. Use may have unexpected results.") if (randomStarts > 0) Tmat <- Random.Start(ncol(A)) r <- GPFoblq.lp(A, Tmat = Tmat, p, normalize = normalize, eps = eps, maxit = maxit, gpaiter = gpaiter) if (randomStarts > 1) { Qvalues <- sum(abs(r$loadings)^p) / nrow(A) Qmin <- Qvalues Qconverged <- r$convergence for (inum in 2:randomStarts) { gpout <- GPFoblq.lp(A, Tmat = Random.Start(ncol(A)), p, normalize = normalize, eps = eps, maxit = maxit, gpaiter = gpaiter) Qval <- sum(abs(gpout$loadings)^p) / nrow(A) Qvalues <- c(Qvalues, Qval) Qconverged <- c(Qconverged, gpout$convergence) if (Qval < Qmin) { r <- gpout Qmin <- Qval } } Qmin <- eps * round(Qmin * 1 / eps, 0) Qvalues <- eps * round(Qvalues * 1 / eps, 0) randStartChar <- c(randomStarts = randomStarts, Converged = sum(Qconverged), atMinimum = sum(Qvalues == Qmin), localMins = length(unique(Qvalues))) r <- list(loadings = r$loadings, Phi = r$Phi, Th = r$Th, Table = r$Table, method = r$method, orthogonal = FALSE, convergence = r$convergence, Gq = r$Gq, randStartChar = randStartChar, Qvalues = Qvalues) class(r) <- "GPArotation" } dimnames(r$Phi) <- list(colnames(r$loadings), colnames(r$loadings)) r } GPFoblq.lp <- function(A, Tmat = diag(ncol(A)), p = 1, normalize = FALSE, eps = 1e-05, maxit = 10000, gpaiter = 5) { # Oblique Lp gradient projection via iterative re-weighted least squares. # Inner loop: GPA with weighted least squares criterion (vgQ.lp.wls) # Outer loop: update weights until loadings converge j_sum <- 0 start_time <- proc.time() convergence <- FALSE # Corrected initial weights based on current rotated loadings W <- ((A %*% t(solve(Tmat)))^2 + eps)^(p / 2 - 1) for (it in 1:maxit) { r <- suppressWarnings( GPFoblq(A, Tmat = Tmat, normalize = normalize, eps = eps, maxit = gpaiter, method = "lp.wls", methodArgs = list(W = W))) T_new <- r$Th L <- r$loadings k <- nrow(r$Table) j <- r$Table[k, 1] j_sum <- j_sum + j W <- (L^2 + eps)^(p / 2 - 1) if (max(abs(L - A %*% solve(t(Tmat)))) < eps) { Tmat <- T_new convergence <- TRUE break } Tmat <- T_new } Phi <- t(Tmat) %*% Tmat dimnames(Phi) <- list(colnames(A), colnames(A)) Table <- data.frame( iter = it, f = sum(abs(L)^p) / nrow(L), time = proc.time()[3] - start_time[3] ) r <- list( loadings = L, Phi = Phi, Th = Tmat, Table = Table, method = paste0("Lp rotation, p=", p), orthogonal = FALSE, convergence = convergence ) class(r) <- "GPArotation" r } # --- ORTHOGONAL Lp ROTATION --- lpT <- function(A, Tmat = diag(ncol(A)), p = 1, normalize = FALSE, eps = 1e-05, maxit = 1000, randomStarts = 0, gpaiter = 5) { if (normalize) message("Normalization is not recommended for Lp rotation. Use may have unexpected results.") if (randomStarts > 0) Tmat <- Random.Start(ncol(A)) r <- GPForth.lp(A, Tmat = Tmat, p, normalize = normalize, eps = eps, maxit = maxit, gpaiter = gpaiter) if (randomStarts > 1) { Qvalues <- sum(abs(r$loadings)^p) / nrow(A) Qmin <- Qvalues Qconverged <- r$convergence for (inum in 2:randomStarts) { gpout <- GPForth.lp(A, Tmat = Random.Start(ncol(A)), p, normalize = normalize, eps = eps, maxit = maxit, gpaiter = gpaiter) Qval <- sum(abs(gpout$loadings)^p) / nrow(A) Qvalues <- c(Qvalues, Qval) Qconverged <- c(Qconverged, gpout$convergence) if (Qval < Qmin) { r <- gpout Qmin <- Qval } } Qmin <- eps * round(Qmin * 1 / eps, 0) Qvalues <- eps * round(Qvalues * 1 / eps, 0) randStartChar <- c(randomStarts = randomStarts, Converged = sum(Qconverged), atMinimum = sum(Qvalues == Qmin), localMins = length(unique(Qvalues))) r <- list(loadings = r$loadings, Phi = r$Phi, Th = r$Th, Table = r$Table, method = r$method, orthogonal = TRUE, convergence = r$convergence, Gq = r$Gq, randStartChar = randStartChar, Qvalues = Qvalues) class(r) <- "GPArotation" } dimnames(r$Phi) <- list(colnames(r$loadings), colnames(r$loadings)) r } GPForth.lp <- function(A, Tmat = diag(ncol(A)), p = 1, normalize = FALSE, eps = 1e-05, maxit = 10000, gpaiter = 5) { # Orthogonal Lp gradient projection via iterative re-weighted least squares. # Inner loop: GPA with weighted least squares criterion (vgQ.lp.wls) # Outer loop: update weights until loadings converge j_sum <- 0 start_time <- proc.time() convergence <- FALSE # Corrected initial weights based on current rotated loadings W <- ((A %*% t(solve(Tmat)))^2 + eps)^(p / 2 - 1) for (it in 1:maxit) { r <- suppressWarnings( GPForth(A, Tmat = Tmat, normalize = normalize, eps = eps, maxit = gpaiter, method = "lp.wls", methodArgs = list(W = W))) T_new <- r$Th L <- r$loadings k <- nrow(r$Table) j <- r$Table[k, 1] j_sum <- j_sum + j W <- (L^2 + eps)^(p / 2 - 1) if (max(abs(L - A %*% solve(t(Tmat)))) < eps) { Tmat <- T_new convergence <- TRUE break } Tmat <- T_new } Phi <- t(Tmat) %*% Tmat dimnames(Phi) <- list(colnames(A), colnames(A)) Table <- data.frame( iter = it, f = sum(abs(L)^p) / nrow(L), time = proc.time()[3] - start_time[3] ) r <- list( loadings = L, Phi = Phi, Th = Tmat, Table = Table, method = paste0("Lp rotation, p=", p), orthogonal = TRUE, convergence = convergence ) class(r) <- "GPArotation" r }GPArotation/R/printsummary.R0000644000176200001440000001370115172314040015536 0ustar liggesusers# S3 class functions for GPArotation objects: # .sortGPALoadings --- internal helper, not exported # print.GPArotation # summary.GPArotation # print.summary.GPArotation .sortGPALoadings <- function(x) { # Sort and sign-correct a GPArotation object. # Factors are reordered by descending variance explained and signs # are adjusted so that the sum of loadings per factor is positive. # Adapted from factanal function sortLoadings (R Core Team). # Called internally by print.GPArotation and summary.GPArotation. # # Args: # x : a GPArotation object # # Returns: # x with loadings, Th, and Phi updated consistently # Preserve original column names for restoration after reordering cln <- colnames(x$loadings) # Variance explained per factor: # orthogonal: sum of squared loadings per column # oblique: diagonal of Phi %*% t(L) %*% L (accounts for factor correlations) vx <- if (x$orthogonal) colSums(x$loadings^2) else diag(x$Phi %*% crossprod(x$loadings)) # Reorder factors from largest to smallest variance explained io.ssq <- order(vx, decreasing = TRUE) x$loadings <- x$loadings[, io.ssq, drop = FALSE] # Sign correction: flip any factor column whose loadings sum to negative, # so that the dominant loadings are positive (matches factanal convention) neg <- colSums(x$loadings) < 0 x$loadings[, neg] <- -x$loadings[, neg] # Restore column names after reordering colnames(x$loadings) <- cln # unit vector: 1 for columns kept as-is, -1 for sign-flipped columns # Used to apply the same transformation to Th and Phi unit <- c(1, -1)[neg + 1L] # Apply reordering and sign correction to rotation matrix Th # so that loadings = A %*% solve(t(Th)) remains consistent x$Th <- x$Th[, io.ssq] %*% diag(unit) # Apply reordering and sign correction to factor correlation matrix Phi # (oblique only) so that R = L %*% Phi %*% t(L) is preserved if (!x$orthogonal && "Phi" %in% names(x)) x$Phi <- diag(unit) %*% x$Phi[io.ssq, io.ssq] %*% diag(unit) x } print.GPArotation <- function(x, digits = 3L, sortLoadings = TRUE, rotateMat = FALSE, Table = FALSE, ...) { # --- Sort factors by descending variance explained --- # Uses .sortGPALoadings which aligns with factanal sorting convention if (sortLoadings) x <- .sortGPALoadings(x) # Column names and variance explained computed after sorting vx <- if (x$orthogonal) colSums(x$loadings^2) else diag(x$Phi %*% t(x$loadings) %*% x$loadings) # --- Convergence header --- cat(if (x$orthogonal) "Orthogonal" else "Oblique") cat(" rotation method", x$method) cat(if (!x$convergence) " NOT") cat(" converged") cat(if ("randStartChar" %in% names(x)) " at lowest minimum.\n" else ".\n") # --- Random start diagnostics --- if ("randStartChar" %in% names(x)) { rs <- x$randStartChar cat("Of ", rs[1], " random starts ", round(100 * rs[2] / rs[1]), "% converged, ", round(100 * rs[3] / rs[1]), "% at the same lowest minimum.\n", sep = "") if (rs[4] > 1) cat("Random starts converged to ", rs[4], " different local minima.\n", sep = "") } # --- Loadings --- cat(if ("randStartChar" %in% names(x)) "Loadings at lowest minimum:\n" else "Loadings:\n") print(round(x$loadings, digits)) # --- Variance explained --- varex <- rbind(`SS loadings` = vx) colnames(varex) <- colnames(x$loadings) # no need for cln if (is.null(attr(x, "covariance"))) { varex <- rbind(varex, `Proportion Var` = vx / nrow(x$loadings)) varex <- rbind(varex, `Cumulative Var` = cumsum(vx / nrow(x$loadings))) } cat("\n") print(round(varex, digits)) # --- Phi (oblique only) --- if (!x$orthogonal) { dimnames(x$Phi) <- list(colnames(x$loadings), colnames(x$loadings)) cat("\nPhi:\n") print(round(x$Phi, digits)) } # --- Optional rotation matrix --- if (rotateMat) { cat("\nRotating matrix:\n") print(t(solve(x$Th)), digits = digits) } # --- Optional iteration table --- if (Table) { cat("\nIteration table:\n") print(x$Table, digits = digits) } invisible(x) } summary.GPArotation <- function(object, digits = 3L, Structure = TRUE, ...) { # Returns a summary object with sign-corrected and sorted loadings, # Phi, method, convergence, iteration count, and display options. # Applies .sortGPALoadings for consistency with print.GPArotation --- # both print and summary show the same sorted, sign-corrected solution. object <- .sortGPALoadings(object) r <- list( loadings = object$loadings, Phi = object$Phi, method = object$method, orthogonal = object$orthogonal, convergence = object$convergence, iters = rev(object$Table[, 1])[1], Structure = Structure, digits = digits ) class(r) <- "summary.GPArotation" r } print.summary.GPArotation <- function(x, ...) { # --- Convergence header --- cat(if (x$orthogonal) "Orthogonal" else "Oblique") cat(" rotation method", x$method) if (!x$convergence) cat(" NOT") cat(" converged in ", x$iters, " iterations.\n", sep = "") # --- Pattern matrix (loadings) --- # For oblique rotation the pattern matrix contains regression coefficients: # the unique contribution of each factor to each item controlling for # factor intercorrelations. For orthogonal rotation pattern = structure. prstr <- !x$orthogonal && x$Structure cat(if (prstr) "Pattern (loadings):\n" else "Loadings:\n") print(round(x$loadings, x$digits)) # --- Structure matrix (oblique only) --- # The structure matrix contains correlations between items and factors: # Structure = Pattern %*% Phi # Structure coefficients are inflated relative to pattern coefficients # when factor intercorrelations are high. Both are shown when # Structure = TRUE (the default) to support complete reporting. if (prstr) { cat("\nStructure:\n") S <- x$loadings %*% x$Phi colnames(S) <- colnames(x$loadings) print(round(S, x$digits)) } }GPArotation/R/eiv.R0000644000176200001440000000114714570234527013564 0ustar liggesuserseiv <- function(L, identity=seq(NCOL(L)), ...){ A1 <- L[ identity, , drop=FALSE] g <- solve(A1) if(1e-14 < max(abs(diag(1, length(identity)) - A1 %*% g))) warning("Inverse is not well conditioned. Consider setting identity to select different rows.") B <- array(NA, dim(L)) B[identity, ] <- diag(1, length(identity)) B[-identity,] <- L[-identity,, drop=FALSE] %*% g dimnames(B) <- list(dimnames(L)[[1]], paste("factor", seq(NCOL(L)))) r <- list(loadings=B, Th=t(A1), method="eiv", orthogonal=FALSE, convergence=TRUE, Phi= tcrossprod(A1)) class(r) <- "GPArotation" r } GPArotation/R/echelon.R0000644000176200001440000000206114570234575014415 0ustar liggesusersechelon <- function(L, reference=seq(NCOL(L)), ...) { # Split L in reference part and the rest A1 <- L[reference,, drop=FALSE] #A2 is L[-reference,] # Compute the part of A Phi A' corresponding to the reference variables # Compute cholesky rot = rotated reference part # No check or error message for singularity. Exact singularity is rare in # practice but ill-conditioning is a real danger. # now assuming orthogonal (Phi=I) #newPhi <- if (is.null(Phi)) A1 %*% t(A1) else A1 %*% Phi %*% t(A1) #B1 <- t(chol(newPhi)) B1 <- t(chol(A1 %*% t(A1))) # Transformation matrix: B1 = A1 * Tmat # Rotated solution for non-reference part: B2 = A2 * Tmat Tmat <- solve(A1, B1) # Assemble rotated solution B <- matrix(0, NROW(L), NCOL(L)) B[reference,] <- B1 B[-reference,] <- L[-reference,, drop=FALSE] %*% Tmat dimnames(B) <- list(dimnames(L)[[1]], paste("factor", seq(NCOL(L)))) r <- list(loadings=B, Th=Tmat, method="echelon", orthogonal=TRUE, convergence=TRUE) class(r) <- "GPArotation" r } GPArotation/R/GPFRS.R0000644000176200001440000001116315162001617013647 0ustar liggesusers# Main wrapper functions for GPForth and GPFoblq with random start functionality. # Overhauled as part of 2026.4-1 .GPA_RS_engine <- function(A, Tmat, normalize = FALSE, eps = 1e-5, maxit = 1000, method = NULL, methodArgs = NULL, randomStarts = 0, orthogonal = TRUE, L = NULL, ...) { # Internal engine implementing random-start gradient projection rotation. # # Args: # A : Unrotated factor loading matrix (p x k) # Tmat : Initial rotation/transformation matrix # normalize : Kaiser normalization - logical or weight matrix # eps : Convergence tolerance (default 1e-5) # maxit : Maximum iterations (default 1000) # method : Rotation criterion name # methodArgs : Additional arguments passed to the vgQ criterion function # randomStarts : Number of random starts (0 = use Tmat as-is) # orthogonal : TRUE for orthogonal (GPForth), FALSE for oblique (GPFoblq) # L : Deprecated alias for A # # Returns: # A GPArotation object from the best start, with optional randStartChar diagnostics # --- Deprecation --- if (!is.null(L)) { warning("Argument 'L' is deprecated; using 'A' instead.", call. = FALSE) A <- L } # --- Validation --- if (ncol(A) <= 1) stop("Rotation does not make sense for single-factor models.") # --- Setup --- engine <- if (orthogonal) GPForth else GPFoblq actual_starts <- max(1, randomStarts) best_res <- NULL Qvalues <- numeric(actual_starts) Qconverged <- logical(actual_starts) # --- Execution loop --- for (i in 1:actual_starts) { current_Tmat <- if (randomStarts > 0) Random.Start(ncol(A)) else Tmat res <- engine(A, Tmat = current_Tmat, normalize = normalize, eps = eps, maxit = maxit, method = method, methodArgs = methodArgs) # Use indexing instead of tail() to avoid namespace warnings Qvalues[i] <- res$Table[nrow(res$Table), 2] Qconverged[i] <- res$convergence if (is.null(best_res) || Qvalues[i] < best_res$Table[nrow(best_res$Table), 2]) best_res <- res } # --- Random start diagnostics --- if (randomStarts > 1) { Q_round <- round(Qvalues / eps) * eps Qmin_round <- min(Q_round) best_res$randStartChar <- c( randomStarts = randomStarts, Converged = sum(Qconverged), atMinimum = sum(Q_round == Qmin_round), localMins = length(unique(Q_round)) ) } # --- Finalize for S3 print/summary --- if (!orthogonal) dimnames(best_res$Phi) <- list(colnames(A), colnames(A)) best_res } GPFRSorth <- function(A, Tmat = diag(ncol(A)), normalize = FALSE, eps = 1e-5, maxit = 1000, method = "varimax", methodArgs = NULL, randomStarts = 0, ...) { # Orthogonal rotation with optional random starts. Wrapper for .GPA_RS_engine. # # Args: # A : Unrotated factor loading matrix (p x k) # Tmat : Initial rotation matrix (default: identity) # normalize : Kaiser normalization - logical or weight matrix # eps : Convergence tolerance (default 1e-5) # maxit : Maximum iterations (default 1000) # method : Rotation criterion (default "varimax") # methodArgs : Additional arguments passed to the vgQ criterion function # randomStarts : Number of random starts (0 = use Tmat as-is) .GPA_RS_engine(A = A, Tmat = Tmat, normalize = normalize, eps = eps, maxit = maxit, method = method, methodArgs = methodArgs, randomStarts = randomStarts, orthogonal = TRUE, ...) } GPFRSoblq <- function(A, Tmat = diag(ncol(A)), normalize = FALSE, eps = 1e-5, maxit = 1000, method = "quartimin", methodArgs = NULL, randomStarts = 0, ...) { # Oblique rotation with optional random starts. Wrapper for .GPA_RS_engine. # # Args: # A : Unrotated factor loading matrix (p x k) # Tmat : Initial transformation matrix (default: identity) # normalize : Kaiser normalization - logical or weight matrix # eps : Convergence tolerance (default 1e-5) # maxit : Maximum iterations (default 1000) # method : Rotation criterion (default "quartimin") # methodArgs : Additional arguments passed to the vgQ criterion function # randomStarts : Number of random starts (0 = use Tmat as-is) .GPA_RS_engine(A = A, Tmat = Tmat, normalize = normalize, eps = eps, maxit = maxit, method = method, methodArgs = methodArgs, randomStarts = randomStarts, orthogonal = FALSE, ...) }GPArotation/R/RandomStart.R0000644000176200001440000000215315162026537015233 0ustar liggesusers# Random.Start generates a single random orthogonal matrix of size k x k. # # References: # Stewart, G. W. (1980). The efficient generation of random orthogonal matrices # with an application to condition estimators. SIAM Journal on Numerical # Analysis, 17(3), 403-409. http://www.jstor.org/stable/2156882 # # Mezzadri, F. (2007). How to generate random matrices from the classical # compact groups. Notices of the American Mathematical Society, 54(5), # 592-604. https://arxiv.org/abs/math-ph/0609050 # # Updated in GPArotation 2024.2-1 following a suggestion by Yves Rosseel. # The original qr.Q(qr(matrix(rnorm(k*k), k))) does not guarantee uniform # sampling from the Haar measure; the sign correction on R's diagonal does. Random.Start <- function(k = 2L) { # 1. Generate a k x k matrix of standard normal variates and QR decompose Z <- matrix(rnorm(k * k), nrow = k, ncol = k) qr.out <- qr(Z) # 2. Extract Q and the signs of R's diagonal Q <- qr.Q(qr.out) d <- sign(diag(qr.R(qr.out))) # 3. Scale columns of Q by the signs - ensures uniform sampling (Haar measure) Q %*% diag(d) }GPArotation/R/rotations.R0000644000176200001440000006073115164767421015033 0ustar liggesusers########################################################################### ########################################################################### # --- OBLIMIN --- oblimin <- function(A, Tmat = diag(ncol(A)), gam = 0, normalize = FALSE, randomStarts = 0, ...) { # Oblimin oblique rotation. Special cases via gam: # 0 - Quartimin # 0.5 - Biquartimin # # Args: # A : Unrotated factor loading matrix (p x k) # Tmat : Initial transformation matrix (default: identity) # gam : Obliqueness parameter (default 0) # normalize : Kaiser normalization - logical or weight matrix # randomStarts : Number of random starts (0 = use Tmat as-is) .GPA_RS_engine(A = A, Tmat = Tmat, method = "oblimin", methodArgs = list(gam = gam), normalize = normalize, randomStarts = randomStarts, orthogonal = FALSE, ...) } vgQ.oblimin <- function(L, gam = 0) { # Oblimin family of oblique rotation criteria. # gam controls the degree of obliqueness: # 0 - Quartimin # 0.5 - Biquartimin # # Args: # L : Factor loading matrix # gam : Obliqueness parameter (default 0) # # Returns: # A list with: # Gq - gradient matrix # f - objective function value # Method - method label k <- ncol(L) X <- L^2 %*% (!diag(TRUE, k)) if (gam != 0) { p <- nrow(L) X <- (diag(1, p) - matrix(gam / p, p, p)) %*% X } method <- if (gam == 0) "Oblimin Quartimin" else if (gam == 0.5) "Oblimin Biquartimin" else paste0("Oblimin g=", gam) list( Gq = L * X, f = sum(L^2 * X) / 4, Method = method ) } # --- QUARTIMIN --- quartimin <- function(A, Tmat = diag(ncol(A)), normalize = FALSE, randomStarts = 0, ...) { .GPA_RS_engine(A = A, Tmat = Tmat, method = "quartimin", normalize = normalize, randomStarts = randomStarts, orthogonal = FALSE, ...) } vgQ.quartimin <- function(L) { # Quartimin oblique rotation criterion (special case of Oblimin with gam = 0). # # Args: # L : Factor loading matrix # # Returns: # A list with: # Gq - gradient matrix # f - objective function value # Method - method label k <- ncol(L) L2 <- L^2 X <- L2 %*% (matrix(1, k, k) - diag(k)) list( Gq = L * X, f = sum(L2 * X) / 4, Method = "Quartimin" ) } # --- CRAWFORD-FERGUSON FAMILY --- cfT <- function(A, Tmat = diag(ncol(A)), kappa = 0, normalize = FALSE, randomStarts = 0, ...) { .GPA_RS_engine(A = A, Tmat = Tmat, method = "cf", methodArgs = list(kappa = kappa), normalize = normalize, randomStarts = randomStarts, orthogonal = TRUE, ...) } cfQ <- function(A, Tmat = diag(ncol(A)), kappa = 0, normalize = FALSE, randomStarts = 0, ...) { .GPA_RS_engine(A = A, Tmat = Tmat, method = "cf", methodArgs = list(kappa = kappa), normalize = normalize, randomStarts = randomStarts, orthogonal = FALSE, ...) } equamax <- function(A, Tmat = diag(ncol(A)), kappa = ncol(A) / (2 * nrow(A)), normalize = FALSE, randomStarts = 0, ...) { .GPA_RS_engine(A = A, Tmat = Tmat, method = "cf", methodArgs = list(kappa = kappa), normalize = normalize, randomStarts = randomStarts, orthogonal = TRUE, ...) } parsimax <- function(A, Tmat = diag(ncol(A)), kappa = (ncol(A) - 1) / (ncol(A) + nrow(A) - 2), normalize = FALSE, randomStarts = 0, ...) { .GPA_RS_engine(A = A, Tmat = Tmat, method = "cf", methodArgs = list(kappa = kappa), normalize = normalize, randomStarts = randomStarts, orthogonal = TRUE, ...) } vgQ.cf <- function(L, kappa = 0) { # Crawford-Ferguson (CF) family of rotation criteria (1970). # kappa controls the complexity penalty: # 0 - Quartimax / Quartimin # 1/p - Varimax # k/(2*p) - Equamax # (k-1)/(p+k-2) - Parsimax # 1 - Factor Parsimony # # Args: # L : Factor loading matrix (p x k) # kappa : Complexity weight (default 0) # # Returns: # A list with: # Gq - gradient matrix # f - objective function value # Method - method label p <- nrow(L) k <- ncol(L) N <- matrix(1, k, k) - diag(k) # k x k off-diagonal matrix M <- matrix(1, p, p) - diag(p) # p x p off-diagonal matrix L2 <- L^2 f1 <- (1 - kappa) * sum(diag(crossprod(L2, L2 %*% N))) / 4 f2 <- kappa * sum(diag(crossprod(L2, M %*% L2))) / 4 method <- if (kappa == 0) "Crawford-Ferguson Quartimax/Quartimin" else if (kappa == 1/p) "Crawford-Ferguson Varimax" else if (kappa == k/(2*p)) "Equamax" else if (kappa == (k-1)/(p+k-2)) "Parsimax" else if (kappa == 1) "Factor Parsimony" else paste0("Crawford-Ferguson: kappa=", kappa) list( Gq = (1 - kappa) * L * (L2 %*% N) + kappa * L * (M %*% L2), f = f1 + f2, Method = method ) } # --- TARGET ROTATION --- targetT <- function(A = NULL, Tmat = diag(ncol(A)), Target = NULL, normalize = FALSE, eps = 1e-5, maxit = 1000, randomStarts = 0, L = NULL, ...) { if (is.null(A) && !is.null(L)) A <- L if (is.null(A)) stop("Argument 'A' is missing, with no default.") if (is.null(Target)) stop("Argument 'Target' must be specified.") .GPA_RS_engine(A = A, Tmat = Tmat, normalize = normalize, eps = eps, maxit = maxit, method = "target", methodArgs = list(Target = Target), randomStarts = randomStarts, orthogonal = TRUE, ...) } targetQ <- function(A = NULL, Tmat = diag(ncol(A)), Target = NULL, normalize = FALSE, eps = 1e-5, maxit = 1000, randomStarts = 0, L = NULL, ...) { if (is.null(A) && !is.null(L)) A <- L if (is.null(A)) stop("Argument 'A' is missing, with no default.") if (is.null(Target)) stop("Argument 'Target' must be specified.") .GPA_RS_engine(A = A, Tmat = Tmat, normalize = normalize, eps = eps, maxit = maxit, method = "target", methodArgs = list(Target = Target), randomStarts = randomStarts, orthogonal = FALSE, ...) } vgQ.target <- function(L, Target = NULL) { # Target rotation criterion. # Minimizes the sum of squared deviations from a specified target matrix. # NA entries in Target are treated as unspecified (ignored in fit and gradient). # # Args: # L : Factor loading matrix # Target : Target matrix (same dimensions as L; NA = unspecified element) # # Returns: # A list with: # Gq - gradient matrix (zero where Target is NA) # f - objective function value # Method - method label Gq <- 2 * (L - Target) Gq[is.na(Gq)] <- 0 list( Gq = Gq, f = sum((L - Target)^2, na.rm = TRUE), Method = "Target rotation" ) } # --- PARTIALLY SPECIFIED TARGET --- pstT <- function(A = NULL, Tmat = diag(ncol(A)), W = NULL, Target = NULL, normalize = FALSE, eps = 1e-5, maxit = 1000, randomStarts = 0, L = NULL, ...) { if (is.null(A) && !is.null(L)) A <- L if (is.null(A)) stop("Argument 'A' is missing, with no default.") if (is.null(W)) stop("Argument 'W' must be specified.") if (is.null(Target)) stop("Argument 'Target' must be specified.") .GPA_RS_engine(A = A, Tmat = Tmat, normalize = normalize, eps = eps, maxit = maxit, method = "pst", methodArgs = list(W = W, Target = Target), randomStarts = randomStarts, orthogonal = TRUE, ...) } pstQ <- function(A = NULL, Tmat = diag(ncol(A)), W = NULL, Target = NULL, normalize = FALSE, eps = 1e-5, maxit = 1000, randomStarts = 0, L = NULL, ...) { if (is.null(A) && !is.null(L)) A <- L if (is.null(A)) stop("Argument 'A' is missing, with no default.") if (is.null(W)) stop("Argument 'W' must be specified.") if (is.null(Target)) stop("Argument 'Target' must be specified.") .GPA_RS_engine(A = A, Tmat = Tmat, normalize = normalize, eps = eps, maxit = maxit, method = "pst", methodArgs = list(W = W, Target = Target), randomStarts = randomStarts, orthogonal = FALSE, ...) } vgQ.pst <- function(L, W = NULL, Target = NULL) { # Partially specified target rotation criterion. # Minimizes weighted deviations from a target matrix. # W is a binary weight matrix specifying which elements are targeted. # # Args: # L : Factor loading matrix # W : Binary weight matrix (same dimensions as L; 0 = unspecified element) # Target : Target matrix (same dimensions as L) # # Returns: # A list with: # Gq - gradient matrix # f - objective function value # Method - method label Btilde <- W * Target list( Gq = 2 * (W * L - Btilde), f = sum((W * L - Btilde)^2), Method = "Partially specified target" ) } # --- ENTROPY --- entropy <- function(A, Tmat = diag(ncol(A)), normalize = FALSE, randomStarts = 0, ...) { .GPA_RS_engine(A = A, Tmat = Tmat, method = "entropy", normalize = normalize, randomStarts = randomStarts, orthogonal = TRUE, ...) } vgQ.entropy <- function(L) { # Minimum entropy oblique rotation criterion. # # Args: # L : Factor loading matrix # # Returns: # A list with: # Gq - gradient matrix # f - objective function value # Method - method label L2 <- L^2 logL2 <- log(L2 + .Machine$double.eps) list( Gq = -(L * logL2 + L), f = -sum(L2 * logL2) / 2, Method = "Minimum entropy" ) } # --- INFOMAX --- infomaxT <- function(A, Tmat = diag(ncol(A)), normalize = FALSE, randomStarts = 0, ...) { .GPA_RS_engine(A = A, Tmat = Tmat, method = "infomax", normalize = normalize, randomStarts = randomStarts, orthogonal = TRUE, ...) } infomaxQ <- function(A, Tmat = diag(ncol(A)), normalize = FALSE, randomStarts = 0, ...) { .GPA_RS_engine(A = A, Tmat = Tmat, method = "infomax", normalize = normalize, randomStarts = randomStarts, orthogonal = FALSE, ...) } vgQ.infomax <- function(L) { # Infomax oblique rotation criterion. # # Args: # L : Factor loading matrix # # Returns: # A list with: # Gq - gradient matrix # f - objective function value # Method - method label k <- ncol(L) p <- nrow(L) S <- L^2 s <- sum(S) # Normalized probability distributions E <- S / s e1 <- rowSums(S) / s e2 <- colSums(S) / s # Entropy terms Q0 <- -sum(E * log(E + .Machine$double.eps)) Q1 <- -sum(e1 * log(e1 + .Machine$double.eps)) Q2 <- -sum(e2 * log(e2 + .Machine$double.eps)) # Gradient components H <- -(log(E + .Machine$double.eps) + 1) h1 <- -(log(e1 + .Machine$double.eps) + 1) h2 <- -(log(e2 + .Machine$double.eps) + 1) G0 <- H / s - sum(S * H) / s^2 G1 <- h1 / s - sum(rowSums(S) * h1) / s^2 G2 <- rep(h2 / s, each = p) - sum(colSums(S) * h2) / s^2 list( Gq = 2 * L * (G0 - G1 - G2), f = log(k) + Q0 - Q1 - Q2, Method = "Infomax" ) } # --- McCAMMON --- mccammon <- function(A, Tmat = diag(ncol(A)), normalize = FALSE, randomStarts = 0, ...) { .GPA_RS_engine(A = A, Tmat = Tmat, method = "mccammon", normalize = normalize, randomStarts = randomStarts, orthogonal = TRUE, ...) } vgQ.mccammon <- function(L) { k <- ncol(L) p <- nrow(L) S <- L^2 M <- matrix(1, p, p) s2 <- colSums(S) P <- S / matrix(rep(s2, p), ncol = k, byrow = TRUE) Q1 <- -sum(P * log(P)) H <- -(log(P) + 1) R <- M %*% S G1 <- H/R - M %*% (S * H/R^2) s <- sum(S) p2 <- s2/s Q2 <- -sum(p2 * log(p2)) h <- -(log(p2) + 1) alpha <- h %*% p2 G2 <- rep(1, p) %*% t(h)/s - as.vector(alpha) * matrix(1, p, k) Gq <- 2 * L * (G1/Q1 - G2/Q2) f <- log(Q1) - log(Q2) list(f = f, Gq = Gq, Method = "McCammon entropy") } # --- GEOMIN --- geominT <- function(A, Tmat = diag(ncol(A)), delta = 0.01, normalize = FALSE, randomStarts = 0, ...) { .GPA_RS_engine(A = A, Tmat = Tmat, method = "geomin", methodArgs = list(delta = delta), normalize = normalize, randomStarts = randomStarts, orthogonal = TRUE, ...) } geominQ <- function(A, Tmat = diag(ncol(A)), delta = 0.01, normalize = FALSE, randomStarts = 0, ...) { .GPA_RS_engine(A = A, Tmat = Tmat, method = "geomin", methodArgs = list(delta = delta), normalize = normalize, randomStarts = randomStarts, orthogonal = FALSE, ...) } vgQ.geomin <- function(L, delta = 0.01) { # Geomin oblique rotation criterion. # delta is a small constant added for numerical stability (default 0.01). # # Args: # L : Factor loading matrix # delta : Stabilizing constant (default 0.01) # # Returns: # A list with: # Gq - gradient matrix # f - objective function value # Method - method label k <- ncol(L) L2 <- L^2 + delta pro <- exp(rowMeans(log(L2))) list( Gq = (2 / k) * (L / L2) * pro, f = sum(pro), Method = "Geomin" ) } # --- SIMPLIMAX --- simplimax <- function(A, Tmat = diag(ncol(A)), k = nrow(A), normalize = FALSE, randomStarts = 0, ...) { .GPA_RS_engine(A = A, Tmat = Tmat, method = "simplimax", methodArgs = list(k = k), normalize = normalize, randomStarts = randomStarts, orthogonal = FALSE, ...) } vgQ.simplimax <- function(L, k = nrow(L)) { # Simplimax oblique rotation criterion (Kiers, 1994). # Minimizes the k smallest squared loadings, targeting a simple structure # with k near-zero loadings per solution. # # Args: # L : Factor loading matrix # k : Number of near-zero loadings to target (default: nrow(L)) # # Returns: # A list with: # Gq - gradient matrix # f - objective function value # Method - method label L2 <- L^2 threshold <- sort(L2, partial = k)[k] Imat <- L2 <= threshold list( Gq = 2 * Imat * L, f = sum(L2[Imat]), Method = paste0("Simplimax (k=", k, ")") ) } # --- BIFACTOR --- bifactorT <- function(A, Tmat = diag(ncol(A)), normalize = FALSE, randomStarts = 0, ...) { .GPA_RS_engine(A = A, Tmat = Tmat, method = "bifactor", normalize = normalize, randomStarts = randomStarts, orthogonal = TRUE, ...) } bifactorQ <- function(A, Tmat = diag(ncol(A)), normalize = FALSE, randomStarts = 0, ...) { .GPA_RS_engine(A = A, Tmat = Tmat, method = "bifactor", normalize = normalize, randomStarts = randomStarts, orthogonal = FALSE, ...) } vgQ.bifactor <- function(L) { # Bifactor Biquartimin oblique rotation criterion. # Treats the first column as a general factor (unconstrained) # and rotates the remaining group factor columns. # # Args: # L : Factor loading matrix (first column = general factor) # # Returns: # A list with: # Gq - gradient matrix (zero gradient for general factor column) # f - objective function value # Method - method label Lt2 <- L[, -1, drop = FALSE]^2 rowS <- rowSums(Lt2) Gt <- 4 * L[, -1, drop = FALSE] * (rowS - Lt2) list( Gq = cbind(0, Gt), f = sum(rowS^2) - sum(Lt2^2), Method = "Bifactor Biquartimin" ) } # --- BI-GEOMIN --- bigeominT <- function(A, Tmat = diag(ncol(A)), delta = 0.01, normalize = FALSE, randomStarts = 0, ...) { .GPA_RS_engine(A = A, Tmat = Tmat, method = "bigeomin", methodArgs = list(delta = delta), normalize = normalize, randomStarts = randomStarts, orthogonal = TRUE, ...) } bigeominQ <- function(A, Tmat = diag(ncol(A)), delta = 0.01, normalize = FALSE, randomStarts = 0, ...) { .GPA_RS_engine(A = A, Tmat = Tmat, method = "bigeomin", methodArgs = list(delta = delta), normalize = normalize, randomStarts = randomStarts, orthogonal = FALSE, ...) } vgQ.bigeomin <- function(L, delta = 0.01) { # Bi-Geomin oblique rotation criterion. # Treats the first column as a general factor (unconstrained) # and applies Geomin rotation to the remaining group factor columns. # # Args: # L : Factor loading matrix (first column = general factor) # delta : Stabilizing constant passed to vgQ.geomin (default 0.01) # # Returns: # A list with: # Gq - gradient matrix (zero gradient for general factor column) # f - objective function value # Method - method label out <- vgQ.geomin(L[, -1, drop = FALSE], delta = delta) list( Gq = cbind(0, out$Gq), f = out$f, Method = "Bi-Geomin" ) } # --- TANDEM CRITERIA --- tandemI <- function(A, Tmat = diag(ncol(A)), normalize = FALSE, randomStarts = 0, ...) { .GPA_RS_engine(A = A, Tmat = Tmat, method = "tandemI", normalize = normalize, randomStarts = randomStarts, orthogonal = TRUE, ...) } vgQ.tandemI <- function(L) { # Tandem Criterion I (Comrey, 1967) # Seeks factors that share high loadings on the same variables. # # Args: # L : Factor loading matrix # # Returns: # A list with: # Gq - gradient matrix # f - objective function value (negated for minimization) # Method - method label L2 <- L^2 LL <- L %*% t(L) LL2 <- LL^2 # Gradient components Gq1 <- 4 * L * (LL2 %*% L2) Gq2 <- 4 * (LL * (L2 %*% t(L2))) %*% L # Negate because optimizer minimizes Gq <- -(Gq1 + Gq2) list( Gq = Gq, f = -sum(diag(crossprod(L2, LL2 %*% L2))), Method = "Tandem I" ) } tandemII <- function(A, Tmat = diag(ncol(A)), normalize = FALSE, randomStarts = 0, ...) { .GPA_RS_engine(A = A, Tmat = Tmat, method = "tandemII", normalize = normalize, randomStarts = randomStarts, orthogonal = TRUE, ...) } vgQ.tandemII <- function(L) { # Tandem Criterion II (Comrey, 1967) # Seeks factors that do NOT share high loadings on the same variables # (used as a second-stage refinement after Tandem I). # # Args: # L : Factor loading matrix # # Returns: # A list with: # Gq - gradient matrix # f - objective function value # Method - method label L2 <- L^2 LL <- L %*% t(L) LL2 <- LL^2 ILL2 <- 1 - LL2 # Complement of squared outer product # Gradient components Gq1 <- 4 * L * (ILL2 %*% L2) Gq2 <- 4 * (LL * (L2 %*% t(L2))) %*% L Gq <- Gq1 - Gq2 list( Gq = Gq, f = sum(diag(crossprod(L2, ILL2 %*% L2))), Method = "Tandem II" ) } # --- OBLIMAX --- oblimax <- function(A, Tmat = diag(ncol(A)), normalize = FALSE, randomStarts = 0, ...) { .GPA_RS_engine(A = A, Tmat = Tmat, method = "oblimax", normalize = normalize, randomStarts = randomStarts, orthogonal = FALSE, ...) } vgQ.oblimax <- function(L) { # Oblimax oblique rotation criterion. # # Args: # L : Factor loading matrix # # Returns: # A list with: # Gq - gradient matrix # f - objective function value (negated for minimization) # Method - method label s2 <- sum(L^2) s4 <- sum(L^4) list( Gq = -(4 * L^3 / s4 - 4 * L / s2), f = -(log(s4) - 2 * log(s2)), Method = "Oblimax" ) } # --- BENTLER --- bentlerT <- function(A, Tmat = diag(ncol(A)), normalize = FALSE, randomStarts = 0, ...) { .GPA_RS_engine(A = A, Tmat = Tmat, method = "bentler", normalize = normalize, randomStarts = randomStarts, orthogonal = TRUE, ...) } bentlerQ <- function(A, Tmat = diag(ncol(A)), normalize = FALSE, randomStarts = 0, ...) { .GPA_RS_engine(A = A, Tmat = Tmat, method = "bentler", normalize = normalize, randomStarts = randomStarts, orthogonal = FALSE, ...) } vgQ.bentler <- function(L) { # Bentler's invariant pattern simplicity oblique rotation criterion. # # Args: # L : Factor loading matrix # # Returns: # A list with: # Gq - gradient matrix (negated for minimization) # f - objective function value (negated for minimization) # Method - method label L2 <- L^2 M <- crossprod(L2) D_inv <- diag(1 / diag(M)) list( Gq = -L * (L2 %*% (solve(M) - D_inv)), f = -(log(det(M)) - log(det(diag(diag(M))))) / 4, Method = "Bentler" ) } # --- QUARTIMAX --- quartimax <- function(A, Tmat = diag(ncol(A)), normalize = FALSE, randomStarts = 0, ...) { .GPA_RS_engine(A = A, Tmat = Tmat, method = "quartimax", normalize = normalize, randomStarts = randomStarts, orthogonal = TRUE, ...) } vgQ.quartimax <- function(L) { # Quartimax orthogonal rotation criterion. # # Args: # L : Factor loading matrix # # Returns: # A list with: # Gq - gradient matrix (negated for minimization) # f - objective function value (negated for minimization) # Method - method label list( Gq = -L^3, f = -sum(L^4) / 4, Method = "Quartimax" ) } # --- VARIMAX --- Varimax <- function(A, Tmat = diag(ncol(A)), normalize = FALSE, randomStarts = 0, ...) { .GPA_RS_engine(A = A, Tmat = Tmat, method = "varimax", normalize = normalize, randomStarts = randomStarts, orthogonal = TRUE, ...) } vgQ.varimax <- function(L) { # Varimax orthogonal rotation criterion (Kaiser, 1958). # # Args: # L : Factor loading matrix # # Returns: # A list with: # Gq - gradient matrix (negated for minimization) # f - objective function value (negated for minimization) # Method - method label QL <- L^2 - rep(colMeans(L^2), each = nrow(L)) list( Gq = -L * QL, f = -sum(QL^2) / 4, Method = "Varimax" ) } # --- VARIMIN --- varimin <- function(A, Tmat = diag(ncol(A)), normalize = FALSE, randomStarts = 0, ...) { .GPA_RS_engine(A = A, Tmat = Tmat, method = "varimin", normalize = normalize, randomStarts = randomStarts, orthogonal = TRUE, ...) } vgQ.varimin <- function(L) { # Varimin orthogonal rotation criterion. # Minimizes the variance of squared loadings within factors - # the complement of Varimax. # # Args: # L : Factor loading matrix # # Returns: # A list with: # Gq - gradient matrix # f - objective function value # Method - method label QL <- L^2 - rep(colMeans(L^2), each = nrow(L)) list( Gq = L * QL, f = sum(QL^2) / 4, Method = "Varimin" ) } # --- LP WLS --- vgQ.lp.wls <- function(L, W) { # Weighted least squares criterion for Lp rotation. # # Args: # L : Factor loading matrix # W : Weight matrix (same dimensions as L) # # Returns: # A list with: # Gq - gradient matrix # f - objective function value # Method - method label p <- nrow(L) list( Gq = 2 * W * L / p, f = sum(W * L^2) / p, Method = "Weighted least squares for Lp rotation" ) }GPArotation/NEWS0000644000176200001440000001514515174132430013146 0ustar liggesusersChanges in GPArotation version 2026.4-1: o Comprehensive code cleanup across all functions including GPForth, GPFoblq, GPFRSorth, GPFRSoblq, .GPA_RS_engine, vgQ rotation criterion functions, Random.Start, and S3 print/summary methods. All existing code should run without modification. o GPForth and GPFoblq: pre-allocated iteration Table replaces rbind growth; step size variable renamed from 'al' to 'alpha'; Table column names set at allocation. Legacy implementations retained as unexported GPForth.legacy and GPFoblq.legacy for historical reference. o print.GPArotation and summary.GPArotation: factor sorting and sign correction now handled by internal helper .sortGPALoadings, adapted from factanal:::sortLoadings (R Core Team). This ensures print and summary produce consistent sorted output. The sign correction criterion has changed from sign(colSums(L^3)) to colSums(L) < 0, matching factanal convention. Results are numerically equivalent in all tested cases. o print.GPArotation and print.summary.GPArotation: digits argument now correctly controls decimal places in loadings and structure matrices. o print.summary.GPArotation: structure matrix now correctly displays factor names as column headers rather than [,1] [,2] [,3]. o vgQ criterion functions: the Method string has been improved for consistency in selected cases (e.g. "Simplimax (k=8)", "Varimax", "Varimin", "Bentler"). The criterion value (f) and gradient (Gq) are unaffected. o Documentation: clarifications throughout, expanded references with doi throughout; improved examples including two-step vs single-step factanal comparison. o Added dataset CCAI: 14x14 correlation matrix (CCAI_R), factor pattern matrix (CCAI_pattern), and factor intercorrelations (CCAI_Phi) for the Climate-Friendly Purchasing Choices domain of the Climate Change Action Inventory. o Three vignettes: GPA1guide (main guide, restructured), GPA2local (local minima diagnostics), GPA3bifactor (bifactor rotation and reliability coefficients). o Unit tests added and expanded: Table structure, single-factor error handling, random starts, factor sorting, factanal R >= 4.5.1 regression, numerical equivalence of updated vs legacy GPForth and GPFoblq, and vgQ criterion function regression tests. o box20 deprecated. Use box26 instead. box20 will be removed in a future version. o Removed defunct SourceForge URL from DESCRIPTION. Changes in GPArotation version 2025.3-1: o Added Lp rotation (via Xinyi Liu), including examples, help file, and tests. o Added automated tests for error messages. o Edits to the manual pages. Changes in GPArotation version 2024.3-1: o Added tests for use in automated validation systems. o Added correct class to echelon and eiv rotation. Changes in GPArotation version 2024.2-1: o Improved Random.Start for orthonormal matrix generation. o Added Bi-Geomin rotation criterion. o Edits to the manual pages. Changes in GPArotation version 2023.11-1: o Updated NormalizingWeight to handle cases with a row of zeroes. Changes in GPArotation version 2023.8-1: o Added L argument to target rotation and pst to better handle backward compatibility. Changes in GPArotation version 2023.3-1: o January 2023: GPArotation turns 18 years old. o Included GPFRSorth and GPFRSoblq functions, and set rotation routines to call GPFRSorth instead of GPForth, GPFRSoblq instead of GPFoblq. o GPFRSorth and GPFRSoblq include randomStarts = 0 as default. o Included equamax, parsimax and varimin (added vgQ.varimin). o Cleaned up print.GPArotation to account for random starts. o Cleaned up vgQ.bifactor. o Expanded vignette GPAguide. o Added vignette on derivative-free GPA: the GPArotateDF package. Changes in GPArotation version 2022.10-1: o Changed maintainer from Paul Gilbert to Coen Bernaards. Changes in GPArotation version 2022.4-1: o Switched URL from defunct http://www.stat.ucla.edu/research/gpa to https://optimizer.r-forge.r-project.org/GPArotation_www/ o Added importFrom("stats", "rnorm") to NAMESPACE file. o Fixed Rbuildignore so that files from building vignettes are not omitted in the package build. Changes in GPArotation version 2015.7-1: o Added default package imports as now required by CRAN. Changes in GPArotation version 2014.11-1: o Minor format and cleanup required by CRAN checks, no real changes. Changes in GPArotation version 2012.3-1: o No real changes, but bumping version for new CRAN suitability check. Changes in GPArotation version 2011.11-1: o Updated maintainer email address. Changes in GPArotation version 2011.10-1: o Modification to vgQ.target to allow NA in target, which is replaced by 0.0 (from William Revelle). o Added bifactorT and bifactorQ (biquartimin) from William Revelle. Changes in GPArotation version 2010.07-1: o Fixed an error caused by an exact initial setting (from William Revelle). Changes in GPArotation version 2009.02-2: o Standardized NEWS format for new function news(). Changes in GPArotation version 2009.02-1: o Minor documentation corrections as found by a new R-devel. Changes in GPArotation version 2008.05-1: o Added echelon rotation. o Added gradient Gq to result list from GPForth and GPFoblq. o Changed license from "GPL-2" to "GPL-2 or later". Changes in GPArotation version 2007.06-1: o Fixed a couple of lingering $Lh (in print and summary methods) that should have been changed to $loadings. Changes in GPArotation version 2007.04-1: o Removed an extra comma in c() that caused a test failure with R-2.5.0. o Added eiv rotation. o Renamed $Lh in the result from GPForth and GPFoblq to $loadings. As a result, rotation methods calling these functions no longer need to rename this element in order to work with factanal and other programs. It is good practice to use the extractor function loadings() rather than refer directly to object structure. o Changed rotation method functions to return all elements of GPFoblq and GPForth. o Fixed the documentation file primary alias for all rotations (which was being called oblimin). Changes in GPArotation version 2006.2-2: o Extra argument (...) to invisible in print.GPArotation was removed. Changes in GPArotation version 2006.2-1: o Broken references in documentation were fixed and updated. Changes in GPArotation version 2005.10-1: o Warning message about non-convergence expanded to indicate function. Changes in GPArotation version 2005.4-1: o First released version.GPArotation/vignettes/0000755000176200001440000000000015174250607014460 5ustar liggesusersGPArotation/vignettes/GPA2local.Stex0000644000176200001440000004143315174246025017035 0ustar liggesusers%\VignetteIndexEntry{Assessing Local Minima in Factor Rotation} %\VignettePackage{GPArotation} %\VignetteDepends{GPArotation} %\VignetteKeyword{factor rotation} %\VignetteKeyword{local minima} %\VignetteKeyword{random starts} %\VignetteKeyword{simplimax} \documentclass[english, 10pt]{article} \usepackage{hyperref} \bibliographystyle{apa} \usepackage{natbib} \usepackage{geometry} \geometry{letterpaper} \begin{document} \SweaveOpts{eval=TRUE, echo=TRUE, results=hide, fig=FALSE} \begin{Scode}{echo=FALSE, results=hide} options(continue=" ") pdf.options(pointsize = 8) \end{Scode} \begin{center} \section*{Assessing Local Minima in Factor Rotation \\ ~~\\ The \texttt{GPFallMinima} Function} \end{center} \begin{center} Author: Coen A. Bernaards \end{center} Many rotation criteria have multiple local minima. The standard \texttt{GPArotation} functions return only the best solution found among all random starts --- the one with the lowest criterion value. While this is the right default behavior, it conceals potentially important information: how many distinct solutions exist, how often each is found, and how different they are from each other. This vignette introduces \texttt{GPFallMinima}, a companion function that runs multiple random starts and retains \emph{all} distinct local minima, not just the global minimum. This allows the analyst to assess the stability of the rotation solution and to examine alternative solutions that may be substantively meaningful. For background on local minima in factor rotation, see \cite{nguwall} and \cite{mansreise}. %------------------------------------------------------------------- \section*{The GPFallMinima Function} %------------------------------------------------------------------- \texttt{GPFallMinima} is not part of the standard \texttt{GPArotation} package. It is a companion utility intended for diagnostic use. Load it alongside \texttt{GPArotation}: \begin{Scode} library("GPArotation") GPFallMinima <- function(A, method = "quartimin", orthogonal = FALSE, randomStarts = 100, eps = 1e-5, maxit = 1000, normalize = FALSE, methodArgs = NULL, minimumInclusion = 2) { # Runs multiple random starts and returns ALL distinct local minima, # not just the global minimum. Non-converged starts are discarded. # Minima found fewer than minimumInclusion times are excluded. # Minima are sorted by frequency (most common first). engine <- if (orthogonal) GPForth else GPFoblq Qvalues <- numeric(randomStarts) Qconverged <- logical(randomStarts) all_res <- vector("list", randomStarts) for (i in 1:randomStarts) { res <- engine(A, Tmat = Random.Start(ncol(A)), normalize = normalize, eps = eps, maxit = maxit, method = method, methodArgs = methodArgs) Qvalues[i] <- res$Table[nrow(res$Table), 2] Qconverged[i] <- res$convergence all_res[[i]] <- res } # Discard non-converged starts converged_idx <- which(Qconverged) nConverged <- length(converged_idx) if (nConverged == 0) stop("No starts converged. Consider increasing maxit or relaxing eps.") Qvalues_conv <- Qvalues[converged_idx] all_res_conv <- all_res[converged_idx] # Bin converged criterion values into equivalence classes Q_round <- round(Qvalues_conv / eps) * eps Q_unique <- unique(Q_round) # Build one representative solution per unique minimum minima <- vector("list", length(Q_unique)) for (j in seq_along(Q_unique)) { idx <- which(Q_round == Q_unique[j]) count <- length(idx) proportion <- count / nConverged minima[[j]] <- list( result = all_res_conv[[idx[1]]], f = Q_unique[j], count = count, proportion = proportion ) } # Sort by count (most common first) ord <- order(sapply(minima, `[[`, "count"), decreasing = TRUE) minima <- minima[ord] # Filter out minima found fewer than minimumInclusion times keep <- sapply(minima, `[[`, "count") >= minimumInclusion minima <- minima[keep] if (length(minima) == 0) stop("No minima found with count >= minimumInclusion (", minimumInclusion, "). Consider reducing minimumInclusion or increasing randomStarts.") # Summary data frame f_values <- sapply(minima, `[[`, "f") f_global <- min(f_values) summary_df <- data.frame( minimum = seq_along(minima), f = round(f_values, 6), deltaF = round(f_values - f_global, 6), count = sapply(minima, `[[`, "count"), proportion = round(sapply(minima, `[[`, "proportion"), 3), isGlobal = f_values == f_global ) result <- list( minima = minima, summary = summary_df, Qvalues = Qvalues_conv, nConverged = nConverged, nStarts = randomStarts, method = method, orthogonal = orthogonal, minimumInclusion = minimumInclusion ) class(result) <- "GPFallMinima" result } print.GPFallMinima <- function(x, ...) { cat("Random start analysis:", x$nConverged, "of", x$nStarts, "starts converged\n") cat("Distinct minima found:", nrow(x$summary), "(minimumInclusion =", x$minimumInclusion, ")\n\n") print(x$summary, row.names = FALSE) cat("\nGlobal minimum: f =", min(x$summary$f), "\n") cat("Access full solutions via $minima[[i]]$result\n") invisible(x) } \end{Scode} %------------------------------------------------------------------- \section*{Key Arguments} %------------------------------------------------------------------- \begin{itemize} \item \texttt{method} --- the rotation criterion. Criteria with many local minima, such as \texttt{simplimax}, \texttt{geomin}, and \texttt{infomax}, are the most interesting to diagnose. \item \texttt{randomStarts} --- number of random starts to attempt. More starts give a more complete picture of the solution space. For a thorough analysis, 500 or more starts are recommended. \item \texttt{minimumInclusion} --- minimum number of starts required to retain a minimum. The default of 2 filters out singletons that are likely numerical artifacts. With 500 starts, a value of 5 or 10 is more appropriate. \item \texttt{orthogonal} --- \texttt{TRUE} for orthogonal rotation (uses \texttt{GPForth}), \texttt{FALSE} for oblique (uses \texttt{GPFoblq}). Default is \texttt{FALSE}. \end{itemize} Non-converged starts are always discarded before analysis. The \texttt{proportion} column in the summary is calculated over converged starts only, so proportions sum to 1. %------------------------------------------------------------------- \section*{Example: Simplimax on CCAI Climate-Friendly Purchasing Choices Data} %------------------------------------------------------------------- The CCAI Climate-Friendly Purchasing Choices domain (Bi and Barchard, 2024) provides a useful dataset for illustrating local minima behavior. The data have 14 items and 3 factors with strong inter-correlations (0.53--0.59). Bi and Barchard used oblimin rotation in their published analysis. We use simplimax here purely to illustrate how rotation criteria can produce highly complex landscapes with multiple local minima --- not as a recommended analysis of these data. The data illustrate how dramatically rotation criteria can differ in their stability. Oblimin rotation is highly stable on these data --- all 200 random starts converge to the same solution. Simplimax, by contrast, reveals a highly complex landscape: \begin{Scode}{results=verbatim} library("GPArotation") data("CCAI", package = "GPArotation") fa_unrotated <- factanal(factors = 3, covmat = CCAI_R, n.obs = 461, rotation = "none") A <- loadings(fa_unrotated) # Oblimin: highly stable res_oblimin <- oblimin(A, normalize = TRUE, randomStarts = 200) cat("Oblimin random start diagnostics:\n") res_oblimin$randStartChar # Simplimax: complex landscape set.seed(42) res_ccai <- GPFallMinima(A, method = "simplimax", randomStarts = 200, normalize = TRUE, minimumInclusion = 2) res_ccai \end{Scode} The contrast is striking. Oblimin converges reliably to a single solution on these data. Simplimax reveals 16 distinct local minima, with only 81 of 200 starts converging (40.5\%) and the global minimum found in just 2.5\% of converged starts. This underscores the importance of using multiple random starts and verifying convergence, particularly when using criteria known to be prone to local minima such as simplimax. The global minimum (f = 0.01080) is clearly separated from the other local minima, with the next best solution having a criterion value three times larger. The sorted loadings plot shows that the local minima produce substantially different factor structures, not merely permutations or sign flips of the same solution. %------------------------------------------------------------------- \section*{Examining Individual Solutions} %------------------------------------------------------------------- Each element of \texttt{res\_ccai\$minima} contains a full \texttt{GPArotation} object in \texttt{result}, so the standard \texttt{print} and \texttt{summary} methods work directly. \begin{Scode}{results=verbatim} # Print the most common solution print(res_ccai$minima[[1]]$result) \end{Scode} Accessing any specific solution is straightforward. For example, to print the solution corresponding to row 3 of the summary table: \begin{Scode}{results=verbatim} # Print solution in row 3 of the summary print(res_ccai$minima[[3]]$result, digits = 2) \end{Scode} More generally, to print the solution in row \texttt{i}: \begin{Scode}{results=verbatim} i <- 3 print(res_ccai$minima[[i]]$result, digits = 2) \end{Scode} The row number in the summary table corresponds directly to the index in \texttt{res\_ccai\$minima}. Row 1 is always the most common solution, and the global minimum is identified by \texttt{res\_ccai\$summary\$isGlobal}. \begin{Scode}{results=verbatim} # Print the global minimum using the GPArotation S3 print method global <- which(res_ccai$summary$isGlobal) print(res_ccai$minima[[global]]$result, digits = 2) \end{Scode} \begin{Scode}{results=verbatim} # Summary with structure matrix for oblique solution summary(res_ccai$minima[[global]]$result, Structure = TRUE, digits = 2) \end{Scode} Solutions with small \texttt{deltaF} values may produce loading matrices that are very similar to the global minimum after sorting. Solutions with large \texttt{deltaF} values are likely to produce meaningfully different loading patterns and warrant careful examination. %------------------------------------------------------------------- \section*{Visualizing All Minima} %------------------------------------------------------------------- The sorted absolute loadings plot is a powerful tool for comparing all retained minima at once. Each line represents one distinct solution. Lines that overlap closely indicate practically equivalent solutions; lines that diverge indicate qualitatively different solutions. The following plotting function is also used in the main \texttt{GPA1guide} vignette. It is reproduced here so that this vignette is self-contained. First define the plotting function: \begin{Scode} plotSortedLoadings <- function(..., labels = NULL, col = NULL, main = "Sorted Absolute Loadings", ylab = "Absolute loading", xlab = "Rank") { solutions <- list(...) for (i in seq_along(solutions)) { if (!inherits(solutions[[i]], "GPArotation")) stop("Argument ", i, " is not a GPArotation object.") } n <- length(solutions) if (is.null(labels)) labels <- paste("Solution", seq_len(n)) if (is.null(col)) col <- palette.colors(n, palette = "Okabe-Ito") sorted_loadings <- lapply(solutions, function(x) sort(abs(as.vector(x$loadings)), decreasing = FALSE)) all_values <- unlist(sorted_loadings) max_len <- max(sapply(sorted_loadings, length)) plot(NULL, xlim = c(1, max_len), ylim = c(0, max(all_values)), main = main, xlab = xlab, ylab = ylab, las = 1) abline(h = seq(0, 1, by = 0.1), col = "grey90", lty = 1) for (i in seq_len(n)) { lines(seq_along(sorted_loadings[[i]]), sorted_loadings[[i]], col = col[i], lwd = 2) points(seq_along(sorted_loadings[[i]]), sorted_loadings[[i]], col = col[i], pch = 19, cex = 0.6) } legend("topleft", legend = labels, col = col, lwd = 2, pch = 19, bty = "n") invisible(sorted_loadings) } \end{Scode} Then plot all retained minima: \begin{Scode}{fig=TRUE} do.call(plotSortedLoadings, c(lapply(res_ccai$minima, function(x) x$result), list(labels = paste0("Min ", res_ccai$summary$minimum, " (f=", round(res_ccai$summary$f, 4), ", n=", res_ccai$summary$count, ")")))) \end{Scode} Lines that are visually indistinguishable correspond to solutions that are practically equivalent regardless of their \texttt{deltaF}. Lines that diverge clearly represent genuinely different factor structures that merit substantive interpretation. %------------------------------------------------------------------- \section*{Practical Guidance} %------------------------------------------------------------------- \begin{itemize} \item \textbf{How many random starts?} For criteria that tend to have many local minima, 500 or more starts are recommended. The goal is for the proportions in the summary to stabilize --- if running 1000 instead of 500 starts changes the proportions substantially, more starts are needed. \item \textbf{Setting minimumInclusion.} With 100 starts, a value of 2 is reasonable. With 500 starts, use 5 or 10. The goal is to distinguish genuine local minima from numerical noise. \item \textbf{Interpreting deltaF.} There is no universal threshold for what constitutes a ``meaningful'' difference in criterion value. Solutions with \texttt{deltaF} $< 0.001$ are typically negligible. Solutions with \texttt{deltaF} $> 0.01$ may produce visibly different loading patterns. \item \textbf{When the global minimum has low proportion.} If the global minimum is found by fewer than 20\% of converged starts, the criterion landscape is complex and the solution may not be stable. Consider trying a different rotation criterion or increasing the number of random starts. \item \textbf{Comparing criteria.} Running \texttt{GPFallMinima} with different rotation criteria on the same dataset can reveal which criteria produce stable solutions and which are prone to local minima for a given data structure. \end{itemize} %------------------------------------------------------------------- \section*{Further Resources} %------------------------------------------------------------------- For detailed discussion of local minima in factor rotation and their implications for substantive interpretation, see \cite{nguwall}. For investigation of local minima using the \textit{fungible} package, see the \texttt{faMain} function. The \textit{psych} package provides \texttt{faRotations} for similar diagnostics. The \texttt{randStartChar} element returned by standard \texttt{GPArotation} functions provides a quick summary of random start results without retaining individual solutions. For routine use, \texttt{randStartChar} is sufficient; \texttt{GPFallMinima} is intended for deeper diagnostic investigation. \begin{thebibliography}{} \bibitem[\protect\citeauthoryear{Bi \& Barchard}{Bi \& Barchard}{2024}]{bibarchard} Bi, Y. and Barchard, K.A. (2024). \newblock Purchasing choices that reduce climate change: An exploratory factor analysis. \newblock \textit{Spectra Undergraduate Research Journal}, \textbf{3}(2), 8--14. \newblock \href{https://doi.org/10.9741/2766-7227.1028} {doi: 10.9741/2766-7227.1028} \bibitem[\protect\citeauthoryear{Mansolf \& Reise}{Mansolf \& Reise}{2016}]{mansreise} Mansolf, M., \& Reise, S. P. (2016). \newblock Exploratory bifactor analysis: The Schmid-Leiman orthogonalization and Jennrich-Bentler analytic rotations. \newblock \textit{Multivariate Behavioral Research}, 51(5), 698--717. \newblock \href{https://doi.org/10.1080/00273171.2016.1215898} {https://doi.org/10.1080/00273171.2016.1215898} \bibitem[\protect\citeauthoryear{Nguyen \& Waller}{Nguyen \& Waller}{2022}]{nguwall} Nguyen, H. V., \& Waller, N. G. (2022). \newblock Local minima and factor rotations in exploratory factor analysis. \newblock \textit{Psychological Methods}. Advance online publication. \newblock \href{https://doi.org/10.1037/met0000467} {https://doi.org/10.1037/met0000467} \end{thebibliography} \end{document}GPArotation/vignettes/GPA3bifactor.Stex0000644000176200001440000004564015174242444017542 0ustar liggesusers%\VignetteIndexEntry{Bifactor Rotation and Reliability Coefficients} %\VignettePackage{GPArotation} %\VignetteDepends{GPArotation} %\VignetteKeyword{factor rotation} %\VignetteKeyword{bifactor} %\VignetteKeyword{omega hierarchical} %\VignetteKeyword{scale development} \documentclass[english, 10pt]{article} \usepackage{hyperref} \usepackage{amsmath} \bibliographystyle{apa} \usepackage{natbib} \usepackage{geometry} \geometry{letterpaper} \begin{document} \SweaveOpts{eval=TRUE, echo=TRUE, results=hide, fig=FALSE} \begin{Scode}{echo=FALSE, results=hide} options(continue=" ") pdf.options(pointsize = 8) library("GPArotation") \end{Scode} \begin{center} \section*{Bifactor Rotation and Reliability Coefficients \\ ~~\\ The \texttt{GPArotation} Package} \end{center} \begin{center} Author: Coen A. Bernaards \end{center} Bifactor models represent a factor structure where each item loads on one general factor that influences all items, plus at most one group-specific factor. They are widely used in scale development and psychometric research to investigate the relative contributions of general and specific sources of variance. This vignette illustrates how \texttt{GPArotation} can support bifactor analyses and how the results may inform decisions about total scores and subscales. The tools presented here --- bifactor rotation, omega hierarchical, and omega total --- are best understood as aids to thinking rather than as decision procedures. Their interpretation always depends on substantive theory, the purpose of the measurement, and the broader research context. %------------------------------------------------------------------- \section*{Bifactor Rotation in GPArotation} %------------------------------------------------------------------- Two bifactor rotation criteria are available: \begin{itemize} \item \texttt{bifactorT} --- orthogonal bifactor rotation. The general factor and group factors are uncorrelated. \item \texttt{bifactorQ} --- oblique bifactor rotation (biquartimin). The general factor and group factors may be correlated. \end{itemize} Both treat the \emph{first column} of the loading matrix as the general factor and rotate the remaining columns as group factors. The general factor column should correspond to the dominant factor in the unrotated solution. Use \texttt{sortLoadings = FALSE} when printing to preserve the general factor in column 1 --- the default sorting by variance explained may reorder the factors and obscure the bifactor structure. \begin{Scode}{results=verbatim} data("WansbeekMeijer", package = "GPArotation") fa.unrotated <- factanal(factors = 3, covmat = NetherlandsTV, rotation = "none") # Orthogonal bifactor rotation res.bifT <- bifactorT(loadings(fa.unrotated)) print(res.bifT, sortLoadings = FALSE, digits = 3) # Oblique bifactor rotation res.bifQ <- bifactorQ(loadings(fa.unrotated)) print(res.bifQ, sortLoadings = FALSE, digits = 3) # Structure matrix for oblique solution summary(res.bifQ, Structure = TRUE) \end{Scode} The pattern matrix from \texttt{bifactorT} shows loadings on the general factor (column 1) and group factors (remaining columns). Items with high general factor loadings and near-zero group factor loadings are well represented by the total score. Items with substantial group factor loadings may be carrying domain-specific variance beyond the general factor. For a detailed treatment of bifactor rotation see \cite{jennbent}. A comparison of exploratory bifactor analysis algorithms is provided in \cite{garzon}. %------------------------------------------------------------------- \section*{Omega Hierarchical} %------------------------------------------------------------------- Omega hierarchical ($\omega_h$) quantifies how much of the total score variance may be attributable to the general factor. It is computed directly from the bifactor rotation result: \begin{equation} \omega_h = \frac{(\sum_i \lambda_{gi})^2} {(\sum_i \lambda_{gi})^2 + \sum_i \sum_j \lambda_{sij}^2 + \sum_i \theta_{ii}} \end{equation} where $\lambda_{gi}$ are the general factor loadings, $\lambda_{sij}$ are the group factor loadings, and $\theta_{ii} = 1 - \sum_j \lambda_{ij}^2$ are the model-implied unique variances. \begin{Scode} omega_h <- function(bifactor_result) { # Compute omega hierarchical from a GPArotation bifactor solution. # Args: # bifactor_result : a GPArotation object from bifactorT or bifactorQ L <- loadings(bifactor_result) lg <- L[, 1] # general factor loadings Ls <- L[, -1] # group factor loadings theta <- 1 - rowSums(L^2) # model-implied unique variances sum(lg)^2 / (sum(lg)^2 + sum(Ls^2) + sum(theta)) } # Omega total: proportion of total score variance due to all common factors. # Requires the observed or population correlation matrix R. omega_t <- function(bifactor_result, R) { L <- loadings(bifactor_result) R_hat <- L %*% t(L) sum(R_hat) / sum(R) } # Coefficient alpha from a correlation matrix alpha_coef <- function(R) { k <- nrow(R) k / (k - 1) * (1 - sum(diag(R)) / sum(R)) } \end{Scode} The denominator of $\omega_h$ partitions total score variance into three components: variance due to the general factor, variance due to group-specific factors, and measurement error. A higher $\omega_h$ may suggest that the general factor accounts for a larger share of total score variance, which could support the use of a total score as a summary measure --- though this interpretation always depends on the substantive context. %------------------------------------------------------------------- \section*{Comparing Strong and Weak General Factors} %------------------------------------------------------------------- To illustrate how $\omega_h$ varies with the relative strength of the general and group factors, we construct two population correlation matrices with known bifactor structure. In Example 1, the general factor is strong (loadings of 0.7) and the group factors are weak (loadings of 0.2). In Example 2, the general factor is weaker (loadings of 0.3) and the group factors are stronger (loadings of 0.6). Both examples use 12 items and 3 group factors of 4 items each. \begin{Scode} # Example 1: Strong general factor (loadings .7), weak group factors (.2) lambda_g1 <- rep(0.7, 12) lambda_s1a <- c(rep(0.2, 4), rep(0.0, 8)) lambda_s1b <- c(rep(0.0, 4), rep(0.2, 4), rep(0.0, 4)) lambda_s1c <- c(rep(0.0, 8), rep(0.2, 4)) L1 <- cbind(lambda_g1, lambda_s1a, lambda_s1b, lambda_s1c) R1 <- L1 %*% t(L1) diag(R1) <- 1 fa1 <- factanal(factors = 4, covmat = R1, rotation = "none") bif1 <- bifactorT(loadings(fa1)) # Example 2: Weaker general factor (loadings .3), stronger group factors (.6) lambda_g2 <- rep(0.3, 12) lambda_s2a <- c(rep(0.6, 4), rep(0.0, 8)) lambda_s2b <- c(rep(0.0, 4), rep(0.6, 4), rep(0.0, 4)) lambda_s2c <- c(rep(0.0, 8), rep(0.6, 4)) L2 <- cbind(lambda_g2, lambda_s2a, lambda_s2b, lambda_s2c) R2 <- L2 %*% t(L2) diag(R2) <- 1 fa2 <- factanal(factors = 4, covmat = R2, rotation = "none") bif2 <- bifactorT(loadings(fa2)) \end{Scode} \begin{Scode}{results=verbatim} cat("Example 1 - Strong general factor:\n") cat(" alpha =", round(alpha_coef(R1), 3), "\n") cat(" omega_t =", round(omega_t(bif1, R1), 3), "\n") cat(" omega_h =", round(omega_h(bif1), 3), "\n\n") cat("Example 2 - Weaker general factor:\n") cat(" alpha =", round(alpha_coef(R2), 3), "\n") cat(" omega_t =", round(omega_t(bif2, R2), 3), "\n") cat(" omega_h =", round(omega_h(bif2), 3), "\n") \end{Scode} The three coefficients address related but distinct questions: \begin{itemize} \item $\alpha$ estimates the proportion of total score variance that may be attributable to common factors, under the assumption of essentially tau-equivalent items (equal factor loadings). When this assumption does not hold well in practice, $\alpha$ may overestimate or underestimate reliability --- something worth keeping in mind when interpreting it. \item $\omega_t$ relaxes the tau-equivalence assumption and estimates the proportion of total score variance that may be due to all common factors combined --- general and group-specific. It may provide a more nuanced picture of reliability than $\alpha$ in some situations, though both are model-dependent estimates. Note that $\omega_t$ requires the observed or population correlation matrix in addition to the bifactor solution. \item $\omega_h$ focuses on the general factor only and may help address the question of how much of the total score variance could reflect the single construct the scale is primarily intended to measure. It is one piece of evidence relevant to construct validity, not a definitive answer. \end{itemize} The gap $\omega_t - \omega_h$ represents the proportion of total score variance that may be attributable to group-specific factors. In Example 1 this gap is small, suggesting the group factors add little beyond the general factor and the scale may be reasonably close to unidimensional. In Example 2 the gap is larger, which could suggest the group factors are contributing meaningfully and that subscale scores might be worth examining alongside the total score. Whether to act on this is a substantive judgment that goes beyond the numbers alone. %------------------------------------------------------------------- \section*{Applied Example: CCAI Climate-Friendly Purchasing Choices domain} %------------------------------------------------------------------- To illustrate how these tools might inform scale interpretation in practice, we use the Climate-Friendly Purchasing Choices domain of the Climate Change Action Inventory (CCAI), analyzed by Bi and Barchard (2024). The scale has 14 items measuring the frequency of climate-friendly purchasing behaviors, with three factors identified via direct oblimin rotation: Choosing Sustainable Options, Supporting Collective Action, and Avoiding Buying New. The three factors had strong inter-correlations (0.53--0.59), which raises the question of whether a general factor might underlie all 14 items. Bi and Barchard (2024) used \texttt{psych::principal} for component extraction with oblimin rotation, which calls \texttt{GPArotation} internally. Table 2 of the paper reports the pattern matrix from this analysis, despite being labeled ``Factor Structure.'' The observed 14$\times$14 correlation matrix and published pattern matrix are included in the package as \texttt{CCAI\_R} and \texttt{CCAI\_pattern} respectively (see \texttt{?CCAI}). The published pattern matrix can be reproduced from the correlation matrix via eigendecomposition followed by oblimin rotation --- see the examples in \texttt{?CCAI} for the complete code. \subsection*{Data} \begin{Scode} data("CCAI", package = "GPArotation") \end{Scode} \begin{Scode}{results=verbatim} cat("Range of observed correlations:\n") cat(" Min:", round(min(CCAI_R[lower.tri(CCAI_R)]), 3), "\n") cat(" Max:", round(max(CCAI_R[lower.tri(CCAI_R)]), 3), "\n") \end{Scode} \subsection*{Bifactor Rotation} We extract three unrotated factors from the observed correlation matrix and apply \texttt{bifactorT}: \begin{Scode}{results=verbatim} fa_unrotated <- factanal(factors = 3, covmat = CCAI_R, n.obs = 461, rotation = "none") bif <- bifactorT(loadings(fa_unrotated)) print(bif, sortLoadings = FALSE, digits = 3) \end{Scode} The general factor (Factor 1) loadings range from 0.444 to 0.854 across all 14 items. Only one item --- Item 2 (``Use borrowed/rented/digital rather than buying'') --- falls below 0.50, suggesting it may be the most behaviorally distinct item in the scale. The group factors contribute modest additional structure, with the Avoiding Buying New items (1, 2, 3, 4) showing the clearest group factor pattern beyond the general factor. The variance explained by each factor may be informative: the general factor accounts for approximately 56.3\% of item variance, while the two group factors account for 6.5\% and 7.9\% respectively, for a total of 70.7\%. The dominance of the general factor relative to the group factors is consistent with the high $\omega_h$ of 0.946 calculated below. \subsection*{Reliability Coefficients} \begin{Scode}{results=verbatim} cat("alpha =", round(alpha_coef(CCAI_R), 3), "\n") cat("omega_t =", round(omega_t(bif, CCAI_R), 3), "\n") cat("omega_h =", round(omega_h(bif), 3), "\n") cat("gap (omega_t - omega_h) =", round(omega_t(bif, CCAI_R) - omega_h(bif), 3), "\n") \end{Scode} All three coefficients are high and close to each other. The small gap between $\omega_t$ and $\omega_h$ ($\approx$ 0.019) could suggest that the group factors contribute little unique variance beyond the general factor. \subsection*{Partitioning Total Score Variance} \begin{Scode} omega_h_by_group <- function(bifactor_result, R) { L <- loadings(bifactor_result) lg <- L[, 1] Ls <- L[, -1] theta <- 1 - rowSums(L^2) denom <- sum(lg)^2 + sum(Ls^2) + sum(theta) cat("Variance partition:\n") cat(" General factor: ", round(sum(lg)^2 / denom, 3), "\n") for (j in 1:ncol(Ls)) cat(" Group factor", j + 1, ": ", round(sum(Ls[, j]^2) / denom, 3), "\n") cat(" Measurement error: ", round(sum(theta) / denom, 3), "\n") cat(" Total (omega_t): ", round(omega_t(bifactor_result, R), 3), "\n") } \end{Scode} \begin{Scode}{results=verbatim} omega_h_by_group(bif, CCAI_R) \end{Scode} The partition may be informative here. Approximately 94.6\% of total score variance could be attributable to the general factor, with the two group factors together contributing around 1.8\% and measurement error around 3.6\%. This pattern could suggest that the 14-item total score is capturing a single dominant construct --- something like general climate-conscious purchasing behavior --- with the three subscales adding relatively little unique psychometric information beyond that. \subsection*{What This May Mean} Bi and Barchard (2024) identified three theoretically meaningful subscales and noted their strong inter-correlations. The bifactor analysis here offers one additional perspective: the subscales may be useful for targeting specific interventions (for example, campaigns to encourage buying used, or to support collective action), but from a psychometric standpoint the total score may capture most of the reliable variance in climate-friendly purchasing behavior. This does not mean the subscales are without value --- substantive and practical considerations matter as much as psychometric ones. A researcher interested in behavior change might find the subscale distinctions more actionable than a total score, regardless of what the reliability coefficients suggest. These analyses are tools for thinking through the structure of a scale, not verdicts on how it should be used. %------------------------------------------------------------------- \section*{Practical Considerations} %------------------------------------------------------------------- \begin{itemize} \item The general factor must be in the first column of the bifactor solution. Use \texttt{sortLoadings = FALSE} when printing to preserve this ordering. \item $\omega_h$ uses model-implied unique variances ($\theta_{ii} = 1 - \sum_j \lambda_{ij}^2$). If the observed correlation matrix is available, unique variances can be estimated as $\theta_{ii} = R_{ii} - \hat{R}_{ii}$ where $\hat{R} = LL^T$. \item $\omega_h > 0.80$ has been suggested as supporting total score interpretation as a reasonably unidimensional construct \citep{reise2012}, though this threshold should not be applied mechanically. \item $\omega_h < 0.60$ may suggest that subscale scores are worth examining alongside the total score, depending on the context. \item Values between 0.60 and 0.80 require judgment --- examine the general factor loadings for uniformity and consider the theoretical rationale for the subscales. \item These coefficients are tools for thinking, not oracles. They may raise useful questions and provide one perspective on scale structure, but their interpretation always depends on the specific context, the theoretical framework, and the intended purpose of the measurement. \end{itemize} %------------------------------------------------------------------- \section*{Further Resources} %------------------------------------------------------------------- For detailed treatment of bifactor models and their applications see \cite{jennbent} and \cite{mansreise}. For a comparison of exploratory bifactor analysis algorithms see \cite{garzon}. For background on omega coefficients and their interpretation see \cite{reise2012}. The \texttt{psych} package provides additional tools for bifactor analysis and reliability estimation, including \texttt{omega()} for computing omega coefficients directly from a correlation matrix. For the main \texttt{GPArotation} usage guide see \texttt{vignette("GPA1guide", package = "GPArotation")}. For local minima diagnostics see \texttt{vignette("GPA2local", package = "GPArotation")}. \begin{thebibliography}{} \bibitem[\protect\citeauthoryear{Bi \& Barchard}{Bi \& Barchard}{2024}]{bibarchard} Bi, Y. and Barchard, K.A. (2024). \newblock Purchasing choices that reduce climate change: An exploratory factor analysis. \newblock \textit{Spectra Undergraduate Research Journal}, \textbf{3}(2), 8--14. \newblock \href{https://doi.org/10.9741/2766-7227.1028} {doi: 10.9741/2766-7227.1028} \bibitem[\protect\citeauthoryear{Garcia-Garzon, Abad \& Garrido} {Garcia-Garzon et al.}{2021}]{garzon} Garcia-Garzon, E., Abad, F.J., and Garrido, L.E. (2021). \newblock On omega hierarchical estimation: A comparison of exploratory bi-factor analysis algorithms. \newblock \textit{Multivariate Behavioral Research}, \textbf{56}(1), 101--119. \newblock \href{https://doi.org/10.1080/00273171.2020.1736977} {doi: 10.1080/00273171.2020.1736977} \bibitem[\protect\citeauthoryear{Jennrich \& Bentler}{Jennrich \& Bentler}{2011}]{jennbent} Jennrich, R.I. and Bentler, P.M. (2011). \newblock Exploratory bi-factor analysis. \newblock \textit{Psychometrika}, \textbf{76}(4), 537--549. \newblock \href{https://doi.org/10.1007/s11336-011-9218-4} {doi: 10.1007/s11336-011-9218-4} \bibitem[\protect\citeauthoryear{Mansolf \& Reise}{Mansolf \& Reise}{2016}]{mansreise} Mansolf, M. and Reise, S.P. (2016). \newblock Exploratory bifactor analysis: The Schmid-Leiman orthogonalization and Jennrich-Bentler analytic rotations. \newblock \textit{Multivariate Behavioral Research}, \textbf{51}(5), 698--717. \newblock \href{https://doi.org/10.1080/00273171.2016.1215898} {doi: 10.1080/00273171.2016.1215898} \bibitem[\protect\citeauthoryear{Reise}{Reise}{2012}]{reise2012} Reise, S.P. (2012). \newblock The rediscovery of bifactor measurement models. \newblock \textit{Multivariate Behavioral Research}, \textbf{47}(5), 667--696. \newblock \href{https://doi.org/10.1080/00273171.2012.715555} {doi: 10.1080/00273171.2012.715555} \end{thebibliography} \end{document}GPArotation/vignettes/GPA1guide.Stex0000644000176200001440000015572715174242453017054 0ustar liggesusers%\VignetteEncoding{UTF-8} %\VignetteIndexEntry{Gradient Projection Factor Rotation} %\VignettePackage{GPArotation} %\VignetteDepends{GPArotation} %\VignetteKeyword{factor rotation} %\VignetteKeyword{gradient projection} %\VignetteKeyword{varimax} %\VignetteKeyword{oblimin} \documentclass[english, 10pt]{article} \usepackage{hyperref} \bibstyle{apacite} \bibliographystyle{apa} \usepackage{natbib} \usepackage{geometry} \geometry{letterpaper} \begin{document} \SweaveOpts{eval=TRUE,echo=TRUE,results=hide,fig=FALSE} \begin{Scode}{echo=FALSE,results=hide} options(continue=" ") pdf.options(pointsize = 8) \end{Scode} \begin{center} \section*{Gradient Projection Factor Rotation \\ ~~\\The \texttt{GPArotation} Package} \end{center} \begin{center} Author: Coen A. Bernaards \end{center} The \texttt{GPArotation} package provides gradient projection algorithms for orthogonal and oblique rotation of factor loading matrices in exploratory factor analysis. It implements a comprehensive set of rotation criteria and supports multiple random starts to avoid local minima. This vignette introduces the main functionality of the package, with examples of common use cases. For a complete list of available rotation criteria and their references, see the Rotation Criteria Reference section at the back of this document. In R, the functions in this package are made available with \begin{Scode} library("GPArotation") \end{Scode} The most complete reference for the software is \cite{gpa.rotate}. The original 2005 implementations in four platforms are preserved for historical reference: \href{https://drive.google.com/file/d/1TetEn1TGLul6FRTlIwXx3nbSQOGlifXi/view?usp=sharing} {MATLAB code}, \href{https://drive.google.com/file/d/1RryvIoTib0d9SIFm9x1fdDFPfjzsh49e/view?usp=sharing} {Splus code}, \href{https://drive.google.com/file/d/1t5Bw8KLlIGrSr3TNy0rJjHfsU6nOlIpq/view?usp=sharing} {SAS code}, and \href{https://drive.google.com/file/d/1JGvSxiphNhbZhW-GzGXkkNPBFcKyfSZi/view?usp=sharing} {SPSS code}. These implementations predate the R package and reflect the algorithm as originally published. The R package has been updated since then; see the \texttt{NEWS} file for a full history of changes. A clear and accessible introduction to gradient projection algorithms for factor rotation is provided in \cite{mansreise}. %------------------------------------------------------------------- \section*{Basic Usage} %------------------------------------------------------------------- \subsection*{Getting Started} Factor rotation aims to simplify interpretation by rotating the loadings matrix. In practice, most rotations are done by minimizing a criterion function. This package provides algorithms that can minimize any rotation criteria as long as a gradient is available. The loading matrix is typically obtained from a factor analysis routine such as \texttt{factanal}. A rotation is performed by calling the rotation function directly, or by calling one of the wrapper functions \texttt{GPFRSorth} or \texttt{GPFRSoblq} for orthogonal and oblique rotation, respectively. Under the hood, rotations are computed using the Gradient Projection Algorithm, implemented in \texttt{GPForth} for orthogonal rotation and \texttt{GPFoblq} for oblique rotation. These functions were updated in version 2026.4-1 with performance improvements and improved code clarity; results are numerically identical to prior versions. \begin{Scode} data("Harman", package = "GPArotation") # Calling a rotation directly qHarman <- quartimax(Harman8) # Equivalently, via the wrapper function qHarman <- GPFRSorth(Harman8, method = "quartimax") # Two equivalent ways to access the rotated loadings loadings(qHarman) # via extractor function (recommended) qHarman$loadings # via direct list access \end{Scode} The rotated loadings matrix is the pattern matrix. The extractor function \texttt{loadings()} is preferred over direct list access for forward compatibility. \subsection*{Recovery of the Unrotated Loadings Matrix} Recovery of the unrotated loadings matrix is consistent with the definitions used in \cite{gpa.rotate} (page 678). For example, the unrotated matrix $A$ may be recovered as follows. \begin{Scode}{results=verbatim} data("CCAI", package = "GPArotation") y <- factanal(factors = 3, covmat = CCAI_R, n.obs = 461, rotation = "none") y.quart <- quartimax(y$loadings) max(loadings(y.quart) %*% t(y.quart$Th) - loadings(y)) y.obli <- oblimin(y$loadings, normalize = TRUE, randomStarts = 15) max(loadings(y.obli) %*% t(y.obli$Th) - loadings(y)) # last equation on Page 678 max(loadings(y.obli) - loadings(y) %*% solve(t(y.obli$Th))) \end{Scode} By the same definitions, the factor correlation matrix is calculated as \cite{gpa.rotate} (page 695), \begin{Scode}{results=verbatim} y <- factanal(factors = 3, covmat = CCAI_R, n.obs = 461, rotation = "none") y.obli <- oblimin(y$loadings, normalize = TRUE, randomStarts = 15) max(abs(y.obli$Phi - t(y.obli$Th) %*% y.obli$Th)) \end{Scode} \subsection*{Output and Display} The raw output from \texttt{GPArotation} functions returns loadings in the order determined by the algorithm, which depends on the starting rotation matrix. This means that with different random starts, the same solution may appear with factors in a different order or with reversed signs. The \texttt{print} method sorts factors by descending variance explained and adjusts signs so that the dominant loadings are positive, making visual inspection and comparison easier. Importantly, this is a display transformation only --- the underlying object is not modified. \begin{Scode}{results=verbatim} set.seed(334) res <- quartimin(Harman8, normalize = TRUE, randomStarts = 100) # Raw unsorted loadings loadings(res) # Sorted loadings via print (factors reordered and signs adjusted) res.sorted <- print(res) # Once sorted, repeated calls to print are stable max(abs(print(res.sorted)$loadings - res.sorted$loadings)) == 0 # TRUE \end{Scode} \subsection*{Pattern and Structure Matrices} \subsubsection*{Two Interpretations of the Loading Matrix} The loading matrix $\Lambda$ has two complementary interpretations that correspond directly to the pattern and structure matrices in oblique rotation. \textbf{First interpretation: regression.} The conditional expectation $E(X|f) = \mu + \Lambda f$ is the linear regression of $X$ on $f$. The loading $\lambda_{ij}$ is the expected change in item $i$ when factor $j$ is increased by one unit, holding other factors constant. This is the \emph{pattern matrix} --- the regression coefficients of items on factors. \textbf{Second interpretation: correlation.} Under the factor model assumptions, $Cov(X, f) = \Lambda\Phi$. If $X$ is standardized, $Corr(X, f) = \Lambda\Phi$. This is the \emph{structure matrix} --- the correlations between items and factors. Correlations tend to be consistent across studies. When factors are orthogonal ($\Phi = I$) the two interpretations coincide: $\Lambda\Phi = \Lambda$. When factors are oblique the structure matrix $\Lambda\Phi$ inflates the apparent relationships between items and factors through the factor intercorrelations, while the pattern matrix $\Lambda$ shows the unique contribution of each factor net of those intercorrelations. \subsubsection*{Using \texttt{GPArotation} to obtain them} The \texttt{summary} method returns the raw unsorted loadings exactly as produced by the algorithm. For oblique rotations, it also prints the structure matrix (loadings $\times$ $\Phi$) when \texttt{Structure = TRUE} (the default). This is useful for comparing results across software or reproducing published values. \begin{Scode}{results=verbatim} res.obli <- oblimin(Harman8, normalize = TRUE, randomStarts = 100) # Pattern matrix (unsorted) summary(res.obli, Structure = FALSE) # Structure matrix summary(res.obli, Structure = TRUE) \end{Scode} To illustrate the distinction concretely, consider item 1 (row 1) from the oblimin rotation of the Harman 8-variable physical measurements dataset. In the pattern matrix, the loadings are 0.892 on Factor 1 and 0.056 on Factor 2. The pattern coefficient 0.892 is the regression coefficient of item 1 on Factor 1, controlling for Factor 2 --- it represents the unique contribution of Factor 1 to item 1, net of the shared variance between the two factors. The near-zero cross-loading of 0.056 indicates that item 1 is primarily associated with Factor 1 after accounting for factor intercorrelations. In the structure matrix, the same item has loadings of 0.918 on Factor 1 and 0.478 on Factor 2. The structure coefficient 0.478 is the simple correlation between item 1 and Factor 2 --- substantially larger than the pattern cross-loading of 0.056. This inflation occurs because Factor 1 and Factor 2 are correlated, and that correlation carries over into the structure coefficients. An analyst relying solely on the structure matrix might incorrectly conclude that item 1 has a meaningful relationship with Factor 2. In this solution the factor intercorrelation is $\phi = 0.473$. This moderate correlation between the two factors is sufficient to inflate the structure coefficients noticeably --- the cross-loading of item 1 on Factor 2 increases from 0.056 in the pattern matrix to 0.478 in the structure matrix, a difference of 0.422 attributable entirely to the factor intercorrelation. This is why the pattern matrix is generally preferred for interpretation in oblique rotation: it shows the unique contribution of each factor to each item, net of the shared variance among factors. The structure matrix is a useful diagnostic check --- large discrepancies between pattern and structure coefficients signal that factor intercorrelations are substantially inflating apparent relationships. The relationship between pattern and structure coefficients can be visualized by plotting one against the other for each factor. Points on the identity line (dashed) have equal pattern and structure coefficients --- no inflation from factor intercorrelations. Points above the line have structure coefficients inflated by the factor intercorrelations. \begin{Scode} plotPatternStructure <- function(pattern, structure, labels = NULL, main = "Pattern vs Structure") { k <- ncol(pattern) col <- palette.colors(k, palette = "Okabe-Ito") par(mfrow = c(1, k)) for (j in 1:k) { lims <- range(c(pattern[, j], structure[, j])) plot(pattern[, j], structure[, j], xlim = lims, ylim = lims, xlab = "Pattern loading", ylab = "Structure loading", main = paste(if (!is.null(labels)) labels[j] else paste("Factor", j)), pch = 19, col = col[j]) abline(0, 1, lty = 2, col = "grey60") abline(h = 0, col = "grey80") abline(v = 0, col = "grey80") } } \end{Scode} \begin{center} \begin{Scode}{fig=TRUE, echo=FALSE, width=4, height=2.5} res.obli.s <- print(res.obli) Pattern <- loadings(res.obli.s) Structure <- Pattern %*% res.obli.s$Phi plotPatternStructure(Pattern, Structure, labels = c("Factor 1", "Factor 2")) \end{Scode} \end{center} With a factor intercorrelation of $\phi = 0.473$, the structure coefficients are systematically larger than the pattern coefficients, particularly for items with substantial loadings on both factors. The further a point lies above the identity line, the more the factor intercorrelation is inflating the apparent relationship between that item and the factor. %------------------------------------------------------------------- \section*{Random Starts} %------------------------------------------------------------------- \subsection*{Using Random Starts} For some rotation criteria local minima may exist, meaning the algorithm may converge to different solutions depending on the starting rotation matrix. To explore the solution space, the \texttt{randomStarts} argument is available in all rotation functions. The returned object contains the rotated loadings matrix with the lowest criterion value among all attempted starts. While the lowest local minimum found is likely the global minimum, this cannot be guaranteed. \begin{Scode} data(Thurstone, package = "GPArotation") infomaxQ(box26, randomStarts = 100) # 100 random starts infomaxQ(box26, Tmat = Random.Start(3)) # single random start infomaxQ(box26, randomStarts = 1) # also a single random start \end{Scode} For a detailed discussion of local minima in factor rotation, consult \cite{nguwall}. Additional algorithmic considerations are in \cite{gpa.rotate} (page 680). \subsection*{Assessing Local Minima with Random Start Diagnostics} When \texttt{randomStarts} $> 1$, the output includes a \texttt{randStartChar} vector summarizing the results across all starts. The four elements are: \begin{itemize} \item \texttt{randomStarts}: number of random starts attempted \item \texttt{Converged}: number of starts that converged \item \texttt{atMinimum}: number of starts that converged to the same lowest criterion value \item \texttt{localMins}: number of distinct local minima found \end{itemize} If \texttt{atMinimum} equals \texttt{randomStarts}, all starts found the same solution --- strong evidence that the global minimum has been found. If \texttt{localMins} is large relative to \texttt{randomStarts}, the criterion landscape is complex and more starts are advisable. If the \texttt{Converged} count is low, the tolerance \texttt{eps} or maximum iterations \texttt{maxit} may need adjustment. \begin{Scode}{results=verbatim} res <- geominQ(box26, normalize = TRUE, randomStarts = 100) res$randStartChar # Criterion value at best solution res$Table[nrow(res$Table), "f"] \end{Scode} More detailed methods of investigation local minima, including the \texttt{GPFallMinima} function, are described in the vignette \texttt{vignette("GPA2local", package = "GPArotation")}. The \textit{fungible} package has options for assessing local minima using the \texttt{faMain} function, and the \textit{psych} package using \texttt{faRotations}. \subsection*{The Rotation Objective Function Landscape} For two-factor orthogonal rotation, every rotation matrix is parameterized by a single angle $\theta \in [0, 2\pi)$: \[ T(\theta) = \left( \begin{array}{cc} \cos\theta & \sin\theta \\ -\sin\theta & \cos\theta \end{array} \right) \] This means the objective function $f$ can be plotted as a function of $\theta$, giving a complete picture of the rotation landscape --- all local and global minima, and how flat or sharp they are. The following function computes and plots $f(\theta)$ for $n$ evenly spaced angles: \begin{Scode} plotRotationLandscape <- function(A, method = "quartimax", n = 1000, main = NULL, ...) { # Plot the objective function landscape for 2-factor orthogonal rotation. # For 2 factors, all orthogonal rotations are parameterized by a single # angle theta in [0, 2*pi), giving a clean 1D landscape. # # Args: # A : a 2-factor unrotated loading matrix # method : rotation criterion (default "quartimax") # n : number of angles to evaluate (default 1000) # main : plot title (default: "Rotation landscape: ") # ... : additional arguments passed to the vgQ criterion function if (ncol(A) != 2) stop("plotRotationLandscape only works for 2-factor solutions.") vgQfun_fn <- get(paste("vgQ", method, sep = "."), envir = asNamespace("GPArotation")) if (is.null(main)) main <- paste("Rotation landscape:", method) theta <- seq(0, 2 * pi, length.out = n) f_vals <- numeric(n) for (i in seq_along(theta)) { Tmat <- matrix(c( cos(theta[i]), sin(theta[i]), -sin(theta[i]), cos(theta[i])), 2, 2) L <- A %*% Tmat VgQ <- do.call(vgQfun_fn, append(list(L), list(...))) f_vals[i] <- VgQ$f } # Find global minimum min_idx <- which.min(f_vals) plot(theta, f_vals, type = "l", lwd = 2, main = main, xlab = expression(theta ~ "(radians)"), ylab = "f", xaxt = "n") axis(1, at = c(0, pi/2, pi, 3*pi/2, 2*pi), labels = c("0", expression(pi/2), expression(pi), expression(3*pi/2), expression(2*pi))) abline(h = f_vals[min_idx], col = "grey80", lty = 2) points(theta[min_idx], f_vals[min_idx], col = "tomato", pch = 19, cex = 1.5) text(theta[min_idx], f_vals[min_idx], labels = paste0("min f = ", round(f_vals[min_idx], 4)), pos = 4, cex = 0.8) invisible(data.frame(theta = theta, f = f_vals)) } \end{Scode} The following example compares four rotation criteria on the Harman 8-variable physical measurements dataset: \begin{Scode} data(Harman, package = "GPArotation") \end{Scode} \begin{Scode}{fig=TRUE} par(mfrow = c(2, 2)) plotRotationLandscape(Harman8, method = "quartimax") plotRotationLandscape(Harman8, method = "varimax") plotRotationLandscape(Harman8, method = "bentler") plotRotationLandscape(Harman8, method = "entropy") \end{Scode} \subsection*{Interpreting the Landscape: Symmetry vs Genuine Local Minima} An important subtlety when interpreting rotation landscapes is that not all minima represent genuinely different factor structures. For a two-factor solution, the rotation landscape always contains at least 4 equivalent minima due to the inherent symmetry of factor analysis: \begin{itemize} \item \textbf{Sign flips}: flipping the sign of a factor column gives an equivalent solution. With two factors there are $2^2 = 4$ sign-flip combinations, each producing an equivalent minimum. \item \textbf{Column permutations}: swapping the two factors gives an equivalent solution, adding further symmetry. \end{itemize} Combined, a two-factor solution has at least 4 symmetry-equivalent minima in $[0, 2\pi)$. Any minima beyond these 4 represent genuinely different factor structures --- true local minima in the optimization sense. The following example illustrates this for the simplimax criterion with \texttt{k = 4}, which produces multiple local minima on the Harman 8-variable dataset: \begin{Scode}{fig=TRUE} res <- plotRotationLandscape(Harman8, method = "simplimax", k = 4) # Find all local minima by sign changes in the discrete derivative df <- diff(res$f) local_mins <- which(df[-length(df)] < 0 & df[-1] > 0) # Mark all local minima on the existing plot points(res$theta[local_mins], res$f[local_mins], col = "steelblue", pch = 19, cex = 0.8) legend("topright", legend = c("global minimum", "local minima"), col = c("tomato", "steelblue"), pch = 19, bty = "n", cex = 0.8) \end{Scode} \begin{Scode}{results=verbatim} cat("Total minima found: ", length(local_mins), "\n") cat("Expected due to symmetry: ", 4, "\n") cat("Approximate genuine local minima:", max(0, length(local_mins) - 4), "\n") \end{Scode} The \texttt{k} argument controls how many near-zero loadings simplimax targets. Smaller values of \texttt{k} create a rougher objective function landscape with more local minima, while larger values (up to \texttt{nrow(A)}) produce smoother landscapes. Criteria such as quartimax and varimax on well-structured data typically show exactly 4 minima --- all symmetry-equivalent. Criteria prone to local minima, such as simplimax and geomin, show additional minima beyond the symmetry baseline. This is precisely why random starts are important: without them, the algorithm may converge to a symmetry-equivalent solution or a genuine local minimum rather than the global minimum. The rotation landscape visualization is only available for two-factor solutions. For $k > 2$ factors the rotation space is $(k^2 - k)/2$-dimensional and cannot be visualized as a simple curve. For higher-dimensional problems, the \texttt{GPFallMinima} function described in the \texttt{GPA2local} vignette provides an alternative approach to exploring the solution space. \subsection*{Comparing Rotation Criteria Visually} Different rotation criteria can produce noticeably different loading patterns. A useful way to compare solutions is to make a bar graph of the absolute loadings sorted by magnitude for each factor. The following example compares quartimax and oblimin rotation of the Harman 8-variable physical measurements dataset. \begin{Scode}{fig=TRUE} data(Harman, package = "GPArotation") res.quart <- quartimax(Harman8) res.oblimin <- oblimin(Harman8) L.quart <- abs(loadings(res.quart)) L.oblimin <- abs(loadings(res.oblimin)) ord.quart <- order(L.quart[, 1], decreasing = TRUE) ord.oblimin <- order(L.oblimin[, 1], decreasing = TRUE) par(mfrow = c(1, 2), mar = c(5, 4, 4, 2)) barplot(t(L.quart[ord.quart, ]), beside = TRUE, ylim = c(0, 1), main = "Quartimax", ylab = "Absolute loading", xlab = "Variable (sorted by Factor 1)", legend.text = c("Factor 1", "Factor 2"), args.legend = list(x = "topright"), col = c("steelblue", "tomato")) barplot(t(L.oblimin[ord.oblimin, ]), beside = TRUE, ylim = c(0, 1), main = "Oblimin", ylab = "Absolute loading", xlab = "Variable (sorted by Factor 1)", legend.text = c("Factor 1", "Factor 2"), args.legend = list(x = "topright"), col = c("steelblue", "tomato")) \end{Scode} Quartimax tends to produce a general factor with high loadings on all variables, while oblimin allows factors to be correlated and typically produces a cleaner simple structure. The sorted absolute loading plot makes these differences immediately visible. \subsection*{Sorted Absolute Loadings Plot} A useful way to compare the sparsity profile of different rotation solutions is to plot all absolute loadings sorted from smallest to largest. In a rotation with good simple structure, most loadings are near zero with a sharp upturn at the right --- indicating that a few large loadings dominate. Comparing this profile across rotation criteria makes differences in simplicity and sparsity immediately visible. The following function plots sorted absolute loadings for one or more \texttt{GPArotation} objects on a single figure. \begin{Scode}{echo=TRUE, eval=TRUE} plotSortedLoadings <- function(..., labels = NULL, col = NULL, main = "Sorted Absolute Loadings", ylab = "Absolute loading", xlab = "Rank") { # Plot sorted absolute loadings for one or more GPArotation objects. # Multiple solutions are overlaid on a single plot for comparison. # Loadings are sorted from smallest to largest (left to right). # # Args: # ... : one or more GPArotation objects # labels : character vector of legend labels (default: "Solution 1", etc.) # col : character vector of colors (default: auto-assigned) # main : plot title # ylab : y-axis label # xlab : x-axis label solutions <- list(...) for (i in seq_along(solutions)) { if (!inherits(solutions[[i]], "GPArotation")) stop("Argument ", i, " is not a GPArotation object.") } n <- length(solutions) if (is.null(labels)) labels <- paste("Solution", seq_len(n)) if (is.null(col)) col <- palette.colors(n, palette = "Okabe-Ito") sorted_loadings <- lapply(solutions, function(x) sort(abs(as.vector(x$loadings)), decreasing = FALSE)) all_values <- unlist(sorted_loadings) max_len <- max(sapply(sorted_loadings, length)) plot(NULL, xlim = c(1, max_len), ylim = c(0, max(all_values)), main = main, xlab = xlab, ylab = ylab, las = 1) abline(h = seq(0, 1, by = 0.1), col = "grey90", lty = 1) for (i in seq_len(n)) { lines(seq_along(sorted_loadings[[i]]), sorted_loadings[[i]], col = col[i], lwd = 2) points(seq_along(sorted_loadings[[i]]), sorted_loadings[[i]], col = col[i], pch = 19, cex = 0.6) } legend("topleft", legend = labels, col = col, lwd = 2, pch = 19, bty = "n") invisible(sorted_loadings) } # Example data(Harman, package = "GPArotation") res.quart <- quartimax(Harman8) res.oblimin <- oblimin(Harman8) res.geomin <- geominT(Harman8) \end{Scode} The following example compares quartimax, oblimin, and geomin rotation on the Harman 8-variable physical measurements dataset. \begin{center} \begin{Scode}{fig=TRUE, echo=FALSE, width=4, height=4} plotSortedLoadings(res.quart, res.oblimin, res.geomin, labels = c("Quartimax", "Oblimin", "Geomin")) \end{Scode} \end{center} A flat profile at the left indicates many near-zero loadings --- a hallmark of simple structure. A gradual curve with no clear elbow suggests the criterion is not achieving strong separation between large and small loadings. Criteria that differ substantially in their sparsity assumptions, such as quartimax (which tends toward a general factor) versus oblimin (which allows correlated factors with cleaner simple structure), will produce visibly different profiles. The function accepts any number of \texttt{GPArotation} objects and is useful for assessing the effect of different values of a criterion parameter, for example comparing rotation with different values of a parameter. %------------------------------------------------------------------- \section*{Special Rotation Types} %------------------------------------------------------------------- \subsection*{An Example of Target Rotation} \cite{fisfon} describe measuring self-reported extra-role behavior in samples of British and East German employees. They publish rotation matrices for two samples and investigate structural equivalence of the loadings matrices. The table lists the varimax rotated loadings matrices. \begin{tabular}{l c c c c} \hline & \multicolumn{2}{c}{Britain} & \multicolumn{2}{c}{East Germany} \\ & Factor 1& Factor 2 & Factor 1& Factor 2\\ \hline\hline I am always punctual.&.783&-.163&.778&-.066\\ I do not take extra breaks.&.811&.202&.875&.081\\ I follow work rules and instructions &.724&.209&.751&.079\\ ~~~ with extreme care.& & & & \\ I never take long lunches or breaks.&.850&.064&.739&.092\\ I search for causes for something &-.031&.592&.195&.574\\ ~~~ that did not function properly.& & & & \\ I often motivate others to express &-.028&.723&-.030&.807\\ ~~~ their ideas and opinions.& & & & \\ During the last year I changed &.388&.434&-.135&.717\\ ~~~ something in my work.& & & & \\ I encourage others to speak up at meetings.&.141&.808&.125&.738\\ I continuously try to submit suggestions&.215&.709&.060&.691\\ ~~~ to improve my work.& & & & \\ \hline \end{tabular} \\ The varimax rotations for each sample may be expected to be similar because the two loadings matrices are from different samples measuring the same constructs. Below are target rotation of the East German loadings matrix towards the British one, followed by calculation of agreement coefficients. \cite{fisfon} note that coefficients generally should be ``beyond the commonly accepted value of 0.90.'' \begin{Scode}{results=verbatim} origdigits <- options("digits") options(digits = 2) trBritain <- matrix(c(.783,-.163,.811,.202,.724,.209,.850,.064, -.031,.592,-.028,.723,.388,.434,.141,.808,.215,.709), byrow = TRUE, ncol = 2) trGermany <- matrix(c(.778,-.066,.875,.081,.751,.079,.739,.092, .195,.574,-.030,.807,-.135,.717,.125,.738,.060,.691), byrow = TRUE, ncol = 2) # orthogonal rotation of trGermany towards trBritain trx <- targetT(trGermany, Target = trBritain) # Factor loadings after target rotation trx # Differences between loadings matrices after rotation y <- trx$loadings - trBritain print(y, digits = 1) # Square root of the mean squared difference per item sqrt(apply((y^2), 1, mean)) # Square root of the mean squared difference per factor sqrt(apply((y^2), 2, mean)) # Identity coefficient per factor after rotation 2 * colSums(trx$loadings * trBritain) / (colSums(trx$loadings^2) + colSums(trBritain^2)) # Additivity coefficient per factor after rotation diag(2 * cov(trx$loadings, trBritain)) / diag(var(trx$loadings) + var(trBritain)) # Proportionality coefficient per factor after rotation colSums(trBritain * trx$loadings) / sqrt(colSums(trBritain^2) * colSums(trx$loadings^2)) # Correlation for each factor after rotation diag(cor(trBritain, trx$loadings)) options(digits = origdigits$digits) \end{Scode} The effect of target rotation can be visualized by plotting the factor loadings for both samples in the two-dimensional factor space. The following plot shows the British loadings (target), the German loadings before rotation, and the German loadings after rotation towards the British solution. Arrows connect each item's pre- and post-rotation position, making the movement induced by the rotation immediately visible. \begin{center} \begin{Scode}{fig=TRUE} plot(trBritain[, 1], trBritain[, 2], xlim = c(-0.3, 1.0), ylim = c(-0.3, 1.0), xlab = "Factor 1", ylab = "Factor 2", main = "Target Rotation: Germany towards Britain", pch = 19, col = "steelblue", cex = 1.2) abline(h = 0, lty = 2, col = "grey70") abline(v = 0, lty = 2, col = "grey70") points(trGermany[, 1], trGermany[, 2], pch = 17, col = "tomato", cex = 1.2) points(loadings(trx)[, 1], loadings(trx)[, 2], pch = 15, col = "orange", cex = 1.2) for (i in 1:nrow(trGermany)) { arrows(trGermany[i, 1], trGermany[i, 2], loadings(trx)[i, 1], loadings(trx)[i, 2], length = 0.08, col = "grey60") } legend("topright", legend = c("Britain (varimax rotated)", "East Germany (varimax rotated)", "East Germany (rotated towards Britain)"), col = c("steelblue", "tomato", "orange"), pch = c(19, 17, 15), bty = "n") \end{Scode} \end{center} Items whose arrows are short moved little during rotation, indicating that the German and British loadings were already similar for those items. Items with longer arrows required more adjustment, suggesting greater cultural differences in how those behaviors are structured. After rotation, the German loadings may be compared directly to the British target using the agreement coefficients computed above. \subsection*{An Example of Partially Specified Target Rotation} \cite{browne} reported an initial loadings matrix and a partially specified target to rotate towards. In \texttt{GPArotation} the partially specified target matrix is of the same dimension as the initial matrix \texttt{A}, with \texttt{NA} in entries that are not pre-specified. Both target rotation and partially specified target rotation can be used to reproduce \cite{browne} results. In this orthogonal rotation example, \texttt{targetT} includes a \texttt{Target} matrix with \texttt{NA} in entries not used in target rotation. With \texttt{pstT} no missing values are present in the \texttt{Target} matrix, and the weight matrix \texttt{W} includes weight 0 for entries not used, and 1 for entries included in the rotation. \begin{Scode}{results=verbatim} A <- matrix(c(.664, .688, .492, .837, .705, .82, .661, .457, .765, .322, .248, .304, -0.291, -0.314, -0.377, .397, .294, .428, -0.075, .192, .224, .037, .155, -.104, .077, -.488, .009), ncol = 3) # using targetT SPA <- matrix(c(rep(NA, 6), .7, .0, .7, rep(0, 3), rep(NA, 7), 0, 0, NA, 0, rep(NA, 4)), ncol = 3) xt <- targetT(A, Target = SPA) # using pstT SPApst <- matrix(c(rep(0, 6), .7, .0, .7, rep(0, 3), rep(0, 7), 0, 0, 0, 0, rep(0, 4)), ncol = 3) SPAW <- matrix(c(rep(0, 6), rep(1, 6), rep(0, 7), 1, 1, 0, 1, rep(0, 4)), ncol = 3) xpst <- pstT(A, Target = SPApst, W = SPAW) max(abs(loadings(xt) - loadings(xpst))) \end{Scode} Note that convergence tables are identical for both methods. Additional examples are available in the help pages of \texttt{GPFoblq} and \texttt{rotations}. %------------------------------------------------------------------- \section*{Using GPArotation with factanal} %------------------------------------------------------------------- \subsection*{Passing Rotation to factanal} Rotation functions can be passed directly to \texttt{factanal} via the \texttt{rotation} argument. Additional arguments are passed through the \texttt{control} list. For example, for the CCAI Climate-Friendly Purchasing Choices domain data, this may look as follows. \begin{Scode}{results=verbatim} data("CCAI", package = "GPArotation") factanal(factors = 3, covmat = CCAI_R, n.obs = 461, rotation = "infomaxT") factanal(factors = 3, covmat = CCAI_R, n.obs = 461, rotation = "infomaxT", control = list(rotate = list(normalize = TRUE, eps = 1e-6))) \end{Scode} For oblique rotation, the recommended approach is the two-step procedure: obtain unrotated loadings from \texttt{factanal}, then rotate separately using \texttt{GPArotation}. This gives full control over the rotation, including random starts, and avoids potential issues with factor reordering. \begin{Scode}{results=verbatim} data("WansbeekMeijer", package = "GPArotation") fa.unrotated <- factanal(factors = 3, covmat = NetherlandsTV, normalize = TRUE, rotation = "none") quartimin(loadings(fa.unrotated), normalize = TRUE) \end{Scode} Prior to R 4.5.1, the single-step approach (rotation inside \texttt{factanal}) had a bug in factor reordering after oblique rotation. This was reported by Bernaards and others and fixed by the R core team in R 4.5.1. The two-step procedure has always been correct regardless of R version. The following example verifies that the two approaches agree on R $\geq$ 4.5.1 using a non-standard Crawford-Ferguson kappa value. \begin{Scode}{results=verbatim} data("WansbeekMeijer", package = "GPArotation") fa.unrotated <- factanal(factors = 3, covmat = NetherlandsTV, normalize = TRUE, rotation = "none") # Two-step procedure (always correct) set.seed(42) fa.cf <- cfQ(loadings(fa.unrotated), kappa = 0.3, normalize = TRUE, randomStarts = 100) fa.cf if (getRversion() >= "4.5.1") { # Single-step via factanal (correct in R >= 4.5.1) set.seed(42) fa.factanal <- factanal(factors = 3, covmat = NetherlandsTV, normalize = TRUE, rotation = "cfQ", control = list(rotate = list(kappa = 0.3, randomStarts = 100))) fa.sorted <- print(fa.cf, sortLoadings = TRUE) cat("Maximum difference in loadings:\n") print(max(abs(abs(fa.sorted$loadings) - abs(fa.factanal$loadings)))) } else { cat("Single-step factanal oblique rotation requires R >= 4.5.1.\n") cat("Use the two-step procedure above for correct results.\n") } \end{Scode} %------------------------------------------------------------------- \section*{Evaluating Factor Model Fit} %------------------------------------------------------------------- Once a factor solution has been obtained, it is natural to ask how well the model reproduces the observed correlation matrix. Common fit indices can be computed directly from \texttt{factanal} output --- no additional packages are required. The key quantities are the chi-square statistic and degrees of freedom provided by \texttt{factanal}, and the residual matrix obtained by subtracting the model-implied correlation matrix from the observed one. \begin{Scode} factanal_fit <- function(fa, R_obs, n) { # Compute common factor model fit indices from factanal output. # For MLE extraction only (factanal). For other estimators (minres, # principal axis, WLS) the chi-square statistic is not defined in # the same way and this function should not be used. # # Args: # fa : a factanal object (rotation = "none" recommended) # R_obs : observed correlation or covariance matrix passed to factanal # n : sample size (n.obs passed to factanal) if (is.null(fa$STATISTIC)) stop("factanal did not compute a chi-square statistic. ", "Ensure n.obs is specified when passing a covariance matrix.") # Ensure we work with a correlation matrix R_obs <- cov2cor(as.matrix(R_obs)) p <- nrow(R_obs) L <- loadings(fa) k <- ncol(L) # number of factors extracted # Model-implied correlation matrix using factanal uniquenesses # fa$uniquenesses are the MLE estimated unique variances R_hat <- L %*% t(L) + diag(fa$uniquenesses) R_hat <- cov2cor(R_hat) # Residual matrix --- off-diagonal only Resid <- R_obs - R_hat diag(Resid) <- 0 # Test of the hypothesis that k factors are sufficient. Identical to factanal F_ml <- log(det(R_hat)) - log(det(R_obs)) + sum(diag(R_obs %*% solve(R_hat))) - p chi2 <- (n - 1 - (2 * p + 5)/6 - (2 * k)/3) * F_ml df <- ((p - k)^2 - (p + k)) / 2 pval <- pchisq(chi2, df, lower.tail = FALSE) # SRMR: standardized root mean square residual rstar.off <- sum(Resid^2) / 2 srmr <- sqrt(rstar.off / (p * (p - 1))) # RMSEA: root mean square error of approximation rmsea <- sqrt(max(0, chi2 / (df * n) - 1 / (n - 1))) # Null model: all items uncorrelated chi2_null <- (n - 1) * sum(R_obs[lower.tri(R_obs)]^2) df_null <- p * (p - 1) / 2 # CFI: comparative fit index cfi <- (max(chi2_null - df_null, 0) - max(chi2 - df, 0)) / max(chi2_null - df_null, 0) # TLI: Tucker-Lewis index tli <- (chi2_null / df_null - chi2 / df) / (chi2_null / df_null - 1) # AIC and BIC aic <- chi2 - 2 * df bic <- chi2 - log(n) * df # Print results cat("Factor Model Fit Indices (MLE only)\n") cat("------------------------------------\n") cat(sprintf("Chi-square (df = %d): %.3f p = %.4f\n", df, chi2, pval)) cat(sprintf("RMSEA: %.4f\n", rmsea)) cat(sprintf("SRMR: %.4f\n", srmr)) cat(sprintf("CFI: %.4f\n", cfi)) cat(sprintf("TLI: %.4f\n", tli)) cat(sprintf("AIC: %.3f\n", aic)) cat(sprintf("BIC: %.3f\n", bic)) cat("\nTop 5 absolute residuals:\n") resid_vals <- Resid[lower.tri(Resid)] print(round(sort(abs(resid_vals), decreasing = TRUE)[1:5], 4)) invisible(c(chi2 = chi2, df = df, pval = pval, rmsea = rmsea, srmr = srmr, cfi = cfi, tli = tli, aic = aic, bic = bic)) } \end{Scode} The following example fits two and three factor solutions to the Netherlands television viewership data and compares their fit: \begin{Scode}{results=verbatim} data("WansbeekMeijer", package = "GPArotation") fa2 <- factanal(factors = 2, covmat = NetherlandsTV, rotation = "none") fa3 <- factanal(factors = 3, covmat = NetherlandsTV, rotation = "none") cat("=== 2 factors ===\n") fit2 <- factanal_fit(fa2, cov2cor(NetherlandsTV$cov), n = 2154) cat("\n=== 3 factors ===\n") fit3 <- factanal_fit(fa3, cov2cor(NetherlandsTV$cov), n = 2154) \end{Scode} \begin{Scode}{results=verbatim} cat("Model comparison:\n") cat(sprintf(" 2-factor 3-factor\n")) cat(sprintf("RMSEA: %8.4f %8.4f\n", fit2["rmsea"], fit3["rmsea"])) cat(sprintf("SRMR: %8.4f %8.4f\n", fit2["srmr"], fit3["srmr"])) cat(sprintf("CFI: %8.4f %8.4f\n", fit2["cfi"], fit3["cfi"])) cat(sprintf("TLI: %8.4f %8.4f\n", fit2["tli"], fit3["tli"])) cat(sprintf("AIC: %8.2f %8.2f\n", fit2["aic"], fit3["aic"])) cat(sprintf("BIC: %8.2f %8.2f\n", fit2["bic"], fit3["bic"])) \end{Scode} A few notes on interpreting these indices: \begin{itemize} \item \textbf{Chi-square} tests the exact fit hypothesis that the model reproduces the population correlation matrix exactly. With large samples it is almost always significant and should not be used as the sole criterion for model rejection. \item \textbf{RMSEA} values below 0.05 indicate close fit, below 0.08 acceptable fit, and above 0.10 poor fit. The 90\% confidence interval is computed from the noncentral chi-square distribution using base R --- no additional packages are required. A confidence interval that includes 0.05 indicates uncertainty about whether fit is close or merely acceptable. A confidence interval entirely above 0.10 indicates poor fit with high confidence. \item \textbf{SRMR} is the average discrepancy between observed and model-implied correlations. Values below 0.08 are generally considered acceptable. \item \textbf{CFI} and \textbf{TLI} compare the target model to a null model where all items are uncorrelated. Values above 0.95 indicate good fit and above 0.90 acceptable fit. TLI penalizes more strongly for model complexity than CFI. \item \textbf{AIC} and \textbf{BIC} are useful for comparing models with different numbers of factors --- lower values indicate better fit penalized for complexity. They are most useful relative to each other rather than in absolute terms. BIC penalizes more strongly for model complexity than AIC and tends to favor more parsimonious solutions. \end{itemize} These indices are computed under the maximum likelihood estimation assumptions of \texttt{factanal} and assume multivariate normality. They are descriptive tools that may help evaluate and compare factor solutions, not definitive tests of model correctness. No single index should be used in isolation --- examining multiple indices together, alongside the substantive interpretability of the solution, provides a more complete picture. For more comprehensive structural equation modeling with a wider range of fit indices, the \textit{lavaan} package provides a full CFA implementation. The fit indices computed by \texttt{factanal\_fit} are based on the chi-square statistic from \texttt{factanal}, which uses maximum likelihood estimation (MLE). For factor solutions extracted by other methods --- such as minimum residual (minres), principal axis, or weighted least squares --- the chi-square statistic and derived fit indices (RMSEA, CFI, TLI, AIC, BIC) will differ because the likelihood objective function is not defined in the same way for non-ML estimators. In those cases \texttt{factanal\_fit} should not be used. The \textit{psych} package provides fit indices for a wider range of estimation methods via \texttt{psych::fa}, and the \textit{lavaan} package provides a full CFA implementation with comprehensive fit index reporting for multiple estimators. A comparison of \texttt{factanal\_fit} with \texttt{psych::fa} using the same data and maximum likelihood estimation shows that BIC values agree exactly, since both implementations use the same chi-square statistic. RMSEA and CFI also agree substantively. SRMR and TLI may differ slightly due to differences in formula conventions between implementations --- these differences do not affect substantive conclusions about model fit. When exact replication of \texttt{psych} fit indices is required, use \texttt{psych::fa} directly. Minor differences between fit indices computed by different software implementations are common and expected. They typically reflect differences in how the likelihood objective function is scaled rather than errors in either implementation. Substantive conclusions --- which model fits better, whether fit is acceptable --- are generally robust to these differences. %------------------------------------------------------------------- \section*{Rotation Criteria Reference} %------------------------------------------------------------------- The following table lists all rotation criteria available in \texttt{GPArotation}, with their type and key reference. Criteria ending in \texttt{T} are orthogonal; those ending in \texttt{Q} are oblique. Criteria without a \texttt{T}/\texttt{Q} suffix may be used for both. \begin{tabular}{l l l} \hline Function & Type & Criterion \\ \hline\hline \texttt{oblimin} & oblique & Oblimin family; \texttt{gam} controls obliqueness \\ \texttt{quartimin} & oblique & Oblimin with \texttt{gam = 0} \\ \texttt{targetT} & orthogonal & Rotation towards a target matrix \\ \texttt{targetQ} & oblique & Rotation towards a target matrix \\ \texttt{pstT} & orthogonal & Partially specified target rotation \\ \texttt{pstQ} & oblique & Partially specified target rotation \\ \texttt{oblimax} & oblique & Maximizes overall kurtosis of loadings \\ \texttt{entropy} & orthogonal & Minimizes entropy of squared loadings \\ \texttt{quartimax} & orthogonal & Maximizes variance of squared loadings within variables \\ \texttt{Varimax} & orthogonal & Maximizes variance of squared loadings within factors \\ \texttt{simplimax} & oblique & Minimizes the $k$ smallest squared loadings \\ \texttt{bentlerT} & orthogonal & Invariant pattern simplicity \\ \texttt{bentlerQ} & oblique & Invariant pattern simplicity \\ \texttt{tandemI} & orthogonal & Factors share high loadings on same variables \\ \texttt{tandemII} & orthogonal & Factors do not share high loadings on same variables \\ \texttt{geominT} & orthogonal & Minimizes geometric mean of squared loadings \\ \texttt{geominQ} & oblique & Minimizes geometric mean of squared loadings \\ \texttt{bigeominT} & orthogonal & Geomin with a general factor in column 1 \\ \texttt{bigeominQ} & oblique & Geomin with a general factor in column 1 \\ \texttt{cfT} & orthogonal & Crawford-Ferguson family; \texttt{kappa} controls complexity \\ \texttt{cfQ} & oblique & Crawford-Ferguson family; \texttt{kappa} controls complexity \\ \texttt{equamax} & orthogonal & Crawford-Ferguson with $\kappa = m/(2p)$ \\ \texttt{parsimax} & orthogonal & Crawford-Ferguson with $\kappa = (m-1)/(p+m-2)$ \\ \texttt{infomaxT} & orthogonal & Infomax information criterion \\ \texttt{infomaxQ} & oblique & Infomax information criterion \\ \texttt{mccammon} & orthogonal & Minimizes entropy ratio across factors \\ \texttt{varimin} & orthogonal & Minimizes variance of squared loadings within factors \\ \texttt{bifactorT} & orthogonal & Bifactor; general factor in column 1 \\ \texttt{bifactorQ} & oblique & Biquartimin; general factor in column 1 \\ \texttt{lpT} & orthogonal & $L^p$ sparsity rotation \\ \texttt{lpQ} & oblique & $L^p$ sparsity rotation \\ \hline \end{tabular} %------------------------------------------------------------------- \section*{Further Resources} %------------------------------------------------------------------- Full documentation for all functions is available via the R help system, for example \texttt{?quartimax} or \texttt{?GPFRSorth}. The package index is accessible via \texttt{?GPArotation}. The following vignettes are provided with \texttt{GPArotation}: \begin{itemize} \item \texttt{vignette("GPA2local", package = "GPArotation")} --- assessing local minima in factor rotation, including the \texttt{GPFallMinima} function and sorted loadings plots \item \texttt{vignette("GPA3bifactor", package = "GPArotation")} --- bifactor rotation and reliability coefficients including omega hierarchical \end{itemize} Gradient projection \emph{without} derivatives can be performed using the \texttt{GPArotateDF} package, available separately on CRAN. A vignette is provided with that package; type \texttt{vignette("GPArotateDF", package = "GPArotateDF")} at the R prompt. For detailed investigation of local minima in factor rotation, the following packages provide complementary functionality: \begin{itemize} \item \textit{fungible}: \texttt{faMain} function with extensive random start diagnostics \item \textit{psych}: \texttt{faRotations} function for rotation comparison \end{itemize} %------------------------------------------------------------------- \section*{References for Rotation Criteria} %------------------------------------------------------------------- The following references describe the theoretical basis for each rotation criterion implemented in \texttt{GPArotation}. \subsubsection*{Descriptions of many rotation criteria} Browne, M.W. (2001). An overview of analytic rotation in exploratory factor analysis. \textit{Multivariate Behavioral Research}, \textbf{36}, 111--150. \href{https://doi.org/10.1207/S15327906MBR3601_05} {doi: 10.1207/S15327906MBR3601\_05} \noindent Harman, H.H. (1976). \textit{Modern Factor Analysis} (3rd ed.). The University of Chicago Press. \subsubsection*{Oblimin / Quartimin} Carroll, J.B. (1960). IBM 704 program for generalized analytic rotation solution in factor analysis. Harvard University, unpublished. \noindent Jennrich, R.I. (1979). Admissible values of $\gamma$ in direct oblimin rotation. \textit{Psychometrika}, \textbf{44}, 173--177. \href{https://doi.org/10.1007/BF02293969} {doi: 10.1007/BF02293969} \subsubsection*{Target rotation} Harman, H.H. (1976). \textit{Modern Factor Analysis} (3rd ed.). The University of Chicago Press. \subsubsection*{Partially specified target rotation} Browne, M.W. (1972a). Orthogonal rotation to a partially specified target. \textit{British Journal of Mathematical and Statistical Psychology}, \textbf{25}, 115--120. \href{https://doi.org/10.1111/j.2044-8317.1972.tb00482.x} {doi: 10.1111/j.2044-8317.1972.tb00482.x} \noindent Browne, M.W. (1972b). Oblique rotation to a partially specified target. \textit{British Journal of Mathematical and Statistical Psychology}, \textbf{25}, 207--212. \href{https://doi.org/10.1111/j.2044-8317.1972.tb00492.x} {doi: 10.1111/j.2044-8317.1972.tb00492.x} \subsubsection*{Oblimax} Pinzka, C. and Saunders, D.R. (1954). Analytic rotation to simple structure: II. Extension to an oblique solution. Research Bulletin 54--31. Princeton, N.J.: Educational Testing Service. \noindent Saunders, D.R. (1961). The rationale for an ``oblimax'' method of transformation in factor analysis. \textit{Psychometrika}, \textbf{26}, 317--324. \href{https://doi.org/10.1007/BF02289800} {doi: 10.1007/BF02289800} \subsubsection*{Minimum entropy} Jennrich, R.I. (2004). Rotation to simple loadings using component loss functions: the orthogonal case. \textit{Psychometrika}, \textbf{69}, 257--274. \href{https://doi.org/10.1007/BF02295943} {doi: 10.1007/BF02295943} \subsubsection*{Quartimax} Carroll, J.B. (1953). An analytic solution for approximating simple structure in factor analysis. \textit{Psychometrika}, \textbf{18}, 23--38. \href{https://doi.org/10.1007/BF02289025} {doi: 10.1007/BF02289025} \noindent Ferguson, G.A. (1954). The concept of parsimony in factor analysis. \textit{Psychometrika}, \textbf{19}, 281--290. \href{https://doi.org/10.1007/BF02289228} {doi: 10.1007/BF02289228} \noindent Neuhaus, J.O. and Wrigley, C. (1954). The quartimax method: An analytical approach to orthogonal simple structure. \textit{British Journal of Statistical Psychology}, \textbf{7}, 81--91. \href{https://doi.org/10.1111/j.2044-8317.1954.tb00147.x} {doi: 10.1111/j.2044-8317.1954.tb00147.x} \subsubsection*{Varimax} Kaiser, H.F. (1958). The varimax criterion for analytic rotation in factor analysis. \textit{Psychometrika}, \textbf{23}, 187--200. \href{https://doi.org/10.1007/BF02289233} {doi: 10.1007/BF02289233} \subsubsection*{Simplimax} Kiers, H.A.L. (1994). SIMPLIMAX: Oblique rotation to an optimal target with simple structure. \textit{Psychometrika}, \textbf{59}, 567--579. \href{https://doi.org/10.1007/BF02294392} {doi: 10.1007/BF02294392} \subsubsection*{Bentler invariant pattern simplicity} Bentler, P.M. (1977). Factor simplicity index and transformations. \textit{Psychometrika}, \textbf{42}, 277--295. \href{https://doi.org/10.1007/BF02294054} {doi: 10.1007/BF02294054} \subsubsection*{Tandem criteria} Comrey, A.L. (1967). Tandem criteria for analytic rotation in factor analysis. \textit{Psychometrika}, \textbf{32}, 277--295. \href{https://doi.org/10.1007/BF02289422} {doi: 10.1007/BF02289422} \subsubsection*{Geomin} Yates, A. (1984). \textit{Multivariate Exploratory Data Analysis: A Perspective on Exploratory Factor Analysis}. State University of New York Press. \subsubsection*{Bi-Geomin} Garcia-Garzon, E., Abad, F.J., and Garrido, L.E. (2021). On omega hierarchical estimation: A comparison of exploratory bi-factor analysis algorithms. \textit{Multivariate Behavioral Research}, \textbf{56}(1), 101--119. \href{https://doi.org/10.1080/00273171.2020.1736977} {doi: 10.1080/00273171.2020.1736977} \subsubsection*{Crawford-Ferguson family} Crawford, C.B. and Ferguson, G.A. (1970). A general rotation criterion and its use in orthogonal rotation. \textit{Psychometrika}, \textbf{35}, 321--332. \href{https://doi.org/10.1007/BF02310572} {doi: 10.1007/BF02310572} \subsubsection*{Infomax} McKeon, J.J. (1968). Rotation for maximum association between factors and tests. Unpublished manuscript, Biometric Laboratory, George Washington University. \subsubsection*{McCammon minimum entropy ratio} McCammon, R.B. (1966). Principal components analysis and its application in large-scale correlation studies. \textit{Journal of Geology}, \textbf{74}, 721--733. \href{https://doi.org/10.1086/627207} {doi: 10.1086/627207} \subsubsection*{Varimin} Ertel, S. (2011). Exploratory factor analysis revealing complex structure. \textit{Personality and Individual Differences}, \textbf{50}(2), 196--200. \href{https://doi.org/10.1016/j.paid.2010.09.026} {doi: 10.1016/j.paid.2010.09.026} \subsubsection*{Bifactor} Jennrich, R.I. and Bentler, P.M. (2011). Exploratory bi-factor analysis. \textit{Psychometrika}, \textbf{76}(4), 537--549. \href{https://doi.org/10.1007/s11336-011-9218-4} {doi: 10.1007/s11336-011-9218-4} \subsubsection*{Lp rotation} Liu, X., Wallin, G., Chen, Y., and Moustaki, I. (2023). Rotation to sparse loadings using $L^p$ losses and related inference problems. \textit{Psychometrika}, \textbf{88}(2), 527--553. \href{https://doi.org/10.1007/s11336-023-09911-y} {doi: 10.1007/s11336-023-09911-y} \begin{thebibliography}{} \bibitem[\protect\citeauthoryear{Bernaards \& Jennrich}{Bernaards \& Jennrich}{2005}]{gpa.rotate} Bernaards, C. A., \& Jennrich, R. I. (2005). \newblock Gradient projection algorithms and software for arbitrary rotation criteria in factor analysis. \newblock {\em Educational and Psychological Measurement}, 65(5), 676--696. \newblock \href{https://doi.org/10.1177/0013164404272507} {https://doi.org/10.1177/0013164404272507} \bibitem[\protect\citeauthoryear{Browne}{Browne}{1972}]{browne} Browne, M. W. (1972). \newblock Orthogonal rotation to a partially specified target. \newblock \textit{British Journal of Mathematical and Statistical Psychology}, 25(1), 115--120. \newblock \href{https://doi.org/10.1111/j.2044-8317.1972.tb00482.x} {doi: 10.1111/j.2044-8317.1972.tb00482.x} \bibitem[\protect\citeauthoryear{Fischer \& Fontaine}{Fischer \& Fontaine}{2010}]{fisfon} Fischer, R., \& Fontaine, J. (2010). \newblock Methods for investigating structural equivalence. \newblock In D. Matsumoto, \& F. van de Vijver (Eds.), {\em Cross-Cultural Research Methods in Psychology} (pp. 179--215). \newblock Cambridge University Press. \newblock \href{https://doi.org/10.1017/CBO9780511779381.010} {doi: 10.1017/CBO9780511779381.010} \bibitem[\protect\citeauthoryear{mansreise}{Mansolf \& Reise}{2016}]{mansreise} Mansolf, M. and Reise, S.P. (2016). \newblock Exploratory bifactor analysis: The Schmid-Leiman orthogonalization and Jennrich-Bentler analytic rotations. \newblock \textit{Multivariate Behavioral Research}, \textbf{51}(5), 698--717. \newblock \href{https://doi.org/10.1080/00273171.2016.1215898} {doi: 10.1080/00273171.2016.1215898} \bibitem[\protect\citeauthoryear{Nguyen \& Waller}{Nguyen \& Waller}{2022}]{nguwall} Nguyen, H. V., \& Waller, N. G. (2022). \newblock Local minima and factor rotations in exploratory factor analysis. \newblock \textit{Psychological Methods}. Advance online publication. \newblock \href{https://doi.org/10.1037/met0000467} {doi: 10.1037/met0000467} \end{thebibliography} \end{document} GPArotation/data/0000755000176200001440000000000015171560331013354 5ustar liggesusersGPArotation/data/Harman.rda0000644000176200001440000000050315174015243015250 0ustar liggesusers r0b```f`aed`f2XCCt-XFN Xfr_h|=oJ/EbRۿ4>KW~ȦrW_18S'[,#>\'k=D\yN0:%JNVJBhcNR@ (J8JsSla:Z<[FjfzF L5лzy0Š\Μ"trd|I%Ez)@JR%zE%B)@!{`^rv3D0?kYGPArotation/data/Thurstone.rda0000644000176200001440000000142314323662111016034 0ustar liggesusersmSiHTQ~$6HI{VDI|FiCD",lZ  3QX:3:F6 Eta}w+f5ML^[<mff8=pfq'6samZ\ [7v.7ъlKГB_lu%F@oC^W|y}yJpkje:tέqc7ݫ{Lb890mzlpzJ15#ߛ 2OMlÉ` 6Q^YڃN-*R[J̧ϨGME}CG2`5xPc@C|p` 3^)Z1䜔a7xPi9Q9ՏPy]!߁-!>E.YC& ֿKuf~Nzn7\ 4;@?4-@yd{$N%n 6v貅=p ttDJ}iJL[0_JHEJ%̫R:1Us=&Tzԧ0`ԡyf7Ua^V+h7Jv-[׊W|j[_#VKbtF(RV- $@ j+v{%jxgv{owsvUqE);ssl̜B)J"JBsKx2]E9I9 <?K#:^:pghc\^wKա}Tp2L[uz0Gd zC[K-=u7 ̌7D lw{W m+uXYV &=]gg)|XϮ6ZVzaZx hʯ@[U+h+<(<> e[K A8/y$p䇺Y"`t=cn+u^x6 "Y*6Ɩv#\**Ɂ랇`,UKx#8O3S}'@~oB;&0H!ց7]LB{}tx(.+%5sLz: &z`OŇ5ҁ̛ăq0nU륀fg;8<(wNtuy 8&&j E}qU`-ac} lS\?XXoX8?7_, )λ}%_ªz0o5i~5`p<QM\^YӱcITޤ~]+GIC]#`V 2~sf?FPtMuy`Gp1NQVaQބx Фs'wٖƹd$o';>@TTP`:X!)FboL{1B@fN@?н%?s7Xse#ӹ[ Ḥ<=vW,Uf,#('?q.UGsЄ {~gUCmq5^!csOw9Yl&n*2 @ Ojs烪F,xU"F^kuIiꅙ:6# צu2ٶ֥f54) kAndj\I44>-Ȅcۡ9I/i/c8QS GPArotation/data/WansbeekMeijer.rda0000644000176200001440000000062315174016451016742 0ustar liggesusers r0b```f`aed`f2XCCt-XFN ZZR$ *`҆ˊ+?n!H$KWj_vbF]qp0Odl{SXF$^%FP00{[D_kdAST3!ȺKMKc\' ~{`?Qaf>L=\҅ ~{`CEsJf.( Q(J8JsSlh2A11CŒP&KP fpXjQ~^fr"L.)،ֆbPdtXp[¼**Ծ2^~R1Ԡ(GPArotation/NAMESPACE0000644000176200001440000000126315162264211013662 0ustar liggesusersimportFrom("stats", "rnorm") export( "GPFoblq", "GPForth", "GPFRSoblq", "GPFRSorth", "Random.Start") export( "oblimin", "quartimin", "targetT", "targetQ", "pstT", "pstQ", "oblimax", "entropy", "quartimax", "Varimax", "simplimax", "bentlerT", "bentlerQ", "tandemI", "tandemII", "geominT", "geominQ", "bigeominT", "bigeominQ", "cfT", "cfQ", "infomaxT", "infomaxQ", "mccammon", "bifactorT", "bifactorQ", "equamax", "parsimax", "varimin", "lpT", "lpQ", "GPForth.lp", "GPFoblq.lp", "eiv", "echelon" ) S3method("print", "GPArotation") S3method("summary", "GPArotation") S3method("print", "summary.GPArotation")GPArotation/inst/0000755000176200001440000000000015174250607013425 5ustar liggesusersGPArotation/inst/CITATION0000644000176200001440000000056414405360531014561 0ustar liggesusers bibentry(bibtype="article", title = "Gradient Projection Algorithms and Software for Arbitrary Rotation Criteria in Factor Analysis", author = "Coen A. Bernaards and Robert I. Jennrich", journal = "Educational and Psychological Measurement", year = "2005", volume = "65", issue = "5", pages = "676--696", doi = "10.1177/0013164404272507" )GPArotation/inst/doc/0000755000176200001440000000000015174250607014172 5ustar liggesusersGPArotation/inst/doc/GPA1guide.pdf0000644000176200001440000134205515174250567016412 0ustar liggesusers%PDF-1.5 % 13 0 obj << /Length 2263 /Filter /FlateDecode >> stream xڕX[o~_!8A@KI[m4a;CDIR!m6HH3g|ÏO%~aOۅnF8,Oſ5zS2v Ĺo*붨+&~YfnxPKOs,ZME?s|jc5qn{A:DeG5zx%wrJ*= Oepm}|\a| Uh\8w.Ǽn6LZA09ɹQjt$pdjDwUY#|]F 9BZlrÔI%&Y!LIrW7E?ȶ- Օ.y 﨟,q}nI{[¬>%rvzmSـ)*fߏehHڬg La Q:?p,X/4ñyeW|͆xb$)3G6j ˛B=;)MwIJW#>ȆVm-(Y]/q HfG>X!R^]Q D #OP-d(=4J3v%.u9111$cx @z7!YC-uFĭ1򠁤 r90eޢcAŲ04sЀ"DՊR?8%0b[(@ Fm )dH"7 Hd|wv|Z[*,ֻ"5E(庣Tغtt, (g<ܞa#-"&\TXəy/^MbQF7߼Ȼ {4CN xw5&> R⊉ڀxzj2Lm oC#]w,姼[LAEhdyoz- 궸B.)3[*1BFW9IBɛWo&ٳ5d 9@)V?>H4 G{,;s#/^pM‹dz}^7x҅屡WrQ*W<<\we ġ!7/yV\Fdc HJy)leJ{f`BO 0 O#V?pIk,VǙ2T2SB$x S)%hi#oui@QS4oZ&JByvm ]>u^`SJ k01`}^z!vLϺ2uewH1w8 g t$ȋ`8ݢ7}'E#"P2u Lӻ@AIXu[lOp OA4Hž-:ea2Aw,, hRIy>f23Ʃ[ӠN8Jtxa iKňr܃`JǝIW'jE=!dglMmr]U(pvJ30,{ЗF2-](~a%=qAPbF8ۆqu¾OD\x#Z9׃(2ydp/cx)wS<ˆ#jYjŭ;op^[ @). )7P|/n^=eS4PXaW0NDi }'r\z0Gw/xۜa乑ZNRO=/ׄE}Xb&gxrŮoR^ɈvVj.SxS uCJF-f A mGv2wQ͆gRglWC/w+(:WdO!aPЪV1_s=Ϝχkg$L|37.9EdLPWp56e*p8W#7࿂\+=; R!L2$H8`9Z{*N˲M{6] kgSfqldD  0A c6t 3GoM.oMƿk ~P#X$x=!{#eE{ OZ7JP}oY81k,Vۈi{%֘x!:sS I>k5 endstream endobj 34 0 obj << /Length 1548 /Filter /FlateDecode >> stream x]o6BbU/`vbÊ}j脭Dy㑶8Ka{0HݑE?[>x2,3͖YeaYVdaY rH(A Ə8h:Q+}nՊW״W6н8؈a 狒Ұ<^TCVW I2E$}FD4Y $-8JVx.J Ji݁֩ԛֽEQ fe܈sInQ%{T^vSFxllǖG.0#0/? Ku5_Cu[ߌ}ZaԺk2>ʒ+0 l@l$ KZ rW''k'<--'?yjgGtG7 ZנТAVkfB=9.$C`9&Y^^߷ƂT+QQ &qځĀ=m{N !ߤ`b1i✤yp\ّ׊V!Scxt}+nywu:c Nq]Dq6'b k7q1|5ŶoկoI[e-'Kۆa!c<ÒgP.8su$0XDnt88ŊP<zLHߞp J4նBQAcZ&N^g|&mJ:?Z+sjP 5I>;nB#/ahmi2F$6/3stqP`^CȨᙱgO1öpuBv}#6nk;æ"Vnw(2 :Z4]3ek4b4@|C#@0qu\+a$ ,V m<1MpF' i@>VL$s$l_XN&E@SQu$:eA-܂: 4\ü ϸѼ+,9 r^,`A-Ͷ}-MăspЕ$8OjxSӷ*y"7#:AI Pd<ˡt qC. 32)1񉤇3lEC{2>+R%٫1'mc_`BRSv$bKOx8fn= 48 OpZ3EcOg7N#HYceb4^3?cjߋW04B{DqC♸"[oqA`<^wKb?A $ >x|'` endstream endobj 42 0 obj << /Length 876 /Filter /FlateDecode >> stream xMo@)~Bj p$(iz׎4\8e̼3v|rv@#-J(j S_f/k2JNtmni!feMȐ>JT% 7n{z8 ]+j$dH煳Ã3,蘳6k&yxb0u]cJ ك*PxkSpV&tc'Y 4VE_Jj2=JWGЛ4K[Vhj9J(u-Jr|=UZc6@ %դ"c=0I3IGAA"w,0,_ះ̄ý*Bs3 E;g 7.y0;1RN>oN>44{۲Wd([Tʊ<.⇍qUuZ-&籌g֛5flCjRAy4DįqK ׵P+Qc;;fr:WTΔ-xw߀<0xҲ xVNR>:[!Ě0D Xsz9ݣ< @D매x27vKS@ua.%B%d\qc rw_3Tu CĽu=vC1l\18 h۬7+X{Ym/S2 bJo?iY.¸ wBD#o]B&Poi{kSZ-`!qdePxm~z֚g-n o)rq255kؙ8/B㏟˿vяvߥ1]t řQĚ \O~+ٖ endstream endobj 46 0 obj << /Length 2205 /Filter /FlateDecode >> stream xڵYKoW tM҉l+q:6 5!'|N~}O\rͪz~U*Yn?r2.v6,a)쪧yߋDAp5fw|wCշ ;UEfE:1gRĘzT}?HRk^\<f3ٲeb ֛[d&5 hy+=a$wݑ58US4TLYI_$\6צ&¿38Sq \'5Tۑya݇z㗕`*7}Ei`O[NUT[9!E`,Og"ۏBbzU)ϽICCAۤOoc?^Rmut]i*dLe6W2i5S7h^OI?!NG"KG?ԠYf_%u,pIB2ͬMAs)gRL4e>^f`*ih\gwq5EoZݵMv{eяm:pLcuȲk϶\,l`*t`*\`UM\k$m{,sY7Vm(Q$iABfvUG+G +A!S*TqA' :+KA~ k ׀vAֻHS@l1t@`VDKDvya -Aٔ2aKgY'z2W 3BlT[$c&t: D\P.͘jS1L\ avUZHffţOLYzL KL6AsVT.Cɳ.|,}d`_Tr&^غsE@G4Q.[L,O_ޜ#%ҷGUl,-{e *ЍO8[,ULsݛE)AgY N7œz/+82%n$5#ntG|}m^jE\,::S@9~O>*֎0_'wշױY=eͣ:L_{&@c"af18Dҏ\O`ⓩ!RKìX R߂TU;4=Uq3S F1_J&{TiUգR/A`eg~|L)=94/t az?4xB걞mSqPs!z H M1&DXۦ9p8Up":#1c22)p*'}Ύu1nf=.8!>H8 M}oT3F[@KNMLgNA`p:PI-Tq+)`fp ݬSvmp2L7b&duT򱬮 ƏY|CCmiSY=5\bX &6ש)$Aq1Lٕ7[hpPGHC*@7b89Tł+h[Urpj SenQװS&C xu C끁7~u;<*t4OEGkĕN-~Iq~jڪ//${R8GAvpm QzMDx #Of>?J$e υYa9,@@«t7x&p֙G&40 0A|3c1{T)t{5B:8MOҥìb>`t ]P9x t:পVFR2%Їatx`RkP7vvX -zs\BpC FPF1j3V7D@L;WAX@}ݻQ&6a,> stream xWI6W Ћ ĪHmTh ^Zm4Lo!e٣irC6~|nTUqUnwDqW"*4wDz8Awm&*J*6\v#`tǻn+0sV;U*eZB,ڂJV7۴(QIf+ MlMi$$> NהvlF3\E#YYI\f+ Y,-z!bV+%J.JFTT|~şai Sz_kn{M7zxgt[ڞ7?_{'_}k?N^{G=ھCO};ێ7Lz6dAJHzUsZ?d4F񆔪,2|w/|AKڮ;NR$/֊-oo4976W_XUJE^;!4dhP&Ij-K}E,tTka^ %)xVJ/9A`2>*_Zu8-E8KjiR2K>_qZ2c`jL"$gۨ4!7 HNn(1/dX7ڮfBR=@ $:`dl4gL t7RENIПo":e!y:K*ROz=Е'gk2lp6FQ;3 ~ %Ifzh RUޞ<Q5l31{(UĢVEY( 0ܺGO#!IC˕`J:}nF+[ (4zEtFӛH2g7UL#ɟ,XҎLq)6|i4ғ~9G f=o@;`\xoN5 s=䫅KzMQ=@|m/Us0+,|K惥DqkA'QsiFyA`a%qC6L|"X;]%:MA} e]ohG jQ \<" " B^\/.(;JHKJ$&^aTŽUI*2~7$n閗B(5pe%[$\ ֥q|iF5Z 4tUier  g9.e(RJ#g 94x ZO~Ud x/oEZI7 dy;pkO` =䟰 (yIWd#Æ˛ BEv;>9x[A'PVe² p &VIM;5#+zC96_SJNau|g`t!> stream xڝWKo6W>@֢Chh)Ɂi,z%* %G^l{ y~ջAEv=+YPlYPY<,d͢=^i=#dSb3/!!:X X;AfDJkPo{h-wu+_rI^\PtWoP/%dx+yƱhESp3ij3\/8M rkrO4lE} Μ[+ Sh+Ղ R5qΒLq[ %YYx/[?x#RxqHS߈FVkS*ъ 1H rڄhYjY˯ fHŸJCj仭B/])|o9`V3px ^nĢ~ȝbEOk۲1,NHScOߩf3 ~ZfP*v 1L Vy&z%Q)Ma'b݇QFTۍpz•Z_BwdP=j^\L$@> "k0)h[YQixMrMԩ(d[eJM;~b}p?tB2X4EDI1NKQwd~>^O!@x'd<[c9u%AGM;K+JՃɒc8! 4t=~e`Z/5v/# ٠ͬ'pɊ (JD?#PZLq-9?8f5F`c?y| V9rv,`I:yX ^k_Oި.X}N r}O 6L#vDPgugqc~?q*E 2Vabf%Xx S`1Za>E7W! /vxE`{Ϟ?5 ꢐQ0 (Cɫn@6 endstream endobj 71 0 obj << /Length 1503 /Filter /FlateDecode >> stream xڭW[4~?bRΦ\ZJ @yII =_ό͞Hhesf ~*"-J,Dj?o4fYI9>_27oI t3rw5Wt[rۯbe|kW%x\oxY&lFci5QX:9j3׿ހ|6/&/}Kʷ3mDy8ΒlIZfEƯ$YxrHBD[Vd<*vjɆecWV|.D'27BȮ{Nڃ~aOFx!QvЛ>˲8_վ8xV% "u':EXuqa3ֲ;sVATK HC5AkH(S-xMټ<Ĝ(G/9fi [^. | ]39GU{U!:^. 7u#x|sOhxB- 20>)p'fO tS럵 㗖ϰ.hXzQ^ VM/<>4`bۅ->ecX@/WR2\&Sp[1dg| J*$|P endstream endobj 60 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (/private/var/folders/g4/2p3crp8x53s7vv1lnz3ctvch0000gp/T/Rtmp0m4acq/Rbuild128de9202065/GPArotation/vignettes/GPA1guide-009.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 77 0 R /BBox [0 0 288 180] /Resources << /ProcSet [ /PDF /Text ] /Font << /F2 78 0 R/F3 79 0 R>> /ExtGState << >>/ColorSpace << /sRGB 80 0 R >>>> /Length 1722 /Filter /FlateDecode >> stream xXIT7q+(DBJdFq@ Y gw344smrՀ{rvw. ݏzvͽ}]!~؛ͣp3܋'Hs {R:R|, >TDŏ`h1ͷVmI>i}^|3+r奶+!w㚢EGO "6`Ev*L[C[umeH梱EnͥlQ㰎d" m&G>ub2>i ,.rl+/]y\5pHA-1;ۢ!Wd5U^y V#miH5ʕڮe.{&7]Ɇϛ|?|f7I, Y)stЅCsoO2FL7c=vCmw߬'D&f᧌0ףxɊ)ά m6 b PR`McL8O9St8Rn*r!TssWoPxMTV|l@kWlϲoX*b#|Á]Yfs7'rEU\#eX+ↇ}Z+b\8MIn*<uE=+\Wo}-R^YMݭնTW\ v'|"'"n-b&W*MaN}N\(!ƍgŤ0}K~-=-_s=d;.?qT-<_g%4 }GFptՉ?z|bpWwo;~n\r043ʕk̂k\q>כ?z=fʲ掜:prZ8wMkr>m;O:xwЮz!6T1tVnQ :+*T*<@e0;W1Mln1θ p HE le3YuN{U\]bN^ PL [ 3 n֑N%X"S38`ڳ6^}ʱ]loHcbl noFUvs).JaiXQ VEZqAHnriVmA7}ߌʄc\y[=RҳP 9 $Okkطhp3[zAᢀ[*(\v. $z ΢5E5݅V x1vmN5Z##l*Z Ww i(>RbSe!Ɋpo3j1={ 5c ۈ݆­8m7 _{:xqX)~0*}v'{iqrzfңcfЕ endstream endobj 82 0 obj << /Alternate /DeviceRGB /N 3 /Length 2596 /Filter /FlateDecode >> stream xwTSϽ7PkhRH H.*1 J"6DTpDQ2(C"QDqpId߼y͛~kg}ֺLX Xňg` lpBF|،l *?Y"1P\8=W%Oɘ4M0J"Y2Vs,[|e92<se'9`2&ctI@o|N6(.sSdl-c(2-yH_/XZ.$&\SM07#1ؙYrfYym";8980m-m(]v^DW~ emi]P`/u}q|^R,g+\Kk)/C_|Rax8t1C^7nfzDp 柇u$/ED˦L L[B@ٹЖX!@~(* {d+} G͋љς}WL$cGD2QZ4 E@@A(q`1D `'u46ptc48.`R0) @Rt CXCP%CBH@Rf[(t CQhz#0 Zl`O828.p|O×X ?:0FBx$ !i@ڐH[EE1PL ⢖V6QP>U(j MFkt,:.FW8c1L&ӎ9ƌaX: rbl1 {{{;}#tp8_\8"Ey.,X%%Gщ1-9ҀKl.oo/O$&'=JvMޞxǥ{=Vs\x ‰N柜>ucKz=s/ol|ϝ?y ^d]ps~:;/;]7|WpQoH!ɻVsnYs}ҽ~4] =>=:`;cܱ'?e~!ańD#G&}'/?^xI֓?+\wx20;5\ӯ_etWf^Qs-mw3+?~O~ endstream endobj 86 0 obj << /Length 2120 /Filter /FlateDecode >> stream xڽXݓ bgsf)~IJ?fl&:OwyڲW,9R^^nŦHۼ̯ Va6)serÊvW"6Z1u+N4mv?톞hŜ_JY,9W"OnWk-ZJ{'45Ub-QsWk"I)g1L2P?mGJΤRꞾch.)3ł4y漷9?pam4.]l^[T)J VڻdViI [XEg|Hw"lhinK3(?l4pՓv׺+k;Tt]hSy$J`'1[Ψ,˴7O5D}Fm|\ cy1p9L}ۺjYiBěo,uI90K]'~pkl_`)P𢘅}Ovr>^c\*B) t+(d"b \"74s bQ[Wqӧymo#IwXeH.jާ 4*jƮb.S(qZ'u,%]3U\\:X* 4/+p:UmkyWaYxȱ|`-i3ȑ ,t- ͸VKۀ;|eܞ(S˫XI{TѠ ey"Dт 5toڪh/Aw^<:9!j`2]9JȥY( Ō0 0V@Soϣ(%cZL&f\L@\܋޸tx׿n1&ߗ[D5p߬ x̛cHbs[d** B@K H ƥ IA>5y$niv#x@bɥ*XE4􇎨Kaݐ4H^+<#=0g^T f)K1% aKY201ZDM*~ꩠ`M*Xx_Desis4G/Zh sHD,93e+HiAzQ|FCF̴`G-gB R?3F-!yD(vXNRw8`j&X50h1a_?*-d&sc!A E*t-*mBN17IOfQ(mFmmC|oC;%<908< +֫fim?&J>=w 7\'8TpLl;!(Xmsx] h=$S`5lPҨYE(*h;x=ډ?YG ]֙m]Z+5?aO[Uwq|YVHȔ =9r f endstream endobj 93 0 obj << /Length 1144 /Filter /FlateDecode >> stream xڅWn6}WneI),P-Q6QJTh}yDG>ɢ3sΜҿ_\ݮ׳ di,ݦ R1{X `I7` lq$Q@K(Q.xc:p.+ lo^*$ECf,dIǩ8p;vG™y"pӿ&t[uT5T8{u7&:/-T57Oh'aK {+D)O᳖?=J(bE4|2$]eP֢ /p 3aQۺ:6cHer%Z B ),T=otzk:Ijƹ'.3gz?Qm`Nyi@cbk&,=8ct 3vm]츶5V:v Yc~AD&o\hw\ H XGuDFx}#R㐟i΋wy"r@'_U:@2l/c| lP7$RosY:i2OC QF{ ;\>rERI'dZy4b2R<#10d/({9n5,O/5cfYp#X݌Տ6 Tט)i'Fɺ59 GJ#t, uO/qy2'pK{wfƋ0RIMHqr 2*S29ٗҠw5zRԏ,^gGWS9җž/nvOpPL)X7mT$)y@L1՝ta V6Y?֗l*2mav؍qFӧzbhG8dION$ϛɷ{"L0A]c`/K#ŶWnrY}_MūGLtkNgr.̀M|et)Ie .'|@ tM(&m5b'$1Cl3Yx82&ڱgZfgl6ڎ٤1H&m9)Ë_/ [ endstream endobj 98 0 obj << /Length 724 /Filter /FlateDecode >> stream xڽTMo0 W=@Z6nC#uGiV*+Is%] !DS{|F՜ϣ:bӂѼih~7Cl}+i%]QVIs9G{}lHd\|,/aesd.nxyRZFra°Fʼnsmc^C?K=nۆZw[i0F b44qˆGmL#1^ڑ4 e9WԲōN$heSΨN1/fu{P1U:[lKpϱ[Yj2/W^~iP19nmF/f ҈Ee"V骪f3ZTB>[cZp\|xNϾoJdry_> /ExtGState << >>/ColorSpace << /sRGB 105 0 R >>>> /Length 24340 /Filter /FlateDecode >> stream xKeq%6UgfӀ'jIuh%RIYn/ժvGȈX>?w>}룍i:Go|??i绿wy]OV|| >~]Ou\>E;p qZG8%wx6a s56 pܗ<|m}©OlY&aFWo/xa6O l ln8e1W'\|1 7~*>dYh}fF썰/g'{rŞ&lld|߽ B*#/9r\7Ƨ"&%mIfJrLV|;&SS/Nv_rm5a~%ʖ߈uoڄل593BAXKZb{ϳw};{9W=?ƅM&1j qScH-xrPzЄzcOUW}{0poC#?d|dExú;T#qfr9wX 18ە)ya/yWvdh<,vWXwrm\Mh}8/&;6.u-u}mYԞraqLfߗ+Åلr.+G0Pf/Y:?ʅQ^\sD9Os=p W.ޥŭ&\r7aV}; GX 0w; -WIxݥ  -AxBKA ~_.EWiwo={gjswoCK޹?a6q&иoQt/0~R!s%N6O~f۲v o݅Mع|&l0p 7׀;-WFxg[BA.P9㵻LݜM]ljdc.D']WgĆ 4@Yل8` F&g  V‚5լj6u+v^\фNbmr݂56anios07ͻz6K``m[w寇0/,s͹iV٢w~_]GDrn9s)ˆߴ^M a6-vl6nv sӼ3Ztai:-sr߯}wm؄ ?Ei s߿Hӳi=wm|fQr9ķMP`]?s5b/~S0psUEW wc#0}cVa-ralJ/\?Maǎ\N`!N4脭Һ˜ao,FXp.0 C2m~̲ w)ta; b_X@pW) ;[,jl4!Q!bOp[q,mm*Y*&"Y>6av)AN]Cn>$+y,'݅M,U0x\|Xs8셻nb| C,UPd)<saWώ&TH4>z2_@Wy ,1I/do|br0؄pYtݛdy-X r㒛\,5td9rgIgGC ?IL.NR/L?X?1Ao,'߄{5c,5tsï@|#,n9r $w/cow>Ijwȹ㺒b06'K|H, so!YnwN qrJ`r0R8W¼pdi4=$epk* | FhAU=i_ara}*[f|d9-7\js";<NZImR 9y֘)dyWpᠥz6r5h)%Ys,e P%&K:RC&Y^d#dp!r('hBZ]p.=Mʐ/Y*6 崛,$sr pb^R1/tl'šaI CWiKLk11eK%Nkb>/`NG83M%x^|Wa%'_{nAZKɂ is`?q#~wo–!yG›d?'FjHOa $E3?nŤ_h)Z3:rK1׿D6Fb[8D zUq N[?t6;#CXlz"\rVuؾ_nMh>\2PI9~i; 3{tl >/rfF~G q'{O;aJٞo2gŇԹ} yHz|q:"r7N<#~z7BƍZ텕T7^8JhVK!~g'H>ٴ_IO8[$ӣ ~Z| ݈s]ABݗpףx0L__]<¹@% x\j(ߠG`~I)O`n cÿɷ.n$A% p tGT{쵐s 7"zs~\s'9>~؞ Կ󕐳 <_3rFR1_t r>F~hl%xJ OG_scC~N{nlщqw Nz)wƑspzLAU^O?JbO ~/A~~;0N~09sujrw h&fcX܏?uC~\%Usmn HyNC|cJ{FȠM?i_t ~sσ= KതDNē|~L%>\CaR߃3i ?!^ܯ55x?#hx,,+yΗ wB}]i v=|q?N`~8I_i/H>A~u'yoMs< r$+Ӝ}s.,J~=/8M|OY.|x]E7>=/0`w~>/x 4Cׇ ~›{sCqXٿχa{BgB~9/[|ßg1gaYQlnC~9+c-t tNh )ק Z|c{iz޷1jDSZܿgA1NDz?d_-|1\ϞGp==4/UUr_a9ѹӾ w'?y紇h~5Оl_Зc_}so|LÒ4ӉI~u(:N~;k/ ~"p'{/it^)&qמzQ\H`z/H7oNz˰*s; %c{zejȽO J=/U q?#95~ ]or=#qyNTe4@br!%?~b?^ VQ/|H߃u1类1ch|,74T{ y^N{{ay\/jgk"u1As=񼑂|zE!Չ'H@0 ci˸.Sm 6b7_<?Lx0^ ǹHK.W#NF.rڌW bXr ։B2MadɅ,/T?t8XqV{@lq+s1 } +pz#sA ^1\SËtdT#Մo<G&-@rr*%1 OIG΃ԡ  n<(KlTA #KeBIF`ڡ#*Xix @JO  oy'Na?8(~y io }+{?8ŃćN4hAcggPPx<_<Ky=N~^|=k9lj`)<7B~ލ1?!1*T"co+ 9GkXq'?S:G2N_WaÐ1ܾD:1T#0pI_' d\A~^}'?z2%GlΏćXOQ`?=]-uT]La%u<-FLp_c V<Kya{ nLCX 0Ϧ}x?u dT-'" dT/'qÐ#?Uwxv?-j|l'jom%z5`,•u=/̭eᐱ7yJ4oDJ4Db-ăXy~pTrVsZh?e;0^2?*sҿG9-]I~w ?\N4Ɠh px cg?/Ghy.B?O Aut$xc.I_ǓhhD$a d?/_Co10^/cN'V__+ѐ_=Ob[X f cu%r= 33\߇"K8k?7 )սϹW\'r}$ dČ|WV$+!8ѐMDlDCg3{p\z_pT(qwc*"? diSWkl * L~ލH@uDӾh͉_ w .DCj& ?߾Z P򖁌?:?Ȇ B dѐu'՝h_G 3 ~|rh{:ϹDZqRܿ/ C~6y@a(,2rnˉ܏h0 [p=iˉ\SIsx_0E=N4*!"Ngl'1 oDd ĝ\ߟ5%O  +ѐ1K~ʼn쿠Qf%/J OYʼnDQh(6 ?D3/8*shOaם7UȇŇ|U_D{ӾD"<΋ Oy?MXD/*L'p I4\pǰC-k§RȊIDCګM~蓼x`b0WĠ^D|XN4<~~O,'n= @2F!,-y5 }!5Ć+9W "M7*<, D43!QEHC!YOE$İܯ eΧBHđ!u.xH wHxgH 7S)$uUz I$jo4X8P"kH%)I I 懄!q!6G:}!ZRysH.TH/*Q-$Tg)&AH3ھhRAH5lDCGM*;h8|8篤J=H$؃G~z.,h5)DRڳܟ){ gb^o({x_PFXPG 8ۻhG4#DC|84jJ|_J4$R[>N4Ɠ\8ѰO*OM&Յ{{cV_‹ ПVBKV!!$^|s_`>J%UDCWJ, p7LoSgLJZz ^- ?DC#$+3$;x*_Bljz_*: i;GJ!u''|wytH!I<;ǥ̓c=zy}H(q5$QQ?e>J| BzOR|:W|:R i>9"$5>1&1{z! OPy?^Ke'*Z$5ߐT![c F~^|=3Xhz6?5Rߣ`N~YhzVPEP]!]¥!an omVlۀxs:TH$$G* )DjiD^pbnJDZ2QMB:QCBQUz!iE.ĢCjQUBrQҋ*o Fߣb!`4 $U sk1ރG G!CMsQA aC8`0,FUxZx!޶ wsE yRRO_'I!8W}#K)W*J!`*()CKxV':(+[uGa)k疡{).Mq'^<'K5+Sc;x.y?FĻ"᣺D'^^ !%x79㟤5|U8|BjS' /Ta%= !ɩ,)CD/Rr>EHvj)8;48+<⃖Z=e>m)ߖRzTGE~N{TQTZ\% ?oE@7*)L|&uU_0 p?)Lcs?(M} O0Պ0 (^S DŽMeou S!_οwϱ>tV@ƱM0';o?G^k‡\ Su SM{30"I~>{8t SX/a C"T`0~jNa*(SAJB ԭS*\8S* u S{T0"?x`pt0nO,4_%Le_0y%L%Le{Kj+ޠKj?TGrr0Q.a*;w S9G(Lyf^}@V*[:hž݂ɷ[?%Kn~.yCDO > ຣg%=ŲSH=^SE) $T roa/Qk>8nӏ, ~U!%K !o+!Jj-jET)ͣ5彊WdּyWz-|VI[>* 5 ~C)!Dlȧ8WUJ+ !N Ad {rBңOoxo5m`|[9!?]N%\Pȋ]P㭢/PjJL)*)*d:< =u)g:oJ oKϾWj.兒դzblYW#ZiRҬ.Is:quIQe,x[ǘ2x&ɓ?h :J0c8_rӾfHpExH ]$HAMp#ɠ|g mqd@Y8vkC^STtAW7g"<@vT؝c2x"> 'cЯư1gn1 -0\l+:bK [D`9\05$ [Jbx*b:`hTæ66ǀMe3%*S@0?5u 0ǔ3l7/[;wH_C $Y]I ʥghV瑁Y}rv0,ԀAY]9 *]΀,f8V7X] Scq* * o`u- bUW DzUɌWbUW]u0+W]B$ (:WE] ^+Y9!Vo(Z5 zCw5.C&}C-^RBf8[3-b [0** ܻ r3x_Sb dؔ4 LuE2`Oʹ*b: '- `zk sR]&ãZp ꊜe`g*âSǐ(3 +P}ћ`(/ ` T=àu(| <ԕ৮X >ugSW ϟNԕ'g1izFYC24 aN`w58 ET.H q1iHƅM#2i(ҖMs0i?j1ih0ihn~ f=C12 0ibӔC,&4;KSh ] C-ْcRLC"Fop6+1(hN\WaJ} ;|k3DiJcx\xxփ~VȤ,뛁I,nPKJaIYQIPq_ww!I5T!IS:IʎG-:55@$2 ZLx+"Af@jqHu2>XT- $`MM3 A6 UA AoU?M1:A<&lァGթ!q.Z* 6b&c-9Ekqqal"'3h)QEKES*? #O4^h"ZtXIdEa()@MMDFM`3=4}YH0dh*qCCiی1CC#/4TގBC*7*H!CqBCa5 ckD %h0>h;F %36hHAC4tlʨ '1&h(DAC:d4"XQ.$*8k 3K?]UL?]ӕ(׮^:eOW'FPhс)>}/PaOW?Ft3Ƨ/mF8a=]ߌ9؞R,ڌ %]Ft%2Kk=]th>2ORJl`Ot0kb O܁',fMcB ӂ;]DŽmǿҝƸfĎ)uhtJt3NrL(B3FDŽ:&+1atIcsLcrĸ'F弡Sň7^8ohw$B)WD(UPJbu8nUe\ 1qOV߸+coL]] xWFeMnLt2ꦫFeЍW-7װ2>xnqtl2ڦ[UiR46okR6vT)(t9 +lr_pj Kbڣ*Cl5#ln!TtW,VepM5UFt+(wVx o2+ȯ2QPСʐQ@BP3Ocfe8ͨ(Vd0s*ci5NyVLY sYp9V5дZ; Ω2 +M&T竈wh;\,m6]w V M)7&T*+ḶXфd9AG_ t S)<Z»"dڊ{!^8y>U2>vK6V.PYb:r0p2!?1^$c{]L^$$*J.G³.ej$>"=ٵW؆O(7llQ( eww=MS%O08UCF^5+k4IVH'K>QJI K; %74l噉 XK7H|6Xg6Mm6Wz64lw=ߪq[R;nK{6 -p^oْII~D ޺ܐ,!n5:Uּ6 czsi NpMjA6P)Ňl `KSC!AoZkL6d C0 $ ىiC1}a 7XC!8WɯFh6 ecW 6PR9*s* %`7/"xp+sCPU Ltj'-\4|3}ntxWv: (2 tg-2"8lX"h;S. I[1 5jO9˔2[4|3CkuWI /x{ArU=P^xi U\錀34tJ Ȟ<}jY{zN]UQV2-MYmP9B,(ا>h.s%d8>:J&8 <$ ~K5s>d'̛/k),m"HE_4~5$f$'xR?ᜟ z6l3(<7S0l<72G с8B/r`#q~^t&ۋ{ѩx<`aѫi*?Q' ͩ9{xOSsjqtݜ&Do: XlojtD|3@ͩ:lN(uZ2$$ o>\Sp0Hf`EӼD#]H[;Ns[#K$aRtgǞ& \;9q?cuUQVX|+zFQ5peކi;|:L_lV<M[$PaAknF Х:":&$盋9kl'6q 6;z{ĢK7܎2hJvḑ7P`V=tLURHAf9D~d*o(jglTN2-uE#擖ۄ%|;W:Pyk^-PM=v0(k˷ 3";ptnG sT]-Y0bӨm܄p8L ?ږ_ ѕ$o: ؼp^W+O6gcGq\;M:LkŁ%-AroA"XP^V$a$_uYJWN_BcIGqȕ@.>2WU قnPzUZS"*/s'$3^gs su95gr 95C9BC+P7ȩM*o]]w8>3Be//70[-zSb4F^(W_kL] jm̮`.\k: 9lLFfבgQL6FWw8Puۄ hD%g8x8`8F=G Á ףLq:݄gdqV.iW`Ge(58G *ϯHˬy˪\|<77znx{*s,Kp>55W(`|kjخpG>L#'Y-;pLkC H1tWZ_Dzw||׿M?ʫv"WM~T2GDp?]$|c,Fc2y(s o a{9=Q,GRW@Lxkʑg(E9*=_xI Q?Uܓ2yq`l/cKq<1Jqx?n%$a?j!hO߇E8I*}82Ӂ<[NYl'/I2O8.s2\$ 'NM8xs 7`IqگǂsI4kGCcIe BV?7DS.EDOi5l~H@%a(yxN1<|: \9:ֆtX*yȼ eW ~ϡƲoë—JKF /D]J!B` ~ϡ 4Z{n bJ~O/n~Og1=t-=a: g?vTf4.y!ks!8 ePd&B=5eTIEc=]65>B5T%dR~y+KJhLBUi=$a>=Jb"|ɣj"zi9\WtOON4 ;3^}sC-2( $ E~OH0bwa{?pwU3| 7N<&0á }Mϩ* ?"b<+҆Yy=áz~qD˨ۘKz Y #Eϳ^ԔO_!} bˏ{zc 9aɄwp!VxT"aCͶvd8!!ͪ,S<0ME@"PiІ6I;@cPX ' JH<iy*Ӧ?8Ӧblg*T'qMEUuMbQ(SIF1zME<^=ˋI'q4.{Ϊ&jF\-*l}$Fa?_]WǃxyRSGJ9oEx2!ēx{!;6ެq&kp_1%X8cēCT'T]̺,pEW]B6A-ڪˢŽny4ڷ  xnV]bEqXk:1b֣%jR zX򳁮/Xi;x2 M68↥izjWrk9= XHw8fVL&Xc-Fu47ĭMt8QQH82qehKR9Q5̉㪥sЉ;:>7NN\7(vA!Otȡ<9 WG=<9=)"2,{BNٮ.NJWLjbZm1T͗#/]jHDY(]7kģApUyPH%TrPlH ŞHHZ<g *p5QFx"r`rpB  eQ,MEqSPeQīmF"F(S%ɂ(SgAy\H=pHY^F㥠D=").MJAm{B)[Am?RNZ)ǪK9,G܂r)NG E/L͔Z$TMA#@;)vJPS=׊ *H:•+1<*QA!)X@,u>EPDJXboI|P[8& r}'QG]#E r: NLp|!Jqª Ho(sR9 j<'±DM"K]'A<߅2- C}ʯsPD/FVs>Rs%A0lP'(0 J+CDܫà#"uG둄]ARvqT$pHe#wHNH9˴3Z.DU/#K /ô/O/6;$„%^w2ǯ q%׏ I<z> KWvuHK$$Y{-H/3)$_Bqa͗oU_Tj:,bǖu_($-^oe_K^[HzJzK,_TӚx1]v#X(2 `(ӮQIr0Guz0Gu0!n4=) sa[m[f3eaM-l{ lia[YG%a xsY }@eBGtIH#渧Qsn䛻.SP&fP'f:P(fzPS)f*?(3CSZ1ִ &j1>\)8b/ ( !ddC16%9!QӐn݇QzMH9DIU>k/K=ƾ \~̰upH}3$bLT砆(Zz?ڈ"si\Iԑ) <7KIR2 GKɐ B7pw:j뇊$"5-J,Ex(4#ESBg !籽"w6G,$F͔SkS)j ϏPwFI\̾wN5Pa&݁pk~o70ṁϴŸ^v _u۫5hd^ԯ*炇75_0\,CӾ ,Tyqt=,:5m\F)=ohTyV9hͯ~㎖˿6']Lى`~7`o+Ni?ZqVF\E[}?A> H^dnh57p}n |᳷z^ǫQxN Ej*5V1_S&SP PMo|[8X.W``o(T `B5_U/T?R5^R5`TIGǣOH]M7)_}Jo*FϽ뷗+_(Uu83w?c[` endstream endobj 107 0 obj << /Alternate /DeviceRGB /N 3 /Length 2596 /Filter /FlateDecode >> stream xwTSϽ7PkhRH H.*1 J"6DTpDQ2(C"QDqpId߼y͛~kg}ֺLX Xňg` lpBF|،l *?Y"1P\8=W%Oɘ4M0J"Y2Vs,[|e92<se'9`2&ctI@o|N6(.sSdl-c(2-yH_/XZ.$&\SM07#1ؙYrfYym";8980m-m(]v^DW~ emi]P`/u}q|^R,g+\Kk)/C_|Rax8t1C^7nfzDp 柇u$/ED˦L L[B@ٹЖX!@~(* {d+} G͋љς}WL$cGD2QZ4 E@@A(q`1D `'u46ptc48.`R0) @Rt CXCP%CBH@Rf[(t CQhz#0 Zl`O828.p|O×X ?:0FBx$ !i@ڐH[EE1PL ⢖V6QP>U(j MFkt,:.FW8c1L&ӎ9ƌaX: rbl1 {{{;}#tp8_\8"Ey.,X%%Gщ1-9ҀKl.oo/O$&'=JvMޞxǥ{=Vs\x ‰N柜>ucKz=s/ol|ϝ?y ^d]ps~:;/;]7|WpQoH!ɻVsnYs}ҽ~4] =>=:`;cܱ'?e~!ańD#G&}'/?^xI֓?+\wx20;5\ӯ_etWf^Qs-mw3+?~O~ endstream endobj 111 0 obj << /Length 1294 /Filter /FlateDecode >> stream xڍV[o4~8*+H77粰HCB>9rHn&x W.pI9K{QiϪ;A\$nFc1.bJ-.vsI͓|-&/2^?4(i*"ȋw߁lS, "7eOYG;א7޹=_EW8Kh\7ةW] Vo.Ny[tA4 d\[p:*:RVh M Ny|7o#$!"S|s,e_Hw7:p(=jl]JH__h`}71|2h8I.~!UWFiq 79 ^NKـ}3IǹsuZ)E=nBV̨+wkZ6q\<#R__&]XQҦ߯Z>7q!llò\}+t?4x^5d[K˟ ~9eOwW%Ojt endstream endobj 116 0 obj << /Length 805 /Filter /FlateDecode >> stream xڝUɎ6+hms0I&@r [:m+D7EMYZ=p& |kH$M9Mx!2Fvϻj8L4EŻ|kv?o11eq;Γ&kJV&ǧ.gYr쒟W`i{̋|4Njd~h~2ؽ?5?R>LV_!`>`r1mzɓѬ5-6ukݺ⤎iߧ ENut 4+0lkK-qVz|\zj(qIs?F!La}2ȫOКbXGYK"*l{s$>#혛՛TdYYU1h&q'Wբ^=̓&րTgPs6 ҨMT֠~hu"Rn%Aj,z~:zV1> /ExtGState << >>/ColorSpace << /sRGB 122 0 R >>>> /Length 7528 /Filter /FlateDecode >> stream x\ˮeqW5 $% m'29H>?uXԽjVr*o߿W;/m^}yU_Zo/s_׷~OG׏|w}=2}]~] ?ymG `)'x9Up h/OKm)ci|0@UeKg xL͘ ]/-&8UD#{GKf2 cZ݅B[4D~i)ûc1'jk/mr_uO N uј"\Fs*1e+)#ь2a5cVa cbkݮ9,Q$B)8%WO4dD3z30최2rݘx+& !i$cFh]?83 [1%j߂z9,^coK cV›bʢ1t؀=J_(c+_b$i9phd-'`fa9otD#Ks/ 3ӇbʢFW=48VPh}:@8jN1a}}^nAB`h;Ʀ ŗIA[_Q3

UFeW7wpy&א 8Bu˺_c"H`SvLk7ܜ;Y a]3+p¦msDIYRK0/m.oOAflV4b\ svz{HiCĈqq줎> j1BLB'`൪0Fb>ڊ= /0 *Ua@[Un~Xy E$0,PNF#Hv=``0h.ө|-MpLP0mq"yi9 _V0.,0.51U [?"!ql!?h`Ġ c a lßT 3NBT4eaH  "_ I/cL &\RpmɆA2AnߍT08NzKbg~s@~6>G8ܾ[qp T󃉈}K\ Z>  pXz5oqTzA^'j rD6F' C ÄdwkhEfl1naN1\qi1>" C<&kI5ć˸Kj ţ87-_)j'Nvc[QuU6WIj mj~:CzNlI!oQ6ir} 7X< 704.CxR鯁r!?AsK_wg҅xSMVI ahݰ؍Ԧurr7?_w!X`XR ۪50$oЌj^?$]-b2*e=l__#>Ѣyp|'bb 9?ϰ?,Y1*s7(\#`ٿIRR}zX/-c'&\.xr9$ c!mO.yܕ?(7GW`ēp3YO:˭̍X֏f |9MбhW`sD4%M)cR'uUnV.*Mh9iQ&ma68.Pww1 v\|hrf6ə=ڌ&>VFzD4ټ΀(ed"PV#J)C/PZYg4^q@4٥Mʼ*8#&}lfoؑBTNh* pQuaR8/;ձ8#l݈TV Kvѵ(|af( aYDEްHtBBR@hS :IŃ{dDk ˰)F(m"0 בRU$Œzy$d]z89wSV[YT`jC#cL]])S=?&٪1HSb100=dBjL&dj+>(:C"̏C2H8Hu ?{(VvuHDx;9 ]v@O,gA!?C`0чu !BV"\Ya"tpcܣE"̠( ڲs >(>|,T "2{ "E@!"oDV8;a dӀS7wlsn`nʶ!NYvPVo]+ºnACs@ cwD1/ kP|nR[<ڳcGӫ*".T,/t`a7ZL݆AcA;+9h;0TKӾƠtxte e :D7z7.NCX*̶IºQaݷ"5`1rWgUMa=5` !xrݩXy7ssÎ}u)@x "̉lum^ '![!a E!'W:¯/{ɝ˓!TBXϢP:8)Ysp&SX{bv La=)a=!cR$wb k/[¹=[:i&pl ]6%PX:TMa8º ؁![h {CXȟ'۝idX=n( aaT!k㚊:ӛp,qZ4fx y)mRXod g?)^(j:CX;GEfQH a};<2&4?14qF 61s 9E[;з?(`\/:op\-Ov@wۘډC#9\ߐq /w}(odN 'ok`+R8D0IBhrz`?ޥD4Yl1H{+ghrjdB=nGq;d x U%OѤHk0ͷrMdD4Ymуh#fq#3\3&W~3tftoTuaxF̀ܦ6"޶ %KBj]8$dGrft4 Fl0D49sI1YM& 3XMz_ P4_lGUL_fi /b0'A)Ūa*2t]3}^ Y@N,ۘXg*jG50MvXKyDNڻyIJ]3t&wzwKXGJH4 gMZj 31%u(Ċ;[՚"ȄrNZU:#U%]([ kEz{l;1L.B”q0@ L&,f6)1_󵆘0#`2>p0qDv#0l>q;nZ)y`(q,'pQ DX &S ~7Inf)mtf3pACbh U ;28c efvaְcw[= A6Qk 6=R*<`C=HDl's;~zP@\5&T6OPx>gHN*-ՖGE;{Ez:S e1z8) eݝg p]ߢn>#G QPCa}gTַ,`h? QjAzyVS0 e=2DqRCY7k#J M3ۏH1>7=xSg0 }?πXT?7gI\[+-0s9Cʃ@+,e&o[:3muȏjݧa*kp[Gn:$xhxҙ?`ē=_:,6b'Ňxď'2' q}]PN]@>pJ:F-@ۦm[)ݲ,sۇN r=_۫Jc+*7*\RS9߂<}nEjd^*vΣgviڥvnd P4b %g.$+c+EU5{ZW߆2ޭ2T8)dUſ4ɓZ :7Ҩ/䭚¬S֗wi*^Vm]yygmly^8Xإqzx}}wgfaP֝bNufP1:?j%#ۭC 6]1SÏ=KFÏ` ~,6AӘ9n$׫eSY.0 -Tֹ]f7u ^ڣ+5#79)ҘR H|WxHJI%,睺rd p8lNG*p沪KVnogn/.+|AՎ s/'0ic2*^ &mS9@^g>thlI}Z5]>N.^lQ\lpICZfuZ*3hb]6S ;ɞ<("\*-/j iT$ѺeUDQxMp`d*~V7]qS?,2v pz|rQf~˩3$c<#%/y3-eYʺx"eY1@69<^wc!v19$Y}&T|ؽ >DeÙu$Ņuf¸u!f 03l]9w>CP{QUܜV0.-1O{Vʺ@Wj 1upc+w8ńԸrL>bt>0q׌q8uOGc\D=n=6➢ádG{LC-F W/ :GʀsYPyZNY-4^!_ };2?{EYW_np]_\dc,o _̬>^|z۞M Z _P/|/{~w߼7_Gx\s+0D䒅GoJ^7_~Tg?E׿o_'4qZa-% uMbA,iHg@< X0cAf">ܦ&}5xXqO|m8Kj$vZʋ=۵˿j;<џjliSt7ۧ~I}k*>yqK%ᄐ' k}~?zY[e_M= 6 OS&?ݩ@4xͷׯ+aq: 0ZbT/^=^1YGo7W/yL={s 0v};kx6S0t_~}*EPǻ6pϧ<֞X^<=崣Z j=͟ܤG?MUvu ~H)Oʺaݏr:Z ޻+֨s[&:&EJZy@t)3YNxi Sڪ~Y! ƢE)w_\f]k%x{j](Lx敧HMyOcXkz4lj\Vnj=UFE[{x1Ǿr=_|KP_\vF~ָS[InWrBr66$\Oy Xk(ǽzh=Lfm>»(LGG6o4H@9GY#֝o2HozR-Y~qSKA˶ =;_Yh<~GYzMo?vGH#5'~+o^{_ON}}Ne~ endstream endobj 124 0 obj << /Alternate /DeviceRGB /N 3 /Length 2596 /Filter /FlateDecode >> stream xwTSϽ7PkhRH H.*1 J"6DTpDQ2(C"QDqpId߼y͛~kg}ֺLX Xňg` lpBF|،l *?Y"1P\8=W%Oɘ4M0J"Y2Vs,[|e92<se'9`2&ctI@o|N6(.sSdl-c(2-yH_/XZ.$&\SM07#1ؙYrfYym";8980m-m(]v^DW~ emi]P`/u}q|^R,g+\Kk)/C_|Rax8t1C^7nfzDp 柇u$/ED˦L L[B@ٹЖX!@~(* {d+} G͋љς}WL$cGD2QZ4 E@@A(q`1D `'u46ptc48.`R0) @Rt CXCP%CBH@Rf[(t CQhz#0 Zl`O828.p|O×X ?:0FBx$ !i@ڐH[EE1PL ⢖V6QP>U(j MFkt,:.FW8c1L&ӎ9ƌaX: rbl1 {{{;}#tp8_\8"Ey.,X%%Gщ1-9ҀKl.oo/O$&'=JvMޞxǥ{=Vs\x ‰N柜>ucKz=s/ol|ϝ?y ^d]ps~:;/;]7|WpQoH!ɻVsnYs}ҽ~4] =>=:`;cܱ'?e~!ańD#G&}'/?^xI֓?+\wx20;5\ӯ_etWf^Qs-mw3+?~O~ endstream endobj 128 0 obj << /Length 1530 /Filter /FlateDecode >> stream xWK6W>J%Q EKZB$ёu}g8-{MoXp ?߯_|s"((]o -< $'ֵD$ں[qmV~{_UwvCJHlN+?Icop}/td}[Eg*ՒޠE^Z'r<ϋp3SZtvsyީQia$2:DU=(z@R_wB+kIW/?݊RRVA5#J+՟YoQ5FkFKӒ8 *iSD$l!djX, $96aJ :* ]=j(LoA"@=Q7bHR50{3U(;"(zLj M&9Y3 )b YWC[( EDV`Gްݨ3;(J 8M'7K`WұeR)%w>ɏ؝"peEX17 ٔ`х=|?f9M/&S ɪMGwW$g7@WFz*LwgD۹y2Cmɗ-Ql f(B'iE}\"džXw7 Q9S1jn9Vgń^HijP[|; 1yG=) +HTZ>Ieydi!:FDOxf~;{S笧վ@|۽R d#KHM3cZB(s@ x79_s(2Q'yecć)6!X/ޮ_  endstream endobj 134 0 obj << /Length 994 /Filter /FlateDecode >> stream xuVK6W{5WضI`${@KFf?>p^㛑 _18H'q4ˊuV`A:Uy> ~׫Tkrfu:ER]G/`x0UEiĄX Wx8QTO ]C zGK-u *An$ w;a<&"1X)EvF^ڃ+9ZFكQ$@)ȑ1CjO '0 0Ԭly(VJ68Ͽ')?@ :ƃ0G"OGxkZK'+()RC 3g t׿ODyrp%e1M| 2Q:(DcggUuug 1Rf-[. }1WJܸ5i9R(: 'nDNpEZܢί!B^? zM@,@<<\xo>ܿǕQ> /ExtGState << >>/ColorSpace << /sRGB 140 0 R >>>> /Length 1080 /Filter /FlateDecode >> stream xŗKo7+xa9ǒ8h hBzHrmՖ!ٍ̒UZ+ +S;/g@ wkA|J*?Fx\?}_զRkKXVNl.*ϋwѷT}"@]_+cȦ0WNj/4kr] -`qht&!#$1:-d$ױ҇nE7@:P,ElP rPAˢ#%Ϣ'x=OϬɐd/wH}]DV6W7Yt4!^g+EGH;Y=6:jl7㚆|ܳy4K9AD1[OTA+&k{~?"fϳONvNm+xґIrh|0fnY|&Y4h :h锰4eKA o ZT;|D |\98,^CE(m*SQsPl˩`<T{KGc/ncI͈3&[¤40Z:LjBWrDRPD*DhMiPfC(@I"gVV$$aeɹ $e?)ْxe>/|̤0FEX endstream endobj 142 0 obj << /Alternate /DeviceRGB /N 3 /Length 2596 /Filter /FlateDecode >> stream xwTSϽ7PkhRH H.*1 J"6DTpDQ2(C"QDqpId߼y͛~kg}ֺLX Xňg` lpBF|،l *?Y"1P\8=W%Oɘ4M0J"Y2Vs,[|e92<se'9`2&ctI@o|N6(.sSdl-c(2-yH_/XZ.$&\SM07#1ؙYrfYym";8980m-m(]v^DW~ emi]P`/u}q|^R,g+\Kk)/C_|Rax8t1C^7nfzDp 柇u$/ED˦L L[B@ٹЖX!@~(* {d+} G͋љς}WL$cGD2QZ4 E@@A(q`1D `'u46ptc48.`R0) @Rt CXCP%CBH@Rf[(t CQhz#0 Zl`O828.p|O×X ?:0FBx$ !i@ڐH[EE1PL ⢖V6QP>U(j MFkt,:.FW8c1L&ӎ9ƌaX: rbl1 {{{;}#tp8_\8"Ey.,X%%Gщ1-9ҀKl.oo/O$&'=JvMޞxǥ{=Vs\x ‰N柜>ucKz=s/ol|ϝ?y ^d]ps~:;/;]7|WpQoH!ɻVsnYs}ҽ~4] =>=:`;cܱ'?e~!ańD#G&}'/?^xI֓?+\wx20;5\ӯ_etWf^Qs-mw3+?~O~ endstream endobj 145 0 obj << /Length 998 /Filter /FlateDecode >> stream xڝWo6~_y{pmI!aEh-27D*1/ʤ-9Ş,w})pn>ga5pp1ʯsPj=N~flrio$s:AKi+ݡU¾xc%0g6q+}mDpf1/\J.>BPdYDcK%R Q.47ʽ)cۥ.fpCgGiim JpN<$K(^y+gҐzڅY6؇".(&7^iu|ݢy%ゔkԠRbEAt}טU^%`E f/;Fp|e,\(f*crƍ7P+ AjlaЕHժgJy?E;"ιNwC9( N]ňM 6ֱ2mF#q)?ψrV.2`_ fEY"l"sׁ=>'㠓]:o5XSLs`ăW' uD|`xZQ%Y(*f\[TƁx=VDRjNSn%שGbl'@z}tmE"ifUff#Z ;aSk+LxS￷mt jYlB:RWȳGҸ.]dNn@8z~AG2?GrӅwG/Z5>prupY>yeg9iQ\jUIZzz'oSNC%zD{Xz7=K0r?dI*(Tl%}'] KJuCʷr& RLxğT.99o^AtfƎ."-6D移ft9E:pF%&6gam9adaʺX] pS>̴CD endstream endobj 2 0 obj << /Type /ObjStm /N 100 /First 816 /Length 2172 /Filter /FlateDecode >> stream xZ[SF~_я!>}7[&ql/.Čdh0.sj.v4Z`)b70% L[3#` #mL0ʄ*\$%#'I q4P`"xJLj=BN&bLš:LC.< LPp 4T)Oྖiu@ˆ8UXfSzkNU0c'!9L)09aV2R d1/AB4qP=㔂lzf9L)fNvZR0MFP=;8! a$ #`fP:GBGCLTY2 (5TKV9'%9f O?v]gM/+u6P;8 hte. :PPa$C57b/z>`X5 'YgʲFS|w˪U t_#/Ppp(.# =QCAγn^guTeN VlѤh r,' IK:Xb@ci/?of/u^ (=ᏜE%"=NYN_ {p|Z}~w'zsXw9ɳ 1L|pS.$̣SR"+t\腓pKǿ:d[I*T,0'gzNfUqtXT~?GnөzpJi/7'pO^=z?y߾V^DI4)$|Cq*X|y_a-" oLi!{SƻgA$9`Gl$56$AObkv(C 4 Tιit&h!s= Aù{876o{!hflJWfc9\V[m]v #Cctb)F̍6cۤP-&Tqrنs swGaKBd  h,bJB4r`BRxĽt Z…œڅp'`Su9tʴ)q `dJT[EulT,D81ds;3~6SƮ)_~y ԚڹrUgeӬ9s$rairWeimlG`+iY{y]1;˼;doFi<Y$s?W/L rSŋӫxOiì 77Ywy-{_lQ-nYMqM ?8^ ϐL~FC,sTY(Ju8Ed(I>Jbc!>\>EE~d݈1oD9T)6-{aߘ)h&}\}"'-D]C] JBs^܎fv=a8U|:ICsUS||{穑2,y 4 Y'idJi(a-Z/aeU68^k8E / X]{rwu^3,hD\&5Lޣ8fM2lxz|-;BT-zȱ^_~x$2(}{1G ~%+vlӲb% m@qh-}1&Ϳomf"J<+; +Z~o»ZCDS7klE5#fn1i.i߃m$ endstream endobj 151 0 obj << /Length 531 /Filter /FlateDecode >> stream xڍTM0+Rplc J]uV]UqTfkcU{̼7)]9# [S3ȹ6>,┤zXZr?sbQ8qA 8z(f1b!OSWmp!r0%w٘> /ExtGState << >>/ColorSpace << /sRGB 156 0 R >>>> /Length 3711 /Filter /FlateDecode >> stream x[K޶_BRC:h} ,,ujhǙ7Eu8s^{Vל#O) Y˳ԓ`Әӈ9Ủ3^,OE-ysֱֺgԟyfZ72h iJt3͹za%;x)r߂Iӎq/8~ռ/mR9V[QOsй/VR%޽/6 7Bm}?cѡCHwAky.0.Rc\Z-u1n Z7גNEyU~RI{M6guז\noAZmR%no|,zƒwst‚=Z :UO2oxoAZm 7ƍ _`0dO}ݎO=Z u/smkKIٹ_-Hkm1nKI4_k`Ge|gAR{hs(<ΥX-Hkm1n%2K2O;;PI}I_'בJ(cr5V=bmÎq/tL#XBL5!?豷i/< $]|+G$ܶ=RƸ9 |^KD$,HڣѧlvRQ%I~&tHmw\ƸїJmKC#D+I{Trt*7RJtxw߂Iӎqs_ F2j(eezrQƇ)=euQ֚_dK1>(21/EF"JTd Y7"2ٞ9dVdG淅M-C5 :<l"甃R[97)`BL)fBYM~%pYM!FčrKۂb_bM!F݄6!S&b nD!FMbYL_BLb428jr*|3*Dl)o 10NKL){Lĉ]Rp4E4ujIAbfe<[Bo%vɼ B̬ x!֋ӵ%谦bDڍlAHU44󬠊XQ2F^t-BeMUr!vlx* 6A9!=;#z||}m5W()p8p/ [і4ҹpFL{*>D=霑穲`% -p8rg ~7#.* %#$͌PPZn1\~⒙\{vtw}Zs^KZSUV⫨̮-:J"Azb 5d}V\ܗ5e\ s_|üMnӏ?[P}#ݶ/]c){JRs_fܖq)"oq ݤ ;7}Uf?Eeulong̮˸@~JxldwVor_^r_Y4ʢl'ή-;r[K+.T}+/{q\p^KZ}c~(>-;r[:e%IrCo܎q_i.,)Q}S+ءU2yEefv4onYiS<;nZ EV3oVWÇ> stream xwTSϽ7PkhRH H.*1 J"6DTpDQ2(C"QDqpId߼y͛~kg}ֺLX Xňg` lpBF|،l *?Y"1P\8=W%Oɘ4M0J"Y2Vs,[|e92<se'9`2&ctI@o|N6(.sSdl-c(2-yH_/XZ.$&\SM07#1ؙYrfYym";8980m-m(]v^DW~ emi]P`/u}q|^R,g+\Kk)/C_|Rax8t1C^7nfzDp 柇u$/ED˦L L[B@ٹЖX!@~(* {d+} G͋љς}WL$cGD2QZ4 E@@A(q`1D `'u46ptc48.`R0) @Rt CXCP%CBH@Rf[(t CQhz#0 Zl`O828.p|O×X ?:0FBx$ !i@ڐH[EE1PL ⢖V6QP>U(j MFkt,:.FW8c1L&ӎ9ƌaX: rbl1 {{{;}#tp8_\8"Ey.,X%%Gщ1-9ҀKl.oo/O$&'=JvMޞxǥ{=Vs\x ‰N柜>ucKz=s/ol|ϝ?y ^d]ps~:;/;]7|WpQoH!ɻVsnYs}ҽ~4] =>=:`;cܱ'?e~!ańD#G&}'/?^xI֓?+\wx20;5\ӯ_etWf^Qs-mw3+?~O~ endstream endobj 165 0 obj << /Length 2307 /Filter /FlateDecode >> stream xڭXK60rd@VD iw9%9mkG)cVA|_U}ԻrSEU.a#<*lyTU0l~ ~I&jݴ A<M[I[j2xޠWݨv8Z:X|\(`wُۭKyUE׎pzqAU(9݆:-7[};Vcdq{Z /N^O UO5dRFI*& )\pFmbt3%tY详rvY^:Ux`~V>A{XHb#cI"OnxA(DAؓH=1j.E"_[Xk-mvLR.5Ȃgzbހ46QxA{eIǾo-E-ߖ%2jM21ei1iZvF42'vfxqRv4 ;Ʃmz;MkO7}\epD" *pH*T/̬ګ7TΏ4>"K5-dKl& T6:R=+֪N]'_^t~Gu-.z&[< Lsg@ 9.PZKq+.ƟR{管 `XPߨ}?t<-GU]߫Ryߕ =6E28}BC}C8cݐv;ʯFXA3kA:" OvQ(tIȯ #0!RЕzX6C,!VkK)>Nn(1I˺>|>$=uWs;d{m ؗX(CCd!h|6DZ"!a y[-t4.B8ñyB*Ѱ_=e%q>ܔ?"` endstream endobj 172 0 obj << /Length 789 /Filter /FlateDecode >> stream xڵ]o0+*E*-CBH )nm:Nti4q7~rs|=9t2|4Y$£\Rf>&)'\l4@Tq'`Da-xC۳?&(`$xYA##rD /ObvN5Azc-šr~,Vh%w)7Y]cqsg" nma}yC""=~rI}#:>'Iv~ؠz]|DWAo:!R>oyw/xDuL 7>*wQ_)2v7~7:\: Y 0JGxwm&.Ճb׸[߽>{b6Bh .~a,ZF uS hsz/5f [7 #3 #Z '''iG~R endstream endobj 176 0 obj << /Length 1176 /Filter /FlateDecode >> stream xWߏ4~ZN"=6$ AM"nAv)"/ۏqȃ<#b[QE΂wct{2f/FiC%w ?M|s+uit׋qT'hcնz`6=9: m ߑ}m|]'^hp+1䶿7{Ϋw: N2N|gh6dVDRJLCvsti}2!E4k,Z\Bf^y ^[hѻFǑny@~J?;n"?zyhV+0Cӻ`>ela+aY+gM'=£\I D9Co6q|". endstream endobj 186 0 obj << /Length 947 /Filter /FlateDecode >> stream xڍU͎6)dVDRC6؞ַĵHCQ;ávkf8 _}CDfeMIY jNn;KO% K $EwLHW^ g6LjelnGOjdI^ d_qeVů.۳rHL$8ǿm<׺{& ^yKlSA_yoLFwO]˭ib`' .Hx2ˤWVY%f(ܗG ~6^|eV2Q^BюH:=3ƣu>h|?E񾋚p : o=,*5 cT~5 ЅL,@VdaptxDǻtU R2NuNBM1֑7,Z#`Ͷ.-:DɊ.ơ&B@MWic 0zyz|dL5_r!ܡ#)݀G9%2_`\ @ wS1t W9O^1ٿBXpGAQ/LilR_ȵкwCK U=feӡUXJZY6&b 6pHpၢ!Cprqr\Ϭc ӛO4W~0xP99a n"~#qj8P7돥֙yqh*+z@x)l> /ExtGState << >>/ColorSpace << /sRGB 192 0 R >>>> /Length 2148 /Filter /FlateDecode >> stream xXKo]_07yt0td!vc^E7jхG <'˛͕rO KmoO_z>ꂯ1Cs_mgo+F1.w!mէNK|}&/]=[ɷl| X@L졤Ie̪6·VߋEIoG d`H|| bLm#YvIl][U/{IB`H'Ɇq _*P#R!深xl0lFBkꥼ{u/m`{Hْ5 S5$|)s2bL#8&/TS -kۼe{e/M##'(j2tԕ`7ܓWjÏ:y{cLقZֶyxz^p|tzp,&zNL|xeXPH[a35قZֶyKyz^Rl DlIV$]3uy,^E,[u$'/Ū0e jYU/=6D8cIBvT :5(P!-:}OsŔ͈mm7Lo BNd~d#Q7߇!^oÑ9җke t2F&6قZ׶yKx ?kYkGP4DGn+*<aVy;DE2Gwd.tZ\o5S#r ~p|;n8ۓzB~:|{ˢ/R{fLqcup[^̋<o{)/N%nR|N޸l%E*C:iɚ᮸gRv)9pO"E pG@f ȱ$# b Iހl-g$_Kz9ગ4_$W_pK̽Qu[/0gKz!Pb$R/8j / [Y*G0;, z hڍQb_WHWݏ_?~gkwEH#zս~x͋" 6~{ݵ(!y4-g%@'EOw]OvD1:gTP>h Q n:ةLe_܇CnK=+xP)u,2H̓hPuT hD0fNb2묕O"kc*3GCHm̃0Z{J{)~'& -4ڶ zO "RVJ!  iSa>qXBV.U(j MFkt,:.FW8c1L&ӎ9ƌaX: rbl1 {{{;}#tp8_\8"Ey.,X%%Gщ1-9ҀKl.oo/O$&'=JvMޞxǥ{=Vs\x ‰N柜>ucKz=s/ol|ϝ?y ^d]ps~:;/;]7|WpQoH!ɻVsnYs}ҽ~4] =>=:`;cܱ'?e~!ańD#G&}'/?^xI֓?+\wx20;5\ӯ_etWf^Qs-mw3+?~O~ endstream endobj 198 0 obj << /Length 1747 /Filter /FlateDecode >> stream xڭ]o6^d f-RtK[ʖkIwGbO}ѯ^|f\Ϯng410lϗ<)¹Q$8/TCٮtg* 隸1A2IE~vγݗEc2iy}m1}hv('*d"Lu r96YrW3۲"|}[U c2#ec(Jx ,s /ɡqָݾv$ò@kaO}2rXY8!N&r([{`ҚR޷~ 1t›L (B3\MTRŒ|+HO0) WѼ#ӑ&xDGO)~IBe:?k4 l9 g;0dBHj&Ӳ2RѸfҲ\,&˶ 6eӔ;ϕN$= %k$8y@9H> I]SIG`(A2jڧBLFs=!NF4\ xSnWsK`9{8 GO{V7j+z,RNdŅ8~/WP (f+)~$:(  Dv)U"֬G-UG# zp4p&{4^$ G$:j(πo %#h6SªȢ6_dg@J^oW]e+cq/>>KáݙTG1znc?w00coy

L(PyǟMl4v|=a}lqtUޠ{fԑ;}dC MZn<xW2&|&e`U+s˥hu[{qg:MV}' کݭJۊ eSVYYSd]T;D0!Էv 2No./ 3K&F9C3Z8qo 3 >ء:9~k˹YeqH(Mne[;#5CP$d _L6aMU ;xuqM\w^ K4ۺn\xv־xRѷwDsaЖ]DD>a3=t8 oPf0 `FF]֎ȓBA %4o]i|Tec%7&LA^_PpRN󳷈:J2|ZMIja#l˯b[@)iPtmpV w4N;1p0e=>ǟ`95DPxC{FeᵎxxS" > stream xڝVM60rH@ FH^PrV,m$yׇI +=EPrgpPs b#̍n7nǡ.LsruqKzQ"ȖZ} 3Sj|薍QSJ%xmO- x|S4TNrٽ9e` ,0` 3dmg`N"Z'0՘6ŝk`1ΉN&V@z &ŐQT=Ӹ^:}CM3KH"QDrH $\1r`rNG n09CU^_7\'Pxn4Ip-L21  VͪJ &M }`2|A13xh9޼=|K endstream endobj 208 0 obj << /Length 1188 /Filter /FlateDecode >> stream xڕWKo6W,|"D1h$A\p4޺Yzh %9H}")Jl4fwHDn(S,V͟۷f,҄ƌScA1q("ۿwlMP" xڡimkXIeVX[E,lI> stream xڭWKoFW*Pp$&@ 'qe=4=Ě"%%;0 73;7g/i2ITR9Yn&$aD&2LS '&+lΣ$K|.g$gsB΀JiRG ]\j9|,βԚ6@'*]k+(6l_h^5`(w =PEM5! ?֣8 9nHM1A@_Jj\ o#B/F^AMb#0h/]^k='>Y @xCx=kAz>t]lN@_'w N_:ir?w J?(z.`'i 5;!ĽZb6:i'j!mDY'J$pZQV4JDg5MD ig6[YIleE'+e+KegW9{MYd+C#E,j >Gþzs6)ȷ@;nD})dUSM9_H(&vP[1/MyV{5_+A;z4 pVeWRr|:0'^ǰakؼrA&k[iWO]-M7^U?K]ߞnF[S}{bQ>fjWtsχצf1̬f?mnӱe0=QԦyFNP-=/6<pp>,ǶD8$}}uk.+j6 ;=ߕrzՃ~60.V_aݢ|!IBA8 @ M-^ endstream endobj 216 0 obj << /Length 1500 /Filter /FlateDecode >> stream xڍWێ6}Wi @.VhC  %jM$z%jw!l\AIpf8c y4]l!4HHiT.N:J?KӢV@& _p As"Q'kx0O/u/p􏕝- is/W,u6FݔtQ7ttԥ8Yt9`F=^n+H `.m["l,bVgtܝW>pGC4@$Gd1Kة=鱾}&'Vh> stream xڍWS8~rw*{y۵"@08 x`t_ l7lr)fQly V+ϾzN(=OqZy'~2?Q>3a! Bk9i*\8o?g̏`.Gč@Ϙln(AIrsAew,'V5;:g[XeMTՖ P3:^QBhuw֮#Xj[\wٍޫgp&/2L?}{l){"nCMv&3~[L:Q#kw;k@`W1t(qC2~z~UOڊ]P73iJ*>=Cl vti]&/;\cU@FMVb ܭ! jb3敕 Wk'gV>6?9A?dP=TXxǜ;KfjI}>NdʟIU i #8KIe#fui#Z n튂dfm+#7URRg,juY}lVzG8-_UQQf* ynx3(`uރɩu>Rxgke )cqjQigY'G+TqI;n/lmwCJu]?_qXN~3Q{WLNouޟȄI,}(L7{pV1´%ANfrKd9̝ i}SG:8Fdj rYWx)NF&u}.[#A]$W01X:РHN!lįD3m@\ -Pȸ'rs{]S%+Ȥ VD~LhA]]|;H%@]<My*dI\O<^F2 C_qm֖.{Ɗ.=H('hҨݒtCIƜ܋`."4yt9/@@ endstream endobj 226 0 obj << /Length 1051 /Filter /FlateDecode >> stream xڽWn6}Wi K/u$buۇl+$'݇/D@QgٌQ%!G|hFazIlt|?]ڕ pɁ:Yޓz@w_F. Ч#/A;tqs'4%H&"%AYj $wz!7QJ Y)À1>Ei͛]9FN HY+Og,mEwEKMbV*+RcZ!":}vSlt~ok½Zn׎^DOj>ûLB]k;rJgky4 &'%lJvX_7 gAďJ׀Mdx5pI4/͋#іh{4bABv/h7=Kab'V(w-ο"۱9?j=DTӯYHm)xDn:TŮԡE@L*A:c q֜5E`]K[tm?bZTESJ*tWMMnbP( "ڭdNe2^GWc 笗ֺLo8/ c)\Cܬ`2t胀Q2܈x؏mZ_ ǽz4b\Ca\yR*Eoٖj@$^Ўqm}ug[;3xaL=^wE !}+08BB>툒"kq4\Q'P5$.A^j(?1#\7V'˓K endstream endobj 230 0 obj << /Length 744 /Filter /FlateDecode >> stream xڭU]o0}@&x8Z'U#ujH2{ !+H`={s|Z2(|;a(L_ 9q­sn *\aϺ̟m:>Eyo¯vd^)}mjTuA]=[@ zwÈ)rWW@(tQB`P@t2@>:Wfmӈͪ:fS #aڊ^@PԠǎ[peڑ)21Ll%;81&5#l{]vnuWSoSf @!H Unʌ+.)o'na멛]c=56:ݓ'.s܁':D> stream xڭYY8~ϯh m# $AdC0,h#K.Ғ[b"U_zo,n7eAx_o~٦QUjpM;|~z?l,O70*hن0A{'[^ao;S DAXhf n@/Ü^Qm#X,(Ko~Q1{>L2IdycoH_nuh G=h+PJoeW~\;X$֑#̇L+Hs,B+ qe[bB?jd{'HwDx-^ۇKQW:-Z7<T;a3tQ!lnmHS޼-b<0Mh7@`7eb#5?;oPsC;Wƪ9uȂ;TQsh R-jFWm-njv=4YAljp&Œkzg}3kߺB+Fe[نe/o_nŠԏS'&@aA t@N"Wf1R62D>[`JU>j׬<7B;1ğ/g'JMg-*ܻ[J+7LT]5d()Y?s:O#Z}wbjĆxquf?Mf1*R4P{eH2Gյ8>+zy+F^cc2A5I\83}.cu gGHjھe8v ^яJ'wT9B`{圽tTW虡7?n/>ţDw3;s4h`!Gsj~5%Ts?\AHQ,8A`V̘xg݀zFV-Bرk|R7[oX(Hd@MBdŭ/ E![8Tc/?,b~UѶQ*#y&ʠ.I"ݗg 1M;2L `_?SӬ ŕxxB ·rGt' ]6rv:t"V .LYpt\(вPV|kٺgus\7Ys)J-^ <*5L(,+X_ >X3"YCc ʼ__' 0 -d?5<&U J0 Ùfgĩ3O 1XO_p=K! ,+-\#lyYFy&`$GbQ^:̣SՅCd#+LEHuHIH3R:3#s; ++ iam (C$)Brtļ|gЈ-xr1K6 >&Tv6sZMK' 8dhػ*1 [%F/#&8 FI=+1;]^cO B0TVaNg)3VqYJ4}rs妐e~+_Gv }7bd nʈKkĸN/DB@XmV iSIMਛ3oG[tې].A/A[y!N5WDi\ecC[2)UcJ^QDI–ipNC;ڞB?Eɴ\bߙ*bf8᠌$A඘Qa ^ /FV4_.L7#ʿ]%lN9 œ؅q fTci# G"zG ٞ8&|*9C$ǏhW+7T C t{0'>W YIbmT]#t]* uKR+ N(؄I>I\N~^eoT{GEx} 'h0cx]!Q\c׿`OOϝ>l`ej!_`U!+;+{ &_.ѺVY|5?!fˣr'r0/계s 8Qìw"9o*(eܰD=dL1:̼ 8kZ z4-9$ߐ*Vrd}fS:ޯhEDWP˗s?@W"úD\i@[C/TBACTuӉ}oimH"H(F[>{n]D]Ϋ=Ts6("!cgةk[1[̣Ĕ-3Ԣ~ȅ ">ŻAvW{E/D_2o W<(|ر:O9aųhX9rP܈JiN#x#1 IJi`v&%vFqm#]HFfoh~@sc%=GGGHUqtDIk! V!9|;PAAԙu?KRD ~gM.Qp}lKR~r1/ ܤS7)QgEH|$M6+cx$Gը$""HJwE%vDG$yP@mxیj#38FB7:Z390T J&EE& b> stream xYK۸ϯБD0 ˇx+TUDAb>dgxQ35*"`F]߽zG"C'|-pQʒeLmG?n+Jh?ĔFUj͔6eIHʽRֹu~E^S+mXXzH6s-*=t]V?X0CcQ$N$f#utڢ*%8Zԃ#:7GEaFmx+ݣ4@jj歮CrV:L? Jtn~wrcCVxrB>XDwiaؾZ`'Ӧ?f8n{ćp7rc=^OUBI=uj izcvJ:vrS@b@ -4ګJ5(cSoNm]hADG WhGMp;0Z;{rΣ 4Oi9N(( H̱Y[/EGW{73B]4=,y %uqf.4#D$r,[~R, A]xl`Ãe)B= 4Hо$ c$i0Q,hP$C9 pPJMШ.RRAfn 41n}9!uE%GR9A^M*C/Pz "߻))>6aéU[7}l}}[f%\4ex6_,i)E)0.ݽ{{Y1A)!,F$R\I`,jjas]pAFFSL0{^P%Hx=Sz23~i˯q'K]<~"YAN@դֱnL%0Ί5~h^3-v, ۓصȼ[lCsoCg:s`e{e]h s w9xg!wu.6~&=DUo0kla|<5]@sE-M=lŧ* ) A{Pa"^` !PM,=6t/#]=j|OJdޙCȕY5g[፛~ sT8_zĽ7Slbo&x`8qdtI8&#X!)AGG+ٴ{7-@8S Y!oCYbOH4ZMxɣq1d}LHs"Bzeј<4$t6G]j:V2$rp{֮Iil>2eY՟sm q6\]wx?~9~orh_{뗾3o h?97yؾ aaY9ާz (K0((DPu3.L ‚?VzGM="E_8hQL?rc8T' endstream endobj 247 0 obj << /Length 2274 /Filter /FlateDecode >> stream xYMsܸW|Ty`|T*ey#{]]GV*8frR~} g8o* _׍ ͔,=^=X2۷].ʺ}*??Y +-nϖn}UBefyozmRoHd+\THǷd>T*i>xYsE]Y+7.%QV3-o{afl7i!ZwƤ]}ԀvLlZg@_/,&Mz]>`7y Z@%誧V\>iӓbg>LNKEYH} æ.٦6.rM3_s$9}d㘑3HXJ fI Z8Y >v,  ǐU U/!܌4՗Hˣ9`K dIآGqJ,>CMs~SLRիjNȯ$`2/H\/3cwZ*iAtx'9sLK3 :sBM~&#7EG &TG?&ҖV>*$F1XHٖOݻPrr0zG5%ûH;Lɺ5\ܑR#}?&eRcX6Gi?L5} Z- ( Zx1 D$/*kX!N%̺r[fHc_eoh 5C۩XL|VMQuslͳ4I΂ؿ鍉ԁ~:BШ+hk?1clw}CB(Q2MC`A(Ԅ:!*j6HD8 J&Q^]%Fb;Gjs ĸgʇyʇ.ͶqӐf)k3hc.̳I=&V3TukC1qXp/}M39ZY>eB ͖) ~S7]VyBFqu7Vw8*L7Bw`Ø (ϓ MIe*߯۲-UP0[]i ߶߸Ǖ`F>Npa:fဧݪ Jb>徂RHJ?iߐj+X]YXP nPc͢\ L}#rUp4t[7Lp&$w? +s*/W-Q6WqM soZt6e v& ϺF!_ƷdǘMW}f_p"CYm[Dv~B1Ί F Z08՞ҊF I]^@!˜5k,."؇)#\QF]nG}^_S*h;MRp U8d\yxŝ q8fC) Ubl|dǦHb'3䕏Q_|U=K;Rf*\Gl?:}#L i[Aj7_Zpo@kZ }myjv.]Ets_cC5o?4aUb>$/=w[8fOx)ѶѴy?10yI:71t_*2W܏\=?u&Hrd&o81X(r[O٧XwZXE> stream xXmS8_GeY/oB wposw]; oW+' f9fz%ϳ\;R.ՎKNjSLw`?~ߎ<;vZ˕W|廣${jWS(v/iѴq-? #7J0L`֨Wyy 4uw讫e狲knyah,-;{vE>rWf]L|^*أ.38ڰ-f2328XeytxiT5;k|5)%&O$S^*V&.O ~θMGS:&1Z%rVD1WUt飧|ҭo9ed[wY ;6s>t%Tލ78R2t짍^VIp:7})<";8RZgvlwJI}+?)ɖsk^a%'EU5-ԱsrZـ'6i!Ả :BxeͲI=_ ׮mit&V <-P#wA>u"/M@^f/ jDAO˼^PΈiEvI/FExSkAq6aPHb#[ EuL]i&-E$o7[Cwm@`tEm-N;TӪbELڤh`ׁLw4^#=a%7B}KdelGI T@47ᓁ!eP,g20% ?b- ~EL]w8oCP  }Y/n԰pBD{B{dMTVHƃ CZ5tfjog(); y&m2v"MEJƹzdg%DƵ\%D6Lnx4c i=\ )V}-T\Al?-=? YY}8)o&&LPMǃZqz?54ퟢy*ߎc QKUr?Rm+(D_Qj$W6W/%[c ]{4G[}5$]x|k2jc 'k@(˛뢣WU/GucҀ#,ܶ= mY4p3紊Ka<.DO|e|[2ZaA৘ NLȲWy?0Yo˱N[Z䃯'2'瑵re6bdF,ufUwnUF?Aq!L &aE[[ϛuنy{ N{WvOxD F k>^׽}^t5To[+60ԆzۡZy/wE=˸x(X!f>{.ߠt Twthmޡt?2~6Π,bd$ЛGSޏFYp{ar 4*"؈cϕA9uE/XP|ԺLwgMRJB&y怲iSm6s" endstream endobj 147 0 obj << /Type /ObjStm /N 100 /First 886 /Length 2185 /Filter /FlateDecode >> stream xZYo#~Ճ ı!a'PHK(<ͿWCKR2ҋE"fOuu4ge VňW3Ơ8|(IFR|Q ʞ{0%syEr¿cON&G&C9'%* [!5VbR*bbyLdE'8 ,df;<zWLDrbB )Bofbqb!b]SINK.` ;o#赤EX$<=YȜ!(0%cRJ:8'B&O A>9+V:" BTpNV G 74JTT`,C*xNX(&)Hёh1|R'yN06(%`%1\dlauO$z^D a0lG,6 l_&(ÌK#C裈lx{=2o /0! M8\])[eW꺇G*O5z梚Ջ頚5n,}_ GX+tcS셃.ПM|TOJ9-l^ G@W_|~4Ʌv0b~05\ <:hw:mDJ=s7_e_z?I|4̟&z85k(Y_x̻32j덳w,GlD_Wns?,fDE=-֐l62w Fv\}4xX`ZOʹ ( G8b6=Lq*zbrן.w oTk;WW7茘 {,5lc凛_ݽd#˟:BW99@&lBdV#5R}67@=VHwm3ѵ ί Z)rDvHRo FJߎfHDu:DGBԴOuk idG9,9w!C)6ٶVX Rs<ΥzK}S&qdd'a8}&wKy0w˯cl#Un;l/ZZZ iήHu1FrTflQkBi;"Q"yd vnji_U=H[#OEw"O#"`C-(@dRffF͟ϴ(kBز."RR{ڂ]c(l_\$=[t:[n\6oa|1@62;3ayMveԔ#c5KE]1wlWђ-&gmؕR覛oʹt]Ap1:1\\ aiz]rgʗLy7K0ueֳqUX "_L±3Kme,k7MGA8g8N|“jVN:Yn_"F9Z.8xmC)NEZDu)$ Ӧ.5' d ͻ4?]ϛk~p\:U*6~zѺpB ߩut(%j#ւӷ1K,id|)HZфK/ #W%ZnDyH>ˍ-lVKehqx-epHRFh#`Rt,ɏ,:ij֓ Ia;Y|]^M1v{a)Z޿5qgv}'W4Gh5"ذrГK#,G0Đ5KNbP1{i..#FrDk[$au7$iiDz(*U? qD4zA&K!.c7|蘍AbiD(Pt1ȗI ãz wIg KupСs5O]&]!XhC94oV~n/zS'zRWD񙖨 si2 6 B( 1 endstream endobj 291 0 obj << /Length 2113 /Filter /FlateDecode >> stream xڭXMsܸWT> 7K+Xe׻T6jiZF|X4` ^n˫KUT*dq( VU`iN뷾[,I.JJKa~wWV2`q7ul슥a50 |'v.߹KLE)o]M^xJ0\-90m={wrCܵ`I/zeU~]dmk>FR PpGG^OCeMFd}} @zК3/:=ւ颚L`c;6CN]BΚ޿)&Jd%?\Z%`!X**kHJCyM~ wATB%2'3د2U hr ix #wmASX* Pq;Zr1r@ 7/c )dI.0nuy%ix)g?rdB T% NʼdJefp{zvɥX\HŸЉˠ_=Њ+Y+BdۘVfEL[CW9@fD#sJQ%`AB|~vM5K o.>?{vc !&05m`(pry*qݍq`~щzJ 4 JdzO## Ta+lZ5Ŝ/pFbbv#W nBH!f!x50PKMapm/n؆qj[Ʋ”s\БdTrPǟ%+eRO%y*eqZH+]LX HQ 5!1}M9B?~!8/Ra-O&dIETz@U!kP;6qJ P"H>vēi';WŢP]Xh4~X .G!w28voWb%^ϋ_Ce [@ ާQ4Iۭӧ\׌ZsL9hr"򊳂Zb0RfE~P!8y%Eg>]RJ?!D\iKMlf?g;(~ cO+!МjVUqp{ m_7 @#/a!UVneby+F-z 9)p4UL5Oqx#t!H ʢJ'uRt23Q%%rPl ; Z}ge7됍:$A?GW.?nd]Iyu^/MH~wHupd-io#pcxkc':FɾV* sLx,1ebZXz~a2uݸD# KA-6*XڰJ=&0›S`N&אdN9+"gCrNרT o: y]@+%iyV%Auk 4*@e[#'பz-{Kܛ@Gᗒ#6_#<=~URG}4_&~H;\T2* np.%No( U$X _@\Bnǁ*_!"jx_ E&#KiLM(bQ 0aI_zl3 ?(hiy ̟0m\2;hPZ_t$;Eؾ?Q<9 e-?qVq $9t&V.UlaEd8I W3&: pdHH.ʖ4ЕJA U`OX晔:}:Q8˫4f* endstream endobj 304 0 obj << /Length 550 /Filter /FlateDecode >> stream xuSn0+t*( [ $-8=4=02m@_ߥ(܇˙r}cefQLemf(. T1Pd?ʶ}hy!@+ 1dM:<;߻iHU)4{:;fVΠ9 vRDoM ub#eZ<m⼜wýkFutmDc10B8޳/5p:4?!n4Z=ORdT{XCU?hATžWg#KI/P,G"21e A?ҦLJTGGo`JJ iN5Q^L)D6>Ȱk&(9 R=6 X1/(L1U0HpLΣ0⟦ݹ;nd A1g|?UuhBT|ƚF+MA>e3Lds9s`ʥFhߎgoW^ ~ >~ fĒt'wu6 endstream endobj 323 0 obj << /Length1 1411 /Length2 6115 /Length3 0 /Length 7074 /Filter /FlateDecode >> stream xڍt4ֶ.j>{ c Fa:zDDt{AQDDO=5k=v6f=C^y{TGEme3?_/@fCB@0\?H(ucSn8@D$@~~@ h8ԓM9:n p@<nP$ ('MF`(rB%|||`7O (PO(j2@ ` 0D8|H( @7.^p{(p`u"kEW?޿࿝ 0W(@WE Ep_D' nKT AQ@O~fe" GyO Bnݏp]8 n {/w>c8 sc" /ĉW#?wo|C pis=P  D'!AP;# N7f_#aK~zQ=oY詚(qi_ @BBQQ@?a gu W7wDgC8.o[ Cnd+H7n0W?zn@q B]m=QufᎮH jCAR_v_ C__/|A\3i<& M,A[, $M/T xvߧc>x?A;.-Y,`NrpV<5 Ex=c%-U  a&[EG>y;wO*5aG=27BzW E[T -{K"&H<)VX#Ѐ\y%Nˇb%.3/ooI^Fp|0_a|OŭTi*_һ4Qϸǰ?+Yf!+^ĿN#/POZ[r!#6sNS>.+젊/>O+>OD_Qwc`i!pIQ+&,Y"]Wr} [25'#(q1 DS?"]zl/g'E߫^E[/"r1|G. ,/Cj7u<]-eH\↻@Z_a1l2O+22w6o{;w]yadTЪqs';i ^)U$Fv]'w!$^j.V~_ b2YaƇS~LÒ %HYD8z_kޕUdtt$V7%dZ 8dÌI̾87M%e=cbuUԩig]~cXÐ;K_>]aqN:c-{oA!vPU}J|g'R =nv;rcM`Hߡ:Am:8{yQ'˕9Χj[^1r(;俰Ο'B)N Tu|V--`:sX=W;)8>thХ*6 $\pR:؜y {z29wRЌ!ph;]lMs-gW3K8~`pd4߶ɾaMKw) {9zk&.zP`#@[s!%f*xSs0nߢTV\@b?ގ'qQ&s5x+vDB4a'k:9 m仚JnKo\;oyI+#Me >L/[kk2w pxn9H *jUYؑqlxvX FĤ/μ.)F$7D"CŃmdp~W. TyU ҾQݦjG/`A/(/+|uCLb"aQZtӣ'T0/X$f@W=_sn[<#+ּJg 9J3Y}eF*Fտ?yl2_Dˏ N\2 b[[U̼yN{gUFk*O#;b;%hȵwI 8(^|nCJl ּXqb3o8&a3Il4%T,A p202Nbz cwX^cN;L0T? eqHZ7-)a0 "Vir0m: !;<n0 S@Hʔ9jBbO{)Rs[/C ܿt7O=suӯ1H%}v ܓ O O>#iXplZiꄄuk<9nlo%j fR\IT2 a=E/Jez|rZ鿇60Ym"0c)%0n)aڬ6W=XcD"ӊ|-$ޏck۶9H8yMKsN#-ԲI"');#nߎyVӣ*G7L$TL&1R՚ΏڵQ8Ћ ћ$Ri[Itke9[#f# "?sls&xF*sXwP 8mh?`h%*ʱy7W/NL`X d<`!eJUvu q搤WKC3\0;||(?_ֲg5uV(d^lg|iz'6Um8_E?>5Nj> vʇͅrP|%q{S\qQ;sz$D7MەOE)%M!̦#'e]wZ -- Fo)܆ʁ tqD܊<5!!tA?~TMݢh H7ND^9͵ ~U!GVڵO -g;VX ԌNa9ȦE){}a_ %OXd{ mmji^Z1F}q g'ma(|uiN_W`/bl`fdc.ck/0=2SmÂ,󐦜Jl2VXgF? DGq~ϻ1n /QZI]M'HTAWp^ِd.*#je2݆8KK(ylj>_J}%u3=$%h'_Ѳk ^G@֮p|˧c%q*bж H>YIL&>J8}z'#eC^'<ǚ|/*U_0YFjH褁<'eG||ҔꚄs;.'3Pc%'+ q`!2@'d>v0n^fU If?`shh" :{G;ōߛzVyWtDs=>nrKcH\sNo07u;XgKiuR (ڗWX.]TTUEm8AFk;%Vʃ6'6ov 1UIC~o*%&xLw2NwT?f=/V6mURe) #*j%/r#*MӂsOqC:YY+z{j ꊓt'`*qb3jb>;v!,j4o= Gw+|fE+Try.:-4~m U&f: '`ILew\Xٝ5o,[mX3/ؾ]=m0HoK=CXByTFLO3bVҖ$g\}J%4> ;Ut2+W q{]%r0xR΍ yS3Wݭd*nts aWCfzM{@nv?WK5aEn*6j}&PH>1bjGR%4q4iJ&/`g9Nzd: &Uy!YSȿdϨI"*%Wk3qH$֧`ž%ϊ/mzSF}g+9^;x}KINڕݹ Ad)ͽf GH??H6W;X|wal uLýDy%<[=oj9~Adm/*?tS:1O?=~&Kf R> stream xڍT6L"hq (Npww  .[@Hݭs=k}Z<3{fgvJU f13 Xbcfc$؀ dGѴقcG;:YAŐp`O6I쉨;8ll<@ XX{hea {Z?:Sz1;)YV44 V`, ;'0= f P;]f-AvZcAhZZ9Ѐ\A`llov<АS@$0 `) w[ق*Ҋ,07dou<Ń\@V 'bjSdh98Ywm7فaNh듴r>;_kcq273݆3U,'Ʉ pyy8x`ԒPN=( 9 ޞv7BccY&` +{?wr>ɏ Iaf{[1_-<9\@yTAVX9{sw>mjvKtM=࿓)C t} Yw"ig[?t?~_':Þ@ 4 K9J`3+g@O fo$if6N v+'i+7Oi=pV`U+) Ӕ<]#NOrz9됲7>v.ntO 4f`? `eBO={!h *'JR#?7jx#,Oo j|Jl7o}:*|*_r!; RXmAv&f.2O9}V'6:>ib)jOOCU?ӖSv'[?OWM.F'}qn`SSֵگH\7FRtٙG Q`}RF+q e?{٤ gN=(9/)-(Lb/M{^RMc6$;cuYi`zJW"#خ]]Oʧk1:#|jF yZ<048K)_1u [J`Ty|˻b4O\=%Z=JnK}k2ltxL[U9Ā#- xy8|+VcJ *̸stQv#ŖZ'kH^neqXfxiDh1zu,N]t~yzcfe䭴J,#3嶏(s}z/kجVXDb3lɐ/ywZFr 82}G N8Յq@M$h ̣EƁ>0OO@Fh}$;]dF`Ѫ:xD+&t %'h&cp 8..m ,3}Z!($C6<Mx|F'40V[u]@Z ւ-ﺇ|,;=SRr߬O3/_'?ڍ kShiFWu#p<0ljK} ~ HQ,@B!- wQ6Ͷ4FgvX|k̽96 a_1U6ox9Q߳g=M4;F͑Vr>z*Nцtw f -\6, ήkM[XOPC[H?4 ۜ h;q}X6OEPMt'pgNT1l_ hŢ~)<ɚSQU*aYTxB̶<-9pžJ^"사 EDP/8HkZg/Ʃ>*l }ӄ 06q/L5J *RcOD2('3vh-GTMgDu 4 X(S b70\p> }uLmsq4d$K^+n^>CCo 7KY!_Au67%Xo';[!xh]?|ng8xb#`{(+*YݏӁ.LNnGIa#nxc]ܛiLtq:lnZ!b"XhK`ؿZ CdUxV]8Z]uu(a#\AJ{Yes sok%%HָJ*_&J@a^R~[fϩn$=MJxF:.}淔DY{=hj1 dj\&ެ£\68Bjy*<\w!IgUEb%*75.[}ǘN|?vbÌkL]pI,&鰥Yx#_43$y9֤Av۸|̧ʹV n'}\m{LH"l"(bS}Ktr(bpQD'oc4bZ uT,g?E`V@7 _dɩP= ?cNLFd =e ЬIVrQ8]K>m=/7 1ۭ9-Ӿ;K1@녒NY3l;5ec-G_ 5al m&iap٭pr{dFoSOXR/5`Z\_%VDC%v5)}SG(dmK%ϩΘ,/pz⸈R@~*iv@GGFc%ux"h0p8m\P"Xq2Z,ZUȗMe5M: Z3?d%v ]IlچP=k/R*sH:w>x&V^Cg}%PR6|cSKIF/,p U7m4n6~|;[Fm6>[1ez -TXL^:\<`\ ?ZӜoD : Vq2O/ogjaE \B$lr$QpCt'?ء?[u0%nь*?6UYa]brMt4h9/`tP,: 6&*|*5 c܅HJ ="<,m4 bŎN!H_l[Fd,hE^q+I3D)S du>GWbOZAR6MՅ.N}7/Fb;1߼ufhB#BRU ,GˎutdYՑ)3t2v5(z8;xdEqj3wjgOZ'<0|R_ ndP!~hTѥ+.R$%f~Xliĉ`D@2VĶgN? cJ:k"?os˺Ṅ3IamW;:eIdgjS =.ʲV`bh eRϺ$k^'NdنBy "{3" }W{N%Jyd,ZRc^ Q?5GH{~3hyNJ~7Rbs)JYE+Xe[o,t.sx;\UkeQ`iZ?cމA$GBͅf {yGSXȝ6{˽fn,C qro*_c#>CNFg|ޢoa(Wv]թ>];OeCȯ4S,8Ԛ8t#"sz.'Mqq#tQ*ыZgb*tAN_khosTH)0t#P3J!gSd=IA:ޡrNxdyKbA2_5L٧ZgqXxKDJ笄oW -8ƌ'e:|c7XJUd*l'E'lI #SN^6VxRXxT IOc< wԧfG~76 [ʭp@j`7q^0@^^cH^ګ1FgŅUM޶CA[3u9/JDV"Tu(3k_=>GH|'X~K.bN B*8ˬekVIYAxO-/ւ -x7-Nai:vQT߮Vz@>N[ʜ '"RO\&Rؼ^>ȹG_ȭ)|Gfc<=crՄ Fa>!&Qħr-\n`k5^@[Hmp%~v=)2zgzLrǖ3^cy:Y35TbYồ Ѱqbt7s|#1+53B6'gus6߹tndjlt<+nBg.!w2cxz-SgUcV촧*Ӓt,K=8 `vѲIkzKj]*֠!Ujvד(H@5^k.dDs}v /ŽNf,p4dDl&ťVDz9[VJ'/jSE,gه>$7AnB3~; hKXOAUC+/uJ5eZB&f%\/Ao^'8E T:kljcrd9Wi@Kx.:񔖪 !d(\2 "_եJ0{XEBg:0* Zbzp)7;֋w7R! ޡ[Fz/r}t+:8a=ga3$U棶e-Rtg,׃a(%pp4@kJnTF7"pnG YsSB||ĻE oӌD4RRHE]o`F{h7ݷrHDHS1^_%6ƱG{|y+MgX|#l+Ut䝻{Vak SjQןDJm|(acGU;1^dm(o#xdRVʾR%dE39*c}Q>mQ UMa~%B{x޲I$Wrܜ0 ?-s!U+07NgΏ2*9~ߢhp9jx MZe$nhZX_kLCl랻g!gg@^}8vaET>#ECoѥn_2@a6"ە2H/vI˫q6rJuSf.cl#:A 7UZ9/Bk ;QV 7+hÒOj1<Ķb o%xrx0?6 ) _Re ^J=} q/ xZclzK)]d05/5*T/JRĵnA3СN<(&'è]۫E7\_P1KD[+Hϣx7o-y&{akBkќ2rgˑSGEi9"c/mM󓪦7-$mX WAcշ|_fWM'G]C?OEgMWWݧ'r'L]bEUpECX/^mh+6!r30Z9ji{aǠ1Ss)JO4VW- )RSʏ^}3˅=Iv!ĐD(Gx ϝ^#{Z׎Em@15xFw0Q58l]6gry/*}I#hRpJhF0֍_^t3o$ҕns=GW皺 )p䡉3|(H<($%T%~!X/VgKNTr[n֠$n#G:=M 9,[ߪLS8X p <3hʁ7PW=bh/ nT?=c$x6f_D.l C?ixw?%=h : )vY? }T-JxE_Budi8ׯ;g}H^[=镃fɁ(6C*`V%o++inAF[F3'Yk,#: 4p8b,(ROߨPg rnǰT.7V%':@47)(CZ !Fa=rh %yޚn柔IWзBU D$,K}d7hVIqȒcQ!+B:*;ۙ`EZ w2g 7X/tiWAq;Ř\k2 2`(Nbe>^T^'aሞ%F`l ~>>{So%%>VMc5 5THT޼thjJǟA&'Mb$ST=Hlz?ʴhGo<<=ѰǺ *N )Qy,QAc2-QQbݻv%MyF}]0BθB?8 g0r@$MuoP7Nv=ؒnZ$NgfDtI@-+4qKYPPV\?/*l`7e˩ *Op`YB$1 d|oe|)$1? c= Qw jMXopH0 2NJԾ)]Edy Xd'&|O1Q*C&na]W'ŸѠo޼Jx}NBWqìu)_7죦-E 'ETo.\U9B9S#d}Ǫ7Beۋm+Jqe">g$Kx_ %rG}Rz|BαU {Q#D;}V/_OVP-`Ւ&6Us|ښR$gGO)IXĢ/~n4e7\?RF}J ׵,K@`~4_l6 AY/D&ORtAo!am5{ıH1Ct!KEBT`l+i@1o d=[8z(A~t\ '83Ih[D8ë)ʫ ERX7KNFudX#t$:О o*޺ۄjȩtVIzLU}!z3H}q89 I hIEدiCx'%+qhGWI;.?4QiTH;^yH>'/ol#yQ`íB'jѡhV4Ȣ^a({??Yi>Fh]Cp=Fǝzʁx2H{+!]7}jH;p8l|B+q/xuOX0-F ~`} #dὧ˝[͸C-f$N|-p3_dYx'\FQ1\t)z|'[޺`nrU#?1O8\8=2j#:?RX጗['H+_fSFa0hF7;:rJ>sT [y[}ǓG"=G_{.`{!Օz6W&سթZPlvdEyF~Exht41iZ݉}s4ICC`1Wfu댵ctvw﫶,xrFH~Glfl \+4Rib#@:K`n f-gYШїWՒJec6M+BA`]'QO.N |`L.\Y"=;tۑHKnO5{Ei$< 'vikB܈oiE6mcM}MRͯW 8G@@,΀U%?y ΧޠgѸM+x~xCL] ay'51n@v&=}yU#~ՂSAF?BJ1Od1yYt>S!:P9k3 5 YхW,'")A1"7vOnWGE RBS+s\yB5{nG>;uF2&u|7$JCѶ`[× E){>Ѩ N`e+s2źbe\K~{Em?6֯YD΍G 0[>pxmPo-ǭP'*n\!6]JY `PlʂKqB*Ϣ2 Uȗ=l&ZW?%u$̄^C//R"Fh98fe]+6 cńHVskg;aU<خ^(ƟtހM6lď 3$=jv*0$0,{(>ESJѭ:e3EuCu h6w2תN]i]-9m}50bDg\D_9?jF蒓Yzv?Rac&&V{RuON"fdnfYxW@c*CM\P P/Zi\3?@_dL£ܻ_Yu\(컂HMKf e/2H*Wkl-rU{Ζ㌑LX=iά m6iɈxd,;hd]Jn | >]u $,j$8CqcC)K6ڸf}>.WD,^T$"gƱzsKR9 peZg/`#S-Kg|U-m ɶ&eIMͪH&$J8 oyEeݲ!4gYHmp.kDbM-Bn |}$. ZG=݋\ Sj8%q *HI6dWr=BZŌӳtYb!9mw!Hl?!I_(NY2ٍ]UVT-]Hᡡ&y7|{)ɹQڅykF}QzQQNݕzBX ڻx`Ulg }2FWA.C>ّS3d8P{|8V=y3;P01{w&>^vMAdGjdZTTtt TT5o*}\=yWZdѝ^~\0bRg$ggf' Eg"as^"Foroe"|\Ԫ ytοʡ^BaT *6^m~: Vo|dUvs|Vq:B=F)5b"W2Z!Gf~-ezeb0 ,`ս`L:@}d=7.ޕ7pHTLSA.h@'Cm';j%zͣmA&x/9͑ endstream endobj 327 0 obj << /Length1 1415 /Length2 6573 /Length3 0 /Length 7545 /Filter /FlateDecode >> stream xڍtT.)"C 3tIt03 RRt4HR"s~s]5k}߽<Q[Gn QÐ<`^8@^CCE @x@> BP8L!VHO iaUgX@~H_@8@j aPw@+݆uCm` +u3@n }*kKqpH.q~ дrw"vH/+wp@`T@SQhB`܀w]oBPd+ A!-%u^7`rFQVVPg+kwV%Yj!lܡH/kD_eP@`HޯԵ٬ kAavp3A< * !(?>{ @o_}\!_n~pWjHCXyBHwHl6H5 : c<~f-~ML ` z *Vп]IU`ПnQ=88YLb-MAB M)7"7;;\>(z QЀdoh5 P PB٣ CJPo6i2 Ao * J_6N?!+JlkeCPr>a6p_X[V~`@m!޿ jך !) s\q;dA/!o 4F"Ա&JƋg}D{?̘g$٣8n1V4 V2wlהs;2sGA=u)dOZiFd9zB4mJjfXIDTZ4>Teӊ"ׅN(ٲW]b}}aIM/r@"q7]Gtgs$D Nb.Uv~֏H9s$ŭ`Wlx+Sr!9N5Rgw' wZb+dw[@ݥUڇz03 1e3xCMt‹{ƌ3dp^8$-?'xԲ)!ur⺈6b٢lw_~谽v晿-d+閥OvwR\<0 'zhL*1O][@>(yH SXA[7OmdLr32ar;!J`6nf% w]{&/*TI `h]VxYchmYiڳ%?F/m.ܻ~hڵj煼6eB\=>cSOF͊q1I{vgȏwI+0T7!91/[e\4|^)ʃ(#,qU˪./LlMCVfxa6PԞV/g: . Y T2_M؛nGhQnG_b?${ 9rXj.Q_Iһͮ}<:* K}@Jvy#3=4 .WzoҼxykh`Ri+ ~ % i{}C^Pm"mY cjθN˫I9hw8Jڤ58/]=6İuR,ؗedƔkʰѼR|Ϣ]B"|ה:xZҜd8S dc;:o "W>XiY9 aZG8UyLOE!' u9ce.Q*/;,r& WQ_,R-I)zGytM^h"cx=뫂nuHNf nh}#V~NF[3~!W%v0~NV Y I7RPvaʓOXMaz[,`-߾t`'7ԈE4Xhe~<{;bu$[([yy@P+eE)JK͟SU98&3LUr}#lfΫ`?"l G4πA~)Bc2ӯÂ$Y;3T꺔;<SޟfFqbS+Ԕ ae:ʅ04'^btܤJU8MܕJs1RN#XHb([) tid?,| o)l_lv%\Y) GsMD>m?&j.H"u)9X#PMMZPa\20O1@$CPBUdn?c!dIx1#m5ȺZf0skuMs퐧KЅy5D+%W0]ܩ3r!  M ʂG lɜ'vMRƝwyV`Za~Ѳ$/ʱ5\^yz3qZԆ6zmxwuZk;@#f =[0dD~jw"ͳ,1u㋰6y<黃O>ph3\U_Sڠjg9g^#Aq`{\ǻO\8+&RE m?fVqjL*DmX0+V̪;P~t_m7Ƿ^rH*.w1+YG{D/3qp6}gɝk߬ӌcn,x$[/Tlf+󂗤`1/EchF;;Jf|B*)qؖ #WUȚ`}b ս61ѷ<57N@݋{ɞ̧l‡D dCfEߚUAg" &ރCk|>TvfxRgn G5hOe`Z `ulMoKvnN:zyTX2#5r CXIzFI,w[&==͚1xOt'GZpP*'A_yp۫ ,NT:iQRJZڟu;ei}NfnrOXFT\g2m72 `k"};/ goLᔛ ~S+z6+M:X~vՄFU)eHûz6gN] [&Nfq9Oq<|K{_:,ՇU;NXNlԺ{U&p'1ցYwBƽWÁ[f›`NE d̷NzmX [naG}ke\UKk ^,d@{WƤrh=&Cƕ` ,i̓;`+T[;yeN+&KI:$aO#ڌ?%Q]5 OM@\m!%,;HQ@&OSg!HfܒޚI ڎp:٪Xb9I#%rMa6غ1=5|tVnָ1dN抮D ƲEl9_]P hFϛ(O]~ラ_MVdXsX瀴Oj}:kKz{=URO:|n_9>MIUЪFyʼVz~2m.NAȼ{Uh_cZYmI ih ӷ zͧ7@U6jkjA,S/ɔqA&>O$RƮ&7}ϗ /{>F9ƹXY䂲:AC,5#7awi(s'#6k$/fsEs'`{~ou_/ʹ"#  Z!C4˧ zqŢ5bxÚ]x7Bzb1lp!OnEy qKa[vK֜f;'7wĔ y)6A- yTtτ<6/_/7ϛj%ܒp7qWZ@#=ǧ՝&n-{1zɵKFävSP=|c}~)JL:_,:i)Ӊg.$K%מ~?Fv,GOOcP`9NQa)~@fyEڀڑ:,36eWsĝ*xӃdžL3IM>Iy5R-*O&ebpAQsAWZ#r@ayd}\1qҊzd_/ݜJyp?ec;09kO?0p޵cYt7(|p=b?5yZ,)Tɹj&W3]zܩxOT>MeLPY@j½yTu[[v! T@IH 2o#לzCf(u-B8ݰӭ ^}0e QBV7/\=tkt{L1Ҷ+ܑgHl o͓yQ ȎJdf׌ 5dҬP9Boy7 va6y7FZEW6.`r8N^*$#hwK\Z^Of>9}Znͣh"hT4$‛9Q,X/|}!3fEHܣnFSX۟Ò 6 7Lcd$7%ڡA?~߯Tħ1̴D6RP-,dbsHE^ٝM9Zn4fNm%i}A#>R'g,gOʓ')dj׀Aܙq/i7[dL@??cm& & I ^eMшEf:sӃ:nmƤ3x5^'cF;^W%: f]OeDby<~mI&Z }\HAAY@2ИR[kK8qp9(`.,~"v[cՑm{ QsՓT$ 4I{ZWA$#G!9L3؇O'KeI淌 ߣƂJ'H=Y=vg==LNiꓱxLEobGI3sq4[?n W-wEOI?hV.M@Wy >($ >qKe.=?1c8 H  #'|OٻsS`ƍlb(b'BۋfZAKT+\vi,.ZƥIUa$8׸~=B"'qMÖ]V֢tpqS@/dĦL?ۓ,F\KMSxrJ!.un2Fw+my1?ßN<4B?M,Őy^Pt^VrWLdBԿTǹl%wpWH8MC7sjjΔ&<&|_OIG#:_ _;LlBd@u/GuT>{r&> t(\{v,׋7T Sw K<CNuni1 )/kRsfzAǑ1CPfCQEHQ]q8 {nNmp P\Q BI6T ޤ(̯fN mG?O{|2)S aX"Kxi(bai;G_Ban..wR.X nxkƫ@3Cd1R9TAQ> stream xڍP\. Aܡ![cw -kwww 䑙3wWW]uo^UTYA(i302TYl̬`[_0&_bN@+&n~Sd]l,lN^.^ff+33 x&F=@!fdmi~MW wP0[^3ͬ`xM,in`+* 4nhb3F 󟸚 xl̀ W9 &#Pr4ӀXY@֠?ML@ K-$)vL@ Ml_M\MmML_  )0ym͜Όֶ[d%@bvv@w}N@c`s@n  k&]4@֎.@L^!0K :fVLë{8P_;rwX6!x9`'+-!̭S50OuN=W~3x=?ˤ).#IgDE^ Vfoq;_e g]"_Aw,EW\L?\;[j?_u.T *ͭ]W+6y]h,i4WYɖ?q[fk *;[V j}x:_) 9N)27b''!J/]4Ab#xm`a{l&y;Ss7Ioddbz=ZyLfKV@G`0Yػ8 0sQ&_ޙȯ_5Iצl]+kDOW^2$|=o&z,@?M;:x@; aaތ/ئ&JagT`bG+kmMeZӍH@- kE'ouoCTZ~y?ŨN ̏c2 z?9zk|C"хE9έ[ʽdi8dvGeSd!R~@4Ei .,uf =sD6(-KwJ:s;9..5~,ΜWQr7|Ldew֪Ʈj,Y `*^FL#'2% p5 w ѕ $E4աSׯ:Ǖ^ې滁B!BK7Z +%T$țv- ;EG^,y̺0]Ä'Y_|Oٺq*H:;ób0N NEW*a:[/f/ ?#gڙe<,hU!>`ٯ scySZ*j^-Ltˆ:WpJ)R"o nfM5Fj )P1s[_/??[7j-VN׎E߿mcc=Saelz ?D5 T8׬b^,oׁ$_ 8}LȜtV| ۶ @gvGCv >Z fMT*2D6i0o5,j%#Bw(,ˋ 6}xx̬ AeS 䜥$G|۹ZwK h"ℱo:1 s7\ OӺլpUUBxB\؈FY0z /ݕYf.cw|)ߚ|\X~!cN\^31sK]}RGqY`GjP$LLWT* c%\*UyJ3SFχ&8uvi@]>%+eig0^ Bk7KlJV4'N҉EkBݹrf4CcgrJ/cW@nmqYbMyJ7cZ$܎[,LEIc;t=ɏo)L `mnؗt*dP]EN$aqxYP=8oWDE  7bé )ϻ"\~mVG+ŇYm%tJ2 ٌu}A;e?с]pLH9n^ݲ)B2 ÷qkqL]mټĚ"4jL%'%b"k|^Ca@dp^h8FZgoLE0f֞ cڐ=_8K nM$pJ,L$ lSPƥztV^=>K£ۖܗu V5ED }4iOV OUѱZ$#Jڔ' pF5p.T*Օ_]ϋAN~VqMq.ln*F8lk&x#XFU#,Ĵ%}Q t}!|^+%*l|٭#aS(JJܥAG]!-3օ$$ԳM%| bKmkYёh:YBڴ_283to®‚S5 (to*:~8q6 B{[;K(g 1JR_~Py$O鋈kHm^\(Ne{s+5¤ i~w_tL&$^0KyI:{<[<\wǵ"YA!K!%.rssCٔB0\ᐨYޏB'4Z(UqӟXɶcxۅ҅dkRsnr-99m]E}dz?i `lYq]6Nf79($&fI9IG\\b.bbt\d_ntm5,gH|_ǐh[{ z01J x륢$?j̱ZoR̷Wnޜ@ #/n#`ckU9ҍt 2*'F>rZԺU?wo$BJ3$ZH^l뉸K>ͪuQH%wL cpDV`أJ5|@JB'$mɲ:y価"(W8(/DBVY+N5eH)?_XZ=Oq;p0* !stlJ.}U3UM (:"w%1]c((Igz9Z %+G(P54^KN~mCj'X2n$O#rn{K2ˉsfgHw 6Ev>T+cTL$ QOxnY9ٜaBrt:R4z-7:Ɓ:>O" Qϊ̐+V!V87s]ڐ&x3yvKn ov$u= |?fI)YOJ|.pR,fhq/1 cߒ,; 26+ݻ i}R=;єc3;AV.ѧzg&Kbw,z^&HsOS/*9'&e؃Gu=^OnUQC"UQFYs:5 k'Ko1b޳Mjr(NE_=Vzpu,W ?øCx.<*uJ|gtuZCQaG%F$ b}\Č4&?. ]=v7t,T4!Pq /iiHϿ`{Gdw -[m#|^Z$A,57ڌKq_uog2 @.`[y18n~c\d~vĸ'];a2K/1p"[l`p-T=9q3p@eAC R Mӵ4j.Xm%RGO^U,`t(Q'tRnZgh*Ob,_W°,-T3ʰJUNӳ @AYGxf:xG;05>]Z bzWP〸Mhλ-g,'@D]NI|V]i,&%=Srd դ)_`ZcO nt@B-KrR-): 3\3@1OL>lkC}[dRʼnh{T oI4|ot# (lFHF(I |!1oٔmrF 0X~@uJJ(#?X x\87IY?fYxO[{-:(X'Ks /%c6o7DT2YO~դ;uSʝG^9ɧ&VJORʹ]<ɝ.W.\,|8:<|IV fڏP4!hvy/+}^0*$8-X沿 q1UZW"Juysw}H4҃_Q}MBp]S6a-zkNZx9:b,C*a+#:ՈVx# .WvXmyzÆJ)#Էw ,PL#7?UŒ~ 8ZXX=@*N~(s;lޖqr<)b \Av)\h8=DqzH7*rќj> NtPMIlR7l9ƣ7]#֭.WlMf9נ=/(Z:|aLYq;y&Xg[N$]S.^X^Oˏz[`;A˝|o#'LMβ *GO~t92!&@ܵ7 A玺{6e%DRi+[y0!ش}L ?Aٟ TX`\WDiscDuPm,FGd #&_]$&R0Zx' 1Fustu'c)%?KOU&nTX=pi^3X,v D0/,hCïee&23\?NjnF(s UG}zN6*w3~4F=EAp: /@ ,24Lo %0o)EX6-`Ij@'A7VA̎z{(%+RQaXW+t\HO\  K) UXa/iZך hc&)h8_P f#1LWIk\ Q1RX9}s:0>~~0‘5Ju Ҏ F՘})O|#;ìL T><)Ƣg˶dBk嵢A0nG73K!,ius*¬:!槵:#3|E"+V}[нt-?SoQ2cZ)v5{-3Wk8(\M\Nxmvx ;n2ћ*U>Q7,I/G Qq,As5:: !1U%Noy_C:pqIȌbXeYT'.2$k;r_gʶiVu -9l> V縭N]:!8NI|"2bLa> 6HNO! 49v|ڑ9|刑 )naSqieJcmt 963! Y)UnBYno>{e^6La`}@b7T3P6:ThUQwPWT+ U{R,a4(&ݛK1įٓCXk/~laUk5ïNkIWoMT u*U,N^rZK/ yǪ#荄\Zh%eߌ'[J6JRR ckv;&(iWLde]xM"ϏbeO#*-I32CqS˂Gw Ro?|xKx\6$vhK; WteFGUXEq (Ybp|7}>3W `WhTF/Al2>g,k>+Xn48TK:Wz~ꆆ$O"$!X L\?.o8n ^EC%,!im-s(iBBג *EdIb c̩Mc"rXLDgJ~j)( yd\{qJ]cP!SnH.e;G"(`"`I/%^nŐ5,,EcLUz^ yNL+L]^3Z)ܚSU8%oGD1*I>#uGt9LyAB)[oM/Cf*T7lB=C%{<41i jxYVZ6n6}z_:U. [ L_& 'CC`q^<7E ZLsvbJ%lnW_7K­9g4-#C|OuC-9IY᭽fn[#d_S{c&[KO!y6g5cpB`)`j(SG4tNbHj%L_Rb> #VR(Obee ƈ N]Ī tBXfh|q(_+xvdXI4bp~b0=lڷn' M X|k fsv#D+pU{=$xef~= .KX:]&b:fk8@J})k=iGV$v*czTQ !XnIe>5whŸ20yЈVA " 7zYlH8QA-Mpm;0!S{0P ғ@+tAжʞMҾ+K)I[siȶfm\֙3ubd~j{1lZ!GeD7)1~&ŁVa?vM8FXˁs%aǍTqB3}@U_w_˰m20yd\yppvHL;#?@o,hpMX/Տ ˩fy]n[@OMZX+PN\LNHߒ(晄~ tK#B%O\G%ϴ``n`Tad>c='+.dH~BCތ"9/C5v)(ݺ;v.dNvo MzL߷BlGNwnQ8 ΁ȣu TUb6wV~hLԪ& ^qmUc$|lZ mUP{ΧsR}$cYUsBlxC?oY`rN=)R&;ܳQhANVtjiPSåuլ֘[57 myHTCwH/*l;zϵ\M~dQ310PFo3myc;=g(6{=;Qfa?L׍LB~1tP)A4 xwکT4蠣"*;8ub@5ܻӕBg#kI*|C9r!u;%~MQ'AK=gSǖB5EĮ)>!ݟ>bgI>1?锟%j (dpN=4bCy[v UOQ\0X^G dm6_4?PnZ[F#lBnHޅH9u583K1 9lW_IMf_sWUC`h; +fׁeC* 7z 6Lr6>.ؽ9$ GnoxmcfMTȤ[K (|zfӄL7vcf _N҂\E8qֆ3G0"Bgv.<1ESѴo{c[:\΃ <I㈲ZPo+c泂ñYJT_e84xP t:(1?r)v6X@w9W'ڷ.RU `Fh NR]Б W# gyW1+%{$5#NĢYp^9D-i{ xf<&FZPܻvR1FB-N~E ,Pg'.3ncp mxx0mżz1%ߑ2a]~8bӨ*jĦIږSu?&@-\'q :4}*_ޗ} E9ͨʴ ^wN$i#4]-GNe$0RZ6 ?m/?^Ʃ.Y״?}ɏ5A|Q\Z< .x/[ lm)L <âOMي % zgXEazPlu㌿Xim;qn͓c>`mmg\<ۤB#~fJZ'[M)P+j w&w§?v1Z6B[\ "JY;Xo-Y}`~I'$\wS{F8D__&}R o#%CF7~ZdŃo : NgE/bNծk,%3;DDR%;FUd7Y?;@SUs ?Uy_a?ADpg9ky0/x4Ũw*Vݳ %ȯϕw+tSJ~IEbIm۱N2-Nv> 5[PMT)!VAC| $,l=+ҳ.;Lgdd/vNUӀawҧeC CI>vf)jvoH>݀fWSt/a{ %(̟`W.9ǫ]OA?QnQ\{]D2-s\T>AMRG:q ܋[c~!Rvc&sB\O~b6i-페gS\exx3į}oҜ8o3x=9V}OxS $ZvptZeg$_N׏j}>~`lɻӫzyPhx-4NENj].Z$F PDL}Uk!#DʳyB=j]Hnj >7i $oK\\c`IvAzBDw.ÇGrی\EM2'UV> endstream endobj 331 0 obj << /Length1 1357 /Length2 5954 /Length3 0 /Length 6884 /Filter /FlateDecode >> stream xڍVT]$e$RPSj`f`r DBJIiEii) i %U@;{׺wk{Ύ}k*;hV"` 10XgzX|po~U ԠX|>B$i9 eՠ~gPT^ʿ@ "++#;c0( źaPO)c!p ŠH14UAPM>p] ݘhc6E`8oD(|/j ?zD] "7_ٿP (W 4`EP@"5z X=PhrvՂk7±@)0,# ½Yˌ?[ \_x;@ @g t"Pf˟=~D6O<-g43誙[* n.t'*.!qq ~O#(*j\@?o_5}!'X8Poۂ0M)z4|=={~Dx>ZUEW k@KDh F,U }>(@Q>`]phy: v.q)i #豈8^ Ph,>o/~ b0xY<kShͻUwV* ʏX>Ma}i_fEc:>- +Ms6^E77:$4&z\I!j|lA@ت×{(пK3l}ĊKi]ӲmË򜞎pbE9ɅvhFr.t!$ q6 GA}XyYmX8ޏ\ǩ0ĕJ|j# XHJڪV~fLt3;^DRk;t۸ 2*g2_^ &/ϟʵ?ǥ0ͥǚ^q- DeLA:./} Qڞ bT.8pNѱ/J";daZcff NF8ít&ŮuUŰb`WSPE1))9(xtƥ9n=yQ K4eLPL! &bnIN>g{WQԎ9l4EkK>bw$̈b{dR#}g|c[fMz |k.H>IƢPޝ/t/|՜&%2TXmL]}%ֳK:G nC&?,Y-z0jg6(𱟮LϬ=, ̫7xHZT!eh"c#{SiLͼ[΋iy7rt^\NX^tڽbHr8nx9ޕgrLexr"\h 7RuO$S dyYNj?=ڡ唶SX>p">.E9caIR<ŏ4vRUOjC^=PwiFn zx.,!feap7Hz(f9`ڡrZ.݊B`ǽzp"OT1c*I\{~̌kˁqzWfCp*OgY zP .DEE_#.3 nڴDD2;ܞG)HۈV_zO{M7^IR$c)SHuK(~^@*6ಲ+s4=2b6&LL `#2֜E[u8j b<}V,:d3=hk/V{\.ѦĢ>ڼMOkxkxJc[dz5żZ.~|p d1s ֋7dcVDM]?]snyxvVNr>HF3O{EiZ)&+ةm]f4>qK}`$JZl׵ߴ#r[KXS5LnJCۀ0 L[+Kn5<,bW?"8q ||mg|- \SnYuU޹99Rk [Kf3:z*ڡki~$bVy!,UB-FŃ ӼWIxWFijsgcB>q+m^WZ+5Hᴛ&^ZB݌RoS9R.xmC_ hwu =- DeID(Z9 gM_ AB79 GYȤې,Nn*款ү6cXuWn%d-eHQeN aZ,ׇ ߘr.v輁qiIzq:N9Oѹ,L LO'yn\m!^οQRB8v߈u[LjK0d|4/:ʗ- f]DOˆDi Xt'|k7m88gh6 *mgO .sʸ2T1$B @->&8s%"a2@o(gꧾ4]Q;m:r ~o{W 8I@d<(Ҥ+zVy%%wlљbɵSd~8Oԋ:S+MRiٓ;/,mi]•GTl4O{krMGKNݫ6RLl Gdw' x.72(Wo*w͑F+zr{ Ў}5't)"(t4h9E59@.t+INzq5$;6 4dj3QV[ic6`Wy_>?Tcu/h?0p'|MU\J LfKƮjt,ՇIϹ݃ -Cf5nwNbgJK"_f꒞tz.0X.#j3MHVFX{cЇ# WK`bUwm'c I sxQC2_k5E;+z"<_"'o(* BT,dlz;MfM߱eJdMTj. )nDhkm.樛E\2_`v]dG:HO%e0%$/K,Afvۯ'@]VhcRhUD.&R[7JՖ?=bŭR4y7tR2 kté95f~Q~ʿh9MK3eU/Ø.d$(i$pVayScD7N˛WPoJ Ak,FDWz[N`R-ݣjỎ/{E 0+V "'U>#%PuǢztC|FD-N^b_jvk!l00^FSSP跐V9䟃̢WD-%pw/Kk'Ć};LE9c!mÕs.%KZ5H26woo8N$oF7YBo ~N6X<\}/Qp}֫Aflg2#۸$y)Xb_c^D|'P9A3LخUԾmv;K{DcZpڋ:6SH60}y2Ԁ*{b>r`zӳ׼euHPrH҄MtbFI)p$W /B/S@zvUwj.SXC綾 Fe.yB4bB//L|x+v4!r}bnP?*ƨ|\f Jԃo9U C)ME/ 3T\ =iH$oG7H?G*y8M؀CJF;JORXFo?N.rk 4T>, 9 Hw-^c vk0q("*ML֋08}&~`pdr%[L-hXL.'2V3rHrኍAyτk<iU+ӳ[ hl%^]#'8@61fk\"w(.3ȅ9B"NTI[3á%[5eM\ VLgRy!|$alJKShyZ51R[$]kV#qBGˍAo~3)րSSm)7QYzBL厍 Ta¯ۿgdTwksw6HO͕ ]\Rjt KI-giB;dQpUMNF^0.8T* DTNQIsdL%zcfO:DiG =W6>!Q?JC/;OW'#]#i=Sl"ÌLچɰ^=H"'k2P(n(5Ἕ6_s"95QL;wҾ墄 os& F,aEri#׿{ӓ ||ě(xUKl `P +&J}VX^(U |R9AKKX/&Dƽ,aB\mn* 9<+&cQ?nr\BM&q5iOuƛ Gclw\na*.n0ݣ| }c4`7y/]jO}c b\Ky3/ *oԻQN .MgY<$a*fn 1U!ZtX%JA}fs:HjLUnGhY0tw[8BK6o!Nz-r A&{V|Zߒ\v )zq 䲗bJ']RCB?ib74gcvxBp^f~5 7Hx|ļ~GkJsdHñ2U2Rp9}s8 !-Y>;ijq1 bm vj[p1?#Xk}8A`OöỜ^Ϩ^Jd$*jIBk U7gσjAjȞ.~''Z3 ;h$;k)>$_ L\0n'@ k=?Si7ÐKt'H!y$X^eT-J3B +T54D f)b\*gS4I(@ endstream endobj 333 0 obj << /Length1 1461 /Length2 6563 /Length3 0 /Length 7561 /Filter /FlateDecode >> stream xڍx8m۾ڵGjτ^U3 B$FljϪ)(jVEJm5JQ5O}?;r>Z}^wrUP@ ( Pmh@A PC 8L0$B?P[SEH@@b qI  JMDKl` @zp("]}a(t`HBB;@"ڶ(G :#0DaP?Bp?pD\%m]<2<o`{A!_-tl]Z$9<2"Q޶PPZ]W(/_~A W ⷳ-tqE{ UD/-mЄߥTv<=`_= feDE<~էs+pHo+{b 1 UWAC((PBLL>`G_ |]atHW= h  P@4sE 00 `u! CZdV U// ,@ @\\8z?u: \>] p?c ʅ-G@Q ?O忢BTcѫ5o?Y>E*5NzxI?[l /Ŵb\}%G:)9k\g vmy =+̊,l37\$g"s`Ⱦᐱzh}ї}1sZr{Yja)5^ /y%M79j˞ɮ΄{H/<UIStEDb6۷F}KZtyS[$U~$<95nEt`?+kM!mxw&Ǜ<a{.Z끗S/,Sn\at[4/9J\W˖Oi1?daY,x=:3j53nؒ><-aG gxxPښO6`[ժ/!lR ;iV1Yb 䋅^,uꬄvrJK!@At'0[W`QWzԧi bPCG-:EԡU& a]ٖ;DvxJ#XҍnWu)+,V}݉ -bRw7%|Ւ}]g)Ntq#p˪9v~lЏެ;u#bO vط^Ht|W;S bhi"z'!57DC2Qm7O'c;U9ZjZ5NOx2.}FڊsnPZkR^1pՍ H!̨)"ޞ;69P{Xٹ~o{azJx )yކ7Jz_~N:e@J‚ !Ģ|淩ʍ汒fϘPsXjy=ņ^:_TJY6 iĥlroL]U-j3[vϷ>Uqo8LPEۛVyH'T470<%Fs=@צX?OV߭5otwujWF!>څLz1 ϡN o(Z 58~Yxa(;i:DEAw}/Xrk4e`+cέ]Iܛ[~8mFъABoQ[2#qJLqcO N5g>NqG.@3b7 \;Vp |8^eѻEtK k,~Ѽ/S8Nt~T#'iz;|| $ ~6ڳWGe (%ǝ}AĶraAo♇<1E}'G^|b,4*8(94 ++:} ,g@h*T_2żNس-7>EeάG |B{nLE"0B]]kTx+˾-gzNAF"I,{0}3o2ْ#ZL#Oz%9mڀQyzk5ywC4{0MgZํr6FX?mԞJޛ5BwxJ VveQr$Rp;Q?r0~5 ߳0u < F ȖZK*_-T),J8*m(01c,HJ`00e) %r" ~ݘqq=l[K>ڕ )]ӧܥlrHB:I,r癿7N5y{v6r*)V;^ Y׈U8RϞþ|vEIl>7|Jss~^;&X2J>uXHV*.;)T۞ pG ж7rOr:.y_ȘsI~SްM(\).nV4gU<@%Xt`ѾN Z T0IupӃǾ\.?HZwb/|*Qm8\ɔ!+yd@81(W:ֹa fzFcg-6wIsr-c |CraYLHyL5T;dn5\duۑ{nyo l\𣆬M4]xȳ W~l2*!ד['R:U&c[_O˓'w!(?hsI= q9^n}񕋗,a:X_\؅'ox mu.z ǂY)k>scŧ~[jɡʡjbAW 쯤 ͕݅ȉy,E*Iv18x{>I)B^f vՂ8]嫐ӓuE#kJVa3lb-iO؆*'Bz|^>AjXV($/7$J~Th6\^WE^%xlGh˙~͡)xFqkƸoD߳'Deq&4v?NZ1w?/cWksۉU :Vzc9j٧ޔ6Bw.>څD0E|mNL[\oAՔs$oYH"i=pKAd"")fc֌v.))&5JLsٞqkk~*|~Cx|Li۶/HOhP$.qj֢'3p8-)ۃJK548 +X q6\\Xށ9lV S u.)UW:EY( _'P\fi* >e# \,H}>8gBQt_f㩊!^tO1#qϮYX=WEҎu#X;fvHQ}77%TJJ?AVZ ?I&G1TZEi\qh'.&F4yEN?o[=6Qތ9o Jا_m:AE5U޴8UD6l~I!Ҋunj7C;S\SK~_3pQsP@E|}#jg8m 򄣡CQ Z׵CeK:m1+z޽1XVea6͉n:{~n)W6!{`^zm_l(K]3Wh5k\2R'iIR3OO%L*98ď7SdF"lI~r\,Ygp-ClNOW*q}cP^>Ӓ$jχw^AR*^mwFZk|>qyR$Rdţ뎲v/1 zRيT^īnd c-/"F?=˹e;<͎ U-:Of@ m"q|Me7d~$lmݴB?聯x9'G㘊7_J/0##VH׵StuS!ݍ~K(J'ttN+gueE-94*A!" eC0fF]%m_ZBC2޶m[R0ĵ;+=5Dl&KSřqHͲ.fjF92G5ȑQ{2Z\P^UbuW"[ݒ'qDϾtޥ'1" / 7Yj E`oI^wrpZ }#qޣmhRįIyA+Zy2 kz;CϼT\X:eQ0 D$9i9IJq:B<{e<~fYAI='/oחW[a<Cu]oױ~Ob`h Z7{W7HL_ߟ)Q\b5]&0^{5y>~.2*@2 1R$Tp Hθdv1J7d2y [m8~$$:_w-(煘x,|0{(fnniSGM8]xY5:(v&:n+-|ԸzO.<{I'ygxcG seƉH7Mt[*~7b|?]{tmR'nX->{='k|Sd)L/Bfn֬{g/bZ endstream endobj 335 0 obj << /Length1 727 /Length2 24192 /Length3 0 /Length 24786 /Filter /FlateDecode >> stream xlcpe6vvm۶cN:m[}99_[֟x樵jι(ɤ@^@VFV&>+ Rhj0qu# Š@ wprrИв31vh99[YE]ܘ݄IRV@ +$ VHA@g;@ r,vQf sara7;`EI Q)e% 88dP'O4_1\'ٙO2?$&VV+hi B`o nu|8-vS2h\Es3 `gt́6?&! A]=*֮PnabUk>*JYWs)O3.,-*&E1[d`n è vXg 3`'@_C習sadc0rXٹ~/fn@i' h`j^/Y<_M??]~|uJzVx.Tp|G$gj:,p๔ҿnU1J L *5sc=Xn#;NΩ\]5{E4k iZCj,O$>}-ڼUXѥ:DDA.%UQea^aㅍĐ2O|V0T1@Jzs<⮎LRH:ň^zR%,vS=m dr@Wf=V™fύ}% k]%6Kgu:ߪ,NMsv%rۦ% rGXֿ[h;`OB|zR3"gapoХ+O00pߌ™e!߀q *?9\f,*Tpjim6Cnt?Y2>>4“F$0],$VHͻQU1~q-p yH]<\&H7A(ێI5\0J7>Kr4H;Gm( %p8#kʘ/_ti4RIG>;,OZ(PT >:/\8R ong5W-9q+b= ϒ'^T| oNG<IzbjDٜ&'@Bޓғa͜C?23[?1kP&LBd]agn!X6%wKwIXS|]q=>fhDLZ)5@½oߵ> ~J̅g)ZޑA޳8~ mB|sLKZFҗnUKvW<{ћ<ζ $+)b0clO}=A'*5}銁2 JG>G:OUKűԸoyO9Jyq&Z0s tO*((Oo{ҁP)9+57z*I-,CyY5ନ cZ2W}riySP7y ɕ;s|Ǥ"߿ܡk(쉞[c7HZ#t˖o;Y≫.z&$a7q;O)U;иhbWlӟ([]Im4 1ɄlvpHs\g-q7~A)ӭsIpG yojۡ&ٴ;BòuQ ܩh{fd#h}_QQ-Gytn(6| {'%-+yO=g?7uPucb9UlWUiG|(Du32/Jh2B!uz%r$_ӕs8o+,jJ.$ps:6TN  bӀ,,YSiH|}\L,O|*{1S7Qi 0 Ѐ AcoֺH>r~(u,nj{ԈR0Ibl7s(2Vw~` /BuY MQ(yp Lplcvg)&QRZqoPRK__g uJOexN̔UѢF煟v} pzé4A")aXhhl ?1&c|EeFܲoJNH~4R'4"w4PtkHRߟBV5tҌʏл`o[_B CzQ1]eliŰa eo]?g)􃎱q']*4übuMܶ=qԳNYx!~CDOyoU󨛇EÍ)MJuy,/S:ނFm.hr_IŤ9iujpPQp鰩ǺTq⨟׼e3ʌ^Ru'ZYRF JmjQØЈMGf!ЩqҭH4~%R989ahsUVϦo9FQ/m=;,~yLh++cuFe_`a+l@Z\~mT܋7u\Avē&^s"$2X5:Yť>b.c~CnkSPiEKzc[+>؊RQFu2~Q&mHu3a`(GC9g͖pB- XzUEXZ x i!U]Y{,z3bp@`$|CozRbiܞzqͫcE! m=2'p tĝ=Fx~i tMROҷs uL?-g7|j#+Ӷ-Ȋ^e_;Ǵ\%WS 7HKk[6A.M"-E"NL2o92B鉳mh?Ev~CzZܬ1.4׽_R7 [mwM> ~B,0Og\ S*ǝh\Yb%$ܕl]Z9'1HqzP=E#aL߬Eh4]uyE T WRFQ^Iq%Ѩ;VT/uVuvEL fƬ]Rq=k44J ~s_ab<3jCR%Te015k6j!YGi ,\\]^rdo28"iLL~CW^C3]e+h"l#  *^ۉ'~slAq`pSKyofڰlѭxk"┈5]=u^rsVCU q| G.ek^?΋$e/ovxLJmYhfDsxT}fẂU.jJp `jNbyL`pnx7|5HNHhLmNp:cf~.h0Fr @Mo&3}w1WBDy $s/[Z7oXUC.ȧI$άEorZ[2] 5,B#u.ܰG^Yx}[Pa§寡;] E)_>'d/xWkvBu7)eDf~NYWϓiRoa6X{s:om')O| !;ޡxu<-h0# 3eoAycORnV/l Bfx\RNľ>'? 6ըr2Ҿ^XSb ,ܩUs)s.{0 ߞtpdFnRV bL@6LmN5,>4E, Rd[bDaW@2B0ȒUk5*M41;|ӭzm1$>za+Xp ʯj߬-EܨG].CGe^hn;w⒆AyڌbUp Z@` k*oVnxm,b<(4!]Z=;8;8av8JpZyG+ޯ61QVCf;$-TVEDZǶwݘj c#^CՂ.?{ns}MR{7TricMM\ڋRaw˘rVZ.D\aY4j?8yVQgܑ[OCUi1< uao"@t6[&>dw>Y8d1%Җo+4Q,籪oM5!jdZ@B<_$p}H#u85G[rO_V<7z(L*&%<0h&VS*k5s/+mJfmfԪVX9$[p3;`u)QH>~M3Sѓ.mQNGZ3BV%wh2) \|`(SoEX-9ΚͫR輨ፏ7T¶͌֌E"(yND8LϨZzЍNe}+L"A E !`X}1߆sǪI>3Xhp rfX` R&Y[rshf.e&smEvgT}U CaU.I&{ѹb8o߸mUc#K.n\*RβDqsBrf\UN\4cp#  m!e,D/iCIʛ $J[+MOvx;<ְӄGڵvh̿¥R!nVs\~$֦!|ҙ<Z._;5㹊4)^՗ hUƦxGBjJcת:GυY [!kFs/&UD?]wVᅱ)">*|5[6z)lksy_P3Y.'*OR<5O\0bQ6Kʌ,G u,Pư3_+ژQ w:FN!7L2`'SUϻ|=10MZ/׋ '{P6X}W +>LS-`ngTTK}=>6̠UWJGt&M  uH<^1hdVɭ{?bRY( 0rwrm|Lz[Q K^GD\^^u"͗-_(j,V{ m,a lHA|ꬩV] %=oO|D![)3Juna^NΦ& m]郵BRYq';, n&/x;)3mPF^&0JpˈB|[چyNhL&uŸ6v?c#F.> l5c!/;nX|ԎRkZ:hZ3<޳rg?3xF} '}%M’q靘@49?U>rZ ̸z8M)_\v[_~0ԝ?~bm6LwbAơ_nξ")֩8K}pI[9tZ0<{jL:ubkh3kliEbQHJTA87:QkȅU1NX#x ӷ0vz=\nvW-Weso(Ƒbz]Pĩ-ᥗjvʚrΦʙ|סS J8ˇ'cɒ,7ɤ'oBWE;DnQ8oQ1mMNZX^0E0')ÙSs))CXzmKNåU6eie>b3~AiDBT=yIZi<15)ǃ?- vԄ|Qm<5˧-ػ ' 9SS[K;q-xk0=ZWow^B^>~h`꾽pZve>NjfUsuYmb[1"DO;N:bg Si0;4;Aݥjc\%K`G##$%-_y#u1v{z2;<^YB"JJ*KJɫ DagD<\nzQr?-w S4vݢ??tKbR]0Re1e0N$iW)ĘH\pgfʷGo4<?ؒJjYZvgy["`~Z"`c\Q$J_ n8ǷW|Z]еғE\(]'ӚrSH7q cv$[}dg^5ak{1,[؃b\!4OZKtO#DtZ*7T:)4t5g@[,$uO_BIun`;年^BOk0w3X3?]2 {71X( Vvϡ)UE7UjܞhX3\$;*?t{;n,V>ߜGjn4Uv\VW!kXN7OtKCPr8%/.5t}` B Nlpd"~ i\aJPV>a%"qDaQk9sr{wm+ܿk­ga(NYeMy^ UxHiP]ȼ(q^gSsTS yߛ%=!,Cd2Op"JDNZ[޵CaҺnB',[4g$ni۟<ϨB-@ExW<`*~j:9eמ~(\AsTt%<^&)LvzTȡGQP]a7wzICC0blImz,cnb }TO0GMilF,N5ׂG#Fmo8"4m/slP(8)f}=Vbrݼ>h_vܶ'w$:Ob`4|g5Q3~h;UL߮!}688pMy\!Q~]9DMeQY-j7[dv!]$y!d)~c]OCfzl?oD 2%/*R J>W}o˙ &Q<+qڒe&VT1漡x`+?kNS2gS]a/,?&A-w8Af% fR;_jgӰ68CݨH| wY> @];pX oȏ h/ƐGƲH[_TυE8syfvrf hЧ_б~+ae&JMp,|<^[^ , r5Kih` JN q#*@t(klJ + z-0dX7ػ޷HZ(}7+=m4t?}ۅ#=jýh nh*ź>q&B_/aϣ a!Z/28⿇5|DhPDʫ[{ bS@R%U[\GҟAҮ#J7auu] =1kw ۊsG j1cEچ 0FƝ&6o͕L[aM6+^vw lyv '{4ŵ01 ݰ昦 4{uo¥Z=ESJ(~x04yN~JJ*'\ KZ}+H$IvMlq~)Mn? _;c=l+GĻRrqQX5J<>Gd*)KN I6IܒRVJPw]a%|r+4XAzc'ƁIG~݃XrT{,gy. :s)ˏKGmZV瀸÷;4grXtnN6~JDU,W =yڇu3oaqZu(ɩS/7'dLJ䞙?SkB*ؕ ݘߨ[^"'M!XņK*I>bG`[ޣ#UpKءJV^jgU9>B!m(-6VGKbu,iߧKSS烏vxwM#wuA8jD4=x{B9/ Bo"lV“7$@9=x"/I0U$_,I0z'-v"m8"H#y*++>1Ric'c ?7cӿ$T|;!GqU%i!G1޵cm[`y],+<.6‘pW*$ xfrBs'R! ?~ Fʝ~'2*|Z^3/iSi+D i}.-TȼU|w} SwngjbY`j;-iٜ7$X K%BL>dOlܿkQt}ڙ1LO eHjf<*+xjWOCUJ<|⟕hP:jV񐪙0 E_2wЁě$ b7ej6RL('mo!=v, r^f 0L! ' ap 'ͻ/HwBɚ 궜{⭦ƿ:Z]> "pwL*[_Ҏ"/oIۉFF{?}Y^,h7|{UPsHk(D]ӫp8^[–/bi[uWbybٿKRK,& ǘ)GUFG6@nA ,0S;Ǣ,rŝ.|}]We!v[ҸjFH< hi3<+ָZ,u!u~mlE3y3S⒢gÞ=b4.Au'DO*Z'z6Qs#՞fP(L;O@˂R˪8k WoM_e3@BRr,KLp-xUlk>,f頤Q+|C=^տ U)kovq/OQ ؒf5rPZB*QaL!RJ;~g<#-GPrCPP5~zE|o`UrAU sޖ{.h䃐h̢Oon| l`%de#ʠEbpDnD:%A)d8!Ҩ2YBgCexʺ7 cgf'Ty21X$۳,NO퍱pdTr#M hՇ O״, >ݍ=^FDZEO4̨ \dWǟ97[uF|Մ(VK. TqI'䊊 !,% 7a=)z:S5ң53Z=q՛Y1Qr*Ha"Ӓ0߂@p#E=UWcN"Ree(G_Dr8C"yFZBGS -h0>  F/tavMquv._rm宐RڑKAZ6JI\z%ְei}׉lH#R+tD& #|WJX us3_E4dWT_G, wiPLX]e 14+$.lj쾓[]?IOR>cISk[x O0 s<ى|rEZoyMɉ1dIGM_loN?Rɺ>?XY=3-Sg4ttK9(lAC @]ID$+ܨA|ꤹP^lwfX(upkg|C1B`uhŮd,sm T;f n7ʼ6,KyB1szhͼiHӅԠF{TW]1$M_L<@HDEyt`xZS־٦4Sb|FT3h*N;LSk uxG$,e9p8SS}nv?9 jLcUҪb<`T/BT; a.j|!e{螇gnKBB?$cp ֝ȧlח| 3 M'/gT?'TTr|(ȇN n77$KYMPnEzë8Xǫ9,ڢufJ-:>r.6$8ڡ><kZLEr&QmF3NȶLռ\ImnVM[_@[Wk׾QIyW]ޙ04/6½Cn;>f+b Я<\^HEC [[b|^ )sʔ!L?=h/hQ,k||{)xu"Б gX_;xqdF̥l!.@:e1q4QWu9Wz^;-z&?KL$6xj:yh!v ޙu?gRy d\=-:竈;fR baRb OÌ9vfVGs /77q ?E>לExRʮ*V }?gzxG鋀:D^5 ar!}=Im x,;ɵ2ClA\VwG;dj2hӲY@T+PAe;Qġ-Х ~uX2N䃪F`%Z,eM ]dF$%}<~F:F'-0hmAadTPB$j6*kJUyԦQ"QDIa(~YFVzu+ghWg]:|fǾTe<) H5*Xl< U`3$,ECZ)($ȗjro Qj󙻭yiLZX#y|_4 0ҹÂb&$90혅; Xx.O?c,&䟜wB3dԻSN&(G>P0Sn 2mjc(C\x}D콅u]/ ȊUNxurDf<̹W{zVLbH,4u@lIۅãsֵ(Wÿ\uHmXGa=^ 0}Q}DDI %KRn"OƚOB` Mlu^t 2bέTR]GD3KkSsAnꞈLQݵn\DKR2|x!5YZ5g ]P;r<)U⡺ջ QAԣk<":[J8FI˽H۹}X3e,3{`*Lbv`\ L'>T/dT7#T0hXOTD.L^KO;~&uWI,SdK)\f_&{= *T"O"@kU^Fշdpmf-j)3,vSsKg:`I;@6*xN;U=Z3YRecu@͑xBNXMWB?^Ҥ{u1Nl&#}(}K[Z"P+F̀+v EE_ ^}n}m|X˧A7KB]a, zȸA8uZ:7ŊP-^MA1_R}ȏs0¹}6>H(0bBmTw GF]kHxO+ 7dޢ֪l^#j1=QI͓ WXM͕wIy_-EW NϤkMC3~cWQZcX{e̡a 8"Yh)eAm>[PmTR*Y)F ѕ<&w[gIR*Ѓ{|xe'-&eL9+ tvZ'S3ϧes/fx~dTJd3+ m2KVju) E lWPre:fktM! },Ng_+ES<-*0CB$Ey.FpOvӯJ(50Ɋd;뒹!po?%JH:Hb༴ "=z^yn?]tq y"dwJVI'}BBi55"/tg+NӋ(u%"L$@lGM} Јx6/f `H_T%=wi{v_S0q?mIa\MhRE؏* #p دBéuy&e(i 8zJ d1,zT w=#۬8ry@]d.O"GiN9a֋ImW-%8Ł:Q.k\Fb"Yr0_]JM f8b+ M频.:y*`Y krMhqu .S)^gWǥyjyKOcxeҒHXo F>xt鴿 &焣nNɉ ^&Ӆab*8tU ޻=AXʤZ# ҆УEכ͸D S!h׋< _6=~@u=5~P\ 5|XZ9=H7:"n}}1 YXU'8[dw$ yw s"ѵlur9qmV4*^ R,15Jgzc3T%A^bw7V%\bB!ezPL*|JD&ЖkU]`@k#kB=?y;V]Àd ` ?SVp84_H*mGVWKHrʩ Z'UQ|}9Q6OQVj^K'$$:TnU,N ܤ֞O\0 6u뗅eԍ_5G71kY7{}^ۏKڵf2R՚O tZ+` kR/ .>˦b }Wp?$J<٦T+a NMp~zc᱃ [{1 J/`q]jɺorw|ܴqB ? ]=́1eH(F(CZwмI/eWoDy$ErΪ*SvI>O6V*-e~O쫊f:[9%I3z4| ȬP㸤-OIϯ00GY?([#C e T>t[m{mޕբ6D3 wn)n<3ݖm9y&]A_B/,n*s1;-}$PXe O-O?]zټߒ)kp2HQĹ[;T[&N؇:@(P[w?@ xg&~Yi L]A 9K^n֧$tD,)`@iK?YJDfCG=LAsᮣ\P=sUxd3;p {,˜B2:-_o|[ZǍTnwd G_dQeRwQ@~ .L`4S)f0c$D*.JxVdF% Gec;!U5PJ:O]YD-9gמ u69N}uIn噻nQ-`wRJap݂S8o}A m{B࿧b>% %D4׼_iu)iLi/^ct`뇲o4AP|>C{[.e,!h =?ZA&qQ}% 'с;NS;ţ* [G2/Y 9 HWC2b29|#5U1*nôe5jJ 螮5)BjOH  N䯥m =&@$xAPa=Dd=(fl6ry,{D}wGʢ< ekGB9 kkv%šy"YYj]OID"!%D G|lNr1EJ}?%Q`9Q'*ȗutق ! eD%SkWclqAh[%e,wunKPĄE:+.]438,;wr=;Cd<<Wd[2N]r$=&(.PQa9^*1f;A,s&("i5m7~ =6'Q5DEމ|&14A_?}M!_+$A}J0^xr39HǑq?p򭣯℥+ b4`,/y۽˜8TJ|s`UhJsȥ?vVV]S@pe ?5i*ňJg^i~bN?4Mxh?:[m{*L() GDHq$ፉSgBb* ( (IZhLS~;}+I%F kfv/wu1(WWNwYd_s`k㇅a [~"KjbqL7;PwϪP͏Z_-xl LEJ]dxnʈ׼uڋX9EYg]`fT([ L)749a;>й9R'n#J gsKu` _"B`L=4k Y (@Oj8IZBY֘i"U(1-$ޕq'".7$0SBssvLGz,^FeZy~=kS{?eݴ~LgR߃BɭphumubJ]e1(('e6ΗŒOxP`{ұdx]״HJ[)fcUCuuEj ͜SEUǨ7pi<:n+eXc`yLe8C>3π]WhG"lOG#h eIK2נ#T>`ݼ+∇"^(0Py="v\zx̵PxifL9.0!!IM3(U$d#OMղS0K%=Q yc,l4·BT^;>XBBU q>/W0qTr^xga7'1eS {i>gF}\ oÝT+ m"PP‚n6;+f|z+  0ޯCU YݍV+(| ( /ǸA!~ZN@ !X4N&JF=>h>yrUiڻa0kE^u xdS O[́2&BH*?v"4c}zW JP+d3pv Ȅ~q 6 P}_*;7A)*~'cgٔa,XJ &dWȐA$ <><Fy~S{ˤ U ~2vu(PBoQQ [;+>w#7b~4&el/Q @+|[7*_2BG6T(U5g!mz]`fHܞ:ksox&CQ.p38S^wZz:Y@Cev>Oiˁwe [m+I!º%w |ϳ bI]Rxx63Ra1~pU`;`apU]>Ʈ08e3 R\=4ly" XL* T>=UyI{`1jQ(>3HfJ=y73U z.̰ߩ ,SnJ9'γnzR[K !:e =2*Q<Ε}S߃ (- (>ՍV p&A'[}ۚ VmOiJK1-sxS C{I؝bNmTK}6?c>+@Whv(.!lHPY/m2R?|38 G.^%uN.cP==^w?<AE9`VSEU4٬/ST|$ ,d< #: bE$rh3]o uazNfW}iݚy"~;źP@HI endstream endobj 337 0 obj << /Length1 727 /Length2 18492 /Length3 0 /Length 19070 /Filter /FlateDecode >> stream xlspf-t̎'۶mOl۶ձmc۶mup{[W_&Ƭ9XsW6)= ,&`c%%v:[ي:@2K p03wPS;P64pY۹Zx\]]\\])R@5 ,))'Sm#k c1 H 0sXٚXݿ غ!fhgUS ӫ mM2:;qku4 2`&#-,t5'lb?GCJ  @!lgc tڙmBv&Qwg hC k_EH:? 2'd$f4QpGrSCw\WT ϾZ{߆,Eԥg 535(;V0 g |YCgG w6ݿ_-sebb238YL>#߲' h lglZ+Z8[A=;mJ2sl1hnxs?`Ļ{#y0<1MZL\a[Vw mc,~q眱@5;FʡY1ڠi;~uVR%S O]4kRpm#,/h[߼<0L+oѰ|)d.Y=kR;|Gfwm3 W)(un5j롭;O+H,d^DSM#4AGmgx[=2i4LHˢ&]|@;"_!ǟM-VleSrEHA) ,٤MZcWx-/.[#R9[ <.Fj4 \Y6ث 4R:<<٦zᅌA`-(6Yb)*ҷGJ@$tO.|9`W9oH|XĨ"Q/vF Lu|%2pSTD"ՄEҥȿ"벉Z&kv5V~7۶@ aU 9˸Mޯ(LKf0 b?Zdmw`>"qc]_av\̓+YӈB;0^&(Ex<ʞ5.!'q|݌0ӕ{9H9KGܴ-'M\J6,0!k=Lճ5 R[0k! mW Nca;uM څnK츷-5dؗǺ䠝g/#t.;kT!2 ľ(R  e2M|O8tlA5i2*XS/omZm("St(4bCmqD Dc6uma&M9r6ijV&,!b8W鬩3)wфtaȶ.mt~]y:P9o&"Jנ]q8j_L}9sR(w>В;kB@W9JV|B2<:@~ͮ,2i M skY"v϶d^"?2Qdۼͩ a`W~dS.?` &ݤLren_lAfյSx %kVc;wɚC1s 0*j˽j3hK{x;m ^4N+ *׻1h6'ZnR-udYs1P7T`+P<%2%9psWqEP<˾%a:L4;d㊅I!mE ObuBF{c.whY\|+˓=?w&JBy_MMyg2Cxl˭|TR'N8CxiCU"`oԭvMns2bfݛ?9M;MezJ꙽~‹,'w,H)ժK9#cWmXv<)S=f 3{GK>g1q2`qRGFo9) rHkԷr@d私 1DfX%{UA 7K;ϢV+saZtrYlΊrNgZX hۣindA nvP05JP?D5fL0ةt]59wC0:O<AlfKsOrk ,m1tiRҧpjo=94{|aF0)^D lET`) &TY% f|o413Jm Y.Kڶ_Ac0ClŌdU YV~3D|⻀Y6ov1"^釿fY|h^{,8>жbiKe`Ƃ&_¯K/ pPBfܜ^WߡpMAb8T yStҙx8-u CҔ|YWW=8]8+#UX w6a6J<EA' >{sg%2dEvHJɏ';F./h6V*ߟm7qOGB~9te ."Xwz8ICx6:*$QɟfG1LZ̊;hhl1jLQl9ʡg@ZS)'TYGYv$~SY@P$PHߦ0 COQ9wݖ$,]S.Kj}rʧDi:!/,HL!Nx53Ak[FsBlNADfh^gkizgĩcV ֡%1Y8ì%Z&9DDDEF9r'lyaa@N0{ s+s9Z Ÿfm#%dzo;|2 T$qs{1]ܵkcۿ o^|3ԜyAηu%h(?i?)^Yb!?؉y\<SUѩv ž'Ja"IYGn#ps8iZD؛D bgxIc2B&2!/"N&3<9-h "WHi+[0x1 P3kyJ.*b P{*fןl*z?7Wk]e~B,Wymj[2: S4c{g?.G&2|jascҺ !P.Nj7~0;tpOI'sɿ t?YpK 8X{B~H)Zc!ܮW $ U@@zct,,켮xKS9I0# SG C K44Ov]Z~ =+Voa&.0zluJB&`{2]:,eqc#61k ,ǞJսt~kg8) 5Ćy^9-"m#x0!oGfrrık6.#-f7F!_RT뾠NhqIc>rUcHQ'aYˇkq^#oC9"de:1XEbo_Tvf}%iZI!9]hN(\se^bGbM{Ҭgad%Gn"q$A9kX;(i[MBR\ʪ7,{+Q)r?4C}Kǘoy6iRK% }UA$\.*)T"IJG 6߲#Z Cv,8p4*q;CXQl)b9*N} <,Q/ %.<`+A9֌#9\bO~!#ԇ1/ b" @>rRe^FQ2О?jlXx9,So\T.1c^|@z m*O8'KQ6g/ӆ6EbVK3,G&s_6ve-/>o<F^bJ —Eiya6$-]4.mvA7 Ot= &7("dQl<'= R\V k o!z,ٴT&H_5#"Oƭ)ifӆ]9 >5}yts7*V E`fGUWkkf/oXYa:0ۋ["+O3_&[n]M Q.p#@1 sUP!3YIs <wzD1z>Ȝp>3A(@8'$֋^Xƪ?גAYsjADZcp~-7R뉗B1]C IBėYM%̶tTE@3ۼ'{-[M]ORLMIB&܋ #^ _~yAbu9[aɶ_u02gMJ,|eO4SG.WF\RZG1#> E޼|"n`K[L}Ću%/6 SoJSE_Zp:=K;WLR?p TP Q( 8TM54aYwvS]+Y˝|d3mrPk#ܠw\p3,Mw] 01K9N1ÚjYYjΉIh rt-:԰(rA1R1 aa!)}bXr-8EѸ"L7H'#[+&`7RYK۞-$pZжיu 7šao[yFȽ8 x(%ǧޕgk 2rL%!f$:C dCլ}(J\[*dM7]/EPj[Z0˸42)ѡD?k6߀z@7^<{ܰ߁wՊe"c0a(p1T+QM2Ya1;!a\wxmC}@q]/CF1|ё\mI,þei)%8Hxf( Co. a+Eխ.N'T/2X"fr(8[ /"/E9paKR{ 0PG^V(Bһ],tUNI^BQL"hmQlm!;)!t'q_.;oHJU '%Vf{@\hHzj`)ۃ`O/&XX569QJx򥉡~Fz ׎OjxuQ~/[mn\*CU? RzTcyt'axï= jvj]|ZV!E0'_գ# I Lʉ7(7J)6>\ury\8yC9c䍈]J1i%dJ. )WFKsf /_d, =OWmy@\]yxۍ=%PmRsOLc$Nt@}" yPxEh9:0A`RLk I *cyws/#_ HL(LjV 5(wfhط"h%;WV RY 0k QR=H__}^j8q1|H-\.ĀDBf !^j)=~0`*\Ƅb9,G2Sh,\%'r "MTYXW%:)95ZvZlى~uwѲ\+#1mdC0siPsZ 8-<_CdK.~7 ƓE6w+$~ J9 dl.oW$o@t USvZO{eLd^\ȼcK| Nѿ-77l2σ#3PV)/g #`n  A ʈ}!wE4ID˵RPkkp1S=Ȁ?i|?0YcLk_|?>TfR-,J}lC_ZVw&TM*?!"bGvh!# \> At_.N%|wMXEC+ eSʠѕнb 1#r wi02ƥg%V~]MBjG*N((8ĔN:c{oaHXRMvU.9)̽{3{~G} OdVA^8"'ז8cyU~zA' #xx-u@+n| {xY:ql0]:Qlץ@8BɁ5)'7\®پ]~gҥ`slU0QIҔp ȾSԑF5U7]( Ct3N(m^w -WHsìW\@vYlݖY2_!&=쀝rWT'}]56r?d*kge GZNɉ*q(5g{rQs׍1j/p$q-Nw{pè0 R5I,4&\$~nDGQC0NIiRcahl Lf+sN.ꯨ7/Q]ߙi 飷)MÐW8xeqۢ]jϷz^B7Cvܶ@^p]kKߨMOOUZugH&5`>gOs Ti{Z߉ |֒ٲpnDƎu*BTז Ń[F(Z̗Zi/4zڒ,uko'rN.aR(*};olIf$7hJŏ[ eQ J\ɥ֪)~FF)0)wWO1,hχ^]^}4z/|@ C;6l yRꬊkԃi=quYҺLZɊ?IQxRC;6B6WuKI,SzWm+IPy:6ZnN ])^2n0ٍ8#֗OWQc-YA_,=q`q%_e }۸EZC0Oue,=Wߦ45DCK2 8Gp9Ib *"x(ϻPc ]8jn|Sa9Npp4[2Q#h!IVN2"V7Eq8 \bF=~D =#Kp9Ƭ,+=IA,d)Bއ>8[2lܥrwDŽ?Vy//W4\5R0C ?l :\=#4_:<{UU$ >](gaGs§T8W"pU!+ U[ME5N#pR/N&6йocrZgDhl!"t`[LF|p`Ot,OͻjC~J M`)JįvzK0a~O~*~utڬ?돴*qyc$=Ǟ;iެ[uh{cj})ܦ^S+2hO,Li Ɗ)1{.e n"ogN)\: +pVdމ%idи+*p2TbyK\_[=+Dԥi_<8Z&ck8E|/UrgDU˚anݙz eCku B3S]0Qҏ ]PJ5 ]g z~["0$2u~#L DE"d~.ɈMvy!3.65ʞU|o V8^!>VM1{݄|GplN7)ݦF8Bl kY Rṡ jb!qS<(2\\uC{NUg橉 *ZilDfܱ !>[h ~ynv>{E6sϠ+S8a)7/yz &;;ྍ4)H i\aP^^[D6ɆihX 5ۄ ʌz>BM-&tQA }?U`r<5᷌:ΙKwFNWlaP4?f(]xX1HDtDl3-[Dݼg B #YrhDՊ,U+puzZ( 2 ģssh] -母짦๮DC1rq 'S?ϒO|gp"YqY|*MR \@d-%,>D]ZK`ͺ";$kEǘKm \MvC* O73|J;J,m="oZ;˾{o[yx2fo#\X ʕ*.*rש^wz{&lL)Ω PNodowPӊI hbhe@w` u5o @v#c鐷OB,*.8I%?gH^u(SV+gYN 5$ݨ;z.fMJm{!0pC1 aFxy5m銉HRJ$6$ž#8?Pdf>&7*6FH}}`p]{ԖBN jnLG`O\X*Ex`~{^Rw{epqV0ls822Q IdofdHqkNEbX-S%@jcI[Z]ԊXh^Xs~n1[w 7Huƚ hrBd2nBKXcyŷ5#mzO ~b+gUo˒8Lu\yI}R('ր:^C(W2G3Ĕ:AԌ/j̻O Kז=E-Bp%h&96 [Q\ok'|րԒ<5wae~gf2c kw.p8Rc^R4ӚpL%9u6ߊ`{XbN;aITQ-S-5ҁ/Ʋa (0`m\r7&F!" ro[q۬o6gfgv,ˆ i6V0,BD i#[2L1%7K2c+M͝=bfSW MȔ^Piɿ{DxQʼH\͙u-z7BR# \ hHj 3r+f 4o;dO=2b(#BSm0X*gsODb7C~Lܗ=\/}rPoEvXm=^,GǺY,jQmkS7(Ma[:feq&8K{MK,==̊ *L x=TLDA)q5Dxm[e=J黆 {U9'D &/Zg/4rpq\$|QߴB-E<ښ$E`$B)\T\,RNഒT%/~o{uk5x?^HM,vEa>Ab)U*,[;ux"]Q  障z:5cϥ=xm}?G_Tr5;HAĄQg̋7B5b΅=J'Y ~ݱۧ;E,BHy$)}0iNÐ#~֫>@H{P&ILg_:uSt: D\rBCY[\3)2#F;1}SV/>) YyU<C* ϒ?]df$z Mޤoʯ:ƌz s]fl8.T/YCq4;f[~,ozD4<0wW)[2Sp+ʤ<5}k,mo?}@UgAso\4,}{kZh}95fgA$5='nfI}]{AA@BA`l8`Y Y]܁<֮֔p'#6WtϓHG-⬜=AyPȨxODPV10*#/;ByM[I7D`]z;H9$zNM5A=*e7v4(|A==Ѿտ;BPS+OŎ$)ʍ&GXb(&(y5HyqFXٝ:P,C\Ϸo30Qʽ˙6Y{"EJD$ne(l5IhxS-zleQz&΄y .+`oM._2pD0×_߆[wֿ?*RO[^\N:!Cs5g!H*Q=N 6^C>him1%zyJFj[s?j(k;I$-kjBA@İCܾR8r"}Ykt4XnP@FтnI~ti4@ڌJq2R8+c]4. P52mu(v~HW*54 Ҳ QL%2,9y ZebZɣWދd[)53v"N;鋞5k{5, LJJ2&S:x@[oyy`_@c"D5Q`NBktAuLdJI:X#V.B VVA+3 5aa8~y{-s꬚4lv[?%zf=dQ$IewgS07@DZVE=F(kňaBD*~|nRh)d#zQzB3 }96[>}6(}ӭtnw]K~BCK(U]UE^LP2xF'`%Ecvibo+^U ^/+ +UFCӒl uT ׹3#r2뤈WjU/## `ɮ?|)53l+?)T ^Xg[,&ҜpFC! egTU8L-%)=z򫉗mV(-]q#9:VIHn2Df4+Y!yY= )=Oɍ^tbKq 0"څ7fasG]:XZhsMEX/Q֗h`"=ɗc!*hW r im֝ ?GEA3I_@&r9Gc8y:w=]G_|h,7ݵ1[ߟeL _&{593g/x4elC;VIKفAU- +XT`6kUwS\#Q4+a{WF4!OTϐ e4Bik%j)iU}-3)EW/ߑqOF_EhDwz&oOP]+NR.Gu`rm*$9GHgɭ1B/b/4LRP(˔ʤ"* `h5gt ^m, c"ǨkʪSCq b^VkP&Hn ԚY0/pͳiLU@|ͺD#}"y+xnY|*v7v+/^{bC,6Yh<bKoIq8U4 㷔XO=5oow1J6[x6;[sHM^L}S:dO_ubѹ*ZUvN{X 2edܱ3;'xk3Q뺩=ڣBцni ;L hiQ=ݼg˱xB 69,d(>3Xˊ-OW[&V1+XaMa H$qz>ǜj.Y۶U nV}Op<3bĴfvNҏ.|bolO'!ʱQҨ%TQ;>~p5/s ݔX t(zN%$wդa]uSF+>$IL B|fLhsd{(Ya- re.0N"h{>#{`D-Z[([f 7km W{_M$!FY*ܹM0'NƓj&"כ #84¢°l/XKc }]~HGȊn(& 7;١(qNHC\KuL! ē|1NJo鍭rbzErkz%Tb}r tɫ]Qٰ%* Ew9~f޳s;^WfR6TE2U\ݠIϖ9Yi/k 3(Wi̿+>˔ UPeSfێՕ 6 1>C%ϴqvP֌xn&8\ Ȱr^f>֋c٥KFU%&I&"u?z,a}66$'tw{ G.M+ D2  JsI?Stc_!=?\hC! a4&ENoɥ(Ah31 ] vG-w@Z4g/ege`l19F’˘кQ<ڊY/۠ȱ]VpR㍹ 2 ԙm 8l܆*ܟ\ ]U3=њ-¤I 5UGHy.z!&/IDJ9$t},x(Nw $BN?Rqvl{kG'Xj *2)&[a0Ξ[G0ԓrW$3A)G$%S,>Pd=†>ﲑҐ2Ic+6zO33ymBJe1*4` J&M[吱KWC۔MŐ b+By*H=3O|mӷVBD7PA(\ ZuD )M)%;]i0Aq~3[~,Y^AtF'BM#<r,Dg]olvDQG)vBN`xpJ.kmk3-kM^ix] 57!`#dQRf9Ø {#QWZ]n1ǖ'yXID͒E endstream endobj 339 0 obj << /Length1 727 /Length2 14521 /Length3 0 /Length 15124 /Filter /FlateDecode >> stream xmsp_-vX6v:6:mfǶ;sgcks(H\T= L<qaMf66&+NTf 3@@mB @ nocfibsss*O p,mE-)y @ht2(Xd-Mv@?_M 13'{[*@LQU`dg ř4_ϲ1e?Y'X pSK1_Iٙ86uuoBP! hFupu:MNva{S h_/"\Ct*Z#?R;i\Ml^:ve8!" esrn⚱v Jʹ.N:lF?!/p ddp5Ia6s10Ɍ(M0$Bg!6,q#շdFx#0#lpJD;,P }~TxR"6RБDZqЦm6Bexj@m ݇U0߻P#dQt3HW:6q"rOHud\92K6}(,z$ܙ:)Z45!| ,xKbcA$LA#FNSpB;m㗨Aavk6Ƅ؃¾^?d<4+9Op=ygҢ~'li#OCfá nHW0NaS`0tC=SR+LگF)9ӿ1LeMw$y'pŬ]{ٿT\e#EC+i. o:7}gac&ewm p)޾"BVy4NPu̟N>|G͟5:=MM[+#ls|W]j+:Q!ۡ>͢jC7Ŝ/vY"y nWV/ O_rv5ť ?gG_ɅJj؉9|bK{dh$k=&zm(aZN%h9Xv̘5퀳}!We] C˳{du^j1r0E%_(cfVn,ݗ ZKa;a^f!X}>U>rB4 0>-rDS[K_JҳaS7(fhݼ bYpG"ъ\\.&a4kL.T ^#{/~RN14 th9qLaxc/BAbݣ8 "CWӛ*ir'U|cLxN~W_(4nD uTڅs1ߕ_/X)ɚ6qxt5U} *Bq э/AKuڷ7z&{B=Ul̟t$~CPk!ģ%JȒ~6̧Ӥ=!LhvwXgPJ z r5|#Պ#$- NFD^~7:pmo: M76<=?ZU.\ZŨ.ح",%:x|#BZ%Sfl)Pmp.މFq0d#코G|k4]^{S,6\hP{.D_'M$qu=qY/4[*d϶|S3&4_̎8 $^-r6eZl&Sk=^H]Q DLwVcፀgx )V{<O2{#-wq=G4kY~Rs.oϥ8Rt_ Vgx!^)hw^ C[cH@4S&Bi))\Q\s-F/.r/r"8tńH+\'3y$/{&gK0s F? =cycGߕsv)#x睥TIHEg_- jKnCzm,8_kxuW3Sv:CS~Aa]5=*% 1haA o?%&Y'XۉɁ=JGiZl¢K9KW]=CA+|D穫TZI5T*ܽ?G;IrP\x<dm{v9u 0@&<)RGxh7h8IԘmр1#8& /:dkZ[TK1qw-,ʋĊjRG_ޤM qZ|͑Jހք(&{v[1$/)A|7_%h UQ 3{]AnjFQJ^ƋMKw>tZwwK[L[dIh< J̵/f Tzr]oR6zu  Ӕr8ux myoXE(VbSB::JƷ-_[S 0,7,\>`ݸ>md!s?X(t^F)_w_P+'|H8m+2|@e% 143Urߍu뗥m %IT4W-e.Zȸh#FnzoD`Y7։{sVJ'Vn:ň8̺?fWؑö8ؖ2bb't(&X(8)4Ӡހk$oޑ,]sI4f#oBLIqK'aZ< 5wmnP^ewf~9 l:Nm+3 P!^/PaMK?H(Pd%f cݣ״_ NQY4ө LLN]vsٳnΞ=kן?H}uO_7(`S]93eCdj>.T4<墌s$ O\0r:~4Fѕ=4+R'׹dѠZ0EM| )0UaIHOs{|Low*44b!EtgA.{fc~~qarO]2vc{<2:kw%vQ:c;T>+idykA>)PL-i|T+3hHĦ}sQ_t5֢f*GE{=Wؿ<4}x2J& k8Qn:Qyi@R Ҟ_ I#ez|wo ro :%QTEW ߞ1 z,ietƱ994ZytIQ:Dx嵝b8{'Z`~: b # +P,usyF_ ̓ [UcS 8]L@t\Ά)ȏ͍PEMmcZo,L!VWK`Lš3~Y[٧N7ѱnQ}t:*OG۷Jm&M^R5W+N)sug#i5#^BK'.a!~3]|a=!y=[aft i~/W<]#V!l케cB.PFZR53T80/R <©؍4 }  *u$Οb-= CD^ĭsG)gvuHCȏww Nc:5‰JnsCm<*sKlnpc[vSd֓&zf/)R#K;Q(ĊPis*=J%G2KXdIk BF s__}:K~{l cI d{Y.7c="4BY pznsh+;7v*3ŧ  *6a6jvNJCIQ%3# y| ہ3l @{RDHS+S_v+.ZQG$׆q8 C.%ܛ1ϲl#{aӤK%>_<#tyM"To#.  2J~;sMċW"tPmZO ʄ.GJ2eP<$)G[gt1y (B/|#;҄ -ʾ$Vb+̕r]ŧzB#a`UֽC*|$ƛߢuXNJC&9|B7p4+U}N0Y/6$x4uHr1Rzb _rM^d3lJV0枼CIb{ |MʺTIοۆ@34f{_m:2kG|WJqy= eyD(k83D"ZUË9. m΍4YfHbد [s2GA!+7%U[|n'ʾۈ>ߡQ̄6rH+i VlCO7ٳ56A˩8h ){Biӣ˒ZH2d/ʀv}FPO xY9yr. @f H0;q~CBr$h<]1]}-_*=QÐ+)lT$Ȯp<4,Za5tF`Momڄ@I!whaWý^|2sbQB"T@~6Y[B YEvo@/Uܷ` >97\X h{Ъ9RhCɯ+B0eh}mxz!#ulIxI(uH_Qv]VRSz$f¹`멮,H}B@HFeֽM8uyH`bog̭jPuITf'[`᲍YmGql!&'UͫjY3׎W 8ӟq>)Rѽ:'ݵ.uTak8m^,)&qZЦSԿ/(WDoP7e:F%hwu׸&DJj3Y#Btg8moTS9zT3Itαe{UtH̾::~ܠ(ytD“yvMl7C?rЖv8|[FUWJ1K7{ o<r>kBF [O#*EGw$ԟ!Kb) Oz{O6 RK d"ѧU9:62,/B(vW̙x "`]:cqGY ff2] c>.W``m[ ^rUC5-Z޵>*]׈u0owǵvmا*i*,ڢ75R"-ƑO&k !_ j ࿔pLVJ>7.~-y`r Z V)z.LIQetG@tXjUIb{/ޟ{?=Fg ItSޛ/qG@wrǞ{⡬ve$ЧEpR:np{ wh˕.sܼˠ-^iȦx׈fyp[.r즛PUb5N$ЄVWVFڙ_pJmF"izJo20 x "Y݌]1.~$4v~(@5hX4~Sd;zWbh*v%`yr0:m1yܽo p05NVNSZABtKy&[1W zw\XcuN>&$To2lrk%0J055BKGe^Ѫ*j8*r ѮoBbAGFXUx. <҅8YpLdWȎ4=;︌[JD_*'Y!~48=7ͤi]p!#EA|nk0%RbOg;W#7ͫAHG(5~E sy&1rSaÐ FeEII@aQzCapZ LԮ*ժ]hR?d{3$|[Nj^k]0Cea&d8lB,(iIZ~*)dR|nwQdQsx`zlX;hUAtX1} 9u8ϫ/g+ Meݧ,L=lA(ɘG6JSZ&/{lMtFt',B59q?tOVIR=ױc18̰ ;%I|rj̋ۡSfC!^4lbԛ x[`GVhT΁YfNW6X@qu x`Ml\un0/;49I/^оd/ᆟIa7?h%ipYN]KF_w*W?pj7i@OU(=kMy#@r$å9Ǔ}8,ԭ1~eYaw&(ZkSkXdγU[` /j"Z2]\ Wg(BBPn Q!i9-m"?x\NP)9+@rا 0 `&|Gp7-J9r;Rƭ/_x)1JCR:c.P*,@21Ϩpol<(jh#4XX4nU5u3J?nŹcX,6{G:gQJTCLh Mۿ^R#>Re1#f%\,?[ ҃ռ'Hft^7'SoLHm3 ,kͷzp^jKGm#( ?z=FT6F&z䴚MFåGk)|>.4\nz« 1zn8zW16S2P xF6x՚- aBr>(#ŨQKǧec=!j|e-߃}4X(!4{v=W:?Q\"ȕ'OPEsF,7쎁i;aK0YsIo\%&/'$Dġ"r - r`0mc}]!u1ofϧYE7չԔ"y3DU;oZuݼ)TFAXeO;Lb$i>k&mTmovŸg SO-@ 5\Nr/DCEVT{'`aWTW+BuW7f&7n8vYGgH ɰ Og4$ Ej%l]/'T 1нqCP3/MRH߅vw|D2B *틿@\ig^`?aG{$6 1ttB㨳Yӓ̊kU=g9k.>*K@^;g7 `,RgF5 EIh %PyUU- όb?^kYZpτ`4뙊R*XsOc]2gQiӛ>ޡvg[l:+D P\:7.?}1|.J|7(*dm%: "'=(nctZ3kマVrVA1qN6A^AANw0٣K&g{ NSS=&VV_fo5 o-u/@mĶ#z@KEYۥRؑ~-u08."M2:: b~Ɠ`c`{(-?HASZQ(oI2e1CA\+XW+;?D%XC6d?c|@G̚**d!Gf2N` ˥"517ΊzY OP`kpKG` ,)J ɝM`:_K pORE63PN/k!NR{ y"D0FAlMf~FGpmі5-h8Ĭ7&udv JgٮkS!Ԭ{sZFeGA 7J\NЇ[珬$ݮRK71sGeή;џPٶb+LϿU_Ipg3 UYfK}zDzMVV ojYj& Ӈ(;4zB!U}sW"R幀L.Y7?p,Mk>u*Tg#wsNSpX>[>iOZZѵ7*Hf͑qcRtn2I_LK;yeqBR(|Kw6tJxzBwƟ3#dy޻ ]mKEqw#SL#PCW:61$f 'EŜ!^NVC25}0tZF W-p?jNa'V|$Q :r<`F1f yEe"1h0KCh 9gi74R3 *;83n³iT`EBBc z4\0QѪt?7C͈͹dfp [q?ψe8RU΄Ht&$k1x$|o9QH@UI:;|ԇ šn#!4,Q**{=u縳nXj>(0}NG`8R-hYykYqSS+r@9'9o '@g^?|J*\r;bZ;*ydC^LI&`5*mĊ% Z _F!>yم$)%[v@fYt6ёT#ƚN7aS$%kwI=V`ڄ+e9Lɾn0j(26ͅ 4̖(ΛJ|sZa1&qӊ &!FɈUg|+Ჩ?#EI3=vf,,z"iVд>3mipz*|;kW&Upк שׂt+'DUZs5\e+3-:A^jtm+WeR {CP]S.HOPؼ%"_@c]ݪ<~ƫR,+*\;D7z~T (_ʹ p14|fYp5KTw6uI#+Mpߛ&Kþ`1)HvɱWIsDžD0Iz0 7e?5cP66Pv/3u zSW*~P&m/H$GaL4LЅOdV|kˆqGR ,wAr; endstream endobj 341 0 obj << /Length1 721 /Length2 25204 /Length3 0 /Length 25777 /Filter /FlateDecode >> stream xlzcp.mlyض;m۶m۶m۶sϹU?csٽVW7) -='@QTA@OCJ*dohfc-h P52( 0![7{3SGo*zfVfKg3S3/?Fc3K#ෘ2@^ oif230v0, l X;;C -$ *+SYn8ײ_Y{[0 C3G5 &aml`w?9 )F,-ell6F+=,pGkwAP,_qUտ?+jhcmMH$!*G 𯴈 @- WZN2&\s(AAWv #8Y;KjF22r52Y[1 4Oi.)-UZf^D6459¹Wußٽܑo"֋1;$ ^y-Un].VL@&1m}_r9#] Cni{8v£69J7>UҬiP>HHn. )i~a7ꎾuüK Q#죐0o3)EU΅C2[k'u%($kG9%+Ms0rN'ʃ H[ V]ǟpmJlZq%u1ҼtVqJ#HwKuK2ii{`4ĨdǒJ5mNV. B`GRrENb̴ k1[tEey-g_z[ UfXljǃ,\hy\EH!"e>1L}CyŅ:jus=ݕ[0}fw$Vz_s]GйBcߛl7"ph59y?6m( ^#XBc|ςbU03"yX4.B(!hz.ewAd#g:CWѱ<#?2'Pi.ݓ&N8t}B':K+lID#Hʸ G]yO,'")sd^ # ٮsF# 0}8[!4K >9BCkr8MaP:œve0R۪K6 z {;ITüow9Z"=GWp.0`賧#HuZ~fóʞnx[.bHΛk1 =h@D +M8#1kӟ; kDSl=^+u].дH^L+~;+-L{ G柞MNV-ܜ z>hěX W8ׄu.F0hP6/PyXR\< `pwM /f#'>!d&ܸT$W}n#Y9}=8 !D !3?\vjƸw@`wi$ \姕ؑzx"&& j1ToK 3]n O$w^ޣ}|r2}qN pw/^)A/g?*μ5~6`bǯU阘gnk*aX%<^b& rO4Ⴠ.|ƺkʈv"5 Rre' ^3BObVi涠`1$~vuT_)4NdZ'Ҡ=qgc,9>eA]'c–nט 3.>TmuG1h@G1sC\d^\ *SׯbA2,~`o"xnntkp3Kmb5U~<&DaV_]=n#̕skaf469+Z(3 alc4l3) T.__}T+C*Hrb Joz̰#DDO]jзFAݙ7̙uN @S;]Yh9衻G43m# 1&ڄk`q`@jVѹ-Τ*s-\k!h*8Vr5ob(ɭKks5 Qnx5LVniKqm^|QŏTQ245d&^72·<\Ws3q]> hWV|oc DI&Zo.+%|n^<~vR>^`&OmhR P3<9In({G6^=@0;Sk5]{I/1| 0ukh&m`:!JFC:vW5Sb I zܻJ%ϧ̩t6*҆D0xs6T,y-$_ՑcPǘrd fIŋ#?v4?&7HxMY,\]jGJMɢT݅@#Nmǭ)r+ţWH筐 |0U5m)1sIJt-!Deפ5~\F("sƖDxqizLk<~LZ:]V-zuZћȿ-mpJ /q\R@ԶI=> (uAfK Q/]leJ;5F&P['3ǚEDƕ\@\{,iY+FYR@3JTt\ӕb`z~y@n|a DBm`]#-BMsL6᩟cSt<z\a4+nm95M|#xjVc$?qy͂ Yȼt}߰;dA F ퟱbVeؕ!_螺Ԅ)mPMyVA|'8~6ɐWgDKE39o(72H.UezT Iΰ^r{}4pPڕp?)S?0{;ipBDyW/;3Syujf*; [{IQ`y t[.rQ9RR-U j!wbhiͫ(|n kH*QxQ:j.C]+#FbɥAk_4NG{- .Haltx[B k}f!pM [U,iƖKO.6?v5Kr ?ɫJ wԴ:^UiJCi,u64zb<{) i?K[^w =Π}9)R$P`7¦zSySصի!(bXW}č9.i[ZF>DXd"O9*$MB3[Q v{5ʲ,ZQ<#rjJ?]{ \<_BsѪ]25nW*N6: Oi7^R .%MyoE,9Ooy)zpbE]'I@|kgq1ݢ.ޠw 6\]QذyZQcBS%{#gq5H[\y~ugX(ht৯y +swNCn63Zu^HvU|(_q];u=?\)JP l&PSȜ-1 +ۋp {4Nnˡމy$N.-{ Djy %w nqsq v4To!3v\#Qv*w藎HL>1%k=GAC1n%FSf9> ;c?a}x|Sk焇eq 1Q!U/95S27?mL-sWjbdKJ&hY(PeYRd1WӜzAfXӭ@UYa^\8˽|ԝi4x& 1n@7u!mE,u!-my7lV{)-p'Sq?8筨okpnu R3B*PUp_Jr.LJc ٥^ڬ25Z).~)>QR#d1 [6|ձ_~I EWL|%QBNytt; iDvJCa$ߛ_"^S_csU ʻbsfj TSa#u0y Y:) nz6N]2}tU;ھv<;/t`$6c0H/ y9x4&FRЂ2o{}y "(|\Og7.z}<8BOPm"`HU˚m{8E"6V)]TpOgAs[:YzKyNn<\QWDtR/(̮%V]';Ψ{["{R"uKXRw q7$rJQτ4~EGU}qX1*fk;Urgb%^z ­_,X/'Zu^(wn:gN! z`Ty7^oiNpX E׹MCkv),L0tc+B,JPg~뫤?cM1+lR^[ur?C#i.0Earnvw(, VB^- NmPwxzK0(C8xn> egpD"ei ztj!|;@W㈪<~ Ly.E A?la4%Q5\\R^c< g1-1[(c84oN&{>X=ʘ\#EoIF?},Npt~3s[e #dW@ݠ~Vat Yݭ?l 4/,olB^L]78x/5S{!\gD^Ugju1š i|{1V46ñD|)+1. gľ@ *7^O/˄kב65Ҋ4 &A}Qȗ}D.&=;ME7pO÷8+_K# feFldN^.^8Qy3nl#- @KxICJ(- p ې7LXõun %:l+q?9=숸̸B y؍zKEwkam[us2 /osrzK5RwfLYFDVtN"7p+'ZG$Vxi0@JYli\%M@9ӄxd#_+6KJH*$^TҢA5-xcz2(̗|t,puc:9w*؊^|_MoVGꨍF'724ĕ0 u'fsϡzP٦ȢԆ]v^ :!o>mQa8Tg[bJݏ\CDc0!AAvl׍L:7')3a rF8'؈K2q\?*JXƏ,8{y"fw>Aٿ֎N`!l7g!Ò:kfh}lĆl1^ߜcER!2Ɖs&~|bɉW EYuHXxI@z:> FD<((PT篿)Ϝ.\IiFGg5)Qs5)I\ʽYH9"F+6rjJ-tOK"ǎEH3%ŝ n4!@z"L )1fEt/ac'rubƑoGd̈$'^|^-հH}tS9"/$KԜ7t'c 6OO\\: 9 Gkκ[iCJD XOZyJHz;snVMl v%/ڮy2#֨y:]VɕL㲗)`vc,8=n;\p.z7B(P3Kd֪sĔ1[ύgI(۳H@7@bVXUN 1+=陽dP6(Bݡ!T\kV9 0ApFμ[99&ʨ0">dxyVk nrJ`3g_% T1E 69XJ/D!\AޖRG >.kR +ċt^Gee2<X&!AI{'P |> c%L,!`12{8]PH^"%Q52i$;瓉Nش=[}L0^aeRDlM'sǹ77-GyGI7߲yC{l-cP  n(C6pn:P$5'?MK.TK*M~SFrrqFvq^!O}c]Ijc}irSb#ɐhO2][J=cjԱ\&{>v fOIH4_6h̛U-Dѣyl&u(y&HCOBXQQEWFxXϜ}KP&OZ<-_-XHuY77RNa܉)T0yzL2wKged?pnռm%l3;&u>:M-'äD2F<$czDxaIvƪ6d} BQ= q-~gLP)G&| 5Qie-^jZ-yvG(v+\Mm" 06PfxsX{H7EStRchr)_Zʏ#}"V l}BirS)櫼CPJ~ MEs>;a|@/=I=>5hg,(sxE|ܙ^7[;SWe=> @;Ȣi!9'%;lUHD:f _4*tZj94l}2xvRJBDχe%c eV:*FcrsEGyc+Bpþu&?q)]K9&i^<n_J.B{_'X.,`nqr k.zW]LScU4AT*tNH fGG`JxE!o"<;Wh!-3{ ]d_f>T QZUshXa "32rqr0W#Yc\eFd8g)rMI=:oԤeIZa 1Lb)</~-#iFTMQh#$AVO^3T0G5`duec뵙MZ/.,@=%5_Og@adB,0?ټ14m>w rG;̉ Jhd6+HnFȲ(pFb[uQFNl*FH{1&3gLBH 6i&N2.o;[ޜ-foN@biXʀ/H?əԝY|[:`% 7zF!13Gg%Nݕ-pȔ ѴK9}Yifv+%D~RE"!߱^ЍFp|a<;o=ZM~y)ZlC9޺KW Mi,5//Gdר ό][`d'/1226uv Ζ2O12"$y?:l<-х(θ UROHP*u]/VGӒ i U`T/N/joSRWV,Boa5E %j)q7K`Cc{q=DKwb=9NTGrE V?x QWQ[$[Z I/ȼbhdg<~NX4>s?K0 *Z6qCnjZ],0IuB=omt#xIƙj7) zYJù]^Aw; C\c7vrN Y{knY`;"#ۦ]];Y.:\#<ǔ*(~3 Gfᴄ \.ҳV!5&wBm%!sxhR !T`_Eb$[ߢP,d0]gƿeAVC]\&Bav;'"^uc"b::;nvح1nVR{2RMf\kԻѳiL}X䃭~AGV&8҉?VF6 hRe8NSs:Y? `2lVGdڹzHD+OǜL);LYy:X?Ol4Pũ%2%,0azb^[:Ѷ?ǭ&ѿl,ӥaMkԫʩz۶=*DYd+B#0ITS>SWax3m{"Sٸ](Y(ǂhREc~uFq<0lsCs8+㩓ѝgN]O7MǍ8B:H Ua5 /kXf+- qhTr&,v {g=V2~ZN+yl5QE~_1r`$+([K0ୈs˲"KeFDFC7^ %0& ɶúdyhbgC&2jg},t4{- FRǶFV?/g"\pS_x |:^a~#H^d2ON\:#!(#o!\q=c^G Gy/J~z%"ȋ7~ީ.*bڜcp¯hUSۣ2kc@:jz`\^flw&hZ.Ud3.mc> & 9jΓԟeD=sho!E;J `"ZE`; DN)d.VʅM(PY?53b~qQ&;nN2ޢ4Wl6A̰+`5{HX +2s i*W_+=TA5v|҄=Tc["(*yo%ѐ(.neQ ( +=gVJgɾ 8VzhD2sbźK~uS6+r2]v=VeZյ7zH&D*|+ Uh:J(bDVǮ'nCVwUHt'mҩvdYYz(ؽ>SڐoP8bnX+=^W_̫1+R4#1I YGl+*I:oNU k#M{kتfi( >:ֺ\6HLe>>LUETΈc%Gr=HۓC}'x%5)c}dXLtx'ӵ l(=I _zc?_ucS>r 0:q$~yjUEZ=黮A{y*Q]KKj\Hyo_^] +G(%R+q>eX,O흪ExT}d:МƆc;OnXD&E W0Y*f~u&oO$ 7"=apPpOlpl^%z-ફ"$J2fZ^_ K ~^s g(v$I A"xJi?>p[]yeu V32ӳ'd_JJ;8`E5C0N(qhv\suLCk 4W*ʞEj.tN{MtueziItZD`1H=n1L]r<:Z<8; ZOؒ2ۏa@sR%#16dM~4h$7"id'D;{s (ACa)@@R7ÝZrId8Pb AN0~ +0U::= .u;o`a8헐,l6\pCG=",ę%zcbI*:5 axK1ܿmzm^ PiY0HN6rU gbއ ~'"B4y $CgtM|uXm1E@!jJ]>s05L}޾k+\lσ[dw'S4hUcn)Ч^4%"+)·TL]qH.*xG@f^d*5w1W:km9컚)Ex|Y1f?@fFzNF57.;֜ASxB[C _Ln=^}w>xiV'sQ^beƴkN LHDK?Pm 6S]?|Ut>daRx=y ͉Sʙk7dMR1X!&pXw-W/^z$.fȺ7 l A(FJXeTC.ِS' \E7U1l4(YcX?XB7j^ԛG>L]k;JKIʤ_)[ 12]PN8y cz%M%hj: W.w"Q4l:cz =jti12`\O@MbGì6uo(NCuAq[ G>x7qXCI 7u0=sQ3&]ͺ\cțΈլBoHg HN3NQ[@%%4='@5opn -h1n|ީ((:z/^W,Gռ#R1fkwe_YkؠĄ3rt&vh}t!B/9v~$}bt0=Ha$sѷŢmu/ XJ>C:c?aNY0X`f+|2ϱ<f=tΞd@^wZD 'S*<)X5$~C?7˨"o{c!-`zE:ĊJ'# t>>yR1Ft{ӷYWf#HL% NN.0mnL\} TJYE}0gB2>jLx\O:*)P4z(PN Qƻ58Ɗ8,f~n &UnW#m5CFː/GI:-Φ)X]NnSA 9qu83òZ+1C`|dk](@3P;U-~%`eOd+ фh8\d-x9{B 4rOѰ؈)nftX4@_::ֻ ,ᕨ(`a5E0 ߅V߸;#dlo|\ &dU GW% 4m7mӠ`ݫ3I8F$`'Y5G~]ص;E4~K,ڷ}+rYusE?#jI*?Ԉ|p@\І2ҮΜج[aXz[yKo~yN)}Є(3. ɕ(fku3~G޲mI޿}ƢTY\)LV7udl[,AtbٸbGq gK"k 5#g…/<>lHæ|~Uւc1 `ZNIе@8Nպm ,ة~>6%v:Gd~? B:g4(`=ޅ^OXf=:hPsГPFTp>Ya¶{O*=<'k$ݪ'/8nQNWE958kx NS#C웘KXJ%FZ4WoHBD)eվ|vR+'; XrJ&7!5_!wyF(=PI 4^ވA.h4VMųHpitaIWNبVpÐ xKdY)∌%=^\7mud1 VFWb0EfcANtUt#|gwޕY[nj6E;ܹЉHHCR;;v Wz*yDFqL-NtIf߽1.}U~8p!_6y;y.*ϓrxr& Gd4"t$)k&<y_v9e-T2b 3t3čFh1~ߕ*gn㬶bo@(daa8n9+g[M`!a- 5QbM]TZV]Y:s(KPj:/3*,(khLtbuV08=DeCv჋w>z~wU%W疖Mnw9FD ! gta(XH:ife~61[9Zw;%w9ݮ1çnF=-ʗX-/Z.$Ɲ)CM=KB2o8 ŸsR\ ˧*Kwb_6#qUkLd,D<flKzp3oKGGB_n_<QPc^sK}CbMUB5GKJ܂!_>QZm[0W}ivjX,I^M3fԪe|V:(\𐟙QPutvP<>V?j$, ѕ~ׇZGԾ!9XY/,MSYd@kBQѐG JܹE9Nf:z<5<eغ08[X0r24TCvur/<ɝ3z"2mNFzA OFmrT[Z!O]g7Ų [;XcCk$SqP5\t;K&gqm%9s~X-g`g, XెO"nDnJ&#G7X&:][eU(v AV[@q$k پy%nóuz-> t=^9@ o VHC(g3MP1W !!AŹ(( "7cZ%~sMoZɍeq N7OJ4T[M✾`6 —'R܅?bJCs=KjF͎ ԡ#Klh q_{~(/XA9+~@pđJpJza|W 'RxwʪAao C_L2|6A4}yш5:g{GPe8LЎ9E:}GoR譿cfj&amʎiFO&h\>_]߀')֝iPWwMPr[ ]B0D H_sdD鏍ڰ>RϭBdVc[*'m7V'~&/,DQ]TSy#PI/tϑAD; UBp'{5^v@ק?طap^"CNIs\OhI8 )a].:<Qm>W@AQ!6k1%2YVzū]Nwɔ+0a-춝$Eer3%7HFOeT)x̫yE`?>DՄLwLQ~/>MM}^]O<| E@$ H)2|*<ͳx'&ڧ\RO27ڑۘN)T*E]|a5$O&3>Av.";$br7mvJd!e#d0p<,^>*ڶٞroL{܋Kc+#ǏjIn!@4Ҋ4O_ ІK^i%W׫S>\NG:pj iVMH5L]GH QDǖzBiL8p&,|pw';4X Ũ润RD ix|)'i p%6Qgaİ:vc=k\{CbCD$"fꛑ@Noa%vt])%7 驒PQ.^{YSфav%nciwbpTTATc7FR ^ ȭ}9G P΍Ndn+ht{L*0mL5|DׅQEzYf:a>ըW8vC+PYf6$IxQN$T:KD>y9t#ŗol0s/6#Fb i3A˖9UX42"h6#NP%`JD#0E׽?U< (&Ooʢ=Be'zv 8/:heh#"GgmN2>2Z`Vfl䵠ۅܠ@0[-xryeu AهmQWu5{\.p[ YXjuW}_[ U:?nOVd`ƱvkM]?0/V a%|TۍZ C )Q WP\:TLܼ?¼V:.鮢^Oh zfqg{+V|G|#fsjW8$qyM[-ƺDbIUޠ\ H,9{.X8NuKwzo"d܍.<{$.dJ:e>)piE}m"kt&+6@$YuCZb~%[ѝs)X $]RVLYuЮDg|0[@s<5(2 3t6ߘ1*hV!_Χ*rolaiGb: b##mBdrh r:;;~x$Rf9,΄Úkُd ԢFkЂa";Uǽh`@a''B'0oW}CX|B5.L&kLJ=Iކ̂ U<oG)&VF9ex܊H˺)ҀEEl"m,kKHӰCOQ+]imB(bXo52-):VV'ltDCD-rZ?9{)q̼Ǖd8`է_q8"B w %_ Bv1|%UQ_|̽\ Au_OP9ow1K&AhT1\ 9In{}Kgh rMt FJ}F+lre(LQr b1'N;$ RO`@hܠ#l.u)Qx06$78ն E-/bC#fE9uRuI?+z8x]\;RP7Hl_F+BTꄢa`/Tz3b(8w/Op)'P%iIJʞa:kZ9ɪQ`V8 endstream endobj 343 0 obj << /Length1 737 /Length2 34448 /Length3 0 /Length 35008 /Filter /FlateDecode >> stream xlp&]?FWl۶m[Wl[66mn~EjgUS 9Uќ*`b`#'u67vv4f 39@@eJo!@`nmjswwrwqcpv`Ije3**iK+H$@sgc;)@bN pp:ͬ ÿ;=@^\MXBQA .ʨ& 0qcmnCe?h=C113̬M]&@8& ppGlߪr'>?R-vS07P:;;̝al/1L,]Eh l[HX{)YĚ0*lֿɨ +")B? o8h Pu[cg[dln0r7vu21]u7V"">Lzn̬\.V.9'Xpk6Ess3F̠+ӽ7CVfW?~{ ^H߷Ǜ#ONG/x)!zS.xm47Us\_ Vb=q*Gd1*DNX] ֧DB0ߧA +6|[E!5*r<)hVg= v b݃^>{gY.S'PYSzg:ܝuԣttߖY' ?]*!31FCPa}g(úp!s@BRv҅+^k7͒",&O%dqOߌf'/SGw_&"l*m}ya]_Tjb?PVc o7\v!q8hn|sg y"4cGA5NE@~fkfr)hXI\bb)g={cwg'p&i/qCL~rM<11׸E,Ƴ&ް'q9AvXF/o!F bx'|7E^ n?%Ĵ@o)9( 4 ާ~OsTکq[^]doȠw 3(s(#跪CjM'V >j0{[` -:?b՛̠kfA晑4Vy ]8@j҇*_5Ț4L$SS01!~7J:t43ӵB+i;5p a$.jjf>~c v)1U$cY'dO{hZGqօ<'bۅdPz ;ꂢ^RF!NUuMxn3<Y}* ^ nu  #)#!t= 1! i*Dk #梅AV;Uw^(_ЃKij`ϧ'8&tHJ$4kixGPF̊Hg@ ЩybY3 nRi5V&%uubІs`o1ouE_/K^(* .^F%C{-2TdZJWAyaCb}j}b Qг|N3Vع~oJp96luLל,tw5Dd.j>z?T5 zf'~FCAofCGOP`~d0}aC  ,)M<&$8 ܶ@2Mo<ĊL|Uj DpoɊ~`* 1*D@$k-ȶ\f@)m.eL'lTە"DRif*;_e."}ǝ.<`5*=D\-GW8e; `=2Ioy .[IK4vPɊ2Q;=XoU`R/ 6D`|ԓ}3ص'NjhG DދT#gl7#-_o"AT-0I@HL߇ųeC^ LlN]KBKq, r UKU}-~P8+ǗG[tj-Ѐ\fIGS>T <G7v.֟y܁10R.͐1jЮc{vdj^D^l.85+:mź|5Mǯr1zkN%"8১VX%*s=kN7Ys^{y -\b ~.:#LX!r;]3.)38-wIŗ2Źb]GtƏApڹӅa< b?UyI̶_tuSj@UDɼP0bW֛<{=ۢVN{S e4vԺI,[{k?/bz"P狍t43,,߱Jg!ᵝ#pfo3jp}WyG)6椉h-ٛaWuTLqJk!TzebbW3W3govM;~ɷG*K)T{RY >sg^*RIRD5ϼllYZKcY'2/oHT8(1&G!o~͖#eʟbpɖ;Lh=9 G u4hn< {I fg Y8s? )_XP{'e +?Pe,Ⱥ/'oS*sO sȬ:XeYX4E0B?;>vS[ѽ5otjFC!DBz-4^EOܬY|HcFP5ɟX Dڪ;<aآG16w8=ϻob!ox|~L慜*SIEΎZnV $V+~tEK+_Tɸx!=5w_< lO˟0qQFp "ܣsg'ǟoХ 6ѷ+5OF[RhB [lkU>=U6ɝH@w>srBՄYUnxP61uj (BlnjG.U/Cߞ!N %!l!ן P˄pzɝ~Vd+V>]qcc ѪPGT 6AAEٻp2uQL86XmtN[=C4 G0Jw}lwY -,0Ҡ.{oLtbxUL7 .^ra#}o`8U<7~4Nj ծC1#;NpU9tWx0[׮S%p_m;ބs@f]F_V *~vB?k0Tmqc~VmZ㇔+a+S*MG %yVbJ>m/P7NNro?Vmg^rz'OJ\㇭[qJM?[.R\YE>M#sU#:e`*" =m l/qlC"񂎦X?R.]$yɩ9B3&,nk>+_w#WO*?bcaOQ褛tcq\r>(f||WT?Oρ4ʑHʇ EQ th\݊xҷh0.mf&9y ;ˉPD(4 T{I;]ޮ,AK呼TD]2A) "lWUZ;Sq7PŔMx^Ԏ" pP==wz?[:4Ðdl7iL,ne`A9)FleNf q*چ ˵0$sR`D|W`^gbF/Qgi$ASW܇+t^g,Q 4hgfv FgFg}7b~*ݓHT@WatNfvԅy_kD,B&1#MkQ>eVBfs֗HCB$^=F"` =F4%՞];I[ ބ6ٶx XNp}8z4y>[vշ;5 s撆!WA~ި⣰ЄaEP1](Q|ZF~R/0Ąa?!cQ\zZҡ^@͉TpJ D&pV7#J<5lN&U3 Sϡ6Y-}#mD7sQiW?j,'eg6wc-|h6^#Óe*:5CPKg~Lg:VfĄʼnseHY=NԵȳI`J7eX֣Ё r9rhy}0¶;bFݦjti I_;R^}Ǻي&Tڒ?Q4 T]{/ٓc . <{acJE7]$M&mJA;FrCKd 1~95S~zhʁտ\ȥ>m7eWՂZ]bꠘ!GqB/|Қ 32Ģa^iƧ;oMWʋĹ d]lA-?<,]) &=tDE=&kLsmsWmH]B|mWM'H>lS80J9Kq{1F-5S[ ?e Opnwb75Я,1j31+\q%--痔՗ŷڻE9_+JSq>빘ˇ)&d!7\b5!9Q!4p{6S:7#Dwn-.)i$ RtfdrE3OH;αvqqjJxPQ;.Ҝ:+bu|SCk9MjWX̪\llu8(N<ZX hN2-PnxWѶ\Ykg?$h/!Jy"1]҃ήkSNhͶ8SRfZyHcdpHXnG8i?@/7BB #F$!u$^{aAm tHۃ|Bm~[a w8ux-6h)i}բ'q9ҕ/;̄^Hƭ(҂:F-Q--](Sj2(lfUϓ{Ͱ3Q$,=嵑]ǀp[#g i@rGD6mp{uEHQ 76T׵vC]]4F? ~u3&&ig;ڷV^Vw4fk=iNnľ;T+u(@~@ ",Ăzߝ 7Q2#(ΩU j]Dڠ=W< b4=VfZ~&嵄K0H$$g mŴ!5parJmD)"*&yLC%TMo@،7%@K1a5/GY7 lcFFֵ홉1>ZMcvnrߚ59__Kĸ+I}1)Q^ ddPR t}fz4M րE"زKA !YTl2gl [%گD & JPlIWg%7l6#bOa0/t9X;[rH }3í'sK37$5(Pgwҋ'yc3'\J.xkpJtT+6vxߝ5:?L8oc@պUc ~3HlP zxh6 l"QV?ē|$rU- G+ wJ$Uyɮ .fʳOO~".5>})cw# |zqH'3"FtE3Wփ4-e>z&LݶطxӚ|?-"ՠAl q$FVR6yD P'V{A,-}(e,=8ɉڱQ'$FlVamN(eT*mN)Vf٦xx-'~ ,tg;kvVm)NGLDn[i8$(3nZj*yz}xEA}yqaJbeq&+2e-N8ڨPhHh|MAZ(z.p^z@!IdΛi1rcL*0x̮-M[IVVZeI+pFEcMaa e\ l50q*aT,fi&Q`浑(Å"yDԲMyR(1p{ = A ɻ[آ P.YeK^%k 0IiuR? zJAb*(#,|fW$roŽI9fAρikE؏ Kp,w5J{>qԊa2_b;NݧC㦒8KdyF&YxAgGk\_{䢣 [Y T6ǘObӔSd ]EY~ܴA2 ]㈄H-JTc_VK{CAe" ^ {yK|\ n +[7QJ;#aw(Gʲ۷]d1PqΑ%H+o,?7J)*&$00/N,L*= Uv"_%Q[2[MnkAIœRPRx 0w>J (\3Q9GYX^o*?奪11<4X*G?#G4#ۂ`#[R1RM߃̛c_ /o0Uh@cXtI"Mc_% [2N{ww CW|rc`oiK'k9pxRҥA'v4PIc@z麅GJHc[3_['RNP$//4̿(9ߩ@+2lq~pP3&<8(P?B[W- ⬚ dvJ>+På9w\S`)d, =wwj%5 %)44X!øDAdeD|ńoLPȦ&AXim>z -US~vY@JM*WbVظxO^10ٰRҎw%_0@oAW ˝1GuRIMvBZ F:8HÙ7k-O5z!/ Ǎxe={~PBT"~/nM_@ʲN`/ZV2҅>gkil*eX^.KG|~auv;YMT:C}=Z0<o\#\OQ5,5EY4BA(]~LJX윎ڪ{]d}Yo&pDB}2RG>WV޲[P]*, -qB߄tIQFS.T{ioJomDo9[4pF2HW;%6{E# $JRȐ$tэ <_b8?oX/L&yXa6?(85'Y.L&E Өͪ8/8DVE7ވTXnI̗Lb{ D6sD6zZfT[E$_V)^^lRt70)WK$y ݄g5?R˥@Ŧ Dc_ѡX xVVqq!/_ύ!+k;b8JUAT!4;5~q@)˚ֈCO%OHI6_LRvP,,Q۷[,Jy_v wh* AqoDX$CΖ:7M?ڕY]f'b$, Ҝ9r uw|UC4ӔM*HG@ Tld|W8u6#?ylfr }-#ClSrndBaR(}C&H?H>@gx,[ j[R:i!: ʸ G]A.O&ņ*3^{`ֲSVܐtЩuo&1L mc/Z̦?E+ K5كAF [S xCրiXQƴAV*:Y=k>#oXఔ}gg i??TI:cZk++$՟ x; gǮTZ=2k,VϪMgU~./9Vozf5)2)W f'x$/6z<|HO3("nXS;ᐸ`((h\4he48r(T`b8Az9}QPIDRX oe֕{s+N/Lgss<+fCd>8x Dd;_ _$wfno.0=, xm_]q!G8@J&d8sjxhCK,bnɛ薚A :gwclQeGuڭ0 D'Go視q"5 AQܪO)-B.ljvQ7Q0P܄E9ͺBBƖ k.ܻ\}af #"KdLA4V&t'-yG6?"[&?O֐ê4gX >: $tf 3$g.3J͒L=[NtF&0 3ß۰{);wox/Dx0,x:0co _1ޢJn"Ko}eo3."ɯrE;'^j8=d\zI<A B,NkCD*$X{=_Ed}}̯(s4U\p.;0X. &97KЙ淮.Hp@x63xħ9Ha%ɔlkFE/hobD&Z ~.L^݈ZEVQc@oc|'\駓}rM׶)KNSNհTL{횺8Z<@լ4'HTtߍq gEh'.7zoI]x@ K@>]SĵNUuJ*\!UŎM HSa V0!AD!a8;f< vyanX#"l^dZ1-m‰d5bw䙉p5n2k|cteŋ6q׮jL`.Bɖ㸆~]N3R,cGC\g !ST:襤&|l`buc6k[J@W|#,)V*zRc랚lE&M^B>SxE{K eGH'r#q N?(u GPCp;#Ǧ:x2p DE*4|eXKlH:ɜ 8dG͝iqxaL4!mJ# _O QaqD,l Ta鞇GҞÑw'Ac#]YDӨxo[rk;{ƶ4_\REڰgaL }BnǜXU3#Wʋ&9~h%9υ|:c{# 5t0:#Ě{ilcaF@dkƝ eơԟy_Ҿ oEP͠"?9ڱ^Ta9 Lgג_Ѥ|B9&ff4훾5.6?*tZvnT'iQea7dQsdNP:FNWBiM' >z]25_v\pJ&GU(|16&= o`[~)A qnUȪpgk;=?-}rX3: x14PB>5@9ĄϿ9Pf`xW1[f2a`KX:ӢSnP#PcDԳ>ʰS"ѣ?אSjԥq<n'~sMږUXו}mz{O"+bL_mݖ%-\S/K`fPBn'9a.l@ԯ?؝Y;Pm_-n4H]?]-?JHg` w=ݧ 4GD~3 gJ0vԒ;fUd߽t?0{4sAl]Qbm,~2G#/<+9 - &NYE&`!Y\Uw4a] V?g5Vh Z7jv\n a|iu--Tym1n|=Ojw=$Rf1rث|^"woY9 Sn天Fi0k0;,*HӨ l 0)#{۪7goFR?E6ƪg\ Se?kjh$#j޸ sMJH9B90szphu`/ZTk$\: 4db7@dW{sEɏA='q^Rm5|%eF[H|K -N TvDJ 쵵<1Zdirfal1fhzɨyF$ VXS&Y!ϧA!;QY{PHT1 [L|pk ɗr~b:,L$PCQ Nhj|]D1QE8xz l@!kxeܪf~\%փʽ#4S6{гP;JOT$EfGDoĽU參g좌ģ(G:96l_6 ;4~葩#\3|ܺ[u# 6C~b~.Os/Q 4*QDm丸>lSkq46h +$Z!#gFe3};Sov4eEr?%rS_S^ 80uWaz6[#+ {Dc.ǖb}P܄ct#Ukڋ, fw 3vx7@H)u=^?p9m>rG$&1}v fXbm|uo GFZszaᑓT5 ' 摰J Hə S̰t@W=\lJ CߊB & hI,JT Y)S-%wh1m==cvFo* h@}vZ!aFP\iW:G0\0yVB9AO~ CQXѓ?=6L.R4䜬:sM^ʢH-J$#9 5A L.YoF~}.2tod_Uj>i#4z1axCg}~ɵ=}WtwVU{JB[DR y\7KsH]apgrq,5.-V.`yPJX + (S%h1"t9s{Li_~h{*p\Tr (rplHr'q{,n DYwApiTHB kT2̍˄mK#,aAנ"d+fĄ,,~ls/-@`[1Se#iYjePCʚuT 0 Ud vro8f痶ۨ!L(Y,1{@=QT)m۝_EPڠEҪN#碹\d/#]yᢽlჼKPjꯛ"~4ץgFTfwKde:G ;Us^1.!P˽3<ԮmJ l |t*`vW7 *~VDW4b(uM!E(jN֛p|x0 ^ϬfTtorH=lftirk i%>IW\܎=@33g7"Ph$[rq!x_~Ԧ{XtP9!h.'RVnPNäO0e:/ pT/[>shCRM̎_|U9lK_ }&vC'+ƔjOk^))KWޣnZŧ钲EK؞ۇ`@~G"024;q_|R+t%RnV)gkI9lѶQLr['޹8`<=0vƙn& 4 &pU6xRU^?ɠ >P,uewuY;{Ioj) TмF *, ZPf(I_?݊RS?2[BM1MUOOs(2$HZ)o N*(CR$/VCђ\kPd3c59(OTy-qy& ,d:y:O}GV"Լ,#>1@-RF椧kT&)C.;s4̱tJ6F/Ӄz3^ T*S3u  J=ad:}IR_EL9 Vɳz(K|Z=?[i+}.W)[,_ToiD0b4NlF5ƓDvj⡆=1a))9J,7{I^BqKWITJ4Pr4f8T縤)+|f]O$n b[vzUkI[<%ՆɹdVP$v7j90~Ef+gHfE+_!Q1:UAN"Ȧ 9ɰ@)"u*9~Bmajcc9h!$AG A0ػiw@4/瘈(Ufc'f4HM4),Y7ƩƾL *Ft:js-Wu+5{l" SfV>.n[H{X}ףɗ>xinv:BV+YwDʓf-f'%N+18etϯ=>"]==W`|u~ȳ>BCrUl2.;Sq9&>tĵk9=f}?n7-H6@ IAAW>M~\im#S6rKebe>@y *Zh |;HB}i}tT0x<_.4pʌC_A_\SEpݩ(<`5TF$vբc52]{ PYh^fw#sw[t(}j|q.T[*9^?l 4Pe6Dw%C-g,Bz:'c}vm₴uT:"DasO!9FUlQ݀)jd@:2\KGt>Fn\Os+pCtх`p,`6jlE⫧F1^>} xOEci-s,W枲a8Eh6[;. 1@-K1Ҁ#c0v5A6tbAY*h]k%7ܜI%=̶ O~'YRfSN?9ﴘ%U&Iޝ+zho'h=JOZ #? e`/;qPCxDc.VN.=dTg$6/߳&NTYtx !MG᮳Y4]YF]䋼:;OK Q"@O_]{0M5!1{|vMMȠ!1O әFcFrYn&DwX~ܢZbLu! DD9AGnD*&Su4 )MgVt~=ĶgA ~BJ>gL-(ʏ@5<73وCjEYP~I想'`ۓ=vK'67O7{8jϠ(T&%9+K_Se ^o|뵺C"f-#8u^گ+Lt '/kVk|-ڒњ r.0!oKL9`kHn%ef]1T5΢<9Ώh(x4iN+!Gߚn^G!#`YÛJR5$À5 JբT[\L770N9!qqth^=h$l׫b?۟BG9bW.D+UQaM d_ k|qBK.%)c2s(QՋ ]/DfeCXA%@5I8 XEJRo2mn'M4 o`VI,,l{/~!IAX G`?r'tLT(ލm{ߘ`(\ÃS!n3J0rbW$o4@G]?Wm4ƌXLޭQ 5&ah`(凡 o).<JAMԾ)"g΀x -R9j'2uuas d[a8Gt@pa!s?VkEP(-iѤKcʤ޽# ǦX4CRY`VyNiG6i2F7.&|S/Ǎ/vupV2쳸c^m1C27-TXa^g0Rz4 J-ܞ2.kMV3'(wN? 2qw:8;>V&|(㎧_?}5V`[n_KrGL]:Y7Knju[XE^nb/6ޏ& \ɒ@^Y*63'AWh&,a>ּ"ØKI,« XcwһGwŲok.X$AG9&oj֙wNm;_y*Zeݶ&oFd7`>\h2N1z3atm|gVg'}=m)|n~?0?1&b̟ 'ႛ@W4uXɆzbKg}rE raI?5WCB̗ ,$^z嶺 -|:{c $pOw  _VpP(id)Oz籐0o I] ,Gl98tdA-м}(樨]I|S~:aU/\2rBh #Gk<4*/[s-AqF3a?^)E&矏H~;^1,1BCү%:l`ps0Ɗp W}L(w=G5#)d֣s=;K6$ r F}n*TQݳUF(F/^) Ở nrkKRtnͦ''z,#_{>n:#j,n>TXm>7# m5.~Ws ?V>T I-dCׁ#R|E[<}R%J}ԑ$R5'E%"dtt}ysb\ #TO>;GXMB侔9#ҝF*O8#z*|'}! j-yhɵ>U5]<6rߞn4_7  Xl7I}@3m82djG6n'q՟aꑤxdȋ("1U#6rE]_2+z%XA,,l^Hga1PI]yQ 6<|Բ v8a{9^uU  =O640yITYPSW Ϗ)x}oQd uk!71Ua{J°f/ tuo_ՋԄ|=^bf9~qW3[yq7 &kM>"N"R7~2qgсk`VgB=qIݬ۔D3o!E[wWC47up@ꐈҷk/aiM=]FaWz? 9,Rhm0e#n0jI~TV,-8"sJ/ĪqaTݼle0a@r2[mrEt2kO 'BK=-'-uD~-r5珃Pא!KJyH~kr?7.mR!7rY?uXaXdoz9шk^~5"|EÿUNe^8տ4}pȥsN9@6܀ t`|%mڳ7q!\9-ŻrdXh&'Zq&7 @ZXi2Uog7c6Ӊ@P=Y 8Ap_R)& U=€o/Ȏ I%"fP78Z@{8UDSVlI!!0Xu盗u.S`T|eX\7rOݥbw*1Y`L:uW@Pt}mnc9Q(FoU2t;xH&9۔E,Ϊ,Q\$k [Ѩx_[anwI<|Fޕl-3M1|;_۠&cfܓOYժ]G#dit!ӳJDs$ѓy(G۰z*tpHOnj[IF!A&LdL55.pL'f-b"jרH=kNK1A&e˸7ro#., J @I%ܥۓ"0N0(9 &u]4X~v߻GW~%jn<7yI.LB˛F0P9sߠ[֤bXKJ$WssE|vW㇢ d oŢ阼 UɳŮJH^qʾs졘*E%<=)so[0;.Dm5Yȥ`p#EbLnTH#l>39ShR5=Jk1Ur r̲&QP05ehoևmNrđy@s}V;x t4wyl CKZ@f+͞:߾ɉ~ZYȨ!|e6HR+@ImsҘuʃqLs+}W@j=L~zݔvnLr.fVU#*=OlnoH& Oq*%H% ;@!FT*,W"lΧtQpMG;WC ;Šh"z|ߩnݓ:\cEi4g>FCȪ]ْmT{RdIWfڕ}I^ܔ\,V.(Աrw(&KdՅ*p̻Lq8,Lحg5Q2ZC͕Ǒ-$+Aؼ)"@ߐ9#fzdзBQ ^^La}񠚌2`d$u~-.H pX"`\3BUKe4#'w&dȸBmz`"󯕘*mˈàVp#q~~6=˫'pj*[So@dDQ )^cPXTx'Ƣ&®ʠbK*5mҲIuA0;_(MQ=Z̲8TRXO ,l Sz?|HoCm`)2eIE`f&;܆FxvA._ucb>dZL@+sxL3N)knS~ጼ: 17 0E8uz:e.' M0̐Ǧ N"&җ؄:zÊxm_^X{Ng@/^nrfQ AB@z*F6ze8=R([1-[Uz`ZL lt>V]zsq䠪=R%U4[]oUC[כwz-e]{3~ьBg" BźO[.|ċO<H1eY|'dԺ3 * ʟ# ?[L0N A{K;偄s@kKթ_0Po[@%39+O#BmiP@Ws[=9$W]#X zvʌp~=fqI^VoH=~"b" R^;@< eIU"Ĕ]S.B:^*Gi:Է|)(dְ<$hh:IHPDc莘HV2fZZM3{;]_HedH\ZBǚuF6c#7d>XB<| zOjU+;iʼ˜r7{u,acؘxŵJ&>%Z'yɨHJflрoh= Ty۾cFD|?HkpSItV ќ^o,9oՓֽO = m!^juKɓ)#[xh)V$傽(J )DiDp\R!RO`nFkA$AwRWۺjH (tOchq7M])vEi9?4[r8,icNU1ڡv)A-ufpe^+3`'^ xIuڜJ% X+cT2;^pg55_^Yp/g>+ 9/ic;۵'FQ#2hq y62(ћMpЌNBV.]D*bDSBebı9SL'[)e7]z}͌.rY7hlc5Oh$O &`Vo{~X]Y7¦3/ᵖlsz=^2+?T\UNiRsT[>F/nP a+Pvx쉲]g{͛q=aF<m`< 3Tjc!qj), fŸ%C \Sny<*6'_gRMjˣ0/ @y C 蒊w {/=$'T`_PmzHd}ʵ]ԑ2 ̆8M5-ZBGxNdBWiTp9}4H&ZT63< x ˕:L r#W[y7)%aq*Y qi7t䫽T3$(Y^i`P8P) AFݚV~1USz:۔2މvr 9iѮ(h9[(曰?X~~VSD#6+ߩHeU0 ~ow-+;*v}rLL$^=h[\G=zWqT Yg޶8d#|gno=:)йSǑ{ѫt{$3w M!g`7dEαa:٘_#RG8d?i+o}IRw`ێυQ 4_)w P˒~8COA9S-P(ߨ @_ Uܝ#3Ƞ`'8^U 8NOaZ%!UEI+ dD._Gՠ~g3_ǟҸ> ؍M 6A7Oa4z1>clv.Uװ(sEJf(Ի1 G>0 yScwFpb_k0(hRW,ua k|v斎r<ֹ[*M㓓q SMlnhe=pM+mnJƱ'ŋJ5J1~k"T&G|ܐyTx<9Ŵ12sDU|A[ps5R ]<.B ߑ֖㙼}E-XQߵ[# ԰+1>J捽h|7I|\~>4p*#NNRD,Frb\$=rqWzA`X"v ց4@݆:`SVgL~mAz^#z&ٿf/=KmYKcU* T0%bbqHߣ._l=UM@S^19Q#BkT.1CI`޵ b#ҵ0V-01Ŵ0%behj@qW%43PƘ  lG0XDXZVI_%-?ɟ \b1%|8HQA>ЍG)%s-7_(tٺhlxYBq'4!&pD_b0,`dyfOJ_HPn_7}wL8g# 5/3H% $]mL! e|fa)՗TOZ[=v9ƒ. qnxRw "# ~4zߔ@ eZ>vKJCcD;? ]K+߱)0=7aw(52䊣K+ {}~kHc". @_;ԉn-I*'P9;ܽ$mJdfZΜw8LP^Yqg$t.7:􇱙ǚ:ځ$`$:(%| nEƣ4W(}K Sj1Q0ŰHSчTZSEKJ"fE ~ٗG^)!:pQ͞H d҆Wt؆SZV:SPfbOjV{!&vYE׌0b \ٵ)Gâ9_-ڦGuIms$7y.健oy6;Y`vGc\Y2mx\ElxXʸ$-46WHSuto%;qhڳl緋VO6~8@Us$qhGtr,K%I))QS)rЂ"4@K(7l޽U!G!l:;0ݎ9OdiV0CcFy.te3v9'NHS%ADטּN{mA<{R3^)1UሩIא̔cy8>]!(D< 糀dm#KMwġ [qE(/T,v1`0QYsr PW*j($7@',?^CnsIsbNý!dX)澖65@26ٺlz놥jq6P%(jd GBDpD*W2) SXCD*x#C {Q,`Յe0T$` ]TB9 ǂ 88%){tW^MqoocN[ʽn xlד^'B}xg"\y5\ݿTꦙٔ*pu.~MEh$ys4fybu8J3> u< Qڷ- gK62BvxOPKhiLaĩ!2fԶ0y3pDGוQ\q)i)< ^t""j;oOs}osfn ?WdE2Ty4$+o=n  6g(:HxƅCzݰd0mlrʢ*`lj'5:l> `Icb o]io=d]%Cڀ8Kq?We@̸mI d:D]QF< -c)6D6rj ڒy /.~9JG֦;"_g_:{o=vwÉ* UފKf0m0gZ(dz7C ԈȨ`%תĐM_><<`b`9_sP'KRY[ wH ֔C+O~5lT;ՠm3*L9yv*T̆Cgygk8¦2A8'O BK˼cb+y~ZY]}[ ǧlti@dx`UrDws FI투׭sFZ=9նt"ŘeEl6Iņ(YD5a—Ϡgaj<>%m./Ci@~δѱ&vI2ʼn9 ;W[E٦ p/&㨳F p"ePR۝ċ:/y-P|"_4 Fޭގcֈ)<,r`(gqߞUߎ+a)i7nkŶ]u1D@*Z؞|+a=/jŨ ]Z6)B_ZL \lQ ^MG0aS[7e(pY7 ^:5=fy4N7g[RwCX"NVR|+dl pbf>ޱ5%,c.F H߄(/!l4 TazkPFg|5у@`龠eK!S;1Jt,,A;hȺ~pb<]?Uv]TY:6k6,f /gJsιw]ˏ6T_MhU8 w-#h;jјlblF 7 jR;`jw!zrYY<‡ny[5%YdSa6|ڴ͌O+&7^wLص:)=R 7ϥ%$^ Ѹ3&njJ6OOmrxQJfxȤ=DDsʿV,0YdbK$ϱV/V"tX$Ӓ\K9R~Nj~FUx-_o4N4I:ί3MVUr_{h}E7.53`wKhˁ8>=*I5QaCIWN "Vl-W1傉؄v fĚk7SgiHb#k"+.羜ntR2.&R`fH|>!뺾E?/c/)jEM<3Y{0۶iwhf+"ǒ_87P hE%s,ڲ4 )~}%#>Ihg:0-B8(Xi="PDә}ٞxLv}^(1w?ΌY<^ *!WTr^*@ ya w ښ㗩yAtf7hy@c;*v M=*B̡Ж_-OTuY0 B:y}R)8%anxv3~J8"}jRd^\7;OcDŮP$U9;UU7|> }g,Wy;I@E īzR%1ߜ{k.(ʌȖ _e%dׇD^t [QZBs:^l.J/F9}'-Û #!t#}Ѽ*KI$9fDž,()(|:"dSZ._`rQ0"Sew)BT>G9:7? }_*{ b5A9?L\qNOxOD* 3SV_'*o1Pa,q5k۝N endstream endobj 345 0 obj << /Length1 726 /Length2 25775 /Length3 0 /Length 26337 /Filter /FlateDecode >> stream xl{cf͖uٶ)۶.۶m˶m۶eν3wb"86Vfrlj8yȈl=MJʿ,0dd"&v&5c=Cp03wPQ+P60pY۹Zx]]]]\]dbp67ZXD4~I(%T&&Ck # `o`dgkl_Ebv6Y1e!qy9e #p[g'&FU-?,X:ۢab[9 M,laK_v]'!(ѐ `lbZ@)bgcl36qr6XX{7\XYpp71VpGpSW\߻#kblbILQ}5u)_2k + 535(9J+X;ݿ|e -Z$(aa;w/:.6 3 8::KJ_dbnbbglZ+V8WN37B:sl1dnwxs?`ȷ{뾙 xrQ k1Iopk0Ul#9;@)̜)R>d ?eHqkT:(p&4Hs!׆{ ayAp7dzawp.,f [בu~f{]ѢDl QuR[7*ܽD!y.Tejpqw)dU44Cz%hp@JR͢D꺺A.䈏C- !q^MT~&E(YpGWDq,\ڃªtd(sH甓H-Kƫ=zpW~ bTCug *6t,NBcs3&N h6 ct^^U9zG  uPY?" 3b4Ffo_|Yߙn "moTҔtK{5Bylo>0Ãx{RWDjݔe/$2 dADďw5͉8Ԣ jm {2`̣`5 {NG\.=5jI`B~ D}Kct--nG9e: vy.@_R.jN~"G-b!{t(UeA UWalS8}9G^g= _x!]=0+XGbɱJR/ (]..0E1_4i=QܦOD :./yTۘBB+|*/hz۱]RdNYw|X;̯`Y!Y,\4z$c)}mk7#p!0"q(iIP c+Խɨ!q>>S7p,ϒ7 *Z_eLEtzN<*dsW RmbB'm4)(w1o'.B}s,*E=[3%IZqtt 4L,fz%=Q:̗,vlL_KxTYr >IC Z'?rq12aCobZ`SVBu<f}XV{ɵ!UjKh5Zl]˺MѶ9b8| 'MֲqǪR, |29Ȇ(wIx@^"*̔|L(Co7N>>%XeRwż˲4Q>ʣAki|:!.Y|J}ԂLx`4@C<+iܓ_'>~v:}xЧaC_FKlaC|L=IeEbV Cqv.4y^H0P`zVߧ"j=^yxJ[@y"ţ&n׫`R([,82!SUYDs dBT,8=O0p@}-# Ԗ:S):6*h:}gLw5)Ak<:Nh< mEDɥֽs` ]#_P>j.yBn1dDhP^j,RHAġhrƂ2q9l"of%>N(_=/hdR~ -X7fŨ |~^ =qs!GDgz3L&I Qyb89jo~B3ra6ͳqb)C@i[Qˡ,<3b .cPVmmsvqvܝҏ!Uf{ILpk\{ #'^ˠ2 o(*n[](8aPGLֺuYTpCK{bJBY@u~#1A<w@>S@ho)SF >03G(zq_[ő̏R  9Yޮ;#).RkŠ6.PLfCEUm*0X ;o(ΐS 036 #{5 w>Hq͎x(HbEQORc8ιS7pIGlEHJ+O~EBeQGAǻM]NqUN- J5XJ KJ%wTgBB3sϷ.Rsl/q"V(z74lߚxEcר#3O֦ (=Q@eŽG*?+ :׳R3$4|bhb/- w9 & ^ґZ+9mמq򊥫q(S )7| ň1MRZֻ<4J|FR|20c%4STۊ :ԏ %)6oEeeA X}K~B.f}K} &BDzVvƧ7!*_Xڔї.@p }V3e߃]5%NQ \aGמ wm* cv+6A;Vݼn+3}=g%p!H.8rٮs1tr0Uvܖ׸]-f [H*Jr+=ghm! iG=K)N猬}~L:ecrRr m;Bw[ X?Jjbz+KK&oIK[$eJ 802f͏;"]"f]ԇOon6A&aC tFe*IfVb7FaNXQ |', r&EQcl9?-冨7_vj7h=K]+`CW!nǕ;-\Lx37~=s?hqt|`L>`Z| 06ޑF\{"ٴBD] AcP~)ɭqK IMxGCejҬ#4d*ҵRjz.K[[\ۤHg."m`X MbW?[p~}ƋnIRȄgḀޢL3HQp*@>nGQTLHL)Js3aOhXx©X8ua^AJs BN^+Õ{hni>wT&,HNl (?֨LuLMjKk֎"2<1閕;3T4OoBGxPqhqZr'VL-Sgb?'x.qAolz7 | K HQ== }wE1ɃNwsA@tDC>k4Zew=fV{%@Rj'nӶ[<~X2Yi֩| /;U/ &Or2R$|_p+4ORߠi/LNxD/3E6f((a@ Do< HLYk/.y@7[߁! sCBh}y 0ʼ"}QU/5 Uw)3ϖZ)Nl;g0>yQtee+?מm1[FRUK߃cYSu3̅e]?ao78ZrޡkҲ3ܫLyLvWa!G>yCzژ0.92[=qJ 1թof-\w&5]pA"f̕>NWa[\K,&t*GJfw{|aƇ+7#Tڈ"V5zlDwđ ]M>ҩAh^O> KoؐQB*GMNsuzfUYvm(jҕ9͂L!vk\Dx$7=k@סL^lB#"VT`fOpLV2b# ~z'jOwz}:~5m(2T}kkp)}k'A a/?g.048}쇨A?F@fIEIwSd @i6o@\H\-År܍`/+W2L=-l4?`7P*T$~:mGu֥=?fϛArvJ(% "Ь MKm+MV0J1+x>dU)3}bt?^lVV_|3zXWiPӽG+|dk i)ˡJz03!fs`L/ڙdwY)pE93Yg+8*H(֔?wW<^vJ +AJ~c a<~BT%Y Csk6q/# ̡* Yg|k-ԗr5kg7NC뽔P[  .彅,LboՁ@m\˂7UԿQR#CTSDi3mQ5p"%rlm\찞,`cxߚd)m ҽ`Ax֤Hv!'s)]L08Yj;3IuΔOHf/ܪ86B8ES 9n{ \\~s9X@Jx?L4J->~b(S:rA([])+4B:=K` a?נb%->尷.HatsL^DS7IO\n|*KWW7|g8ш\D Nϴ(Q@NQAwݰ +OWpGt(J1sltB 5K[j߯P%:Y%Pf,?YybJ/~,lI̢">ƻ +xȦ`bWL:%΂IuLQG&i_L.hX^lQl*gtjIGHxH,ǦGnѳwNH̓6 L]%roc#4&Dz_@XtZfrd`ņ+a{lIG MVݘ<snbjurm Lydw:gͣ^wGƫr Z,u}446TPaA3F%{gH Cf&(p,REW #Y.#s2uP˅Sߋ>Fv\]Vvk;wCB?ߜ,ϬdgۀGMײX>3$aԣd=YeAٍʔ`j#tX~RłņdTe> ő1)쬅L0iuD$}SDF"q/|ݗ9ݤB+eslb"m ܤwoyACZQdc{}Scfڙ6m" 'NXE~8 z>ZS=Tˉ6ʢ:t$GGXMB0Bm}x\pӞdW/Fcn+|ҢO%šd꒓TNW!:<{w1{ZbOY ~ש㊖8tq6>M݅ݹ7?hbxR 53VƟ"x\ܥ‘Y\3p7!qO19CxpnDG^潟5b۹砙L皃Lx$c[ /WLӢ"5S}-q,6{p9oL?ɵA3^P)=Ru n}֞7%Kmi|*$^ v#LPnd!lsLcjxL4^Lz\ӛ<Xp1qcѬE1b?Zn@燮kqE C"BnRt},WnI=I('l;H-]V>sk E:ФDkuIZ=.(NcI Y,9%}lD|X*YS;fIkFN?cɎ$)mN`y ZXL@poi !xwTE!03)?'(Paa~%D/Nܘr? YN;~PhCXݦ)E&V'5&kS,=}vHSRhi kꝵrQh bˑ^iKFTy9ƤЍ|LK~~&K42vl];LRWC=Fo>Eˮ܊ 0沵H Iy1`4O666w +nF[ Q3k]=1:p]ljԎ&Ħb:1涜r!`!U!ysIz熧$< | 9Z֍Me\ؚJl\54CퟹZdjS/wȤШ :V8YR[*S~ EׄUC%G>I9zTOf\75qbl]ټ= w(IPIPv?1FSxuR|vˋϔ2N"G7[6o0Na!mqwEm=m_޲, hDi-ɛi:w9x |!ny(ëo(;͖z,)+;u}ڝOÕW^/LcOl&:n٩3迕u,6V!!K& .pQ8J#+#4?/xdOzE >5e=} XR*F]emF ωdܐE)WYTY½Jj XNoތ>w*,N\S-gʷn.6ƿL`T"gc gr`f b.|.$椬w{5iP*.^,d(p_ D͡äD|ǚ|v:tBy ߸^6PguQ9It-wfWL:KkWBƇJ?"ix3e@v * _!v6S ~4_uQN2rE~GnPc> ;:Yo4{I{,|5EDׅꍪQcXl7\^ toIF.ŕ:Iy n.T<_R/e)7JO=}rڴj~QB ?[˥0/t;b=rT&m ܀W59 9bTr荼ѼGS}ӉT¢ĕWԒNl'&1=L +-RwrqZD kz(EC"dh[;ĩݻN5,`>MsF73;uXQ>1FNJ x^n$3+w{jՖSIsJJ?u-{@1^~f4X`CS@/K Gۑ\#P&x\^LśڋݰHb꽪 >VQw'ÆN(N'98}8!{4ԇ˄tEcTYw%J\99bSV+rs>Js< AAyz^ʩ]i/nɭJϩxOly_آYؾDڒ.BUD*ӂrnJ,ڝ%GԞpןBGMb%9ZM_{b#+D~+JK>|ǭ%sS&HZߘ.| %t~kښ?R&1/d#+9q9캶yc({>&޷Q*!:ֽ!D><9;?a4G=&6Mg7+YieaA*L }szd88x7k{ I za%|^Y!z݈g[0!'|c*;ϪVt-L ˪Gt%H!Vb>1xTta;%U`$ ASY)o'-|GL^=}[p0O"(2㈃oKī_r"BoR8hXx2;Y=7vy*Xq& UCDK|nԔE)K5w򏲷)MD 1\%Od!qFmY#fnPSnX73f}]'W ǐ6-C%_HcG}vņN<b]&~ TBM3-Y*22xPoHZ%2T\WdZ7{O-/+7]cdT&s|ٓʿ37 /tt@.DJ)Ae Y/(0eV-~ʓCw| }':#g@lp jTG9xuWdAD- %2D K:s!n\nTMA7dކu-ьj`)]FV ,ECPoz<}HpТT宏m QT%4@Flρ{uչcs| i 9e j[N~gqV.#!x"*c P}f\mX!mjG'BmKڏ HX@Qz`s L'3 h?{hσnl6f cRM3IL/Z>&gTmjIeQ,ǑbΎV|ClոeRtϒ͕Ф7QSp=۱VL ks%Z)X2Uvvn6V,-JG`RqE ߹[\ qRv­DP1̸[hcyIy<&뻓lhoa>sļjSfS\G:Cj"q'S 4V~r$a*+Z [zacჲv`J'$c@< ׊aͅ G#!h,a;l8zۯDMu+HvhkN>u#aLb4Ov(#`V_yp܇K:a ѕ*/㝽ZoQQ몪17HG uNKuQ-SЬ҃&7Pil~$dqFA7նmr, DD'؂+i' *+?Q"#eJ0dxz*^ׅZS's¾Lb1hi F$3u@M{[}&WF9?#"A5(0rDU_U(ބ01g|uBuyȍGܓ:HA #=i-sulzgl'N0.U@vu> ZjJdd -!)q9·j_4оȌ6Y6Ivɤ9XBvAC]&:^ 24e8zLѳ2j*' >u5`yy:V4/G_[a8:*5xX"겔lȼC8jY/ oNnJTae1u`Qw+Gm)Hc 5%& A4p@?@H ϷkG#[tbQW5-'@^b=]Y@rC>=W>Juc:G笎hc~fI*{';.ErNEiLpO2Jzcb\`p(ʰ0l.Y{n5/◱/ong{6J_#"hV*d׺$:7G0j}Y]ԩ6yuq 2kFv'}R<pFkSw>l~0 _J݌)3|÷[݄Ńr\+~ozV hF'28G NSphl曌B@87z/<>,u> 4k7Fۭj%Q唀5#3&I@U}u zp n,fwfs*W S/R^TCȳh 6vZy5FH fw$z?2DpLJWΔ0[Z,?u^$5efP&E£z,/tx]L"boqWZoT.C:DͿ?iL@-"dsh:'E}6|:qvqz:?W6WU I9f $ #zE dldBJ `ٌ&)=O޸E/UXb̿wo-(Ot+&yfر q"-Ҙ,t+scYAKQxk-6l[ __фe!9Q巰H;SPPAlv)QT}`klA힖Q/ͳà=|ӫkJ֜jg|#Zԕ]6\htHTJN5`>>`VryoK)(͸:1up!Ė #hc WV<ڏyxl̲dS1wGܵMʡ+La?-AuJZ U7d}jn% 5&3P')@QBv/ϫmTԥ\nߎ^msjC>Ңjcc;꧖kWL#N6*,N#I`(DBW& Z\әUvT031BE!F_GK1U'|  N%nEv˽QMiq5 ɫ*D-2?L6$C"Z2ԵʤxWfqZ-Ls=ZQtm-3m^ x7 #N%%3o{ن Yn;h&BNoBY׻ X`SV}+?#6 ll`)Ϣpď2/ЍjU&9Ze"C8mF] r16YBe6$d\</J&t<~UD6~yހJ]jDzU}. 3ĝ)dm%_T=p qY22>[1+3O& 4VghKB_gRD+^":3Ho.y_C ݣ].$ !MO'3p{7Aeu{trikz'μg'?:N+M9BҤD [ʙҳ10lVz b ) N?"'XjRڃ%#f>#K U2Lh gh\;~5cᯖ]ZlC?>F8@-U捨:mVkTыV(2H`L\"0%H!'{&6ʸK5S4F8zۿ<|vڦoH7.8K('7m׸)U~&7$"}}{&6O_`sC3⛆UM+=p_+$4 *2;h%L {l֫VO0x :}K5zow)EUGq['+7'E:ZHSgyy ":EI>cjV}[0F_ۂ]N~Jmza[!'˜ay%vw\yjFjcQ$@v'N݀cO)L̪9dZ/q2sjg[~Q&j>NC%J`#߄S-%LD7jbkp%QlOk ;{B}/+>w>Jq>:nʟPldhCS: B(R)/ȭ9gKY*8FE!cCgSt^G_ ξ~h p_[13hJfa.Ƈγ04Hq.HK-JD\8JOa'(:WevHNndER)2AYݧtZ>kh[( Rs?y@<64ݭ5i\-%hDˑ(RJXF?UҠa[ab$ :jjNǓnCݢoZ(SA:QӅԠ1W+ T}Sh"tEr?3mR!qʛCg|B"Vy1#/]\m=KktSGZn_lR-0$g# ㆋǖf 'ϛT6:Od\-ː@^ /pN$ UqI6Wj&nٹi#\=GN5ۡ V7%/--lqKf91%# za:̐&c/La86z~w c4DͰTK8}eTs5Xv* 2,nR[!W!={; j Mݎv,}9]T-%pN#f1- @>9iȈ\blAbU@E\G%mM qM,IKD vr]< Nݼ1n6-^kIZO)[B,.t[GY6s;#lHk( >;1 [>Jg[%hiB۠q IDhorw:Q=ٝ'쒺$+͕yM7Bu]&>T75{oA`yÅR[h3)8B9#}hG3F(e4⼰2UVH  l N`U֣4=mqf2R8w/m8#9ǶApS˴SK*TOKxzlۿ(X|-x]2T{/9}NэSFP\]QmXżDfӫ*ѯ۩XLB7asKbĜs>Tp6G04w )u :$p}:e`z2?iQ;7itAv4Fw]ml"ݠo.8oyz/€c 4xf9*O&p^Hie^[ua4r M<7cP9x#uW~ᯘHW!*ͲA^ wm0Rr9|BfyC'Ħ+\X3-fujʓ[߿cN~`ʰІ.crI^x 's=v!HٖDYNU P3MQT=8&90Bco$t991JRM攖Yaro@nůcWШ;8@*&gTϛ?\3ϥ8wj.g>[ p4U r8P rF]nJ6_dha2pQ*ilaW'oy_RRire(?ҾO5ZO4@I)=hJ0VU>Dkhe4 ,`y{'e(sF*\rsvmb栗FOzv-%bIߒ9o9]$ lJkhA)k'߬.8Lȗjweq$l(_p*OZQ-c$TP xᝫ-5G_;ԠD8s fuu{ޢ'NuEL= 3O=w}=&DSt hblfAm b Qޔ(0nzaAL~bd:6*[ @$]̱O8-(khZJ">[^x7@(~+夭,>Aeaݖn DOh۪?a!l7o_p|0Pţ |p`s(b:׊Tb +B}{5ߏH]V{h5ǟ$b rEw=5X!6u᣷Dȍ>14E&Uu;~ʊδBdHMO+z![W;$ɫHj x50Kz^$XMݓ#R:۔D&(4⑩^.`Y#bJ@!Oqy>$NԞOiqtM{=)|lB``WV!z y|{Z<*<_N$)g&_M}0 wN`DTqQ!uk l(O>qfr$U2+9zhDkP=8#HO ip~I-p*Q3ivK-(\:1w y c+*=QH : aj/;]SDFt\ kol͌G\=>`!+)4<Ó*ms׭n-B6aV-%TVt%7:fj`Du1[ڐxV26/htՉ"KPogܫ M^Oeg1)>E|&wM^6oiV ןlnKCgX}Uo{W)8]Z6 ]{ |OO/xN4#`zI7)xr9RoK.ۈژ N O]msd w}@kbՠ &br*~=%BcG6,}1'1'YlGOV|q)d Vs8V%ΰ O "Vg,RgqPȖ'F 4'ͩ5k(\&{itcQɦN HDr89XvHnC7ԝ]}pHC@[˶?P/`z42nۡv?uzT__H`: nb2 tΓThZ_a#kGTm̟EͪlhSHHGWt렌JmHu }`oo=!:r; Xe=/-''/HH&<Ь,̾ze ׬+<0<`e8^AwZh*XAT+UwףP;tbFGa4[IP0> -XURs:!MrѾȑh>uxR_glևihW$?U8%- A[9.q&|(`?,% p*>X {?2t )< ybr?>LJjz\9 W6f>,=IH;T|/Pzk>2BϏ75{&E^::+`.[ln0eNs%ݕٸ#XF$LRž8S <EPLEY#NjʈJ#݋uqZ&m ``f|<#w&B CFUmS7#!.9qXc5w<:-]$&k 2}{UӌJ >S[:~| .'Sg]vO+?p&-RN,0 pȗ>W 5xP\Gv#b՘rۑv|97~}b&_bo40ַl{@5G{NU UplbQ(.}v)4[ d _4J(Pza+>Xnͳ:Wn 𡉱ģTWҪ;rûlL*t͇ cB58SA_Maa'XF'g¬GICb.%n۟_KhB8s-6z1F>Eü®8򩇽>gL59,R"^5_\40CJx+WRvzLQ=At/9DD]ac-7)Khkk0v:5M"97wź+;1$@-Ej҂PK6> Ib֞!O'tkxhvNţюFdն;R& Ѯ~Way_jMG 3P\ Y=6ib5\u"3Q;X F>qrA,gW@sgTqG4ov\p09% <Λ@r/A{ESyWj./Ӓ3a>&|sjs *z(u6AoкtiqG' =*C5Qs9w}BYg}-H{\H#ZO6 8q[G)( >5I iFYRi_Brq;:cY:E,`:&I`>JD F8Er-B'vKke̔bJ[t,~k(Hqx1 H;AZۈW(CvdPyVa6q(*<^_s՗= :gBq/{mnIfVT6Z`eBű//}Ϗj- rFuEp vmA[7fcטUIxlHvylPfWNL\/S^!L07 :r2Ta2N% Qay%Kf/V'c4EAn*ӂxfXCλ5Ա Y<c-EGUHLꐶ+Om8'^ Z 'Vќ06wK-sXoQ({fV!VLCӂ^X͝7Mh1}-')Ns4aN)xdumЈKYy ^!Sr;2$nE#Y}@q֝Z:e'. CM,P-Ǚkef!{mL[C jNYtͺ/=V|fՠJ+Hr,E uF~#BmjBGph;#2R endstream endobj 347 0 obj << /Length1 725 /Length2 35980 /Length3 0 /Length 36486 /Filter /FlateDecode >> stream xlc&ݶ-\̧l۶mvWUm˶m۶m{{gc5"WfF۹x:221pTT t0N.v".\uS C wt4pPS P14tػY[xܜ]\)R65X,mL r q9U @ ciljlJ 0wg03&gs3ur-@VTEPL^N *L" 03HSnO˿ײ1e_Q'Xt0Kc x3m?9@S]ml mM.NY{S';ww?67C2?.Kg1KSKvqr5[?{#kjbjr8gWMl ~Y<[.ȬO Ոح'^iuurLj?.RD0l#{\9K.2c(TxedzDNgX6;BJi.&rlv`&NdOCGO[[ʘ߁ F`b-nL9;YG-3cYWUH/|hW%.R=+xnjEXd%}僉܂*y 㺓!'N,9ۏᄏ^&zg/Mʐ @f8t_nܭjҙ̽j7sZ*C[DPr!e- {epxk倍^p&2\0Dg ;$=5>R@ėПZ&ۧuj/|}T|7J:[`H\ySU a{ 4-96_qW* ̓3ݨ2Q <qPnw*wab=V\+n.|YIjlwI~w7I~L=8":WU !-ޓ.[y.+JΡm9_6`+is6mC3f̹IwH`S7L V+CpM&WG dӅ( M1.V p6D 6ɵ0ddG: €_ MͶ`;"itᲹgc?n AN{Yo૽zn}I]W6$SK(kEꔵ'?1-!'EO=+ORbF:JD M˂^)f Y4I'}oO>0ggHǓ ~[% gY7S);6ng2W=DshL=:Ѐ9! \z~:ƯO"O5Cmuijߔ>1G1}5ؾ!KRfATBETޗ-_.Uh Q%r>8T2IwfoY.tX *b} lkdH/!=T-+ϔ|mBQZ <| ͊urq;?xHA>/@*T0g#nިn:B}9~s.F?NFb]6}r~I_RbUpS1SI3i7|-={bdl>[Xi#\D $9#1@y x*b$~zdO#T2~uqe @\J!1T"Ɲޓb3UI#`ܽOOnGweW);<[ʃn2*SۮOTRiDh*u)adxBb·l˴ίфugaP[N?'oFŪ3[9Gߞ*c\4&Tz Q&g۴}Y"1{R="wҩX^BH<6ǒƤA޹0#Ʋ :U}ba7g/]~Y 7Re̮ɮ~AOD~g}׵nFPy  ('047Xs 2B,7(տLsR}sB>r H\\ l#vyc0a~f>]!ӻHڥޖ)O Pbxr}ő\jIe1=LW~1ݟJYX iIvCR#'UA0V(ж͒=t=srh&N2bfT{:6)hnBa d+l;XaX)N5*Bp[$=$;mk#&vu~ Dbd\y2Vh:nށJ}&mll''kƲdFqOD룭Y}pO*;.*P2rw %GmQ"bѨE&v:M`7Co=T &^,+[sa$.S)MD=*UL? fk[z(ʠ7ʵ_c61ECINY7 \svf?T2G z6,ɝcKˍTd`/Y\LAVS+6}rgjIsG1\5pOCا9S^LR+9ÂhLaúZBt }uW\qb}sh18]oI,|V${ hsi#?^tz&GBEq2O{MUpeɾX9Zj76w uUQ,imEL"nViJ;50Z1{iu"8&xO3X4WLsmoΗVJ nfcU+/V;ly}^^6lcdo+79e:gYȎ\[~Y O|UsN< es*C 9YRX%ReA&oNU[\ .}1C\`$t8Q| E7{Rf1ن,N}MŝdKCh%H]2#93t1ctЍyfgfwަ# Ñ 09)H 8]{4q/< Nj|)kp< [ zAz.ф?{ME!ӯ௛ɐKp6d֨[z'|9z;~ߴ1L賤~qόo?4& 'ϱ$SqHJ9;TP̒]lqaUy?{Sbܗ\]NA} d r$>+S<{G{<9[پ uX Cw"%Erm7`3tXAQsT`AAlݳۖ7Ҷ2bvȀ3t6W <"pb6QV`)c0"I:= ;<]/A ]e~ICܞ6׉Zm  g"qM dmgĠ%#-FK*:DJZ])M6]2ܪuVT ?mhGNV&GVrҟ H<BL$Tuw~v`9mu/zCx:)g Gd_hrAb'6pTyLj_McO2oifLw}^z$+i!%K48aRΓL.r-szqlIRVF0r !4w(Yd4TMHX~P׵׍)4dDDrD=H6uͰԧ$.OIaXފF? ,!b45[ĸ 8A,awI3MԘ2.%1|C&Ȓ$DEixnsL/ #JP ٲcY>uU}yy`kg6RG-z >@؀6dw܌+łK&mǵ\' :(ꨲ09O?RѰt(1z8/3T}>\y)hh\B~Eu{ {4g Rm'#|R1Sw h+7ӞǰA8)TXEZ͸fk[|{&eRh;:o֍9UOQ&qA;t<Q_!ẉ82$/Rb%G xvN;;`CڎmssmoX?Nr*>Tŝhi,ZE9@ rf]C$FQZFz7A&Y@ 1 eZdAeC]K .&JV0,Q Ϟ|yA'm>wqGު@nzj1qZ>0(٠l>j6@0O(mI$I CbG֪,mGJ' X: <6Pg_g h!ғshVƱ$DKq\=cwrvW4߆3 ǒ>1C Brjk5,~-$"|z-ܒ+f}N"rʃsK9jcH+*!-ϲ,i3x›wIp g7v!~^- n(ͭ.DP[4q qe%o,я͌_@FΊLP{. HF9F1Xn/S)F#ʹk$poX(\~b-!3ca{̧vaډ9fUR.ZjVB -*GF+%"XwD M6{=gf MB  n,!Nrod:9c_Q%8 :Jy,iӖ\I<)k-#v&zNugnEjdްKN-4?Wz,/GM rnq0ټ{.EUJA ^rdS6uk-J4f4?B(]ۙ/6ngFt&<@[OAᐖoS\P/͐Q?e|P®fW4P9;wQYfeny#QxVGf\>ƮDfǎ-b0_#l6iW; A< X<>spwF'$!?iv2-5'hƿm I٘X0֨ &v|U'JNZ?gȮm$>FLJH<85fXfZgtap'yL1+ +[b{ؘE r<.11Sp!W|p 5a4>YBX!g/7gX`Z%[kTD(oJBVE[VbϞUVCQeo̥@ת_]3fN.Xӯ'UΔ@i9ow\C SӋW-݊]䑡Ybǁ0Y$Ht5I)']#a-tn9h0Wɬ,+>m4@;!KBU{>My˨f݊EtIBޢĺ6tm\{UNz/u`G$lpfOk!Xka#fER2,@nHHtBiF 㱈?!Jƹulۨ=҄Im>iu3r&䓴vfElpXA2!90&Kc %'X :? K?U/4b `+[s)uPY{E}`JXMktFҦXA"@v㶐Ȭie摸Qbk[9km?@,XicrSRyTxXzxzXTMFgd]IEcζ;<1[bkk晧ud?t'Y!xL]J4,,oiҗiCn#(70PVl:n$hudj{)sgd1uMN' q"EmaoA59> eݣa9h>j0kV5jq,]MVA1ol+KQ aj%Oq-r#aW W]2x>-8MU̅603h%JHWnxN2JC0ɕ!%PΛzWҬuk12WS}{֯G5[aizYp1 F(KL-9( rrO}5%| 惪 ]U< sIZMW&+*oviL[J˵^EY^zB4pnv:9E8Cwkg2l(~P7RVhb5 "EB21e:euL-+ɫ4p^G%u✜ h?蓥`tִá0x\-_[t]XcG;RVPL&=Q="]ۈW8m~raڵBї )H|"wF8%5Qo'rv/?WNDMDYKY/ьO&v!AHDZ8 =anq*pn埦R1?8C· OcB;"O.1xUlYf`DY3Ty}ǟL+\(ݓҹMun"Ho\(?`՞hJ/3T|TnOl+sQ8g* lDL *HSQ巪)_E/LPjRS NI?0g W\)D9@݁,ǖs;Ց1NRŋv w5rW ( /ǡn]RRgudG| չV.Lih|WE2Ʀ^w֧Ej[mdWd#D7-W\LnZ?9V*ڦ8rsuz u(`5S[` h+{zҹdkNffYOʸ˜F~qhrUUg9׳.bQnDF9L:/O|sgS=f`6_l©;esBwzs50{k֦,bBp:Qw ׫ᶲ2^>wef";i˴2;2ʮDԒtu8 RNqOc]>r)nR)e N}]%v.'kw'cc҅0Dw4Lbf s,vulR}8G 0SQ𗴞\羆FoAQ}|Ɲ&tJT-jK~  "`VX<¥ړ3py$o UǮX*2Ap7KQ9-t^_vnJAX 3f_-oN>R4qkSLƃYDy=?ﲟ$Im%ĥ !!hETeŤ}!=%NB<Ӿ^C=ȰXC#QdBE#Tj*\u("ym-uD~)L&9i= 1[Ⱥek`,c E\۵/--}7̸⽎qdus'HQ 1sꩫP;]AQt뎛_^ Q s^a/ _׍9a$~\گqqܑZn.3C˰29KqS}'d?ٳQVNGut?d.l-lDgJnc_\^bV}v|d֧bjAgkDҰ^M4prB3q+Lr SZYdN"WJ߼e72*3*c8nZ[X53Ce{($f E^GvOXWb'[ŏq0x]f2-IKǁwuյE]H4Ja$ wn>Z{8qE4hA, ]WyɃDD F&dvS.mBjlW^ikDZʸ3nlLE lI\\JwpɈa;^Ҙ#h ]WN?ҰS#o~%}h6xk1:[k%WtY͘r`2T7/+E{*XaQ w>>欢WuEI(º'$Pv&FTǬoBٺ1a^QPQz s}y nz^>\.&tb>*$tmT4V52v=kn)E#wx I%/ʵ?+S4;K*dEJ|%"^lr'+~,u 4*\T`R*JAK:hҌ뺌נ@*@ȣ=O+"G A=_>@lׇ.D603٧*x,AwX蘩4yyA d5DDNSA*4h [яdcᖦz%p`W:_~k_|־#g9\W!`S~/$f5d B[?`g3 zVsND,33QԣT"wF ^Ln$OLd9(# )+TSo8[/6똪hwyd;1rnj;dgTSxfIoo;i+Q^P;E1GH+,1. 6}J,[ Ypb2n"LWCP4#b7rX~E,Bt$+eĺ z(y8爏W4yVjW^ 'jGCXp`AU8,G'1!yϴ~Trӵ%yLA彺}K]g2mna԰"S/+_x <}q匑)Fy 93g2q7?S'`H:qly:5nyka>1ib)AwoP8Sjš/%PK#~TW#D.aufdflܔb Gh'H1K!"2D݂UտC  3EXy9z%ЦFs9 nW8;5h}'4_st6K풨SÈe1?\"a}>_d5EG@GV㙥pWXKăF\TYY}eQ㣋9afUx` #3#uY~5m6uZ? ZϡQ| m+@I12QZA˘~ӾQ7.b'D▰d0䦒 |"OI\oVK,X8"oƧi ~ac#ҕj3^Eåzֺ7 TQ}@t.ck:3HF \V^G̤4[A 7vIKȻj,Wڻ =\12ս _TUt6G/7*m$mz_'݆Fߝw ZUL1_h?wJ3ܗyԴFm*&ſ3ۋ ȥ;MLX4at1W@3ߙt2ӟr#){~y !_wߠu"H@G5}K=ܐpQHLnpz^ g:95 21ڢf9~+球rvTff2;&F&%|[Ѝ󩆈rו\(Ix\ڽ+fxեޘ+S3f%`%tЏW>nT2 s&P:;zEc|<7B.bcr:܏&\+`޸GK\!98E|"QG#nP]6FfX%@ۡ'r&Ė7{>&K9jNی'̈RdC*ݺHq;cD#D=ޑ(پFWGU/ѫ1s8dmPܜBZ?*AÜGK}rR>׃ Y$ɳ)g귵~fZAo!pW;G4 ?T0go 3b5}6 xgloPX 25BYT=cD6E H'9O2yW3%]!꠬k+͌+Ur*1 NR_Ime(FBW #6[Pj˱![U-Ӧ /6!lɃ б7Eꭢ'r&HG!ƖXek.bdbץ;")/G]ɏ %U|a5?S?6caM'зf`&_Gm owLo'{|g֣|Bd,Dzj2fb HMV>J9a#j0m.J>כӨP{D|EMSc.Qt͊Knf fʈ&^!8_1c|fg|Ip4++5OʙKޛYY| 9OZ'hd)+'M4,7/6kpi[% .m"=VTbj {9=I8ͽE]ū_[W{kJU O>"~"567;b,6prxarg(ZͰx {h/7OǢ!J+oa|.!#8=1e?? ]M!;լS痈ǵ D ^~b3pг`9QrLϫ}i3N*DOIَ_n٭XWSΤ$$F Te45ܽŶMg>o)UX,vqotq[nM6rɋ/f$J>~\ihZYz0[9_!{|e^f`4CWe8_|L8ޢ=,/tF0_=D= !j02vOֲˁy)o' |E v=SSq}|:uڗ<`M(ƙv/ ɋA"zBƴVR%JچdB[M`UaBh5O-Ymp&=*BNo]$ކ$ryִWaX$R"TJ)fz; E@ :ބUaA/ k 4/KaG[,k):]{m\d=&y5N3D~ ufMlv:ZnZ 5g9̖rqIz9?y,?\Cp.c۶m7m۶m۶mvMͶũߩnhXGgH!~c+m<좁9?kL1s5qF+Ѡo<|v21ⵊh^6l) xؠo_T~uqX_Zz&@Hw@=&>G%;5J' xh%$⿪4/q@bW JRٴUlg!4n5vm$0U Vd&;+DvG3^2gzsq@^&3ȦL[TD%,>h]Z,<սκÒQ0rV_$~ʖoF0}lT|pNxDlk$Dօo\F&IՖH#iJo+aez=6`#YFUcȝy!m%vBӵo D/Ϲ#ec7 H& 2h Ptƛ[\ȥC EQ±8$7?\afkZ -Z@C.RT(Ne^ PP:oAF{[i4fM4(zLŸMմDj ij=gn[N+ShG2%N,!lXecԆXtT}c$k=ṏ,o;L0p bn3mg!ZCƾ}9qL(YkLu/B:z!&X#t%IBsYc>ZŨ,t=Ԣe ^}S!AOQ0!ݺ Tp@4+q;d]1F>i{-Px%}<#27 b{kMԞ.0^Ȃ;t5xrԶo_vos聢Ο@`V.иݐ`E\)´:Ǎe2?66lppeUatk7Nk9TPi׹ 8I@.e1r(yj DRX; JǃRŜ|rhEٗsyލ1SK U\ZVa{o*}|*8-U+sxeFbY#:TSFT0zh`))r3"CǨݣf5XO g5,}/)+!%gfFnڨ>, yPJW5zVUN"|C$7 -WdQۦ=8C_jq騝gn^zn}$7?9=utE= _s_Uyǀ6N &9ѯ^Vl^Ds{z7 ք\ZB,-`SiK9e]Cġ9 h?Mt6ަat _ s&mK6֣|swIEgfv-_ ;"Wz x|=TѯPo:bXnh<zF%OK3WM{%p~[yX~$e3\Esl̳Y>\1<;yk#D= Dm8z#U᪫x~X=|Vz -0?nv<gIӡJBImkm9~(6)afHF#g%eΉLjP%zadp >DrЃia.l\{HV~!0! H@"8瘷7wy=7WVnJz%93d }|)F2 09<_PlSGXƄd䱊8GH{ knh_q>|,tv":KX_Fthh9N^s+0 6ud@~- {c#%ݓ`d<̔`AYgi Mt{xh B! ~{v"dU0o-}ȕ+)}L3A!"Uճ%YFN-R$Xd5"e6\> :Ԩ"Ϸ[4([dB/˜B#Gw#wf5zS4RZ79f0|XK&qϽ𒣄+Q?3dpX> t];!B%UvZtsȓV5(naaqr+A}|[8>(=#^g$d .*׶?3Pfʚbokjg1 \j-N|C{heߠHpf-[Y"Ybp9<)A=0J͸BdB37x+q1+- @Ne+$gKI [L^54?j d|j#jҬ黩Gr܀ۊD֞Tx>k5$-.2ˆʑXCS:Dbr@'աex5Sv:8Aʼ{l (%p ܺRH^wyMVܔ6I?Yʿx*E |T]*6RĪps! K8єWatI02kG_yQ zݘ: 8 Y\Ύb=ZR댊uJETcGeE`$/Xϸ~.]s(d;JQ,;E5 fFLR0 M\ 3~Է3#1Sea).Zl%1"Cx9DH>mڽ);]֒&: ﳷOJrZs2X^5S$S^.G3mfղfΥf حKMGWhԦ+5!Xjrn:w TO >tcu8vcEwM>*7 y2ذ8>%xk߶Ju_aQzеy1TjALjX(kWx}CηO.s2aɞ~j3?rx 6_q"s~}',,>!J&SCn8W9*׆&Ґ}0'.d~ EDdv\0ںO Х72Lbͯt Yt^jIxN ч5m pZjhjࠟ"yW[6@H83-Yc|γk6sBhVNx[5FE67k" /H:ⷭ`X#;[:R%潟s{ AB衼BT\9+-J}߅ƛgUE<):g8!S"5 ӂdB<2gѦt=TS F?bV/q*۵p0P[*,]h³^K˼Ԡ@oOT(p]ec-.ncBbؚ:hwA *yBd9#wBE+MU,Z-g[fL9d~`Y6"8׹B8NK[X(W镬ȏ 7Aa ]Ӿs5k2wٽؐaY\A3Ĝɜ}>>z`=-%!1MP6p ᆑၳ0:_ªۥ7wvꇖ/M0<4xw6qdLP) f 4 ï6%^P1煎} q,uR6F`#ĘߚmX3SU7%lzL=],M\^l13*Ԋ?)eֳ=s+\ix#g:XTrcH}"9|I$s_)' Hs<}Rg;l |ΰxFV2D t-A`8L_q&_.byJMDخ마r<iףeCPϿaS澸pIRriIٵK՚bFVUEYAyӗjs7)wbneTh1zKxijAHxM|6E{ Ye# t?/bOI[8-X9U)UjXQվB1SoPB;݅g4&3KQZD1W;' :{;ղ8X s|gyAgѼ/K |TX]5+!g<dqB C%Mo)iHx 9ް~@~*4hBB3"P}>GQhx>?`ƔErP%}lRr}x19OMpȵB=!u=iXe72ziuv1ǣ;m$Jch`p7 eV>n.lV\/hwD xe&} #!+uVbj313pU(~;gXLT~dDcurDpIR%lrT9fQ?U{8c~0,,G^Aޗh*%Cȶ 7*He,\K)Ņw?|_X,ieH/mbl]H};vQ`b=IYT'JJIaK-8\_IoV'q017NC1N>b{`ssď -5t?ߣ\J25;P r{<{\ ؈;׏Y7i8{6'D6A}e8:?U,mUFR/{8{;¯CU[(]Qqy(Μݟ\}=/l{. >ٍ3]${9ظ0ITR8z=\4$O*&)ק #$Vnw \+l-fqxq;ñ,YNͤ֓9`6^ y_N"RzrRUϚɄ&i&Rƃ zL43VRoD!HM|^Ayg~H1`:݌(Q'}S7]%w6! ~ks&dUPuRVي⓻4.H_H ?^0DjǠlXbsϚ]8[93{X{9z$,BjاG,SFp [8J(*!.ܙ2NYF 3/ђ9B@e [/^nA xexjeR?j*w$dzL\jj,Y&@:YOsU*V:X[K'XY5:E%B93# ((&!.|x6gS6tPI s/cuFᷗs&_=IkB$5NW't?)%ⁿ; 78NP}hVL|TFwJU Va >|+ >JCͬWx$(57|D#! rKJi2q,5uX6%Lt _]Glf 5 ܈V/q+7Wޛ)ODL*`{6V.yոK"~)di:֧i]4C&&~:Z|Ccw4Qy٤ϱLO.5UjiGP*G0n8)Ydy>U: ^WW=d6aa:_`{c}ϻa6iY|feel#ӗK,!ӎ~g3jX.&3杓Rձ&=KJ iB/YYP=3iG<6\I$dHuF@QgE,å}YF,ةX.\V^ҡ}W .._CV/5A=K% B?e>JB9ݕI;5JyI0;cY-lT4SFз)=`kmHѤDK29W=ۯ{G8桸)%g-;>T(Ǿ jmH7e3 ljUnUhx>g܋' tAAΌۮ`($lxFIU+:v7J<Z92Mz:&4Гћ232z0rEywo72VJ5Pb&ָCayФ_l>U_|bȗ3B)vf̡ۧ6~ʦWU`L$<f%P'8 6D8V4J V֒8 q,]LfN3s$ǀe5,? ?؇a=\.*gpd{'pHge:i|j+ 6gGk'c@$|$ ?z(ގ\NZO*TP3kU$]&A`;WscndVj89^haWmRVe)Yosp_vDwvWz|^aF*jVAq6s1%|:EpfC($.4${Q#!/ - buZ, F7>|[ILc3wHY j?eH buH-U?)bhz~P9j7P^cU%F;#DRR爃@*>HzkG kAݶg34"%lEGh<=ul#3[jǁ)\}B# Ʉ:LƘh[n^"w@Պ`堍KOIzR}rS \b(Jc)c{{1֥٠ӶWo2דXw+ua'{-W5'5ʗd/v;*>3 m'X(ۇq"#ER򛑾Cu)P(Wj4I3@셠7i] fb3dMG) {g'b"/7#KcA#q~[? ӣw4{m$.Dؒrpْi:1fu#J;_"V M& K.|YFExh"58V?K=݅$tXd!^u\)k G,õɓ[9>[Hwd7%%Ad uyl Y𔧿5U ߕefht3x,@WJ>hGh'3͊o7\AȘ[ x T켪]6-.&hj9Q!Ci*BB33AcfKRJLd_1yw3R5̾v"45ʱi4}Nѹ"6`"?y,q׶Nu@1H>c#khy/8'@=Tb}t骔QSߚ'*zmp]мުRJq=/;^sy[I X e|@*#N_mU׻ΰ)noU)nb 8*yԟZngq ,'B2bˬ[YC,E,xI6ѿ?ٵ@+5:>eQs h3F>?&̪_[1 5FXTI\ge^}7A>i_0M&;QaKAJWK+WlR.E^Su.}DlƏ(Q\^›lxƭ +)9$%#|\Is 6[Fs~N1ρn[X UFۊ_%w0(/e)OTy%xʾGˈP+, 5("쇞! 9!B]9* ” Rp)YHhZ"` O*_q>m\`HB@_{: &0fxd@Ks ػe 3j4<&Ѫ#M >|Od?dBfy#D*tJqf^L*Fԛ]}=0X UXQ,jœ1<+ĖW"?Xyqʱ Ŝ=x(ң# "oguZ?Ċ#A^u{#ad9 zֹvw'M6QdXS%S99 ړQAqd"DgոMtICjwX(+nZ@ 2lt> )} 9*Mkw|=JUK IdŽ7 i<1×3ė U;sdltbwuCYc %+QBJcj c7rsjAD`"yz2*m̑u_Q>#Ѥ?B^BYw[Oo?p$ dQJbuxknx8}Kd48 G7@8Q2b(Ѿg碞1 1XVmh(Dȭ#pe+@wd/s46?qZ* 64!%`gȞaX2;قIW==#I% xbf4?iɀLw ru Ao9JөP8X(6e{6 &"{i 6H!_&w!";~ϯc*pBOaY9)PGW*~즫loGWڝ A@z 5WXa r7sʀ{W ̸;DiLJB>TЊKMH{dym΋2l!^AgYpltc"Opo! M@^MҠ$d L4:>t7~\neҕ%+`jx&fӌfȥړT߹1\\M $/*ow ~F/ NX]H:@QPqxcTНY[2gmo944YB|GUӱnezcw0uKL ; YՃ T4L{vrcС˘6RF{Ip07?6e'/CA f_"t3 ռ:S[+zM( ӝF#y@=3;ko>R妊=i=yC=o Ic,:E9;3b:9UhcTg7gX( WK*:t E7ANjJY[l3_k⅕87X bID yv4v*Pta Ʌo Ua1Q0j:ЅAVHF!:'tS禈4Dƿ N&gaZ|VAݑ-ү@%^h{lF]/q'gB럇hMtlzs/\R[}Py3u 8@e J e5-⟵j,<u|VZ// 4Y@Tľ ?uPPcPppm1nJ Ϯ#yUw;AT5UHsF_ױWGfL/%a#(YҾzq xۆ{M;^ٛ`ysQ̿kD@Q }Ȝ MdR˚HEϗcc>M|bL=AH=)L:2˫z M{,P7n( .l'^,tnn P拆v1b$iP2k|T:Pg pf4b; W@*-Jcrċ8IN[F[d[8FuU]!Z3ʯfYy8';wsfNO=qYi1j+J:E [8a?H;gS$s>e#^F}2(d p}IJ+P#Xaf(Gu\]_4dtcɘ0(LIJr Vs 8O`>PynFF: P7gb}&`{ +*"tZk%'㺈U)|I|OO.36 "J,oC*طe4 1 x-&9cS;\ئ`)!~Yݸr{EO@8(tԪd@*fGܽ6;lFz,.̽Z|},\%k{11[мʋ(!rtj{jR\sQfx_ R Oٝɿ5dn"ph6Csж5M x8rFeʦ!w Me`n&B@yԙ۪S;8I?*cb cش69v ͝*>e5^@]p0v0XH&bVfd KCH!M7x[٢}LĶ2$^i<& .{Jf)Noz.Kan:WpVg ̹sb)C$ RHa~0yE3u$JQ(+3瘆WtiKEk.̓Ĵ -N/7?,FĮft:U`FR9Ms^>3#@=Tc~sآwK [UnIyAW#}wOOEP"@C?&\@6+FM*a3"{I5kvl^S'ߌ8Ǐ2}cQ[Ar4/d":RPyb=emwQ]ds?v=KYs]aa|ŮC#йg$~LgMy%љOh{չZXz#Ith Rm;ZH'\@E]n `X# UQjsm1IaU6[/Gvqb W100g'L܁4 JXǹ+X4N%-LEǧD>ՙlWtI%ĭg5aVw˗кb-='_8q~x?0 At C9R˙}CJcV%3aYHRY2y4bVO+V9z0EG&bfv\oƫK^y,8pZE&w0S K~Ӎ'e>NWjW Ѳ혊XD 䲞cVP7=!k@{CFOZ[ʹSeDE@_{mvX-8e2{F!UZr%Zo*M+JT'Ü#>Qئm7V/ZO'l̷@킟HVzɱĊI3/TX^k& 6B$hХ!Bv|j,m}ٍn+Vl. ә;ۇ^7}^j';܄ (qOe"h> ;SҊ ېі?$ܥA3PAjD2&*JTݺ%@FI`,Ox6(Αo޳'M*]$p'@(L3V9)d`#RPޒ'5cv[~n`'U{nl$!{„6 DSqdR$#al},.Mb䥣,_t =Ӂ }an~|Mf\iE"ڶivH7p#sN"P> 6ub%QM}*s+mM,S0,7#{W} ɅXg{EEH rAoMǽ JzFyH8M]VOܿ=VLg"T6T^=tCxCE};*%g52hYchIM׵6ՠn0ptD&Yr&s6HBjX>zyu\j-5A5>[ 'Xbn!mTӬlP&yMdR8Su b%Iyur4*R]v.l( ~"@_DKu/ 0-OԲsi;gL[9i"_|/mzT?E2 B!]υ+d9xKt ï(XE#̧+Ί>HsՏN5c*Z8N~Oc\b  @i^v@7}{QE)8Suð6Hv8]E[ d/"siVS(7fant>II0K`QH- ~0µD ՝BTCGT-0Ro0"3[x5iiIVMV?tT7 bkhYr/MS< mD1i`oIP# q෬fJ ډ_]} Iav)D},JRb %ŕs76HCVUhS3;:.Pl7O}ɋѪB6ldF'eq6 EtO1@RFn(kwqZ- cjCjf3 endstream endobj 349 0 obj << /Length1 725 /Length2 17745 /Length3 0 /Length 18270 /Filter /FlateDecode >> stream xlcpf>ۚ8OlOlքOlgLl۶m۶m9_YW^kvΪ@fzf&n*ϟL&V8rrG34,&&f8r3ʘF#@*O p6L-E-)y @h t4(Y[d-N@j#? _ 0SG;*@LQU`hk'ىh󿪣8dmIut 00v,lś?fu|8Mv7Dl]9;-_ܻ9ZcPC kr6 ![cIhhΎ.5?8&vs?<K}m]G/;uQB|د~[ ,H1_55DXpZi)") ~i-¿^B,1bS[]Ȓj #NjήCrALD$L˭L#JJЬ ǣl`yX=" p}\lv'SQFu#ÞGzJAwrN1L1!RmcVk!ȃ1璨يW->A! ׁ2Dy1|吴}v 9z28و5uQGCj06.zOCElgx3#;Z=)2X054.G:ؔ }C0pEߙ"sQ9d/jO ż(5nL>Mg/W(:  gbڔ1VAJb5?; 찭g>;V#^f T]Q7woqא1`(9c_ 6|B1rxsv(ѭ"کd\)1[)|XƜX0C6-]WfRj%UUbp˟=SmMqXcW|G3Kӡ5 SJ- | ܊89 35>wtY6 x-(J6;,1`WL1 1 ۫1| o$L"5GWgE$1G[9;U(D]B`MZ+J^nN*"$3Ek*cbV2OHc4K 4Ƃxt@cNq!9'[=4@nN/u,Fˊ?5"\,r*п3>nŚڸ/ErK\O >}ޓ? /<}=7S@Utq]GiUwLlb>Hh+@s_]k+4H!wfzD&,r.pA(0Yt2cҚ^~ OrX0[A7r ]TTpoL{ TS2uW'*<0%f\ね̬Ͼwl9[)&'~{O2 ~Qƈ'WEkxg.kDBaDZG<3`V/38^GZ4BxՀ~`;)jz.PmϿb D,#(?6vWE0dϔ;-eI!Ct k[TP0LP3ܹDY}ׂ&5nr[ {CЧ{U"LjTM0wۋ"x:{Y>*н6yԚ:n/#F{t/z_En8p,tnΥӃ,]b;aq ox.:@wJuյqGrw?:p&r hAvc|u1h?A [NoT0@)晨vV= -$@ODDש_v)`!x>,HaX$՛Zk\3A8Q45EyzL, g+}r X'ȯO"Z!R *|m:a- -ȟ k}=̺֫1mp^۸d1~ԁ ZȞXH=0 Z܌`BķTybeqncS2W.zh.NK䚷D䐏PP1u(B1x5}JYSi7DOeڙBs?}*ۼf>ԇ]65|`bWSa#aӋyGܲV\\ʣ-!ix6`eKtUu<:_CS[b18"]N$G fBL>tWjVܦfp@&-a)EJ,>1y ڰє 7qjn91 O/ClA?jS@iz3q H`P˼T =!nδvkMP U5nq"=*S%_C8zP%$n8W|%UQ۩);E3G|PzX RkSo٘l){ZJ-(u?^],MMGmG& vw#I#iy?eKxYjn:;3ҝ[[3 <.`.{LKsğ){ ڄ? 2p%Jr(Ғ/yrBI0?mbpk麱yn)maD! z[] k>Cj8q pZ}_\RۛEv`>ZDha]1&FZKN\8m(wl7m"z9RxkWS0XqY+E6ھXSm;7<Jo̜z 1E@e\Pand^ub sKє(desy \$Ju/]UY eH|"⧊ u{0=}!M]Q.lHXb޽A"͓@kt.U ~P5coHCFߜ A[_׭Kv l] /|CG Aٗ%dtKjxe񪴶 ҽ-ŐO1-)H^eK7;pvLݢTڔ$w4jXCZ$1{['|bܳ̌!6yǪ?h~KaAtq)@$c4qb!YCCŗA[ ~y}5m ćhdl&Дb;䏞 k0 $M9a)Bpvn3 $Vѷg8Gwl5Q rW(`+F432QqP4aZ@g i@7gPNYGoB;q?~9iv)MwF|BnPm"X[eCZ+Q\U.[6J$QKZ C>f9=1>l}#P`!1W ;ڀx*G&r0;Y$`ߨz{Mx%6A۬Fdl-Ls9?kiP #wl 8KI|'@aEͷ$5TH^!K8Y\ΫAR~bƈW}L29?j?+!hR6lA/fŒ{Q&7SBN5XHV#qa*# .nIg6AM,:@OWsXe"b F!a0m)H|jZRE:($)r ;2Y|jivWeڿ<q99=6{~qw>6O=ž1OաCG&[Mwu#I$n$|T4JF;.)Ac/Ԩt`uzIzneȝ 3 J<LҎF8Y_!vL8P | Kn^khv O8W7:Jdw5iE-[,uȸpmOI:K`d\Y^=Nf֍$^#yv)1٥ * {,6 K"R>JQK[Ӣ@2[Sg.döR%7zԦM}_8KB-q;Ԭᦢ^}jх.Z($bQCfG\hqf=Z%1(#MqE$>m x!rg{%y]1$G=VcmGWYL}}rY[IP0+7Y"uyFH|QDw_@s*75Q8* cFgb'K*DPO#. Uvtp3"LLbMQq8].= v 0gb!]Gnyb򬔨v3}բd @ 1 6f=z]_CP=bIf'%ICXTU g.G,L].cmMosZ5_)x!dh\s}bƕV>{ / eQTnwWD)(ڐ/f c-]U(UO#-RM5niS?h)LsȂn x, d2~J ?ʊwT6*IMJ{Dc3ll: T% ;Q!|B^A5A>U`_!Ni`kEc%Eoba1ŝqgK69pV@G3'B[t4SomKrP1LuEiK*@{{"F6`x l%mɑw\ԪƘ{oSg Y_o b>YRn.5ұsA pqs0p;uEIZy Rq˖qPKδacjQ9 v˃ yr-7 Q*V2M6 qRX"9{qh\T98#v!}˭kXƋəv(8|sl&xއTeh8ICVrH H zJ[庡Pd@NēLħδ_'7sv.Sת=Z3jGcy!Bw^Hߥu.{Ks&g.:TMɏN%ղPԠXħ'"£oyHpf4ʪ-T=r8ޓ`ad.|Wsӧo^jB[C_u=)mb_=$mZ'e-il=AV #O&AM>Eޱbɽq&ΛUoy£ʖά\Wu$0cʝfZD3ךÆG:;վ=!ݚOY7xGf1OP۵%bX.ɔZm=߲Y8iм۳8Zڠ;{OE(dQ{23ג}U>uց N¥8M ,' Ȫeb3ȹKr]_VO.&_ _o0=DK<'oXf6 GȘ .XW]m:8]تCr 5vYxWu)ZMs#]캃4zp)\:ҙu 4 Y ҷ|(~-t! D$[]*\$6K._jjƻ bb1'ef*3c Œs&7 vR٘YNe?kD"vw( +>w:1HEU LnidDTd`q-xV5(ni>}!V$$ MjLYy^>RB\xGmˏ滧KZa`<54~rTLOu0A>p7΄;wU%Z78r.Z:}Y)qO;\f:)+ a Tdž.[2Ƙ}?}]sǓN. e,^o؇V嚡t >!Q<]g '=3I8yOgfWNw6N+̌?wx#D 4O]5caWLS7CЗ~ֹJ|!y)<``>L$9+;Z3B/Z]tw̑7(Ʉ'/!M&rbGՖ|!"C9Q;ŚY.{W) 4 /<gL_[f#n `?m [OO-vumcCxF#)yu(xd|a}xoO!th';ՆI!vbMHDc/5*|,ؿ/_ԩ [Hc3HEUyto-6$@Aw}{PE9qi(v(hN/ޞ_{؜ƦODȩra1.Ȗ (c*Z!!ntMԷ?j7^:>o",Q%&VZ져*Z/6@ث FY=^De=P˪WMx~}Q&3Weȹ{?H9XDGW%KoAIÍ]F*4ژhk<3M| $}jHB׈CzP .4o~Muf ' wrû箖Dg(o% 1$|-uߺC }?'o |`@T7/(W"tiKeϠKMf=_GeꉊiT>kt{Cҁoo؞GųJŜ|P$$2겨<]ff%N򱡲/.O f`; X!=3t6j \'YA}L,, ]!v],t,%jWEzd$ 'ɹ?GbX_ FڻBZՖ7W[U?IlWԩ[9 N?VK X 1xpFcM#̮f hN' }C6˞\߿e4{"LX%gSxA6NIܶ#=̼ zsH.5ݠ!~>ދxJLN>üج>I)XHe0QC Nf|`LUx[o' l}ΰħ=}( 1chGVQj[XOr+-2c,,"6.6ya~#9.wuvڨyq (׋bf51R&[M9P)_vڔy_@ Ӑ;HIǐ1^4 qt_x`a#0f×鯶 9:[bs4C5I8VB)31~GTa<qcKT"r(S~›(SH-[V ?TѾ,(1~e)g& )@HܢnoY==G5LL72BkA449$$OP"GWzMy\ J,V:?Bl0[Jm.;z*rd.v:|3l8Ti_+7t%t}haL*շ 'A_1Y3RT}>R>G¦HUkG^dyW̒fmN"e{ws/Xxe*WK?(ȉT+U }9ʒn[t # XC%Ia==u={FMǍF<ӡ2Bm`}if9蜎wmdǒq6 :HEN"vW^G^Q݋+ZFV]bz;zu9A+$AkD%[u/I РeqZJːbv*[ '#szD͸HzRU/XJqւB; W='0JX 9c1N )P'[&N;GKK%+nȗlA`9@?7`1MQY4o w $qў[LhO;QFt_\ eD)jίsYԪUؾPb֕`}fOg@}G?aT Kی]~d&wvgH$q߯Wbe{T'Kxo0B"4C+M4kU,&p:KTij֫,ͫ64%_Lʿr6֚t1Z_֣l6GΘބ;(Wg1YU#-u#@7iRկ2N(bWQSH@if}oRZ ^PdCw\y5u=e6 Uܰ&C5ؽ!Ki)bU UGSO0ńAyweU6Fݼ63g; Gůz7ϮyE #nʩOrsMsfTk>@%A8L! idMr W?GAn i 4yf娋nf nrFRyZ6S#.̫>ż̥#2Sj֐<^72e .fޢ׾4 up7wPAHkKY,.p%aYؑAIq75d`s5ezlq,5wQv)` m9x-BK.Kv2ż?[#-Ml7b6+٭蛺1HuxҮ-$Bp3JIL WECX[pF0=m 'xWOawg Ot V WNS2 7ᨆ- I퀶Un/OR~܄,ra.BM淪$BOOX9NlPlQv!lG{ rhbbB2 2l(ŸPT{=,8OC&U >7G)"! M 9aikbxtsXÇBnBn'۟0Ru)ɞR(e`%6ɒ7EM*e]LE|#/2/t.Ďd5@Ď-jXEEM<'6B#(V!F` v+&+tV(LS鎈ri dt5|DCd`Yńy Sfkʆd'BzHN/b_9#}1澺_\4 } B^BkKhKC쌳 .0X**G8-xۦYGʁH #!I r1urqNPEjWmXh7Y"o2lf+)jΧu)c . -ъy̑Q!~(0lYZ]QEY{Srl&6mZ,  ׸WmP/4G~Nh)]ɍw. Y|) 'u{^a<2r]cʬ?]HCr%#~p)c4$!㺎 ,0{H oQ+3包}^JcaNHOtKӎ(I`.big4ZMyL!w+O/!2K?R.#nS`  y ۅ>|JXy>usaGyj1$=K-K!ĨYSSSa4,D,Ʋzedt.;=g ݘKэA!89U bd;N`'C1t)b' ;MKp8|XN~6p0b4AwW(gNsm¨;tU>y(kms^Woh%1˅̟x##]0pmx0d'WJ\]ž4EGlTE uSSn 1CY9䕸KG'K~kR eCK(~]ASOݼ&ILSDL,$UFK gYOtˣW_),Z/ٝpk h|L\F|F[{iZ47~=3!4Iq0 .E׶V;-~rR8?0]s^]UܬJD*|ʮsÞ2Vq2vpzt)g:muع8s&x}1XؒKI*ΐv"8@͍8r_\i* !i=|HXX!OLnĦSS[@*\q35J"S!{;JS! K!T:~wrF(?&ae?i~C:jO5ܪe{c,J7]tѣ,j,p܁5U~zq8̌!YBφx/PzRj.P Dg+yL׽:ֽdw3+Q;2tM)C _*DQJKļա ItiP0$n'P}vSUJӲT~f@>sjXm?6yp-A+:`s*iì_u)Aݣz߽u>5c${>79dp|;|mJ9L;wn4 tlnNlgqXXMDg#fg {d!g! n=Mҋr8ӺGvXR əп:[AM>/w@v?*dܩwƂdu$ :;.0"g갂wT2wDtJ*+0 JVֳi5·j]}PRB kF8dt`kMc|Q4QUPD:
r[wTs=WgJOaڟ}\xMqZO+V@p^'bsEkQzŒ\u㞝-=!T,Q kuQVwc۸rFNӺݺiȘNLo3mSHPl9dcx7 endstream endobj 279 0 obj << /Type /ObjStm /N 100 /First 913 /Length 5119 /Filter /FlateDecode >> stream x\[s~ׯhOi˖TYvD'.?PH1E*$$% bt +o+Q)*c*U$fTŴѺRATND|{VUfO]I)pC0UT4,$fTT\"V؀p RR*bTG'JN17h5@VCrN-L'R=-hM1eA_BEK0ӴUM hMSRuo0bOK 4e++i1,n|唥Pa ya#U*=L GC"PE/R>+@kXBFYpс̄u$I 6=mvZw(Lh;`JBF:F),G#s0H@_'!*v>&;pteD@ #uXhTOMe^-V{k`vkoGLq/[,B,}Ο&v.&Ŭ5y;eYYG Fpc匬XKxtt'7sټ?7=bp2nNw7dXOh@tfk%v}{?y3kbLRڐsGWG(P'֫mW`pHm :uS^(Q{5%X 52哮O}=_ZTRFg ! hw SJ` [Dž P D.AMHNJ !Ylrk[`MYEe(QlDVGBY(8hImN+@_JTNQ($ܗxW f+0Ps?ȗZ#1ORXq)guЋ~}H6q)[gb8!9{)ʈQh)"($eHQ2+" = } sI$ ǥ6R?z&-M9-񍥜NY+<4l,Ȇܲ٤``4ENõqI N-T{zAOJI1=E4TY6b,~}%$%n<fSZInJP^R 5W^(L1Tî CT % (=:qL!EldKF]jp8iah^sqqIjvԜT bX/q AkpBs$pdWK^dW_)z%QRQ\r5ZJ"/S?xW?]hY}L-f5KZM#l_ TcPvflxASrj \$+z9@}PbZçNm\RkpKY)m BzIQs[Z+['){pW&>OOsji">rm"u鄖[Tyܦ}OՄShzcRCڴNjS'7{:>O=Yr7я (C|wӢ3MU5# SCh4h°W̪If*4tr|p,m&R˼) .iBst @! 1k\`qN;>;Aqt# [ڸOE2JlԖAu(5&=ce z؇Dc :߱LTfӡ`\Os?mgg|2M_0?{㿞 .gI}́2Ձ&Iy!k[ l. M<FóQK'^>aSz]sM_ڋ2]M.LGCE?Koz߲l_^3ճm{ {g8,).v)i4>ں͓YyӼo&WW梹i3l|n>hpuz>hfL溝'as=ll4}j*{U?'*YS2+JzVEwλ/{9fx#:Ë,ݼLfF;>szsִ FNۥ3\nf ol0m_餯x5xǤ-FֳՕ&Z۵]rCl䷭,V[Hr3 LqpvNӦWXd͇ף-)/G:9:|O{lvM?^{ciɄܳ1v1ܫ9A{ۼk)6My6lͧO!#;I b6Gn?/uowO}o]:REe^}ov]I_N)K=Ut٦":YL*zU(g$tE#+S}.*(XGҖVf]vߤ_NgsBq%^r] :<=6V5Nt쥻;Twa{U^ݝsZݙ֬V)-Uk+Kኝs_ұ vz% _;wiaH"o!{E$OgԷi*lT8B٪HkX=7V%÷i_i~+7ZE*f8HH, uߺIIuݫ|uCE*'sTS)ыb27e9zy=9U!`<b||y`4گBgrx5ӧ]%dIxb T-v#F|9.)G F]c "%\#MاyʑH#}TvAY*[tӖ%l9iG(Yʩ,rz z <ir-"n/62eGJq.4i'vЎi e7 ڦ*HJCO-, L?k}bqcP7"Etk-'r t 9tkLzM`r(,=[fO (nMpZ#巠QT;7fW5k ͪe-]Ѯm<ꭂ4=['Wdw"ni֯Wf]vOvM*:5i QҬ_&ƵMvI5 I endstream endobj 373 0 obj << /Producer (pdfTeX-1.40.22) /Author()/Title()/Subject()/Creator(LaTeX with hyperref)/Keywords() /CreationDate (D:20260428173151-07'00') /ModDate (D:20260428173151-07'00') /Trapped /False /PTEX.Fullbanner (This is pdfTeX, Version 3.141592653-2.6-1.40.22 (TeX Live 2021) kpathsea version 6.3.3) >> endobj 365 0 obj << /Type /ObjStm /N 8 /First 62 /Length 320 /Filter /FlateDecode >> stream xڍOO0 >R$HZ'N*Mg PmTik+Z|{HP=W5 HEV! J{^VH,g̀?`$%Y"˃sjK,R ͶMUn1rB3OMLsOmLu"nCO^''2jT0l : q}گ7Ֆ Qj -/_{nЖ;ǃMm9  i0h'oM',BR*u\י/p:e_]"x]us˷~_ծKIJuܮ endstream endobj 374 0 obj << /Type /XRef /Index [0 375] /Size 375 /W [1 3 1] /Root 372 0 R /Info 373 0 R /ID [<34586DFB60AA96EA809F3920B94DC4C1> <34586DFB60AA96EA809F3920B94DC4C1>] /Length 905 /Filter /FlateDecode >> stream x%KL]UBm)HVGPRC*Hm(M4!41&1~:T#EMsC5(/{'ˤIR߉J,A@)T)*/+r8zY~,"P,C-e8TIRi7:y8iZ:wAzcpβ,\}AR׶(u/jV}y.B%vew[N]ЭTcYF`Pij[ 10 T04[Ɣpu &*$L73J?LJ{)G]VaQ=2-uC.ÊүMw-c_7ٻ܁5݆X %>ͻRفңdM{؆P AЃAb  qn(KR Up"qBt y5w;E4/ fhd7j#C߈ivh7i f!W %{c@Gz-(@1 H °#1c5#AcRz AbZz13@c恈ɉYüq 1cXI]]k@̂1-VrxxF3Hgrwi2U(2(@+8 9 ym8p_j8 5^:opLB+6h pzWz\/I?SGWm؁; ^R)q{^ $bD= minimumInclusion minima <- minima[keep] if (length(minima) == 0) stop("No minima found with count >= minimumInclusion (", minimumInclusion, "). Consider reducing minimumInclusion or increasing randomStarts.") # Summary data frame f_values <- sapply(minima, `[[`, "f") f_global <- min(f_values) summary_df <- data.frame( minimum = seq_along(minima), f = round(f_values, 6), deltaF = round(f_values - f_global, 6), count = sapply(minima, `[[`, "count"), proportion = round(sapply(minima, `[[`, "proportion"), 3), isGlobal = f_values == f_global ) result <- list( minima = minima, summary = summary_df, Qvalues = Qvalues_conv, nConverged = nConverged, nStarts = randomStarts, method = method, orthogonal = orthogonal, minimumInclusion = minimumInclusion ) class(result) <- "GPFallMinima" result } print.GPFallMinima <- function(x, ...) { cat("Random start analysis:", x$nConverged, "of", x$nStarts, "starts converged\n") cat("Distinct minima found:", nrow(x$summary), "(minimumInclusion =", x$minimumInclusion, ")\n\n") print(x$summary, row.names = FALSE) cat("\nGlobal minimum: f =", min(x$summary$f), "\n") cat("Access full solutions via $minima[[i]]$result\n") invisible(x) } \end{Scode} %------------------------------------------------------------------- \section*{Key Arguments} %------------------------------------------------------------------- \begin{itemize} \item \texttt{method} --- the rotation criterion. Criteria with many local minima, such as \texttt{simplimax}, \texttt{geomin}, and \texttt{infomax}, are the most interesting to diagnose. \item \texttt{randomStarts} --- number of random starts to attempt. More starts give a more complete picture of the solution space. For a thorough analysis, 500 or more starts are recommended. \item \texttt{minimumInclusion} --- minimum number of starts required to retain a minimum. The default of 2 filters out singletons that are likely numerical artifacts. With 500 starts, a value of 5 or 10 is more appropriate. \item \texttt{orthogonal} --- \texttt{TRUE} for orthogonal rotation (uses \texttt{GPForth}), \texttt{FALSE} for oblique (uses \texttt{GPFoblq}). Default is \texttt{FALSE}. \end{itemize} Non-converged starts are always discarded before analysis. The \texttt{proportion} column in the summary is calculated over converged starts only, so proportions sum to 1. %------------------------------------------------------------------- \section*{Example: Simplimax on CCAI Climate-Friendly Purchasing Choices Data} %------------------------------------------------------------------- The CCAI Climate-Friendly Purchasing Choices domain (Bi and Barchard, 2024) provides a useful dataset for illustrating local minima behavior. The data have 14 items and 3 factors with strong inter-correlations (0.53--0.59). Bi and Barchard used oblimin rotation in their published analysis. We use simplimax here purely to illustrate how rotation criteria can produce highly complex landscapes with multiple local minima --- not as a recommended analysis of these data. The data illustrate how dramatically rotation criteria can differ in their stability. Oblimin rotation is highly stable on these data --- all 200 random starts converge to the same solution. Simplimax, by contrast, reveals a highly complex landscape: \begin{Scode}{results=verbatim} library("GPArotation") data("CCAI", package = "GPArotation") fa_unrotated <- factanal(factors = 3, covmat = CCAI_R, n.obs = 461, rotation = "none") A <- loadings(fa_unrotated) # Oblimin: highly stable res_oblimin <- oblimin(A, normalize = TRUE, randomStarts = 200) cat("Oblimin random start diagnostics:\n") res_oblimin$randStartChar # Simplimax: complex landscape set.seed(42) res_ccai <- GPFallMinima(A, method = "simplimax", randomStarts = 200, normalize = TRUE, minimumInclusion = 2) res_ccai \end{Scode} The contrast is striking. Oblimin converges reliably to a single solution on these data. Simplimax reveals 16 distinct local minima, with only 81 of 200 starts converging (40.5\%) and the global minimum found in just 2.5\% of converged starts. This underscores the importance of using multiple random starts and verifying convergence, particularly when using criteria known to be prone to local minima such as simplimax. The global minimum (f = 0.01080) is clearly separated from the other local minima, with the next best solution having a criterion value three times larger. The sorted loadings plot shows that the local minima produce substantially different factor structures, not merely permutations or sign flips of the same solution. %------------------------------------------------------------------- \section*{Examining Individual Solutions} %------------------------------------------------------------------- Each element of \texttt{res\_ccai\$minima} contains a full \texttt{GPArotation} object in \texttt{result}, so the standard \texttt{print} and \texttt{summary} methods work directly. \begin{Scode}{results=verbatim} # Print the most common solution print(res_ccai$minima[[1]]$result) \end{Scode} Accessing any specific solution is straightforward. For example, to print the solution corresponding to row 3 of the summary table: \begin{Scode}{results=verbatim} # Print solution in row 3 of the summary print(res_ccai$minima[[3]]$result, digits = 2) \end{Scode} More generally, to print the solution in row \texttt{i}: \begin{Scode}{results=verbatim} i <- 3 print(res_ccai$minima[[i]]$result, digits = 2) \end{Scode} The row number in the summary table corresponds directly to the index in \texttt{res\_ccai\$minima}. Row 1 is always the most common solution, and the global minimum is identified by \texttt{res\_ccai\$summary\$isGlobal}. \begin{Scode}{results=verbatim} # Print the global minimum using the GPArotation S3 print method global <- which(res_ccai$summary$isGlobal) print(res_ccai$minima[[global]]$result, digits = 2) \end{Scode} \begin{Scode}{results=verbatim} # Summary with structure matrix for oblique solution summary(res_ccai$minima[[global]]$result, Structure = TRUE, digits = 2) \end{Scode} Solutions with small \texttt{deltaF} values may produce loading matrices that are very similar to the global minimum after sorting. Solutions with large \texttt{deltaF} values are likely to produce meaningfully different loading patterns and warrant careful examination. %------------------------------------------------------------------- \section*{Visualizing All Minima} %------------------------------------------------------------------- The sorted absolute loadings plot is a powerful tool for comparing all retained minima at once. Each line represents one distinct solution. Lines that overlap closely indicate practically equivalent solutions; lines that diverge indicate qualitatively different solutions. The following plotting function is also used in the main \texttt{GPA1guide} vignette. It is reproduced here so that this vignette is self-contained. First define the plotting function: \begin{Scode} plotSortedLoadings <- function(..., labels = NULL, col = NULL, main = "Sorted Absolute Loadings", ylab = "Absolute loading", xlab = "Rank") { solutions <- list(...) for (i in seq_along(solutions)) { if (!inherits(solutions[[i]], "GPArotation")) stop("Argument ", i, " is not a GPArotation object.") } n <- length(solutions) if (is.null(labels)) labels <- paste("Solution", seq_len(n)) if (is.null(col)) col <- palette.colors(n, palette = "Okabe-Ito") sorted_loadings <- lapply(solutions, function(x) sort(abs(as.vector(x$loadings)), decreasing = FALSE)) all_values <- unlist(sorted_loadings) max_len <- max(sapply(sorted_loadings, length)) plot(NULL, xlim = c(1, max_len), ylim = c(0, max(all_values)), main = main, xlab = xlab, ylab = ylab, las = 1) abline(h = seq(0, 1, by = 0.1), col = "grey90", lty = 1) for (i in seq_len(n)) { lines(seq_along(sorted_loadings[[i]]), sorted_loadings[[i]], col = col[i], lwd = 2) points(seq_along(sorted_loadings[[i]]), sorted_loadings[[i]], col = col[i], pch = 19, cex = 0.6) } legend("topleft", legend = labels, col = col, lwd = 2, pch = 19, bty = "n") invisible(sorted_loadings) } \end{Scode} Then plot all retained minima: \begin{Scode}{fig=TRUE} do.call(plotSortedLoadings, c(lapply(res_ccai$minima, function(x) x$result), list(labels = paste0("Min ", res_ccai$summary$minimum, " (f=", round(res_ccai$summary$f, 4), ", n=", res_ccai$summary$count, ")")))) \end{Scode} Lines that are visually indistinguishable correspond to solutions that are practically equivalent regardless of their \texttt{deltaF}. Lines that diverge clearly represent genuinely different factor structures that merit substantive interpretation. %------------------------------------------------------------------- \section*{Practical Guidance} %------------------------------------------------------------------- \begin{itemize} \item \textbf{How many random starts?} For criteria that tend to have many local minima, 500 or more starts are recommended. The goal is for the proportions in the summary to stabilize --- if running 1000 instead of 500 starts changes the proportions substantially, more starts are needed. \item \textbf{Setting minimumInclusion.} With 100 starts, a value of 2 is reasonable. With 500 starts, use 5 or 10. The goal is to distinguish genuine local minima from numerical noise. \item \textbf{Interpreting deltaF.} There is no universal threshold for what constitutes a ``meaningful'' difference in criterion value. Solutions with \texttt{deltaF} $< 0.001$ are typically negligible. Solutions with \texttt{deltaF} $> 0.01$ may produce visibly different loading patterns. \item \textbf{When the global minimum has low proportion.} If the global minimum is found by fewer than 20\% of converged starts, the criterion landscape is complex and the solution may not be stable. Consider trying a different rotation criterion or increasing the number of random starts. \item \textbf{Comparing criteria.} Running \texttt{GPFallMinima} with different rotation criteria on the same dataset can reveal which criteria produce stable solutions and which are prone to local minima for a given data structure. \end{itemize} %------------------------------------------------------------------- \section*{Further Resources} %------------------------------------------------------------------- For detailed discussion of local minima in factor rotation and their implications for substantive interpretation, see \cite{nguwall}. For investigation of local minima using the \textit{fungible} package, see the \texttt{faMain} function. The \textit{psych} package provides \texttt{faRotations} for similar diagnostics. The \texttt{randStartChar} element returned by standard \texttt{GPArotation} functions provides a quick summary of random start results without retaining individual solutions. For routine use, \texttt{randStartChar} is sufficient; \texttt{GPFallMinima} is intended for deeper diagnostic investigation. \begin{thebibliography}{} \bibitem[\protect\citeauthoryear{Bi \& Barchard}{Bi \& Barchard}{2024}]{bibarchard} Bi, Y. and Barchard, K.A. (2024). \newblock Purchasing choices that reduce climate change: An exploratory factor analysis. \newblock \textit{Spectra Undergraduate Research Journal}, \textbf{3}(2), 8--14. \newblock \href{https://doi.org/10.9741/2766-7227.1028} {doi: 10.9741/2766-7227.1028} \bibitem[\protect\citeauthoryear{Mansolf \& Reise}{Mansolf \& Reise}{2016}]{mansreise} Mansolf, M., \& Reise, S. P. (2016). \newblock Exploratory bifactor analysis: The Schmid-Leiman orthogonalization and Jennrich-Bentler analytic rotations. \newblock \textit{Multivariate Behavioral Research}, 51(5), 698--717. \newblock \href{https://doi.org/10.1080/00273171.2016.1215898} {https://doi.org/10.1080/00273171.2016.1215898} \bibitem[\protect\citeauthoryear{Nguyen \& Waller}{Nguyen \& Waller}{2022}]{nguwall} Nguyen, H. V., \& Waller, N. G. (2022). \newblock Local minima and factor rotations in exploratory factor analysis. \newblock \textit{Psychological Methods}. Advance online publication. \newblock \href{https://doi.org/10.1037/met0000467} {https://doi.org/10.1037/met0000467} \end{thebibliography} \end{document}GPArotation/inst/doc/GPA3bifactor.Stex0000644000176200001440000004564015174242444017254 0ustar liggesusers%\VignetteIndexEntry{Bifactor Rotation and Reliability Coefficients} %\VignettePackage{GPArotation} %\VignetteDepends{GPArotation} %\VignetteKeyword{factor rotation} %\VignetteKeyword{bifactor} %\VignetteKeyword{omega hierarchical} %\VignetteKeyword{scale development} \documentclass[english, 10pt]{article} \usepackage{hyperref} \usepackage{amsmath} \bibliographystyle{apa} \usepackage{natbib} \usepackage{geometry} \geometry{letterpaper} \begin{document} \SweaveOpts{eval=TRUE, echo=TRUE, results=hide, fig=FALSE} \begin{Scode}{echo=FALSE, results=hide} options(continue=" ") pdf.options(pointsize = 8) library("GPArotation") \end{Scode} \begin{center} \section*{Bifactor Rotation and Reliability Coefficients \\ ~~\\ The \texttt{GPArotation} Package} \end{center} \begin{center} Author: Coen A. Bernaards \end{center} Bifactor models represent a factor structure where each item loads on one general factor that influences all items, plus at most one group-specific factor. They are widely used in scale development and psychometric research to investigate the relative contributions of general and specific sources of variance. This vignette illustrates how \texttt{GPArotation} can support bifactor analyses and how the results may inform decisions about total scores and subscales. The tools presented here --- bifactor rotation, omega hierarchical, and omega total --- are best understood as aids to thinking rather than as decision procedures. Their interpretation always depends on substantive theory, the purpose of the measurement, and the broader research context. %------------------------------------------------------------------- \section*{Bifactor Rotation in GPArotation} %------------------------------------------------------------------- Two bifactor rotation criteria are available: \begin{itemize} \item \texttt{bifactorT} --- orthogonal bifactor rotation. The general factor and group factors are uncorrelated. \item \texttt{bifactorQ} --- oblique bifactor rotation (biquartimin). The general factor and group factors may be correlated. \end{itemize} Both treat the \emph{first column} of the loading matrix as the general factor and rotate the remaining columns as group factors. The general factor column should correspond to the dominant factor in the unrotated solution. Use \texttt{sortLoadings = FALSE} when printing to preserve the general factor in column 1 --- the default sorting by variance explained may reorder the factors and obscure the bifactor structure. \begin{Scode}{results=verbatim} data("WansbeekMeijer", package = "GPArotation") fa.unrotated <- factanal(factors = 3, covmat = NetherlandsTV, rotation = "none") # Orthogonal bifactor rotation res.bifT <- bifactorT(loadings(fa.unrotated)) print(res.bifT, sortLoadings = FALSE, digits = 3) # Oblique bifactor rotation res.bifQ <- bifactorQ(loadings(fa.unrotated)) print(res.bifQ, sortLoadings = FALSE, digits = 3) # Structure matrix for oblique solution summary(res.bifQ, Structure = TRUE) \end{Scode} The pattern matrix from \texttt{bifactorT} shows loadings on the general factor (column 1) and group factors (remaining columns). Items with high general factor loadings and near-zero group factor loadings are well represented by the total score. Items with substantial group factor loadings may be carrying domain-specific variance beyond the general factor. For a detailed treatment of bifactor rotation see \cite{jennbent}. A comparison of exploratory bifactor analysis algorithms is provided in \cite{garzon}. %------------------------------------------------------------------- \section*{Omega Hierarchical} %------------------------------------------------------------------- Omega hierarchical ($\omega_h$) quantifies how much of the total score variance may be attributable to the general factor. It is computed directly from the bifactor rotation result: \begin{equation} \omega_h = \frac{(\sum_i \lambda_{gi})^2} {(\sum_i \lambda_{gi})^2 + \sum_i \sum_j \lambda_{sij}^2 + \sum_i \theta_{ii}} \end{equation} where $\lambda_{gi}$ are the general factor loadings, $\lambda_{sij}$ are the group factor loadings, and $\theta_{ii} = 1 - \sum_j \lambda_{ij}^2$ are the model-implied unique variances. \begin{Scode} omega_h <- function(bifactor_result) { # Compute omega hierarchical from a GPArotation bifactor solution. # Args: # bifactor_result : a GPArotation object from bifactorT or bifactorQ L <- loadings(bifactor_result) lg <- L[, 1] # general factor loadings Ls <- L[, -1] # group factor loadings theta <- 1 - rowSums(L^2) # model-implied unique variances sum(lg)^2 / (sum(lg)^2 + sum(Ls^2) + sum(theta)) } # Omega total: proportion of total score variance due to all common factors. # Requires the observed or population correlation matrix R. omega_t <- function(bifactor_result, R) { L <- loadings(bifactor_result) R_hat <- L %*% t(L) sum(R_hat) / sum(R) } # Coefficient alpha from a correlation matrix alpha_coef <- function(R) { k <- nrow(R) k / (k - 1) * (1 - sum(diag(R)) / sum(R)) } \end{Scode} The denominator of $\omega_h$ partitions total score variance into three components: variance due to the general factor, variance due to group-specific factors, and measurement error. A higher $\omega_h$ may suggest that the general factor accounts for a larger share of total score variance, which could support the use of a total score as a summary measure --- though this interpretation always depends on the substantive context. %------------------------------------------------------------------- \section*{Comparing Strong and Weak General Factors} %------------------------------------------------------------------- To illustrate how $\omega_h$ varies with the relative strength of the general and group factors, we construct two population correlation matrices with known bifactor structure. In Example 1, the general factor is strong (loadings of 0.7) and the group factors are weak (loadings of 0.2). In Example 2, the general factor is weaker (loadings of 0.3) and the group factors are stronger (loadings of 0.6). Both examples use 12 items and 3 group factors of 4 items each. \begin{Scode} # Example 1: Strong general factor (loadings .7), weak group factors (.2) lambda_g1 <- rep(0.7, 12) lambda_s1a <- c(rep(0.2, 4), rep(0.0, 8)) lambda_s1b <- c(rep(0.0, 4), rep(0.2, 4), rep(0.0, 4)) lambda_s1c <- c(rep(0.0, 8), rep(0.2, 4)) L1 <- cbind(lambda_g1, lambda_s1a, lambda_s1b, lambda_s1c) R1 <- L1 %*% t(L1) diag(R1) <- 1 fa1 <- factanal(factors = 4, covmat = R1, rotation = "none") bif1 <- bifactorT(loadings(fa1)) # Example 2: Weaker general factor (loadings .3), stronger group factors (.6) lambda_g2 <- rep(0.3, 12) lambda_s2a <- c(rep(0.6, 4), rep(0.0, 8)) lambda_s2b <- c(rep(0.0, 4), rep(0.6, 4), rep(0.0, 4)) lambda_s2c <- c(rep(0.0, 8), rep(0.6, 4)) L2 <- cbind(lambda_g2, lambda_s2a, lambda_s2b, lambda_s2c) R2 <- L2 %*% t(L2) diag(R2) <- 1 fa2 <- factanal(factors = 4, covmat = R2, rotation = "none") bif2 <- bifactorT(loadings(fa2)) \end{Scode} \begin{Scode}{results=verbatim} cat("Example 1 - Strong general factor:\n") cat(" alpha =", round(alpha_coef(R1), 3), "\n") cat(" omega_t =", round(omega_t(bif1, R1), 3), "\n") cat(" omega_h =", round(omega_h(bif1), 3), "\n\n") cat("Example 2 - Weaker general factor:\n") cat(" alpha =", round(alpha_coef(R2), 3), "\n") cat(" omega_t =", round(omega_t(bif2, R2), 3), "\n") cat(" omega_h =", round(omega_h(bif2), 3), "\n") \end{Scode} The three coefficients address related but distinct questions: \begin{itemize} \item $\alpha$ estimates the proportion of total score variance that may be attributable to common factors, under the assumption of essentially tau-equivalent items (equal factor loadings). When this assumption does not hold well in practice, $\alpha$ may overestimate or underestimate reliability --- something worth keeping in mind when interpreting it. \item $\omega_t$ relaxes the tau-equivalence assumption and estimates the proportion of total score variance that may be due to all common factors combined --- general and group-specific. It may provide a more nuanced picture of reliability than $\alpha$ in some situations, though both are model-dependent estimates. Note that $\omega_t$ requires the observed or population correlation matrix in addition to the bifactor solution. \item $\omega_h$ focuses on the general factor only and may help address the question of how much of the total score variance could reflect the single construct the scale is primarily intended to measure. It is one piece of evidence relevant to construct validity, not a definitive answer. \end{itemize} The gap $\omega_t - \omega_h$ represents the proportion of total score variance that may be attributable to group-specific factors. In Example 1 this gap is small, suggesting the group factors add little beyond the general factor and the scale may be reasonably close to unidimensional. In Example 2 the gap is larger, which could suggest the group factors are contributing meaningfully and that subscale scores might be worth examining alongside the total score. Whether to act on this is a substantive judgment that goes beyond the numbers alone. %------------------------------------------------------------------- \section*{Applied Example: CCAI Climate-Friendly Purchasing Choices domain} %------------------------------------------------------------------- To illustrate how these tools might inform scale interpretation in practice, we use the Climate-Friendly Purchasing Choices domain of the Climate Change Action Inventory (CCAI), analyzed by Bi and Barchard (2024). The scale has 14 items measuring the frequency of climate-friendly purchasing behaviors, with three factors identified via direct oblimin rotation: Choosing Sustainable Options, Supporting Collective Action, and Avoiding Buying New. The three factors had strong inter-correlations (0.53--0.59), which raises the question of whether a general factor might underlie all 14 items. Bi and Barchard (2024) used \texttt{psych::principal} for component extraction with oblimin rotation, which calls \texttt{GPArotation} internally. Table 2 of the paper reports the pattern matrix from this analysis, despite being labeled ``Factor Structure.'' The observed 14$\times$14 correlation matrix and published pattern matrix are included in the package as \texttt{CCAI\_R} and \texttt{CCAI\_pattern} respectively (see \texttt{?CCAI}). The published pattern matrix can be reproduced from the correlation matrix via eigendecomposition followed by oblimin rotation --- see the examples in \texttt{?CCAI} for the complete code. \subsection*{Data} \begin{Scode} data("CCAI", package = "GPArotation") \end{Scode} \begin{Scode}{results=verbatim} cat("Range of observed correlations:\n") cat(" Min:", round(min(CCAI_R[lower.tri(CCAI_R)]), 3), "\n") cat(" Max:", round(max(CCAI_R[lower.tri(CCAI_R)]), 3), "\n") \end{Scode} \subsection*{Bifactor Rotation} We extract three unrotated factors from the observed correlation matrix and apply \texttt{bifactorT}: \begin{Scode}{results=verbatim} fa_unrotated <- factanal(factors = 3, covmat = CCAI_R, n.obs = 461, rotation = "none") bif <- bifactorT(loadings(fa_unrotated)) print(bif, sortLoadings = FALSE, digits = 3) \end{Scode} The general factor (Factor 1) loadings range from 0.444 to 0.854 across all 14 items. Only one item --- Item 2 (``Use borrowed/rented/digital rather than buying'') --- falls below 0.50, suggesting it may be the most behaviorally distinct item in the scale. The group factors contribute modest additional structure, with the Avoiding Buying New items (1, 2, 3, 4) showing the clearest group factor pattern beyond the general factor. The variance explained by each factor may be informative: the general factor accounts for approximately 56.3\% of item variance, while the two group factors account for 6.5\% and 7.9\% respectively, for a total of 70.7\%. The dominance of the general factor relative to the group factors is consistent with the high $\omega_h$ of 0.946 calculated below. \subsection*{Reliability Coefficients} \begin{Scode}{results=verbatim} cat("alpha =", round(alpha_coef(CCAI_R), 3), "\n") cat("omega_t =", round(omega_t(bif, CCAI_R), 3), "\n") cat("omega_h =", round(omega_h(bif), 3), "\n") cat("gap (omega_t - omega_h) =", round(omega_t(bif, CCAI_R) - omega_h(bif), 3), "\n") \end{Scode} All three coefficients are high and close to each other. The small gap between $\omega_t$ and $\omega_h$ ($\approx$ 0.019) could suggest that the group factors contribute little unique variance beyond the general factor. \subsection*{Partitioning Total Score Variance} \begin{Scode} omega_h_by_group <- function(bifactor_result, R) { L <- loadings(bifactor_result) lg <- L[, 1] Ls <- L[, -1] theta <- 1 - rowSums(L^2) denom <- sum(lg)^2 + sum(Ls^2) + sum(theta) cat("Variance partition:\n") cat(" General factor: ", round(sum(lg)^2 / denom, 3), "\n") for (j in 1:ncol(Ls)) cat(" Group factor", j + 1, ": ", round(sum(Ls[, j]^2) / denom, 3), "\n") cat(" Measurement error: ", round(sum(theta) / denom, 3), "\n") cat(" Total (omega_t): ", round(omega_t(bifactor_result, R), 3), "\n") } \end{Scode} \begin{Scode}{results=verbatim} omega_h_by_group(bif, CCAI_R) \end{Scode} The partition may be informative here. Approximately 94.6\% of total score variance could be attributable to the general factor, with the two group factors together contributing around 1.8\% and measurement error around 3.6\%. This pattern could suggest that the 14-item total score is capturing a single dominant construct --- something like general climate-conscious purchasing behavior --- with the three subscales adding relatively little unique psychometric information beyond that. \subsection*{What This May Mean} Bi and Barchard (2024) identified three theoretically meaningful subscales and noted their strong inter-correlations. The bifactor analysis here offers one additional perspective: the subscales may be useful for targeting specific interventions (for example, campaigns to encourage buying used, or to support collective action), but from a psychometric standpoint the total score may capture most of the reliable variance in climate-friendly purchasing behavior. This does not mean the subscales are without value --- substantive and practical considerations matter as much as psychometric ones. A researcher interested in behavior change might find the subscale distinctions more actionable than a total score, regardless of what the reliability coefficients suggest. These analyses are tools for thinking through the structure of a scale, not verdicts on how it should be used. %------------------------------------------------------------------- \section*{Practical Considerations} %------------------------------------------------------------------- \begin{itemize} \item The general factor must be in the first column of the bifactor solution. Use \texttt{sortLoadings = FALSE} when printing to preserve this ordering. \item $\omega_h$ uses model-implied unique variances ($\theta_{ii} = 1 - \sum_j \lambda_{ij}^2$). If the observed correlation matrix is available, unique variances can be estimated as $\theta_{ii} = R_{ii} - \hat{R}_{ii}$ where $\hat{R} = LL^T$. \item $\omega_h > 0.80$ has been suggested as supporting total score interpretation as a reasonably unidimensional construct \citep{reise2012}, though this threshold should not be applied mechanically. \item $\omega_h < 0.60$ may suggest that subscale scores are worth examining alongside the total score, depending on the context. \item Values between 0.60 and 0.80 require judgment --- examine the general factor loadings for uniformity and consider the theoretical rationale for the subscales. \item These coefficients are tools for thinking, not oracles. They may raise useful questions and provide one perspective on scale structure, but their interpretation always depends on the specific context, the theoretical framework, and the intended purpose of the measurement. \end{itemize} %------------------------------------------------------------------- \section*{Further Resources} %------------------------------------------------------------------- For detailed treatment of bifactor models and their applications see \cite{jennbent} and \cite{mansreise}. For a comparison of exploratory bifactor analysis algorithms see \cite{garzon}. For background on omega coefficients and their interpretation see \cite{reise2012}. The \texttt{psych} package provides additional tools for bifactor analysis and reliability estimation, including \texttt{omega()} for computing omega coefficients directly from a correlation matrix. For the main \texttt{GPArotation} usage guide see \texttt{vignette("GPA1guide", package = "GPArotation")}. For local minima diagnostics see \texttt{vignette("GPA2local", package = "GPArotation")}. \begin{thebibliography}{} \bibitem[\protect\citeauthoryear{Bi \& Barchard}{Bi \& Barchard}{2024}]{bibarchard} Bi, Y. and Barchard, K.A. (2024). \newblock Purchasing choices that reduce climate change: An exploratory factor analysis. \newblock \textit{Spectra Undergraduate Research Journal}, \textbf{3}(2), 8--14. \newblock \href{https://doi.org/10.9741/2766-7227.1028} {doi: 10.9741/2766-7227.1028} \bibitem[\protect\citeauthoryear{Garcia-Garzon, Abad \& Garrido} {Garcia-Garzon et al.}{2021}]{garzon} Garcia-Garzon, E., Abad, F.J., and Garrido, L.E. (2021). \newblock On omega hierarchical estimation: A comparison of exploratory bi-factor analysis algorithms. \newblock \textit{Multivariate Behavioral Research}, \textbf{56}(1), 101--119. \newblock \href{https://doi.org/10.1080/00273171.2020.1736977} {doi: 10.1080/00273171.2020.1736977} \bibitem[\protect\citeauthoryear{Jennrich \& Bentler}{Jennrich \& Bentler}{2011}]{jennbent} Jennrich, R.I. and Bentler, P.M. (2011). \newblock Exploratory bi-factor analysis. \newblock \textit{Psychometrika}, \textbf{76}(4), 537--549. \newblock \href{https://doi.org/10.1007/s11336-011-9218-4} {doi: 10.1007/s11336-011-9218-4} \bibitem[\protect\citeauthoryear{Mansolf \& Reise}{Mansolf \& Reise}{2016}]{mansreise} Mansolf, M. and Reise, S.P. (2016). \newblock Exploratory bifactor analysis: The Schmid-Leiman orthogonalization and Jennrich-Bentler analytic rotations. \newblock \textit{Multivariate Behavioral Research}, \textbf{51}(5), 698--717. \newblock \href{https://doi.org/10.1080/00273171.2016.1215898} {doi: 10.1080/00273171.2016.1215898} \bibitem[\protect\citeauthoryear{Reise}{Reise}{2012}]{reise2012} Reise, S.P. (2012). \newblock The rediscovery of bifactor measurement models. \newblock \textit{Multivariate Behavioral Research}, \textbf{47}(5), 667--696. \newblock \href{https://doi.org/10.1080/00273171.2012.715555} {doi: 10.1080/00273171.2012.715555} \end{thebibliography} \end{document}GPArotation/inst/doc/GPA3bifactor.pdf0000644000176200001440000074143415174250607017106 0ustar liggesusers%PDF-1.5 % 5 0 obj << /Length 1925 /Filter /FlateDecode >> stream xڕXK6Wj% TUTz:H)Rߧ ljxt~JW}˒M,/u&lSTE\fnݫGAow(4j@-.8N-Kg:~oɏ +%-liS&1gfx\dO@t⴨6 *O{(TӶKȪMEV ϮF |ҸN+b}3Ӡ[](+t "׳e/cOzSs%ܻGG>ʾr v-PR]1\[Wh!*:a̅m"%"O12ڳ~VėgڏF^e+%yɵax탚W<YZ:Edw ;WǞFJOp"t"@hu1 =JMF[VL4èmH֠!/P%4h剞ԱzT^,קS0[dSB,x)_RH恶=n 4hÜF`El.ڬJ o6h2<) N;khsHL$.ZxoVHނaqf29Œ};ގ |o. .sv > !@Y{tsRCZn" i5Y?~`}+ FQz* ~y$TWH'R ԅywID#[(*` ==} =ֻfTSS@ |}V,B \FC?KaP 䪙.=„L2tJ L0ZlgSwzuN\#G9(;! 9Ktj4L>ZActoAl!ׅM7JrP}>[xDӁXNq]@aZr +x ,K@o\O}{9v^uMF D;2|_*o *h8tQf>DŽ' ڪ38k\D ؿ%N=Y]$8enDPbvQVP,݈nPZb[N*2qsO/t%sA(::hڡlAF4Y) sv3gN哋y>nט4]K@"@ݻ4Ѝc@hóa%Imկ~b.36MBj;iV)? C!O}V&b {~Ѿ9_ʿQ,,NSyKdgV0|U}/~ؿ5 endstream endobj 20 0 obj << /Length 755 /Filter /FlateDecode >> stream xUn@+,qz:o @"]t,i-%qq {e4HK*li&Ti 's|Yծ\ )1 'aIWk>QBBXl!&=0xdT!( ibINeSVPoK=3dO\X؇*_=C"9Tf-`- rVWUݔ]=NrX UwMyWJ,OJG%/ef*G?)AcӶAgX'P<69&cpsφ^l١k8XE;>CaxDUHM.kۼvEo_M0U}Q>?-& ]|:["le@ASt1P qW P݇;._R/(a&ԃ' endstream endobj 28 0 obj << /Length 1967 /Filter /FlateDecode >> stream xXY6~_" uKbl23ȋ5gZjSjO&A{XA's$U_bQO/=|UE`qU8lu[.sя//Z,NR0Jɳ:ŕpH7sbz lEĩL2 c*'*6IdEH|ě%̫oz+f|)/xxS=FAebbٱB BrWME/ NPW$À|"\Rn'QMWÍuNRэ>hS6J"h=S8,0);Z1H -S= D"Fe}upGxIEwmO'}}F- "qaIqfD.' au^2x%ETݮy馡G{+n(S_uFae&;,$zİٖP`_"Jc0uM$>k6uyCI0,9 WIت3fW׹IrBʺ`t9h<h43`ߡY5 ҇+d?a6`l1 T]{ #8(@8tf-aV殯{Utn#vk=o5Py^.7sKzbZpw* _@Z!xT_oJ[;S 0sY194&)L/aMTʡyjs9ܰq)6z݇_l Ri$j;e@G-O2mcH>/UHtN RN);PM}uʫF;a )c~Dj'?l0NO2jh\f~deS3<x SBrNJ4HY lFq& ܢh^h_\Ve+y1 * w2h&DG//ޜ1HdJ̳|%WdM[KBC?Pp7oϞb+)6TZY[Y%γ|aw8Li&8&MTe>뀅r*[سZM`5*lM0#Ǧu(!6M]4P /;@ZlOmkWq%9@͓IµYY܋C/s?~`V H5Ȩz ޻ ̆oCl1l?C@4P ֊ c3ϊ3Tޓ- ˷Cd1S8!ևr8f8$8IĶNE!8~#(? 87z|ڴ'={Bܜ7,GPo> stream xڭXo6~_e( "R,݀uh }a FmdPRb;_Ul/KLw>~ͻ0~xvO6OSfy?<;lǬTk|MyY<Qp}nj~ق1?"Bn-. &o]eA@XUz>W5{4r1 z+o~w$YQ2D/NݼIz lCÔj[煬K+6h0A`Hym'$=umN]rG*/WBI"hQI"bΗ.je'r/x╅ī[(eNY5%uz$b9,l"6PA ̠r/GׄF?h9,*¦!EFSd"^ɪjŰ[ ub ,|Uz-}t=ØgO^"PDU7U!ښ V#E!w% eecE5M1ONꍲVjXK),`Anߘk4qgȝ-y@jWI.x,h8h*3Mr4H@ph1ɪKle*֍s (}Ъxvl'w,ӊU5؝ v&cUKʐEYIGM}}E̘Cs$YL_A ?k]2)PZ~ZNϻy=:$ H˘Ӳy=}^5D> !ki].q+lj}x\v.N [9Q@Ǽ҈v+2ZZbC1Ѫ=6`ʈnFRIOc؋ MVGMB,,h\#6hB {Y<m|*1oO;-=MYB R+BNR0(Bq5ȓkW+!lO!$b_lm̎n,LV8" ޛL,$qQ!8m ]VF[#?[cgcT>_ϐx,bG2ISƫc? x#ܷ,En=[O/S4$vW*+2_0Ћ gq'ݛƺ>xi|_<`>O$]wHG endstream endobj 47 0 obj << /Length 1856 /Filter /FlateDecode >> stream xڽXM6 Wlsז )z[Z[3cOd;|"=c'n6m,DR|O{/IvSUMeeVI?nwʂZQ=QZu?>}O]3Qc`m˘dL}SHnS (LfⰊ vl?T)K,cۭ(>ӗV.;nקsk Lź?~7q<>8dOz Zo)[~f'f#h}ǥQ8+N ZDڙ"ɿF}![_/ml(bK=/TX" 2_ݑ:I`<:iP;U>cAmMw`T73δz4 kF#ۼ!&Hw d 0"^EwHX&FlFeXlch9I@*-4*-{V,C4ԽWfY]-G6;i$ObYʍ~hгOyg¹qe& = cCm?[zڙ7(Z1`i!*>^7; ѐ-%=nvhGUAsrpUtc6¸J()%{ YJTw`Ps; t`uhٙnkǨ!Je_Ā:*(2CaZl5n:c,牀kM&kQs$%+} gz8gp |f*LT_xZ$גIC1i&&@6 qr/;8JS["&yXX8* |E(&damq-O|/)g N]/d=)FfnujЯd9~fhF4>FxMtD(q^?ZZN J1t0*ںṾPe1AݓJ endstream endobj 51 0 obj << /Length 1870 /Filter /FlateDecode >> stream xڽWK6W{5#z.&)&5C6&"K.%3R%'Ù!g曏ԫW"\8͢,"SVb]->}U\EEy}.8חoI;٫ղѪgZp0R`+;;mK-?[X!"ڭjwR7*+(ţ^魗Z8]ׇ7?ͷ2ʂG[9yQuGߢf4hܕV`+7nN{#9iöL['yBH CrGr|Psg'.[vnPfwKY.WQxu77:&+3TcU`m , J$49::q/ NtPi Jio^Jl1cȲ~/A`a`ܥp:׿zYſ֣`q3wŖkջmKE܆łgV<Į- EN>tLi\%QT;㞝0ƾb5~ل/4>.qd'τ[.IrF6<'Sr>˓Yq J  !@ KÓߚ+럻 $TDPuL9\aaQ@qd*FshYu]) ng_Y endstream endobj 59 0 obj << /Length 1574 /Filter /FlateDecode >> stream xڭn6_ ʛDqtf{Y@iK,y4sxhN b~nXؤ"]V4Kccf3z;fLb':X `&n^Ն$D%jff/RZN"dglX:&j'Z/RIB,aц*cӁ%˖@D,>p{2]Bh(]JnO'ӕKj$NlH<DV3ْ3j @j#Nnbh;@MDk,Lj!m}HLLON7T7.bpD fw\;x*PRF^ܢygsD>hc)Ia]CGxKTp c?.JkBDyWMocW{ ]'cZO+gS 2 =ٳȧ0/}EPO uC^Yx  **}RrŒ%1Σ-3DIc;xxqU=שNSU)KaQK:0 ΕdZT8 g#,#f?d/U^I,%=BD->׻;<zw[G|K\Fz'z`%  !5=}~7j_qSCno|ޚ[3!V}~ < l3f ^IK{&~ 'fT&pՅuihٟ_s;keg-EKc,u? \ǣ+7w=kf1Z.q˒eeQz8ki4DOŊ;xEE'лwts8H. / YD(*U2]Pr(H5Nt!p,AHZzL-"|jO% 5AHPR^I+p`8;O/بzp endstream endobj 65 0 obj << /Length 1846 /Filter /FlateDecode >> stream xڝWێ6}W ѵEQ ڢ(#}& LLdɥlEsle͋M\^<%.faiVYyβ<"ֳw8uƙ6v8UMX÷QuW,`s?Η"R뭺=nm3 ?.%p٨5궫Ma5x, "FtQ/,JUV;ԡ@T DAQ :߉nJ:gBJ!( xJd3.%F !ēI'C~g)G;OI#[%}{5r'w7dʙpx=?Xb`DGS6whðGi6<$)Z-aT&d5wSw 0(]"`2޸7;9͉?mkNY^*!pmAv7W/HA4A$ e0!$ !em#nխ(t;54daދDNkJupŎl d^ ˔8ٛZSKv*ŀv7AB v;jp2v8;UmnJt-/:[e;ՊҎpHOo&4LwD84vwm*Z=bYeDKW:(@l.nMɋCQ@K#ae9jÊUCKp)VM-bDj寔C @I,{`[f288 ^^B&84ESAcu reEtrTD0e^*Ј.u X.ÞLQY/PǑW<{huϋvGl2x:IVM%f2Vq-08#]ǚF(9,$3N+!I+TҊToZ[^@u+dT<,xFCev5jigX(05-X @XsS$.@I"5v/ir<*Y#ڔNnw<@p929v'=p=ғ_suFpn7~qk:O.O~^={9' endstream endobj 86 0 obj << /Length 2788 /Filter /FlateDecode >> stream xڵYBNkK2h ؅uPþ(I<1E*|٥;1iٙ߼~WmZޯr)XlfEnMWlj[덶6Kծ슡hW`Wȭr6 d<~T2fRHh3 JE'8x|\,gw !01֦ ۶@yWAJ71qCHT3ٵLou[fODGMH)$a^{ c$N.h{^ڰSeaU .Vv VhR5eI]3<P"TgD`j6R0ard5#< +Mu7K,[¤;قp2.(짅&"KyMwMٌ VzfK W2fӂSIy$w2霋1:Өܶ]W.z±;2mD' 3^!cBۢ;1OXCI*ǻ_ЬH0Z6?iH N@aOq.TB*M֔^k*K'ke.I\4\ Η&((%Ը@)5Z61I"p{E`ueMt:lI$LX(,dKCAjtpQk YO'GIPR\@3%s+xh=*xڹS\oϼ6e:?-)5ЍہޖU气be;s!zS 0nZ0)N7=ɱҝECe2~k&! |5#C^ Г]vM,x2!,Pgg12_H\OOűj>iZ-CTρs0nz㡖$PdWmvS-*KZHr  R2@Ps/^5*Bb)]XbucE4i.~t:v[l2um!NTNռnp8znɼyF}`U@ ?ּ*箐Z,pZWȱ(zh;t t|.̎1hlt7KT?,߫g ػ܉H@`2B%'q+j: .H>! 7=[F`7МA+\م4v,A{±,zhQyFJV0/yΑϜS4z[Qqe…s S3p8rb8֬%1Vn?J,+J0gWm#o>ԥgD '.XۚFA ћL+ RFgPdxBһ03,?j#7fj.sUۮǞw|[t۪,y"~qNEq[Ԃ,^: Wb];0=: n Nr͖=tZkрռp)tr{zs{XzzS3=ۥw % SP{Rz^)vj520c΁αOg#lD蠫⮪+{?oiql*./^5zt-T>H#m:7XPIYS$40ho`;zwGZGGS᭏z|Ģ^og4 Q4$1X#MT*d2$ies*OWAp=+v~xV9tKMvծ Mo oJCc+GZ=G~\ƐZCYo*7hLxjl7(dS~QӳJP 2dPb,$QD 9N$eLC^N  P=~1g8V0$Rm4e3.j_ՈdYd"z'&‘hfd=]䓋C}_,uj8X v$\cNb8}K\f6\o{WR+MNyA}_wM17 cu Wnx3S5Y$Ȍ-ds_j 8B]vdJv)#[..aeٗx.'S@_,'5_KLė%T2rN X@2Haǜzq; endstream endobj 98 0 obj << /Length 309 /Filter /FlateDecode >> stream xmQMk0 WhCH0-uqi] I vt0,KYO~^5z-= ٱ@BHOq)*%! H2EJ7X1v8~`ؕ<%;v+_ u0hw+Ayð|:vsUܷ>!w`" ZJVA0̈S/qH9a/Az$Ym]4R[6( 6y?@FS#u8Yee]!YAw endstream endobj 117 0 obj << /Length1 1384 /Length2 5931 /Length3 0 /Length 6879 /Filter /FlateDecode >> stream xڍtT6)t(1H "ݭ C0"* H tHK}{y}Yy}]{_fg5SE@Up( PR1@?(HnC9CC0\?JH(ucSnZ8ࡇ3$J$@ (7(=a-~CNȮpAP7upB 1(Z`" 0@@`P?RpJ;P^^^`w~^C9P'kd6g4~Bv/FB7g w BuM+X//@+ ; \\p`stT5Q(^n vvGă=0g w`|3!H+ʝkF_inYnpqQS!}sNp5UW1fEDb qU ep݌Ao>hw'Bz@ ( 'w3#a @_V7 E} }&&<FSQ @ %D0@LLD`؟F#XnHFݳpQ7ԅ8tKr;G_YWwGο?qC]ԍ 7b7v07rP;k#a0o. q1ٍ~i"an/ߍ N77 -7gI8aKh"0 !9曕 Q-7p&p3?$u@ Fro{[P7B85H9V5V*[¾b=lIU2CUK7?`'̶9n⤺y^]j5_?EVj]YdѱB1sSy=:BSBx`٘l{{tGRN ^$ع^Y<28DhtuSO=5W?7*ij1`Gܷ43Dy|4RkT % .)'ԝI#yC;Jq!(󼃓[C uRU\'s.%N|K^pzxz"+8?[jtCţ\fPн0?Zô͸;- I.wMR`pئ3YU04[I^/=KF^Q6610]:!pI[Q+gGX \qnJQx,J\ΐѸJ;( Czx;gEn9kW )x-v#x6 :.M݊rAw6Ƽ?O(B[-FTk%9ڈ NW^r 2,t ڃNep/r1;*ȒZ?W=y^Z=$.q)~*oqt2;wV[nKhgxM|uahJI]?ލ[W ٓcFR뒃2VcL[/oFn<-}-ܶx(1ITERɤ=oj4) J;pv $zogKӮEdrR2KOcFŧ鏤ʖ)r1϶NP]ֹz U?2a̚"c/.0Gx ;6Gis`ZJx}< -v}rph+\ƥ+QBiYߵZ1\|#G%*꜏f,nFZmYn]G!ɔ ߔ{q KʰV.iq+Mg~S8\}+t`י5Mm(Ǫ'69NC /W^dӾsg`q|=zQM1TxְM/fh^^%_i%8|Y ?zPT,nēDIvC2k[e<‰ )mnRb95p9,B)Es+g%{8q\ƟjryA@s+F1%A*9 QB?1^!<}MII8"ý5D_$_ut]Q:JҖh= >xGlꛖKH%t ל}ma[4z fX )q"AKo=T9)1QYgxrxG>@NZCA}YyF'%x<*>0BsOzs,U VIIUnm {84kъOy? T{YKVʓ{J9==VV4եwo$nXX=V6, bGGZUlY}ճb_ϒd[|굧qD2MYqiڥp8-Dە/Vse~YHXmZ@vd"yN pRمUIu 2;( 36 vN5%;׶/W*R/b#uwcWYaX=-2%P-Wʈt0'e %/-۶μ2/c;[ a=RQOQRL;#aw`1ћ>*>\Ւ`z~IPʐc3/VsJF|,wq= ?"}KI }`B.{ (?uJN M_77-۰JEB2U^Q>*սuI ӱuoZY?yce´\򠳾5Rf&ڨޥdWUv9c(#;r!ǩ΄:6fj?競+IVEUIT6O1 H>!kMޖM{8F&鸳BX+FT^6Gu9ZZq)_PkG cY̸$ jL)B[څ3'8$3N689ԺPwR߱6Óu0Ukݍ:i5'K"iۧ)!dPF^$0l882Q,0<CcJRgjT(!80UWJ ^,&)OxLη0́faY<Nf{Gm`jY8nҒ󀺊XEM~0.UDNyY{6m xOD6WiɱN Ǐd, Xcwt&iiv 5&^ojLϣߺ+逬;8 %uGP$lE19lJHXn TV*0f!p8?!G3n[EpR-r6<|&6fa=HDh3!fal]bmryj]qJ#%[+5A t%yY&]Q+vP `_Ӊ8ley*:$G.T,:/rmIܭH<Í(~SHPU[d>=B72Vw)qā5bR*-NSڵ{(IfZjg嫘4)TgRfcJ$"Lҏqʍl2,T<:4 :W^Nh_mhOq/<;{6A`"J~'V/c 红c:*%?;@UvgT" ` fAE0/bR/kO3,ژiٌ_'ۯM~@/S UŨՁ\Da)ܷI@+_ǝ3@?Ȝ k),>?~ZyYYWsAFc>ҾRVJg`]8i[я4kb&x1)?#嘹G`%;u`%뀷N2#|yP!4`m0|@*KOblwP~֭=RmxҸ&wM.Xs;"zMStubM6lrEĹ T.h!瀮EdmlvJ |Oa ۑk;Q.ꊾhf, `,wzrX@ok9h5RR>bط2c:+yԼ º9'|+-$5ɾ91f+ݴz,wZH2ӑ=y}?MM_YϦ8 p@c>i$8&㗼?LJr}^߳"Jw#3 _C\t5^{UhPAQ}εcϗdWL/vu'Al&xC smejnvlDt/2x3[7* Rz'|)Ah|"fYI,} gi'vm7͈]%ʐجn䧚ɗcc;F YbzeB  : ˳ej:6ʐc8yʖeh.Rz,S1bR> stream xڍTk6tH34CJw4HC04"]JJwI( ]79yk}ߚf}k{ae|#@aH~^8@AKKy@|VV(7jACaP@@@HBZ0WSg _D8&E \! 07jD#ݖ/&w8@ڂ\Z -BJ.D<==yA.047tA!e6Wk> B@(j quGE(bwoeujg u{ QS!H0P0x:Zz;TvH Ov cQ}dRikkr0//G@ 1WjJ^F]_"`kB8N CI`G@a-YCd+U[Sg~?uS$j `ap_1jAЧ.UCP j4/PuWzAH[?8g+1AECMqGi 9eCPC:\ma_' ,! o|,a/?jLg 4A-Q,@p͇ڴ1b/o@PsCQYCWO6'j _8Vc틶j9O1IsK\d҄J~v֜Flcy#ߵ:zoSM{Ow}h>52N/F="“=Id#/Q~ҦU]IA+fUb3d.|L0hT & Ɏ *y> u,H%!ZE!*s=v2H}mTdweK)ڇk;I]w}.HiH0A3wtjbW:' ﹩jf^sk%Hݔ7x؅>N!YS ~==2e,`&f ]4/5ЄDPVix N驯룎y9(hyW|mk|<]VNV,4]`>m.{˟Iba7۝/b(y[#*ЗǁJ.(=J/w|~g>XKMtڋ '@!ݚ."'|ȷ5EJ5Y"/채u^F-FqLLm+ {-kXО(KYí-'Kso y̟͆~3mdO,cuwIgDKO66rgʇ. ~x)2&!gD0"d%ME:50vɿ5>G2yh׸V`R*Zwi`at혡7uEF H#^p]1Off2%B fŹW/=șm5^rp$ԇ @wrɳ_6`#v2A"8}/m(yq;|jubA. 9z"c~ߏAdy9s6mvء_*|#4'v»MV/Ͼ7,Iͭ yfLgBZ"Z7h)) Cn̙nezx|lwE1Q*7iT2˽^1YDzm%K֐e_7 .uk+oBґ8Ec>ml:n,  o\]gаڰ?~wm*%k~7r]8 'fI7f <n4U?5RaBh1G C ;Pʩѭ>{D[/Uݪ5~3d Z;ܜ }bEsD@m$ [q"o5߭)F|+ :'8LX4ٖjS=ANÒɔiC㤨gXܗDMu*T1-t~T7(Ǚim?[ZS^Mb$ZАfydMٌ= uEEe -r/2dNx#jIn Y|_B%[w% 3xA5I,E3|ΟDܖk=kq^~IvJ6y}lt_ߞa@5hz#6($όg~.&4炙)$kۏ7ĉn:X?_K dlD嶢PYqd?I?+G WXz&T|)gvG=\f^݀׆"{Q׼ڹOY_1DζE,Vc)(ٴ{ro3$ȧ=e%h{yP@/2x< g@1"@ w dD ܥbڟ<$Nmo[rR WjWD-.Z=uE2hQ9< 6O)"3{- ܡ-@=P_j;MLRt/0Qcnulߒ@qԠZ8'u/oo X9/Ehg7V%G1+<{!\ВEhezTNݰ}Ӵ515yRUag>_qev [Q.cO^T0s`l~8{134iig4Yl?AD,J ʪ1.hK ʑKzLg Ot@oVc`%։Võ 7ltc 3[i;f?[- َZ~T&Kcw_ 0kV\fTeUݴ}7ZNSGNدdžg-֨>YUO$8/|-E{\b#Dr|vo8 .wPp'iRx20Ŷ)s?8O\Ic*+Ř3LZ! v|:RsvJ(S$|]^jnH.r-\~g,܊7n5?*/[՚Ļ/`+eS.l=]:ꅿqϏ1wkwٟͲVm|9/tzRG-:X9ыd4/Y UeO)`1ztF58ސȤ^ΏM6m󖸋wX H T8wڒݠ=.<;fAQ H&'t[]Oe命x~cuPT$>ngId[a҄V`r9Ɣƀ5EIfQ^cZnWK+Z#ce؆@TMC^m(ybےvFB^J%K&gH1R.9r/p¸prTJ[C+X_k,VGݍm*K f_}byּޙBS ߓġ]=/_O/cw8, -,.jϯ2* 0oSln1 rZƈC4 GД }fx*Ϩ}gq|ף=Wə;#ÖM1f:J4ȓ-DZ\܈\rNu|aN.{e;V+U&64x$~@u S#ݭT\EI:˥Y wr׍KWr*#m[?#HyCVM+Z*DmVK- ƭSɳ*,:ӵ!4I:] 8˘{I2Hi,(]lhdfqE#YX>Gy} v|55|Un9#H4q^*:;ȺrJG$Dxx1OvSckF Lz%:'$93NdKJ[+vQ>h}.ɄCk1a+ OxwΡUQj;w8nB^xw5y?P b`[cFYB6cu@aY ٱgCվ\v`~՚s910-Q񱂶yᆌ=׉d'YK?ucUsLlr CEI}̟ߓ$]R8Hҝ֔au!J!ħEWɜ+e-B=$$uĖHmKE/!E3QG8[h-K{U܆(V`xOrZUڱMWtH0`p߇z%H\|)~9™"~D\U:br V- ޾Zz%(?**"ۺ"xZcoŤN"+(m'2QE/ gd6e(N>AJDSx$pRp>jW`u+yLlpӴp*2E5&d 7!9HE u̓yܿڴ廏mq(OK)Qo Ƥj: ,~ Z*gej7U(H³Xm.“󼯑WYs6FIb ݜk [Q[,y *qbz帏HYh95?s5JCxy`/7o*0S^ :Pqg腥(ه.x]lm~SvElrVU:ϞunL]VF u.|, {7V3d%xb]zUƇFg^&71U}jPE&{h0m_94R^,Fw7C+L[8Aaԛǧ9g-ݾϸon?l.EdIqQ?@yA8ͼj t] !}-Kf OQrww._/)cظHBǎl_IQE=5OCrhBFevr[F|}/XSoaºSLdž6ݣ} A\3_ڝ ˌ1eӾr⾛6XnMd!0zBQt;k^4{ay^[0K;djx/v 7syU :K{ǟC "XyP7r:]WnM{q@oE 75+bb QIBa71Bf*Em.OMn%4hxfF\P7G>p@6Lf8qV'з.Cj~ek:Z~klO:M[9?[*$h)H՜0l1S&4=}y^;ֺ ]V}S3QGwBvMd? AWI``f0@ҵ?G%.Z07>.v3_YQS~L\4p[`m<ٓwoO\%#([6yoϣ< -3rÑ{Pdr ס'рtE.Lf. ;PV4w,f̌1a}`NPe`:(+@>ݾ,RHQx %BT℡*_ xYIJw\UmtL9WO83s/|N6jP?emgF8+Vd1jUo<$^%[aSƸ uՈiD'c^]ʄ 4S.II[&x^{v 3&sfp(,$گPVkP0j$ɘ޵#~1ojphD4^o&:S枬ws#1+Jj4xCu)UƂEV_Յ-(erKOWmBݒUZ:nuuԄR{\v=C_3ǰ';3dsĵ]oF WA(Z2yU 40ª< endstream endobj 121 0 obj << /Length1 1474 /Length2 7332 /Length3 0 /Length 8330 /Filter /FlateDecode >> stream xڍwTZ6 "!t3CHKw*5CC -%-H7HHHzZfg}>gaz%e 7a.7P (@^\&&(ID #6Y0 \ >HP$$ x@8E`7%@A\pdPkr,lpjTrG =@n ϝx{q3;CIIC?K،,HȹE6{O-}Xj'3 )u.P!]B Rd:ļi^Y7޽e^%C"9AY~*\"7H^L%Ǯ`T ;lDm^gH} $t0_߯9 XV:Dj;z-#<ѾDOܛ~\>7\>B;ZK$|g2Eˈ / SwXR5&fyoug&~8ܧXCU;SFESVfHQ6\q5Ͼ'Zٵ-.Sd=fDmm?Ay&Bfuԇųzb2.  UQ#' =Pb2 $嫛^y~ݜ{IA~/H\e 9,Zv6inCw嵄l9Ӛ[Q%3 orCZ"5HjU=7tCtyQ?oLk ϰPWaϢYA kIg9klox1pRt^o86q w'WiL֠ʼn""kF!;7s}z$T&\lc/nBU[N0W[_5<3HkTmp :'eE*>5CoV ne-]d Zz%?&@=v>nf<ЧU빿@~^}e=(ʪg +AQU9o/ e. 93z\ˁ+)F}wQїV1?D]A+j{.`iGyaDO-ʿMzNyȯMU周Mգ4&m3XQzs#ao|^]xV|ݠ }EOq\*~ïHMr$U1F+iĪ~\xr6h HCGwhGف7!"/0D-K.?֡/3M59_Bw9f^v|3oHbH=nQ0)^#L t|N7BD.H/zߡV(CYTJ|Y|pm}s;Oh .R+haҏ-Uw(+ϡ<ך0}u&C.F\:Kd[% }Ař:'Fs(d 3Q4]Ow-[R/1q񯽬7" 9o2~ Y9(sp-Bե@nY2i Fz]+-q ]feɈiMubZ;E mOӓ^: lf}L3ᄢxpj+(AD[N/MvOM͟4œ|'.hd%00ߝgh3Otq~hdH-KxXNjo,)Bč߬NEܧFr_rpiܧ$"}JSNc~_Wl5[5B {W_x]X 8]! \wJ-(':hG7E ~SXCqӌw wdz!D WܿnKƈQ5\YQ*X-8^$j]Ǚ`VC=-Jtxws^F{3ºkܾ8!p:xCsFdC`$.Vi甈Nyڕu&yLL{7իa:DcJ{Q\FvLzXG 'D+tJ WCB 8#k<q%QL.k{P6^ebtoϰnf^lyhJVjN9SEP?'"VϘT'ݖhh^$b'n"}>)I;EL&Ljf3xXH֝ޠ){~QECQ㓦sLYI }t=Jm7s ;&l)Tq4px|;ͩW~ _uLmޭԠEt/6 4Nv,Ԇ]j7Pc} 7Z1n@ >C9(V]e<_c*$Қ%9;#Y.G!Oi4w̺xkXF) =mX7Ŏ^%TO]mzr}9QorP/`g :2 a GMC>qT+'@b Gk<PZV\"-"=!"G5 bxĽm.dVFesVЧ 㶹Kzmp^F҉y=-ҽžfiEZ_>= {|J(os@먜"<*.59`|AGxiMLd*}.9ٻd#?vd$ׄp֟{\^^tFMHˉhP-)w~gꪲh6Ǔk ksA {sP/՞{8v}F@UbZ{Ȍӧ 1쟂߇f$nP9WzKB/O ˁD4Ǣof[Xz|r \ZU̖QJ%N!cRvwj{%jc䇔vNElo# pXwjszuxaPt5e/#_L2P5q~#;<9\U-RzFI4{}/xD/nul-=~|Q4g_n+=ͅ`*u!u`M [S-T:*{}E$38.t}hE1(%e L[@qf:o@ CWk1 ,揃ēBK.8Sp .ű%mR2ڠ0ſZK-T - %CطN~j:Vs)$Fxwޒ r2? /?a"ج |ƻs}sLtɋ*Ԣe5&$-}TaImFOb,ڑ&BaLdX /ڔGa`go0WV9?~j=#Qvzx" [ ;|\v͝kvEB?-vbWA#Q7GVPӕOO9 MZpط٭p4 í=Hw?3q>,Ք5LRR%k"L27:'ДTW*ǯ9mū (55ub~HlE_tjP% ys4a;x'z$hǁetc߼#ygbuH* LJ/ec$ckJ{*jxB.ZFe&}DۘG ۹" +v`r[tv\_44-fOԪU|Lخr~!v-¿ϫ4~}jkjP\aG}>St'}廟u["k̉l%DNtO@[fEdݿ(}WfUlEC_+E{0Azv j$z]`asau %_GZGm;4-.mKI4O֤'BK)Jo$^?ǿƦ4DKzc;N_D&wͤx5:nӗyiovn_P:]얢I`idʾxM~wE7[zS99v|u(q\{v-O2&;khjfW߄rBqia0`܁ |im(}=?zťAސ&tUh^'bpDxx9{iIG{GnQ荂 GwR̞G G, cGڡr)3y4iιkl BJ-oA!b5gM`CFm kLScMb˝g=' k>+,V UKY7 &6"}[@NMyyVnቀCg'>&7єFyFa}~ >B!;>dsh($XБp7Fr'#Dr~+ vC e.xONT9ib=\$m>AY!n* <Dy7ayg?q́cW9IyWqUP*7m3\CNXknѺƕv2s L9 WqHI]W-姡w&LM}uSf-ݕ[?%`#+W8-\cBsIzݱx4R ,ey,IcUu_ɑ^H1(~|Ϫ!WgGk  Ѵ>* t[Y!CPeFBb7ف7Nj&-E*^ k;t.2p݁QH#g=̓aΙOc6B ~ VCAOC$ɭ#&X^LakyHDRsz}]C%FN{ůH5 Uk:g[7D/g- 02quL5w2l-ohW&AE)N[#%8{~(>}E2<`zT)}w8㹫u4[ymtN>,cj>?]՘=ƩDM{_nW6dP1ct>n(>2lMQI vv۽h9*qNp<b 0N󭍳ϲs ]6P%6z-! endstream endobj 123 0 obj << /Length1 1519 /Length2 7723 /Length3 0 /Length 8746 /Filter /FlateDecode >> stream xڍvTj.!HtJ 1tw =0HH4RHt#tzwݻֽk֚yw 3-"<|b9 ] OYq Ap0 * \AV$&o@iU7( E||\V`[@q`^`{򚿏6vPTT;@ 4 '6V Bx+,c灹Ks<.ru~ дr`v+W @6 (TZ c?\z/_V660'g+jC@-Eu' `ehÐVV`5wVEʃ۸p8D_a]V@PW~`W ^& %؁vus5]@* !0{ '"*@6{9~+`d~>0g[W7V[`d Ể=|H|>9=Cxc{ZJ*NV p H&<;4 -MgZvci! M.7"'Vj+'0/$iЀ!ߦF?K9Va\=?m [m0[ apg鐫et!7W*@m`V_H`j元2Rh Mb/@`8&**ڸ9AHoO#@$߈(#x OpHFd"p?>z\al MJd??1 'gff#XtQГ1uw>3na/O ^r=yN0v"=Kw]_}?!Qz#YpLU 65aszϪ̙.njg{t*yVu Ol ^}51 0Μe6A :?9#S}ʼn+tńB>?) (V*OA|gD]yn-rn4}`x-•A"Q!Db'tjfzVk`a;e,my_mj.)j{ iX [" ZHkk 0 T\>1:P2}+9lY'x= ּ A@25-+EEbx%f<`GЋN=aEhgSRTY_YhϞaAcPN4VMPlHXiq9wAGlo"Y/Zt3ZZJ2hg֌NqFO.W[=TYf4ԾKD<(M6Y A*Kԍ9tFZßTϳQ:]e򁔚} $C^O?ZzukUh!S=K]2 Z'xYDrhG[ȚIr7&}IW nVHr"VĬiI^*Ƶ𛌯JY:ОG(̓FqQ+L؅clFcJLV%%PȢ d%\y_΃1Y):(Baa 2iݞTxx[PqރAQuOH& [\QKOi@B_;Nյө}Kjj>~Lꣴ:I&õ0}rS[B8As1|2'.\_.p@ZQZ9:wEA;yoClhа!%NobqҐq{&oPCB#Äd Gxy5å=3i_Mx(~q+XE=UJoơc{7fLXE r;|ٴb{4}CE60lں;Lu2 QI薐1.#xNPTgk2v/g3,R/;͉MLfru)CZyFt[]m>m yczeHW_%d/v/Fz;K?z|[ VԱ(Rqﶕ%봧I.V|5dU%|:Q+P zro},OW>/A5amIAzgM]f‰\ˠéSh""iޚoǥYKv'iffm,1ZCv=Yu "=!"t4xϗV\6Ɔic "fV4;>Ӱ¶N}r5 4k5_[#¥[Wx^k[wřgVt:,i-voOןhWm54F,;5x(`bA.U%@ ed6 ΁)?Ց57*5kl5 ٓeiK5s,wZ ^B emi_Kc붊&&}}$͟fm_@zjú_+6IM%A+nT^vQ|K(:%Qf7(D 5B;NQPB {}[{0W륌 E{xbWH6f͹T5zKk6_=/< :]qOrD*ϡig(VZYfT0Go5 Q p\bH_+q6$2YQ1_R(J$%ΰOR9v=Vxth9؍ȍsouHR+zXL8KIdTzuz[iuR3K8۟g64Wɧ]-sMEeHn~fH\9n䎩k^uI ȯbA^ٴI1ΐ"BmZHr ke$S!|es]RjiH'Ku4Aw9O?Y]Ɨy7YdXlI8_Fh),?O^l'۵T/y5gkZsI侲4߰-x |@$sC}t}Α~rK!y5E/'GCnc>9w9Ζ{|hٳzp=DH<LTw2>&at*cPF}wl?5*Vԕ5ѕ|Ȝ2IP~oicod?>RGWa]3Y~Y{&u0>l TrKz'xfLJOCI],wAXx-Z׫M nu8 *co vQw+~_yj6>~9=KĻ g]rvd3鬉5 bvWnُR|Igq)Z|+r0Պj{ʠg8L3X%B(nhw|l)XJު:$Y&&*;fZvRqrjj8g) As)l`Ud,WЯW_giT(dj7ha[9eZ^ʪn^LI Gopl\:8ڼoM]>:oyhUڂd)fhuαY(ܺ`Im-wr+E~Ԍ9`}o{՜blsJ''eRMN$ dcg4)e ᐛu<)'7=ǸZZKQ+١#ܪ~m>+h7k (/ʴ|(kˀBzNUƎYCuPr"?}W9Q~]F0'C#/A9<,H=->~O-YxΙ[}7 }_R`Y]n^$GNMk0ιtv&#Vk/ݪ3G%:/JF.9zO (N:|o6U3=p0""ޝ{ OGk((a#+ˏ9^=U1>N)LE_$7VD}HꜞYr,-}9<32[87"?7b=9IZgvԣ7!|8GQNpަT 0YE"$&D6wٜХ^)CL~SPB3-iiIGv #5Hɻ;o]Cy ߷ ~\zɻ{ezp(n$LjbkR;czYPl|< W<.@ެ3Om\Nfk@'cK:#:"Gk9:YZw{4A픞>c6Ig< ] ZL7F 4Y XQf:m*#tRbӊ䛚w*$J&1kx0Fià~7\O5HGPpMpcu1@5M_p>M#vooM YƑ+[xņF'D*IL%nΟJ^Z\INr՘1Lb zws[SLC ;^*gW||mz^v`Oe\l֑1|4Kn^j]/$P3Qtxz T# +pj.#7yդimtj|m)!,E/D#p;Ef6ur@սK:lb||*λjE 6c1{sR6ػzB!mUE U[ߛ̭ 0*91%[Q1a$&yy,oelUYFp;P;@nR8Ը)ֵdXC::/ɫF(O(kqW*~yb1%BG3ea#lLCeTW~~j^> Q"0GӸkŻfoD$6hUwC?S o .[VRwXh!j, ܏\;^j0T%?+S&Yآ@x 4|0zGz2ؗCuSx`. ~;8|‘g L5:ܭB뤺 i_X+&Eq08AD;SʻT_oAjQ{rЍe޾]%C .]I>v,Döo\-O8­|Mk %=KxY(T*NE=dž権*q @o yw@V`h6 ʎ ,$2UL# ɿ~Ϩ}ObR/3eUfhXՓT axTi tuxoڈ(= =JG =v 6 yk@*[5,rqK-Ɲz0:j:۠<-L =T"Pi / w7JGvc &GK/SH) _NLnikc']kc݄&5yTFQwxM'ꈯ[#[>o b="2CۢLlnLxYsj4Сa} %opL2ci,eIhJU ;dVucip3tj7֞Z {$VV*Ϝ.9Ъmk$:0ZZɌ*;LuPylzّ1B|tm*^`qV}'xePlZy`[wyaZѶSLOC=+Ps)tlm1>Mwhv7b^p<Ϙڰĝ}Zo0σ\]Qʽ*od^T%xbGutyeD]S2/< K$vij:\ Y o;EDߔ:ݜ͗UTafF=Uo2ِS~S'nk U:C=o4rF{ ]} ύ[l{>&WQ֏"oa:V-Vf$ء/X ެXl풛2%6g,<JX'R)xAawMݖOgVV< @:}XV-ϵ&jQ xEZ!FW;J0/jD/ٱwj" tXlRu1}Xmk1 \3QmxtG%cmUs*<͞&C1 f`μLE270n_G] |Saϻ՗wCSDmpn'a }|L^ah$Efh 8ڟ3<&ht#zkz\ͅ RsV™\jvۚ^0/ڌtgl~- endstream endobj 125 0 obj << /Length1 1357 /Length2 5954 /Length3 0 /Length 6884 /Filter /FlateDecode >> stream xڍVT]$e$RPSj`f`r DBJIiEii) i %U@;{׺wk{Ύ}k*;hV"` 10XgzX|po~U ԠX|>B$i9 eՠ~gPT^ʿ@ "++#;c0( źaPO)c!p ŠH14UAPM>p] ݘhc6E`8oD(|/j ?zD] "7_ٿP (W 4`EP@"5z X=PhrvՂk7±@)0,# ½Yˌ?[ \_x;@ @g t"Pf˟=~D6O<-g43誙[* n.t'*.!qq ~O#(*j\@?o_5}!'X8Poۂ0M)z4|=={~Dx>ZUEW k@KDh F,U }>(@Q>`]phy: v.q)i #豈8^ Ph,>o/~ b0xY<kShͻUwV* ʏX>Ma}i_fEc:>- +Ms6^E77:$4&z\I!j|lA@ت×{(пK3l}ĊKi]ӲmË򜞎pbE9ɅvhFr.t!$ q6 GA}XyYmX8ޏ\ǩ0ĕJ|j# XHJڪV~fLt3;^DRk;t۸ 2*g2_^ &/ϟʵ?ǥ0ͥǚ^q- DeLA:./} Qڞ bT.8pNѱ/J";daZcff NF8ít&ŮuUŰb`WSPE1))9(xtƥ9n=yQ K4eLPL! &bnIN>g{WQԎ9l4EkK>bw$̈b{dR#}g|c[fMz |k.H>IƢPޝ/t/|՜&%2TXmL]}%ֳK:G nC&?,Y-z0jg6(𱟮LϬ=, ̫7xHZT!eh"c#{SiLͼ[΋iy7rt^\NX^tڽbHr8nx9ޕgrLexr"\h 7RuO$S dyYNj?=ڡ唶SX>p">.E9caIR<ŏ4vRUOjC^=PwiFn zx.,!feap7Hz(f9`ڡrZ.݊B`ǽzp"OT1c*I\{~̌kˁqzWfCp*OgY zP .DEE_#.3 nڴDD2;ܞG)HۈV_zO{M7^IR$c)SHuK(~^@*6ಲ+s4=2b6&LL `#2֜E[u8j b<}V,:d3=hk/V{\.ѦĢ>ڼMOkxkxJc[dz5żZ.~|p d1s ֋7dcVDM]?]snyxvVNr>HF3O{EiZ)&+ةm]f4>qK}`$JZl׵ߴ#r[KXS5LnJCۀ0 L[+Kn5<,bW?"8q ||mg|- \SnYuU޹99Rk [Kf3:z*ڡki~$bVy!,UB-FŃ ӼWIxWFijsgcB>q+m^WZ+5Hᴛ&^ZB݌RoS9R.xmC_ hwu =- DeID(Z9 gM_ AB79 GYȤې,Nn*款ү6cXuWn%d-eHQeN aZ,ׇ ߘr.v輁qiIzq:N9Oѹ,L LO'yn\m!^οQRB8v߈u[LjK0d|4/:ʗ- f]DOˆDi Xt'|k7m88gh6 *mgO .sʸ2T1$B @->&8s%"a2@o(gꧾ4]Q;m:r ~o{W 8I@d<(Ҥ+zVy%%wlљbɵSd~8Oԋ:S+MRiٓ;/,mi]•GTl4O{krMGKNݫ6RLl Gdw' x.72(Wo*w͑F+zr{ Ў}5't)"(t4h9E59@.t+INzq5$;6 4dj3QV[ic6`Wy_>?Tcu/h?0p'|MU\J LfKƮjt,ՇIϹ݃ -Cf5nwNbgJK"_f꒞tz.0X.#j3MHVFX{cЇ# WK`bUwm'c I sxQC2_k5E;+z"<_"'o(* BT,dlz;MfM߱eJdMTj. )nDhkm.樛E\2_`v]dG:HO%e0%$/K,Afvۯ'@]VhcRhUD.&R[7JՖ?=bŭR4y7tR2 kté95f~Q~ʿh9MK3eU/Ø.d$(i$pVayScD7N˛WPoJ Ak,FDWz[N`R-ݣjỎ/{E 0+V "'U>#%PuǢztC|FD-N^b_jvk!l00^FSSP跐V9䟃̢WD-%pw/Kk'Ć};LE9c!mÕs.%KZ5H26woo8N$oF7YBo ~N6X<\}/Qp}֫Aflg2#۸$y)Xb_c^D|'P9A3LخUԾmv;K{DcZpڋ:6SH60}y2Ԁ*{b>r`zӳ׼euHPrH҄MtbFI)p$W /B/S@zvUwj.SXC綾 Fe.yB4bB//L|x+v4!r}bnP?*ƨ|\f Jԃo9U C)ME/ 3T\ =iH$oG7H?G*y8M؀CJF;JORXFo?N.rk 4T>, 9 Hw-^c vk0q("*ML֋08}&~`pdr%[L-hXL.'2V3rHrኍAyτk<iU+ӳ[ hl%^]#'8@61fk\"w(.3ȅ9B"NTI[3á%[5eM\ VLgRy!|$alJKShyZ51R[$]kV#qBGˍAo~3)րSSm)7QYzBL厍 Ta¯ۿgdTwksw6HO͕ ]\Rjt KI-giB;dQpUMNF^0.8T* DTNQIsdL%zcfO:DiG =W6>!Q?JC/;OW'#]#i=Sl"ÌLچɰ^=H"'k2P(n(5Ἕ6_s"95QL;wҾ墄 os& F,aEri#׿{ӓ ||ě(xUKl `P +&J}VX^(U |R9AKKX/&Dƽ,aB\mn* 9<+&cQ?nr\BM&q5iOuƛ Gclw\na*.n0ݣ| }c4`7y/]jO}c b\Ky3/ *oԻQN .MgY<$a*fn 1U!ZtX%JA}fs:HjLUnGhY0tw[8BK6o!Nz-r A&{V|Zߒ\v )zq 䲗bJ']RCB?ib74gcvxBp^f~5 7Hx|ļ~GkJsdHñ2U2Rp9}s8 !-Y>;ijq1 bm vj[p1?#Xk}8A`OöỜ^Ϩ^Jd$*jIBk U7gσjAjȞ.~''Z3 ;h$;k)>$_ L\0n'@ k=?Si7ÐKt'H!y$X^eT-J3B +T54D f)b\*gS4I(@ endstream endobj 127 0 obj << /Length1 1423 /Length2 6282 /Length3 0 /Length 7258 /Filter /FlateDecode >> stream xڍxTT6"%H׀ttww330 ! !  *7sk}ߚ纯,F~ #Q.T;ٹýOvn>rQD^@B6..^*eUn)DpƋЌX$/ڳ`~C]i[=-/nIO]LuDmYz:aӛS,T' =;s񋜰&Vtxx/+kM>mdw6|™Z闲V@zzP;Q׏\t(~V?B?•-Sl$yrbkiKx{k/gVbд׈Vְ|kkٌ_W&VɃ; %Ӯ= qOD䥈 r&v#Hx5u_&8Y8zuLjɇ6g_s-|GK rhm'1ƺa;@d>՛a]h49P-АҰԋ83n-8Bď.w}֎;Fw OۯxD&'?%aѓibq}_R0ëZ{s|5t{ת]O-&}C|&B97\[u3'+1*P 6R?T*DjJٻ){#|>64/NiF+ޡxCm_9{˙jd5NTûUַHhWMa7bL.\79\PPڅII*!Sa= a槛Xk,&!=.:f6nfR=){0Ltt4-/f(@>Ӷ28AxڳBsсsa=n+.{W'xj9PE#=Bͺ<0yi' ,0ϾAlhp, PI1<>JR]{Q/mhӘ1xO5?Źr XDiG?=w{}j7o`6km ۛxallD2ih]کї'Eh "1Οph`*/VDNس0a T:oZL]#Tz10"a1]C!nnʜU_3=uAc0Qb⩻⡜4_;%8G5GzœY풝%#qL,%;ipj/7.[;0cؑJܛ9Bwtc)(=@<"x`(ZCoa{F1Ot.ncQgzuu{'e_R8q䂸J;W + |K>Jmʘ% S.j/JG箶Š2z񜨩 t7f]N#፲uk6ǻrSBekzd;OŕpY0km.Kgmo˕Wv>y5~w)f곓B(k:0Rakc]XxlfUsBڔkdXv JN`r4e}'b& U]*nIyg?o:R/ *EN*B0٠h,}D0ZiO7v E#\f}=xe8㲋~vw+HP>qNMz^ RƣULi7V$3!SiB_Ń );0|8'fL bϺF]}k1WhAgѪ= ^kWVAx4d{~Jd%ϼVyɌW...Vj0-k0LeOG~]d1@jmfEcدi:{NkKyR qr7lTmF|`u qƽ'l7OL Nifb]Npd*]8G[kV׊|ڲ,U1v"V[䫸gܟ)Y 'u4h^0g~%s\.HVAd%TIN;C;©JKS/z9IU'@; C])Xq`p\`̵a&.⨟aoSt_K ! ɀ'ks!mfMsD_9mJ7O^MEѳzFWLc\USf]`QR* &[Q[- Ob,CIM UƗWTRUZB&q3+HWU\85q;h}̢,38 upQ1TѢCmf7*Hؐwyֽ驱wl~f:nV?1" ^ ,"^tq(;{ 6zvj,jM/ %UhZ}0|@ɐNi&&ϐ|/̔4WwUMRѰ8 {5|dIӘoi!}j#8׃v=DȹBٚKӮX_ jꦰ"*&%_{p04H~h9r|UiLzh;_2o9G 0~*IA7\ju׵'ހgAȽ@a"㵑j5oDc!/g+| `*_;a gN̈eKhyIrc^,?cK 3,t}2^;9ȱCoB3DJ"ED&\Ml![}5o$-zuRGQ=[թ6 & [=EO=#rS Xnyofڷ=\J\2xC¥QPsV] =5- d|"pYPբstwNZWt乄d=^i/iAK9!Hi4'H648hN(V̯4ֵ5/ Q~\S-cea~1./&DW}B۶Bʈ^Y܂! ix3y ϔ,تɖhcZAjce y"h˓N<&$ w)^]Ko|`f^굙VaXa2OqzvI7&9^z=o'{$8enə~-+j" 7 w\`W}6RyYR w׽]t-9O6RG#%m1<\1,ZgB1L*Fq+UXa>1HO ^̓W \[ou"桵ޟDNEL_)u+j`Stawr(5 |+mޚPNȳNT-mO<\_ [/|z`"Ex 3XzeF8/o.(c"}!=vGvh;W @>PFVcLيGi8ZNqc3̌=#a;1~-EamYb##r刳%1j|hW"*J&wZ=D4vaQ$*W(T mz7 B+: MEx T)*7mpڗvT?̩DCL endstream endobj 129 0 obj << /Length1 727 /Length2 12086 /Length3 0 /Length 12666 /Filter /FlateDecode >> stream xmyeP]Ͷm w]ao wwww!C{έ[j2昣gZ]Dd002T%DX̌l@cg+3 4V+33 @ptPhYY94@ W+SK E@ 0D$Ԓ I=bbke 2;i G)_!` ttKdWPTP2rR;;EMM=-Z:bD`aY:LVLMw_BNjH0E*Ԣ ;3 2:D@fqwg?hc;+[/ CVNV@3%+習ꟸ&B^レm=f)Ǥ%+*-F1'-no 2:U쿁JVPLXח7vvr23kH_݋ `b.@{d t".LSC| fʡfX '/uѬ- osݐL6oHcHQ$KOEd .4L.#Vh'3OeJ$YJQǮKS#wPg,C/L=mBm!]RZtέE 4ztsXLBX\]K)LQhr˯3_淴%S8 ca褱rݍ/PĖo:>'T+Z_,O[٩}\xI[1W۵vV'r,chէF[lXwZ/$sn8l;dg4 n)~C!H CC^`k{pNdD kG.(!xf죚p\Zp@D].-A7a_ՄxmidoHI~DP~ƭ{1tr#>+J?Trw0RyyJ0VJ=oe +lW$ \YSz'ީ4J׭`Đyw|i 2nI^_ٳ0\-]Z$ҕW{MR7E34_f?= [wC؉~tB6&R8!$R*' 7rHXKP@{z9;:DSš6%0V/DyγF^:'N(6,pyGoAT46IS~Wp+H3!19Zn;[Ij9U'IaB F]0.aq=ͨ3>G/J[-Nm/a&"~҃xN#Ψ&k]a-W=VX;lLj>ao'^N˳(+.$aޘszẃ=VS ? e|I=,v3^ n)aBYa~G04./WWdr3 ' CSż'_RʏcJ28_b;M_wwXP$R]^GF% +foLCChs5ڃ(u_ČLcNx~٩l:MvչnlE&r5o6Mkz5!9 hmXbb%Qi G'FBle##Re?Bkk`F6lPcl<7 ?쀭"TGc\E6Mh\H&.g*p2v .ON OSEN} 0u`]^Gܿ;u@ dj?lIX0o$5J}?>Ru Ldhړo۬Z Icp︪Oo"kgq^%VgQԝ}q~tsƣ(,$afs)Bgx#.;2%qa]O.C L&psjx,kح2k 3xbu W+X+%!+`wBEt]JDt+l%t8At!]8kU'c"YE꼁  D h/]~.$Ŷ-%r-?MZ>an6V-kR]ZB/VVJԉ=6wlFCVB"Ou;U:#=CEyaNtQ}p0sҮDDۋf8Zߤ7ۘSk>;dKM> p=Hw秿IwK# W_<[>otxLG7'A)DHzerktE-Bj´l)9,0לeeS H~rKEWp?/AAߵ”T i9mqÊ]\ l>7)j&jm2 _d |qmD?ÍYNoJsX߅sʖF3fj.LY!iL'i&t.RX9Puҹ͉Jek6 x]7)]BMٚmz2*GC W5L5?!z-9nīoƋ҂L=NH&7@/J"No <Ϝ['U cF>KF & Sn|>HM? >-5sϲj0 \`+ض ]80|=ΓdC2"O ]Z-Kry?iuDj}˜Ԑx+! K}"{"N?7v+o Mw,gMqnlV>U%ĂS@2=V۳,v. IfqD *>d~%OH7I5*"[l5`e,'p޲gxpcL+F:9q"N={~Z9!dAF;ԫV}OWEItz }졑zx̘Zw/Prq)` V\AΚHc2$;JD4~Eդkc4`>mے=Ӥon$Ks(#ZfRҿ<G&_):"㾤 ;5mRw%E;4ܘX+PŔ/R[qS&Շ6e-0wH(:+i__'ݩĝe]e:RTY~(M+-${zq.'Wo_}Gqvr2F}PVz\YHȒYrŀR$8;ߋfP9 UCQ*7|^:lRz/k?1 dAbUW<:uw'ZMҠy!t+`5CI%aDYypu^zId:S|qz7)vBYwQ*Y8P H?H kKu=SB#7%XҴT/P@ٽW]ւW1! ~ {D\u3ihC":s4@#Ѝ#x~ tCXt=&Ț(ь|.!v6H#+2*FJ}w3!3Q&*LZ6ߟMUf1l:߄$qU?J[G V |BOD]'/;G|9c[0ڷeZH0]Ԣަ0Boe._dn`4ZP>?V@YZ$ 9]-eLތ4.󡬨Ú)_+q6*TwHEmIB5˄ٶq~/:)q+Hsl%^;#;%‹\7G7(LV:_DUKV5`%2dF)#81Q$2 SmR2N=FI8EF#y&C)VgOؕw)8_kRPF`&Ӓ-Ǔn[pAt{J|gs&e1M(Kl6k_yR_eHZ3f_n%iL곕dЁ7#WȢO|:pd(yc?EXy[FqCYi'CNh0FIxqsp f]ٻ5{j=^79 vuBH ;8c%|i=o¬ =e V|SCU |/!ڴ/xLJƜ}W.\,Tf :/w#Vu-c<ϒُb8O-r:wn<U lZʢa-*MlNI@Nb sѳGqu&kퟡ"(HZa"(92ku%4{OɤXǴ߼¯5/i+4 ezlRh P7lݦAC[_Ix7W!c%9tXQ??s9P PU6kx;ʂN1a7.FQtnDg^qk 5b~V_zFZ)/W;&BJ`'3]6H n ΪUOإGd=Aد6np]%ٗvrz^}YN9\ɵ΁oI|5\L n9K@Y 6-(o‰Ke=hŭ^[c|#8s%܈ ;O UpFj\8R:@٥=$ S1BiZ( EqI".䒉6Qa>Z;K*[kd!M'8x&_we@KABܖW^ܒ!G.E`DZpu: &OUrʭ Ԗl!eחC~#se?A 7R42s{Qjo2$ҝ!gʋ Nq }T>LzԴk: ,K\$Ony?DoE!}u@ t ߽$Eŝ&zQ"TޝTF.|( ZT#}v_ei*ũnAt!:N[߬_s!4X06)%f.COHVaZ`7ES_zwj|lDN0Dn[%:cN> W/ (SXRҪ/T?i/~(Pm;eډ '{)KL,dh^R=ȷ)_~f Hca.찝hf+ghb ,!~˒'7 `A`;ⶂf 5>.&/n:% f]h]> ?NMEZܰf2aJN<s:+ q]I[ECn&ۏf|GeN@(+EdU#m4t$cPa9qϟYv|Z\8ZIU@x_J-sPzn&_)QSc&{L3~"2B^nR3mpXJ.Ì묃$@zVoFMppHٴFAebLSfɖ|Ws 7O2x,*:H/?yPAcD/G1xKTu{- a\/d(WvJS*ndk9#$l rr]:S7Z&M/D /d_z.RS+Sp_?%b.Fd#i&AI0;.Ngʲ n'=<(zjK%DXU24TWtE!~Ps^?Mzadw=;^!=D.>9{x0~(dT5t$u_˟PHv16%%*}<" 44z` rO4ָX2<o Xr=ګyn E(3[kD۲>'JD%yZՑSɢؒ%r&ER ;,DCnHG7΋fe@|ƭ_KX%'Jٽ%tq22"?Ai#bGV gl-^ôA焜$Sj?ӻ3Ébmw}UR/EUˮr~!^%}}(@/{v/dW*)Ő*b0P׏ޡ2 a-pq#Yw"i36Eo_ܿ7'+> I51jCQxfV?Ǭk~EZ]5d>eD.pI*oLT>a᧼v$(Mbxst&7R;Df*űκpձl! #z*O#6(Bʈbɰ L8a)3ON?z$+ I *f2]q yI#ܴ(Sm[Du, .#!;CXS8qq].yW7r21L!k׼ r.ڨ)@HmF=\,] ;+^ͦ{*qy_P77\,ǔ6S%1N] a'BiJ ]xT٪v ;~\ӫL?1ݹ@ Jn=@pĆMcDR?Hg ނ¯aЍ8Fx< 9թUa[E?[Nٰ Z̠r&\GlqHh]9aooeۗDF6$K~oMeJpA+am8S*xHȗ =j)z?49t鞲3kHʻ,^{kN/%γ[d˘ - ;.C6QHW0G(gliɞI]_xas7 ,pu ;8;}py~,+F+zBCZq/ϣm;2\%tb>"6zZeL jW:oimxB%)Vp#*%I:/3uh#L\TК{HE۔ }kX C=b{h=,Ma ?Y(Űs\E㴠T >x˭WX䗵l\yLFK}P'q"4~cH FOtlGPkQ6<"B-֯,Q4vjW4l2_PBs 2D{c3d"F{h0g =heyujSjUω~Ӏ`Dzflnl Z(β8!~3AjЙDM-3ݷ}ԹTj*HY6\Wk)kaP1*Z7d+ˢO^ :k~Dw[վ P E$5ViTdz3OHr繞q'c`%sl3Лt)QtwiV-7TM*k¡xW,ð5x0 rBfa n?H~Z_=7'~ۀp sRNߚN ,)kdB_,ƚ rn멿͇s)y9#$3gl̓5241WB\l7įkLf-NvLr+Vrg9焷ԙ5 7HA35!uinl0TT9DI><=5 .>L|X{u~;؃ 1Q=u)1僩cF.1Z 2׽葻>4I;)˶ BFìHd$(+}/ۅ{6qMypٜ ߾rcaEĦ(Q1E+OvL3|%&,˴4"mw#v:@Y>kCvWW\>CT779BJZ"z~XV緆iz3/վ7.O:9Bp&_؜ȈF5m]re~ޮr`s x[k#y { YOҺZ%3B^WT 2fJ^;* ?DkDq~7AEeBrt'Px*3K$ pOӿ*l:BL^HD -;l6Tu$2Vi`YRt@ANY ~;s#7#Y{zE<㓱8m9M#MnjS(Lz_}a]1 \>-qڂ¢]Q 6 gT'uAڇhZ*XC6YrJШ!rA{>Xa[h)gdb`~#aZ8`8GXgǛ8X4Eخ}evSeubX\\#&Vd.)ؗ5ƦN7Xw֢%0sAĕʹq4:lVW0Jۺ9۲h͐[Q75=g7? HvuqwQ!2 [S MSJnoo<[ 6[!n}HU*쭅[ЖY-S-H2+HKe揼pofBi)~%CHxՖ]ID`횤u挒Ip>ON>_ΉOR [$ƤtDqSW# *(<~8bDU1NemC*.Qs?/52I,%?Ui;\9Y 98;Bk.q|˗p J@k,Svsp]m&1J3ӂT82r~ *&sz/3#7iMq _̶$D~)՝}=`贌ĵlf,Izֿ9o;#1#MKB=s`IY2FY)79dxKK([ܪ"TQp s*' ӟaWPݫ˂8Q`ie[ymɇ#G]q`vas&ZZ_k"[Gnrl0іS^ ^ČT|Aҙϩg a` 6xKK՞>*m|hQܬJkwl5c0mUO1j$ZЪZ‘3JSp/5~WT>@"^[QJN3oُ~tEo>!D`llQX$ŷBIm15bR/7vG0$CDFjXT?2Hs5ˋ̣odr+ƭ'Nݶªjk]O4H+\Zws喩јa~\ 3:8_l1)9ZT|"Ko(zz)D~\L w"V88 @3;&+_[/y7:R$h^M5s퐐lNq1R:}ЇW-֔tQ=WpJk)z,EkUhyn0'b/9k{ endstream endobj 131 0 obj << /Length1 727 /Length2 16301 /Length3 0 /Length 16873 /Filter /FlateDecode >> stream xlwspmLlfbĶضmۜضm۶s=߭Ocu굻ڛXIHHPRgdb`01Ò ; mmD \51@ h`da%ڹ;9((Z[;Tml]̍<....t|t)'3 אP˪ā6@+@h:lmɑl\N3qȈ* *D镅6imA 5 ,+ ,:XFFhjnK/$mLll ;7!(ѐ` 4le%k` PZ9;2@1@ hc 4/I'1GA݀NHnb`Ts>jZ9Wc[+aݎ^NXCARiQ#[csS?8Oiywϗ1pr0wh1kI(!![7OZ&&f-3#9;8m-?:n@#صe[# 2rHi}eFЕ-A3c+{eHՅGqJ_}*YkC׽5м]r=2PͼGv jkf Qпa;һkx?YSVïZp4ӈq"Ku4TckKs.nvgLw Ul72RW'kɲň~=wX+rᵗ&=:Y E|E2"Ea6L–3)IDTU{ua;#^B'۴S3P,xeX lp4^ 3 % xq*6~G S/v( F [OuZ~'0pSG9 UFԡvϿiLj^bF6B3Σa׷m48$ͪ|%~*_Q*`fÍ~t!S|DRd X|!aqR'Gp,@iweCc8cinJL½eͥ`ofҚs|*.^x@̿?!FzQEV %seh&L)H~5%l؇۪g/=|6+{T2Į(ⷩ#-6"dĸpȼ^ked!Xػc,U6z4TV=4T*jllǶ8@DcV5-Ha9clڛuA?w2쥆d[n¹M ADں8r^pNYؐ ihjfƘ"f(T2_ľxs)V} s\dォ?v +*7kvrT*=,>h*}Q9e#GpЗo-z4}l_2Ա Ld^Tzgĕ7W$S63 .H 9@]e(]{|6<`(ndeAmiؐ٦W]G_1:GRSssޣ썾P_0jBd?b3 -#TDn-K4=֢ EX$ޕZ˾(*Z|,k}Ƭ(fnA.lJ_.ȱUS]Swx+r##`*|1XSqHȎk6[T}c}|oyܣ۝m?vݗ7PdB=VFܨ:~e γ>]%vgYNW]0{MH;3qĜy;Q,賕)ViOm{ Bjn j:9\ 3N6cU/Pxj?/1N.Ih^XɹMQx;>jaJ߇KUTᭀ5!#pU駑sQ MǸSQZ)Ui#C~/e[l.*vxļQāA!*am73-B %.lFcr*2/PD!{c=Btl[{O^M UZ#D>&b[[7/r>)M`/'=yz 0p,K>s+1FO ~R&"bfȲ,b]Vo#Mՙ!UHFXvk2&-=?g֡޳~z?sP1HrvJzG٪x^1%, :/}A^'o~9.*u˹ZrYsu^Ֆs8# DQ0ǜ!φs(X2CZ#AyvgZȦM76'$~QRR niC 0:͎\AC BwE0$aqCW%sJDf2;G 4;wF-dTr!N`'wr5-RfF;zΨ"ߕ\9,V8]mw3K6'p1|7)N짙"~nNj9VGv[RiZǠ`P[hِcŞ~&k+TPwؚ&"pi}bc μb=/vڬSV[oo)C.0 #C1Z-- IR||rs'Vl l Ԫ]O B~BИW ץA˓צcyKU ,ɴ-SCNZUB@DE](Ю;ԀЕj`Ojoć bga*jZL@eVhݘ5| 8Ԡ\^ǩTf[PI_rY?)BUywB `SvfQu_hL(vz8Į|fQeսH5N(Xܯ~]w(Hv-mP} }1;'uML􂹕0Q Mm~DJRwؤZ?'Jndi#qLךq_X-aENFMK#`hОczHs唘J9_P#| yl9GkT*+y.B +q[2F.؝Hχ|*i'ɻ^ohF {!_DziM4t/njU}l1]H$SJǔN4۠ywa tzH+ JD6Pb0v'3-͋o#9e5;ŌE?i-*.Ýɢ{7r7[~Yק j])%IgjCD$({NnxՋ8Z$Q"(  ~j! %"` 4sBF0p)"U(/A^5YʠQ]R8?x6~"Z(IVMI_rkٰ]f^7n5jܳ^Yxovs- ^W2SH=?],M_|+l*'NG\_I2-T6}ҫe~,Hl#ZYu ӱ-n*,b$_Zj-I31BdzT^ =DvbK(^7sF矊  T7InZsr 2b#7O?wż2wϺMٵSzY'1r6@1o,PGNʬ/4y_vqNeQo/1/1 d;{h^8K=k3v­.U~1]|'cH\ ?P%4|$t5COkY܊ "Vi80ŰܚGQn8gtg[~,ua ]|Nϴj*9/&0'v6?woPy|(((Vڳ٣/ک u3N x38߳+h@5`zN5kRmrh&DIV;~B7W1UgK;Fm߬\i58(%F2op%ȸi;i眙5i(W>OEYeڈDuDn:\׶-heinc s*o* VsSz FŲ!}T8N&ӏ?imn&Պ`8o=3lqEZ t<?v;+R0v#%\{+)s ?YdKM}w{88Hw~^zS juI5nbl\E4D#TǻM-Qj%d,? +RɉFc5+ڎƃoW;vHRb۩_G3uǑйT)<}|* 9i+zT*OÊpe 0Jzq$ ƭB(gBD[ylxKHMcf]>7npKo8mHۛeMLC[3r?x~}}PԵTfL9 FL!Ǣ7^oAKt{S):gz+H`p3!y}@NOA ĀVƷx.@ N/ŕZۍz/ۙ>ySa"!b>} uXnsi&I*ٞxr7r/+?xX{ J7W>K([ڎK 1"V LM]xjj``z"2{`Ƴ_y^iu 1n KNJJrKgyq)u%LVc(~lЉJ;1xz N&k?W[`FtikguN#b(_HjKwլ \xQrV , ;}oN1$!?0[]SEDD#J* /ʙp6Jndx-?[ ~"f1_y!4OB3sjו8Ua##J=kx]pOv`[" $Ѽ;.&ҷpzQ"l?v=nK=)K4_ӧFP`4>0<"J =R#d-gQgA~̳KSB.qm5YQYrFwK7.D,a %%5+,Lq@sXL cLpC>uh^ZDg -2o $ gWKx̎X~ŏ|[%L]87Xޟ݂aKtܯę]:xSfe 8BẲUIt:mlM|g.7ȹN_462xj F?17,1!')C,:K5s} h^Fxȗn*4;ǓPZ U@%4WL*.zv:B^s=58OcqC8>#Se3t!j7N>l\a)eC:C0BȎ+,m[݆~ރ5d =h1Hwcbtא3":N1bڈPڠbƃ$װH_B_?IׂeIow_hH$d%q p]۱-l<݈ |Ds.UjM t~GŅuXV9mcN a ;樣t !fk_Гװwo4)c5Eo^~QZ]5]wwӿzg$r0jK6΂(S4V/yi/bJd½w8՛4VG <6I@ ΡwK7,8!?,E;c9ƨ5b??[펇H~:2 j`ycd=PT:ɼgw71gK}]?Mw?奏#,w '' ?::Ak0*$\ˑA Rl(tYX(QSˏjtY<]px;gj"ۋLsLV^.E"Z!SUNa@Sf-9 `*|v 77)gh0wu+v"VadWMQ*QI\B ϤO-X,?fN}W5rmta(n BmHP+a]<T:iL>&710>$ɟ{**WT:a iխcbPD ֿ X4\eo9pF:Un:l,h '@eu^L˗Í0IA%ƸBGMWG_v6դ 7unՂG "MY߸k d^u7m6$T)}/:` 3l䆉w$/{iۓXsVUQ ʏ |x7:f9Y}QǛ,pK`$cS{5|ZI.)ح $v խG0mElО-e ,5CyLYzz=N]|!j^EbVΌpqŞJB;otQ%M#$+Uy,v*bOi5X6l5HijmdIgr]"` ɇ'/K<[~7&)37Y<ഃFRܳj ڇg>Ʈ>=x$yRЬ.Ht'oԒ3ݕapiTY:u,ksmb!570cǦ!JZ&,)c4rB骶h<]ǪtؿSl',}^1L ׀-K }{VZyNML`:i|a{mCВ`; -zgpN6&cC~RhhEŧ&ٷ5kpn*cek MF>j~P5~|=KhPHCCYL]1O3zMs[M+{ qA`B!d=` w[J龐`գ DmZ|6BLaJ^oӅM'N oa `q F۳ _khǾiҏ_M'rꥬ܇f4.od4NĤl1<6mjx'3,yTrԻ5L8K5l&F (22BA8M}\˫^b1򂴂GqW-P=OWv`/XuGNM'~$ZvBOf0N{l"7*/d@[/h5F>* qԹm `4P(MkITfw)`ٵG7yO]Ԛs5kyk%o+ 8 Q" jYL3nL{N0Pn6c.-j<ѫ"FyH-Ovݏt40q`U`:?0$Q뽃7Tez%g=εWs`~oT%SA; ` AN$/`ٴ⪋' t$޲$kJmnb8{AT4zcz@Q6q=u '.ƥLZs50@f] 喺Υj՜2d`.,ma˨!GH*+CB}UJ>uotIOhu;^M>W &:G DO1>ڻO%]-ݘOx2fs[d3%F"*OW CT;.!wz!H*$Ljˣ6L&l#7[TVJV..zXyeaG!}~Yk0DIEk#k33`REҩ7~,$4ԓQhmF"xo#p5pp3jIcuxm)@̤nGvm<S8&623l8P?Ț!$s^IEx:ԿU>n6k0Ĕ8:KZz{RtD㒃Y&G+y$p}X Ekz1a) 'e)s뱏JjLPuÛ\@XEZ`Z;zy ZM 2d?#,net{CeͪÉ]g  5"I} "BNcVNW n}s¾iŖ\|Ya^O_S,L\I pIgT2RNAʱ6AnzX4 W=ߠsЅzq?_jNM7囎,(05JVԽ֓w{7=0'}RW{ĊF F#8"i*QbJmbxʈ;Hr|8l5(:*giX?ZAJ3Z鵫6=\Xh`q-V};aTҹAϵ.>*~c\ doj3n>Ӳf6NOZ:~YϒOIz+83c-g Qgu қп0tQsR1nuv7'1TǦϩgn.ײXnmj:'V1rD<+jXQRA(%-7ZО  (0 a*}[!~?HEwk:{ꪁBzp|^v5AT=0D'G߀[{fؐ^{YeoJǞ\KX^\DX} QUĔ1ɜ͂EPv>OK^J|>@V^~&X,mҒ`S^%ݯ=>µ !%|^;;ƌNBJ(5f}M8Mؑ%ZNBvPx'S%@ˇ0Y:?ɗ<:%xbw#3ܙ,HQ޺<tToj$DtQ %E%lxqkt>d &xr nH^%6SHo"K"%$6TąjlR/\F c?=xѯ@| iU\AbRB64.Gu Fݻ>s]>o"EJ֘ v eGVՁ+$^*aQaFJ4jWfmn \J)N!Z̟Z3"OIN<(@ϗF0wFkHgmX"zJ1Coy 㗿xnк! 1LDpmi6L{;ЫlߓTnPݏ U7k\|.g E,ߝc8atG1 3^QJ>OX"]Kv1Ў%j}d62|ǘmKE2e?,oNʟD S$0a$ַn׫s5pwA)%#r<8]^w|K:R6FSh+M 2@rxlQK4rG>(閥`%|p.TѤ^mh`&.U&IHC#"TS&㈗8;mT"|aNBa٢6!Mv,npҰuc,p+r#nEfsUA<*\Ŀ\E-ݽ4^;RFxTȗ=$H~5[QRKg"C||L3(b._M槮oQl^J=9^ް,Z!e}Q>Ͷ.Q"3&p Q:ÊyZ~wE߰8rDT>Ht228 endstream endobj 133 0 obj << /Length1 727 /Length2 15053 /Length3 0 /Length 15649 /Filter /FlateDecode >> stream xmct%\-bĪ8UmW9QŶmTl۶m[}ga{ٛTnda`ad k3()E ;[QC4,VffJ9@cL #9Eəљ" 2L-EM)y @h t4(:Y[d-N@Z#?_M @NLUH\A^ &¤*05JSn r 46rtYֆg/`ba ,l&MC~4MA;[[4"v6 #@h 6&@ m,!2G![dOI hhGrSCw\WT ϽZ vLRZ Z[lL,l*5t4_iECw,ח39Z$:t/JX̓+Ch _Vy-SxLAOO//Mt^iY_ߪ"MmoI6#ICu̼6^^jC.~C]݀VW3OJ$X" J[{Q7cm%huӵ>AF;+!HWxCrw [OXml 9pk42UիX8iC 9r4V<( 3!ڭ[Ð%jq+'Fipf6ӣZ]pM󽵅 Y'%S0S꜅r.d.:7ʛ}4>־nĕC|Q3ύ/aΥh?$Ư.UP\{ƂZFѳĻvj4Hîmq"N \̑hg>CKV2Xf[b °J_1'=Mt.aa43xJ'xر3SwnVRN{K1 ;9p+rx&h8H_^ւdM2c,uOM`9Ŕia&XN ?w i5jmkA$ą%|6;9njJhq] _aoc;peAzٓ˃2\{t]VHj];ٜǓHف>:N֍u#))']zk2}&/O4,9FcLsmsC0\ɫUYG"ZtlA;IMu Br^ΐ"4ҡ˵D N~͢rנଶ?oFso†W_,OOȿbf#ه# W L :μ[S&j?2ľatLPxa<ǟ+xu}Lu6eQS Xu5-C Aؘ"zA||TMJ3 .aQnN4rD'|PW ?暽9ӓc:+`dkt6fS> q宑Idq"s;F~N 8U|b˸jp LuF35 zbėms/@lB@&erd錊Na"nu:B>:َe֖q5sm)%4'q2GkgjsrGXm=t!Xv]c+; knNsߥP%1ʳQEԗGlY`,O$~FI"mNRM)F Œã"BS+oō 6I&-fdv. ^h$%EY::Fk*1mZY2{ Rc)3/cyeEˢٻMw]R6Mx fL??(ћ[kl;Bpج.2LAGKs:*7̭s ?YEF2#"4tNbb Ĝ=Ÿ]'qܔ #@싟>0:ӄ۷蕚HԃR O"=._Ɩ{n$(%a=T@-nZ3ZST!~gw-vyEBji|KA'pdњYc2ŬKy%nG<,иT+,v4H]wgj=A7ͤڌonh-v1Wңg0Ն<3O u S櫂_LpW׹2|19xs\~ڝ\ҥ+úPkix D}|>a''iY4hl 5ߩzCBc'dhlE$ptw^%^X=jKAQiy#Ţ'JȒDGOͦѦ>##/ܶ4UO7u0PYDDA_-2'N.w. k͸ub߹غF#8bpY2fUNE dc+12q*}HhFy$Z袂?_\YH/h?VT(Ŀ;!)j͹ b#N?6'=YɩљRi^lBDѢOudӂr3ꃣ:ܽGjLGaܠph Ra6ҵA*$&˕a`o ^/͖t3qY$GJ6z0[.&)^"[bOwRWXrx>$?b05dsbFy6R#~zVeEv)Y<00H&s0#c9gF/$ ADrHrѣ"lWN{EDK)S𹄤|Ƨ ӃX9|Cv}Byo;4-afMUrD+Z,KBn0g9i^|ytg<C)jS{u`_6<)%\"bÂ]7=%$$ZۊA<KGhXãr=y!˃nQ5ģ荤pRn)^Iw(6:pFh#Fs/@ >tg}ߍ3:=iKϺjBOr< Ӊ%:BޝcP"29-0,(6h\]P_M9vs% ,ʃ̆ Z6)IĨWǓb9?dK<&LeR/!AxrY6(,F 7[q! SQ 1yYBi]!8,,Kk{>r',չxARvA7j>0isO> L` yj1B׽y r :; _Єj$e xkqhPA$Vl4?UuP;%_]]Ki.S`P\?^dx(~WxLjл'3T'x;H^P2P؂ȸO 8?i-bاFʴR (X@mT2{+Y+(g*͛˸Q6"ʑLIeZ>5f`ܳD k<:)QL*ן`tmۖf5'$t&ѥ]TKG$ȳucjE( Q(a X?tJ~!fq~:`HQ^],*OӖ)ݦ-\J%@J!]/1 Nl`nI_*@G&1jBi4U<Ruk(\vy9ޭU--0HT#M8$X@"X'oR ;Z 3hS8̓PL[z|a3DUt12E=_햦24O94$G(ϳalyy ^zi:w>NR_c6x:o ;@,e}iNOĝ $_Vy`;[MCo^LED{줫~O ܿZWpiI#Vu@1-vQKٳV'f^md2&pڭK%&671|KN;mq#[#Ѫg̓4T3 !F[ۅOwX#xլ0V$Iseweɑ@FB~;Gwٯֳg S4Sdk Le{ L U԰8Rx~$M3>ɧl%kQMt,K| x'e~:jclƓ6gK[w|>6l; Tğ-շaq;Ԥ(]y:0hJ' RZ"X1^A@=L=6KjΦ Xz󡈹CHoSPi vg!I7kL=ub[!+u󠺯"ξQYRX1b'E[J骟80KK-ɥky#-:2qZOo_PV##|~uOzHe+ȗd^\V75U!_zr>#YO( l1^ ]#16|<&g-q3Qٳ|;Ky̐uojy3E1>&LBՆw {heU" c5gzW Pj=~ss?U +D[_5/Fv W=jH$4wixª(B{sj~˖4E)#T(bs4hȅE™zs'$оD:FhY4{pdK,(L()']:+Rt[[,THp ^ &yP |B>['b@'+)m2plY0A.͙ òu-QdazI#Qf[ ݪ((z&ƁVqae wFԚH_ڪM(3%^- B5rܲ6*0`F #7f촑|Ǖ>W '*"Зw\BcFżTJ[0Ҳ޾  \ܛy법- ۟J@F$u-v7 .:I#~>*ǀo1CTc=#%&hVBbyBNu\5yVnŖw6,¨A;j_<HLpX@@3KRB+-G-Ib2׭Tsw%tlJ"oL@H4D'&'ï=? 5]p%T_lt# Kn\M*_РVpL/=_oe ؜Tdnjr:is\=~qԭۑ?Q{]BJLL%&sxfB(̆x˽#;<"(@Jo|.Ҟ W~JuȠ_L}I4N' #3$45y J{Ϫmtiɂdց:#22{O %CUO sHE5=Aob m\q06M ]w.ћ\nPQGs`I3Ev)Sц7ʕzKf)HK[៷'D6 yRg?5Ga_>%G@1X?[+6̙j+Cf9ܝ~(ɯ3n#pF5odL+#9`Z(Hк45kosL@ b®M@?dEet7WK$uu @G*6gxu5\Of~-nypʝg9Y@Vwd'{xr~P"_OUxi5y!!Ą0 åKoÓJilۚzzBMR!Jla-]@(0|Ci14NL?y~'W TiU7(|H˷U'&v.ƕўa?L8Nm7`mq/p~D?Y;˫BeA~ ;dKHX%zu oUڣx?/PnЦF4~Bዻ4UHGkttl*23a @^ZDfa6dfϟkG4O'^ ZO!9V LS_d$[/WX[$PΓZ0X읁ٷs;j&u-HW[1\m=F5_(x!{-)W+dxDЯ(pe\\sH?a۶!aOfE`꫽g\%6DFjbC`ba%Q3ּlÐ~ cmܓ$ $eiE7~ܜIڹ >)/9C/S }E伲 '3F> c.(hg>hN&}tv,hv?m&'f2hꐍ &ǎ|nuFW[NZ!_iVwbJ : A[5֩Xf2#:O7Yp!^4^X>4?${wҕ+ >r;ĕ :$Ncȉ"ǒoJnD neMp|4Z~%kݛ^j4~  q곹o" -K@|:_d0,0?:>m :n"uРX?jWK1zUwtbՋ$I!OR Dz} O1-nyՓl2yl)V\u>n :iIS)ftGPb%2 ؈TqQM1F,qaiU| -3yE1z88^ "R 8: 979-Mzbt]}=0_'R=+- YԄvqb8hb~tA!;тI ^#Ӷu䇙q7fv1_V8Օ)IqW;C]U8 !uHz8d꺰Bא<=wѤhYdxy,"[n F]|qct~s."gg3Ÿ1)]?-~F!Jqhu{ܥG;c1P0$~X%Pm׍S9_5` G8NF6wvz9I;J u4"%ؿL%]V}?Ði*>&-۹K-|g41q&hހ K,ֵu7)~i7Gn'Ht*wO QCUNAa,St~uϑ3-7O/Npx! -@mI259K鈠N<{p*fS= D/y gb5:ypqs[k ~Q8L##7:@i т5z6alg&ǖ7pۄT"I?n4?89G\/~O ZДwbL\{xU7V`Me }(a7p@h)<8xZX#Z3~ˎ2UiFHI,LACW1ai1ӑV1wEdgEl -^(?Vt.S$۰,ӈq^ݨzz TR!EF&6 h}X5 pl=>~ޙ4L{8燾f祚#6XIs`g=);wLͪ/M_t} dtPgԛ V:p`1i|ŃmChDz :T}ϛvaqNwB\w=V`gin9G;"b o1i7ҋDZ1jb='6߽j~RjEh =8S佖,m]BDm~%\,nf?لQ(U4kS3XBq{gѮݑr_m]{@KvYd:P>|-)|JkʸHr`7bu;Ɂ,n6T쏰ٷU L;Sj.4y"Gc=F.qKЈH"cAc;0Eɚ\O"'.-`~ЅuiW}2}ق#fy 6x*dPH;=pS427A(KzJ-ie~8 n.X<3 B?V$#ѕ'hm;l٫%t՚~ yסmhYo_swp5[xob%o( ;QE>He"ݺ&rMߚ)G`F30E KzZk#I<#^%XY%7$ B'"+SǏ6-B<3m7b(Ov2Zof}!YAvM[W O['Ya_z .EDَYCQ2A{R5˚!Fb I'ݟ`\2"im\Ma٬gcxPSUTr&dvzp%^bL"}Fyl f|?T]il5[{Q^}kFm X1r!q>geSIg'm(wNݙeH# ~r.i1!5W>~H# OB92Z_/n@!$N }-lo`-eKS&\̠f*z$] c؍o^Nf8X{UPU=X+Q)`y%,!: .D=-ëcI:ŁƬyvQ5ܞ=-R>6Y%ekNMŘ|4H,R)J8xmVudKk>'%fqX3lPP/P%+/Y63ߗAoK6}&!lOs_&awyi fİC٩e.JYAQ;]co>8zc$y$c~Nܓ|~wcM"2:0fUB{Q`՜Z eň1#tĽ 'Ά*Ƌ&e X5cF_)j}"'1r',=Ap45EýmnqUf5sPiͣ]`dNY% Iߕ;/{ ҃fYAʡImqF<os>.=V${9ߣ=uJ .:qr(7qߗxԪU]&jBbjFcoTMaݨB~d15obh( ] Bhg9jYb^(g 72}( kNѦx1c0^+PzXBI35ʂ{E&:d)9 fs<~p+j3QioBx%Y|) *B-GG[y="Vm&K2 Dˎ4m0N>k1|;ftŒb8rXP bSOe"g+R}F@\S56cq ٖ׮UuXo`tSĖg‰ XmyU.oUT/•I!=`( qIϢGciIFR|zyҼ^=iM0Z*_LJwcgV؉@YZ|I/:GiWgPXXY~ʹM;E#3\}6?o'.~W'O3GcH`S3x ߣRS,+h.rRަWwCkD +u{0\$g>S{=2.+|!tD];ǫΤϊ"~wӣ Vxuעᅤx-߸ `LNԍ pd4د(ev遲) ,7) -XGC0INU#:"Ǜ#$P]nv<[w6 >3kMۀ*ind~Ò ?CIvظҁm+N] !8-^lV1S\5&?/n&΅]9V6SwI 齚 v cJvhǡ^~ڴ ,s˔={2WxF$YHT{}bޟ#pa{ؿ'П%qm!P`")v |wV J0Q/bjEg4{TkRUvC`#ifLdL5/)Bq -:y>&)ݝTXDFet,>(ubȼ_("Gwb-lNBykTq-90b 4=_3gkGy% ̍e9 _ qKNx?~Ș~ԑ3!,R++9qN-@K05Чd-Z=u@ۥhx˗Ylqvڨ˜>0.jO JI$]E%DqNN|:X :&X+*Npjؓ"Kϟ^%MKH+ %v5YO/'Di+#D$o AeY^>UUCe:oPPZ*-~ -Zp`m@p ޘr=B%kZ|Haq'G"w|&0$u~++'Nx$2\[#F0t}:t pcY{I6#12,maԓRwDRRQG-syHܲY!pˉjLrCux=^,C)MRB U)hzJE*K ;1⿛ePmDS1;w^D% M\]&tf],-m.8gjg3=pOJBk{B7|1 ~YdIVH32=ڍ@DžA1EɥH[ltfIƟVgDE+yN*XfтTgN$ܷ i؛Yã#[mޭW?m K9WXG~HYl"`5X_C>iR+ֱ"B No4 7AZrb3t;K9ےX@){Ӄ+oN x0o?Ð5~7KbLlfc3ON jqhw7}WE{osM:ޔ_{wKPR=@M*XQbev&2&٫dE7N?NpMӔtKaȫwFpt]9[iq'\ปE2'@fwx1>VD)_ IJ֎A H @!iDr'??#Ƈ-/rMڜG"D2~̎f2%/^S9zMM!q'NR^YgLfG-cx"qb8UtP "I#u^Mg!UG ~fR[_7Ț`I"bj čAV!:9Kk,uz)Z@{`y IC5?IRBxMҒ~l8e'ZtTg3 v"vi=2ls.Xͱ#0*M_5*H b]")$e^mw+#sU 35ݔ8 XZ ,Y|Y0>h4~>.; ⪼G&ꊌbh&RDJdL[~èQE&XB3|[ϔ>Zg#Mި.u\۷2#4AI:]|Xxq Sp )q6_287,kR`@S Q!OA^PhVCbf1F L endstream endobj 135 0 obj << /Length1 721 /Length2 23875 /Length3 0 /Length 24481 /Filter /FlateDecode >> stream xlsp_-;y;m۶ض;m۶N:u3sgn}U_=l]{uzOq{;UO =#7@E\YHGF&4r5rr4Gwt4pPP;P12tػYXxݜ]\)R.@  %%/WHNF6EWcK H0wۙZ3 ع\!fdo SWW0L۹8s8k:Z,YuE04q-=?aSW!??RLf]mllJ{[W@dP5/R.F dgr Y:[zM-]\䀦?'jjog[3ƿ2(kkI(o373N+Yg{K`@_ᅱC {x1qrXLl.]W''˿g^$ hbobV'V8WI37cF:sb9dajpt{@0h̷w+uLlD8RLRaWZck"qy뒾H=ŚsV#Xʇ"cXc'amNJ5C x@Sc"Xe,`{-ԱR6@~>ܩf69n b ڥ'Y֒ .`دbMMfeCN(2R;$*wRZ4F? S][\^wS\F$ԅQj'အ"d31PQ w2{p4y\ 0E3\N5&kk(>8DK6mi T#yGւWٕY{15a%f`KHxklƳEÕ.8eLF2pvfgBc*3/; F):񕾦wbBA ةK\xWYJ{֔-*ݹgڜWt>GwGgMaNy-_Xh1*p"1[Xice, H@(蛐 ARm%X2H w 3BE RcZ(sW d@^ \ >21‡ȫůjd4SCTۻ<ͬ@\s0p4dW)lU)SA' XCQ:瀯Qf2j"uv*Xذjqɛ;,l2O, 'Eds,^W4&k"iBQf&oc-ٺA2\07#7n74uOqNtGQL9ӀHr$+=쒹|)l~Om7r*I{9CN[HX-rDȳRM V7soy-n,xǑ2TI~<)fYtQcԟm>b{ӳv]{roInuvWZo2 !_'otez x$m4AŁsF(1N0 Wʍ6A-DBF{%XSey ΢<:0 '7ţ!-fNi֊a^xB~S 2a@26Zo7>aT@k"βrmAcpнcU4:!Y]+1bΤ(EE5F,lOϾ>`#IO~3ZƖYaBW &ْ*ǣmF7$,'a=4<TB,ԀJS7IqA]+9d1,,b_-![rު_vEjȐ󘨵%Ԣ g&mG2^Oʼ0y/aL墟:KD<[_`2|g` ~ׁtg!úBN_@L&Or_!WU둉 mtP1Bvћo_\tA*YTPzU+WW *0飢خ"ldI ܒ{#4o"ЙDI4qv= [s8C50RV>8uMN623IASh3lsOfYgٵŢ.%Zg -}1B_ǧ FpHV/{xU?]ˉ4Z;dmH$dw[6D@A|0]clJJE<>Y^!Rrc7QXPBx$ʱ` r֢j㽳Dn#Kv@q^u>ɀ^lX_`` }89lǝa_JYYFp5p7&UeG).w;~–\ $?w J㨥+Y$r.284Z`]ie 5\1j5(o@Y|L@yjkuSݣl.pنQ1ٲ\l4 Vn{3ж)_u9Sf.N;Tla<)7 <. lo7 YeIZnR$@%~UXTETOٴlt>EJ 2=}/ܒC(, 3p-T߮H6W Yd|sDn/Df斠J~6Mɭ,U7`gEXh:j5"CL-}ZGWQg?o1?hŶ(?[NeP+]Jb$C5Sgqvke'i,EpJaxoa=dCeCf:5>NW&/e>ԃHYZ/~"8&!穧m3b_>09ٰѬeFaP)w]_pڒ*飺ڨmKSGԩSMh*Qo ?ֽnr :ʓ ̲pdʨ/&Q|a 3:-oQ|x!\%Xr2jm (,EU0=D d (Pt6^[p^,i{Įߤ$R«$)-) IR"fLB8~`Fb6_OX?K~9sL%Kԯ$O.L'w@˭O 0.fLU`i_D.1jY4z8H9Ɛc7cc; ־'׷BG%j?rQ ^@>~#g&whUOӁ`10;q.W߉|S&*.*׽?.yD㘬2E?pk0)qG11XM]Ҭ`:d92ϒ-^Jꐅ̘'zUƞ.A% [!!G7OxzRzjBzB?~M3gD}4+%މwq+0MJOhdQ4Tz@axBJҜPۀ_&=Ï ]pu'+Ysavvx$[ >l m:$mm}0:[w>kb=n0e0\3rf89P0ma3((gac̆zc2Y Y!05X+k4ܧIJ}q>Z mne; 37To2b1}HsWrKYmQ4+`u0GjbI8y ||"וz Ѯ+%\򇦉d?KVע^ 9i5 };Ϭ 1{i R(_PJ)W% *U8)IQ? 9DRFvG{E]ohw-OAp}r35.U|_} dzLf3_WS:O[IjHsxd12%NdF @ܴA?)UY>$% I‰N4j*gGX*ۻ@&дkC' b,HTڒ7%:F*e nuQ Ȯs˖7:#@?d4MG ;d-f m&S6YkB r)3g]8~LY43CN%E 4~ 2X|GN'5Vb eXy7@R1a!7z@(_GMlblBW ۰a>ezq4'!izh{qBsZ;PFŭnE]FEVzJ(!jk^iIoۂhә?of/:S! א6ϵdx *96襨 4 A[ӄzB7Ѕ|\e'תG'ߞMFCdg!zPuP&i_2B19ĬkGO6A9h]9YDZNe3p0LnFpX-|d Fs# kLL>0ԪG~NcSp (% ).*r8cMJi9Μ{K3Br!uem A6y \Q59ě]Z!ۆȋ!.2uN6?)ۇ&7 ?%tl|NBsg7p{ętwL($¾nḾ<uyUE=7)}>E*^Ia53Dr^ӿ`.59y60k(}uu5I W!f]sz&9ϵh%RhƖ"R~1!&]f:RO󲡹>,s ٨'AiqOwdGCZ,F)%(|~,ߍэǏ-妺Kqɧ.=J*AFkӧcʰפg/fz7pNybkpQp%%3}l/$yM` 'Hx MWfכ|ovw^J:z-o.IF?OIXj^9f5)-C#ĆGA:V6 -Ѕɵ<0FCbNqCN ]SE(U0^1⼳|a>T+'("2~.Rz̿}Vi M3a=VB5>Y_A _8WQ{G:FK`4 I⣅?Q^ 6Y[1֍F|?sFnO$! /\ˇxAnt|D=7V]Wə M^=fP*:kIKg朹1cV}][F^a2vx-P;r@Vã2b=ɾ?}}Ul9X<5[[!z (IZ_'S}cECD%!9"׋1cT0@-[lF7 ? USܭC ) T,Ogc3xXdFսy;%љ׷ƫ[v➾-j!BD/Wb֒"BVmсolLW: A~)N߽R?MFB%ۣB# rq& % 6NoU2WBR6}ki_?'kFcb2`ꐗɡ&'4i*rBar銑S .OsT#*Ytjkd3&vfޝT]\kk+ 2նG+r/';Bj)ƛg ]ԃt#QZxw)`-EAVA ĨDWRFxW_98ջFX,bm\ʷi1&q f$Wկ aŶ4.@0AqJ|jұ=c6#f`٧E@[-p|h`\-aG&o2D/ŕ1o-A{ٱf?(ҫoŷk9s-LcOD/l< 3o&YNbHY]i5B-+vpv;*@|i۠?Z<[8[̦#eC5/yƚOyK7+u7szzV˹c5SfA$X4h0 9&/ۜ)xO $;DNH #Ay3(kͽ,[r&[5p,ӻ&Vv%֧'Y-'FKp&jk[Dm*Nm6MT2[WB=VТ߇ }T[IӺҬtf;#=vtSi^m.\>l BapyAIVE7HP?+P=/.<\ !7f{ϯG=cѸ[ a\KV/^^0@u!hc| o93&f-?}4`@Q/WxEA/ rC4w[^/*U]_ @g@+[ 6LfY.ܽ/9]Ș 33 `tD,u7tnTi()s~U/Zm9!\E(xCBSkm)<}^sdBXÓ4cB<_ Ю1ȰDSKk`M*{Lwq"z작!˓VN Vu}(BHt(5.Z.U8JVx検'MҨ\T&}{0U%QKE%wvt J3oǦFeLkyH|~m2 4=Li L x;&q&s Ps&'K.)X$_+}2NF@PY(RL6b{-+%h̛M[erl14R4Bfe7ePr R%MwK3]ԣ7#}L-؃۷}wކj6>:6O{36!4o@ѝŠo0koP9w+BbRiٝjHs oS5^Ptd`GVsW|$} K;@aE ۞d Hބ{j$06)6zZoh4ιb#&,L10jˡu-,B qZ6s_%nt0ظ,bʘS.PDaGY[گBfE]4W\SմsMx8/ŗGFW3+#nga\(ee2VA5S<؝9C"|ֹۑ˴v؄njH4 1ja`b.b+įG Ɂ]j/sn;"(Qj),5啷=5gRCDBX /ZN5?7Y(>b*J(XL~oYnI}X.aUͿ/AFhaE3&B-wuŮ)SQaWG:fRy?spƕrcu$I|ӎh[Tٙ3꺂{lXB/KYuE HрQޝ}B@cOP&P%=&f}1qF™&"`M01!s >&Ρ⚑THIe@n7Щ|qEq3e?Ǣ+ϋ+U@p/ b2n]Z|Fts2D7j"wS#$_#Ύy=O&75n UK5.eipϿN?^DDˢ5k8mj &6S5 aF@/ 3yb#dB*釭TrC`W4~0{̲1m.$X+*bb[ߑux8iT/>Vjz elYhpp2S(fUV^EN{IvII`!S?Bx52 Ԕ-:I&6bRz= 'JbmN*~'PjkTy>#.҈M)Q=6Y~ka%yuksoDkaz*9WڵGF~0sӕN!Kun^YԉJ ȧ4pFn{m*#c1uL`su s#W5#4qOSD}6y?.<ɰƚm}Sq)-;V w{+GJFL#>XLĐ7D[cP0hϜC|I#6{FrB\}ꊱv @MG ԴfjMtJ`"MOҍi9K>aP{%~ʍ;rDs7a_ƪGiG /Wo$bR6:ZDNoJ}1)\{}<4{\Cc*YXq^ΗċMold 8.@AX  knT|^+yw+le޲o!x`3%q Q~*ږ!׵V*Q ܈AIt*Nǔ᳐-aշ`L-~FO H 1acTz~Wp:Pmh\^UdJT=SJ"6IXVIpze B30|1N;gekH@ G%<쯯!p2N /M pě2p^AB _=S 4kf"G=269oGj6'0ZP}^D| Xvǰ(1zav')El@ofmp))YZ,x"v ^bʢK%)͢ƍ=.|mRBj-Oh޽-)\mbPin\eSiZkQUrO}Z|5蹲GIEBpJf>!,@=/!`~>T{/Je7|^Z߻)ޏ-6f%W^:1/N&PCT%--p}1qu?4mK(>9;<^} jqen* ι 7>PU\/b8XP[4ȕéjU!vU}kִːeWY@rl i^TtxoO}أ͜V9}j#=o+%:P]W:C3V8TֻёLk!O3/Ac^ѾZV6Ԭ:`${IF^6o~ #o HL}/">Z+ө[Ոڅbl c.M'v^^z;]AJ݁e7!-CI|+%诃lέJ K uEC:?OڗcO %Ol+*~\P&OaF&݆>gUn;;^;/F=CyրY}i x _Ex- <<6j/uMLDsGF^̎|)tHnCŢ Y{Tt$dH+]0FEΛ;o1xqy9X=C E\ӊ\Ϟ娾윱6]fdgFN;>L&oy.+ۓ1$wϚk偍ǓJ=$9 ߾ {u"GW{U@K⍇e.mbƲ8Y@Ibc+cV~^ZhYxq"Yn&UkOK.DŽKP@w!SxeX|:-VD)ۮHu/%O*!OS BQ ED(ms+*_ݠ&<ͳ^MBB*0hp~L@hI'DC{[ۚ;s=q+SN!.O39%` l*$s\ aLZ"y+`dA3i}g }v/M%Shu?Yԋ+m&"!t|sL>(*"vO{E6}|a+>;y)Jtx~oЯ5C`lr+U'abwwl jEMiP `sn՗2g Iµ.*0uˠ dۮ:Ĥpi7θ;V k%3uǺr i ٖ)+,`ƺђQuFVu0!TG=Vu5 G_T2=[꼱+37ݔ)4ŜdRp) \+NR{Ρ{hquoؔ4$[P8xC?0pI(*}hCw|'TVπw3j-G^6;Ҿ:dW\j#6:P݀a?([O\fnl,doRěiJֳ6!]ޚIL]D=>" \u]J3~>* j.Pߋ2^?r;"?bYZU3_* fV)볉^,׾Zs$Q3|Č'],a"'&1S0 +\[a{k处WEƄq3i3`:t*5< K*y^~g{sXzWf2 w:bozJɈo*ܧõ 4‰~p&MVc-F51n:V:/+nϠMK yCxuBfK x-G 9'̽pN0&@.KX 崎 k|`oDQ]a¿)'xG{,$R.'+=I.&|qw&f#Mh1WODqkizP3=fsT ^,6޵oz#q=_T9K [5"!#`UϨ]XX@O&F*#yډ3S8ywᷫw;R(+/q޺(.Fc[jiz]j#b_p(=ǷI\6 `NSɏ/fv;B7 (8>ODYeӞ8Fk6yfή*zudwԼ~J/y%( ͯ:+#np5l]^"toev~/.q7FoAL7߈toCQca,͹Q.r\ xR!ӏ'?I50O\;vՐ0PEwR z'{V:[z ?y+}6ľV jt(x/yU8Lc"R?_ Ź6%操 vErVyLv{LI}tEd=$51=Yo)(,EeyX+ɠEZ*>3|sx%&Q# 4OC^C.#oMW*?,:Z wߗWY{MmIBMY?6;M`& }@&T*Gةpǹ-QGڛge w)f\|?|PN$^,Zq+B?IqAaIe@IdI9qݩ10pk!_/d>CiՑ& -Z\̼/ y߹4З>O 0xڄ*Gih/kd jZ>I)I(͋B 944զ.ULdF{w3 Ge69잓ZS`}EU׾BM@߃qhXKJv⪌P+m3 Qcr,lUd}#(eP[{%uFi'JV &+RjwtWv|҂)jK.ӏn tC#:=kd8$׶ ?Ufe ewNpÜV%oo0_IFLG"Q͆X8CuޫLSʽ`-Hn4)'Nܨπy[)jZH[ } 1t|r34+ky&C[WyNܙB2;aSJOЇD }՜yx:D;ȝb"nV"1B9|򅜱F8DU>xOqBRfX*@Aʜy׍%b3I4.yX}e@6sOvBЪ]1~\R1}-Im)__gF1*նEWs $ j't ۤuvdӈAfGN2a& #>EySI4ϖ %(:?[ͱQA0'iɃn`RqB2<- ڦY+Ӕ{ n1EڊxʆcS$F˙dk,w6AGc!e D{S lgL̶G&u@8yPycB*4< eD RLL6)'u;TŶzaHeݞzEbI H\PHmj~tE[ V4[Pt#[Dl-:Ix㣋.9&22"="}`1߷ Opd&Tw= *h1;MQ+պvDH[@q!pGMKɐ S;'i1͝Oe2UP?zy,Ռ-}LUp`4qʥ$#| Zy+v`ofl<\C1hc00bg(wt^\jleN’um$wHk@+@nי">fH[(٣i[S K{CnfNܗlgDT(Tɸb$^."+v^wYؗh9 4[#^9ID^66ɳ0΃>1pR3"кzb+>cwTTxJ[\\7@clL;4Umj3?m\1kuLtWv-uu𬴿dgqlOgԏ_|@ uI :Mw3/8S^ѡ0lݻ@=:Xv'NIVq*_">63. h_EKt| R݅J7YY̓pd'c[hD컶Gj*(}+FcOZ7zfbdlZ(zx`m ;̚%\{Hٹ舕k$ $+p[QH! M[6iQD7[йE8QJ/@?r]9͎ͬ#BQ{+ъg?ksq⾵aKj29%cRqt%nSHctZc8 1 _hZw~ d8g??ǥd^s@_ Dҥij51)+暶W 3n $p+-_1Xf0âcNr4uk%?ALaEE:yà"K) {:"ac|(.d?g_DmdK[ZN%YgjԆJx@m2' L?VuTF;8,SB Vq *T3]^DZ@gb0\A=Ӛňu Imh2J8knrڀz0 0n|bBbIIų_ȳKnɹՂ|F "30B]kM%:vx{I-%LT\|2[4$\C~d.' \^D<2aX\ZF6v #܄g![g sx_'D6$(P/b,)emNͬBΒ|"yGGPqx ҏ#)CFdcQdӡ,CV8sد5Wp0D㧂7\ x. Щ41>jhՄtd0_Q1U%GD*}ڞ{C rC M)HQJ]>"^]ܭaH4K!3\b1zCƐN\t(aB_s-4D':P  8 p9ۗAۆ}ں :ԣu6w۩j,+j{57,@qJt@?Q!xC R MG88Wzzg6ҩ5V+6Tr#wi7ĥk˞Yt\/4& "ks˨B*I,'e^|<E` sXCH endstream endobj 137 0 obj << /Length1 737 /Length2 32264 /Length3 0 /Length 32847 /Filter /FlateDecode >> stream xlf-\]]zʶmwSm۶.˶msΗ{g';k9J&'uV2330T$TTL p䢎@#gK;[1#g @h PY,LLpQ;{GKs g uk#SKKGUɅE$ lYZ Z*Iy5$hd Pt144:fv(;[Sarb7[W?lr qQFUQ)?N?RLfDX[Tv6.@G)/-eQ6I1M?F"lk l1[:IXM-?$4tMl=Ϯ=T4ivؙۚZښT,M]:rFΎ& ӿ7JD݋ @ϋ5qqt:74[]3 Jk/2T]b]A058q# `:b[(p4>M㥄ܷvM!\ BD:9cm5Pf-+VơU9ڰe+~eVZ-S G[2cRxe, pMk`QX`]pi%8)+JZ;(|wɺ &t84Yyͧ/(Gp![ŧVq3;Km`5pm/ɉ}/RrDԒ5Ol0p2ޙorsTsDڊʃdkzz.EY_~@*M^Fq)l|wr ⑰wLW0 D̹/&[# "0nS=\k7 s:uܖ14y,|VwCOrCxBٌuO}Y8VŐҀ{1Au啟!UsHʴoP=;4a|I(>$:OþdizLzB#mk]d1k}W-殁 <%{L}tt|ey?uHWon8nda1T#HX{9ё*ē2+G4E^Ilh2ܜG&F<03CO{r3P |"<̦(dI2DZ^sVE|~vۦ<GD']ۛPRN0PKF1 ِ0?"|FM=ܛǁ5tx``z 859 .f·:,TS;<&| xs5_stwC>_ Heq2Ozch?x} qv汄~R5Zkթj 7*R)i cHlG?~E/)0zdqMsΪ thA:=P,%(j?WQ^=XB?Z yXxIoG>ۢ.KrO= |mٟE."Zgt,lK|^JEr[6fü4#Alkm۟Y ^(N!x>G! U Iʴ$-do%oXxXĸX eg z\xķQ%t؍ >hO3f`#%cӶSH?'註kQRXͺ^Qѳ\8ς ,^9`\8z؛4Mx=_ E֫)/>gO:kqMQCp۾\S9lu,mq\ywWea ~{4c%0_Y\x@^eR%Z^ 2 /'DcÇ%gDHD-AOHqڸNQHvв+Vi<乎8,6=dpv!;yyI2 4y@0"03qn;%cf%~箤c]ѹ8bQ{F~6^}BSelhTYNc쒻>i9 *DXV=tnּ΂cSd ׇpE$%u8TcrNק&w2W~\Yo.DjR(jwgෙE.Pd#4&6kQo8~sCNEVPlF ?- NP,.z u&Zʕڊ7෨U$/m6=;tj2~⨪|HF"oՌc[%+S W0%gX>0\Ĥ`27IWMsEomgJ`<흽%'9ǁ?ЌDЄqj.}}Z\xKVۋ 3-1LxuE[4]틃6˝5N =TƩݓxN }M  b~`E𬢇b-ı~f̟MeKnSݯ ƪ-@ŷa3/x,@6 PZxNlOKLhhkt 7(g J8[M.?$w՚jK;XR4ݕgs7%߾vMD}2˰W/,og7 @ٞ6v2;JC<yP!|%-8_XQ91K& C0sɗ fP`2c4CVjޏ∪ƽd\-j@z4Dn<{R'ׁ7 6><9OK`=I^ѫMmC` $4{|ǝLYĬ[U~i=yʼnY*I|<[yJIl^L4NŢ'ϛM^jxZM,6oٱI+""n")@S4KZo3:'Ǚg| s(qf% zBIe$< ֢1b0S϶Xp_PRB,cA@fփ=9 Ss)E=POy+‹Yd HBg/cfr =$Vp8ΙS8t/Qz"N{:h&#gՓ[yڴ<F.UJlFj$%Ҕ:pk1?r e9!+fKob7igЈ7u 8?( #ؤLL~ȀhQ~۱u}A. ~ff?>!xHm${u(hJM&1}̤2L=rdPGCg<ݱ蛂'yvwqׇfnwHN ft -]8,n4k#'*yw)Iz07wzHzS爫p@m{-0;KZDwzȏjN79 Kuހ-vƔ*P\"H pFD$)zR,c泺( ki`}ffI+HW3{]8Fh0κe` P"5d|ݺ,"]n7E ,Y.4=upR4nŃ d6XЃ i3{S_HC[YҖiqPϳ;5hMM'/̯T"HŊ{ bN#QHhB咙=i P(eH֕iwauge0ٹB&xr87 $Hc6w&J39'pْMs G8݃O٥"$U}u,s0I!*R(ɴAR,z3`=RŲ@"PL}up?;l'*B!sִVhKi4g^L/:In ]\:7Cd[A_2N] ɳ  8T}!p_ o#m{G.̏`šp ad>H%e,Q݄;M_t#{0D Z-EQ] >ZߥnC'<=mhvi7ӦwOnKne]PN¿&#<@Pf".hάp gu+—܏$7:k[gZ*/,<V~e PnHɱ̬b c/rw\?;HgI6}6kw S)5ֱ=t8h a2ǂ0OYR %g0Z$|!Ӟ#ܛ9`G@cUS2gn$3B] vLg'4\"dvFNPW8tlCjgj#viR- .;~5\$^YEn;ͽNaVQľ=sag2[uIoTؾ0k$6њӑbSV`~HzAǵ S=2ngr6g[1 VmZ3ޥ_q"+,֭:pUˎah(ώLOTA/3(7ȋ Iz]v:Ogx C"T;ow46"xu .9 vJTq(8#=J܌0GPVe&IRrSSk2~ՎieV;#m iOs1zg`9Pvo~LGB]3VZտI*ezk:Z;\# =FqR#Һ5.vd¨E(Bғ7Sou}Yy; .no ml&;ӒAe (q. ӗuC!/r+O&\pMϥD wYD i _3 쬹"28t wVtb~^ﲖ?/+#cu呹9l,8wunNTgR^7) 8;PHiע!;iЇ1IڛH!lcEJHk ;:7'G5(C]8S|Ov\s{'Na+;0K[bEͪW)A}>yʫHٿOY(g>Y[Yw"km?ZURS ) e EYG-j5fϭycF3QM1|,EҧHI ͝r%36'l{:͓-|aDTJEfө̉.DfhXVLԶA=]#P͈|Xf͂hZcf;>>uy <ٞS ~eGVp>;rNnB*{8"gb`B.0uw[u }7c/Xz%c_ J)Z@MQ{kFTa ;>0KWi?V == g P,K;65ٺpl~q1okڴ\M/nE|?ۀڼ&nrs^mhUUΜvRmqY<"BFAXVh'ҟj]Gߏ۱6(Lj M;ܷViKp!3`;ГJq dM.C#+hHLQ[vk+ܘIUn׏C8R0*4y+*~'o٭E3pƗo!'MM@HnXmpEW+ uFz(N yܛE>תE 1(|]z&ZXS UHqM5%W3֬ing֘EнTm^3H+iǰҒe.Pϫ\#Ta9{X C r_vPyYp7jOycGe2QC52s5C_s?{9KoCd|mq~P%g)qR0(p'"f5qK6 s] !%zPkEU^mʱߏ1GS= 0fID0-L\ȎIgѣ"?.4} ^dj A* x NaVwr,]l"fX3y֫!r%_mZ.  5X~ЇU:U*sź[MX]2g9ر8dc#_5ݽ̸c̀5UGmSOO"af 3'ϳZ {Mҟv%S4A?J8z{+Rl +48A $2"ՇWrď_F|nlE:^`WK:!S{\S]ԄT66HQO׎w x{LQnymCI^f l Dr!Ϧ!nMSڃ*5:UίG kx%uRh6y8XFž.i%J\"$7;zu^)&ʩx2Y~[9NQ2bF 6CU-$g^!!gbB!7g>y:O> kw\a`,қZL=c ܚI<H/GoLK9~)cOc3_~8f~U6#Ե ~gt?&/5"զ{>IN՜ԍk >:WY.m($dLOgJ1S OTؗQB~ו ΅? 'VKZѯ8d]k ªfzoޥr=qRsڄj1:"$<nZ[RM&&#.pKkS)1ϠZys, iSli\~AcQ'!ԧj!`Rlךց$:Muxs}u=@\YqSJmUK#pWJ*|߬񐬺hJ]Ы[>#VtRR;gvQYϩ `k}oFlcݻ֨T B33?{D ? Ik>|`1&5 5|٫g@Խ6?ΤuT^ #D(.TeLο/5Rm1̑ 8.xj]ִ3wʍi/K 7o|%2r]+,._MinP2 ${`9i'7P}?aNfo25^)4ΔI_CF[n\0=u*QuK`A܋s1v n_/Uu*GTc0ߝ`o˶wI&7b{*s5!70 O1'Etr0cE`|$G,|JR48jLpHuyt\a2zߏء)<x] ڊ(r4wn ](E)<ͬ24ВZQ}Tޯ!ojK oXfV9o#?řQ4dIYO죪 z85nDݵ~,e=Wb IGAp:"C%,01^%ؤ6E e|#}M ].D:KxQ/}L-ks¬2x(x`%g%pqT_Y&@ixP4 m]hVH.T@s[GeR jV?;(iɧ5rԕ"q+&84X=~ rG) BNМaaLxmTR  cz9ZLW4qȖ=jd2{Cy,2MHKC =MuגTyg2Ů'p Dܹ[Ku=^C:!/ViB 7v\PRN*O`F&vHE׽>ajp[a\+~ Ďr]ʼnFͧDO榝P'l#0civ]_i8R2 ]0ӄq}K vib"6h#P3y8ѺN=/Y=X(7t6Hic˧E%exG'SWKvpu8L,"t RQ -:B[U:)13ڏ# ىO_AolۋIG۩C1toR3#htqjE͢lV0؈ڳ/MP JY|6=zj__!= - O4mqYdZa6FD7FmӢU[RHF:(7Տw2F&XM ^ǎ۩/`ojvFe d>1:Zc~!Rrs@PYh@gtUAxF##)e6t2cAyo^Jvo{JyKV'p5ez| v&y:왷3Wsiw+q׾ӡ "Xl#*i=uAMa8Sx4ՌJ4 UHaSO9ǵJ(vJzm-AS3_G+R^+߭;͓ع?_b꾴97J%j_;C%gPz.@*n*dx7|Z7Ĥ gkZR31VPo&ӵ*b)OI#]$3ڠ xX;N#MiɝQY ) hoqO,괎t.o*҄GRFx6~Om'.A;`t> ޵@?q{q )e dhry"N> +|Z7Jxd,\Om,\.8ob Y4nv|d#9Gr^5V42}r[8{GS3<$Au{USsKxx*xl%x\ W}kQ5fp!xqat6:e o\- Qg;=kUЀ9w6E^QBX&7,_E!ODMuŁ*ZP#XII-#eb]k@{nuOUyGۨ%Qك>Ey6Br6в"Yl;暍(qg>9ʗbxJI0j@|s.}1PeB51awPc ;6\3^p>0b"Щ |Sb):m9wodtfKhmz.pdpm xƫ %fۓ+ؾ"N&Yk*ϽPwGuɓtcb"- UpSsQ:4DЄulEsxv^ϓ"f=C8=vܷX@,IE_q$ ^cX ՞h{1r$bA[Rm#-ظR8>#/Y(Z08?E 4:}%옐mjH35e8 d|` oxB"nSrK.H/CFQUTpŞU}|%,%MK$#S^QvH{}z}!+ ΁PǛ-ɮ1Q+$ZADX \ޮX/K&"`۾^YEXnKeOien)F&I9CIJfs~ͥ} s#(u=B;b@CƗSm_@Im* H`j3I#I,H:#Ǫ!yFjk#2ա @l%f Rm< 1I4XAԛVX /B] lx_pO!e釗K5DF|.TYȪ_Z5ȶ֞.D2V)K]~OIO. MVT1P!J 2 &ڸkmv$>m&Œxz#g͡ W33Jm$/zIz6?Y-q"ĉ,k D~qU!W7[jKm23w]SJ0 j'؂-xqN5CEt57{4ϐo^NMC<$Ta8$i*^i%/A⻺J)h9 7G6Gk4с}p= Z+!ohnyY)~D` bM6 o.DxʮXJOM2hw@r ݓ!z,lǏ"bgPrx8X9-yy/ܖҼ67t󋒮}Oq8.;DK݈ۘ]n5!.z8 Z+zŞ%Fd%9ﵔ26+6@}пd 3&= v%%+2?O)p@S(LѵΎgA$3ē'鷋hX?򸯲VߏZWcrTǸtՇ_&d/YtL@"SHq2AE$C-ΦŊ}b뜾X+S@,=3AM71bY75߾Iqľm,P x KqBITiYb!AHҜ!A4fZJ*p/5&Dgm.89AtA`QhP"DNpAvuO̡ 1G( \҉-՟כ_U>18/[C-e9ex^^ƚ&}Yqj(,i7]! >nVB>TpuuWTrMУ|b-& I7yw?m? 2ihP7}3;G Ϥ #)S1a.'O_ 䆉5o?F1l\9$Fa$^bkǷyPdQε^Rh%nFri5dM- ɵ ;6<:k 8= h݈ylr,">JbCޛp UtWW})^Rűpkĝ!(G{gH1pagF !cݻ?^A!J68jmsl1WjnC۫PED@E.RhØI43."tӷ ,Wm`NnBu_aCxJw]b62iax2SPr,P ^JCP&} 9w m”፭Ru]T=19N}BO3EW8T#Yg@)2"C?ɞGBs睑 &B*j5mPD[ 90RaG"BJj\ %!+}irB[6JLɒqҦO^4_n :&GN~T0 {Q ,^j:̳G׊>?sw"%WF4$Hѧ>tKKt?= cʹA2CJ0/Rn)݁˘4K>^틾r8dU:dQ1kcSKy(}?KeJv9DhօLF`~r/_@:q %cT_}_OT*g*坞hGSf=59|C*55S8mB`婅d;~s]Y x'qo׌ǞB͈-\4#eB`@_A v*C\Mq <:(ޟP}FN}g]i Iu=~t?ݻIOp~84}5dHJ͊,H{6-@.bP[rUY+VHգ~[)B,5LGaҟI)tr%Es >ߦ]2CIHÑW-9A~=F\G6?9j6E3lLZb~yO .}[ =/=/]ž:u8we.9PZ/Cƽՠc抲C+7Я6_ YByKMq$N"YeqalBO}.BA:AB.VdNY0Z85W ARg#"-舭3Ho[ RԜ8ˎl/D+O1z jۑEj)`mO<åtܥU^DΆ|}^׷; = ʠsNU`1 ٠÷#5>a"&%5|k_?^8A\ҬW<̱kd[@^>XHMI J$/@wFo9R e$8_(%s7srD\|q,̡C-f)4^. Ag0myR?BXV9qae'^:/Bb*Ugx(A9qM뛿q;L>љW* ̉0;:iw-`ʺ?®tn26r'vq r0`x $@Nh9 {L,Cc{u%.Rq9B"4xΒ MFàKx'Q*&]#DdAަ(QsLj$ fSET_d8י3 MTۚ '$99j 8`lr.辁SA὾`&L~Ka,|n0qtn4Vo6vLC<.g12O3&Ttx勗>}pj0:HȀ^CaeQw<`I遊Waz]R]V/V]jy-H TkDs2ʩAk{o3oU*&! Uν f4qWb*]8~m;ib:΄D; ~,0cP  =.\o!gxc둴 1s4/f8}|:7{?4Z[z) }ƵQ$5Q.9pæN?QcG#:\%Ew;YFX|gÒ_;@#N EyLquHo=US(B4<5E-JMҽ\Z`xnn7Pzo)#Hf~qbZ)*{ס: Hh5x4ˆ7+7ͭxjXq:ھXm=|G7kEb+;ΐW ^2oKFC_yjl^l1+`] ^d䄸IOH=a|OuIK6]cKRCv\aVX}M Rtq,+H!1%}w+W&_ ʞUE: 'r |u~vIej(\ [,BDt,own]. :HMr8x(C\dOb6/2f0Ξ9 lX޸Fbs+4W 4,tAl,9RpvٲK?7o|i_ni~DرNu]lܡMw aL3$P4.},ՍdXӑ("̪c!prWVj{lo˝v ;`4Я@4^S]5?l_sPNaI0ZFg-Zn Gq$oe&ӹ:]u>c__Z'7pW6l5h.z<{d\4%Qlť] y6*qL85ֲG'yLyT3i.-ǰ? J@Fc ɼ)Jj:p(Il x?Q:c a6W \8RV^W7Ywiv`y>H4SȽ:=}cV!^s7SSd | sʺ~l~Dg4cqzgЄY"[ZTrE -♈y{4߯O9љAJZuQIm}zKu:i. |oCN9뙟ۄyKMYu:pA.8&'] ~s4u1 u pqxEKEc-[j\W|Y (!\Ƕ7bs{RXѽ3fSO"GB'*STgōh]lnEÏV RpRzm-\-s$+q%w["CBWm ;uZL-?k6@ΏVS<8hU(˦ *VK͔dm ֌(&N/}5(9f; )X](A*#*Ycƽ"L:"˱-ͧhYuT,qջkGX +s 2:X=nd,d%+ $+*L;SLğF qFKrX_WBCzHC!r4E$H"x7  >'_vTkg lXYG 4yt[!NjSU0ƿە{r㋃b/!ȹ<wXLEE^%|_ޕ, 1n1ڜ ˁ<ʙu6/Y;<9!5]8cwEhXzm Nj0=e.؈p(αfQIT# C\u0W[@nb*N.=ZBg%;u0t׬%rߌOx`)b+7A1QXo&tt 嘢́o9+_}2v#ĜݾnW Xh "2T˹`zH#5+SR˜S*Feđa`OE 7lnsgq93HVXa]JӲfr4wɰK$ \e{;]Μ58'dD7FuOqCݏ+A茗eĶPs(,TL'ޚ QmrVDO^8ۉsC&N2#>xP<} ;Oc _&5ɱ#5J*d2MO0XƽUŐVF: j\##kIF ^RgLrHV,戃+cG`181Gx5ftEluPKF0~Đ&>W"{{IH^&wČ`s%ӳy ީ= ,ю׹xCl+άZcnw<:a%-7S7/Jvs|;sz4 S!_6!pH]}]FvɡIdO8A, +?h`~V7h\ʼnjҤ(`HIU}5G=k4l{/YӒfg2 ,¡\N,K#IpR~3vfu@$ަېe V !Tp/_W巐ñrdSϯ2p'=t+]`ǥ>I!Hg-粄MvOԳNܯ͑#qX%ɩYv$ēx,l|g+(|{4~,t { $ )Sn~/q) ?{Y > rWBӛn]KҁدeI6֘l`$X}F\5+FqcI/I_"¶Ο)+Yz~6a.S9{8MXΝG yTO` 5lgɚe'8Ѧì;=/)8XiaFc^Ժt֩VaSxuAnNaC;|2 X SވE.4~r | xpiaau!''.IH- |h~ഺ-$s'ɹwo%|&0ԩ]3Q0bm(BҢr4Ys7 MNi[+73NZ_Fpȱ}"'?+4S QȦZpr=3#0ox5;ңDbYគt:lq4^p{T)VG&[5clP+1|=DcnE"F䛜=B|Q,+|+LƯ(-a X bxZ@_#&WosHZ1HVH9{dHv:;Mȳq6c]=N>ݮ ;crJ/{,gA:CU&_xZA׋ u@DUqP2Wm_%CDs6 0 smm8U,RTba궎? A/tu Ύtb.n8HmTҫ%v˞0>:WUT֜(m3̖inM`uڥMFy)}/ϟ?bRloddaڕ${Ktsr9E{ǖmp\.W9B><7[q&1k5!,PEկp=@fvr ]q8b-3*JT?LR˗ T (@ S%Q"T6 K'A^I/Dd *2tp]t`ɌL*>ǟkQdR2{۴IeȆѕ3IbC3F %\_(qM6v{ydON:~cTB'uBjMHFhk& 8`y+,YrrCcOlCvA&m&, P@mՀE'@Aٕ95#<t4j+c%'>4 9ւ*\̇ SBκZްy,8duK ?ƌrzžF46ɓ: 'zh./g DǦt F(ckAɋ,BI"Ώ,ĥIOd#Id(.9x8378K5KB QrVqO*v+j ~IiuRD;(mZA!̚4XdRi[&ˤK+{GE=ܮ|9MpZ%_ uWLj/{,,mR=J\uZ{~< ( . oWEy>W-\B2k+ު`[Z]ߐ䂋{ETQٺQ@H~O&PIf%R:,Ž P '2ds44U,rP,MK ՑJa,!n#֕r4*Fz6tӽpĆep fH#K_JF%[מ7qJ?nغGl=exȿKš7w!vSSQ);D?d5vyY|捷\ȬE캟jgӲvNs@Oa9sZ =Q-E-c3 w#0_hLEsCqLtzFC>4'd[F˼Zɦ&4޻xXPRXgC 'J>Ϙ!uH!M !]pb Ia,0}_!|Ѧ#1׭JD^B{ʧC䮱6i>x8dv1AߣYF3:AMLCF?8&G]Ҿ#Qcv+%ٍ[@ T@d!LU+X1}ڰK 3h%jա31B-z)J}O"uݷ>Yh/=^.^gpzK+\F.-u"[JqSة\B ⇹3Hb[e6ɞ8bVX >W{0ًqXIY7FOy&KSWx[ڭ^&UCc9D, nzP]M~o6H a]ƯOHLi@,C&,MXVY7pB|0GElF]/C}˴FBaP!7$G̢@at,4471mayl:UP+GQ5Q>o8IFb8a9e Z"BEOċdf`кl(Qʾ Zi#DdW}張Pw;K^8fW(K208Rx3{]5*} $s|O֭DfMad=|H@]r.e0Sn7!$ 5UO'|0]91y4юE@PίDHzvs -Sqsn>PacIf,ڜܶq+~$ֻk+}B' ESH6/oqX(#i7d,ZJWQ pd,C?| E6 zS@.Bb)ZgȄ,X; i^KaN$[z3M-Cq_JH49w=,̭XGG̷>?*Ӆf˶QwHA;ܒc'ٯ=L C7Ć;\1b$-)+E|^v+>O1'㭢~ZirRRvufz{wgC̈+?Qh]v(RysjeeIv'^ /{#aF.!T"rusI(n>J׋Q95C7`Tqʚ&t xOi/||ŷO6nk5Ӈ|׸[ >yO%5q"s#ZZK3~jV*,fx9ǁtvǶ:}zYhibF, PityϘoUd5g3f@{P|AWKMO.K~XaDTnm=j"h2(Vz MYZ|Sɱ@6nfvv&?6t+k0glMBVrχ hv2PX<{+|YЩ7*oU&-T\u?s!V& Zt4*ST%G-^O=;Q vUeq u *-Gtq{2cY`߱oN4D:RYҤ<]bpΨ``biLrM6/k[ \ٚݩ&RE?SmL/> (PneHGMH;ރ'un *8ξgaN%CE2Uclڱc|(rq”77@b(dwa`N\F7P16փ _ rp1h/ YaVK=q`&dgWjE6.fqT^Qʖd^ sgiE`m <:aG aZ/èZ(3N Iu9Ёdo[b+@Y/'?VRT{ ~_&F ,GGz4 ,04cb4j,XH+ @\b#;70@wZ@ %Ji6UM XN1,hV1K.QX:[훎B$Y-es!>GNJ7p'r<{чZ Ǭ͜MKF0m>bd}hRЫsb@ ˋM@Ոq=;Eg%^oVۘ@\iSUD̵v ~5L[qy3@h%|zCMI:v9]U /^gwk15{nat?>Fkbo<̘ČE%#;T|HuIO)Wd`jϴ:7 9 ħc> ڞKyXx[Aźp/p//y8&$f} GmUi;223h-^7 Kd9XØdحt rN23c,RĖm>.W~ T:_w6]2*s&\z:X/ T3ohLBj \($e:i oJ-o*pVI|*~rMQv$dF$q]:*gfE2夽9?䌕lsb.yk֍b(w2Ü䮵8EIŌ s<5oau9=r|[j;ɋ)q^xwf]{_:[K_†9TJDz u2&B73` ZFhӢ)z\#8AU X%@@O-[= "aKȣW ,M8S@ MKA4y;/G(O!D|a8CIԱs,y̿AC [+`D,1Z!ÛyH Vpˇ2tQm,ћ4] 'W<%egRnzG=LolQլ,w0͢@B0Xy>|, \-a'L w\J#~p^q g;Pװ*gW?˷PΕ h2⇡@i  $\O;PzL1sgF~՛_e.[{Uoma"zDw;Bd:Tr:fMviJؤmQf仾KZɱ)1*p'mu4&J6>LL֚Gd0CR5R.+~JdQx6> WnF.yD(X?.C^ \Ʌ@3\ ZX*T#o ٚEI*jN?m WIUT'KjQi¼&ԬdH8][oȽAD?.knhGA#B2hI^C_QOg!I]O":zԉ_MnާX_eӴ{T~dP/,;QvӼ`C^B?>ve!oT.Fd Kv6*±8dz 1޽{4yi":fVj)@^ n e$R1:MK0cg -lbzTo#or/wxj6ϣMZ1^&xl,}an}wb?4J#,B4`ZHq; &Oq2Vq-+~pq3gr&Io[e8ñN.$mQ'#5D]&&:+La{]j`K6m T:55.;mIA!a@/bANY tV#1tu24Ui hҥ`}gA3#tf4ϋ$ 1Tg 8ySM\%!LuVÛĉ4hBŰ7ӏ}`"z,D>?>vQ^ GJ`Q+KdEG`iOCNVd4t-$-;%kI{gx_[R-kˊRB=OTRDM_1sλ; :n -l(towݼA%|>]z=r5)Cp|mPݚL^bnR e7ZG%^ g#KfM^7i.S>z6ֱ-> JK`*-x-I[I(("#wqJeYە1cLd4C/$)dٝQ ]a9G~.SS 嚅A<*)":&@Ee+!k'4Lٵu$%FZ8 U L-Wff4)1EգUN@&v̈́vS{ƾi;|2O,[ć6969(:roL+K#`T!c_leVE/s8ty@D/"f#d M9.y/#EUjpdC])S΂-:p 2m͉lH!Hjp7XJn}yH9cOpf#Don]πFn? (D[>]$yO,[ x5mh\*}㘨0dl@ !Χ8L<޵J^å 2/QFki v?/1U@i듄Y xŹAp﷘7DwKO4Cd2ruUs{06,UE&݂7ܣQy1e3.JIϿeu2͌uGRA9)sxTq1$=\rfk3=D&4!|apțL^J̡7Q)n'EJ@ "Y0)ngA>owGKe HQ+SjmurGDzpSyK,[YʷYqh9w. J͆[yϽS\E0tTC(mq{h DSBތUwh T7֢^B19LYB+PY O.clnݩ' |{GB~x8TK>1L+ <+lxN.CUb }@:BȞ,ĨX y ]xa|\v毈Ʉ̮LLIgo5JC25;k͢% 06j@;mE@~Z޷v-faNNЋAts=)_dƪ<$pޯ%(ңdS̷k?I[Z8sWzt[Нey "ߙ. pM|j&4J5$:ePw5+%--2YO 羳/ Q pp~s& -)CIġUMht[$˶[v9=`1 R&i̬r-r>tig0'/}"GEvAy,.y~i46# p*%S<5vcPmJ,͟>- q88]hLE]݅bY,c[]l$WAQX4^hCT9X˦`Okt۱JvY,昂2cRha]cfy@[9Yp?2v`جY#1yשCi⬍+vG?D/HgorO:%ڥ+nj|3{y,1CGezĆq"K ZFbmlpáD!|%x8+/la/|X c{FlVa6`BsHe5`?R~yϿ*Kv/> `KJ`<K5tN Di鯄y\y>*_['\'"t8<˷O><ݹ{c;-Yw4ɬ}@0;T?v"~tU3J(̗I{ۻՒ5 6  n'ʸ!EiJ2$˰Z5P۾Rzt ^#_ Va8a|>EHqZ #E[^Td&MnLާuޥKC$si2ԟFCi&ezp:h?ocgP08corBJlP|%m'Y!uLn=AO`_quYQ%qv|H_^Mh4%"9KF <m*Ozp?ϻ:LwݿByl)h9෠8~$Y9"I)mn# $J%$9؆E&"U na4O& #.GY>o5 ʰMŲLTuT\7i'tt-g DRU@Z 3 Y>0eU)L^By`Q 4DQQK$P<'(GU0%Wnj9*TJN 59T*Jt.6)޷yN>A%0.uzu;ռТ_ O$bXGUt+޼ '>rKϣI@RZ9gpg 55$jP\Oc(h_Wf^ Tg-xƿSZCON+[J1hȴbB2ğJ8QHBwwv})R.UiD]Ш)gӠԂ;;- ]#Cm .̵ӺZ*:ydlþ)s%"o5):gsk2ZO|~1o|YāM0)gL"V!3ܫ7ʝ~jgQ,tyE;PɬT*xmm.c)dni;,ìG- $hwj^-lTZ%%B\N]UGPoh<,+|w_HEg&+$I\|-NN:ܫ_])Ӫ޶#0 8GO*%Î,U馮 ?UyY9Si8v#kBM„Qzre/'Ǯ+i~'(PNӕ8((cEЙ_:IDD48 p)2iE!u۹3z.;y %cIekI53f*pgH'b[4|'wx J% 1#:$l1omq)V:${αe<"PLis` endstream endobj 139 0 obj << /Length1 726 /Length2 18610 /Length3 0 /Length 19180 /Filter /FlateDecode >> stream xlycp͖vlyb;ٱm۶m۶m۶m;1wΙ9SSg^Un2"1{;OS&:&zF.$###LNŔ njP6u01`N.Jcj6&N5{{7Kc ++?MM.3KS8R\N njgdhPp54X9R6Vv&3s3ur'03'{[ @TAE`hgg3?hScʎ?x<-01L,]Fv0 ś=׿&' P!)R kobdt1'Zx7\XYmt05Qtp3C]߻#kjbjILa}5uI_2 K*K 373(è r+Z;ݿte ],=ڌU$(!!{o:N6 3 5vur2s?f}ޘ;*-Ox fa@f xuVrDA>ЈwjW0dz&(Bw絔ܯn]1BL X6%sc=Hz5;NʱY)Ơki'aϓ8.J7M-҂Ehэ:HxA-EQeQ&ܥ+Kw3ĉ9CMu63KiؒԾ,ٙ!7J ێ ӝ |\&ZR0v:QooOU(Xy"6h[CUqPWz| >3uDÀƄDzR^Q24t8*eVz, =`Frħ6аq'GcklW=Na!=bj:3Tv!=7 i$¶lվ}Tyk CL|lQA q|s + *6["tB~W s&`X ]L~~U9F' P* Pyb"sɢU4Jo_ؼ9gI;ި) }qa^)G A-Я{)Y+^Hd"Ȟ Mx|RZ/h8Cr /H% I b1HpId FT4=kHM&X5;;`:Y&wOMq6TQ *'+tN"(ƎL@-TU|폌~,JUl@M_w^Bq׮[u@QRF."˨Jť QLk$a}BZ!#\ Y"Ho= DŽ R>u1[y۴o3D#0Csu1kIE<:? #8):|8KB&Ed<IBYf&TIũ֗>1Zd0Ӫ? WU*6hrB=КN4C{m~?r&ӏm,oʶ[Ǝ _!`Xw~i[u|9⥹趇F/@DLk L⁅#߂!|Z*Q\J[様iǓ 2?dh#.FqG~PqdOp~I}B3g)*؟7y{) |wh0߳cEC秤W➯Ǡ1E@h@s('CZh&''\opn_WN>jo'²($AʖuҎr3{*wџ22NR6x~b՜cC漁;{,j!$VQ:Ra&l$Tw7ҥl|/h#ppyp]ai| , g-unCSRa zV|Y =؎_q U VWSZ0T}儉ba|53k0/>jͼ=3G9Q05!9xDZ*U"ޭr>^*iˈ_:* 26e,.uhJb!֜$xlpI,/X||P04|fUyhH7u{Uk FK#wM]T laMr$fӊP<@%nMT]S`?O}_Rތ-A֊F )/M-]:)WLbTYC1X薲 Ꝏ\Csi5 څokگU^L7XQ +Tsgˮzpq@ք ˗͙H7D+WBu+DE͑f zڤ;P!@q+p=ֽEcҞ%BZ_5KFO.AoBnK6V@M$ټkqi%t.0l/?|/ Y6AܨRdEn³J.٥@I*d\ވ|_"ǿ \_ThN vuN=#'"_n7.od{hSY#eRdV1npŖ'WmiUMd*F4S=SCL4GNﺘm"I_QG%k!`\F3S8zw`?|! _6>K !B@qIdH1$VBvZ {g}Ҷh"l[F 2C[.>zstB̩*]/fE.N]M"`zkwGOh͗ZBBBZ=fPӞaUOKsI,{SۛPC3פ]]$>s%\:/N3mܤYri*<1~R_ܣSQr}P^?wTE8:Ap;f<Ầͷde J  f:B:md;a~M%UWjIR6a5FTg..ܱScnu;:,wxY'i8 @ p}k -:/3&aO zc9_aÃֆa蘑-®f`w5Vh%%{(̾FFJ71i0 [E$t!)3*sSꔆp4(zmu:a.`5EcmX$l콣AJy*l$a d+DʱOd+_y]ͪez^Z]-,$TSl$aj76g9;bLnE,ڡgQ̊=xfLxnq#<&6tHiӪ,x_{0%6}~cP%nŷiqcF{֌]{ o946]5&̐g1x;ԝrܜ}z;0 t+UO'7W oX7!G*v|@ ^>Oj*s{k5 ]yȋ/DoI<"G̏@Sv^m4-Rak&5+N;*R&_W?n{8Oqُ ?5evˣD:oQ#r٠׉:;V\Z7bijNCmd%QXA_|A;8=__cW ל-z=[LXSZDȜe>M[iF'nEyN*(w4,ZMKzp@1E ]>g}*fLD& f%yi{br͉c,+KT ̩獦Kܚ rTzP}+L%[0n,)k;p%u>vD,ظsu|%z.rZ-.Ź~+:+u$w2kݨ*(/"ehX`t+-)Zj7Ϥr2ڶc 6R#XR%xrӐoͲd[=8;>4z kr&ϼi骁WOU\T/XNOf;Zձ-h"iP 6l={(g4pyMܒe5 5Nz)b-\{][&,,Lyϣ*슉-CwJ˚I vi@,]cZ9F[rʘn\ [6 nqh5;퀏Ia AS?F3{Nٮ=TI[SRϤT@~R!x[~=KݫEKiA/,dj$.I;|gĚ?Ȥ4yƢ2Wܥ\+t'ѝτؒ0rA=Oht䁞e0n*GOٸN[1m)IͺJV&Kb_ͨH$H1zFe5KB>TSJf֨U## ɞIv"4$Y\AA46~NgYKo rEӯ RMdF*gsWAas]HMN;AC5ML) g!EDG#Y<^u*29o9}'~5RN%RuԈ<"fj S[X/0ŨY>5ir\ kS3;* n@~qLK}mV "Ɗw KV<[;ZL7{6`8kt~EH•lP? T˟3Ǹ  YƳ[_⦎x Ӈ 8A+^'=Ba,Pb']ɾ tnkway_no] C^B.'9yxW+_i`.Rp UAN)1cYBӦ~\/,X<ngPQ = 76~nϚp >*rA.V*THsђoԯ/"( w˦~b;^?iɖfz{NoHZ}"a]cmr# YLnHeMv_Dm)z4)9zűeFJ38Z?G5TU7R3c L|8.f9ӕ.55)hSqaEv B=ÕSҰ/(PO P2sNIwpҙ ]Jl05P glMWDD$ `kJBQ;k(sK.UMa"F.iѪЧ>]KB`&to|?--Abd)(.%eͰ['˽umךwe:\5c{S(}Z/=OjgUGAO]M 7mZABr 9=΍ J[q_ӻcdw!ȅIw\ܬ)/8Vլ(9 JK6Q*džy{"͍w@'luBdfuzû|)Ejh{ڐ\LpꑇiE 05}eӅ9x'{S 0UxS+F0uٞ(tIu9k¹N=<1 ~p4k;N.GF)^&(lj"=g[eM*bJz-J%WQCāPEcU}AOUW 4eGtthE:Da4p+t4[F-.X~@?*@6k!:dҰ&19t;% 37͞<ӠF6-!A$~U K]?!م<#⸙#/x6- p*-3 9 .ElaCuM"Z@moujoc 6M6y{ I:|Q/h!ȂqЛ@§vL|&M[hK-hJK"S`ku(vJ4(R8 PrZz2i·c"bQe%Fbh,aS7t znMĨdX9_<ˁ^Z >9c^u1{rxF]x5|C>=%bKk7ihtfőT4qg{O qpB}&fd f`ٹ#ˬ*WB!cm|^Yp%2#9/We˝u- R-y HHnw o%>TŬ_/<3Ā.̠ ≲ 0yۋWy۟$]5^ Ŀ pۥsv [dN ؘ//S؄U&HdZ(rތGJRo)X7L[͟p׼kCUZk&E5q.,\éUt֬$/ PQej\N%/,w7LPgP.quTmN'( yjФi|L}tI~H_n]v)C @RՎ4 k47Gbdl961^ļ0%H8|z49'^o!˔Ǵ {MLĖ{11bޱE#:[qίNf+tG&c__5˜"^0칰{1r sHU7o0W> =-߬H[Gu:gV'ߥ0~p7& eY—\uſIX/_#RC"ʗ3.P/| Eq|}h4c9ZB~ DdPL}dcөe*9 II')A^_|dZs_MLT#4&L5} 9r\ȹc]@tvo?#;eDwiT0M9˵S,8BHh}#)1Jh9Ń0+}}.u՜Lr;0_"=N 4ucs4 D9E#p:h [ pY|>[@I}#Tn-@؀XI "I 5AMPUmCfv>w鮊eOH`׀p{W˷m;q!d="Je.N~ 2u7̜sʻy Zu-HC-D֦?JlX!dB 񱭪;|H!WqZ@d[Z* T!$Y"+3Kk>C Lƙ[ n6srZpl?0 Jaef,A-BADْ xMfZ Xge[c5]=Zl`#]T#f/޵rKU݀vd"wwVfCJ1M6cޏ6YYrxoJFGݫ]((G.?Z)>#H38nǚo5zY Ԉ.VH-?dG;xݒu=f|LI1XqE~QZHa7VyWחXs'| . +q' OB%+:҈9sr 5F,0X(i \h @e.٩a ?vαtyhI$mcex)&a̘Of\%- ~g`[ӑ hV7fND0;6I#rGDk_gL ?-ವ/VddCy%&-_Fr6n#Gfj鐘&$_\fOwR<6/CxxAF#]Z b2 РBZ ~P(oo" DLG 5wv'7U Tk΢W=٨Й'x{]-7"2C;#ھrcӕ9"21H*$2}J&Vg+VT, psh%b[ KC {+]HP=x Pu ZZyͧdϩNgqqb,lnE'ƾucLbS+F8rDʻF`eɯO&mP'Ԭ0y[R+0@\@ۋsFT4UOyA3)K\Y4u_h>ʗAwc y$;il~^`{ut-$x !ҋgPZ ᾒF2?s(O=3VWtIޓP\ŽU7@j/ wf˝f˲ / 0Um+~=k=Ū܂^+/P [$WJW 4VڱYǝ] "/4bNU)o-ԊTkXSea Oi:cCv ϱ8)b.la4'h|1jS[Dv :ǿ1¯KUsj,oRc'8"VZ''W=NG+J*Q\/eLAE S4NߛV fD)Yv@Pz[z29FoHpj.abA+__vS#=4qH;u In lVu$b jB*]ۤo.ZA~ֺ|[s{8η\ݾ{aC}eMLskm,_\`ܽ eo G[?]7Tq:f2-U=^Gy|.~sgM2"8HOG<װ*e*%|?Odrd]ݔjJAc\Qs ̑.:'PDZFy?Ti=:%C"ڦ$Sv;IBAlzjm +]k|WnfuIJ I3#4F~\/̼mgT6|iIc'pY٫\ޠ Ɇ!uvG6E90kvAuꐲ G[-aػwRXTVAӺ=/zu -03>Fv(#z0`8=1 nn+PR(Fӧe1@ʇ$M`'g]!z`cBtrMzN(dV=r`X ;&!0D#E\ٙ1i#:aÃOI *='7>Z*e84<5BpN<ͻ,~O\4lh/ x)~ _l\_.g*,}xcL}NHζ!?r\|IX6)kf;anILJ(DPMCRou C?jD/4 䪬PPi:#Wu׻tR1Y7$8c"{*fpa1S#xm&η`&vבnY%|{ 5Ǩ2 rL"1h_Yz-q(,.%Bjatg AptA P?5D~E”x2 xᜋv|(4"~ 'bWXo4aS2:v] ܜt|ve:#GRFTߊ{<8V"p*,]RVBEzKq :coDEX0U ^CM0+ %~'{6C+?) uIbщwcwM^g17>Pb^+6^k8T5}ծ sOɋo{ܠbo2pb$sx>*^)t׏x%F9Yo i(! hO)9)g -,v#6 K%@6  SVֹ\W./y66&o#3'-u$䔑X"j wӤ i*@_f *+/Z|g{ 0yJ 2 |lO`)ufWսr9J0)~ٓ!5\ $ͷ܃e+cሆWT Bx|-;:Ó̆ /{W^+8^#0GVT(2Ook?\8VIY2aΦƞB,/EDmnxeg4al>j݇4iQƯm%}o*uU1Ed#T8]31/: u7΅Ω Hlbue@ LfVLrdZ `y[.v3CmǷ_1U-jV%j&5@R?9Tj)xy(zl+?Y`CEJTV֔2vqAFQ1OkΟI=B@MM"ͷ3 ˨1Aֻ~:׀˫@}O'DcbyQ%í?\K dm7>*KOY͑θ2gVUVީl{IWVDA 54p(4w=iK۞VD9iKaj' t+^;2e`)2빊hTP1bʏayzxaaic(A C|@r64K π{/8fl 6 Ws w"M>dk3O,TJBgɈMq]"^Յp|lz •&XB9D zK΅Wv]Z&n)LA6)MKW#\*nЅ S-_^z=H[\>\]pN)ؠ%[qQ#v^Q}{#?)pȼb)Xi[궄<]2a V<Ė4˲?;*] UWƱgV ڕVq5~,]HTc>:\p[ ȁomd =mӉ>-~#\P.f9 p23[q}A.^mU@T%8yg |7 AFsT]`.pt,^-- fӢgD`؁xNnY${ k6',V"T;v.w`>3"7^Qb*ρ|oҞ, ( 2 /}0QE˔= E8(Ԛh :/*@݀1槛WAy*`zT-;ߗ#IN Asb=!IY/ rZhYbBp1(xѺtȢi}z<-Ne܄dg2JIPQ&@eX RYܥHə u=trAv,d *-ۻļOE '[ZGzbQA't51gُU :ǒ ,ڋ EV;pa~BG|.pDF0ἴlE2κ}6􅱋e`b-)%2UeJ(!"sg!ؤ#6D($wOv @IcP3YoHl-'"˟ul.4p^rDY'3g5ʑ`oA6ud /L4 ݑ=ai ;)p٪+\A:|WI9Jq99BC,9$]=a4 ΐeųM#+Wf?R}fjzK b4 N:$tDTS_F/;$K/wrӥ0%q+?gnr:i5AH"WI=BHN򑨎2xN͍ x5U.v^G(};0x*m fK3zzSGu}݌Ri\UFCGٰ`یfrR2hA (iyDXI_ѳ` 7~{X). iAp ;2+,ك};rh#YKSKMB!|x!Sck-ex[0+ndW0Z/w) Bfgs}I-,~ܘ,m9>Ҽkv iYQ!н>OF^Zk)Dz;.KT_b&>X;Rsl:O&٨ QYnnөoX 44K6ɸ0ZAt6&9$՛*QPX9qȽ􊡑ۥuJMOI֮-[a mrVszWUb;@zIpTȣZD~(Mo= :]*.ga)E/튐=PsQrLOK™RF-ZX]!zYxu+@nF#aM 4v{J>Xwl]K0av>T&; \.|9H8JqƀO oֳ@?%")v[! endstream endobj 141 0 obj << /Length1 725 /Length2 34245 /Length3 0 /Length 34764 /Filter /FlateDecode >> stream xlcfݲ-\ezʶme۶.۶mtٶm{}n/X2Gf9fs-RB1;[g{FZF:. #TVل nb P602Ivf #5kc  G9UɅх"e  ,[RN@!. 75q4(Z[d,LlL(v8#;[cqr7[WG:dEUT*[c?N\d9;;Xc?QGXtЌc #g-4t56voBNP!%lkk9#@/-Aj`ca3$ CY8Y+X8`u썬M]5+ʿף[PQaQ[#;c [3?z8ﰂ&\;Q8;Z5" zk,!!;w/Z&-38::[za21q71^[3Lm --W^f^B27;¾Wsś 0ݽܑo&23=& Y~-&0zW׽Uò1sN__ Td9r(Eg/Ch+NC kO]8kRpm+,/hKϼ<0L3RXcFV(ٶkWfxڦSgg~2sFS젗 +` i()*ą<uyJYpc5]-uX?b([pU6qGOOҠ:)ܱ;gLwˤ ?h셢eVұR9RE/YPN3,7t&3Z. ŰVdta2,r/IXΘg 3,:%Z:>R%.@1X 0l)CbTkr i*;YZVqމvI å,>j_A*8@rd2q1+&-=fsSP-V9#O՟mWg$GK뤍.H/^ m8OJs&(u6drS2&^WwF|HFrE!NdGT#Et0{%jAXh+c7DEp*d]@K&~WX.2/1u^gv7n1NxUd")[aWƗQAd/y%D$q{5Y^'K"ɉJ 6 t4^)QfQ7}f+q~yŞ0_Ȗ$pM|WJ|AX7ͬMM檺2 w=U>u ui4W.\[rEssKYDu_hC_%DrD lشȫ"ᑸ dASY6N>] =m䒃A>ka_ԚauyW0/jT,Sܟ3z׿sх|-aa8eս!BڐΥsdwKg(֜˽76`1*1LI|p uM0>I׎ ;&RhaZ$Cvd= "kq][s|NJN5|ϵëVm`9ߵv_,,wyG#Y tHyEnxF(;OW***o1o-Cf 8 ^ZQ9߷k8Wg}jI <#_;YB"tTSŞ}"O?5aP$H<7٧N.$_<ˤ:);P%[ڧ`7]_ݲ/m5A"a[]8h g*h᳑o8<[ y u׃Rf:0wj MAw/GtI;+$\&tq"k9=ma')\*J{u:W/mջI~ ||Ӳ}IU)SW&QJ׃I?(A^,;Q&@V0rve~~unA zrL ,јQV3T}idvnsMŊCW xϸ%erf:& n(1oU5O ;%S4d|sdyObճ[0w[)Q4Ѳ-zD.XhŠ?'i-yrw#"ݹ8^40.uYM 2\>>' Y! lAb=@$ =K{2ُT#F!Y_M8K1)=EˡppO}Mk5Ǝu + k#ҩ&y6srbٕJtkiz1yÁ1kPKŖ"NY)y$@CY0獥3ĉjKoXkTj$S}ϸW,huY"4V,xaoWCsI%&QÝB㶗%hqc*X2GE=€#4w+4н"G?`4ya'bEmG(p0Br? ŲC'^ߤy(İz8֛^(` [(롳8c/谴QLuΌӭ'tԿD ǡE]N}"]27-Uj{E*y:FAѝ*.s]}:#k5N(bEko SȔ" ,l?{pYmQ]#$P{\TOx`/~w&Pl- C*;#wY{_rV]q K.,%`h;3ݧs%}},lnz$W+Bl"<^KlxZ:oG"d ҩlZ4GM2B/ISJ?^3lH0<Ǹ6P&d\@giۀ.A8;US8 {`#;1q.6*dG2^W`2znMwQFBVG|/:R0k?ŽQWT垚Ű ;[T]M1q'\Yanm[vxmC907 حA[O4Ni퉷¾ӃӴR3N TϞ޶E&Ac\X'緎* ]C~y$ͩef%9Y>/ժ%Eq Mׇi͡1)Z%z؏Cԫ1?N9HP˄!`10GreElqDq}ej\8%H|IV$:kVԨ4;@/KܜkEw˿wPu^;bsm@!V긃upzkjHR`ȏ|:<(2jc֊-f h*g 2 *ߩ/!nhgB<5WJo'I,͑'r=0F<Ϣ+!=}aUYHB13${'v[mU)(1)}YejCQU1GХD3pE'03]nK~]}O4\RkS H{/򐭆Cd1F((|'di"vb҂S:k)a-R;8ϵ!b׀,e.oNHhN@OGr?Y)զl?GaNlS yZ,N1b9XHjLk,{Eܸ>oF[  6A]ˢDJ&qYX6e5>YPrEb#_?X> z|pJʦ2C]t`]cz r%ĥjRi_Ħ9qXօ}3VZL  s}mkK(v#Hko`Ϫ1Ow Noi$JqKX9-Ɇ?y;#aIEe|ft4 ɧ7اXF4iAz۝l$Ve/ȹl.uq X"B^g_Ki³FΖ:qcf+p="G̳ESn*$_u"S>T5ɔtԦ:Ȳ=ѮoA52kfI5g%rkZ9q|beSsZ(hA8K8EmC+a}xbjfD m;D~5KlQE d"i#-c&T>5E o%͢aH$c!SAWxZv=^8CNTh&0^-kᄵr; h 9q8 L(ÌQ "H-Ql-EL)tZ1vV#HA,^ZV^z5n¯ː|_[/$mځz(8ߘyN +Cf蛩>@J na2Jiq,E]3·mܤ̝s[jWQpl2lAj&}-C ^iȿud DiլȒk7HmJ% PAm,yڧVJҀ8xYϼ4WOy~d6YJtÁzJV]" *.e7biu)7%5MؓP"]\Ju7踛Ihn9ie)*[L * S1$b˴$&viI'M0[J]վ]20FnwJ7 Zc}u>!+Z[Qe*|o(ij5Xƪ TW:~g+ 9|(W4h$uT.sta:t F f`Tˑe*|{-RJ#7L;N)oQdK{TZgm怏-<&8慷)8z *^ʤ wXagO&MХ-63] dlzn~ٶ7{1q|VO72s A1$ ѝ>o *ԅK3ˤx0 tIO| t6ĕG>@mŤfl>pGRltG&3#L8F*ԏB4wB1ϓtE %$v$Uu2fCvǴ#< ~S_^q0+. )ŎP#K 9 يX.bxy%8s3ӦTa_H+y0펷F߮SJVR1CU^T*BP47T< JNqvh겂^(+7USA3h\%SJEK‘쫳(UK0l#yLa J7aHqV& $ƮݟGj&m`F"|VlqtmLkӌa@ _[Əkhua5fyǍ4=9peΠr0 *ym+] LQݓlY,\55O`* 8*Yy8?!\u*a>H~*Pfx$u2Gtub,k0(! mnO \$m$$Uuszv`=t_ژ#i_qy ]=[;Usٌ`\DF`dh5 YsTͤ5=ЂdLE8KjUxz&pV-7uPyӞ^Ԃ%I| ͓țʹިIDdJ>@rOB!'na׈z,"Cp}9,!! hORZ6?ȠGp MWl#L`G34[mүuOtp 'ʴOǟZLؤBbtu.DL̀:7^o=</n#cƓ^ik'L/0' zI)"vy$g%A:@$ld Hg$INYGcێԦ8w@Cw$^ 2O1ZvQe#oKWXv ݦFIK4 1J=jG$ϡ_UDzoV5cjBysm"fh/57U{8R. >R'=8{{`سpr]'fY_~$.͠zgzw\i 6 ʅwJd$3~{cC@p(پA1tD2"e,nQ5M+*wm6)Q.yg#zTL=S\y._scSv A!2~fGNbb%d+m^;#SUD|Pg@bް,:Vpez:9R[}GުKynr[nw$nr/$*^JՒ hͰ(f}%^Fu4|O=>HRC"qI)Pk ?~}mi⽆Blv~V9vPsKq;R7s"Q-heMNcN1R!ơN]S_ͶڇL,j3ލ1|pP\p;R?RF&6ET C9'Hvg/}n"7vW?l ٸ4a@;XKs}QߙhDe7Awc\2M|̆ݕt~ aipjD^]04;UL2:ߑj8x\ܪmk^ӘuY tnm)0yYǖ?UݦE!!J'=0Y'Y1dr 0IsU`\K-xP*Xy;Bgt_G"Q٩j|sx q˜H;&`'.R}aPa!qe蠿C.d 7vL(%MR+>qJB~O? /NLI :@Ap:15\94MAR-on.<x!;'(m9mz\$Ӏ5f!S\<1 jWkrpz2ϭNsYeA# &@Ͼd"_< JkβTħtk-kX"̯s(v Z}X"Q{O ~spڌ/\咂*֑TϏtx}xr>pEjN7TQD4I&_K!mX{! ƭkH2 N6_f72Ԣdz/Cf&ci"uH~@D# ks *O"毁1.٥Tb>e!'{]3 ĸfKs̘J6]Y&0WLwםg&U H1k߰tΕ)OKS_r1xo4` bZ]* XG8|h8[M%f[Oi4V}}xz\!t˱yܯ* w{,6@F:ӕ9';DA-FSeHTS{:,%VjR)핾f.^;GEf/R@PsրBU.~G\=7 u^IkCEUʃ? Oot3|OGhJFvI3DAN0C0|T,n-JU=vp#3~µ+*z_z `SS3yD7`/޶< ~)cE pw ]OictԦU?9BfmF>ۼݩ a@ (c|xeP ?8獵92}o ԯK|y1|&#cܙM! #Pf鴃 * ~8^YD_4] bJډ@,A}*,! HY*¢ԓfdCx8βcl3),KӞRfǤW 7/n6EiK D3 o&z??pl&SǔÀ[U1@Q+P\}d~<?{^ n|OK&3(&06Zp#tHz˅Y&6D%Nj2|+:jZ*_"(r+Autu Ii=L'Z:TQԐ0sB:UZ6LQF =.pix> ̏WYxĠSe1@KLF62./` y"COb3tfB ԩB=|G^L(#6} 5.=ffA0cʼD Ac>e1,+˂E p?3+*itBs1T=}n:YL>d\oI%wEzDM=fXޯC.A7aDaT]'8\Z%OC3D.a@O&iR'Ss '+$ygBg=PDzȶWJmI[?$>JyY -RVz8Ys$ 7k3ꛒ5 X̠?~Dsօ<luѿ#{:|F}}h""(Ԧ 6RTHcb>VE..[U0H; ;yAg\ ?3kd=Gke½3(h)&V"<I,8OA: ʭOgJ:%_!tL(Zq1݊Zs9<4EU?jq9T[4)rW~SD ol{J^ )Ag%FJim-s:֬"2ZlPD~QFfA iv#$얹DyTlpCB`f٩H %@򒊃s8O=Ao N䋃(n~2b! A@gUpq %"t`~ڨߨ=U*hup@θ{oq%Ԇח ;ֈ- ˭*[T+SRh;DG5s7[5HddN H :jiVH9'A 7;0q1 Zkj$JKe} 86?` U*YWZgؙL8TeddP[qəPeO(ݕ[u˧vTC1^n\ܺm3z uݒG25CD/^mEф6E@ 3v.o)/|`&7?/T[Y ;ԅSۮ W]wu4 TkA|,bM/t˕ys{GllUK$ JBR%42*h|Sp،v-u ~>bOHkb%Վ.}F%3}qh![]TA:r !u0Hdf A*k% Exo9@q>JMuG9~׳褉`n1aoh>yJt 9mr0`cֻ lg*Iike/RN^~N/bx()\fi i/Eۣ4-񌤶-c#.0s Q ATzzt:s܈N솦-uT@.LFpPvT@`5$*O369],Y\!~d{r`6^.Բ:ll͹1b 콋.#{_qMXQA*Ft2tt~Ecߊ1Ə ,)+ mvh31w _o]AetZ%@.yPDD}f$ޕ$OuZus&I# ? !}5s_/sӊ\3"L$sjQ՘&muDRm Web`*~i(n9|ã!K*ӓzЋBl]n}<~QX%2ɿ3~D݃)πfqum1U7 Xay*Tw@1!ټlӕt XX}f ΝUXTT߫c f JPQK8BO<}T[seLKOrݻlF`ٚĘ(2ģZ"xƐxm]IݑT/Joٍ"ʿ5 E+$Zu%_B@ݢRF0rc`|cB6`mZ_.ucIIﵛ̂b*fo9 F>B/BzlzǼ2̨1aV7:bVJ߭1Ԇvʻ~Hf)bjBr>gpCۄpc h^oV#Cw3 ZOVY=&:*33fj=C>yt~jS-+7>T^s^qY8VU)3{>Gr(Aﮋ:˳S"e@oVAR6`-W*{}ѥӜigdl }wy*Ǣƀk՜syc2LY"Epwa1j ٨ܨI3w#D׆$U F, ha'-=CN ZToF6k{"2y3>BX2t4°&LeޮWZ,sH2SVe_^B~`ܡ:k E={tsHNe=s,ŽNגT!2$ȋF (ZDDOn3]!:2gt=~kz2F%j!@ /5ӆp=YWt?pa@ʷQ^j*=fp?7:TL!ii'+IHUK\w %`V|FigK;ؘEͬľdm ]29oؖ?p5J=yoC0pӿѾ{l dZX4@ j׷2}1:ƃ\j$I$t!(u&.qV%xN ioC?Z=| 5S'<28*|3fha+6=0 x};y}j}K!+-dᦏ~@˵o&R C4:p]D2/Tpj۲0+$[ y pɚ>k\IwmU8N԰E'+HDEgP[jqַ G5zN˥M7bG[lu$-:ALOWITW,ʴ_KSyȜ1&]2áY:j>; @xֻ{6hYar6df$9`5w ݰQWy?&~7)6W쭵E"䪲Qysm_ǟ[7BBy2+-l|TL}:.\ .k 2.l…-1!׹+JDq/ͩBė7͘u`@ABp-Ⱥ\XAM7lׯ632y f{6v5&mE=v?fZc52} nZ~% )ƣ( lvJO<.tI4ĝ5 Q3v0;$m:rqB 6-,vAJ܏W9 A'lV :3"acѪaZTx&-D`3#3z#` ngE2L^pАbp)t.ۏ߽7J|w^aZۭJ"P{AW*/遡aI~icKsy2Ы{@8МZuz׻C$os~b Q^qQ!15YM2W詩C Ixϭ%Z'§N|pEXAuQ}oޠB\@@#Hsa&DpJZjb(V{{/ټO(*y."wWYep >`!|rBt4 zBsۨBՒU.3չ1Dz^#s\P:Uom=V"./3hqH8T- {XC#R!a4 }kE|(^[_*Lghy{pVw}\? \C8SW|1ck)h!r^LUtRSX1KΖ9vw.M: 3p w}hX/hOy\Ɂ)c?Xsrem,1Gß^1o=Τ\]Z4˔oGJB;>".Eȏ[‡ZPSYJ(S<=m@!>3nj4#z؄.K@[8=yJs ekzDfyDn10RalkUY8/^,᪴4΋,D?.;6T#06=Z"&{aĪ R5Y7 x:΁ J4W|z|-C5F#77rmG /o++&dѴ S4p4Y1ѩP9ȝb4ΆARqAVAr8Fw jAyJe8'w%0 $Y6:cgadPwԱEjX;` n.4r37A{]v&"$:9PWv .85 k-E,v8_ArQpiA"%x|>Whwwՠ3 K#paUh9f O8纁m+\Y0cڻ |%f>;9gH7kkwGΐL4QL@'aTT-IMM`r1G5Ёz ذN}=t*++ 8^cB]$RtxHRѺ$?fdZwf1z vԽ HȘOJkQH(5p ^|E#۵fk8Ⰵ]z>vwr+P{7D0X1WдsMr2UI.c#@(oϚ鮕$ H]ZND,-X(Y8r9&{k1*;9:x PUCExNz ^0 FȎ83_c[]KI(.ƕy.5u ˮϰ;]B}@lֳm yřPVY3]QEl!b1ɝ"Շӽ,Uj,K '|(ͮ0kf71=!BLo_#!Lb!(/(^ I,Jwlī>*|qlR_sӐ$Gq=<) ;MJ#6<2Kݴs Rx+ k9fR$k{I 2>E~f1w}#Vi.."<wf´+Gɣrh4޻ IN_kNƇn.Q=ZOG@@ dz3Y?X$O-dYeNxS H)K7-sTS}_7R}j!Ao0w|76/ ,0B~m̗z_gx^q]TNTħߜ.,dTSr~αN:rILfʗ7&j{CHe:uޱIYzy".犫f2J6g#d?@_v.͒ed@Abdw8!bqYa5*`m8W0((e+45OEj+XDs@HG0Q_QIUcG8 D"./'vQV0ࡔ 6SM4oN,>Q&ۅWi~K,Qs!D}F≚^!c8+as%M_P /FQ9aSTwqgTΟ8Did [ZȼB==:1mݬѷzz5J!,fB3یosRX J2F Qķ|pE\-xeą"՗[;NUh*k0г+nAGƧq-`yū\ANH8Qsj m+6K~R|9U|V0ńJQ}dk~52iT _t>\YHGI۴` es05A^ O|Hs`=}Sb}M}%Ց+p9`ؤemBo-Quzf#.='|mg.`׻PSR-a``%> ـbv@^X@S$9'y`c(AEo:A/ :)X:qƯj/qRod2)t? D ixgA0fLAqtgaJr&!7Jb. >dl `@k/ ՂBbW;A+ aryJ5Y,,p%jV9Q-QZMj"IC (LuI Xa^W` 2*! !Tv $L;+ANaS*, )kĀ}W &R;b #u`G)<)zYe,o% cJ_KJVG"%]Y}dS*ȗSػ!(‹>nuqw*@)&SsOS9G|n)6-s$(%M-߽3k +/!; I98jQ6`{1A'.:| 7ᩳ&[7B>n_QZ<=Q±lkn Ŭ<;lROy@(N;'kXH6:`Τswۨ4=w s*w`~nDPo+¶S^06hX5"w?Zu'2Nķ8^}r|iLr9kcgJw)dɱRo|*튂(FggJXoU%~V<(+95p۠$ļEߴJ̫m9<ÿ_o Aک8( fq??Ojl2G`)5-g:{BG+ZQYx{BO,_E!m)Noe.0{,w]%߈h# {.:iȉYBp țuzqQ|ۗ,b<3[Ռ{|@*WFU|rk>o^vozZ⸩_qLN>"ns;FiXkϞ^4x.NefV%Wo3SĿ*t8aFO KPꗧki 0\0ӿ{?/-7f{b%N+uniɻt$.Nil"{{צ nKėIo> 95sb\$տ*I>@3#"F3.RQk$-0v%E^C5(s,>ךlƒ71ȡQRdH0WX40Z8! V@"]B۵+l>_&{ DS[^D,hA-4:gU1 ˮ%n(62#} l./L:|Z@YE=}Z zrڱ K8.+SDF|L tqj-;ٽFJ"hۂR49d,7:n5 QX?DԦreK)eT/b kJZ]-/e5P-/ZD~3(ܵ%|VCD[ ޥ!<'-qΞxr9DԀ_JߒdO━*~r(fI=[\+D*)0GS;X(:e`qF>q'uxwG`【n4u Y_)f$<ẗ4[_B,T9c -?Xd:6"Ӕ̣I˄&>+,Z]=P6~ldTN8m6P3Zp1Je~byܟƹnBg;PILȇਂwT<@~GdĐm>o/aAo۽(BpSav}'9xkl ̝舃}9F- 0vֵrBtIv ,\XTYt=W0Hys!InBM=1iDO GJ6K7Qnd:b:a]Mpx1-ŧMxƬ@qaרK q8V-fHJ6xc~HCg ԣLXA]*Lk[AV cj&S:$ɎN6a/e~evׄ]&pے]Ş$!Ew2ãr,0R^lS갹ղNnxTk8ucć9߳ j6\+b&2U*×LɋyH /6S^8 wI(mi}nM{ 1xa{T%řrin+R"3z11m5]Jukȴ)7J1Z $+9M<)Mr P^_DfHȴ^"4I`Vȟa̰FuaMYyYCtVc<ΝisvKfOt aŽ=)"O,a^Fb%S1>-k+]M&h 4;w3n1u|P/aq4]\55@P} EQh)`lt+[n+2c2~X?aO/PQ)BK"TӭtQf*o9UZdLCg}{8H}, ;c4 8 2(|Q:;s! ! 3B@4gz0Qo@ M ӆ(*J#G뽳fjܞ_^ Zc0Y`([ ӾxU/iآNAH#8H>%FzE;b㯲~Gs=-$ltbmDNw顃{I3Fp?6r%L"yk}ߞE6(4{K1;W-ZSo*XsP̂39eϚݢM׶v5;Fcm]Yo4R.K@hp$oBIu[R4&M*N0ھήJ'a XQ4bv P 92NK6[)E]bDܜҠ;s@$Dz _$%Nz5##TQW|-i4 puή-eƿkҸ@iMla:evi6ӧ>x!O4ȮKp鑉qJO8@\勣g8}A~p=g AuiEy<X[8o`-#&'k$E Oɞ#ZJbzo>ƑՁ6$ykLEL8oie7\aQl񤌡3H7MTP?K:S.s5˔_*ɯ37ԤdRdHJvS=h+st9#rQKcEs$r*+CJ=ŠSҝY,[U&^țشf-)T05¡S>RUHYѰ Jbhi(rܹj2=&r߼8vx%`vE HXp|?0sc}'2e壻%1Wwޢ[j9V+ gؗ3ݱ@ Rf[E\$F8g#ΛUvFbIeu$+:c7"!Q+՟:A1Pf >pDC0wrP6L[8hE5@ocrjńHCC.Cn#BQ_DRv:Ͼ"y!ԝ<=D3UhmL,ZbazpʰBCK~r,hh6`Whlˇ坏Q^hXk+R< QawU)tMw:c-ط2^%Q!7L)m[XQq!9TTDima ;ɦt?G1`u_#!bm@݅Q{th dxLx*u^{iN9٬JWoekϳ=hV)2-C1<>&¡|\ߧ'ۡQ^ WnbC ҆zSK(VoF/Zo Sjg6fxS nJ[-"EUq>oBB@K7P BÀcӀkc)l/_՟4MԁYԧ3t½7;$ņa|ADOil['G 5Wy LI1gҿ<!7zrYd/%դJj^RAX@Ư|qxt?oܧQDa6%]|I[{${tRd#-0E:!iy.TUmBPTH9H 0[XOqIwjQKzVn*zd aܶ@ 0IEa;aXQ|٣  ̭7\PΞ Oࣣ sD˶U*\k^62X%iqV1 >"x-mFĘyng|Y`x̲\94J́ڳx<(2lp{% qiRnKb w*OZS!oQ$'4c7x!B@!Xϝ0.gcI2NjႄqR[|c/?~B#LEk享vS | APVXK12S3 "l^Odk'D NBBe@{$! K5ߢ1:DM||\); ŵnDZq+gn$;``дf`3 pe\=g,+@<@}XJGo|˥^Dmӈ|XST7k IK ](ZڜL.ftt]X E8H Da7UtC^yjpx5x`;8[մ#zxI9@ٰ70hznK<`9t33`СR>A*HiGQu];\WOUh=Q5,?GۡgNg7vStjRkոr:l"tA 0A|b /׆8NFQqf؍N~/#V1#Tޘ^ q1K-3d9Of%؋T.b6 Hm}ɪU+^փE5X6.Ǫjv^33"&W2a=$*S fRa%1+GZ^d2z"| a>GKK2'@h#3xs9qD!&??S,^Q6 ;^"XA,~]aI[i(#oeFJZļ!")tר''/9ԈBzU؏ELV* ؖ"Cu~p"{P! ]6-j塤Fm hC4VV>bu M̉|:D,!ޓc2' U oʕzœ,O<&9;0:qkHN'0~p)ɥP{TQ4dy@vΏ5s3\WOX!s,Uqu9&1R4)s`"=bݯ@nЩ@}wcZ~sYh+=]GDQr[CZ@-& `Nخ^{O1̷OzTk;y1ޏX3t6/u+J8gӍ>RF=m5ɯŝmޝCN |H\۔E3 +ݻ:arExH`#9N:L%2 m+x|Rr,x3}|,_~}Y~{}Lg>3n]jܮNBk˦%yZނ[g ZB U-kNs *X2{D|9k1#DԞ:1.v-d$0ٛ]W èL"y͎p3] ?㟦VN2R f"?ܾEÔm(7Fҵp/E2f :}6^vƫiH`c2gax k.6'dulW%qSHxQ>Y4vtR.`$L`sDc(bl$PQwFxwMO3lxԬZp)3n/2ag"K;'drnKK[YK䁨-xo(B{R/9=4^s?[=aJf CA訴S{Wt[f4=fv17d"Jtֆ %gU1o$}%h܌iKU MQ} U]pJ#X&3M4aovAlM{vzoRsW#9q^TkʂJnk:6C>gps^o1 QɰL[wkRk_m >ff VxGK$}qtf QIS+V { )Bx:$WO=)@WۻFE9q)~ 9il|p95 oKxB6,;&@U4x@ud;[A/${rlI4DG TY߼"hAJ1IN eNr2q£JFC'giwoI 58ncr/BW(RyC192@D"zg8´XneyqӪ@aƂ~ymo-#F(s/vIYe#r7U4]g$#"\Nܪi^tJ9kS.,d7Ԝq{Nl}СJnX,riJ4vlq.j/tģ?2eLK1@gEYސг( @xF`.Մij.</oԉ6m@{byƏ[1sctH( Ƞ\8cD[PkULҟVl}uYqh՝&-kJĸNU~+KaB̖֕2;>mv}u\S^@5(\w&Sߧ->P9m8ɬ>/-k &j%S_8jʤ(\Ɏ>_Xew^g_ Uj{ezUWewoF0H#"CW3GLdg,'!#X; WlXē'5xX<)ӉyV)0 0wH5RxFS1:c+_W=8DLX:EJa*N:-ze\~j?M9 !ÉEjꓜ4+\ |LgF^:!vSli_Ӑ#pP". K4'-@ _%9C_X/ۊμr7~d]q,EhU 0@X2^+p.\8r .g Yp49yZԽ&^֝i~8GiaT (~gSI֪εsm9Q$[?CۧH#2SЕ5ck+uV1ƨ#P]~w4J}i93Uͪj=Dsl磢Jﴌu~\k/ .kZ}U@XshE;|^Z<֘CV{131\)ѱ,f5mˈ LR%MdsSz!QJ"DJ!&7"ِ­ kbkXMzbEچ E;hJ[Olh'4Hpz'6a%E;lz%Zêm3Mq\4|66J/ݣ觓TlFsR} ]o/{z." AԚ]cI^s?*)߫.^Kwvg@>Vuº)|֮Ɔ񏒰 0X5pԹ.qxrsSQ TӧJ&Ty=f&Pjg\̪|3kl1j. oH{M@W0OEyG:*(tQ7с+J%;i߼G%.~HI :{ |]KI;HА|ܘk kʺ=n#)2tP2;ĂۙҌ-.oTDR5"ES5:PH@tsKo< "@n}O8u_ >o c;W|UKRI?M+~hw ΘWL&UA5?NAl\@*YhܜzkM5B;QEI-cW.$)' }\Wt~>Ծo*FN$SLص^u*5W4^vU 4}E`Z p{ּ'*_sYt6*L $085bhTAu"ȅаT:٥>LV1m:dWf#nZUzΎV]>%[=]U ,Fv \J|@"Wkh̫{Q)vipiFn'pc/GVn:4~m6Ꮀs bTN+Mt/ml$?;zzEdtZKQ«P_8ZtzD|P+D٭3/=g颮@;e2^TS#Y^,KCC*9 ս&&=.X)qQ5Brpj5H"%~VĝkQTrZC=on>!fm ý /;G>9'y"tP X-*-57q20Hl1is_fX`kOjV+ 6ԨGo`|\&#-hjsΆ3X[(:R.Wyq^39}$gzQA s_smr96.ҘڭF%Yn j&LU??M;A} y!]uB+u@(abaSӚfa4djϼ8 7ʼn<svƅ6Ja˪'ePMR[dbɻJJ;l8 $h;pW>q7> o * XfM!I"fd.«qa)B(h+x* kNB:291 :Pcl/@.0B,.]w$np^VOw_iXkVa_M_9,Ղ3  xŸ2m@SK\H*3q}CQCsMPn>`IcnLj _Ba/`~x endstream endobj 143 0 obj << /Length1 725 /Length2 17745 /Length3 0 /Length 18270 /Filter /FlateDecode >> stream xlcpf>ۚ8OlOlքOlgLl۶m۶m9_YW^kvΪ@fzf&n*ϟL&V8rrG34,&&f8r3ʘF#@*O p6L-E-)y @h t4(Y[d-N@j#? _ 0SG;*@LQU`hk'ىh󿪣8dmIut 00v,lś?fu|8Mv7Dl]9;-_ܻ9ZcPC kr6 ![cIhhΎ.5?8&vs?<K}m]G/;uQB|د~[ ,H1_55DXpZi)") ~i-¿^B,1bS[]Ȓj #NjήCrALD$L˭L#JJЬ ǣl`yX=" p}\lv'SQFu#ÞGzJAwrN1L1!RmcVk!ȃ1璨يW->A! ׁ2Dy1|吴}v 9z28و5uQGCj06.zOCElgx3#;Z=)2X054.G:ؔ }C0pEߙ"sQ9d/jO ż(5nL>Mg/W(:  gbڔ1VAJb5?; 찭g>;V#^f T]Q7woqא1`(9c_ 6|B1rxsv(ѭ"کd\)1[)|XƜX0C6-]WfRj%UUbp˟=SmMqXcW|G3Kӡ5 SJ- | ܊89 35>wtY6 x-(J6;,1`WL1 1 ۫1| o$L"5GWgE$1G[9;U(D]B`MZ+J^nN*"$3Ek*cbV2OHc4K 4Ƃxt@cNq!9'[=4@nN/u,Fˊ?5"\,r*п3>nŚڸ/ErK\O >}ޓ? /<}=7S@Utq]GiUwLlb>Hh+@s_]k+4H!wfzD&,r.pA(0Yt2cҚ^~ OrX0[A7r ]TTpoL{ TS2uW'*<0%f\ね̬Ͼwl9[)&'~{O2 ~Qƈ'WEkxg.kDBaDZG<3`V/38^GZ4BxՀ~`;)jz.PmϿb D,#(?6vWE0dϔ;-eI!Ct k[TP0LP3ܹDY}ׂ&5nr[ {CЧ{U"LjTM0wۋ"x:{Y>*н6yԚ:n/#F{t/z_En8p,tnΥӃ,]b;aq ox.:@wJuյqGrw?:p&r hAvc|u1h?A [NoT0@)晨vV= -$@ODDש_v)`!x>,HaX$՛Zk\3A8Q45EyzL, g+}r X'ȯO"Z!R *|m:a- -ȟ k}=̺֫1mp^۸d1~ԁ ZȞXH=0 Z܌`BķTybeqncS2W.zh.NK䚷D䐏PP1u(B1x5}JYSi7DOeڙBs?}*ۼf>ԇ]65|`bWSa#aӋyGܲV\\ʣ-!ix6`eKtUu<:_CS[b18"]N$G fBL>tWjVܦfp@&-a)EJ,>1y ڰє 7qjn91 O/ClA?jS@iz3q H`P˼T =!nδvkMP U5nq"=*S%_C8zP%$n8W|%UQ۩);E3G|PzX RkSo٘l){ZJ-(u?^],MMGmG& vw#I#iy?eKxYjn:;3ҝ[[3 <.`.{LKsğ){ ڄ? 2p%Jr(Ғ/yrBI0?mbpk麱yn)maD! z[] k>Cj8q pZ}_\RۛEv`>ZDha]1&FZKN\8m(wl7m"z9RxkWS0XqY+E6ھXSm;7<Jo̜z 1E@e\Pand^ub sKє(desy \$Ju/]UY eH|"⧊ u{0=}!M]Q.lHXb޽A"͓@kt.U ~P5coHCFߜ A[_׭Kv l] /|CG Aٗ%dtKjxe񪴶 ҽ-ŐO1-)H^eK7;pvLݢTڔ$w4jXCZ$1{['|bܳ̌!6yǪ?h~KaAtq)@$c4qb!YCCŗA[ ~y}5m ćhdl&Дb;䏞 k0 $M9a)Bpvn3 $Vѷg8Gwl5Q rW(`+F432QqP4aZ@g i@7gPNYGoB;q?~9iv)MwF|BnPm"X[eCZ+Q\U.[6J$QKZ C>f9=1>l}#P`!1W ;ڀx*G&r0;Y$`ߨz{Mx%6A۬Fdl-Ls9?kiP #wl 8KI|'@aEͷ$5TH^!K8Y\ΫAR~bƈW}L29?j?+!hR6lA/fŒ{Q&7SBN5XHV#qa*# .nIg6AM,:@OWsXe"b F!a0m)H|jZRE:($)r ;2Y|jivWeڿ<q99=6{~qw>6O=ž1OաCG&[Mwu#I$n$|T4JF;.)Ac/Ԩt`uzIzneȝ 3 J<LҎF8Y_!vL8P | Kn^khv O8W7:Jdw5iE-[,uȸpmOI:K`d\Y^=Nf֍$^#yv)1٥ * {,6 K"R>JQK[Ӣ@2[Sg.döR%7zԦM}_8KB-q;Ԭᦢ^}jх.Z($bQCfG\hqf=Z%1(#MqE$>m x!rg{%y]1$G=VcmGWYL}}rY[IP0+7Y"uyFH|QDw_@s*75Q8* cFgb'K*DPO#. Uvtp3"LLbMQq8].= v 0gb!]Gnyb򬔨v3}բd @ 1 6f=z]_CP=bIf'%ICXTU g.G,L].cmMosZ5_)x!dh\s}bƕV>{ / eQTnwWD)(ڐ/f c-]U(UO#-RM5niS?h)LsȂn x, d2~J ?ʊwT6*IMJ{Dc3ll: T% ;Q!|B^A5A>U`_!Ni`kEc%Eoba1ŝqgK69pV@G3'B[t4SomKrP1LuEiK*@{{"F6`x l%mɑw\ԪƘ{oSg Y_o b>YRn.5ұsA pqs0p;uEIZy Rq˖qPKδacjQ9 v˃ yr-7 Q*V2M6 qRX"9{qh\T98#v!}˭kXƋəv(8|sl&xއTeh8ICVrH H zJ[庡Pd@NēLħδ_'7sv.Sת=Z3jGcy!Bw^Hߥu.{Ks&g.:TMɏN%ղPԠXħ'"£oyHpf4ʪ-T=r8ޓ`ad.|Wsӧo^jB[C_u=)mb_=$mZ'e-il=AV #O&AM>Eޱbɽq&ΛUoy£ʖά\Wu$0cʝfZD3ךÆG:;վ=!ݚOY7xGf1OP۵%bX.ɔZm=߲Y8iм۳8Zڠ;{OE(dQ{23ג}U>uց N¥8M ,' Ȫeb3ȹKr]_VO.&_ _o0=DK<'oXf6 GȘ .XW]m:8]تCr 5vYxWu)ZMs#]캃4zp)\:ҙu 4 Y ҷ|(~-t! D$[]*\$6K._jjƻ bb1'ef*3c Œs&7 vR٘YNe?kD"vw( +>w:1HEU LnidDTd`q-xV5(ni>}!V$$ MjLYy^>RB\xGmˏ滧KZa`<54~rTLOu0A>p7΄;wU%Z78r.Z:}Y)qO;\f:)+ a Tdž.[2Ƙ}?}]sǓN. e,^o؇V嚡t >!Q<]g '=3I8yOgfWNw6N+̌?wx#D 4O]5caWLS7CЗ~ֹJ|!y)<``>L$9+;Z3B/Z]tw̑7(Ʉ'/!M&rbGՖ|!"C9Q;ŚY.{W) 4 /<gL_[f#n `?m [OO-vumcCxF#)yu(xd|a}xoO!th';ՆI!vbMHDc/5*|,ؿ/_ԩ [Hc3HEUyto-6$@Aw}{PE9qi(v(hN/ޞ_{؜ƦODȩra1.Ȗ (c*Z!!ntMԷ?j7^:>o",Q%&VZ져*Z/6@ث FY=^De=P˪WMx~}Q&3Weȹ{?H9XDGW%KoAIÍ]F*4ژhk<3M| $}jHB׈CzP .4o~Muf ' wrû箖Dg(o% 1$|-uߺC }?'o |`@T7/(W"tiKeϠKMf=_GeꉊiT>kt{Cҁoo؞GųJŜ|P$$2겨<]ff%N򱡲/.O f`; X!=3t6j \'YA}L,, ]!v],t,%jWEzd$ 'ɹ?GbX_ FڻBZՖ7W[U?IlWԩ[9 N?VK X 1xpFcM#̮f hN' }C6˞\߿e4{"LX%gSxA6NIܶ#=̼ zsH.5ݠ!~>ދxJLN>üج>I)XHe0QC Nf|`LUx[o' l}ΰħ=}( 1chGVQj[XOr+-2c,,"6.6ya~#9.wuvڨyq (׋bf51R&[M9P)_vڔy_@ Ӑ;HIǐ1^4 qt_x`a#0f×鯶 9:[bs4C5I8VB)31~GTa<qcKT"r(S~›(SH-[V ?TѾ,(1~e)g& )@HܢnoY==G5LL72BkA449$$OP"GWzMy\ J,V:?Bl0[Jm.;z*rd.v:|3l8Ti_+7t%t}haL*շ 'A_1Y3RT}>R>G¦HUkG^dyW̒fmN"e{ws/Xxe*WK?(ȉT+U }9ʒn[t # XC%Ia==u={FMǍF<ӡ2Bm`}if9蜎wmdǒq6 :HEN"vW^G^Q݋+ZFV]bz;zu9A+$AkD%[u/I РeqZJːbv*[ '#szD͸HzRU/XJqւB; W='0JX 9c1N )P'[&N;GKK%+nȗlA`9@?7`1MQY4o w $qў[LhO;QFt_\ eD)jίsYԪUؾPb֕`}fOg@}G?aT Kی]~d&wvgH$q߯Wbe{T'Kxo0B"4C+M4kU,&p:KTij֫,ͫ64%_Lʿr6֚t1Z_֣l6GΘބ;(Wg1YU#-u#@7iRկ2N(bWQSH@if}oRZ ^PdCw\y5u=e6 Uܰ&C5ؽ!Ki)bU UGSO0ńAyweU6Fݼ63g; Gůz7ϮyE #nʩOrsMsfTk>@%A8L! idMr W?GAn i 4yf娋nf nrFRyZ6S#.̫>ż̥#2Sj֐<^72e .fޢ׾4 up7wPAHkKY,.p%aYؑAIq75d`s5ezlq,5wQv)` m9x-BK.Kv2ż?[#-Ml7b6+٭蛺1HuxҮ-$Bp3JIL WECX[pF0=m 'xWOawg Ot V WNS2 7ᨆ- I퀶Un/OR~܄,ra.BM淪$BOOX9NlPlQv!lG{ rhbbB2 2l(ŸPT{=,8OC&U >7G)"! M 9aikbxtsXÇBnBn'۟0Ru)ɞR(e`%6ɒ7EM*e]LE|#/2/t.Ďd5@Ď-jXEEM<'6B#(V!F` v+&+tV(LS鎈ri dt5|DCd`Yńy Sfkʆd'BzHN/b_9#}1澺_\4 } B^BkKhKC쌳 .0X**G8-xۦYGʁH #!I r1urqNPEjWmXh7Y"o2lf+)jΧu)c . -ъy̑Q!~(0lYZ]QEY{Srl&6mZ,  ׸WmP/4G~Nh)]ɍw. Y|) 'u{^a<2r]cʬ?]HCr%#~p)c4$!㺎 ,0{H oQ+3包}^JcaNHOtKӎ(I`.big4ZMyL!w+O/!2K?R.#nS`  y ۅ>|JXy>usaGyj1$=K-K!ĨYSSSa4,D,Ʋzedt.;=g ݘKэA!89U bd;N`'C1t)b' ;MKp8|XN~6p0b4AwW(gNsm¨;tU>y(kms^Woh%1˅̟x##]0pmx0d'WJ\]ž4EGlTE uSSn 1CY9䕸KG'K~kR eCK(~]ASOݼ&ILSDL,$UFK gYOtˣW_),Z/ٝpk h|L\F|F[{iZ47~=3!4Iq0 .E׶V;-~rR8?0]s^]UܬJD*|ʮsÞ2Vq2vpzt)g:muع8s&x}1XؒKI*ΐv"8@͍8r_\i* !i=|HXX!OLnĦSS[@*\q35J"S!{;JS! K!T:~wrF(?&ae?i~C:jO5ܪe{c,J7]tѣ,j,p܁5U~zq8̌!YBφx/PzRj.P Dg+yL׽:ֽdw3+Q;2tM)C _*DQJKļա ItiP0$n'P}vSUJӲT~f@>sjXm?6yp-A+:`s*iì_u)Aݣz߽u>5c${>79dp|;|mJ9L;wn4 tlnNlgqXXMDg#fg {d!g! n=Mҋr8ӺGvXR əп:[AM>/w@v?*dܩwƂdu$ :;.0"g갂wT2wDtJ*+0 JVֳi5·j]}PRB kF8dt`kMc|Q4QUPD:
r[wTs=WgJOaڟ}\xMqZO+V@p^'bsEkQzŒ\u㞝-=!T,Q kuQVwc۸rFNӺݺiȘNLo3mSHPl9dcx7 endstream endobj 2 0 obj << /Type /ObjStm /N 100 /First 823 /Length 3910 /Filter /FlateDecode >> stream x[[S~nb4KR[ɒpW3o&_nc` d%UZRW0(JQ eQXc* KJ8Ax"8„'+Ti SA S)0 8쯄r),}Rb}0VXЇ]LDbi] nу1pSρmK (`>!y} O'j.BV_bq"0z hap!H / &Bx}S'>t֮* <<88߆=3US>M}䞼H@,PD+CEX ;{dk4Ϋj<&l_KyV) h+4jUX ̚f?{2CL/̘f?`iJ(ŠtÊmB%mV6Q+$_DXrp"fRD3b \3̷$gMD/pS5g6t 3Ρ270 c4,ܾwOۃp2d>?WʣɰLBRﷂQZǟǫ@Ӹ;GoMQKe\խTe,eY`)[3X`*QzUanmL)cVV*nsp߭aU#;Vr1E_tk+y H%5HvZR\cB֢ !պ(]T3:o{w᮫^׹07,KoVGsMumgъ0hIT%+ݺ r#a"x5g}-dhq˭l!׸d Aڪ׶3u,>=Q}na'!knsߕ:-rgK6[vSbO<si")&3H_ho)>5['d&h_+d,lJ3,=)_cxZA6xG^  ϦdB!aݢ!`7Q,dEEH$C\`>1o'}kȀ*3,c\Vf#4%mo-=̙#`t z2vx'D2a.>U@iKvDl;ygϳ4udRIޑl)mb*7$Rm T8^>R=0Pt-]eA(2YJl .FxQHZ/Y5vZ-tc Oy7{4+b6m'vKR[$=@.1kDh9+.1c:Tdf< O?>!q˅[BCh>sog ʿd |M(tVF/!t0(nQ~}.D9xxC_[ nf:韝M'_"Oc(|4ZrHރWMr$ڪ\Kk-m1? T|:TcɴV%(<~TwKjjIaw5Sy_>OsWˏr iXˉR6ýw=Xۅ N#W_|_=[` 1&cy_g'0 hNs"Dů>$#*; =r\Sva''#I?O[dy Hγ}<% X'ӣDVc PWG7ʾ C$瑎LRMIZCq>WGGL=.l_k}!TR/V aN2>bpjF?OtO*p=Ȗp~67<od\h,b 8dZ--lpm 5>p1;i55s5oKh}C^ t_./^`oǻBNEpeX+5@:;JFzO:5q!/B}]$f endstream endobj 155 0 obj << /Producer (pdfTeX-1.40.22) /Author()/Title()/Subject()/Creator(LaTeX with hyperref)/Keywords() /CreationDate (D:20260428173207-07'00') /ModDate (D:20260428173207-07'00') /Trapped /False /PTEX.Fullbanner (This is pdfTeX, Version 3.141592653-2.6-1.40.22 (TeX Live 2021) kpathsea version 6.3.3) >> endobj 145 0 obj << /Type /ObjStm /N 28 /First 226 /Length 1281 /Filter /FlateDecode >> stream xŗYo8)Xo|&a;qEdڒ#ɽ>}TҒ6$q8!EQ!8K"O8%+gFAJ$'a 6B6J1$J&З0aC>!L`RN\$\|k5D]HIf衬H('Nm$Jgqh@7UH_6-lZyŲ@hP,̗p0< _bv=UY/Ԇ"-lB5:͈@*OYms:R%:H _i*K!M_R(R0O|V_!Wq2At&u`6\"S!!ʋXwKhA:Ѕ#88gp}KkFp0&~, faIf:S|-)S8hm2DDiHAS`8Xb`kH C97nB+-$˖xV0*WӤhp;-LSiat0]GY) K=4@{EgfC1g2Yꭳvx>uT)ՙ?_t|r{{mԽ=6uaIa{WlލNP}wꢪ.w/>8ތ[Z|ݪG7cNμVr88Yoޝ=Vs"'oqOuЙ\%KT+Dng2j!@_*؇$/t}~r4XZ j!Y/4M.i8:TdsrHNo0>EQo?U7.Hu}dIdF/Ժ]\H{[ە~*;m)@i*\t8J sM5,L 57D|GLJ_KCkM|J@.lh 䲝!Z_^uafE~Po4"ڬIfu,{4 ,G$SdGoag*ؘCeI:.*@U; Er^m0MˀڌZmm_4U]GK [&j{Xm6q$Ê*ҪiQ(f{Ո~a\Vǭ1C~P5bZ1#qCa *q[ KbYc] h>>l.Q}Xkj7(}HC?ZEJr<)ʴQp~:Spm_A<.7*i9tz9 endstream endobj 156 0 obj << /Type /XRef /Index [0 157] /Size 157 /W [1 3 1] /Root 154 0 R /Info 155 0 R /ID [<7FDC6DB36BA78C9F7D9B799D6F558B8D> <7FDC6DB36BA78C9F7D9B799D6F558B8D>] /Length 409 /Filter /FlateDecode >> stream x%NQ󇶶 Ҋ"jEEP.;-Z(`企$Ȋ.\,\aɯ9sNȉqAKH !ih8GbpB#4CRa9Z!Z^Ͻy.A>a @B%cS.C$]%cpR*}d=܄*֗.Z9V)֬Yې>((B?܃0`! Rk=a0 c<~ xaRe2mgbW UJ_mJ{O!K*[KK*?떖U~WWTXZU-[ZSTUgi]] u_Y;> stream xڍXYoF~ϯ\fpH"MQPJچ\:v;ǮD*L(O^GB~b[$"[yEXoxW}/^*JS旅W˕T? K&w,BL~ۙҨ]ud:[ӄխiblZ"3uYׯTrO)B?BM6 m>Ei"0YB"NgUr{]"g=-Kɗr?We(@x9OoVFjUۡD{#y-fC(As05zS[&摟$(^Q:’~$iI~.B84vm NGy boꁃonh|, u .uhJmz>ԩ곪>)Ò '[r g2IA }00!6UhHyjV0rL66ӗ,sյ,k+;#<2j7mά|:Pb;XZrƹꍂTs\^DYVoޤڛ%%ڊXDQ$<:D# (dNSiWs8LY޷l,FʼP~oDie6NgꚻeTX9R̡4̪55h l70s0 gK:IiLFtIlf\CSp^+(28;^YN;I%hoCĜkξ[0rڲ~YbűI(dZ,!1UCYRgv78qc|({ >;5xΑ)aӻF&n$Y zGMexlF`(C |}zWo禼8 :x5*%_ǥ=x@z>H0Cx `̀O0P!r;w~ƽ[z,M(͟ z^qt@hw>맍fML" w aEqQJ/Ps$*=2兀-(yaxS?,+{0 /$41aL̸ U[L19?KՎF@o;!}n 8,!PX{8PF*ף)Ϭx,Lּ1īF eJyUI%~XxЫK5-dԊйL}n޾ |Sx;+Yލ$YV>/3ձv49g+j|,ae[CO-'x"Ga6s%x.iDxG""idIU8,g\&'(^",@d-GUEr/^ngh[x"yŐS&nkGcv7Rac\:cE5\ߪ^aj\> stream xڽVMo6WnJakE}%=l tTJt­D:$DLГ̛7#^",8_l '!uE|.qTugm%(henq-E 5FCgq:Coi}UXFQ:KG5LbR dlߘ+ޘ*s4V!+.,qOGlI[R*z9y3[Lo8R.f11G쨢?3r D1`4i"\9U9V3rv/ƃa8;B\@LjN$ &9KdCw=7Z&;+{z(gјiaRh Ӿ.)YSJ1{{"z !Q|f1$ ):餁DG(G~UsǵR(Z-r:[!> stream xWY6~ϯ0}5+VHl#@,Ї`H-TE{gն@,9f8W~JYyrc1WQ4|unnEv zk[X>\[uQ@c8pƓhZ]hvlQ5P3(I-ޟӄn4hQ02ɫa˪[(GeEuȶ+(ˢ8{&8'ﴈIM/etC7oooD6{C9D#pqbyhFԹɢJO0{ګ:ub/-:+!A?=|f-6_2ˆ:,ߛ$$.>:6EYo$szO ?TT&0,w)uI̬(h_IHsA&SZ:UAA=y1.~X@CAÀpݨ;cf(_m>@P7agcr;wtйxӇO1vMzI>paCy,m3,CnmAY3G%hOk'մzIakƒ 9$}Hu*Yo|?h64!%> stream xڍXYo6~ϯX}%2)&H\.HpFZ-}Y \Ծzeo2AmDś8EV˹}  ^Km|ia޴3HQ6q^A"M9A(MLs Kvݵt=k?ǾW*9%J["Ã<]D*51]qՍTme>&'R$Ix[}~bX XxR,Uc5^Yӫ"#֘J' 2EGC?ewS =qd +]─hIr7p4 }WB2ko!0yV2"N&ּƺ!SLC*(Ǒ~k(S9x2N8!KTnSZ-7JK=8D FDp>x4d_*\/I" F78TeAtTĥA)d~r~{X@LDbߚDy&X*Sn" /',w<Llq:aQ#z?s?PXwA4$S|7V׋t)ѾĢLbja9~YKjmk@4/\ȱdGA]Dd qܑxP=mzzjZ lmQExCA'躲Ҝ*,ȾB<3j`J#Տ{{V(,v tu;{^M[ u(?,P6D A {ڵ9̳&* ĘkJ/Ɯ ؛=kn͍ p>J}VR!0 Og)qz36-O"+jojcS#6H0-i@s`toW%gJ#0dӲudIJ7$0~bSmS4䭩̀ec1&,wv0I)~Hh鉏!B}W{ AzHCV og5' &+֪z -ai>JkW̕EW)mvO/h׍Pȩ̶Uv7aSTέшrDX (Go:, T9Յ-/GGhzQ0Fca*)-ti&}:Hť U=r8sFN'\Oە/M4nڮ֕wLeD&\l|Y`Ls=y4gGv8F4m=?jN\E Wn|!>ZWO߅MaY~9mvp7}2Сa Tʉ^z){LD+y98zSͽ[6ї6}<mkÅ5ْqM⢗Z[%|89Q)Lsf=vVߪj &=Durh=D٬V>jOpk~fP+|N^& ./HD&Ҕ2x}?ކ endstream endobj 42 0 obj << /Length 1592 /Filter /FlateDecode >> stream xڝXY6~ϯ0X-)@ ll"@fWʒc7P7rsjH|srHGO/XeqfY]V\bzeRgLmW#h#D3k(ca`"Yo$Wpq˲ͻWjyiMr@K5Ci3jQ 1Gdь,B#g͈Ii戩& |1lTF儨YĐtDL׹EmK\,I˾su%Wb߿w?>n2(;}z)yRq xJ$EZQضVڮqYu@+"4Euf- [*'Zj/ŲFi8  vHw(Z"nRI9jMXփI{vRSgͻ }l(x> v=_ӝO n7MA+4yW7ϻNLQF E0Kċ(}gé`#CraBb:$2<S A/?[ Ϫ1jܶ3In<>Ҙ?R$cn~PЩF`/Y3'2NօCuAe$؇S:@kб2Aۋ/(2,N5ְ3?yG\ J͜o؞mMߐM|m z6RX8ԉ,Vf׈UPjG 1F_;o`>2ZWQy}8`AzlV &`a[ vxVv?#vj'Ic!yK}\2]>d"x7>Ć=ޗ> M2\D_x=B$5\'n3xo-(mFTt:r1N&i|;rg@5F.E@C4zVd :=LO>>)<͖ %,],~WG/HF endstream endobj 47 0 obj << /Length 884 /Filter /FlateDecode >> stream xڝVO0~篨4_AbCC4iHT{44ڦKSq%AlO}> $d8Ih H-$6ˆ$ H̅#J ")p"7? _'dQ'B84" `!:`Lc֣Ѓ%}8q`{0ՃhGM"qBpfuYvҀshQoneΊ|F@y(O5KDcFPU)(ޏr'_'Z J[i],3+'pONGKp6GюUl? q,tN dAKeĪD1~fYZǫb][?ݲ>gżr1626e{w~i Vy(gM8ٜ맼A}k!{gAƒCP`CJ7+:WCBG{ݕC HJrrJabR5 %ʝî>&uSIt/~J`+H;ZE/bcl4ZN,pC[݆jy|Az=w>dLdpvhRyHeӽ{ga v]߃HLK;cEpxmG:;AeHHOf/s(l endstream endobj 51 0 obj << /Length 979 /Filter /FlateDecode >> stream xVK60=@Mh A7hѢfQȖjc+/ɡDڑm^z|Ùn{U2IjNJ0$+JeFT|?Yo~C [?l\m8A)c !(ʤRe F%$Bdcb$q0K74(|etJscɡl.uʒW Z>vYS ^|Nnn@ڵk&Odq=@f ))RR-ܟ79 i>׆Z7õho = L_`];@Epl N׏ ֩?wXv@g z֊I$1_Hԗs|RW(c$قNgyHlBr1!YT)&$K$eaWO<{*m?hֵMx)Ig0vWv[ N0Enb0ewΏ9zDwt&MLv0[3. nX5?}[;qZ]XmvsMP~6Z̠d90,ZQxtc<~8q ,.q8913]5 gƭ i ן^ _0 endstream endobj 56 0 obj << /Length 682 /Filter /FlateDecode >> stream xUM0﯈Rxi`Š.BٶZ$͒8 {ر%Ayfg> stream xڍWr6}Wzf,$xM/3n&$^qd20 h R&$n]`I2Z{ٳKǛ'OX*"nU~4K W7Z}V<ۼybj~$V劗i6ZDiv˗f1 SpEbe:ZhΒ̜$f,e,CX3͂sAÉR|S\TK5HQ)sn)N2o0LhҰebƣe}Bg9.>KA6ZDrBeWQ>0z(gaNڨ^˦6bI;+uu2oP!'c^ B,pPIR^Pfz|ރ8 yU_ aj&*T̸naS;w\[ ѳhw'R񖴛JCW-WQ{Yrvh56)xhă{e~~/l Ln`. spq x yz(a~^ۀ1ъ",T"yG X'ċ-w+!Qh3`92iWγL]ϕz 3/o85mTjTGI]j$p:8s0?ʢ5#>r״V(ÑƑ"Vh.!P_ԥ ^bظA, \[Q:juKm;.25W@פRhKtp!J\Sc pXX u/Q"Z YuZ(J XHif%)ƹv;qk ,cZ9PeU)*8`ծ]!'Q`tXtsF:zF,𡿇yoᾗXh 88ЯPK=M)4t ;ъӒ;IaIcv۲7?lpu7pD/hߘrv軭\ V߿ kR(q̏@N͕ +O-֐Seח®iV/7wl ݉=GTkЧ4I<;_>S,1@qzҊ${zgctXocs5Yx"lٛ7;ڬmb(tsDovDmkr&$pF[[IH%J&g.ձ>_{}g3_:Lђ_ûEC}1'p,#N vBxVϼoTI~y_l1-$a5/ܡfh_?Mnn}|w xT3:_<<w`0rzO^<Qk endstream endobj 66 0 obj << /Length 775 /Filter /FlateDecode >> stream xڕU]o0}﯈Pqm04LMjl/͞*rZ2@0~{|i{uY $Lf @,Y' MasƐ++D n &Nr@3%<1;{]>o?V@&*|JxC+c~eYQyn];Nr4nb}݄7Y-Cڞ/Q:6k pZ"S6,4M&ao[soWa6&=x#{ ɉ(:$2BZ9TUŨ+Bh崷< CafҨ 8icNnJr]"~|a9IMO%#U];aE2- r ;../FǃIh!n8ҼJS 7$1᯳xssaD{LG ex~_jU2eum(|"[J&_>Be>0qbg<1jq=&Y{JhQ˜HL8XrZ I `H+!ŻWmZ;(㝁d-|1t_f:GLT&`f\/c~QF`9N}q%*@ś9n8@h,Ê8&sApLrJsra|ԏ/O> /ExtGState << >>/ColorSpace << /sRGB 79 0 R >>>> /Length 23737 /Filter /FlateDecode >> stream xŽM-7_oiI2ɀ`$ n[ojNF"tݏ=SoD cɏ'#׿_7_ʷRWcėodZ_  \^bzAڷ6Gͪ@/9z·?R0ڷo3}Np~;I;cx}_#|F4~~x~W_C~ |B+߮nhV 4*~t9ǷkWHЏU[u_{Oo?{}pϕ]Gq>f>ڟnK>=s_]K|.?\|ӧ^$zCO|A\wnD|-ER%~~ x~D\sﹶb仯7_sTf\>c{}37ڎ>Vjg_C+c׵>Vۺ]KjG?Cy|ӽ<ׇѮ4 W<Ɵ=;ƞ碱٧zo8ӌ?=ciG~Qb83@ט|G~`t1y4|o_l7q^ۺ_ ?.rc5={cgvl(+y^M^?[QſW+=2=nu}/ڳ~oʈ}R| ,Ɛ {HV&?uO{:ۺD36|r|s9'ˣװu}4"yZxg.k l6}R|3[ m|ZtO zxƳ3mu.?$|ОmƘO#5gqcW`k˃lW-|f{o'\.nJojݲt /~-UQ炵ʗ{w߱l G+QϴoX_i~Q1SisZR |/>aexbeM۳LֺV0EAaW*>݊h/NJ[ؘ|̚¬9e91c%Zk/uEi{Ъ RVg~)V5)9|/G1s8Gi_ꊺ3xA&գ_z/> $m3E|~~/޼g̡h `X0ت RVg~)VL' #燏 ѣxzZ5`K]Q=ժ "/Ŋ$)׵f7mqu_.kB? KF>=CP&&G+ÿm狂Ϯ"t&Yg|_II|=|mOԷnqYl5mgI\#sl 櫡Y/}˚רmvEj9n'diAԴ8[a# }!%zm6s`ۍs: "5J+_ҺI>\k],M^}Y_vצ/$k景=үn+Rqc|i~~›!vMﵚV6$/}^nMϮy%Ch7-"<{-|+BMY;NvwξaG\q<Ӛe Ϯyn]kCkm`n ޚ\Ѵu1$Yҷ[wo|sx/LY`kgLG=D[sSgtWf/t }PvF}Î{yf@B?Y3m\}MZc.~mϵh/194o1mwvEj9ng 779?v#Z*|~iK$oL?j׫M|}v.q7rRl~,v154iu{4+ګ}>T.H4)ōyzg WK{mF߰+RqR}=3H!:%7BH8=׭Hs s@jԜ3!5R3Vܰ q6 V8!5ptƎ\GBj#+kݟ1[)G 5k+M͌kBjR3/ 2w{OĘHNY2Rc{o I3~w4_4D$=H˸ID"Ic<ګߢ/1lm$\ -0F\AŘ Z|7l }CaF_nS^$ FmwEҌ+H"iEZ}H`\F4$ h4ƘHCIc3-H!(*fٜqK$͹Ak6DҸ1-_&i|YtnHAf |ok/HnFڳ1-F)F%m%1+C? X,Q1xojՄD/ź4PahbI[Stק.$V4Gt$Mo"il.xn~ i`%}Okc¾iG\qo$ K>fY/K |CDUQ\onqo$ z>YSI3[gj0)#_HEх}>R"idWGŽ4اd"N,Hٍ/4!}jc߰#.w>Ǝ޽r5[4hMWV ;oڋ MJ}Î)4-Hg"""iW Q^"i$ Q1;o{'i|o34ͦY=vq)4;)C_Hd48o]]Io|s;I]7,fhsHv'eRIfQ}cng\Ž4]OG%Y=h=#EvW/TGמRz^J}ÎI]fY&ťL }%F˷L鸔I|s;I{]sY֥DIڝ$Sc[-vfŶ7 9sL4ˊR&ihwR*NiFז\jT߰#.wP>fufHŤL }%x4;&o[S+mR&ihG\q$dY,4#-E]h}/K5q_}D}q1VY4Kct4n')㾔퍤vOhۤ]o;' f₤ t4#3IЬS i s4<|s/&j !t O>! ;HB $4 %l; "5Nyg׌ iy:zh C2Dfj4}elaD nMq5=Humt`m4,:czӬ`_LDsa (ziƺmiL0͵ ٘"`jO3?aN{{s8Sgnx8ZkǙTϟixt+=O0#`%`Fв"Jip~E0 .[ɖ!L0 Si!Xg)?c|wt9HNn/y tnB.T1ǁ[v+R̸㓩wnB֒>"-V6}R|{ZsH(|0{L3e`3s!z(GNg#ƅ/ź4SZŽ lVOYpQnċhUW/ź4S;BO-{83vZ&F0G܄LmO"˱0MO2LsxzT.S d\0 υL?RS_p$a)<E*7L3 9{i347s1+a#L3k6L3fiHY1+3`ɚ#%Y]4Y<ٍ/+4įh+c߰+HQYg׬l$ι_:D){S2@#_ILBMQۏUmc#;o{l0d-P,i];]Zn4|!u]]Y }D@J슴W;sKtۯ!8..ƥL }!uT {yb }) rk[˰GM7p3oHP=& }ӎޙ_efʚ˺!sRfnhw Os3leͶ] 튴W;sL ~b\ RըxQ}îH{gn|5#iK(-O@ݙJ 5В]j[ׯq7ǽ375E2sC354s4+}=6)37+Rq̍oM|v^̍KݙJj;ss4D7 9mϮ#2$7aܒh4j-{.aG\Ž37%eɔAf5EE"Lk넍5s^)37+z~e -{iW 3Ȝ_') N_HڬI-ҷy- "5˰wCt@mo)ێω}îH6bfn^f\ R'e/Zw#}qo_}Î~e-Ϯ1dnazJh`GvJ TgC{|vjq̍onk#fCfkܗR%4-5>KWܯ5CЬ/kl) |5vբ|ma|bnЬaH 71f`S_I&Ň|eTAMo|s;s[YCZDRfnhwy;iZfs]۩o|s;sM`r/k3Ÿڝ/UҴ`nۈ8.evE+ϮS3"<1)37;SC_I<٦|m ;o2k]GdiV>JMt3HH71k,+θw{gnkcnY eY .7cyXԸ/$o;37ӎ 軎v)37#R_̍mIŎN;a)Ƈ `jN25&|en7 9'k:YDvCnL|!]BSFFS]{cnp,;b_:D_7#15t M{I+>EoiwƏt?f-R>U} WjQ}RmqVvqtfnmu pҔ^Si=\\}îHKyŽ37~5w07MnfMˎ0tLzNRC?NJqTeg$_un|.a{_wq!7>)\ pOX=X5U?](<24qbEX=? \Jъ<Z-OXX7fq]*eøY]02|~.A]*Pt3.գ_u^aYnI˩)$fdiυxP\kРvoRi& GNZk!emU..ev'e+Y[||`R&i`G\I_d[,_C* 4A$Mn&D8$evEZ+5g\Q=b8iڝ$QA؊LOQAvNkz4<6/e C2Tv$\6S$7ǽ4HCHY ;HRҬ32#kP$ |s/홤YϏF\ߚ]I4ǝ)fJ޳ЮHw$ j(Hc{Y}AҰH4f)_4"$$ ?Hz4g$}~4j.x4@AHq_Jw}Eo~48C3y ;HB4mv-նG7 9}LҬ ~hB]-;# C2|gҴfIg1 ;j){~Ձbj*@]=ׁbƗevy@1Kԁwu2D(_klp#i<ULg?@\٩\a)_䪹3wM[曹e!wsfWeaV iՓLk$ט]jz E3H#2ICלNl&i-lH+.j{I |)i4ȅOfh[+ytnq$)grY3]فIB*̓4u|QʥLЮH7ǽ4I*Ēf9lGFO#I }!5WKSKߺnjZ}ÎI$13f,ZοIBRUic?\2IC"q$Cdf!hUvq)4;)C_HWdҬgۭ "7|s;Ig(]3/,-5t24 NW]Pcv;vW ;o{'i'4Q@NT4 N*&QƪmՕUnH{'ikF4 ti4 eRI }OiϨiaq+sL<f=mu\$ NE9ijdYYK]{'i04k2L'JLv'e I)%_nIq7ǽ4~5+ ha ueI C2,)\鄾tWۗo|sIϮY,+R4I#2򕴓4^34I#EFkE_:E7: #2Da"}ыl{nd߰#.w?O,ŲD]IR![,!׍ϲ0qϮY^4NÀ$V܂f:|i]hۥLq7Ǎ:PZ`':)[ΉLu3& j\){jm$z>tXTRR:̰'Iuݓ:P54aDҜSpiRpoUɩk!YAu.]yFҬl54uڤT.)CiHT8\ǜha8A`xl<^WJs}X-E߮H~m8YO_?MRwZ_5VBw.їXj:P$?cf D+ۼ֓oJuU+ZI5ŷׁ{Q&iCn/d^ c1:+?/t=PR,,@HZY>X7)vN=-bJ"VUzRo54Xu{"7o=>iexbIʇ+hv5ک"2ATT&#ݫj3ӭr;IsYĮܢZN>E i*@*V&C9*hAҴcPOX^{{ꚢhR42N`UU )h`4h ilA$in@Ikh~)֝)| pU TƂD de-!~R4~huįᕲIՁZDLI$y'(H$M$V %Ƃ92IՁU$McH['fzVZxOhZ z. "xգ_:Pu'ijՂq)48Tw~:P%H}TI-uL&iN[fyyvq)4/󋤩#|m*oiw`y9hkq)4;)C_Hs'M fvE+g׬LFY+j4 NWzi,|dĶBo|s;IkLfIp\R! C2T^I9i*-m2IC"mN,64k.Ex)NU4 NUIcִ@}îH7ǽ4IcrK|uC;g1N }!@#zU+O}^U|Jg ӜV?4/%eJV\s}rbaWI$#4cIڝ/&iƕIqef\ovuefHS}vIcùHH5!pj[ 7 9Isr(UrGKHRNL\Qcʥ]oE:JYi`ߥL }:fNT:l 4Id}{'i8 MD~*S8 C2S[4"OeIĩ-I7ǽ4~5wryD>0;)C_IL&' i^ IgBv3qHpINI7ƥ |%?ݧm=eθwE(VX),W. v2RchR ޙҩ|/xjbgI?w~fyn[5h2IC2D·$m'$inCf64o{'ikeP'fIJIMըK*H ;opOLƲrtTyǕWv䜁/9s]v)4{\qHr{' t'DvDga&QUN(IQ>ʝP2JҘU̝ԍ4(ͰC(YX45P[(Ay1LW2fu~BhDV 8_uGifQGuU*YvheVW=ֽ TQP8L 5)|VsUu*Q'ZM(O4J+3Leu,@in0ﺕ( N%EzϏKTՓY]' {J㓿IŅj \|('k.JC+3d54O(^\H( Fυ!dKvxڅlOX^XZO>εj7PSKW*5 Tb#jp`#弁+G{~efzd^- ˈ)އj`GNBB~^b]4v;r-EMj.V+KLe[U}v2SrdyK fX)1;d9{j|A5Y fʦzL#1^R\͸lƶ/vEZ+W:oY/f;s*S 4TvfX&ՑJ ";\ }sܯZOTPsY f ͗T0C P_HA{D _c0RafvUwWܯ 5]uEB3`, ? 4ĺ"JKuE7 9WάI3YYdsg) @_IGgAzB}Î~e:*JpYb7GmGBGu';Se'Gf=HΛh "][ܯ 5ef8T,|$j9#$k;s5{"a4ʲ¾aW|Žs5iz*$iWZeXIT vr*3Wh!mYmMWC"5S{,ދNJ+1 4~?5nq}Î D{,Q%f=K3WxiTM!q7ǽs5љ!ؖb |mLʜ=з6"RUpcYom7jvjyi;sUmj.K6vfKI4tZOU$|,ԄϓO Ϯ鑡"*evf+\M5"j[V7 9iQ>B-kq+=jݹBu#|[fvZԬc߰+:^qeۑ2m91+\ f I0Icskm=ƤaG\q2te ͘xȫϓL1$dRsY^m_ 7 9լ"=:~*A`chwnJ5N;RmnCo|s;WA]s_b[VCKݹJ:™~ws8F}\ang\Žs5~5mLZO3z%vF<#SOXmUSY [͞NO j.O8 j7ZNPSADB߱Q5 oJ=BvF$ߩLOK^pڸTZAլP3zZEܼtFנenEkP2mv$QTO86\Iմw!%v'lMjj*dhjJ=5& 2Uc)EլvR5H!fH\gP4>v)ʳRUI>)8Ŗ|ԓ4&*tAWi(sZ|P3w2F ^yk[',wJ=u+2DAԭԓHJ=Sԓ ,?߅/3J3QVm:H>Ucڴ oX4%$GVT;UyOTHjp\BP7.dVg~)w'LwS=;z:'UɬtNL⊶6Y' buA$Y=Xwn{,J=J=ba jJ1x4>̞sROsKPcɐp4g1zt *4reROwIxԓYt9)ֽ3,GQ['hƬLAjD [D(diUC++uuj|;]sQ߄M9'Q(xYCLa9uҎ52ZX5bN%]ZjO.hV&1? mj=K?lmjheN~ﱾ YO$Yw!5.$V&iiՄ<"f:a j6VWR q4`VYeU8C12s̒ K)A?aا[XwvFE\ЉH_`ߐT ˓8+ľaG\q/> [\E1/;C_IG6- m8WRfgh~夹5;.0c^ؑs. M)kG)*goi)IsР0u9ixN9i̮3+i4ǵIS"'nu7.' +VDN0gvǔWv9S%MrN\ |s;;ϮY1/ϔ7Fh啁JbjFߕ1ݸ|sܯ4U紡Yg cj+vqߐxvv3.eveV0'bgf LLf" @bgDs>QSi^qؙ|T \*3|T_5Qf : jR>* "mm,sil]˵2t*Ԩ蔨HUII3gTX m |C`G&J²O;_moojo{gg|;33NQBUiw^^mG* "m+WN3{䅙^HO$+;r΀t {#DmwԷnqrbRƖ4)+:&敁=Ф4&j:}0hib-2q̩ǎN=Z s=yDvgc+ث;|#7 9άyO3ϼDu'2;C17v-C$ M"=+ϮCʰgRtP1T WR/!-_틫 ;o{ggk0ؙ2Y\ WϜ,::sFߴ#.7vG>mW4U Rbgd76FG٤i5|$h-VnH[}Ž38욡4G)3;CߐxERgb[}Î}0%_3pο>H8j}ɾڮ\Qo|s;cOE*U`ٍ/Ky)B~]=ŶO`߰+cq~I"W47RbgdBcI3q7|s;;dziN~ك:c_hw6p4 v}(G q7ǽ3~ٙgvpWÙD8B1Ԃ][Rbە} "m+c^ ٹx~D//4_Rv[;;sh/ɯ69?ڝ/$NV jS݈}îH' H4#ؙ d[=':[e8-ΜH$SȎL8XI9irҴ՝iGIg.Pf*M1NG Mc*爜4N8`bII3zb$mFNqGN|I3mdZŶu1i$ۜqc4E *ı9rɅh_q 62ۅV#Ӄr`٢7ELnm$m̵.~۠g̕H߶Vsi =cjeogN•ge5tzVcBϕ\QfXb&zE%(VWNtfbIi1s^[JOX^XwzfCżExq( n?``u>$v7Q'$t+q;'^9i4cNX5ERXY(Vf44Gcsd*礱08yW`:-g Bh-*BghexYP(4-O打Xc/d%-&y`H6;'M;4N)' ƬJCs4nr+a 天_uI뜓Xu)V@SSW~0 #4렏mƳB "5Sc]¤fƥȎZNT4՝[ר*Ж=' Qjjp!X&Ytp5鑅afq5^mG" |j^R#zjGԔdR\͑k=vf|Ib'+1=}s;WϮJQCqIݹJHDM[th)evUxlq\/3WspٖtRSy) }!)sj[OLoi9^q\/?fFNuKݹJy44ks0Lm=.wL4sm,ڮOM6h+B_OͶEUoWcڂ{j|$s5k1:m%ؗ]s1n7_H%:5(6±o޹\MIm|h(1;7C_HAʋ"haW~z'F LoWp5.evr/ SQiWոUiW{'p۸+ʙD'HWSR'ze'o;q5+cNpQɥȎHgĶ44ya,'3@ye`GJ"'@=/_ 3@}Î޹hN\2WCs3tDea\aC.zo|s;W㛴y~-IݹRRԤ)3|VTW;W̙1Cez}q)s5;7C_Hf 5|O#1Y]o{j|skfzZG2WCs3Ļ5o3m7>`a,B+ fW31@p`chwn ?Fsl;8 ;o{jP"s5 ` N?U1;7C_H&%1÷19ڮP߰+RqCgԜ:?MZGs<~9uVH6vp3Jhv+vEW{N;Σ3e䅹GGq2{BдIsy3ێhW{N?~*/m^{ C^ؑs!沪' j;o|s{N;:jnIg`9g )C9i2۲RYIl̲qߐJP8ésaۑ#}Îw{j?s5=K@<=:z̒l LR·yT}îHKy\M7H!-f~ZO9ȼ%f89iΜ$"08B!M/OGkJ9[;nW=RN9S[4I<sW4*D._ISX h]^Y)=9bX:ՓTF5\[[NQrNRk5Us='͘imDլl9'.'AL }=2USy@!qffKj@-4] jfjzj|'f&ƇjjVR5\8j-W' (AIG9iH$L׹|b\ J1C1-+'M{Q5GN㊜4F՘,KE9i9iFո$M[|4XxJWIs4e rf\7IsISR(,3Is-wNdN+܍45Up:)GN39:䤹RNr;4=夹^9i l4.ew!6'gGiF9jIsIr%塹v ~b4wIz+IsGN1A M9i3(?rڽǺS5RHK"\ֹ%S" JRs֔gx!4feTbL̿0.n$ԩ^*):Ww<85@˱9i& ^PqtT]j&S2gճυɃ*^lu}/ź礱Tj:R*K"t jHoIQr̜fFI+3N\RK_j2NT>6gj>Bz4K9ilwU~Bjh3 DڡhbݨZ'Ʊ]L{a>ǩZmZA?HQu;CVW=='sQT6ʲ...evO<W&B.s\H {;>SbLk<b fX)@8öcb߰#.w|W^]Nͩ2# |%ۣƖWmUMq7ǽ3jiωsu)fjnʹ>DZv/$KU*aW~)*T+õ}U$ig+ii.۞e)v9WZKe*Rt+C}2L-;ҥ2QYjT ".ɖ0MsRg`3)I>< ܯJ@tgD4@+67K:,wMv!aG\qəϜ#3eWgΑsn>sn J6A:gƆϴ i3mgxŽ3~2BXlx }!bgȬ𙛏|]5R 8bT/i" 0#_HE)#RlT. )q`W~ߥ[Zߥ[Zߥ[Zߥ[Z?LK'fGZ#馴4hoH )-(9-Mk9-M{QZ־RZqD܁T/ ij(2+-ݳtl̺_/ (چȮD4c~QY{QzLR g+"m*aC_ U3@}ît9?*3XT;ҙvc I+f]5tj[+7슴W/|F! L9G ,ͫ(Kg`sFCi ֹ]wiitJKSY3!ii̮45o;3m4VJiitJKRW/|F1/i",vʔj(ԤIhZIhX14_;|J/}îH48vHii--"- HKcv94.CSgNKӣ\K]obB=>s>,m$k! 3{.mt*7a<s$On.̓͒<3\\dhvNVT8*7sڟq6ʂ[E KVr"~A#qq{onl~k>^s@_K>{sGkO +u֟ih}2Ub~TAZlO"˱o}[ѷweRݎ+5!o(QaWgyje}VD~9Vkꏮ,3 %Iq:W ʅV]7~^Tؚ~U gnE4c#s\ zgZ7>t{ 魺o(8֪~m};l`nE4cq`;Ð׺A۳\Hox3G@űkip!UXX73fa)%W͸5,gN. +9ӰVT-nzg5&EOR)([uތQ^R;ӰԎ4*L[Qr?p;O:RPu%W͸5,ԤzD/Z=_L[ooG3LAba 魺o(װT4,3| K"+ KlGs?>))F KkgUAA QQҰ^K"+%M!8K"([uތQfa41*ǰV)I1cX“*DȮq? cVp K+xV}X_6:)f KyBzq? csPվK"ÒZ}կ_k~1\/w/?Z_/ӿeu47llp\g7H;;\ڻ,{ ;?Ӟe{;w}twjk-C~?=Ǩd{Y{ǭ[]ir6@ivH/e 3%R˻ ƒ endstream endobj 81 0 obj << /Alternate /DeviceRGB /N 3 /Length 2596 /Filter /FlateDecode >> stream xwTSϽ7PkhRH H.*1 J"6DTpDQ2(C"QDqpId߼y͛~kg}ֺLX Xňg` lpBF|،l *?Y"1P\8=W%Oɘ4M0J"Y2Vs,[|e92<se'9`2&ctI@o|N6(.sSdl-c(2-yH_/XZ.$&\SM07#1ؙYrfYym";8980m-m(]v^DW~ emi]P`/u}q|^R,g+\Kk)/C_|Rax8t1C^7nfzDp 柇u$/ED˦L L[B@ٹЖX!@~(* {d+} G͋љς}WL$cGD2QZ4 E@@A(q`1D `'u46ptc48.`R0) @Rt CXCP%CBH@Rf[(t CQhz#0 Zl`O828.p|O×X ?:0FBx$ !i@ڐH[EE1PL ⢖V6QP>U(j MFkt,:.FW8c1L&ӎ9ƌaX: rbl1 {{{;}#tp8_\8"Ey.,X%%Gщ1-9ҀKl.oo/O$&'=JvMޞxǥ{=Vs\x ‰N柜>ucKz=s/ol|ϝ?y ^d]ps~:;/;]7|WpQoH!ɻVsnYs}ҽ~4] =>=:`;cܱ'?e~!ańD#G&}'/?^xI֓?+\wx20;5\ӯ_etWf^Qs-mw3+?~O~ endstream endobj 89 0 obj << /Length 1839 /Filter /FlateDecode >> stream xڍXKs6W 5x|8ML&v=$$aJ*I_],HI6\b.uyJW+Rn6+S%*SVVDR7o6;'O;۬chYh[w&5nV2pgzzRBC1m7aU'^JH &WWWPM;6M}P/(U,+&AUDRm5"u?n蟭O|`;8$զ0Q0qXD}0o~%cTvhy Ci$~~ٛpweX lUh]r\)Y䁔];NObsMY RD`҄L/.nK:&F/!ަL,f k&dz49'`ݛM]_!DªiR>/aU,xCҤ8ä7{.ybn{e[XX<*8,_-\]]&ױ!pyiO’jM-5_NQ|R0l#PҬN(+0$F2aVMH$z]uXfG۷cW~!rQL_DQej /!Kާuxp(ђe7hć'm,p+MHZ? KvdaCgɣ<3o9 ?c![R(R9\h@Q8 f jmu*Uh|6cuI'ӳ@_k#0e9EAfىSrӲ}+|K'[+PƉL㤒b&C_jD1Ӄ#Zc}/@3%[3nC3zw B̶i!%1;D[pѾY '.+5ֈ;-l',mm3$bhlEұc𵽩LW-@LpyE| Ӥx֞k .63@bE7ZJKp } ũc=ӎCxW7/rӰ02-t1O'p5W#F&'Em*f8c('0r `&'K $B 4]qV@ʼnчq< k]p+^]@R@fPIj0+B>Jn;5#JT@Q{7wgLp}Xk_9t8%~myKZ@໎<ְ޿drGOBKMa3=[7.ݠZ"p>,'- KuϱHpVdYƙDZ2 v4pm7XXs‡H>2H竓y;7w# MJ_"zm- Y7C N2JLڦBo_:DiE(Iz,>WGJ߯vg>-Z=z #`byFXSީ!󳧅C&2K5 v @9\fJd1T  SXO>gj> stream xڍwT6 EH'* &^BBH&]齈R HU*T^{gfyf7tydm0%  kj P'fe1NqbVC GC`%j"\jO HX H (1 n!\`hbVy`DEqr:Pp( Ü;B!N}x#=sww8y(;)n;cЃa(7 d4^bVmGb!( 804剋 Wh#a. ܀?U /gpFB\<.v[ p .6WDANk,W.O}h( Ġyp`YF sS`P{i - 'H>"7f"D0Wjw e]|$[n {!n0A X.aS V~ 'sl.Nj1XCG1ןeCxy}kB2"h)Gyrg52M1vQ} ?pY!oQԔx!]/ҏdyzJ>$e<Rgx4`p_F0/\H6%$ƽtFsfRk JJ/RGݱyn)k (FyH-Da(N2|ӶAbA1&9V}gs4%ܕt3'atT.&o[m B|-b 7]/Z8=^?/%p{z]=}lQ8)ּM̷KѲ[-0q^PGSՑDPzcIw)%2uIA-7d,xKUwF̯X|_ ?ߵYaP#ݷՅ ۘX,ȴK"oj些eaggL7FC7V-~,dgm4!H.c1F> o%P Oy8b4Jk+ , ]Jn3Gv\ioVE}lIz:ͭ|nH7!_WEwr CZ(nL6}c_[VQyXo (s]=~xS⋊ILUu77}xX2gXScrTճƈp(hr$Y֢=,#PKj,^/#~)# `S2e"r{R$=D‰b_rbVhRINɓQ\#_|[ͿFKN'>Tk>~eU8tdЁZJqܱƿqwFl[8Ì%f)Xe3 fs"{}&3"ڪrΚJjRR qxYAA݌hZ-Nbal=aS0/Ԑ#W#I]"#.65-&4$wvs]}fJg;I'ʝ\*\%4@z%>74t!ޤx{Ƶa\fmX_׉:hKeF9bTq x'FUl WinATy#c Vt0EIBF>^{K);> r6!^SI5UӚ s *দѫC޵&<ԍ~q8aPS׬kH-FKi{0r[B2Qn!^ Oϻ?4ex+'LOf~ļy&j rʋ#cS4}ɃWvzPIכ |ͅQBW$|kbMrɹl٣C'@sUq~OzK{5`|1Ǝ\9cdLQ2sW?vܻ8k_^r ӛ}k[]L\щfA9wlwbB%sWٍ?o v&-Y!yf0*7OWᰮixe/*6}z@œًr}0`A)&cQ|1w@ 3pbz8;OXy1"進dEMʌf8Xܱ %o\(!QhKJT, :UhĺOfPGk)auaQ{lƷT3zSޘ}nx3=-~es)ux2vB~Af#Cd#A^Pl.392G 2"rÙX j %^B^,osGH7;(4Ițp+| Q̓ʊlwB*譒dD"d4 s= W2ʇto CyGVB_fۅ+Ol**Y%38[;.^y`_g C^h+olvy'I2ʇL4{ԜCHAz# nJ=ynQM81ҩ93cB%h6^zq75Nu5P* £{0ϛ<гO|t|qI 3g|+#-}-Qf@ӨCl, T^ޫ`Ri{ ~ DcDo>}[wΘcY%i'W0+}xyB+P%2so]X#egͩ'ыIѻEÒ(wpg";D +_?j[bw|TL]")-7x" _ތl,M,'Dh]s44˜A:Tpz(}pn $yX+o{|qkf㭪doPqxy9 %mx-ianSxsfXI}}`Vc\7^s#nouja8sCqҪI,1s<Y J%'i7g]ÓaEe[>sRr ?IWa/pOFb !xCUW ?1aL.T9ὖ~o$gG%oң grQUT]L'rv~4-}z"t(|"&u +?KfIKiœUu Z| ?h>I@eAV(#YnD,'}TɱZEkoP\/.%;>s8:x'uCpЃR$X{V"$!SR`#XjDc=X."i- *9S>\hfj›KMbש{=g.%L.s>-m'C1WnvYoם-;:y!~y-AuUi?\Fo.:>ُ=Q#W1NO@˝8f ?m^q^=N|ٗ oq,몚Q8"Ԃ|>Ur$zq0Dy'I9׈rh¹%I3+~K> Zx^f(5 ..ՃYu40j`Jf6Ǽr$ QvnGMaK7~4"nsQmѕPYAf$dܒoK _?!M 7$"":'پBT g"Qdw UN8AU# ʰzʼFe, #w3BGAw5Ha[eXWbo_8!bc>MVyVdh|7*˴A"ϓ~0oIw/h~0<{Fz]k!Ijv6WGb}V6&Ϙ|D"듥."Y;Go qDˌNF0 c~K:spxTJ3i]ObOߒTA5ȯׁS|룠ͼ8 }4^Xc G.z>}Sm0TiXхvw"wk4٫5ecw^ᤖDsCG@h w^h fNJA)<%kO(z! gJkm&uR~").8~+ XַN/..$A"15sUU( GŏgMev"T߁&^EFA;p^V)국?'^]em¨]61#Ȯִ8ݫz 0\2gfD^S?Q4Oh =DZۜƉ Yw," )DQrޠ,ehz$޷H9fxgCy*6 7EIR#{M1=`-q\C7yܠ-#Wgj=l[vc&)(7ťWBᐄz)h-hK ?w6I&o 53J4iT^1Kx$_^P{T<7\iWFҩ5|wAey,^bѥYAMלRxF4Nt_|^STf kY fy̕M/u<\> stream xڍt 4o76KKuƾe7}:L !"Y"55.{Y#k<={9;_}}>77 Eo`,6C`j@u0,Ot|DHA`@ ##|.FAjh /#@de~*p aXw3 pl?R)cr~~~"0o4M_C`7 w~ <&qf?zS+x Gy#|P.p /jpg?B߻ "+;(7P=?V\~9h|<@œ;Pcx'[54[@=<(7W 6{C\(_Cx^>pm.x?:78Ҳ ;Jo mR' D{!!W8 X<$) n?j| ~>F!{7͠&&MU Ka1I02i!i`mXm+-ձ_%?\h4_&}_qwԂߞiZm%it]qG&K~}k*oYɯ )/z[&%|Ý#s(ЯMM;nȒr. pC9NL$XaV2mA}:A!A7 N2nbbJG=8TX0a̿V9)+"be8Tuko;b j: !}YC-\6utþE뭧&d?9(j~VzMw} |piaWDž˗JJ 6SrOq؞ Mpm+BOdNaQ Aw@2ĭ6%? )6x77D=828wzt{;]\1_NF^c xPNt{AD(]/i^r{WfhiW݀[Gy"%yq=UᝪQm.Ū_G%~1]IGg0US%‹Vrf Tf7z^ չy u*Dۍ2SfW&VhxGp)CI]XT^#hܳi`+YbR|J|1;{Akl͌JĵItZ@~oƌ^ Hr֭Lc޶3t{ Q7l fՕb̿/H=y_3Q|5-yQ=8ct'FXnFc k]2U82a^Ί&F9rԼsg*uD*tz t8 iDrpɻqE/CG8pzWzRP 8y+ت>˘rߞɎ-FVUuRҮtCw6͓w2F aؾC- *Jyښ4s5bDCb`0d?m3Vm]ݲ/MÁv]7e'X;:Gϭ|f0Ͻ8řo=4l+2YQn,FfV#5`r.V1CR)m#..ϯǯjlֆ=]q,d̺ݣ.\EYX>T\xl<8?n+y?Ee拘: :*iYQ؄0UA.uHmXLz(I?"eYߘnt&-u6hW-A|=U/x:9׿y)W[+a/r?#8vL[#mIMukD6riȱY.+6%iqjY*yHҠOM|ƬQP$N8g2A&c$63FE N*gh} ڑԳg5R,ꯞKg7YdʆLwoخ.8SkTQa{/9t32gziwr)) 1ӧ"}ȝXZ@2m*Z A";6XO .JD阘cAg[igar]1MΙvgX^P6ϟz^d?-Q3LOsTmfa|l*մ)]ͅq]Emnl6۟.H'3%߷9tp;x_oW5A=iw=ӗ;͔`TesѣjJ mXBCq  %#á|$c vc_})p9{s0ɬ@C‡9Oi#iqDM/d4(4,5vq'B Fm\Fq#Q޲ф %l #9ރ{ٕI\#.eسZNGI!),h+>:-qxNDzUJc7-1<뱭񓖫PŒ{␧ϔAtBIȺ zv P>vRAuP/\#w}nD0ފ*E›ʽTsX&B~6w'K_y&a-oZZaBfSEQ'D:z9 d|)ʠOi* ]htԷ; zeyvd|-٩\g\M't-vwP7gRo|F9)=  PSc bt& v}m̈sr6z%<`_;Σ"M RpJc_*TK?F?CLw·݆V+BX p(e2oDv(%V0=Ԓ#$ZudrL_ju,KӳǛE0FaZQH-O*'5FXr=Y>e9XlCrIMp48y*IԫVymƾuQOo,thS:/ӓ^.n%k'EsPʏbze߲0ND՞D|!{:SBReIXRڇ%TUWC ʏkq|cy-8blUE5r_@9,2n}r:j*VŀXXTa!jҍ.NÇxG3RSej@W=c) o6`G4^Ԕ}"N-oto"4{'.<,x|یv;|BUآO8Ij${Xy}.WZ 6]3aw]0/Iџ}e$i +Mhy ojݬ,7y޶bd6ِRsf]Uu7Tǻ@뻃um㬅1Ŝ$}#k͢~y6ً. 0Z0E)K%M3)RdFTwk݊νM?ZiQ)+t&ϓRv]ae"smšr1_FdEkݴN0k"`\gf`6_VSڜRN!x+baTKy*1ܵ/vZީ/oX oBz}82I:!ވڛvUo4}$4I!/~RaE Qwo$CJP1?CY>d+LȊmfE0+E?䷆6zuD\K9ouER%Nɹ*$؝Q֣P(ވ 7+ͳ9{њ"֋]ک^d{^U$~IK?x_qQ!F|4܆pӺ:+jNf*L%=6 'l,2v~(B>) nvRgHܸoxr[N5XGs 73X13-vkI緞7Wم!3$جC"bm wz~7)m(AW )HM ,GH%\k "co.ۛEBN(bnh(;7!W o7|nYtL`qHo 2 JꈎT2"Ma˞2x"eB Ymp`-g=ٖD]> W=12TwO 2Khc?{ ͹ܺ^P[6ENAQUNiJ',pG_X/7w Wȅ=^o%lR`~4bƥz,D'v [ɵ #`Ow UV0gMg:-B;Q}O,f3@Nҍ#+mf̛];1,=WNaP?j*){0 a<.u-۪׆E{"v2I .ɫU~ QtV{<*.jWEcC@·B@O ] p]ai%R&oDC1[bcZF͌el֋]h)9 w G+5%#VI(K??qa:~pVSvX`y#r#/_DJ(AtKt˺ril{j'ڪSKm > t$ntoZ%љ[%DT:.SV ؅%R\=ȿboI_?eYO L;^~CbQOFs5=,fG"N@yqInDt\^A- -\B &%bR>S92g\ [ݣ̰ͦ0i:pjٲ+-ȿ~]&A&iyTV勬ZסL[W ;(@3i""7HțT^4<{ΥF܇  endstream endobj 111 0 obj << /Length1 727 /Length2 18768 /Length3 0 /Length 19301 /Filter /FlateDecode >> stream xlcp-YqrǶm۶mض۶m۶=ݧ?5="!uV7aa( 3i`HHM -l M8j&%{# dghaf 7jm`lacPs02p::dbp67ZX5$db*1[Gk@Ʉ`j05LN`j0SG;2@DNY``k 'ىh#C?x-00-&f0tÛfcu|8bm-k`c wq6q8"&&m`ca"$ Cmpp71prS]?O)?jlgk ̿щJ ihPg 535(9è rX{2Ύ-zWQv4&V8::z__dbnblgdR#R8[N5;B2}l1hnwx}7oȳ{#qDhkw<1Ȩz]!.LLH&9}}-@r93ZҡY!Ji;nuVB %Cd i<ڐuo $4/pKϼ0T3RHd@mG:5Q еEeʈ,9 .a+ʊGK{@XF%npE[e r)X# j0hrd&v$lYN&ЮzXC)!{r śV%H'/i誇H!WZTS]g6nԔ[=^93KlA|T!Z'9߸.o[5߰p rl VtP9p:Xvpw[ ke.fnr3)Pij.Bcvr!ۯ+N0=\'cv̉I*-&H(As ܼp DaNq@J h|RM\:ʛƶeAwW+3| n;2]THdl "Q$F%P$ My3t',;lyFoOKtiň"ClzA"D&yߢTwV> Ŕ{࢕SO\,/ܪm6ϑZ {h"wBxWEQt~k!<;6_׈KP_}wlm=_!{ › ʚkg=%887d/79FjqU*NJuzo tݐ7qKDv?~JyՐdkQc!+ 6pd-y퓃`+@?p`uzP0%cs]x݁'9BC$H&}t٣tzB,_ZZ՘)!-q֋2_!Vo+7,ZTVy>ʵ.ڐO"[K #/ lV b>My(ܹ~oBdB9T/[-h2o$nYS1g^K;kHE頃KV*i7XN 0y03cT4y #Mqjr|x2āߘlWy~9n4۸Xnr -SYmጂw̵%Cado!= dՠ<'> Bkhgݕ2pWdJ$nGFG(IGZlEL=:«.Ğ#"R*X%z9RbwO?2Ă'O*Lctzu7'ͣ8"f ܑWS-SQVzV$,a'Pɒ~iopA@{J-h>9L$aN3hL%"n QFsOEZG*?)<'[=jP!dbk +Wn)8MJ$0nI/k:iҗNUp tS/ ҇U:}ɉ>P2V4.uoPwإ7?7ar8#~$oX_=+,MscMW4$- $\׋O|u`: ]AUhJ&?]E䲲@[+w:SWh:8ᥪY}&|nYRQ̍V/o[r8$Zh kl9 iVnD%+/x hG|C [R+- osVkٙ.xAC`Ck-#`['V'PQvDbދuoiu>4[G-pܱ띳^ANxFIy6SK>@w>R:O4e돠H2g>"EV ߡ_ ɛdG5haDR3|CBfXVBp>wi^WHMhj B] B#]):RO#RWbZe({L;vNؤv"9?ow8(GvVnxin߫k*guq.}L{/C#mn TF ƛ[SK{9( 'U}G`&-[Dpԑ?MZ+**^0QpG'e;:܉!<{&f0k*aJD&u/Z%vAa>66usûK4voᏔ/m?^~Ƴx/\n2v޿*ti:~vZI %F pOpZuܧAO7y WO7{V2iYY`Q 'o|mʝZy3648u>8`\ `VkԧjQgp%Ztn%?5@*R(6J#4>U WGCR-f>iϊؘ| 폈)h`m7).%6K Y@>ʶL ~N!H9.6bGAjtW}]O;w aBz] SE_x&tTj'6Y⡻ͮ7ȯe w1O|6zя^='qT: Swp7ӱ;4 sf{_;FKkJصo/-IXH0 ?qœ޽Dji_n'Q-ZqS^,MQj [yQINU`qM;SOfXOSB!| L4I`hnQ|,8\ jJbوk1sЧBYiE}C?M~& &)!Խpo 4 4 h >Cf36On բXew !^ (m]>/YFk_H|G߶ۅ/rht[C rbf ud#$$|ںE4h(,' ( ߖnK,qԙhW` }M 2xſ5=LNAfj%Y .%D[his-'"bс#7+V,vmܯ :tgĞ{ְ A/TQ`ysı\AYq~ i-vd/~.N`Ff A3iEW+L=At̄[}|M{}:tSh|[jeV~}, [~s3y:30OڴስV16t<8g(?P;pRP4<0YmbQ+hb%?+`ˎϺsarWn kP)}ĚLuMh$!#ylYGWѳЮ#4 4Mk͸W H~|ם\u>C˜"M.0﨣4Oa;=;VƝl~Vݻ?S3EZ T3ƁD5FqsXvuM蘒d2)MU4>0ϣ߼6^a`~LO6;r@wu] 02a CF$r "|QQub$>}AKf ^R,}wɐ- ;v )LQrَJvofHgX[kOɂ$,\YYk[Ƶ𫬼E;P0O ^k2%%lvzU=y^=MYbؓ)ۇ**&5/MI-՚n*Gk L:7Q ""fSs޴ ' Tok$PFמN.J8vi_0YVIiUd 2?F~2OxNzpkv'9 CCE v4C/}[kaD\3 H?6_<㏤C[ÚsY&fџc%?kEDúW4˔ag~d#f_ZK!4 bʀ4p@l_|wLt`$Ӑ$Y䯃ZY!VPcziߩ)>K3{0"dA(硳4k&C0ǚ0kHgR^gSEa+jv=V؞@`a"&Eήs! [tMGˇ[mǾcPwmuoF/Oٻ\ i_7o6ꬖoD'-S+AWGSCW1j&BVS G"ck^-XV'U߾wy+If-xŀ7o"'g.a{':#k4tņTqXcS|=W̘01uQbOkQwGPSsWJ}qu lv-Aֿ/M H ]Xpg7xMhac=Uw]W(ޯW($.wXu 鮀j.pfbJn\. 0Qm/fBEX BQ6^h|hP@]s J;?t`R5oUJZ\n۱NyV%*x$J[X ,dg֋jǯ=JtBN]js3gvռ d4(C"4o{ZM'.KI߭`mBןJ"赖@ˉQ?:(i-: Z 3r;Դہ6+]M7'aT{Ur*u⬎<3&UZX8ңSo|sKB;uLK1VTdSgBZLH)$uy8ʽԬ0Izh:<$ PG/vzEm\RS}G\R -M?al]B XL#TskIuF~=$QK}1cͩӺi#~2TYk[0{F*b@VW=1SHӢH m 41Δ` 1 kbW o-WKE: A*mUEp ?y C jTRDK削"@}R#B+bdmH$bA7cIvDf~-u(RXF<tv>9|qͮБ=M=8e@YzBzU}m5eL+#_|˪2:נkjqMv$IUt{2htrj*nU}VIL)_ F-'Hl/J/8 'n[Q2(5!X<+L@賎LPndH{7@E(uԘx]e3w ruCOZq#N'ShebYNr;9Y>g_}vZ˻)^-{{#vwwom%[bFS2=\6ݼ1;7:ۓP;9L Ͷe@KyI= T?gΘgzޓLf:V"[kLRX'ܨ@2sQŴ$@ЊQ#I5YMƤ4Q偑B^U8)nא–ÐD-A-IhюT[:ſdf3*ycշ kƻmE g l;W*@Pd͵ I7 R8\LpCY{J=1/>8gH^tů:KKmXL@o,'; K*\k4x Ӟ~]3n.05D Iްh݃K3@߂uؐՋ}> нwMt.h c{x]r0 ,6.ϑVx 1өOH43hu=ڿGxVOנރlI׏S{ G!x=m{L~ P= Ay^ˡt-S^,VGUSDK)M]- @q;'0|/x*w|Lg. Ȳ\<42pYMsaW0˘~v^H9D^ ZVrcA  ѕE1564VqGD|nJ|PODwV5=@)%|c6j}YZFpfxH3J<I~Qn(Kktv7Ha!UN Sۖ>FHؤ,PZZQqi }ƧM%>Ѓ_y9m?fqr!5qO,UjG@̅"ЍAv^!=z3IeX뻟z:y5i}14N gQZ7 z[6Iiv73ȅ;{M "pN6ȎUuHX U1qr.c=(;,No~GIu=(WQ]Ey/*; ɞg'"fwd[S wF;XgC[(+O-oC2D(7ֿ~zcuUK(wSua>|='Y&z^dAg~{'%&Nam}.ؤi-@7IqC‹ɼP Ή]D2R^h.bU~ZPeHeL N 9 38,Ez:Zwx{3dB㉽9 pzd\ hZ"va6%.ȳ+Iq=kr%B`᠇1huu+SOuJM.Z ;M`h95l3aNۺΖUŀu먋 o =2EG NWfas@*x9^6]ђE0\!4_s&{kgzeR:>D@μ~ nwkJxmc,܂1KorEA@ *|Zc`.>*BҡZN <ǒm!(ꬄtjG{J 8Y~x+r$:$~rT"s{#}FlCd 6kjخA^^u<#I6WxLe6D^TNijʏ RNt溺ӪRJﲫCyɟ']2:[UUB[EHs P/DazDQ_XtRSZCvw 3KmM=K0dkrZӎƷ/K$tCmP5wYIā R\vh.,b2kMI9`}EGUv>Tfrpk@\sLaӎzt]Xp}\~V Ž场WUl6urBq#P0|R8Pm:6ҁ;+Y͢ή9p])h^,?Bh& ¼>c.ެ2KLgmqA{)ZbDgTQ˦JoޛEonCR2Oh@<2Ǽjn9^+Mi'25qAK{o%t.>'ծ!;^kJH=sa>rcö`,$ ;Ja.-',=Pܪ֘ HѨ(B%,ÞG+>O[Uso׽@`oyQ,$ N'f~0|!VE,@=PAdk祔-Fb!/_Q<#|&ɘcKwy^JKj`#T~a.֢xs2\i _Yi~0P :yYC{5`UA'3^E{4c0xm|  VZ7 ϏipYQ{v}"Up_*0 %D)cY ,䞘w>-&Z{2\k oBlt^x\db/sV;9Ud/ƂkL^=eQ9ްOK2 x>ZO^Xcwa $7(kn㢍W5ְ= 9{>f>6]MP|g] 9e hESU>_:"z Aq!u2t?$T7ao{0ԗi@РO罼5HPfS90-0 KNjHwdNg$xz%|k~=ܐׇ]-1(Il,+, hj\#R^ø](<!,uomM oDg",Šy ou502MPr[O*O&#X'HҞ TA/;+m˷WZEθYwJ'>5tF0+WTƜ?/RV.@6C<0IGR:+0d tp0*%'tVW<6:c G}@}@RR0mx":B$\3ʽ(yfĜzgǽF.5Q_(<Ȍ_D.S*RbRUC-pΥZ4[U-ݠ'#e>ch{|mmhyj8<3¨6w+iݜKɜɭg~ ꇾ%}γ eHdM..:scvIL $}H}ORrUK9$rz :R!ï2Tu^xDa؜kQ0FV|U! ӴY$if0(Z ,#ȁ,(0%_=v0C'`L$*L Y (P wqRD(d6vĸ₭| @:B <\o֛nx7cEynJ"YRjEP /0J7]Ŗ *BYeQDƬCYzS~€_+DSpAGl!"  KDK -"/ -:Imnj"}[>bPx& $U44$BI1U\fE)nܚS>n'H[ Oɡ"bGFÈa9G#-rhkUQH'Ny/%(&zjBǧc-G4ZsRf,k^!no"Lid]߉=oV ը:(+֝P[4L 6qk}oL/6˜ GO*AZP|5ȣ*Xش~;qB=uĄ@@x)%h;Ԣ"K?<cOȨ#Wo_~<Ǩ RMGe}h j+fp FXf`x>խ R1e@PH<܈rt}g#OC0]Nu$hm4 &ڥQΈoͷJ|nmKcD!dģ+@pae0TiT5lC"uEϲ1FmxiW>m5 cKvXmr:F0b*JvL Y\Nw#k=v7mca7U!V cnL.Щ7[g6==.;ʎΏ+(bIzCрo5#]9pduKsy!'ws G7P[sC{Gvx|cOxDWC)]s[l_JFW\MJѶaAT>obi rO:O=:yLj9< &|ы[JaYB_9h qΰ)÷*t)#j>ZZ: hU:Jh3ʼn@7k^W^RrD4E+ H0U@$[dT5 áre%KnP+EvfJ9lǃH)YE %l]3:BQYa$㨻m)ݥ2er=I>SzS |nb~àkW[1yQTX?:w7N%B5&_Vq5KRq 9$\Φn 8P#I Dm&ʜr 0C/l\qӗKÇFzl( 5.I n9♜,ȴ"-J/O+vr&oL*kĻF6rXmAs _Yk}PRe >sA|ESX3Cw0ehef'<"hИZ?r _և+hn$ "_ endstream endobj 113 0 obj << /Length1 727 /Length2 14654 /Length3 0 /Length 15217 /Filter /FlateDecode >> stream xmct-vضm[uұm۶tlX<{3o|S5j\c]DM Pfagg03QPMܬM܀-9@ `a23Q\-f44Ḽ]vfV~aWwFwAԀ@`am))(J5R@@ omtp,]vqfo@Y8$E$bLbs?nf_俖f]|[qQNQYb6eM7x[bݡ."PC068@|%?^GvT 9mY$3l+X]'0 !P\HzlǍ*TwMacy̺}ׇE|e gN^ 0 zpJ@Y5DÏ0`ه省|`Ƌ{vr4)_:J|iՠiG{>xkRtW9x;q?-6ܸ`F[ tEw7׏.l bJ+弮5ϯTs\DAW?ƒb %a}SZձ!âMd@ABDO}ƅ&sVu;(rBa6Y%w*[{br&zѱw +Vu8KZ>SHckp.\ ‘]!gn!A^ %r P[Tz"4=IN NjDY#D-I1 Y+DsGJd׽"90Z!G݉څ? f5&G8fQ }U .h#EuҕO}(S)AݸL#uPilu Mnkf)A4!mĸM咧DZ[^Ԥ_1qmc{tihHmy?ZրkFQS9_fOX}0:ܷt. U2ŗja$ʆ&1DLs <:)zqW[,A|DҪȚ)@Ͱ=KD"IӁG3:׶Z0$Id\g#YbJYG+7rEQBz BO]AlEUgvnD24Fpq*XZ,KeIrV\7ד۩u0 .8# F~Bʢ&ɱO[֚a'03s|'.^>MK/E@ȇ0njFϢMn_CmgiZ Y[h!PTZ̥<+J;:0JP.z=EƝ ֞‘qk}Lt[4u2otثP wf*wZ!ٔux Ԏ7 I qWU` *AeM9L4ɨhYK0&7d[kԞm , R)jԫήhtۏp g©aEܡ2i\kjGH$z+Mo"fE 3*¸& (WA'܃TV )H:ٍS$bko+1. \bj\16:1ɱoT&ڰF)ڐPlE/g0;>K  H^KB:J5{^Ľie;D\pFʉ8jRN&<~B3j<I1yפB@`7{q2 3}zIoM򔚞EƉI,f{ ^wAv1vTQx\r@Gۨy~pTQ,sz|{ڒN1*uX~3l۠k~; )(eK:.l,b9c@8\k ]fm*7i\Ҟ|.*Vj#`2C'x{(, eoYj)nbV׬%>*oQyzq|61ħDbki)J!V +{%<3KC푷cYmMqPHr|nnK s4.@b 7r4yU[h.Rm^=_ywE8|)GezE& :W^CAI≮tG7wd.L=xG5uz=ty=A}`jyݜx j˭~ m1_ ϋ+(^#?^>(Ir8N߳=I},f>$:r\{ q` K|=،;[^o?5?,ZAIQ,ɹhVt77˾y(#%h/(:YgGѫ[T'X-[ݿ/l[/;} eVf5y(o/LKx/jO^awKID/w- &Ȋ8uYO-ʩ‹'}=-)Rf͵fu{/,g0h-\sBM0bckr efޯ$O05cx| @kE I@ +[jp cw?@cٍ9 v\%ZMNfW* 0Tw  W/Y LVj7!YSoԟ9Li̒zl1atrX):=Q4vXDYܰ1tVCeƳ> C܏ ɴyfqS>0rc37m;.@4Xm.#L*>)^VjtHe^ݰ"f?)j.vی[};0nM0ۍn !wדmg'Y j[]F `@ޛv8M-SH%+M'5|Q%.NPR*-$uAqMl?7vlnunlԗQyRR'm6 o},mN9_*y,^cztΌ*)[?*X|⹺O斥|G@h gQ|_8ӈNuK (;u)fEH=[~[+D}WNNXYh~3.+pT2Iuk:VP`ۂk9cMz :i5gLףcD+ǘ]@8,̇bvE1û':<<dWm+8Yx]h?$Mà=[۴Q\MZQ+wˈc*Uޗ{ Y9uɫ>|Mij+`5&5Qw t Uo59<}7֢Mkϕޱ]UgE˸Y) tR"ƏH,eaI6Hƒ&`_5ˍe]0:Z>&Dnm,M=%&)&n`+Eb\C \N*- L툚µP*k HOݛONH|",IY"Mi* (`9>}IuQ3p){MQ 8lD򔆢shGKʞVDJȨ7WEJ1 kB4$_h3{IeIe}>'ۨknu| R&m/3p~৤ȡ.PG/\Jg)zsq[—+gy+Rx l[/v8"qtg8)6?퐙YmZA2vɛJ}j`&*(vʌнfVv4wIA3#XM0M4ߔ)&X!hP|eڲYrt}eM\kGg,h$aeT]{$#50?1ơ\w>WOUꡂN&ּL%kTW0I(A{H5bj|E)AY +l\< Siݭ۝֖S 넂JBۈv0P3ښ0MR+'M[=hf zo&{?֮Aq9CO\c@cBz"[SMZ>O |'Id5u6],r*MɽL'gXO5 s)f?bht]V0DrZCNji:'&ÏY 2PW"FI&bֶj PM `wH5kmrZ%syGržmmwamJW': o``5N3TiV$A&Ew*"Kj5\'5 Wq%/[ܫJo'Hcbr Tzh"Ӻ͵?@4(L1;\L"B%lŒ0{d0Q 2(>堻)2)C'21nuk#{wK%L߶-,)!֯A:ZC2dә6fv.k5 P)H=/p2D~_1q{H\/bWЄ֮L-=ʚ[9_ )d'AbȭTՇ߾&(I'gMRcfty4ѦY#_[9 N$ߢ⃔$h~5M̴O!|S P͎.\Y|L֥pI*ˣsaPhC+䦥 ;SLC@ؚoҀc> XU2Gs5CBxAS]9Ճ%܅WDKpYlsN"+k ;BJH.3΁1K?ya-g\# sDn门$AL ջis8!&F@8\ir4ַ | h)Hzqid"|0ܔ.D#2V1\/'_P;FTjF^܇ UZәS"$,+`T@- @1`4 s5m']qf%qP(h%u;  9 _5(7ز+a搰r/$i1zKGviB*;csLToDd]~bB E}A;:*J9򀔚UBrlUu#bYȔ5 XXJxsyQDBDC3K<ɢ #YXڽ_P*IX/ yyMu50c_m8I"uᕣm.%փ <Mco;_hkD}w l6FyT71(o59u*h|(b6>)jH:mHDSZܭմ4hu|$:5EheYv8)0OcQi2#DflL閉Հ tIpR/K9,oCF {i.u lxZ󶺳DAL>z6iws0FxYxlvy_t ),47ߚnVӿ) |P'L^+q}%`Eɰ/nD6L3>^ ]ImIC*$b'MW#p/Sh?:F/a!sgʹ z8ڻu#bǨsv@ R;)ʸDAbvkĨZ<ěcCdIe^Ag{`}XZ`#^Ct+[?MX̥Xӷ͟4{fRDѓqۧPS&IE"Qyn K}Bg(i"+,(zOHPqxq^EȾ7iw*L *#aؐmܐ_[ߞ0P ,ޜe5zZ5bjiY&3d<ߕAsw$X7e=ljI016f9%ΰBxg|,9uoUs3e[˄=%-m>[a1nW+rP1LNKTP9Nj&:}[xџn\ǔR 9@aPMBaTe*ΈQ0k`gn?Fcvtb]uaT^Btǎ$pp*(8W0&QI ʴү\z`b8NV䧬bHG%;5 x^˅|B˂/d%K[ Z>@]HKRk)+rs2햣+~ Wdjv!8i+;6Ka &.Zn> +vlԐ.fI5|:Ǒc[SȔl^p)#@~XMs"XhXtjq7{ȶ%a.)ڪAܷkBx"!h[$u6ohoB x Cۜ}XIs.2q@G҅-M>߅Y1DDXۑvhxM/qnSZ޶k)$Ns*W>ApnX@p|Z0Ɖ ٳk@CzMSqnT[MFy /.ޠtj :nՃL.uZլ"bVaUҎsG>> Jb& d[YzEs豚K=<ʝ_7g Yc˙5 -qryajQE ?WJD+vbA.Eo|͈deG}ÉoM2u kX;~Q٨rFYݚaYߕT7Ř#]X%x,wODu5_'N=v}ʇz&(D~A=Ƥ{D0V)E6|x{((̔h8ݣ+Տ  1bȸN!AxgD5ٛ1|p|!-2F#Mj2M}P|AX .V?oLOEj2<5Ufms; o٤^snF4TޖyKT\e2KOq6zXvu~H8q껰e)n4xS6 ~S(`3ke>>وRwyz&lŋ.7#rdN}unQnӦc lpm%i :ZyoeOv: &(}rw>5jQ`/`KYѫX4g--W=t6T{M%p#=%O> c*o{Ն$uXp# q>#׃Rr!ig8L,x@1j jxҞ |W}}Ic&Q.LL Bw}u)ӄsSrDV;8ONI*ow3+.HNC G̢52":$M0%+?aƲ54@95Ln恎1&uSi$YGCWSث(?uǥ~]g]H$[7tmIzc)T:N^QS*ȝtsIC{ߋqK&R\f|KB Ctf<ybUW.w ;J9\6cG" x@OmPتj#q{ƍСCʲ٧-D(ߘxfx`Gt מ!Ώ?c2I{Xp2EN#-jnS."Gk:?~XVshzsWЇg6¦m0x; 1c4k!v;zS=YH8`) #gJM)U`mʼnJg k^J%1 m b֖\󊩉ɾ}p@&W*o_xX98&MgH[nU.1VFP_MݣQ\jggs/NRe. n`,IIN&v!fkόRE}_ u\&c$bv!>V7fmHQcq_4y[PX6C]äTPc ;!z)ݙ}\{,G%SP6d{aၿe0 :/p MZ/XfUzn`K.,5QU6dʠ]wq^Èo[g ;3ɴA&幐h_Z.G&ģs/CY|\<[pȕTWF@XսXSb׈|nyuv٠yצ#Д[箘 VsؖƖt(X]| ^CAzؤ3!xVj5e  'Py!/H rrfm9o ROT˼ M Wu% ^|Lkuj\\Jf+@ 3^H/E`s^봷7ѯ? xB9v#y.7[v+D 0=ޥJzNniR>@@`@ӝ󒙹T ~)XWqY$}>z*5 CLݐ%t*M߽0Ɵ "dWۙ?Oj1 j팧RB#J4A/^צ\QD ܀?EՎ2&c82X_5{twbvڈN{ONzo1"łNM#2+{Oϳ!Xxd j9]7 } tԿCaT!`&%L"y^U9i`4~(=337`#:]XBDj9'YM]Pڃ?(a:s zB]ME) UoOޠ4Q<DUUgghxk-rz`/ɟa 5xq)mɚ=RQ O˵UnD~3PQd!~a ݂㯝(/']ܢ_~nb$Qy_~>xEp"|( @Hduщr>¹ܿac_>7\bir(PA|Q\5Ĕ]Ϧ O/f8 `<0 >xZqB,!N +l"iiN邺^xl}KR& #f4:3"D>KHzl+]VJ'O~U7Ɪuce\[ǑgFӜדx0՜mc:RQ 0r/l # ;8yۿ=N"(@?QKKZRv-9yo&{|l{:Z [LA8>|QeX "_nSqK1`Ί#[U }XWZHPXujec Rf'T\UΚ`oZC\BZvז Iܠy6R7Іpiwn1I()4p Ӹ0 (,"pRD 8{^r^3,L_Ά@Nz)uŇ.Ml >שX iVc~Q;QYP ]Й]_-Fy9_Fw9Mnń5$x9}PX{:8gtg,rۗܙ]y <ǤKe>_2qUDD]1aրڑ[c3*A^m͡h۪׋/-)ވy5EYQo1|Pi\8 BoJ-Y%PnS!@ ۱!vvJE3:A < 5(X 'h]r6.,/!l0Wm5fٙQabOo^M. [Hz,tjDMo)2YL.r Ha@Reb5"v_BꗗC$cGH\bl endstream endobj 115 0 obj << /Length1 721 /Length2 24443 /Length3 0 /Length 25036 /Filter /FlateDecode >> stream xlspfo-vގmwm;olN:mwl۶73w֭v=k뜧uV2330ŔdL p"@Cg ;_@: 0X"vf*cjֆ&65;k;W cs ??E@ 0D4%Trq-bdma 0:v8c;[qrb7[W?Ll*Bbr*QF @Fr[g'@cGuGpem?&#-t5p'lb?GCj  @%bgc tڙmJv6EXX{BlQ?! '1 w?RZ#ѿEhbbz?z3Q;[ks?m@F yIy-Ӣv&fe4t4_iClwח5tvph31k=(aa;w/zf.n=+ 35vqt:[zE݁pKv?,SC|E f!ig TiA'Q-\ݩ!N\lK5'~.Vo)օ]AA\:V`sV-P‡*eP2`+NKܣB1ο2x] A&7/ ?ռ3bW6qsː9:= . BI* $[[P癟f;~TA3빈rmVΣHUrcezG;ݪk6 Ȣ8y^`ion%3]B!4ɛ5PųҲph(rtsI.oD+TL:O!NՃsjMS)P'nX1vz=ВXZDQ\=|3~6}.RC4tKc&i؈<s=ɘHMrSϢ[Oy[dŴ:'s4 #H:ϰ&1AH|xm w @HX<1[,(lvmPhWꦞ1yFSxG9S9(ۙΰLl痢 6h6C 3x:;=J(EJ brXHjPbhI#%,ߘYa\zE7!sĚw*9f$%jhc2Q_,AQ==9>[7 sO6hU1й_V(/>-Yeu mf.ܫ%򛲿1#/#ӿbm&P^{ Lh<~ }Yv]8ʟl<yI(\\ OMe 2%!`xLq#dj5R?%4hLoA J {s4((?4ō:3\!03SoԠK\y]hx"' +D y؉P0׶ti@}N q}Ky;EVs寡 ?z&gӒ8X_}^S#1dƬ(IMЅ/X}EyNC)cp){fa#q$B/Lγu\!{1NPHPPqф5~D!.MtoҸT!F7L @zc[ipiخ{r}Ĭe_G#nsS.>t}@-MgX! XYm!>?*}'^:ă{ +^E2x:4V;* A=< W]TOj"3Y~<ۤ~v}{A_Uή'Ys, @9EM 4rFqsRV΢%Utu%%,QS> %R=<8GfgG:Ӂ3Ql%ȶ M~{ln#g 7- C}s<-`Ð3<dzLהO:QjC_M ꐛܢལs1DeV>OUCW!؎X8KsWjJ ƞFԲ4cTuk+Jڟ(uF.hcɓ݄}yv a:ȊCSdzF k MYA*և [nHf w=>)c@~<0#*g 嫱y\>F,O Y-,)l !|RhzY_vc=ˮIC fN]֨Q^Uք^qYx>"W"0`Gx^.NQ'Kؗ65V3m%+H:~N嬡+^"v*? 7cYia __E Z6yNӧRZ/:" I+Pg6هh{̇ou7wrUO|+kY-;Ncu +o}0ޔ R RZ\J/m,6*dnIk+O$aG5DmN;S~ؼn) > ~U/lJ2rΕ.UYgwrlοdI~6O.-T5 [ F[k:h\ M'-Z Ѧ?hn?h E7(>#*KLM*X)n`5Kg {PCi gՐ_vRɫC'{LAf݉;eL(05/:MP*Yِ Iދa]lje(($E?H nܟ;@.9,p:M[(n}©] P¯ -). MT$aL@8|`Ab1[[;K |٣uH!MЫH ,Hx]=GǣK0*jDoaWHK}ؼ&i\!*x:k5sf̔>O}I9%z/`3q}xxa ̧ejn;em;F+UƩL+R\MV,U]Mk 6iX"Y/p?.~G1XESܤhעI/d5+G2"6> )O#]S 2,&4Le9%Cw>b + ,fjLjL/v]#{H}8+kȻzRڰT+4Z$~gsw/d?R4l.)aF/K!ކk0ޝ1Xv\VZ4VRAMԜK?>t}24uump?2[g.s 1g;O* 9mf{̌A(EKl #`$>?nUrǮwH2&W)w*@5\ 8ʮ(=Rϙ,!My8[Hf2K;y(:`%wehՃY…NSbFp4b9}xάiyۘ]HCRBc1#Z3U-٭5MNRZ1jqYM?[YݾߥSQe'>0FeiC3k4Q^*-V(ʺjnSfa260d $,*45j@&p_ݞVk&VvbiT8V_u`ysL[Ojy=SXY63cp(N*o\x0$׷ ԤRl?rh%nrb焨HVnafï}>3yJS783iusd:/@l~@ zmY9b+|ˣ XI/n]Dijv{TeP@2sX;bRmfiǝayJsSQ5j/C- fc>LQA!,Ųj9 ɠv^0$/.5R^¾i%|6,,ױq- ql9̲<=sI<ЧϊO dB_ ^KmYL {I<Ӛxbg XW!UΨ?E& (3Ԩ'>Ҝc>X[K ]#6 #u,Y: 0'M N2l suyLؙa>r#zOzb$HTҜ;kEz 5>Cҭ=wxrUwKeO/hG4u_{ה;x z ]s6iK\2,r =W](:Atᔿ "ڼD*?g_;Ӄ\;* G 盷MsOgGA#;՘h&2`v9$[T/&@8},)U}~!FhRs'pҵsѰ0RWQ "Hg s3U,mS^@)E .`7s#K bpAdi\SEzzd5XzY(XB7`<(>$A?`@bhG50H6'`X<TUH4P ¶*jېGPiGF>i:sNR(#_="B BaI78,[ T/PHg`@6}Y8Rz#1%b]]bR%fEW"졝.BC_`Du0k<@KbQv1LGԔpdv5Hb-EPdɧ5D6=]7AA,Ƙ$9w+Es)6\<AP&;{q15AKw̥U\YH/z^{}Pw3 ?\Vp1^OvhB%̐M,ӈBd=㥖Ն2~-(l{lY{ k6'+O?4=BڙiqnOoBޡC(E:hP=YIkV3#¼KO i`B7&+'4W&{;)8UxQU11]Bũ ,G̍B/qLל?Q:mvsE5Ov(BT$,ZQ$Jsپ>$" yda#c`ƵPn)T >x\3-A^vNnC̀q]O_^ӳk+ 48:s3H4X%~HYeMEBer -cgF0n/7[=B4zK펝e{&j-GeTDDʏ]fyJ&[˞jI^)1&) e°Y~|/SR>4A(PDObk7PULpvX*W2ڦ;z=}B_)SOl{Br8_-%u5L R2+nR49׫'ƚf'_5D 4%yK03p3MḊ<ŕOI㡲.}%w6e9=m|d#oH<Cwb0%WsRF;cL4q({בPns1r̆Y*C5n{]9L\^Ą,t(mW OQ{UȤ;dC"71=q#V#ГסIaGSၕK sEU!H ^3Y'D*R?oS$/Rot}[&D`!vKu WQ6hq[]}>S⏊8͘-MjAth "l8 Cy+ώWS4\;p2CvGPUph%c 6M ۇF N;=3*_DOĠorJdVa#m~T)^ګ&E2}Vo{0a0ny!7H*:<5j:&è+rBftJ|'W5ϚE(ְ ;&~ZαY#'ŷ[cy&QF 0){erC_=sdYd46q7?gI`%w|y(].~g|8Kc7=ʳԨrR$\LJw^ >eUA+X J K(E TB%$h\Op8\U.{׬Rc'SkEHބQ4tIJ/2?Ρ_A.si"P[% Ƚx$zI]k~.1S(=bJ_0/57§$6do uz̸~(CQE90" gh .)}r:uZFkK1Y 1(f&BUsVV3͑~ 7uotWə>:*EF ]rj/HR>e-7e6,FSְXF+U:)Gӯ 5ⓦ&(d:5PqiX֌,AF\مHcӾ %+ҙ:!:zg>JƋ h ?)75( yH,,Lmu}l"}j|Pi1=<_ci4c'tWsRRmcb$ ؛Ӑ=<"fI! KVUbH[ۣx\ĺ؃r H .^UT8f{\)IyxqUl~sV`㙜1|\ 2Q4F5(Vϋ~.#6 )ѥZd1^@4 5!x"Jq4>(&E !;(쫒E zy@bkUfrUs((+v #:~|H4G7; @Aa|H :)"o'~_8_nZ(F뙗t++*INWNCE_4BnR)S|$;m4p8Jx5nS^;FZRـ0S#OπUX=]q2->ء9"aЩ.G9!Vp58 &k ^s kFVisjGNX˵Du5ڬͤ޶|(b䁥&N5*_y-b$p>$KGÏIdSuS-]dTY-~kz{C0 0il܈o}<\WPibgc^ۚ=R$͎wSKX4% %hWߑx(.+)x=Ӌ2 Dw徱zhAb3z.FHJ^h5]ūmJm}ce9obɀecp9pS+ s2VTq_3}XT آظ]yϜlj*#RU28:e3^`T. LGJ@b;:xZ#6bJ3= ʅ_@A#'2N7vv$Sϥl@(:|ERğϳƆ]]KU/vy-ħEے|\q,//e#~VZ64`Iē ]\ <t%\lӆCTśyD :g.0ҦlqԬv)E0ҹM0 5!stIO:m~tjx*W4 }:]+_> DɄg%B;K݌㓅 )kM|';̫KH['z(B6z"mm~kz4EUwsraGKʺ83MB&zB=_FJI;Nln仈m+C wn 4d\=膣зfxz|7(_uC3߿r >nZYR}=;%# aC D^e?jarۃ@֐snۓ-E.ĭdT)jMA< XJ N8PlHJ2p0v( i5ǻwj4v.c&2 p)!/;TtY,|rSM"uG(՛HĞ_n=jbU˗qOjs2zډow߇uWm k%I;K,s,+凡—~/#@mZDr$ Y?n0 svͧs.ܯcq^ ƻp 6Sn-'7FgEyPc##kj7*-KhP0F2.2`FeU5g:9}=^ :r'՜*e2VȸTbJV3W+r͟Nl:E=ǓyZR5h,׀?|Y"2hA%fw9i_RFgB'Fz|%Pߥ GK=?}4Hrf΂ZʸEjeǽ* o&sfgS' ^EO"F f7E*q u"ucza3,u0"*V01L᧥C9215y?*`m1pFq?N @l4!d'5*BhSgɻIYx 1\ꑅJyjR\Z^ O08:5>  Q_> H͙"t(_`gD1 c'|ou)[A1O+||-JO7fnk yl}YWƸ%p"'Ca|]q,@zs_|1]6Z<[0qAۛbK !|*M~8T_CC h4(|g8N$_5,;}!6XTө]};;'\F5E#81v=kչ#tU֑_8Iyht$CxՙB"Faa27~UzpFS$Zd̴"9 ~D!$T!軇 xNI.m8 vqh;;r"Ptkk@|r/zlҦc5^^i V4]*10#Ǘᄠ.hp8?j/6e1[/w(R?`:cR ^@5#Ab wy6sf[hܹ֒,ASbgync'f%fScrI_:Q1:s>t4~ff(rzkkZŠ#@fD혏-v FbTR G}FpV5-Y{-~32 \ `m y623(_#W"YN=Kͮݯ3 EGԱ#^r"Y0,S<LjW|_@{HL-> K':qLlH99s,OQgJնnwJ"^^ lۙ@|{2l[3:;݃`Mujm>7Aؓe %X fo'1aF F4]Ҝ̃DODt,g|L^=X(/^G̸,z+1{`Us)6j G$U*KfF9Jtiis DZWaËgfM{koi m.tJ 5 'DY55e=m9?ze轀 bl ɠc;M w?1J(A516&5>fiҢl Oʟm6$?R0P$};I(7\ iIiDi Iq?~x7Kr![qL-?jw}N1\m>O͉6HSSmTT(J\nɐ@mA^Ԗa1X G9F"(BD9[i CW\λxK a7֪CaAZ:>3hk_苶mҙ|~? 2ESNWO?Pob cL-Y>,x-ZJBتunq;rAv>jj%w %6aHh-F8~lqt5w  XӲQRe'BLA;o~/WSp-ܪ@pAyKxg'G,  j&x.Rڒ).\[w(yPwxhe}mQjO&)U3剞0|HHZ2ik(?jǰX} `+@8> tZc(Z-2zT - H#9P#T;ULN o-$F zl}S/ԩ0-¯ǽ5JWu|$ݟ~#3GGn)k67t8&*x@JPl3V MHVS~"cV5/*򯾺~<!PޗW 5 {asQaZc6Gdz.p6ށlgag@CSi&4h͗9ewX/“qvUƘ5fTY>'_QקMA[QU󝀎S1f0.<90oF_ocW~6yLT~#vN7kjRHLPVd> J/rw`4Zᝌ)ey%5bN 9;\= Z BGZ㚺G_톲#"Zg6fMmYU+ȷ 22%Zq6 k%&̍q>|͂o>AMx, M 4phieTE^@׏̝L.C~9U[nW~:.:h g^j}e U2[nݾlۊ.[µ[=Y38_猄3T (uxF}yAtX"*#p5N'6;:FĨToLo?>JLWm-*j\MiO&okd A-DNÖ۪Մ6'a*Lڇ!Nj|9aMt6n. 6 M9( |aɒsOWa~߶[8,)vנCR3o[Ypπ;{`؞\V[{tGOPLVpL@\" vlrU3JF"1SdA}}\L|'iXVޡ}MBΟ0e/qRDe9vk dȄ-DlIF^#R}5RHP_ +0 WGVss|fLJd0ƼJM+ AB [70n۪C_W (=A.p`<8zAd!+ǽǭT'Un#q61 Nu1̶Ștw5ZT`p8_n{ys<(o8xB9rK䵑4hn7uV =e7? 3a9 BE٘>E Ω 1F h,܏wSʵp}Y?e5f2k8trE^<VBy!ҫm7^8wF0\<^,KK] c<"lH˺v2/M*B\+)9QFwQx;-eO,<ᲿܬY9v6z"-ҫIEQᨏ{Lj/lݘmW)~ō!s23 Vqdyp g2Bjh^Nans.mU2J欫S ~ݱ&Qܹb }"3C_@n*U?%L),H07Xۃ8 t-S}Jhs&1 tO;K4N:7idxCYow^//d \e<>a=͙np|gH?1 SM* a* ~-[@0`:I TrT/!h8 ^-D~89Fj pct#U%3qݖ0m}xYf3e.>9K?A dx hL HtNURo ",jæ[3ʌ!ouJzc[<=EWy \0H;|{f#CU0#.c"?=bzaC MoڔR=>^A):eӴ/'6&sh:=>7gwFhi3sZg[ $FMk'$Y;):L@Zl'0ϺI/-B<=Ӯ Rڇx$T-]f2l ?7fw]0Ddi5½n%滉/2oc7 늯{k`iۖos$M$opWџ8 x;ҘYA?$RVzee?'F S74M]X'kh!VJZUDs-9/&!TmdzuhdvM4w r2ͅtQ)i\L, iq+ٹ) MTST;ئ+kz䲶m<"=:ٺ˷-eUUbO ;3AD+`.=vKZT|>s /`0E?^S8#]40 =87a#L4Ɖ,eBđu՛!hcU鹞IDFt*\PqhUA9x+2΄a\4y#u1c]!Sb4ک m{Ņ.5KSuVe8z"vϤ᥃;Y&~Ͻyf/:D󲋱$Xxz" O#vϛDǩ(E" Bj`N mRNM&~nGP[W ^U'Jpƃb@ZS HΝb'QB^ `T:'-LE3q>qF>ZiG_w?h{p3$Xs^@t7eu! sS)4f.hd(u p!(V4KAӞqs#,)vLSeį+:JxءlAKWB5ذn~ItR9(ocJMBi_h8[R΢ajm% '3B ;Bh.NQǮ/!Q[6:!TXD$?"G.p %OpOAG6D1Iz%|74v`NK;F6te#ug}kpj|l }qHP 0R/)|P˽Hivn=<@{DUfL Ƌfi t+hRfx~ έ~zʅ7[!daAGQ} ~(;MnrC#o_?FЙ[;?[zbDޘaz$tv"8jQSE'U7I0Ʃq4s'=0`;^JQBf5Nb'hA@ٿ2:(/;-ŧW?>^M޷Mn,/Ӱc,S1  )@*Ehg.J#6A;B79 '>>^@]7z^~s}榢W[-Dru˾k2ApVޢFzTE/HqXQDl ?X'"Z ZxB Zi2s.#Aȴ$A5G02NSfeԍZT,J]#V'|*})iو+4h2HQΩr% =[dj0eLO抗X+G`BohUn[YRy=2:Jt6G2E Rh@GR =^. ?!ke$>rWm+ |q5j'fVI*ٞ<' PPvc$.VæjL|ixR0^9хY@P}jqjGא=ڟPϦ ;mvZwߘv#}?I <=s,u3)*484{kfCKe,'R'sڍF ;T}F3qLu$_/(lA@xܭJ?PRe1n "KL}|AL\`:qhl\& 4tօ-FϨ!oψ2~Vߣ2t7Aʑj=2Fgsj8X`ʑHǕ<DpTݠٹiV}L5)ɧ&6 w[RLa.b0 |y'z@RM,PGU>uXsmQ.Xl$H} QQA暴ճ͋՗bRщ5$8f_ݙkG8|mZle J!n Lm6:6L.= RΚ'dĊd4D9ЌǃGn,J]cWU\prBUnُG_#2eiK>0͓t1˖O=IKX zeq3tj&"/:{lng} 9q-vJm೬;%~Tq0 ()<:Be2"߭\Wkۯ]c9FJ=ξ;૔F6S_ЦN\FFarP92rWHS^kr3V7!RǎW mEahTh>ɞZ= ~oFiΧ8? {uxף,~$FzL~lb`LqTpWkb`r40w4-ʵ. OJ9\Z%Nhqڵ$ƫn5V:*\:!ofD׀lNh|Od61m* E&HzUbڐ5r%4^̅ܰd^K! AT~Qeˆt#$4VC%0F&̪I6#nzѝz>"=lYMW_} X_+1MB!#P4nJ(H^@%gχcO<_ZL!smimFw:gpLP79PWcEJ$_gmVV['jjr:[og#BCKs4Cb|/AvN$joNJ)T| }ff,(f\Ჰ=s9yZti-a5L' o?enI1,7 fwwXe.T'u@u4\2] C%|ɡ!7WgQ)< RVI:΀!-'zlې.1Q')6}$.g},6 r gkN|_ L.!AX@lӺ`"{^Y"oTDcbͻ xehO[Gϵ `FT?2~DCMVRBL'DgXdReӹJ`-2qQ, ij([*BOw 5s8^?e=/OCK~-xe:"m̲#$ w;hfdݠi2"˻UJ@Q )Vɉ# lBz0pA}D\G~y`vG(iWp}7Ay@~1MRۙs?~'=PT}SƏ*-Ey~.Wwe<+\P}oTr4ppנCPfAX[1qsy)nUү, ;ڮU9_a8_58S>8e}`P ib\E_Xn.?òw׼Ѧ:t1<v2g Ԟ듇bhm*k 0u1$J=槞F bc[ňRɮV['s@I;p/TV'@撟ɓ*3iqP%h 7ќI/"lc@,S&p`0C3 4O{Cݰ8A;ݐEaFQ5w+tvӄ hor~&]]NZYyYGUqFT6?Hdg(`A0ߐ< RsaH8[1 #Laf{*+ZZb ͑LOվ -\#2QpCJK9 i΅eK@GHN`2#- |BvsOw96Ը{HSBXHh+A|M!H@B^Ԫy*⣄5ёImiOb1too&qoxKyuO˫SӾZP2 q;%0evj#n i[meЂ0,KdUyn>:<.`C)UBVBB"!&5҈'@~(r+g9/#mg/ƸES*3H:be)Cե?[bSɿqEN/L?kFr`*PCY·v6k*H"ẆZƲ˫HI.dǁ$NX -PV43~uD党@ r?ZY-t>`VۚNQ2z\mlhO`RaZmv\uL_$)aV3F>>6JzMIEt ¸SM^ >6s캤jǷA"v؍cq G|䞑Lo@|(X2y|Mܪ =2&aR CS`Gfɺ^( d=C̟Ug`K7jP 6@aCîQ8N)dž3s4s".~ګ=~5'xV9^(xs(3PH8^*GwxzMu)G/M2[dc9L8V5 &śѓٮwP`pMn(5xeQ%ڢ]Z&=_.}5zB,ȋn.rQ`+`DGohb7{R98d2Q4>JZ H3zc)Ms,<0נXXl\KU/+N%e Cf [nM=VZ#n&}0I ntg* //ph9u%@CN]<&Hmb;0/G_gs]bO6ߑOz֫LW, ]Lg]sAց{f(,>sѯ\ys}Ïb\w^iH{_b,"7ꅒ^La9%n")<=`HLGau#S8Xs;m6mCFzw&բ kL5pJo>H hQ#C^dn8%q _WxD6WN4p86v|ORt9i%gٹg%gtj'P}IϺ@@xZҷȴ<i%th$&]'f?|>$ )GaAp?(V82vNKJ't`DbڬQ~*hػzy)?@DԊN'}wR*\A1mz*d*@+aj0-꤉RlfJ2)3-Z%` UK } F]mS>Flr/ީO#!tv$ܩ__(P(\8S+Nv=$K_h56沿c g.Y +Okj7E>Qِפ#&ےkӵvd5I0Q?iX}b4*,,Z P|fhZ@@0?OZW쓫om|xߡ&i|~B31ÑhD.p\* =̢%iw8$YG_gp7?Uقšcv2W~=)T^PWl$lj͙ sҗ's@Vc@݊1[p`}r  t1Wazד m?t,QRSdBUZ$tbr F^9&0X45v c=pfcMC,s w_ݢг 7xPU$ !M^`)zQgGA;rϾJ'pLżZ: 6)|3{DmЄW[tA [ ~"lR$=UgfyK:CvQ9xs'Yǚ+i~%H잱*WH+O` )o(dɝPs6RvwkXR]kPm6Dx8B*[nn|joELx8tZy%`TTV ,NBY"^`nUMpjsɐ"Q+  fXYt1Hl^=Oɋ0̩t+Jо7GsחCf7v # GB+ YJEkbb"y(\ơrP>7"77=880c˓ hta>ß^V$5ۼl;-©)F Ҡ''Q M21ijK#ȓɻ}eKTަ/gwԔ3B(4b| {Vօ2bӱ\Romm3> Ӱ)ecV*!Sq>Cg2:r[*^65̎`(>j2F-Sywownq<A~?0M%R鵚t%b22آPz%;.Tb^3@(_cŢ l}wAi[ӯ>i2!sHqve}B78q:Mey5}jQֲ En1k%y~ 7!UٛO sV%:fWz]"rL^儆^}&(Yz5q; 9uip-wƘ u?P:|3L?x{e`% ҸmrŤoX>/aKzq &&FRcG6]~MUnf t#H1vnbr@`y6v B~0A$.5e|Mʝڏr]O6&64tzD_ ]0P"!H%і<ɴ!Vln'(oNߥ:t5SdtiIm\β;-ݚR-sHfއݨ+΀vyp$-9 LAg)JKcI$ ׋~mAj ڤ&ɾ+'1*^%$6$c&d Q!d{%lT endstream endobj 117 0 obj << /Length1 737 /Length2 32014 /Length3 0 /Length 32590 /Filter /FlateDecode >> stream xlpfͶ?LlN'1Ķn{c@,'sUvW] OXGi*i{^DcKY/8c#(.haͧ})qHf?S7d>xL bul5R wyj@-;*0ZV'L-+C2|B.mŢP"ͽ?IųoS+AQ"FΏ$=ZykINHY@ K`/2owc60K<_ z\Ei:S^c!o)yqb/<,)̈Zgּiͧԗ kv>j+,'R{kKKȪ)LM2!xYWcy jIzyɈ hYk 5QNÒ+Z8[ZkGϺ}s?UL 2}T یwve D&=BI5BI|>(m/=#9`'Wdnhy7PI `w!ةof""̼=4fɹa"@Qt#jsE^&k&2ȹ6Կy CIgdFIξO` S^Tb5]3Ye 8M20'2Bؙ@cvG.nGBt)6_uo c1?IeD SAo))tU "z;_,t~TTK..^_էQ8MU{dsBW!( 87D}g)wbiYU"Sp]?L"J gCn~\lKz>EM&גu "&)EGt J+zG:"+X}S,%`!Rv/8"BUuD!~F#\ ?ժwG=m FWT4kj]phrg\咂qӆIW$z,Qv*Oz*Ï|H]@ܰWLe.e4hԻ!u[&ڀV3U#eY)*zp<>*fvO~j}~wz}[0W$(GBg|=rCt q5(\FXCq?~#o\|t<%*Q撐xo>J QJ@Ě0•k ȶto M.iT;C& JN!\_vbJEט7ڏA\a$/W xtvԸvF|賏h-'(!9[u\5ngkN粩7HtCg<)[̶b4u}U@SZCytgs>'ڷKR$\/fq1#&Ĥ$B}kv ֍i&`N`~™!t(S46uI&^*Dn^|ߛ02Lq[CX%{5GcESr01WMmЃSՊnGfWB}AN ޵ē)o'_mmlz @ɈSt/In7!N,`gr6ť9=r7GyOgyAe?r[ݲ0602waE]aH̞ɳcVqūMnxҳ"eM=D)2XCĩ֥fgCv5'Oe%Ez/wMhy1ǔ*iP/ M<^B G k ˛C+ R+ZN-Lg` J_G/""v!) =G0c1s8Vg*z:>sͻ µZ! тJ_0 ΣCxa6UlS # +}fԹB5|ADW(5y0ZP 1I:^ Ƙ[ _~Wiv zn:upNӟ[H.)("Jz1 9 _pP#3|Nc m\5f:\T9S0K H\1R$'fg^;e9@e¾\%5}&*_ocCY/ePP|MdۃJV4 7dffOE u@icǕXX0)9+GM3 [ɼuyEou^ ٻͨ1S,,0ʁk\?yEv'FF^'urh(_LLIn[3%T^ $Ǐ#ruqNBBj H6s_hŃK6\.~mP&n 1SrDG-[S-8MLdfff"zvOd[+ e/EI e8LV6VTuCm6^R$uK/bY'-ЙI>No4#^翳`lFI0yOd(aoNM[yǹOݼ#(I7 `&$򌭾ls-s;^a,@hP ecA"Q-k{kL-:| R~}:m ?A:ـ DUl?f_` LOJEDe"ƉGr?^MzH5{)kޖ1^,,/ሽugt"6K--ap&D[0 PAA-D~हXQ\pqVRcqoM.s;Sx稧1lث490E}wΊB@E_B ,0M͟=@~IP}2YFˀMoΞXrGU^>l.R/62Yc{/UH\$QW)-~M|X[PDD︝_{ >Py /D@g)i'l:α44@d]i+u:j ǞGbHaMt,)ק7ę:Վ͒t Գ+퀛Tt*yN}ŏY8'@U&d(WZY"!wJ-RViQ~k_90A!VuDk;h}+ CS-ʢƈ{byX[sKCTFPrxGwb(V_'.ɍJЏ0Rƍ5rXod;R^׾]G;;xPAx;Y6^W5oEAi=0MbI Wj v_|N,&MLa{ߡ*g?,lD9% Rk fJ 9M=.'떽KT]݁!1+ߢGNN H1M$d`(ytdX¢V'J"JZ0#I¸qXJ]xsLUiqXEqIqÏ(*$_{!r$0)<4T|2+*N@l#r +6%ӆ~aN)+T,j%m|֮w(~h;}9T2QH1v"iuŵF ;t^Db˟{a\0Յ3ژfdw>p9橰hkiGH&6\^yڋ>w;g*]hNtI0YsBddhNHzfHIl/Mic޿l|̲-DM/L<>χpRsڔs넸VIPB~BSzRbp%|I Ή 9o͈2K{xLo id2 ;Ak& i0D yyv@[/@4P`L&s0*ۄ9M-d^j`{֠Ȁgz}7@Wr_B7λ.ztd` d|F[8D:>y&]P-3J1a9_L_Պ>~Cin<)e)yHFS& 7xGDrv8k~[jʜMwkU?bX!pgxp#nykwf-F*G6ϩnΏ#dɏ% }-Y_N;sbMc~n.>˝~BI"޽<5NH`CdsJe~ޒezpv)Ѽm98]4Oj58@V^`ċ"JfQoF3iv!yVݔ(An⊊έ ˕ c&`ͽC "[4l8pz/τj gLÇa+kf; >Xes?!NE5J(V#vUrYD&[`|yE5+Ge-Y;A Jt.ϥvs&P Ljb~eΌ@Cg9 0>8[Cu"Fx̍qJg!WoyiIWف#[VjpYȋ!D`^V ۞;(2vt$ũ?^VS!h6 CUd4~ ⮞p$d`/r+~6YLdW7kС?AL!Bl嗠,{WNUf8|C`l=YRNis\J#z-Dw͛n>g&4}W773ꨑ=Ķ``Sj:gTYӃC)&{wƱJNYtvViH#U/ZhP.cW=gWnqD;=9Ұr HR6%j).c2֯9\I pt @)iIC힟?7SfG_C.gi/yʵ~(i <$|3y 0E }f)ypv O, R8ܳF_((v 6@+t'V@XY_jn<}5'qrKI( l-n8xoJq9oQט3КeXᣔx{&KX:Yw2jK(/R;5wlU XֶR~nr=‰0$*ƣS0m]N/P"7|fnug!fD{j~4dڸY*M8V2s4ߴ÷BcQ.`z bl[ ΖZ_\/嵡㮢g&D74yFWYd=y֨nz"Snys g r";kLzS@sXv )ޠG` 48Z>+ވrV+Z"dz\߿+)k (EWG ǻ4w/0s=3vS *aR]ə?LQ /UIO-~՚75V`'?0sM~4.d\a -6H )cFW.`y%4I=)%7rwv@DPOB@KK̴S+F ]ցD7YG%G^4AW9b,YmNzW<" 9PwfS)ZRύBL"(Mma !d˧x>EB)djT#@ٰ '&آ&( 3s1= NI4Z;5\XǀS N)„A=+ev1PpP"8InZQ~]i~wTso:tNo.l2teúX3E?xG=XD{pJ [o![1gFVy|n0pB|H8,hrZko@@qSDǷ)|jEz5sF3g;h!Y1^HM1)tV-ui\-#x%.$On?aᣝwH9T-mXsW; _{5vz4~/}bRv;+)[5bEƜQ k8;kq]nNa ƦL:_L#=012-Kw)d)uڑi@\/V/SAf\ݝ0n8};|ˑbh02W 5.Rƞrm ȑ5UUhz7:25z(2:ШzoFƑ:6$~ e:-{^ ?w=+i +ĆC?1CLIʝ­QFP>[t m[CD9G1IV3~XaF~Y`u[^n:rJCT?Y$4-!y/;ە)(ҌyojQnBYǩeyEwx3N%p-Ӫ»8.gMq\~Tȉ$lk$"dj~$st,@C7M±iʎ\'{Vׂ$ ^.Yw=Oÿ![F@)C9&H$4>`ֻPl9xtLrcV[Oum>c i 8u.괷VDeЇD5RzGЇ->s"-uk*_WH 0fXGk#PWBT5ԼW7;#Cx&JyMmyq? /$'vtW<9C]QmYԂel9S@8iQыJգǶ008k;&TyнsnNGmI As fEBQx6V2\ZIuA[uTLXc'p-:6veJyqсY̏2A'm>f(i7 y5ƌYe#@ae`NӸ o,u( { +hg&1ݏ*gJ&TShg.$V)&a켣ּ ux̏{Dc760C(*Go<4fX2:^dB"  rYã ?($­S!84GX'n#8b"cjH":xӄCN 3Zj~'oC7}I~H5V]6jRdGU˲XR>]l0GNAy[Yo[IiWhaO Cc nԘomaZ #q/0hTa#q~M{!';ɘфăJ0vǰj,ږxƊ:+ˆm "myKodbBy}+w mejV 7;;# %Sx|Tő O3Ū%[=ٟcDNpLi9윂JX.ErJeR68̰ŽN/ R {Vgc$Q/x؂ۄ񘾁 ^ 7.n<#ۛaG<'dPu%ȸJ eÜ\n @hLixw$P $.|Wђ|s_NvylH [I7㷶G6m~ P`IAhs&*J"g_h s/EDL?pHKf]ufȂ3z8k07@RdTřIuIЧq(ypSTxa.[S!Ւ )5]aܳΩ (a1G ( %3ЄeA+K-꩚k f <zONL mLY,t}uu"@]ܚha.7dJT!頄(UyR$gطS @]K=Gl |8}].*u0Uq&zLIבZ\w1NRH$#AW̆1ZЧ 1ʌz!7 Yop_k’~rtƐbBȤ&L[CɹA|j&ӍIٰ<ӧ?5כ{E(ܮBϥ74.5G~.e4[L^Xb8C>]bRy;w'h3{UYu>+Gt&R@ja|7Gj_R>* mu=#gj4'S۵fc`n=T9&d1_T6Tg%8Y{.h LoCMe]' ZG۝S}i'xE ٕC W9}-e JUIEK81um7;@RؤP*H/*'|nr9|p YP|*<@0W?DY4^RQn4|FǓ`S.jފpMFQxZߌU qYH \< D2Q5 8nl 7:]S۪ y~ 1xOǀ),ChhLgm)k&I 0䓮;_|r!cpƛpBSxe.<~$/~yߜVu(?[0׍ч;뚾fedҁ ~VՔ@,˄4o(ՌM#렯 a?Kzj ysTqTlNR`˸9x̓%&~i3b]QF_ bNn(3#IxCi+9LRt2Sf}2f`XR}RV&_n54_[2DQ7V_?ph柱ZtZ6jGI +0ى++%yXo$<`YaDZi| +7G 7.v%bZ\J$60z]Êq֝c {W  4x]8;Ob}x7h"7D%ڄɩX*gja$GY+L%Ԃ%N ѻzWL·a]=AJeYթ-1([E=K8 '%\q+`]j%cd7zWJ"Mv& & %h4=N^ ڣ.\#J*pwSt_I]+ی6Aa~sL@K1D-*pij"גv .Zg1AmiPT%A{@.#ӝ{WIs_;k0O96!A=(zԖT7ewXJmK7_2'~O*4\F\vbʀF)lN I$E.0"_@a(ٙVF5*< ZP'wɥHK\3ԴOᦋM3n<˹mRе*rg|n: qJ%SenfNP0J/њ _mԣ߰t?,p}>hog%~/*NyU^Mp"~Jq6g2 W8SM 3KR4b leI/}nV4g}p~gfvgyys%$$pї%;ӹ$F\JCaٔa5[MoU[Nzf'?!S9Tҗ"2>Vm-J b&DT[ZBҿ9먮UL40͉OVLQ~l$A>F۰_Ri֓evFބ.7?\XH"rJ28xXdO}9FCY\8f';5b ʯ}qy K>R'na%jxA͈<JM\AtÖ+UbGGihxSXgü2J9UL$I+9|9+CMpexstq'$܌LP\U6YE6GHIUa 'cёQbdHUǯ3Je"2\ϒkI{2wGZXSTN^4P3ŹK"HV>iRVr V I#5wR[V0ɈɹHN"@ҽFް@02;M JYeU*%dکJyc'&L1lrȸEܲ"P+-9A fprS Rk{six %^8ƍRwZ>q5Dry%JNAFBl!-a=g mQԍopOQљ 3>_9e nK!  "ZV+j,k8;;m x&MjB* sW?nGPa֬r"v:;Z0q)OymGdv2(9`안w:0>_xdcj5VO~Ē<bלkq5Oqض8L;\sS~k0R*YsAĕ{KOj*PThz˥0:+R^'`05f--YJ'"G|F<JWL@MTʢ V:(,.o"C2Jvx:+qE_;⽜Э,6I$H&{^R8 Â-A#ɶ\QvqX=>͜3k6:}QQxسP˨@E!o%-W䱧ゕa/x!ʽ8eP6ncrsUtzрNU;ZCM^B|X*76TI]u*׀ΟEF8 iAE zQ!}8{8 O|#1Uc(ZiAx,@\\֝.T%A ?6Q pH:^`Ǫc={\tk_0Jׅ츳gљsf\WlS~l xH)& :CH.C2*an:.s9.J ;@ohH\C!XDPI5>|O8wOjrs@0ݮi}}ڙ9)ˈglwm)cĦY]YmK T+k<ԛzxS|[%>SwDŽ78i%=1/]xU_!x{[nF[ UgS]{GcmĬYxkF3 ,m֥-g)SU~Ftgs?>j?LetQ4UM8K$K.|{(pbKj=@TlA5:vc~wQ@Dh!'tEӧrةqaAkF(PŨ@}}nXPZJF2~w< 5hFV{@k 6zDm{jZ94 }|wsr[s CBP?0gv&|[=oW^ -^};>]ej>YN\˅ ߨ>o2@>lAJ@'ЌtW: .\͠J-Hʑao^%wAp=qpiΠSw PM9C*bbEޡ`+u%ynZ#.J'tH׭20U,Thqt2+JW9`;(Oȯ.0Zb8,DdR  IF2_+@/" "#\&)e{AFuA l*#{ɦ;VLӄJ&OEGR9 I1?.Ri7Ud΄Zж8^ۻ< 6[{qgA-S}9_̼>lTkV^^ӯ m2^`ŽfX=}*e}j1C4* $6129TJLF2b8J_6[H@M>K@1){-owO36E`AX('ZWD??fvKe@d~ugso90w젝nO# xqH=EHxb{]Lma2|#̔/0MYc׭xgL2|f4P?aRPT F : zzH2:lףǘ"̿w2 !b )Wȭ& h)p0jFw?<h.%~P|smm\m>X]7.CSl%2TA YUQ7 ߾c(*8xAS. $RXVC6  ,G[wT/lDq+`N'2+:Ը[,{,X n@#38 WLeDAA4g[=t^.;ARVLfU}&,%:aY.e gQUhW^uM+T3)b$ x@՞H򠵥:ydd.B.NAB &3XРt\@C@#]w"8/"+81 O!3w5a%ۢ8m ozz&`~~񘶎xLO .}:Ϣ 4*ZġuR% P NZK`h^N\[ܷԠc[(#(?WfcaDԓx]`r InWx.9[ o-ɝ1Y2&ADTӠIX5#Z4KD3BS]Ec 0YK ȆBVnc(%eF¥IVo5=A#Ig_v1FfWSc,k!&CJXsN_Ƣ:)@{k|45޸Lf":w- ‡ 󐋀̾e`o`yP~/NL#LK^sT\&oKgI)qIQazVr!u΁mh{SX\Lp2]mOgĉڅ&<ԮV&G:ik^- FT07 C=rċ|Tqĩ켍>%&I;7"H4%v.0vfN%7#%|)I.lD z UEZձQS$$<~V+zK[z˩7۵zH,M[bnhbCWӿ4>+UJi?onzG7,w!,j5[{@2\Xs♳c#"Ä9' 4U ̶TĂvK՞5}7ܲp޷H߲UձQ1D_B|/|aϔ`a6]wE44k?~zsaPD0 $~xPr.GmF _sMuӵkCm#g=rV1& ,q82,,v^ߢ;d™S/QUDqjQ$sA@XST'^"晽NS7XdVڒ ziXTxN/+Yg.ֈ}n{ B!V-7 g훤G [}DP^\R.# ^M6g2Tol*?% u#v!66 :!^^͢o7swi,ZqZ -ND_ Z:ٱ`/)F}XZDuQ@oܞ6LB]ݡpq,<\h_9tWN+naa]"?8X3ٓ석?O< >hߵFm_ZUX2L9?y1n[-ox1)#՞{3vVX'(Odɩ2#ŝ*<뙩d(m>cq by6-R~j]-617eq2M 4_y;K7Tf9\i=Ӵ2xJ ؅[[Ћ* 4=e CEɏXGW.Q4FV_M )XRx%VSZ0ͯ'X2zRo,|Yye -`MIk$zbJ= my"G69xr>,KKsԮ PA F+պRꜮh*zJPP@e/d-:\'G1,_CӪ쫠k qJx]y]`|棂}g]N'?u񠃲Iy~J`۶ׯC +f߁60jU!xzTw!JtV1!':rjғ)\"G iq %X{jb+&“ؔN)Taz"|]ei&dՠhX!̸v8p3'uq(T Z |(_g7}@ɐ/1ޜ  ۀ⅁5)ѕ!Vz +Iw{O>&V Q o#WlZnCZmZ,PRqhk4+&ON=h!QqbvYG.--`YQC.{.bg H55M5QE,%|8^tzoUm-hHu[a.ᶣ;( dwab=U-?<izĴdL|2\mk-H.e@ʢ[zt2]&K!Kl'dk;{h( Wy#Fj!9 r8h_oD!n1IG]U68θ Wҋ*ul5]`%FYъF!r+~Y!:Z=D$sS_m6wpҷp'UM&1(ʴ)/_æ)ǗgI@D$RH|ń$}<؃u [x^_”DՕx%}=ƤC`M:?]oGMfΝ6H٪zatv y[vMֶOʁ8^>GUő x\?^c´6+Ҩ;ulKe_#bːS=>:P|c#dl7m .yLPƩCsSۊ ;Jvv>xh 09i`ůGp ۖ]( [R d* Ltw_M|)h4 s)g ̈́ Daur-7|׸XT>muvO&ed n5O_? v=GMP@SO=V!L^˖oϕw9qz_WGgrօO~/̛^må\pV?Ǩ-IUBȸ Z&Wr:ze]BBD <+ofghw<^3G4 (̹FRqq7֓QP-Ɓ:(&GحQ |UU׌_8> ?PA&ώ>$}dkX?~ ԢF|IN@2r?p[ ڇvk?,XϜYe{^9a\ iK?P wSsDC b*g՝"l- %VӮXf#$Tb€VT8VK4-4d*7l!V;5SJ )-Jb(լ 6dX?T ;!|z>&2PRnl=-\o|J]/c@e%+1a瑍Mxtse/ғi;Q*U_*.(v$7w N`8@=̋^Cny'$­G3 sD5#+嫘$jyݶ:[a}5nxx`C T!ZJe4-Ԩ@aqSKpBvY8k^amdw=1 ʀ_yB=7;ӓ?!4cG]Kz +>^BJR ZSNS~uV]4MxkEWuf>Q_ Gw!d.Z.A7~.Ր¨m@_TINRmDoS.j畼pCQCfi(0ֈ v+Ygu{1+5NYn $[8LA_/(c0 jcUGU w~fZ=CºgJ v9=[rσKmm9+SK ܎aDDlŔmWgLi0DjᘎBrj#| ?N}TdZ_q)!+; wXλrOeҾ`B[j?9=h9cEr_ VeˊwIyhV 6*3 =Ong, S=MŖv~T,Em{ Yދ\!vJC:X5~].-Wϭ\p& cR5my'+ o珣֏2#n=QYМ#%6l2kLY~v97W%CdZbxc'/di:`P7Ȟ'lQX\ (dD戩v8U +/rAVͺ/}:eSbi8P/Bƕ/K kEe{eDJqÛ ˟V)*+ݖAEyU/(MfwrIJ%ѻ-(ME@ ?έ>|ZPw1;&Fa`_ ewG m@;0>{4sNr~ڼ\$) > P)ošFBUƁVN3UXs8H1{ݔ,QBE1_2(RY _zн멆>S~oBa"t 4c,JZQ Qn줫ȏ7K7'MEzHԬy2-}WH G-A!a#y߹2:LĽ \NGJko*`3^Rō<+hu=E SV3-z1t;6j.KZQQ4D+O5}(/WM+Aˏ$"meGPy%&Xm() vn]7 B_m^q278R.TupL\%F"eLXj!^5 \o?tJ=*#nw9''{,EQ92jNYs0|Ĥga{hF>6,ʱlgJO{MU/)O޻<0Yu3W_~`9 Z)O,HoX_y -[Po n !9*^a8E Чn.ȡd6+H,ruR1/k6mLUiF)\ oVGYG9B"UMF-U=6:d$l[2aΩF`mQyŝx#˳VԿBҤ/5DT(4UixZ3qe-_1b G\kWLf =AU;qWڥg-Bك5HLɥFF&*2wS$JDgʾ8í1|[x3Tu%ŔLEBޤ7gR^Lv; IN_kސ$1:rxPf=S%h◕OEƏ~=}B뽝Ez(,c2Ԑ~}RA! [Vzq9y*v*oldtNBZSw(J-1T\bN sA1dF"֣&k(R$Nmi4 U(>cAn<_G뽳 E*&%+ޗݯ`! ~n_6]uJyo&1m5Y l PWRtVHCFX8ـc[ߛF zcj"hrl$C4dC2]a9ն7KH:IF6,>"(Oݐف:Qs%Xvs|2;Mdے}*5 }nQ32q艌̨-.9"fD +V+2MJk¼ uad_@&wQ` [_{2t5t]q=^i(z٦#9hx/bk?lwUb4m*9ϡZZs?tn&X E{S7kVqB^JEi.]vRJ\Mo*XR6"4ΑZnt#q*g-^0-qTx_cv|mT^6ý=󙲁OܶIf|2! jDS 9rLinYdxBb~+15 y#D~ Nud(hǓWJ{gc-\ڛuWqEA|z?WXGYlxRgiM,a*O*t}eH,SI%80Y|]8ݵ3)hPRjzMN8X0~HNRл B c:Ey7Hw)hh@i-@Z-'+IÑ'-}2,C~,1dL wVk>ơSs#%ArcˮT=ꗏ>=Ec֓%޷Xt9q~| (r?M8u" NFA 6[u, ^,-$iV[jI֓fCZ mS%ғZj ]+^)a :h|7oӌ!)`bIUFp5aeFzY wJ'İe,wKF_ '31vńDp3+ֶV{# W_?f/''Jj׆s_nrxD/aC礣XD$s7DG:Ek!r4eE6#C ٬7)UӐ؞)b_71=1"~wQPM(2s96;x &v;@^ral:AlCb3-MdR8YbE/; AFx56;X4*̠ޥR%fph SX-s>VaґQU̎dfvņj"ט}?<|OOg3#8M% /8qd`IWm37Lk+$' ܒ+΁̌#B^11,88gONrSݷ:ϕ*KQ4N1sMb_åY/h1UW(N1-{re1:S7Hp'p>WL)76^kZ_DVCadQscxiܱ WʟEy͝f xdz? Hh|frK3Ť z|{ˊP 1UԤ:aI<#Ekr/E @AmmM=ۏQǖ2Ob&g6ъūR* \ (.dHk+W4RJA zOըRF^F}r H&2@A*垞]o;p33Uv7ސ3{ Lw~>:8EW< r쥓;5R'Ȳs;YYK}ʃ+k7Mȃ0Q1my9 Lr׾a |߄CNsųLP0\]EcIzy=v ~KAnSE]-&k{9cD5 v$m GbB=2 %PO,(J `z6db p˥P}0 iC \\Qv|ٱX$'Lžhjq]RV}C,| ܊| jbekZ5\lӾc#3EwkSCRF ׋bpMjKs|5#Yn&7_3*MlZ~>Z?hODCT=+jtn! ,欘'Dloْ\Ctj9r7Gzޢ̒g5i?l?'@ 9Q+ zd?]Wo d ~$\vfPiq[ QWߪLCت[{`I! Th{KwY5n=/& > stream xlspoϲ>1?m۶m۶m۶mcǶsխzkxfZ=k  -='@ITY@OMB"hblag+ll P31( $!;{G 3sgſUkc  G9ՕɅхAJ&&gs @HN^CBV @.&35q4ȻZ[-LlL(v(#;[cDl]M  #, *' Sn_Q+YW2_$Zh3_IؚXc6v_?9)&]e lLBv6.&;cG[?/?l?v 'Q wcy 75L;2&.6VWc;[kYd*n[#;c [3?8oj@tgG w=_J:%(hEabd0038}OF.&fTWw5Aq[VWQP0j!Y ]c=(c]J<ęLMG`Un+5ހbɂF;glSN3g^J: 1Dw!įy!C59A7)1{_{Kg^X`q {)~bF}eלs,d&/Cr<UYG!) sB³I"=%TFfo_<gYn2#(\iku-Y|_FqA%Q zș_I iRp`[.H‚u9s .i! bbЈƈf1T*5Tٯ ,a90(㑛&!)b#QaiN,j&"4S֛XAU7h/8"ʘȃgZ`LRe*'H_an-0Ylr‹:4* _UjuZ@?MVAJ#E{,jxa]S_a9ƲX6OL%v̰(<[Uw, ʹe7N~N[HR1x0r;h-(Q%kW{5t#>lO߷_i'YX'\,U}ҫ췺Z\K =t FQODӨ{ٞ-g4J/m\9Ͻ-'\8/srz\2}jFRbm>_g6nv |"Li 6GR7.y 5yw F9FTU-k $>k[xc#Ϩ]Hh1Oxi"Pp!v`eQpҽ5}PQkTҟNHEe~Sz,@*J(W b/nU€/ j9[ҫ]-cn.O>>r| ?tiB1u^yI Hu=~wǵnR󏞣◎:}XWƽV2C}l08~׀ǿ:EIN$)Id4) 4ą?w|zWBx>%YR <.IVekR+ba^d"C8\UQӞ{quN;P}A_3mMSC=>w2R=9 3$$jL99es: K`1Yr+}@ ,JA`sI>&)<2xa(`J!L0ybqw>]Ś%i=hii> PI &dΥq4GUlBsoچ:Ҍ4hNS YSR˴I]6OxZV)1[Cmҋ2Չm@OɻGDѸ`ċ`tR7ur.&s]RJ*+0gL:Qq\Evh.+:Co S]S \P~}8΋qF$MxRC`裦G9l⛘#}/ak\ZZa@#qDDlpRN tI[N+!OV\k-bm\˜;?8EG3/YwYTHGbs1uw$щg݅k轉Wat/aܮ͹]($|0Q34ogI{keGĶӁ}z!K ΄E1;~J=ܫ£gΤCc)#蛔T NV-Y{9 Ώ(\hG(Wjb9i3ld,t5yRs5ov?"yf:Y_}y[L?e!'ÅJv}txwzۦyGcndx)$]m{۰DFue۹Z7Lr_o_#!mX᰸QZ s1Ch;gyfؕPRIj$ $Gy3>W4ۻZXDU8j_SqD.,/wZ }DTm<=R\~ jvԉO,rdliC7IRdk[ 0̴ʗbmJŹLv9\\%ѦW&a3rSqZ]kBa>f9Iؼ j&ٴѝ{ڸ;ܭoB}$PJu@Gv4CBGEV\&hs$)otA0_G\#0nXw18EP~\]$;l4δ}\Lx@ӻ.9.[iΒU>ْg8Z~pox.XbB9b9K`:CDybGzgLÉk1:bZL"gZ)??G￱7y;ˉ9vuL3zȮeEiH6nuK3<Μ8FC `U&hmJg tzy-q5\kr@\-nq=`X]]O[jh0ξ<2D`]9, kpu<#gVU~MZc}5o_.%3P%aED$#aǚ.{NjkjC\1sr!-:(_ߌG >:ܦᐄ> {˧8\MAYp بؿ(p,% ;Jj] ƫbn'"ay'8 ᠾϙԙ?'SLQl9:  k^ggZhE1;-bzhJ╃ó#i&U"Ix *7;ˁJ0vl @aw?m5~J&r [v{m H.F87['1Ο@~o\2mqU /ǩj|WrKi*&h_AZZsXRi ֛s\vHj$گ|« .݅ڄwZG$ KNRq-ۅݟޖR$"zڣ;e;  |,=80_0mCO Z pB)6-evòq5@|y/XЬr-,bALJ?0@Vm"N~v7͝@rJ`i:jkju#y)^lGk0vyD 9DA^&ye 9Ni30wBR=3߉o2"D*vOj [E(>c#U\1):xbB3XN9 wqV<ÑG)y^LqKհ`|J~-qXnqF9߾pl ~S~oT80imZ4:յu Ouhx"eՑm̾(,-ܽj),.\_J xtc Wa&rJj=;#TA"^uڧWq.<3$&_y^l=Z5Wl[k3$$Cm祿hqȰMEȎ3J HlVHVpxMJzuJ<Q6~E#n J&T*g\.:S44n&oG $ۮõ4`ؖ2 1ORؽ;3cD%ȝ5 55<Ѫ#Lzanw>bWR{(7u4]LweK܌ XcǤ;Kҿ 3%u[%,ĉ@ػ/E-f $~[Z.ȵіo6)okgOiLuRzuVmkA25_WIНOc|CH5bg)m_ 8DS 3fvbpXx"d؃E_"j,*& 3\]vb[/]R%vSk}ϩvP39l蜯9.־)}E( {k=ym['ǝK$q=k#BIğQ/0XYb|Y8C(!QFF[W; Tt;1RnJryv;_ol+ϵihi س|_ጢ]'0ʈ$V4p%r(lTHJ5d1Eh%fm2jDZP1g2]b =T(H)@=&o`P0rҊqi(l4 0ݞ 1 :A [Job%{?Vujh Arת6ku+UT809!($,ʌsŪW#W^ Nm}Amo%c̵ؓl ?:=ɀ)v&gZu%Av#?!;n|0Ssf!T'Z޴6"5wWOTYSKʴ kk] PS_ɞWƳ@/i"'0Ur9 nN\2S& YU#_6g}Dϗϔ+gӸcTEv˞u)4"S ^PN9:pa[`wUX \%Zb|>A!Gqܽ'`kj9IWVϨnzrQ"1\;ƕeV\5*NI+۞C=ȀMiHNxOl{zg7:JgҀ}-c$c307WpZOIy = Jb_ _e770` RGNJa5Ojڀy[1(hC)_”\*S|xW"Zܔ *{~q _M|-~E-c$p$qKE#E)5|'܄*qCexZhQ+O(J$ :&#ssU1;HE< SZ~~:^UrvLT/fVNbMYzR G2U>uM7Yr+@P035k:tŸ4=E/O.x.sT^Ep#L`okfog0?g׫ed]h3[QE gɷ>Gq&鰺}W.= {C, LO:!娼]Vn]Cs>\^%<ݜhE|s\_q.?cΒ.an"cBdܒdVZ1"jzXCxC~TKX*5"*uMI733[,2ιk1DT'$W F fr5uCe?6TJMcfmKsj}qhyv5doCN%BdՏᇢL󍈷ٹpSkbK_4cL`E1x{3Y5SւcYS"7V.,N؃ԛL ڍV=;-a2k w)S56YoSsT֒,.Z` B}7Z"=xo) =/+I"X-RN:QIl=hh#{A4>&l+>` w>nٝ!i̋16hƾU-ea;Xj! G$<,Y$PSAF<d<7ˌAڲyD ' ͪFw76{֚ӫɾ]F>̬z?zٔ\P8 TE˃XԒhn\y)Z䷘*C^!c k@) bpQ1q&XZJf+wjQ xvqM`0`Ru*UdwlɵgjlY$G1?$5!Wz _琳E^?0pc FۿCV(|T*A ˉWSp^\ 'yjMp?bTvɠSD2ţFkh.i}yׁ65ʼnE! FmBGi2,OR֤M'|lP(_ ܗ$rUpxl/ 12ǝEJe3y224@naJn/ no9l5eZ/jJ0;񊼣\h^t@q*!~ؾޞҚf7W+nc4]maW{y(8RDS\h<9=W[&6%F.#ٷLWIR^˖tf) kǂ~M:dQ,F;$;gjp'pD(4`^!rΝ~ QIt:)VB~%3N= rU'P>zmPX Ƈ; @˪mG5iOM‹'+eMS0}a'o}V2WϪpn f=p p7KH2Co>x ڗNv"Ir 9)Φ-  1V[ GW Fg[rp{8!9s+p|3]a&AutqU x įϑSvI3GY;v@ ֱlR w4ܿNFczl'UgLξr1v! i(<R,uJ"bAK󻹷&Lvl by)f}#/i0 p_-MЩ"$IHNEepwZySɄQ=*y(=Ssǡ2)γ+bBČ:aO !Ų ]f|w*GdLDum,vGϗaa3~Gp؛v6k\!5k.wE#Hg&U}>*Ä~{ ɉsG% hqDdv|ù|*AѬo}ܐ4Xw얃nA71yeс>x'yU'3U-fׯqٞs/pˎq>/7ZJNͣx׸bM #Ϳd5}!pZ ŭxϷuVi[ eHi^9 hD/B[›ξ'k T>V/Gaj5~mȥ%obcp&ll9;P郄TӯcsO`nJ#"̚LMGoA;9gV( %Pm#,+J!n1'S65&$yCz4-2@v>A5$,.T[ %Y>#ꛫG7=o|~==pdO-Dcz_h6! ?]fa-3M/gfqĜNK| 20;{%Ql ;%St**?O}l0&\~o'r=QoG9|~q :vm¯[p$/e/!Ư<FDZR4?{rbO_61ht+$K>՟0܏15kP-k} ձjLp]a*,kVr_GyPۿdk / LwC~7 fS=7 a}bޜQI[5 44t@ADHh~No&Z-*Hgmꠥlfvӥ 3T#IUp8} (u`# +;#Pu#Co k8 p Vn M, u,}ٱqO&LOP%K?. uTO QM|<~_lo]wɭBADSTaa56;c$i5m7_D=-%g8s 9_]n!(KF qh;EaТ1DYM;Zί Oʵ9e_._5{BPʵ{QRs37/PW^ =MEfĺZ3˓vh!F_)UczuL@No_{%M٧[W&aFB:YBO@"E?_6ݶY[sX%.^7ZKx@ Tmxcӱy2)QI'1^ldJc_UDD=8 :T5mjјVd9A1I3Hb'5"=eg,Z33Gpk?NrԖ5*A"aI{=6yWp| >ýo]~}^fzqug78`bl&Fce ya׏.3|qbj9vCvAd+Q^d0/gEQu-ƷcM,2AVwlj" UOgf]$0wh1,֧(:'\9Azk1n;ː/Pg;)x\A-+8T; ƿ!wfZXF0)圻*cle!~uق8yzOp %=~d:C<.Q`"֔]"i%LN /L3yTǞ`rs?$NWtG#z,L.n P'Z$)1m:EHš]qݏi6wTn\5%`VCm˪j$A%L N@ޜK'JEbRXgeYeֿ]9ZhCc%^Pŗb+ڵtMQـrwd,{wjM>E6mNև2QQ|xx%^YJ4fNa8ÇV6v#u ScU+f[Zߞd(kӂ968 X]o*N,i%AݦqfSmU4O͛ZrةVg%->kfe 0y\ݤ #^ ̅6)57Ru WEח' nKDVmvbOJe.5q@Yfg*5 0S38QJ2fF+.Z Ou#BtV*Eqsh&se~[8Ņ/vCV<2I9P{:3XѬ.H R}bdmCUuspb;)c<#-Fv,P$'ZBIPʨU,OLT6:DTwY9%N:G%SSL`U븐nLEbD5蘋d=#chrQ*y~@dž }|; ױGz>Hآ_x3ѩ4H0`>rXީ0r RB~ӌOWNNE`4{G;x*1G7z.មǩ"Y"غ)SxIq Yp|XDI;2 cJ"0/A<$ {@,q*zޡ]񧂠3OL?瞘Q2E4v1 BGxJ8ϊ+o~f,åBZlA@(Ivܱajdޠt䠒k4LzMd?^FlhHvYQdծT jh |zQ/K0^ž2\Xm)eoÕ\ǜeܬ4Mt/*Vճ\Ki&Q#7Ÿ^Ԋr(ao1WRK.<E5޶ʮq| _'B 'L?0,6`ڂ0IzBsXUOM,]? B]tA[ / `E쬄1 uֆ[E$p t^"ZkDPBիc2|]aUmVecqbήiEnjE4 cXVT T[ea_ ߽:jxl@{C  9Aq~#fV̰sA3$Ŷv֬H7_Qog\HM]8orCsC>ۥ[OEqZs:_cw-=/vX҆|ooqv~ Bs "tm}WN_<=t7:J§*;'kI dFVyy:!u_*߃3bٲ^r+[NHϦؔJk\tcd`GOý: L{41h[˓ 9IF#H 2ӱ&$pKwu'NkTBP-2) hCXECk/hN!pI~z|-Mn?s~?LAK!N{=gUBB4%4-'TTqP%M2moێfe6ٝhѧ}Q{:Lri:`Of2Ӯ\u>RbE9EB rD)AGI9y/&@C=6;WK;7{[vbՖ $*0)_  VKVhAC<@5;??C ύFZ ivx|MT4V;~ $Uwi6~}SN&aOcbadF֦$ëIp.q^~~CƯtqe%oQ=1ELC^{v}Ze>G߷۟!la1j|WWFѡ]| iZ%>*S9elq@ǴhǗbm5qe/S;%-Їd#K70 ui. j' #sB+ckyַNVM%!8AcSkx$ -=n(BД޺~zH~YC QMNVaF ̿lJ33ѻGsE)s1b`{ iݩ#  _v/u&cT㦺K,DPm>>1 jSҧ/_~\ɜ"-ڗ|S,sG 쑉o=B7Bo _ṇ͉Hjv/nRi-"lu6п^̾{b0vXB~sIg zeuńEiگ qo;g;[3MuXsC":FqsEIgqrs(B\h'5ֆ-אԷ:__E uEb A5sٔSG@Uױ9jA^v.+\XӍd<ɩ]ARA.Uq8>%vXMCd>F-0 dܹ6]^|* P~Ӿ$Bށ*:[S"Nmu-hfX{C2O4:!n~tƹjAd:n:+8ʖfmC 3-L?;گ}O Vq٤am2)gNw@>ňwU0 O蓌i3ܨW6 zE f:cܘ*R t+bݝkJ[')p^tĞy-n@S`sf劖#Q)o򴒫8J*PQLv/Yen620o'G3;y;77zb1xdįf].ٍTjvZ=8T5 5J Xc0_/bB~JR|tQOB~]n_܌ u#d\d^=RH^0[8k> Y"J`b+t9˔u-~HvB>1|vd[Q 9"M ׶K޶(̔ D$ȪaYBs&? rAqO RR%2Ƀ k@GL#\۝pX)Ot@WvrmnF˘XS+WdAҟP*U;0&;3?􇑽/SۏF̪寍a=蕐tډA,j<~=eS3&\M!ÞkhoҍU$_sjˆgT?Um4(cuj%w]ҧC_mfieSP[#^a(*$Jm)JF:Ͷ:u*XKG/kܔC=@T'D g -ny.S°"WZzWqQ !/}eKz:5>Ny U1֪%!3i㋁󟈲ˌdS |~ڃcF`s6 ew˾HW21ǮFA/#z3?e)KߒRd}C?r}$jy@rP;_ gC`ӥa0YYv&8 xL?ZZHa%.XqaJ#(8ulRg z> (A+ϔСRPjU J1kKQH!/8.?{)bȒ~]_QP`v;1˲mdak03)ܖ' 5:@!FdN7kDE ݀T@}̀)OO[ 6=$bB3v۾D.2eU}D RӟBzEXqE t;8+Ẃ+">oaPGY^$Y $I"߁9F!U0^'Yqd}h rY;uW0)Timy?4KbԉlDVsaj\\$5rnf#ea赣%~9 Q2˹n,n:ֆ|aQ`{tmR`$ۭ ţcUP-Z)ɭ%PGJ ee=x/uc$ W@dD>z3):*Oӣ\CyGm?ޡjlEo^޶V?c$nG3WZ=se7`;~P_]L]kZu lqP-ybW,v?Xi2z\j|?嬸SJ"`|XGW7_s|xHkjLwS03HZZݾ5^n4eW2GnVF, *zZ¶t> stream xlsp.ۚ8Ol۶mLl{bOm۶{=gZWWuK8ػy9xjjLLL&V8rrQg+ 4,&&f8r+ʔF3@.&O*p̭lQE%miI:@ht6(ZL.@j3? _\ 0sg;@\QM`lo'Յh뿪dkJu 02u-ś?f37q|8vU0D\y3=_{8[cPc;+[!j'L]݀1k7@3+7]5s+SʿcTё&[fk[??XO7vu21EDD-|s&QIr]7S8(X7 ?F= 9imIB(g}y b2`LDNyrw4RJZf6{ '/s읩7@3үJ+"ҖEzV U=34~¡(ͯH^Q#ǧY\Еү =~x$l`~tPXm%) n&QRGR;"j d.JMj ^R@K.P2[_VOun~BeĵEtoPK+n2LĆ~a[1Ǚ&^>9>塎"q12d {<_fՕu{'.s e!:- Wƺ-*a>~L\X+FahQt\w#/KKi+tw1ދ_ Ġ-gAÒ:vi#IEhp[z9P>[ 6bdի]3k^/(&+98i!-qNa}+*P:**s8TmzN׫.2Wa3-1w?nF:s:kEy\IhD:M[+<ٹؚ/IlԔ\'L}.S J?5ç̆_d)%؅ؤk \B7Ns˕`joz'7SK#)/e$u> r |>Wc> S%\/DLXj?ThITVD49jτ%ӉãV{T? /WE򟏍%n e5?Xzi%3[ݹ.a_dH1\,`W*$DJ]~]pzNP&#[+Wf -߻ihZ{(4甂VsXîe߬LA@[) C+FDpl 8Uda$s&,,:bQ2ƒ!DUtvmMCJf ?"-;u9O?O$('ަfÆ 0~Xܤ1pvKz97SIZM{N[gYb/m2 w{%6iOUlFKAXrYمVĄFJF봐<1T5 M3'Z@T?lKT/eqVC{Kk#2]c\kd1=Zoi!#dZBeLvy1߈ LX#ML)bC ckTxu?&~K uy`#37cO je2_܍,!"z_"f+3P_Ѥsx,رO\)F/=n8اzr`Lyyщ`9lJ¡>3P u2y4!EŸFj̜-;x, X3,xZB4JA$j~"vFМ$=gB[ݡ"!l~"ҕZ`9ɝj38?DY +W2Iwzd*pӊ'L3J:S%_YI]ፚ/gUY #if\`֫|t>3o?Vq pMti{~EfNO7+GW4dudu)nwp{Fwɝ_ $nS4Lj4q˱6"\q eĶ+rKBr ]ayA__-ٓ+8x5te)O<_g.p"t(;Qk-[BΠ*IN ٯ?Ȋ/xAH6;‰?)˹U[]mf0 ߀q#Бc[Be:((٠gJiODHװÜ[e$Ɂ XLgL a2A7 iO  ߎu K[fEbȻ -4h@ҨXr=6&_,c:2Ux⏟BG%516r=4WT8:߃(/CLt(s#Tu9lȻ%vo|iNUşƓgx ߧK6z1n}{TH)WXi!;\fEY<Νɣ$ʐ%4a4=/Jxs€ܳ.r=M% GY:c/,nQoʃ=و/ ;Y:7Gɸe2ls٪"%-pkZ2@+eLfgt,II+rSE(+rۇmP0Z:ť& 'QZݘћ!Ty$[&"5`xѾf$sF&9Ѓ U \+\aa[CZEMXZ\y Ϻ~{#+}KvU^#7-+JT] ^n 6l"0cE!bL!55F,Zo-%EK xCpk|ָLƮުbgX ܍ײ|V6}xvb/,t֫ɦB%(^~2@+Bdk~[k0։,q ?)ѐ7]]0Ԟ~JFז.B\:}>pxMy(V|@\bX¼DeNz~Vzf^-0J_=1=Rp\p_G1ƴELF.E/րpr ^e>uA>I\^zE-H(#!yߏc[ BdUrWw{1t/?/>4_y?Nr֊4Jb%Էo[q1 ع;}okD `Ýl6*f~)BC** y9 $slxF9R'Nn4>0U%QsOy@'{ DdVD]DVXvW "q걡sPUg-m^Y4dLa twZ31mW󡨃tK%)T( !o|!bNNg)JY`s!` 3؊6vCCஶ*@( 734y~Ջݯ`7 %-U1uYkFA$$X< uݹէmŤ v$q|ot.S>*ɂĵ{%6-x/H,H{j!MLiiUˢgnq̺җPW6n9k@:˺l?duM +(4a 30#0߶0 :IU|ʉ\L=޺$v75Hy-.mYವYMCCbꙨT =-nRdkĪ0%:1*.R:r@*}ɵy7+Oi|ba71rU}gkuNPpIwMa]>̰퟇̻9/#h7E5+jGVYSZQ%jO~v rqEMl񦤊K:ZAG>˨x!ö3t' |dυmײ#lg wӬvӬ-HYt4J†0C0WWc5FbA7uF8vO$3̽u$BV~ K/֔LZގi]PFCr=TO(( 0ta.,7ȭ(FM+?E'6Ȃ-F KZ![E@"ŘwlMZDjmyN}SN"8QI!d0;zn'CW!ej0R}!6J<7\}^=ssuqTi^ +,yzTlVFmqB6rqSCR$$(Qxƿ/x*505i؉gUdKjZU&wwĺ~W8Q ;du1m,zX]W;r]8^r91BtXl 8 ZE64 k]aS.g94wC@/ZlwzA]Sw[ sb躅Ɖuimڶ]aX?:md?atr-Q'ϊzTj\8VdyFث$RqSuyciNNBMhD 4OpJ~MQ}x[5daH4=95D""t;e6ú<1[[gla=S0Ia135z +ѳRE} kMn TjS`YwR,(8;wʶHjm LN)CP9 Ftz[$emuIc#ݏ猽hw5vtrGUy~½?DxH3RAu_c99cDr6aŞ8};u ~:Otew7Ylp_adzFnWH`:`EOb #+B7v5(8wN7+d 8cr)O%mһTz$"x ]DBS<<Gb^^ <&x3r4]4M lo5ڡfd} ]*k{?אRrxVzԙ 5XuORI(3 X)s =[(m թ>aD>TySf ~QIe0XĂy0LAstD7&3\HXJeCyʧb[{mI=d0RB_vQXJ@ o8}x׵(̤sS=9 l 2Hѝ,lMJ.s~/r&A&DЫnU@9`ԍ(6+`nS)A *@IWR>*2'X`MPTuHZET`.LFC1VNg#3 ށ_2ýO>-j˻1kثykm&b{fb Z⍩J",$rehZ @yvh|¤(Jk4ĄTpj S7={jPy2u1B wPÄl[r6'#_°jẻ#oo*-Nڢ"ɤ&#,{Q uGQl4wAT4*C?^Nt?q4J3MGs4)ZV^ӂ,^S $4ioZd  hc* v5FRm;c4$B7F07;D?~g8kLzr'\wj S_kPW*.! ! P!Z?kPO 4^L_?ޠwhD@tQS5XH6+=Oϭ[̇X9P^̷n&.dLy#.!\XS8Y &\Y{j.۱/T{9 ne"ʅCr=Iz*8A#DJgeVAD2D'kR"|gDc ѓA>%كF URG(WR5րW_'&/[a,~5C!IwC9k{^(ab3> @*,f}9p m`!P|a˞y:#yk1kQGn"FgJLavjAǽz'@l.P &9݃:|Vs}$G7H=Dw͢e}ҴEY }vdj_ݰL~T8Nf'8+xaukc7ʴLOJ,(V痢D iTU*1\D(E,\Jr{A;eUgʷDLs_4h9C,L1kvP0" H/6L,uQُIHKT¶X+Mqrr_PuutRcьP m'2g)k<XMB-+Jxp~fǵjtaO#Vibg8S= `k+qb(L=?x49Q#y`o79D7Y7|sհv@# n:qCrNv=>eĔILӲł!]MSҤo6`~|۴L߰K F K$"G:"H~{XZMw0iT kZh茮`Fȇl2(WL7wѵ VB(9#4F7a$@F) s&>~XfmgjcK֗UϛϲJ9WntK/N;Xm*{c xÄsUdWo_B-)c2ؙq/!*ҥ]{gX/]xaaA痟㐪G=-sJA00<5Bq_JjIb>aOL O!7.ϬIM Xfl2b ^h^ DM-GmVdh U<WZ^H .{~Qqf#AcE>"*&ɔ'V s0b2@9 Sn!36 }V0Sr嶠ˏf G{Ar$54vFVѝ(BZ`Egy-`FmCku{07M=oQNeZ\9Wp#@m0U\]y)@ H$oÝ4sK!6/sr"nޖ?Y{ C$qe|[,@kby'smTԢi.0myaۅ:;nHQoڎW n7p *6dzY C+7k i w!"Ng/帍>m,u QpMBb<{l>"ꏩXn54ƠHԯb![߄q_lW˲R81G%&p30n$GB~4(Pp+ OAsA|l\p ˿ʽNHOյ?vz`v]eW0bhabt8mE`@+=E45V2٩԰|p߱gS W{f>=~{ÜD$a!OKh`=횕3U'cĶFtܮȂcHV'`Ry)8z{&6{obhݹy+WaLqK[lL&שcvȏ?e-xtMbmqk8LIJ=Nҍ-|SLIr⹑oÃ_Gȷ~r`m '%0N 04eij 2!z,-gp(HOuQCQ!7ވ$uF3 h- );zjOI }kɱA[^NkrbN ً/oͲig/w[Sod|~%!#T DD{PeC8fByqbI )%2'} k[e6oYÖK T,yr@InEE~SԁMc4#ؔ$ĸh4Dbv`/^9,ER:(cPWԶ7t@%̃)z# M2dX[Gj(nHa7azHZ b6G8:\M|&kRԚ]{{ CXMP?ryXJZ_إ|9w^gIW_}*ܱ6 ínUlU4@ZH:_QECPY pZC@E 9|Q;i (Ѭ0FA7?`(xr ݅yvݖYaS1+M=94Oݦ5Tg܎?(|^BB!Իk+iM_- ~YF5[s[JBT(NO-gIaƷW:aQ҈/Ekϊ4rA=U85/hf?oK5\pۜeoabΈP#Gډ}:տn#Cl>ԗi(;đ1]t$lj>ո6j9wFrqIQYg?>ozPV2\l."p Av)r4,0_1[f1ZLp)_eIP ؎h4!=M"NPMIj{oS2%>W~JSHb}_Aځz}cKxHCd$l8^f@8 i{Sj&j/wu!v /$V$B}gI!uWZe)S0MmMfzt{' UR|NWX;_39%ojb܇ÃZ==hQy=` T(&٬辅)vJ}CM1"#]x!o^O#BPEEk3? : ʞh#u1mNUD)03e8@Y'6[D N1{c ՠcč{?&#k1M h4s"(CO+\L sUѽP̪|J۾S͒'n6ǵR0֌-vhHx;/1AU)@?b3.p uܬ2pmiuNtrIxw|pF])w%͖9SNܠ.Dzٓewݏ,h5i.y!Q!~mqɎő^ Q)d?|Bn gˤKMq*)]yGq[R2QnkpC"EWZ%_\`ס+1[`*$Lg3M[6VIw~<5>Cye=IBzVY!_8^%jHU`n< Gp⬥$.g0 mE5D^F ~2hL.tvoH'ZJ3cEnPq)RHِ´lҝu=3M c9? [C(m0Ͷ)h@"EDĒ ۫tSf#ݪ8:a'dJrF?Jw`@R_5MҘV 13H'9ՀHkÜxyQ̙SE3Pl )j7Tɬ0 CP+HR\H}wkQ$OAHyi](/Ū1_Cft=&D.a3 Nx;E<҃7?W(`UkV)u*\1ŜR`Z[mS$sҮe4W !4 U3XAoNl5f-F#qᙕeI}3fبfK~NxR,b2v*ܝC uMo>Ѥr.V,]kY|:J-7&U i !g~R=<7}iǾD,J8UwĤ[ψ@i P%#ӹ94cOEg"m'ә~x0΁%ҁT/Dur6I Sby׮XjA:b P|w&bm5K~:X)~sN$̿d9ʱ#L?%쵲oDOo=RS۸B+O ós0iJT}2Y3iȔW+dHfFu6JCwMGEwB"Gm+f4"*iJ="rz'ؐ4; φWZ{t1.|C*Ҭc$bu.έt]37lWR`NˠL[}NeOy7@8#x%'ј#0L%cJ!.w%Q^,Ռ| r _q71bwm@_Πt1vaM:ڋv `of 8%]~fPDqu| N;cH|a׎.>eHb*PMWE_:+Ѹn>&3PN@"&.NBmSPeBcph^n36B^CfW~Fj şTv*S:b]mNG7O rD^2|EEPz}-`G*"b1B rҔXy6g^kKG{;Tgbc$||!ňiWifMe=i +vw̝0zl&R.+PtyfR4ԴL\|1[,1@ο00d .MYx\{ytNttb]jߍL1#ny$#(̠Webp??@<%o_~T#>˚,$%P5MvI5a@q {瓤$ܷtxM"ʵ9T*~>Odp 9@:~Yoa%f eWa Kt+6)<r͟U5WJgsҡcSpBXh$]/wz QB< gvCÆi.T !V,-Bu魒e^vUe?%F\c` S놽%\֠#$%ƝH1}u={+HyуVlĻeJ'd9am^.FA((>0 r\ Ũ(7co3vy%Eh: ޻a'6wb)^r%D.j~AAÊC`Ec6^L[$*.6Iv\O0[ _DsbmI|1ꘚϟlTbp<P3Y{De&W\&ԛ\,Z)_j$n&9R}[K:bdEQ[MPдu|%@C,5y3wӞW`kC\"'a-u;Pf%1!Qhd;L.rB(diĿ XNl߷;\} 6M:l;2Kvl3 v)R{ k s/vpEcwĜ;(ȏH[تb _@jx"ȁ礌$j ߥRMpG}gnSs{`ђi1*~(pҸ!u"cC"aGg$ m9Hd8E>3 7'nA`0홞 x%MU| ٹ, -N*=5zEةR fusͼ$~2So$L:G6:W"\-N;ݶ$R[sk0wqj۱F.|Og-jӯ$'H)5-Ր6XtkZ]֠ 2Llv!!۾F Жm#,>5p=8f[u( ԭXIŋ: cЕ@pVWD1 ՗S}% SSQdݾt" ?aok1GԇErr47FFP6zr#W&_a x;AN.5<`ObUt< $==uӑh8 q `whr/ubJb&+ pG+r:;|$~1#ǓK/OEBX|cjBLŽ0Z6̷MmB薼@gYLd*tFkp,^VpN%Y JoN?V~,7 O5 ؐKF,J6sZa9A[z p&jH+)MS.)Aɞ^ߝu1^C<;MUhY5lG>'Y@FMueINفRi{UgÓA"aeE6 k &΀ ˆgZ!.s3pዴ/T`sHڡ!=n򭭿r D7 {$n&eI r.M?b~fE U}<}+/%&+[;[z,pn^Xv1U;,Û`Տh&kSk&l(  Id"[!ݧmT6|BTwg|V9/eJΨFqH)'ԶIi6.j^88p$7"k*ݭg4,J)L{?!aHcgFHV>J1{1@ǭ0ҝ?ޅ"X'P>*T[vHPY/D'Xr'pмWk酨v, e٥\>ʋM0m'd$֐>}an{szoɗ]i`u {4%["& XdHIzr,&j)[X7m:Aemn(DڗƳ;Ê[! `T~sy1Q=c,aU.!VWTW`KwTOzERJD*imuG YlOjeo:< 2u(1լ8p*.K2hP^.QcLU}h`qG-s"8L7 E3x{hul7g.e)A3SZ]%|@;^' 3aGʕXST5l>F <')8^˪J#t_k%pxp/n5NbU15ZĢPO(Mཧ"s'I_B[Өu{ޤqcrqr1o7rBc\ߎ/s;?,|ld]47/Hg; a*Zf S(8Mo(JKI0D)J =kLP=`T)V/Vz_v4r/ ŧ;>Ϗ/@ ~R΂h<-Jwi#=®؄p{d%021&o#-K 8m&_*}}QL;z!p U$}ܑIHg7SAZfn\gQ`~rzF:3qe6b'cX2\{^YjSX,0CG;}S{8HSqA:Rߧ@1I-ڧe**Hk8 Iu`PCxp5mf@L&D.%ئ@7EImLX3қ!Aq1#B "Z!zD"6tW=vb4`e0Y@[m48jN D,̣K\fqx۫ ކ R 4W#b{sk=Nbm'JfZaDόpjg [H+qv_ ΚӧI@ࠢo$Q?wgpeP<UhNln.& =tw+Kp ,(TWOJJ[ބlz N]hGq~mw5w^7=qr'tP?JvV6-U;+JWdPSf/A# U1.gN܆z֍AӌQ?Qln[ئ$ԚrHF``haG2B"G=ۃ=0t:^JA[#+QAijP,{aYUi 5K .f$sS|(Cpq a<'E'5vБuj~ڡp/{ER^H31IW[\2J҉*e#. LT;~hvw 6^Tip.4Cьhr5 u:;6_檦L`.D;_nflASTd5cKz!Њ.;^2(/;e"?$M*6my[WĮOZOѨ 8BAa0Ѹ@ֆu;9n^:M">X|:rGYCLL O}տ⧴i`q[CtP\M jؤ.kؾ,X0}.dl ^䙨M =P<ԓmiC[x7 #N%%3o1LLv_|6Nt$)GpYN0Oyc$joGgciFQL `2 zR=y>4cW bڌw:mHl|n,7a+"!QED:rC-)|ߍt.JG7d%--+6dnOBn7{` _9WXrx)}Fkz]D" T*p\gUGkU) cZSBq$^h.&0?_F̧VAxo၁m#O:voxmΒuԷbMQUy<=o,M/ǚ)(I־"dn [K(\Hˮwǿ5Gv炣B AN2 7k bUt+جfoSBřY3,&SC`08/p4UG#8GFhudx:oSZAW z˜ZBQ~/P,55IzR9iF@|d.rqcާln<?M'7?q=nt/$NZT8JMɛZ. ƞ{_x܆?;>|h}F 9V@='C <"C@<t$*rbs@݌,+WY}L{qR-Utd3E֯A6p.5]vc7"BQc,z'F\+zCnl ^FyqP7^KTSDX̔Lҩy-iLdS@J#+1ې8(? 79$TVCp8t$~ UD)/z} 2RRNl חtU7LBner%.Aי@!$'?{"Fc>>Rl¨`j[L8^t\'5J5Y*5}d^;B!PE00w,7ۊw€S'{9\+FUy5nL K$K50b&?n/| Jtlso6[GMb;׌ߟvL|gEo=)_ OpD4\j% m~c0RIT8Q̆1I 5xLԺ-`0~Q !>혥)/ 4r*ՋrwPǗ@h,9fQXXIӫdpf2#;dtE]%d[!6eQ #±g2T{wVhv֘GL!{^Br'1 mfJoG-B~0FO^73湧nz9j=;\BMdU~{.c#(>8F4xx`^T 3Zh`S@ ^ʨ'S9\`ʮ W[n7~?%0r?";zyy^1f6w!Hv."HJ\\d'\ +"oxKq|5D}W19MC? ?P,2qĞ(cȽ]U}$ph("݃߼*LcOmBu6Z#O⧥?T]!PC@QB H.RG(cԄE'>4L*)Y\h Нq8DD1X\ G-8_^G.䷈@uA4C}8Zp^#8cLܘTpk|Ћ4EI&i}i2 lgΘDN]:6l_b:;Ҙ`-ȰV68v\{zސ,\-!iiSx9^dDŽ$!ߏE3GQyҤerT{9Q|jbȺinRZWZ&L#i'vH!*}I ׂ BV3zA`H5\I+'\2m7J䱩Q@=yC怩C|ADs/]uh Dumz;qG(9Y2'sv nY&O?]WT9NP戥58CI0Untѝ,$Vܰ@Ԥ1"&IȳOlaUDgKcO W*/L]7V6ݩPwʯ5U5…F<%I ZӬo9m&a?ڰو !)k+܂n.8CQgAںSB"4Kr ={%1~J3Я X,FiyRbڿkGbS-Zl}WBadEES?7QD5$4ЇZ|=Gze,ZU{{HJ0|$!:hi˞%| &geijZH1_DZ z䚳\~"t?$p,#]˧$sqL%̍Y+s}fLJއRC J?{] ,=q7GʕS:yI)TJ#l<%c]zbP81GcVzԶQ+ {]CF mcX\݆)>*B8foP"W 4ȣ{b7v4w'tik(?ܰNx3㰵]JUTM4zc|?W9>Cx2& *1Ne􃤯zڈd7&+Pgu-1(LQIgQٰ'Ga $)eO(  J7߬tw/W"ur(abaT~xxsoOU'%qИ&)64fQ>%lpL(OqoOL̲%D2%5B ͨ&^dg XciTq ƏH9 \(7K贁xM 90KWOKET#B\ss~t3u^XT.O;}O"_ĝ q5ƘRO2%tb``e3ˉQ3Du{~;ڸc cS{Yh/ĘҚ0RvyΚf{nk*խ}c+ʰClxYWc͘>:[ VJ٫F ;co~. eA|TqЃ̳N+9]oJWi8CK+Xq;I"Q9ҸpF3+2g/ՌK ĸeV(F16kt\g-#̌[6 +o%P␷OlA+n>?*ϣi'3?On2GĎӤ-ӱBITr<6GsAp&)7FL<xWiEo@!;p("6qb*cH;s W)jYFmv-^c^۟TeЉʢϾޟS:OUjE#O%BFUM >`IƇڴ\fy096Y5<İv|.'(kbw[ A yͭ%؟6…-[7F*ӽn RL׷;xjI!nMld"5|^@`-NoeЊE8 nG4Ҿ*wũckZ/8E#bqX"X ~A4Xv7i+\{7#i,=|Lb2n#A.0mNvR4j}XŬ<ֵ~%-Q<K_Lk#ːkX:ɅՈDKFuUQYܓ ߘ2< ɭ#xЃf5@*koRs5) Zizihg*@9).R 2'kKIyEEv_żlN41NGfsmT/>Wrn_!U5][w$"˘l>OW06t%GX޷tFhz)%B~iϿ ŒT'LnPb6J;#*9?ԧ4d"Bt$phV `co˗^c{ [WNnvҁ cG;"4į0ld Ɓgmw8`-O(>҂fv6}bFHP3q_^~TK_ɰY:SiO^hդKfVR,eV|@ qՃN€W!ɤPb\@sPPÈ_4ƓGRpcmuc&J^$(S.{++SHꨐ9{?OKx{Ƥ3 q7bFwtXϺyBcM>X7 C֫׵r&G硤dJY{2ק瀧y订lsb XAؒm&xVy 1 թfV'4l.4Q1[60//"bӺdlǭk*8~ζEZ\⽫)+ԩUjNh7 P̗j r|mT@[F%:ՏKesqiܷ/D3ҡUE1DzKyVӤE>FR`2GK'Ɏ7M2pjgNnΩ(+>?McFT΃/{!o&+]m>Vc[=SEHiq>_$#m>~])":)CxKex4l6wrјeN=ʰB<;Z}:y ] *D0lTuGߪtP vi| &~h9xDw\}8D4OrNyG€m-ZK} ߭˛'o >~j`]KzE$d좙)~P7Ս.XOY#M퐒 \GڭX.$8ej]~y^6U]mT?,񙚕ܖ7,t_/&nNP +sq2N)Y`LJ ѻM8iM{v-/0-y {DI!5 cU_j6N >PV["i Ɵ'77&r/LjxǞ[G wT?2_3DLa (@--Ft!ᕬkMɤSi|:zf bLg ĉ…#$pvX9.O42)^l٢~#rfګ`,‹i;ϴ?b0ߎ=IC<ԩ 9|>T)d˛* +r;^DujPur I'

VKEF/|q}3/%paG4Qw_,.'ʌ>;9m|i_ _Ѱ9$-M ɉ;k>y|.h4<knVqk1=Jan$ދ'? ]9C3s Xevxk8J 0-s'Ғd۫UK}_'wJ-43 x;Vo+2gէZ[OKFx!,vXH+UcʛwZN%=2<{@;1?>5J"LA|cQ#}7-~MA1ZJo Yi:Ah1Oqtpu0񶢦Oy!KIϴ}=QbAb* 06l?]o,k +7|ęnZ`B(Pm0tWP_>k\AMd!'tՓ31 ΁XE'/Oay'3S{MPs?O|Ŀڳ`6QO$%>D/02ۭ[g/NEhSjC>zBN|S`}&^E] wDk#lQ뒷*5EGhb݄Ukr/7]7DYnu6@[EpD; f~\Bpwm oiMTý ۲ª}y ΓW#J?rxp.D;f)ܷ.B;6e'OF<+j mbqS2LV4jA`#VzC* *Lhffwr*l@H %smɔg/.zjt@9>b}K͵O!],NEU4^ɇgMTdsA:U_̡EvPCi=PsNcrD}  w2o#&$3䪇ϰ*iS*мFC7*+'3 =?sA7عxw"^ײ}m8-םϙ{_YYeupD1zJJ3N j_-P566ZQiW"|R e܄MUfPwpO2? tPl%Q&LnmAWd>dC1V@~G dye7x bpq+5}ZhҴۮMwHAA_\Lؘ㈣O0Wޚj*k1> gY,SXQ_~ǝ."bfN(2 G qfb箛 EDF>jþpyPUܣs8,o@Z#'nއ .haf%| [-k/9 /y@{.MG H]$e3ΎSnad2DT$@R>RsK򈌺ISl 7d*EVO$F]z #jl.:b1ӰÕhLH|ղF {a_,MU\Gl9QNGՠ;6+- nxϻ{ZGO-$?}H -0 /b'o󞦊*, Ǵ}X-g HɌBi{vPgHǓ~cߡ1Q "zIwPzAde6y 2[Jxg3㽀k6Лg+w;vtd42<Ѩ//O/XAq rA_)Y:+MBzah0u֜U #eJ$0!cI'{zNtBb^t#:pɻ2.Pϣ o?'u @FcehŗH4].𒏮9AN~Uc/| ȿiU;v$ҢWR;]:%e[2"l. 16f뫾n`&a=3%L+7'g6*i>.f\Z2vkEk\T`GD#Vغ :ԟ@(߆b(ZOHc ȹȈBI-8އuGLY wѷ n?kBb̖*&OzgΚUAvp6RrE1?ny B/"./R4ԺcSIܮ!.V?}($6G$[Q.xPq)NaY;놄jeυ{QFFGT~tA8:n2AK?Զ00x 89FCq *ƅ3w*A>f^H tx3xfrY۪5=;Px4rn<['At q;OS=t{){$jZ+FIjĺLcMYV#d+{ϻUWФ t _haF|iuz$fvXf1ʫ]:)2.ޓ>~oȌΦ+q 9Zĕi6"9PA(#85t>VwN'@OhEx.,޻R2%ǀ4?Ǎ asF7Ev f8b7񸈾AA"ԚHt`L| lb}H mB1 Tzge!0$yZǞp L* .Kـ&BI$ΨwoΥnؠa;$Ss/\ԓרifBR@+/L25>i.w*5ED|Mt} u+fՆ>xؾAKtHB TWigOf=5kb3e@%Z0j5$$xy81! 4U) iu|Gl5aܩkH?U]~"ڝ{ʢғ*Cdm`eq!=9\%QCV= w>W0ڵQ*k=M"U)~B*kJo;;Ǖ_52ky|xV0)9@T9}`@c:0{j pZ&C endstream endobj 123 0 obj << /Length1 725 /Length2 16817 /Length3 0 /Length 17354 /Filter /FlateDecode >> stream xlcpnݶ-vpŶm+m۶dŶm۶{ϭsFm95ɈlUBc~w&O,/mr_ L>iDTAʾSTsF(# cv K/(J38YPc7$&fk7z0?J-kp-" ڬſ~LxԓDX^9+;k)+x\oUT4K&2dfb|.>Zٍ["fݏ.NȬgbtC۪N$:_zs/d ?y=EW>Q5r'"Bfu꼜Te{u cɻ-LuDS[vA' |" r2"X?P-@~,3K,]IUFa^BoPD:T.TX/ D&%tI RߴP(A @``idzy16ub>ªPx3i5}] ix~7ߙx)y0T/c&fȪɹѺB;$=@.z4%ic֓!*XV ,8I^v:i˻$fv|ZbB𼞎Y!`fQ@E߲EE vۙi۝ؕ] d[-Wߜb-uK^k[v(ʠ7ʵ_k:byҡQ9!` .SΈdWJ#ݶ|8^*t TYPٹ(wB~Or ξיO13u-&^RC"M}%Og_(t-_NMQ`KQ|΢uON4a1C6Oj%Xp'\^2FDBVBtMn|+ȇ߀B:6Z~Ϟ~txG{xXűf>k#:$:BiSB(kozm߹יI򛩱,6R;b컎DHGԹ.AyKH,V҈4_pI)]x(#{^u+]z޴ [֪UcftnӔ< 2@Cĩj$YF$c[?NܟJj]V}Rj݋, p P싎-uTn7/ArDNxXtam/icI!._ IёΧ v_h V]#<$ܚ K]$!} HZZf=zۙ$QA ~Q̍8< oY~w\Xra!0.ޒP|q{Na!%}^ f5 S^U˞B[DXO .dv8w5̗tώCęgϳGoxmu=xwHiu{Q9F݁ ě3uVJ r)VFzX֠ա⢌k 7ƞf['BBzܟg}~iuxȻ1e&SPN#~#-P| FaUD:sd=Q烐epvfj<*Ҷ@5^zA9rF2,,܊$rwGA1 no@Is༬2Y0cYYf'6C(ývᾫ4(ežQXsu Wem#Bq'Iz,nX 1n7M+m9RÅf:'TF韡ՙ`0o&(A`_;1㵣2'KQb7G ,`~PL{0T- ,GzK[`nQ6pyxnvaM!uo8 {l| %HlGE,`*G+r:qI<Ʒ؇C9`u)` ϧKʼnzA~lOupA*Nccw哩3ˣ5Z.0|LlcNԬPJ ~;Zq}ga?OBߊy=? Oɟm"?  b 8K"2UPH4+D#͠j)#)av;wDWCX\) p!k5\,yPA0j1K< /IÓ@Zv99yóZduY #|{ &nYL,8 LSWD).5*C4߇q'!g߀_RaL X) _]FZi.Q#*f*Y ID,(bPJ㦶e_zlkoSCWg$q9OsAVT6"àR(*n tU 4FbrV1*~Q&)ԡŤ`FAdKiРCaaŸ0I3?Ĕ t*?b<\h-TZpFZB]5vtDre1{+DC/ehRvt=27ƈV{ fJ +?㞖9~@B9oGo9=ogϠ02M<:ޅ\ n+7st =0V 1 U?z/RRWAGIw@Ε{trrEoz)X}1:K߈!L}[U;0~T_B^FSP#%4m!.v'Ƃܷq/gf=$SŠ vE<8"[S"R˥$ݎ0B߸l ź! Slm3T9@L(9HE:,Qpo|5!n*wf #@PqXtї0F^wd *LPb5 ^h"Cuv ޙهqVB/xEB`2ʀE[f+̓9HK0~ $(NGJ16-(P B[HJ~|{_UoYgV{ϣ<8HdED<7rr*9JuHaY6^VPm5"Mq9ۙ%4ڷZ‰v(6);D5W3AcD{M_ql %eEYĀTeD9z;вKd7d]/TJ5~Jn5G !?5 Y¿kk:r@Q`8FPn0‘Dx;c޹humN*3vDÛqt P}$"(^L%vfV\6L3UIgo`O /^T<$:Pk¸'p(DEm孍BN\l8h] vکmb2CǪRIMЁ@Oø0Fނ <$"J޸ x5^U ^QWX<}<& XJ#޼lڕ;DrJtV g%YRȲZWAX Jhuih.r Qhl^|O mz\@, u3lSq1rR;<ּ`>/:GCYrP0Z-aI7FS .qO FGZQ|M%[Тb<{Ñ!^bﴁ7gMJChy$M5)cVC'~ 3w¯MhG)<'amr)QatIݚ33z V]@EBY%Ofh)X^/T)Q7vC@"(ucdTFs|ٓÉdu'vonbu+`ݛۮkgf]yΑ:_\'ƈ4wRl̎INm1gΤ/<гpȎ ؟ZΥuQn +юNrt{!GGt_>:W 74:f/8gyU~1BĊphs"ndsXѐ5)a$]Ex|`_qŪdZKI4_I)fNd 򛻽k X{` ͝H7{óD/Pt#3Ω9yM q xcD>Ѭ[9'@qC(nQɎ P3'\꼍N1bNj(BΉLKV[Q/THKv'~-G֭vZB!d!x3uJ0lam!XBDkYZUV`R^N]6ȡ@259tMQf`Ճ[qQ`Щ N>|ÃGzoux_36w^SI n0K&%i,{y͎Ƶ\od.qRH|9-1tgL#P(и#3' $>bBwfmAs>Xz'lvS!ߊWF03ג9ܝC-՚|Jq튶ZDaf$# WOAvK[D5_!{;D8A C:حG5&Y|8E#.: *?2]9Ƌ܈z9SfgN_IO 5/LYg~nF]өW8ǟIB)7?L=9=v^! ܎]z,NplQ.YW-Jv>A^ƦEN/$#eA,>)`2{-k>@3vZ_H~B9.vs[> A&IՏT09nۺt:Zi`eAy]=ϛzkVÉ9T J-_,ywDbI^y"JxM&5rݻ,Zѱ W1_ TRf۰ ZGOs&P2悋ThRꜞ-5*k JA GSΎ+%D)b]dd;4ĺtmw+8}=win#[ԔH!QkzAճ!ԏ8A붑52 $r>l՟o/8萨?Z~5NQ 'q"Nhv@zRj'?Z, lӞkHNʘtO{uvwJ?= "PNXlMBX_ʼnҾ/֢WKuLkW\W'姒E̮1vhVKX'w)N~ 4-ocw*LxQEbVg快1$#IB^=dܨ=s ڑgIub?++-> 0K;NtR\ue$9^Sn&/?Ëu)nyd,5+9\UEs'L+m 5o׫F*s@cQfJeVU{CЙLD(q(J%7懁šEw]oʝg.wzkb9q|%[)ܑtl4Ŷ3S9]Y~GlWмA'%NFMl\N}J~sٹ,F m^R;GX+?p?a0huSzt|{8lz0?|:dO 9s䵔ܡ}sO ,Q/WAEMAO'e `*7r+ ]XQQgN7,(};@O>Ը|LtC<$(N<_|Kt8K0L+\.e?2t>#Cyԅ6s@爛/T+N; u%;>(srSTѲ#"Rƺ#S7´Tt+ҋ=]MqIӠUCCxᆖLUA']ojH%V,{W\]b7\ v%̂nPon )ܪY}3Д_rabݭKe5g̝gCz"PYrXP(`6VZttA[i)dE[GF^41 *ON&{cИ4륓>NYa1﫹a-^u#2fGUS,#c+ A| &gz;o OZuOs+P*1Ɇlt9 L~Ԧ`Zs?^$ =<`JEԡ!ٍu=rݾ>:%iTj9vڗ35$|TXQ'Sw`hKT碑I,Nͷ(oG"`|;-_,xoM u35uIJC "^:{ȑ7~N.M!CjmI?ڦE `'`~u=PYQ *6ڳ=> SLw'B˦xvU&41ǍLOoRy:yuˤ8Ŏ0*4I& R;BvwI:zx臚j]V@.I1\A-HV,x6~1c"4f,E\:m~⁑ !5uĔu PV]* Vk0b'} 6a k81y~hcR_Pni˚OBc1eyPDF=Q`v'ļ k=n75;>S:f*boJb9{Wo_ZxQ=lkZ,Mp9pOkbGOf[ - !++MM4K KN1]u c{ ^ s:+meD5ޕ2Y^wp`)*K%~y^5q'2E(ByGm؃-`?lofwKpɱtjޖT mIj´|k a*MǗa2GD~jQ}I)ӖYR&ZQ'Ew'U{եB^M/56mP{N.N.-msk) IxG):B)aI QN`"߷7,NxkE4=5leYug2"{<Ӵ3VvSԬ_m!;XY`Bi;1=r/{B&(΃,0@'ʿXz 72'V=)Ѵ.'Lz0+&SOL֒,Sp}@;gJH 0WO6Q=sCkMwzJe_go {%"V#.q@|9YtL<,j<̇bjo`ũ0 3L-Vx9/c~RI'@l>p4ZxT?,Ӻ$wt/l_$~UO WO=B_m9xm)A7z[~қԦqłr-Ϡ?9z Ν I "1H}w_ la$GoH/?$gZ@$PD!u;j7͂C7TFZ/j =: OJȿBehXxu"9RuW;I!M2(W<q B{Eʱɡo[\+UDx:пFg"`"r<>(QOj9r])U?)rpc_<Z5g(lrΡϐaۀprb>ZVWsw6J/-FfVggMxT[8%ihzJ ~|9xs,J>. c1N]Y&ێ+ȇ4T$6\dNAt}(Q"F1fY?rvؽz)1pSt{"x겮>2An@EeX4E-9%l)ge&I%⾌_r")hd?fέtqyri坸|6#EѥnnqV:zHZԏVXj`)<I"Ns 7>ڟk3]J jPr@>V6Oh\O{;; =kU*E|+ qQ~p~$/Faw4^wdbEh)& ?Z; Yu8uʠU2m? !)it)v7޾w,a7MLJI z%:+sl9 2^z~w5a2kaK4/2S-[h-zO9%blŀ`Fsȳ`ZFig05'ygoah cLI: xZnhd]go&\0&Vs|⤑3C?# wy4ŽSt".U j)W-bH+M{6w~%YyUJ8:`K)Ж +5^z轒's+%-Mq4eH|Sm5_TJJάѧs381HALWK`e=_ Q,-|}P֪kcsAl7㾨K[ˣ*`mzR|f|꟏҉FH,X%g2|D=ȭ"̚ XЖFS.(X<@6FפěhdS-fX&:!J U{Jg5O>w[ns*fƒu$K j<"]9t !JF}qc!c'2NokedQ5S̱܊WD}ea"'[.eᕞ,[B(t1@}tʞeA`1×*aO1 fίSş1a"՘,k[ڰqa%fDr/ |+nۂʂdTND҆ºM?@sm\">*GۤO6F ,1~sSRӨu㵹0-VS- K67(C#eccŗnI4A0^K k/`)"Ro㭾^ƩhII+:bd {Uʑ=2D_H\{qCfM ,$m}kg͠UEi4(%իfc(ȁStcs4G3He`s/T$?3w FP,fY_#QB,9X4*U"ab>O.F;3ALŽ2+Bą!g 0xE3=*~PYk:E&VNV˦ɇ\1z)DZUkE)q:t}~*hЩ^cJS*8Boa]IF.> d hD^ÈҜ3 {bm.х?mشK>)h6\&cBo~Ѵi?hEqru@i) >6\ j2.~|ID0梐w*mA~yLc0ԉS"ڲ5w/vۚ]֕ wvo1gP7|<18jF0e 菐re?DH֐i*jf}'&qu-WC ׋eaPi(lN ,Z hlfͤV(r?7Rŋ>_0]٠FyG (m@e!dBJ#mc{xHj/qJ$Il#myEWn$ TJV&+8HE%Qa ~*`?gDZ<I4Qo DL{T΢aixiJiH>;s edT]Sr_5Ua;tDHG4׈'(eYxЃګ ~Bv[4_@p^_\ r [C`Q{ikXXj} 2 'fyw.*1r7Z;*K"4-Ǝ*hRαw TJe }M>[͗v)> ¾hXtCt[շ[nmInsMi+^Nҋ@ r#Ld)9MUNW߀Ow4fi$gBNz\))|t7j}?,!14!Z|%MB_FDabAIO;5vBT *&zfLad>7GA?B۽+e;Tɰ\ ^2OOP<1 f3X`t("d'1lL&\~NS]֕mN^@-z@2S$j0 \AX#bk H* Ԩ)#_>(Mo  $)LXrh9 endstream endobj 2 0 obj << /Type /ObjStm /N 100 /First 814 /Length 3632 /Filter /FlateDecode >> stream x[Ys7~c\SnTjd9qbVzh-\.3~tMҔ)ѓܪFc=;%L3-af9fg20Kˤ`!YR,ؓŠX@2LQLQ ERy .V24LZ$ԺkPrCV%LF@SBf0L!AP2≩1)l B31 PN:0R1}8 Ҕd"aswx3` L9b`JkQo%`#bdXH{a'XԲ0 <Ī,hjPmb1SY! {bɀeЯ "x<JKxF@`I8:ד@A 9)A@kOAA*R@cj6YL & U|4 8:h<`0RϦԥT`ֈHzbޟ=h2T47yå(SSY~w_%=rx?_ĖsF#k (l+M'Fnܶ)Wb_dC|#{ò4â/ApSRsO1ξa2e|7Xwܓ){S]vrbpOަִ ݖ=  o GӪדr^oS Q;%6;CԼ`O˛?cAhWS5-f =Xg ,xPO־J0'c5e7OQvć&g}Oǀ;3u=>UHT9Z> lEm1WrN1|0YͯNJżz_.'>t2 mХ!\>1Ŭ{Auɧa,^b4,s>_x_uonf+1 b|׺ӡBc@r^F:uhӆ8aa}VbgÂVDtkHo MbOt̆5B'ԕ Е%A)5\DP"/IoM3>CzqJof䰲LE\yz|! M(WYi Gg07AtJBy-,J W[Y$v`tՠ>՞?ÈvDkM#Q*}7֦Z&Ej*C!^M5W:}vo%9fÎ+A()CxP)0(Zja!-qRD jdE+4"Pj Q `bCq8N*mF3!$^hYmN4Υ * hGS1Ʋg}nCps6/[ڌYΧR4`Ufd{/d֐f!7*~&d02.i%OXCyn|!罊d0JΒ[4Fni.hK6s43ߤ\*ReCuFrmE թ^dTy$g{&o;M5Lr<54B5&6#VdYt#` ٤wn19mjuI89ͳtSՒ6OYm` .=N ֹvs|zP"V¦) YQ]Js`]rJpF,Y|6kbU+pЈ;ё܎N ,n-1s9Mse06 $=,QL6-aErΧ CJX6 RweȤb(biz%.Wn- kvQ6˺ *Kf߳ѥ˖`3pS8T二O7iӾլ?oi,峾??=;jLn(<^顲 !HgG3:LyRWx [*=Ty:/uh|5Pj+o^FK r]Ni 3j鈏Tz2x91󇙟gɋދ]r'!܉7w6W?tP C'?>9~/O;xR*n yl]SSVt21?I /k^ ^+~k>#>~Hfcg|Ӫ ;c )G|w11f&24 #d2?FgW(R ?nd??wӧgЋgZuPh 8bdXGQқ|~;oS9zud4*i^WmQ%<}(,hP0I2Sh,RGY@NЪs41KnKU:;>bYφDa'Iƿg)o|f_槧 gi隧wxgYvK#W$}=@".2:Ӳ\\pXNI5TrDڐt +@xTgrqT"^ (c}5FV_?Vwq*~'%V>.VW-67ck~>ٜ۽Z6/̯gK=o|&*m-ܦ;lNwyV77M;A[MAv0&SߤmR$NWh{IіjFP$E Ԗ]jD?!:&E[wSEQw-Ky%E/u譵IQS4;v ؃ R5;U Z,oHIc=h~η3xsǸ\Nmp6U4lj endstream endobj 135 0 obj << /Producer (pdfTeX-1.40.22) /Author()/Title()/Subject()/Creator(LaTeX with hyperref)/Keywords() /CreationDate (D:20260428173204-07'00') /ModDate (D:20260428173204-07'00') /Trapped /False /PTEX.Fullbanner (This is pdfTeX, Version 3.141592653-2.6-1.40.22 (TeX Live 2021) kpathsea version 6.3.3) >> endobj 126 0 obj << /Type /ObjStm /N 9 /First 69 /Length 393 /Filter /FlateDecode >> stream x}Sn0+H*vBU,j)$(1]cV;rȁ8P.J`a9F)\`dP./"Lg!{Vk=$٬۵iެ@^3>tIm4G})8YR*ɂFC͠S!ޮwߪiݢ1A<Ddfcl$v$!!E}i,**0PXiֱgC2Ϊ0H4?ښ0@EM81l;u9,ue9EKBke=IbTIȐFMoGomvx#Aa3eUӭj8{p_}V:{bgӺ\lu{H j? endstream endobj 136 0 obj << /Type /XRef /Index [0 137] /Size 137 /W [1 3 1] /Root 134 0 R /Info 135 0 R /ID [<067B9B65D3A41C7A7F34A567A6D9D45E> <067B9B65D3A41C7A7F34A567A6D9D45E>] /Length 353 /Filter /FlateDecode >> stream x2QsmnmjFKц161 (TSegPV,mxˤ|wϹ~""o' Id@UȮdC&6dBl/!(|}ZP E*S[C AC|TE%U [@=ԩ,O*-BhfФ1 *qg/*k6k k1hVhʟs{ #Хr{}00)0``f *W݃yGK kK--?YZV/yaiEIK Xƥvk9蚣49jrwt~q*d1 endstream endobj startxref 225268 %%EOF GPArotation/inst/doc/GPA1guide.R0000644000176200001440000005213115174250567016032 0ustar liggesusers### R code from vignette source 'GPA1guide.Stex' ################################################### ### code chunk number 1: GPA1guide.Stex:22-24 ################################################### options(continue=" ") pdf.options(pointsize = 8) ################################################### ### code chunk number 2: GPA1guide.Stex:44-45 ################################################### library("GPArotation") ################################################### ### code chunk number 3: GPA1guide.Stex:89-100 ################################################### data("Harman", package = "GPArotation") # Calling a rotation directly qHarman <- quartimax(Harman8) # Equivalently, via the wrapper function qHarman <- GPFRSorth(Harman8, method = "quartimax") # Two equivalent ways to access the rotated loadings loadings(qHarman) # via extractor function (recommended) qHarman$loadings # via direct list access ################################################### ### code chunk number 4: GPA1guide.Stex:112-120 ################################################### data("CCAI", package = "GPArotation") y <- factanal(factors = 3, covmat = CCAI_R, n.obs = 461, rotation = "none") y.quart <- quartimax(y$loadings) max(loadings(y.quart) %*% t(y.quart$Th) - loadings(y)) y.obli <- oblimin(y$loadings, normalize = TRUE, randomStarts = 15) max(loadings(y.obli) %*% t(y.obli$Th) - loadings(y)) # last equation on Page 678 max(loadings(y.obli) - loadings(y) %*% solve(t(y.obli$Th))) ################################################### ### code chunk number 5: GPA1guide.Stex:126-129 ################################################### y <- factanal(factors = 3, covmat = CCAI_R, n.obs = 461, rotation = "none") y.obli <- oblimin(y$loadings, normalize = TRUE, randomStarts = 15) max(abs(y.obli$Phi - t(y.obli$Th) %*% y.obli$Th)) ################################################### ### code chunk number 6: GPA1guide.Stex:143-154 ################################################### set.seed(334) res <- quartimin(Harman8, normalize = TRUE, randomStarts = 100) # Raw unsorted loadings loadings(res) # Sorted loadings via print (factors reordered and signs adjusted) res.sorted <- print(res) # Once sorted, repeated calls to print are stable max(abs(print(res.sorted)$loadings - res.sorted$loadings)) == 0 # TRUE ################################################### ### code chunk number 7: GPA1guide.Stex:193-198 ################################################### res.obli <- oblimin(Harman8, normalize = TRUE, randomStarts = 100) # Pattern matrix (unsorted) summary(res.obli, Structure = FALSE) # Structure matrix summary(res.obli, Structure = TRUE) ################################################### ### code chunk number 8: GPA1guide.Stex:241-261 ################################################### plotPatternStructure <- function(pattern, structure, labels = NULL, main = "Pattern vs Structure") { k <- ncol(pattern) col <- palette.colors(k, palette = "Okabe-Ito") par(mfrow = c(1, k)) for (j in 1:k) { lims <- range(c(pattern[, j], structure[, j])) plot(pattern[, j], structure[, j], xlim = lims, ylim = lims, xlab = "Pattern loading", ylab = "Structure loading", main = paste(if (!is.null(labels)) labels[j] else paste("Factor", j)), pch = 19, col = col[j]) abline(0, 1, lty = 2, col = "grey60") abline(h = 0, col = "grey80") abline(v = 0, col = "grey80") } } ################################################### ### code chunk number 9: GPA1guide.Stex:264-270 ################################################### res.obli.s <- print(res.obli) Pattern <- loadings(res.obli.s) Structure <- Pattern %*% res.obli.s$Phi plotPatternStructure(Pattern, Structure, labels = c("Factor 1", "Factor 2")) ################################################### ### code chunk number 10: GPA1guide.Stex:295-299 ################################################### data(Thurstone, package = "GPArotation") infomaxQ(box26, randomStarts = 100) # 100 random starts infomaxQ(box26, Tmat = Random.Start(3)) # single random start infomaxQ(box26, randomStarts = 1) # also a single random start ################################################### ### code chunk number 11: GPA1guide.Stex:328-332 ################################################### res <- geominQ(box26, normalize = TRUE, randomStarts = 100) res$randStartChar # Criterion value at best solution res$Table[nrow(res$Table), "f"] ################################################### ### code chunk number 12: GPA1guide.Stex:357-413 ################################################### plotRotationLandscape <- function(A, method = "quartimax", n = 1000, main = NULL, ...) { # Plot the objective function landscape for 2-factor orthogonal rotation. # For 2 factors, all orthogonal rotations are parameterized by a single # angle theta in [0, 2*pi), giving a clean 1D landscape. # # Args: # A : a 2-factor unrotated loading matrix # method : rotation criterion (default "quartimax") # n : number of angles to evaluate (default 1000) # main : plot title (default: "Rotation landscape: ") # ... : additional arguments passed to the vgQ criterion function if (ncol(A) != 2) stop("plotRotationLandscape only works for 2-factor solutions.") vgQfun_fn <- get(paste("vgQ", method, sep = "."), envir = asNamespace("GPArotation")) if (is.null(main)) main <- paste("Rotation landscape:", method) theta <- seq(0, 2 * pi, length.out = n) f_vals <- numeric(n) for (i in seq_along(theta)) { Tmat <- matrix(c( cos(theta[i]), sin(theta[i]), -sin(theta[i]), cos(theta[i])), 2, 2) L <- A %*% Tmat VgQ <- do.call(vgQfun_fn, append(list(L), list(...))) f_vals[i] <- VgQ$f } # Find global minimum min_idx <- which.min(f_vals) plot(theta, f_vals, type = "l", lwd = 2, main = main, xlab = expression(theta ~ "(radians)"), ylab = "f", xaxt = "n") axis(1, at = c(0, pi/2, pi, 3*pi/2, 2*pi), labels = c("0", expression(pi/2), expression(pi), expression(3*pi/2), expression(2*pi))) abline(h = f_vals[min_idx], col = "grey80", lty = 2) points(theta[min_idx], f_vals[min_idx], col = "tomato", pch = 19, cex = 1.5) text(theta[min_idx], f_vals[min_idx], labels = paste0("min f = ", round(f_vals[min_idx], 4)), pos = 4, cex = 0.8) invisible(data.frame(theta = theta, f = f_vals)) } ################################################### ### code chunk number 13: GPA1guide.Stex:419-420 ################################################### data(Harman, package = "GPArotation") ################################################### ### code chunk number 14: GPA1guide.Stex:423-428 ################################################### par(mfrow = c(2, 2)) plotRotationLandscape(Harman8, method = "quartimax") plotRotationLandscape(Harman8, method = "varimax") plotRotationLandscape(Harman8, method = "bentler") plotRotationLandscape(Harman8, method = "entropy") ################################################### ### code chunk number 15: GPA1guide.Stex:455-468 ################################################### res <- plotRotationLandscape(Harman8, method = "simplimax", k = 4) # Find all local minima by sign changes in the discrete derivative df <- diff(res$f) local_mins <- which(df[-length(df)] < 0 & df[-1] > 0) # Mark all local minima on the existing plot points(res$theta[local_mins], res$f[local_mins], col = "steelblue", pch = 19, cex = 0.8) legend("topright", legend = c("global minimum", "local minima"), col = c("tomato", "steelblue"), pch = 19, bty = "n", cex = 0.8) ################################################### ### code chunk number 16: GPA1guide.Stex:471-474 ################################################### cat("Total minima found: ", length(local_mins), "\n") cat("Expected due to symmetry: ", 4, "\n") cat("Approximate genuine local minima:", max(0, length(local_mins) - 4), "\n") ################################################### ### code chunk number 17: GPA1guide.Stex:505-536 ################################################### data(Harman, package = "GPArotation") res.quart <- quartimax(Harman8) res.oblimin <- oblimin(Harman8) L.quart <- abs(loadings(res.quart)) L.oblimin <- abs(loadings(res.oblimin)) ord.quart <- order(L.quart[, 1], decreasing = TRUE) ord.oblimin <- order(L.oblimin[, 1], decreasing = TRUE) par(mfrow = c(1, 2), mar = c(5, 4, 4, 2)) barplot(t(L.quart[ord.quart, ]), beside = TRUE, ylim = c(0, 1), main = "Quartimax", ylab = "Absolute loading", xlab = "Variable (sorted by Factor 1)", legend.text = c("Factor 1", "Factor 2"), args.legend = list(x = "topright"), col = c("steelblue", "tomato")) barplot(t(L.oblimin[ord.oblimin, ]), beside = TRUE, ylim = c(0, 1), main = "Oblimin", ylab = "Absolute loading", xlab = "Variable (sorted by Factor 1)", legend.text = c("Factor 1", "Factor 2"), args.legend = list(x = "topright"), col = c("steelblue", "tomato")) ################################################### ### code chunk number 18: GPA1guide.Stex:556-621 ################################################### plotSortedLoadings <- function(..., labels = NULL, col = NULL, main = "Sorted Absolute Loadings", ylab = "Absolute loading", xlab = "Rank") { # Plot sorted absolute loadings for one or more GPArotation objects. # Multiple solutions are overlaid on a single plot for comparison. # Loadings are sorted from smallest to largest (left to right). # # Args: # ... : one or more GPArotation objects # labels : character vector of legend labels (default: "Solution 1", etc.) # col : character vector of colors (default: auto-assigned) # main : plot title # ylab : y-axis label # xlab : x-axis label solutions <- list(...) for (i in seq_along(solutions)) { if (!inherits(solutions[[i]], "GPArotation")) stop("Argument ", i, " is not a GPArotation object.") } n <- length(solutions) if (is.null(labels)) labels <- paste("Solution", seq_len(n)) if (is.null(col)) col <- palette.colors(n, palette = "Okabe-Ito") sorted_loadings <- lapply(solutions, function(x) sort(abs(as.vector(x$loadings)), decreasing = FALSE)) all_values <- unlist(sorted_loadings) max_len <- max(sapply(sorted_loadings, length)) plot(NULL, xlim = c(1, max_len), ylim = c(0, max(all_values)), main = main, xlab = xlab, ylab = ylab, las = 1) abline(h = seq(0, 1, by = 0.1), col = "grey90", lty = 1) for (i in seq_len(n)) { lines(seq_along(sorted_loadings[[i]]), sorted_loadings[[i]], col = col[i], lwd = 2) points(seq_along(sorted_loadings[[i]]), sorted_loadings[[i]], col = col[i], pch = 19, cex = 0.6) } legend("topleft", legend = labels, col = col, lwd = 2, pch = 19, bty = "n") invisible(sorted_loadings) } # Example data(Harman, package = "GPArotation") res.quart <- quartimax(Harman8) res.oblimin <- oblimin(Harman8) res.geomin <- geominT(Harman8) ################################################### ### code chunk number 19: GPA1guide.Stex:626-628 ################################################### plotSortedLoadings(res.quart, res.oblimin, res.geomin, labels = c("Quartimax", "Oblimin", "Geomin")) ################################################### ### code chunk number 20: GPA1guide.Stex:685-716 ################################################### origdigits <- options("digits") options(digits = 2) trBritain <- matrix(c(.783,-.163,.811,.202,.724,.209,.850,.064, -.031,.592,-.028,.723,.388,.434,.141,.808,.215,.709), byrow = TRUE, ncol = 2) trGermany <- matrix(c(.778,-.066,.875,.081,.751,.079,.739,.092, .195,.574,-.030,.807,-.135,.717,.125,.738,.060,.691), byrow = TRUE, ncol = 2) # orthogonal rotation of trGermany towards trBritain trx <- targetT(trGermany, Target = trBritain) # Factor loadings after target rotation trx # Differences between loadings matrices after rotation y <- trx$loadings - trBritain print(y, digits = 1) # Square root of the mean squared difference per item sqrt(apply((y^2), 1, mean)) # Square root of the mean squared difference per factor sqrt(apply((y^2), 2, mean)) # Identity coefficient per factor after rotation 2 * colSums(trx$loadings * trBritain) / (colSums(trx$loadings^2) + colSums(trBritain^2)) # Additivity coefficient per factor after rotation diag(2 * cov(trx$loadings, trBritain)) / diag(var(trx$loadings) + var(trBritain)) # Proportionality coefficient per factor after rotation colSums(trBritain * trx$loadings) / sqrt(colSums(trBritain^2) * colSums(trx$loadings^2)) # Correlation for each factor after rotation diag(cor(trBritain, trx$loadings)) options(digits = origdigits$digits) ################################################### ### code chunk number 21: GPA1guide.Stex:728-751 ################################################### plot(trBritain[, 1], trBritain[, 2], xlim = c(-0.3, 1.0), ylim = c(-0.3, 1.0), xlab = "Factor 1", ylab = "Factor 2", main = "Target Rotation: Germany towards Britain", pch = 19, col = "steelblue", cex = 1.2) abline(h = 0, lty = 2, col = "grey70") abline(v = 0, lty = 2, col = "grey70") points(trGermany[, 1], trGermany[, 2], pch = 17, col = "tomato", cex = 1.2) points(loadings(trx)[, 1], loadings(trx)[, 2], pch = 15, col = "orange", cex = 1.2) for (i in 1:nrow(trGermany)) { arrows(trGermany[i, 1], trGermany[i, 2], loadings(trx)[i, 1], loadings(trx)[i, 2], length = 0.08, col = "grey60") } legend("topright", legend = c("Britain (varimax rotated)", "East Germany (varimax rotated)", "East Germany (rotated towards Britain)"), col = c("steelblue", "tomato", "orange"), pch = c(19, 17, 15), bty = "n") ################################################### ### code chunk number 22: GPA1guide.Stex:778-792 ################################################### A <- matrix(c(.664, .688, .492, .837, .705, .82, .661, .457, .765, .322, .248, .304, -0.291, -0.314, -0.377, .397, .294, .428, -0.075, .192, .224, .037, .155, -.104, .077, -.488, .009), ncol = 3) # using targetT SPA <- matrix(c(rep(NA, 6), .7, .0, .7, rep(0, 3), rep(NA, 7), 0, 0, NA, 0, rep(NA, 4)), ncol = 3) xt <- targetT(A, Target = SPA) # using pstT SPApst <- matrix(c(rep(0, 6), .7, .0, .7, rep(0, 3), rep(0, 7), 0, 0, 0, 0, rep(0, 4)), ncol = 3) SPAW <- matrix(c(rep(0, 6), rep(1, 6), rep(0, 7), 1, 1, 0, 1, rep(0, 4)), ncol = 3) xpst <- pstT(A, Target = SPApst, W = SPAW) max(abs(loadings(xt) - loadings(xpst))) ################################################### ### code chunk number 23: GPA1guide.Stex:810-814 ################################################### data("CCAI", package = "GPArotation") factanal(factors = 3, covmat = CCAI_R, n.obs = 461, rotation = "infomaxT") factanal(factors = 3, covmat = CCAI_R, n.obs = 461, rotation = "infomaxT", control = list(rotate = list(normalize = TRUE, eps = 1e-6))) ################################################### ### code chunk number 24: GPA1guide.Stex:822-826 ################################################### data("WansbeekMeijer", package = "GPArotation") fa.unrotated <- factanal(factors = 3, covmat = NetherlandsTV, normalize = TRUE, rotation = "none") quartimin(loadings(fa.unrotated), normalize = TRUE) ################################################### ### code chunk number 25: GPA1guide.Stex:836-859 ################################################### data("WansbeekMeijer", package = "GPArotation") fa.unrotated <- factanal(factors = 3, covmat = NetherlandsTV, normalize = TRUE, rotation = "none") # Two-step procedure (always correct) set.seed(42) fa.cf <- cfQ(loadings(fa.unrotated), kappa = 0.3, normalize = TRUE, randomStarts = 100) fa.cf if (getRversion() >= "4.5.1") { # Single-step via factanal (correct in R >= 4.5.1) set.seed(42) fa.factanal <- factanal(factors = 3, covmat = NetherlandsTV, normalize = TRUE, rotation = "cfQ", control = list(rotate = list(kappa = 0.3, randomStarts = 100))) fa.sorted <- print(fa.cf, sortLoadings = TRUE) cat("Maximum difference in loadings:\n") print(max(abs(abs(fa.sorted$loadings) - abs(fa.factanal$loadings)))) } else { cat("Single-step factanal oblique rotation requires R >= 4.5.1.\n") cat("Use the two-step procedure above for correct results.\n") } ################################################### ### code chunk number 26: GPA1guide.Stex:874-952 ################################################### factanal_fit <- function(fa, R_obs, n) { # Compute common factor model fit indices from factanal output. # For MLE extraction only (factanal). For other estimators (minres, # principal axis, WLS) the chi-square statistic is not defined in # the same way and this function should not be used. # # Args: # fa : a factanal object (rotation = "none" recommended) # R_obs : observed correlation or covariance matrix passed to factanal # n : sample size (n.obs passed to factanal) if (is.null(fa$STATISTIC)) stop("factanal did not compute a chi-square statistic. ", "Ensure n.obs is specified when passing a covariance matrix.") # Ensure we work with a correlation matrix R_obs <- cov2cor(as.matrix(R_obs)) p <- nrow(R_obs) L <- loadings(fa) k <- ncol(L) # number of factors extracted # Model-implied correlation matrix using factanal uniquenesses # fa$uniquenesses are the MLE estimated unique variances R_hat <- L %*% t(L) + diag(fa$uniquenesses) R_hat <- cov2cor(R_hat) # Residual matrix --- off-diagonal only Resid <- R_obs - R_hat diag(Resid) <- 0 # Test of the hypothesis that k factors are sufficient. Identical to factanal F_ml <- log(det(R_hat)) - log(det(R_obs)) + sum(diag(R_obs %*% solve(R_hat))) - p chi2 <- (n - 1 - (2 * p + 5)/6 - (2 * k)/3) * F_ml df <- ((p - k)^2 - (p + k)) / 2 pval <- pchisq(chi2, df, lower.tail = FALSE) # SRMR: standardized root mean square residual rstar.off <- sum(Resid^2) / 2 srmr <- sqrt(rstar.off / (p * (p - 1))) # RMSEA: root mean square error of approximation rmsea <- sqrt(max(0, chi2 / (df * n) - 1 / (n - 1))) # Null model: all items uncorrelated chi2_null <- (n - 1) * sum(R_obs[lower.tri(R_obs)]^2) df_null <- p * (p - 1) / 2 # CFI: comparative fit index cfi <- (max(chi2_null - df_null, 0) - max(chi2 - df, 0)) / max(chi2_null - df_null, 0) # TLI: Tucker-Lewis index tli <- (chi2_null / df_null - chi2 / df) / (chi2_null / df_null - 1) # AIC and BIC aic <- chi2 - 2 * df bic <- chi2 - log(n) * df # Print results cat("Factor Model Fit Indices (MLE only)\n") cat("------------------------------------\n") cat(sprintf("Chi-square (df = %d): %.3f p = %.4f\n", df, chi2, pval)) cat(sprintf("RMSEA: %.4f\n", rmsea)) cat(sprintf("SRMR: %.4f\n", srmr)) cat(sprintf("CFI: %.4f\n", cfi)) cat(sprintf("TLI: %.4f\n", tli)) cat(sprintf("AIC: %.3f\n", aic)) cat(sprintf("BIC: %.3f\n", bic)) cat("\nTop 5 absolute residuals:\n") resid_vals <- Resid[lower.tri(Resid)] print(round(sort(abs(resid_vals), decreasing = TRUE)[1:5], 4)) invisible(c(chi2 = chi2, df = df, pval = pval, rmsea = rmsea, srmr = srmr, cfi = cfi, tli = tli, aic = aic, bic = bic)) } ################################################### ### code chunk number 27: GPA1guide.Stex:958-966 ################################################### data("WansbeekMeijer", package = "GPArotation") fa2 <- factanal(factors = 2, covmat = NetherlandsTV, rotation = "none") fa3 <- factanal(factors = 3, covmat = NetherlandsTV, rotation = "none") cat("=== 2 factors ===\n") fit2 <- factanal_fit(fa2, cov2cor(NetherlandsTV$cov), n = 2154) cat("\n=== 3 factors ===\n") fit3 <- factanal_fit(fa3, cov2cor(NetherlandsTV$cov), n = 2154) ################################################### ### code chunk number 28: GPA1guide.Stex:969-977 ################################################### cat("Model comparison:\n") cat(sprintf(" 2-factor 3-factor\n")) cat(sprintf("RMSEA: %8.4f %8.4f\n", fit2["rmsea"], fit3["rmsea"])) cat(sprintf("SRMR: %8.4f %8.4f\n", fit2["srmr"], fit3["srmr"])) cat(sprintf("CFI: %8.4f %8.4f\n", fit2["cfi"], fit3["cfi"])) cat(sprintf("TLI: %8.4f %8.4f\n", fit2["tli"], fit3["tli"])) cat(sprintf("AIC: %8.2f %8.2f\n", fit2["aic"], fit3["aic"])) cat(sprintf("BIC: %8.2f %8.2f\n", fit2["bic"], fit3["bic"])) GPArotation/inst/doc/GPA1guide.Stex0000644000176200001440000015572715174242453016566 0ustar liggesusers%\VignetteEncoding{UTF-8} %\VignetteIndexEntry{Gradient Projection Factor Rotation} %\VignettePackage{GPArotation} %\VignetteDepends{GPArotation} %\VignetteKeyword{factor rotation} %\VignetteKeyword{gradient projection} %\VignetteKeyword{varimax} %\VignetteKeyword{oblimin} \documentclass[english, 10pt]{article} \usepackage{hyperref} \bibstyle{apacite} \bibliographystyle{apa} \usepackage{natbib} \usepackage{geometry} \geometry{letterpaper} \begin{document} \SweaveOpts{eval=TRUE,echo=TRUE,results=hide,fig=FALSE} \begin{Scode}{echo=FALSE,results=hide} options(continue=" ") pdf.options(pointsize = 8) \end{Scode} \begin{center} \section*{Gradient Projection Factor Rotation \\ ~~\\The \texttt{GPArotation} Package} \end{center} \begin{center} Author: Coen A. Bernaards \end{center} The \texttt{GPArotation} package provides gradient projection algorithms for orthogonal and oblique rotation of factor loading matrices in exploratory factor analysis. It implements a comprehensive set of rotation criteria and supports multiple random starts to avoid local minima. This vignette introduces the main functionality of the package, with examples of common use cases. For a complete list of available rotation criteria and their references, see the Rotation Criteria Reference section at the back of this document. In R, the functions in this package are made available with \begin{Scode} library("GPArotation") \end{Scode} The most complete reference for the software is \cite{gpa.rotate}. The original 2005 implementations in four platforms are preserved for historical reference: \href{https://drive.google.com/file/d/1TetEn1TGLul6FRTlIwXx3nbSQOGlifXi/view?usp=sharing} {MATLAB code}, \href{https://drive.google.com/file/d/1RryvIoTib0d9SIFm9x1fdDFPfjzsh49e/view?usp=sharing} {Splus code}, \href{https://drive.google.com/file/d/1t5Bw8KLlIGrSr3TNy0rJjHfsU6nOlIpq/view?usp=sharing} {SAS code}, and \href{https://drive.google.com/file/d/1JGvSxiphNhbZhW-GzGXkkNPBFcKyfSZi/view?usp=sharing} {SPSS code}. These implementations predate the R package and reflect the algorithm as originally published. The R package has been updated since then; see the \texttt{NEWS} file for a full history of changes. A clear and accessible introduction to gradient projection algorithms for factor rotation is provided in \cite{mansreise}. %------------------------------------------------------------------- \section*{Basic Usage} %------------------------------------------------------------------- \subsection*{Getting Started} Factor rotation aims to simplify interpretation by rotating the loadings matrix. In practice, most rotations are done by minimizing a criterion function. This package provides algorithms that can minimize any rotation criteria as long as a gradient is available. The loading matrix is typically obtained from a factor analysis routine such as \texttt{factanal}. A rotation is performed by calling the rotation function directly, or by calling one of the wrapper functions \texttt{GPFRSorth} or \texttt{GPFRSoblq} for orthogonal and oblique rotation, respectively. Under the hood, rotations are computed using the Gradient Projection Algorithm, implemented in \texttt{GPForth} for orthogonal rotation and \texttt{GPFoblq} for oblique rotation. These functions were updated in version 2026.4-1 with performance improvements and improved code clarity; results are numerically identical to prior versions. \begin{Scode} data("Harman", package = "GPArotation") # Calling a rotation directly qHarman <- quartimax(Harman8) # Equivalently, via the wrapper function qHarman <- GPFRSorth(Harman8, method = "quartimax") # Two equivalent ways to access the rotated loadings loadings(qHarman) # via extractor function (recommended) qHarman$loadings # via direct list access \end{Scode} The rotated loadings matrix is the pattern matrix. The extractor function \texttt{loadings()} is preferred over direct list access for forward compatibility. \subsection*{Recovery of the Unrotated Loadings Matrix} Recovery of the unrotated loadings matrix is consistent with the definitions used in \cite{gpa.rotate} (page 678). For example, the unrotated matrix $A$ may be recovered as follows. \begin{Scode}{results=verbatim} data("CCAI", package = "GPArotation") y <- factanal(factors = 3, covmat = CCAI_R, n.obs = 461, rotation = "none") y.quart <- quartimax(y$loadings) max(loadings(y.quart) %*% t(y.quart$Th) - loadings(y)) y.obli <- oblimin(y$loadings, normalize = TRUE, randomStarts = 15) max(loadings(y.obli) %*% t(y.obli$Th) - loadings(y)) # last equation on Page 678 max(loadings(y.obli) - loadings(y) %*% solve(t(y.obli$Th))) \end{Scode} By the same definitions, the factor correlation matrix is calculated as \cite{gpa.rotate} (page 695), \begin{Scode}{results=verbatim} y <- factanal(factors = 3, covmat = CCAI_R, n.obs = 461, rotation = "none") y.obli <- oblimin(y$loadings, normalize = TRUE, randomStarts = 15) max(abs(y.obli$Phi - t(y.obli$Th) %*% y.obli$Th)) \end{Scode} \subsection*{Output and Display} The raw output from \texttt{GPArotation} functions returns loadings in the order determined by the algorithm, which depends on the starting rotation matrix. This means that with different random starts, the same solution may appear with factors in a different order or with reversed signs. The \texttt{print} method sorts factors by descending variance explained and adjusts signs so that the dominant loadings are positive, making visual inspection and comparison easier. Importantly, this is a display transformation only --- the underlying object is not modified. \begin{Scode}{results=verbatim} set.seed(334) res <- quartimin(Harman8, normalize = TRUE, randomStarts = 100) # Raw unsorted loadings loadings(res) # Sorted loadings via print (factors reordered and signs adjusted) res.sorted <- print(res) # Once sorted, repeated calls to print are stable max(abs(print(res.sorted)$loadings - res.sorted$loadings)) == 0 # TRUE \end{Scode} \subsection*{Pattern and Structure Matrices} \subsubsection*{Two Interpretations of the Loading Matrix} The loading matrix $\Lambda$ has two complementary interpretations that correspond directly to the pattern and structure matrices in oblique rotation. \textbf{First interpretation: regression.} The conditional expectation $E(X|f) = \mu + \Lambda f$ is the linear regression of $X$ on $f$. The loading $\lambda_{ij}$ is the expected change in item $i$ when factor $j$ is increased by one unit, holding other factors constant. This is the \emph{pattern matrix} --- the regression coefficients of items on factors. \textbf{Second interpretation: correlation.} Under the factor model assumptions, $Cov(X, f) = \Lambda\Phi$. If $X$ is standardized, $Corr(X, f) = \Lambda\Phi$. This is the \emph{structure matrix} --- the correlations between items and factors. Correlations tend to be consistent across studies. When factors are orthogonal ($\Phi = I$) the two interpretations coincide: $\Lambda\Phi = \Lambda$. When factors are oblique the structure matrix $\Lambda\Phi$ inflates the apparent relationships between items and factors through the factor intercorrelations, while the pattern matrix $\Lambda$ shows the unique contribution of each factor net of those intercorrelations. \subsubsection*{Using \texttt{GPArotation} to obtain them} The \texttt{summary} method returns the raw unsorted loadings exactly as produced by the algorithm. For oblique rotations, it also prints the structure matrix (loadings $\times$ $\Phi$) when \texttt{Structure = TRUE} (the default). This is useful for comparing results across software or reproducing published values. \begin{Scode}{results=verbatim} res.obli <- oblimin(Harman8, normalize = TRUE, randomStarts = 100) # Pattern matrix (unsorted) summary(res.obli, Structure = FALSE) # Structure matrix summary(res.obli, Structure = TRUE) \end{Scode} To illustrate the distinction concretely, consider item 1 (row 1) from the oblimin rotation of the Harman 8-variable physical measurements dataset. In the pattern matrix, the loadings are 0.892 on Factor 1 and 0.056 on Factor 2. The pattern coefficient 0.892 is the regression coefficient of item 1 on Factor 1, controlling for Factor 2 --- it represents the unique contribution of Factor 1 to item 1, net of the shared variance between the two factors. The near-zero cross-loading of 0.056 indicates that item 1 is primarily associated with Factor 1 after accounting for factor intercorrelations. In the structure matrix, the same item has loadings of 0.918 on Factor 1 and 0.478 on Factor 2. The structure coefficient 0.478 is the simple correlation between item 1 and Factor 2 --- substantially larger than the pattern cross-loading of 0.056. This inflation occurs because Factor 1 and Factor 2 are correlated, and that correlation carries over into the structure coefficients. An analyst relying solely on the structure matrix might incorrectly conclude that item 1 has a meaningful relationship with Factor 2. In this solution the factor intercorrelation is $\phi = 0.473$. This moderate correlation between the two factors is sufficient to inflate the structure coefficients noticeably --- the cross-loading of item 1 on Factor 2 increases from 0.056 in the pattern matrix to 0.478 in the structure matrix, a difference of 0.422 attributable entirely to the factor intercorrelation. This is why the pattern matrix is generally preferred for interpretation in oblique rotation: it shows the unique contribution of each factor to each item, net of the shared variance among factors. The structure matrix is a useful diagnostic check --- large discrepancies between pattern and structure coefficients signal that factor intercorrelations are substantially inflating apparent relationships. The relationship between pattern and structure coefficients can be visualized by plotting one against the other for each factor. Points on the identity line (dashed) have equal pattern and structure coefficients --- no inflation from factor intercorrelations. Points above the line have structure coefficients inflated by the factor intercorrelations. \begin{Scode} plotPatternStructure <- function(pattern, structure, labels = NULL, main = "Pattern vs Structure") { k <- ncol(pattern) col <- palette.colors(k, palette = "Okabe-Ito") par(mfrow = c(1, k)) for (j in 1:k) { lims <- range(c(pattern[, j], structure[, j])) plot(pattern[, j], structure[, j], xlim = lims, ylim = lims, xlab = "Pattern loading", ylab = "Structure loading", main = paste(if (!is.null(labels)) labels[j] else paste("Factor", j)), pch = 19, col = col[j]) abline(0, 1, lty = 2, col = "grey60") abline(h = 0, col = "grey80") abline(v = 0, col = "grey80") } } \end{Scode} \begin{center} \begin{Scode}{fig=TRUE, echo=FALSE, width=4, height=2.5} res.obli.s <- print(res.obli) Pattern <- loadings(res.obli.s) Structure <- Pattern %*% res.obli.s$Phi plotPatternStructure(Pattern, Structure, labels = c("Factor 1", "Factor 2")) \end{Scode} \end{center} With a factor intercorrelation of $\phi = 0.473$, the structure coefficients are systematically larger than the pattern coefficients, particularly for items with substantial loadings on both factors. The further a point lies above the identity line, the more the factor intercorrelation is inflating the apparent relationship between that item and the factor. %------------------------------------------------------------------- \section*{Random Starts} %------------------------------------------------------------------- \subsection*{Using Random Starts} For some rotation criteria local minima may exist, meaning the algorithm may converge to different solutions depending on the starting rotation matrix. To explore the solution space, the \texttt{randomStarts} argument is available in all rotation functions. The returned object contains the rotated loadings matrix with the lowest criterion value among all attempted starts. While the lowest local minimum found is likely the global minimum, this cannot be guaranteed. \begin{Scode} data(Thurstone, package = "GPArotation") infomaxQ(box26, randomStarts = 100) # 100 random starts infomaxQ(box26, Tmat = Random.Start(3)) # single random start infomaxQ(box26, randomStarts = 1) # also a single random start \end{Scode} For a detailed discussion of local minima in factor rotation, consult \cite{nguwall}. Additional algorithmic considerations are in \cite{gpa.rotate} (page 680). \subsection*{Assessing Local Minima with Random Start Diagnostics} When \texttt{randomStarts} $> 1$, the output includes a \texttt{randStartChar} vector summarizing the results across all starts. The four elements are: \begin{itemize} \item \texttt{randomStarts}: number of random starts attempted \item \texttt{Converged}: number of starts that converged \item \texttt{atMinimum}: number of starts that converged to the same lowest criterion value \item \texttt{localMins}: number of distinct local minima found \end{itemize} If \texttt{atMinimum} equals \texttt{randomStarts}, all starts found the same solution --- strong evidence that the global minimum has been found. If \texttt{localMins} is large relative to \texttt{randomStarts}, the criterion landscape is complex and more starts are advisable. If the \texttt{Converged} count is low, the tolerance \texttt{eps} or maximum iterations \texttt{maxit} may need adjustment. \begin{Scode}{results=verbatim} res <- geominQ(box26, normalize = TRUE, randomStarts = 100) res$randStartChar # Criterion value at best solution res$Table[nrow(res$Table), "f"] \end{Scode} More detailed methods of investigation local minima, including the \texttt{GPFallMinima} function, are described in the vignette \texttt{vignette("GPA2local", package = "GPArotation")}. The \textit{fungible} package has options for assessing local minima using the \texttt{faMain} function, and the \textit{psych} package using \texttt{faRotations}. \subsection*{The Rotation Objective Function Landscape} For two-factor orthogonal rotation, every rotation matrix is parameterized by a single angle $\theta \in [0, 2\pi)$: \[ T(\theta) = \left( \begin{array}{cc} \cos\theta & \sin\theta \\ -\sin\theta & \cos\theta \end{array} \right) \] This means the objective function $f$ can be plotted as a function of $\theta$, giving a complete picture of the rotation landscape --- all local and global minima, and how flat or sharp they are. The following function computes and plots $f(\theta)$ for $n$ evenly spaced angles: \begin{Scode} plotRotationLandscape <- function(A, method = "quartimax", n = 1000, main = NULL, ...) { # Plot the objective function landscape for 2-factor orthogonal rotation. # For 2 factors, all orthogonal rotations are parameterized by a single # angle theta in [0, 2*pi), giving a clean 1D landscape. # # Args: # A : a 2-factor unrotated loading matrix # method : rotation criterion (default "quartimax") # n : number of angles to evaluate (default 1000) # main : plot title (default: "Rotation landscape: ") # ... : additional arguments passed to the vgQ criterion function if (ncol(A) != 2) stop("plotRotationLandscape only works for 2-factor solutions.") vgQfun_fn <- get(paste("vgQ", method, sep = "."), envir = asNamespace("GPArotation")) if (is.null(main)) main <- paste("Rotation landscape:", method) theta <- seq(0, 2 * pi, length.out = n) f_vals <- numeric(n) for (i in seq_along(theta)) { Tmat <- matrix(c( cos(theta[i]), sin(theta[i]), -sin(theta[i]), cos(theta[i])), 2, 2) L <- A %*% Tmat VgQ <- do.call(vgQfun_fn, append(list(L), list(...))) f_vals[i] <- VgQ$f } # Find global minimum min_idx <- which.min(f_vals) plot(theta, f_vals, type = "l", lwd = 2, main = main, xlab = expression(theta ~ "(radians)"), ylab = "f", xaxt = "n") axis(1, at = c(0, pi/2, pi, 3*pi/2, 2*pi), labels = c("0", expression(pi/2), expression(pi), expression(3*pi/2), expression(2*pi))) abline(h = f_vals[min_idx], col = "grey80", lty = 2) points(theta[min_idx], f_vals[min_idx], col = "tomato", pch = 19, cex = 1.5) text(theta[min_idx], f_vals[min_idx], labels = paste0("min f = ", round(f_vals[min_idx], 4)), pos = 4, cex = 0.8) invisible(data.frame(theta = theta, f = f_vals)) } \end{Scode} The following example compares four rotation criteria on the Harman 8-variable physical measurements dataset: \begin{Scode} data(Harman, package = "GPArotation") \end{Scode} \begin{Scode}{fig=TRUE} par(mfrow = c(2, 2)) plotRotationLandscape(Harman8, method = "quartimax") plotRotationLandscape(Harman8, method = "varimax") plotRotationLandscape(Harman8, method = "bentler") plotRotationLandscape(Harman8, method = "entropy") \end{Scode} \subsection*{Interpreting the Landscape: Symmetry vs Genuine Local Minima} An important subtlety when interpreting rotation landscapes is that not all minima represent genuinely different factor structures. For a two-factor solution, the rotation landscape always contains at least 4 equivalent minima due to the inherent symmetry of factor analysis: \begin{itemize} \item \textbf{Sign flips}: flipping the sign of a factor column gives an equivalent solution. With two factors there are $2^2 = 4$ sign-flip combinations, each producing an equivalent minimum. \item \textbf{Column permutations}: swapping the two factors gives an equivalent solution, adding further symmetry. \end{itemize} Combined, a two-factor solution has at least 4 symmetry-equivalent minima in $[0, 2\pi)$. Any minima beyond these 4 represent genuinely different factor structures --- true local minima in the optimization sense. The following example illustrates this for the simplimax criterion with \texttt{k = 4}, which produces multiple local minima on the Harman 8-variable dataset: \begin{Scode}{fig=TRUE} res <- plotRotationLandscape(Harman8, method = "simplimax", k = 4) # Find all local minima by sign changes in the discrete derivative df <- diff(res$f) local_mins <- which(df[-length(df)] < 0 & df[-1] > 0) # Mark all local minima on the existing plot points(res$theta[local_mins], res$f[local_mins], col = "steelblue", pch = 19, cex = 0.8) legend("topright", legend = c("global minimum", "local minima"), col = c("tomato", "steelblue"), pch = 19, bty = "n", cex = 0.8) \end{Scode} \begin{Scode}{results=verbatim} cat("Total minima found: ", length(local_mins), "\n") cat("Expected due to symmetry: ", 4, "\n") cat("Approximate genuine local minima:", max(0, length(local_mins) - 4), "\n") \end{Scode} The \texttt{k} argument controls how many near-zero loadings simplimax targets. Smaller values of \texttt{k} create a rougher objective function landscape with more local minima, while larger values (up to \texttt{nrow(A)}) produce smoother landscapes. Criteria such as quartimax and varimax on well-structured data typically show exactly 4 minima --- all symmetry-equivalent. Criteria prone to local minima, such as simplimax and geomin, show additional minima beyond the symmetry baseline. This is precisely why random starts are important: without them, the algorithm may converge to a symmetry-equivalent solution or a genuine local minimum rather than the global minimum. The rotation landscape visualization is only available for two-factor solutions. For $k > 2$ factors the rotation space is $(k^2 - k)/2$-dimensional and cannot be visualized as a simple curve. For higher-dimensional problems, the \texttt{GPFallMinima} function described in the \texttt{GPA2local} vignette provides an alternative approach to exploring the solution space. \subsection*{Comparing Rotation Criteria Visually} Different rotation criteria can produce noticeably different loading patterns. A useful way to compare solutions is to make a bar graph of the absolute loadings sorted by magnitude for each factor. The following example compares quartimax and oblimin rotation of the Harman 8-variable physical measurements dataset. \begin{Scode}{fig=TRUE} data(Harman, package = "GPArotation") res.quart <- quartimax(Harman8) res.oblimin <- oblimin(Harman8) L.quart <- abs(loadings(res.quart)) L.oblimin <- abs(loadings(res.oblimin)) ord.quart <- order(L.quart[, 1], decreasing = TRUE) ord.oblimin <- order(L.oblimin[, 1], decreasing = TRUE) par(mfrow = c(1, 2), mar = c(5, 4, 4, 2)) barplot(t(L.quart[ord.quart, ]), beside = TRUE, ylim = c(0, 1), main = "Quartimax", ylab = "Absolute loading", xlab = "Variable (sorted by Factor 1)", legend.text = c("Factor 1", "Factor 2"), args.legend = list(x = "topright"), col = c("steelblue", "tomato")) barplot(t(L.oblimin[ord.oblimin, ]), beside = TRUE, ylim = c(0, 1), main = "Oblimin", ylab = "Absolute loading", xlab = "Variable (sorted by Factor 1)", legend.text = c("Factor 1", "Factor 2"), args.legend = list(x = "topright"), col = c("steelblue", "tomato")) \end{Scode} Quartimax tends to produce a general factor with high loadings on all variables, while oblimin allows factors to be correlated and typically produces a cleaner simple structure. The sorted absolute loading plot makes these differences immediately visible. \subsection*{Sorted Absolute Loadings Plot} A useful way to compare the sparsity profile of different rotation solutions is to plot all absolute loadings sorted from smallest to largest. In a rotation with good simple structure, most loadings are near zero with a sharp upturn at the right --- indicating that a few large loadings dominate. Comparing this profile across rotation criteria makes differences in simplicity and sparsity immediately visible. The following function plots sorted absolute loadings for one or more \texttt{GPArotation} objects on a single figure. \begin{Scode}{echo=TRUE, eval=TRUE} plotSortedLoadings <- function(..., labels = NULL, col = NULL, main = "Sorted Absolute Loadings", ylab = "Absolute loading", xlab = "Rank") { # Plot sorted absolute loadings for one or more GPArotation objects. # Multiple solutions are overlaid on a single plot for comparison. # Loadings are sorted from smallest to largest (left to right). # # Args: # ... : one or more GPArotation objects # labels : character vector of legend labels (default: "Solution 1", etc.) # col : character vector of colors (default: auto-assigned) # main : plot title # ylab : y-axis label # xlab : x-axis label solutions <- list(...) for (i in seq_along(solutions)) { if (!inherits(solutions[[i]], "GPArotation")) stop("Argument ", i, " is not a GPArotation object.") } n <- length(solutions) if (is.null(labels)) labels <- paste("Solution", seq_len(n)) if (is.null(col)) col <- palette.colors(n, palette = "Okabe-Ito") sorted_loadings <- lapply(solutions, function(x) sort(abs(as.vector(x$loadings)), decreasing = FALSE)) all_values <- unlist(sorted_loadings) max_len <- max(sapply(sorted_loadings, length)) plot(NULL, xlim = c(1, max_len), ylim = c(0, max(all_values)), main = main, xlab = xlab, ylab = ylab, las = 1) abline(h = seq(0, 1, by = 0.1), col = "grey90", lty = 1) for (i in seq_len(n)) { lines(seq_along(sorted_loadings[[i]]), sorted_loadings[[i]], col = col[i], lwd = 2) points(seq_along(sorted_loadings[[i]]), sorted_loadings[[i]], col = col[i], pch = 19, cex = 0.6) } legend("topleft", legend = labels, col = col, lwd = 2, pch = 19, bty = "n") invisible(sorted_loadings) } # Example data(Harman, package = "GPArotation") res.quart <- quartimax(Harman8) res.oblimin <- oblimin(Harman8) res.geomin <- geominT(Harman8) \end{Scode} The following example compares quartimax, oblimin, and geomin rotation on the Harman 8-variable physical measurements dataset. \begin{center} \begin{Scode}{fig=TRUE, echo=FALSE, width=4, height=4} plotSortedLoadings(res.quart, res.oblimin, res.geomin, labels = c("Quartimax", "Oblimin", "Geomin")) \end{Scode} \end{center} A flat profile at the left indicates many near-zero loadings --- a hallmark of simple structure. A gradual curve with no clear elbow suggests the criterion is not achieving strong separation between large and small loadings. Criteria that differ substantially in their sparsity assumptions, such as quartimax (which tends toward a general factor) versus oblimin (which allows correlated factors with cleaner simple structure), will produce visibly different profiles. The function accepts any number of \texttt{GPArotation} objects and is useful for assessing the effect of different values of a criterion parameter, for example comparing rotation with different values of a parameter. %------------------------------------------------------------------- \section*{Special Rotation Types} %------------------------------------------------------------------- \subsection*{An Example of Target Rotation} \cite{fisfon} describe measuring self-reported extra-role behavior in samples of British and East German employees. They publish rotation matrices for two samples and investigate structural equivalence of the loadings matrices. The table lists the varimax rotated loadings matrices. \begin{tabular}{l c c c c} \hline & \multicolumn{2}{c}{Britain} & \multicolumn{2}{c}{East Germany} \\ & Factor 1& Factor 2 & Factor 1& Factor 2\\ \hline\hline I am always punctual.&.783&-.163&.778&-.066\\ I do not take extra breaks.&.811&.202&.875&.081\\ I follow work rules and instructions &.724&.209&.751&.079\\ ~~~ with extreme care.& & & & \\ I never take long lunches or breaks.&.850&.064&.739&.092\\ I search for causes for something &-.031&.592&.195&.574\\ ~~~ that did not function properly.& & & & \\ I often motivate others to express &-.028&.723&-.030&.807\\ ~~~ their ideas and opinions.& & & & \\ During the last year I changed &.388&.434&-.135&.717\\ ~~~ something in my work.& & & & \\ I encourage others to speak up at meetings.&.141&.808&.125&.738\\ I continuously try to submit suggestions&.215&.709&.060&.691\\ ~~~ to improve my work.& & & & \\ \hline \end{tabular} \\ The varimax rotations for each sample may be expected to be similar because the two loadings matrices are from different samples measuring the same constructs. Below are target rotation of the East German loadings matrix towards the British one, followed by calculation of agreement coefficients. \cite{fisfon} note that coefficients generally should be ``beyond the commonly accepted value of 0.90.'' \begin{Scode}{results=verbatim} origdigits <- options("digits") options(digits = 2) trBritain <- matrix(c(.783,-.163,.811,.202,.724,.209,.850,.064, -.031,.592,-.028,.723,.388,.434,.141,.808,.215,.709), byrow = TRUE, ncol = 2) trGermany <- matrix(c(.778,-.066,.875,.081,.751,.079,.739,.092, .195,.574,-.030,.807,-.135,.717,.125,.738,.060,.691), byrow = TRUE, ncol = 2) # orthogonal rotation of trGermany towards trBritain trx <- targetT(trGermany, Target = trBritain) # Factor loadings after target rotation trx # Differences between loadings matrices after rotation y <- trx$loadings - trBritain print(y, digits = 1) # Square root of the mean squared difference per item sqrt(apply((y^2), 1, mean)) # Square root of the mean squared difference per factor sqrt(apply((y^2), 2, mean)) # Identity coefficient per factor after rotation 2 * colSums(trx$loadings * trBritain) / (colSums(trx$loadings^2) + colSums(trBritain^2)) # Additivity coefficient per factor after rotation diag(2 * cov(trx$loadings, trBritain)) / diag(var(trx$loadings) + var(trBritain)) # Proportionality coefficient per factor after rotation colSums(trBritain * trx$loadings) / sqrt(colSums(trBritain^2) * colSums(trx$loadings^2)) # Correlation for each factor after rotation diag(cor(trBritain, trx$loadings)) options(digits = origdigits$digits) \end{Scode} The effect of target rotation can be visualized by plotting the factor loadings for both samples in the two-dimensional factor space. The following plot shows the British loadings (target), the German loadings before rotation, and the German loadings after rotation towards the British solution. Arrows connect each item's pre- and post-rotation position, making the movement induced by the rotation immediately visible. \begin{center} \begin{Scode}{fig=TRUE} plot(trBritain[, 1], trBritain[, 2], xlim = c(-0.3, 1.0), ylim = c(-0.3, 1.0), xlab = "Factor 1", ylab = "Factor 2", main = "Target Rotation: Germany towards Britain", pch = 19, col = "steelblue", cex = 1.2) abline(h = 0, lty = 2, col = "grey70") abline(v = 0, lty = 2, col = "grey70") points(trGermany[, 1], trGermany[, 2], pch = 17, col = "tomato", cex = 1.2) points(loadings(trx)[, 1], loadings(trx)[, 2], pch = 15, col = "orange", cex = 1.2) for (i in 1:nrow(trGermany)) { arrows(trGermany[i, 1], trGermany[i, 2], loadings(trx)[i, 1], loadings(trx)[i, 2], length = 0.08, col = "grey60") } legend("topright", legend = c("Britain (varimax rotated)", "East Germany (varimax rotated)", "East Germany (rotated towards Britain)"), col = c("steelblue", "tomato", "orange"), pch = c(19, 17, 15), bty = "n") \end{Scode} \end{center} Items whose arrows are short moved little during rotation, indicating that the German and British loadings were already similar for those items. Items with longer arrows required more adjustment, suggesting greater cultural differences in how those behaviors are structured. After rotation, the German loadings may be compared directly to the British target using the agreement coefficients computed above. \subsection*{An Example of Partially Specified Target Rotation} \cite{browne} reported an initial loadings matrix and a partially specified target to rotate towards. In \texttt{GPArotation} the partially specified target matrix is of the same dimension as the initial matrix \texttt{A}, with \texttt{NA} in entries that are not pre-specified. Both target rotation and partially specified target rotation can be used to reproduce \cite{browne} results. In this orthogonal rotation example, \texttt{targetT} includes a \texttt{Target} matrix with \texttt{NA} in entries not used in target rotation. With \texttt{pstT} no missing values are present in the \texttt{Target} matrix, and the weight matrix \texttt{W} includes weight 0 for entries not used, and 1 for entries included in the rotation. \begin{Scode}{results=verbatim} A <- matrix(c(.664, .688, .492, .837, .705, .82, .661, .457, .765, .322, .248, .304, -0.291, -0.314, -0.377, .397, .294, .428, -0.075, .192, .224, .037, .155, -.104, .077, -.488, .009), ncol = 3) # using targetT SPA <- matrix(c(rep(NA, 6), .7, .0, .7, rep(0, 3), rep(NA, 7), 0, 0, NA, 0, rep(NA, 4)), ncol = 3) xt <- targetT(A, Target = SPA) # using pstT SPApst <- matrix(c(rep(0, 6), .7, .0, .7, rep(0, 3), rep(0, 7), 0, 0, 0, 0, rep(0, 4)), ncol = 3) SPAW <- matrix(c(rep(0, 6), rep(1, 6), rep(0, 7), 1, 1, 0, 1, rep(0, 4)), ncol = 3) xpst <- pstT(A, Target = SPApst, W = SPAW) max(abs(loadings(xt) - loadings(xpst))) \end{Scode} Note that convergence tables are identical for both methods. Additional examples are available in the help pages of \texttt{GPFoblq} and \texttt{rotations}. %------------------------------------------------------------------- \section*{Using GPArotation with factanal} %------------------------------------------------------------------- \subsection*{Passing Rotation to factanal} Rotation functions can be passed directly to \texttt{factanal} via the \texttt{rotation} argument. Additional arguments are passed through the \texttt{control} list. For example, for the CCAI Climate-Friendly Purchasing Choices domain data, this may look as follows. \begin{Scode}{results=verbatim} data("CCAI", package = "GPArotation") factanal(factors = 3, covmat = CCAI_R, n.obs = 461, rotation = "infomaxT") factanal(factors = 3, covmat = CCAI_R, n.obs = 461, rotation = "infomaxT", control = list(rotate = list(normalize = TRUE, eps = 1e-6))) \end{Scode} For oblique rotation, the recommended approach is the two-step procedure: obtain unrotated loadings from \texttt{factanal}, then rotate separately using \texttt{GPArotation}. This gives full control over the rotation, including random starts, and avoids potential issues with factor reordering. \begin{Scode}{results=verbatim} data("WansbeekMeijer", package = "GPArotation") fa.unrotated <- factanal(factors = 3, covmat = NetherlandsTV, normalize = TRUE, rotation = "none") quartimin(loadings(fa.unrotated), normalize = TRUE) \end{Scode} Prior to R 4.5.1, the single-step approach (rotation inside \texttt{factanal}) had a bug in factor reordering after oblique rotation. This was reported by Bernaards and others and fixed by the R core team in R 4.5.1. The two-step procedure has always been correct regardless of R version. The following example verifies that the two approaches agree on R $\geq$ 4.5.1 using a non-standard Crawford-Ferguson kappa value. \begin{Scode}{results=verbatim} data("WansbeekMeijer", package = "GPArotation") fa.unrotated <- factanal(factors = 3, covmat = NetherlandsTV, normalize = TRUE, rotation = "none") # Two-step procedure (always correct) set.seed(42) fa.cf <- cfQ(loadings(fa.unrotated), kappa = 0.3, normalize = TRUE, randomStarts = 100) fa.cf if (getRversion() >= "4.5.1") { # Single-step via factanal (correct in R >= 4.5.1) set.seed(42) fa.factanal <- factanal(factors = 3, covmat = NetherlandsTV, normalize = TRUE, rotation = "cfQ", control = list(rotate = list(kappa = 0.3, randomStarts = 100))) fa.sorted <- print(fa.cf, sortLoadings = TRUE) cat("Maximum difference in loadings:\n") print(max(abs(abs(fa.sorted$loadings) - abs(fa.factanal$loadings)))) } else { cat("Single-step factanal oblique rotation requires R >= 4.5.1.\n") cat("Use the two-step procedure above for correct results.\n") } \end{Scode} %------------------------------------------------------------------- \section*{Evaluating Factor Model Fit} %------------------------------------------------------------------- Once a factor solution has been obtained, it is natural to ask how well the model reproduces the observed correlation matrix. Common fit indices can be computed directly from \texttt{factanal} output --- no additional packages are required. The key quantities are the chi-square statistic and degrees of freedom provided by \texttt{factanal}, and the residual matrix obtained by subtracting the model-implied correlation matrix from the observed one. \begin{Scode} factanal_fit <- function(fa, R_obs, n) { # Compute common factor model fit indices from factanal output. # For MLE extraction only (factanal). For other estimators (minres, # principal axis, WLS) the chi-square statistic is not defined in # the same way and this function should not be used. # # Args: # fa : a factanal object (rotation = "none" recommended) # R_obs : observed correlation or covariance matrix passed to factanal # n : sample size (n.obs passed to factanal) if (is.null(fa$STATISTIC)) stop("factanal did not compute a chi-square statistic. ", "Ensure n.obs is specified when passing a covariance matrix.") # Ensure we work with a correlation matrix R_obs <- cov2cor(as.matrix(R_obs)) p <- nrow(R_obs) L <- loadings(fa) k <- ncol(L) # number of factors extracted # Model-implied correlation matrix using factanal uniquenesses # fa$uniquenesses are the MLE estimated unique variances R_hat <- L %*% t(L) + diag(fa$uniquenesses) R_hat <- cov2cor(R_hat) # Residual matrix --- off-diagonal only Resid <- R_obs - R_hat diag(Resid) <- 0 # Test of the hypothesis that k factors are sufficient. Identical to factanal F_ml <- log(det(R_hat)) - log(det(R_obs)) + sum(diag(R_obs %*% solve(R_hat))) - p chi2 <- (n - 1 - (2 * p + 5)/6 - (2 * k)/3) * F_ml df <- ((p - k)^2 - (p + k)) / 2 pval <- pchisq(chi2, df, lower.tail = FALSE) # SRMR: standardized root mean square residual rstar.off <- sum(Resid^2) / 2 srmr <- sqrt(rstar.off / (p * (p - 1))) # RMSEA: root mean square error of approximation rmsea <- sqrt(max(0, chi2 / (df * n) - 1 / (n - 1))) # Null model: all items uncorrelated chi2_null <- (n - 1) * sum(R_obs[lower.tri(R_obs)]^2) df_null <- p * (p - 1) / 2 # CFI: comparative fit index cfi <- (max(chi2_null - df_null, 0) - max(chi2 - df, 0)) / max(chi2_null - df_null, 0) # TLI: Tucker-Lewis index tli <- (chi2_null / df_null - chi2 / df) / (chi2_null / df_null - 1) # AIC and BIC aic <- chi2 - 2 * df bic <- chi2 - log(n) * df # Print results cat("Factor Model Fit Indices (MLE only)\n") cat("------------------------------------\n") cat(sprintf("Chi-square (df = %d): %.3f p = %.4f\n", df, chi2, pval)) cat(sprintf("RMSEA: %.4f\n", rmsea)) cat(sprintf("SRMR: %.4f\n", srmr)) cat(sprintf("CFI: %.4f\n", cfi)) cat(sprintf("TLI: %.4f\n", tli)) cat(sprintf("AIC: %.3f\n", aic)) cat(sprintf("BIC: %.3f\n", bic)) cat("\nTop 5 absolute residuals:\n") resid_vals <- Resid[lower.tri(Resid)] print(round(sort(abs(resid_vals), decreasing = TRUE)[1:5], 4)) invisible(c(chi2 = chi2, df = df, pval = pval, rmsea = rmsea, srmr = srmr, cfi = cfi, tli = tli, aic = aic, bic = bic)) } \end{Scode} The following example fits two and three factor solutions to the Netherlands television viewership data and compares their fit: \begin{Scode}{results=verbatim} data("WansbeekMeijer", package = "GPArotation") fa2 <- factanal(factors = 2, covmat = NetherlandsTV, rotation = "none") fa3 <- factanal(factors = 3, covmat = NetherlandsTV, rotation = "none") cat("=== 2 factors ===\n") fit2 <- factanal_fit(fa2, cov2cor(NetherlandsTV$cov), n = 2154) cat("\n=== 3 factors ===\n") fit3 <- factanal_fit(fa3, cov2cor(NetherlandsTV$cov), n = 2154) \end{Scode} \begin{Scode}{results=verbatim} cat("Model comparison:\n") cat(sprintf(" 2-factor 3-factor\n")) cat(sprintf("RMSEA: %8.4f %8.4f\n", fit2["rmsea"], fit3["rmsea"])) cat(sprintf("SRMR: %8.4f %8.4f\n", fit2["srmr"], fit3["srmr"])) cat(sprintf("CFI: %8.4f %8.4f\n", fit2["cfi"], fit3["cfi"])) cat(sprintf("TLI: %8.4f %8.4f\n", fit2["tli"], fit3["tli"])) cat(sprintf("AIC: %8.2f %8.2f\n", fit2["aic"], fit3["aic"])) cat(sprintf("BIC: %8.2f %8.2f\n", fit2["bic"], fit3["bic"])) \end{Scode} A few notes on interpreting these indices: \begin{itemize} \item \textbf{Chi-square} tests the exact fit hypothesis that the model reproduces the population correlation matrix exactly. With large samples it is almost always significant and should not be used as the sole criterion for model rejection. \item \textbf{RMSEA} values below 0.05 indicate close fit, below 0.08 acceptable fit, and above 0.10 poor fit. The 90\% confidence interval is computed from the noncentral chi-square distribution using base R --- no additional packages are required. A confidence interval that includes 0.05 indicates uncertainty about whether fit is close or merely acceptable. A confidence interval entirely above 0.10 indicates poor fit with high confidence. \item \textbf{SRMR} is the average discrepancy between observed and model-implied correlations. Values below 0.08 are generally considered acceptable. \item \textbf{CFI} and \textbf{TLI} compare the target model to a null model where all items are uncorrelated. Values above 0.95 indicate good fit and above 0.90 acceptable fit. TLI penalizes more strongly for model complexity than CFI. \item \textbf{AIC} and \textbf{BIC} are useful for comparing models with different numbers of factors --- lower values indicate better fit penalized for complexity. They are most useful relative to each other rather than in absolute terms. BIC penalizes more strongly for model complexity than AIC and tends to favor more parsimonious solutions. \end{itemize} These indices are computed under the maximum likelihood estimation assumptions of \texttt{factanal} and assume multivariate normality. They are descriptive tools that may help evaluate and compare factor solutions, not definitive tests of model correctness. No single index should be used in isolation --- examining multiple indices together, alongside the substantive interpretability of the solution, provides a more complete picture. For more comprehensive structural equation modeling with a wider range of fit indices, the \textit{lavaan} package provides a full CFA implementation. The fit indices computed by \texttt{factanal\_fit} are based on the chi-square statistic from \texttt{factanal}, which uses maximum likelihood estimation (MLE). For factor solutions extracted by other methods --- such as minimum residual (minres), principal axis, or weighted least squares --- the chi-square statistic and derived fit indices (RMSEA, CFI, TLI, AIC, BIC) will differ because the likelihood objective function is not defined in the same way for non-ML estimators. In those cases \texttt{factanal\_fit} should not be used. The \textit{psych} package provides fit indices for a wider range of estimation methods via \texttt{psych::fa}, and the \textit{lavaan} package provides a full CFA implementation with comprehensive fit index reporting for multiple estimators. A comparison of \texttt{factanal\_fit} with \texttt{psych::fa} using the same data and maximum likelihood estimation shows that BIC values agree exactly, since both implementations use the same chi-square statistic. RMSEA and CFI also agree substantively. SRMR and TLI may differ slightly due to differences in formula conventions between implementations --- these differences do not affect substantive conclusions about model fit. When exact replication of \texttt{psych} fit indices is required, use \texttt{psych::fa} directly. Minor differences between fit indices computed by different software implementations are common and expected. They typically reflect differences in how the likelihood objective function is scaled rather than errors in either implementation. Substantive conclusions --- which model fits better, whether fit is acceptable --- are generally robust to these differences. %------------------------------------------------------------------- \section*{Rotation Criteria Reference} %------------------------------------------------------------------- The following table lists all rotation criteria available in \texttt{GPArotation}, with their type and key reference. Criteria ending in \texttt{T} are orthogonal; those ending in \texttt{Q} are oblique. Criteria without a \texttt{T}/\texttt{Q} suffix may be used for both. \begin{tabular}{l l l} \hline Function & Type & Criterion \\ \hline\hline \texttt{oblimin} & oblique & Oblimin family; \texttt{gam} controls obliqueness \\ \texttt{quartimin} & oblique & Oblimin with \texttt{gam = 0} \\ \texttt{targetT} & orthogonal & Rotation towards a target matrix \\ \texttt{targetQ} & oblique & Rotation towards a target matrix \\ \texttt{pstT} & orthogonal & Partially specified target rotation \\ \texttt{pstQ} & oblique & Partially specified target rotation \\ \texttt{oblimax} & oblique & Maximizes overall kurtosis of loadings \\ \texttt{entropy} & orthogonal & Minimizes entropy of squared loadings \\ \texttt{quartimax} & orthogonal & Maximizes variance of squared loadings within variables \\ \texttt{Varimax} & orthogonal & Maximizes variance of squared loadings within factors \\ \texttt{simplimax} & oblique & Minimizes the $k$ smallest squared loadings \\ \texttt{bentlerT} & orthogonal & Invariant pattern simplicity \\ \texttt{bentlerQ} & oblique & Invariant pattern simplicity \\ \texttt{tandemI} & orthogonal & Factors share high loadings on same variables \\ \texttt{tandemII} & orthogonal & Factors do not share high loadings on same variables \\ \texttt{geominT} & orthogonal & Minimizes geometric mean of squared loadings \\ \texttt{geominQ} & oblique & Minimizes geometric mean of squared loadings \\ \texttt{bigeominT} & orthogonal & Geomin with a general factor in column 1 \\ \texttt{bigeominQ} & oblique & Geomin with a general factor in column 1 \\ \texttt{cfT} & orthogonal & Crawford-Ferguson family; \texttt{kappa} controls complexity \\ \texttt{cfQ} & oblique & Crawford-Ferguson family; \texttt{kappa} controls complexity \\ \texttt{equamax} & orthogonal & Crawford-Ferguson with $\kappa = m/(2p)$ \\ \texttt{parsimax} & orthogonal & Crawford-Ferguson with $\kappa = (m-1)/(p+m-2)$ \\ \texttt{infomaxT} & orthogonal & Infomax information criterion \\ \texttt{infomaxQ} & oblique & Infomax information criterion \\ \texttt{mccammon} & orthogonal & Minimizes entropy ratio across factors \\ \texttt{varimin} & orthogonal & Minimizes variance of squared loadings within factors \\ \texttt{bifactorT} & orthogonal & Bifactor; general factor in column 1 \\ \texttt{bifactorQ} & oblique & Biquartimin; general factor in column 1 \\ \texttt{lpT} & orthogonal & $L^p$ sparsity rotation \\ \texttt{lpQ} & oblique & $L^p$ sparsity rotation \\ \hline \end{tabular} %------------------------------------------------------------------- \section*{Further Resources} %------------------------------------------------------------------- Full documentation for all functions is available via the R help system, for example \texttt{?quartimax} or \texttt{?GPFRSorth}. The package index is accessible via \texttt{?GPArotation}. The following vignettes are provided with \texttt{GPArotation}: \begin{itemize} \item \texttt{vignette("GPA2local", package = "GPArotation")} --- assessing local minima in factor rotation, including the \texttt{GPFallMinima} function and sorted loadings plots \item \texttt{vignette("GPA3bifactor", package = "GPArotation")} --- bifactor rotation and reliability coefficients including omega hierarchical \end{itemize} Gradient projection \emph{without} derivatives can be performed using the \texttt{GPArotateDF} package, available separately on CRAN. A vignette is provided with that package; type \texttt{vignette("GPArotateDF", package = "GPArotateDF")} at the R prompt. For detailed investigation of local minima in factor rotation, the following packages provide complementary functionality: \begin{itemize} \item \textit{fungible}: \texttt{faMain} function with extensive random start diagnostics \item \textit{psych}: \texttt{faRotations} function for rotation comparison \end{itemize} %------------------------------------------------------------------- \section*{References for Rotation Criteria} %------------------------------------------------------------------- The following references describe the theoretical basis for each rotation criterion implemented in \texttt{GPArotation}. \subsubsection*{Descriptions of many rotation criteria} Browne, M.W. (2001). An overview of analytic rotation in exploratory factor analysis. \textit{Multivariate Behavioral Research}, \textbf{36}, 111--150. \href{https://doi.org/10.1207/S15327906MBR3601_05} {doi: 10.1207/S15327906MBR3601\_05} \noindent Harman, H.H. (1976). \textit{Modern Factor Analysis} (3rd ed.). The University of Chicago Press. \subsubsection*{Oblimin / Quartimin} Carroll, J.B. (1960). IBM 704 program for generalized analytic rotation solution in factor analysis. Harvard University, unpublished. \noindent Jennrich, R.I. (1979). Admissible values of $\gamma$ in direct oblimin rotation. \textit{Psychometrika}, \textbf{44}, 173--177. \href{https://doi.org/10.1007/BF02293969} {doi: 10.1007/BF02293969} \subsubsection*{Target rotation} Harman, H.H. (1976). \textit{Modern Factor Analysis} (3rd ed.). The University of Chicago Press. \subsubsection*{Partially specified target rotation} Browne, M.W. (1972a). Orthogonal rotation to a partially specified target. \textit{British Journal of Mathematical and Statistical Psychology}, \textbf{25}, 115--120. \href{https://doi.org/10.1111/j.2044-8317.1972.tb00482.x} {doi: 10.1111/j.2044-8317.1972.tb00482.x} \noindent Browne, M.W. (1972b). Oblique rotation to a partially specified target. \textit{British Journal of Mathematical and Statistical Psychology}, \textbf{25}, 207--212. \href{https://doi.org/10.1111/j.2044-8317.1972.tb00492.x} {doi: 10.1111/j.2044-8317.1972.tb00492.x} \subsubsection*{Oblimax} Pinzka, C. and Saunders, D.R. (1954). Analytic rotation to simple structure: II. Extension to an oblique solution. Research Bulletin 54--31. Princeton, N.J.: Educational Testing Service. \noindent Saunders, D.R. (1961). The rationale for an ``oblimax'' method of transformation in factor analysis. \textit{Psychometrika}, \textbf{26}, 317--324. \href{https://doi.org/10.1007/BF02289800} {doi: 10.1007/BF02289800} \subsubsection*{Minimum entropy} Jennrich, R.I. (2004). Rotation to simple loadings using component loss functions: the orthogonal case. \textit{Psychometrika}, \textbf{69}, 257--274. \href{https://doi.org/10.1007/BF02295943} {doi: 10.1007/BF02295943} \subsubsection*{Quartimax} Carroll, J.B. (1953). An analytic solution for approximating simple structure in factor analysis. \textit{Psychometrika}, \textbf{18}, 23--38. \href{https://doi.org/10.1007/BF02289025} {doi: 10.1007/BF02289025} \noindent Ferguson, G.A. (1954). The concept of parsimony in factor analysis. \textit{Psychometrika}, \textbf{19}, 281--290. \href{https://doi.org/10.1007/BF02289228} {doi: 10.1007/BF02289228} \noindent Neuhaus, J.O. and Wrigley, C. (1954). The quartimax method: An analytical approach to orthogonal simple structure. \textit{British Journal of Statistical Psychology}, \textbf{7}, 81--91. \href{https://doi.org/10.1111/j.2044-8317.1954.tb00147.x} {doi: 10.1111/j.2044-8317.1954.tb00147.x} \subsubsection*{Varimax} Kaiser, H.F. (1958). The varimax criterion for analytic rotation in factor analysis. \textit{Psychometrika}, \textbf{23}, 187--200. \href{https://doi.org/10.1007/BF02289233} {doi: 10.1007/BF02289233} \subsubsection*{Simplimax} Kiers, H.A.L. (1994). SIMPLIMAX: Oblique rotation to an optimal target with simple structure. \textit{Psychometrika}, \textbf{59}, 567--579. \href{https://doi.org/10.1007/BF02294392} {doi: 10.1007/BF02294392} \subsubsection*{Bentler invariant pattern simplicity} Bentler, P.M. (1977). Factor simplicity index and transformations. \textit{Psychometrika}, \textbf{42}, 277--295. \href{https://doi.org/10.1007/BF02294054} {doi: 10.1007/BF02294054} \subsubsection*{Tandem criteria} Comrey, A.L. (1967). Tandem criteria for analytic rotation in factor analysis. \textit{Psychometrika}, \textbf{32}, 277--295. \href{https://doi.org/10.1007/BF02289422} {doi: 10.1007/BF02289422} \subsubsection*{Geomin} Yates, A. (1984). \textit{Multivariate Exploratory Data Analysis: A Perspective on Exploratory Factor Analysis}. State University of New York Press. \subsubsection*{Bi-Geomin} Garcia-Garzon, E., Abad, F.J., and Garrido, L.E. (2021). On omega hierarchical estimation: A comparison of exploratory bi-factor analysis algorithms. \textit{Multivariate Behavioral Research}, \textbf{56}(1), 101--119. \href{https://doi.org/10.1080/00273171.2020.1736977} {doi: 10.1080/00273171.2020.1736977} \subsubsection*{Crawford-Ferguson family} Crawford, C.B. and Ferguson, G.A. (1970). A general rotation criterion and its use in orthogonal rotation. \textit{Psychometrika}, \textbf{35}, 321--332. \href{https://doi.org/10.1007/BF02310572} {doi: 10.1007/BF02310572} \subsubsection*{Infomax} McKeon, J.J. (1968). Rotation for maximum association between factors and tests. Unpublished manuscript, Biometric Laboratory, George Washington University. \subsubsection*{McCammon minimum entropy ratio} McCammon, R.B. (1966). Principal components analysis and its application in large-scale correlation studies. \textit{Journal of Geology}, \textbf{74}, 721--733. \href{https://doi.org/10.1086/627207} {doi: 10.1086/627207} \subsubsection*{Varimin} Ertel, S. (2011). Exploratory factor analysis revealing complex structure. \textit{Personality and Individual Differences}, \textbf{50}(2), 196--200. \href{https://doi.org/10.1016/j.paid.2010.09.026} {doi: 10.1016/j.paid.2010.09.026} \subsubsection*{Bifactor} Jennrich, R.I. and Bentler, P.M. (2011). Exploratory bi-factor analysis. \textit{Psychometrika}, \textbf{76}(4), 537--549. \href{https://doi.org/10.1007/s11336-011-9218-4} {doi: 10.1007/s11336-011-9218-4} \subsubsection*{Lp rotation} Liu, X., Wallin, G., Chen, Y., and Moustaki, I. (2023). Rotation to sparse loadings using $L^p$ losses and related inference problems. \textit{Psychometrika}, \textbf{88}(2), 527--553. \href{https://doi.org/10.1007/s11336-023-09911-y} {doi: 10.1007/s11336-023-09911-y} \begin{thebibliography}{} \bibitem[\protect\citeauthoryear{Bernaards \& Jennrich}{Bernaards \& Jennrich}{2005}]{gpa.rotate} Bernaards, C. A., \& Jennrich, R. I. (2005). \newblock Gradient projection algorithms and software for arbitrary rotation criteria in factor analysis. \newblock {\em Educational and Psychological Measurement}, 65(5), 676--696. \newblock \href{https://doi.org/10.1177/0013164404272507} {https://doi.org/10.1177/0013164404272507} \bibitem[\protect\citeauthoryear{Browne}{Browne}{1972}]{browne} Browne, M. W. (1972). \newblock Orthogonal rotation to a partially specified target. \newblock \textit{British Journal of Mathematical and Statistical Psychology}, 25(1), 115--120. \newblock \href{https://doi.org/10.1111/j.2044-8317.1972.tb00482.x} {doi: 10.1111/j.2044-8317.1972.tb00482.x} \bibitem[\protect\citeauthoryear{Fischer \& Fontaine}{Fischer \& Fontaine}{2010}]{fisfon} Fischer, R., \& Fontaine, J. (2010). \newblock Methods for investigating structural equivalence. \newblock In D. Matsumoto, \& F. van de Vijver (Eds.), {\em Cross-Cultural Research Methods in Psychology} (pp. 179--215). \newblock Cambridge University Press. \newblock \href{https://doi.org/10.1017/CBO9780511779381.010} {doi: 10.1017/CBO9780511779381.010} \bibitem[\protect\citeauthoryear{mansreise}{Mansolf \& Reise}{2016}]{mansreise} Mansolf, M. and Reise, S.P. (2016). \newblock Exploratory bifactor analysis: The Schmid-Leiman orthogonalization and Jennrich-Bentler analytic rotations. \newblock \textit{Multivariate Behavioral Research}, \textbf{51}(5), 698--717. \newblock \href{https://doi.org/10.1080/00273171.2016.1215898} {doi: 10.1080/00273171.2016.1215898} \bibitem[\protect\citeauthoryear{Nguyen \& Waller}{Nguyen \& Waller}{2022}]{nguwall} Nguyen, H. V., \& Waller, N. G. (2022). \newblock Local minima and factor rotations in exploratory factor analysis. \newblock \textit{Psychological Methods}. Advance online publication. \newblock \href{https://doi.org/10.1037/met0000467} {doi: 10.1037/met0000467} \end{thebibliography} \end{document} GPArotation/inst/doc/GPA2local.R0000644000176200001440000001741715174250605016031 0ustar liggesusers### R code from vignette source 'GPA2local.Stex' ################################################### ### code chunk number 1: GPA2local.Stex:19-21 ################################################### options(continue=" ") pdf.options(pointsize = 8) ################################################### ### code chunk number 2: GPA2local.Stex:57-163 ################################################### library("GPArotation") GPFallMinima <- function(A, method = "quartimin", orthogonal = FALSE, randomStarts = 100, eps = 1e-5, maxit = 1000, normalize = FALSE, methodArgs = NULL, minimumInclusion = 2) { # Runs multiple random starts and returns ALL distinct local minima, # not just the global minimum. Non-converged starts are discarded. # Minima found fewer than minimumInclusion times are excluded. # Minima are sorted by frequency (most common first). engine <- if (orthogonal) GPForth else GPFoblq Qvalues <- numeric(randomStarts) Qconverged <- logical(randomStarts) all_res <- vector("list", randomStarts) for (i in 1:randomStarts) { res <- engine(A, Tmat = Random.Start(ncol(A)), normalize = normalize, eps = eps, maxit = maxit, method = method, methodArgs = methodArgs) Qvalues[i] <- res$Table[nrow(res$Table), 2] Qconverged[i] <- res$convergence all_res[[i]] <- res } # Discard non-converged starts converged_idx <- which(Qconverged) nConverged <- length(converged_idx) if (nConverged == 0) stop("No starts converged. Consider increasing maxit or relaxing eps.") Qvalues_conv <- Qvalues[converged_idx] all_res_conv <- all_res[converged_idx] # Bin converged criterion values into equivalence classes Q_round <- round(Qvalues_conv / eps) * eps Q_unique <- unique(Q_round) # Build one representative solution per unique minimum minima <- vector("list", length(Q_unique)) for (j in seq_along(Q_unique)) { idx <- which(Q_round == Q_unique[j]) count <- length(idx) proportion <- count / nConverged minima[[j]] <- list( result = all_res_conv[[idx[1]]], f = Q_unique[j], count = count, proportion = proportion ) } # Sort by count (most common first) ord <- order(sapply(minima, `[[`, "count"), decreasing = TRUE) minima <- minima[ord] # Filter out minima found fewer than minimumInclusion times keep <- sapply(minima, `[[`, "count") >= minimumInclusion minima <- minima[keep] if (length(minima) == 0) stop("No minima found with count >= minimumInclusion (", minimumInclusion, "). Consider reducing minimumInclusion or increasing randomStarts.") # Summary data frame f_values <- sapply(minima, `[[`, "f") f_global <- min(f_values) summary_df <- data.frame( minimum = seq_along(minima), f = round(f_values, 6), deltaF = round(f_values - f_global, 6), count = sapply(minima, `[[`, "count"), proportion = round(sapply(minima, `[[`, "proportion"), 3), isGlobal = f_values == f_global ) result <- list( minima = minima, summary = summary_df, Qvalues = Qvalues_conv, nConverged = nConverged, nStarts = randomStarts, method = method, orthogonal = orthogonal, minimumInclusion = minimumInclusion ) class(result) <- "GPFallMinima" result } print.GPFallMinima <- function(x, ...) { cat("Random start analysis:", x$nConverged, "of", x$nStarts, "starts converged\n") cat("Distinct minima found:", nrow(x$summary), "(minimumInclusion =", x$minimumInclusion, ")\n\n") print(x$summary, row.names = FALSE) cat("\nGlobal minimum: f =", min(x$summary$f), "\n") cat("Access full solutions via $minima[[i]]$result\n") invisible(x) } ################################################### ### code chunk number 3: GPA2local.Stex:212-230 ################################################### library("GPArotation") data("CCAI", package = "GPArotation") fa_unrotated <- factanal(factors = 3, covmat = CCAI_R, n.obs = 461, rotation = "none") A <- loadings(fa_unrotated) # Oblimin: highly stable res_oblimin <- oblimin(A, normalize = TRUE, randomStarts = 200) cat("Oblimin random start diagnostics:\n") res_oblimin$randStartChar # Simplimax: complex landscape set.seed(42) res_ccai <- GPFallMinima(A, method = "simplimax", randomStarts = 200, normalize = TRUE, minimumInclusion = 2) res_ccai ################################################### ### code chunk number 4: GPA2local.Stex:254-256 ################################################### # Print the most common solution print(res_ccai$minima[[1]]$result) ################################################### ### code chunk number 5: GPA2local.Stex:262-264 ################################################### # Print solution in row 3 of the summary print(res_ccai$minima[[3]]$result, digits = 2) ################################################### ### code chunk number 6: GPA2local.Stex:269-271 ################################################### i <- 3 print(res_ccai$minima[[i]]$result, digits = 2) ################################################### ### code chunk number 7: GPA2local.Stex:278-281 ################################################### # Print the global minimum using the GPArotation S3 print method global <- which(res_ccai$summary$isGlobal) print(res_ccai$minima[[global]]$result, digits = 2) ################################################### ### code chunk number 8: GPA2local.Stex:284-286 ################################################### # Summary with structure matrix for oblique solution summary(res_ccai$minima[[global]]$result, Structure = TRUE, digits = 2) ################################################### ### code chunk number 9: GPA2local.Stex:308-344 ################################################### plotSortedLoadings <- function(..., labels = NULL, col = NULL, main = "Sorted Absolute Loadings", ylab = "Absolute loading", xlab = "Rank") { solutions <- list(...) for (i in seq_along(solutions)) { if (!inherits(solutions[[i]], "GPArotation")) stop("Argument ", i, " is not a GPArotation object.") } n <- length(solutions) if (is.null(labels)) labels <- paste("Solution", seq_len(n)) if (is.null(col)) col <- palette.colors(n, palette = "Okabe-Ito") sorted_loadings <- lapply(solutions, function(x) sort(abs(as.vector(x$loadings)), decreasing = FALSE)) all_values <- unlist(sorted_loadings) max_len <- max(sapply(sorted_loadings, length)) plot(NULL, xlim = c(1, max_len), ylim = c(0, max(all_values)), main = main, xlab = xlab, ylab = ylab, las = 1) abline(h = seq(0, 1, by = 0.1), col = "grey90", lty = 1) for (i in seq_len(n)) { lines(seq_along(sorted_loadings[[i]]), sorted_loadings[[i]], col = col[i], lwd = 2) points(seq_along(sorted_loadings[[i]]), sorted_loadings[[i]], col = col[i], pch = 19, cex = 0.6) } legend("topleft", legend = labels, col = col, lwd = 2, pch = 19, bty = "n") invisible(sorted_loadings) } ################################################### ### code chunk number 10: GPA2local.Stex:349-354 ################################################### do.call(plotSortedLoadings, c(lapply(res_ccai$minima, function(x) x$result), list(labels = paste0("Min ", res_ccai$summary$minimum, " (f=", round(res_ccai$summary$f, 4), ", n=", res_ccai$summary$count, ")")))) GPArotation/build/0000755000176200001440000000000015174250607013547 5ustar liggesusersGPArotation/build/vignette.rds0000644000176200001440000000063215174250607016107 0ustar liggesusersSN0M %N\*_P UW78?emR ffyKWoTj-MսO C>,B\3BoHq.a3%_!0(6Ù/ lz9d<9ÿ om⭃$d>shVNBa*Lè.w`dvL~<~a;Aα*]E 9RNtu޹;[r.00y*GLH "sqۍ2gKUD=A4ZZ#1kѴ`}\3Q'v[qƐB^rC=/Z~EUn FΓ RGPArotation/man/0000755000176200001440000000000015174250607013223 5ustar liggesusersGPArotation/man/00.GPArotation.Rd0000644000176200001440000002016715174132204016115 0ustar liggesusers\encoding{UTF-8} \name{00.GPArotation} \alias{GPArotation} \alias{GPArotation-package} \alias{GPArotation.Intro} \docType{package} \title{Gradient Projection Algorithms for Factor Rotation} \description{GPA Rotation for Factor Analysis The GPArotation package contains functions for the rotation of factor loadings matrices. The functions implement Gradient Projection (GP) algorithms for orthogonal and oblique rotation. Additionally, a number of rotation criteria are provided. The GP algorithms minimize the rotation criterion function and provide the corresponding rotation matrix. For oblique rotation, the covariance/correlation matrix of the factors is also provided. The rotation criteria implemented in this package are described in Bernaards and Jennrich (2005). Theory of the GP algorithm is described in Jennrich (2001, 2002). Additionally, two rotation methods are provided that do not rely on GP (\code{eiv} and \code{echelon}). Four vignettes are provided covering general usage, local minima diagnostics, bifactor rotation and reliability, and derivative-free gradient projection. Access them via Access them via \code{browseVignettes("GPArotation")}. \tabular{ll}{ Package: \tab GPArotation\cr Depends: \tab R (>= 3.5.0)\cr License: \tab GPL Version 2.\cr } Index of functions: Rotations using gradient projection algorithms\cr \tabular{ll}{ \code{\link{oblimin}} \tab Oblimin rotation \cr \code{\link{quartimin}} \tab Quartimin rotation \cr \code{\link{targetT}} \tab Orthogonal target rotation \cr \code{\link{targetQ}} \tab Oblique target rotation \cr \code{\link{pstT}} \tab Orthogonal partially specified target rotation \cr \code{\link{pstQ}} \tab Oblique partially specified target rotation \cr \code{\link{oblimax}} \tab Oblimax rotation \cr \code{\link{entropy}} \tab Minimum entropy rotation \cr \code{\link{quartimax}} \tab Quartimax rotation \cr \code{\link{Varimax}} \tab Varimax rotation \cr \code{\link{simplimax}} \tab Simplimax rotation \cr \code{\link{bentlerT}} \tab Orthogonal Bentler invariant pattern simplicity rotation \cr \code{\link{bentlerQ}} \tab Oblique Bentler invariant pattern simplicity rotation \cr \code{\link{tandemI}} \tab Tandem criteria principle I rotation \cr \code{\link{tandemII}} \tab Tandem criteria principle II rotation \cr \code{\link{geominT}} \tab Orthogonal Geomin rotation \cr \code{\link{geominQ}} \tab Oblique Geomin rotation \cr \code{\link{bigeominT}} \tab Orthogonal Bi-Geomin rotation \cr \code{\link{bigeominQ}} \tab Oblique Bi-Geomin rotation \cr \code{\link{cfT}} \tab Orthogonal Crawford-Ferguson family rotation \cr \code{\link{cfQ}} \tab Oblique Crawford-Ferguson family rotation \cr \code{\link{equamax}} \tab Equamax rotation \cr \code{\link{parsimax}} \tab Parsimax rotation \cr \code{\link{infomaxT}} \tab Orthogonal Infomax rotation \cr \code{\link{infomaxQ}} \tab Oblique Infomax rotation \cr \code{\link{mccammon}} \tab McCammon minimum entropy ratio rotation \cr \code{\link{varimin}} \tab Varimin rotation \cr \code{\link{bifactorT}} \tab Orthogonal bifactor rotation \cr \code{\link{bifactorQ}} \tab Oblique bifactor rotation \cr \code{\link{lpT}} \tab Orthogonal \eqn{L^p}{Lp} rotation \cr \code{\link{lpQ}} \tab Oblique \eqn{L^p}{Lp} rotation \cr } Other rotations not using gradient projection algorithms\cr \tabular{ll}{ \code{\link{eiv}} \tab Errors-in-variables rotation \cr \code{\link{echelon}} \tab Echelon rotation \cr \code{\link[stats]{varimax}} \tab varimax [The R Stats Package] \cr \code{\link[stats]{promax}} \tab promax [The R Stats Package] \cr } Core gradient projection algorithms\cr \tabular{ll}{ \code{\link{GPForth}} \tab Orthogonal rotation function \cr \code{\link{GPFoblq}} \tab Oblique rotation function \cr } Random-start wrappers and internal engine\cr \tabular{ll}{ \code{\link{GPFRSorth}} \tab Random-start wrapper for orthogonal rotation \cr \code{\link{GPFRSoblq}} \tab Random-start wrapper for oblique rotation \cr \code{.GPA_RS_engine} \tab Internal random-start engine (not exported) \cr } Legacy gradient projection algorithms (code unchanged since 2008)\cr \tabular{ll}{ \code{GPForth.legacy} \tab Orthogonal rotation, original implementation (not exported) \cr \code{GPFoblq.legacy} \tab Oblique rotation, original implementation (not exported) \cr } Utility functions\cr \tabular{ll}{ \code{\link{print.GPArotation}} \tab Print results (S3 method) \cr \code{\link{summary.GPArotation}} \tab Summary of results (S3 method) \cr \code{.sortGPALoadings} \tab Sort and sign-correct factors (not exported) \cr \code{\link{Random.Start}} \tab Random starting matrix for factor rotation \cr \code{\link{NormalizingWeight}} \tab Normalizing weights utility (not exported) \cr \code{\link{GPForth.lp}} \tab Single-start \eqn{L^p}{Lp} orthogonal rotation \cr \code{\link{GPFoblq.lp}} \tab Single-start \eqn{L^p}{Lp} oblique rotation \cr } Rotation criterion functions (not exported)\cr \tabular{ll}{ \code{\link{vgQ.oblimin}} \tab Oblimin \cr \code{\link{vgQ.quartimin}} \tab Quartimin \cr \code{\link{vgQ.target}} \tab Target \cr \code{\link{vgQ.pst}} \tab Partially specified target \cr \code{\link{vgQ.oblimax}} \tab Oblimax \cr \code{\link{vgQ.entropy}} \tab Minimum entropy \cr \code{\link{vgQ.quartimax}} \tab Quartimax \cr \code{\link{vgQ.varimax}} \tab Varimax \cr \code{\link{vgQ.simplimax}} \tab Simplimax \cr \code{\link{vgQ.bentler}} \tab Bentler invariant pattern simplicity \cr \code{\link{vgQ.tandemI}} \tab Tandem criteria principle I \cr \code{\link{vgQ.tandemII}} \tab Tandem criteria principle II \cr \code{\link{vgQ.geomin}} \tab Geomin \cr \code{\link{vgQ.bigeomin}} \tab Bi-Geomin \cr \code{\link{vgQ.cf}} \tab Crawford-Ferguson family \cr \code{\link{vgQ.infomax}} \tab Infomax \cr \code{\link{vgQ.mccammon}} \tab McCammon minimum entropy ratio \cr \code{\link{vgQ.varimin}} \tab Varimin \cr \code{\link{vgQ.bifactor}} \tab Bifactor \cr \code{\link{vgQ.lp.wls}} \tab Weighted least squares for \eqn{L^p}{Lp} rotation \cr } Data sets\cr \tabular{ll}{ \code{\link{Harman8}} \tab Harman's 8 physical variables; centroid loadings \cr \code{\link{NetherlandsTV}} \tab Wansbeek and Meijer Netherlands TV viewership; correlation matrix \cr \code{\link{box26}} \tab Thurstone's 26 box variables; unrotated factor loadings \cr \code{\link{box20}} \tab Thurstone's 20 box variables (deprecated, use box26) \cr \code{\link{CCAI}} \tab CCAI Climate-Friendly Purchasing Choices domain; correlation matrix, pattern matrix, and factor intercorrelations \cr } Vignettes\cr \tabular{ll}{ \code{GPA1guide} \tab Gradient Projection Factor Rotation (main guide) \cr \code{GPA2local} \tab Assessing Local Minima in Factor Rotation \cr \code{GPA3bifactor} \tab Bifactor Rotation and Reliability Coefficients \cr } } \author{Coen A. Bernaards and Robert I. Jennrich with some R modifications by Paul Gilbert. } \references{ The software reference is: Bernaards, C.A. and Jennrich, R.I. (2005). Gradient projection algorithms and software for arbitrary rotation criteria in factor analysis. \emph{Educational and Psychological Measurement}, \bold{65}, 676--696. doi: 10.1177/0013164404272507 Theory of gradient projection algorithms: Jennrich, R.I. (2001). A simple general procedure for orthogonal rotation. \emph{Psychometrika}, \bold{66}, 289--306. doi: 10.1007/BF02294840 Jennrich, R.I. (2002). A simple general method for oblique rotation. \emph{Psychometrika}, \bold{67}, 7--19. doi: 10.1007/BF02294706 A clear and accessible introduction to gradient projection algorithms for factor rotation is provided in: Mansolf, M. and Reise, S.P. (2016). Exploratory bifactor analysis: The Schmid-Leiman orthogonalization and Jennrich-Bentler analytic rotations. \emph{Multivariate Behavioral Research}, \bold{51}(5), 698--717. doi: 10.1080/00273171.2016.1215898 } \keyword{package} \seealso{ \code{\link{GPFRSorth}}, \code{\link{GPFRSoblq}}, \code{\link{rotations}}, \code{\link{vgQ}} \code{browseVignettes("GPArotation")} }GPArotation/man/eiv.Rd0000644000176200001440000001056315163644572014310 0ustar liggesusers\encoding{UTF-8} \name{eiv} \alias{eiv} \title{Errors-in-Variables Rotation} \usage{ eiv(L, identity = seq(NCOL(L)), ...) } \arguments{ \item{L}{a factor loading matrix.} \item{identity}{integer vector indicating which rows of the loading matrix should form an identity matrix. Default uses the first \eqn{k}{k} rows. If inverting the submatrix indicated by \code{identity} fails, a different choice of rows must be supplied.} \item{...}{additional arguments discarded.} } \value{ A \code{GPArotation} object which is a list with elements: \item{loadings}{The rotated loadings matrix.} \item{Th}{The rotation matrix.} \item{method}{A string indicating the rotation method (\code{"eiv"}).} \item{orthogonal}{Always \code{FALSE} (oblique rotation).} \item{convergence}{Always \code{TRUE} (the optimization is not iterative).} \item{Phi}{The covariance matrix of the rotated factors.} } \description{ Rotates a factor loading matrix to an errors-in-variables representation. } \details{ The loading matrix is rotated so that the \eqn{k}{k} rows indicated by \code{identity} form an identity matrix, with the remaining \eqn{M-k}{M-k} rows as free parameters. \eqn{\Phi}{Phi} is also free. The optimization is not iterative and does not use the gradient projection algorithm. The function can be used directly or passed to factor analysis functions like \code{\link[stats]{factanal}} via the \code{rotation} argument. Viewed as a rotation method it is oblique, with an explicit solution. Given an initial loadings matrix \eqn{L}{L} partitioned as \eqn{L = (L_1^T, L_2^T)^T}{L = rbind(L1, L2)}, the rotated loadings matrix is \eqn{(I, (L_2 L_1^{-1})^T)^T}{rbind(I, L2 \%*\% solve(L1))} and \eqn{\Phi = L_1 L_1^T}{Phi = L1 \%*\% t(L1)}, where \eqn{I}{I} is the \eqn{k \times k}{k x k} identity matrix. It is assumed that \eqn{\Phi = I}{Phi = I} for the initial loadings matrix. Not all authors consider this representation to be a rotation in the strict sense. This parameterization has several useful properties: \enumerate{ \item It can be useful for comparison with published results in this parameterization. \item Standard errors are more straightforward to compute because the solution corresponds to an unconstrained optimization. \item One may have prior knowledge about which reference variables load on only one factor without imposing restrictive constraints on other loadings --- in this sense it has similarities to CFA. \item For some purposes, only the subspace spanned by the factors matters, not the specific parameterization within this subspace. \item Back-predicted indicators (the explained portion of the indicators) do not depend on the rotation method. Combined with the greater ease of obtaining correct standard errors, this allows easier and more accurate prediction standard errors. } One use of this parameterization is obtaining good starting values for subsequent rotation, though it may seem counterintuitive to rotate towards this solution afterwards. } \examples{ data("WansbeekMeijer", package = "GPArotation") fa.unrotated <- factanal(factors = 2, covmat = NetherlandsTV, rotation = "none") # Direct call fa.eiv <- eiv(fa.unrotated$loadings) # Equivalent via factanal rotation argument fa.eiv2 <- factanal(factors = 2, covmat = NetherlandsTV, rotation = "eiv") # Compare unrotated, eiv, and factanal eiv loadings cbind(loadings(fa.unrotated), loadings(fa.eiv), loadings(fa.eiv2)) # Eiv rotation with a different identity set fa.eiv3 <- eiv(fa.unrotated$loadings, identity = 6:7) cbind(loadings(fa.unrotated), loadings(fa.eiv), loadings(fa.eiv3)) } \seealso{ \code{\link{echelon}}, \code{\link{rotations}}, \code{\link{GPForth}}, \code{\link{GPFoblq}} } \references{ \enc{Hägglund}{Haggland}, G. (1982). Factor analysis by instrumental variables methods. \emph{Psychometrika}, \bold{47}, 209--222. Lewin-Koh, S.C. and Amemiya, Y. (2003). Heteroscedastic factor analysis. \emph{Biometrika}, \bold{90}, 85--97. Wansbeek, T. and Meijer, E. (2000). \emph{Measurement Error and Latent Variables in Econometrics}. North-Holland. } \author{Erik Meijer and Paul Gilbert.} \concept{rotation} \keyword{multivariate} GPArotation/man/Random.Start.Rd0000644000176200001440000000475015164013620016023 0ustar liggesusers\encoding{UTF-8} \name{Random.Start} \alias{Random.Start} \title{Random Starting Matrix for Factor Rotation} \usage{ Random.Start(k = 2L) } \arguments{ \item{k}{a positive integer specifying the dimension of the square orthogonal matrix to generate (default 2).} } \description{ Generates a random orthogonal matrix for use as an initial rotation matrix (\code{Tmat}) in gradient projection rotation functions. } \value{ A \eqn{k \times k}{k x k} orthogonal matrix drawn uniformly from the Haar measure on the orthogonal group O(k). Columns have unit length and are mutually orthogonal. } \details{ The function generates a random orthogonal matrix using QR decomposition of a matrix of standard normal variates, with a sign correction applied to the diagonal of R to ensure uniform sampling from the Haar measure. This follows the approach of Stewart (1980) and Mezzadri (2007). The naive approach of \code{qr.Q(qr(matrix(rnorm(k*k), k)))} does not guarantee uniform sampling from the Haar measure. The sign correction \code{Q \%*\% diag(sign(diag(R)))} is required to achieve this. This was updated in GPArotation 2024.2-1 following a suggestion by Yves Rosseel. For oblique rotation a random starting transformation matrix can be generated by normalizing the columns of a random matrix: \code{X \%*\% diag(1/sqrt(diag(crossprod(X))))} where \code{X <- matrix(rnorm(k*k), k)}. } \examples{ # Generate a 5 x 5 random orthogonal matrix Random.Start(5) # Verify orthogonality: t(Q) %*% Q should be the identity matrix Q <- Random.Start(4) round(t(Q) \%*\% Q, 10) # Use as starting matrix for rotation data("Thurstone", package = "GPArotation") simplimax(box26, Tmat = Random.Start(3)) } \seealso{ \code{\link{GPFRSorth}}, \code{\link{GPFRSoblq}}, \code{\link{GPForth}}, \code{\link{GPFoblq}}, \code{\link{rotations}} } \references{ Stewart, G.W. (1980). The efficient generation of random orthogonal matrices with an application to condition estimators. \emph{SIAM Journal on Numerical Analysis}, \bold{17}(3), 403--409. doi: 10.1137/0717034 Mezzadri, F. (2007). How to generate random matrices from the classical compact groups. \emph{Notices of the American Mathematical Society}, \bold{54}(5), 592--604. arXiv:math-ph/0609050 } \author{Coen A. Bernaards and Robert I. Jennrich with some R modifications by Paul Gilbert. Updated following a suggestion by Yves Rosseel.} \concept{rotation} \keyword{multivariate}GPArotation/man/CCAI.Rd0000644000176200001440000001620515174241145014212 0ustar liggesusers\encoding{UTF-8} \name{CCAI} \docType{data} \alias{CCAI} \alias{CCAI_R} \alias{CCAI_pattern} \alias{CCAI_Phi} \title{The CCAI Climate-Friendly Purchasing Choices Domain} \description{ Correlation matrix, factor pattern matrix, and factor intercorrelations for the Climate Change Action Inventory (CCAI) Climate-Friendly Purchasing Choices domain, from Bi and Barchard (2024). The scale measures the frequency with which individuals make purchasing choices aimed at reducing climate change. Data were collected from 500 United States MTurk workers. After 15 climate change deniers and 24 multivariate outliers were removed, 461 participants remained. Climate change deniers were excluded because the scale measures behaviors intended to reduce climate change --- including individuals who do not believe climate change exists would be inconsistent with the measure's intent. } \usage{ data(CCAI) } \format{ Three objects are loaded by \code{data(CCAI)}: \itemize{ \item \code{CCAI_R}: a \eqn{14 \times 14}{14 x 14} numeric correlation matrix. Row and column names are item labels \code{CCAI1} through \code{CCAI14}, ordered by factor to match \code{CCAI_pattern}. \item \code{CCAI_pattern}: a \eqn{14 \times 3}{14 x 3} numeric matrix of factor pattern coefficients. Row names are item labels \code{CCAI1} through \code{CCAI14}, ordered by factor to facilitate interpretation. Column names are factor labels \code{SustainableOptions}, \code{CollectiveAction}, and \code{AvoidBuyingNew}. \item \code{CCAI_Phi}: a \eqn{3 \times 3}{3 x 3} numeric matrix of factor intercorrelations. Row and column names are the three factor labels. } } \details{ The CCAI Climate-Friendly Purchasing Choices domain consists of 14 items. Items used a nine-point frequency scale ranging from 1 (less than once a year) to 9 (at least 14 times a week). For full details on study design, data collection, analysis, and interpretation see Bi and Barchard (2024). The Climate Change Action Inventory contains eight domains; the Climate-Friendly Purchasing Choices domain analyzed here is one of them. \code{CCAI_R} is the observed \eqn{14 \times 14}{14 x 14} correlation matrix for the 14 items of the Climate-Friendly Purchasing Choices domain. The correlation matrix was kindly provided by the authors and has not been published separately. \code{CCAI_pattern} is a \eqn{14 \times 3}{14 x 3} factor pattern matrix from principal components extraction followed by direct oblimin rotation, reported in Table 2 of Bi and Barchard (2024) (the Table is labeled ``Factor Structure'' in the paper but contains pattern coefficients). The three factors are: Choosing Sustainable Options (F1), Supporting Collective Action (F2), and Avoiding Buying New (F3). \tabular{clrrr}{ Item \tab Description \tab F1 \tab F2 \tab F3 \cr CCAI8 \tab Choose products with less impact on climate change \tab .95 \tab .00 \tab -.02 \cr CCAI6 \tab Choose products with less packaging \tab .91 \tab -.04 \tab .01 \cr CCAI7 \tab Choose products made locally \tab .89 \tab -.09 \tab .07 \cr CCAI11 \tab Encourage others to choose climate-friendly products \tab .56 \tab .40 \tab .05 \cr CCAI12 \tab Problem solve to reduce impact of purchases \tab .52 \tab .44 \tab .04 \cr CCAI10 \tab Encourage others to buy less \tab .41 \tab .44 \tab .12 \cr CCAI14 \tab Give time/money to orgs reducing purchase impact \tab -.01 \tab .97 \tab -.02 \cr CCAI13 \tab Give time/money to orgs reducing purchases \tab .02 \tab .93 \tab .01 \cr CCAI5 \tab Donate to charity rather than buying a gift \tab -.02 \tab .78 \tab .20 \cr CCAI2 \tab Use borrowed/rented/digital rather than buying \tab -.02 \tab -.18 \tab .90 \cr CCAI4 \tab Buy used rather than new \tab .00 \tab .15 \tab .76 \cr CCAI1 \tab Repair rather than buying replacements \tab .03 \tab .06 \tab .76 \cr CCAI3 \tab Use borrowed/rented tools rather than buying \tab .10 \tab .21 \tab .62 \cr CCAI9 \tab Donate or sell old possessions \tab .22 \tab .27 \tab .46 \cr } \code{CCAI_Phi} is a \eqn{3 \times 3}{3 x 3} factor intercorrelation matrix. All three intercorrelations exceed 0.50. \tabular{lrrr}{ \tab F1 \tab F2 \tab F3 \cr Choosing Sustainable Options \tab 1.00 \tab 0.59 \tab 0.59 \cr Supporting Collective Action \tab 0.59 \tab 1.00 \tab 0.53 \cr Avoiding Buying New \tab 0.59 \tab 0.53 \tab 1.00 \cr } See \code{vignette("GPA3bifactor", package = "GPArotation")} for a bifactor analysis of these data. } \note{ The raw data are publicly available on the Open Science Framework. As the data are subject to a license, users should consult the OSF page for terms of use before using the raw data directly: \url{https://osf.io/h38yb/overview}. } \seealso{ \code{\link{rotations}}, \code{\link{bifactorT}}, \code{\link[base]{eigen}}, \code{\link[stats]{factanal}}, \code{\link{Harman}}, \code{\link{Thurstone}}, \code{\link{WansbeekMeijer}} } \references{ Barchard, K.A., Okagawa, K., Hoffman, C.K., and Odents, O. (2021). \emph{Climate Change Action Inventory.} Unpublished psychological test. Available from kim.barchard@unlv.edu. Bi, Y. and Barchard, K.A. (2024). Purchasing choices that reduce climate change: An exploratory factor analysis. \emph{Spectra Undergraduate Research Journal}, \bold{3}(2), 8--14. doi: 10.9741/2766-7227.1028. } \examples{ data(CCAI, package = "GPArotation") # Observed correlation matrix round(CCAI_R, 2) # Published pattern matrix and factor intercorrelations round(CCAI_pattern, 2) round(CCAI_Phi, 2) # Reproduce published analysis: PCA extraction via eigendecomposition # followed by direct oblimin rotation --- no additional packages # required. This gives the same result as psych:::principal used # by Bi and Barchard (2024). ev <- eigen(CCAI_R) k <- 3 L_unrotated <- ev$vectors[, 1:k] \%*\% diag(sqrt(ev$values[1:k])) rownames(L_unrotated) <- colnames(CCAI_R) res_oblimin <- oblimin(L_unrotated, randomStarts = 100) # print applies sorting --- capture the sorted result res_sorted <- print(res_oblimin) L_repro <- loadings(res_sorted) # Compare reproduced vs published side by side, alternating by factor comparison <- cbind(round(L_repro[, 1], 2), round(CCAI_pattern[, 1], 2), round(L_repro[, 2], 2), round(CCAI_pattern[, 2], 2), round(L_repro[, 3], 2), round(CCAI_pattern[, 3], 2)) colnames(comparison) <- c("F1.repro", "F1.pub", "F2.repro", "F2.pub", "F3.repro", "F3.pub") print(comparison) # Orthogonal bifactor rotation on observed correlation matrix using MLE extraction fa_unrotated <- factanal(factors = 3, covmat = CCAI_R, n.obs = 461, rotation = "none") bif <- bifactorT(loadings(fa_unrotated)) print(bif, sortLoadings = FALSE, digits = 3) } \keyword{datasets}GPArotation/man/Thurstone.Rd0000644000176200001440000000331315172572236015510 0ustar liggesusers\encoding{UTF-8} \name{Thurstone} \docType{data} \alias{Thurstone} \alias{box20} \alias{box26} \title{Thurstone Box Data} \description{ Factor loading matrices derived from Thurstone's box data, a classic dataset in factor analysis consisting of measurements of physical dimensions of a set of boxes. } \usage{ data(Thurstone) } \details{ Loading the data makes two objects available: \code{box26} is a \eqn{26 \times 3}{26 x 3} unrotated factor loading matrix for 26 variables measured on a set of boxes. This is the recommended matrix for use in examples and benchmarking. It appears frequently in the rotation literature as a benchmark dataset for comparing rotation criteria, particularly for assessing local minima. \code{box20} is a \eqn{20 \times 3}{20 x 3} unrotated factor loading matrix for 20 variables measured on the same set of boxes. \strong{Deprecated:} \code{box20} will be removed in a future version of \code{GPArotation}. Use \code{box26} instead. Both matrices are suitable as input to \code{GPForth}, \code{GPFoblq}, and all rotation wrapper functions in \code{GPArotation}. For a richer collection of factor analysis datasets, see the \code{psych} package. } \format{ Two numeric matrices: \itemize{ \item \code{box26}: 26 x 3 matrix of unrotated factor loadings (recommended). \item \code{box20}: 20 x 3 matrix of unrotated factor loadings (deprecated; use \code{box26} instead). } } \source{ Thurstone, L.L. (1947). \emph{Multiple Factor Analysis}. University of Chicago Press. } \seealso{ \code{\link{GPForth}}, \code{\link{rotations}}, \code{\link{Harman}}, \code{\link{CCAI}}, \code{\link{WansbeekMeijer}} } \keyword{datasets}GPArotation/man/WansbeekMeijer.Rd0000644000176200001440000000346315174017577016422 0ustar liggesusers\encoding{UTF-8} \name{WansbeekMeijer} \docType{data} \alias{WansbeekMeijer} \alias{NetherlandsTV} \title{Netherlands Television Viewership Data} \description{ Correlation matrix for Netherlands television viewership, used as an example dataset for factor rotation. From Wansbeek and Meijer (2000), page 171. } \usage{ data(WansbeekMeijer) } \details{ \code{NetherlandsTV} is a list with components \code{$cov} (a \eqn{7 \times 7}{7 x 7} correlation matrix for 7 television viewership variables measured in the Netherlands) and \code{$n.obs} (sample size, 2154). Use \code{cov2cor(NetherlandsTV\$cov)} to obtain the correlation matrix, or pass \code{NetherlandsTV} directly to \code{\link[stats]{factanal}} which handles the list structure automatically. It is used throughout the \code{GPArotation} documentation and vignettes as an example dataset for oblique rotation with 2 or 3 factors. } \format{ \code{NetherlandsTV} is a list with components: \itemize{ \item \code{$cov}: a \eqn{7 \times 7}{7 x 7} numeric correlation matrix \item \code{$n.obs}: sample size (2154) } } \source{ Wansbeek, T. and Meijer, E. (2000). \emph{Measurement Error and Latent Variables in Econometrics}. North-Holland. } \seealso{ \code{\link{GPForth}}, \code{\link{rotations}}, \code{\link{Thurstone}}, \code{\link{Harman}}, \code{\link{CCAI}} } \examples{ data(WansbeekMeijer, package = "GPArotation") # Correlation matrix round(cov2cor(NetherlandsTV$cov), 2) # factanal picks up n.obs automatically from the list factanal(factors = 2, covmat = NetherlandsTV, rotation = "none") # Two-step oblique rotation fa.unrotated <- factanal(factors = 3, covmat = NetherlandsTV, rotation = "none") oblimin(loadings(fa.unrotated), randomStarts = 100) } \keyword{datasets}GPArotation/man/NormalizingWeight.Rd0000644000176200001440000000551615174127354017164 0ustar liggesusers\encoding{UTF-8} \name{NormalizingWeight} \alias{NormalizingWeight} \title{Normalizing Weights for Factor Rotation} \usage{ NormalizingWeight(A, normalize=FALSE) } \arguments{ \item{A}{A factor loading matrix.} \item{normalize}{Indicates if and how the matrix should be normalized. If \code{FALSE} (default), no normalization is done. If \code{TRUE}, Kaiser normalization is applied. If a numeric vector of length \code{nrow(A)}, columns are divided by these weights before rotation and multiplied after. If a function, it should take \code{A} as its argument and return a numeric vector used as weights.} } \value{ A numeric vector of normalizing weights. This function is not exported from the NAMESPACE and is only called internally by the gradient projection rotation functions. See \code{\link{GPFRSorth}} for details on the \code{normalize} argument. } \description{ Internal utility function that computes normalizing weights for factor loading matrices prior to rotation. Called by \code{GPForth}, \code{GPFoblq}, and the random-start wrappers. } \details{ \code{NormalizingWeight} is not exported from the NAMESPACE and is called internally by \code{GPForth}, \code{GPFoblq}, and the random-start wrapper functions. For a full description of the \code{normalize} argument and its options, see \code{\link{GPFRSorth}}. The choice of normalization method can affect the rotation solution and its interpretation. For a detailed investigation of the effects of normalization on factor rotations, see Nguyen and Waller (2023). } \examples{ data("CCAI", package = "GPArotation") # Kaiser normalization factanal(factors = 3, covmat = CCAI_R, n.obs = 461, rotation = "oblimin", control = list(rotate = list(normalize = TRUE))) # Cureton-Mulaik normalization passed as a function. # May result in convergence problems. NormalizingWeightCM <- function(L) { Dk <- diag(sqrt(diag(L \%*\% t(L)))^-1) \%*\% L wghts <- rep(0, nrow(L)) fpls <- Dk[, 1] acosi <- acos(ncol(L)^(-1/2)) for (i in 1:nrow(L)) { num <- acosi - acos(abs(fpls[i])) dem <- acosi - (function(a, m) ifelse(abs(a) < (m^(-1/2)), pi/2, 0))(fpls[i], ncol(L)) wghts[i] <- cos(num / dem * pi/2)^2 + 0.001 } wghts * sqrt(diag(L \%*\% t(L)))^-1 } data(Harman, package = "GPArotation") quartimin(Harman8, normalize = NormalizingWeightCM(Harman8), randomStarts = 100) quartimin(Harman8, normalize = TRUE, randomStarts = 100) } \references{ Nguyen, H.V. and Waller, N.G. (2023). Local minima and factor rotations in exploratory factor analysis. \emph{Psychological Methods}, \bold{28}(5), 1122--1141. doi: 10.1037/met0000467 } \seealso{ \code{\link{GPFRSorth}}, \code{\link{GPForth}} } \keyword{internal}GPArotation/man/GPA.Rd0000644000176200001440000003715215174245016014127 0ustar liggesusers\encoding{UTF-8} \name{GPA} \alias{GPFRSorth} \alias{GPFRSoblq} \alias{GPForth} \alias{GPFoblq} \alias{GPForth.legacy} \alias{GPFoblq.legacy} \alias{.GPA_RS_engine} \title{Core Algorithms and Random-Start Wrappers} \usage{ GPForth(A, Tmat=diag(ncol(A)), normalize=FALSE, eps=1e-5, maxit=1000, method="varimax", methodArgs=NULL) GPFoblq(A, Tmat=diag(ncol(A)), normalize=FALSE, eps=1e-5, maxit=1000, method="quartimin", methodArgs=NULL) GPFRSorth(A, Tmat=diag(ncol(A)), normalize=FALSE, eps=1e-5, maxit=1000, method="varimax", methodArgs=NULL, randomStarts=0, ...) GPFRSoblq(A, Tmat=diag(ncol(A)), normalize=FALSE, eps=1e-5, maxit=1000, method="quartimin", methodArgs=NULL, randomStarts=0, ...) } \arguments{ \item{A}{initial factor loadings matrix for which the rotation criterion is to be optimized.} \item{Tmat}{initial rotation matrix.} \item{normalize}{see details.} \item{eps}{convergence is assumed when the norm of the gradient is smaller than \code{eps}.} \item{maxit}{maximum number of iterations allowed in the main loop.} \item{method}{rotation objective criterion.} \item{methodArgs}{a list of additional arguments passed to the rotation objective.} \item{randomStarts}{number of random starts (\code{GPFRSorth} and \code{GPFRSoblq} only).} \item{...}{additional arguments passed to \code{GPForth} or \code{GPFoblq}, such as \code{eps} and \code{maxit} when calling via \code{GPFRSorth} or \code{GPFRSoblq}.} } \value{ A \code{GPArotation} object which is a list with elements: \item{loadings}{The rotated loadings matrix, one column per factor. If random starts were requested, this is the solution with the lowest criterion value.} \item{Th}{The rotation matrix, satisfying \code{loadings \%*\% t(Th) = A} for orthogonal rotation and \code{loadings = A \%*\% solve(t(Th))} for oblique rotation.} \item{Table}{A matrix recording the iteration history: iteration number, criterion value, log10 of the gradient norm, and step size (alpha).} \item{method}{A string indicating the rotation criterion.} \item{orthogonal}{A logical indicating if the rotation is orthogonal.} \item{convergence}{A logical indicating if convergence was obtained.} \item{Phi}{\code{t(Th) \%*\% Th}, the covariance matrix of the rotated factors. Omitted (\code{NULL}) for orthogonal rotations.} \item{Gq}{The gradient of the criterion at the rotated loadings.} \item{randStartChar}{A named vector summarising random start results: \code{randomStarts}, \code{Converged}, \code{atMinimum}, \code{localMins}. Only present when \code{randomStarts > 1}.} } \description{ Gradient projection rotation optimization routines for orthogonal and oblique factor rotation. These functions can be used directly to rotate a loadings matrix, or indirectly through a rotation objective passed to a factor estimation routine such as \code{\link[stats]{factanal}}. } \details{ The \code{GPFRSorth} and \code{GPFRSoblq} functions serve as the primary user interfaces for orthogonal and oblique rotations, respectively. They act as wrappers for the core GP algorithms (\code{GPForth} for orthogonal rotation and \code{GPFoblq} for oblique rotation), extending them with the ability to perform multiple random starts. Any additional arguments provided to these wrappers are passed directly down to the underlying GP algorithms. While the wrappers are generally recommended, the core functions \code{GPForth} and \code{GPFoblq} can also be invoked directly. All of these functions require an initial loadings matrix, \code{A}, which fixes the equivalence class over which the optimization is performed. This matrix must be the solution to an orthogonal factor analysis problem, such as one obtained from \code{factanal} or another factor estimation routine. Mathematically, a general rotation of a matrix \code{A} is defined as \code{A \%*\% solve(t(Th))}. In the case of orthogonal rotation, the initial rotation matrix \code{Tmat} is orthonormal, which simplifies the rotation formula to \code{A \%*\% Th}. In all scenarios, the final rotation matrix \code{Th} is computed by the GP rotation algorithm. An accessible introduction to gradient projection algorithms for factor rotation is provided in Mansolf and Reise (2016). \subsection{The \code{normalize} argument}{ The \code{normalize} argument specifies whether and how the loadings matrix should be normalized prior to rotation, and subsequently denormalized after rotation. \itemize{ \item If \code{FALSE} (the default), no normalization is performed. \item If \code{TRUE}, Kaiser normalization is applied so that the squared row entries of the normalized matrix \code{A} sum to 1.0. This procedure is sometimes referred to as Horst normalization. \item If provided as a \strong{vector} (which must have a length equal to the number of indicators, i.e., the number of rows in \code{A}), the columns of \code{A} are divided by this vector before rotation and multiplied by it afterward. \item If provided as a \strong{function}, it can be used to apply a custom normalization scheme. The function must take \code{A} as an argument and return a vector, which is then applied in the same manner as the vector input described above. See \code{\link{NormalizingWeight}} for an example implementing Cureton-Mulaik normalization. } For a detailed investigation into how normalization affects factor rotations, including its potential impact on the qualitative interpretation of loadings, see Nguyen and Waller (2022). } \subsection{The \code{method} argument}{ The \code{method} argument takes a string specifying the rotation objective function. By default, oblique rotations use \code{"quartimin"}, while orthogonal rotations default to \code{"varimax"}. The package supports a comprehensive suite of rotation objectives: \code{"oblimin"}, \code{"quartimin"}, \code{"target"}, \code{"pst"}, \code{"oblimax"}, \code{"entropy"}, \code{"quartimax"}, \code{"Varimax"}, \code{"simplimax"}, \code{"bentler"}, \code{"tandemI"}, \code{"tandemII"}, \code{"geomin"}, \code{"cf"}, \code{"infomax"}, \code{"mccammon"}, \code{"bifactor"}, \code{"lp"}, and \code{"varimin"}. Internally, this string is prefixed with \code{"vgQ."} to invoke the actual calculation function (see \code{\link{vgQ}} for underlying mathematical details). It is important to note that several rotation criteria—specifically \code{"oblimin"}, \code{"target"}, \code{"pst"}, \code{"simplimax"}, \code{"geomin"}, \code{"cf"}, and \code{"lp"}—require one or more supplementary arguments. These additional arguments can be seamlessly passed via the \code{methodArgs} list in the wrapper functions. Default values and direct usage examples for these arguments can be found in the \code{\link{rotations}} documentation. } \subsection{The \code{randomStarts} argument}{ Because factor rotation criteria frequently suffer from local minima, trying multiple starting configurations can help identify a superior solution. The \code{randomStarts} argument, available exclusively in the \code{GPFRSorth} and \code{GPFRSoblq} wrappers, facilitates this robust search approach. \itemize{ \item By default, \code{randomStarts = 0}, which defaults to using the identity matrix as the initial rotation matrix \code{Tmat}. The initial rotation matrix \code{Tmat} can also be set by the user. \item Setting \code{randomStarts = 1} initializes \code{Tmat} with a single random matrix. \item Setting \code{randomStarts > 1} attempts multiple random starts and returns the rotated loadings matrix that achieved the lowest criterion value \code{f} across all attempts. Note that this returned solution is technically still a local minimum, and is not guaranteed to be the global minimum. Users are encouraged to review the random start diagnostics detailed in the package examples. } Under the hood, an internal, unexported engine named \code{.GPA_RS_engine} safely manages the random start loop, tracks convergence diagnostics, and handles factor correlation matrix naming. While the core algorithms \code{GPForth} and \code{GPFoblq} do not support the \code{randomStarts} argument directly, users can manually supply a single random initial rotation matrix to them using \code{Tmat = \link{Random.Start}(ncol(A))}. } \subsection{Legacy functions}{ The original implementations authored by Bernaards and Jennrich (2005) have been retained as \code{GPForth.legacy} and \code{GPFoblq.legacy}. These functions are kept purely for historical reference and backward compatibility for reproducibility. They are not exported into the package namespace, meaning they must be explicitly invoked using the triple-colon operator: \preformatted{ GPArotation:::GPForth.legacy(A, method = "varimax") GPArotation:::GPFoblq.legacy(A, method = "quartimin") } The results generated by these legacy functions should be numerically identical to those produced by the current implementations. You can see a direct comparison of this in the examples section. } } \seealso{ \code{\link{rotations}}, \code{\link{Random.Start}}, \code{\link[stats]{factanal}}, \code{\link{Harman8}}, \code{\link{box26}}, \code{\link{CCAI}}, \code{\link{NetherlandsTV}} } \examples{ # --- Basic rotation calls --- data(Harman, package = "GPArotation") # 8 physical variables quartimax(Harman8) # direct rotation call GPFRSorth(Harman8, method = "quartimax") # equivalent via wrapper GPFRSoblq(Harman8, method = "quartimin", normalize = TRUE) loadings(quartimin(Harman8, normalize = TRUE)) # extract loadings directly # --- Passing criterion arguments via methodArgs --- # Crawford-Ferguson family: kappa selects the criterion. # For box26: p = 26 variables, m = 3 factors. # Equamax: kappa = m / (2 * p) = 3 / 52 # Parsimax: kappa = (m - 1) / (p + m - 2) = 2 / 27 data(Thurstone, package = "GPArotation") # 26 variable box problem GPFRSoblq(box26, method = "cf", methodArgs = list(kappa = 3/52)) # Equamax GPFRSoblq(box26, method = "cf", methodArgs = list(kappa = 2/27)) # Parsimax # --- Two-step vs single-step factanal for oblique rotation --- # # The recommended approach for oblique rotation is the two-step procedure: # (1) obtain unrotated loadings from factanal, then # (2) rotate separately using GPArotation. # This gives full control over the rotation, including random starts. # # Prior to R 4.5.1, the single-step approach (rotation inside factanal) # had a bug in factor reordering after oblique rotation. This was reported # by Bernaards and others and fixed by the R core team in R 4.5.1. data("WansbeekMeijer", package = "GPArotation") # Step 1: unrotated 3-factor solution fa.unrotated <- factanal(factors = 3, covmat = NetherlandsTV, normalize = TRUE, rotation = "none") # Step 2: oblique Crawford-Ferguson rotation with kappa = 0.3 # (non-standard kappa, not corresponding to any named special case) set.seed(44) fa.cf <- cfQ(loadings(fa.unrotated), kappa = 0.3, normalize = TRUE, randomStarts = 100) fa.cf # Single-step via factanal - correct in R >= 4.5.1 if (getRversion() >= "4.5.1") { set.seed(44) fa.factanal <- factanal(factors = 3, covmat = NetherlandsTV, rotation = "cfQ", control = list(rotate = list(normalize = TRUE, kappa = 0.3, randomStarts = 100))) # The two approaches should agree after sorting fa.sorted <- print(fa.cf, sortLoadings = TRUE) cat("Maximum difference in loadings between two-step and single-step:\n") print(max(abs(abs(fa.sorted$loadings) - abs(fa.factanal$loadings)))) } else { cat("Single-step factanal oblique rotation requires R >= 4.5.1.\n") cat("Use the two-step procedure above for correct results.\n") } # --- Displaying rotation output --- origdigits <- options("digits") data("CCAI", package = "GPArotation") fa.unrotated <- factanal(factors = 3, covmat = CCAI_R, n.obs = 461, rotation = "none") res <- oblimin(loadings(fa.unrotated), gam = -0.5, randomStarts = 20) # gam = -0.5: more orthogonal than quartimin res # default print print(res) # equivalent to above print(res, Table = TRUE) # include iteration table print(res, rotateMat = TRUE) # include rotating matrix print(res, digits = 2) # rounded to 2 decimal places summary(res) # pattern and structure matrices for oblique rotation summary(res, Structure = FALSE) # pattern matrix only options(digits = origdigits$digits) # --- Random start diagnostics --- # When randomStarts > 1, the output includes randStartChar which summarizes # the random start results: # randomStarts : number of random starts attempted # Converged : number of starts that converged # atMinimum : number of starts at the same lowest minimum # localMins : number of distinct local minima found data(Thurstone, package = "GPArotation") res <- GPFRSoblq(box26, method = "geomin", normalize = TRUE, randomStarts = 50) res$randStartChar # --- Factor ordering --- # Raw GPArotation output is unsorted — factors may appear in any order # depending on the starting matrix. Use print() to obtain sorted loadings. # Once sorted, repeated calls to print() are stable. set.seed(334) xusl <- quartimin(Harman8, normalize = TRUE, randomStarts = 100) loadings(xusl) # unsorted raw output max(abs(print(xusl)$loadings - xusl$loadings)) == 0 # FALSE: print() reorders xsl <- print(xusl) # capture sorted result max(abs(print(xsl)$loadings - xsl$loadings)) == 0 # TRUE: already sorted # --- Normalization --- # Kaiser normalization data("CCAI", package = "GPArotation") fa.unrotated <- factanal(factors = 3, covmat = CCAI_R, n.obs = 461, rotation = "none") oblimin(loadings(fa.unrotated), normalize = TRUE, randomStarts = 100) # --- Legacy engine --- # Demonstrates numerical equivalence of current and legacy implementations. # The maximum absolute difference should be zero or at machine epsilon. data("Harman", package = "GPArotation") # Rotate using current engine res_new <- oblimin(Harman8) # Rotate using legacy engine res_legacy <- GPArotation:::GPFoblq.legacy(Harman8, method = "oblimin") # Numerically identical max(abs(loadings(res_new) - loadings(res_legacy))) } \author{Coen A. Bernaards and Robert I. Jennrich with some R modifications by Paul Gilbert} \references{ Bernaards, C.A. and Jennrich, R.I. (2005) Gradient Projection Algorithms and Software for Arbitrary Rotation Criteria in Factor Analysis. \emph{Educational and Psychological Measurement}, \bold{65}, 676--696. doi: 10.1177/0013164404272507 Jennrich, R.I. (2001). A simple general procedure for orthogonal rotation. \emph{Psychometrika}, \bold{66}, 289--306. doi: 10.1007/BF02294840 Jennrich, R.I. (2002). A simple general method for oblique rotation. \emph{Psychometrika}, \bold{67}, 7--19. doi: 10.1007/BF02294706 Mansolf, M., & Reise, S. P. (2016). Exploratory Bifactor Analysis: The Schmid-Leiman Orthogonalization and Jennrich-Bentler Analytic Rotations. \emph{Multivariate Behavioral Research}, \bold{51}(5), 698--717. doi: 10.1080/00273171.2016.1215898 Nguyen, H.V. and Waller, N.G. (2023). Local minima and factor rotations in exploratory factor analysis. \emph{ Psychological Methods}. \bold{28}(5), 1122--1141. doi: 10.1037/met0000467 } \concept{rotation} \keyword{multivariate} GPArotation/man/Harman.Rd0000644000176200001440000000316615174246316014730 0ustar liggesusers\encoding{UTF-8} \name{Harman} \docType{data} \alias{Harman} \alias{Harman8} \title{Harman's Eight Physical Variables} \description{ Unrotated factor loading matrix extracted by the centroid method for Harman's 8 physical variables, a classic dataset in factor analysis. } \usage{ data(Harman) } \details{ \code{Harman8} is a \eqn{8 \times 2}{8 x 2} matrix of unrotated factor loadings extracted by the centroid method (Table 14.3 in Harman, 1976) from the correlation matrix of 8 physical measurements taken on 305 girls (Table 2.3 in Harman, 1976). The centroid method was a standard extraction procedure before iterative methods became computationally feasible. The two columns represent unrotated centroid factors (\code{CF1} and \code{CF2}). Row names are the 8 variable names. The covariance matrix for these 8 physical variables is available in base R (see \code{\link[datasets]{Harman23.cor}}). } \format{ \code{Harman8}: a \eqn{8 \times 2}{8 x 2} numeric matrix of unrotated centroid factor loadings. Row names are variable names; column names are \code{CF1} and \code{CF2}. } \source{ Harman, H.H. (1976). \emph{Modern Factor Analysis} (3rd ed.). University of Chicago Press. } \seealso{ \code{\link[datasets]{Harman23.cor}}, \code{\link{GPForth}}, \code{\link{rotations}}, \code{\link{Thurstone}}, \code{\link{WansbeekMeijer}}, \code{\link{CCAI}} } \examples{ data(Harman, package = "GPArotation") # Centroid unrotated loadings from Harman (1976) Table 14.3 print(Harman8) # Rotate the centroid solution quartimax(Harman8) oblimin(Harman8, randomStarts = 100) } \keyword{datasets}GPArotation/man/echelon.Rd0000644000176200001440000001026415163643676015144 0ustar liggesusers\encoding{UTF-8} \name{echelon} \alias{echelon} \title{Echelon Rotation} \usage{ echelon(L, reference = seq(NCOL(L)), ...) } \arguments{ \item{L}{a factor loading matrix.} \item{reference}{integer vector indicating which rows of the loading matrix are used to determine the rotation transformation. Default uses the first \eqn{k}{k} rows. If the submatrix indicated by \code{reference} is singular, a different choice of rows must be supplied.} \item{...}{additional arguments discarded.} } \value{ A \code{GPArotation} object which is a list with elements: \item{loadings}{The rotated loadings matrix.} \item{Th}{The rotation matrix.} \item{method}{A string indicating the rotation method (\code{"echelon"}).} \item{orthogonal}{Always \code{TRUE} (an orthogonal solution is assumed; \eqn{\Phi}{Phi} is the identity matrix).} \item{convergence}{Always \code{TRUE} (the optimization is not iterative).} } \description{ Rotates a factor loading matrix to an echelon parameterization. } \details{ The loading matrix is rotated so that the \eqn{k}{k} rows indicated by \code{reference} form the Cholesky factorization given by \code{t(chol(L[reference,] \%*\% t(L[reference,])))}. This defines the rotation transformation, which is then applied to all rows to give the rotated loading matrix. The optimization is not iterative and does not use the gradient projection algorithm. The function can be used directly or passed to factor analysis functions like \code{\link[stats]{factanal}} via the \code{rotation} argument. This parameterization has several useful properties: \enumerate{ \item It can be useful for comparison with published results in this parameterization. \item Standard errors are more straightforward to compute because the solution corresponds to an unconstrained optimization. \item Models with \eqn{k}{k} and \eqn{k+1}{k+1} factors are nested, making it straightforward to test the \eqn{k}{k}-factor model versus the \eqn{(k+1)}{k+1}-factor model. In particular, the Wald test and LM test can be used in addition to the LR test. The test of a \eqn{k}{k}-factor model versus a \eqn{(k+1)}{k+1}-factor model is a joint test of whether all free parameters (loadings) in the \eqn{(k+1)}{k+1}st column are zero. \item For some purposes, only the subspace spanned by the factors matters, not the specific parameterization within this subspace. \item Back-predicted indicators (the explained portion of the indicators) do not depend on the rotation method. Combined with the greater ease of obtaining correct standard errors, this allows easier and more accurate prediction standard errors. \item This parameterization and its standard errors can be used to detect identification problems (McDonald, 1999, pp. 181--182). } One use of echelon rotation is obtaining good starting values for subsequent rotation, though it may seem counterintuitive to rotate towards this solution afterwards. } \examples{ data("WansbeekMeijer", package = "GPArotation") fa.unrotated <- factanal(factors = 2, covmat = NetherlandsTV, rotation = "none") # Direct call fa.ech <- echelon(fa.unrotated$loadings) # Equivalent via factanal rotation argument fa.ech2 <- factanal(factors = 2, covmat = NetherlandsTV, rotation = "echelon") # Compare unrotated, echelon, and factanal echelon loadings cbind(loadings(fa.unrotated), loadings(fa.ech), loadings(fa.ech2)) # Echelon rotation with a different reference set fa.ech3 <- echelon(fa.unrotated$loadings, reference = 6:7) cbind(loadings(fa.unrotated), loadings(fa.ech), loadings(fa.ech3)) } \seealso{ \code{\link{eiv}}, \code{\link{rotations}}, \code{\link{GPForth}}, \code{\link{GPFoblq}} } \references{ McDonald, R.P. (1999). \emph{Test Theory: A Unified Treatment}. Erlbaum. Wansbeek, T. and Meijer, E. (2000). \emph{Measurement Error and Latent Variables in Econometrics}. North-Holland. } \author{Erik Meijer and Paul Gilbert.} \concept{rotation} \keyword{multivariate}GPArotation/man/print.GPArotation.Rd0000644000176200001440000001016715172047270017037 0ustar liggesusers\encoding{UTF-8} \name{print.GPArotation} \alias{print.GPArotation} \alias{summary.GPArotation} \alias{print.summary.GPArotation} \alias{.sortGPALoadings} \title{Print and Summary Methods for GPArotation Class Objects} \usage{ \method{print}{GPArotation}(x, digits=3, sortLoadings=TRUE, rotateMat=FALSE, Table=FALSE, ...) \method{summary}{GPArotation}(object, digits=3, Structure=TRUE, ...) \method{print}{summary.GPArotation}(x, ...) } \arguments{ \item{x}{a \code{GPArotation} or \code{summary.GPArotation} object to print.} \item{object}{a \code{GPArotation} object to summarize.} \item{digits}{precision of printed numbers.} \item{sortLoadings}{logical; if \code{TRUE} (default) factors are sorted by descending variance explained and factor signs are adjusted so that the sum of loadings per factor is positive. Adapted from \code{factanal} sorting conventions. Use \code{sortLoadings = FALSE} to display the raw unsorted solution, for example when the factor order is meaningful as in bifactor rotation.} \item{rotateMat}{logical; if \code{TRUE} the rotation matrix is displayed.} \item{Table}{logical; if \code{TRUE} the iteration table is displayed.} \item{Structure}{logical; if \code{TRUE} (default) the structure matrix (\code{loadings \%*\% Phi}) is displayed for oblique rotations in \code{summary}.} \item{...}{further arguments passed to other methods.} } \value{ \code{print.GPArotation} returns the sorted \code{GPArotation} object invisibly when \code{sortLoadings = TRUE}, or the unsorted object when \code{sortLoadings = FALSE}. \code{summary.GPArotation} returns a \code{summary.GPArotation} object with sorted loadings and, for oblique rotations, the structure matrix. \code{print.summary.GPArotation} returns the object invisibly. } \description{ Print and summary methods for objects returned by \code{GPFRSorth}, \code{GPFRSoblq}, \code{GPForth}, or \code{GPFoblq}. Both \code{print.GPArotation} and \code{summary.GPArotation} apply consistent factor sorting and sign correction via the internal helper \code{.sortGPALoadings} when \code{sortLoadings = TRUE}. Factors are ordered by descending variance explained and signs are adjusted so that the sum of loadings per factor is positive. This convention matches that used by \code{\link[stats]{factanal}}. For oblique rotations, \code{summary.GPArotation} displays both the pattern matrix (regression coefficients of items on factors, controlling for factor intercorrelations) and the structure matrix (\code{loadings \%*\% Phi}, correlations between items and factors) when \code{Structure = TRUE}. The two matrices coincide for orthogonal rotations where \eqn{\Phi = I}{Phi = I}. Output includes contributions of factors via \code{SS loadings} (sum of squared loadings); see Harman (1976), sections 2.4 and 12.4. } \details{ Factor sorting and sign correction are applied consistently in both \code{print} and \code{summary} via the internal function \code{.sortGPALoadings}, adapted from \code{factanal} sorting conventions (R Core Team). This ensures that the pattern matrix shown by \code{summary} is consistent with the loadings shown by \code{print}. The \code{digits} argument controls the number of decimal places shown in the loadings, structure matrix, and Phi. For examples see \code{\link{GPFRSorth}} and the package vignettes: \code{vignette("GPA1guide", package = "GPArotation")}. } \references{ Harman, H.H. (1976). \emph{Modern Factor Analysis}. The University of Chicago Press. } \seealso{ \code{\link{GPFRSorth}}, \code{\link{GPForth}}, \code{\link[stats]{factanal}}, \code{\link[base]{summary}} } \examples{ data(Harman, package = "GPArotation") res <- oblimin(Harman8, normalize = TRUE, randomStarts = 100) # Print sorted loadings (default) print(res) # Print unsorted loadings print(res, sortLoadings = FALSE) # Summary with pattern and structure matrices summary(res, Structure = TRUE) # Summary without structure matrix summary(res, Structure = FALSE) # Print with iteration table print(res, Table = TRUE) } \concept{rotation} \keyword{multivariate}GPArotation/man/vgQ.Rd0000644000176200001440000001264215164010257014246 0ustar liggesusers\encoding{UTF-8} \name{vgQ} \alias{vgQ} \alias{vgQ.oblimin} \alias{vgQ.quartimin} \alias{vgQ.target} \alias{vgQ.pst} \alias{vgQ.oblimax} \alias{vgQ.entropy} \alias{vgQ.quartimax} \alias{vgQ.varimax} \alias{vgQ.simplimax} \alias{vgQ.bentler} \alias{vgQ.tandemI} \alias{vgQ.tandemII} \alias{vgQ.geomin} \alias{vgQ.bigeomin} \alias{vgQ.cf} \alias{vgQ.infomax} \alias{vgQ.mccammon} \alias{vgQ.bifactor} \alias{vgQ.varimin} \alias{vgQ.lp.wls} \title{Rotation Criteria: Value and Gradient Functions} \usage{ vgQ.oblimin(L, gam=0) vgQ.quartimin(L) vgQ.target(L, Target=NULL) vgQ.pst(L, W=NULL, Target=NULL) vgQ.oblimax(L) vgQ.entropy(L) vgQ.quartimax(L) vgQ.varimax(L) vgQ.simplimax(L, k=nrow(L)) vgQ.bentler(L) vgQ.tandemI(L) vgQ.tandemII(L) vgQ.geomin(L, delta=0.01) vgQ.bigeomin(L, delta=0.01) vgQ.cf(L, kappa=0) vgQ.infomax(L) vgQ.mccammon(L) vgQ.varimin(L) vgQ.bifactor(L) vgQ.lp.wls(L, W) } \arguments{ \item{L}{a factor loading matrix.} \item{gam}{0 = Quartimin, 0.5 = Biquartimin, 1 = Covarimin.} \item{Target}{rotation target matrix for objective calculation.} \item{W}{weight matrix; weighting of each element in target rotation (\code{vgQ.pst}) or in iterative reweighted least squares (\code{vgQ.lp.wls}).} \item{k}{number of near-zero loadings to target.} \item{delta}{small constant added to \eqn{\Lambda^2}{Lambda^2} for numerical stability in the objective calculation.} \item{kappa}{complexity weight for the Crawford-Ferguson family; see \code{\link{cfT}} for details.} } \value{A list with: \item{f}{The value of the rotation criterion at \code{L}.} \item{Gq}{The gradient of the criterion at \code{L}.} \item{Method}{A string indicating the criterion name.} } \description{ Rotation criterion functions that compute the value and gradient of the rotation objective Q. Not exported from the package NAMESPACE. } \details{ The \code{vgQ.*} functions are called internally by the gradient projection optimization routines and would typically not be used directly. They can be inspected using \code{:::}, for example: \code{GPArotation:::vgQ.oblimin}. The gradient projection algorithms are described in Bernaards and Jennrich (2005). The \code{T} or \code{Q} suffix on rotation function names should be omitted for the corresponding \code{vgQ.*} function. For example, \code{GPArotation:::vgQ.target} is the criterion used by both \code{targetT} and \code{targetQ}. \tabular{lll}{ \code{vgQ.oblimin} \tab orthogonal or oblique \tab oblimin family \cr \code{vgQ.quartimin} \tab oblique \tab oblimin with \code{gam = 0} \cr \code{vgQ.target} \tab orthogonal or oblique \tab target rotation \cr \code{vgQ.pst} \tab orthogonal or oblique \tab partially specified target rotation \cr \code{vgQ.oblimax} \tab oblique \tab maximizes overall kurtosis of loadings \cr \code{vgQ.entropy} \tab orthogonal \tab minimum entropy \cr \code{vgQ.quartimax} \tab orthogonal \tab maximizes variance of squared loadings within variables \cr \code{vgQ.varimax} \tab orthogonal \tab maximizes variance of squared loadings within factors \cr \code{vgQ.simplimax} \tab oblique \tab minimizes the k smallest squared loadings \cr \code{vgQ.bentler} \tab orthogonal or oblique \tab Bentler invariant pattern simplicity \cr \code{vgQ.tandemI} \tab orthogonal \tab Tandem principle I criterion \cr \code{vgQ.tandemII} \tab orthogonal \tab Tandem principle II criterion \cr \code{vgQ.geomin} \tab orthogonal or oblique \tab minimizes geometric mean of squared loadings \cr \code{vgQ.bigeomin} \tab orthogonal or oblique \tab geomin with a general factor in column 1 \cr \code{vgQ.cf} \tab orthogonal or oblique \tab Crawford-Ferguson family \cr \code{vgQ.infomax} \tab orthogonal or oblique \tab infomax information criterion \cr \code{vgQ.mccammon} \tab orthogonal \tab McCammon minimum entropy ratio \cr \code{vgQ.varimin} \tab orthogonal \tab varimin criterion \cr \code{vgQ.bifactor} \tab orthogonal or oblique \tab bifactor/biquartimin rotation \cr \code{vgQ.lp.wls} \tab orthogonal or oblique \tab iterative reweighted least squares for \eqn{L^p}{Lp} rotation \cr } See \code{\link{rotations}} for details on rotation arguments. New rotation criteria can be added by defining a function named \code{vgQ.newmethod}. The function takes \code{L} as its first argument, plus any additional arguments, and must return a list with elements \code{f}, \code{Gq}, and \code{Method}. Gradient projection \emph{without} derivatives can be performed using the \code{GPArotateDF} package; type \code{vignette("GPArotateDF", package = "GPArotation")} at the command line. } \examples{ GPArotation:::vgQ.oblimin } \seealso{ \code{\link{rotations}}, \code{\link{GPFRSorth}} } \references{ Bernaards, C.A. and Jennrich, R.I. (2005) Gradient Projection Algorithms and Software for Arbitrary Rotation Criteria in Factor Analysis. \emph{Educational and Psychological Measurement}, \bold{65}, 676--696. doi: 10.1177/0013164404272507 } \author{Coen A. Bernaards and Robert I. Jennrich with some R modifications by Paul Gilbert.} \concept{rotation} \keyword{multivariate}GPArotation/man/lp.Rd0000644000176200001440000001214715174240516014130 0ustar liggesusers\encoding{UTF-8} \name{lp} \alias{Lp rotation} \alias{GPForth.lp} \alias{GPFoblq.lp} \title{\eqn{L^p}{Lp} Rotation} \usage{ GPForth.lp(A, Tmat = diag(ncol(A)), p = 1, normalize = FALSE, eps = 1e-05, maxit = 10000, gpaiter = 5) GPFoblq.lp(A, Tmat = diag(ncol(A)), p = 1, normalize = FALSE, eps = 1e-05, maxit = 10000, gpaiter = 5) } \arguments{ \item{A}{Initial factor loadings matrix to be rotated.} \item{Tmat}{Initial rotation matrix.} \item{p}{Component-wise \eqn{L^p}{Lp} where 0 < p \eqn{\le}{<=} 1.} \item{normalize}{Not recommended for \eqn{L^p}{Lp} rotation.} \item{eps}{Convergence is assumed when the norm of the gradient is smaller than \code{eps}.} \item{maxit}{Maximum number of iterations allowed in the main loop.} \item{gpaiter}{Maximum iterations for the inner GPA rotation loop. The goal is to decrease the objective value, not fully optimize the inner loop. Warnings may appear but can be ignored if the main loop converges.} } \value{ A \code{GPArotation} object, which is a list containing: \item{loadings}{Rotated loadings matrix, with one column per factor.} \item{Th}{Rotation matrix, satisfying \code{loadings \%*\% t(Th) = A}.} \item{Table}{Data frame recording iteration details: iteration count, objective value, and elapsed time.} \item{method}{String indicating the rotation objective function.} \item{orthogonal}{Logical indicating whether the rotation is orthogonal.} \item{convergence}{Logical indicating whether convergence was achieved. Convergence is assessed element-wise using \code{eps} as tolerance.} \item{Phi}{Covariance matrix of rotated factors, \code{t(Th) \%*\% Th}.} } \description{ Performs \eqn{L^p}{Lp} rotation to obtain sparse factor loadings. } \details{ These functions optimize an \eqn{L^p}{Lp} rotation objective where \code{0 < p <= 1}. A smaller value of \code{p} promotes greater sparsity in the loading matrix but increases computational difficulty. For guidance on choosing \code{p}, see the Concluding Remarks in Liu et al. (2023). The user-facing wrapper functions \code{\link{lpT}} and \code{\link{lpQ}} provide random start functionality on top of \code{GPForth.lp} and \code{GPFoblq.lp} respectively, analogous to how \code{\link{GPFRSorth}} and \code{\link{GPFRSoblq}} wrap \code{GPForth} and \code{GPFoblq} for standard rotation criteria. For most users \code{lpT} and \code{lpQ} are the recommended entry points. Since the \eqn{L^p}{Lp} objective is nonsmooth, a different optimization method is required compared to smooth rotation criteria. \code{GPForth.lp} and \code{GPFoblq.lp} replace \code{GPForth} and \code{GPFoblq} for orthogonal and oblique \eqn{L^p}{Lp} rotations, respectively. The optimization uses an iterative reweighted least squares (IRLS) approach. The nonsmooth objective is approximated by a smooth weighted least squares function in the outer loop, which is then optimized using GPA in the inner loop (\code{gpaiter} controls the maximum inner iterations). Normalization is not recommended for \eqn{L^p}{Lp} rotation and may produce unexpected results. } \examples{ data("WansbeekMeijer", package = "GPArotation") fa.unrotated <- factanal(factors = 2, covmat = NetherlandsTV, rotation = "none") options(warn = -1) # Orthogonal rotation — single start fa.lpT1 <- GPForth.lp(loadings(fa.unrotated), p = 1) # Orthogonal rotation — 10 random starts fa.lpT <- lpT(loadings(fa.unrotated), Tmat = Random.Start(2), p = 1, randomStarts = 10) print(fa.lpT, digits = 5, sortLoadings = FALSE, Table = TRUE, rotateMat = TRUE) # Oblique rotation — single start fa.lpQ1 <- GPFoblq.lp(loadings(fa.unrotated), p = 1) # Oblique rotation — 10 random starts fa.lpQ <- lpQ(loadings(fa.unrotated), p = 1, randomStarts = 10) summary(fa.lpQ, Structure = TRUE) # Compare Lp (p=1), Lp (p=0.5), and Geomin oblique rotations set.seed(1020) fa.lpQ1 <- lpQ(loadings(fa.unrotated), p = 1, randomStarts = 10) fa.lpQ0.5 <- lpQ(loadings(fa.unrotated), p = 0.5, randomStarts = 10) fa.geo <- geominQ(loadings(fa.unrotated), randomStarts = 10) # With factor ordering using internal sortGPALoadings helper res <- round(cbind(GPArotation:::.sortGPALoadings(fa.lpQ1)$loadings, GPArotation:::.sortGPALoadings(fa.lpQ0.5)$loadings, GPArotation:::.sortGPALoadings(fa.geo)$loadings), 3) print(c("oblique -- Lp p=1 Lp p=0.5 Geomin")) print(res) # Without factor ordering res <- round(cbind(fa.lpQ1$loadings, fa.lpQ0.5$loadings, fa.geo$loadings), 3) print(c("oblique -- Lp p=1 Lp p=0.5 Geomin")) print(res) options(warn = 0) } \seealso{ \code{\link{lpT}}, \code{\link{lpQ}}, \code{\link{vgQ.lp.wls}} } \references{ Liu, X., Wallin, G., Chen, Y., and Moustaki, I. (2023). Rotation to sparse loadings using \eqn{L^p}{Lp} losses and related inference problems. \emph{Psychometrika}, \bold{88}(2), 527--553. doi: 10.1007/s11336-023-09911-y } \author{Xinyi Liu, with minor modifications for GPArotation by C. Bernaards.} \concept{rotation} \keyword{multivariate}GPArotation/man/rotations.Rd0000644000176200001440000003751415174242674015553 0ustar liggesusers\encoding{UTF-8} \name{rotations} \alias{rotations} \alias{oblimin} \alias{quartimin} \alias{targetT} \alias{targetQ} \alias{pstT} \alias{pstQ} \alias{oblimax} \alias{entropy} \alias{quartimax} \alias{Varimax} \alias{simplimax} \alias{bentlerT} \alias{bentlerQ} \alias{tandemI} \alias{tandemII} \alias{geominT} \alias{geominQ} \alias{bigeominT} \alias{bigeominQ} \alias{cfT} \alias{cfQ} \alias{equamax} \alias{parsimax} \alias{infomaxT} \alias{infomaxQ} \alias{mccammon} \alias{varimin} \alias{bifactorT} \alias{bifactorQ} \alias{lpT} \alias{lpQ} \title{Rotations Functions Using Gradient Projection Algorithms} \usage{ oblimin(A, Tmat=diag(ncol(A)), gam=0, normalize=FALSE, randomStarts=0, ...) quartimin(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...) targetT(A=NULL, Tmat=diag(ncol(A)), Target=NULL, normalize=FALSE, eps=1e-5, maxit=1000, randomStarts=0, L=NULL, ...) targetQ(A=NULL, Tmat=diag(ncol(A)), Target=NULL, normalize=FALSE, eps=1e-5, maxit=1000, randomStarts=0, L=NULL, ...) pstT(A=NULL, Tmat=diag(ncol(A)), W=NULL, Target=NULL, normalize=FALSE, eps=1e-5, maxit=1000, randomStarts=0, L=NULL, ...) pstQ(A=NULL, Tmat=diag(ncol(A)), W=NULL, Target=NULL, normalize=FALSE, eps=1e-5, maxit=1000, randomStarts=0, L=NULL, ...) oblimax(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...) entropy(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...) quartimax(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...) Varimax(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...) simplimax(A, Tmat=diag(ncol(A)), k=nrow(A), normalize=FALSE, randomStarts=0, ...) bentlerT(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...) bentlerQ(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...) tandemI(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...) tandemII(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...) geominT(A, Tmat=diag(ncol(A)), delta=0.01, normalize=FALSE, randomStarts=0, ...) geominQ(A, Tmat=diag(ncol(A)), delta=0.01, normalize=FALSE, randomStarts=0, ...) bigeominT(A, Tmat=diag(ncol(A)), delta=0.01, normalize=FALSE, randomStarts=0, ...) bigeominQ(A, Tmat=diag(ncol(A)), delta=0.01, normalize=FALSE, randomStarts=0, ...) cfT(A, Tmat=diag(ncol(A)), kappa=0, normalize=FALSE, randomStarts=0, ...) cfQ(A, Tmat=diag(ncol(A)), kappa=0, normalize=FALSE, randomStarts=0, ...) equamax(A, Tmat=diag(ncol(A)), kappa=ncol(A)/(2*nrow(A)), normalize=FALSE, randomStarts=0, ...) parsimax(A, Tmat=diag(ncol(A)), kappa=(ncol(A)-1)/(ncol(A)+nrow(A)-2), normalize=FALSE, randomStarts=0, ...) infomaxT(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...) infomaxQ(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...) mccammon(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...) varimin(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...) bifactorT(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...) bifactorQ(A, Tmat=diag(ncol(A)), normalize=FALSE, randomStarts=0, ...) lpT(A, Tmat=diag(ncol(A)), p=1, normalize=FALSE, eps=1e-05, maxit=1000, randomStarts=0, gpaiter=5) lpQ(A, Tmat=diag(ncol(A)), p=1, normalize=FALSE, eps=1e-05, maxit=1000, randomStarts=0, gpaiter=5) } \arguments{ \item{A}{an initial loadings matrix to be rotated.} \item{Tmat}{initial rotation matrix.} \item{gam}{Obliqueness parameter (\eqn{\gamma} in the mathematical definition). 0=Quartimin, .5=Biquartimin, 1=Covarimin.} \item{Target}{rotation target for objective calculation.} \item{W}{weighting of each element in target.} \item{k}{number of close to zero loadings.} \item{delta}{constant added to \eqn{\Lambda^2}{Lambda^2} in the objective calculation.} \item{kappa}{see details.} \item{normalize}{parameter passed to optimization routine (GPForth or GPFoblq).} \item{eps}{convergence tolerance passed to \code{GPForth} or \code{GPFoblq} via \code{...}. Convergence is assumed when the norm of the gradient is smaller than \code{eps}. Default is \code{1e-5}.} \item{maxit}{maximum number of iterations passed to \code{GPForth} or \code{GPFoblq} via \code{...}. Default is \code{1000}.} \item{...}{additional arguments passed to \code{GPForth} or \code{GPFoblq}, including \code{eps} and \code{maxit}.} \item{randomStarts}{parameter passed to optimization routine (GPFRSorth or GPFRSoblq).} \item{L}{provided for backward compatibility in target rotations only. Use A going forward.} \item{p}{Component-wise \eqn{L^p}{Lp}, where 0 < p \eqn{=<}{=<} 1. } \item{gpaiter}{Maximum iterations for GPA rotation loop in \eqn{L^p}{Lp} rotation.} } \value{ A \code{GPArotation} object which is a list with elements: \item{loadings}{The rotated loadings matrix, one column per factor. If random starts were requested, this is the solution with the lowest criterion value.} \item{Th}{The rotation matrix, satisfying \code{loadings \%*\% t(Th) = A} for orthogonal rotation and \code{loadings = A \%*\% solve(t(Th))} for oblique rotation.} \item{Table}{A matrix recording the iteration history: iteration number, criterion value, log10 of the gradient norm, and step size (alpha).} \item{method}{A string indicating the rotation criterion.} \item{orthogonal}{A logical indicating if the rotation is orthogonal.} \item{convergence}{A logical indicating if convergence was obtained.} \item{Phi}{\code{t(Th) \%*\% Th}, the covariance matrix of the rotated factors. Omitted (\code{NULL}) for orthogonal rotations.} \item{Gq}{The gradient of the criterion at the rotated loadings.} \item{randStartChar}{A named vector summarising random start results: \code{randomStarts}, \code{Converged}, \code{atMinimum}, \code{localMins}. Only present when \code{randomStarts > 1}.} } \description{ Optimize factor loading rotation objective. } \details{ These functions optimize a rotation objective. They can be used directly or the function name can be passed to factor analysis functions like \code{factanal}. Several of the function names end in T or Q, which indicates if they are orthogonal or oblique rotations (using \code{GPFRSorth} or \code{GPFRSoblq} respectively). The gradient projection algorithms are described in Bernaards and Jennrich (2005). \tabular{lll}{ \code{oblimin} \tab oblique \tab oblimin family; \code{gam} controls obliqueness \cr \code{quartimin} \tab oblique \tab oblimin with \code{gam = 0} \cr \code{targetT} \tab orthogonal \tab rotation towards a target matrix \cr \code{targetQ} \tab oblique \tab rotation towards a target matrix \cr \code{pstT} \tab orthogonal \tab partially specified target rotation \cr \code{pstQ} \tab oblique \tab partially specified target rotation \cr \code{oblimax} \tab oblique \tab maximizes overall kurtosis of loadings \cr \code{entropy} \tab orthogonal \tab minimizes entropy of squared loadings \cr \code{quartimax} \tab orthogonal \tab maximizes variance of squared loadings within variables \cr \code{Varimax} \tab orthogonal \tab maximizes variance of squared loadings within factors \cr \code{simplimax} \tab oblique \tab minimizes the k smallest squared loadings \cr \code{bentlerT} \tab orthogonal \tab invariant pattern simplicity \cr \code{bentlerQ} \tab oblique \tab invariant pattern simplicity \cr \code{tandemI} \tab orthogonal \tab factors share high loadings on same variables \cr \code{tandemII} \tab orthogonal \tab factors do not share high loadings on same variables \cr \code{geominT} \tab orthogonal \tab minimizes geometric mean of squared loadings \cr \code{geominQ} \tab oblique \tab minimizes geometric mean of squared loadings \cr \code{bigeominT} \tab orthogonal \tab geomin with a general factor in column 1 \cr \code{bigeominQ} \tab oblique \tab geomin with a general factor in column 1 \cr \code{cfT} \tab orthogonal \tab Crawford-Ferguson family; \code{kappa} controls complexity \cr \code{cfQ} \tab oblique \tab Crawford-Ferguson family; \code{kappa} controls complexity \cr \code{equamax} \tab orthogonal \tab Crawford-Ferguson with \code{kappa = m/(2p)} \cr \code{parsimax} \tab orthogonal \tab Crawford-Ferguson with \code{kappa = (m-1)/(p+m-2)} \cr \code{infomaxT} \tab orthogonal \tab infomax information criterion \cr \code{infomaxQ} \tab oblique \tab infomax information criterion \cr \code{mccammon} \tab orthogonal \tab minimizes entropy ratio across factors \cr \code{varimin} \tab orthogonal \tab minimizes variance of squared loadings within factors \cr \code{bifactorT} \tab orthogonal \tab bifactor; general factor in column 1 \cr \code{bifactorQ} \tab oblique \tab biquartimin; general factor in column 1 \cr \code{lpT} \tab orthogonal \tab \eqn{L^p}{Lp} sparsity rotation \cr \code{lpQ} \tab oblique \tab \eqn{L^p}{Lp} sparsity rotation \cr } The \code{Varimax} implementation in the list uses the gradient projection algorithm applied to \code{vgQ.varimax}. This implementation is different that the \code{varimax} rotation defined in the \code{stats} package. Additionally, \code{varimax} does Kaiser normalization by default whereas \code{GPArotation::Varimax} does not. The argument \code{kappa} parameterizes the family for the Crawford-Ferguson method. If \code{m} is the number of factors and \code{p} is the number of indicators then \code{kappa} values having special names are \eqn{0=}{0=}Quartimax, \eqn{1/p=}{1/p=}Varimax, \eqn{m/(2*p)=}{m/(2*p)=}Equamax, \eqn{(m-1)/(p+m-2)=}{(m-1)/(p+m-2)=}Parsimax, \eqn{1=}{1=}Factor parsimony. Bifactor rotations, bifactorT and bifactorQ are called bifactor and biquartimin in Jennrich and Bentler (2011). For a comparison of exploratory bifactor analysis algorithms including those implemented here, see Garcia-Garzon, Abad and Garrido (2021). The argument \code{p} is needed for \eqn{L^p}{Lp} rotation. See \link{Lp rotation} for details on the rotation method. } \examples{ # For extended examples see the vignettes: # vignette("GPA1guide", package = "GPArotation") # vignette("GPA2local", package = "GPArotation") # vignette("GPA3bifactor", package = "GPArotation") # --- Accessing rotated loadings --- data("Harman", package = "GPArotation") # 8 physical variables qHarman <- quartimax(Harman8) loadings(qHarman) # via extractor (recommended) qHarman$loadings # via direct list access all.equal(loadings(qHarman), qHarman$loadings) # identical # --- Rotating factanal loadings --- data("WansbeekMeijer", package = "GPArotation") # Netherlands TV viewership fa.unrotated <- factanal(factors = 2, covmat = NetherlandsTV, normalize = TRUE, rotation = "none") quartimax(loadings(fa.unrotated), normalize = TRUE) geominQ(loadings(fa.unrotated), normalize = TRUE, randomStarts = 100) # --- Passing rotation to factanal --- # CCAI:Climate-Friendly Purchasing Choices domain of the Climate Change Action Inventory data("CCAI", package = "GPArotation") factanal(factors = 3, covmat = CCAI_R, n.obs = 461, rotation = "infomaxT") factanal(factors = 3, covmat = CCAI_R, n.obs = 461, rotation = "infomaxT", control = list(rotate = list(normalize = TRUE, eps = 1e-6))) # --- Target rotation --- # Orthogonal target rotation of two varimax rotated matrices # towards each other. Data from Fischer and Fontaine (2010). # See vignette("GPA1guide", package = "GPArotation") for further analyses. trBritain <- matrix(c(.783, -.163, .811, .202, .724, .209, .850, .064, -.031, .592, -.028, .723, .388, .434, .141, .808, .215, .709), byrow = TRUE, ncol = 2) trGermany <- matrix(c(.778, -.066, .875, .081, .751, .079, .739, .092, .195, .574, -.030, .807, -.135, .717, .125, .738, .060, .691), byrow = TRUE, ncol = 2) trx <- targetT(trGermany, Target = trBritain) round(trx$loadings - trBritain, 3) # difference from target # --- Partially specified target rotation --- # See vignette("GPA1guide", package = "GPArotation") for full context. # Unrotated loadings matrix A and partially specified target SPA # NA entries in SPA are unspecified --- rotation is free there # Numeric entries are the target values the rotation aims towards A <- matrix(c(.664, .688, .492, .837, .705, .82, .661, .457, .765, .322, .248, .304, -0.291, -0.314, -0.377, .397, .294, .428, -0.075, .192, .224, .037, .155, -.104, .077, -.488, .009), ncol = 3) SPA <- matrix(c(rep(NA, 6), .7, .0, .7, rep(0, 3), rep(NA, 7), 0, 0, NA, 0, rep(NA, 4)), ncol = 3) comparison <- cbind(round(A, 3), rep(NA, nrow(A)), SPA) colnames(comparison) <- c("A.F1", "A.F2", "A.F3", "|", "T.F1", "T.F2", "T.F3") cat("Unrotated loadings (A) and partially specified target (SPA):\n") print(comparison, na.print = "NA") targetT(A, Target = SPA) # --- Random starts --- # CCAI Climate-Friendly Purchasing Choices domain, 14 items, 3 oblique factors. # High factor intercorrelations make oblimin the natural choice. # Note: factanal uses MLE extraction; results differ somewhat from # PCA-based extraction used in Bi and Barchard (2024). data("CCAI", package = "GPArotation") fa.unrotated <- factanal(factors = 3, covmat = CCAI_R, n.obs = 461, rotation = "none") oblimin(loadings(fa.unrotated), Tmat = Random.Start(3)) # single random start oblimin(loadings(fa.unrotated), randomStarts = 1) # equivalent oblimin(loadings(fa.unrotated), randomStarts = 100) # multiple starts # Directly via factanal call factanal(factors = 3, covmat = CCAI_R, n.obs = 461, rotation = "oblimin", control = list(rotate = list(normalize = TRUE, gam = -0.1, randomStarts = 100))) # --- Assessing local minima --- # For detailed investigation of local minima across all random starts # see vignette("GPA2local", package = "GPArotation"). data(Thurstone, package = "GPArotation") infomaxQ(box26, normalize = TRUE, randomStarts = 150) geominQ(box26, normalize = TRUE, randomStarts = 150) } \seealso{ \code{\link[stats]{factanal}}, \code{\link{GPFRSorth}}, \code{\link{GPFRSoblq}}, \code{\link{vgQ}}, \code{\link{Harman8}}, \code{\link{NetherlandsTV}}, \code{\link{CCAI}}, \code{\link{box26}} } \references{ Bernaards, C.A. and Jennrich, R.I. (2005) Gradient Projection Algorithms and Software for Arbitrary Rotation Criteria in Factor Analysis. \emph{Educational and Psychological Measurement}, \bold{65}, 676--696. doi: 10.1177/0013164404272507 Bi, Y. and Barchard, K.A. (2024). Purchasing choices that reduce climate change: An exploratory factor analysis. \emph{Spectra Undergraduate Research Journal}, \bold{3}(2), 8--14. doi: 10.9741/2766-7227.1028. Fischer, R., & Fontaine, J. (2010). Methods for investigating structural equivalence. In D. Matsumoto & F. van de Vijver (Eds.), Cross-Cultural Research Methods in Psychology (pp. 179--215). Cambridge University Press. doi: 10.1017/CBO9780511779381.010 Garcia-Garzon, E., Abad, F.J. and Garrido, L.E. (2021). On omega hierarchical estimation: A comparison of exploratory bi-factor analysis algorithms. \emph{Multivariate Behavioral Research}, \bold{56}(1), 101--119. doi: 10.1080/00273171.2020.1736977 Jennrich, R.I. and Bentler, P.M. (2011). Exploratory bi-factor analysis. \emph{Psychometrika}, \bold{76}(4), 537--549. doi: 10.1007/s11336-011-9218-4 For references to individual rotation criteria see \code{vignette("GPA1guide", package = "GPArotation")}. } \author{Coen A. Bernaards and Robert I. Jennrich with some R modifications by Paul Gilbert.} \concept{rotation} \keyword{multivariate} GPArotation/DESCRIPTION0000644000176200001440000000212015174331613014146 0ustar liggesusersPackage: GPArotation Version: 2026.4-1 Title: Gradient Projection Factor Rotation Authors@R: c( person("Coen", "Bernaards", email = "cab.gparotation@gmail.com", role = c("aut", "cre")), person("Paul", "Gilbert", role = "aut"), person("Robert", "Jennrich", role = "aut") ) Depends: R (>= 3.5.0) Description: Gradient projection algorithms for orthogonal and oblique rotation of factor loadings matrices in factor analysis. Implements a comprehensive set of rotation criteria including quartimax, quartimin, oblimin, geomin, simplimax, the Crawford-Ferguson family, and target rotation, among others. Supports multiple random starts. For details see Bernaards and Jennrich (2005) . License: GPL (>= 2) URL: https://cran.r-project.org/package=GPArotation Imports: stats LazyData: yes NeedsCompilation: no Packaged: 2026-04-29 00:32:08 UTC; coen Author: Coen Bernaards [aut, cre], Paul Gilbert [aut], Robert Jennrich [aut] Maintainer: Coen Bernaards Repository: CRAN Date/Publication: 2026-04-29 07:30:19 UTC