dimRed/0000755000176200001440000000000014263015046011457 5ustar liggesusersdimRed/NAMESPACE0000644000176200001440000000453514255350572012714 0ustar liggesusers# Generated by roxygen2: do not edit by hand export(AUC_lnK_R_NX) export(AutoEncoder) export(DRR) export(DiffusionMaps) export(DrL) export(FastICA) export(FruchtermanReingold) export(HLLE) export(Isomap) export(KamadaKawai) export(LCMC) export(LaplacianEigenmaps) export(MDS) export(NNMF) export(PCA) export(PCA_L1) export(Q_NX) export(Q_global) export(Q_local) export(R_NX) export(UMAP) export(dataSetList) export(dimRedData) export(dimRedMethodList) export(dimRedQualityList) export(dimRedResult) export(distance_correlation) export(embed) export(getRotationMatrix) export(installSuggests) export(inverse) export(kPCA) export(loadDataSet) export(mean_R_NX) export(mixColor1Ramps) export(mixColor2Ramps) export(mixColor3Ramps) export(mixColorRamps) export(nMDS) export(plot) export(plot_R_NX) export(predict) export(quality) export(reconstruction_error) export(reconstruction_rmse) export(tSNE) export(total_correlation) exportClasses(AutoEncoder) exportClasses(DRR) exportClasses(DiffusionMaps) exportClasses(DrL) exportClasses(FastICA) exportClasses(FruchtermanReingold) exportClasses(HLLE) exportClasses(Isomap) exportClasses(KamadaKawai) exportClasses(LaplacianEigenmaps) exportClasses(MDS) exportClasses(NNMF) exportClasses(PCA) exportClasses(PCA_L1) exportClasses(UMAP) exportClasses(dimRedData) exportClasses(dimRedMethod) exportClasses(dimRedResult) exportClasses(kPCA) exportClasses(nMDS) exportClasses(tSNE) exportMethods("[") exportMethods(AUC_lnK_R_NX) exportMethods(LCMC) exportMethods(Q_NX) exportMethods(Q_global) exportMethods(Q_local) exportMethods(R_NX) exportMethods(as.data.frame) exportMethods(as.dimRedData) exportMethods(cophenetic_correlation) exportMethods(distance_correlation) exportMethods(embed) exportMethods(getData) exportMethods(getDimRedData) exportMethods(getMeta) exportMethods(getNDim) exportMethods(getOrgData) exportMethods(getOtherData) exportMethods(getPars) exportMethods(inverse) exportMethods(maximize_correlation) exportMethods(mean_R_NX) exportMethods(ndims) exportMethods(nrow) exportMethods(plot) exportMethods(predict) exportMethods(print) exportMethods(quality) exportMethods(reconstruction_error) exportMethods(reconstruction_rmse) exportMethods(total_correlation) import(DRR) import(methods) import(utils) importFrom(grDevices,colorRamp) importFrom(grDevices,rgb) importFrom(graphics,plot) importFrom(magrittr,"%>%") importFrom(stats,predict) dimRed/LICENSE0000644000176200001440000007674512772463050012514 0ustar liggesusersGNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright © 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. “This License” refers to version 3 of the GNU General Public License. “Copyright” also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. “The Program” refers to any copyrightable work licensed under this License. Each licensee is addressed as “you”. “Licensees” and “recipients” may be individuals or organizations. To “modify” a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a “modified version” of the earlier work or a work “based on” the earlier work. A “covered work” means either the unmodified Program or a work based on the Program. To “propagate” a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To “convey” a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays “Appropriate Legal Notices” to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The “source code” for a work means the preferred form of the work for making modifications to it. “Object code” means any non-source form of a work. A “Standard Interface” means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The “System Libraries” of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A “Major Component”, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The “Corresponding Source” for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to “keep intact all notices”. c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an “aggregate” if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A “User Product” is either (1) a “consumer product”, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, “normally used” refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. “Installation Information” for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. “Additional permissions” are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered “further restrictions” within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An “entity transaction” is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A “contributor” is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's “contributor version”. A contributor's “essential patent claims” are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, “control” includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a “patent license” is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To “grant” such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. “Knowingly relying” means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is “discriminatory” if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License “or any later version” applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16.Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.dimRed/man/0000755000176200001440000000000014255350573012242 5ustar liggesusersdimRed/man/R_NX-dimRedResult-method.Rd0000644000176200001440000000244014255350573017216 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/quality.R \name{R_NX,dimRedResult-method} \alias{R_NX,dimRedResult-method} \alias{R_NX} \title{Method R_NX} \usage{ \S4method{R_NX}{dimRedResult}(object, ndim = getNDim(object)) } \arguments{ \item{object}{of class dimRedResult} \item{ndim}{the number of dimensions to take from the embedded data.} } \description{ Calculate the R_NX score from Lee et. al. (2013) which shows the neighborhood preservation for the Kth nearest neighbors, corrected for random point distributions and scaled to range [0, 1]. } \seealso{ Other Quality scores for dimensionality reduction: \code{\link{AUC_lnK_R_NX,dimRedResult-method}}, \code{\link{LCMC,dimRedResult-method}}, \code{\link{Q_NX,dimRedResult-method}}, \code{\link{Q_global,dimRedResult-method}}, \code{\link{Q_local,dimRedResult-method}}, \code{\link{cophenetic_correlation,dimRedResult-method}}, \code{\link{distance_correlation,dimRedResult-method}}, \code{\link{mean_R_NX,dimRedResult-method}}, \code{\link{plot_R_NX}()}, \code{\link{quality,dimRedResult-method}}, \code{\link{reconstruction_error,dimRedResult-method}}, \code{\link{reconstruction_rmse,dimRedResult-method}}, \code{\link{total_correlation,dimRedResult-method}} } \concept{Quality scores for dimensionality reduction} dimRed/man/Isomap-class.Rd0000644000176200001440000000577314262545547015105 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/isomap.R \docType{class} \name{Isomap-class} \alias{Isomap-class} \alias{Isomap} \title{Isomap embedding} \description{ An S4 Class implementing the Isomap Algorithm } \details{ The Isomap algorithm approximates a manifold using geodesic distances on a k nearest neighbor graph. Then classical scaling is performed on the resulting distance matrix. } \section{Slots}{ \describe{ \item{\code{fun}}{A function that does the embedding and returns a dimRedResult object.} \item{\code{stdpars}}{The standard parameters for the function.} }} \section{General usage}{ Dimensionality reduction methods are S4 Classes that either be used directly, in which case they have to be initialized and a full list with parameters has to be handed to the \code{@fun()} slot, or the method name be passed to the embed function and parameters can be given to the \code{...}, in which case missing parameters will be replaced by the ones in the \code{@stdpars}. } \section{Parameters}{ Isomap can take the following parameters: \describe{ \item{knn}{The number of nearest neighbors in the graph. Defaults to 50.} \item{ndim}{The number of embedding dimensions, defaults to 2.} \item{get_geod}{Should the geodesic distance matrix be kept, if \code{TRUE}, access it as \code{getOtherData(x)$geod}} } } \section{Implementation}{ The dimRed package uses its own implementation of Isomap which also comes with an out of sample extension (known as landmark Isomap). The default Isomap algorithm scales computationally not very well, the implementation here uses \code{\link[RANN]{nn2}} for a faster search of the nearest neighbors. If data are too large it may be useful to fit a subsample of the data and use the out-of-sample extension for the other points. } \examples{ if(requireNamespace(c("RSpectra", "igraph", "RANN"), quietly = TRUE)) { dat <- loadDataSet("3D S Curve", n = 500) emb <- embed(dat, "Isomap", knn = 10) plot(emb) ## or simpler, use embed(): samp <- sample(nrow(dat), size = 200) emb2 <- embed(dat[samp], "Isomap", .mute = NULL, knn = 10) emb3 <- predict(emb2, dat[-samp]) plot(emb2, type = "2vars") plot(emb3, type = "2vars") } } \references{ Tenenbaum, J.B., Silva, V. de, Langford, J.C., 2000. A Global Geometric Framework for Nonlinear Dimensionality Reduction. Science 290, 2319-2323. https://doi.org/10.1126/science.290.5500.2319 } \seealso{ Other dimensionality reduction methods: \code{\link{AutoEncoder-class}}, \code{\link{DRR-class}}, \code{\link{DiffusionMaps-class}}, \code{\link{DrL-class}}, \code{\link{FastICA-class}}, \code{\link{FruchtermanReingold-class}}, \code{\link{HLLE-class}}, \code{\link{KamadaKawai-class}}, \code{\link{MDS-class}}, \code{\link{NNMF-class}}, \code{\link{PCA-class}}, \code{\link{PCA_L1-class}}, \code{\link{UMAP-class}}, \code{\link{dimRedMethod-class}}, \code{\link{dimRedMethodList}()}, \code{\link{kPCA-class}}, \code{\link{nMDS-class}}, \code{\link{tSNE-class}} } \concept{dimensionality reduction methods} dimRed/man/AutoEncoder-class.Rd0000644000176200001440000001243214255350572016045 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/autoencoder.R \docType{class} \name{AutoEncoder-class} \alias{AutoEncoder-class} \alias{AutoEncoder} \title{AutoEncoder} \description{ An S4 Class implementing an Autoencoder } \details{ Autoencoders are neural networks that try to reproduce their input. Consider this method unstable, as the internals may still be changed. } \section{Slots}{ \describe{ \item{\code{fun}}{A function that does the embedding and returns a dimRedResult object.} \item{\code{stdpars}}{The standard parameters for the function.} }} \section{General usage}{ Dimensionality reduction methods are S4 Classes that either be used directly, in which case they have to be initialized and a full list with parameters has to be handed to the \code{@fun()} slot, or the method name be passed to the embed function and parameters can be given to the \code{...}, in which case missing parameters will be replaced by the ones in the \code{@stdpars}. } \section{Parameters}{ Autoencoder can take the following parameters: \describe{ \item{ndim}{The number of dimensions for reduction.} \item{n_hidden}{The number of neurons in the hidden layers, the length specifies the number of layers, the length must be impair, the middle number must be the same as ndim.} \item{activation}{The activation functions for the layers, one of "tanh", "sigmoid", "relu", "elu", everything else will silently be ignored and there will be no activation function for the layer.} \item{weight_decay}{the coefficient for weight decay, set to 0 if no weight decay desired.} \item{learning_rate}{The learning rate for gradient descend} \item{graph}{Optional: A list of bits and pieces that define the autoencoder in tensorflow, see details.} \item{keras_graph}{Optional: A list of keras layers that define the encoder and decoder, specifying this, will ignore all other topology related variables, see details.} \item{batchsize}{If NA, all data will be used for training, else only a random subset of size batchsize will be used} \item{n_steps}{the number of training steps.} } } \section{Details}{ There are several ways to specify an autoencoder, the simplest is to pass the number of neurons per layer in \code{n_hidden}, this must be a vector of integers of impair length and it must be symmetric and the middle number must be equal to \code{ndim}, For every layer an activation function can be specified with \code{activation}. For regularization weight decay can be specified by setting \code{weight_decay} > 0. Currently only a gradient descent optimizer is used, the learning rate can be specified by setting \code{learning_rate}. The learner can operate on batches if \code{batchsize} is not \code{NA}. The number of steps the learner uses is specified using \code{n_steps}. } \section{Further training a model}{ If the model did not converge in the first training phase or training with different data is desired, the \code{\link{dimRedResult}} object may be passed as \code{autoencoder} parameter; In this case all topology related parameters will be ignored. } \section{Using Keras layers}{ The encoder and decoder part can be specified using a list of \pkg{keras} layers. This requires a list with two entries, \code{encoder} should contain a LIST of keras layers WITHOUT the \code{\link[keras]{layer_input}} that will be concatenated in order to form the encoder part. \code{decoder} should be defined accordingly, the output of \code{decoder} must have the same number of dimensions as the input data. } \section{Using Tensorflow}{ The model can be entirely defined in \pkg{tensorflow}, it must contain a list with the following entries: \describe{ \item{encoder}{A tensor that defines the encoder.} \item{decoder}{A tensor that defines the decoder.} \item{network}{A tensor that defines the reconstruction (encoder + decoder).} \item{loss}{A tensor that calculates the loss (network + loss function).} \item{in_data}{A \code{placeholder} that points to the data input of the network AND the encoder.} \item{in_decoder}{A \code{placeholder} that points to the input of the decoder.} \item{session}{A \pkg{tensorflow} \code{Session} object that holds the values of the tensors.} } } \section{Implementation}{ Uses \pkg{tensorflow} as a backend, for details an problems relating tensorflow, see \url{https://tensorflow.rstudio.com}. } \examples{ \dontrun{ dat <- loadDataSet("3D S Curve") emb <- embed(dat, "AutoEncoder") # predicting is possible: samp <- sample(floor(nrow(dat) / 10)) emb2 <- embed(dat[samp]) emb3 <- predict(emb2, dat[-samp]) plot(emb, type = "2vars") plot(emb2, type = "2vars") points(getData(emb3)) } } \seealso{ Other dimensionality reduction methods: \code{\link{DRR-class}}, \code{\link{DiffusionMaps-class}}, \code{\link{DrL-class}}, \code{\link{FastICA-class}}, \code{\link{FruchtermanReingold-class}}, \code{\link{HLLE-class}}, \code{\link{Isomap-class}}, \code{\link{KamadaKawai-class}}, \code{\link{MDS-class}}, \code{\link{NNMF-class}}, \code{\link{PCA-class}}, \code{\link{PCA_L1-class}}, \code{\link{UMAP-class}}, \code{\link{dimRedMethod-class}}, \code{\link{dimRedMethodList}()}, \code{\link{kPCA-class}}, \code{\link{nMDS-class}}, \code{\link{tSNE-class}} } \concept{dimensionality reduction methods} dimRed/man/mixColorRamps.Rd0000644000176200001440000000254614262553601015332 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/mixColorSpaces.R \name{mixColorRamps} \alias{mixColorRamps} \alias{mixColor1Ramps} \alias{mixColor2Ramps} \alias{mixColor3Ramps} \title{Mixing color ramps} \usage{ mixColorRamps(vars, ramps) mixColor1Ramps(vars, ramps = colorRamp(c("blue", "black", "red"))) mixColor2Ramps( vars, ramps = list(colorRamp(c("blue", "green")), colorRamp(c("blue", "red"))) ) mixColor3Ramps( vars, ramps = list(colorRamp(c("#001A00", "#00E600")), colorRamp(c("#00001A", "#0000E6")), colorRamp(c("#1A0000", "#E60000"))) ) } \arguments{ \item{vars}{a list of variables} \item{ramps}{a list of color ramps, one for each variable.} } \description{ mix different color ramps } \details{ automatically create colors to represent a varying number of dimensions. } \examples{ cols <- expand.grid(x = seq(0, 1, length.out = 10), y = seq(0, 1, length.out = 10), z = seq(0, 1, length.out = 10)) mixed <- mixColor3Ramps(cols) \dontrun{ if(requireNamespace("rgl", quietly = TRUE)) { rgl::plot3d(cols$x, cols$y, cols$z, col = mixed, pch = 15) } cols <- expand.grid(x = seq(0, 1, length.out = 10), y = seq(0, 1, length.out = 10)) mixed <- mixColor2Ramps(cols) if(requireNamespace("graphics", quietly = TRUE)) { plot(cols$x, cols$y, col = mixed, pch = 15) } } } dimRed/man/mean_R_NX-dimRedResult-method.Rd0000644000176200001440000000215114255350572020214 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/quality.R \name{mean_R_NX,dimRedResult-method} \alias{mean_R_NX,dimRedResult-method} \alias{mean_R_NX} \title{Method mean_R_NX} \usage{ \S4method{mean_R_NX}{dimRedResult}(object) } \arguments{ \item{object}{of class dimRedResult} } \description{ Calculate the mean_R_NX score to assess the quality of a dimensionality reduction. } \seealso{ Other Quality scores for dimensionality reduction: \code{\link{AUC_lnK_R_NX,dimRedResult-method}}, \code{\link{LCMC,dimRedResult-method}}, \code{\link{Q_NX,dimRedResult-method}}, \code{\link{Q_global,dimRedResult-method}}, \code{\link{Q_local,dimRedResult-method}}, \code{\link{R_NX,dimRedResult-method}}, \code{\link{cophenetic_correlation,dimRedResult-method}}, \code{\link{distance_correlation,dimRedResult-method}}, \code{\link{plot_R_NX}()}, \code{\link{quality,dimRedResult-method}}, \code{\link{reconstruction_error,dimRedResult-method}}, \code{\link{reconstruction_rmse,dimRedResult-method}}, \code{\link{total_correlation,dimRedResult-method}} } \concept{Quality scores for dimensionality reduction} dimRed/man/getRotationMatrix.Rd0000644000176200001440000000161414262545370016216 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/get_info.R \name{getRotationMatrix} \alias{getRotationMatrix} \title{getRotationMatrix} \usage{ getRotationMatrix(x) } \arguments{ \item{x}{of type \code{\link{dimRedResult}}} } \value{ a matrix } \description{ Extract the rotation matrix from \code{\link{dimRedResult}} objects derived from PCA and FastICA } \details{ The data has to be pre-processed the same way as the method does, e.g. centering and/or scaling. } \examples{ dat <- loadDataSet("Iris") pca <- embed(dat, "PCA") rot_pca <- getRotationMatrix(pca) scale(getData(dat), TRUE, FALSE) \%*\% rot_pca - getData(getDimRedData(pca)) if(requireNamespace("fastICA", quietly = TRUE)) { ica <- embed(dat, "FastICA") rot_ica <- getRotationMatrix(ica) scale(getData(dat), TRUE, FALSE) \%*\% rot_ica - getData(getDimRedData(ica)) } } \concept{convenience functions} dimRed/man/distance_correlation-dimRedResult-method.Rd0000644000176200001440000000224514255350573022606 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/quality.R \name{distance_correlation,dimRedResult-method} \alias{distance_correlation,dimRedResult-method} \alias{distance_correlation} \title{Method distance_correlation} \usage{ \S4method{distance_correlation}{dimRedResult}(object) } \arguments{ \item{object}{of class dimRedResult} } \description{ Calculate the distance correlation between the distance matrices in high and low dimensioal space. } \seealso{ Other Quality scores for dimensionality reduction: \code{\link{AUC_lnK_R_NX,dimRedResult-method}}, \code{\link{LCMC,dimRedResult-method}}, \code{\link{Q_NX,dimRedResult-method}}, \code{\link{Q_global,dimRedResult-method}}, \code{\link{Q_local,dimRedResult-method}}, \code{\link{R_NX,dimRedResult-method}}, \code{\link{cophenetic_correlation,dimRedResult-method}}, \code{\link{mean_R_NX,dimRedResult-method}}, \code{\link{plot_R_NX}()}, \code{\link{quality,dimRedResult-method}}, \code{\link{reconstruction_error,dimRedResult-method}}, \code{\link{reconstruction_rmse,dimRedResult-method}}, \code{\link{total_correlation,dimRedResult-method}} } \concept{Quality scores for dimensionality reduction} dimRed/man/tSNE-class.Rd0000644000176200001440000000533514255350573014453 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/tsne.R \docType{class} \name{tSNE-class} \alias{tSNE-class} \alias{tSNE} \title{t-Distributed Stochastic Neighborhood Embedding} \description{ An S4 Class for t-SNE. } \details{ t-SNE is a method that uses Kullback-Leibler divergence between the distance matrices in high and low-dimensional space to embed the data. The method is very well suited to visualize complex structures in low dimensions. } \section{Slots}{ \describe{ \item{\code{fun}}{A function that does the embedding and returns a dimRedResult object.} \item{\code{stdpars}}{The standard parameters for the function.} }} \section{General usage}{ Dimensionality reduction methods are S4 Classes that either be used directly, in which case they have to be initialized and a full list with parameters has to be handed to the \code{@fun()} slot, or the method name be passed to the embed function and parameters can be given to the \code{...}, in which case missing parameters will be replaced by the ones in the \code{@stdpars}. } \section{Parameters}{ t-SNE can take the following parameters: \describe{ \item{d}{A distance function, defaults to euclidean distances} \item{perplexity}{The perplexity parameter, roughly equivalent to neighborhood size.} \item{theta}{Approximation for the nearest neighbour search, large values are more inaccurate.} \item{ndim}{The number of embedding dimensions.} } } \section{Implementation}{ Wraps around \code{\link[Rtsne]{Rtsne}}, which is very well documented. Setting \code{theta = 0} does a normal t-SNE, larger values for \code{theta < 1} use the Barnes-Hut algorithm which scales much nicer with data size. Larger values for perplexity take larger neighborhoods into account. } \examples{ \dontrun{ dat <- loadDataSet("3D S Curve", n = 300) emb <- embed(dat, "tSNE", perplexity = 80) plot(emb, type = "2vars") } } \references{ Maaten, L. van der, 2014. Accelerating t-SNE using Tree-Based Algorithms. Journal of Machine Learning Research 15, 3221-3245. van der Maaten, L., Hinton, G., 2008. Visualizing Data using t-SNE. J. Mach. Learn. Res. 9, 2579-2605. } \seealso{ Other dimensionality reduction methods: \code{\link{AutoEncoder-class}}, \code{\link{DRR-class}}, \code{\link{DiffusionMaps-class}}, \code{\link{DrL-class}}, \code{\link{FastICA-class}}, \code{\link{FruchtermanReingold-class}}, \code{\link{HLLE-class}}, \code{\link{Isomap-class}}, \code{\link{KamadaKawai-class}}, \code{\link{MDS-class}}, \code{\link{NNMF-class}}, \code{\link{PCA-class}}, \code{\link{PCA_L1-class}}, \code{\link{UMAP-class}}, \code{\link{dimRedMethod-class}}, \code{\link{dimRedMethodList}()}, \code{\link{kPCA-class}}, \code{\link{nMDS-class}} } \concept{dimensionality reduction methods} dimRed/man/LCMC-dimRedResult-method.Rd0000644000176200001440000000221114255350573017122 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/quality.R \name{LCMC,dimRedResult-method} \alias{LCMC,dimRedResult-method} \alias{LCMC} \title{Method LCMC} \usage{ \S4method{LCMC}{dimRedResult}(object) } \arguments{ \item{object}{of class dimRedResult} } \description{ Calculates the Local Continuity Meta Criterion, which is \code{\link{Q_NX}} adjusted for random overlap inside the K-ary neighborhood. } \seealso{ Other Quality scores for dimensionality reduction: \code{\link{AUC_lnK_R_NX,dimRedResult-method}}, \code{\link{Q_NX,dimRedResult-method}}, \code{\link{Q_global,dimRedResult-method}}, \code{\link{Q_local,dimRedResult-method}}, \code{\link{R_NX,dimRedResult-method}}, \code{\link{cophenetic_correlation,dimRedResult-method}}, \code{\link{distance_correlation,dimRedResult-method}}, \code{\link{mean_R_NX,dimRedResult-method}}, \code{\link{plot_R_NX}()}, \code{\link{quality,dimRedResult-method}}, \code{\link{reconstruction_error,dimRedResult-method}}, \code{\link{reconstruction_rmse,dimRedResult-method}}, \code{\link{total_correlation,dimRedResult-method}} } \concept{Quality scores for dimensionality reduction} dimRed/man/getOtherData.Rd0000644000176200001440000000053014255350572015101 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/misc.R \name{getOtherData} \alias{getOtherData} \title{Method getOtherData} \usage{ getOtherData(object, ...) } \arguments{ \item{object}{The object to extract data from.} \item{...}{other arguments.} } \description{ Extract other data produced by a dimRedMethod } dimRed/man/DiffusionMaps-class.Rd0000644000176200001440000000644714262545141016411 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/diffmap.R \docType{class} \name{DiffusionMaps-class} \alias{DiffusionMaps-class} \alias{DiffusionMaps} \title{Diffusion Maps} \description{ An S4 Class implementing Diffusion Maps } \details{ Diffusion Maps uses a diffusion probability matrix to robustly approximate a manifold. } \section{Slots}{ \describe{ \item{\code{fun}}{A function that does the embedding and returns a dimRedResult object.} \item{\code{stdpars}}{The standard parameters for the function.} }} \section{General usage}{ Dimensionality reduction methods are S4 Classes that either be used directly, in which case they have to be initialized and a full list with parameters has to be handed to the \code{@fun()} slot, or the method name be passed to the embed function and parameters can be given to the \code{...}, in which case missing parameters will be replaced by the ones in the \code{@stdpars}. } \section{Parameters}{ Diffusion Maps can take the following parameters: \describe{ \item{d}{a function transforming a matrix row wise into a distance matrix or \code{dist} object, e.g. \code{\link[stats]{dist}}.} \item{ndim}{The number of dimensions} \item{eps}{The epsilon parameter that determines the diffusion weight matrix from a distance matrix \code{d}, \eqn{exp(-d^2/eps)}, if set to \code{"auto"} it will be set to the median distance to the 0.01*n nearest neighbor.} \item{t}{Time-scale parameter. The recommended value, 0, uses multiscale geometry.} \item{delta}{Sparsity cut-off for the symmetric graph Laplacian, a higher value results in more sparsity and faster calculation. The predefined value is 10^-5.} } } \section{Implementation}{ Wraps around \code{\link[diffusionMap]{diffuse}}, see there for details. It uses the notation of Richards et al. (2009) which is slightly different from the one in the original paper (Coifman and Lafon, 2006) and there is no \eqn{\alpha} parameter. There is also an out-of-sample extension, see examples. } \examples{ if(requireNamespace("diffusionMap", quietly = TRUE)) { dat <- loadDataSet("3D S Curve", n = 300) emb <- embed(dat, "DiffusionMaps") plot(emb, type = "2vars") # predicting is possible: samp <- sample(floor(nrow(dat) / 10)) emb2 <- embed(dat[samp]) emb3 <- predict(emb2, dat[-samp]) plot(emb2, type = "2vars") points(getData(emb3)) } } \references{ Richards, J.W., Freeman, P.E., Lee, A.B., Schafer, C.M., 2009. Exploiting Low-Dimensional Structure in Astronomical Spectra. ApJ 691, 32. doi:10.1088/0004-637X/691/1/32 Coifman, R.R., Lafon, S., 2006. Diffusion maps. Applied and Computational Harmonic Analysis 21, 5-30. doi:10.1016/j.acha.2006.04.006 } \seealso{ Other dimensionality reduction methods: \code{\link{AutoEncoder-class}}, \code{\link{DRR-class}}, \code{\link{DrL-class}}, \code{\link{FastICA-class}}, \code{\link{FruchtermanReingold-class}}, \code{\link{HLLE-class}}, \code{\link{Isomap-class}}, \code{\link{KamadaKawai-class}}, \code{\link{MDS-class}}, \code{\link{NNMF-class}}, \code{\link{PCA-class}}, \code{\link{PCA_L1-class}}, \code{\link{UMAP-class}}, \code{\link{dimRedMethod-class}}, \code{\link{dimRedMethodList}()}, \code{\link{kPCA-class}}, \code{\link{nMDS-class}}, \code{\link{tSNE-class}} } \concept{dimensionality reduction methods} dimRed/man/maximize_correlation-dimRedResult-method.Rd0000644000176200001440000000175714255350573022646 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/rotate.R \name{maximize_correlation,dimRedResult-method} \alias{maximize_correlation,dimRedResult-method} \alias{maximize_correlation} \title{Maximize Correlation with the Axes} \usage{ \S4method{maximize_correlation}{dimRedResult}( object, naxes = ncol(object@data@data), cor_method = "pearson" ) } \arguments{ \item{object}{A dimRedResult object} \item{naxes}{the number of axes to optimize for.} \item{cor_method}{which correlation method to use} } \description{ Rotates the data in such a way that the correlation with the first \code{naxes} axes is maximized. } \details{ Methods that do not use eigenvector decomposition, like t-SNE often do not align the data with axes according to the correlation of variables with the data. \code{maximize_correlation} uses the \code{\link[optimx]{optimx}} package to rotate the data in such a way that the original variables have maximum correlation with the embedding axes. } dimRed/man/dimRedMethod-class.Rd0000644000176200001440000000375414255350572016211 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/dimRedMethod-class.R \docType{class} \name{dimRedMethod-class} \alias{dimRedMethod-class} \title{Class "dimRedMethod"} \description{ A virtual class "dimRedMethod" to serve as a template to implement methods for dimensionality reduction. } \details{ Implementations of dimensionality reductions should inherit from this class. The \code{fun} slot should be a function that takes three arguments \describe{ \item{data}{An object of class \code{\link{dimRedData}}.} \item{pars}{A list with the standard parameters.} \item{keep.org.data}{Logical. If the original data should be kept in the output.} } and returns an object of class \code{\link{dimRedResult}}. The \code{stdpars} slot should take a list that contains standard parameters for the implemented methods. This way the method can be called by \code{embed(data, "method-name", ...)}, where \code{...} can be used to to change single parameters. } \section{Slots}{ \describe{ \item{\code{fun}}{A function that does the embedding.} \item{\code{stdpars}}{A list with the default parameters for the \code{fun} slot.} \item{\code{requires}}{A vector with all packages R packages that need to be installed to run the method. In some occasions a method may work without one of the packages. Does not include Python dependencies such as Tensorflow. Used to auto skip tests} }} \seealso{ Other dimensionality reduction methods: \code{\link{AutoEncoder-class}}, \code{\link{DRR-class}}, \code{\link{DiffusionMaps-class}}, \code{\link{DrL-class}}, \code{\link{FastICA-class}}, \code{\link{FruchtermanReingold-class}}, \code{\link{HLLE-class}}, \code{\link{Isomap-class}}, \code{\link{KamadaKawai-class}}, \code{\link{MDS-class}}, \code{\link{NNMF-class}}, \code{\link{PCA-class}}, \code{\link{PCA_L1-class}}, \code{\link{UMAP-class}}, \code{\link{dimRedMethodList}()}, \code{\link{kPCA-class}}, \code{\link{nMDS-class}}, \code{\link{tSNE-class}} } \concept{dimensionality reduction methods} dimRed/man/kPCA-class.Rd0000644000176200001440000000505114262545463014415 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/kpca.R \docType{class} \name{kPCA-class} \alias{kPCA-class} \alias{kPCA} \title{Kernel PCA} \description{ An S4 Class implementing Kernel PCA } \details{ Kernel PCA is a nonlinear extension of PCA using kernel methods. } \section{Slots}{ \describe{ \item{\code{fun}}{A function that does the embedding and returns a dimRedResult object.} \item{\code{stdpars}}{The standard parameters for the function.} }} \section{General usage}{ Dimensionality reduction methods are S4 Classes that either be used directly, in which case they have to be initialized and a full list with parameters has to be handed to the \code{@fun()} slot, or the method name be passed to the embed function and parameters can be given to the \code{...}, in which case missing parameters will be replaced by the ones in the \code{@stdpars}. } \section{Parameters}{ Kernel PCA can take the following parameters: \describe{ \item{ndim}{the number of output dimensions, defaults to 2} \item{kernel}{The kernel function, either as a function or a character vector with the name of the kernel. Defaults to \code{"rbfdot"}} \item{kpar}{A list with the parameters for the kernel function, defaults to \code{list(sigma = 0.1)}} } The most comprehensive collection of kernel functions can be found in \code{\link[kernlab]{kpca}}. In case the function does not take any parameters \code{kpar} has to be an empty list. } \section{Implementation}{ Wraps around \code{\link[kernlab]{kpca}}, but provides additionally forward and backward projections. } \examples{ \dontrun{ if(requireNamespace("kernlab", quietly = TRUE)) { dat <- loadDataSet("3D S Curve") emb <- embed(dat, "kPCA") plot(emb, type = "2vars") } } } \references{ Sch\"olkopf, B., Smola, A., M\"uller, K.-R., 1998. Nonlinear Component Analysis as a Kernel Eigenvalue Problem. Neural Computation 10, 1299-1319. https://doi.org/10.1162/089976698300017467 } \seealso{ Other dimensionality reduction methods: \code{\link{AutoEncoder-class}}, \code{\link{DRR-class}}, \code{\link{DiffusionMaps-class}}, \code{\link{DrL-class}}, \code{\link{FastICA-class}}, \code{\link{FruchtermanReingold-class}}, \code{\link{HLLE-class}}, \code{\link{Isomap-class}}, \code{\link{KamadaKawai-class}}, \code{\link{MDS-class}}, \code{\link{NNMF-class}}, \code{\link{PCA-class}}, \code{\link{PCA_L1-class}}, \code{\link{UMAP-class}}, \code{\link{dimRedMethod-class}}, \code{\link{dimRedMethodList}()}, \code{\link{nMDS-class}}, \code{\link{tSNE-class}} } \concept{dimensionality reduction methods} dimRed/man/dimRedData-class.Rd0000644000176200001440000000602514255350572015634 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/dimRedData-class.R \docType{class} \name{dimRedData-class} \alias{dimRedData-class} \alias{dimRedData} \alias{as.data.frame,dimRedData-method} \alias{getData,dimRedData-method} \alias{getMeta,dimRedData-method} \alias{nrow,dimRedData-method} \alias{[,dimRedData,ANY,ANY,ANY-method} \alias{ndims,dimRedData-method} \title{Class "dimRedData"} \usage{ \S4method{as.data.frame}{dimRedData}(x, meta.prefix = "meta.", data.prefix = "") \S4method{getData}{dimRedData}(object) \S4method{getMeta}{dimRedData}(object) \S4method{nrow}{dimRedData}(x) \S4method{[}{dimRedData,ANY,ANY,ANY}(x, i) \S4method{ndims}{dimRedData}(object) } \arguments{ \item{x}{Of class dimRedData} \item{meta.prefix}{Prefix for the columns of the meta data names.} \item{data.prefix}{Prefix for the columns of the variable names.} \item{object}{Of class dimRedData.} \item{i}{a valid index for subsetting rows.} } \description{ A class to hold data for dimensionality reduction and methods. } \details{ The class hast two slots, \code{data} and \code{meta}. The \code{data} slot contains a \code{numeric matrix} with variables in columns and observations in rows. The \code{meta} slot may contain a \code{data.frame} with additional information. Both slots need to have the same number of rows or the \code{meta} slot needs to contain an empty \code{data.frame}. See examples for easy conversion from and to \code{data.frame}. For plotting functions see \code{\link{plot.dimRedData}}. } \section{Methods (by generic)}{ \itemize{ \item \code{as.data.frame}: convert to data.frame \item \code{getData}: Get the data slot. \item \code{getMeta}: Get the meta slot. \item \code{nrow}: Get the number of observations. \item \code{[}: Subset rows. \item \code{ndims}: Extract the number of Variables from the data. }} \section{Slots}{ \describe{ \item{\code{data}}{of class \code{matrix}, holds the data, observations in rows, variables in columns} \item{\code{meta}}{of class \code{data.frame}, holds meta data such as classes, internal manifold coordinates, or simply additional data of the data set. Must have the same number of rows as the \code{data} slot or be an empty data frame.} }} \examples{ ## Load an example data set: s3d <- loadDataSet("3D S Curve") ## Create using a constructor: ### without meta information: dimRedData(iris[, 1:4]) ### with meta information: dimRedData(iris[, 1:4], iris[, 5]) ### using slot names: dimRedData(data = iris[, 1:4], meta = iris[, 5]) ## Convert to a dimRedData objects: Iris <- as(iris[, 1:4], "dimRedData") ## Convert to data.frame: head(as(s3d, "data.frame")) head(as.data.frame(s3d)) head(as.data.frame(as(iris[, 1:4], "dimRedData"))) ## Extract slots: head(getData(s3d)) head(getMeta(s3d)) ## Get the number of observations: nrow(s3d) ## Subset: s3d[1:5, ] ## Shuffle data: s3 <- s3d[nrow(s3d)] ## Get the number of variables: ndims(s3d) } \seealso{ Other dimRedData: \code{\link{as.dimRedData}()} Other dimRedData: \code{\link{as.dimRedData}()} } \concept{dimRedData} dimRed/man/dataSets.Rd0000644000176200001440000000262614257370067014311 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/dataSets.R \name{dataSets} \alias{dataSets} \alias{loadDataSet} \alias{dataSetList} \title{Example Data Sets for dimensionality reduction} \usage{ loadDataSet(name = dataSetList(), n = 2000, sigma = 0.05) dataSetList() } \arguments{ \item{name}{A character vector that specifies the name of the data set.} \item{n}{In generated data sets the number of points to be generated, else ignored.} \item{sigma}{In generated data sets the standard deviation of the noise added, else ignored.} } \value{ \code{loadDataSet} an object of class \code{\link{dimRedData}}. \code{dataSetList()} return a character string with the implemented data sets } \description{ A compilation of standard data sets that are often being used to showcase dimensionality reduction techniques. } \details{ The argument \code{name} should be one of \code{dataSetList()}. Partial matching is possible, see \code{\link{match.arg}}. Generated data sets contain the internal coordinates of the manifold in the \code{meta} slot. Call \code{dataSetList()} to see what data sets are available. } \examples{ ## a list of available data sets: dataSetList() ## Load a data set: swissRoll <- loadDataSet("Swiss Roll") \donttest{ if(requireNamespace("scatterplot3d", quietly = TRUE)) plot(swissRoll, type = "3vars") } ## Load Iris data set, partial matching: loadDataSet("I") } dimRed/man/Q_global-dimRedResult-method.Rd0000644000176200001440000000214414255350572020130 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/quality.R \name{Q_global,dimRedResult-method} \alias{Q_global,dimRedResult-method} \alias{Q_global} \title{Method Q_global} \usage{ \S4method{Q_global}{dimRedResult}(object) } \arguments{ \item{object}{of class dimRedResult} } \description{ Calculate the Q_global score to assess the quality of a dimensionality reduction. } \seealso{ Other Quality scores for dimensionality reduction: \code{\link{AUC_lnK_R_NX,dimRedResult-method}}, \code{\link{LCMC,dimRedResult-method}}, \code{\link{Q_NX,dimRedResult-method}}, \code{\link{Q_local,dimRedResult-method}}, \code{\link{R_NX,dimRedResult-method}}, \code{\link{cophenetic_correlation,dimRedResult-method}}, \code{\link{distance_correlation,dimRedResult-method}}, \code{\link{mean_R_NX,dimRedResult-method}}, \code{\link{plot_R_NX}()}, \code{\link{quality,dimRedResult-method}}, \code{\link{reconstruction_error,dimRedResult-method}}, \code{\link{reconstruction_rmse,dimRedResult-method}}, \code{\link{total_correlation,dimRedResult-method}} } \concept{Quality scores for dimensionality reduction} dimRed/man/installSuggests.Rd0000644000176200001440000000124114255350572015721 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/misc.R \name{installSuggests} \alias{installSuggests} \title{getSuggests} \usage{ installSuggests(...) } \arguments{ \item{...}{additional options passed to install.packages.} } \description{ Install packages wich are suggested by dimRed. } \details{ By default dimRed will not install all the dependencies, because there are quite a lot and in case some of them are not available for your platform you will not be able to install dimRed without problems. To solve this I provide a function which automatically installes all the suggested packages. } \examples{ \dontrun{ installSuggests() } } dimRed/man/cophenetic_correlation-dimRedResult-method.Rd0000644000176200001440000000244214255350573023134 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/quality.R \name{cophenetic_correlation,dimRedResult-method} \alias{cophenetic_correlation,dimRedResult-method} \alias{cophenetic_correlation} \title{Method cophenetic_correlation} \usage{ \S4method{cophenetic_correlation}{dimRedResult}(object, d = stats::dist, cor_method = "pearson") } \arguments{ \item{object}{of class dimRedResult} \item{d}{the distance function to use.} \item{cor_method}{The correlation method.} } \description{ Calculate the correlation between the distance matrices in high and low dimensioal space. } \seealso{ Other Quality scores for dimensionality reduction: \code{\link{AUC_lnK_R_NX,dimRedResult-method}}, \code{\link{LCMC,dimRedResult-method}}, \code{\link{Q_NX,dimRedResult-method}}, \code{\link{Q_global,dimRedResult-method}}, \code{\link{Q_local,dimRedResult-method}}, \code{\link{R_NX,dimRedResult-method}}, \code{\link{distance_correlation,dimRedResult-method}}, \code{\link{mean_R_NX,dimRedResult-method}}, \code{\link{plot_R_NX}()}, \code{\link{quality,dimRedResult-method}}, \code{\link{reconstruction_error,dimRedResult-method}}, \code{\link{reconstruction_rmse,dimRedResult-method}}, \code{\link{total_correlation,dimRedResult-method}} } \concept{Quality scores for dimensionality reduction} dimRed/man/LaplacianEigenmaps-class.Rd0000644000176200001440000000426214262545141017350 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/leim.R \docType{class} \name{LaplacianEigenmaps-class} \alias{LaplacianEigenmaps-class} \alias{LaplacianEigenmaps} \title{Laplacian Eigenmaps} \description{ An S4 Class implementing Laplacian Eigenmaps } \details{ Laplacian Eigenmaps use a kernel and were originally developed to separate non-convex clusters under the name spectral clustering. } \section{Slots}{ \describe{ \item{\code{fun}}{A function that does the embedding and returns a dimRedResult object.} \item{\code{stdpars}}{The standard parameters for the function.} }} \section{General usage}{ Dimensionality reduction methods are S4 Classes that either be used directly, in which case they have to be initialized and a full list with parameters has to be handed to the \code{@fun()} slot, or the method name be passed to the embed function and parameters can be given to the \code{...}, in which case missing parameters will be replaced by the ones in the \code{@stdpars}. } \section{Parameters}{ \code{LaplacianEigenmaps} can take the following parameters: \describe{ \item{ndim}{the number of output dimensions.} \item{sparse}{A character vector specifying hot to make the graph sparse, \code{"knn"} means that a K-nearest neighbor graph is constructed, \code{"eps"} an epsilon neighborhood graph is constructed, else a dense distance matrix is used.} \item{knn}{The number of nearest neighbors to use for the knn graph.} \item{eps}{The distance for the epsilon neighborhood graph.} \item{t}{Parameter for the transformation of the distance matrix by \eqn{w=exp(-d^2/t)}, larger values give less weight to differences in distance, \code{t == Inf} treats all distances != 0 equally.} \item{norm}{logical, should the normed laplacian be used?} } } \section{Implementation}{ Wraps around \code{\link[loe]{spec.emb}}. } \examples{ if(requireNamespace(c("loe", "RSpectra", "Matrix"), quietly = TRUE)) { dat <- loadDataSet("3D S Curve") emb <- embed(dat, "LaplacianEigenmaps") plot(emb@data@data) } } \references{ Belkin, M., Niyogi, P., 2003. Laplacian Eigenmaps for Dimensionality Reduction and Data Representation. Neural Computation 15, 1373. } dimRed/man/getDimRedData.Rd0000644000176200001440000000050214255350572015163 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/misc.R \name{getDimRedData} \alias{getDimRedData} \title{Method getDimRedData} \usage{ getDimRedData(object, ...) } \arguments{ \item{object}{The object to extract data from.} \item{...}{other arguments.} } \description{ Extract dimRedData. } dimRed/man/total_correlation-dimRedResult-method.Rd0000644000176200001440000000263114255350572022135 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/quality.R \name{total_correlation,dimRedResult-method} \alias{total_correlation,dimRedResult-method} \alias{total_correlation} \title{Method total_correlation} \usage{ \S4method{total_correlation}{dimRedResult}( object, naxes = ndims(object), cor_method = "pearson", is.rotated = FALSE ) } \arguments{ \item{object}{of class dimRedResult} \item{naxes}{the number of axes to use for optimization.} \item{cor_method}{the correlation method to use.} \item{is.rotated}{if FALSE the object is rotated.} } \description{ Calculate the total correlation of the variables with the axes to assess the quality of a dimensionality reduction. } \seealso{ Other Quality scores for dimensionality reduction: \code{\link{AUC_lnK_R_NX,dimRedResult-method}}, \code{\link{LCMC,dimRedResult-method}}, \code{\link{Q_NX,dimRedResult-method}}, \code{\link{Q_global,dimRedResult-method}}, \code{\link{Q_local,dimRedResult-method}}, \code{\link{R_NX,dimRedResult-method}}, \code{\link{cophenetic_correlation,dimRedResult-method}}, \code{\link{distance_correlation,dimRedResult-method}}, \code{\link{mean_R_NX,dimRedResult-method}}, \code{\link{plot_R_NX}()}, \code{\link{quality,dimRedResult-method}}, \code{\link{reconstruction_error,dimRedResult-method}}, \code{\link{reconstruction_rmse,dimRedResult-method}} } \concept{Quality scores for dimensionality reduction} dimRed/man/getNDim.Rd0000644000176200001440000000051014255350572014053 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/misc.R \name{getNDim} \alias{getNDim} \title{Method getNDim} \usage{ getNDim(object, ...) } \arguments{ \item{object}{The object to get the dimensions from.} \item{...}{other arguments.} } \description{ Extract the number of embedding dimensions. } dimRed/man/KamadaKawai-class.Rd0000644000176200001440000000566614257375355016013 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/graph_embed.R \docType{class} \name{KamadaKawai-class} \alias{KamadaKawai-class} \alias{KamadaKawai} \title{Graph Embedding via the Kamada Kawai Algorithm} \description{ An S4 Class implementing the Kamada Kawai Algorithm for graph embedding. } \details{ Graph embedding algorithms se the data as a graph. Between the nodes of the graph exist attracting and repelling forces which can be modeled as electrical fields or springs connecting the nodes. The graph is then forced into a lower dimensional representation that tries to represent the forces betweent he nodes accurately by minimizing the total energy of the attracting and repelling forces. } \section{Slots}{ \describe{ \item{\code{fun}}{A function that does the embedding and returns a dimRedResult object.} \item{\code{stdpars}}{The standard parameters for the function.} }} \section{General usage}{ Dimensionality reduction methods are S4 Classes that either be used directly, in which case they have to be initialized and a full list with parameters has to be handed to the \code{@fun()} slot, or the method name be passed to the embed function and parameters can be given to the \code{...}, in which case missing parameters will be replaced by the ones in the \code{@stdpars}. } \section{Parameters}{ KamadaKawai can take the following parameters: \describe{ \item{ndim}{The number of dimensions, defaults to 2. Can only be 2 or 3} \item{knn}{Reduce the graph to keep only the neares neighbors. Defaults to 100.} \item{d}{The distance function to determine the weights of the graph edges. Defaults to euclidean distances.} } } \section{Implementation}{ Wraps around \code{\link[igraph]{layout_with_kk}}. The parameters maxiter, epsilon and kkconst are set to the default values and cannot be set, this may change in a future release. The DimRed Package adds an extra sparsity parameter by constructing a knn graph which also may improve visualization quality. } \examples{ if(requireNamespace(c("igraph", "coRanking"), quietly = TRUE)) { dat <- loadDataSet("Swiss Roll", n = 200) emb <- embed(dat, "KamadaKawai") plot(emb, type = "2vars") } } \references{ Kamada, T., Kawai, S., 1989. An algorithm for drawing general undirected graphs. Information Processing Letters 31, 7-15. https://doi.org/10.1016/0020-0190(89)90102-6 } \seealso{ Other dimensionality reduction methods: \code{\link{AutoEncoder-class}}, \code{\link{DRR-class}}, \code{\link{DiffusionMaps-class}}, \code{\link{DrL-class}}, \code{\link{FastICA-class}}, \code{\link{FruchtermanReingold-class}}, \code{\link{HLLE-class}}, \code{\link{Isomap-class}}, \code{\link{MDS-class}}, \code{\link{NNMF-class}}, \code{\link{PCA-class}}, \code{\link{PCA_L1-class}}, \code{\link{UMAP-class}}, \code{\link{dimRedMethod-class}}, \code{\link{dimRedMethodList}()}, \code{\link{kPCA-class}}, \code{\link{nMDS-class}}, \code{\link{tSNE-class}} } \concept{dimensionality reduction methods} dimRed/man/PCA_L1-class.Rd0000644000176200001440000000540414256653702014577 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/l1pca.R \docType{class} \name{PCA_L1-class} \alias{PCA_L1-class} \alias{PCA_L1} \title{Principal Component Analysis with L1 error.} \description{ S4 Class implementing PCA with L1 error. } \details{ PCA transforms the data so that the L2 reconstruction error is minimized or the variance of the projected data is maximized. This is sensitive to outliers, L1 PCA minimizes the L1 reconstruction error or maximizes the sum of the L1 norm of the projected observations. } \section{Slots}{ \describe{ \item{\code{fun}}{A function that does the embedding and returns a dimRedResult object.} \item{\code{stdpars}}{The standard parameters for the function.} }} \section{General usage}{ Dimensionality reduction methods are S4 Classes that either be used directly, in which case they have to be initialized and a full list with parameters has to be handed to the \code{@fun()} slot, or the method name be passed to the embed function and parameters can be given to the \code{...}, in which case missing parameters will be replaced by the ones in the \code{@stdpars}. } \section{Parameters}{ PCA can take the following parameters: \describe{ \item{ndim}{The number of output dimensions.} \item{center}{logical, should the data be centered, defaults to \code{TRUE}.} \item{scale.}{logical, should the data be scaled, defaults to \code{FALSE}.} \item{fun}{character or function, the method to apply, see the \code{pcaL1} package} \item{\ldots}{other parameters for \code{fun}} } } \section{Implementation}{ Wraps around the different methods is the \code{pcaL1} package. Because PCA can be reduced to a simple rotation, forward and backward projection functions are supplied. } \examples{ if(requireNamespace("pcaL1", quietly = TRUE)) { dat <- loadDataSet("Iris") emb <- embed(dat, "PCA_L1") plot(emb, type = "2vars") plot(inverse(emb, getData(getDimRedData((emb)))), type = "3vars") } } \references{ Park, Y.W., Klabjan, D., 2016. Iteratively Reweighted Least Squares Algorithms for L1-Norm Principal Component Analysis, in: Data Mining (ICDM), 2016 IEEE 16th International Conference On. IEEE, pp. 430-438. } \seealso{ Other dimensionality reduction methods: \code{\link{AutoEncoder-class}}, \code{\link{DRR-class}}, \code{\link{DiffusionMaps-class}}, \code{\link{DrL-class}}, \code{\link{FastICA-class}}, \code{\link{FruchtermanReingold-class}}, \code{\link{HLLE-class}}, \code{\link{Isomap-class}}, \code{\link{KamadaKawai-class}}, \code{\link{MDS-class}}, \code{\link{NNMF-class}}, \code{\link{PCA-class}}, \code{\link{UMAP-class}}, \code{\link{dimRedMethod-class}}, \code{\link{dimRedMethodList}()}, \code{\link{kPCA-class}}, \code{\link{nMDS-class}}, \code{\link{tSNE-class}} } \concept{dimensionality reduction methods} dimRed/man/AUC_lnK_R_NX-dimRedResult-method.Rd0000644000176200001440000000347514255350572020522 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/quality.R \name{AUC_lnK_R_NX,dimRedResult-method} \alias{AUC_lnK_R_NX,dimRedResult-method} \alias{AUC_lnK_R_NX} \title{Method AUC_lnK_R_NX} \usage{ \S4method{AUC_lnK_R_NX}{dimRedResult}(object, weight = "inv") } \arguments{ \item{object}{of class dimRedResult} \item{weight}{the weight function used, one of \code{c("inv", "log", "log10")}} } \description{ Calculate the Area under the R_NX(ln K), used in Lee et. al. (2015). Note that despite the name, this does not weight the mean by the logarithm, but by 1/K. If explicit weighting by the logarithm is desired use \code{weight = "log"} or \code{weight = "log10"} } \details{ The naming confusion originated from equation 17 in Lee et al (2015) and the name of this method may change in the future to avoid confusion. } \references{ Lee, J.A., Peluffo-Ordonez, D.H., Verleysen, M., 2015. Multi-scale similarities in stochastic neighbour embedding: Reducing dimensionality while preserving both local and global structure. Neurocomputing 169, 246-261. https://doi.org/10.1016/j.neucom.2014.12.095 } \seealso{ Other Quality scores for dimensionality reduction: \code{\link{LCMC,dimRedResult-method}}, \code{\link{Q_NX,dimRedResult-method}}, \code{\link{Q_global,dimRedResult-method}}, \code{\link{Q_local,dimRedResult-method}}, \code{\link{R_NX,dimRedResult-method}}, \code{\link{cophenetic_correlation,dimRedResult-method}}, \code{\link{distance_correlation,dimRedResult-method}}, \code{\link{mean_R_NX,dimRedResult-method}}, \code{\link{plot_R_NX}()}, \code{\link{quality,dimRedResult-method}}, \code{\link{reconstruction_error,dimRedResult-method}}, \code{\link{reconstruction_rmse,dimRedResult-method}}, \code{\link{total_correlation,dimRedResult-method}} } \concept{Quality scores for dimensionality reduction} dimRed/man/getPars.Rd0000644000176200001440000000045114255350572014135 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/misc.R \name{getPars} \alias{getPars} \title{Method getPars} \usage{ getPars(object, ...) } \arguments{ \item{object}{The object to be converted.} \item{...}{other arguments.} } \description{ Extracts the pars slot. } dimRed/man/quality.Rd0000644000176200001440000001112214257373616014223 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/quality.R \name{quality,dimRedResult-method} \alias{quality,dimRedResult-method} \alias{quality} \alias{quality.dimRedResult} \alias{dimRedQualityList} \title{Quality Criteria for dimensionality reduction.} \usage{ \S4method{quality}{dimRedResult}(.data, .method = dimRedQualityList(), .mute = character(0), ...) dimRedQualityList(filter = FALSE) } \arguments{ \item{.data}{object of class \code{dimRedResult}} \item{.method}{character vector naming one of the methods} \item{.mute}{what output from the embedding method should be muted.} \item{...}{the pameters, internally passed as a list to the quality method as \code{pars = list(...)}} \item{filter}{filter methods by installed packages} } \value{ a number } \description{ A collection of functions to compute quality measures on \code{\link{dimRedResult}} objects. } \section{Methods (by class)}{ \itemize{ \item \code{dimRedResult}: Calculate a quality index from a dimRedResult object. }} \section{Implemented methods}{ Method must be one of \code{"\link{Q_local}", "\link{Q_global}", "\link{mean_R_NX}", "\link{total_correlation}", "\link{cophenetic_correlation}", "\link{distance_correlation}", "\link{reconstruction_rmse}"} } \section{Rank based criteria}{ \code{Q_local}, \code{Q_global}, and \code{mean_R_NX} are quality criteria based on the Co-ranking matrix. \code{Q_local} and \code{Q_global} determine the local/global quality of the embedding, while \code{mean_R_NX} determines the quality of the overall embedding. They are parameter free and return a single number. The object must include the original data. The number returns is in the range [0, 1], higher values mean a better local/global embedding. } \section{Correlation based criteria}{ \code{total_correlation} calculates the sum of the mean squared correlations of the original axes with the axes in reduced dimensions, because some methods do not care about correlations with axes, there is an option to rotate data in reduced space to maximize this criterium. The number may be greater than one if more dimensions are summed up. \code{cophenetic_correlation} calculate the correlation between the lower triangles of distance matrices, the correlation and distance methods may be specified. The result is in range [-1, 1]. \code{distance_correlation} measures the independes of samples by calculating the correlation of distances. For details see \code{\link[energy]{dcor}}. } \section{Reconstruction error}{ \code{reconstruction_rmse} calculates the root mean squared error of the reconstrucion. \code{object} requires an inverse function. } \examples{ \dontrun{ embed_methods <- dimRedMethodList() quality_methods <- dimRedQualityList() scurve <- loadDataSet("Iris") quality_results <- matrix(NA, length(embed_methods), length(quality_methods), dimnames = list(embed_methods, quality_methods)) embedded_data <- list() for (e in embed_methods) { message("embedding: ", e) embedded_data[[e]] <- embed(scurve, e, .mute = c("message", "output")) for (q in quality_methods) { message(" quality: ", q) quality_results[e, q] <- tryCatch( quality(embedded_data[[e]], q), error = function (e) NA ) } } print(quality_results) } } \references{ Lueks, W., Mokbel, B., Biehl, M., Hammer, B., 2011. How to Evaluate Dimensionality Reduction? - Improving the Co-ranking Matrix. arXiv:1110.3917 [cs]. Szekely, G.J., Rizzo, M.L., Bakirov, N.K., 2007. Measuring and testing dependence by correlation of distances. Ann. Statist. 35, 2769-2794. doi:10.1214/009053607000000505 Lee, J.A., Peluffo-Ordonez, D.H., Verleysen, M., 2015. Multi-scale similarities in stochastic neighbour embedding: Reducing dimensionality while preserving both local and global structure. Neurocomputing, 169, 246-261. doi:10.1016/j.neucom.2014.12.095 } \seealso{ Other Quality scores for dimensionality reduction: \code{\link{AUC_lnK_R_NX,dimRedResult-method}}, \code{\link{LCMC,dimRedResult-method}}, \code{\link{Q_NX,dimRedResult-method}}, \code{\link{Q_global,dimRedResult-method}}, \code{\link{Q_local,dimRedResult-method}}, \code{\link{R_NX,dimRedResult-method}}, \code{\link{cophenetic_correlation,dimRedResult-method}}, \code{\link{distance_correlation,dimRedResult-method}}, \code{\link{mean_R_NX,dimRedResult-method}}, \code{\link{plot_R_NX}()}, \code{\link{reconstruction_error,dimRedResult-method}}, \code{\link{reconstruction_rmse,dimRedResult-method}}, \code{\link{total_correlation,dimRedResult-method}} } \author{ Guido Kraemer } \concept{Quality scores for dimensionality reduction} dimRed/man/HLLE-class.Rd0000644000176200001440000000437614262545547014377 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/hlle.R \docType{class} \name{HLLE-class} \alias{HLLE-class} \alias{HLLE} \title{Hessian Locally Linear Embedding} \description{ An S4 Class implementing Hessian Locally Linear Embedding (HLLE) } \details{ HLLE uses local hessians to approximate the curvines and is an extension to non-convex subsets in lowdimensional space. } \section{Slots}{ \describe{ \item{\code{fun}}{A function that does the embedding and returns a dimRedResult object.} \item{\code{stdpars}}{The standard parameters for the function.} }} \section{General usage}{ Dimensionality reduction methods are S4 Classes that either be used directly, in which case they have to be initialized and a full list with parameters has to be handed to the \code{@fun()} slot, or the method name be passed to the embed function and parameters can be given to the \code{...}, in which case missing parameters will be replaced by the ones in the \code{@stdpars}. } \section{Parameters}{ HLLE can take the following parameters: \describe{ \item{knn}{neighborhood size} \item{ndim}{number of output dimensions} } } \section{Implementation}{ Own implementation, sticks to the algorithm in Donoho and Grimes (2003). Makes use of sparsity to speed up final embedding. } \examples{ if(requireNamespace(c("RSpectra", "Matrix", "RANN"), quietly = TRUE)) { dat <- loadDataSet("3D S Curve", n = 300) emb <- embed(dat, "HLLE", knn = 15) plot(emb, type = "2vars") } } \references{ Donoho, D.L., Grimes, C., 2003. Hessian eigenmaps: Locally linear embedding techniques for high-dimensional data. PNAS 100, 5591-5596. doi:10.1073/pnas.1031596100 } \seealso{ Other dimensionality reduction methods: \code{\link{AutoEncoder-class}}, \code{\link{DRR-class}}, \code{\link{DiffusionMaps-class}}, \code{\link{DrL-class}}, \code{\link{FastICA-class}}, \code{\link{FruchtermanReingold-class}}, \code{\link{Isomap-class}}, \code{\link{KamadaKawai-class}}, \code{\link{MDS-class}}, \code{\link{NNMF-class}}, \code{\link{PCA-class}}, \code{\link{PCA_L1-class}}, \code{\link{UMAP-class}}, \code{\link{dimRedMethod-class}}, \code{\link{dimRedMethodList}()}, \code{\link{kPCA-class}}, \code{\link{nMDS-class}}, \code{\link{tSNE-class}} } \concept{dimensionality reduction methods} dimRed/man/embed.Rd0000644000176200001440000000605314255350572013610 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/embed.R \name{embed} \alias{embed} \alias{embed,formula-method} \alias{embed,ANY-method} \alias{embed,dimRedData-method} \title{dispatches the different methods for dimensionality reduction} \usage{ embed(.data, ...) \S4method{embed}{formula}( .formula, .data, .method = dimRedMethodList(), .mute = character(0), .keep.org.data = TRUE, ... ) \S4method{embed}{ANY}( .data, .method = dimRedMethodList(), .mute = character(0), .keep.org.data = TRUE, ... ) \S4method{embed}{dimRedData}( .data, .method = dimRedMethodList(), .mute = character(0), .keep.org.data = TRUE, ... ) } \arguments{ \item{.data}{object of class \code{\link{dimRedData}}, will be converted to be of class \code{\link{dimRedData}} if necessary; see examples for details.} \item{...}{the parameters, internally passed as a list to the dimensionality reduction method as \code{pars = list(...)}} \item{.formula}{a formula, see \code{\link{as.dimRedData}}.} \item{.method}{character vector naming one of the dimensionality reduction techniques.} \item{.mute}{a character vector containing the elements you want to mute (\code{c("message", "output")}), defaults to \code{character(0)}.} \item{.keep.org.data}{\code{TRUE}/\code{FALSE} keep the original data.} } \value{ an object of class \code{\link{dimRedResult}} } \description{ wraps around all dimensionality reduction functions. } \details{ Method must be one of \code{\link{dimRedMethodList}()}, partial matching is performed. All parameters start with a dot, to avoid clashes with partial argument matching (see the R manual section 4.3.2), if there should ever occur any clashes in the arguments, call the function with all arguments named, e.g. \code{embed(.data = dat, .method = "mymethod", .d = "some parameter")}. } \section{Methods (by class)}{ \itemize{ \item \code{formula}: embed a data.frame using a formula. \item \code{ANY}: Embed anything as long as it can be coerced to \code{\link{dimRedData}}. \item \code{dimRedData}: Embed a dimRedData object }} \examples{ ## embed a data.frame using a formula: as.data.frame( embed(Species ~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width, iris, "PCA") ) ## embed a data.frame and return a data.frame as.data.frame(embed(iris[, 1:4], "PCA")) ## embed a matrix and return a data.frame as.data.frame(embed(as.matrix(iris[, 1:4]), "PCA")) \dontrun{ ## embed dimRedData objects embed_methods <- dimRedMethodList() quality_methods <- dimRedQualityList() dataset <- loadDataSet("Iris") quality_results <- matrix(NA, length(embed_methods), length(quality_methods), dimnames = list(embed_methods, quality_methods)) embedded_data <- list() for (e in embed_methods) { message("embedding: ", e) embedded_data[[e]] <- embed(dataset, e, .mute = c("message", "output")) for (q in quality_methods) { message(" quality: ", q) quality_results[e, q] <- tryCatch( quality(embedded_data[[e]], q), error = function(e) NA ) } } print(quality_results) } } dimRed/man/UMAP-class.Rd0000644000176200001440000000645114255350573014404 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/umap.R \docType{class} \name{UMAP-class} \alias{UMAP-class} \alias{UMAP} \title{Umap embedding} \description{ An S4 Class implementing the UMAP algorithm } \details{ Uniform Manifold Approximation is a gradient descend based algorithm that gives results similar to t-SNE, but scales better with the number of points. } \section{Slots}{ \describe{ \item{\code{fun}}{A function that does the embedding and returns a dimRedResult object.} \item{\code{stdpars}}{The standard parameters for the function.} }} \section{General usage}{ Dimensionality reduction methods are S4 Classes that either be used directly, in which case they have to be initialized and a full list with parameters has to be handed to the \code{@fun()} slot, or the method name be passed to the embed function and parameters can be given to the \code{...}, in which case missing parameters will be replaced by the ones in the \code{@stdpars}. } \section{Parameters}{ UMAP can take the follwing parameters: \describe{ \item{ndim}{The number of embedding dimensions.} \item{knn}{The number of neighbors to be used.} \item{d}{The distance metric to use.} \item{method}{\code{"naive"} for an R implementation, \code{"python"} for the reference implementation.} } Other method parameters can also be passed, see \code{\link[umap]{umap.defaults}} for details. The ones above have been standardized for the use with \code{dimRed} and will get automatically translated for \code{\link[umap]{umap}}. } \section{Implementation}{ The dimRed package wraps the \code{\link[umap]{umap}} packages which provides an implementation in pure R and also a wrapper around the original python package \code{umap-learn} (https://github.com/lmcinnes/umap/). This requires \code{umap-learn} version 0.4 installed, at the time of writing, there is already \code{umap-learn} 0.5 but it is not supported by the R package \code{\link[umap]{umap}}. The \code{"naive"} implementation is a pure R implementation and considered experimental at the point of writing this, it is also much slower than the python implementation. The \code{"python"} implementation is the reference implementation used by McInees et. al. (2018). It requires the \code{\link[reticulate]{reticulate}} package for the interaction with python and the python package \code{umap-learn} installed (use \code{pip install umap-learn}). } \examples{ \dontrun{ dat <- loadDataSet("3D S Curve", n = 300) emb <- embed(dat, "UMAP", .mute = NULL, knn = 10) plot(emb, type = "2vars") } } \references{ McInnes, Leland, and John Healy. "UMAP: Uniform Manifold Approximation and Projection for Dimension Reduction." https://arxiv.org/abs/1802.03426 } \seealso{ Other dimensionality reduction methods: \code{\link{AutoEncoder-class}}, \code{\link{DRR-class}}, \code{\link{DiffusionMaps-class}}, \code{\link{DrL-class}}, \code{\link{FastICA-class}}, \code{\link{FruchtermanReingold-class}}, \code{\link{HLLE-class}}, \code{\link{Isomap-class}}, \code{\link{KamadaKawai-class}}, \code{\link{MDS-class}}, \code{\link{NNMF-class}}, \code{\link{PCA-class}}, \code{\link{PCA_L1-class}}, \code{\link{dimRedMethod-class}}, \code{\link{dimRedMethodList}()}, \code{\link{kPCA-class}}, \code{\link{nMDS-class}}, \code{\link{tSNE-class}} } \concept{dimensionality reduction methods} dimRed/man/reconstruction_error-dimRedResult-method.Rd0000644000176200001440000000406714255350573022711 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/quality.R \name{reconstruction_error,dimRedResult-method} \alias{reconstruction_error,dimRedResult-method} \alias{reconstruction_error} \title{Method reconstruction_error} \usage{ \S4method{reconstruction_error}{dimRedResult}(object, n = seq_len(ndims(object)), error_fun = "rmse") } \arguments{ \item{object}{of class dimRedResult} \item{n}{a positive integer or vector of integers \code{<= ndims(object)}} \item{error_fun}{a function or string indicating an error function, if indication a function it must take to matrices of the same size and return a scalar.} } \value{ a vector of number with the same length as \code{n} with the } \description{ Calculate the error using only the first \code{n} dimensions of the embedded data. \code{error_fun} can either be one of \code{c("rmse", "mae")} to calculate the root mean square error or the mean absolute error respectively, or a function that takes to equally sized vectors as input and returns a single number as output. } \examples{ \dontrun{ ir <- loadDataSet("Iris") ir.drr <- embed(ir, "DRR", ndim = ndims(ir)) ir.pca <- embed(ir, "PCA", ndim = ndims(ir)) rmse <- data.frame( rmse_drr = reconstruction_error(ir.drr), rmse_pca = reconstruction_error(ir.pca) ) matplot(rmse, type = "l") plot(ir) plot(ir.drr) plot(ir.pca) } } \seealso{ Other Quality scores for dimensionality reduction: \code{\link{AUC_lnK_R_NX,dimRedResult-method}}, \code{\link{LCMC,dimRedResult-method}}, \code{\link{Q_NX,dimRedResult-method}}, \code{\link{Q_global,dimRedResult-method}}, \code{\link{Q_local,dimRedResult-method}}, \code{\link{R_NX,dimRedResult-method}}, \code{\link{cophenetic_correlation,dimRedResult-method}}, \code{\link{distance_correlation,dimRedResult-method}}, \code{\link{mean_R_NX,dimRedResult-method}}, \code{\link{plot_R_NX}()}, \code{\link{quality,dimRedResult-method}}, \code{\link{reconstruction_rmse,dimRedResult-method}}, \code{\link{total_correlation,dimRedResult-method}} } \author{ Guido Kraemer } \concept{Quality scores for dimensionality reduction} dimRed/man/DRR-class.Rd0000644000176200001440000001104214257545030014255 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/drr.R \docType{class} \name{DRR-class} \alias{DRR-class} \alias{DRR} \title{Dimensionality Reduction via Regression} \description{ An S4 Class implementing Dimensionality Reduction via Regression (DRR). } \details{ DRR is a non-linear extension of PCA that uses Kernel Ridge regression. } \section{Slots}{ \describe{ \item{\code{fun}}{A function that does the embedding and returns a dimRedResult object.} \item{\code{stdpars}}{The standard parameters for the function.} }} \section{General usage}{ Dimensionality reduction methods are S4 Classes that either be used directly, in which case they have to be initialized and a full list with parameters has to be handed to the \code{@fun()} slot, or the method name be passed to the embed function and parameters can be given to the \code{...}, in which case missing parameters will be replaced by the ones in the \code{@stdpars}. } \section{Parameters}{ DRR can take the following parameters: \describe{ \item{ndim}{The number of dimensions} \item{lambda}{The regularization parameter for the ridge regression.} \item{kernel}{The kernel to use for KRR, defaults to \code{"rbfdot"}.} \item{kernel.pars}{A list with kernel parameters, elements depend on the kernel used, \code{"rbfdot"} uses \code{"sigma"}.} \item{pca}{logical, should an initial pca step be performed, defaults to \code{TRUE}.} \item{pca.center}{logical, should the data be centered before the pca step. Defaults to \code{TRUE}.} \item{pca.scale}{logical, should the data be scaled before the pca ste. Defaults to \code{FALSE}.} \item{fastcv}{logical, should \code{\link[CVST]{fastCV}} from the CVST package be used instead of normal cross-validation.} \item{fastcv.test}{If \code{fastcv = TRUE}, separate test data set for fastcv.} \item{cv.folds}{if \code{fastcv = FALSE}, specifies the number of folds for crossvalidation.} \item{fastkrr.nblocks}{integer, higher values sacrifice numerical accuracy for speed and less memory, see below for details.} \item{verbose}{logical, should the cross-validation results be printed out.} } } \section{Implementation}{ Wraps around \code{\link[DRR]{drr}}, see there for details. DRR is a non-linear extension of principal components analysis using Kernel Ridge Regression (KRR, details see \code{\link[CVST]{constructKRRLearner}} and \code{\link[DRR]{constructFastKRRLearner}}). Non-linear regression is used to explain more variance than PCA. DRR provides an out-of-sample extension and a backward projection. The most expensive computations are matrix inversions therefore the implementation profits a lot from a multithreaded BLAS library. The best parameters for each KRR are determined by cross-validaton over all parameter combinations of \code{lambda} and \code{kernel.pars}, using less parameter values will speed up computation time. Calculation of KRR can be accelerated by increasing \code{fastkrr.nblocks}, it should be smaller than n^{1/3} up to sacrificing some accuracy, for details see \code{\link[DRR]{constructFastKRRLearner}}. Another way to speed up is to use \code{pars$fastcv = TRUE} which might provide a more efficient way to search the parameter space but may also miss the global maximum, I have not ran tests on the accuracy of this method. } \examples{ \dontrun{ if(requireNamespace(c("kernlab", "DRR"), quietly = TRUE)) { dat <- loadDataSet("variable Noise Helix", n = 200)[sample(200)] emb <- embed(dat, "DRR", ndim = 3) plot(dat, type = "3vars") plot(emb, type = "3vars") # We even have function to reconstruct, also working for only the first few dimensions rec <- inverse(emb, getData(getDimRedData(emb))[, 1, drop = FALSE]) plot(rec, type = "3vars") } } } \references{ Laparra, V., Malo, J., Camps-Valls, G., 2015. Dimensionality Reduction via Regression in Hyperspectral Imagery. IEEE Journal of Selected Topics in Signal Processing 9, 1026-1036. doi:10.1109/JSTSP.2015.2417833 } \seealso{ Other dimensionality reduction methods: \code{\link{AutoEncoder-class}}, \code{\link{DiffusionMaps-class}}, \code{\link{DrL-class}}, \code{\link{FastICA-class}}, \code{\link{FruchtermanReingold-class}}, \code{\link{HLLE-class}}, \code{\link{Isomap-class}}, \code{\link{KamadaKawai-class}}, \code{\link{MDS-class}}, \code{\link{NNMF-class}}, \code{\link{PCA-class}}, \code{\link{PCA_L1-class}}, \code{\link{UMAP-class}}, \code{\link{dimRedMethod-class}}, \code{\link{dimRedMethodList}()}, \code{\link{kPCA-class}}, \code{\link{nMDS-class}}, \code{\link{tSNE-class}} } \concept{dimensionality reduction methods} dimRed/man/nMDS-class.Rd0000644000176200001440000000420614262545370014436 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/nmds.R \docType{class} \name{nMDS-class} \alias{nMDS-class} \alias{nMDS} \title{Non-Metric Dimensional Scaling} \description{ An S4 Class implementing Non-Metric Dimensional Scaling. } \details{ A non-linear extension of MDS using monotonic regression } \section{Slots}{ \describe{ \item{\code{fun}}{A function that does the embedding and returns a dimRedResult object.} \item{\code{stdpars}}{The standard parameters for the function.} }} \section{General usage}{ Dimensionality reduction methods are S4 Classes that either be used directly, in which case they have to be initialized and a full list with parameters has to be handed to the \code{@fun()} slot, or the method name be passed to the embed function and parameters can be given to the \code{...}, in which case missing parameters will be replaced by the ones in the \code{@stdpars}. } \section{Parameters}{ nMDS can take the following parameters: \describe{ \item{d}{A distance function.} \item{ndim}{The number of embedding dimensions.} } } \section{Implementation}{ Wraps around the \code{\link[vegan]{monoMDS}}. For parameters that are not available here, the standard configuration is used. } \examples{ if(requireNamespace("vegan", quietly = TRUE)) { dat <- loadDataSet("3D S Curve", n = 300) emb <- embed(dat, "nMDS") plot(emb, type = "2vars") } } \references{ Kruskal, J.B., 1964. Nonmetric multidimensional scaling: A numerical method. Psychometrika 29, 115-129. https://doi.org/10.1007/BF02289694 } \seealso{ Other dimensionality reduction methods: \code{\link{AutoEncoder-class}}, \code{\link{DRR-class}}, \code{\link{DiffusionMaps-class}}, \code{\link{DrL-class}}, \code{\link{FastICA-class}}, \code{\link{FruchtermanReingold-class}}, \code{\link{HLLE-class}}, \code{\link{Isomap-class}}, \code{\link{KamadaKawai-class}}, \code{\link{MDS-class}}, \code{\link{NNMF-class}}, \code{\link{PCA-class}}, \code{\link{PCA_L1-class}}, \code{\link{UMAP-class}}, \code{\link{dimRedMethod-class}}, \code{\link{dimRedMethodList}()}, \code{\link{kPCA-class}}, \code{\link{tSNE-class}} } \concept{dimensionality reduction methods} dimRed/man/PCA-class.Rd0000644000176200001440000000521414257545030014235 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/pca.R \docType{class} \name{PCA-class} \alias{PCA-class} \alias{PCA} \title{Principal Component Analysis} \description{ S4 Class implementing PCA. } \details{ PCA transforms the data in orthogonal components so that the first axis accounts for the larges variance in the data, all the following axes account for the highest variance under the constraint that they are orthogonal to the preceding axes. PCA is sensitive to the scaling of the variables. PCA is by far the fastest and simples method of dimensionality reduction and should probably always be applied as a baseline if other methods are tested. } \section{Slots}{ \describe{ \item{\code{fun}}{A function that does the embedding and returns a dimRedResult object.} \item{\code{stdpars}}{The standard parameters for the function.} }} \section{General usage}{ Dimensionality reduction methods are S4 Classes that either be used directly, in which case they have to be initialized and a full list with parameters has to be handed to the \code{@fun()} slot, or the method name be passed to the embed function and parameters can be given to the \code{...}, in which case missing parameters will be replaced by the ones in the \code{@stdpars}. } \section{Parameters}{ PCA can take the following parameters: \describe{ \item{ndim}{The number of output dimensions.} \item{center}{logical, should the data be centered, defaults to \code{TRUE}.} \item{scale.}{logical, should the data be scaled, defaults to \code{FALSE}.} } } \section{Implementation}{ Wraps around \code{\link{prcomp}}. Because PCA can be reduced to a simple rotation, forward and backward projection functions are supplied. } \examples{ dat <- loadDataSet("Iris") emb <- embed(dat, "PCA") plot(emb, type = "2vars") if(requireNamespace("scatterplot3d", quietly = TRUE)) plot(inverse(emb, getDimRedData(emb)), type = "3vars") } \references{ Pearson, K., 1901. On lines and planes of closest fit to systems of points in space. Philosophical Magazine 2, 559-572. } \seealso{ Other dimensionality reduction methods: \code{\link{AutoEncoder-class}}, \code{\link{DRR-class}}, \code{\link{DiffusionMaps-class}}, \code{\link{DrL-class}}, \code{\link{FastICA-class}}, \code{\link{FruchtermanReingold-class}}, \code{\link{HLLE-class}}, \code{\link{Isomap-class}}, \code{\link{KamadaKawai-class}}, \code{\link{MDS-class}}, \code{\link{NNMF-class}}, \code{\link{PCA_L1-class}}, \code{\link{UMAP-class}}, \code{\link{dimRedMethod-class}}, \code{\link{dimRedMethodList}()}, \code{\link{kPCA-class}}, \code{\link{nMDS-class}}, \code{\link{tSNE-class}} } \concept{dimensionality reduction methods} dimRed/man/dimRedResult-class.Rd0000644000176200001440000000760014255350572016241 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/dimRedResult-class.R \docType{class} \name{dimRedResult-class} \alias{dimRedResult-class} \alias{dimRedResult} \alias{predict,dimRedResult-method} \alias{inverse,dimRedResult-method} \alias{inverse} \alias{as.data.frame,dimRedResult-method} \alias{getPars,dimRedResult-method} \alias{getNDim,dimRedResult-method} \alias{print,dimRedResult-method} \alias{getOrgData,dimRedResult-method} \alias{getDimRedData,dimRedResult-method} \alias{ndims,dimRedResult-method} \alias{getOtherData,dimRedResult-method} \title{Class "dimRedResult"} \usage{ \S4method{predict}{dimRedResult}(object, xnew) \S4method{inverse}{dimRedResult}(object, ynew) \S4method{as.data.frame}{dimRedResult}( x, org.data.prefix = "org.", meta.prefix = "meta.", data.prefix = "" ) \S4method{getPars}{dimRedResult}(object) \S4method{getNDim}{dimRedResult}(object) \S4method{print}{dimRedResult}(x) \S4method{getOrgData}{dimRedResult}(object) \S4method{getDimRedData}{dimRedResult}(object) \S4method{ndims}{dimRedResult}(object) \S4method{getOtherData}{dimRedResult}(object) } \arguments{ \item{object}{Of class \code{dimRedResult}} \item{xnew}{new data, of type \code{\link{dimRedData}}} \item{ynew}{embedded data, of type \code{\link{dimRedData}}} \item{x}{Of class \code{dimRedResult}} \item{org.data.prefix}{Prefix for the columns of the org.data slot.} \item{meta.prefix}{Prefix for the columns of \code{x@data@meta}.} \item{data.prefix}{Prefix for the columns of \code{x@data@data}.} } \description{ A class to hold the results of of a dimensionality reduction. } \section{Methods (by generic)}{ \itemize{ \item \code{predict}: apply a trained method to new data, does not work with all methods, will give an error if there is no \code{apply}. In some cases the apply function may only be an approximation. \item \code{inverse}: inverse transformation of embedded data, does not work with all methods, will give an error if there is no \code{inverse}. In some cases the apply function may only be an approximation. \item \code{as.data.frame}: convert to \code{data.frame} \item \code{getPars}: Get the parameters with which the method was called. \item \code{getNDim}: Get the number of embedding dimensions. \item \code{print}: Method for printing. \item \code{getOrgData}: Get the original data and meta.data \item \code{getDimRedData}: Get the embedded data \item \code{ndims}: Extract the number of embedding dimensions. \item \code{getOtherData}: Get other data produced by the method }} \section{Slots}{ \describe{ \item{\code{data}}{Output data of class dimRedData.} \item{\code{org.data}}{original data, a matrix.} \item{\code{apply}}{a function to apply the method to out-of-sampledata, may not exist.} \item{\code{inverse}}{a function to calculate the original coordinates from reduced space, may not exist.} \item{\code{has.org.data}}{logical, if the original data is included in the object.} \item{\code{has.apply}}{logical, if a forward method is exists.} \item{\code{has.inverse}}{logical if an inverse method exists.} \item{\code{method}}{saves the method used.} \item{\code{pars}}{saves the parameters used.} \item{\code{other.data}}{other data produced by the method, e.g. a distance matrix.} }} \examples{ ## Create object by embedding data iris.pca <- embed(loadDataSet("Iris"), "PCA") ## Convert the result to a data.frame head(as(iris.pca, "data.frame")) head(as.data.frame(iris.pca)) ## There are no nameclashes to avoid here: head(as.data.frame(iris.pca, org.data.prefix = "", meta.prefix = "", data.prefix = "")) ## Print it more or less nicely: print(iris.pca) ## Get the embedded data as a dimRedData object: getDimRedData(iris.pca) ## Get the original data including meta information: getOrgData(iris.pca) ## Get the number of variables: ndims(iris.pca) } \concept{dimRedResult} dimRed/man/ndims.Rd0000644000176200001440000000050614255350572013643 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/misc.R \name{ndims} \alias{ndims} \title{Method ndims} \usage{ ndims(object, ...) } \arguments{ \item{object}{To extract the number of dimensions from.} \item{...}{Arguments for further methods} } \description{ Extract the number of dimensions. } dimRed/man/NNMF-class.Rd0000644000176200001440000000551314262545141014371 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/nnmf.R \docType{class} \name{NNMF-class} \alias{NNMF-class} \alias{NNMF} \title{Non-Negative Matrix Factorization} \description{ S4 Class implementing NNMF. } \details{ NNMF is a method for decomposing a matrix into a smaller dimension such that the constraint that the data (and the projection) are not negative is taken into account. } \section{Slots}{ \describe{ \item{\code{fun}}{A function that does the embedding and returns a dimRedResult object.} \item{\code{stdpars}}{The standard parameters for the function.} }} \section{General usage}{ Dimensionality reduction methods are S4 Classes that either be used directly, in which case they have to be initialized and a full list with parameters has to be handed to the \code{@fun()} slot, or the method name be passed to the embed function and parameters can be given to the \code{...}, in which case missing parameters will be replaced by the ones in the \code{@stdpars}. } \section{Parameters}{ The method can take the following parameters: \describe{ \item{ndim}{The number of output dimensions.} \item{method}{character, which algorithm should be used. See \code{\link[NMF]{nmf}} for possible values. Defaults to "brunet"} \item{nrun}{integer, the number of times the computations are conducted. See \code{\link[NMF]{nmf}}} \item{seed}{integer, a value to control the random numbers used.} \item{options}{named list, other options to pass to \code{\link[NMF]{nmf}}} } } \section{Implementation}{ Wraps around \code{\link[NMF]{nmf}}. Note that the estimation uses random numbers. To create reproducible results, set the random number seed in the function call. Also, in many cases, the computations will be conducted in parallel using multiple cores. To disable this, use the option \code{.pbackend = NULL}. } \examples{ if(requireNamespace(c("NNMF", "MASS"), quietly = TRUE)) { set.seed(4646) dat <- loadDataSet("Iris") emb <- embed(dat, "NNMF") plot(emb) # project new values: nn_proj <- predict(emb, dat[1:7]) plot(nn_proj) } } \references{ Lee, D.D., Seung, H.S., 1999. Learning the parts of objects by non-negative matrix factorization. Nature 401, 788-791. https://doi.org/10.1038/44565 } \seealso{ Other dimensionality reduction methods: \code{\link{AutoEncoder-class}}, \code{\link{DRR-class}}, \code{\link{DiffusionMaps-class}}, \code{\link{DrL-class}}, \code{\link{FastICA-class}}, \code{\link{FruchtermanReingold-class}}, \code{\link{HLLE-class}}, \code{\link{Isomap-class}}, \code{\link{KamadaKawai-class}}, \code{\link{MDS-class}}, \code{\link{PCA-class}}, \code{\link{PCA_L1-class}}, \code{\link{UMAP-class}}, \code{\link{dimRedMethod-class}}, \code{\link{dimRedMethodList}()}, \code{\link{kPCA-class}}, \code{\link{nMDS-class}}, \code{\link{tSNE-class}} } \concept{dimensionality reduction methods} dimRed/man/Q_NX-dimRedResult-method.Rd0000644000176200001440000000231114255350573017212 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/quality.R \name{Q_NX,dimRedResult-method} \alias{Q_NX,dimRedResult-method} \alias{Q_NX} \title{Method Q_NX} \usage{ \S4method{Q_NX}{dimRedResult}(object) } \arguments{ \item{object}{of class dimRedResult} } \description{ Calculate the Q_NX score (Chen & Buja 2006, the notation in the publication is M_k). Which is the fraction of points that remain inside the same K-ary neighborhood in high and low dimensional space. } \seealso{ Other Quality scores for dimensionality reduction: \code{\link{AUC_lnK_R_NX,dimRedResult-method}}, \code{\link{LCMC,dimRedResult-method}}, \code{\link{Q_global,dimRedResult-method}}, \code{\link{Q_local,dimRedResult-method}}, \code{\link{R_NX,dimRedResult-method}}, \code{\link{cophenetic_correlation,dimRedResult-method}}, \code{\link{distance_correlation,dimRedResult-method}}, \code{\link{mean_R_NX,dimRedResult-method}}, \code{\link{plot_R_NX}()}, \code{\link{quality,dimRedResult-method}}, \code{\link{reconstruction_error,dimRedResult-method}}, \code{\link{reconstruction_rmse,dimRedResult-method}}, \code{\link{total_correlation,dimRedResult-method}} } \concept{Quality scores for dimensionality reduction} dimRed/man/Q_local-dimRedResult-method.Rd0000644000176200001440000000230714255350572017763 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/quality.R \name{Q_local,dimRedResult-method} \alias{Q_local,dimRedResult-method} \alias{Q_local} \title{Method Q_local} \usage{ \S4method{Q_local}{dimRedResult}(object, ndim = getNDim(object)) } \arguments{ \item{object}{of class dimRedResult.} \item{ndim}{use the first ndim columns of the embedded data for calculation.} } \description{ Calculate the Q_local score to assess the quality of a dimensionality reduction. } \seealso{ Other Quality scores for dimensionality reduction: \code{\link{AUC_lnK_R_NX,dimRedResult-method}}, \code{\link{LCMC,dimRedResult-method}}, \code{\link{Q_NX,dimRedResult-method}}, \code{\link{Q_global,dimRedResult-method}}, \code{\link{R_NX,dimRedResult-method}}, \code{\link{cophenetic_correlation,dimRedResult-method}}, \code{\link{distance_correlation,dimRedResult-method}}, \code{\link{mean_R_NX,dimRedResult-method}}, \code{\link{plot_R_NX}()}, \code{\link{quality,dimRedResult-method}}, \code{\link{reconstruction_error,dimRedResult-method}}, \code{\link{reconstruction_rmse,dimRedResult-method}}, \code{\link{total_correlation,dimRedResult-method}} } \concept{Quality scores for dimensionality reduction} dimRed/man/dimRedMethodList.Rd0000644000176200001440000000235014256653702015733 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/dimRedMethod-class.R \name{dimRedMethodList} \alias{dimRedMethodList} \title{dimRedMethodList} \usage{ dimRedMethodList(filter = FALSE) } \arguments{ \item{filter}{filter methods by methods that have their dependencies installed} } \value{ a character vector with the names of classes that inherit from \code{dimRedMethod}. } \description{ Get the names of all methods for dimensionality reduction. } \details{ Returns the name of all classes that inherit from \code{\link{dimRedMethod-class}} to use with \code{\link{embed}}. } \examples{ dimRedMethodList() } \seealso{ Other dimensionality reduction methods: \code{\link{AutoEncoder-class}}, \code{\link{DRR-class}}, \code{\link{DiffusionMaps-class}}, \code{\link{DrL-class}}, \code{\link{FastICA-class}}, \code{\link{FruchtermanReingold-class}}, \code{\link{HLLE-class}}, \code{\link{Isomap-class}}, \code{\link{KamadaKawai-class}}, \code{\link{MDS-class}}, \code{\link{NNMF-class}}, \code{\link{PCA-class}}, \code{\link{PCA_L1-class}}, \code{\link{UMAP-class}}, \code{\link{dimRedMethod-class}}, \code{\link{kPCA-class}}, \code{\link{nMDS-class}}, \code{\link{tSNE-class}} } \concept{dimensionality reduction methods} dimRed/man/getData.Rd0000644000176200001440000000040614255350572014101 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/misc.R \name{getData} \alias{getData} \title{Method getData} \usage{ getData(object) } \arguments{ \item{object}{The object to be converted.} } \description{ Extracts the data slot. } dimRed/man/getMeta.Rd0000644000176200001440000000045114255350572014116 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/misc.R \name{getMeta} \alias{getMeta} \title{Method getMeta} \usage{ getMeta(object, ...) } \arguments{ \item{object}{The object to be converted.} \item{...}{other arguments.} } \description{ Extracts the meta slot. } dimRed/man/MDS-class.Rd0000644000176200001440000000506214255350572014261 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/mds.R \docType{class} \name{MDS-class} \alias{MDS-class} \alias{MDS} \title{Metric Dimensional Scaling} \description{ An S4 Class implementing classical scaling (MDS). } \details{ MDS tries to maintain distances in high- and low-dimensional space, it has the advantage over PCA that arbitrary distance functions can be used, but it is computationally more demanding. } \section{Slots}{ \describe{ \item{\code{fun}}{A function that does the embedding and returns a dimRedResult object.} \item{\code{stdpars}}{The standard parameters for the function.} }} \section{General usage}{ Dimensionality reduction methods are S4 Classes that either be used directly, in which case they have to be initialized and a full list with parameters has to be handed to the \code{@fun()} slot, or the method name be passed to the embed function and parameters can be given to the \code{...}, in which case missing parameters will be replaced by the ones in the \code{@stdpars}. } \section{Parameters}{ MDS can take the following parameters: \describe{ \item{ndim}{The number of dimensions.} \item{d}{The function to calculate the distance matrix from the input coordinates, defaults to euclidean distances.} } } \section{Implementation}{ Wraps around \code{\link[stats]{cmdscale}}. The implementation also provides an out-of-sample extension which is not completely optimized yet. } \examples{ \dontrun{ dat <- loadDataSet("3D S Curve") emb <- embed(dat, "MDS") plot(emb, type = "2vars") # a "manual" kPCA: emb2 <- embed(dat, "MDS", d = function(x) exp(stats::dist(x))) plot(emb2, type = "2vars") # a "manual", more customizable, and slower Isomap: emb3 <- embed(dat, "MDS", d = function(x) vegan::isomapdist(vegan::vegdist(x, "manhattan"), k = 20)) plot(emb3) } } \references{ Torgerson, W.S., 1952. Multidimensional scaling: I. Theory and method. Psychometrika 17, 401-419. https://doi.org/10.1007/BF02288916 } \seealso{ Other dimensionality reduction methods: \code{\link{AutoEncoder-class}}, \code{\link{DRR-class}}, \code{\link{DiffusionMaps-class}}, \code{\link{DrL-class}}, \code{\link{FastICA-class}}, \code{\link{FruchtermanReingold-class}}, \code{\link{HLLE-class}}, \code{\link{Isomap-class}}, \code{\link{KamadaKawai-class}}, \code{\link{NNMF-class}}, \code{\link{PCA-class}}, \code{\link{PCA_L1-class}}, \code{\link{UMAP-class}}, \code{\link{dimRedMethod-class}}, \code{\link{dimRedMethodList}()}, \code{\link{kPCA-class}}, \code{\link{nMDS-class}}, \code{\link{tSNE-class}} } \concept{dimensionality reduction methods} dimRed/man/dimRed-package.Rd0000644000176200001440000000275714255350572015340 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/dimRed.R \docType{package} \name{dimRed-package} \alias{dimRed} \alias{dimRed-package} \title{The dimRed package} \description{ This package simplifies dimensionality reduction in R by providing a framework of S4 classes and methods. dimRed collects dimensionality reduction methods that are implemented in R and implements others. It gives them a common interface and provides plotting functions for visualization and functions for quality assessment. Funding provided by the Department for Biogeochemical Integration, Empirical Inference of the Earth System Group, at the Max Plack Institute for Biogeochemistry, Jena. } \references{ Lee, J.A., Renard, E., Bernard, G., Dupont, P., Verleysen, M., 2013. Type 1 and 2 mixtures of Kullback-Leibler divergences as cost functions in dimensionality reduction based on similarity preservation. Neurocomputing. 112, 92-107. doi:10.1016/j.neucom.2012.12.036 Lee, J.A., Lee, J.A., Verleysen, M., 2008. Rank-based quality assessment of nonlinear dimensionality reduction. Proceedings of ESANN 2008 49-54. Chen, L., Buja, A., 2006. Local Multidimensional Scaling for Nonlinear Dimension Reduction, Graph Layout and Proximity Analysis. } \seealso{ Useful links: \itemize{ \item \url{https://www.guido-kraemer.com/software/dimred/} \item Report bugs at \url{https://github.com/gdkrmr/dimRed/issues} } } \author{ \strong{Maintainer}: Guido Kraemer \email{guido.kraemer@uni-leipzig.de} } dimRed/man/makeKNNgraph.Rd0000644000176200001440000000141514255350572015037 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/misc.R \name{makeKNNgraph} \alias{makeKNNgraph} \title{makeKNNgraph} \usage{ makeKNNgraph(x, k, eps = 0, diag = FALSE) } \arguments{ \item{x}{data, a matrix, observations in rows, dimensions in columns} \item{k}{the number of nearest neighbors.} \item{eps}{number, if \code{eps > 0} the KNN search is approximate, see \code{\link[RANN]{nn2}}} \item{diag}{logical, if \code{TRUE} every edge of the returned graph will have an edge with weight \code{0} to itself.} } \value{ an object of type \code{\link[igraph]{igraph}} with edge weight being the distances. } \description{ Create a K-nearest neighbor graph from data x. Uses \code{\link[RANN]{nn2}} as a fast way to find the neares neighbors. } dimRed/man/getOrgData.Rd0000644000176200001440000000047514255350572014557 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/misc.R \name{getOrgData} \alias{getOrgData} \title{Method getOrgData} \usage{ getOrgData(object, ...) } \arguments{ \item{object}{The object to extract data from.} \item{...}{other arguments.} } \description{ Extract the Original data. } dimRed/man/as.dimRedData.Rd0000644000176200001440000000174614255350572015140 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/misc.R, R/dimRedData-class.R \name{as.dimRedData} \alias{as.dimRedData} \alias{as.dimRedData,formula-method} \title{Converts to dimRedData} \usage{ as.dimRedData(formula, ...) \S4method{as.dimRedData}{formula}(formula, data) } \arguments{ \item{formula}{The formula, left hand side is assigned to the meta slot right hand side is assigned to the data slot.} \item{...}{other arguments.} \item{data}{Will be coerced into a \code{\link{data.frame}} with \code{\link{as.data.frame}}} } \description{ Conversion functions to dimRedData. } \section{Methods (by class)}{ \itemize{ \item \code{formula}: Convert a \code{data.frame} to a dimRedData object using a formula }} \examples{ ## create a dimRedData object using a formula as.dimRedData(Species ~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width, iris)[1:5] } \seealso{ Other dimRedData: \code{\link{dimRedData-class}} } \concept{dimRedData} dimRed/man/DrL-class.Rd0000644000176200001440000000511514257375355014326 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/graph_embed.R \docType{class} \name{DrL-class} \alias{DrL-class} \alias{DrL} \title{Distributed Recursive Graph Layout} \description{ An S4 Class implementing Distributed recursive Graph Layout. } \details{ DrL uses a complex algorithm to avoid local minima in the graph embedding which uses several steps. } \section{Slots}{ \describe{ \item{\code{fun}}{A function that does the embedding and returns a dimRedResult object.} \item{\code{stdpars}}{The standard parameters for the function.} }} \section{General usage}{ Dimensionality reduction methods are S4 Classes that either be used directly, in which case they have to be initialized and a full list with parameters has to be handed to the \code{@fun()} slot, or the method name be passed to the embed function and parameters can be given to the \code{...}, in which case missing parameters will be replaced by the ones in the \code{@stdpars}. } \section{Parameters}{ DrL can take the following parameters: \describe{ \item{ndim}{The number of dimensions, defaults to 2. Can only be 2 or 3} \item{knn}{Reduce the graph to keep only the neares neighbors. Defaults to 100.} \item{d}{The distance function to determine the weights of the graph edges. Defaults to euclidean distances.} } } \section{Implementation}{ Wraps around \code{\link[igraph]{layout_with_drl}}. The parameters maxiter, epsilon and kkconst are set to the default values and cannot be set, this may change in a future release. The DimRed Package adds an extra sparsity parameter by constructing a knn graph which also may improve visualization quality. } \examples{ \dontrun{ if(requireNamespace(c("igraph", "coRanking"), quietly = TRUE)) { dat <- loadDataSet("Swiss Roll", n = 200) emb <- embed(dat, "DrL") plot(emb, type = "2vars") } } } \references{ Martin, S., Brown, W.M., Wylie, B.N., 2007. Dr.l: Distributed Recursive (graph) Layout (No. dRl; 002182MLTPL00). Sandia National Laboratories. } \seealso{ Other dimensionality reduction methods: \code{\link{AutoEncoder-class}}, \code{\link{DRR-class}}, \code{\link{DiffusionMaps-class}}, \code{\link{FastICA-class}}, \code{\link{FruchtermanReingold-class}}, \code{\link{HLLE-class}}, \code{\link{Isomap-class}}, \code{\link{KamadaKawai-class}}, \code{\link{MDS-class}}, \code{\link{NNMF-class}}, \code{\link{PCA-class}}, \code{\link{PCA_L1-class}}, \code{\link{UMAP-class}}, \code{\link{dimRedMethod-class}}, \code{\link{dimRedMethodList}()}, \code{\link{kPCA-class}}, \code{\link{nMDS-class}}, \code{\link{tSNE-class}} } \concept{dimensionality reduction methods} dimRed/man/as.data.frame.Rd0000644000176200001440000000124214255350572015133 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/misc.R \name{as.data.frame} \alias{as.data.frame} \title{Converts to data.frame} \usage{ as.data.frame(x, row.names, optional, ...) } \arguments{ \item{x}{The object to be converted} \item{row.names}{unused in \code{dimRed}} \item{optional}{unused in \code{dimRed}} \item{...}{other arguments.} } \description{ General conversions of objects created by \code{dimRed} to \code{data.frame}. See class documentations for details (\code{\link{dimRedData}}, \code{\link{dimRedResult}}). For the documentation of this function in base package, see here: \code{\link[base]{as.data.frame.default}}. } dimRed/man/plot.Rd0000644000176200001440000000433314256656253013517 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/plot.R \name{plot} \alias{plot} \alias{plot.dimRed} \alias{plot,dimRedData,ANY-method} \alias{plot.dimRedData} \alias{plot,dimRedResult,ANY-method} \alias{plot.dimRedResult} \title{Plotting of dimRed* objects} \usage{ plot(x, y, ...) \S4method{plot}{dimRedData,ANY}( x, type = "pairs", vars = seq_len(ncol(x@data)), col = seq_len(min(3, ncol(x@meta))), ... ) \S4method{plot}{dimRedResult,ANY}( x, type = "pairs", vars = seq_len(ncol(x@data@data)), col = seq_len(min(3, ncol(x@data@meta))), ... ) } \arguments{ \item{x}{dimRedResult/dimRedData class, e.g. output of embedded/loadDataSet} \item{y}{Ignored} \item{...}{handed over to the underlying plotting function.} \item{type}{plot type, one of \code{c("pairs", "parpl", "2vars", "3vars", "3varsrgl")}} \item{vars}{the axes of the embedding to use for plotting} \item{col}{the columns of the meta slot to use for coloring, can be referenced as the column names or number of x@data} } \description{ Plots a object of class dimRedResult and dimRedData. For the documentation of the plotting function in base see here: \code{\link{plot.default}}. } \details{ Plotting functions for the classes usind in \code{dimRed}. they are intended to give a quick overview over the results, so they are somewhat inflexible, e.g. it is hard to modify color scales or plotting parameters. If you require more control over plotting, it is better to convert the object to a \code{data.frame} first and use the standard functions for plotting. } \section{Methods (by class)}{ \itemize{ \item \code{x = dimRedData,y = ANY}: Ploting of dimRedData objects \item \code{x = dimRedResult,y = ANY}: Ploting of dimRedResult objects. }} \examples{ scurve = loadDataSet("3D S Curve") if(requireNamespace("graphics", quietly = TRUE)) plot(scurve, type = "pairs", main = "pairs plot of S curve") if(requireNamespace("MASS", quietly = TRUE)) plot(scurve, type = "parpl") if(requireNamespace("graphics", quietly = TRUE)) plot(scurve, type = "2vars", vars = c("y", "z")) if(requireNamespace("scatterplot3d", quietly = TRUE)) plot(scurve, type = "3vars") if(requireNamespace("rgl", quietly = TRUE)) plot(scurve, type = "3varsrgl") } dimRed/man/reconstruction_rmse-dimRedResult-method.Rd0000644000176200001440000000227014255350573022520 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/quality.R \name{reconstruction_rmse,dimRedResult-method} \alias{reconstruction_rmse,dimRedResult-method} \alias{reconstruction_rmse} \title{Method reconstruction_rmse} \usage{ \S4method{reconstruction_rmse}{dimRedResult}(object) } \arguments{ \item{object}{of class dimRedResult} } \description{ Calculate the reconstruction root mean squared error a dimensionality reduction, the method must have an inverse mapping. } \seealso{ Other Quality scores for dimensionality reduction: \code{\link{AUC_lnK_R_NX,dimRedResult-method}}, \code{\link{LCMC,dimRedResult-method}}, \code{\link{Q_NX,dimRedResult-method}}, \code{\link{Q_global,dimRedResult-method}}, \code{\link{Q_local,dimRedResult-method}}, \code{\link{R_NX,dimRedResult-method}}, \code{\link{cophenetic_correlation,dimRedResult-method}}, \code{\link{distance_correlation,dimRedResult-method}}, \code{\link{mean_R_NX,dimRedResult-method}}, \code{\link{plot_R_NX}()}, \code{\link{quality,dimRedResult-method}}, \code{\link{reconstruction_error,dimRedResult-method}}, \code{\link{total_correlation,dimRedResult-method}} } \concept{Quality scores for dimensionality reduction} dimRed/man/FruchtermanReingold-class.Rd0000644000176200001440000000457414262545370017607 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/graph_embed.R \docType{class} \name{FruchtermanReingold-class} \alias{FruchtermanReingold-class} \alias{FruchtermanReingold} \title{Fruchterman Reingold Graph Layout} \description{ An S4 Class implementing the Fruchterman Reingold Graph Layout algorithm. } \section{Slots}{ \describe{ \item{\code{fun}}{A function that does the embedding and returns a dimRedResult object.} \item{\code{stdpars}}{The standard parameters for the function.} }} \section{General usage}{ Dimensionality reduction methods are S4 Classes that either be used directly, in which case they have to be initialized and a full list with parameters has to be handed to the \code{@fun()} slot, or the method name be passed to the embed function and parameters can be given to the \code{...}, in which case missing parameters will be replaced by the ones in the \code{@stdpars}. } \section{Parameters}{ \describe{ \item{ndim}{The number of dimensions, defaults to 2. Can only be 2 or 3} \item{knn}{Reduce the graph to keep only the neares neighbors. Defaults to 100.} \item{d}{The distance function to determine the weights of the graph edges. Defaults to euclidean distances.} } } \section{Implementation}{ Wraps around \code{\link[igraph]{layout_with_fr}}, see there for details. The Fruchterman Reingold algorithm puts the data into a circle and puts connected points close to each other. } \examples{ if(requireNamespace(c("igraph", "coRanking"), quietly = TRUE)) { dat <- loadDataSet("Swiss Roll", n = 100) emb <- embed(dat, "FruchtermanReingold") plot(emb, type = "2vars") } } \references{ Fruchterman, T.M.J., Reingold, E.M., 1991. Graph drawing by force-directed placement. Softw: Pract. Exper. 21, 1129-1164. https://doi.org/10.1002/spe.4380211102 } \seealso{ Other dimensionality reduction methods: \code{\link{AutoEncoder-class}}, \code{\link{DRR-class}}, \code{\link{DiffusionMaps-class}}, \code{\link{DrL-class}}, \code{\link{FastICA-class}}, \code{\link{HLLE-class}}, \code{\link{Isomap-class}}, \code{\link{KamadaKawai-class}}, \code{\link{MDS-class}}, \code{\link{NNMF-class}}, \code{\link{PCA-class}}, \code{\link{PCA_L1-class}}, \code{\link{UMAP-class}}, \code{\link{dimRedMethod-class}}, \code{\link{dimRedMethodList}()}, \code{\link{kPCA-class}}, \code{\link{nMDS-class}}, \code{\link{tSNE-class}} } \concept{dimensionality reduction methods} dimRed/man/print.Rd0000644000176200001440000000047714255350572013674 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/misc.R \name{print} \alias{print} \title{Method print} \usage{ print(x, ...) } \arguments{ \item{x}{The object to be printed.} \item{...}{Other arguments for printing.} } \description{ Imports the print method into the package namespace. } dimRed/man/plot_R_NX.Rd0000644000176200001440000000441714257370067014405 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/plot.R \name{plot_R_NX} \alias{plot_R_NX} \title{plot_R_NX} \usage{ plot_R_NX(x, ndim = NA, weight = "inv") } \arguments{ \item{x}{a list of \code{\link{dimRedResult}} objects. The names of the list will appear in the legend with the AUC_lnK value.} \item{ndim}{the number of dimensions, if \code{NA} the original number of embedding dimensions is used, can be a vector giving the embedding dimensionality for each single list element of \code{x}.} \item{weight}{the weight function used for K when calculating the AUC, one of \code{c("inv", "log", "log10")}} } \value{ A ggplot object, the design can be changed by appending \code{theme(...)} } \description{ Plot the R_NX curve for different embeddings. Takes a list of \code{\link{dimRedResult}} objects as input. Also the Area under the curve values are computed for a weighted K (see \link{AUC_lnK_R_NX} for details) and appear in the legend. } \examples{ if(requireNamespace(c("RSpectra", "igraph", "RANN", "ggplot", "tidyr", "scales"), quietly = TRUE)) { ## define which methods to apply embed_methods <- c("Isomap", "PCA") ## load test data set data_set <- loadDataSet("3D S Curve", n = 200) ## apply dimensionality reduction data_emb <- lapply(embed_methods, function(x) embed(data_set, x)) names(data_emb) <- embed_methods ## plot the R_NX curves: plot_R_NX(data_emb) + ggplot2::theme(legend.title = ggplot2::element_blank(), legend.position = c(0.5, 0.1), legend.justification = c(0.5, 0.1)) } } \seealso{ Other Quality scores for dimensionality reduction: \code{\link{AUC_lnK_R_NX,dimRedResult-method}}, \code{\link{LCMC,dimRedResult-method}}, \code{\link{Q_NX,dimRedResult-method}}, \code{\link{Q_global,dimRedResult-method}}, \code{\link{Q_local,dimRedResult-method}}, \code{\link{R_NX,dimRedResult-method}}, \code{\link{cophenetic_correlation,dimRedResult-method}}, \code{\link{distance_correlation,dimRedResult-method}}, \code{\link{mean_R_NX,dimRedResult-method}}, \code{\link{quality,dimRedResult-method}}, \code{\link{reconstruction_error,dimRedResult-method}}, \code{\link{reconstruction_rmse,dimRedResult-method}}, \code{\link{total_correlation,dimRedResult-method}} } \concept{Quality scores for dimensionality reduction} dimRed/man/FastICA-class.Rd0000644000176200001440000000455014257366205015053 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/fastica.R \docType{class} \name{FastICA-class} \alias{FastICA-class} \alias{FastICA} \title{Independent Component Analysis} \description{ An S4 Class implementing the FastICA algorithm for Indepentend Component Analysis. } \details{ ICA is used for blind signal separation of different sources. It is a linear Projection. } \section{Slots}{ \describe{ \item{\code{fun}}{A function that does the embedding and returns a dimRedResult object.} \item{\code{stdpars}}{The standard parameters for the function.} }} \section{General usage}{ Dimensionality reduction methods are S4 Classes that either be used directly, in which case they have to be initialized and a full list with parameters has to be handed to the \code{@fun()} slot, or the method name be passed to the embed function and parameters can be given to the \code{...}, in which case missing parameters will be replaced by the ones in the \code{@stdpars}. } \section{Parameters}{ FastICA can take the following parameters: \describe{ \item{ndim}{The number of output dimensions. Defaults to \code{2}} } } \section{Implementation}{ Wraps around \code{\link[fastICA]{fastICA}}. FastICA uses a very fast approximation for negentropy to estimate statistical independences between signals. Because it is a simple rotation/projection, forward and backward functions can be given. } \examples{ if(requireNamespace("fastICA", quietly = TRUE)) { dat <- loadDataSet("3D S Curve") emb <- embed(dat, "FastICA", ndim = 2) plot(getData(getDimRedData(emb))) } } \references{ Hyvarinen, A., 1999. Fast and robust fixed-point algorithms for independent component analysis. IEEE Transactions on Neural Networks 10, 626-634. https://doi.org/10.1109/72.761722 } \seealso{ Other dimensionality reduction methods: \code{\link{AutoEncoder-class}}, \code{\link{DRR-class}}, \code{\link{DiffusionMaps-class}}, \code{\link{DrL-class}}, \code{\link{FruchtermanReingold-class}}, \code{\link{HLLE-class}}, \code{\link{Isomap-class}}, \code{\link{KamadaKawai-class}}, \code{\link{MDS-class}}, \code{\link{NNMF-class}}, \code{\link{PCA-class}}, \code{\link{PCA_L1-class}}, \code{\link{UMAP-class}}, \code{\link{dimRedMethod-class}}, \code{\link{dimRedMethodList}()}, \code{\link{kPCA-class}}, \code{\link{nMDS-class}}, \code{\link{tSNE-class}} } \concept{dimensionality reduction methods} dimRed/DESCRIPTION0000644000176200001440000000303614263015046013167 0ustar liggesusersPackage: dimRed Title: A Framework for Dimensionality Reduction Version: 0.2.6 Authors@R: c( person("Guido", "Kraemer", email = "guido.kraemer@uni-leipzig.de", role = c("aut", "cre")) ) Description: A collection of dimensionality reduction techniques from R packages and a common interface for calling the methods. Depends: R (>= 3.0.0), DRR Imports: magrittr, methods Suggests: NMF, MASS, Matrix, RANN, RSpectra, Rtsne, cccd, coRanking, diffusionMap, energy, fastICA, ggplot2, graphics, igraph, keras, kernlab, knitr, loe, optimx, pcaL1, pcaPP, reticulate, rgl, scales, scatterplot3d, stats, tensorflow, testthat, tidyr, tinytex, umap, vegan VignetteBuilder: knitr License: GPL-3 | file LICENSE BugReports: https://github.com/gdkrmr/dimRed/issues URL: https://www.guido-kraemer.com/software/dimred/ Encoding: UTF-8 Collate: 'dimRedMethod-class.R' 'misc.R' 'dimRedData-class.R' 'dimRedResult-class.R' 'autoencoder.R' 'dataSets.R' 'diffmap.R' 'dimRed.R' 'drr.R' 'embed.R' 'fastica.R' 'get_info.R' 'graph_embed.R' 'hlle.R' 'isomap.R' 'kpca.R' 'l1pca.R' 'leim.R' 'lle.R' 'loe.R' 'mds.R' 'mixColorSpaces.R' 'nmds.R' 'nnmf.R' 'pca.R' 'plot.R' 'quality.R' 'rotate.R' 'soe.R' 'tsne.R' 'umap.R' RoxygenNote: 7.2.0 Config/testthat/edition: 3 NeedsCompilation: yes Packaged: 2022-07-10 15:28:57 UTC; gkraemer Author: Guido Kraemer [aut, cre] Maintainer: Guido Kraemer Repository: CRAN Date/Publication: 2022-07-11 12:40:06 UTC dimRed/build/0000755000176200001440000000000014262570071012561 5ustar liggesusersdimRed/build/vignette.rds0000644000176200001440000000033314262570071015117 0ustar liggesusersb```b`abd`b2 1# 'IM+K,-JM)M.rJU%̂44R:^Xt%Z_g;<f&6̜TB2K7(1ݍ(\G^PT6@9XVr7W dimRed/tests/0000755000176200001440000000000014262570071012624 5ustar liggesusersdimRed/tests/testthat/0000755000176200001440000000000014263015046014461 5ustar liggesusersdimRed/tests/testthat/test_HLLE.R0000644000176200001440000000035114262544723016376 0ustar liggesuserstest_that("HLLE", { if(requireNamespace(dimRed:::getMethodDependencies("HLLE"), quietly = TRUE)) expect_error(embed(iris[1:4], "HLLE", ndim = 1, .mute = c("message", "output")), "ndim must be 2 or larger.") }) dimRed/tests/testthat/test_dimRedMethod-class.R0000644000176200001440000000065714210361274021322 0ustar liggesuserstest_that("pars matching", { for (m in dimRedMethodList()) { mo <- getMethodObject(m) expect( all.equal( mo@stdpars, matchPars(mo, list()) ), paste("par matching for", m, "failed") ) } expect_warning( embed(iris[1:4], "PCA", asdf = 1234), "Parameter matching: asdf is not a standard parameter, ignoring." ) }) dimRed/tests/testthat/test_UMAP.R0000644000176200001440000000422014257245743016417 0ustar liggesusersskip_if_no_umap_learn <- function() { if (!reticulate::py_module_available("umap") && Sys.getenv("BNET_FORCE_UMAP_TESTS") != 1) skip("umap-learn not available, install with `pip install umap-learn==0.4`") } test_that("UMAP python", { if (!requireNamespace("umap", quietly = TRUE)) { skip("umap not available") } skip_if_no_umap_learn() res1 <- embed(iris[1:4], "UMAP", .mute = c("message", "output")) res2 <- embed(iris[1:4], "UMAP", .mute = c("message", "output"), knn = 20) expect_s4_class(res1, "dimRedResult") expect_equal(res1@method, "UMAP") expect_equal(res1@pars$d, "euclidean") expect_equal(res1@pars$knn, 15) expect_equal(res1@pars$method, "umap-learn") expect_equal(res1@pars$ndim, 2) expect_s4_class(res2, "dimRedResult") expect_equal(res2@method, "UMAP") expect_equal(res2@pars$d, "euclidean") expect_equal(res2@pars$knn, 20) expect_equal(res2@pars$method, "umap-learn") expect_equal(res2@pars$ndim, 2) expect_true(any(res1@data@data != res2@data@data)) pred1 <- predict(res1, iris[1:4]) pred2 <- predict(res2, iris[1:4]) expect_equal(dim(pred1@data), dim(res1@data@data)) expect_equal(dim(pred2@data), dim(res2@data@data)) }) test_that("UMAP R", { if (!requireNamespace("umap", quietly = TRUE)) { skip("umap not available") } res1 <- embed(iris[1:4], "UMAP", method = "naive", .mute = c("message", "output")) res2 <- embed(iris[1:4], "UMAP", method = "naive", .mute = c("message", "output"), knn = 20) expect_s4_class(res1, "dimRedResult") expect_equal(res1@method, "UMAP") expect_equal(res1@pars$d, "euclidean") expect_equal(res1@pars$knn, 15) expect_equal(res1@pars$method, "naive") expect_equal(res1@pars$ndim, 2) expect_s4_class(res2, "dimRedResult") expect_equal(res2@method, "UMAP") expect_equal(res2@pars$d, "euclidean") expect_equal(res2@pars$knn, 20) expect_equal(res2@pars$method, "naive") expect_equal(res2@pars$ndim, 2) expect_true(any(res1@data@data != res2@data@data)) pred1 <- predict(res1, iris[1:4]) pred2 <- predict(res2, iris[1:4]) expect_equal(dim(pred1@data), dim(res1@data@data)) expect_equal(dim(pred2@data), dim(res2@data@data)) }) dimRed/tests/testthat/test_isomap.R0000644000176200001440000000253214262544757017154 0ustar liggesusers ## no isomap specific tests, because forward method is not really ## exact. test_that("check vs vegan isomap", { if (!requireNamespace(c("vegan", dimRed:::getMethodDependencies("Isomap")), quietly = TRUE)) { skip("Not all required packages for isomap tests installed") } eps <- 1e-8 a <- loadDataSet("3D S Curve", n = 200) vegiso <- vegan::isomap(dist(getData(a)), k = 8, ndim = 2) vegy <- vegan::scores(vegiso) drdiso <- embed(a, "Isomap", knn = 8, ndim = 2) drdy <- drdiso@data@data ## Randomly fails: ## expect_equal(drdy, vegy, ignore_attr = TRUE) err1 <- max(abs(drdy - vegy)) drdy[, 2] <- -drdy[, 2] err2 <- max(abs(drdy - vegy)) drdy[, 1] <- -drdy[, 1] err3 <- max(abs(drdy - vegy)) drdy[, 2] <- -drdy[, 2] err4 <- max(abs(drdy - vegy)) err <- min(err1, err2, err3, err4) expect_true(err < eps, info = paste0("err = ", err, ", eps = ", eps, ", expected err < eps")) }) test_that("check other.data", { if (!requireNamespace(dimRed:::getMethodDependencies("Isomap"), quietly = TRUE)) { skip("Not all required packages for isomap tests installed") } a <- loadDataSet("3D S Curve", n = 200) drdiso <- embed(a, "Isomap", knn = 8, ndim = 2, get_geod = TRUE) expect_true(inherits(getOtherData(drdiso)$geod, "dist")) }) dimRed/tests/testthat/test_misc_functions.R0000644000176200001440000000244714262545231020700 0ustar liggesuserstest_that("squared euclidean distance", { a <- matrix(rnorm(25), 5, 5) b <- matrix(rnorm(25), 5, 5) expect_equal( t(as.matrix(dist(rbind(a, b)))[6:10, 1:5] ^ 2), pdist2(a, b), ignore_attr = TRUE ) }) test_that("formula functions", { a <- matrix(rnorm(25), 5, 5) b <- matrix(rnorm(25), 5, 5) expect_true(rhs(a + b ~ c + d) == ~ c + d + 0) expect_true(lhs(a + b ~ c + d) == ~ a + b + 0) ## expect_equal(rhs(a + b ~ c + d), ~ c + d + 0) ## expect_equal(lhs(a + b ~ c + d), ~ a + b + 0) }) test_that("makeEpsGraph", { if(!requireNamespace("Matrix", quietly = TRUE)) skip("Matrix required") check_makeEpsGraph <- function(x, eps){ naive <- as.matrix(dist(x)) naive[naive >= eps] <- 0 epsSp <- as.matrix(makeEpsSparseMatrix(x, eps)) all(naive == epsSp) } expect_true(check_makeEpsGraph(iris[1:4], 1000)) expect_true(check_makeEpsGraph(iris[1:4], 1)) expect_true(check_makeEpsGraph(iris[1:4], 0.5)) }) test_that("getRotationMatrixFail", { if(!requireNamespace("Rtsne", quietly = TRUE)) skip("Rtsne not available") irisData <- as(iris[, 1:4], "dimRedData") expect_equal(class(irisData)[1], "dimRedData") irisRes <- embed(irisData, "tSNE") expect_error(getRotationMatrix(irisRes), "Not implemented for") }) dimRed/tests/testthat/test_high_level_functions.R0000644000176200001440000000272614257372562022064 0ustar liggesuserstest_that("high level functions working?", { embed_methods <- dimRedMethodList(filter = TRUE) quality_methods <- dimRedQualityList(filter = TRUE) scurve <- loadDataSet("3D S Curve", n = 300) for(i in 1:ncol(scurve@data)){ scurve@data[, i] <- scurve@data[, i] - min(scurve@data[, i]) } quality_results <- matrix(NA, length(embed_methods), length(quality_methods), dimnames = list(embed_methods, quality_methods)) embedded_data <- list() for (e in embed_methods) { message("embedding: ", e) if ( (e != "AutoEncoder" || reticulate::py_module_available("tensorflow")) && (e != "UMAP" || reticulate::py_module_available("umap-learn")) ) { suppressWarnings( embedded_data[[e]] <- embed( scurve, e, .mute = c("message", "output"))) for (q in quality_methods) { message(" quality: ", q) quality_results[e, q] <- tryCatch( suppressWarnings(quality(embedded_data[[e]], q, .mute = c("message", "output"))), error = function (e) NA ) } } } lapply(embedded_data, function(x) expect_equal(2, getNDim(x))) expect(inherits(quality_results, "matrix"), "should be matrix") expect(storage.mode(quality_results) == "double", 'storage should be "double"') }) dimRed/tests/testthat/test_kPCA.R0000644000176200001440000000543514210360650016424 0ustar liggesuserstest_that("general data conversions", { data(iris) irisData <- loadDataSet("Iris") expect_equal(class(irisData)[1], "dimRedData") irisPars <- list() irisPars[[length(irisPars) + 1]] <- list(kernel = "rbfdot", kpar = list(sigma = 0.1)) irisPars[[length(irisPars) + 1]] <- list(kernel = "rbfdot", kpar = list(sigma = 1)) irisPars[[length(irisPars) + 1]] <- list(kernel = "polydot", kpar = list(degree = 3)) irisPars[[length(irisPars) + 1]] <- list(kernel = "vanilladot", kpar = list()) irisPars[[length(irisPars) + 1]] <- list(kernel = "laplacedot", kpar = list(sigma = 1)) irisPars[[length(irisPars) + 1]] <- list(kernel = "laplacedot", kpar = list(sigma = 0.1)) irisPars[[length(irisPars) + 1]] <- list(kernel = "besseldot", kpar = list(sigma = 0.1, order = 1, degree = 1)) irisPars[[length(irisPars) + 1]] <- list(kernel = "besseldot", kpar = list(sigma = 1, order = 2, degree = 3)) irisPars[[length(irisPars) + 1]] <- list(kernel = "splinedot", kpar = list()) irisRes <- lapply(irisPars, function(x) do.call( function(...) tryCatch(embed(.data = irisData, .method = "kPCA", ...), error = function(e) as.character(e)), x ) ) for (i in 1:length(irisRes)) { if (inherits(irisRes[[i]], "character")){ expect(grepl("singular", irisRes[[i]]), "singular") } else { expect(inherits(irisRes[[i]], "dimRedResult"), 'should be of class "dimRedResult"') } } ## This test fails with multithreaded blas ## for (i in 1:length(irisRes)){ ## if (inherits(irisRes[[i]], "dimRedResult")){ ## expect_equal(irisRes[[i]]@apply(irisData)@data[, 1:2], ## irisRes[[i]]@data@data) ## expect_equal(2, getNDim(irisRes[[i]])) ## ## the reverse is an approximate: ## expect_less_than( ## max( ## irisRes[[i]]@inverse(irisRes[[i]]@data)@data - irisData@data ## ), 300, ## ## paste0("inverse of kpca is an approximate, ", ## ## "so this may fail due to numerical inaccuracy") ## ) ## } ## } ## This one cannot calculate an inverse: kpca.fit <- embed(loadDataSet("3D S", n = 200), "kPCA", kernel = "splinedot", kpar = list()) expect( is.na(kpca.fit@inverse(1)), "The inverse should return NA" ) }) dimRed/tests/testthat/test_fastICA.R0000644000176200001440000000126614257365042017131 0ustar liggesuserstest_that("general data conversions", { if(!requireNamespace("FastICA", quietly = TRUE)) skip("FastICA not available") irisData <- as(iris[, 1:4], "dimRedData") expect_equal(class(irisData)[1], "dimRedData") irisRes <- embed(irisData, "FastICA") expect_equal(class(irisRes)[1], "dimRedResult") expect_equal(2, getNDim(irisRes)) expect_equal(irisRes@apply(irisData), irisRes@data) expect( sqrt( mean( (irisRes@inverse(irisRes@data)@data - irisData@data) ^ 2 ) ) < 0.3, "error too large" ) expect_equal( scale(iris[1:4], TRUE, FALSE) %*% getRotationMatrix(irisRes), unname(as.matrix(getData( getDimRedData(irisRes) )) ) ) }) dimRed/tests/testthat/test_dimRedResult_class.R0000644000176200001440000000112214257365140021435 0ustar liggesuserstest_that("predict/inverse methods", { dat <- loadDataSet("Iris") emb <- embed(dat, "PCA", ndim = 4) pred <- predict(emb, dat) inv <- inverse(emb, pred) expect_equal(getDimRedData(emb), pred) expect_equal(dat, inv) if(requireNamespace("Rtsne", quietly = TRUE)) { emb2 <- embed(dat, "tSNE") expect_error(predict(emb2, dat)) expect_error(inverse(emb2, dat)) } }) test_that("conversion", { iris_data_frame_as <- as(embed(loadDataSet("Iris"), "PCA"), "data.frame") expect_equal(colnames(iris_data_frame_as), c("meta.Species", "PC1", "PC2", colnames(iris)[-5])) }) dimRed/tests/testthat/test_PCA_L1.R0000644000176200001440000000642414210361262016604 0ustar liggesuserstest_that("general data conversions", { skip_if_not_installed("pcaL1") irisData <- as(iris[, 1:4], "dimRedData") expect_equal(class(irisData)[1], "dimRedData") irisParsCS <- list(center = TRUE, .mute = c("message", "output"), ndim = 4, scale. = TRUE, projections = "l1", fun = "l1pca") irisParsC <- list(center = TRUE, .mute = c("message", "output"), ndim = 4, scale. = FALSE, projections = "l1", fun = "l1pca") irisParsS <- list(center = TRUE, .mute = c("message", "output"), ndim = 4, scale. = TRUE, projections = "l1", fun = "l1pcahp") irisPars <- list(center = FALSE, .mute = c("message", "output"), ndim = 4, scale. = FALSE, projections = "l1", fun = "l1pcastar") irisResCS <- do.call(function(...) embed(irisData, "PCA_L1", ...), irisParsCS) irisResS <- do.call(function(...) embed(irisData, "PCA_L1", ...), irisParsS) irisResC <- do.call(function(...) embed(irisData, "PCA_L1", ...), irisParsC) irisRes <- do.call(function(...) embed(irisData, "PCA_L1", ...), irisPars) expect_equal(4, getNDim(irisResCS)) expect_equal(4, getNDim(irisResS)) expect_equal(4, getNDim(irisResC)) expect_equal(4, getNDim(irisRes)) expect_equal(class(irisResCS)[1], "dimRedResult") expect_equal(class(irisResS)[1], "dimRedResult") expect_equal(class(irisResC)[1], "dimRedResult") expect_equal(class(irisRes)[1], "dimRedResult") expect_equal(irisResCS@apply(irisData), irisResCS@data) expect_equal(irisResS@apply(irisData), irisResS@data) expect_equal(irisResC@apply(irisData), irisResC@data) expect_equal(irisRes@apply(irisData), irisRes@data) expect(sqrt(mean( (irisResCS@inverse(irisResCS@data)@data - irisData@data) ^ 2 )) < 0.3, "error too large" ) expect(sqrt(mean( (irisResS@inverse(irisResS@data)@data - irisData@data) ^ 2 )) < 0.3, "error too large" ) expect(sqrt(mean( (irisResC@inverse(irisResC@data)@data - irisData@data) ^ 2 )) < 0.3, "error too large" ) expect(sqrt(mean( (irisRes@inverse(irisRes@data)@data - irisData@data) ^ 2 )) < 0.3, "error too large" ) scale2 <- function(x, center, scale.) scale(x, center, scale.) expect_equal( do.call(function(...) scale2(iris[1:4], ...) %*% getRotationMatrix(irisResCS), irisParsCS[c("center", "scale.")]), getData( getDimRedData(irisResCS) ), tolerance = 1e-2 ) expect_equal( do.call(function(...) scale2(iris[1:4], ...) %*% getRotationMatrix(irisResS), irisParsS[c("center", "scale.")]), getData( getDimRedData(irisResS) ), tolerance = 1e-2 ) expect_equal( do.call(function(...) scale2(iris[1:4], ...) %*% getRotationMatrix(irisResC), irisParsC[c("center", "scale.")]), getData( getDimRedData(irisResC) ), tolerance = 1e-2 ) expect_equal( do.call(function(...) scale2(iris[1:4], ...) %*% getRotationMatrix(irisRes), irisPars[c("center", "scale.")]), getData( getDimRedData(irisRes) ), tolerance = 1e-2 ) expect_s4_class({ embed(iris[1:4], "PCA_L1", ndim = 1, .mute = c("message", "output")) }, "dimRedResult") }) dimRed/tests/testthat/test_diffusion_maps.R0000644000176200001440000000064414262545136020664 0ustar liggesuserstest_that("DiffusionMaps", { if(!requireNamespace("diffusionMap", quietly = TRUE)) skip("diffusionMap not available") expect_s4_class(embed(iris[1:4], "DiffusionMaps", ndim = 1, .mute = c("message", "output")), "dimRedResult") x <- embed(iris[1:4], "DiffusionMaps", ndim = 1, .mute = c("message", "output")) expect_equal(dim(x@data@data), c(150, 1)) }) dimRed/tests/testthat/test_embed.R0000644000176200001440000000014714210361230016710 0ustar liggesuserstest_that("standard method is PCA", { res <- embed(iris[1:4]) expect_equal(res@method, "PCA") }) dimRed/tests/testthat/test_drr.R0000644000176200001440000000050014210360624016422 0ustar liggesuserstest_that("drr forward and backward passes", { spiral <- loadDataSet("Helix", n = 200) drr_spiral <- embed(spiral, "DRR", ndim = 3, .mute = c("message", "output")) expect_equal(3, getNDim(drr_spiral)) dsa <- drr_spiral@apply(spiral) dsi <- drr_spiral@inverse(dsa) expect_equal(dsi, spiral) }) dimRed/tests/testthat/test_PCA.R0000644000176200001440000000502414210361055016243 0ustar liggesuserstest_that("general data conversions", { irisData <- as(iris[, 1:4], "dimRedData") expect_equal(class(irisData)[1], "dimRedData") irisParsCS <- list(center = TRUE, scale. = TRUE) irisParsC <- list(center = TRUE, scale. = FALSE) irisParsS <- list(center = FALSE, scale. = TRUE) irisPars <- list(center = FALSE, scale. = FALSE) irisResCS <- do.call(function(...) embed(irisData, "PCA", ...), irisParsCS) irisResS <- do.call(function(...) embed(irisData, "PCA", ...), irisParsS) irisResC <- do.call(function(...) embed(irisData, "PCA", ...), irisParsC) irisRes <- do.call(function(...) embed(irisData, "PCA", ...), irisPars) expect_equal(2, getNDim(irisResCS)) expect_equal(2, getNDim(irisResS)) expect_equal(2, getNDim(irisResC)) expect_equal(2, getNDim(irisRes)) expect_equal(class(irisResCS)[1], "dimRedResult") expect_equal(class(irisResS)[1], "dimRedResult") expect_equal(class(irisResC)[1], "dimRedResult") expect_equal(class(irisRes)[1], "dimRedResult") expect_equal(irisResCS@apply(irisData), irisResCS@data) expect_equal(irisResS@apply(irisData), irisResS@data) expect_equal(irisResC@apply(irisData), irisResC@data) expect_equal(irisRes@apply(irisData), irisRes@data) expect(sqrt(mean( (irisResCS@inverse(irisResCS@data)@data - irisData@data) ^ 2 )) < 0.3, "error too large" ) expect(sqrt(mean( (irisResS@inverse(irisResS@data)@data - irisData@data) ^ 2 )) < 0.3, "error too large" ) expect(sqrt(mean( (irisResC@inverse(irisResC@data)@data - irisData@data) ^ 2 )) < 0.3, "error too large" ) expect(sqrt(mean( (irisRes@inverse(irisRes@data)@data - irisData@data) ^ 2 )) < 0.3, "error too large" ) scale2 <- function(x, center, scale.) scale(x, center, scale.) expect_equal( do.call(function(...) scale2(iris[1:4], ...) %*% getRotationMatrix(irisResCS), irisParsCS), getData( getDimRedData(irisResCS) ) ) expect_equal( do.call(function(...) scale2(iris[1:4], ...) %*% getRotationMatrix(irisResS), irisParsS), getData( getDimRedData(irisResS) ) ) expect_equal( do.call(function(...) scale2(iris[1:4], ...) %*% getRotationMatrix(irisResC), irisParsC), getData( getDimRedData(irisResC) ) ) expect_equal( do.call(function(...) scale2(iris[1:4], ...) %*% getRotationMatrix(irisRes), irisPars), getData( getDimRedData(irisRes) ) ) }) dimRed/tests/testthat/test_NNMF.R0000644000176200001440000001277314256661025016421 0ustar liggesusersskip_if_no_NMF <- function() { if (!requireNamespace("NMF", quietly = TRUE) && Sys.getenv("BNET_FORCE_NNMF_TESTS") != "1") skip("NMF not available for testing") } ## if we don't load the library explicitly, the predict function does not work ## (sometimes...). ## library(NMF) ints_trn <- matrix(seq(0, 98, by = 2), ncol = 5) input_trn <- dimRedData(as.data.frame(ints_trn)) input_tst <- dimRedData(ints_trn[1:3,] + 1) test_that("2D projection", { skip_if_no_NMF() dim_2_defaults <- embed(input_trn, "NNMF", seed = 13, nrun = 1) expect_equal(dim_2_defaults@method, "NNMF") ## Expected results from ## tmp <- NMF::nmf(t(ints_trn), rank = 2, nrun = 1, seed = 13) ## coefs <- basis(tmp) ## rownames(coefs) <- paste0("V", 1:5) ## colnames(coefs) <- paste0("NNMF", 1:2) ## coefs ## dput(coefs) dim_2_coef <- structure( c(18.807241710186, 30.2191667888959, 32.1069052462692, 9.53490906878683, 164.109205703974, 0.00064246562138093, 24.3924277525021, 56.4301459918642, 108.103923297376, 17.566220349863), .Dim = c(5L, 2L), .Dimnames = list(c("V1", "V2", "V3", "V4", "V5"), c("NNMF1", "NNMF2"))) expect_equal(dim_2_defaults@other.data$w, dim_2_coef, ignore_attr = TRUE) dim_2_apply <- dim_2_defaults@apply(input_tst)@data dim_2_pred <- predict(dim_2_defaults, input_tst)@data ## Expected results from ## t(solve(crossprod(basis(tmp)), t(input_tst@data %*% basis(tmp)))) ## preds <- getData(input_tst) %*% t(MASS::ginv(basis(tmp))) ## getData(getDimRedData(dim_2_defaults)) ## colnames(preds) <- paste0("NNMF", 1:2) ## dput(preds) dim_2_exp <- structure( c(0.427476458116875, 0.440237021147746, 0.452997584178617, 0.512256378881175, 0.5332094651398, 0.554162551398426), .Dim = c(3L, 2L), .Dimnames = list(NULL, c("NNMF1", "NNMF2")) ) expect_equal(dim_2_apply, dim_2_exp, tolerance = 0.01, ignore_attr = TRUE) expect_equal(dim_2_pred, dim_2_exp, tolerance = 0.01, ignore_attr = TRUE) }) test_that("other arguments", { skip_if_no_NMF() dim_3_args <- embed(input_trn, "NNMF", seed = 13, nrun = 10, ndim = 3, method = "KL", options = list(.pbackend = NULL)) ## Expected results from ## tmp <- NMF::nmf(t(ints_trn), rank = 3, nrun = 10, seed = 13, ## method = "KL", .pbackend = NULL) ## coefs <- t(NMF::coef(tmp)) ## colnames(coefs) <- paste0("NNMF", 1:ncol(coefs)) ## coefs ## dput(coefs) ## rot <- NMF::basis(tmp) ## rownames(rot) <- paste0("V", 1:nrow(rot)) ## dput(rot) dim_3_rot <- structure( c(11.624951277152, 31.2554213278975, 50.8858913786408, 70.5163614293837, 90.1468314801264, 2.22044604925031e-16, 36.4357899711133, 72.8715799422292, 109.307369913346, 145.743159884462, 22.4019808842378, 42.1081005773292, 61.8142202704197, 81.52033996351, 101.2264596566), .Dim = c(5L, 3L), .Dimnames = list(c("V1", "V2", "V3", "V4", "V5"), NULL) ) dim_3_pred <- structure( c(2.22044604925031e-16, 0.0731742704517501, 0.194863499580201, 0.50224638618713, 0.557517908619563, 0.197219538171418, 0.0860784848917408, 0.159094934700865, 0.10366866301249, 0.216483929440989, 0.54891083782883, 0.481738298195276, 0.40204352636632, 0.274419226004639, 0.211867578024856, 0.256578985276104, 0.236980211423017, 0.16984840699324, 0.135869049278152, 0.0584647425861749, 2.22044604925031e-16, 0.0513058500137363, 0.0774360678481537, 0.00720517673339281, 0.0678012129377125, 0.344046917890136, 0.49099862480747, 0.542386371921862, 0.660426277478513, 0.691161417731563), .Dim = c(10L, 3L), .Dimnames = list(NULL, c("NNMF1", "NNMF2", "NNMF3")) ) expect_equal(dim_3_args@other.data$w, dim_3_rot, ignore_attr = TRUE) expect_equal(getData(getDimRedData(dim_3_args)), dim_3_pred, ignore_attr = TRUE) dim_3_apply <- dim_3_args@apply(input_tst)@data dim_3_pred <- predict(dim_3_args, input_tst)@data ## Expected results from ## crossprod(basis(tmp)) does not have full rank!!! This needs to be considered ## w <- getOtherData(dim_3_args)$w ## preds <- t(solve(crossprod(w), t(input_trn@data %*% w))) ## preds <- t(qr.solve(crossprod(w), t(input_trn@data %*% w))) ## preds <- getData(input_tst) %*% t(MASS::ginv(w)) ## preds ## dput(preds) ## getData(getDimRedData(dim_3_args)) ## preds - getData(getDimRedData(dim_3_args)) ## input_trn@data ## input_tst@data %*% basis(tmp) ## colnames(preds) <- paste0("NNMF", 1:3) dim_3_exp <- structure( c(0.118730450278164, 0.144080695556738, 0.169430940835312, 0.494122495652466, 0.439293850852014, 0.384465206051563, -0.0169733070286198, 0.0591496323928872, 0.135272571814394), .Dim = c(3L, 3L) ) expect_equal(dim_3_apply, dim_3_exp, tolerance = 0.01, ignore_attr = TRUE) expect_equal(dim_3_pred, dim_3_exp, tolerance = 0.01, ignore_attr = TRUE) }) test_that("Bad args", { skip_if_no_NMF() expect_error(embed(iris, "NNMF")) expect_error(embed(iris[, 1], "NNMF"), "`ndim` should be less than the number of columns") expect_error(embed(iris[1:4], "NNMF", method = c("a", "b")), "only supply one `method`") expect_error(embed(scale(iris[1:4]), "NNMF"), "negative entries") }) test_that("Full_rank", { skip_if_no_NMF() dim_2_full_rank_example <- embed(input_trn, "NNMF", ndim = ncol(input_trn@data)) dim_2_recon <- inverse(dim_2_full_rank_example, dim_2_full_rank_example@data@data) expect_equal(dim_2_recon, input_trn, ignore_attr = TRUE, tolerance = 1e-2) }) dimRed/tests/testthat/test_autoencoder.R0000644000176200001440000002263414262553701020166 0ustar liggesusersskip_if_no_tensorflow <- function() { if (!requireNamespace(c("tensorflow", "reticulate"), quietly = TRUE) || (!reticulate::py_module_available("tensorflow") && Sys.getenv("BNET_FORCE_AUTOENCODER_TESTS") != "1")) skip("TensorFlow not available for testing") } skip_if_no_keras <- function() { if (!requireNamespace(c("keras", "reticulate"), quietly = TRUE) || (!keras::is_keras_available() && Sys.getenv("BNET_FORCE_AUTOENCODER_TESTS") != "1")) skip("Keras not available for testing") } test_that("Check if tensorflow is installed correctly.", { skip_if_no_tensorflow() requireNamespace("tensorflow", quietly = TRUE) tensorflow::tf$compat$v1$disable_v2_behavior() # I have not found a way to suppress the warning tf gives on first use. sess <- tensorflow::tf$compat$v1$Session() hello <- "Hello, TensorFlow!" tf_hello <- tensorflow::tf$compat$v1$constant(hello) tf_hello_res <- sess$run(tf_hello) # in python 3 this returns a `bytes` object $decode() transforms it into a # sting, in python 2 this is a simple string if(!is.character(tf_hello_res)) tf_hello_res <- tf_hello_res$decode() ## print("tf_hello_res:") ## print(str(tf_hello_res)) ## print(tf_hello_res) expect(tf_hello_res == hello, paste("tensorflow does not work:\n", "hello =", hello, "\n", "sess$run(tf_hello) =", tf_hello_res)) }) test_that("Check errors when building autoencoder.", { skip_if_no_tensorflow() iris_data <- as(iris[, 1:4], "dimRedData") expect_error(embed(iris_data, "AutoEncoder", activation = "sigmoid"), "declare an activation function for each layer") expect_error(embed(iris_data, "AutoEncoder", n_hidden = c(1, 2, 2, 1)), "the number of layers must be impair") expect_error(embed(iris_data, "AutoEncoder", weight_decay = -1), "weight decay must be > 0") expect_error(embed(iris_data, "AutoEncoder", learning_rate = -1), "learning rate must be > 0") expect_error(embed(iris_data, "AutoEncoder", n_steps = -1), "n_steps must be > 0") expect_error(embed(iris_data, "AutoEncoder", n_hidden = c(4, 2, 4), ndim = 3), "the middle of n_hidden must be equal to ndim") }) test_that("using autoencoder with parameters", { skip_if_no_tensorflow() iris_data <- as(iris[, 1:4], "dimRedData") expect_equal(class(iris_data)[1], "dimRedData") ae <- lapply(1:2, function(x) embed(iris_data, "AutoEncoder", n_hidden = c(10, x, 10), ndim = x, n_steps = 100)) aq <- lapply(ae, function(x) quality(x, "reconstruction_rmse")) lapply(ae, function(x) expect_s4_class(x, "dimRedResult")) ## expect(aq[[1]] > aq[[2]], "the error should decrease with more dimensions") ## expect(aq[[2]] > aq[[3]], "the error should decrease with more dimensions") ## expect(aq[[3]] > aq[[4]], "the error should decrease with more dimensions") lapply(1:length(ae), function(x) expect_equal(x, getNDim(ae[[x]]))) ae <- lapply(1:2, function(x) embed(iris_data, "AutoEncoder", n_hidden = c(10, x, 10), ndim = x, weight_decay = 0.1, n_steps = 100)) aq <- lapply(ae, function(x) quality(x, "reconstruction_rmse")) lapply(ae, function(x) expect_s4_class(x, "dimRedResult")) ## expect(aq[[1]] > aq[[2]], "the error should decrease with more dimensions") ## expect(aq[[2]] > aq[[3]], "the error should decrease with more dimensions") ## expect(aq[[3]] > aq[[4]], "the error should decrease with more dimensions") lapply(1:length(ae), function(x) expect_equal(x, getNDim(ae[[x]]))) ae <- lapply(1:2, function(x) embed(iris_data, "AutoEncoder", n_hidden = c(10, x, 10), ndim = x, learning_rate = 0.1, weight_decay = 0.1, n_steps = 100)) aq <- lapply(ae, function(x) quality(x, "reconstruction_rmse")) lapply(ae, function(x) expect_s4_class(x, "dimRedResult")) ## expect(aq[[1]] > aq[[2]], "the error should decrease with more dimensions") ## expect(aq[[2]] > aq[[3]], "the error should decrease with more dimensions") ## expect(aq[[3]] > aq[[4]], "the error should decrease with more dimensions") lapply(1:length(ae), function(x) expect_equal(x, getNDim(ae[[x]]))) ae <- lapply(1:2, function(x) embed(iris_data, "AutoEncoder", n_hidden = c(10, x, 10), activation = c("sigmoid", "sigmoid", "sigmoid"), ndim = x, learning_rate = 0.1, weight_decay = 0.1, n_steps = 100)) aq <- lapply(ae, function(x) quality(x, "reconstruction_rmse")) lapply(ae, function(x) expect_s4_class(x, "dimRedResult")) aa <- lapply(c("tanh", "sigmoid", "relu", "elu"), function(x) embed(iris_data, "AutoEncoder", n_hidden = c(10, 2, 10), activation = c("sigmoid", "sigmoid", "sigmoid"), ndim = 2, learning_rate = 0.1, weight_decay = 0.1, n_steps = 100)) aaq <- lapply(aa, function(x) quality(x, "reconstruction_rmse")) lapply(aa, function(x) expect_s4_class(x, "dimRedResult")) ## expect(aq[[1]] > aq[[2]], "the error should decrease with more dimensions") ## expect(aq[[2]] > aq[[3]], "the error should decrease with more dimensions") ## expect(aq[[3]] > aq[[4]], "the error should decrease with more dimensions") lapply(1:length(ae), function(x) expect_equal(x, getNDim(ae[[x]]))) }) test_that("using autoencoder with autoencoder results", { skip_if_no_tensorflow() tensorflow::tf$compat$v1$set_random_seed(2) iris_data <- as(iris[, 1:4], "dimRedData") expect_equal(class(iris_data)[1], "dimRedData") ae1 <- lapply(1:2, function(x) embed(iris_data, "AutoEncoder", n_hidden = c(10, x, 10), ndim = x, n_steps = 1)) aq1 <- lapply(ae1, function(x) quality(x, "reconstruction_rmse")) ae2 <- lapply(ae1, function(x) embed(iris_data, "AutoEncoder", autoencoder = x, n_steps = 1000)) aq2 <- lapply(ae2, function(x) quality(x, "reconstruction_rmse")) lapply(ae1, function(x) expect_s4_class(x, "dimRedResult")) lapply(ae2, function(x) expect_s4_class(x, "dimRedResult")) expect(aq1[[1]] > aq2[[1]], "the error should decrease with more steps") expect(aq1[[2]] > aq2[[2]], "the error should decrease with more steps") ## expect(aq1[[3]] > aq2[[3]], "the error should decrease with more steps") ## expect(aq1[[4]] > aq2[[4]], "the error should decrease with more steps") lapply(1:length(ae1), function(x) expect_equal(x, getNDim(ae1[[x]]))) lapply(1:length(ae2), function(x) expect_equal(x, getNDim(ae2[[x]]))) }) test_that("using autoencoder with keras", { skip_if_no_tensorflow() skip_if_no_keras() encoder <- function(i) list(keras::layer_dense(units = 10, activation = "tanh"), keras::layer_dense(units = i)) decoder <- function() list(keras::layer_dense(units = 10, activation = "tanh"), keras::layer_dense(units = 4)) iris_data <- as(iris[, 1:4], "dimRedData") ae1 <- lapply(1:2, function(x) embed(iris_data, "AutoEncoder", keras_graph = list(encoder = encoder(x), decoder = decoder()), n_steps = 2)) aq1 <- lapply(ae1, function(x) quality(x, "reconstruction_rmse")) ae2 <- lapply(ae1, function(x) embed(iris_data, "AutoEncoder", autoencoder = x)) aq2 <- lapply(ae2, function(x) quality(x, "reconstruction_rmse")) lapply(ae1, function(x) expect_s4_class(x, "dimRedResult")) lapply(ae2, function(x) expect_s4_class(x, "dimRedResult")) ## expect(aq1[[1]] > aq2[[1]], "the error should decrease with more steps") ## expect(aq1[[2]] > aq2[[2]], "the error should decrease with more steps") ## expect(aq1[[3]] > aq2[[3]], "the error should decrease with more steps") ## expect(aq1[[4]] > aq2[[4]], "the error should decrease with more steps") lapply(1:length(ae1), function(x) expect_equal(x, getNDim(ae1[[x]]))) lapply(1:length(ae2), function(x) expect_equal(x, getNDim(ae2[[x]]))) }) ## test_that("garbage collection", { ## skip_if_no_tensorflow() ## tmp <- tf$get_session_handle(environment(ae[[1]]@apply)$dec) ## tmp <- tf$get_default_session() ## tmp$close ## tmp ## tf$get_session_handle() ## tf$Session() ## }) dimRed/tests/testthat/test_dimRedData_class.R0000644000176200001440000000256214210362247021033 0ustar liggesuserstest_that("constructor", { expect_equal(dimRedData(), new("dimRedData", data = matrix(numeric(0), nrow = 0, ncol = 0), meta = data.frame())) expect_error(dimRedData(iris)) expect_s4_class(dimRedData(iris[, 1:4], iris[, 5]), "dimRedData") expect_s4_class(dimRedData(iris[, 1:4]), "dimRedData") expect_error(dimRedData(iris)) }) test_that("conversion functions", { expect_equal(as(iris[, 1:4], "dimRedData"), dimRedData(iris[, 1:4])) expect_error(as(iris, "dimRedData")) expect_equal(as(loadDataSet("Iris"), "data.frame"), as.data.frame(loadDataSet("Iris"))) expect_equal(as.dimRedData( Species ~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width, iris), loadDataSet("Iris"), ignore_attr = TRUE ) }) test_that("misc functions", { Iris <- loadDataSet("Iris") expect_equal(getData(Iris), Iris@data) expect_equal(getMeta(Iris), Iris@meta) ## No idea why this one is broken with --run-donttest --run-dontrun --timings ## Also broken for devtools::test("dimRed") expect_equal(nrow(Iris), 150) expect_equal(Iris[1:4], Iris[1:4, ]) expect_equal(Iris[1:4], Iris[c(rep(TRUE, 4), rep(FALSE, 146))]) expect_equal(Iris[1:4], Iris[c(rep(TRUE, 4), rep(FALSE, 146)), ]) }) dimRed/tests/testthat/test_quality.R0000644000176200001440000000657314257322052017347 0ustar liggesuserstest_that("quality", { irisData <- loadDataSet("Iris") parsPCA <- list(center = TRUE, scale. = TRUE) resPCA <- do.call(function(...) embed(irisData, "PCA", ...), parsPCA) if(requireNamespace("coRanking", quietly = TRUE)) expect_true(is.numeric(Q_local(resPCA))) if(requireNamespace("coRanking", quietly = TRUE)) expect_true(is.numeric(Q_global(resPCA))) if(requireNamespace("coRanking", quietly = TRUE)) expect_true(is.numeric(mean_R_NX(resPCA))) if(requireNamespace("optimx", quietly = TRUE)) expect_true(is.numeric(total_correlation(resPCA))) expect_true(is.numeric(cophenetic_correlation(resPCA))) if (requireNamespace("energy", quietly = TRUE)) expect_true(is.numeric(distance_correlation(resPCA))) expect_true(is.numeric(reconstruction_rmse(resPCA))) ## suppressWarnings( ## resQual <- list( ## Q_local(resPCA), ## Q_global(resPCA), ## mean_R_NX(resPCA), ## total_correlation(resPCA), ## cophenetic_correlation(resPCA), ## distance_correlation(resPCA), ## reconstruction_rmse(resPCA) ## ) ## ) ## lapply(resQual, function(x) expect_true(is.numeric(x))) }) test_that("Q_local ndim", { if(!requireNamespace("coRanking", quietly = TRUE)) { skip("coRanking not available") } irisData <- loadDataSet("Iris") irisData <- irisData[!duplicated(irisData@data)] parsPCA <- list(center = TRUE, scale. = FALSE, ndim = 4) resPCA <- do.call(function(...) embed(irisData, "PCA", ...), parsPCA) tmp <- sapply(1:4, function(x) quality(resPCA, "Q_local", ndim = x)) expect_equal(rank(tmp), 1:4) }) test_that("rmse_by_ndim", { if(!requireNamespace("DRR", quietly = TRUE)) { skip("DRR not available") } set.seed(1) ir <- loadDataSet("Iris") ir.drr <- embed(ir, "DRR", .mute = c("message", "output"), ndim = ndims(ir)) ir.pca <- embed(ir, "PCA", ndim = ndims(ir)) rmse_res <- data.frame( drr = reconstruction_error(ir.drr), pca = reconstruction_error(ir.pca) ) for (i in 1:length(rmse_res$pca)) { expect_true(rmse_res$pca[i] - rmse_res$drr[i] + 1e-12 > 0, info = paste0( "ndim = ", i, ", rmse pca = ", rmse_res$pca[i], ", rmse drr = ", rmse_res$drr[i] )) } # expect_true(all((rmse_res$pca - rmse_res$drr) + 1e-12 > 0)) expect_error(reconstruction_error(ir.pca, 5)) expect_error(reconstruction_error(ir.pca, 0)) }) test_that("AUC_lnK_R_NX", { if(!requireNamespace("coRanking", quietly = TRUE)) { skip("coRanking not available") } irisData <- loadDataSet("Iris") irisData <- irisData[!duplicated(irisData@data)] parsPCA <- list(center = TRUE, scale. = TRUE, ndim = 4) resPCA <- do.call(function(...) embed(irisData, "PCA", ...), parsPCA) expect_true(length(AUC_lnK_R_NX(resPCA, weight = "inv")) == 1) expect_true(length(AUC_lnK_R_NX(resPCA, weight = "log")) == 1) expect_true(length(AUC_lnK_R_NX(resPCA, weight = "ln")) == 1) expect_true(length(AUC_lnK_R_NX(resPCA, weight = "log10")) == 1) expect_true(AUC_lnK_R_NX(resPCA, weight = "log") == AUC_lnK_R_NX(resPCA, weight = "ln")) expect_error(AUC_lnK_R_NX(resPCA, weight = "asdf")) }) dimRed/tests/testthat/test_dataSets.R0000644000176200001440000000025614210360550017411 0ustar liggesuserstest_that("datasets load", { for (d in dataSetList()) { ds <- loadDataSet(d) expect(inherits(ds, "dimRedData"), "must be of class 'dimRedData'") } }) dimRed/tests/testthat.R0000644000176200001440000000007014210356130014573 0ustar liggesuserslibrary(testthat) library(dimRed) test_check("dimRed") dimRed/vignettes/0000755000176200001440000000000014262570071013472 5ustar liggesusersdimRed/vignettes/classification_tree.tex0000644000176200001440000000722513371631672020241 0ustar liggesusers\newcommand{\imp}[1] {\textbf{#1}} % style for implemented methods \newcommand{\noimp}[1] {#1} % style for not implemented methods \tikz[ % tree layout, grow cyclic, % level 1/.style={level distance=1.2cm, sibling angle=180, text width=1.5cm, font={\small}}, % level 2/.style={level distance=1.9cm, sibling angle=40, font={\scriptsize}},%, text width=1.4cm}, level 3/.style={level distance=2.2cm, sibling angle=30}, level 4/.style={level distance=2.3cm}, % text width=1.2cm, font=\tiny, innernode/.style={align=flush center},%, text width=1.2}, leaf/.style={% % draw, very thin, % fill=red!30, rounded corners, align=flush left, text width=, inner sep=2pt, font={\hangindent=0.2cm\scriptsize\sffamily}}, ]{ \node[innernode, draw, align=flush center, rounded corners, font={\normalsize\bfseries}]{ Dimensionality \\ reduction} child[] { node[innernode] {Convex} % level 1 child[sibling angle=55]{ node[innernode] {Full spectral} % level 2 child { node[innernode] {Euclidean distances} child { node[leaf, text width=1.3cm]{ \imp{PCA} \\ \imp{Classical scaling} } } } child { node[innernode] {Geodesic distances} child { node[leaf]{ \imp{Isomap} } } } child { node[innernode] {Kernel-based} child { node[leaf]{ \imp{Kernel PCA} \\ \noimp{MVU} } } } child { node[innernode] {Diffusion distance} child { node[leaf]{ \imp{Diffusion maps} } } } } child[] { node[innernode] {Removal of shared information by regression} %level 2 child{ node[leaf]{ \imp{DRR} } } } child[sibling angle=55] { node[innernode] {Sparse spectral} % level 2 child[sibling angle=45] { node[innernode] {Reconstruction weights} child {node[leaf]{ \imp{Local Linear Embedding} } } } child[sibling angle=45] { node[innernode] {Neighborhood graph Laplacian} child { node[leaf]{ \imp{Laplacian Eigenmaps} } } } child[sibling angle=45] { node[innernode] {Local tangent space} child { node[leaf, text width=2cm]{ \imp{Hessian LLE} \\ \noimp{Local tangent space alignment} } } } } } child[level distance=1.8cm] { node[innernode] {Non-convex} %level 1 child { node[innernode] {Weighted Euclidean distances} % level 2 child { node[leaf, text width=2cm]{ \imp{Non-linear MDS} \\ \noimp{Sammon's mapping} \\ \noimp{Stochastic Proximity Embedding} } } } child { node[innernode] {Alignment of local linear models} % level 2 child { node[leaf]{ \noimp{LLC} \\ \noimp{Man.\ charting} } } } child { node[innernode] {Neural network} % level 2 child { node[leaf]{ Autoencoder } } } child { node[innernode] {Discrete mapping} % level 2 child { node[leaf,text width=2.5cm]{ \noimp{Self Organizing Maps} \\ \noimp{Generative Topographic Mapping} \\ \noimp{Elastic Net} } } } child { node[innernode] {Stochastic methods} % level 2 child { node[leaf]{ \noimp{SNE} \\ \imp{t-SNE} \\ \noimp{NeRV} \\ \noimp{JNE} } } } child { node[innernode] {Force directed} % level 2 child { node[leaf, text width=2cm]{ \imp{Kamada-Kawai} \\ \imp{Fruchtermann-Reingold} \\ \imp{DrL} } } } }; } %%% Local Variables: %%% mode: LaTeX %%% TeX-command-extra-options: "-shell-escape" %%% TeX-engine: default %%% TeX-master: "dimensionality-reduction" %%% End:dimRed/vignettes/bibliography.bib0000644000176200001440000006220013371631672016630 0ustar liggesusers @book{rojo-alvarez_digital_2017, edition = {1st}, title = {Digital {Signal} {Processing} with {Kernel} {Methods}}, isbn = {978-1-118-61179-1}, publisher = {Wiley}, author = {Rojo-Álvarez, J. L. and Martínez-Ramón, M. and Muñoz-Marí, J. and Camps-Valls, G.}, month = dec, year = {2017} } @article{arenas-garcia_kernel_2013, title = {Kernel {Multivariate} {Analysis} {Framework} for {Supervised} {Subspace} {Learning}: {A} {Tutorial} on {Linear} and {Kernel} {Multivariate} {Methods}}, volume = {30}, issn = {1053-5888}, shorttitle = {Kernel {Multivariate} {Analysis} {Framework} for {Supervised} {Subspace} {Learning}}, doi = {10.1109/MSP.2013.2250591}, number = {4}, journal = {IEEE Signal Processing Magazine}, author = {Arenas-Garcia, J. and Petersen, K. B. and Camps-Valls, G. and Hansen, L. K.}, month = jul, year = {2013}, pages = {16--29}, } @inproceedings{scholkopf_generalized_2001, title = {A {Generalized} {Representer} {Theorem}}, url = {https://link.springer.com/chapter/10.1007/3-540-44581-1_27}, doi = {10.1007/3-540-44581-1_27}, language = {en}, urldate = {2017-06-12}, booktitle = {Computational {Learning} {Theory}}, publisher = {Springer, Berlin, Heidelberg}, author = {Schölkopf, Bernhard and Herbrich, Ralf and Smola, Alex J.}, month = jul, year = {2001}, pages = {416--426}, } @incollection{bakir_learning_2004, title = {Learning to {Find} {Pre}-{Images}}, url = {http://papers.nips.cc/paper/2417-learning-to-find-pre-images.pdf}, doi = {10.1007/978-3-540-28649-3_31}, urldate = {2017-06-12}, booktitle = {Advances in {Neural} {Information} {Processing} {Systems} 16}, publisher = {MIT Press}, author = {Bakir, Gökhan H. and Weston, Jason and Schölkopf, Prof. Bernhard}, editor = {Thrun, S. and Saul, L. K. and Schölkopf, P. B.}, year = {2004}, pages = {449--456}, } @inproceedings{babaee_assessment_2013, title = {Assessment of dimensionality reduction based on communication channel model; application to immersive information visualization}, url = {http://elib.dlr.de/88828/}, doi = {10.1109/BigData.2013.6691726}, booktitle = {Big {Data} 2013}, publisher = {IEEE Xplore}, author = {Babaee, Mohammadreza and Datcu, Mihai and Rigoll, Gerald}, year = {2013}, pages = {1--6}, } @article{mahecha_nonlinear_2007, title = {Nonlinear dimensionality reduction: {Alternative} ordination approaches for extracting and visualizing biodiversity patterns in tropical montane forest vegetation data}, volume = {2}, issn = {1574-9541}, shorttitle = {Nonlinear dimensionality reduction}, url = {http://www.sciencedirect.com/science/article/pii/S1574954107000325}, doi = {10.1016/j.ecoinf.2007.05.002}, number = {2}, urldate = {2016-08-26}, journal = {Ecological Informatics}, author = {Mahecha, Miguel D. and Martínez, Alfredo and Lischeid, Gunnar and Beck, Erwin}, month = jun, year = {2007}, pages = {138--149}, } @inproceedings{bengio_out--sample_2003, title = {Out-of-{Sample} {Extensions} for {LLE}, {Isomap}, {MDS}, {Eigenmaps}, and {Spectral} {Clustering}}, booktitle = {In {Advances} in {Neural} {Information} {Processing} {Systems}}, publisher = {MIT Press}, author = {Bengio, Yoshua and Paiement, Jean-Francois and Vincent, Pascal}, year = {2004}, pages = {177--184}, } @misc{noauthor_scopus_nodate, author = {Elsevier}, year = {2017}, title = {Scopus - {Advanced} search}, url = {https://www.scopus.com/}, urldate = {2017-03-28} } @article{diaz_global_2016, title = {The global spectrum of plant form and function}, volume = {529}, issn = {0028-0836}, url = {http://www.nature.com/nature/journal/v529/n7585/full/nature16489.html}, doi = {10.1038/nature16489}, language = {en}, number = {7585}, urldate = {2017-03-22}, journal = {Nature}, author = {Díaz, Sandra and Kattge, Jens and Cornelissen, Johannes H. C. and Wright, Ian J. and Lavorel, Sandra and Dray, Stéphane and Reu, Björn and Kleyer, Michael and Wirth, Christian and Colin Prentice, I. and Garnier, Eric and Bönisch, Gerhard and Westoby, Mark and Poorter, Hendrik and Reich, Peter B. and Moles, Angela T. and Dickie, John and Gillison, Andrew N. and Zanne, Amy E. and Chave, Jérôme and Joseph Wright, S. and Sheremet’ev, Serge N. and Jactel, Hervé and Baraloto, Christopher and Cerabolini, Bruno and Pierce, Simon and Shipley, Bill and Kirkup, Donald and Casanoves, Fernando and Joswig, Julia S. and Günther, Angela and Falczuk, Valeria and Rüger, Nadja and Mahecha, Miguel D. and Gorné, Lucas D.}, month = jan, year = {2016}, pages = {167--171}, } first application of pca in ecology? @article{aart_distribution_1972, title = {Distribution {Analysis} of {Wolfspiders} ({Araneae}, {Lycosidae}) in a {Dune} {Area} {By} {Means} of {Principal} {Component} {Analysis}}, volume = {23}, issn = {1568-542X}, url = {http://booksandjournals.brillonline.com/content/journals/10.1163/002829673x00076}, doi = {10.1163/002829673X00076}, number = {3}, urldate = {2016-07-18}, journal = {Netherlands Journal of Zoology}, author = {Aart, P. J. M. Van Der}, month = jan, year = {1972}, pages = {266--329}, } @article{morrall_soil_1974, title = {Soil microfungi associated with aspen in {Saskatchewan}: synecology and quantitative analysis}, volume = {52}, issn = {0008-4026}, shorttitle = {Soil microfungi associated with aspen in {Saskatchewan}}, url = {http://www.nrcresearchpress.com/doi/abs/10.1139/b74-233}, doi = {10.1139/b74-233}, number = {8}, urldate = {2016-07-18}, journal = {Can. J. Bot.}, author = {Morrall, R. A. A.}, month = aug, year = {1974}, pages = {1803--1817}, } @article{pearson_lines_1901, title = {On lines and planes of closest fit to systems of points in space}, volume = {2}, number = {6}, journal = {Philosophical Magazine}, doi = {10.1080/14786440109462720}, author = {Pearson, K}, year = {1901}, pages = {559--572}, } @article{kramer_nonlinear_1991, title = {Nonlinear principal component analysis using autoassociative neural networks}, volume = {37}, issn = {1547-5905}, doi = {10.1002/aic.690370209}, language = {en}, number = {2}, urldate = {2016-07-15}, journal = {AIChE J.}, author = {Kramer, Mark A.}, month = feb, year = {1991}, pages = {233--243}, } @article{hsieh_nonlinear_2004, title = {Nonlinear multivariate and time series analysis by neural network methods}, volume = {42}, issn = {1944-9208}, doi = {10.1029/2002RG000112}, language = {en}, number = {1}, urldate = {2016-07-15}, journal = {Rev. Geophys.}, author = {Hsieh, William W.}, month = mar, year = {2004}, pages = {RG1003}, } @article{optimx, author = {John Nash}, title = {On Best Practice Optimization Methods in R}, journal = {Journal of Statistical Software}, volume = 60, number = 1, year = 2014, issn = {1548-7660}, pages = {1--14}, doi = {10.18637/jss.v060.i02}, url = {https://www.jstatsoft.org/index.php/jss/article/view/v060i02} } @manual{energy, title = {energy: E-statistics (energy statistics)}, author = {Maria L. Rizzo and Gabor J. Szekely}, year = {2014}, note = {R package version 1.6.2}, url = {https://CRAN.R-project.org/package=energy}, } @misc{soeren_sonnenburg_2017_1067840, author = {Soeren Sonnenburg and Heiko Strathmann and Sergey Lisitsyn and Viktor Gal and Fernando J. Iglesias García and Wu Lin and Soumyajit De and Chiyuan Zhang and frx and tklein23 and Evgeniy Andreev and JonasBehr and sploving and Parijat Mazumdar and Christian Widmer and Pan Deng / Zora and Giovanni De Toni and Saurabh Mahindre and Abhijeet Kislay and Kevin Hughes and Roman Votyakov and khalednasr and Sanuj Sharma and Alesis Novik and Abinash Panda and Evangelos Anagnostopoulos and Liang Pang and Alex Binder and serialhex and Björn Esser}, title = {shogun-toolbox/shogun: Shogun 6.1.0}, month = nov, year = 2017, doi = {10.5281/zenodo.1067840}, url = {https://doi.org/10.5281/zenodo.1067840} } @article{scikit-learn, title={Scikit-learn: Machine Learning in {P}ython}, author={Pedregosa, F. and Varoquaux, G. and Gramfort, A. and Michel, V. and Thirion, B. and Grisel, O. and Blondel, M. and Prettenhofer, P. and Weiss, R. and Dubourg, V. and Vanderplas, J. and Passos, A. and Cournapeau, D. and Brucher, M. and Perrot, M. and Duchesnay, E.}, journal={Journal of Machine Learning Research}, volume={12}, pages={2825--2830}, year={2011} } @article{torgerson_multidimensional_1952, title = {Multidimensional scaling: {I}. {Theory} and method}, volume = {17}, issn = {0033-3123, 1860-0980}, shorttitle = {Multidimensional scaling}, url = {http://link.springer.com/article/10.1007/BF02288916}, doi = {10.1007/BF02288916}, language = {en}, number = {4}, urldate = {2016-08-16}, journal = {Psychometrika}, author = {Torgerson, Warren S.}, year = {1952}, pages = {401--419}, } @article{tenenbaum_global_2000, title = {A {Global} {Geometric} {Framework} for {Nonlinear} {Dimensionality} {Reduction}}, volume = {290}, issn = {0036-8075, 1095-9203}, url = {http://science.sciencemag.org/content/290/5500/2319}, doi = {10.1126/science.290.5500.2319}, language = {en}, number = {5500}, urldate = {2016-07-13}, journal = {Science}, author = {Tenenbaum, Joshua B. and Silva, Vin de and Langford, John C.}, month = dec, year = {2000}, pmid = {11125149}, pages = {2319--2323}, } @article{roweis_nonlinear_2000, title = {Nonlinear {Dimensionality} {Reduction} by {Locally} {Linear} {Embedding}}, volume = {290}, issn = {0036-8075, 1095-9203}, url = {http://science.sciencemag.org/content/290/5500/2323}, doi = {10.1126/science.290.5500.2323}, language = {en}, number = {5500}, urldate = {2016-08-16}, journal = {Science}, author = {Roweis, Sam T. and Saul, Lawrence K.}, month = dec, year = {2000}, pmid = {11125150}, pages = {2323--2326}, } @article{kruskal_multidimensional_1964, title = {Multidimensional scaling by optimizing goodness of fit to a nonmetric hypothesis}, volume = {29}, issn = {0033-3123, 1860-0980}, url = {http://link.springer.com/article/10.1007/BF02289565}, doi = {10.1007/BF02289565}, language = {en}, number = {1}, urldate = {2016-12-22}, journal = {Psychometrika}, author = {Kruskal, J. B.}, month = mar, year = {1964}, pages = {1--27}, } @article{kruskal_nonmetric_1964, title = {Nonmetric multidimensional scaling: {A} numerical method}, volume = {29}, issn = {0033-3123, 1860-0980}, shorttitle = {Nonmetric multidimensional scaling}, url = {http://link.springer.com/article/10.1007/BF02289694}, doi = {10.1007/BF02289694}, language = {en}, number = {2}, urldate = {2016-12-22}, journal = {Psychometrika}, author = {Kruskal, J. B.}, month = jun, year = {1964}, pages = {115--129}, } @article{coifman_geometric_2005, title = {Geometric diffusions as a tool for harmonic analysis and structure definition of data: {Diffusion} maps}, volume = {102}, issn = {0027-8424, 1091-6490}, shorttitle = {Geometric diffusions as a tool for harmonic analysis and structure definition of data}, url = {http://www.pnas.org/content/102/21/7426}, doi = {10.1073/pnas.0500334102}, language = {en}, number = {21}, urldate = {2016-03-30}, journal = {Proceedings of the National Academy of Sciences of the United States of America}, author = {Coifman, R. R. and Lafon, S. and Lee, A. B. and Maggioni, M. and Nadler, B. and Warner, F. and Zucker, S. W.}, month = may, year = {2005}, pmid = {15899970}, pages = {7426--7431}, } @article{coifman_diffusion_2006, title = {Diffusion maps}, volume = {21}, issn = {10635203}, url = {http://linkinghub.elsevier.com/retrieve/pii/S1063520306000546}, doi = {10.1016/j.acha.2006.04.006}, language = {en}, number = {1}, urldate = {2016-08-16}, journal = {Applied and Computational Harmonic Analysis}, author = {Coifman, Ronald R. and Lafon, Stéphane}, month = jul, year = {2006}, pages = {5--30}, } @article{scholkopf_nonlinear_1998, title = {Nonlinear {Component} {Analysis} as a {Kernel} {Eigenvalue} {Problem}}, volume = {10}, issn = {08997667}, doi = {10.1162/089976698300017467}, number = {5}, journal = {Neural Computation}, author = {Schölkopf, Bernhard and Smola, Alexander and Müller, Klaus-Robert}, year = {1998}, pages = {1299--1319}, } @article{hyvarinen_fast_1999, title = {Fast and robust fixed-point algorithms for independent component analysis}, volume = {10}, issn = {1045-9227}, doi = {10.1109/72.761722}, number = {3}, journal = {IEEE Transactions on Neural Networks}, author = {Hyvarinen, A.}, month = may, year = {1999}, pages = {626--634}, } @article{comon_independent_1994, title = {Independent component analysis, {A} new concept?}, volume = {36}, issn = {01651684}, url = {http://linkinghub.elsevier.com/retrieve/pii/0165168494900299}, doi = {10.1016/0165-1684(94)90029-9}, language = {en}, number = {3}, urldate = {2016-08-17}, journal = {Signal Processing}, author = {Comon, Pierre}, month = apr, year = {1994}, pages = {287--314}, } @article{kamada_algorithm_1989, title = {An algorithm for drawing general undirected graphs}, volume = {31}, issn = {0020-0190}, url = {http://www.sciencedirect.com/science/article/pii/0020019089901026}, doi = {10.1016/0020-0190(89)90102-6}, number = {1}, urldate = {2016-08-17}, journal = {Information Processing Letters}, author = {Kamada, Tomihisa and Kawai, Satoru}, month = apr, year = {1989}, pages = {7--15}, } @article{fruchterman_graph_1991, title = {Graph drawing by force-directed placement}, volume = {21}, issn = {1097-024X}, doi = {10.1002/spe.4380211102}, language = {en}, number = {11}, urldate = {2016-08-17}, journal = {Softw: Pract. Exper.}, author = {Fruchterman, Thomas M. J. and Reingold, Edward M.}, month = nov, year = {1991}, pages = {1129--1164}, } @techreport{martin_dr.l:_2007, title = {Dr.l: {Distributed} {Recursive} (graph) {Layout}}, shorttitle = {Dr.l}, url = {http://www.osti.gov/scitech/biblio/1231060-dr-distributed-recursive-graph-layout}, number = {dRl; 002182MLTPL00}, urldate = {2016-08-17}, institution = {Sandia National Laboratories}, author = {Martin, Shawn and Brown, W. Michael and Wylie, Brian N.}, month = nov, year = {2007}, } @article{belkin_laplacian_2003, title = {Laplacian {Eigenmaps} for {Dimensionality} {Reduction} and {Data} {Representation}}, volume = 15, issn = 08997667, doi = {10.1162/089976603321780317}, number = 6, urldate = {2016-08-17}, journal = {Neural Computation}, author = {Belkin, Mikhail and Niyogi, Partha}, month = jun, year = 2003, pages = 1373, } @inproceedings{terada_local_2014, title = {Local {Ordinal} {Embedding}}, url = {http://jmlr.org/proceedings/papers/v32/terada14.html}, urldate = {2016-04-21}, author = {Terada, Yoshikazu and Luxburg, Ulrike von}, year = {2014}, pages = {847--855} } @article{van_der_maaten_visualizing_2008, title = {Visualizing {Data} using t-{SNE}}, volume = {9}, issn = {1532-4435}, language = {English}, journal = {J. Mach. Learn. Res.}, author = {van der Maaten, Laurens and Hinton, Geoffrey}, month = nov, year = {2008}, note = {WOS:000262637600007}, pages = {2579--2605}, } @incollection{hinton_stochastic_2003, title = {Stochastic {Neighbor} {Embedding}}, url = {http://papers.nips.cc/paper/2276-stochastic-neighbor-embedding.pdf}, urldate = {2016-08-17}, booktitle = {Advances in {Neural} {Information} {Processing} {Systems} 15}, publisher = {MIT Press}, author = {Hinton, Geoffrey E. and Roweis, Sam T.}, editor = {Becker, S. and Thrun, S. and Obermayer, K.}, year = {2003}, pages = {857--864}, } @article{lee_multi-scale_2015, series = {Learning for {Visual} {Semantic} {Understanding} in {Big} {DataESANN} 2014Industrial {Data} {Processing} and {AnalysisSelected} papers from the 22nd {European} {Symposium} on {Artificial} {Neural} {Networks}, {Computational} {Intelligence} and {Machine} {Learning} ({ESANN} 2014){Selected} papers from the 11th {World} {Congress} on {Intelligent} {Control} and {Automation} ({WCICA}2014)}, title = {Multi-scale similarities in stochastic neighbour embedding: {Reducing} dimensionality while preserving both local and global structure}, volume = {169}, issn = {0925-2312}, shorttitle = {Multi-scale similarities in stochastic neighbour embedding}, url = {http://www.sciencedirect.com/science/article/pii/S0925231215003641}, doi = {10.1016/j.neucom.2014.12.095}, urldate = {2016-04-28}, journal = {Neurocomputing}, author = {Lee, John A. and Peluffo-Ordóñez, Diego H. and Verleysen, Michel}, month = dec, year = {2015}, pages = {246--261}, } @article{lee_type_2013, series = {Advances in artificial neural networks, machine learning, and computational {intelligenceSelected} papers from the 20th {European} {Symposium} on {Artificial} {Neural} {Networks} ({ESANN} 2012)}, title = {Type 1 and 2 mixtures of {Kullback}–{Leibler} divergences as cost functions in dimensionality reduction based on similarity preservation}, volume = {112}, issn = {0925-2312}, url = {http://www.sciencedirect.com/science/article/pii/S0925231213001471}, doi = {10.1016/j.neucom.2012.12.036}, urldate = {2016-04-28}, journal = {Neurocomputing}, author = {Lee, John A. and Renard, Emilie and Bernard, Guillaume and Dupont, Pierre and Verleysen, Michel}, month = jul, year = {2013}, pages = {92--108}, } @article{venna_information_2010, title = {Information {Retrieval} {Perspective} to {Nonlinear} {Dimensionality} {Reduction} for {Data} {Visualization}}, volume = {11}, issn = {1532-4435}, language = {English}, journal = {J. Mach. Learn. Res.}, author = {Venna, Jarkko and Peltonen, Jaakko and Nybo, Kristian and Aidos, Helena and Kaski, Samuel}, month = feb, year = {2010}, note = {WOS:000277186500001}, pages = {451--490}, } @article{laparra_dimensionality_2015, title = {Dimensionality {Reduction} via {Regression} in {Hyperspectral} {Imagery}}, volume = {9}, issn = {1932-4553}, doi = {10.1109/JSTSP.2015.2417833}, number = {6}, journal = {IEEE Journal of Selected Topics in Signal Processing}, author = {Laparra, V. and Malo, J. and Camps-Valls, G.}, month = sep, year = {2015}, pages = {1026--1036}, } @article{chen_local_2006, author = {Lisha Chen and Andreas Buja}, title = {Local Multidimensional Scaling for Nonlinear Dimension Reduction, Graph Drawing, and Proximity Analysis}, journal = {Journal of the American Statistical Association}, volume = {104}, number = {485}, pages = {209-219}, year = {2009}, publisher = {Taylor & Francis}, doi = {10.1198/jasa.2009.0111}, URL = {https://doi.org/10.1198/jasa.2009.0111}, eprint = {https://doi.org/10.1198/jasa.2009.0111} } @inproceedings{saunders_ridge_1998, author = {Saunders, Craig and Gammerman, Alexander and Vovk, Volodya}, title = {Ridge Regression Learning Algorithm in Dual Variables}, booktitle = {Proceedings of the Fifteenth International Conference on Machine Learning}, series = {ICML '98}, year = {1998}, isbn = {1-55860-556-8}, pages = {515--521}, numpages = {7}, url = {http://dl.acm.org/citation.cfm?id=645527.657464}, acmid = {657464}, publisher = {Morgan Kaufmann Publishers Inc.}, address = {San Francisco, CA, USA}, } @article{lee_quality_2009, series = {Advances in {Machine} {Learning} and {Computational} {Intelligence}16th {European} {Symposium} on {Artificial} {Neural} {Networks} 200816th {European} {Symposium} on {Artificial} {Neural} {Networks} 2008}, title = {Quality assessment of dimensionality reduction: {Rank}-based criteria}, volume = {72}, issn = {0925-2312}, shorttitle = {Quality assessment of dimensionality reduction}, url = {http://www.sciencedirect.com/science/article/pii/S0925231209000101}, doi = {10.1016/j.neucom.2008.12.017}, number = {7–9}, urldate = {2016-04-04}, journal = {Neurocomputing}, author = {Lee, John A. and Verleysen, Michel}, month = mar, year = {2009}, pages = {1431--1443}, } @article{sokal_comparison_1962, title = {The {Comparison} of {Dendrograms} by {Objective} {Methods}}, volume = {11}, issn = {0040-0262}, url = {http://www.jstor.org/stable/1217208}, doi = {10.2307/1217208}, number = {2}, urldate = {2016-08-15}, journal = {Taxon}, author = {Sokal, Robert R. and Rohlf, F. James}, year = {1962}, pages = {33--40}, } @article{szekely_measuring_2007, title = {Measuring and testing dependence by correlation of distances}, volume = {35}, issn = {0090-5364, 2168-8966}, url = {http://projecteuclid.org/euclid.aos/1201012979}, doi = {10.1214/009053607000000505}, language = {EN}, number = {6}, urldate = {2016-06-10}, journal = {The Annals of Statistics}, author = {Székely, Gábor J. and Rizzo, Maria L. and Bakirov, Nail K.}, month = dec, year = {2007}, mrnumber = {MR2382665}, zmnumber = {1129.62059}, pages = {2769--2794}, } @article{kireeva_nonlinear_2014, title = {Nonlinear {Dimensionality} {Reduction} for {Visualizing} {Toxicity} {Data}: {Distance}-{Based} {Versus} {Topology}-{Based} {Approaches}}, volume = {9}, issn = {1860-7187}, shorttitle = {Nonlinear {Dimensionality} {Reduction} for {Visualizing} {Toxicity} {Data}}, doi = {10.1002/cmdc.201400027}, language = {en}, number = {5}, urldate = {2016-08-19}, journal = {ChemMedChem}, author = {Kireeva, Natalia V. and Ovchinnikova, Svetlana I. and Tetko, Igor V. and Asiri, Abdullah M. and Balakin, Konstantin V. and Tsivadze, Aslan Yu.}, month = may, year = {2014}, pages = {1047--1059}, } @article{han_deep_2016, author = {Han, Yoonchang and Kim, Jaehun and Lee, Kyogu}, title = {{Deep Convolutional Neural Networks for Predominant Instrument Recognition in Polyphonic Music}}, journal = {{IEEE-ACM TRANSACTIONS ON AUDIO SPEECH AND LANGUAGE PROCESSING}}, year = {{2017}}, volume = {{25}}, number = {{1}}, pages = {{208-221}}, month = {{JAN}}, publisher = {{IEEE-INST ELECTRICAL ELECTRONICS ENGINEERS INC}}, language = {{English}}, doi = {{10.1109/TASLP.2016.2632307}}, issn = {{2329-9290}}, } @article{van_der_maaten_dimensionality_2009, title = {Dimensionality reduction: a comparative review}, volume = {10}, shorttitle = {Dimensionality reduction}, urldate = {2016-06-28}, journal = {J Mach Learn Res}, author = {Van Der Maaten, Laurens and Postma, Eric and Van den Herik, Jaap}, year = {2009}, pages = {66--71}, } @inproceedings{bengio_out--sample_2003, title = {Out-of-{Sample} {Extensions} for {LLE}, {Isomap}, {MDS}, {Eigenmaps}, and {Spectral} {Clustering}}, booktitle = {In {Advances} in {Neural} {Information} {Processing} {Systems}}, publisher = {MIT Press}, author = {Bengio, Yoshua and Paiement, Jean-Francois and Vincent, Pascal}, year = {2003}, pages = {177--184}, } @article{lueks_how_2011, title = {How to {Evaluate} {Dimensionality} {Reduction}? - {Improving} the {Co}-ranking {Matrix}}, shorttitle = {How to {Evaluate} {Dimensionality} {Reduction}?}, url = {http://arxiv.org/abs/1110.3917}, urldate = {2016-03-18}, journal = {arXiv:1110.3917 [cs]}, author = {Lueks, Wouter and Mokbel, Bassam and Biehl, Michael and Hammer, Barbara}, month = oct, year = {2011}, note = {arXiv: 1110.3917}, } @techreport{de_silva_sparse_2004, title = {Sparse multidimensional scaling using landmark points}, author = {De Silva, Vin and Tenenbaum, Joshua B/r}, year = {2004}, } @article{groenen_multidimensional_2016, title = {Multidimensional {Scaling} by {Majorization}: {A} {Review}}, volume = {73}, issn = {1548-7660}, url = {https://www.jstatsoft.org/index.php/jss/article/view/v073i08}, doi = {10.18637/jss.v073.i08}, number = {1}, journal = {Journal of Statistical Software}, author = {Groenen, Patrick and Velden, Michel van de}, year = {2016}, pages = {1--26}, } @article{leeuw_multidimensional_2009, author = {de Leeuw, Jan and Mair, Patrick}, title = {{Multidimensional Scaling Using Majorization: SMACOF in R}}, journal = {{JOURNAL OF STATISTICAL SOFTWARE}}, year = {{2009}}, volume = {{31}}, number = {{3}}, pages = {{1--30}}, month = {{AUG}}, publisher = {{JOURNAL STATISTICAL SOFTWARE}}, ISSN = {{1548-7660}}, } @article{bengio_learning_2004, title = {Learning {Eigenfunctions} {Links} {Spectral} {Embedding} and {Kernel} {PCA}}, volume = {16}, issn = {0899-7667}, url = {http://dx.doi.org/10.1162/0899766041732396}, doi = {10.1162/0899766041732396}, number = {10}, urldate = {2016-10-05}, journal = {Neural Computation}, author = {Bengio, Yoshua and Delalleau, Olivier and Roux, Nicolas Le and Paiement, Jean-François and Vincent, Pascal and Ouimet, Marie}, month = oct, year = {2004}, pages = {2197--2219}, } @misc{_gdkrmr/dimred_????, title = {gdkrmr/{dimRed}}, url = {https://github.com/gdkrmr/dimRed}, urldate = {2016-11-30}, journal = {GitHub}, } @book{luxburg_tutorial_2007, title = {A {Tutorial} on {Spectral} {Clustering}}, author = {Luxburg, Ulrike Von}, year = {2007}, } @article{kraemer_dimred_2018, title = {{dimRed} and {coRanking} - {Unifying} {Dimensionality} {Reduction} in {R}}, url = {https://journal.r-project.org/archive/2018/RJ-2018-039/index.html}, journal = {The R Journal}, author = {Kraemer, Guido and Reichstein, Markus and Mahecha, Miguel D.}, year = {2018}, }dimRed/vignettes/dimensionality-reduction.Rnw0000644000176200001440000017352413371631672021225 0ustar liggesusers\documentclass{article} %\VignetteEngine{knitr::knitr} %\VignetteIndexEntry{Dimensionality Reduction} %\VignetteKeyword{Dimensionality Reduction} \usepackage[utf8]{inputenc} \usepackage[T1]{fontenc} \usepackage{hyperref} \usepackage{amsmath,amssymb} \usepackage{booktabs} \usepackage{tikz} \usetikzlibrary{trees} \usepackage[sectionbib,round]{natbib} \title{\pkg{dimRed} and \pkg{coRanking}---Unifying Dimensionality Reduction in R} \author{Guido Kraemer \and Markus Reichstein \and Miguel D.\ Mahecha} % these are taken from RJournal.sty: \makeatletter \DeclareRobustCommand\code{\bgroup\@noligs\@codex} \def\@codex#1{\texorpdfstring% {{\normalfont\ttfamily\hyphenchar\font=-1 #1}}% {#1}\egroup} \newcommand{\kbd}[1]{{\normalfont\texttt{#1}}} \newcommand{\key}[1]{{\normalfont\texttt{\uppercase{#1}}}} \DeclareRobustCommand\samp{`\bgroup\@noligs\@sampx} \def\@sampx#1{{\normalfont\texttt{#1}}\egroup'} \newcommand{\var}[1]{{\normalfont\textsl{#1}}} \let\env=\code \newcommand{\file}[1]{{`\normalfont\textsf{#1}'}} \let\command=\code \let\option=\samp \newcommand{\dfn}[1]{{\normalfont\textsl{#1}}} % \acronym is effectively disabled since not used consistently \newcommand{\acronym}[1]{#1} \newcommand{\strong}[1]{\texorpdfstring% {{\normalfont\fontseries{b}\selectfont #1}}% {#1}} \let\pkg=\strong \newcommand{\CRANpkg}[1]{\href{https://CRAN.R-project.org/package=#1}{\pkg{#1}}}% \let\cpkg=\CRANpkg \newcommand{\ctv}[1]{\href{https://CRAN.R-project.org/view=#1}{\emph{#1}}} \newcommand{\BIOpkg}[1]{\href{https://www.bioconductor.org/packages/release/bioc/html/#1.html}{\pkg{#1}}} \makeatother \begin{document} \maketitle \abstract{ % This document is based on the manuscript of \citet{kraemer_dimred_2018} which was published in the R-Journal and has been modified and extended to fit the format of a package vignette and to match the extended functionality of the \pkg{dimRed} package. ``Dimensionality reduction'' (DR) is a widely used approach to find low dimensional and interpretable representations of data that are natively embedded in high-dimensional spaces. % DR can be realized by a plethora of methods with different properties, objectives, and, hence, (dis)advantages. The resulting low-dimensional data embeddings are often difficult to compare with objective criteria. % Here, we introduce the \CRANpkg{dimRed} and \CRANpkg{coRanking} packages for the R language. % These open source software packages enable users to easily access multiple classical and advanced DR methods using a common interface. % The packages also provide quality indicators for the embeddings and easy visualization of high dimensional data. % The \pkg{coRanking} package provides the functionality for assessing DR methods in the co-ranking matrix framework. % In tandem, these packages allow for uncovering complex structures high dimensional data. % Currently 15 DR methods are available in the package, some of which were not previously available to R users. % Here, we outline the \pkg{dimRed} and \pkg{coRanking} packages and make the implemented methods understandable to the interested reader. % } \section{Introduction} \label{sec:intro} Dimensionality Reduction (DR) essentially aims to find low dimensional representations of data while preserving their key properties. % Many methods exist in literature, optimizing different criteria: % maximizing the variance or the statistical independence of the projected data, % minimizing the reconstruction error under different constraints, % or optimizing for different error metrics, % just to name a few. % Choosing an inadequate method may imply that much of the underlying structure remains undiscovered. % Often the structures of interest in a data set can be well represented by fewer dimensions than exist in the original data. % Data compression of this kind has the additional benefit of making the encoded information better conceivable to our brains for further analysis tasks like classification or regression problems. % For example, the morphology of a plant's leaves, stems, and seeds reflect the environmental conditions the species usually grow in (e.g.,\ plants with large soft leaves will never grow in a desert but might have an advantage in a humid and shadowy environment). % Because the morphology of the entire plant depends on the environment, many morphological combinations will never occur in nature and the morphological space of all plant species is tightly constrained. % \citet{diaz_global_2016} found that out of six observed morphological characteristics only two embedding dimensions were enough to represent three quarters of the totally observed variability. % DR is a widely used approach for the detection of structure in multivariate data, and has applications in a variety of fields. % In climatology, DR is used to find the modes of some phenomenon, e.g.,\ the first Empirical Orthogonal Function of monthly mean sea surface temperature of a given region over the Pacific is often linked to the El Ni\~no Southern Oscillation or ENSO \citep[e.g.,\ ][]{hsieh_nonlinear_2004}. % In ecology the comparison of sites with different species abundances is a classical multivariate problem: each observed species adds an extra dimension, and because species are often bound to certain habitats, there is a lot of redundant information. Using DR is a popular technique to represent the sites in few dimensions, e.g.,\ \citet{aart_distribution_1972} matches wolfspider communities to habitat and \citet{morrall_soil_1974} match soil fungi data to soil types. (In ecology the general name for DR is ordination or indirect gradient analysis.) % Today, hyperspectral satellite imagery collects so many bands that it is very difficult to analyze and interpret the data directly. % Resuming the data into a set of few, yet independent, components is one way to reduce complexity \citep[e.g.,\ see][]{laparra_dimensionality_2015}. % DR can also be used to visualize the interiors of deep neural networks \citep[e.g.,\ see ][]{han_deep_2016}, where the high dimensionality comes from the large number of weights used in a neural network and convergence can be visualized by means of DR\@. % We could find many more example applications here but this is not the main focus of this publication. % The difficulty in applying DR is that each DR method is designed to maintain certain aspects of the original data and therefore may be appropriate for one task and inappropriate for another. % Most methods also have parameters to tune and follow different assumptions. The quality of the outcome may strongly depend on their tuning, which adds additional complexity. % DR methods can be modeled after physical models with attracting and repelling forces (Force Directed Methods), projections onto low dimensional planes (PCA, ICA), divergence of statistical distributions (SNE family), or the reconstruction of local spaces or points by their neighbors (LLE). % As an example for how changing internal parameters of a method can have a great impact, the breakthrough for Stochastic Neighborhood Embedding (SNE) methods came when a Student's $t$-distribution was used instead of a normal distribution to model probabilities in low dimensional space to avoid the ``crowding problem'', that is,\ a sphere in high dimensional space has a much larger volume than in low dimensional space and may contain too many points to be represented accurately in few dimensions. % The $t$-distribution, allows medium distances to be accurately represented in few dimensions by larger distances due to its heavier tails. % The result is called in $t$-SNE and is especially good at preserving local structures in very few dimensions, this feature made $t$-SNE useful for a wide array of data visualization tasks and the method became much more popular than standard SNE (around six times more citations of \citet{van_der_maaten_visualizing_2008} compared to \citet{hinton_stochastic_2003} in Scopus \citep{noauthor_scopus_nodate}). % There are a number of software packages for other languages providing collections of methods: In Python there is scikit-learn \citep{scikit-learn}, which contains a module for DR. In Julia we currently find ManifoldLearning.jl for nonlinear and MultivariateStats.jl for linear DR methods. % There are several toolboxes for DR implemented in Matlab \citep{van_der_maaten_dimensionality_2009, arenas-garcia_kernel_2013}. The Shogun toolbox \citep{soeren_sonnenburg_2017_1067840} implements a variety of methods for dimensionality reduction in C++ and offers bindings for a many common high level languages (including R, but the installation is anything but simple, as there is no CRAN package). % However, there is no comprehensive package for R and none of the former mentioned software packages provides means to consistently compare the quality of different methods for DR. % For many applications it can be difficult to objectively find the right method or parameterization for the DR task. % This paper presents the \pkg{dimRed} and \pkg{coRanking} packages for the popular programming language R. Together, they provide a standardized interface to various dimensionality reduction methods and quality metrics for embeddings. They are implemented using the S4 class system of R, making the packages both easy to use and to extend. The design goal for these packages is to enable researchers, who may not necessarily be experts in DR, to apply the methods in their own work and to objectively identify the most suitable methods for their data. % This paper provides an overview of the methods collected in the packages and contains examples as to how to use the packages. % The notation in this paper will be as follows: $X = [x_i]_{1\leq i \leq n}^T \in \mathbb{R}^{n\times p}$, and the observations $x_i \in \mathbb{R}^p$. % These observations may be transformed prior to the dimensionality reduction step (e.g.,\ centering and/or standardization) resulting in $X' = [x'_i]_{1\leq i \leq n}^T \in \mathbb{R}^{n\times p}$. % A DR method then embeds each vector in $X'$ onto a vector in $Y = [y_i]_{1\leq i \leq n}^T \in \mathbb{R}^{n\times q}$ with $y_i \in \mathbb{R}^q$, ideally with $q \ll p$. % Some methods provide an explicit mapping $f(x'_i) = y_i$. Some even offer an inverse mapping $f^{-1}(y_{i}) = \hat x'_{i}$, such that one can reconstruct a (usually approximate) sample from the low-dimensional representation. % For some methods, pairwise distances between points are needed, we set $d_{ij} = d(x_{i}, x_{j})$ and $\hat{d}_{ij} = d(y_i, y_j)$, where $d$ is some appropriate distance function. When referring to \code{functions} in the \pkg{dimRed} package or base R simply the function name is mentioned, functions from other packages are referenced with their namespace, as with \code{package::function}. \begin{figure}[htbp] \centering \input{classification_tree.tex} \caption{% Classification of dimensionality reduction methods. Methods in bold face are implemented in \pkg{dimRed}. Modified from \citet{van_der_maaten_dimensionality_2009}. }\label{fig:classification} \end{figure} \section{Dimensionality Reduction Methods} \label{sec:dimredtec} In the following section we do not aim for an exhaustive explanation to every method in \pkg{dimRed} but rather to provide a general idea on how the methods work. % An overview and classification of the most commonly used DR methods can be found in Figure~\ref{fig:classification}. In all methods, parameters have to be optimized or decisions have to be made, even if it is just about the preprocessing steps of data. % The \pkg{dimRed} package tries to make the optimization process for parameters as easy as possible, but, if possible, the parameter space should be narrowed down using prior knowledge. % Often decisions can be made based on theoretical knowledge. For example,\ sometimes an analysis requires data to be kept in their original scales and sometimes this is exactly what has to be avoided as when comparing different physical units. % Sometimes decisions based on the experience of others can be made, e.g.,\ the Gaussian kernel is probably the most universal kernel and therefore should be tested first if there is a choice. % All methods presented here have the embedding dimensionality, $q$, as a parameter (or \code{ndim} as a parameter for \code{embed}). % For methods based on eigenvector decomposition, the result generally does not depend on the number of dimensions, i.e.,\ the first dimension will be the same, no matter if we decide to calculate only two dimensions or more. % If more dimensions are added, more information is maintained, the first dimension is the most important and higher dimensions are successively less important. % This means, that a method based on eigenvalue decomposition only has to be run once if one wishes to compare the embedding in different dimensions. % In optimization based methods this is generally not the case, the number of dimensions has to be chosen a priori, an embedding of 2 and 3 dimensions may vary significantly, and there is no ordered importance of dimensions. % This means that comparing dimensions of optimization-based methods is computationally much more expensive. % We try to give the computational complexity of the methods. Because of the actual implementation, computation times may differ largely. % R is an interpreted language, so all parts of an algorithm that are implemented in R often will tend to be slow compared to methods that call efficient implementations in a compiled language. % Methods where most of the computing time is spent for eigenvalue decomposition do have very efficient implementations as R uses optimized linear algebra libraries. Although, eigenvalue decomposition itself does not scale very well in naive implementations ($\mathcal{O}(n^3)$). \subsection{PCA} \label{sec:pca} Principal Component Analysis (PCA) is the most basic technique for reducing dimensions. It dates back to \citet{pearson_lines_1901}. PCA finds a linear projection ($U$) of the high dimensional space into a low dimensional space $Y = XU$, maintaining maximum variance of the data. It is based on solving the following eigenvalue problem: \begin{equation} (C_{XX}-\lambda_k I)u_k=0\label{eq:pca} \end{equation} where $C_{XX} = \frac 1 n X^TX$ is the covariance matrix, $\lambda_k$ and $u_k$ are the $k$-th eigenvalue and eigenvector, and $I$ is the identity matrix. % The equation has several solutions for different values of $\lambda_k$ (leaving aside the trivial solution $u_k = 0$). % PCA can be efficiently applied to large data sets, because it computationally scales as $\mathcal{O}(np^2 + p^3)$, that is, it scales linearly with the number of samples and R uses specialized linear algebra libraries for such kind of computations. PCA is a rotation around the origin and there exist a forward and inverse mapping. % PCA may suffer from a scale problem, i.e.,\ when one variable dominates the variance simply because it is in a higher scale, to remedy this, the data can be scaled to zero mean and unit variance, depending on the use case, if this is necessary or desired. % Base R implements PCA in the functions \code{prcomp} and \code{princomp}; but several other implementations exist i.e., \BIOpkg{pcaMethods} from Bioconductor which implements versions of PCA that can deal with missing data. % The \pkg{dimRed} package wraps \code{prcomp}. \subsection{kPCA} \label{sec:kpca} Kernel Principal Component Analysis (kPCA) extends PCA to deal with nonlinear dependencies among variables. % The idea behind kPCA is to map the data into a high dimensional space using a possibly non-linear function $\phi$ and then to perform a PCA in this high dimensional space. % Some mathematical tricks are used for efficient computation. % If the columns of X are centered around $0$, then the principal components can also be computed from the inner product matrix $K = X^TX$. % Due to this way of calculating a PCA, we do not need to explicitly map all points into the high dimensional space and do the calculations there, it is enough to obtain the inner product matrix or kernel matrix $K \in \mathbb{R}^{n\times n}$ of the mapped points \citep{scholkopf_nonlinear_1998}. % Here is an example calculating the kernel matrix using a Gaussian kernel: \begin{equation}\label{eq:gauss} K = \phi(x_i)^T \phi(x_j) = \kappa(x_i, x_j) = \exp\left( -\frac{\| x_i- x_j\|^2}{2 \sigma^2} \right), \end{equation} where $\sigma$ is a length scale parameter accounting for the width of the kernel. % The other trick used is known as the ``representers theorem.'' The interested reader is referred to \citet{scholkopf_generalized_2001}. The kPCA method is very flexible and there exist many kernels for special purposes. The most common kernel function is the Gaussian kernel (Equation\ \ref{eq:gauss}). % The flexibility comes at the price that the method has to be finely tuned for the data set because some parameter combinations are simply unsuitable for certain data. % The method is not suitable for very large data sets, because memory scales with $\mathcal{O}(n^2)$ and computation time with $\mathcal{O}(n^3)$. % Diffusion Maps, Isomap, Locally Linear Embedding, and some other techniques can be seen as special cases of kPCA. In which case, an out-of-sample extension using the Nyström formula can be applied \citep{bengio_learning_2004}. % This can also yield applications for bigger data, where an embedding is trained with a sub-sample of all data and then the data is embedded using the Nyström formula. Kernel PCA in R is implemented in the \CRANpkg{kernlab} package using the function \code{kernlab::kpca}, and supports a number of kernels and user defined functions. For details see the help page for \code{kernlab::kpca}. The \pkg{dimRed} package wraps \code{kernlab::kpca} but additionally provides forward and inverse methods \citep{bakir_learning_2004} which can be used to fit out-of-sample data or to visualize the transformation of the data space. % \subsection{Classical Scaling} \label{sec:classscale} What today is called Classical Scaling was first introduced by \citet{torgerson_multidimensional_1952}. It uses an eigenvalue decomposition of a transformed distance matrix to find an embedding that maintains the distances of the distance matrix. % The method works because of the same reason that kPCA works, i.e.,\ classical scaling can be seen as a kPCA with kernel $x^Ty$. % A matrix of Euclidean distances can be transformed into an inner product matrix by some simple transformations and therefore yields the same result as a PCA\@. % Classical scaling is conceptually more general than PCA in that arbitrary distance matrices can be used, i.e.,\ the method does not even need the original coordinates, just a distance matrix $D$. % Then it tries to find an embedding $Y$ so that $\hat d_{ij}$ is as similar to $d_{ij}$ as possible. The disadvantage is that it is computationally much more demanding, i.e.,\ an eigenvalue decomposition of an $n\times n$ matrix has to be computed. This step requires $\mathcal{O}(n^2)$ memory and $\mathcal{O}(n^3)$ computation time, while PCA requires only the eigenvalue decomposition of a $d\times d$ matrix and usually $n \gg d$. % R implements classical scaling in the \code{cmdscale} function. % The \pkg{dimRed} package wraps \code{cmdscale} and allows the specification of arbitrary distance functions for calculating the distance matrix. Additionally a forward method is implemented. \subsection{Isomap} \label{sec:isomap} As Classical Scaling can deal with arbitrarily defined distances, \citet{tenenbaum_global_2000} suggested to approximate the structure of the manifold by using geodesic distances. % In practice, a graph is created by either keeping only the connections between every point and its $k$ nearest neighbors to produce a $k$-nearest neighbor graph ($k$-NNG), or simply by keeping all distances smaller than a value $\varepsilon$ producing an $\varepsilon$-neighborhood graph ($\varepsilon$-NNG). % Geodesic distances are obtained by recording the distance on the graph and classical scaling is used to find an embedding in fewer dimensions. This leads to an ``unfolding'' of possibly convoluted structures (see Figure~\ref{fig:knn}). Isomap's computational cost is dominated by the eigenvalue decomposition and therefore scales with $\mathcal{O}(n^3)$. % Other related techniques can use more efficient algorithms because the distance matrix becomes sparse due to a different preprocessing. In R, Isomap is implemented in the \CRANpkg{vegan} package. The \code{vegan::isomap} calculates an Isomap embedding and \code{vegan::isomapdist} calculates a geodesic distance matrix. % The \pkg{dimRed} package uses its own implementation. This implementation is faster mainly due to using a KD-tree for the nearest neighbor search (from the \CRANpkg{RANN} package) and to a faster implementation for the shortest path search in the $k$-NNG (from the \CRANpkg{igraph} package). % The implementation in \pkg{dimRed} also includes a forward method that can be used to train the embedding on a subset of data points and then use these points to approximate an embedding for the remaining points. This technique is generally referred to as landmark Isomap \citep{de_silva_sparse_2004}. % \subsection{Locally Linear Embedding} \label{sec:lle} Points that lie on a manifold in a high dimensional space can be reconstructed through linear combinations of their neighborhoods if the manifold is well sampled and the neighbohoods lie on a locally linear patch. % These reconstruction weights, $W$, are the same in the high dimensional space as the internal coordinates of the manifold. % Locally Linear Embedding \citep[LLE; ][]{roweis_nonlinear_2000} is a technique that constructs a weight matrix $W \in \mathbb{R}^{n\times n}$ with elements $w_{ij}$ so that \begin{equation} \sum_{i=1}^n \bigg\| x_i- \sum_{j=1}^{n} w_{ij}x_j \bigg\|^2\label{eq:lle} \end{equation} is minimized under the constraint that $w_{ij} = 0 $ if $x_j$ does not belong to the neighborhood and the constraint that $\sum_{j=1}^n w_{ij} = 1$. % Finally the embedding is made in such a way that the following cost function is minimized for $Y$, \begin{equation} \sum_{i=1}^n\bigg\| y_i - \sum_{j=1}^n w_{ij}y_j \bigg\|^2.\label{eq:lle2} \end{equation} This can be solved using an eigenvalue decomposition. Conceptually the method is similar to Isomap but it is computationally much nicer because the weight matrix is sparse and there exist efficient solvers. % In R, LLE is implemented by the package \CRANpkg{lle}, the embedding can be calculated with \code{lle::lle}. Unfortunately the implementation does not make use of the sparsity of the weight matrix $W$. % The manifold must be well sampled and the neighborhood size must be chosen appropriately for LLE to give good results. % \subsection{Laplacian Eigenmaps} \label{sec:laplaceigenmaps} Laplacian Eigenmaps were originally developed under the name spectral clustering to separate non-convex clusters. % Later it was also used for graph embedding and DR \citep{belkin_laplacian_2003}. % A number of variants have been proposed. % First, a graph is constructed, usually from a distance matrix, the graph can be made sparse by keeping only the $k$ nearest neighbors, or by specifying an $\varepsilon$ neighborhood. % Then, a similarity matrix $W$ is calculated by using a Gaussian kernel (see Equation \ref{eq:gauss}), if $c = 2 \sigma^2 = \infty$, then all distances are treated equally, the smaller $c$ the more emphasis is given to differences in distance. % The degree of vertex $i$ is $d_i = \sum_{j=1}^n w_{ij}$ and the degree matrix, $D$, is the diagonal matrix with entries $d_i$. % Then we can form the graph Laplacian $L = D - W$ and, then, there are several ways how to proceed, an overview can be found in \citet{luxburg_tutorial_2007}. % The \pkg{dimRed} package implements the algorithm from \citet{belkin_laplacian_2003}. Analogously to LLE, Laplacian eigenmaps avoid computational complexity by creating a sparse matrix and not having to estimate the distances between all pairs of points. % Then the eigenvectors corresponding to the lowest eigenvalues larger than $0$ of either the matrix $L$ or the normalized Laplacian $D^{-1/2}LD^{-1/2}$ are computed and form the embedding. \subsection{Diffusion Maps} \label{sec:isodiffmaplle} Diffusion Maps \citep{coifman_diffusion_2006} take a distance matrix as input and calculates the transition probability matrix $P$ of a diffusion process between the points to approximate the manifold. % Then the embedding is done by an eigenvalue decompositon of $P$ to calculate the coordinates of the embedding. % The algorithm for calculating Diffusion Maps shares some elements with the way Laplacian Eigenmaps are calculated. % Both algorithms depart from the same weight matrix, Diffusion Maps calculate the transition probability on the graph after $t$ time steps and do the embedding on this probability matrix. The idea is to simulate a diffusion process between the nodes of the graph, which is more robust to short-circuiting than the $k$-NNG from Isomap (see bottom right Figure \ref{fig:knn}). % Diffusion maps in R are accessible via the \code{diffusionMap::diffuse()} function, which is available in the \CRANpkg{diffusionMap} package. % Additional points can be approximated into an existing embedding using the Nyström formula \citep{bengio_learning_2004}. % The implementation in \pkg{dimRed} is based on the \code{diffusionMap::diffuse} function. % , which does not contain an % approximation for unequally sampled manifolds % \citep{coifman_geometric_2005}. % \subsection{non-Metric Dimensional Scaling} \label{sec:nmds} While Classical Scaling and derived methods (see section \nameref{sec:classscale}) use eigenvector decomposition to embed the data in such a way that the given distances are maintained, non-Metric Dimensional Scaling \citep[nMDS, ][]{kruskal_multidimensional_1964,kruskal_nonmetric_1964} uses optimization methods to reach the same goal. % Therefore a stress function, \begin{equation} \label{eq:stress} S = \sqrt{\frac{\sum_{i>= if(Sys.getenv("BNET_BUILD_VIGNETTE") != "") { library(dimRed); library(ggplot2); #library(dplyr); library(tidyr) ## define which methods to apply embed_methods <- c("Isomap", "PCA") ## load test data set data_set <- loadDataSet("3D S Curve", n = 1000) ## apply dimensionality reduction data_emb <- lapply(embed_methods, function(x) embed(data_set, x)) names(data_emb) <- embed_methods ## plot data set, embeddings, and quality analysis ## plot(data_set, type = "3vars") ## lapply(data_emb, plot, type = "2vars") ## plot_R_NX(data_emb) add_label <- function(label) grid::grid.text(label, 0.2, 1, hjust = 0, vjust = 1, gp = grid::gpar(fontface = "bold", cex = 1.5)) ## pdf('~/phd/text/dimRedPackage/plots/plot_example.pdf', width = 4, height = 4) ## plot the results plot(data_set, type = "3vars", angle = 15, mar = c(3, 3, 0, 0), box = FALSE, grid = FALSE, pch = 16) add_label("a") par(mar = c(4, 4, 0, 0) + 0.1, bty = "n", las = 1) plot(data_emb$Isomap, type = "2vars", pch = 16) add_label("b") plot(data_emb$PCA, type = "2vars", pch = 16) add_label("d") ## calculate quality scores print( plot_R_NX(data_emb) + theme(legend.title = element_blank(), legend.position = c(0.5, 0.1), legend.justification = c(0.5, 0.1)) ) add_label("c") } else { # These cannot all be plot(1:10)!!! It's a mistery to me. plot(1:10) barplot(1:10) hist(1:10) plot(1:10) } @ \includegraphics[page=1,width=.45\textwidth]{figure/pca_isomap_example-1.pdf} \includegraphics[page=1,width=.45\textwidth]{figure/pca_isomap_example-2.pdf} \includegraphics[page=1,width=.45\textwidth]{figure/pca_isomap_example-3.pdf} \includegraphics[page=1,width=.45\textwidth]{figure/pca_isomap_example-4.pdf} \caption[dimRed example]{% Comparing PCA and Isomap: % (a) An S-shaped manifold, colors represent the internal coordinates of the manifold. % (b) Isomap embedding, the S-shaped manifold is unfolded. % (c) $R_{NX}$ plotted agains neighborhood sizes, Isomap is much better at preserving local distances and PCA is better at preserving global Euclidean distances. % The numbers on the legend are the $\text{AUC}_{1 / K}$. (d) PCA projection of the data, the directions of maximum variance are preserved. % }\label{fig:plotexample} \end{figure} <>= ## define which methods to apply embed_methods <- c("Isomap", "PCA") ## load test data set data_set <- loadDataSet("3D S Curve", n = 1000) ## apply dimensionality reduction data_emb <- lapply(embed_methods, function(x) embed(data_set, x)) names(data_emb) <- embed_methods ## figure \ref{fig:plotexample}a, the data set plot(data_set, type = "3vars") ## figures \ref{fig:plotexample}b (Isomap) and \ref{fig:plotexample}d (PCA) lapply(data_emb, plot, type = "2vars") ## figure \ref{fig:plotexample}c, quality analysis plot_R_NX(data_emb) @ The function \code{plot\_R\_NX} produces a figure that plots the neighborhood size ($k$ at a log-scale) against the quality measure $\text{R}_{NX}(k)$ (see Equation \ref{eq:rnx}). % This gives an overview of the general behavior of methods: if $\text{R}_{NX}$ is high for low values of $K$, then local neighborhoods are maintained well; if $\text{R}_{NX}$ is high for large values of $K$, then global gradients are maintained well. % It also provides a way to directly compare methods by plotting more than one $\text{R}_{NX}$ curve and an overall quality of the embedding by taking the area under the curve as an indicator for the overall quality of the embedding (see fig~\ref{eq:auclnk}) which is shown as a number in the legend. Therefore we can see from Figure~\ref{fig:plotexample}c that $t$-SNE is very good a maintaining close and medium distances for the given data set, whereas PCA is only better at maintaining the very large distances. % The large distances are dominated by the overall bent shape of the S in 3D space, while the close distances are not affected by this bending. % This is reflected in the properties recovered by the different methods, the PCA embedding recovers the S-shape, while $t$-SNE ignores the S-shape and recovers the inner structure of the manifold. % Example 2: Often the quality of an embedding strongly depends on the choice of parameters, the interface of \pkg{dimRed} can be used to facilitate searching the parameter space. Isomap has one parameter $k$ which determines the number of neighbors used to construct the $k$-NNG\@. % If this number is too large, then Isomap will resemble an MDS (Figure~\ref{fig:knn} e), if the number is too small, the resulting embedding contains holes (Figure~\ref{fig:knn} c). % The following code finds the optimal value, $k_{\text{max}}$, for $k$ using the $Q_{\text{local}}$ criterion, the results are visualized in Figure~\ref{fig:knn} a: \begin{figure}[htp] \centering <>= if(Sys.getenv("BNET_BUILD_VIGNETTE") != "") { library(dimRed) library(cccd) ## Load data ss <- loadDataSet("3D S Curve", n = 500) ## Parameter space kk <- floor(seq(5, 100, length.out = 40)) ## Embedding over parameter space emb <- lapply(kk, function(x) embed(ss, "Isomap", knn = x)) ## Quality over embeddings qual <- sapply(emb, function(x) quality(x, "Q_local")) ## Find best value for K ind_max <- which.max(qual) k_max <- kk[ind_max] add_label <- function(label){ par(xpd = TRUE) b = par("usr") text(b[1], b[4], label, adj = c(0, 1), cex = 1.5, font = 2) par(xpd = FALSE) } names(qual) <- kk } @ <<"select_k",include=FALSE,fig.width=11,fig.height=5>>= if(Sys.getenv("BNET_BUILD_VIGNETTE") != "") { par(mfrow = c(1, 2), mar = c(5, 4, 0, 0) + 0.1, oma = c(0, 0, 0, 0)) plot(kk, qual, type = "l", xlab = "k", ylab = expression(Q[local]), bty = "n") abline(v = k_max, col = "red") add_label("a") plot(ss, type = "3vars", angle = 15, mar = c(3, 3, 0, 0), box = FALSE, grid = FALSE, pch = 16) add_label("b") } else { plot(1:10) plot(1:10) } @ <<"knngraphs",include=FALSE,fig.width=8,fig.height=3>>= if(Sys.getenv("BNET_BUILD_VIGNETTE") != "") { par(mfrow = c(1, 3), mar = c(5, 4, 0, 0) + 0.1, oma = c(0, 0, 0, 0)) add_knn_graph <- function(ind) { nn1 <- nng(ss@data, k = kk[ind]) el <- get.edgelist(nn1) segments(x0 = emb[[ind]]@data@data[el[, 1], 1], y0 = emb[[ind]]@data@data[el[, 1], 2], x1 = emb[[ind]]@data@data[el[, 2], 1], y1 = emb[[ind]]@data@data[el[, 2], 2], col = "#00000010") } plot(emb[[2]]@data@data, type = "n", bty = "n") add_knn_graph(2) points(emb[[2]]@data@data, col = dimRed:::colorize(ss@meta), pch = 16) add_label("c") plot(emb[[ind_max]]@data@data, type = "n", bty = "n") add_knn_graph(ind_max) points(emb[[ind_max]]@data@data, col = dimRed:::colorize(ss@meta), pch = 16) add_label("d") plot(emb[[length(emb)]]@data@data, type = "n", bty = "n") add_knn_graph(length(emb)) points(emb[[length(emb)]]@data@data, col = dimRed:::colorize(ss@meta), pch = 16) add_label("e") } else { plot(1:10) plot(1:10) plot(1:10) } @ \includegraphics[width=.95\textwidth]{figure/select_k-1.pdf} \includegraphics[width=.95\textwidth]{figure/knngraphs-1.pdf} \caption[estimating $k$ using @Q_\text{local}]{% Using \pkg{dimRed} and the $Q_\text{local}$ indicator to estimate a good value for the parameter $k$ in Isomap. % (a) $Q_\text{local}$ for different values of $k$, the vertical red line indicates the maximum $k_{\text{max}}$. % (b) The original data set, a 2 dimensional manifold bent in an S-shape in 3 dimensional space. % Bottom row: Embeddings and $k$-NNG for different values of $k$. % (c) When $k = 5$, the value for $k$ is too small resulting in holes in the embedding, the manifold itself is still unfolded correctly. % (d) Choose $k = k_\text{max}$, the best representation of the original manifold in two dimensions achievable with Isomap. % (e) $k = 100$, too large, the $k$-NNG does not approximate the manifold any more. % }\label{fig:knn} \end{figure} <>= ## Load data ss <- loadDataSet("3D S Curve", n = 500) ## Parameter space kk <- floor(seq(5, 100, length.out = 40)) ## Embedding over parameter space emb <- lapply(kk, function(x) embed(ss, "Isomap", knn = x)) ## Quality over embeddings qual <- sapply(emb, function(x) quality(x, "Q_local")) ## Find best value for K ind_max <- which.max(qual) k_max <- kk[ind_max] @ Figure~\ref{fig:knn}a shows how the $Q_{\text{local}}$ criterion changes when varying the neighborhood size $k$ for Isomap, the gray lines in Figure~\ref{fig:knn} represent the edges of the $k$-NN Graph. % If the value for $k$ is too low, the inner structure of the manifold will still be recovered, but it will be imperfect (Figure~\ref{fig:knn}c, note that the holes appear in places that are not covered by the edges of the $k$-NN Graph), therefore the $Q_{\text{local}}$ score is lower than optimal. % If $k$ is too large, the error of the embedding is much larger due to short circuiting and we observe a very steep drop in the $Q_{\text{local}}$ score. % The short circuiting can be observed in Figure~\ref{fig:knn}e with the edges that cross the gap between the tips and the center of the S-shape. % % Example 3: It is also very easy to compare across methods and quality scores. % The following code produces a matrix of quality scores and methods, where \code{dimRedMethodList} returns a character vector with all methods. A visualization of the matrix can be found in Figure~\ref{fig:qualityexample}. % \begin{figure}[htp] \centering <<"plot_quality",include=FALSE>>= if(Sys.getenv("BNET_BUILD_VIGNETTE") != "") { embed_methods <- dimRedMethodList() quality_methods <- c("Q_local", "Q_global", "AUC_lnK_R_NX", "cophenetic_correlation") iris_data <- loadDataSet("Iris") quality_results <- matrix( NA, length(embed_methods), length(quality_methods), dimnames = list(embed_methods, quality_methods) ) embedded_data <- list() for (e in embed_methods) { try(embedded_data[[e]] <- embed(iris_data, e)) for (q in quality_methods) try(quality_results[e,q] <- quality(embedded_data[[e]], q)) } quality_results <- quality_results[order(rowMeans(quality_results)), ] palette(c("#1b9e77", "#d95f02", "#7570b3", "#e7298a", "#66a61e")) col_hsv <- rgb2hsv(col2rgb(palette())) ## col_hsv["v", ] <- col_hsv["v", ] * 3 / 1 palette(hsv(col_hsv["h",], col_hsv["s",], col_hsv["v",])) par(mar = c(2, 8, 0, 0) + 0.1) barplot(t(quality_results), beside = TRUE, col = 1:4, legend.text = quality_methods, horiz = TRUE, las = 1, cex.names = 0.85, args.legend = list(x = "topleft", bg = "white", cex = 0.8)) } else { plot(1:10) } @ \includegraphics[width=.5\textwidth]{figure/plot_quality-1.pdf} \caption[Quality comparision]{% A visualization of the \code{quality\_results} matrix. % The methods are ordered by mean quality score. % The reconstruction error was omitted, because a higher value means a worse embedding, while in the present methods a higher score means a better embedding. % Parameters were not tuned for the example, therefore it should not be seen as a general quality assessment of the methods. % }\label{fig:qualityexample} \end{figure} <>= embed_methods <- dimRedMethodList() quality_methods <- c("Q_local", "Q_global", "AUC_lnK_R_NX", "cophenetic_correlation") scurve <- loadDataSet("3D S Curve", n = 2000) quality_results <- matrix( NA, length(embed_methods), length(quality_methods), dimnames = list(embed_methods, quality_methods) ) embedded_data <- list() for (e in embed_methods) { embedded_data[[e]] <- embed(scurve, e) for (q in quality_methods) try(quality_results[e, q] <- quality(embedded_data[[e]], q)) } @ This example showcases the simplicity with which different methods and quality criteria can be combined. % Because of the strong dependencies on parameters it is not advised to apply this kind of analysis without tuning the parameters for each method separately. % There is no automatized way to tune parameters in \pkg{dimRed}. % \section{Conclusion} \label{sec:conc} This paper presents the \pkg{dimRed} and \pkg{coRanking} packages and it provides a brief overview of the methods implemented therein. % The \pkg{dimRed} package is written in the R language, one of the most popular languages for data analysis. The package is freely available from CRAN. % The package is object oriented and completely open source and therefore easily available and extensible. % Although most of the DR methods already had implementations in R, \pkg{dimRed} adds some new methods for dimensionality reduction, and \pkg{coRanking} adds methods for an independent quality control of DR methods to the R ecosystem. % DR is a widely used technique. However, due to the lack of easily usable tools, choosing the right method for DR is complex and depends upon a variety of factors. % The \pkg{dimRed} package aims to facilitate experimentation with different techniques, parameters, and quality measures so that choosing the right method becomes easier. % The \pkg{dimRed} package wants to enable the user to objectively compare methods that rely on very different algorithmic approaches. % It makes the life of the programmer easier, because all methods are aggregated in one place and there is a single interface and standardized classes to access the functionality. % \section{Acknowledgments} \label{sec:ack} We thank Dr.\ G.\ Camps-Valls and an anonymous reviewer for many useful comments. % This study was supported by the European Space Agency (ESA) via the Earth System Data Lab project (\url{http://earthsystemdatacube.org}) and the EU via the H2020 project BACI, grant agreement No 640176. % \bibliographystyle{abbrvnat} \bibliography{bibliography} \end{document} dimRed/vignettes/Makefile0000644000176200001440000000063614262570071015137 0ustar liggesusersall: echo "BNET_BUILD_VIGNETTE: $(BNET_BUILD_VIGNETTE)" echo "_R_CHECK_DEPENDS_ONLY_: " $(_R_CHECK_DEPENDS_ONLY_) if ! [ "$(_R_CHECK_DEPENDS_ONLY_)" = "true" ]; then \ $(R_HOME)/bin/Rscript -e "knitr::knit2pdf('dimensionality-reduction.Rnw')"; \ $(R_HOME)/bin/Rscript -e "tools::compactPDF('dimensionality-reduction.pdf', gs_quality = 'ebook')"; \ rm -rf dimensionality-reduction.tex figure/ auto/; \ fi dimRed/R/0000755000176200001440000000000014262570071011663 5ustar liggesusersdimRed/R/diffmap.R0000644000176200001440000001103614262545115013416 0ustar liggesusers#' Diffusion Maps #' #' An S4 Class implementing Diffusion Maps #' #' Diffusion Maps uses a diffusion probability matrix to robustly #' approximate a manifold. #' #' #' @template dimRedMethodSlots #' #' @template dimRedMethodGeneralUsage #' #' @section Parameters: #' Diffusion Maps can take the following parameters: #' \describe{ #' \item{d}{a function transforming a matrix row wise into a #' distance matrix or \code{dist} object, #' e.g. \code{\link[stats]{dist}}.} #' \item{ndim}{The number of dimensions} #' \item{eps}{The epsilon parameter that determines the #' diffusion weight matrix from a distance matrix \code{d}, #' \eqn{exp(-d^2/eps)}, if set to \code{"auto"} it will #' be set to the median distance to the 0.01*n nearest #' neighbor.} #' \item{t}{Time-scale parameter. The recommended value, 0, #' uses multiscale geometry.} #' \item{delta}{Sparsity cut-off for the symmetric graph Laplacian, #' a higher value results in more sparsity and faster calculation. #' The predefined value is 10^-5.} #' } #' #' @section Implementation: #' Wraps around \code{\link[diffusionMap]{diffuse}}, see there for #' details. It uses the notation of Richards et al. (2009) which is #' slightly different from the one in the original paper (Coifman and #' Lafon, 2006) and there is no \eqn{\alpha} parameter. #' There is also an out-of-sample extension, see examples. #' #' #' @references #' Richards, J.W., Freeman, P.E., Lee, A.B., Schafer, #' C.M., 2009. Exploiting Low-Dimensional Structure in #' Astronomical Spectra. ApJ 691, #' 32. doi:10.1088/0004-637X/691/1/32 #' #' Coifman, R.R., Lafon, S., 2006. Diffusion maps. Applied and #' Computational Harmonic Analysis 21, #' 5-30. doi:10.1016/j.acha.2006.04.006 #' #' @examples #' if(requireNamespace("diffusionMap", quietly = TRUE)) { #' dat <- loadDataSet("3D S Curve", n = 300) #' emb <- embed(dat, "DiffusionMaps") #' #' plot(emb, type = "2vars") #' #' # predicting is possible: #' samp <- sample(floor(nrow(dat) / 10)) #' emb2 <- embed(dat[samp]) #' emb3 <- predict(emb2, dat[-samp]) #' #' plot(emb2, type = "2vars") #' points(getData(emb3)) #' } #' @include dimRedResult-class.R #' @include dimRedMethod-class.R #' @family dimensionality reduction methods #' @export DiffusionMaps #' @exportClass DiffusionMaps DiffusionMaps <- setClass( "DiffusionMaps", contains = "dimRedMethod", prototype = list( stdpars = list(d = stats::dist, ndim = 2, eps = "auto", t = 0, delta = 1e-5), fun = function (data, pars, keep.org.data = TRUE) { chckpkg("diffusionMap") meta <- data@meta orgdata <- if (keep.org.data) data@data else NULL indata <- data@data distmat <- pars$d(indata) if (pars$eps == "auto") pars$eps <- diffusionMap::epsilonCompute(distmat) diffres <- diffusionMap::diffuse( D = distmat, t = pars$t, eps.val = pars$eps, neigen = pars$ndim, maxdim = pars$ndim, delta = pars$delta ) outdata <- as.matrix(diffres$X) appl <- function(x) { appl.meta <- if (inherits(x, "dimRedData")) x@meta else data.frame() proj <- if (inherits(x, "dimRedData")) x@data else x if (ncol(proj) != ncol(data@data)) stop("x must have the same number of dimensions ", "as the original data") dd <- sqrt(pdist2(proj, indata)) appl.res <- diffusionMap::nystrom(diffres, dd, sigma = diffres$epsilon) dimnames(appl.res) <- list( rownames(x), paste0("diffMap", seq_len(ncol(outdata))) ) new("dimRedData", data = appl.res, meta = appl.meta) } colnames(outdata) <- paste0("diffMap", seq_len(ncol(outdata))) return(new( "dimRedResult", data = new("dimRedData", data = outdata, meta = meta), org.data = orgdata, apply = appl, has.apply = TRUE, has.org.data = keep.org.data, method = "diffmap", pars = pars )) }, requires = c("diffusionMap")) ) dimRed/R/fastica.R0000644000176200001440000000702314257244146013427 0ustar liggesusers#' Independent Component Analysis #' #' An S4 Class implementing the FastICA algorithm for Indepentend #' Component Analysis. #' #' ICA is used for blind signal separation of different sources. It is #' a linear Projection. #' #' @template dimRedMethodSlots #' #' @template dimRedMethodGeneralUsage #' #' @section Parameters: #' FastICA can take the following parameters: #' \describe{ #' \item{ndim}{The number of output dimensions. Defaults to \code{2}} #' } #' #' @section Implementation: #' Wraps around \code{\link[fastICA]{fastICA}}. FastICA uses a very #' fast approximation for negentropy to estimate statistical #' independences between signals. Because it is a simple #' rotation/projection, forward and backward functions can be given. #' #' @references #' #' Hyvarinen, A., 1999. Fast and robust fixed-point algorithms for independent #' component analysis. IEEE Transactions on Neural Networks 10, 626-634. #' https://doi.org/10.1109/72.761722 #' #' @examples #' if(requireNamespace("fastICA", quietly = TRUE)) { #' #' dat <- loadDataSet("3D S Curve") #' emb <- embed(dat, "FastICA", ndim = 2) #' plot(getData(getDimRedData(emb))) #' #' } #' @include dimRedResult-class.R #' @include dimRedMethod-class.R #' @family dimensionality reduction methods #' @export FastICA #' @exportClass FastICA FastICA <- setClass( "FastICA", contains = "dimRedMethod", prototype = list( stdpars = list(ndim = 2), fun = function (data, pars, keep.org.data = TRUE) { chckpkg("fastICA") meta <- data@meta orgdata <- if (keep.org.data) data@data else NULL orgdata.colmeans <- colMeans(orgdata) indata <- data@data res <- fastICA::fastICA(indata, n.comp = pars$ndim, method = "C") outdata <- res$S colnames(outdata) <- paste0("ICA", 1:ncol(outdata)) appl <- function(x){ appl.meta <- if (inherits(x, "dimRedData")) x@meta else matrix(numeric(0), 0, 0) proj <- if (inherits(x, "dimRedData")) x@data else x out <- scale(proj, center = orgdata.colmeans, scale = FALSE) %*% res$K %*% res$W colnames(out) <- paste0("ICA", 1:ncol(out)) return(new("dimRedData", data = out, meta = appl.meta)) } inv <- function(x){ appl.meta <- if (inherits(x, "dimRedData")) x@meta else matrix(numeric(0), 0, 0) proj <- if (inherits(x, "dimRedData")) x@data else x out <- scale(proj %*% res$A[1:ncol(proj), ], center = -orgdata.colmeans, scale = FALSE) reproj <- new("dimRedData", data = out, meta = appl.meta) return(reproj) } return(new( "dimRedResult", data = new("dimRedData", data = outdata, meta = meta), org.data = orgdata, has.org.data = keep.org.data, apply = appl, inverse = inv, has.apply = TRUE, has.inverse = TRUE, method = "FastICA", pars = pars )) }, requires = c("fastICA")) ) dimRed/R/nmds.R0000644000176200001440000000363614262545165012765 0ustar liggesusers#' Non-Metric Dimensional Scaling #' #' An S4 Class implementing Non-Metric Dimensional Scaling. #' #' A non-linear extension of MDS using monotonic regression #' #' @template dimRedMethodSlots #' #' @template dimRedMethodGeneralUsage #' #' @section Parameters: #' nMDS can take the following parameters: #' \describe{ #' \item{d}{A distance function.} #' \item{ndim}{The number of embedding dimensions.} #' } #' #' @section Implementation: #' Wraps around the #' \code{\link[vegan]{monoMDS}}. For parameters that are not #' available here, the standard configuration is used. #' #' @references #' #' Kruskal, J.B., 1964. Nonmetric multidimensional scaling: A numerical method. #' Psychometrika 29, 115-129. https://doi.org/10.1007/BF02289694 #' #' @examples #' if(requireNamespace("vegan", quietly = TRUE)) { #' #' dat <- loadDataSet("3D S Curve", n = 300) #' emb <- embed(dat, "nMDS") #' plot(emb, type = "2vars") #' #' } #' @include dimRedResult-class.R #' @include dimRedMethod-class.R #' @family dimensionality reduction methods #' @export nMDS #' @exportClass nMDS nMDS <- setClass( "nMDS", contains = "dimRedMethod", prototype = list( stdpars = list(d = stats::dist, ndim = 2), fun = function (data, pars, keep.org.data = TRUE) { chckpkg("vegan") meta <- data@meta orgdata <- if (keep.org.data) data@data else NULL indata <- data@data outdata <- vegan::monoMDS(pars$d(indata), k = pars$ndim)$points colnames(outdata) <- paste0("NMDS", 1:ncol(outdata)) return(new( "dimRedResult", data = new("dimRedData", data = outdata, meta = meta), org.data = orgdata, has.org.data = keep.org.data, method = "nmds", pars = pars )) }, requires = c("vegan")) ) dimRed/R/tsne.R0000644000176200001440000000540014252035676012764 0ustar liggesusers#' t-Distributed Stochastic Neighborhood Embedding #' #' An S4 Class for t-SNE. #' #' t-SNE is a method that uses Kullback-Leibler divergence between the #' distance matrices in high and low-dimensional space to embed the #' data. The method is very well suited to visualize complex #' structures in low dimensions. #' #' @template dimRedMethodSlots #' #' @template dimRedMethodGeneralUsage #' #' @section Parameters: #' t-SNE can take the following parameters: #' \describe{ #' \item{d}{A distance function, defaults to euclidean distances} #' \item{perplexity}{The perplexity parameter, roughly equivalent to neighborhood size.} #' \item{theta}{Approximation for the nearest neighbour search, large values are more inaccurate.} #' \item{ndim}{The number of embedding dimensions.} #' } #' #' @section Implementation: #' #' Wraps around \code{\link[Rtsne]{Rtsne}}, which is very well #' documented. Setting \code{theta = 0} does a normal t-SNE, larger #' values for \code{theta < 1} use the Barnes-Hut algorithm which #' scales much nicer with data size. Larger values for perplexity take #' larger neighborhoods into account. #' #' @references #' Maaten, L. van der, 2014. Accelerating t-SNE using Tree-Based #' Algorithms. Journal of Machine Learning Research 15, 3221-3245. #' #' van der Maaten, L., Hinton, G., 2008. Visualizing Data using #' t-SNE. J. Mach. Learn. Res. 9, 2579-2605. #' #' @examples #' \dontrun{ #' dat <- loadDataSet("3D S Curve", n = 300) #' emb <- embed(dat, "tSNE", perplexity = 80) #' plot(emb, type = "2vars") #' } #' @include dimRedResult-class.R #' @include dimRedMethod-class.R #' @family dimensionality reduction methods #' @export tSNE #' @exportClass tSNE tSNE <- setClass( "tSNE", contains = "dimRedMethod", prototype = list( stdpars = list(d = stats::dist, perplexity = 30, theta = 0.5, ndim = 2), fun = function (data, pars, keep.org.data = TRUE) { chckpkg("Rtsne") meta <- data@meta orgdata <- if (keep.org.data) data@data else NULL indata <- data@data outdata <- Rtsne::Rtsne(pars$d(indata), perplexity = pars$perplexity, theta = pars$theta, dims = pars$ndim)$Y colnames(outdata) <- paste0("tSNE", 1:ncol(outdata)) return(new( "dimRedResult", data = new("dimRedData", data = outdata, meta = meta), org.data = orgdata, has.org.data = keep.org.data, method = "tsne", pars = pars )) }, requires = c("Rtsne")) ) dimRed/R/kpca.R0000644000176200001440000001065514262545461012740 0ustar liggesusers#' Kernel PCA #' #' An S4 Class implementing Kernel PCA #' #' Kernel PCA is a nonlinear extension of PCA using kernel methods. #' #' #' @template dimRedMethodSlots #' #' @template dimRedMethodGeneralUsage #' #' @section Parameters: #' Kernel PCA can take the following parameters: #' \describe{ #' \item{ndim}{the number of output dimensions, defaults to 2} #' \item{kernel}{The kernel function, either as a function or a #' character vector with the name of the kernel. Defaults to #' \code{"rbfdot"}} #' \item{kpar}{A list with the parameters for the kernel function, #' defaults to \code{list(sigma = 0.1)}} #' } #' #' The most comprehensive collection of kernel functions can be found in #' \code{\link[kernlab]{kpca}}. In case the function does not take any #' parameters \code{kpar} has to be an empty list. #' #' @section Implementation: #' #' Wraps around \code{\link[kernlab]{kpca}}, but provides additionally #' forward and backward projections. #' #' @references #' #' Sch\"olkopf, B., Smola, A., M\"uller, K.-R., 1998. Nonlinear Component Analysis #' as a Kernel Eigenvalue Problem. Neural Computation 10, 1299-1319. #' https://doi.org/10.1162/089976698300017467 #' #' @examples #' \dontrun{ #' if(requireNamespace("kernlab", quietly = TRUE)) { #' #' dat <- loadDataSet("3D S Curve") #' emb <- embed(dat, "kPCA") #' plot(emb, type = "2vars") #' } #' #' } #' @include dimRedResult-class.R #' @include dimRedMethod-class.R #' @family dimensionality reduction methods #' @export kPCA #' @exportClass kPCA kPCA <- setClass( "kPCA", contains = "dimRedMethod", prototype = list( stdpars = list(kernel = "rbfdot", kpar = list(sigma = 0.1), ndim = 2), fun = function (data, pars, keep.org.data = TRUE) { chckpkg("kernlab") if (is.null(pars$ndim)) pars$ndim <- 2 meta <- data@meta orgdata <- if (keep.org.data) data@data else NULL indata <- data@data message(Sys.time(), ": Calculating kernel PCA") res <- do.call(kernlab::kpca, c(list(x = indata), pars)) kernel <- get_kernel_fun(pars$kernel, pars$kpar) message(Sys.time(), ": Trying to calculate reverse") K_rev <- kernlab::kernelMatrix(kernel, res@rotated) diag(K_rev) <- 0.1 + diag(K_rev) dual_coef <- try(solve(K_rev, indata), silent = TRUE) appl <- function (x) { appl.meta <- if (inherits(x, "dimRedData")) x@meta else data.frame() proj <- if (inherits(x, "dimRedData")) x@data else x proj <- kernlab::predict(res, proj)[, 1:pars$ndim, drop = FALSE] colnames(proj) <- paste0("kPCA", 1:ncol(proj)) new("dimRedData", data = proj, meta = appl.meta) } inv <- if (inherits(dual_coef, "try-error")) { message("No inverse function.") function(x) NA } else { function (x) { appl.meta <- if (inherits(x, "dimRedData")) x@meta else data.frame() proj <- if (inherits(x, "dimRedData")) x@data else x resrot <- res@rotated[, 1:ncol(proj)] rot <- kernlab::kernelMatrix(kernel, proj, resrot) proj <- rot %*% dual_coef new("dimRedData", data = proj, meta = appl.meta) } } outdata <- res@rotated[, 1:pars$ndim, drop = FALSE] colnames(outdata) <- paste0("kPCA", 1:ncol(outdata)) message(Sys.time(), ": DONE") return( new( "dimRedResult", data = new("dimRedData", data = outdata, meta = meta), org.data = orgdata, apply = appl, inverse = inv, has.org.data = keep.org.data, has.apply = TRUE, has.inverse = TRUE, method = "kpca", pars = pars ) ) }, requires = c("kernlab")) ) ## get the kernel function out of the kernlab namespace: get_kernel_fun <- function (kernel, pars) { if (!is(kernel, "kernel")) { if (is(kernel, "function")) { kernel <- deparse(substitute(kernel)) } else { kernel <- get(kernel, asNamespace("kernlab")) } kernel <- do.call(kernel, pars) } return(kernel) } dimRed/R/autoencoder.R0000644000176200001440000003643414252034635014330 0ustar liggesusers#' AutoEncoder #' #' An S4 Class implementing an Autoencoder #' #' Autoencoders are neural networks that try to reproduce their input. Consider #' this method unstable, as the internals may still be changed. #' #' @template dimRedMethodSlots #' #' @template dimRedMethodGeneralUsage #' #' @section Parameters: #' Autoencoder can take the following parameters: #' \describe{ #' \item{ndim}{The number of dimensions for reduction.} #' \item{n_hidden}{The number of neurons in the hidden #' layers, the length specifies the number of layers, #' the length must be impair, the middle number must #' be the same as ndim.} #' \item{activation}{The activation functions for the layers, #' one of "tanh", "sigmoid", "relu", "elu", everything #' else will silently be ignored and there will be no #' activation function for the layer.} #' \item{weight_decay}{the coefficient for weight decay, #' set to 0 if no weight decay desired.} #' \item{learning_rate}{The learning rate for gradient descend} #' \item{graph}{Optional: A list of bits and pieces that define the #' autoencoder in tensorflow, see details.} #' \item{keras_graph}{Optional: A list of keras layers that define #' the encoder and decoder, specifying this, will ignore all #' other topology related variables, see details.} #' \item{batchsize}{If NA, all data will be used for training, #' else only a random subset of size batchsize will be used} #' \item{n_steps}{the number of training steps.} #' } #' #' @section Details: #' There are several ways to specify an autoencoder, the simplest is to pass the #' number of neurons per layer in \code{n_hidden}, this must be a vector of #' integers of impair length and it must be symmetric and the middle number must #' be equal to \code{ndim}, For every layer an activation function can be #' specified with \code{activation}. #' #' For regularization weight decay can be specified by setting #' \code{weight_decay} > 0. #' #' Currently only a gradient descent optimizer is used, the learning rate can be #' specified by setting \code{learning_rate}. #' The learner can operate on batches if \code{batchsize} is not \code{NA}. #' The number of steps the learner uses is specified using \code{n_steps}. #' #' @section Further training a model: #' If the model did not converge in the first training phase or training with #' different data is desired, the \code{\link{dimRedResult}} object may be #' passed as \code{autoencoder} parameter; In this case all topology related #' parameters will be ignored. #' #' @section Using Keras layers: #' The encoder and decoder part can be specified using a list of \pkg{keras} #' layers. This requires a list with two entries, \code{encoder} should contain #' a LIST of keras layers WITHOUT the \code{\link[keras]{layer_input}} #' that will be concatenated in order to form the encoder part. #' \code{decoder} should be #' defined accordingly, the output of \code{decoder} must have the same number #' of dimensions as the input data. #' #' @section Using Tensorflow: #' The model can be entirely defined in \pkg{tensorflow}, it must contain a #' list with the following entries: #' \describe{ #' \item{encoder}{A tensor that defines the encoder.} #' \item{decoder}{A tensor that defines the decoder.} #' \item{network}{A tensor that defines the reconstruction (encoder + decoder).} #' \item{loss}{A tensor that calculates the loss (network + loss function).} #' \item{in_data}{A \code{placeholder} that points to the data input of #' the network AND the encoder.} #' \item{in_decoder}{A \code{placeholder} that points to the input of #' the decoder.} #' \item{session}{A \pkg{tensorflow} \code{Session} object that holds #' the values of the tensors.} #' } #' #' @section Implementation: #' Uses \pkg{tensorflow} as a backend, for details an #' problems relating tensorflow, see \url{https://tensorflow.rstudio.com}. #' #' @examples #' \dontrun{ #' dat <- loadDataSet("3D S Curve") #' #' emb <- embed(dat, "AutoEncoder") #' #' # predicting is possible: #' samp <- sample(floor(nrow(dat) / 10)) #' emb2 <- embed(dat[samp]) #' emb3 <- predict(emb2, dat[-samp]) #' #' plot(emb, type = "2vars") #' plot(emb2, type = "2vars") #' points(getData(emb3)) #' } #' #' @include dimRedResult-class.R #' @include dimRedMethod-class.R #' @family dimensionality reduction methods #' @export AutoEncoder #' @exportClass AutoEncoder AutoEncoder <- setClass( "AutoEncoder", contains = "dimRedMethod", prototype = list( stdpars = list(ndim = 2, n_hidden = c(10, 2, 10), activation = c("tanh", "lin", "tanh"), weight_decay = 0.001, learning_rate = 0.15, graph = NULL, keras_graph = NULL, ## is.na() of an S4 class gives a warning autoencoder = NULL, batchsize = NA, n_steps = 500), fun = function (data, pars, keep.org.data = TRUE) { chckpkg("tensorflow") tensorflow::tf$compat$v1$disable_v2_behavior() meta <- data@meta orgdata <- if (keep.org.data) data@data else NULL indata <- data@data graph <- if (!is.null(pars$graph)) { message("using predefined graph, ", "ignoring other parameters that define topology, ", "be sure to set ndim to the correct value ", "else you might run into trouble.") pars$graph } else if (!is.null(pars$autoencoder)) { message("using predefined autoencoder object, ", " ignoring other parameters that define topology.") if (!(inherits(pars$autoencoder, "dimRedResult") && pars$autoencoder@method == "AutoEncoder")) stop("autoencoder must be NULL, ", "or of type dimRedResult by an AutoEncoder object.") ## setting topology related parameters from autoencoder pars$ndim <- pars$autoencoder@pars$ndim pars$n_hidden <- pars$autoencoder@pars$n_hidden pars$activation <- pars$autoencoder@pars$activation pars$autoencoder@pars$graph } else if (!is.null(pars$keras_graph)) { message("using predefined keras graph, ", "ignoring parameters that define topology") tmp <- graph_keras(encoder = pars$keras_graph$encoder, decoder = pars$keras_graph$decoder, n_in = ncol(indata)) pars$ndim <- tmp$encoder$shape$dims[[2]]$value tmp } else { with(pars, { graph_params( d_in = ncol(indata), n_hidden = n_hidden, activation = activation, weight_decay = weight_decay, learning_rate = learning_rate, n_steps = n_steps, ndim = ndim ) }) } if (!"encoder" %in% names(graph)) stop("no encoder in graph") if (!"decoder" %in% names(graph)) stop("no decoder in graph") if (!"network" %in% names(graph)) stop("no network in graph") if (!"loss" %in% names(graph)) stop("no loss in graph") if (!"in_decoder" %in% names(graph)) stop("no in_decoder in graph") if (!"in_data" %in% names(graph)) stop("no in_data in graph") if (!"session" %in% names(graph)) stop("no session in graph") ## TODO: I am not sure if there is a way to do this directly on the list ## objects graph_data_input <- graph$in_data graph_decoder_input <- graph$in_dec sess <- graph$session optimizer <- tensorflow::tf$compat$v1$train$GradientDescentOptimizer(pars$learning_rate) train <- optimizer$minimize(graph$loss) ## TODO: do proper batching and hold out for (step in 1:pars$n_steps) { sess$run(train, feed_dict = tensorflow::dict( graph_data_input = if (is.na(pars$batchsize)) { indata } else { indata[ sample(seq_len(nrow(indata)), pars$batchsize), ] } ) ) } outdata <- sess$run(graph$encoder, feed_dict = tensorflow::dict(graph_data_input = indata)) appl <- function(x) { appl.meta <- if (inherits(x, "dimRedData")) x@meta else data.frame() proj <- if (inherits(x, "dimRedData")) x@data else x if (ncol(proj) != ncol(data@data)) stop("x must have the same number of dimensions ", "as the original data") res <- sess$run(graph$encoder, feed_dict = tensorflow::dict(graph_data_input = proj)) colnames(res) <- paste0("AE", seq_len(ncol(res))) new("dimRedData", data = res, meta = appl.meta) } inv <- function(x) { appl.meta <- if (inherits(x, "dimRedData")) x@meta else data.frame() proj <- if (inherits(x, "dimRedData")) x@data else x if (ncol(proj) != pars$ndim) stop("x must have the same number of dimensions ", "as ndim data") res <- sess$run( graph$decoder, feed_dict = tensorflow::dict( graph_decoder_input = proj )) colnames(res) <- colnames(indata) new("dimRedData", data = res, meta = appl.meta) } ## TODO: this is a hack and there should be an "official" way to save ## extra data in a dimRedResult object pars$graph <- graph colnames(outdata) <- paste0("AE", seq_len(ncol(outdata))) return(new( "dimRedResult", data = new("dimRedData", data = outdata, meta = meta), org.data = orgdata, apply = appl, inverse = inv, has.apply = TRUE, has.inverse = TRUE, has.org.data = keep.org.data, method = "AutoEncoder", pars = pars )) }, requires = c("tensorflow", "keras")) ) get_activation_function <- function(x) { switch( x, tanh = tensorflow::tf$compat$v1$tanh, sigmoid = tensorflow::tf$compat$v1$sigmoid, relu = tensorflow::tf$compat$v1$nn$relu, elu = tensorflow::tf$compat$v1$elu, I ) } ## no idea why these and variants do not work: ## chain_list <- function(x1, x2) Reduce(`%>%`, x2, init = x1) ## chain_list <- function(x) Reduce(`%>%`, x) chain_list <- function (x1, x2 = NULL) { if(is.null(x2)) { stopifnot(is.list(x1)) result <- x1[[1]] if(length(x1) > 1) for (i in 2:length(x1)) { result <- result %>% (x1[[i]]) } } else { stopifnot(is.list(x2)) result <- x1 for (i in 1:length(x2)) { result <- result %>% (x2[[i]]) } } return(result) } graph_keras <- function(encoder, decoder, n_in) { chckpkg("keras") chckpkg("tensorflow") inenc <- keras::layer_input(shape = n_in) enc <- inenc %>% chain_list(encoder) ndim <- enc$shape$dims[[2]]$value indec <- keras::layer_input(shape = ndim) dec <- indec %>% chain_list(decoder) encdec <- inenc %>% chain_list(encoder) %>% chain_list(decoder) ## TODO: check if this uses weight decay, probably not: loss <- tensorflow::tf$compat$v1$reduce_mean((encdec - inenc) ^ 2) sess <- tensorflow::tf$compat$v1$keras$backend$get_session() return(list( encoder = enc, decoder = dec, network = encdec, loss = loss, in_data = inenc, in_decoder = indec, session = sess )) } graph_params <- function ( d_in, n_hidden, activation, weight_decay, learning_rate, n_steps, ndim ) { if (length(n_hidden) %% 2 == 0) stop("the number of layers must be impair") if (ndim != n_hidden[ceiling(length(n_hidden) / 2)]) stop("the middle of n_hidden must be equal to ndim") if (length(n_hidden) != length(activation)) stop("declare an activation function for each layer:", "\nn_hidden: ", paste(n_hidden, collapse = " "), "\nactivation functions: ", paste(activation, collapse = " ")) if (weight_decay < 0) stop("weight decay must be > 0") if (learning_rate <= 0) stop("learning rate must be > 0") if (n_steps <= 0) stop("n_steps must be > 0") input <- tensorflow::tf$compat$v1$placeholder( "float", shape = tensorflow::shape(NULL, d_in), name = "input" ) indec <- tensorflow::tf$compat$v1$placeholder( "float", shape = tensorflow::shape(NULL, ndim), name = "nlpca" ) w <- lapply(seq_len(length(n_hidden) + 1), function(x) { n1 <- if (x == 1) d_in else n_hidden[x - 1] n2 <- if (x > length(n_hidden)) d_in else n_hidden[x] tensorflow::tf$compat$v1$Variable(tensorflow::tf$compat$v1$random_uniform(tensorflow::shape(n1, n2), 1.0, -1.0), name = paste0("w_", x)) }) b <- lapply(seq_len(length(n_hidden) + 1), function (x) { n <- if (x > length(n_hidden)) d_in else n_hidden[x] tensorflow::tf$compat$v1$Variable(tensorflow::tf$compat$v1$zeros(tensorflow::shape(n)), name = paste0("b_", x)) }) enc <- input for (i in 1:ceiling(length(n_hidden) / 2)) { sigma <- get_activation_function(activation[i]) enc <- sigma(tensorflow::tf$compat$v1$matmul(enc, w[[i]]) + b[[i]]) } dec <- indec for (i in (ceiling(length(n_hidden) / 2) + 1):(length(n_hidden) + 1)) { sigma <- get_activation_function(activation[i]) dec <- sigma(tensorflow::tf$compat$v1$matmul(dec, w[[i]]) + b[[i]]) } encdec <- enc for (i in (ceiling(length(n_hidden) / 2) + 1):(length(n_hidden) + 1)) { sigma <- get_activation_function(activation[i]) encdec <- sigma(tensorflow::tf$compat$v1$matmul(encdec, w[[i]]) + b[[i]]) } loss <- Reduce(`+`, lapply(w, function (x) tensorflow::tf$compat$v1$reduce_sum(tensorflow::tf$compat$v1$pow(x, 2))), 0) loss <- Reduce(`+`, lapply(b, function (x) tensorflow::tf$compat$v1$reduce_sum(tensorflow::tf$compat$v1$pow(x, 2))), loss) loss <- tensorflow::tf$compat$v1$reduce_mean((encdec - input) ^ 2) + weight_decay * loss sess <- tensorflow::tf$compat$v1$Session() ## This closes sess if it is garbage collected. reg.finalizer(sess, function(x) x$close()) sess$run(tensorflow::tf$compat$v1$global_variables_initializer()) return(list( encoder = enc, decoder = dec, network = encdec, loss = loss, in_data = input, in_decoder = indec, session = sess )) } dimRed/R/isomap.R0000644000176200001440000002046414262545527013314 0ustar liggesusers#' Isomap embedding #' #' An S4 Class implementing the Isomap Algorithm #' #' The Isomap algorithm approximates a manifold using geodesic #' distances on a k nearest neighbor graph. Then classical scaling is #' performed on the resulting distance matrix. #' #' @template dimRedMethodSlots #' #' @template dimRedMethodGeneralUsage #' #' @section Parameters: #' Isomap can take the following parameters: #' \describe{ #' \item{knn}{The number of nearest neighbors in the graph. Defaults to 50.} #' \item{ndim}{The number of embedding dimensions, defaults to 2.} #' \item{get_geod}{Should the geodesic distance matrix be kept, #' if \code{TRUE}, access it as \code{getOtherData(x)$geod}} #' } #' #' @section Implementation: #' #' The dimRed package uses its own implementation of Isomap which also #' comes with an out of sample extension (known as landmark #' Isomap). The default Isomap algorithm scales computationally not #' very well, the implementation here uses \code{\link[RANN]{nn2}} for #' a faster search of the nearest neighbors. If data are too large it #' may be useful to fit a subsample of the data and use the #' out-of-sample extension for the other points. #' #' @references #' Tenenbaum, J.B., Silva, V. de, Langford, J.C., 2000. A Global Geometric #' Framework for Nonlinear Dimensionality Reduction. Science 290, 2319-2323. #' https://doi.org/10.1126/science.290.5500.2319 #' #' @examples #' if(requireNamespace(c("RSpectra", "igraph", "RANN"), quietly = TRUE)) { #' #' dat <- loadDataSet("3D S Curve", n = 500) #' emb <- embed(dat, "Isomap", knn = 10) #' plot(emb) #' #' ## or simpler, use embed(): #' samp <- sample(nrow(dat), size = 200) #' emb2 <- embed(dat[samp], "Isomap", .mute = NULL, knn = 10) #' emb3 <- predict(emb2, dat[-samp]) #' #' plot(emb2, type = "2vars") #' plot(emb3, type = "2vars") #' #' } #' @include dimRedResult-class.R #' @include dimRedMethod-class.R #' @family dimensionality reduction methods #' @export Isomap #' @exportClass Isomap Isomap <- setClass( "Isomap", contains = "dimRedMethod", prototype = list( stdpars = list(knn = 50, ndim = 2, get_geod = FALSE), fun = function (data, pars, keep.org.data = TRUE) { chckpkg("RSpectra") chckpkg("igraph") chckpkg("RANN") message(Sys.time(), ": Isomap START") meta <- data@meta orgdata <- if (keep.org.data) data@data else NULL indata <- data@data if (is.null(pars$eps)) pars$eps <- 0 if (is.null(pars$get_geod)) pars$get_geod <- FALSE ## geodesic distances message(Sys.time(), ": constructing knn graph") knng <- makeKNNgraph(x = indata, k = pars$knn, eps = pars$eps) message(Sys.time(), ": calculating geodesic distances") geodist <- igraph::distances(knng, algorithm = "dijkstra") message(Sys.time(), ": Classical Scaling") ## TODO: add regularization k <- geodist ^ 2 k <- .Call(stats:::C_DoubleCentre, k) k <- - k / 2 ## TODO: explicit symmetrizing ## TODO: return eigenvectors? e <- RSpectra::eigs_sym(k, pars$ndim, which = "LA", opts = list(retvec = TRUE)) e_values <- e$values e_vectors <- e$vectors neig <- sum(e_values > 0) if (neig < pars$ndim) { warning("Isomap: eigenvalues < 0, returning less dimensions!") e_values <- e_values[seq_len(neig)] e_vectors <- e_vectors[, seq_len(neig), drop = FALSE] } e_vectors <- e_vectors * rep(sqrt(e_values), each = nrow(e_vectors)) colnames(e_vectors) <- paste("iso", seq_len(neig)) appl <- function (x) { message(Sys.time(), ": L-Isomap embed START") appl.meta <- if (inherits(x, "dimRedData")) x@meta else data.frame() indata <- if (inherits(x, "dimRedData")) x@data else x if (ncol(indata) != ncol(data@data)) stop("x must have the same number of dimensions as the original data") nindata <- nrow(indata) norg <- nrow(orgdata) message(Sys.time(), ": constructing knn graph") lknng <- makeKNNgraph(rbind(indata, orgdata), k = pars$knn, eps = pars$eps) message(Sys.time(), ": calculating geodesic distances") lgeodist <- igraph::distances(lknng, seq_len(nindata), nindata + seq_len(norg)) message(Sys.time(), ": embedding") dammu <- sweep(lgeodist ^ 2, 2, colMeans(geodist ^ 2), "-") Lsharp <- sweep(e_vectors, 2, e_values, "/") out <- -0.5 * (dammu %*% Lsharp) message(Sys.time(), ": DONE") return(new("dimRedData", data = out, meta = appl.meta)) } return(new( "dimRedResult", data = new("dimRedData", data = e_vectors, meta = meta), org.data = orgdata, has.org.data = keep.org.data, apply = appl, has.apply = TRUE, method = "Isomap", pars = pars, other.data = if (pars$get_geod) list(geod = as.dist(geodist)) else list() )) }, requires = c("RSpectra", "igraph", "RANN") ) ) ## input data(matrix or data frame) return knn graph implements ## "smart" choices on RANN::nn2 parameters we ignore radius search ## TODO: find out a good limit to switch from kd to bd trees COMMENT: ## bd trees are buggy, they dont work if there are duplicated data ## points and checking would neutralize the performance gain, so bd ## trees are not really usable. makeKNNgraph <- function (x, k, eps = 0, diag = FALSE){ ## requireNamespace("RANN") ## requireNamespace("igraph") ## consts INF_VAL <- 1.340781e+15 NA_IDX <- 0 BDKD_LIM <- 1000000 #todo: figure out a good value here ## select parameters M <- nrow(x) treetype <- "kd" # if (M < BDKD_LIM) "kd" else "bd" # see: # https://github.com/jefferis/RANN/issues/19 searchtype <- if (eps == 0) "standard" else "priority" ## RANN::nn2 returns the points in data with respect to query ## e.g. the rows in the output are the points in query and the ## columns the points in data. nn2res <- RANN::nn2(data = x, query = x, k = k + 1, treetype = treetype, searchtype = searchtype, eps = eps) ## create graph: the first ny nodes will be y, the last nx nodes ## will be x, if x != y ## it is not really pretty to create a ## directed graph first and then make it undirected. g <- igraph::make_empty_graph(M, directed = TRUE) g[from = if (diag) rep(seq_len(M), times = k + 1) else rep(seq_len(M), times = k), to = if (diag) as.vector(nn2res$nn.idx) else as.vector(nn2res$nn.idx[, -1]), attr = "weight"] <- if (diag) as.vector(nn2res$nn.dists) else as.vector(nn2res$nn.dists[, -1]) return(igraph::as.undirected(g, mode = "collapse", edge.attr.comb = "first")) } ## the original isomap method I'll keep it here for completeness: ## isomap <- new("dimRedMethod", ## stdpars = list(knn = 50, ## d = dist, ## ndim = 2) ## fun = function (data, pars, ## keep.org.data = TRUE) { ## chckpkg("vegan") ## meta <- data@meta ## orgdata <- if (keep.org.data) data@data else NULL ## indata <- data@data ## outdata <- vegan::isomap(pars$d(indata), ## ndim = pars$ndim, ## k = pars$knn)$points ## colnames(outdata) <- paste0("Iso", 1:ncol(outdata)) ## return(new( ## "dimRedResult", ## data = new("dimRedData", ## data = outdata, ## meta = meta), ## org.data = orgdata, ## has.org.data = keep.org.data, ## method = "isomap", ## pars = pars ## )) ## }) dimRed/R/umap.R0000644000176200001440000001071414252035756012760 0ustar liggesusers#' Umap embedding #' #' An S4 Class implementing the UMAP algorithm #' #' Uniform Manifold Approximation is a gradient descend based algorithm that #' gives results similar to t-SNE, but scales better with the number of points. #' #' @template dimRedMethodSlots #' #' @template dimRedMethodGeneralUsage #' #' @section Parameters: #' #' UMAP can take the follwing parameters: #' \describe{ #' \item{ndim}{The number of embedding dimensions.} #' \item{knn}{The number of neighbors to be used.} #' \item{d}{The distance metric to use.} #' \item{method}{\code{"naive"} for an R implementation, \code{"python"} #' for the reference implementation.} #' } #' #' Other method parameters can also be passed, see #' \code{\link[umap]{umap.defaults}} for details. The ones above have been #' standardized for the use with \code{dimRed} and will get automatically #' translated for \code{\link[umap]{umap}}. #' #' @section Implementation: #' #' The dimRed package wraps the \code{\link[umap]{umap}} packages which provides #' an implementation in pure R and also a wrapper around the original python #' package \code{umap-learn} (https://github.com/lmcinnes/umap/). This requires #' \code{umap-learn} version 0.4 installed, at the time of writing, there is #' already \code{umap-learn} 0.5 but it is not supported by the R package #' \code{\link[umap]{umap}}. #' #' The \code{"naive"} implementation is a pure R implementation and considered #' experimental at the point of writing this, it is also much slower than the #' python implementation. #' #' The \code{"python"} implementation is the reference implementation used by #' McInees et. al. (2018). It requires the \code{\link[reticulate]{reticulate}} #' package for the interaction with python and the python package #' \code{umap-learn} installed (use \code{pip install umap-learn}). #' #' @references #' #' McInnes, Leland, and John Healy. #' "UMAP: Uniform Manifold Approximation and Projection for Dimension Reduction." #' https://arxiv.org/abs/1802.03426 #' #' @examples #' \dontrun{ #' dat <- loadDataSet("3D S Curve", n = 300) #' emb <- embed(dat, "UMAP", .mute = NULL, knn = 10) #' plot(emb, type = "2vars") #' } #' #' @include dimRedResult-class.R #' @include dimRedMethod-class.R #' @family dimensionality reduction methods #' @export UMAP #' @exportClass UMAP UMAP <- setClass( "UMAP", contains = "dimRedMethod", prototype = list( stdpars = list( knn = 15, ndim = 2, d = "euclidean", method = "umap-learn" ), fun = function (data, pars, keep.org.data = TRUE) { chckpkg("umap") if (pars$method == "python") { chckpkg("reticulate") if (!reticulate::py_module_available("umap")) stop("cannot find python umap, install with `pip install umap-learn`") } meta <- data@meta orgdata <- if (keep.org.data) data@data else NULL indata <- data@data ## Create config umap_call_pars <- umap::umap.defaults umap_call_pars$n_neighbors <- pars$knn umap_call_pars$n_components <- pars$ndim umap_call_pars$metric <- pars$d umap_call_pars$method <- pars$method umap_call_pars$d <- indata pars_2 <- pars pars_2$knn <- NULL pars_2$ndim <- NULL pars_2$d <- NULL pars_2$method <- NULL for (n in names(pars_2)) umap_call_pars[[n]] <- pars_2[[n]] ## Do the embedding outdata <- do.call(umap::umap, umap_call_pars) ## Post processing colnames(outdata$layout) <- paste0("UMAP", 1:ncol(outdata$layout)) appl <- function(x) { appl.meta <- if (inherits(x, "dimRedData")) x@meta else data.frame() proj <- if (inherits(x, "dimRedData")) x@data else x if (ncol(proj) != ncol(orgdata)) stop("x must have the same number of dimensions ", "as the original data") new_proj <- umap:::predict.umap(outdata, as.matrix(proj)) colnames(new_proj) <- paste0("UMAP", 1:ncol(new_proj)) rownames(new_proj) <- NULL out_data <- new("dimRedData", data = new_proj, meta = appl.meta) return(out_data) } return(new( "dimRedResult", data = new("dimRedData", data = outdata$layout, meta = meta), org.data = orgdata, apply = appl, has.org.data = keep.org.data, has.apply = TRUE, method = "UMAP", pars = pars )) }, requires = c("umap", "reticulate") ) ) dimRed/R/mds.R0000644000176200001440000001150013562741725012576 0ustar liggesusers#' Metric Dimensional Scaling #' #' An S4 Class implementing classical scaling (MDS). #' #' MDS tries to maintain distances in high- and low-dimensional space, #' it has the advantage over PCA that arbitrary distance functions can #' be used, but it is computationally more demanding. #' #' @template dimRedMethodSlots #' #' @template dimRedMethodGeneralUsage #' #' @section Parameters: #' MDS can take the following parameters: #' \describe{ #' \item{ndim}{The number of dimensions.} #' \item{d}{The function to calculate the distance matrix from the input coordinates, defaults to euclidean distances.} #' } #' #' @section Implementation: #' #' Wraps around \code{\link[stats]{cmdscale}}. The implementation also #' provides an out-of-sample extension which is not completely #' optimized yet. #' #' @references #' #' Torgerson, W.S., 1952. Multidimensional scaling: I. Theory and method. #' Psychometrika 17, 401-419. https://doi.org/10.1007/BF02288916 #' #' @examples #' \dontrun{ #' dat <- loadDataSet("3D S Curve") #' emb <- embed(dat, "MDS") #' plot(emb, type = "2vars") #' #' # a "manual" kPCA: #' emb2 <- embed(dat, "MDS", d = function(x) exp(stats::dist(x))) #' plot(emb2, type = "2vars") #' #' # a "manual", more customizable, and slower Isomap: #' emb3 <- embed(dat, "MDS", d = function(x) vegan::isomapdist(vegan::vegdist(x, "manhattan"), k = 20)) #' plot(emb3) #' #' } #' @include dimRedResult-class.R #' @include dimRedMethod-class.R #' @family dimensionality reduction methods #' @export MDS #' @exportClass MDS MDS <- setClass( "MDS", contains = "dimRedMethod", prototype = list( stdpars = list(d = stats::dist, ndim = 2), fun = function (data, pars, keep.org.data = TRUE) { ## meta <- data@meta orgdata <- if (keep.org.data) data@data else NULL indata <- data@data ## there are only efficient implementations for euclidean ## distances: extra efficient implementation for euclidean ## distances are possible, D is quared several times, it would be ## much faster to compute the squared distance right away. has.apply <- identical(all.equal(pars$d, dist), TRUE) # == TRUE # necessary, # because # all.equal # returns # TRUE or an # error # string!!!! D <- as.matrix(pars$d(indata)) if (has.apply) mD2 <- mean(D ^ 2) ## cmdscale square the matrix internally res <- stats::cmdscale(D, k = pars$ndim) outdata <- res D <- NULL ## Untested: remove that from environment before creating ## appl function, else it will stay in its environment ## forever appl <- if (!has.apply) function(x) NA else function(x) { appl.meta <- if (inherits(x, "dimRedData")) x@meta else data.frame() proj <- if (inherits(x, "dimRedData")) x@data else x ## double center new data with respect to old: TODO: optimize ## this method, according to the de Silva, Tenenbaum(2004) ## paper. Need an efficient method to calculate the distance ## matrices between different point sets and arbitrary ## distances. Kab <- as.matrix(pars$d(proj) ^ 2) Exa <- colMeans(pdist2(indata, proj)) Kab <- sweep(Kab, 1, Exa) #, "-") Kab <- sweep(Kab, 2, Exa) #, "-") Kab <- -0.5 * (Kab + mD2) ## Eigenvalue decomposition tmp <- eigen(Kab, symmetric = TRUE) ev <- tmp$values[seq_len(pars$ndim)] evec <- tmp$vectors[, seq_len(pars$ndim), drop = FALSE] k1 <- sum(ev > 0) if (k1 < pars$ndim) { warning(gettextf("only %d of the first %d eigenvalues are > 0", k1, k), domain = NA) evec <- evec[, ev > 0, drop = FALSE] ev <- ev[ev > 0] } points <- evec * rep(sqrt(ev), each = nrow(proj)) dimnames(points) <- list(NULL, paste0("MDS", seq_len(ncol(points)))) new("dimRedData", data = points, meta = appl.meta) } colnames(outdata) <- paste0("MDS", seq_len(ncol(outdata))) return(new( "dimRedResult", data = new("dimRedData", data = outdata, meta = meta), org.data = orgdata, apply = appl, has.org.data = keep.org.data, has.apply = has.apply, method = "mds", pars = pars )) }) ) dimRed/R/dimRedMethod-class.R0000644000176200001440000000743214256653532015473 0ustar liggesusers#' Class "dimRedMethod" #' #' A virtual class "dimRedMethod" to serve as a template to implement #' methods for dimensionality reduction. #' #' Implementations of dimensionality reductions should inherit from #' this class. #' #' The \code{fun} slot should be a function that takes three arguments #' \describe{ #' \item{data}{An object of class \code{\link{dimRedData}}.} #' \item{pars}{A list with the standard parameters.} #' \item{keep.org.data}{Logical. If the original data should be kept in the output.} #' } #' and returns an object of class \code{\link{dimRedResult}}. #' #' The \code{stdpars} slot should take a list that contains standard #' parameters for the implemented methods. #' #' This way the method can be called by \code{embed(data, "method-name", #' ...)}, where \code{...} can be used to to change single parameters. #' #' #' @slot fun A function that does the embedding. #' @slot stdpars A list with the default parameters for the \code{fun} slot. #' @slot requires A vector with all packages R packages that need to be #' installed to run the method. In some occasions a method may work without #' one of the packages. Does not include Python dependencies such as #' Tensorflow. Used to auto skip tests #' #' @family dimensionality reduction methods #' @export setClass("dimRedMethod", contains = "VIRTUAL", slots = c(fun = "function", stdpars = "list", requires = "character")) #' dimRedMethodList #' #' Get the names of all methods for dimensionality reduction. #' #' Returns the name of all classes that inherit from #' \code{\link{dimRedMethod-class}} to use with \code{\link{embed}}. #' @param filter filter methods by methods that have their dependencies installed #' @return a character vector with the names of classes that inherit #' from \code{dimRedMethod}. #' #' @examples #' dimRedMethodList() #' #' @family dimensionality reduction methods #' @export dimRedMethodList <- function (filter = FALSE) { all_methods <- names(completeClassDefinition("dimRedMethod", doExtends = FALSE)@subclasses) if(!filter) return(all_methods) all_deps <- lapply(all_methods, getMethodDependencies) is_possible <- sapply(all_deps, function(x) { if(length(x) > 0) requireNamespace(x, quietly = TRUE) else TRUE }) all_methods[is_possible] } # to put standard values for omitted arguments setGeneric("matchPars", function(object, pars) standardGeneric("matchPars"), valueClass = c("list")) setMethod("matchPars", signature(object = "dimRedMethod", pars = "list"), definition = function(object, pars) { nsp <- names(object@stdpars) ncp <- names(pars) nap <- union(nsp, ncp) res <- list() ## exists can deal with elements being NULL ## to assign list@el <- NULL do: ## list["el"] <- list(NULL) for (np in nap) { miss.std <- !exists(np, where = object@stdpars) miss.par <- !exists(np, where = pars) if (miss.std) { warning("Parameter matching: ", np, " is not a standard parameter, ignoring.") } else if (miss.par) { res[np] <- object@stdpars[np] } else { res[np] <- pars[np] } } ## if the method does not accept parameters we have to return ## null, so in embed there is no args$par created. and passed by ## do.call in the embed() function. if (length(res) != 0) ## return(res) else return(NULL) ## first try without the above, all methods should have a pars ## argument. return(res) }) getMethodDependencies <- function(method) { getMethodObject(method)@requires } method_can_run <- function(method) { all(getMethodDependencies(method) %in% row.names(installed.packages())) } dimRed/R/mixColorSpaces.R0000644000176200001440000000467114262553576014764 0ustar liggesusers#' Mixing color ramps #' #' mix different color ramps #' #' automatically create colors to represent a varying number of #' dimensions. #' #' @param vars a list of variables #' @param ramps a list of color ramps, one for each variable. #' #' @examples #' cols <- expand.grid(x = seq(0, 1, length.out = 10), #' y = seq(0, 1, length.out = 10), #' z = seq(0, 1, length.out = 10)) #' mixed <- mixColor3Ramps(cols) #' #' \dontrun{ #' if(requireNamespace("rgl", quietly = TRUE)) { #' rgl::plot3d(cols$x, cols$y, cols$z, col = mixed, pch = 15) #' } #' #' cols <- expand.grid(x = seq(0, 1, length.out = 10), #' y = seq(0, 1, length.out = 10)) #' mixed <- mixColor2Ramps(cols) #' #' if(requireNamespace("graphics", quietly = TRUE)) { #' plot(cols$x, cols$y, col = mixed, pch = 15) #' } #' } #' @importFrom grDevices colorRamp #' @importFrom grDevices rgb #' @export mixColorRamps <- function (vars, ramps) { if (length(vars) > length(ramps)) stop("need more or equal ramps than vars") nvars <- length(vars) rgbs <- list() for (i in 1:nvars){ rgbs[[i]] <- ramps[[i]](scale01(as.numeric(vars[[i]]))) } retrgb <- Reduce(`+`, rgbs) res <- apply(retrgb, 2, function(x) (x - min(x)) / (max(x) - min(x))) res[is.nan(res)] <- 0 return(rgb(res)) } #' @rdname mixColorRamps #' @export mixColor1Ramps <- function (vars, ramps = colorRamp(c("blue", "black", "red"))) { mixColorRamps(vars, list(ramps)) } #' @rdname mixColorRamps #' @export mixColor2Ramps <- function (vars, ramps = list(colorRamp(c("blue", "green")), colorRamp(c("blue", "red")))) { mixColorRamps(vars, ramps) } #' @rdname mixColorRamps #' @export mixColor3Ramps <- function (vars, ramps = list(colorRamp(c("#001A00", "#00E600")), colorRamp(c("#00001A", "#0000E6")), colorRamp(c("#1A0000", "#E60000")))) { mixColorRamps(vars, ramps) } colorize <- function (vars) { l <- length(vars) if (l == 1) return(mixColor1Ramps(vars)) if (l == 2) return(mixColor2Ramps(vars)) if (l == 3) return(mixColor3Ramps(vars)) return("#000000") } scale01 <- function(x, low = min(x, na.rm = TRUE), high = max(x, na.rm = FALSE)) { x <- (x - low) / (high - low) x } dimRed/R/get_info.R0000644000176200001440000000215714262545361013611 0ustar liggesusers#' getRotationMatrix #' #' Extract the rotation matrix from \code{\link{dimRedResult}} objects derived from PCA and FastICA #' #' The data has to be pre-processed the same way as the method does, e.g. #' centering and/or scaling. #' #' @param x of type \code{\link{dimRedResult}} #' @return a matrix #' #' @examples #' dat <- loadDataSet("Iris") #' #' pca <- embed(dat, "PCA") #' rot_pca <- getRotationMatrix(pca) #' scale(getData(dat), TRUE, FALSE) %*% rot_pca - getData(getDimRedData(pca)) #' #' #' if(requireNamespace("fastICA", quietly = TRUE)) { #' ica <- embed(dat, "FastICA") #' rot_ica <- getRotationMatrix(ica) #' scale(getData(dat), TRUE, FALSE) %*% rot_ica - getData(getDimRedData(ica)) #' } #' #' #' @family convenience functions #' @export getRotationMatrix <- function(x) { if(!inherits(x, "dimRedResult")) stop("x must be of type 'dimRedResult'") if(x@method == "PCA") return(environment(x@apply)$rot) if(x@method == "PCA_L1") return(environment(x@apply)$rot) if(x@method == "FastICA") return(environment(x@apply)$res$K %*% environment(x@apply)$res$W) stop(paste("Not implemented for", x@method)) } dimRed/R/l1pca.R0000644000176200001440000001407514256645203013020 0ustar liggesusers#' Principal Component Analysis with L1 error. #' #' S4 Class implementing PCA with L1 error. #' #' PCA transforms the data so that the L2 reconstruction error is minimized or #' the variance of the projected data is maximized. This is sensitive to #' outliers, L1 PCA minimizes the L1 reconstruction error or maximizes the sum #' of the L1 norm of the projected observations. #' #' @template dimRedMethodSlots #' #' @template dimRedMethodGeneralUsage #' #' @section Parameters: #' PCA can take the following parameters: #' \describe{ #' \item{ndim}{The number of output dimensions.} #' \item{center}{logical, should the data be centered, defaults to \code{TRUE}.} #' \item{scale.}{logical, should the data be scaled, defaults to \code{FALSE}.} #' \item{fun}{character or function, the method to apply, see the \code{pcaL1} package} #' \item{\ldots}{other parameters for \code{fun}} #' } #' #' @section Implementation: #' #' Wraps around the different methods is the \code{pcaL1} package. Because PCA #' can be reduced to a simple rotation, forward and backward projection #' functions are supplied. #' #' @references #' #' Park, Y.W., Klabjan, D., 2016. Iteratively Reweighted Least Squares #' Algorithms for L1-Norm Principal Component Analysis, in: Data Mining (ICDM), #' 2016 IEEE 16th International Conference On. IEEE, pp. 430-438. #' #' @examples #' if(requireNamespace("pcaL1", quietly = TRUE)) { #' #' dat <- loadDataSet("Iris") #' emb <- embed(dat, "PCA_L1") #' #' plot(emb, type = "2vars") #' plot(inverse(emb, getData(getDimRedData((emb)))), type = "3vars") #' #' } #' #' @include dimRedResult-class.R #' @include dimRedMethod-class.R #' @family dimensionality reduction methods #' @export PCA_L1 #' @exportClass PCA_L1 PCA_L1 <- setClass( "PCA_L1", contains = "dimRedMethod", prototype = list( stdpars = list(ndim = 2, center = TRUE, scale. = FALSE, fun = "awl1pca", projections = "l1"), fun = function (data, pars, keep.org.data = TRUE) { chckpkg("pcaL1") ndim <- pars$ndim orgnames <- colnames(data@data) newnames <- paste0("PC", seq_len(ndim)) meta <- data@meta orgdata <- if (keep.org.data) data@data else NULL data <- data@data fun2 <- if(!is.function(pars$fun)) { get(pars$fun, asNamespace("pcaL1")) } else { pars$fun } ce <- if (is.numeric(pars$center)) { if (length(pars$center) != dim(data)[2]) error("center must be logical or have the same length as the data dimensions") pars$center } else if (is.logical(pars$center)) { if (pars$center) colMeans(data) else FALSE } sc <- if (is.numeric(pars$scale.)) { if (length(pars$scale.) != dim(data)[2]) stop("center must be logical or have the same length as the data dimensions") pars$scale. } else if (is.logical(pars$scale.)) { if (pars$scale.) apply(data, 2, sd) else FALSE } if(!(pars$center == FALSE && pars$scale. == FALSE)) data <- scale(data, ce, sc) pars$center <- NULL pars$scale. <- NULL pars$ndim <- NULL pars$fun <- NULL res <- do.call( fun2, c(list(X = data, projDim = ndim, center = FALSE), pars) ) ## evaluate results here for functions data <- res$scores colnames(data) <- paste0("PC", seq_len(ndim)) rot <- res$loadings[, seq_len(ndim), drop = FALSE] dimnames(rot) <- list(orgnames, newnames) rerot <- t(rot) appl <- function(x) { appl.meta <- if (inherits(x, "dimRedData")) x@meta else data.frame() proj <- if (inherits(x, "dimRedData")) x@data else x if (ncol(proj) != ncol(orgdata)) stop("x must have the same number of dimensions ", "as the original data") if (ce[1] != FALSE) proj <- t(apply(proj, 1, function(x) x - ce)) if (sc[1] != FALSE) proj <- t(apply(proj, 1, function(x) x / sc)) proj <- if (pars$projections == "l1") { tmp <- pcaL1::l1projection(proj, rot)$scores colnames(tmp) <- paste0("PC", seq_len(ndim)) tmp } else if (pars$projections == "l2") { proj %*% rot } else { stop("projections must be eiter 'l1' or 'l2'") } proj <- new("dimRedData", data = proj, meta = appl.meta) return(proj) } inv <- function(x) { appl.meta <- if (inherits(x, "dimRedData")) x@meta else data.frame() proj <- if (inherits(x, "dimRedData")) x@data else x if (ncol(proj) > ncol(data)) stop("x must have less or equal number of dimensions ", "as the original data") d <- ncol(proj) reproj <- proj %*% rerot[seq_len(d), ] if (sc[1] != FALSE) reproj <- t(apply(reproj, 1, function(x) x * sc)) if (ce[1] != FALSE) reproj <- t(apply(reproj, 1, function(x) x + ce)) colnames(reproj) <- colnames(orgdata) reproj <- new("dimRedData", data = reproj, meta = appl.meta) return(reproj) } res <- new( "dimRedResult", data = new("dimRedData", data = data, meta = meta), org.data = orgdata, apply = appl, inverse = inv, has.org.data = keep.org.data, has.apply = TRUE, has.inverse = TRUE, method = "PCA_L1", pars = pars ) return(res) }, requires = c("pcaL1")) ) dimRed/R/dimRedResult-class.R0000644000176200001440000001544413371631672015531 0ustar liggesusers#' @include misc.R #' @include dimRedData-class.R NULL #' Class "dimRedResult" #' #' A class to hold the results of of a dimensionality reduction. #' #' @slot data Output data of class dimRedData. #' @slot org.data original data, a matrix. #' @slot apply a function to apply the method to out-of-sampledata, #' may not exist. #' @slot inverse a function to calculate the original coordinates from #' reduced space, may not exist. #' @slot has.org.data logical, if the original data is included in the object. #' @slot has.apply logical, if a forward method is exists. #' @slot has.inverse logical if an inverse method exists. #' @slot method saves the method used. #' @slot pars saves the parameters used. #' @slot other.data other data produced by the method, e.g. a distance matrix. #' #' @examples #' ## Create object by embedding data #' iris.pca <- embed(loadDataSet("Iris"), "PCA") #' #' ## Convert the result to a data.frame #' head(as(iris.pca, "data.frame")) #' head(as.data.frame(iris.pca)) #' #' ## There are no nameclashes to avoid here: #' head(as.data.frame(iris.pca, #' org.data.prefix = "", #' meta.prefix = "", #' data.prefix = "")) #' #' ## Print it more or less nicely: #' print(iris.pca) #' #' ## Get the embedded data as a dimRedData object: #' getDimRedData(iris.pca) #' #' ## Get the original data including meta information: #' getOrgData(iris.pca) #' #' @family dimRedResult #' @export dimRedResult #' @exportClass dimRedResult dimRedResult <- setClass( "dimRedResult", slots = c( data = "dimRedData", org.data = "matrix", apply = "function", inverse = "function", has.org.data = "logical", has.apply = "logical", has.inverse = "logical", method = "character", pars = "list", other.data = "list" ), prototype = list( data = new("dimRedData"), org.data = matrix(numeric(0), 0, 0), apply = function(x) NA, inverse = function(x) NA, has.org.data = FALSE, has.apply = FALSE, has.inverse = FALSE, method = "", pars = list(), other.data = list() ) ) setAs( from = "dimRedResult", to = "data.frame", def = function(from){ if (from@has.org.data) { org.data <- from@org.data names(org.data) <- paste("org", names(org.data), sep = ".") cbind(as(from@data, "data.frame"), as.data.frame(org.data)) } else { as(from@data, "data.frame") } } ) #' @importFrom stats predict #' @export setGeneric( "predict", function(object, ...) standardGeneric("predict"), useAsDefault = stats::predict ) #' @describeIn dimRedResult apply a trained method to new data, does not work #' with all methods, will give an error if there is no \code{apply}. #' In some cases the apply function may only be an approximation. #' @param xnew new data, of type \code{\link{dimRedData}} #' #' @export setMethod(f = "predict", signature = "dimRedResult", definition = function(object, xnew) { if (object@has.apply) object@apply(xnew) else stop("object does not have an apply function") }) #' @export setGeneric( "inverse", function(object, ...) standardGeneric("inverse") ) #' @describeIn dimRedResult inverse transformation of embedded data, does not #' work with all methods, will give an error if there is no \code{inverse}. #' In some cases the apply function may only be an approximation. #' @param ynew embedded data, of type \code{\link{dimRedData}} #' #' @aliases inverse #' @export setMethod(f = "inverse", signature = c("dimRedResult"), definition = function(object, ynew) { if (object@has.inverse) object@inverse(ynew) else stop("object does not have an inverse function") }) #' @param x Of class \code{dimRedResult} #' @param org.data.prefix Prefix for the columns of the org.data slot. #' @param meta.prefix Prefix for the columns of \code{x@@data@@meta}. #' @param data.prefix Prefix for the columns of \code{x@@data@@data}. #' #' @describeIn dimRedResult convert to \code{data.frame} #' @export setMethod(f = "as.data.frame", signature = c("dimRedResult"), definition = function(x, org.data.prefix = "org.", meta.prefix = "meta.", data.prefix = "") { tmp <- list() if (nrow(x@data@meta) > 0){ tmp$meta <- as.data.frame(x@data@meta) names(tmp$meta) <- paste0(meta.prefix, colnames(x@data@meta)) } tmp$data <- as.data.frame(x@data@data) names(tmp$data) <- paste0(data.prefix, colnames(x@data@data)) if (x@has.org.data){ tmp$org.data <- as.data.frame(x@org.data) names(tmp$org.data) <- paste0(org.data.prefix, colnames(x@org.data)) } names(tmp) <- NULL data.frame(tmp, stringsAsFactors = FALSE) }) #' @param object Of class \code{dimRedResult} #' @describeIn dimRedResult Get the parameters with which the method #' was called. #' @export setMethod( f = "getPars", signature = "dimRedResult", definition = function (object) { object@pars } ) #' @describeIn dimRedResult Get the number of embedding dimensions. #' @export setMethod( f = "getNDim", signature = "dimRedResult", definition = function (object) { result <- getPars(object)$ndim if(is.null(result)) dim(object@data@data)[2] else result } ) #' @describeIn dimRedResult Method for printing. #' @import utils #' @export setMethod( f = "print", signature = "dimRedResult", definition = function(x) { cat("Method:\n") cat(x@method, "\n") cat("Parameters:\n") utils::str(x@pars) } ) #' @describeIn dimRedResult Get the original data and meta.data #' @export setMethod( f = "getOrgData", signature = "dimRedResult", definition = function(object) { return(new("dimRedData", data = object@org.data, meta = object@data@meta)) } ) #' @describeIn dimRedResult Get the embedded data #' @export setMethod( f = "getDimRedData", signature = "dimRedResult", definition = function(object) { return(object@data) } ) #' @describeIn dimRedResult Extract the number of embedding dimensions. #' #' @examples #' ## Get the number of variables: #' ndims(iris.pca) #' #' @export setMethod( "ndims", "dimRedResult", function(object) ncol(object@data@data) ) #' @describeIn dimRedResult Get other data produced by the method #' @export setMethod( f = "getOtherData", signature = "dimRedResult", definition = function(object) object@other.data ) dimRed/R/dimRed.R0000644000176200001440000000232413371631672013220 0ustar liggesusers#' @title The dimRed package #' #' @description This package simplifies dimensionality reduction in R by #' providing a framework of S4 classes and methods. dimRed collects #' dimensionality reduction methods that are implemented in R and implements #' others. It gives them a common interface and provides plotting #' functions for visualization and functions for quality assessment. #' #' Funding provided by the Department for Biogeochemical Integration, #' Empirical Inference of the Earth System Group, at the Max Plack #' Institute for Biogeochemistry, Jena. #' #' @references #' #' Lee, J.A., Renard, E., Bernard, G., Dupont, P., Verleysen, M., #' 2013. Type 1 and 2 mixtures of Kullback-Leibler divergences as cost #' functions in dimensionality reduction based on similarity #' preservation. Neurocomputing. 112, #' 92-107. doi:10.1016/j.neucom.2012.12.036 #' #' Lee, J.A., Lee, J.A., Verleysen, M., 2008. Rank-based quality #' assessment of nonlinear dimensionality reduction. Proceedings of #' ESANN 2008 49-54. #' #' Chen, L., Buja, A., 2006. Local Multidimensional Scaling for #' Nonlinear Dimension Reduction, Graph Layout and Proximity Analysis. #' #' #' @import methods #' @importFrom magrittr %>% #' "_PACKAGE" dimRed/R/embed.R0000644000176200001440000001217614256650700013072 0ustar liggesusers#' dispatches the different methods for dimensionality reduction #' #' wraps around all dimensionality reduction functions. #' #' Method must be one of \code{\link{dimRedMethodList}()}, partial matching #' is performed. All parameters start with a dot, to avoid clashes #' with partial argument matching (see the R manual section 4.3.2), if #' there should ever occur any clashes in the arguments, call the #' function with all arguments named, e.g. \code{embed(.data = dat, #' .method = "mymethod", .d = "some parameter")}. #' #' @param .data object of class \code{\link{dimRedData}}, will be converted to #' be of class \code{\link{dimRedData}} if necessary; see examples for #' details. #' @param .method character vector naming one of the dimensionality reduction #' techniques. #' @param .mute a character vector containing the elements you want to mute #' (\code{c("message", "output")}), defaults to \code{character(0)}. #' @param .keep.org.data \code{TRUE}/\code{FALSE} keep the original data. #' @param ... the parameters, internally passed as a list to the dimensionality #' reduction method as \code{pars = list(...)} #' @return an object of class \code{\link{dimRedResult}} #' #' @examples #' ## embed a data.frame using a formula: #' as.data.frame( #' embed(Species ~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width, #' iris, "PCA") #' ) #' #' ## embed a data.frame and return a data.frame #' as.data.frame(embed(iris[, 1:4], "PCA")) #' #' ## embed a matrix and return a data.frame #' as.data.frame(embed(as.matrix(iris[, 1:4]), "PCA")) #' #' \dontrun{ #' ## embed dimRedData objects #' embed_methods <- dimRedMethodList() #' quality_methods <- dimRedQualityList() #' dataset <- loadDataSet("Iris") #' #' quality_results <- matrix(NA, length(embed_methods), length(quality_methods), #' dimnames = list(embed_methods, quality_methods)) #' embedded_data <- list() #' #' for (e in embed_methods) { #' message("embedding: ", e) #' embedded_data[[e]] <- embed(dataset, e, .mute = c("message", "output")) #' for (q in quality_methods) { #' message(" quality: ", q) #' quality_results[e, q] <- tryCatch( #' quality(embedded_data[[e]], q), #' error = function(e) NA #' ) #' } #' } #' #' print(quality_results) #' } #' @export setGeneric("embed", function(.data, ...) standardGeneric("embed"), valueClass = "dimRedResult") #' @describeIn embed embed a data.frame using a formula. #' @param .formula a formula, see \code{\link{as.dimRedData}}. #' @export setMethod( "embed", "formula", function(.formula, .data, .method = dimRedMethodList(), .mute = character(0), .keep.org.data = TRUE, ...) { if (!is.data.frame(.data)) stop(".data must be a data.frame") .data <- as.dimRedData(.formula, .data) embed(.data, .method, .mute, .keep.org.data, ...) } ) #' @describeIn embed Embed anything as long as it can be coerced to #' \code{\link{dimRedData}}. #' @export setMethod( "embed", "ANY", function(.data, .method = dimRedMethodList(), .mute = character(0), .keep.org.data = TRUE, ...) { embed(as(.data, "dimRedData"), .method, .mute, .keep.org.data, ...) } ) #' @describeIn embed Embed a dimRedData object #' @export setMethod( "embed", "dimRedData", function(.data, .method = dimRedMethodList(), .mute = character(0), #c("message", "output"), .keep.org.data = TRUE, ...) { .method <- if (all(.method == dimRedMethodList())) "PCA" else match.arg(.method) methodObject <- getMethodObject(.method) args <- list( data = as(.data, "dimRedData"), keep.org.data = .keep.org.data ) args$pars <- matchPars(methodObject, list(...)) devnull <- if (Sys.info()["sysname"] != "Windows") "/dev/null" else "NUL" if ("message" %in% .mute){ devnull1 <- file(devnull, "wt") sink(devnull1, type = "message") on.exit({ sink(file = NULL, type = "message") close(devnull1) }, add = TRUE) } if ("output" %in% .mute) { devnull2 <- file(devnull, "wt") sink(devnull2, type = "output") on.exit({ sink() close(devnull2) }, add = TRUE) } do.call(methodObject@fun, args) } ) getMethodObject <- function (method) { ## switch( ## method, ## graph_kk = kamada_kawai, ## graph_drl = drl, ## graph_fr = fruchterman_reingold, ## drr = drr, ## isomap = isomap, ## diffmap = diffmap, ## tsne = tsne, ## nmds = nmds, ## mds = mds, ## ica = fastica, ## pca = pca, ## lle = lle, ## loe = loe, ## soe = soe, ## leim = leim, ## kpca = kpca ## ) method <- match.arg(method, dimRedMethodList()) do.call(method, list()) } dimRed/R/rotate.R0000644000176200001440000001642513371631672013321 0ustar liggesusers ## rotate X in such a way that the values of Y have maximum squared ## correlation with the dimensions specified in axes. We optimize ## axes[1] first, then axes[2] without axes[1], ... ## we maximize the squared correlations of the original variables ## with the axis of the embeding and the final result is the sum_{axes} sum(squared(correlation(variables, axis))) setGeneric( "maximize_correlation", function(object, ...) standardGeneric("maximize_correlation"), valueClass = "dimRedResult" ) #' Maximize Correlation with the Axes #' #' Rotates the data in such a way that the correlation with the first #' \code{naxes} axes is maximized. #' #' Methods that do not use eigenvector decomposition, like t-SNE often #' do not align the data with axes according to the correlation of #' variables with the data. \code{maximize_correlation} uses the #' \code{\link[optimx]{optimx}} package to rotate the data in such a #' way that the original variables have maximum correlation with the #' embedding axes. #' #' @param object A dimRedResult object #' @param naxes the number of axes to optimize for. #' @param cor_method which correlation method to use #' #' @aliases maximize_correlation #' @export setMethod( "maximize_correlation", "dimRedResult", function(object, naxes = ncol(object@data@data), cor_method = "pearson"){ ## if (missing(naxes)) naxes <- ncol(object@data@data) ## if (missing(cor_method)) cor_method <- "pearson" if (!object@has.org.data) stop("object requires original data") if (length(naxes) != 1 || naxes < 1 || naxes > ncol(object@data@data)) stop("naxes must specify the numbers of axes to optimize for, ", "i.e. a single integer between 1 and ncol(object@data@data)") ## try to partially match cor_method: cor_method <- cor_method[pmatch(cor_method, c("pearson", "kendall", "spearman"))] if (is.na(cor_method)) stop("cor_method must match one of ", "'pearson', 'kendall', or 'spearman', ", "at least partially.") mcres <- .maximize_correlation(object@data@data, object@org.data, 1:naxes, cor_method) res <- object res@data@data <- mcres$rotated return(res) } ) .maximize_correlation <- function(X, Y, axes = 1:ncol(X), cor_method = "pearson"){ if (nrow(X) != nrow(Y)) stop("'X' and 'Y' must have the same number of rows") if (max(axes) > ncol(X)){ axes <- axes[ axes <= ncol(X) ] warning("'max(axes)' must be <= 'ncol(X)', removing some axes") } chckpkg("optimx") xndim <- ncol(X) without_axes <- integer(0) res <- list() for (axis in axes){ without_axes <- c(without_axes, axis) nplanes <- xndim - length(without_axes) planes <- matrix(NA, 2, nplanes) planes[1, ] <- axis planes[2, ] <- (1:xndim)[-without_axes] if (ncol(planes) == 0) break o <- optimx::optimx( par = rep(0, nplanes), fn = obj, method = "L-BFGS-B", lower = 0, upper = 2 * pi, X = as.matrix(X), Y = as.matrix(Y), axis = axis, without_axes = without_axes, cor_method = cor_method ) ## The result looks like this: ## p1 value fevals gevals niter convcode kkt1 kkt2 xtimes ## L-BFGS-B 0 -0.1613494 1 1 NA 0 FALSE NA 0.016 if (o$convcode > 0) stop("rotation did not converge.") res_idx <- length(res) + 1 res[[res_idx]] <- list() res[[res_idx]]$axis <- axis res[[res_idx]]$without_axes <- without_axes res[[res_idx]]$angs <- unname( unlist(o[1, 1:nplanes]) ) res[[res_idx]]$planes <- planes res[[res_idx]]$X <- rotate(res[[res_idx]]$angs, planes, X) res[[res_idx]]$cor <- -o$value } ## calculate the correlation for axes nres <- length(res) if (nres > 0) { ## the result is the sum of the mean squared correlations of the ## original variables with the axes. "res[[i]]$cor" contains the ## mean squared correlation of the variables with axis "i" res$result <- 0 for (i in 1:nres) res$result <- res$result + res[[i]]$cor ^ 2 ## res$result <- res$result / length(res) ## rotate the input to maximize correlations res$rotated <- X for (i in 1:nres) res$rotated <- rotate(res[[i]]$angs, res[[i]]$planes, res$rotated) } else { ## if we only had one dimension, simply return the means squared ## correlation and don't rotate res$result <- sum(correlate(X, Y, cor_method) ^ 2) res$rotated <- X } res } #### helper functions for rotation ## we create a number or rotation matrices around the 2d planes ## spanned by the orthonormal matrices, multiply them for a general ## rotation which is then applied to the data X rotate <- function (angs, planes, X) { ndim <- ncol(X) nplanes <- ncol(planes) if (length(angs) != nplanes) stop("length(angs) not equal to chose(ndim, 2)") ## loop over the planes to construct general rotation matrix rotmat <- diag(ndim) for (p in 1:nplanes) { ## 2d rotation ## possible optimization: create large rotation matrix ## directly and insert values linearly without a for loop rotmat2d <- matrix( c(cos(angs[p]), -sin(angs[p]), sin(angs[p]), cos(angs[p])), 2, 2, byrow = TRUE ) p_rotmat <- diag(ndim) for (i in 1:2) for (j in 1:2) p_rotmat[ planes[i, p], planes[j, p] ] <- rotmat2d[i, j] rotmat <- rotmat %*% p_rotmat } t(rotmat %*% t(X)) } get_planes <- function(ndims, axis, without_axes){ nplanes <- ndims - length(without_axes) planes <- matrix(NA, 2, nplanes) planes[1, ] <- axis planes[2, ] <- (1:ndims)[c(-axis, -without_axes)] planes } obj <- function(alpha, X, Y, axis, without_axes, cor_method = "pearson"){ ## correlation with first axis xndim <- ncol(X) planes <- get_planes(xndim, axis, without_axes) X2 <- rotate(alpha, planes, X) ## cor(x, y) returns a matrix with the correlations between the ## columns of x = X2 (rows) and the columns of y = Y (columns) we ## want the mean of squared correlations of all variables original ## variables with the first axis, i.e. we require the relevant ## (axis) column of the resulting matrix. ## Possible optimization: use only the relevant column of Y -mean(correlate( X2, Y, #use = "pairwise.complete.obs", method = cor_method )[axis, ] ^ 2) } correlate <- function (x, y, method, ...) { if (method != "kendall"){ return(stats::cor(x, y, method = method, ...)) } else { chckpkg("pcaPP") ## make the cor.fk method behave like cor for matrices: if (is.matrix(x) && is.matrix(y)) { res <- matrix( NA, nrow = ncol(x), ncol = ncol(y), dimnames = list(colnames(x), colnames(y)) ) for (i in 1:ncol(x)) { for (j in 1:ncol(y)){ res[i, j] <- pcaPP::cor.fk(x[, i], y[, j]) } } return(res) } else if (is.null(dim(x)) && is.null(dim(y))){ return(pcaPP::cor.fk(x, y)) } else { stop("something is wrong with the input of 'correlate()'") } } } dimRed/R/soe.R0000644000176200001440000000264213024273620012573 0ustar liggesusers## #' Soft Ordinal Embedding ## #' ## #' Instance of \code{\link{dimRedMethod}} for Soft Ordinal Embedding. ## #' ## #' For details see \code{\link[loe]{SOE}}. ## #' ## #' ## #' @examples ## #' dat <- loadDataSet("3D S Curve", n = 50) ## #' soe <- SOE() ## #' emb <- soe@fun(dat, soe@stdpars) ## #' ## #' ## #' plot(emb@data@data) ## #' ## #' ## #' @include dimRedResult-class.R ## #' @include dimRedMethod-class.R ## #' @export ## SOE <- setClass( ## "SOE", ## contains = "dimRedMethod", ## prototype = list( ## stdpars = list(d = stats::dist, knn = 50, ndim = 2), ## fun = function (data, ## pars, ## keep.org.data = TRUE) { ## chckpkg("loe") ## meta <- data@meta ## orgdata <- if (keep.org.data) data@data else NULL ## indata <- data@data ## outdata <- loe::SOE(loe::get.order(as.matrix(pars$d(indata))), ## N = nrow(indata), p = pars$ndim)$X ## colnames(outdata) <- paste0("SOE", 1:ncol(outdata)) ## return(new( ## "dimRedResult", ## data = new("dimRedData", ## data = outdata, ## meta = meta), ## org.data = orgdata, ## has.org.data = keep.org.data, ## method = "soe", ## pars = pars ## )) ## }) ## ) dimRed/R/misc.R0000644000176200001440000002213614256643006012747 0ustar liggesusers## if (!isClassUnion("missingORnumeric")) setClassUnion("missingORnumeric", c("numeric", "missing")) ## if (!isClassUnion("missingORcharacter")) setClassUnion("missingORcharacter", c("character", "missing")) ## if (!isClassUnion("missingORlogical")) setClassUnion("missingORlogical", c("logical", "missing")) ## if (!isClassUnion("missingORfunction")) setClassUnion("missingORfunction", c("function", "missing")) # Squared euclidean distance between points in A and B # taken from http://blog.felixriedel.com/2013/05/pairwise-distances-in-r/ pdist2 <- function (A, B) { an <- rowSums(A ^ 2) # apply(A, 1, function(rvec) crossprod(rvec, rvec)) bn <- rowSums(B ^ 2) # apply(B, 1, function(rvec) crossprod(rvec, rvec)) m <- nrow(A) n <- nrow(B) matrix(rep(an, n), nrow = m) + matrix(rep(bn, m), nrow = m, byrow = TRUE) - 2 * tcrossprod(A, B) } ## a + b ~ c + d ## becomes ## ~ c + d + 0 rhs <- function (formula) { fs <- as.character(formula)[3] stats::as.formula(paste("~", fs, "+ 0")) } ## a + b ~ c + d ## becomes ## ~ a + b + 0 lhs <- function (formula) { fs <- as.character(formula)[2] stats::as.formula(paste("~", fs, "+ 0")) } ## check if a package is installed chckpkg <- function (pkg) { if (!requireNamespace(pkg, quietly = TRUE)) { stop(paste0("require '", pkg, "' package, install it using install.packages('", pkg, "')")) } } ## create generics that appear in several different places #' Converts to data.frame #' #' General conversions of objects created by \code{dimRed} to \code{data.frame}. #' See class documentations for details (\code{\link{dimRedData}}, #' \code{\link{dimRedResult}}). For the documentation of this function in base #' package, see here: \code{\link[base]{as.data.frame.default}}. #' #' @param x The object to be converted #' @param row.names unused in \code{dimRed} #' @param optional unused in \code{dimRed} #' @param ... other arguments. setGeneric( "as.data.frame", function(x, row.names, optional, ...) standardGeneric("as.data.frame"), useAsDefault = base::as.data.frame, valueClass = "data.frame" ) #' Converts to dimRedData #' #' Conversion functions to dimRedData. #' #' @param formula The formula, left hand side is assigned to the meta slot right #' hand side is assigned to the data slot. #' @param ... other arguments. setGeneric( "as.dimRedData", function(formula, ...) standardGeneric("as.dimRedData"), valueClass = "dimRedData" ) #' Method getData #' #' Extracts the data slot. #' #' @param object The object to be converted. setGeneric("getData", function(object) standardGeneric("getData")) #' Method getMeta #' #' Extracts the meta slot. #' #' @param object The object to be converted. #' @param ... other arguments. setGeneric("getMeta", function(object, ...) standardGeneric("getMeta")) #' Method getPars #' #' Extracts the pars slot. #' #' @param object The object to be converted. #' @param ... other arguments. setGeneric("getPars", function (object, ...) standardGeneric("getPars")) #' Method getNDim #' #' Extract the number of embedding dimensions. #' #' @param object The object to get the dimensions from. #' @param ... other arguments. setGeneric("getNDim", function (object, ...) standardGeneric("getNDim")) #' Method getOrgData #' #' Extract the Original data. #' #' @param object The object to extract data from. #' @param ... other arguments. setGeneric("getOrgData", function (object, ...) standardGeneric("getOrgData")) #' Method getDimRedData #' #' Extract dimRedData. #' @param object The object to extract data from. #' @param ... other arguments. setGeneric("getDimRedData", function (object, ...) standardGeneric("getDimRedData")) #' Method getOtherData #' #' Extract other data produced by a dimRedMethod #' #' @param object The object to extract data from. #' @param ... other arguments. setGeneric("getOtherData", function (object, ...) standardGeneric("getOtherData"), valueClass = "list") #' Method print #' #' Imports the print method into the package namespace. #' #' @param x The object to be printed. #' @param ... Other arguments for printing. setGeneric("print", function(x, ...) standardGeneric("print")) #' Method ndims #' #' Extract the number of dimensions. #' #' @param object To extract the number of dimensions from. #' @param ... Arguments for further methods setGeneric("ndims", function (object, ...) standardGeneric("ndims"), valueClass = "integer") #' getSuggests #' #' Install packages wich are suggested by dimRed. #' #' By default dimRed will not install all the dependencies, because #' there are quite a lot and in case some of them are not available #' for your platform you will not be able to install dimRed without #' problems. #' #' To solve this I provide a function which automatically installes #' all the suggested packages. #' #' @param ... additional options passed to install.packages. #' #' @examples #' \dontrun{ #' installSuggests() #' } #' @export installSuggests <- function (...) { "%w/o%" <- function(x, y) x[!x %in% y] pkgString <- installed.packages()["dimRed", "Suggests"] deps <- strsplit(pkgString, ", |,\n")[[1]] deps <- gsub("\n", "", deps) # Windows needs this installedPkgs <- rownames(installed.packages()) missingPkgs <- deps %w/o% installedPkgs if (length(missingPkgs) > 0) { message("The following packages are missing: ") cat(missingPkgs, "\n") message("installing ...") install.packages(missingPkgs, ...) pkgString <- installed.packages()["dimRed", "Suggests"] installedPkgs <- rownames(installed.packages()) missingPkgs <- deps %w/o% installedPkgs if (length(missingPkgs) > 0) { message("Could not install the following packages:") cat(missingPkgs, "\n") message("please install manually or some methods will not work.") } else { message("All necessary packages installed") message("If things still don't work try 'update.packages()'") message("If it still does not work file a bugreport!!") } } else { message("All necessary packages installed") message("If things still don't work try 'update.packages()'") message("If it still does not work file a bugreport!!") } } ## input data(matrix or data frame) return knn graph implements ## "smart" choices on RANN::nn2 parameters we ignore radius search ## TODO: find out a good limit to switch from kd to bd trees COMMENT: ## bd trees are buggy, they dont work if there are duplicated data ## points and checking would neutralize the performance gain, so bd ## trees are not really usable. #' makeKNNgraph #' #' Create a K-nearest neighbor graph from data x. Uses #' \code{\link[RANN]{nn2}} as a fast way to find the neares neighbors. #' #' @param x data, a matrix, observations in rows, dimensions in #' columns #' @param k the number of nearest neighbors. #' @param eps number, if \code{eps > 0} the KNN search is approximate, #' see \code{\link[RANN]{nn2}} #' @param diag logical, if \code{TRUE} every edge of the returned #' graph will have an edge with weight \code{0} to itself. #' #' @return an object of type \code{\link[igraph]{igraph}} with edge #' weight being the distances. #' #' #' makeKNNgraph <- function(x, k, eps = 0, diag = FALSE){ ## requireNamespace("RANN") ## requireNamespace("igraph") ## consts INF_VAL <- 1.340781e+15 NA_IDX <- 0 BDKD_LIM <- 1000000 #todo: figure out a good value here ## select parameters M <- nrow(x) treetype <- "kd" # if (M < BDKD_LIM) "kd" else "bd" # see: # https://github.com/jefferis/RANN/issues/19 searchtype <- if (eps == 0) "standard" else "priority" ## RANN::nn2 returns the points in data with respect to query ## e.g. the rows in the output are the points in query and the ## columns the points in data. nn2res <- RANN::nn2(data = x, query = x, k = k + 1, treetype = treetype, searchtype = searchtype, eps = eps) ## create graph: the first ny nodes will be y, the last nx nodes ## will be x, if x != y g <- igraph::make_empty_graph(M, directed = FALSE) g[from = if (diag) rep(seq_len(M), times = k + 1) else rep(seq_len(M), times = k), to = if (diag) as.vector(nn2res$nn.idx) else as.vector(nn2res$nn.idx[, -1]), attr = "weight"] <- if (diag) as.vector(nn2res$nn.dists) else as.vector(nn2res$nn.dists[, -1]) return(g) } makeEpsSparseMatrix <- function(x, eps) { chckpkg("Matrix") n <- nrow(x) dd <- stats::dist(x) ddind <- dd < eps rows <- unlist(lapply(2:n, function(x) x:n), use.names = FALSE) cols <- rep(seq_len(n - 1), times = (n - 1):1) Matrix::sparseMatrix(i = rows[ddind], j = cols[ddind], x = dd[ddind], dims = c(n, n), symmetric = TRUE) } dimRed/R/nnmf.R0000644000176200001440000001244114262544570012753 0ustar liggesusers#' Non-Negative Matrix Factorization #' #' S4 Class implementing NNMF. #' #' NNMF is a method for decomposing a matrix into a smaller #' dimension such that the constraint that the data (and the #' projection) are not negative is taken into account. #' #' @template dimRedMethodSlots #' #' @template dimRedMethodGeneralUsage #' #' @section Parameters: #' The method can take the following parameters: #' \describe{ #' \item{ndim}{The number of output dimensions.} #' \item{method}{character, which algorithm should be used. See #' \code{\link[NMF]{nmf}} for possible values. Defaults to #' "brunet"} #' \item{nrun}{integer, the number of times the computations are #' conducted. See \code{\link[NMF]{nmf}}} #' \item{seed}{integer, a value to control the random numbers used.} #' \item{options}{named list, other options to pass to \code{\link[NMF]{nmf}}} #' } #' #' @section Implementation: #' #' Wraps around \code{\link[NMF]{nmf}}. Note that the estimation uses random #' numbers. To create reproducible results, set the random number seed in the #' function call. Also, in many cases, the computations will be conducted #' in parallel using multiple cores. To disable this, use the option #' \code{.pbackend = NULL}. #' #' @references #' #' Lee, D.D., Seung, H.S., 1999. Learning the parts of objects by non-negative #' matrix factorization. Nature 401, 788-791. https://doi.org/10.1038/44565 #' #' @examples #' if(requireNamespace(c("NNMF", "MASS"), quietly = TRUE)) { #' #' set.seed(4646) #' dat <- loadDataSet("Iris") #' emb <- embed(dat, "NNMF") #' #' plot(emb) #' #' # project new values: #' nn_proj <- predict(emb, dat[1:7]) #' plot(nn_proj) #' #' } #' @include dimRedResult-class.R #' @include dimRedMethod-class.R #' @family dimensionality reduction methods #' @export NNMF #' @exportClass NNMF NNMF <- setClass( "NNMF", contains = "dimRedMethod", prototype = list( stdpars = list(ndim = 2L, method = "brunet", nrun = 1, seed = sample.int(10^5, 1), options = list()), fun = function (data, pars, keep.org.data = TRUE) { chckpkg("NMF") chckpkg("MASS") ## TODO: remove this, depends on https://github.com/renozao/NMF/issues/114 ## require("NMF") meta <- data@meta orgdata <- if (keep.org.data) data@data else NULL data <- data@data if (!is.matrix(data)) data <- as.matrix(data) # NMF expects variables in rows and samples in columns data <- t(data) if (pars$ndim > nrow(data)) stop("`ndim` should be less than the number of columns.", call. = FALSE) if (length(pars$method) != 1) stop("only supply one `method`", call. = FALSE) args <- list(x = quote(data), rank = pars$ndim, method = pars$method, nrun = pars$nrun, seed = pars$seed) if (length(pars$options) > 0) args <- c(args, pars$options) nmf_result <- do.call(NMF::nmf, args) # this should work but doesn't # call <- c(list(quote(NMF::nmf)), args) w <- NMF::basis(nmf_result) h <- t(NMF::coef(nmf_result)) colnames(w) <- paste0("NNMF", 1:ncol(w)) other.data <- list(w = w) colnames(h) <- paste0("NNMF", 1:ncol(h)) # evaluate results here for functions appl <- function (x) { appl.meta <- if (inherits(x, "dimRedData")) x@meta else data.frame() dat <- if (inherits(x, "dimRedData")) x@data else x if (!is.matrix(dat)) dat <- as.matrix(dat) if (ncol(dat) != nrow(w)) stop("x must have the same number of columns ", "as the original data (", nrow(w), ")", call. = FALSE) res <- dat %*% t(MASS::ginv(w)) colnames(res) <- paste0("NNMF", 1:ncol(res)) scores <- new("dimRedData", data = res, meta = appl.meta) return(scores) } inv <- function (x) { appl.meta <- if (inherits(x, "dimRedData")) x@meta else data.frame() proj <- if (inherits(x, "dimRedData")) x@data else x if (ncol(proj) > ncol(w)) stop("x must have less or equal number of dimensions ", "as the original data") res <- tcrossprod(proj, w) colnames(res) <- colnames(data) res <- new("dimRedData", data = res, meta = appl.meta) return(res) } ## inv <- function(x) { ## appl.meta <- if (inherits(x, "dimRedData")) x@meta else data.frame() ## proj <- if (inherits(x, "dimRedData")) x@data else x ## if (ncol(proj) > ncol(data)) ## stop("x must have less or equal number of dimensions ", ## "as the original data") ## reproj <- proj %*% other.data$H ## reproj <- new("dimRedData", data = reproj, meta = appl.meta) ## return(reproj) ## } res <- new( "dimRedResult", data = new("dimRedData", data = h, meta = meta), org.data = orgdata, apply = appl, inverse = inv, has.org.data = keep.org.data, has.apply = TRUE, has.inverse = TRUE, method = "NNMF", pars = pars, other.data = other.data ) return(res) }, requires = c("NMF", "MASS")) ) dimRed/R/hlle.R0000644000176200001440000001046614262545545012751 0ustar liggesusers#' Hessian Locally Linear Embedding #' #' An S4 Class implementing Hessian Locally Linear Embedding (HLLE) #' #' HLLE uses local hessians to approximate the curvines and is an #' extension to non-convex subsets in lowdimensional space. #' #' @template dimRedMethodSlots #' #' @template dimRedMethodGeneralUsage #' #' @section Parameters: #' HLLE can take the following parameters: #' \describe{ #' \item{knn}{neighborhood size} #' \item{ndim}{number of output dimensions} #' } #' #' @section Implementation: #' Own implementation, sticks to the algorithm in Donoho and Grimes #' (2003). Makes use of sparsity to speed up final embedding. #' #' @references #' Donoho, D.L., Grimes, C., 2003. Hessian eigenmaps: Locally linear #' embedding techniques for high-dimensional data. PNAS 100, #' 5591-5596. doi:10.1073/pnas.1031596100 #' #' @examples #' if(requireNamespace(c("RSpectra", "Matrix", "RANN"), quietly = TRUE)) { #' #' dat <- loadDataSet("3D S Curve", n = 300) #' emb <- embed(dat, "HLLE", knn = 15) #' plot(emb, type = "2vars") #' #' } #' #' @include dimRedResult-class.R #' @include dimRedMethod-class.R #' @family dimensionality reduction methods #' @export HLLE #' @exportClass HLLE HLLE <- setClass( "HLLE", contains = "dimRedMethod", prototype = list( stdpars = list(knn = 50, ndim = 2), fun = function(data, pars, keep.org.data = TRUE) { chckpkg("RSpectra") chckpkg("Matrix") chckpkg("RANN") if (pars$ndim < 2) stop("ndim must be 2 or larger.") if (is.null(pars$knn)) pars$knn <- 50 if (is.null(pars$ndim)) pars$ndim <- 2 indata <- data@data n <- nrow(indata) hs <- pars$ndim * (pars$ndim + 1) / 2 W <- Matrix::sparseMatrix(i = numeric(0), j = numeric(0), x = numeric(0), dims = c(n, hs * n)) ii <- jj <- ww <- list() ## Identify neighbors: message(Sys.time(), ": Finding nearest neighbors", sep = "") nnidx <- RANN::nn2(data = indata, query = indata, k = pars$knn + 1, treetype = "kd", "standard", eps = 0)$nn.idx#[, -1] message(Sys.time(), ": Calculating Hessian", sep = "") for (i in seq_len(n)) { cat(i, "/", n, "\r", sep = "") ## get neighborhood Nui <- indata[nnidx[i, ], , drop = FALSE] ## Form tangent coordinates: Nui <- sweep(Nui, 2, colMeans(Nui), "-") tc <- svd(Nui, nu = pars$ndim, nv = 0)$u ## Develop Hessian Estimator Xi <- cbind( 1, tc, tc ^ 2, apply(combn(seq_len(pars$ndim), 2), 2, function(x) tc[, x[1]] * tc[, x[2]]) ) tHi <- qr.Q(qr(Xi))[, -(1:(pars$ndim + 1)), drop = FALSE] ## Add quadratic form to hessian ii[[i]] <- rep(nnidx[i, ], hs) jj[[i]] <- rep((i - 1) * hs + (1:hs), each = ncol(nnidx)) ww[[i]] <- as.vector(tHi) } H <- as(Matrix::tcrossprod(Matrix::spMatrix( i = unlist(ii, FALSE, FALSE), j = unlist(jj, FALSE, FALSE), x = unlist(ww, FALSE, FALSE), nrow = n, ncol = n * hs) ), "dgCMatrix") ## Find null space: message(Sys.time(), ": Embedding", sep = "") ## eigs and eigs_sym converges much more reliably and faster ## with sigma = -eps than with which = "L*" outdata <- RSpectra::eigs_sym(H, k = pars$ndim + 1, sigma = -1e-5) message(paste(c("Eigenvalues:", format(outdata$values)), collapse = " ")) outdata <- outdata$vectors[, order(outdata$values)[-1], drop = FALSE] colnames(outdata) <- paste0("HLLE", seq_len(ncol(outdata))) message(Sys.time(), ": DONE", sep = "") return(new( "dimRedResult", data = new("dimRedData", data = outdata, meta = data@meta), org.data = if (keep.org.data) data@data else NULL, has.org.data = keep.org.data, method = "HLLE", pars = pars )) }, requires = c("RSpectra", "Matrix", "RANN")) ) dimRed/R/plot.R0000644000176200001440000001747714257367546013023 0ustar liggesusers#' Plotting of dimRed* objects #' #' Plots a object of class dimRedResult and dimRedData. For the #' documentation of the plotting function in base see here: #' \code{\link{plot.default}}. #' #' Plotting functions for the classes usind in \code{dimRed}. they are #' intended to give a quick overview over the results, so they are #' somewhat inflexible, e.g. it is hard to modify color scales or #' plotting parameters. #' #' If you require more control over plotting, it is better to convert #' the object to a \code{data.frame} first and use the standard #' functions for plotting. #' #' @param x dimRedResult/dimRedData class, e.g. output of #' embedded/loadDataSet #' @param y Ignored #' @param type plot type, one of \code{c("pairs", "parpl", "2vars", #' "3vars", "3varsrgl")} #' @param col the columns of the meta slot to use for coloring, can be #' referenced as the column names or number of x@data #' @param vars the axes of the embedding to use for plotting #' @param ... handed over to the underlying plotting function. #' #' @examples #' scurve = loadDataSet("3D S Curve") #' if(requireNamespace("graphics", quietly = TRUE)) #' plot(scurve, type = "pairs", main = "pairs plot of S curve") #' if(requireNamespace("MASS", quietly = TRUE)) #' plot(scurve, type = "parpl") #' if(requireNamespace("graphics", quietly = TRUE)) #' plot(scurve, type = "2vars", vars = c("y", "z")) #' if(requireNamespace("scatterplot3d", quietly = TRUE)) #' plot(scurve, type = "3vars") #' if(requireNamespace("rgl", quietly = TRUE)) #' plot(scurve, type = "3varsrgl") #' #' @include mixColorSpaces.R #' @include dimRedData-class.R #' @importFrom graphics plot #' #' @aliases plot.dimRed #' @export setGeneric( "plot", function(x, y, ...) standardGeneric("plot"), useAsDefault = graphics::plot ) #' @describeIn plot Ploting of dimRedData objects #' @aliases plot.dimRedData #' @export setMethod( f = "plot", signature = c("dimRedData"), definition = function(x, type = "pairs", vars = seq_len(ncol(x@data)), col = seq_len(min(3, ncol(x@meta))), ...) { cols <- colorize(x@meta[, col, drop = FALSE]) switch( type, "pairs" = { chckpkg("graphics") graphics::pairs(x@data[, vars], col = cols, ... ) }, "parpl" = { chckpkg("MASS") MASS::parcoord(x@data[, vars], col = cols, ... ) }, "2vars" = { chckpkg("graphics") graphics::plot(x@data[, vars[1:2]], col = cols, ... ) }, "3vars" = { chckpkg("scatterplot3d") scatterplot3d::scatterplot3d(x@data[, vars[1:3]], color = cols, ...) }, "3varsrgl" = { chckpkg("rgl") rgl::plot3d(x@data[, vars[1:3]], col = cols, ... ) }, stop("wrong argument to plot.dimRedData") ) } ) #' @describeIn plot Ploting of dimRedResult objects. #' @aliases plot.dimRedResult #' @export setMethod( f = "plot", signature = c("dimRedResult"), definition = function (x, type = "pairs", vars = seq_len(ncol(x@data@data)), col = seq_len(min(3, ncol(x@data@meta))), ...) { plot(x = x@data, type = type, vars = vars, col = col, ...) } ) #' plot_R_NX #' #' Plot the R_NX curve for different embeddings. Takes a list of #' \code{\link{dimRedResult}} objects as input. #' Also the Area under the curve values are computed for a weighted K #' (see \link{AUC_lnK_R_NX} for details) and appear in the legend. #' #' @param x a list of \code{\link{dimRedResult}} objects. The names of the list #' will appear in the legend with the AUC_lnK value. #' @param ndim the number of dimensions, if \code{NA} the original number of #' embedding dimensions is used, can be a vector giving the embedding #' dimensionality for each single list element of \code{x}. #' @param weight the weight function used for K when calculating the AUC, one of #' \code{c("inv", "log", "log10")} #' @family Quality scores for dimensionality reduction #' @return A ggplot object, the design can be changed by appending #' \code{theme(...)} #' #' @examples #' if(requireNamespace(c("RSpectra", "igraph", "RANN", "ggplot", "tidyr", "scales"), quietly = TRUE)) { #' ## define which methods to apply #' embed_methods <- c("Isomap", "PCA") #' ## load test data set #' data_set <- loadDataSet("3D S Curve", n = 200) #' ## apply dimensionality reduction #' data_emb <- lapply(embed_methods, function(x) embed(data_set, x)) #' names(data_emb) <- embed_methods #' ## plot the R_NX curves: #' plot_R_NX(data_emb) + #' ggplot2::theme(legend.title = ggplot2::element_blank(), #' legend.position = c(0.5, 0.1), #' legend.justification = c(0.5, 0.1)) #' } #' @export plot_R_NX <- function(x, ndim = NA, weight = "inv") { chckpkg("ggplot2") chckpkg("tidyr") chckpkg("scales") lapply( x, function(x) if (!inherits(x, "dimRedResult")) stop("x must be a list and ", "all items must inherit from 'dimRedResult'") ) rnx <- mapply(function(x, ndim) if(is.na(ndim)) R_NX(x) else R_NX(x, ndim), x = x, ndim = ndim) weight <- match.arg(weight, c("inv", "ln", "log", "log10")) w_fun <- switch( weight, inv = auc_ln_k_inv, log = auc_log_k, ln = auc_log_k, log10 = auc_log10_k, stop("wrong parameter for weight") ) auc <- apply(rnx, 2, w_fun) df <- as.data.frame(rnx) df$K <- seq_len(nrow(df)) qnxgrid <- expand.grid(K = df$K, rnx = seq(0.1, 0.9, by = 0.1)) ## TODO: FIND OUT WHY THIS AS IN THE PUBLICATION BUT IS WRONG! qnxgrid$qnx <- rnx2qnx(qnxgrid$rnx, K = qnxgrid$K, N = nrow(df)) # qnxgrid$rnx_group <- factor(qnxgrid$rnx) df <- tidyr::gather_(df, key_col = "embedding", value_col = "R_NX", names(x)) ggplot2::ggplot(df) + ggplot2::geom_line(ggplot2::aes_string(y = "R_NX", x = "K", color = "embedding")) + ## TODO: find out if this is wrong: ## ggplot2::geom_line(data = qnxgrid, ## mapping = ggplot2::aes_string(x = "K", y = "qnx", ## group = "rnx_group"), ## linetype = 2, ## size = 0.1) + ggplot2::geom_line(data = qnxgrid, mapping = ggplot2::aes_string(x = "K", y = "rnx", group = "rnx_group"), linetype = 3, size = 0.1) + ggplot2::scale_x_log10( labels = scales::trans_format("log10", scales::math_format()), expand = c(0, 0) ) + ggplot2::scale_y_continuous(expression(R[NX]), limits = c(0, 1), expand = c(0, 0)) + ggplot2::annotation_logticks(sides = "b") + ggplot2::scale_color_discrete( breaks = names(x), labels = paste(format(auc, digits = 3), names(x))) + ggplot2::labs(title = paste0( "R_NX vs. K", if (length(ndim) == 1 && !is.na(ndim)) paste0(", d = ", ndim) else "" )) + ggplot2::theme_classic() } dimRed/R/loe.R0000644000176200001440000000315514256645362012602 0ustar liggesusers ## this function produces segfaults and is super slow ## #' Local Ordinal Embedding ## #' ## #' Instance of \code{\link{dimRedMethod}} for Local Ordinal Embedding. ## #' ## #' For details see \code{\link[loe]{LOE}} ## #' ## #' @examples ## #' # for whatever reason the loe package has problems if I run this ## #' # with R CMD check, running it in the REPL works just fine ## #' if(requireNamespace("loe")) { ## #' dat <- loadDataSet("Iris")[sample(20)] ## #' loe <- LOE() ## #' emb <- loe@fun(dat, loe@stdpars) ## #' ## #' ## #' plot(emb@data@data) ## #' } ## #' @include dimRedResult-class.R ## #' @include dimRedMethod-class.R ## #' @export ## LOE <- setClass( ## "LOE", ## contains = "dimRedMethod", ## prototype = list( ## stdpars = list(d = stats::dist, knn = 50, ndim = 2), ## fun = function (data, pars, ## keep.org.data = TRUE) { ## chckpkg("loe") ## meta <- data@meta ## orgdata <- if (keep.org.data) data@data else NULL ## indata <- data@data ## data.adj <- loe:::make.kNNG(as.matrix(pars$d(indata)), k = pars$knn) ## outdata <- loe::LOE(data.adj, p = pars$ndim, method = "MM")$X ## colnames(outdata) <- paste0("LOE", 1:ncol(outdata)) ## return(new( ## "dimRedResult", ## data = new("dimRedData", ## data = outdata, ## meta = meta), ## org.data = orgdata, ## has.org.data = keep.org.data, ## method = "loe", ## pars = pars ## )) ## }) ## ) dimRed/R/dataSets.R0000644000176200001440000001442314257367661013577 0ustar liggesusers#' Example Data Sets for dimensionality reduction #' #' A compilation of standard data sets that are often being used to #' showcase dimensionality reduction techniques. #' #' The argument \code{name} should be one of #' \code{dataSetList()}. Partial matching is possible, see #' \code{\link{match.arg}}. Generated data sets contain the internal #' coordinates of the manifold in the \code{meta} slot. Call #' \code{dataSetList()} to see what data sets are available. #' #' #' #' @param name A character vector that specifies the name of the data #' set. #' @param n In generated data sets the number of points to be #' generated, else ignored. #' @param sigma In generated data sets the standard deviation of the #' noise added, else ignored. #' @return \code{loadDataSet} an object of class #' \code{\link{dimRedData}}. \code{dataSetList()} return a #' character string with the implemented data sets #' #' @examples #' ## a list of available data sets: #' dataSetList() #' #' ## Load a data set: #' swissRoll <- loadDataSet("Swiss Roll") #' \donttest{ #' if(requireNamespace("scatterplot3d", quietly = TRUE)) #' plot(swissRoll, type = "3vars") #' } #' #' ## Load Iris data set, partial matching: #' loadDataSet("I") #' #' @name dataSets NULL #' @include dimRedData-class.R #' @rdname dataSets #' @export loadDataSet <- function (name = dataSetList(), n = 2000, sigma = 0.05) { name <- match.arg(name) switch( name, "Swiss Roll" = swissRoll(n, sigma), "Broken Swiss Roll" = brokenSwissRoll(n, sigma), "Helix" = helix(n, sigma), "Twin Peaks" = twinPeaks(n, sigma), "Sphere" = sphere(n, sigma), "FishBowl" = fishbowl(n, sigma), "Ball" = ball(n, sigma), "3D S Curve" = sCurve(n, sigma), "variable Noise Helix" = noisyHelix(n, sigma), "Cube" = cube(n, sigma), "Iris" = irisdata() ) } #' @rdname dataSets #' @export dataSetList <- function () { return(c( "Swiss Roll", "Broken Swiss Roll", "Helix", "Twin Peaks", "Sphere", "Ball", "FishBowl", "3D S Curve", "variable Noise Helix", "Iris", "Cube" )) } irisdata <- function() { dd <- as.matrix(datasets::iris[, 1:4]) new("dimRedData", data = dd, meta = datasets::iris[, 5, drop = FALSE]) } swissRoll <- function (n = 2000, sigma = 0.05) { x <- stats::runif(n, 1.5 * pi, 4.5 * pi) y <- stats::runif(n, 0, 30) new("dimRedData", data = swissRollMapping(x, y) + stats::rnorm(3 * n, sd = sigma), meta = data.frame(x = x, y = y)) } brokenSwissRoll <- function (n = 2000, sigma = 0.05) { x <- c( stats::runif(floor(n / 2), 1.5 * pi, 2.7 * pi), stats::runif(ceiling(n / 2), 3.3 * pi, 4.5 * pi) ) y <- stats::runif(n, 0, 30) new("dimRedData", data = swissRollMapping(x, y) + stats::rnorm(3 * n, sd = sigma), meta = data.frame(x = x, y = y)) } swissRollMapping <- function (x, y) { cbind(x = x * cos(x), y = y, z = x * sin(x)) } helix <- function (n = 2000, sigma = 0.05) { t <- stats::runif(n, 0, 2 * pi) new("dimRedData", data = helixMapping(t) + stats::rnorm(3 * n, sd = sigma), meta = data.frame(t = t)) } helixMapping <- function (x) { cbind(x = (2 + cos(8 * x)) * cos(x), y = (2 + cos(8 * x)) * sin(x), z = (sin(8 * x))) } twinPeaks <- function (n = 2000, sigma = 0.05) { x <- stats::runif(n, -1, 1) y <- stats::runif(n, -1, 1) new("dimRedData", data = twinPeaksMapping(x, y) + stats::rnorm(3 * n, sd = sigma), meta = data.frame(x = x, y = y)) } twinPeaksMapping <- function (x, y) { cbind(x = x, y = y, z = sin(pi * x) * tanh(3 * y)) } sphere <- function (n = 2000, sigma = 0.05) { phi <- stats::runif(n, 0, 2 * pi) psi <- acos(stats::runif(n, -1, 1)) new("dimRedData", data = sphereMapping(phi, psi) + stats::rnorm(3 * n, sd = sigma), meta = data.frame(phi = phi, psi = psi)) } fishbowl <- function (n = 2000, sigma = 0.05) { phi <- stats::runif(n, 0, 2 * pi) psi <- acos(stats::runif(n, -1, 0.8)) new("dimRedData", data = sphereMapping(phi, psi) + stats::rnorm(3 * n, sd = sigma), meta = data.frame(psi = psi)) } sphereMapping <- function (phi, psi) { cbind(x = cos(phi) * sin(psi), y = sin(phi) * sin(psi), z = cos(psi)) } ball <- function (n = 2000, sigma = 0.05) { phi <- stats::runif(n, 0, 2 * pi) psi <- acos(stats::runif(n, -1, 1)) ## make it uniformly distributed inside the sphere r <- stats::runif(n) ^ (1 / 3) new("dimRedData", data = ballMapping(phi, psi, r) + stats::rnorm(3 * n, sd = sigma), meta = data.frame(phi = phi, psi = psi, r = r)) } ballMapping <- function (phi, psi, r) { cbind(x = r * cos(phi) * sin(psi), y = r * sin(phi) * sin(psi), z = r * cos(psi)) } sCurve <- function (n = 2000, sigma = 0.05) { t <- stats::runif(n, -1.5 * pi, 1.5 * pi) y <- stats::runif(n, 0, 2) new("dimRedData", data = sCurveMapping(t, y) + stats::rnorm(3 * n, sd = sigma), meta = data.frame(x = t, y = y)) } sCurveMapping <- function (t, y) { cbind(x = sin(t), y = y, z = sign(t) * (cos(t) - 1)) } noisyHelix <- function (n = 2000, sigma = 0.05) { t <- stats::runif(n, 0, 4 * pi) min_noise <- 0.1 max_noise <- 1.4 new("dimRedData", data = noisyHelixMapping(t, min_noise, max_noise) + stats::rnorm(3 * n, sd = sigma), meta = data.frame(t = t)) } noisyHelixMapping <- function(t, min_noise, max_noise) { make_noise <- function (t){ stats::rnorm(length(t), sd = t * max_noise / max(t) + min_noise) } cbind(x = 3 * cos(t) + make_noise(t), y = 3 * sin(t) + make_noise(t), z = 2 * t + make_noise(t)) } cube <- function(n = 2000, sigma = 0.05){ tmp <- cbind(x = stats::runif(n) + stats::rnorm(n, sd = sigma), y = stats::runif(n) + stats::rnorm(n, sd = sigma), z = stats::runif(n) + stats::rnorm(n, sd = sigma)) new("dimRedData", data = tmp, meta = tmp) } dimRed/R/drr.R0000644000176200001440000001462514257526622012614 0ustar liggesusers#' Dimensionality Reduction via Regression #' #' An S4 Class implementing Dimensionality Reduction via Regression (DRR). #' #' DRR is a non-linear extension of PCA that uses Kernel Ridge regression. #' #' @template dimRedMethodSlots #' #' @template dimRedMethodGeneralUsage #' #' @section Parameters: #' DRR can take the following parameters: #' \describe{ #' \item{ndim}{The number of dimensions} #' \item{lambda}{The regularization parameter for the ridge #' regression.} #' \item{kernel}{The kernel to use for KRR, defaults to #' \code{"rbfdot"}.} #' \item{kernel.pars}{A list with kernel parameters, elements depend #' on the kernel used, \code{"rbfdot"} uses \code{"sigma"}.} #' \item{pca}{logical, should an initial pca step be performed, #' defaults to \code{TRUE}.} #' \item{pca.center}{logical, should the data be centered before the #' pca step. Defaults to \code{TRUE}.} #' \item{pca.scale}{logical, should the data be scaled before the #' pca ste. Defaults to \code{FALSE}.} #' \item{fastcv}{logical, should \code{\link[CVST]{fastCV}} from the #' CVST package be used instead of normal cross-validation.} #' \item{fastcv.test}{If \code{fastcv = TRUE}, separate test data set for fastcv.} #' \item{cv.folds}{if \code{fastcv = FALSE}, specifies the number of #' folds for crossvalidation.} #' \item{fastkrr.nblocks}{integer, higher values sacrifice numerical #' accuracy for speed and less memory, see below for details.} #' \item{verbose}{logical, should the cross-validation results be #' printed out.} #' } #' #' @section Implementation: #' Wraps around \code{\link[DRR]{drr}}, see there for details. DRR is #' a non-linear extension of principal components analysis using Kernel #' Ridge Regression (KRR, details see \code{\link[CVST]{constructKRRLearner}} #' and \code{\link[DRR]{constructFastKRRLearner}}). Non-linear #' regression is used to explain more variance than PCA. DRR provides #' an out-of-sample extension and a backward projection. #' #' The most expensive computations are matrix inversions therefore the #' implementation profits a lot from a multithreaded BLAS library. #' The best parameters for each KRR are determined by cross-validaton #' over all parameter combinations of \code{lambda} and #' \code{kernel.pars}, using less parameter values will speed up #' computation time. Calculation of KRR can be accelerated by #' increasing \code{fastkrr.nblocks}, it should be smaller than #' n^{1/3} up to sacrificing some accuracy, for details see #' \code{\link[DRR]{constructFastKRRLearner}}. Another way to speed up #' is to use \code{pars$fastcv = TRUE} which might provide a more #' efficient way to search the parameter space but may also miss the #' global maximum, I have not ran tests on the accuracy of this method. #' #' #' #' @references #' Laparra, V., Malo, J., Camps-Valls, G., #' 2015. Dimensionality Reduction via Regression in Hyperspectral #' Imagery. IEEE Journal of Selected Topics in Signal Processing #' 9, 1026-1036. doi:10.1109/JSTSP.2015.2417833 #' #' @examples #' \dontrun{ #' if(requireNamespace(c("kernlab", "DRR"), quietly = TRUE)) { #' #' dat <- loadDataSet("variable Noise Helix", n = 200)[sample(200)] #' #' emb <- embed(dat, "DRR", ndim = 3) #' #' plot(dat, type = "3vars") #' plot(emb, type = "3vars") #' #' # We even have function to reconstruct, also working for only the first few dimensions #' rec <- inverse(emb, getData(getDimRedData(emb))[, 1, drop = FALSE]) #' plot(rec, type = "3vars") #' } #' #' } #' #' @include dimRedResult-class.R #' @include dimRedMethod-class.R #' @import DRR #' @family dimensionality reduction methods #' @export DRR #' @exportClass DRR DRR <- setClass( "DRR", contains = "dimRedMethod", prototype = list( stdpars = list(ndim = 2, lambda = c(0, 10 ^ (-3:2)), kernel = "rbfdot", kernel.pars = list(sigma = 10 ^ (-3:4)), pca = TRUE, pca.center = TRUE, pca.scale = FALSE, fastcv = FALSE, cv.folds = 5, fastcv.test = NULL, fastkrr.nblocks = 4, verbose = TRUE), fun = function (data, pars, keep.org.data = TRUE) { chckpkg("DRR") chckpkg("kernlab") meta <- data@meta orgdata <- if (keep.org.data) data@data else NULL indata <- data@data res <- do.call(DRR::drr, c(list(X = indata), pars)) outdata <- res$fitted.data colnames(outdata) <- paste0("DRR", 1:ncol(outdata)) appl <- function(x){ appl.meta <- if (inherits(x, "dimRedData")) x@meta else data.frame() proj <- if (inherits(x, "dimRedData")) x@data else x if (ncol(proj) != ncol(data@data)) stop("x must have the same number of dimensions ", "as the original data") appl.out <- new("dimRedData", data = res$apply(proj), meta = appl.meta) dimnames(appl.out@data) <- list( rownames(x), paste0("DRR", seq_len(ncol(appl.out@data))) ) return(appl.out) } inv <- function(x) { appl.meta <- if (inherits(x, "dimRedData")) x@meta else data.frame() proj <- if (inherits(x, "dimRedData")) x@data else x if (ncol(proj) > ncol(data@data)) stop("x must have less or equal number of dimensions ", "as the original data") inv.out <- new("dimRedData", data = res$inverse(proj), meta = appl.meta) dimnames(inv.out@data) <- list(rownames(proj), colnames(data@data)) return(inv.out) } return( new("dimRedResult", data = new("dimRedData", data = outdata, meta = meta), org.data = orgdata, apply = appl, inverse = inv, has.org.data = keep.org.data, has.apply = TRUE, has.inverse = TRUE, method = "drr", pars = pars ) ) }, requires = c("DRR", "kernlab")) ) dimRed/R/pca.R0000644000176200001440000001023414257525743012563 0ustar liggesusers#' Principal Component Analysis #' #' S4 Class implementing PCA. #' #' PCA transforms the data in orthogonal components so that the first #' axis accounts for the larges variance in the data, all the #' following axes account for the highest variance under the #' constraint that they are orthogonal to the preceding axes. PCA is #' sensitive to the scaling of the variables. PCA is by far the #' fastest and simples method of dimensionality reduction and should #' probably always be applied as a baseline if other methods are tested. #' #' @template dimRedMethodSlots #' #' @template dimRedMethodGeneralUsage #' #' @section Parameters: #' PCA can take the following parameters: #' \describe{ #' \item{ndim}{The number of output dimensions.} #' \item{center}{logical, should the data be centered, defaults to \code{TRUE}.} #' \item{scale.}{logical, should the data be scaled, defaults to \code{FALSE}.} #' } #' #' @section Implementation: #' #' Wraps around \code{\link{prcomp}}. Because PCA can be reduced to a #' simple rotation, forward and backward projection functions are #' supplied. #' #' @references #' #' Pearson, K., 1901. On lines and planes of closest fit to systems of points in #' space. Philosophical Magazine 2, 559-572. #' #' @examples #' dat <- loadDataSet("Iris") #' emb <- embed(dat, "PCA") #' #' plot(emb, type = "2vars") #' if(requireNamespace("scatterplot3d", quietly = TRUE)) #' plot(inverse(emb, getDimRedData(emb)), type = "3vars") #' #' @include dimRedResult-class.R #' @include dimRedMethod-class.R #' @family dimensionality reduction methods #' @export PCA #' @exportClass PCA PCA <- setClass( "PCA", contains = "dimRedMethod", prototype = list( stdpars = list(ndim = 2, center = TRUE, scale. = FALSE), fun = function (data, pars, keep.org.data = TRUE) { ndim <- pars$ndim pars$ndim <- NULL meta <- data@meta orgdata <- if (keep.org.data) data@data else NULL data <- data@data res <- do.call( prcomp, c(list(x = data), pars) ) # evaluate results here for functions data <- res$x[, seq_len(ndim), drop = FALSE] ce <- res$center sc <- res$scale rot <- res$rotation[, seq_len(ndim)] rerot <- t(rot) appl <- function(x) { appl.meta <- if (inherits(x, "dimRedData")) x@meta else data.frame() proj <- if (inherits(x, "dimRedData")) x@data else x if (ncol(proj) != ncol(orgdata)) stop("x must have the same number of dimensions ", "as the original data") if (ce[1] != FALSE) proj <- t(apply(proj, 1, function(x) x - ce)) if (sc[1] != FALSE) proj <- t(apply(proj, 1, function(x) x / sc)) proj <- proj %*% rot proj <- new("dimRedData", data = proj, meta = appl.meta) return(proj) } inv <- function(x) { appl.meta <- if (inherits(x, "dimRedData")) x@meta else data.frame() proj <- if (inherits(x, "dimRedData")) x@data else x if (ncol(proj) > ncol(data)) stop("x must have less or equal number of dimensions ", "as the original data") d <- ncol(proj) reproj <- proj %*% rerot[seq_len(d), ] if (sc[1] != FALSE) reproj <- t(apply(reproj, 1, function(x) x * sc)) if (ce[1] != FALSE) reproj <- t(apply(reproj, 1, function(x) x + ce)) reproj <- new("dimRedData", data = reproj, meta = appl.meta) return(reproj) } res <- new( "dimRedResult", data = new("dimRedData", data = data, meta = meta), org.data = orgdata, apply = appl, inverse = inv, has.org.data = keep.org.data, has.apply = TRUE, has.inverse = TRUE, method = "PCA", pars = pars ) return(res) }) ) dimRed/R/graph_embed.R0000644000176200001440000002231514262545264014254 0ustar liggesusers#' Graph Embedding via the Kamada Kawai Algorithm #' #' An S4 Class implementing the Kamada Kawai Algorithm for graph embedding. #' #' Graph embedding algorithms se the data as a graph. Between the #' nodes of the graph exist attracting and repelling forces which can #' be modeled as electrical fields or springs connecting the #' nodes. The graph is then forced into a lower dimensional #' representation that tries to represent the forces betweent he nodes #' accurately by minimizing the total energy of the attracting and #' repelling forces. #' #' @template dimRedMethodSlots #' #' @template dimRedMethodGeneralUsage #' #' @section Parameters: #' KamadaKawai can take the following parameters: #' \describe{ #' \item{ndim}{The number of dimensions, defaults to 2. Can only be 2 or 3} #' \item{knn}{Reduce the graph to keep only the neares neighbors. Defaults to 100.} #' \item{d}{The distance function to determine the weights of the graph edges. Defaults to euclidean distances.} #' } #' #' @section Implementation: #' Wraps around \code{\link[igraph]{layout_with_kk}}. The parameters #' maxiter, epsilon and kkconst are set to the default values and #' cannot be set, this may change in a future release. The DimRed #' Package adds an extra sparsity parameter by constructing a knn #' graph which also may improve visualization quality. #' #' @references #' #' Kamada, T., Kawai, S., 1989. An algorithm for drawing general undirected #' graphs. Information Processing Letters 31, 7-15. #' https://doi.org/10.1016/0020-0190(89)90102-6 #' #' @examples #' if(requireNamespace(c("igraph", "coRanking"), quietly = TRUE)) { #' #' dat <- loadDataSet("Swiss Roll", n = 200) #' emb <- embed(dat, "KamadaKawai") #' plot(emb, type = "2vars") #' #' } #' @include dimRedResult-class.R #' @include dimRedMethod-class.R #' @family dimensionality reduction methods #' @export KamadaKawai #' @exportClass KamadaKawai KamadaKawai <- setClass( "KamadaKawai", contains = "dimRedMethod", prototype = list( stdpars = list(ndim = 2, knn = 100, d = stats::dist), fun = function (data, pars, keep.org.data = TRUE) { chckpkg("igraph") meta <- data@meta orgdata <- if (keep.org.data) data@data else NULL indata <- data@data outdata <- em_graph_layout( indata, graph_em_method = igraph::layout_with_kk, knn = pars$knn, d = pars$d, ndim = pars$ndim, weight.trans = I #pars$weight.trans ) colnames(outdata) <- paste0("KK", 1:ncol(outdata)) return(new( "dimRedResult", data = new("dimRedData", data = outdata, meta = meta), org.data = orgdata, has.org.data = keep.org.data, method = "graph_kk", pars = pars )) }, requires = c("igraph", "coRanking")) ) #' Distributed Recursive Graph Layout #' #' An S4 Class implementing Distributed recursive Graph Layout. #' #' DrL uses a complex algorithm to avoid local minima in the graph #' embedding which uses several steps. #' #' @template dimRedMethodSlots #' #' @template dimRedMethodGeneralUsage #' #' @section Parameters: #' DrL can take the following parameters: #' \describe{ #' \item{ndim}{The number of dimensions, defaults to 2. Can only be 2 or 3} #' \item{knn}{Reduce the graph to keep only the neares neighbors. Defaults to 100.} #' \item{d}{The distance function to determine the weights of the graph edges. Defaults to euclidean distances.} #' } #' #' @section Implementation: #' Wraps around \code{\link[igraph]{layout_with_drl}}. The parameters #' maxiter, epsilon and kkconst are set to the default values and #' cannot be set, this may change in a future release. The DimRed #' Package adds an extra sparsity parameter by constructing a knn #' graph which also may improve visualization quality. #' #' @references #' #' Martin, S., Brown, W.M., Wylie, B.N., 2007. Dr.l: Distributed Recursive #' (graph) Layout (No. dRl; 002182MLTPL00). Sandia National Laboratories. #' #' @examples #' \dontrun{ #' if(requireNamespace(c("igraph", "coRanking"), quietly = TRUE)) { #' #' dat <- loadDataSet("Swiss Roll", n = 200) #' emb <- embed(dat, "DrL") #' plot(emb, type = "2vars") #' } #' #' } #' #' @include dimRedResult-class.R #' @include dimRedMethod-class.R #' @family dimensionality reduction methods #' @export DrL #' @exportClass DrL DrL <- setClass( "DrL", contains = "dimRedMethod", prototype = list( stdpars = list(ndim = 2, knn = 100, d = stats::dist), fun = function (data, pars, keep.org.data = TRUE) { chckpkg("igraph") meta <- data@meta orgdata <- if (keep.org.data) data@data else NULL indata <- data@data outdata <- em_graph_layout( indata, graph_em_method = igraph::layout_with_drl, knn = pars$knn, d = pars$d, ndim = pars$ndim, weight.trans = I #pars$weight.trans ) colnames(outdata) <- paste0("DrL", 1:ncol(outdata)) return(new( "dimRedResult", data = new("dimRedData", data = outdata, meta = meta), org.data = orgdata, has.org.data = keep.org.data, method = "graph_drl", pars = pars )) }, requires = c("igraph", "coRanking") ) ) #' Fruchterman Reingold Graph Layout #' #' An S4 Class implementing the Fruchterman Reingold Graph Layout #' algorithm. #' #' @template dimRedMethodSlots #' #' @template dimRedMethodGeneralUsage #' #' @section Parameters: #' \describe{ #' \item{ndim}{The number of dimensions, defaults to 2. Can only be 2 or 3} #' \item{knn}{Reduce the graph to keep only the neares neighbors. Defaults to 100.} #' \item{d}{The distance function to determine the weights of the graph edges. Defaults to euclidean distances.} #' } #' #' @section Implementation: #' Wraps around \code{\link[igraph]{layout_with_fr}}, see there for #' details. The Fruchterman Reingold algorithm puts the data into #' a circle and puts connected points close to each other. #' #' @references #' #' Fruchterman, T.M.J., Reingold, E.M., 1991. Graph drawing by force-directed #' placement. Softw: Pract. Exper. 21, 1129-1164. #' https://doi.org/10.1002/spe.4380211102 #' #' @examples #' if(requireNamespace(c("igraph", "coRanking"), quietly = TRUE)) { #' #' dat <- loadDataSet("Swiss Roll", n = 100) #' emb <- embed(dat, "FruchtermanReingold") #' plot(emb, type = "2vars") #' #' } #' #' @include dimRedResult-class.R #' @include dimRedMethod-class.R #' @family dimensionality reduction methods #' @export FruchtermanReingold #' @exportClass FruchtermanReingold FruchtermanReingold <- setClass( "FruchtermanReingold", contains = "dimRedMethod", prototype = list( stdpars = list(ndim = 2, knn = 100, d = stats::dist), fun = function (data, pars, keep.org.data = TRUE) { chckpkg("igraph") meta <- data@meta orgdata <- if (keep.org.data) data@data else NULL indata <- data@data outdata <- em_graph_layout( indata, graph_em_method = igraph::layout_with_fr, knn = pars$knn, d = pars$d, ndim = pars$ndim, weight.trans = I #pars$weight.trans ) colnames(outdata) <- paste0("FR", 1:ncol(outdata)) return(new( "dimRedResult", data = new("dimRedData", data = outdata, meta = meta), org.data = orgdata, has.org.data = keep.org.data, method = "graph_fr", pars = pars )) }, requires = c("igraph", "coRanking") ) ) em_graph_layout <- function(data, graph_em_method, knn = 50, d = stats::dist, ndim = 2, weight.trans = I){ chckpkg("igraph") data.dist <- as.matrix(d(data)) data.graph <- construct_knn_graph(data.dist, knn) embed_graph(data.graph, graph_em_method, ndim = ndim) } embed_graph <- function(graph, f, weight.trans = I, ndim = 2){ f(graph, weights = weight.trans(igraph::E(graph)$weight), dim = ndim) } construct_knn_graph <- function (data.dist, knn) { chckpkg("igraph") chckpkg("coRanking") data.graph <- igraph::graph_from_adjacency_matrix( adjmatrix = data.dist, mode = "undirected", weighted = TRUE ) if (is.infinite(knn) || is.na(knn)) return(data.graph) ## else: remove all unnecessary edges data.rankm <- coRanking::rankmatrix(data.dist, input = "dist") data.rankm.ind <- data.rankm <= knn + 1 inds <- which( !(data.rankm.ind | t(data.rankm.ind)), arr.ind = TRUE ) data.graph[ from = inds[, 1], to = inds[, 2] ] <- FALSE return(data.graph) } dimRed/R/lle.R0000644000176200001440000000467514256645303012602 0ustar liggesusers## #' Locally Linear Embedding ## #' ## #' An S4 Class implementing Locally Linear Embedding (LLE) ## #' ## #' LLE approximates the points in the manifold by linear combination ## #' of its neighbors. These linear combinations are the same inside the ## #' manifold and in highdimensional space. ## #' ## #' @template dimRedMethodSlots ## #' ## #' @template dimRedMethodGeneralUsage ## #' ## #' @section Parameters: ## #' LLE can take the following parameters: ## #' \describe{ ## #' \item{knn}{the number of neighbors for the knn graph., defaults to 50.} ## #' \item{ndim}{the number of embedding dimensions, defaults to 2.} ## #' } ## #' ## #' @section Implementation: ## #' Wraps around \code{\link[lle]{lle}}, only ## #' exposes the parameters \code{k} and \code{m}. ## #' ## #' @references ## #' ## #' Roweis, S.T., Saul, L.K., 2000. Nonlinear Dimensionality Reduction ## #' by Locally Linear Embedding. Science 290, ## #' 2323-2326. doi:10.1126/science.290.5500.2323 ## #' ## #' @examples ## #' \dontrun{ ## #' if(requireNamespace("lle")) { ## #' ## #' dat <- loadDataSet("3D S Curve", n = 500) ## #' emb <- embed(dat, "LLE", knn = 45) ## #' plot(emb, type = "2vars") ## #' ## #' } ## #' } ## #' @include dimRedResult-class.R ## #' @include dimRedMethod-class.R ## #' @family dimensionality reduction methods ## #' @export LLE ## #' @exportClass LLE ## LLE <- setClass( ## "LLE", ## contains = "dimRedMethod", ## prototype = list( ## stdpars = list(knn = 50, ndim = 2), ## fun = function (data, pars, ## keep.org.data = TRUE) { ## chckpkg("lle") ## meta <- data@meta ## orgdata <- if (keep.org.data) data@data else NULL ## indata <- data@data ## outdata <- lle::lle(indata, ## k = pars$knn, ## m = pars$ndim)$Y ## if (is.null(dim(outdata))) { ## dim(outdata) <- c(length(outdata), 1) ## } ## colnames(outdata) <- paste0("LLE", 1:ncol(outdata)) ## return(new( ## "dimRedResult", ## data = new("dimRedData", ## data = outdata, ## meta = meta), ## org.data = orgdata, ## has.org.data = keep.org.data, ## method = "lle", ## pars = pars ## )) ## }, ## requires = c("lle") ## ) ## ) dimRed/R/dimRedData-class.R0000644000176200001440000001373013464507204015114 0ustar liggesusers#' @include misc.R NULL #' Class "dimRedData" #' #' A class to hold data for dimensionality reduction and methods. #' #' The class hast two slots, \code{data} and \code{meta}. The #' \code{data} slot contains a \code{numeric matrix} with variables in #' columns and observations in rows. The \code{meta} slot may contain #' a \code{data.frame} with additional information. Both slots need to #' have the same number of rows or the \code{meta} slot needs to #' contain an empty \code{data.frame}. #' #' See examples for easy conversion from and to \code{data.frame}. #' #' For plotting functions see \code{\link{plot.dimRedData}}. #' #' @slot data of class \code{matrix}, holds the data, observations in #' rows, variables in columns #' @slot meta of class \code{data.frame}, holds meta data such as #' classes, internal manifold coordinates, or simply additional #' data of the data set. Must have the same number of rows as the #' \code{data} slot or be an empty data frame. #' #' #' @examples #' ## Load an example data set: #' s3d <- loadDataSet("3D S Curve") #' #' ## Create using a constructor: #' #' ### without meta information: #' dimRedData(iris[, 1:4]) #' #' ### with meta information: #' dimRedData(iris[, 1:4], iris[, 5]) #' #' ### using slot names: #' dimRedData(data = iris[, 1:4], meta = iris[, 5]) #' #' ## Convert to a dimRedData objects: #' Iris <- as(iris[, 1:4], "dimRedData") #' #' ## Convert to data.frame: #' head(as(s3d, "data.frame")) #' head(as.data.frame(s3d)) #' head(as.data.frame(as(iris[, 1:4], "dimRedData"))) #' #' ## Extract slots: #' head(getData(s3d)) #' head(getMeta(s3d)) #' #' ## Get the number of observations: #' nrow(s3d) #' #' ## Subset: #' s3d[1:5, ] #' #' @family dimRedData #' @import methods #' @export dimRedData #' @exportClass dimRedData dimRedData <- setClass( "dimRedData", slots = c(data = "matrix", meta = "data.frame"), prototype = prototype(data = matrix(numeric(0), 0, 0), meta = data.frame()), validity = function (object) { retval <- NULL if (!is.matrix(object@data)) { retval <- c( retval, c("data must be a matrix with ", "observations in rows and dimensions in columns") ) } if (!is.numeric(object@data)) { retval <- c( retval, c("data must be numeric") ) } if ((nrow(object@meta) != 0) && (nrow(object@meta) != nrow(object@data))){ retval <- c( retval, c("data and meta must have the same numbers of rows") ) } return(if (is.null(retval)) TRUE else retval) } ) setMethod("initialize", signature = c("dimRedData"), function (.Object, data = matrix(numeric(0), 0, 0), meta = data.frame()) { data <- as.matrix(data) meta <- as.data.frame(meta) .Object <- callNextMethod() return(.Object) }) setAs(from = "ANY", to = "dimRedData", def = function(from) new("dimRedData", data = as.matrix(from))) setAs(from = "dimRedData", to = "data.frame", def = function(from) as.data.frame(from)) #' @param meta.prefix Prefix for the columns of the meta data names. #' @param data.prefix Prefix for the columns of the variable names. #' #' @family dimRedData #' @describeIn dimRedData convert to data.frame #' @export setMethod(f = "as.data.frame", signature = c("dimRedData"), definition = function(x, meta.prefix = "meta.", data.prefix = "") { tmp <- list() if (nrow(x@meta) > 0){ tmp$meta <- as.data.frame(x@meta, stringsAsFactors = FALSE) names(tmp$meta) <- paste0(meta.prefix, colnames(x@meta)) } tmp$data <- as.data.frame(x@data, stringsAsFactors = FALSE) names(tmp$data) <- paste0(data.prefix, colnames(x@data)) names(tmp) <- NULL data.frame(tmp, stringsAsFactors = FALSE) }) #' @param data Will be coerced into a \code{\link{data.frame}} with #' \code{\link{as.data.frame}} #' #' @examples #' ## create a dimRedData object using a formula #' as.dimRedData(Species ~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width, #' iris)[1:5] #' #' @include misc.R #' @family dimRedData #' @describeIn as.dimRedData Convert a \code{data.frame} to a dimRedData #' object using a formula #' @export setMethod(f = "as.dimRedData", signature = c("formula"), definition = function(formula, data) { data <- as.data.frame(data) meta <- stats::model.frame(lhs(formula), data) data <- stats::model.matrix(rhs(formula), data) return(new("dimRedData", data = data, meta = meta)) }) #' @param object Of class dimRedData. #' @describeIn dimRedData Get the data slot. #' @export setMethod("getData", "dimRedData", function(object) object@data) #' @describeIn dimRedData Get the meta slot. #' @export setMethod("getMeta", "dimRedData", function(object) object@meta) #' @param x Of class dimRedData #' @describeIn dimRedData Get the number of observations. #' @export setMethod("nrow", "dimRedData", function(x) nrow(x@data)) #' @param i a valid index for subsetting rows. #' @examples #' ## Shuffle data: #' s3 <- s3d[nrow(s3d)] #' #' @describeIn dimRedData Subset rows. #' @export setMethod("[", signature(x = "dimRedData", i = "ANY"), function(x, i) { x@data <- x@data[i, , drop = FALSE] if (nrow(x@meta) != 0) x@meta <- x@meta[i, , drop = FALSE] # validObject returns a string with the description of what is wrong or # TRUE, so the following lines have to be as they are! vv <- validObject(x) if (vv == TRUE) return(x) else stop("cannot subset dimRedData object: \n", paste(vv, collapse = "\n")) }) #' @describeIn dimRedData Extract the number of Variables from the data. #' #' @examples #' ## Get the number of variables: #' ndims(s3d) #' #' @export setMethod("ndims", "dimRedData", function(object) ncol(object@data)) dimRed/R/quality.R0000644000176200001440000004772614257373431013523 0ustar liggesusers#' @include dimRedResult-class.R #' @include dimRedData-class.R #' @export setGeneric("quality", function (.data, ...) standardGeneric("quality"), valueClass = "numeric") #' Quality Criteria for dimensionality reduction. #' #' A collection of functions to compute quality measures on #' \code{\link{dimRedResult}} objects. #' #' @section Implemented methods: #' #' Method must be one of \code{"\link{Q_local}", "\link{Q_global}", #' "\link{mean_R_NX}", "\link{total_correlation}", #' "\link{cophenetic_correlation}", "\link{distance_correlation}", #' "\link{reconstruction_rmse}"} #' #' @section Rank based criteria: #' #' \code{Q_local}, \code{Q_global}, and \code{mean_R_NX} are #' quality criteria based on the Co-ranking matrix. \code{Q_local} #' and \code{Q_global} determine the local/global quality of the #' embedding, while \code{mean_R_NX} determines the quality of the #' overall embedding. They are parameter free and return a single #' number. The object must include the original data. The number #' returns is in the range [0, 1], higher values mean a better #' local/global embedding. #' #' @section Correlation based criteria: #' #' \code{total_correlation} calculates the sum of the mean squared #' correlations of the original axes with the axes in reduced #' dimensions, because some methods do not care about correlations #' with axes, there is an option to rotate data in reduced space to #' maximize this criterium. The number may be greater than one if more #' dimensions are summed up. #' #' \code{cophenetic_correlation} calculate the correlation between the #' lower triangles of distance matrices, the correlation and distance #' methods may be specified. The result is in range [-1, 1]. #' #' \code{distance_correlation} measures the independes of samples by #' calculating the correlation of distances. For details see #' \code{\link[energy]{dcor}}. #' #' @section Reconstruction error: #' #' \code{reconstruction_rmse} calculates the root mean squared error #' of the reconstrucion. \code{object} requires an inverse function. #' #' #' @references #' #' Lueks, W., Mokbel, B., Biehl, M., Hammer, B., 2011. How #' to Evaluate Dimensionality Reduction? - Improving the #' Co-ranking Matrix. arXiv:1110.3917 [cs]. #' #' Szekely, G.J., Rizzo, M.L., Bakirov, N.K., 2007. Measuring and #' testing dependence by correlation of distances. Ann. Statist. 35, #' 2769-2794. doi:10.1214/009053607000000505 #' #' Lee, J.A., Peluffo-Ordonez, D.H., Verleysen, M., 2015. Multi-scale #' similarities in stochastic neighbour embedding: Reducing #' dimensionality while preserving both local and global #' structure. Neurocomputing, 169, #' 246-261. doi:10.1016/j.neucom.2014.12.095 #' #' #' #' @param .data object of class \code{dimRedResult} #' @param .method character vector naming one of the methods #' @param .mute what output from the embedding method should be muted. #' @param ... the pameters, internally passed as a list to the #' quality method as \code{pars = list(...)} #' @return a number #' #' @examples #' \dontrun{ #' embed_methods <- dimRedMethodList() #' quality_methods <- dimRedQualityList() #' scurve <- loadDataSet("Iris") #' #' quality_results <- matrix(NA, length(embed_methods), length(quality_methods), #' dimnames = list(embed_methods, quality_methods)) #' embedded_data <- list() #' #' for (e in embed_methods) { #' message("embedding: ", e) #' embedded_data[[e]] <- embed(scurve, e, .mute = c("message", "output")) #' for (q in quality_methods) { #' message(" quality: ", q) #' quality_results[e, q] <- tryCatch( #' quality(embedded_data[[e]], q), #' error = function (e) NA #' ) #' } #' } #' #' print(quality_results) #' } #' @author Guido Kraemer #' @aliases quality quality.dimRedResult #' @family Quality scores for dimensionality reduction #' @describeIn quality Calculate a quality index from a dimRedResult object. #' @export setMethod( "quality", "dimRedResult", function (.data, .method = dimRedQualityList(), .mute = character(0), # c("output", "message"), ...) { method <- match.arg(.method) methodFunction <- getQualityFunction(method) args <- c(list(object = .data), list(...)) devnull <- if (Sys.info()["sysname"] != "Windows") "/dev/null" else "NUL" if ("message" %in% .mute){ devnull1 <- file(devnull, "wt") sink(devnull1, type = "message") on.exit({ sink(file = NULL, type = "message") close(devnull1) }, add = TRUE) } if ("output" %in% .mute) { devnull2 <- file(devnull, "wt") sink(devnull2, type = "output") on.exit({ sink() close(devnull2) }, add = TRUE) } do.call(methodFunction, args) } ) getQualityFunction <- function (method) { switch( method, Q_local = Q_local, Q_global = Q_global, mean_R_NX = mean_R_NX, AUC_lnK_R_NX = AUC_lnK_R_NX, total_correlation = total_correlation, cophenetic_correlation = cophenetic_correlation, distance_correlation = distance_correlation, reconstruction_rmse = reconstruction_rmse ) } #' @export setGeneric( "Q_local", function(object, ...) standardGeneric("Q_local"), valueClass = "numeric" ) #' Method Q_local #' #' Calculate the Q_local score to assess the quality of a dimensionality reduction. #' #' @param object of class dimRedResult. #' @param ndim use the first ndim columns of the embedded data for calculation. #' @family Quality scores for dimensionality reduction #' @aliases Q_local #' @export setMethod( "Q_local", "dimRedResult", function (object, ndim = getNDim(object)) { if (!object@has.org.data) stop("object requires original data") chckpkg("coRanking") Q <- coRanking::coranking(object@org.data, object@data@data[, seq_len(ndim), drop = FALSE]) nQ <- nrow(Q) N <- nQ + 1 Qnx <- diag(apply(apply(Q, 2, cumsum), 1, cumsum)) / seq_len(nQ) / N lcmc <- Qnx - seq_len(nQ) / nQ Kmax <- which.max(lcmc) Qlocal <- sum(Qnx[1:Kmax]) / Kmax return(as.vector(Qlocal)) } ) #' @export setGeneric( "Q_global", function(object, ...) standardGeneric("Q_global"), valueClass = "numeric" ) #' Method Q_global #' #' Calculate the Q_global score to assess the quality of a dimensionality reduction. #' #' @param object of class dimRedResult #' @family Quality scores for dimensionality reduction #' @aliases Q_global #' @export setMethod( "Q_global", "dimRedResult", function(object){ if (!object@has.org.data) stop("object requires original data") chckpkg("coRanking") Q <- coRanking::coranking(object@org.data, object@data@data) nQ <- nrow(Q) N <- nQ + 1 Qnx <- diag(apply(apply(Q, 2, cumsum), 1, cumsum)) / seq_len(nQ) / N lcmc <- Qnx - seq_len(nQ) / nQ Kmax <- which.max(lcmc) Qglobal <- sum(Qnx[(Kmax + 1):nQ]) / (N - Kmax) return(Qglobal) } ) #' @export setGeneric( "mean_R_NX", function(object, ...) standardGeneric("mean_R_NX"), valueClass = "numeric" ) #' Method mean_R_NX #' #' Calculate the mean_R_NX score to assess the quality of a dimensionality reduction. #' #' @param object of class dimRedResult #' @family Quality scores for dimensionality reduction #' @aliases mean_R_NX #' @export setMethod( "mean_R_NX", "dimRedResult", function(object) mean(R_NX(object)) ) #' @export setGeneric( "AUC_lnK_R_NX", function(object, ...) standardGeneric("AUC_lnK_R_NX"), valueClass = "numeric" ) #' Method AUC_lnK_R_NX #' #' Calculate the Area under the R_NX(ln K), used in Lee et. al. (2015). Note #' that despite the name, this does not weight the mean by the logarithm, but by #' 1/K. If explicit weighting by the logarithm is desired use \code{weight = #' "log"} or \code{weight = "log10"} #' #' The naming confusion originated from equation 17 in Lee et al (2015) and the #' name of this method may change in the future to avoid confusion. #' #' @references Lee, J.A., Peluffo-Ordonez, D.H., Verleysen, M., 2015. #' Multi-scale similarities in stochastic neighbour embedding: Reducing #' dimensionality while preserving both local and global structure. #' Neurocomputing 169, 246-261. https://doi.org/10.1016/j.neucom.2014.12.095 #' #' @param object of class dimRedResult #' @param weight the weight function used, one of \code{c("inv", "log", "log10")} #' @family Quality scores for dimensionality reduction #' @aliases AUC_lnK_R_NX #' @export setMethod( "AUC_lnK_R_NX", "dimRedResult", function(object, weight = "inv") { rnx <- R_NX(object) weight <- match.arg(weight, c("inv", "ln", "log", "log10")) switch( weight, inv = auc_ln_k_inv(rnx), log = auc_log_k(rnx), ln = auc_log_k(rnx), log10 = auc_log10_k(rnx), stop("wrong parameter for weight") ) } ) auc_ln_k_inv <- function(rnx) { Ks <- seq_along(rnx) return (sum(rnx / Ks) / sum(1 / Ks)) } auc_log_k <- function(rnx) { Ks <- seq_along(rnx) return (sum(rnx * log(Ks)) / sum(log(Ks))) } auc_log10_k <- function(rnx) { Ks <- seq_along(rnx) return (sum(rnx * log10(Ks)) / sum(log10(Ks))) } #' @export setGeneric( "total_correlation", function(object, ...) standardGeneric("total_correlation"), valueClass = "numeric" ) #' Method total_correlation #' #' Calculate the total correlation of the variables with the axes to #' assess the quality of a dimensionality reduction. #' #' @param object of class dimRedResult #' @param naxes the number of axes to use for optimization. #' @param cor_method the correlation method to use. #' @param is.rotated if FALSE the object is rotated. #' #' @family Quality scores for dimensionality reduction #' @aliases total_correlation #' @export setMethod( "total_correlation", "dimRedResult", function(object, naxes = ndims(object), cor_method = "pearson", is.rotated = FALSE){ if (!object@has.org.data) stop("object requires original data") if (length(naxes) != 1 || naxes < 1 || naxes > ncol(object@data@data)) stop("naxes must specify the numbers of axes to optimize for, ", "i.e. a single integer between 1 and ncol(object@data@data)") ## try to partially match cor_method: cor_methods <- c("pearson", "kendall", "spearman") cor_method <- cor_methods[pmatch(cor_method, cor_methods)] if (is.na(cor_method)) stop("cor_method must match one of ", "'pearson', 'kendall', or 'spearman', ", "at least partially.") if (!is.rotated) { rotated_result <- maximize_correlation( object, naxes, cor_method ) } else { rotated_result <- object } res <- 0 for (i in 1:naxes) res <- res + mean(correlate( rotated_result@data@data, rotated_result@org.data, cor_method )[i, ] ^ 2) return(res) } ) setGeneric("cophenetic_correlation", function(object, ...) standardGeneric("cophenetic_correlation"), valueClass = "numeric") #' Method cophenetic_correlation #' #' Calculate the correlation between the distance matrices in high and #' low dimensioal space. #' #' @param object of class dimRedResult #' @param d the distance function to use. #' @param cor_method The correlation method. #' @aliases cophenetic_correlation #' @family Quality scores for dimensionality reduction #' @export setMethod( "cophenetic_correlation", "dimRedResult", function(object, d = stats::dist, cor_method = "pearson"){ ## if (missing(d)) d <- stats::dist ## if (missing(cor_method)) cor_method <- "pearson" if (!object@has.org.data) stop("object requires original data") cor_methods <- c("pearson", "kendall", "spearman") cor_method <- cor_methods[pmatch(cor_method, cor_methods)] if (is.na(cor_method)) stop("cor_method must match one of ", "'pearson', 'kendall', or 'spearman', ", "at least partially.") d.org <- d(object@org.data) d.emb <- d(object@data@data) if (!inherits(d.org, "dist") || !inherits(d.emb, "dist")) stop("d must return a dist object") res <- correlate( d(object@org.data), d(object@data@data), cor_method ) return(res) } ) #' @export setGeneric( "distance_correlation", function(object) standardGeneric("distance_correlation"), valueClass = "numeric" ) #' Method distance_correlation #' #' Calculate the distance correlation between the distance matrices in #' high and low dimensioal space. #' #' @param object of class dimRedResult #' @aliases distance_correlation #' @family Quality scores for dimensionality reduction #' @export setMethod( "distance_correlation", "dimRedResult", function(object){ if (!object@has.org.data) stop("object requires original data") chckpkg("energy") energy::dcor(object@org.data, object@data@data) } ) #' @export setGeneric( "reconstruction_rmse", function(object) standardGeneric("reconstruction_rmse"), valueClass = "numeric" ) #' Method reconstruction_rmse #' #' Calculate the reconstruction root mean squared error a dimensionality reduction, the method must have an inverse mapping. #' #' @param object of class dimRedResult #' @aliases reconstruction_rmse #' @family Quality scores for dimensionality reduction #' @export setMethod( "reconstruction_rmse", "dimRedResult", function(object){ if (!object@has.org.data) stop("object requires original data") if (!object@has.inverse) stop("object requires an inverse function") recon <- object@inverse(object@data) rmse(recon@data, object@org.data) } ) #' @rdname quality #' @param filter filter methods by installed packages #' @export dimRedQualityList <- function (filter = FALSE) { quality_list <- character() if (!filter || requireNamespace("coRanking", quietly = TRUE)) quality_list <- c(quality_list, c("Q_local", "Q_global", "mean_R_NX", "AUC_lnK_R_NX")) if (!filter || requireNamespace("optimx", quietly = TRUE)) quality_list <- c(quality_list, "total_correlation") quality_list <- c(quality_list, "cophenetic_correlation") if (!filter || requireNamespace("energy", quietly = TRUE)) quality_list <- c(quality_list, "distance_correlation") quality_list <- c(quality_list, "reconstruction_rmse") return(quality_list) } #' @export setGeneric( "R_NX", function(object, ...) standardGeneric("R_NX"), valueClass = "numeric" ) #' Method R_NX #' #' Calculate the R_NX score from Lee et. al. (2013) which shows the neighborhood #' preservation for the Kth nearest neighbors, corrected for random point #' distributions and scaled to range [0, 1]. #' @param object of class dimRedResult #' @param ndim the number of dimensions to take from the embedded data. #' @family Quality scores for dimensionality reduction #' @aliases R_NX #' @export setMethod( "R_NX", "dimRedResult", function(object, ndim = getNDim(object)) { chckpkg("coRanking") if (!object@has.org.data) stop("object requires original data") Q <- coRanking::coranking(object@org.data, object@data@data[, seq_len(ndim), drop = FALSE]) nQ <- nrow(Q) N <- nQ + 1 Qnx <- diag(apply(apply(Q, 2, cumsum), 1, cumsum)) / seq_len(nQ) / N Rnx <- ((N - 1) * Qnx - seq_len(nQ)) / (N - 1 - seq_len(nQ)) Rnx[-nQ] } ) #' @export setGeneric( "Q_NX", function(object, ...) standardGeneric("Q_NX"), valueClass = "numeric" ) #' Method Q_NX #' #' Calculate the Q_NX score (Chen & Buja 2006, the notation in the #' publication is M_k). Which is the fraction of points that remain inside #' the same K-ary neighborhood in high and low dimensional space. #' #' @param object of class dimRedResult #' @family Quality scores for dimensionality reduction #' @aliases Q_NX #' @export setMethod( "Q_NX", "dimRedResult", function(object) { chckpkg("coRanking") Q <- coRanking::coranking(object@org.data, object@data@data) nQ <- nrow(Q) N <- nQ + 1 Qnx <- diag(apply(apply(Q, 2, cumsum), 1, cumsum)) / seq_len(nQ) / N Qnx } ) #'@export setGeneric( "LCMC", function(object, ...) standardGeneric("LCMC"), valueClass = "numeric" ) #' Method LCMC #' #' Calculates the Local Continuity Meta Criterion, which is #' \code{\link{Q_NX}} adjusted for random overlap inside the K-ary #' neighborhood. #' #' @param object of class dimRedResult #' @family Quality scores for dimensionality reduction #' @aliases LCMC #' @export setMethod( "LCMC", "dimRedResult", function(object) { chckpkg("coRanking") Q <- coRanking::coranking(object@org.data, object@data@data) nQ <- nrow(Q) N <- nQ + 1 lcmc <- diag(apply(apply(Q, 2, cumsum), 1, cumsum)) / seq_len(nQ) / N - seq_len(nQ) / nQ lcmc } ) rnx2qnx <- function(rnx, K = seq_along(rnx), N = length(rnx) + 1) { (rnx * (N - 1 - K) + K) / (N - 1) } qnx2rnx <- function(qnx, K = seq_along(qnx), N = length(qnx) + 1) { ((N - 1) * qnx - K) / (N - 1 - K) } #' @export setGeneric( "reconstruction_error", function(object, ...) standardGeneric("reconstruction_error"), valueClass = "numeric" ) #' Method reconstruction_error #' #' Calculate the error using only the first \code{n} dimensions of the embedded #' data. \code{error_fun} can either be one of \code{c("rmse", "mae")} to #' calculate the root mean square error or the mean absolute error respectively, #' or a function that takes to equally sized vectors as input and returns a #' single number as output. #' #' @param object of class dimRedResult #' @param n a positive integer or vector of integers \code{<= ndims(object)} #' @param error_fun a function or string indicating an error function, if #' indication a function it must take to matrices of the same size and return #' a scalar. #' @return a vector of number with the same length as \code{n} with the #' #' @examples #' \dontrun{ #' ir <- loadDataSet("Iris") #' ir.drr <- embed(ir, "DRR", ndim = ndims(ir)) #' ir.pca <- embed(ir, "PCA", ndim = ndims(ir)) #' #' rmse <- data.frame( #' rmse_drr = reconstruction_error(ir.drr), #' rmse_pca = reconstruction_error(ir.pca) #' ) #' #' matplot(rmse, type = "l") #' plot(ir) #' plot(ir.drr) #' plot(ir.pca) #' } #' @author Guido Kraemer #' @family Quality scores for dimensionality reduction #' @aliases reconstruction_error #' @export setMethod( "reconstruction_error", c("dimRedResult"), function (object, n = seq_len(ndims(object)), error_fun = "rmse") { if (any(n > ndims(object))) stop("n > ndims(object)") if (any(n < 1)) stop("n < 1") ef <- if (inherits(error_fun, "character")) { switch( error_fun, rmse = rmse, mae = mae ) } else if (inherits(error_fun, "function")) { error_fun } else { stop("error_fun must be a string or function, see documentation for details") } res <- numeric(length(n)) org <- getData(getOrgData(object)) for (i in seq_along(n)) { rec <- getData(inverse( object, getData(getDimRedData(object))[, seq_len(n[i]), drop = FALSE] )) res[i] <- ef(org, rec) } res } ) rmse <- function (x1, x2) sqrt(mean((x1 - x2) ^ 2)) mae <- function (x1, x2) mean(abs(x1 - x2)) dimRed/R/leim.R0000644000176200001440000001331114262545071012735 0ustar liggesusers#' Laplacian Eigenmaps #' #' An S4 Class implementing Laplacian Eigenmaps #' #' Laplacian Eigenmaps use a kernel and were originally developed to #' separate non-convex clusters under the name spectral clustering. #' #' @template dimRedMethodSlots #' #' @template dimRedMethodGeneralUsage #' #' @section Parameters: #' \code{LaplacianEigenmaps} can take the following parameters: #' \describe{ #' \item{ndim}{the number of output dimensions.} #' #' \item{sparse}{A character vector specifying hot to make the graph #' sparse, \code{"knn"} means that a K-nearest neighbor graph is #' constructed, \code{"eps"} an epsilon neighborhood graph is #' constructed, else a dense distance matrix is used.} #' #' \item{knn}{The number of nearest neighbors to use for the knn graph.} #' \item{eps}{The distance for the epsilon neighborhood graph.} #' #' \item{t}{Parameter for the transformation of the distance matrix #' by \eqn{w=exp(-d^2/t)}, larger values give less weight to #' differences in distance, \code{t == Inf} treats all distances != 0 equally.} #' \item{norm}{logical, should the normed laplacian be used?} #' } #' #' @section Implementation: #' Wraps around \code{\link[loe]{spec.emb}}. #' #' @references #' #' Belkin, M., Niyogi, P., 2003. Laplacian Eigenmaps for #' Dimensionality Reduction and Data Representation. Neural #' Computation 15, 1373. #' #' @examples #' if(requireNamespace(c("loe", "RSpectra", "Matrix"), quietly = TRUE)) { #' #' dat <- loadDataSet("3D S Curve") #' emb <- embed(dat, "LaplacianEigenmaps") #' plot(emb@data@data) #' #' } #' @include dimRedResult-class.R #' @include dimRedMethod-class.R #' @export LaplacianEigenmaps #' @exportClass LaplacianEigenmaps LaplacianEigenmaps <- setClass( "LaplacianEigenmaps", contains = "dimRedMethod", prototype = list( stdpars = list(ndim = 2, sparse = "knn", knn = 50, eps = 0.1, t = Inf, norm = TRUE), fun = function (data, pars, keep.org.data = TRUE) { chckpkg("loe") chckpkg("RSpectra") chckpkg("Matrix") meta <- data@meta orgdata <- if (keep.org.data) data@data else NULL indata <- data@data if (is.null(pars$d)) pars$d <- dist if (is.null(pars$knn)) pars$knn <- 50 if (is.null(pars$ndim)) pars$ndim <- 2 if (is.null(pars$t)) pars$t <- Inf if (is.null(pars$norm)) pars$norm <- TRUE message(Sys.time(), ": Creating weight matrix") W <- if (pars$sparse == "knn") { knng <- makeKNNgraph(indata, k = pars$knn, eps = 0, diag = TRUE) if (is.infinite(pars$t)){ knng <- igraph::set_edge_attr(knng, name = "weight", value = 1) } else { ea <- igraph::edge_attr(knng, name = "weight") knng <- igraph::set_edge_attr( knng, name = "weight", value = exp( -(ea ^ 2) / pars$t )) } igraph::as_adj(knng, sparse = TRUE, attr = "weight", type = "both") } else if (pars$sparse == "eps") { tmp <- makeEpsSparseMatrix(indata, pars$eps) tmp@x <- if (is.infinite(pars$t)) rep(1, length(tmp@i)) else exp(- (tmp@x ^ 2) / pars$t) ## diag(tmp) <- 1 as(tmp, "dgCMatrix") } else { # dense case tmp <- dist(indata) tmp[] <- if (is.infinite(pars$t)) 1 else exp( -(tmp ^ 2) / pars$t) tmp <- as.matrix(tmp) diag(tmp) <- 1 tmp } ## we don't need to test for symmetry, because we know the ## matrix is symmetric D <- Matrix::Diagonal(x = Matrix::rowSums(W)) L <- D - W ## for the generalized eigenvalue problem, we do not have a solver ## use A u = \lambda B u ## Lgen <- Matrix::Diagonal(x = 1 / Matrix::diag(D) ) %*% L ## but then we get negative eigenvalues and complex eigenvalues Lgen <- L message(Sys.time(), ": Eigenvalue decomposition") outdata <- if (pars$norm) { DS <- Matrix::Diagonal(x = 1 / sqrt(Matrix::diag(D))) RSpectra::eigs_sym(DS %*% Lgen %*% DS, k = pars$ndim + 1, sigma = -1e-5) } else { RSpectra::eigs_sym(Lgen, k = pars$ndim + 1, sigma = -1e-5) } message("Eigenvalues: ", paste(format(outdata$values), collapse = " ")) ## The eigenvalues are in decreasing order and we remove the ## smallest, which should be approx 0: outdata <- outdata$vectors[, order(outdata$values)[-1], drop = FALSE] if(ncol(outdata) > 0) { colnames(outdata) <- paste0("LEIM", seq_len(ncol(outdata))) } else { warning("no dimensions left, this is probably due to a badly conditioned eigenvalue decomposition.") } message(Sys.time(), ": DONE") return(new( "dimRedResult", data = new("dimRedData", data = outdata, meta = meta), org.data = orgdata, has.org.data = keep.org.data, method = "leim", pars = pars )) }, requires = c("loe", "RSpectra", "Matrix")) ) dimRed/NEWS.md0000644000176200001440000000143113464507204012560 0ustar liggesusers# dimRed 0.2.1 and 0.2.2 * Bugfix releases to pass CRAN tests # dimRed 0.2.0 * Added the R-Journal [paper](https://journal.r-project.org/archive/2018/RJ-2018-039/index.html "dimRed and coRanking") as Vignette * Added UMAP * Added NMF (thanks @topepo) * Added the possibility to return other data such as distance matrices/eigenvalues * Added Autoencoder * Added l1 PCA * Added `getNDim` * Added an `ndim` parameter to many quality functions. * fixed bug in kPCA if inverse was not computable. * added autoencoder # dimRed 0.1.0 * Fixed kPCA predict function and documentation typos (@topepo #2) * Added predict and inverse functions * Added a function to extract rotation matrices from PCA and FastICA # dimRed 0.0.3 * First version on CRAN dimRed/MD50000644000176200001440000001513614263015046011775 0ustar liggesusers7b8f19258856b33e06fab93a5dfd34a7 *DESCRIPTION ae5a59342168733d9988af23c3ca4c2a *LICENSE 2de80a960ad50cff8ecfb0c1eea47997 *NAMESPACE 796f16f5f6b46687e1983c5506c7f0e5 *NEWS.md f64409cfd9b0d92a74c8ec1abdfe96c7 *R/autoencoder.R 1491fcaf87baa04fbb481e72ed53f5a7 *R/dataSets.R dcef24898d3cd637ff8f0a673b94661b *R/diffmap.R 9e17b49bd7954ac4f67b9cec33eac1b9 *R/dimRed.R 0b64904774785f20eea821044c0d004f *R/dimRedData-class.R 846888664cde08c899d92ec7b9ab1215 *R/dimRedMethod-class.R 3fb979a5be13d3e18b4dde7ddf0506b0 *R/dimRedResult-class.R 2e884f558f954befe1c09175ae6d9881 *R/drr.R 127ac676befe3b8ca118d4820e38060c *R/embed.R 82effc7dcf0e7f81745c76fc8a7ccbb8 *R/fastica.R 8b934d56081b9ec45672e471dbe884f0 *R/get_info.R 79caf23c3f5fc9f655fa42427e9ede18 *R/graph_embed.R 3ae996f080f3e1221b87b6be6698319e *R/hlle.R a34ee519ae6604794ca30a243a13b30e *R/isomap.R f7fd4a72a700621ab63025a8f89edaa2 *R/kpca.R 5c7d4c42d1a490ab0bed0f045ac9a8b5 *R/l1pca.R 14f0b1e87026335e1e5a2cc6ed53974f *R/leim.R 211837b77915c12d60aa8afdcad30276 *R/lle.R c581222aef2dbf574cce698e1a7de896 *R/loe.R b60460a99bd739a082780629c886ff4c *R/mds.R 334bc31da9c3630917960f47a9464200 *R/misc.R 92ff206825d071893e8aaf362b1acf64 *R/mixColorSpaces.R 837fb3dc78d4962a99e573ef34746a5d *R/nmds.R 50c7500d7dde202d3f94856ef9e453ee *R/nnmf.R 86ad8e8c74db92a5befc64346ce04539 *R/pca.R 02f7ca463dc80475b4d5009bd154b051 *R/plot.R a45908c1d41960e62db1e92bf79572e6 *R/quality.R e9a61868c99870bbcc03e8f6e4db0fc3 *R/rotate.R 546e6d5cf4d954c002b0e5d2031eb69f *R/soe.R 50b3ae8bcdb80640b2ea464167048ce4 *R/tsne.R 5562e7ff495118cdecec4178ebbbef14 *R/umap.R 843c0ae08e1b419c2391fb7529f2aef0 *build/vignette.rds f4e3a303a848f1a0b6e94c44191c70da *inst/CITATION 2ab520458263e4a5fbd9ab5d1e14382e *inst/doc/dimensionality-reduction.R 08f8cffd3a53d83eefb2a7a18e3a8cae *inst/doc/dimensionality-reduction.Rnw cc0f01cd907ee7a36aac818f6053176c *inst/doc/dimensionality-reduction.pdf bcd35ac3b1f65e2b07692ffb9a7155ae *man/AUC_lnK_R_NX-dimRedResult-method.Rd 7347fa97740684c96b9cdc413f6111e6 *man/AutoEncoder-class.Rd 976565a18d4af0cf00c9859f4f2e6440 *man/DRR-class.Rd 87a330819aefc4ef9acefe21ac646228 *man/DiffusionMaps-class.Rd 51dc7e1038c606e635ce98902eece4a3 *man/DrL-class.Rd 20e6ae4649bd6a09517284f8cad2bf2b *man/FastICA-class.Rd 4fc947ca2f01479666662ce0364f0c7f *man/FruchtermanReingold-class.Rd 89f790257b32f72e0d188a87f6a32b22 *man/HLLE-class.Rd 81da8d68bf7fdde5fbf348767f1c9a72 *man/Isomap-class.Rd 71edcd146fd2a666d3ba322898bdec4b *man/KamadaKawai-class.Rd e66ca8bdfe51f81a92791247fe1d8d2e *man/LCMC-dimRedResult-method.Rd 53259414357f486a475d46955497f1cd *man/LaplacianEigenmaps-class.Rd e2d23d95746626b693ea0da127fa7f24 *man/MDS-class.Rd 64f80d82dc242f4979512600510f331c *man/NNMF-class.Rd e7ca731adaa0dd6c5d58fbc5d456be9a *man/PCA-class.Rd de2bc4b1ff1c5b7ef1f00ff53636b716 *man/PCA_L1-class.Rd d2a64ee29016f6e9c737fecc37608b44 *man/Q_NX-dimRedResult-method.Rd 673691e8e68075b3d22249960a58ed9c *man/Q_global-dimRedResult-method.Rd db781cbd1ca24c2333ffb1a19c33d0ab *man/Q_local-dimRedResult-method.Rd c80cf369e22ae6e24de57a6ecfa3439a *man/R_NX-dimRedResult-method.Rd 53ab297392a7fac382e680cc85acdab2 *man/UMAP-class.Rd 718f4e21d3332957a02215ba01e9125f *man/as.data.frame.Rd 5b85a0e6b1a89a9660bd9e48ab4dd58f *man/as.dimRedData.Rd 7d8095baec2b3d9adafadf37e6048785 *man/cophenetic_correlation-dimRedResult-method.Rd f0bd8fc3c88f81644d68f20f2a22767c *man/dataSets.Rd f1a7b217df5585e3800a558d72a3df7d *man/dimRed-package.Rd 25963f304d114b9142d96f500419b841 *man/dimRedData-class.Rd d86f4071f2405e8efef0a4ac4d379378 *man/dimRedMethod-class.Rd 10dffa1f570d7b214a2a332be56e87a3 *man/dimRedMethodList.Rd dd02f619260c835191b8fd4d36d85fb1 *man/dimRedResult-class.Rd 8245ced1f3f0de4235b11f84b1a54024 *man/distance_correlation-dimRedResult-method.Rd a6c062760361e192c7b614bbe9db1b2b *man/embed.Rd af8863f32422517f0758352f5773d916 *man/getData.Rd beb9c9c0b2b9069d2cfde3a7ef78f810 *man/getDimRedData.Rd 3d700516a933d7d8fe95cebd9e3e0365 *man/getMeta.Rd 966f27a61120f340e6967930d5a4dae4 *man/getNDim.Rd 54af2a8843ad16e4c8daf4b75f80fd51 *man/getOrgData.Rd 47659991b1edf53bbf1a544d8cbfc231 *man/getOtherData.Rd b6a82a60362da823b309497c27b54d61 *man/getPars.Rd 8afc551d35d07d41b0e186dc77c0aa8b *man/getRotationMatrix.Rd dd3364861488caf3f1e293c986809ce9 *man/installSuggests.Rd 8a10b386eb60ec0e46070f5dcbefbf51 *man/kPCA-class.Rd e6fda0f5f8483f08ff20d467eab06cac *man/makeKNNgraph.Rd debb38427c3c0f1d3c3559ad66a3269e *man/maximize_correlation-dimRedResult-method.Rd 889d398a1978c51f13a5319bc6e77ce7 *man/mean_R_NX-dimRedResult-method.Rd 9c4126f34fc27b575fbbe1418fcfeecd *man/mixColorRamps.Rd 3a405d9be89ec32727e9894d5e15c2f0 *man/nMDS-class.Rd d129fc72b1b204e139d23885ccd064bc *man/ndims.Rd 26e6f98c137b3fbdbf2cb63644fb5630 *man/plot.Rd 606393d1d95a868d9ce18b4659e29bd7 *man/plot_R_NX.Rd ecdac99d07501417ba48b07a28ec5f5d *man/print.Rd 40b26ad6ed19a983719618afee4f0d6d *man/quality.Rd 1fe05b1ae61fd475a4b39db0176ae977 *man/reconstruction_error-dimRedResult-method.Rd bc566baaf50a52c8765a4ff8803e6a6b *man/reconstruction_rmse-dimRedResult-method.Rd 86adb0e35656d593a6e4b99ac1f8a753 *man/tSNE-class.Rd b8152e44f03d5cfa9046bef699bea694 *man/total_correlation-dimRedResult-method.Rd 90e7032d9dab3cdce1f4cdab889c1e5e *tests/testthat.R 03cee355cbc64743519da8174ff2db64 *tests/testthat/test_HLLE.R 5f52a46b0c2f6feb223c8fd4b13ab496 *tests/testthat/test_NNMF.R 124cf8e233b989da33f93b8aed767c6b *tests/testthat/test_PCA.R 714d4b2860fdcd3dcd139022997b64e1 *tests/testthat/test_PCA_L1.R 3f74997d3c10e771d752cf891fbadcd1 *tests/testthat/test_UMAP.R bb8c3b4fc35bb840b2253690974cb23b *tests/testthat/test_autoencoder.R f6a9f52f7737fa73cbdfc9d392fe380c *tests/testthat/test_dataSets.R c8693e4a0167b88ca1a6324d1ea9f551 *tests/testthat/test_diffusion_maps.R 4d5f6d5e1436b93d3e134bb85c0010bc *tests/testthat/test_dimRedData_class.R f9c92929b794fea01107fb2a706613da *tests/testthat/test_dimRedMethod-class.R 808be8f4fbf949ae2d5a4acda8d5324d *tests/testthat/test_dimRedResult_class.R 535ba190da5bf8033aa9cadc3e69f15a *tests/testthat/test_drr.R f688a3a3c1982e8eb597524c65ffe8b4 *tests/testthat/test_embed.R 6b44dd83dad6c0627ff2d748a64ec770 *tests/testthat/test_fastICA.R 9758aa26e0ecb09c696063d83e7ad7a8 *tests/testthat/test_high_level_functions.R 055893333a59f9ea739868924cebc3a5 *tests/testthat/test_isomap.R 9e854d7bac4f41dcffc781a071f581d4 *tests/testthat/test_kPCA.R 66fa0b1685e640e4acb5a6edb2e6233f *tests/testthat/test_misc_functions.R 4922b74b4d183266fc9e405ad5b4e302 *tests/testthat/test_quality.R 55bd9bdc93bd1f08207db81085ff756a *vignettes/Makefile 6b21c813361c55cf8b7361b7a0b3bacf *vignettes/bibliography.bib b3b0dc9c51a39436ebbc3895a9b2f9f6 *vignettes/classification_tree.tex 08f8cffd3a53d83eefb2a7a18e3a8cae *vignettes/dimensionality-reduction.Rnw dimRed/inst/0000755000176200001440000000000014262570071012437 5ustar liggesusersdimRed/inst/doc/0000755000176200001440000000000014262570071013204 5ustar liggesusersdimRed/inst/doc/dimensionality-reduction.R0000644000176200001440000001500414262570016020350 0ustar liggesusers## ----"pca_isomap_example",include=FALSE,fig.width=4,fig.height=4-------------- if(Sys.getenv("BNET_BUILD_VIGNETTE") != "") { library(dimRed); library(ggplot2); #library(dplyr); library(tidyr) ## define which methods to apply embed_methods <- c("Isomap", "PCA") ## load test data set data_set <- loadDataSet("3D S Curve", n = 1000) ## apply dimensionality reduction data_emb <- lapply(embed_methods, function(x) embed(data_set, x)) names(data_emb) <- embed_methods ## plot data set, embeddings, and quality analysis ## plot(data_set, type = "3vars") ## lapply(data_emb, plot, type = "2vars") ## plot_R_NX(data_emb) add_label <- function(label) grid::grid.text(label, 0.2, 1, hjust = 0, vjust = 1, gp = grid::gpar(fontface = "bold", cex = 1.5)) ## pdf('~/phd/text/dimRedPackage/plots/plot_example.pdf', width = 4, height = 4) ## plot the results plot(data_set, type = "3vars", angle = 15, mar = c(3, 3, 0, 0), box = FALSE, grid = FALSE, pch = 16) add_label("a") par(mar = c(4, 4, 0, 0) + 0.1, bty = "n", las = 1) plot(data_emb$Isomap, type = "2vars", pch = 16) add_label("b") plot(data_emb$PCA, type = "2vars", pch = 16) add_label("d") ## calculate quality scores print( plot_R_NX(data_emb) + theme(legend.title = element_blank(), legend.position = c(0.5, 0.1), legend.justification = c(0.5, 0.1)) ) add_label("c") } else { # These cannot all be plot(1:10)!!! It's a mistery to me. plot(1:10) barplot(1:10) hist(1:10) plot(1:10) } ## ----eval=FALSE--------------------------------------------------------------- # ## define which methods to apply # embed_methods <- c("Isomap", "PCA") # ## load test data set # data_set <- loadDataSet("3D S Curve", n = 1000) # ## apply dimensionality reduction # data_emb <- lapply(embed_methods, function(x) embed(data_set, x)) # names(data_emb) <- embed_methods # ## figure \ref{fig:plotexample}a, the data set # plot(data_set, type = "3vars") # ## figures \ref{fig:plotexample}b (Isomap) and \ref{fig:plotexample}d (PCA) # lapply(data_emb, plot, type = "2vars") # ## figure \ref{fig:plotexample}c, quality analysis # plot_R_NX(data_emb) ## ----include=FALSE------------------------------------------------------------ if(Sys.getenv("BNET_BUILD_VIGNETTE") != "") { library(dimRed) library(cccd) ## Load data ss <- loadDataSet("3D S Curve", n = 500) ## Parameter space kk <- floor(seq(5, 100, length.out = 40)) ## Embedding over parameter space emb <- lapply(kk, function(x) embed(ss, "Isomap", knn = x)) ## Quality over embeddings qual <- sapply(emb, function(x) quality(x, "Q_local")) ## Find best value for K ind_max <- which.max(qual) k_max <- kk[ind_max] add_label <- function(label){ par(xpd = TRUE) b = par("usr") text(b[1], b[4], label, adj = c(0, 1), cex = 1.5, font = 2) par(xpd = FALSE) } names(qual) <- kk } ## ----"select_k",include=FALSE,fig.width=11,fig.height=5----------------------- if(Sys.getenv("BNET_BUILD_VIGNETTE") != "") { par(mfrow = c(1, 2), mar = c(5, 4, 0, 0) + 0.1, oma = c(0, 0, 0, 0)) plot(kk, qual, type = "l", xlab = "k", ylab = expression(Q[local]), bty = "n") abline(v = k_max, col = "red") add_label("a") plot(ss, type = "3vars", angle = 15, mar = c(3, 3, 0, 0), box = FALSE, grid = FALSE, pch = 16) add_label("b") } else { plot(1:10) plot(1:10) } ## ----"knngraphs",include=FALSE,fig.width=8,fig.height=3----------------------- if(Sys.getenv("BNET_BUILD_VIGNETTE") != "") { par(mfrow = c(1, 3), mar = c(5, 4, 0, 0) + 0.1, oma = c(0, 0, 0, 0)) add_knn_graph <- function(ind) { nn1 <- nng(ss@data, k = kk[ind]) el <- get.edgelist(nn1) segments(x0 = emb[[ind]]@data@data[el[, 1], 1], y0 = emb[[ind]]@data@data[el[, 1], 2], x1 = emb[[ind]]@data@data[el[, 2], 1], y1 = emb[[ind]]@data@data[el[, 2], 2], col = "#00000010") } plot(emb[[2]]@data@data, type = "n", bty = "n") add_knn_graph(2) points(emb[[2]]@data@data, col = dimRed:::colorize(ss@meta), pch = 16) add_label("c") plot(emb[[ind_max]]@data@data, type = "n", bty = "n") add_knn_graph(ind_max) points(emb[[ind_max]]@data@data, col = dimRed:::colorize(ss@meta), pch = 16) add_label("d") plot(emb[[length(emb)]]@data@data, type = "n", bty = "n") add_knn_graph(length(emb)) points(emb[[length(emb)]]@data@data, col = dimRed:::colorize(ss@meta), pch = 16) add_label("e") } else { plot(1:10) plot(1:10) plot(1:10) } ## ----eval=FALSE--------------------------------------------------------------- # ## Load data # ss <- loadDataSet("3D S Curve", n = 500) # ## Parameter space # kk <- floor(seq(5, 100, length.out = 40)) # ## Embedding over parameter space # emb <- lapply(kk, function(x) embed(ss, "Isomap", knn = x)) # ## Quality over embeddings # qual <- sapply(emb, function(x) quality(x, "Q_local")) # ## Find best value for K # ind_max <- which.max(qual) # k_max <- kk[ind_max] ## ----"plot_quality",include=FALSE--------------------------------------------- if(Sys.getenv("BNET_BUILD_VIGNETTE") != "") { embed_methods <- dimRedMethodList() quality_methods <- c("Q_local", "Q_global", "AUC_lnK_R_NX", "cophenetic_correlation") iris_data <- loadDataSet("Iris") quality_results <- matrix( NA, length(embed_methods), length(quality_methods), dimnames = list(embed_methods, quality_methods) ) embedded_data <- list() for (e in embed_methods) { try(embedded_data[[e]] <- embed(iris_data, e)) for (q in quality_methods) try(quality_results[e,q] <- quality(embedded_data[[e]], q)) } quality_results <- quality_results[order(rowMeans(quality_results)), ] palette(c("#1b9e77", "#d95f02", "#7570b3", "#e7298a", "#66a61e")) col_hsv <- rgb2hsv(col2rgb(palette())) ## col_hsv["v", ] <- col_hsv["v", ] * 3 / 1 palette(hsv(col_hsv["h",], col_hsv["s",], col_hsv["v",])) par(mar = c(2, 8, 0, 0) + 0.1) barplot(t(quality_results), beside = TRUE, col = 1:4, legend.text = quality_methods, horiz = TRUE, las = 1, cex.names = 0.85, args.legend = list(x = "topleft", bg = "white", cex = 0.8)) } else { plot(1:10) } ## ----eval=FALSE--------------------------------------------------------------- # embed_methods <- dimRedMethodList() # quality_methods <- c("Q_local", "Q_global", "AUC_lnK_R_NX", # "cophenetic_correlation") # scurve <- loadDataSet("3D S Curve", n = 2000) # quality_results <- matrix( # NA, length(embed_methods), length(quality_methods), # dimnames = list(embed_methods, quality_methods) # ) # # embedded_data <- list() # for (e in embed_methods) { # embedded_data[[e]] <- embed(scurve, e) # for (q in quality_methods) # try(quality_results[e, q] <- quality(embedded_data[[e]], q)) # } dimRed/inst/doc/dimensionality-reduction.Rnw0000644000176200001440000017352413371631672020737 0ustar liggesusers\documentclass{article} %\VignetteEngine{knitr::knitr} %\VignetteIndexEntry{Dimensionality Reduction} %\VignetteKeyword{Dimensionality Reduction} \usepackage[utf8]{inputenc} \usepackage[T1]{fontenc} \usepackage{hyperref} \usepackage{amsmath,amssymb} \usepackage{booktabs} \usepackage{tikz} \usetikzlibrary{trees} \usepackage[sectionbib,round]{natbib} \title{\pkg{dimRed} and \pkg{coRanking}---Unifying Dimensionality Reduction in R} \author{Guido Kraemer \and Markus Reichstein \and Miguel D.\ Mahecha} % these are taken from RJournal.sty: \makeatletter \DeclareRobustCommand\code{\bgroup\@noligs\@codex} \def\@codex#1{\texorpdfstring% {{\normalfont\ttfamily\hyphenchar\font=-1 #1}}% {#1}\egroup} \newcommand{\kbd}[1]{{\normalfont\texttt{#1}}} \newcommand{\key}[1]{{\normalfont\texttt{\uppercase{#1}}}} \DeclareRobustCommand\samp{`\bgroup\@noligs\@sampx} \def\@sampx#1{{\normalfont\texttt{#1}}\egroup'} \newcommand{\var}[1]{{\normalfont\textsl{#1}}} \let\env=\code \newcommand{\file}[1]{{`\normalfont\textsf{#1}'}} \let\command=\code \let\option=\samp \newcommand{\dfn}[1]{{\normalfont\textsl{#1}}} % \acronym is effectively disabled since not used consistently \newcommand{\acronym}[1]{#1} \newcommand{\strong}[1]{\texorpdfstring% {{\normalfont\fontseries{b}\selectfont #1}}% {#1}} \let\pkg=\strong \newcommand{\CRANpkg}[1]{\href{https://CRAN.R-project.org/package=#1}{\pkg{#1}}}% \let\cpkg=\CRANpkg \newcommand{\ctv}[1]{\href{https://CRAN.R-project.org/view=#1}{\emph{#1}}} \newcommand{\BIOpkg}[1]{\href{https://www.bioconductor.org/packages/release/bioc/html/#1.html}{\pkg{#1}}} \makeatother \begin{document} \maketitle \abstract{ % This document is based on the manuscript of \citet{kraemer_dimred_2018} which was published in the R-Journal and has been modified and extended to fit the format of a package vignette and to match the extended functionality of the \pkg{dimRed} package. ``Dimensionality reduction'' (DR) is a widely used approach to find low dimensional and interpretable representations of data that are natively embedded in high-dimensional spaces. % DR can be realized by a plethora of methods with different properties, objectives, and, hence, (dis)advantages. The resulting low-dimensional data embeddings are often difficult to compare with objective criteria. % Here, we introduce the \CRANpkg{dimRed} and \CRANpkg{coRanking} packages for the R language. % These open source software packages enable users to easily access multiple classical and advanced DR methods using a common interface. % The packages also provide quality indicators for the embeddings and easy visualization of high dimensional data. % The \pkg{coRanking} package provides the functionality for assessing DR methods in the co-ranking matrix framework. % In tandem, these packages allow for uncovering complex structures high dimensional data. % Currently 15 DR methods are available in the package, some of which were not previously available to R users. % Here, we outline the \pkg{dimRed} and \pkg{coRanking} packages and make the implemented methods understandable to the interested reader. % } \section{Introduction} \label{sec:intro} Dimensionality Reduction (DR) essentially aims to find low dimensional representations of data while preserving their key properties. % Many methods exist in literature, optimizing different criteria: % maximizing the variance or the statistical independence of the projected data, % minimizing the reconstruction error under different constraints, % or optimizing for different error metrics, % just to name a few. % Choosing an inadequate method may imply that much of the underlying structure remains undiscovered. % Often the structures of interest in a data set can be well represented by fewer dimensions than exist in the original data. % Data compression of this kind has the additional benefit of making the encoded information better conceivable to our brains for further analysis tasks like classification or regression problems. % For example, the morphology of a plant's leaves, stems, and seeds reflect the environmental conditions the species usually grow in (e.g.,\ plants with large soft leaves will never grow in a desert but might have an advantage in a humid and shadowy environment). % Because the morphology of the entire plant depends on the environment, many morphological combinations will never occur in nature and the morphological space of all plant species is tightly constrained. % \citet{diaz_global_2016} found that out of six observed morphological characteristics only two embedding dimensions were enough to represent three quarters of the totally observed variability. % DR is a widely used approach for the detection of structure in multivariate data, and has applications in a variety of fields. % In climatology, DR is used to find the modes of some phenomenon, e.g.,\ the first Empirical Orthogonal Function of monthly mean sea surface temperature of a given region over the Pacific is often linked to the El Ni\~no Southern Oscillation or ENSO \citep[e.g.,\ ][]{hsieh_nonlinear_2004}. % In ecology the comparison of sites with different species abundances is a classical multivariate problem: each observed species adds an extra dimension, and because species are often bound to certain habitats, there is a lot of redundant information. Using DR is a popular technique to represent the sites in few dimensions, e.g.,\ \citet{aart_distribution_1972} matches wolfspider communities to habitat and \citet{morrall_soil_1974} match soil fungi data to soil types. (In ecology the general name for DR is ordination or indirect gradient analysis.) % Today, hyperspectral satellite imagery collects so many bands that it is very difficult to analyze and interpret the data directly. % Resuming the data into a set of few, yet independent, components is one way to reduce complexity \citep[e.g.,\ see][]{laparra_dimensionality_2015}. % DR can also be used to visualize the interiors of deep neural networks \citep[e.g.,\ see ][]{han_deep_2016}, where the high dimensionality comes from the large number of weights used in a neural network and convergence can be visualized by means of DR\@. % We could find many more example applications here but this is not the main focus of this publication. % The difficulty in applying DR is that each DR method is designed to maintain certain aspects of the original data and therefore may be appropriate for one task and inappropriate for another. % Most methods also have parameters to tune and follow different assumptions. The quality of the outcome may strongly depend on their tuning, which adds additional complexity. % DR methods can be modeled after physical models with attracting and repelling forces (Force Directed Methods), projections onto low dimensional planes (PCA, ICA), divergence of statistical distributions (SNE family), or the reconstruction of local spaces or points by their neighbors (LLE). % As an example for how changing internal parameters of a method can have a great impact, the breakthrough for Stochastic Neighborhood Embedding (SNE) methods came when a Student's $t$-distribution was used instead of a normal distribution to model probabilities in low dimensional space to avoid the ``crowding problem'', that is,\ a sphere in high dimensional space has a much larger volume than in low dimensional space and may contain too many points to be represented accurately in few dimensions. % The $t$-distribution, allows medium distances to be accurately represented in few dimensions by larger distances due to its heavier tails. % The result is called in $t$-SNE and is especially good at preserving local structures in very few dimensions, this feature made $t$-SNE useful for a wide array of data visualization tasks and the method became much more popular than standard SNE (around six times more citations of \citet{van_der_maaten_visualizing_2008} compared to \citet{hinton_stochastic_2003} in Scopus \citep{noauthor_scopus_nodate}). % There are a number of software packages for other languages providing collections of methods: In Python there is scikit-learn \citep{scikit-learn}, which contains a module for DR. In Julia we currently find ManifoldLearning.jl for nonlinear and MultivariateStats.jl for linear DR methods. % There are several toolboxes for DR implemented in Matlab \citep{van_der_maaten_dimensionality_2009, arenas-garcia_kernel_2013}. The Shogun toolbox \citep{soeren_sonnenburg_2017_1067840} implements a variety of methods for dimensionality reduction in C++ and offers bindings for a many common high level languages (including R, but the installation is anything but simple, as there is no CRAN package). % However, there is no comprehensive package for R and none of the former mentioned software packages provides means to consistently compare the quality of different methods for DR. % For many applications it can be difficult to objectively find the right method or parameterization for the DR task. % This paper presents the \pkg{dimRed} and \pkg{coRanking} packages for the popular programming language R. Together, they provide a standardized interface to various dimensionality reduction methods and quality metrics for embeddings. They are implemented using the S4 class system of R, making the packages both easy to use and to extend. The design goal for these packages is to enable researchers, who may not necessarily be experts in DR, to apply the methods in their own work and to objectively identify the most suitable methods for their data. % This paper provides an overview of the methods collected in the packages and contains examples as to how to use the packages. % The notation in this paper will be as follows: $X = [x_i]_{1\leq i \leq n}^T \in \mathbb{R}^{n\times p}$, and the observations $x_i \in \mathbb{R}^p$. % These observations may be transformed prior to the dimensionality reduction step (e.g.,\ centering and/or standardization) resulting in $X' = [x'_i]_{1\leq i \leq n}^T \in \mathbb{R}^{n\times p}$. % A DR method then embeds each vector in $X'$ onto a vector in $Y = [y_i]_{1\leq i \leq n}^T \in \mathbb{R}^{n\times q}$ with $y_i \in \mathbb{R}^q$, ideally with $q \ll p$. % Some methods provide an explicit mapping $f(x'_i) = y_i$. Some even offer an inverse mapping $f^{-1}(y_{i}) = \hat x'_{i}$, such that one can reconstruct a (usually approximate) sample from the low-dimensional representation. % For some methods, pairwise distances between points are needed, we set $d_{ij} = d(x_{i}, x_{j})$ and $\hat{d}_{ij} = d(y_i, y_j)$, where $d$ is some appropriate distance function. When referring to \code{functions} in the \pkg{dimRed} package or base R simply the function name is mentioned, functions from other packages are referenced with their namespace, as with \code{package::function}. \begin{figure}[htbp] \centering \input{classification_tree.tex} \caption{% Classification of dimensionality reduction methods. Methods in bold face are implemented in \pkg{dimRed}. Modified from \citet{van_der_maaten_dimensionality_2009}. }\label{fig:classification} \end{figure} \section{Dimensionality Reduction Methods} \label{sec:dimredtec} In the following section we do not aim for an exhaustive explanation to every method in \pkg{dimRed} but rather to provide a general idea on how the methods work. % An overview and classification of the most commonly used DR methods can be found in Figure~\ref{fig:classification}. In all methods, parameters have to be optimized or decisions have to be made, even if it is just about the preprocessing steps of data. % The \pkg{dimRed} package tries to make the optimization process for parameters as easy as possible, but, if possible, the parameter space should be narrowed down using prior knowledge. % Often decisions can be made based on theoretical knowledge. For example,\ sometimes an analysis requires data to be kept in their original scales and sometimes this is exactly what has to be avoided as when comparing different physical units. % Sometimes decisions based on the experience of others can be made, e.g.,\ the Gaussian kernel is probably the most universal kernel and therefore should be tested first if there is a choice. % All methods presented here have the embedding dimensionality, $q$, as a parameter (or \code{ndim} as a parameter for \code{embed}). % For methods based on eigenvector decomposition, the result generally does not depend on the number of dimensions, i.e.,\ the first dimension will be the same, no matter if we decide to calculate only two dimensions or more. % If more dimensions are added, more information is maintained, the first dimension is the most important and higher dimensions are successively less important. % This means, that a method based on eigenvalue decomposition only has to be run once if one wishes to compare the embedding in different dimensions. % In optimization based methods this is generally not the case, the number of dimensions has to be chosen a priori, an embedding of 2 and 3 dimensions may vary significantly, and there is no ordered importance of dimensions. % This means that comparing dimensions of optimization-based methods is computationally much more expensive. % We try to give the computational complexity of the methods. Because of the actual implementation, computation times may differ largely. % R is an interpreted language, so all parts of an algorithm that are implemented in R often will tend to be slow compared to methods that call efficient implementations in a compiled language. % Methods where most of the computing time is spent for eigenvalue decomposition do have very efficient implementations as R uses optimized linear algebra libraries. Although, eigenvalue decomposition itself does not scale very well in naive implementations ($\mathcal{O}(n^3)$). \subsection{PCA} \label{sec:pca} Principal Component Analysis (PCA) is the most basic technique for reducing dimensions. It dates back to \citet{pearson_lines_1901}. PCA finds a linear projection ($U$) of the high dimensional space into a low dimensional space $Y = XU$, maintaining maximum variance of the data. It is based on solving the following eigenvalue problem: \begin{equation} (C_{XX}-\lambda_k I)u_k=0\label{eq:pca} \end{equation} where $C_{XX} = \frac 1 n X^TX$ is the covariance matrix, $\lambda_k$ and $u_k$ are the $k$-th eigenvalue and eigenvector, and $I$ is the identity matrix. % The equation has several solutions for different values of $\lambda_k$ (leaving aside the trivial solution $u_k = 0$). % PCA can be efficiently applied to large data sets, because it computationally scales as $\mathcal{O}(np^2 + p^3)$, that is, it scales linearly with the number of samples and R uses specialized linear algebra libraries for such kind of computations. PCA is a rotation around the origin and there exist a forward and inverse mapping. % PCA may suffer from a scale problem, i.e.,\ when one variable dominates the variance simply because it is in a higher scale, to remedy this, the data can be scaled to zero mean and unit variance, depending on the use case, if this is necessary or desired. % Base R implements PCA in the functions \code{prcomp} and \code{princomp}; but several other implementations exist i.e., \BIOpkg{pcaMethods} from Bioconductor which implements versions of PCA that can deal with missing data. % The \pkg{dimRed} package wraps \code{prcomp}. \subsection{kPCA} \label{sec:kpca} Kernel Principal Component Analysis (kPCA) extends PCA to deal with nonlinear dependencies among variables. % The idea behind kPCA is to map the data into a high dimensional space using a possibly non-linear function $\phi$ and then to perform a PCA in this high dimensional space. % Some mathematical tricks are used for efficient computation. % If the columns of X are centered around $0$, then the principal components can also be computed from the inner product matrix $K = X^TX$. % Due to this way of calculating a PCA, we do not need to explicitly map all points into the high dimensional space and do the calculations there, it is enough to obtain the inner product matrix or kernel matrix $K \in \mathbb{R}^{n\times n}$ of the mapped points \citep{scholkopf_nonlinear_1998}. % Here is an example calculating the kernel matrix using a Gaussian kernel: \begin{equation}\label{eq:gauss} K = \phi(x_i)^T \phi(x_j) = \kappa(x_i, x_j) = \exp\left( -\frac{\| x_i- x_j\|^2}{2 \sigma^2} \right), \end{equation} where $\sigma$ is a length scale parameter accounting for the width of the kernel. % The other trick used is known as the ``representers theorem.'' The interested reader is referred to \citet{scholkopf_generalized_2001}. The kPCA method is very flexible and there exist many kernels for special purposes. The most common kernel function is the Gaussian kernel (Equation\ \ref{eq:gauss}). % The flexibility comes at the price that the method has to be finely tuned for the data set because some parameter combinations are simply unsuitable for certain data. % The method is not suitable for very large data sets, because memory scales with $\mathcal{O}(n^2)$ and computation time with $\mathcal{O}(n^3)$. % Diffusion Maps, Isomap, Locally Linear Embedding, and some other techniques can be seen as special cases of kPCA. In which case, an out-of-sample extension using the Nyström formula can be applied \citep{bengio_learning_2004}. % This can also yield applications for bigger data, where an embedding is trained with a sub-sample of all data and then the data is embedded using the Nyström formula. Kernel PCA in R is implemented in the \CRANpkg{kernlab} package using the function \code{kernlab::kpca}, and supports a number of kernels and user defined functions. For details see the help page for \code{kernlab::kpca}. The \pkg{dimRed} package wraps \code{kernlab::kpca} but additionally provides forward and inverse methods \citep{bakir_learning_2004} which can be used to fit out-of-sample data or to visualize the transformation of the data space. % \subsection{Classical Scaling} \label{sec:classscale} What today is called Classical Scaling was first introduced by \citet{torgerson_multidimensional_1952}. It uses an eigenvalue decomposition of a transformed distance matrix to find an embedding that maintains the distances of the distance matrix. % The method works because of the same reason that kPCA works, i.e.,\ classical scaling can be seen as a kPCA with kernel $x^Ty$. % A matrix of Euclidean distances can be transformed into an inner product matrix by some simple transformations and therefore yields the same result as a PCA\@. % Classical scaling is conceptually more general than PCA in that arbitrary distance matrices can be used, i.e.,\ the method does not even need the original coordinates, just a distance matrix $D$. % Then it tries to find an embedding $Y$ so that $\hat d_{ij}$ is as similar to $d_{ij}$ as possible. The disadvantage is that it is computationally much more demanding, i.e.,\ an eigenvalue decomposition of an $n\times n$ matrix has to be computed. This step requires $\mathcal{O}(n^2)$ memory and $\mathcal{O}(n^3)$ computation time, while PCA requires only the eigenvalue decomposition of a $d\times d$ matrix and usually $n \gg d$. % R implements classical scaling in the \code{cmdscale} function. % The \pkg{dimRed} package wraps \code{cmdscale} and allows the specification of arbitrary distance functions for calculating the distance matrix. Additionally a forward method is implemented. \subsection{Isomap} \label{sec:isomap} As Classical Scaling can deal with arbitrarily defined distances, \citet{tenenbaum_global_2000} suggested to approximate the structure of the manifold by using geodesic distances. % In practice, a graph is created by either keeping only the connections between every point and its $k$ nearest neighbors to produce a $k$-nearest neighbor graph ($k$-NNG), or simply by keeping all distances smaller than a value $\varepsilon$ producing an $\varepsilon$-neighborhood graph ($\varepsilon$-NNG). % Geodesic distances are obtained by recording the distance on the graph and classical scaling is used to find an embedding in fewer dimensions. This leads to an ``unfolding'' of possibly convoluted structures (see Figure~\ref{fig:knn}). Isomap's computational cost is dominated by the eigenvalue decomposition and therefore scales with $\mathcal{O}(n^3)$. % Other related techniques can use more efficient algorithms because the distance matrix becomes sparse due to a different preprocessing. In R, Isomap is implemented in the \CRANpkg{vegan} package. The \code{vegan::isomap} calculates an Isomap embedding and \code{vegan::isomapdist} calculates a geodesic distance matrix. % The \pkg{dimRed} package uses its own implementation. This implementation is faster mainly due to using a KD-tree for the nearest neighbor search (from the \CRANpkg{RANN} package) and to a faster implementation for the shortest path search in the $k$-NNG (from the \CRANpkg{igraph} package). % The implementation in \pkg{dimRed} also includes a forward method that can be used to train the embedding on a subset of data points and then use these points to approximate an embedding for the remaining points. This technique is generally referred to as landmark Isomap \citep{de_silva_sparse_2004}. % \subsection{Locally Linear Embedding} \label{sec:lle} Points that lie on a manifold in a high dimensional space can be reconstructed through linear combinations of their neighborhoods if the manifold is well sampled and the neighbohoods lie on a locally linear patch. % These reconstruction weights, $W$, are the same in the high dimensional space as the internal coordinates of the manifold. % Locally Linear Embedding \citep[LLE; ][]{roweis_nonlinear_2000} is a technique that constructs a weight matrix $W \in \mathbb{R}^{n\times n}$ with elements $w_{ij}$ so that \begin{equation} \sum_{i=1}^n \bigg\| x_i- \sum_{j=1}^{n} w_{ij}x_j \bigg\|^2\label{eq:lle} \end{equation} is minimized under the constraint that $w_{ij} = 0 $ if $x_j$ does not belong to the neighborhood and the constraint that $\sum_{j=1}^n w_{ij} = 1$. % Finally the embedding is made in such a way that the following cost function is minimized for $Y$, \begin{equation} \sum_{i=1}^n\bigg\| y_i - \sum_{j=1}^n w_{ij}y_j \bigg\|^2.\label{eq:lle2} \end{equation} This can be solved using an eigenvalue decomposition. Conceptually the method is similar to Isomap but it is computationally much nicer because the weight matrix is sparse and there exist efficient solvers. % In R, LLE is implemented by the package \CRANpkg{lle}, the embedding can be calculated with \code{lle::lle}. Unfortunately the implementation does not make use of the sparsity of the weight matrix $W$. % The manifold must be well sampled and the neighborhood size must be chosen appropriately for LLE to give good results. % \subsection{Laplacian Eigenmaps} \label{sec:laplaceigenmaps} Laplacian Eigenmaps were originally developed under the name spectral clustering to separate non-convex clusters. % Later it was also used for graph embedding and DR \citep{belkin_laplacian_2003}. % A number of variants have been proposed. % First, a graph is constructed, usually from a distance matrix, the graph can be made sparse by keeping only the $k$ nearest neighbors, or by specifying an $\varepsilon$ neighborhood. % Then, a similarity matrix $W$ is calculated by using a Gaussian kernel (see Equation \ref{eq:gauss}), if $c = 2 \sigma^2 = \infty$, then all distances are treated equally, the smaller $c$ the more emphasis is given to differences in distance. % The degree of vertex $i$ is $d_i = \sum_{j=1}^n w_{ij}$ and the degree matrix, $D$, is the diagonal matrix with entries $d_i$. % Then we can form the graph Laplacian $L = D - W$ and, then, there are several ways how to proceed, an overview can be found in \citet{luxburg_tutorial_2007}. % The \pkg{dimRed} package implements the algorithm from \citet{belkin_laplacian_2003}. Analogously to LLE, Laplacian eigenmaps avoid computational complexity by creating a sparse matrix and not having to estimate the distances between all pairs of points. % Then the eigenvectors corresponding to the lowest eigenvalues larger than $0$ of either the matrix $L$ or the normalized Laplacian $D^{-1/2}LD^{-1/2}$ are computed and form the embedding. \subsection{Diffusion Maps} \label{sec:isodiffmaplle} Diffusion Maps \citep{coifman_diffusion_2006} take a distance matrix as input and calculates the transition probability matrix $P$ of a diffusion process between the points to approximate the manifold. % Then the embedding is done by an eigenvalue decompositon of $P$ to calculate the coordinates of the embedding. % The algorithm for calculating Diffusion Maps shares some elements with the way Laplacian Eigenmaps are calculated. % Both algorithms depart from the same weight matrix, Diffusion Maps calculate the transition probability on the graph after $t$ time steps and do the embedding on this probability matrix. The idea is to simulate a diffusion process between the nodes of the graph, which is more robust to short-circuiting than the $k$-NNG from Isomap (see bottom right Figure \ref{fig:knn}). % Diffusion maps in R are accessible via the \code{diffusionMap::diffuse()} function, which is available in the \CRANpkg{diffusionMap} package. % Additional points can be approximated into an existing embedding using the Nyström formula \citep{bengio_learning_2004}. % The implementation in \pkg{dimRed} is based on the \code{diffusionMap::diffuse} function. % , which does not contain an % approximation for unequally sampled manifolds % \citep{coifman_geometric_2005}. % \subsection{non-Metric Dimensional Scaling} \label{sec:nmds} While Classical Scaling and derived methods (see section \nameref{sec:classscale}) use eigenvector decomposition to embed the data in such a way that the given distances are maintained, non-Metric Dimensional Scaling \citep[nMDS, ][]{kruskal_multidimensional_1964,kruskal_nonmetric_1964} uses optimization methods to reach the same goal. % Therefore a stress function, \begin{equation} \label{eq:stress} S = \sqrt{\frac{\sum_{i>= if(Sys.getenv("BNET_BUILD_VIGNETTE") != "") { library(dimRed); library(ggplot2); #library(dplyr); library(tidyr) ## define which methods to apply embed_methods <- c("Isomap", "PCA") ## load test data set data_set <- loadDataSet("3D S Curve", n = 1000) ## apply dimensionality reduction data_emb <- lapply(embed_methods, function(x) embed(data_set, x)) names(data_emb) <- embed_methods ## plot data set, embeddings, and quality analysis ## plot(data_set, type = "3vars") ## lapply(data_emb, plot, type = "2vars") ## plot_R_NX(data_emb) add_label <- function(label) grid::grid.text(label, 0.2, 1, hjust = 0, vjust = 1, gp = grid::gpar(fontface = "bold", cex = 1.5)) ## pdf('~/phd/text/dimRedPackage/plots/plot_example.pdf', width = 4, height = 4) ## plot the results plot(data_set, type = "3vars", angle = 15, mar = c(3, 3, 0, 0), box = FALSE, grid = FALSE, pch = 16) add_label("a") par(mar = c(4, 4, 0, 0) + 0.1, bty = "n", las = 1) plot(data_emb$Isomap, type = "2vars", pch = 16) add_label("b") plot(data_emb$PCA, type = "2vars", pch = 16) add_label("d") ## calculate quality scores print( plot_R_NX(data_emb) + theme(legend.title = element_blank(), legend.position = c(0.5, 0.1), legend.justification = c(0.5, 0.1)) ) add_label("c") } else { # These cannot all be plot(1:10)!!! It's a mistery to me. plot(1:10) barplot(1:10) hist(1:10) plot(1:10) } @ \includegraphics[page=1,width=.45\textwidth]{figure/pca_isomap_example-1.pdf} \includegraphics[page=1,width=.45\textwidth]{figure/pca_isomap_example-2.pdf} \includegraphics[page=1,width=.45\textwidth]{figure/pca_isomap_example-3.pdf} \includegraphics[page=1,width=.45\textwidth]{figure/pca_isomap_example-4.pdf} \caption[dimRed example]{% Comparing PCA and Isomap: % (a) An S-shaped manifold, colors represent the internal coordinates of the manifold. % (b) Isomap embedding, the S-shaped manifold is unfolded. % (c) $R_{NX}$ plotted agains neighborhood sizes, Isomap is much better at preserving local distances and PCA is better at preserving global Euclidean distances. % The numbers on the legend are the $\text{AUC}_{1 / K}$. (d) PCA projection of the data, the directions of maximum variance are preserved. % }\label{fig:plotexample} \end{figure} <>= ## define which methods to apply embed_methods <- c("Isomap", "PCA") ## load test data set data_set <- loadDataSet("3D S Curve", n = 1000) ## apply dimensionality reduction data_emb <- lapply(embed_methods, function(x) embed(data_set, x)) names(data_emb) <- embed_methods ## figure \ref{fig:plotexample}a, the data set plot(data_set, type = "3vars") ## figures \ref{fig:plotexample}b (Isomap) and \ref{fig:plotexample}d (PCA) lapply(data_emb, plot, type = "2vars") ## figure \ref{fig:plotexample}c, quality analysis plot_R_NX(data_emb) @ The function \code{plot\_R\_NX} produces a figure that plots the neighborhood size ($k$ at a log-scale) against the quality measure $\text{R}_{NX}(k)$ (see Equation \ref{eq:rnx}). % This gives an overview of the general behavior of methods: if $\text{R}_{NX}$ is high for low values of $K$, then local neighborhoods are maintained well; if $\text{R}_{NX}$ is high for large values of $K$, then global gradients are maintained well. % It also provides a way to directly compare methods by plotting more than one $\text{R}_{NX}$ curve and an overall quality of the embedding by taking the area under the curve as an indicator for the overall quality of the embedding (see fig~\ref{eq:auclnk}) which is shown as a number in the legend. Therefore we can see from Figure~\ref{fig:plotexample}c that $t$-SNE is very good a maintaining close and medium distances for the given data set, whereas PCA is only better at maintaining the very large distances. % The large distances are dominated by the overall bent shape of the S in 3D space, while the close distances are not affected by this bending. % This is reflected in the properties recovered by the different methods, the PCA embedding recovers the S-shape, while $t$-SNE ignores the S-shape and recovers the inner structure of the manifold. % Example 2: Often the quality of an embedding strongly depends on the choice of parameters, the interface of \pkg{dimRed} can be used to facilitate searching the parameter space. Isomap has one parameter $k$ which determines the number of neighbors used to construct the $k$-NNG\@. % If this number is too large, then Isomap will resemble an MDS (Figure~\ref{fig:knn} e), if the number is too small, the resulting embedding contains holes (Figure~\ref{fig:knn} c). % The following code finds the optimal value, $k_{\text{max}}$, for $k$ using the $Q_{\text{local}}$ criterion, the results are visualized in Figure~\ref{fig:knn} a: \begin{figure}[htp] \centering <>= if(Sys.getenv("BNET_BUILD_VIGNETTE") != "") { library(dimRed) library(cccd) ## Load data ss <- loadDataSet("3D S Curve", n = 500) ## Parameter space kk <- floor(seq(5, 100, length.out = 40)) ## Embedding over parameter space emb <- lapply(kk, function(x) embed(ss, "Isomap", knn = x)) ## Quality over embeddings qual <- sapply(emb, function(x) quality(x, "Q_local")) ## Find best value for K ind_max <- which.max(qual) k_max <- kk[ind_max] add_label <- function(label){ par(xpd = TRUE) b = par("usr") text(b[1], b[4], label, adj = c(0, 1), cex = 1.5, font = 2) par(xpd = FALSE) } names(qual) <- kk } @ <<"select_k",include=FALSE,fig.width=11,fig.height=5>>= if(Sys.getenv("BNET_BUILD_VIGNETTE") != "") { par(mfrow = c(1, 2), mar = c(5, 4, 0, 0) + 0.1, oma = c(0, 0, 0, 0)) plot(kk, qual, type = "l", xlab = "k", ylab = expression(Q[local]), bty = "n") abline(v = k_max, col = "red") add_label("a") plot(ss, type = "3vars", angle = 15, mar = c(3, 3, 0, 0), box = FALSE, grid = FALSE, pch = 16) add_label("b") } else { plot(1:10) plot(1:10) } @ <<"knngraphs",include=FALSE,fig.width=8,fig.height=3>>= if(Sys.getenv("BNET_BUILD_VIGNETTE") != "") { par(mfrow = c(1, 3), mar = c(5, 4, 0, 0) + 0.1, oma = c(0, 0, 0, 0)) add_knn_graph <- function(ind) { nn1 <- nng(ss@data, k = kk[ind]) el <- get.edgelist(nn1) segments(x0 = emb[[ind]]@data@data[el[, 1], 1], y0 = emb[[ind]]@data@data[el[, 1], 2], x1 = emb[[ind]]@data@data[el[, 2], 1], y1 = emb[[ind]]@data@data[el[, 2], 2], col = "#00000010") } plot(emb[[2]]@data@data, type = "n", bty = "n") add_knn_graph(2) points(emb[[2]]@data@data, col = dimRed:::colorize(ss@meta), pch = 16) add_label("c") plot(emb[[ind_max]]@data@data, type = "n", bty = "n") add_knn_graph(ind_max) points(emb[[ind_max]]@data@data, col = dimRed:::colorize(ss@meta), pch = 16) add_label("d") plot(emb[[length(emb)]]@data@data, type = "n", bty = "n") add_knn_graph(length(emb)) points(emb[[length(emb)]]@data@data, col = dimRed:::colorize(ss@meta), pch = 16) add_label("e") } else { plot(1:10) plot(1:10) plot(1:10) } @ \includegraphics[width=.95\textwidth]{figure/select_k-1.pdf} \includegraphics[width=.95\textwidth]{figure/knngraphs-1.pdf} \caption[estimating $k$ using @Q_\text{local}]{% Using \pkg{dimRed} and the $Q_\text{local}$ indicator to estimate a good value for the parameter $k$ in Isomap. % (a) $Q_\text{local}$ for different values of $k$, the vertical red line indicates the maximum $k_{\text{max}}$. % (b) The original data set, a 2 dimensional manifold bent in an S-shape in 3 dimensional space. % Bottom row: Embeddings and $k$-NNG for different values of $k$. % (c) When $k = 5$, the value for $k$ is too small resulting in holes in the embedding, the manifold itself is still unfolded correctly. % (d) Choose $k = k_\text{max}$, the best representation of the original manifold in two dimensions achievable with Isomap. % (e) $k = 100$, too large, the $k$-NNG does not approximate the manifold any more. % }\label{fig:knn} \end{figure} <>= ## Load data ss <- loadDataSet("3D S Curve", n = 500) ## Parameter space kk <- floor(seq(5, 100, length.out = 40)) ## Embedding over parameter space emb <- lapply(kk, function(x) embed(ss, "Isomap", knn = x)) ## Quality over embeddings qual <- sapply(emb, function(x) quality(x, "Q_local")) ## Find best value for K ind_max <- which.max(qual) k_max <- kk[ind_max] @ Figure~\ref{fig:knn}a shows how the $Q_{\text{local}}$ criterion changes when varying the neighborhood size $k$ for Isomap, the gray lines in Figure~\ref{fig:knn} represent the edges of the $k$-NN Graph. % If the value for $k$ is too low, the inner structure of the manifold will still be recovered, but it will be imperfect (Figure~\ref{fig:knn}c, note that the holes appear in places that are not covered by the edges of the $k$-NN Graph), therefore the $Q_{\text{local}}$ score is lower than optimal. % If $k$ is too large, the error of the embedding is much larger due to short circuiting and we observe a very steep drop in the $Q_{\text{local}}$ score. % The short circuiting can be observed in Figure~\ref{fig:knn}e with the edges that cross the gap between the tips and the center of the S-shape. % % Example 3: It is also very easy to compare across methods and quality scores. % The following code produces a matrix of quality scores and methods, where \code{dimRedMethodList} returns a character vector with all methods. A visualization of the matrix can be found in Figure~\ref{fig:qualityexample}. % \begin{figure}[htp] \centering <<"plot_quality",include=FALSE>>= if(Sys.getenv("BNET_BUILD_VIGNETTE") != "") { embed_methods <- dimRedMethodList() quality_methods <- c("Q_local", "Q_global", "AUC_lnK_R_NX", "cophenetic_correlation") iris_data <- loadDataSet("Iris") quality_results <- matrix( NA, length(embed_methods), length(quality_methods), dimnames = list(embed_methods, quality_methods) ) embedded_data <- list() for (e in embed_methods) { try(embedded_data[[e]] <- embed(iris_data, e)) for (q in quality_methods) try(quality_results[e,q] <- quality(embedded_data[[e]], q)) } quality_results <- quality_results[order(rowMeans(quality_results)), ] palette(c("#1b9e77", "#d95f02", "#7570b3", "#e7298a", "#66a61e")) col_hsv <- rgb2hsv(col2rgb(palette())) ## col_hsv["v", ] <- col_hsv["v", ] * 3 / 1 palette(hsv(col_hsv["h",], col_hsv["s",], col_hsv["v",])) par(mar = c(2, 8, 0, 0) + 0.1) barplot(t(quality_results), beside = TRUE, col = 1:4, legend.text = quality_methods, horiz = TRUE, las = 1, cex.names = 0.85, args.legend = list(x = "topleft", bg = "white", cex = 0.8)) } else { plot(1:10) } @ \includegraphics[width=.5\textwidth]{figure/plot_quality-1.pdf} \caption[Quality comparision]{% A visualization of the \code{quality\_results} matrix. % The methods are ordered by mean quality score. % The reconstruction error was omitted, because a higher value means a worse embedding, while in the present methods a higher score means a better embedding. % Parameters were not tuned for the example, therefore it should not be seen as a general quality assessment of the methods. % }\label{fig:qualityexample} \end{figure} <>= embed_methods <- dimRedMethodList() quality_methods <- c("Q_local", "Q_global", "AUC_lnK_R_NX", "cophenetic_correlation") scurve <- loadDataSet("3D S Curve", n = 2000) quality_results <- matrix( NA, length(embed_methods), length(quality_methods), dimnames = list(embed_methods, quality_methods) ) embedded_data <- list() for (e in embed_methods) { embedded_data[[e]] <- embed(scurve, e) for (q in quality_methods) try(quality_results[e, q] <- quality(embedded_data[[e]], q)) } @ This example showcases the simplicity with which different methods and quality criteria can be combined. % Because of the strong dependencies on parameters it is not advised to apply this kind of analysis without tuning the parameters for each method separately. % There is no automatized way to tune parameters in \pkg{dimRed}. % \section{Conclusion} \label{sec:conc} This paper presents the \pkg{dimRed} and \pkg{coRanking} packages and it provides a brief overview of the methods implemented therein. % The \pkg{dimRed} package is written in the R language, one of the most popular languages for data analysis. The package is freely available from CRAN. % The package is object oriented and completely open source and therefore easily available and extensible. % Although most of the DR methods already had implementations in R, \pkg{dimRed} adds some new methods for dimensionality reduction, and \pkg{coRanking} adds methods for an independent quality control of DR methods to the R ecosystem. % DR is a widely used technique. However, due to the lack of easily usable tools, choosing the right method for DR is complex and depends upon a variety of factors. % The \pkg{dimRed} package aims to facilitate experimentation with different techniques, parameters, and quality measures so that choosing the right method becomes easier. % The \pkg{dimRed} package wants to enable the user to objectively compare methods that rely on very different algorithmic approaches. % It makes the life of the programmer easier, because all methods are aggregated in one place and there is a single interface and standardized classes to access the functionality. % \section{Acknowledgments} \label{sec:ack} We thank Dr.\ G.\ Camps-Valls and an anonymous reviewer for many useful comments. % This study was supported by the European Space Agency (ESA) via the Earth System Data Lab project (\url{http://earthsystemdatacube.org}) and the EU via the H2020 project BACI, grant agreement No 640176. % \bibliographystyle{abbrvnat} \bibliography{bibliography} \end{document} dimRed/inst/doc/dimensionality-reduction.pdf0000644000176200001440000350253014262570070020730 0ustar liggesusers%PDF-1.5 % 1 0 obj << /Type /ObjStm /Length 4702 /Filter /FlateDecode /N 72 /First 596 >> stream x\[s8~?o;[Scĕ[Seqxl'v5DȒ#ɓ(hRظ}XSII6ei)a(fYre)F x2i3, 2Lk&E#&)2kxΙLimSV,˘Nf`:SHifN0 f{ˌsf02EgDƀdB0Q!YαbTur hra}̬f@ i`( U7I u 3 ]44TWY 7@Ypϡ~.,tqa̠:.40!@Yq\e%s(W89W@Y5ql4N*4P6 'O@Me55N{n$(FYJwAIn ($hME?;Kx:^3o Alq~>}X.짿Bβ|.O,KdV/iP9_WKe@{,!ub9]1raRGb^M;Jp(r_dM/;߁|M^P?a5ao&L{9J`)qy9w,OOs\4U^Nv7Xr>-`;KSڨ'WO8H{ wܚ\}۪))S \M =:\rq(uHXJ.M{n&M:po+w6&UNoM f2`rXo a+F A (; KWAEʨΟl%Hp @tH3ڥ FB,1_*꒠X)>V)XxgA)2u¢ڥ)1s5̽L~K^'ǞMwwcn-EJB&Kol1E% T-DfmDFE$ň|{r|0"aGmDr=6&x"{`Vh41bhR cfB0ϼ:;O#n5f^g>ޙ)3fwk_m=ߪ5h o!]a%ʁ\ ThAC+ x 7H S5xd1ȿ@vf[*5SLk@&%jxF`PbDT:@ﭯ${'F(m7v!ex1@=("9!*9$Ar$y&H9O.@y\&W1kwD$yfyM.^eB,Yr v +ao9Ȭ}JxK]u9(Ȧe,Vʉ )jݹxIw?{X% MkY zڼw/EunU \_ 2vY^>TzOjXɟɗ+ X*ѭ"rSiZ6F쯗ʬbKmaOO//Qj68Lac#E_,ϐq i ȹ4,8cycu,S+v&cݥ[Rx*q%;AZo$0G`x ژ3[͑NF_qZ yJWg#NN捵Y!/etZP--UDT$'F[,[|DZ!,.J\ 4Ao(!uPlʔ4$ &zynMKI*FhX+qYjɿw*alwɽv_-IvOv~_.Xހx|wg- kwV=p ;Yv`ESW{+ ||/Z~xUcҌW_YGiPѝ܏v7Zwrts/{Iw2ub&1ebT_81SWa2>g{XP#rfX(3_m=;E^yN{LJy]#>_u5{e{X/Ѿ_p7B`㸀ː[1O̢7jVw9cA\^Ew9erF玵 ~ihQs&5\1J|¸hDڥym`{9|*I\i|??}MZ'ҭ>o2dqԪdߺFֵ~t]o} 6oa߷YcyY<ӡ<9%Eu /m~Qqnz X}Zdڴ:-EOźrnwo+I#}P(vzmTS$X-"k dbKn1w߽f;隴9hYgLar]F@ <Ǚ)dF@\uD 5(i}Uώ> п Ѿ[sAǷy >]!0B?Mx6sk_7}'IԦ*)Vѫ6 ?G'mh1C>c8+tPx;/hmDu0VxΉmiPNw}GpWA=[2/n(ZЩcNSCzŲmYM0Ts (W9yC fpdo:##&5xHjѡ{63i3q)`7 %TTs+ڿԭ)Ko%^ӏMAxqtX-wۤ_rlě~D3CRF&3p8;zݟm-С)?mb;s5Z)07RT~e( t0b{MOq(}j7#]| WWںUݏ&mVϿr=݋!bKz\*Ldi[voq&VˏJZQB˽q0(΀|n1.8YD>heNM{͂E|&pKT=z^з3 Jˤ6;|@WLc;fqiY>WƝC _Uzyʺ\oII#Ï\i#ٰ ^vbښ71xVƄ}R,vWŇftNPUlLAz1X>alekmtcZ9r@GiWHa0 Vx/h; R: <)xFlu)FJ-sh*t#xGSؘ#R~oXS0&6fދȳ d f vs~ڂg, -R^.7s"A_z+<W'8YSPڕyx&oCUaXk_v6ZV+Ь_8=8,O oaFU0a ;LMچ="mz[HҚ~sp8-lOA7邰vTXLT}3-="%ޅ<\Tde!rhKtr䤺tf sTkeP"jز^@L1fS4hxv<:qk9ӡO?Hjf5O=4fW2}Efvv 4ӡA',nN5Ye%q{\~۪V<;ۧo_]I(>\,8q7mf1ȀN=?K(sXt5\%\3/IڈrjDǴWN cn]~T d|O`9'}`m> stream GPL Ghostscript 9.56.1 2022-07-10T17:28:56+02:00 2022-07-10T17:28:56+02:00 LaTeX with hyperref endstream endobj 75 0 obj << /Type /ObjStm /Length 3203 /Filter /FlateDecode /N 72 /First 639 >> stream x[YsF~_1IVUdd[Dʉ6<@$DbM ȯO qH%vEroK!B2b<"}ă?%+H3$x0-aƇrIC^ i~pi#\k &0p">#\a\WDx_2"9v:'R>aK1:,D1%(2W`e Vj|U0 ѰBHD .#0D(1 VŘ$K2FF3@Q<" 2A0@9 m=@UH صm6p@^Ƒ, 4, \Vp\*6ZKC: \81-@B&|&!P#-GIQ2%rW Y' <_?@h/qF Ї0L4XÌ|G{^w^k:C{:cRۍ><ЇcHՒNN,aL#4&4](%Mi~vif4.ÐfGL'4̗ѳY0IDg~ d@oyY4 4EW<ߟ_ wzhԋ'(Mxs4Φ00 ?_a>.l-dI^ʉIŠ@qNX 4է/_e8b ^Kܨ 9 SCㄈ zCB ~`W]XT?HCۛcm;(6`i9il6zm@puq^}!waK0B-I@ʸ`5mehx I֋-*/m~I.Π%ųE 3e0Gb| Yd8H`}VE.3MgA:]|dQn ]F?O~VܩX `epUTn]1O+mZihHEѲ7}EMlO>9Q2 F0,M)]Tb :3a6MƩ8\bщͰ H(?ZB}+I(\^ARH`8;`e>(\L~Q@LsSV4+:fx^>u)nK:|ޢrx_I*.pw8,b}=oOx>0^xo]77`^^[_ <Ѷ4&yk-^S$Zu45ٍېrqGL0zhKS,WuFv9H{7q0A8=瘣dG[8؄o6a<@jE ,b9Jq+XqcóQ:o\p#\h6D"%E0BAJ.vo*ÀKhajN$x3`'YßFA}$-:vwEvz,Tp}Gw8$HD9\B֠MTL '#_d=  apxJ8w|1=!e/yކ_b<?7w=ꈳowۚ͏aFӶi1}8#B7"v4P80p}dلe}|x,X40[Ca8ܼAϤj@zL\#:hE̍4b=2 Ο ,F  } ,`1Q>-YK3Wyc\,ack6NlwFɜN%=tݰ6CD&Ƒ}t_]WX#k)GOܽ=_7` ,J,2@\R}~>y~ۮ:BX6oc4[k\{8=z FVʵuDG,w>*>(yL6Ļ5WjZ4ikeGl8d7_zroǙ?o^\EU: fKyk:ԿMwTnJOmRoe`%\s\>*aO8f,c./F+θݦqMZL< ,ڢh[`dqY| {e\ݚ-Σxx}vktQѼF6nRO\ -:Z}$Z*dd6>"^&٢A.7aڣ g~Qv*k[g.ju䋧s%&z˷'Q `w)lHi[ݭyvB؅/@5:kdP/]텝TΝpHqnvzm[ug]kn.--zja8W4MmnGh08T4oq9U%dWF]]_ahtT)P&e׸~HֲBt=˰VjƷ_#s#W!CG*]f6lm߬XMNڷv9ϾSN֦9*sad}gC!/.!P|# Xl'lgkieM*zF!PHEC`-gN+՗3Hu kW^ 7yJT°8[Qú_wFf?H}endstream endobj 148 0 obj << /Type /ObjStm /Length 3056 /Filter /FlateDecode /N 70 /First 641 >> stream x[ksܶ_dg'MvƩRdtj!)[ί$Z?WUFH @&&rbVi@׆PZgSLYiPILyKeK^1mxt0B2T71={ό_Kw"3>  5*3h400JQ:CaN㙳4L @\LOHK+J5TbQ3#^$uq,%DςT ,x0Fb$&%PIчJE7T,z4Tɰ$ݱ,)a$ِ~gR<:LC|FBP2nKVZC | '(jYi XIN7$L Sa5|C+7 ƆKjrؓjNF/MbPE 058T͍OO_~-OM/<9ŋfQ/9?V{qR5m`U4F\vTۮnzw씉Engd{UC1J/U~fʤ68/쫯qk%Y~SV_=+;(,YM94Zzwuq2H3߯0?Z}2<;%ܺn}W\oQWŽDCj[(KuſI5,)6|Tь~1rw0zwEnk aTw|:^갫##A<7T<'*FbF |Z4q$e[_6eO gOzAկO-?iq^ [TVvMݑT2G(^?>[tUn}ퟅ(su ?\]n?﻽_7˲cVd.Ӑ4&c I;J yJ3طnP;5='p0 Mo9)ǯཔ2 &(%_0xs 8<|/N$<8w;P8,;{Wjh`@6 /x3 zfp #%XBluف\z ןbaYQI]iR4C"XAq8!)6^ {O8߈G[X<߉TG(ļ)/n]>zCXz#φ}.Vbz*7/Z\Tuͷb[6UhE[DVMYU-.KJ\w?4z3ϠR$[?v}0Cxˍ@⧬pr^/b|)-7]C{|Q_@}c$4BJu\I)Њ9%r a Ƅ}҄prRJ+Kp89_,E2[gD1p .d:i-07[-_,K 58&gϪrmYuēA.t'POU^&)n"L4<Z3zZW|YW B%Sx#N[v12q/h#O܈8%mI(m$q܃M#brl;k`r/pK&0[9Fxr (QM>'@b[ULIoF"Ig>gJG9q XB"+ \ !MLJ0dtJGJ[h =Z .?IvvH(2&ZB5@d&ÚѼ7/^2'UaӒPf>3̏{woo5W^M]6T#R/Nb\tz+o/W_&IK͹2ԏ-#jڏ8|mt^t7dF M&N]].ˏu𳶫lCx^7b^.iH`#7FOW~JēW=n 6xXUn ;Z#s*4Jc0T"[ƽLNi?av6<@PPȱ7 s{,V3i- "vTuZ_3te`A35SkG`Vc@8@3j5RFM)QSʨ)]QX(,П2*:UH&ouA`0{\ : cy7\O=IF3уy`A|G c8pVsý-z͙v0i :{WL&IM[},Ui'Gd׫=ӀaVݭ8"!2̆clF"2$:-۠M{D)~!~Rnz9y+p̂UtXę(gj݂FS5 ͆XY','R.䬒#R׫-Apw툥HB<H6d5x1?_@]Xy5_WPٲ-keW.gigM];~i0?# p yGrHLtYhN.,-mQu5>-;`y;-gyggX"`Y?` :ޘbQ\\f2ET"Lɥ)ͅH{Qo<[I)7S8#` .ob~Ԁ/]Z[tb`# G&&''[8cWtq*]袙9+gֺf?& N Z:bn!?o-vŜVR @Cf9 )[JVne #s7 hy =mrފ{M>!Q#/Q̈́0CbR78h [UOwu( Kk~kqp#pACGX+endstream endobj 219 0 obj << /Filter /FlateDecode /Length 3177 >> stream xYKs\r+5`RsK$N\7I92ɑVC]t F?.M.ՏWGw_rsr<] &ev[{uܧIj4ZduiCQ[lP7(Ҥ+qsz )&ϲBǽ,hdue͙XS2l\~,fQo۷Eu\*SAIbnw0:qd S`1UQVrޜcjzɴ7yRJjT;OpD"]%3 Ĺe%ۅIglrުhofC;?ғTშVZk%yuT׾m*նRqm\R~ޟH@QD=ֳ 61Q ˋ9mbKzӋ Nu.IZYXH! "ƈ,Hڽ%lj8A\_p!(BzJgTx=S|gNCׇoʙ*Cz\^ Bx[b ے\niZ"|&!:Lm>0 &i5sxvzgK!Dz&>;5F¨Ad5!.MsX7lH .ń{~|\nEw~ $y꒜%U1NKgs_Z.&g㔵Ό/d*W&Osf˭ك'!SWlWڎ{/VsکAzޫw׈q8?(h>F"[aSPBNV s8JZddtD~^axth}~+"TsKH,a9 2iX?շ'?HPS…ҽ83F!?ɾs,;A%i='Ɩ!,ųw~z8B[Y[j28+?J)CDP=.54LQrqxNJv ) <"hE7>S}}|YRh8@~?{CbPA`rPϯ\$$ o7ɏGH*4Cܒ~7+ q2d|laVT8ް')/)8PymmMȿÍJ& ~lc.1fjoyӲ|GH,X4󺇰!.o><ӋoBҖ1 @gkf!O3AXʈ [.9H{A 1: :gAX2V  Dtq7nRlz[.=N8hW`j dmXZ [W.? 9049^5`\ d 硽oؠYV_WV@Ϲ@8.m)3_/o vޠ?S4tzaªֱ7b2r/SͻxBE/RD']iyh0!)5 0,K28fc\)?i"āendstream endobj 220 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 1571 >> stream x}PSWo9b۬vw:KWj[GeREU*R QH %@B 9MH @^B"c ֩mٝuðX]v:coj_;=EmruzjzzʡJ%Re) RQiJѡ|lM# %&V:YRz=USԅHD8J8]~ zME݈ Sm䢌S?M兩XbymRG@{@> nn]xNB*(z@[>qn.eO3I~@A1BG"k*"Ə9X['w V#],^z% 4 *'my=%>ov|}9O&bgM5w|V~D2;@$@žVtsbCwU#PZ5(C; +;}GoY隽#`dQDf2R^~=wڽR\ʯHĢ⊈񫟎LFo Cn#NYE՜ZWRl D[una 8! LAHr{CSԏ 8 [#X\f)][SB͇W ;uH({/ELE Hq~wbs{1C-5PL 9dIAeS/v"DŽb@l"v 7)ȕ)n{?GL@>L1_gGSɰ' $z듛؇ _7@杺ߴhHo=XFqoo:@顗"e-mENm7C!ۨdm.^_G츢-.5֘+TNb'C3׾ޓCzXp8B̤eP}jD8v#r܂G;{YS IwXzǙQ{fܙt;MqjH ;`*X$p> 8{Md;1-Ă͈>|hΝ*Qk|[=2V2s|:s 2Y8M&hZ7@"'YA#Rɔ#f$M* TI" 3%^$yՎ\FVED+s\XLR'^ },/5dGN ?w󶤮7C%(y;ޟ~(] O+÷Uں.ETLjyÅJ.[{y{?,i8Gp\\F\d7t:N(|Q{0<'/,v$=T#T\@dO> stream xV}PgȻXJ[b-v{]۱xRV~(a $$> $4"_UTU Uk{sݵ|C׎3>y(B$fNO}񕗖DnalF ĉ!.ڷ f~#=JD,JC+(]qH#6&b3&R7ěeb;"x' DDlԳQ}ˣ$ŸcJA=G$6hcD|‹4x׸x8,SzQv' .R4N*+8Mo}ʼnp S|"2p3npǭao `Uw2[@9EBXyW-d}շ,gU>˱ԹOIC g/0uPGk@`e-PG:J(DLęXW%xb/]d+tZF?ʄXJj>jB>R(y9fDYxVO3j㨱Vk2Q@[т:#T;d;H;zkS%%/TSNH cRdwZ]D] Hf#-pFt{\=نj~(u^HOjǵ1ᑁ5۳tCq $O©H`[:&M͓^q^sу_BP q!3w g@-g^Us>Ϳ^+ZXhS5LI'ÿ$o͓ߔyObk"x&{Yg5iAM>QN8|xd%ޝGlH> n /P-*?FL(;̄-\a3TdWk4v)\_#X3uJrnctͯ~:|¯˔=h#/8@-T,:ֲUAnC[.jFMhLd7w~Otx'JiH+Vf33H=6E36|Jq|B DN GJ3_^;2;kc@u>u$>:v6.h$PuԀAg .u/")⨱S}vlz$nOOG؇mcف,xdxq>Ǟr4+H@#*ng ğʼn$dVcſdlxaK/y\6pHI.gn4\a`*/G (nUu]iɜ}%\ޕMiNS4EBRw s8 (i]a+?)٭dvSV%$~%O'Q؁Ig; 5kխ] Gr;ٻj=eB fתq|M7lx'FI)cZkC}zAٵy9M.sq6w$*ƤI*zv>Oc:? 4]=T_g4(VeZa/٣ܫˍ pP:I4jvٛys*Z >MOR_KbXrai[\2odCLGrFj UVJpaFZ=|`DԱu`!TqUݪAwaIyDB?K"c%ݒ35͌BIGMY 1e=mC{:{`j >?52@}nc[%ҦrWe!9IFW揠&kĢW ,,80ڎ2ݤjRStt)>}w%%v8D*ㅄMDxy_<H237_Win*;DqZ%1mRLn..@ d a 4'/EX= ՂBG6}_hN[ SJUCFȳ(+_&h֍(ނ*jTUN{!&U noic5vJFm5F!+:AjhiHjxjոXqA\A0endstream endobj 222 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 3325 >> stream xV{TSg?1﨨4#T=g3zNulm}Ψ"*Cބ@$Oȋ7$ Ҫhjűӹ pD:f͚nbB L۳%2b+_3p|_ !xjχ`z|Yꦌ̭YێmWFş8,MYrbXH!/b2El"-/_m"I!B11M,;!!'SGN]56G"#J:Ϙӂ-3za'-YOП `:.lod8Ls-(!WIp doG~ݻ)SҙNO7e=TQpL) ̏Bg=|Ch^<ͣsŽ8)z2$''ġ8x%S_30JkЛ 8v|1z:]uyБא~ܺ i"^ʠ\F`s̷K8W:?D*kA Zt ťRP#h@bm̻7.'TKĮ|H9qؔH.88hA Hqk#QnM mukAjoS \.)I jn6F &,RAT|xʘiq0NlҌ:ɬ|wcqғ?.h.ef h ۿUڋ sq$>yȍ.5[Տ{ؓŌ{yniԘZ[U #rlv)yKqw: ^0=jm9%bwxLDHrfݐTdVi4^nKvpb9 @-Uwއ&jOL X5iҐzn7?|*9p#9ڢ@YNW Ѯ-֫t*NGo~mv,Z4upԟ~<|G׳xgc?!ٖIRr$A ȕlFd$cT S؇ÑqTf)TsţO[{ h.IIk<:PfU(˂\$Kм .\$Uf!Bq^8Qd7ԑ sB!=~\q. Gv pLlyqS]ٔ\V ^f&۷Ʈ|VAY Ij?P,t GCocGsO:{=@^M"7OU%K/{iifRV7=cֿ1``OXޱk^ZҀ yjyHUdRS^ңteg)K;]5R{L˭zJMސtC>79pmg+h##YܬPKeNl}0Ld?t5)z.ƃ k|8o`ͬk5"ʆ rW&#R3MH|_kKeדZ>\NRSǗoGu,g,<&p<עF>MF T*{2xYK̢+NHP6@&2,卝a7X]|ᤫLjQԐDIeJEq%Ubњt&d!KWd˗PVZҋLN{A;jR1/U8,lǀgql$cw\ۢ_erO2 ĜM`@qrC|\LI->IIleXh gJ ِCԤ>] ӓ$FqޤKI&?I~)Y.+ݵZtj=`8 y(%_dLOO; `?{oUԄ\DJb2AR!a6gm$"YVz\?"\߅_iui?]uՎx.,d p~/wf!gGpXp2 0sjXBr (Z V·1_rx~'X \ ԷyZڽ@.v) (N$R'˜dOU6,DzSGNxQ\.._@!?vY 2[7Mꂢ\m!#;9-Wp/[a͎Ƶ9Y99aYbуF.([T]r(xRy+_+x.jBs?_ZsFG Rmt5n}/#j%cܓ;6`%MȢJk/~N)ToncM,y*,%7\d7D= 5]X>xOB 2Iendstream endobj 223 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 1049 >> stream x}LSgK)+6pæSpt&EFƄU\| 8)|  hgWe108-[sKHNr;s~O<$A V}`Q%[X?&R!KWo74iJAjT(BTTCO_clahC` ن}9#W"(b6xMt`7M&נ`?FͮLD-f-}|^&^>ܘhWq:lFS`4Hi,iڀ<RHI/"y t*I/0AOd@l1c6X >,'{N"i v%slC$~ycΡ_|%=eҮ[e]MSk{uSM]VSG}˧cSD g68fyqڹZtӯs4ubmsT]DSIOQ`&}Sz;sS6^t*9W?;wvjk9 rlE:N(C}7l]qYQƈ4^D$0IQzv4nr15T/ e78i ?Y/n)P=᷿n?Y@JF^)8-W^[P[nA["fEQ؂-v lAp KaϨO'k.O\^ƧY.P +1}ni<@9InдY.vPRҤW*z ]^FHYX,`iۓendstream endobj 224 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 10170 >> stream xzXW`̸YF6ȉ^$'q7ahju "@ !-qIoɦG{?ur|;D @ ڸlCĬfx2YzCЁ'_?1|D.J޶$%ԥiXBRgh}1kb_ 7$m 8sW_?iSN{rS33\8Ckxb*,x@l &I&b2Bl![i6b11$3( b&XJ'i/~tĘFNChTGݬbFbG6#97&g/c#Ç=yQsq/;QO<̕g'<{||"1$SgO3)L}aiӦyʌf tן3|߃ȉaG}0! jg8C&Gniwr@C9Y R)1@D'm) T&H7H"uҹn^78B=:]_FyY8{;Yl8ކaG&v߼ c5yNΧE^jonQkx{24S .nu~Igd$T\6%{-f.PNͭM`8 tB6M9]+Gptg#c5@ V#Y6z(5;%E*GoC(rMjTs{41,V6Rah.Ǥ)@>OR%ɝ)ͷ7t;5jLFpr+]%┸++mQ+4!h>5$ LOd_+ɕ(-**qxj ,rW2> T [}p'_-EnSpQqX'OK,;9\f*,9kc-7MGwI8%fEsa:&S\x| TMaa G,xx~=p>N2JNZl< UMlDKh- whu  pթRT()֭poY1@E>nO/&',No늀C[D?"σNqQ✚}/9Dʤ mvtov(1Ā>d9dۀ _@jUpnt^i9sl p zi(G$o>_ [9 B:ReWbݜl7 FjՁ뱋K|f+=d綬4RmGs+h;7*B[L4n5Ʌa0N(UaRZVȹ J6a1&y`ޡ"/[V9O(ZQ)K 6;Q `.IS%3}u6B7aa#uB/<}܇i$a=WidJ 1Pq!pw @4jcTz~ V!%[qu.|E:]gD+B l%Bߘ'xO/ eE*E!ptkkOUpI-Sԉht4M!ˀTE lMd)ᓺ ع{v N}8'}{mbࠋd& rT:u8Ϊᬒ < ̏a^8EIRWp٣pTh&XU '`4b8(@@fd}VX~)$y Y }[󏯴?.̚ĮsX[Ve7&hf<ҵ̔UBep q_N읡OOB#Р?`:VM*l>: ɻfD^G# h5$X'9)֕h[@W帯nOpylAާ}XK$($b=2B_{|?^Qy GH wzТ-Ouf`KZMkL곴lr] |#%mkL>XZA*Cd׍6I;?wBJ}zw{dyoJ5ﱭpaa2úkVJ'(.ϕ %Eiƴ y܎TSd` ##ʾ)\@K5r.bScR : nkɖ6.tIE'hcD믣6X0@!CݼFZ$

>;N'v>w٩ڃdA dh%)ȷ'ip~N. eSIIN.Ii-^1(J2f<ȏkA(Ai_rzkxpCE8`u/`w@y@_Ng =/xo^PB(U_BܦOo|xYl+mu{RZPR^)4(l$ҹii*yj-|_(/ZUV`kqy/7E00;j18OSj_@>dkEfEjLc3gT҄_rO?;e cMExmdpwZ [Lxʦ-맛FqS`.4;j/?Qq\b+1:i=i̱s RiԺW9G=,1K194c{-?vizG|y  Ȓ3פD25V5W (ɶWD5dQiǤLKRBD%k`O?Of}?Lw!XgC>7{X0?]n+h'H*y ΢e[Rc^2qU{I񕱼m[?BVSS̸*PjfơIԛQ1s\褿d׷sGLtܿV8W̸ɼFb47j1l2a;ek˖eԑ!_'™nQB̉1e?\ᦏ S:NԲ;T{Re`;9VDtq1@PB ~@{shx"_ɀ^@f\+*, uin署ʎ 2 ! dH֧nXi=~` zK> '3uϰ3$ N/ָq1`Vh4`z pՋ-<\l%nú&[Ϥڝ ۠x8!^X5U|9{Qp{ nWb-܇Ԋݸb$>jۻz;s~Eh؄cBOgфNu$Ա+(zzlDm5X%WRbvwWKnQw: |}%Uyh|Cξ`Zol`Naphܷi&6&*ͨI?C]>k!𨎳܇ )gvBG!@Ϗj8C fa‘ ]?z7MD[U,]RIhհ)[tH i}5[*! _xA݃Kz?&O_Ejis`&ÑhLd8S_ь 01κ eRRu)8䌧ފ/o>.AKq=i\l8XUh]8 Asa/BwQP I6||L;[I RL\xbx5uZɗ,ՖV.rוTUYkE&bl` u/7xrw0 {3}h;(J6tS5Z$ThZzoF 7ǹ hO-8eBatNBna(P x7khl'S UYd)EGS$-V++4_4z+qJ CiPڂ&aY5eͥuBkX<;'gCOn;ww)זEc;>8ir{ݭM/Unk NB-9dqtO}ptGd 7i+Mx,M4y۹Pc=ɺhFI>>c 3˭MVl3``H=՘k| ѻa?L43 BMϥP`cO4눺ĩu6uZ>Sg~ݼGyO<_+c0TW_Ń1xm9Xv*AX\$,7?7K9o\mql Y\S_wP*9Ǩ+ 0%ߎBö'9Un(beh|n3|M8Sk Ċ6RC .x>X_*ɬk:>JJ8(]/| kf{o6(3O2~}7=/#fсtf Yyh`W)R>6~2!I1n/5Ǿ僲 fu&E{\auJJ7П#!\_Y4jnGKW庮fłeZ&PRMٚ{X^T**\K*ZS%7HEifpC[OU+"@%KN;ZEN_͐ 7clůi^zBEe.;TYT*tF^f:QPf~UV-(EB :[|?CX'l ƶNĮZEf$sYߥfx=ח7F:1:Y0뻌2^W#&s/a}w0\obj?N? Yi׿I1N{,:`-OtB0@Se$6y-hyNECjڂȎ{x" ֊Yp8b.~\ WU\[;ՐXǿ{k;OcYIR^h-38 6;SG?^ypp6Q>B z.0f}X.ԖWҝ|haF8,1B%lJU5Vr8 k =Wb2>)ҀVZVFO: "8: :(4Rf%f~87= %S <#!m?0}C?vÏA0w? :]3w9W/il!A1߮& ߅RVa< Xg} &`~>N7oC>¿^Մ2(~ ?P.Q 2Ǯѻ6{ܬ$fJB{$p]o7>W ҵH=ʊZH]YPn2 J &a_G#>7&Q2zOBNj#hZeM44<r ¶Kl(`0Sj@Z#3۞UacBᔴ~{zM";+aT:R]W*[{$ :R+2=>> stream x}W Tڞ̌H]s@i3źEUoV^EQT "{,oV-;ЈZ[^lu֥~?#39ə3yyyxVbUX` :,h?ocGlOC^Z|^CL!N_]>a#>|Ru&EM̓l .rzN&/O1`Q {-Az\ z i kкg&CY OM:;Q Q7x3B`]C̑4[xdAy ?g1hrꁴ5VK}JiFimIaZ@A]Th&֨-Ԑ ғc`6wMpp PdmVB={9!;ٶB̮*2riU&A5}=|I ̔$UCpc9 OOܮk ӆ:m2͜#!v,WFAA:rHt\cjwg;#2DP+ !^㕮 w%heR/V[,Jȋ8XslXC3ܴ-7Zk`@]etRRJJ3(0(lZ҂BuCXZh6hZ-WUB 1y?;*0窳XfSKԥR):\ yE S9ۘj`Ղ:c\hwy3G}>_*!+rIU][J# Qڏ:M!~3m"V蔈ݯ`w@ޔI2rR)墎-'( T #`/|J2M-ۓM(X`݂U8>y=iG/kG'K)\!qqB*'@o)(.*ξl۫2hK]qmIm1{=Fv[[ 27!^`) j:MvnlޞXR)#G_X qKh1@Ko s5V,g^zˮs UIY5q d+^i7\jY,yݹȠi󾖌v Yj ]V`'Lf%1@kJؽЉȓd; M@#J$zg{2!{?*33vDҨHcXDT]$5zFjrwLҩ(@Wp#^ Zuȷ[}q婲!oJmj224̼ro. kv(%&7@'&H|SxtA>U^՗.1ANTvX$DA]xR6,Rqqִ`b^--BX+QZe.TF/u5=|$ )IJ}YLAZA#,F#+P w2Udԏͩ=M-]g6X"A K4H&B D~އVADȹG=R!b+F(2v1✯M`.5Bjb賀)&q4`3m=,~~x޼v\WWz!ilkhOk+dbZRtZ)kf1#`WceэL+Lz#N=e5 mXVuCOGçԯ"C֮+J}A9Z7`2kjCC?őfJD]:Vx41*d,'-X- T=Y`\KL E^ܺܰPk>j8 kb+dH% حˈAb=DNbRh>iz'76lZ}V8 qd^SC111"Y }3ŹU0Q.l?Q STvECS/ڟaxrm`AĺK9,"f6 3:Ҍp4EPVPKH4h굨v;[퉇y聳kbTcS X =a~Μ?sŨePW-2:]%D"W!V{2v v@kQ4`)2M׾ojj4EDj9xX{Qe-qљ-u̠11|=-}n~> stream xmW TSֽȽVk+1%{Emku}N G(bDFBYfŀ8[֩jֶsx־VJrWsg}x ^0xڌS]F WΓ0 Weį8x+G^e\7$$$.ږ/ ȔDDF^zKָiN1s{ƛYd1& b>ff:&e&3?f13Y¼3әLf,g<321^ɼEKeXFbi-SK=E|;[?KA/ Z4 :ఁW_9W_Y/#7^ށ 2ޮn6aT[kLu.x1ly4$:3cY3,"iȁ8LMBd91A|مs޾x nw9Wrs&NBnۋugaF{' K׈I鳯a9 ڎ֤}PEd~YƧ猿v8%<;97:Cdh?)iޘ'i/s8xɨI'k}#jQOjhh/mз2HABvu|dJ|TvDBDe=z{8Ln38Ɉ'>_b n@sg(q:̀i~7b*mZz%pj~~.Gd91ћ–,Y05ˍ~K9gjɃWt M%LQV^_n(.jIhDK0梡ܫoJV^LpCpCE'քdl$>JۼBljڶG] Pɚ.vq-D:4,h'/;GKt#o)~ 2uv\8u_>86Cp%t>q?ƶU!E,/~unO/k="yCCׅ,-N{b] !B[$=N*n$y8Wг&ڸ$IC;:ю8;<@7/ߵ _ Rf8mC99[[]"_)t)S,fvE?j%Wηݏ$lɰkkKI&٧r>/hEJ_f2UHuŦQYڔ)O8d,C> ofv<2GWyj;,_בD %d ]!rrEl.T}Wg9p@dKp>ÑptMTڸS\̔+aYl~ ")RyiDx']5 Y7$Ωl] b~gu6h`ebNſ\z.6KYE~jAn){k ^qxSZ@9rGq#ܿoRqMH~"*Wƌtkoɒ,7(ZsM qTHoAUK-!SȔdJvvUjj쇓{^HU2ˁ{ab;jd4 XO:Gm;BJ琷֖m$|98 GwO/z\ZotS0{p][ZFPH뒥Z9$1A't%`Օ?2 df!Y7L<݄~hvC?-L~p paCJs<==.vV~ jX cs_&*q:wDo N{n@K95467AFXYإ-'u#G"A]m?gp`4i‘^yʳy̔?@lb[ʣ릁xXM/s_Hܚe2ʋM7=ʚl6"_঑Btxhɹ[%b8^svY5gd"-RhgM%d?Zjʬ&0Z[\V42x8H-i%: -eegmo_EkƹjvZR.4&H^Q'5`Myʋ8~Zߕ=[G3[{Xփ?mN t|K_lwvJyJ3j&ܾwD{+;_2 F= &\EE!KUP 8@憬ж[Ε䲪wQUkW(BҝSYF}GYqhR Gt081v aƄw5w%6FtxhqםW--F[AWH7;E 8[W ڮNEVEZ2~mD-Dg;TЖm QCm?R"rި!3F"&4'dHi6v87"x+@_eq7&12uUw4&OOSO]sxͅMf+]GNUVά1h5ӊe (2Ŕ[E*FGƗ¤,-k.!uX:8 RI aѩ ѹѰַ^ȳBg4tC7p~+##vA+קiSS!܋io9}1kާm%vł҃GC" \B.֓B?~0a8]dibN8]Pw^\IӁ4SVOƑBa=p @a`ఐ k;{:ĭ,<43?T,%%fŮϑY|eT̔ qE?;嫰Xq~/m\1Q[Sr#i4 j^חp (|zwl8':y<#'zОˣwܺ-踌 :$˄&8 N:f,2M@b047"?2^b_\qS(0=gL(h5 #BÖQJEJeJERe|&~ɭt0%:z2ԣ0endstream endobj 227 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 7398 >> stream xYtSW}XщƢ=B%01lݒ\dU^Yݶ*Yr މIH 7++a̚絼,={9Uսc%1oFFF nWޡw!î# G3RfJ }vFT\xSؘ- .ڶ}I҄e+VFָޞΤG 5z`F-^QPW%kRuj5ZNVPoP+U j55EPPcT&5KQhj5z&R wpK xԟO QTO*C S r[tOB7trӟsHt,}9^_;om~_/8^ȍVX=*o<;pA=!!g1Vح_a5yn?\~X'ih }3,8LFg]FbN14J|~aZyZbHZjɜLQ +k%ЈUhDZښP+RbKB:[]HXx;0D` G.D_CEp7f%^u`saC8ܶ s G?^`O 4sRl44g[U.7dž_kA"}#; :ŐQeA\:^*3B9#@WW4񏠡mmA6Bi^ؐ5%8[Qa.;#ʱVTwT`)']Ds[mxa{ ߆r(7!!ݧ*8ݏde<.4nh (ᶡ^o"dv0x/QQL˟U,3 ]z'Y^>rv'+;eVT,4^“ Їh0+bBl,$gk/އWlٯ!NLl7]BـKN1ph'0r H24m2B')ü5UO[@ǧ= lMmEʰeXVs6-ތ"u!th N}ʑ3?7Y6hqB!?6n~Qsk%{lpD#5\g4O Cq(~!!I ̶mFC!tлJvZKkȂ'whr TT5C%C8&lk~ӑ"F)pS+8|, :;eq zWgu}Uk/p"<0p1p-rNf %uezr㨋 RY?j!ч5[Ms$qH ?@,}.]XdL‡ޗ6.Re`?@zNfPoxZQkYa]C8)HHh Dk뤞';Asd0 tb@p~0D%,ɭuqmVX`  2{_{G7 r :|E{ W$|+f!=r* f{p[vƚVcՔ#vloM4V Q^ҚsؘW!Is|d+FUQ^h1f`~%H@( ɯW)&|]kv ,~c%蜦wR1X ͮ]?o\@egc-."fʳY&WV*_ie.e׋wFU]w? 7I yL(!Jj$BWZe^̸ b4`x3 ߢ*RЩq|u&'?WVSHZs[%Gz6y-FOG:;TG؂5hM_7uZ }q,ҘVSG&QSƚ)pGe?}3}Hl$jv0]r'}w%xKvgUזyue Cy8{ͲyZZYkQXSl$ߝRZD%KT 7kWtڅ7D i,EU\:KȗN$W[>̧se1__7LjrO]U7P+XINLWJDDu*evXK=>zw3lrE R,09*J*+0UZz$Z`?k܀;o7?A.i~]WU.UK5269*mvRTG);ϭ]\ & Bꩃ]rx9afԈFA^^ SԊRO-co{;r(þĻtqǵjq4|2Ndlٜ0&E)] g7VH9-p..ԑFPލڀЖlPGY:Dƀ"*x m[%4JIR|-_Gle2K-~l:1OɁp Sggqrଢ4֙)/'u a>NAsOi7R(g4&0ӨՄ)hMWȠG2(ͤLfBz,֬ـf;N1ꇣPo<7צqTh9YK+ɳTZjϦ@uvAs@&tOHP%k(qT:|MoExfq78@7h{9#[:b]vlBj_ 2L lXxZ״oez\2qǙ@j $wt;r\o7ѓ`UڥofULg7ϝޜ#yQ>m4Ѷzc/<(q& ٤䴤t:`":Sgfd! +it\? wF3ŏ‡\|Ⲙv4apŴw׉1_"0@ryNu EoYT^KZ,3gYsW'g[|̢vcZu4KVL6oAU|I\IDΗnmHw\"V_o6X6KAXשBNcd"滿3_w6w`[>_F8Ifl7f45ntypE\}a4\+wLwt<378Eqx9ĒgJ'Sn25GChQ40 D Z2210Hv= 䵸Σh9SǽZ0[@>_Vsd-Z)TUJ^b9ފlFuEA9P H j~PT&fQ,E6/alQi2 9}H[)/+#cLJd>{CZXŰ d<s~^a }{<>4rj]w+lTQ uNUk*ʛnFwGx$~oCQu2/f'\"Ώ(Ĉ.`5}e`!,2vEI|e$^%ھW/*Y1sMS> aS6a]jF4gU E6 q`" "y`GV"LOfzN:B;Ĺzŝ涝yvLx[cbrչ@x܇f<^;rdbgKwe~@O|3Rp<<ܶ䥏3PkA-\~d^@%Ls9V6FQRRa!6Ԯ3%qyۀv`xHBw/dKe2H?)Övi^(0= Fp h0NLԺ Z\ptDrC] ~s<Yә#+yylL~T߃x{ZtV\;WPDDoB4EQ0xmjjAo0 Z3:Z^G0/)op4{KDh,+cTQ8 ?(.\z?lTwHh';Q?f"j= *Xx.7)%ݼ%tG0=3 `+24avjFEfMWZՙE￙8c;];K1R9Cf:W 2J\ahEmq8Ax/=Of&WgՔZ bާЂ3!EH[*΀aQ;A2٥# w*{'k+{~ 9o8\#JuJ*""ʳ]#+*7'IsibJVaQ5H9p?[y:%CM, }t*LjsezgfLТi{=a^w8E/ qendstream endobj 228 0 obj << /Filter /FlateDecode /Length 4314 >> stream x}Zrd=vj¾&y!9y4>b7$,=XgεPMQ\^> OMp{p[W_>|6Lo}e oôgyz>ۇGSCmۏ4ۗe}{|[F}͸NAf~|sd)Npldx6F=O,oi"}h@\ąUϝ/9LM?N؍Nja>VJe]ss@TQ"|6o;[0GEPºwAa̋gB _蚚F B=%^vQ }/pqYn>8u2*PeL>s:[v:U]487OTtҼ7vZet%șΊ.'\6=vt% Eߔ ;yjNG G^yiz;> mGV}3r>܊v*͉7&}-sK)@ fPqюpwʙ崻tFƢg6ftr{h ) )vK@q4D:[]@mIV%Ylɝj[3Na@-Pq:)x,Pۍ ZWTu,~<HuNhVH~S)PFA7L/\y[{{WVA;_\; ."&S 5k!.7bAq6_ I?/:NȜ UСDAm_Ǖ4]TycuIc IҾ4Z#,X YYbN2DFXIjK*KAzY"N y98`؅Qani_yԂh+HTKn,! +`nT!Z JrpҮ?%aH >%_&qyK:, +56Kݵ}p\ gΩ&]9 7Tƺy54[w JzDK,x2<:P gPpY(;:;(j Ms;IPH|z<c:Pb]-,[p=HKbR'V,;,AV|/̼Nӳxج$hQ9, 1甞3wj:0H2,f35?8e"uj`ue/1y;PV4"_V$^/]Q.\C<& '~FR}._};t5IB:!²2݌ k ㌯=øj3Ĉ[`п]gd{ˌٴȂтp.bƐ?9@l uv<}L3r|-sjsSFe yC'tTk^CԄ ;u-JeJcٸt]m3oSVW%=xG^!؍7z`Ƃeq_P7OU$m]D'qx r6YB9Nj̵4O$אǤ m7JFtlC+mQ'ڻs&)lSeF~o LIYk:{״BӀl ")&o$Ĝ $=У}—|Cs[t׀X -j"tAGX$ zǠEq`o{&i3Yvi@<(煪|Kq"l#v&Ń s<ӄv 9E3GOiIӱ0bD;&ڛS!싆7 0MK)HљJ{|FP , 2gWqƀkKLX+ڡ}4m`X2%Db<858 rsl41^N^|Y ͂"p\ph]SJkzG;aINH;6L$\h֬sh>Gpvf'2 @A]O5SN-KH0EJZ0tx`^vyמ_)H@&~l](=[9]DN<;8f%'*QFC Q8(ۈ+`prvQ{qiƜ.Ot;e$|S¡x 厀>ɄU^dtᔒSHUǺJ4x,yKe1+4ˊ+E%3UPE|*-l;RN;4`xqQ?1ؕV,@i;{GnM<2 5P((<=$,?9Y)|3w4̅)r8Kc5%J"s[f ,"QPđrǨ86 DYT I~Hnq AޯdFDHU^)(~PAX yѱ)J^\|_.xK5%tg"tRӮY grSfۮ8vz2vRW=`LȨ~%:{'UAm|1$N"-Hcb/3"+0>ʇf gE2v[<4;iS\H'FW3~vER% HSoiGBWaG >!J|#"r[\5PRy3!R9lC|7[Y4gI$2ėHbaB,r܂WMT6'L-Yc㼸QeQWTNq |e7EԌ j47R]7: FLb~8g1dᤫ~X9DzoINBԸ.5sӳێbf˖ӎcwيjRԂdРl&{C\lk6 IU !`:Eo^_ZEC$w, C^AfRMM$Z1$'LsO9vIbdgӆڐ*=cn(^,0j. 1"@Z:d@D@%e@=RZp~M$ )I ^2̍C󓭯/H)I? 7$d%6}K`?~A[1 7{*1kOB<\=k޼͎ JUvx!mrQ\{k}JK3ij$TXy"Q:W$(1O6:| r\l\BT(}lDm7"v(LBxy9j#OŞd&F+ןȱ/ Ն'ukw{Zϣt5P[#NRMNc"G+RB/f`4i2cm߻EX&2"4]A[{̈lI5=1 ْዞTߺꕵlnteIX?/Ţ اQt ,Brge>0U\VS {HJp`ŶjG=_ O21 K>ή:]cs:+\B F/EW>tBnP\HMǖt?ՓjENDbrWCp iyD?R%Αcyr+%z˾KzW[_kg"+%K-HDMNպgc|s8fq⽆kqRWQ6(+/K)ӏBCDN&ϰ _9Gb كeۍ06` #Qr '2( %}Q$h&=t?endstream endobj 229 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 5693 >> stream xYwxTUڟapQ ͬrVDE]\ii!˔Lg2%ɤT=TA b˪w&|L]]?w}$ϝs}ﯼ'\q._r3>QsC4TuLn;|3* M፜4.HeyUe9%rrs wp8*ݴyq+Y.yVf5k )Z_'f` y+38gg&'s'g-.:zν 888s6sfs8K8Osr9 䉋&:up }&87|-[ڧO&xa*L՗Od3|~[-Is1.Z& niFh ]%pz8icf83eA_渂(ȷU m]`& YF 5jmBA#NB#0jP]fqz! z`ÿmɻdE+<G_gVgHwWksoA*MWSb}%C3|KJYhNn 5Б6`pג!ŊrYb-Y1 DźbC0v3U`oC9> q۹IGA 7vGm(P 5 ejRuUWT姭n@Ȫh.c.6zqm!83u]'|*/5$gjB׳1j`frT^j *ZMCHG8ZIzCt$uX+a&*Zuܱ#T bL|G,ivd@5F_LK'M\~gm=&@y3A8u,c\>I->=_Jh eDtX GCīGEa'Mfj0*p|ZvM5T}r5L;G5IUCMmm SG+Aޥ : +jZKl<-wf2N QvUPhhO`h`6e&D1mggְaLh޵wOvQS1 ťR[ &b3 }3ϢYChh2u|}WhփRkA'vt( ;$ЗZ;PdkFꠎK:Khet5T+n=B4MAwYqnxq*J~zk][tԋG Pރ8VX*\S+.8G[h@ۢ]CBBb4mC_k *=G,. HjmuK_{/dVjqI|na VGHOn_%s 쩞~բ+,ŝ&%fǽ偾*}@6*|6|`S)B 8!J@`]+ݽ#&K68pMh'?$1@LHDsKCO֬9 Ruj[,vCHV ݭW"z}F?{٣sy&`ÛڎǸ/Cə5\> - J5r';'m6_ѩ )Е5 _;fzS2=YxsVUm>F|;ڋOEy"K‚KYH F I1R(FQ L Y5ggksm%L0haT؎ lSJ`_B t+Xjj̬MXVɏG J{EW&!ހ6,Rȵ*=i,e {Ļwn}p!z0pt D]YvU#̓N/"nL5**Q[̾F2KVH}Eg Zm0y@T㉨#ioޔFz"YX h=TC5SRm1TY%ߣRhL8 ۆ{2oaTV] Vo8 ݐZ)ߜOW XAlDגv8^hVi ar}.B. TASZ rhf0'Ɣ"A%vp^F6b Zi+9џjm+EkW,?/Uw~WK>%+NX)Q}= H#QNn @rmGMgBhtZRj,\T- Ɇe '< b6Yhix:;6#KR=#!U??dh9ۏhBv:V3腥9.EcƬœF T&MAЕŢM9O.F̦F*~B"v5E"rzۮ%;wo2U'\AQUtC/|X֨{܁7]ɛy*&?]wĆgoc6|{Zw4֒#ح<"}~Sc1.KĠ#I/>t_*Y$&5càF1)&OKK(.n≓0{XMG #gGD%@TF-jiK䟤Ʊ4b4ß$O I̔u8|ʏyG(* 5cؗ,u*QuDmEbRCK^O,>/c,`E3Tn VqSNqhaOy(o롪F > C3qTnApTys:^'Qx^Y:+}D_Fe${ujX={J$Z2u'?}h-D2=$>% ,jP^z]?FNgd| V%T',Th>V OxQt4k>dnl,;H'A>4]BK_j P ?u}HD:;(l*ZKbXK}tk#hB6jO]\`Ր lqat9& n?ڰihэ&]Ԝ=UaxSgg㔲ǤۃXL$*r*"Ue%QUdw\ YA fu eAqYyuC8U9Fx*w݌5c2lxq<1e54H*gXO|btŦI3/RgNW+W Y0帡&9!scƫ3U.6onO8+euZ5wt 8mIH9Yՙ*+kG%*6pw;ih[6gRhDTer L?'KjqD6#e`k{TM&ger1 b][58>ja7h"hA{yTĝuALr 2<^8 ~=&ǡ{{e X].aqa쪀1`c fTk7Z%(5nGSmFY(/l[&4BqDv\OԽ)}{u +z`x<#G ݝ=tK}N* Z%h~+[9|gK!r@W[Cwhl zB6wַ5ڡ#wꬼ--r\!J$mD+ɻ^% =(`Vګ`[g iNƒGX_+V<' a>$'BM!Iog݋a^$Xlv>{MGsDƋ`6^t{ { }\Ptj՚LzIʪ,boҚP:݀PgvP8w!AGߣ;=UYjO@׍,6i"L&]np}endstream endobj 230 0 obj << /Filter /FlateDecode /Length 4990 >> stream x[ݓqOq󖫔B+ g%rfQ7NW⌸+ZR_hfypÊ$hݿ5ib?z&[ZKNl'zv?@0ubꎛn]O]UA]\M[=4][Cr.E5& ״vfZr1T8K@#)8![s &q|ߟwu=٭m[ XBM NtC}65M?pɡ9CUE G%?K2`m nҢ(f1u /8CavN:is!2}j!bs+H Xyl露t hϚH(wվ:ԌON5ʏiW.A(b/9ZY]RႭ8tů|Gw`e]p3+Ws@{J1!&ymνL<0H&I< qM.y~(byDm<"ta8~܃n $!!,uxJlK!%-..Ѓ#-[qF5 6`*c_ ytL.4Q6ܓA-{~/ a}v\aRJI@aNL/Erq I9L lܳ a)="!ps0:~P[z}DPRrV҅a s&7ol8e)8H6O)C$9@vh| X{#{a@1uDq["3n 3BN:Ov_ywM-P2 BnX-yݰX+P@\vB'1HwTu%g")V3DOgvif%cSS Te>0)4ҀT_)tusnkpqW{o Ѿ3bDɉoZAB{n4ОH>Tk&`{ WڤE$v3/&fh:d]O*>s8$;:2P<KVq(:.x>CxނQ/ro6@9&Ǽp!<շY77#'Jyj3էW#)fK4!01BxLRhHfwL,C'?y퇆X?/ZW]{ f4< oD^0(4>m%m<ҩ Nv}ӝ>Vl]%<;>s }lL gPoE_&ao5}AA [v 45!t!1'\ֽ/|N;9RTJ ;0[gfS0RŸϟ/J{{M.s&rVxⲵVU >z?^O惜zxo8 ) g3?49*$  * gWh5 sO _̵]XJ|TOa3 YƳ&)R3&=BA9r<;ao+e<3i037 OgI$0u`w7`~E\Y-幯;rU#wt)`=xh;32IX̀2l,71BԀB@!>3R}#^PofIa_^ + *ED#.~tGT B?k` L[ᒽ:b_FY7 , )װnQ M;A ʠ K^bZ[C=):Ȍ# o6t|LJLAn`1'C*8_TL4О{h-MOSy \ӫCVnyυOo,[geʥ)5i,d346S":Lvl2Ýu.1Tȇ;.c C#C!0 H ꞱX n+%T׋q9"X91jdʍV*ө ְuA^T2IZd\ >M%c>~m&y :fޘD}šygNht?pWz@DۗP$@D;9)2J)i.A( S..=)fV ש_Mȵ.#f(F b8V`۹RSxbyCNSc}h U u,E갂O>^ O[`6D2ƦY&Ɇ2Ϳ${>]ƸVRx1&#_'6&PkawX@d[:)t\1-!ci%f7p~*8CP 6}T./B8ЇZ0Ue/`_XM_=wߜ~婢 ;:޷>fF|yNWZ0&P-~?W(IJLrQc&%$JLUnа>/1տ-@t~6m.L22Lz0rq1oN,Tm=N#<ُ4hTb6#t֣O<0)+HuboSsp}( ·5T WLym mSp~e37A4 o9cbjgj ,2܈*K*%~H7,"}IwΨ DܐT_Dž;)*К9ag@kE /XGkj 4jQW0<^ ˛h+`Pi80ԁ4b65:X%Z50ofN}>J'ͧ ^Ȝ<^L[N[*$ [p?"(endstream endobj 231 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 1731 >> stream xU{PW?B_!B!+R|eײZetPAa  (! "#-H.tjwH?ϽwyCSMȘ߯,$@%|X"<ͯ c22+gʶn1qsER*z(JL) EDT%BQT&ozcszy{~_ſ-*$̭q{ܛlt,J[(-t0ў zǏ"^&ȏKş^`5_&nI.g ԰G":.8}! t aTM!y=t `d^z}$V`Ԟ0vt9g5(/sF#k1Fij[ 3Fg6 ԽE,V%') Ҭ#..XDo9#0iL ]*>WOʦq{o6WAMR`#G{~KXKt='ћe>O4i++յz u*H#Wap5Bq;V/QuKa4k+uFy{y&F[Fݤ s <m0Tzn0 Nfsw<*2C͐(C܁MZpHukKlq L}:U%`φDmؑxPJj~ֺłHa6R?a{(Z WB[h rsܙ!t횙Öu =F.][=b<~Ϛ:"t@%NIK$mK egbP-Ʊ$Nu>$,4h5ME.`$W#40M" $qs@!&[ijoz3\_zq="/}CoBWMу <|H6u:mm-hH_\Pp@ѵQa1ॠ9YL%l ^>.8*J(8(0C\2 $2n)I-gA)B[@"oSendstream endobj 232 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 2125 >> stream x}lm]paj+U&t];u%҄qn|ϝ_r~;1I B o奄 jZ CUٹt96~N=y'U.?{姵 zJp- L|cwg+o=}y|-jΎM?v~$k! lVlNVBe%V,Tҁf,ҊRQ(>Sw+#ΫC }M(4 6c{B hqo8hq Khn{3HHxIzSUpԗ d'<Mh2ָ'MLk/ a@bƖ&@W<&<>uNI͵Mb S'SJ%l:-$|W5=Igr(@]tbt^5VF:nШb8w8d x6eb~- :5@V/HƅoyajqbkM@nQD #uV$YXϲQP EQvxaf4gOdr^*H.˥afչ)(uGW<+^6 "=e1$TNNB "닁`텘_r:ԾjA%za㶭7ިu^оciw^?&21ljܣ'K '..8Ѷ]/V܎uݐ >\Q>_Q̅4^)o@RfyClg+@D0; Y2ٲ0@ءcΈ9 *1⍗ +E/ T9 1>Fm,*cx`NF`uXoF7Oo2z&=r+f#d@d5- !Ő ).UEޑdX-o.5H[x;reZmsXGrp×kL@P2va$Qau1n?Z9ԴߗBbB 3j6Bx\T按.M2\vOH8 {þ$LDݢJ9y{fJm}z!]j{xljDhS)BX.NHSw**Ppޫ(FNm02:>2_~OiRf}$ѵ5~`P}J>済7 ztXXc }.g}|̕kƃceh)%Sr^^L)C{Ѓw6X==T'.E" .簼*9zKli/x*nUQvA4kOw4ӂПIŚ*즺 @cvS܈lie0x1(cZȺE~VqvV:E[P/o] 'B_ڠd}\3vFtL_X1 "4kϨ(4I;㑔oh 6 ݿ3CM)]'=ɍ9uoLnhX/ ?$g'/2} ;nG?|"qi{[ovmJخsJK.gP!\?:Q̛T V}̙\>cCj%hfY_a@mp:B(k|!SzZ=ł2H!v5, f5x"((c1>JM!|pJQZ%z3sL?+6U'Ko(%d9m|?/% ֘Oc|S`OU^OAסzLOjPendstream endobj 233 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 1029 >> stream xkLW,;n׊N$FScB- $"$+Mp"kdѝ9,@܅qBLڅ[bSjS*JRR2tS&~9NC Nd:]<^5 je:eѕwfʙm{Fa(E(V5E>RB1 $I*&'nU7O)ݏ]ϱ}o;>%^ZKcTE%j{0wMSy}V<˦HV2{ƍniÁ؏85KOAfL|·Zr:YZJjX{j~Jn!L}8 ! hc߳g]+rԣIZ- Բ;L@SGOqT^p"fn~骴*ONUQV.ϫ. 5P i~׊folX:(. Ds#pEk~r0o-)ROi-U__ pOh )*7@=4_XeutvtLok͑ 9>O6n\0dy3'&I9H!{Q'\~M?, ߸H$ݻ͸'sApނC -Ψ6ݹߘ,oC,X Ux5Xf4^%yKIL-v\o+>޹q{v{?CKDLzIgxihEy"|*G{*̖#Vh42U jP/B|=endstream endobj 234 0 obj << /Filter /FlateDecode /Length 197 >> stream x]M S51l Q/@ahXZ^$G>64`,#>.f}Rͤ#igU}4Wۗ'^MfDm 090)j$"*K*lآ,JQ6K}`U&宬,+0|j)AXK sD͐bendstream endobj 235 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 529 >> stream x5KkQs:i u^t0H]+.* m\E$d:MOQBbB- (nEusf: 8x50??`YG(%2_{3D< Wt:|>Ic!{˳B+\ (ȅnet׺LcƪX׹=-I7"?x9> stream x]n <oCd"_Km/@T9 uv,}-;^Ne^mޖIsI˭EbiiPMw| ^ʛ uۚZCʙchWnuLS{L Hn @ߋFTXhBub'('}Fy0Ho?šD*QtB{%Ⱦ#(oQY5^OR @]tY|{endstream endobj 237 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 1310 >> stream xLSWߣоuPlos&&##t.q! 8Ah=(`E` N6":t.\2K_f&+!{e-qs~KSIMKdKv)hNT &wg-W(YHIiZx_]VZZYQ֪*k+k+U#GեՉF@ETKE˫*ן|v*J 5@wfBm"Lo{>.i]eA1dhoB :̮ov-ruqJbB_ս+by;'QX C(4R.D Sp 0-Br]‰KR7T=[J`)p! hGF؃DllS֯=zB9D$(%P(>?T?vdz1Q\ bM6J%D?X]yxiEksw\Cv9i/[,"V}?VO&up X^F&0jmi3@~]Lw9t:AC0"tmOxՠCoa:@ =N0h\|LLfhitz@qxJ*YGNA]G Nk]fE1xK^2fH>n.gV'O >rH}RS_rMendstream endobj 238 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 352 >> stream x;HqWz^v8(p1ZCDАdsDPAڋoZy٠]O  Zto ~ʿg,L%LK@W_KŁbP)AlM5Cp2J~3f̅( Jtk_ƛAƇQJWNEr@<EpTQCזa6sC1WkT.7eUy׷~3Y\!g7]iׇyvmA:VRg,Yʎ_\,OC Ҍr1nʄMG R!lA ɠ.(1e4Ii%!p<wOCT} r9dc?aendstream endobj 239 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 8126 >> stream xy tTU !R h 22dNjRy3@1LR!2$(ڶvu]c ~}]XuY6xQ2yZ悾Oʇ'ᓏ?e͞VU3kfs"\yME,|gmK/ݱtyY(ɫFy}?aMy׎xeH -cal[c˱tl8Va3W,l$6al6-bObk|ÞXlV rAX! Fa}#أD6{ {=AXά^{kroo^<;>CF+R@~GcnO{O>!x'?ٕ9S%g?2Q0@4p3 :V8|f3wMi`zp?=;ٝC<'~CC bX0?{=kXˇcRa|/::1j<2A gUl[a,Ҭeʃq>:Jth@L&YU"FlF[]<Yۤk.G  H(%ڲ+ۘQ:I^B\8}] KM`|3 .NLg;\E~@Y7N0+p[[-qIt&Ms~ۂE&ԑ')˪T.Se2@qR*H4ãAg<.uqJS_vAn׊X?}>WNpJ>ߧHP7cu)q(.WgIVl냾q8q.zRGad:[R.+e/}l6M'mDm.;R9HW.4籙#*ɽyH:;Lb }cʈwsкikFf~U4HMOw7l 7*yuf 3yf:C);a^L~Zŭ5lZz|5RvI )ϙ# yHtn =`(K۩%Č7,㆖QVA~#\9 QK3BB4|.x|L+ E>if5 A ] 4֣F"2}'ؗhbyO-pm/Z^v[29w`]wqNpj#p F /^8t@KVpȶCюȥI /P-kAm4%D6TJ:5m)p 77-] |v{Oa!@ކ9M?| %F_J`kr_2wL>S@v}zVD(_.+"U˪dҐgd"b/QW|؞&[rIb3ZT*-'ԇAp՚4 JTwQ[H ?)5*Eni>ɬX+޶r" QcqTM7^6LoZ =rT)xߞ:\cd5-!c4`UlwkG. 9[[[<ѤЎ, !g!WrPgY@C[ؤب޸ *87Qzk2kBm N.ipA85M#ƈ)ȣDSigp'^jvҽHD@ܼVBp  >|^x9g'f!rk1aD77[N"|NX[-==>ţbX<;]kDw6^PJdP5qXD|m *"Ìlo (0{, _ 8zoJܨS|=ӕuJD$e-Nn] pB2З9w682T$j1_"8eڤrPN <+bNYh*j $l֚pbQgP7/)w<|?A:4! (naK`##eeϟGGZ[i%QU$ϲ &q i4N|\A|E-Y X `%} eO@iP\ ȹLK_ uWtV\dnY#J, 7BZ3$"pc󧘡NKT@e费ȴWEY,3ڊ~-u>* {oy`oEK"DGPzz rp)!B6 TJeȶi`eiN ΁-BA ZXԕiEH1W# #]}\(A  –9,Cej39{C6CfpboW5+ܛН凰, 0HT\AJآ.3!u *8HFːό Mo!Q:-^@wЌppY/Vg4lweo/|nM9 bPZPggN젛-]Og~Q%֠%v EB=%&Zs( jkԛ XQ9ն1挬Wk:LjHW#AF5{ ʿ#ͻ6t}B#q6X +g'*ᖫӒz%^j͙Dvaִz cIaxTd=|A?1bfLNgD$ >Iv%dbH{AuWfΘvIJH\P= }:cʹ83"kD" ؕu.pesk4шZA\TN~ N^-WrcSǕ>s˅wQ"{}󂔽 {T5HQkVW4#Hf[~[{ӗW~. U Dp$3,Dǁ3tA@gr!Bޜqb1@nQa&nHZb=\No# "dUU`RDdu5AM _>C2BEXL R{SʱIQ<,.g^5LWr"("of|E3(.@ɻ;[j lAє<^vU؅43 IyHһqefHI{6% f-\ EB23&o| JQxo\!zp1G'wQ}`ˆ'ȣJnh24[-5Xybl>8Y1#vS *J)Tc>o8!uVL-)f.AJW7MkaEcߌn昄V\(pQm4]L;~nd}QF$#GZ -g<_w6.J|GpT>'+nOز_&{;@)(rUّ6\6tsͿ䲙a%,< 'ui- .kv{|S9En\)5uP[ȰO>܎h0: aN+3aްmCt=s ],CuKI|} %^&GC*d/lb+uBD}%lh@ &1Naۛ=_*!.-WYgy!Z{ =-xlUTiuYUiʍRPxdyLWY6" U Dڞ3Pp/m<{S$Pϭ[VGq)kpp*ŷX\`cVh@J.Nذ~|Mp'wQ dg d"ho [l92ڨ.t;h&AܝI{؃$קmKYt6~\7Dk a߫)[9lNa;oٮGaoR֫ pEgVm L>fsvq7LRۢMH7:vv)1sSm|2HZ`lOF]A -xuiuwD0r Kt"]Ld=#!{ ".Z8fFquH ޷Hk_H&oِ٩E4뇹8$ny>$O^]4gށr|pAn:*[4ļ)%˗??q/'_NW/sDм2o07m0V@w!Y-M-6$A$k-`y_ CX"D]LyÃ͠&X7 ߞ!X!0֍^{VKpaCbnj7#[|&w!F:ʉ'BJ8J+J37Ο짔^{Ǡ- 4em=N2OOGŻ > 6ikx`b]d mջ6S:{o֠ZÍ*x^d'AY@DzF[`[yKk'L'M΍lxv[Kx y.u/ݽdҽHOW ^NFD^ڌJQ7D&gEU*P4e*Bto<u&*DZA4_BxSQ?\vIť罱}@U58 1!/9d.aqO^ zA&r.~}f.."D4`։e-kHG(eCۗx,cINyHOFfk$L'ZǏ6s̠XJ_xF}# z6N]YN+Wɀ H=jb3c؀a&)2T' >OA |M CF$▊}BzC}q~z*r.#W+r%ܷ A7 RrXVR҄u6~n3BrpOfTa ,m6Ij*кAຫ5ފACE@dB{JT + jD?d=o'2?_(rX6bKk`Cb/pbϵ$˛;9ke?6>f|5L(fC jL>{Db.l1E-bYW2W:8V~jۚ*lF_6'nN#2 >{^Մ=b]/M\f:"FUev'u"1S娄Ȗ5R #7pBٓЌgMըB]S8 [y;-+DAizs  )B|T7o8mV{z*µ@j$g0_zzc RHHWF2nU++qW{AqYѠ/X\S产>> c]endstream endobj 240 0 obj << /Filter /FlateDecode /Length 2507 >> stream xYK{/ćixRbM2Aa,M-'>3Ab1S]]=\V/λ1DTo' Ͻ֎_u Oxbvx^&nD&dǼr3ʚ*蔫nn'u:FHn򑝵]ڴUlS-ea"5 I(_x *w9۬a3V֓$l a/(<T ]ӯ匶ua>՛fG%RZ0? >1!ctio0D ]~8CDarOŠAQXp""J(,LzCFt<[#|$߸O(J`zUNK` 6{z@~S$%qq\56wTv:P6ED#̷\Dp vwx$BG "fD&fP[K]lvY<0ORvvutK cSlD#To<]?&q;XVek}iSQ܄3j}lP9Wh͚~rmG48Cio7rlEywhWM;(X_ 1(v}&"_,TOuN3[4Tߪ Y)Q@xdb{@Ljr7/e=oQyll(+d'oN ٯ= 켽kVBh4.䯛GA&kwMELĒs1C2RS30U QNS fF\6Yt%{FTq"jd HJZU lB\'i!W O`wH8G{b"mc@ #*cE 17d׫Q 7HPלbyE*3ZH>"jn 0 ōmŮ 1y`*D(544H%{_F/$Ÿ <~nz_y }xl(ܸدVz~o;P4dj4I6b| L4$D3vT ʝ4lYtO XL V Eg]ՁDXsVDlw`XY!3J Q[B{`aN傽~o8kyu(@@CL醏;%uV vLP-sݣJ]]'<ǰ7q#ܓ-ne2zQ0!f$  z毗 -}i W=wy.1 {!.{0C3tF-4r%> stream xm{PSO,9dY[[g덖**M$I)\EX -pu0Fm l[wJ]mw-_GkOtt3g}Q>FF{#,,{H?w>~ mEOy%>I _o4cZ.Nx e6~nH).FpfFb];wh8qDBDb@0h*p=a{ h qbPQO a+c'A_T:8hԩtK~ ^_#& y "\kol'859) 't'qɠe'g[ 4 p2 !/"dOM0uS{%KI ~lJmR^,⟠GS}awA!x͈#2;,~)'/WS'U(D[^ px;a P_ŌDSQE ;};{`{Flwòb#>z*f)wz\2#b籌* d3V*jeviwM<`"ci (36*l=P5jCOH 0 _:?"^$&y..`6K]/NSP\q?a' ,y|p ǽҍ i xzvy}ٶnדKͦfht.:=.X`)z> 7l :M 1 [nͻkj:Wu"R'.!CB}I{w鳐l_76{SںU9}4L>ׅ5]`n3C$觰lOBDx}َm Mmqku046 &v$M[MRj[M\dp+wT-??zFEhp}NޡH3z.Aء.ϻB5Cma;[/o{J[[ZƈB32,rK1#n?{#*F0xclii:-`\dl ё {Fy^Xlj4PȜ>$/W)et8Tb%B<ĵzf`s^LSL\IN{Rm]|ފ^gw6ɋrb- Us1g2dC5:ٛԔz$d7 qֱ^&G_C5ʯxWfC#ЁRyxf9; |ow>F_xtI"!;bdEND;v%l | ;?6A`++ʒq!іs)iQwo_?zb'_#FxQ,|D {nI؅!lӧ pHHLW.9sN}5 W\ &n$WYxK \6=ˣO~3FyBr5^coqw;>CE>x[dإRKk `-(?Ģendstream endobj 242 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 4862 >> stream xX TW"ݯ:Q|ՑyZۺ[-괂 +! Y5eq߷vժotN3Nvn뜾ә3=38˽o8qy*jͦ #"̆8= B`焣S0/ VKd#͍۵>?a=¤MQiϦ_Rާ>P/RQKT45Lm>bwB?L<0QX`Ro'Op:{\ݴi?pQ ~lwHncM-oB5y&wn+_7iJh2]k }DwB" 2YZY(J[mlȄИ-X# +&\ijI/ahQG+x nk5~eQ_ %mTG$ d#O.jj+l FopIr{ Cp76R:w'yx(0,xQ(D 3ƳelAP_p %Mh(SdB85(?(S\ˋ+s~4>,ߝn(x:k4$OR@Đ)~knaJh[Aiaia+mE/yRnh#ϵ WxXax%Xa=l[2H&.JHչZiec|c1R[:cyJbQ-j vb!+RnLI=쁌O O|jDsľ78 c+>i]BY9 f1OQx?t5FA9ʞN 2Ii)-"d _0qn ONUT8H^ˣbVj==mL@,yh$N~VnEMr4Bh!e3eJ1UY5#"E\#Jkm8b|ԙX-> W?VT/, G{k[} -'~,7&Xl=Z5c @/{qK _Zd[ܳ# 'RWqBF^ NjqsK岲 c!i&Xڢg;{+=uur,ҥrFHĥP41Bǟ b7|y1OOAH> LW$+dc6i*53a@ʯ3ay¼MX1/O RCDpޢ9a.6m]:Z.Vɪz9ٌRO-D:9wB BRsa'tU5g< b|'!j> p$:5Vu^qVZ ٱ5+x诿]GMwBqbq IԂ}4@bOLf⯦a0sD:\wD@jd߁'Wp8VQ\Ufk*tJ5s+\OȆU*@Ax.'C(*W`S5f50{FK6>v Ų0ݷ1? 5)r~`}$(HڟW:zu;SD(.Qk>COI Д۽_ֲf -Z ʐ$/L߽=gdtjNӞ's}j} Ν0k(h"M'CNHx NitrPO \]-{-vAW˨P2s[[*GyW_-ra.3*8j+rï|e^&{e3[V/e~'-5ykd>OPXc760] Iz}uTDwGd>!6k Du `RԜ9]nI6 ~iЀwF6t/3٤?{@5}A 6$Lâ4;3`2;W[:E?|],+ɗ$Qn/uCKO(r J.5mm6Ñ~dasCNRi\o0O#v`CS ?^!(d) NNpowXl +h} A ^17#c!59Q0:<9.هxQAP ` 8M|Ku/I8d?W>¯VIAKȷvHJ]JiAPPQTu e=/fM&ݕ~Kߒכ ?b^{÷^PTYdT8!T]N5#o.Ijh ~F̘rG1ŷX,VH̃ ֈ]]6tF^4^Uɫ=ʲ#N^ ZCB:)ZNKP7mIJR$YL 8/-`Hs"JG߂t9AO޶_d;?B?B?]:#Ԁ'گ [sZԨ՗m͔u ۦr U"}$rLQaryܚk/߇CŷYrj-Xmгswe:Kd2%jڢ ggy֬&Xkzmћ[3^6.XCTXP.w[x"*h?= MEO2!sNdg2YxYn5&hJ*T'O_J:sU:QePT{#1q6U`C֝<[N-EC :̦1e#m/&g>G~Ҽ:9úEh[`WkU(C"c\g)gеQN>n)jJa#ߣe& &=&0,ѐžendstream endobj 243 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 4286 >> stream x]W XW-V'I'U&edLD70 chnޛfF@d׈4d̦Y 3&/m_2U{sN1"$$dF?C\w!,¦U=$x,-9 %Yof/]\*[)R&J|+iuuivxN"LjD $Kl$"∧ 1,&xXF@,'+(%"#XCIFPDiȌ=>妭vmd&:Gg̛kƭ.RFg}:;~?䇳E޷-/(%_z_+#hN0ӤU3s1Q\ iUG>* 록 e7.Wyef/&^С dB$D(b:./U_Cq= >@O m{$L)dQ ͖F5YN]ht;5QR&**[YTEA'tin\Wر}iB1~5 R ETݣ. V_ՎEw`y8絗w|URq-AƏҢ܌MrPЋ^v'ddij?7ZI'M1+|NPno.l\8<O{wɕEh{xΖv:ʜPզZK5]Rco= ͚DUlx:hvb&b& 5|auڜ6.2N |FdbSg-V胏CcHáH\",ګv3bTgZ؉X 2-IKlGv'sl;{X 8[sheH䞍[ƠDXR@nogQhL[(|@Bt?tLTL2K JfcJI㱔,zrgiik_6K82Z./+l$+ݕ>C -Ddbme=Y_p jg6Jq2J_+M*S2ҽ.S=5l4g V~9Kw{3O75|ғXȦ&[?;/wJ,RSL]/3 r"dTt+ݪHm@UibAQBIn FOnfjxEV^@{ا7{uM)+ፂq;Gao1#[͂T48Ľa(6LUrشO{kQR{M#ř7ѥ?X}yoNj X#Du #:+8ԜN:4,mR.3b'Isow&tVHH}UE$hRel2 w]<8=ch2 G P?AJ)7riJ: h~GͭSUH"Y l d39dH.X6w@Q7}৶؞m%P:(S[͐).`®Y+R)XXOLo͡Z!^71h%Z{]Dy$/10=Ga3%vdhk"H4%,ڢh*f~ Sr(~՛c t3SOgz ^QE"X*iӮdkZ++pqm5#MHL8MEsWQM2{wt ( VqUܼ=6'RtY\*FY<.[ިz~>^N%-Pde[D\$xSft3ȆfiXE=KGͦ)wX'Ó5?D3WupPa.Ta`cѶ2lNo-ԁIݦ5ocbT-TW{Z9$G  APD(!p^lޖ%Yc_Z6‹JjQj!׭.v /glлL.؎OfHԋEs r3ۼ pKVfx7Ԃ{?.kw\qu]1g[]]pz|SE_!/|I %mǡOS_=iT/TujȥyM &յ`?&8xIbުh]]*^dao!slEE^ []&;_ɪkgze5n+yU4 0^Ջ=ȿĚ ?3 pTGgF9m?Q'32@n/{|Ժ&a[*k2՜'A͐XWff6fBؽA3)!endstream endobj 244 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 3360 >> stream xuW TSW>Hgk}UZmՎEa(>AQ@ސ ! ID!E|A+*j(>*Ē[^܍#ǺNvYuߦnM##"#g͛5pGg; OqnC~.e}鲐 aM+27"M-2j]gPxj%%&PIT$EMVSjQPqT 5ZK}IͤYT0){j95 >>R+yT8R)$TQN[݂2~hFX>jPa 3Y43/I#GUqϼh^?3<njeɇk>"[1DUqaU)t'a#y !f!kGOҨc"V퟉4Y\ex_"V9%Nb! L\幊 uUۥ//h+c',w >}}s+cC1*?Ji^v@Z+D)BCj¡D$ݝǒ?ᱍ(9,< c 1viCX' /9/c 'l}iPxp\yfz^|z*#$x4Ò{WI]ցe_ßo`&`Q`,Qe+ =s;ȏZgq@!Ӝ|YAra gp2)BV, GX w-^BjJBN8Bi$`Moy:4#Y}0 'JuM( M ]S湌6x ?!pN6g8~gPny$ݭu]o3p=ґ"W1&+*xxFTN[jHRxB$ԭf"CE);$G eYbߖ9QJrTe,g~&sc 3x|+xߨ|ݣ[`oT^f515i aGM.ʕ`G j_pSd|qRTtnzl@:GrPz^>T. MYQjim~fj0/9^– H ZS6eG2u-q-" Pmmے'+rE_+9_p&Rao[s5j"}"zYkjFx*վQ$G6vt;WqoV–kE H+DIP+ ؤ 2!tmw끟BEܵ3)m]roB3 e6 a9Ӕ-yGJ:V3Hu@U\LߦXK,::ѩKGl7:V]&G񓷏Wge V] T/qjF\ =5XtM  #WYC ?+y_y4p="t@w| բj(tK\x&iyhTg֢22jd8Cgi;ձ3ZY0ˍJ{8;/5j QtZb;J-o_Sj}v);C0RDm~7񹹮>jCz90iY!?ih*Z6f*)I;#0}{èkϷJ8RBxA䥔?=DH_Ux ?9qb<ߥΏ ^ ' <r:TΐC?y9opAtfFy"@IE } &egbO;~0jgX̨V}DSXU_|.BI5A.`|H)z]>h> h_C߹tP{,~8vJҊ`|9Lş˶'H=C# v{ Uj]_8/ $B,*]rU\8!s .BXB[hh ]x4kk+̩# ZOA_E* q.{:r^hE a.~a7| 11' .oAR'U;3+j\fK].R%{JB N.S( <|+/Os['Dv%cUK@kՕ&t529 “J w(I ֤3LY'!m1^~RZx)1hU^Ҝ+v|+'2ﴤItE5RL:(8eTn>g#"տF Gb7˵ӧkqz{yGp +%"Nh~|C*Q e3R[IWigR֣0:-!Kwιc}'My=(܁YLE1eBz+KLV߽[ߢ^VO(EnL)K/-eTŁ7UӬj3a1(Su4 h@O!NiHJx)0Ю7Q|LT)j"|W9 /Ezd_uw;+*0cF/o#sۥsЬ(^^^bx{HRaa]0cc+sCh%r޹[gxbnnPNo -gKXGD{^i`K# af䔰M(EͮY>9.M|'v2܆5CGTc!dM Jwl4VRM(ѕj K5n[yeJv0i xq~k_@^,Ϲ ^ tO<.YԻuOM j,>,VWE);ְɛ,52->5朥I}1%a+}D;@ 0E^#D^> Imendstream endobj 245 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 741 >> stream xmmHSq׹o6vF.Eև AhVK82l JRk^f]BnaAQd2BD 쮾v|8χ9yGe؝h4Ɔpf:2 Wu#Kb>l'd kM4 Pp̭8u&+$ĭ,%u(BK I~&/4QwNkr!XQAʺhM=7Y |@[ lG2O { u Ԛ[tl8apl 9G`fׇa9_Uh2=6jZ.WE C|I}ɩ2#6B`ˊQx o"OySs.)Cvͺ5KjQĿhayiAϒ3AbEI\vLIzcN|9Ō?҉m{ՔZTEʚJX֌6_OHYwҼk(Fh? x{=> KA}R4uݘ./Gg;7,-Ћ 3HY2ܤ-K ooԃף|ڸ$Vu2Mum~cWȔR$ 7N[`]xkIij!rm<֫}lB&l)> stream xZKy9Yh>vl(aG 3Zr5_z5ٜ$c;do7i7)&nhz曻?Fĺlnxh_$Y7ct2[4I9m+י͝궷mƭM4YE^3a7nqlnQ4rhԏ4.-Œxx4Ho հ_Q~S$e9R@6)Aȼj|z۶Fo4 [S }hU׏@Y 2XZT#2;T"L[xl K@ƞ6Am ߑEU}S0x NA[8{i.*t.`tsQo~VuIJ_eySԹ> Π`5Z *鯭:[M@mރ+|MZ`xƗC  jLK 4mO{SܒTOsX/o^U,lsEA3wM^At`ՎrB-Zy`5 fLN?dyɶLO0uhtcXA+(Y:S=K>3,z(,~Ƞ㸇>rxX ӈԡ}sI'l6)tYQ|RƲUۆŅsx%-X+hσZ+>\[&p7rCG86> =j_DK^se=ٮTke0L&(Ґy B\za1{EF"q f 58YHrj0daAHx^(3ϺƊVďA[4[:2 ݚ, [xYxO;,,$d zDWЀoBX\2a'T尿^غKIsL)Hx9Mg}Ղ"35IWI > %Xv适̂K438G#q67 OpS{mDn>ΒA뷗,QB ]!,f:q b@2pϠFdo9`X͚tFgREx ?!{~yvcKH3};Vcha\ICe(a"LDWso"&TFП%ed_gN;cx }dHG$shuq ,G#Mh,L`YJF;uy.+aXf9ab)f΢}6th=S̐h3'|“)K4 ҩgtUk-)=`'0ӷx6B@f$b!j^p,!/@m5..6OO.@SC\Sovg Whap~®#BճՉ@Ie= OZ=zuVMY(&又%깰.XNT-:U+K }1ma(t05%`2(^#󒮈S<ɳB8M;\a4$\T"YyaGn3!Kdtʢ =@L׼vY2^6rPN8% Чi# 9/b̌`2A2& 7͙W0l G70҉L;Cd09v2-}Cy r{! S[K-4h2pҒa҉9D+XSHK} U))#/)'P!y;c)N| t"֘l ԞF,Jt'&exA pcG5:ّQKRXΨ#!EL%03Ztr" X0bp+=+cdN[U!ek58ό.gĤC=h)ޔO F0a!?EA¦'ņ%;:_pFsJK#Й55m#QssmۘadșKaґL7q圠} bkI&#@9ERL˯E1jB~a޳kM F"qpk tK&䜢i"7srN,04=^HᛒmFM+"*HX%`zWpݠ ?ЋCz2},Sv`MO՜"IW{6 C<üÁ1C1(!2XYfׇ~Ѹ%DAVK|̀8%sAs"Dq^Io Ɩ2^̭Xxm'Gt4( &,3:rq-C/P46sffܳ}g} ӴlJ?rUJ y=utq=9p5NVoBXX: NJ~BTJ^H},;'>SGa *_)8s #3 1.ҧ\yX%kon^o$Z~KDE*de{$ ĕ'6ƯaW?bC,]1%?5Tdԫo$Q G |b_%qcX;EP'B띁NfEJP&s욷Sntd.wEUޑ$dj %p Fz! ~J;ʩ.SH\tbYGT*6.&ΫJ {ZD5|d"u?/@\rX1' +\P -1=6 E9 XJ o\ɵ-o{ep: k Xv5uӯ j&Iѫ`H\q'޻RGx kv]D͜^Gm@řdÉOq\& Qϸ#2Os̀ƧSMz8~ rӡoɝ7 :hb߰II "̟k @oK]!!qoE Ni ?6qpf9w21:K'`E`L!GX=Xl7!/q8~5"A5/Oz%~ ,p~_#SS$k X`s,6n9ffH*z$2P,V{ezendstream endobj 247 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 5442 >> stream xX TS>a88rM֡j[Z:hä"cٙCgD"Jc'V[Zྲྀ϶;x?j}k=V $k}P~>@ )gΙ#ΡP #j1|ģg撴˖gdrV{%/~mº ;6ܴ+%u3sm`@6PPj25DM¨j2A-fR2jMPP+U}7o z45Sϰ熭64rpaĝwGm0: nT{myg E^ G^Y8a%K% I^#ԼRjUR@l,f]&5ZBZ3F;$:l$|&kNm9n` Ͼ%.- E)nu i"߾䔛C:ղ1[WiW`La8dɃ n'-!ېȕ'8>P/oaƳn: K %JRsXt \ ׉lT icBݛkwC|:5>Vs-Q Z 5hX.LezBjW,f|U'OHDHdcϘ,eKϙò"B9W^)΀h+9%yP"VB,m8JmP"¸ݸI nu8_zTBo; ˇ޽PkTJ'VE<"6pn~2nb0L@}`  :{.˗1fJ~A}NM-op`-3wH<#qL_Ĵ5$|Z 4oX||i'dwI-Wy__^y+~/p|+Bi] 4~9J*3]u"m!3tYYqHTtiIbg^m&3.Nwv46( \ˇg3+£׈EN{I *M^†x {-h  (j1[ݷ͢q@P+ZtOT*ܩrA74K}OוI1EkAc  :ʞ&;0?oZVT\͇ImJS:ot m|wo;* "Vr0Y3=%GˋW9s+Z5~3;Sz~S&?^S+trNboRZTfUP g)yG5{qE3/"G`,/=~uYt>(h?g ?s?[UPV)`tqplȕ5JG>΅:YXqoǝ 8&q_tY}|?%i~8Աn$̠xTLnx"{,<Ե;ڡw%[Q%֪3#a)Ľ~_ ғo椣}t MN4I'Y58) xkg*4~gR^D/}WrHW[)o?22_(ĥtF]*ڬy}^hoa#GrGvhp~ĝsdhWjP m b2 q-hM{S⠠ޅw,4#>'7b/6S) `*T)%&f? pC$ }|KpܶUf^"'=2`1Vi+ *Z2͆E+{nQK®`/y=?wVrPHes< EZjٺL&9#|}XasQ1<ەΞ&<{B8! gx.;*lmU}pZޭ>w$6'v} }w-Sػam)^kct;)R~NMMhּ\d)2O/j,R]sN1DaדݖBI9t'b/O)^v@{g]Kh(s[׊V rުDb2@8$CC!ϮпKp@.-hseu&&eOa7jI5MrN8 &³(*IHcq:CO;߼`/:ZMkQ]*F+ jڬ6T3%EmJoϡ ӪM!ʼIn{8Sǥu;| 7]exCHxϏN5vWvC;+,w+9,.g>_qw,"\<紷G.p >E } ?jkhƦ|+a,v]i_%ܜg~$}<3/;E 9W<3M6m##܈? M̃4:mFrzg'x?^|$?#f l3תoXPSWS>(9rK9ℹ#یLylҷmwaGW&%ed)!?CF\AOi識')sWxkwOqQl (F* *m$ /[&ҭ_ape9S!R."; Tbp6}+#02`2endstream endobj 248 0 obj << /Filter /FlateDecode /Length 4742 >> stream x[IuV'o: Hf4!5>LX lpLln #H/o7"Õ_x%Mg{|y{b`]1[\bs{ʞ3h1Q0D*])FEB{8o<8gq ~q.(|@"nAHzIcdMrmLh8I$R i]<~w9@0sLä_W߿ٙSaJ`&Nir42OYq-`CpLغ0JYr9^y{̈!P.o6;=T &۶*BX.`V$d\J [B?%wR NBH)[9Gya3!f"k6rFB̭h8錤&lBήHpz7(5ϖ)rQ6ytvsz(rwMEkAϰ+e\&vT@|)}VmOmm 8 fg$v:{ܬY-(6b5ffH8x:Rܑ0XMu @Xx\'b;Pu@L54,/.t(@A[_zB+^])p~ dX6x7|s(4cݧO$;}~ncQO58\ۍ@T؅#"-@<ʀF;^-' F p!+QchX{lQ\"] v$ˬI>ڂѪRg|=ueXwxa3~ޟ| F{uo`jt33rdu}Δp29Ihl=E/gGٵg\Gʣuv}ݤop`XP4O.< yr=] Xjb7:2[|{ɥKqH|d(pOΌFW"F8h ? >.x?M u=-VjKWqjq7mú0hlٮ=MyBK?9kE';-9sK.±"!gPzJFBXG?S`νKL8:JWnAx8'\fxZCh؊,T];.}xV? Y97t~T8Mf!6;Lj z6IhZw[՛DnIT&gMT۪9~[ҥ@ݚqq|Y&A61?I( i>xn SxTnBtSh8J. -XhSAT7/r;_jHPۣK诽e}"I u"-ѐEˎ# ^4>͒#QFNEm2CK lj*@:^3fZОmH$ywp/2 l̘PoFfhRΏGמt [`#W4qn,lDb39`v*:;}*YɓS;'z!U/b- h﫤!{NX4L'kJ@7KQf1r@R"{DE;6w&S~_uML% zUOZȾ$!'AW#_7L#OT 8KմMBr"}?5 ND><((Tv%RR %SYOR;y?,G>2/%r(P /gJ #X'ؿA/ك USD&A(\x/YSDN:gjAT|{5ҝy,gsݐu9 ;R!ׅ?Ӕݡps= |nj()B6(2F-iƦmrm;7 إOEEVxUpvG*"B ?m]K [#[0f8 g{c@4K/LZvJr!*-X};˗ |NM >hEʽnԂ{Q 1$1ṖgS(zHarڬ}/Vz[SQ;Eڋ={X6Hi'!9/$M$})!Rj i%9r,gّyNI`"\&OeVM{'$FwzҋJZX"wXhj]q$\䶺q eHEËEg[) RbSE1|Z*b좤kEa7(<)0A;" _Mªb˝O$>=g uvŅOCfo _!b8$%J7)68[%p"=?ix8r&@@icB hZk\9ZŽdġw cټ{@G~FFbQpLT嶂j\,N9mftZ3dIϬZ|xȕҢX6RPRK{K*3i. Ү<<#sJ}EɟjVAٿ Fq ~VqkO~)"b!"8tN+" |dMp-Cm چFÎX\Beo u 6蔤ʭRge}|&aEOu)O =.Q&|r;e 777IH{F2._~R]]lWx3YjY?^rVnI ; `ë=Z3{+{ph\~ٹ /!_/W  k8"&HX <'YfUX`ެAHaE\^nEN,05ymHpcL1:56 xCu"?m*a^ 9z=MdO ĨpJKwձIp?)/iNj<ENL~܍&`U&%aK!WLbE8OT6* Dz[C5"Q?X SN bf/M>&Mi3JƄ%NPP+Lȩ9p(c 0TFAk}Z?=j{rx[!h{ccAض- 8pDQfxy4UH{qޕD롥kWԬUxg>!?}l @9 jW)7sIëK)ocmvi8LϓwؤS3S<=/HBMOApWu*U,Gien-14ɚ4,Vj=v** qUX>v;-BnΝա|N͕aM40Yl-)vPK;kYCMS"h%`z i0л$J7㴪vO>u vm1l71y-:bs6(Cy*Hyo1H m궣|aEMim5iQylTA˾TE&  L?sWwx}a2j{Vݮ9D>2Ѩ]D-f1m>RP0 UknQONUwRɏ`zhC꿞SCW<44hEV\ k۷ٗ"튳Ȝ˘m' A !y!︬wԈ=՞|Jl&Gǫv<Hj}υ:E! z V*ޑUܡlLn?h{1IhQ)Dendstream endobj 249 0 obj << /Filter /FlateDecode /Length 209 >> stream x]1r E{N (Ni\qr ˆrF.R 4ӯcH{iAnȥsn]^q-endstream endobj 250 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 1231 >> stream xmSmLSW*NY$7Xf2]ǜ$bthS c @b_-Pe㢢Nc9g~TXdd&992ؿy?HaWT򀟶2ti(XPH̱/AD0J~;+΢1**fPQ9Fr6WWlSM_k٨3 8-rCXj z85lyR]d/5rKDbv{QX([?` 0!&D(̴0E$RM2ƼĴfdgl&1.W&ē|VA)6OU;Npj| EF45 jo՞YEOB*DP6Q% W(\G4aST&Jq))yY<0/=һZ:KNGSmO Cθ+!"U+S7^gS%,NU[Lj䦷ݶT`'yMrQ5>KʊY^LLtS'zrJa8'D5l|MvCEu}ZQYxN^ > z"O#!4%Σc|cT)6XUU3wM$hKW2ҹCGa둁h,q_v>gCG\PG*xw:هV&\Da8 _8</D9hS7,gbJi>73 8ߩSYLeern3'&.|;݉'?ۖZ BO-i5^JC}ڍ2I?G_FLսǷT=A~BC";/j,&z&LC}j2FI-H26W#0āk > we2z6p+E{PWՊ?yr@[hdLjلk֠AiRD!]jS޴;ޡFche) u&P,E(J${endstream endobj 251 0 obj << /Filter /FlateDecode /Length 4153 >> stream xZ[Osїj*EyK$H[$m2@Qd[@cslelّl?=R<<%rx\VE.Vb{ AoWzʘru{{.7VTzu{|]7ʋBfM?+iw7keU^95}]l[|BM3 rc_8ǰٶb>Pe޷IH|zr3h$t?<>ZA)A]z^-<…9[}]4PN7SEQUZLNnЯ4O?Դ˚6}JITt"qo[pMl6.eP)(̕ChL"X<wb)TBz3jFpY,ttT+JXKYPA%_МڛaM4 x쁅裇3 ȅ`e@^< S7 ʙ?3V0hr__9PZo5! mq,-sgʶ~ͪlM%.{ɦV*2>jC}~p-,$$nHs>z ] j%܇J0kY\j[{π ?9N=J4Rs8E{q%piwԜSroyR3Ѻʺ(ֳ,kQ;lhbADIPȓ'ؼ̎~؟-bC*$uIta8 =v_ʼnt&^߄7f,*mnj5h8 )~ˁt} }#&?8s |KPk| & cl%&t`L S2Hk&/Y !ufS؇U̾Qe%`'nm\wH|5f(FckhYģWٷ$.v1ˮSkEfCǘ#^6<.w{/vet>yɯ3QiHm<0.68$[eٱT:=&oN3Qfatٍ` Nmn7~!0uOdF%+ɠ dH8[lu`d;>H 0HĝJ+$|i'_`9=*>ʭhwO͗΋B-KVEAས(܂Mŧ׎(dJ,t=XsߢȀB=;M[=T1Zpy_hrOXo&fS)⿞M!SfJW܈a[6M-40APA zTpbMULhD*k;:PV 4.uhVae18k)YA<[q[R0@&pf-vj'n2NPdh'ht@[cL9s%P0WnG;ɉu#m2sdʎGU,6)-5|öm1isdQ f=X[œ4G͠yhwL> 5]ѱiGs9D%o8(,H S/H@$m͓rFF(SSww lF[)P4FXn(R巯P[(+@HE el )4;dF!H̷ZbAW!MivM!җu ߿RË30TQ 41k:e"Ш 4dsu&4r-MbY%bDBr ٫.ft0GOzx¢ tb5ԟb,]%8fRUj"o2^YVY\3RSR?uio {vLF-.ʍy>s1 ȇ͡g W$򃓜gy{ɺO@bwr@hrp -}En r[YP# ˊhM~)Rf_DhȆ1@ uJpB e3>Nh_e>1֢5FĎ"ykx"u[-Khei"ZvFa3r4X| M]~T0R@1r'U""$UmD,j {*6:Y?3?`|.MǪl]l_SWa!eZ,DuF ]RʵS  Uk3g|Y)t=@W#9JAKx Yk?@AﯞRW?q27p*\C }s2rp UO-?aщ#zJ)S\sy0d)ʀט'5Y(a#*)xy4[5cDDtR0^zw9Gȵ*e kr1zWN~B7[J9 JrktHOf86M)r Цa:7Xћ ᲀ=+Th zQ}l,C%=Wt\ "McyUͧozLYJR'<rwj}RU.Ctϩ d :vիx'v4W6P*:rچ\9Q4J%huH1zzW_a:VVt!$Pr|xQπy7mTg!;;F ,slK_Y{TL:,y]Ik)b&|([ -OIuy3}نn`1t˲k;`}246,imIF`(tOxNäL9D1 zGSW Y <܄ 9t C U;K4©StKa?U{f$Ċr֢,Jᮯ!ƉZemOJ?TT|0*GZS0p"`]B,Gf9S+zNkq%<+ ӕtA 11 ^" PntbW_}U͌S<9BiF mTEYt4Hq(@Q2!8V:F]KJf\U V&J.C-|"CFXTfӕ9AzdO~,>٢}VT bl0 B ْts3 5 Č_I2l)9l/5Gq\rn! I̸7T݅Vy|(xޡ G)sSm,%1dxoY&*LXv2NcNjtK:ZAd]U }5ځ߸Ah {5e>?B~yi ,1#T>ڽMJ7?Fr:\fɭ6xϛB>Pw;yf7BCՅ>c0 be7Zb6>9f 2]0n.VLkY.!,#U`XDtU98g/[6nendstream endobj 252 0 obj << /Filter /FlateDecode /Length 4332 >> stream x[[ȕ!@ %e]Y5<$; x{ yHn%J&%_s.U%Rv-U./B.JwWg[?HEp,ox\H WمU]\~~RU*oŦredYv*N z)R҉;kXTZ40 EZc~*+瀔 Yqkxk8 ۽i6.OmalQ?C^dmsihzqH/aإJft+J:].V0)>dWyZ+\g -8 46f t Ɗz86=~pkxRv~!3>~(+8qݦG%9%ձo n= Ik/kۻ% Z2bq`(Xqފ~gҠh9iaGixׯdAF'e2.Zw.4o݋K@PJVov 'xRf;hqH݋ђذw]}AބǕd^n- ꛛQ`hy8d:M;vu.UO~W!ފF)~ Z:JC.-;cd>^(lWpx[TZE&$,˕ʊWȏH6r/Qu)YN0A ^ yFX%^.#vKl=2IZ;ߌFlF$"=pX?(#=ʬb Lh ŶmPNI8B췛ё߀DY;t6@vݕGW(%HA"'6:oCeof iQ ¶GjpOcO/xm֧l?lVkt\Dwyp.G\݂*;{4k$p$F;a.լpu'hod N3+!?wUEae mm+U8_y2B%  P*uwr4 ;Sf~rDI)_RZv0ɷ_\2GTObJ1 g&I%).<{ C I ~8<8 ,nR5S=C&k:IW*>[h{@|A>K/$VvG~ŠqJVMLAOWUЭMskv}Lb`ʐ#tIe@"(fGWeD+):Ȁ8 wF>H/%=nbr&E<sXZΥ 2@xLNSE.X,=q8fπJ r#%}bf< g#98o+U:ST!8^̕4JƖ#Aa1~$]ԵYS- /#_$.1l F<d8kB#mXl QV|) K#p?#ĕU2 @_h$髅0칰<ҫ V-$J\X?V?fԐ5F+*~^GbLJ1zA| TF4P3"'x1.'ʘ( {c*3RqgB})LG}8&9g)N͙ܦYwC˵w2׺S_n'{ʌ ?~e4_1l1?i\ďcE =<Ɖ˔A9'"NLVatZvߔSTfbYPޕFb+Ne$p(߄O=/EXS/3SKkue[BǹIVlM0c .$>E]yHؿ{zU"x3ϳbHsPe:d :]Ȭom3SZQ !A󺏗H#N\*MЛE8P$i[Ӎ;NEs@fp@11%%V:S e@GzfʒDts.P==.~aB Tm7\;r c;IKxyNBcVr_qMrmdW+{^`71W='ѩG,IE+$zjD_Qt\ӎ*7ѪiuXZ p$H#Ɖ-9[pXۖ%UƽU_.NFӰL: DXC:WM @4o'+دÙK kֆ>6p6; ?:AM*1dOJ2R訜{!pպYoO /CO!%wFC6T'鑳"D|A5. smpHQ+K}=&Ey67U%y|(ߜA\M]hڌѪis66j€@AfY"FcīaF%[V <E-wz 2sC$~ *zjo .LCpTk+2u>॔.u=H0 X|J%wC͍v6,"*32`Ipب0q752 9Gw|́yR}Gql)ɑ=DXnLEԎ +|=Yl$pԡP(X?\7g8?B84 cZɔyw}`dނhM!/ߟb <ܔGݦ7ׄxEw< E)gӦcҬ_qf 0lLL3i*E˜״ *k<"9ڡP:Θ@?-1S=u[`f< +/lm/8 &[.TMch0`|l (EmHg:F3}pW> stream xZ[Hy ^偰 ;>l@r=n;y\|Lr];"ſMFU=^aV> +a|nYYrt}v{aٮڷUlɚCn-C^ᳪ6Rd#osumٙ`/ c[pZȕAv)DQȸ_88X)V0&[==CQ(o$;^®s~s4lcөl  >x 62VIs spg?D.&+*8IE!d./ V2w*4=ޅ[~:s"epW,.;T,ЧBeaи0@٩Ë%m غĆ/cv{3 wQ-'nyj#&D}s.0ޫɰ-`[(5Yu^K\}m]uK-|f :7ƁINGeVEͶe:kS"WFT0|Um  Jnf>vs ^hіl |O]Rz1 zוAAd `ޙT-pSzG((1!ʆT(`T4!I~p.{7;4 s_}ý-@C "V.) %/'5hhBN { %%ʣA]Bv܇[RkV3Vf56,c IEs*EddܛuN\T(Qdn* 7Ǟ]}Q3I#ُkc=JLg~Ilɒ;@)p]KiV _{%R$Ir@U0,krֈm ٶ8@wښ}s D M՗/ehѾjtUҜ8KYS2.6K_59Va<%GA?V])ּ:?m+X/̺4f$Yt І%#sPC$4]eD {U]_C\&1 = |hUO*1yg KOX σff4?]z\a0@܇:,KLoҖ$նU7YsmY#1 #zA RctTZw}ꗏN2B5/v_iRcaa%1ĈGJ{f.-GBvsz":X "V>Qz>y/Mv•kpS3?C.?٠!h:RZNHR@Hwb@8B>3dkf e(:fv @=ޙBs˖L\`'z_"6G81_lM|8N&&Eػvv ,PM_A c "\BVM.dO/kl`. Dd>Ysɜ/`5^B )I.U@}Sߝʱ0v*v]17knGP}RƵLSH+!un.Bey]#D(APgRJ[gA`m}@#C!tуP,ڥ:!f~ 0 N S1lEX&0SDZRcV$Cx:!!2x>$8#ʠC]sA,v X<ˣ ɄaC<m?F] $\B(C`dRE"#m\tCiǥP@Kj BbLl{IE DHlRvWO 4XMa髴ՐLƞ`}oӔ0E@˸47(c;ɺnzלp?VڧE͙'OB炅N~ԩ~QB#B=d_NXrn| pgL D.@-cĭ\RK" wiTQa(a `C:/3#m ǩ5e! 63): 7!P=̥LTXE@C 2+d7>25\EsO}4d ̫v'IOD(MtH""MU7R=VVg |CIga038qcbp:ZN-|nU]rF{Mouѣ\МќSTgyaļeϮ*a<iR%O8b:3XNZ9͹9Py=wæUP{JԚ-8[XS_KAY IGoQDQ]\ \3:+aT$v8/xX[0~^)Ĥ@1VRbB[fJ)1w[ŸtLc]{pBs#0YK[ <3*,reRz7/#u%˽O_|}roo$%F&WTp^1|9|s)鹍DJJ@VsO|+r@ R=~mW-ix]=ƙIWƫ0Tdۗ6 WWV mo hR~W6W `wo,6; 4az>@"]ꓦ:I RPpz a ''>l,x3 --\)>+y FawE`KzVf@2x PiJ)\!BJR69)'D\yN K2{@Lh>q V8~H V0b+&Ebzx )P*mev7<ғ6L\ȭr"3O:}!|Kw pE^&' 2ThHCߴ;Ц1)ZgnY/?Q/mIYQiAvKN x *?CUDvwUl9O`T{HKė %Nȁ;z^V7C݇UP301dG@U;ӚxE4Y5Yo_/ږ^/`SJ~#ؕ(^ڛi+L7]s(TQQRgSGzB6 6V>0I- F*PMPf 9Pk&4}S:?gD*Ju fvה6FNM7RmA~Ԑn /lڻqxʰM6Pa>RBB5|[4KfaώtQ!n }U{I?MNMUO&-3nr}mՇzi}x) :F;p]_7/endstream endobj 254 0 obj << /Filter /FlateDecode /Length 4226 >> stream xZKsܸY!a'9$Φb{+k鐪Uf( ILjZ[[:hHhHH/_/ ozK(gL=B"1V/z8rR:ORn[5U|4n%xwLz ić6+BUE}͕xRlOKeSgU&Dw l!ޝv]աrDBu]΋i~{!}>-wL&YZ((zU@*$vmU-%֤'B<:0RfkFk'6BE&ޕus4Be"M+ WYQ5"?h&0 69Fi?մ 5]%.W|ݱ ұa 3o'_']4G iG^,)sa*jy@B*EMh3qXYPn!{2+J1YCY;># 6j>=Xڙ1-a6#uqPx6*>|JqdpDNH!-Ek-:gIe[Sn+S=tʌV~C&+AɽQoWi;ޙ6~Axjn#ɏoSd٠HQ;ӵ͵h|ϊ hM-RVHǀ/۲a!uC  u) ۖ]xE s/^B)>@d32}N;jw62C -_{}LThzm'@FhУ*'UD\VUNvd̊O=!4&wC܏Mop0dh-9Hwd."nj8dÏO8]j|*(jic#b=;] XC]R] f!ԾS9s+I}Yc"'f&+ڦyN 3hcRdI`#\@H\6'qin?^|q! : ,\t Uh}Mȩqo5v@*QO%e΅8$Zp6g T˝idAJy?rS '01Ŏ| -[3SJl"RB79A UpjJ "):bOof9C{L;I,pfE% ʴ֣pqP6t-06}X G]f3ΧTtZ'Opx@rW ÇRm=Qȁ 塧|kؐ 8C=[I P< EMH1@te)pi,h%Mc35۴2ԻӀc3!P DZdywش\@ј<.J- V@Ib w䱩 bfnM[#}b#C'g/aWQCxR?Xޔ21AVޔ}h7uCYQ޲hoʾBBa7^$3 aۜ^8HW50ðqܱj놆J~ d1bM?ǺGqdYs}BdlЛ F+ ,-#r*2ci!_p+6kOe=45>DRop~c0ԗ,&ѡH*lL3DKTg|O|e41OԞE/kﭏƎd h%Sΐ(@^ڕOSǚ];)'$xB'՞1ZnY2M;T|3T9PfT`$}5MUȱL)v>(o/OܑEi}`7Kb!Jhb$[isk-窗BX =+^ɋK(Y2-Pgqug:z5CAg|Rx ~\]QNIC'FQ ]LSω-{XnlUNgxnDWL7t)ͯrjPDZW(  'Y<ēG/6 7'6) sX#&sL$5?(gD biM\ ga_8% Q Q.zNqQ'a„1N8Y_vE>fmCh5طiy"t:H6: .d0CiR"ҥR_+!﫥}}lغ#v໋,0P90b{`E՗K}P诤W_~6Nжh&-*K؆"YDl :33KP#Gy(Fv[)$ZpQbi0'*p=> MS9Qb#lC/r00t|E 㧜H{@xR҇VNjrź'DUTw-ʵg=}L1LE;ޝڎo,= &3Ipw1s> stream xcd`ab`dddw441_#o7s7B`P&FF|߿6!|ǙP}6ojil$9nJ]sIGv\ocV]I䟰yӜ]'&&MlklnXn% {Mb1#ǢNendstream endobj 256 0 obj << /Filter /FlateDecode /Length 4165 >> stream x[KHN!XUaX^l,b=<~=YUJ1shɪGV˚"gËbu FŸa?bjes\]߼3؊KVZ >6.L^0VMՖ{Y{jVrf}}:wVeǛ?D11klw. #%r8x׿gur:)g)-z2ʨ8uc5g8YoX^aQYT4TRFs\p8D̙*]mI3fI(0rޜ Ƴ +XVx[W^\V_qY}W`cY_!oVdbaE]o$›3YW֫R]r{lo 2YW٬ۖE13crm3l3͗<[p #*@yvg=aTS4䢘,[}2Р|mQ?P2UuG$o_x%Ʊ; >k8 s; kfz"3)]$4]3Lk8rgs#,UK%t] ad_l^,%*l4V\˰fWn}| _ƣ~ߢzG`hF j9! 8 ~Wa.NzK*bjwgF\j}EmUfJڅ14daϯ^}M q3BW=Z]1XGA0mwt>('_I;]4??85#hFݯ<#""*ַu!7!߃op-':U4 d A{u$˷1 a'[V$N1\MR<?DANӻ 7,2;B]IP:K$-M?9E:G0L4l00LK-U4lK7.0 ];  qт0={xioNGarp+񸃆rVA=kUf9(D((*x" Y W 6ʱ!EH(} Z0z!xmnD*1@K96߂:pJ1JR5AgJ:|xiې!~C_GqvPos8$y 4-$aJ(_uq;$:'C 8A|>!] )1ġ0: `?[iT! P@ ""C #ozS:W0j")]H- 㼠P[q49\`BP5P1MoqHw/$ Z@.xe7@(b!BI,` SCj@΂U *ll7ldB)8APr^ɿ\QM'$R7ER~FBy.~~9?NƞsN`3.jAȳ&sΕa*ux}ƆYjKulk!C%1%q̎۱jq:bC6T\ܦ `3Ί Ǘk&LBO 9?ba(Bx[  (TL7*eAq)_#JW2?C"z s(iߴԀk@h+(D̴GF~Y\ gr# Y/G֚sثlGp %EPp&Z!.8A k9A *W)ϺgUhݰjv#yyBlw ;⊀04MeDž +# p#5 FB۵rg G7̇rhL$ah_2'dPٟ(䊚*'YUC`v.(/E+'7B~#x?/Hɵ :nOױ.$b8srP+GB#`."'-A OGB` ~+7iLYz4ɹlpl 75@97.\-AA˵^I uʭ;sL^< ,ʌh ybI#M0E(ρ9R3=zJTI90ذEOTcZb{?pd9vʾ7Fe1J= ϯ1#둻&,]k 5P+8jsG͟2EOuÌu|2CJ GɎQMJ MX ?7q$D7]" #B1|ZC:=Ftȥx/I;`CHm%CMLQvsm~;PtK=xP 691$).!&a?*t989/Xҫd; YCiIFM_/{VSU:b J9< M@`﫶*zw;|IA@1}uYh)! F~,C8lG[rWgDJ?L=Add 3AAb O1DF6endstream endobj 257 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 1581 >> stream xuT}TC$mĔ}kO-geGSEZTHB|% ! !1LHH$RתWO7t+gs{?=_P(@+dmʊ_W]_%BRVy6̩?\P,WֿP*=^UMQQ|j'&zʡP{<%Fτ:1[P0.z~j;asm}ЏI"}vwa-~GQL{&Mj%AѬP3:<+û/lQr/*8%Sz ^}_S;[W55*ry}-Rr(ZC^ 6QӽmڨPED96]z'?ޙT^Qu[\& 預Z[M-lKQl8zl8[AȆ[daE8DFI Da[Lɬ:Bl"k} eo0w\}`X XiUECTV;ءrˀ覟h5 sWXf,Cm34A3VTwd&':K/., {0'!əO7´nܭsVUVR?ěb<8["JBdфz5~T)[\O%O7FOt=08yf*VPZ`mZ8!sv.}Qݘe n]_`3`6AZ&jX'*c-2b2Lec?فJg_> stream x[͓Fϙ  u! $@LqB֌cK-<̆*j#K~"K"z-n.\.~B : QTb JU,%r%]:'_TW o.ifW7U,SIWtUmt z)>6ɶ$e Xa(]r%`ɋdX•*O*)tQdKI)g_a4g_@!+닫_\ *p Z\2u[v4 ԴUF?UNIxwE-{?:svVa l.AǨYJBd(o0H'-&yK&U$8%;jڨax*$ةMC#mg0uu ? T lᅬ塯N$ Jto(z3rܱ_G 8AxÒi,XNP-(Y:hnЬ\WB0-Vjʖh_zֽ$KYUo X9q:xrξ仸/g+ۺMm$ʹmګ|= ?tfR$XɮF_uVdC_]XhqN{|!l_Q6+gCƻ{Xk J"GEǘrA[ڗ*؀ėAm\p*Gw.w/V){)C AJvK0ub.xl>5FZ-ߦ @8?,v{]Q9I&Ku3 F aA#Q9b|^462@|_˦nw>XNcj]SW]_DNx_khЪ/g0&hf;"ٰ 3)և-?1b6TvAHz@z!on!ce4\|pSцDCPF-9DyD4Ұ ;g2~PԌ n>XUCƥBNE@jz.87jz&\M|rC.R~C%]NQ9DfQj_5#RS$lF L&Fi&'ur 2Uq&qK,ˁ$c'aA x_ wDwtq!?d'UQ)E4g|B7b- ڌ4mGF_;̝|} s}dg" RI𪯆4- HU%@TxYs}KqZ ,q00rCIJku2r2,>.j h- y)ɑ9Nd{[ҤDwCFP5{3p%D%iT9'' IiD 1Lj\$7/"nZGA 5"d+weI%{&M1.j@SptuI6̯ M9a% WQä_wf\F1lcr4}A4>d;NpaJ麲}LYPzF q9 һ0ApLJ2_i}gPtFw[hXRc2\5#K3Q ]W۩YCoPD{]kTT탨Ў B|١庮}¹paBu|Xu]yVQeIH/|>ajpj1"Pl b_{7@=K,Ss`83I/ˈi#_}Rԋk"R#k ,hiՄ296 0f[Ve2Fa ##]pJ2MMɃcuNxz<9$c7 P#i \e.I' c6u>l1xޔ#z~>b^0S7&,sxi9{4 !psd(& -60v(# vLcg$w`l?O3CKT "]dMZKGQ0)Ulu3XC\E`rh;p LS{ -||C{J*&Ss7j?:K ]!P9YTi/76#u) ^ץ| h< nԘѩ6G AoB=(LQ pm ڛELb"&-SIۚ@p'bAҪCjX8yY8L1k&27E} Uf|۫_%4 gGQcp抂lBOuv*ҖEyKe'MnR.C=x~?CzzdʱhSշN @f2c GnUF};LFW/?.!'.UP\ާ {%b,UhfsHbkɺNk#Q_jұ!s`[+bi*,GDh7g\ef1y TΤ.<fՂ5cF _Nq=9|qLK愄.5<朄(˄Jwj^VB߳8"Re#;?R~ lDz>QGk>a0v:Z|Y$j؜,51xL% ftC아O3ID>"R˙Ef̽0QXF/s<0QsPD D''߲'ZQPĖ}HUM[=2*^ ЙdAMO X '1?>x8#s޵ &>T: 9 2}fy~ ΂KT+OK>;bE4L(aB @繌Y{k{tui4Qa\s>PU4/ Me==#\~ 8R&8ϏaHT\D͕ PBV{ t#Xs@ݙPcOPBʁ>9{ Y Ent)|.( ŪF0#'HIMmܘeoc3 dBG0gr"Fl"&2CV2V~$ێqaȳN<}9a"- ;L#s39P Pg8/!@*΂&-@ ݹfs5Qڛv5/t3M>{ E{uDC$txȑ =-~DCSh!)h"OnSV,X %rZX{nxnLX40i' i FwßIBᴢesE}Tx\ǟؖ*BCu^1eixrvٞٳ)7KG%FoxSd5mfU7Գc GVE5IX@n>uy)dgJޙf(Smڦy~d8|z_/!FҖz> qӎqzw8[Uv/57 $4Ua|M {>Y?6ŷ?\endstream endobj 259 0 obj << /Filter /FlateDecode /Length 4130 >> stream x[Y<[8[N+ wpErtקpV+Y=zrb/gsX}ss\\Q۫0vzeͅԫ۪-Rɜ1>g"{D̺]Y5ѹ)|}`lv+nn ;K6Ys la/X{kX9<r+a^9ڜ~DX`¦ύLfȝYqLl:̵^d]yW6owf-;dz]\Ìm)^u[[\ ~Lu.dJ^ (r>YZ8[\W(ԹU>zTjdm̙z]ҏ6.٥ʎeu#9Vzf<%]xk~*;ӕ8dkNWto2?^.\1Fe9bu^ge)M86١ݢBDΏsM ˥tA+;Pe]5JZ`Jذk$A0urqFΌ)N`_~08L"һd_qbqt&S0^'l!voϸXXޫe6 dƾc@ qk{ռ\H⳧ KxwN1 >:H8Q!|\LSKj\3R08n"~KZg̐~FNE 4d ;iH/3.(Y 'GauC~cz!?pj)q [p>@q-Pa'KAG0}q- U `r.j6?Ab_F=T_IjD<`Sumٮ@VyZ},c-$H_q?V7^T"X@4ҋls!rS ty١7q[ ɞະ7Wi!.1wab9Uܖ.FKpωj}4P(?4fq~+i7iP`*x[ ᘇP6e6gM(Vng0C#vCϯn3"qYq`Ck9T1Yugwut_('jtM yܘ6QPT6>cn ֆN'بf@D=f6Ɓ.f&Z /P)}wFB(@$$ނw,!pP8W a/ 7$Qv) WdJ|m|n* TSnN HQ< q XJ4Arc'QN ! "`[q_Fp-Ri@ M@J`*0JFH(# ;Z246E]c06mC5J.f joq97ր4+ ovllHZ`vrU]7C }ٶi&vu':0)_gŸjCܧ (](dž@"!/7qƟcIAE ~R,Yl xQ L !G`i)ӒS-+X@fuwL}uMLTEz0?Q-q,m}$|St8)ƻ W߀~jӆ(kJaM>J9"Š&H0sZo\hК "_STIW =c/q'} SЍa!9xN?&FY#Mqs7Y,42unAn&j+-B|ՏWl+Wju\oWx6mfij6XAJU0?zA 4έpۣ tӡDng?Djwr j +1ϺX>$XQ)A1\&"[``'՗dKJ )[g [gh|Yww3C1ht0p։B jޠZ\jZOq"zM &"f2SL!:DPqÝ8|kD ~>a x*-N fq'WFy@ǔ N)X0( GvEp4w5>B(){x<@mb\AnbL˕uHn>!yڧ(0>>[eK*El ߐ< Gl+@ M^Y"P`ӈ^ާM\,㎳  d 8..|K  }L6N-! Rqf ^beS磊{C<,9vzcP*#v/".x YM@t#|s+ ?C| !•ϾOViitAtK!%ɏFQ#|xs#H {f @Z ID[%7xXilMք/ 2y ʩIO _:Lʶ8@vT[Pd`zC&rE{uB%k x8? -CO3|[3t))◖*O.*)Oˆ@A-/`comct5k,W[EJoh =G: ݥCQН#*[JtPy(8>tz*?i^8j4ߤ+i=z[u l tMO&x,$xJ<İ^R,ܫ#1Rn#c /8\*Ӆo3=m棣 ,k\kǚqV?LՓeP_ Ar[ɐf8+N?(XAmojF#J1`3i1?֒1}F?{vJN(Ǧk \L׳+,ˬWtVY9vOZWb豮ұkgwpL~!w&WX?֝Qjp'3wcQS98qJL4 c _ G,4Vpm,ݧ}LB#P,^`r/:vrsW1˨{JGC7 p~hTٳFbt[ocqP|@@ CxpRل#84?jp"̣[AP)MDl]X[;;&Mmtsc>;B*ÉL daIM5~F6ŴCM+\.zDN2ќ22ũ /da(RGgZ3-9KO/{O$`yyd2Dy8;%D KߏWMQendstream endobj 260 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 550 >> stream xcd`ab`dddu 21~CeWB`Ċ\'H?VN@&|?m|[]y g<{E_-,myՒeK]\;iܚius<8,_ȮaWYšXcw㓓O3+7OcQ@k<> stream x[KƑsv>pOC^{^r(BHt7<$Glۊ94Teee̚" J,~vw\Z kgȅt*7XJU͟f˛$-FEP &l-Ws\XL|\Ts!C.LɬoM+UaImVFjvOn@%ʞG3:/Er% +/1w7ݯ.]<7'29R^~M(O[VK{nN]X|W_W;OVeݕN7۫:!krJ8¡Cg0l(}،7gĦl@l.z,4P~WkCUHg  ܯ p + >B})1frӬ~{A )rC0RI& Jpf <" WFj4(V`YXջz' + a4"HQ(6j L8mp=c$R%(j.fs ;V ~1)?Mgh׿^/.b~Ϩ]T9^qRhýH+hNᣠ35udODS"#RBε#-byP#,-P6į5(@֥~A'pʘ_(M| P[2ªY,`v5٩3@hbٶ_ur[! b{@l4A @GM[7i  y7C9*pxxy;L );uuY?F03.CXLR\Z7+8iwv塭g3F8O0`n}ܖ " @Tq3RYr 5gCOwƜ~93wb wwܯuǃל] 1  @dEGoghI`"/L_D2P֚Y}ʵ!*LI@}D}98y쏨jAt@1kώcGL`10 N/d]j'`w |i^>*Tš10&ahiD.هz,!␆#ZȰ$DaR-hZ]Zl?ԇd( ś_}S8[0RcQ>sC\&HbQ%h?3ɚ織bЧc- ?u:"*vM:VG mclҁHp9@z+a  Xyh\I7^ְ, ' i ܃W''t=f# W1̆mɿ0)$kQ^: o,|TU.bK|JKhev,HFKŀ}8q&mu߻Deh܂OBg}OF(1A JGLѧ#_Bcx21IljfgS0k!fB8B8 beU~Oa*R沷]w]"­eⰵ'iboY.? ؓ&Qi]aDG@j/Gʪ7s ʷӝG+~ L_ebESTEHƘ >~8;K[.8Fyo 8.z?n!UW"2w96V&mx&Gi ԥ2z{U&tS蚈A~Fp^jUATPCe \jG1vC @ˈ3HBv!*+bqpR 8m]QO;bקYM.v%](Xu` 쁐3D< NaéC sxMb%}/%3i%LbǵeQ! >nvBnuF{*ǮJI?(rL|W"8d<Caю+/fbqwW)v+tZF/]s!DAYT"HaW{1/O3P3(‹6G]iO/>M{,T.LE{gc;ɤO.Àx؞2۳9wnQAQ  _ĺ*9 aϕ1Wû(Sx"l+3,gj3\fjȔ X!{x}7&ISXݐǻt}m(W l 3}u˾]sQhYфjp??,B8+RM]֧֫5fUˀ(\4Z7|;!u%!Xjۦ ᭈ1I' +k@Ek1a nG]ƻ._E'&AoA>ϻ 54dXut?>V:e[oc"2J uDr&ME ?hj>NKUt}!Fh&&1s% -jzQ* 8!O?ô؟< %H {}é%7m4)S oPxs{RfhGks @[WW`endstream endobj 262 0 obj << /Filter /FlateDecode /Length 4124 >> stream xZKyB||I+XqOv;q'Aسs`GFJ,I}͇V,sGu=w<._=ݽtwmO?<ܽvY=x\I3WؕE]=~lmTFM_*r ?R( Qu]ۥIVjdbV!eH SꋆWT܋jj\fݝo?ñ ]d0G{乲.0!+ v%}e<=N )#a~8_>>˧>p"^j߁VV;ry39޽iۅmupzlض̒K&)ʙ/`W2u@qnɭ[\R̅5}*+p4Oe8pGB 7bɴuʂ_djx?i)gE%NJT\{ǓL>;«Di3>W*k Z Ŏd-5 g)xcE&͓c))07?${YX{9FaK pl9P*Ֆ6“mcߴF7maB ;^p'׻[7{HQhtk;;P`2 xo^$00̊=_%%4=mAXMS5\W۪p)t M)_-ݮi}" c0o:l\ d[6QM|=nҢ7֌ /Ǿ~1Vy͔Q]uK9? .A !+O20]Pс xAJLJ;r1΀h8 %H9` p2\c3_ڍÔۅ7L!R%9,8c~dp^ HlU9"XHƅJ;mk8UáSv}kƸt`HoW2.jl⯾:76 HP\c{M ..k9+";OQAm]Cy2Q2a` hRlwv*ML5ɧ{03fwWw*3ގukM /߮ӌ_d37#z>+gɜUzɉ@-9\?'b;=rW#[ |Vs ݏ gE ^\YZ$>') j/GƵ&˗@OU9їfN.|,I]H(I>R)Bٶ+E͞ kut }.ey ݄ovPD (Gf>bN5;7#^|b\d*VG^ir{%rT/9"GI)ʥF–NcFt84v5JyյC:~sϰ+W8 sۮln5XaKgŬ^YނJBj%33=vLS!6{5wmR39js_VT|DV]Vhf_h1d4)q˩gH_b'g|+&q8"w[,<$ @ge5)㐉 PY+ N+80O;ES]{+E_n=5ițȲ)7#U9}{;4{,8f; eS\@G)gO8I#\e|ɹ+/$XK4|$SUoġ[;풗e'<ɂ7'S4'6i8H: Ȏ) 8Y!l8"Di>֖RPo#O8B^&Nz:2'TM<ƅs,' ũgaM{x4g,饧wXuI mR%}Z|CkJˑk^tyi%0xز[5vLzQy%K.}{L28U"S8xX?cҷmH]Η\Ea.ކ>IJvǛp2CofPF&4'*q p^AC}M%lv42_@lֵ Dk8K4R E]^KT@] p|"+q|9+q+T5^I|ͱß\->%nĔWUя5+n=rayt?_>!̤[2mܚ]^Ç vgf N<}H^ >ZzaH_-hQJ1S x=0'3B /Y=ʬ~52=}~%C7?Nsendstream endobj 263 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 770 >> stream x}KaƟwyVD}0} *Wit2u.yeVvplE%](>*K`?~1q5r4@WҨgCOj.tDp0#+cѻFarD@\",}PQ-u"G.$2,醢L\ d+ʔTJzהgvJ]p~0f9e_{v ca֩7yKs:5.z3<<Sޠ1?coXxX#%t t/== ]g2.=%Ǽ_]~D> stream xYK/$/c`IR+ZRRDIbߧg.+`_̸Xfo ˽]~\d˿.DDžZq!a[|X`m?o_Ji"l.B D4Zsrs\eYg|vU}Zg}[ۦz}ffw `/{5/A'r|ynNYƝ6;PJ\.zsN8+\V;`v,WkVacP'{\걎B^kPu/Mq؞EW&YTKu3{! VҁX1g%kuӿiؾI[ 5e{>t:YExN U/A2i+. ^S<E99AE}]u-w߂8U&⺙W(n ofs[ZY$!4NKnH ڱ ޲m}^аn‹LX0q]ᙴ!8wmq8<x^)n 7saCO07Q ! zyqrLJ0%Z>(f;m|ٱV;^AMU!K@7(~APBᆵڗc PIYFIh,EbESlϼ-PHAmW7} )x%< PO*;0tfPG],v󇷀nJPB`n{xZsBX4TJT`9*st[Rg[C_͕bq:iI"H60ؖC%Gə`[#'e&:rˁuHrdNzT^{CT/cUfȘ9mR`H#)zʜVܨ&rb4$mVv#Z."ur.?j 2,VD @zi<4ޱwp0d*O"yJ4KR`uS\*Z>Q٤Wk &UAȍU9̫ n}4^$'r3˵$I_zHBS} w.QnVdyϏ ZϝL[_J&P?#Y5pB!7 PmRH85,*o0-I^Jlv$sWH;ĝSi cPӂNd b`pΗDK.3\I3LΕTBnK O8XBegC ^ǴO eu,L1%vr8KS* {|{Cc}Mu  bEݓ :`/\K:ntUqVm&Nը0{pa@(`xt{Y([F!3bvy}+TAyxJ ˻A`CrNxL.: ic^~b)Hlf0s<>C"ɬ`YnYJnIEiA4G^҉~Ғ^$rI $*H^3 A認Q(j$Eyҿ_ة>W0ONoFRmnez( SP D{GY%1pd+&[!)7R nfkULvVHp I.Slh |c7=O'+݌Z.QB؜nx?sA Y  _#1 ،/#cEu0,=c0 Pvkp:1E{n4 7Fp nT>ecXo"2*me ͒SO1;'|;ŭ_CTs J:69f[~%< 1}l,AY: »Ŏ|w?+` {0S:Z>$;QB#cEc$U}P0hh 6Sk1!đ2PvzhB{. m!m <9)!Wv'N|C6RAn?<oXGBJ ]Gۮ}YjٰEkH_ĕg:AS)X5JMV*41 Թj]-0c-τˏ*6Pf+Z_89ɑь{跧sKBK艭{.3dB 1췪),5SX 4>%^N\h'Ғ..@y\9=;CE@p-T L5x=Ĝ{bR> stream xW tUU$@^ƭbg'2"  HIwuWN?g^@H@DLA,#E㨃Ao9[Pܳs>ݧԽ^C @ .`1cdizك`A.,~x"谫=C̋YR5bWs6lym#ӫyb.1xO "b*F4zz?r|4~H!;8LRA, Νŀ(U\Hdx$*]րέÐB_~@S\WnaC(,2R+/BPv-5:U.Hptj) Crl4e>tJV}NnQc 0PYEΠ&\rH('e*TSX hb1c'n[*Uܲ:Dr'\rQCMB=i W>]fSKLZe}F~(M-Lx ^Tn-FxȔz fW8@k4ܯLtesb(l 9XkD$0tKк͒d<=?a漊+{f񲾢)M #Q}Hzߡ<83Vnx蜧^[#lnjuݱmUtrbE2 k̖`{I~.~ Gr: b<m,y9Fh$~u!*'XL'Dc@F#1J=ĚO!u+lD3FrJɦriad4І)aɟ] L0V\fA RE7т oH'aMj[ۣ? ߂}-̟Aec<Z6Cf0X55s\k1ʵq.Q6 z;;/!HE_ fq%>߾HQ,IWhb< `3*܎U㶹K< R mDEYzTbRV Q鸚9 s<҈ٕ 'Rrnd2FFְ) 43n`)wphh5PI?I#"1MDdq ,oXO烨a|n.I_&91#|(fB-+L^P4bQT#wz}BJ: Ơh /=SMR%ߪ8ً?+ ;#N_}(qX=)uّf,kyt!q6cZEf`TF1;TAeb_^,!.J-:ΪꁥUТ{bA RsޯN6b~;\]?>gȭ-bk>;Jr>~ гK)IJ41WA,I&Rvi:` CweL.`ׅ"Ķ.tqw,+ݯSKHiٓV]:cd{Dq/ "knnbWfYpD>@-P]UnGٴwyQ_>H'5w']wk?UyӼgdFdR+#̈IDrE4Z BDԹDv zdPIhTFp~+2nPm`q2e;) <9f,XPQ*5 vAVJ(w!|јUɕ^UEG@~hFv5\EB* aEVy}mI8~-x5wCnп j1Iq3{W1b9i qԈ4Pc"H]C3ae ?)5,Л)T*ޏfOGsgB\%=_:KH(éBVaӁj8ZI_tyVJƪ^O[Z?]5G{N6$x鉭mz 2)kbo "TAFa=Mbh7@UG•6Sk5~+7 iQփn!c&dZ+Sy /E!q,)cǀ. qT@f:J(IzW{N;+b+VaH1g#XR%X1| R9aD IJZgL7A彨(N6h)b yX٘}]HĞK/{Ƭ$|s/8|+H$0~mDJWuj*y$7T Xr?{F&'O`8}}{{e$!ay}}cƴvDYI~ksA'7iI"ͬN z5ae155 klǟs:C͍2v 鑷g =PG(9F~,BCx^s#"`("wk=7AL|$zuy!*zh0*с2P5P e1}HIDž|(A' *" yÃ{7MFB" C2hb$W\AE +Mۻ=^aoG껋y?Z8s ZCxDY:Ɩ?PC\ Â"/4kendstream endobj 266 0 obj << /Filter /FlateDecode /Length 4429 >> stream x[[oFv~_Xh̾iurv8=,0 N7%1ݔIJ\xiq4;5&YU_WE.VEBU=މ:WO+a|nYYrp!E"_Y|v2N9xѭHƬ|D%^Y]Vr*dpWu{YsUmu\ːnûSem󢀹-<li{2et_=oE㨬onװPpANJR̛(`BiTVO;l i (xQ A|DƄl ㎼cwG|}M"I>HRqx[u(Q]}Tx5))M&Mȍq` LS*;/"W*6$&jv Hv307Bp`G֔Y_"iAR 1$& QBZ@>ݾYߤ6q>-hJ;1!]mNX9ێʽI:! gM3ڌ)*zEn<9T;lABOq0V{<6MsWA+rUih_f}SdЬ2:4'&ddMgfڬ2tE0#€"u"VH:|\hisaeHDTI^S̢"Hh8 ʖY#tEKv[n/b}+!`.$n.;|)8ܷȞnOFe"VҨơ(!sByX_7]ZId-׽mukIOl'=ZNT7mq>DTOe Z}i w=1Fj硘QIqꌔԥՄ><6;V>&k7m@" ,.,1>RӔ /?u)A 'Pŀ}Pb3PT|]i4z]1P@U Z#*ap#zL-l0`roI*NSDaf%YR}HD)E4v9cC-gfNcCpyhco//r\@6ͅ0P{RpdR@Ǭ!Z5̷9:7;aAB;'}wk}}Ǯ^k(/ . pDzf`UD,Q&%`{) 8 Dö2o{ J)L(9(0))d(m'^M\)!hFJ"XuP8)rnJPO)Sʻ7g +0)ga 0vwY`s}1B\I(lՒ\/ u9O)0/=ūPJ3'r+Ք҇!O~4ۇY4 (ŧ Oc\2u_;_MHA~/܌,q_(&@m<tJc* A R' 8 S\,5Y/_ki쀇O@a1AIt7w74#9[54v5+g%-hTAd(YM9VygRv,{'[$) 9KûWg ATlަc߮$Cp3+%ǑbRO)"+Ɩ>۰zSǮ;_]~[]<߳-ߦ8iqXrmR'IۤÚMhM] QSʐK5%?UgK#s0|[F=mw?3ZTieZro]ejv άc-/Ы;sFP3ec7>L$ E~59$j=y1[5#F0#wn&؆7W_#zO]! @n}ک)E6 */!b2BTM t#z LΛI a0)JG3 GFz7s9'ҙa<5 a~~'WG5H*F'|Br^M, $=4+.{>)Iffm}و물OJ<{ ifB5)S\'uޥK<8K1ˮ7-ݝꢐvj;`:,-QA$^|V3 :Yy&vKV'n~OTYK4I2Ƒ"ntJJB2nsIP'c"k~͛XMUz :FX!z}Xf@ #B<[a<:'95Ov[('Ĭ&pBqa_﫸 # 6F o/zꮈE@amz&NoI3Kqi*Qi7H"~ a$q@!v ??j 0]HZg3ָBr!aW٬Z4A$5X}궰K1@ _T(>Cڴ$Λ}hI7cH@ f`T :X`I)- Һ$u:f=DqBLs|=S(r<tDlInm034~O0KquL#ċpM[-t(B^ADB-Ϣ"zܛhb:YYͧoۇi!TyjˈŒRċr\)-AD!yZTJ`gSSnjNPoDG#6?jIn6 MPZsޖ ӼTĵ_  M"JԸ)H lC1҄:>p%"Dox]"ޓS\6g}/n+./J)JsuG WO3G1tcP}/VP7JK~L;Q’ݤhzJUv)N1$GAyðs~X cIeD5+cbLaW#0ocң 1xhMM(Yx25x=jLeG7O ,#uiSTaOo(ɸN7\7N!&I)W)%,5'OPn0TĽBӏ#>}O%xTK!d@]aΚ!%N7 f>yPx_143w't}>,kǽ"묻+}&Hzif.f̝S) <6vA'q yR/p1T$q G? dt͏uuU$QC_W?6F#!żǎT> stream xXwpU!< nv@XvM{6l」e[,4ӓzrorI9:  lkM8|k5p,u}uF߭^TI{}%%%7/3iNVxO`r)LYyr yWwSPy料ms;ds *7VoY\&5{s</&X"`7 VV ^VJ0S````eW  * n<%%'o+(=4)TP'D?#/7w"e#M{r;bm,G|ϧ>6;'Iooc_1S.4U=tZaWe,N TZ"t(a# m& 9O%!$ aaܚhD-dEd)?u)T Ugg5@2k@Ml)k" ~9B!Σo"!]҆|":2X?Tjy1]ZБm[ t. .Yn[zcM PAyס-!J{7ZmE% BP6~2IRh#wU8)uK&1)e&6sբ2Z d ҉2G nbkŏc%sHA)K3GsBT@EBwd2&<үq=rt@xnb-TWo+~}T*˟wi ## O^|.W0,k׿ȅKДq7'X0O'6I0 Μ/׏&K\!OBdBSuViv;A4qW{p Aah,arz! kaLkšvcHIkӛ6W^8}tH>KyӦ?h_H'3 Z12=z8W-VUy%v uƼJ2~u7>&8ø{>=jRRbӹ4,lqUWnHvd~o:ouHGHMv9؏V N] e|'M{S7 abjhdh#eJ_yY?V"֍lH|h\^mY%eqc-͙-Jg9Sp? dGJHwm̧_-T7UEeDz]c- ̫z.[yC 0,O#djyB=SMib!W\wS~Od+RnR |ŁG<W]%KDi+zbs FȜ2-f~Nkٵ7jZ^b{Txd8ίw1U#0Ү[;؝v'|3$&&zb4$Ȩ1'm5*^ 申MM@֙{揥ޢCݑ%E[wm}cvK Ê)JUam~.&c@fKkG:M%%_ڹΞT+Eԁ4jml g[yvdgf(~sǰrT8*4 N ËSUS%i~҆ 5;}Y:q6>9 ٣(XP)&UT{_ocsEV lDK|~_'Xݭ“,WUaCFyqd"CyW"KJ/눘Q4E{z+ԣŬѤf=oo9qu;vsKg-v+2dInR"srwKEOFQ(Jj[m;AH]Bf"EʌZaGBNEvuHP4-)Q.hh2{ҡ"n٧AXѢK7jm6n䟐hWW r'.p+`)6}t4ЬiVMؔQ_s1+u. cwGISdHBKjN6*) [4:F'OKK*&>rVaO]CD.KӢlZkD&+LREN]wrrԉ\SE Ir~ % c')i5[רs*Џ@_/#--mw̗pqꄢntm{{СPH}}կV._AYu֡%925t~=L]m.2JLkTkg==XXOO$Noр:?;{< l:*={ XLZ(d&%UⰢ{=Q 7`Z7\K ?znc tv a"ENaz=OT8#yxӗ+c;Z C=AdVeTe|?[RbpʪCoAOѽ2g;y߽m:1|'YB&51fMsד xw?иrBoBh^^bz-$vfqqnabFN76vDy;=NDHAeכ3"0سJ?S43G:vΌDŽԛ*='&T;hUl99,/ƘVʑu Ǧ#?n0?:"!D '"yZ4фKF.QDĨfn:[&(p}Y|ˎ;kN{~#ɌfJ 7 R ^Řff-E*%cݑ'y܊%Y& O _¬|PHF<&;\b^Aʤ1*njL6@D$ Id;PܢfZSn;v)i.S{ g};8ڞa2]CSu N)Z<`gF}f9FRΞ|%v*E\Gg,JĦƢu> j[h˰><ʢnlv@ˮ_y 0/QpCb[L@ pEg;ƘIyҔJ'}*0ݛ[:{@o{KG}fJ[i1ބIEe{Ἇ |xw@N)έ <9xܔ8F3i]TN9PoP!{mmM t!uLUبavĶ!t$@&>q&ڬɭ sC @bؒY{$d>DIBrWya.;*$ތ?YuĮUOkSp/bpIqm6mYD`~ljELY87r"v}οH> stream xM;4~;vwORfWb5$R)VU.JWjU姻Qsgq^)giߣ^}Ͽ>ݽ=~w,"*3KFn Z~^[kYVx]'[>5VW}~uxSVڤ:uxVQ~O5z{Xb5}~Ey(uVAIUPVz77 BjStQPRz?VAIΧ$ݯ1_ggx~߇hh4~QoՏ}r+QV~)[.;Vl;"ekwlkEYW?7`Za_oQiXǞSi~?Ks݆پO??OW/&\.&.r<|_*=LL)q-YSoWO4|眥ǿ]ǾT}o~?NoycX;S3cM@cNƶE.uNKP1عD2; %lm8haKC0d)fL7mmj!%Qh[;u9^]cs<ڋ84p_Mqwj1]61a=HsX"CJAl=Ea&'>W_OmִV+(X:e[~HvJxǜb~6b@Q,0sAl=EaGGC| (Tؼ_f7>fl/u;31 t hB'9A]@XaD~xo$n RŚxiŶ'dskba-S);aa=R6փZDЛqx vv> ~ 5&}g5NS`~vhWC|2qa 20R8pZEM8p:z~V~gcvZzv Y~s(6'FփZDЛqmǰ\\n١L648lZW¢E;a=Dn=a7փZD i)8X{Owv|_`%~Vl{ 5a~֝uœl<|=x/ūSM<%_= ?׏SrP ^rloB_!ObAqswg\zj `EPS۟~e- fh78xW3ٻ (60_v%ҟ#k8a7k'o̟8u,nl#8 ;C)_Qo"cT-BGr3<܎R쳟o`\sn1w3reXt{wbՊ:'yIb&sUM< ]g73MlĆ4qi!0dC<ێ78c&1>%SⰏ#[,en\wRah6G|q|`]haI]eR9o2[iRqCP}9$_ .po{wwZ#00BBZ>}e+_[2s 3ǬyM)2gω2w4'aoިQ7-G",}>O)AÛ2̈́7Q@X Ot5)2w4; `̭A{@`0Q Ⰿb3 be-8kc{wq(G.,q[iK`X$+f2a far8]c\LYZ><=]npѲAy|`Bꃻ]3+0.mn2re1nW"b%BJ>m9`9>mf-b~ecZ e2c2p$eHsP1#~!SbⰏ#\qbf\*8ma3>bGK)s1 A#&,BZßqm<-&| E|jǦ|;{ ̗\Z2b }69ة& =Ri-(8r7P7l0ܠ\1Wo ◼W.o( vMPЛqh#]-|sN{0_0w8bW.f]0ه՛șgxR'. -鞯ocӗoes곖czw R:.MMYcZHKqǑ ׁ(a>.I)vZnRo^ ^jW J 3 څA-}nY$Қ b_Ϸ .,żoHy:7n'`v0 7jaۢ!x?rPp.15SⰏcR.u7΅݁r Eyfkf\-sv#(v 2}g (3G_V0KH' s_-{7o3S|K[Κ6[J;ϣv)VVi.J7NϢ!(+N'hz1NV5S&~v.=D)v^ζp]#PЛqg8V?S))+ RqsWveS]vts2[iRqlsʷs{j8L2w _8LF~h1ڍp 3/2JKP 5`[zzg9)78^aEp,"ӑ J$}zpI 56X And]{`r&Zh@LA `O) ~?EⰏ#xɖwt`p %,+Jbz-ȯ`ӸS -q¸L΁2Ѓyr?Op8= Ɣ82e-816Ə'9Cϸf.2+J9y:7fAH:?]VY;I=!3]޴[Y.B7~6@/7 b99`˵u_؟U:'K3_w}_cf"n6?Gx ,ȍMA[wBgNB>Twg",u}w݄y1Das/ۂ'~Cc27=e 2"fX`Yc,MB-8ac[ŢԀ?+.i_"S]͔1e)vF`Y1uEⰏC</>Loe q?_8f1 9޸aGT{7.=Hi E8 P )I(ka+~`_]|slO2yf,,#JTx3!HS^ Nģ/ t$?ϰQysta\3EKUAq[vuz<?|^-,sv<ȃ2w8[u2 -BZ><`w97^l ? M΢nH"sS :ypd'%ZD}>[֞ɦ"@vloPi-¸wT,Eev)p_ֈJWRzl .&ż lB0$%A-E^znSO+sH"$D./bNVFlܻ ?pV'HwJ^lwxp*BU~4#JZ&=zf@g 柩nZsL 4Ź#(fx^{,q\1^ٞ))Gsw>0 OaW2F8J 8>zZke^o;^\Xt* N2SAe`AJ Ў]c'Ⰿ#yjI N M)(s*fkM̶l¶|)}XCK槠_è Ǹj!-aGw숳ǰBk `nGqeyp 5CgdbBZ>E8Ǝaݏ L>!Jy!)X7C4[~=qm ]\H3Vg`,B:>tzDav"7Sn߭ؼPE.1ZqX((u?C ܢA -8$pk,.ƶ6K~"5բue&o2 iRq"x̕{d~Ѱ}-0E26]/#Ge8'2%CGZ|ֵ^3c(wslXo?|sL[rTsR8/?eQkgxX~B-8<*QaB_VdPUOPEⅅ5‚.=D9`S v*2[,ßq2Pj~^gesBm}~lHja]A̠XHC giRq=; eVpFp`^[UKޮgˆ{ =l'&I%-Zd 0nEn*7QťR,xw_J2.g~RecYՂZ?H)?4(AЩ P(s*zRn>a)A([mP(nrdRqKȜSsP`[N܁˙1dXbn6.=HQx8cblZßq2e#?޲V{?`uWEpm"w9\(c8>8Va~ giRq`qeܬdY:n/mEPc܏x?2m%SMcB-83shG[3lñí"ECLʀZބ,Fn{].m}>r0fuZ2j \o&1EC`~ݰ#Vpj B-8H-8)(ܧyVR+B:bv'sr,"^#`t@`ܻX\6 )OzI'U!U ]I|, 3.^-̍>svC᷼aߔ D-8Ȯ  8en͔5E3<fxaax?b~+]e8="P iIƑ^nAqo~M/)Wf;*ߺ' 155ug A)B }IKЁ-BG23|Db𤋢>O-㉌b}7(O8.ХohRq{!z2&oD8x}4fN~va-̳\-@ ʂқO]F_`Б "vG֯f]^6gQGښQt{d1o,-g 2ЃS!p 08S Ⰿc;VjωK0o91Bo7<{J[9n!w |NN$sc~x=ޛfE':A~r*MؾZs\PGe8Sٙ)KKqǑj)܇=RrrQv6d̚7xSS9M% B6 3k0WMcNSB-8Hz B^O.ύ'S0ʓw&LtQbuS-l+9, `AOfm56'Ғ#[2F幀cƲ R=*@y"rwfP^(!zk>SgjKmy)X~ΆgSߝX&2uc¸q@dU&(sjy e8~?K Ⰿ2egeЙ}·_M.}?_2_l‰=moMQvօmU .,ymMYcܛ>}YWu(^=ǯ' *m޾aZw5b/ZHKqǑџmW9D (WD«B)g.nQzN5Q(}o2J28Ȯr* fcakrf݋nbP޺:{4wY_wxԀک0wh  sV=χ0p[yg 6—`e`8JZ}ddc6_+}A7Eoz-?{ LD[qv|Bcqu)d8~?K aci+e~.֬d4\{ӫA_yg/hkGբx?bc~~"A%BJ>rJ ~b# E> ͇v-{ƯhZgc Ϣǫ̉A9wRB-8خ=]nlg,QʿyjƯGPZk 2ЃTy2ZHKqǑh.%/TIYF[lp8^"Q%8 _š]cNB-BorǑOBG;i}Ԫ;0ߦE}-'3 Aʂx9//{G͵-1w$BΛocv!(Jz.3v.=F4Cܤ!YZE[>ܑ%| -_Wᾥ~=NN(3|p %uY lǔE8~?6N-_~ -*+\(Rވ{?tR'ixWr q 8\.YZ}yv⡞ASݦ*Fqdg+S~'Q8,`*p~jj;}yoѐ ~X5Cҷ6RoRO`0bpWb`;,kORPW"/ۯԏAjOK|bS-\?a:#1[A/s\TVdQX@X d*+ZE u.nC8*ݕ}K_m&3l-MKG!S%  ,Jm^`Bݙ:8*}|gYdu(f~ܶZ'܅}2܍pOMP˔8.1ZHKqDZ<Ւ #Ayx0}N|W]4[.p0: UñWwW^k,M{ ˙QT8#˙0^ҢE;/% ].-+^JZEh)'}/_ݷ 7|3Ӓ".{LqjQªv+XD^,%"tFmisqّ(sy f7}Llq8v'Q w(Iogx"0&8;<0O(i#v&vDz .¯Da~ތ ®Ic!-BZ>M}}cKjAik梅^$.T{=hQZ-,v 20q2.P.mhRq ŎLyڍ?KCrbw`X$ |7 S6?bI0L-$؜k(rJ]OgFvHoK4qIց`:r"p3B-8ȗҞ~(Rýd=37Snd llJ-ͶzZ]0tA'C փJt}i1b19j8|0E)>)OsS<]=wG s)-(7>puA~Bh!afh92Z^d?x-3 ;j}n =v^N}}ػwNQP;uߴ<9s=HDDc[Ti!~=}uoIb xȕOjZ]9aQOHaŖKɩ鸽vS~ _aT8`:92̀Ϣ܍E%"JD i-(ѧ|]n<=mQi~-,m&/hq>;#ڂB?`哳 Xr] 5b"o1)ϤIcVgIG\aӝ$1Ǜ(AepNARš]cZEM8Foԏa| &58+cg9 xb0.1p&}۞ g+uy %=(WU_m^JD)k{{ ) >|"eY2(wWcW:3AK'j@3vU$3(݃s+І"ZHKqbᱪtZ sv^p*k,,됬O`;+O0&]Kһn:Gp磈m*nQATڲ#X. ̶B-FP }npd8Nh!-aGFkυBE4DG&(l3D,+ףsRrRwEZHKqǑpG=>O('P0GWc_wEZs1 s8(1 K a<81'6TWKf4OҪk%hm 2$Jg jqu;jRq.?2cԇ}qZ m9{ܬ8(#GU/qu׶G,-aGvX|7%}9x1)PςE_AQ&;O' #ooi (dq0],-BZ> {^wo G95&0?AC<"2U$ >!p[[pu`В#.5-8" p|?U_0R1<+Xs}ӃQe WLi%X?jgJ hΉ7Eс~elzX;,Vv-JH Ⰿck_\~gt'*?{[TN zD[ce`sL5ƮJDPE K0vT"E/o$ĩ8w.I6ۏ8`?dcF+"-}yo1,ͅ{_D ~ Vlf8}O7G/.,-dĜξZ,!dS|U/B4*5-m_jUegɪ_ϙkAeDDa gi79؜Z":/of Yœz<8mlO" ftGO~Bh*>4Oƈ\7h4$g?o&m~kTR͟$sX2Ѓ3~wB-%9G+P۽uEQ%l͗-j8JbgGD{eGZRqh}N[1;t)f)[ڪ4,u_["?2-|?K<.m8_"sAShD6;tn'UA)42j!-aG42E׆{f*shwOvұ*dvŲ dq#jFeXVhId'$i7TRd:㣞\̓y 3 f]Z^9̏e˜LIz]ƚ Z![Pk.f{D[ {艁x?>9o2q؇ `EP+] 19Mr1:y WR޻ `F3Uw܉bi OC\/2h| VpchWj]zq2BPЛqۭM1kro\j^ٌ Q cc8,Aq`]7U$`Б b3CxngfjofVGU&/Z naaEŢ\*NX9dDB-%9GbvJ͟嗽D1#0ޞ>xϩ]^[&Q%>e`D C ǴC -84@`Ue0Í]48{$|'Q;cZ<} 2WZ2B#pFwƯW[jea\9ygiO8%a٬.uJ-g`?2Sg.$J 9pjz> vuuW:^( 4㕇_zԢy~=ΟŁ!PLThRqMa{R|V/|W>m7_qo][x?bmEr2[iRqµI KK¤CPDS;}sz $W>.ޯԂw!.2A=$1-B-8ЀmC3 QJ/(b2ψ0͊CjD-A8BC(Xr=~?bⰏZz0.4rk81;Qu6Q*"vQ2.Ka]`В#?Vgf;#;)Ã,F1T LӏW9(/Nm"Z`愺EzXVi\p6{?fLd-@ES,r\YY1P"HG1GWFPAtoM婞 %''Zep"(ma)ZHKqǑOr>߮G(hYg2~IީE-#2019pLO$ 7u(biZ~E;(D{߳83Z!zGp~B 5bbsXܜ&"ˮ/Y"LՙTl0 WcyabKp< dZHKqǑ'gHoW%WynZy59-SY@t[n qcF4:)5sv,9iR:p|{rUhLQWLc^7uZt^peG‚ w9^'g)K?uOsރe4 J+o붠ţ94Q]7o ]SRhL*e8ƕP(( 'n:,E%E "\rпzz4o.O{\j `E>fd2«gPn:X;0D/Ye08{jRqdZNORGJD)Γ怛O+$]$v8/(R3228H3, 8yDʣʜ`F@~P+oq]#B( my|:Nȝ\訋O C  9%(% ǹpl=ZHKqǑn~Ρ"O{J wԏ]0_. ܌v9.)~`,BZ>lV=QI "Yp&JVAiwbhAeŮP-cOQ̫nqO_@گ{ٵ@-— “.JsJplY[Q QleSpy/{_ʈbfD{H0V(JT2[r=8PD(/ZHGqG_gQpgRf %uuu[ٵ=IsPƦeˎVZA9w A ad]Hrv),orZ4 %Lc,w2zp\cA~Bh!-a8#=U~說.}`F:3c{aP)r.ñj!-aGg6 "(gCsBͫppzDAx?bRg,-BZ>zgNGcP|Jwٱw@p U{,= EHz]^gl1p7QenF(04WjQϝ 9qmX<'38\ݣ[6<غ#Yu!MfV I |\A`AYcK,-aG q_[iT)̢~/c7vIu482~b; Mp88KRZD i)8|tO q\EyxyѮ t]_O(5s\hnl'>vqB-BZ><_iIMNfM(f%CYؑ%k왂'C`a{QVvR Ⰿ##.( (/ mD1aHqTIXEY X%DDMPB-8pBJs˸Mr9EA/+Ѣ֍CX$8p k9Z}6NCU)9h#vDAv]CC>` giRqdC)P؄ gww#Q3B? c>2ŭ2ːmo sd8~u)Z䰏c[qq%ǁ遷-cv ;G0wnlMhURc~t]ʩ{ҝ##=Q Ey|l~f5-B:nkGLx<zɝ>֝ٿ 4ڸ;|?KP;uߴ,>r=t ##Q:m4y#ZX!p[5IlH@eTkj!-a5ń,s}RHPf!FUm="QX8Ҧ'z|y_C.M/,1_DYZßqh\cWz! A.v譎?ҥ3V6%Tj1e(^JA~Bhz>4K13~;1f6(OU*y [LוZAeмf,YZ}OUNN-dvWٶr% BI- .#+/n I]1%M8dʰ?X #^&(ūwvF`S6 Z0JpvoA|^ a.w*Ⰿ#+0i;^72]Яŋ;۶ ;~ZՉC ǜ֡ZHKqǡ5XnsބkE7 !>D1v/dmciLm |+hQ$'79țf"Rz9GXM"-) 1`O-x%]Lea%2cueRqI듩춊zT7|%2/{y/J|\`旐Q#-}m,N;y^|5c??c.xQ:vyK#/TAFY={gS*DjꫫYKu+v='gd6^쾩}hY慽mGz>.ZZhFbbSQE=V$eEa&}Y39-Z} 2x2wA{9X,1,-S䰏#q{qfjw >raw"B98(, QI}EFNi#$ЃHeU?K{r9um 2`A9#1ȡ>4%ZHKqO8 K 6xt6+.|!.w.T§~=1Q`G>֠X)'8ύ2JcBZßq䫑ms+QYy^ @+ 2[YEk~=|قAe)~Fe82%M8KIe};TadQNӗ_4F¯UZsvmb.ۏ8L|f,>}y, CyqvPJ@^2Wհ=s8v9|A))BZßqhw #K\RXpnISDxQA,^n,B"¾Il>DoRG6}n<'YW5 P$,nԂAeD98pl=ZT]\Vy^M7P>4ߞXYfz¶Dˠ {&peRqlq`^i({Sb`8#SY׳g02.nA6.ױpɔ8(WTQQD:YVY^ H+ѕ>֝RglRՀک=GyTL'S&nʢ tɫfs \lIj,Jq/fq8.h}?쾏`S9Gᾙq)flOVt4lh0A`#s݅>$tap}y)uIVw)7l1T[]Al%3̝p6x5vk,x;p ^ruOQƚGH 朳126?, K5j!`E؏P׻ҫUQ~=;,H;D>wXH-sbHoEXʩ/kBҰzPfP`=7\3f8#M8(Ád8F˔%9GY> 7QZ~_"!'~=It W@EXn#ƙe) Bk2G7|̑~p+(栏ܬ\O׃|ZuerxUq,1>sj79--Y,n@$)=v1 g8ϸ,ZkX2Ѓ{3s\0=Sg9t5Om_~aNpsil߃!CVh}uft([Hb3-Ҏ7 ;c*X [cEf- 8)|.X:ԝsQe` ݭZf+ک} rF3SYj] px/0NLc`pfx~V~$%J9WՄCOgh.N/bnnC'D/PNsR[tCSMU/ϤVVdRo EJ\=[)fڍpY I9E"F f-87**ªw(v9Ѐt!uX`#0ob )~vۗeJ*Oj!aG0mHF3n&qPnU7 Iw !pQ,Qi#K Ⰿ#ۋz(nTv +՘}³z:-βs,(VjeuM - 80mSL1M=ͼ:Ne,'4-(4ޛh(!'BerH2] -8DXr^aRE'j__"NN_O`hawC`Uw 1dh%9pq\_pZm(--x&Vh EpEv1`IoIR}BZ|yUpD|[Pn$A<!SFT:9v! Nh [mpvXFELdB a6V#znibN'Jmne+}uT+-ڱsvtqp]cei)8Ҝ[Ĥv|F[IjX+[kįw' f LNV-Yc55b"۬:nThłZ;O/2#0j>-͞s\T:aV L2"YHhRql{鞸Ʌ%j~tG%x8Mnv(u̖eG%CGLނZڽQ`1}nxox R]+Kj6rR'ǵpZ}ij1[gRTo}u*0Α)( %i2Z䰏cs=y?\<bx[#2Rҽ6&qב tNjtu G,)v*TP '6la˼%YJXE/;uד" {tb Ot {k}XT2㶇*Y[oAvXU(l ]C:(nֿ<1E\wz`G Ɓ2Ϣ=Se'[qe>H=FhQ|sJNV1h($$Q 8܀*Op@$]j!-8!Bem(`Tn|w67aqpߪmhV׀ʊNT:%x?!6Zu1xIe!<Q:;KY*.]1CgB-%9G1P#6ܤ>.:94΂]7:"4Wo5;XPw!QrlFo@'K;X_OXQW m/Q;PЛq F1Ayxq~cO#]"%ܣゎ滃ؔXU!OO[-=iϬa\}Art-72:ÝW:det^c<IEM8C:6V [~!=Mf⬁_I/-s2^UיW,L_P i)84~l5/Ńb;˼[aHErÓ|``@L 徸^8K e[W"Hk1Glhx E!x} s=#|ˇL]]p XGtjN vQ#NB,.``3Q5O"aȨz ǯ'źc62yy&rhc¢%-BZ>/#>= JﺻyA{pk AeŞWp`,тZ} {msV K)Ǟ-qI`5}g "ŋrppG%8~?K`/1PRԞ |x(7U]@è#cpo-#3s2p&eLp.1v35SⰏcb Ι3y[P$J`-0nkL]@E{IDdyJR(([ؽUM1c@3ܗG>QGqla^]CK1!A1_8p~j!-aK;n^SphZxl&ބiF>S;!eu?^n?!!C(t㵂vC*F@*`N7L-s|0"(7K giRqȎ7l#ԧ͓BPJZ[M0򞙂3a~(b` lbLpD>| l#CPxS7hF`؍pd o;HZ}\[YQ˂Qcodfsb.+J;rQ,('d!#Jj!-aGvx^J ~?Q)Zu |DZY%P+~?bp-}0λONO9YrwN&s>=f~dU-FxLRx\e wz_G|aJ%,܌vn@ !Tl;3<9"nĴ]$'YM g_mX^x?_ GSwd-KpQS.SF(55'AJ60;gru5z>@@*><}" C4N? %V(T$-Q+)A+XLt"GT~݇(@ox}?y%[gݼ<;g^62GXqX56ɖl"1VĺЄ~KúzC6 TB=t`Jп[dvXhL  ,*ը!BՆ|dzi :j֮?;8-i;)Ap"K"h0 6[ۋ -&c#d*XWQT >srb^`Bh;QIFsP.iLέa 3{i :A_P,ޔ1%7 m3>gHo)j{ \mGKkXQfEu!KS|@mC 5zQ9Џ)v<w1 s~5Zòxf'̴'\]>Yr;ϸan:x{rT ޹}cx?S?UB qPm"GKkXס/qnw9ErA~{A?_ucʈX5l$03ƼG~KúxP0Oy⦄n{F˸!.Z#ǹjHl8IV*>ʻ c/z95ЂYv˫>qen䖜;"S 0sVx]L֐6di,5mA~a/:z?۔w41 K ?hR_AEABZP>BHo("qń0~t"G԰t9t-"ƽFb8 +a&0?@Wx0R`f,Yu!_o/?EAfn7K"\-GkUr;p ~\@n`(+qG|׹h0 eI1d\ 5hL/a]G4؏gp=+Ɂ}eoӍT.St).iL*R #5OBX9Jɉ@ȉA҂]c?c Kjdc&t#m*XWQ0JtU8.38[CΊז_`qbO(Y*?88z}Sf֓v^Qk T&j_7O ٍ-%꥖k-md7#53hs{P<#1<%SR;]XTu&FW 봊"cIl63+U6z& gϻͽߺN ~A.3ٗن)dTji^9O_7 (D`Q:2!Rk^iy0u.4P~Zn1"u+,AR R=2%5Epvn'zkZ.BPzINFt~'h[/ǘ#v,n$N^m`a/a]l'3:ԉ&GD0%=Վ#EEAlbIGsjj``]Ei8ӜNc"9 &F{*EC byGTuw<|{&~[%7;C|yhsWfhLTě[[ruXmFg^ﮌYun[ϒf1h]AJnxq`l/#jH{J]35j={i :w Qu8om>~Gw2I_eҧ/H}U-}~Al_O S7ɸ#xaMw v<.*h(|yY^Rah§m, yx_<'"6^$vdbEѢʥdc(α8s#oiXױOu3#NH\}Kb%\e@+ /§ā_?jL<ZgӁܠ"_wJn䜝Uå"IQ#W5$M!r&kjyu?D+]9()obJnGP"tVeq)'ܔ4h`Ob@ 9J5,Y$}ǡ'SonuQ_v`LgJΓp< a/<^Zú%%*o0"i =-Dv]?a/:`BiNJ$r-sDI\Ӳ]D7Kh03%\!! b=GKkXQS=j8T=C *Lj|Lgsilc,SȦy Hw9}YI][ 4^wx_w*_[գ-E) 7^R v9W ƴ4$XSC{VoU2uuoW5iCH:5y)(~ C$֐6p;`Ƽ>){jL'<"ݦuy칫4JF|5F"@$̢$,z1xAX6dSa5DP![.a:!3Cgo .-g:(ńz$Dϟ}nNSۤh RlВ4#ၜѦJ(0S$,O Xmncf'< uϺA}{}4Ut nr#,x =P#+M,):r<<y}n4{^]x^1ѤAQ[ŽHķpt}/uhYCE;SFҀb؋1ޔtd:HrFnq!LIܛyŽ' n6EAL)9oaܫqNx}?y NFؕ ʔjձsʑ[]71ŦD!)k@.x!~ H/:Y{)[ʋTKl ftL%jt`LgJZDO&t# gp:fѐ}Pl_| »cJM ^m&/<^Zúa%eD׸A9`KmKdarr S1m3c2X4/ߥ! D b?25*Rwu4.~CB*rT_ |M^Oq:ȣ Y_7O vh6-LL<ZعU= WS)yPvP/ܸggvˍL"!+qՐ8ӳ-v8W H/:V\.A1s.%Wgэl$sVwsDqT i IԚ,5gA~a/:iB7vVɣuɘr%!1^ K#Q)iupSs>b~}}n<}~[IԌ#pDxr!+~GdfO$yUq'yJHzy䋤- :؁A^MAMgyIt{7Ox<GA6OJÀ!Rm̭xhU^uuOe~YxWTeC€u?=AQֽ371JhH\%IV0PUlN/rL :9Hynr7nRS;E34շxU1m":5w0~?bHa]ǒˎc} tS,6C$qx xV ƴ~`jhjX"^Zú%P՗(kGz:.ؒ1˨#a ==E6EkjL/<^Zú/8A o^ɘz`~lXA(3Q^Ж4dYAP$U Hx-*􈾼PfdvsNJ{~_{1{ | Ew,"u05eW&}LC42E[]W +'cIϡ[ulr"K"AE1m)q;56 ־{i :F2M_ O"hHM~;9dιѧeIx:ɹG!άH^峖( rWs sh0Uu+9; ߙ\tZMfRrToP5@c[`L>؅0fJW>؝euzbvbDiT5K GПrW)o/˅ӢdS0+P=R ~? ְǺg=w6PƿWgk5elXB{EgP G E5ainm'S [tzWW$=z/{]dsƷ4ljcs#5G5G#F [$~qxt/ۑX-I4Q2FJ;kL"ˆʀZ UԔ+]{}~h<ob܎ƃw}Q&ϔlVdY-tH*roOJ)ه)9(ݺ11JjHLgJƶ X^x? A,Rd=!T.aLS㗩EE1m)ilgA~a/a]GÁWL&-uJHy)Gm`Lp_$ŭ5W #5먡ǀ,ηMGI)XW$0/[ 9y pӦ&427R 3/"%DAVi#yG+XW=c|؉5?_Ikݟw x''*~iQoϜ84Guh.)y&vH}=Z  SrLZq6Lyu ܢIA8<Ȍm' ^[B|QG$ }S g}7{o3Ag M4%|Ў-;.\FmE0)<$){YUFtbQFvO|ۋ cUd- ֡J;)Ep H:FzGap[;|+[Zúzu!DHZIי$rU҇Y8.D?BbC 9B^uZ0cgUxu0JI;u͛5a,\5$nfIÆhjƖGKkXQQČmp?|K#!nmX7N~ÈJ.& %iA k1vB#Ki`Vo 9P+[lv@ףxlU6.SWouojzaF@x-lW̮썔'@\ĵղ*Ĵ$ S6^Jßuxო?LlN{OɣCfRwZ3)G((5$nN{U. QsTm3g#GKkXQH MZ罻ے[ c*,w'̤$ϟݫ愙#5XLI8?P>}ç!*?/Ӎ_1~ j#TyًͫmߐutIcq6)Nw#>GyjH<|CRL EiL>{i :4.BpG+.XT(W#Qǭ"\įzb2S!-)~3m5A~aa]EyHL+msԲu%Ya6%l/9a|6WOyR5$]IɁ̺A5ji# ְ!y0v˒:Jҧ';Wm+"Q$nY'ɽ1q.-/>'igZ.<'\*{d8ȍ r-P?O_~~.<}>ήR: SUY }<}^Oˈ~ _r4; qSH&%ۮ2| WIch#{IxV# ְcI{@;j76T<)m`#eo8V G2A)piG^xuR:o%5,xR2,ۃ o ^ɼ۹2Y0u$g(oNHخ.ϳtFn;o}X$'r~bz8!dh>Z5ӆf(iJj}'F~k Ha]G}(-HDѽ3:G`kt@C(xE{P@񱭳j 2r@Eoa\7M^|)d:0΍`:gB/jGɓ?ztCWrvgy5uwz,x*h-!m.V $TǮ`UoYojc& Q1䳻̒kSptڥdba]$g_5y`SøV#/GKkXQL>gU$JE)y& x"\nb2DSmR\dȬE,k#f%ecM^$nL߲dg>@$TZ37Jp^4ӆߐ4^mGKkXQ7LUO#%{Q*<{QF˂ڊrP#5%v]S[:+(TaKHn\ժ *j-iLIb 6/<^Zú-xY~z!}r-sVʯBUq G$,a K6IA4Wi_P{a˛w;EA(i=Ec^gJz4X4$nzydGsA1iX'xuԚ]8- ,#Ķ3WX1"Uh0RZCW)mJ/rD- :?"ç];ig|pXeB91"z*T ƴ\mA{i :r]OG+(E?R7 U,ylf^z]sڒȗ;WRY^v$ لz`ܲuJ65+K[6~KúӸ_LH>a}ԛv>O֮%#hHLgJ.xZmGKkXQ ݜ/`KέPcCI+֝]YBU ,gJ;VHӚ~we+tbSlcg8UC-959m+Hְc)~N'2ɃDPWylΓ̑{OY%}7w4$ % Pl"GKkXQcPNzsxԗ.$w'F/{1~]N֣FđhHL>@PTU1dGL,$]lL=5@̽($e&I2:JsxV ƴүCRv6C{i :N3ە!$.?C|[^F`/#Ƴj3%͋Wi-b!ЕCAEú9})CjJ=K!1m2Bw*e +IRWg Ha]G}%=8&u{ #_LFqB<=6 ۿ~1=}dͩyn<}FxY4\οjJӁ憔Cw/og8~0q$i:LXŠIzi w/H3ܘ! $Q$dQR "ʅ)d7붤85cAo]>g5hU 3t^0S1G[-Ktyerl/HQ ~i~>0:ܾ$Ӡr"hsύcc j% #4RABZp0Q z[MׇGGkXWr,8 wf5B1=ƿgݷK޵)ڜ`VjuA^c쫙5vvzCb᱘s)ik\BWsQ^|ʹsd.~K GT.AK1WyyyW3O-,=OgSv pvϮٖ}&mٯb1fgvM_0 p|%ul飗PJÃL#AO*al.=UCM脟ڹ D^hDzyDjl˽;JHSZ 72aGsE  gNOE= id^;^DgP}fj־NJsϐ$6ƸZApw_JR44]ȗNx}uJVbGI`%tf"Ԍޖ7,,xh̩$L&e},0s:\ Yծ= bj~FJGKS$z CN$S_8s]/5+Rw!^a:"2%Y#aW#Zuk59" ͫ<[b%5ӆ-dzi :`POt&+ƲE 'D)ؙ`9n&];جHLOV) ONomQ~y~qCxr߯ :.y"ype>0=x N*G}`LgJ3{GAC$W Tuٴ}~*%0jsR }H]55ѷEě;CY՗6qJ^Jßuۆo CE7>qc6q8QF}Ր6ϔlG%x3=U2]uu13z7%cc=Ϩ> ƴg%8VzF Ha]9@`:Rrnx:wU~#j0 v!YtLybL/<^Zú}qöIUt4Z5K/yVl pBF(#ƾj0ߜ P~?DH`]E=3u%<xx9I2|(0Nڑe6*5"NU1m"b*ӵW^4Q3ݥgfEv%9RM-˄:3.JoȥD?.GW*0aIGЩ1nG+XW"Gf*z,%d$ D)Chu>eZܦěS$AqXɦ c/z95똏+0_q 7SH'^K>Ҵ!eH{R1m73լl wu7/:l`8v #9!Z7<9uBlvi&*1bbښߋRBleU&W_6/Ň#}a8k14I}ˉ ;_9t6k]n'KKH:IxT6G!1l`j3I!Q%ejXQ)"#dbZMܳ6/1̽JlChge$ /ӿᆰiy=Jؐ1)yoS 8& ._5L쫀D35kU{) ֡!@1UDG*emCJe[DbPILfuPsjHLofA7:y` }-64U^Zßux+|l(cWUJ&^Ƅ&oXWEEʔ|HVA[i#k ְcyPD8*)nCM:hB1 6' B7F ogŹRm&揖m]fc%4g{ KF!e#^zm;U1m( u5K {[mق^xuqVH{gxJ47u"Au+8\ECbڀS߫ bl*^Jßuԯu|.J͏ƄlhV"cз9q]lNԵ5H_Պ7.چθ-Gl8p_x)A(9kT:x?S׈rRCWmN^{i :\1v|iMlS ݋;<×^ٟ29aQ^JԨ:S t l`Ccg8_2)y6LpJzqU\CҠTYzuO 6j)3uj (MɃpО|G_bf}C-v V'uh546k)&vd+lV]kBuwMR.HpE?I\y}ŲD%#A}sC%MAie r1U1m`$j|mA~a/a]G _gP0NR^j¶2TsY50d bퟋdzi :ꓪ%Y{kHG}ONŊFz#kՐ)ӑڵ ƋnTu[h M_8sb9svX$Iә<{QYJӦƋ lEr#y'+H~ⷴw+{Xrr[q6`/<^ZúՕt&c$w4hPu}*W ~E»-D^hDz) ֱdz)EV)Qj=B i}t8϶j0nnwA"F^{i :!D",s$Wz;% \n_<2m]XId迨 ZMٔ sA`9Q bHm{}䋯E}4^~?Ggyԁ:4wn-jC.hщ_U1mS`jQJְr]bousJ"]+mjF M^J+?F B\,oqZ6!;Cu5Jr2_7o7[}xٔ^æ-?DZjD۞EnHSZ;l^x??N? T b˼FnG+K|tAǗAc, Cm/͜͜]:^o|}x}dqEzUq68G&I:6 L Ȩ!Č?ٮ$'WA3V?ǂ:EѢ6dj؟^xuC9p%;/`Uws'ϯW ~UlKK.*^veDM 2G-]"'`k&rڦ$.6G!7GD;.5/# b*^ZúzHx^ 盧7=-}="ϭj0 !~'5ƯFqgub :Le…LV@ Vl!6:h0S$ +(iYga]Z|pw.84kg!8wܼ|4),iC&Ϳb ~? ְ1/o<~ٶ촋^ yVio1IsͿ^mGsFgK yE S:B!"1WCGDH`n?`dßxD.vV%8-\W@:Qc5 G"GҰ?JlkC8DWm6&ꋴi~Y)T$[4$n.qЮ1.[^buZpCVru#`<T' OUw_(PSr2E=qaJPBX5LwKRVڧ ְ`+g,3@!ҝ-hl? ۑƯ@zojs oTiJi~GmSϝ8[>]#š^(tvUCbx?Eenhj^xD- :fCQ%[M],ytONh_?Jw2h7햰Y*8nd:)*#eZ6l;x ֑eS23 h=1^GfvQ`9%DH YmtFlR_'Ж0@ݼ܏߇^1zV o&LDkAiOJg0߇!K.rij4߇*v.~?*h0 $9 " ~? ְ|kb=>ygͽiS .؂Z8%ֻʈ`/݋İ~A!khjL/<^Zú-B|2awH5ĉ:1%;rR1mLxG_%kcqݰ[u=lK;v]nB ;:&ο/7-on`%WknY Z ְf֐3aU$́eu {ˈg[5qI.6c{i :M.^ɩyJn ;G}P:G]!Rr!|j8ƙmGKkXQrl Xq~Y_`&vy j+ԋ9WMKrM>bj3m{Ztx|)v#IgmјUK{לc@G<ʾ~N{1k1l{ HS[%ÅQ$#/$f8~J MRøVgzuolcNn( d{`/KeQ`o T.RW's{٫\d2ͦ ]%|[e5 'qU1m)iV-GKkX,Զ="#3S8m8X$ĝU0ąEE;!nd䝧//[29 :;@F6~Md—,GG ?&tl6j墚?^KM/^ן7q`El1ƮZ!c Q +70DnH S@9=(*~B){.y:t[$`6Ah_& R ƴ-H: RC\U ְ^1w4 sy"NwmܯhD/i˧hoĸ@&1nE}=e_Q$DtssTKr74 䆨` 9bV ƴ HNeYq66U$KkX^WD JT~20-Lҿ vA2_6魌U1m`$L! 3{i :zO4 j3[B¼"q>2&m[2;L:#j0N|_g}|}GKkXQ_l$]]c7ɬӔe8RذmTh : dzj0 ̐Dp< 3{i :qԏ 66QNɍ/K6ĖcnG;sDȪ7$ϟ byux%dwS} ]FvĈ um9C.H1^sz숊~B]>sydoIrʧD}9H#!?ad3*Ao!ptv~Lc{L'r?A_CD׼Er`<0shs#eX5$>#R=4DNA~a/a]G*Tqc nC(/vabd*@f<"؏c;$Yy6q&a/a]GSF:1tnSr# =jV\+O\h^~ .5%JI l]=mdB#KizӪc*dO[\HMnԨn+5|9{fOܧA Fɞj/rL :㪛怉lbnH-5~2 mTqrn<[{DrHJ1m}`!E pazNjl3F%۹/ Rn砩G˜[&dKMyT%C9y彊Gqn9H=o,u{zks@ܢTiLI ~rcp#"Y{0P}jјclh:.=}sDԗT ƴ$0ihjL/<^ZúT%oMyx"~8~S 6oJy5tAׁ(ӷkѿ9a\y}}2}z}ڙHB)&KG<8n_`UQF}`|:w=%?SWuԟ,Q]*r7DL9DŽa݆//ޣ,Ɵgk)TDTD4햧WYIïal8@SҐc1ouMM1hS$U~Ry~6U j|L *!L{1yM| Iϋ_ Xqq[#ƹjS$ u&jC9"u-ǞQ[wFa 9+ S$ܽh0 Eane=@îA( {i :jMgPYG򻜒N;G`^d(#ξj0 l$pO16r#}lB~k3M̡D o%SsG9BxsJKԅ5DjC8fȋ!/SúuᓒR)B!0~ټHL<55)PL 6#oiXױ6Kp̗-hv KpB\&H")jAX">Z`fy822:%T\[,QÝs~;]d'qntNxu}6SS%ٴD.7d sk~0m1{i :=لg2E&xse9y.>EGۣUe*pi*#5XU p'8d`#"PHWEcw뉱ypj03%zc[mGKkXQ6,6U0c-%߿ߏ{F3R#t.M ƴiHLo g[mkY$KkXQ']~ oOlq8W7,b~>2=S0dz(6g/;Oү[I[)=C ?3K$ ̡,( ƴ-%Qα ~? Ha]Gy 횰. X2AId;̉]w8_e2ax?SrxT '} Uԟ*J\S2`adgfw/IW9i-dC;4wϺbB9"ݦu5N$Oʈ!%7hgm$H#"ǡjH\ D ̐~6z1 ְ[mk+LyEWҍUyLy"G>`| %آ쫍Zz5^ZúQ5u@= ~"iw#zh{uT_'#;E1m)9H,ƽ #5XW*y8|Iu_Y"[i+j0k\8פWgzu,Q27](ض\<u)ơ8Q& "q/z)Ұ+O. č5Sߐ>oற7#wTpe~/ /%L۵|ߗNx}u5v9obҘ(%PaCOK񦒇fgzu5˻0y?`Iy@Ns}yu8F[4Ô! !، 7wsL :uƉc@)I-ю#k@p2Ƣ9V YƜ&:k؞fr#5XIQ"=nׂh "Q@:,P(He{ZH"ӷgѿsy^%h""eha֣*swtND'vkr28W ƴ~$.j~WM㼱WtR U?ʻr-ívĽBk|9#moqns6O0\e U!y,\l`x Nd8$DZI Rs/3EU }JLFZ{ux عlwn%i,=T(&;?1Nog|#6pX3/5{A Pyuq־;wAn}SuT =ȸJsy,e U*q^h6?Wx]>2 "xl?_Ik_:[؂?sΖdԾc-3y婋Z{|YOz[$׿"8 &YLDREqd#5 &m.+[u,_Vdl}Ѻ7Na 1@^N#5q/^feDi ƴN *(HYr^hDz) +}ceB/:D%-kR 5}V ݇E+9L1Db iL" Qy^m"GKkXס6\UpMvG,FR oPW`<,T߫t#X6^4'BeA=|vzuƫ$"+K$֞e'p*wG/F0U1MÒpRꝴ@~^Kz<8?[ w_A[o]iJrGwTISFuj0YoIpofEge{i :b}Aߔ[(td}[44|q6)4YG}@%ZwIeM(Zh57wҎqorZr⒰~?Eְ'N b<.:t8YN;|En oA"S"k}r} JDl}`SŸ`!z0Uϣ0]G=ěRnj؎^xu+L_d^ْھQ$=^q %Gt1IABZI5Wa*j6/ #2@ R" ʓ5j/~Gt*)i! d6vW}<=nm10^;:vP۽Y|҇),' %7ndՆI/ru\0ؘG1%ccO-J>̆[D&֝чffAX60Ch԰}!3Eְ[l Vyuʹ:?$уo*~y|W"`L:| y|&~Ѱ Hi?+ Q$mI3 4|?0~?bHa]GuKvp:DX.`'eo4jH~|JXm _m#M](jc"TھN=Nx6u-Iz$~ɦue8W ²~?ฮńN-*Y?8CP\'ўdWL[qj03%( m5AU%I)XW. QǷ[2 ̄<ٟz3q!"h8Hf( 󺊠xK cTԞhsCo7CuTCkG|vugvSSPn5 -x\CU&.wsyz⦿.G9>r6;캖6RE%L0zLWLk!sqW=i[k]<{p70燗\0y]SW˫DAo:]꿟|. ފ e' @V,ͽ[t[nkextaW'Ն0{ mleONֿ-%;ɱ#C--;\sD?V ƴά.j(GҰnwM)9v\w$Eo;PEE0EnJޅYڽhM/<^ZúVI%;ÿ2.{R7]ky5rDV ƴ\6{G c|g˩a]P'YL#?HULQ%6 wqݫc~DUoaOz#5먱q7"Ɗ75@L9OEڂVey!*A iC;dJL}6C>9bgbc~bˆ1Ԗ"%Qx3F{h9NG_I'KCbPLK Ǿ VHְ6ƾ|bNA~WTܰIc񻤍dI/<"uuAK a ?Oْ Z"`pO,Fz?X5ӆ~О3{i :CoݳAm%7iqlac*Aχ 1M|?Sroj8,;; U,!*Ttg THNuq  ؘ1?6j0 EU!cc[M? R$QH M T|Ynؚrs)x*Z1hiGx*vS 7 an*DB\VM`A9h:ICmӦDUp?c!1?먩3Ns@ouJjC3q8-9"T 7%[D>ȬT25'#X0vCmo&'H zSDd泷x(fs4`ҝn<<{%y[ң2P$Lv)XO)dbnfNgge8PuYYV77@( CȚDiȊDW`;zaȊB#Kiz=kk86uk 'Yr1[GLHx:V%HY43%ti81#51Xny WVɭ=R׃4A IGߦA!ۓj, H/<^Zúz9 3:rI!jZSple-a&k[53%MՆ^u+}r/q9 wB7M ¢n{$VBȸˈ)`m+^xuk=oUF7H$ aN#cvPmQIT؏El|?SOjjCnz4Y8f(_)jIɎˇ*Ũڮs$VHXTӀ pg7+ ]M#В Q`p>—&ўnM"`;=f坧/TUQG02$%~eoԋ%e{*iqQ`<߹k ~| Vf1+o!w1MK㨷I>;O j tMIW5kAxuK"8㏖Q"1WT,Ƃdjd Fz`|G_ kH߉\J& F~' g~8#`+b=2b8%ʀ$:zx2/!G!)-!ҰW6%:$L :^jpćY`;%~ɋ> ؍v2Y6;2O2,#K6QI}ł0[[`]W.08 I%Ԕ ʤʌQ'q#ƾj I!T'5mv!9~[ú b7^N9zK;fIN;iM?{$֞Hc nLWk[M\nLNx}u^y -tYUq[YrYiWsv+ ^Fo6"ٴW؞ Hc(Ђx'='HTN]1G϶j0  y_ GijGJְ7%owEWԂ`/.z;UbwUyvBN+0Sj "U˥/lZS%jΙ 42HPiApqBȖ"G԰sjw$/`HRq,j_ޥ 1LD]K"ѩpL6F'r|?XNonƽك|U|C muLU8E01l(})ˮ!Ն0"GKkXױR{|ZM1m\x F_V39plch׷^=p[ }upLwyƔDH雏9+d{P3`Lϔ` TOz#52Z4Ut4Fܨa xU [:uq t۾h\=@y}S3qֻ(Ot$|Q/s6hL7Ηx[Lryi}vlZ]DF~M۷wQQq=sD3%^xuZ0C$gwjHI, ;|`Tz>53%$5gAL/<^ZúzlXoR\]ͶS⛥ -pyWIriEJ05jpmEzuC2xG"(IM[$$'zFM#@+QH8W4LLϔlOz!~LKv(t7X~XV*RZDUˈs_5$T`!9^Zú@{Y<[Y)O>ƚ, ̪$#gj0 $X# TmcSJ/B ,̴]b?;k_U`,$ '5W!9~[ú<#g/#참 %H&Gk`]\v5jcwqAz4YG-RlrfYmgg;`L!KRlPsU2ur3m X5_pNq~eS4+ W$U iCa8Hng*vjXQ88vR Up$pYA]2Z@.TnQ=ϝ*ᗩS@P'x R0˼.<{n2QGJCLEr{ر>zܷ=." r`LzBr"dj83{i :#jl A|E5G&M%w7L Yo[$(]4'%}4u_l9B^uPcrhŁy )9DN:`'SЂX!2//6c$ 3{i :LgrH8%ϥ@>$c$cΊ,Bahۢ!1mE.o!VOz=;,6&xё~zKAyö b*0 H\++PUZ Ys(QeF#nl+BN2AL'q93gGVQOSf/'|20rӎ\|c0Wƴ1m&l~tsICwlt'wY4G*D:)9E1n6B{_qiiqcFA?S*6GKkXQRpo`&2n5v-_r\ "c~,oS6V#oiXQs؃Q(vlͤ.R4 r,=lİLIkH ~a/a]G} ݠ8T\ͫ  NԩF;k}csa}ĢP&obX;!b9O/* tY{|HM-YM>xah|P^5'?_J.6k ^xu5ļfva(>Ln5"C82b8sj0>7%bc6 Ha]G]0M"}e{qi3$AmAQ%KkXQ߻|*G3|Ub2q̇7wC#y 𼭳 w[['GPO09O_׹{'76 |zo7uS*$B`Ǫ8 D`>۠u,eKOd -h[FQ#~!_V .4[3J?6Nx@z-*\يŁ?%{5#ʵk,L<)? a0*I/SúzWr/x;%nǘM"WSF95 C^m?Eְc az{JN ɛ_s':=8W ]=5c1\^xu%lTVDȳ NÒq0ڙ[G>N0Oe1뉳5L 4ݫz'NB :DNo)ѥdD|=Սq<UqwN25 ~ H`]EIe|66%oD'-v@U$gg12m7}Sg.EziXB#Ki$3a8?ݔxu<ϏwkUڪ!xS ` F~GgFH/*B\Kb˺+'I8g[2|V4lW]*k)XW:7{$PrhP,@tΞusRGϿ9O}=$.z$Ľ9CE}=6F7dbx) ~?6ssrse:v_ \K0L}$;W7nLϔ(K7ô@}\h ""ʎliolRds Fgq4iF{RUԍ 00S|S.O~r}>Dk6!df`Xm?Eְ1C$Ds?.ؒA*f$kt%*}4"yĴ$PBgAL/<^JßuԨܿނkԔ!3ice KkMJhRomXid}_5먿`WORm'&"Cc8w?dtڷ,|BhǪ6P$8U Ƕ ?QL/:>WB.Z` Y/vCފEu#P @9='ѤtNW})TsAtn5,y7aVڭzx2liCCJv [6V#ohz4svq _@qcwiݲ PY1mc3OxA]L/a]Gt|^r$^j\)aV(7bg_Hj. 3ʒ ?pơ$%oh6uTp&#(!~Y[ :7ݮE{!!{5^."2DRun):k!%d ԟA#{Uxw%[g!50'^69kR%96✬RW<3\5gNwU ̲Wv_?WE7]cPdM)y+{*INcՐ؉)ݟ Z%U}U2u{w8bR ξΟkJnZ mPo, O 7od 5cA樒5WddQ7l(ޘ]tq,&E#X5ˆ25( r~ ~oGu6oW^.ol5lҜh<-8p AS%aX5\;9XYl;!/<^Zú$SjH$21%;`4BXW[Y䎤[U1m|?)sRíĶ!9B^uBS ݖSz*̛wKqH7cѐ؜)yuj 8y^xux%$09ugjpp Ao0}'@_Ƞ%,& ]hBBjTjǟJwu(<=ǥ8'ePE(~GE*>ʀq-IжG["{eAzz/7% ߹2m{ @ֱHR.HqvEMbiG;wQ#gZ{$3iH"fuve ٭p!`)x [CW#5Xqkh>w2YRQyk22oھ?n'v݆B<^Zú fHWEyo[$ R |vMwkmU<2ܧ㼭JIǾhj}AL/<^Zúi7SfIC#`e#̺a Ɨ)ѽzj8oIdzI ױP8]ߢN~ $8? MchVW4$ E(akբ6"GҰc '.DwPk }n5A=yu]q/Ӎ6qzb$ְ,A gj 13E%"!uǵ AX5ӆ"JD!>)/6H-5o#ŠL{"%iHS%H6^43%m4B6mgIWְc8ߗzl(-#d$+y90xj6 J >Ykq-6`_$oh wd; ~$'ŷoT:<=bUlやX!l !/ruv L͞ ;y1ɟ\$ H^43%-Y LsumWPOtu)7%(vCb0Yy"y1z2|CIٛ m5AkڏlFӤZ]h侃ofyM A[OҫJ@hH  c35cAL/<^ZúOgR!tC% rɳ:و=Kآa;I-Np>Si. wut )QζG7 ܅qf{Hrd\SCb2č;GKkX8np+u$~)P]6V#Yb^6"W0vȔȤqlΙ?y %NA\u5Dij`Ǵd??O_WPpkq6n|H<=V Yl?)Ac01m|?S?pm bxƪx39% 0ijCI/rL :v6a+鑂i%# /ELeX5$v&JZ\4bwS2ی IߤBx_ÆjctT,u[4_>ċѪiS@iF94l6?4-Rrw2(3J>Yٶ/G(45_&_L ✩VfB#Kio>ـ|妤mx{G.g!sJX4lSņ0^^"GKkXQ?`('1A1p[%72iy(=MJd@I۱ FP5+n(vuo<\#\L#1NJY4$EMƱ~ҋa/a]G>vO,aTGTģ⊼ƈ%USCEYK4 !6 Ն0.Ea]r@@l57NǭRr󠋗fvjwK˛"Fɩ6ty1a 8^xuÊgH8;iSgl6f;J{=9|5fb;żY49Y\<TYQmV֒wavڱ" o`Lx xO:#X*:( 3y*@lZ"@ei~Ա/Ziݞ1,;wm?Y`Q39!Q^=܎(򅐓ĺ`*Ph-ieww- b$GKkXQ_O/*6-CaL4Duڒ?OJSW4LLۃ$k6GKj2 }BWDgߓ4`B)[ ƴ $;Sv6a/a]G=\f)ނbq%/AJt[7cCTc;sWɻ9V 6Mlld JGҰ>uPemx^1NI?!t~ڪ8Uq$:]?SV#55I}\^w7p -hڀ"ꃏr`uO ƴ_$+!j !/rL :꫶7{{+T-,Q1byUCq)+ѭaCnߛ^xu5ILտQNJ * '8xk[57sOIcpc 8[uԯ^NJ)x(KԸt>Q6hC϶j0 =!q5 ֦HְV]cN䯿U++B.r *FƸ# c IVoT{i :r3ġ׉SijL ق<#8Uq&W35(?m8zuf4:OFa& JX}n4iTe:8xktѐxSSllh >Ǵ!9^Zú`vX m6͞-_d6FmѮ:B>nDE ާ15cq174]G Z#?lzq2k-;#k35kKֹG8 i[r#RSRXM?Ӝ~,dx j]H26F_B[$ɦ,ÔÑ#Z$m{6p-"I|WY~]vWw{i :?HZ||'sOKѠ(y9EgN*#rcA0d=bE!-Ą#j8f Ha]W#"x.##IU!j'RN1 JDwȫUCiISS;L1^xux0{H kԸaJޭCE'HqvT܈HP- d/5cې^K -w`G 58%87;o_W=0cڈ)4uI!")~Kú.o?#s4fOI<4T;= ~%At戫i#fXґ?5c #5K//$4M]ElmиBG3)hV4L,V)aG2m y#5?ܸ8)ilڣI|ۯ(8^sE2hHyH ;ۯ Ӌaa]>`ld)Oĉ$_ؙ<(ى^2b i3,԰1~B#g _38~HrH.I"4>V ƴ3,yA]m {u% 7ǩMeҹz'` Ï<4DHU%#43,@<5D r0?{?w&|<<X~A0.U[C n(&6-O/^:^>X`cgw~uݻKgq&HA$πf츢/ =-@I{NTQOewxUw+먜<ʈs_'޹:: g e/CFx5﫭q?lIS׵<6aGňROG( LV$%XM? Ha]`*ʺ~JU,MG3Տx@Pdό`VcM'@٩p<8޷e|sDi3$YCdU1^xu`byߘ_$@&ˈ#7OɅL-1"2Jgzò (#+^*`gą=ܻO +߮kj[`E8Vg9 3.0;?)8wDD11.1#*0n۝S^lzNx}uzckYM0dOɉ掞w X-pBd:GDj0 YGL#c5AFL*j`@u=r:HondGh {lbrtlѐ6cI<- .1?},utcSpr̦0s"e1"sz;^FGye-)i<y2\E EqKS9԰m {uh;eWDG&qCbJnht{Tht*28gLxǵj0 ̰O a/<"uzvnJp6B-%&F u T#j DQ-Q;5Xl#LuWI[u>yYx"7g:.uJxuoѡԀ f4%|UΩ-]mZg[־aaƊi}P1%[~ʾx3}ɭ^e i"&XLA1[-$<>Z \`N><=0( -xd| čr3邷Sp!;:&Zp6坧/{NtyYկ=O ?s?{ޑԚ#k`+%Hcbj`ic;l^xD- :gݯ,-vw;+'g6ugyR5$aIt kد1 JgLD^Ӝh$۹W ?zىn9=ыz8:q>S6Pa Ʊ>6& R7|&G~?H6GjH)S8W1^xu ξ{<2aħƠįbD)8b#WɈTEL`$g6c U轃opUpZF/ƈ%>wuAʋUi{#ȊdD9؝򦄍vٛ6܆ozuӽOeu m+dۉqL9b\LIɆmԠ)"GKkXסOs!r2xWxJj#˅#4;^14vԀq \i`qڂ}h*ta \>mJ:xXSa]F!J^|-oJ5Tpx!/Sßu8+]$i~qfA>b-1B="TU 0  34l` {MF"1b؃bJ΀3pIOh0 Ed 7H ,U6bz4Yǿ6RK컉fJ:Z^|#r{` X7jj0n"iTSþ66GKkXס \bWjp%Z- /'v؆9V ƴ3,yZ#k1N{wL/a]ǚ/3o\;jd`JfDPKA\f'OǬ$ wIMmӼn4}^)/ϰ .n Sq ?r+C~9U1mF {SC-_1S[a]T},b &dF:N2gUĜT`H 7ƒ- Z_V1CNUԺm$GK^ ϒ l=R+$|q}͕WT[Z5fX  ƥ[u1NHͭFfrӜ9.>tV|;ow-#9"24ٔpo rk)XWL߇y)i~߉Tp#<2-bE* Z4.~,AYkjv96Я5 FFtN$t&}5"Hb 0^Y&S%c0ijH+?%Øt6q)/<^Zúm!aأx<@u^R\,F\B]a&*gc$ "XM ^NhD:IVƆ38F=`Ek<-@2 ~0c3 /|cl (&c\/ p 5єW%oR|O4?Hdᯮw~|6 "S)8'TcE^Dܦ G鸪dX5$Tm !H !/ruK28p?RRDv06 /{ņR!(X9mta/a]FE*O@=r~C}")>R+16yk=} 8c hA)yAzRR"x_< aX"yhH)9ً'5Dӽ NC^x?("5)|F3uؿEeΆ+J'3 3&^&Hұ t@N1Nx}uNG1/M=_]/d8 e !qwMnJoc$0YmM/4"?Ђq֌4Z Sr (w=̧BъGc`LH~#ujxN]GKkX-`H[ KqI49>q@hq i-Z.m@FRg.}S)yJTO؆2j(ܫd-60&sڸM^m1ؽu <%|+h8q6ACU*HL!I15AAa:YC؝sFED!/QKGI"Ul`$Qg" "GokX\1Q/OP|{peIX=:~>Ù<ECb K@ ƞ쬒75YvXT@=m656sқef7Fp%8V ƴINݦZm+M ^xul[hGrbVkWD^'/oUCb@Y$T!4mAmz5m>?a&3Fvvd. {EmBF02,k[4*2Wqqhe? ƴ>jQ%KkXQwɍT䤡Sr-NDQum`~&EL~UhJ:ZO ^m6GKkXסg@$L(zHv^/*Np[kq>E*J d5O_loSJa]n?>}oVJPpc}k7ĸkUg`L!ɅC[1Eְ>/J "~XA;*=H1:?ĸتGvxWJlְmm {4Y/kt,E ћ% qͱ?V/0zO˷^FħQ4$ \ J_U2? 5ATU xbAK$9 RzRI -Ȗ/^s~Ӈk6&aݒ)l7i=U%#m ƴ%ϋ1_GҰCgxGZyݶc@ub*{bUE1m`$԰_ b ְC ~ E{Q3xE2߭Ymxgb gNZZf/etQ/["9Hu?ğ",D{q}/V$wTӆﬦ~KúK7cУVd$ LɃ|1! xqEq*FV5$ rILB?( 'vR UԘ-r&2wp0m$a)T]ĝ0ֻy}ۊ}měBf)X1HGKkX=|#D"+7i#bQVpEABZI=8Tľ ?( VtX"$#J܈h{fu8WG`mj0 <%3+5jeyu8MEPbm:t;)Io:WR OWHƵ% 2ϱ#k?joZҹ ڔ P9UqT-ٹ)L ۳۰a/a]).pXNѵ}ĦMPZ$nl+m玃WwO$V wVNkR[ WN/<^Zú$dz6c~vļ*QQߞn@1ɖ0 2Yúz%DN.DquOb]HLcNYY>5$'%Ұ+Rl8ӋA'`]BCrdP?~M@)`@qlJC60L m6c[uTkgM#|N3Jr~IavKpޣ^m1ؔ}\og<c', wS^lޫdzi :*.د dgI\4ʞQĞ5Ǣ` SBa+$N dOQ _;"X;)PPxaփK"?GE1m K+$Sñ6c/<^Zú?ty~g98~+X{&P)@NxçdȗƜ=v@d]s^|_A(JpA;W5%A~*ېmsDݹ)٘ij AUmHְ&:"xSr1cSl [)28W ƴL( L6gzu1Lܐ}E[*鄂Z42x#e,3Jk{pe #ᄂS2E?!r/u>H'J 3 ܤɍї8X:..iClxҤxT8 Ha]GMkEy.K/`gM>|bܢ~#H1m|?SS!߫ a/<^ZúœQ&"G'4OI Mg)q)?;ٳJph Krs5 0F(C9~[úԨ vB#I* y;Igݝe^(9rY6 ѧdb}ɱ#cѐ6m ɻΆR2iط1rzL/:j$#}7ěu"ܨ@Tmbu@Sb<*W ƴ]IoĉJiҩjO,yuk!dn4}[%l|sgUASr5Kyqa`]YǧmF /b,0vcL؝{:]+e?NN+!sOlr⺟ȷ"b*Q\=3sNR5i(b9qfJH.G<Ǫ!N)~r?S9 g:vR UT׸8,Y 98(GIn`3ɍsD0KV C4SBtd Zm6GKkXס XR`NaGІJPwGChez@ ?İTH 6dk;Lz@9B^u789$Q I`zF㄂l@rDU1m`$Ry6GKkXx:dT"[${80\hm)#gѐx>%L ڧf~B#Ki TdM[gV%q$  ×msq i3$)O Zm4 Vw3m޸qHjD&Wd)_2[Iو>ȣ<}Gr_'D`Szz;uէR0;" tlmcK J]MS1m|?S8 6a/a]Gm.&bJޠFr'Nt4TaqBɳ=dN ƴ$"I kW^xu[yCoICCG>_"ۋmtAsTkNm䝧/kwM8"HI[}!F$__d%ďts@$pm[-NNۢw:t:Ly9Ѓ9!OɅ1|mӋ/n.*~Yݥ@LJVk a<}]Aee\*iuqtb\.( *R[ОxbM 7c$h gzuԞ{6Q~))bKy3 6 S FEh9"V 7Sr6X8VĨ:dz) b+wҺBH465Lߐ]wq\c IH15lmAQ%KkXQcǫl~@َk7ȃ.v|h#FC6Gz!1m"RzL 6Uk/<^Jßu";@A4~2\:K,e~hs9"Yl;N3^ۋaa]G=tM6E˸xjh-5$QAe.HCt!&y$ "d+{ zy `Lϔ zVxU2u5}f*Rdًu9˷!|T,sD{V ƴ/6=- :%uE6J|aSB}G Wƹ3 ;9"bUCM)yy?S~6c{i :{`V3~ǖ ǻw-h=D?rgJFg-`L`mv6c[u,Tʼ6uKFFןmHҾn<}_O]+XMh\w2h9ЕTqeXRj`BZ~d w) b\U2}Ąxɒ;Y8Srk+?`_2 j#X5$KIkj" 2݋ bl8ZL/a]vw;zz }nNSV;p@f[ ,aM4JU(Ƃ}[!K#GǪ6p41ڃ05HQ-6c٪^N :ڇ/^؞jhLָc\O C+{mGdcg9"5!)9M ǹ84N/<^Zú]NK;+4i-%zMuQrMKw⩸F|j0 -aQ+jN96HǤ2qzS☽7v%HTfզD*iF+].5|#"jH\jY] c7q2k9v YE"у H@'9UkEG20{ydS4%uzbPY$SAtj Ir]}8zɲbYo(c6K}>k0uH*n OR`LJzlSVprF,EW*O,d_81NVaJ=3P|%:q>'@5%rs14~`"x͞h Kbp i)Zb't<+gծb4M @?Sk֜hܦL8Miъfd/.ysmȠsڢ&u*-T )/\YI4N 2R}ITUg Q0!`w5}ehoJ}V Ēt<nY0&_Ƒ+$yp`Ǚ !GmަAX6@saIc*4DjC "GҰlͦ{lY^R!tVX=ivWakw5gI] #5_n9+"T x%/ZDyO#FtY!-CA5}bU\sgy̜שPyJng =odQu#w`|$1åa<TzuԐE3A?ng, ^HL Bw] :qk|T 7 ƴYr- F{i :_D'm_3<;3K,iu_̒48JdDS!1m(%*͆0GKkgG}Pg>Ëq*$7>) @[1HƐ#޾k0ϒzi~a7x*Y^ZþZ&Kp U\7:hGhAUi5~:kHl܈/ n b0 ְC`Ҟi  6FfV8V5,H,!k@Veü ְ÷>J"/N;%=JI׃_rLaj8i0 !9E d ,^6q^J?(_("A܈Dr~zM_tVa{ fH2B\ƻ ި4Kf;'z>,eI"ې̦q `-Q wAX60eKC4{6QD/rD- :lWcF>$2V.,8{\;εUCb,Id E>5| D,/uUVyOɒkn.Wme}&Ub}dV-Ic!Djhm3њM-AэsN]*ϡ+`SBָW0UOIT҂UVЎD5[:4J%~wP/c-T('gź2w 3)-1wim1^x}jd`Rn$<}`b-I60Cq5 FU%KkQ߾$y>Ly7tҳ/C`tֈ{i{KU<5h6GҰc#e*uLHIcwx61MK霦 #SY{,[H^E5|o{+dY/9BB8 K|>k8‰6r%uUI[ur_sq9UT֣p>Ub^*S/.o#s`LxZr9o QXm=VI[u/,t4ƫncC_CTg&{Gd'#Ƴk O4laD/bXRYFҰC &{0k_\Jx$ Fl,b1wp]1Mv~f{6w Ĩb_W02E.5 Ԉ5W$[OsZ1 6+#"+s 0'hZ6$_42[c_haᦼ9KU5D jCǽY%5zIb;՛<6EBziGgF-D|qatA_54S$M^flcu~KþeZN>ҋ::n,(w6 @- !v$1قYq[{UyK=ayno=}^ZrL݋;S_:ɘ|-[g|{x|c IN4X1ޯJְCot{U-!7b%{w n"q>'M M^x}z ) . {p5)̒pvILoU11]1m K|~y6c{i :9U)hE+!I@hW=Ȣ#Yj9ZAS\ˆ1*Y~[þS `i&8MFlKT;4b^\ιFMli0OJh7X  a1I:i*jAE*5dBfcXz'{N!]>ːu"Ƣ1Bfi'DQ{{-x8Xj m5)9D9?&Ÿ"Gk0n@p#50a2T8Nd}%oqdU qɒ3!"3[tCGA yB(-us^HBXcpoEH3vg3u$dW$D<~'N ƴ!"H:, ,X6 6dyi :j3q*Z>w]):;eͪsJsWMѨK?טDH/Hծh1qHA4xܑ_U$ 6Aូ R?KTK?nÜ qff'{;8C=W7:ԟElIa+{ߟ].Q9 ?:tDlR}Ҿ;߼_yoM~~FP%j:@̳Ga|kĸ7 H :6 !h *]bdzS=MeI<8`ʛW i2zw M<*Krqi8nha/<^Zþs$Y8qGH)g|^ܪһ"Wu`L2C8knc:/!b8 )On{Ɲ0Åx*p>&oi 'ɨ?X/Џ0%Gi2foχkWv[4|"JEmp^ 8*`VaYҦ1G0 [ Ծs7Oaa_>u*2ɫ ڈ{_Fܙ Y>'9g = XboNM囀7kK]!#~Ck"H&}" i+La*#FӄX)ujP\ FZ U8U4S_0c(+.¸q5}WXÖ0nl>x}}5sU.d8P'%4}gD¸pq[#c`|ǒ8qG A]Ym y#ejױe,f-M"q#H!q8s؆t #9K3%QK s6 {4p} &bGGƖƣl'[Yq@5w/Iq蒆6c#57Ht@:{l?OaT)Od=čWPKr#oiBE}d_GV^$oWHw ?G`V`L%n/ 5l6WJ/<^Zþgm֔JyP0#U! Zs^")0wGUgaN8!*]tw}IM2 b%$Oɉfw(D3V7F 8 X(ߜU=8GA+ؗ'28o:(Nd[`geQUů`bSF̶k0 b!eje /HְCwx|bM4U)%CswF |d#{`LzC݄4D!Xګ bF,/a_P_[[Ј Lt77H6)Oyo sYz% K6k9>Z oqk A=ȼo%fݏ"uc~?:./~'o.56o[:Ũ<x,9 ߒDI:܆ $GG J{]l hI#˷4| Oz#oiס#ߋ-3e336I!sC._E0 c; ^UAbP YYl Nx}}.YV*%mP*L^8هD+$g' ퟟ%8:ϬE='tNw3Je<>؀}EJL}\L%؏H5$ ̠$:gn6I/rL :|Yc V -v}coFuqX5<J cƾ5cf'/XV'RcI^3Y 7 ]uE‚p9m^xD- :us7=|_۩Xr^1ө^)H{2b2݀'e v#5+0+{>S h6 -_kvۂf57坧oksJ`NHNҦN#sDƆ6 yFބa/a_G,!|Ev8yZ,o\ܝHdz5┒D-Ac5p.vgma*f-@(tLjLWB-Wut\ cLM,=-+=$wU]D#)jJdL!lmNpKc71``_sbn"VOS  ơ EhڊSׂ:!dZ oɚ͆]Ӽ??h,VrywHz/FYDk㈁hѾ'j(4$ڤa> #54:^.P*+>j[8RsoN~GwyoXT OQ6d8%Iև*JI4v%Hƈ!qSHڱhm ְÍbf%#ؔS :.UdtQ%e_ t1qlJgQM~^Kþ yz6>}4zK?#NpfZhŹi^i)Q58I6VuTk]޾xYY )艋药zzM< Ѫ6c{ a\<ֺ!迟D(gvS4Xo64zyw$GxY. sDdU i#fXa mz[^x֡:wԩE7>LsoC;"t`Lz^Crqigyu8dT.Ws$Fdű4q ~UɈw=JJ>{l6؆>J?3ę]ly5 0oǦ98 ZRMByFPKIҝ~IE56c)|YNUPd:A7PJ+h~JF}:1۹iHLԕK8va/uȫUcktEЕrB@X9A2#uI ²$r`$6־dm :jfjԺK/4^d̮ov2U&HI W ƟFk+W3,9X&xEd'UQ!o&`>5@xOƗ+vRXsnz.goגC{Y&TS%hz3jQ%Fa#Gg`L!fҀdbc/{i :Ꞃ5INFL%iuJp10߃N$ 160Ch~!q*myu! ʙdG4Sd߈rc,5IY!Jְqp|yK6 Ɖ6e;(J( 7!.gCnpi'ĥ{ w3Z=XiCxgtˍH8kc4{kr g5}j \h\(O|~u+-XG?ԹكY%& ^֫JF+oilt, fi#5q㍫ub)4h}ij=!Ѻ#k H1ZV8ҋaa_GmnM >[F,yyt=LHM|w@c`LKHv͆-쨢u(N{o9U"6!y_Bv gL6'BL,p0P Ȅ5l!9걞Ff6ȥ;U$,lvf d~#eN =(&f#,sux!q#..fXq6?? ְޮj ףG2)с0H& l:GbPZCb/ SCR6cu /ɖYCHz'P\lg&ĞM!1m)IS"5S1mcG%/<^J? d|Xߖi3}oh%,HdQp??>ݘ>?KTua!<"]Q[1P*"S7.[pwGK"BZ +a:z`Fc4Xi< %@ :0*\0 _fxDT ƴ.I"WA Ү^%KkQ'n|ک;'Σ'l[Kx"P@<\gadqy6>?Ecڄt U}ݹE*BIIR0 HB5"BU1m|~Ug6mVI[u8]xm'Z~x-^qȕ֟b,-G̾k $yЄ<5DtmC{JְOLc2OH/sjSĎjV멒k3;:%7}R b ְCV#-ԫV\6:_>lcIǯ/,$T ʱq*0&CIITqLa`_X("9F|pgkIH >wgf&{.Gk0~.6rVm~a/a_GFz|%5FPx?'ݹAܱWg`Eiok]1m@ a a/<^ZþAPJy6Rr+o|#GVՐx*IH:IK b\UR}:OZiQ0BG! ⴂ6OƮgB"p~\ AMZ/9q).> fnFAM0lf|mאlXl 'ulVdE5UW g$7~\aRt &%cTUϮRb̗;k C1m ְݔ`"au͟Ǧٲ힧o!UY:q0ؑ}K07%2-R @4IF4. >$%E\F 7H:6&Vף<؜_SI:=\/{*FrCdK1m`OEIԠr!=Q%ejQXZۜWkh)z+^qh9'rK:S2P57a魨LskgQ?GHPc}ߩ6) rybLn V]FqP5ӆIVc:2!cU]}~VQ;{-gI3gAh| u/ JT ƴ\qɷw7AGI)W+mx.*\#r%h`S$@l%0D\2 2LAAԵ mU @ubiȪzPg~" ABc؎E+R_ @.H1^FޟM?!boOwy@# ~AC^Gzd:%@tVf)U0m0mga_:M5[ȒX GXz9]q9^Zþ N;j,9L}1'3/#^QrஒqI|ݖwı~ ױ5$-U!Y6N!N_gt+wbD [|k0 ̐d F == bGKkQnY'o.IL8yEfqMd=1vO . ^wk0LҖ- eca/a_уﵯ0#CZȊ|9QyDU @JH[4GKkQ[=h|:/([]<Ԝn⽁`f!FQ]%(S4b$ za FQЈRY :j&*JKy^SiO)@[%ʪ iAeWnc&W^Kþ Zot>AF 6wxgK-d`X5$ m"]`←bCX*#5+毳ĦvqIIOċU|aF zdD6b%GKCo b] ְ_h&*eË'mEr/(&4l,Sm{{ꜻbJ;:X8YUjçB#Kig 3e1gq%_1fr"%2.R YBnyܦ;;,眜}V\<9N{nqPmrAɫXY,RҌO^Qayo Q]~AzۮvC]"R )HGUO"#F5%Q9ij1]G,/a_GCP1@#lDR~{_b"JZ';S7+ |gMc^x9jcI+Rv8=U} ` zJr8*k, !CM)5.$o5$6EJ204Ezu35T#GI$Wqv<"ԋ?dοUA.%94}qvې``_EM6˼sS{% Cb8lbl5$n*OIC6jX!xu"^}&+I-y{YI2(/w ƴwcA3GKkס.U ~гT77#.0N^*('Mxm4 Xt'~O7u1т >*XW%8.!LuS: +Hč%m) be2.j-(제x1rFLdܒV.KA1dV_]%j6 ƴtWI&;/ m ^x}ZY|RAM>@K(&L˥q/؆#|1 1\ǵ˾?wy8/D&%>}VAK0,Tf!o0Zqѐ6>?E6nb#Cgx5u B& ԃ ' {M8UMqW %9o!8 #5{+Owߵn0eɉz31N'{Ҥe `<`)M޻T%ْV %,:n]qD,EIl+<⪧8[=Vni$b*Y.b`~X9$`DRiz)槊IE=kAY$۲XA&~aa_] âPBa|Iexb33`xi#g`La sxSCgo V_a_dx!_XdKD}nRu r ;6>/ɍ 1RԎ |C,$Sw7@ "YZStEQIL[(7OHIRd JT)#UB&.?]ůRwUۖ]5%ko/@хj9Ǯ6P'ɘxm6uo_$KkQ|kwwm u8 _d0y LluYBz+#w`La IRww-4Wm2%vE4;k(9y)Laf>2f*I&ߥF3a/u(܄Y3C:?/wrW6ΝrI=½;!!4՗v`A-Q%Kkױb:~?82d^" ~bvGM1mɍzw: ְk-Nm#N@X{mD+B#-1F /g`L%9Qg4$1GKkסGq9)F=#!XW|PqY/N~E!6ߜ-zBEZ]޼/Qbó+iM Et9y֞~V qm 3V\ `X&2Nx}}59]DS5%R@$|v yR_6 pR2xƹ^hDz) C(20:ΛD򌓒[Mθo,|]ӫ c,I{G F{i :tq,G84%{pI"(pP@#4yiXK[Z b|*)~Kþ*N>ѥI س302lO4fًb& Q|f4oةFP6]ꣃ^?I jx# 8L5JT i3,a^jcA'{ojg>w/\wTlayЏ6:{FR4> .c(4{mV$GKkQ́< d0^TYcWXKrueSv U|}|n ]HgȽOxd^BPDtQNe' >h&D^L{s}*"ʉp4&/*>HЬ8Dc2|v]~/ɉ _b*Y>J?0g52`XfNqO#:uF2%x8 аcAQGPRXuN_cc=`23&&Ax~6}9Y??{e͍HR Yq=|abaDD"W $dSДl< [Hi0>Ir# Pm^yu{f n$[OKz5OѴ4.0(l7&~j10GKkዹxܒ2Gq PJYhD E_cK*"q]l !Ck˽jCX".#50sqV\^7Y$@8Nv@ЭGo(i4X$}in8f ְ# MFq3[a<+fˈ9w ƴ$l24ԲAmY%Kkס/QSu-<3U[؟"5)"ucFq)˙.mq]1mČÅ5!kz#oiסD:!zkdKBr>X<乪Qײ4r0a#5WgM2u5q:l6vL$k0@X&d чa`_ijP߿fɡ~]ފ?]]4R6oK ְI@UhQ.;kϒ{]=ޣbA<ӈ P5$ϒD,tJCvğGKkױf[Gt_%ѩ8w]lZyՊ0 e<=2%ͪRCw=Z HUL1tȩK-@^!:QMTX!f;;2^&\9SA?v ma`_H:kⓩD7f'i&*GΙögK0(HLƓ$hކ91nGG+WQ*+<qxT,Dm׈iK<jX5E֡k|<,E6򛪃l͂[_ ɭ>s#V7b6q /<^Zþ*&vv%،؟G:@D\,lNj`6qȢgS7É]\q^G,$AD7 <\K_)G׮6t+ 96U}~3w#t[t)EVH0W8l 7R]8KCwgK; Ugv,'e@ ɺS q'|vm Uq{=΢@?K!2 bGKkס?x%m/y)(`6 <@S'o?*Џj^ qMN,ew{=uz^lD 9l|YAجYsT 7 ƷRr36.9^J?ЃqEqTM(Tls##b_>;'_TI2,r2,{s3vLѫ8!H'l|lFVq'F;ؠU ]uK%5n[~>T鉡_j'bDMyn1Pv6RN}45Ǚ_ף%UIMl`$M qb^1N"GokQ;q9M~M*KH|n2ݵV "w~F:-H[[PKP{hĴb1gS㑮JN&ط8y&H$FYqDh0 \qJrPj g4/6QC/r}EKS 't I:dqFv}q},eYe=P+,X^yQD& 5R@~3J @h&v`^{mhv ncx:/c /5l iX]iҋ[r0:LרW3{FBYx Gv\#kz}Uº.5싨I#Ǟ4SuKGQwuTBC璸w)%.hfؘ5s;xW¬kl)`OAy9Q,z_9A~!`Lp'4 #5p!'q Kt|He8v<d Pȹhq]1m|~DMaFah^J?7{8".Y NLfgި1slGdE4dI;Y}j蔆mId/<^ZþҶS7o& Z$z1pt}hǽiHlZ% s̤a5mLS9^J?{an|H<:^uMI9e9μ+FDC9mcP%"(6C9"}:dxnBeJ5I$ $Qt&X6 ƴ($[ ,/<^Zþה TH=9Xd { jE'KT$4w]Ɂ+pm^xD- :Ot9R4ZridzIUt ԶiH\"a5Lf륍|"G:T0#ȭ=4"7RL`\"EFb2FonJ`LɅn&KüwSmʖa/u+ %㋏B5$F$ Y#aH˄~4JCϫ a~DH`_X80sT}d&Yct4wEciL¢5bc@Q1Ą" mp]ְCŃM?r4STS /f kd>+j\?X$(4[d`ij W1^x}O %x,7{083\B/\7 f<9bV3;䉛^9d hZLV 2Q˻tᡲ%@YJFz*jOj.eo~_DGHrM4D,j!\#{`L!IRPkP︴AQ%Kkױnf=)x[oǗL捊dJEXZE2$e`LH@!ιq̰a/a_8ów0˸r %n& C;K)a *g`l|&B HNAy%a ҮLOąjV=c= ~~|wyQ[=;+|3 jƋn^v/{5#l4qÑ#s`|٬%BSCд!3J԰ÑUJFg+ؼ3_1%J7lEr{S}PSFDjH \7y6f&, ְ43bsf@v}ZS߇'ßߟć 7G'yn4{^I!O^Д40 |h]ln ~pnǝ @y *7幎ijۊzYE-ܼ*V"9UCb$„LϤUm+W$5xmwSL6pӉh8ExիMCb I:8KCܭWĺ}H/u:6Ԓ0M|_#o0Y.Ux 㴠rymmfo׾%o Al OCDTϼ<`R-r\ R=SАl )*=@y}= wۓ1K&%/"C7_H@2d SjH xIVԮߥ!>1BGKkס'Unzx_䷒L4/{cg3iQ|(G?Gb0nڊqK1wǴ {4Я7y\̺S%A#IN6-܇M蔌N~8kn8f ְ!DUN8Gr3DуͰ0'<@,&0A=P*hm\V>x}}!#zZM*ALHjZ.Lռ+Ft_6G6b%KԦd^x}y[ſD*B>MGE]&׆ʺ0m c<d[ ,<@yMvKYy_YdL$Ȟb .y9BYAX6JA'4Olaa_^DOkEƁ?N[@¢P Ϩ3 O $"GkӐ:ti8ơF:t  ͖gtU+/% t3ЏV91/- b6_ڸ^m :~ WdH#/@YaߓQ OddT/'<~~O7kq_rCDSq<8Ns`~"G+2U?8x\SN|66Aɟh*omLNnb#2{o*o*ޣȭL$7Y.( C`=bm 8m J:)엄< N%Gjg|Yo V~?8~xi_xm_L.W\#>WOfK/|ٻZ$716DxD)yIL:+Fx*A#"\5,T򀤆(z6&~dy) CtBmcVQv`D"7 ȇX$m es\ crk)||qbVqVJ6~ (d|_dgEزJ{sӐAJ.9m\1H/<^J?4WrUD8LI dAgym薠Qi?<%]L{UFmC6h}2dͰUPh/R@  >h!1m`%- ߓfXD^ERQ[d1s;+e&d>d"??/ SⵇwkZ02ѝhHLHoB baz,/uQ'rF b ^|Pa`9S M( ?^A?n'}n<}E={CE jm_Wt^Ď駤wkZy66GKkE[ϥnȜx k7~+CY׀OH* wq a`_3@{7 #乜0ъbdOD^>m.HD fV]P)a>лy_o'~1bӾ+ZF=Ư:1Xӆj!3ji8dyi :j !z5-AS(tllWaCآ!'ϹOF y\ VQ56:%uT$h)H%9N^&JmcQˉ``_~Y]7k#DJO 9)6gYѐ6|D\p=m\^[u{Φ%L^;UvH\m;{8ӈ:kHL!ɡ{͆p]yRYGmnE``+{$\<-̤E҃OjHL! ɗUTN/<^J?x6_"NΏRřPJ7ίvݺ&Ոe#fX"GokQIoH>߁v=.kbyl ^?F6>?Kґ44nЈRYfs#5K2|-o/F01'l{qlzU5D9"} 3=_l5"}dؒxPfm|ϊq5fHr#4nϻJְccA''b)JlSkD/&3Q];EoI` 3 R`<>Z9l=u2( #m%7ҏ/)Ǯ6hKġ} ^xD- :uϥ$!>O!v蝴$S_6UQ#x #p]Abb8E 'iA-o,`_E:i+at5Xavl;ˈ~i3$4sAYi9^Zþ稾r<>Ov(ɾؖ<褈Ie'c-#k0 )9 X6n#oiQI]gr'7}*xnCCmq+,Qet4ϝjjgםd䝧o;5u5 s 0^Z Gj~vcF &(n&2o ,MO$θ&c/I /vވ _3.iul a  j5=E='V7RewZG:x5+~Hm(jkW:67W}/kdq6(]@vVܤEhG;]u.t+7$Mjjrܩ"5QO9@zɒϚ7\P y:1[]%}}m '9` nM8fְ-oM-m|7!nR#O?lpG˚âPo%Xnyzey͊At4ڱdYq_]Nx[ Bڊ=Kk Cq]~)#KCU¸ݢ:}Ģe C,)7Axq_^%Hiӄn`Nڱ ``_mI ]l!++GB}4qHp\?5UqcڈkizA+.y4߹58tȣ?D7Y ?Y͸?qaa7S4O~A3yulf"A6~a[IRň}/Ȱ0fԐ6 )Ŋprٸ~ЈRYG`S{hFAvI"3.S^G |BEaو<(M QRm#^m :doM&J̼AMyْ ٛJǀ~5 ēr q\[T/aXϏgoׂ$&Ny\}GRY⥌ (y|[) >*\JK ƴ!+0Whܗ"ͲUa_ʉՃ n!:q:JGEn#+xD4?$̎_l#O'<>J?3J^QID=Kl i-c{A"П6R/U!-`$m0 bSM#'<>ZþJ@wmZI):{6%Ӈ^` '#U$˥Gw`L!ItC4\n{i :*CƙYQM_+PmPhy1r#4z j`Aӫn!m$AEH~򎢌?lA2 aو<5' Oz#5pڕΐFB6O$A=҈F\q#17JzDcوo=imv )d/U3 뗘#)RqC&N) T*j?Ż+yt(CoI{_jj[0l/+H|(C/%˅Tp]bTJU|}5!Jb; ì%ѦN]FQLRY% /-*,9ԽP Mg@d H`_wBrQo]Hz0A5m,28aĴ*Adp`Siieify4З'>\VKbzOAj J#5_$ʿKA?wx*YNJ wYj{F8 n S2n"xXo"cT SҙnnX^x}.E."\\#EF^,y6{La©g*gIZow̽Lh'4"VũGsh67ɚc8(I#3ʂnxxi3$9/f>Yɾi郳Jְ׷ i|fj$w xCB%qt%DUc"w~M7C :=[!vk', <}^Z_ n0 l8V/ǷxurJ:ʃc I3!^&1#51cڜ,GI< f/x$Hn ^\F}6g'l*IA ADyvyVɊ3l/NZ}I_y߰doc7^1`@ Tm#5먗6.\t*{ǐD_C+VH ,xCZз Ku&-h *EH_} ^WDWDH686M$V*5ۨ?l$}&Ǧ<=y~}(D, pU $y. 9aI #"zP5$NaKp] ȩL4pM'wH:~Kþ[YB͖q˒v٫z 8#M&5⻉4'%/4Dt!3E8a_"쳄s =i`$Q5Nf9G{OfA-*SgeΒ<<[C6cul:jnZɛta_ɉtd"5Y(H%@[Nn4ۢ~O<8M|BD eWJ#`$kD|qlǞiII`. Wm\.K/<^ZþZ߭-·jݑ8ǒ 0#JUgYVuBpD&p>,ȶIAЏ\8r~q8Ҿ?{9}#;hօ_t4IE6> )*U2P ƴL{Ix`v6?? ְx!CAh{4Q-, TD&\wy_lYK2+ {z_q}nH34欒ďn CKA4 ,/<^ZþJ2̩{Igӽ'7VJ:0P8\ 戓٩aa=(%LlkjCo:6VMet(6'꣰$諉m<.'Fs<"J 5SH SC7 a&ְyg|^/Mȗ?ю- }Bp'c3 yhU4 hZ&.\wqeCzޫ$-LKqx5qa1Ʈ6pA&Iǫbin]#56Do&4Ea/~qIP(%̏TI5F̰!ܸ4cAY^x}Z0~)F':Hrc$h0J*Q p=MD)8fPv ĸU|}5fylfG#kܣ jz5=邗hƗ GLOĤ|nw5}2V0_Dal\1EW=6E8li$jU V0{i :q۞k5Ji:/+:!ܱe>خ$sSCgkJn>S%m ,/<^Zþ}rDLO FpdukwZ&HVbBJְINJ<wbH&N%`~|᭒d|Sⷖ5sѝ^x}*r߸ymaTyW77Fg|)LyzfB9ͷ85"}(_܍_ܠokK5خ[@Yak!EyQن)9柍E6p6%ְ/`q8JuJ %G}‹{(2AB8MKrni=AY^hDz) Vwj~HEcLUަd"lغ)ڱL,%E҃ŤjH<%Qbfn`z4݈#A N^)9so>(JAzŨ!gW`L%CQ=BQp[-:eV UmVmZIk!x_|]:R$_| G*5|ܛ bU& ְCEζś ?%q2VAOI\J$i0 qP# '6]C/rD- :bl_:OR_Aۋ1q/,r"{`L!C;p b ְá8}H;]\tZ45rObc9ށϱk0OJ"۩pGׄ!/SþZK)6'V'k+_Ҙo3 FVς:d4,2NА&k+xf s&D"Ls WFUh2Fa~ִDl8b7[-뿑(tOm Hws4q"gJn8ƍ@(G('5$>XL$*\I I6΀a/a_K#b;JLP\S,X83٠`]9.4GgӰpc`hIZXرlLH:J&tc硧 2U>5b#Ron]Y `ئ'>tMq29O Nj˂0ZBְ/x>[/[wv+5\A|0DXEϦ!sl`[Cw6W&G:%yK8gN,o,NG9R/\Q]޼౉~0_L@~n`5ݘ0Ò 1Xln,Q46HPYǃOۃowyEª[)[=Уrd3q]ȗa'`_3Q×NcvRu=0 u=DЏ  .r>{j~Hy^pX]%7ɐڊ?cd+<ª!0$4nOoyRY'6?E}):%6#8d:hZntcwX Gj b|GKkᖛ'c7"H:)oob,yO#L>a IFqU%  b^GKkסs,,V[M.2U/&qM̙q$"^%_d[]Bι Ɲ{i : =[d#s>jbۋvֆxw(HX5fXr ^ic&6쫨4/|p6 jyQv܁ڍHUMCbu[浧Npi3\z#5N^5*ҳ 2daFS-j[O`kHL%;>pJ16J:yOd #T߮H$-n7kd˕2J@oi HVK1aa`_E 60< (eCjtax;3Ǣ8NXjEݤ]1m ^^- fXjB#Kig:g(T`*A߈ hg݉LG 7V ѷEfCZ"GKkJRMΛDς0hUGQ$1%|.MLwFL'4"}VQɟ_ؑy3p_G_b w콛>jd*n m~^J?P 6:KERWJDIyW3حHЋwӐ9˒WQj`YҲAY^x}o _v; u4" GC%@͜7F,nizZASEWr9.t8Q%ch)H|%3~hG XRm'r|L*jY P7?ݣ_$tQ [:[1.Z iTIn0d*Y^J?pS<hR[k2yidFTRQ#CѰL4- Vm~^J?p{e))(=`D-#uehM62o',ş%_OQ*@ZGvP672:2՟_1:=S}ݿ'⫽TCL8{dy{X;M}l4wZ$uw8/_'p˛O .`E,KE`Masle&ЧJְB呵C ^S8I,} DHgk@? 1M U͂0bZ`_ED`H[ˑ}W_ ҽ׈pj0 -i5b%x{Qd-Vl)I BI qFS%5$ j%eihnX3B#KigQfk0 ɯq ,7-=`>TدcNO~霊F " ~(EVpВ4aџ]qw@J". 8]2^x}^pȉ#qj/a1L({b 38#ޯ+S,@Qf*;{{GDa?|p>Ғ+1gaAa;=k4bI?T2 NITV+dx^<'%cICgj زaGҰÉ Z~Qe %"8)n uhotACЖUd퍮Nɂe@d T]PcWa`_NLP7 2r-a 4* 'Prv26'q8Oя]1m K.d / ױ Fr{i :`~ؚHWD/xQeH9wf6 ƴ)a1n*)~Kþ?wlݕ<۩єre_m2A^%oiC#Mf }61C^{i :jWV2üÑaHT6?u`Ɵ8ލo"ojеgȋ#50]lT* YXK9"^c>h]5fXpRj6ĊI[uԨx})W'Pָ݈{R>&HNǹm11s{ٛG9NC_#sP$3#І|"1iT̥1v I@p쪉edyG1J; 2e,8ݖn#o tk3q$}y Y!~Նp̐9B^}opjj D._|wۇx₨pˉۦAJ5" [TKrxigyu9~K 4/P*ߘ%I0zy2WWb$U2^5fHǿ U*'rݖ}enSvA!i읦=4 9O_KfDv@׾)F1]1m`%uRC V1^xD- :jnWIh݇.M 2M+Y%#miXI('B}m6qa/a_GNfTLS6?!"qTRܦ&|TYe c<lNϾ'}.<}Rߍ06)x?7c8#QFϮ60ChUm {u8jqe|k>:¥d4JMN`41EqiHL KB bRYd²Og\HkF2 V_Rna#޹k0 d"ZWpEER}93MJv1)a'62ֈT+d1gI@Ugy4pYDfU![#%)Żm ꊨi-!9}}iX6>?Kߥ x` J:\:88tR%q1䍒ʓAwV'Doh~;6ɾ>{FhRs PY ?#hy%"B ~6]??)p镳ݟO1ٸ>g9 _m}s:qss2֒#(*_/ j``LJ2zi68>U}j ]LB\ٴ$QF/GWqϱF -Ĵ*DH. m~a/a_Giq$*p5v3"C,R~ >'R!B\A¼י9^njnFbzs8+l[hD$Ʀl7 ƴm"%/ Gmk/<"}U-;U#j ^j+~#.\ĢNJ&hNJ<JJ&T|/zq 2Qtdc y{mW~*Qͳ^%@#itz~lg9y^eteq>PD|-۬1qFl]%/ iA H.Vϥy&?? ְb+wpzMb d`r<7#A=bM|>m7<7턟e䝧o;k1F1rX`W$7EN>gT±xTYnĪ.1y4iIFXblhyuTn|}GpJvaO;/{(6 Rr3 5md#5p WΕן8 y!%эfF <eA3pgۮ6p,K]sRl>GKkQ6rRRIRJQlv.ໂP$U.O\cڈ}Sd5YBi8f ְlZwRlAE@%zÞE q٬kiI>`M\a'`_E0#%qNb%W%+ĸ^1x}}N]v)sd[}7/X,#j0 ̐yKC$T-5 $$F]W%/,  :=$vl,ڽ ``_x:7gpWϜ]'thqEE# [ mE{fgU_/[ Fߩ4(K[ņ}uwם3PS$ٹk0 $9٪.5lњ6u^J?ɬre.#%%w/*WQtUI6ݘpbS컍m.X2EtGnQl"G!-GJ^]&2;n~]1n*AΦ!q# 0[, 1.DGKkQbn}3R=G^7LS%xli7L_ƻm ְ5U0P fعE3Srk/~[f5Og4vDNsZӆ0Eְc\%å؅$m^BhqjYߌLr!lrͽ/Vbc/z4PI$;ΫKo zK lt;[^#cאXy!KrF䥠] bdU}ہp fGGc6`Z퓢I&ƨDZM§)Q~jnB#Kig΋5{RW/X uAg;rE'ȣ{g8ePuh<Ӳk'h*2qS% ~숳pH׻nG;qʀߒ|wh( 1>x}}:|6 |h3X KrKM|IDxYI i3,i(J s6_-756< JwEywq  V9χUCbPDRXCh6iP$50fCozʱIJNDAF0FdZK M%9X8m ְÝ0~lHt4ԗc|ia#xγZN76Ē|]ƻ ƝK/?OWb<9 _%9W*+jx]$47ŗVzi8nXSlY4mEɋ:X_H!t,c'8kD$"-' T 6 :$z@4*m\ /<^Zþrp@^F|:Kg,.%_4 wD`y(!FU?c K&PV+̊[uhȔs+Hr}DwI qƏ~_ٜKC[ HE6KCD b\*)~Kþm@dq`nbg*>"mS`u紫b^FǮ!qcwI[] 禍5m1 v]+o]\}5B_WxD*#k0 D,9pՑ [uh&7 J#{caԣ$FŠ́ #?M1m $906Eh+h% Cb T}F49v &ަ$Hae}6U^}:1UWƚeE؇,-)ؙ6*nPs'$FtnW inIt ƹ YNx}}WU{"Aw PŒZ&,i9v [6z$bwinXU #5먛[a"WEr==I| Ei ڗB8%sx9lo :*,Yٝ@ކ_dCC\\eڻSE槪!%B"! _j6x X~S?=u@bq}67(4D )4yi N\(( Q* <}`xHm/W<$F~e80͒w\&Ն0^"GKk舁HN eJN}T1.ˆ[mPg`L\Iroi8qچ{i :*T t?,=Pʒ1z {gS`W!iB#KigCIa;PlIcҒfx VBY2"@jK: 0=IR31.*g`L!IZmK^x}nq)f=*ENG軂v7¨5=$\w vH@I*Nmv#( Ė%X$1ւy;P x A sAIu)xyl c{{nU͖Y?lͷt7DU okD;!1mNNKAj%jmI~Wű #o1ڮ6bFJ6Ҧ$>Ƹ- :jX]XHg;$A$j=½xH9^<<%G4q[Cb,˒5D-HA{) }:gbpEܣɂyh>unQg/8ݟ)lGwgJ<k濛v<1^frKrN(<8ϻcˎUI,7Y/4}qt۰a/a_GI>V0"H58 dI\|~Cn>C#16j4în*MuPz,,<.Zþy ߹wW|]~ވHqlTQJI+{W`L`Ao)~O7 xH`_iSY3d!\C ¨WȒױk0>FBpfCJ԰ 7_z$E/vcrnGb]%xG!a|dHU҃zS`u6[Bw7^`5_1W]~EE²%Z] ?Q&Suڮ6pEݿQ@ l6c25p)h=yz0hI25"Q#X ;\ԱGܩi3$~5j| f{i :6&4>UH70HȴۣVnjL4 eV*n8&HUߗ$Pe12L޷% xE J=[QFDR`o)xu- buK^x}֘;v;Q2IJ"=B8O2$ըqZ\C) Rp9lNxDM*L2޾˜AzJKn(6")=j(heynFHɁBm6#^hYGkd9/'iQrr 梓;ΊE{.O\c,IgF`j}Ak"Y^Zþ=C/"]YD`Һ D=~m %ä9=zBpER=[<:IV{@2 ΝĊ9-ɉno!yuhNvh`+V]9*׬+o}lW޼$RCKUD*I/Sþz/M[hrtqi)ynЭ*?p#Jz=U 7$*bWD l#.NQ Y. 1h;u.I( f7{ %Vy૵i0 m)A+(B+o V9[u}%C$Oġ.MeRd4\E ,/<^Zþڂto'r%xLٳGANuDžq̕FudG ڥİ)IPw)P} ,'U&VrQ {h`L/ 5U/6bćFKkQc8REnloy5߇dO(}mAۡ#r⏃ߪLj%M_wMsQj')MMݼ.)^ Mn5{ޠXqM6Y< r2X] d…_ibqVaD*݉~)QjJ#JFD!l1=Aw_Jf۽hKݸ_N||g"w*foo8G]0y̓BVdi@XGDGnxƮ6TҀfKņE}5vHsɱ'AWCyH,|/eyOqKC86n +6n<>Z 판:nӾƋނ"K/츘t/~+^R1mF`jKC?vĪ<(5IQDOT'Ih]?D[xǮ6j/ImA^x}Z)OVDNJ9fxGD^%_i3$tWc ]6/<^ZþfcGTCdsF4<-(&\& d\6<b izB y}ZA ݧ38-uc%/ ab$GǮ!qS)"[Fl5JϺjORhvW$dkß}O¿DDvU_$4neI\@ Tl1ja_G- olr0u’f&{jmt?ZП5b(` i#v |iͲGKkQ#f/KJ`7#t`'瀫 iY,"-#EG>x}}NmM2i9 -lA+KJSmn=jiz;_7G(4fHĸA wŸ"GKk{oB KSfJ3ͅ* #.e@enr}u'nDX%>.`sdO&4^[A¦bJ>%MLaa__$.Fȇ))yOҙ20?hVnГֈwاD>vs ְC_.~ʔD56/9 Y%xl{7?%݉4~ H^x}R;Q}y>p\~uW8Q}ߏ#|R&Xr(F 1r#iiUgfzAŁUGww! M-S\ k*gVp޻mVB!]1ɽhd ΠPd4Q SQ:,b>ølC=,/ kvrO͓7]%=~++qv["-x\ -G1XwՆ0]"G԰>X<.fP){3ĒJsFh4mLQcGUM.)˚ F{i :e4\@VYSu+m#yQo[s#ivՐ6pJkn{) Cj9FS|\kFz5E¸zX5$nӲDiSCSmJfyuT(6Sqp7?-y&#䲸dtwpWJ5?JS\zvğGKk T'QضOX5ZJ3JF7f/f^!) h*mC :gwRr-ܩdH%nb *d`L$Ԗwۄt U+Og_čaZ[:!=f Q%=h6 ƴ8$ZHl~a/a_i9eSeY\) YFڨ`h7-8'dDyӐ82,y!lc8ְVʰ>;ٳk$yȿݳގ }Y%3@5ٵʒ] 1^x}z@#eeGyR LD\ǾF"fq 5B`LZI ~*WՄ0o,'`_EezIʂ\'NR22?UN0* Z8W i3,NoiK H^hY}=q><$waI G#K4"J JĉQ$ kX α8M Ha_ޯ6:iq heKD+Dv8 '(S] %0GP5 l4zWBPࡌuf_|5ފ1o3G8i[CJ !+ bD[,/a_i %4RILn$/BqĎUgڈ+8r ,ꪆՒ)m|͆G^FKkg_ P`ѡ@$-Rp@D ll;kc,׈5fX. !lՆ0J:jŁ\GD-s뷛wu7 {(=GVei0ϒC7Dbz5!Y%I)WE.҆'xo"!PB (~L?vՀ5HP)PԷfϹ' ,7Ex!a!4n{jh;#W7EKaa5;%lh A^m%$^XṯWMGt,N$NE-,uǝq0 .a%K Õ]eU+LuJcWɉaa_E%$eI"/"Dd2%ɒ!6z*1<Is8w =SS-9H m#A騒5p=p/yMDz"s@Cγ?lF-c K/ j86??EHa_{6\$Z1fTʍ7) 2➻cR. Hְc 42p+v%XG[cu~q=P܉UAX60Cg) l6cu,s™|X~욹$RMbT3С#&bK1m|~%KC b1I[u$AWI{tTF$\4^B=eql#EMC2(kq${i :tS~6B~ ʯإqF29_}M#yMOܦbvRzpwkNv2")G΅P H^<Χi#Nrcw!#,1-OWDJ0N77t{İawJ^q -o{~G1]Cf~K.628W1Nx}2G3 rJM.0F쿂ߦ_L,FIϟs?۾>O5}֦2#]H>G<ƊI:N.榡 TС\X)G+#[b`Lx+Kwi`ϲAJְc{^9SAvʖKz/P ƈ{QfV4,kihsaGTsne:/HxKU EP}}q4GWgszk0 ̀WhH ߇[mgV\ulV00w20%s#v0GŢ8F`LJ;bD*)NW`l1rx2tEfX+oJƫ+1.(]#k06 ome}&L}V0 ./+x[VCFb(x_|l& A׈gӍGf '. 6fOn^>nXD,x> o N#!-lC,(}u`SDVn;)Qw2@y/LlaVDBjĢF0o?T^s[+]}-TnynZ]OG6pe gv$'|@ǀ+E\KrHFToH^Abp{Lj2Fxbwx|U*-^=W6G#+V@^5$>[I{kjC^{i :*!Lq=_쫃@M[#pe yvlr)[YQW~~Ҽ?歚y_:,xCOZ'؈Llz8,~{#qofH2^aXl blf,/uꗡ,8Yb~Ǒ$֪2ח#][%H`LJץpgy4먿Zl>Huy8U oO5L-ÎW5$njfI"w'*6:$L :`d)-45b o\V坼EWQϺ2@RAγ)9x,QG^-0d(^Z>dז)8a@Ghlm>QkOB+"q*;E, &$.ߥl~a/a_" W =*$7bXYPy>Џ4T t%GlQwz/fo[+f`N6Qk|E8d$W3jQ&f ۄ5"kUq%kJNV06QB'<>ZZF5!Z<? A0Wqn:Ad?5Dr!, {<^J?qu^z4)EK^GA(pnEMr} 7Q> N ߃f: Ux\RNĐKDpeߨ0us&F:T{!1m J aCыa/uEF)>F+ֵ!bf(tE4gIn- Jܖ b]Oa/a_Gm "4}C<=%ǔ>I)ؽMvBuUIc,ZI //<^Zþ ٌx}OHϟ>$u#ΧAO7>HXF/ u <2y|ľ|?oJe}ДlFs!U͂enC=Rr(UwK0XG,aw)&Uvhc2%9D^PYέ$x~m1~ E=!ni^{`"dW?uswEս$8A?l%\$Hn4$>Qߥe㜶a/<^ZþJ wpF2"ylP6̈5껂M7)}O̐Pc}h*j\H="_ᔼ|6vB=gZUx4$~N 6_6.? H/uT`vyuDYxϦs4.-sp+?.:=qc8oaϏ0۾>{(UR|قVn#4p>ǁWk@\ _EALKr2 [ ʬ?+O]_n #X轧JK ƏK`j9"}JAr }]MMӋ/[K\nְ)Q1 5fXO' .7 bl.*)~KþmفSj`Kҵ[߭u3D+[;kHLAI?=A <^mljI^yi HfA jeɍa2l$UvmfH2_4y6UዂFB=|)ZTLL h!7ӷن Yq]DZKyo8*?)BƸ) fHB7!8`%f.H.o=M;!d쮦o׊,oD/ϓ6*(8F,q^n~eC7|^Mwz#5Tں~i'";Q'B7Sn&FtfVIǙ 1M :# Ɩ0MV >x]ְ^ڊ#"V4QrUS쉝oAlLWr ~wqBTT鱬z⫎#*S]MDﱊ)c\2.ábDO׹S JMRπ+1@L4>8Э]މUc/->GD RՐ60C8IwՆLdz) ֡ȸO3#=$y׭ 磷4[ *} ޷Q^O~r턨ywx,g0 J 5LjR8-Ze2RCMϠ-!oUĮ|%5]GU^@4B)Er"1I7~b0[*=* i? UOw1A9UVl6ZDŽI·%ٹ݉~H:7Vx\h0gJ!6i؞؆{i :}~9Ѧ>Gܩ cɹ~D 9dbƤ8[a%H|H  R#g'zß[#EJNwo?_'Ц0[[Z5fH2!bjj8f ְCcfRWI 5%&oGكԎĈpUJECM-jSKx a/<^Zú~˦ *&f~HN^ƱSpq"@S5hrJdSh bl+GKkXסp9ҝz#Q ;RA$].6y+[<6JrȨsO 8=}?xO H9]B;vo4u@J q_՞}*:-iCOrȐwalQF˩a]B#.&"r4d$y;X;} /+txUhK.^[CĎ aPЋ!/Súgr˼h|,m3WkHvjM"@R1kڻLɆ԰.GKkXQcȫV=Q?Syƒ8b" !Ho&o 1VJ"h0>T8%A~6n#5Ǡ2Ie0$ɽ!:Z^:UɋU1m`$z=1GKkX  {%2cAvwR `7k!1m|?S! G[m? g`Hp~^/Ouf/`xdDOՐ6`Ic_mm ְC pQa Ȓ]6Ggbp8R׈(F<,9snj8N`E2u4ȲM31UBAd6wO0], ˬl'I\U4DM!Wvt%S ;?ol#ŢH8. i7" ~jhcA^K 3>asp")@+Pɥ/IkVU'59"US´@iP;Fge3σ`ƏKY$/z`w⯒2blcpBc !2 gzuqgLG,TE>Eog)3 e[ŸUtvU-)pb&qWtR U, Dn7cfۉdqnɻGv :@vwiN0rXRpyJ<٬Y2NE2uJ=I:fO?ZCNY|Ia#Had7 *٠6i]9O/ޘ\69~3`t(@G106fG~ej0 ,UM ۾ bGKkXQ7ͤ8qR?cvJNdQ|\b+ƨ/i,԰? bt ְ#_}Ͼ]-s/?S>?l?epV#-'w 1(%g?Ik3GYRFMӠ%uTW9ʒ:juu^l?/Զ??۱zI0$Hϊ«Gf/Ao35m/qFո72[`Rr6RPǠ.<ȒeΦ+e$˨F C%2*isT-^Gt޿qs_(G;_+}!x3϶:a TTGs-"L|O~ $rTQ!X`G 71uHύht~+i6" <'q‰X'紐HeDcڈ)0q̰1?P=R P,S$(uq3Hw],cdo0 Y.a&m ˤ9^Zú7UgiA{G6 pc՝#;5F̰nsj A3GKkX$;sT"9;]9Z$GG@l0lÑ,+g R{ fN߃'2/ n*n}#0"Q$ODp[Σпsk~SJ_ejHX/ -1C"Wm yC \>-[8\OɎvD=^Q"י;Bdgqcڈ>50|7m {uTFRc{NIPþ3-~Qadz!OHA=Y5o[$|K Ԧ}kӋ~Kú]Ѐ))cf͈;Bl]%-n= ƴ3,35ljCyuԟIXmPMdICP [bG?c Jθ?!& aޯ*I/SúGG%=Yx&;-ΜLw{ts͏N) xYS9!Tgo^ǺR=d=>6I,-p ѯUm|?S,540jGL:EHuQ EM&[=ajbl*JCbwR$Ωa gzRCG}#pT z7 RcG|CЉeqUCd)pp6,6ߪdzi :/how;o$߃QǓԯkcF:yD.e#fXg/6#oid%_o;"wJN{$GVP;ہ]/ ~"іj0>DG5%ɩaa/<^Zú)Mzt=Z@ oxxG@-]q|vt#F_5ӆ6 85_q̰~KúLw1g#ߢqvx&?} y\͖T-!/gcNm쮦//Ieebs?.J R;Pt=^tic/{}<9{BRNAC]ۜ06휦ޛ{n&)tw!)adȢ`QsMl#ɧHz$ S$k,6u /rD Vs;UȐZmð$HFw0J>x_h*̽tezsSJR 4U{C{?+ߖ5;+ =գ@"-FE|h0!IM Fw"G԰CBlOWoIo4@o<jy6$aSgA7{i :L;["A4% =>Qyёlj<_UAJX4$x$ ?a{bC8lȋ~Kúz2%#Z?7c+K\b I qU2u~v~Oo[$ e"#>hVd׈X5PbgОWH԰Fg1t\$ }2^VTU:GD_ՐxfJxx6ԅa/a]ɐIƯ:4 {\K=FJvj0 ̐dgMjjC!z#5먜.dOfG3w[$كF`Gϟ11?w0Y$!I|qdՆ0pYɱq*Zq7𢢰ڼHPEZ6 ?lUq0qc%cUj]a!MRM$YMwiߛ)bd)R 0` 7{԰CBz75Y2y!J]t w{4y5яq!vVI|!1mBL6إw ƅ{i :&oo4[ʔﶇG>^Qqxw]_iľi#fNkeՆ0*)~Kú; i,ǿ[Tג9}=RQs e$ gXƿ} ULA ܻn%KOI?x w8x3FwDUq|JI\m_-l-H`]_ߊEbGauJ"[91x*ց-)rDW ƴ%MixO blhZa]w)Ž@d@eɷHn>6# gX$<G0ƿՔ' 5Xl y#5Уd5ܦC4=qeQ&"4Z J=S(ώxj.KC6[>u 'rIG̷G6,+W0Bf{xu]8%SC95sAyupW{  C; :FPFp?|AWB~N&rt ?_~Mrv̬"a^BV{VFHR[5`gqc,M 6c[uuCbpF*A<ň~DgO[5$aɁa\ a/<^Zúcv jL*~(kfY2U5GcՐxs^%y5̳ՆpIuTf.pB2ؕg `zAuu c ^"#`w5}^'f<~[EaH}g>1ƭJl]ӄߐN;5j: UTI8/ hyx;,AWe~k؃խ3XM4'LňMyqOqQAAگ"pyw+й  cPxrN Zm 9 U^~{/nZPDw˂/d`84`<^/|tCp =; E;a\{ؼ;M_WP%OK"!Sxi eǝ23jr6DO|Q% _43%c(Cɴ ?{i :bmw[|FG&31tYW7:0pW^0Ʒ*Ϣ60c5lqIWl y#ejXQIg| G@ήpJ k@(awFmR~&UCbS>ۦhSXm URC?\RaZ=kHVm ~Oa#{xlUrE1ma.vvFbՆ0"GKkXaںq P%φQ},ƾHj )$45w[l#NA/ruzf oe==t؂ޠ$6\pB<}npotˑb laN?ۢt{  w;%w\ycQQlaGx* 柭% ѩ! b\ VU(KhCS~i e;p(-ػ"E9@qMt4JtNO>K#2"xI}vEFo]4U1$z=ku}ĒxMU;1NPz*2`GF'DQKGDGodXG60tOL 1Vm y#oiXQ7uN#Q.^KIHD lN#FlsTIߜg ƴ$iSCW1^xuΣGViz4y2Z8ja5 ?"GokXaG{PIIQE`fʓ8m;k:<`wGi, xvVat#Kk?7G ;,y$ 3g(GpCG9<;D<Ӵ/ͮ>;%6uLcnM k' ~m'2HX5"JD35j8f ְÅ E4kH}N;w<^}Tāo{O_Xe>邦PlƦvN`w5}ޑ=.DlJix)AQr20.QQ5$n.Ƴ$c' 1C^{i :uB(r2|7 'M.UBQq|:;(R2^H 6GKkXQk%vD"GּZrԦ6fkg`|РtiJ6Ku䅄64VnehHSJƱ<a/a]G}|W=@$ F UA{W$(^B=_; 8A=ʈ{+l*6NIJU*`.?<R=ͧdɍN-D#]dtq"9eS1m0$klHp~#5# /%Y|% ާ/5Uct2VY I9ا҃#2O &~V3v=ܗL> 2o@Ghƶ&}~:]c{#ZbEjN8&`W 恦bH9_$e$l`;eX;6}U&dC էX0F[h*\ToD&HlQ6u7΅𱑒#ZU )(5Dw!_sy#5Y_HaeHN~ْ[%E.Fb<*pjH}6V-#oiXQ¼b-ɾ.^ دq灻9hc5XHְo ju(u{̢@y*-;@Gsa[~FA2]Ml/ `z"WGb.7Ҹ8IuCˀZ$J$H?erBa`]cY\J=o"hus ` bׇ)'Ǧ(~zo9}]{$e` |χnRf(:H-(Mە81Gj0aIlP # 86va/a]3VԵe|%6d=>P=%#F͌^xU1mČ0cA Gy4Л v$ҳ?lylf7댏 Y>={x6.sl*X*Ug9MsJP@H'5HظZ~#2GN~|k#"j0 D-i"Em6aB#g.}~2]qte+l∛"]#E} X}((l13{Q\EN[o"ĉHI#r/х(ĸ9|`|lSVGKkXױ\L yV6%7kZ &2Ȯ?߫_>zXAMw)Q5teنp̠9>Z'CYsa\lcI"EKէww㋉sg(0 ,UV{-]^KUp:;;wdg!8o qvRwqg`_4wMSҘΟZ[m4a/a]G!jqF^IK^'GZK i``)'5Yl#^{i :+vs0sUXHZOǎ_)>Gk0T-sSmQ mZ-O/^WjƍMAWdѸnk])ّ}>"܇E'~/#j0 $K5دdq'x1GKkX禠Dl􎍢gT]R&ˀH! /,NFJ)8jtb$KCmRrv6 3yoUң֢60Cq0gA3GKkXס? %QGLjr AC\G0[%1p鉡)8AW~?Ӽ>Ow9{ޏ$of^M~w,ur =eZ0%T}σNO1~\sq,ĸ`K>ܼ㰥|0tib[Ց#m ,xJȣ4D"B!U%okXQ=; [%S؛H/\h]0 wYhH&%cyNij^xu S.S{ʹ>E1!8ڜXm`RtjHLyd1tj\AJguR)RpX-*@oB?2;ahW4mF/p>U=bS0f(uwnw:LCMɃ'GQH1A,~n<^:m{.̔ !&sNw/FUk)'jp#_U;j| v7f-WbiЋd\h`e`-ъj0 ̐$ZZ^?S a/<^ZúqIڦެ{,݅A?C?W; N ƴ /SÎi; [u8K9y뽽&")" 5-M4U]L[4$nzd ꃴAdyuT[R'xųk);?-ʁ&qyD?W MS]|e6Z!/4b:j;<6oՎJ Kذ߽Z輇+Կs†ECb~C`jx` gzR/W0L}Tc9\1%^ b}\3ﯵ2jNHI\L]Nxu5⸱ȈP$R򺁫$c[#{ ,ODOjjCI/rD- :ic m%A4w (Q_v@ oT c' 7g~2;0|:-T]m^9M_}VdGNɃLNܜTJEsDK%5\LM FC^hDz) ֱԩ1e-rXak0|%R 2|sDW ƲLɻ5G!9~Kßuh|{q >$&'Fw#( POϯ;5xs:yz5GOdeU$GH2vDB^$y*79@&p#IGs*jV%G+XWQnwQLrq䠊g%uaOq8nfCWPUCbڈQJ)歡FEiz40"C.n6%vKU;σ{`3#s ,ϔ 6QWu,Ƽ;V˽)9vD^$2VZ.xna~a5m7۰^Jßuowh? /KNGmlwyw"׵9ݰlĂF-'or׀tO,@c=(\JO n@vȊ~p2" M`< beUZMGGt2%yw8"ZX`G&5LI. wP+6"G԰CFNXuF㞂/Sr@#rF?v#(H)8+8鲚t#5X(SNcɨG^o` ֮`mp3k0 }P ijX"^JßuTsfi3nTKOEd@;WɋEH&Kv4 :N1Nx}uzPdv201R DG7/v)C:Y_$=UnzFSv667L/<^Zú9OԮ(FN0H"F[$noSC wF}QЮ#F۶hHlJ)ih{25a0a#5PX\]H_U~M?q(U%߶I#` +&V)9V;5 ն6 g[lk4QcM c t:I_w8UC|J]4԰m?EְCO,\>>'Ӽo#)yA}?*,ԈHY* c)i` j6$)Ѐ5YNkt<>fCŔ&ړAJh0n&NI#4ljc3wzuģ:y_t~ؤ$<9A:n${#n)5fXWԠ$i-,<.ZúmIq|*#cU1GpA4YGGk`La RC T QI[u82T=ʿEރ OJ-tUq̰~KúCx:7q?DMq3qǃws{J n!}_P)A\M ;Uh%aʿ.KxK=⋸_S[gHu)ߋo{[[o'|n*&1^Sxd&%G6<=jU93.\cra I#柹ņְ楓OEӥb$ Z^ăJE҃o*0Vp bĩĀz瑅PoE)yUwvPΤ]m@˺ hp[kmxM9=DGAkXPO t&f9%'_h'x {>Gת0ZJ^S*F֮a/a](VUQc5%Z:(rǽ#~p0ƮW FOoSe0Jñ6Va/:j:Y> \&ltm2/ (!^[}.L`C-S?=6w3 lJF҂d@%Ȃ#HZ/ iJG2:~/a'`]txM$3S b~9bV ƴD̐Uĸ;dzi ::}w"yp3{M<2FgW-8U1m|?Sr5DFA txu)Axˌs oo sN<3hH֝6!Jk2-8'|A[=!4g/;em]Q=zķJԷJWuNO;KE<8WsH |BxyTM֭v՛(A_bR1awSg7q;3vw cɋ.;J=Rz MhSxC1ѣ"ibڀwx_pfx$jv Rm#pTIzujGZj#\@Z(.IN3p^S@, P)n a%##,K6Cg}E +wJ(c$AH9"`s8/실AAX6L"ɻwߞ@ !/ruU*vvoM%4.;FrD(&nꖗM+yņ0@OL/:{znũ)rAΦ+<1:n.Tb/O_6X9G  <6NdްVGz%;{ި^q;d2"aPP^jfjCI/ru5sSn;Ήr.cw!(vuVz9#[5S$ [#oiXa՞E%fs꩎_=~yQɛTh!኷z]+2%QS~L ':4L#5pv+u"5?O _ 3>'߃b]'oqUCbfwk8k!3Eְ&)LW(NT9%I{d)Fα֑:#bĴLɆ԰q2GKiS3[=/& u{-IT>=yjUk rӇ)apwz4Y eD6+^%XM\6')P=5ΓlQת&0MTAX F.5Y$`C'Q|$ |;y j x[F/m~x#C^ ys#{(&Dy:ʩ߾%l̋ b"9ĥGm/̇&eO"%V %F)QzwjP~w]b^xunT )\LJpu;*V.#mՐxc@{Jzg`}Ym^L/a]Gv&5e0-sll[$:DI71Fs*Z8U1mm%ZDɴaJҰCn~[qu(*˒g#"jxSmLJv4X;m? g5T{zh")9m(vgGcD*AxdF`Jh 3#PNx@z-*}DGS ;#F)a"hxuwþh0gJR! bd|*^Zúzfh\i;XwWOv8g Qʆ߅"noyPSi{6WEة܉4s,}[T>8ss( 6G<}`L( ,zņ0~OL/a]^$RVW"jva[[‹\jڟ̩ Dr:6S}nA`[-]];,"Ji4%R .ˆk Q"X4$6SJĥd Zd/ruI2eB}&)cCoDzq"HuUCbp\Ä GKkXQvIġ> ߛu`"}_? ䷌9}*O}j\gQ/|~n4{qS0yxvv~88%/'־H㨽5$nMI#_?SCV:N ְ-ݨT;TKL7 D+L4am[Ex5%z#I~&j'<" 0ѧA-9U*%xd#v͏AZ'=p y};Q,uWjN{&VP٧/~Es &O%FUi )8p%{U (0gJ(npVO: U:F}E?Z'4'|\lÍy<)٪zR\N_oYluGQtG[dG4 IAK$Fa=۪&tK ]RAV H`]=:۟)=J&Hj`"5G}Ր'%$ƵNI/<^ZúW1t+d7SJƠ\G׀[6(Kڪת60CgXj؞1[GKkXס.<SSsޒf= >~>7xp6^#'U4$nR)J X6"Gg="ČSH3Qռܬ /eoy~O¼?x_x9:mo@.F#=+:ьCJ5FGV%-z-7OI$oa4sAG{i :nj"yM SqU?߯uۭoa{,鬒H=4:OP?2lNzHj0gJ" {5q#;j;%}r 'Y<ԒG+Rhrd`c*q6p' xSXL;vR U赣Yf"a+SKVI;[Je% Uk@Դ"GҰC'l1k3ޔ\[ \UFVG+#k`LC$aܫ beuF^9\s8p7hS $zn+Q2۰'?%ٟf~#5KЃ2[f?y}F{N[vQm"^aQ`LMPaCAZ UԻ]$iSrkp%Cqf J@Z5$gJNRù6GKkXQI:lSgf5WEr$Ȍ@rm16 M860ÒzҠܩA[uXKbG4rY “}ϺGcQ`H xZ;/k {VNxDz- *BWպTEȋc%?䡬&D]KyV C)aީaWn#5Xp~ufhJ$AJF!#+#?5_mPSW{[_"iXס*jgf.#Hp"7L K=4rnFOd /iCyĐGdjmA`{i :L.Tw"tOv Q`<;*?>,NpNA *7Ӹ>o^jOK 0`-hݘ]%o^戧i-I*@ #5zIG9"A뎻(z-&wȖgϾ3b-K?sLnM|d4m״- ?;J)ݹ,K3yDL}$Ws~i3(ç`66QZrTIzuT39 O"`@ ە{9Ԝ U!1m2Mu-O6VB#ߛ^ƌzf@)Xɔ<'C wF#{`L!Zp^ bLU2u`S^DHi8%dF9~_' DVp<"3>V j`4eia#y H/:?vLda^lWRpn+%7ntC+)&9}l!"{YFd"a)EUHf1 W0rx#X4$΃Ҕ4fXC%m<( ~Sßu; @͔'K;:3sV ƴ3,֙mAL/<^Zúӯm!FYzMpkԔhͦ`gaz7]i+#c`|5jJ^mn^xu˻H'y` .#JI';wz\]0 v##gՐ+%jA i yua+D$_-{gT}uE>+ք^ԐG”jj8jlܑ;Rf uA0ҔE\)y^hV0~ø#k`iJD#51M<8"jO.{)w%AoTr"/)hr>G!q*%' AZm? ְ{'lոCNБ&CE~ ō`? Gw9DUON(4<==E`j}ɆR@ѷSS@֋pog\r&<m0S)90ZmlOa/a]e/^h}[-|?}U%:2iDP*)~KúX;bŽ F)ĺ\'kᗭuO=amWSM/jQs;0KrQ[$ylYq|)U%Y4ӆ 頮"]m? ְY0;a1xDaag.Ѐ W)񷊪QF`|eHXm ~Kú/o0+$kt5r-xH'f[M'35eզ&"&hj1Ga]TShw ixSVɍO\:]y޺XW_9Gbhxs(ƒvSCԿTĺ*5Ыb׳IN'd#G`Ɖ( 2nAD:/ l՚WE=`y}n<}^URwy I 3)^|=O/i٤ +D))̜n-T޳UhDs;w׃̜g;r.#!y|M;8x?G<0pVjByt"G԰TR6II/ SO Rm>,Kfʀ&ԏӷL x uGlv ,{#A#xk^wByTT)d\ p./ޛ'XE:T\EG 1?qU1m(lヨj]!;"I/SúZ%Cw Nʮ5".)HETۢ a<[‰SAV=GGkXWԙCVwL8בOh_'DОDA.Hs: S?!ܷ"H<}Y{"uNGK\ ^E[EJxQ5ӆLNEmyj8j7 #oiXױd.f-}'sq%vg¨\}?-9$6j RL eĪa/a]G iXP6rX*#(ɅԲh˹'LHPh0'%?|&!G'ru–yxw&$JpC| W{0bX];UlIPK Oz#5먍\vz_do[$zAMo`!(iԨVjY#]37QV[[lpM[$T[Gn ]:`W4$"OClbA[`]/k3fAeC*M֧{"-SxJ2G"dvQq 0G< aӱ=%9`Si"#GGkXWރ]2 ܐ9P/dJOiuX){ 9".mc~ũ -6MFҰkc7L8$={ѱ9AHH(mm O4n)=%S?qzً cA4M n#"B@/| Pd0e x ^cӏkOeߟ;O_9vdQ~oox,K-*FlbanE=^01m|?E N"]ms+S="u]%t[oJn;YXO#*^ 77س$(4Oj؂"GKkX1uǮ<8*RȧM5AbƳU ěRSr^15sA{i :Lr=ٻ5h Z=Й06W+~Ŝn*ւFw(j~|wx0Nv$KrӍl-bmJqڦh*D  ƴ%JkPs ~~Kú-BR؃GM6bL88@ŴG)  (e* ƻPPkjgK{oj'R`kGF7ۆ w7"ү{U2E1m`(I?"6GKkXױp_w9--;6[t<Ë*Xs\s{- IoB( vAzNj)0zyiq'ɜNݼ] aYGa]j0y3?~>7&!؁]ViEқc }/B^m#^yuTnlϋ)2m)[ccp(BcO/KAX6FG<Նؤuԓytǡ|'_H A2ГHPISЃvrn xJNۚ>~ty}n{_ōzN;qg^Jnn. Olo猟T٪&$.-p6v(PȂEP%%R߸}w'+ˈ[53% RCdYVȸ߫dzi :RaI}Fg$n@ ٬clt(Q{BzxSCbPUHEk&1BB#Ki7xɫi-0z+wỲ>ùweD V ƴО1GKkXס?p\;Hm\=pגhyrlot\5ӆ!35DIOAL/<^ZúJdͺSh{dgSJ sw_֔QFsՐxSmKojCI/rL :`&~ W{\Sdhg8}['C3%,@TNW*eg"-.d|$_)ADVbBeJB?e %緫U鞧/;Q4dT::u>X~ X8Jx&z R=Ĵd.q􏲆V]u H/:,dBt2P$禢Ƈu7nvTI?z[4$ \oJ댩aVB#Ki %_TgIf "7ݎ+aÎ:-I )hIXp[;k4ҨKݦ)9ȋ yzO6;z^2B=S$Td?Hn ^m6Fg5Zi-޺AJ[(A 㮒LZĴ]5T6f1{i :t%ikD%qܳ)cI"YQIN$lwgˮJQFDsQ`,G$nթ)4]!Ds8YE:KŢfp% !%oHC="nQPIΏ7N^}VVަ"eNI{"8Vq(Rɾ}_5;g4%7JS͜Ӵq;+5{i Qd# i|$n/[$A4Z[t5%J_~8ɜ/9\j Ɇ#xu ˃_.{Su)Qq?ٚC/tj0 ̐dǁgjj^xu5RAIA6nG'0{ƕ_U9?e6682̻ Fq5먥Z!6Q%̄"$W![Ov9ldSq٧DSߧLO/4"?q}(caJZ~YĦYFgѐ60tN qUm?GL:j T-joFG_n۷qiUТ!&jꔼ?{~6a/a]B8+.SZ7ovf'_b>ihU$a|_5mJ:SRCWGKkXסg֏`'›}(Z =v㇯ `DxڱD4'r)A"`ɒ_0GD6K iأI!3Ea]GM#c_E-dlܔlErkqNeVh_4%ۃ0ij@j!gOIz) a.3G de5nJN<[og~$&XsFdۥ*0N.ܔϼL bMɅk'<>Z Lzv=]G\)t<zg[lKKab~Y5β 74]Gi}~- F"y"?n~Dқ]X%V#}P}ɦJv &5,}{hJMnq޷ZtiDALzq5*baU1m`%<;ְ1Nga]q-.(k z/r&]ȩgǍ ݷPYS#8r%~M<]wrm^OܛdxMPG9nsO<_P-U ?ú^)%o] d'13W#⒱jHLI4}.6(4p-lx=ZiCln玘GA</lN&x,6ŖlJCņ0"GҰ6xvidRݤ=xQkE}ob[O82DFn @ֽ;O_dd߯SxSMxtCp>b{{]0bHϾj0nNJD-ko!9^ZúpQl; uyy!0g%UG'ƭX<\, IWIc I M6G^xuyY$#hlS${bk"y!q#3D35jG}yuD۲>ÎV' : a?*$0vd* 7~uES@4yX:ԃR$4>v<%b(2C'#.f) iE@;Qm NZz4Ys).=":}?ujNKEVaQ \$`i#f= SEO#oiXס{,_%IUkkO֓KPm'%@2#$΁ϩn[Gg_"$h:~^hT0 #αk X`j~!dV%oig<ʖaGŗamr oѢq2|v ! UI__ث-A:Dd8yC-)X`/T85Qֈ5fHr15}qt۰a/a_G)+;zW$f*&Qw&H)0Kr]m,^K ڙwy$^eێ"MxqEU8_ yĺXg Fb*쫨me}(.yI 7Y5ָ_#s`L˴k0ɸm~ҋ!/SþHA2ć7!U|\eeHa(W$[pu1rwW~3Jwy_(nyPQR;C]?X-QEU$ Lmi$afC^{i :|{lA_S|J#3z^PqooOKr .6c[u8{2Svd6WTEfsl NteWI&Gj*#5'{f58Zw1Ey= #]f2#⊼j0ϒ5, !/r}a #j&CJIJTMVm0<=w4)l[1v ğGR¿`,LBHh&n"K2/VqSr6a!YwA\JgyMp[H{q_$-(i$L4$IjΏg 5 *!/+bUN8dҫ#_⸆F6b%nf m6q96dyi :t՞jz`0`A{4)_4zD`e ,6 z~SßuMqYdEu#p>ϒS>j_%GGaՐ*0I,6Wa/:6,!`nFݺ$)O߰`Ϋ~#5n-@G4t#m*WQNl(.}H%6J5Qc3Oh/CT&hļVfKrvyc<{gA2w1>rY^ud8) S hyQ$-n$/w)`se:?{_?;/r7זB . d-Ɛ$Nb%+K1m[ Kwa/a_Vtr.>1$"|"Jbc4"A֦6>?ErW"vZmkWFҰcdZc}! C,*[ : ~2 mӈeCQW Ic@̈́'6쫨L#k푑|ϒ#Ƭs"4=+ƞ3#w`|/%GD'%_UR}>ON}}{+Aڑ)ȫ`%HzлV ig8K1N lnT^xDM ֡3Br ʇ9M)чQ-]S[agNjnJ;ÌKgDW2 تH,jHL%/u7m#P^hDz) ֡cDDP&hUAG/&/YuUc3fHwW {uxr8u_ 1G 4O#`8)o|~׮6[@~p1v#5puة~` K}J˦/&O|g3x7Jzg״6b%7:- ׳ B#Ki1v#9>)yp_yO6\[|g)eCAalCVB_f:",fnLIG񥡝 a/<^Zþ-zQ9KԍC:¦)e#I085eR!,n)#ejQz<[oUK(m%UPsxd}GDzOՐMR9Ԭ]UGKkQ/H>ϋ]f,$6N~xT\#eCΐ|2ai"7:uhE^{fԎ#%d6@>)73n"azD`L:*wi@l &/<^Zþ1l%jX:CŒ$EJJCū]%=Es)9;Y*`^ b5 ְiwÒ\}2QW~27#s`KB#41^4)7gXSe'¿"1u[1T;:*^F{`=H"õ[^[u^cw2޺$'"-bՑr0l'7Omi$4cA3GKkסW0\ aG |5PcF /Xb7qU#iPho u6Q>@%:3]εAr#_)nME_tc3{`3#՛#s{ٛZ%PQ9 2]LȂk/?%#F<邇c;D vYTΜ=z7ュeR)1sJ @8cq2d/VƔ4lR.l'< }I_JaY)HCɿ bG] X1Ot=&1sy[TisLY=feFoVܶk~8%*8GI"GokסMJL^m#ҹ^KFSgnƒ~{*X7(=mS1m KDgAM{i :݋aC?5g-2"O{SVt4(?=C>vw1 g L0PNR$/ǥj|D/ZUtӐ9MkVcl y#57١Gw/)7PD!R\D(x"N5:_P??)xYjztG{$KTG|lV^y~P!oiCdɐHY Y2ЈRc˷`C& i3-AinG:Lظ_l 4Kpd <,ʏCm\5|_=bMq{%qqJA/Ϻ/l8k0 THť a/<^Zþ}yA8WiG\_U+EUG;8n"~4,ۄ|O0q.\/.֗^JßuͥņW7ḙ{dpv1{B~-Z"n,<@y濯,tL"ДܘcjBs&FVQ%ݫc I"3BX B#KiLD?RdX-:"I?דCV%HhgQ`L! )ȗy6??G+Ws2qSyH񗥴3^$}li0·NJ3A[ʹ#505Pxu̻F/:9UHMB>knL@bNzĪ]8˾$?Nmj7'E2)xYyN/~Z5PTԄ~QY0)0_Eo%cy婛:4mK'YGEy iEAbwto]sLA|~,DjUf;c,Ihb4o#5 R+f K>, M>x =`\~Ory{l e<觐 %FS%kkWgxq)& A4Y nПya#ߓC6|5]1s2ggNY=@y} 3]Mo46zjй/=8LU#W5$ ̰v$5\sAL#x75YGMZdӦM#%)pa++vUtL2w=RgLIC{٥!41Jְ)`FdNJU懜)'NذdO2Q%T iC忐$?j)3#4YgvXz$#AP/%!!DY?N G|ć{aX95DC!sU%KkױvnyuvݝB |˸;f*r%@alxe l4K.W|Y\ ܦ>Z'ؔ0Bf'^' C3ϒ'3d4R>[Jo)21.$VF)R5$ =g i'Y!ժ bGKiUY@G۫|NKMz}|mT R;sOu.x]dڱk_~5PY]On,jABvض@O8O#_U1m K;4P|A{i :ë񢎭fq sJ.?xlFf' (5FH mSۗi#oiס^PE?x)6%XɌՀ"PnjGD, i"fX2q;4̶ rQ!ցyR?G i,#qZ% iĦ),Y^xD- :j@ŠD4O5V b/bE IlvIYJg |/5Q?Y%c9j潎EPW\2b=+->zʡve#5)qpWNkݵ;C g$IM1m`$TŸ"GKkvEh"?K@߼ğ ,'<>ZþTI]=A:LmF| [kxgx wM$}w@\MN FJ,"7nHzT Ʋ`$]jC^xD- Q"sVVČ"PHаe Ic b֜1^n<=E g,wҍl|Ld7O yw_k cw&?>ݘ4 /xԫocMs{kE%ifj].3, }P$0% -QyCܜnxJ9n8si뉾/Y}ޢvX6%{L5v*΋ݧ1JgT5$ϒD֥!7 #4Ylh蕝6WkM"؞'_W/#S$Vi0N˔6ņa/a_@ bd~!_\\5#=ٯ8D96bFJRÜ a/<"} wWqy S_Y2LǷv|aA}Xa PT`ܓϒ&<)h}za`_~x Up;F' 8(}jP8sW`|9p`ЀQ lϯ_-oD]pJ;8ZEa0!ڙ8\yOn34"Ĵ$ Ԡi[u88qk.™'^D/ ,\,'Ɋ/qTPYUjHY)iN ǹ a/a_sOK::g}3Ä AߑDqAoNQxD{6 i3$Aɵ4\nB#Kis#RRCW$~@%%.yw//It8Kt8kc13^x}@m92/G)xI* >[F'!BmB(!>-hj&_\ "vrW7k-}:o~~)rsFpcd'~2Յ#U/;[zKB0nc^xD- :jc"l=.Z_ݨ0%/k1~Q(Ǩ_F!Ϯ6tcȇ"o4Y߻tb~񣾀|XbfչcQ#1X% 9e'7N;2VEsTԐWKr ϴAU%Ki?kS,otJh:n.ˢiK($9b^4^OmB Vt;):>/nnp..  qBp^tæKH t釘_0~~.<},;.|WBKplt|݈y?eTDa=9|ׁ%UWģ{6WC*σuf4푟#Mq\fICk!C #5 X_2Ɗ>/ %ыY yU`ag9"jUĴII8G@Tl+ p2B^}z^nq|g[=CORM4#{8|Oq@||MDOWFȷ]rӷ(aZ} v,4m"#E'@<DҠ9Џs79y}n4{^kuX'~ A 4@/Mhq޻_ ave#5 &t'e)yH4R@*3%L ƴYՆkWi@[bC sL :jaj$\ac(]l\kTu-T]˙H(Lн*~ˈ6 W K. YldB#Ki6^A+z]Ĩ)y"Cf[cǙXfEpQ\$ |#$n1@a Y[G) ]z0Fe% Y&hF~EIp.e9n㻻Œ=;R66GKkQ<7õln_Mf*):~fvoޞ8J@l%ys$ _ܫ ϏX#5]DG? aVeMKd;K%Ȇ՞mՆ7G$'ă{= R7߅K]/,d+G|Mz D%gmNY5iI֭xIjh w?9G_pwJ] ,'<>Zþ  ob#ܔTD"3bEM1Mƶp b>Rb.,HAσٗD gUݥރo;oQi5w =[l\L/<^Zþ]I~Qz]d\.yImC!V[#y>eļw  J/<^Zþt:s>풱Sh4E@4#.85➻M,H!6lӫ$L :~ IWkHC#ȃEy٢j>_wB5Bmq :J,}!׵.aa_E-fc<=OePT{5 D9B-R1M|VSG! O6% U;]ǭEĬqK^0#1GbKCb'$WX,WM~a'*eںhy< {Ya8H#f5ˆP"SHְ=~I>^@1ɟ$)qw ̨kt`ֈeS$ "Nl6c75Yм竩qoE sPbB1]1m|~ui&jJ(r} &Y] lYR1W7A{$KS+K" M rR`!Um+^x}|~]\JB؈aOPQHz}l|捜)4gE@]J ?$򈓫νƦ(s\D\%U7F:'9]IϑC&5hZl+Hg:MMO$Ħttp^+'8)0U,$_.dX&9ZU*'e {q)$~뿰EȮ }UI5F̐b4ol#JI/rL :*;mjb tL]%=xc@N&6. r%/rĚs1}=^W$Mn3bcf`ni3$a- wf8f ְcOwݔ=lo$E.u QLp~+Ɖ9❻4K᜻4GҰ4hl?U#"KW_|vt51\aM7O[NNlGҰ%{H 6D!?^jQa-b ~|F<*ii0 $5[R!v1GҰ?xfS7nI4ꈳrCPdQNEң``L!xgf.wJL~*ƌCIaD`c&TVWjmi4!vՆm*#oiJꦂžcG&EL/S,q`Fq¾c(MM=KSȌXlWRC`,鼧>7J]I}@Ձƅ_]iֈw Ʒ lBIpm^hDz) tKE'(h?)9Qޣ .v;T.{zJS1m|~켩a f B#g~o9q6aɚ$wâkYFkא5-%. ,/<^Zþ8w3"%˿pot!ek]P׹;6vBoxzodt#5l pS7_27XtOɉx::\x՜ H]$]1mČ65 r`a#oiױ?HG@HX-aCX\Ļe~Oj @16`o#żhѴQ&][pueJcEx HB0Hğ3;:]q57M- u97]vfmZyE/%aR1X(뉕P$=7 e$rk 8U1^hDz) QE15DC4v{oWQ%gtm{@ܰC‘Z|i0 ̐$G~S̈́pb*?<#:[+YM ~6?? H/:|3a7#΃`mt@ifn_|V1]"&oe6"9^ZþR݄x }sy*k9 2۵]o*jOcu2-#e~B@M% \ ų,ꖟ|[jnOt[l:=wxU.(]awF!کUHp9"} ǀQ=E 4$2uȒV5XqN0BpruI)awi8n4#5K JSH5^,IcL'{yq Ylܴ)3@qfJ05岑]4 ְ7(pC/Ȯ2E4~3sHpX5,s!Ci`*۲sFg"b,:PFA) Zex_ 5Pk2͌㩒%x]EII/<^ZþΏQ} 7Q-jХ"YyIw5$nxd'0gyu!*8]=sP˒ |xޫ7 sP˒Tkna/<^Zþʉ .g}#:%,mEtFN7\6ʈw ƴ3,ɸgAt"Y^ZþrfOaA/xUkh9oňPrS7 Sr]ks1m Ha_GIwdbc}:. gx'yN[K܉ׁGͽ4,cܒ|, ׵۸{) QshGI'\1Qx w5G60CFuJ{({i :6n,1LԧAVd`cv=f `k0 ̐#J V&i,/a_G!'R0" la^(eDГ=/ݹV%4$n 3(6?? ְ2LyxhJ^j"m ,fU 7$^! 6cm/<^Jßu8KBdGA.)yJa#TƎ)7X6;K0;Y<}\z@qm>syG޸$5GXWN =qv; *D_hi0ϒ|iNQgyuS j02g ~e G_9zv ²y:5 2O !/r}5Q_x - b/Z M{4X0僛,)h-XӏgO$Y靧ot)2dNG=OrD#/Mq7!SJ;VfF#5s=j?ڗ[k  o:y %(GϱqrJ_RGi rPǢGq~wjK6҆FփmvS/Q%=NmibI.8VğGKkס*x_< ZF/ ZbT I™νJ4,|6ڒ1a\ bmGFgcSҦo)1RzP݄L"{m(3*W\U.Jߟcɛzswu}#iɒ XhX)#{iH|jI{{>躮5 !/<^ZßuvKreʿ"N]`/Fc`L'Il}KA bU};t=m 5Ff)j?jOv3!]%[4l`fIS3k8fGKk[\4v UNh4cO<BYA|FyhugΈF\60Cߥ!B.1*Y^ZþhpLURy{c:Dq O͉5ğB,&JYm%M~a*er#ӭ C>lڃ% ȝUMqKKߥeÏGKkQJ Qv[|Zk(6-"LdS~[Ab(A0nNx@zMVX[@d, #b * 1RwW &aySZ O: U@u $fZIjžwo29bc,d<'5cAY^x}uѱ])K',@NGXf n8Eak\u Uaؔ\ȗbdEKtVߝaE[<60CɍRj ]^x}[J H*AcĪ<} 5* O DW)Q'lǓ&N7I'<>Zþ mL}Zn<Hye*>6,  =r ..#5[]ڱ Hְ M |ZZ~;, vECbڈ v8H mf8^B#Ki$5dj t0l6#n<B`GiU}^57@pfCX1"GKkסg۞ 999v! ]3l?]0^ #5$>nIzg5sN۰^Jßu\ƛU1j ؾG$Y-a@+Y_2}޷86b%79 !dVŸd[#54dA?Wn'[^XDi*6t= Ͼo:U??)1^dʬ?Wy\kD$؃]{nf ټX=bd^1GqIؓ$5h.iL/<"}"6qum`:ژ ؿ_X,9_cڈhg qQm>xTRIo]r.}W$$A m gb`G|_Ǧ!q93^TIM&c('r?0xϦ5vW)>ѽf*ܢ)C6xnJzPmi3$*_9vğGKkסM\Iɇw)"<]Jdx5 [{$Nx}};_[/@%Jl8/ H$r5$>H$^]66GKkQ]x:e(5?LJ"u~mWW{O}-ɡoC X~Sßu.˟lg-ij6" {eōYAezj2c,EF*}0-VB $vFhRаCN Gs x[!ݞj@rIخmېyiIΩ-2˷'̇)[dsDcYD5 WRCEtg?C7&Y#%XG3+ϗDʝˀ{ iIy)j|h* ubm҇0*oI⛁8Mze;:7Hw %lIp'6cu8Ƿ.J؍ -MLxoCox#G\ϮU4%Ku Oz#oiQ x9}N_N#yۊ{)y TTUrHƿѯ]Cb. k5 3{4Y)-G;q;HLo gcyYCg(ZSe@z ĬX^yyށ7TAl^T4fza԰2$Caq%8Ow}S[F&Dúa IFAn1BA!'2]??Kpӏ'oiKR0\d;^5lc%˼|Q8=Ƌ]E}}1# ނfVpx Llۓ8d*z<;e᭞y)_ӣĩI{}c͌ ٿz@_"ěG7 |X@.%LEެ#cW`LFK8w1CNx@z-*eēASك_\C :aT\x5!1m|VJ_% b<*Y^Jßu8f(dSN '-˓0ۮ DR`cǫM~dh*[|g֩v\H6*ƋXKo)p7Ѯ2`<^)QDa ˯^%G+W%nFDC|c) 9Jz|4ƮH')0` +pԬ&v#'<>ZþDӫБ}@$b( A ơYKƪaCȬ[ N^x}샼ԘVU6ړ[ؠŷl9pn VxrĥĿ1 gߖcj+0%%RGU^$ '%ŵqj=A!/UTbtcه0;b3qG2$9񦏧]g7ğAXE&H!X!g2pi9_ܢNf_CUPgIXfg7@Y.x}n儧J}q@|XLy.:K ?>ݸ" 9'"s{ٛ{yS7{H9 O = #|ݪqܾ!~K1m 1͒8.m&ct U8y3 GҔɉP% W7#<{i0O=7 {m߷*`bqHq{3/طkAn*ۻ6z k=;ɊrBT8ɻ:̊hu K`߇kS?UچLl3lvMʀ inK2p :pU ªY#k)WQ,f $3:Yz"Ղ<cITfdQT-zU UTBN>N4|m{%p[?D cdC1OiiS$h fsJrDzMV]t]T[k|4޽/O£nV1k)W}Ӑ6>?EظXbPmbM:G,:!OLi;aJԢog{1*|t5fXr4\cAJҰN Ifq*gd>F˖;8(]s \"kx6Հʴ>[^)g?Semj.;&%UZ(a7AM1m*m8i_&m~a/a_˽K 8HIрS`/K0@ظyvmdn  59z1\s|Jޗ<ۋB5zdĵUQq#L z5b]1m|~EjmA3GKkסDw>kS'ɑRlMp7235þx,#c`L}D0! b*Y^ZþZdXQw#-!x&nNĭwi9 tAI7.p)oeߟ;O߼5:Ek5U0b}žPes zq$ݔKp,I0tK;LoL^yVǓhJyQ(8$@Ts UCn54ْV[ei1#5aևx_uRd Dž#V>>??EXCOH<a7bD{d2T#f$^wDq< B//.=W??{7̀ >_9|4T!b,0F3H⼋llZޣz#e9k3֐x8 $ ">waB#g>"be_Z04࠺$/x0}cTa*#k0ϒ, n 2F#E6yw :j%[u=U/3` %asudӠ@FTwzا#s`L;I, i6?? ְj3s:&{yqEAOnǮܒesj@bX7WE}HWC)w3O},y#=R=NM 3}&ć,  &='( qؐ``_IμsfàEb#$|#Z[F\}`L"f75D+iC"GҰnwk['GזdZ{5 N#}׈H;$o3~Ж ٖa/a_sG Ud#!r: n$A0"a+0%鉯G|jzfz2ϗ{iEtor5]ذITk8{XN0Kr@P_E1M O#-$G U(>3)c3LX,n= Ƹ yr]Atޒ F ƽ[wV7RNqPG~lS%M7ȸg^y!qS+%9pM"+VؽHgp1ZwvAy'QJΓ7) >RF[Wj!ª6bFJPٻ4y ,/<"}XܿФc_hf ˄׍0v5|ǧjˆҗ_aiQ& pƚ(Rr?wW Ha_cd&ps1fq G|DLP= 9#niCIXvi81nGKkסŵW"ĩۼLGPe\lhpe8*>dMCb\~ڻ C^hDz) Dw-Xӓ<߉-AUɋ(\(B;t.Di黆M)iHH[kATyuzp|:; ºh^>X|`xr4Ο?mn 1ނBʜK,q~`yٛ1* >Гmo -ZrFBtk` ;yWi0O^LJl(4P`*[C),(;OuNi4qV 8. 7o$ߥ!6QgyvR EhxqfaHX3x |"N}o25,8<}^E4-3y婛.{>غk0c _Y\=c8޻? QQ5$ XJՆ0R*)~SßufdN%o(%~O|;a~q|-#xi0RJIRci4jC"GKka"7;]Az͂`#osd ?j,U>6]??Kڛ}v2vW7kYl>p{vaV\ ZuMhd6]ėei8چ{i :*W Ӡ*xl"a~ lɐϻ c4r(G;Qs 56i&PkV[i{?֔U;Gz Ҡ 4PyMb:ht̿׺]m޿ &{$Y={bMGquGLx@> rِ+9L|"2a|D` ]^濘Ho_o;ԹXR2p3$%68,{k].rw=q\DZrZ˷֯/HS䞨bl_GeۄhT|rZ8W|}>}2/=T+_(_y#Uߩ8쥐8GfeG,EAPԾ"ne [u d'=!ZlLK؊,햇yE 4B4R"IbVD6ig"Ep\{̹ x]rd~'U{HlgIbLJ]b}.Y~/!^?C$\렍IaYJ{l0^FC3\mLRGL] HQy:D*KlKrcjƍ? )D\03MlBR4dfX!LÌ/=L\] 0˷7]28Tx+ny#q",'r R|gQwi O$b졌lKC{܁'GJ*9{`08Cy ε sc.q40atP^p ^(nţ,OqyV>L#skG R`t -}.Y9%8Ii7KND+?{^GYtk~B1 E/ F~S""Qm 1e"DDh-d s ?Wъp#\mF!XrDJKąv{)ю݃mց7!yuCd~0!u~"?d !)36;V\=t86.RM$Hʣdk66zST\ß##7t܃G\j#j`xh۬DB=A[I ,]L`Y{xfu~4:uQwi&rS#B`YllQ<+2[i{?6Jc6_ҮJ3Jm3w6A&Z~Lv nyywk}z{M ;m D 2fQ7<#t{\y_y:toDp{.VޏUe@neX2'b`Ck)Q̓m s0ClsuV`Al7=ꇩ. %/ryp h!3eDO%7A~m$дv,wNW_2}I"J@]|Ǘ*86frJ?ڴ: fmO_\ӊ/sX5|]pC8T j$Ҏys-bc5p1Km [u`9 N=XaCv\Vd ~0Bf)H1JCKcc}17K6Ď=D*:]J{STOhq'Jc!j/bC`!jbI@"mm`u`g^g%Ñs߱PQ.:B*ȍA=@ڥz۵ R]muSV[i{?4EFP>ToٔPK듈&%*K{:D"#̎:djEP+ocT.4V Y Žp_jd]m)q݃mL}Wa{q=fςH@J!;P+D[~;'ɵ +6S_< C$&kC1*q_۷y\Ps~ І,&+U܈5}F L1UxGS$ =쫥YjolD8 T塶T^­p ~,ZMͱ Q3qc,,<܋чY"B*V &F4yp-1s.Vޏ5@͢(GnI<_/L3eI h_ ćwu`U09 A+-ȍ$cƆ:cDFO0^mZJy-KV]nIi˙J ##*_Xggd$(TJ2 (sEF41Ad,pbũ*aj3iFi쿣Uxi`xNǸxj̥Dvi\};7 ۆz ?law,lZoG.|<8@t},@OL!P>XlD>M9KDߦY3#AXjJd+W?4UR[{1{o &))saYB`;S&R8Ap ~w.ؠ"n*&ru_n -ijH%{:BkN+؈tt伙+Ql\<$ O5mcx݃mց+PmzzK֑. p+a*õmmOel/HR/;ZkTPmR݃܎DO:M*d?و,F Gx=7܈ A~V"ʵ> qvlr:GKon6PhVDR~J3Xeic>RHpHX⸛1!ggXlAf`u|?Q 8W+\­+]O BEkyNagozBZzڸCl vbTwYNT*`""DjFʎiƏ6~&{?qU6pu'{14;Dk"DaY,WX=}֖]y<%ZWY­Θ1I3mcoAWTt\/)l)OFÃ\mL%Kr<)c=Vx>=Q6AHVO>< XJ0$=:tMVDR~CK"Jgv}(XXTD ijYv|Y,!_z:p7遤Y­p ~h2C-p!izimީN6vfxWg>=}íplP!:Jnٸ._a vQB1vܟBUJN#[ɻMuT>KTF;W.V`-YUlCrZt#׹ ;$sHJK8fԝHv, vִk8{6Bba:~Z:(.V~hnV&jcᤱ]Kl|qH&KHFǙy@J%uaP.2לocxiy~>gDSdPOǸK2DgyL]M>}z]@[= >rR7D‹ل  ¬*Qt zmˤ{'qfv*#15M# <"%9 ន7xvYQt~*h?.F G>;P?}{)X p18/L3y[,Lc9`I]V4ҝ\6d Z~bDxC^;OM_b|f,]jqRرツw}`-Ŕv݃mLd@mzx [ %J{G|YN~Cl wm}j9:H8Q}C{=!.6 M&d BQFja J}T2"5Xd DdT Ek1.YmYMQ-1DĬSaqZC'e @6B RM::0[n=XsR0Vl ڍ"ۥqy l]x:Y_mL%!5=sv\V[i{?e`S S2[f"VE2L.vKS*x̓msY&2H-= 30_f%J{/z\޴xbDΤi_-I;fqS"h6p#w/֭RjqުFUB V5rv]\"s0w / !m$rLH DIε bk^q(:D4˷L"fYA%r̊gA1U=:I 5&/\59N)iǭAҰ̓m,H6=LZm7.햇6`Aak$wɆ"f6yH9ɏJ&TKg ㊀y:D|< pbCjez0k|V߁dS9aS5;s!,ӃmW Eh=3^꠭ cM0K;AH16"m\) ^2>GC8VX -gp%/;=fX9x(Yli.ny2m;F4H;4Qi%Kы5ogEޏƹ{:Y1 vP*djDfދKkgZT"6M,xS_ 4_Rx<|y2-KD^ՁZJd@|z`ѬcW#\mΈU3ݍ`D2LAbjDԈs`pxM7z` q8l#43 Zh&د yKVx,BkQ<7IDKqRN[^mRҎCXՃmց+eV:&K{?4cEPYcI=LBb$ީ4!_T0;mP+)13JÀ2\s;#Q64u05_u\&+X;t74P.S0HGzpdwB}:9٬anӹ *m_׵P>E|D] zdnrZ8p~hO*CxF+f ~4d 2 ژBak+`07xd(Z_x\. @0}Nջ˷gűmnŭ6stJD$؅}]Ճ 4e9Je+\­J1`l݆ Y2DJފK DҤ2\ktł{]R2D9MuZplXm"\6A5~ Y"[-{/Ǖj^Ec{Pq"JqQrHXJ%/2}JĄ`uvc")\_{賀h{/옰F#cI$V&ʙ&E/@E^y.Pϭl7W}ցU ,qB,D18]nHy@cƧӌW|zu˹_KF%R9&DeW3mI,k_Q`(#Wz8us#\mj?NW|Їy,u|]4V[#S[ p.?d$f9'Dd^a37ה3sƐPBզiDGSI38F Cf ٦eLU*F^w }R3mpr]Dj |^$m@ʑ';fno%/%Z=f mꐭv/%cMB:5:i ƬF.UNc_mE6qXRl\! uc1 d?!Kw/Ǡnz @48 ͖Vt PCz6#Z;_^\^^)fѥ8Yfw7w38]Tg=fDÙ=H*HlK'EkuNpy\=|^<{ Zs<_'K%8Dg:um߽XH>RlΐT#2LRB͋lj&{R CڹI_o6uEf+W?ζ@qIܜD= 1ӎWmSC֎H$xLeruvD%J{aT\n^z};gA"">W; ETD05d+>JW.q݁lUL~·![R1[)"P3H|qw B!ə旱/bo^楐 &boij3 p7XorԊgAn*NJTV;FtX%{: # UӬ#uO.!ez&[y5_5rԇj!ՠ#tWDz6b5KDvՃmց+ӊ+!q[n=ЊOQM[{<`yS4:8*i%nDMUC\a&b{CFdo]X+=&BO~qy{q н<< q\ϊȐ^ұMz:8^m .]?h|;9Rk aX)Vqt2'LOv`*NpF'¸aV[i{?XeF{S54$u }ٌ}Ip/۬H*A*hc.6@6=eq:~2D)HDm:Ƞ;" "fx?(۬Wnz}6>,햇sT:9*D4CK*q*}0Bqij$VZsi?8 ˏ ys#؂AgAg,X蕊3OIKz _6~&RGk1 p+a=&a"PEys+,t`vK݊Vϳ{HR`(d+[i{?, 9#ℜ6Cے')Lδd+qu U|?!CCJYm<8n5[phI3}j<oR\M8gE] mVWyxÅ/d#T (zN_QD~/*ŒF6ƦqT)s Kl 9!O.5F͵"K` g6h`EEǥ`D?cP|HIR:o\K %fqlBv\Fd 1=، ֞ib)G" DR BF2قy:܃R:d?ي,vޏu?kzo2HU3_"!?\a9/׳{]K06!=cx嗭p ~Gs֔J+"H E}#Γv4A̓ތ/=s6 vdhw?u)?Tz(Pu*z-.[۬H{=qWLW XNRE y_8WL"Lgud`n]׾wYraZ {*Wh{/W;˗άcmx sqHqidzy\Ft\?۬Hjck}l=PC\eƱuz"L}j0.ڹ;}@9Pj,:/<mp:GW!K`zyS_*iR{BB0\ #M3Ve[~rtC^]}靦P u|kW$^^NZAwmd -4x[|>KtӁLՀ$!@{V![6"KB^Y!׉ U 6ÝmQ >KD Cڧu PA;bj Vï~,y帹/N_ |ml|]An2y.ӃD"Q"p ~q|Ԓqdhܯ1ƝZRh<C'dԂnlHqk p+aKT=qN% TJ<\])#DqSc)J]k  Xiq]mEN.햇k#w4&w/J? 4 `;&k,:kXxk\ܣȿ]^Ԟ;\{TV wO 712%āc:j[hzHPDB{:p1iI![곔P+(cPr2h0ȃ~t}m[c݃mWOA_d+[i{?wrU?Dkȃ]!B+z? RN,PvK;"#~L"c,%bw.lV=Dٚ})VjC0ڢ/&2 RMy&^--7m^,EkzHuhJw:h?.햇+?aqfur¥lT"~Ұ$cg݃mց!n_*dƒV[i{?VAa&u_␽K_7 ȳTqL icԩTRn!mց+LʱAXJyՏMW !^/7D6lKvAr`u@Kip{p ~ƌ@z7↜)|{]Xll̍=fʠz*5U!{6Dw{?ZΜ 7'Crr} &Ol^߃acRm)q݃m֡- h5j qnP BlHFJw># Axs[ij䋃Y.RxXh^@[o6^hgmUX(8H!50tFluR)XF=9Ks`n5Xd+\­_1&D݁'2@}훩+1 86@0iҦ~u^J{%A%]z:o&Ce@?\ŁLՀYȍum:x9[1:Y­ޞJbU}$A 0Y;+d u Zg"Gcʶ{y{܀5S{j֑ p+W?LXX|ĦLYB"E #ʽh&a9zϝ3tױ;=rGYNW .6 +Q̷&YI䖢Sp"\Naʲ_JQFuc ╉ 8=\VT԰T+D[~O3'DΨ`3RDn=C*P^G^%&LΠ*h4j}PJ-hmwIrw2WT"rC6+"KdapWBȥƶQJ6hpĉJ ll;aG"w)=4&:id+Z~h5Ns.NID#5hNb$lSy!픢2rKLJ"ZBn=X$ AdcLF^lib}5D1%X~f<(!;(CK훎iajݚf!yUd$yc@ªJYâ,bT})Uۗ%&20Ʊ1V[i{?ִÌАK[B;CmH֑.v(U"K!"xH[u D!:d`n7=:_c7D#T~~"N1ˏ ~9"l*+Rci󐶓W%rMA_됍#[%J{?BH!-rA}пO8}o+_}$_>OTDND3AW"KX:,R*l"sJd)kgtϿ~\{ #ljT!h7o|?D2syQo> 3BV?}?P;蚕=#E>P=#ڰZJV \jφUVJm]J-_T3`#Oe-Oyѷ`ktߎ x tQy7օ0#DzNhۿ75DwOrXE4_;%.oh;._>!<4P Q !.2#ǫ1f<bzW"d7x^* iZxr5 'S Az=G/YSX$LLrF'ps7i81 cOʣYEXĬ-n|0r7SU2z0C!Ib(-AFhOA=GՉЖ@yV\Uԅ^ܥ=Y$yRQutj@ m ؉,Mv.zdU+t.IO!e&͊Oq=5…q ~_%C0l"A+@Jtpl AJw$RO"i"q[UZ@Fn]e +tpNd0ʽX{|:| Wdf1_G *Ddqټ"\,yv,N _D)ol⟖IŁtNqP;|aÁ<|zh%FHqT >W $Nd*G rWr\i8_[gD< ;A ` St`|*M|{0o ~HN?|0r5!WaANbsACdWuQK,d;syw c9 ?8uU'‡" ǰV-Jb]x6H8Y=( +FU[w~ 1{™ݰ [) 6́\H<ȁo oN+Cx>ל}ޗxA8=d2H,Dl_DJ<ȬIee _t.RAQAF!wq? ov 1[k*mGp]pv oK(BnD*)]w7 /] K,sY,V'J6gk3Czʎܬ'J-H8~xTߕHiujcC@HݹŌ٨Ƕs`6f=M zPP|~-orc{$C|lC|"E< {/)9إ XWڛ\L-;EP#R I=HU2Me_W!s"LM"'{ʈ]ox7#M}&R4HG_ܑ9zv-0W9\0=sk #y--~/ 2Xϊp^CWiq\'ʰ۱}Ajo(?pzߗ/t8\׿izW!Si5"%G_nBKvh4rr+4C8M7.'=A8iǩШȣ-?kѰ) Dnn1 Ùs3H3+g`~ X)|K缰຋G:>BsKwܚ(v} [9>c/OUZ2D3WrB~-.둿ww zͩ歇q\g{1Ya6@}k\ܾōcqQ@x\zں [:s,n4#O[VyEڄڄKTҸX<[7a>~;@죉AFC4P?da.w 2zEB\^>\8"1<ԵHqt#93fcEB?73U /–&Z<:a79=B q}f=SbS R=%el*.J.Uk%(̭89Ӡ> 6+<72eo6E<B$ȷ@.7sG\*$"HT4)T DO#HLEWqJ̷K|$BvB} EK?s唢k;|#Q$7(P~6r` H=VumFԉqzk(y cPn횛 :Zk# '"=Bʀ3'ܰYH|,C/0*ТA2^Eh=״`(!WV/ů"o(<,Y|x<ؗįG\Cq^9"%uM{kx)gp>Ezoyel1 ~-8"Yx%x\umиQqĊs\O];kkӞ8 ijͥ} D'R/#xVE[] zxhn%jʙebr!zzƽ>p0j -OMQNߜx|άBF3OX8nԹ*yP xJPͯP\}ޑNejLV`TZy1I2׮x'DJ|>\$8)|lˡUN?8}lc?nTgVtq<;N9>g[u0u!ΝH}\.?UJՓ.IZRͱh G<=8E [w 0!7zQ2Eq Yڜ" ި:b֤(}YW yvGN]n,Lɍ\M"׳>D*S=Ƚ?J\cD\ee4[Q-x<32_j?C.BY(29!w"=uz3h ;< 9|KOƖR]MjDǩ0wqs#Ofvn%F\T:>r}sz $E6N|I<oRS? s_1:AY>'mw݋P8)y޻0*]M/e;ԼsFx*  a)'nDv` 6+Ben%1H;*6o#7H;Bx̺LF0h|kU8JDtŏι߭w^dBD_͈:фz3Xꩭ@faH^q|p?:+d-g otx)m,\Ls㪓i *ϵUV'kIGRzj ґȥ9bjGs>7?>-׼vmfuYذæ)!%K7074 B@OyF,e !z߾, rȡv HvY@hT CSP9Oz)Ks@Fۏ98J5SF: G ,ERfrOߛ6ypQ]+S4obgQ;uʌ2OAxobOMn{,/^[B{rȉ:uއA/iuL#-=2v2GOջo*5N u󁻿"K&BiǕQPَ9+X 3d a8C ʟO |gMYH3^`@RC1\oBmM: w/Sr8">6?LG҈o:"-Z3? R`\FbTH77NtZ1.q+D.gţ#Wp1.$a-7(Ef}Q}  ԍ>0Wh1ߎ.'-m\~0+bb}j((V'9،{BbRpq:"[<G;3B34x^Tʏ N\U4T#CN fF[/,۴"7(Lz;q[1oE8l歷 䭷ŨezSTi!*:y-"0K5oUlr!v,vY0֫.[okI\oq1]ƷίCvBD]hCsN)&w싻޴=H"ط+,z>Ҥآ+uqq<-s\oXLzv#Bvs\mA,i;lz\og\og"8's}\x9g_T$8Jup(z-uʼn'u3gcv]V;oR"k'w}|8&:ɃD^^뱂 Xd"_"oKD^sD^5A]2PݛǏ7\Ќ:Fr| M'wEn!X ױku:MgLV|y|b5oYc]oS^ǨGT9'{]WUr/rU(pޮt'_Jױ@3 /')Ey; yE4BY-Ju,[u /`܏H]o ˻bߙ#/N=dBxx :v8∻]-='$^GV^WN? /?Q۝aݹraSSSq_D\=W^My&"",mrرYEΧV4MWaⰿa*λ>/ⰿH5حe JƆ.vddž6`ǦUZs`"WWέv(p:ŽS)0Z}PT8E,v+DqzzY8l3_+a1t󰆂Fy';t&zƎ3gQ #;cKMI8 $vJl$v~>?u]5q2<ɝzb.2RN;NO kh({ ȕŎkc2^W<Mx虮Ix8+D;E%))P> & XF* `Ɓg⠉~,$yrُطI}ښ̎hR3Ceb$U<5=4bZ>MfQfϠ|acQ~-fy#ԺRe;#HLb1'E3df6?3}2QEgك&"ڞ$PtC4|rNN1ŬtQK?ǂP=3znef#"F챌}yLfكfŧ~ُɱ=GehJf1f9~t~lD==gكH%*>`Nřzb"jكULn+sZl#CPf >bbfOǤp>kf+كg;IfꜤfd:cW x4SdՍb4y2c!틶 " oo~X1辈~LNǙ ts Ϥh"}bn{ %1U۷& b8y쁨!ñ9C0^W=v"전rg쁸ɷ(5}rMMd,z2Bcx .c{^e4꤉AI";$Du@qWDW챓DId?2Dpm<`=UyÃG~\L8ސ>G. dĤt0/%&;ȭ2zܳB0,6#ϵ#ޠTjDe|.HMdPݤo؜$M1>0ɞN*{2˒TIe;T+#Me&7DE0}qg*{>&\\@s$>LI2wdn8XϾceXؚ..{L~Uce(pcc.{N>&] PV=>i2,y7R@?GGfOAٗ2,yёdd=g 'v˹}ؗv4c.{n&=;ei[i"/V/$.YK+!~0f#IJ{nzw7!sU$*>UeLb$o'}$)$9D>L K,k`Lb#aQKHnYNXs6}`¤O/l#ohyN4wT|ղ"Ts,9w0YWUbi{&=ՈWTb4}vدۏi =֭*tz},cz7ycb-]cmZD==I(IbMxI}z7~hLbW&Wj ~Qs_>Y)j{n'I !؟)YTk؟֘81iS<4j{9&=O cR`<Ǟ2Idn ٟۏ7<5=R\Hҏ+s)5br9yF@MHa+K^ReLc/yb{r#{Da(;TG+be[-{Bb)Nd鿩 !{Di`ΩYe*^J-X, k*{Ihe!^P42(XMDcG"cyGh^ZXY7b/uIXv(^n@8+{DROS^H쁘aM< AMb/ydLƜH쁜@%D$v(V#Їl%RS.1=,vds \.^a5& Ӟv%{DT0,vȧdXϼ[YObDCZb4jiYURmlfr EAs- g:7w:#ƽ #8vhG&|Bg%yݛ<.s;AGJ.mdg :>!+v-v(΃?{QIZ`Q).-FGjg.;glX \MvxvˤԖ4ƽû< JuJݞ{"~ $ O塀PlYu~tlqfr>t'C%;G5z`<˚Ӯu>cSl^9Nd3Ki؃,NpgǹUg#ekg1YVf Q]R YvW W̮kj`{PV-UKJql~afBE1CcUNv^8wb/Ue y'p;/㘼@t^l{yŨϨo:+pnmKes>Η[$ =kHv` +SJuthR=,r_Y/*.'1,.+ƕng-nP"n$U +>5GC &Ekm/c-T5&m@2m8+fREa"0h;i*z]d@F谠Wv!̴PT h_Ŋ&zT$kmcsT]l[ek8^uj9&e6y`Q۴}͈dU]~dR" Ȯen1d*fK(ՎdjG0-ߎT5Q҃#ܪu #"[+B-D-"ƴ#ʼ8,B5vn@j3}4g;B١v;bbz<#SϋR N(6apg5}ʴb+,krQ|m,plvh m]Ք,q!gW 4"1 ~{`;ޓiI"Z 7 0.*ZomSYqmTkoh\{[*X`-U9'hЪA*FGku5\T{Hd5 dX\K[完T=r0 YlT^2y_YG\p_*@= %2hER,af)Z} :nZVrvi}`(EZUr _.Ry|A_.gUd%6ױD*ZmLpl DBC,a91A-rJ ̋З2ӬC5&0Q,,4١0jUK'it2b#2OZ16x&Os ZM)[Þ'.|"r#Dd%k=WP: ; *o ('L}*zXV9c1H&t5?*D Qk6h"X lAj3L uʉ!Ji@Zy Z5sd:L>]]DV@Ys^Z"עZvu2g65Q&#Hہ5E+dl- 7e~G s "Y:9}Y4Àp__^QX@~կU*󸤤^ॖ / /\xaa0G'1\L2 NV^n ^jLgxCD/Y.LWI]2jHtZ}'8%zN2K2-KwYB喐 ,^n^*̲x{-%OG0 ^fijH2K2-K1YHR'5,y䖐O-K#Ń[E/~sW 52a7(mY1Op^<^uTh n]B%֡+b-WmsfkTB<^Q̽D,/\xyyr5 f/:EL}/Y}/-kipbsV.Ie}ǐ4zD}]DO'JC3a)P>\(mDhd7Rj/Pl /M*0S 16Xؙ'~ݷ bgSI=)O0K"22B aS;]ݼ4?W%=oY$B'^&엷7L߭> Fm^ `wWJt&ܭ/"Ӭ, Ѽz&ixڭ7Ys߮7J}y|=3ER7e>n{ӿIj>нo;n2uכ{ v[Kәapx:kJ}}p!Ш>ͯ_;`4sE?ᗁ_jO.؂jSCJv5~lSߺ.Hn>g<}FNj ]4[]%{'.)#8\7m7x'X'ґY[?7}~?]sws hĜ<%{R?htv/7Pǁ܊m ?J7rOw[/Wmgg?EiOPtOB?iBE vw6Y+%vofK/9} %yJwp|炒fWow&,Q0[nPaVHV]*RGmߐxЛQ=zT&=wm?uYܽDm^[(IMṽ܉{lNhi֏A}Mo0➆4:G_2}2*+ĠaQ@ nO{Ժc J  ezڢ9bϋҦFڡß2g >Y׋;(-ˋLɗٺ.(04mЬԀ񠬅ߜk"endstream endobj 269 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 3523 >> stream xUW XS׶>1A&Mы$2 3" "(JЪeVZ+(*j'X " @ ʭ>wvI|HaD"Rظ>21sCԍY6L^mҸ`(0h$MdZ߬7o ޔp󊠜䐕)ai"ӣ2S]\ݦM11aPf0DfYD1hƎY,a{&f2c2 2LgfcȘO͘3f cbF04Eƀ2W$AR%0aqö{-HHKuR21'̦qN"] 0M8*tz;I)[ 9]67745bؤ 65Z'T عX3aJְ9_d1G}TsmEcfMq *ifMm]\v .YjR[=2gZ_%6!%R  ,a9I@Ē{,yCo\쁚)EbjM|zL0#O֓&#=#@{m6e $75RFb&974Ɉ N!"6>] 1p;bڒ ^2 nnũ}خtGҭsY)vIzTF$85H|0PȜ}PDzr{rz _ޟMF.0FէTJҫ4p `A +yNRa6OH kGlzUWy*IF [U񐇝U=XLysb'4sك'!_fk-t2=y; YF,oU_v*`}Tj({8~&&W9Av&H}ydzQE^V:-Ww \!1i O)c߶'\pB~cܢڙ3푛 خQ)}4i`3]gE]̬?oM"!u[Q ^`7%l4ҭ*Ii.nѣeV Zeqh\2TJH_ˏ䘟#W.iCU^*  K!y+A!HWF L`{v"7=p^ϽNPsj⟪_B; xk19U~6׋.n/N#51|~j~ۉᖜ]韇ˈG~}C 5ɿ:SO ODkvfmX⳥H\yŲCރG  gVw"wq@5T ҿu,Y=S "zxH1֞oRDI1 s *Hb3;6˸;Ǽ*rMf%h7yDdmXN0 kCRITibI`>]cTDdP#ud,eŅ_y)9yi"}'P~d1t 쇓G*iM[VI[[m:Ztڋ31 ^ģ aԳVH1˛< NZa$i "-Cp>D Z%yqЎ` D$ziE *9Ҡ3faf/؄+'{6 Uxd&)j"|i\DֿVTȶ,hI.N!f 9bL䃕RXNFa ;I&:5ahL#Ip|.nnXd$"%>kFJ(XĥhtMg<[({ԅ`beDMM]8cž( pky _&]\'xpUU4; jPFl^h&=:E_c$ FˀN =p\60GeDJ גъ;, U >)ewȧsٵ/'_\u.2`Q]=XْnbZAOsthv^t|ڞ<=A X&b $ā08BjsXGȖ٫L@Ɇ G=1&~YQ!?=#IS'ҦCo/NR,/)B)Pݝ8نKp?}C*F (!X/򤩊@컄CJ `si_z 7_s^u\㉞A* 6љ7>-md7fb׀c* fXwq} vIK"g瓺_'#hI"c\nDR@@fa26ffo C(hյ?}qC t߸XUqR`{,Z^jPxJOńbϴ~RryrGVkjhX+d,v,iŒn 6W{t>dxT¡iԲrtWyḃ0&~~ }6vIHKt'1 6y ߕ|6"bk /=̠,xOdET_oCt-{_uw&tshYO^أW!1rDFqă|F> stream x][HSqGqupҲv ]`$.],t*:+M)ֲ&ΚaiiK,+6+_"z{p#&K߇|)$ @E)O j3˫*ʊ6(l>n Ĭ%P-G,)ѦEJCG"$CGP΀@f 4 WNÎHW7 A2GHܑ$I Ѵu3ڦ&c}c%J:w}Ιi5+,]WH.rL\zxiSOvYoon Iiơ47Loσ̑*O4kɟjg#؀U%gL)ݮ9zoҳ$} >S# Jwa@3َr`O 9Aȕ/w d]6̭}h/`]|p u |> stream x{HSqڴ_mY !q/( J4$K#̊¬4u{wys_S.[V*Zbj*zR1zE!AAi9A) QgP|yhQ5Du?;<2@!Em6QiJEWg8d6."?\I*FHQGj›b%gyb dV+]n_` jrڸJG_ܕu46{Djɡ0e1c W$$!Fa>zA4<5k+ r8b9{(\ Ix$;>u+eW+Vy<04z,Mc U,3j'$~[s&ݱ+hkd#8y5ɮEgKT:Ûvhl; ig"BKd^@ V~<]n;3"k>jޘOMrv;G_yaFQv{Qh1գq%кkԧظbƛy(E& v Ɉbb}sj)evpęt5ܒm wV!EsPwn`܍/ {wAsACcU&T+i!tꯟ(:n۞JrQ=[Y3 4AM> stream x-ohu/mV3 F_HU, EQdڤ&w{~ec2t L }廻x~_^|y~&8Ϟ}g~: 2pMN!4PLO>fF<yyyfz&{u`+o ߻3 g޽?A@m+rlKSŜ$mAđɤE=M_0眏( f_ekjSbd$H))P`iij̇$G|2ꅽO?yYʒ<`k lbM؝-q"MT`4^ Ly.R$^ D*qڰp["bgH+,OwnV+P0ޏ8~vڢmêoĊx*NkW2jCAPݏcDF*.%aKa )NW>BԠlq]EU BAYxNxI).s+H.g+Lo:%usk**hs^p^w&#^&]BsYG#m3jܨ:D2<"r?ڼԮ"9.Jzi#iُ 'VP$e9#^͵Fg' g RWFR=P92n6u/=ϽKtksmDF>[oabrlՀ 5F>U pӕiв±nh= صendstream endobj 273 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 166 >> stream xcd`ab`dddu 21aQ2A}@ѐA%Gߏ,Y}>Iw?) '_Ǡ+#}qC9LbSKMgoCB (OeWFO|>g7W7w76"endstream endobj 274 0 obj << /Filter /FlateDecode /Length 513705 >> stream xMmIn%6;|i(oa[hn@<߮߾y}zw{GGK{}R}_񻟿Zt/q]/o_o|tߦE_zq?~mŀO ѿr^co|H֚D-k:"&{wFkᅦ6ksP-/&~ZNDb߀ZlǗoGy~L۔]|[^:~_mK/?@P|w0kWO8?7zC¿k[Wu_1׷MZmg+i' jytL?_nUԚ?㏋4/T|g\ EVg/ET~19/??(5o~&&GI:$~&v?:[_~XOZs]5oN~ݗ_~oۻ}&FZyğ8%~TeS[(loԖv1o~ǟŌ; 1:-_;-w5&4ea}?B?9Y?w?q=E#C~1׏w>]mԗ7?Ya0~ݗcZZuJi8WWS,5}cA~+մ{sJ~oKYi}Ft䫗Ǹ?U~Wz/۹_4KZ6|v+bx kvvޗ^Q{*|-p}?89Z{zamF~oy}.Lmչt?.9zp 3_}}Z_VZ10jfLìa n[KLeÌQnˠqו>I_70ۙhGh k[jktlnb֢̏6i􏾄_}giaU>~~'`”14׾VրZGJ^caֿrYsa/lZ1X;DNCVzlv]T?L[d=m-[c+i[ӫ}Bs_OmʜB166ԤZš J!֢Tg06m\s&gAɾ|~5| ^ 4,njjb=fR4m}_<ւ^}<~,/ wLK>aL̟Rm=6 YX*06DD7#6WZz_VaR}\kZ `Rbze^kW2U/UP_30w'~j|A53RI%Iծ`S9AsWOyP٪NyPiF1a?·k$[j-Z D*!ֲ4˽L{Ǹޠ~7_8έ}kv0l2?\?ɰ`iwF7n\kU\\kJs|U|CPlﵬ%cmWnul,[*;c<[nݰ}ξfomukAHUhPc-JqY,T26υYOm;g8O>f- E*cmYUFk>QY- k3Tf1 Zk+3/:`8T"Y/-bW[K b:Wֶla,+^7D8hZ7D9lxprA3~ A5evAj{;sP)MiX%D:$Ѵ(DBD\EѲ?!"{HQ[8 44ߗɔ*N^%u4X׹e١!tp%ot/f{b32ϗl3+,%f #_{i&dK3u&;\teѿ۫̓_Z }*KWgm=볹NٟC0.q/Yc밿op~nBY|_ˍ1[^6ԟ~$W$v ]g_ _yQ=k^[%~[׏lasU`XZrSizp,ֶl;SH=gPL εlmixM_pkzf䂇 ebX5S̅98eSO~u·Kuܟ8w [e}\uyQ)Qw%gl! *83xF8 T'sj:k2eBߠXCF39 !0&,-µtyhkXS] ɲ'2c}s%Xb'r넊a{A1̧zpp2d:&a fCaZ8E-y/lK&V8d%pD~C2l`N!k3æAQܜ!`ȰY?˂yCaZ8kϊ&Zla1M>z. ^y&>(m CN8ރ0e"(epxxuG3] kƝ~t3 s6Z 6]6)#['{ŝ6dصEh)_`Q6*#jQ&}5z0^{^\0SbTsnCpLZR}.ZH!p-µty^ˈnb[72 .0 ́Cξ~zmeksK2ÌNZ:<|Aaca\!CHbkm2K ӆ G L?  pLA E FHp1sZ+: ȸn k_;e Ow,_)[=8 f»:--t]iĹj/-.֚d+ r{8q7Ec fe*amI p-spT+~䤟7і 'gƗS)Lz;0VP'!FH9>U5iK6WK1y!jZ?~̥]]qC¦XA0@dxc|8G8VJ1nMڄmO~cjvQ Uc3hD> sxKE^fHc [D|3w`-aMs0%sdq0 em FMhlKxyٹFD}P$KCs  ! -D&q>[y!N"aF[jn:xRE2O0eꘌ`z /p[x,NI+mf 䁡UŪp̸!x.ƬnݕCa,R)\EĹgq-n [uJÉqr~EmnsXv .`bMI9 k)PQ9Mη*w-vcymfϊx9Xfvc \:1VfL]Sf᩻&yuhÀp ,#? 5֚&;nSL\b-؛Zz"NZW8vm)ћcC\t392/[4n?D:;L$& @טR)BiqxN§Z:TroLz"V q8L!Lc99Ca]B Q<y4vR|9Ơ ~Xa篠vphY {qX12)\KU5o`![&?O̍[b_N9vyxGN($$0d`0cN`_;d#--µtyaHǙ65d}$g7na}PXN6 0)Uif2AXB8|5ssm [Dby &%'s^7f]| 0D`#,;B)Bi0x<zf \|ZdnRe Zu#>7M]pcRDb]Jps p2> GJvSH!Na<fs Zuzf<-m+d΃"<8tZfecao]=krPnU\s_\s6Vdm eut)<掇9btN׬`奙OR&, ^/  g7 ms(-0ĤS92ȩ"_綝N@ FQ.+×ky U gob\S, }pa%,su7+&6粔s#b`3+$% yʛ"p~sp81琐_e-%-µ$|[*ەn64K / m "C&0簝AxwqN!9MOx`:M5F,yf,.AQo;em -́6)\KxO.`{O`:iآl>Tx[BO9|y/Lu'P~PHi#sAk`&Ys0_qFw kܘuxAhsX C]a\MK p-szV&0_̭f;-Mָma^ F @Lq? !9 f{!A +n_<0%d=o +4ŬCIɁaP'eVNk|1ՁmRe]:|5K<[NLkP@hPXA:8u@͡ } d/hsxCFS˾MWc X$4+CJ8 XpXt{wVx6e8 O~M%9 ߄n5UUOᐪQ吲#%&s CwZ w:7AX)(6|5 a5Dߨr+<0qz<$_~dcQQ9sU<bI)qY1 gNv}mEuXR{aP0E~I`~y mJ8 8OBpJ) !`e|n2>\EH27 HK|ji"8~2ZE-y?oC"qʼH< 9_dl067}hNLSvQ\ u-"<|w!4qr(2oܽEip7'Xw4EdCAH`'!Vkc58v"]ug.gS-JG¸ u6 %ǖ!G{j8y"Y VeA`<7 :@m=93Żώg㈀hP!#A>5e(fn .lf?tVo+<9i*kev<04n)H0̢ȋ! ku}{SX}rdCa&s""Y:Pÿm[X3j,Km*8Vi ޮt qpxg9ԛcm °S$`V]p {e}sEЫP7,EkŝuL^@ fqH ,EIs8T\-Gígx%6)ǫR6!϶(( cBa?փu|a>-vQUI92\}gnuXYC2]1 a"o)-µtyW^ ffib=PwG' b 388\zktAOX07q ^6 ف'iO[cFD3 A1 㝜CEVH` r7 Q>-p 99MQң2  81}1"@8+s]c10 VH =tP f7)C%X~g 4h8y3|Cb 6fZ v!'d9µty{["[GbcN pa lAvK DR)BiqxN<^fI]]eD 0J[o>=`|EX+88 x,!0Sbù@ii ?rmu,LNOu>.@hpű$vl u+ S8ₚ*DZdٱl?R:e|# x,d&~U0)9 _+@:[5"p R~\&ܲ{XUϮS'$l (9` ]e_EQx9hLuhjض v\sx4{;lV+ L&/aHe΀S|r&-IP'KAڄj=(Boqx\SU\"K'9 ;1먋r8aYUaf_u$K@sY c^#ﳾ_7 if2STlÔz;0fsX' .0<)BoqxtA2/&8VDrCBVFӬH\T|):1<)ǘw#ov/¯SHCgf73x$/G0y7Rӝ2 N/ǔ` \.cxF%cE+7z vɨok.Y1ދj}O7We,_f %`c>yCa-PP)Bkqxxiv /4ۃQI\ȵ[pC$uE5ET'|pp20BN 8t+NZ:<4_ȅ-ג->0z$+z]W=G ÍY?[AԂ84q UIcNxqmMC=1Vxb~)DVdƌ[a dTisx40 9ͼ-1,rcn2̑-+MȅA<8P`&k8.G@VÿDbnX5/P4V]< FC;~PPV~h<ϻq◖9ssd=\3@͌ѱR㨹]=v~P-aHxmՅ33h À]'pc疫P;nf{kM03.ZB%|8n#`]_(# 9@7bgO-ǺUpPZd;e 2[zIei2X#99"踬 YpL:qò]A8H9֋ÒI3GΊB-{`H%J gQq6)Ak1 ,)-B-Zt+g!:XafWq_TNeE/nXkFK<(uz -J$|aZxF5Y;0S HBc()`+S(,8b`) _eUQ9sQ.qxNL`jG `+]XF FL8Kd8=Ɨ{J*b+M_M—e\{9k:f2^UU VkNR >ks ˄޶ N*:$d{a D< 9~jQ]7+qZ#QO F$IY.!E޶sx|q6.X6dǬElH b `0E`7VY]e@%utYEǍWrͪqz>9GX{~{!8VvfqV2kmp-s,GrLkn+ZU'rib&/:<X)j|ܫ2k]AJs2UpR26xIfqVA,faw1@`Cm=&f| N92a*_h?ms_jm2ȵ`8"Zef/Vc:(rg fЙ&>w}s(YLZ_,qaRѠX6 :Rc3PGwstH.)\Ki[0gTlAoVYcEpbh(κsٿ(j% <<5JcjcЅhx͖hV;6j & Z8k)_Cey(yb:$oU ql+ŋn:Æ/7o`Ddp| zZ"S~a0ԞґTcBX]QX ,~1kpp@$yU "[W `kTΣ9tؼy;1̮|X+̸qPbp܎8ΡEtqy_M *4wQnt >ђRgWp5PTC(V4wo(\Qߞ4i|ܬ-p-p% X&X00l 1ښUX _5 9?`FpSp%/EYl*GY=x{0jȮh6R*\,3"./DJ8Eh-Y{h] ં3/ڹ=1aX,Blf?7/ V_0XW)\EfllG,ݐ@bŪWlHFV61xA,%C1`.C̉[8fxݝXvi*;PHYi<1Aa7^ X2`;.Q-CjVSqHG8đNaLA2VX$~v@ PpQ n!Bcccm` 9%Cn* 9<uX⼩B/zy`:ⰸ#p` F}PckppKmW[Z8E-yz[V;y`:N Ñg{FX~tχ_\jz+6N **l msxN4*x+HYs/BLt+סf JH nRړ(a93L͠_,E"2p99sRrakJKaU, P*#hEG8BxPTSFcf`5ZE "(epx<x%pӔnLAQpL\Yc aPI4bJa]nvPijta mJ՟f,6UOa|TCMs˨B5<'qn9\S C<7y`m9PNY~Zf<X~3p"0@ ; -D^G(\GgŹ,tT.4flP(ogʆl8t&>bYƴ+!0w}slT=IRq-1S)=n=av_ٕ.z0p,6ƫ;z:8 xvwbՋ0$Ͽfz}Ϯ96mWx2^z3y~W<0{vs`v[ p-s.u - gvb7p8^Ͳ!`ߘ4pjoINZ:<4a֭V#4 mzc,wﴑ:tn56|$H4眃m "`٧A [pGX*Â!C=~ ŠA>a{9r>TvJ0.6kh!R1_kmGG0>07} p孵 ]uI ǝGc Ӹl%YhfUH(6fP[ageAU7,o$rYš vՔ Dc C7\@+*8#7 7 ,pON!HCH2 bI9&M {0X' _o[9z4+~ZY̶6,t4*4Abd||6; b݇M}! \? n@;孽e[fdrX9(Wlsp2^o{Cm^:'Y:PZßxlSZR oDE#)\-"by(lл8 [_:K'91󥭏~#| ,%}gޭތEkb\\8}Ī\E1el JbP?w }sb̨0KL/A&Qa qfw+@U7bf o&!Dn W\GHpsѧ{>n-aGD_;Q3P|AxS$4[~/`LMStUo-WҮvdyU*, gA0zA*1 B!m3x\zSA>O -:HEZcf9PZ6G` W:[F#ph8|5 ㄧѮ'Ǭ7)KYǙ\n5 ^ 4S91\\a9&![x,QT^HRy`2hW5 ʠ%&|7Azۘk& ¯Sb,C^a_#+JcTD7m7t]cq|>Pxw0_!0sxNaF!3쾉m Q̭+ɖ[NN4[]9uj!w.=0QX۟r>bzJFi  /a^Dc(_kÔdݷM0^!?)+0?pjadj!l wB=|w Weވb׮qp,%ZX*!AZcvѽX`܈;{eFp#QP$eOC^;nc͚ܶUv:sP3L.<^2l̺%v@ۉI嬡 X5 kC6!(;~H z:b\rᴠUkAXfO;6dl0/T|N^ +lnFE O>J}3q.aUUp W9<'qhX-(sU2˖!‚_ltr;8 ![87SMHͻݺNzs]uTs_{bŁ 1p>2AetJ/C?2p 9ZPL98<՞qcހJ@y*|S}=,LN^_ە/F]'Թ~DʢakaHZP6 `!ۘ `^*cWG?Is8vUzp3\hjH"m2}3-oX5f66%m^o[>?4 Gt]:;1l1&A\p03mSF8\_m pe j}iyhxOiWUƥ)o n:0oNnV#ʺϛ>RcV 2Z'}v 59ExN/{W:;E1 e}FTi煍588ĝcc:s}E͝mw??aoYv4*(f U9ptc.jB8(Jy L08@-rPHEg𘂦jX+|/ZLiF@wn*<䛝7E,-^J"uDQ]V^d[V)\EL;_՝SЀ'IVrk]ep>\~S3E\a(èʠ{;88La܃V$C02EPǹǦeV rf>="Z.dVvz@ OTr|t;L ŧ`+{JAiN ۶uhOR5HC{ 6H#%7Ei^Hlcl }BDS!A@5_f _;&79XDR[X 0&1 Qm @kE(-I<ƈD։ǮyQkKy^>7C` }o 3ʃÅ[a`S~]6晠zky`Fw0f=CqSѭI u'{¯-)Bcqx܃v`x.n[8sqBKX,00=O LA3 p5-\ 9 _һwR,|3%Yf/kj辻`.-©YP Fbl3 "pf|ɡB A|=Ud"pszQ㾇'50{B`&ͩ* qQTv3 [C9"5KA h%DR)\I1x|樕Wua$LC;IQᶠ C/߬{{`ܢs("*g ks8L̵43;b2jL-LOTT:-Ӄ~p8k ḿ /p ) 8',Wuzc6ǴJlAnLjt/.E,ہzqv!mk8gpl9MS2aƇ ܫ~G e3p"L:,Vd2}9h^?w9|p]^[av(ٵ)r! X20By8XV"BܕIF *q>ѥc/;3oyo5)+ e aѦREf3T ?o%& pLXzH ,_,Tp WY 3d aZ/}5?LkspJFz{st E7]Qh5<u!"$ū|.w/vq]Y#`կ" q?߸;L`t]aK9s1{:R2!Ss6bXx"c`8!- Oe1o1e eJl-D&q.O}ӞajGAq,P7xa `QAX9TRR pxo=2XWf+Ęw$D2ysmRoBJjmeKz  (Xv΁A#́Ε-Ý-[ 9Ӯ`˹V9٭rG(b-:\5`<.bil.1]8 hQB'{Sw͑i\hS76&o& ]x.\[ %B} # 7LyVN}mb3U04P _RTIՖ P4n`J] ngk 0w}pp29oI\Fj((Pb;88Le9䮒גAp[p;rj6̴h ʅwŚ.e.:YJ0)Ffs,x1n.C6 9<b{'@G'foD[wd\r'0"1Rl8{ދc"yCIq_)ﳼwL2.io@qm`nX vq!`0 M6 [FSeSHI1xN8쒪J*8=݁M;qr8`zAѽ3p"t Ly4 Dx9ӭHT 1}oY$boE_0}K/aS 9lzs``ۭ2+0"f #>!B$6e+d1 CûH]2K^)`do+n)%H=8e=ΡoAh^1p 9<0ޏi:ޅnʟ&+YFFx XL,3'WUDQnu/pL'st !In"(epxCe[{"ϋCökUR*7X~k̥'v ,sD@X堃SP]ު<=0LPXa.K!:* }Qlc2knU Q9ל,#띹?k8:0mPGPpjLSxuq荧Ap Z r~ch٘ B^S4f/y+c嶃óyYX9 l-[&9S9ëxr/=0nx?o(/x!CQ-Acb/Xٚ 9$Meۆ_o^jSX*P Zo k'F 88奈ƵLKybPq ".uúbs Q!Kρi*X{ ,7Uk8v[Eύ' ڕхHɦW7G}ߵ2y1{cl#AP᡿_n=wlrzg9}0{>bs]`)|s`g-p-µtym=xqśRm R̥!Wv'{:S),r+m ;g6 [R N*:$4YTI5r3eP}ĠBS2BTUqP>(zes6N`jCcѼhsxp=1m5CPs#AwI>F7V8[5lY2+/̓"<8]F)(HP,rlޞG *5Wt;[[J#n0x sa Z2(="l9sM JFd}kzΉ v|Hq&b:Fax8A7q7Ci NbiV."3 *Gdikr؉bz;0xw͝;y\F?4}ʖA_qy`ffP ,xһMX6uU6)Cv1_j`#!0 )i8 6"'Ag`h0p"0@ >!0)\Gg𜅯PSp"YO;)- 7`CZorQ5 ,SX8f %-ZzV 󭱾 Ω2ϋ_n-G?OL#(1Ϣ"coGSw&y0'yw WOO(/a}WZêI~(}; N1:.cPHIʤe=̓BZ<]={?6ꍛBfLS|~7K;{t́s[FW)\Kdch7/7խU11W$]L ̼F0eNpl_oEP'1M 6ך\̎e H/3|Gg:9$+r{1M9릊[(EN:fc HKnBfЄQ݌ Np~'P%{՝Cb⿋ 7*管A?*y<wƠr0..xj19@-4x_85 "j}Ze*k<0~h{&M|D*W(S[,!!+DR?w }sqg6V:ASǰuoEY~Ѯ@f d<>ІM]9 MQheNT,3Bp-r6x8EA+'@`@yG⡁Sd¹kR(O"F0 m2oIDbZ0ؙ>()M?88LSqe2eSbĹ0'\DM_yc:6۶~A<$[ }N1l3X]~6ƌ9ԛw5.091! /ȗ)gbG:a28 [5bBp83Qa! l']E;)ڻ]?n_SkgSRxL:#لö,nT>"5<3_+ 8O S"7nX'ftz۟j᤺vQE0%VF`v {ƒ]MT@c^tb]# 7 p 3;C`xh )*ǹ渽dq/'YbXB!c GSL]:sr`$"  BDR)A>9 6'mEF>*ygG⥿V'ѧa ȡSd" APBjR[páisSmElAVO0 c_9&+))F/ Ḱ\wWDK p59^RXc7V @ 8ߪk3yƩtUbsp20[a<6B[aLWZ8k8xx431mX>33Y< >(z-nIJ !ox$A0p<[QM3H|Bv슱1Yi(o%ZoPqp܆ c{0Z{Hj%PA!%s|Nu2RTx1ʃirwS"A')`U°CSb,<|uo!)y`҅]fhnPDA9488L Hm%!4A!-s/vw4ETBSYc!ؤ?}2Pr ͵vPI¬ bjB9ϨEE&(a^Q~nN7Ŭp65VY^7k;k2%F?(\9T_k@".g"=q=aۻ,?I46?`M 4 O 6l c Bȳrs33n֖ێQ۾_G?Ihds^H$cZTDhyĄsGў M6z.8C,\ZLxӂ*Nvo=aa!a4#Цn9OS6 Ϩr%w K eŵb0Jk9qY *Xz[H87O1(^DhY- ս!S,J #?Z" <_87*a2 \ƻzˉ-;mVbxr}ѓ,*#$ư@E .aG@W <~Sv?v=\qW%7ܘOk#BDhш&As7V}Qv < 唽vBqц{ n'F>8BHWP`@>i*"T $|uָ>wyz|=)^KnFMr6 bSftCB \0̠77Ztul1sGBIrXkCy<s;7U5涙Q2玹QTbH'Ύ‹g>fLzya,YcGs io{6clTѶ>?]OtH?;*TDU% l=ʂ9J$ONU?^[$GϥE]S+͵-*qΑQB6.e蹕}$xfhCE4m~>Us?%*qq|D.GGфcGy~ڣYsE"{=5%EUK23Q:C8~1&xmΪp+hJz]*Mޭւ%.^ҽg>ҭuv|Al[o;W Nɻ[NhNdr1b*!ڝ{ލYCBs~NU1>>N?Q*axe`y͝U٠5kcLgvU E\l\,TZ1eHFy?ȝz羙A<}µ펱C8Z۝jDB!!gDon kcXD%WYh IOjk-IMX]؎Kh:T{]]1B BŐ0N{u#w-j`SCdsVNo9.%w#{V#\]X.@P)(!*+I 6 ͔((4~sjMJM>Qv $bLi=ANo--=q^l=v;t??U@TM8zGTZy؊(״*=Jl*!6ZU.&icXSkU@T]8!qI-pq[a#vJLfBwj;],@>7c,'$6:a"&94= KQHY-IN:;ڬ3ѓMHUbkt"t ,F 7̌9FzER6ol4>TCBm x|R.*1.76-ZqCj[EͽXisX0ݎmZW,Np"MBm (Y>5hDhy~Kchǒ4rB؍ T1k3]!n/Xcx2잸f)Zc| oa'Sgq>_=NZE%qSS<{X-2G:oQ{xWDۆDϦVt܍`m]]@T]8؋Κxo7{՞ےs$HZ.Z2+V""I=h'YZ)EUh2$? ٫7俽JtGZ 8=FT +P ѽ˖*s[H~Ԡ@Uhs8 8íamyJq/kERL՞o%f\A,qis>Z3!YxEsL@ma?nn|"pD%Lv*c^٬Hzsj Ә甌v{6zP['{.*sKRncxq!\*aG`I^1E9|]ϡ˺KH~\fTh W(n}>6~{ct .:5}S P5Os樐n湶Cƿ]ϭ&`5S?jbmVc*yv#afHU*jO2?tH8O p1iZyuJI>]{+-E K^7 Pޝh,V 1/kK"RohqN(ͬ]ǟNJ/&; ќؔXSᙕ㲺i*m C4 m #<ޣf:d+xgQ̋U%v輣h\s|[OڟC BG0wnTZQk'{My@| aVcc\p|lߪQy2)+ǖYЍ8zV#;L1RMBmq3Y1ں-C8Y?EhKyg7K54F1/dz8#dɝhg=9MGC8~y:}s[Gss$z$Y 죭4|F}HmVr Z=罊i*;bNJT F91zjZyOqRV4$Jlv=ů)N RJgX[Ja{G=V݌V!\~QrQnrU^^5Drhoד}}X9WB8hm-wI_ȩ} n=z0li?1B B .a.mj+;ݚzZOmA{泇yCIyQÚ=ىCBNو1_k%L\zeeY5QQitGOPK&lј,Ȼw*PGU@!aD>vH*Um2 RcǷڔu'a1>#kO !XtDuU!af3UwE29Yb̰X;j\nZ㯣CF)E9{mG!`삗4kFbЊ+՞,\ec λ?Ƃ,j{b,&hruڟE Bː0ΣiwGm6hl$!·hQDu_< *mmC>z]¡6bJjY FEKt^윑z.;z R"ߏwa/EǣmRX#ۛ#XTDIgB$؍Pn#wD-=D3+LSQ+^%xpCZ'JWicx)?!B0ΣML6_46 z4CbW-AسPDPۧ5[ {:B-RupDSz1(K6~' WV+{+)aAt۲A!: 1>?]y]C8$ %jQUo0'l4D ߮,?lSFr*~(,AuvqmҗDgư\@!aOra4&QVK='i*QTmF=di!Ly7-e.ƸLUK0'[z488G%G@b#FomX ) -Uе8ddutU@!`Dg](*ĘG\O^5z$붅 Q;ܵ+ny˘{kxaWG`OS!K&18bpu䣼?Bid Z;쌜=M6qJ"DSCzt8$g#XɪC BcO _ʫ)G"kwv$چ8!|wu6 ?vd);?_6eJ e/eT!ߘ_%j:1t_v\4x=ybH'v)=4m Y iK48_8IĆZ[M(WqTDޒJGw 5h­-> PgYsJ-kK5^WO=,r;D*sTz!.A*յDhy؄hTОܤNͫOpCŲX73&hs8XxۇpwܖI$(>6??UC8?3NV#l[#Sx 9A۱;Q#vei}9_Bot [m3jWQ6⬨q1S(u|9 zFAY =yF"8g4}>ڥGft!A@mk:v~C,ćȩ 5 +gzcJGTלbO;6~&~6(Z" <|z<5Q/)܎מ*y܏>o폅XI?GxxP9Gʟ&}1=B@!aGW(CLW+jX]"(`>akphDS|tK˘@WPT*a%o56o|;SږMv!hIi9R1E .aGLXnMJFk1@ 4W˵M DIFR,v##62eՠ"L*W>?Q9GֺA cDX YTWksV*\ru; >* Z,QO?zGmS j`5S{vfIi,U_AemOSW*YӜocxv;TUc8g}(yezDA%x Ha<iqDK#T$?ڟƈX gѭŗF8k֚W屺7G1(,` ۖm9x}:&{Ԣѡ鬤MS).B{}jocE? \ ]}E91GiM@mT r֝ǔ@YG1{P q^8z.f-A3KݷX{l@\ݯCBmw$\ġLj[4νC!aGc=9]9}mreK& exyj RCۘ}BBm3=]S7??Mi**8n*]Z<2RVr3=P3zN@M ոkۃ(C܏셄hz<2$B|Do'~ bȗ>No=J P:RkrCڧk;Rj%V{KRm q 1Oٕpyj_s9רfGv~2f8; ѶW=hPFam s-{▐M#'1k)+I,^mbbmc"v?m^nu| o~Qv mj_XmcsDqOSԏ剞3g$D;Oe . i&Wc ʪE .aGx4$ocbpVx!M]I 4!uD:ߟ?M¹e‡8mC8Si*.fi=Eo\nbjz0B_'6v׽KK6w:*"T $|ZCTpYjϹ[KElOm]G̠__hg܂kViTBQ>:6d*q g-u/lk_Z[ Y aٱMBm'=ȩ۸KHZӴam?^!\0L"&?Qa>AYf;ܡ\VҼ޶mˎvѾ+Qq~2F种gGyg?z< S{RSQ=\- {g[еS]DaU4-ZylPjӭW5?-z᫥4)fz%Z[^bk•!sMQcNlZ1^!"eH{. :ܔzK"v(gS}ZDjUhm >g*& ;ckGтR%*%U@!@23[CE+@%ʵOJ6}%DODr6 u k[ZyľkKf!K-o8,Cb5E1>Ok8ٌ:$Dۆmg5'%2 }m~~P?= O[ 9no7Ū[&fzc{w Ѷ1>?]O]J(VJI=\pac; ڞ( r⼭?u*IBi=ɞpՕD)>N'kOW3aOpyĞmv"fM(BfRXof=^Yj#X{U>>ΠmM~"BDzʋ'[͔3bRYT%Dt=ZIHư-\@T]8AyVGCI,UZ[;W6=n>~~?J ѱY"R#lPuD9 ƫn[5*G .$Og!IVNjyG1NIhG索U¹;߻aOF%L7ǂgFl˟L=0u PQo9vz5S?.+`i=E.M1*KKU!bH' U'J -Toc+2tt_6g#x]@^,Q?ՙbEUٔ@YdV2=~F={Rg%N/ڔ0Ru>mA޳Ŧ `&_[zϡ^|xjq*U~f#NGV(}h]hmW,SK RT67??BlGW i1(M֓i1Vu)ڲZ+hTmC޳+IN aG7E Bː0ΣV5ȗV6NjyIzZ-ojEN^?mc'g,fH5ϬaO"eHo̯HEl[JBaU(k{\Bb*6uGGB|ޘ4t6 gYU(uAYkz4B'i0ip1: 6*SvUH_sYŻ*2D E"eHӽ<~1 O5j`qNPjh0%Yrm fB1R[alU±Y0zaOUK0#j1'm_-=IxbټcxhC.ږv?,m y<MAwO"YBfuvX~U!bH'UsC%[Rdt7[_)=ۯ])9[O6 ܍aO"[>ީ `ٓke Ue?15uuPut,X&6MVHGδ4bmownDwqM.Aiܓ M:V,t%{d/U{3mZZھQ躌x-wmlIѓjS yC>աZ" ^{G7fy9! C8 d0+embb ?/__pz>??5ad?b+r }~?WFNb۳$> {˫$f^oS P둀d G5Ti]컕iӡFE;o{xTrJP|~_(}kC*#D,+U翳&IXڕ4FOII-T(PSX=Jy`S%*{zTP/W7,lLl~R}4}w`w~[M$A["Ks%5{T*zJ{L('ļɪIOuJSQ{CWѠR#=qk'>r`=ɷR,w7<@s_$hTE-P,i%h7)m]mKݓE8Zcxyg{۽yK)\}%RZku? PEDZFVNym핈)-VT@MVɱMwc+v-@>) KKdȢ+%KFsrfKˋǓ.23-QIo$gK18g̑z=\ %e#l5-um=Ygy\^Ypk e./LKPZpwnoe%x(#TOĩYZKH+%q/I|>2E*;P$:ֲٕqrJ~Q{J˻61j涢2nh{}R 94侶u_c)*J6%t}rӗHЄᱥQa٬%JܱH0'\rJkPVR'-QRWS:_/+g;9')ԧuLWۘYm[(*ZzVJ. 3EeˍuG|CėjVX%vb$KY`Qaޗ< vMB$xICYl,@ 4:Mzג2Y/cF%/"MST)רǼCI5z8Ȯv-gH=*.Ц "'v$gw.k7LCVӬcRȹ@&enu]O(fSD_Q ~fWMQ&cɛ$b;V[s)oV=TZW]S,je^NP%4֨aS.%U%^EOK+ƶҝpu_QϱDI8pBKmbo8e"4ձmfSfqx̵Q 4&aJDE9-Y(#ؗ7Pz{HQ$)"JDݛ~vQ2BKqx}RW(+ʨ!u[7ijߗ;E. uw_V[>jt%56ҢKP2a(qtm)o{}gb2iDy;+,fXVV(N"ј\ۈ!5pD'd}>%[_= eaJS%Rvo#_H~g* LRBT^9.\b2y\qqR/摳-mtL@GL1 m,U~11 uJ< S%P9Cqn l\'}f$Va#!Q 6J5N$:hKCLt4cWi\8wWSXyo϶uO]%o^=,'(vFTSJ\u띻ׁ(-vڸp܌9Izz_Z@ms !BBfJ\ӊ\zz]j:=01z mSX$rQYo#GM"bruQmg)+e jс]R+ԱYO˲Z%l-*Vixq"3ViIr$XU$KOIu:7d{;51?ab(a6M([TB[_e-)5`eOiڌ_i *jF52[֝svY16%/jy^|8uʖlJMG1 ű.=yZsuAP?AP}S}L^&{F)&G%QT v]g@\C[aR;,dGz0E9&$On@Vj9mgXfmomFzuk yŖMDU69++X:k(рnMJ2*z]֣ GSӀ"DOãB.ZC/iK1ۮ[4{DkBT^$V>%j\b+ڷs#FRe&KY^5Ⱥ- J*_5Ub%[˥ O0d}F97ֶe>8_hYQC^J ˔" ă00,8Al.ɦqlĖsTр K{`_XpA0,2oz%%(5Yɿ`^nNk"|(' \)a:`0a^8,+hsnɠna" >;/SS@Ԟ<Q)W(tjB#"!GT/ϥ\"R?:l&XE>^JbB1KQ tD3?j% חSB|p.o ;ݞa3ƜTT " J`ɩ 흚— $AJ"![(Dl-ĀqvOVn\+).j+*g]N ʊ?{nGP*3Gl *mOmCE,|@Z׮tz'^q_%tzz"5ydLfDoo<8MJ2I.%'أ FBzRIBp8p?nT7Q邀bEyڕxbDǾ_fXw"vvSp/( e %/(tx~A/Yw:k^)pFr+CK%:6"К"܄&ӈ*zei%2{1 d)5q|]?-:{[ E&6UHd+d.u+3!Ỳzc#MS(Xh6hh6N+z p#êL+ ,Q-vH3Ql\]X,_~OZ S( ԃ4AY=T2~r'QD CbxQ^ݒԗ#j|V%FaH*3+A4FcpKk88h< eW Ql OP%/!l J#uSp͎Q_z](b""Jl0sԱPkNT"jILH갲Y,w)U@FZWYl# gW5h_AGaFeXR.%unTy^w-ˁ_tDFPfRd{g(% KP{KP#.'~:jV|O0E(()Ŷ :4F+lGK_6_Xn9W QBSd#/_ױV ـF..@/(Gr!uє8k 9ZH'veR\酜,4EaECv0RYFV)U֜$LY^g{߅=K|"(DF<F/-Bxو4{`H\k@l DSQ%!ZMN*VX Y&e@$0,#aQ S*Aď -Y$WR(<1JBBE J,%bԝLG: j19#/q, _Gʈ9H Ndik"D" D/(JCdAœԠ%;! %;ԣ=u;7sJ0Q̞7zizI"6=ɍƐԣ#fzkx/@4ZJZsrlGѳB1A1_J@U^)EZ2t^_ȖZ 0k@Ќ! +>LPL+Cee"z j6ETVذ" A48DM+W`HEct%:ŧEYhg%z6" !C;rfɂW(¼D@伇((BDP4Pi<~ r@2TsAׅ z@QKETmQ;Uϛ7V#X(HdP"AAuY$΁E~!FtCWݳr,6(ʾDZ <͹Q?-ʟ uZL"LD1717,$T+X"  ]ZzQ$iQRIT([zu0R XMu7;,#=Z FҪj^ZQZ@H2gHgڅ%L%VII24LPME[IʲtН7Q(VI?~5*LkYVsYRQKFYqFVC k xVex1$D)E䐠"\U^m 5XW f'GDHѝHE@E!E=P/ !1|9?a,ns*% =}[*aĸl j4=g^= 8Segr=Fi磒=]!"*oVD7ײ$/QQ, QWj;shw((x ʨtQD([b"! Ŏ ?3 |JP+tߴ'G=.&2- ꠾]b4 b$堬tdfMX% % I@ ͊HPG DFAlU#nF9m K"&_Y|CP]By9 J'K:*( Qc %P̬ E" xY) ZJh R[iưJnj/e$g"1%_Zx;==szW@B[_TZ MB:d/${"ÊޤKQ,, @0A3SI|9y:A 2 0PPn,nQzeS$r33V+#CF*26$O?9@{EJp@D(DԂ W:ZD3uO b*|I( 2E0VMֻ̞] DMKQP  "ZQ*xf9(""NE.\$XzyQ01- Yly "KxPQnr o((3/dž7rዟcXבA$J:X"bg&D8Z2"Ȏ$n$j).nL6I/W8_Dtg3(ZQ@PĪ@PĪ@GP"V0" P#k!z\MD1^!zB@1*/#_/F\|_f=# f f=B+{f w¤rE䤤^"X|e<&jMoPhqDYEPEPEA=[V6DjauEmln"V:{d'_&@ٍ) %A= P ]TE'GbU !JD~*&0Qሠh&c< DmEm D"(O /(~!J^LF]w45QC%m B4FT-@,..2A_ NrWyH!xK%JzJ],ȸ,sR_fYt;l FCDcw72dB KO;`{[@6a DW$T:M#j<.eQgPn oj1o,{3&z3rP;("zgagm]m"b3Ƃ$ X&^OKQ (zFYLD%1GHD˚DI2`0ɀE /z" W^Ǽ7n仈"I 8cJİ 2KD.^ "/EK" _ HL&wA( `lFd͎ZA' ~Nn6 H1y1w5A_4HV' s5ӻhiN5 hMo+|\Z;̌<G+DQs7FLajF15YQu`:i+Kx >r~Z WI߻Wa\V+#XcD?t\dxWpKDbD b1bV,DD1DvW 9Ŝ{E{byDS9X+PaL^Aă׭LΫaV$a`18iK_ b1p3ƷQPZN xiQ4Gdfڛ 3Uh0툀Hɓ!HH:͔A]d"c'A,V"YYsiҊ~N0C &F+ё$(RojkUB((pQb"Hk,Q Y K&m A}eBH)U n_)bxZs}UWPd"&TXA+HCP h+U~@aTx$Mƫ6h!iŮڈbi2"^7L+r}ӝy+{R+{`(5JX}b|D)׀ V"SIo$$ 2$ +sرm:5 0!aljB"Q8&RvpJY4 b.`KB!i<0Vv@,a@ T T*^ea !3%0jFcAd)t|YR%`E`Р@b@֌zCVD]D"hemP!Q(F6,ZFV/bDy,]D}i X|-Tz EˋJ'Cw hyv+U빒+?3|&Ђ3 }88҂^CBeQQHkEQBD!'dOWt5MŪJ4(iJPpkOi°b$HA4<0i'Y5< z"ЈbDC!34rFK,~Rk,z~=ynbbDD[Q NvQQ (000&w3SGIq^Qz=-UEd~ɈY#i %%@&@Z"E0!aa񎲸G!#"ĂvJ, u"7)2"I%?QAdPDYjbEG% 1&!ub k3'' Eّ5}eYiY، "  #&5TKbU%ŪJ |_SP2deFDDJ00dQ,dPv (rQleK#(LBЭv]P֎ Z(ft71!sbsbf'w3׽C;DIty%:LbmD%V(RӉ#unidleky(:LQm@lZ#Ďϐ! ;AVh}XRN3HPPErr 19W.w@v@|2D|2DL1=GI`ZfE@C!Oo+oX %"0=쨣|ZytD0DQ$сbD$H8Nt|阉uE'Ȉn#bu6X1j*RSV.@$0,T鐹+9t5"p$L@ȕ^vwYV\7+5Qً`e^#rYY7VS&xԜ 6b{W1UC諵Q E*!U# |De_y%Ci0{RYFjre7Ö>Ev xC1YfOt,ka}C `BMȀ$HQ4#G$5=R KssdDڌ@AK4A6Q^[ $xȢ9B$G~I"~I2GRl,7R\Q?BW(!2 }Du5}{un@98 5Ơ.ف !Sy" (9pFDьt\b2 KI e;r#D dh۠% z%! B*VjB6T$z>1W{Qg(BDK_䕬"EMFeu6!^lb!D=ND81SF\*,(cW+jIb%P/RX@,Mh GѽP-WŸEc5dPcJ/70"qk,;~v!DpNDFGt@$Ho2[Y`1@c4*B&L郣iwtZ;H =DΘ$Eե>~s!%ϰCc zwh`Y}ev6LqI>i-k7Kgv!M/'5wNC)9CQV*J!h@m(?*`hl 1Xq3X b5@%V$3O>2Q,0Q̎@Q`G z ы #BdXSZ a # A r|ymWgdy<; ([U[b|u)?)`#Ւ WvBE%z Eҧi!V}+㱒8 :hQWЎỠ?@ SA^I$& 825S}^KmEEq#(F(Ff(F6J*k((V QHm6lao3Eobn!P/LF z*ESVl2b6",Fb6"%A^`+~Ŋ7P7qb o$khIgL@aɵ6$ru!ѽj$Z[chX[ĒĬ-W#ԂJcF] ! ! EF"Izt](5@bY(D}E}5F" } }pDBV5!"#"QQ$0BaVb^-"EIAeG~cA,gQ,䛠H Ap|e-GX9]l ~"( k" kBo@ ~Od@`pP{-`i "^bb~\DV0i7K$g1w-lW.bz41jZXrE]QYbLkRYLIɈaN".#j̕]X..m\1A# "E+qMWᯠ&ٵ$?m@-'XZbaWq5sV(@l"G-ºD/V j2"I~?ǶN (ug8h3 jhX&rD}˻A+0g쉈y,䀢魈"\]EƜj?׈c' =h~ W L:k\ U(Jx($#CA3CQ;z^z+[yDpHhߞZ[}C+6dr'w8DI(ԎNd@$"`ȹ9kVw&Z2KŴg%Wͭ9Souztv\ H9`XkDPr V"3ڒmKRghD bt0,E:; FO^/'A,Îb:DP2&5jaV?QԻ.޵eu(#_ "AABL$] EDY̆$ Q, ׫'Q#[RbDF!Ac!B ~v+~WZ( gjsxO"o[DH,vB 1tЯ|bMbdDRQZAZyV(ی4J_ ND&': dT% 3~ZS5"MfҥP\1m9`J]bZ@QS-vܳ"Ķ~@1/.m&AAȝ R2'` d1ҝ8E"4tM s'ٟ%UAItB^r" [" =w~G'_K@YMf%&1>J"3Tb<`An GŢ D!|ڊe6ZvxQ; JA+-_ق %d$"  -Er#gmP6(vM &P-M}^AX06@S p@4i]g"dNEb!⹉( !0&dDx 8^5=Lm.=ɑL~BPB=ZŌX"AEDK5Y eu"5K[b+#"'AjE\wb޹ j q"P!vEAeAY(v@QNԋpڌUCH<,*%Be%]4܃Y$Gd4D{}5.,⽟Jd*% k~9闳,V{'2w֯jޞ3Fm cE=R+HCP,VԕQs)\b]" 괄(V"6@xx2 3-Ҁ,P3OI!RF#X%*mvׂf$3mSJ!w(BMQdJzISvNW#yy򀢼򀢜" X@ZPXOYͺ9C xr4.mje"y#H7"T/lt)J@} Ar0c#hx@#_7UXX! ~8"6g< b< < (k JXmHQDܣ&nv CYH;u~Pu(`7nt4m^ Qc"Ū ]iJ6?]otymA% kqf{ڶaբ9+C+# B(FPOd!A=倄~̅.2-25&9P,UHdDrGjGr*1/D^DS4mJd@rFԢYk^GDQNh@QNa6(VdQ/=`w(V-Q$jʣ,Ve18`k9P\dKD-,H=L r<ݞH JS7qH#jBE,&ғu;Z!gY9Z!g`P\E3⊍ vwDAAcKCҖZ{6p)>ĆxDjp$f@a p$%aT{l |13PSr9 )l ZP–ӲC=uQrTKR(@I VG]yۚ@T tEۈ"UtzAA6A6A#bf Y[i˾[7Qux 8 Ru݃ "eIP[aBF (XEPӉ BkE$ ĝKIyDFoa7J"(nE2ESB{\=Of~H>7E7h>Aw87Y+6"tjJ( *+?&a v:aGV &oA(}ExU,E b!adf($Bf Ffe+QSyQ'Pͩ+Y'5ԜZZL](NQ(FQ(FQz1 =Tn#qdOD.?WKjnpo+hQ4Y"dD.(6hg@Q3P,4bfiDuD!Aj] "d "NI|' w֣$t#}az1p&+}6ssss(sXfʤ(J;Qe2"P21PgtX-ZfY5VI5iBS@l7HxŲQEPby zjYkFD]*!߱Dv֩d0`Krj(zt>kDA 5 | b4dp OE6iQ$]"ÈbGr2 9lYn43_F/1CخJQP㉔`Ϥ((; /6?Y9jεFˣ&(,DP= ROE߿> ~?R_] ~িaP> ;#OROBO/6=I]xlv  ɂюZ?H=> =4{zj +4hoįc֯S֯S֯t]ZR+~qi3ۃCW*q;FIWet$XD]Zc_"Ϝ\ uz =~=\4}ύxz| =4+kS=peO__z/_E oh xKy S[R[Q[_02ǯSF/哦2_Эak_x"16>z\+}+r+.|s|#-2~)WWIC$W) xE~N#N#N#UOl[?i}tOW詷Wqt_]sN\zGqB ˩Q$y D?(z D?l!\=!~BO|`mUۯ/|MI/|:<~ϒf_S6QH=~U}稞~=~sTR T߹ q۷J=J=H*#vٓლ֓шed+ \_A_$FJ==>zT7U8y#z Wq|ӓ_oTtg) BlAWӲKlkwÃ'_~Jc?'!=H})gɃӞON W\G) T`6A!+7 zd z8z8{0zB{Ϳ՝VGѯSѯݯSуCu|M~? @+@u=JB>-}F3{#z^H=f;rܿzxӴU\gcSa1W꩜AOWlj'`'`kOVB7Y{o[ISS[?:?:fJ=B=Z/?zSJ=)~"8:GqE4eÏSAGW c +ӯ~ ]6%tM~I<`#|;p=yDau< Bzn+u}nl`+?o # bc 2^x9^KA襤_wԽ_~/_c[4W/G߸sAAjYh_'U MgQ/| ~տROh]RO~1 520k6=b =DO~S?BOOB߈࿻AkW AI/ie_Tz =} =Mz1yj1zLWɭjG__կS[?ÿRZ`,ĿNJ2gҷyǡӏәǣt___߿實_'nޯ)=6Rp[?got s#O:|o(+(ER=Ũl,g=0@:0A]-}ב~)Ys0fpEzb po{$TX@Fg-Dnz ѱBNL ]h_wy-\!8C1 7-qM)Hı6E&i8ofX ~ ,NS}+ס26[ Fȧm̜=~#tLyKM[Ґ4l s"7tg pvR vXXmWDx.gZDfpE:F' I58_cNi^KlІ2/5Px9V8\21?PII/ ,/zICҴch`9A^X"}pK|e=eCj'u/^'z.=RcFx+Iڶ IVSpmvcl}p[lk^Go$yF^GVvַ&^M'IC58 LX`,zr^[<D)9㒱4:!N6Fiㇵ#69$Ii s444D 4#Iq(Ѩſqik*-'Go\I?Ȑy䵞Lx&mx Wףca 5F!N<ܩJ:񧨓Ď`6BCCLL|.z}튣16Jт9W0EI={AR']֐4l sVatp߇6V IpGS{s@= \泛 . Iix&.CC{ +%oiCoڂm~hR-cw^F5"Mf,D$e!iڈGMr/ְkxa[é[z_пcT2jjb FiӏĹ,Q8"59ucP*`0QtNH".ρ=GY8[L[D7 ~l ])-,rAX3Xa,K}#"w^"`5B+dj.I;~ KZ>i0Ͱ d;ڈ8K0@_?ka<[31)gDP.5HDž>% DRC0~ NEP'6H {! ;)MT⨸"~7*LV#Q1pNqYFx= iC/OrP24e Ҹj Kp߇~0ֶZvQdڕF: H4oKQaа┝`k FA^H"}`)?m B?񀍁wu)SLB,HF &H ;a ,N[ӗ )JQVژ@-IJF)כ}O~܆ ~ A@SԝKm:<'VU Ui gl>U%}-O \nzͣbrLHuOyHH6cqo|չ<ypȽ\q*4iD77IPqhHhatp|Fq\Q-1܍ :p|PdUi> b4 _2f !$0}r&{ڪҔ~0dz a;]kΎ@de F v#*SMgn~pp r&ɇĻ}KZ~Q뾬ΙDkRHG2IM5R`&bEr pyO&@_>N#Mg۝l%2gLX O(+oB`o%3\_I+XJi$~$ PZz&-(v?Ƭ𗚜 ewȇ"s!p4k4\RCad,HྋJw=}.Nu$gEy4uTOR(n+0I X`nCAݘ pBkjڅOȵI7X|#E?'KdA1y CJZ,ǐ(FryqsǸ \.X"=Yʨ 댨~g}fz1GoCnu|Z}Jsi@_'pAS'nExE<+)$FI"O D51sn}CX"}9\kQQ`?˂Ɨ-_XV!1ay -zs0M" w"e8TvY~[}~흳VЭ?Yʞ47ICҲ|45P;IJ/R"}L6V\ 4 +;3q745D55 gDGHQh@'RNsm Es. "+lbB}\t&.I6ݝy/>/1i/6鐖ᔰRp\G \xH:4̜#z[9gA%LR)%$ٜjPERЄoX31D=%oZcGcG"FW`oa<4-_(z!H` -Lx'/`?3g瑩)(|#NE 6W'YKN\l2qOz`!)=eTLBF補(,L(hR( ѣbHp]QX È8;[5#cF@agy%KNL5q0**5`lÆh‹Hᾏnok"7q 'CNΗ M0I"ۤJj3wdC4EJp߇NTG.lKL<3q'?j^t("ʬMĜT`& @&H_ Rp߅bpjv򧇡 gӅI^ؼ)2<>iHnj'q 2LiSNH".|;PKH8N_"9n[-5; &("ѶNq;& i+Y؞h h&@D>tZܭ;^Z#ZQfsv;Z,Ċ i7%cVp9 :ah]8ۅ+=bRu ptc89x7hMcxϫ<]j>āАtapp 14lxp\NRr;̌t8+@_,FyՎ'4M`98즂bH.,^K}n3-:LFĝAO^̜{]Ƭ5TuLn N4Hd4:%5߆w^ꬿ5H .f; ݵ. '! =KDޤk Xb -cVp߂8T[Q Xx\6 +v I9LK\J is0nh Q_M/,~K} yrGsgq269|j{pE6}hyҡ `PuI,yUe{|GNX)h^cx4n:LVS iC4jEJpPF(8 |cfi,:ק4+YlF&u7'T~g 0``~KDq4$ c̉]j $߯\~߄lAmؖA"j("nnkT4%NusaR1Dm! oXZ} ~;:ڷ.B!L~#htn;xtj6I7\cr0@o5y` ;,7+n,9iQj,1h!Ɛ>-O*EI4M6Ha>^~=Q6T\")ו"^G&+g6e+Z$8庒\,heF&k)BY/D7;g PS#6ur>fcIQ_& i8 '߯%oic_YPUj+s"chRg #&{ou]a(V:& ׬3|QZ1Tc{O+§! v!kL8WY_;q{s. @4嬓4~MV&e5|@z-](<68HQޤ"gv0/"5ѝdI#q.%Kn&FJàNY[, ׿HA^X^Z}s¾M7ѣ`)+`zU"a:^ llL/OT8`iC4^X"%oiC2R]jv6'+K!b$P`floNI"'"4; ~4\D:- M* U*2y@kՕcK9oQҚN 3C^> z?I>Z}~M4hn5R8vi *iu9_ˤ! Nq⫉@4,,Hu}/RB^>zՆ@۲ K2~:hGjÎ-M LzQyjGڡtUĩPz6l /,˷Y;D@[Sq[L43qΪSgci%ʗmT ޯ(aBj' H gj~UDC~W:`tsf~'$v1ŕgMS$/)kH1<8 a %517L1(U?9)$읭&Hɩhp*ZxH<>^~߄_gbџ82rsqNGGG;G[Ҩlq/0l3'@^ jn}%4|c.(9a2GNL 44@j"Ci sVZúc6H_ Kp߇p@-B]&mNNE!rPkM.͂JKIiڈ5,+\m24UOxq 3*N,x> ,Cb_,EiX3s=+,U>IqOra;ò8{DoiHdu8uUu4T z^X^Z}>WnYu8H]̜ݻ1;Zw54z75y 1"a-@xaNX>Z}3PnO3H&R 98 p;j{BFV'C!iC&'"ohQ1LTK ]&n#Ӡ)i579Us94VqI Cz RCcP*|z4WƮP#3@Q&J# N]8MC,QR0h'3}v5ƞ 9!Q vqǞRQaL]/A-|y@A1V']U˰w^S?i%ܷ 77ehG#P?31O|QxP އľLE͈dXxLzTƫG-ay@oS 1@zHl̩/~ݖ&`Ils[" EA:V ror.DQ0*uL+T]x M,?J|LA/%~hPF2m~o\pr*grN#\PrkK4,,HmWzqa D%_Ԩ ^#aξ-2/Vp߅#4D?m4κfa۶!ȢΪ+"Y@]`P N?rMeK9-]zCM_Uc#ig켫MN^mRU "KsX' ߯%w1#;}ƀ0?3GH'G,qk*pt  .JX&'C*p kh47\klGgA([OY rCix&JvD_CJRp߅ﱀFIV3nEBaN`. ÓvUi~/)Ch<ɯsfiL C[xE$̲u+ބ)QV\S P@ 9:dg0Q ͿN6]# 6V5p) i+lơacUwt:aZ a8 $$&cgUNd+P4Ί+MR"EL LuَVoEMֿin[Rdoɉ~៉q*<~()nL[C-|9P3 AӋVpۄcNhwg㋎P3岟6j&PƘxcN)m(H-fZv,pa`qe` h M(}hLx0"Cĉ:Q^{tזּ R!@$-`5ngcy xzKp߄Oo`H+%Ƙx5Zs Ѱq /0&xQҨ] ksav + Rptc{<7#'08ĂkP D{c]ry5lx3R'52-alfu_х@$lBq$x36Ida BI_ø%5qU>"m$hZ/P"#JruNyZ'tY [1uWfqt:ډI Ϥ*Dͩv  KI+mBԈȢcu|0pmgY& M0XCC u 1}r17LĮ[T?߭9퉨oEaVҙi pcD!-#R4MVDŋ06,vN E3Y1 b [s+15֡ [8ű/%6v419RkPf^N;aZ Aqe  Gtl;fg쁱qpj#Ƅ&-̦: 8\?DMb ~ HknRC"NE,1uEsz~R=UsZ`|TcWɩᒭVBBU*=vЫ[G.ugp\a6pgpį_l:{e`\8oDˆFOSx~j)~K} ꙑvH2I2%_ӷiq& c_'yL)d,JC2 F#^X^Km$V,5{ = stF]4$HOH4 9Ӵ~M-x Ҩg~S>Ij=`O@spO\W<:u;+IO)o`zנ> acSFixa[0XS1rsՂx8Wc0X:RMxXMm"LL/,~K}:N!qk FŠ0ǃDSf/ν)0f٤$8xh0MX!N?5 R:Ri KKkc! әŎ:t$ ȃG oAPl|J(מLƔilxO[CT/L&@*y:Mm503h,0 Nd8+Y-A!?̈́ cJJ߯t"%djBYDTSB3sv ;gYr(Hq|ڴ:"䰚3ׯlYLՃVp|Pf@ӌ.+K6!s[xaE=$*t܌\2VGKEkob/b1Ҋx Sp`Њ9'_ϱ$ _ɉ\_8' }.So'9&l&{<D42?(K]/,'L^Q[X)Pʄƻ^rphO[ rK0ΓP}r! VE"QyVpŌRYd!(Wm*cӡysqa4yG~"%jK n*cLN9r ;4b\;ah](PcF`AdO695a(6 OPҴc $I 6O&H NHbxM _0 ֚Lbg̘MW&bd*Nt1l/QӔ'W'&yԿ!i%5,*'0wcKGCV,GcYi442hH0ě]=iikhd-% KOe1|E~3qK Ƥz~>ݺNE!6ڡaݰ T~xa[WKi2_&%@@a\֤,gл@Æʇp߇.$AW w#YƲv/X%+ǜU/NjnÆh/; % S}3"ћ=[`pHUrg7%b9'm-k0{H,7#!U%oicY9XW8<(X슂q YCK19$"W& WO-[k*=l41Oa3b]u¬o:W+.%I"Q1b$Ds)aatP` nxf&Tj|88OX0%%L ;\rX64DFM6HH',`k ;4њIȰ-"X_ʒ&%hCp$ۤ4m`9llD~>Mzvr*2yޢIf8JUOQ-DJ.%+0Nɍ/2 # \]&|@a޺0cj bXxlqlq1M"}M=-_;l5\]isZC_xWF$p8r,9 siC3_D <zaA.B8 .!ƺad,HྋvV |y (SP*v;ަhZ$֕֐tc" ÄAZpXEn2&1WHc F$L!3Kb;xlm#ZԆHi>X.Zmsqn[}د|o؉x+ čh$.n ]c uȧ&#p\X㮁QIwhpg\ڻBۍFD#\,/xciasj\EhLT!|鴖71wBkf6(GBgHg׀G[7椶:p+TRmN2ݎa$ ; Wف@wM'1un˂I`縬T`&t^qF[_5ӺO;G?ᤍʼb+kLZƣ0tblzM* Ҫge~QQ n[pR%wP9JB&vc43D`6ޯ/IE,NxNK )vA9p0PBrǴ`9Q1+0 !yKEl4` paHc70u 5,'/B!R:Z9yד ٌq$N!馱ɉ74T9 ~ /,a/ᾏ9t Nw8gi Kp߇^CDFO đ`g h逯&iUkI`lI(0@]ʂ通 qK؋Y7ŜpG0CҘMkHg Lh Ne5t.@k)bjWGǭtvVӛ8 G9X*A-2@$8$ۤ!|ʚhgqg?H {i }䮀k7 ˀ9YTYȱH]O1LǓAVzd4r+w辏95C3*ԣ!3EB]b.@'DaCI0ܖ FHASM,Rpۂ(Ec0Jf O-RmoLEUTWIn i+AFdhT2lZ n|ji;i!l9X܌ee$hH.tLg)Yr"ihDdgKiܘA?e KZ; qG%Xm߯b/o+Z?Gv [,=`R>lȚMH eə@^ $Rʄ??!Y1#s( Pð0!%57qjaCs.3gbܯgF.#sijBmkD>)'9S >Ga $z:=[)m{3bz҈Nr ԗ!) eV( IYY wiw>cԨM]U@̌!Ls`AiH:cDH Z#4lZ&\\uc F(h1!'w82MϏ?/7 7*^bj*R"]t-AլZ6F9^-5i{3$Z&k0MYp沆mwH[Іq .H 4n@MZ0 v@BA(9 oc.la* P 0GYXNtߣUUS)!n/ʼn(^hu /$bqII !N`ѧ4Y\e.nY0rhhf&3;gGG2,m+ |ZnNg Xa,NK}sHpF1@^G%`Uj41U9F=QXB4Jà"D;yp;mFN/RB^Z>Lƹu.d9h׈='b mAY;VOljsJT$r!TК2AMrvn!)h"RYWVa̍[H9KYp5*8x /a~xa[p7ۚD/D= h:m=ƨiWI"ICYX`Qi#L~҉Vpŭ  rtP~fፏ#dD)иԐlr !KE,(e_AדأbjⰞ7lcgU)E;̬!iu6~vT]}n 7ړSTGK#j3sT0`BجzeH=IAŐʡ C}X~)a UYY˸ɗs9X98H0z9C q~Edy>Da^j0]AKV& (u/.{@h g$$qb8 z`O&'ФRA4.0!ht"%ww.謿|8íDPS͐4/ %`66sE^aC``‹HᾏGJ^Ә[k=uY.~#1Wk=4P((M=/|2i mXaNe%5>@G&mF<~S>_𶞣ͰTa#,u=8w9OqQ9[G#C,KlXK ʉ$/7c,0_VX ͦڋ#_O!OmҐ^X6vg[R5K&HG#',a'ᶋ2[[t*fL[.t84mL"VtWmMrb@sHȀd5;?"ڝ2эy}.gŸ ԝ(2[6 ڦ0pSnp0ɀpm9/xn|u3>3J0RBqach/%,pɭ!i ΊHZ"aEmKu͙8z$3ԨAqgp֥~m1"skפ]϶OEPxpp{MFׁ$@|q\#زz@^MN-='YT1qP'EuKT0 4]i~>X .<>qDjCi[9UzNNhr\v^L#hy8xI YNfaY IÉ8pi+qH;9lBP4m_XP&\p>tZ-fY+{G9+rA`qPeNJHȤ0s$> >@` h M芎inkg1fQl(j2m=i1uSjHd(N(쥍K/$^J>]WNLNg!33N 8wg,jLZ杨I]S@5 i KIkbC je|gpy n6x>Il+^V`znr7iKEkoB(,glq 4`mAYhE%J7ױܧB(F(<Q:~&`bb_d_6G~&»kQqLW~CH KGmAGW>H?|c[X0G_EZ2DP-7vWӁ6DG,\<-F1g` K &H'WVGdh#j3DT;P0EY>bhJ.= G)څ^>gcOa}Uqr6 URt9] +wގ I#N n(puVBpDm~ҋGynsw7փ/qr@흛ZIw{U$v_RA_bs6(;'߯t /'0 Y񨻊SɩW]d:*ˋi6I`~P@R9XRˣ4`=8vuUJ"&f DVGW g@ܫ f&9:HR!2i0MFpv58l4n4>ӿy+{[X]w;aD84BHP _t T ʜ ұBNX>Z}״#aк%K1 Z_u v Be4*0?)4// 4 b,F,|Dz-]蹌FU_v6)(x({ y{gI%r%.g4 ɹ*pۆi z941_ ґBiqLn= B0w%U& i/^sX3t ҄h mJJ"ݦ."He!68Q_N-sYݎ2I\/­I_ppURԿkNymýЎtO2NDm -7'"lhE0h%o(`0A"9!tRУ :O5@EY5k`t#t8/LZz '9sv5yO {)GVc;%-ۤ!gqrz!mFY^X^Z}ËvC,10/j0F`!HH$Įb\5$](Ai5|}.nM\G^ &h;s]׉84N> $@\du|pVN5RCp@=o[[V- œCaĭmlj[j:$54$ ]~)a/ᾏ9Gpo_K3v> 76E(Ɋ[JJ I+n"TsthʄhT ALKp\bhnrrEs{tl%iwlu'"iA=/;{}7AEX;Bo Cbgf ,#&#rr`'HNJ~̨([ jeN&Hs6^p߅P<.,"1"t$?gCμ G\E1@2.`ח\nbArX :`ˆ莑 H )[&B*b?l +jTxxB@p$98+ތlykX0lF}.tBSLsiQ]fB9QY@rtgڋFB%;wh0 HQ5yK ڡL~H ]Q)8q`SϿ8s 7h>p q Xb0ek0=eOCA?3%m*úС$:Lc"ZJdsj\<>9ɑ{O_ M2$`6PjSuE+ x}Nk}-!x(&"a$ǡyH6}rJj0M p=|sA^X^Z}dkkT7%?=@cho#h,4M_8視l(k`Z '+[3қ(z= "3uCFtnK\Gw[C͓ijK ]mi exa {i }l~ K k-wؐCĹ;k#6n|L@\gHUDmhH65P?kxa[9O")M5a1N !YJlf1IlNih ގaC1Ip߇n'\BcOl~^U٩kZQڰD А4m lN$jj`AGya[?#}$m~oB.5mK5oVxa=tģDa sl` h Mu؝Jj^b*κ F{* sPǟIXI+g>8̪̺ ˧Vp߂1U4vl]jztms.%*C!DPRab[}XHI)B uJi:KLaA4q>kѳvt(ψY[pI#)ۖs~mjɶ}=9gpUX3xĆںSe  K&i iN&H#{"',^K}8˭O'Ǣ$' MtmC-EqB$S@`:Ǣ jdžM eZxwna߁)Q`^ZTBËl'ʂh׊p$ql0f,`ӆ ҸA Kp TF>4)ꟁ]L6V]f~S>t=W`DLDR%ljKMf-q.rjH"`pئ?44f H KKk\9G4EhSLr˿h`藕`8;~v;'kӴw91B~(hlLNͭ%m*beıEQst欄_B[}DV Vt˜%"Z' i8?M Jt KTp߅'X27c(r]4Q4r8jEs\ 5I v69m\kh6 KKkcSp/QU:oۮinUMH >-!qn=5 cuh`N}9|{a[pb?<-h]Ϝ}>xw$_YdHi+ `zHHCԸ Tzsc;-xZsq4|zpwDO((pI:Usi8Ohuw'x["=e XBxg\w5.uSޡ@I`YgiBCT_z m*Qr !R~(Aԟk>C0lA+xD9qﬓjRi s*a4tw/.Z ЭeONh]T.WkM)M4M`9XAm'@}?|e`P"dE@шц'T} Ÿ]*0 Y8{.5,=g Aނ]D ~e zg3sI fDʼn~)mҐtalpvۦ`' ߯>^~߄#GC}o<69;*b *IS`CPtӌC*`yXpz` h]ʺio JW>՜tr@Wx%>}IDG0fSIYP19%RppAQ DJ 7 >(ʼnm8t>3&hҭ8O[Yf-I%oiÕub-mx Cu+dc$6ReL4\0Li K_)+~<>ܧVT'+\2ЯcylߓFa~GbӴT9u=!f' <>?O9.^w%9(+1}~] =@+gG.zhQ&H[>X>Z}F^qɰ1ŝGHbNjq:YNdgvNvKrvU1NI ٶ]s;4~6]4LFC]٢s3MPٻIU)GN{ C 5l Kk*ob5f?a- ø,E ̔ܒ|sh K1&xՉci KX}:|@z-]@ (V.,q]3&u~!4Ma1]ZY>IbE:fh-5p4D2eC4"%oiWo 1 m-i+IpDܛ'&]X`Fk6K-M߿b7.Brp$XX,ߧUƓӖY{ȬqVXAӠa 3032]7Kh6`$iOH5X'-vǑF Q<Qeik$S[O2ߪrfuNɴ̻=j :BgTd) =='I0GZ, 2ߖ_aY4'[¾G/bhjGOܹ%,_vuD;%|''3az^ʲ9*9^ d z!u$}g5*駇lgO`TL LGxZ4D;%|NGbsU,L9'~ ng]%V'/񁸦~FndLђQwcq(K(g㍟ZcɌHOL98;|=69.퟈so"-YEe[fnl U(DS:%|Ye#D$Ƿ]DBs*s~+;c΢ݞ$reIצW6M͏{=l?(zr[|}!)s+Ep}\#uZOt= xkp{Uh\?ίZZ{6Gv{OncxO:Geh$*[zLj?nkxKf=1kmk7^짟ػe7Vy"nu_hIA^v̹GU}~3Jd5loX!~{Hv|d`fG@Z>Q+ ]yV}<ߩJ/(9MU:oxlUټ N,quu_Ү|A_D1RyX>dO/Ag^8?[\#%XNzz-GvejQҲ$|X5P:FjM'kѫMIPE+ɜa d OՎ.O( yoڵ4n*_!a~roL '0aqwJ =ퟬ3=ǙCI ՞'S\XJtd@Q1u)- N ($g?Sf;ic'~HϨ:dw%8c qҷ֮CH{/gv M%s+mX˧ckgw2H=V#Dɫap;W6lWϫy<G ˊfCr܈[;lW`s?K?,s9U'XW!4ٌ2_LY>ýKB4S Ęn[%hI:Y,=1=nNlf,</ײv.g$4 ފ~(n A&m?]hzqs[Tl&MI\b~A7+N;&"jFijnq踻r>hZQKQnSAdg'9Y׾NKsVBvVj]z'"Z{ z, {>*۴(D*Y>,:k_[%S'7ea| MBk7zl c2eIGe,Vь=c$blO ̼DU$k&[kg6=[NJBkEYO,w{KViQҲ$|#[P9{\'gF +Q$ vʰD3Y;={?vts=IX 2bzZLaPtJD})\1ta2 γzb+ùZ204DT]3턅`[@.'cp cG>PM9'6>h+!ciaom/̴ke\aUHD03]y<- wsn% ѴN xZ_cnM[R׃BdDo _M@<4yOHnKVe{l pBIuPΫ醗ClAw4^W0OG\%DjG?';%^c⩷(-K8aޥ'G/X|ӛp$"܋xxS#u~9/uc%tUrC#׏ȴo#~0!ǪI\O"񖰍PƢ,- QZq/ɴm$Lh'̵(DiY>Ǒa#~DOs8UYhw܈vW'L5V'T̿ó$YV7zcܰ=1M1vsa5&jG?Ov.u V.xm?Chzq<+eT47‡|p#XP9"#?ZHCS܅G{nd܃I$XG|2ak4YLx3㢘dGcV^3C}jIx",u~Hh:[Bƒ>TjQҲ$|)EmkO4gۚIG{ccm&a=EiQҲ$| v5 W$n1FʼG#T$D O= ' fִťP,#u_0(4h԰I3(VOJ\p;gx=ז=-EplcM=d0^]D;3hjϕE%xIRdkFEVR;׸F^58nQWk (isRmR$|BMPԙw[#k؜i?Ye)<>`[}t#NE%T;'n!%X9GZ>Ǒs)*#ۑndDfqrY8" 2Ʌft qXY=8>L[fq`[B4S W4Let=Չ"O=鹯Ջ̭햚-¦֮OW&a1SӢeIG'hOETB>8"|Ŋ8Y8Ngk׳\ MB?'S-H*ΣiQ:| Ƹ< 9+M3gM;ǰ5̼loayslg?Ov !?^B4S(HeZd[IGeדm}̉廃S rC!6 n4'sŹ>86D;%|#<>+'fSct :ܤ'G_ vqsЯ njx2EvcI-uQ{ԭC)sEv-;͸=2$Yd s(K%e!4 yՓP9(ʿlv<MRxZӶI:GIJ^5jG?O / s1> thZ>Q] Pmk%jiOz9<(nέ0O a/ռÁs+9wٶ?HT, Mfo*YN6s%u?A{m}y< &aߓ5ϟ[B4S8jpb\5*&~B"$cliߩa籵]n7Ȳ%C$< B"9;UuJ34; ,5;}Ԗ/Sz헓_–#/;7D,GZRBkϭ$`>[BǶ>lӢeIGUHt.j\X#Sɑ[ln:Dͩlj;"֜\ƨ磃h?› TL ADnK[;^'} # 8.wiM9<@QjtH,w1{\jO2;zWKW^YNZF4Do nKLjƸ>ƺ7- N xXdSqy?Yƒp< לjghy>s\̢ۛl<%lmm}D6RB%s/1}qf $qvll:5nu8xT1naި!чԓ6 ؎*VZ>LT sF~f MQ=rcpcA+q5#GnD^|2]%Q5j{Z)qB[(ʽ+9ԫY۷=C#+9}?xZ۝a+n }_ԓ)CRu#m5u?E]l͓nkOcglamigA{_PϾd2h)aP]UPu E^|WVGݣ*p<%~4Dzj{ݜ<Lncv xB")c/壍,լͼ/K.A W]Ө뒵Ї$Z٣ƍؖ9tѮ iŒmҠaIӰLyL̈_#!~,3C3.)?偰!3h=0|).`XJ5%Q:!<9'?KU# 2f7kG$0{'h)vg!iZ{r( [~mqL- QZqEOQ/Ϝp}Q˷KT؈1yAE!J˒9ܛ} ov]("->k9qteP!~G(j""P[cTvw_*QvEw#Ŷ+[lgxΊu&#qh{H?ynv1I)o~rwQ *(%S(ǩ+DF?iɺ4-i78)^!=X"IvQTFcX$$ghUskQwJ3m;_y9-zN/d#aYb4%bFў{?4w8ID;%|Ym*NHJcDI@yD^إ?q(8x vt$NXZ(nCg<pY+Jլ 3k{rxѬ]5ĝf^qK>eqBr)3"\$x˃cdK%8ZV͹Q>C&J~G^gO^RQj='fͧ= lg k?f%vc*;˩Ih"m +pIK#iv- QZq4YlfU~O<r˘8ٵ̭uG.DZdړaO`5磏hGQZqNٮkF$fKp/#?KZ o'Y7IȺVyiQҲ$|HDbXQ5{ٔɒwe:ߖ0;Q+}L^`G=((DiY>$@?H|ճ8IrZ̃k2J2Y"vtQO[IDڻ9o ׯ!ICm%<2O=أa5^6QIh#kI򂔄-A-}o-q^HK\p]YG8dq6 wcs8ԗЅ!G)ēi^GZ>Qq7ͣ] n9s0e-n;h?pfø:oZ;P+2DuIؽJǾzi[GWq IF9Ol Zؐb?vtdLA4~?7?GP wΗA.~{ӛvI՞\glQWۯɞιlRŔP?o?o}DM9HO5aNN&Yv.4g'brN[BkϹr$y:}dۏ١E!J˒GV[WxfmܝP\3Iby4@XIjAW)ȳZSk5 Q*AP-Sl*N~G9Ϭ%6ihƢX/ =% M{.p>NSB%c+ڌAVq>>Ls8 {ϒm48i[ hm`F>:G. uc`ֳZ=ǵ<#F p6kO*,zOOOtyǵ<#& L,@xPR9| iWx #\p~O$*xjtVݳc$Bz6Mn)T&2{ TCa=*[4_O?h??3Yמs Ӻ~-`:N??R?@߳_gߋ@lKLvsl+'ǟPe_3qY1V$L^z@I_7u_0l2Zǿ,ڦ(hb n'4x456%;j( 4=U00Kʥ{l7=͏uM̷vg-N̗l5`Ovm8ub_t2jZReȂкr1""ߛ7e<^i@$cN/iFg6i2vh ~:Bα2N0ܟsn\>RnOV_XkFNet7# Vl}4@xv"`]|#b۝˛v[u 澬7]ݗuhLW[GJɃ`akߴW4Of#-G ;$!i>k>3ǹ~|8au.K1gKfC]?g е,+m{fh&^VΞ\V2cQ8]jB^cҲ\FMk_yhyh;3C=߲lC;4Lh(X_0*eq&S)Q[juj懕Ng+C?v'uq-s8ÿ́h?u%~j?c2mfvxmn}M6QsArwb9M/ 933 1~.ֳ\Ўӯ}ݜ_[Me G-gDLZQ^:0?X%m]zf{y%>e(r 5c˥=~8k۸|s,ײ=+C}ux،Oe{߂Nz{TjeaF꾵ijV/ tv}uqغ?8 {L,nM3sё]n"!.Y6}_Βwf/ 辞IW ftף~u"yxw{\=[Ɗ7|۶$Y| a9S4<:%) y'O~mi@Yj׆4(;^@I%JX4|j s1sP3v͙:((IV+8|DQ/7J5+ҷ/rSơʊMӱ?Fq{=l2`jۿ-%fwGxD _ttov]>,ٛI~ʫԓorI/t ݔv{9n`; hF #vY}֖D['ί2&䡙ju,vGGnpVC8 C^tL;9纚gw-pޘm~~8eE4}YG[9(o?S(:/üGq3⠾hqmaԪ>c.j8BbIGkeyi"S_pD)s2L4ڇoy6t՚"\GУ<3cq&2wű/HT'\e:;h+ 6A6z%# DPvSq؂6ԟ47 8dzT:r8.mɐZj} YkXE N5~ppfǷUs"g gٜI?ǀfB xGCI[N3A?~ۣK26?p˲7?zS*~yn$C Ɋ9x n?m`U 4TTiۮ mVsդ( 훲q^2*N۟(hHkREF&<%VvD5%Yvz(~!]V"n˂8A1n0Qem SFyCiG/wᕒ/bVY+b򮗡j.x9;c_ g3 aYdjrbk&:upy `n :g\p41z-ޙ)keg3h 9BVu+N:?n}"߬s_yveYjD1A%[8=й=EJ# Җ#h<}pC޲^I4 fd|_enK߄Fқqo]Q9k+AKxWeXVY(d& `u+j羲a+Ȃy FJCZL)a#BZLyپ.f,{2{2tH Kw[YZ HIsH~QHzȒg~Â`!^{'X:;--UJ( (TP-)!ڃlYF]߯ݹ{XXE%ގ~CE#.Pq k|b 芦tR=Tq54 P+Lp*ZfY,sm(V=;&a{D%N @i2go Bm%EN/73G NC;LjU$ `BN;dQ %Y14ׄJ ek^JM-B| u "ȧ$(),))\<#Ш,85|Aٷ_F{T)O (FUPO9TXU%It=Qt4*48` Ǔ"|1d+4F+u]Q}եU^7o@RЗ(շW=Dt8SbE~`UDA+1bwb (0* (7d6>YxŬ(ń݉qzu@Ux=`\U"*|`\1qUQ`\!V XDA-vGhE~d7즠M:Vi*eW1T~#AH** 詒T%~60FD<{$!Jjƈ0f?#+Ln~$4:"J3 $IAuS;n7="6Oɱt2*.Y:d~N 9EGםJTIIݽR̈Ȉ_Nj-C$ {b} N@DDN0Duf@ȉhuH@D& ,*iolؾ%/ExG8a I$utz#'g5s我H_0dC"u).t78ҩN@8I_!鿝PvE(]Pʮ(zTz$Nfҵ?B WeoIL< s~QDS A0Y4Ļ (`" f~ell}ZuE3^,,m^aNg xEQL<(a@;hwX X`FE ^bKF|sܜλ^Q퍢2ƈrJDQb< N&(Q5yxnqQ7Dq PolD]wlۇL1jx ]'K4Hi:E`B:ya$3cG<Eq1kbVK"aR5vY2{2^e좮G3lj< @eMc!,#a<>j }p͎@ m'9)PUqRGRk:M2܉|xnq?Z ΘsR}(%d)*q}eV/a;bR_"wKB[]=3T~=>r<&э}{btwSwO7NK3"*,XlSɿLb3>b-vԦ?_s|2$!y A}jz*k|z {\COUC!*'QPYPNAQѥ$$N^% J:YWRȱgIekIQ[)};HztNɽD% 'j^GD?HBGE ^]Q:3Jx'RY;Tt)H,6ݤC$}o<+pE'TEѩRQtT*EyPp^TEJp#+A{8Vˆc%X/HN(KNĨ hAùRe ;e&+q}ɹ+sjh&s/O{-FW=tXKΧ;|Չ:(bWQ mVn[ՙj폏(EP̣^B1=WxPWY=/<S,Ω4{< qMFY5u1,4|{D2ʃЂGYľ;[ߵ=|ČPd0^VC2.gJ}Ì{~vb`b裀HUW ?\xSQPɘPPRz%EAJ2cJCj|9jAfa4C㧺끘.pzIL<[ʂ4]ZPy<ňn~>D yG?PղYBeQxSzWCC!<"`:b>Z#ev;vO޻+̕\_C4_Ad# !+"Ge*!즲VYtvSü+τD,WYc|@A̽EA0I=Rlʢ|o0_GcXoEq! "a})E k/+A0?w4?! ƨ+~oOU"4(2 ( L0D5 4(2 (.^a#K?LYJLƲvF5E(޳^(X EF #fBJ@Q*r^Nn(7Jz(AanQ" t&(Iźdur%ɰt(zRF#̽&u{$ '.^WΡQQic_/ʍ17JEQnʂ(Rȍ v|AR>{u2;jz( ͠(TwINWA74+w՛`-ȱjI CD͊f:>utRRzR ؠU- Ь|؟v {WhWqZrzͮ(jVhۃ(ⅆW-"p$ D 4N׼yy;yAqSz'īwfT.u>ڝ)>"; &U)I@P` IQ=B(&Bߩ("&f)Ҍ`TQK #w;$6aB^V<- Gur%}=z0]TPPP$'G-IvގzGIuZ¾ƼLb>OQmjSx<.hBׯ^4uxYQȄRfR *TNz͑nNۣ`x-:7CF_u<yPig}ӽP_ud C_%~V%#Ys. ' Ra9^>w.( ڒ;*Ȏb[m)@CWmlNiwڞכ+ft`{TaK%;u'[)lM󭴡*<ffQXֺngFn\-8ɾ}ްio,/WIaǣw iX <(]AhRyE&EQ0L_Q0DQRQ䎂yw/bQa!;JE; V U"iو; w"w/ex~(^'w((&MфM tӐE/(̢W<,Lzg,*ޡ;`y%9JYA-MWV ,0@`y& gE}3Ͱfa恾)$ a a^7Cg@g>:0( H-#N{r&;s1DQT0PZ0PZ @P'fOPw2s@~iPV]ֵ y"m}fg&[,S˜~^ܗz},. l,_F%@+Bx'>UkH/z 1ʂ"n>BIdv7ٶqj*z<2Q7nP^#*VyǶ L\ P.C :_/ / _J;$. JG0`FB&~>B&(2UC@N&Tp)GL}ӥWW ֍F (p2H{qEs8-}jb8[0TeYƦ 3YY]j! cүy#e,#}1A/x꿋}!f I-J")GK/C0  ?eI' o/ CE#G0dI@~L{,R]ʓG5d;`}j RM᫆TSX^D:u#*D(P: K'HJΕz+ aIs%M+aT^+G81KuiJEeeEaR\ (8W^PV>iI  +F[ѰC@=h%5a4BQ g/ z9({R(bE1TEA (W>j%~{EP෇D e ALcT@귇ŬN8q=s:=L)UPඇ%n{4| |cS!N4 ]C,j:v>- <Ppks=p?$۵můwrMd<' 4jUҗqqVcetwQN;˱X_Aiロ;<3!Qg76kVƓ%{sْ'k? ҡnc|m,J/ ܍%՛}S95sjɭ_{O-~d)4iG꣆_DS{(c;Ȼ@=8zDziG/oW/( |p(ZtJȣ/W/(KW y^x yEuӔ^zD/1EZ(Q"4Hdaʐ”!Eiʐb(eHQK(H,҉"L,ףE4DM,& "ab(E*TPi)HP~ҏtR!jM,RQXGJ,R%FE=p&w1fpD͊B""NdEC -o@PPb wsMQ>39B]bl,b}e 8hJÌ/qn$ 4ۿ!z]DHqGfYP{8)b-[t^c޲?fW,a?0w9A[A(* jyXuXTK9%;ӌB!zo7IdIQ{x(W=R59Ճ((2EaN'ԗRyXzGxk=|]PP;DAJÇ%ߡ?ƭQDU*v|Z1h~XcDa)v<u)=dK+g(Up0/wʢzt(Q IA牒ᠠ;Dq”BL,-:fIzG(M tf^C>akrx Qv>7#L+?7<@)1_᳇0SVG QAq^a%Bܻ+jR]E|AqA&AA< "{)PyG血ǙzRSTuJ_6OEԓQXOJ z*ʃU EP֊fŴX^TIw 0-j(*񤟬Fehy,,,Sh[i<%cl=z TA#OQ'ĴT6K:ԧ A R$Hi$4@P$T@ 4ǮN W$d_ʿYQu7.AlM]ԋ' XDWYa8/g85\[Gu o.n_tvLoCzfї= NOl-ݬv/OWNg;*jbKy@]T%#( K4B9W>C=1 4SH3Ah`Ե}﹛nY%N#p, Xoy-ȶ]TkZ3{N8g^#>}5e::AVfoy2B6QFtbRʮ/߽-7-|#AMfx$t@潠0^Qy ʼTVju*CJWA^zϖnሂ$~@iz>1/ˁaiAz>*/|X Jχ!vfƾVZn_f~k]g^jmJBA?̩f'Aq~rAd q9;S_p=/c7DAĔ(@Q:g 4]ೆ! z'":/pm NP SYPLg:h~rU`lu&=L('pv&޾yU`ă_2>)~0?'^{AP۽;޺w'[Bo ޺)GH޺( Ao!8ɽ|r/)D3Pν @9+M9҄oe=@\Hޟ# `{A bKV׼A2'X۱iQTQRPuGY<=R<HQES{z 8R{ )hVMհJ{z 8Fw=iFfMQ" w=P끠( SҙW%>H+EăGom}V]>pɫ+r8ݻOu roVI!FJL:8|z ޽vG|OVATANA$/éF&uߤ7yzKaMSo獡W@jo*|DodtV@zN`v9D%Y"ފ-6bUcd& ,A ct[$C񝍭ShiE:4D_ ( yp }Bl]ZtŬEKLT#x/)CEQETQL=Y6ARHB"zE<<ÜjvIP 8a2 ifKa⁨Dd=$Ce |֩ 2v(`Ƈl0DD˩<>Nj?S+,ĊFlO?. ApVAtM. F_tET-04=]%9T骸lDEu2ƯsDRDt& ȹz[: zU|_Um,T1`#WwݭqKW uy@b')I/;8h!q?:<e#G<##|Ep 7ԉ<eJ}ԕ5FIyɚ9>1r^G2ޛU*"5HEQPƘzˢ"#Bt5Zm$24>I$ڻ$>:̸ I;5&(H7( ww:L4zӻ:,%E)5"з{LK"%Ac(gΟ S%,qñ9b?L-Zᄊ8h dE]^e4#@4g:[d|Ҝ*'Oě&H7' 3FFKjŮ-e$пgJTZ'Z_'/7QDa#Sվ.7 (tx<(-i qm~n& *ǻݱi*||c(K\ڶK(އŬѪ UӇ8TXb SFƃ2Fk[!ytӥWY!Wol;2 ,)(,Ifj,\tvXm2_/zVlATAeoG2:u f9+aah'0YP؄> tzI{$w1f :,:_*?()Aa3nw'Q-O5- ׳[ח MgWSA)% DJ1 `OgCAR:tR5HJ0@<$HJT )Q|I{,{IS-O0zCR!HJ%A H>I*NRT*ũJ@*]pG[4>"OE@jO:ID{ɋe]sTULYpY%F{>3 pjjE9 +'cNBu5->VkV[(G}>"0;B.()˓0IPQE!HN=8 EN=8) BEaDDz)Q D/"pQH$(fQ3)tRj&ޡ*tICby)U'}s ,Oֲ<)Xt- OuS@鈢P;=񈢀yD@H= PTE6dE"RRe%)<) D`EY@z / L,"'E퉂Dn!`Bk^d!Iy0(I`m' K(uyw_8B$8!+[\?!^!i[;vUl^\&u Yp:#Z#`SD&n B&_s{1хQ^˦]cknNyYo;40MXU^./Wx9.)]!…o&W{6Wy ; fw˺ hD `F`#[\QW:U1zD" VTB;*c$[(c$Q#% PDD$ba"y'ٛ EoŁfSM$T:ATމ:$1Q=$%$+Mŷ , SD& 3xGTiW( ,R9nAQȂ!EQL)BƐ-!x=0RTwIw}5_H ҉ `ڢD R$8"x H!i@:@$iJ)YH& Q29]Q(p)JJsչCq5 \M:y=YRC4PN(kKygRUu*"? QL JY8y~4fӜ D 7w;u&&@iF;/gq^=I׉|cN(ÝBN0_K}iDe0QQ3teS5SNBTuOќi_ʞ2瑘7oβFz9HΛ OG2/!£ӗu4oJ:֋DNh%fNh| tz4RH$ {g;NpE\PTzCEP)Sj\e\E:TvNwˋčD0ζג(qWh)w]? /k#֨NBt ~gy,g? n18|@qOx+t;/8?O*~?Zkٸq߿6_EyPy\S}zt#ʷ?evDF3DmL{z5~\ .kzpQgʸ?;$WUmg7u}ƻtt9=EGa+2hcS<>')շPXs#Fzl# 7(֌҉ Yp@N\zbDz9OWۊz$C\̂,<%SR`)us['1$ݷԤ=9$OW~_RiOIeSRDx >zu=t]a_m2]ί։%-"X,1%x Oo޹o }E=J4NY</ϫ0d]©^ <=1y>1뺽wbznkxbז+=l)G,;Gw^38?QD0c^w\Tm}-Ğ4vƇsQQ#{-i_67>ľ>>Ԥ"ʢ)JIu\oi;34J>/S V~\w?9d(hdczjҜ:`{L2TSB2TQJQsZrDLaĦLlu.,+@&m2v,K* a~>)SPPiʟ'z u:g1ި$" mLnܯs'&VL<ҋ(D5 Z6a *hKmSPrBh*kP? +-Ym,Q!KdKȖDDW=UFQTOmN[ ٪U~m~ :țhٍuZ7FөaZYx MA) RAAVUDu|3*ٹkDVi-~G}}zeBx/~Q O%$ߡUCI@!HT=aSw';O _ԇJ66[u8Piӆ:f6 ,m¦{6HY{˦1?I)bvuq{Z1DGP|W<+V5 (N%@JtNjJVjOpa3 7kt7|-;ik+G#Z2eaPoiӠ> vgOޭʒ/Cl;|ak{^y!kLyzgqT7y=/o܇y^]lӯyn=nO!\~W4DJNIҀЋw% ~ Dg_Np4{^X9:μmy8pu6(HV]8usP8<1ΔJ);-<x;uptõTjTpUXp%qܛ@?EY@)(e9u?tj}oǣJ )jO}y,Z 쟼.}įWDQl]:4|> I׃'[˔pw_>:l-|AFqڤXfA_=5~&},,{/kkT+sݎzx[ >wџ-z^+ 5"[(\#{os^S0 S뗆 ߂)(v) B SQ"l**Mnl 2|lZmI *%N̥E"Q`Sܴ%|!H*KKD.%x K4|`xp/av9 kn) dODN0;x4 k\N-~>`*궷:>uSxPj*kO_?PO SQo/KC(1?EDž6l tLx=d^^ *+G6XOjg^|RX,7^ޖ- r  jAĬ[}mǯm]k;`Eor95Bu^9}{TO/OznLX7̀?UovF}PNR&!yT}Z7Gi^ߣ73`Ս-?>1'VŅ2 7m%Fgij԰iNLSЩʑJz'1\}0afP`cMS_"к%4R/eũRS%mT%R@$'PH*]($V|$5S܁aoB+ W9Є\GXBgIBGhEh$! V̇.$8Dz|y؜1 ;LǁfI""rD#-;TyAb J jmh@q)?=s[E+ 2Pm T90jzCZ$ҪY&e=? R{ M?RϏ*G%}g@H݄$t謠Gg>uh!P}TqܡG@jZiQIQx]hQ{Z*iYP{l֖h{hl=jKtGctU|Q > dz xؒ?oP r T3 $$Ẽ?D3LMt?2JzDsdyMd?$7KZz^d$eyu8QƟ)#œDw~HY?O`hCn\Vasj#8OWUQVwBP=BP-%t>ZԸuYOF[i0,\RIǝ+ucqVn4}n\й+Toő>WX5wX%i?U0M(DҎLR*)P%^H&- ٤ݾ)^&"3(T|adHLD5!J/5|\kD7 ve"J/ dqqgzp/ 8j#rXZߖ~_yo~|<,)+p=. ʋ)?(dYilO竏|>qfo5GP#j}'6ҜM_/-x9YNY`m M1)>d%irϬD Z`,7_@\gV HA8FaI8(~)L0ȣ89R! QFpCaALXsed*O3ʥOE)(>ҧ(ҧҧQXTTj5uD5UyDRS@,},}ʫSҧ&آbQSWW:׈~aD>’PTP,jTQ*P Ux-}3Ӣx,qV_A. YV/ea pvD#KY%@Gm@h fR tX4%A AeKYu Ҥb1*qVXK/TU(\R KrZnFdKa:Qld-f}_!wRqQxZt KI`;:BRB?P4&}DlVNIP";iAdDO,% E)Q% JjJo2ł% % χaEB8)0jSC(Q&JٕIRmTeF<ʞR~GUfhJZ&m1jLJ(CyCVP$ eVE4 FEid%䵕 TU<Pɞ=`~Bu?,(} [XrV-eauDWѤs~DAZA*C4**X7jUU UP҂oVUW V2V4;MZL')YMM:SS[(9-JR2@PhQ C+Z{;(ӡ=WyJ}bZ}KVŎDuhQGZ kth_Ѿttkiャվc{}MQG yhT]=c(=!=3.r TVk$KSgoccz_uۮnçǀx/쇲(! x>>(ϱ>!ZBDYxsWW41\To}Xo}#ye?(bFwGokYL(JiA1 :*iŠ PW);= w@|A1vuzQ1ODKx<>h44N{oޅ0JжhNt@ȦM(j<,W=-~,;3(N#Kӂ; ӨEidwZ3wZ;V֤V-N;TkVzEjzEkyxEDhQj)+Z JNjSe8X5uf@:XuSmu:$[K%+P_;)=%FWUAꀃX}ORz\6_E A J|VEϪ(T62C9A8>X烵B˫?keje}G$Y`SWR틙 ԺT*Nն(SA{{y< I): Q܊7wiGK;bF0ôq|#+Oz|Aȭ,5Lc=O;#:MZݞ ʐZ|)E Zb" ŪA 7VO'ˇŎ3ko_0Nn:nyy{8z7/سm3w|C+ܰyrY/qX[=y rzt0W]h@zm}mg㔹Ha^p' ?/JzGR~6H/Zw}Gó/ QQ_3M˓>_˃{*99zǼnOCj/kxm^Mxx ^{w~O4tE~/[5pDžy]6euӏLh1#_ A*-È(^ XHvqokS8sJP|a>:>:|XK¥(QBq:|B'oYaP lO#6zNs+ul5J1"Jy@B y8%B.%%3llzrXa5 =f<˟tǰf:omKw5za\_vwG8%+G7D膨OC+'z.rh>0'<=ҪвVOox=nlk Ƿsfq[/̅T7hxYiSzd_~Z Z7vu/u?sbr9sR=naiu;s L:t#Ée:]aԈĞ}ṗxk HZwJU7jnN\J~ .еnUL〻Yk.~]'Ӆឍk_݆0q󪍦6K9&mfx#{N#-E](Ph.( H))yC¤ov@#PJ#P(|TRP|"څv]hGP|!څb@ s7m* "YS&E (ޣޣX=ޣ@(0§TY W|E%^9<%|E)O()TX3suL0 琅8,`7V2w8D!vH['թ^5sZTCNa4# j;CxndEVyo< Ŕ* !R)PIA]^{uü9]Cun$4-rûU@ G8SFЧK1/s)t]xPƯ+^~ IT̅?A3.,36N,잏xy~ :l5ǔXQw{$$v)>fhnmK_)d\9g) Z({|K{$|X,̤Q>RJ')LD?rGJ泋v]yEPLm /KR/QWĪ\μt}&q(m7(#V6-2ܗrzZ=/Z8 뼓%i T=6haT^ٿaڅ,rX`L<1#DRʼnTOtdaq$:Ɔ>m˧%!ZerӄΈ[}$~8pI0g:5(a{|sR(* uڸ^nH%;j7W~"Z%*=G;JOwAE;w\Gx{j<֫YTz+TzEJzt0=`/u+S7O3n6 RNRtRNR%;AFR6|ɭY$-unT)pķ?ڏ[ DZs.'!/JDNX^ ]/fgb(x,] ;u[j/KE^ؿԿ3zg-IK,K;#JTL5Y峂DRe3d<3Μ]ՙ,9;Y:sRt,u,u,J9љ3 2wՙ=汼4nq6ig 'qz6ۙtzm"뾵{ϛPב8qĶGA flSHn 5ʝ>jbZ ,QQ3;G>p|?<=u]O5;}]\{xDqxZ!xTi';[Xr+3y#nSy<&þfm(Ӈ.kӳGd^=kx_B1b !(gzuaꥸ=FLg;~#(Gj;@J5PE A/Hy2 ; BЫT<<(+AT [rWFܶx䀈s~BQi?Ϗ3{?x[?{[;鴵{{w-z^]Q:u߷@$)J$l#E=kDp@V9I`> Ti/E2d}/*hz5,z^WJ $JXm=y @-kUP67kzt)!K3!N\q+hq4;-n;XK{?#/2^Gs{ Sa@<>B&?mmhQ)ZNTKޝ[Y C-ttJG*P8S1WNUpsUj`!rBV| cZ^~!ߐ3#TY`nn u_[m}/sOk x+O溇ʩnQX1')P=%Rʏlڳ] YOzG@<y^&Rr~@J19Z59_59?F`r~Rr~P@*49(%wn_c)9?(&wD%L+/K49{]Hί_ݕ~!+Ji=BNr~Tr~Or~'S|"(IQ,ebDu\̢ 9(@!ؼN%Ww4J;"CU~. O9(j\lZ%צHIZb^m[Wa-57VUdbdBQ|TgLoQ:n틺auWz9+E(w;nuQwQ:q;bQh6b_8NӢiog.d~niqILpBq9GN>uF ו(;0dkBR1=8߸/o5~Ʈ+q$+=|Cm <>c^T)<ث& Oc!ԫ0 #g; Jwȥf)$Ls(L$4:~i ?}^DQ>9ig08V]hG3}e&F;mWb8#HL(Á'>wZkTnśYAN$&tU P]K`$NouM_N~u=/X't+%j}/VLZo!4(H}wSR`@KQ_P];^ʢx#ʗYYeBV)+J^ʢf.J4PLofXL|a}P.y/%L@21貉%__&PL r{_&lwÏt0XVIeWyר r}zr 5L]6bؖy.fq:>ku` 3W{EzNJH3>,Ϸ(G؃ %W-;!K9E!i KdC-dZwv_\/Y,G1?*v/wJ-TW-kh~3zM7lZyC{wuؽؽS=wKؽz*͓)J-foCn-j.vnӂ7-jo,j 5 V(+d{ Tl''lZg@{Bq@<=qmO6F+(9?WO?a:@ q]b, K YO[?>N@շD܌,|<1官\j3 <3(<󫼞E]G3&3v3Z3Ƃ3O3n_KZw>w>-w>| ^l<,`{=9yCF: <\h@ԁ jQYLeڧgl+WÁ߷ҝ/@Iaݎ;P?׾Fzz5/%B k},Q-)䈇m_\ͳJhFSMsS(T NkQ 5jd>@(; H_#Cw\땒HR ꌮ;Ҥs#.0{j1xn]6t~?kmBNRu{p`+"k[hE4F|!Pkn]=D6ތm;HE7K{܌3 paos\F#Oڸ$QpY @mV M\q?ݷ? (;\7f =/urzsWN/p ))0}~sJ4 N ^ nO w7Aý NݏwtطįNlQG,P4 QцW'FK $Ŝ0 0=_pyfӄӄxGV\Oܖ8#tbSfYBhP.:b {X?lEGā .Onpz^.O>qJ:?tR[%.J}R8"#/qQh$.5c=ץC}Q^Ϭ6}\Gdvz*k j+MCӳGtJeZJg|b/~s0zH?OﵵGw\o[pz<|Xmq/܃>>XZk3|$['Ϣ9tF u9/[!jDqzVu n qv΂YT;9\;1(mƝ PsXV BթZRQl:`fwu+\K˿%RƧ!7[VGiQ wԂ9yef G[OLn<Ƴ8pb9UWje: `DQ&EQTz'uM<jA]:4oU(P:ng҈RiQJ#,%(B-OjJ(E,JA@ R,fnUc5s^'Ry?# " 3ujoIVz^"y8Etj,:KSSDq>4썊l{w /{Iq(FXǝwwADe'MӒ%%XM@0"D#kp<׍hGܲX7Zy1Zb&\0xh6}t/fWSTp"]˔]b/b/V h׃(G?2Oׇ"1iQ:lçO^Ny \%5-8F G^ ~wCjQ:\L$w) 5z:A/  Õ%[0" #>I _gz.z PՔ̫F HAwF* z]e#ڣ^Z[%=fڽںx xDb2}d 1iQvFy2Gk,1 u5VtOV &խj#(KTBNkݳp|д]`IKN/;ʨ ^P(IDvo@*JUROE}OTdJ j쀚%BCmoz+P*) ^M[>AAݲsø׳"uC_kߪQDDY3{c."_18_VbcY$p-\ HB{ZSE$ F:0/lRK[;ejHdH F#AӈvNZ5RlWw L/m6 JB:93\F鮆"uЖ">.ӹdBZRSGD~A&h/~qI`(RZM3ꈨR%P%l'FTPj"$@ B-VRQaۇZ*腢Rae&awB?a<$X P"}h^5E2-FH% HW@S}QWH-UmNJx7[UM1+mE"[))U;$^4{)@K 1R4/#U;5ս~ZQ@O)NIAӛFШAy쟹 1P`6 9,9PIZ ^`S^坓^`T 0jTBF2 c2q=W JEZ;.[֓h=h vPZ6óV!sJ̝~ew2dadi6$Q|xZ%l'NyS/͉VvE]Qje{+{I=l}~Q-JR <(5 ᬢ<(4+J0A1RQ΃ZojwhΣA~#ۯ2V^&u(R Q('9ɇ}Q'8{-^ەt:|8P.6T7: [:B>@/Ju@ʫ(DuVäևPPi>:| :||"B>Q)PbYo,&XtLr}oř s f'TCS8A),Q_TIBY?Ϯ`n2)J~B(ER((P}Q`}P?@DL"R 05lY67ඳ!L%e>쀞!+9E$,,AW"X c H{5綜6=բ}?m(8Cu~gvߌ:zD95=uӭF4E3Oib?Y:7vz%A9^m{2Px}Qè,04C\iOPj9nIK@4p_^(GCyGCVܿǵ(p4{-q4w~tGzQU/[xuz~%5{~O8yFF}"uΊZG^z|֫J |o {gD/{jTlaPdWxrVf׈Ox_+k[[#2 g~C9ߟj}ǏM:q[//ƪp:8?|~i]wOp~~[>4_ aԯ1k mrwOpNR#skazZܪ3a==u}SzʿETQJ*JISE)(0&TR`0!K9L 9LXo" B&Jrjǭz'>TTYa<"k"9L=rT?߷=^to+XJȿ!e ߷mh\(nsUWOz즍rN" DӞq|E!a($Ҡ//}YbH7!ʐ)CjA} xSϜYb5jZXM`5g/N֢D Q`"!D HUeSw*R@Eg|yPzzf*ҢDE &ڇtBE)BE)Y(+K!JF1"@?l\j@?D(az! ~j 7 6Џ_-O&_P~jv15GaFq:E)s@Ԡ9_wRP UFyFe2P1rK9brKaѦBTxiW٘'A^8xW-zBU/ ֨zlX28. KiPi5$"Ymƴ'u UIYɀ,Ⴥ!Kk`C ʪ^-5^<ȷf ;zde7QIY<1ṞOz}bO?N_:-K{nǿEr}@ʭM)q~jYPӖ9{z7_%׿Vmэn+2 R=@4 2+( HR!Y w4!P Is RM <{*AOKS $hHE~.N7K7Ly 󗸛OfCR{9=Ff_%8LU#@$5_KU#|B̈́LTgAU {wz΍6ٝ!Z(fLUOzizORS>T SAəLJݦΧgrj@,UC5 V'BRTTfnxջ5:K>)TJl Қ+Hj j7z7ف$yv Ƴ7pb…!L{Қa ըZPc>MŬ%.IkX6YZ~Żbe2D/hQwB/(>nt%C!}mb ]t)*7]bzyhAj Qo}ʣyhe)VODТ)bTR1*1* sjbLTS@j je@#X.Y0|x9Jc M@8,14UlҼD:om֧u@=؜ ?Xm,ӗ[qn,Q`ŠsQ8G q6kPP8@ %1B{t/8  =9`zERQ0xf\ר$~fRx񐕦i~N F68oW3۝5YeZ+8nTo?xGekmvߞ1E+.0ӗ 78)bd@ȕQ~?m 6*sxӯ/vG:o\f ^Zqkt_kc?h^o- ;>GFY|8uz5I3'pggm;z EYꨬV@9 AR{\ň'G($ꎻԤRQhN 40*XNn@`C` F(&dt@NI ,QFQLc 5sOԠ_{Lj٤"3]ERSĞ""EGY c;YL$é,Dbquo=VéH@#H$H$H0!2\Ab%~Rk%; Ғ2<$!!%9C*GӞSېLJ*Qq7 AsG QE-m`-8F|(V(m{ݶ0<ܶ0! ]X \ϘD8wa8w1"q%g+sQ?WYŀBX)+V6C٢juϤ?NTD*?󔟲8*b6@`*JLA1OYs,^P~h?r3|q CIߨ)'d5bbSPJu HIL)fPjSPJbҚoSғN׵ZLb9x|yXr~{]k_N.C|.d:->qF;kH"h$詒DPBiA")hh3hP)N\7Iih}Gk(l9(Jj1($> $|B>v9cM徜JS1Xu0ͅNmL9E>ҡZ̢D\U*s?Q%EuIAb4~0)+\ҐUh,0Ec~@ YrY4Fz瞢Ni"A= pjcuWjlTO`67|0U dfZ s_ArxgU*kPIvF ~nӀ5Nu@z `KxC# ЂQPIsuUAu@>ګ\m~sgI-Y_J=3sV[+OuPX}3}o]=P/JтT+[1/Y(ZvD- c@cRv @mFFiGD֟Ƕ(-2<@_#6Y((Y1-׈"~moTo I%[T ^9BR@7gR(-1W.TʕNwΤueRQt.?<ҡ Y?V@O QS{dNb8 NSXii [g܎3p3vO-7)Z/NӮ2n.{Ҿ؊ z_.J7 Nfp2cտg7V)NeZөyzN. SP:$! Ԫ=R&5ZneU^R( R'|Λu?R Sͥ SQjˆ EUG랹Z a@t$(`e=r 6Vz%VX 2a{j   |ujˇz oIjM1&L|Ƌ:T'Y{B~-躽Oo"P4KY׈F mn~߲-*yi*y*yjluz#o]\K/^X_*{ Zz{ǫ `gպ|2nn~[raz_ZحSŽC+jB^Zq/YeZ=!%Z&5 PՔ`or(fؘ()JD| =j |D:T%~{4-G0h9rD5}TjM$E96=#Dk"9 Is=G`-` ؘ5n[|T KaiG,D^% ~޷_/dIja$˳'^&$'RV &w0;%zQLt)Bk-ePR4rH'jvZDN^[3PJmg̀w9X·ID[ht5sBUofnQ?ë`۞!v|ӿ ;@=N-1uG}ts[Sx:=5@?ɋg`Li'n4'KMPbcIyz)n7 u_*/*U)@>%/gDד> ZkiQrB^s,>;__KC1 ~_5^qޒߛLejo\F-eIzрT.ZI-|vU4vPMu2Q}\DRӀDWzP"Z*DkmgEF?)4h3$]Dx)dsF6oF.(eDG!xEŧ * xH"vEF;)_JZ^vQvPvV|OwVdx1%( :=b&Qr~IWCO;16r! 9|- B>+p%PCv;[(c(J>T:m-wC_ve:lj|_k# {gc~?ݐ@=6(RO˗|!jNrJ%owBO#~}^k:iz_$$Uj.)3ܶk- ^Ji)ܐB >a-1lFl뵅BM~ k?C(- B>E[B$NuK]~#)ea V|z:yX;%*yyX5O.ȸ\Ve)H)LCFXr=d>I5\"1T 'yϔT^FmkFzdttYƈ[$$RylM :6H,$/I{tF&jsv^ @2dq%w꧃OonXRodI+RkY^7W&mPj?!ȕ$Yk:~YOol||A`:L4(ӋRo=BovLjCV = yw| jߩVBę (EK X 1^Q߃~'3j"z"c@iB4=B1*KJnŢTMXEX1AcpCcKc3)u>3; f-SqПWjZXMi@"iҐRH(lB(~;ӏE)%֑:JSt{^J,HD5R&r  6Ngs=xNhmzcҜ`iHMa0B+ʮ Pa0JBVgdQd~J3A9(2?Wy0?$j']ϑEgΝq:gDq:w@q:W8kp:צ-(1?w=\yeq@%%g0?w<0?)s1?w@1?wՈCϵ++*ߢ]ތz{4T(u+JNJBN~yE)TGW=] j?>>iD;@B;ntr̍9>w>GG1?}&M)o*JzE!UbQA)JjDj!(ER?d5oA`D"ݑT7u $$HI((%z@ 4d!K4_ cׂQB zXbQ9F, V-ÉOj.^|RTQmNWUIhN*eVKVkZM*N4 퇢n ywiwMv*/]wZ.5Pr5[JzX^9sjd Jzos-hg/ՙZNˢpZϖIY(K!JgjQ:SaPm4"Tشg*ę qZ֦h$qAVK%@à(0*AZbH,X818T pZrM'6cFm/$O9 js(o Ā:U~P9,%z*|!ݢtrzZ6cDW7|#a/;"؝!K A5Q,TXenQqTHҧsb3rZ8*1?8޸rağb5' YHRCM=Yz E%HUgt j|/U,_^UjFCJj@%k((z5%dj@ ^'%L`Ŵ֊kr`}cW֊S2ZA8-9ZqZZ+2*|\˨xtݩi\oY(u Jm+ E R厧˕u~V^eN&txpvN'<,u; N;<Y<'AiyFg mS0h6(iӎ(PmLUj2׫# METjy3-?(SA fG}a%,,J)S@!J;ecW]uݎg#hC}Y(]'zzlT#7֔L|/ n cu KJ5#nW=>sL. ܎L#怍q{> [iʏEsYѯ3|ݳM?wX̷OB6?ږnfq{=Ik[]?Esw.p/aЧOQV0¬4-9Uk NLN FvAnofQl>WCIˋ_z}oj#6EQʑt>__~ #mvw]dWIdEuRH IKP쪼:UV259:H뎻bOR)nNIxoa[Y0!+\xQٖ$o[a,:P:+/ Qڲ|]G][q7lz)4yEq\.u׮` Hvsm3n(_QKDh'+Ϯsr-vގ?%Xpel -^A`k;~ܶ*ǎ=R.˛gP-\4(O;uؼ_:.4Ҷ~5խbI/^ck ]PuFZYp0D5Zt?,OTu_d WEvR }I⥲RYYTfe#nzr)VYV=c+渡^E@(E8,3%P)6Ո:Nq[*Y0_[m_#oG3,Myhc pp4c:ZIQ@VOyvy(m8zuZmpw "^2MpA`*-(LQgg$КTKU:WF*HIPHء@@%+@ կ+3T0`zJ`h -ՏuTu'v %T?PZM?9{ p$ 0F_|͓NHA  >SjQ@- T@V@:=ιrx%J@4#^ԋަpyJ}́Md6ߏaR Q#4{_(Q*LB#GH#?^OEXT(S=a~J?[gbQ֦x<׶d]< K$R&R!$3EMneױ5ZY>1–l~,;AA0ugƑ)(p =VG$KV;=NO ʛާ/!*JC?STRԟI>Lի$v95f"wryDvϿ:T:,nYf*>/6OGXzЕb# P;x~D Yj֌Y3&͚cTIWІkV(#5ˆgKwVN}5_PGfxN>'zD[RhKB}@"y(3UHD0ÒR| b&"( }(+LT#X %BT#E^AjG؛`6Ç~xas}RO ^G/(W1":^hoCţeQ̓,=U?Xb|PNą%k#3ʍDJF|^HVD%kdml×VjVJ5n-!pS3>GƵVxeb8Zh% BOtޞc<-KZʙ/.dū0,L'ѢIv@'Q|?{Z8ץr@tR_w7ru܎R7o9OvX~&oKG#Ql#)^]lo+Nt Rb׻B(MUZ4hTC(^Urs\^j!S BFl_FE>QԂh0^ףiIX69@FDjxdNAAV[G$,|H'$,IXI3٣yHGCÐJB7Ja)饱KR`4FRn iQ}:-G2M< 9LM(F͗D<IiDDͥdn(%53P'6NԤm`j,2g3=PGIVQE!Q45G4Z>k#qY4qLոB; :Pj-"Y! c4uv෺e!s!Y==XkY5mʆ/6"}rg P͕ח\yh߭QoB|_O5k*bJ5ǐ= 7( ZQTIITtVb/U%O :BNW(t*J7RMB_͢DŌUl(۴| ><\XŶz Qk&Zh)MA2k{XދbhPJ iUKi3c_b.ig\ҠKrIb.iP%KZY%^%(4V"kQL%Rۼ8ݶ;y?UVj> )&UjjB "N5H8$ev7X>Y*^*/J5ўEEsTjBJb)}PBakVrz|髻 RE}RI՚kTTMUV/7m]}Q*^SJ'PU!U`>P #P ]BR.!AD5+Kui$A|B#%N94)@ >")d auǟQ,B^2w|$!Ku&4V|rx0I``)OSڧO.K~QSV7Wrq WnxM?( ֲp 5LQqkFaA^/pǃ9ǃ:?uc$zyӻ9uRDBj;5wYR8 "; UU *@UQ T@@PTaTQ8U@UQT@@x TSܲ5/UE)E;$A ^!(:`BP@!DS:=o{N+޾)j궿6"Za{G=^Hۂ^Ce ʐ;(%c{__$s+o@Cf7NY0ux{19/WP墣K4MJIFx"^%굵/"^^ %=uO^^7^d՜dA^#AkXDqUj/qiˍWYƫ,pDn.}?>!Ƞ/ zݓR5g[HM(HMHMEԄR~Q3剆1ӱf+DD#:kF1jS3@AγX0k 4E띔ozX,YՍg5ہyVxNaXNPNMjٗ>1 3ҢoU I* Z(+ PP 6~qr<>QThJER(y j/JA)d(CDA)Dߌd0{)^#zV(IQPp.((Ng:m?ڵZO n S( zPu- Qzs3v1?mw(zqRN2=,qxZz}׿vE=k~`Pfuؒ,.!a_U c]v})EV#^b$q1kEa] 2c& @ey=[-CC50b^)zN#Zv ;4N%ayk.𭆼2ڶpgdSl M;I+K|^}G"Ϝ5*9+ "I{dDelRVԨ̇!JC3(>aO:We/Bj,=Vw$B-$m#ZY9mR#&@&)db@MTۻpuJY1+5(fV-e|ӠoM;_Y&Vw%D.?Cy$ 'FI++dT*4S6vR5B7״*ה7Y? ?`ܝ>|ӷ}w;k>w2M2I$x}^ϐ]DJjj1o j<&Dw9.QϟU=Ji'Sԋ_STJ4"zq*\}ԈWa쵞_3e˞q>L\q>kӈxԈy͔-v~ZA(X(̰5tZv|%3{u,r];b?ů-u2珻i;>6(nH3?OJ=x;툹69^EhZ;iTn=z*9wY(Yp<-uC,<ů-]s-L _"ׯ_yش@WQY붅 OoyE3W^wqzHvoi(<3$Gr};ƙdvמt{^I^5_jʋ8偧-d5b"~1өk&utǖ&=@JݯH= } S @$?J"UF I(8"ӭ^v EGIBGEB@%(#rPgPP@PIҵ,CAAa/Zb%߿_ 'r)拏3Ls"6DZ"+{E.;[괥؍D.+@@hT.oe=&祬qm>W B)08dzMj \(FoxHnǥ%=xesS*nJsl)n(eju%#J+tL'Yݟ ݟ`/zK F>O}?ɣ(-}IԿB}_R}PlTR4 R#*FT"6^ě)"(ñAY NOTU9bS! 2 )DF?W1t+%;AiD oJu:o7q5 (=u w_~z-J1* ^WOmisۗ\cہ8H15.Kqxi幈+0ж,A~,5ފa2j'{+Ժny#u^~AzRO4PXl 9[~[\6ODkl|`SЯ?nC#-wMW{iQ%.YvɠKVvɢKvqx^q^ b/Ka0*RL{)^ ^"vgfg+JQ)#. su,H$>EXj쁘b"AvJXa*SNS"(W\F Hb}QZ{ 7CRSIjx_s斂TD@Q!"vHWk R>D[ 9v|OZ.A YjRY8+FUz :Ӥi(I)JM`LeL풂 >mdT\־C h; ړo{8UC:Z= K+H"N G@/Q|F;FOZ4 JzpQɂ*JKDSQת:;U,Bg'X:"v9tQ (lڳ 3>SkgSegSQi0b2>Od'[du΍J_'<:6!2hQ-yT ֚3g? - %@(ޒD#Q@#B`QAytFB4F:Hc5Y"$@HE!IQQ?j,= $оv95@eқ`7]$GA'6I@b7A-A" I&+H0b H TzzD͌RhMR4. iH- ΐ !RRˣ_ }UHtV2@+ڑNn ڠ%B/[2oQoJB=P( ]B9I^.Te ղ}P_ ! !ҫrV}x~?@iZ{-csem]FzQ$_ ['w2>?rdJzͱ\I/^Hp%/EyOap#mrϠR1 ϠG(3w1g,g8\c2 # `DpPVzLpP!sK>.}-${*} 0m@>}}$6?%IA H)W3 #t:y_DQj'W T-z&- H \*9Y]t2ԻTZSZA` !L~H!#: t̪$wq%DPs?O/#dwں!4O7Mp~^:nOSZa[[@_ۛޯ\%n2>%F U{=Z"<p_Jzހ g@E!SX[H_.I+7G}6>&7}F@"5gx=|+p}AqԙMjq6 4ӷާqX&~'ݖT؜GDHD5i+cc[[}G~a/AYA\P[aҔ9IYI X9es$i7 HKJRu–SIQ_6,GzAcGV҅kql^%6/pSć֞dڗ捲JoݤW rnWcNwQ*,tA<3(gV|@dJ/g.._k}e<8P⠯!PkyTzbg|.gAҸCFpy\æ(v1s>sw 3<PQEᲡu/OwQOP=_q}ef5 #-EiGRS#nGш[1x{R!HH*HIE)((Z( Aw%PE 呜T2H="6( BmxӸ}X($F.F,'d&|fRHgRg;#'B9KGט^ęZS18(]A)/Y[ø|PK,@U_׍Ho%y\LJ'a}[}X7%׈:/_>E/C?B(5R *K&ԢRQjM)NsT+PnI%U{Kj;&UZ&ĞIEiRRפRۤʚ9Ddy6W(5N J)+mTQTGU%s{,iddw͒jZ 4?q ]Q"l2b u%:J>D}m9Z?@ j(@%:LuXa}Jq&),(0APAI ‷&OPgs b@O"Dyg/\O@o{dP#+v$-Q"_PH:֣#֜dP 6H vWՠگ K\z}=X;d˫ (1aV:>9wҘEPr{>x޵.çqކ%%AOw rhW["W X>bX=a!~em9!x+A|+Z߿cXH[>3o|Ȗ@ lתЗO@FK) U9pTFuRFhEh(bh(E0"F@!j5*JQQe)jTF jF@5jc!jT3(jELԈSLԨ(EQW5,DR fD`FY'jQo5ˆU@KbK[hObG-n>D%HlLÁK9 P)IjַUR*.mssj4elfR0(dc$5,grN q0w4+k_Er$uk{&,dV 0!+o Ih^/f΅dE]w%NZd_IJA^Zhi;lqZؗ B= mdUSDd˹PI/smQ}_( ZM/Ӄ&]M B\k fʹ|87{Z6ZӇ;D e.p.mZA͌9U_oj`h/BaIBJP` ' Ip_(A$jRQŖ2JJItVAI*oDdL4 UT折ѤEӗph+gL2 n,Oz6}DgO1ɉߞ>Hf:InE=!pH7tǀfun4"n8l8 9f-tǭ#FZ:Ц7Dk>}Dq>"Z֯5~zwXw?Y8yE|)z?_bp#Vfk^k8ߜ:vk}гhbX EHQ)JKAqD7R RQ`\x!.`\*JK`y0.AV K0HI) ,R,baqE' VKNN<8IJ?\&7 m4[b{T}7]>#|=Ni^T:WHAZ YYT>YQYO >B'PY3(듋ON1YE)~ڬςY Y,d}O,>ڬO~(d}o 9 "75 Ӏz:xIz; HJңh r  O;GWZx1)ᑳe#d9榗WrUoV+PjVM2E#KXϋ]xd Do)9"Җ{>vQq =*?tGFWphTGo$8AXk|F> qWR. <ԒMڠ ^G.o ! vݾ&(0s@W#}@זWUS0q NSBJTq+,넊5E`-e\H Z֖ox ./KY_盟kKܾ.NeNP~}UMH/R;82`4v)˧8z#lHQϏnS}lO>>}^&r]B528\w.;s|%:1[0( 2(`ĠPȑ݊bĠI`PTTnםCvz%tOcmH,U,uiAT@T(=R=R@ϻVVsy>vCs涽|}`iIq(ur(uITK1HF R@P㞶=w[)Rv]e!,4,%[nѢ޽(1CV6EJ(4N($h>0*HRz{CߡC)=HYZq{(m9"lK zCypCV[EͩpwY ⱉ4tzXTl"jnOQxb,J=8! =8bЌbNH؜nWKT$VjFl:OZ8+IA1ScA :pI ; jmm= S:Rd&uѨjN:sZppSS \^6](mSl:diӭ,m.dž:'m#2Ph K` ^ٜ9l sEi- nAv¶ caۥVvi$&TJN1{% s^ BScVvT·rӎzzi/qx]|`N@w;D]J^ @HXT>5ŭWskst1MmkS?-b-RQ:{(.JB9JŃlP æ}c(+J'.NEclB9 jbw U.JET(*DReJLPHa*%ReءT6^e@\sTz5eGFrQ^.J0}4G4CV3,Qgxji4J&kfzWJ꒝>ʜbH1E*cAA og3b*~Q׀MƏƯ,\ A1%_RV~Mꮼ.3"3JARz~-|_sUZ)Cv _b}R+gO|J_CS-qdsyd'%(u3B Tٔ:l<Xb2'L[",cmO&w:|6EUf{.y- y"MB΂7 FmmjZo#دh<|1H>}cY5bW_($b/>~RGli#]rmeBmAQ QhsͿE ~Qx [Rc!b(! [ Pݶ0 mama}Fw-huڟ ~;`?"* ҮYݏُ`&MK|nnT)*=1)%RaOC^u#'g#:3gP Q[[e8 q,J$d8 屗$̅$F\v܂V+;\XE,5A)M#"/Sl^1N5ox*vݢ`y(͘cOXf 5͘_ S̮V>j/ n tz핝HɅnD\._z_EXUa8&G3}^9&W}i9>m+.uu]$JIIɕ6Rin)ܦ)' Hr%Ncq5 4G.?2?VjUGPwK["Jn6B$éδ?I@EН$w'$h١ V(мBՂPPBIBi%?HL ~um jOevQP-ZD?9ﴃy}BP:]]wH!R):g?ҜRSPTE17 #7(uZ mPsT2z|m׍-f@_cvQeH*"'(%CZOL); SlSAJ`=m).M/#Y;'sLDs~33J/9FgKԢtO[B/Ei,JeQ-a%nYvˢ[B/얘bwKA}(@uCd b$mXl0rBVGJ:sJN1{eQ+1E '<%=/3`AtMX"SPd},:EBx)i[Pj%DTpIJ{d.)<,NCss? kieLMk/a"SK|NU^|N>TES- '~m ֧N{7T@sq{ߜB~QI#x}×r.޲&H6NHmK#6Jۍlx>ʊ,^s8RMFzaQw6*$B!G]6~^"r=۲j0"I :Vh#~W.rسuv?9_c/QJfē(d;Y'z>OF䅷ݪ&9&yjn(- l@ suJ7#yjp9H(eRKxyw o A2@/'|B _J@`/Yx&is }*ͽ1U2|jE)ꑶ{9^߽ ZNZ5Kcvz3goP`?GC?pC SC1bpn^#bMh~Mw~lʈ )LݶFlבd\Zs__ iPh׺~xa~~//T:-2 F/x<, 姍NdK2 q\uO!Ҕc~XdX-5>5:6a{u.ADX} ύN ;q~O=)J.wSljv l< ?|3>N#F {XI9U e$_g ]/.%RR?ۭ ;8Gy0ao#]:C޴oЧ|/-aBרZfx^ƕx߂Zǖj_g.xڎp\R/zL/ϻMBu}w@_{huo㋗UݶQj[oQm;pftMgޤCR -=l7Ͼoq\r[ֽgi(L{zyn[nKO#iw<8~_?I#A-7!n; )dic.?܏!Pھ!6|Eݿ_~}"Đu=(_*ja7aRnO#6ĵߙgi_Apc;)> U[H6p8vxM[<Vh>a{/Uc<0B7yLo%Rmlge.;"?gɂl-Ưܖbܸ~~P *mtyC'4!c=z=Bv񄳥kRH! ȂJ]Fi-}-g#&F zv-o.=O4 S{qxwV}z%JRHSϲ}STb%˪s%7-={6t}~r=-go&NRsԶ`W()J}EU݁7Ngɤ(u27tG(;Qjd>F&PLhdB˧ e Lb#|Ahd~b v't_=6^v'Lh42) Gd? Hs `SQ6AM W~rǀ ]U֐tpepMqbi j-^ p7^ X XPq,|k۱拼E^+}{=j/[,>l *8ߛ,iP0U/Z\e"F^ʲ0 ԅJ{`ZhPYIlpI,V$x|u0B%kK>@JNm KbHNIc踕$>]O)˅{ ޻T2iC}|}pdQXjX/5oka)_ۻ89]wϥPtSʵC]z} R( R9s=?}c[}%TZJC1"Ȝ0" HRiQ* -JE4@ihQ* Њ"C(( ,%Z@ Gi(PBi(P8JC xOoeh IK-(e4g/3K {W^@J^&CQ?oշNQo*+ph$<2,OE(P8$ ԓYj (P8aw,=v2BcciߖŐ%:(Z5tP͈mF%:(XtP@(Q8_jP Jb]%2=ؠ9 6(mWx/ɋ}x`/jB}ӔдԎ(jj}Ў%Pۃ_JquݗT)̐S~Qb/J-~Aj\Ǿ_KQ"/Jt<1"arc@pCyPצtW0)=d]'+GY 2(u;Lzk+Y ǧ&zXm4ÈcOS,u=E7}XkuMӵ#nQa2~~皯UjP,*,Ң RUjT+0T1C$V+BZ(T Q *Zm #[JU+e%[jT rJ/TV)[[(zhT-)Gz)eB)w{NvR@(NPJ]dV;4+󿲔_kWv_K(_o=PQ_QPڝ!K%cJj)饼^yf_@^J`9@D(eCJgy@~^W#-V#*Fr\ 1n=~Ѱi =m''GG@Q}Ӥ0=Vp?)d!N,MB颔` $V)Sϵ;8Z~]kQ.O^G;==[= = y >yfrzNzAjZ(:&$~L'L3^L#IxKz 4o@oY]=f8b,H;*z$͇7Ҩ'R|}!@>:9bUj>T! CA'CU C*RnUGJ6&JBN+U`2:r*K9SE)g (LU/Lșʙ,% EGr%K9SXGT@[DTR|9S+Pؒ e`{dCA/dCa͆"pYRmSPXi)}ϽjUUYO}zu(m*JM&(ҦTs}_G,@a) 8K}ܞug'9w毯+Mʣ ˤN5R/|`TSoO8ګ #6NtXf**o5Rʤ0-B8ޝ@2UIAVI4?avSoQjk`Xj j#`TԹꩃr FaTFSS$ ʝ2:*N@KjJT:U * uN2I+3&N(&JA%R~ڄPn${ah%ITfBOJJkelG[AiyY;iޗ UxnNS./a|\_͑T[pj!Y_cUxxm4[ok^ƣWp~:}_tz>.*V\>x5TQܵ> Yv͵0#Vw?% bs۟xӄ U>L,xFgkz|H>k˨Z?WoakȌɯs*|%# r$Z$x.vp;PFq b?,ia h>u<=DN2hXA?\> V@_:Go5$Q$N.e;Jrxb׫$VjK4S 5+H-A$c}'4]OyIxvLk4ebʾn'lY]HR{ԫ$(*)JJ:.$EPh0R/èB.$EuFD8Z@/uʔ!p =0RY {}"FB0FOj>$jCCBM! &<#\Tcr-RSQ^*HKK@!/(%%nfLOA15D Uh$0Enf+iNҜ*KiNҜBSRSe)3,4'6BH`—jK L#蜨W ɫ='0H`߃# ~4au3HAF:-HyAc8t h?bOYo9%{\D! z/+xwAf@A8MKQHҀM//.M/ϟ7sZ&SI8R>o>_u2<92$ IW2S,ImcaQ-w]\ɮMED\TD嶜@hZS%ugN8U:XW#Qk'@)Ƨb{ <.-tl^kuNIz{Xh,x_$F~?G3fۓ?Z=羟$븽%gi^0ަsݎT˕.3 F~{޸7bRt(5].JNeҙ(q3ϢY:3C:3\S ݔ2)+! TI@QrQ ,*'S燼TIpR%A:%/mS2f#R-3)"yo> 3Cme,3.C6]Vi̭MBvӢDhҞ Y͛QJQ[sQjUd~Zdw ī"ī,mEi aAT 񠼲܋.!da;|gؿa{i?7m66BKo},j}p}@gpm=~K ҝ=te_X=sӅ=ބ^֥>[^|ˈ@)s1ڸGg]3nHl=zNyOE%d?DZe¼"a^G^^e z /(rŅ iR𪻨*KuU.4b:b⸫MMEW(EE A_YCKo:L j+lms " :~KD9J$`{ꗑCXaCӀp$Y*'T-L[AQP*gWIvzK^έ}8T4a߲~뽆S;;ͯpq@ m4Ŷ4wS?.`v O6"$Hjbk) Џ);NOL~$лH:x:Vu6)hn4yHQCA *h"R]2pFԦ&+''~"xJu.˹w?-lXCG5$=O7Uv% DW6Dfp!x+JPءb* ~o$<ݳ(F9fŇSI|R4aZ~G6R0 A.K"ex~8_9f_JCix' FEF4V *D;wv,ԇv8v=n[vīgGO- 4B=L:@NkvpzWTPsj-gSRZPCy *ǝ+K^BQ8kmKVYTv(BrVJF,Y2fwEJrf}ߔ#i:L5LV3NK RH(-*DSfd83ROMs6Hr "i( $)3GjSMѹiM JXT0<YHlZL4)]}z[iD4m.J%#{KA,tn%{ڡ笵?gr )+ANjqHJ]0hJL9n?Cq51$ֻzȖka19p$=2{]@*k(: w2]!du@ Z)M}\5FIoVR@D3Dt7kR!cM >D@_>WHi|Qء0E:D;Bb} ڃZ.jyXFPw}*f?_?N[Y⟇Q?O' <r?Kl_Z@MRܓ~fwU(EыRriye)]B)MQ kCaTCB0b1kBco?4BXE;UB֕uiFG` sl;qԿ5FP<"pRI['B&X%}HQ0; . P;D$(aЇTsF+N5?BD"NǗwQ)Gt#>IäxV^il.bp)?o^bG/ZBM*zg.J vZa U{1a8D`Q:HvW\+*k1t/ !"k8E#uD[&B%-aٙ u 6E #d!/ 볧\.TIGz@Lxza}"~t-5-53Ϛ)&u?Zק#ϦE]]6=b<U.XR;jN;^_7΅ïj ._7Cg>BeBhMm\ zxuL=q[i@BS}ߛ͸'-A-~m"긗!T_ur~sӸW/mk@6[p^$uv׏d9Ap8nT%FARĀe 4YN|ȡ 8r{8Cy4 Vp}}8ԩ%2 1xȀn$è>k̾d֖{NJZ5g$u9+)UZ_FqhԂZ/LR4UkyPZe B?yaAytӟ%GDז>I+ؼx}{_᫝(m35@F#*Ԣ](m#J6+K/lߝح#¦M]v6 Y؇a.lDCWi-JlFXF gӆQksٶ}8ShTDWeCb?]s()Lf xEqe=2I2A-5؀^<0'C{4O.J͓! B`RA"Zeؓ˘1ɹJA4hAid^Ѫ 21>IVBH+=j <K1!Q\b6x:Çq9?Ou9ڨh Dg%*S%J!҅ ڣ }i0WTBݴԉ(5B7:AaPl\y.'I==Vo+9h-(mPʶ\6\K͙jO9fW^YvRe=}HLGXz=hiK!m) Ppz2Ta-% =K>XߴZ0x*I<#f$!O @ Nd{kNM\ tagWxu7 ³F˯@#z&~ۻ ]&7D_^lN={)ܯ']R E9*4(=Ջ<@L+ yP9AắZZY-M\Z;(Y;(3T6gR:gP Zft(*YS?k/~vJ JgWh ЂZ@3DE8/CYB ̑v`,(oE)q([Qy VN)ʢ{"ev9bpLgVC`s. i׭=j=pj@lp>7],6&ENzUZOKIHkGXz 7(O*y^[^OSH*)P:3Y(m4EHCܚbNnEiBE%p A+7T:*K4h%#4iC:O1$jcH5 "^)TiO}R*ΞcQg2~glPn{ژ]eV(ezQmj_,UboZB2bAW2=5" 9Qs >4D2*9ciDtˀTWQjBWY3t8Jfhq &tUw?~]a9CI_v o6(͕(#eX:WNPZCNPqAy^ =U/Şb\(jTERhsTlIz596^(ƗR) E RRIZ5( 3Uyř: (iG\M(E II0;Q }Pj@"p ~$ǁ￳h;ХDCl6,=GpnhQsCF^яI/2;/>;`X_nWH ܨ (5ph\h1 8W8WhVVd @0C0kN~3DYJ74#0R :W3Bf}ǩyF@9H/hR!B|5jvKfMD ;6ܟ)nIi4D s]d*yyD+2٭}P/&ڜ=Ř]rda*5봥 Nɭ[y9=t6E((MQ%ꀪ% DQDZD]?J?AWeʞjeOP Jj T6a*#@x`U%JhY*H*|%o!.竗ƢX^Kc@f//!"f7Ă 3bQjI ^a4¨xi,AK#-FBx(͢ď(RqD_s_ TJ|9a^K##:G>n 땴XAn_. xxT Sen- 8ރGsgmGM[Ww)ʃ?pGh˩_:`w}k[}9 ӛn˕b:-}uPx߿TQ,2r1| !GƛÈo7_K~gkIk@ӸC&z-oay.]P@5^ўs9>me)=786; |HJ+/YscyL~կ%Ǵ/NEi)GOp Jp'KEZ89B|.[i\v)TKgzĞ1E!J-HOR>CnsTjK|Ԅws >}׽piD閆ؾ+&TO\=ѿjdTlXp)F]N˥Ξ{3ǖ(oJ:51F]wx~]q|q~zz^0m?4]Ń}nWtBb[`-j$2N3u>mD'*lr|wV4ǽHw1u#wOiNZD-i;8i=}?^[Lzj[:%_C 0rt/8kO[^_Ka[4\ xrWқVt=WohziC]Ʈ*S-j׃"_b@p/JQK  ZKA½z½z½#zb|QU_k Kk^(U T^3]Z]Ϸ½ʫ=(V]!P^R\uծK[t3R0>E{A-};U𰿣 }=rϯz1Oe.VۍhK,ᘂVXCv ~]MEn]|_Qv[ء&5|ڞ-Fhވi#X*5.lC;N]I@($%?_G'jJQՄo:^qb^D)?"?} [ʣ;=7-3|xUyӟWiQMn vݴSVN Ct(P{ P–T%\D!%((ߍqՍ ƅϧWAJݑb{Z)v{ke{`-Hl∿6MJ':uۃ& PP!@PmM_jK>rԕk=B+l2|6pyxfՀ5nBu_Qע森lڣdwŲCZ)v@kOBoJ֞l="r2jw%w+Y=$ ֱݿUU) *PJ}[Aؑ9r@@*Hި T/@RcDRO+ B}@b,$W+|Tma~rA[VtXj n);XK(h(%lv_$nfAWH,̚һiU)s&egD@ (q jEN5SlF)6kQQlf^%bT9`-lX٬t3+,_2NK\7jY 1b&P-,yS3:Ȣ ZrA1"R3RjfQJ,{lr%Y~?]\~nVH߄M Dd+;$O$O|>_{Q4JMu<|ZEyb,r|hɠdPHj2(\ɠ;A:)Y{kGݞNXjI3Ϯ}`Y&sEdnFPh2ZuD5,=xGňhWY"* ?>Z8c' gP~A8ob04Q+P _>,|Tv3O}`bȓo1-Zv3 ;#I:gٮ3 u뜇c^pl9spl;g{gW/sz_.:yfv؉ BϬx9Kb hlAIh#'ԖFls&\7{/d+H3&~mk?2rPb\A͵\t3oG%ҼRKQ ~pᗹD\uD藍όHE\s'آN{;A0Km([sGasG5hanR{W7*sPp/\EnE Q:m6E> ;Mmjrj"/ujD/趝5C5]1fc-xG7Ga=Hw~BDa/U#αj^*hFN z7PMskr)h cq)6[ ۰ f@R٢貥?·!ӵW#5P_imu%NXF' BDh3_\y_x*=|wnǻ9re(Qà;8>"E6#޶`S֛#D.K\(W^Bv==>Xu76I}e}mua`x]j^~L<߾>̑a^0nkGۇdcu&_zOӹvq}/JwuSeY@p&-j%} KVBW(|@π6$}`O@ t@ʮ3 H1vJ'uAY["DSITR/fgV/upf֒T+s ~wn)s'SDh'P%5U4N+k/Kk+dTtc534ޜQb/J1v 풲f/G}?/Ɉ1[@* ADX8{)5ګu5F+]c"Fc]Cq,аW# ϳM? flB엿w~͗WJx/U ;^ެտYZ[.P~ ?^4 3Qq;)}IgAjQHpk?)}{ }X75 ) GQJ/F,Tu/X6CRU?tݞ{?xE9`k*7x-z!UmWO_?_v^ "4J~RN(- \u1lV,HۼdA5מŋ?G#>UKRQɎ099tZnUɅ5m><ۺp!<M7kUæ)_6Gau9y*9W߇m̢|@Zk&Q]iVn+Y]8tf?Pqrv@ vDm1@_@s.1&Wոڮ|Կ"L5t+ 0")o$zfXR7:Xh#)V"Wp3,;68O)@V2yoB P$ ??6%Jb ȇ#1GAzqKS|5jǕdl?yLeSv;֔5Nv7Zn*GqU_.?PX:U9P3:jE+!tJ;PVGMU^ TU٠phV-8QH,<;z*@-rF[Yyfnb",@Y:>rE(4惎oS9ZnћъqUG 5VuQ,Tq|?{7THU.kmewB0-Q -+DGBq .6^]uTUG:UՑ:~utݍctզU(UUv-_Ei;]Xk )ŏ]~S,J?Kb*J?{}V7UwdcQh4?QQG;k8g5GEE(mDrlC? q¦1 U4F{95Q^ |11U6F13ʌqBf S<Fa*#AO|t@0Pq6/i[9w'il$_>IBhkbh1JU-Fa.i>Z=5ߠ΅h ]O?z)EKZl*-}IzRG{ƩQSoA=8b0\4Uˠ6%jw8j7䆽̍+8X3& {QQBB۽Ǎ ղz_ۈ"UӉ|C7JUeT9 UY#D(UզRbE(UNR]aV99JUT WcmH,*b"x¬"qxF+TƻUUVQu^ܮ1)xǪBSXܬ۽zŊfo=:gPWwuZda@XMG'(UԶqW19BjQ vXEێbҳOEێRжe&=/cwBՈ]3>v(dZuBYm;5B2-݈'mGqdžSݐhQz<](F"yH%hRe(Us|j>HUqU 樫ÈEy{u' QG>;Qt~U G"sqTɟ=fOW}T6t_8rH-F,r@y^Iō(@j!?J-ǛZ$f}'ywtI՘YTp6}:REyP!UR)N.zkd[$2Y/z%U8F_ܮr ,*M-tvE(_<3;MbcUQHw]WT]ˏRC`ʔ|&^uJS]TB@}UP\(8U֏ޅWR]vSX"^Q 6i (p<3m !Qpb:]7)sǷlnb iZ[Ժ`U5׉L۰(bR߱'Q!5c x߿œġ*|0Ua0B~4T7V*$W)Z]>1 ۯBB@gkD?. 0JjC}#TbEPU x8Tm76Ge;~0k0UVUCo0Ut@~R5|TFJ׈QHǖ }byf`N f!C0"bH5ƸW~GpܚVRCkqTu(U >JGb*TuD/#zq#zaWq.]<Ự8|R{*bV8zqSz<'B8SN=V>1c|Fb1}c|q>b8ė א!P?ܦ"{[Q]k܀WA]`uMh1讲ثF@Zװ,cSWʮo@j?Ŗa|YMk1bZ^ Gkؒ3ObS:JUg`ƣxKO3B"CJ/QQ@),2G00/tTU?JUTQHTQ/P܉*jG~ "ǿ(/2K ME |!UY_ Ct\fk=Ny=ń tq zYäccݶD bu Lbȓ٘˿vFB@:. f{=Ӝx3x;NxHŌW3-C0| /g~V6OZ`4Y ST.3utk7s6B, aiI>Og!iigY sSC|n ҟf%l5 ?L׳]{dhߞ5M3Pic84$1p82E-v/c+hEM{OZuI,*9e=a9}^Rџ?$%nqO Z?-a<%nixσQ~b@keٚ~;E8V^X5$MCqV,mdž7 iVX"햆<8#{Gl|~<"??tɞ`c s6$ir qD- yhA>N,{OnDYg d{ܥ"Hx.Nbc'5$!i8? זV'{c;wjgߞscY敹,sJ:vK 5 i aG*X'F KF+xϢ̱DϔXq"{:0'c_Dz#3QIġIfS #|~vft\`,FK{Zz꧝-schMY' K .!/b^,'%JXJ{ %j\ϝl9w,$E S{A~=gG^Ic\ 3%8+܍@LM$bG mELXWA!'^DM&8t\-`묠3^VaX"5! - L:V}R"NC>'&5DCpZa [i yp;vO>ME,kskA30qKO \Y`\*HگkrnSC6O ޳t~,FT}t; aK4xA~XB=}kI,AGvٺ ^X5%l->bO댉<ΐ8q8 dXrȭ Ma1f G8BFDZ- Y]ExvOr=$"M/JВoZ;](`c|~g%5𞇞e}^gg+ tE&*h  n*XԆ  ag^c>ض)~= [VnSx-)4;cX`G5yS4 ,*XcRq$hcS^]xn;³Z~Wvq8 [iwA ςx%"$eE8+Yk>jcLr'5+,vS<0aL1~Hس0q959L,QO 3 N&D.sp@`O:.Vc6ષiw%@r"2>G@bCA!K$;ϿִMS?.0y=]m ż=9V¥8cUmG69 E H _kG?E,q.,˴gɉ<MAa )YhXBug-Y93Z0x$bbnGk.i4W|!3'70Tsv5^cB,#~F&1# 4$1p8paBcn>H+k~s1a۱y~7roǹV1Y$Q>s?k')03 ΃ص4gaZ޳ 3)osR,璫9&Rz<]iFmLPnLs \az5 Ss p K>8,\QR]ΆbS 'fG,`cN^h9Fi??2Nq K2 \xo[6DP]ApH5$hiK…;50A96q>~M^Î%"$HC54~:'bj8y$?? ^])boww :csY}fb$pqn ijbn Ic \!γiTjY 2m&I ?h1[\]\̹I9/JA`kVXϫO?]z%oG_fk~ M2ށhR> '҉b'&߲=E5kzqFLXx6Ou{/FQ;qt^<3/p?;NϱiY(ҕN"R鎦$G 3! "܍@{࿧ɺ=m g/f{2d!< YwxyIØ`^nDŽZwZI4=aB!ߎ1_ܑ33Բ'Ɉxϝy*0!p8qŒs5̀mjc+dlgџ;<5H5XcBvM`ElFBI,vh Y4cBzKݜ??KDkxOB֑LD'9fZYr0ECp?dCpIi01t.$c\1aYa[ ֦41~,It>Qua`c|~:ƍ4wv9IhF$.̜["Ӕ=g/L%fJhG̉Xʖm9ie%l5OLF|y /8χ|Ñ[;Sww (=-gwi9qS|[j'WxpK6_m=>=+c뾠f)]pa p+#e$%i؂j&25 tm &v@ C&i.M>+ww'&>ĉr<7 ʴK+p$!p9ӽ* 6hZl٘ ޳~KgK8'77a;㵽 /ׁOh8 H[;Aʷr$.^W n4W`LL+&쥡;8M|Ď&!4DSp`9㠐i9M)tKM8 }{#s4<IW^$4϶XH~ P=Wg!"'źñzuUMU$.:DRb'Ⱥ,`;kr7iDJrv᧝N/ SZs18E0!ώ4K>f)qLe'1o" g7H4en}{" ~(^ټ"het2a%? @O[DoMA"0*ρtd@)J,>lh0oL6:&xkMZ$"}4$=M|j> W KJkxCK1<;9v[Bv(BPR 34/e̼)j`Z ޳_b^(FDYlH@4VZ"׵ih 9'vBZ4<+~tcJVXVJ,KcX (R(،sA5in?Jhru^Ub\` 6Ya iIht-Y2Ofߞ-˂([ZC"p$$9T,Ս@N.` hYƼyZIe3'vuz?)0"5$Td3d"\!D2"%ddjxg x,H6#$滴pXuvS9K2%676N׿a[) TTYa [i y2'좖-!>c8ϓmECgn K 4,JdXulVX"햆<)_ZWeP4΅Ň/2?#S0JV?l:8oV[C+ÍMߥ},w7ie%l5gtH'5P4qOD;b.i.Zb75YȄt^_')&HgmZ3ڑq_vh4*8i 9س W+  Ya[Щ@}]?ͺn#7r_GjӪDXKouo Ior$'g!pdj`6O6ر4%z w>ȝ[ݕqgю,:T ZC(H@Δa$_ x tig!jl[V,:O8Ϋ/gTX7wu1H*0!p9bi`6OaZ ޳Yy\uRRțơSx1o@3uKy^&ѷPמ8f翧3wZA Dٙg`){\LCFj2%YhW,4\:D=  YI Z_]Ҫߎ Ьي43ˤw]@ Rg8 iFXFJ{v5"m!B6qUP@hф42hjRC+O'/j[Cn ҟf%d&Z^U+\3%q"fq˄ ؜Ĭ8U/}wW~\`Z 6qHbIH=B#&vk$Bq~Mq'VXN(t| Vdn5 G*X,4>7LJZ޳2xo'Ȏ޸cOwrg{َ 9i^ǿznY83SGˣ3۲nI`KUDS @\4Sk}uzD, )xUe'dnj~{΁5 V~]2MZb>b I*0GWkсV F˿'vm Q$rv56Bf/FruIN 116nRӡ!H~EaY'؛#Ё^ uMs7N)1o@W&9@țv$7 g$,_P*\}]/X~;Ntm;28qIcDM՝yI a/T0E A/m@,9?̠YO4&9wfU .by'L~-G^4$}88RK K+,vS<2e:D95q"?ބ@GDGLS7x> Ȅ/9 Yjz6OZi4уZ3 d+9Eg[%YN' IO NNDl59!H;$lg!W*b=xo->ѷ؂V u d<1='R E9By>n$0s"c7l_4h%l|MA^TܱL^=1{e'F~;yNoSâ  RE7mҶMÎs;dV;{>įN k>əYbcI]WnbKB+xA[*z [< R V;h=R7%5@Gj1f KSƺy ڔ[OLꃓ̺cDZ.}4Mif:Bs P KJkxßxmY%::s4Oo 9ۥϮ\:$G6ߜU{)8*0 DZ- Yt+=;(<8I&G%@X#x|ĉAӐ_9pt\a,adp mUc-ɾV="8LN+_иܖXz`γ:ϢP٤N[$??iB B+x;wR~њ\Gqȵ0;zƾ>)MNi+AQx*X$C4#,fS{}gxA,(8n:O䦏'ζ)0$hɉPؤAo9ik'`=v"|,c)3!C!8'#k%pmcq LH"Xil_6=j&%?@w6)'OeO[i+̙p(sy\c[VD- ysgWW$8QA◄Bԏ0sw;*HR[ !H rFX6Z{}A4kԡEo9p|"xyך eQruLsOlșhڍAZk!ƄGBw'cO[ϮfM~׼u&Z(_@s<\ߗnHi Rp"@|`}enq 99<|JN$!y[]4'I i66ї'tU.Ǔe-T_( 7IGybe$ /Wwi "9|N`Ւ H=e>˄7)85_Eog[1Xx:O W4RÎj6 i4e0hRMAlzh-1LZ[.c7)HI{ i4|0FahYX3^ݍ| 2z6s ;{Q5Ul]}(NJLE_W?=OZiX` h )pEI#Pf lę&ʍ"!ζt.[ C#x(."9i$jI>?'ḵ@EQ^Fk oZDsI̱:!MFV GHn`[h91YڈL=b%ʂHZr' DjwIxrJ=RT/㧀K ]BNu'aQI{ƉMC^C;M%i|K@Z"V 9y,Ω3V \l!Ds)) ٘޳lk_2M<&I|sI@ߢؑ5=yx}6'Y8|B Y|D> LΉ3JFxb rIql Dj' L=gzTl;z0 'JLG3)Ňr4rd򁬰D- y|_ᄇ;:s]r7ݺmi],HػuYoR 3<80y df$FiOEb)r]HEߞs!r"_'^ ? X^Kbf2KQY`ѱbX4%l5mw=-`awa"oIǍþ[87iv2X9ڷI螖=9؜E;Zk # iVH"y(: ~K@Jxe#` @s" 瓭|/gWPFxx6ӓ+(IXr5Oڐig79Br\dʰ=mH6gpd; SCҳRshk [1D&V<,P@,zyPt8Ax0N`aH.A2Љ)LspM@,97ϱ[#;/oǹ صfeBDLS 3=&hCOYj8icHkitW&N\M;21)ɇԑd׼eG&$_oNS`r܏ t6cqߚzpd]}ҵgL|NDL2ca}ѳ뱡!*gjsKjk 1{H,Pb2UIcYN Xi%8a/,[bҟf%dMI~VkTRd}={Y; ME>: IkrvRM t]kZa [i ywh<8D퓚b}Y;yI2#76JN >]1#`Y5١TzSdZ<Eۂ75$1)*'rsJom/mk:0L{c#|/aȧnsNZMU8qPM&'% x аl%l5'sn$d*B@ lnHέ(즢qk I#J(ϔ`&WV%mUV4,a=N> ؙ0͜MzZ *@) $q0;5a+{7OAOu{ZLIeߙp}l ;ە`{ۙt,vO8ui0-gEiPj`6[6+,vK{rOΤZ> gUݍCu 7ȉ[`^<]OϢuIF3g'&HMӆMZ 1YF"Ԋ70q>9;Lj6qwO4"/8@|U(8\&X&+bw:ē;;No hbY["s'qL6BI儷B 46i:hYt,j"8A|8 g/1F{~._: 90na91ݞD- y+ѣFkLݎZG;nU䖉P\Se"XWJk9!iݕ6imo𞇷HΘK1nh5cI ;C᛺9ǃy{\Ls\!Nt\5 Fm x]d%d&̀Z87kHN;>;; /evb 9mSYKD/;wu骼KY{b"mوngw'(kAAIy9Oi4 SȤԑUhC?DJc=٠I='%J 9(jb|uc\VXBFZk {`"lݱeNe 3']j{M9ۜug'4tIˁ4Da֍AkD- yӘ'i,s' s( 'p.to3䅦kxr6?)n|{lKT6^;ŝOѩt@ An2XY܂ZeF]шUp#U!>?MCT5 Kj)xMejXı֡(\"ffak$>"نZp* ^JDӐRTs⛊,EjOt1DC+RBFZk}iia&{P8 _;BBb֮`˒oLvְoi.|-..ȷ`Ɵs"fYTKD$5INC yo_Ӱ3 ,"9+6yYYa [-I;aFܞ.83 HIW̌'LOلYM 엜R2MCM6X6Z{}؎@cl`4utF[J}'و&[Ӑ4"~|g}k8"ӄo rK=r՗q.ld@]@:b C /G5~T ܝ{`4yy:Ǯź=Uw]Xʙ&u|2*ds.IXW\(4$=)9*9ŸI J61H#SVXVZ{=K14aoe ugw9[$ii$J53+MV[=Oi5|BĕPh$k!PI>>m.& 9o͗XpW'Jd&Փ-`묠3༞Sĸ >{.q~hVѲt~tDs\`Ƥ\D* }nCKFDZ- Yi[_sBtIa23}>L{wL0bv1HRDHw]7?QvgZ<镝D{SpF (,LM$lHK]cV(ҳGi|'-.}SbծO Lr\ iS:!wKD+xM'u@nv2H`'zv]>% 6 ~TO9$ vDTHӝ鹵Z`c qvaá1H~+BU%1N6eA`}[0>V#iQn{l4$-Ɖf|CCxwC,Dtm66ї'gYA) 0p 5':o)gϙKHTPn7Nz~V9p"??iB R𞃝([!v몺Ah8 nH+o|^: &H˓vDӤ_@64}= ŬɃ"VI@rfw*]4ՙoBm.|'4xw LOn8nK ,mHZ ޳'wi{(/R%]ՕəgmVo&((R>Φ4Sk{"{NB8)QNӌh0s/lVE9rp}=;c#޶$-$YM oc&>m,p4`sڃP7LL{:M.sEnjH'9vV+|!D^; ٨_S8WtѰ>Mr66\x̬lq&s'hVMMr5=ۥpj$MϏ H vQ3*HOS_7ꋑgFTb~%FI͖o&A[i87"Ԁ ZnjG_2C%Z D- 'g 4Cq85kHf~'3Xis&A=D6TL,VK{=EVq}8SÁ9;s$q^nZkw @zO2{|8ϏMh6ޓ w=&gN%وtv:vy#Iwo}oc"9BțmV^-N?鐷H=)hUK^#仲;9IJ'?'^I|}!g^DpQKKs'ʄ=eׅH#o^Kɉ-WO聖6%}itrsVW"G i&X"$,#ӧ: Ǘ ߸ԢkͲd(b:xפ=D dMCs,81H$nixϣ%lFma.o=G|ݾv^ט#R?8.|TpH~ Daa-ي96 Aq𼤑d4Ĕ8y8H I+q!40f%l5 BmǧhUQ^\&g:΁m_P:DVqwQִtÜϭ~,3?? KJkxϣqY%l(ps D8. ; k`R?i|d%l5`|WOa3NlfsNx{<[fϴ%a$֓_kH-t0Пa )Y;DHc W(~{ƥ }b#[vc9HM I/Smߐd$9O36^HXv(,N8Ј ! .by6^L&g<эAaYa iIt}qӴX^<51\مdz}"gzJuSRnk01H.:4 ;m %H=~ayVU0ߞC/6Pc`D@H}T&xF$qa? F+xϢP;1g\<fG'xEsxֈi:Ns]R]a` Iͩ6Fs KJkxC/s |9Ha93~>+1n jgx MNj IDp`C s&DSC,H{7i Kj)xMqfW{l&$TqF/Xg2a6Xt6Fν6g=2sV|=ª@=$ҁN~l㔿OYs zǕ$yV7JSU76fDY(iT `MMCҪjDseS?q6<:csl./;sl!>E@ QV|](HfL8.yZAy0gS*keE#dlg<4q'o˅]OVwl%I~Cwzw &1vA"A҆=  g*]8 y4[n"n7qYI2(5u¶Y=ie%nixCf&e`Y|B-]7&L6rӐ-9s4,G<Ƣ KJkxyb~[b3yBr8 {g=p._,J>mG t3_JÌ9O ޳𷨕O9@Qp97s . D=ռ&3͇%֕)L`cə!e 'Ѻs p K1w}{w6roM 46(5L!i ȻD_Os"ΥH5 eDڳѹ~G1MU11%coY})H# & HA@{At϶Dڼ ݩk9FQq 09ZUہZQ/q^P_.&rӓ jXR#FrJBK6ia!8-gW3=D‘DT [I)+9V(~f2I0;$--M}m Xd%zxNFV(pڈјB $$V(5yBJgc7 k81N{ K𞇾80fqzⱝÒsFIHN 9ix_IH aL?cFC =|G*nxx*Ӝ#6cvv*HZzN[_lihh9Jc"ڿ DZ) _c[Q^7ԩ, / }-*i?SksMþ8~"Y'iX"M"jEE) 7ITlriΊ6w@zD+:vlCUjƘ׬D- yp;!wrf9&3p~ 80!%VvK 9@:Q<>1kH{P7.ն+"Ff$`kTDӍa) |YPQ zm%_w` hYȵMCH'cWGb)' ϦDګ_ {gcJguBCbY~ tK(H"s7 6@KDlgCYtNPwwAx'C#iL@%.YC a3q9C'H Yp >UsoP9Loٹ*9#Y$uL_f.Oq_~HO4{KB)xOw {S4 3]8{un O|FVؕa Itq" Wٌ44 d%l5`X̅H!̷9KL3/*Rb>D鯝C@vs3I(X??iEJG9A}.9*rjyVax~h iש%R̊av ޳л˔{Ą|ʳu19qBd8<'ҦTT`znl&9Idj)xBMqSE]/4b ,\Xr r0?byy%I;48OӢҚ4Ҹe%nixϣ}W*Aa!'C|T`D]EHLyNtZCғ!J!V<|?gjfG=:YL*<ߟ:w'=+V$FBpf*MM$8%b!iaaM2O,9ѢIb"}KCJbc`cػ]>8 i&X"}poYRml{v5Ov%uOv6q5R2MHIrƗ/aKfKDkxOa8hZ 8=i{hu 39JF8mH _S/Lw.9qN].h.L/Ҩc]Jh4$= :,9Lnf1HlPVXVZ{::w:\.Tw {{Ur1vlIzid]ȅ䍳Pׯ xKB)??Ξ [d0)QcLm%nixE}Ț'C}هFo`a-Bp{EXH:NfN_:8흆c!NϰbU^n36^ޑix}N\p&9;0*+۸=k"%vqX]MCln ҂H==Yf[P쯴ץ0uX q+%nb8WXNJ5ҩ4yVX"햆<=B)=*D?` ⤆^,'&CyoYADPuj|Sƞdl}ۯe<3ȑTCAjFv0)| #iD< }'O՜mWi4lt?? KJkxCgqN{umJ4I=C2Wv' G4SE,q옗v8ĉѱ H+ &XY{} Qzղqnbu?7s>%")HrSȫc׿Mh$KT5mZfWRC$qx*2Kt͍uE46<ľ3 9q6B '6Ʀ|ahYh+5]+>q8ʀ g.$no4`M 6ie%nix5:ށmcAö9U}bV{rroiY/k0!>?rHC^?? KH+xM?ϬNa @. ( 1.rH'%%{R`yj0!*T0jO!fH5􂭷OǑ3A ebFƩ.&1$gDKԐd$YsXK4L W KJkxmKcs89;s (Dw DkOY4G@Fڊ=PĪTE~:Y9;y;7g[bc^j0 `4l166+,vK{MaA0]?&ҔB.c*ܦ;B"\ڟ#|6M7P~!h'o /݌)ɻkS_pS7Ѭ9i^#?%$hs97!֧Bi4|C7@-=,\T3+Q%hUs'q _*0=`79 5br6X&3.%6c9%jJnwv1]!;7zZ;3S <l&i.MoY[`EZy lr.zȹ\0'1~23G#@bg7`c`-6p38\VX"햆͏ ^9a3 Чͩ^B(P!}#|m!G H [i y ? %I?SI|Ĭ;gB|A'a3; ZcwfմW|}gK !UH4 @| -2GOSkpDau aF6ENx`/o]Ke^}ѽYJ9[72U(HP -5fBkb-&DQ'silYSpe;k$]ϴlvqkSļ7U&~5.GQC.(:|tk+eȞOs%u=*=Ime٭nC+[MZՖGQv{HJQ%eqG<۫TK kh>k<{7pS Qźmq؟œ8\9^Z`Fn),x>Õ<|d\"-N5ق#P3g%2RsE$N|0r4U^7բD3e(&u2ŭEmJkKHW*vpoa~,u}1 MU,2>#@3bE(|!Wk AUs?5G./{nܔ`ڱ?(=QC+Oyl5ǖ^as"(mTCEIY>b"{;:9nƏGUiuof[9ѼAƠsV1 .~݆@IEX>;̣2yXYpC>5[Fٵ# l\hfǍIZQ(2|淗bkn|Mk&6OY`lHڢ7VjT!Ɛ[()g?*S\wmvf83T9xuĮd_ "\|]Kl-v,Sռ-E=%/x;;M {ׄqN+dRSVXьZ*/K09kUsMg![g뼱8 f؊jn=GcP$^ppY-d#TD_v!g"mOO}\S<?jh:-hs$Yv #ig4z|}["qtwYmtl9ʎyfeRKB$*/{ḴO&ws=ƼKIQMُb9ʂZMݎYsF TqC;Z76\A+q̋m0ބkY9X ݂~n M Ok@}ZqǩeiPS8oԋ=sk8wgö) ˹d1Z(p:x~߻('ΪP%bq9|Z"s9.5[D nGLU䤶rS<[_rK5 nas(p R piR-qS0`) ]zv5hH9/e ,U&U3=`zh#ʿ?EQR'N|-F歎#]+]pZ±zB8r##%3GUNGnW(8|kod1:Ռ)a~+p@qn-<* q ]4#RQ4g?1etr[5,p19)˿trL7qGcz۴yKX0Xmc=EQR~<|"xkksˬU3UުHCd{31^`\[\5*Gf Rq,ڈr(O;恭ptܽGM8o4z]Fa*Ph&r$6mD9]hr'~T#є*Q2sc~tFdxSKC CߟGM֭l"˿?Mv^TD Cc`] HV^E'\Efݒ xơ%RKϏ6sKQ%eq**^"yGfKSLDBᶝ5U!ې~Rlk8VrOo5o8Xh#iar),#) Of}gAadQb")? ZqNB15e7EQ2^f'\81=W9p1e#( xprz<*ȷ] !n\n!I>zQ--_n"m9[v:Sn,͘.IplhV ZyNV3Q,q7ߟ["(g/*Lt# a\"05͐yzv87XN Û_ZP9[P9EBNc[HJuMRW|CqL#Ir*7%ᮉ;~*@k) M o(emٖVas4xK| b8yQ0LRK4U&R0/4AMx!^"?zPml2gGM.8z'±^L]S<5wqqď:md=]FP2^TOC(ce_eH"dY|Q,G3sUUO7>-D9AфNx +c}[sX̪HSyrK*)le?**$)xmh܌wM޹CZ+[͘٤(:|tG>)212^-idY#eLAF|}"VlI#`PjK?~فqv,emլU%;|PG(kZ]ch`7aȲ{,xY<4"-D-Cń-Lc",{MW.b_ 8PQ!Yc DS̢F"l>Q~Q˟ p)A2i}ӘD-_''+9\VN[A`t ւn%a  ~+pwm5:8efp+g)تl\Mpn7V%kt,n캛Nf'Ͽ矝*rI#gpj}<<}8sJǐ7#ufPC{ kZ0D ]m}&{!zh?R7H(s]p3~nd/v]Z9@xzQ8T9_Ti㰭 ۈRhr'~8IM}s LWH`V07yqrῨ)ߊøgdAeUH)ɝ>o|O̭cOjP1"gm%˿-O#dž 4xyrd(|?wxfJ<ܺ65[dGn`sodw{GQ8PhoUa66T(OU7ѧ#0li1g.}[:xdv(5x{QR5\ӳf1`:&n"~o!E8|yC_7|X*sf932u1_蹕]QFaKeά-26[ܭEQR~m2l*<(VsF X[䌟m\ng7ݿQfp(ϯ&@|j«MnkLʿaю=PhQ5K$ul#iv$hr'~<3Wi+{Y⬚QgzZr$tY4]lȐ$0'V&U8auD2A:zQ˟J:wF w{8l;*S'd`ybslQo &Ȳ{ӄN-*|ָ9exjzVUM- 1>|cZšFx&be YeO)ɝ>Q"(2qx#g͙[ N[EDlT#x,Y]oCö&a)COm|B$X[%@ͳzŐ"`vqokx|{Wb7Ə~u:t3U;VWqaB<ۊaB_P}]"/mc?$-r0xu!:mz+YvU͞]Sg¿12g(2'|S f*k0OܕmD(Jُg:LlGt+/gjyȘjHeHP+2s1p绅Eȿdz5打/9̎P~v"=MRŠ=c[E5ch.¸iPMdчBuȦg$#2-B}@$5˾=-a(49r9K#q̱#FQi2ߛW' [/-N{9`x2Vt;{^ӣ]Ӵ|W??EMl֭ҥg<̙8jrUwe,0R8EZy.fdž&B$_vbNq뻰ۄ\=G6eBY6&-pQrPq(:(&wrG% s? ЦL4>5s@ mݑ90g9w)ipPhQõT6xJQMُB㏤/U[ "E:D!̜7'knݜm"rFM r,/8Xɛ1Dz)E(G'~q)a!4]h/O eQ5{,4 6g4PS5=-" sW'o[X= NwTvbPYҤFdyeE QMdً 3-71}^-$H㑺gcR{Z&C+u͝o;_mlC]J()g?mLʿÕb*qyC9Q~8E7#u*f!WZQ(&wrG]$=#BYjGfvq]ξPHeoNܿRwq7吠Q4gaWe؁>*ְ[ו3#˿O$ERPJruW̷egSY&Z&DQ4G/<U㸟ncWVǫq :4Xx˧]NLlq|y={/hJb)?ZpiK=.S& TSlwXV̷c}lgA+lj@jxS&sP%c1"b*9T"h44yȟǞE\~fA׌2|Ԅ?W17Bz2E:|"O wTҞח]eq5lVL6~c1b9~wkpPM|щBC;c͸řBs\5m>DmHarP4UEٟaZ9q!#%?9׻,/RFB6ȽDY_ɶHQcPrv KĴ47*\.ǟ1LsP%a1C*G)UkȽ4ⵊ->qsl ǘǼu^F=9j6eQ O0ՊpJ\7>j O$-=o}֚(o9.69 kŠ{L!k1тEȿ7]О x{"F,] _@m0r/{,wuK-=7|?eEQOAj1-CmL 2SZk@=}ŶcT{z5rlhw4o#sn#W95<ͶZr.W(е|?: Ҭr!z>jNEʛ. cZ;Qd\qhh]g#<+ eR~<7m/I]q1P&{]W`qiH 6*oor̶FomqҤ(:|t"w|*HiĶ[LSdcڦ }>~^h^π;?7s;(ןk R&nYco?8"]K}kZs+ sqr&=j!ZI(sGitG{ iܣ+[1 屧7 rrWڤ,g5ssw`l ˑ[&-3e7-M0*R9D@D?V7\V 4e{-|0hJIjp4n0VQJbً܁e|q, >n/Usۘ^,^ #V61ԬF1zlch箈_/oD3x4&rڻJ杻fk #m.ȨZQKZyHNB/j׋Z^eȿN'peri O1 -c.H.aei5ʳ8dvдTrIÁ/e2ʿ{aev]S=ߵ_ǃ`i&rm5O0%Xs6eEQ"?w3|*DN e1ۊu]~4)*7lf PqI1&^ QMdًr|FݝJv]_pO,~^qf91َA-qr4QGar[Ɣ[(G'o ` !e]-| M2ٟk+'*]o8I\5-h ,"EI ^}x:O~kʬEwy)Vqӹ`Yy89.F¥V^ʹjkQoEjvs"9aܦ%[R{X̎;.>Di'ɝ%^y*U-3XQMD~QBE:9|6>`q]cD/ywzvSBnmZT5sӢ~$2LwIq^(w=&x)`ٿ̀*,XaLCv9 r _324>7*G.5 4Z-B>P8I|u.GhsltG9{ N;N@qDwyWӴ8XS,REIY^_P>b6 cq:&, s%y0bru_gd.YNr>(R jj)/+ f j8$9X]mugF0Ma)UܖW ~o㣁(8r$E9|X_sqIqMc^n5 OK$B{ q+/-8T9_dn7![QcJQ%eq̴ 7*G"4ڙִ5*0oCQLwyVe1ȤV Q%drSz׉˚קӌ"p eZplq,RwjO".YNjR f{4y>{\\gu/Zt& f} ?yȳV3{p TW&qwC/Ћk3@^ 7Yē[~3#I'M/3rw4U&U1ܻ,nK֤EѤNM*.PcPyܷ& 9nl}DreKni+=(35.N#]kH4*~4~nzMq)T`HUZjcm0w%Ehr'~|DCD|Z uay>kx64esz/ s+<ObLφB(([X?u"woC!8;L6۬9écZd8}7摴o@}S`PhP595AW 7~PMdًDzc=2P@k, >E8XFf9(#SQR^ Z1k5'tb0x!S_BEX>{xB_c@Q25D\FtxFSCA 9*#:?@[!Dh%bqDy5ײlkĖG5Xޟ_q^[G6xwV:w{{Hɜ >6 &ׇlA,y1E{lW9" } [ Ş^šϣƔ~fLDyQBE;|"# ʊ::7nMS+wBgP嵰WZE` Qk"ʩmۃI>zW<0j]qȊ# ROsMbP9łV'bJRSWV3rl`Qˣ(REIY>Q7Oa6gLi4P5G~GLǓew/gFEơsB>j/Hߟ[hr'~Xߙ?dxxI>x_fc_d)= |?.[ٿgU^mVq͂0og\9ݴ#f]c7ѩ!MU7V2ߴUyPj<>E}~|%x>ۤfku_#?_ɮ6b=1˿fbL?/tM@3Cf*Xv;VAew]TYAUF432Q|P{`5OMG% } VW>Jã4mZ1؟2MT~ԾKI2.ΤŐWvhH;=%jzrjjSŧqmvuZڻ-|rMfiKb =E7Pt lw)wP͋1?O]^Sqoq["=~j9{vxՑ}.R jsL,=+(]ztRxrwg48sO9%8bP7Qwo_ֆYq=מ% +c]CFxE EyLzSwyFsQ]k.GW{T[|k8#U[:|iûv%ڳlѿ/@?̫">kn,_XDIj`u> fh* Pͮ%BX3~9zr˗n q<;A\cz/\^ *Aʖ / P顾樰GO غhڷ:/wb>kq}#kؾ}K=CL\b:? ~%lW DkۑS:b?׷@w>/ṞXcBw{@ɧ-ޛ?(/?y׿ajܷo o\瘷SwV+~jw*N NBSHTIT^wQjQjQjQ/aPAS*3~L/ܔ 4747K47"inآhnJE *hnʋ47]Sn;uH*w0UAS=8u鷻r+tE"]Q[]BuEm@"--j8\{wHQW-PH ;+/]qPK./=:\W5P56%Phxy7_fTENUU0*˜ "[xTOU+HJtu둻N9ENq KNصpz]9/*,tTX8A9y\o3lCl8@9^ )LPNxjvͭpUwWaaz谸 tXL@7zUbA%Qb+J,lB@UJ,4JBD ]ϣc51G'[ԡ,!Gj-w^j?LOW{eٻ 4@GcAT݆/ka';ؚQ|;i򰪩x@u_rUȕ0ExUKsd82E^Q3+so1$'bAƯܗvĢoEp$VP7Q[PjACt+cu4+&K:1p2ǒJI0_70W=Ne{D7lw|5^ݧ $֙ϢV(-]rnM1fݤzK©j@e_'c_au<.н 0z;WW!\hO5m '9 3B~ Y:yp]L1eˊ ?1$/M[i*m8E!#WO}lLTS)559 &s>vעE%R k'YH#mD1ݭqhW)roD\mq؟6Glo×kG̢{Nt/+ю|UIGasc5Gwlϝs]q ޥrHʲE<χoWuy҆?Vߒr^'=sy~O"9WSNmlVfC^캙zbm:Mc;ՋV>2Ma% c*e9$\zŸo[=g-XlWk_UcHhi(=bKvӟ\t12K%wY;ߓ)R6~92 sʣ3QgqgoDٓ}])c,SW+Q)T o""o"2Rj[I1U1FL[{^ 2Ic@:'L90I,5`/5` yW! 48DEO(*"L5/h@"lZb%Oz$Gh([jVIZb#) ",# }F’s#*_X5_gb TlN*?b1(x T&*i5!ĚH׋$蚰Ãp⋉s։SB 9(j$^D^?<@A^le>0AA(x{Y./E^M},,*)nLvV[o R [84Tq}O;PAxzTWT( *E0+Pok xm8m}ւ}̓+ӈ7jP8G< ?D5/V\ 3p:0wҪ#ml3Z2\EZ2CQI,Ui: iK ExCвLBtG  D =AYW+5mji>-p̺P;s@kZ_j58i":&q]>\Y @'U!}4Zj }DxڑL>_Z޺>Nͻ[+姺VBYy*&*UKJNKN%"@D*7Iv7& &2}_&H4o>JjŷVJ ]q¼5W"RGA4WlPM&NQ$qj/3NwQ78n/P;' .(8 Chآ Ӟ%kZ)iy*+|]q DwŁPaoݵ2>uW讝k6h)J^|_>׾h8D{E*^qv&K{Fqʋ}x)@1 {:ׂO{ô y70mgwr_bL$c5oc^:Xԟ Ĵ/+<1tq=Bir[$ca7-_S xUc 1ĘY;AS7:|9 6wO?FL#4UNYH|@13TF%t2"NN!"}R9g< wZ운Ng3RnqBl6m q`rڦ+dL7:Jkma;  2WD57b%Bd_L3hiWyhskJbF{e͛p4{{u>-]AvlZGAR 9Ek'1|t? )y_z\Ao6P) &w;#2eYL: vPI$tb'4C>wWuҷqty~*5h~ji{^tRM3_9؟y_jlVpsqSckNVy8Ijp=?\>nаYDZ~iqZq-;'Q-=~=E}!RQW=]~].? 4@i`iܭ$n%^ w+[yc}B-jWS5+w+4y`i CJ H3;3f$o3V{[4w,kpRφHuyn<8%4+.lk۫1`8;T!U[e-ypG[A/'CRIJ%,W"8+tXvuua!0s_NhTJZ;R(h *%MU)iJIkZUJzQ)iLUY3n",~+<oez" TYqx+,$WR|UJꢪ߄oّVW|(UR*SZ }&O$$WUGayP?ഁ9yhJvg5ꛈjxU īJSP߉W*%^աīJDW{rF ɐLdz<· *J G|T RXBS˜jt4!,ABX\:-0O!+l~e- BFX<dY#aa\0! ׫^aa@W\: uNUT%+~ z!׫,04i ;>[jWȚ7wW r¹Y\?^Y\aCWP,xJWغ!?+dȼd^u(Ku Me=u#r⌐\0 +nHow/7CH; W$#,b䂌k֌8^#^~'^b^Qyd8U%+g;+n%4bKRHкL:{jKRʎ.` +: l9D+xp׏{H߬"+y+&k>oOB"g\)o gWE7ISq @#s |A.>^2ɓˑ D |$G;_AGiړye@× @ڮv/Gm- ?qw5JE } @v]"tK?rQ*JC ek]ܒAzEfJpr dz14! jeazBqi҃1NՠNjaao~?FN(h_ 8 +#uYN%oB @; ]7?g;?g8}N|ceG| _ Vvtv"^좸\?}-i95-nxSpGf8 XTU37KZc?3 b{\NTY 1nwkko[ "fhgJ8/b/c4 /;%e9WLOyL՟{f3yzk,h3j^ZLBθkS\ҼԢ}AxJ +RIW.R_V_&~L՗dRS-|JriVf_^̾Рdb%"Ċ=LDd 2PZi $C,(bq5Rk4- IKkX@ 7@kPxv~Zy y[Ax{%*0\j$YFr,uS%+W5l۰*>b͓eA'Y_;m#/6r6bצ#I_߷txQ6!txh͚4/5uP4Ms96km4gڬyjҹDL$k64ӴQC3췡8ܻ~xgso0쓚͵sQ|[JL«mђl$\qw-27Wחc9 E/B|R^JvE0jȶIyV JE(M*=4 aN _*dE&xH:Sp5;SS p)AVM`l%@¿mx&83I"&҄A_,؆åV_<3e}6ThU^d^$&8XREd`YKeil 6Mu<5X XX4DIUVajH-tQ@2`6U*2*M[TyXS*(pIx.4"~E0v*1aIKZ̘:4v6OB`O IX3P 0mޠJD"L lJ%N%sh֩bA/O1c'3&jƄ5z|ԉRG^ђ+J/ /Q/s9ϥC lxx:ak|.oL"u5~iorA6e ϥ!@ۈٟw,_DĆ ]&0a`Y^`Y{h^i\e( QhFZ׹oA.BnC/vS 0c]D̘x'{5CCjySzxKkQ`0WZ׿ TT9mc{*?D%3;W"5gJ3d[j1s#_[Eo%,AW WAIK j2Xԓ0_Ac:i6kL'5y­ "K5Yw&t6g NMs"aUK@Gsf~2>jgwPg{=y27֤U|cj4R JL':L̿4z)?׭띤V(t9j r2{稥1cѣPZIri*[Kk o`|J-KFS˒X4>&AQ<[>rkt %z猥 dsemc+ױ_:ab[F{wr,W)f2snx]$/"]5tҬ]?o=X#ZD4 BJr==tW:X:Rf{{.̑gؾ? 3{;i,~櫓GMKkWX޻`iBHWG.Z1`<'?o뗝`Po_TJtycG*aL@mwyuԺ ҃TRj]U*NA.NA,NI,`AvPaWIxU;EPiTIFXॊVܠ`6pyxyR*|FP(c-FBM@ZBvҒUS-PKQNj NzU;i> c U^@o*@j'-lU(I.5W|Wo*ɕ ~;6X>^6Xj DgFwIV|[pԧ9dR]_ۚKEeDa!WFSmū5_3 Zs~t5ne ,)P_; S=Vk]bRKDža<K tRKwU`V3,G\d>6JPufZBb;ը0_޶SKTe#eaKtvJ+HSZj%Vb} Xy}bN0YmjjkgW* V/ :U 8A,~g {ʊЅE o)}/7)V")b"_ sF2<_EHG@U^C/c,4gA,-A.@!jz1 Jgڢ槥YB-,#/okb1$ )!HH5]ԗЃ`Y" <No xibYQ0Z ۍ@@-NMIBeVp܀pu ;ʫē&BV(mt`%D ZShAo%noOf RUaf* //:%L7L ~7aN ·IV&>V` (~Z3NpU? R0=KI*xuCuqtTBCIBj![+QRTBJb{[mYqy+0_:#\8 ZSvTWzY*PF!QGҋ(qRXU$*=jEFdv>Kˤ,JFLbfQ( VGq̢H̢8a:+ҊC%Z+6(YRj8Dę%Sb<%^j<őxC2vx '0WQtT5?>XžU4Y^TY^tY8o-7M?-8ZvϧwQW)QV-Z]-xLV[Wŵsj4W<6Qӷ~Q\ Qq;OG᭿~4(|XT.".vfKIl.&}DEvH/3%^sgx)$DvΨKSU3@ۙ/)%/Q"/~qD& 0n$vKlJ/D-ŋ ]8W;+Dky.ś/U^pw "_B*o2pܲIT @ۍ©ۙnPӝFbI}9Pغ0um1D%4nF ` CF b^sВ!b.xk4Xu6l{w 1`ʋa zl!{wlC)-M[0H°@kX=.͹/-rxg + n)0kpyvYAw70x]V*_lQ|q U;cF xIUb5aݧ;F)@V3tq T T[:<"c*׷|8ս Pi,nUyX4~gٮKQP iz)/7/a.!x^)1{\G ;kllN@^27iͫ62{ ,-npOHE2ˮIހ:xfpIum8[{:^> ~3"Rѝć+i,.35qd9o!w?:HMbp.C spoL_Hяk{i Cmm>2$)Ӗ@HcZՇg]>ѣRW>5mS)114$^obZk~_X#.I.#׾ 9oG,Y6W=H|hW65_f9>b~ BI,&VG|E{ߧfטO; o\yU1W5Ɨ[ӗYa Hf\e)|M^RL܇/e<;ce|# xe}ڂmLbA-ҕQXGThKO "KEwչn ]ESKe}{-LOVoY?dJTdQ7mڦjwb۲NxQ)Qi)jx4q T7KDq FY/Zw@QaԠwIS*n0Ma0zbᦱ68G5V6o%hwpI. ;ߕII_ӨMq[L=*i`]zE? aw~C %V_T[]m_w˙(@;giv Ե\ҿ@l~v"iU-w#UE V7~$8Oft|ƾ5٦E ɥ OJpmgo{+"a$]E8m;^k ȟi?{@+V=*FȾpKXk~AGʽ?na M_4(̟Yv@nw?S5N2}e4ЪTU#PvҹSx1R^UUyQVU¬JS}FR@EZ ,$OOaT!۫*e{ !HcP!+d{.^a)vXZf6q('E9ar*e{ y\;ZUOMT*]f^ms)յO1+ȥ9|EH ҽj{!^q΀rO5q m9RRX`^aqxk:D׌<ŒpkKRX8 ),<{^q)$ԡ=ޥ^\$8!+淡+&rQDB"W]nL0Xa$caqS!+ /^aU?hAW */J ;e$k 0I+¡W(݋plKT 3Q6ɶi@akW'/ڷ)/AoS&oUdM@2W&sʵxwYJfWiKi5 0~D"b('DM"@4Ik Dc {UklJWt$I>7iUI#'o$&aMBCM:F$DȤtN[@cNƤ,&DPLD$HLI%YƒL]pIg%0Iso&]M Tn@` L:ITy1tDL}8~ Nz6N:]sO& tRzNoI&eQR~d"@d-6gS8Ƥ[1UI7@b{1t&ݖIg70Gr"&]Ԥ2Nsfai˩DMJM21 {I:K4/yIKz4-T9.醢KyNK\) K눥ToIz '/C_6IjdTT/eG&WL LJETRc*P1Jcpڎ+&WjQM0^`M*xxPR (Bm6i#`)A`VKZX-yCt}1.bkT -Ij'yvRh0'Nʫm'*\`'*k* 44RԠ\iъ͕JsPm0TOeNZYr0B RJ lb}Wm4VjSmSC _RR2m$@i- VB/}xxU!"%Ѫ `D 2}2#F2K6 O b^7)(ڜ-)#^a,}WRcYBYA$U6HuM]uAA+*')'H0֓*#5\Rea`Y"&' U"6KA̭6Ѵ*V2XZJ ;FU$mNihakvrS|,L] c D^a(C xGDc^ M`h+ z~ S1H `-wxp8.'PfG+6_^Qzh|. :k G` DCxẠ@tua&#n_W 5W`9)6ѽ{B4>_ؾ50e F0A`,L'a{+Ud}Gp^y5/[8 2fV*QQ2q[ӏE57B)70ТQ) 49`A 2wv-FWKʊ(kvKS9i B:as亖}`墬3JEdECZXdܤU5_j%Ve.I `FyI2pA>1G9 l؀fyv&u l`! o60 ! 쩓)r ْ\8*umo_μuw?&v_,JgyNn _~Igܢ#{e$HφLqɷ|S1w4ygYXA^~Ԍ9 ($21Ntƀv` fs47VK ߈i(P-4#70= ^Z$ n5xSbhBJ/# EI)Gg<+^џxV&}r}d3czi25ZʟO:BIlCY\H|y|yEYR*O >I III x0#p0R @/30#0#STSTS `Tz) H#!/)R*) @Yf`F0H[$0#f^T.3>*`F @BS#]y p#8,pK@3QA DW@(D0 A@)/ y B .0`t!Rn,k *Pc]y =ZTPn$T @EWH pFp8#<>ϗ/I (K%ؼ@ &4(xn9@ gFR /F *@#QF9F+PzkQ~iP]<HauRBX`Xj1"RVbJEKwl:PӁM_ŀהC ^T w?dޑ4j&V"2hy ߾A0kdV*b? >-9t[WeޘgmJs ⵭Mi}&fH"3$y0CœIںμYo$dTKt@qj;* X4[;f8? 4aRA4aLU-bQ&H L =XGb}WXSm*pު: ?p]5 O1i{~y#&MlMLEץJ's/|0hxxu{[.@M^~->G[ӥ]^uXZKXLpQEf"] ̱ӨM&TjBֿSn3К4;ۿ>,{G/8Sv~ HLJ0]`ۭl %4̺xX>baj)6$Ֆy).`mdV/]zٺ>ǫ~*r9M,TM&bobeE*y էC1v/I:51CTο{txp}[ # QFVg-VwGTyVwCUwCTw)U-VGZ&Z&R&R& k8|*jbMCjjb|VƯj.jbjjV+.U|TMYMLJ5qXM\UM\MU5qvd5qLĕRSM\-T5q}*!|pPM\R5VKoRMYMĽcQMo&n&.& &}jbN[M\Y8̫X2QUGX&!7ꄫ6I'ȅPj^&Q5qQQzXĵUWSUMW[MܫSĵXTOXj⮥j>TM3ĽUM\_x1BEХ%ԥ%إʸK K"RRPK]JK] _A%RZT-|' Zg `P`@' ʗ~* /?u-?A  P]JPPi11 kTŽ' ; XP] `PUyA <@(upg PB"*P)pp P 4PPCAX@3CuCCoi} ETB" & (ȴ Q& NP@QA' ( Am'PWppz 'u`qr*@r•('"s^#sS%@'(hs5ߔ~*u$fT'u`ƌw;RAvۻju .XT|5_*n8ϸ.(@g$sTy[7kmyQC@t^v;<%EiZEiFQd+QEv6lLC}ez&QBtC-ՐF2TEmbODC5A[%iضZ_M,qo{{{>xGJtDE㢾,:z]B(QM!m.} Ω N$[6f~ Yz+$cyqK g $J,.SPVA TRpwV´@iZzs!bt;U;692輻HCEMQPZ*M@P1۴kiimCMm 1۴REKTP_ lRi)es%@~mZ*jC @RHKZY;jjVGB\Rm oou]]4J 1L5 T!R%V]* ´ULz`u0E{1lź Ù:eu4-pZ4Vxu$+O1#Y|[DuݶzןD [/ŰPq@*͹KT;b@*: H0 fzk0FюSIRBdU-ŵW.#YyEMEzw**HVa3~7ͫ2EmYgn+6$`n‚JġF[i~AJ!loܵo\Woq1R lBo$q%Hbu 0]p1v<_a#76׎_zTBCo XK 80 d*s8ٚ>' )TBJ.0Ѝ=t0+=zL 2xBk]py@W@R7r%-ʼͽΧJdz C@@.by|2}i5BSQq>2큳=Rk$)C|{mɷ%\b}K9A~@7CoMf`PPM^ߵ "p_P[.2HD@æ `cC̏jZ?ވE TBƕa\P@&'r22L] 62 0/ȰM\ןGvS'x],U(byjGEb>is;qbPkkV;;yD˫WTh^[aAUP|TlT6USOR%7qe:ǹݲje_74އϰ}sUYlf)W\%6J o +q[k!16hJg֗*'h:Vf>WPUʕJnY:X%J!ʏ;7ʏ_VHVanM 7r91*:U;Uwg*̏)œ^XV?Q2v̮u/b HOj8Ur7BM]^*=^ RbRs+|j](ΠESlEz%Jz{ k k Tз?L 6%[A}҆A}Hs޺Ϸ7x*$e(ꓔai=y))BCj;y[}WTLGqۦ( ZkO˼49Rw]]Ǟ8o5LI3C<ߊ|ZWDc?IJS|%J>y/֒ΟV̾I:""a)j; | lwVv^4|[m7Oޔz ׶3@{\z^ "ܰXM*V XMRҺ+":2џONҭfY;5}f}zr[-QYEtTr  dD50Gu}MIS@'t_=U⪛DU'<39JKGΦOuo]'W[ d4C56/Jqz@/0c"{xpUt&tFg=[%^k}.T6c;ϴx̀N  d%z? v@'Fa]a 4RFkT$zf=ꍻ JKYI=RYrTqPq *TPq\B11%bf%/cG wG4J4 *J QNa2%8GTÆPMoDu_ZI0{)-s 9~_߉$|#JK^|"{a('^**r*r|Sk B-G-*jmqBkmVz]pi.KLUm>P i=.L¨Q˫8Ĕڂږ-QEKN- TѮWX*_qKk>kvh񉨢R(hpȥLE.n)TV\5SߟR•֣"y_]ۥs;z7ׁԫozus,]cbCňk)Ze#+*Z ezgKPT *`.6DSD$B$ A Ɇm"YPu4ͳK*J(t[Y!zzR++ZYA /Ě5nyz irm^-8R<0#Ħ ,uXm}la45|٤yCOsZY 1~ *m~h9@^):??/ UlskI[ 4t5쉳UYk+o2*UʔCN}h]C3\ Sb>aIu'n[bSbF`#FTȌJ3oJ>}~gdPQ1\-jKhT \*%PC*> Tlj);R Yy8IBEJ;2ҬB|ƁRT*+a~֘ZHVPaʎTXSvHÄ:eGk![*ev{ؘcCKTBq ! yedGKud1xd(c vf|=ұұϐYgt,/9 !rp(c4FF-x~μfؑf0Gix$dlc>+{EّgRd }gQgRU A(F-P17 z Cq} ,+ZJM#"JK|}#{{>1֓ bSRXNj:"Z",LzU^W2J.STg˚BrQ7dTQqeR\YgVRظ2;2*j\k5Ǝ/Kƕّqe߲+^+=s4cgWY-T)nYOyFoPoDZځ~0̑\D#Y2N"X%HqQ>pwpw.`{EqUK<~=KnN~JoKJ_迵vubB[[Ċe;Z](8vVKc Q>08ڢTL79AlSܕ*)u+qV$@CI [b:S 1HeݑVhbTdbp\fm{$ІW!y%OH CD>X輾2 X`[уỳ */w?8a!Z t6Pf_8"Ҽg_\3|3Ew@z(P[(тqQ,W`T`܌ Z `_f`>f`< ̗W4$;cӁT̿v0 ¸!7q7~G[+sEEpPk)ڵl-ҨRApRTJ R|!i^[8lQҨ*ҨjҨQ ViϷ@KQ6 @J戲R)q 7-0h w˗һP0nܖJ[2X [*0Y\I֗6lޣl+BK! h*^jDrdyq$S|~} _Gvl+l1w98E@c cdo4'Ӂ1^MB}dp^3\+k"ڵkVT+IZiɏjpqtʢBȢ̷F"ɏ.7~0Gq.^H(TQ\QHr(Bv/=i{:z);Jhq ;ڰew 9Tޜsvj3eGɎU(mlw緿ޜڛq?O\o}]gJaP<lPQ-s~iFX2F^Z'ЃK%`T[qmR^m [t_knn?!.~|"~Q~-`J Puoߵ>mGY-u_|8>k[m?_' iv=Z<oR݈=Ϸi;jwl" ~[ru{]km5uE:5,-ہoǖ_>7/O* =Ww @ OÁ>p=ؓ$pָy *sms˧ !P;ރl`%_eom\SU]@zHWwmH70zen?xmyצx+__n#|:f݋YI:2!{?0H=z)w~JFQ }np/|~~qDw~mi=z-NY>q[c3M#/˵Ȃx@N" .سT^S I*Ğ>zŽ"R)"HxTj#nH"Ćm<^T+SŋXbRإ/2ja|)Z*Kyy[2J{Bke{`IG%%Unk)'"LFA-ctzBzvG0 (f_9V~n*6|u$rLC.alBRm0+!> =06D cuRC kE .Opo}IÐ{~bG C ҙ)|,W*<9n64 %(TkȏF\"tʚ|7-ZKu&π*L 4XV&>0ƥivSY)[%Eix HnpMbd|vl0GkXT/Ǝym`/@R|YR|&XJMjJj/:^Mj f]v8E@ Ys,N?>v矻;;?P!nJYRAޏ^;TkkvcJzkWR^}e踖cHoagSU0;x[,U:V/TEZ>GU_|e^)[Jw\SJyԞ:DsNcgxM-ьuqN׃շ`EvCSPk A_w:sNisT<7jy!"JR3kiܬb}=C:%F.:[>:bq֊ZlN<;Fht*]9Υ7~l֫ q;`$N. h.voV~zMY7?n|=7):7eDjYR!vJos9ʥSEĐil33vDEr?q| Sߏ'O{/.b}{[fBKn!?ՈFz?RSUJOC.^̱_k$_QO9qZrn7.-˼߉ e6nyq?~K' ت_ԑ]y_>5SY+ogOsd+1q][ e][N`^wi:JX/;.k c;]q{ާ91fN?e鰛Bd]މRn!Zo:vJ qJ3oT2v\ZFmud`Hk({Oڮo׽c+k^'5;0wz;gs5DLbJIR)IZH҆IR)I[y9aEJcP)[ʅRJv)%iaX Iڲ$m$-jK)Iۥi I-_JBQ-%RjTIVJv-V\Hv-V7sj1BlwT,dZ]Y#Ҵ+i"MK5K,N XhjT9 [Ы}4-iC4)MK@GjbOuaο♁+6s$,myGbh7YZ9KYZX*x K A>8_n]?_asW98B_DFkwT.2WpkGb9z^H7>رW(`ȿ\Zȿª?_S<%3Rܵ*/w)w)yw--a-JhZ0\* _HO_r)Co0`~bp#pqp_, hZ0Nh0spaA.[B.`]KX p@BTB _(4~={yB-UEJSy- `Ђy#- Ђ7@ F-Q`CTK=av)av-> 0$`MᓀL$`k~/^0`\UQyU$kBn)UT^0 UT%Ta0M1КOEB!R1{^slzdm\ Z R w$Luͦ>MJ2q-=ϧsT{#I+W*Uu6 VRWeܲ'K4R"ׅqէ՚Ul2O}>,>ک'3ul9ׁmVzJZ[ i}Nuz)BV~b.%K9jƕɖJm Iq[d+>OB\T+;IrV+$o"Vz\<=1豰]e`EZ:骘oZ owկwPzRũW<5X}?}3|-l9>Ss=JnLO87>[kR FrDլʼnQUg*OT Ǡݗ#|~.<5PkqXj8,5TZ* K JJOB#Us@ZѰԬaJ5,аRiXjB&az^H՞Ff-T96 kHUmؑHFvǞHRiXj}J;,5TZװԪV5,nR MR6n_E3T"J|4xUKm JAs?i Fr LiKpۉBvfҍ8߯x-/7ߣzgGq}}4,a(KO F[=cI_yQNVz\:#_8e7N TXfgbrǭNmǵ3%fHHn/7L4s; U TK7bN*Gki1o).e*3W8Pzf]~L${ nN^ӁBwP*λo.6<FhN>Fq@5;jG~*x_?#ϛELT* $_6Z[ *-{}~oy@H *&AISD<8kb ;iTOm4BC3$8!o?pľ'TqmA6 Pw PP9o N'x-|y@o?>w廮]&T/ _`8fN*T=m:'{F0wTifZ!٦VA sl閭bv0Z<A3n[y*vUPaުB0G0GRMeTi`Qrw;1IՆl"8ѧ'&Gb0 <|HTo;ɷK 7TD |||g*#H|C"o"o$,E$,E$ q5o7o'o"o[Ho"Hov$HouP Y(е"BP||7ZJWT(_B [%oe/(*@z%[Ho[Wβ =VҫHoYHoHo%^]wHLd^\3Hx*Ho zyV@zBs"R rJo +^B魩 t\(}!QW&W6B:o=#o[˵~FS> [5⯌X,[N(7/ӯ%B5D1"R"%hClWBkyB \ 9퐛*گC퐿J 2خ ~:(q,m4s -h֕cFrnnsfn?=%B &d qWB&o~<5=\9!; lr+5 k:De&[[AGewC·D!{a" -RaMc/΢Mwъ f>*#ěƷmC?;-͚fMBVM ߼-̭i[H"UI[9[nZ9xmmSw6GLӰ&XK~7ǁ.Mq(㫭,&r%BaS;㶾/wldk`EidNK͘.u4q Yؤ-nw 7!IC[S?GKh Z !j~Tʏ Q QP!?*N:$|b)d>arZ9M&䀜 S,' SOӣZQTQP5 EK0:_okC5՜CLCZȡJOC*vDuSծkΡ꬛CŎȡJSCovT$QYRԯ>@vDȎJ͎J!NQh5;*"hI7;K*);+ov+uo܌u͖2zA4 'Oħ.&>{vSh G @H$*vDU$MJ5{WS3%>H:4GgrM|I)MvqO7254^?)MsJStS1)MVRbjNU7)Gc8QNQP!AZ*,K%v|_cZmb-$7K%P]QTTȔ @m'VVkTȩJ%/RfLR2CA|(6vNiS|"qN S SDsSԫQxڋ xw}H8f \P|! *c塓/l\!m ׊:#Jp[*%xg[ y`)Ds7MZ!nr|Ro 689\&qT3'3ՉwB2X؛ޜ>mT/&PA l)6jϙVkrPpGf|[kN85YZ=;'xW3<╪6ǫ+I^s_xJ^z5A+JUrZ)"Kkrӊ&aee‚wa7T7G!@TZ*Skf*/ͶZG8flY `aԫTۏt}>U>'v7@=i&@}2$C=ypjMoHo65ZMZ"o\"SNA,HCdʼFf5%l=Z 2vx><5DJ!2+r"tLB-R(}#N_C"FJhz8uhfMBs̚jBOvQ2\JqTަD*䮅S/*C UG296[UʣV|5H5_s T4b-U4C2d4bG+ӑXB2dߨQo^+behJqMtfہe:c|# is5XܫXܷ 2d^s2f*0y)C(C$}oKoMbn)]9%/<{:Yr7 )$;%h+{EO!d(5?ݾma sl{q0mB\&Zod ؞I8rsycӶ3$WpDo{tt_WVەW{m؂c_H)znu|m/KCb]ۯ[ie0ף}cvZ\U~i WJY>{lbA<ꉕiJ0ܞ-MHYH8~W>?GE\Om f^cx[Wj{Y~-lTt\PExf7?ϗ[iX->Vm{nYe42/?*^VN;{d׫ XkFo|ׅmhdoznɘ2TQJGb@ [*ꊯ   S .q+*-xe`?i5u߱'4qk ~g0.:-]6DzfYJKлV3x^k_ŎI)ߜn"7*@-lm;W6[_cl~ӝH`-Ձ>"l` r^v^ط /l}8`8nS:7__,^P|W\L"^^}zl\MLH+ն fX\ :x_NQj_%`~|Dc)Թ~8p?/>nZ?Hw@V)G憟JO0j91-?8ߞR#޷}8 kT3TmוT{RIUM1<>M4*u m;ץ!߸iR6} LC:BeH[gnߨ/oJ3RgjZܣqbh5T_`/\ jj(k>#߰?!֯\*e6Zu| QLMm3o7/a*_6.z=9}gB$DSQ^Zk meik4فP:P?d1dsIbF-FΎؽGl߇>VFJ:ܭoh3;000CVrn̉hh@?kWCR6dsgGgٺp _.Yи<5aVn{ خ{іXoȖPٲʇ~ ]-e+͂fVОYC uX׵:ϲ"UeJ94( ?mk93K]՟hd+  =.w53]ϱ)ikԡݝ]K훥z8̏l mZ}=izV٥,n{ρBi=ꟚDuYB+TR>⯧_]YBZP]b-?uGuHt~VjY~K5m -!kW2z*/utq|ųkSF+AOhjæzyT?riֺ l?z%U޲u xҠ:0еT ]CuRV;*J.noWTj?ŷY y\JF9-Y.<$.QPGݰ N%t$Ey6sx"jB 3RRC76ooG@L%H + TMR;4~[n"~[I8jGj u($ԛ9MREW~(~Qb~,6Ilxk\vAr8i@J ?@I!/Bc}sb}^CSkMFr.#o\)ЛOMsMP *--WA"oTAU >7BxSZ !-0"nRHxNJL09 Rp 4rsHK9X sHj΁)rJC´RliX b@i>)\ѡS.ϰs[aRܰc[TၹVGJ 7%;o]#0ah4sed:T;>i]׵va"(OwonԦF|f6^m@wԧqNӪ;F6w(>} fH:Egh(7e-*ܩynN =8_SC!&iIS;LƖ8&;K})6w|sr 8 Յ8ůqy>(F,SlY~LMitFgJm:oƏ) 9fʫLXr ELh;A'HIR * #iB#ib#jo9~qM&4^bU)|}g>dƎ%_aSc8\o4Fǘ4 F;ke: b2kpJXzfo5[l*)MzJ $Bճ:r"s#975 ͹j6MU i4M㹎f+\k6w%x /;5T~Z[Hvۛ=@8Tюx_R)-u,r~J.vD+SpNaFqPǯRw!>S_Py]8.'޿ߦ@5޹=[v#75n [%֒kټTFty7-swϬF%>\?sV@7NZx&  @tQ?so=qKWoߺT#PԎ}F{!*4n[pϏ|e]d;7$ٴ|` yYjӿgI9n)&sWm[qp)6UcӅM郷GxcS=Hv?k)$ t6e~{wI|`Wޯ0P3hJI<Q`Q7TEP!XԵ? Y.>粖;bE1XN~Ϗg( ہn4so+Ѣ\<9?c>m<S צS9.Iפ5]tŵo~m+9xIPP nh Ch I/ q67uޞP>'aP GJ0@saRy &HK0X *d>A %X Ri`*wrbP![ b H<0UT_SmͿNiP'[s>-籹IZ\!{$nV9EnŽkIMZ_%N|택z?@:vΠBBTJ['fH)zqTo??l[e\Dqk"ZqS·Y UmnB֢jFj5mdOX|+WFhDQp&+v%7 (kH:XXm Ogȓ᨟(E~*.!̄p*"Qp*"-;&$薂ppQPGQG:GW_8HAe\$DpʕpAҕ]^g uL"w+X cXRE$M$[JJ`I} *DBT*Ag RmB0HeK0HU I $eC__x/=%I iBG=a.QŅ| ($$l$W$JBHH^HH\k-HԵTLHH6Fк`VS-v)h̔Jsf@ 2RiL%4AT S4AȾd!ڰ!6,93&ȔyLR ӥ4A 2X dʗ&@Q1AT CCfPiL7ĜC#5e 2jM4|"@f2XT=&@1٦;j mpB^puOa ``C̿![N)&1Z6Ty Vdf̚qfny|f1f5Y)`fMŎ53kp#bf xyf nL` dF}4Shd4iBtRY?TPi=C=>TPt];L<:LlDW(0Rv\3.";F*PjqUV+;ݪtJ3԰_TiMO+|zZ!:(m+9] |tlRR*c`&mK-$j|!i I i+&i Նq RMڂ-T'*I[I[,I[դ-BVڤ-I[P!i >4i{"~"jSS]}bi I[ 9i+l;"i+jV|{)i۬I[$m!9i+mV>"I[!iƨդfJj&m{8I)i˛oTKJbPT$.@#ꍱ#@r~?q=mj%C}Q=Ԁ-c~WkW;vNoYjYTeRՖJUPcٽt`ڝSIXj!1v:dK#1t? T '_eIRڗUڱesU|kl6{JZ [ M}qXB\ik]j\֕ X{@1*ҵ+QMvL|Du%Tꨋ Q+S amWw)wJ,#`I!pN%Rˇwa:vpɗ\,mqOqIOׁQq~ʤ?BǁmHhN%ĺZ,[Sqjqދ- *0nٯ~!ЕtϏi*յ7peo#"\J)m7ꁚR]_[8>klsѯ Ml>]r N□|^ǟ~~܎v.tv~\(ki_czp.'=Dy]:oSyr!TMS[ 뾵r~JXLLS{9x h&v7پ ]KoesY]ן{?1~y~ ,(F}-#d=K4 O[{??$K^T;m gy\D[; !^ޏy=?5csMkX>u[I:4<%QrV뼗Ku)k<:F;۾UAo0S!ՕSNpЂg,NKD0.hSLWs7 M`ؿ9Aā;w"pλ6^40$YGQ,DcTM3(0)&pL1\!χy_͗5j06|p8pܲ@~',ߘ~ZoW"No{I: ~Kq7=I=V4Dp,Wxv ^]Gy| ])߬/0("a勫2H9:=8GXcRA%R k k )TH**/$JI@R@U.%.%#lX#,裲%J *@R}QTGQWD*AЃH1Եdуn .Pw. @*p`f.|Dq!pVpDYZ\ ͌ [vD` *+P1+c"O1gܪp_*31 " C=@ B ~ "ECK*\pEQpE8LRW\"i+NKCGDJAFz uG!Gw@jF4:xB4MW>cZE4S 1FX FW ƟKU7ͯXRhأ*hv4BoGܿS'q).:9˽:9K00?hP+TS*;_F;v SD`+hkŔJ)$2 _.5-Ri< E[(dߙ0}PDWn}w}qϠnv={|ߞ_$c Fhw<][>!uR=Z*̄_oﻷijNt&$qyǑK&4l77Oך~Wx:QqSH^졧L}$>͇ߠ(V@kGup<U-}Ɯ˔?#wBEW*4 J WaeͽzCzC>G{+5>ixPUmme FCXੇ}}B@OKBwK=n?݇Jƕ?w QP|cGض0~,^.iZi oNS|c;M^_;_4vM=$!c0=`y~^K`em" 1R5Tڵ4,;b j ,㵮[{ ^ڵ4xTZ* ^UlPi-T.pW^.s-aa+#\"0•Spe4` 0蕂ȠU|c_@JϠ׵~p`+'#\+TDR_c5c+N2fqMCk/@Xz 褥o0د #N NpMd>m gim& Y&:'ߢT(фsfB93Ka*˽*. S1̫pli6Ll]r`zft-BP l^#fP I`K/*+UJuKa4;6R=Ə` /;Ad`-[  2PTLۅP[*M鎪1b dc'pB5&tCM SaaLC 0U^u0֑|{*kMYW11D2aXEG a42ndp/.VQ$|a dRbc * ;t <*Q A`L4@W5*<@U13d ]naf(j/Č[ſxc SS";%pmdA1uνNONnF*^CQ3Z -2Z|bۈ*n] #nHl$l0e{yÅ9a7Z3s2H/eh*<7GD@sdu8惱#ڱ^)rf/$%LZPSrYe}` Iic9m,)d>}cҚ-)o, ayc 2+J0fSVg=e>9+lYCCǜܱ K6+ 3gqϹc݈,>|U&Pg2v_>SYbHY6Աc?Ա0{M[Ա4IūzJJ3G;f4g}sWT䂯&i}cW6.wshK!I+曤$:tT:Y4|bx-M-v9TZꁝ;S oqV706K6FP6Tl [`KP6Tlh $.5ʖ-5V(`lFYQDWwXL[[khn lnՆmn [ԐZՐ6.ZٶZU)aVCŶڬVj[ %յjj}\LGkkVK[rPZVkkVPkkQ(_}~iZ ش:Sv=2a D]y"k5v ͭjt}-I^\mnPZUYlV[ګoߨU}cV{]F&ݪݭe^ݭUБ,>δuʲ))[P|\;e-JS6;SYumdSNY9vNن%-ݘXI~YVOV4M #YCęRX 5T畊[KkkI¨nYXs\vCMrL5ke<00likW3 c_5ZA4DR[0kok@,WRek7W0p &0 ][5 v\W\S !0\a>cl(i+ykyW<+a+\E~q+z8W!0ӑЅÒ&V ;n_y1}<#Cba^Bk0'TX8:b-ĉ1q"G ;U&R&IH ѤJ4Mb)LsUD8Q8T5s*ذ!U~L'?? 8?ZӝUެpR ѩ:^k:NAgZۅLA'{MiC?8솦R熦.}.<J ʥ&Նk ZЯC`X>R\iW\_[‚wRbvzyʬ8op *҆vkpÙSћ:V`6liG9EƊbEbc+^i(J([궒 _du\Gnu+uXŝF|z\Ev5sD)iD)MmDytDy<Ɲ1q,6qdN<Vk5cqoQ(x>P-7hg@Rvk8TjՎ(MZh%-`.VhY[ "-c-LZHF d`,̰6lqΧŽ8-tBZj+&NGmHk,S-ZE?z%'*jٮl5R}2},K -ZsVr]K eڱeĂ$k]׵֠KOc*6?_RfcPG=˃~$P%+5~8xϷJX&͢yKiLa(ʔ>Ɔ(7C#4|AjcYXeҭ6Lg}>'t%fa} qZ[d|9^RȂd܅eY?w6@7*;D# -d,Z"bpqyoqgݼ ~Xt}W&`ʼ0Z #>Gvَd.mtN*ii%ۘ uX@RoT$fC%bڮRi*lwTk8k%TjvƊUZ*uVs cD*S6%.v@jK%D)3ZK gdZb@qlm y nd#!H~/ѪsSeYYDm_蜅a+vDluM}e ]E+yZYahe>Oa,W<άW6ZlW0<.tfqtfSa!3>.d k 7\~ZpDH,O,v m:x]ۀ^yg\?wࡇVWZXZ]ᑊl&֥B^ W*S+.1;Nz,vT;,nkC̘~u2c#olӬ# SY޶R6Kmb"f넊uB:B ۄ4kiNO%9=B*"2IS*c}^ՀR U!u- 2IDqe~Pw U&YcbJ)Cp&Tc-*[bך@(6fa-"acPQs *`@IU1Ila~d \ni`2znY7ϔ!ܳ2 #1?;v~ؽI\àj&7"\-v/30H8i0ۯkG!C8qeu!t||.&0kiC`ue=f~P2<b-M)ąy>G d_? }-4ޕQ}˪}pƒ|7"mC>x`}KqC`3O YcͧNu4S)THȂ-tςQFTBTƈ 1"U?O:cdO=pqԥO]JOaOџПџueBʎu )Tu `@I+@ITPʆPU7w[29OH0&?SSB`Lّ`LUT1R `jY6 fה`jeY az>?gIG$pzGAi&26Tż@j>Q<'HuoZWoDJH^ JB(c^v/R)v2 RgaHlSTM/lSm*"Sv~y^鲕?nS8:+nܦ>PTO"&y"26Tȴ~lEd'gu ;"p…$gpjm*ӄLĖJCbVGlՆ*lJO1X E0߁V.z*籭:OKA4g:*8Md>6_j]EᮔUrÌmZJVI iEi{e:X ؅Yro؅)ΩSqѭnՎHNѭ"B ?CYJ2 xP\c ,eֈtp]~m}s/wrXeV&we7(+2,ʜaԇ vXQe ,WR֯2Z~&R2"[օ>L[l $5U'3* 1^i+]ez7] igԫ^JɏW |6Jnfv+zJ٭|6=CLJ? xw|~V*gS P kKt6lTH)R)y *$O}a! XA+B|Y'Ŋ bՆMjäXTS` )V)V+BK!*iUk8Y+b̐Ƞ$26l3C"1ߤ vlԯ/vDWtdZctBt-c,ԕ 6ԕi4+x'cSM &A c,G_c3?'eM6cǦA4sl5lZidiMȺF.ȼlLfY~3R""k>yA*BTx`<;s͗Rh+)4_J9 o׬*听*5+YՅjMYUOgk%oL&j`9JXN"S'y%ħr/%~PJ%& KfRu߯$TAY lYl!/*Ad%dr/d%|#А#АB=D$u/ d% KDOfRT*a&a-`&{KqT#X;%xa/ KJ7$~1/AOs R+kkY(%X,p_Ž_D_dd%>z_ /%K`JP+پ}q1ڵ~ %8]&~0`h _ǴI<0jD% uB[h£KtYk+O_W9фSDDm?K_| %p_%O__3D u/E9QK]`rMS~j} 3snkx-i  (Q $O 4i,)i 0HtS62%j'+ ? -QJ'B-28&P!O]ӧdORN7R8fNqS^yS0ԴiWB. IS4gJ0LM -QSRsВT))J @ʦSK4gSkIZ\*>T*I7kG;Qy"s7E} nz<+έiV^sO&>)_Sl'w h괒D6'N @ӦPfM&svҜ_S+5c˜04_=MR5[xQ~$Kq $WwP&uHBMOIv!RwSIť'>O'}Ŝ}Z#o{eizTPF8DƆ-APԷT7 ԷT@}˗@}+ J톂ņņR-[L ۥۥ /j_*@p/fKR!`Kb_In(%a|"`!bG[gR/Ul`Q`0 ڗS_) /l xcXK$b^.j3c%C\{!"pnώSlc|a6 lcmk( uF[Hu W`z#N)` 5E0eԭ$QW}8G Z$,wzlg X;7UjW?74lI6:j36Vh3`ͼSku 'ބl&αYH3lp`v2|XKTyOj凉5gaLfq;1fD:D3hLe%Ԙy͌wab̼ŀ&b`8׃I1.̉͢3b0!fKafMwͳab\ \|̪|g -@XD#G;>\mt̼ƿ [藕2/R }əcK\[^w0\C',1&j0qó_/QAL~7YΊc1:ϙ 1О-N?oxXt̬)3:$0N&_a2(|ctL2c*p'+[}H'BEdRm-Om'-e ?-EFu-/JE*iD9娒~Q!"l"e$noD"r/R\̯OXH0u@9+(G8^).XHd>XHJ%,$ʽ8B' |co-@k 1ĤR=FU"R~) J` J*pJU1W \%(pxmW "RC|ppUŽUW .IઐI  B&2K 2 gGQ[v5L9nς9"KkFOL"LŽLSI@&?[p);$$x@&2i! dnNq$}TssD{ R`p #p_#|;O3wI# M<MDz}30T*Ns2]_CӒͶn/~74RvVzri 3Ɠ@;DOC|9'7Rӽk}(؎Ip:N[G0o8RFzxTRRU`J2u;n^w}E҆޽:bJw8C2bugm*4I'`(=r;l~dYuf]XݵŢ_soξ~9$ i_{|mveˉCS@)p_x~;4 {Ͽ@}xqL)o5~?3Sx3 r| *SSzsxOYA-/p)7֖|;<7f1[kk Q@v7z?lkNgxZ3:i.$hyh:kл!m+D%J .6^nN g(RV~\< Vo~utqpY7D[*+س۵nDSjPl heS1Kz'ꝺS$~k=@N@~]. ^9R5 !R^ "v;󺴔Qm5hY"@VOۅRK'-2bUheQeo ByΨ N>Ɩ2BH=[W٨TåV+5e1ǝ&@lS+]XoKE ǭX)&ӖovFԸV0PX/pks@í W9eD0T9RK n7^yy~ϥBioT[*Jvz Dq=ЋW m m m#cW ZW Z Z8-ht(PP^-{Z-hF$|"JUV Z= Z8-hZ-BT&'L*mL$AUz"T`K-a 9rT_rkrT;rTJMD)ppԨ//Z_Z_*T7lЄ[*3,4!zVhBzY! -lu 51&HOX[^} JU}jPu 6Unqt'T =Ys?J $ yZڂ]Wﻖ^[+N Ԃ]>ќ] 9$!B٦]nX`鱽`K6T'CVQ Z?ZۏCQ ѵv-ŦblZI(6-_M˖bR;cq<;V[2bS6R)z!Z:+zD]xwk<')",'F *QJ\a#`"X(b^^,~n(eوKh^0u˷MVJ56D j Oߦk[Df}CZ F0jwhe>GjxD] 0~1uݐRhȌ0ĎhT!PDÐahmK ό/ R pKn6\ܵ%b 'p7l)A֗l`|ܿЏ720|!Չ0J0q]\ 2z1"BTRj85q,.<ıpP}#T}?_SP+yES?PR00aytLɥ3Ѩg؊ڻʒFv+u%Ivv%R O}~u23ǭHVs,"Z-F'MZ0;B5 ij]SÒFJڕ:;5 itjZ/v%M OZBcߗ:qSeiĤ^ORpi3N v4z98ҞﳃKV11 &[thh47qGD9~p ƇVޘZmP<;`thC{tpLù-3A7F0nA{w2 @ХB?8:WNcE+LӀ.׌KIA a8i'MZhRݦɤ1T>gk\o ~SI"!&<;T+IHZ1t}G*県o/C #vEhGb,3ޮ95M!-ߝB+CH?GZ"Nq.㒕F5ZjׄAr8 wMi-CJ#Q/-c'lQ?1~ޒW~-|+;,q`sT׭N:tcneJiviEU> = (JYu2N:f?mdsS?~Z1K_F6f~60q_Sʃ9(c[]W5gB+3ų,[ϜkF)yKd~ݲbMz:X:x|Hoq;sPX'`~qhzoPo!{ǣk.4*1ܞy۵x~;HmƒS^o4bVq kFj0RiLwl4r&kqNL✘ U|iLw40i2)i2|g :d3M5O1bP 6ĠxNyxJ;foӀz>o9f͔궣TQGJmVQAD_Qp1xgP]ޡv\+ZȷZ*зZط8 5#+GVzө5X SP;V|M#6,|n9'vҌz49ֵ0ik kaQ[ uD6JFa@0 } 3]͕B8W&TP\P',v\? dĢn{AǟpѲ'(cz%fW.f]+;oZt =s&Ѵ}_X[#%ǰ{y*>?G藻`"0]}Ew>`1n͔Jf$"J3 8';hs||G ;hFA3F2 {6G8}c6 =k4A?#j@:KG+Ⱦ 1$ǞdFz[-6L3SኵTpPp\*j-D>-cCc- :j-1}pI<' a,U &]sܧR 6Պ Ij',ѲXtce|es, q/ygj,O|](k+_XckZ̵JpiՆi]${M#/4~2rJrmҴWvn_J\Ŏʛjj&ݗv_&MTy~mѥM-JĹlͷ |Ko=̾`=-ԅB,`f(TolzpӵhJ(VQdi4ͷT*XȀȫwq7@\4.<\kezE s./aC/!5/ZφY*}fyv.Tt0P?\*kV5>5b5Jͯ#Ӽ*I``!`OVs!ABIga}12XK2Xk2ϕ2xq2AV"X._ %La!d=uTB%>+pi冩 \( *\R\~b pY[K/"ކ#r.N0TKm?RSSL.7L֜ uyͅ<*#¡C$8TP3ʮr^Jr^:6p*祳|~)Χ;w~*Q*Wgj]\Rw~%TbI/O/RKifJ/I~jSL(9bBẎ~,<_x 8k!]@\.BsZqZDKV$*A)쎈6)Zm21QKZ/'~Uɴy^aqpEn&y^Q 6*=Di :vՎPL O:2K'D"3u>!.uHuڨ_kx,*0P-(r}K!QDpc.[Yc;L {=R\ޅ ݭzזSen[nl͗ۮu2C6w%1rM*=``(2qTsxqkNIl qv.0)\7 擜~24>ͪˇfU K%q+Hq%/4ckf\ނ{58`1b$g8#BS+ Y7X *f]ۮkF3P) ~ʺwDVR|D)kq'BJJ+>+Tk?Qk4BW!R{M,\i%#* vCERTSDT]a]Aؕƚʅx$6D$ @$ F$I=M$ j$Y"E$q[ F,UbJA1"XGK31"uy˖bDC2NV'F|{TKU8nBuޞ![mNV5*49kirNRT1u}Ǒ>^\[\fpLLj[ 4Vb8}7Z;{VPaLiTǏq@c#h|C)R0X:l|u׏ktR|[vNf p"9 KH VlcH!7lom`b^7`N XGaE*<|߷_S{S 2|RzU55uD5ؙ ̯|n>`mqőV]zy<)b䊡 _1xB5K.~n?QtրF||.}y\h%ϥ7/  ~ %_JpJTJWx1ֺk{a-DX afUsB *6uBԎMnB^AjRش6jc\BXTb9pvc]P]8G9 *@lP!ʖ$N#޾Ѹ6l-CKz|yt_J^K9%۱%?g8G011xݠ^zWyƦUSysQbh|*Oߌ$B+ |e$_Ud`CYp˂ pTrF Bs: G4M#ApoܺqKrbl-ԁ9RWӛv&sҞwf9>ѰTi|}Nu3rvTCYbcYY)ٳfAdi- ӥb4TLvGeLJ/L! $M˽ iӲi7Tk)s: PxaJ @k) # BT?6W+Z*eZ!.ZrVlkťt+V+R) ٜkm 6TjTB\HBSOUzr@~TJV\ZMG #[q)[摂#/l! ؛=D,<20Cbq6BHBT¤S~ 1(gk+풵cF maH-1[0-n($o֜UMP"7HMp@ng+N t9W@Ż<(PE*[BA NR;w; rSe*&O|~Env@nJBn+dFn 4 AU|/ݚn4ŕ R i<@<@Dk (qeLyʄz>[&KLpnRc$@J|H >H>"cix3l[en 7>Q/V>)+ )+ )h)4YnYJBYJY 0B$a)DN9ܤ/`f"&UMiT"`!U/@HќXRq a<@jv@J@ "nR$ RTR JQބV@#e2Rb, zR`puy $?NNtl%౼.#i-q'2#4e2o@/E[-]3jp^Hd N{u٢5zEMu^f.X|\bu}qn ܦԦ Цnb/ TߡF1!J"Q' ? SU L`+a4NTNwóMYYݮퟕVfJ&N趖*`mzVX[cemzNE=zY8~xRϪک:-:UK|iR?͐X X<+?ʠB?+3$[z ^PVP%8m"5SHxs^u'І*ۆ !ö'j^ךfU)iU7>{ s9mQK-jQ.F'қ6zùUHKڼ Gx/9wC?L5"j?MuTfUnݥڰݥ:vʦ]]ڵ]*׾QYE;BA5wRhyZ4;B}νҩSFr}.|ӗ[rՆἴ`sݷ; ~~}m:44J kv\mTwS;B$:B n#zJrD{=}soc5ח:B~SЬ|nb(7x ]a<vW{P}s=sڃz~o粒o5kDsz6v6`U/~鎯tdoڵUhlI7QՇ=5595ڨ뵍SeKC⮥⮥bP|Dj[*!Z*!Z*!.JKVPmܣ̷qUsUgRcJ!6Z5vh*MmTu^Ɛ};]QR2\ jjjKZcZ㮅*bATSvVlZ*ja5ڠJZW+D a(H c54L۵j>Q qbMS%vژZSamNOZ?UU мSɴr7]H t?5D@SˠJ/T7yT75V74f*OeZa@[._h5  qmH pn0%p(I.\+55ɸ6P\&jc}կ$QGLyЈ ˈ7sܚ(?½ 9R^5q~x,wlV;6S+fjELJVxzP\T+M?~?]R*/ :96O뗥F4$%9}iOB<3p/>JIFK {ZĎMlS\sb6=j|yr"ռP)L?Ń3LzH/-0y@.sblr:t:῿ȴ_9'~Td>߅H.E3?)_H׶?X/ҩ=9D޾Lҝ{RTǑ?_kZT[6?N=dFTH9l|¤ۚ^GZiHR{e/xRZd7iS|YCe}\s~b=^~Rǹߠ lO/Ʃ^Y~'GHyi|vJv{eO,Osyamn絩S>H=uAm]`{:e't>/wϖ|#VƏzY[y Ӯ}HHZsMiH'Do|yeMVS`[Muݵ=hz|yTܷTk]w:u<]/\N=w @}ψaɏIL5H3/;Cχ*-BP1 CPk)Z eBP1BR)-BRKUk!୼V\ xKBBxxKT xahxK*)"*3//B(۵BUvGBY*tBR)-_ eKPh( vC,,, ,xTzRaRy> RVT@®BRq7H6HE "H@ڵBOW"H}ݞQJx!-BY5BP)1&-BY5B2P$,P,ehD(3,B(,,Op8ee!/|d'M(7BY8&ྡ,,/9N, eBYXBYXC? áFq!NTwC!0Z퀍m23Us%BAqCY9k] qiybF/nMe(A)b:f`.V.w7.W[J)[B/zIVaN-J{ ;rD 7ݗ|b*T YR+׾ⷀg_[zWzh݂gHQ*//}ek{[ xL-bv|=?1:}M̸zv6yiOـβ5di.^9Fv<J0TAEмS&h}/:.S%uaCQI wR'ܩ/x87D-@`;f+|M%bW-G^˥i:өtiUGlwTl* OsaAs?mO Az36e1nť~Z~ZPiWiO \/vZ0ɭdݟn\!:suKM8?tB2d}i:sy̅6q.phFέ]yfwm֤閦[H Mh啘vZpvZvZ\h7"?7Knt [|#nhи| nwkBBVꅎT^vsG*|RyTUXPgN fJZ [ASYV~E_ѭ] >vWa+.X<Vbyu0Vg 4yB]yIfH]aDqmyΝ*yOۿz\U\~crVrTiv]X}Xe;+ٱCwzkQwĮv '­v*`kߎ0#^ OW' .}"dI݆=z|Y1.V;v\Oq? + .Ob}ϵqyӁ .G_dCd(oϐ˿R4R:0VT+_k ?:T7v`t>X1XKj<BSOcu],+; VT*iƗf /IZmQvJ(X=oS^<O_>[oMK?!M:D?kN4ZNdGUfe$nOCO;=ګqh)`He~rΧj>>_RHp|v}&9Z7.tMS@᱉R XBƨv益ۗO;qoIvR uf)CM&@:69M9Zl'e¨{E8 e&Z+GVi0SFo䘕wZVN^GוFr`B,uﯻ\EqzwFk7zVK*sRmsX(UqϷ\~~0sFT>Ki7Ŏd#B *`%D`ZVJH+֧xU$ X3s*i+aq:;qMwNN{`b\+tz%cz9Ք{ 6ƕu%~Qإ2|8h1Ԏ >uЍ>sd) kR7C.7p9Rc 6V).4)ΛAIe%Ԇ3u8aB4i60}͡n0%ĭ{UҬ&:eppB\*᫵aM})L)L1@Z:':/)9ƜPPUj F=Gj o5M;Z洣nbqj jΑd:Iy&'%ƾ~sjuv7shkV-5\񊷿\wE:MCFәFhGXͨe ]!Rh:q2jyBWhD nז !솶֮.Ѱ᪑KRGFUqhP KO`N7}N YI WZEh ]biIfnlf =f;uH4D ס*yPF0;bJ9w TRҰ#86V0UxOsiN6l[|JqMMeD%ݩccu"ss1:s^tKZ$*W9Vm15֞n1qZm4 [4֛ϴm%E3h2v1#mr& )DZDK1#ǂɩ]Sk@>t0Tϴ{N]}ꡩ[VP8!9n'À HR *DQ4e|!fŎrty4T5qrkc=ǩ1NRWKq?fqj=_|i4+ YKѬPg( RUд6 |Dc]v0X21 Ѽ0t|~<΃`4+_*JChRi4+8 SrǗoUX TaA Eݳ3[ڧr*}}Ʃ8UH enYk*gz~ގ_w|/Zkk*:^^W&`1o/:VH[1B\V 1Jzj V>2̏1%[Ze^vV´ӄWH T.[zk=t5ԈL̏^Qy]⅊yThfrS,᧴]_^o~7 1w^|Z0 Z[Xs3XϭHO'Pۤ4TG^Z9 ]vmkH J^.r3qݗB=FOuɗf4jí ?;2˒L<ƦaOA_Qx}Y!m R DAʨ6^!݆>"옦QvP* D{8%Wpt udǿ9P;vhl?ڼ"n/ b鑶ml9. q/ 25ŎdZI# NZ赂D}xlz:K %?~~뷴B>w/2K#v|^ZqE5⊤(NTJ쉇8~>9_/o@9\;T9L(QZhϽmY+W(iq|"1w>f[cOx|D hu+D~" y7'"[|Q5_e,jaRPFyJGok^PoV*E:Aݸ Oy:2ދkzlQڰQEA{铄|@(m i׮v%a dITU&IeTBFR|H|HT)#AHk0xFk! ;0Fiq##שD M2&(#mm<&+LZԣդB ?gpǤI* /eUXO@7}21LZLtJAeAe2-xf%ND%ZkXLtHIPgPT[ "[,Q&P311Y|>-:+C2VZӼ^͈'|'ձ2lMiSMnT[la[; _Mڪ'$jM3}&%R!oy`zLm9؏"-K0kWT`}@{R&k5.RT(#֎*iLX"B/*8WjuBa1`l`)j)W+a5LY5ֆ|?4f@:k!6|[>~N>mֹTEt1 OŲL [}uT ʌ}6+ 7͒]Z]2m KTcoP5hX-ۋ*6y<2պ7W[&blj\,=m-IZ;6kdW+5vD,P=|_UHd}b#k)}cfQ5fZ۬h\5o6|JJJx $q-ACE0J0MQ0MX¥pvDp$R1;|K bKcK d8r pKYȿB>i!84'E H$a8wvZS &-[ UD!gCg-\ 8*VRCEDXPWpQx=Fw7UD@%$Je o*4V/6pOGZfJ*:?V`Hj/Y@1{!rܗM[I p6D_q XS(JKXWR_{B{q+U])VхE/o,4UZY6`m@[=c9r֕ O~S9ww9MUq cǰjGjAb\-WErP"VJYXQG\ɁYXI>YXl,l?JGjdp,yRR?yU6w-`%`e)DHJ ld,j;J;Jg|#˽Ig~!)+,B V>)XP!8݅gR(];fB^S:WnZ4sUDTKk]X\ 3+wq@SlH3`-ԔRMo)5<+Ϛ[CkPoA56D5/i .VeIR\O4l\)L2iÜΕ)+Bm3vDm3_#s VǘyX*fH4`(nR7KQLi'z7Q+ɣPvBixJN.f_yǫLc-ƱJhOUP!m*MJ;{ן@fj`. QtIcҘ_ ZPcaӹ0\-t.XI_XjUn &)kWqu٧]~Q1rtb)뾸>qWMyҚ]P rD1ҹv43r:} d4Y;1|支bM~{C&susv^Xu2+lێ\~\i=zº3\v8 *$`KjjUTMVVSJjU K!K$M9Lq& BL'%:g:u;jVd~;RI fNNI*Injڑڐ#5+T$'VHEjJN. lJNR^Iz$'IN$I{U\LI@a4ä|{b>M>9R |>sAfd&Q5O'&z~󉼦T!u+BbR0}8 yAͩBORJ"c/׹|9uQ'H:mj;͵I:&yO'7P)7IgVS|2d0`rd0)P+zϱL⫭gʆJU ]<ݦlĕlB''^?ə3ZCL*\+UJ>P9J'l(R `n"U&;eruNͿY'@*U A_n+yц~ v ![,~gw up|ju}ohclN;9r!TjC*>1σhTh3 /m 3;+*SKevcs/6^_9CaTƓ3\+Ԭy )Och2V3b$03aD5̈́g& +^WSRxèב0sN}Ioޟ1)scnoΨ3h~A"|2 ?1~s Qƈ~ r}?E0L@uk&\i3p}W6dl zS"&(`ر1 gl qu;\`;#h&!)".mB>jp-2W4\MP!o~u~\ 2ΆA,miiy%|YV8 +.kLk8 *6Tn|ZjV-_hVjV-Ud) m2PH sxi_ѷɴGOl7PPts#o*,j1߇7CKfN9ZEݕ2kW߈ЮOYZ> spJ)+Jss& =+讬bzNPs`hԄL1cZ?s؁wfnK ܯ;Kl> =kcZ> G(Ach $x@L3JO#* QYhD;B#*?hD$h)Qi:cnU2UU!.tB0TS4T|vnUHxVU0h)\ :L(uFCd0d١F걤FqQ *`Jťpb=<ܣ;X*F1$b츹QYd +ڮ.4Xf~nZ[ORZ ϾZ`,VX8~=GDat./K X Bu||z#KX8z{Ze1<+^?1 >7e3Mg[瑻Fq${;^7_2֎2\ c)H|^;+i}*@RՂQY\aHylNwfWW?O羟Z=, Z*SKϽl'+x&buӖWYmM[Y eu\V\ T%]VШ88۩긧8D*9J8VqwXx5|Neb3p^ܕI˵-g7-wT-g!-GMT[LPלP֬cKUs= kߨiYJZe)UsCr9aifN9D)SjJ"e݁QlrvSrU$Tu˨;&XWW+X{.9'AqBq6S sq}xq}Ը Ƶ%WPg\@qWBqVRRTP<\eBpFp)*{؉v|euq_K(.֥ ŽPYTX\QWU0\zaMR.\G^;;̅5km%*' j Hb$)wHeKHew>l#{D@H>ɷj$y%#`$$' 7O|˓|3lFo#;оs[Nb7;~x33d^ $0l_F_[FHw~fɷFHh$ ϸX9@·}A;9S/]ϦoT-lߙ{^xGK^_*#Qg'*s \cj-hT^@At~RS?ݩTh7۝:av\NTnOhO\j՞:}tbkx:h<1t[J'/ZJOtKᢥt~ҬZJ'1tVYVn)-AtVjiEKn).X۸t-9.ZJgR:[J-բ߈R: uR:[J'UuK􅋖6R:-z|t6VkR:$ם[JgR:-h)rKRZWKė[JgwK4n)7tK|'t>NTn) -tK|:UC-:+EgOnn~ޜȖmpO鬦)߁tCb,.w*әywiEOLŞnx <rtOgqLY n<Og=z5Zsݏ'.gٞ:S=u~S=66NaŶ RhZVv[JTTP߈Ru#wI鹉U'=~~yO>C_8ި#;wZyhb=j[Y0]ۆXZKU4틖6J~aMŝ"~[fa/>TZ] KED.V}`TɉsF8˝Tbs\|Sj rGOͭЗW|fAܠj57ƝzzTOF:6 үl멹B])NEq .'UQpQTy;n>wOVT+T\DSmc˳s$kn 1lÖJKR[*Eqy7"_a%ư1,j Â-İ` 1,B 7 jưX 111,B n +m +I4隭9 B;A$&DNX|#SlNP=I^5)GNWlϗ WXMX^oe־^T<#"OY#OP1|DCO 5 K_}[PP!Fد'n7 ce c% 6uĺUc]Nb݅N93}wPW/膺>9_-xo;$['a0%O sl+)4X `B [Q}{bE4̵X{957֜Sz&ՋaUyauY4 -l`2EqX \*ERlZTF PF {\U*K `Ax̣Ljbc\l Ʀ8lĦ:Ɣ7C#P,bC7Kf| SRӔ7JV-oʛ8-oYܷp;pTP$G$[,jIRWlW|!{TVKWƯV.c)jC΅N51䐐j3$ˏ&Ywgkz"N,d>6bce6k6lTK6UeLsS,hIMK-I;jI5-IHk`*ei| J[l [l,A4#0vDRl 0 2bVˈ-#Uˈ-#H|иTg SkWkӘ:<˿ Ͻe~EUcc /ܒ$,$s>b)k% >vTv T4XK ;/dzø 34d &YB-~2p 8S\?2׺y~:|z*ObM "-X k!Վ bcS!<ņOS.Ă>f_뛨y,7" 76 '6 ֆ u u %f-9\*͒DfQ5n>7n pp[T\ e m`K }/[*4`l{9rh-94[wzCgQ%t5<6s{;βR&G[V|!16*v5*bF~[h@T,jTl'1G~XQ -YW"-Yج|lwT>vr>6|)"c'3滊yfm#YKuΥbn7gRj' ͆fC8w)fv4V*!N_VV{JM ss52llJf-lrYK@ecfckVGBsRV؜m Vj >(YJ^9l+:E%d7JȆYZ cT#YEUNLjf V9MOs5k4iSNSrhN3r`NעrBNSwTsD4{I50r>9z̯:,P1?]hU9>*3}vẚTe>+y9D͆Lq3Mm(ժ`ztM3fWRU/i6!;T>h\*:DD" ;T+-7oxX숑#]WFbCtՆ 3UKu+HW#]VFb)tR*HWuHWRԎtUGZana+6Wφ1Klʏ<ހhw[&FJm;eKAt$?tv"i,=|9Ǝv,vĨYYG͂0/ρүK@Zm؁6E U}~e~[+Z vu @Z4kc֬fug,/)m"+;ET"+m(@ΚLftԶ7kլY0Yڰb(u{C]u꺠PW)yy>DzgnZZqg򫮂U>Da͝\=GĦ_ae?+M|Xɾau)vWb&vl:UN~8M~ɯ2 { NPbN4^'T* t-)ӵ48߈9^s- )[S48kipvlks#@%08J9PB Z# saF58HRi$jT ` Ih08Ƒ9 ){;^:u!@Q;v݊[ 1_"|RiNw|5`ׁsp/;~0`R\[ŀ4Ē'@ }[<]/c^\|J>sWA%.ׁ|:LW%fNLRi&nN8~S),fQf&3q`At&!IN{sdrN>39N0CK gCb⮥b⮥b&;n?GoTr*{H%e^%e^%Q%]K] u]JP< !. |P(\"QܵTS ޮ%@&hDK!SCmP +{ֆ:a|!! ÏNB0BpSwD51 ̪&飚ʌj:abᚁG51ļRM\*UCkF0ą:jJ(4 Z(8HkeFꆪ]vRPrNT 0WD?' o4ouдA S]Q }@3TθQ V8 N1@1t4CQoUo?D1AmPܵTLGdfT%5dUɸ1PoܥToGRꍡ74|5>E1E?WCSIbu}>~)proNk"l8͗f<^+vֆcy}$?^~>S{B=3&\Oz۞c w_GiH ;<_AEф7Y? *|A%NszPYWp鎹 IZ}T^wtv4BZ/s^ϟ/QFJ簸\ҶOjM#x{ɦA=o`W6>+[mm-4o{*vO?}BвVyPV.0*b wӧRܺniw9jgC25~>As{98ER29:D?V:uǣxֶ:ՓLԩ3NGc<{^t}ڗάDRg=^(_su\nV)աBu<>ɍDr yBSqZ7={d տKv>EfL^"HUF娺9 I1ދwVeYxCav2Qep<;J~.ΕZUu%1TEYNc,6;4gTӘQNCNcB6;4bӐbӐbӐbXژ4'TE1 RTژJtrԄژژiژ4u6ihc6y644]ژⳮSciHiHiz81=gӘPmL 4Oژ٨iژOTXژ ik1MDS]4ݍژmiژ>6H46ijc66U1mLShcb#jcRlcƥ6y4ژTb1Mūi ژTSylc*meЃژTz6yiJlc*omLVRژQ416y46jc֥64}ژLԯuWzƄuF^$TuQNug֤)ĐB6qJ)X3f6flbIef%5B0JP{VzP15?kB)%V,fraSb2pNLօJ,#$g->Z5VBS]s*4OTJsӥ%BKb"]ˊti͘Ҝ1ҥy"]Ztij"ҥ5VCm^Gk5Vꅏ_=lmQ K1:!gMTCdh#C3F6zν晎 mO mV]j>ҪuzUk1]1]~ʘ>;dOK99Ϛ9cȘ愑1]\S49cOȘTdLsUsg{I4>y# ̅=L 4H`ֿi\Q#͹xLiHM֌̡"5Y&#iJMOd \|&ښRuy[>Ni>Ҝy4gzHsOa6'x> ؟_Տ V2אb+֕,jJ(Z=isvX6֏`@{VBs%l3Xn%&ULRWsFTPA)Ο@'mB)%^8_I P)T̫K?3)*W5 "F-l#0!Ja(ű@褓|-ۻ>dޞ^* ڔ "M TC -nYzJh訄JXX)*asɅ+m%~Y\uQc%]QN[o91ҙ W %|%`=#ft}r+ki%J*3+}3rY`#v/gBk͂1ՔjjP)H)(B@S'6%Om(O,)QMh @M2R>!&8$ V(dZ\8Ab D q #Dbބ s$}'^B3\?h!M( måg $ @̖`. |$0CؓA&.] &4=E@;pDž+MTf츼'&I 1M$Pnn}>0% StP&m`F2qȤǙqLr1g/wf /[aFq$5%E/Fy}0պK/6KfD.@nYt t3/MeB@-&3O{q(~# Sr1-[ }ٿbTH"Ųң\fLTcWc"M)A iJ?öJR^&-,_kR-Vkl7'eg@Vuk.>n#zb9kؙd y.aI+\sJpZ+u )M>'[Vn㶶`{}J jlŲ[{VM:Nڈdu NѾ\i]R%)/ 4\2[|\#]>%2>aepmX5qAyuXawZ]KkP_er4tsSIz'%(/ Oszԑ9ys5ȵnoRa][tUި-Ԩʹ=!ZIDB|ihFo9L$:e%)f6Z'O/SkpO]HU{TǸ*ZE-v~=O8yY ԺEj1ք=wÌj@Ge͸|r➾ 'DS^؞:HF7N@ )r Xjc 3(gDJF9ȍr,RJmT7*~"ڨbB03A Lk03 f&hK lJ!E$`@ )6[#VA S9RJ*b -X -J)5[Ō -31#hAZC(F-YIВH8f @O-"ҋ8fIE& BTA'2%hdJ9ȔCIn&"J.%O$a?JWUj4[M)5[Mtj#XMRj#ؠ66O j#+DWSHeWSwՔ"pK7,I<CEY,$a(45{\J0Ap)|3G)ߨ+OsB>qh}ʷ`0.% %h RɸDi&o^َ 6ڔZ !!ERa1pX69 'ЌaSNs,᝘1N $C%d/F c }uW]<wu=j3r[^Fa(k(Ǡ]>_o4Lg.!9>.cjTxgJ ﴩxgJ 朗VAo*$iW2#7p %uy2Մ2q;5huvy}ק_H&~ Lޟdb{^\)]'(@Jl @Jh!AJj})׍P]Q)1 b|t3J 2u{a)׋' #M,VX&N|}W KP`&7J^wA7Č q)8:f H%V "N:g7X3y3JXgl<ƅ^N~PQ >6 }6 wI}Tk&Ik#8y#Xv|޹a]R nJLJ)>XK_tRu\c)1֤QFDXW#CVt-fWT%3=֕_E-]d8zb,RQB~Gh)>|%˺^Sbm=cWm} uG]+;@_4#S;/Xg !X^cvkɑTU!քøݿ`蟝n~}m"n5q~E2K)L3TCqbR[3H7"~.j͘1`ďd pcKRhK=HWE5Cpi4Bp)4HW'E6~jcpy\'Cb}̷X^]y97'/>t,5ޕe{NjzW&s3&}1+9XhWa].uu3Ⱦ/@!}{N]ϰ6xXGU#Tة 'DR䳦P 1CJjJBnדBJUs=N)eSJYŐ̈ rSJH+XH+N# XH>}!8gl)c)cW?kR2Wӓ̾Ȍ))uẬ+u}[E/E^1yż_bУxpDH3bJ*~_h[j)i_Wud(b2ytnjÓѺLED3ud Ëd.u!gs 2Zu;9Z ;?y yxg/a8諊.pxmvJ4_HK)|#^ws3TF S.CgNo*bԐbRQs,Ũ)5W3}Tkee|RQSJ1jJ)FZUi ,fD$;H5RR=8˺|*{DjDX"Yh,b]dqɦ"ٔR$g[,vlΨH6B.@6bu^|ץp?. <QmmD Fge!DPQq62DED @+!O\B>SJ'a%Vڜ[GԷO8pp|%'N P1R+.BW5#%,l.K,l9YXO'~"O>sFt#V1ODmD~1 [cp߈-On"&ž1Ũ<1*ȭNFDnK,5uZx=e^JVwtJiXu<Mh?ێ_ mC>GOWސ\}5`I|GCǧe߷󹬹 N&GWuRf?ÒSkh myZK ٥+tV Q+.m;VRc{u` {wH\r֯!qA=pOɱz :xəG,&P]sj2_ꡎ{OEqj[}rvZ1m<+kF2<W?ℽNmm(-Ma5MD>_~5KYgujߗ=^m㺜He+2A~ހ=Y})\~GvQ^Nl&nrj?9k'5vz<{}nˆpnfC}]hx<^/L +-Yj[/m$}'&&sn/緟6Вhl-nAɰ^ #9ڇ<X>2Ջ"{)"xᾏ]C1O-%oO}k 4OB .||:Oj 䦸'zn{8m'q< 0O/Nr'czN5EXgNv˛dxmMsIݖWFPko=3rg!gTÚOivBY7Bi)Ԕvr ܋ߘɽd$"/#;dޑRJf#8W' ',S1!RxC]Zrr%RƁ,a>,a"d !K{,aid Ӱ"K8Ok˴wTF{RBg ʗ^Żn0ris.q.+Rj48F1dfcBdG1!38mǹգlw*"󒡇Kmd9/;q"//9/懼d=OrK#L\b%\b\|PrK cF.1]MC ;w.1%|&F.1f5Y}k*B1XoSb/L]3ww)I)v`]jJ)Q5a,toNX=`wŃBV->jlڊ_;+j,5{*5<}٢?-jx4mf H,<7eޮDxHg#)0#HV;Xe 1ºG7HNR% H,Pg#(l 785JF&{hlK뭞zs[Z+HdKV[MqtݍFIVzIO#Hۗq#mfGֵyR!+gZ)=[&c󹹎lGY6ׁg%o1w'&awvOakf̮9\k 'ɗtm&IsWZ$_o:2heptG6I{ꡞ ql8ydG/i4TR:u8Xc:5Ry*fD}jH@5ׅ Rj.K9Os,*PS XPքI]D*Trkԫ VWR+B+v对zBmfq+4V3[SJkWHP_UՔR*fDk VxAP Q+E9 T=QUXM֨"U! PQ\R(iQ_A(6ţPV`̅x1 Qq*PZP)j ^ *Vqx:j8-U导g^i>zP'CTDTOD,~b'FE-JjqRYT+1jQV{OnNTֻ]~È 7Q\È\kU_ I^c3p難jlhA-U|F-2*գʨE YFRs+9ƣR^% n`H!{8O?>;- ceWa-k?PCRR_g #X"~"K "a)aYKGm}˳g+kqPTX̟8+Tt,jYOűҬ+cYFjLUug-f,dtŴHC>>n:9BcO̥ _OYaR[|s"#jZ\OFrYC3Y|ú ^_IBrN,~i/Up-wGh;sbseSoHYXj L{{{)- qzg4gij+rN)KdNl{˧Ϝ>dz>J}x>͒j8O+ 彙Is:hP Al1{#Ӎ\^9h Ӛ钺cZjry#HLk~x 3/{f>If>..~@jW?ݦb!9Gv0";WhX[}lhOy/l$sێDF+߁+ X`1X͈9cB b,@K-aSJ-aSJ^!f)f)fszń @אbWDBR*R]@VH?+>1_ ]\UtK>Pj:AB hNZ<:bj!V3&P+G0W[j`'ߕ,WxT6΀L"Z_g3T?jpy}}tqŽ.tqGא+'+aWWlcq͵D։EהRV~!W7PhѢ&Wm%:lm~"'F#W\ J* ]ߋ3kwcq1&X{/VF`]h" -Fv-JՅ6WHW.x,01]S'k#!Vh~#V/.|5FZ< -ON%XzؔR=lH6TRŌJRmXի6gD=lJRk] ETBڥkb]ͱPeEkDUTJT(թ9SzT :ԜQթSUT>:GW9F:5RiJ𔾫=n-գ<V9 Oy̢BiJ^ÇXSS*OoT+Sy3qc^S+EXi8W#֎RB+vR״dBYZ--yVBt6Q "V^U֕Qʛ:Xq]/)oO.UI5aV. UoM)u Q銧*]V8԰lc#vt_n_"9;q9˳_AE,F^~^Ai-oĹho~^ '( bq4PnQ;%U!\Yʹ9rSJĹz粔KR%C1R%K 5Y%%L,a=sC)7R/M!BUńͱ k@/, vX&c)R˳ G_XrոG3Ι8ńAjÊ_CJk 3{zdRs:.qq!7 t`|2t\qHńH鸸2tܔB:.?qƘq3񕎋St\vqI4HڅA.LIHڅ#i3"iHڥIdQIʤ],P|Ejo*ԥ~! $H҄S d0҄H&L `:x0&$-  5B@_Ch9`!$5j^kϭ>P݇կSBo:෹osI@oSesIesT+?nk@5o'eE^?`)/xmRΑZPOKm.'*aJo8@+aks$Lw_ma)bWq]M!_),%06#lH!x@},<&cadkF<㤝xU EmFǦc;ֲP գ>/2h*j#rU47&1RQ+W/8\;W qP gjZU|P˥fR wTj]Byh.iea}Y>AMYA x:fT<24cXSbzaf);dy)l.U)c@>gZ z9j,WV`sً~XKnVMqC t}4)8E3@b!S־w":N)l<[AJqhٞal/ٲ#m<)},iԴꞪC%e޵뉮ɦֻaÚ.@tDnwh_gKmQWZ:m{;\YuA*jESƯP9 tPc撶R6;ȬYԩ}gLKۡ w-aPcKl`77 m'$և vSfmBExRKzGM\Ыm;9S;Zzjߢ}*uԉi][]rSnr^ߤ|SFՒHKʲ8T niC %%u{__#ncR{[D{ u{g"{~eMT(GEK:\~uuFsL9Si$7hښbF ~ Y^ԏHKGZUT8+"e/ lzHFlj;;~T_H ;[ )N^0QiO8Uhx7!]ĩs}Jǡ]Mߝ 2RJM)%نl.$XL!<RJu)a7RJ`RJꑊV)TT"ޜQ-hzdR՛3*JhW_hX=rqАߔR/Wb6M 7RyXA/vYt G|!`>C՛Rꍃ#amo/_"_&V5"_7 "-QV) b] /|]>uqUe. n+_JI$´2GI< ;uHŌ˃Sl-#G)|!(H$񝈋D\, ikN^q+"ohSi|EDZ,V\'x*Md򬣈9yٜ<hPmY`˷Ԍ\Dx3W#{Rֿ[BxB^}MJ)څX,K\C1XuND(աujJ4˭[KKggd[׆vZ/#I KR l;QƵ붼L)5u)eݎ~76Oľ ~dr‘FwOKh9X)nP-K ֊?<6}zpڍ!Nx뷧ơSz)NZpK5_?1i5(MP kzx,ҾǺIymqK=2ծK%6Y3ȥfDYm[|Pu?kGPR=d'vx/a'm-;ݒіFr^zEwk}bźst;zF#mU/ $YS\OM/ z8*mn$=ϲ}E?GC~vo/s|`lvWx{fyOk[_R:bS@;ﯙRGxS 9sq>/)s5k=PbI#(G,_,uGgKֿOL]i:'27Wr׳Ҷ+Ev%}䢭Le x-7Ep~Kn'ޔ̾idzܔ̬jʬ ec]Α| esUi ,]fK=7WD-߮)(j EՄ|B L)ᐐ'543aČ+uˆ 0jD5a jGqLz XCb( 8NF+qH 8 5qHH%ij_מǙmÚ[<@+}|fRkd'fxR3<'&)=ݮ@'<*Lx3JxTOWs)YPe@0[`B y^O3$ʺamm7"A$"+6Y^exAL8V֐|J洗nmw:7!8GVO4V&jG9A4J@Sf!5zB$) "'$iLqz*H &yFe͉zj$XCח4k>Fu~&6zvQ]zj@=uLӧlF=5Vz&%;qB=u'ꩣmc w10T_͘ٻ)%JBRCH*D`̈D`VHŌj¬A&f4}^0ab+{HW*r<JūOl+\HV"Z!Zx-jDl1V"rookmlաN U1hxmgF7oEzHR:KV[Ԟ9D9udNEGQFDS<{sH3lUkv9ůc MfNYL\3=9dV+Fn>{5ȫ~iU{Bߛ3fiG0 _)R|mK$_jf|ố #) 0d"EE.i&沔 i8Ӆ!Q7׮LݜQSdKٺL2r푰!c5Rvge;{~@f/2wk,zr3 {qz 3Eo `|bD.ţOD;D_>(qQ>pj^ 9c(s]H ;cb-.^e9 È;A= ;1뺋1!<^PicLg1CRAgY]hr(ue 0G\d"2Rj3JP,j4Ykú|'t(蒃69'쌿NWV9([(. ~9'C]O.'v]-sV7 2.I*]^Og}rfXXD@#:7wڌ>|N&:赃ln;X=Z]trf: Q+EwSF8~"hRpCn7RRxLm'g; 9 h5'TgeeU9`ZC&[M!˘0CWBהRՔRR ]S J1R, A)l4RAiJ)(gP !pJa5 *Dm-#&9DL*U?WD4ku!Ź@|RdаJD49rg+7:bRnaĤ0I1!bRH+\"WlaF*"&pNr$ >*NM޽s ;F ]ey2Ba )8a7-_)#(A)ЁE`#q7snB7T7nDIF+$B$IS|dDgW\=7.ě &&&,oQ&WzDˆJ#*Q)0"*ŪПB65uL8tM!Ĥ!]Q~2)1We@#8/:zۨ{+dZed|YHT!}T1ݵڗlBB uϹˡg>qܦX۶v,V-JC)<0DyhɑJjL`-򓇺Nyt'ǫQ_9qǔZzZ* _iL75]*nO ;7}nL_Nò~?8uC/HW۲X(_TjChƺe(v]S( 5btm ;v.oeL׫j:ӏSE"pLwiBNN2(ºդ$q~u|+7a4Ǹ @ }f5w`11B?Niz|M/Fcc;Hm-@ܮ!EzᔺvE}R{#3F7S$fpJ_RNM<[U2oq8LJt-glp-Kw%xgX腱P PI@ .fiOWV ( ͱqWg=mӬmImk? wOx|6*=\ˇ:B[SN;EЛ3ws>ōx}Ů#m{;#h|鴂N1ow]w^}Pjs] RT{:Ph(x|aZ=\bMm5E'>lp4Nگzvx \!E|t2@c u "R˳;=?_u1붏S t"o&s]N!\WӞnFlPi10<]y5Jj !6`ez|&JwYJ-oLhhfJ inM\2Z2^I,y D2mbm@ D<Ĝj`Ss(,G//gMRW&:sqFۊj]P616rĥD'QAL1-FJ/X>[(&[MJ_F8c7Ųu97t. 0 2 #>}<Qlє:ó26⵼I)  O)p[vRD׃קf  ut+碞89og=Gv^Me]{`qM)axt"77ꁛz7=ݏZGj  3M6uz{wZj)ǑjnokQwӾv ZxS w!:Y\zr[e-1~?.ĵuƽb^>y/v!l{=O+!a+!aƄq G+|k1XzQ׺쥩&D+&D[lUǸ϶Yɗ,=^׵ kמsmV~,j}'rlE=:> ಿmY3 @X.2Aܓ+'B?5Вk`FUV>W+b {=mz'cp\M m'WOGtsrʎ~B+tAv;@h%딊ÐBpJ)7g6~3Ch bXM)7"/ʼ`, LyX<*[1#!z^>/zc,cVmPf"e&22ӓ5+CW3$x_>t+5cf5CjfVLd$W?!@W7IkϪU !9ҕu)׶ٽCp妔j! `̏1#iH2ZR%4jØ0G2=CelP U !Y}>v2bfi4a)4s}.ᔯ3xϗ _s8,zseNO"˹%7h=uO@H3CW1|/;3 D}ΙB Ʋ4 PZWƱL镾׮dK?u3W szUÖ/Ҩt$ckkNfN?}߯"M!D!<{߉tJH(l)!E9\%N*@( G$ =e qp)\\RM@KssM vʑ$2Fe#!Beq ex7qT1R9\8TXJF)T>S'TʢX(BQZHURN(,U)R:Ռ8(TizlZXN)l͙l rb$$ 7AFO c G)$#MTؔ(֯FQS F,8$EX8 pIY Y HC%g"E:=>\ Fp!{y[-#5>#OM$s$AjmĵeŃI R`R„ı[:q%7)Yj&R„ RXG,0ngtKi-aG>;sr"%%+`,)HIZE:D(HI&5)vW %_ꑅ K(~OYr2i巭RlKam)n ߜL^ɤ׽G77~~/g3;8-&ߒLJP{r$i[!||dR佷N}J%h܋NWIUzf$w4Jp ձkpIXׯ-~@̄KG3 u۸|3JP)F2^eIJI:LJɧ,ҕ1VR)0&o9cyR)&NG!$YE1qjٜ#(FQ$JYh#~b{/_<;нnRƇlJ H~ǽyT@ it-GKHÔ#_)UkA 2zIBb` !Q+gRj<ٜNI4RP!b:4-)\A]^Eމ(I6\Te$kH-X}_DFj"_b)$ CԒJ HiJ )RhH)J*R H)4TZ )Մj@J5T"XRH C)P@Ju)Xb]@JeΉB*R,(J M4MLtcݔ1'[v:3n4- ?2!# DR&"e͈9I@$!DR+IoHjD$X=$n.pn7n5͸|L: nHp0r nJU nboœ֞ঽny'CH nh,&pS/7)͓3q=C&N'=_%oHO%QRY|=>(ONT3J* T;QR%XT'JBI^xoYA~)ȏBx{&AAkmYޚ+FeZ9rV94M]_ql/ Kk$Z Zu%J"<3i b"-y?QP gד4c ygsy9c2 I6Jo[}œ]L$ uXفkI6%mu)Aj!a0MIZ$'-$O'Ik2 &神I~;N:O/B`R L5VJ*S>S-+SIE`20PL)s}Ҕ1c0R W _9PL+> _5T+W.~%O1n3WZJ(鄩q9+X "eE$Lk\-]z-,GT2.8STM#jRgRyӔ#r{f5_8kD޴y]jX-{sh2DL]CK3m12S3gSƟ`V#J"-sˆ[sy2'aIE Lp΁3Pw_{˔pG?e.8QSFLs#G #.^?S \k ^)50W!rt{~J:¼X"O@RR!.Wt$f3SW=,eDwf )RXͱZclU^ODKzB"䛋o(.Kd.愠J?/N ^'֯L/6Ŀ9SN'/pTG$קG)%B^,0š'/R^Vޔ-/f/oD`z д~Kibq;/"ysFrGoƿrA =Y~Ժ0ֵ՟RE&asvr¦SJI)RW\=BXq֥ XR[s/D͛E (!tEůSlJ;_VΘBPYC)gt ͧL&|bŒ4zx25'P#eO 0C-:̚͡e\C6թ@. >j,$INN$ .$Ph? L6 OtNkx"&}aeehWltbFdB ٷ&iEXX Cbsb-ԀT.$b6-*b6͇^[{233dOS[VdKFOxB ٷ"OR->ʶ"*'jdCZ-D]]C}CElnvYD,4aYg xA!G@.B.-5rt>~#Eb-sR=#+WfK:ڕLQuCa<M4SJ+z|ׁהZô%,C֕ -O0fRL1H!ai55cC t۹6mpa%N WXDOOfll{g]Va'u[Z׽V <:IT )0c]c s6,iϦ̫An=0kĬ pC 3S֕ !81$9 #u M$@t=Վ*OOLPZc`3֪߱\Nc(kU ɱ;[joqy,|xc(kXVO-Zo3i)Cb>Oi͒"_i> }fVw8{GzQrm7M)X]B h.TF+uFku'vj?2r˟goF v3@WKmi!ЗmoVfR[s5 ^8MRjN4w{7wy^Nۯ~8x5ġ8P*Z'MqEW<W^+nk-xvt~"t8ЉWZy }v/4ڡˉN;E'ץ6:p_裃g#*:[^:|2F, rpK)aŞ.*M)!%4 fs,)05W)`RfSJlJ)b,/m4rͱB_yrՌ/ƐB`u%*GR SJ36g#QsH1|X>g6B^ ,fD0Ӂ`6gT0;`#ٔR0R0 @Xh"C^,!/B0#,&ҏG0{,4visW쌋#weW\-(k[[ {)Ԭu~>gVoD'\7\nɁ{>ڠ{?YeDQ{\n..~kW{D|yn \jѯ'[3n5^juMc89pw-Yfo/3v_M{'8{oʹ63OֿeKc:|O~q݆^ju_^(@"_iv}*w+:޻%]'x29>kg?B `ƫdxk[{}N=r}˞gbiFJ)2_ػb6Z•kVV}\&8s=jj[EzX]VDfVk6FHџfn>o^Z{}1|ks_=.=?z>}zun差__x;>< VK5+>wk{J+qqYq~{ 6u j#+m?+im h9>>R.AƘ1FcAc̷|Ƙ2hi3161!듡xJer )XJα>jf'K*3| ^>B/li@\km)d| ^>壱K|N: e/I3SuTYZtXNZ'DZ+|a)5[_n׳Ca_SCV<IH>+~pi_ڢT,s,@79gc _SsR1&Dc `DyOB9]X3O{]i+r}\AS|=y}񧶈/d^2K/]׳-^HpXRrrzx{~w߱w,:N( ۔ΚRYSJ,օF .B~/BP M&ue0x"uWcϣOH6($H!JIdVzjX Rţ-5's)\Rj aP~cBZ}x2 0#YP+al +yRDa|m!daMVgVl]L^8\aכ8㿚1ڵJ߫,:EdTW(U+ 5a`#p"p}v&1b)=_<;3S%$.NNU>zB:` 8{'WRb:+,O] h1C>3+Ed. 3;_3L0cE]BVWur\ 7&L,SM U63|Ll"O#ԃ>3|m8#Ox`X,v)6(JOOCJNSH?&V}kMln4$NZ< ONf0c%o%pQ@N)!/RvsFJ* zz9#؜Pplnw,9CXv 0`` ɴ 8hLXSSmSJ@kx_oa8c1 T3@)%0!JhJ ""qe?(tzȺẄV `9_5cgE6@kN"%lH+~aBcs>؜DQР[gԊcjO5.ԚZ j:㱼CG 0Ԕ $IZ̢2q9!}X7+&)_vBw|ŠUU,<-^W E3~ƛˋ䬢HrˉLа՗_?IE~dW"ǫL꯷x/4sSbnCVuUJoQocZUs;޻Д#G˽ginaFU#A:s_$wrC*NV}VdV} eV5LԪʑUM<+$zțLy|1EFV^H\3v4_J)+2We$2гBJY.gB mYF c=+e 4CV[DYmP$_Y.921X 0Vv(Wgd`TVoKT[tcXƠC)֎ RڎcY;&JY%ѽP1ɺӒ%h_5L(8bI*MT]hK)U6&XkvLbBz#MHo(e7٬5#8Fk&F i&u?1Rƌ Gq_FF;aѱ2 <֥\otRyi5kTMT"= Y &F- 7◅F-uwVcEʚ,AJ,AJ,AJ,AJ,q,7Z$eDzkuI%.˚,qYd˲&KKZ1^Z1fK+&1/i$%8bmVLrɒN&KDkO4.JaKsdFiDMX['1Bi$cI['9։RI|/:i$* K?li{Ú?@Q"ŶN#Ll$#mŸ#Z:瓮NO: dW'tu'/]JW'::ҥJ:ɉfW'?^_^c$W5+I5~MykuI+&UH Q^Z(O#=H☥99܉IW#Ys$Y4GG!H)ᐶGrf `F] .]̆^8AvY!]7:5ʛK@Hr)D/^fCts"#hbo_'_ R:͵ZJsniY WzϙvXto9ղrs5݉+2>B㧢LZz~c-q Zr\N8)Wm=]?jXc2W՜m;֊$kq)JozR30.y46/e-WKd^oWr鄓6_/*e/ac#gm{:k1JGC ㋙״wAyua.5/=RnP[LMڎ8w[ޜu 6}cR{%Bu^ZS@ͧ=<9SV_mmY`=V br2[I_<@ҵ"nrXWb;<+]ґoεҕ^GZRuUh.3 Ǫ;^u|fmD˲zAXQTܿDO CnKl7~Ozi>'[ p g7lߧ/5%kxNo [b6w㕹yW4%~8vAWY1gS,$UH!dxBGA0*BĢ\@Q` _w4l2 D% R*HH`**lj UF"FR^}6p[ujV9-v2N*0g(̑ c+즛PYLH P%Nv\?WQ5NآVW9tє-[g4:0Lhec]^z!cn_ȫɈW,*M*>TMtN0S#IM+U^Bb&=#F+/"\u%9W&=úF*k:x{&pBƭ2l _O|\:їF#w*L(*~HT|.L`$P9Dz7'*<0Oҏ(WWD*嵰RRZRJ{J^Kih)"]Rж_JYkRA!% k7X eŏE0IJ*&Ii!)oGJ")Xc{銔- )֚!J'AGy!bm<(>(Y5=v+Dc\L$'Y:&Jl,+)giDElrl$?R)ۭtFg=0ixk{eHARZB)J6A"bo>JGYzW˖GtQZb!)Mc͐xNHikCɥyd1D3@쏥; Fv-}5E*LQ^4:ʫ.GH#B7"܈7Ll]ikDFޕFI͈O2Jk>FT e%]xã57Ui6lk{l{P6mio J?f)%^rϏ" 1RVIibP$hc1bQ*6㝾sCDR)cIfDφbdφBhφblOPvf7 X&3b!?o:5ou2nZuFKj)FL]׵>%2dqFbuX3F@pI S4O :W?ʡA;B1p8)g ]m_9gBίsX|U[;3Qj19]vOCn/ԓdj;ȢEG}oRMt 5si92rѢ@-Ez97dYR%iȐ|S) }]D6l{x{*%VgN~n(DzLUvu*_9`0G!5z)Z:}#QR ֔"(CI4{{Gm}%'#uvbhjb] I鿝#zxxZI)mKLC~.3Z3#xP:,ZI`d. kYgOפ`I BJ?OAh.S!)ygk2PŨ*F5fjo?]sν|mVbPD)5gtXDOcWM >cK[,6g0+BU0h!"'|OzKWGj{h֓%?.orWH`V[~RݘL52֕뽪ms>/Qh8S\o]\V;µ_a7(I u]^?ix[eYk$O[xirHV@97Z-`8ϫsqˋ8r/ 0~Pca}=2z꽜iĚMկsws|ŷ\) /,ɦe~7?X؜AsԻ8g<%t}CYV/3RuE[q5赇/#m] 8ZM2.QK_EʺAB&˺gܖEW6t$kZeV%XYt%LkbO!b Oqn@ּ5ܡ u|-L+3JgMjEJԺ9{Bz|m(|M] X֠cI! d޹v) Y$JI%ݕdYk7Qܜ^Qn܂IYm,38jo["KHrîc;sMhk'c;+)w$tDQyHqwj0Wb0eٞ? 07J"C'б ؆б[MɡcY ă~$YT22z_ٗDmFFveTnıR&EФHcҤHYFKB"%QZ_ɍ~p~;3εE1jH¯Ԓu]J'EURB)6*q;9#IQ(^F*9#+#'%kneR_,Hx# eV[9HPfJڢ̺nwt]{z`sz\).Dj1()s8^9(&*u\fU{ɱι:=!a5-M3V)F#"utO-O|L5RϗUv⥸Sk`e] 1K!-=~wp }ªB"Cԑt<{Z|4Ř_|,/ /F岬UQ(I.+_#Ru$SR~`hcmӓNoFoo t4UԵʄRċ؟nЪHYikƸ6r,+RZK)+mReҢU%EʊV9r(+Z#좖r,!7keUXVrM7Q_1ֿb];"d|(Z,"Y[{ukڲRZ̨KKi.+X)-fRZHi) BJKiV$Kg]Q:i[ܪD-VOaN VҕH--bB\Yk\cYIe;gmmM,֭bZ5$+i;JZ-t5?i\ҚD!- i;Ҥo)5a!- i|xT/[v~7Yh5`yVQd+euo͞~|Wg+m pmFW:fWߺ5o$c GS )k %H ' g@ 13*u 3nGe/=CTu e.Nh.2YdU :5-8Zd{m}Z`sBrS&\.2p",t.>E]cls=Qڑ(7 W%0b/CFJE(k1/UdNdJY̶.! 6ht2r~OƝ`&Le  96HbX/BFK#WKo(1ә2FFB!q+v=d2Rr9+nƪ+c<4$o>2#"͌e+GƗjL3⼅EFȋLxdjHƥ/_L2`*3;᤭F#9AUjBb W> @n l1bB#*|1/a\B#c F`ԏ|+*mPYcĺ"0owv9i /*KIaS:cTYlf>K=2l]kXWӗuq~2o7^k7k4X뱮[/u]kΧY4fh43nկ/3juᅬ~c=?Xk/X?[)dguXSphg.`j{/-g`mJRg>z˪O?R$۾q'D.breZ,#Qu-4bN gOY䍫Ik}b<7iȠ]Sdj]/N-ꨥ.՚LUЖSWo^/-R2g6{w vocl{"l_cզ;{Eiqir|rc!uxSq-j!IA e]X[ IշvXZIwp-KY~iiV䇺پ b/%{47o/ ,jڲȥ?ә8^zH~S`3X^ރ=s\xy+ N;viۋs`ˊ~|xk/<|.0iꏬj`j{RwԼݹ-N7ߎJ2^OHo5YTmkx碽amy4k9ÊbYE6T˰((3ԄHjjXe9AYJI(Y z7,EgUE0l --[%[-(Y5{QK6 * ޕ#xm]9gk/?URYVV]OK'H3 XmV*SؓRG\\G?VK v"R=ZWy-T'V JUuy'7¯ k9E]n]@5[)lNpBR+bGh/kG}sq)^@A$zU[&F!JeZ1ewr/ Z{-[f-G`Yru6Y`g}GiU[2\ b[b&-'x3oҿ]!cXZV Y+a I,dbY $B[op~,k\bY8 c6$X}+a1~XSj,#!ӘI1 b9)@#1k&˴]fSjKh !뉌٘ K72VӆU(g s:ȑTt/ƚ$AJu¥0-œN0WX4.N,24gaMyz$X\{nr핺-XLr"2Cl7o 'ʗ1X.jbbZnxlf,ò";l2e3WK}c <_y.0Wl-yKb@Z]q1 3Ž1UX%3MFpgf4aK\__y2GXFBKdd1W9L+.)}ʬt B 9aGJxֻ!cBJA& eR )eR[t iR5EĚL(hS&$ܔorY8SC2!'2ɡ t))c w9 O.P%XY/Ȩ# '4@ȱZ[pۛnX N3(T/'[-3C&95Љ! )C6."6 d$l|h'ٍН N Nz ba(ׅ@5a| ro ډ :-xv%3f*R@@l)F#Q|=s`֘~X*߰PВױO+{ xS/QegFtVce|zs&ʌbDql,Ar]^+R )c%ڪ4_4_Ysl,I%ʌ ٱ MkL<&j"5٨}$бz3U ډ+)22gU,~~y/(9v.2 % Qf2=̑5e1GbHIYvUP ٲnk#JȆb R ?m=t"LJ D s&6?B4l&O4,"vh<Ѱ}"Ѱy.\;~fkHk'6;HeljSTT Xz'ʚse>b v sEJVXRXT;S~J`؜S]228U.̝^&`yoGBf;~s٩<(ZVO`mH`m V3Aog xBfі@fa?԰ak"\j"XsDCM!0vt7 ͧ{wڼ&i{k!m„uk;ɚ )G#${0A¥iz0›(!:˩H{Q4?2kɔuדi.Qg;_0:~)eVZ΅ޒP{!mϯ2hR"%XQ,*k>=?s,rTJA?g_&8=1/5փf\'''4뚣j N%f,:?*?<e ^'vr)X沲G|u~^R;BDѺ\g;EeYw\rh򫥇ęhn2=Uf#H|T8u 7^x5QzK_{X_#%A.!D'eB YJS(rl޴,WL '͹(}˪pCe#1޸;xh^~ܞ܈}//<; àjv|s~~23ۊCvÓ)h$ql}yܝ` 3 6$@mW8\~=V?{xE\ }jA]cYs=TŽ',ȀבB%>1~׬Ols]umqQP[f!MJb$ bgT {yNyU1AA1A!d!Nj\x"#mAT$,+]*3+NY(ks%$K|r$zI= %+$|1<, !#LL ĎQl0A{yY78]q4j2F,ɘZp#j6'Ԫ1J-Y.< |"Ʊ8O0fI[gԥ.דÌ9z91v[# 0R?uK%U@ d8bw vTHQHr5 5*2fT.iJ&74 K}h>KvpMZJ |G%3 GwfՖ2,wB/BpLSKJURQ4"^je T>%h^ԦYʣ2#Dرkʏo|ZԔ/=.vA%>5L7AHI0bI`IԤro!WڎHߗOw0:R=.һ Ht5!gI1la35,Ve!eRUCIT7]t,Ds N bYPT Eu(n4X&ŚM=͑ QqTS%$TBA S'~"DJEn 9UXo*taK`닂bsRlP{4?Uc˵:|;sJ*#[mkKKjs~RQ 譃?5b.TPu"v;:T.Tm!@^qN_ވ[X62<~0HM[O,;+kEg_UЪhژ5+RC>GDjz g8>ƚ>Vem~Tq;ret 3u^[WNS}&kuI-k{*{Kײz³3L˶9rON~%+Jۓqnk/f2n+[6i#,Jj32L*c}h/bfCOȰE%E,,Lp=kH]7o/|5plsc뱦m\H[ ASjTPI1Jq|KoP.7\}-9.ZL@#>Ps6Q0Pl0>< |Ǝ˷r|sۦ9:o˫ijieʋRj3iAO2j&E!:5=}ۃ4Om-R}9s4]cnY9xk{8GȦ\'eئ;=ܒ;{sZdKֽ|[~Ь(͚28Ўͬwަ/|{XkMQGu]M/F_i _ ku_m~O B:']bk;j_*aTSBjO9r$)5X4v.]>IMN9NeI?wv\r*8r=v~-, WFXFJkEjrkIIj[JS I)TvebܨX>*Kb]he),T|)AȰޓKM8ք!?\ d}cѨ&Pe)R7+3WݕS9',=P<CE?ol7Rj*#J77WS17Ԝl,9%mKOr+Y(Lt#T~2Ցr.T8RDr!d /5azSQ9&{"| Att/}~q,Q<SuimOqUhT)kFQe+RPsr%(7V6o:PY@e$V.s8]ր#ꛪWQ/ztjI0s)z\I I[:R9s,#T^RD~S_wGE!cAQ) /$QI"p(..jTpmoߟ ,{iQU IPU-$X*{(( (̆&gwײH*@B2wc$O$ r0!3oO;Pr]eϱ!jMiIAcR蒹 V&AYfQ9$tp4~A^LW" ]~\:ORnDeM c D`|Y u2) ,EV:cٔ ,rT/E??֛bqwrm(wWr]}N%\onʺI)MNqޙ%ΰ9;aZ I+ΐ|b^4a0)"ip+nwN7[/[9M {c?FOʤX:](\gUIN!J"\S jF K2I!zqd!zᚄ#I*KRd\/2j\^ $%&VHC!!{ U <.uq U <.x\&qe @x\&c_  u<ƬӲ(NS YΘU&cV/Xzƻ G"UO:Vh 8Z $upʹ&I\q!i  s_*-KmT+Ly~1qrm.T.ԸPpeMe$02F(@\0PPrw* dT.rʅ^@\X6FP߾Bb*T.vtAKE\J |SU*nYxT|cKKeM,-\}),-P.a1yyyIy\b|/"ʵA Cg!|/:(||/|l T.fNLL.4Y]@Z6--"DY8rieI %Mвܫ?8`Z?2p(Blc$ &B*H+zO^˲&A\u|R+<8/Qydp흘|.Tf/^+yv]I뎭(=_&)qɯowsJ;t4v- `O .)0||2Y֯a|X8ml,ӁBXJs/_0q lFk)='xW^$ˤlY^ G貏uϯ8fkMMj.MhB!4hB9Q{ʺH홅 b0g,v3 @E ёIeTL3KE BӤHRF)#\\zbFQ3W|Y@O&4UXX@EJX@E *FX@ w`6=$Bus23r]hog) uW8. UgP.'ۭtJ7>xTsi`׊|ʲSO5.|t3`SĦLEFQ} zRUsJ)]p:Ғ{sM2!Y\dqnk;.Fz&!Δ3nV6B7OMj&Q?N[b6P٤,γyIRI-iw,ia֛6$Eb(,ԝcg,d2g}V.e+m8T\q->BMֶ6ovšfsBڍVœX-L:b[6p<٬S,jq~O- Ś+=e6Ru[ZY٣ J=ͅ/Ŷ澛,Y[8yyϭlY[lr 5Z[ؿBK~)nmfH٥\֑$ iJ؏v[gzW&MDZR.`XN= X:;eX܃̔餹,Iz—Rb$k?.DZf?!MhOPJ 5!BLJƔd|PAeu"3'BdUB8fk1nCXx6#GDR)(,i4").,Y$j)u"C n)a1qוᥩfϑ0NjE)A-gvg~wGW 3MD~>-'$F3BEQ_ehjGi P DYTMȱiޔҤ(wϯ%7~ei^)!%{>l "Fp4&/__Ҿ0ј5@ jEy&; CEJNeLiWmX h H,fS5/BQ?dɨߚ x qoRG$_SS=>YBJ;bYR3j [HM|m\7vV---֥l$P;r(f !A26-ǒJb(m|˳ho9ź- ՚BʺB:ۖHkRl˳fB,˱Q.֥ri*zK[@O]ޚҸ.fԶ<W>6t]NW;?֦h}zyQ/S/-V'ocmxyI,xmBvZ+^ R[FK?";ֳ>BJ: X^Aƽ s/5rZ/հI_^,Ge{iWkk=|!Jz)k5/6|Z^kkwiրjxgw ^^^cI]^?`:9[] 1Xd̺F47"e\R2,eml.rBP21b(i_HQ*ʅ$j `U> l(55f|RdMjbTX+RRk[(b5E]=+geFu\kbMʌ,d5b! 2 < YBV4B9*F(F!pǤTT\]TCIrW[ЏGfR R~# YmYjC1łBVh*&v?j(w5b 2hs[HKEJXKװ\ Y-Xo*tU%Q]m]hIGOp@*F/l@KUI*֯EruUvG ݩ,KNe,!s%kNz_!L)RPR*cI*DzJU*TJY*%Ʋz1RJm,FaeL[! ՚RYJ!Ym1&diL(V)ebLn634e*-♶,cIzi^@)eubR*,⺐+CY)($ *Fe+ZɨJѐQ)EJEJI^PQ5Rd&f]R#LT&M:*Me Dl:`=i)HMTnj$))%ÚMRqWJN33!avY C.)sի ׹ 0B)OìeөĊɳ"V%bUfR:[tkg SnҙlwRJ 5nQd+(Uz)R/ V>VL⶘i%Ys Lcs!!ⷧȉ X …M(>|Gj.?I&GVXBBMJ!&5kH?C=RMgd^X?m)$<6&җH$HB.#6G>Q I.OTNk)DٮӓFϝ#(ӅId5xLYN.X+F@SN'5ױ"XK}9ݸZBqiR«%ӹPH\&B򻁨` Ls/)gd6!t.j^:szedTZk ;Ǡ|k-_z9Lj`U|]W$98Ge9*J"Kl)$bqWn5=!A/b^yRH𠜹4ZAUx{>^K9˧t,DF #j|Y<uP2\5-C( WN-wnۅau'r8sˌ#WRY8hG}_^Uƕoo["urH_*83])AّRs-&>Q`%UV/pSiH(ЦN%N=0>ɲ$)c r2EvX'͸K`!q!C2OlJ8&llA ee***RUEJ Ed((`3BHQҫ) y "?g!cY:FH9eDeI`ٔJh}j9[L[w"%`ut"+E|^D{\cx%ES73zՌڪZ_D =M >}U F5-)ϭZ%,J/eͷw^Ϊ!^{r#XŘw$9.S6}ݨ[_jH9}ݶ(HhA*RG~%u-g6A JEMfix5)olZFTbN{3*i&CSұѶ71kQPsĹ~3g  !æ>J2ʑ;J r:N1Ah<^>Fx[E]ED0(D,ˮ  $eM_AȲ+ r$AѲ&h$Z!4)'2MG?KnNg1W2bMDq`h{>k/R!$E"ĺ\Je&Tof{3DW6Ppxu9̑l:. <땑q9g͑o mt刵EMH·|Eڜ8[ -7Q6d,;6NbJrI= H[_~\m[6yi%zr%yͽ(點@A̩؎.ѷ\s"D]Z%yS[Bbe)Aey̳ /e,N,W>סCBg:Z@jpd׏Pt_.3zy+ھ9Q]j(ǞbGdá̭!T+SX>0QVQ%͆e]dDGۧ8ZUzkt~8rQ}3OFGX{AApEgl/|0FEh5͟7Hmd|Z~ckL:q~F&Yy.ZV0w)&Laۑik {m'?vxraZP>jkZ*'Ge7 t:9}L ;DWflMckI,y^:izyZT ncf'#~Z6y6ʚK'o6gs:nD*nircfKdy}^JzOiD ~UCʒO[d OpzglI麞싣[x}m mZk9 Yx܏3xI_STP-{۲N[9oQ?ܤqY3ʌjz9Rl2%xKzG|{ tK^%l{a_?MY9*c.#Hz~gfDf\WG2ǃR*Z+xy'u_S&5Ԯ:\Y:{_5YۺF¿ d(t$cI#e(%56CFF4a](e](e]d,[C$k; Rl &J2!&P6ѩ5W5WDZYȌBKcJZ;cF>qFNˆi\*ȌB9cv#MdIs&0D#RI!9ILFfNbIvH:ÙRC'1Ui$36`eFɸG&Ei/$D$KnNڕbu>5I>J&Q5$N{gH7'}٠hJ4F&JƮDiI0J&u˹ҀIN4`ydt!.}i$6Mjh$6MmSn$k U@:iӤ4MRI24MU&XiC!q'J2[+904M-M {5VӅsRJ3f32j3f<2(5\QPJ(k8Q`(tEo~ZRpBX׍OڤS&1+PhLxf$GAHrĐj2}]r9B$ 3rh8/&<뽬1'\?/{ NU=8y#لs,3vdBal;rۑmG4/D:"6BL#H"׀q篵2}nGNu.t;jq0.s6 gf!F6 XFE#&qD4xb: k6a ͫHԋRNFS[AJ~áF/6-ֈF\ ka@XT4H@E&~L4)H * BJ!(Wf+RLC6)¦ aD2`\Sp*RYRԍ&Rp}qRi4S&/|!1 /$퉪yY(Tfdj3rFC.A "S[}‰ĉ(D;&DU4ihf$&tu%4fqWDDDv[ A- o &ouBD2d,i~2²QZʲ uۘvM9bjC0LL^~+2LWĬF}lk6)j5 f5-5cFTWm3J\sm]ltk> Hfd`Q U;E4fV"%l苈_W@=ڊPҬFAfWk_^n1S6@;vK tYA 6#DDV W E!}}#޼ۀ'/W׆vn9w5}ȫ3DW ][uj͸*]}ک@J. !Z5-v7[E$_mLBV /݁ŸNU [?[]Mـ=LW$$R8=1qA,1Ud!Ud+xjbCbXe$Fee9(K BBڢ%_o]e$JBl@lf"öu `IK.5 Ʊï͖sy#;;ۉd|2^4^5g^6ES_6DhkM<%zPꛫf4>]s4o@psKmX}ĮJE/Gȵn+l Qd ;q 4p%l;G KcZy涽!/ד1h{( M.h [ovͱ|H05sӺ%Xlb I_'٤)p&01(i_I@,֞fŚ@4_9J*/BDSCȆRFd#c e2PrFRԈPȄFʱ5cm*F]Ux?5;Ҫ'6ѓG%=AGߠưPBc$:"T7 ?{e RX=g1uoA|c'*5aD|;JJfHYqFi`< ɣjj#%APYV5D/$X#Av9šjB.U겘ePLecYR[#Z22u&$)PlE!PH?! Y?!l"H՘Y ˡ$\)g݄;MBj4l'k;! HH]-eMxzz{yCҾDfKčCf9TZqB)(IiLd ٲȜdPHPvLX *Eѕ BMMCIQtj-hr0ԸTꕂ\|#EhԽf!:\ 5`_"^#ԫ-̼PMJ!2*9T L[g"epؙ;$=hM^,&do20)S}' ȼ%B≕JW` |^uBdllXPS!dԩTYyݎSA*\UȚʅ i*.uLl˜* L*.KTRRe!@§ʁo;VpH\嚄qU "R#:Ŗm5xӉ3KKk7pVXLQ1zU2+W8r*PrM QRH]e$t#+:W9*dsarKT *Uy\`]V^Jz@fzHv8h(5B׳a $:WxU/]2utNe9ҙGQI e$emUVUȵ*>TӪ\igUKYmRsLbp bFTs Pz E}we5ח@NU?S,׾uӓ=$&GFԗ!DgC-Cs 6T ScDT9OK+ѥU9vl_ZRBJçir(>ń>ń>%|eI)E,|j;)dSi:)A§JçXO1F!e!O*B8`CeY`6*Q3*dH5I'Ի3īF5LlaJ7Z0nswlyyB!Oh.<$Is'7G ˲,@ȢԻD3D48](?Q"ja=1W)Oi >QڱF* CRPF9g(ݲFc`R뉁}FmyL8I--||ҽ8ݼOY_wFa .?]Gp\ą/,'kMs5Tē6{jF|% _&\n|n^[d\O~4i55K,tV27t(n<5+{\[8'!745ily}/Kihq=wfH~#ֵқ婻^+:r Ŝ-J Yg'rrAns>9~_楾P־t\Q.=,wE'ZaKmytO9ޞh`PE^C?&m$ZyV;~q+r^6w)߾ $~ NJٲ5>p=m'ɱ Bʺ튔aV=ZeZ,)YţfՆb- rn .$pR-e,\5DwӧڶZp'?р'/u9K(u&GgVTj׬`r?mbenꊇRoruքʲnbed@X)HR@e醅ŵ uql@,TS0xku&X[ |-[}ߣSX'˚#طGLjꇠUʌѿqZ^ eFr #- °UGcT˃x)([ܩ jdzNE ҕcF:M(d](e5"%36gdHbJ%2"%2L"%dHI%b%Y]}$g%]d1InHB?$J"PɤHfvGf7w$Rlxd|#{^*Pn0RÐ1r0FlKٌ$7TWkf#䕱SFYHuY{Js#Ȍ%vSu.Cz2ؑEg"Df]h;䛘Hl2erosO_#^6+-; q \ {.ʄ1"%1v{99T6^2#s;`gZJY'wE3hod&cـtL"LvdIcc̺HcccWY6k3(kk!#I¯X fQQ$* -ygb"31;bD ph0ͣP0P*<"(}Α,F 1 ((&7As #"3jڡZɰ ٙO;xn0 vxT&~.C4grXBgX 3l=̯*C7gjڪɚ1oFPTrTzcHOrA1L1:,PJTBHI `.Xvax2o@ Uϰ'*GLH n3q;='0eF.q?%:ՊWh W/b$aPy n(H{;,}Su \OMh|-tC#-5.uozrjHj#p] KH"4-≛.ۃd4cNuSk"b.i2cv|NV+뽢 J]gB>*G=IJuS_<*tt҃ \rx[>8Gt w<.Ew4+m@zqx^6[?a^},C|U7n?_ Qw|_\l+rP)2B h/ʾnZhV_L`݁mo{ ,vm섣ΊT.|hg&']YASWuыwW\hҾrծve$ đgWTw`i)}{:n\1=M+Snx^݀ݸ2|@减6_ -EJ% ]ڌlPk3Qj'5)Q)RViRԴ' iϸ&l?v/i S/5UnN"d}k}y'T5Dw@8*7H&iRD(^Bp]̇RLEJ̸ JG q*U/ W&loOJ/TTo}k)%}k9W V%-p9@Nѩ@N ̓d(=:Y?G_&Cv`qm,b\YԷ 1VHWRc`/Wv>IrUi⒞X)s>dYm,43Fo6DϋCam]f2s;?fNܞ+}BGl|d.%"$H/}"k'wI@F"7s 8CvZ{F% Η L6_{䯑5bӋ-[%<F7U}k$:%ś'>'=rwP s{1P!PY=Bfl/d`ݲڛԄ)#v?aY[yl,X?9k={XĹP"εssyڈ$oIos9,J<.S؃Uul%=pmF[s{4\y Drn5-ZQaxh}5qR$M8LŚHa+]uLMJ!a&#+'SSƿ2DR$J=$Ò!#1O8f<)uIrPY{_X*A娀TM  ݩͰMĶ'wP_[+׼zdJ["է Py]x ToסpS? 6UT\.IEy$Xt4M?X(FP1ɹV?:N$db쿐Q؂BXIBuWrRpJҲ/6?w r2A)~7k!ae]:S>IɍֻjL@=^C \ry?_ѺQG=V BXQ%*cIDfdDR{:;lKܕh',|(˒L(qWK"%qWY_Dy J/g5h1Pqv.TT/pc- 1.(92e>=l|[p$ t(HIQVݚ͏_ vŀHI@fd@HT˱n=ѷӹ6zZP4\a;$ind߻vً/-AKp3‘~py{Y1C-xp,~=+J‘_Q\ofzNټؖ-͸) 6ٰWJ^}vzl#]~u6y "D | veɟތ;?H4eQ$hY@_4D4oVsosI+G3^#2v|Kf<ٖZiN6AFWQK/smmF=EJ i3pF R\7J y 3 5"nS܈2 ?xnd !QӍT7yk`8(q8q'GNXqĬHyC!-l!:f4Q(t܅2~фp,cQ)P&~'@?Ce2[U\4U-0ȌB#V#;5|aуjq#r32ZꅠG13E\C)#QKnhz3GYk}t#ҿWmKxzd($-P<~ )TeG)55D[ $G]3 vP:;B ܣ]qtY دk^%xD^u͕ꚡ]Xaa#b2 Z0K%RN xK]gD"6HM] M%SE,,&ȩ0K:`-OY*KYnZ퀠{+4FД%J=_ $f:'p,,HT"#A緙%0^%Ti k6K@1 -8R07J;J0"(^zގSװYT,&XV3q;)}Έw\ёxH/9n_J PV%~/4S(Aqh#;(lJ@ H ׅPB0B(}6#3uimJA ֠bq=IY"D!|h<+j`v;Uu{JfyB J+^Ͳ7 2!48\!Rn:Ca8j04D yq T!Ơ%jxɅȱ<ZE3U8r Qd( :!%[deS=S=S=x{]aZ53GM R;JD F`%BI-nl@Rq<(Ne/_?Ёsi1kFh8@pNwo?#g ^e>1_7CWyJ-X2ZQNGy;C}cgg o 6lc]l#Lc-b+}ҾiӧiWIWJJ('w)md-9-ߖ:~+ xlD2Ki1TJP_)ccol Zm<6/vٜDK 54eAxfUS9ƎO?F 혾P]O[ZLǎO}׸[l6MP[~l͜vc3Uo!("beUGuw>$FARm8 TrZ*M0-aڵ4ô߈i0ҨS NKaFL;'j)6yAƢbGE 0LjѨf{ GBc:*QKP&i0FTZ4Hlej8J;fj4LiX RH!K0Pka* -#UK ;0\ab*T`Vܣr*Xyd+8C`Yc+޷_wVlap\֊y؊xXV|^b V} uǴU 2IT,,Ri*\B ƨTF2+!R⁊qxTb^*NSKМTr?TJ%05Kal*-6sS287&²1:wv*oqxjQS\]S&U?&3Bo_)TD@ZB@#J$l BF]KF]KFQwQHC#@!"ʗ]B* / u-! A4Tj>:<"Y񈺔#GG<" xDX xDvQ?QxD=@RZ E'Mh#X56•h#|bt@p S@bJh#!Z6mċl6*I݋+UR  d*#HGq=FFOEPQLE*do@}a8=x`+E4@AYYTYOd4EP.@!#F 6`DpI Oަ,B"k,tRk0=9i2FKiSZ*p VT ;",lqAkt-EB4 "k~o#BނU[Ur=6-->TqFTl'/)UqKU.nޝ/ܑ\k9~cƄ%?%-Gv^Ãy/t</K]wX]oSq޶xl6n?f[}[yY?׬Tk0OF15:z{MѲl} O^%2׭nU"k[^輦 |]]]厒8vNZ<'Xy@!W;vMe2myUٹC!Rk+~:n]tݽ)e+i<[n79ncSWwu"K/x*f=~`!|}Kx^ZCtI;ʡVX\}1ëq]xb=^6UMF9/(lQOGV[5Aq v.>?'M~BkUv~/ {+?@2Xi'r~q VieAǵsj\^@ p۫eĠBqn{r / P>TOҎPa|#q}k=>vloT DZHJB@)i:"IS[jAjU`` aUBUu-Z N_̬`2B4IhÕַ;ﻙ-\%鄊@M̿xN\ojz%b?> OiT`\BOIr%Վm)^^NJ|@CĨ.j*[É/i%J/W 2A,!O(+-:T%ߛ#rkziM]b)7W0dezowT#9l}ۻˋKrx-^U%]ܺ_]ufcwx/W$B2M"Jj e l h\mTww,F^-5t,IXK!o?#ClҠ0,=/.o?Tџiz;_=7 ) *>p'JO#/v;o4r.+v6+.pZ tnn疁ZDl%=z:*4Ӟ{|s  x+8|0P`)mw]`vrԜFǍ:(rʚ5jV`a}ڈ튿|~ͩ}oۍzY#SX"`z +طl6GjyM˃mB<߯/"RwuMJluPa4ia{'\ ߳ۅ9=[O5RuX+XR 1y9XC,N|a l5 (zP!. m Y*.Z`|3Nq`ݬ4KZ[5ˎrbCc)$CHt pBT }}z͞=ZT褅_ # e,*zW-X;ZX(^ڴ @ӪlfYc%"Aa- ʄ)H{ñT(iP۵*oT`MP! 6^MQnû&xnڙcVUj_`ݲ\7n-km;UQ%kjLvJ#*7آR)*?6;v/`8ӵHJ%ڕ˸iT ,iԏ SK3>`/, zTL a[?A%$P0)TB*}H! jyZo#/mrTrr r m TT k K K #%#3PJ#VPJ%n#E9Q;`UH0(#|" /2FRT*(#`G#S9,6l l`HH0Gc*xfCJC: paBD#]w`&Z / &G$$|_W!P`r--V4@B/1༁^zdǢᤁ^doAt鴿:/7Z`q?#qk"csQBM!a! 7 $Pf#^Ͽ4׸D-QHK&RW+ND͚0r(̵mX5T XEGǎI\Y*4Jݡ'vݫ\o ~%w,~}7OT J-0ͷܰ;xЍka6wi|XfeA_ diw? Y ZC-M,ͱWi:_cZ_'Ϛurzl_1Jg.C8Nd-~-Z ohoiaWF=F:yCb "hՎ`2L4f$ė_潔o2i/#yr߿1cau0&,iLYꜗhK֔!/{f_DN.y{LQ0-X~i'0P&+aX8|T5adKNE[uߘULu OR LiKD/H\0;% iPK4E0cZz*R ~@9sE ZBt{ʲ;bKC\trRYb>]aJ>X̧ 'xy7߾ckex>uezfxKW^z2ww)0lukK}y˳.}a mԖ@0%Fe>0"FySƀR'x3R:o$2w})ۇ"wT*q̯xNv;scؘ޹ӯà29/\i^M.uLM`d&SDŽ10X<1ޥR`lKԖNKP!,oi&n P$p k!7#_ 4"Mu68kG;/7/EA<JGJWJkɮaʗBaccaI>^sF4lp@< AdTUqը8kFΐBgjcghV^,C'e" JJ֪57q|z$ƵB`{~a*ſXk48?oo>/p>Vlx_.<*o\!kl.7e)ŰhJk+Ț5813mTOXcKt WB8>V.kOXlK#5ntCB;QZOsB(h`g޵%zG'*skt'A7y<(n^ B]Oq[bS96aưD<M!R` -@@TL <5AZ"a5`[-CXϲȡ/RJ$!h\InX+<Z9- l6 5KG H'W!e8fc"!0= 8E%B_$*̠ EE0BjO`/OD婌IT4B% 9T"c^:0uyֲt5IWllDPm oħ5 +@Cp>w'T@%pT+U`a{={Οȵ{7 Ƌ$cLmQ`@4o~?pA8az#,TȋS Q_7oED*N[PJ̡`="L=S=z=CVlNq!6z937ˠ5Sgʨ9u\f!5\f%[VIIYe+RH8vdj"uGYdQ)('uhJ0YTg=:X'43||2z1PgSʘOp*b#|vG R~S .lp۟EB0X|,e(XG?s?ʳƏ3~zzݿ} nR4T-DC><.꛻bYӮP):S+UMQ|#D(9OߘTe9-zNs qO\iN)B)?qƾύ#TESILk|֫7pjj&P8tv)4wBX-MPH-  Th@ v$2]e&K(%z@Ah e,k0 vROcb<;4B\-ČN-~Rފ'_-}S*Nq+m]qT*S!ƞiNcͩphN_mN֗؜Z9:4홶SROҿM1m"@"HIۑHI ݬnv;bG"fb!RG4Dʜ'DRѧXN8_V#UkTJJLɫFSY"-#YZ/%RB5</EMApVC {Oۈ@i!v.XSA涪 +!o+-v7 ҿeyҺ YJ7tI_đ9$PH=X b%T}}/C j0"Р BfZFMW\0KRjQ _;O+1hmUZkB1OM|yƈQM*)/@FH')\ ZI! v-5(F(/l^Q>|i.SJMYZS<_bz=![qz@H(0`x T_VDx~wѮJ;L*S ݌ Ѝ[*5BOKx;TFOioōn jj*`(z0isЃq텥 7űb۵v-%J.B[v)E]JnR[*ER T񉈉!bbP!&Y#&.!TWbbH11BL*PĔ}bP1&ÄW\-Z99c-DΥR9&ry9ӂ9wCDUAEJ!D0YDDDԛDμf9d9Co9HL W߈k)&cdžj]p@!*Ā ""BT^ʼn>|OaO}fI`II`%IKK*sK\f@BZ ?;?D` B`I?eo d~V1'.rD|%'$Bmeb{6TL*ŨP շTrQz,C_S5ܣ\;bL70BF`  Ґ@0k!1U戁9DT:d+s* ̩ 4kaLșr\`-bLL4&^cb& @oR '.Bv)zbd@Bh$]Ԗ|4('0MaN $91Uwt1La2{ɔu Z 76vM0Ob. ^-K;\O@S+[k!ޗGޯ\=>nPtwgDڜ'vD6Sj6SjldltLP!O /R2-cJhSrhSk5 *Ne]S}# Pq7>QSF_X:/]l h lٯC,ٕJUI 쑢4ڄlI4ƚ 5h 1%Єnم@)4ƏPކl q;7v;#cSG=/$?Wv0*b-`JX X #+ c `ca`Tk-vvE.SZBZBFwk勥Oo:CWW!BʷT\qKU /R|a ׮dŽ^^>+a3X0}@WcPz!yʋ(.([S/dU^[2jx> K8¹a2LL/>a5>̗0_hr|007/<|yuzC%"!q@ Pz@F/'cc }.0p00]Dvr >#`uT } WٚqNu8M!0jyrt~ҎMjǽ)r|^>@],D^/0rw: NR{Zm?B,~:mp%-r]QӘ޾:y{.B$_LxZs:mF69_ b`s!A'IVp+WX?1s| "5Kk_<~[}s!kڷ2\SF&Eo\ bClJnr> >ɷѪU_3)C=]<ϵ[c(ķLg̸0Jm?g=vLT\2|s. Z.uC޷_b̧-׵#]6kvy=cE|r٭ [=/_/YARmiw|Ivй=w\뻇fr?Bz͍n4/kn9/~jz~ytnwz77ߜ%zbQ͙_;č칇O>q/^eS7.:>k7̘_nԦΫwfZ=\!ۧODw<:Zu/?otXZz3_j\MJ:EO.#M䯸oZWTӺroe|1O9Oeر!zSGh&[ Ӥd (XEw )W@ ˣF.: DĜTXD/EW/, Pv%"@NtR߲U݉:[Gn]x-3b{hwrեw//Oq%_ 2ftl9R^]ՅS/= *@U:vΕWO,"'wr>霅C,M:zl!;}n:'|=vXSQa6\p6\ 5 F~WHb> IPl sl-w&U]s_ B%K((Z(Z(ɥKI.%Jr)-Jr+W]|"vag'n]^{V wƵJ^(ő]X6 w!lJ'^6{y`,SYSl 0[Y;!e(ݒ]HuЇCn]>vyPQڱuPuYRK{M.+)wu/սT2-ީvR+u.qC]PQK.{ oyYnmoAK!J('I 0f)L 0$`|cKm 04彴sE#٬86+-Fs?m%R;׼yo":ξpVRkVR(dJ+'!R0Y"ĒB|"ɬ@Qx!y !Kg^=7;2 nF[E [PVf%E !ggGo G#&!$-O 6+F9aFq(!  ͣ5Z G טVvVOij_ҹ]&̓tuP]" A %1joC3%{%}:""gJD"-Zݮ u?40;5qio^a†;?<H8΢I@H]N+Y"M)eMgnDZqVx9܎XeeMspN7DxSB([h:T^gDZMַf_b^W_^!5Uvt;dy`f:j8}^U׻OrI`^%> vvЀҎMQ>Ʒݕۃpï-,{O/hZߵZi9~^LO=Y#'y |SrnkmfsˌmbO~nЅ>S@.+8N/"8hnq]֦̩Fps!Qǹ2=I_a]bfǭr q#vprZZ'w: ܹG"X omE* 4mjyUЩklknWyj 7729 wgTW3Xywg-ǹRXmk]q"L=}v|_S[/;7=]%Ƿ{p1펿g,9 S#`oew%ߜVd6LWZC~5Ou{yoomHHG" υ-8;oS1g.?/W0o_Gu*T-O _3۳U~t_`U/r/|/hsE-$"`ad D1`7zG@3vX0X2`e s [`!*`/˔J3ch:U/F|R0*GE~eR]W,2vncWƮ3P ߁*R TUz1vfE,8]!^xt1) g~'9= ^:d ~?Ιtreς ;lDŎ2W_C\ gr!.pB7!.x` L^PǖLҥ4xϨ9^ +*|d #Us/gJYhxƳ"-JEX EX TXhR!v_?*~^3??Jav/JH +q7OFiaBo5AgjPO,pZI@R7OMCo~l%ha1Ύ))*~(>@ qS$Ž/Q n| )5:(DomKazDQz^ ]KAzN1H@8V8x܎aȸ܃IU:*p:NWp bbMQ0 G0΄ᓱkKEeBN0 0!~T*JF:kU@\#p\#\#|#p5_5[5†#Zf"wR 0D]`# 㿈0U F`Ffk6';EdZ0"A*g@ Y$ YbTF FF@Bɲ Y*@ɫHddY Y$3{E<$ j}w=}#_#!`D9 Ih&R#,U0" `D+k8`DT\EqHW0"Lt0# F$[0ymԯ6nM! Yz,Edj,)d,YEb`Dz-H`D7G0"U0"u#aHw]toH^`DR{B#zNi*LW9HnF|M3aE)q:q+k$) ~BDP) *$-$ HRBTJqb--qJ%फ़J%%P{| | 'T.%.%%lX&,%5fBBjŽjRjRkY*P*-,u)a(* J@I]Hw&=\Pp@$Uq}N]S½<%]K@K* y%A C:\$7& I!"n7 ,>Hic]uTP=57|SY懲3Đ2@1ћxLt4dƒ% 4o& 7&2p F] isSO9NygAqVjhu%\_! P&8o@0\K o1~yh HQjVl5~~ETW3IP!ĎN1_aDm8QK5N[!-DZ+ BJ׫'/ JQMѤuk*ng;6Wc$l1Ǝ'6LB ;.TҊR ddWN=ըZ2Q6l.W\3?bˮ˓$v5a7C|0պbV*=ncL-S Ჴa]d }8ÈT1+Y5  ᫴a"Ā0Qѥ!&aYaȵ5 r71,ҨSzZL`c2Nd:e7vmeclKvLl*[Ll*Զ8ƦZIM}'bˀ~Y-o[*5\{53"`h^isxDݵ6lnwҖoL.]n* V~9އö611[m=Zf#1( CLY8T˘OL χbEJ|L?~PuǻtD U߁>%XdrNcfYbgr.DK:nv >V`Ȳ(<jڸͽi[OLEr_I_sWZ^u@~NYԁbwy&O{e\c.=DDO\x9nEQ|qr8Ou鶙*NoY,tKH/v _[qTM}n7z پnE)_}\.k{V2`Rka wa' b"̷̗Ko.No~nq|Pz;1߃ZHR.Buv,Qp q"`-c-c- `HoCΘ꾡W1s@V7ZIXl%mXp%iDѕt 6b\Q $QD'QI\L')Nh=$"68Ƥ*T,M"R|V@0%X4%U$V[ ?5@TRI>JR*4Z2 ddV Yɗ$)dZp%SZ3b0I\E4)cIzS%ɫ(K\%l%bA@%iDъee[mIB ܒ/oI2-Mmcu1) O,?qDK[$$QXlY7^W}Id%Ft@DɾkDOm]q ,__% Kr^EY0K~8Kb(Y^d=cʢwaoBnT"Uvb%TD,vT"Uee\eV g7 w7ww!T%G*( Ov*^7D( 7D*LwjtK"|jtEl ~ t+&RV^.eUTf;VQs[angv7ۊ2[ PcQWmmL agUgw!b{&r m,j+*}`Jk+FTֆma ` Fm(텊jjIe#$N-Nߧi{Lno&>(PI;r7-mODJcjUi+LmAvVZe[7"[(RcەPbW*lu rQ_[Wi$Q*&J]KRDi,_[v--Kezn?\;"MP]wU-ʁBȁR\ɁBnbsooP TGZɺ?2ϿQR:2RL)R,2嗐)Ȕb-dJrqۓ`1/$(>IR=|_FJJ'" ;CxłsR^R"Ba-%8!/$8yq$ F@*qۥDM$gg`NR/cl=͵|¹MsܶRnwCʬO-򩼁I~MlnO⒟% Rv8EsqN\|$%+>KL~gr]g 19N[v{m9+J(.r|Z& G&f/=0UBd7$,M:X@x}UO0b㔥Ihj- CMW<j~|j~EԚ_~o;zFVFVOW1e]zKmc6ǧWB;Gu2^ ZRQut:ro{"Wk\V:%q(>AZ ; VRl%"ִxڼW\ViǔN?d %mVƟB؉ʏ-\VD9J_:?Yw̭aTàQ*mOo?APSK1 vrݼri[a JKc -ܬ*\cw,j-Oq,'֗ BI1BYשol"cEy'$XM;љWvTmt6,RM+ֶ~P2ɡd}mMjWn QK;[=Em|ZK;y!?y|DMO﻽Loa*D[;1U:_PmW~Z,lZb-dacR*jj-}!ҾX i_P!^W!oi\!o 0MZGVӦ|PێzSR}}sR:AP E4!*+kBTk5! *jǦMƴ)vl`sXP ZG!56k*լ)5FYS_ScTf֬4YSs\:C͇b-CWbP:fMW}RZ)N3LwsuTvOIP|R1:h:&MF4Y̪Ofj<'^Ϳڋ_$+ n"KkkBuͿ_l[&iMOUdMBbݞW];bC4Th6t$ҥ+sOV^v)K;LNT 'UKeKUKVX sW˽殆sWCʼnzbjOHUKD򥉪}'v)MTR ;QKajDJKRVgv)JR n[DZ)*殖 sWkeڥ:DJ gL4zp5Պ:Yf+#\FBS1W“t8+TYZ" gL1z<-Kk8+VU8A]`*] ǮrÌ]'>:vUXƮc* DU<0QǰT0a 4~a;^Ƒ@T[ #U=,ax`X*4RqcX*LRq`X{X*l /aP Kŋ8iTHUɌTjUT8*U\;xpJUxpa*O`nPkk=O` T_-zf˽zfzfKYH}R Z* }8 yv-/BsZs {SMӛ*bB`ќ @sj%Ԯ%_8´ŠZ*bG41ѵ;ݰ4tvCV nXݰFt KI7,t A7,G+\sZssD+vl +TT"S8)Bs*ͩ0k4~Ҝ Fs*o4Ӝ ڜZԜSDs*M1ػOAPuht']]̣TBJϕV-ha5j'ѨدԴ6@ly 0L-|T4 ޘg1tn$etRi(*[8h'0U|u詨2T̫7T;|w~DTPz?7EOMdSR'=I_=|{;]}c&J#:ul^E'_k͖~#BJ5P Ye:U_Uj=vAg>0\ v{f:*Vop__Yx 2ɯt](YqP=fߨ>_( ag%T * V*\ȡUTKs7Ѵa3 Ku-~3'3Vy}Wv,7Y^dhY >scE0wj/ũ rm~jd-5DKar]J!o؝8|YKxa~|?j;v"-i  Iԭ2gL,2q,}HT"MiFN.6f(u(jKTZZ.B.$]PjWT_څ$.o#WWWKl2EmJm/Bm/BmZ R`#qTk{g&W M5cCc-K[,iu2vDD`ʱX ``s %șxaBnuXvH~Z,Ma2Pna9V0Y+0YjaɺaS\"WyGceI˲%iYy#oeIu V%T%kUxoU]POacں}5D+u<$+m%Jb |Z&'l˄eMu1˄O$}c˄=!>e6رLXp˄cʄ7)3ml,Z-1LwP&;3z& R=C<:3ӴX-k=޿ Xpb,mk!S-Qu0XG|qz' CnCO?Qǐqq!rPĎ,uy/K/Kim}*.KpY _ZxDaCbcZ2VO_^l~{~ #rk<}BIakE%&\5BTcNdUK^k2~ ~Ž<;0g IoXJ * 75.WQ˦Hм4Z5]sѳH~Sdy5Ā./LYl0|Ӝ-qL/뉔eIe_43ĤpkzTM/{=j.߮cW7bӽn ˉܯs^~5Mւ>}** bUS^c tvlVKX*Ty/ZT_RK7ki _\e`#7y,NXc|ba'Ɨ5-0^ Ŭ>1zŖ |߬Ku]%o,P);v{_8_D7>k4xٮŷ>>k[T/R 8e~oqZ/ND SiUes*J\BX{*hj맅Tkeo:kunv]^4eM=nyly|-z^Lj`XU:a7>?~?ؼ3\ M٨SZ߬qMUbƲ = LTg̈́yfZr_b~a-6sX3[\.v=_}m`@[M◣>G'3gʅ^i2p\#ZJ//xι_.\:Ǧ57n)n^zv}=ZҲĿ~f}}./Z8gr/R}L_z?bX.9Wkuv;tBxWZ7+9lkkkeoOu=ފ׽@a/;/8|{^^jQ-;˧VnHݹKE]ᙬsm^NEq;Ĺ~~z:kmbϹ|_S=n;rVT[*jFb-Us>fCSa!ŠL[q>p*NacJe:U*3vj潂 ^%{&gޫJluޫt4^%DIRLrQ'Bk0Uj_/ҬNLtb4S4T} *0TRZO'j*T_;S0TЉ: P ; UT/E؉:17PƁfkrm;B}uȩ!=4B5; UQP݄"QCҎ'W8VUTޱFn/Mg>qrډWuwbqb}:y=Pu[tJޑkm} I~R;qDdV;oú%Awn˃cܫ {*+Wqcj(tBq:8nA9ҠPaN8T[SIhlM4T[S4@d6Pm!`RnS4ܦ2p6]Jm0kaMp3۔ m[k[hņ37OWʜReNN7Ԝ99PyɁ&5':?_99Pzɱ`ua\W`CU+d\E]w~O4g=ڌ{@07l'󄈓ytGm5OރX+\kk+;wp?a7Mwj8XYF;GQ:qAai{|q 8C̶`lm(j[[5 881;v̺p&17Oqm1'ƈ99XmslvCBh}M?._m*tp wGt;&bWR\*DP3j,  wC•baXK)\^ICtCE0kDX sW G\*DԭDp76ry>wyG=wooT 񁗽W{5R:)H9:F61D_ѡѻBtXBtx^l:3lΥ|||E4.o^Rkds;bo{c%0-;DBuxŊk>%]m_,7,-p q> ҡ_$:(P7Gλgdw:xa-t 7,1ACBd xӞ7ӏ$ r[q!fŎMr]J<uHgء7a]m`Ku;6tGJmkZOU6B,B,Bl$͠B-^S׷=b-ڱ@NxA'ɫKZJB+qt}àB߰]8GymG4zAThеBϜ/Ƌ+IW6^}t#thеuHFB/+IWw6D6l6HF籏W:X$# }}st'3vC]]m՝YY6JVm-;p5xytJ*_.Wv.WPW|S o=V=. J텕Oj/TՃƎYqߎY]S형cVY;f$1+%l/U# 阕9m+{E_uoǬcǬj3lͰ4Î?gdM3ٿTk3՟.sR1v&n bkr$w^G?TӼ_YgֿT*b,%;IstJߥTČ ,%WZ찖Sd.5K;IkM%[E$[RM&Y1a*&,$,t֚$,c$98Nuz'Ͽ|͒Uz%?'Ao&Ͽ;ΒO%q^h5>^A'i&iK4Kk烚bh9j5&y QS y?DӼf6L0d?d,`#?f[*( znY[`jm$e9|Sca$ߥT5s__yT䚤RE5&Ը$R{pTp؝ң'$:$TϓT$:yG ^RZ~Gqˏa@3ykMMm0u AF*: T ;GT~7)wL2GT!?IeTIixH' ;OFku ?q'CE$Z hUjMCQe YhTYdWF;2U HS%TʰC"U Ei+.TB(Rƌ[ю‡ve)4"N`oO;Ni+.DΧQHꆂ Xa¥{2p  "8_aJhS,aD*Sp+NXbIXLҙaP bU|}RC@XТJG9t7f4vSFC 7ѱ<ݱ=vBm^wmp5vb6j)n6-0t&cn7**۫:1+ ae~*OҠ~V_CWycJ, *]QYPT|!@8T DA(T 3#B߈ Rk5#=BU),p~?Ck!Slx'9"Xq:B(ڌQk!_ ]?;"ؓ$g,=!{2|B'G|!<;?FsZ⓭xz? 5oF0I3K^j;mU[ǵ#ɳHc+o$6ycj`R#gYyf尾v1ݠbSSCfIG˅o&.Z=&h;1BG"iXWbc.A9P1w/߉M\*|}돡j^->GsP,a KY•W☍ģB-ɂ4j)İ tii  TX.PX\C˗Rx;|5 Q x"jJs]Z")*jL5|_ n *ZSW /D8K!Nw-Uv-E"p""TJtXXZ\*"p7Bp~#ί4qE[[p--kCCkIJVa}c B?Ņo_nSV 39?_:7^x\GTlw{RV斱b-AMgC5ڴ6~)^7]_zy?OGXzؖz޿L,cj-Tw38繷_?,pmTK7TD*auk$gk- ~l?7/sAR֔ԔJy h}N^mB/w^%& MpϷv)F"mwG/>~O_u8%l=s38.+G Z3Ê[ۚWDޚ~w ꬗EOytޕzz?ѿHpv퍸[;WAH8&>pLT~mE+'[Y} `ޓm;%n c~@؝$ɲڶVX4*_vsxs7 He(_s'n7{e ,(6 C!:rIg~W11,(^AG>: K%5< Ki~ K'7؈7,/aLذtb #NEeET"\zD4D{nqdoq0]VbW-*;>/_F=p)a9?FJXb{Bnup. %nƌ<<$¥ﯿe`~bOȈJHbe7B KcK%QjT:yE Q)KPi+2nH: F_?uF_ߨtr`\Uu #t bn 5Rbn0Xi`B@4OApZr>]{/:R;`nK#]{ H&#Cp^5LF2id2M412OAַ=ş f匥6o׵N/ 5: !/} 52.l8>XqJ_o,} fD /}o1K_K5}z$`!XbYn4TYn|%brrB a~@ M!?(Oˡ<mxWj[l;Dr!ׁ +G~*s9eo{\[d^ga{k{ks[+Dc`MG)vF.uF~{}s+%lJBk?Q BkSkb+\m 垞eW^Y ^Y_zeNۏJ毙BQ Q۱QO2l'y]XV±LwK7BͥoXb[MF{itR]e}CPi拓6_(m8i&j:0fvRn`ZkZm4r [*(0]N.J5p)>j\|`[sqZ{s\ Қ/lY^ 4)Y4:`q /X>!KIo+=Dz[~þt^^S)ѶFJ5RE]rU"kgDUR͢BZ״skJbƦ6x$1!r ,]?Ԕzo?B.FƝsu`QXklr.%0u8Z9='xto4J;WknHjޤN ")f[)NJ+%RX1xH+$RXWҬЩFR:}ʕ2ց4g)7!e5#y}|enYK;onBMotmLpgmn}`>$W*էoi|$Q.DK_}znR|k]XT՛,8>mԔRS(wezV[^& Ej\sKPd7AϘxVxX0]IӀggzKu,zn6Hm?lE/:J) )dU1#9[5k5znf ~iO,ѿV]팢X^4F\3ՓBeuu=]]+$bWy/[X=ϑTӎ+z{-cuɗ׵Ck+U^W.t4vQJ3>ΦUR%%e#%ѩ@J[)-ir<ѿtk2p~]K w-ƻ??1IZ:0LB;14p1B~b-]t}N=n+[f!ܴp n?m]o3㾵^xZ9r*ֲymx߯٪Ă۱NenYSy:%F]^u#Y.W<.M x>RH a+|R/=z-zBbRmU겮TJUkm J1Jp d(fDY)Ŝ=0+2s\.nR}@V/{Dߐz<.^/[O(:myxiSD#ky٫wc=7ls5E?G3"um߶.-b˺9lub*q5+7%5|bk bkl6fhi[.cl 7԰9BJX#"2:eE4#7#+/3 3]Dgjk^^nXRILNG u/Ÿ_1\Cu tSGP!rƋ3 e)փhCQ8xF/< L^SZ}l1~{b!J)u )IJRc!XH튱źB aR+.\h]P{ y.e[ SxtJ SFd[ fvk] SeͶ5 c!0X.lŌZǮe(]H!i\)ҼӻЍv-8#5Մfme7G 6NF]ːB2fDlf]͘[ĺ_%ibSl82첀r /86xH!*q!."^_.YFOp̽EJ./F6yXz<]yPhQ|Ɏ9F#6cڃENKGu%ʃC- T* g#D:u=w25x5Ќ?q2{?@8d}XWx1Q  ; ہ-_8I2lC?eԮ^a* T|cTsepq7Tғ$1(^'0U0OC~Hcc38RyºP\!!wY*BX*BX*B+"dHR*/7bLbXʋ(/"P^LE60+iEȐB2E]"E`,8-/'ŕRy1ʋxc,WJŘ (/էp *øP^.N0Nld\.b*-Tӧ"*~}^],"E0"BI(-2wBRL|։5_6_(>|}u08PR xG)^C:遼VdR[NEmE~x?ii.uC5kGBMOJdƀSC-ve >*mtǡprF~cG w4ڔ-ByNϠUt\ gd:}߷y"sW/k&`FjHjHI~n/7nU pDl(ćThgQF{TqӄZ3~:qu[uK"O xm$&FI7UF~pPUcw8OkbXCG~R֧~~;Ʌ>+a$r6gd!L.0bZA\=k%so,msٞ>Ajm.^x\kFnĄu+aJXm6jhh&/۲ׯOu5ɻ1G78{᜜u & U%p7pmPY3LHi2(ęََEE|#њ"EJRt:kztb,CEB~RTSR-*L'NMP0*&]KN=Bt1"E 0u)rVJm5u]hŌuSfTnwK:Xth7SSGkiiEξpMBT Q@Lrcc-jc-|p껀{ݷ8kFѣ'1՟ I7Ko5uה} +SZtb Է0:02qEТ u  :4]hͷxˢ/K,& 8h>aG,cfpI,`qz:ש\fy-Iv3"6\I"6uh)f2 'W!Qʵ=^J6GmpJ68BXH!BՌJQ8kmit Pҿ\JʴT"CW !dEۓgB1rbdra4(FR(3Tf ߀2cl"ʌ.w(WJ5ļRCLk?!PC̽ž.Ҹ&ذ3RGƱF=2B1/TÁ rdVˑa-GeҘXiܡTi UҘƐbHZO 14b8$ÛXjq4_ܟTËҘ!x%`+4i1+ƼSC 5XX"l ]cuX`|Xf?~8mB]H00bM]矟 1ma?^X-am. o}ZuJ}=|deV0y}&"ru}XkU;:b\ךtźu?8@~ϩR=] ZjNȺE[!lmѬx[S$;|\6rifV@o.Znx7qV\;/o硃>Je+y,ni{#,mڷ/|e[]"ݯ$ܮÛ%ЯΏm.T^e-*fۯ-x--}/=/G'#k?>?Mތo}ks?e!Z:7xݰowYr\>v֧Du\Ӂ~XQa ]5lu_P[xq>GzA'n돊ulQXkz(~l/EJd[eu>|^V__en =x\ќOkI;u>.-yt(:ۏH/8m]qr"ֵ=(aO#y>8GϚO/hu~;)sCmb:ef,^Vmynr{`!J=Rr+(ROOO[)K=z}"ՎT|":R!^S, bѤՆTYDCe]t6iE.z(bsv}gjVo[CP0R49J[Zc]>M)kuTZ۵ԮÜU3vp%(ź@- iT&ۊ@۪V*WV""t]X ?_jYk  uX{nڷn봶ڊ*7~TW?4_jll+u6io1-R:[C٪uKP8.-W|Xδ  GVYQ#+̫JW״VTFض\(SMrmjΡXӝ\2]~.Zz_u@{FDMD; ]K线W%&Pf$3u$B$wHvH[VH * ը@$:pvMX- zpfv-VpybMPHaP𓺦k?-RV0`A Ik8ZuDX;b:;oo_d~Rf$b:Ӎ$@pWu`@ڳY*!,Ne\Eb+zCrClg\Pf$7.v4^"X[05Ůݩ + Q= z^ g2#q4@@uւ&8 |ǵ4z~U~֮)BaT ԩ~3Jx)Iա MjoFayY'/T£!Ѩo˅޼Fey<Ō*_9b@4noD<#hrYuR* K1J1J;J+``*)U|}+bJcطoBR[ܡTܡT "jE0&DEp'ToT닣Z_ bjÕ=4;OlvBvVYP"x1#xq~GiQ.I;3wp#BJt])^o]Nz`*+z`jꁡfI>aۙ c](S6L`l#*c/žX4Rse e R ܥXxiRPK/?VB/!}-T˜w[2^*epJ&kx7(ŢsUל+s!ž)7G}kRƋMl/e<;)śe] Ռrx%4ikURJbZ[" DrԊuRc M3BWgeIBR 2S*@O3WVP$T%j$3VYQֺV*~oIa۳_Ds Xځ k(c!4Ԋܰq__(Q#+vkgPc5uj6"<'.}C$Y*Z( $#E'_{:jz2˄ݼ&ֵ597(j1܍,Āa%swr^ Cv 7\;qjsrl/^M2KR3/͡Rm[>97VG`ҪZ-kUiV,=|8X~/s#_[|2~s51j1¹ίϳ &+>2\kR[<O@h{z3PzT. Jxj?T\}MI!4Uk쾟͗'.^ۯs?*ZWsrIAE4WK8P |>Vߝa~v&AZg(MDr%K#Ƹ.q\~b s43kkф2p `h9NFS:I(bH$0\;@a D\|e4`qx se>-|2T*]rE݅'P2jY  gb2vT_:-VghF& 0Y5,/ XeLK&Ýr+j̭2LrB@/c + / w:4e^xFR^eV1!Q3/C UJ^31/e|!aL7<H;R!<~™ꃘ,dHF-Z `2_n^BƲLm 2FB8C0&ӸLL`b>)Ƹ\ HB)Z;W.vBV "*@)bY":NNv1t]PҡvEa EvȨ gDb(ѡBCNa4 :&ӎ%S|#N;N)S½:JzO fPu *U,D֠ Sݞ1b]+I/fC{K[8A\zC1W,su~v]_FULUܯeVYR`VO< W; `h=xHhG+, pGhC pZ`_&7DPbBB _մRuźD RnDO*t Z3hU!ZU|!SqK 'T;D?D ߁#`H1~vU%(Ge)ʭ1ʍP4b~a`KR6hZ@i %$+QL -wf{1ShB0Y\hvhhrR M ZX)hG:27qLj@@s8+A HRnXˆT C5#ȥZذtP.0 Ba$i'?0)1-\mZopN;R^1#LW>U )Z?\C/$Z۩ NOܻBˮm3+c6]\1h+UI _k%li%!:iP{?1[:efli8-x@iw%SNMkfqZ2KԊYzi~֑u*mi;N}4b\7Պ;}ٞ'gE!H'3*IBJ'jO*>V P5c!JvJ\Am/Mk\FǴ(?gb¦E5`ińm`mAMl&Ẍ&Xe VMX<`6&Xy6jQm o c,&X6jFiDTk[NH3&X}b`uCh:1桿U߈ 68F롿#s[=vzrÛ6ӓ*iOv=cOݸғJ{R!՞TYC{Ru.YQ3PCzRu'U/'U_؞T_{RmcOX{R'oNU>Q/Ob"ZH'u ŷqWAD'oV V-Vظ*mqU"5m\؝86ڏ$3pȜƱ9SG_ ܌毈T3HpĀ3fPjfS "qp A !vQ-$83jt3<0Xf{/8XhQ̸AeO^g:HhgF7e#3%_FR֗?{z[zy 3'>|0K3#&ˁf̨8P "u[".x_ƣҗpKhdq.j2gpx ˠrsW/$/=I&F+jfkIas\`F|=0Hft/#/vs>\3"e|HG%M>D/;TMe2lr mƖ] "a-"j q- _(#JqhW (ʸ%\|-hIs⯻k}Dq@2:Aҋ=eti%JҲ<{=*7#H!"'tڥnČu6sj҇b]Ǥm@3>bԺXiV*j= uc-Oge}?ݲIOD#'vqc33n뽶 &o{^-vp>qnI,R=ߠӞx[ d-RB< *)kt+{̿짐B,Wrٞ/4>vP4,u5ղ޻.tVK}~xNեv-bSݍ~5VRocuKdM~b-.7~unkJ &y'HF47O&#c\)4n>Y}C_dc)?SO2O$&D(p 5!J-秭f }(6灎e]=`IWl%Vyqy s&6WH+gjԋ8gTZbٸ?oުRB3Xkm/xM-$#ܘN=u2r }hG"IfقjY R6RMتһOer[vA8e!m z\w@3!XfAEET B`APH(kUU|e_y]bݎBW;k2=՜90m_>~%&pH(E2#_W\df b{XOfɫ{rp(bQ?;kQs $;okX/oЯuCP^AK\t| 3,.]\g%(G}DŽS#]g:ȪPvswQlm[cb~Z]z}?>R(o*\+`BRHJSvzl}1k׿{2FB j+օW [PNش&LZWC5eE?<)==@a(b'׭>~\:6k.efEzs._):8lGZb|Yj\#t{VX7/zc|sanCE Ɠ1$bXe\;w|]+hiĿ )Vfl8pcTUWS|sa3_W;%$k[,{~nٞ"nW#?:Ucݰ7_P+DZw; PZ6{{7Ų78W 9b9C"t ojݯެ?iEC!zcYvηsہ&q{r.i}ZlW!2XZ/x~&fLR/ߓdM= []x(-ŒGnWXf[it^ XWȺ{y{|Jwk[) EAX@m#+/9BGt>Աe@:#u!(t:[!bI Μgr)J@@@@J D.oP-^W1~00~? u?@n  g(?OF<X@2sB@ t_i`\~J ;z/T h 5lM>|`,r*\P!X)|vV[YN@?׶k'/>x F@N^\[e9{!\7/m&D o; tj~ gF.a Hc/.sN nA Pw n%!|#@A@c$H@|/"69.ߝǂ{k Ś49 #JäH7RjjBbDw,w,W )fH"R1J7nRݕV*%".=|~i25! anIO{:tYME3n?tnT@ 4n(~`85*;uf{3w;p zAHLOljc5XM AJT'{3h?e0WmQE H$GcC]]^s0}bcLpIH 'Bq`h"ׯٴP1Nk߶Iեsjx-Z\[IhU# _ؔR;MF S$K/8H|rOa-0¦a\)<(8Nqׅ`+[eڠg,q'X G{})qV1ĩ\}yeZؔZJ<, )?UJMRb, PL -R8(B8)BA"=ij ol 'pFgB*СV( fD<(5zB'P&vJ IXd'6bF?aV1B؈uIߘPj@ |㘈68zzc{NP 졇LN"M7 tIX0&]ӿ)M)MNjh/6q̴\e ۤgPa %TpZ⁢ڨ BV{np Aw~Q] &mX~*9p`ə D&E+r*%x=4+[4<kde2lux`Z9 ՠ:`([B&K"4q:ܱTyܱTy\) b,w*J|UVJŻXr1r/W]HjB$PU գJM!pg2օralʅU@&cLB0- +%d&mCM3  0~ +e 1z!psLJ@1cʘ+2f! C-PƲPssc=`a7*za4K01Ƙ7*R Ms hbU&)41Zhbf@w(AcoPvl:ZWc&}zb.>Ę<P3 `>5RK^ N(E` V}"d/_ VndqIzS]% Yx0c&7K$*He5TTkRjZ+:T=R4o!Zi}_tۮl>>71Pj/֞*hvC}z5G{XPHe[qÕt1;ƥ>؏D4cűL4==4=8KӣRqc9Hz$Z7Wβ!Љc*%cccbJG*@1=)1h(ƌ(XKphYE /տRiD~0@ſB4"Jݘm=gcx:xԖJ^K* 4<Y*80Ao#SVDaP$rp#}qd.OXA_t_=\<[cb\d<= ,@ Ol.H_cwCk6x2 '8C J2$A؞W3,?q[wX^(01&, 4 _E@'}xeX g ڸ>}YkwJGRK`N,,v=Tpᤍ9i1!d1!djYc8b%/u>vĚ7 !dJ*틷?O5XQR`lت69jz‘U6V)K.wJ,ڄ:=dFJˌ*3-3adFNϟ/驶X՞~])8O!5rBLm6׽2,py y*Oy^̨/\̲[ }tA-'ܾ̗^bTYçc}2QeeF[^km?88<͌Hwjm)te'^+cJ )=arܷŹ%Rrj_3.>]EKZW T5uϽ$FUWR'ŪzX>c=.xF-={y~{ű:/Wxs3__|W9bǣlB Qijě]MLx"X7ě!ޔHMHB$u$! 36VmR8eX a'r2Znɹ$bIqF*=m!MLpC%GјT1 1jLj9bh\F:a\!5F2F$&%ńM6z\eʉ\e\%U|V e J?cq!rSR5"W_C*ko䊵7H'=|p)+mUo#!jLnI7'6ڔIcR= cR>iD)Ij&'o1VVc5ux#W?o1r[_cGT~p\mCj'1D:\FYpX<ܱT<ܱT<Q<)w](\e,,c,R* Qe,*mY0veOeePeJe;ʂwcƢb*RQ DYpToTY0O˂!PC`J,3,>iDŌ(DpBpF8(x ]i)ƹF0üR< waQbCc8%C(*^7Xvc+kUvaw&G<)0@q?P`R2nBF1k qux? Q`cX`}S`\)s⃓vuQ <*@M08*;*JJ0jTaQ9 }rTnNLp5?~PpX:c~ W.?52d'Đϝ8!K$a<~ _[yk ph )g,g۶g #~# #ĢNA}pUWmZ[׷KOipET)wM4a_s%44'_?\i,:O2Q5^#cq㰵\6#)Hۨj|ZPڿ5_=k{Pef9j8LիYoesHyjRܥ'X@AtT#-d+{bA贵 ֝P5URK}s"곎E{UV?ì[KHHJS# x,O%R{KQ" U"DYs*Q00Qfmsw:pWBTHVI]s?˵U,G ;z'ĸވkHubؚf$Rڅ7d:  2ŊVhc@ EѐSD0uT1~]ݚ-h@nFR[F!\İ=% ;;. b5n4pvoFHdOd ԉLKBY!"Fl(kKh 4|u{JbF(&̨f>_elmV|25T;Y`i-m -&Yv6ri b~}ϬQeFK떑NӯcYEL)=vf(zCh7{`W';/7FzM$p{GZWR8Nɯ`TĢBQ\"Z7Qyġc^ 0u{%/e9v:č]F)5ٕYDX%8ƕ]ВdJ%5Rl6M;޼֥H]׆|]jhj':]?m1:cQUSu-wov~9hH >aقӁݴRh$i"ZERjٱΟӯ޵?hkvqyn(_"0I&v~I.4Rj$l#iRh# gc+?Mj3E_J=>]ӃZP<_I?i$ŌmQ?P8,|toksFRSC#i״bf[Mvy7v0{RIƜ?_9Rє꣺j-,֠upZWqu/.ܣvrI?gp$ ^I4M/ n\7ʼn~St IoD')}nzDa^SM"S(օ&QkV(^yHR')ŸnSv␡oO]Y~D=(?D6K6K66"MbQ6]6P6K6Mgg U(5O55P5J5P>X/Jf(651`F0l zIwA࿁R* \mpllS)1`F0)٦3^6 651C_f30pCZ `Ikxgt40EGoY~Qo@Z:l6htEGSR~T"@ZQhk Z\Ag6<Mjl4mP`񥶩Dmm 5i࿡ N77MG78cILãJfz|~/}CG$eS[*70g8. CmOh!#&&#BU.LqIT4NF@a )E(=. .F #%Iᖢl-R)'"8ƑZ)+evž)QR@2[zX1b$} )/ԧq$>E|G"s[(o<ʪS,72h.pz}Dc8v֝:f}bq^|\*cY'v5w>9ýk^ g̭uӐBݴvzyԚU]^;"57ӖMqm[a-7#Z-zh}|'|-K#Tju]YJhch:ϡgYu(ZT,R)FZeSoj85VcXb`aSH!:NFjD QjQ"cD )D@*_Ҿ^DS̈^i}F:a1#:vt}HRt.DB_4PWo 'ֵ=l.l=¾]ƈXwv#b9FűWc%l=mWj+WJWm6OY`Ko ,Vj` ): ,q2jՏ=;*z>sUƨz46Fe6ƨZWhuM5V2DCY?Wĭd{z5h('yC՗ں~A U%HEꈲO"/joՋuBŲ*btS΀q8*!j+.6NnMv!]HoWz/.4іP{py1TF"J]ՉNw |!#C!T؆PاmT3ػ3҅57L \,e7],b, Řò҂cU@/RXڟ Cgi@ZT1Їq?,k/QT`&<!9, z-I/8|iс5V}o~bnW/Jm8q IT\(B 9oaqEŒ&t!q1][]qpZgώĭ~Vغ, .B#.NTquq'blDS1ubZG]XU(T\˿MujП!A,Ucԑ^vh:t9t+Z BhT@)T%J)ln3u$bMEg [׎ULXS:Z_qZ!4W~ZȹeuO#$tᎄҮ J/̩ s# jl,=u}^ט9?؈>1Ԛ*ZZupbW^O,,Y+ֵc]vz½|-<ꔕZ^VokFs:-l3/.>[y?8fg|n^|DS;7<0nEdkm7v\:][4lEsnVWJ͑8Uz???~►ÑU%]|`Z넏5AVx79meOtpgl= 2}l\7yAc݀zh կ x*[Nm'oRTb }ue5܅屇I*5QGc5(RՌօ&XO~ܦ3^>?j/}.|`5mx-͍Knb,oX^:-ƺ?4ws=y'VCVX[u6b|M+E4ʓRv: )NLC Gv8c(o'v$ֆ z뱗N"6VGX5^ }QaU?DpoH=(Zi!|6_zc'yO ;hŦ{Zt= VaÆ_k5HSղ/\#ʭ|`Qnu77ȳ79IXRvĆ6jFX]VWx^kPJST݃W寀KNػ:G\f,.ǰL2hl{3xGOOfm y.N@PԄ 9X1=WVx>8e3ՁG&Vz1AjR3qw7'uX:dHRE0Ҳ[r ƺ=>乏LZ[7g+%BIRi5*ceevsaenB!65cY}[M, W.G:m=t)Lq&s/h(տVܠ׊f+߼-Y%$T)\%U~b/QN@WSu9n8MWL=Ģ걖\^k Y>׹&izM'}oJ/)=C =RV:=5/*}\,-7˾;tphLxX<:zkÈ5;"ίV*hHZ ut~B]6[j6#7vR`+IݷeײiFuFliip?4 O2@0ż-Oy޺uwOA/hJNmv` ב=D1[<&Fqd0rH^4?;vbC-[Q ,->E?uV|AqzG)EQh[)av]|J8IukA98i4ouH#>\;+%d`<+%d`"Z8ƲcxLo< J1~ `i#1o,19ܜ;XbU:!PyKÉqoMM3c"9*m7bP0-@j2ӓqA1V )(0 s2 ) Oޯq_q$Qu vNKǘT 1Uj!"H|A`:8*Ҁ"|+.W^^X.J *\o׋eaacaR"T/_,+Ti@(@/iU*U% aU$N?;֌)O,zXvZaH|aˏXG==fl'=V  3X`0CX_[-yGbق.* IXh&Mu4 ],W^_Řڡ4i+}~ cyb+|XfahFglqձ.1>ľGl$C{j#AY@4ֻmy;au`~B,I,f,XJ>c_*N[R,>TNXk/蒬ͅ.uv9:Ј:,o[ bkǺ>v>ރY,e [|\Une7mkKj!Ŋ<WkGB~zjz#BCP*e\rMvOLS^qznNԔ*50dTR2f]'>`oa 4̬ T!7ʭؔR6쉥孄+m`̷rWtX~cVH4*vYT{f_L+n˱VdlJW$OK"S4,_ c~gUͮҔ*P/S!$`0TjhSiǒ۶2]8R)IUcd)p#mk+Ś*L)4\*WWc*w̤7H:{@xgJ<)BBPX²T)'a,'a,'EJȽI}!|_(%KD@jB1a1a(1uYׄ+>*0%)jAm6A:cQ}2"5?׿@ x(j^DcXHA"1CUJPt P3PX'PS=,G)\g &<=QuY:+)j~Gۊvsv*ܱA']6VqVa&e MVconE* U]|5!(G)(,. HS Mi Rwox(8yCWx(x(>4~ALmx.5\ֿx~քؾN8eko+jO0VQ{j/o + p4_x+G!n1RXTXUwZOc-V2Yja)ER#K' !%!|"y:Lmhu˼ԖR:6hVԺlu ICKYJ)mF'a2aZı߯S[v#,i8|!RlZ<fRʽNqmxηE[ 9;I;HM3M6ӌ蓄ԧXq2J =jS)qc$/\(? }?e²RJUynrLdҖ )ero"T=EtnhE'/iH]r~_y^.u!_yp\c'v>PԽN֞5}6[1=xVXc1wԖD>/yf}جN:Aa ϷwVշvb=L)6gz}^G'U:qt-HCcCcC3C5RPСZִp]S~A"a-^}Q}K ͧVOxB[h+h+F=رԾM 8؎U#Ė_{:EW)]RW)R]8*U*J1#JE<Ҍ*{CWiBWiY]8*53^w,Ł?TM8h*^:J)ݢߒ9]tBmIR0۞X>ypퟷ&}pGxc>I5:7yu⌽M3ӕw &V4 ڵ=VS˺ *İR b,İ1lb]a!6Raxİ1,B ue 6ЕJjwJ t1a]!F7Ѕ. VV3WC!`$Еh@Wc5Ѕ]@@36Еl7X acVWJΜ)uzbNn_[pm%$sQ)ѴJ4Mt[~\V\ vӡDe=WO{jUTMIe/)Y"ƆSXV0>?M?z^ j9K҉{9do1aur~=BVd/v\_ۅtUsjZ;WRUfM=.OQ]_P?8u`VbWf|ƲU8?qy ^lBSB'.Rc(@SN,RZfnNcLuډ~$^)ԥ)ͻ~Qa )7TR*ݳj?.H*V6d/x^;u;ATu:Zaxmb_:CDMMF F+=72t:+KLbpBIjsjCtfJ4 ONly4r|w-ԻĿ7x]>U[%+&|΄ωs *}N`SkeĎMj&oXZ(&;b:wC:w c cbtV(p6}Pp!ւ)5"\J5Kk TҁXal:+A, (8p JVo#X t`O= nDI+XsD{7Wט/s`7 t`7p`{OׁnBX]s:z8@ Stsnwn&\+͕J7WY+nx+\3DZ J{a:aJ=eVΰm֎ ~HgXA:\+ V5=X?ރHJ Mdo*A~`Tz]#z272@ b)LTζI2+`ZOG@aNBMkKe\ J`N*_>|ؑqcCR5V 1BlUk,,zc6q~q†srV#v99K\|y6bq`w2x(G>w baO1T?K;bnh i-g,#NZ+㯲~rmWBe)` Af03[jܡ50X5 0؀0XaI/ MQ.r523`Yȿj,6,w:[j&MG)Z9X65wO#csC52쌑 && A" 52P1 6w0XqHݑkHڏyMQ^sKf,w|1Ƽ)U))1PT4NvWl8E=͚@LXVr a; a9t?S;\31ٺ2 ˸Sʻ'Bl C2˸# ߊ)0Pc+ yƐW03ݙȝ\s;=魸AqwDxNgqH#&wgdUx Ҍk,+ӌ;I8͸G4nAqg`,Ҍ;qMY{e#6Xl4 Ng@^p:r:sG9Ebn(GQĆ(b)8ŤEb.%G1BdU<wkLNQN&IV %w27̠OgsBdgJ3۠kx~&*+܄ 傝rr-w{/\/7\l/77Dȇ/ XI]iFL=U1|a;_/ 3 (W p2rz9a p"gϥ\(\Xesq]@uU`V3*wxlP n;h w&aߐSQO u7.,^Ympa~…Zpaa]XhW`z%;S@Ʌ X 1XLᄒ;Zpg;P&Aa-Dj{J y j߹\J7hR@+tl/=7Pr44i'F5 ȣkT"/w'v/= ,S.%/0ÉB)|Euvg **&\E< ):=AFN؇H/w7yD Lң;srpA ¿w Nkw HU} w 0ë0lМ VUyXR.,dJU8N0sd3TKi2<ر}( @M5&F '6\1_`]a\b:`trv} JwLZ8A.g ',I z!YFk$X۠ǍvnԻ[7]$X[}f G<c f%UR~Ү1H;k#4>^eN1U@9U4ȁʁ1jJBU_?JUK(UTɤ(U* s)t-cS\S]t5R9TwcoY1dl\|Vz~|A~@wT)b*9+ Uwk_;c 0' 7Rɤ1}^1 0_/FOѽ)н)ؽ fP(x (xJ(xޔPBPUP.ثΘrCu†/Ն/ K_T~QISZ/*R\J kTNP`ztJ(t"oE'RMX|5y<hDh;&O)<%^jѷoJ(oh|gQоRomMپ }ъLxh̄ןHJhEeM䚾}VB&7AYgb&}q:TWͧA|WgH|nJYo= 4T|Y J8k$f* "! X7KAC=&)W, :fpxUwf3L$8?{Z3ΖNh4HC#7*M6Qi*HC54 qoTţ##v40oSul4ɹi-4^vt4/JqdJJQz:4:1INDݪa ^Buj[UfmjxLZ԰ncfnzy?xSk+Aܴz]pLv;3jzVuh  ٿjd˙3´]-G֫ #Wt(x5#ե $z}o5("sbFAm~]Z!} [7cf!RVuA<1Tc8L{~*3 VB".(U6/蓆!tcmh&t?$׳3 hI"j$%kRe]aWw nHSd5nc^jFULJPj'qYf9S#Rͤmrl2cW/,sq⒭Z}{'E+|ݧ3 [v,r5s?/eJHVoT.x&zE~^ϔP>MMguSa0 wyXU7|?ûBWdtkziLl}]0{f|]k۫Ǐm [&G@7ZPI =Y`k׵R8 2_Ǽ^u+|]ˇ>WPbxo=VY3KJ2%Rk,n]Dso5d뚤em{e17#FF5sDUE3u}]lY|v^a)oM(EZnl׏;ʻ&ۄw JwGk22M Am7e2H2;L Gjݏ{HN{Iy %oȧ7 v7M5`u^M* ~9n^r%/'dl/K&Z%nroyZ}(ǿr\Az8pI0z녠ٰ߰_ +d7WpRJ7W ?{]֏1 ;5u- .6IK=[ןƨc~;PpYu-S2h~09<\jp;|W|Wj]b[.V6gӂ+u=V(3Xx6JkMڳ{mYeRgF>K~Yj}Xu&9<<.=!{DfTق.@jܵ<y+!4!69*6.Qs.{xuj;(MuƵӭ__˘UElP]JXTϟ$ m7v]gX@a,j!:F~:+~nǸ^Jgehcz˧RUkl61A1n$#j+KxnKgjwKqh!u䂷P*WM<7?nW*/GԈ=KaXG!{ZnCR7tny6ݳ,KiڍnDY~t9MtcJUD"<.AEQn$s܍duJ=ZsYr!wݏ~"-J\ZcCM`z7\cc^slV1{-NX.TA$x^U*{qnO{9A gM+Bw,O>7F]f=>ﻙ1>!Ƙoz|jhNm=_(׹D 7:#S \D6TaP)J+ajKK.JRn.i@]H]HWs%fө5SNٚ)vSk rl͔ 5SLAJf fʷL.%_R: o|H z{~?}zA5y)F7|J<bfJCN]TEQ8]TJl]PvQy+.Jr>E͡]ѵJ *φ.OS]5pVi8Đ$Qx}MRɓe4yJ ɓ@ n tJmm4y<%S0ߔ5$Fdm447%}fJaljR'ả$tߔ8W7퉯Mѿ)Wz&u)).Iq RԄA]}ۛP,L\A ScGƎ,L ( S(L#05biӤjN9M՜g4D\5A֜kNyԜ&'TT jNd25P+S257Tej"T շf x5 WHūfWY"RūWvT*|a*^MU;x5廊W(^UM&U[ūUux5% WsCx5GūWòx5UW(^;Tj@x59KūT*!WV(^=gt&*^MSJxUR>RiqFY,K,5 y|YP*^Ui,^ūqDx5Wydc-&TՔH*^MxUHʔU1jJdlR*^MYn(nJgބ^7.;‚zT5O(%/$b-$ ~% 5v{ԳNf.‘;( jm*CU?n|d:?耪O,{Ecz-7:teqc/^&gEPn?8dMn##3i@Ȅ2~2ucK{D4ֺ& PЀB..;꾩ǽ}eBfGf&&6[=|zxsuSys_xwl7rH:SnG *6"'#2bK%&7~J:h J6k{_j\81Gr$ce_.eW =ϋVf2ֺa}0EHNdGd%p򱲸BB>tf:/fm _XkɐP,Y "D^ҭm6HsqF 9tTvq r+C~^B&~;6+Ixhvw!vk!Ѽ> {%2WX\aD [yv,`{mO[+,3 X/#Ӏ6y~vᚩ~eK)#lq;&WUbGxŹc /vH/YӐ.cZMkO؏tJNqB)N(9}bk#o-ׯ~, ~l@)?}̍^9*!.d> #ߢqϧdqEIRjZ?R@xfqD]I?ԩe Ybw9V.k[q,{M{.gmoN8 kun%V!Y8C&\Zv祦]u>=ob5=T1\焒S onOxV[~%]MzI)e = 7n\g!\g %4_rj|WG =ܤc8Y>A0[P4ϧn?Ou2qt {L[8%|zߋW&)}吴=qL۳jjuf:!V n0Iti|t E (\T5 (n{<ℒPrwJ.N(ŀJs 3ukT<;RDMr(` b x'B=\K]Jt$# \X&W6]<=0>HY4(EF4;uFU?Ʊ(OJB`W5guB$Mf[΢c|a"\JkRilq){>{ SsiJ]{*z|Q)5Kis l.@. )0XP7nBc`aA z/^+죩/6DW_mm}aRh/h־ZzU~b)4R[u6Wy^??B;as\ι8y1h( (tƆegkJ qW i<,; debX,{ KXFam]rЎ]?kAQ}c%Bb}bU^:{k`usqmg3Gcw8$5V+roW;* +b,*dc= P,!--rŒKF@ee/ctW/Z3T+%#3dC ;R*9G29=Z0yʳw-<Q9qj$2!>M^[M{D[b=C1}#\nslf}4gbm˽ Z+;S6NZֽ{+R𯶛6<@A HoаNPXoCvjن>ZvU#>tOP&S004lfʗq4|h;Jcv> Ln-wZ?[sh=8$9&0זjᤊ!G9&K@)`ɘr X)'lc>S+t堛.܀ws E?ۍ59&0^J?f>N59iMn7`CՏF7$@7,o(G߀)s ̀_SǏ6i&(@PyCO!Oo vMŅ3ieя1s^Sx)I9S?8)C5׹8\!3urPʉ:X):QTʡ;q9N|srhcr( ~Hr ޷lP {P{Z9lUP &&Z &Bp4w$CA)A%Ddj^"""@JN0+o2̚@ Tb=Z7  B0܎`l`,(`l`,"˷XPw,) @Z2⵸jkWcEZ xm"x.'f>^ j!^㵐"B"^PbGkqDkǯ;^ X"EDb!"ԚH,AքBAV"} dţF +d@AV2`O!l>#03" G;"I'BdyG3RPgB4𺉲"yF'n+MF!"$CDȓ&BBvKU ۏ'^sUiZMMٷϠ[!,_[bm^3=7DXkeRhM eR6AK@!j ʓ.Ej4| ‹N|)#5dR5{ZWrZdy#]P{@q,jGM?W *imvZscf&!>zGv2 , Ih)H!s:u|D amM˟#ooX Q.dVF*V5e42H*J>ZJ)rg bkM x9n0WK/ԎV}S⯍*.խ~H/,cz<1ke ӊRbǜUrVtLGJ˻C˯*ꈈT\kņJe^7=^,#fHϱ'KHDaMqMMlڮJwB Ib-E7mw `5)$ua ѽQ~6j-gʰ4{fŽk\<\ (ɵ4;bM@qM5 4Z՚kixMBixMBix 0&4&V IJ`x 5k7K|4 Ґ1;b, (4Xp={L;X31J&tX8 8064;bx D/אcxMBixMbp L1k8954Zqb FˆpF1}L@*a H3nZ1&4kqDm6^k@S̯̯Ỏ5$DLk1G5П rCeSnc͘\S[,ؘ~Ɣʮrk|*p`b CV!S1>3Oy 119|1?2&[`s`[>٘=חJڀR*RP7\cA)P(y3@@ b }~0ꃺAPA]HlըBzXc!\P ׂb,L+gP" Bdթъ/HբR'cB엏'BDEwS0}J> ʚ;"~ vF4"~ vT+i(.'PyV#~+)$RO!⧸( 8Ԋ §@+#,ԓN> nODY(+xQVP4K/Te?TeV*%/Z X*P*FmX"}5H-&"xdR"EĖD&ZR#FĖ[VU[-B4-nO%~VDuiG,XʈĒ#H,EDKD$X! ;ҚPPPҚk!^45JU+9:T /=~M5JtZ^0g8Z8Dk=Z }!o uH=g+ZV55ȗLc,ֈm,2%Vpۮ9Zn՜Z$gTz칯O"%5A\+rFrtO&j'M<.x7JVșkkuPߍoռ\yr3rúX>SMBkJע$iHy uALI'J nfͿup{,/&rZܙ8Ӯ_`J}bX }c&b+cBbX ZbY@o1БP5 װϺ[mu,e!d!#f媠X0/JHԬZZ룉> AkAk"J Ӱ6֎iGD;fl[r7VTFKd\|툱c}}\:#,QDdp[m>-ɰh݈30xHrɰ!"C"^ZcC²0?X"f`+V}aQ+Vb_jBAp1:bV}uxyW\Z8VV}+b1+eݥ_3~q_Uz@QU}[c=lk *2T.͙rqW>g@]'ޖim錌66RضWG3vQ]uFub`$kBW3zɼ)TkVb捽_5vc/Hzj-P_DEPgݫ7R"!KnK~O@!/JTǠQ=oTZZs1Eֆs58pa5ǻٱ{Kգ8IYye&g@ZדfOT3<#>7VV;fVw}knYkA=īE2&=Bz?:H)BTPZt a ņ,bnvj!,KԪ66 qX=^5Ϛu͖s^4;kzT"o2Z+oT'd]3\KInc~ug[xc"*5/tkjpah;좧"ճ0z*;͈JfTOl>j ldUP-o/ui~P, o=7ϔ K1TCzZ隷.qbI3 S3ӕ; R8V[w7qa#mjץ|xT9YXd(Y֏MpZ.O}%s?i KF@W@"J$N(%'ĹJyF%ZJ$%HgT"qDDKĉZ-Zh W#ug ^Hp"9R3 xHpN($8sH]#*u9RrB))x!;"8)tc0!ҍHPJ$Db x[X)"xفWgo] txbkv7H7Q9yB$CB 'fo|c"|cƠ*TvH DbRH$3D"1)ٿ ٿ WIES'FpB)ٿv%]__#283*+5Sa#EHCdg`xH xH$Dbl>l_\+1 64 645854x!cCM9 hEb L=4)AMp,m$>-45Z Ѭ Ĺ\C ȚNnŹyt+gb bEaĉ'T!N!1d!Υԇ8I>ĀBbH\!1}V߇C 9園3V[1L L`>k}!rB "ZѭR݊zЭb݊0Эk[1݊1 : C00%`tƎ0 02a8/iF``|SCpô04: Q#CL+0y_x=DbCL16Db(t`=@J  eJ̔+!'8@MJ)5u.P6R138l g%]NH>J{ vL] /rJHO&z=.C 3pK1dW'3sxB!d&4]&B'2! 2uTT|1T!Ti˸ZJ 9 T 쩄pAѢ _C˔fX(SX6k(1LnZ-ʹ(} 3_?"鮳-8Y_FRuzVj~ |vXR;,IM&#i"v`d>LBD.$svkxh"h-*3`y-]b&KttݜЈ`I)[' ldܵNXT*j$ 24ծ谜.Ll֤K;hꝤwN(:,2}5=1݋ yʣ" $^~>_\ku]L7NoCE+:,ÒˣDžJ _P~.sad&L.륕{bVS{v2b k թׄeN jc'~,NMQGiT7uI6i/(U6BUyɨ:MW%R45oޣ$wZnF$Nsg 篢8혵AҘ5UjPW]ϭ}ޘ6~8*tM հ&U_c5F5y?a D~ a 5 1U_S 5tMQk`JXY*ռE&TP%ugi5J<~.vUH;$6TD%d7R*ʒ+5hYw &C.e6T5RQ jפ]3YǚPcM2B5*TS4BUZ1+TSV%PdžMXd d=]\s}=%AfjfUJ$ek}@PeԪu"$6Hm _,M2DKeX\YƚԪ բ]SvaWX\Y+2Kb>t )ezQK4ݱ9Ў&" AW@!*/L9M(E^++yTF^"ײ;;"> ՆՆRZςjb)gzZ^ϊ3> Ϛu[ 3{!"JJ}@P}@" g@X5sm#+b cG6H. ,=ak > a]vf]G@c*ز>b.2j,xpăH`*xq:_ƃ3+^`2 A.Ȟ^^ Jd ꀙE,ua= pˀ&BWacY,64s3n,^s@͌~Rf WL+ȕz֊uh%'3D+Lfr]yhUTB5XP蝔Pd͵Tʚk5BR%rV U ѼoP= |4 vM )8Qeuy*44R)Bi:R= IJ`LcN1ZDW!TOP%T^*aMJ`(>zX(FE,GI,vZ9GoŬyu'QQ "A8]j͕4DǠք VI}h4QלVZJ9fI q00gD5WH$`>}A.ΏCڇ9%ZhdaA:P=1-YX_mD91e)М2K3)xBJ(hN4 iZD7Fe}b+^f>aJհj\Kհ&&jf}@jknY E@+'}e-@PYKn ]H]2dmm.Y@l644!u#a!tqD Y\" p(@(fi- )JkyQ4tP,=aq=(MPKikBQ]-uEՒgZ\!jAP|%D]-!j*fYiT⦳b@JZX"ߗm A+!&RG`‚VY {WLT 5Zu˨Z@bJ%*fmr7U1˻ZX$RD-,5Tq6<BxkQ g+8F6TԦykc+Y55]+&\Z}5,$}Vf!jeYm e+exgm!1VkWl$Jn L-d1cxwMr"⊅|f-ûJhűç=:H> 2d+!bK샬pbBa2+!re*ȔqS u=e<& iũ~(x\_ +,5 rZt1N qVe8MP: epzB fGea M^ '%E{+E*2 Vf0@ I7LFՁ( sPs( (I( sPsxiMN瘛Pcn!`s0&Ҙ`sKiM.17x?s0&Ҙ3$ܐzPO!F^셈JXŌBŌQ3zpDLMә^y*1,I>&ahI>$h3LI>|2sǼk$y? y?4#bOy?d~V$p f@[猞i_Zc4@aCiڻ:$A1X``910a>@G52fF怓{|b I ց"HVrSs 0;_w94Fz֒&fQ159(NZ96@b{y8N2y/ǥ-@qv|j\ݻbjoqo=c%$zc;&N%cX=g!`R~.(!72Y7w^Cy2O.7W ܄A.xoPّAV@IxI=zpgT!C$fSFl鹹PiV_t-ݘv 2E-d-{vn()`zG{~oRmňQ?6|sǭ.:jk08>olo|}3E)+ |ٻ12|᝹L]h}jxLo{O/2.4NY|zEi&@d3njVί/'@}3^I&?)fm=6[uV}5s$Q'JTMb_m̓Μ!OݬKF Ȑ85P?܌gUi2ZHT9]2|4:n_Ɣ!L#)0jÚz#눎ҥij=~GLNꓜ2/]-ܯ6݆D&GKo!)73⾻H*r2ҫy}eR >ڣ.T0kD"_%8#v;Gӕ'd+Ce/m>ݗ\ %ɾpNR> g /JvWZjjǧ+qzj\n+~@) e80apjj}}B1[5 4ZWU\ٙH*~=U2}n\nw,1qj_|n5Ũ3RMc[ 2ei.h .-g[ ilܚNܖSdCik&+AkE+بۦ G햳c1:6ִWm{ōa7 zl FBqո6&Cj*m_: %2bjܿ0ku}H<;DZ(46Y&)` Ngk2.٩0Krtj)=F^oW tUȀ@1l;=F ]KI_c#ZChjѫ&9x51(r * nOxTUvpWb-+s-,ؑ! 1PD%BgL d⭐cBvTdTGh2L('AQD'~yLRh!Bd DŽR17THd.d3B&T65†Cr"W@$pG$P$>b|g4*%‘G `cBEFԙK`bnh"X9É,!Pr`!i | ! "Bb4!8QC3*/+#H/ FpVzCblix%%8K %d)bjG-a lIqK+\(rI+*Bb^Ҭ%m_6@2&h-D[L @Z`HcOHL^3Yqɕ05OQ -S;M L;<ƺ`+a (#L]N008\]9r)ޜwNMs ٩[@e$Bøv94<0o?J˜pJHJ9 &ǸRS!J9/@wCx xJ9[ x͑~ x PG.%gHQ\Nv1P%g1N4α/x9qX,'0u `ι08}NťQ-%c(@qG~2( lhė͕0$'L92 y'PYL5xO9e u;BQgr @?R C'@P B9|&yyw JԂsZq] (8 %/36&bGu?Tv%{fcz$AbG+]7@-K_&X H[IE݆%/PyѺVn |/0::ȁ^eOBJP/;{ n%{߻o,JB(VDMPf~]5{j[?cLḾ7fX dAze8c\]W-243Q*J~GMkEZ IUE5̖ †>Td}[lq+%]BtdeWbxVγ:aKj>vg%oѩq|V}ZN= R*8=HcyҚhדjuUkܷ/j ػ2'OԶH߳V+}WkV=¡ISB7JԤoSOSؚ4P4P!Cy:hrkJ2Mg&Aqh@mh|RA;&0h4qǠѤU M 3IFj<MœXsFJsFAJA hi6٠ɢ lcM  v@JD4A4 A-N y xih, 9TlA~44-'e]"P"_CD1D44DT"^t?~MMĤ|4IR1C49K3DT!*f 頢zNMj:h-MMc94~6hhi1'g'=CTw3DSnidMMP44*&I2rhjMM4i4ҤQDNMzih&&kҨl4*,'sҨ4kqҨ:'JZF)gyݿ X)QA5`(0sk:ŏuۯ~v0L gzX(Y`y<٧Uvcx_LH*JYx(scH lxɯ퓼d8;rma˖ʴ ޑg8gmON'b,d )rlƫ fpB @E?@j|m&sY4OߕNL ]fD? 5s)EЖw5w72^\>h :F82Pt6xHM145R=ZF>q*A#SBhזAO0=^a݊!k'z'DOs;/h4Tn$X+1/+_CKQw+Ա(PHp) "7?:Y&?Ϲ2bl Z$_gp]4h=񌖂L,M J]JxFJo+PM0i.㟉Zer 482 5T\M2KX*$k>K RIG5)ԑ:V:ʘPJ`O#(xdmZ#&jcrW@!*ze(k!*^G]3 (^ѯ&6Mv|?3Ot{|>@M _3 (4%MVR?n;cZkmY`|~ݴĬ597^퍣3] X_ZM¾6Fl鬴ʆI+ê / #+c}T/ ./bBUBPEly{3}$V>z#a)\Ut>RvE#*W,.'Cbh[$ qo/qYe~eڸb$w@qX$^U1ڷAҘ7t/CgH֏u#Ujao| Ig;$ٖQˇw&:}]2p*X>\(bX-!R7#3_>\+XQ"±ok{$2BrHj,2PL (J͵:k)y6Rl@1PHM(%&h$٤dJM(ʂHZH͵0 2 &DlB)m68لBblnX5c*=;FlB)ERI` {$/ʂq,;*]6iY>HM(%&^JM(4H%2#67T-6D-lْ#܅T[HnD-n H-F-ʴ[.$Bg-doA-Bg.)HE 2 7f >E-d%Rm!H + "F&}d&Գe=\ٹs)""CDE. ta"OF#2u#Wxe $<􂡑 ň^ dU z!FvRZF/l8B g/T}ooˠ Nu?}/N*r~IO6wZx^jMw{ r7SBݠjnlfgpcNJKMxm YxHxd7y=vhss[t 87q+jۡn\ptꆛfɼ@j8n>:4 MQmpc!u 5lz2oryOnJ{GXW2UtJh@ꤛ/tS8nmtEٽϺ9tMh7nN}v3k$ЋVj}}ц׆NIlě v`7R$8kVڊF@hVy!h+%wSģn0+\WCZ/e^@M*ew:Gyl}gd{]7;2ARTh:tt裛.We Ow_Ih,{ydb7GUH)ЉW-C^)jÛ~:h9K@LOkP0JcB) sZb-X ~0J^-D@2 x$K%ҙCoD-"佉"ZOyD-u?v;c bmbGxĢD:cbw#"/n.^v+ ^PXKKM3jsehׯVlO6~p%oՎv(ȅ(6,aRQ+CJGT4Wj%c"zzT"T+1N^Xe_{?V9YI nDMeeV7Y>( ní"W[%3*3í֯gӵLVLέ4gRHpΘ^X5SPJL(5lTq~6=Hz@1E/#CZ*_X@)7TP b-b-e'r εأ$PUP3"7l_lUƬ"Ŏ9 ;"+F2,d`b{*!W9 1\e2a_k*@;yω{ZќPh Wk! 9G`Z\eJվlU;"W1rJxB(53 h! K!,Yj,d 7" :Yȸd!# E1Q% G9*pG2?RzԬb W$tfP=ә! " Q8 ҙQWg:%7׬b-eFHA:S-L)FY*y0d @0TcW[D0B0u;pa@HF0Ϥa#]5ub4LҁFVYMl^,C) (fPPSm:?L3~ ;*O !fy$R2=8R~p޵2vS+BAVݼeL 63hSL/G Pp̨}UW>q> %'%Q+8^±#§V<|J,(fEjq+;brT)ȉr1" 96d1`dIF9ƹu}?kW+͈PUq5#9B́U"=T@}Fr0V:"R;'9OII(d%bJ AUWz=\l[ҫ4ժ8OOt,y3A2ܨho΍gru\Zz;|:˽LSsND@kay-GKUװ޾} Mk _FN 7t*o{ѵĪ~!N8 1O:Nz֭X> 0\5#f#Sg UBՇ?=?9~d_/v$NcS۝Wv"y-J/[~&!z?E*9j?? ?Rdg>;oqb?0m*BdT {mYhbRu矯~K6mT>X' h.~dn|Q^J,2*7?o5~G~? 6hA8q9.rw,.)ڲRm<],x욢Sa;&i G_\sܣ.8W=nZ<Vi~63TCչ,< 5{X࿟6D?h?88 $~OmI-5O~|ϯ60JՀ;~ a'G[+BkbGX<^sSOh˿88 ,~¦~j"M< f\+_30nRG]Łq`y{rզymu/SaVJ]fЗϻ<~U2(/dz cǟ>) Y2-Z~ω q}{Xc?w}T>ޒ;~|qٽ^سVgjiF ENb_ق>H ?%\m Wwgu!_~e{}e+NdM$ڞ{:7]Qf:+L>X' ^؛ڝ# F~YV=?xZeX 0ڷstڣbGX-ry_TtvgJ6-5^1?uOO/_Z95;ښr|}7ulICQfm׳ENEMяg.n֟+|~ߏ+ڣ.z`CX+t=jD>^-?/Ϛ/*DZ׫1[.,_JQ}wۢ/˹Bk rn~րʎpb/{v}{WܾmH#_j_i,->ay|Al4%߷\ %ssڣ?pV,csH=6s߯Zʟ+O^Լ|A<ݟW8=2"C>X hm_5(t-;Ÿ9<M~?Sr@4,p>}/uF}^x޿<v~O[Eu*RS]Kɧ7®݁k=%>[جypn{Ԁy%CE]q=Dӭ^4vr]N/̰+@]̅wyQ􁸷sw?{},c~T{,KPvֲ_jY UJ%EM>?)6X]b˺qR)~&)!c7IX@N DEG˂hĽepG=nPL RF KUrER{_Kix>;GdOz4͕SUbUѰ+PFY`0*c?d foBC?ZhD5q mV^^X">¥)yF<%q KpE`L'كm R`&E5tRC@e D"3) S{[:-#W+nhgL\PH;~X7 s8x/'糜Dz- ]=!g0e!Dԧ`U8%S I Z̈z@ f`}i?l;gp",QpUEEgKgm=n238&Pp%j`T ._ܩ`4 ~{RS.$kw6/lq׫[Vi'w7%=F L` !4/,1*`6a&$eCt)~K{*C܅ 'sU Œw㜌C}E}SxMDk)0Mz0S= "Jz0Bw+ V(+PN<ߍVYoGڕt9S';k0 X`FǿG* h2A:V K"mg@w%#2D1cPW"dzn17 8,81m~> KKkxCe0&]U7lY.1{U B~ޣEI3pD%i`;==pR.!Ҥߊm}hkM;1c>\M#㖰s^v/e2.y)irN-~3oe/OpX$R#}ɇH -#,ߩ.Ys7P( * oz vMS?(R0 H?7F x4w'GDcxp(BF2#7s'!&Gל-g2@,,aaہoxTu)Iϱߍ$ߪ<InW%1)0KsKA+*MT_ KGkxbs i s2wg<&P {" eN!fRiH:Vɘ70SB&D?t"%djxi.\k.,ݨy|\H-:/m=/:NHZ실D IX`-.re.u[&$4 &:`?jY(,90(,aA:P wpNI"CjHԜYKή~ (ya 9iM(#=j=3ZsNT% ϛ 8#N$.]hN52Li>sߛP5N N"z&;PWc(5/h)00d)H& &q |}.|V5S7gƋWaCƚ{A!c-Tk_3MSc*j,̨P\h@(߫l8g|m uJTYI"2Yck}. IN Ym@,,`=qw^g7NI*ćdD2Pk?pZ˓DF*|W,FDO.X.Z{.$ޞ lH7$pDh/&񓺘7Vb\;1i'|yK_d#mX'|wDy~U GID}iH:G95 NͶ /RB^>@t 﫤brBC!^} fo=mHZ^.rdY.X"&>^D&~7}0=&c7qrf^٨Xiu8 `rlrNBȤOr |އAn&FYiVCKbc-'AdaͽjqK~;r5pg)5*裠br}T87,@4mĊc F-l~>EJއѢ?o6Ƈ)3̖ZX x* 2%2,0 K1;f 47X 1@SǍ(@痨< h.JLD,HFg߷"/QH T xG_bxQ'h4'4gU)ͯm`&' zY&D?t"%kixb(*B=!gs}C2DJiIAK#А!TLAE/oB[/Dן(cq *@j)`ēE#zH<)xyDYƵ V16tZޛY..xG's^v__ݲrXjȄߍՏ{GsB%_KSbv"KIZx>Q$d^JDNJwg~r*{+q*/LΉPʶ2M>UQ<骎4949-N,aὉ!x:b,LH󯛜 i2zi$iH8xn l(,Ӵ+Әm41A:PTMR>Cvq 1YdžWp|j/%'sr[H.X.Z{ynw9),^2Crf~aR5ĩI?!mhUW"i0]|][J ,fU4>Wa(bHƉr@<0,G|tWLsiCʜF`/uN:Vظ%]ixDTS$bƫ9: |6%G[ǻsnM4x}Yfc=D܌`maknh3 7C1f܌O"/jO{Ku(V#Ԑ4L`8NKA,/,!' {V^l|=$H[ KŎ5b z]ޚȀ~~M#ԧ$mT eNX>Z{?'-aXXsPIl :/L.NS":ZݔOVb+n5u}nϼE0=n;Ī8_EQꏧ FYߗ+/)%O eO6Ju񅽰>" LMĄ-ۄC=Vn ~> Y6 ؒȩD\:aZ^P'"0r.>4d20Cj^Z烥t/οZN̽etK{flaΜ<ܳAFs)e`6nR1!Q)/,~K{Apb}q.F9&) 0sqI y@$-<8Y\D:- M(bo`aO9绉8Ũ;cxy]G,HNJM~> KGig.U0&G:_շ nk!8t9\y}h1Al`9<YC|ˆhiӋH὏ZU2ES_7A̘jrM Ѹ WK"Iw I` PWj`A,/,!' #{9: ?LCmO`0Ghw8 5-q ,nA&G!03ضAZ'xa 9iM(f Oǘâ9QtRڅxK%@Hiڀ氈?5k +%oixK~pQXߕGC΃#I&;4M`9. 9Ok)xA(Ecy&䰥pq19.f%!( fMW}Q/Qj8nIՖk}.s{z 8(7)Em.}5 gp^ْ D^%#NL$6<]({.hm7 %ػX$ ms4 86U[7Y {U_kt8e'*,?fۚ_w蔈$- XO(O$vKkci6q0HN r= `oju}*!\ {@r.AR>K{ >``=*W'NLZ{Jx9EͣMBYL7Bh)k'E3}-m[n .Nt ވmDZ8~>˾%쟗w{@OoND`m8D7q0 Qy?NNBZZR;*f!F"NͤCڶ-aߤ6@Y^2q*29P;q8 ЖFⲊU(Cn Is/JC Ѹ KKkg>+jр MpV|Ed'WלSMfpjqz%5KS"aE̙ŁspCMȲߌ$eKNg\"ap*p M,\;aZ޻ػws1(a|sb/4n=|"i$r4jNoq~M)a}~^{F "*,4'YB]>}7k'F&@/m)-gC *8ѱ@>XbyMB]OsEt X @PޭH0Ay8IҰ覠ErRЉ6HuŹȒ~2fJ' AhQѓ x3. FM\N]~v CtXؓvDY}c_rXE8Ʉ/#Y!힋eXz8On[F4$7A8!.9z-UMh'O-ϷlDUZn&W +%5wVQ"z·mkwIo:UFFZ5nuH l4)/v}糜}.ilļrr'wu(hdy2"w 4>%}*Hd8BIeKH#,a \lV:x?F杛 %Z/ {W}U6@)z`;h-8#W@~u#<@`Hd 5Yɪnu3||y{1mNUgG8CU:c Sq2'i{}~!>'}r}[)gy` {h -N#l FC͉블AE(&kͱq4 \fl٥!7 q̒<&t%L]S%p$xrDq+6R&er O]S@s&|{&k6Af`Z ޻ء|ޔeXȶXS^41m'xq?uꤋs#W)FLXZ{ 8ΉD8 n֑k(0{[^ I3KD x`6YRC!mh/,~K{`6:2Ԭ۸8Qsc\R[3bH,SէZMHZ@Q&T_;@7w` h M+oYWTYqqМ9wLdO_gxTb [IQB kn&H?4׿ࢮ[!U(ȎMM,_SA/BrǰL"pQ7RCEi\zGKc^)a/὏n̽i)T#J镳N"6цL4gD}~+]q8*xh-v47Syui97=zG ˤ{8Yp!%N^RCҝ٘eih\ |Ǟ 2] ڸ8'[3begd8DPlrxp_ Iյ fW3-Dp.]<uNEq GFF/Ԡ L/3.iN̜UQQr$-!%c*xbl(ԼY ŷ7`}H 5gIgiH(/9#΄JlΒ൉ӿ; )QN9ld,1cY/3irjJ3!CN98Cl8m^X^Z{{n{zz Y%'^thu=ެ qMJ}K)4msz/jk:%q{ӴTtSCD i, Kއ{t}VC,UUqҪc$\>TV- m~> KKkxj<>qmo!.!j cQ$ZI:7%SV`LAթ޼SXa',^KkqD٘',~7u5P(9Xs j4>ř7X:;V;nZ^ivfyáLt(1=M=l+#?)rIi`etal;NX ]PG>Wcu4 Tl 3>a8,ؘ%#EDInKây4C@$#Lt5~Xl+ -37r>nRhţx~~mh-yiZ֜ªR)88%7-~>ga/:`P?D88xCվ C+xap[j'òM`&[Wpȸ\ͤuILJ v*9&[糼 wm(,)DK']=R~֤U ծMBRGi*}+|G+@q%oixCw[DY{ 6unRkBnGy?]ˋWqiPOBR6w pK䬹Ƹ^q4wDDB뛆zgSƝ4/mF&|@Qea2@EŘH:Q(Q)"h$X4sXi9M@.zk Lz~Zf,+{|0!+-pNzZAOes`ƭ2&H,`ཋ=g.Ӯqrbt؜hd`tlUT5XIB2g9LcYC\7lu<7Z ޻p &ϡ?lS: st)?63ĥ I_o)0M(5wԠZAZ߇{H  cFsB= =w􊊕Q[ҺjM.+!'CC6 AE/oBoܺNSwl<wž<4fiYhCIHnٙ:=A3^JއKF8"zL桖)G"|$ HIls>YqTxAۂh$CJRޅ%['^rDʌQYzk^݄gkT$r- IVC A,/,a VMUC" A/FZ`2w ֌~3 c&]}mȖh,>ڪMiiHOvx*4=WlIV+&GjI;Gwoב34mbCRБ\&zK;a ;)]썵W@H8*̸982¹̦Qb`ISC0 8/5XK2A,'$NJ{;fꍣETY;+ONcy<8|8dMK蚜S!i s [Cm ҈G KE_B.,K+X"0X2|8_ Ly㠘mi Fq0dwvܼ0ׇ aavXaέaC(D^?qmH&ȓ L14V+)`,պ{a3P(Xe8gc=e`$yr4,w`"?I_MOM>8UƤ`\lR7tY [_LNY;PGGGNSͦя`̯M"bW}A-ya {i }]D\u39wSs8wc̀UQM' /'l ɦlZHi-obpp~G2۠.g'+ow&Sb(d RXSCtz @̒Hmmk^AEѭA a@NnP]ANvʃzrjJ `4`2FPq ` h M"&%djoh = D/釰2D<,ۦ!UrN8=m0 b[؈ElOtjs\RJH⥢.yITLXL[ V0HJ}%m*xB!b#  cN8M! 1rl%ưXC [RCײ!On]IǎQ^̪gE>90>. a8a-SH $LY|kN}&ǧ+%5ƣn #)U,|PY*̓Z*.K'ƭ!i!5kA=4SB{jkKr~ffD֬U{ D (0&,xqKO|I,>K{{"$Fd'D. (yYX$g I_N-NgN*Nf<]gE.bCa)NZX𚜙`%>$RbL840m~> K倛٥U Yp8ȘWJ5U_b%q: I&VA/&w.M',aὋ%$}q -*d@sTS ;$[I\cZ$C\ڽ\]ozgٷDz, xR(Q 64Y98;V,3-zB:` 5 TS3nYq:^X">^,V/J0,{hWii;'qSCU5Aɉoi|ן6H {a {i }T8jaq!aTH!**hbDp:Kϓ ܋\U  w/K،~qne˛IPQp1o<0HC-@ĉ_[m6HA^X^Z{A<8x\֓s0/]8cIh9.$xUҟz郚-["C(kU,Nԋ/VOLJX-p n %hl` jȎyu' B%^:TfG8⭳DuW#E7%<3OͮTuKEkxob8TB4[l 4vy4. 7Ǜ5q-7MȽg1lH?%57F{ SsbbsqdxNjM?JOj0M3o5H6H?%5 "{sJߢ_c %9ȇW3V$gvlIy|lL8/$u~)e}Nk{.òF0]8E9YMwI+j[O%~<{rX l4a%577jSh  hb6 8N pZtSbrxZLiI,`c|`0)cVUۃ/@fZJ4L 84A,',^Kk-o~'[ Tt rXA%8 <1$rv^xT9Q̿vſ&9zƻ""P- E-Z!ʧ%hi8odPr ^s[PˠE2 }S[qBZZ.>8*K'M~> KIkxZd=<@0=@Rį\_,ǃ5F [%lĊPA71eB4tm(g;,nEÓ$W C1P`V|:RADB^^=Ns;-lpEm%pc`3}uJ" .KYâڨ@] b3shCdN\ha=Ԓ4D2N T  zhszӀ.\L Mʊz|G+7an4D[NvbcP,Ҷi0M¬U.{k0vmF[^X">D:vh#d>|w**x[4~ ,ȐeR2 iYNX>Z{C|աgT|sriVa'[ "e`%R`tC˦Yt_Q3~nOċ! {[/Y8lWnvoZC҇YQdlt,/,a/vk7*ɏqrL^ pǼ,I\wY+0M* G!okF롉|k)xBdVA3vSƹg WMa6aMuC0/Vtnza[@qǫMd2mB,\BbOON 7kH+k~y$·&A1xժHϲo g [*N )f8d<&v@H4̓sL Lå0G|<&v &B@m4591v\_jkIJ0yH ics*^Ω^(0I5ހ嫒HN-f4c!mɱQiNo_IJ΁˚~,\&a֡ 4w qqS]k$4qHȜT.ۤryFB]+go~(LMWЮʨ"@dc)Hz 8Lk, kdMFQ مQ%7Y;|8 1Gf]U< Q#Qb]z*]@Ὁ= U]+D|Nك"Ù[H*%xZ& tj0MxNPbal~> KއPŐ!Fo`cp37أȱ+=x[t6aICҍM" *i^X^S{:=܄>s^zikxhw\F-%N3i0&Ґt%P@rwd*cĺi|ҋ὏}ύԠ@ B)Y34~;J S&AL_1'30SC糼D- }0 o~nCo[!.*:kSh`6ܬ%"mL/,~ڇQ odpCEWenЕG .MN\+P@SDwr RLتfi~Ъt;~vMB!ivo)`2A,',a' Rol.d <[L;/3DR8}:F QP,U ,a}&v ѵmk8dU3~8x.ln9ni0MX!NƊA:V KKkxUXa|Trr87귐2p,_xzݛ '}.5$xnڜ\UCrj|ruI4ԞDdMCҾݚxEJǞ#ķQ Tpr4}Ւ Dxz,ˁ)lIym MS8褌"|k|xJvDnuG;؃Wmr.m4:Д`ҽ-s'YIA/^3-r!W-=4QWOp\3YtԑkN=]DgFjHZ(fDU|]}mY r\ڂO>FQ,X{*$d{Po;sj.kF*S_ҥ!]2j5T] gya 9iM_O'2#ŽnASզՉo[{UDz4Ys49p3 ҈ RޅPai;pM'D.N&G bݴ2"o75ˌq{PchB"mr25vX9&0ps]&]k7~sc ˦4m9U͗84lN̓*@&$b*xA{e>qt>*SsF07B\W|ܢ?J~֓DQ2 YF5(|ȤgP~JH]8%؂1;Gl7TCQmAKiP oTprfd 땜Dz- ]Cqpf EjZxٝ~ϤuIs:5$}𺔌\J ~?¥?}—:>!NAX"ϻk9ч; o4F;E?lLKShx>ÆwDiC)` a䡟kg6Y9Y[u15j@ u$kt=.H ,0ͩ f4%ia?k)xB7ۭNxij؜Y2a6nD_I."[ Sޛ4JWs0Cai&HF5 Rޅ~l$MuLFhBDI#iM(5 ,0PXcf4~r4vob\QD{آSw Q䩤U#l0l%ɹKn)N ǴZNX .teȍ7=upg̜B'!c, ?oʽi-ϑ#RAw"&DߒND {9iQ+~UE,݂7v&8,DTg2JGi./3Kňg%57[w'U:ũuqOD;̈~rMbT"Hix>C,1Fd0&j]k%{+O{ztL9wt3_rjK6H?%5VۈQ9B43G e>MӀp.u* dݲ`P%˷Mx(s=ڥT91?N3/%Ić:S<2|6ao ЇHཋ=;HT{4wҨiѓo:^ob\} IQ s%a)XDR/2jd }y9ݕg[@w_4 $ ݷi4M? irs:75l_4,;ay5Q8tEWIMƌF\][aKAkxoa\{:0Cߒj 2*9=GZ76X\t1`9ko)Рt۾%ֿ7[$0G˸NrT 'P=!Rm}|jH*K:4l ^^&vHUTnD@ᘡyaJܦCUqڶ:i!-y@Rrv [XμLXb‰[sn 蚊7]$m nBM l>X>Z{2PsE*otL2Aa! ~ePV4cՒ!91&s%w;C|:ӕdcWoi区< 챱 ~RAV&GŴAŶ6ոwCPY| آæ͈z<\A8J ևj8u$LP %mph#Dz- ]`+(5{bVO8DNmdn֔!zBTT]4}",Yq=”7(GOZJĭw`ŀTLƵNDz- ]r @;z9q„,ͅr5NVDĒyRQk0F%0,6H#%/,~K{,v=PbM/'XGjI?&B7H @x- i6sNW6H {a[pSb>ODjkCK0I_[+ZN 11&}8 e1<ǁLuyZ- t{#QD0ӓ<ХY}~\& ']<՜^Y +%57&Jk/daq A[&I5aV`'$0҂ zڂ#WAga8y#0و|'jbR|6NH`\&Ћ@: Һ:=$ߝTS}~H¤ K Lh&MۡIvqdUA :-su ݨ! 0A\NL:4۶%w|]S!Dň eNDs+jʱuƾT܀(nEW+-XaF\dC4ަp"k)xBivtΕϊ3ߍ3**I8di(}ZnYwhNaXAA@sHz` [CuAVu= Olv;h-SP95,&Or}JGˆv KI+xoPs˭=x&Biʞ4.I65& 2Md4rr_ܬ/0G5'ٷWR*/b%)0Mg4@RcY|҇Hཋ]z~7NFzQna$NX%qD(Ӵ|6ƹi4h4a bg30 06Qp4̀EcT QdGZ3ulщvmLӆJt9N ,HX6H `M">^DNVΌ;?zuN2 wP‡%iXa-K%)0 ,GL.?:m. p&pF'.A!,NyxT^~VIJ#) g1]+qXI>tZVé.Q.Nq8&qB>wҨuL=#԰h$#657lFNS^XBNJ{[MP?1Ϫ3|U'z|C?L*Iԩ%iH{46XAs?]6 9i]؂0-`ԋST Q-_"ٗF6yO+80)-T~.k{ +U]y#1#=޾An0~e'F9K0Ķ4.~c-A,k81s\&jb; ! #}$R4P'QH"bako Td r`{ 1&6ܵ.}톻K{ U.Cv(m&a-Ґ#9ޖL|>}n t8\g{q.9hcD'VS Cr$q]a|6`N~#mbjr4wa}FaM[TU%f fLqm3M~h*KLyF i, ޻3VŘ>l8ՋdhUiL Li0MXaNSPETa6Hk%D- }l`D'LD)=ң$%_{S`p's@VatA4 ,).`˓1qdg7/}܂i+ĉoi OQ+$4 va}]Kn b@Fޝ~$,paD+ nAH]CwsKPp52mS5%6ٴ@*U)g6"@+3.bͦkj\a%") *<8YOwy`tY^[uaTV)H,dDmڶ)HӜ948 i3Rn@?/~P8h]|%<- ި\WňH#$}(UeVpg` -x)0&[ Ûg4ZKp0rn1*jS +d1Qw28fY.X"&=ISw9'?ߓ"*|AKxss>ROfQAbj]D#CR.Z{FR_ݚh D+'U0-é.T bT sy9s. F\.X"&\FO\!:JK#)ޠ9gE$ݔ+OLPjkA:V G+xgi:@g)fTգt {K?i0]PNNo*6A,',a' rn_hqkqbuaw d5Ik0 gJDroi0MXap )i5Km˿ whYO.hy "Qc c,pD*0]U?&[Aaux(Hേ-zO\aQU@w)\`;xIbH ^▆Ip)E6DN/RBNZk:1 -QgP#07X);,_x%~T 4G9EwiA'ya {-MZ+.7jTFh:՝k{zJA?[ӴϚsdw[Zބb:2nyhL5ߍӁ w`d'/KPj^yoSY-:Jk$>Fsӭ8lc ޹K\q` -KCDfsH5 zJ0>]P*taXR_[!tǵXA҅_5e20afh*#9#=9E v(8ЀP2a4z9q0j{y%p)Éi@%b6b0P}k=R\6йʑÞkzpqxH 4@3cT;0-bliQ3C:H_H> O14 i8[CLbEI]LCGolN 2D8v kG"ǵIVLӆ8^ gya[-DM⹳$/Ifffw'5jMw@po74$}T99qF@^O ]of]% Wn CL=Rn_lHժV`T N)P0/ļR8aZ޻nUZ8+.jL$B Vqr$5G0}[Zn Tf4r47[>2 ʍPrX@͞C1)'dW/0VD=XЮ49+=F=?Q}"DYnDР1 ײ1j MN ic}p κl~THm`rz9MmNJS_!"0Ȥ4M`9M4ARPak)xb/iE? Gc"~ ϲI$HN5h.O:ah]T.U;o/-gc"ޱU德ƙV0o 6 IW>%'r𛔆VYk^X^Z{Ebo~sG]ˇ6CGdq6' Eɣ&XAMCI(Pih8K >|wLy U ׭;: w2%F]ZCINǎR\&&KG+xݦk}1XTL}9T ޿; !hvDJâ1(0+ q06H}x  `0,ɩzA mNTpRd#p-`6tk"Q6H?%oix`ƮLV_wN84&**tU$H#{Yo+k0 X`*RJR2!)^Kk-Q LUAaUg)N#~7NOF.+0M),0?Sꤩ_a)rjz#I/tpQX+3+"Kl,v v}m&Gdd{g{,f!aDGEFVwF}cY 5Ԁ$s@A3EZMb/D zmŵn tEfTan55lknyTyXF`%^7Ęr-~{ƩMaWa"oYl[mq,sXftamgu =@3%`fvfкP=AP088#"D$@"@0 3Ԣ1G_"!8,j=B4d*V(!`4z [/a׌0 7 0u@z wZ %b)# P guZӌ$V}j@[DeQ0*L~"͖2>.AM\4 N50q+Sٌbg)+IFt]J-~fquZO bbvAoF<gdjc+cGkVYMJ'c4c#R׵nN=}j?$QI=^0ZȸE[Th +7o||ZǦ]O˞{b9ugCX0_ 4-Jˍ7ON՜:uABS`48:ND5*u+:"p`[ =[.l&1'3ln!t2`1vIӃ5 F }8q )x Ї]$nj&:5͌\1 9נS[ *`nMWഝUG,L8@I(AZ`[ +:IW%# !I0 ΀&!I;F!ݥ`fiVcΰDP pa[ obq<{/~fbձ3m䌚]CR$,nMFӶ"< ݍJlц(h(mHf $nġ@/=d ABR!CuLmm8[<& ]q$UqF#: 0FZs]`ZM@jh&s[>X*Iia*Y"sȝ33NGtK3\0.Qi0ev'tfyl{ $nj֣3V-hƁGD,F; K>8=9宁z Ї3lkQgnj2#HFRpJ42~[TƞdCK i0:ڽzy4nemVM zpY`fK1:q Kd) ,_hPIipz:9` dp ^胣׻^0 sdd]UK:N'ȍ33!CUUasg%Up(44:qRFi`'/SA&aVm=80`YtHSY!^6f@@"Ř18scA N'f;w _)׀xVhy¬0 4lч$7n[|8siQf?ViK()P-ߋPk6w3V®1!w9B  }8WtզTZ}fYm jЉAá[6w7o+Evnz7uhvN9fU茤i?X/J]"4828pp #.b] J4I=Ӫ߯Py;OL#{VtC>JFM#;sM)8Y OaRZa.plSX&@~p5[N t Ojztj+nj{4]#tAvlpcac|LUƈ-ֆœd Ҙaz-H7c'1-#3 $oof=5Gb#] Ŕq8@ZZ o6xbH]MNuNڍaZ/€yF[=dS AN`}4S 2hE(y5ho+c=<#dSw IxsЄ3O PLҺ 4k0eJ9]yլ0 4la~%HY@(fxeqVdJu[Y)^8 nMB#BShuΌa14A ԢaK ɉ; sKH:wҕj D 8 }יVDl3$jj֢M;kƸ5;'zZU NtZM]7_5`4D N~JLC,4cqNg7'ج,$.5+֩u.,4wmgK"58=Y$l\C#Z$JӰ9t]&_5b8ҁIasS]Vq?X&:tR(C]L3"4Ix#gfI԰G1Vs#H:5]LNBHCLBx* +F/40Mö}T[}mуh3㼜3G|.3b!"$,@42 |4\Ce>hvCÓzآ!0kY0:g;:ûv:%]=県L8AR 1 QJ]Ml4ZtG \Q9gHCu 5\$|b@iN^îan55lka.kdbH3#DB^!D$Yl1$ mT`.D8q 1"^F($njփ_NGO=+uq XY(OFKds^|LӁyhNf0hEԥʘt `[ . NpXvzm.v6 4Җ0Za8j^41Њ 4$FӰWy"tL%~b((7'?(APG!g\3@>AԊy0 ;MǷttT9`soS?&MQJz^tPA\HAOtPYWgwQ^[듣%w@[1]5ҲאM:uc]7_'!?7I[6LϫyAW< 描gqόac{WUmÊ!=) Xݤl{i=6p|p{ bs֟Iz.k7kۖ*Xض&mi}Z9kf܍]jawÝ<ʱ+,MjJISt{w߆9GtE]SeYʳD5g^%OOM2w+~$}< 8:$][_0mb0QXe,@uu64(~^dYx 9;֩uѤBU]v޵}56vrjJ1ik,uAN×ڠ8>j,"no"$%ɕmd>8ꮬvg88]_[OZApLz=f Ӱ]aΧ>S{i?(2tPd1O7[uu.fA`WquGyNHzVԩ{kO RuN i~-$=YD]Jz體?~¤i)d;U:)qi~~IrnK׫9%BJd߲5oy_N~?t kXVXBN.ce(iJ /؂[NovTXAҦ_uޥNH-())/K(ZM/#RPӟWOzE]H$%l[W/?Ή/F^>"@e׭ˎq⼆_tJz1+}Y@ˉI%6#V괭/R))ӕr\09n/R'z꫗*bJ}%Uq{{{~EdZM/4Ѹ}N3}'Ny~WEU*.SݦZendstream endobj 275 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 548 >> stream x%O]HSafn-`EcRQZn4dndmu_Ijsl!!Y`"̢ $|h9/CyaEuXC!daqTXpfنXZNHѐ}DOsq"'dq3EA- 1iyFdbMڳj[1gͨGU5tO9Nɴc4:1<_ج5Yp.t,`K0\ÏPZTLwUm$tWdWG}]q*gVHiVD`S9cB%J02oyhmif7&[vS> stream x[[Z~_a(_F3tNs8%h!'7Į#2B˺_^3QLпtq%肷ÿ해e6XYL BTW7X` :zpZiWe"?d\%\d&mn6s޸m?L:Pf^ Sդ_1|]6ڦWX#ͺV߫o^]mLxp]akt'lja_( X-hctAy_Xk!)©\'/ᦒvHN xV9!| @tfnղ=ׇ5Lf<$ H/BRr dY5UZA1PP@ :`.!)w3ClZG-!ǗAuÐ//bXF"H=tWƃ`&ʞ@ҊQz+K~.m.DG`tT(}X O*!7z"H΅|}Y; !^&@YU8ET]$>E[H.(l!I PZBydidp&Lr[ԣWi9H2ox .%춼$E>ŝ޾^yM5xwP[cDG7C^miJlJ8BC ĤJL5v =1-&龡'Z !PT30I^uBP!8Y=!iaዃ XϐdGB%DOy3*oD)%@@hT\!v1LUx̥3jo@9_$ |ϒ AA(5vo`?C,,_,c"(h1P='d3ܯWt*#ȬhQv"#(c A"AFEk!GZipZ4*9pVHBO(YJ${|o鐈T{TZ=FNAj;|;(5BqvMpl.x=ۑ 2];t}Sѽ\$xD%O Tϟ",Voms3{f]%xGU%q7%͟TzZ.5K$2uHi gevt9]ͪT1bw2/7gy"ddꛛݦ^-_t%B$j˗/~1B"WlO A+Txk]e匿e"(T] !_ϗ?RC9,ud+LPo&Yo` HTMMoyןӛ>Y@YD@ty,)¥ \iGH8ȫ;|x]5߭,aQEɵ^s9el+Synya4³M)uc6oneg /=ۥbfBj)\vJt vJQ̮#>f6bXfbK5WxJ!SJXiSFz5jn؃ꑴ[ĥÄբnS \ԠIBQQ»M)Ͷ4NŅ.q/%}Tu֤ho7f+RW [7k-+ՃNu`?/ϗ=lG1@ܞ"͍F`Gwj_+4 IJLENPJX$x-Z3e-Yӵ-Ty@~U@\㞜UCsN [ݡb{}מ?LH}=TP)cRljy"qPm̓j}±y^aM,ZAI]J.|hk@ JIwЇrԑ~ɶI?]zϸ6hN 5k"/ բ/d}~r Ҡ 1d;+ε ?Hw=HK >laPZd@2'5x&3_KU8?Hsw@WNZN˓t.Mt%?::2Mm<?gKUq|w4x@bos%?h|endstream endobj 277 0 obj << /Filter /FlateDecode /Length 3421 >> stream xZKo7/eK8 MjM @dA6 %u<=]ߪ"Y@~YW_}EE$\a^<^p -ɸ^l*sv+^* LᄓE-;?LمCZ_6+`B98ߝn}ho':%2/vrkg3k_M,YHauf.!V3)7ʾ|g &ӹ9MHX;_<7X*D&|\iaoҕ`/q[:[DӉR<}- |!a[O =Gw }; 4ֹRVjTI! W A^o]]|wbo4ܡؙ);䐨nrBixpiu+ ϫA(0P': o` h_`Z6wG,=;ŭ:8za[KedNB>^{ 6uմG+)Q>bn: >ByNAR,72X؋YR¿{w5E*g ڎP4ECf m@i]G!3Y?%&65&CKCIt -%V*SAWQB:SKSMڧaʹdl-n crN}? y~-`@_ie4{9e7 7.xeqhފL92conRW簦n @w uſ7u|]~)<܏SU+wZ/A=p :o}C$ YP+zcPr7+rxHHZ5#sm{ հ+U7j7&9<>]D ֬_C9k҇"č^@ػmh=ꜰ_+\&GIAٞ55. d0wl_Зctp9LCduӏ7*ƑM-}}NӠwÔuFv9ibC=rɡ3O1҆"=Nj-g/ׄnS4Xl3@ ThD%&gw@c1KxYo6N$oF=T*QhdEh:x@grW?l6R.}+|tn)S& (B:4H!*DJ)RWG $ց\C@4|Xm˭O9^~y,̟^H0tH+X**YIK9 }kcu];ժU 5<xPt> ^<ܶǏ!7&ݘ -Ĉs}D!"^.Ν>);8QnOIBd|2jdp'!p@6uB$a~VϏ?SMl*&Ea{z4B0+X Βd2>M QaPTZ"R`-|.{j(GܤAbOn;}ـ]Okm2J @7N@s7uUcK.@7J( G|4GaqHL:k{ |KS1kxD.Q;%,S *:ؙ-)pȩSI^$}m$1`iȍ1n6/6y{ora;$΅X IGKl8BP'#"Vs5|Q¨ >3W&TӢQgܩ?Mle J%j} I?)Vcj7%Qˆ5YziG#I2"~pQ!`7e4fqZKM}SԨGԱ k 0|s?ADP5;<%'6jb"[N8CwJXC}\&rnsL(9i2J߲tle-yYI)¥Yr"I?PAXer{ U4󈶉>'%MCG|?rv7+mu tIkr _Db|ڈ/j, 0f݆\|fThmZ`s2`)4 ztmU'*"@< AIcBR 7 a8 ķWqdv=ܖNF#maVzn=ݣCMkeR-W+%bnБO4^, ]x W}==hKT8d37 15M&CNK!3~)(tث6K.?5rrVx?vlP8L YQbЍ "Dڕ\5X?vwu@KC ̳P kBpHJK]D4Bw'kf {$ާGIpԎ>Mx܇hY֛}@tцtu@|/ z߲o^ϯ;eA!s+x ^w!W8 C]8<"7]웉LtkTn~oh?H}g*~9{vj$O6(:х6؍oP'^ 1z"EO^ < $$ξ{1T?bԇB߄nU JqhH<.DA1zҘ&DK_NDendstream endobj 278 0 obj << /Filter /FlateDecode /Length 3337 >> stream xYMsS.:SK/l)cw핽l6YR II ^kxy3C2唪l`oyVw~{Vpio:}~lvQBgJ[yzu,t)N 2[SkL*szz'y+5vѳV-B)UE;/~749uV>sʪӫgWU8E)E6z3 K6BK/^r.5MCxd^v[;caf+V~Ddg*;C(ЦtqNl po~}͛ "m@ڏl9?S !Y}Eӟ' Q-}0p0y#? j„\nth%Ĕj[/z}t;Z)jU>a,u}pRҺ Ɨ݅0Α1E}jz@^nM5FU6ݷ~d*Wav.9"L߼ T^%/759T,H R6aW&S]PPjqQ }G)]"^]!EN꾇0O;;e8#q*飰'j]"VWAth&~qhj9X%V4p/fh0zj@X"kb_nDBDUn*D^"!:q μ/eBǏ%xS= @9lzee!㹒|~4Ʊ Ifd9\J ;Cy}o#&[,lQt9C K7;V9Bx̍| gϫMfY&IfnU~nV6Q]Й";4ȭrq䀖.?D@V zMhttI^pz ZV9IK}WO_1`2 ϔGv;ڬt. /ݒ͢?] Μyaac䎒`ܑysՈzр;-W3r^}bPl`ҦM9ϻzt!P2K/ј#ԈvoU#ڊz@bb(R+Pk R x*x>o<ثDevclP@nJn@tK~UӸ'@G2|SmC:H;t8e&uQ\˨b q6|{@J樝6$kBHmG94IRtwH5+?C=d$LmnτL FwMpE'w^m#;2吷wCX5u`+O)^ܴsBm|TDŒF&i|TFLUsWvNhS{+ >/7zYr`m;F jƛh1"Mwe~$qg|w^dV׀]<7}9yRI.|=1#ք̋JGdBFp\sGpGr9dd9i(b%Xb9LٺE¤2&#?{T}7hu(Ѳ PE|%:IjۀQ7Lݣ# Wըi|% Hi.8HQщ pUh.*]q Y­Ҧ[sIYP4Ʉv-*!Ѥ Pf`+TRIPܲ N2RĶ2ds~p􁕌 lPz Xh>Rcuuή-F(Jsb4!,gYV 7i/o6}z*rrz3kF b/^ڣe ςN챏\aQGX $ٰ3^} yCÖvg!wg ` (>WBD(C=h}yƙ{T,ƀB6q/[[ E`ty iDB@˜|ז`fC$tUF F~?CVw+ 섹.%Jɹ) $4?7YOMeth+>XWWoT6M3} 86ܠ!7cYv L!&~ȪT"wddnhv$F)qR20q[N/mlzTvx٠`ę*t'Zs*>va|ġH\e.G- l > stream xz tWCNZAUd_GKݖ,K־KJbɒe[16xl & B6ty&랗+RLeH9s̸s$U,ѤDYYY7fѬfM-ge2LɆ)9w=.>g]3Bq_=ه{G|ۿeU=%nmR"mOfcL^?rCBt dXy_e8|![F_t_L ;YdJgHgeF,k_xϩ0NsZ P=Mg5uvMI/[]f9lC9=4*eK'HV,xE6kWv =fbvQ痂G!Ѿg8Km-E٢JwSS%tVz-T(urV('->[`~Qf'a@QrK K-P^Zs֍W3\^u%Lm@ ͩT,62&hI DPWhgj߿-F(QVu~%fKK0IGRviZ5\0zQ!Q%sTh{Mn3kr|NV%CGu:tӄĆR.o+=k{:rik݅BC #Ĩm`',:G׃ 5Mިx}/fLf?o=DT@wG$t{K೩yZjoZR,Wt}:"؏@rđ[`g4ї"e{Уd_M*?1cw|.z݃f[ݽv>VΊTXՅ?OXVjyFQID;ϓ{[NssjԴ)R"fCT!"(ymU@pvlᘚYwqd?ں_Vi?lG)(WAqjIS0MMOP+4awU9f i!p=jiX2A; !+`-~c+Jrbn_C{8Xff"ka'Fe\p9#a'XXJSؾ_{f]!sY|.7{;?SfX` MA&@e^&:ө33EK=ӠwPk۾Y{~^B3sh:z "dP4!>df-Ե'psL^^\ \%`$q856>~j6՛n2ٯ*VT+њbi|ﵗd|:T!<ΥGFpa40A+-mN ONÐFjߘx![ŠS_;' ٻFw6B`A?]ݨň52CHOylC'3[ɡv&3Ip}<}2p9Rr.l)v;ȽVHH9=`h`0̑]D2h{͋*^5af!bu*D87鐵>z2dVjiPlRa2r 0` )p r%zu&%hshtGBumsa!׬bոX TOVJ!YGEaeU2JڪтT5RM֔S#fh!9My7:uSmRqz4JGϷO)GhQnK:zY_|6CdRNxi7H]zZh=ۈ>p;Ԟ2([ !̎Nw;.2h_KH,f֜k95d&Z.DkX@@K"j Υs%'N:Oljh'Q]&Ppƚ {BM3 4iڋfɸFo݈%TLI=&pP8#mpĕh9i:HheҪ/ռw0^49ZZ₣wzt P.I]XuO,k0om*ʦuh@5ڤjd '+\VVtH9;0q }O>.;,S&b.ò7ı#n$F?ccwg)l|n+&Մ"@]BjƲZR]Q\T}eƃp:ou IKCY]I/u'^LƒY//ocjw4M{FP [M$4=hC}ڐOj-7Y˷ d!@K՛w =zgF)֭Uf_7I.…ݑ?qbeA=Kµ[j+ KU6eqayp 1 AGgO}3;.hp-r|3RfpOFC'Ԯ&.DZ\nrw]XW :rC  DM@یęBY~Sg2EvN;45m#f#WETRoWoW˜֨Y'$OyZa4[0V\oXM *_hr H^Aȩhgޮk[dU@3Vv+ckgAtC?1 6*c8һ\ H>pJWq:4Q?񲎭:(ӎہ7u{ de},FS,WبE|ҡgVcbgSG]Q8#(&uz~'LbX҂lwƎ'?0k&FX\BM*p-*S7{R"öTUe}Mq`86m9ra'5! z6 u׮&EƢcߟ@S]Œ kT;vm5TCUZxV.{esXpӛ.+Nރm*/[j,奺5A>C@3K/a| ja,)hk5 *vQ rm 3A 3k6pSMcMMcX+>,<Fk]2/qdaCQ_莌%:HrD(nk7YL(Z⿠ȟ׊4-,T5DZSul]Im;҆U׻Ɓ`p%4Kܨ2 O6[9.binNƛ:;@MTl^MZojRmhEŶCZ 8nu?}q1_L`P,۶.ڹ ȼX~zcJpfqRʫ4)z3n2s׵ŭ"™ByGMh 1ZNƚI% k*+o/ofT&-l> s#(\ &®&r>"QnR&7c!19^ d+  6g`3W_c5Yv#M̭2Gc9T i驢kesaa[&&LV#-m|D-@# HHRHJ% zhRfp7o)3Q*gu&l6qHZ;e ={K aӦ2ҠUVPгlyg䶯Dwz|0 J0p]1K\daO>+37s!tۛKprSþStz\7NYtXA@;dv1%%VW e`YPaq4Ӆv,Ӝʜ7qcWYхRf[ VaiaLN ˆ5X}X^b=8KBzqqo'2 eFO#6d,?$ĻC|kq7`(bC4X'L{lluRٮV K2k [S N= ]{#백\7/=j؎h"D^@i+ \L~P?Cq75۴h>=48zc>t-|tmJr!83'϶G1O#=Ts${'"eeXK?]F⡫|]?/o=@hrj4i=9ƣv7& l:sOzKfBQ=m#M13{ˇ|܃813K_f, g 2~ .C(yBV?Su>6|Ёg xX7&t uuM|ý_9c'kq 뽞rWhb:vQB+E+{R4q/*Lcsb>NaѪuuuZ]Pߞ/nPشš,x{=F7&}2p3T*UPGbd[kK%9Tkq^@Tgzw1 f9(Iѯ߭9ncPחjϛslB8+Q 0{m- %?"wmd^OY^sz?ܣ^w臖@R'fVLN~irh;Va l& ٫wOL՗֡SүXkق w<"MG{zw{ƀP9Njj(f]MNL,;}ЀNCF0-mx`s+!,=/f&[!ωi' T6XY(872qAڤpm1ھ'b= pXDOx7D;C4%S9;`,S3(#=kCnS:B)>ɠbi}$C_N2 K* ub-~Ս]o/=dMN 4;em&_5[1p~ K_gX50imodžax< ?[*@0)v(>ߍuyb N\:59Hy??৐fmh$G.{.\z'YgcqL,i$ʅkDjZhjib] c|2тX71 Rrьh+nGә;ZY2FXlkH**rBU\fd;zsQvřˁʬ߱o 0L2dER F>w28QQ T-!ܤ 93fh+hCDoȹ?B_ȯkq"NlE @/xC(WbuYtWW yeLFF@$*>:߅Gcpl#ԋ^ٲ^Qv@nP`08}ʮBxk"%kmݝrpo `1A_XMݜ'5Ls2j_/7VZ \'#(r  x g/>kİm $Ѫب 6 Xր0H Q(SKJ|i1Fz=oЭgYAzgHO_|ydhҁOc; F"ܼͬYtjG,N}D_߲'om߼hf1t M/lK7| :: 䐺G+[8t,Ƞc7okm&,z&-Ts=h}$i[gSwJQ盷?>#hw6_$xꁊD7',UNӢkԃ$ʒhe}E.ecɚBˆ8[ jU~'lͻgy֮,{&,0M!0oomok2Tnzyk!m F|g:fyxsz;}nwBy8sx 9ݢwjz{V Ű##FJaI̥uYe. KZX[(B'؟ڒWbi.Mmb{?эVvfA⢺h222D_t+܍p_Uԩ\iiۺƊv\4#6s:vD]WЯ-Vh!?լ҆rJojK%I~m\|ߵ><rpӂ2xTx&%}~ZuRj>O.eӥip,.L,ޡ7XEk76"^-*,76 9ՙTmmVVҒt(/e[nn'%~GJlɍAF:QI{,% q.<~Tʛye7E\A߱[s|MH,3Ya<1CEUOвYF.n=i ډ%Zsy,lR|tC]?R6z eVOݒ~u0r+L*'Sendstream endobj 280 0 obj << /Filter /FlateDecode /Length 3781 >> stream xY;wջK. f0w$˒%!uN5 pPZmN~p} )1;w/~9yGIz{-6ǯG4.HXϿy, bkcc*#PY:v#8H}DZ,}Ј#gp 7i^O#s[72%tQ3J)o0%6$RH1>$"_qV"IZ^JXpDÆ`77e6yYc~uB%,b19ca7 4좁-\ -ؚfzqz{r Ôl 3#d)kr6<_toxfi$-$NdON{ڻzvK/8"EyĖ+o |0$ -02J Tp2lv6J!vc![lܛqy@p3ANY~&$ai!?˜^9Aeňjq6HIlVuϰ!' DmeAE}֋t ;۳pZÆ7iMhLRkM퍈 `Nh#*mA+Ps!eռl3p9}Pf|,yK,8m>6 ;ǴҦFXu|tiY:묀qе_v#%>^ŢWd44tCF\#|J`]1X&[{ĉ*eD<]$ ,fM:k#1FEMYw쩃YV>IB1xpYu2 7`52QC1D/nU @N\՘Nh"-H\ U[5#}ŝ C፴bo"oۍh~?9kqI(%OH EiI7[67:hD5GS*Y /BԥH>h`,E 1_t2v:dUl)&^Xu]<V\OW Duf;^ Cˆ;CSW=EnRC1  (HF%ɍCcRe ~L4rЃnR3k 0СlOj1iEsfw픻O~.wɃQI|٭{[5+M 3HS4r_j%E)H ʭt]5Tو'.Y_8KG{)ƈ>kÁն+?ce #5M奙obC|̾\`XB_bȇ)~',?jGYI śh'G?@H Ѹ/K @ƿRF%K+dG}d[ ޝI, lB<d⾽Yy|H "C`nx^8( /)H ^Hp jKHOޖDV,u?vk &/0NQaf,j s7ڦ٢/r!̌T|.i*!x7a.XDK\=|\q8*1θt~v5 .c[Xۋ<24@a:RJ?=.o/R DrJH)BW'-_Ko0v RyljPW[Oɼ%ғٵZ@)(ɀFw&LI֑6gta !ؓ/~X5j2QO`Ea ZHIM9Ϣ]Sŝ2a5fԾȖ{K ;l@mQn8ݧRlk/Q[ɒz}vHQ֧d>i"w,q%:FB6 "2o'9+{c`p22TU]ƾTJ7&ڊ-g~$j ވ$ 7vB,PIA4qXmc/Bǩ SdZ5.a9ڦiR}ց| ]土!k̽dhPAw$5UUӺpHhmͪ:(P-J^?tosx^rR, QWޮ|*ls- U0hev% yӤ~U:V`mY@ 7]} kkPo>r6&Y,7T9-O@ ~1v*Px>ܶ碍ױn5S%VRM! ͪdՒ eϨ>ȴl_#d( \E rz:!ȹn8M;.`mBNGT;'GI8&x>`Q )t]8:T2yմ]&ߨ0A'F p,$JD}"FƢ*vF(ݫI w{L/Y!L/862ET^,x<_Յ݀~+חcX!ѢHSG =PGŢ]NbQs Ss7UƴAD#Pu!" dt@|cM_V|?(0#v .!FOt߲2tLyEڕ:՟kqR;+Bz㻼]>+24'0jѥRcN\>TdЅ;ڋۜGqR k9sYaGj C!r}! I;ltH0@E8Q_ѠV8%>yP8)&2O'^^8dK>C廄`2uaכuo"ϰHDPIc6I+ls7n%.&}S'}ETp\J W}5PQ#]ē6ͣ0u9P#`KxoT/ veiZ|=X#02CK<»*/O7GGpn=#dͻg$luH:6:}k=ظz%f{M-Ɓqn3C}[/ՠRmUH,{b?dU%dzպ j%^ٶk wCT5(V{TceS,D 9s{Ϗ cB endstream endobj 281 0 obj << /Filter /FlateDecode /Length 3360 >> stream xYMsFtnaˎIHJUqI@{ )-`{^~,MYJt=[UWw :k[LüXXy0br3Lx1f6a0y)OU>|6ޚ"lc*ss;f|w{{ JS-~As`REa#fMr2S4?/w>d2؈?\Fcsn\hI32XN~ar5Lk47UfYa0z'ʼ Kx;v9"T*|ilbmyx#P_S(ԏf@ υSbŰ x p%U[Bp&(0Rw:mDy8lo_Cu2,;:ZT3Bh4).uѶ 32 Y(],Rf\|?vSbL\F )EDڀe JJ8ĢE?!'_TMaϏuqo5=R001Dvk Q}Cx,p[OGX:y9\ob %\WvvwZ4?:k,{D2O=hynY4"4@:jBpiaGnVIʦJ Z`74Xn؞ X5M]RdDr2xYsҕu*IqmYu *q`!E[:)RqK{; z >e`xR)J2ѾVE;Ɣ=q %^WVvtx젭7@ {&#{6_95aq7a/TG ̒TMyь=*<ԫqBlqXenħ˪_Tm( h&.M5H8B08aˣvg ,^n0$RwBu֢CB(ځ_ְۙA>N5XЬyFO<m{16恀 ITDSzEE}*KdȦl#M%8Q^;Pm5t<4/hæ 7R&"pVc"LRwhfc5D!8(Xl 6݇!T sdnu5Ҩkew%* J4&Dpca%7w afȑuy&CaIuLLu6yXbwʹE$C@?iGdz8ҺZr^Lħ,e.IHj)ȩqnHK m$@ IhxKHbv@~YyϚcU1sJPdj腣@]UEP˺+X>ЍRT0ccH\ɡ?ː\7ET +,-ӌAPIūEOHOTSDi-M;WE5\=yPشCOt vKSՍ!(+9/SJ;s0{>`ňui8y+b;}KY.[X6Q-9[M +:FZ8"kPLHUIeܚޖ!}} Pc^i n-VLןO7{26h%eڝJ!bŖ(k4wF%\c֔Yn>8H9Gb܎ ʦ^},-$X&C]N q*dG(ƽRd@bPsKgiFov~LY|K-Wl%bz"$_wYpϡaP!x=buO$&xZNM, 9כCt,NrS8atc|mmrX~}n^`f*\;}l'n <| PiMMnaؚﺘHZΕǟ{Ŧ-(V$u&9]o#\^Asvc:$ 9W<4[>~r>8t6͹DVRLQbֆOwKgS3'HWq> stream xYKs8|[hˢTmmcؙTdkhcR&_7<>*UHF믛< ؜_O$=ٵԧ6HOoN y* LONӛ}0Ɖ BiljJZ)l"0D4i-ښ_+QFT@dc}E$F(*oG#jeqnPbQmnZGmݽcY$b"QOH/)e$za2U).x؎4ݼ;IaPө,OD-`r F#FQ`M`\Y|\н~X&}Y9jmxɔ%53Ro^ZƓ LuHvAd(%ga>OD4LCbYqGw&B36S T[qbM2LcXkm 3Qa &Ahֽ񑬝B/|UL"܀d?Ml6YK&GLTv_y io 'MmfÆ}h @Wb:/Pjq͒YMQWgǮg=fG1 زhYTH\8/jGqhkpz<coy򦛋{(# ##mBsxu]{Z޲F"|t'7Y,H$!K̒ݬgd6ؿʺ8jَJBV-<ߚ4D4 ";2 HW\)]u[e, xXM֊Iȑ/ӒA"`$̚?*kN#<1VƲ'M]UjXV.߱KWݴ=_>N$lˉ&|%SsDSd 5[[LPYHfC=(R=WVgF!`BRt@ 8AsN3mu=a&Vƿ, 'Y2SbQ:|ۍ^4}$>e' Seɫ8v9cq*nńubQ丬}-N/-..ңԹΥ׆C#^mzr1.@I+VKJ2\]!=bЭ$&íǒJ4,Cd3"pz 0҂7A9S 9Q"W@BROS?lp y\BaʙH!7Z>r@tHs>\p}ۑTY/ T&[u- a0Z(,+E - pRg;$#A/D6dYp\8\u_ MLk*3&m=u\M]ohPa9r琍C|hB%|m #d p_9&s,SY:_AP4[ی9XmR,lbNʸ`@}X ITX&"J3~3AR.1Ja[1 J'd .3^ H]SN\,_:J4JJ7lG{UXWoYyXzl ym_=4/Y35xU'n#)w9͑ e]h@\Щ$Xv7QTB?II-}&a?Ϡ{^O(<!o:\suD]#_Ʌ0/!b:L£)Zb#y ]huVD5_2/*uv_u/OySCVh5wF1}(k1pAIO1EmYf}/.&~kJ ?MۊNW$ 7,+z]3i^eu`\׆}_ecе;s2n:6nZY ,KwLR30w^K~Xܯ2_f^tE o| @>#gRӟl'Ai~ޢs#04]9|>qeNe!|7.OʁyA^b \n5msļj[Rf$Rzړ \%53יK. LO&椎:hjP&w p& he[^$ WWIoҐYUP"36mΆ`2p9(]R(D|3rW7Kiv~fbśu"&nq%?1jlr嚰9)5vܽvtr_#= G<#b_jD(B_%M>LJB3:qwԦɊu_d{JH} զш$ӊ EAUv:M$j#$c$Z=1C[ڵ=:'Ї>R(r?CPdbG" 5 ƗLxv b9&"&Z=mެ=nnDћoQ1> stream xMsF [~֎:4&9tz`$&ecQ E;XV]u*H] »Pqz nr5VJ;x,RTnհmHᗺP!nEg_ڮP N4Rm{xۿ#kڋpQ5 <a,+#]R*Ts@:Ji"ܔ]:MI?uͦ0[av\IJ"Q|W.R$C:Gz]4p/3[x0䉴RKa/W[It8 McԬ0bN\#^'aLsIRRћ}i.eqwJ<-۱]JFE}6HI`m o.']i]FF=cQXBpZWM~zEkC)&O"7ۇ@/S&>g,f\> ɳp>!!{lYԆo|F3 k{'G+Dң?ςM×FUEyF+:iX#5p{߹l=b;$X\JS F<<\MΈ0#r` U}sTV>]͍^5C6y%렾z8sXB$eF?rwN(ӳݷ]Sy ~!+1!xr(MR0LdpȬf*<*e_ ? #11 Z[lRfQؼ(P1Q )ȳ/㩭2E+W]9:zL޹JOR|WeD0z(endstream endobj 284 0 obj << /Type /XRef /Length 290 /Filter /FlateDecode /DecodeParms << /Columns 5 /Predictor 12 >> /W [ 1 3 1 ] /Info 3 0 R /Root 2 0 R /Size 285 /ID [<026ee15440ecc1d9993eabe33b014ce5><12f85b851ecb97d345e2d988e0e09fc8>] >> stream xcb&F~0 $8J?@6^Pܽ5wCϠjk%Fcmp wټA1^"9sA$od-b D RPD"'&ȁMX"Y@$#d`3+lpV\` R$l2Xl=sn6Y Die={πE*;#`9 , ,6:W. endstream endobj startxref 951075 %%EOF dimRed/inst/CITATION0000644000176200001440000000105614200237535013573 0ustar liggesusersbibentry(bibtype = "Article", author = c(person("Guido", "Kraemer"), person("Markus", "Reichstein"), person(c("Miguel", "D."), "Mahecha")), title = "{dimRed} and {coRanking}---Unifying Dimensionality Reduction in R", year = "2018", journal = "The R Journal", url = "https://journal.r-project.org/archive/2018/RJ-2018-039/index.html", pages = "342--358", volume = "10", number = "1", note = sprintf("coRanking version %s", meta$Version))