dimRed/0000755000176200001440000000000014153365332011463 5ustar liggesusersdimRed/NAMESPACE0000644000176200001440000000457414153217466012720 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(LLE) 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(LLE) 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/0000755000176200001440000000000013753034327012240 5ustar liggesusersdimRed/man/R_NX-dimRedResult-method.Rd0000644000176200001440000000244013753034327017214 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.Rd0000644000176200001440000000571113753034327015066 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{ 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{LLE-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.Rd0000644000176200001440000001246314153166463016052 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{LLE-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.Rd0000644000176200001440000000241113753034327015324 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{ library(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) } plot(cols$x, cols$y, col = mixed, pch = 15) } dimRed/man/mean_R_NX-dimRedResult-method.Rd0000644000176200001440000000215113753034327020213 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.Rd0000644000176200001440000000152113371631672016214 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") ica <- embed(dat, "FastICA") rot_pca <- getRotationMatrix(pca) rot_ica <- getRotationMatrix(ica) scale(getData(dat), TRUE, FALSE) \%*\% rot_pca - getData(getDimRedData(pca)) scale(getData(dat), TRUE, FALSE) \%*\% rot_ica - getData(getDimRedData(ica)) } \concept{convenience functions} dimRed/man/distance_correlation-dimRedResult-method.Rd0000644000176200001440000000224513753034327022604 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.Rd0000644000176200001440000000536613753034327014455 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{LLE-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.Rd0000644000176200001440000000221113753034327017120 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.Rd0000644000176200001440000000053013371631672015102 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.Rd0000644000176200001440000000641013753034327016402 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{ 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{LLE-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.Rd0000644000176200001440000000175713753034327022644 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.Rd0000644000176200001440000000340713753034327016203 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.} }} \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{LLE-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.Rd0000644000176200001440000000501413753034327014410 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{ 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{LLE-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.Rd0000644000176200001440000000602513753034327015633 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.Rd0000644000176200001440000000253413065033470014275 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{plot(swissRoll, type = "3vars")} ## Load Iris data set, partial matching: loadDataSet("I") } dimRed/man/Q_global-dimRedResult-method.Rd0000644000176200001440000000214413753034327020127 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.Rd0000644000176200001440000000112513065033470015713 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() } \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.Rd0000644000176200001440000000244213753034327023132 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.Rd0000644000176200001440000000415013562225201017336 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{ 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.Rd0000644000176200001440000000050213065033470015154 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.Rd0000644000176200001440000000263113753034327022134 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.Rd0000644000176200001440000000051013141064362014043 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.Rd0000644000176200001440000000561313753034327015772 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{ 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{LLE-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.Rd0000644000176200001440000000543313753034327014576 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{LLE-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/LLE-class.Rd0000644000176200001440000000437613753034327014260 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/lle.R \docType{class} \name{LLE-class} \alias{LLE-class} \alias{LLE} \title{Locally Linear Embedding} \description{ An S4 Class implementing Locally Linear Embedding (LLE) } \details{ 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. } \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}{ 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}. } \examples{ dat <- loadDataSet("3D S Curve", n = 500) emb <- embed(dat, "LLE", knn = 45) plot(emb, type = "2vars") } \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 } \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}}, \code{\link{tSNE-class}} } \concept{dimensionality reduction methods} dimRed/man/AUC_lnK_R_NX-dimRedResult-method.Rd0000644000176200001440000000347513753034327020521 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.Rd0000644000176200001440000000045113065033470014126 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.Rd0000644000176200001440000001101713753034327014217 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() } \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(...)}} } \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.Rd0000644000176200001440000000431313753034327014357 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{ 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{LLE-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.Rd0000644000176200001440000000605313753034327013607 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.Rd0000644000176200001440000000650214153200601014360 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{LLE-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.Rd0000644000176200001440000000406713753034327022707 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.Rd0000644000176200001440000001077413753034327014272 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{ 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{LLE-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.Rd0000644000176200001440000000415413753034327014437 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{ 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{LLE-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.Rd0000644000176200001440000000515513753034327014243 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") 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{LLE-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.Rd0000644000176200001440000000760013753034327016240 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.Rd0000644000176200001440000000050613065033470013634 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.Rd0000644000176200001440000000544713753034327014402 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{ 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{LLE-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.Rd0000644000176200001440000000231113753034327017210 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.Rd0000644000176200001440000000230713753034327017762 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.Rd0000644000176200001440000000222513753034327015731 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() } \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{LLE-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.Rd0000644000176200001440000000040613065033470014072 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.Rd0000644000176200001440000000045113065033470014107 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.Rd0000644000176200001440000000511313753034327014255 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{LLE-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.Rd0000644000176200001440000000275714153177013015332 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.Rd0000644000176200001440000000141513065033470015030 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.Rd0000644000176200001440000000047513065033470014550 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.Rd0000644000176200001440000000174613753034327015137 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.Rd0000644000176200001440000000504113753034327014313 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{ 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{LLE-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.Rd0000644000176200001440000000124213065033470015124 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.Rd0000644000176200001440000000370013753034327013505 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") plot(scurve, type = "pairs", main = "pairs plot of S curve") plot(scurve, type = "parpl") plot(scurve, type = "2vars", vars = c("y", "z")) plot(scurve, type = "3vars") } dimRed/man/reconstruction_rmse-dimRedResult-method.Rd0000644000176200001440000000227013753034327022516 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.Rd0000644000176200001440000000452013753034327017575 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{ 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{LLE-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.Rd0000644000176200001440000000047713065033470013665 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.Rd0000644000176200001440000000425213753034327014376 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{ ## 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.Rd0000644000176200001440000000451413753034327015050 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{ 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{LLE-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/DESCRIPTION0000644000176200001440000000301014153365332013163 0ustar liggesusersPackage: dimRed Title: A Framework for Dimensionality Reduction Version: 0.2.4 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, lle, 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.1.2 NeedsCompilation: yes Packaged: 2021-12-05 20:26:06 UTC; gkraemer Author: Guido Kraemer [aut, cre] Maintainer: Guido Kraemer Repository: CRAN Date/Publication: 2021-12-06 10:50:02 UTC dimRed/build/0000755000176200001440000000000014153220135012551 5ustar liggesusersdimRed/build/vignette.rds0000644000176200001440000000033314153220135015107 0ustar liggesusersb```b`adb`b2 1# 'IM+K,-JM)M.rJU%̂44R:^Xt%Z_g;<f&6̜TB2K7(1ݍ(\G^PT6@9XVr7) dimRed/tests/0000755000176200001440000000000014153220136012615 5ustar liggesusersdimRed/tests/testthat/0000755000176200001440000000000014153365332014465 5ustar liggesusersdimRed/tests/testthat/test_HLLE.R0000644000176200001440000000024713464507204016376 0ustar liggesuserscontext("HLLE") test_that("HLLE", { 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.R0000644000176200001440000000071613464507204021323 0ustar liggesuserscontext("dimRedMethod-class") test_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_isomap.R0000644000176200001440000000210413371631672017140 0ustar liggesusers context("isomap") ## no isomap specific tests, because forward method is not really ## exact. test_that("check vs vegan isomap", { 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_equivalent(drdy, vegy) 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", { 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_diffmap.R0000644000176200001440000000053713464507204017262 0ustar liggesuserscontext("DiffusionMaps") test_that("DiffusionMaps", { 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_umap.R0000644000176200001440000000376414153173664016630 0ustar liggesusers context("UMAP") skip_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", { 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", { 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_kPCA.R0000644000176200001440000000545513371631672016442 0ustar liggesusers data(iris) context("kPCA") test_that("general data conversions", { 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_dimRedData.R0000644000176200001440000000260113371631672017650 0ustar liggesusers context("the dimRedData class") test_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_equivalent(as.dimRedData( Species ~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width, iris), loadDataSet("Iris") ) }) 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_PCA_L1.R0000644000176200001440000000645013464507273016621 0ustar liggesusers context("PCA L1") test_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_misc.R0000644000176200001440000000176013371631672016612 0ustar liggesuserscontext("misc functions") a <- matrix(rnorm(25), 5, 5) b <- matrix(rnorm(25), 5, 5) test_that("squared euclidean distance", { expect_equivalent( t(as.matrix(dist(rbind(a, b)))[6:10, 1:5] ^ 2), pdist2(a, b) ) }) test_that("formula functions", { expect_equal(rhs(a + b ~ c + d), ~ c + d + 0) expect_equal(lhs(a + b ~ c + d), ~ a + b + 0) }) test_that("makeEpsGraph", { 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", { 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_embed.R0000644000176200001440000000017213371631672016727 0ustar liggesusers context("embed") test_that("standard method is PCA", { res <- embed(iris[1:4]) expect_equal(res@method, "PCA") }) dimRed/tests/testthat/test_drr.R0000644000176200001440000000052313371631672016442 0ustar liggesusers context("DRR") test_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.R0000644000176200001440000000504513142050030016235 0ustar liggesusers context("PCA") test_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_dimRedResult.R0000644000176200001440000000106613464507204020255 0ustar liggesusers context("dimRedResult-class") test_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) 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_NNMF.R0000644000176200001440000001255613464507273016424 0ustar liggesusersskip_if_no_NMF <- function() { if (!requireNamespace("NMF", quietly = TRUE) && Sys.getenv("BNET_FORCE_NNMF_TESTS") != "1") skip("NMF not available for testing") } context("NNMF") ## 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_equivalent(dim_2_defaults@other.data$w, dim_2_coef) 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_equivalent(dim_2_apply, dim_2_exp, tolerance = 0.01) expect_equivalent(dim_2_pred, dim_2_exp, tolerance = 0.01) }) 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_equivalent(dim_3_args@other.data$w, dim_3_rot) expect_equivalent(getData(getDimRedData(dim_3_args)), dim_3_pred) 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_equivalent(dim_3_apply, dim_3_exp, tolerance = 0.01) expect_equivalent(dim_3_pred, dim_3_exp, tolerance = 0.01) }) 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", { 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_equivalent(dim_2_recon, input_trn) }) dimRed/tests/testthat/test_ICA.R0000644000176200001440000000121113142050040016216 0ustar liggesusers context("FastICA") test_that("general data conversions", { 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_autoencoder.R0000644000176200001440000002234314153207515020161 0ustar liggesusers context("AutoEncoder") skip_if_no_tensorflow <- function() { if (!reticulate::py_module_available("tensorflow") && Sys.getenv("BNET_FORCE_AUTOENCODER_TESTS") != "1") skip("TensorFlow not available for testing") } skip_if_no_keras <- function() { if (!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() library(tensorflow) tensorflow::tf$compat$v1$disable_v2_behavior() # I have not found a way to suppress the warning tf gives on first use. sess <- tf$compat$v1$Session() hello <- "Hello, TensorFlow!" tf_hello <- 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_all.R0000644000176200001440000000305313373523703016421 0ustar liggesuserscontext("high level functions") test_that("high level functions working?", { embed_methods <- dimRedMethodList() quality_methods <- dimRedQualityList() 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")) && (e != "PCA_L1" || ("pcaL1" %in% rownames(installed.packages()))) ) { 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_quality.R0000644000176200001440000000474213475160740017350 0ustar liggesusers context("quality") test_that("quality", { irisData <- loadDataSet("Iris") parsPCA <- list(center = TRUE, scale. = TRUE) resPCA <- do.call(function(...) embed(irisData, "PCA", ...), parsPCA) 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", { irisData <- loadDataSet("Iris") irisData <- irisData[!duplicated(irisData@data)] parsPCA <- list(center = TRUE, scale. = TRUE, 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", { 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", { 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.R0000644000176200001440000000030413024272076017412 0ustar liggesuserscontext("dataSets") test_that("datasets load", { for (d in dataSetList()) { ds <- loadDataSet(d) expect(inherits(ds, "dimRedData"), "must be of class 'dimRedData'") } }) dimRed/tests/testthat.R0000644000176200001440000000012513464507273014614 0ustar liggesuserslibrary(testthat) library(dimRed) test_check("dimRed", reporter = LocationReporter) dimRed/vignettes/0000755000176200001440000000000014153220136013463 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/Makefile0000644000176200001440000000043414153220136015124 0ustar liggesusersall: echo "BNET_BUILD_VIGNETTE: $(BNET_BUILD_VIGNETTE)" $(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/ dimRed/R/0000755000176200001440000000000014153220136011654 5ustar liggesusersdimRed/R/diffmap.R0000644000176200001440000001067013562225201013412 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 #' 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 )) }) ) dimRed/R/fastica.R0000644000176200001440000000666313562225201013425 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 #' 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 )) }) ) dimRed/R/nmds.R0000644000176200001440000000350213562225201012741 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 #' 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 )) }) ) dimRed/R/tsne.R0000644000176200001440000000533513562225201012757 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 )) }) ) dimRed/R/kpca.R0000644000176200001440000001051213562225201012715 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{ #' 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 ) ) }) ) ## 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.R0000644000176200001440000003635514153211745014331 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 )) }) ) 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.R0000644000176200001440000002024413562225201013272 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 #' 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() )) }) ) ## 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.R0000644000176200001440000001064414153200510012740 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 )) } ) ) 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.R0000644000176200001440000000650213371631672015466 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. #' #' @family dimensionality reduction methods #' @export setClass("dimRedMethod", contains = "VIRTUAL", slots = c(fun = "function", stdpars = "list")) #' 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}}. #' #' @return a character vector with the names of classes that inherit #' from \code{dimRedMethod}. #' #' @examples #' dimRedMethodList() #' #' @family dimensionality reduction methods #' @export dimRedMethodList <- function () { ## return(c( ## "graph_kk", ## "graph_drl", ## "graph_fr", ## "drr", ## "isomap", ## "diffmap", ## "tsne", ## "nmds", ## "mds", ## "ica", ## "pca", ## "lle", ## ## those two methods are buggy and can produce segfaults: ## ## "loe", "soe", ## "leim", ## "kpca" ## )) names(completeClassDefinition("dimRedMethod", doExtends = FALSE)@subclasses) } # 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) }) dimRed/R/mixColorSpaces.R0000644000176200001440000000452313354441317014746 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{ #' library(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) #' } #' #' 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.R0000644000176200001440000000205413562225201013573 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") #' ica <- embed(dat, "FastICA") #' #' rot_pca <- getRotationMatrix(pca) #' rot_ica <- getRotationMatrix(ica) #' #' scale(getData(dat), TRUE, FALSE) %*% rot_pca - getData(getDimRedData(pca)) #' 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.R0000644000176200001440000001402613562225201013003 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) }) ) 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.R0000644000176200001440000001217513371631672013075 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.R0000644000176200001440000002202613371631672012750 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. #' #' @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.R0000644000176200001440000001227313562225201012743 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 #' 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) }) ) dimRed/R/hlle.R0000644000176200001440000001025013562225201012722 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 #' 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 )) }) ) dimRed/R/plot.R0000644000176200001440000001665413371631672013005 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") #' plot(scurve, type = "pairs", main = "pairs plot of S curve") #' plot(scurve, type = "parpl") #' plot(scurve, type = "2vars", vars = c("y", "z")) #' plot(scurve, type = "3vars") #' #' @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 #' #' ## 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.R0000644000176200001440000000310713024273620012561 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 ## #' 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.R0000644000176200001440000001432013033377101013550 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{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.R0000644000176200001440000001444413562225201012576 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{ #' 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 ) ) }) ) dimRed/R/pca.R0000644000176200001440000001014113562225201012540 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") #' 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.R0000644000176200001440000002151013562225201014234 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 #' 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 )) }) ) #' 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{ #' 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 )) }) ) #' 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 #' 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 )) }) ) 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.R0000644000176200001440000000414013562225201012553 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 #' 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 )) }) ) 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.R0000644000176200001440000004706613753034327013516 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 #' #' @export dimRedQualityList <- function () { return(c("Q_local", "Q_global", "mean_R_NX", "AUC_lnK_R_NX", "total_correlation", "cophenetic_correlation", "distance_correlation", "reconstruction_rmse")) } #' @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.R0000644000176200001440000001310014153203477012731 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 #' 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 )) }) ) 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/MD50000644000176200001440000001513714153365332012002 0ustar liggesusers8fb6bb466b44be0ffffde3351503ed68 *DESCRIPTION ae5a59342168733d9988af23c3ca4c2a *LICENSE 2dd5c5db35ffa4df3b59cc134a5382ad *NAMESPACE 796f16f5f6b46687e1983c5506c7f0e5 *NEWS.md 14bff94b02dc99cbfa7807b0b41e50e2 *R/autoencoder.R d4e3e654a96439e20fb41d3e10985af0 *R/dataSets.R 52c76dd9c2140c9858f3552801ff6e68 *R/diffmap.R 9e17b49bd7954ac4f67b9cec33eac1b9 *R/dimRed.R 0b64904774785f20eea821044c0d004f *R/dimRedData-class.R 9012058299b382d56cb9a4cbbef96be2 *R/dimRedMethod-class.R 3fb979a5be13d3e18b4dde7ddf0506b0 *R/dimRedResult-class.R e1b1c9e87513e7d4705876c8fc993b56 *R/drr.R 78dd0eb23aca3ff89346da8e47e4aa1e *R/embed.R 9dd870508ff1e5f4af4b9bc2b81979b6 *R/fastica.R 1ef49b08102bfb5f9fada19d0d6e928f *R/get_info.R d0b0b1fb18b8534e0cfde6a8a0590551 *R/graph_embed.R 83fed7b8134e99d95ed390be193a9c15 *R/hlle.R a8b7fea4d6c2d257fba19c3a4bbb2f8a *R/isomap.R cbe329e1211e5af2490deba0e55a8d2c *R/kpca.R e7aa15524f1ea9c939ca393835ecc192 *R/l1pca.R d2ecb14abbe9b6b9f9845760a85f14f9 *R/leim.R c04a9856b551df5080475fadcaafc241 *R/lle.R d188fc370cdc5ea1094613ec0b3972da *R/loe.R b60460a99bd739a082780629c886ff4c *R/mds.R eb62d31d8645997200186731444ff667 *R/misc.R c115a187e0c2cbbb12219ac0db73e66d *R/mixColorSpaces.R 2ddd29afc005c76d5b20abebc9c688e6 *R/nmds.R 792917d6a6d66001518646ea6defd557 *R/nnmf.R f8a40db8dd043d54d357b3a916de8ffe *R/pca.R f99544db6dff93b3f27f6cba2043695a *R/plot.R 0dd086f5a53d9118e2de93929ac895f9 *R/quality.R e9a61868c99870bbcc03e8f6e4db0fc3 *R/rotate.R 546e6d5cf4d954c002b0e5d2031eb69f *R/soe.R cc2c350bbfbca7b74f46d2f3a8c1f0a1 *R/tsne.R a7ca7aa36b8ab73303354939b77029bb *R/umap.R 7e8d2039a421b5a819163feba460b5e7 *build/vignette.rds 941a4ba018d10bb388f78d2a47a93147 *inst/CITATION 2ab520458263e4a5fbd9ab5d1e14382e *inst/doc/dimensionality-reduction.R 08f8cffd3a53d83eefb2a7a18e3a8cae *inst/doc/dimensionality-reduction.Rnw c5aa1da66d33de1503ce4b9c9a2de474 *inst/doc/dimensionality-reduction.pdf bcd35ac3b1f65e2b07692ffb9a7155ae *man/AUC_lnK_R_NX-dimRedResult-method.Rd 065011a39f409eb9759f3001651523f8 *man/AutoEncoder-class.Rd 705d899d9095a33217dfa39df2323f96 *man/DRR-class.Rd 5519095e624e3e204b5e9208085e7fb4 *man/DiffusionMaps-class.Rd abd2c7b51ada0b47af339c8357f58398 *man/DrL-class.Rd 90711cddd66d9c9ba710483e9e5cf5d2 *man/FastICA-class.Rd e253b808cc55932ee2e93b4e2192eceb *man/FruchtermanReingold-class.Rd 7bad8e8a2100f98ca9c7e48a1e2ee614 *man/HLLE-class.Rd e0eb458fdbd0c33dbb7ca4a7ab17f910 *man/Isomap-class.Rd abdb364c81b67ab0bb3d6ef690284fce *man/KamadaKawai-class.Rd e66ca8bdfe51f81a92791247fe1d8d2e *man/LCMC-dimRedResult-method.Rd 0e8eaaf5982cb1cda90011cf41da125f *man/LLE-class.Rd 34a958e7e8f907658558535107b36ca2 *man/LaplacianEigenmaps-class.Rd 9687a6e405057c15012ede04b316a198 *man/MDS-class.Rd 594258b8dc019d834d58f49f53e36368 *man/NNMF-class.Rd 329c88ea12f4db10f2e8d2b7af19a249 *man/PCA-class.Rd 1a0538d0bd1f1e096014b59b6545cb0f *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 6182a3d84c9cce8e1e8fbb4c22fa5d8f *man/UMAP-class.Rd 718f4e21d3332957a02215ba01e9125f *man/as.data.frame.Rd 5b85a0e6b1a89a9660bd9e48ab4dd58f *man/as.dimRedData.Rd 7d8095baec2b3d9adafadf37e6048785 *man/cophenetic_correlation-dimRedResult-method.Rd 419144b1768266c642462c3c959788ff *man/dataSets.Rd f1a7b217df5585e3800a558d72a3df7d *man/dimRed-package.Rd 25963f304d114b9142d96f500419b841 *man/dimRedData-class.Rd addaab77dc1c4ab13e424987a84ee34b *man/dimRedMethod-class.Rd 3eedfbdf1b1133896a9ef58ce47a6d1b *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 2490bb8ba610ace97954566d69493448 *man/getRotationMatrix.Rd 6df2e37941539cd6055499ba4a0eca83 *man/installSuggests.Rd a4bc899053dedf014db21d12324b9456 *man/kPCA-class.Rd e6fda0f5f8483f08ff20d467eab06cac *man/makeKNNgraph.Rd debb38427c3c0f1d3c3559ad66a3269e *man/maximize_correlation-dimRedResult-method.Rd 889d398a1978c51f13a5319bc6e77ce7 *man/mean_R_NX-dimRedResult-method.Rd 8e8c844dc330706d5ed9331782d6912a *man/mixColorRamps.Rd b0909632cd8b7d9b9c893699ff10758a *man/nMDS-class.Rd d129fc72b1b204e139d23885ccd064bc *man/ndims.Rd 9b29258e3f3c712a2722c57e395aeb53 *man/plot.Rd eb1cb8345ec44a88cb210318aca2f346 *man/plot_R_NX.Rd ecdac99d07501417ba48b07a28ec5f5d *man/print.Rd 3cfba09d8ba772ac2b17cf8240391f77 *man/quality.Rd 1fe05b1ae61fd475a4b39db0176ae977 *man/reconstruction_error-dimRedResult-method.Rd bc566baaf50a52c8765a4ff8803e6a6b *man/reconstruction_rmse-dimRedResult-method.Rd 35017e641ea3990b2f39deb7f19e1621 *man/tSNE-class.Rd b8152e44f03d5cfa9046bef699bea694 *man/total_correlation-dimRedResult-method.Rd 8ace2d0542826960bc7b59ac72f45236 *tests/testthat.R 5d2a1830e69ab3855dee09cbc64d1788 *tests/testthat/test_HLLE.R 38f08498979faa5581533adbd4bffbcd *tests/testthat/test_ICA.R 3268fc53ab376b48bb9f6e982edf8655 *tests/testthat/test_NNMF.R ac423f8fe5975d8fe26d6e7a1b988da9 *tests/testthat/test_PCA.R 81ac0e38a036949d78ce64a071934063 *tests/testthat/test_PCA_L1.R 977a45bcedfe70de65d7bb0627c6dbbd *tests/testthat/test_all.R aea4f4374a64f0a754351aa040995d3d *tests/testthat/test_autoencoder.R eb2b0ed077c46c957b4069250febb644 *tests/testthat/test_dataSets.R 8edfeba82c3cf5d4f8d4155988d32ba4 *tests/testthat/test_diffmap.R f9ecd97a5a0d177661d7ee22a051bf19 *tests/testthat/test_dimRedData.R c9add493b83df66c3509203545016ea2 *tests/testthat/test_dimRedMethod-class.R ff7b55fe97717cdc7f3dc140c110dc5e *tests/testthat/test_dimRedResult.R 5f32a62cc46be17283bb8acb2540d627 *tests/testthat/test_drr.R 84413e591356fb49d6b15763c66fd0e9 *tests/testthat/test_embed.R e9b780f2fe15468d89d547e41dba6ca1 *tests/testthat/test_isomap.R d6b6bf63d34d8ff812d45ba834032333 *tests/testthat/test_kPCA.R a82999dfbdecc5dade5a2804181fc1a4 *tests/testthat/test_misc.R c97bf6676400f0a0e2c3886bdf877765 *tests/testthat/test_quality.R 1280e99c0257255b1346627c897dd23b *tests/testthat/test_umap.R 085333b04fa2e0963ce84308776bd7c1 *vignettes/Makefile 6b21c813361c55cf8b7361b7a0b3bacf *vignettes/bibliography.bib b3b0dc9c51a39436ebbc3895a9b2f9f6 *vignettes/classification_tree.tex 08f8cffd3a53d83eefb2a7a18e3a8cae *vignettes/dimensionality-reduction.Rnw dimRed/inst/0000755000176200001440000000000014153220135012427 5ustar liggesusersdimRed/inst/doc/0000755000176200001440000000000014153220135013174 5ustar liggesusersdimRed/inst/doc/dimensionality-reduction.R0000644000176200001440000001500414153217725020354 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.pdf0000644000176200001440000344127014153220135020724 0ustar liggesusers%PDF-1.5 % 1 0 obj << /Type /ObjStm /Length 5004 /Filter /FlateDecode /N 95 /First 794 >> stream x\kwF&99B_sQ;qdgx?P$(!Hlg~n/Y&%iYꮺ}AYBB \ L a+/tW[[Yd!TEP`KRaU!BaRqa!EaPYU 40h,}Me[x($%$l}U8CיyQ ';I_kL CY^ (}YCQEf4cmRh9 $Y̱q6P iRJCmd驥 Yq9 +Ѝ4a!֢h6h'Hւ.d!YndMj!Y{d*6GBw jYHB9H:H@{S0C3Pϓ84dG!CWt =yWA $+A N,u. 5 .4зE7q}uUh2FmI~fj"q ;:*#\?[D\u狦KiQW/G]U|KA ϶\}8[tzUͤ2-&YL}iqS_vE()9.yqu[5ėu7h+hq5(5VPv<2~.[o 6wOtY:OǕIQp?&9"R2#|ё,&Kyw7)L!s,E \ =TcȁܐY_TD珏kV^"uvEէ#lO󝏫5L +9pg~5?2!2_Os<`$qҶJmǫ&GmzˣWϾzq| |"{O2!/ ;K#jxw?kHkk Tt LLti >3O`kx7C]C8x: B)ҌG'LJQ{ן#;6y J&V؏FҶqI#%LDٱכٸtRN 7 g (Վ)y?߅n|a#}ˎw '=eGN ~aد5Svڌլvi!lƋb/.Fl*VWj>lʦf߻Mgl cga;fu79ͻz6؂!ԫj-p]D}VaU~g_0bcUYIwĽta-k:V`[`XwT/O/c7w,HҰAiH8gm7q=6>7atQ]O073.vm x|!몋Q[Ǐx \psom!9їל-91tDOF-7|8l 0{ޡAtj7ɴ0[:J*9|;'D1[Y"ޖ.)rIfű󷽢Dn1JjrD>2)lj̅]pgHW܉p$w?¹/(^%kKwނ 7^E2yeL SQSLIW/@iK>CRى9epEk8U%N$ .5jLJSEAᛠ?M}M^FqoP2?Fomv!م]x)M\Cz.iG 7B uŮ5Og!ڿrAnV0r2-yr |A&EdvSH59T>SA;;!ʓգgϞU81[p·>ZfN` a5v؎ٛd)#ҹ ,CJ[.tCF:sWy )O]5 c䪋>FRmB0f\|1ue99/Qⲭ 5 ގ./Gtm Cp^p{Oޯ3$eHgw 7b!@' ~"oO`,%F "9PI+%U)%^Fa) K3)%,n5*v y %ߟ ^+%ert3lbin4׀RxNCICICICI-&I#I$7IMRfdw쭸[_r$DsKMa;j嶵1-ZKQQA)\xZťw]Rʥw}x:>'5>IIJ.zo.kd<ߦ>pSJ8 Ei)P1)R- ϠIX_$T9 %E= cWKAA_ SZ-iJҎ擖bn'Rao9~hr%rNݶ *O)u x^'#tcYYɔٔ ؼ!rvˏ=lˍyjJoqOGƕܜ5et>k?{~ֶ4><2s󓞶YY̊Vv\S9^YfW؈k+o?6Con8)߯FzF'&j{Vq&s6:4#돩tr?2y6#ѧ a8Z15MMzhVR`{@@ví*Ena\TyY!=^je꺡_] *VZR?[+-\㊸ȜןK) Ul2aae| R~^jեC'ɉDISg.Ў|ryR,O"ȹɣ٣ ۵qZrgV?'>!9Jo8j}/]2f\E!غ4QNtc"V;XqT!w.ՂէiiYo|IWޚMtQU4A+KJˊxh}j2 ',SjT$Kt>EՈebɮRKsgoM<p3 M^%UG7VUWhz$F㋂|d@11t;cv4fmy34/,X#%bK/u/cT5*@{Y ZxiYE㼤Yݠl51 p" %9լ>-'T{/=mOa;z9B$弾l82PQw4F B[M販 Z\^NXDAz>i@w,,HQb-(ғf:jC9Y9ˑ !8 . ~-}˒`inג{1t8k䎔{'[}UovffnBgLi'&_V-hfJ8poWe5)&  pvYV9?CKG\z~`dsޡ VᴮSѰ9\X#Ɛ!9RwJNt9ZRݚo$Z낲]=>SRwhjBՎ@*wi=MO+Dl:PP {`NTWq5(*a&2xs0lr~:jT\xv#>*0bՇ!7мIrU ^S&՟Ǥ/%-q*{ e{ 3靍{x̥ȳ>FhIX(y4UqyҠ %UWH^ f$lZ,i4I|qC%_Y?Kv ȷTB5L}yg0iZz@#F&b&4F O%2 2icSƢa û0Nwl%{*LB'uʥm 4d,bPyWHonVyxGt֧z[~4i&u5UWM`UӂV5UwJ*=b&mtA> z?)ZCa;*rf(Abtp3c8gR[ny7ħ!1qw`o")^w[m p{ls Y:h߇ln`L)vMvw8ZutZ5bmdNI[ Ez7ȯGP]kz155jyMTӛjiE4Zbgpk=3ڮ劕ǡZpYendstream endobj 97 0 obj << /Subtype /XML /Type /Metadata /Length 1387 >> stream GPL Ghostscript 9.55.0 2021-12-05T21:26:03+01:00 2021-12-05T21:26:03+01:00 LaTeX with hyperref endstream endobj 98 0 obj << /Type /ObjStm /Length 4623 /Filter /FlateDecode /N 95 /First 900 >> stream x\ksF~>V*ޭd;q98rR( PBR_}EbAx fzzkzR&3%*3QYg^::,%Li.@6t3,^Lk"fE)ӑjRJfF:*Z]̸Du(+e3kU\fGY$d6j\&~2D@h9q34 6s1Kz/=wS'fޣu"Gndf<}ntEmfc/㲘<}n|Tī%PO̒ SXFYHFFW`i@h@&~>1,Qn8P&wN[w=I Tr}#R9$`DWgQ33ޡ`XeFM$(=@q qtG#q_'.pU@;؀vt7?tDA/$'0pUDMqMG0f1oA5q;;?h)| jL?w~^e_T4+r~ m=z^b>>)VTxy&VT?Io TuYmXʳYUꆳUg[˻Ec%rU\-_uWU|-_uWe~wOK;- \xxrꛯNx6'K-|XF$X|K}? A:۳UMBϓxR_gblZY_c F)\ jG}C K3CB{Q`c(܎)Ao>+~7Z5_Lo X[t;0F]d` Pw,D>9=9^M&Ũ߆( 0HxCdæx4) wɽJYO=,YQ'd1m@%I7o,rIF!j8P6<Ԝo S Oy8/-b9N ^`i~.@!OdnS=.+ܓRppT&9Qa5yNy8Sr UZ^Sev ]qy mB;crk#QՌR3:F"2G"JKkb|S=] Q$T|d9b U^玄PmrKWU^L@N4pXQHDizYEǂ>D X\ɛE9kke:}PY;/Y^n/6e+g/ ,w_O5Jry2<5vZ#PBL-Iwi1C|&q do X߅3U`x&X0vJkqKVAPq->wI۵@z÷O^X]hˡ28!udfMlYځ-1v\ـ- :m_PhInzSwY[}kdV} u9&!Ĵ扄y4>6 n5UA5~?tڃlA.bug$!ws;=Ouԛ?4uNsvWZbגwC"P=dÀ}H5Dz}Rj YXp Ҥǔ"Z2>*-y")\%S"qLOhAi4vb')r[ɬX'uZeYI喓d믷v|"눓iGnim;9QB] 7#O!Ҵr9rIKÆ6JW>抚QER :esKފ*H.GB#QEi* UPՎq>}I؊!ѹ.uȮ/bS|W"'_iB+7 ְCFeN;^##ˏIk[JIJ$j4ci7񤘍:_.RUpNJJ{FȪv ɿUqR{N#AB%y ͫa_;;Z&c`%,lY;hF@;ь HKBk6$!)O'[ S)Ttu=UՇV9JC+uBߜq gX9l΢ YݠxX'>hjlz'n*lʚW6;2 faW!lm>'ջ~O+.f2m8]]rZ66qD ;j=uɫ Uٿ xendstream endobj 194 0 obj << /Type /ObjStm /Length 3713 /Filter /FlateDecode /N 95 /First 883 >> stream x[[SG~_яIV6UškoR %" ɯ6K0- gs?L%ϴ65)%/PLkN:4 FʽU_Mݑi,;t+ NfFÌBYf3T4JMĬyRuxfj#>STӞ=9{s1iMyWd1y y|c'jxcXP ȜĂ(m% 6e|UѷyY5)U^cQ >=>'Vǣ"+9/^e,s\D + Kvh .6MCܐjH'6m{#"~got8Lބ6.*۟ fI ʳ=-5'I5~;8]N0"W;i*{JUR)16s6))eD<ӦnH jH yz zXq4 ۛx07Ϊb6./l(/l1*R"[,Q=SY <3턪xNu88w*\PDb\NMrbHy,"8++Y .?8oEKz L*J-lE6@&-z@O +6A&Ǧ!Ѵf!?.,rx4OYH )Lhbu=iAԋR4($xYna|]Dg(Rf[;T PSS|E\Rj>B4KZ=i laudkTBqlAeaf.£|w|ɱm%cVzAxS.WDFZ*}(;Fi%/.P|c1rܭsokA7=LVף}omN+rܭ`7]Y.wgNZd8 TC2:⁕vP y:/U Z#l0-~:XL@(*Z JHjI=9:)JH}yk&t3q2T&S12<MgEԵ3;$QS#ZUyu(*R]PQ`OwBՅ=c<߻Ka遵醍S:DGq||Hv-n*RzI*wj>,6v)APmPv=*[8GR>޳B^# yhli:[pzN6|b2]]Pz\1:Y,hK|MckzJ-gz|#xw]_<ْԷ+r5Yљc"͉8oĻR '@5!/|jq0 FdPh,ƴTtYL2UP1z5'U?/W5BF]Cu^5ABڂ}";g^ǟ~zz1wOó{DJp[z I%'ro׶D +0@s솆ZcZg ڒ+ț`b^a}i[tLؒ39l .Wz! F-)eզg^xJ֬i-V5VM:pGoPbr K:(h/ޯ/~%|~ kKeu1HkZ%_:všy!a W1-%Yendstream endobj 290 0 obj << /Type /ObjStm /Length 4041 /Filter /FlateDecode /N 94 /First 877 >> stream x[Ys7~_M<3T6Uo\>)?HZ":k 0ВrsBSx &`r%ਘ.f&\ ex;ƹ'q=xkgqq9N$' 4N06eI aPAW`RҀ4s?Uh)A/rÔ[4 SVW) ϴ4D3mdB1-@h Ì7%,\ˎY)3FUL:R@ĸq\ sht2gy3< 3_ U0Ix щdބ;{2P\a{R tXpJ,4’4Xxbb{Z,U+i839 %e]FCI S "UѢk1=z/m9P+Eʔ[E)ێf0}~^~>xAH|=$Z2*X^H))y|7Q{94́\޹]s 2$ Ƣ.'OZ:vTdOv%%iL`nhY ^NvYzrLkttTȊ|ly9I,s{Pk5O!ާFڻ?vȤ0Ctd )5W *pWf\Ŵ4|y vDAb{? ' VexGcmPGD}7yV$P\vENis3u͵Pv4bYc~ TG:MSt~$[+C 2^LeAD{ح*,ۉkh.'/œ±ly:_|poo tŜVrul^Z&(œ*o槛 vj?i)PB2"e+YhB9!"oM*Dh|Ӽy!򛠾0}9=_#?Jxw'h"r>{8~Ax^CA2MyM5䞿s"!_~<"zRb֪Ъ(Zc> xτUY~*LpEUՑ J+y o#"j!N7{U:/ ~:7_mCG`13mP]P1m(T(|髧o+za)22J QFqj1ǀ%&B_OU#SԸ`DCc 9P:nV|iL|Ux'E.R&OMU 39?=P8[^]M0aq(r5_UL}fR1؛8Tt^ ST0Ї/z#-hz5# V,w {J[6nx7#^ 7IfѳN98CzU}O{UA׵ꗫr#ԣpA+ݶ&6sndVm=)g>]LgIF~]P  <_mEu<4yxM\l:ϯq:߄yyqIEAI+pnGc}LCΨ=63aO0A>-< ;QlI†xQmWp.J'O|Bԕ5k[J-.c2P4p<1k?_}t< 5u$Àan ZaAؾa@QC0o2E% v:μ8q*w5S)s\U+ز[cC]Eifa&%xƥնk?`˔ x;`H3qL;n˔}41hL)YQl%)ýb7wߒ 't M^ ,͓ LARfd~DVjܮ:BN DMl*+̽jL% WBLx*`թRn{Yca_a x]O\ra,cDs4h zw6s%k \Y9,4Մ63.tE新x x4=Ȧ<}:(Rkqk=|*+51TOEm&ld5U5 ?Q*U,Iw;KQuv]ήPW;o(jVsdJ̖z9u|sq>-U~8Ђ3&GKR=D!"CGX킶 U庨u1{_0T$ n` 2j)blc&WT8.qWcܳ/O^L˗]:oبH C&Y 4Bj{oғo{jkw #d{#Y~Fކt{̯a^.˳Muqv7My2l7 ,l*71oph{YrpŎeGo}EM2qPm~9fR2i Q43(€L3 eS{˗DƩ&ɜ'W>I+8 +s*,8>?oCCc -D ~Jc, %S6sJ TG^Pǣ$,HYW5M 9g?Iy}>:>~j[ %i/oAts#9}q?@rVVr,?éחE _-zxN?N 6 ng`~4iĎm}n&&TysZBЗ!즤G;b=_H)]~6-BKqBN$O(^܇q+7wmm;,cK-6nc;v<>}Yۆ*::C(^>vKW}Wt .Qx0I9lZY)f*sj){QBc2'C"|!lm3 H7 ")F2@]jѶl12j`!  m6 g=)|tzC턛}IեAZHmHU#v7\A{y@: 2?1iݧ䆧JkϿX*D#4j25V}ODZendstream endobj 385 0 obj << /Filter /FlateDecode /Length 3187 >> stream xYKs\r+5`RsK$N\7$zLr}ծ]:n̏<W?^IZ=uw }.S+&uJdt{,Wem/>/5p^*7ߢ`4%ieucгAקoM^eـ qy<' oVI,* 8Q B7^tƉ:$z/7HBgyމg|֘"|, S(aX%ƮIbja͍xj2p4> aaC"׬;W,̉K2i1 Og\C_S ┴./p\2z>ϴU€ki"FT>{,c.}0]!otS{12Aohxw 1{ =܏QERHskF@)@pdUޢE8(- }X(q)Z„PEL^W}Y$UPr !?\{"3v1b9wa~" Ao[Y[ pWaD89 ABע8a dSP[аRq# !2x:LUt|Ppq9:#DA m Xzgi)ẋWxl [kMHEfL"w3<֠BbzNF\-1Db)Bfaȉb! X"4 0rq:vEW( yچ({`qO=\C~}yf\VG? Z)kqfW*0\GX?WEhf(H1/X)&̟ 2si.PixFoU"m |]! =#CQ'~ k =w8aUM1` $a=2WKhUijj19~qŘ5,Q&)(*e3-iq(}<3 ~T%uaGYө Bc3EAp< IV6!X{,8/^2 g$wȽ Vjzt=q`>=S;J?Q5]q\aaKž$D1׹Xu =0B4$Sыz"X1;ۘi2Mkk9%nSԜSy 5&P#j[hCHX4wl?&*q7V]x^a}?:pmיnHac[:B紮RK%@)AiC4f?f' edW1Т1|ZhShټ 2 %,I_hciR^iQ{ IؤDcRlq6&GY/ -g {=0IQ e?I 2m/s ;C9^7nN &b_!9Cd$ŇTf2Φ܏bJ9C~0]7qI3+1nCd$-VM ^0+S4&9@ׅULw JoBV}cHwiWZ,ٵneN_ұ6"8u$}N 6A @bnq|@m솈ī:*gGP{8o<%@~--z; KGpdD@Klj8A_sK> stream x]=n@D{7~li\$\vY.ř)FZ= //6_vi;^~4zh\_nusi[^Oz>˲nqO]ێ=zx8N*3ZQY*P~PתNǪά*<;ggY2D} % /aP 9% *!gAm* q,d.cP\檠XUPQ`+,,+,,KUPV)*xMFfl51 &f#ld6𚘍^kb62xMFfl51 62ndǴq#>LFA>9\]N_pu:}._u|Wu:\]N_u1;qo9 1! s7ds9b2xC̡7d́}B7 (Q`F6 np }%\SI߄k7pM&})ߤo5M| הo7M&\SI߄k7pM&}r)`ùg4=m|aeiAEIy'/w,oyX߯׶tM}ڿ[rԀwBendstream endobj 387 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 10216 >> stream xzxW㙡b!,p2"!Гlc[lٖf.EeK;WzK( =aCz[Ml{w#dIܽ#wќ~gAm5w֬/ Aֿ(C`0t`/VCF A  =a ?)%#=V0.+H'w$"rQ%)Qo.,K{3}y JўU⽫3EdŬ]]7&lJے5zV/|Fι+s_}!cpI&A8b0)1H" aN\&# ! p"/f!Fe:E/j?d! ]OtcF9eQvu1zC.snL_F7{2).2^7v\ӣy&+mNxDbII&Ϟ|W{g SNN:MW4#dF،33_i̿mQ< 0`ϿCXQM!pL.j)Y  d(ܘHb:iHaxǧ2@QZ()ҔKpps)8hTk5ha#\W nɆm80{Blw(x͛p0V[ |\1tj'L[p9uoO:##$u LٻoLN65suzoN{kafyACynީZ=zLw9 8FI 4@,Ξ5k׈SRRj65Dil_,r9lUmWۄ>NBWb[cQ[6RJG 2a/^X?>8 .N**K4}XpiM-F6|,NC Y?x~ќ)nEYA-USPP$#"5\ϠӄF/ 6~j&6S4~zN;p4ú̀P8Tkpn8ҷ~ ڢ]GɎS"P+OENVVzwqN> ڬJmvov( %>d=d7؁ _@fUpnt^i9sl p zY8[o>_ [9JRzRPbݜ,7 &jՁ뱋K}a1&y`ޡ"/I[V9O(%:q)Kv (A다Y)Ә:GpUnxO0֑@Su>C7 `X9~կLq.Ǜ|ِ|D6F^`R57 [WW(PǩKuN4h (V~ O PVG82!O\$lOܒ2=7 MUr %vuòXs?Y +B~e;v^[S} y r$9{a1(f)rzM8Ϊᬒ < ̏a^8W.w5,^e2>ԳG G4M4G 4=]O>hq($1Q ~Lϴlr2 88H^0SA*+ 7_阉̚ĮsXۀVeh6&hB'0Qi:iF*yX^0߸l'Ч'hПQ0d}Eiv!>: ɻL^G#h5"X'=-֗[@W帯nOpylAާ}XK$1P{|?^Q [ H uwzТ+OucKZMk\4lr\ |#%]kL>XA`2uFv}b}x;n9=\S-{+ Y ]߰2yy!úk6F'(֡ȑ ёJҪ2 Si~cjpP\nG^O9^VNe]ge<)1iQ^ZjY\nW``R/6.2/ S[016ϣUwE\8ORͪyzPr 2zhĴIx[~\W o4yc8 |< 6J?}xl܄fyh3Ϣ0;Gq 2B #D{`xm=88 (V稔?+W fœ ZG4u&=`Qlë 5*  V\D ōr9'$G>qV7GGseLVؚ=q)2hםޜW +aevf\(tVe@(b?Kzz|| WA27J kcOj0h#iPW-L^,,o1eùJ"sĻx7bڐm-͊.OJz;: YǴ~^Y{eہyGP()1d c>"GlAo7b$~xvF^iWyݵ95F LGOayz嚇kZXdSs]7~GZ>0֪֫i#gO> nww!ձXKabj7ڹn\j9vјShY4a 1 10s*\u W]JëDIn_iP.DZy6JxAT*K9[1<ڜ ?:)CN2 &ySbcWsJZ35p ijGjwc''-V[/Qkreԡ:.1bx4w0}5Sqϡ1I?зb 8 `aM'Q+] U[4ߪq>__G*C1@N/ߐ/X.q8X D44[4Z[[kY%ŁfTd.vHyTY Å?+# Gr@5|5W!Yh ?]?zk0LּL}RIh%ո)[|H iC5*1 _xa݃Kz?&O_EjiL0FH&Mp2)/h YggRGC٥T| 9)anb' e&4 lxe@OA& ֺ:C\ا]`1Cpƻ>&yȸs;ބ|M]r~~~N`9 f  w=K#v`b=V,Px3_ON3B9\A}o8@ yh}Æn&E~ 5ٛ۽6o3S #@@='歆ae[zJ$>H()[§¡hDDfoΨt`0Ɋ5 m?MC*j-jy*\2:8/-nH.MLBVVc!I*AFIfUf M/nto]:,y6qow~3s: fUSk|I]@*y76nX%仲 [mwqݞ~mȴd וs; 6ʡ˳|c: 8^i(.+I M%h܄4 ˢZ&\ʜ_qg. Fc+s{z6y{ws\4s?8 ΁[f ߚRFj$4`RN$)xO7z 'KwDp3HS J)W@!0ݓfTS?Q?73꺜ڴm;F,1}~^$N` +$\z V.)fє8uGڮ;46ظ-C•ffJ2v8jQ{uZVwƖo|4D+Ea1U_TüG~AC/ʡ~~C}3zzQR|TJBb6TP\V<7:}fy\/!Gإgn=s84p3,i%Tk9xot\9vwM`Lr@X(Ʀ梯iu;~Og307H噕O[~XDƙ48E%\tBCȠ7id3e.p ڛLɕte_}_B݅U?*̃W٢a彶1c;VZw ={zW$|+ȘCL#y\Wf DޑP?>RQ}l]g։c',z B^RX\FeU8rs|!—nK)?stqbZj+9݇Ny'@4Waʦ-рl?=# R)O|D USX1GcR &{ ((ՏNH*@ ()kw:\ER`Vg(4~ݼG4yO<_+c( f.83|c&s\UEUj}HbZnBo ,KZ%ި<ٜ3ٳiڿﰡ TJ ImP5HbJ ۅmCOlP4Ū"u*8s3|M8CgĊ6Qc .x>XN.Z}WYclړ^D)3cCzd9XueaiͺMѪ:pG=c)h`j5 \-? ږY ^HD(Ѐyqe6{J2vQ:[-40V \ Ml#u>(`SD  gZh+i |ڸ}s rѓ䂅- Rt:9{EsXƭrv3-Y)f~9kRGIŨˊz (0{p-=+ !d8ѭ;18GK%XF&? Ѐ3-INPcdKRfg&ŖGd/_aul[SsϮ^r馵V_Q -(\5raGJZ@&d b [\:s/hC]C>|BU[#Ih^k (->N}}xe3׬95Xnpz|U$p~u8ʞ+YvCd,̯8 h֥MNh{ ЯM|BS[UdT:=r%% qO^ʆ5Ƚ7q|ve'Yr߃ґ@,F<40WUwzu?~u7 ȚcAWX}-@= o:%%MțpOÑXp./xFR*ʣ+r] jŲH\%fo v=N,jI#U@֫htReEipÀ[OVU+bP-KN;ZEA_͐ 7clų̊YnZ&BUm);TYT*tF^FQR~Uf-(E :[|?C͟X'l= ƶN$ZMfd'sYߥ{=ח7FS:JiVKȓ;_ؿ _5 k:H@`@{X^ WEFj4L*mjKiusy!SV|$IUiu\NPl<! =Ǟx?x+FLW 8ҬI&WmmU/a}ػ'ct&++aweomFM _ۻ^b/a`~~ p(H݋ӮcXt)[(`x끂K8}mFZh=Z4V+, S\.Np./Z+fp%ߎ7s.o_BT epngTCb{\?S08)C7c7Xsà%1sWp ֎;;za۹].e[\=ɣKZ{|&:M`Gc~t)#Um/⧚c ̋" /pjk0ORh4Ge:vY>E0M'VqWV2&ʂumPb09Da &a$F~dvߘ, xdz3c-Ҕe4fmA `TVhL\!@Rsa.@e#@I3`@?M=S BG-S.CG]aY,TԳQYh";kS K{Sʒe:r#%YV^\lu:smY\LW?> stream x]n@D{w kHC(J|\`,E>3H15IJ^p9kc76R0VU =󩝪~Rcw~kOe6+enR&>Ue}82)M'pN pM IbL 0-)@#zRN$tmR[b`gO J""##J" aa#Vƭ a062meʠn7MF}IߨoXߤ`TcRGbN 0!g4 ZI .}uظFa2r9w)8 ] xԞ7ū>ϵηy.UG#cLoH endstream endobj 389 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 4819 >> stream xmW TS׺>a8X)Q{Omsjm(V*&1C!;dfTfŀuC[TkZk[Yu?[};z{YQ>^&xQٳgx~=^Fx>m lLz )/5.4=>!+mܢtIŲ%EQo,LKZ"CÒV%E:Y}gEP+0jHN©c-*ZD j P3T5ZF͡S ʏSPUʟR7)S7yq^ ޟ\]E i']V: / Q>o1ȡJ_:Z7^) 를}1]L*Tkכ+E5],_yp5Vv;ۃ`XNUUZ#Ml] ^3.᥹4T Blߑymr%_/[C3Ͽ^)70m-Z_c7AC,}ek8\P͠n]#co-,_Ms&^nQ 4T vw( Ax:Zںh@a}xb(_u :d8]DѶRlEV&d&&_B,AvB .)> 0- (}8f\_M~Dx &߆DfFgWХe"Q%%'m]E3:";R׻|&ai */kJ(֢(er%OQ>GM{l_' PVY"zR~{ݓ@зUDY] 4&Jy#w2nlƣX5kƂȋ%c<{+KUL$b=?Ë1 8P z0@ 0|YSiN\t0Ǵ\wg&0Cw7tNU"Y_b)G|ң.ht`ys0}@-YP`4?NAu:< 4QD#MB*h)Ytq}iYPD;9 B`δoߵs_ W;f^\Q Imy]Mm:bC׮^YaԞ3z?w: v :) w}Ex잵  XGwpN+EZJW5"}bsk̥\Vf,0  f&WE=[Q]& Iw %*ElZS(#ի-5UTUW[mb3[D}nOgpJ\Fwo(^Ͽ,x_G$ ۫F3c)#ʮWD +B")p~kgV;Ky@yŻQ<*d[F{tr40‚L:')rY&L+nbښi"ɨoZqZ6T-r/7{:<'ۅ$\3C DMsݫAM-+I&޲l5T^gxDpP!KTh*:ۂ:Xfϓ}@SuwLA*mN)Ŕr0}.Y)m7GawNo Sh{~ =tן ڭK;b mfp:2x^t})8?>KXe3c8_?¼9iVV#p$|.#K\LoJ +(Ń/5xp`FȤ2ImW"Ri**Mҥ"6O \ĬmaX{w|cPHM@ʊAݦ"j2p_Z46PbS]R+fF} G;]Mڎ05$0}3Rk1⭙ʭRÖ ĸz9Xgnc'QLvwr'a0r+[vZ[st-ڡ7?eHR ENI.C. 7` bE!.BԵ;nW " O\1c Zb xŎ3NhT kWqeH87zCv4b\ |V0ڪ4|/ݷv=LXJS66ɪᥗqȷxUn6M m!^:sCg\8#U$[ӗe[[UV+u!0-Fe#!pNJyH=52- Nb:cGo^۹Q30:}.6%R晉KF> 1jٙ3iLjeGUƦ(}ZzA_  #*%1g~S.Evx+Pܑ؃} y`(d-uGzLY|"c1\4h>< 'X/F"c6WZ*]݊ny{SRRfДHn/llܶޒ,fp:V#<ʌ,גڔDkIo<%n}wȀȨ/GFޱVeFUM? Bt~18%<"(+^'雴͞L`{N$K;a'Zj@61em]g/sJ՜<5DbЖmu-?M}nyx632+*D:E'Yz&Nmԅ6 o_܁5N*!6V,4Eہ|O@>t] ZaZVM ҕ b%zggwݎ;7Ve! Iv߇d#(DѶV(z?Z ک%ufGu#AlA /qE!TS>'HG {">1_}]A^q!v&*ZӐQXƸ qvnGм[XoDƊl5"} ]Ӱ7ÿ :\JYf1Ɏ~⺬mmD'`nHɉ2\KOճDaĞ|rO$$^4iM5JSI=Ϧ)ɱ ;9瞓s DkVۋFrDAmiTbtIs~ I:KU5j9huP1SЕ Ri: ,(,ؚ_ĺ>NjvU84|`Qr΀' sMIfI;\^< |/ o#?_+`50nt "MQ˦baMj: #O\]m{MPh,K-G HRk'6E`:,Ԝpɟ A,1?sKvZq&mQFU4AG7(,%˿|cgº \DG{VJcrYo2A'v4LfD> N}N'wIP`b'_֓gsS_e̍ɈO:VCˆڬ6nfdfdԦkّ%U0;l09hmapp8w(VKendstream endobj 390 0 obj << /Filter /FlateDecode /Length 3777 >> stream xY;wջK.`0w$˒%!uN5 pPZmN~p} )1;w/~9:/6G#Eoh25IG/G qV\gna?H,0rGi I ~(>7u/XAOFb30Z}(!QJ96&iz഑-ґyq H"f"sY忥M^F_%`!㱂ELr<_=f7'xl)'N߿# ԰>4ih.GK ޞ\0mh4<̳&ddaZ1/OyD}o7QkO#%C48AM;q7. =$NP}bMx[8ՋP0BLD-D|oalwCnF%Ʊd{ #^'DN0,_?L `2fA~N؄ueY1ⷑKwiMlVuϰ!' meAE}֋t(;ܳxZÆ7iMUZlGcUT`kjoDD BU/h F UYL8',^Vv1wя.aڒ Ăw'&cLӚNK>kaUntÊeUd뼮FIB~ٍL4r{2E߯hjNG~`l 'Ϊͮw$@ I"9;l:n]oAܴxΞ:e$d W)U!xf[#]?TCHP4"VBhEZ큯(rB" E^3W܉=: ѷs!获FKx4 ppQ T~O/:F#>'nPܔf e:Fbg8M$PʏijUY?1N}+=v4ozk\a𖧿Cm?#/ޤ+ (W) +@"CdFtbuyG t뭿\٢vvN/=YR%p@KYmo+1 :5v6jd!V|z"R^䳰M*/U܇xgMFU<rƺ$*T~0rcv,^_/D==&1SqvV}e(HپL'XtNWn&~~VrWB<=|1hɗzUYصJ?6)VQLUc$+V<8u!\"[>3|L1F=2ybm8sf \{3׸ݺg >y`b K|;\`_bȋ)',?!cjǿI ƛh'H?@qq_QQKW$ynҁ|/!+ <,"Y@*zx}{3K !@Canx`8 )/J ^( jKHQޖVf"sfwI|zr;Y?@G<|i'{oo`۳nG(!8?|49OgۋCC1xRBpڀ+'i^@RݠNn}7e[V߄a"4$^Ï gM?myK'kh#b&աɀJw&LI֑6gta ! ٓ/ Y5j*QO`Ea ZH+MYϢ]3wzDͨ}=-;w wH'ۢ$pOi1$٢3^&E|U퐢O"|4bR߱x ـËd˼)+^~ P] ]_zg)ݘ h+!Ė-z#(eZ:e/lx:NT\̞&Ъ1ue+8XnOm̉6M;I3?wX$D9?C ט})iPAw"*>vcQtUuPۡ[,~`+Q7b/%)Xw]ն|jls- Å[;ҀQ|TEe:V`mY@ 7] ˝kPs,>r6&Y8T9^.O@$~1w*P|>޶ qlȨJ,CUɲ%Aή}lپH?eWJPiS~vTu^a/Cs0h4B^B I8}#PF$H0 uqF!1 ̫]aBBG'!* f Ѫ8qHWw/'4s0fҎD-+,M|]W?.5v!}j7=KL*dXPuZcEnazdEŬjЏ*5Ê 2I|=& d\ ?zs@!oBpZ`TOo=?p=ĢUPV?>8:a.S[u(!HW< -NcE|d >ymWϊ Zt3 qS{;xSy\9]iah(FB5Bz8"E4@jO1/4$3p$_֠"KZ[ҷ# G2d Ļ{|upԾs>[ 1+`ĭ{[y"ـ 3IZXgmq. vIv|P:GA,z@ UmK(HMu \^t4cԙhor,|3|_+N )-C/ȿd˖Z6mx[ƹ=@h :lkA'd۪XV*&#Nu@(V&^߶k Cl#Qji5""f/@YS|~giendstream endobj 391 0 obj << /Filter /FlateDecode /Length 551 >> stream x]n@w?-钡Adx,(ΐ/I':P niܺ:nn,ޮغs{,ñ.:ncX||k27piNmƶ K۝288ϟ?=4qX%[W؇*>H;U vmUmLTC`TU=Җ*Zz`6Y%ؤ~Q E +JDe2T"@d2RLTF*He 2Q D&*#De2hZҸaEӒ%+t.tA:!.H't @tB\# BBA@H(( !`P $ 5k\#|B(o+{ z /a`t Ns`y+L.+ᯏ3s߷-7:x(\Y+_Zendstream endobj 392 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 7446 >> stream xytSG5NP%RIh !B `5tleٖ-EV#ۖ\%Knr4B'z'&!!lHH;dv=?OXzzs~FQTh***^=zt䟡A1oX+V7xOq}GEGEidѐdpȢ ?IQԤ)©2g#3Sb JͧPR Ebj "F-^S+Jj.5IޡFQ3xj&5Cͦ^PcT5GA=Aԓ G@j՝AS>Tߨd P QFω0f]ngb~@>_ߓe>SݷSO/>ɋxU\]]f(7A#קBdm!؟^Ϩ>e iTSO!7Zamu47{nX4rJEiS*6uvYiՇ](U*te+аehXޡQ ID|.OWXEFXrybXi$0Es m)<'(͍,n3$vddX4\inj րQEq2l-,RИ{E8 Os2Y0Ҩ}hG"OM)۾<@[HNեd}fߠ-<-/O6 4` %s=Piih?@=_A4pf vnLJD؛{'"1@10gT.pq zMl垔$`D(/1(XQohYVx ~ǫ4OFA/;A;]btsIR#y8 NW^t6 ^p^}'{x0eU|9YN[)[=QkdpxX0%,.*`$ B&'lNzm+kASj6Qok=}ɪ썛ٳU`O?5ih5㬇I쭚]1h"3}?z3#qBbSOg D=OGϗt&x%?yRcj!@z,''rZUMo/sԻ\f`q..ߠ5k"e[oj.DŽYpB&iә"E)|HLrQѱ ;z?`qzW ~Q*r[,;x!_pIJQaV9E.N+Lѐ!Bw1c=[`*qd/ 6L?ɑYT*AĒ E**EdKhrM0 g1 /kL/s $&4epvQOԽ] Oч8 XhV@:-NhgYƘL) )+1 U -[bͿERE`ޮ/󽣫!P^n"-w^%f=ry<iP^ 8U4&CV(ʖ4H:8/d,B6I4ůj"N9,o+ ։| ]ҟ~UGfU Ax|.dU[4%6WLDdfx6r#OjͺA}@B# w'&GԖ쁴ph:ڢLo$RMƵl B &zL) i}/7/o=^s hx}trHu.9>yYg}]2x~ge碗h߾3֞05/i_/hP { ?'cĀm\EBݐiM":դ0(ވNPkc'!J2v• 1ŰIO0.`| &Gc%$-`WiUR-Ls@8nL96$**S-Ja}pYls;1|\IlHRӭ{X2Xnf$c{1t>*%w|'Ѿ`ZCMK,PA},䤇diml[<^3,eB(K$ᑡIrڤ7~yrXB)1HXBNxGQWTQ֨kƣ|.!K5蚦]UvQ!X$NΨ8oSZ CyOsՇ^%f-t &+W\nS^KGc57?7^j *X/#F$B}@ި >#>gto2A%2OJ֮Z2j1|]>_[4d|63*/nC:4F`7u ? v{ }ytҘ68V\ASM)pk}}Ud7 &n7*xrk+L!jlmжO(l$ߍb4:"RjR F5˷\Ȥh3֍~Jou--+-nGI0ӗV6S tX]Hp!aEs+eNݭ.囊LV:-_/CwE?C.+´Z&!֨K[ Xwy,]`"-HX}9d[1uvH<<]E-POƠh5-,DTC3oH$JK$B"9!etg;ɫ{!)3G2c?ѣ)'7V$ѻq>m8P f4k%*Z*}WePPVYK`= Jq-('Z8WkW+p_櫩)urgHl>uWsh; QE03jF#Dͷ ZNH p/$)tfUn]cq yyc?;wv:aw;vL,2Iךѥ~\zbiە "wA݃h[COb`|zy]ZnXW..Qʊl5+hu2ZpU+-ti.㧂\?<ᓪ\klW,0uU9EE;}J1+Q^#LAbTDi_V0үqxk? ڭj?hԊ 1x$+堵ΰ5M;IwӸOp?/ ЋdtAu~g-2_[]Z㬁{ Y<@^Ue%&&gyEF6Soh3؇]Y?q>RV<#E}q^o?agG+](s>Ő%oqNXi](C gQhKitqB;G?R5\L^s@mUѳ_*EoxiM"Z_P kU}s 5m_Zf٘,NOYPw7ԠE'> c8qW5<3X^Gg:n!k̯`6l$Cz4'*jMXkqEUo$Ih@+ѓ"ßgiҊ 5,n[tIi!)ʶ6`"T9P̮D d6ꪂ$`t}3D;{B=;lf'5%sn/pq Uf$~v(8MNL!0:qƝfBzṡKXZ+ LˬPFbڸ^:1f7zFeh EZWYI8b[#ٌ+^|*{_ǙS_a";A;1GLb1HCˡֽݺzr2T9IɶPa9{qc˖Pu-s;=cU*g]R6Df(.mcз>PJ 4C'5*V"Br<BU5uA>m7FdC{Dl(( Wg,aVg?}0q] B]S ه3_'{!it \?*}B?w K‡L[x伔Qm4avŴwׅ/K;Ddllv(T(y:oՀ0{ [~~(~$~oWu^2b{Ͽ^B ќ];nDұY 7&`4& OEB"Nds@#p*r-h.qnŌ;oڴ. {Oh)PӷR$'&AIkҩEEs |u*SQآڦlMD6Q/c6"z Aݪ,65HJSȐ3K B]ʝHlD(25~"\`/7`%Gp)MG  u]~¯U3"ݳ=ei` n`±"nz?>~6._f;.j3-BN'1@ZvFtdi|Џ4@/?Q۷U )Yow#H'n3\nSYQ2K5eᦨк/cCW oJhh9 g0hӚ5!\0 &Ur!xW Q˟ؗGL"*NXk z3?ڎ>,@ مbj2f;QTײHHrdL)[$,ZRN ,ikGNce<'cXάjܚ $e#G|5, uiܺƐZ{Ch`(,&qߍiW?գ F4\H0;bp!8?( 03u'^#aQ0Pz+i_|`H\@ puFj+t/oӠ}qh?\m]wEI_FxkԔu0&r麠1_#)6j0rAQ!ڄg8{Sg32bC!6eqya /<-sU* }]H%)f}?{Ņ@ˁ"ZT- B VZp/Dn!)F~\ "D䑗y#?~.IOͭ++{0$My'JUp _4wBd*~#mbTqodm"V@po<7rDPBUVenm_s`YƔty~c0#Mta!.vd[h%g8cQs;ϨJ ܛw/Y_Q@Aw^q^#V"SK!ǁLuSiendstream endobj 393 0 obj << /Filter /FlateDecode /Length 4317 >> stream x}ZrdM;pS&tHm&A0R/^s ڲry9n}xx&[W_>|6 o}e oôgyz>ۇGSCmۏ4ۗe}{l-~f\'lD@T L8i#7봜$ST>AWtC(bXsֽTntϻ46vjWu@WeZ>|sdJ$4:osQiyK",{Zn`vE)q8K~sg'Q |x)G3v1/e^l@F B`=%^vQ Qȗnb4=w2xNf VdY)]E֭uGkul#;csF|IAA+{cUF+#tWv9#(/i<>.J2:K3؏GW*:<<?vvZtrb6}{<D9A|0z/`;_T "S5A5;,r"2:NQGn%194Ypk5 m!p]HK|qaO_*q;%PfgVk7%\v6p%/^[$I_k X:N fQ <jfA,xd<\7f쒲;ds^VzCfN"3N;6!eT[^= ٕ5RKHB 8:U؂LܴkkOIq"CQ7h~]м]>|=l]W ;hqfh%1qގSy l0-ͫ58У7B^)eyuh8 㲘Y O(tBQ4/2LΛ~vǐ2`xc:b]4,b)p$)1WHww1{L˩lՠ-@酙̿vD=I{$IH=,t q?ɳ ($2i+/$uEE)2@ xԈ %,LD^o]Q<'\O& Y'FY}?}z$!jnn#`:AL7mAcm=4C_K1SiF Z=oGۅqF'M.1" ؈Æms쬋cHZj>iBJBRmIXy;tU9Ӎͼ-Ym`ip_:}@o^|ۺKy~щ8OHb$2嬲r`?9U3!/BkiH!I5J&FZN!A앎 OۓB9މÔ k֩2O#VpwSw3f2[; tmtapJlIѝd^zOHH7DyH1 P&BhpeN`w '3 ph!8ށuhMK|^8@G\((ٷ4a2=T4B\Ao'F32zf8[%Fģ-ޜ e_ԽQڴ ɘ9.~G;޾bИwB*ty ("3K'/2ZI(ȮJIrC.OK J$Oz2~ ^:%q3^X EXAR8kS"i${c9?mQk׸bӝ|NQ ̗ wM\0"e2sX=vj獪TL)c@Fe-8~/4) |dV%3Z 0#ˬ߹&Ct "\+4nH٨(҅#L:L]"vƅXESoFBo`هzD[ʵ$K<C$'] *6ŷzX%,htB؈ &Tm*8#ƔVh_y `tW+W52:H#" 5K kG1ɖ/h@RQ7P;b[ROBW5}%}NiZ@g,s@Wl>Ppwئv>ɢ+\b3(YV겥0-%=BfWOަ*9A?N,_`yN%g`J,%)"((9X \1ުdgԻZ;9m- /ٵx,n ?5T뾟\:{{ ☟rombGP'>_-h]Ssi2Tx0-`,'&Erh͛Sendstream endobj 394 0 obj << /Filter /FlateDecode /Length 423 >> stream x]An0DMbd.D,B#{1OUu,Rsxzy~Yk{[N{o{Xߗ9vWZ>9<:Q%:އym(uڜBȧyM]N>1_cVB?5eudҳ֬je'~J]eZXKVY,@OYAs# @ύYA}`} #+"#"#"^VT%Q%R%2+ !gYiV[\MF_LYș9Q g4 opu:}._uTWu:\]N_+fm{]#ї4yT4Ui٬endstream endobj 395 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 5848 >> stream xY tSeN Bf{+": ";lM}o=i^P({YWqF_Jgt9:szNOғ|}+3v Z#Ww'n&+eߝҤL~ǔnE5LD9[Z1[ݾ%eՕ93=óϝH%9Y髲D%Y"8}CYNa:}c"QJeTWVBQAܪJIJE髳JrGvx%e%bQneݹUeEYYY%ٻ K8νOnٺ|iSgVHٝv {6o~E:I@Laa1Q&FH|ZhvQ['_V@evF,%Ą ,DF:Dr5 khgzjhAXzVAO ^/^JjU=qn"Z G"3.#~/SI:MUSbd%>߇y&ZEF| t4`pئ2ԐS][! $u`$4NkGdjw/PT++(]zQ.LU^i>'iu:Q"ucvpmxOp}2"l&J_h=EP cuEWT-n7CEU4.d6e<؀zΦ %o=gI1BsvM(B0׵*UEJzJZECHG8ZAFA"t8=\=8fJ˔XB>Gﮦ:4 BQA Nb QhGҚ}h/c:C'9{MrYdkFRm:)FBڋKY"KҌKYH F nEv1-L&j֔^CJw0ۇ{~vR`#qPX`;.Iu~B`G~ %`-1tr4/_mqYB'>HP+D *p4c5!q]F# el~$?gs@Cch,jt BΘNU4Z1kmX2ٛY`yzh"#ϼhx /VIdF8In!UXin)`_}wpZ\g3e,D"BT0UD@h#[k)N5%tIQb禉.۴xF`fiRf3;%3^}3Z+Ӓf6vB_elZ\=_'/wKǰ?Dm uP3I<"XNk/jz2 |>4^ ^˳i*+EnSOTp+dxW΍@,-F9uQ9/ 5såҐZЛ`ʳ$k8PFq^Qġ6MF3m0OeFW~DbYUg$8J'}4 ~2'{|4KC.b4&iv"x҈1Q@ZLp H=Um^Lݫx#`~ ^!өvD[[om\SI$evƷTm;,TǗ/u,>FiKV=k"q-h#4qWVZQYqJzG[ds쁜hrXkKm DiyhC഻[LfmSPcᚿ3+Fs V7>L Y) 3 L5S *׭ yWpԴQ% d fZ٬x'y :!0v?mTg[4m)ژؒ+oljYOHpTlQؽ$'|'O]+qyPWɶo>ko:VGĸN*ȥPI6|ў#'7}C{^^oKgi\\)nC^ȗƞ'.BqYF$IzKzn]S,%KN`F)0HH\nnyǏr'OEB՝I37w.Qoj[+^`5F_€ }(@?Ź0S7$ ?z=xʽ)žhWJհ"- }v3w(ʖ]FbQ~{W)|۰KjWA{ĹWZ:4GVtG? ezBiեEdϥzD߲W.T=)QټK,`Od7}z+!r8ĔOy @Ils-nD˂C5t&Rl]el6eTG,ThcEl+B2ڿm'Ozq =_$~O+aϢ4d'ōeRgQhKP] b%+h +ʥAycKK (U= Dor5"T(G;B g=0x$rvGKνi(@xJuFD-eWdfv ~чC;q⎡\22^ MMxmV:%YWoߘwf]p$E"N6Qm%qNUW1'?4瞵a4 AG;i%/F.jȍ&8Eo78 g[bشH4 Эb'5ikuGݿOUJ1qJcT B,&He뮡rgFUeʈ2D:_ yhSVɢEĉy@RV.*uPz'|[#Ogmvq>0I C#B]~<3ؘ:IvcL"ló`9lZu":&}󣒬«3U.6ojn; eqX|מlyiuv8ljmQu#3|+suFƮ,r[fUU^M2UwxCSWη'g_Y asP}tGd2=.[Mb-6ۚ%4kq|(U &ox4w84LET[p1xjbRK+Gv*kQrXO b^|e Lv*8m!*Н&. l;mmqJdZvBm[`kH1VKW P Lj/vі[9 0V;N$\i-8iB d HX\!>ohy&pۼ^6^I_dJ !Թ ^C)-KJr~Me"_J*c7bqZ.z䉥z}r:$tN[h]Ҋh`Z#-mxq1ކUZcmr&2kZ¯vZ3M }f£z\B|=X+MGbAO]Djpl9T..7Ng?,.O:x8:G27U,:IUFo6}8aathf+שNQs'4m!ZڛlЙjMF6rJZt@<;VD+\dV< M7la4 8(@v^j7ʂyfn6VkuP+Ձz_fP"6 W<1 F_I*/a~c8=Z^&|u8=c)v p @-iÓ0Zt>/cmtУh)8$ u`='Klxhnh|pi7bocT⣿aC/vl\mzŘ|{ݗ~R&4b>¹ 6>|uzuJR{2m"UܐXzQY>0>0??5?endstream endobj 396 0 obj << /Filter /FlateDecode /Length 3338 >> stream xYMsS.:SK搒?v^HfU*=3(SN=_=vg4|,?{3ɭճمd8uzu,t"Sڞ^*.Ixטּ /Ѕ=KkĸLK?^teӧWϮx?.eD6J/~FR\e|RUJ+JlmͺM⬭}ӣs'X+RԪ?xEmiu6a\.T-O׵8몶o&hN?} s;:tJQG$^:i TW̉x[Wm+ wM;o>^Vg7r28ҋ!bѾ0%Ub6UbKXJ^T[5>T2JݲjXi#ެw]k1Ony\z+XE2:%QaHs}CP |Ί||PzrD47UKH2A"BaϿ|G5JZ֨_Fu-r7'ӳ8ty*]pt: )z8qVڴvlv^iM,vٴu8i%j6_ۺ>p ~v_#GrxaD֘v9)]཭U7o*rj? p L U$[dݦ>ޮ/զ<@$E\T]x穏Rsh DFXwӧ3@[/ %nm>Ml!ubFG)/VRG '`|9 ])SݧqT:ay]um}' MrhmX꒚C,R҄ //͇! aM'2:KիHJ#.;!(} +$7˫bi{yN?cPj^,ka?;a\- K)R8%МcȥH U)1mJzj% N)մrT{F7Vd4y-:X+uMlڞs@p3X5$h͞C_#^V.}â=*n\RӒH\=cU3 >{'JpNM,`jk!)`ItėTb|D+Ѡ$n PI`1Q9wܵͼ 0ÎCvU>hx# d_n6G《nV+?wwƦ.לǚYcr#"ĮZ6p3ҹxg ћcDpU|)"ޏďSP8~+xǛi ӓ>+J9Z"'$/#\:W1S$FJd‡U P7m$s%.`r|$zde-/gbgG 6(ژX,B"y 7̏jo% J@fF5\9e'RkHBfћ] DJ{X}7vҲ PE ):^)*9 u VLBnGeGdQӢJ|3L^Tr$X)஫6]tU+aC?ԲƇMRs"np jTArAţILV"e[0}Z=;+mw puIokF"Pn>Җc}gLή%Z yy4!. GIޱ.7 _^n~B{IRh_=< 7{=_<$ڣu $PIGI>갮#,ƄwATl/> zbBÖKwo!xg  fzBB k=M:c@|!8|}Cխ-~4C5]~KcP,t㵛upa>RqpEP=`8Dl>d|rNbP!N@J t˾]FBukOl4Kdbr9%P(.joAN%b<m͞4(Nʾ 3LֿӋ惛6ۿx3]^68qf / q(RWb )?3A'ZommǨr 0|;Z~pVG3Ǘ{ǥ1 k\YU 4ד.Si9AϽOE/B30O )s/~s:(!󎽁yfP_c(.>%Y-)򷂞:$J(E Xendstream endobj 397 0 obj << /Filter /FlateDecode /Length 3362 >> stream xYMsFtnaˎIHJUqI@{ )-`{^~,MYJ WELHL1Y>U5;3(ZOT́K-*54KJ0>Ɉd'~ƐKf_$+L{t~|Ju TmR6 #Fm_{vU%&q$X~%摚ϩ] 8rkBnޖ!_@\ >M}xōbYV3 >Xeإ^a;.s0'T>|[5vaZ/V!3a%KcJ3@Tp{Jl"=a$5t1wQ^F7q|(T%|Dz0 cuÌ⨽M~h4jRvrR㛒P J,E/KTʘ6d h^W\J 3M庛2-q]}3 z'|()zxڃx~qS6eσ=?qZ|_#HUۭ92'DU-;Rݲm=i rwo߾@&ŧfՎQKAajQM,10Wxx@cﭸ 4"Nj{CH/n뇰![Z;Q{V#YD%^(ǡaw(:6'o;TSj74!V랰 3y aBd 7jj,D=)NI^ S~q{w –1m@XzY M#NquijEe 56_Oq:] 05IY"|nzqOD Qϔ'I˙ZM4/jFS]uRd>r]mM@fi,כIld6z4ܲRi~i E:tT9zeJ fZ`74Xn؝ X5M]RdDr X; pͳ+jUVUgu FiUtD' tTT> $_u/n!XO!v8^q7N뺚miT;EhCb10 aoi(zr: Ŋf t1}԰qZa]ͨGcqD1Xy58]3mcؾ*}9E΅.#|M2ʦ2Ӱpu%IIBÀ9?w'H3p1iڇm`8/sI(=M!H_H@2WvXjC6}%d9l9R_*u~>Q~Q=9 45o}pV2kfQFD 4Rv\&[l:iSB#m!j.FC;>]SwZgz5b^!+'攨:ɂ G[saB-.BgC7JU49+CL%_tY-vj8_wga8ZN\%AR= >OY4^!73p Ac=/1#-9 N5W9D_x#|nbL+0m}a#EO"Ԋ-e 8nb٬FT* n6*ܮH8ʭCG3q#eYE$v2gFfz[r#͢.: [[b?g=(oenL*t~*U-i=/Q hj483<ܲ63So䂸 /:E"!"Uԫ젅dd(ϩa4.h)WCUrиAluVRJ}nLfHpvs+Dnke[nt+Y5ԫ!ϊݘ4| 29x/xr_'@ӢXhv7mXR7u}Yq*7p}+o b=0.4Py;ݸU_uSw~}i3YD2WW0}߽Lhju |@es>-6mA"騭vsw9p F9Ɏitw^ul!H2 нGW7AJl\4Wdgmx$~gtm?>5sM$\lw͢x %~ΐ~VWIHUӶb mSVIp67Q,`A-"Kps=gn+zk~ آ/GQ<>x/V/J.?%q;FH&lZX<*z"~qu'.pW ZXDKSQYvj0PJH}fXeLO1p9W9!%\t"Yqo 7ĸ-PJ ]RnQ[ ST¦f{3Brc \PuS; suendstream endobj 398 0 obj << /Filter /FlateDecode /Length 4978 >> stream x[Kqv8g߼͠5P*tXkזZGl I~QAvʏ@UVVU_VeZdXd/޿o>v[x7F,|[oXSJe7?%VM+D{nnbl>cu*Iw\@,spѐ*U 6U{l# vH2)vz)>kaPJⴓͩ48\uJeX!EѤ\?D{80;3I\>Y>Yg?שRln:xz!*S~ t{>H΁ O6MRĉ56C/a$8qlO'&{ZO Yhh`iLN"/YӃms_7ehy^`x$‡G :h6;O;;Xt*i/{i7Ê!&YWGZ6ki]1X[.0D]:'LN~ XVI-MNֻESAWGp8Mnj('w%yJaT55 N6A%4aזo񥠙K@2`Jafx9y3~ 0r9ԃ%IwI'Y؉?hEźk MpA )4W bf:;aBG%9!25[FD cG6CNoo+9ѿ$t3;!{Sŷcu\ʢ`?vRnnJ@Ee8zMhL@-,1Li[i=864,šb),7mGRpڕ [e8}` N=1V)z`,d6|wCu_65M?pɡ>CYE G'?K2`M nzQycG<> I:뤦ͅ۞ͭ#`z]8Gs%_%=k"qjdg+ f|"vrU~,}em-G{ G7jGo l:L#(?>ZBCT !ɻmp`م]@2!mKgjwɻp &@D!U## SO1/{ğ:3Ŧ*Om)řEqfL:ZAkm U^] ~*[6ml:l9 5'u[@8^"&=N-ö+?wusH}(%׻ӆ91Ɓ$ D0%?`W#ʢ@ Ж8t =@qn=O< \AIYI'4̙$S|pna(68H6O)C$@fh| X{PvÀrc30-vDfrf7f"'`̵If_^7IBI4 aUv}B%00:2:QzH-ɿ- Y !:bd~D [b # #՟;9TXw<=9 y*pe0'c7ZgF U~)k?©PDŽ($4՚ >rr!ln9m)>^Eǘk0S'bpLhNKh薵l9DMdq!s'{9:qQ>rmyN\5-j3/d}I/j6׏]@-G|BC ΙG<'>f!T{|Μ$'7UHVuH,c^;y뇚?/\m ޴{f3<o<^<=)|46$߼  > e\o)P% 9#ZZ0OCwtk_y(ϐ"BHœy GDZHrq} UO螽Y[$]L"7+^!"=HnԅvwU; &8(H( ɶCl3TC13Άf蟁H)NMá=)=>᪝$ }gڌL0/\OsW=:n V"~ cj:?n&@9h Bd/ mؤR,P\CRdlQLJ!>j52{{܇M.Gs3͠JQt:3l#2VI?@Xc["N.n4؁.H0<93m;TŦhT"~i%|}Z 9*gv(EOwQ1 z25P @źDc^VL|Yr^ZeohJECxlR/%|TB!7|Ox Q65I# JL1޷B[)3.+ <2  LdD3ZG!otK4_Us. n 5A!8_V QY}#w)`=xh;32IXπ2l,?1AԀB@.W/h72~.`Ef"klbD~IaE*T|+3Qe4d˫3.ĿCҘ9Y8Ӡ cJ˧E5ԓC([< x锡=%d 6^D`}$:Hw/BZL1,py\ҩCJsg|wAf:S/C#LXF9hwQٯ?,Sz{|1uvD4)0ȕT6[S!r5ꂬ@)CIZT\ n>MMelֺoфǫ27;>Q+wX73gR4A]>Ώ'5^zQk$cmU䱻IPOMv bQ3XDM⦘Y1@^r?&fZ!j`39!wNVX7Wd ;ݟB>}h@Vޅt,B>wW;!ThO 颾 7% l eKY&Ɇ2Ϳꃇch+) 175K|`c3Sv c`k俦q^ε6xVrnvgrfɡP"Ķ}qK"V|kJY>u9 ˟ ëKWݝj_KʽS~U5!jվ/)CV;e`Qӣ^Ed bvxAi_?*xJAD o}cQ5OU۵J_.YE,9`OIJtwU_GWWCaܼ_ +<ë<"fs[9IEN>SY5ix9q:bP;z+P' / dKxw6YXVbZJq(ʭ9==0+wkݚJZMхn/XO!k..2e]C}K snSޗ +?<-`yY$ A8|w]L\u 1f炕Owf8Npa sιZ&*,7U9nqN,愎4E\F?Yx P\RJuȬah< k.&8&jZί;+u dE4>Qm_ Zt50s[&^}6LOGO&$Szr 6'XHͿ¿/*aendstream endobj 399 0 obj << /Filter /FlateDecode /Length 594 >> stream x]=n@{7}?6 lc7.I.@KC)>3#;EG`$f?<,[]_͗ecnew8ve}&=Ƿa퟾ ?kB?-zt4^cۆN}_O\wm+jOćA|`|GơjƱjGƩj'V5qD 9}'j ***j U 1z :cT b0f &#          l &ߤ`T0 |Qkb62LTF*HeA<3i4 0jwu1;.f'dvtٳEW&D.*'pU`ghopo`ghopo`ghopoPW! FPuG:qCA@bJ ,6R*J ,6`2 J ,6  &:N9M&\SI߄k7pM&})ߤo5M| הo7M&\SI߄k7雐K ɻ5 ƏmkMn%^Fʯ:/6endstream endobj 400 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 8173 >> stream xytUU !,^DAqTK-ޓoァ@C M@n@J"@qq?:}/} g>SX—gTUT[j/*R[9XTEPϿ|aiLQ=v6+l'4_ydᖭ-پtDzҲ$.=捱0d~?套W_;#1l-ƆbKaRl"V-^V```ӱJl6[^Vcll:Vbcy|l,[=1{ccX6ascac~d Il*6#c9z +_+y|QHHicOwDvW 9d n0?/gw'kpL*=LE'[4F- ybS&j`+4 Bјͧpj$.Ină$)wo_жȤ7Ճz<%jYejLH>SJE }yx4ǥ..0)N*.Zqc/Ӈؿ*T &hL.%ep 7Jm9vc7/>EsB(<6lӕc+mVJq9(p{I3QOT0ҕ yl|`ro1`>a_-?N8ӟb0B6Bv2,nښQ'uE Trw禇֛Hμ3< 3סW`^LbњK6-dllڻC)psH㟎= H~IwسR %" j45Ճ 05)J'<׃jЍŽP]ȶ;f!Uk֨A)T?w'~ #poYqP. _l8ZYRYX1s" Zna?y @~||L3"b?}(q 88 Zf ybYQa nAg1hf#.YCH `!#1G /r݀tldE䨮⍾)YI`*JA $祡L 6rǏDw蓮Rݟ^nX͹wʽv+VsEiSF7VxX@g-YTG!N.lF;"f+3C[WѤۗnPZFQ/Tt]=5Շy43Ktm4Gn:38(Vf.lD#U" r*o8M%`zKκ8*OR=OHL\X[Gצ|2JOd|z&P>\^*DpU* !&ffEL1?[_#M~f4U9%'ԇApՖ4 JTwQ[H?5Dni>ɬ\+޶r" ScqTM7^6LoF =rT)xߞ: :VcL)=o  >e ZBib׎P}s}CݷI?yI5Y6A C⫙C`j@u.) VnFIQqtH A/J=M B\!w5N%2Ѝ D4lĿE~Rңqq\D+Qih Q9 -fD+K р^~Av#" jQ yw{}͡8_!gXG4;hLYfpQ]\Պudv-]g Jֆ$q@6FɮkhҍH!v+aBlFOg;跙^eB,ōr¢0+߉m,jZ>lo (0{, _ 8zoJܨS|=וJD$eF++w% @. Җ#_r3X܅(Pe|tifLA)Hx9-BH$USk'ggԅK;/>*%W]8Ӱw:-jqf%+`5X>'?? Ap*"箞2m/i%Zm_eYMpaeM( ,['|j˴f*X v0C1; ur].K,DMDjz8 fiV6k9CF.PQf{{+Z Z*5K%7.0K&Z3.Ov,7DdR"(")g]ۗ:}8NoL" 1kaQW!^ 7q=*Tkq70 [֖ զ x5qbׁqu0ְa_aS(D돮poBBwWvf j4Oü2#QqY+=Og ΄u#. /Cv?3Z6~J4侕DPx݃C3Kp…qf]oXѰ~V{IT F$n|7$ CM@Z#k:MNnjv?v&uBZN`ځ' %Fvh-:(oz`#2.`Uj L3^j3"ANGj6`&3gG 4l0 SuGl'qСo^mĊW*9pTc3pn* r7r!1YluǚĶ:#|Pz~6(" o;VXk~^Y?f`1y6erkADr^_5IdM+lM\S>CPˁA/% -7׃~H!^J' b( l1tu8s7tm`!.hZlLkuCs͐[Aۉ8 ._IKpK*N4Rfб; K/3ƅb-%%K63'N5¬i3 Yx m.|SG~|s09J"Fϔai" z};؈2yt|$xG | ܊+3Qg`4QP$.ižWfZ wJ\5I"  z pIn-hB .lX?}oQ'֫6gp‚z( >u؎yA^ ]HL*Z5-[}+E-Hq-=K+^?D" 8GI"qAg:0 dz9b!o8 7 ̨0d37 T1{ʎ.w2&)f"ʺڠc!~!"C, bu)u)̤({ytq 3/ZY+q9u7B]VsR"oENy-uV`hN{/ H;ȌH Bg<$ 8 3$"= Q3.@P!7(7gFB=8|Γݻ(^> aJăNG^ 75o`d-V:xWWؼl1X 6Qߍ)Ur%_d*17:iڂZ3 { ϦϢoFSJepLBj+.iz.@C(#lّuL#-t3vWS _CpYƣ~o8*ow& )PJ\zUv #]pw@/lfd 3 0Oʼnf]vt /_^qNWv/d72lwb ںiv:BL7lP=݀ 6\G AC!` vCSRcl$|,g,'&t K$3aP.mc ?>PwHf FShOeq?JKU֙psVro/({6]ubm#YFk!F2/z5óte' 5p{M*N] zS6|bHAMd3|x횷"XgՑha}p toO"kgoxZA!}fFD!D#/R[*s0/ȟ`kڢR7ލ{젿1؟BkxJQga~HEv!^C 0;{:^]ml[nO/t82bj[Vd1Ϗa,_mF:Ty3E3f.}kʴ_QfS+l 6A:Tٹc)n<ߑ5.^3e&Wd8_@89Q}-A^Ag@^RCkH(>H zo΃wE36р~C=ҳ?ü9g6Ѭ.. !nF0[6dvjya.3G._eW͙wivΤ;( 1oJeEzl3><5/o^W5% \d!4+`M5`71EH iii +i'1Az8>\^hH+Qf0bc3? w|$VzLu2ג*\Xb9lHL-Pm_5<|{Wa~5|<6H[O9SDR GYiY4{rt̴IxWgrrm- w4@l˞vffJǜ|zmQ:rpSOԋ̴3Q2( :\ѠҨtKy1or  $Ytel|! qK>a!ȇ8?=T|9WUSgE N\(O[ BIB*֪}A4Asýpl JHNP촙j' QCD[fWSZ2y \w[8H߼;=}Lh/b SU*aDl/dR RNe3)6{ Va>$fR'\KICHZF hO_Nsˆm\Äb6D-K䣱G$[/V3[])uzcoرjf4Zisd eWsBB6Sȭѐ"G y -fu"\ :F2 f_]/XqLV* )JèUƍ#7/pŷp;{v;4.+!k;=qo%=vq\}0jendstream endobj 401 0 obj << /Filter /FlateDecode /Length 914 >> stream xMsF [~:$&9tz`$&acQ EXRv\ujX] < }+UKş{-TVh-|*~quޖE~CWzj4\m᪮^c:E] vȋ~kf^EWRqӉF"wmwbsM{ΚᕁA0.udt%zRڗ RڐK(Q*Dtڊ5C0p#jsXV:JEPD{HB:A\*L% y"TRZ])NBzgpaq95+bT)vz&xEat(eqwJ<۩gՂ]JFEC6HI`m@Pz+p>ExSta 6Gi[&by\CK9 gݶݮ'F껨>Jn#pJNk34cw/&Ϻhzk:6|q%PVG}W{Əh}tkIѹ h,K I6# |Da`򛀊1Q!ȣ/㩭["zIOQSy &\g)ޔ|We̔D1|U?endstream endobj 402 0 obj << /Filter /FlateDecode /Length 3704 >> stream xYMs8t[ԆE:bcWۖ^;bTUT,ysþLڝ GXEH$/_&;y?w; 7gI~{v痷g-mޟ\jD*緻_ħ`6Ҋ/3RLaEhf0HS'Z5Vr/֩NJIHQUFd?X+b0ĪۼZ01]ݿSNkcig2L8KQLYTFt R-|.!F3>f< FZM E6q1e[@q[fZdl=gsRHMk#hR"g5]`F"SG) uB'i,dJ\ x;24r)ႷKŦ*k8aZk n4 D[67p/dʈ|䛺͠dT$$ƘhS5dr$MolVrr7n:6+?Mq t!m ,muuq?bv -EE1-0˲~z(4yնϛ~.fϼ.ȋ -Mv֭f2Gjy1]/b7G% )\Rgd&mf|7< &x3Fyd (d.Cm,N{HMSwNّQN@z%$Lr~*cijVL7HBD,WCK18RB0k\ Jl):ݎ2̢˞TT7S!jXV>?KW_>N$l&|%SsDSd  [[LPYHfC=(RTVF!8T(O A$a4oF36hbKpzax84gN]),'(m?y]R\W` 'L7.Z@Vݬw~TÄsbI个}-WN/-..ңԹΕ׆C#r1@I+6KJ2\_!=Vbح$&ǒJ4*Cd37*pz 0ӂ7A>,9S K4E*oz"a>0|LKO; RRB7W2Zeu/:Xlf+w bA[*XQ[U0@TSsɓc eDڞ>fUqBH?Mo@hbZsS7mۯ{gnnEJcc;Tsm YSdweޒ6B^ I4p+-Ɖzr弚/Л :(G/궹H#r'ԭ-ޝ:0ഊ.B! V`)RQj+<c  5h$n(|Z ,/?l@f[ٞ[fLfN|KoC2V;r| o[.V?4Г_'eZ.{r,$p",SSu %pI8rLciS/` W.)'^yC/!$UwNk*f=Yy`zjO#m_4/Y31x[ljm)9@݉ ^ i@\Ω$`7EQNTB?I)-}!a?ϟ.aOrm8xf-_a_Fы8ɨRR0 %V.W 86VI|3 ~ A@EmW7'CZ,ڎK? ;<$`"x?;4M};_2!_IJk2n4.C M%]mѵO#gV<)'A~ޢ}# o8v}9~C-p=k n&]\#*C˂6pz =$ kV#{,׉y۶\(LLhf_ͻs \%57K_/ p&椎A :p2asOQ;{d8R@++UALbA`!.9q%%Iu~>v 2=`܅%2:0;|,b6mU=)}"U4|ʷ"unfyg&V/;1,}^Oc/y,Ia/׆I=4m ][/`ڞG\˝R5e;PJB>igFtSeJTٴo&mӐ5X6lDOW3+Y厪V.I0:6&&!VLav cT9I#J*Hzdf} TIzJ` )cv߶c,R_&kZ+X_2ޏ@XvzMED_+8jy`| \7IU P3U};J)V[Dwّ_xw"=r jbisedi BU삣_0F5Bxd=2M!;xBYT&c#E"y?s"3kbE|EL{4GL h꺋*ӗ % c> stream x];nPD{;%ݏ 1$G)3#;EK`$RwO|kw?i^ƭ_?:/ЎpJo럿kmqC_X~[up<.7ty{IוO$x tendstream endobj 404 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 9786 >> stream xz tWCu r=!_nbuᒆ˶-^rǪek+xg{^~sOD^M-/Z!)z@4]Jh!âGDD֋^m=.(z]M\ѓyD D Eψ=+zNXhhE]I"עEE2=\,+_AE_eq75„>xgE䕛EqkmݾW~}Kw|s]I&(IzOdYkΔOixoor夋̚z}M0.rwHۓP?);/O fzN*ٳ:r=PͮdH#pYuDe8dzrĐ{(ZRΖ`klԸ5sLbF4SfL5VUgKW7Kk+6\ HA]!C40H{x8hGItv7)\SgWڔev64c.OۨRtπdHiŢWhs-}%?T12>= ؙk9~^xsٖbzZ-ʫt>U?I,FgBR* _or`%o|(!qrƓ xi&lb@:z}Bb1+;*?!sAn;{}GG<[gaI;!I5hUkAr& ?*l˫5jΠqKW֍6:}? +1.πg$pQ e%z&e򯅢A?KmEY''rց^=aֻ}D*Ũi֮uh_]lͿ ѡ7AU;MB&k)6&77hqz`*Z2Oxi>[cAG=MLl(һþ`#ǟz֝h,4=Bv2xaT*{=@Xm/l,SIvHD tOM@T>֙ +rUKߣ#bω$Gi[vN}Q(R\}' =uߤ;+-~ѽh*=;io8aLU]umvG`:No{D4צ-\^UM] gvI'K-m1~k &o3 ʶRx  4 4cxH BS1 zW^cȐףv%*s.\`Bђw=VOp$';e7E }m1oov."H>yB.4E%{[Z{:3vlU:'jթR>OwdV dTe۟j9:<ú_d3 zZ&fmK8w7%4 = B ECCfB]{hn0˴TkŸEZ@PC]#G1fq^ ?/Ra+)L)f0;]{If7ͬSLB\Z} h}?FR@ߞhԘpH40 )kY|waR@'81\{2}@{{`رS~pGJX!&SDl:эzX_/2ĩةa7&=$z8jim;Wѻϻ߷'G#%|e3ks V|VE$ӌFiѼZqk%Q!n!fm^ODz#Y;c. wQ\gR6Fw$QV Vx*VE9Jn%5pTVf^6-(HU.ԙ>:7XquyQ=e9bƈ&Qxܔw^G0f//@oF騷q6h1Mt}@QT/{fۛBߊ<>F#@ROYPs;vuSPcZ!#Nxþa6E B-^\kI̚s : BDKҥ]t|տ`hI59XD ۹tI`5B $k؄>jX|Mtr\iF<^=M{ 荹1^9)ںjgr<M<'MR mL]Z5R;}p18cE.8J{@nUҨԅuXWsה,lZ4PM[yr¥oFus{2cxwٙ?+e 2YpQ6E'G'p{} 1;Ka s[4Y& `U;4֒%հ7+k<[ǐM49:,˞U5RwUt/|v;z1O}OF/8ݴ{ ¸ՄpFB<уgrs| ?_䛽y'ر/xɀcwl2l: Yeonmx"\>?K+ Y"4]2w%V[ImP_b-Q. ~PĈb6Q?& fBw\BK^!mM ©^?IMP~Prqva ^=1 5m lv7Rf$z>x//{u UG/ܡ!n#4񭸪; ԖzzJ洰F=`:1d% M ,梤O ~n΍P \%BSM@ BNE;vO\, ɵ[^ X6?srll`մP8ǑBl0Gr)^~tvCDyT>b_ďWH0:FLmw' rMJ\aI1Z9e;PmSСX#VR_֮Ni;:RzX zvvZRy~P,aB[ӈyvF3ƦۮV68 GN8Me3`;d?fZ]i0ΰ#&YF9;q䤈p۽V NԲ w-\d8zt ִ F4L}DÒrzp\{l{?L@ 9\wky3P6sDSnPXI'9yeXv5丈->Q:k>ln`U2jEÆq}XE-D[/ЇI $sQդ&м+ mַp1?3ث?~QQ_L`P,[,ܱȼX~zcJpfpRʫ4)z3n2s׵ EB™ByGMh)#1ZNƚI% k$+(nofT&-l>0 q(\ &®&r>"QnR&7c!11Nd+  6`W_e5Yv#M̭2Gc9T i驢kSdsaak&&LV#-m|D-@# HHRHJ% zhBfw7o*3Q*gu&l6qHZ;e >{K aӦ2ҠUVmWlгlyg/@wy|0 J0p]1K\xf`wJW[m%8tþ;Stz\w7NYXN@;dv1%%VW e`YPaq4Ӆv,Ӝʜ7qcWYхR&㛆M VaiaLN ˆ5X}X^b8KBzqqo'2 dFO#6d,6?$;|kq7`(bC4XM{llqRٮV K2k [SM.= ]{#백\7/=j؎h"D^@ɒ+ \4ŽK:@3ZM Fe&|{>/Euk쇦ON?A{=y—t7{#g#㖐EikhҴu%;;OxQO6K?RTOjmмZC 9./%aԻhsdʴpGpęA_ƛ-=c] Az@wGEnh6ئKbNAd&6!8zQ;kUEtIynF򋔨 ѕRK6֩+MU _8$bk\wO%p2=xoOH/2.żB&aRQ(u_9|$?A~&]~;~uH4sejMMC-c@;88o]z dgOFª/&/N>NP gY]* Q Ђ_" QPkZ7фݾt{:ʛ?{O %+TU.MejF{q1 , n2`ZLN󜤝أݍ]N:u'Gklk킴)t8L0vDiAI/ЯOʆ9FKSIOA+csYJ,@*p؅a4ז{h{;s!.L{B%Bqd .?bY)mZœ`)jc\~{p`X|F5Vȋ0V8wn< c_l?Tڿ7ŤssMߖy\Sxsxɍֿy4Lmh706'Vd4>b>NaѪʵZ]S}nPشš,x{=F7$F#}2PjST*UPGbd[kK%9T+q^@Tgzw1 f9(Iѯߩ9acPWrlB8+Q b0{m %?<wD^߶&x-v$nn%~Gg<-$(Nn 40 wxc#ALfWי/I GCZ+__xCEy F͋ L`bLBo;pѥzz\D]}]71rX hP̺/s{ݙfYىmbrw =ȝr19`$[QXt Ե_u&;;ZT!ǻrXGJx|_F(c9ƅݠsPB:MͯYNkkl|+6D^\f Yw@yn/ sϯ`IԿ&GJ<6,ֻ Mb3x%t%_$|+}l,8 P%DTpHvB [6mVS"\ WRUc_̓obZJf3Z K&&AJ.mESh bpAn_+Kƈm BEEN(ʡl agzXon"jQBp8s9РU5s;V]vIHjCwW3h'|U}'* :%$`Au暀q m%~t 9WGk^~ X]ĉH3ߡYߣoe$n9J|R~A">f`W۟@CçPgH`W+M}+kİm $Ѫب6 Xր0H Q(ғK;K<ɒQ'ұ{9cֳ, BMhmt9^ɁqiAه~ad,>? ?u ?Ǧԁ|{EKxi|8Ņ; UhFF 8+8Ue$g{:SQZUժ*]Z%l[$CHبm۹1{H'*iϼ\^g3k1iݣBM$&OxQ `̱֘_)5xA&I uR WGt'.Dr/a G]I>1.Gٓ%'?J('k;;)@:Q-8sgJU;,>z<]CPC B 9BL?1C/#pnagAFꕩb) &|xˡ[[ïvH?mendstream endobj 405 0 obj << /Filter /FlateDecode /Length 4092 >> stream xZKy9 < G=xw,q&Hu#qMc#>j`fw4ћtn7n4=ȿi^{..37IMX;V4MR~hN[Jujm}ns~Ѯf4)KSO[eIYu>qqs9E+,BDKr!x0AZ 57ERf#Ia3Q/q XhC߶4C+PFhޚ'tCW~ BUThxhd9geEXV]Ɖ^=R|U'ɋԫ`:d4qk7]Еt.`tsQo~VuIʨ_euSԹ9 Π` 7Z: *:[M@mރ+|MZ`z旊C ΋jLK 4o{SܒTOYO:]) ,e FŠ,]ЩAq= j?wdNudg`iFe9\ܥ6q,J)t_cYmCc6uqsyZcŗkp Kv: &}^i#cis )]WCh^#t [u)xnX)mk->PI0֝5Zp_DsF4i\#ZJZHZ a*rfW$.dXɜ9Xt7'OD|k =pi w \4gYBH~އaՏcg=4x7${#h֤ 3?( Yǧn ߫ ۱Cd NNB^_lS]EyuS#s<@z:'YCK׌ᥥ8d8lbFead|R2 e7 ءc%F8H~W °r'9$bR?Wy90Ts`5{W`O3CQ̜7[BZv?2Sj`70ӷxvB@V$b!jQp,!o@m5.n6/O.@KC\Sov Whap~®#helu">˸G7kirX+=gV!Ъ) % DU=֐ ֠,!{yj@JgX`[:J%"]dz9LM9'03btr X2bp+=+cdV]U!ekU8Ϝ.gĤC=i)ޔO F`!?A&¡'%?:_pEsRKZH}L:6Ñȹι:}x03dZ')x$Ml9'hèZH~EeOQkQ(_X"#(B½QC\6>M9EDoBY`hg07%ی PWMOI?ՐN1lAO-AJƁca2_C]ALY4=Us$\c.(l] 3   ף S2¶`]JE`3agWYY/a541@uƙ%=x[xC2bh^89FJ 2l(|첛auВ,HGjT?viAR2-Y1>n[w 9CKCxŎ)U@~W RWuTKbk`nlN)2m3.D !{$'%kIy(iM 07_haL@5 R@qq LJ,ȶPX4"ox%R4z?|y80ҋ7qϰ6xs[߮LRl#Gt=" N'sXX  < ~^vT V>$ G+DI& !w5!J6SMd0SG6-Jl0L2B4:YUYΪdr !n # !*<,O$@C>5' 3yIz٬ZuRXk.Qkpc5狟 IRZ&x Xћ utuܭ?Wih Bǜ E{< ͜g3lơndK~s Q-ȅ~6<+dys?ybMÊ .^|sf{%ۄX"*RQ%K;A-BL6qMի_~K%+ ]HUaFMrpȉ)Er[V_7opKw¤&nT^Ι^9-܃ή{B{?Ɔck@c}JR*X)S5E bV&d.wc3g]dPq*pskɧ3 e99\4T ߃\tڛ_ :hIIE?n.,o,&l;@L= X@9Ddw'MK7unXEv@7]Y: k]A t,I3Su֖wp$bKb_ z0bPzM1\"6}W\@[ŌoNb`))25KKχP9gvIffH*H{$2pP,VGo?|X{Cendstream endobj 406 0 obj << /Filter /FlateDecode /Length 4735 >> stream x;ɎuuXB̲4<ȶf0v&L2҇DpKVu7  tx/޾ˍ?Jl~&=l ylnBnds늍-\t=\eOUW]`l(X"B}u}#"OXȃsۼp `rG0i  zrT6&l4\I{ ADB)0_^J.l\R P ܹ~h?E [1qKKANeefěLvi \F?Z! V x; 7!xlp! @5fD Rj.ưa,\Bft~yfu? 4D .q};r|Si)2WOzP plOM}+ [W(iyŪjwtH9Ces ) ]By?) 8ʮ=8zU^&}+8 ȅ!Շ?~z&Piti3 }nVoVp(*&FGfKԀoO8agK”ht% /P]Gw OA]nO{0Dr4ڒUfҫfĦmX7PA;:!tkuSPO0>c-vQ ~0׽"+2zT2zD SpY`UP1p52?FMo *]Ae%̐x:!jh@MW_>T"Y97tT(Mf9Blv2Ng!&SpLJFӹ۲$w'M2?kͦV}_v3ؒ.TuẄ˒pZK 8^CGDK{Iڏ6*fˡ1$)fS SR4m$o!&Cc* r?Vuf.C+d!T2ޒ'5r0Q-_ޒMY Ecʯ*<:e$H-PZp癢ʇ}Y3,Oȶt%g ;cV"3"==[2Zյ'mx?HHͩD 0 ;1BgL)䭪5C*w,ʿ^HfzdLB8AeԕuhVٔN%,:<:Ĺ_-*  *WJUdHֵBW]S!YkzSOBDGݛ$8QbK[xX6С'0BUb8~k5m9CپXk˚]7"?KMVZzICdv)Ra&[YOr;ͼ(~8*U_(K>P1h@G()]#>bCK^:@.mpI̺B {;Q(P@H h|i:t =8Qrм'Ũb]\|CR|Fܶ󁌴qd8q)HI~H06ɵx,b>)Ym`8 Z؀=hDN0hbތ="H6ҎN+I #MEDɈ cX}8mM5Fi/KX\ :rb)ۘC@NK4;?|Ml&yυ%ct7Sˁ9u؎se(4jB |O ^"V|nߝJJb=J/*i^|cŋbţ\jyŕ ǺIQ-/^]ە/Jд $/),\;wQ$tBAAymS`2nwJ@VZwUŤ;xy@\ɝLKhڳ_O:;ByJtoCF6FI N‹?#=?mxrˇS!eN܁Rعƺ7t@׬ 9B-xd E 3DeJqRR Aj3Q fq1U;y)&seIl^|xuȕҢXSPmK{%u0A +l9/?/πƔRA(1xgZ5RCP|2A$@sqs-/D.Ea~" 90|jKpkԶmHl;`JR/8T z%rO>p~'s~CIb*Q>_ )0ܞ#ƌۘQjsgX!sq:f$ղ) xs[%6_^՚{8 _ )3AQyᐎ/,EF[l" D փ At,0A o6)//")YX=mHf*X#W=icm"+Չbp SݶI-AŚ:<ݘqD88yw|t"G;A)zU MZ8"@mĽ0QWuby88SylZ0&{j9Fm︆fU:]O&r}]u0ҿ$:ʝ&y^u=+8BӮ*wěњb^Jb)+qĀz` @WchfE١d$ULK@%&){ڐ~NϦ!*M %cRq56u pk.2881~<z* }š/G}ʈ|}-]G=I3t@/ڞX@t ~\8y(3|JdC@J9m0ۇMI+*2-Mm2Zv1OQh5m%u+2\I` 1XjfCrCqw5h#{=98MO7;x#urt$6&Va0^oXų 5?^8'endstream endobj 407 0 obj << /Filter /FlateDecode /Length 4147 >> stream xZ͏zS{0zX+")4 I(-52l>HQhfw sKvb9^e+AoWgXEb%M W6Tzus!ҥYLr{N$v[72*u$u"n-i&DP{|L&?߮x:TMڻ8Ny81L-3O6mR7k+%>8GF/9tκr&T=JrJkE1{?l{BC<s6OǑ幓`+nE0?%nW!IٰےF LZk@@r&J'vNhL}|TZ?1@ &(m&\[Lmön](/M"o-& \TIxd\R;K 2R\ 6zI  6#2:MBu?ͦZNu]YGd7,~ь E3hi(!R1&HVycސ%A5L!0@q'cLc3 _X@r+SEpUx/9 ?wv=!Sfٔg;gY?wUٓӴ %7Z;r\FVĊ~31{6eT25539:M\#v65߼xAIq!ěL#ЈT2f\?x\jn V6w-eQ ͬd 4d# uz$=@mƋA&I!Qp8-K~ `_7q P cMhGp 9n~C ]fL2𨊼Ex4XEKbSƙ* ;Y26X(3Vշ$L (81U х e2:l{1OOfhm&ﻪ< `r3|&\4GgA34><' r>AaGZ|ITD<)ge2F8ew[ftuI^` NO&)`-%`%j҆x -CcCO047gp௪wP!Mf\VSq Pg*n8OnP/Cxq2G*&&vrvBDOverLj섆2GA,dMRX"H" I(#r'=<uaQQ1@Է!v?XVFxM .#-DVRgSc)إo GvLZ\K e@},c,C9Oz'92u@bs@XZ&=9H(P # Kǥ )Bd=/·Rd 2fH!7}ތSYO<<Gp(~EO(t Hpzy@V96i ;3 X|MY~p0bӑb@1r'gf ?*x۪m@/ 7{*8ZI?T'~ޞ uAA0a%eZ DMB ]RJU Y5ƙxS> Rg8f](PZa xQ?~+PI҇ l[K_[ׇjRSP.U#jV8¡ğicO/˿ !KQE %¥&/ƽ`B@`qA-:/j]sQ&R21Ešl*q#,B/@i?nUfs)'!YNnJӑЦI:^vX=g'opFQpe7 P(1p$+IU}NL6&GP@O\$hQ;\YmO8bPŲ"sNe@~^^~/pI<=R> ~SNMSD?Y]?G*I+E`i'c[qĂ/` C>mM8s[4ULj1dzz[b:]Vt!$QR|#7xБU m}oܨn|w:uThsjKY4 #Cw .2x?Xj],Ic(`2*_{`KST]L&4;u%=trYcSɦJ"CZ[n;vmynxA^y."4Ml])\, }j\cņ`aEVMՊS3|0Ot12=bEPEkуC"b[ ] D3Ѹ'՟6ĺ> }#rs)8us4z&b9SˌN˹q%< +gӕt^ 11^ $2Pnao~s2f)X4M,RpZt5Hq(@J!XV;F]DKJfXU &JD-|"IFXxA h=`bmDh^A FzҼxxYe!avZxA┒jR$K''KQ{\$\ u*agF Dw!OD;64en|J񦥌S!FCϧ[€+, D }ӏ9)M/[iER>)valTM'Fj .>.Ezn|̵jܠY~HcFw|\{G_oN=l6c)xcᲐB>Qw[礢Gr577޶G*ң|Yh-_{Ї; 'Չ~?9.ռ3ñG 8[d!|OH UR](>I.st Ic ;XX90*nxo*Cׂo==VNc7::d7P^+ݵlرWY#Xp NGjU #StcO],*c @k'\ HTǃ ؤǺo_r#{$3=xS%uFO^4XMۍa iRPe t> stream x}W Tg*ѸPtq3:FD33QJ+"@7@7항dApC[LԘ(q0,z5FU9oߧO~a07~ͫx1g{s 0yLt 3,@©h_`x<I i{E6&E%ڜ'q0L*17#QjZ:ȍQ{cm76a,m6l[ba 5"l-cwRl &1F`Zɋ92%u47->&ȭ?t/0eщ'^-I'Oo ق'u /LnhY?vS;_m6DHr[)DM(*֣~/>y^*eq:2<4i fffOzI5@XUTMm܊F{=j>@&&.&uO 85臖`חt.hSb uf-"n Nc{yh: @3]ʹϸKɐ_2<My<|NgwDvzmZ 0eb"C @gdjXj:H30axAKAR#@F=}T"! }5/6?@K )![jzS%b^SG׈xPL-m0RE0-hGA z3ף}0|橒u A}V_M5^e`r:~͈x(Q@IiHh=wοnwX\zHQ+ty$5qC|X~= YEkԉ䴜wJg?2_-;#{ *T 5PY_V[ ͚f =jۙ'|B.%$R =r(C}TTcdox{g4^zS: H2&ڷ]Vc0\~ݐi1.J75NWftcU 6W!Ħ5>_=&6^a%\R‘Btϱ9<`l4^3/גWYQyvVd*% šBv=Av/[kW!^M`#k:MfWvth/R)  a'kBtï4T+LKf<"y8T&^fWC-xXwhcf0o%@I7R]H*<;0k P 2JtsnǗ&z,)b^xD+h'*4 9OG!N-ѧa:#"+<'9F=/4`ׄC, 4RskN&@ #gC-,G dlcbOOcsA>uq|\hC1i$6!H $9Nr 2U?rYpÊ ! RHg 3b4}_i}_ jZ^Xu ]D.ʢJKa+_LB,/˔zS٪lrULސǮK֖.kSh+R;KDIrg*W:ͅ^Krs3W$3=gńA6'!{{3N P@K,-9w?M|j@.ir1i jQ{7Fj2m>M܉`.9Aq2ˀLH1հ@VE55ZVQ jEEV, "hu0a֤ՠGISfd=2,k>^#qAP<UEOB,a&o r-/f̤]V\ HQby^\/ݻzmW^1xgְ^F<~f%#P)3G]FWT_eW e ;ni ]'%C $c& E}чzC@uǓzzg$$C4D'HUbcơY\{V]\l(8&=d b3I&q4`3mݹC,~~tYONcZY׫@=]T%ihoKi*dbZRty\.Skz1{ټY;Z3&LdǴ^}m%;WU\ȣS1S[XN݆bqay.[UBMȟ z4q'TB?zw-dۦk6 )@ذOLROD&9PAsi]~)Ʊ5%ZJy *{u›h ?]ReIVX;N߫;tݲV願 uW =ſe >j8hDH& ҆ǤŤ( z5JL9 ({ [M.C]~RA=oo+4X~mvMMٮHB,!b _a])}_]mFC3[dviƛH4PWKX4hWvѻ[w7I~jV*sFBDW"U:uxo[5ƌ ^бzT9C0Q>˜!?=]?3,2:U&D"G!,F}*z z@kQ4`)0M׿jll0AiݘxPQ7 b%qљ eLW18{1dͿE+_J>]c<x:v TA'EԱ$" ';*e~J[ aMTcC7KUx%?5>WN(ѪK襁+_AT)<1\P˶he^k0#-Eb@f8;fd1ǽօKbܮk:IN^B58PmҀI@ENۜEhɎ3;CwK&ǰnendstream endobj 409 0 obj << /Filter /FlateDecode /Length 267 >> stream x]1n0 EwB7FQ\%Cd> stream xU{PSW%$xnJA);*.[UZĭb!%!aA cBy@LQtA 5vV]aVݵ>:.ً?93w9s~4F4-LM\6f0 ΉZ!H ߊh, oRVS5ڢB"./^hٲ% IIJmQ^n"=W_TJAWW( 'umAJ|H_TZ2_)+>U+%N~R5R^Ukb4|e*iq[dSTLGQST4CIYT5%ޠ"唄J|T8U@ [wKÿ& 7DIE.5k1p}t8 88}SE 2D?(>zQ2RN͐ GaYI/,,,:ېkis.Lqo:zƧKύus"B_'(ɫ;#eO`8c$o6Pʥ_8P%ڸgE8 kd*񰣣Qۗ3 #pZx l}34qgA& .B (򜼱Jn;PPYkY|Ɗ64ֶ̈́ÓJ[=l ?['a(۸ƠQJ^>{ωiփNp}۱3: =`yA!8 WFyC$ToW{ˇ;c:]97%,ʨ6v lÍGNxNFaNm`ZsFWC%?kuKVa@iD=+P=XŔW^poc]O6<#yw.yLȑg,5vyѼŶ*;OG`i͘xcp!Ll!;qݥ;XM~U7_ 0W@0r{DvOCXu`M.wKWǮ@^IPVwbLH]<_ஒlBȆ"wAwEVeNa&NèFo4}+pt=$_ uFS7нx/vz=܃z=_$")lFٓ3Srލ_5p#A:,0Ѫds,@cM>C+K_Tp%iݝ(+Vw$A+m&;})/v{Fd˨SƣfH}\s.(NÏ"񊤤!K=*{eޫ_фy)KlLN*$#E)fqSYΫVtze:-Q{u/v#ɷY(ySbu #'N4 g'~'XWty P%LTeȹd;O v_Uv\zI?$V&bD> Џ+ž}'g,w/J%Dz- toD4F"Γ ^yקq ؍aPQvScZ֦zMFf9dnBY6޽`a{"}Fv@ %ۉ =}"s^Vy& p4g:i.2$ȏWOrrDn0KFȀx5t[IT &KM-="s?|]ip#";āSdK:%o%nT/Iԉendstream endobj 411 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 2282 >> stream xkpWm.ԈD ɮJ:P ɤ%y8'cl=dɒvgWWKlŲ" BB(aN!)C/Iݕtrh;ݙ{gwvsw+Úa2ec{?iܭd˄rC \ rhm~[ћyM|rL. uCV}h_՚֬YـV߻kPet~sZUsqh}{ gk<5h#}'uF͖f){!Q״i894yK)mb۱g}&l3 ֎Ėc T ;/[\|D*DK,PzSnɄe9J -hahqwFd"IJiVtx잽> |zOӹwr|.l41)L~MRÇ 'z:-vk/~6yjOIN[t{weX.Q$2Ga}~𱝛7'9*00F5U:XNFbs,njQԟ jIǷ10,;9:L$X۠ڷ=w* $heQc!:m1P`"`apNRH4:0;P#bzW-v& |ѱ>G³PJ#D4 S NDHc60S+DWx D>;mXwXч @&B#\& @dt"cW{ bQkڧȯ7*}ôo7?H.0/Src 8!U oWm<_כek848<;&kS)|2LÉP"9]{9.MWϖ*\F;AzծXh瞭Zr!$. O*}~*IIU I{0LMWJˆmQ:&̄X`LZR;j1Ѐ=#|k_`p6Omx0g~3jLw4%yN/dBNJ뀾h{38D0&Ⱥݞ_#R_dl"5nZll_L"q 4kyi9o&OcXbv& PC219~U|I=uI"kD* L@46Hå3챹'Ϝ8R/C#oMʞ>W̶x)a{V_ŢMED[{揗+%?aVN֟c,BǃM҄\Q^?+ԔXR:q"ƿU ] Xnϫ8_LrQĥ\ʟʼnů#͊-b\AgS.՟UJȲRxۗ(P;n.IsQ\1R6&S)~"N^7wÕ74=\h~.ڊa? endstream endobj 412 0 obj << /Filter /FlateDecode /Length 214 >> stream x]An1 E9En0H qPd0,}m[zҷa(ywfrnӽ!3]r1`cI:vPOJ  W~V>KHZ(2[`*8sAOT*Q012zyzz# ѫ٫@HP9SzIeY{kTf^@υGSe? nendstream endobj 413 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 1183 >> stream x{LSW-p>as7 DLD@Qt@| U@޶J [uft359ZO"ѓϿlR$м߃}؍46ЍJGG.n-=qݼϱH%6kKIs~-motBPw]urj6`1ѕ6;w_aBڷ4BR }ujliv؝Cմg8ДG& 8]U {~H,UL%phv{ljƦ4L8l1c"~_MiLPV\c̔lpfTÉj|g2!e> stream x]M Z]4ltӅƨ04,J m^~1.fQsB[ji iuV-ʧ'"4r^7|ŋIMg/$-c5Fti_ L "rQCBEL'hꈻKhy_endstream endobj 415 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 671 >> stream x5KSq?s؜ZM"P9 KzA*P<ŝcC6{qmVP݆]7s<:*]|/>vbrIwM ) 5Hߺ#:=8؅n-_lM0Epd}1H^Z{4ź6/9imU!gq'n , =0H\8}F͑/ONh> stream x]n! w78'KdH}LзkglǷc-}\jx[=^RNp 뻡wW>˒ݛBl 9šm]ұ?GR ;fXjG#k4&Hdd1st CUރ`Ľ~4H| GLF{X7SJڸKx/endstream endobj 417 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 1451 >> stream xS{LSWB{e L8 "A|,ёIA-p"-XZ*]h>(} CI`:a\s9]23xn9 ٭.o9Nsq!$I}r*6db<#a}$ !v$o|M/GȾXBz}Q[רVV)ekrss։23s2F!-$*F&QrqamQ6ʺM׫ >VQe:ZgES.U+W? /:QՖ3 yDQ^Z02F+rgN$5D*T0nO4%"8YQ]Cdmx3mAdVBA%b8Ki#tICD,a&!\LnD]&ލثql{RjsC^"pC1zj0RNpvyH<Hwp(0 ԓ8wa\F<>CiϯB3AP.,Wq&(iTIC I2xQa77@D/4r 4:)  bԡ IhB;"x r C55J\>8~phc-=Ö<apt?8s᳹|T@kYiXW6(^-U.@9ݩi@E]5_϶)a jiBNx"zcU}^TG¼Qvag.ʯ蝎Ó+9F!%yٽv-Pj:%9fr(齅3s0U (2uTIjR^?~|垍N OCl1G|-k"N*h VVCR,Qi+ht:ӊQ"ZZf0h:srpZ\vʼnwQES0A>I7Ap)64- Ch$4";^ ( el>\HSv~Ǚ Fq:JZk7kCC<7*]ߌI?aGQc+۟9_[[V+@=:sU9n#*c’31WY񟏞x xgLB/>z>7b1ICGn h> stream xcd`ab`ddd v541H3a!3#kc7s7ˊB``fd/r/,L(QHT04Q020TpM-LNSM,HM,rr3SK*4l2JJ s4u3K2RSRSJsS ӃP9E A L@00ֽucź>c9lߵ~L^2FrR}_nrlsguϝ:W>mr-S#z|gx2%[euweռG&Ddlk j讪=W2Is'} }wn=eKӻnn ߡkEt9`koߢ9~>':yn)?zٻv/k񝍭Dɕ3{VY3vgW>> stream xYK{/ćidޏRbM2Aa,M-'>3$ϕ9&`Qh'<2Z;|MT{7iDbdTqLMfLj żyPη}E+l 4WM|p+JBrq^eehꄴN@f%[m7z!Hdx遲h|12-L"i Sd߿D,^hb^/ͦW˝gnUF[J{0B) $-(bicf\~)$@x`*w9۬a3V֓$t /JQx&B·"ػ_59/ì}7bW)*cKʹ `  hEH},UB<8+(c-1 ]~D}rOŠADRXr$&A+LxDF<[#|$OMWNKd 6{ d@  T%%́\5wT}:T6D#L Ep$vw΃$bG%2"fD^&fP_K]lvy<𢽺ObDDA]]=SBD4GcuINz{lQ2̵ P7 %mf X4esʰК5TS$ێq2 ka jA%wA#<;] v/;>e?/d4AG*NFB.W'ZJ3hFF!RrTw}pXͥ/E[||Q?,y[j,`cGy!&ch)y!/V4 D~"wPIgp“ v( E@N XP5&I{^ k[2q iJl9Y`ң8(dT%*K}AS.b <';&,[ur{PHf>20S恆Ɨ\ h*U(c9(-t26&hA38x†zؿr788Cc`fk{ma0kT=q8r$?TiM, eVag/6u׭W6 B!cFכma>uLٯmG3J&^P?wI )(` AXFǐ1IHخ#b--JTJ!#2KK/aݭĢYmِ"drd F1xS2ss䴱h5{q񺌩cW|P|Gj+6rXa'JTg#YHP\5 >h%|cq!4cD5[ /9sj#)AW GQq1љjI(;û^af{ZHu'tKFK0JDM.V vG4ի-\<+BM.w-X6ǜKSf b4ШP/l6+2lNYZa{uprW"4 v?"GG2]r 8=I@oR %1˫lŚ *f{SE4h)ٕ(.iEN媽~/@l^zdY}q x 3Mj8cPN& ]% |RGc_Dϸcu~OFR 9tM]g q 6~]BFob~_ Ӗbʈ4?NC?_؀X x= h tF-u\~37xEf7N;$a|;:S"ʣ.`v&ͤ]ϰNj&/!O`JF/ @&Z{aPA17!k=8$ 麫L#5$C3i:swXOp}Svݢ]#^`Vg]yf 6)FbgM岮M08|V/[?1N)ύfќF1C0|@0endstream endobj 420 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 1855 >> stream xm{PTp%\vHݥ S&:-TH\+YF`yR.˞ECHy :hP['&Ul͔mZ29K&v&߽|w7F$yCYws]%/  ^V qRedi9Q*erNf@*]VNT&+0̊Lն\&0I|$=av3O9a1L, c™&yY)C5X*V8JȽ+fe$艨t ĭd19b8rkdqnBO{N2d6X`f^GƛQӝpէ 2 `l|7?Pl}F;,@_4XILERUb#!Iݼ7 |zߧ2$0^sipԩ!T`*C\꽪4*8lƪNsOYy| N? Gߒ d(><ޙ}KPNuZ-??sNfwĘ9WDͲCw iEʄxפ}1 d)x=;%@lvo@;ۈkTAO7nwbgԈM/@]-cv)gdKTX l4H7ֲ6 r[)19R}# TFʚZ ,}mP:C_h0p_>.Fx]c1'ŕ=ձ5-ƒB(ñ'8~ &ϟ2LftcĞ@y?U8p,lL/DJ?ܧM,WsSAbpvbm2E"{P;yV6 $AQNi[ #"TT⧪N6p@{W>j/5mK6W}2'kR롰!SFIaQH_6Z #&dZ?g@OLFcUIW} @Y.+ߖIUB3\Y4uNGbCICqGe(pgYMu21oJэpCpyulvG4[Ƹl`Ѷrn''D&ӿn-R#v8{*9{H  kKzx~ucjAU :ծ!UPQSQÙlg e:JڇHΡtc8ct؀tЭ vE+TG}q V|`ɹNRRRYܑެtUm jEфcq{>|!S4L[fs34q5*6u% BQ܅fHpfȞK׎[jŸ:rQ01ͦ~' ^^i f$㝓pcK u2_2K.hAZ}ޤq:UUb5Pθ ]_q$xm77?C7)*(I!M̉x*?0yN4|G>o2B 4PW^7Oqsyq8 {^T(A!aE /c0]B1{%F8bq['#H gOAO%2Ҕ/)gFG3F U`4> stream xX TW"ݯ#1g[ȼV}mݭuZARD [kܬda [;j7::t7˽o8y*vź5ÿ<6"t H8&zRS9=3_P#8I3EYyɒk;%׉EG^X)Z\"ɚ p1H,M],V,[1ۦo6[Rg;Z@7 f5(S("!w Ma*/c+:MNz -)mB0ƚb %oJXQZ @hj{:{w2p{?dHf![.'X- 7$(8D 4kGcg<ߏHdOky_ a|$vk=AXn*̱/tsޤllGJ2GD7v"T s9d]zR@Yu0M&ef4!:M Ӑ" 4ûǹ5Lxyc5ǜKi5NC_y&-Ԓ sWR502yy2:P!z`/~oJ"H j rk@E'-+ զLn $r3T CՑtdjRL)sh"﷠1DRf3NԐ0$IƝyi*{͢]+l;B"6Ρ>^Xqqŕ[(wFyi(¤$gu&-dTkk~4q&ePƈ}M5{v|'poЈMuL`qy`N':|.nh#2Xh*̇b>iAk˨QBĔ%g$tGggWhnQ(ԁKQ}Ǒ3d;y]=>\yԌ"YUx5W?VR/G4յ4[N Ex>ؘd%԰1Mfjy/}i.C-81:pֈ?]U*Xg(M7V=<)WS孫4Jʥ:k b`>ބ˫5%|z"C!HV:d܂Y1q֣riSUjX1VT9̓W$3TA㯠;)UFma04ƣ1 es0oziv}LϘML #'x/{3y0ߍ86;!gtS :rj0t:t)7@e:`C`W6A+_H FQ`78!8 iFE*[;e,-)K6/2XP:UDϹ M5\sc$4eCy?wb~!5)vci^A`i} *J[`:zu;S4DI.^ Q+Q>#Os˷|Yǚf2V`rjm2(C8sǖ͐1I0>9W{ g~Jn]`i}9h4M"CD:Ox NJtjPTO `͕]-vCwۨPk[[-O\+a>3$8j+|e_&{e3Y\Vϟav7-5Ux*LJfz%-4EaX4|T!:@K^p(T<?[إ,@~)@ Ipzp*/m{ݴ9c8(966DH R2YYSEYMm9i$%?ͅu>M;* r+n8Hݵ^9 E^.z|^xq\ ~ ZVdž-/!j"!(+u+k4AQeIeg/O/s᧖xmRu~ݕ"~KR'?b^{÷^#Icg[_,1BSWwa~r ȗOR櫃G50{?9Ch gLF LtwyZ[ѹ(r[mr4)ʪ5^wUEU'_ JC\:%Z.-z36d%i& ~ {Xܚp$rorCoA:ǜ'o[o3ȝ_!}p}_!}.<:+ԀR'گ qZԨ՗կ1ʹU ۦr e>i'n="T!/#wH=%ּRrj&{A4z[]6E&cQVuU" ~vO?; l9~XgU'Л[Ӟ/^6DΣw"PXP.˷i-x"d/=GOl2sA8P`2YH/ VhY5%TCZ/Y&Y,gߨ2( ]ʽ%؁D> stream x]WxWccE'"3NI^:I6M5T#Lu7Ŷ,Y-YG]{ma\0.tLa)!K.K⍳;6yy77ν?O1~11nqx͚x<, \T`J$LhnTlk:H }~_T_~9w~n;/;bdME)p0"p{nM03uᧄsGw2&T%TR'{AeR/8K`ݔ¯ie6UQ=Z0xX'k۶W!"Z43Bn,.V/zX|p.凎 a8gƓ/:kR77cqAjzn˱ogCF ]:5gѣ3/Kl "uw]&hLŞwJZkk\9`sQނe[?YphZEgrR2tx@;U}C/ ;k胏#aH#H',ly`7]@)H<Y,Ȣ-b AO/R]}pT LZcJ`k/Fujf aVKYNL_tJ Q ,&|;?'(8vUd_,Spj^B8{5c0ؐgϡGEw*WyD퓹&:U繽]~FׅҙVV^YZSYp U7}e+W ֧arH5(lFEo˱L"wjvZf-=jj+jjPZXoW͙[0)rSҬJ[LXv9g.67eɽ2)ƣ=l ЇwBJo{!x }yǃh BnfONϦ7~OQ&$׼ `q`ͳB.:ΙoVA+K}ʏ}:%=~>~sjBRzGu$(?9rQW~EQ6IBj)6I)Y}L )(%o/^SRkazٱ%']D 2ede"\ʾ"gY;I;)wiWFO5t򘍤wCN~^n~7YP }}r ϡ=2CJl0 `1Y?71HYz9#cR\iv``G>W%[GA]O5aQiS@gWa ؜GY$ vVa)[m߸Oxpd %3&ۖΎ|G)= lhqck{[DbKUd=ٞ2ֿ/Տ#z~K Z6ɴ%[/]ĞH婐wb3JF537Ü[X5.!?6Y()9 ?%y-[=b>7Ca$PVxW+חD'Np$$n[=PYYza4*1Rp)z)z$ Kɜ f6rs3rbp[z;]&DnD$~.NsIB|bM|ѽ{7te 'چb"SKɡe ;ŦaEtsOT05vN=)n¶~WV0ɤR[K(J  B;QYv2u"-W)4 *$D1nTj)#'%Y9}]=X OтvKGns.rBE^리$s?U NO!vHsa)9Y"1lOlZ!1هG9׋}BjՓV%i3Ӌ~6S{i˛X֤9 _Rƭu~ Q'wG)p4YM'3HvTTa\Jv)oF*õS**+TU}Y N4:76R_Cٷh!$!P\tVUWK6q֘ZIHAk**JX'ey>][Ə?xqwd_3 h:[jq1ZfKM!a N,jwc!Q]:6C͞<ڔ1!zםۅj[ _4{H~_F{P>O.ա|xjf-7D8`ʞ坳7nHvPpۈ(Dx\m۶mJծo~< Kffjr:FO.-[5T)Z @Ul,. R0y^ەm7bͤhͩ/~MgWVl 7.]>rnHx|P K=x ⁰v{y7n7po˸<>2~q|?1Pa#swODuJ0_2aB~8R~lǴCW&epl#9C,JQ筭޿'|,J\Y"_v\!LWe6ݝ_J E`&!!̒XqZO\##PUL[ 6rhMend d3"eR0drDZ8z^OWxmw5Z};'jT]VsI W+s;^rOi [`n]M㶺^d`z* sKY\]Zcc ?qfwQdey|%mSƘȷ5m M- w.[!(QkyE;;M^2[<K*N:<7L$mAendstream endobj 423 0 obj << /Filter /FlateDecode /Length 409 >> stream x]1n@C{B7ǀ1MҤ"i,(N/I'[l,Qqy 뵝esjZqsxfwԯ:W^w/=4\C6yJS񿟎(7kRٜ}RI<xb61}p(q"B{;w*c3RI<x2QvT+2`vȬ" ΐ3 ;CΠ+ 93 ΰ3ۀ]wS,.*,.*,.*,.*'XLP9B#G!4B0~xB#3232mԪ씶NmuzɽyeS-sendstream endobj 424 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 3412 >> stream xuW TSW>H3Z_UV[w|Q1" *IHKEPG+P2N,Lal{?Wxk֝Zg嬽MSc(_<e O m и1\Bo`ڄW):qԔ$1I ^[cw?EXzIɾ)2mkbc ٰ't5ZGIzj:LP3 T(M©TMͥ6Q_P(j>K}BZC-OϨEZj1Hj&Ib2tC1kr\XxI/lcf0V%>;},rJt<98z\и~|R.:5Ah/,ZoRSBS5YPO#GrA2ظ6;XQJQ{ Ej#i2(qJ"\9-N  a!L\يuߪ֗Wj+W GR a~Oz1AHު`9UbgLY|jd֚QnMhfEʢ=t_tKqn 01F>,gĂ3Lh׈QɩF$Yjsy<ċ,X}ףHƏ,ϭP5(xn[Ͻ3w\wa X"#9j4`bcK`*J5emwޟ|NM(m/7~|d/Վ2?p$ݔ {ǖ%ujZb :*,Pƈ+6D](tc' Q:yU͕+OvCf]-Eƒyyi3vMQ!N]T/jF^gozA2/-[s`kV ?-{]y4t髼tPwCGgnhQQKxLyhXWE! :I˱V oceHQ"7*ao^ʐU"Diu7Zk:wL5jjNB:rRo糳 ?jCz 2k"!_Leگ-PmB ||*ZJsL.0s풍6)! RLiΜwSW/ЪY\gˆ{1e'[Fy (+t7߂^9YoӰCtB~"C@E쏒$ aphQo,B%N}DS^X\t.F1>v`~@)zm3sD|nm '͋ ߃i<X@q uDa3|ŸtxZKwwzؒ0>'\Y-vx`uSL jFyJuzAfa&D%*SmWg$"*:UG^GݾA[IDt+FuooDr=RwdPs_%Nl(݂І(,v>k]4`Wp3o: n*6Mn}X='ݘYZ$#^Y=qQUyAe, c1(:鳇CgIiDJ63AaB3mtp{Ωd :p߹/._@/ЋFGd]wթ]{k+0S^~l3=gI)DmA!f9 kגo}Kaa]:w|+2{49g[ͭ3#<lb~)]: &3A++::B&y䗰Po;ǠXMlZ\B@vozџXއ٤vO|gVFMUT[I1mUdiJ5̈́ZeVW1xԠJj꾮X{&L\Zb36 ?Oa+5 ρ]ȱ@AћEA[^?׋z/h Mb҆P"aFVt;n{?y N wg(>Or9kR ^xQufF?ѯCCV@o@̏N=Ǎdendstream endobj 425 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 792 >> stream xmkHSa߳LvBƎE(u n*(W:3b"{Z4q]=BDDx[<Q(I(`)^`2MkIX|,WGR$% =LjҷHCQV:{+=vW]ENGiEFs!EF9hZ")4g)sJߍ#2WhJcJHHh$LGG}l{:V%y}=d/1>zFhqG_ގ3YQTqI F@tp@f[}%ħ_3J9v#A~g0v.TlY}UJaz gtUiD>qլ@X㸗\ {> stream x]N@s?`uO7+&{Y{{j-s|x\k}x/kN{|cU{e~{U?Vj O{9XS{{iLcDz[M󜫲Nam,^)KM'd XΥpf Y]Ѳ4b0=K@'FAx4X000455455455455j:t%HD1r1c,'rIh"6%Jtt ;a0"8#8"8#8zruѓ+gW4DD5   s΁!A!x#Z=f\z^u}t=x+ް'endstream endobj 427 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 5497 >> stream xX TS>a88rM֡j[#(Z- `@d 9;#!3"A%ZDvNjmklǷvXݷ[+a%$k}P>^@ 9xy3r? |]p/>Oa}G)/@<{EzjF,1kºĬ S&%%$&ۇE^"cePVp,'$vOy'nܙi)󞙿`=oR$jBRSifj:FmRTMER+9T5 VS!j zZGQ~G=F )JDP㩱#R4P6@wxwo#=~)cgs#֌Y5J80cvȊGmqn s=E>w?^_僧 .rGRTjl4I**{+&Zh9)#\Oњ}A4¥"Mڑ)PlEu- cL'(mBd!߱ʸLnߞA?w}A(mbT K\4^0DC N~s ڭbq`0Уx5 `iljn@/CGQ^x ǠZwpreNTpVBqlƍ"?sǍCnxހsĻ"O.7bޞ֞p \+Mr Dwv@$ʺpXϒ?*q r8џ; |V`eܵѼca·\^|p֕ ژ X\FǏs`ơ-8k;ѯy{@ls\bTkJ ׇ ơw( RwAAJ*4֭=˝WT-.t`0/ ӲϴZnɽ*<ԣp%^J^TrP5BE!!I]>K Iv_Gj i]XYASs\} !zD)~p)--@\!7рy\ě$\, [<書yu1(c1,V<|k\ZxAx%S\XD/ )7'J}JbEh`L8lɃ= ./-!ېȕ'vu8>P5ZYw)у;ܵl8V6YojLylR{vFwY[}핎\D+X}xw+N~q܌xUSfbfo+ NC,kAc{)uOq{~sXt0?ׅlKTi'bB;@|:ַ>Vr-Q Z,5hX.LezBW@P#VFZ򝮲6?u"Ɇׂ$ygw.[zYb;9U \C[QW %b%9rk܆sU n #"3م~?@1GOG/c&FC| u:Kt*$,Q1TtSq3a=!@B}_[&hԕ|iڌԯ)mb.ʡeN{?ITJ]OcTkcCA$ C34A3oo2Z dn )z߻{K7MkqϽt9g9g=.v6ky/oO%] O󩤒~|~\-*/jL> ]mqTUkceҷW7w6G[I/naFCS#):[ ヅsUkwۣ}}=X U&aCk=CALLVUՔ-nUf jv&#*Su V[\L|oI1EkAc  rUyn(XPZVm8m_e`]|V4 fѾ.?Zı=3`7VڤI0~2Cپdc~7¢쎖Cgt iDX/!ک`.DrRI&e4(=i;p| 7BV6!v2}vۜ8k͟kSMkRg 4ZбzNJ.LD$YWR3kb+2z2vel=t }^EA)qٓ8[UӸRMeŞR|\*^S&SvNyn'sC>Aƻbȅ͹jFg[hGdslf0Chm߇*`+jḘDȑbկUA6 Ϭ/~cqɏsXSꕠ n,lnolٗݞa&^u'+zFCpPjWYkmNNU5Kb5dU.#iP;jwvd9B;saP|>7 yib^ٵJG5+ڴ"3P .l04Zؿ B5M-ˀ{umm&{Zwx$3?D*@)亰ω&zl~_{̷ gf`MZrC}M Zy-g*53騸-lZOAIa ~%Ad0]IyξmVau[rmU⚧x:oƢ%uObj}d=+TVhO->]}C08be޻-V^fάNO??Dӕg~2gkĦB]eTJ0 EL,jJ5h7 7cM[H^3ոH}f X_%d8.k^"u'2`1Vk+ *Z2Ƹ%ʠߕ׈#Ju (&imawwO 2[R?'99(R"v/w@.6~>qp艃~m@/`j9~<~L vg87cI`a^鉸7N~Yİ;lJ[{uW~8 mhؐxuazr}}w-Ӡس`يaU)>kS7tӻ)R~NOVh־\d)2O:.j[pd J!$LfGڛzz:T_ڒmW0:|ܝ+#W/Ű1㭕KOQ㟾9_b {˻>%rڟd 7=?,b I(NQl$uG7H&mAy\Y އf_m0MFk5O\im@/{AC9ℹۍMylҷmaGW &%ed)!?GF\IO識/)̳Wxkwf L:}OLkub; vYl`W[uerzfY g-︩e\<{!hYR\X$Gj:ӞJQvMvuvƨFeN>2t4-?w-wTxF?ΏJ(՗J!du9;vee'>F3_xs-M'~ek/;bbᣧwnp0ф@Vt+LB6>Ό8G*$@E~GaMAɛ̃ՒS/q7NǩBW6 vqRӏD̼sY;$r.~}.&]ZH^.~Y\Wk uOV_V^n0K ~Lޛm<3"6V("f]iάI,sR,7S>EmMu8WQO89I%UQMlGGzW.=lendstream endobj 428 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 1372 >> stream xmS{LSW׶*$[&AtLbF3|\K^Himo 2^-N/fÒC2fN]b9Lss1er}ҔtE4anf~ q++k@!̝Is*nOS=9uzLSN2+,"^ U$3sV4==S󞑳 tl_uhh6 _Y.^\VV3ZL•ZM/pVbզR^^g4MY&sMIYJ6cb&W[Kt֢ vJz-3,\i E|ј.]dpt˵1 ԃ7DL]2Uz?LAPc3R8gv 3.H%fI4M{ן;/E_Ӄ< ʖVhO=4յ8; /dn-/e̷7G~y &FWGk}$W—5LiM,II`e)R.z{JAga+q x|{+ao# U $QjZ'AT*mP `> I L7\cH;^ 7TC|$hFyk-T9}>G(޾҅ |#dyJ P"QAg-ЪNxg?ؙD}vK ~p. ˇ&3*cxՕ^R ,F~M3㠽 oaeWب+_l-J4 9c%FO QgQ=-%2' _afxb x|UVCe,YŔ{nj|f I8"__,.kltH>$9IA$)AGW UPo{' kO ٷ䑠/x5-ohT558y&?Q.şݗs,%0Y6rT{y j%UQ&Y> stream xK6Gr&?h TfVKö0=hB~ݢCj`~3Kd׭$@8V%}([O>߶߿y}yq߽qDy/8~Ϸo^?7^cض˯oo}\߿-~*_~{"8ۿ>Uӭ\5o|117|;Q6}f:8iV/?}SAO bK<`5~wbq_~_1oK=>!]jͷ66~_?GS|?Hm3|vc;Jk&c!Z a?juS|z!{v㢰oS Ɯ_~?su\5orCVYuj/ tc`q]5ǗqcTow]>Ρt hƛqԏ~s0F'W Wg?3֮xv9d^ގ_8b`gQCBLA=0%9~ʡ1aĠ}lD}:&zCALb< coWw9Ƌ[j ݅JfP-cmbe9=qj? oqmɿը zz}sc25 ,U2434exc ?A0q1&XfXw̳x@8=?pD?~5i_Ʒ r9W=>x1ǺW06xp9OXBРKXBKz >f,Q w3|90c+AP l>qMPžn'K[.1 jedlڅ}Pd^y0Atl{{3']T\+ Mz2I*'#8H,T׹ҷP%fwxn UbzI|~eH|&z>O]Hoq [x}&HQ[ʹ_x4_&KmؤP`f_=N|%-[@,yc=Wq2v֗c:}y/[,xu,:>@)qO ˷=4QCbb.;dߞ?o5?Ў{p#K7qkdyo/+a\ *p6s9?/{x+8G/0~/-7tb,ƿpӧ.oKŸzley>x_z7{|۸Mcנoܸ)cEX ƀqѼ΅"d`0dg,)BpIZs7q-[3m&01qu55?.m 1֜,m6H& 2{?kX8ĝ@P[l<}0~1s,4CI='Y&1a2i;;|=*L" {' ǫ7~)p H9M_2KPL5\#Cx'z>'oƖ: o8CQ iOx(SǒVbʹp,!̅7-9g>~!8FH&5,K{hc9x5a0/^%Ÿc20H `L dcAX 0Ej-Yh;:?m1lɮ U%N0/aݗ)!F$姖)>k{9,?q[u}q&+c?alaxNK+^j}o0`Lī L:ks޵<}:H8>r go Ʒ]PuV=$RC+9 f؅a/}B!H iKnX56ؿgЈ9qܰann qݎa)qDH5~}#ERXk1xL«S̲ckyN56pOKCnRt:|KD3Gb_Tυs*NG83DoMLXӏX|(Z0DWo'w*9ۂ)<LS@;AO59uz_[Ѧ18"#>qYt8]p1sA4=Wp1 s {lsubPcD qq 9ֻ`( >#.X=8IA&U4'f '!z "0$Kӈ5}8N]p0Wf0>̟pH}X᱄D&Vv8O00'Mq'b0e̸jf[b2ަpװ i„+o5aw ;vcM X!-[{mrH2ŧIzs%΅("x::HC %Q 7@835iu [1UH 3XWa=gEb#F^f:ÿ+U"f}20Z(Xus|Ea8<ɮ :/J{aWaҵ AJq1+LH\9$Dxw' WAJB::|)\/"wG+av[( ""㩏Uօ↉zrH*#1:ɡč 1ZZsCˡwYU:avyXw I1q]\?E\<<?"0tRVdsglj.Y-61gG  u c+<"Nu20H mg2tnB*aZ˼:LF8to\1'WX0gp@m{l.d`Sk$pxXfzs,R19<'t|ݼ G] +₸V7}+Cr/+" K bqSr' 54cUlϋS#&117,3z,sdd).!aȀ֧C8u1eƻc(9<籞+:Tl&G#ޑߊ;Wp%ߓCz/'f<'FtRf*S@#R`bɵlj0Ng*.̚.'Ӓ"0%'QqTH9tao.ד1gِq;b \u2`ܘTssW83Sn0X@7`TZx*#yU]Q &޷ˆ-wͤxL)C%fÉ(9 cJ=$W[g3Nϻ1ȊK3:ʕ9ʭ.0e*` cGCaH zZ"<_ 8IDlyE6点P({;m!h`m )m2P@6U0E*]<&W[B#:r]hHkӁe <ؙk)C!,.>9Dŵ ̾/8<7ח:DiL-s\ѭ2b_{0[N)ƲnxġݕlzK-BZ&<4gp3L߮1pEFPD'}h0W$ C{cRR47CcJ{Mc82mM, Ex}C{bCKx-0}` (9=^橆UЇTx0&;p"Oa(ᤠz20La>co u U޿߯oWW8yHTD8˘`.3CRN.a10cS8;.CvpwT*✛3=`~r{?#bD.oyz2c1ܻ%_C"`!-OO\p!8EOwI07)Y1nq1e\cx'G6՚VZ'\9~DZH LgkMD|«:3ǟ+a6S=C#h| W~'fh2}@;T0U4$$ݺD3EC6* Vi)hguѲpH):1Q9*Sa8)9<籾Ĭ5:F @ 1.(p?QKª.Bq3p&9$l(M[n=9y`StBie^0̋ lgy%`<=_2>ol@2&Ţ?0` úPXosxqxbuCȩJ(21&aKceMk5-b5وiweܰ9$\dcLLI"9DkA604<:glb`1ULDª L_>Oy"orR\ N7L'h!Z$E-y7ɎJNGp71ߘFIa9L20Bpj8H?2I -La-yd{+UnԬlYi+6ƨLq[_8 ؖad|rWD{ZaX楅)RoqxCEEzV¶r+T̀L p ;O9p o%Q1Mq2&H595!۩qXQb B1SSǑbayv:UEqoCBDѧ9hp:Ba9uinH iZ⍂p1we^]>n;#hca z Fɰ@6U0E*-I yicdL[vSԸhCvN(@JAPVsx2F1UHTZXw{?mų0 I m FVB#+pn 'GR19<'ٞp_c\NY!+ָ uR87wE_6+EPp'z#ౝUK6%d8<_e`jmHX  LjZtl*Gxߪ@o#ON!;9D,SYdR x\iMm.[0W)h;e$#Ͼp0숀1G*cSFumja[XPjDqq`W{܌. ZWgrֽ WUdt}<'BqC5­8 R]&\0umAbl;(-T[ 0`;bw&H59u8 tכ?! 1D_h v0EZh S͠03?%FVt0Ej-Y/q^KbcX`cxeo,%?.פ=9 1sӺ" cH9Ǵ5U.}5tPXn"ӰJ0)|p0LaLc@q(dVq,8<ΗeCVv(8zcj3T8WJW~u8e=5Ô;1Ea;c ˆQH9uízQ.lfݿ01@hʿߝ NBX?@SEWaF|vϕú)l+kdõ ]BJ ` o`sJ4,F_oERc3?(%U [p9AŒ"99n 1O 3*Bct:5?Z#ԁ0!^JQ,QIRt) C@""G{L!)<~Th өq-]6a`iH&& #)+E%0N zE"{>LgJ _oSSXG1xa5@utpFmTA@犹Czї%Qha? 8ҏhp/nna̅ R @Ryrjow}PURm".VϪS^鐅p0u 2]CUYF:LJO\$B::cb߳WZn1NO;k)vf%j &9D 봴04<*cefac 1NVu5ixmǣ/2&Eao"sH2^o &!2ަzWX-4r_OG{(| (dVc8x>DB\Ls0L%[,7`e~͌ФbzSW?ejT1ZTwb.E[Bb6',!Lݦ}J&rorʽ"0̙X'W_o|eJLdg[d+Ύ06ĪoOWW R艈°( R3Q9F)0.RVlY5l*XwhvH̅uT`g Egg`lf́DᨬhGu}Gka kiyv|kwǁsʥ,7C 7%Lţ=eaJ9 `;IqI:ks;2mǗKUG'biaL[sO18H{ᐰʵM8 Tgš(q2J&Y SXKsxc=P)F"Nx*,+]G\&ؽP269$sVbK%ilL۝Npia kiy+ՁƐtvc]!VUjg6+Gu'XdbUSp1)␧n*aT Xr(=$ ]RD ÌUIKWx=oB_RX1{ԡCE-P6_}l&+lPkicPϿjN63&4so0RV xx3pWG=VarZ!`Yb /GI1tk =`F! H9Se!wJ؈<M" /7pye2a[ARgq,8 YmCk0H myN+l& #t7HۑE`:Q{ (y맿r2U~8.1iOc0E-y,~̮.Q{IO4Lj&G3S`b2q0e(΋%Rpuxİ)er(3-8@#0E-y}>%ygCۨLаmyM9<U w6H_oS)?gNueJv]V]ʘSvmQ]:j{gǞƸ8b2/><4]vؒvGăK\a"c%,e)DDb~v/w2j)Cɲ uA604<^[NLcCSQgab bOlm{St7L DjA,a)j=,isX/@Ϊ}ƹG 4E4jbN"(`+> qn tLYhl*DEvz킹z.>k[%}!h['% 5zYZ99e@q'lܪ[ն^Qֹumn,0EfKLű89Zudb:>>,GĜL`Y$d * #>8X0?9$kcZg9oZZZs*L6/G\k'vm4m,2.v'4׌Ѥ`p8 jr)7S~mˁ_ 5]A<5+ZymkL4E%M#B@Q8lc.UeS %h &{Q,03)aZXƻtX,ca CMhotq,,3\2axMLur{Q5Ǻv SΧ'o*3y):Ph/Ɠ9.j[`660 =M=H9>'w]t3zׄC =}!Yt*1WP)#NdzP2J!Kr5vګ7ϤgU15^\( WrRpY5\#|- ">T\qG!n&NL|?T 5Zԅ–|r0LX*AX8$x]erA0M"hr{a5csH8@(>ǗMY@6u0TuZs{ DJmPnF:v00L%0 (jJ[M̟mj TOEtࢽAtX8Dh6aYBscI4JfۑަH9Ǚw%;IЀUI#?p,hKȥ⢈ Z8 ,j4NmgZeϋ}``Z'{q%(QDNP*`!@AD*|R2%Vx^YsXd-?PT>)\1WE+*˯hL3}2ObC~vq.iAP9z tqugOUi[vު{⽻Xy&m ce(ZRW0eLC.,"jWXݽ=vT5UQgnno {gRJN)@>ʗ A}FG:T+Vą8Umb L-yx_#r` awD.17HP/Eke(aEe`M;N 5WgThQ`Σ À/Z\Iԭ!B]q踘Mc04<4a*6T:t7cbTx}@^|7]H&p~-祚X1յnPK Vg`(0iU0Rڌ&:Y"=t ɏ!@D&&z!. օZs.gQ^wcyz!me,YHjrCBR90c0b/3̎O _oSSHC3x`iCZ<<:.Ơ5E&XKMI־P(&?9$iIa,lǽ ZZs/n2!>nOLe+*ECg:)S)>“Æ()pH9lzJۡ&&vtYYJrH'MP/ZpH{k|=iznnLJssv!>.%Q2Nmh2?QGnvk2Ƿ( wosH"d2'I!X&-Z Xo@mG9~$mVBø7h;Zձy,89. >1Gj-"-U$4[z1㍫ Y0pT1NM=#u!Hfp=1ᴿߓYS]]SSXG3xb2B\!A'?Wͪ*aҮ;Œ^SQ'\֒C؋"Jmz}Rf Jk,.0nn,&V !R &\ۘpl3`ה@6u0ufn;"T(L\8ad ~+[p00n9c֓x^讚g]R x|̑͡8`Lq#!w.*_Zv q.;h7x`edMX$VC! \0.Lb eQ(U'{g("؛09$Lr! ¯)Rorjw;TUCz605Ro,Vfy'f6M l,b3$2ަH9MUX|. \0`+?Tu΁~s7EY@ Rǀ91"RXC3xa+rm5;va2@7]ޛ_z2{k mĪ֌. 2:F6y&`qL `@DkUcR $AmRúta&ZW~ڽ51 O> Cvτ.?GbPy(0ax-6HEyŖA60E&rkmu)C<1\ VB3Ua6E5R5:ze {z\(Rcqx1"TO.bdLcxз){,4)Eo@JP i/@6UTĺ@VK 75靘1+t۠*a}ULz`K7a/!n@x`TZx,L4rFY7+wLLg3A aG5ayiڱP"b~;j<1lZ-v0E-yhˆls9Vh Fxju{QWLM5ι 7O.ٖ k`W6l}^#"<x tTF{h4q&7l;˴Îzh-e~YIa-9N/wdxeCz)j2i:2FWAge h_o<$Q}\AԊvб)6;aL{q7 LYL *NRaf)Roqxc]XKǧ\73:t 0-kPV<^.XPNߊg)#nEϳi9NPzK-BZXvDZ&h82o!JաE˰PD}`2GI*Wá$7 㱴0E-y-oyx.QU߫͊6=al$<'E&>ljJd~)c;04$4Y\:!G'kR*Jb*9;GQh/K  I%`ZM[O׷x? {YцsN5cĩ:KmhasH14-LԵe SZZsaQߣu炸Bw8L:a4]F bj  xe'mÈ _z;XwO1 S ,Iq:CJ &Q\DlL:VßXo3?2t+{ 1g4,@Ҧby!X<,/ kO)i B{EDW)Rkpzq{{wyշsف炩;cW; gA8Emr0LLosEsPmTmja[nwѸyUJVs[/zjpȰ)Pl& 1Pr`&\婅)9<5p9sZ=<5NYtԙpw t(Mv, Smllxf X)<&eOmނԘn$+Z~7כ ׬Q%f_8$\f&<lgQdV"04<|ӗ"((v}W\8Fě~YW N黌҆7 ~{6/p#n +'_jc:#ᨼe(O>8t *u^F&eilDF'rB*s ORyit]⅙) SG{h& lvlw_%͘/+ ֓E-{a]0Pn;Q$7m `l=8gY ScP{rrF` GZ"<עkPTR[UMc§[*{pdS{f?ac*n8ɡ,`Ugo E-y ?n<#gĨITyn5hg 1E$):bꭀ|qwcdǺ0Do!\XՔ߸3^%aR}ḧxz+nJ8]* civ.әv%1eu{2G ?921=1F{wl)@2"aPP9Mvjwvf8犹/6=$buv$ED^0ȀĄTAċ)(c"I!-yh­ ^JY8TnK7;KIDJvi XN !GDdPyKGT.{}wr*DwSl|<LJa.CJ+<[ 7g&276TZ@urVXץv=^ޝ\es>kD43ݕp@#[mcHYl,do_~MLa9u՛U8^b@{L Nh6nǤٯOǘʰa"mja k)_CF-tdȵ8lm&PX:$LC8,fl W-Ƅa>xqƈ IA%cl{QQ*x[dSc Y5; #cлaW X20B0աx9D&13~-XY܍Ոe\1M; _USsT uMl5>eM-La-9Xz?5Z+֘^hQb82‘' FNwHLc/r3hlE)La9J퇚M0?cRE|^ؾp|[Ge9 |tM=Sa5J SXKsxqkxiZY.qR+{ç HJK2`)H**s|Q>>/oop]i, Řp<&n_l,5E>9%N ],~n=8}Y<8<1w͈SΌ4vYXjD)Nޛ $rXBC$u0E*M9x}*sA>Km }Yn8'FesIѻS;(< ˆ, 6Tbpb;)'ʭuڦȦQhNߔ$XMvui""#DJ:sVE5!Pp88[v9): 3EަH1#Ԅ>=*.O^bNV 掺.zJg]3_3&A >>ԟgbt`1,]Ð*La9 _h}'gu #^}Tyҕ-*knv DXƸq!L_o)+EdLEa!3ūYh: #XP,ʣϝsa x-&sN5L n=ϩ?g͜4Gi]#wc*oռ ]ve)`кpr4cA8FX Sjֱ}ROQgĠ~[Y,(EXXMqtFAMe?9l>" - lwDmP nLUUԻ =+lBQa\MK&.8N-֨RTZX'~Q#É轈Xq>C5A]FھSOv D-B ~V99u5.G E y$ʯ%ɟ%zHvϥ,u/Q6/ mTH?QSSbºvv)dm%sq5Rq݌V'bkb({qHtɿA:pqoja[[0F$vEcex:¶HC°VH7y(^H H.isx&qk`+h~.jUdӊ?+y,, K.RۄY2H$`f_p0vSp9l+>_EuW&椃m>:w hJٯ&9$+xbd`2STVR xSc59 b5ed)LRY]9^~}gL)9<=qeEd́[xೲ4V/v] }ɘaoj({sEka kiy?(q0jeiyJLEt~qNn]EA И} ]/z0"+MQAd`1Uš]GJ`8< s< N0c)`<,od}#Xo"9 4\W)㸜Gd-Lzs0\816Nq=,QDd ;O0E]*\w*bIQG `N{*_Mb݅vl7&A۬"QA,-k>EHؕmu7"BJ%I l::cIKOUuug(.X{?b!LQX39$C q횖Ai!R\#uw~1mc_QygQ /Ǥ9`LTcCz-2c&fX]>Ht~:wς-b%l}"{pqc΄Ms@vI頿[EN_.v?İn٥zPT^bkxMs1 HS)Aub$ۢۙF*JX-w,Ю6M.4=$8h6O ot^  8*js,e}T>M;ϋECgrWN_)C9T5aG,ԔAK0E-y߭AW%?*j|;2l5GJ](*"']}La/s8e~M-LzsOWKa*J7eQJwǻv'w^2:0]5$ozQzR΃welQqh<:7m qw&l@X J MvlD ,ۚU^aNLc0vrhMM~(E-o=բަsƿ +Cys͞SBaŝl)]q(tbWAj!RcS.$173rfi[NXfQEc]p٘wp*F2Ό"-S{8\yic߂AEo#PLX!p2EC^ Oe/smJ)9?s]&+֔_gr.>36k}|$bw YBvN9X:1c&onsܨgXgXpc ;#DѭymE>IrW智kc>'TͳrO T,qx|imR0E&ߪ`&);504$+bTY/JwlNe亰g}#fѰ6s!acVs0$CQԻ1m9h vmcE4(-ZA%簒 ":<>!aNӺ=uzz-OEI6vԕsUȐR3J9U̝;B]yQ2FE֓CVbd-La-9SO4ac |-PB UYږ6,eM90V+KQ0cO2̰$ S$xY^ (ͮGҢ<-b\Ga057´q)~2pBZ&9RĮEn=9 M r=6yPƆ wܬv;2Y 6~1K)耛 :1h=94,Z"<4aks ۱>|3~v/ԅC'ײ:ZZs/xޔ5Qԛ=~.J `yp:$c(;CǙ^-}$Oj!79|5G3+5ƻNjRČk֭촹1z B)[XXpZ,.g{# a_֫ E+O5O,nlf+ɏf\2aT`"QwD_sa m k331?@@AQ= #baS XcAd D"Ą" S`5`=mQXosxcZHSE`.@ pذYXCmIwrͤ/2;MZ(9׻+2јknܰ)p0e&vQ0׽ :1SKqj>&77ƁJ _[MvFKz, #$)G`210LMRa$)Roqxc5^\u"HeEĠi}tm kNW1[sn!#9`džCx%~#\-m9Eaȼv q8l m)9<hlu8yܐb ]}_ CM]CDqCʇkΖQ604< OתզvOb 77"o/v'flX)#Q9s-2`+8Q(2,:oY?ANw'#MEvNL8K6Ô˘7PUK8Q\$mJ::sAr]'#.-\0'>FLd҄aX'Ç=iz5}=O1]ia[Џް/;OrLpܿ{[ֱPUE?[$7%%2ka kiytA+$f;2༼GV/pz1=5:ɝm7C{^T ~~Dsڌ dQkºմP0N)#,e>zAˠ0E-y-FB*.q)sV.Z$ǽun(~Jra-5ndO6ś  ԑ"l $5Y07EP:af¢k˸U0 q 7i ,kG 3 4S&S|⻲wZ5"Z˰*#@ +麗@c`"drCs8{]YKh !<6EBH=Jb[H'淵|Js+-2#:k 3i#ƸbR/dH:cOwe&:P'H7v–Kٳ >OGZnGifG6gR6KWxzª:5Z} faЧQ6D$LM5x]: %ZMC`]̼;D>,8K̦\-M5lM"eHUh@2w=݊ёP!bH/¯6k?% UkP1$ _Ulj}02̭{7ir^xKp7;D9NBWgriGsfc kk2$ao'\=xGK 󉤧;?ސ&JcrxGXu{-ڌ7/p +c= fo {gξtYZ9'O'Jvi&Zǩi5"&u }Dq[}WHGZ*x6 {ä +HY^"N|ֱޖ >:kҜN?yumg"4W;q${X+%CDp :&TtXuF`cDK!=AtN~H㲾g]},'6quXPu8|Ou f|ac}V\@!a8MIq,5I-~j$[ݺm:Էn}W|xF}~=!X> TDU픞(OY5.?3EZQLՉwNqpd$?\{'Ɵt+N9[5ŘHr@CI m3WcI*LJ"UHhyb>5?/qr|:hkCkԯs~z:#\yYv&J[6|hdĻ>>26i7t8I˷iK/axȵݓm\[6j_oppnz|Ik HI3ҚKPyc9 UGT]t~Ʊ[c F_޻mQK6irWF\Pn m3>ԭ+0]p ~zy.:3wϛڨe֏bu2Bi+Xoz*"zچ8Cbv mY=Ǣ*c < Gɛ:-c&q it -@{vcE Li>s8-x=buoip65\?/e  Cx ~zx>zn9L(N;j䠑e)8ʮol36ضfo_GX>m:?xzݱ R5Ds3>Rsrlumތ:Ե1yt#[K+3Wl]cu صDhkO~Kc [gm3\ti${L[|Un;UBm Ddwz05hTwOw1wJ񁕸'v++N)q="Ӣ@vӐc[8{H,yUk0^D֚x'wx 94 N[yOc-orn M@v3!܍_+D Bǐ0^_qwX#zL\kExp(?Cw'^=)Vpv5M\ t|Ucp^* (᡽ڧ-Fj( My@#`zh)u'ob&Y\1STsA{W\:=CBdcszj| {tKEZ}4°ٮNֆUq!ȫړXM󎸼z?$\c&Z=>5ajd.o=c}v8aTIZ%u֦&WV>fSjh9-q?JxUz/>>]ASkчkf\IB]NOȡ !yp 1C:nː );ac/8Z:rՙxu(wͤby^\ 14`Ofccl+xgB%H`#orĸSJ M NnG oϝ3&Ʃkf.C|i'SIc[;dxv}swMo0]G=c$QOFǾ8O a$"`z>-i)%iwCQ6qޥ_Ƕ~;1a(Kh7 tOoGF^r*^fccWN,Ilgm#&)̩n GCfU¨_dJA*saUj"m ݫAm弁H}rwg^n3H8$8z]#Մ"yBkhi/dk瀊\2ϭ:)ﻎ?q?wxNBu 5DDk,aOS"Uk0\EpX9GFL!Zgeg5Z&MtQǑ}ti)rP)bF?M@^DRC@.` \7pd-fsqK)i->$FFNlgZ|<ƶ|fW~&`+X?B BŐ0^D-LvPd26sfOFD3Ow*5 15>?݌gǷ57-Qv u T;8̊t2zou3F"MPkImw6 D0::rؼ0␺qK9DhMsG{mm3r&f$B-G(WoEw==f(VE] ע".a#ge= 5B1-f ge\mFJykhu(N-C  P?=]BZH^⋽-Dn6h0}5H_寺] wx`})^xgj xw( 6O Cx w毠]w=c&z9f%Ӟ^{ȧ{1wO duzovC+*l~U<DN,ԙ\>Ũd{Jƚ}*{zE88$k7$ljr%67IP1>>^Oj1%LfҐZ̩ilJ#{lcȧIU[ K[ƟD &` ̊Uud p*KڱY͘A+.ȋ1' E-yStF7ۘ( > hf[D+K¤gR7RI=z23A;7! ԶpoDb/*?zmG5ޭac=WzѭaSzgb:lT#m洢˛$+оnccwvߝ:ޜiZ$u '\!`vگD̼O7(W 5dn&{Oav:UrOqˆxe '-ּTyd%%,8g7=Q(Jޱ^v':iw kblkfՀ*Xcs"Uo0^Gev&&fi6c3-c5$$8mx!THFGյZP{6b얀l*ZRY5򕪓@Yͩz?m^: 151cdBUfE .an7~wī`(tFN/FU3=R?]0k:fǡCB8tj(ڕ@ƫo23RdPVVgR"X.KWaUvmCBblkhP+f{*6-Qiif?nඝQFuG>oSgN3ׅ PէY.wx:0+ܝN=._(bմ(bZ: >4/jAኳ :s-~/{tc@ab|y wb=XKXVM@!aޜR#XjܔYQ,m.Ȼkc=f3qfhfv 2nX#GE .a^e1쏷G N1|ZKvԦi?s6 ulK/fbw #WרYtU@/?zF3aiz 괪D]ZyNϑ~+_c澌y%%l:Cxlf%zGx(1}ՙ$ÏNg%>;DRUBm L6PnWRE .aݒȴ6Oa޼oVar͒^ߏlp|.ڳmf4.`ѳ|lݟMQl_7iC LJ΢9J2e+4vU%ԙa]Tǧ ??UX?>^DDњ4U0RY,Hw*Ħk~ l¯Ok:fvgp 2 _†jUGgtS[ev~3 uB\sm==BX\NB8LptkXOWE Bː0^pgrHnGBc7gvO $u}}af3+V=xUK=去:vf6paYrVڲ@5>?L46 5|ZTD%|4G]QK=b鍴_cgeXEϒf҆CK@1RE Bː0^GZ3e.5<;(bB4-5B~ס]1è~cP^uϏV6}DߏytS 9A>I۷?FSI5 i3cp n6(+ሪK¯ւyFyEGit'uXhFqy,%ꍱs!Jm{xw:%tϊ`oJǧ6Ԉ\Z볤:,tQm ǘY!Mn8͔罥e$]>}Uc[ L&aDfC~=Ĭ309'f+ƞ fXΨJ`6c0Uq 5lkKZzI4i{Kf 0J,6 ݲw{<Aq%Ա-f!A*[ -Q6Enq%ý[]mNw_m^r83uO˪ VV秩P1$ѿ.{1n3?X["NboK*1l5h1>nps+X@B .aؘÏ j+˒ uzT6;Yhs{\uFs"^%Y6\P%F\8Ljw&uZa;⶧rynfxJ0dYL!Jc[B?1bu ȵDh_^|ܦ|n&I_lt/=Q(Fc=b{)k3OXL(>K(77>QUv %ĵgC_P+G:L@$m198|ޓdUρ<a>}8JDגX"ƟP!Bǐ0^_u,gC6k&N{?58'kgc,".#+ Uܣ=:M@!`f?QR|鷟12:!w\cOw4hH~ꌵňNkQeHcxlrϠ3@|BrQhņ]wqDbZbݑYgRncP'_2-*"vE]ѕ:_sJercSnv[F1V!^УC_w:1%]3Ȁm krce H}l6dxSS6KwHuJ wPxc%iƊ0*&Ǿ秛٬%=ʦEET]x%e x Ğ3ic7t)g01T$&ex6cB8+SUK/7* IMW{j.]f]Č r jhDK*^c!n#blkh,fvuT nF[jK[w{ .վ(3Zƹ.;ZgJg:JТⶄ(Qb||xjZeq;=èf35gڛN^qP|rc_65 {hcpCz:p&Ϗ%ZE7o?co'ks;;:u溌!$X?FAPDh=r滉4qfy1t#itmCo4->c8ٴl 0*8"4t?U_D Xuj(|~+v|GdVʐ=T?z|SR-%8jn6^tԡw%Pǝ7qΤxBl@[5r*"jW\yn4݌^RxJ2t=wx6K u{:5$d2}W-Z:w{\i[w7_MHH7y.#7fޱ.ڸ8zɏUm õDhi_82t22 ?h=R:O @m31XrwGcMBHml$k3D%vΝ g6Xj3/HIZ-c5=e)ɢ!L,ְ~E#.aܛUОh4K\Ѽj'"mі'hPWWy!?j3 VZ+5cYaiM@*@–VcK:T@!1:x+u%oodclcͨOi$Ա-^' ~Dp^NkX_֮E ~fLYsKL<>,)D2Z(4V(ΛTDU%OR:9Bx-AFzSXJQ9N(v,)b{0:[kTIʭ3)86EɌ:[tK3mnҥ[+)ޮ:ޢ?Q\5sP͑X}sCxq'?FU)7xi=L٭eb+Ʊ[)ձ[=3J~h]a }Ou-Qv uĹ|W߭|N:S$k~sD~{ز:>hvP D4nƼl. {]W"&`!w+1'W1L:mm|~(crē $pf6ϻw ס:T/JNjG5z~DYG2@:VJx-Q^Pǻ'יSY`]c:E Bː0^GWe-h7s4 3o5ri-r/j^ ^uN;1a!x.#f|췲q:*ƋCH*Hiu涇b79zocfK4ҊF#f"94b6OCxokע\% 3E+ȢYkD>C(s uGLHIvǽCxCL*tlu& ˣU?Zi㏕{GŘtB@ Sc^So|P%U@!a?Z(o=|o#\T\Hv-\cW8wPtX>J|<B] BU!K.af`~=>$Y3oSg4ˑ 8f̛շ"+e_PǑVgJHHHk5Cxps[֙b/+sN(uOz6qtPe_b "TϏЛ"P|!E]_UKTN%?˿zy[5>__OHK?e[?>?kFѨ1(rr3:('N\0`M}FBݲ}=B¨~ )~hax(6?MyZNKH=cf*[ƞZ:IkLl='}Y6gcFqH $ؖPwslƴ4(\X_&-(C2cC8*Q-]W QNns1VJ9;6V+5D(:7'H&y=uчL(XMce/:!3BwHC!a+L 7%xVکeVjC7bVZdY!A :Ҥ SZWr.)Qpr=oVI*YVVc{s:Z:YS%uְi2$u^8dVGfe}Ǐț<x#|ػ[|n8 m_2uuglGt/sIkOj6# vݎZKQo;|K|~m̐ ZkX>aJT@hƫCߘ ,ڥr~FLYvh H$q5 c&f`][YEjt%LO8cm$n(׻*wcJ$l 5!W4 1n1kIwb=2-CxkODɧs޿}J`bycvıuIІƳ}pʈ&":DU%y>I:]Pg]znÏ׹pD|^3Op?%| ]b'+iʻnlI %xox&# M Gُ屹_ߟ/]WVN$O" @f]}e!r|+?ϯ*OXy5w}3@Pmf^QJփbavy[֫3j7vUg:Ԥi{CCOa/|?,??)e2c{S kO(??$)9Κ/G)IǾ9,;PZr(PU,v(PPw(QkC;]f)_|nzwӿ&߰KI7ȇw͞i7TISa{MO<߅멨{b%/A>?bhb~{ttZīe';gAuEZ d ]Yb keKV:DqVm}/N<0bhhw.E+@ ٻ4 *F_6-~Ւ_Brf2+뎷T[*hu[a &&IWNJQJN2. רdZe[R傻2,oȸm4^Ll]v!O4rimt5H@2qZ y)Hru('Jo ƌ%nIE~4]l88˴ N` @ײ6?4%/emFޔ!~)4ʢS̈tO}_.N@15n5V($oj_ :h5xW[ }`SxL{{JgiVd{wŶMF MvN0bGjZ#TE6Hwz4 Gn-} :U=nղ"rxM],Pœp){u_/Tn{M%I<5froYk ݔ{Kɞ&Lbot|!ZټTr #CHүMHG^/ffwGdl?T4>4w]N?+I)T\wJnczEi9 KW}job$Q D" D%T7m@&A&AKW'ԋ^siRlMfC jF|*ϕdzX#ҽCL%7_ʿ,w J"})k){0 <*wlؽ3zmv,QY.ou.Q>6S~A%^kI7h :b@ &γ:j1QSRM|;>Ta(b.VR֨:Y%crỴ$.RkG05fAXkuYuϭP{-ǿ*i}E =&^Mx}w=_ ˭z7U-HZ@^RP֨9)Muze忿,h_Q2wڹDg=!Xybi fvpI慤$Fa1sȊ_PA c_tgW+[>qNI`跢T 96 cp!p5e09^$R.o-Y?]Z[TmlOV_{v]w *J.7 GIhJtс0+s)QQ.B!8Z1Bbk3Sӿk@gүS}"'d5Vai`Ky uZNyZ-emP P;z>#eO}.b]DE3,k!e(+3޷'&X,E%yfoœ G(D~[D'A jM\҈b4g3Y[#"Yzo gي (sk$3⾄W&JaPwsxCQEsA,%-K%(I l+k$xyסuޙ`d9kR,BI$DY?̝ ]= DV !c{+j7b5K-٩޴ʉvL>E@LR,R9 L!_y 9HZnM,b[^fH[iQY( +ֳYRjE-ٮ_5Amy},t=GSB$Q+&7nByȻKq(*sGm&MN P(ijROuhltEUPs !|.JX\ ʳDGi)Rv+I6kTÒ\QTɌ+Zn\m@աz*7yjFf쬉;g& '@w`"~J@wJ;iNc#7ș@W2_#mDp%oKK%!${)τ>%%ʟ?$(y|,ǿFSZ! U9K6ջib"ʨ!Y.n,K {S/m %hl9& & E .k6|s{7AdT]Ca"Aힶ>_|/@旖*:n뿲=e⭍[щd0ŧX٭3$|%|y%g Jj+ 9=)Zngɭ4PG]Ş>(f Z$K""]^g{8m;c%RB)A>jgTϵD)ٞV@3z[s.oc+G'ΰYΰ5x(q$(q$(qD8"yي_r4_13[$%qAQ>IxQkD}yVpRQRJ.i8O~(Fc CH." Ky,yYਫ਼\6h2hP4̏(GYk(b"rhk BvׂJ&@}+`E N`L ڜ(K/JR¤{Y)1-'_uY>+yTP{op81ױFɋZ2YrfhRu֔SM3(LYĩ(r#N"9-d.J-wn~!AVj/,$..G $E  E) { %rIzYѪe-u (ka!?γS" F !rYF,oڙ^$GdA$ox,.8ن|V\ vI2$ˌ)5n8Z提$ms9U<AU^ %9[]ʯi>[%T5žm oM/&b)Z܄QB&, S$n|"(CA J +9D^S 5W~#JGK-H |*^X&ќ$r8h.>s~n)E@>Zҡ$J:D )\S&irtћi1l}T{Ce>e>ٞuŝj%ے(w]Z4}Ǫ%JNu]HQF+$wM)(@"(RDW<jd⍿z@ iBd)Do! rkVn$mEg to/) 7 Jw,I5͜hi)Ҡ+& , ZݕUTN7}1.KF=V,v@nYgw٩QTl| Rࡺ;@ވbafD#b2^p%&T&M ._HYX XH X AM)/)/ڎVbipPAA.6SKY1/Aɛ>3o |4pYѿ(ymXZ2%Oq3C!xN# lJu.jŒ,H~BIk" &D"<Nf/P\PYeV^j6" B1o?Sm4Ih5$sEZT}ϲƚ_PYyp.X8c\@p. f3j8+ԒV]zԪ ["Qs:,T"wzY,`cNx6Ca,HNL-" $;z]z50<(?<])"ReBYRwFIY(vJVTqUl2",KՔ^lZ|"r"%>4덡nW36L.G9}1%Hk~V(y +5qުd]?\gs%芷߿\in-cj\W(VԔW\*^?x"EJ{EvDr1ʊtXEoQ߅G;r1屔|u; yD{ٜz2{$JDb/(%yUErX-KmMz8E+Ɋ'(rS\ю V>F+ Qh*vtޞVNP־yFICVԿ9(F'&T::ƪgFIN5gte,2*  J2YJ=;H~!pz3ϻ 5uc"K$z=`ӋWlZT(XT(TGwPk4 *DQ5e~ L(V猨E8gFp΄ZsfsfΙ O5RX(Vf(VgJVVwO%īV2eˊjaD~ DظDrI\-3!$9sS~*-Q Q,/88Q@UP]έ)jʋS"=~b@Y#ObT"_{l|Cee QmA]z,tMgVoKԹէ5!Db=,ַ^ W6 >-9Eøf;%*s9Bz|7b5K.ɾ1&i&Ezgﯮ}V%=2` `"H&j'>/sI<̲C~K+AejN zU[V(ZCdAQ3. ż*k7RP"yżDR3 WjJ{;s4/ ĺ 44D}G 3~巈bx6X:t؈bذ!@EB QPPpbI]L/(@9c bg "D)l{㔓p0!m HG Q,剬9& "EKFqu##9NmFҙfp>"hnu(, JffP7Q7Q2ώ&cQ]zEPHVd_@'׈\/u$ (R@Y<.Țイ4Ґ10]Q ZgXn# , LT~UE(Z<(Z<(V<( ( Qxjy\LmU(*Q{@@7wbmc 4}Y&ސ?S,pV5sɭ (E0@T{B$<M&k.%F@*~RR*ah{KTă"Hp#g;[i@SwQ(RQ V(R+J@>DTfC S('=H%(s=<<5woL1xb{ ы1Lb yH,7-XX!*(e"܎| %㹬Q曐kL/17sߒ[5% h7hF^j1k߰-,Iѽt~ѭt";)`F Ru?|,-,-QV(fAK Y!d3{^z1;AE`"4 #\] Я h7c[PY]3 UڌUQ_^sEP Qɟw"\Y҆,g.mnG6k#k#k#kk3Q3ijs( Qs88!8fWTr Xb1%DnLХ ׺c%ܕZ0ED?V(Ӎ(~(kBPQ|W_Sڥ).VMVb7Bh}auB4#nBr'KYchh8ŲQ/WW,9er$-%M37)E8XQu:zP{VNdahuf9hO)fGn_r9)u!ӣ&=k3X^]+;X CA&7_|X]OL%_(8H E #Pt:T!5;S͠r`j9cLw Y@jMj.?"p1QHW"EʈS}_ʏ"쑥H-Fn(E5-Ej5 {N^*~is)sT3\MV$]LVdERV5ty_H@$((%JV$N "d)n5~y0X=X] i"L%jAJd/mj@ Ķ\* MoD1g7ʺx']W_]xbړbo ycY1R-6pC]7WݚgZ5A-xfa#zlzp \ d #Y$Q,()!ŷ8i!ۜbF'PI]<|ԟ|/a,EX,dA Aж7! M¼DG(RJD,AQt?.ş DgP$(L0>xLLYi$;D (QXk" !21rrH'u!4z% ڄgH-GΧ(%5R5.e{t |ɊK@'A0{;%1LD&޷fX#hh2R~4s3f q5ܠNĄDIĂi~i݆(ֺi+{hһ˜k%i TRYڱEעv/59yQGX"[$E6?ҖEq#( EP$GV$D`E<-D/d|jPD(Dy`BʰzEV;Ed=fYv,wc!l?|;C8Zi>Ż^!vj1l1#Pge144!~j~,w2Ձ(HVCˏbɂD-Ad.ɑђ~ V2ؗ)#_.( Y}ƹGkRl ZC 5X@, V ˑ#Aa6B Ū%MbY=D/n"HVA3wQR(e }W(Vp(耂fWk_FKgǟBPigy=+5$o52"rbEv"f0T J'5qXXFh \7zA=]{&ұ((F΄(~Bs?4$,_@ZTU婾{o _wf(q5C1+BAjJ('W8N+=A1q@Qqn|"jR͑Qßm9P`N2fs! "9Vs-XQڧL/wÌwÄZ ,z7̢HZRQE+MԱ.~D*Asb1"ax.OPj`$w w+=(C!mB;w.\ڀ3!Q(f)^$͔g$T[[y,_g~IJcA1uŘ]$z-gAB@'"Wcx7N-(8AȞ,az!ȢL( >&+ $X.@Q\Q2, BQ]'H FEZeGO: ĈgɍjX"@1"nD&G a*@mj ceEbh 0‚,!e%z0v&x-ԶFe erڢKk"zȂIE,/ V A%)p{༌ \SQ 5=F +^ryκ$(cJǴӝ| f `2<{$ @S1_p].QA\l<#U"UϓͲu X:dEb%⨛H@! B}6 {"m}pEְ {PH%61 f"zbEƞq"-DEI y[2E3&E1r 궰)%ƌuOؚ{ּ,ٮk:7cb#mT)qAZ]%T֪rꢧE}EsȂĵFQrה\vA~ru9,J#="K`'/Q}APif:q!y,CHܖj1ސo]!!%QY=Gd4_qjh@.焉q BZ͎1;HٌJbɖۋG) *Q )2(d,FA#b#5qE{E;P,ҁ@Z,`Ϣ>uKDlEXl?bL ;Zvrfy.s5YƸZfmwR-hKbY zԫC&66E5ri֔vg+!GCMGյD&OEabD JamsG2/s"]) "dEV(Zl(bq#Ju۽ZEZ @iQ~xE,'/꽈(;JFB\;$NFZb{'" Ob'" ;QUOUDM3A<եv"O1~ѝf#:$keMlQ>/@EoՅ#y/kLEAIOu"b3s\ʍ-PryP'EnZ1@Eьړ'%3])G2B1",6D/ (ນ1X;Ƨ51PزkG({ (Ҍ\"bM]4bE$EȊhPA8ՎjmE9ŒJEEQ{RIIއ/6).y:o4QDY1^] y:."śNy/cx?rp:~}b"@aX$@P$*!$/"2,̥Q:/;fy Qj`OkR:9Eeɶ)jM6x4@-X&ԂjFq~Y/4b~9"fəA4D I|0 X6 (Fhub\ݜf"h.mjD1dXf7$EٍJzld'bv"(d=BBDJ#e2VEGb"HPؚ@EJ@*ʋ(E&Q]v"`"Q^"J W&]56i^( H'i@5Do3 AS'+WayQ?BHԁj (Agxo h.?HwdƦbI\;%(lw Ls"jlDҗv]FgD1@D.b|\]T!"!"!YTE* "Re]GP؏WE,QM#zoDQ(w$Q/ݮ`b0#e40,@%ǝ@%ߚX]uѝP^s{`8E98qEƹ (lbۨCB[a4@>@&;w+e+fOuc%]f]޳Fc%Fu# 'A1"hUfR0K@% Ni\DDDpX Q,مhOA-l"Q$"yKYgEX fSkC!1Q!-BZ@75&8#?H@@H@$qRrҺ&/6Izk<$JWwb0E-dˏ_UDtEJJyɂSAͥC3^5{HP;(:3+EZ; F!~by(iz~ lքh6n8@17Pl}iK噳5G2z;Ʋnr$.X䖀FT'om;;Q%($0O2C2zA%jaW]BR.+M\GD7EFa~X4[GVļIIaBց,@훽,ϖZMXQvn{O=O0W/IyJkh-S\u)xWW`EҡȢI.l9ec.*.*.*.ɊršsyX9:q1Ej,blcnD~`giJY% eYX*A@ VLPs!aĽ%#%FYpE1#4CM΋^N`W.xVC)3ٵ<+OtmG +0kIb鎈LMe, j 3'֕cQZ~D,"U -@?.G82F"z5d2/Q$SZzKik걙A)0%?5]Y((ޯhWgC@HBH'm%/'5AM£5YB(*(ZN(ZNVrňP):)'K/7;f\ EZo5V)Dȳ禠c*LA0@0}tDg -^~M5煔]Qf5a br,bQ_ J/Hldw( /QX}w^vOong:O -EQl=[ bn$7$BPĶ 4e e"Vh#@F>(X ~V]f^)Eʶ ,E^Dyg mG]O&=A($\ ך!Y:#wHBQpD-!^U,ԧYaaX] e u@$`0ߓp`)^%G=hr bˠX5(aCwQf(0$, 6 Y`Dad2hУ_ΑdD4"Bm?vȎ͟E$^qYֲN#?2fh/͂(B;)+3R%Q.jG(@@{ j|!,QRi@ѤfDD;KI!(LFeCe쩈bDf"dy2CTD1TR{'\4DEB"LpD-CP$IV$Kop]T#8gv1BDY@3AN_̗Sm3vY 0D0"$`b$`tA #(OVD.:I?D]ȂCGmbYD*:a jYָ 3QQ/$%>q>.܀b.v* ܀nEm;pH{bKDaf" Kmw9c')շ,%I5A<ENRz;ꕺME[c#6(iRAH0*0o09hJ(uE< ňwŸZ Yĭ   @-"ʳr=XVcud"(rB14NX{EZ3 f-ɱN@UPD2EE jQ/Db  *:ʋE[#uKGtb=Bȹ}Qd(ބQAH s#ɊU ꅭJ&NJ(cEY݊(Vx@VKY艝]AaTA@Q">؏(h "MQ rQ̪&laa K J<ʦĨ&H,wk."QZ D "\<1d[~b_(E }"ʏ,VLŠ7Edp9Id1rEE]ߋ"mv0zY(>C,4!$vVd bycDѰ&"{'CIPdj#ae*`9FOOQ,(Gd nL{tO,(;MQ;(v0!z 5P-e,(sw((@Px#U*Ycy Sso܎iT"T'vy}b (Q5XwksQ}DQQD1@>Qk.ǜVOAa   A5W"|Wt3өx\ɊtP,]b(Щ$zZTā"TTtA' 2zA@CݫIɤ:\ŻYt$( QY "8hԘ,)zVꮶYӹ'/oP>lFq0ň؊H +2b0T gSme"b/E8ɊiDQԨc_HH @$u]q_KA$և C!;m~"D25\XV8EZ w|M_}bE Eˈ"IEˀb_Yi:^BYXf'BYRuF}r.+~7zHPKJn{'kХq3^RS6tks쵓`vNF*!bEEÌ@zXE=,"fe1YIb\^eeO%q kHvOmF@^Ԯ@$yHV Tz$j#T3]B}(yg"Q+ϧ ES"ݗ"!\v}s2CPY t>kQzBQC&I(H"Q((h#;oVq&ixIۃi(# lYu]zb C{e)*C#Y9J!K^`3+V#m;y}JML|JML|JB|eH_/_nu"vzm{H=^տB/]wSٛ{ׅ)rxzY=ޮ /nGһ"r ~kߤ^HM|HN|HeB3[pPvwPCy_=}wD߻zC5z;8|zoz{(Na6'[S !VS_ȸԢw?N<*Roa;OHqS gf؇{CkC\!u{PonEfX{W5+Izz+qzhz :=4kWQC_H[ aU`}y a111O[ݺ }zuůc}S굹EjC;&LeZQR|2c6HEaRKLSd9^z <ނ+}s7\n9 'Gz (K^^Ro=$/Ro>ŋ_h_?xRopOO4SYs)rzQrzJA:%V"~7a? O Sm׋g(!:>|up{z{z{CY"5z7}ߛ*RY˟R,S ů\ǜ_}5_ZlRo[KKE%"lE)zCy""SGCzKU=^Go7{ZW|:^[b)~J=jޤ޲O^2/{|qo?JBo^_,Os/%iwC9:Tc.]s!EDS2J"u/p7ig_?/&PE{ۑ QJeRߙ اG)uC)f,}{oz}>->j~8MHBoGUoBRB&>^f޲zCy2o9̇K 薭s*}H WWꥦ?`AOW%&bǿt!u)! 3.AYq?Qv@E{S'Aj{T[}~rJRps'@\ʵ}ZŊ-yy [8w@.] WOf]ƿV9:%ұBXYnt)-NvΑ;DĉuΉ5kXg\kXW\-Z~D oIt %e)o{ݱCN|$! 9&eݳ"h6%vf \|ѭ i8?A"]z} xNΖ/og8,uo{'_(`&Ρ , *OwB4߷׍:l5ųz=#Z 7pZ|QдU }W _ev-,{׬or+]_9fx"霦㟾"%k ms"2_'KokCcdywn8G `h\Bb4Jd7+ m%qj4 g>55tc>i.8&7:쬈y938+Nfs#hw Hm)+cF`6THu _ tqEHn8^WSE1wdWv*:HBn?Q&n/wsq԰^Z;,X )a濮"mTLԆYV,1u'CiD4kkuO:aZ !*^:et|qT;2`:@c"O֡uXg I;cF+< .ƛ@xpk(6#EDt[J'cq D IX8?ɉ‚3s}bK b4 0]Æn44.Oo [:8A%:u#vl#}FQQAuPAi \? y`t{Fuy}x3gs:<>#I8gԺ{` ~0inL&nG|N-|EdT4 C%6UZi8?]nd}Nk}zLq+=)dq(߁C>p>Em񵲆i+̩qJ=i$1:c+#osОU߁7o>=:qYv["Ai8?O஡< +%oiC)p[Csً B!hW Gl0%f"ZCҴH,9B {!75C+\77/M<;rVm"L뜇>Y2DDACҰq~:'RqN6H%5H o+xodxx<"O4DKAh sP3aZ 'H[ac nxCkAZˀyoX#<8!nf[CҕiQ<6H%6n|W'xzp<93ee~c8'j5yv@j-g8)X<'z<96wN=ߍ.E\i{׫f8 UTZrVExi }鴖71t+"q@,zcOLߧ&׈s1f!MѮ i8?*5H >X>Z} Um5t*xO,,2Q QtVa+|bit 6H}/,a/nxݎ 8LD;r8c@8uW'%>%KM':9+J5# {a {i }ZĔ&*X%Yj߁s=B18.HDAWԐ4mĊ,  j˺ q~S>n56-|Q߁ÖR¹[{= ό_`65D`d~ޝM躀}ygi03~g.I|xoKCy4 ,cl}*wa u)a 'X-2 og&GhV @fr$* kYW`hR/ǟ5 *V0xռ pma1oݶsJӁCsJE ʄsl{%I.APT RRA шЉH eLgUE[b4bHBEi #áAja+ĉ:XCӽ>6z^A}G^%ZguBP)PNX".tCUn %8x66j:a%K,5$0*9;jRƦO`zr n(T߁S.وm#H:+=KsFw (&\oq-V^裕ªqWEUyq(_Μ$ I<$].1gBuڽ y C G+BZuU\ka߾p!Yfl-H+jK< Ӵ+iOFG&Dt"%wp!+N=:98D]WeqOI4U >m`:&;2++3?i%m*B#b2Q@-̿GT9X44eK mx+0MXa!ν ']V߷߳G{=xb/rrf0,|Q6}򋌌1H `:Dck\!nNe6D"%ejC7\m'Hբo Uhs*׫zQ!}}+0RS| .`Y n{p>T˘ q8k_ۧ[DE]"?[*z"Ld6׮,Mիwm=MJߑx"?8Htc"t&@9`[  ` (?_? Kp߇NOx\x9(/3-,{KGCa]A/]! ҨZ߃=8O;zJEZO6gFxD@S"FE$%O5󓜸(;t[p (25{y+_Ǣ.ax:vl'#f> p|9(09eƂo_ VO>H1JeU<FsvevVG73BjtMq1]DŶ]<|@.` h M(ʣ/'fl;r~syp9IijtUJlO IW5;Ѯ:袁6H%51>΋_9`bnQm9J:~Xqd%f"XA +:g4aE3z[=@(?P /ߝ79x(n0A=SǟEyBPtV.qJf) Lf4a㽹9ȉ 6s>f̔E`DA,HXE^3n}9AҺKKEko͌-U= aP)%i+S\HKҨݚO::=t19WR@n4j%71h؈)݆3"(Db -«/AE㢲S>( ) z.Z V. 4#t!%iiob?EJpGlmc#t']׋o`"dk&]Xi|\]994S׿kHZSPQkmTv/,a/}Qwa8Rp1 *$|'Ch% 4KK6H 9ah]zϨ`5&sǣrGD1M]A*>F:aN`A|o؅.a70CcP (Ga.9ˬvj`4=J;Ilkc8զ: >FrA?D,-5R:UTΣ xf] :QDߑ?_'zyҋֿ.:SKC+@a)bJ!5Rs3|RP *цyPLXD%v A:gBDj(8&vǾlKp߇aGō! 8&m .H8a+$wv~󸅴aisp3i4J%g*oWƠ:+#xQQXXUjde 73S$V Ӵ\i(%O6^^s8;rPN d/-X#9X935$]X9mc54YtP/,a/IH Y I ix w9#8i'}ĉ3#Ӵ[kulF D- }5r+~Ő/pl)zZ"C Iӄ.*5,NmJk*obL-xTn*B4-¹#'Ne)4+}rϱ / Ik2Ot)a/ᾏS1c_r8;sCc~D{' H14bsI`0i.&}Dz-]觋(:~{TG0⍭s^QaucM4 T3|ӽD- }!w)Vda] 1{ H'GYiלEmR[ ˟Dz-]؄@ރֈيA36 CHD'`$#Ri8?gEH8 D- }ܰ i7o릱~dIࢲj>nScy0$<፩_iȀ/+_.@)txn_va\V^TT@bܲ%*%yjH4iƖn&]]l#a"lβ?.bjZ\9;rvD $!}OE!!Ŗ8f帥!4PrZ#05Lp!KЭY>v{*scG9[PG1<bSLl2;Q H@HruSwI>II[yhb8*8ŦD=AhZ8?_{+k-.s;գ#l#ڄRZ1(݌adX#[D'kSwj4 jbE !5ijl0O2Vv4\@iQlw2gWkZ sh<$+,6PXC5ęc SUÓl{ ^X^Z})57z/ ξ'ﮓAo؆..-S"% -\ӆiEHwL>Hdoə(4DON$}o]CS擃rjxwsq~K}z#jά⒩31G<v^,:rQjTV3ۗ/-$pqj}gZ=^玉Z:c%xzd)т|Ox%@[ܱ2ғ!ʼn܎ 5Dj)iBb,]-{DLY 8q@A#gC}0t|A$"beCE^i$zxk(wR[ai\J?c}7 ^xa {i }% z.|Mo_b38č>|T7Ҹm"}% LÄ`bVА&H ',a'ᶋq D8*^IѴÑhYFSi. 2 HᾏXh4ilC;r]Rl: \u$](Ґ05uqp0۱ugLE # 8q,ߓF3S<5t:K&k@ei]^v }x ߢ\:,wA4f c -O=V)%`z_IjS[ C"%oicD_q4eQcٜ)Nr NDQ*/h$.ASD)%^ak0ٜiN=5C͙\^X">وvE)YOKA, U}PiېDiDձD5$(Q4%5ƼB9k pɗ«9CVe̡ݕW,qim멆jkYl>? KKiLjkup2x 5pH8hKOORdLy8^݀Gv,NK}[j6>`Yݚ%O-]4jHKpLu*0I J3qBֱ  ^C.nUSh1>M]+S9hÅjUݡh\qXt`T\+4/J\9%wn18"4ewY|C=8jjPP݄D/=dI"i-I#x Hw =>8OFt9/cs%i AzM_M͙i0ǻh H㻋 FQ}_T8MXh/II/88eHSCn$}k)BQjRs՘5z05PY18$,bNhB^\hN]AU7 NXNJ}yjD3<̍Q-$&o͜bm%$Ω;KAEfZ n]`=8- D݊@E,G&gAgx0?76V0!i qN_bj vEy!R~> \SJ6ՅEJl JTnS6HӰ1 g,/䟷& zDծᴱ;p "AڇfdAL~FI'5v b 6\ٽD- }ϨR"8߁SIp:+E]"4m`98v  ɓ Kp8FY7083W]ky8"ߑF50qciL?l`qא"ѝCiIJ%5s,xG;g3I Q> K1 5h#+k;QUs۽D- }K_ UQ$^m  8PF2H$Kh3 b )^KmxcW)3 {#gG')h/Mo<$ X ΄1]Tȵ Қ',a h>gz*z,`;gzQ;cxI(.qS B̗?[Ӈ }Y{s${ w4{"K9F5 OtI\Ohn`ܿt4[@Ll*Ѓ#ui%=ìPB]4ڳ!`>k0\96DiHuL@$ssb}aJQh%^Ji+QvV!Zg2Rp DHMaᲨ)9jB`ָbvرk⢚2Xg1Ґ ߝS9L65TMUӷ38bFvB;esQ![]c^:G [8$hcr,zt.X.j}*bBolrOZХ9º 4Ezfl tHN9jS Gn4;[<;k7CH$AE/ob,]Ƕ:O?*Q5m4So&wNM b: P59aZЃ HW+kCfbog);oPdM$L=,' 4p\*(/Kpň7a^7fGO/ٜLn߿r*#ՉΙC#rvoПa)Z+##mbo8c0RQ1ׅ0/OzrA9zc#Fܪ-aFY:QE]&8Ducm&Nw1E,H H?Wh.7MCHT00-V1htZ `Ba[x>}RuK\ bH|zi8[tPߺmqm[¾Iy%&7#L,uh$UXڕՁ3cأ3ݳD! VjHz29Zi]C86dXK{a {i }U;w9~6bʮvlϪҪ"ֶ MR=p8u-OyoOyqOw]}sУ%3jl;p֕npS2 %g<􅦩7XsI#% Hw 1Q$viR61zl j8 E[Ϯ!YUs]s  7/v˱ @4߁ >Vc*Ib_4iIsޥ :O!2_-?+Uhcv8̩Ӗ%ZM8fvnb$JLOXb4~tOz41V 킺bCs@e\Kʚ)$3xF\m5gbV8Do.Rp߂n8 i\SlBΜzq.?5- ;fӴ>rWȃy-x۟ -p,Fz# +\9JPA7`B+!!i %Vt^X^Z}Cp''3' `GQ28qpL 륆7H+mbK;!55w16 % P⏤{:4Xp;h\XuH^i0M2OaS {D- }p|v(]բW ;wU/M#.?B Z6bINaØ4htPBEJp8k+H;Z:'x31uc$ H[šfuOPkۑ w@' ,x ;Z*wONI CZOzHiu,Ei'}~}Kpw_aV-"-2saw"w$iѪI PuRY<ڜHqGk`I]&cc_{6upJF#N}a`䪞 4?KRp߂/vr ò-Dog4-_LiGJ0e9N656 )#i 6 Խ&@E/Ӯ7(F v . R܋D8ic%bP ?Y__΃d7@q`tZ- :\gq-z V9ktW!=%"LwL$ 6CܽD~1|-bvV'.2jr^/這t.A݀ j.oKM̀%iioU2 /4!'tΎHK#DwO:4v1N<=I,>,,!u^$@N[*NJ\y 2!9K!)k8 +9-eB<ۿ#-bžD #cRBSC'eę zK6D9þKp߇6*nsbp6Gՠ͖lozSԟKq""H)l4ܷD ;zH1J㙳NLU.EBpHdq`91]r4p~:JIA]8KEkobg-[0f&윍/ ܩe9!%N+q*Ox!K7AR4? 5&dbaԍsDc'[ BqINt]qi5=\Op b&Z|DIU4`6!YPYy6D+:A">FHzy;0V]r%NےFW]"o4Lθ~vxIYA7Qߝ.FhUکeSXWx LS].E xo:VY92p̮`reKBwe>NXmY9ĵߑsffԷjMZ0|[Mc I/hN D6ҽ>@ Q` h M_ke@F0q'b :)6Ĝ5X8D8H=Խ}~ҋH=}n*'L5ۍ#U%Jn Pó$)t @ :BO:)\4v p)m2cԥuHIh[ޕDmACғ68654MӕVpۄ ?NwP9i7TnKQ]ch$wB[bSQ̈+ `9&M_ Ѩp׭4{QfUv^ s#1`(eB´^1H0)5 0ȭ!ƽI5ai-oB 4qMyZ#GLhl]|8KKT1w I3qhjX'6D^DK}$sA{fآw}Z N5+ؒV 4.sӆӽD- }Z;/=q`ͥ[1f#]awQ cGR" Z_m!.Xѫg˶~Ҹ;tO闭)CoUsp~AYPkњ|Cq MjsY(l>GdI$t4qB$jj @CĈ2'j '%&$-X6)螪ӴLe e\ +%oic KxG%1LpYIvyb tʾei%%EiXG!) Oefi̸qosMGϕ%5$=sX5\Om0Rx>]&>E )Yv7gFaOTҢcEw .1.3'=;n"6>݆X)?8uxT.m7ڳ9X͑ &JBe]i@q9Pp7MX>Z}ʋϕ{qN!S'vGGHk'ђ=9hB*:MjZlkqlFN^X^Z}z%j^eepEҴreV!IG8b Φid$Kiه^lF9oNɑ)eXn֍t* $eaL ̪cP$Ą|n.9+"/q'h] bC%]<3]`}/!G".Jb/7MX`QBt47[ph+=.EC5i <]p+Mbf1%쟗wG%@BĴdDib`G( 1^4Pl7Jr Lޟb,SÀ]D:- M|W]$óH†֦&/kHZUUCʮ%N݆Kp߇%|C7/ah s1e#3w¡6֐{N3oLZÌ414}vyylk@ kTN>6jƛ[j0Mx(]CD_`4B4Lߟٺ3Nي~YAtuj;Y!Ze$oiøgϘbQ_gsV@T|_5K6ɏ^_7I{wQ#KHK {߼+(3Ɓ39&9+gOH#r*=KkHzYr-ѪH}n =Й9^Mi^`pAWQa;AHcD\D j .v΄\ 8}ng~"3央YG.6W zҚ&SSHk&3pV@D `Z D-럍S(&t99h'dDk8?$s 9s)$atk`y:}@(?dUj&^N^8ͣ}-I,ZK(ʮ!\) h 6H%ojهg Am(%늫ޤP#iEPEn d9Ҟ!fЂ[G4pӖspwǣOќ4|K$)j$U8wj+H&Tv eU&H>X>Z}֪ꁍgiQQxr]4 gfא,Q63z61{:l:a ;)]7^t̸0/j~9t?<퍏5I]ҧxtRj[qy%C{Mĵ>|]y͕mƳO;g's t}_\+!FIlq4%S.Ll m 8] KKkcM2HG~{Y7J2_BSl6}ry)DAC,ٮX12%l"ζ`~^_e%(_RRIY9VЮ/mH*FŞD~.k} aڵXu% Uů~-ݿbd SC'1:`nhP`(^H"}P?wG!¸]LEU2,6g':5,Ќ蚎A͸Ѳ(rPQcӆh@d[x87ƌ6-$ccrv>g9֛Dt!%0zXʒ&HoU]\a6w$rPDIw,>?IR𳋱7Rh"1|b8+=[ c2Mzחk8v>? I0ݞ iP?43ye7jjJ Y֦lnlAtӈp\OJ\O L83JR=C 菼D- }1dFd捖wOrjL"*:,gj0MXa1'n^X"><6s,16m317Xؒ85 PNcO_Կ!cտ;j qΪrzm&nUwNY؏w YhS*ߴQRi9w I!nrjbUw/$}QFi⼩!ϴaP!o$>=litN4F?@u` h]zVSB%>oD x8 T=5<9EC]Abb IkTr甝XPbu/{1>LTӰ EΉ\7624~rD\(Hwny`*]mí qGi݅޴|U%ƾC߁jG_Dl+IL)}y`65o~hp=m{a {i }RĞsZ79 -Rh5CbSCK`UcChJl M i+ĉ+R.6 }~ X~߁Sl m;3o17!<bK$*Bp ɪw9+1RzԮ\˅w8gPӷH\4. @"RP +"4 q_шTT(YEa$ԃ>^^bBK?iفp(%57@%^#Rj5!I 9йF^YD3g HIW &ήa*| Ҹ G+b@ۀI1Wȉ»N>;^O:*JFd@be8lcfhVl9|$9̜(-,]>XBjm#?a?G,F@{@Xy t͎ƛ#Qgٻ7p&V[FT7+&YkPl}1ҮAaʾx;roH D3>zO6va85/ep߄[JOvD#1GC`}+`(˦{"\LJTuАGf0Li%%5vq[RXuS⸛;PxQT ul;#C<@ǰ<ꙎuLH+R샄]&ơ7g=0Ag98 j;7e S4IEDaojtTL"WO;CJWO\}|\y6S(7O\0 ["ACҞt Bi^%w1^ *sC7P8 ]i3pcFZ-Dзٵ YsO5Dlf?o{?;7MN7m مTq/>KΌq]Z)H(mNԫ  HIj\ !ߡ-ΉŻhM#-02JDt DVpm3>,ӸD l Qm4M`93Z5>l&K\߃G4)u^)jJ;ejm>TeK EMVE f!<ĬNw4w1bM 68|rÙMmY0lQ]0+x%5^ka̱!i3%5ᢙ=y9GҼ[M)6rI4) GY5N}ӥyəOi sFlcnު=}}{5éۓ"G^2bu8pܮ>t䮠M>jv-8Wk~GM-z@@B%^|D hNF唩\^9* TϩJ,aᾉ[š/UEt2ierCJhV=v ef5 9,v ƪiX7U Kp=R ;qyQK+Zp!b%i`zlΙyL s⺍t%oiCa+y9i 'fBEDON.K2(0 X`r]ukB&H#E,`~܀^Q!oEW IS+v $q|S"204mnTp[1&Hw"',nS}DR߁9",˸@4x0%*Ri(81O@ܻn4nt Z!ꑼ,4LL $gSW(p3##S+ ) xl^g%~&ƪMZ߀-yQx61G2؜cgKpoBhvl=5~l}VW,b> :HI+m@K^4i 9< z1QW^bj}HAWpWFnjHU; 'ƙuQ'kPn Su5 gr8>5(X<9D- }B(LIj 4*JꌀY[$ ª]Cғg1;^X^Z}im! s`3\цix8C02 pj˰PE̜ ~Ѹ07BI n4nq8;2v]!ҋ [E#ܡ.N'GJ I,˶hi a'ᶋq19jAz\uܾƘѲ3Ckןf[isjh*d eP!`Z p52#v;rT9/s`2H4ϙӴ<9u [41vu>* XY8R'`M#r.Hv_/Nv(veR4M`9 |Ik)bD 4[Mhb,[$Fє>hHzQ69q<HVkQmFF^XBNZm`W.'B,(3T͎hVWQ(.4L('FFea4wOw4v7Ww8R}J՟#zUMr,%5$]}2Ai4^t*ÍDrMN19$dW\rͺA"4Ah19sҰD#mŏ^D- } 0F1J&ZVO#0g5L`A*% ~_sʺ2om"^r9 ,5D1 }~ G+#,N\ 87h .TTjhADT mӴ4w cy {a {i }u h;pEPgL<P?@ ȩ2m ћ4At,^K}cd&qq!1BO+s}US9iP,D_;C-S;144FzEr+5wv.Uk5l֣&'чPKG#i,/%L5tb޶+`l }~Rpۂkx`1d!`ErvMŭ#^tFW#,Q]Izr a :|k} /ҬZ@JqQL.zgG9q; DEQa Z6# ;G ѱB^D- }xO<6okt5kYN?ĕ0Tǚ4;{K=J`z2$9i_[7!:r v7qrO9A:ƞh ]"jZ USi- 3 ҆AnDM ?~?OJj`[U^`Nt:;,HT$^!jHKw#&kF yVpň.@ZT0pf쎯TuS"í'י\4Ng Cl߹z뜴ʦ6H͠@$-@^%[| 4@?n`tZY!e(C7Z+mC$76Y{_iC%=V72X }~ f1` }Mzü(U}b;އ6IH6orЏ?׿EYS,iAZm Yr-#:C>uZ`T-&U sFhhi/ lEv LTL>syշ +U lňL9:6 MZFG8Ԉ AϮ!iá&')!)iM KKkcΕBˈ#v3U (HԶOsdJDa5$ g`T|3 ;!55w0CN|`.q8QY%LU`!d,4m3w-+e^X">Ʀ51&b$&@z4F\* "cWD }k؄m["f G+B-KxCnB8e38G>(I++ D;:(H:cκbt&H+,` 㲣U r{CI׽bQ;waR(dLVs9Qz 6HM^X^Z}⡼b`QswŻCV$ ȫƪKK5$=+@53A YІ\>3m[<-;ͶۜWd.iX6K\WL=ppxE6|^X">KEAʡC,KGLN m;_lM'bZ m`| Z6&GliCI/R">>2vihۄAa\t"VV5ki<f1(0MX N;G!DFgͤVp߅vIhT7qY3d'b|H }ɹ*6/bܵI|>g^>8>^c n?1Oiu1kR5Ʋ~q]I%ԓq8峦D%57Gpj2ȿ6@9' C獝FU(%B kHzi39Lv &@NH>sMz*5gnѓspFv9(ǚԚcJ,NH*-_w^+l@I,.J&FpvHon׊!Nh @ hkF`]ڤ=k)a͵ҽqK\삹3k"qlmZDs纳Fo`oא!2yװ0W6HD^X^Z}Gc [m?p48&*m9?fXA(ka%]zיosƷ ppk!9p#? )<x7,)J"2*.*DQ1~ߌ)e_J-#!Z)0KV P's.GmWaIBDlH(QY*0%UvzY\DzY+5WI J3P!J}WZ%J)ߠ1.ELq"_PCI)W5=)a8GxkQE"=@5#E-bW@2nI0rMf8hhHרY$J[h{N`jQE"=vޞ+L~<{-a'/WNH Wt:>{OJOyy{J(QE[`iȶoCjfiOIj1EsfqļeEiPjVmqrofO8fc+\Mh}<=r% ͹TVU(bD6{:iqǕ`4W[!͙B|@NvRV KS0~aUʊQt,ޣ(JMq͌љӷ "mc:حZ&a4J;z_+&tK]fڍ](:_Cȃ{"7v#Gyʞ0 nZ,٫nUz%93S0n UBB9u8kVH5O.^rW;Ye%vC@2U=Tڙz%XcF wv椱:"ԍ?T ¹˨VxFf^={p,k秩sh:adMH(q!wT)`=tU"n %*j^xfF|n3fհS\qjpy:eQdZg:I'92{\- J[(17;#/*6bK;zHA\G t5dZ\ BT1[j\ni5+iW%wg wl7yҎ劧Cؓ*DU:%Q~)\Vq6DzeC7o,H"{q f0AyrNT CNx 8YEd Dk9+[I}zi-z CBiP{_si!_?QQCf`˒r=yJDa>$SOъ݀%Ȧ X\,=D֡ E{i ?KmvNy.I/)+7::Qj{.Y/劑n Vnyߟ[H% Ǒ}s-}ye Om<=.X'LEQ2(ﻯa),wwQ}UZ(\S4} ,ST2RXHF,J{/dPZ[*߿P|Ϟ?NZSZ8Ζ+ƻ!݃m=ϵgM¹SOJ;_+c㥄}G9ZD;%Ǒ/af6SfDm\y\T>'-xqōfn0 J{s/n<;X2zV  ɳ;xX,qpR^=euTۿ ɂ0gPV+^ X.(],[?(JDU;Glڏ(uE2I\"3ixCi:*"Ҏ>_LQ6L{V.ǤT !=grO-݂vte)?|_;[v8lig|<a%v-B6Gwa*QE"5<{GĻpkk>5LL WhhZ2SJ;_+i%gffkZD;%d,{\T◰`R8/c&qigy@$AYPE/j~ g]DV )5gx71 #ra3lVT9`!-׭3\Pޅ ٪,WQN QhVMjQUGn"#gںG|Zkqkzѹ*3a y[ݞҍR\StdPKXcM[(Z qmkEc|6R /;Pt@U~4sG.ڕ_/ٖL Wٗi܃0b-݈RӎȉϿn9.W PC3q})=g͗pM/5'*yt4Y:8B w3GBftஹ`4;'S~EO3cI( :⦖+[;[ͽ;XKǹ>reNr~9j)T/v CȗoT E"p\$<,s\KkKʣq.QH(_sL&GQN q<7?CMwtW d ש \ͣ;?ŸXhg^ sKE\[Ԍp p77YʸzoŘ> k:V#Σ>nĸ(QD{0A0UOQn3Q=g][ 1<-r.4gJq k-A|m-[f'$b *+9r%8WEF.:ߋA<I12mƒ Q\c0JcMz_8曙Wc "oZH u_[y/H/1.?҉%V?+mc_\,GUy dcY>L௺(5WPuN1 ؃Wft,#^b@brM>.Y0Gy^ql96`[Bmxy`EO\ Q٥v팗"^(E80A-|-9\^K3B Jz1ym/%\q[@X[.x}~_5Iuf)J5Qd!߸8gtsen }/Uº<ֶoR(Z q{`:4ػ/GZ\n,}2k{*>r%#?a o}!*DQHx_ ĸHYz_Ji`t7f/c~ dPх",) ^_7C(awv<73 fs¥o5r1;-zq_ "*a RB/QN qp,t@xm/㈃e'hFwxFΪQk@<;";f (W~V?~skENho\<38p[8bB6D\*E2:-o`D#ˣh{YjQUԳy;Ž#rƚ-ٻxl-ߟaEm2JCn XGϬb_rfL=ûyQ7RtӼ+lv? Sߎo{^ Jm\ُ+1pATW9* 37蕮#u(۞=l.Ǖ)!KzmuKQ5ΟGjvs|2+2/SLc>nk{*9hʴEYhU(bē7X3ݾ^ ԾzQ6^w&L5D`}FtaA-O+EBk>Ԣ E{ORMmס92B]X}-n[d ,A2GZpc<QN A+0I4J;zpK<"EY⥇h:D9BDN9z )ZdHP;ꢠ?Sw,\|(`%cR_⽕DH}?5/Nf'yFl{(\3Xv`4B Q͛"-SBio2U. ǻ{\(wJx# ^3 lUﷄ=d`rH#zm%QL 8^&%y;yǚ -LNu¨iG6#x# vtsFd(a,=k*@Q1C6릧S (rW mc KsX63xc#؋Ҏ.҃WfV AK_z(UsU9B_}|c FR{_كCj[3&r />ƒoeSZ;=$TJ+/LHJا̃>x E{~O0GF+A Ě\Vak3ʆt$BҮ!J IGPUz89h|0^ BB`Yh=v=g"l70>$Om[G`MDQ2G@Gd[Dv2zb(58=xtJ6Dl~Kv(W<4~>X~w~>UO;R-d9Ӗu }e&ӴY;ۦ1D9؂Pч",WEa(d x"wn8^ſ-;p^l/>mm8@"<,PY/ymOJ hX$,qf5%RBBDۙW_&wEPPd/=]dۭšDEUke,>9l9Nn!$7= 0!+W\G(Wsm?Qt,ޣx>uO*;[>kqW+kLn) zu2%=7;Al~ (9+sfC~3"JJ@:GL8ǚ):/lSZ: ØfB)(syNglg?+ ^$Xm8wOe ThQU3 6#Nu|MT\Y`,%أ'KI3dd| 9?$Dor%XRY(m?gATS{Of:NH_c D~Wy >EETS{%mQ;gm_}\1ȇ)ES~t,n w;KW/rpGeDT-SB3|xr/|.,W8U'/[3-EBm_k0?R(Z qײƨwU4pα7:Yݖgğ=Xga}iI_cOTh>fz+gƝUuX2l+MD'~d] JV/xy QT,ރc>/?+?=v<6v2d.bXN?3ZnqNv\[2 #%v!qe ZJ"10ޢEETS{ymmέ3ExTe9Jcy )_NJn 딼YGEH% \kQQ_hlre XJxF D^}mzlٍ0“!E4mU?>9wJxEG7{woRn$s^95FMpng3lgr%(Ǘl'TS{OŠ$\BUFs-W9^Joֻa{1RuҎ.<\kaHyw;MTS{ yHU.sdy=6ggQGi*g5lgy|+CjN3PUDnzZ*4=^ؤONTI{2oZۿIu̅=vt2 "Duԡ )=pfSKnUѴ{R+{#rzav/bT%vodEE~./*W !='EȌ}z؆`ӟ<>DMkﴜm[yĊH)jn <}D;ӎ]H% ׆yLz}ut k}eOuuLcߠ~Ƹze*GKFmE4):@ѱx"SƝr_N!n'5g`Y8݋=It0}9D9GJ#͋BVOv&f:fTs!Ϲ<^WʟTGUm]}!Yc omtz[m?K?c~ :f !鵲?3WVOd]{-aZ?1*e:oThz_ӷ9=!w_.erg4{ϏmCW O/Trf#8genW@5>Q'x^/Ǥۛ{016n?d}ӿc6r5\;;_^k7i/˾8E^Y'>}VPŏ'*PG~TwTBC ͲECNdZ1׆b#q2Z魿V_l؏T0-ngl+j;/(8#[#j^Ϭ8xq;K!Z"M^ٮzkX=@Yiuʸk(>.]l=NIt+]Y1A=ԐV hteuGʚbNX衮Z6bםt.՝G/M=Ce *Xn;bSm/Zaf`wn^p{(*Y<~+Pcf|C ޾^f3ۊ{k;ds_ߢvwcv{WӷX^yt{H<eR;5DsG=7M]fw"֤(=@]%w?/Bԩ5F 语 d8m_u+-m(pJhfz2)vhu}rrh[L=ԼEBz()t!a|ߤ Qg\1fwٙ=n^ŒrrȒp0#fO'GWcן8GeEƙ0f3:w=Ιm5fL7Y>:|12L=Avvw>EJuu8X,qzPn4;E(#߹wAy"5=>,qUyQ\`=ԴƆ+h19Ɋ~2{H98?_nvvF'*EĠ%֝^̖bE/3YS^J:)G=a8EP:5 G( rkd KXr6jڳPwQ[cSױGPڟA8)V]T߶틬ŘʞH2nu{O!>Htv?#k];4f){eݭKХiW5lev{84}MY{}qjK#R_У{8ܖ30[lqf`ݺ=nAL0, t:SW-^m4- Zl_;k7˥Ww(lۧ~SƃlN] tpj]݂"x8Pܿc >k(@Q)QP<,JնA8(PdA>9P`% duA8ꙆdAh,AMY/M%( &46Pd{ST7OG5#؛5'M!V/Tk&v-(]Ca 1'џs}vZG]pP($ lנ=aaqbVY`rƩ4K˞ |Vu AN ܘ" &-ͭNWlCG1;kG!XF[,CpP,v0p<:i[{rtbfelo{Qv c\j;;bx+űt$nbgEmÓ 3 .Xtv"싂1Eޟ8j;xv<<8$KS[Pz 7h / (:H5 t|q 8%z܃5p w_z|(c9H蝇b(FM^eOܗ5yySEe6WFQvJb1J^a#g9}PY-ZTغ3ٶ;KdVZ-.hقd}rٵ<cLF٧]3C`\`]ε\t ؗK)Cjw\g)kB'HtZò=<.e׀ zLQi{W7n/zc=c֜թ=<@ 3u;>%e'>+lO!R3qqD *jg h3(}'QQ$IYJ2y%5D!t! C՜C<9iG W<l @3b Fʞ7[u!xDǼgml @(S!v>Cv( MGz(w)vTj%KEQ#DGAa څ{tHQcb11h{I?|ªu5E<@2'SH{ [/Ei2j)JdFm)ܰ%Pc.qeNEs,g8*UB$aec@*SO(6g˲g;ahϾ˸8 Yy"s{z+wEJT_fYU;e?' k~+e%p> KA2ʚH/ <~ɩqNo>BSQ!Ե(1]z[%^-sV(FjҶV oxnp[Mg" (UF;T ҄{4 fJ<7xnpJ' B|2d]Xo& "MAUTCvR@dS-&ڕMo XhD%=MU.H 9ъksנQ}kZE `'GրAY}Pe\,@^C >hginFBg~P ^0~'d\1vYyta" `bf|5;lCa SٝYXa[5bn۰EG8oIt+d [}jP% s%M@3U*йg_;YHbޒ-8~c/17_a=WV+Ȏ3c$j ]A[Tbm]oĎ ױ&ӡ;ZE2 VT{`yFQD(QHe`&fiE)2z'PX`EY4l4Fep4׆n(Jh-8_QL%0WVLV"SwTAy UzE })>ô}BK׀|'9#'Prh4PV(,PeABA<,y1id zPgXɐQ3*IG#\ώ"-GgGώ%g&T>;:SQSOjE 5ߌ!}*h$MB?,1Z "s%/_9qf2Q[#E:^n"9(2(4~5@IX7JN(ρZj{ۣa ikP`255{RJLf " y(r̀ʉIs OEaM;\0s +.REDٞ7I_3m|;pWLk|0lqQAXC@TC~UE'*!HjwBPCgmLB 90ݐf 9z2 *ơA-%)![-ٜ{A14$  1=4B&EdB>A!U@{$bA  ! 3wt)ۀΨW͇}zٻt() \A <ߖ͵M>j+!u}*2y`#]>e "^@/@e/)K/ΩZqAP֛q@!8Spqt0(C`* >BH8~QTu(OtD2$nI7`XULNkًgO] ]`JQ &&JOI/S Ҽ?/GQm:[ @Q?EY}2{\"B>jt+D#de^u'LAeR|AA+;f@ R)ie aP:<յα=(g^A䩡,Mn'NDp\٠ÃյT7 5*Gz7Ap,i/=Ɉz_Ki}`&F56T{D+cȱcX_;f)p-p#RmE[8@LQBTRp ;*QJJAul`= V luy#n\ 4D:mOO'TQTd뺠u]@Ⱥޢu];T>uy$XES-M)q,fW]%)!4h bp]Pj V|gZܩ(T0+h9nEn@+`TQsB͉#MEO#YJ o@yDpt*JYqeIQ`S n!T΁5#ԸՂW@ UW%5.M>Z-C=} HKMHxqU_TDKN1V͚>b%Xo.Aūӥ; ϶oKzV)/7{ QYvn喛i:& f?=^9CͷØWYaQPsLIhꃆp7v݄0&hx%qnsV5͙~}\^ϰzp;1Ձy:Nݹ<3t%I@j@tԝܫ;e,o%pɲAwlM7O(<+Lϊ"۳ >JDػrtSR+ ۺ e`_Yj` j~x?ߞ{hX2`%h\3b##G e; IS$p8"4ڙ p["z")[TRD:b7ow[tDt{73Uru9 :˴Q.KAR@T- ? 8[9NRqb!/&͂1U1uɑ)gGN]XԅEOZY[NDZ=Hl@҈mםX@w"E$Yo(*xa PKpoa@;gv6@DYLW7iԃ0_J 3=`g_37Y <^ACPM&(&SeփAa8x=pvHd:9٢h2՝d#Emz S-TMqOĚy.rEa9BjAN PDSjQFםIv缡ֱևQ=Aa=AIG-16CTݏ4"PR@WY/QdnQhxIzb WpkQ7 P`uD#&*QuZVgũ:[{Oqn-Kn2MT­Q 7YJT nVg lowd٩'.R.Cv*ʉ jJSE>Q.Mզo ((QCt(,-pW'̻`Sĉh5QH4[5Ǫ1CAlUM+CƇCAu  dA)L<ć* "crFD HE8_Q` 1J'LO8 7(eMm4hҠ4EQQUJ(* 4ҠҠ:TTJZTTբҠԡUyҠҠz4J Ҡ*K"՚5EAE9 L-q@-yY o## G+d Y P\C4 b߾̤ fm$!4 M Cp[DFۻQ}@@Y (@ju::]"VtkwcDZ):H%#H?F!PÔu:Es#Bi@tçi;(+ lVWe"]w 1(`XF ;Üy:;uS@DC\.`U1^DwqM:GF{(- rI(u:(#ZQڃP$ mg͈Q(͈I+ț0jwFѰo ((C*̀O\J9 H_N ڣ v% %(t @uQ.4nJKr t @u\48%U\Ms 3 xT>I*GwLCE| * :p׻gs:$ I>IpԤ xx^0( ()Lk<Y ΕY*: rs,@}kV/ַ!Riz钐O#|"J9vx lE@A1^(@^( RzkP:z)UL,Zη_WPrsoPH0D(M2@PzTf^5mO- CJaC=j1PZsMPh+MSӎDPSATSQPS@`O~0Z:V ڊ*0YPSQ`yx 4B0U#JLՀ2,@9HhqmB78=#ڑ kTopvfӦ#}h% 9s)NJ Fݡ4R'@*v}t?dӧ`G)0_"W'I=`6:9=Ea!E9!MKE8K<ZF5" x@mEkd-؝ 3]Bu탰vh9Vi߬e6~LGQBi*X5{~q)\n_nrJEG'(Ea_C:ea<(XS`ME:_g~E T }ꖢ?NEQDܠI<zfR]* #:iyiD4S":uS$ ǷjDdkN6{l & t.h;l.LML}T}z(/pu7]e c(^#":k\@\YTŎZNp%R~dWSFps4,[T*j1qrɣC= fۡs$E٫&kk*N\Oqg]ɲt,7 j@{|q&jS I m 盠'ɺv.@MX_Y5+CN=j6!!PF0Z e\kN|C^gu]cI,ca&|/l8B+B Mڶ2Z-dfӭ^z "TIX(-nZ,8 Kwzl* @q7* *7*:ys<꛶ s&d)~@KzBc7< E/-wGHe$0S*ͱ.Qzk3`cc[%o=_ЗȗQ}.BQdQ=AQdMClqLzTKLX ``)R 9* RKAϛ$TUA xPaS=¦NQCdSsߖGQSCӁ,=)5vk0R<@-ݭ5~͞;T@ooQEPܡBwvHNNAS:DCu*(t<;PUCuN=JW)LULi(n ~~6wJ ( * (j\mo/ؔ UՍo3vK/{9aKџg[E٧ད vj\5/1՛Gȓ]Y|xCQ R$=%rS0m(Tqm^K}}Ӕkѽ2TG@mK 8`v=P O,cD;9Fg JzOMڠ:nE8-&mduܤ-ݤ^&me/v6(v6Uݤ:&mQ&mnPM ܤ &mzwhn/Sqʞv)UY "(l0LP "BI  [  $(PT"- Eq"(l JwDP؂P4Aa "BYJDP7E etm춊-z,UP*(i%|ЛnAT)(@BVQ\ S54/CR%8Dȯ.5?aET˂kT *NäJ 61(7:ֈ.7R)¼kWcvZ#^' ;f. cFe 4p{"xKxZ@w{/RvZ|3BnC-vCͮݓ%%%qCa_b7< m% h hN`fXK;ˣC94Z غX[ Z NK7n1hn0hnAOָT_* f{p- EuE٫[Z#^{ ȪEn9G~19j2?PE֪[}Ԍ8z@qFQTdqdIEQp iA| HlsrX鰢(:la LV^aE{n۸w=^rQYtZQ6Eo(B'qӢcdEy6( dDYO*T kv"\#9?tRPRҽ>|oL5 DEQdRzT*BT\ntw&' jSl'мTFH,A' G0FZQPP%zQ4 NƨU<E + p!zYQ _:4ZǃPKYПy !J4Az2Ec(akds(a(tu+ֳ i s0`O` V=) ixŞ&(L.!jAۢ !FQ=|GHQeΠmꌂ(wkk 1'8G)STEwL~IFIT1#U @@AEQ.=L@EAt%r>G,ɂbpAPT]QTP(;ICwaJ%JBb҂ 0o_ѭ!9;G(7);0Pi!Z.@(-\N>54 LIJ\APB<-l"9Q6Ȑ  Ll0*|;ykw!@,ы[%I^M8Uq}mJ3 fJ@4/iQfM0 ;( 9EG"E]hk="@ sBGP/'KYtp^J'z)R^TKn;ÂWz)9YnD57US*6t f6d*HAd DGU 2AVMQnA(t5XQ)QRHܦ^k^_e`}5F\Pg[4C}  E > >~`Qs-!GB5TK^Nv',z,Ri;|8tݰ?dp სM.ϊʚ(˴ߟ~|-ч="OEPm()(z@,xp3YnCE zAyx6p vfPQX kL)n^^1.BߡzOr0a5P'@w,*:RNr삠vE@tUB.R6TtA tFt&݂;'lOt{(&~<3DPϼ,a0OiA,(("Ň.*(T+( w*ExT~I/N~i9WvU:*)~n]l[RSu#MwŏׄzNi',-qI{g 0мn5xP! >#~*.qPfqm6UdB! C(pmJ'?$4x6H6#zDE (KD@'4+LQ'(VE@+X@@{!P C4(ЀhEQ>(h"Ͱ$ &#D@^ 7j7 >m}hUWET Tda)PՋ| bpZSHU>eXSeAOTn¤R-P.#Z:z+j,塾;NEֶ][BP(_,+rLըm2ׇc(oӵX="G(ZQD3OkVmKQ>5T-MCto:YxF2aλTnl/оNzPXWQ(*ۂxஎ *)SJeyE-0 4P^AQY^aY^AaY^*K(-˫(*˫wQ$O'㭁`oõFh %-hXs3s=6hB)d.?r Z),IWfH({*fB4Y&EXA*b Ik]~ؘ0cQSt+kQIAː/wZ #,H2,]AS<,޺%۶>2Zyn ;aӔ&Hߺn*>SW%3Pxd3MCwoWm2cċy"vn [lDsuvapSvO1|EJph2 6YQDZ ߦ#=IQlEѠ;+Zڌ8FgJO3SpHD3wش( q$@;s{|:9‡ P  ՋRTҰl!@yxz@g@6Y@!||L<_>_<_bل<l=f= O!MBiҦ"(bԽy*Eٟ*?iNa^Eyyu*:Iy=Z,:] F4)(=R^'X&XL/n4ٻ!9a, n7" )`B KXŶD%̩~6:ϣ1x3fVy$k=m>-Ӱ&n׭ t\@vX*A <[ؙ-":.@v?&^GͰv!X,b糃SY8-{9bW/:taףT&K#Ɛ euuMr2DΘcXcĔ_4Yani>ұDh$k|h:ݙ껻;U^=9JjǷ; LęԶC}i"#+9Q;g=&;B[A٥a1mn/mьw\(J +Ѩ, Tv*;A{( Y  ;E0KB1q(!oDZ""7p4SA>vNrjrjrj" Aa5"PQXMzj 0c,˧;X6;Ŕ1aخuQpȟs 2;ػl}N'jb(< rn@IU !Pz㟵o#(VC<@v $E{iu20K@( &e`5P*}fv )uۗ 9kr%#0E'CtZrD٢ :PsPKj6M:/e /!L0$/6Қ[~/ JN+p*rح6{nHu}+J)ER vEA;ڣ JjYJ :bV[ Oy5Rxrr_r-a 08S:lok_2Z%ZZ|U97E>#4a^&)ߝdN;Kh l%!Ʀ;P#*ơ{CDsi|E~Tilݏdg'L6`%'Du"St~;>a'@Q\ QW($ a`&\Q  ;]p@A8dA8 .!CWEI L<4(jCk]FIQPSAtd/3 dA1Q0][mz(KPKX`e P+`PrG) .=CNGoEЊ" Ea(FP4kE3BÔBVjNi1$JE3 5#JhZټ@1mp-A{}TlAo2R8{gJw*jw*w^M!;-ԕŕ@AՆkWy((* 5m4c֩pH~#YP$ IHmX1X]k!s V*(*u($OkQgj]h"J WS^E{(da޶"6A]GæQK&+EwڴGbS=_3?~""6A!a-)SOmQt$kM܊!GQ@} Á!FQD (U("_݉E08Fܷ -A0(!:@BtjniO=2zy v6(OE c6CwŋyEEQ>(vgs.N\@igr^3 Gҿ9a 3IbCbF46۩.ﴦ2FEIL%o]SGDϵ(r( \; "׎ȵ(p@Pe;FPGXsd2ഁ[/CQvXځ p( \;!8m@8mp懰Ǹ}:1l"(A! IP@ `U275LAP( S1n 7A/ ( f ;E aN! &آT/b䝠|X:UZ9+ <<8U@-=}Gy@QPT ƨ~@0ʨ ʨZP KR;E]T *U֠R71N( TQQŁJ}@TnEQ') J(N K@L(Ld|, قpP|a-Ig囼px2uD|޿S=lP IGlQpN1rqV/.ؠ(2vHT6ba6b+ k#k#UW=lu窇ʎo5W=lcRsS;|TRq_Ƴ]>-VzY8|q&6Z+=ȓ 屢鹚g>s|[l"jtw+osF< 7g|ڃg[3L5@Ѿ]<V5BQY =UMPhU#a%Ȥ(V-3+(}\ s!#(AwQ[sZ ZZ VEVUBaBjc$" (2|A`Ef/0(zl:d6 lP 燙Ė:" ,{UحE#p*8 EժuoZY#ӡQ-(Gw& A!V;dlkOk@9Rʛ}/}#z4q U ȩREQ )A<\?- HE*B@aF- HQ;FbÉHPU^*Py`IH٧xI^K6 J䢬&S1e>.h\"GŦ:z~Fٳ[Pl@zi4Bi(bdiɂ`PAQ"ȢQ%]ҬjRBg9ܻz(+bN^KRwj /uBm5GKy[*JJkxP1" )h}aӀ:REAED-Aq j /zlh",>ZC=蚥ß&G{ڗRſs_/*E텪eyɀd޻g~ طIVX>=Xo (-ضJpI4 xƂZǀrK+PRJ8W<IzV2urfFn;a.Bg߱\AҏrIM4mGCGTSmGT`HȀ̊F[n("12+ egv6JZvAƧYy)T[mj^#R2EA(DAp dg r^@ĭ( IQԞK|%+diQҠAA<@ PEy՝6*aq6M=>^>JU"DTSԬyAyHYw\^#f(V?mA0BJE=h"$et DDED DuB# 1jPUFT  !RޤK*J*CEaPz-*(-SJB 6Ŕ:gaD8* gE'11v/i:n(]AGtB|ʴ ]NCk؇*>T|RԮti_?1 fCj- d~*nKAj$xuS=6Or=q;RNnc#]ϫ4EQ_7(dBGꢨ[ܑI% k;9K]J7P८ڲ֨szkAP]7(n wf*TkCRXA*Hk$RiPw}eQ+ Mb im8Tn쳨 H_BM*H [ *wEֆ^Ib'P[HRoĢ>/(^^bMbbfxI[-7ﴎ.ajcNI@]ع#~Aō#ߵeF?%zKs/I[ӽPjT#NG[QR3 jKSQ~ HUPԌ-iF{t+JQyDjF)i('PUʈR*HjPPjPz^qE ǝ7bQ a5o[V}@P`L4'nBk>!,l#losdQ9> rͳ/c~xC[ǭz{vE=߂Fzk _ԎEҬ15*/-~R#jnPz7y@=ҌiM~.AG 4@[SNc?uGg >|v) gA $S?ÖzG*JGyt F)݇ÆL }'>\r!ǜz̟YKePX֖(Ab9&b Edދ?]#)媷҂5\z.f*.fPb*\eY/Ν?!b5j.},W 66hsf)xS_: iə>/BM#n_ͫEPH9Q [4ޞ:\AG6BL#l#glLo̶q_]LPɔ?ګj$q;*J_EK]=3KkxmgQAYwyc #JW/='Կ)-t/K["RZGܯD/sZ- ]^~)ۇr| kP]-u[G]V0q#$ZGT[_.Pװ۽ @]_賋o6{JxFmEV?gAca bOMlUqHlX*@UeS8QfE@ HuA ]:IğԀTy]KXE ~vZ)H]tEAD,!!TK=$VPtEiKWtiKW*xִ!lvlQT! 1 tC ` 5xV vkPݭM*GQeH \.N[w"`x~SoN' ۝fcR޾!B}4X?`@}'}Cc$Vv-oy]OeZAA"Nc8\uҦ;stpxho+yS;~yu (hݑaz,ï;p2of/ D w9}8\4L HW4'Fl?Ɨ)8끷\{N({N~8~辌kBh5A dHMD3} z< gqD0!z͐`-@'<d mf?P =O zk<< ?i\*otH^Dawt|L_tkc>?@icW"C߶Gإ/K/#ZQn#e^נÞi3X}5Mzmm>6^eBZζ۹/,fFAr^1xλ@ݿ.;G'o5:#E@ݷX&GPVӯK~=c>v#wX3޷ ~G|{e,c?lmꗯ?痉+o"q lP^}Q/ p E>#1^t^$u;}; t8;wJJX6Q)#B(I|sn[F4qO qE<a%Erx8"-( `vSwxf@m:0LK:W3m\U@LA(+x/foFcAh{O$7X/u/Xt}> eL-mxg޽HjJ)Ѧ~mkf4@UG-a-$ BRJLbg"˦>!SdA[6e+JtMD.E.dL3fGN6r{6@᭷_m34eJD^J\hy 6|϶VS 6܂mJ3(1;Ƣ[P!46ǽu\V%1+M)r`"Q.\|~XS pCk$C4r{D#cWj"y4Jn;Wpoq&D=΀?^vkދ1P(7(7$]~Y8]<Ы2_oP@i-oy>da>N<8Ӂܷ-ר. K;A_WGם=aVޭ$g6|-vz;o紷x88A[ rtQ u|"v~apkVz9XXNCen!PTqډ×)nldKXBAP (}#(Vix΂ИE S3M[q"aLtǚ'ThPU|[&|\NR~)U~z8\.2R3lsAJ#4rQ*[ T\yïc@$R(&-(LdCinF$H3k;Ug0  ֦ V oե%mT K]*] Hk3%iIi3iX) ,h-+E5kq\%k * 2=LKdTQJF23RgV ͊RP"_(#-1^ɹ*lԏR2PKFRL[H%͢TƠ4 QQs m=߿?s qQ(%rf?PS_(%Rb|RW:ghdm)M6vL$ڃ`:Fl%=KsoKz B,# Má?nCJ-/{~))HmR#sg({Vj̍ҨG~)i5%ևK{x<)eYQvYZj;i׽:HA@)J'td8/\ MQy?5>n(p(^/*.c0L9EV(s9s9()jP8 {` !ľE$ i(b_i0tRiQ3euPQL:{})Jxlo7(i5/liL 4#i/Y!@0Q'q}yڵEYL$fQbjś~pDֈ R$ɨ э AΗ uUP_f}/g< ӏmwUA^NHmalN}.>c$y9<د<7 l?c>5_rfS<U S93H9dDրڛ@087Esoi]v^R^Ǫ FkWY2\OK*H$ OzAttm"@<.3f BW@ЈI $ 웢fi5FT2BKɈR2KBɈz46"|DRfhn-XEGrbRB )yQ=/p R'ΣzգϨAGlG{mG{b'څmZCJLVdkͶMdCqej &'{6^iOٌ{ֹ9;X6_9~e@,^l˯,eT aACJs{ƫZDEyTjyhB5kگYAIa J%C-**U2U2TkuAPWP~wLmymk$n{^F=ڸX8y!kPq_?c??57ҏBHQCM6>Ϩ$7bT0qkqsuGk s(ߖyHDWTOkq*=aȝ~ŹHTbPc.܂.b/G@~j.NQ zvc& PP:(S1uoK[-s1 skKi&\kPխ[w@芠D˶OAE(if:[N@l{ ;A:D0W4 J téNM!PSZ(0@{36XVSՄ#vo+6EQ4(*Eeڒ2hQ= kʠPa2h]GC(Ϣ)[lgD5?U*O9UϢY9DG6H=#1ĵφ yzlc+Zv*x[=N絩؎Jk?8:W #P-E֖P:6c׷]\OTOFeELƓ=奟 Ss8@tgG˭ w6Φ(t VlQЯ` -ʦSΏ8)ziaLl]Bo^;!_Tz(oE[}ÊREGHh|XZí 4;hjz_!@|!|+ݰ | ~'ZX:XW:TV:cXU:XT:XSK*)O(MTPZO04étl-i>#] ҧSi"r<Mp*#K"h)"P[ g;Q 7ʚ3;u;z Pn_(4ŭdK3-bxoFRpKհlVM4bbd.~2TMϏxLQ[*HrU0u2-z@ILTPSJe>'u=QOQRj%Nv$ynFobFׁs}=əG 1QX z.k "8CtUQҎ QQ(F"9jD SEI< ~Ap~A<*(G\9*JQjģJ&!j:ۚT*PPi5T<o&X?eX~+ 'fK!Hpoف;MJ&JH ٰ()JQ*ˆ-~'~T[$59ÂE["B!z󋤅oMPdDe{xsgF)c B&! (UTx@Q*(-J5Ez(]Q+xU=@46XV(Tn"&;L,24;w-䦀mMrSHn(M>e(MaDM%))؂P BRjzN\_/M!BM5_\ j(A> \tơ߅%0 O%p) =PCw܀O<\>LyXn=Sns9S-j=RgQ*:&DVa/3zEl?8xKZ%F|sF"-D JI.<(1Z` 5t $A1|i+6ڀMS :"?L/Sl w'M_Qsp#f/~7JyN+>hQΩVBݶxh<*LΕuݲXih5ژ׾.yz{ <_縢K0RC'똃C#zAيޯ5ޱ=#bxgŀhgY?s7*W[!u^pӯ*~|_jw7k13\WZ%155{?ki X5`&NC(%<"y%ښ e 2xF` TT f ?Em2K(`%hQb(1 ȢE-JB ͺ@YhAV Z z'J+m8i@W8J A@ F)*U B" e*lHTR՟l?̠*DuB թJZ=R"RP)PZJIħv$j)QqxA.jfy{Y(pKmS>'ׯ% ֒TelIఱtlU0( fD v%7`c/F}zxWa׾..lPbs_O# /vX=E㋁Py,0J$qc u5]'J'r1=tŒJf~Q~ϸc}N: U#\xpWǎ 3渷g+;%s~se<]qۥ?7B [u>Krg07'B .>ׅ}M]Vَh-J!Ͱ-d0a75D:nso0q?ޖ(iho}g&.jt07Zw\L.=?iڑYMaGVKؑvdMeGV[ڑvdiʎ(:vdi8ّ!ؑ!ؑaD`;2:L(Y|DMMcSPhͦp 8EINrڳt),# zmVo=>KJ0L}&@9@D˺nVERn=RP,,mU? n4Zx[z!*$j> )*מkϢpɸ}xRtAp'lMV`@µ'FTS؂KRt [@Pu]CQAհF&C@l5 ]8" z/NoEׂ/ِ9AmP AH`$tD1r ` ,['\\5( 0=2?EjH<@ܿUq6E/{Oa@wKGNOߠR jk wu з$`vpgnuŌN; 浣WZ5P<#S#k/q> ཾ1!ANuG!Om{~D N%ت3PǞh8E5^J(u %1SuyN׋dkRh؂ He~ JѲq*n3iWPQz;A`[5Q!;v]: dhxyPTA=R@}/#p4R]'ky.hD[9lR@n!)Y0(UÖgY50(iX~ ݪ`P}-[%jغjj]PFCV_VWU/VTWnEbzΖ[0R( R( S pR(dA` tAH7c qmASk{8XH]sPhS|>yLD.J7d#X8_-e)98oys+J{'+H{2‘gTv? GGxʠz8/VRR #LKHqA߱/+ M x fT^ EQE:(ʤ)%-BD\Eƀe$=EFE.JEAwrg^3@>%wL! ʣq߻;+3z|w_7ywC>P>cMnK#5˩##g/g|hd4/ Omg4W9>+zzguYz&l_ZHLDZbt@\KY@\xu 5E)8G'uZq׺n{{-4[`[8zNjS7.pkmANet;/@5FaՏ8s_v(ꇥsy3ʀrIc_tp.}EzF:°#~H oqi3=9=SSCMZjE:DW-P̊Ŭ()-aD{k (ъ* @DF[,m(պ/PV:I(b1p) gp(Jt93"bR"^N!'9(DPsGyk+D5SD;'j[! L$*UhEP[Xk5yn/Ɖd!-81wV],"AHCAHJ]Q3m 3…b,>\ǻ%D-X*UK{eʶOy,[h|d70]u>?> u=J|#_N0ڮ$Ϗ^[CJ^Se`"$ir![$u>ſ-يz.]o5F;v>l?n Σ ~]vȹרoܽ.ѯ RAqA)a~{ǐZ$[ۯB9[Q*gC$ 6WaӷzFaZxMn[v%r:mIM7(PϑWBޫqhQ˞j=0u:(,P_MJ[hEtIfy.ҭ_Ņ5$.0N[|k NZk+ ے?DN9;.77E!C]Ԯs}n5*@ C r CoR1l鮨~Z( JixWTn- N'eҢyPKP[NSO~|EmUغ+X Q;9'5VX@)F$4H)m K~,5VX5w_oA,[LFE'm ݠOykqu>Q/碤[Ty*/w簗,LA(Ib@_c z)vnAm}#^VTy}n".ޢ$Q^";L-h)5VrD{É ;3ԱwC!õqU HUC nUhⵚNIiZB"">d Ԭ6aBGN;hQFBU*Vb SՃ8iMU=Q=Kq䧪Zգ'6M!Egj;s;9w!OEj,(֞MVScukr9a u^O/?2W8n.)Y\d:ʠAxLuFe:eKy<~F f]mpTIܚNغ(BOQ*-/zR6P( E=E=B"v!xe=EƕJNҊW.!+3`u6@4r!vYX#w0)O@ q>oW}[U2;5 5 P) #-[,(,Vk^9G <( /DX"ʁv?] @y}N}[O9:T yb|_ t>_h`3 H2g;3?uXyw~OwڒJ{_Q ;`V->]/^|?&h˧;~74|*(teM%zetKi Eں+X<F 6X[) vjS*v~ˇNnIGGlk|~!W'jø\jU k`A;(h ZP }??[hkb#NQߝA߭)EڒnnmIV7(1pwkK^%Yڒdnd.j$skKbDp" Fxe_WAA uY3I4-F(]{%]wu#ugOKhmU $^| U=WQkm-íPO{qa?tcmP6n궥Gr@)–OEF#e;?'ňxo:c#7=x ;Z '-<NQp ]}0Ix,5+\@6Ž7Ԉʐ'BzBwaR`zB-g[P#4>_e塮\(GT%- =1My LXo<8l~|$-o&of+ Z* qHa8ahiu% 8Zo&PU2UPOh`vҦg%ڌґIy h=YX^[A"T4C~ӸVr%O!QF,ymR3BZtיGlُlVs{-L()bHb@@sP>E}>phDhuYph,|tͧ{!b ZEIpDȬ(tW(ɣé|2 cD!9&RxY`ajc B] /[ 7'cVI-%)Т6떟>Ch!,J:-` ]Qq{$*F®(-R61ص ?ْgBLb8;r^iy<R:e\E#Ngl5ڸx:+jD"}ʰuӯT޷#\&դ P갇xq70c4nWD5}O{ [':eW5EV HTRPj 0!ThVaD1oS_:P-h̠X p ާwjq*LS4ELSt-i<4pWY&P c '(pxbE#GLňF8w<߲vo:~-f& 6];2v{gKȼJ3ߒ:їdƨ֭P8>6@E yAii wk}j&U6#>D3͍?K?0Ý^{;;m%YA7n\j\[2ħ Ĝt@]23C%E:`éSbKW;q)x|1k05=m4N_i܄QDHO"02޿%RSE,Gb%!ɳ8% (%TTTQꈒ_j $@H(I@EqphV%:$RC7%NcAqQ4cE) M[ɡE)Ԝ]:l48[܎Vp ɸ|$ЀBo-wvg@C$&75VUE: UXY][*Q-W[]-[sibX:pv#x=Q5֚Y73ZZg RGU:>=}ek E"РXZ[*_,-"z"ڂX;WhmTH@ϨRQԔvn˛z}T4*>%6W, ق.Jk#o/ ǹJh LjHE V/&tE+MF#Umr5j_g#L;[_7@X~T~h%B=O8^O'P,5@(|{e=ͧ/^4M"GLn/FD>&jEkѴWqdq6By㢎ߺ"_#c]# S˾~nkSUk1PN?{#XԨߖLW(8hmP_R$զwG٥%aJ=0i2?Ao;ĮK[a31 e|lPj6ۂbm}[Rl1=bm j ŖkJ-DR5Ϟ|kDz6fk$H[r{Yzl훎o4PxuO5j)>޿ioQOE=ƍsXH 3j?o'GDNQ[bq:NԊc.:os^EBu:cX֠!4EI񼳍HR.--]s8Cdj J3Bԍ(V)t* mBSݪ([o핖ڼqW!h_UWV{ST;Sq="Tg8TB_ǣZČ^rBmt_-(IhDP0tB=]~-ڭr\B'COO%4DcSqE= S_C!GĹH#B soizHrz"wy@zB<cIz<䃌+hʳp'sLN@$`f/OK Ugρ<{Wl'.P8.Om{m'(ط*,_K>o}+4:ns6/huIt\yenD5.EH9QX,L.~]b&&dM z#@'/@/M;%|4( Fm!lw_Y^mew7dtkow{dd.1us Yi }L;}xl޺7Ǫt˵ߐ[..bљR;y9]e! usNϷᄊ[Ip+Yn%ҭ$ʭ$>9Oo%:KLt. [NtĒ 'Lm?XOool p"V$ ߾(>%V>FTwBY QFM? YD,yK(U>g<q%rG'MLpH~BMLMfL,.@U,H&8+-cįˮeDOO@4i~N;oيGLi_C?` 0غmbFd5b`rj }/|#^zq*tnkBp谱._??O,A/fE<Pu!]ks@~WOϲ@Q|+J^/1E LUVm J{ыZ6^`@ldFerk~&$SPx OA$U$#&BJTMIJV*RAS> xB AiV)H% 8-~5&J!b(ER(@wBOTK] m`6@K)H C 2S^ej-M{;SPۤ \vq^\׏x緻Fw:zw|O> [)Jz8(tALIB+bG#UN\˛'#Й1ω\ۜptK)79"G冦~F~`t;#f4_tq7SC5e$J>/wW7E*^H@'%@Q" m /#0>bni||% `49p Xˠ U&I:D?,hBin|!/k >nd孺&S[ecpA ;j+^2:Av#^mm,mF>H[.CQr=?nYxre6zj9:#(ѻj ]Т*31A_MPf%vl-PזB_ɯ_^ggeT[y'KB''j3P{Jz/~l)soA'jn r@QS{wԖzw/-;zwԖzwU%4=:|zwջ 5;jbhD{w#6kS}?5J1PqY*.SmIT\b89!VsB Td0beQW U|M"tׁ1'Ĝ D[s\}bS80;9cw"uDC*ߦrH4>^ y.wbr|?FfFg%& 6HA3!~&¸^S!a݅c㭝#'D=߰/T%zڶٿjmRю8{YOA~=ykB}"nbMg|ѿ~mbwj|W^(qMVmߜR'OC$}oїqO sQ<֖u.ay~/r߫eDE%;2RÍΗ#R#BO3-qP7E=DZk;ӊz1M)oqsMMAA].s2r:\K2&\ Z3]Jg}-N,A8>pPg+tUp1k)o}{3|{37OZ/[P;; ;ٔxf}3w<3w< E_M(_"h~{-_ _"h\͙-$AUVY@* Ze}Bɠ֬U H<( UݳBhC@W<{@ITO]zmIJU >QcP( dgXB}(,>RTẔ5"C1"CRu(GLgQ숪ĚAE'(\F4lžD JV R9^WɁpFVNt11w4=!/PK0k0Y2'{~֥V`F" pH' BΠqSAT;7l[AFגŦAizQj(ʖZ7#,zzi,V?;Wi:/u`W NkuY ^:TPl3X[j3@;6jFxa#f뗚f*PaK- ,lJJ}3JXY83N-K8T8-g3P8 8/KYTzs[Eف Flu !lsدuʍ_{.-KVvaIEՂܞ跨ZP{_}mo_9%*SQS;:Ϗ8֠붷 e[Rmj wxژ#}}ymwI#n?/Grwd;(ZwdT_q5,!GGTCք9_5e{o5,ݶI>/BYT?! (';2ŵF,5@˂-J :jlfLLB [(-) " s Gl23*Iwv%I#DD[T3%m.3m% B#/:fkQ̖8áqp2gW袔.J袔ƈiC<5C(婋R(䩋R(U@n#"swQyu$x$D5^&' An(,JAQ=(ugPlG{QJ+2쁨&' >)5Kh٧ Cj)GԺqhSO?;: =މ{Tj'|*FZsOvto, }ɇح - BT$N$,s#47]{ObL>z zm!wkK;`sS:rƁryʙzҩ({ҹ(iҡ(X0"5RQ9/m/m34+z BMP<`Dppt4BG {R+XB'M-L3 1IUÅ K-YJS,&`ELWSXdMT3ũegAh_lFyS{o:?׶w2}dK[>xEi/v}Eྲྀp{ ZG.oGUcT{22^M:ydkWwvòQ]:5o;cFI(su oPۨ<zDt%:~xyͣzob9\@+J48 B$[? D;`y:=/U֦(/@E[* Pu^A0(КRahWahåТT泏ϠTUYU)T%B3*C Reh@hΘw:z$7?Su(C LJ׎x@Fx&PJ>Vu_­!t8o~O\Q#n٘mm7EHߨOTABOOAq}R E!>{҈qOd,`&R|㝯RƗ_[I8eV>6Nߚ F{S7E{C[_1a{(W`KEmh&(iC{0a` @AV l0M@D("iԙXQٮ$vo!VdҀNZPju ԊZZQj{gDx_u6l5%}65ڒm}ʯ"5Dv00P`+Jj{&ĿmOP>P_Hu+xB p%T[`t@soY,O%˥p`}B\ A 'BʙoWB7EA Rm-KK6\r'$}_HT[v}f{C.A"$^k?F~t9g"iXzS+:5=&]-Y.(5Ѕ(TAc8:T\9`'ddl(5>_j|Xn܀jî?5> jRKzݤ YϮQVZ]Y(ݽ~rf "EID#}ߓ#Џ-Jʟ@AXςGܒYmpIxOU}P }P4E}n.gq;?#[AbH",'k rҵ9iXtMEN$ (E ][jMS[rҜIyIcv 'PrtA@N m kT ˌ#?Z~jBI* B'T|OHd4>)ܳSrO}=Gzj Zɇ_߷Ầkco/T96ojzQ˾ɹ?Cj [ȗuk1~:uɔM,[ r%"'FܿU>ؗ뾭uAdN[ 4E ]#{ᄦ Gwoֶunȗm :Bx :?Y|Ο~3rR+^=sPpxCF.kدB˦m݆qSn` 10A!Gm/Ӟ:* kŒAݝx38H1ESh1e5΃C?1 ';c`D)J ZVpdB_u05KuR&UZNO(%vM_-kJrd55y-\=G PT@U hR*9/ޟ[8ۂMR45WCnAB f8OO d 1DE=#B= `? VE` PvkVK*23YoA,H= Q9b NZ:<$'Z*gAr"ȗWl]fB(W&@`i"`iOe$P}ɦE 'Pؼ@GPlQ[-[yڼ)\)p16Qh LjA6}>Ԃ-m//|tw$nK e|_9Ȃ^jt ]}߄tGz@ܼu%f="nKqFm_ע0 (|R4P[c_*fTSEڿcگͧ[۬u,T[a]9[P:jY*( Ѣ4(QB(QBhQ**#؂QLT8ѢP0  FR\["Zm5ۏsՍ(M52,Q$|Kʼ*m."J UVs?'g,I3YP95ߐ@0g}\;]8Y`I(-"j(W!P* AY{ R1"9E'E%iPrDkK$50Wi} B<ѢD)yYo ͢DX(JDX( @E(JT2( ,FkfRYp TJET*P"`KE(H0*p~y&Ao315oMjN013H:czN@:7p:N%tOhiEq^ J9@(' ٚ/ێD (v%)u%%u%%u%%u%zj j붿TK4IԾUAA] 79zP/ 3A' BKMo֊B$[{LĤ)JL)0iG Eđ-IäA%Y,LU-(0iq(0i<׹+V[^S>G@IՒ_) 7(#봶=шE$ad l}jlG\mw(J+>( ZP^- i)FoO%ٵw$M̈|;}׎u>D1-ޱ9J\ȩ& R !uIwt׌r #"€s&~DϜr '+ |?b2gxL?czqK&a,3:B.5Josy["9~YS-6adk^i4*z^FR>Fvp Q8}u5`=ck3ӷ4q]| y;aqvpGyg:P8íd8R\UBJJY G% 6ؒFlA~Ie THD#%5lAA~r D 0Aiӊt:S EIA lU (LF:ό z)&T6Sj,bCp2p؊Ak8]F+t H IanPCP04w,Y%R(u)Jb (ljm Oښ`z<;N #(PHw653P}d1ftmj&zEߖn-y^>|˿އn\պmCz8&pw{엁8?"ؾuYC*b`D%%zlMZMl(b$?cB'.Ac7^wHQRzZiĩwH1Rt[O wEmA-Ph YD[  =A,T7󧐢sgGtQP`P}P;hEZڌci !)@H8z T-E;Zv\;tm? qngp3~...p:( @A]ޟ8!|-m3#@eZFut6BULv[CbM#y34jEo% '4'{8=`wg4<ڶer.:媚ںlse~ 56 M:p4{xx}T0СPe[0(2l>׬LfQƃA X._]tW&QymQ"Q@` ` `E%%ўo @Qb %P` |~ߔς@m?$@ z@An\Uq0+!PQ*XUUpBÈ%) Ue#+ul/uE f=\U=\f}eo[0ٓ-Y@NmuL}]yj-}zS0ڌS]Qu[DГjupГ%oHojK3W9Co>X>@)rb)-uOH}]ؚ60$ ކ]wQ5iDxRJn9K⸍/恌먲[NQL)EzEۄZͶ\6G#*bmPtx0yP>b5>s~wrw3Enn/@B-VS+jKv_J w%xܕ FgdiQh7B8d\.ǛjO Т$ $B`gQbd=gmI(H%.`'"B lAvu0kl>Η刐fg"Y[TH:sіuQ*|+JoE ŒJI Q@b# &7P(^T!cPR--Tq%TK.. <~o[1 [ RmvQ{񫞺T߲p()b[y 1APgs#</_54}aCMwP+5OQ҂)H.9R>,E~|{dY|@R8!jU[B1`DTfU9*-*?`˞:'O[zwvؕ(VyoFmkmc͌ۡrq;|ʉumʻ(Uymxm1A?ňse6LdQM[~| a'BMe07"aT-C8P/tߵfS۹`8̶|P3'juQ>2{˄Łe9\>LŁeK6cRyjG3>{;S@;ꕕ*δsubFD}\Q kk7B 1my/ aL[i"#ׇ` .K ]R]P/50]+״ o}k<8?q~J 5􏇧 T>M}@S_&7ԗɍU><]JHG=?Ӎ(z#x<=3# _58"j-*F׫Y+Fu5~ k[E,6}S1]V?"}կ/}z[?ehoi+2v+Z[>tۏ?{EF1`o+җtr\o-kO_ ^jP `{MC^j}0p>FE}0POB/ S`h}0yaW0+9@p14\Ͼ $ {^hTI kz]#A%\oqT 7gꮻ^ՠn(p Wk'=BRr3(H zQr jWbPKj܆V]VGq RBTK ]@jakl濽-rE?K RU`]Xgku lFs V- lc1נLb$@ ~ F7jZ3KƷMSUSݺBGh/5(EM}@/xB"^jT$:j>pkPJKJIJIJIUԨJUĠJT D7Jtu)Uop_CR#5鄆lG tk =:{=Gt85 5 =:rr9?P#C @9B]6#_c  0b+po]# ^ـZ~j@DfEzTmė5|njSGcA>?/ا]X&* 9Rϛ-V̱ʦՒB_ upDhxO/um`ϣ*4[Y&_#vKzoo+מ\vyaS@eFAF:NhWh zާ Yu ` ֛A{`v=xЧ7ϲ @z ] ?0#VSEҠ4(Xtq ug 58R^h(}~FxCx\uXM N}3@FȺNz&Ԃ>` 4H-Ԃ%*oɊοb](5b뛀4bX 쬗 o6*z$evK-?,@FĆ׫ % "7[JGn k_@K]CjXM~z 5Z`8ʼHd____.7 EIv&#]@ԅevY2pD .nVh̰0 Q#ҁT=tp66ۡ[d|.DW5h kK֕-g fF7ąX{=^.FǸ:k{gRlX#MԨ T ܚm@Rybu*S z F?5 n' 0^P||e/^gt@rk]]O'ˏ^NjXKJzs ('_c?ςAaB0=o~  S<) R¸^"`ҧFY/5*y] Aa <؃+1(|]P?2 B*xGa2 m^gn׿qƝ~.Wߺa 0c]:s'Gh'4L QgkT+5Nu4GspkRڻ5J)TE{FɢJ /i_9`_5p[`8 8Y#]}hk>}?_YR^EFe:EJ@j3sBXGyk5FԨƧ vgcQf?ǟ/AٌAZV 4=?xv1񳑮>~6kYc^#>5S E rGF~/@~>5xGm-\bL_w,ϟ@ chFM~F_^> %tB^ W4kFhmAcZ2> :[onnattlAi֛tHU,-S ?UrT~vB^Өs`/=Xگχd]T5*>(.E%u :~8Ԩu4 :R΁oQ"Ek0EUA>uuA_ ZUDv+z%U2 Q9#m2@*pwTdY+Z_\[ vv)GW =)V2v#U06#xv\9SDh_y.CŅкq!679QxՊ왙5;FCGR|{-]amL5F2KSÿV_g'5t Vhq58H5襆ؠ_@zR#@NjI :FF蚽[uV/5:牢H~2UAԨG/5d句ԨU'4mF+Ϛl0h{?h{'խ"FTE\ѕ] ~h@}t{^#\u!{F7lA] ]G:'ck]Fz5DߎoOǟRøY?~[>5b]5uqN(n @ 5 t k" kQt}a3/#6{ҋ RT|b^(C#WS[j_8I"ʸ@B1}LJGR] 4﫾.T U4tueڣ :ǏUY{~be HdY[jP= 3}%~=b0HZtR(K6=Aŋ9`# 6^]]s/5'2DzA?ӅN! z .V}\MÏ?{gԠE :aԠ5tRèAoq5-0I _0_c68tBx@oppE :aԠF7No3}~[!1餆9z[EFy;EީQ@j6~3 }J@jKֆR]JN/5q3ĝ% t w~I v{ W_F' _iJwIj߃[AK(潦] @GfMw{`ӽn)n;xJ`^d ,4v4MZ7Ɍ;HSռwi58tbNLŘ)4,A~vqHviFam| {#: G}5^Ѕx~0:^h\өԱ t ⳑ[žn pk}@ng#=:t@jaPk6ΧkT=ڟ״+%Y=7|6;e H7HC9]lvKt1}G^GKDhH&Ol3V s46H{a 9iIܟrLVLvd*.Y8m8'gw ATԜ!l&i$cG:< tQ~&>Oks9ϧmb9:o"@x4pNM*؁ V-?챆&sw<p`oqIm9H{[ N|O+ ;zå@䞬aykC+xnj, ޳l3U+oᓀ@|[ΉBX V۾xX"SlJ KӪYOWctR~^%%Y#a-gC^D!"d7C-H;GZCҰLd-%Hߟ"%5 'Q僚96qm9sXӘuWM+1@!PG!i؈Y|]YFAA%N >D[0a[XaY܄L }Uk07GC'QW ?K_)-9nꬾy+rp36OVU4 / >K-a<=Δ?&=O~- }bN^䳮*]t\MyJ,8aDFHekMǓ"%oixC`>'?9.S8v6L'gd+BM#4Mi8س @i{h21nX8b˳ZE1ַasCgQHL+FbG*Z`&0 VT:7&H;aZ^l,Nľ-K,FC&_fg#܈N IF0gb(,5LWc<WMpU$if8GBX|q㗈bȟqdqEhvi$z4L^l%'*.Hiߐ𞇞Y.c݌c bn~[D|1AfJ]?S^W#KhH6b9y( a/,a/=}Ks{0oyvO6hef\ą4ʪ4msJ|3('RE]?J$&[ΉG%.="e %$DdlB6dI$ɉ:u4@opy`;MOzR9Yy7'?2X4q` 0ǪUC ҺF .^hê31Vfqd쑺e}D_HA } ,¬[CaT몂 jNXNZkZL+{X.gюPW-=~[p@#s,9ƹՎ1%^֐7OrNB*8MT% {i yhƄ '_O (#~_ϙaT`Ʒ{ݜcSZz=_tz]jbV]Za԰f66 Kk)xM‡{׿gI^giΡU nՉ{QpzSj$fn4$ 1œgU`q IÆ _ Cq`Z ޳hGMwpK]'+_C7,j!UDYX5LIOl݂WռlL+\,3 pܫ5`60߫ újÇw KKkxY?'EigwMLmJmM+¥ ҁ4u!9 `>u-ո]Y#NvxD ;vcC K&-*HZY+Tj:RMD|},bl+zw$6 mq*qE$|?Pkzw2\(-&#DoŎv‘ȥ\(3zej׷SbKT~ $ DM(0d]wՀ䮴l@N5= Ijm3+X׷ᬼ]qC/ǕJ Ef%`9rLӆ>$#A{hLbpQT_\m3nd+|/ͫ4.VfXQs@[0ΩٴRQjtV^W=\?aR5Vy!yMs%"Lzo:yN?[BYw!P1 s8 ?#~+%0[ GY!Z7Sd@Kzh0Mr jX56mޫV(X(& V߆ZO:i-x Ӵ,FZCaAvi$oixI%[ͥ?|泩Μ- | hD $} @qm$3 LpsfϞ 2AkP9aZ޳/`lW )E8':y˜ٙ$#*}rn7S[K.g唘8hTp^jO:r ޳  ڼDY4K>ȸP7!eeG~ȋv 9>F?ie2* ;h)#tDs!^̉vgVz΂:*ѧQ`&& L $C.X.j{`O[\<ȺIƦNag-f-eZf$TztnuN ⵻7H#%,!=(Ji|~xND#VNd.C|"IPuH)*0I :Zu8#_~R-A|D:M9(ʵw:Ƌq%ɷ0!81S)e!tV !z+HڇYyn+ia!|` hY'˹;^*vɹVq@8b3u!*26_CuUIDL H:1\5bf({h"<4n9X ;wÓ~HO#znƵyIT9V%L9P*ɳf]-`yi5z@8KݒҰlp0Ld za {) ?p}⑉ȫ &`=1龕= / Ď$ҳDnf( -"g ގ˂#DIDa5xm8˭Ҕk;)zmș( =ik{b|,W4r@T4YlR#?kENZC-UiҀmVnb0M)3Y6J|uIF"V9W4m`9Iϫ6 it H= pfl̎H]ߖsRE(dڬ@آ3HoNJ֐əNx@6H@^X^Z{1aKMB2)| Co A/|"&Z1HsI eUCҋjZkb cEp2 KKkxëcQu*o?J3S{ءy}p_}eՂ5$% 6JB KKkxC73U.1%XPzVuq>;jă<1]p&܉aݸ HH= }YUW߆;΢bэgT֑ӴBqV89Op}' _$>ќճ1P~ L(Ԕ`ǔ8 a&irqJX & |V1H=69J !spnamra.dD# @\AIbh!k|{ʆ^<"tC=Xn(VNTA{dFάlHXwj0MaΊesjJ jxa {-I81vrY7gfJD!.әt|=3 FIY bl?EJGMW9 OoI":TptZ*%|j|YPbZUBDA C+xZή9mG|AYa.6L fme$9>n׹1@Zs` h985 = N*gcmp~#x<)lǧO4r2PDp6q~,/6 |)!/S{m^4Iܝ5M*^ZH,v4IŪԐ4l`+UicwUza {i ygA+^Uҍ<e U3`F2 t|#|LAiD iicӞ^X^JȈyH+JFK VT T'SȴAZxa[Ы \zF.ށ%)s9:xYѽ4vcrѲquIV0\cۄh\:6g_s1| j^Նs2t!D[a݁J9WK<_R9,*VM? KI)xB=`|VhپKZX@63;i6ϊidb(Ӵ̬xG_ HSH=}zV.*ڂpr.EX5-4R6 hoE9X.dC4!p ~f{-U>;߆x[ŅϚq5!yb).oUi? iHݟN5=| Pa]f[98XCt\{JWړµSj-xɊs2` ^d\؋1H0 SY*aJFvqmLKyߩQ5,w `ڵYgtʷ1p6YH{^6TXѓfi$Mji0Gr} "hLƭ/',nS{z/#|sթRD nƵ(-5,5 &Sbaj0M1œUg(4AO<2u 'l"m8P >D-3oaL:W I1#XH4&@"4"wIxDL|YM ߖs&6B\ME)yꚗnX窡nؐ!P tS"5$}z V9K m^Hg_hDNͻ&:>7w9X; "z?TlhL&M1"9D/O i4ў.,j+vI(:1:IYx:unKO''Y"LΆ8o(MOu sd 3U yIUj%Fais tYovj*0 ʏdRjik k fJE+xA& 2sAm b('h>*rN INccöT1*MF>,{S"g[;|E}ݫP6ғQ6ZADi rvR޳hS;Zv,6Ix⌰yƟɣMR=2!׮L<ez4Ж MmDH@gƹf  M$HVͿpp΂e46_7='&>~*sflB_^NI&W?YϐÓV|r/oD,8 %b_+X Ea@w--TKm ^}hή5D 0},Zfڨl ܙdAI߬$$6/S9|%LXE.X"$ىUU<;B8&$] #G!Ctf&Go+tݫ@:KG+x`kr/qe1P;|[gjw&֘ᠿ,I*IN@AAK,a= E)VVm@<+Һpx'ΪML S8;S԰^櫦}-mypC?$ K 5>BHeD[AEnmDq,-,a߇@<]q{Lg$3w_*#Whg%MW&''cen~UUaqD:M ?p+PM5-N*gݳ;g,2høq[,nDSbV 49Ya:=ffݪ HǠ)!S{z/h%Ԋ9]Lў\<hq*1c"M3 Pz6Hc!$.J$pQr?@ e[rE74`d雸HO JW}aFncAT/,~K{mSekܕU^a[Aox|̀?H}nƒX<#GwG ̆Q,唐gvX0B9d@ڏ׊FsE5$rxD6Ѧ q KKBj7hcNXewZ/LdQ 5P(nFSH,i'}yKTߋacŦtvktMEѯjWeb[TVYbfiHZ6gj԰&6Da^Ъ&CU:MsRH𚺉EnϳzytҫYq҃҃&Hǐg )lQIC@əm<i, -*t/:4bnʰ!鱆g`1eΕE56 ߆s`G"]8f&3"%#/0c'߀^W F*\D:- I(H8ϟ+"Ǝ9Ǥ"|!# oB"to(?MU!S]]$t3J߆sl5/vrt݉v†r)\lj iC}rΗ$mdw4Ѧ+\]%68Б/ ?ϊf&:rѴvHk KZSZa',a=6(FHd6Sצx4zd,,Ĭ 4$ٕ+&]ml{!75C'Aa1]ȮaJʹqZkΪǕբ< ma bp {y!R~a(w$]Hu~fDqgIXFp4" 26@fEWG5Wo#V-YC##׿CG]\]CN^ Gsb +8rta ޷ o/,~K{N*G[Z_ g;eG-ےk5%6 L;ösR6TT7^Z ޳eYX`G\\9˅k4R&f.-팊[CElN!Kc4"hxbx ?_M9=v~2oR4MP-ӏ$OA̢:wg,FJג\na7j$KoJ2'\([JAT/,a/=leٸjetrj_tN "}D`i썆WI VNg\)H yp.6P9wý\qUrvKDb1Cw8rkoRB.$ϟCh`5oلJx'L4WC݄U/k`6t~yҰ6H/,~K{: ;sc#$n oٸOߕ4:!$KVY9xr骕rrV }g^ G!%.6ӋCl)"T ilG AS41om);N$PEjHj?مjo dƺˣ:I,-`saf^ @HyY9Q ΙHb+J } 'x.N(K˓A </X2="G#l(5"Y@Rba}Cj0MNjXiD%oixϣu6i&K]9yJ؎taa<r~H:'$A[#>TW]׸M /(Hz69gn.'}H ޳D|A85'߬g" Pp}'ߍg( -bS##u=*W54TvvR ޳h ʜUQ1s1M 1?$OƷ(ui? e9^wi4@%eixM;Ԇ[Ζ!a mwHBkٓbbKD'jH6X4GhְqՕ6Hߟ$3oϦ?ye9UAa i1- WJG %W4MsU[ñi@$eV~]puJl)2>0ZܟTHtgJ,t@(eI_3IL&ِIDIvfV6["< ISda^f&@YB` h \OjrX?W(=Ƃ J%֙֐%'꺠SbԘ|'"`S +O#}CM'KbC^ęXB4d7"X[Pɞ̅Ķ@T,iNۓ׿&;fS{wl:m_76H8l+Ӵ#3!>5l13{fӁ{͟D- y+`κj иkvcMcaqZ%-u`60œ%ACl? KGFhQ#du6Z''#&tG3y `5 lK'DHfPصĶ<L^MaSز< u@!aE+U(n!ID1Ⱥ%1WI&gӂ 6pmNX>Z{.ؕch 34RtS%x\5 D̙ cO ,VDDu~2wZ ^hA7uh&gըlh FwBW? uxk`S:\6i qM 8UMQlCf^ƵU{р+iOȅHdrk0MÁLS TY.Dt~[)̔Qʲ:7 Ϋ(A!iə*K a/,a/=[kAj RY-gW`$1O,+z5E657sf6M 3e 6;l}y,1eu#!ٓ4e!')Q֗L1CCbɩaEJc"EO ↁƃ2~[m3pr`826fJdTI5#a!aXKNX>J,Ūc ArʒSbhoElz{T^}4 {/4@ړt~&гj$@ΐ`,yfNߗiohwV ;9Ňs`]U,Ns{{ҷdʹDžuY& !6gUv>+r eR[Cb.k{ F@|}vĬTꏚ@ؘHZ%RKx^C34@ZHEkxOBԴ 3(Ùط,LăMrJ j.n^93A _ HH= ӎO5|p\9<ݎ$~Vp3It|;ϕIKg%'T: bbGI^Z{$IXOb2yr@aRT#\\x/yfr4TZmS*gGj`j]MH/gqf9, n pPd(#N侐q,SKDl4$15l6vL/RB^n"Ubf5@%FHZ—x Q _lMwdNAY9 %Qq_x;]Ds y~o˿3L6ѡdZ|`t;_IfMS҂^vJJ԰J iya 9iI5.}<%ge{hѪ*}FRA$ʂWRj0Mhpl jԖ6 K g-c6 &d;0Վ3^RL IEr;[[Cůi%5~{m]D= }H==G=UKuvu0''q@,%LqΎUBfAlܟ]a>wʆhҋH= i5*D vW68G:|*iMZ.*-qR[iУ cŻ-59'w*눢St_S1hʀS%l4$]oJΣz0m$BSAaոa)BtLx&NhHeZ K#0c9 *0rNQAKCDߟvQS?5)Jvn{2ҎX)<(,I i` 2ccimFJ +/xCX$T`&0œH =7&HciM,Ns{./ wA -1W3JB2N4O)zII!]*J Kg)xM=nu{Y4P72|Ӑve[Fi]882q9r j*wwm ޳hLĞKƦ769LFE`X^SbyyjHzrwơ` I3}x^*`l߆syr# &{rt:Aj0_asH4~APK7V"VL:ڤ=1R`a?T$}3Ps rȳ VCUw-*gE٫J߹ zyg@ǟR5$M/ FrWj(r6Hߟ%oj8Ǵ7}59ɇ8ʜ.kI |Ҝ¥@ZrPl˥cEHr ؈d宦{Ma2.JM&R9z67IH5= 3I r1(4ɔ8N8ȏ#i8MGNuڑ}yt7rhӷD s{3ڤC)3#-5 a 34̫dmHKkxuYO/, y΄x9JmI}d 7W&/Sj*A&- KGkxBB0]$ 3P3\r6EI'[q$-ja-Px;Ήq툇'ͥ_dˁV+Qj xs28O&g.͙G{KU5}00(.F7BVGV`TtY3;Ȍ!P%Ƿm\3R-Gwa!$眙0DvYH%Z8 D$_$`~VQ5I#cUX"]}b ^qkUƉY.ѕ'vD+kxgi40aMqd5&H#PNX",^Y+<x< 0N~g {r>5t@8'LPR}o,ֱ\D<)gd{\:~Өe][MAjYMLMofViBY,b-^S,+ !ęl0Q~ڀtߚ4C !%J 限[lA(n4HVEmvbO(Fϕ=]tۄUh]SbРF'Xx(cL+sv_&颺vbKCA RUdbqZCAxNf]Siq9 4qAT/,~K{"~mԼ*9Ѻ1v$$ P f& Eȕ#)ΟH# V>HzM?h;LgURXϩf<)|Euٍ*ځlʲ`ԆT­6-za[xhCu1m %(G\]Y)X㩚3_!EajP´A yAN~6/|)Fh2SUWE[:X@RAҋ 3 w2A|},|܃R q.8'jT$@a8iЍ©ys9qDz* /S=qm8bHRXP6gCGiHEK,I|!9ӇktJ)K+A"Qnzwga9^*`cj˫ H="'0y;#3P#I+jDcv!ВJ@3k0M͘$0` ힼD- y=^(.qNiǙ V984-S,d1*utި&k?Y FBH")8 8*r<9 +ۈq_THt˓<MSV0!UI,.K{ xV)}ej47sV]Qo\vJgxQKf5.JaIn4FYa)ZTrv.牭jvE±&LT`&O(4-dzj 51F[HË,chd23t$LJBD9/FϬ%a~ߖ F> @N+G!}XsIO,9UIZ8b[K'y` ~ZQn7eqS0y9TѸ5mUYg YC^EJS]a\jG|1{^X^Z{GS¶ T"8JNba;$ٛ?8Ó")9< "B\3>GNzGMua{EТQ2^<|ˮ뙇SALS32a,or1-Jy =Hm#nO\iύĺ >X L\d!y/-2@'2vwWr" #5 H bAJ ᕘUy& 2(I <2 O7PoM*6,8ıˮF-B%vAIAEYMQXy - gdےs*Pb`ZI+%NT I+'zYi KKkxC+&pHj 5㱀g5atx =8t<* }a4 aUWe][zM Y՚J%2,Xؔ"AaRkҷbyeD_ *Ļu &HE$G)E'DTW䊻VaF|.{ f` pr7 <VEۉ71#;˱grN@nOQGڻ\$[Z93$)Bp$ h GXjA՗mss2S;ʲoQT9_TMų%"ⲍ(g>&^(}/v#jMت9?R Y{x(JBŮ?[0u+ak |G1uyt1>Tsٴq1b;#:ƖWG8]jwVvE͡цո7=ZQΛV{pJُ9Lyf6K7vUsalOL:nwC )H8Xh#?n)ɝ>@ |=*sqO#ez+|.w| 79C+oKTú X#!D̟:Q:S CQ>H EpdBNY{`clP5mhw QLcDΟv!.C?B5fHTJ1_"%ʞBE=~miiZ1h6alD6d,Sw4^EhkAnoCN[Ypg? w/Yp*GyFl ؖZ Qv{PlX-z,Κ́HnYTǃ`@w9YT 3-iB3Ne(&u2E#އM03'{qӡuy2M wr%txpruK97h#REI^xj@6=;PkV5rZ1#AzQ~{K]37ݰ=!4>jvsV@ΐIQšцjz(g^&E;9|c ڞ]>j!-<lےE6nY&bM-x7;dR i;Mdً6Ʈ-l9(ظI:E$A;id#HR#~cEoȫ<&Vvzt7(%(&rrBi>s (s׭w괙xtmbVE=uWiL*ldۃ~E X>?|$Y>s4Ng=q?Y-fϴÎ/e`4?~eo5sws\F~Q|TT-:O]zr/~nn,eȤŠZX' wS:K"(g/r&{x##o׳FB#rB-."Q,gX5 ̖qhFݎR4:|t≩-]ۏ[Y곭&29RqT~fLS$O܏s][FXٙR L#_-dWQg'h f9"k ˽QI]qc+#A EՌ;Z&.)CRW/*>Tv1;+׬k&uϲ|FҴ{= *G?5k' x4 nsMg'*w%3PʹMtk <* r]^VG!` C%Ί^ÙFMD*@n֭׏sδӲkKeWêjw/<Q5oheqbjmD9t(Jُҁ~Gvq1.<>jVɽK4y:Wc \nw8LR00X>PZ~)3MUc-YؽBSj]eўP??b4pLR=žmT#ǟ-y̘Vgb"VOS"ApEqX5ş_ EФNȝ/2"o\P NO̝GDL, n KX<\HUszwYUB4|N⳧+̩٢o5E7gzu8@gLVv#8A>Z bae,Ky7d[(ëO{Ϟ=󶆳>zgis/84+?nWFaC+ jFY&}ː/矝x:N$vo1k|QUZy}j=Aa p4WnIQ%eqGxb? 5AXetH(bn˃"3C+GpP5s%1?ڈϯ[~ wר=>1%[!Ou b?^{[,mD-EQvC$6б-)w ̲}oUǐ@ɡцnfWa3ncS(/qo,=3E c=LQ4S+|0hbf;"xqd(|i 2L[bY+h?,"!##!6 9/kk 2A7(I6^M)~^#LU<#0ǜ\NM b:ldS{mkЈmmD9]()g?ro [b4!8V(Gt[+z7=(.ц}& uoaM _v ]q#Rxd`kۧ}KtZ9vs* "V^fğmD-EQՏ2 Ċ|)7ƻf˦{V%Bގ7"wGűZqry5;Mnb-!^"?;W w9.& j k,1qm4ny]< h Mk,!bˇ?ZS(g/]uL9.E{X׈Ժ4Z[8e9y~PCCT [1Aghhߛb#L̓9,ᏖoU3g[ul#\~:7pRSj5 #^nMhB'NKF>B1>wpX??ar=#-1V}]VjSǞyzwߎFU 'Z37d^3#h.)&q9 Ƽl_6dpiAbn2j6OϡFW'.˃"ƠϯG gmk"?n!I>{ 5- 3"=ϖ&_ěyA8VMA1&/ɜ >Pg"u^)NqI{U޾m+޼(@ wqHۻƣ j"nk!!u%HEnn𥌄0W$Ιpk 2cEbc+)"|];9rQJjqHgXmDᔢ(Sqn}fXcq%2v,^d@R[ M/f w`GQv%0(&u2^? 0XV m4쁛eWáQEqhp&o_EQR~P:qfS4 *4V3oݮ0DvxC[؛*GSq CZ(%,e(&u2E^!#pgeRe"rUsqh=0c>p9rGhCxA{TLe\ ,R|&&}{P4G/ ^¼fFmtxXyh6(npyT*w?;S?={ \{7)~~UċчiҟV1E13Ǻ2Y]iBu>ؑT9ZKQTL0TS-D_S(]xB×L.|9]jL i7qW?b6ϛ=7V&Uƍgk!J&rՅb=Ɔ GST꧷/4 L1TGƠтjJGmЄ(9хBѼSm%#-kJVa޻9-s GǣK$kg@4Uj0SxTn(Jdщ|l9]Ny w=\f}ʠ1fR<=M7b:k(xC+{bsmnmDR()g?VpP>f>6*"|t؈p;;{sNj68Ån>#Wg݅]%t˲DzO?!Ay+WzVSbdVyd˟~ ĝ\3oL<]9A% wV S ŴEby+Lͼj,["ϧ0(Jك<2<mG 5G LG" .0E>*G]Ź']rrῨ9as(oJQMُg&@^ |]Rj #<.*Ś'Y xPPhQ5S<%mD=Shr'~<2Iz0kbdH] WLs,N0*T5K\xh-d@-ABxy̶'~VKVTfS&۲Lg+sK#S*G?5C$\#%ϯ&E(G'r'vG#p&PfH(3xG)09rzQ}R,~ D~7&s~mE69| _)^Aݟ QfcHh!6?2p9TNjj6dnkTRE;9|y8]L0ޠ Qq&(7K8/. kz*?]$b0>gH!I>zQY8.``{.j!Oӽ{t^WW7zi9V.kfaTa(KQ%erx[݆?m1f1#zbsM<.~!Ụ*5Nwσq7eEEQ"NCe:r{2Ӛ+<iBE<8*41251V^2]1N10Vs˼VBE:8|wHy-@IGf4? Ǽ1c7YiYvDH(Wi }*<K|בDq椸E.v8hPK˰GzuZ|WUC-q m,9rȚ9<6($I^x>TqgOv ɒKyJ=|.Y%5f&(U6U3R "nbo!z8T9pjU$9{:eYNCº=(TLaixoRUc2}t+ϝ[ qn/Co6scЊт 5K.D;(g/>ΟPsƞ=a]ql1 T#fɷ 4q4܁$~֩iȠՉ܋~JE璫~)y?-RPA S\f?X(9.11YQ39Fcp>&W! n}.,K鈋w+7gErsie"PnU&2A bV떡(~_kfa;~}fwĝ6JXBP߸epuxG_#ce\F=IЄM?՜xÑgLZGz2#C!Ӑ!ل'w95|e8`(΀+UUSc`룉( z QMًL>?Lḧ0̾fH w7XV (wjr쭍ޤH&erxnR,'Ҷ*l5_^'۶]b_UVk]#5}Uqw5 "nbo!L(k<ؚǼ%h5ۚ.K_kO8FJ`p^Y,f1w-@ɐ9n>ҽݗvo*IIc9KY ;q\2h)[CͿo՚ѧ~م%#6c$v哒Lh>KMQ!ϯG4 h2MFQR'NTYTcџ e(GjԺmt]W3˩}( yph2Uwj < )z*Es?~c-+BVgD#@~5 ,](5~6,mg&C ƻ&,ۚU׋v8fqW׭\rRr_lE X >p1js}f2Fu^m-ߏ93G[y1L]tsNqDzb댠EK٪#ns3U ;i75l1Co)"å9zZeMM)ɝ>Q݂Й=0ŭ=/{Ep(y^=-Xݱ#(o E<Zy;u"w`ӣ(EBN_+DpkY w[Bp(D> -@C Dg﹭(/J()g?y"LQsLV?T%mʽVi>'4NP5ln [?7EDN]ˢ۶wK5޼Й<"Q@ i(e u7J^™Q&V?BeqY½~8Yw7^%\qid=Cp='wи=%2>( -UkwS5!d,($#rcs5[,ƲLNݾ~ʉ]j2qLS6#۟S& ꊄ0XbUؑ];|N VNIA4Bz_6m.D#H](+~r1V5΂-n^3U 1|Q*GIbEeL >;Q_UgagV^)di,-jkşGV*GՌP8a&ơl%C^R˕bù=H7ùD,(3CL ,.т•"ߛ.䇍}1⁣}/{fh5' /ٷ57#}Kmvõ]ڈr[\hr'~oqmyhhQG‹CzxWD:.r\hR'^Nb~gx~w͒A3>ˇ>/1XNU.eIȒ!ջgo),HH5&dĽah!- Y}+g(_꧴&Ÿ%nYrh奜«fTaY2jkY*BJMG*=øus-Gfn5aNGMkEnGOg&q _"RBV\T4iXXW1дpP*Gr6tdhBAX >{Qnk-j3m[V3nV{i绂8's.1&hqrr4Ӿj2p09lg9EYvVH(BC'b`.5嫀KE9-w:@ُx!?7䇅<8^of;cN[ô&} Q%d0x"G# 7q{ԬpC,Q:(\V38GQWJMGޏ+|k!/MlD;VQA1dyita=̡md9իAФN{,#Zu/g>[ >W^#XuM_(y5UKk.[h譍t&EQ4g?PG<3m֭f~ b_3~ ɸ(v3Zbr ,w|PMى:kǴ<ܭ͆=;?}d&)\}p!]@Fphp>rֵ9RMXd(|"_F;yv(@<=P zC<7Q6ƠLnQ`AQ.q(*>h,C6ĊϿ/('rTUAdfvQ+薦JvO?/aq^/fku/l:Ne+Gj]ߣrq:~u+9lkbkz+_$49^ɵ-~9 @ts$Z ,cK5GW/_á:T0`ٵ.{0v&vt21n}{X^Ŧ+W ;ṋ'>ficW&1-qQ8q"e.npP.gwOo=!1v wvp_xc嬦;gɠյ?x'xE^Ѱݥq m=VX,&-ϑN5!/L%< 1Fw:$հ}e;=Tgt.w~qJe\-\04/>+c>"}nJGٖ]1zf˖jNbSA~aK_E\Xqrjw!o_΃x}O\S_#ҳ{lݾA{䈷یؗ8\ngͱ?!5zjutJ*nܡ"=ZptGb3 1uǶ5PKsv͘ ;qyH֖6O'hfoT}3 LŞV%XYܷM;{SSiP%LxnCwhvU^2S;daPAɦIJ6QMqqրUʼe%Hbf&۾$b3#צ=^huG͹}X/xC ^ۉ8k[5;6ַEk,emQџz׉|Ӵ:W9ӵ/ Ge7zAA9 | }[^҇xXr~Ϸ$oj? =(B۶b->Unp?3Euoz hv xmW]uͷOevvj,2EЗ4)m8cST-v_2/鬚'֪yRCSሁXfOjsUc spE\̦=B({+$aX2KC[@/k# ^0 ~pB5 2 $49ihq"%GO畇XH/{uk e3a݉řGOґߏq(Gk=7vHNDYVjwD"F4yv_v:H S` :yӏ)dӛfE:bݏ/@?6^a nu:8ѮelH$p&{oVtvsߗl;Nw}NohCg=ICsiMk4,{tvpЎ{Mg^ .ngĽwz'y>͖ lsg}ݖ).DD<=܏z >؎uc瞱fa-u^W#eް 0wk$t/1<:;qy|\|.D_7lg|Mk8mSgc'2B kt5F;X{}MTuɥ)xDk&o hd:Ba-+-C$ 97{; אk ӷ@qGBr0U_,U*CřbzW`_eo qx,XcW. DX ߢMLP};1ޥS}p !OZBy0cQln GwW..oKbt큞R\ZgDC.=g_ tn_ rEe#IYuS[)}xyAȓX _o_V8RJ!J[;7Зc+͛16O%dyx;(Cl/3U]iymd"vm|Jʎ3ې=qpK;aree[.ٷ[.Q[.NHmh~:ᖿ˕,m%s7_/{ hrZJK'Mu,fTekT/ؿbQP+^Zd88ɪF_y." 9=cUzrlՑ=UV.9gUd}o/"8ت O̷'·Va [q*.0V[~4gf8"/qlLa[|;+p Rܒޡ x8' /~f^t0գXG'vQ<:qsN8u?S)cw( ; x*yvw(īE;!Qѷ(P(^3W GC,G9v*LZ_lm{v_v|"pVK8šgU<L 'W9j~`ͿlU*r FE0*"h 4S ==B.;_JuN#S8IշIQ-0toH ZZ'hJ`J' lK^dox ]`#*LVMA.1D1ݨ2Lc0 +U32LMI͉L  є4U(jєK)iM<\oݛ$ս޼_7 h|\j0 1MAUV6RIYfZfom6\6Vjsgx)|~|{ߤoEDT%EUbRT%&^paN(@EFBfXfXB3"3j1O4X+}DcBc=k V[$ckh/fXjU*2ÊXja1 ziPVD 6HVZjaQ ۩N*Nu:T>煶S b;->DvQ-71ʴB=ke品U$ө.2Se)fs2-e6TZ3,~D"[񵍜nlLWzXKadՕHfXXeJ^MJES*W~cδ~Ð$ީA4bCL흺ީBNm:I;i:; X<`#PhhNl:L}"e 5өnuoN۽퀺UfXhQ%c 063N%yv c-XDdm!V772*/2Êea߰D?Ci{$}c7#nQDSZŏCT&NZ4镇Ix{_GJ'%%%~+Ĭ=s&|+Q{ol%Cx+kxtg!5PE7N@ZvBٞam矯y\kD7g b k~""2'5EzGU(^o(AX)Tۼph JW W fN]6ET}O?G-_jʶ# *wŢLXS47EYxsN)IjeXME̠O]\[m3Gp p2exEՌ/_UK#.ėSy oR~@ EåOh٬xLDL*i痥(K|qWX).}T\cZDb)@ A۽ [?_6fS"VDgN5.SV DTċߖ?0}gp4M:7#>pLyv̾6CM\M|љh4~%HQ Nnoy5 zigLE0M@E*"*"5(IHf6Y~W岗Keۧ+II,  a'C;LkFl7!': Tmyk0rr-Z pykv~uPv߮j{q)HʮD8ס@81@bLb\HHċPu'nR_X)40(1l" +0~ KM*'7]S@PF*`w')c4Oo$~r# ;^҂ rŋ]1_Q:4?"Ҳ^Ëruo"jU`^'|P7{!!+Ƌ@Ôܿ͢00, ny_-: lP햏7T0!1 h 0R &_*SAu`1\L]ٜ{?ASqxìQM5/[SahPVrjLhg>պ)!<펗lj6ױŴ,]#4ㆈ֭̇Ӎ&2r*0ei!"Ta @wWsa¿ݠPs,Yz:ogk.cs"S`<ٲƐHf[؀tCo,8 L9!#-?g!D:SZ.%B@&v7u)&ݹK8:Q#W OXs`X4 ]O,_@jЅ//؝s\'n)Gg7$D`H:;!ѡ9%&>-HܵT<rt a `]g-L`뚽E8)eڦA1 Q 2/a=08VyWZOB2UNBVyXHWw.JO%r P`)cnR,8X6 ph;+c±IrQ|,G!(AP0XU.0ׂv%`x,Xe vI4OXO5Աapq~m7'0юΞܐ @L` @{~vC _n/h T//P[Ԣ*HQr~Tq -IҫIk"Q*}A=@'1B5 bSR% @ZԼ2,[/N,r*}EEEU$^DYx - TAS`hQe&Ru旪KtIZA'ґehJH&/ǧHCz I J-G <^U_"Fi$4 Q5K xT%_@(QdwC/Vi 4:-m TzD}k4"Ӡ 8Rs}A(ѷV-[M}PU`-ߠM*h[yP;wޠM<^|7|ξS^oœ[-Nh TEG!4`K%Teu;?h9K;D= E 6}B!HJEHB{9 /x)Q)-B1* -*ВR*B!+6wbAh az'`_-'__ D{ {EBQ^W5_d_-U*݅pZN8]ܑNx). C <(8mu7l^Bl^yx}B-z!^ Q) _ Hxz/D免R5T"\^o]X DU!H,`A\D py(\^6 @dY0l(} rVFH(@RgxvBu~a:x/ -*DR -/e-iD--^z?W"%5zo@юfk_,XeUx V(T(«QW,(Co||(y}( y#p>&Ns $;aYp\\0[b]l\K3 2 Uؒ$P`.uD%8^j˴QŝMmiKK#;|NҼks0pKTK#/Dmrmr4u65[T{3fZ|'2`&^'LX_KTKDŋYxFN"Qx~t痣ExqIoT Z[5SAbjq6xIm`yE7CLmgSzyrlEi#Q^.ŏ-qD!_?v `cj ^ה.~ MmWm2$ 𔵠hi+n抓^Ng^i[1:¯D#q:8z>RCDVz (ZD_``W ]A.w^T,GY!@4VKPaWE"9SVhy,$o``?A>:'4(Hg,$U5 |ui(QJ4'ȃW6y*/%w8(4~E  FH FyVrϸ70m CByJϰZgXNj|;7y W)^B* /̕E\iRi V'[zǥQ[Jӭ_%*rͥ*&`Wx3u=|uTC151<ԯX?6j$aKk`,. /zzTUcRXP -|䣬r1 >4Bց _`^KڀiVg"J[  pRa%"(mT{ =v]~8S#ӥ]ԗIJE!"R\rx(ژuD0qiEI _W- EIIƩD`T© kWRxg=GLxiy|k`؄T}mv]VN$0 [xީ4]d}8ȦCN9E\&` x0v_Xo`u 2ӆraT+l\ M2VUI5٥6UmܻP R f&9]F`R-КayO7؊A&eޅDqVe9wJ5PvjGcaɩ`y&V8Fd~]`nJVXXLj^;,4u 3Nͦ CaSC'KAꥻ9QeXc݋XBzXZ +S̠xA^ZbO|SwXvH*/ L"iEP1tLdp-"]Ty Ґ푮Tl0Tn)P$%ڤҐ:TOP*/(aJ ZuJk@PUb C N%EUxRU,aLAuvGKG`꣎AP aq֡ *pj kTM%Aׄ Mm& UyQThQN{Wޚ#*VP]֛̤up2pwQP&Ma=Hv9~4% +lYU?u $k/N Q߭}O۲8wYY23gT$^4舸9(N ASˆq6]o_`}]a36Y(A0͕4l=~r/‹Nt>rejG/sh^oy+9գp {KY#+Ґf[s%V}/ZIC_jv!sQA}PWߑ5"r%ҀnL9_aݘF^EZm덢s PU^`FQ*ha !e߈L4qԐ Tj DYiAY袂-LU)@$K!_H٩N R\M̦4lڽ|$ʛ䘅^e.ֵ@ ;d*F 3P<%,fo|'ZejΥyN[JV8?e?HQhpϼw@, 5ƫL< IWa:57r-XA4!+H;+ȥZb2}*=-MJp`htX!"Ve V@HUA}UA{%ʫ0"U@uUUs@q[1P[7("‡TVԢ*"7mEojhBBJ# *N7@u(ATGO&}*'P>鞴D'(-FJ!}RS NtNP9Ʃ# K7*h*(Yv>TMM,g)jN@%EU.0;7OBuwVQިrڨF:yJ#-UlP4FK0Ҭ}Qus EB/蓽3CqmR&P&E&%URI`9/h4{ʦ5IOUSW8hz!ES :@DeLdjT|%,ISJӡ*+1NC5*Qi:TZ,'JhW.!i*PATҤ uٵ:e:%4*^ HJq0=9S*\ƖaGAijijUԪ44* />/H TעڑJU~߿SB'lu~L)tCÃ"Y{uISp4yͬ 9x<] e͆eΟ hHCYZJv>o6FuM5#V&iգȼӯR5*}/rQbUZUy&C% z=K|#p.o]*/m/ׁ䔏'XφLKUSR\>yԢ$9ص)tx'9HT4OmPT:R4a*}ٮ~O_;jgRֶ\׺zi=n`lHJWiEAbk{^𚟕6ͼJf^PtT!*+416RҼ5JDykj+R*[C-j4@EVWḫ*=d!^j UVX횶s(CaJhBˡߏГ-SyAB&O^F( }lM5C_HS͐`eđx'(FhQ/05\6_ӎm ArZښ܆N҃ &QS!BMC-J &z!NxI Rn/Va|)px[#,GMGKSxi #X3A.0ge܆KLp"HrYiTV$k8 k$Hz'#VKkr6< krڻ4m AvTMHC4 wzM5 V̳xz'^d7>,D mh %1j7w bmB֐\g 4! *~Q!{-L0AT6/-%t4 ^EPHJJ_Axp4V^ : rY 8^$C@ *:\L YeE t^\Dk/P -Q|EG^ #J60A*^cГA8D^#ħW"^ػ@ǝD\vÄ}0 -h  ^c/ 8hEdž\A.ОEОQzQPոwpj :j?k?k^g giK@Q}k[})(*/~Pfqpǔc Y<,hx[mzf6_HY.AOTT\h:^[™ ppw2~h1\^-h0q@W`{S\@J%>D8N^TTaz`"KI9nA|2Q9X(@4m޷; n@"x%QkK~0U=tJ=tiyNm^{K#rW zTXXnº:Z%$>4!BG0 zHچ/iU0So[n<+Żg^ Q92Q2oo<=J=(ي?_z4z4Uzelw%ogCx wk-'ֵܹN5oOk÷PMt_NYǦ=~w]Vdmkn#_η i2/cT?k^o?k> 5}x37ig#)D*6_oux;ZŴ55+oGkT=}^5鎭T׬rҲ]њȎLwӚ5_|K~gySAW"D8 Nj@,Q)tQfqE0K4d!xQ@ T80/$%Q$j(fR4;0-pFJ-DQ\cF^,T?w~θK> X|@@@pr+vnG$ Bߏ2@?3ӏf%^3$Q^zCC!+c ~Tt+e<eˁ5/R@\q6@?$+dpCG2Ryr@-G([͖ûo÷MY E!(4%+ [|c1L{80q -1Aq b1ǰKqw8^q i֩?Zv>ZKmQ dl)AHJ A C5ؒXjdŁ)~CՈjdE$zYiJ#+ާ=5ŢoS,bU|hTebqS,bpS,X%FVR#+Κi}YZ 0ߏYaA՘i%-՘i2*|yxۡF,+C,xS]f]6}y/1zUfk;;;P䆶$K,.D%J,q%obE*v{:CJi.t.+*6]dJ)sDW"̸{f-3#A/ce-2[i n~Z-"`uEpW?.4rGW*7OQe2H8&}͗eֲN")*l,_&7*X8{e 5L߆Kk}U1{'e")#0/b*P[)P[)k+vKǵ7/ǑMjgw66?@hf-x5~j an0p 0|{89g/g {|HCeSsɻ~7kH2Ħ!-|7*?*CN؝n9m)#솷7 S]H87}:՟殷d؟^kqXoGcZ'0Wp;Ƶ|[X歯!Lv g{vD~5fa63U3~<[Oe q#-޵x8Ees;`"br5 .,DG.pp1fTc y yR"g۞ۖw˩5ǗsF_{kٿ֜g\_3lu~XknSrk_{t;\ௌkzE)pĂkL.'/7 cj=\v/H2(,@cEJ (1,*$e#1|Qt;},aEJ -*WXJ jd>J+HEafneh亻y6LLp} γҍA|%_-==;䫅j ̂|덆EaK5/k06Shܷ0gV Eqr%޷/SBڂTVGksm={\C[j~/Ċ֙ȅFAx$-n͓iHerQ[\e/H)Z>7ᝰ?-wfIkGڪ\G(yN=im+~Kt5swZ!-^lPQ$\f8DxFb󆊢#mWVٿehm(-/CHTAL҅%t$T8$.R(%\ylFmEF %'eļxz}鼴8}qMlq;!o Id̀$քnLD qЎzJTx*$U"NB ,PAYhpnT)@~o<f%1L2 BY,4T{*@zEK_QcHijfXҜ$|>7w{V$*CH 9hMWB%*ͅJ-jSZo `Ne,n61vUV*x$&_}YGtZ|ko\Ks"T]aFQ dB;v;vti_CRxšpiVU*Lqt9pvJå))mϚ{NNaIQ%ԇ0h/u/U*N=j hJtENhJE"H"[W*JҫMx @WZ Q)Z [ $Uk_l, 83R-$W-&j4iT dߚ8N.HGDFJ qEi)HT K ќP!ڪ/QҬW5*n"n4N?4U AK@꣪0H(IC<^o!wEgSPBtfI7E :hTpTI*hBqhP%]*R .jD6ɥ6햪a6}Fհt 6^հiTT[yϨ3$o|&uHzձa$@#=C=֞ygڟU{QgڗT{>jXKul9/T57>3=$Txiډs" s} 1pt}ql&\eeU&4XV^`$J1 $*2k%7;DV"ddЬ2I`ז摆*' &q([ndc [# "…Z\JY&9 $cX` 5F&0$^5i{o [`4-0ƚd#Ti ol)JiP`T^mHTm@Tr Cˇ+Q ,[͓S@cPark*nT T&MRKah+.1T+Sa6|7w++hh T<_qOhfܸph)M̤{bD*i@*nMhPj*56Me Xin𛼃ZQ1yǴB4W; A B4lv B&MeE&MBn"8BdT^J TdTTdQU'Y0ڭ?dđx'9Q5^d^+xRb [l 9vM`ׄ~<^bRU`쯎WV/k*9&h#X? GuO`^jD"~jd.,,\d#-ॿIYJӋ,nbVY8b^`Q~ [r,jB@RHԍOlHv q'f0k5q\`?a"'Tj}'N1~OkaO' 'b1-b!UBl )`l =>aw'N'| fUO,pjnT‰RB ?VgY`EX ұ*cUxTxQ:VtBinSgUYL#3yuH,ձHjW\hYIUEȆC]TSuA8hFW8׷c46G s=]dj"ݚ>;,p:Z \+пAxYYӐfM֬tfTuf3xFl r!oH5ŚwBvpiYTc4* )Vy[}[lW`_gF?ajQajq}y{WwPEck&x6֕>u*HJQ2e& 2tį~&^gpu8qwWUhUZd斦OYSTmS4~jɲJG\ܢ;[٬[U=6Muy] ~ͳj;+- ʊ[E+Rs)Ԣ*.Hq'_F( PAV¬6آ]nvT`*r*!CJOreȁ 9޹oE}#Ao^L4@KdN%hd@L/ h` 6i6RT40 d& $*H29g00' v% 1; trqx6E\rn7_Yze0@_xH-6fygCIڴ. { 䅁.B^Xcb@B}0/zѱf^;=5Q0 9r%OhoȦعѝʘ\;ek<]{=V&N$rQ*5 vH;$r \p }A[&*?v0' L?åc`;RX./ _vդ6owNB㵺b/=媁QUY:z ՟k018x{"gd 2Հrj` T^jh! +4_~_ȰBêaMņU"ê4&S6ad*Th2d*Th2%d"CU,0sJ{d"4sꐪS8S8Sg9 "0Q1Me2sꐒS[T3РS̩CJfN3dT^`攙LfN]dqaZd JBm: d ^h -Dm2d {Ɣ, ,2몸c~C2X)T2BE2&BFN"#d:d^ ~ Ђ@J7jdU^hURUU7y`UՅHVU:ŪW VCVU]dLSl:>^S۫N&+]''۫d{RcQB'Xh+V7g l4Ȯ1vٲ丶EтEo(皴q.P֬W W\O Uaiz6Z| |cgݯZpiDBj$$;~p7T`|"Z~koVZIm_I]-|KX M|K8B4߅:\jm% C/+c ۦvf9>yiM w"" s` u| }-ՄFǸo{gHcLF4t2_- ~] CѨNż/ҪTU IY1\RN_vv:6Wφ B3b8ӍziBx z s5s:݆ \o  ?d-1*tqt51Л#˗`4 z>{Ck|Oa¢'05 qݵ1B b8 _Q1XT.@H¥R(3?&-t*z#/FIiFt쌵Й ߈vRB(P;EAH9"%@J}rWЂ1%5YBhԴSe>m,i7)N4JPr]Mv_my!YVKvCb/cld)N#h쏄 k6vQ4TH,j#Qvlap?$BH]=~iZ.VBKayȦqt*I43W2h"`[-c T}B.4*oh_I+ 6X\m{i`=V,HڴbOӊ#IۧȊ:)i"wemK)ʒW;bG(넚,+ys/vD6sJl0Bΰsscs!/ ˗$gxT2F]#Ecmxii}+;Ϗ|%c `>UŽb 1㮥x0$@[T|zAc+9\p rRdT,tO0XI7r(_9= _?]=5ZI' ^?9To*Cd)o(޴#ޟ̋+R}cXBX`6gY߁S>:: Axbq9sss=X́7; !v܆2r b-D0@7ͦ͆LZ߮;jhٰQ▻~kBTڌ25<7bEl21Wn"c0;]$qc1qcčAkzRN7!ah3B|$ *q{@u?ªªĄU!ªx"_ [c}BYWtkm?S[SحT4R[vlP[SjT5s[|[Svd^ݚxBխ)nMFvkѭInMRnM!alnMY}0Iۇ)l_|G)[SFݚJnMUukխƯnMjp\~r$Ut7S6T&mEm }k5q9 {.d&N"9[SԭIQ]=JN;rhmDK#65b_>m[mLf]S}5UjT B#khTu>muyt]^iԗ{⺾>Zb- Fq)g7b(BnR0[Xz}'sj)uV8u%ue ׂyDbEH,G$*_xOõxlPhTw? };kgiDcWcbwlj~]\6dVÿjW?E ZX Abxck]l^<$* (IGH,P:oC9xFuq;lWǼ FFHWr/ҕ^_Y+/x6r$^#Gqsč?_=vx9O=< 0kTrÊHeol0VwvvD±dZnͯZֿ֬7AjKKMhH>XT42Kyu*_sA4}#t qǎg-l]&9K %+Z.:1z{>7~Ja =R^|a^\u}8$Hly|Pcn~8rEu~xW>PQBjzPb-J@)IPBq(s~1PR/Z#ZWw% @ (UwڰS&[)` 씤 ( (Wn.>8N~aWv;ݱT"^{p\QB>*8avXa{..x?|aOzܹH\;A;sEU+;}`XOuua߾O^-#d5: _[Bwnjw˖JŲ`+m{Pk.hnep7SLuL:&GE,POFXIRV|ٻ+:bk{u}Bx+U0~63Tg='/Og)$[KE~;I[ P+a@ 'vG[( 5Cwx>G{whuߎq=샥=C3Ɠ]4ᥙ84v W؝\ fI9x2)G;qʤQuRa3s5C)Λjyo/J_&z{}u3+zxz];^p:ap/u!?tmCh+=۶Β]^JrZMFL\X(Uci$ϕ> ᳦uzguR523W)|^Ð~b2 -5`8(T@A9Rsc5~R1vDscImEuw?+Î0ySaPN}B ܯoGiUn⩃r$zUpv|Dy.ZMZp\gfaQT#8onW|+0v\zcyr{~Q-i6&`-;;eƧ)_c밉&Ձj qѦ&Q6rpF l7bcgɺ0lgKqm(~>l~@xjqXnm#=^i ,^_zn=xT*+8~j+pޏn }@{;ہ'QQZk4~1?YqC4vGfC/G%kGHp(wswd[dܬ4ߨ@֞#r7qnC8tswc{rsjL7:8nyQ uxwl:?4GSut-vp>X5{G;v$;9T * r -b- U+oKfPil%6Fb-ON{[bf7::ov;fAv-LR0=k!ڶA͘)bz,0=B\X5&7K`zl4=X5@CH[1lIЮ!m[V IaX-6İZ+b&$CVV *L$4ȴZPuZ- q"8Ҷ_piK1ɒi i F1w2+-ef0fÇ  ư d Lc^c4i SD1LPdq%w2q5 ưDdYLch3r!Ǝ!D149x!`g19|w&l!&b?c: ߋS.r ߦK)v"v^V~a yǞɵGqt/e}{7?wr-q{*|,η,ތX _gw^TJK{㹽_kd[ _u척5էsZ5p8xIɒk̾/+DZ_%8qpXBBx?t6ZK} r;R|9H_nzI;@4;7>qªL |Jo[BЉ_vXP.TA-m|r5έF8 #5^Vq@^?TG B&T}R} y/߿6`-cAZ"U0Z*U|b㺢j\;~Ɣ5_CW2WQuګZ4[H`T^z`YP-DvKE,C h,h|ҭFc%y`g)v#Π(! 2)V@g|bCv6TUv㞠jS>k_*A~q@WJS] W4:]`kuhNi^AZ0cÄ>A6V,%$#S8A i(: Xl qTxAXR ~r  (xGJ o$X/FoeBP`Y˂o; "B-/>TBD ^PvG!^p+/d * ^U[xCc,$ -EW$["!n,' vG]anwJ-P* }JRcQ*M?(x/X Xk!([q RUx!. ^8A ^(/,}R,`0s$ff,3:0fq,O;`W,Ŏ>`$i2!  -RB`D{Vs`B` TP`Y`,!7^, Xʵב׹s)qY: e)`Y8`Y^{`YP΀eƁe#%$ a-, JGX|e?!~uAmcKTPBo+Qa'aO?t$b-V KSli:(GZBHi%B+Od,sAB 1^ZBФPXe W]0(LHm+~LF\o+`J(~µ^|\Z,8JƖ֗Z^ Mu)ζDP"RlW S C8V*UBծӮRI*JmCA)8 ZNJC#!P +rs` ֡RPiTBᮥ&+MK&X MA&lϖYG'4Zhj_-)!8X|C6UHl+pRW`*sA+0;bVJW`5J]!/t&_"/~;OGuٽ|;u gӑ;Bk+05{a`Th0Lu0::IaCyw01\Z m鷆A?3v]y/æ&cvR"Yi LOc`h/4ZGZwG-ZN-~#pm ÖAXoo`YF=,]&RE_4-є~DS:JoC&bõ<!RbPWTI>}**V$r_+2wZ`+^ B^JI.}wB⫥YcAtwEڱuu-w|0C!E-#Ö)n=CbOfe\B-P,̧\%|ZA"sLI׿,ۜH(e/ IvGSPc{l8pj>Rk#3eB@,f}9p3agH*>C*.vl![q Vv,݈=nZ'rmy=tC^=@v-AO((N0^^/Ղaa?4u 7 $I[Ә+Ày%qKI106]&;Rld4? J; ((زT–xKqlڧ2vI~p{,4׀yyJ=z~;iI^ l-%ߖRpD¨i[pjdn$y|! A,Yq_J{ ǜ/dk_WöZGYuqJ:?nBhy%f{lxgulEIB4.z]_RׯŌd ^C^{Fo^[2hEcS+l({kez~_7A9k׎[tkOYWN-g JzYi߻']zo\vz5eqwZQ.vyOZ]{jQf p-zn6m[4µ|[uz<FSIKmG|D&ky¬& ^kC[ej.+ϩ++ӿ?lm*/kEN_x{.EՀ$рR hEJ$jlu7f+~ha/\rM~{-x>xIm~~wQN(W`ϯz^^v^ldk2uj_ ^;e,.s {x?uFD~'^{q9pKۏ{joIi6f._u9?YKŹ6]KsmJ6` kJ5`k@5R.\|#1k*y̵[k0&DkӅ4&TkjXZ7%Ě25{ft-͢)f1gY4f`΢QgMOQhft-͢viMťY4f@\EC,(fє W05F1(3Ft-_E0^hc (|#`G ͂!3 2C3dnCfJf ]꟣hz3^Gt)E(CgaOՀw̫@1fZtO_CSs6]j3Sm`jmTZY𱔩6j3?Pjo6@3x<97:Ʃ6vA6x̾JV/LȁbB r#f3f0+&J% NQG鈪#pkz**p2}lu燉q]J+cwDչ;od>!b-$K߷ wrӌ+]O,]~&FH%]:ZpWT<Ye{t])JEԭ-ܷwF;[v0K%(M'9Bj 3 R^GxJwyZoL=u}lmjӂôSRv+* >#lDwV ] !64PNnPR(Vmev $&#PNO@"jHXT׽D4CWσؔl:t.R[xZ} tNf m3g=^ןA:UgO~mmNJ99=O֡6<⫤J|us~/1R>_nma○i[t:DQ_tfLp7knm3_TZ*j#R6D"'**s J@mW+P+?~@mSv$R6 1P[-Ul Vk)Od87;VGovd7T V V2۵Z 6[q)+7ҠoGAP)[\RD[`ɂa+4\q)4\WhwBKp=B3Z [c,I(n7Ko.ڙBÓgnh,BY2p}B2F}˖RԷjT:su56[3S<ʥx\ϕn8 )[P ;*[l´XaZPЕL|5 *:TJ-M-Ibj(:O_84P >1<s,*,r-RI~OzԤSI?jI2r0 CY턥`*0-u sR sN>9%X{skoEۉ=aU;BWT*SɽPXNK J)GE0?0WX6LiV< KT-89%d*ŹWP8bOq.w|En?]y[jJo'>d,[J"ԈޒUe*|hUCTDE"t?b.%bڭPlX_c,7 R5!6bj?FLeHPm3 /1*Uu6 hu  zTvrqխK#^S?tHC,P5_Ci0 e )Zڕ:O'DlxjyB8_h=RK춎xC13")&t;\jRKiXRt$b|OsYv|.A}͔fNN)\ۃC6+)XۓC5T+Hmwk/\2VXv;^q@tMVS u%:[Y"8ۣCUbJu6#0;qYt ˖qDeˏlWBHgi N.)e3jA&hn@me`/-2!ɢBb*JS!$ 쩤VVT_(ndWB/{"ȮIO1C@a +Y@P !bChea+vEt0":7z W] \A( *A#$e]Wjժ]ӈ,R٪[%|[nh9aU\bҥ9IuK}[)0b>Xz.,F8_Q8/8WQ6*HDo#\1 Au a(`DH0Bwq!{'M9 !H= CEX"Lz;.OvG*3Hi;nfF,d4YVn1v2ōt ̴P(GH;%MwtGfFu'n? $P5ɴVJ"#6څ4ZMhcM2H g#f:(54biןi9Φo lQGO-[liq[t6ާ9LqP{I5g@!AwРO=dyI;&tO[PZٻb~mfvHuQpq9k@9^)_y_ks/doZC׵p:ca/X*nOƐ$>#Yr?qlO_+ZPs.94ݍp_/~Vh{oKEPk ;" k]:T/_kq{g~WZ}=:^֮YܧR&ߝT{@Ǟu Hx`-ZVK'8 Ȗ~y|!On?Rm=Pf`NzY(~Ұվ8X sz{;K]72ǯ 7?GDQmF#j|T:J|Ds{MokA^sۺThKnDnu(܄Fk}m~ 6FtW| CDhW7BBڭQ,'Imc>>[aP=2LNxkV5=߾֓gP6+ed[{[bkϭq䋨ZhgFdȗ"XXj3Q ԒjR~?!Ƒ/z٤ i"* s9["aFJqX8,_RZÂJc]Zb_7&Tۂ 1BELBx(ac^+[@-P/Lf4lRi8 NYWƳ@Wot;":4cS&w$ 3Q!CCZW2]z51_JL T 4oY26DyI>ftG}md@ԓ|5]cf κa FJd jpXRmpX;b ^%CWA\0*" =EW* RH)h&@U֭LV_wD$ҵ[)]"b.PC_pa7T[*j0@0tC/Z?3"1hVo.@ 1߅ xmxUxUB\xQV\375X*ֱzBTP-vlZRW--e*V5(OjWPڵTv-`jMN`Ra*vl嬈Xۏ8￰]Wi$][cCjÖ|]eXVrdAϠx_#,PWdz"մb-Bkصav,Q|yD^߁O9 WkG{ukue(dKuEϹTUߟ8VJODk㈭޿}g/VثV9̯~kbp-' w.wiߜbjD= 6zUS(絹ѝqyoozYF} o5 [XHCvLW7Z:\Xu҅}u=peWx*:܉zʛX;gÕ6vvTt.57υNѩ\~[; *TbETv0֧?3 |5y~TgZ*3k>/:_ 0Ti *4펀)FJO~obJÕ^-JX[Z$u()a0\RJ2 9펚r FX B-fx0 i[Ƙy8e mx=0Ff=͟\_e^cQ0=xc?~[ksm(VYezf|,ZsljP`a3[y::ul ]yf+| Nߘ[1:F!0k56o졹XS ϗG6z:ro0 a͙^VGǸBB֦1 zG-Lf+*R} }Q_헣b4,,c_ `>*Uf:,ըTaqu@,]/|0JDd_ʊ Ƥoj؉+aIjOC:RfX Df šٮ=@d!Y{7i|[;7X4< v$T!fdė(VE5KlYYrcVŪ-bI @Yqݗ 6 ~ZgͨxS-p3\ m 6f]2@d!>:.Ӏ+$~?cxJŽ'?{-II/+n*sOeXG-NYS -+@^J@]˪peur$",0ey e}إIbGSW"L:e#@]Jê7@ZfJ~=/`G)\#r]nS Ct)xp-qz0YXʝW(r5 Q{`,{k{`Yïpb=A`뱽>ڱ=}KY0PJcs`X՞Zw.uy:>{jv RET@(_c=>Jo?/s@g`NjǠL_[]:~A-5bl ,I5oz혷QSj Q;_}^ԵxL?z}'ܨէ׏ıOOk^'n v27?N^o.vR+{쩢ȡxkUy+vY}S^77$wʴg\-Fzi/_b@Dc_c>}|mӧ/k=k5v~x.;5A|G@KjǥR߷ԟfqc?{Jc2a-tZIvj}.{t\9;F4~DmP$9矟E^J`~g+r;Mpߍ5vk%I'Kے6l%^|6# ^;Blaexo3")|?<~=yjҧ)[Xd6Cv"-,vIZy>ЋH^AV*L-[>"FN56Zml4?ƿ-kfSb ~Ej"ϯ9~Bt#TkhW䓹+獍ڈHڮB?]FD>Yg^DSڋH/ӕIad!S 5m pG[k޶<͏}Ǖʵ7|Z2?FL"=v%&ywl󣹗HrxlOp ")vEM_&/):2LHSt`ebҠ/ЗIǃY;P`O3% >v|"F-I 0T?Q;IhLITi$lH}pCi͍t`l'} ' 䁻i G=}T^0:HzCtlC$Q=Wf)i[$=l!:i;ɏ`0D!:Ct`wK ,͍c:#mPH<߀{ b n4JCt>3*7xaV M$SҎm[)Al$t>+3log&* !_8{!xQ'PRG;"ҤQiji;ޑF)Yg4w$Q*oN ь17M>M፲#$}7']DRwcXM2HەǤ|:RvscMjI sHFo#yC\yZrSt#?$JI0ܘ]Ss;~wkUqMi*|v U锆0 T|8RQHj)OݎGTcjB9~ѩ=\$/E&/dJ'h^yNe\H`kLns͐xݚ*5=oaET/fS*k]g#\inkvu &MpєZlR)|-k#eAѝzȄv5wu8"մTÆp6Tp_p?d}>씪3xrs>BV]Ac&|>~[zER*z}%]GIo.|ݮ Р6/Ufp>٫I_69&0&J 5PN|ap힛{Oea#gզ0.s7yH7mRlI?2ˊzD$JMjaDee[t1V 8fҬZ9nG7 4VNڱfdۆ`{?lJţ0*GCu{nad/{rŚj|vG|B(ĎσPڵ>^P >Kqo(e8||dU`G]mv~BB6+x}L1գ գPԅ uZ;|pĢ* #Aih.$-{}:~X xS~PJgs[5b9T#X h^!ԽmO;\}p6W6c~:z\6㖭055mqPZK4nU]%<"]WO^6q}yGUBSZ˿ʶ(đ*ZPT ^_xBz=3Tˇn֒P[*|θm]X \_T_r1Y^ _"餆X0ګ.ylR"ZJ"sP>zVNd,i7 UV"O+zU*, ժBi_ϗ߇[0,& ]+ZOnwqR]ַ\=ZNzoXPq v58tR+ܻ;vw~b2Z4#~"~q͵2kqI{S_O, j*,ͪ~D<~ͬbSZ sn;joeXx{[-ig3L~q{ZV/EЋmjՀxw@!08l~˗f '.UvnA` (av KCڒ旁&Ӏ*I6lpB_義 X#~>* SM_#:HGjX|p 3փ8]JSoH7x|y ƶ:B }f(Ox,5U KYk=ş^ae"N&ԄDhWhyW~'g7Uhͧp9nWچC)>.@B%j3 |PZZ"(jѮh6k?$AD|Y6=㑾= ]f_ Ym_cv<;҂"9ewXL n5-Xj9mEzlhVd[xV$Sj,d{l}nEe-x{iV6b0mga;e:t"ŗN{ovX.&o NnBS W]ٔХC-`aK;ٱ.;?$-OP˒hoE vY}L L g.K y(c4fu2}G*HِɾRowTo0TPV0R)/|51烤.ўZKjr0o*dFNRoEZK){rahm }G1|cV3)Әr sAҤc0ެccX 2+*{ |caH?P d 2RWsT+yd!u!'&DpSq0:t9|Oq3*j|vcw s~v0PaK*Ɔ(sUQ367@ *R)|t^PT*Z:bǦi`,j)xGݩ6,"F}1BFκH8<ܣUgݼ_Q5W:TĈ#eEfj*7VՂKWSlVPF%;kt[bGJUFuۼWܷ- Vi"8ɫ8!dJ<ŌؽWGNƏSz-<ճxkZTޫƠB(P- Amhc_I@URM驖*N.UvqSmg#Nũũ:fq۫Er-X8kN cycyN~x|!.gD6s\.9eڱ։Akæ썍~e-}Lzi0ܷDZVr5D֚4۵~DB>gHġN\{,0˕ANѪcɈ_wޓ9kx405+i^7R*g. $a%¬i3oG+ejViji'Fk ٳ ',aFj9ˆAeyƨV:a:,:T{Ƒֻai[Ki/n]5Jeɧq-sOeI{{ݩ==q<'1~rg{doxJֿaܩ|z&MѱqSԪnda:ji4;m+?4|Uq׮KsEnP LfT—R[`P-S1˗0fˠ| j/AH;DG *ټk* wp@A8UZb)^u>m *R\J 0NT 5*FBeTc# >"gLU '^ŢV9 ᴣV;O-d>sUK0S> |00' j Ўseb˹.A,OlCc"mUH@3 Һc4WQ5,wӰ2#†ƽd̻'7'jBij+XbŎb?7}_h[mun\G>P+tkͅEFPZITm˄O,&[n=ܵmW$Ʉ(<~Q_wR|[{qޫ|OT1RZKsǼQǚ-5Wy%gH<Ӣキۚ7?_okjzR= q?ڶV)]:,*+:;.][аȏaV:r:Pe+50v"%lp`ʪSG&_|'vinib_A[m.J6],qA8Ux߶Z^zZuۑIy73GдpIA84jVm//Ň킦-*.M ogr pEl|hy?M04' "bej9 -mT1RhX)4hTRu'h֗F+"$)Ч2k<9 G:h(v^hyC1c0N!Ei[MAM UKۓV^CjN9 0p{P) Ɖoa~#L?di[ehQJ6v?=j4xI5&jU}m6Zh+/O;b8k/ ]-*/v'%~Brq/=v8{p?.B)P k(q'!D{0^mfTkC{KG/61v!q 3ToTKZ*V~v-~J^Y]=!UvS;TJUI|,Psw!zyq)v|SI ٽ:{-!#):AJ5=7Z*"TQjeSq.#mlRYTY9 ̷3k)Z߼V>ZĔJ*B,#dk-x]K%Ky,Z3P!W;*aZV)-jE4hh 6[S' |Yx]d){Pgms^V;iGT;7AG\ aر2 lNGfwl[$UZ;tbcZ%}T[EJJ=RJ XJՔXڭG;"r_#;GtvDm%Qᕱft湥Rk!VjѮo|CjT*?#/;X?+KtK_3*6s s=ܧ4QR! Z$1Nii B{](:(%F)A8% 6Z)yvLZژ ئyJZm ,i5Zj/297 cAJknG^X|R"6_S>SosJ6Z W;.]abG4_m+MDDJm=OrqP!KmE<[mc_ގj3_iscFgm?c^_cVvtU[y(ZʧvRƱi9\e Fk^yx5 ]d bG_K<7z^ 5W0E bWõWÄo2,f򰘬9090Ks`B 8-f90往W{NZ@LH=t=g;jL6D#,)4S&sLdʙ2Y3egtGM# 괘i1=EMZK3e)SyiLvLYAՔ/|ZvCiOS*LiLfTq4-T:7ϙ2fʔ{͔鎚SմPqZL T"f5S&|!jvLL &|޳O80)6"-i P[ ^4ԗl kK=t<(W`B*oL5[T*,uB* :4| wp4JNm=fPs*j]u+ 1=uI?jukZWT]Iu*Z,Py=?Kb?6sqD@!R|\yC,>'dBM䥜F>"~I@:0ݒR3eH.2mow% Ϯ$!D$0`+L$w;dMuT"$C{(4!3ʘA o1,$cXfsmDG8?* op?i Y ||t|wⓖ 9>.\x67*vMU@*T\[Tnsg!vQ kL^ .Ѕ(sŰftisc._Lc.Lp5΢Y0&RNcߧ۹]xn]jq`dZ<>KgJqc@Hsr ۵_0# @"UbWlWhH֨kpPemuhK*̎ 3j5 6:d; \; pc1KWE F*ũ*EQ"ˑ2[TSq#H3$1qQQd8cf ! BG@ШehL4 a#ZSBŊp-#R{ym}ZЖJfbđ ĉtF'9d8~Mq!bq BxF}zGsQ x1RD+ԊGH1S()'WMѸBJt1ª8mwA,#y?p*LJHEtɵ H+_T.\+la٨,PX҅_?_C/D 0TBr"+_b-A%TںH3,OhHsUDZpB.J':'cݕsC(F6˖ !`GaC!!"+{%%fZCV1xv1.劵Bu{>n\ 4}VtRaE)1P?D_!R\z\bplBm%/Њn| BF XޯcҬ}@]X5._tcaq28.1 2gDɐiB+16z# L~JIդX6 P\~{OefxE!qS c@ݭeeK{T[DU gܦTmPd/vx^W;>xOQ-rx-_k]v=;]qz]*jigip}*}s觿Y_\#vZ_qSF_믫O !oXGx_#M~=7znQb|srhe}ߛz~'614}MeԆss 8}? (7nP>gkku;o߭D^ ƷN~Ml-cbη\:76!rOBnwZsa߻^x]t*7VZ%X߃ کbm_;u ^`Lzwgf="_֥ /Zoaw3tZNjh[jZ,Tx~ [d>tocS7icϻ{f>Al5x`;;reE.TO`^8tH뭸nsZӦc2 \kl T_kemOk!=TH?h $jnm_Kzϥ&CR$;^~A<B߈VD鶥j ! "f+-Rmn_ןG)$&C:ŶVB]KR}@'*RmdIƘ)ۘ ArW~ɐBE+"Q,WЊ̷C[ٝM,ɐlMBz;.oVB3|]Kc yh4+aJ:k,uh0^+@' q, 4iJy”R0!Ag놡.8-_sN1߯ O~QgÔc_L[xL}| \&Ô# :--曖'L1_T;;vc!*2%du .SeѮp*:+a 5̝ZZ!ΦvMC5ttL:&n [y{̵r\>~kjҕ08)`J4G[a+8hL[ƭE`J+psli2 ,lF1x.)W XX,@1X2UB[M`- W)_aJe*]GSptx )`Spb~Jw̢TFmaJ4D)*xt 9*% 4&X1Jr,IJ.4T͘b R`mn-Ǽ(=Pҵ42e(L157Ʀ@'roxु+|f ˆ\CV.1e;6 ^wS9u!jqKb=*7Dלwk[ӵT[z%R-vD-X%+\ ף\JZYbY 5ղF QOT+*R=,ĵm@T6B,JlTR [(e/ѻKUq֨Ŏ- k\ usw<̣>W,zޱnxݫtRm gެ)sc|l=_J=i'6c5psӟzZ^SBE ~ݠ\FeaAMCSVZ(#7߮ ~A[:ւsBw=?iUjm{>0qn9 }x(_{kԎ̺qSgoLոXK\PO7ݹBvPS;=?v^Ԣ\zT򁽝q0UOwֈB`X˨%` x塄1^jx7(3U e=UyX/M>ևD?cAP) *wG/TvG*eJlCtlX[*b$ y4>TV\-)- rMjh%5B+Gh%Y".hIPQT5M.OW@u\0T߻D%}y]愻L8p*2M??^tSxrSC(lNaINuv $[k|.;UJ`qGS%P'=$q~N:02R4o 5e%AI5pN|pOYIhO 0N/yGZTPao{MKLVԕR'R i!eD !ZlBل! Bf&f?M,%]$g #YQeBK5gY}@β%9KH9Kpl$]dhIl$DldRf&:y=$X*gQ''N1 F2Hɭ.~yM"NYȐ5e mQ)&/aL)'dà҉֬?^vJRc!EZQ)EsF@G_N@!B^kȶ¢mkr9Yxd)1'FNL0CQ2ɐogJCWVTjLZ5.TrZ*:uGL ifjwl35Ta ^ءTmDP ģ*:@%z>- vz`u-H z;%/ \P )e j;@c2 :/\ eKTٮ(#8A 톚>TTRqԢ,R?"v wD:ÎwTXsaecǩ8"aKzCȈ7g p/~xu&mwUla/;vvNz(l_f։hms*rjpZNfT`[Nz[N%+MԒ@ة[T1u^[Oѱ#բ/v56̿p0>o6)zP|f MZIkCաk|KukFkWT1F|=6I[TP\*cGTNtQ^V5P ;blbeDEJdpRd5" Ƞ*0w #cCk(I)5 E:V%kΊZ-^20YePJb KU[ ,j1CVVje-}Z_D  5Eڱ[dh*TCqPb ٣Xh#ej-ձYA%VO/Rc]5Z#eX.ĠB-Rmc59jT'١Xgݹ96qn<\kd([I%6FϮH}sllcq,Tk ʠB. ?\^sGjeP,Z(h3CŲ̱%8YxGVLZ!MǂJh¡Rjܵz W*{/B@Ŏ@ .Z ]vS>  T*.: U肯 *@BZZDž**xܲx\p6.? 8JDX/. ]&Z9q-ȋ' ' T@ bD+o3ӱH?GD-TUӱk0p"K#`¼: #0aH-LN0]K0Ă XA4q4@@ܵLI'8 8ӷN0<%pCt.2bS|tt~>`APq^k45T,(._*((( ˽JJ!{ cG RaPT;j^+d߂b<-Yh*1e]KX}#Qv **0ZJ ⲅbpblb:1g5seǐ'ʎ}*;6`*%d>qƊQ o 3B sR 3EcP옖?+Mc9u|ꎡ6;թL?q>F-:TN$ƬJO s?Q55 lI38flйT*t֏Tp"(aƥf^u)a%Ծ0 S C 3Bq2>x8ߘs[oTq2Bq2%ʎɯQ|[ X& 3]a *Lk-ay[ Egۏ7VAba'$+Мc}%ԭiC Dbao xw`mF9n@/RE1z?PwsџȜhakYo|kEyyNjY?ͅ;:.̊%6xM5zl^LTkkv<Wk=sBiBm+X[ZmRg{îZTl?؃ > RQ;Z,f(<[-<6G\Py,ɷ5k&uVΞV@[Sl{ ~G үFzwO։>YxѩHroMqv3͹=ǸsE\ל=8#܂jqs8P׵`s{K_o>fKu{_7oy1Bȫ/ 1JUA Ɣ|gQ5zUPE[5Bls,`c!.1 U[m'z u< `6`K  %1`=k5ZE`[[hZnuw p)NpPYDC1TK ¥AD掍c#gyFZ:Ʊ,(3U"x14NH"*R37lx@OSsz |'#J%JUNF@8{@8Qg/8j]¥%JԵT +TJƒM}@T"՘ؔT刻ޢm~Dg 7* '`8 W՗T/%$d'@ 7R q򞽭y?@~5 ^Qp&@@ŽNxPxP X/HO@zC;HOK4dbHuSRTHvR0.BR;~?o9)RR߈-qLb&RKos/~ʤbCdR)dR!dR~rd?AgŀRea![J)i#-rRGk)G Ax]L*ESus'7 ޑ,[J~B} P]K-"z'-G~FN_q뼒XIٲIro/CDN HO'۩7[-SD~kpNGN̖}2pb-d[{ ŝ5\Sr]rbnTH5'Պ %)GI56Y{pO/~RZRbQBFAVfU=Z#D+h-ྸ{_W'8:\= 0ԆӱZWkXO1`+*R1@w1m^__Z+juZ!ԉ@Xi2zwҬq5J\ *e ("-7vL]եR\ #EY?ev >B A4$#d|_;*D]^ !:}8|)GZ ѡ!yD8kDߔjưİ~1,B OW,30ѵT&ZMJjT'Q' *du#*! T(%?Z$ %YQu,j0}-U8&J?a8w~GYTc5c.FɢjeM+̝ Q,ٷ~k kH.dmcձdR[u2VѢcE#cѱnN(M;V;v6LiCdHH= xdIaSĬO,* HX l6eerq-ʦpwdJ\<:v`tMõ[^\%}ÍC_-[-ՂnJ-¶aC_Zifǜub*Zmc}ac}àVm" e*oM߳cV(+hBda #lX K/8v%v a3*ٰ0̆c6,>af⡎ٰ4ab ayi؏GW ? $pGŷNnGĶVle4jCvKm$xvQ4B,#,8v$AjvRB `#Q(AihtQ8 E A74 DG3qQ9ROSVә3tc#; 8#A#͑-9 # 3#fY!r#:O WNGTBL/e\ɉ+&KBΉ$c#qŐy Uc1,p -WcF\c-E!ZMbh2"że'B%Ĉ9~1D~ͨhE>.qaă0ǎ07R#Băy!#2#g! ?B Wᵗ/ {#a?KEUR\;*Ȯ [n>y_3C;^6-xe(^x27v|Ka\'PZw}$Tm,gMyIOLbIqƩg~;b3NF >:u}̕ty 7ׁlU@,KQNNzf?X^}p0U]O#du mˁXT.#bKq o.=0TQkrQ=t9(lϕ ffг}}T?QY=p+e.cH6.}=y5Z; ׬Ĺ'Yiڱr[na3??ʹW=_tu,g}d_/s6kJw+6kjft-S-X -rΕokGH;:asR־O3|G4/v|HcXPaD_h4xl4>m4ա@%mG7U|5jö;Gh )B+__^E\m4nPoM_$tT["↊B1n7T9.ŶB-bRZr?bv%4HuRm-DҨ9*\2:\PR-nT;R㑧f\"jrWZHK\u?T¦Qw[y 3|oB-P͡4W_JݮZݮJ\Pz' T[UA.jnBn?V‰*_ajxabŎхsC.jpq]Y/Gpq>ϯLkk7Ȳ5SڍEpIMׂ/{Y_:Th)j107}R^( yi)=vN%1P A.Wv!'tWTw{֋ .c亚\{q CePyBQQ A|NonP'T.f1CQ@iJy9: _CD _CT_Kq3`KA. Tr!-RoT ItDq !Z : 1߰\!.j쇰T q `%߰d=7|y1:$!"Ǝ KXa5a5dA2ڱa5 a5tsRLILJ+>quwT\MT`G"Ʀ~{s!-8ES(*S;Ҹ֛Swj~X/:pa\h_ ψt%ɕH"ZtS‡7[taϘ^a?t[tity$҅|MPy<C/#SB^\,}tXJn+~ 0_x~va5Sҭs|Y/{t7U[6u%97ͯMv:/57,K 3]־R{喭ybkY[Xz΅u~^ eM /į^_: [;JyM Ϩl|V,`*B aFEpU|U@'W'PI8"8+ 8a% 8zdG'Q i߱=VIG]'5<8OȲ8O|qty |Z9-AxF4(4([eEѠ$AaGAeَ>`FIqbFٝpPWt F8(s|wpPڱpP7pPZpP},q΂Fi=I $*88LrgRt${xg6,:T#Oᠤ5pPF8(YFF '݌EgyљMC\ ']p 46XQ'9"=IfDzEzҍ] 'i_qD[  N#lXMDtlIdžJLZ )TP!9oy +[*ccAұ1O{$m˗ұ]P"BT;d[~ {uAkzv)FiFa-FF(k ΔGK Z*FeƼm(U(-U<([%,1<1r`%cA"=$$&\4&65491{]ןVW> n_`_<J[HZ 4Gb&F|Sxʕ-K X^?վ ^9x#.ە8kZpi-7brx ˮJZ_B%U4xI]t6} Ib(Sy;HSyp<ӕ4I+i4t*ТYi)M)Ɍ3rJ7Y Sr@6-P%;()t-f m?IJQ8jL)t?LSx!b 7pH~1;b o@6 0W'&1Td;ϑ̢:cM,z̢S /NXS^ &5sm[}KY478Na _x~Cו7fL 7p7ksmz>k^m`4/*S$z|U"x]#st\w]ՎolvU$pNͿ Sڃ[sm֚R;Tޏxm_*%._huZ}ղ M=*hbZR{xsV:BH` =f-CU77$X *TB K*rK\*rW*rmW)k%맴R ;7ٿEE7u;^]XKp%)>66_J*U*xw,1cծEks:|*ک|Ţg|{/K@2ԫkH-j^]Z[Jp'96G?b7ԽvCBO:+G+B+RJ68-^hex?*u+k_o!^'mn2s/: IK}r;< s37X =I&)Nx[_59|N><%]~oq}R=V+\Nz%kW [n&byJN ??z:l!{Uy6m}EJa/xblSe*vvGuؖ %RODnԇOD-a{*bAX@[lWR$ D$ ̊6T @oJ:wtŒ[1V:0Gй;B @ *js):ͥBT\q-mTDDDشz/zl?/WoD %<2Ć$bڸSOՐB 6 E?gQ6gH3;a1.=4\oGbr^׺yͮeoWy~/Wm./и]ڥeCSqP?CkvsT_뭷h\^JL GK'#2~bMVUX#ZUy@fiۏTk)O8 " UE81,m6*V^{âgVݱUi+As,%h" u0 ͱƦoO Dz+IfStF*U Uf>wh-Ja6BA T(6C/ą\,<)Z=y7'R5|NAM-Rb@"t@NoS|OРTAhP"f?`w~$ SX"t,Q/* P[^Tr?*ţ^6EWXs28m^cۯG; ܧYKuRezmUnS1&Zx#ܫ]~gh3WC6,(!OH[k#ӷòsʝ2j5mnGO~jZrlA"Z|/YNe-ciIՒiJeequ-˅uEXi e-yJ8!sv@9;P ƒrp-T} 8w8O=NrǀS*Fd;PRɋWD'W":H$p$l⑈[!pxJpxH0x Fp$ !8| xH# ͈; w܌:N\7DB&/ z#"$I"ZMoD)_*@lެ$hq%" m*.o)Xq;n7Z ݑH`KڍSn>N@9+)ZG $މKJ!Sc) o.'+)M Ɠ$wA(3o>lG_x̢Ƈw\X8@/i}8`Sre[`!BZ)_w1~qA76'heYi)Iʩ*8w'7'P0Tx9J0ÂR,_(ݬ EcBC̊c+6 ?XCÓЃ#G`crx/b/{7pmw*@ J _}!EUap___X9O?چoT/=HPW"'qJdH+x_ץ޿?c)`)n_U킨5%j׊]ʮ/ K7ۼPDr_q_ rHM$6xf* Q}"C/FGlS2ƊY=>eE1ˊ,7gvm5=}f"J ,c.Zdemo˙VfBZ)IhR dӘFBcy,XpXm%mx~1뱀VwRg!fl%x'IzWK`(wvv_ϜPP JOz؉,n+{CCYG@rɎbڟlhw3:Wb|QVV6_kTPt+{Jͭ=-4{Cz7ry@博\]rjzٕ:!R+iWD[&syždWߖZ\?R\Wꝼϟry4kd+=pxuio,®(A7KU\Hع2⊪?⾥:" cwnaq^S`s&UTU][X x+I'(+t-?Zc\x vwGm+ڐ8oQ*/ ^!⾵z%:W?#FP"cEU_UL_,n`ʅ_6{].|@ktE+I~5⾠[b\^J8 6)87wI|m?mӡja ėS=@}Pw&8KD"H(:oD[nʵFJkクzi[QVu&g$ 2b|FBiI$/ߋ$'L;u.;C{2Q]XG݈HI)iڑIf7+)vl$*AviQ;;e&M܆vJᐓQ&'CAN !Z"[e(﾿~c +)I$BMFHHVH W9CVU,ZnZHEP9tB&F&5DʤH> *n?[Y^cOXjҲVvM_LcҲI˨%[oVrҲSVY}J)37Խ4i2 ~P RoH%1GZ"񛱊$"I P{krrɑU1#_Z9OF Hg^p[u]{^S PBgdk%ꋵ@_m QmP]ƅxW&ԨvBxlY՝]T_7mYZT$_*KBP ~ |T___@a숢r`%.%PїJq`kXy 5SS-TvZ_Ӂ +v+TErQY *vD(ރ}<i*fjಥDcSoqRac$'TX ѣd(T hD{RX Q4R~\xn> a:k̊BNa1* B10$&.VA|NW'ФPK{ɲJn%Q\jMaD*_jM|}dר&I2EbB!Ʌg#Y5w3G/IRhTT-`/zajjꅻ#Bg= zBU1g |PU\KD!0'ʅ sN/},'{9=ָ+?33u!3a=y~^~q^#J 5#.ays45]bXG=?2~F;| p%:;zt׆b(+TDSa T~:6OM@ SrvT3[pQ!TRz/>DkN#P&o6rJ aa\ 6|o^TmmYs5}uO ru޳kExtZKV>pʛoK=v/=wwX|(Z>)/^3-%Q7<&7j{jgj1ڃᅏ/0d̍GZhE-[xq].p+Ko.(k`{]`x' T޻ŞWZb"_.N_t:IT{O.'pRZ#Ͽ黉^k.s\ֿ\~ZX֤서a֒(l A4`٫UD`}bC`P! *+Nc-ʒW`l T u*)tk *D>W:HYrDVqwd)d5LVi$SY co _ f?ra86W/2`@lZ3ъ 1$1`0:!bs~TwTmرZ#]勊D,#s숱in ,h׉fbCD2Fv#c/q5~'.;?772Ucnc!vs0UwF"s/1:Uo[FbQ5T)X7T`*zfXw ]%bˬ:V\RcP V[8UT_Ai`?7ApDlb;)u;HhJ *RC0dYo?l wTba%9 C#QIhL1iw!m@ĐdBb[K"cIkXb\ 0L8V!w%/k;h H@rWBrP{\ƋTy7 %R"Aa@<$#"ER ukm6cobN;w+a=[Ýu*Qg]AԠX4R>QbG.P'XwZ]"XC-[9gWhcE4xjA4e\e-tLce2$d]+qTt'Gv-7jXαb{iXlKc`q4s99^AO,9e>yPip[4,VTAVovl}v qdA*vv[U;,`wVI[_ݪk[egZ*`15ZSYuʪSYkڷք4F0&٭  &ͨR3*Ќ Ռ *4bG4 A< ͨB3#K :E@eƃZL"S:ͨ6JChZL *@E'=61r!bM#FZXh%JGSKl+[ VIF+ZZ;aXY-ae-aeEmV va".4 +h,"VJJ,dYY_WݗmW~ymjghSЦV]ʎhj$ *4J:kCSPÔXpJ_P!\ :K|0G(X? D+?WF[Z%ӴbF3ۈ*h#oHToަ=|{ZecVՋ&eB?{ZE%`i{Z+3Cu*(8U\UTC}4}}i'aiXBHFF^4郄8E,6HH $3HF`]a4"DE#/.7*(YAhd̪P T$:UZS*xPoT,P%X ua*,PL@Q@JmH*,P",{ɂF%{vP?QA5a$ yԵԋ]AT*X:RAR)Z-SZZe׊b\')"^~ljhcxS._W`O֔;ٵ:]K1v~ٓY$ZrZ{NcFpiܮ?~WBh,6xT!(=Diu.ݬ3 qpZ+sy˝1 +n~?P ldžĵaqcq2[oxۋj*ӆs{a-FU_ߟSƘ^kVO3 K!7pK~Ww|őcP)\\WELx RHt|ǽ.sBke ec 8 pveۯ(Aqj *Ğk-R"@U0Zm0V ѠRGX}\w*a*T?j(O8{5N.鱕M?_f[v w΍)u7Ԇ"ny8ΟMjFZ_IRr61Z(m y*Zg}cHY'0OjS-kl&VKgT+wZuu>qZLkA+ #oluKb֕QkX 3UdIbCTDCHٶ1:;EJxkv()>z!.7-WKu7-mяC\$;bgb+Ku{vbkdzjfeḧ́ Ӻ8:E|5n V ̱^qxL9+@x15^BRT(Z)mwEʅ# OqSrCzשTG sQQ|ʽJq(=Ǝuk@T(* ֌ u@ۃq9Tځ=noj?_ZwюkrtOeW׺}?(>U_LzE9Q2 * C^\WO};\+%Fr̷X32kbϽ̘_5O _?Ylm=EY.ηSQ1.c+tx(=%nVxs׭:_DS=t@aJ.T#{2k5?;e̴ 7/8чqVqֺ"LN:μ`S̓Ns.Etk~9ZMqC<X *T( ʼ9^|^uyG^ h&k"RiE5-\Q5޾La[~2N>WWm[kj\]ɑ;U39JgZ9k~UV]6 =k1hދ,b#zuCCLܻ;FCw0N?}_wu֢ z-ç1U5MmzGhh6ހ흱&^5*;w,cցx%tHA,Ӫd텑-.ub !oXŒOl,=b3fv$& oo+iaXK w#Ll6C[xUxG!f[.l]9`V]D2E ZD-ۅ퉤UVl غ/+nmr߭:E^djnw 2BoBoЫ BoD ໽9a|&,K2"Do] wk@ߕ[~YL!zu@߭}3WWg h{ q>zq|W'9EηV6V?=}:Z^c-|maEF#[Y}uGۤ*m*JVʀe,h++vDm,5`W:oovlMmI >iߏGUTQņAՈDd7 qzp^~ У7WCbQ5_ vq>-]mחEΏ'.ctd&_Qj q!vƎhRY6ޛF(_KZV"g_k1b\Ll?#Ғَd 庾ׄ\k4Βj;g퉕KõczbNu uO5X2bweNX_ϹB1XT-'_ݮO?oNQ-A{u$O`ʎ%ӗ=WEd?`dG;uu&B꘥Yoൢrgo?M"C-L2Xyʙeg6Xl+EՒf Zl]^S׹XjdXig,51̯`WKIXo,'*`+J[AQ(VQ |5 $$PQcQ&f&I}P$Ԣ&y奴y2R*U-lB#VPDUl%SI2ڏIZ3l%a$b+ib+ٰGl%bgJ&I,WtjL"0r$N Y4'~D`Ulo\L sd}<#ldIR&=tB\t>Lv+"Jq>DUp%?5Fp% _} LD@0t#P^,* 0I&+̀$]&9b+/[IZ:`+YFl%ር$+*j>IX I5i75I|5Ii'i5WbbHjZ+kXQu+Pס8TĊT[*THR?+9t*0cUܣF@0q譕Q" Z" "Uc?TJ8\V*b2*bP>l>XD(WWx}Cq"_". zyAZcj";"Kw2Jҵ!ԘNu ei1 S0lw`Mix&*7Y*3qdS-f-K]IXJG$9븐aԗ#^`BC+m`9+vcnKS4T$YJm,CHQӐv[o4̤,D$Qa-!Y?c_嬇G0Sg ɂ7&ABHv%d@J- O qr |=1T .0G5q~=/Gl^woLj, * Cͤ Tqbr?cw%HhدOWk[ȑJ.E&ScTTH?\*H%Ҍ4*s1~̤Fȥ*2x"l~z7; LL0xԇĦ&*2xǥB|eغ?w|_憁DAl(fX2+mUQ㓒f5%+3nҗ?8<`COĭ Ҽ΃ w g8QeC$*>!ڼ6 ׏~ktezݠ+.(n2*"2/ICfdA\V=܀L1&|Cf0u <1t+bcelCю+ c`hZh$U&)̂$V Pab &͗͗kL]x&ϛXrAяP/8|s?/ťP:B 7֗bTu2k(=j:G_q5dž96{e/kk}8{z3q .)[hB 4&T8y;z9lɟ\8WCnJa7Xn]hh_Q*UGԀ-UFH*g3X g@?{NՂV96(h~*&Sj؍gS?ġFj: I爧 α2*_ 9 KuDt}bl2]DcK:]G\Uka^{_9ie)H8޷^ݘ4L0N6dND9=œչ9bss,"~4͑;G;>ZbM08G9588GDG #q)zt$:Fϕδg"8G$#qi:F|nccƇ16҆Oc16~ cltc#sM&x:T?16]c#s{D߉ a7za7zw >n| ntd؍8FTv3 lk"dϿJJZ\lnŎ \<-$q?Fi2wdlޏ<yOyM/3޹ӔGz%m_?J]׃lw YaqI!9oYC0nf[}jZcVGX-@:o J~ P2B}>52Cm~9뺆e]sWSk%i1Ӊ J Tkߖp]/C%f'^NyGuųk+vS.>3Ad4_I& υ_` ~>gO0GWbMQ-lDޭېE#쥨 6/)pK Kd/g.?p%Y{(Ku4]nT/$ <k gQT0K2Ǫ_Dc<8嶶n@'i"Txw\.;kliMj&B,T{I {D[qP$nTyA)5Ԥ9-C8%$؜RalNT/T9rR9r86k9Tj-1TST I,瞏q֨.W[)9\*ϠBs?QsJgϰE?C(_).&Jsp<(rHgpg >s?粥ggGP\&q7 nXd%M˭!x[Qn5SgU\5džWYG0f꓾j!P#]IO3P\gVЗ&?V? 3lR#:xKDB@4R" 5E3Ag*M=i2[dbNP όg"P/H=ej!y>Q ME3n>ӟT5͂cX,j&-I7|E"c"cD(2A]h}w1|˰ʇg[e[1.jc+Iܐ>%`d SV+w%cY3JqyWqTcP= hi|I9x:3З%?E&_` ~ ~A_|" ~q6-- ~i7)T*UKy}_J^䡒J^i+yCS Qc;{ *tG*͒)s1٤> վSWZAK>M%P싫žjAp\vQܾTLII0$`x#BqN[`}N>FžtܚTX I^e2^t|bC/ؗeX|Bѵ:n4xxa(52^(iS^dI6HFTȈq%#[1_W (dZw{ @J+A*wfs!jZ9HKDլ/ZUk5+~<ֱCqI]9"ti~mCWvX, ~ˡ,G}?CsܕB4+ nodKov|lYV mЄLofL\K>Z>!ݫV;[@H6W"OɏI_+טZMJ %(mIjB)hb}V%O–O{~mvo.8N__]bޏF.o_|Djߠ!"(pR*͢E*A/A/LZ-"r5!cf.hX\?^X6 a#a y4T .a4# 4inHåA͍otV*Egn{>복NAd :)91SrLn)9sW17B+`awt"=#ps8VHޣ1R qkdaxB 1B=b8RH ^Pzx|W< y@ z+[?iF-_Dpqw\YTpD_=TS|/U5!/.瑛|"cw%LJ Lc6a*4wu*|HRy. o*JRk X| X;&NՆZ VJ#Z髥i jK6 lkVh-GS,B\nZǫ*xf#j%VJq͚&0MpF&iPk<ʝI2h*vjDћVx!Q7NF 8Y^cRksxe;5_X',RўVQpG=Q8o ʊ3"D QqĈ3mAiZ,.zBY5 (`RAa, aPDp##ܵ$L 0P8 ` `ЄV! `s!\wj)` C#F`z!b0d```P`+v F!S^Uib#xzD>`:x \!<00 xEzaPGO]q@%aQsTA>/0,/0R@ aUa^<. ?8e u@C _mzD! 1oO_"_@ġ"1P0i`O_0bȀF̗u'H\*AI9G 䵿i ] xg!4Ċ(eqKXc4@_`>~jT]70qPG@\ K\r'2h۱ 6ʖ lri E*h20b&ÔdP1U1Te3%CLG2-溾/saQ'TݎH8B w% WoU\)#\"4@H jL_;,Z1?=ڮ4$g ^8n\g2K,cIqߎ~ߌ8p銕y]s~ >`COc XBc<*}t->ý/{p/MS(J2]dRGq?淉ATcoc(wx+10a.qm Ӌ>LiKtnvZI+u:@,vOGPgyʼn_[ iuizZZ6 Ặ&+oDoKl@Rugk/0CB` >10/ڱQ0J,ԭ1y}icaU(hxr1N~? Mr vR韛LíM^~ $iǩ:ی K0Za-ԛ"a$峦ퟺRO[+,|*0\WbRjjN> ky@_c*ƒoM\>>~$5d:xNkn9?/QU˖fUgvGV-󝭚JuSP j.Qi-SZVU'95TDA!/v ND HmH_Nq;KvZҰSᘿc$*9vl#޷?B^۞R~*Pq j0ciŮYB:5딚<:aiN;봢:m(f+̊[`^[i qqzǡj>Akhjw^_桖{M:5T nہ=.DNu*//#Q(xou9̏$46ʇTχO6 WY7iIߧ 3!e45rj3Km UKpe*)5 Mi6ro@;˵T*g3r)YSZ{x4Une^WuvW{<|Ec;"|2R0(Wx QH n80FdÿlTEѨG8ip&)o(jh*2 A P j=b+pP$_ԠZȠ|qcq8n4gqNE /0 $Wo3 A ۩Bx1&CGBFoȡqfס#aaCqާ9f×f˼fCŪٰŪ2ߪǪفUَUeU=h!֊ِbiNQBim7**iJkKZsKkRKk|*]b* 6D* VbimPZ[QZ[6*pTK} p+֚Q+ ]Jŵ]JŵRq$P"UqmwTqmo9y{Ƕ>\Y\+oqm%jkKپ T6oTl eS6["ٲYP6T6KlwSl6d٬-5.ٚf[6[W٬Z6CfKYlwf WAЂXE- WZ+;lAl7 bZ[*}?ϒ!R:D"rqKyJv)㨩J@VAXcklT(퐮;p{ciVSGe:],%]WܮUDVJv7@pv;$0"Y"d:-yJv Y9!ƄfvC!cCA! X'T_B/t_+Q~<h%z!B(%?9$R5$gJf81X"u&;'@t&''0{ǏN*K{B)ԠvLlj$pHkf_ҶX[+<鹓%(CJڱ l !9YXJ%J>V}PP)Ŕ4ԽMTv됉D."8-ꥃ|dmə33RBQO1X(i*IPn jP˸JP{ #S!rQTJ5tvl( AABR|!QآXՠ߈⾱α.vl*FJnVCS>׷{*Sڰ)BnnNлAuEՐXG}O/PX"E}.-eܫrr7|[-+zQ/f^B-j A`2Cdy%?okQ2oSUw6쵀:Dsmfcm^)EZ7hTeet@wɥYϺ[bˏq4kƵƌb uA5)2W8WwOkM[;!Ӡյu8Tȕ6'?,-LOVOjpVjP!uUl*- Gv!jjGL,FhToTuǵ`G,Ŏ:whZ 4%Tt&j-|KP.R IZaO¢ScZc;9٤DzVae4KPuT%G cu2 iaDI czVPSk_y\&b}dzY=b3m+pcu z-Ŏ<u-[+i7L&sZhRWڢ^„kkQբ^yKQ3fsi{{:yusM5]T-֎-"@8 N?&t:I58yz@$DqT-qb'f{A.=Tm/|ʷDwOf{0Zkoa5p-8}P1dgwD/>q V}ˋ,OX+* z1n)f4b/ٮ ` qmDj7ZP"~؀m!Bd=ggלNTI9BBi9qUշ14>V OU-SYRb!,~]?KSz;uHdR,ao%S# dwۯ;Ӂ["ÑȞ[c,Ndsu"yOݻ~~ǬQ 06HnՔ֜rVA{#jH8(K4X w:KuU&!kbyB"uLkkNi7 bI)JJcD}u+~Z)c)C)BY O.\ed(1fc_c(/.ZH?߆TߟRqG"˲2{Js{)8 OVVo ae'r,QmZF†>V{ZtӘaCk pkRMT넹%@C.Uz,]> s{sQ~$ø~Z|D)^n[r'RmYdWD?H P)[H/{u4xz|ZyCZl,/O]VO5)gضNPSZsYuj5'O,y׾yj;[}:/Z%=c/\| QMnrTMq]֟*V뜫ӷP{ڤ3u[>oK`+ [|ʳu: UlE ) k/4p9U"Mx޶΢X9V=g+ܳiU ?Ͼu~7-7{ ޵*[}mu[Dؽ\jݟw_=׬bkN %Ǣj1u}|rO3v?ήu%~:^#lﶙr hcizln 09۟Nm=ΛVW bu>/νX{ӹO&se}ϬoՓ!,3#LK;.x9x>~^z)=g]>ݞͲ<羟yHG_czTGoX4;場hI8 i \J!,X)CX@*#U?4I-'Ҥ,Zd_d~ן}ZX n~ZpA!,)CX|Bs`) aU:aRD~)`& i'8hL;Aw N`]vBǗi'U&<bUU"Q!)1` 93X0EC{5s ,]j.5?tMUsZh ,Ј@eB.V;s,d QS$ [cpncQa@y$>#K#Q0uɣl]!TĮDbW4]hFOD5/ٱ؆׃g %"B ٮZ*įkP,,AHZL2` J=E*eV k-b Jc*4Hc?5HVw'3| nPp+܊Eޒi9cDBE$ -TZʖ"*`!kCaW.6R;\`ȕVtȽx^Tc܅ re) д. !9eR\i@.P L'~$w<Z+4 k,Jw0 Ke)s,u(R-͊XMW{pzۍIM?xTKlQ{qUXP ڜ`zfg'\B/o).&WhMK'uㄺ D]>נTQuhjmX{g4wGjsNTPaIcǎjE~Q6(fXXۖ~XS0[wtqI0۝2Ka~R+޴<\zyGOԡDEyRlkw\OI/nE *L0!_ÜSlةo}gݥ0uTqْiki]a|9V;Tk]A\'Xty?iʼ楊R *Ӧv2۱89aZ ?Re=rzٺuNO]D֜i:״T8-Uvi;-U9| AU~W%=Jt/:yb1\'QҚT }j7Oo2Tj]+`ju'Z RN8_{\vo[ie]om/IN:T|uv;T鼕2s?-<̝p:G&JOpG8->sT?׬&yu_;uRj˄laaغp}[GU7/?#G*NbW|3 :k!_^cϧюv}V,jWxmCTpoy+d;>4놥y`{Fvw`Ro(u;\w\TJt[חђ6m<{`!$QB2)iyc?\Ӫst Wm_ϫغ5w:O2y5f{r~݊ @!z?wӵ.{}W:]>u;WRm o|\dg|/J-AlA|B__[i~OP ߷EqjvāP[g}yl%=RknA=GvnӇnf=KZˡ5naOs/v)Ļ>OKdمT {&cgu; |mWFB?Wty/meϧ? 'rZCYiP}/N-O5?/1$[kFg~~kO,ry_.T]+JfW 240%ZJpukp (1D PbPT%HJ (1$&>y缗|-`-F8o5~!&ffX׀l/~jfmyy]淾}qmR"j. vvn O.]y+C0Adk_ul_Xx5@څ>-y׭腷k6l/_eJFp_(*}qwzK}G>=S%RJ,* `81iiK@/%7 ɣ;}Wؼoc1Fseni3f7efi[h̕;mc.И+O\Ā0%/w":nuuKVf.Y_cnV*+GvlSL̬~L{t?QrmZ8i1)ܐigU{V{VVtUO;[V;[!.!>}?&*D*qTc D 1Qc *Qc j1vl]GcP/\1Dbcd%ƨRU w- 1 |5fT&Ua.! @ֈ2]apal\`qր0o#0Sg ŴUU`c~˖)@Ŵ\ ga: SABA1\_88Fc)ӝu-`AbA/Q+_d>HL;buB]lcDSj wjДyZ:[Lc J2(`@`)w-$rcC)V{tĝjiSp`oʉ;M wwNQ54DԙBAxS'lZq}M=o;Fd<1"u6x "M ku ̷KNpW'$E$#+S!ૉS]MUq"U8I&M$$IzWRi總^d3u00t2E`7O'Vdx6LZoq)|83hH$дD`m .Ђ+HXiw:7R o6ohoH/n- j+>M@!zW'2Joꭸ[H8=V[L+Fo Zz+JNovL)~ f%FJi\N?@v?'|VX@jֿ>!Np\ JpHpKz9tm Ӎ.{(Q;g{rmꛕ26d.z+/?tༀj7N@0k4gq}%{ϸ|X0]@)=7sHƺ>3?x% j>ATh>#Aie=ZT)! ТcD*jiRHf>Bg) ",Y Fg)jg)YZT[^?|;t*J^XSHFM)n~v-rӲSxTJ7? `ɴ~0rս.U#TyK.U8Տ/4 F/+1^s| zYp^V>7 3C/+^e3X ˊXKu_φI *vTR TG*w/vf-OOy?-O#"Y]UuۥإcDhR/kZY⾽2/Z*5Ɩrx ;^+/utyv-u+uvCujj:^::^+Ou֡ڠWI48uZ^l^VB/l:ኽi{YڵڣV/k _3~|*o/kzY)JR/kť^V]e'^DzܴU4eKb/km#R-Tu=K.UUTeR^KLK.վԥolԹ}u٥ZԥZG.Ց]t[R _R ]zwK uԥZT_, "ؑlWBkVRv;4= IخȵG:)Ԯ6"Pd"5TJ FΖ19[ JsOsVjb )v&("& $."* z^R i[("5i τGX.HG൚2ƮrcZFHB[ [֮Az&rR#VY֖uY;14^Yy~`;k4:u$H ͦ jil pLk>NSZG"`^ph$5zu䈓WG"^ʼntjtRUh5,uj:N@ L6Nlu\SXmǚ_FKG-&@f[j)qދ̼dkٌ$Yj|ȑ4<5& ׯi,*|dyߗ˟85i&jFF 1u ]:%ϓ5OV8X546ar~;=kW4zu܎W+:x5bwx f8k \Yv55D՘A?1Ws&9ݱCT 7l.i*>5Q?|H[QC^.oı8MG +LCq4XWj87$5}46]=򓋘]Qm뵳>nwX"D VP<"U%Dd|'Oԅ+myͧ>&+!K %Ĩ$1f(**$E<_B>gD@1(F%QbTbԕb/t`YKA(ѷ[ӀbIl+]wH)8$P~7 B uԏkH,ƐX ='l3 $5* X4$8A˺ tIRR]  g@C{iD:JE:Y{D:tbćbP# bwWQ  P-]+_X!\C)@VR!M=T@VnYi\S P9o1 PgP Pq#.5vmE-.Z}`o"vJ. YkO|l բ(jd?OOZ|*} Zy,G~x>7TBDP7NOT-"y)A- ޜ8F6IT:_-+VK->֒Q-6o=yY,5Q0F9碧ןAs_4oy,$̣VZX,]\|7;(aǵ~(eo}OwT}s$Z\N5w] uo,֭v\릾3t*$:m)>wYVw'){nh!Mgх-#q_![o|Ý~?t7ע_5t[f[h A AGx?|/!?mVz~Zt>хzac8=;aK,Ra5g^˛|nBDϧ9[~U-/Z|Jx߯X^~~ώER;; *pG"U ŵ] ŵ5YįޅsQr URtK*]2>TVB"I޷_INfoj.n._Lc%oIP[P["VMJޮ('){k0dH?CZ,+5u) K@k[kqvvD[ Lzۡ+ MHUv+~YyquN:]87un-=A.2VP ߊn_b:b^q/c-/L Mn ~*[̥R^J ppIJJ޻ZK+py{ 3Ztq&)ӅY&O0EZ^II/1*բ`h@aۭ=PǧE&E-CmaȻUVQRrIT*AA.Pw02Pw$DPR1}J%PT~`} B@jOylOIkK 60~(A|` XKpBS) /; 0b, 73oUʍ[ d. xR _^ CTaJnW,pm Do@QEF pD+xDs; D6A8Խ\"l`"cLM+DNNo8? OEUZ4\+.3*fZ OEUZykK4|TX;Ekaiq^+Ho op1״T uX0T=8y캚cJ .,B$k Qk5  3D!Zr;\+F~ \$/$_ \V'hf+gH^p2 ͫZYf^|9DL,Dq _^GK]ֈiY #!H}qV²sNՂCTtCԹHfy*zEd5p"ƞ2d _ڵ^>}}G6uH CP8'=Jw.,[u񜞡hR2<Z:L]q l;SWt{u= 4EbRxfX89SWǩ+7Nxꚦ&ݡ+s? A/vmM=szKḱ"[hzK1 g ? `KvR~;6f-jR)_ C`8b0 pwT0ܵ  {QplBf)NR)[ iazqN1w)EYsZsOQs1ՕWk^CŸRU\-WGÖ.Z^quu0qjzJՕnF9RpQpXX7.ba4anW[V+G0l)̭)̝I;̕Y4+aԦan"k[+Օ07k107k1kN3L[GVf>3JT۵w7%^54+M*&oS+vvuMJO|WhGBJKw M{#4J MgZ `: ؈3O TG_*@RlRPP|zGVG`CB1-LC{-C8UiFI(vZTZZ۬ԸY*5eBڕ }Hi 2iai̬Йu *]R7xxٵyٵz{Yau܊>3|x-6hcWdhҤ.YMp݄6MH}Rf_ od=Y*uF5f8C鴃6o{lF%SSDgpy64wZ39EڌP)z@ymM;$<Y*&Ojz$n_C'vدvJA}4z^uy;(Ay .~#\Z c.߬.KMR4ɹeáCŭFTaa#A*gbXfccN+.|Xai}H>z,zpRg%ᐚ.qnoD=?/.cBHQitHߧ1ѡ_([~GiMEj9^Sv?Z)hM;^y ը[a/0D3#THXߘ<ֻb֗轺mupRZcE3ВF_uHi5iyQd5quZ^`/+t}o|?ȍ~mK=|8ܓ6J¦6TE ~N#l%~O*__N&mn5sCy:w[1}sIfs|&9wI;wq3I'Th]u*;nw)ӏ͞}eWbt ir #|wHJ^k;HE;%f*mOXfO x P%P 7K"׉]=c҉hs Ѧr߇D<.s_V_["21ra*ߎCP!4TI0lT6;gUTZ>czS4߈5F 7~x)y̭րέ)WIWSj0hJ/e Y-qX*´TPa*0 U4TaŔ`ǎg MϺgQ3] OKQ38V"́4WAd HA)n_OԚ USkpZA`j Fր/_[_s5kE/F 9f $9[1gl Ęʂ:tzG;o}tiNSYޓzjɔ)9h`Z3^ Ckx3YhbgJO_Oq4k q4pK/CkG3R)K3`!/A3q l#\d ^hիc\ehZ$I1r_*I/=6ͯjZKR)qڱmj[+B[+Z*/ mڱmZmF[S֊W=h9h~Q_EW0WW,W-WW*hzon[2sG"+ѷThkZ%BE[+z8?̷Uվkl~^_vW6J4jJ" YEVT7-&_c_e~]vrco?=2G66IY#+Ȋ# *tf_##;}=G:Yݜj"{dCj쑵=#SGVGT~X*WT~{?ݯzմUjwC/wVjL__aMkek!n MǮcWr#fbvb;!RDv%f~,3DjƇ+$iiv`֑ z)Xf<+h:Y{ \hndh}[h*[i#[5=}s7$īskY"$&'M)n#\"$qp7w%a'=suy~n_ [JfJO[r䖖hgS n%fRJ-yiqKH@ Sl'}Xsr*PSi%]3WYԬ8n>;w̯o&׌8/1 g6WpoZAԹzU^>gAhi8yv(6z;8aK靶3.a^C~b]S[kU=#KyFo1? $hӏ =`P- WS]RAJ t#lWp#=u6b@awOH ~DˀXTXT"aC8JZuVWV#NCT}!,T!zH7NdlfMzY#Q_ A_3m6Dꚕ*v4iF0jIC]էJ \'۵%U+G 0(շwkt;Ӳ |fgDY1 )}r8OZTW%za DX7x%JzFW /l%4o3į}ai` }S܆NQUS~4 k>6tnMح)kRpi.su_hַz$nۋyR秼V;?W;?O9=?aZ|p?t034:D^CDEޫ~c,%RDͯm?U~J%2zQkThz#zZέ vU^ RǨj˨:zJ;Z=F!rñST <.q8AO 23  ƖNETB!EڎM"PcQ{;Vp?ذ>Ġ_L_0Lߊj{7ڼia8xJqL L_2L_X0D":&}S ѮIO'/,?v)Z?|=_#hhN0xPP6Qj-@j쵴D :y4`xW2e׷}~ ^,#/tpcפՁulߞ_P/`J}e}gXoMKe=yKN'}<}T/#@Bgzzy ͨc?K¹4my#U;REġ#[ڵ4.l @T W*T SZo8R+uB5*KX8xU7*ZuX,`-ű=DU-[Z* L-Zqa`j40Uj:T1D֓\8R "!bjcUh:Vu@b8|YWK5|^KWsҘb1hhDkDّW}`Gh@hQkD5w`\+NkQvkťA}4;|U1lO҈V]?C-4ȵkkOH\օck-[\R;GFF^^l(0U?ս_,f–s Z T4KWExU%fj*-XUkƪ ;VKijcU<ǪŅeͱ_0 RRRRYRT4{ l l){5X:@dQBd uh4B2UE ɔɤ$$L%RԯR]nI n> 0I$tBH[n[KI~+XJMXJ=b)e!4}p@e RŧB*SLNLҀ.HKMGz&maT&y`)₥Tۘ eWypK\*SV!L23T&]#Ri7eM߀KppJS>ԅڃ .Ֆ$.IT"`)),>)$Sx$C(Cc*xj_*2K ԏCL1G"FÀaPJ0خa$!RZ d :ԥD (!B5D3]ufHøt\xFHNd"h)m0C=̥iX1W1j1bTЛ2޵1!r I%XIwy'h!Gޙfܳŏ6b[sф罓2rm@$sJ$J KL t]'Hv =QHơ'z $uzd,໲D\{4p1p-qn CVt4=ƹz&#VY1KO@ WڈtK(l(V|b!bZ@FW!$[E쩐"gWBĨh{0-w1C(ޯTYF !8@dlnh% oxo8vo[[f!Ip|}C +7BoVoUiD-E{F뭍W^RzK_ ޞH!xC^xe wk-Oխ`f*-M=bf!A'QrߙJ|t+$턥+  oW[n`MX5o@i~pv{S4 o P[o"}^C^i7n~߭{zW+yWOxfZ`wu{u]sWϜ@+ ._ܮ>.8Nxoao'`)]vn(8#Yav%񳺤bn78>q뽚i:PT0Χϯbt$ .yzUMqN:ǂj ߂g.ԃc|oFGzMi+QL[i}Yv^wDBHR*>}C]~^d71 Y-7teC7AP|$ъ׏~tU\A*Vf#om \8ՆŃo<" 7mo%yӬ;yS^\GW8**c-^בLտ)'rٴy}̝@y%ӂJ +>7_^d`-yQ(]ffˎ̭NWpXvw\k'*_B%U݉nL 'Q?d9?PX񊥫fu8 $._XIZ"C`sk+ޖG?0a\`B0#kZR<QČqFLE#b12!|q;8L50єeaF ݊sar ja(31`|+a_<x2 ƀ^r SA(^GcF"05/_q1n4,>brˤx kNxj+:p&nԍ4n&i3\63Y3|Uf̸@܁.ex5%FH{*/xhx\2&D ID ywtL[c8!\({pep,斬^>%KE>w9+gu9 a1ΊkTLzmimi'4Mf-E)135$&7͈L#b4E~bE!rUh ^gۻ*4%.!;eRmIمЉY*b-uGbGGu?u%uZbZH?JdyWdNzK鰻 ̇7'Djra:mORh=z!4p S" PS*(G*CbAh0jVbj^U &'X.%x=F#XOwB$9o ڀFJ\m[hIIO"-,@= aJ@pZq:;VHA:& {4Voi!> JDOδ`Rayc$P9W%iCdRhS}0`K&C "B'$O%znwVz-G?~=.wzA 6N=)wO[*e>{5}p@Zy/{Lwf蹽)_E+)ZfS $,qA,䰘j I޷Dsi.-`(-i#r*#r[,Ӏ/#Վ'۔/~EGJ<^?EsdþoM-٪Mjyps* PS:Q: |;?%^_̿W.H BMuR$_Zώ39p@d쁤o|z;.A%q^Z2M셭 kxKXq|+PJ*ҚkZ{v$[V*:Y`)iӶ郗t@Z^K/B2ገKhdѯʬ48$قzN҈4<#3R_Oi&>lBu: T@oҝ)\ބ$&旖W8@Sd}_BX_SV+ԯ#,B) HP :TP;T]:Tc:TV:TK1\+dk=T\uLN16V>j| 3 1vӉ_PcXLcK';|uaR dZdZ>܆ݧ:vR"q!hUNVtFL\:1סH'+tR:UJ:`d%U:Y}:Y=E 3tc+1ߕDw<`~W(FTZvNK˨Zðɋ+XX]'JNjwYotNt(#yuOTTTVT=C:ġ3ÏuT=~ &OAjTHjOs+jN<)wz5'jT䩹&_>:-l~8dX|2jyoh{׃*1W"x;>?{]#DHYQt6ǧVTʝN>t ԽpmqQJߏcptfMmVd. ?op~dSlY; k'K,ˑKR V껶G>q/I/O\x[b\>[a'8&8[eg CW9%cnx^T4,kzM}'yFZk?~d/ M!c/%|{ͥ'MgZok3灋kzU;bf?W}ҁv5j,~=qCҜ9?r6N6;1'Us2seǰz>,rͮ1#*ݳh u~ν%<[ts|ڒeHB]fy nu["@Dʾj(6f^A+|0уWZ$+$`f\p%l0N?Ps3V` bP"C.Mq# 0vޯ" S`dҰb<d[rRÔK6$`0KmүnE " -ppW//]_;IW\`wv9#*0-n@!E~.5vY8`#0  \F徂 1`8,!)jB C=kk hPMOҐ4d@HT`^q#@0L$i&#:0 BqCBu^ʔF8_'#o`YRT_UX\AfpuKؠ˫qjM]CL2"~y|ҙr+~/mŇ_{9#+nHr3NIIe$Eaii?-:t WIIoGR7ҍ#]"=:|x2:םuŒ":B5$TU!?,=Ŵ^sv<ijKӰNyXW.T kk. PpF' ;u{jqplQp~jkhKͫ-ɨnT旕g":Ve5^rl M^r.d$c~-R߸#[i5Wҽ_wݗOzG 2~d *(oϓW U9\]J#[6^ZVRzK8d󪎄^H!xLOu|6|SA_Q]Sha\5%|F 'Յ\HEF.O= E본{s21OQH]G~>DR I²@R?Al)"6AlՃ؈SA FX|@lB"6| 6J)T`eJG$?⢂R ?e[TDP<"JQRP@E3&]MPeϞ'Kc(z2Û~j|z&EP萂d&is *"(TD!5ۗۘ-od"ʱЧF3"x^釰c*"PPΆG^KBZ#>hG$V zD $8dHʡĐ'Cu5\İ%4JAl I H=u>D}zՖge$ARy$Q_A\xA#2=Ԉ=h .MP P#1f pAgf)b jgjdţIMJeb+̈V6zզ&Ц&65)mjr:Hh@jPQ hr,VϭeZHlZ{2X@ Mcz4FiL i !r4! >`0!` ,97D;\UQ4. `@guj[`hcH h3iL1x1jAӘP`pXt"hEi 41phRj ֌2/TC 4B#XjMcT4@?^ So?,*¦10@t5cExlYw28h.[8 RStRhACۚ-SÃ}jo!:Dkuū օ4xreo)KWE0nۧ+MĮ9ۈ{5hr6[;!$&\R' 9R۠gJ!3Ey .CYVճPՏ- dQJ(9T'RTpI'J'Z uID2`z>ZJ#@l;Vy:':~0*s>$dN.hXlD5JqV O$h9%RJuS#_ MCWvӌ p7 N.Pb,P|1V:o,`PѠr0stTZs&86 -g2R_Q(x>#d8;XXj Z dJB\hXYBh:pty3Tm:D>m7aРŲ |ZׇvFZej g7Mʝ2̝e;~NPx^aD;C@wDlPBP@=~2L)aԨlQaڨ`.ROa9$i?bOn+)q#eigPs5e k#'FbY#"T:v.ͳ!`:ߊI4,ch:]4 YXb&J*t.#Π;07Q*oT^ !TޔR*o 2u!7Q 9~S ,%T&tJHH,纔c= ӂϙc`iAcYH ҂zCBH -iX;2~12~? #͌_:U)*͌7 12~IDo_92~s,e~3~s+6(bY iE^0|D^0ԅ` y #/F`^R^0!` yGX yP*%~q`X^ 91sqАc@Lu İT$S*R.̧nsf bY$#5R_n' ~iG~~KXI?J+B/^]KIʤB"Vj fj:@ӐZ"}X Ʋ9sYP:f22x,O5.R@(W,=kN'nC#D*0n*K5%J+S[eĸ90.g }љxk)$ ) a|#0H8i~ά4 i.%saƺƄ08a z s(Ao8xGZ=@K::j<@5T P TPMW@10.@\ .49IX'nwszf1ƪXâ/=YbcNYa&۾>XWcOq)c}fh*%d}.>2 gkլC2Wv ӞYڜG{x|aCMkMFVbFd5XgMIH,ÉDd }{ݯH!3"Y:͘+ӂ% ZW&_l~"B#ŒᑾR1tu2MR(%q7\),]IeP03kux2(uefRdgf.VÚZU&!Nb&%:=YũgbNtlk1#Rf å69\*oŜBb|D&S]p3I5UL[ڑu>z_Hx`y0S6(Sy1#zpd¯u\흍#i62-X3N&jp)$xOSJ3xB B,P )5hzXك&%L)ЪJ \e^;1p¹ VRhCJ$u VVH 6-mhi L䉑ۃ60źbYuϭdf5n0EL.+;R]Y ،P ,ƭT*`ІwKu:}EGԖzՔW I%E_c MHy+_.Su.@ZhA5 Nbfk,t{\wk]EODv?H//guNl:R~EP &Nc6tGC|cbz4ˆ6cM. ߏR9NGW/ABHeEWlDE?DξuZBcquX߳A*g.ǒ?ZfDlRfUqyzՍxY~㽅ZKÞrSY;zk{ Ol o~Ea ? g=OnhP'B ~|-hZ~},RxGxAnT{Y\On N 8fm?]˱e16KgNzvz3nqU=k{/A8^@@b݉պ/k{&uM>&.qfW{_hGg2'UCZ;pٖ-tSvbKt*Ƒ>9-0Ptm?}qa\_O^Gho밗^AѢا'q^֖^+pz-ٌk=/.iGu" C;AN=;L_^iwRaJ]FĶ=Y~u?I۵e??Bj?^#}~Xc]oa5S4.owOD֫Bu0x鷟*!kVx uUQv̟wl&°XTukC/\D QЩ5CI ( mw-JSYý7xzOťg},hN_8~oZۯR{zI_g|>{>I6)wZQX(,j਷˾1i.#/|Svy_X«|QۼŶA{t;^w<@q=޵M@2J? ˱2*UIP$tecKd՗eZvQ.#=u)l !Ųu䑡ȩȵV齼0{!uN}8ݽv#N!F+v3 ?ߘFƵ_~rqʡu/L}v0h6Hբ{2~v_^k_-\6Fe=m)uwbKh'vTVܞ9N+u%L."C]Yr#lU3bCet{Gs42V >q[g YGc[Զ'+J$ I_ff:(_FBRӦԺEҦ?uib,Tb,TjƌbFTJ_M)՝o7 R̈R ^jV䵕c:U)x:su*1S:"ZͶ?nkV=kX=qg_뱖 4h0đc*TseiY-u=91cYH$քZ_%2['EjLn#֞\,S[WՠguP ΰjA{5F=a7=uq5{9U5֥g9<};y+ds%_s+VW) ck?JﰰVPqUͱP+yB  3\yg ӓ p dqjb(!.WHaBTTRYreWJ+ₑf|iTje90W%R\)%#6.0.pZjAe@2\>YM7RP?N`IׄejSh.0)dYi៑'V Md٦(S>ٓ 7X|#P,N*>z  ǛP@@Ō "x,,_L nfx_kd%ݾH"*gD12Bb'fK Huo8EC(NK QXvƿ_XJ-<''U nR=S-FSؘ_XWSjMȦr b&քʱ[ua[L:"zODVY3! c%7 6 }iZWG" Ȥb͘QNA#Z4 'kY:.O. zkG{Ţ?e]?|Fd랊D`L(xGH\;t=zRA]3JF]9p$E1~S|pV}DA 1UќfJg{ **)~s9yg6h씚/l•pwxT9dv²DD(8^#a_+;!% (I%fTB߈X+W?Q@ijBX|ZsUjكв'Բ'gT@QTNQTH!z&TJ1@Ope6-{0cI5I)Ni{ͱ;A3f>)0¶(d]&DK..Ń*9l]Ō'.NZQS(*l)ٟX+VX_FD'("BD V\rX+MDQqZJo ZapВ@bnɃu%1#UِbpH3 q SJ )@ޜQyB󀼐檒9 –Z +MB»91Pq~Pq(T- 3 P* {JR1cT:@iPX@9葱J.Nu TB]@t6ea8pIe8G`YhX B2hr~(>"S} ,Y.TLd`eUrL,C beS6X,Ra6@4@p%}vùRa\Imla>"o7oy`Yj5,*,/ ʥ7딡#,hЌuOhC~pɢOy1&f+f?[/˚Ѡ.5Alm|Yff?pphm|`cp0wЃoL;;qJPpHu%?0flU@z(lŌ:Խ?f?˱DTGW-zz>^lЮ1;$Y+kdF"ЃP$+g|Oҋ[ys/͠NuR ffDǚ@rd%V-+i!~=DG$=*hsYFxZx2C`ڳ?0XϣN5ARi$fRiXLJzӚɾ-dv3]|dz.Eךͣ31Z߸u)N>Ƥ?~Q~?:fA? Y>")}QFUln>Oߎ3yvEXX(}d6 ZcA],f>eOY3faN2%Gv@+v@k#O$]ʹVce)|} dW Ϧ:R+sFSHyDEHc)cB0օa B20֕BekJvBb0B0l0 55QY u!߈L_TjP`G>0U|\2}SyE/ԅL_:[B/]Ibᅩ"G/91Qqo B /JSl$B )Fm^̈\\+sƓFfns(Er.L͡ A )-5n1#n)5PWc(P.FXQ#PJOI8H6F*Y\^?}à[/ҁy#/ #iWs0aH-[Bj1%HB0 Is,օb|ce#:zJWk8쇗l@v{t/d u ys9WC3m۟ c9]?2DiXyysrg~/lk@ rJ-\2߆n*mkalynsO(כ5t+G Ռo)sxyT2f^#|?֟*#=..]X:lm)?p4׼c*9OKq>{[;yuXkK>ٶ˟ow38lxK1S3r֭6Җg?^ ^JOz,yZY2I=ټmleg/bo_߷?yC׷><[eu5n ՐN_/9{VF0V{o.'h}=؞hQ@`??^=a{n k uy?㠟$֮tYk} Ʃ>cwQ.T7\zNhrGRlgI(Nhr˹htx[/dY;x$ɕY~LJ0[xYuϞ;[>q4G}6_؏nnTo&t;QƹnKV/H3e%X?,gAǭ(#N/g:Kڭ~.R㾛;"zRBt1#KICJxKIs*%M)TR埩-.&X*ODh]E!"YJ1 ;c$v3XbɦԞŘ,c -CZN2B˜aˁ 07a̱TcfS&5-lT)_՘i7 )Uc3-k6sTzP5fZ1c,@.lT$cWgtScf3(lI3gT5fYTP+(UAcR2+(wm:˘R}"1XSpTcTRm3m+maY,k6,f3T5pYj6;fSȚJٌuf36(q6!(O*;c93m^՟YZ՟ZkD<4gThjBLGYNlOVSxֆ.#=KkfybHUV# *$d\xvo?]qEJ3rṐ\zaj52!k4ul=z;y%HR`waD0-$C HT´PH ‹d[I!חFmMgܖteՇ/#>rxQ?CnyR鋛,}`Ͳ <+E9pX[ yx!u>?Js1n,x?A1!J,Gl?*g.cfcnDX'K;kRjM./ؗ0#ؗ0x.*a,*a1 $D0&Aj[ }Y'KZca׳u(P.'K#Hpiͺc (RJB(R(ڂH1.eLq8c 'qoq^[DѿDp\6v;q0„ItѳŃw(ul"Ae=zҺ}\y(HO$AOCO8[UO|ink?W/ CX; ޡRY?BڞA:zh%3|Nag/ݹ'g+KmK5=~|Ϩ^!W.n5'7Rp-B٬^gR0(r,`lqT2(*Uo6.HRbTrBEax hr]AJ)}sFDzDz%X"Kº2B""ƲI, RAu%/P*)x*q%aBDaa\`AeO,i ߈Eؒx9F3u.K<3+$ZN%_&ݰļ[JXWrf%, KB& $$%zHKLH #\G0؎RaomFQOlF\gLF#bؖ |E%>i?HTHMHRVi]Z|rSJ3&ёV?Qbf#͖tGl9(C1Q*h(GƠ>g# QaLSg) 9AsDxvf¯MdGZUqwf# GtAzDGy=TGҪ Ic%Qqiވ* #)`J"$N3oI2NtH嵍K}6I<Zk,%>1~1WDD cꃎI4XۛSz^ޙ/r3qUM<31xNLXV(n_QC[7S_'ZiO=cMOŻ旪ǵuҩ]'R'u*&b'm 6h +}䅧 o' '$N\V8ȉZ_/'7>-5S>i;^{1@+DD⋁@R(Pjʾז)Qь-:">R "URYoV WPcBC*h՗WOm/3mit[i5X`;=.Lޣ _;A*Zƺ;=3K]5AaHfdh$D-fY''Lb'e+}Vgd-~(HG YR r$PjjUA1=Lg)+($u./Tڕ,`v0s;Ga흶H_4b^k2(%VLueq+uȚ9mܙ˭F,_QI,^dY"7->q>uTU^?|R)K*eIcd:A/.^3 ]P4S!jRE\{R#E$L},2qАٜRlƺu!gG2\},WWo2O,XYα^B9)eriБoD2 ~F#tAT}dC 9 b>"n<ʛ'Ϙ^,uɾ&v%`{7w@JŐqH3qJcR`&)rXb&&``&OptlP*؄& ) &c%PPαD9LAQcA9 )P"J &AL /71qJZ115EL11V5H[)sBRgb:11/qAL@L ;ABv88s qL1'8N8w诂#=~Lwr&dk/bA_ /b!7Ycgbbt&&8ƽ aøbܜ &11-9qρK0J+a~cP'rtA9\ oaPÚנ.]70 |20_30JRc$PÃrd(t`Č"&&'_WHJ*ǚiJ~Ռ_%u_@ (7Y>&֌Y 1K*v(PT(כ=\I%ʅ"r!`1 `a^ڠJ+}%4X34X4z]4RMZUBSMNb ڿMTJh*jkXV2, h*P:CSI4)֞ӻ3INzw;ᤏXGσhS|L%oNw"S325#S8n6o5h/@ ʱe9:u'e1X`mX3mVaXm`vҳԐ`X0a51s10~c|\)uK4ߗK70 ?dֻ-!3dt~LY#%d`53'X )*M)ŦbŦbURjue4 )bFB(t3flKE̔ք)mͲgB e岢6'T,B,,ųU~"gգ3f-%tQbeeB,e.x"nmOBF-PboD,Lų=g(ŌY<[\i%GmHcP=O FA;%X=Jl™…*&¥>@+G.5ŌTޣ(BH($b.4G,9]iQFFkyRQ +D+e E+m"]S_*dyD!+3 Yis!+BV(dMW,7Qw6fm*ym׼癿Tֵ ڬK05S%٘KgcFΆKgc],ut6b,, )t6Kg,MRQlh5bsQwբ5(TUl.]Uy4TzjU5J4AU角5WJ+YF5widMP%k*Ys,TJ(+YcBVV'5 .V按Ad@d*6QwakIyGQBw55bk1#]SzUJ*b;Y{>ҩPlJv6ץټbU;I1kgbAlzSΦRlNYN6v6Ø8VBevV7Fƌ՛8kgeY;Uy+v6jg9k]yEmN FUئ"T;FSM7Um8+G2(RjvzF[!V->#B$Uz<%5Bs>Z}F?pY8ٳceUV6^qJ6+rMϴ?}Ux0:/eiҳaB oGx zTz 7x翘ߵyockmfƧQ[Q[la[n|h4mN*?A[_>`\Cmp,.ڽE\n퇥E{ i̝,gVzȐtB3Ϊ3Ϊӟqړ|*F4( fnc4ґT6 V'zmv/lPKU+ 9ݷg8|m49T+?Z_Dj`,ls,YSbRue,+>kS*` @p-W؜j9ٯFRىF&ke צԣcV>odp-p-T=||#R JEB0hXs,X1V&BkM@Z BL9hG9h3 2ɔ5xlxl~2N-A[8mS o$4..Mm4"~Α]5bp+! #K7D8 XncZUZya?" a8DGsFEGy#:Jˉ(!8ڈ{b{bF=s"iT?O{Ȧ6~F 5%a$H+|oFZ5㣙{o[@)E.TH[GRfSu?c,gK\P9#0/fN3hC33̔5uLĩDT,~ƩiH5l@ׯk`^(ׇ,xpȞ{}0&䲀ye4Ad챂*d,sHd,Dr$`2y0袰ٷG.w(u>``iFL0ĺ:f)e])cyo6(>.08ٕLJmJ1K|{PfI+Ē(Vc/TTOSP<92MRVqH'6X',BgqY`6QCn#[%PסF}^>J)bjpI'BW? C]P !BkǣoeߺS۲ dbu=k iPx;=Ѣ1WWRLx!^Cuo#:lC LձȤ[}dm}Um!3Wr(CUݷu>?_k;g<n$}a`sdbVzޝGIJ3_2 CiO*P8lA˽6z?0O֢־TWux,vWӨn/'LOfzo)x'Լ:=^HέOu0˶^tDw~f'놊b9(VgFkf=ǻz}Wm'XoWUWGpInv";Y'xdٙzeF1Oyzfޱ:z2TDB#BJbCJUv9r]N6Nc,N6W:KdCh'NSVBY\>Bh'mv9˰mbs,ͱ&mbjw&Rh3M,NJ8넔B_hu `sBv|hʳM[6uͭ]֮Zbo2j-DXV4Xh `1!',J֮֮㪲5Ė7wX>r,߀sX8j(tX Gʨ*֥>!S6npv[~@i W>VվF-@"i8Nhyx4ٛnR-jvg<񶝍p{}tծV:zmh9(X2牽Aӕ+nvTG]i h Sמj~=~Ԅ_-W{VAv( nY17^^˙ۻ8=Rk։9Vnvoxέa(m=Wk=ZBR뭙աωnzJѷoˉKj|(|) [nk۠6R_:'Zhv0F}B'O1nˣV{zŃet|Їޯ-\Iߵ~d8'Rc'd]: tT])8=a\ݘ[uW/7'Gn{ioE{j72!nU۫~#__ZgڅeZ;tUURSg J[BM9x:Iv[BN:X Ni#òX;3±+kO,\LMӷ6v,WsY3Y&Z֟.Wqq"]3DאIw2:oZ* W}`]_ U{U~-*;&uҼ-O[Ts"㍳f|p>(B2r>kYC:EfL:I VL f#M&k37 J:T-WVkuߒ y 4N"ȟ9X{U#Y_Q{2*7U(.#Y}棠uDDos7.. mˢƟ]A_RHEVf3WdWi`*%O%TuJ2[TFTU_dm,'oL #l@zCdF3Xzu-&bIl+V3&ƅVaO jBbYHHXe}.񁙐UeB"!U/>%jLHHA<4PHMiRV&j]Z3fڪV?b&gˌb)#\VR*rM5F\S EiaS)N~r90R?s'},|єթUeV'>guj#NYm$Z|m#OFB)+2Dl"TR!Z܆DhsG,+Hl)4[ۚM6uy4#-n)C0ۊMCٺceN*9jdT2r G,n yG [ϺXZxZ Yu5Jծ)jW>M ~Z4 ~Z৕Fj~Z ŮrԞި4X=-^lŏ7)[bJIb+$Nijt3l.(eiA)R-(e5~׷ xgyWϳƂwJxG,8lyPqVkyE8vRx?-+5ަRj2~ ԳxzݡgOn2MYRٴ3fL.-ec㔵7R#@MD2>9Țp?<]J)e*cY.֌"n5_GMs˭R}`8<DeC&*kkOxr]Jg7"Qv^`;Ru!YN4tx=qkw:H0NPT/*P\hz]_HUݒf-koJ=̼Z:|~qDi3\g ~FNbyh39RH֌aOW?ǘu!Dsyu}f3B c!g:ٙlSZ}uP 5k)YxEa:~y짯3H˻ZwcH[ 2}w.?45ۍ㱽huy^?m_Кy;whyGC&cfRC 9{x/HrԆ.ˋFiDN29YLENu顫ݽf&*R#tB fS `6fٔOŌGK)A^ȋBźBhhIzYNuucjXưļ\|ٜP@c'*f^u$3U3ͩՓb34X Ԁ<ʻݖ$ЛMf$0Ph:n[jS4 ho4Abz ^̘w@/oX@/(}4Xf@CИs2c^8e zZq]?ú[a#^{qY4K[TY(@@3N,,vYlj=P$*j}UX}[hۂi3!svR0yuL¼yD`C$k }[ C ^p|TIŰS$TuN*I|GR1c LSF0:' c6}F09y|b ;]\ laz)['x' ^F00wN#P&"c0R'RR0q72z„X.Dt1:&gTQX/XRJ-v2I.w[|PX}png@\|t|Ic6$ ƯDQZjPb>d#vI!CW\hG13 jy k ЋRGG4Cj:3]jP#n3cce =oRNN!ٟ GYc-lqzo/yIПc]ڲ;Z_׭T)ioN=8û :p{2a6kS'gT_R?uR̖_֕˾a߉a39com$ߨ?,GERx̆fύHs.S,D  m`h Ռ#.=d {输G|ЫxRGqSLݟ~FN=7Ћx0:Fo3PLSj[pr;+#RmJ!JbR]4TMM%^L涃2#t FO5ToV5{)) vX{;RdB0 ^N!QnOg[[vegn{n"JRڑ%24Lad/O~Ϗ?n;U::Oj2Lg0~zp}:2`e_y=V3YnIY3Gdnb[q9,=DY_d-=uE͔St7D!/HX3YZ+se>c13 Dabab-+"{{2@991qHtt3"O7;KgDlJeFl~avѪ뎤\,=RpsÑKۜ^ʮ;ZWvXOFO0SAPD~*z )>wݑPt),9R]yQ[GUpGH+a>?\}&BF'lSxvUeGCeC'}~ Oy,B ћG3684{7Uy4av xc\ĩ*]jիM0$\yx^+#~!_+H*нer0tx3BOxFo, t KMŢ#~aukBr0ǚ91EםF`SHM]w)ĐB 1HOmwWO'RzsG+e3)V;^+B?w ,Aè46jP͚KT#dqh% s 8 ߯L H( 06TbsaeaS6`_S _CU5J Hs6Ҵģyʵ %ECHH4$\ɄCCӀ/c$ ŢhR-:SJ5NT.'0e@Լ==u#H)2(sM'ԚgJ4`2yp 𦞔7eM8R_?/- /LzNG娞3h)az C .qr7 s9J ܘNԋ7F}1+Ęk`yӼvT/h1RH2E)1b.QfL)BCP͘pČsB*% @ڞ9WBcb,A PTJ!͘zdX"e%hiEh3L~BE6({I3R!'T|HiDLZHL P D:`|I%Fk Ӂ)k-=t1v052U  8RČg{gx )c}cb_͘M R:cVbis{e9e7&bnI%'!5 P asBELJ2eMhWP->AǚQl0#:AIdG?YsZK͈O9)ĴcexbV>ɋVoD[߲3j1C%w%^%4@Fz+f.XKĥ1qjYK%5RMOc 0QJjj>πmdd\V(JEQ3P(L(|/ CЇj #ȭ}>VHΌ4Tb:>tY,O֐MZR E* DueSc%"+ϯɕd\Pܜ& {@RmmTD6j"`/h+n)ʶ16) }2+" ғDcNTë\TB k \Z5Rz#c$ct F`?0n!5a\@Lg [q'-p*' JgMq|!.?1}m-KQ{C?~fy\f^*m.uܿ ՈE[w+V`Y6\D}SJM1~͗Fx<1j¤$HW0!؏0%,}r(kQ}|>ufi\cE)9_ϖ8Aސn,^6|4c(y[}|@^TFX~"vz"sYG}9uHm'Ǻsv,`ֹHv#, 6܊:+4n/-+j'wzF3W_7\xzK?N =[6G 6X 6]L;Gߞ[w\7ǎM0LYۣg胜۳}Z[E]x^em/d NĿ;ڝ?^6έ=ڮÁw]ۓ[˙K>pZZi%%㒜no1RKsy@MRJ~WRkG}=/#phѻku5ޞ c?'cbɏmѾ!mwOOa {i2$V>O2emFZ@!<4d׷Gi 4r\j2nBu(#KgQ9(pr?qVW1p}fOQ%Hc iDOl)AF@m+j(m?fF@jsj@b:- 7h1B@Dx'FWQIeWQHeWQ}z?M)Tb{HKOZ#it<*<ʅ7W$H3$a{'4zirA$kH#-kY|̏33C$ugbI$*a, \©G.gMN^boLL fTjv C?L2$a,c]sO4J|ңb\Xy(KV#*{rfQ(mRY`"7g)W 9#dsG>~:wjBX ft#߳p#5<.J=$7!*axfEPj~[[{"K_ܜsNzPB:&<+ k&r.ԕ\E:% ^?AKu8oR`Х(t*a}F&!VHh~~AHM!Ag!U : 4J\ Ac:9,εKHy@P4dT'ZRh3Seg\8:S(L]3PzBFINj"2ԤX!sE#q/=#$JyLMePUzDQeJ))J*좢2GBAe4~m72Ps)g9rSO˔ƣ,3*SPFX6d"3] 2e=0c3>NŘj1)*Nn.L!Tb+a&]՚-(LW4Gz(Tϩ39eOQB*颖S&ТǕz}.=Ȩ̧=-*Nq G#z7ϕ2(Y:ϼQ晛*\57Q>eRA#2|%]+3n#O,Īʹ,㍚| dS[w.cĜk=šKӻJj#?+36lCR pUcd{"\H)% )Z )QI%DĺQ~]UO>Xhko?c Nov7TRaYO9D^1qc[~Cjĸ>3~F'/>ߕ2ĹJ+sZ:a9u=>|HK &DNj7A|ª0b"QHn{ѡLI%̴ۚ!1cHI,=gGT'FOuXT_wSXR`R5do8S}gdjkJB@e3,Lh*/*x%VҙMJ3-lןangx̶04䓣S8NߗKcuz9+,gf0[`Fsk g}Z[.j\Q/N5o#M9XW.q w_׋Vg[pO mOH Ap])¸|2E] ER/֎_^‘ )$b]ǚ|} Ga|a ) S Jk/_L_H!aNqkB&h8B E@J PȀ6DF x DR.!%hPbF(O{RP@O;9nS,gI4 mۘZ:H uvUfP-pYѲ7w3Ƨ%&70#Z x %źJ4q={tFjBDiDuނQn:A'Fv]` ,+MH%HP!~ MT#<ձ tj=%՚fh/2`*SSORuT;>I`6+&{ rqPS%A@HM6ELݻ2e?fQ +p`1e{E2s&Œ!tp#+F ?uW B(xs6p膐tM!Pt赒 GjgR4 DpeI!pBU%U ^lpB(nsŒcĜtK-FJ [S2z=Pu_7 )Ibs냅gڝ$, OWlpb F >W̭Mr647M;!3ׄ.(afŮ$), V'ߙ7#%m,T-Fm,',n'/ӻy6ijXPHeXRԴ&pBOI9KY ]`Τ|̜lŚ Kj[o{_01[5,غ$ѥ9t)tP_}bx̸94̙<7sqifCx%.O˙u1[rͤ@œA Q0ʉgw).!X&fD03kgJ)) zbF`N)5ÞBӫRDa$G5TG "VS*A$UfZBB T)+ڝ B TCT9 T!' QUy BWA$\""=,U4ëX< ?$@ aX|cX񉈱bJe.fU3F5'D _AT,=:bF).ZyD[enGW~e{a0ۑixj2~ )]ufRʶa|Uu3j=U5cL}O1S 2 ݖUŹ֕_Z|je,h}"!k3,º:>'c ʜ3֪3ت3ze$c "2Lղ2js)9֭|fl$`B!e=)z.V{CO#)W"#ksզ03Xd&N 7w q`#!6V\uhظjd(?#e3S^$٦ ?ތ)nA™d$Rm)56֤״KdHzM?ּ Z+5Aݭ{Tfl^Ȍs\Y>Ƅش}.b?jM6T]IA"p;ٺiͻٺ!DPqs{Sٺ>Ysc+7S)ߜ@qP+1|#7__W38YySdpDn{p%Nt[@)u,e]͘!EK)%Y̺1uSbn(+ۯ`șgn*5۴xY7Ĭ'mn%9hsc,'n usERMmn^2nH\7*r]+uC$׍e\7W=g4a$MK TOG.M}WZH.<ͱ<%CdM)1+u%oJW'7L _(Z"O*_aRwo_*_5t ŷp/~C]]0 u%pvKA +8 @8oWQX5$M[,9Io.>K|ԫoL^`MW#^9dLԛv pHz2'^58xs$qooqƌdugZא"~֭C{+URs#="yC$NءyڲSJ[RC]a_ӓ j?_RΤ*U^ky^\|C T6ޚ:,M ,p9. jt½>chԪ͹rL zX`l/?K;>wj&\Nho/NlZ:@u(HX%IuEAg_"=>Eb,)v%U˵֭xl%UGTƎ wˢF%Զ>o]@Ul{׀tC\*#GքtM ;lGV/)M] ]zk)jv)jַM|5jz; TD.qs~6ի+Ql>?][~1W[*'6ؽz׺~kwqpLZ~ Oc=;?/bE*^_D-#f7+yy<vrWP'ӎf?wDNo Sqq`K~G|%Oj~ ~3r5~ǧVkC)^(8^$/:8jpn:!8f Udp0}7nާ;np%z [auߪ~͡ʘ.R* UGw )j.{w WoX+Wi!Б. "0*Š=/>?^JbMAlg[ymc[ka]Y~n:Q;^?< D骟ܿA+Snpϝvᯯypa4 ^kSy8vw(M;x^.b;6N.i-YܠNGW0οD:ͯ鼇 D ([z>x{>bZ+.HE>XHy;w~MaZ =ZZmF[`[V|^o<2TJ]ZT<.=Pۃy8鎗̝euJ^˽FVCQ2(a):R5T9S" ;bKnvJ ^AWObxRg,?݃5v)4B2 :H!%v%5BEZIT#-j$dMR+iKZ*5B\&Πk@C)R(uŃGOio)1Ja~4>kkKuKO#^*BTe(hAIT/F).:tBZh1-zLK&Sb`dJV.^T4Vi7*j;*ƆTH.%vT( RZJyw[*/TCѾʇVWEo*V4#B kVXy~huЙz\blzbaww@/+hfF7+Cl`bhz{]B+$W8uא0څq-U1 yR)/;R9/-vGeKlR^TG_!۵Ŏ ŸXkD%[Ci-' T1 SsTRrPQi);qBg3&!$qM<gR/Z )e"qM)CVH)[I,MP,NRP'd1jCq5!  '"ZJ㨑$StiQ}g|Mp[CCs N 'F2.bP!_ /.p]C\9^%$p֘Y# Dk% MEnAgd]I+ɺ YWܱȺR%ulȺBȺRɺ2Iֵ;*OT֕wqpͺuULi8&D|3RyM)ņ|/HRiMa5Ⱊ|"Rit?ͽ TV+JiSHq`#mOF4)x4;v Mh8&TCSj MOchjCu6*A` M^ch!ƴPchd-@{ΎɎSj*LT/T1𥖯/r ,Д)-HR&q4˥SSjM|)6Ջ8&kqK _!6Wy:r\M45i< ^hz)ª1k_^l~& t(0!WzS"a K_a~[ ŗ!qxwVw$0@TK#cvʖ=ꗯ@RR-Zq\I@p{0\_8g*_ZEŜ0ͷrrZo bE sÜ9;לx7*0̵xʼ hD1#D1 |xPܵ^qJq)~ΩN]pMAT=bRk!R_cJaIk]_j ҈ZS[!-LmZ-DX ̣8YٮX e:FjlW5RbG’}ca)Nr11FZ K(|rt;Uj, Fr#rV\H1XQ%Q,†X r[KSlZG`G=D `X1Uac׏1v sc *q s&Mv^su8YOFҚ!ε6q~su6 k2"*:6f6fKj4ӣFe2>ڰq5:FxMwTevo碧η՟x~}}.<ⓗ E<ʗ-_֎ ѵV(_Σx`1:sܣXnkZt(BhOԛN*adMJN4`SsU5 1AjA5҈'?E,+1걈i/!+=hZrbhR7uu+ukO[DW|3ʜa>(:ƛ_1;a m-T[aڣPvפ|5[~ViDY&m} vZmbjKcP5QaQPX&W]x=!,R:.%8Z^;V]Q5Н|wةneJe2.E3ǽ嵯ק+]v$TVCh*[㬕Z,Q|YT-__`'3/kƊjȃNFnb>e e´׎j;.R%̥{ C!{=Z?f߱КmZUZ+u %T S^+p~8_n^< ڑ*UɼR̫5U|EժdQޘa,"a*|@r1wr}-Rwm}bm'>^+^ދ׊Jic[ ʲE( JE]IOiCxEv<6ޘ!&_7gN1'ƓdV^|ṘTeJ"\)%ۏ`%jR,DHfTAԄ*xj<5mI%T\ͯXKHvhK4j::hN&ZdPAjF'2yDn] IDT%x&~o+_h˘ ֆ/:m]s04*2c+ ;v6b)%KXyJ0,T[ۋz SͶR6ۊͶIbxZ~8Ka,s`Äm9`s`+PJK)dlBX~µa,ŕ٭pImKZJs'1IɈW >[;}X }A/vDǮ$ŒW|c[v6GeSdd2 Ƙ^l^6 JmJc!tNC/k%ce0*ܾq}'] +s^WR9qfaY"@U>ƁPU>QRu_sm Ϲ~ځځ qa$-' =Pcr@19PMBk4&rR19:ը Ѩ ѨZ4LoWTZp=B1rTMm+Jk7pXh|* a JqeP ;r:LGnCH)Sv>J~k ށpс Up}4cp6M6Sja pP9ahEF{_h7fxG̮/'] A8P tjR 33s*ƎR8[e.zʡ>ܣNtJ2N7(g b,t8:tNonTP8г+44 ݡ~eLtJq:t98U8(8e@q:P4:HROj//HJP1Z*[Cu[.5h'_Jʂ}qxhS‹To\q=qK ^x}R>)WYR )WhB2TIHg>?HH4i7\[uNOKnUν\v}.Pi1/KW9e!)e}a^M^f {C"[foe뱽a7_K9^P5{K0fo˕קuu_9Տ \΍)R^"8x#J+G>k\5f =fbGmDs7o[Jr^kz_K|;)IlT@7ZҬF!|L^_|}̢T[K> ?J-2W6* i߮O84jfeoWkfK,)]w g:]nz,@@2iM 6ts}B轶Rlt?o5HTA܋m/}bP$~,vUǯD*=E-See/&_R*\3nU}oRkJbm~<G>yMlF s@>g6a} {|5=3Ն͙7f@\[cmzɵ굕>Bvz~r׹f9p}FS$#^km+yw׵1]<ݮ>bCkÖc-_.>Nt޴XT-=ǧT(e|  iBAL\? *'Xlf,*v vC|^zˁiQ6l!*nE>%vkΕFջu6#OI&J--(ߝoa-q1iu\9U s]caZ+[L:Ο6xm)aմB5-vi}:C5vKJ:SM~: 'u;tN7Jh[3طߞOӖOE^vhS`vp_* o ./wc!7a92(;LןNH|kKI^GR@v*"(FcՆQ\ucSiW3oxqb'rt>Q>F`ԸF[I9>嶣^=I0~ZШԑ贃OJsI,wgHę!Xwp-q%8 U.ߞ&lߢzv*Ǚ]CPFCPu45hjCPCat4#JCPvlFjNj4'Ĝ* 6scfuNjM+o @aiVtӬځq>n񅗩z~fm.Ts5K+ujXZ|޵6l sW%J#tZacj-V`Fj0NlZQxiVz(k>U5/67x:KIv7 [aتnFJڻ™Ubqj8zv$顕 #Ru5eDj*r(!dr[ƨ.1Fܭj2kb¬:9Q1QqU۴(,cTZ `Bjy„zKLHR:pCg% H0 Rym\eB%!QQֶ׭BwT*T/Cuǵ`G"{uGt HeKH*,;?}Xhl줮%R ; |]w:}D]KX:k&`s}XH  D XY X`M5 Kg35Ak Dk m[x5 ']&H0LVX^&sax 'X%\Ǩ8 T0LT*A,O0KIDZsl <r 1JHLD 1#-rn_VSts!/ׄE5 HLxTh)SZszοi;: `#q vUiV7=. >*n**;lc\Z_֡"5mQ:*:i(ۤfTh B}2NM vO= Z+) օ vOz=umm:E|cmItbc._[Go먜$y!#p{=`:L8jdb>SiJmC%] .ѡY9Eu_{XNTZk;Tw*u}|Hu?ߞUP@)Z4XOYkG@N_tb N}_[7AնL0Lyw͏˧M~J)eiMKUk;GJ=jSpv\1 *41BР(*~Td0Bin\oWsz|'Mm"&D[؅(|`Kx5Z?TgL|m?f,ϖ7^fa`ykxVӵ~z\<:2!{dM)ywp=Zr*OoBke^wg߹sz.xN[vǮ?4nɰnçNT )>~''IG-g~?*Lywy6ʩǸ>l-濹ۯ]cG\Fy}~sqqqHX zQ,Bo#vlO{s^o;(y},L7T/ճ[1oU/v*rijXcY /*bKTyJ|!2"c k^_(JQ6Bc-DFAvGF$l9c|5~[c݀ !4Ȗj52O#7~4~4ÊeK썟EYZkMHf][E~lcSl\,I\lcbCT,h *D qQjƟ񧨾("TR/"aFoX @=BDoB,1bӵqZqqI\t?wvt=4?*|-Q '"܎?ͷ! muڋwV0Ďݤ\ ݬc&?MG?#76ӕ(_p0P;69Tcs;DF@°-j-S\=*=*~h|[S+>7 [^t\kGq")SkJzo>>QnwC4&TGS4/6$qB׷t-ζmc^K[k&V0xo lDSa:*TmJ@R b 2P@F۔yZmA 198E @wLb@9UֈC,/T\򐯡b磹C׈>$>4Q ++DNX|BVJqً 10FdyƯ!-Ud!z ѷmwl~_8ۍl` WB鲄#rg4xGz];ir'tI<4XWF@(QH72"Q4לŠ"#j!4XExsj@N"N(8ZXhk<{O/y|{^-:B}M>q@sRAs"[As'ib=Y۬ԈO,Ӏ?UCkqfNwԬRa o *h* 1ܫ@MB!=]#OĞ=84tOYd>0 ɬ4k0}Jy 6`6$фvt~ 7ew4|"Ǥ1>]Ks|*- 0ɇ&Sz*.`N0Z Cx&0b/9f.ubTx#`&/"0TڃyɃcLR99%Ҡ3&t-ʁ\@Ψ8A81 ZVlns}vk4Xk5;a&¼|#dK"!0-a:bkB|!Z_bGh˽QR!Z-UNWjŠjwTfk)g"lZ*wKZg*BZTH{U!ѦUK*!C]HBZM ņH &7JߐThR*ro*K) džT( R!Y$'Ā$g򒄅$gwTk)}iL_V }[˲% ?3]#p춒䄸䄼)L05 S S$LAT(B*'ThR*nPPd9L;ˉ2f}cYN,'JPIU;ieC#Cbwu0k$VI*UG Td_U$ST^+ 2%yU<̚Wf鐪lpĥrHum6mU՚Ե!\*%JF *(aB{@ @ d*0};[y*+C#@`/A PRpJ pJQK=lVVf@7vsLT8O!R%Z 6BqY d)Ud)#0*SaFU3BE9=ڱBT[.ol]-ŠՄYAXRc@*_¬  d껀Ep "X qe9l+ X]KXJ#<p{I8Vm6 6VW((4@`IZ_6rY G[PH 3($&&nc=!|О#О, P1 f`;* fP1 S!/DT0#L- SK0)L)LZS+R GZJ((V @PHhwToDZ*P!b {E @ UE 0 BKBKMBK%vDhYq)7*TZ{Q%1%=BK%>%XK% e7Th вTg' Zv)~獡% BKxBKz@Z > BJMWWPXP((k)a*Mh ST\Sy00FԦL,^Kf4N0G0 ,*Y`a:5Dxz4 7[v9w\g Dmtޛ(oޅ< =84v6f}jvj|&u%u$ Hh?/ߊGZ Jio+LHj";5=4}eL&25mzfۥǴl)̤%BS({ m Jt{w :}kw?Ĵܴ$.jZNomT4=8tbN^ʅG\o[ڢn駵X-MQD% k($EۭeηEuo;kjkJsˏ;6I1bڱJvj ]/ {j'Rګ KyndE=Ug궝ЧklS^WS[N)Q nlQSP݆g|Xq57QyJ-Pv t dcMm_^m0zvB/w~(K .՚ʺ%4Ÿc!aHE аZԊZW?JņU ^ ka/SThk-jk-UZq`ߩҼf}׮8RP+~ٓ$F;w^T뺵l.~ l ߁uy~i6sтvRK Ew/Bydw&ODg$)#lp) A0C`ٵb@?p!O0o\]Li'v-a mPMǸt̋n5zpUm<#VVᮥVa(!/trM[׃vN kE;1VB0DFa(*0I pݡ֎@ 0 \*5^0`QuTp__D.nضѺK4B " UE+\ѲW,ZSWZ!.ģD_;W~ͦeTiY sh *OKܨՆFϯ_WVS@c)$HI )e (Q5LnUoNJ͸ShUDd=3 b0>E4j-&q'3$huͫUQ5iJCL֔Q$NI`"'Zj4,' tZnfċ x i>Ikf&Ro|dyI^ Cv:$dIrHJڱcHWTtycf.pO[Cژ 1M?c$\(ˉrRO+*Y_j`ҾwwrC~'!ajM2tc$klLҋ$g3LҖ-yO|xK2.OWf,0ߓқ&;Ǔ L0]c5$̻v!c;T#ƴ-TΨ-bG]|v?f˻BֵL) ֓uvJJ]+,UJ^Pq+~cЫ&8- Nh4$8A%7"u 7uY".i[*U³t&%*`2'6`2ԦiPXX3p+e8qpv).q w W dz0&>ˮ%!uR~ @Gd%jo!&ou`b 1d3}T7Bo,pIL2]qOU [\Rq)1m m@qk%8Wf ( '!OJC'ų:տxs"JMN./S8d\)Rr` ~r TZkJqEIEgߒ\' ݡj{hn-Yr<ұb괾kcu Ҳʴ沦X6z\6s޺;oSIh$v2o'~,mҌVQu1W{'Xk8Wkc gRo-dzuFkԎ|cMѵn?u k<kWo?WZ?ѷN︼Tۮ+ @up9:К;?@;\/B]-t`e=_/|mc9H;=5־73֟w/x ,iՆc->=mUE!k=Nݝ>Nۉ2~uv=NGu P]7ǎ1s.6[^G^"C#K(z5ve lv>Zc@\f M:B6Moº\=C&2fƒ|CNi?ZMɐÊD:P*xzz3߷CA\w #u/܆-8?`؁"sA_14w$/{rӧ)}|,z 8Z?|=soS$C'?p=֕oNvo#8\[1_L`e cZGG^[mU[95c&). ^7p,IK c\# hn>znwUߞu]Ϸ%XKv{k*HN8Zm9ZkM!#PqK4ص Du> -&+<&>^[<ƿwߘ~5\ _:$Dz3_IQ4h{!YeOlշ^eM \׍_7Bv$ARvhddG^I?FMf&2/ZX[Ӆ_/vku"]BG&BCIҐ iH2Zj dEYqg4+= BT :Uڌf~ 15U"9ڵ-[ROL;6߂y sIwvDku䫴\7IVzU1rJj1j{d*# IR;6[[P`EsC‐a0;9"wX*i*7&W$*P] Nab*7U؊{5! DRj: D!I}NV|%8Uwcڗ$ I I GFڍ'9ٿ}S#YFcԉ{B*sDT79ZRks` H.Eh_@TgQzwчDMh6a*@J6Ȉ8Q2)D?0phE#I8FԆHKLj6E_PDփPD1NV#X6p*1HLjϋMրc4LjLjM>MBPPDIwVfD(h.eEɳtFv2'݂=D e>!PĥPGii}д2 MY*qջ 8FbQI$3 Im>`Mpյ2bM0TE(~^VK61 *_BDʿBȿJ~-Rk!K P׊KU,fRY:,-6Kʭb-VC>:OA;vTgR-yZ<-ŕ<- ;yZ>P , fkc\B\h'O OP!OKW<-yZ*8!i! ic]Ol!O FWK|esq1&Zd`ƛ].D0͠=݅d.UjjJ#:FAjť*D*+UQ624d`)V! ViɭY*]or+J' -D3(/d`iRs5"k ?)ub̚-dMp$k _RL#8u͹J( B7|X^̗ jChƦxN Ӟ9^ONH>s۵13DkqoVM?q%mxnyc7hYE]˴"zVBj;tQQ?@FA>? RZ=>#h')FQn7b="\3kt})d8͏.ਭ֕{ڮ cj&Vj&౫Szu9# Mt^)Jݤ~>w'{*n3kFSn KҢRݠ<Ԏ-O5Qth7)?-s9ܱDm1saŗjmt;novrsalY-O{vV+ '2#,I%P ?l,7ez$m*͠{O%cw)-i/vm*mC%p_ 7qn{9 m~tѥ=NQ|iw'`7Ur<wNO)_c[)gCc) ݥX0[ D[概^UCXAޑY'T:cΔ×˼!{{󉋳JfNEanWjniT;2~+Ds; <ٯ5:kC஥P-lP)T'.!Zp=EQ9qznU۔۔y gC g) WT,,ipm]J¥Rp%2`N+|ClǾ1J2RzT5li)_jauQx)a)ߍUp x>namQvNNGϋ!!c}ˇGg0 ޢHXNQ5"oRo"^@ |k|]JaBmpiTdnX۵T1\{r^lI=ڃOO&%@pwCoB5b5tZ[3DoR/ B=gTH2t* u -(2DKU:kDm%rJ3*CLg[yZ\U\1(zeiC+CJdѩDo/Y^*U6@p]ȆhO\[˚+5W FY`R\Wrp@~ DU,빒ZXVK#n'a !UՆ|6r-*ذ+2 FXSkU@*@pT?;_ҵ|TV Z}ū68v_VTqL 2/R"xpR[AU 5lv [cVQ5l-Ֆ]Stc[qV;6U[VTcp^ۛty@?yoXbhLjCLJ[I2ƭm[i[', q+!qvT IgI IycH*BRrBRQ5$%1$Drtt+p+ z \'t\zWjj'wؾ[~`[ +-ŐV;6Z \'wJIJ'pՆ IBN\K?.5+'04JvlJ6Ĥb58Պ7r%S\'R\\S"ZC:y|GDN!%P !5ķJ|Dۉ2N>q\'QF2F_3DjTc Ն[~.?͉˅!ln5_Z˥>Xm}bqyWJJ ϗi L/Œ{ 7Fbm&EZEȒj)Syڰkl?%Yz`)oLnDԒRr8lx;-@jIߓ^6%n0|SZ)qQ5%nSԒ6waM_}ޜ{$֢5)K%ۍ^N+mKM\'mo;eBY[>`Yt$R-7,CVEܬN])ǏW2WIW/}7r{=w&lcX|hv<®JOxEձdoډ6|ᦤ?Atfy>/d|`~r\>?YM,F>~OUE.Jp /v03feb hrƦ~f^~XB!SV?U~5Ac+ RJ'4FR{C -@1_ti )TSo֜ ?-!?)*"?;CONU5$lUb7v)D]YK >Q] @bo,~zc!/uЖ e^j-h[1뵬*ZK8jtBZvZZ(:h:h+vRZ }w+%>[tlK>[(<:hah{hZhn绣vfUz4+5BmVRjVEP`9oIň6,ABES+ą֮~UHxA `J-Vҋ B hiV3ZZ6him q<_AW\'~#zZqg4UCX`Rrh~W(_IVq}P{ CC_+.X:VqacUݱOL*#tԱZձ б7I;V$ұ b-m0qiLE.SP)9*jjG )QIfTVBMf:͔H+a>|bCEЉHܨD:4͡TdFԘt r_S684ݨ<ҚдGVTSQkߖ&<ߖj=$o{{u_m{m)[02ܧVߟ{/s8W$VZJ>qlņIVIfBRfyBeޝw>ei\cf[.s;H!ͻ<4j5޿ S]Qy860GT˥Q/wǡ@q츝 ;nqKHT2ݖfډŎI_ظZ;`i#hTaAd'k#A4jnUYF|wMGH%;^.{cEo~N`˽sO<B` A8qƎk)8& {aM+<XiNXÐ=u3:}2$ "Qm ft% Q!wplySg`;&[iHʌ,FH35]iJ4D:&4M#hiL:r,rH4Si*H *u&Mf2l&Y3=BH2edi S1?&i|LW*6#f0aF8`21,߇$adKS1&<N!S(y%DI>JN_#3;*fx{bJQ1zfR4{PLe'tv v3`ҷ[4Ȁ È(aJ8P5BD S9BxtbLߓyWSh$ Qԑ48v-#!p7uL.G߸+1Z]_}=5btǵj{j<Aqڋ~.u}du+𜳵Bn}>A>:v>kvsa]z[S\׳~B0bO)Zxy>0y Ӆ # Duw\)[cy?;>`>%Oɋ_W\|nH:߸?8 [k׌Gz7,b1ul.~ޚCNw=^6/ԠzC+IVym챽בg~7:cy(>7i/H~mZS'. {Ӂ;][1u!v/K빼"oU{82צճ]TZԡf=n,O_οOOA?C~={52;.s]\isO]Q>0sY!)dv8@-4vr> ӏ-NoK̪ⴃ徾^D+콎Rey.tohT@*NA*̠)_B1TCS4bЌ!3QSfB13Ksf { &͔/)[5S n6S*iLXKci`>KS5|a2 1ih>MS44xr4tGM aDMҌ3p@ph!@^:v)4c@D1;b ȚK3k*{ $0߈5Ksk( 5F.5d1ki0 ,iFb6M4n ihgOA`> _-)68ł +a [ב9n>o`vf 7tqz{6coh{8LaM4/! _~߀-̿ݞσ%'80!;;Cppc ⛎'ZrͽJL%xP};c*xFxԕO%++ \ =Z 3'J) *FJD D% VFx(M~oRζZJ¯:<=C"*u-!*ӌsr . *A!oT*UZ.*S. 8YuPBPBرCr8(ok͵; KliZC6?tp@Z Mtەx\>B%m`r v.H_.- fe5 "^vE|u+rH#h3pE2]i05"âҁF|piAŽcQ XIiȨf\X#XvXZ$ 8Dڥ44TkIk(Z^Z*M/-_ _ko Gu- JR֞y-Kڥ47ڰ-LBza*RPa(3GC%^ɫR旂1Xr]ڗ9`-/䋆+Mѹ9 {/Yne_ */7b0)4IL jU;v0)1ع mkgI| 90VQt C{KEX S!U LŎ0bȴTڥ'A톚ZmFfTsP!AJAIOi3R3;bx)-bӮ4ޤr ;MZGƴPY cPqOd_JO1q~M#GYR{g37FqV a8TFpp hWJ\Mʋ?r=S5H+T bcbKXXP+6T-bbKXP+|+|+k+Xcbyb˖bbbbw)ߵ|z~WPg~Ww-]!U~׊^e X ]JЮߕmwB+$~Wl~W+]+ [w7Tw~Wk]aw]/ibvp6Mx=*~WVw)ߕZ~WxBZC+d~W~W_w#E+EσGb#K+N]bad튝ȿ]tBsŻ]X ]plZe2tŎ5?XnRitMTm *2%N#&U)ӎ6U'WSQcڏJJ/g  J#ebeZeXR Pao䜷~jſԆR\cY#NzEՂ]t [K]#qժ^Iag!CҚTk-L(Z#Db #{ɡr(#t6ژ aRBwJ*yB@| Pu$)#Q눩ͩ#Z#(!]?c0+i=\¼0:L:@2Tӌ@ܯÄ_PCzfxki<"I>NHO^;G:znH1 D\E< IT5Ά5\kYk*//g-឵Y= wCK"⨊Xk8kIkָZJBUġbq^UU UU!,yBR$1wJ UG<5:~#Ug-hUG\*UG\-Tqe:ꈻ#E:l:♛#Ύ#o|hUGVjk#ⴎkRUqOK}rXjq TOn/H'jljPXJa=Pt:>:BNBɣ;k!+A$ *<A'^Gcicƴ<턼@C8oF(va.)1Í10_7j0luR SCŬkwTֵTʺ/KY׮k/FfV#.,P1[f)DPBdpYnhTfS+.ũҼR4B4 B B0J|R Av77"L+I \rR8 rl֯+|)E=bK\[(n|)}ũQb@@+yŖS[G jF j䅐62'%BVk!g~i&^0q%xBF4*qe8Z, R]#WBF,+%Od\a,XB,ȸB XY&ʸ+Jn@KCY yY^y RRL'T8Udoy3nb^2DUR T*@J3B *DS ѳ*<dYqZR ;R H)WC^kΈ):lso[$nEwʷ^Y Ub/B)vr:9VHQX `aGLK 籏/|~f{&6N4L\i1Ć+. */DRFfj̥[ # `~?L`"S㝔P+o.0)TjP̢a>岺ɤ[.+O&X$҂7IM̤/lL{ѢHo҆ dESaM ;"wLiC7bCWǤMV%IK4U}cdj}JoYosk}c}o^MÀ4Пf Y*mZjE " * JA,B * Y~ )Ib)DjS:F|v72X ZQPRy:yjs ZǒY|jRWՔ !5Ua}үJMEJ 2jDŽ&CFl8"u-_%&,o*R$]d96IFՀWjsD8+IdV7ִHǴDK!M~b-ِ;lDg,MjLJ^+\xp!';y57b F_T mdcVܷLjR__Cjn:czcw7 cˋ%{jc-H`3fcX޹?8q߾[؟9CXǃc~WύFRXKQorbN6TɆJ,RN6Tɖ/dK,䅜lRNRUB _v-dq!/en˗22Bdn_ܖ/dnV2 [[iz.]8w4;* AT! ܵ" G."V#ҭP[Itk7Ttkn-_JBonҭr?[++[ᴚH-e .D*lR)Z*%RkHHN9Y ݊{T+6H " ޑ"n T~H[H Ha Hlc$,|.k$e񍍤tC!u ŎHQ-R)uoD[-r-n nq#uOP-vDBv'iRv0bVTfG2m智ZLʖvɊCu}6=l!CPHq??Fo,.᫁'ZeXMj矈T[Z]jfS:939[LNwG%CU&bβf'@]s cr]. UlY#oWʾ~~[R[dsm4*R*vDeKUeg{@:{e3Q6to׬F˽k}no˧ojJ Rx~ o!{]s?\`CfsMBnIΚ'*;]q!ܥw8ygPs7}CRW^IYYzR5)+I4ݪ[TFSRG)ҪRbWB1ė:$R˖ pvZҭF~6)q4L^ct{P!u[r#E͋~~ZHjǶbǟ_#Ωu? 5OZkfTkt:Z$V}GDͥzlz mf?zo7;JZT idypBu:<9Cc/*{j_r]>cl?|#O[f9tֺms̯[r|dB;o>p} Ou喼P=Su~ۢ|Zksy %Z"I<.;nQ+>r:n7|6yˆA'Njr>F.o/ZTq:8]b3Yv]{?.y\׊jAvQcIYa>>WzFDRZut kq~umpsU>qT>}ZNfQ]!>S'߇6L9v"wl|" C?zz^6/a=Ɯm+\N$\XT1(l:hɍ~x1F8Y=t~k︓F6>\G.չw{}?Zڎ`Nzrڰ ^'ZSrˏ&ɵ9\vߞn뭽NN:SRkwb[x՜aݔ-l=U>vrmDe=~{ǰSCzsˉwXPGssx};j)IuKq gOmz?7{Mz;nhɺ r~O'}(׉%*S_+ RRAf pj{s%s%j>DjcA_l)SNM¬ P:d_cZ˽K7LC \g1/$aOH&On<۬c8SR6=SNj&O Q)7V:0,8:rxDzED mڙ4І8yRj'lzG*HBJŗ'5m-y"VS(ylM"4J"ߗ<54﬌@0VRi.$Qds_k_B<`Ry"g3]7AS98YB94wC'"e*i;Y |itWyPiJMSf\`  ,M'XIYtQ>|Fo9$'iayՊD[_Sֿs]T=5.vծՃz4..1@_.E7_o<΁{O9jvG'KV gh.n=\{9:@he|ب?deyx9}Rý+Q_sJ4OP۽ 2d/lI4![eO@Ԟ_mCm)wUu.#Ƒ\v]fj?mĄz{KЗ˟_tv~xtL8#mV= aS 6_z3oFL:-_ZL/VƽO9%Ƿ=R&򗊳ڶE|ϮVx_dKOj?N} R7c)-4 z%o:/oG n?V_k6V>agp̟e2P?y)wK[etrG["W5ł&}D%+J'Q^sf{289{h^g<]3=o?{L_mgo8i~bKHM9n mVV:.4}m4ݗpXerٮ\^?x'\aM?%c4n{ }&R%$Ĥ"bRP1)wRr/dKD#:?DI%횒=p@ 8AV% ::%%Uvt *a|l s|PKp@ 5p{4XbG AkR_F 8\Oц)6L9Y00_CZ  QK0GIsO-`^`H8L`jlÔ92 |2)%6L^IlĎh$jj'fi Ч3ԥbGdZe l @ NRI%)8Hтj]>5Tw'Ҭ)?0*.QAC?X}4E8$p(vm6~Ek D'P N0!`5%#PxB%K ՄPM &-Rh04Rg..0fp"'8 ;&pR?2X )RxEƷUB";|$SI5ZPgAIuiX7PT[P8IߘIVu~H1=E&A#2̵]IJ=r*ZѾNytVz> _RfiwmV;[J_-b0ƒ[Dl}/S'r{Xk}QA5C-as}ov#q3ՙHYS^ o}i ҄2M>QVb*fV4miYMO:ΒidE)k@N|/I $ ϚWdǬ4֎$~Ц$"vKgx_DZ:yhc$EhZP (STgX74*2ԲۉWBw˵_wɥ~F3#=~SҼ#'M[,1u+RԚӃg2IL Ḧ2Exnzos "X;W:ޝ2:RˢʼY34euhCd^7d͝oHFr )Ki_|O>xs9+> ڔ$D8ZRٽ~*c!vލUl47Xl87wTun2_CiIճː\.M7{ߡ\I徢:kpA<[Mz9jڋOhJlUc+"ۤRmR6[NY~k gSNsnPh7*i,r~%_(Ma==gJ;Nջi:(͕[:%Z5+G~_ZtѬ_ϙ]GKsa]pZ3n8>'w1+xz{DK]],t+X>)Ui<` ͏Ur[Yf,:M8gֹ }zU]-UށKb.6N*'_aWxKUPtyY'09-iKoJA>/*sz Gy<˓s+ c T_|YB(AD M$0@C K oJf2@׉ N[Xn`b,Wo-ЖWjA@dC|'hJB dY4L Ht9bJ\X\NO67W*HL)H9Qp7| P`d)Ă" ´R&fYKw[hylg YafV !c"т(eI*XIJYʲ"ژ P-|`LZ,N¢v=3eӂ(gS,E쑵^Y7/d8*#ǤRT=5_5bLU(vD,0&hkiL~#z}bGDX !)B*ZkNLIle*Qe*2adO&Awu8zb-J9+윕S@k!3Yi.Wi8 *4^s U|L:Z`FB'ΦTD:kDgv6Vp6 WZ"HUht芥jU`cbC4oe *4 ͩֆ:6q@UFHO)dW W5-3̸V3Xlu ϰUP]Rg:q]%t7b$ l#;ENQN;Icƹ<3Ul\\1c]H"Z $Qe/BeoPWLe/_1B/Bv_1_A]TvE8 w_-< *l*v"Fb,%+XJZ }Q PljY9˒m,Y!T.*ku8QlSǠB\%d=Y,urc}_R&ٮ$zR"J4`MZ`7a)XxVb)  rYkUZk Xv\WTYOB\tJO֗t)YTBKO Sk!r]~KB\߾W&(ܵW6 qMU qt~v XTYk[+N4`=JW,M??Қa1@X¶Zԫk,zVfQXg-T&zAޠba/wޤRi/B.Pܫ&7RQ.d\P-Ŏ *bǮ#xN%]PBqćuVB(ⅨP ϯZ,[aD/vd`ʂA`( Vs)ֆ#Ai0`x+Xj =kb zJ/B/Y3Ͻ1Tcg9L(8Ɔ8OT1Ġzb|Ig k1TIJ`bq 1aY Cb`(  cR5YeЙLO$ZAb3y˜ &雬hCLy::Eg|-}.J3?/gPX+RU?SgT.CX m@3,%ΔDT&}wi2vD1< J!j00녧`ܨ䭖B1B1lǠBpa4p=L'Sӿig峿M?v{dli9Y)sI$^%roJ s@&}xMѲWJzl >,ԯONrVu0 $@M2 "$xD-AZ2R$tu& ?p]= +xtQ0D $ 0E { 1q0geg^X]$>yatQ 8q\'ռI҇b$R)v;rO:74TxGjPV--HK&j){׭S43ܣ?4.>gvl}47 A'tc A$Uk2ixrm??g8aELקm\_kٗIGyx^ V6 źb]~c *0wVU+qVTRizlb+qx)ëP7ԛwb핲_$^MG2PiCkeӪDDZ+I$`/O({\\ ُ γܘnOI21S הDK _$'_Itp95Xtz |\>g֊zcr-Mk򙯂GKvvri_łϳHZNU0G哔3U¯#Վ[Bt@_O68v=/`ۭu>gUX9bg$5UTӴ/nz; GPKTJY+ڗ|K)v/>Fx4FpupTH9ҤԤ°$d WXHUPa*dI#U!/T7֑0JpD^2 *q%\=15W Th|B%Z Py B'9_+1T|մ/h4x54xǃe ^Z9R&iHtbjn4J=}aI;" ,Y`;"}+c+Q)̩B#oc,`y8X- z}h oeR_"pob,^#-ʖ%BW*ډ) [yRg`LņRkiJ-=xLŽgVΟNadJVJT+S߹]`+N:3v\1 8FߟiWr,!3R-fB`*Õ 0Q5)_:k A _F1*A60[65IvbLZHGj,bl Ιm$fuTs#IsL=z| +A$h@wë R}~spx4OeJV6CVX$GT\Ǐ^kY7Bg]e{שr׆Lsh Hwog]}]Y E9jJzEzƺC^׻4h-0HqrщBa_˄w͆:~Lokgdgd'ںGt^?͵i3и8˥_1Jt!!Z>qʷ~&DlʏX+)1u:PGm0{?|O!>u-_#/p}"0ę eg/}>9~͖)$wv`vwVgݟ0tk=fOtWZCqCf6J_]{W䠤rPPMv=|\KB+JBX BPr/|\KB8! +vrP~ DPc 䠠Br3 A^l^(Bi "" @x!hV AG/TU%/bCL~@*qNxFЮV2GBTyl`$Xu#-#%[FP T DkH0C@ẍ;(3& 0L "˫B PE|T$"^U[1d " U% D<Z/{3#FBxY|Uj| ///pu9~87 5_O .^hlx!>*| a) a- Z/* %__ vh\~7J[XPeaw}G IEDNj*%[B# .VȺXs_p<}nEgTmõ=%CO*xJ\aCmId XIJ0Ѕl R);T@ z(zU<MާBE*whY**U%pT ךQAi9j̟\K?Pwcnijݺg|R|J3Y/oG,-u堺]cVPR ,&5 4К8#83}ji)>w|0DwCa[qh!PJKB8MCq4ZJhD'G}?~5:> mꐌZ0n7^ #&=$Pߘur7_T#P wKQ(Z`/>mʼЉ:6n(k(}Z07H81aaYBq!kמMj[%WoW,E}ix%Sj}k"osenQs kIJ+)V|%$$ђSu;(M$qu҉K;~UaN{D06odn߀AP{,_}j͍1ThJ`IHZNK>#lPF茰cD&66D=wL6vD웣s;Mdَ;vr)¶[ke-fo|~Wzªn5$8Xl!([ez=bqSXܧScqI5cqQe,nmX\^)l]T?WfWomd![p7L+wo0[ a]} #hv 5fh,nPՋxTj&6®;y#ӸR;Dz,|ǬX"ˍsl#A^N-6Zd+ dkn+mJmrJqy+r2$Dڡo Q+2g%'ǃI* -}rVx Ĕԃq)y{c &9(E'y=3VbRdZOEb|JNI/EUޗ bJԇq\eo4=ʝ|Om}f֕ǿ;Q"\[ jKO䰗 .ArwᙞSW~N.91C%V*JJJkYxCZcDKJ?CUۨm[)Td[MZ܉m8'ZI}*id1E>[$1%y()(MS(}e6VWo-mRtC[WT{Z79ȀmwaljB ) nUR'ok^!:Ysa{z!u*~~静O$仵[߻=yw)J~İ)巢6}7_&t zHT *TT(5=zHT =^ *B^_1`cj;7V'$vLH$pJZD@"Yq*ؑlk%HJ""[c)Y'6N1AD E:)J;^ WB PFjBel%J^{ x$\~P o}W0 \_?kV Q"vz$J.D)ZRd_d(H@b*p w$ +EZ Qd{)иW-Q4Z_Ez$ @F~ #H$q:ҿeIbPin;8eTLv)혘BLe3W *+[~8/ޛ;f#-׏;Т킸ME$'"ϩ0pNuҭڧZ|'BS;#y6?ƯYB&VTl1\w9;~{iL9R;_GZ<|[z%˫z#:B #b&E_ә_sB6ΥZc*GƵNlXҴ:9x+zҕvvm`N,&eUEUݝ;lqاwgfP%{;nyxT{ɶbG$\ {iZϞA$ U$hkG Rgc (c; (c; (=(KCk߸~AZ=; U $ PuԛNN;g@*s\ xBB` BfA3\1 {+q:reJBM^C@`e Uz'㈩r*bd\!u*-Dpf8xʈ;YwnɱUPDCبM@;C _.!Rs%4Z4*zMuC5VRIw,MM>.c\ 5)i& 7t.f R)tD4,/Bl|UNfLK#ըQf 8\](E͕2ée@&q^0W|Dy@ЦfCmra nJ 3n~'ln 杁iY jnA.'q(Ma&Z"͏Cam6Zt2⃿4f4J_=Ko[4t]>=UIXKXVnʁ .>1ǚ cM͵ r(jM_+cFED}Iu{ZОlT2 3:QT0ecʺ+aZNߋ i QbҬ7_^9MwTfY;ke(f-LGRǖ{eN[t7u|/,(m)4@~qrڨvL_Sx [[9tn?8F@{@L7%\\\rwvug k 7n˲L.[U))P%!P.55ra؀?/nܠkNU.8nKӛݖRR}Un- -iyځHG/CnmR ~<+-6-C@$s~H]bE}'lR)ZsG AA|8X;g*3PTBPcNɖ ST8(5J{'[-i%"RqRe Uǣi -$cnjA}dkx ^Q3Z(o>BysBU6UhACQ B4e1>5L0PQ QQ CCysR9xάvoPAC(7:̃TWBAC? o4.cTKZeG.%Ij%TfX@4eX e~2h5 i1~5՝d>*! DaG1%Q#UߍQ#L;_PTy&ޤR]/.TylqPg'?%'GV×o$FI *J $Rl!WTʕb-  ^w`ɉ-}TUˍ%,Gv@vؠΎS|O;)"9 *$g|&gz!1ݧ"m|"q? NM* NedڕtUP!Wlg}6K'/cD\ʣ8e>?gW6>c?u.kor~;QGv|Ax>,c,ӽEb+1RQ#O0_C0-rPy] u#e q!eB4uV>fiL'|! WzqbAcszyBr< y^(^_rmqsr)|ߟ `k5d˹5"5Kb *fww~8d]#Ɠ1v94|)[cN~8SL)Ns@x^NBҕH IWm0 if:b!t*S3>yϞJצ{ZwG}{Afy1xB< Auz+5[0 Tl}W(1!ЂVJ᧨2 -xiۀŚQ!5%rB/ `lח~.b8xpY9vء֐8xfV3̰S-CE)i ;=scbyŤX x2VUag^Ĺz>\6~li3dAͶ?XCZ9|EGƲl%^c`,}5I %ӵe*rFj[%IJiŀWEU$Hb `RZĪn=^!0I}tvR L_ R?sk\*2.ƤVQ]Ǎ; ĵ)8kT@"554585 ֤ VX 3X5& ;bkRa* yti)) xJ)T`M*W5^5xUPW1b*UArk _)48TUP585T,t%18ڵ;8^Cap*$ )zM/'WRa3⢙D5Tšߨ!W e*\XO49ꊧ_Ip"לJZy<_Ǥ֩H&ZcR+9z U/Ř cR+15ҤVd1*qwVRik\yA ^\% @pSc+J8*^<5-\}1ϕ5sz~ 0yj;(QmJ\oyAu^Zov_PWR,GA/ڛC\ki,1Ke0KC(CadQL-shi@K3fA>1{`WFzeCRj/ _}*%fSR$\JPI`$0PI%`(`"S.*A>/@> 0'`N60YX.''O`>A͉K攟(4Z%.`>Q# 'OI#̧OPSSvL'z|†|!'}9y94^y.`>ѿF E, tp}<X(h`pk$,`BP<쀅 & X(]B+,|| O '%_H&{U.ò5AŒ\KĹAbR1qP8W1qPRE11B11vbb^S\*&Z *C#UKL82Rmo\Kl`) `j{A^HU\JS3VŽTQLjmo Uj{Ո_!Sb u]Q' }utΥeVĐ:)(&@11ʖYHT%ǠBq~J)(9UKˬe(K*g.ee5ʒyQ%ӋDY2JYLdP,T_eD(^1xoڤT:^QT*^xPtQ g׊/%ci͋#Nos3ccCccCLg5wT5?1j)%Z-_BMWrT>NvM ]}5U:VXR5gjwveL#TVwccegM*cCXؼ9F>VAIcI(cMP>6whpu9 *`'mzJ`{zcGdA 0` N(s1s.i[QeBVD Yc's?c$9bۏKU3m5_5mki[xݎ;zeBVT5UMhQTHJj5_% kDleU\eUf_:t9\enA5jVRg&Q2*mZ<9L3ժ#_7Xv̄<}q~s/yv-Ucm% ?lӛf8v"LZ5=*HOwDUsicxjՋ$RT2*LJ\V|;5|ׄ,> YyC&ܓgKM5?-|,m|Uc3+WV= 2 P%j9Tk͡J2* TȎxn9qn_{PWP(?$roljW/봤G`tKx~FA5U,9,%/퇇я߮$R+B3ڻnFLZں"s$t BC+jRwZa/8tGedǎ'e;wZhC9f gYSp.4o-TNV9YTEUGL*+YdCڌs3-##sTm:Rfj0Ŏ#MqBOL:_٣ y[13B'?{4}+uc&rH1~?~~>> Ź.[Q{|7s" *t_2)U+{qr5^;ޗD$gxx+8SLUQF#Ou2m6o^=W&MU8-]eWs+8u߆k>!i=qv1~?3)WLmx JQݰ8enҗR<=yJ3 _Q|7kZ_󧺣n#0s-'z,J]iBE5b+ӝd%@ds5ҝ jqVo-ҚL>ʮIOl@`-ZD{ݾ}& udy䕹)> _g+!*_e ϽcPGx{Ln'QjmdRn)r1v! :#20YP<#Ң A^4T&Gڟׇd/3X&,#ɊTOBioRVBTG9.$VJ5vJ^P]E^DVL-3FbRuBQGz*%IMrFvR#I+UG v&,1<šQab}hXk}G>=r\k2Lk~R0U:5 =h~dSKю'e#-w5>N[ؖ?.Z,A C'nY\+qqvqfU|e^R!L J/+C>t-_~+ X^=,:[[#Q;t{]s%x.CD֗T%_~?y\Pe@b ZI_=4W:\wwj^PwZ\+leB.q,]W&i1<\J6Tމ_0fr'Xiu@1]|E:/%U$kkUzTA'F&0~ I$ߤz/VPQCYL$8M?hKÐ!U`S^u+`+As? eR as"s@0~T A`*'!z[_1n5i4n5<p%a e)|%>1¸UkOx||xbL x'8wVH[0+*15t 1 +c[v'Jߟ-kKt\,VF42 䩫 +èX^ā /_O÷vo:oH`]\Y^j4 ` RDVkmz/隲ԐږLn`H,2~(30M"ĥ`<N2^"I,!bcgQ$6 2OoS]B q/#$|>w<7U2TUeDDU!u˜,2Y@F`IX62vg oHk۞~T|\D<xp/.LJGy>-`;Agh2g}Hk\6HbMM&`3^wh6(z™d UʈsA֨*/ f Q(L7u(?J+=;TF, ׮pQkz K,Ǵm7:6,E8+~YƳkBfUƸҩ#l e˪`'N2)S! O ҥ YB2vcDnի*UK %  AKlYQ B?v?T@J) R$$@H )yRR k )/#ԡb(ww (#3fJ4#,8#P'F4J**U"A,YRF. * |)8ʥv? b[~ :r,Z@L:d<$0xV$Pp)pV ': |EQ.@O%>E' J նɨed%k[-Q5IpK|Np oD)AvrLK ԥmgЙ g Lx &?8h&<҄OL0 pE%\n,u 5PSnԲԤ1r|45k9;p?i&-;ND D [6B6Ѳޑ;xfͤE jIiYk&Z YUٽz;ٸJʽ6DٵYܵY]UݵYU#?~[;nΪlLߠդʝeIkgulnڬnMi?Q<H n,k*SrcgqY֚4vJ&ݟxY6vVvkg̳I UnphZ Uw@& ՏRz9kMDۭ-^#"$ZXtgwJ"R@hU&)OLLFQHZMэHIY4J,'fVGI/2D0@XTY!<_5203:̜K91Ǟ&eQFK'%~:x0G"͜13&k,H-1j2XeZ+`3k+M{~v`T;1\b-Ɛ0Cf`2c & _e;F%hb;|3e?C:fkfۆ?ydh )~0ƶ_ր/ 7Qhvs\k6I6SozSA` 0y5ɼ>F=8b vT02SmJ%BN*:}6]JA,6pR`80 9ܻ=T!OD< * I%t0vt0$`Pcst6v0S͹07 ܰRV4:pqQZ <@ cJ/(1Qz)7I<[~jB,~mx AL/?xp ^/q3 .TJrb76;>}z3;^6^KS~@ *"N}/1+e?[O80qTq@?X_x-!>õm}pn_;v08,0 ~163:yYT LRi+kUNz0z0|6oPnpޖѣu{{JUL/]#TWLߺ|~-&m(XOnGV2^5Nzi68 cE U~qD @ƤR~;"Ax|!?5&X %OP! e'yey!? I ?jְQZa#vOYM3UCK0RAX<'CKYf[\G!fUʕUF>A)}Fz'& UdneÉ*c8q1+c8DfRVDg&6Dun1VtDqT5>wi}]DIBH@(}Gd xlӓQ̅ŎWFf^#3irFfL;f̥3sa-d#,ߖe9Lk 0̀QHˀ2^Ug$O̔ ThC_ol?s*4J˴T+ʌ'1!|{Ikqn<=oEJ4c}#M[CS ) ! U *$ae>O;](Ye-GBWJͱƚŎ di)"յFen Z$Tz~"H˔{@${ Cqs#szM,1~mrb ,49Z+ȲL 4Gپ6-\IT\JjL[ߋc-(Zvν=\NnȭJTbgī_WoL/buރsebɌ ^P'Zzp2c=ț%N^%*͸2̆Jٌ+'PtJZ ,EMPf+s~ol>^Ed)4vT| e.+q!/İ,Lh*Na#`zeHZq VҿՊciϤR+fW;"LkXUX+TeLD ˒'ejlyY<+#ZVQe-v*U*7\Kߔ# yd^UfāxޒʎK ŤFvD!dՊ)Cb$ɮRAxBuq88wQB q]GL|zط:TzץPzyZ۫vӮg&4P~ _NLC_Eu9)U+:omwvV{>ډ &aV,&ףv_R'[e~TURԉؚFke~3oֳ7g3?WbkNZkOWe;轿׵Rދs4q4+K􀚹{Đ_Z;s{>>2uq}2;b:9U+hs\ 'rEo})25|h :{x\}<.o;'>J\KQR-3'ʭ A'']f|4s+ s{uSxәwC΋'rkwuʩlo wf;ݥe=/Z\ZƏ e=ទ.|ۭYáOxsb;oYkG|=nmn[6h3hƋU;y=(Wg/?:\Ї;T(T `aa F rW~je%FrXMl}`)[QB]𙛵GvߦuͶ_u3amk4I4jh~>ZFXUuũоMȭXC!K x}pOU86D(l0̎;]dY/No oit mY'U4`*)8iLQ$b*N'EEPi3&掚 [UPa*-VJs0E:)X+VbCMQ|QQ!TGSRULQ͵4Eka*STS^uj]STqTGI QSi 5D>CT BdWZc*/ڐ)wK! WV]MZMò37*7 GtR)7 4,rD~P33fqMw! "L?Xǰʧ"`55UcQ%ꀦbG4K7]^9 6v6dl׷t-ˉIBJBaXAr\KIrıˉS*' EpBJvWrbuB('NѫX*'޳8vi2lTM<XlX֓¹ SV+Q9qR85KZ+ˉۨ7^Ž{S*KJ)MCLT_i=ms)UV-ms-TJږs2&7Xɚ\ɬ͵TjܠbMkrs&c3vcVRQT3#vT+8vuGeծY|j7/L K :u!JvӃ$>yJv Uk Kv3Y+QY*sΆX٘uRoz-&-:(N P߹5ˍ(r|8R!qVg RppaG4!A%o}X4a5o #op&2PD5]Z]GzD#N IE!nO3PP)pՎjǖ쿝,ϤBJ\_r\RidD2r$WctoޓPۧD?~-ٰ,:ZNh9 NΧ{d.S_=V_DRoj?"U,ѺyP^fT q)ԑWiuYwǸSӸ>޴w2U<^y~;3 ϩΉ,A<5b쾜uw/uTЮUXFg_XBlce_S)^Gpu h?ϟH8 e&l)fcܱb>\F/>[[ND=~lha\Ţ0OGR_{Z >|c.e$WnD^Yᷨ2dӬTC/Sij<5^N| BmIk =-sj[EGRtH *-lܵ5ͺ??8.Ƅ +~P^kȕm0眭'ޭOߵ?'b9i8MVwͽeDiGD[-6}c~ǧ<8˿!\Q[ugw?sutv7?Л?c,S^i|7$SIED%m-|2 ʵ"HJ2Q]*^E]b*dtj(ˤ"y9*mVlU_Ž٫*K)5д[Nv+6s$VHy/rhQ{N4A"D&MX4)h1G][9iKsJ.MNRIwtl1aU &AZ MVtRX冀Skelf*}ȦPO4R gA{RdU='_=y]\Vs{Nn9Q }$ۏ<2(\IM>B=pVҡQYL]$b++U2'쑅𛖤E*y^ZWubLܜOɽYRtI:*mTHq]R|FDGKӫD5✈4rHqhz'fJ>$!lzmG+c;kFդ=*Z_^Z+UEINQuu Ukk?6j?t]) *jݝ8Y+hC8u5Tc̦W-M?ko/ue>T>T66ڭڛ<3!*P%U6tڇЇ /-,+U[BmeQp8c. OJwLi'589׈:^+5 .'";hA+{ZSm {Go竼hm>6W˫|0.Z9GkE/+-vG]~-6BM; l=/ZE`Z˩iW&}b?ݑ'ҝvUN:N?u;{f uǺ=1hՋ64v\:K;/}ÉTzekyW1 16ا*p|e7TPl!T;fC X mگ cl-B4j 7  *4pjCvLPbQE{&=Sʐ6^JI ڰH7S1Q}'V|`kMEU$T&kkU]A 5RЊGѤR8l)ŎG|JbamLE̚e0WBJZS ZJA+B8߈9R#ժA$4&M!wڀ! f@flD&?,kY!#2a(Odɨ/ Cdt1DKa< 0F4ʓ'>f$,f4&Vҿ4Ķ8YV:4ii{D.𘊚sf| 2WD "jVsf$UĶpo‚Xx60Xx8'juCgr_Q#`, Syrba"`rDBguDx" 9z"N;DVĶf"[m1!G|!F+*#`|"b_M$,4 [v[ˎ[+[[ $l-lMֺʼֲ$leIZRZu%IaIZrZiUU&i4 ir@Zi;B4]i9 -v1 H+_ H Va@Zi5I@ZϐiYjI@Zt@Z?СfYkjֵG( -T4_xq@ZH+Hm)lMVZakIZak [U;l+CakrZrZ갵:Aak%rؚX]!l8l:㰵|һ|+ ۺjnFTp[ I`VZ_[)މ* 8Eiei9I@Zr@^Q H'l-xГ48R?+P_XT} z_uq.N~"w@k l  CgTx1fl/}.40&%lֽs oXRXXd>E8I88gŁ F?zV:=i Q`MRi 0 Ts?C3)֥=ѐ”l34,̘\K3cr-̌/Ĥ^nmsϦ$Ҍukm sj ֺtv؊S\R0'SQv958E̩I*ͩI*͖ȱ1I1yɵ46 ccp\y{+-^yLUh0 D2XL)Ft+5( hxc ,1y'oM=eCQ6-nTl eËrYm_#eWw(Fo@ [l`Ҙe,<Řx#˄s̷ 󭹐JC_A3q'FbGB&2DNj[|ػ$ME`-'̪Zѩ7pZT8w>@$DzH`Nh`R1,G͢[tX&tPt+2/wvNճ4WAnuoBª[Y* b =bIYu6xK᪫bHmȌr, ksTDUIY %jͅ ,gd]Dd7WK2bIJx.jȳ(erJ2z[Kآ;?}a 0B2KHY$X, +a`QXoFV<|Cuu+xum X.`Q~ ۀPIVCs"z+R#qYy|*KOsFH(Dfտ@dVަ՛1WT¢U$誦 ɺڒ늁u\$s]P,7wTnbY"rFsx$s>u#*w#1\HH򉕊n$&T7TF ҍ䌒u,T rBIM17B $ r6q ڒ RA4MH "2O׏0TJH,CPG*vqws`,Z n | Q3N׏ e4Ye2V T b+b+QZ[!‘K+V86#[Xl#{V86[[1 V8FV8.i#T GfV82qj[[[ j[X8&7>c}5vIYPlr61iܸ}[~ܘIbXlrcbD6F8*MnMnd61*4qElt:6o&7fiƏmr#˒&7}~7qmm+Mn\N&7F&7 K/Ŷ[߶‘dm+PI+m1[V8fK \lc75[XhS di2ڶq5l[V8vlcKg+c[]f+N7pN4Vw+RY+@1e o'Z؋peݶWg ǟM+pJZᘆN9bbjΨPI VB .kMFőt%GrXwr"*] B%F\`[}8gZf9Q?eMZ=E*fu{z!̷ֈ燃N-> }/seD;ꦸVZŵcmqmgїbå?]uϐ"aN=ıf+hB$רXOT͊0X9I؊SDpP\A5--JqG⎠~}a}З-n@/Efޗi&S,FVBmQcNR]eאV/%k>KjuxUz}^l ~u(TP¨?]{6: '*~UP۹~UNk7BGߐ MT}-bݎlm.{{J<*l;oϦ¶cUGF\=)xyk||ղ%y5sAWPΦ,kc<>OƤywN,T+ϮE%WڤIݶ+zUwޱLo*_wtR].5[vZ^bw҂[kqFѕd%.J-zZD0S J0#ItPd6}3ȣZܑU\q 18$)s| 6iJт (Ȫ}oQBPlQB%APhKY.eJLR$&)bLWZYx2eeM"$FH"rhUyQ>֗f$rI䌟&qcDh=aD%'ȞȞ5"{Ȟ%=e=АY݅z{~"'.ىFg^KvG ډ&CJhhO8!=1cl|;Oϖ%?YJHkq~2䰗r+ˉ%=xf%(\%u.Ѱ^.v%kl/ƄD %nw[QBeQBY$( }ءG}* R˶8ϗBg?%X(}=EDlaꋻrjqIEKJ\R5c\f̯mNg^^*;(KT5s;8}@^ƩV9߮YwTh {Si> bb#$) qISDBb2D/e^sd);eZ(bʜYȜZw+GC$Χ]b C$W2v3xfO)ʏyk3N9C&Fcx_CT5 Y]%'DO\}<ӝ0!˪oS{Mq0-0?a([rJ\Y4q;/驢V'׷r^ Y$-,} CH|Yi8>+Ր?|PM>-|eտ` D9ᚮu倎,|M8S;VRRy^ />5^f|9 U@nc4]\벎"8!j)@.9E}绬5U$b_.%%g}z]^}lWS5鼌/,i?-vPۙQ/~/)TVU='2#.SK (/=XNp}=[p -s#Zo~"f|峿40=AV)zTzR)vY5[{ƾJh=f #L/=%~x3Huo˜y:^<K*Dez qs*b5{d~`jp3W2ӊMQ/4KQN5l/2^9ѷK੄Sy,5.sW (ҨhTk#-dAT7lIDYDk ׂȢ؜$ՁCP-.Z.\XS},2{ҤaZQږ{.W?L/2`9 H⸔KqmIt" r6R$%+I0޺tbM˚Hǩ/nIR,\imŴvӪyv0mԪUmFXժض U$2d) kH 7-~YJ굂a[<2M?Ȍ*kUPJAM1l"ΝfQ QU6#2MQ)OɌhu!]ЧHا6F觭MLF666jp 38J&#ۄ˲,jȨ[66jm)dKoC2BP6j֙v3.5+CGVm]?ɯ/2ԷNM795F0tjժ7DX͌#ŭ:?Zdk.H Wx^6>|9#wmY*Εe 2Hl\[| }+EWǸ3?+5][7R~ȋq\21y6P E[;%_cq|vZmH `W->JE3ZW֨FkT=3W#pO+s- Sw>*5kDYы9{@uMOzYiYGeY{ϲex{ش+6@5G^,)oeUC+eq|b;T2s"~QfCm}f}2Xh6\5gt7/TfSY6] .:o(k}vg=닧ϐe^\}i h]W9/ĹԲidPyooaI4~OG V4I0^ Z8^ȯC_05swqP}M>}^m{^u97 !|]~z}{ C^L)23_?y o׆JxOǍmj1f!MkH`_j}]-3uy"=x9 y'8𼶬FaֱoiiϢwe]rF'@P`x~ܚc0+ArX2)^J*lEf[ . ^Qk<2>wi^8Ϛ}zIՖEըZUsfR~ qaܪޯ_23 rAV=SsD׷U;֯ u;G8%5 ~!1UVIcĩr* Vzx:!<۞xjWv d EW;_pupmpmupmmF6V=j/z7!^ D”t`RU㐀=N>C$+K$'YN~^Kț+m(Qe3#p Q-cqIL{ں.j%XVЅlz _!W_‡#tgƝVw s5ޭjUv@wTnyQ> [ބP]JѪlFzVeJ)3H lBz2@LQm=g3mYMcހG%6-#,]b%uvM۳E|r ׺vҍߌnsuc*эP~R'.yzfxŚ8@_N_o,|۟ή؎wи6#X=إ\%:.۷՜=zM=*k3Kbcj޲s*v6V}f owxL12i&J記0m?c'U5fEfTo{ܶe3fᶗfI=k%^6uV϶B5DaƔCFUoy}2CMj2TtYdp 2k>1ãt~ry|M7jvδ~՚hvy+_NJmH bӺ<}|]b_ExՒ޲"j2T ;mQKgb}1kvaP+gu>\9i<t >[\DLx%kͼ)p^稟"/Ћ}xҵIǮDM6a~ unz<9|;*]x]m{exrk+W[c*\LO{)so˫9=cyu^Nx:֯Óyuhl|g );ۯ=-pAt ՘؋9^.%nb*?巯-x4X9/]fόT*revVU$mW!2)huo%U9|:Ԫ9!*]K Bj'׬>>yUZ@2&}Wyb2c( #|^2ducpe~^*T* tIVO'[BJQB%QE %G0SK BHrnCF egJ*PB%P6AXb`ͨQSĔa7GZQmSSFE)0`GķP-l,ӡ2\ (?Uel 6 G9ZebGW!d$@LNo0ѳAΨo|IXWv wFŐZ?s}8~!(׹~rjAEՂMFE&"@1KӀ^2GP-d:7@_M@Q"?_['y;" ml=Ι0N~70Nf>s Mv9ɩZ7Z4 h2GS_(՛!Ύ7`Ov(r0!\['d"\8VV-%X;VB%bC%ܒ&}Xr(i(+,md1 * n ipؒgE*k`[[=AX*T*VAJXa*rVBڻjl" ZtwUkrʱ#+ǒ2x:ґ\*8+mʉ{%:!]EPIoW1UPz K++ INzGVQicշK?VeXIUziUN_iUöӪ\iO[ULJU@鴪믛ܹЎUҴUlh*,Xl˒>A"߭ȃtcիV"-[z6E֗Pmk2جOlPdeF!G4**{d*$MA:f^SJI 8gcKr}]mP>se&Vƒ|a;! wαK*kk3ך>8yX:dqgܤy iDzGe-g$l4*kbzk*WmMaB0&LO6*'8+>-57lFflgIbjo)/vwLx݀t/iŶ*& >kT2aXƪUcLIݖw8qa>[l3M|m, f7m)F޿ߍ:6ǓI|X=u-=;۵|XU.G箌fx7]w=lӓȆ^|~,)/6Qh uJ Ua&eIi+ڲL Mm|zbX5I`D|ٚv'J[T_O퍩1l3ᩭS{{e{1u믩&֤So%ڝF6#SxfY*>ޟeFijFZu c)yQ!7oזBb "vбIoXIȚr$ "6sŲkC4[+We\ 4r%th5"4h֬?+=+G`;HgV8&%mWRpl*6KX[RF Rې+IXu+.8n+ b;Ka\8 6JK"i+$_ir՞ MΰHOW{toGW΅n6&Xjn4sD˕I+Wj%2A#Wq5"q'Hfb-=f2cWwuZv5i:`cV&Mw#_u,ۮUc#UQYY%F%EMQrU܋S0ZwԄTJLYd /kGjT 7o,$ @$)3JTl2aˌ-k>=H%qQ.bdTh$ ZؓT$I6XcYS k " lKdSЦ6U+*\ .eaDTqGRDY◤P1) -IY<ÓQOʄX]d cUe SM$"\2EP.L?V z%)̒A➜qZN^BãmT$K"r/͂B$W}"$Lh#"3,^^GձշO006_HEHR!o2bJh2±|[AU^k岢X`  }A $+íjjo*x-T_o*TU$Tjd]B*k\#cIV+qC% % 8ުGVuq\U!FŚVb!bURTzjFI8x#cIcKQeҪU%M@OΚFłUc=[1qSmF; YNK9 n-u hlhmEne0-VMXmB6rK62m >?vՔEkk-]e6#D+uSkk&v6sf'Z=fm,f(te{28ϲ][=º"eB~̀`3 m3!lcv5NOվj;)N9Ά3qeFcrl,vʱxKf|սdPǞHc b)ó;qc;Rk$^Y)fdC[UJKQ,ɸbg*ӚՆʋV1VrQ,[%խ WA\r,]Z]*5$STbIZvjKb) OM'XyJ%SeS2ªOyR~ "?5`)*+PA%T݊PZ-J*nu*MW6(T)E5+ZTpAQ) RVbjڂT.*R+I&3ZlVUQJU,bU3ZM5=dq*Woթ.+OTD=mcTVuY*eEHRJݐxPJ"f+YMnzV^)qX2cժ2g=DPʡ`˲H^<,YXͪQhUU>,`{Xm+߮7hXeY},p5 c+)q5sWR1g.rkTD%!j*L=˜*%U|6l8YZ9؄/uڟz" ˺96]Ea X *Nboj@Ɗ==Ʈ|vpU_7" U-iUuoX lD6&If#ϐ-ΣX_xKuj2T߁YWVGX~Br{U]$F`"}K[uhl;;5t;68ck"·q\?= o\3"!z"׌V$T]7 f$7YўH|'QTF#u*9yܣ@xx1"ǽFy꺦aQMPÓ+4&+Ry-rrYI"}gW RF*ڙ_Qi}M}wƸ )exeFOu6V5}gʛ/֝ƨ؝̍xrB̪=66a;EZV%5-9ߗa[lae,acc1e֔NvqvӀS|}kDȾ5;".j!n33J>翓amƙ'̙8Ƹ3>n/ҝ_#m¬pY@|? 1[6.igG Oݩ>VK?ܯe@Q~U􋠊/c1Y|pQ3u]m9^Tc\_Lҷ,Y. 7VoMά ;ؽN7G,cG,wⱈ+FB|]Q|]2U|S3L 8B$S["mjӡsjKdɺr:iJ"魊5].X`%TrM֣D֢ӱ0VF6]DD9>^!pi5YU0]UtDrIRʑ*JWI\Uq'TJ"i>d8Ru:Z :RaP5Tp)X)TS-J[)"jl;U;ط&͕IV.ܾT{ QMQ'랭6r%;*7rPQzOJtT咤*].SR6TMڊLy. S TI$T1VvʉD{}wL?dOK2<)ipRL=nmTZwbĆfkɔ|թu׷ke\TʪY*\4_e#WiX6Tbi۶{q;aꊷiڳ[_YyZT$-^vx啋RQGҔHGVr%>^NE$4Ie.(>%pHB%^9Yxs/s6#9RQϨ4]" iЉd4!&c&cf&B(qM;FwFExOj7K<3]3̈́ɲ٪eT[]=78g8{*:if#3̎afdLB,>eY}Q7-<~حjTpZ݌4V!VS \XZإuMEj\{ϵӇ5*eo]]EbP֟@mPo'uHHfll?6M@$3HA'oփ6j\hևvhhEЍӏ66Б6cJ9d_,җl~QK)Jַ?MߎaHo=]Ws/y`_6nu[ykJ$цtVd˒-,V6JdQbUnOtx[vP2q Q,yJ*A`KKpLھ"1lgCO9gifB%:J:td|]EWrUEGPRYOlWSTIz'K dA LÀ6ENU r4d(AN27fJ_6H|%c4=6_If|%4=%+]+HgT9+JfDƍR(LG07&j;j2VzXMF% Me]j*}cFXMgj2eoT!"V?AUɷ`54FD'EtKdjA&xb5].bjr[J: 8L.mW{naɽ/آ޲(]U{U0≰,UWc4t @8jCm1d ޭU4ye.(.HwӨnڲZG##EP?E!{K7EƢho\D=ET!ؙqUc˂TptpgDpTf֩ӵұe^ ieuԾlUeCR5<7Ga+fr;,k|3fc.Rj0nXt:ʯeA7KY7K4Z=.$E<ǺWԩqS+*]DOOO~cpTsK7kL3p ODMّD' #l*WGـWeTD2[YU>rS*cPHs ..'*Urͪ2ؿ՜NۥNUZx3U94WG:o+1qLu(8v>vHM;NǴc`s}yQJ")Jm(զCQ*ޔ#I)޴%zSY)RRY))Jk*QID1 .񀭔gRR;_HJIFVlY)bSԑl'~HM)RlJK)m:RY))uI(hlN[Ik"\vr6.Im' rs$Aq$bI[Imb'R?'D6=!ZJTrsRIJJ*IM%$ @I$\HӬ7j;1ŶnR#D$ MZ UZE))ݖۀrSI'oIqMuukDiۤHl2D{O(OR$JEAޫMR$jOHw7D9&I( De$#Ɉ Ts)^hTQEoƽ%-Ue]-T-Ҍ^Qr 3JPIT.R??S%vP餩*Dz䴄_^%%Z2|kuYUDU΄eOq: ;ʚVEauI+,aUVl;PϦY6FHGX9Av%tc67_4z;+T+vMzI׫pTz(&#Uԙ^@W9Avq%ޏYcz Be}\eU(}\ ѡT֡UQ 'kZx??* h"U4nU{~IW/i*81+8hMaJڽIڽJR(+ਗ਼E; X|kr#mZu,iުkHVU*Vէz V;Vn0_*o^*#7U=6%׌*^oPI/QIT NAeK6t*)%iTp*0dŔTFf$%kG '5"i8#TҞ@%G9Bm(Be,pr B9L5*i'#LeB;e]H%AQ㗴u-`Tpe1zjCvmDd5j` gn1k42lYpFZXpQ1l+{ }igێ\Qkÿvi2kL$[:A һF)mm;Ɉdw?2c2"SpM0N~7snI}P]p>o"6k$m8LUnv}4 $PY/ 8ƒ,aeiº. e,*IeyrBfˌ *M B,l`9! U쇍anWeHl,|ΆȦc_,˒cdˌ26^IȌ$ ddI~5bm$X%I:cE,CXώvmZm,\UD!XtU9 یqMɘ," YjKۦ6UyI)̢;zL*=֣_7HQCD$)JO'YjyҠUƑB%iqml7>JlqUhjwcȷ * mFXɶtkԢKUf+diQ:dI*hܷG߉2#;ՒeX>6$k3Y@8]Je,.barSi̦Nf0귥1_癢=(qy 6`Y'a>Px.C]AL* ש"Ƈ޺/&]'N1i 6XF_t&Jfܥ3}} u>,T.f"یA,3*X^Ck?2b 20ba,B( HX4Y6  98Vdː9VX#E >k ¬r-'2ba!E,+G[X>֬rO/wӐ„+_˃I*{%䰚m4wEsvO{ˆ^yu/bƚ*Zp髗wWg *-|W Wyj.j$+T+϶<:e%Tq43[_N W|Ջnڻ谻0bVr?jΫ mye")"SMa8}nU*HڿXWW eHֿ kw}qOyq ̯%kd6s O)zz} H x^ eL.ˎ02!0ett} LX2@^܆K%P}*hp|ϸȄCD;Ԙδ bxKkϪBU OHCJVp?o-5L) 2q΋z-c~cJ!཭>b5γ9Qm{?sۈ^cK|~D>Kn,JCl|n[虫^dz/WݡbOG_%3OWX;X/͖ZS=ıgB>A_D~Q^ⷬ}JMJA9I؊SjzGT*Js1q3"c k cGG#Pס{!~:/<4xr}tMpYDŠcM>ƭ!nڭiz0qV#&/g=l5qYoXp-v]aį*8ڪ PϋY # /(ay-=:7ey;oDSD,,~\=lkۦ/ap`J7ׅn{}Áq(:.$E9{ MUy^k}j쒼*G-CV7eYDY6iǃ}>&p;t:}#>DRҋFZ{k{;Aǖ7KRcS1> ;,U_xf<ʴW9m IcpVLٌÏDꙒHSLw=ʊ4m]^ "]m᭻IC8q qprt":9'B Ab!-!ưpBWHN"kV"+^RLĻ\|KkɃ#cIkVoer2}26%~8)"Vd~"F*;axzg>T| Cx]mr]eLѓnî3ѹř d.{t*HULUoS)o.q6ZnF|h^_7rmx4>NK["N*(!bdiτ$Z)ީo8n=ZڍY%"њ,,~_L&n)澌SIw«KJ_3e~fTqqGy*gjIEA/Km~'JӉȋT{xv.98fSswE.5hz/ƧԊTGj(SJjTKDwɌ B$-Zm [ek⍊>#ݫ!R[Cz "W>11R#"7Mnm.cY$"ÛH5ŷ)+3aƻNVXCP}%o[SYm[Żkzm,]Y>Ύui-kb$ķ=2>h3]s---AD DDf\Dmws?6(?q\_.c "ۖv#%m.0ݲgGd.S%'JZ,S ,Bj5cW@eTxk1;͋8KV6"iZTdҮ1+QIXVĖuCy|U6.KVs\ t: 4}SAkvD%m"kVۋpqJow8v 1ӴeUH8Ο36kOz&8t\"Rd?-n@uX9Tb:)<咤VDV*%Y(BQ%LzߴDԆsY))Զ\{~/(1F*gy_^&oRX<{I+ LS%WWu%wW A3Y3 5 腒ʛ،*Tڞc]%5Y3FƲ^7أTXڣ'dMjfdͫpXkm_^ќv6vlUC*:UH> g *ʄڄoȅv=377V鞚97`AɲqEY; <}9i¡1 6YHEύH9#TE}pd*eo]c(t Ⱦ1ܢ5X`zRwy%urkB*•[SVN1ܺE4q@9ڧؽ:o@JH#H#^I;K.&gI[' dsb Oފ un!2MP Y^NV6Sic{" uyE u!W?WJ^P4z&]czVˋ4i2kI3[)5d=hL lFkh-J6;2_P)ίDe/YPY*3T[:ː98 Te(Ų.A)X5\q,q_ex,-z@<c.2&Db.PIe(\辚bbvWp.E\d\d1],#Ȝpc12,c17SbU  7)cXL`EX-`'Ty]* LE9α:+L1h0B X @Ɯ̀W2@Ʋ=(]ÿr Dh"9aR 0قEa">,aH&bl|X8!êfgE7|c?qѡ+A0/Td,GEXV/2r2kWZ6N 4^ԥ`c0X '21540 T Ēʡm6+T R'K*dm] ʌX cIPN@U&h@xŲG i30&$0fc ֶgØM{&z&#4_R/@~v%D0PJD10i5PwvC% Ojx`r(4K0pM4~PKl2oR@]\,vL` 2p^Qy{" ˱~g98 ߫mF_ .b,95]P)!tiE5էiˢWiZm\Ħk yMl˷&5Ky`dpyi ޢ3]z/m_v,I.W8ֶh@|CЧkhH aOch^kN&l8 d/{LI*Cd3)_ꅵ~lF-Sه庫0>BTڌ[vSק:LK}2 CG&#',ERFR&j/.aV9Be59?m:)|S.vf5]-5$l`~ѯ)1"ٗTMgҋ q[?Ø  n s}Pv!/v&pKP^/Sά>1 ^' ABmv)`ԮUv8]bz3 ߋVFWU?y(.L-Hp!4Q;ZAhxRrese7|Wq#tN'r8*vɈdz/8Rq꺶j#TrIUH]h$jO@]=<(,4<|.?X9S1'%m͋)35=/wkb|}ש*BXH6s]PVԵ62C3s,Ml_ƮLN-P]ǫ֧ : t:>eCUSVPCqt&ZBnhy/WJ}$ҋOubRպxwe0/-lkvj|p{8nӕL]+D\}'*O؈@U8z x}-ǻ1q|Sc9 SWўnē)k0QNn7$`JIeQQBkl%%`. XɆT6$XXf%0PI$pB|ɤ2c]%DWm[ `"I3mt\@fI3Rk32WY4/zVF/U Xk6^lD5b#62hrP}xEP. ʌIklb~p^/X9=2*jr:&MHqOE]ٟD1MY4k"ҬSmWWm:I.6T˓AXL$Tkf~i;Ím\3" ՒJT]yBeMcfƱ=&0-~+!d[W%)nS]7g6àYT]$ecFuG_cþ2%Űh vRIeĠZ|#Nۓ$cY1DzTbQ9 $TV}K*K化+3ǔ:rW_m}+9"I{$a. I$/>-&I%K*a^iXuMl!L%wYX%\.dIPIH.XʃjˌךdIPIX.Ƀs$ ͖,[Z&liɖ--kli.^~S[lAe, 6e浘-ɼVF Z 82e,f^.fljjQEI )zY,keȐ+ٔ <`TҠIeibEX&KJ,KҠ4h15L4h/-%i"\,!΢BVrߌ|g%ˌ,\]e|c}"XEv K±( D±HI8xp=2 z*qKH9]u#u3Z/4cYb/֥ U'T؋eib/$^d)JSvA)(.cw]%ɸ D){RKIlkd\[q)Vkd\$r(KU#͖4[2+Dk:mٿh: *%Z}N2.(ɸ%ɸܠ$R%6qyΒ Vi-4Z_˥[* SqA<K%,T\^ *Ͳ[#fٚyG/\\JJsqGŵF-rY.,c3Z.jK3vi$c+Cm7IQ场|fSmzǖ2VlL띍g:biݟ10G_ZQgwBW쇈_;G=6#jy{cencmú"%Ƕ!CoQ':E5_+*jym xd%\?a{y}uVyآ1 Ҧo7#j^`co [9ZWD\X_SKCZYblT,6ix KZJ_^c/Wqyɯ>sJǚ3Kdb[jgnTHZגTky\m9wqrc_s"N[nSg*5Lg t>e)/NjYjQegɱLo{NBIYqu 7vBBVRiHTuuH[e[Pi-,p+{d»2 Y\ 0hA`Yw9wG rF Y\d,d9d 18I">!DH9EH*}'Dz(\S!K >%)àN2>E"$I* }r]钠PIPSf&W߆++ Wb Db$ȡ,(&!FRYQ)l4#QIPtG"<-JPnDJQM[HRzK[;F,#0$)>eYD)2-(>9> *b!$)6WJB. i $)- i IHTҔ=[2X$<[xT +ATyKWATG[o T R92X'NKaZ**2'RIWW^!{j"JQR(̨Q BDi 7'LH'(dOd?p c+DVO4fT&J6h {(&LPLc*bm,FETV/5fz}*b;'6#SRj3?Ni'S9;uOjT˖2=Oc=O>9g d`gwo]Oq4J"]OE6AwE|_q*e€!*I6}J;nlҖNҗB9xm(z‡5_f^cӨS7>etmބFEoNa.xc W8՛(c5ޢXS;\myQaEY|Jjq9EiE0"Y/E((wp>wH\KpܙxtjPCi3U4@*dkNk$aS#4\+f )=XgDu/Ӟ"KXL|S);OՋkk=XӠ 8'5Z,j!0oPaL:ZT>neIPԴ^ͱOD3,2/ΰZ7qsE-k\\YB%n\XYWs7Ww ߔco*7K\⛊o |Sjᛪ87Uqo*HB%^\u=bbf?hb&7UI xhzݛǃ (pU[-;E65q7,OF'c%Hz B7{~t $2Hq6@BٙDh'Ϥ3qƺEcd,%$DI!I!xQ~"Y_6K(!" LGzt&[ 2 L&ѴHd}Ts6C @l2$D1:ж9Irp` pd: đ eqwHZk%]iCH4E͏h ʈdL~&A!zII'=/pǻMThpL$#-c2%G2M6_^Hf؇Gl#DSM(Dơ#H.L(WOkl% uDLд"&w3=}5K&\ɦ,]uȤN% U&xGL;]nHڿQOڮ8{p+R~J|oM97Q#m|5]: ]e2T "zFDw3HᖪT_Hf0_~6P)P 0g0CpޣQPuNELaՏ$N,LXGhw0ӳg*OS,ۧ++CC#r.K|0aRsΈl}Tc9F;էô>L*DCHde"cEaVX "T/8ſf(\G ͽkv袠>u Y|_?q^jEq#ܿs_BN8qW"k۝˥Y6MoMRbѼ?'f[}uǷm?aj\? Kڽ,kE~wQw;U*WtM#\ɋ(PNE2~ I_PL˚:r^ܿ&,ᢸx𻉺ףrB۰GpbK36nOdgIiHϿ~]r-?=yVpQ\ FB밧mR-ɬr\<3N4Z`ϊ;abkkwq˖`yq⢸VyS sئ1mS|ZyȿĒbaS{,ٯ|2#]qeG=BTdsyVqQ>Gi]XX4\1lF"[cj|;kM)" j= R<lQYEq.g,OKu[Ii_)/_|;^\}L~)_S-ޞן%w X*^'k/@VL@$^+59|Q :E/ P޳ѵꞣϽZ5.GE1I.V!-r|_OTk]^[?3]RD-ȱ^e|۸'X}^+՝4?1LӔTiQ-3jtɁk8;|#ܿs_G{QYEqw= /y̗G~վj) Z=?>?_Ŵ9ş[f RR)TsŹllmrSϐᅣ矲3Wryg cfEP,O[z$)\3A kw fjiu +Ke +YR,{(8=\? ˔o{-}g;ŵ^9.v?Øx9ta[>mzG;QϹ,wYgHaA63 .k{5$?}c?KU`> P(SGvgNDٛOVp\ OD7r&_-ߌ|l[|ė_? i~\?< 8_nz8z>)8=xg,d%[ݵwMQܷ}]8KH%YtϳZ5>p{16>?dYg+t/+"懮_a9ǟdf\']sU<u8iz.}lw3Z4W[k2NJs竣E$"9A/KV>Xs"Vx Sob⋳͒0&p(^ɼ}23Ym.~OEzJŋb:>#\/ο =°|M0N]ϛg:㌴ӹ[|WIRgZY:k/ێ_#ܿz?d=@{֯)".keKii5/;mòoKIv3o_stwp9%7]#LgϳZ5>N+O|\,2_+3[_4K MvW3ք"Z _#ܿs_ZaOW{_U}|RrKV5 L6eT(: 2\rbPEc/ELP+s|P\Eqw[*/mg[D~eO(VTq%tSg 5ΑҮdg_9tU\~q|?\kUoC|B 3Xq\gk"sh.F~9_\ >SEϲsfv?U~yYreKmz7Zs#I_=^/_l]K: ggoY?ۙ *8MbK|6ѴvnIۖoRv~6.~VwD"GQ1iN,]TcӐ4l v m/A,iC4o"%ejxCᨳeVZ+Sߍsx\ZhUqۤDĥ4m<[LlJ^X^Z{8 H;sfk[9W8ȇOW[gZtѝ؜JT#W']H ޛKy0܈KJ28Qu*dMagyo»7 ilo- 4\D:}שbV6&jhߝ3o5!7#C8kɗ%/\w vv;Ѝ,qO>tӋuKcfڭ;L\4<^W H!LaIaѰ|ӥA6H?$Kig>=NDᐕ/JfQpߍs5޶φP|Ā&Tid';Ͼ7C`6, -/A)Sya[7Њ' sn\S%FO_R!QâGy*`OU']D/K1VfA<] 8o`]EˬSJg)-gT!\6D?іwTͯFNW&$hFs'gčT |`*ٓ邅t޻Ul; ]sM}t!h},GIIu_,@$-{|LD!$2^r@ODf-r $q_MW=O2VG.cmnн)I g1.m | H pos.3hęQSj3*Sw~z Z6 8 'H -]U^壃Wfa R;ՈFn6)MAUq"5tW;C G+xB?[VrUWkNs 97KJ|慆MZvmBJ?N̊hPJ%GIW&ć*E$(4lәZ&qRCftH݃ŵ>b=\u8uHTԕ3Fcrخ%.Ӵ+T1mƿ}t@jփ9rHgwcnObTdeN Bq%pQc)H5# LBL  r_[puR}fhhI*˥᭨UUjxA?% ٖӴ|6өe |H὏̤N4mDwn8C>ƒ$J/ ,"ib@v`/Q/H߿냝-RUϧIcwL~{+1!hDDhlyH IL=R8ײ!_[B^>t@Dg ! "wL&BBQ1yBcAb\Ċ ~[~ KyonJ%'E=Qh ұ^XBNZkut{~~_5'1ݙTZO$QAv( 2/ꈔ2|jxXrT.tXqLfiMՑ`1wDc^~Z,}rJRr4|6NKü0$c\c--3 ).h. c! _gg\q!i?ʓ1gisuGyza {i }6 <%H~7N+Nkps⮿ $&ߦܴ6NzV=-ZX"}SFy6}345n3J.>@j0AƤ.ʏ 鰠*ߡ>[APPF "Ov ^{ ,SiML%ΔMNYEޛeO%X4 s"3{kUl,߰g` {(Aw>4B/ 2ey;y1zKg}4- W. iC r0йl~> KGl9?FEi/9(>d˧/VEFKnMꎋd,2XOm_ H pDץ⿛sUfTPɿc PW1X)U)H?k e0W'>"X02r|q:3*9K\ H"^zS 80fd>Ib@i_w^_/LEɱߍc( V-TY<7 i#V$]KCL yZބְ81gVߝs ) @k D4"L;uRCJ.N4>m^&D?DndB>&͚'sʹ4 .,Oq^}KZށRĐBN9%/>iqQaHӚh\N>!-ъIix>K$A 8D- }YyDi\0@<9l. >1y@`Mt5ICG(Mt%HཋUw }7DOʶ>7Ox?㘶"66il*CyҪ= Hov(%qƕ1@nUoEѻiQ5? xlӐSHZX$^گOZWg*xoR(ӭ{p8y =y!o~#*ˋ(T"(C`)(¹X{`h=卓uGώۢqKi1k;W`%Q+'ZCE%hZځ KKkxcOu<&u1^ ,΅|Thp%/KĠEWs2NZ .j?1.% "Bǒo`荩FpbU 6;&.AJCEĐ4z כ\}XA^3ja\dۂ2!?<ϿB2r4|6s :VȅHὉG؀Qa4v T[ޗIԓ֐è7@އ J\x*+!n &}FY\ym<@(5Xdl7Ig85DHniB ҵ|L]0q|wmq݆ǹnY9<\I3κMVYqm9YR8օcMH?ı]4X}oшWЅH߿;po"p<6na]\?N_nRCX^tտLrN^R^Z \]& rhz !,OYö!@IK`ai7Kw"m{އ`8J5+%92wr^bYҪ0WW^LFH]O ǩb[8eI/,~K{z oe>HջeeߍJz5Vs7yFI4{Rީa)@sd5 &͎N=!̬2VG"N5 Կ5bZaчG@Ӊ88qh>MĦک;8$UJhFMGhcҒj4 0 XT6e{a[؛"qPM9b"nδŬI댏%]6 I7%gxo6H6onF=usmDPCikN1xax^DDѯMC҇t"D!Z=@hL }x e8ٙ܆P2PiDc DO?\*NL"l4bwr47cw\LuU{\wDte=;9`4ފ'[*-4mo.&85$pSr+Q*'ҵY |^ڂN3Lrwezqz J%8bDBЊ~ `fJDLIB,HN * iNHbyM b5TwpwH% ߝsөz+LUk)Z˓6Fr-p` h M|Xቩ`’›q{d~TVZ+Hki2tdH&M@RxN/,a/2:ѝn#@,~D ~W@A('Ĵ~..5 0!f糼D- }KYGq;m] ~# 7% QYH4e4*=%oixc 9'nS^8 xIpDl\m~$9ǭ%\ M3CVނ8Ar$vGsD.px8:St|"l6 MrMiî\_K={pJP OjjOgQ8yGm} Z6\0/5>鴖72^qT^ q˓w\<~F G! +z(f{d\DQ A9@vAtQ݄NRhJN5Iƥ$20ѮMrFjHZ d.^R x KIkxBc*Rdef79Sͦ(=1֩,܈Ԑg&^# KKkxcnmS7`'8Q܀aT$EpR(Kɽ8N}m{ Q مB53m=j=/5R'gL[ߪD{+:7Ϝq@69$hI_=f6jUuz] BT}'soN ͥ!_"Tj*6ѫm%5v_-hv[ǜs;ƒ(.~1LJCKp(hr.˜5fxдnϼ?Ҫƅf9d˺7Q/%/,a/*85b,U=K%j>K/}'K( DR6rP7Ł1<) k ?"P#A-15IX L]8. hW)S 4wÿHΛaUZ L`fCPt@Yb T7lTu` h Mx1Vp0ԁ% sW|1Iť++c99mhG8՜B$)( |>e)xoa?R6P/5dNၬO?܀.&<p0"V˶VGGKz!/R"]:\6xŸ֜i P6CG$rԮ-8}qnH+G ,a}gDDcB$䜨 Epf1b@c@$].>@SPTj%b%5p cbbNV^'0Ǐ8b`B~K\#!a `tW I.X.Zöׅov` vBi&4,6kĿKL~>g)xAO&mN]3t瑋?| E?I¬qxvCg[|҇HཋmNR:LAx} 9>5O3DњE$siXax)s$JniБ{AZRه>_|(3T 63ފP%""rzɩ,A#vH ` g Ȫ1X;9fOc1SphTcDUG5 \Q5ꣷ ҨH὏(FOkԁw CMaC<E?L Bp1L{yej%57>Wl4BTg|sqO<<)ORqY x++7[:RxRtV7gJU2]h0#{;֐Oɉ6o4Yn\-a/c t؂#;yi谧o (se Ok0M6%!^6D?khJއK1(d̡|8E础; =14!XuJf4Z ^ȢNĂNn}7&jyR$di[X".~ V ;gq)a'Y Ė˳D$]!Cގr#޲Aya {i }%B0hw܇*<lPxÙ[ǹ S24M(40۵oz?A~oAS7Ҁz)$> \^Uag"Q67i+iX } @= zt3gp$)!L3+0- /{SqqMV:,aὋfވʪɳxl`GZc!ItO I.94EIJqx Lza {i }7VQNd~S9PB<ƠtI㻆Klk0}f㰝05@ gya[{ARl(P1֍!w)HP9Z6胈 4!b!c*x¨gAsrJAHߙ0~l-1OICҕD2A_#q a'ཋ}@׵WT ݷ>NTFt(p,2[8KԐ;S5h=e4<6>ۚ)ZUiߝs  *ۉ7\E\*0ԩ@3ذg|#[Y}EY|>&Y w@A fI5]T! IWg6̉dRpݓ&H',a'ཋ뾶ވEPaRq&2~8]lMй$ `9OT J8.9t2qz3w ]C+ >#~rV’yҐ4mhS?uߖ']}2'f/ -t%쟗w♄*nѫ x0g~t'QDSQ@ @7ϥk}@HNSb GM}yyOv{D8@!QqPg̤U7sMbުғ5Fzq1e gx\_m 0 59IYH'+ vκȇ]WXix>'3_ |Hཋ}Rp $•3CM&"gfW*lD%&VɉޘKU@6!iHbG޻g\RA(w0}U8r:I pzQԏ jS?i%eixoA'3ECwjgȹv ]3}-; 鞥3p\jKgwicVޅ޴haglߗ,Y9DNNGR/8KEkxobCg[ d2{,QVz7=J:Z7]M63 SӖҖ.X.Z{J[L –bL|>¹=2i$$dG5$bP!D Ѩj9LMlD?4;mz.yEѐ'%[C[U&) QF7 KKkxcG'(D(:[,LsQǼ ɜ.F!ZM?H -v NE K̸uHM^ΔZLiXtQd{^ YC>糼൉6"swLg:ߝÃ\Gu?TY;:ĸJҸ A+xo%rSTW(!cĜPH=#p rXӴ|gbA,/,a/὏}@ r<# 祥/sk#H+ K򺔈 ,0V^LV;`%Vkz$<9J K1Ƒ&c7#+!Q!&LVܦ76%އ/8J" qfu?Uf8v #{z}%p-;W`6)hH42:ՕtLA'"!.(vhR͚4 $ s `J'opit V:a ;i ]Л|:L 8=ѝ@_ <^!x8#2T4M`9lI ?6A,,^S?kܭ{)|rLq-d|L]ϵ".p7T &XJ!YX,S14 ,~>KRޅ | ;%f40(enVGjHIΏ$`Q:V@|eM.R?{Ym3n:D;ɵ3vL}fSb2ØDVӘVe$INk{{u=票we苊nx͉Kd7DTA"g.!]LriGV^xh'==eG mjoXxL,2jD6v0i.ΡǮ|ñ4n ;g o a鶿| ýbdsZb^ZNn s(:0kyӴ`S^^d4%"Q^;oF zu⍂=Ǐ#^yyZ]q;@aMɹYC뗾lF H {) CIR\|iDQBv Ė(on`i] uHJ4./aMCEyv^[Л$?_@c摝@r!JDzQMiBS~ly&{O҇ gٙX8sN(%Y^9PH_VzzHHAiGj Ikdt~eS -U%a/὏`AvT|n^O˛찫j@6LI Vڜcnj \6H;U07 {i }辇V.XEc@ No Lr&Oq2mahӴ|6?-r6w&׸jMNgOOb)o;3lqs5 0i4T@k.ZH 0l` sׄܢxT m-Tz*Hgh q~gt#[A )` G/^ 7lLmEzh';D,tL0zK H ,LY>X>J?ّɂA(b l_*g.*vsZC0G~JA#A I, '<=8XHdmۊ<5ix% \̥aw>sb4*#%4V/,s-ZL4wƩ '̫4^E|!,P[Z&NJڅgd+mF9(%KV-i13Xq\.K#NY=ITՕAZ,l->.BhUǵ&j9k&[rRZ>5B=I}}Mix>C!` 2AR/$` c?#s+;Q[\J+!^3ivItiIJ14Df$Zsy;_Jة*DysD@q,OL EJB\)H)=v/X^S?C 5bwMfaetlηD%bPjHP-Er 5TFq9&E GKƛ*ӈ,9ad4a6D?kxJnzS ˒ őش|>˼n(&ߴB#p 4dX}F鴚"E?Gy+9_WjX4,(NFQ bf"dBI'R>KmkL:"슳ìaq) 5^t J]Dp==ޜh~ЦC!><(adX=@"Ms mK}"$ǡʦh(_ L`po$&,^K{/:*.[]1u.99KPߛU7g$ l IW)@]  l䳡Qvߛ;6MTJ}FuSǁ|~؃zmjKIY?@u@2 ~u8yM?wLD=8g,*ɴ^jHyq.{XC gȆhыǞl0`S' d"c®^t%I 853$W8?\xc'|kZϿlFz\1F񱔜Fvn^ K~gI;`6SrJ F,BoŹєSɜ2Ǫ%>5N$}H5yryQg W]%.K{ a<3:jſw4{Dž1e4!c2&FL >y borĀDǛ6ɈX{@T? oMT RZAY˓nB}6g갃n4Np6G_ozRq1tꈐ!^,QIR"]>2ma`ĦwrT?vN6"?f L"te&#$Tj0=`q N/QP!',nS{z.?7JrVLs*%9^q&:Iu9y-7}aq&!N`_]&w1ƹXG{L<#x&ͳn3V`Pf#,w#MLNX". ^bkKAlJNT9'-tI,a K% ͢0y3"Vcr?#C7X3oNQϿ!糼&8"5w-PFj鵇 E2/-q^8ևD#Q&xE )%.v[HZ\ ry6Q%,NK{z*ĥ͹\bqMts(i<-YГL /Szw[ |HV''֭=!zL6ŊrPkM0`iHg18Rh*& (&އSl ˻zv^Sx;iN D]tG$l DVSa2qeCΤ&^K{d,ttGs.䬁JGU!`RX B~ɩJMZFƥZa/,a/%=4o#~q.LJp߉ o $VQA%%&$-[3m !Cvh̯-(Јˈs=͇ځF] ,lK]X;koAB3l)a὏ J7E]钭!xh|k p@FzmUEMR=̪ͩk=ұ@Xj}CW S$sQ?]񟝕 EV56 ߦ4|6NA 543.Y;A/,a൉x}.U҃_(.h@u {p+m- `2ϥaчh^.1糼>a܁pL倄ѬDI⚊O5&.?fuEb~֧}K?kx}U]:pԣ?Xs.4Wdwk#^f[]oQ+HꜙQ|etVޅԞN}Eqr֓mᮢnRQﭲ'M &` 3 F<̙~Hཅ}ɺG՘,9'r  I3iĉnR%Y }69sY825Τ\ퟗw|f#JzSuONj[t;F˙s<G$c)Hgcs3RA&D?t"%cjxb T&D.ЗsĜRv~OI#6U! E~nMۗ Ѫ8hK}Z}Ť/2kW2:9л4NjH iY 3:jum6H?$%5a& j/0bVNg׍,g=8\M *HRɺ8Q&Dӥ)a-Ĥs;x0)A]+|a//wɔS6" sAI'+Hg`s~&ڗXgrOA P/^dx^B$mKzѲbqS$Mr"%m*xbŪ~WY B dT(BO6<{ľ%щ>LVS(6qRڄD+ǖGuU&ګs䌢6 /--iv+J A8,K mdl~> K)UZUU)W0T9mi8mĴ,ǽIp&Ґ_ɩWn!f4n'r}@^LTrF9 #)~%I@`6œj8k(7/A ya[xavx`4͎ݢ|A th,=i&\KiPo)9KRH.3ݶ\o?U Ld+Y_H'SB#z pq^fS-M-(^^ r>AmFnOY?9}=@@;K (W/+.͒z-xKAig yx(×V$VQ @#,֋Ԑjq ˿SC5lV1 ,!/S{;ف%&FUъU4j%ЋTHЈ rbV0 A $pNTCqg)xU3W&r$uČݫu|Y}] tn7!i s8:5NE '=wهΫZ8irOgUtiԍ,U؉""ibYd% FE\D:- M-83c8+s+9gEIn]L84Wun6H?%oixUY dI84YeKԩ4 ]VZi`%²AG(ya {i }j7:;o$wc4ēը55UL&6F@Q&H?%kixBg(YQaΙ9H΅TJt+t*B+iUBSNjjI U%,NK{z"hQQ-4 UQf̩<mDswHҀt8 OpV`t!w*8:OptcKG+x˜rJNw %< '8GlUO뿖C|H_ Ț8U-i^'`=x^- Uex]1 t6 >sʢM"4Tx1*^e3@z,>KkFDviGa!crp)NZUor Gxlv3fr.~*U` %xv [0h;G5BJf=/b4M&NUS, Y*YOg;-P54 a6z94t Ā ́h֔7|V`zwcmk04m,n9a߯]:T;Sm39(:;]KLb)I g1*eY.X"& ǵb7ƶ2Cq&gF$*+jMoFRb0  ~/PR@oݲAWfya {i }Fe@A q~F;rst D #Q4^ [B4m`9sk 8a%oixcpOv̜IT $jNmI`@~kFȇ4 03zSCYiFz3A">A$PXX}F:ַbG[4orɴx{ˀhBJC+xaOڷrWܺ$N]bŐ GYL~1FM6ߣܖq0.*҅HὉE#8N芅_j` 4 J!s* b2zNX".fwx>7&08wPI-")gV 1AwNS9H[ ،\]&ѭ\T7ͪg'bߝ3o9ճQ}C#iZ4[H?%577oAѐZ{9>S1zafD̎M˧ũa93&s&D- }\鈫&S+~GHe޼X2Ӵj'sI 1m6H {a[HPP[wqB܏"'ք! eѥ,q :Xa,NK{;">8ZDaf-xOaT+,h/|K̩Mh(3tANw-Z#?̹MA,A)xH]IS?>%sZT%\fdXHཅ@H.n R7w1.*hG1&jZfp֐t@'^pvi: II)xoթwFUcJ@$0yj/|E#}0giB)r p2.O:aZ ޻7Ml:B9WQX^1P^ky҇2Ea,"CX |R^q?Pl~7Ή'u2<̣p֨Ƒ՛rQ[@R}o4m[YyW o3yƊ6]1sGVO6Ӹcl &,ITp$-T \5p@k f9@8`ie5I^%Qț>-^RCEhCI/RBNZkugfhHp:b  lNftl/6z MgqcqyS,|>B cm`/յ]|J%F ^VpwdaLc$[PgIU]EbT &e.#zL'VX^[k{ְZ)/9W{8g& s4J4OV:v;H(' h-ݖ р1l}.=ibL" xpXQr:yU (mיt|bg$n=79{RÁֲqxoza {i }*'xoPli(SpUt$@&%4LZHΥ 2f4TrvR ޻u9lt%R܍"!J}wBWUڭlrf01.~Yn:%,͓ KKkx"ɈHbjSߝs1˗15Z~MˆaT*)$<)U]2AY@9!Q|BU S;GCZ^%;TRtS7kH:g9.YǛ^X^Z{:MWSepuAىs(dj!PI/Ä)i0Mg+1Wl&H?%m*xb/vx-^ݽ0ɹQ#xHTX!|& OH"Ǧ!@s3)80t @$$a'ཋ}J*'wgLuTZ#.kHe6RK!K1B*˄h|O:L ]lx4k')s8x8$Ť3zdMiL8fJCSKm4$./,~K{;1ˣ}Xs!!78LZUUiOX"!4M<90 miylF^NX>Z{{tq0jCLZ;؄/j,QȨaW&"0Yd6fmt~Wy.S].l=Jp \f{`dz03Kucv6:jr- %` !owMl@)Lb;]Sri 5~uiDʱum6H 9aZ ޻`7yST5N(΋g&9qqp\P&bZnœ‰ "psz+x_A(Tl,[GFfazZKx#^,quMæ$}IN/4Tj(t޻;8H!N3Sa[0 a?_<ꤋghzZM 6 :֞?n4ՁybNaz1/~b8&1kV6ƩĈB, c,>K{FfG{M ;9Md j?9pY>ɔLoY$g7yN6ɷ㑩(XY DY s`Op | XNS?PUCG/rR[Aua۴~&9KA][rܛKG+xB?;c^ll:]pGNd OclzA IMTmaig^\D;!Yor\@Fq :ZUODybӇA~y:)QdBI'YN_e+=xGge x,%\M"NZh!nN_,/w_3糌["ݕp!vxD lXK[g~4y#&}&$gcS`&X7C EA@NWs|Ll74 lhmpha?%Zg IX[gz ^, B~&vHvv ?O ~wCkb]xn XBXxKC҇˜V!4MlF>FGdKDX}!ɸcPQ84r|DeDjHc2RA 9%N|EFob1O4]Haw/K%ůߩ κID4$]uY0#BRe4 E%5v{ FQ4_c۹ ;p]0]xo6d-dpT1@1%SU8UŸԠᴱʔEJHfF樽wܜGT"YUS>)줔!U\'VԀTOF^, {i }Ӳ?iquM ~?ЀqD_qM?l,cK޶~mL8ZΌ5}kZ ^Ѓ5 )M3/F%9`dTyYQDZA&yPF0($>8mCxCs'w\.ZtoK,ӁRB&74a؉%nS{{nZn'g6+՜QɹՁ;7NBb~ uJ)qf45$Luv *-Oz𐅹x>T=49쨪 3ڣmIx5$N􉋩^`l&HTNXNJ{6q 5$}|I[HTQH+NT@݀$I5@`i4%k*g;,S S~bCx lvQhڶDD"Ґ4M<鸄/ c糼&+w^ | ޼FIr᷋bdK %q^K̘(\ՓO?]XJ{ VųwԜJΩy\X`yGֹIx.5$};u5u{c7B4`y:WQ`hU0<w\~آzMBпt,'ili4%oixC"4W5R혚Qƨ`)8ɷu_Iǿ}m "`& ;C6A_9aZ^.TA))ƹ#V$j/"RXwb/SƜSZ5+I= R7/ldJ\ cq&Vb `UiW& H%M"vSE~$'f=(,tC I>[+UM!<u84<P׋C(K+(wbiPmHڅ8@FS%~_b~wjFv!n8%P !bsA%i4~0B45g*ᥛߑc9S#pS{ I>Di#k69Us9 Lާ g)xaOMf &89bq?!Hx~P{J= Ni%i4Fp`tZޛkV+!h=Ay%}".X#Vl&[X&UP>LVނkЕ8:+N"x.dpl7,??(#۟g4C\mI? O.%W_ӆ΋4\;79((E: 뼝:4,+%N~b(=kq- ʊ̲Iڅ#p%XKOybswJLJL] W6K'IVrj Jz 峊`{p*<+tI@wcidQ@<nPI?~KDiH s"?T:# igt^LMi|<]Zܭ:z 7 *75,D 2nEEԡZ=8e*M-``s^gCN x&.岐h_8/Cȳ7A@Ԑt Ҝ.`,'2@,,aڟ\EN1GZ1ZapEyHI([\`63m5//,~K{z&k y܄q}3VEisܭ4g[*n Iw7S Z&HZIGmAŷ {TԠDpMF{7_ྒྷ#E?DF!%#tl .D4KA '}]#L<#V%^d }s XtSw98 1`Г$.HKҰ@Td\ |OO+p ^ȟ2[n4$MgVV6H?%o7 J A_t_ xHțL? $Ȝa|t^J!uAZeX~S?ЯMjہΌKqh^rVy~CMC-E#ˌ%qrPj0MXaGJA4j DJۚڅk&t6iN ̙9c<^Lȇ?Zi \d)k88X&Hơ>H`y}D)>@:>.YA'{Z ͊v՛>ۢgTD? cG#{eq;/oiJ \SA-#4ynH?vcU39Q&L ڡ F}-i ej )L IW$-XCcd p> Ig)|^r.^:#+NgL.$lP"$]uK4&H&/,` |TVqBJ 4>lI?&A*JʠAUNi# KއNB"!H@19'g(RRK ",iiH g!5fY^X^Z{&&Tb:HlzHyy76>8^M!Z׳=uprOyRy,  ddsIL6 !$wB5P !$c}}.v(|V \MGsMO"\+B;ʸ7YMǺSK e踼D- }Uܺ2 9*'EcmiZIZ~1[CPMon޻0%Bĸ1.9@c xʠF;zI:0ݖ~ &ԂN ~g`iKG+xB8|iA:Q5us4] 5t,ʾz;YkI%9:a`DɰVޅĉb@q@;;;ζ0ZuYrMCLDp#m\D^L }%9iL5=pr.[Q*#'E#T-`6Bqz,Vza {i }`S9~\I UwclU*K ilC POweY^i9 LH7ºȒvl(,v}m6ɱ3d{W{/0KnPi&YY@*?^JBVSnQUҥi@xq mTfx(k)hQGIC⌳?adVHBVJ~\+ lb 8qfo+goM^$mXi1V^T;n lVH"즆 fng:5'QRD-9dQeѡ_6>%h3&'(g6SFLMBCF`P!AQrt yV ypmܰuWc4ܿ |nK>5SLDf.4A^hU7CѼ|? ^@^l@ў6VX?󹡅}[| iM sNhWp}cE+$!+a?Tq6ψ$KǙfd".H>D;>a) zTZ)Ґ2?v/d<H"z-hfnpA4` 8a%}:Ȋ&!`7 ڙwςkF)Gű' FjyZjƺU4g].0kjPBR{{9Rk^N*m\¤$'Dcӡx],B%$rwuu+RJAlBCKYQje 7 ؀[IXzCCFq&HH:1Y! YI ?pC?UT4ap軵}8,s,(+M`S4:|'8BAP@ti$d#4=PWM1Ib~.u~ޮu 1`po4DuP$MA6o0lj/MycQFIO7A2Q vsR~d)Yׁ568i%7,+΁4{^N2S@Ŭ8q(=ە6H",cR:\z "wf8^# ZxP0˕glҞVK8vHsӡqw .Z2!!a?>Et@vVAA<^:^/^Y 4uf)#0 ߟk^?&H"lzm\XՏ$q89@-0m'tuQKp!"1_ ΄3x҆ }:!VS~|ۆI"-?~뉜EI@ Ӥ9rN0 +qLwlI԰D k`ڀxiDHUey-b"Q\9KT:Ni]qFn= ƈV&fGew-uu"ysaJ"1hN`9t8#BT V+S6H",U*{QNJ0'+Sʜa¯D+a@|i1`c]Q1ӡ!0 B8:>^i44ߤJvІI#HCwGH =O A#B"̆,y{YXi Ee3ٓgoZASVe) XpЄK7ӡ 0ІJ5^QY-BZ7^lPe|~E%hJMC{g-@a1h IJiCi9q+V^9*Z%i5h_&% T rRgaN8DYa8ծ,zN++Zk2Kdkdw(I$m{i 2\d68u]/^4qeO`ḡkBMN p6nd/F$| к^䤸.[8.FIuxQ^_=l1-མ{v@8D~$x| iFIy :mJ e X1>[ I԰~Olz'3Z”5ouZy@}Q0Fhty}ac7h:VIl:ʧ+˖yCΊ7q20V m1t k4+a0+VHBVRóyp%|B# B)^[qV>R< Y ۂ%%(QNpy66 uYK7$d4\ҁU p83RR,๠|a8JPA":2C]GDH½jPb1w`V. 嶝;hlwXbq$?4vEpFwE+XVH"즆ҰE_ӆfefPQ}mǁ M?"3#ۀ;Ih6V`YSL&xm l~OKayp{\n}wA ovh>:΄_i}:%Rs݆1U텧2mUh yA~~8}4֍t#$VS~@?Ywpu.}œs}D]:Nȉ (b,p.wIj~Jl}Z[RpO/?,uc3hǏSOnHl,˒ïg )PSu n4Ba6g!,Oh|Ij3y1&!+h<0w'R@^IAvP ;ap|7vS_ءW MTawOB4W4uC AO ݵVۆpth6su/ÂO̥, :U >FCvh?G]y g`qOs$ `?XTo RNj &XH@X-SAR hfjz'.ҸڶCjI@L BE~39/=a#ҕXeaDO-%)2vNDnܦN2m2Q'dz/ݢ!#*2"EQGMbD+  tOf$njϣdݜX8m聛MSpU:)_ q~ax͋㤮MAI7R5'yWI.4=o8%NWO [9),ҰG,[gdbA2y İsV/:HzDce >Gvh ȇmЧC3A2 v3лXe\/^WP> i|hҧ$$&sCCIƋg!.c$K6CkQRdegh]{}{ywV#ipJɿ\/Ǜ*hhim䏯h~a><޼pַ̾kKǵBzqKN6yѾy2dySM\,x|uJ7/>>b!F,|O5׭T7TiuoGrKp{a_z= #ʳ}pS2o0KϪ1/S2oӭMC}^P];ۻ'[)0<9[#?Mx(3aNeuvGg<43j"k#U~OfXz'VeVSWnٷlFx~߸oF.DZ[k//7woۓjIJ>~r}f돆{*SROX;Ow7ṷ[,}}9P>nnNg{Bzh||9OǿĬ_7oqzׯ7m_~班l\[D2g>ћ^\M|D!lǩ1=M_!RL[|U!/A(Y?R~GrO}o˘>^]~\on ToNf_jl}z<ӌFuؽr.ꟾ>Χ}aޜe햲#6o=1v<?~|zg^Y h|9H\>g;'{7bܰk7\͞nR(l> [θ>5} ^^Mǿ`؎ wGsw{c}|,TYzkWǎshFZhSw;L5KXi>:~_aل,h;ܯ[vZUoC>^eVmk=J}\9?;m8 lyhX"F]=n<"x?ԗg..}[Ϻ]^.?W~K'3ur-I/O*a%tZ_kpNǯo^gۨvR/7ϲ~C&eC]'VuC_ig`r e׿/tK^O7??}omOc7մy&f$R>P\T2Q9^՗܇?lunD;ȥ& p:m#Yܱn)~9g[J{JR&Cقᨻ/3-CK+׏Y|]j j7Zy{Ԏ]j }=g|gLyֶobm_~b?}i?=amwc_fV"X?BzZFËM'lFǯwo޽egZKu` tEhG#+c\2b-i }Tfoendstream endobj 430 0 obj << /Filter /FlateDecode /Length 4325 >> stream x[[HF<_@B-^Fi㺺j>E@AhÃ3Mcw¯\$*ӶN];]\/]+Iozկ_YEp,ox\H WمU]\﮾~RU*oŦredYv*N z)R҉;kXTZ40 EZc~(+瀔 YO5=ޚ4wvh[xwP*YěubE}ۤ[qD{ίKX,e%wiRö5݊vNL *yYǕp oK8< ƵY]M_ޥTAyH)CL NvQ:mN?:M;Z\/+/º[x 3xJ g&񊁂w=lᵸ;x( k|W}rNTa,^^nRѥѡ[{qü`  =ylRPcX gOހ]| "dy\݋R`}$aǗhҕ!?=-Ux[+l0&nmD%@Ɍ J[ _͈(yadi@7+T*1EU61v@ݲd- )IpBez9 K*e݅ 5ǻ}T>Ȥ,>ZFh[3Rm8&hg"SuŁ`HҸfmHy͆ObEjLOb8}?4ǴۉM}[>o` Zʢ=vAOhHQV@m"P}8-xP,426M ֧5YI"J8OJLs-8 B{1ZVRWkߢ0h^m5}EAP}s= -b7] [`ǮߤJqC>k (:;۠%Q4<;ܲ+>f@vG@g@ 貵L+LIZTa+)/!qd5@lUa{*,J<_GxR{>،HL.gLtE8/l#sBXhC|!Bm%T:xR:!е7&}t%7@:Q=7=0 l '+PJDNtކbDCҢmb?U؟&;ߟh_hv/P=#'o;#G퓺Sz/ בhko}#-# XG*@x/ԉ`DݦZ 5:0#۳mR.'"P^Ffy ruTR 6 'lT3+*HFe-#5a й|,lHeygP.ϨRϒ!2#ғ,;3եFpPz=uQU#bô)j 35=̟Q<۾ߠ7#2(D>)d{xi0Lň4Yh#&-^xpOs{T:b'qE-i.ѹ[4P w'ǔu28 N:i9.A]p:'6!9 Df!dQ*UAG] *B T4! HXp~Bdا2Ŏ*) a[TzF#9Q3pl}|8`9% ꣵr}\QUv\i@H1^Hv ;]Y# T?Oh @fV$BB~ X7L-b 'WVYAJ'$Ly5 $Rse<L('oǗh'>݅(@h|xU* >0I5`OHuagv[nĜ`uR g%/x|Ox'<ְq̟cwb  n\MS=A&k:JW"F[h7F|{@A?I/8dVv G‹ rJ\NLC<WU1]еQskvb~Lb`ڐ#zI#h@"(nGWeP+)@Ș8 wF>PK-C55B"%+ n>r.eS~gr ,wr}+(6{UJ #)K7=b8#əY[֙bQf"&Q&G00Q܏#5/ 5B_i_<9` (@TfM0B=5Qe?m5G~TUPE ׼K C 2b4p[8DW&M0(tBb &+CӮMPgAX%S 1q8J%n>Ə2|ʱkJ@BGx`8p%nN:t٨Ns=ɀK .Oځ!.%[4d,;H$li叉-1eǂ*Ik!{*mkx h |? Z j FI{x|6AҲ*jHLYn΅F"UՅ"o2FlRbekHANP`mxG 8 ѹ1"IpRRpYz _Ra|2? Z ːvT mnSo CwçK/Ùs kV>r6{AUr1wĔOJ3R訮{!qeYoOŭ/]COM"Ewf]T鑻"D}a5spHQSK>&Ży6W%|(ߜam\U^koڌҪic6umƀXAY"Fcįa%V <E-| 2s]$~ jzzo .NC۶pTk+u>॔m.?D٪ z95@sUa+w>PqA)r&9],kn$СDMz!Y-rDIs\1pHYhC3*  Dž j\s779L4}hh2ZXx)lV i'МC=թ|Vϸ=Nof -LV'84 M?fKZf6`fRƿxUx}/5i(aA$HΩv(ΨG3vďzKd~E6}ľF 0ۼeK%N㺪Bɖ }: ;/Jx|Q!Ymb͎n'C=pJp+f (!Bue1taHyׄA^9bW']Q뫿¿^endstream endobj 431 0 obj << /Filter /FlateDecode /Length 4247 >> stream xZ[Hy ^偰 ;>l@r=n;y\|LrNwN?VE.VbǍg{Z7F|իۻ!V:RP7Jh]o. 5wχZgUW3ldd#osumM0Yݭo^-J r;\($`;ZlP$?^®s~s4lc"BD͝4<8o[ -@j#sm<8 }nn}6X5VMVT@I̋ˢ2dR r+;4= [`~i :!epW<.;,PBeaP0QA٩Ë%u غĆ/dF˽` Tim^ ڄ~uo{5 }%&k:8_[Wrg>CG{vf :7ƁIN$eV3 muv״t\FSeo8Uy,5L^8FHP*}umu3KW3rܐhf+a~>ҋaw+ݮ 4tN dޙ.5[QQbB w;ҩPiB\\Qovhh8(t7{4 mUMf(y=ACeDx l1`A,JK>2+u q2nIY XX]֬$q8ܫˇv}so9!^QxbT4pDp|vjGSN$ ޗ[f? {=ݯ7DDr[PA&DG KM Nmv6 tkGdTI)/}U? 6EcMM!6P;߁kkͥ;>7ZX&-4՗/ehѾ|UҜ8KYS2.6K_59Va uϮ ֽ:?m+X/̺4f$Yt ؆%CsPC<]eD {U]_C\&1yvuחmAh>T78b88|)ͬaMͨiZ~&A(` -Fu\Y*L oҖ$նU7YsmSG bF*1訴_>dk_Qz>y/Mv•kpS3?C.?lP4Ob)#IX R"X+@ʭ Xa0QysaaofTO`G N C?;P),(eK&Cf=//&A' MY΢|M;; $T9Yށ9 *xhQbLx.aqBV "JNf{AZ%$>j!V%H4M}w*~ kܑ{Pk߬YCyDBK;MQ"LWh֍{b7w( 4,!D |+5幫{`!'-G1?W'K=]* 1sH42n&;I6|"} b.@)x[*(%9jeI2nchb(C_y% !xVO([ú<ڐL~ v;cE@JkUj!2t G.Z/:U0OG1|И&Y|\ N@?Y-/DFt9.R pm&8ji# ;}2Q3Vmf!pFqioP|#Fwup 9~ O3> -dSw-Fz3ɾd!XõahL8]"S[Ɣ[Q7 }Em&V\$'"T%p&@X*L K6Zw}~J:lu7u*3cG8V./CŹIwWuBNJ50}6=+ mz;1`ȕ|ԩ!ӥȫ2s4j 94mRGFpAsJFsR<\O RbPO\c"2?`UO2nc:,?ss*ѱh,$6 3N z!8.x)ě;Gf#T[ǀeGjMuFdT>^aS~wwD8_ [t՛ R`E_Fub#}RQ-BjDΨeR$e_s3v@!%~^h9iaoٳ D00e5Oys3,)CntܜU <_e*=Wej͋_-)/,I:V/ޢT5DTXAsgtWè1Lq:_(*Ea>Vy b0<* ч6ᨚǾ%Jm1/߷'C*+){7~Y9m>J"W&wz\*zWK87*oXFb]bpzu\'ϒ^HtMn%#! 7}܂X(i7՛|Un CY}pe~nm>L4L"2wٜ͈?XUg0WK}RUP: rA A>_AaCLa: >WA#CicɨGK/@f\Ì|U 'D *J>/\c03&A m@K#TJaZ a8VrI>zS ?O%X= ~Izh> (2J",b(?τ,b -&b}yE)P*mŴv7Br6VN\ȭr#3W:{p}KW +FJa&BCc-P u4L!|д;צ1?:f:O`j[ g+F'\o ߥ;'syV>Gџ*"t׉׻*M`T{HK NH;zr7ك݇UPO401dG8uߥ>;+3xS4Y5'0܁lmK)%?h|hJXCaMдހRZkX9iw(3ɩ#$@]s{p¤&|#UJ2(}va&8o'a@:yR;|Mī4XLhf7Nic<Щ*%6Vkxh]uTUՀ :j4:eX7 {v q A˾3=P* hrlxb5iqKlwN?>mL#\I")_w`s&wᄺ7:Nendstream endobj 432 0 obj << /Filter /FlateDecode /Length 4232 >> stream xZ]s8vͳB^--5C$@8C;؞ڱUdwems&q>DR ǫtpJU=|{s*gL=JEbl2MWǫ_DFYLu7.Ni:T1J<۵*׹I\|u+>-UgũvME l!ޝ}Uէ<f[z?Ut4q[ݾݱܞr- ڹAwhљNĢrٯO{CI)s'vBʺш:a7&YQՆ(, bFT-/Hy/j:L6)Jqg>>*hqs_P(u-H\ܟ [FY NϺT(iz#uRHJ-Tϛ Q6f:g㾱BTeʡWb6rM"v|=Gl}z=:%kgɶ,YVUݝHa/WDk.WsaXNl^:/i(lPB-6LաE*RR~OL`ׅOl0l{)GoF/,Ӿz7CCĊÈdJQvsnXp"Q.Ya(fX%E$)E+HfVw}^0(d }[Dg I^>Q(-Wgةwm:0YFnrn4Ƭ6$@더*Y; ݒ0eBXeNDڲh;Xz~"? 4y-4 ÷uFʾ ͍%Y ^T&2ӱΎAֆ &{ [^+N%آ[C SUA DC,oyS )`?Bf^h@9f[qc:;C9'@6c| }7FNY9덆Hih(VS H_]=&ciy̫vY[DnF?Қx>U`1N6 u8g,O@F[jCNٗ-~0Oob., K):-J)vmlه"}'熖|< }07 1 Sa^WMmb0Ui0VH>WOn>ى%NC3=6U07X`$[fe\"aޥ_}b!!~A3enC歭2.Ǜ\Zg` B'Wp.)rIu4jxCҲDR_8.bH]$;Yb;KnSrb3wYPIrcRY;`'R@Ln@v; jYB}A\(d r$FTqBh~aEo WBVKͯ/4dJ< @)6U.]mfri *"b1-TΈGl^41tG1v6[8Av\w_/>uĘYq.괡2mcT7Fkˆwf!SawK1N) dGy-83R 5< l_^ f LLZl|6Q?Z.CSSj"R7#Q UpnJ #*;cO?W8}{:pX.sӌceqLaa8rt|,ۈI:N x]O[ .b0Xĉyqw?4>ȿ-8|(((wg::Yıl9v ٰZm0M @EAœQ%FGi6 GeD+ilON#웎(,C,=charFc(,[5s'/Oy_t'N-[6nj{k_v:1=aa:O@ >2 PoC7НxW=WY2L-Z2o['GT ucC2 Sm{h[|zy,37t`V`EAP$KE^6%J՜&}ֱH具}رw;+7$RHL_īWtTG;)'$8y"'¯=qcJtZNP tZ(PeT$}&UW S"2_@bX?ە}!2Ρ?7܋|gx!r>'8Ko Suym0v :T@?Jqf35 #^ x+J6&: K&_0|s3azh1ش@4 9 f_B%[h$l?4yi'Zߜ@,G;qkXK=/+&dwq?!>,5e^n G׌r&]=)\ת`:l }|:S1d0>#3o·ÇҳB}ܼ[`mM~9wYPKk#*q"O^"sT9ʕ/Jڋ%7Y}|)|KـSimɛg:z5}7ܦ<^ s'!X%(K=| EdjB&dc4as8V=_CH:X^r\']0ҥ4ū;щT oP?;OөۯFYb(N+$<Ľ3I %* vC۟C "!\&.0 9% a"9 ¿l I'qMqZ錖E-̞Cf1`j13%B̭sk= Vt^$)FN¶Yhh,A}8o0bVO؁tJeڭpu;0s8^)W;0(h۾g扇-"jK؆*Y$HuTNP#戧y(&5vW)$3,fZs\L|4'RԽ<ӹ B %|&+:C_Nc+J#" !9jǩӊ.<(że|SG;ϯHxi$! eX̱x#l迚uU!8p4[fC} v8X$Xu/ D p _HI@&gu0L59r͒5[$>~><:Εc<xt[6!J/]8)%}Gב<5ס+vy',>KQLOLP :csmK_{ :7aqIs]kԷkK>Ǣ(EP 7Ǫ4pKbnڗ=ſr|mzKL$[33`@^^QsE`y'b.<״<JM_TG,`*{VlvM_/9l>\m s`2Tc1MuD8g[2bC:P#l QQ7tPG<ܕfx"tCbT/pD>*0=daE $_dyxZ)Shq`Vu?Ǡ\{}U;}OIX=LW2‘LE;=/-;&̓Ip?1s=z_ui8MF*hȠŵ+D򂻤>|h7?wZ bwée[b.t˭BnD)ScmIeă] \':t\{ -ǜhXN$\T#Z(yxn%QԈpK5E3ҳYp7Ý;;-\10>(%C7!#J/z=(DE90endstream endobj 433 0 obj << /Filter /FlateDecode /Length 4166 >> stream x[Isȕ:woFML=S>mM;f5 $ѮPZLl") ry۫"W7݋/zlWyk#|W7/xN:+k\.ٿ>Vk\^U)w )tXIX)Hu {adG\^`~Lˍ3i Z -rUiayQE29̳8xr__/q"x!:pj=z5hƛ E7.GȬ}Y;6uwo7f}٥rW{(e\n); rbZ;\2;s\K\ Yҩ9rU>m&XPmdo GzyJS8!!9`u 路"^ѩG|ĥñKHmUJ }YI4갭PA)cBhoblb0 i+Pm=rTRH8桩Hș x[vtR ^0v_V& r"PwbOB `Z2!b8AQZP|61`< WGsM%;,4$}86%kSdO͆=E96* ޿|\ʶ̆s,qA3|P O>vtMM+hBwr:A?`zTx^y@::8Di֨SWO/_0Udǂdg6kDU򐴋lgqs6ON!׺GCw+T}P1NoݱO߷/$ VAdn󲿟 (!BYisfh cKB@΂4D|h>X\!!BEV a s4;p$yX`CO ATgmTUzt#sķv C8a&YKqf3%~>!}{:lZmĿHq*& >C$;iJH?h>& ,eRhX0k94# ky`-98)?7iso-rIBm%֑62 A mR6ygx8MNj: 3(s ٯ8{N((}fׅ_Ԃ"g9> 'Û36r AeݴX'G ۆ6k 1?;#`b."ޭ8 H=`@%<5?EhjçE(=Sh%xc8ka/Xn 1v"ɐQ B )ZfW" 3-Er!i}5|b bQ4,vi..Cv1YƊMKܛcEA&Yߊ՟'`! |\BȨ4P1mN;'j1*VQYF~U \ A]SW"^ݴ%UO8HnD+fg&vM4 '֨cAe?^d؟F/mXX:^yN4/-)R,zMQ(chO² fHd3YXVqhˊ츗5^/ E[fE x5t"3f⸌s11ʃ'Bc~pdۋbr1 1 I{2>@IprR ݞG(ٷ xԅe`&M\`'YwqM#֩H -_SGr1~=m}> stream x[͓FjG pI( %*yF+{FZKۛ-3kCj$u{Z~R=\da_=+ʦN|uu}#J6զX¤RwIHgջžEKMUv|+TU7]u=f%C]KMrԯa gH8.n0E2JX'z(\rXåͤ߯0_Onu/K[^A{Un-O~_ɶo{oj*h&'$_<{懻"-{?:sv:ٽYQ7ePTaNZ/L'MHqJwʹQ+NI UIT&uơv \]OSxmy0H<0#ZQ7nZ6 u4h܎h0,) {&΂qI[IMq!T jnQkcϪd_Z"ʂbK0NOΙ\lCnnF!fx@wnZw6l]F JqK:O3)Hxd_/:]+21 fHOB0؀8ű/(ދoq3=5B%ws~#բZcHR-]Xl@̠6T.IC;ia+ջ!\ $E1<6Cfbׇ[bh#woSMOOiFvA=x޾zď@Ө<,ͨBC$c0 "AaD E_P4zFHEgk {(`UO; A3KL/+ջOQ\Av}AZ9}S:Mz^lnf@޿ >`0z\QLɆ}L=vo  :ֆq@z!mn!ae4\|pSІDCPF-9DyD4Ұ ;g2~PԌ n:XUCƥBNE@jz.8wjz&\MnQ䆨]dJr[ gc9 dr@nաjFŧ87IBɌL"VL O՚&o8VƩ.*"W/TO‚v6R6$q!?d'UQ-)E4g|B7b- ڌ4zK<QV0w !yp"jL*Hm&Y㋾`bAr-JB@82[Lj {!!JRmm2r2,>.jb h- i)ɑ9GNd{SҤDCFP5{3p%D%iT9'' IiD 1Lj\$7/"nFA 5"d+neI%{&M1.j@7SptuIu6̯ ]9a% WQävǡf\F1lcǦr4}A4-}vM!w]о &,(>#`u$03זZ;Azf1XI+; jN({0C'jTTqL晃c+uyqi;CpU0(j\Xidĉ@-Py,T(Hw1] ;uYw}HN8j%Td!d TƬ |"TIcTxy|9]o /KEA Sq'MwnxO^JSbeDIW_o}+Fu8⚈nqGH) gZ5LmMyHݐ݆kǻ0[t_{]NN2jL0qΧh-u掱k']}NQp%͌9Iu%t\([ePgKWHZJh4ץ| h< nԘѩ6 EO7!f(mڛE"vb``$m f kH i!5D,O%̘5">y*K3UZگ`kQ}E.V@\QP $YNڲH>o7Pp줶ɫ:P⫫Р*Yr)TS?+ j BQW+@fzPU u֟x{h.iH"jdWu zB"eɶ ЅD3Ȑ+9mW?\ Q4J| !3.p <-g_vbEk/)5Vq)x1j&pZ l6+V19,Y3@ W'$S󪴰ʍw ʼn*+B,v)iG-|\`L X|Yj؜&hbN"Й*@ 97޷.C<̀ǘS{TK-gQY̽",`#?9jQ21p01p~&\ ?ׇlP۴.}rI䟔X<p >デ3<<]a2 qOuӐNnP.gI b,x?!ze"jT`V}rk.YCyV=Xvgb]9JT9("#dpΞf|d$"s-H΋ Ū`| ř|)ci eg_損璿fr"OFlidnj<E,U: i1?҈sgAV+SFl% vzj何*B8a.b\-'^T0s̃ra&ÂL9#}|yeAc^<,hB` tКkv'徽iL#<6D 0E@xD_G(bߛQIgj"G^dRPGis\OqS4H)y+kSهX`*rZH{rxb\Xj#}$ i* i FҷHBᴡ/esE}NxVؖ*BCu^1eixrvٞٳ)wK$FxSd5OlfTd8|-Hz>0|^5_eᦸCLOYB1&;S47E߱\֡m狯%ÉsT~ 7tga//3Ӹ'ⵣxEai> stream xcd`ab`dddw441H3a!OVnn }O=J19(3=DA#YS\GR17(391O7$#57QOL-Tа())///K-/JQ(,PJ-N-*KMQp+QKMU8OB9)槤1000002012qߝ3?=sySNk.7f]fwo$uSK:R~겕7uW4N'挎:ɘ5 ?6ib{_kg{w{\TEƺvsv.Y=o<_قSM^wT\gXp.+Gendstream endobj 436 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 1631 >> stream xuT}TC$έĈ{_qvZ6{tf_ac 5"DZRSUx!k6¤9x `2C,m@XŻ?KЂ>EmEV2d KB.fE$1x>p+LۜЃ{vҢhѲCyw$v`/<0c1y|B'UIoP )_LUCwZT; odb%zsq.Fd-M, ՠxtBqIw 3hGͣp_p~Z&§F]gЁ7z^; H;VPG[&h!0B{ކT:$~8]=(cl&e!57[Lj qW*p"WӶ(}Wpԝ h;ٮb:z<qvݾ5]]QgE6OiT>ܣJA~;ȍeU#xп u9f)-4ub$IVD.LNb=!=^\FBɶ &> stream x[Y<[8[N+ wpErtקrV+Y=zrb/jwU9 W.ƨUW\X2BmՖkdΘ~Y 3W"^fݾ\WmVw6ٗMy[7?7,tιo,r㽵a+Ó*:!US͙WL&l(j6 ĖɪZ\E֕~6k9flMѕ"R@gB/0s!$W.j@ ͯWzjO@mNYR$kc'ls9ꊙ]TV=)Yk4SyVW.‹\sT=KI8 Y[. |eL&/r3aT19*fPa{\k"؄3n}͎ET@J$r~m`X.= Zmdɬ<2x.ڥaPK>W†U_# q嗭[3rf4Myvnln5WpNXaN, Bߞq͹WlsA\;} f_*-m [״2(J6OOew9`GwrF)Z2$^t`;~ ˎjH-ׅ]%ꝈL qɾ; ϑtQ5^*5Uͷ/fJ47ڬ>:m48LT+:40*ئlXo򬰉T (h6~=֨.΍nf(N}VpJm`ov ohbo=Zš` mbn%܎PNEwKj$BABLj/:{ע)[A$թQcOn1 6z3Y#HMLN)7½@`A}KƉ'UQbp5MwnHD"~c0Rʤ b=I0wjUQuP2l HGe?8oVݏd)TJ7BauiVHpђF8յqV/̈́)rrQtQ4cPs|CѼE`\6M}p5]in,v|lHZ`vrW}7C Cٶi&u':0)_gjC (](Ȇ@"!37qƟS箆IAE ~R,Yl xQ L AG`<i)ӒS-+XB@f;:V'&ǧ=Lt(a@8>N):]o`?Mi 5߰&E waE}$ 97.4hMCYo)$+wb `1:Ά)}gcG`y™e tT{ल5 p\h`ǣ}+_# )ԈCn=0V"*.e]!ħ91tbW+C|,UCOqO||{pv=/<&Cb:DjqakmhTXFU>mb w _m@rq[}> AHcvjA3Cl^be磚{C(<,9v{SP*#v/".x YMt#|sg, ?C 1!µϾN&ViigtAtSAeɏQ#|s#H {f ـ a$-|<H,qIfNaɋ|NiWNM|g 1gRD1 $pGMEu[LܘO:j WQ/Y6MP3$.t0×9M2!~iBuN) qH l8 t2 v)6FWv\xRmr3{Nkwp{,,!tHʖ{j7;`OW'^7ZVݾ>wå)-0(]c[Ӊ?b= %Z2Bl)N|lNij) ≷1Lp.z‚ZM@DAx03hK>fbՏ0ydB\> mVi2$Wjcu͊Pvx_Št?ÖxNLXVG@`O՟R\kI՘h=_kce.mD=f+:4d;GB-iXvL|;_@8Y\a]X^_G(;汰]}l)a~ _8 =0 3|0| gS/qcVc/GbkM|954+H+._SL=zOhCkU9p)&zLw6N &1)M8J6L.<tA Mp)ޅオcls!tXI7S[?_)> stream xXwt[UE˘}!S(zM()۲˓zͽ )N!$8$%; 3W˞+sϱ;~~WTě:WTTtˊ V|a?3SCӢ8NyمH{7zN4.ޔ&ԈXZ]#ny`Y T_x:}x~D@Fo^$򆢪vYݛ[뛚ǓzxyyKyx?[%oWUռGxkxky~[Ǜ{777 'y x yyKxyr-[yx'yE E,y3oQspɭ['n;:mմoy}wL9Ϋw&l{L{ROOL%ɿ3W󿠧?_vT9# az 3,*52yD'R`.̈́iD3x? (HB%Fʉ:% twJTFd54bujmYkH'.OFGS hۈTXUVn4ub6wU<ÓIqx Q1i"jcͬLH羅C-;mŏSEHQ11[=+7?b2D#D4_rj_BNym\:n ۚy Vk׏!~gT,ɞvAN`×G8޷'_[1<]2ѯ_Fʪ6%ˇ 'h K@׿2|'00td~4M 0⚨RLVmX:2 ^/k!f +V& Y =M\RQkhi<PghMfKR5\2na`qyY7 OCv3zh3S\jVU-4RϖZ AЅ?+pb ff"t|QPI[4ԉXC`.AC|f2$H4fB2j  KQB/HCC@R5puyx8" q-m\~+v"uLa(&7G*,JbէD6#3ƼhD@x&rpp|[JShQY"֩fpe ;K.6 @1%=Lw=)K2<f,ZW^!XV @pIgG`6%IOʓtxn_ 5AlQ9d)M|5 ޢ3Z6.6@G:sj\:nVs|-ô+?G82:P9^V4XkOOt~9ڧhIh)@%B_]53)K3ꎸIAVQV>X6M͚֡W>͑.ڭlbiL;Tmu^>ωg?(JKsG})CVfٚg1ԛz'ߡ {GߚWi`J2ɍE"DdnT1mRW]If{ b޿Zƪa5?Ȧ:jRbq^D6MQLJ MFɍbyz}dٓ7JW bQEz@ ns$Ea t)jIԺd@Y?e }m lm޸#RIVsncV{$w8u p.~bj iњ|:::s\t RRB+ wG==h:XL&N6/A*7;{=9> } ):%RSUXQ7L~%TU,j5c-7Yj,74me\o7~K:HӰb\!oAy/2M) Y-zx!/EHs'4!Mr,o]OYG)-M =@<[Jwg;е]*Q|'\*6Vu s敉K~GԸp?GߴvLmf,QTzO^\ȰְVNE> Ni kz%nkY|*F%;Q;!$"Y-GuQl?v5a1b)$5LO & 4[88:Rv #` ]bF+4Է@}x8G ꐌd=hne?Xr)!j09l>|d MD{Yw5C˫]qw_ӆx&ÛB:3\nڰEΨ6(E tOx8 D;`̬MF ejԵ&fuGH?qSɭmi& J /O rTl{lGl{3 -;$Gs,-bΞ\)tSl$G *хg, jȪS?ѻqZŷ/eAfi7W2n gJPQ5gů,KiPHfyG]QC5 a+dR+" +1Y˜L%<}n?W<{`o{jpu*FmB_c*C9/ړ,{iׇeNI%j3&U5D)mDF #qxhڛ1bj#ǁI#U^O1`ϣc#C>Qc He|ucS͔IaYҧDV[D AӶe`Kfi& .6~L#q/JGk@ r'K I+za)КWY蔰E.aZ 2,m/֭vG5iGfGNS7';JѽmN# M6Z/QΝG'_$W+vL@NF,R(vufeYz zt=?9@c(.\=Zh 'tu:Ck+O0.OwOEFp!8AS2<` z`7#e^)YKDyp.OoZD` D|Q;eEJfhş6,PVZ!`!X?xhG'LUeyY",b f 3)s hJ|GQPɍ ʿY]N{֦fXv =ؚmeY;dO1`\{_SW #F<pɛhM4l:_i˼Vgc #0|Rr־E$Nq6U;!_3 IuXɲB'Kx鱿@[XVh9\ 'qw=T5haT ;p~DCJC Z?$&uVR.v[?n9w&ZgexwS'[CXB${{{h=!GO> 2=VH}$'x1VPT(F9nn52@PFh" 'ʡ /M[Z2mۨ;k47Dp2FZzi-<+tendstream endobj 439 0 obj << /Filter /FlateDecode /Length 508 >> stream x]=n@{7H $ȥAEn"iGe]n~[3/>R_vʹO6lӷag oӢO:m>p>yˡ߸̟G;N'V0a\Ði52M\C)טk4s ! c!d  B; v6 v6:#:6:':Ǿ;;99wUpVpٹcAג%}.,>9054989054989054989&'' >H?J`5BBBBBmBRmRmRmRmRmRmRmRmRr(젫uxx_g3~{]oԺZ:+endstream endobj 440 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 3688 >> stream xWiXS>pQGDlQL* 2#("2+AED:tlԯ֩ ZOAQ,j "-"%FV?w{wId䜽z5eL1,˚ff&'5ceH~>1LLho,XvE&OvY:?'3=#W2]<_?*Ե*[KZZ^n**){m0yًW˙67`]`'GdDfFRLqus:M5}LGDa˜L83`&2L7f!Lbb{ffXƇqd01|Ɵ0L 1L03 aB#gF23dXf4cŌa3Ø 8cb Mdk?hӠ PvYA7A&u&Bt,Oޙ_W𝂫%TSCb`+15M3hh!̪ -W4ULo MB}#bYńf[?~`>z0D37fB2=H&:A4,>34}cug C1 Q3\&<'$d=4⯁(԰:,'1B1l%7oO)J>+OC߹Gb^6 w^xu4Z2S1мjx!P^\nJl l. y1/<Ҭb^pBtwErtwK*=}UX\:|\ s8ۊ']2Ec f ?T|nrEMEHL߼B `Ĺ?%lU yӫHa4;X`5ֈEcf)߀FVW  o;9^s_% bj~X s䉝']Bx 6 oop *p78sbvbj-_|>Cb)Ꭰ%W躔t՛_,]?V@ b넢Ӎ(tMV~o;rAe{.؂Vm-Z$ywپ;ih̅$B_{?'uj!q3b.j(4cA"Dr<=$p/x$ \_XXC:Vf\u"^vOׄnE/&o(}OQ lI(Ȑ$mPvݨ8VC FIF?24fhp c(+<Q_ ws[~~G'vءzSTVkkN?^|›֋ 1!ijW60QܣN_Dm0,otryZn]ZI8hj" $0pbV7T`^CPt4Ϩ*ގu%, ~O 6?oV7 $ޚM,dhsc0;QgZcnouS-ܻ1=:?*IԼ#yd^ ؁YW3(--[uyON]7K~FⓆ@Gebu+d/]ß=mծ⾰ab@*][ ]8g`E ְYvPv2AAn#6#R/Tʠ\.0uڒ#mDui'i=YL'L JߋdaV(}Z}zEd7⧸v2G2 wUn^{k듪*}*rR7-jb~G͗'y;3bElp9M[濕ZᬁᅵX;R~Si/=eB?URa' }T>fN;?i:~u F9qB_yt n"J+?-G,t;G">Zyg 9 pDrxȁts=(ac=/Ԝ9X A6C&{WuQEYU|Yނ=^+a W@zla/Jg;Ly"ԤDץwv0<'rkbR_kt]JOcCzR6%,p̐޾c7AcXO|bC |2t?T=ޠ^(>z!=>r5?Jel?њ<9c L]TWݙ0BGD5ۮ._tܸꖖmJrD{;b{x԰ uOig+{fJC?`#RyO%Zۓ~Li9e> stream xkHSaߣ<ڼt`^Kc$it 8Ak.9.˚4kް4E.bj/}"#/A}{.x!UZ^Sn*> stream x%}LuhεajR_ޝ/sL^ftaf"[AmcPݷ;i:^Z4Qc|fh~Wo_$'07[m}u7v\Lzk)^: 0J܎V̀l_z|#.tTuwһjkvػis1;Cpte{jjx{zYߑ'vҼs^㤛n>`0Mbe=>61 3İ]أ`F#PӄR^oڪj9ܕU+Yقj>E;P3z~Uzy}X߃r)e@? ?#zNy+:#1}v ]&1Kc\oN.#g@YlԷhz#P ֗^| Q-Ý|fyee$TOe(A ytAE65f'G3ӣDf Plv:: tc9bu.:k~LtrIjJLK$}ŻBN1V\9$9cYQ”<&d*mk((1d_NOd7&hT$}{_{?L|Lޛ!*ɠ>UQ V-$ "b 4[KFCۯfFY<~ܢ (ą$_v_=JS>$ 7qmWޙLHR |q%?U(8v CRVLX,)_NJyui{=t3N3DTUQƑG-oM-9lư^ɠendstream endobj 443 0 obj << /Filter /FlateDecode /Length 181 >> stream x]1 EwN 6*E,钡UL@ }I:t|߬wG ZM%Iar5N睰YEOZ `7سi/$& ,QiHO@:eg$W5vwR *(*Uh$ǘ&>R>Yu~k-"_{\endstream endobj 444 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 702 >> stream x%mHSqKS[a"Ls`pntnw] L,_r4L -DRwMsC a"BS$ma? DܟQ _݇a6vKqxZT$Чy#c)jLt50F  tY[ʰv:e+R9kV٢?@sc.&12k2+l,cs:bB iEhtPh z@oxGﰹċUܽ*VW r!X^՜g ]2U7 sixj}}`I+F{sC8c`>0dڄ> stream x[Ks#Ǒ3Ow'7vRa2FS?`]n0rﮨ5amz;W/ۼ,93ƻ&̘]D!; S:c_moU%>IɏFERIs%ϳRGzWOz#}ސ 6<-V.?\}8TWYo6W_uȓC—wa=:_zNmXf9#6JJw5.Z(X cH~}i%,'.P UAS`IsPEj~#|!˦m!٭~ŝȳSmݪ٦Q>+NA#A%j BOфX[xgϙ! G^ JqoaqO{W/:u@`4zGaF OQC k2NO }bW7pM¨*q6}38B$@xipʹ##P&7VzӞ)J-|)1fr\x~{ ~f, TK%֌Hi5)D- /E.i R)Ӟ\z6S"ww-fלc WyiN Qrj%-Tѡ)ϥ0&ahi-RG z,ZBAqӐM~Ñx[/HdX` 騮ԍdAYp /EEp/xp?93 Eo\Voc"ʅ 1G@z12T0 8||K.N}}T5 a86YET.욬VOO[iGALG*ڲ'|8\ 6X]/{}>qN+(:[*P+}e݋irt %ә'=v]GA/i|y YޕEbZ%P,ȳUXk |͖7YxLG%/HSKח̃ʜڱ -B"7Q7}jaq n>Cle`n`y>ehՎQ`Dtfl4k~4Kxr966*#4rXKĆ;.m&~@>GyVu!V3 -$ɍc 6VV)l,UA~xqա~e"g!i2hv95ONcuy@ +O]KD$:W}T9,~WP}ץ7wT]Mm2;BepŌW:uUt QEJe7G@4D1aX=-4]0g0x1*s yli׻A f ž~6Ǫ~zfbτIP:Te؇Ynݾn3 `@䯮Oo"=':Sǿ7\n`$DU<>(;c710v<>!hoIq[|pR8s#wU 5.g@7H< pncUѭ72`I ؈RN:013XG& e3h2Mob"7r)w ^o8lCBPr%M o9i2vjvg{NufCH2 l*QMx DG+vնD$]ds7J~>p4 4a fG^vՒ`Ij|浲\#+Gp$w<<$N틈f)Y 8:gHnjU;bif ֫2[qg'OeM8_9߯W5\ 9-U) vH+L&Wm&lhh'k, 2\7ao\>`T] s_qr*}7qS;qҔiB;f(7"/쳗3;}'% nQu=endstream endobj 446 0 obj << /Filter /FlateDecode /Length 4122 >> stream xZKyB|rI+XqOv;I'Aسs`GFJ,I>C#m9H_}UUUt>I[Ypάw̎.p2`\z{/|p ]Iis<ȭiH𷻇|/ΗOsiǧw07 zs3߫Nfތwwnwd\^92[(6$RI 0s  n;М|jkwkkK*O,y*sƁ?zGhPT5mLS<#sXóILqe<+r-q=V'ڻ8I&N~1 HyR\K}HPC@g*Elsl.GU,g2n`$WVיF4'Z7px;;@DV*^(f}.Dr"\mQ?C .Uz9DW&S$.MQlI&aT[mTQdV(/p`ZI!&nwi1[qd"`F&[!>In ttI=Aོp|B_K\ b!0¯"D ,ﱢUga+Z4!wo\x\&抻i k}sme#W~\o0AnRáCs궙=-D8D" D!bn0:$NsEta, qD+>bhQb_ù4@Mmњ΍ axS}[=Hˣvf9 gG'ʁ<,Jy[ki]ヂcr[x-ǀmCw&c;㜵A"2ΤMŎd-5 g)xcE&͓c))17?${Y{9FaK pl 9P-Ֆ6“mchO' 6F =L](qz~Kn=wq/JB_(9hDkYlc WxR$aVt.=E Yc5YES 8}P}ddBxQ7iQCLۃM0\$k7wyT KV zSqP*hOzw }UG",w`|$ IwNǡ8Knxc:N\V: {)ɋRP^wRJ4mUfn02 r-lXsQ! N EsSQS9z1$wHӼ16pW]\1/Pk Pt2~i I&*2ت.D S5 v8 qC˧FF)qrG_#{ʸLͳؖ?Uۼ6P$AIry7yr M쬈Ok(@G!/u5.d)d@Ѥ:Ggh$_'ۺA~%q,DZ4Pq"F5Ͽxrs?T7SI~UǾwxS3ޯmvuS  a3|`Blwv,/ӭ0k͈/L ݭʌcZS kȀ4#  *oÞ g2gg;QՖ.kuU }?@䆳"Xk.,~ *Cn]Vd5D#J_KK3gq>Vmm>s=R0LTJ|8syJq+'CFrB`#7p)M}.e ݄ovPD (Gf>bN5;7#^|b\d*G^ir{%WrT09"GI)JI-Mv5-USQ =?Waׯ6Ɣ; ax|vەMm"S=wY=x3R^gf zљ"Jlzkڤfrf <Ր5 I"Z+mDoRyB!5ßϏc TxH`~2K%>8?foRwmkʲԷrM06лQȊ Y@`?<>cgGJFaJ(S)v_R\;~q8m35ȉqɳIg[X}OIlF@f!*V,'""JNDZФnh=L VrW% SWI|!qF.Wc2Ѕ4`OL'5}q@(B%VW/iH!i.Cw6L2O1pP/[-+&vf#mTY7v907_c$2OM8J>`1RS LH!)qU&>Zw& 9}OF<q@xn4mw"K7zPM˂u^ o_v)s)JJ 068/kqdz,B~3@ CQx9V;΢F]u4qCMx:hm MfA^p"`xS+r /!=Rv%@C*$@ge)㐉 PZ+ N_Y\x)^)j2t{=M(Ek]\ LyijŏNU93f1a(}WҜ :J9*# 7+SSW\Օ kl*@4'b"?s'b`Rpɩpכ6~pю㻎Ds[X+%=piB絺u|E?wH> stream x[Koȑ/x ֢|gׇٙ1[-c$T5$%lw<2(nCT$332^_D0\ bus˅o{Xſ3f%t "V:RCf!"/Da :n er:W[򿐌X6տ긖!wU۬7Esw[x%\l `Ne4~ˬ OzފQY[ )݄l*U˼"&$^9X@e%Ö-ᎂ G!hLv8:Ȼ>vwWj$"XmUw;~.nLʬwjo>ȜfOIaj0iBnӸ]`UyG8Ra!19Pm@"8Gv)N+  ?I,^$"D!JHk(ӽW~ &=-|OzH%*ʛ*XLPhwe9%tA05gQ!I'DIc&C8EEҍ6#G0]c-u?H)jwOf_]i*>ve_C* Y,oZ UF^ǖ& "Di@蹹07y 5pDZ(r)%-riE6VDYWH(L*+ |0*[ F~f3\Y7h_єWBdqx.,n.;| [Hn\dOw#gv e r |ʾ]B aOEx-Fwwx pG~;ne(HqO &/%H~D|%wWG X$YOYPdiIXwn|\A]LOj>AB`*dZyd=9CvJG%w1\KRi4lU aF]ۤPH( ȭ&Kn!enWdPp}2gGzM!^[CܕP紆l7,Y ؏Hu4Ű=P"3V`tC,gWkDQʁ(X ]P8G, W1°lɽ1'9MBdN#=HfG0~K%3[!oheL]}v5SSУ 1vhMM }8&_GT0o܀?(hxӦM=C:9jI*Dȸqt?$Ma/aA>yjC,+48TGTB4jλK´~fSb' q]K3#;G"v+j}uw嶢gVjv4cZ_ A,%釰S=+ σ }38P _ۛH~;ѱ~o&ҀZ`maT>khCP̓;(SqNI7qY~恾Q^ }xT&Zf?caORsf|/-R$$<,{q ˞;w2io3T˻;2@|L_TLA !n #C3˛C#3Vͨ]SD1.p 1{Bgn/%} χ_,C0oi=OOTC5#0o6vt,??OvL1GS6 .,л}C#Jo_ƪ:29Erܵ6%>4A"VeRGV +$#d |*K(endstream endobj 448 0 obj << /Filter /FlateDecode /Length 3418 >> stream xZKs/勱)x K)L1ɁR 9jfOwIJҁ3G<ſIx>Z-Z8q *sv+/r{S|8dowO99_XTIX _pm ZfιuC{翞>?)-ъ0sgs<+jbB %L\gFL]ml5Uٗo||wdyVh\ͶM O_9iayf1UL[JZ@ذ7Ix_g˒[l˧K)(+b- nzjI1ڙogB:yJ>Ô*2 8DWa\MXq}8۪awG!!a)"%3cRB]ٷǣxZ"Mx "1 .rӋӣ\,m}}簸+.o<˹.efӽ]N *MK!aSn)qZ8{/G~ϸM˝tܐ~U13q8;vC35Ruǒ!N8>g @S<5;IǓ0߀Z~}L,;f ٙ-Q5Z1#sJdK L. U/[ns[q!RNM]C .Ė1?!L?Y\\wH,t5l$Y 9(`Qʩ5Pƙ,vP:cBib rqCibء415KFKGQQth2V,DE>55YKv1ײPD E,lΏWC0u Zr`S%gk7}xL/>.tL9 2conRXw簦n @ ſw FW_ 0w>Tw8T09oAWq0x°>Q@,w3],WZR8gZ5#sm{Ҙ >p*UB lN]up@dZ.D@ ֬m;.us\"]6u4 =9a7^W>l6 bqYcjmq v7+nVؓ x~O6p4aE}7ZTt͡O[ո#6T@Gڐ e Jt5![MD,ی-){ۃ4~FI <ͮp$\r@1BNСp~lokp^f9e4\Nt%Y6^ A/ *Xq͡ fE\qiNYz{wؿ4 b,WR q3Tst8|K)" jÞ=Ex/Ng3nQLc7dga'߭~|<!\G"T/ C9 Of&6{у vV|a8v>&0~y"|F0f>LMcTubpF}E!FTuzA8dHj[^n}`$0OYX|8r50~ABF׀: 8.B 6Ҍ: O)sBJNy?u tڵ54/9梮 c6R>+?iitC'7pUp+^l1^c" 1g y@j,-ԐjaΨI>ޔb&=֗USlwvM o [nYId|2jf!ְ@ C6uB$a _5ߧ|"LߔRS<=PSRB 1HfDKbrˤ4|B'PCNݦ14y@?\x HIAA/dt]wc՟ADvӁnn#9dzt]lOoP. U!&ާ!0j5,6.M.Żs2߱(|d]l)mLDNU| eMER6OL2mKf܈ |u8{c gO!q.dH9Zbi8u>щr7-fGm<1 =:N}@Q\.+ab\H庂z$$Y}܏o4G #&Vdzs1G,RdDx8RZX(g>~آBN`7eN.n?~X>N{6R (<Ő^pf `~ ~WQ(EB.s! Ջƀ7[|?1endstream endobj 449 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 1624 >> stream xPǟ$$/HQ,ӓy]96mU]YTOgTB" H!OBɓ@o0zRcvۼsgl{sO>JR$u϶Mxu}2XȔ&qcHzJyşR}%H2Yp2]}<+_lh2J(xbQ ?X\Aw&vJz=pXߪ{\A 7{n?d{ +DķB/"#M1S`!A~l dg<X"+2* YA_}JȰl8kJHNC zRs!M6C_80A4x(l=ńuk1kI ~jF.t8~.E@?kn >WTCmCa)|O!ޅ^^ X =_u\!SzG}%t|It>D DŽOOBCtoυ4|K]H T #~t¹`1WQXDA"O٪B*HEgOvf߳~si fy n}26f<ͼ|nFE-q:MY!_ssl K7{g."o ()>AfU M:醏@d!SH]([o]D6վ(X* au3H=c*dxϹ9,6 ?%:Ax;" A W`TA@ >eVt,R^(gvr >[}\u݉[3<VF[l8,v<9t>3P09wr!d>l]Ayʅg.]f!#:Sh V֏:;Rӈr&.Zu{Qd`ry -Q{\9dYxY/74;%Q)iu^v־x~nnP_eŽtz:8Qz~F)hp COeK`7S$T_endstream endobj 450 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 2368 >> stream xV}PgɻPJ[b޴3wvl;^(UjJQT>L! E'n  DЈ|UQrB{WZ۫m^6iﯛٙ}}b@&3^X}XIBʙX Tz1ȿ%b9OVUUE)¢ yJBS?A労*N¢L2 6Ofb %҈W5kZEb=;"x#fl1:뉽+ t2rܒ,c¡HD]4R5R N*+( Ln XUi7uJJyS`_~5&{`l zf7wd$/. hruJ&-qGq8 C"vWϮcl>i'?2{~1%U\w:HM0!CPq*+ ,Σ"+|ہޯqARLH~ ]kMW7zco~AmN(۰I\[>6텵Z6@ Z;\>/$;>hT N/OtQWoxohvVoٌ|UYnvIFT{͚yK6. X?q?u#qvIZn7tvWZVSpܵ >vճn@փ묁Z'ښ_ŃPu>ȏ94Ōxִg2PBt&~ +s`aNF8奄'T3 =4Ę/iٙi;.]K9}W#1|ռ#577~cq|*,+F{DSH4[zGdTy(-Spdǃ_/Þ.S2ECRwxՊ$r(+]+?Q2{(q LG$z4pAk!f}p~43w6-Wg 'hNd#4Iܐ;+FwPjE P*Փ ȭ-ȃ"4O!کbo1kL(g(m{5ݦaӠfAiڭvh&M-VVHFut:h:Q4hxzkC*Zp&F&/Ec1X@igwsrr=5+Kvƪ1;TYE}>0PQbex}V -dY*JGU?@NDiaY4wFZ<Yȍ6MBGِ m{F}(83nm.[x9FZiWr=Yg5^3O f8v'=&[Ԣ,-80؁äդ֯:l PJJL$#|i0zr69rI6u\ [@Ie]] `$0vL^ k.<ʏ2k264Au،BĩV Ȫ}Hp3CT8/ެzendstream endobj 451 0 obj << /Filter /FlateDecode /Length 335 >> stream x]1n@E{N X%kq(JrX€0.rS+=yx>a͋eJ_0vݦ,o2YYݐ'qMfΊ[3̖\OP:M/BCkfco=N*)V)4yB ,2ʱVX[eB c uvּ5u vݍ2#j  ĭ B q )9!(I+^ |΂ [':%ѝ#|#;GF:Gwtz.P$,6·0߈r$endstream endobj 452 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 3411 >> stream xVyTTgeI}O%'6D1vkeQ*Y (ګޭ؊*yȢ(mh4IՌWcN؞>}̜9_w @0i[1K.^ YBGnP!Nl5U7o%S <7w,pnNR֜hYbRtN,c$bT>'w щIŤg,^/-"b.FHl'vkDXGExXFCl$M4b:!&#! Dȉ;af>N!Q6j%#&=?19jwʋSbВЏ fIf" g 0q'\H6\+JPR i87}Ֆ-WI TE3M4#he*sNVn_*Քꋙa? #Tb#㖑\Q.\D8~O#x A{:F?{K'ϐˑcxXfvƌ֭2ғ `iSACyϷ-ٷO!I[QQ}тs mFi 4"qϼ W=熯v~H7);/=c#'d3 WDrirh3PAۚBt _zrX ed6EA\^ cPĤA)S d#3 H%p4;LNɠ"dGmzOّ/ҫtJF`aU$˧332!yȵ+d h:έʇ@Fox!P!el UF^F:e96]wDުn.Ɲ榷)zM^h0I?8v!-QdkTOB"]/0p2= Hnjv.IRT u&7mvTJҴ:kk]5\< >6l;VƕnkԺ2*"=u :nѿrn͆S<7-JϮ! I$s)9ߺ剠)brəwGrWS6Ga?D^h\Jzc ߿){Ŭڻ͸k(#| +pUج}MB_wF -pbimR 7.m;$AJ}vs{AD}N&u(!]JKM%fYxtNj3M2/óKrѥsgP,2gimzNJ l͈Dӧzz,lGøy6QPS!u6'YgA&9o& xXiMXI`4N8[rX_ yd^QzEs:%o000&6K,vG>C\3r'4uyyWhy"m]( R b!@j_r_ZΡwh<zo9hQUW˒sC3R@G  ۞{s6l4r_2/Viuq>WƤ$# mb߆hشG4˽?Oa>8`" SpJX@r8:3.`0n&'L\ XNں[;|ǁijT\BMoWYp09c?ZZU_mz?U)NGDm%>iSR[reqiR킿U+J}Y5wͫkWeeGdjj=DΤ= DMxUHHg^*kx,_}P]h(ᝳO̭]< kxMĤnIH뵼FdYp=%;wede|MU j/)}+ 455x)q}SnC&%>k0.Rs_m`SBIQn9endstream endobj 453 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 1104 >> stream x]}LSgˇ+I85!ưTZum0>ʘPR(C Kߖ١[G iٖl˖s5ayrN$ϑ Y H$=;36gd,bJ.x@8A6%VB"H Ն:ޘ[]7V,M`WKDѯkME%!-:(BLH@O$_(clԒĩC%i8rE -"%iCPlUP'uN :xD`G'm#mpob1odg3%7f 3C*Q#ru2[<]25;T:?~;4 4&ξʄdX rfiF`f"x~04*NR8Ogu, A)$ &\f{ScP,U:kp.Fʯ]]XƗ8;]}9I5f Jlsz}`E}nngرɔ{|>mAZN:O #8*p{{5ҽ҈9>mv3QŽO&Dax*֬\iVab*0i\ >x)\)iw/y1u\C5sۢi: x[]qP}cgs#~O4CUGJqBay&؝eB @Fd= -fG3~A-3gHRu#mmӱb*ZLޥJ}uEmRۃ_k85C0m.3Qw# ^~XyqaV/|8\uir|WByr,Ի!q 9{7-Z_2a[j t!԰= ?ls k Sy~=Y `vendstream endobj 454 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 699 >> stream xKqz^ӊPZh+0)QZntlN639]*)6}O"@G{o>Ǣ0cg#K|EU}.W*znvB Hpvh4c:s ?)`.[8ldL)+8 +&79ΤDBvfb-YX̢)Z9.W\"SZ8&b -oin9)9am`X1VEcn\]BGYߠ nT8Zl\Uuacܫ{#]>:~ }Mn!NT:JLD<2K{M/ P,l'ՄF#ePNz-pV!Fjn]&0He*EONpIu+0L&$/& 0Xo#TGyg:- <'f<,z]{lsg#^7o^b'ACvyzi=Sz 0Y;Q Dw(- xGUA KzNH JP;bd&*إ!X=D &b.}5 quۄ 7x:.::Sf:aFtNUendstream endobj 455 0 obj << /Filter /FlateDecode /Length 221012 >> stream xɮ5M4_Wǃ."!$ 1*%dO@\=O###"WUeY~ן%O}Y}ΟܯYO?]~/l8>oG<v\>~;1j:8DծP{kٺwb@umoe]YK?WQ[I e݃׹YkMLP!{10{+Ub s=bP%fPm˽VDO'SR%PV~z>4&􋒪-T*c&m~Jj 0U]MTտ~ciqgZ~M?m?p=Oѕ\c`OP ӷY[[0$>?۹=^~^+8 0Ia-LzK7?զ+xK?{g)#eM2cq0C"u׃y/$NkzrQ _r ?kP\3qH20䐫d+-"z2-wELWw;[wW/u@rz#4I _}p=mc)KO2+E߂C?Cŏ/-] V(b( 0fw"p+BR 3TLr S[Ҏ#kbc^ů7X_}W'as Ce? = ǯ΂O8$Lx^Ƭz^OF [ Q t=p`ZE3sH?u9 ˺1B9jA8FX SXKsQ/v8/p~òb Wt)קPa_Pa/8wdULjiQgdt~nq=..Z„zrܷ a0-~?I_a2LYapI304yu+^CpGknpLL1[$7v~*+^Pr`2b019K2i297n (\P` ;C + mnO"> 'c]pn>7yKkߘR=aLG!aS*2 0?󘮹܋:{Ql;pn;I--ˉ :&͖e/I79Nsb[α4g9 ei6Ej) c ~>(Ξ܋zXW`< 68fP?9{AO8qրyÆZ`Øa"6o-X.\q|+00"zM 0fť.9,ZbMQ4˔ ;l`߁ '.s}M Ų lxT ĕaɐ Xê2\)g>m{iH7D`6DtQ/ \iO# ~0eĈĬqaAOia[yoxʫtUU9ʋ1MFRan|IqaO$ufp[kA*fhi<>ftz{71+!??acrbO1gRB"+a +),[XC7J\-xBv­OCw>/m9qse9tx2 jr͐BZ&?påp[blǽyӄh+ⱬ6fG)130L8=Mydl 1̳nGd^qx%֘b|HD\?5E;f)7c :~A7b0ϣ>ߝ΅C~Eq7;n7n_ *nU Swϣ8,2 ka ki<H km,3~Ռs?팘3]3NP` }+< S+aV^`͠h°43t4yڰBOh7I&&,tCŠw'C”#l*+M1j`1>o8жsI[077{0 Iїa冘:CI`{ŤaG|E?/Cۺ0]wC'Ya[oJ~ 9w's$0lO -<& ikܭt+إofyS~`2𸌑/= /`0xyiCgkLB#GpOP{+]pg_8Pl9Y"o`8%aq>o 7Dy0ήOn9y5wAV<*ah,s5ͱۘ/4|% j^f)o`^"C0NWŤaeѪ탟~$ 4b4`c1 ,Om(>q0Låp3sV\e~?ER0ct=e9*(fa-0o'v c=c~8-0 ץ)RoqQ0ov #{5\YqLugxZ86_$LaLDk'ڭ" ?s0Ԍ0dAvʒӊ~GXMOq! ̾fpخYa-DZßyLaLEf72e `` y29D^aAX' h!<< >=sq?_k0Y%,*Y;q! \6''M"#FJ:X0[>qHx!!1(qدY304yu+~x^G Gr _)9,`"-8ջhYM)̊%K a]+hMf1Մd^U[H  >Ƴ q~4{;@FCQj}ïxgo gϷbFB;`GaaNL ^3ZA#F3ddr0u4yyzȰi=otRu8YUB8MMeF^(k0d`0}!O2 j8GMM-R~CƜ}G΅m.h0E釈QA&f0B]F669&&eD[Wd>ccQ g%ץ RG13zV>6?bҎA߂YYoc?pn#l!0muIq3ËC#IZ!"( QHaG=;" 7.Cc7w#9)Tpq\Z!`YgSEaV:"ypK%4&qaHn@x< b&A?DÏeOܳ R;+ԂUPiG{TbFEa"<~Q0H- 30h's8YaB``E='ӰjWlkҩQ}ۅ?MA˄,1s0LXYNFC,DUaZ<{[FA mƄ炾o/H*u(Q XD=x peArߵb=|_ w XZtIGByaF_ZԘǘ9KZ)}2Eq Spe : zIa%`TJapm}"Db8cQ7&"Nf ar(Z30!3l*J"u?toa|k". ZoP0.sE+Ò~n*\IL2")9xU' ήg_9K=8Qpb&0eOfBQ5PA3Z ~0ϣNXUNT|xk m~Q)uZŐ.Ƥ 86&)ba֛afyxɢ LmfEM641R[$ц\)5sy H&n>^/zJ#m=YѪk̹4tψs_X"$ax?pnD ~0ϣ2*Smט"Dj~䷲J,/n9:- !j\7*n`URp6(k)#9U3 ~0ϣJWMaWpԜ} ˞(s${V1 O Sϒ")̳AH}:WE8@t6ptAzaDMƤ0e(Є R^2+Ej)QY˻$ – Sv%݊+\_`0C.,f7>SU]=#4&  } f~m g,Ŏ8S\p[o%18Z"y]gw ]0Xzܮ6GD%guWwiO{H5|A궳kZܩ5} 8GT|:J lG^:gG,=ag[vHaG9jS(z74b' *iy_<<ᕹӉs`[n4zҾ12dtUnK>S0~A|Y4. 1 m[K.L <|־300*x^*ު ðX:,tOxgoK"?PH I&%&6%baa˶qKf)1]ġ.)Roq1R=^MNb@6N5Av/c*aR!mrwUe~?C SXKsQWUHO9&0[퍕ृ7kWuBqa)Lc p\ ¸`H SXKsQ'|?%$vݩ bGq=J>w9$Ȍe2O-La-aﶘ0G%Ӹ$J&wtx/#BОaa"NMP)̳lb N70I-}Øk_8MV3sHxuLc  3}n+v~X"b/*ÔWRsXY304yu9k&_cF! á˲T -W%#[,xG S$~Ypl_ )!1<|{w#=1uFY0~f G0U,Isqfȃ04yՔ|0 tBsIģ ֒A{2  z1}pm+NgC.qlCADA0U?DlG fҐÔs0zX$ݳV%)9({Nf ˿!xM& \Ol[XC”¬*ib}3d`geAZF0n;ń^[^t_e~RC0e,:*]Ia-DZßyh#@>%tE:ޛo -FcO[75jBI/ L (1y -0X6I uH h,^t߲Oڷ`8l( śr1T/0E L\]?!Vq[\ YLfv"\Mr%=j7{0_o((^&fR0CKsQ#xXDéHL!Iٔ3ALC )2(2Z'QCdQX|?CnͮgҺ.╮ 5ڲ\mg}UiqbʪpJ7tVbؕf[f u2ND~+f_g%.kQ`=QŹ[61}FZn4z^-3Q٤ќ<Ce.dDndE1C ւaʐofp 6 XZZ}BD"ڙ.XBZ"?"nix_ WAH= PtÚa:fu5؃~S!tKY d '04y^p`(yz}N74f3Wo$ȡZ/{Ad}+GVf 'H mj$&v>i_Envޫ߂vVH k(M gWcVU2WSƚ_ERH0ϣ:sv{U C:"2vdM&n?"lQhVN1sHEs[r8,ZZ,p H`gvŜ _XXVlj}VeaH\NK.k8e")9Kr' 1 eQo;[rӕ<=KG|f:|3O35B/8+)Cn[P38[e/ E-<&k HeK@#e{QGi}!J_h6[|3uApl=w+әmwwwPḰx[4eCS|1m( ,8]0,V\l qI_fOO`eZZ<Vj4 Ɠw[]:5ǖplZ9 &28-v2k!RCfǻ7"PPA<$U`49ɳvm=65d00<+ȤxSX;X'=KkD·`o"|{y: 0Vb&F}r~)93g)yT٪}0W@j4}Z}^ui߹pqE>։f)'}ZQ(OZ`F,2eUP06$ 9$1Q'5Z1CI23 p*C:W]~*-ŏ,Kj`2' Cي °EI SXKs 罹/MbzOH eZ2Y`X$H s\lKkQ TJ:J{-Oy2u<a7Br]8j M^9D-A̠gPi[CPj$[Kb/ ,!Iٰ=rH708s$|=,$ ki<+SՈ?QvibM?eEf./ -H')ێ9l,ZbMQ}rhmaDyOƾ`mNZWS9 Q9YVg~y2)L -%&z֟! 1ZZ<;^N΢W#Qf2.fQbi׋wTXNc$2[~+ah,Ul#[17R6v_#eA3>sHts`G!#ȧ0ϣ. ;WwշKōsbސk\.<|*7)m`2d^b-Gv)#0ϣ-TKQv#XvC ɞ&se8@Q7Ȫ]zfɼ&\%BvEgz`ݓ:ÿ(;#;DqMxfufQXKsQ,;ҝRskFpԠ˧)tO)CDGr8YaYj fhii:ԗ8Nݍ;LY104y02Vm 'o,%ہM7Bƫb~6q0Lg`"KqNaUaH Qg[3lxcߊalB][#0퍦2S!a7K̆a=g^U0CKs1}Дkƈ%ƣ v+ ~Y`[':֘}gvA&f0ϡq7^ {@2O&L,,ЪNʤa6a>WŠAdƟdDF?{b0³%{d;(ӈp2\7lΘKhAd.<=21?1M <|ҽ7U| -WViՖ"`!P /LvM- },9a8FPAaaG=XQ(jՁA<᯲r,i 4m]M̊vl)#)90O]nQFz⛈e=؂9Os@=( rxSw]~R$?_|rl QIڙ1|'Fg/5W|R.d񵦊އ 4q 4f'&荍5X *|3Yae`Y pHx`I*+XF`I-D1&?q׊j#$Έ W~^{ٟ-"a: ͠pd: wʝ noi,b_X)`)$,GUer~-8$ԓʒ~2v>S SXKsQWaGVvZ]oeSA:Ƶr?@30,rTecXk3g1eo EG>h"@#v6%M=aj$&pen`VV702[R S0ϣ ֶvӥi,N4fݔ"Ԑpc\G2҉ax?A$F#~RaG=8Si] X݁+M;Zf^ahj9 &-1E 8LüNQo~|9aY?zf`svĕ=CFvaH-La-aGu`&j!~赂sI*fl7aXWŠk4Ġ`>Yl)̳zk)+*of F΃[ȇ!,M_j" DTqY)6OS[44D=-,ǖqWu6wᆳ,L Gk>;[ک ~?N-)N-9>l7N~) [enZZ<|z7H̱%F6F[],Q"vgU!6 =_A*(P7-U-|бE@~vX".$ܿ58KOݖPx,WV:\~}a0bK;B1s쟢KcXZ4΂_: 憉aʐA i`[geb0Ϣ>Ɇ+ݮH//ln75 وQ(] v`24mTжY304yyOvWm0rqp¾ Q%P XZe/Ia`B=?0;㳛0lG,C;\z6LI JPY&F(5<{UJ@f)5?3zL;ʦgףPιL +ai'#̡-V YT ([PӈĬ,QEN${CX} V"C”!;#d1] xbPPg0/xwPmW`{H&y_ L>} A»[apǯ,`ͣUEP_fWcE[Ua?cW7Z_~S0&R9 xu_cnr]HZ$4y56qhcx0޲j0΋xTEzLG 9 EQ- Zޠ)9-f2FWǬ7cbq;ǗS\0ere_ZZ<nY҄A؟vca>kV}?B!Fr, :y䶧ev^,CI-z<2~>vr*ã`'Jjrt :92JH /g&eɱ`0ϣ4_ߣ-$S-4.6J͚p(vצ8CKQEusg^e~?ERXKsQz \d}6rMQp26i␰ N&F"I,8ZZ<MDRb}49N{S<82[0H[g3H"t"faҁly"PELJ/.3͡>]0p/Zbۣ&DClc* c/4E*) cV,08(k2d%/ ?̳ g7sq;Cq/(pL<»P0e`02&2)9|QMj=aQB)E1F B* IX \e&ΓG!:q'b> amwyB0~*SL!udxNٽA2stUyLkFy;XGX9ܾ|cSa)hAd DCe!b0ϣu}`} /a״ 5#< HqgmS;o!=8\ Ej)QOYc"e=U8̘42D9;7,Ger܄>Éq|i7l2jT&]up,;~2䪶,O(KPôc3 !·8בTsrW5:ig}RE#j0δ2EDtU% srQcd aGu-4Qh* iI?Nj/ h窆aa]$Nٝ:04yiPisaaU raⴉwoX{/k jU M#9,c#70Ef$dsR$h?X7 YT**9s0HJbZ%EֆT0CI1gQS!{Xcօ ָF(_T(HUӧP(s0XclXydf0E-Q-69"Qv:Q-b4z ok'E^t ON:;Ea{Š0CƑ~clyi2(ꫀ2a7ȸbDxegͶ7_)'iE#:&BDEݛ@lQ 7]ۏG/.P,}L@<|k-8FphG[^i8Qiϯĕb, f.~,A/ITewSݰ7JcLT@6S.h)*C”1K8Ӯ5Z$4y ow\V?*C¨l iiQ7vgTq')yTN=,\yeZŠ0Ec.vG.2 #a2XG3gQt'#{dMjC Xғ/V&Z~x}“#X4rL*D,:Jf<@WEVMRpk20L(0qT8,I%D:Y9Ys0j̹T}TLIYrh  3ÔKj= ~0Ï7. / Ƭlr7Ϧ0JET /#лTX*Z<)QpW̼YmuF/`8VUF2U' g ;{x_mwkѳD ΅#}D3 C6nGY9|`2 Cf)0yԍveqˆ Hy2NJ-La-a?pp^D:?p<ŴʟU 1 r 0;܈ 1|gcSSXEs'1Qo-s@z~bLy2W Uel͹80e(eUYYǹù2)8Gvyu3R8nu9쀱-1>'6e|\Rōm}dc~KƇ)2Q\O񖌏vmme~KƇ)9€:#1.^yiAߟ<4^`5~a7 Oc{cZX͸4݂E;iZ+E-n>g;f= cۧJ"&yuUmVi}=Ñ@D@Wem& k} ) ̅2Gõ2)9nckKBW\2ܨ`۰GC>t 7A+  0faPf@t0EjMfQ? 6 #hF-DFG>K8:ӚP})܄rA,U Z<)kB8hաĘUEWbZ{XUiMDXDRDMAdO{yяLU-B0NPT")̳ϼ̗Q\5QdqF۾e#`(T9 xɺ33D*WPVR YŪ!`FowߍœjW0eN}{[gAZ1CKs^f˝|u2+K}.\K,ckPl,O2#r!XI%,j 9}+`'v\$Ia0Z Iq;J:nuS4Rç(8x{&ϐnӆY7I"ؚ8,jÞ.1B E+;#$F} ggvFHaGn-=֣Xrss f!!Lt6&?)Ke~?C SXKsQ'[qo"bܔ|hq)NP{-0TY0IJu-Y(pdwIPt?H9@i[B|'vX//_,z Ա'9 鳦$sM$2&ϱ"XS4#DYlP~? HCnPm{qE^j܏rI9s w#].Y3/?銼t#]ґ<,XuG-HM40385PFCH/3 \HF?lNvhTm:lܫ7~7ex2'BW,̣v)|OdDoՐPFlH?u|h D:'u 0ߪ2;)uu8]}0~E\HB w;cOPB hE)&U88L^xD-u=FswЁk,Ac<` SDW?GC_܏~?KۂKL@tq>O62w{#loV߃ic6 8XҘ%\rEm#S|?iޟ|އHjb.S#M1>.(8G)l4"H+Bʴ+AD3Qd|{6RС~ll{c]-J~;fFLZcj#yuӟS>owddQ/٢n4|'SK9of[uq|BIXi­ߢVdZYVɶ1R 9% a<1#y IHwD0rf,Š; /z82mXBe}V#o!E}ȈM̓#X[akc}qjP o Ai V17D3"Ufmjn=&vV9v*|>k:ɶf+7f&--\[0GG 4ߧZ AZop$ZoIH~I?S4[-)V\ ~ņdlGB38 KQ!#%[1A4(7hh3BݧSÜDhj홋߫-uuE*x\NE#Toշ_\.>iks2Ջuiq3ttm)#Zjgjl&8?k#"ԃ(5 {L\mP+GK#[g@%[4\⠊hIMc*k=62ma*646(kX4o!?j6E \R: s_\KT,ط!RKk6¡Rb8^{iuv_KbyQ-(2 W)%5zr=5"fP3ũ5&uᘓ5Q7xf45Б2yʈxT{l 7myG^x4::l|[4Z`<)-dViL߫ 'ЀQf1WSDʠ3.8/!ufI'RƓ䬚*”]"C86$"GK!GͲ83V#ѱa5e-Nx2=|]-[ &Jw| -sjr:eUET%d5F%XCF{Я2M*n\AhR-PQ |ЈQfrsU}+<5`lS.w!Nh.;G\mEa|j%"wڐu[Σ}xhOwK-X],N{4}LNG eС45!V}(ʈ[ "X \!`2"ڠ~a/Ci?Mj,nt ]缪S I!eN a^x4:*RRgB^oѨ]E:p^nw91Na/'DD8lB#K!Gp5'!zsaY5z)Fe5]H`xL`]jRF3{iu/U!ގ.Hʗ*S^5qWw;i#f[{j1Agar#Yu󹬛.z]wojhȾ:y?\q2MD%H+Նc'r|Lu50n]I;4HeڱU9nh0"XNڙԈ[N۶m'a @v1Rp5U.Uvh zX En5+\,P~?XgQT/BϿE8#Nm">zQqhǶ\mѵ֩ "S(N8-Y[-;J/UB@a/3ƮV^NeR+l1]ԀT-;~~'!p.[԰-sf;JMR(ɨ)7qX={sv.6$k Q4e"pR)Eau3Ppo-Ziz1ry5߅ԆY8 gz RH? =l+eڐ4a eD-um`l!xo #ڎV嗵(hXRIMd0ؠ^5K#X `DNC ' [XsR4B=0:9b+3˳RýQ"jr\a/<":8ĸ[4N\X-q/{M)@[Q N1Ā|6Q?u>EG}.VW*Y6=@{hHۇUϤȠ;.֓KV:ȣE³3ʈ!GYmP~? HΣ3i#pE}ă,,7 BEBȕ2j"X =* HΣt3$v`~W;[s84nҊnU~I!x]es4637y6(㏺WM[<[v1d: `Y[jBѥ %gUY!UЏ{qiLͮmAYqբ^aGMH-L-@Ɗ{ף+8MH|Pz?3/?ۂ&sQ4Z15AuEUdi.#ȣiLqJG_MP~? FXgQBؗ<XF4hCB;%>;BDV4 Wʋ#m8TmE]x\ϟU$>xUA4Y7@@C 8}Dk~~)o""zDjd*y}nt}} ?Y96]t<~MfGiX/n3g߂rS;5Dnu[4K#Qy ~FErbkElܥSeDo ”Tw֌_ x H/g5ԏIDArYl7aSxƇ>rEB1ǣB]DV>Wt̙ذ=LҦ*CE,Dsלc\Ȯ4R|wm㞮Kyw|>d}.`ccߢi;;ĩbMU$UF),ol&/EHՆ^y<?ٵGl!6HwE7oźoYFDפ`6a5)*"֍*E^{iu ] *q0;fU{+FG G`Y,[P v0XgEJ$ l|jA4/(05q׭Uz@}iֹ?-@f`Cd3tvWiH_$0@UtB#G!E=GyvA/Myne3G q+B-DD2#BjC2m"GDXQuŮNB>8A<RFpWiLDj2ayÏ*+-hrYNy ] N2 e8Ȝ):5GjĮ&8E$T(zr,&>:j%!4/pց|+VxJk)8z}Y.i id"}A9a/ΣQp"26EK{DˢjtpKͺLĘ#X ܤeb"lj273beN] ՎTD:^S!Ց|r;W+"3nO[(9]7ƿdlLA(Ek`1FMllǽ"XNƩA|i# HcIQut}Ĥ}YjolܑOҷǼ iM0ca.g?i`v aΠ 4%~dBYIywfI|DwrD⿟T$ǽS|?~aPVL׃lv#5av][ ],DED83{iu5וM(24qG( &bܚ-|O{K%f@׶6ӍY,|⵾N|G_jH(Lj q%/^2bJ"X ,J9Q1j1A 09vR,s4bF&#`ҁTM$@Ş_25}~~)njiEۈln3)4/_Fvm#wxQ3Js3o@ / }_,lAZӣXgQ-h]| j̎@EmA;EA2mfH ڪ6(+N]4o!XŻ5qUDrhvdGؤ[VhhxY.L @mni#)l|:K>ȫ zR{Y{S|]\ye+}(t}TLt;mƿaFʩ!dlǵ\ӷ@3R& Yq=+BfL d"r4mfL/<^aG UwM] שaU=^'9a} I4Bx'{"NI.x]4: M2NXhD6l 4ɔ(FYHn=;m/#2R P/xڠ~1tx6撂2nj>`GMʹو$#ގ8/Gw"ܴI NvAYǻ#y5 ;$ "kVf?lDZ/iZAr?SW/)9LؾeلK`9Ok<4{zth炐2m٘wnY6 ~< W*F~":v4ഩ7O$#ZjK!-hELAlCI/r4:Rc)Bk5.spD@yD:Z"TrDNx's{>y=:؏18}]`),Q[4qJ$greu!ex?SN6A gz<4]I<ݎ(ғY~xי, `&4'@V #Yx]Q~roѴ}h];ٞ$g9"n`6=:z!UuÄ9B^&:%WDo0Ф1-s0=EPD:pw< y4Hd0m$yBzRQ";%oxPh'1j٩Ypq,We }Z!#%:wGgZ R{xƝ,PZ:M%+R4ߙl+jlӅf!Y:W` ΢3ޙQO烍FԒq{j }T%Kq"LK̏}3{iuu Qc3EɫX:oE$0=pgKMR|YNsX.H $j$"d^.__޴LDV*~'1FiҢb|oU~yF{,b"X35Yq.86(gܫfziu~^?>;J06ēeݎaWq&q0A#z[RS4/3B;VqTMQŀvO&r+pjzcMҟh-+BtSmX֊ t^ ˥`<xg^_B,r6c,ˊh*̌2-7. -2)lL %G.I [6$b^LASE5^p74h ZL̓hw'{MO6\Oebp ܜiMDDد^hDz)?-ԂL8~#qZsOwqy1{ֶ#cL=W3_qdo9&Σ8 `]طd{;,>O.2e>Zhb P8f<dCŢA`9YhR#DLH#y + sL B|Rw!jYf 8 R3t `?W XglP$䃨:ϟؑb=8n|Yd=>%e3vb**)9҂);}n}2nm/G $B]i6Md.B!_/ !,iLͅÉe GK#),02lhDv^G A@N̘)ӆnBSZo gz- yU?*nCӏ`P`/}WH\XHQx;{/W{"cwׂh dX:Bয.>Cݣ2SS#Zx;ċ>ʢ]MM$ ex?ECZDhj/[5'Byژ"GBX"a_/HܥƢ&?H~$+?ViBGиɓڠ~ Hg>~44:,Msɚ}IXw_ulPD,gjXmH~?EFXQJ:9H$jʜ&6]9ăN'GؒY,Q"|w gz<ʋxL1&o$L:Qbs})k=`S!M7cjDdXmPe4:x֊0Pr4Hcο-WT]SnaʛBR#2S^x4:j7:,4EuthnP;89R<^˴~<ȶkYmPF{iu5WweNoR xDtiC4X7BkGK#KePVX~x7b!r'?& ǿ3ED(K$ -|8|a]p[Xb vw.(dhGN82m!K"${υl؋pWu宝X>OdV Z+8A!"{uTRe|i 03hu˽3Y/GG#t3LdAJ Jve9Ϳ`c"r}i۽3eQ0'؆.I~F! n¦8Y suU<⻣_,'_jfIMI^x4:oWĝŷ[lߢt4UF Zz@pViP?hd(̭$!GG_E# lQ,@ϥ{/8C雖mrDc<q/ۂO'r@쟮_)~̿VYHAb?uҗm4NPlT'V˴jFf !M !Ћ!/aPמG訾#[ J2gw'BMD3ڹڠ~a/Σ>o6QBCqj]Xw,`(9Vˇ{NlFXm $L/<":8IqG\'nͭ l4ǃdcGՠxAHy:qi.RE'y6( ^x4:>VȋK # xq6DRsJ  ”]枚[NbCI/rŸydZ?E~z~H޹=(f.=75N);#QB }A#ỵ~v R[ĵ+}4VO9WeHW_OELh6rA'ei2N)~ aGaMcϡG$ 87sS{yZq !eЊ{'"VMH$BEĆ}j"~٨m}cp4D\4U0 kP/ƦpF|z!/guvPd\(-1g`U[[ š#sELCe{A;FX ?m#̑ 5Fk@#) ؠhM S$ʂ50 ",&$+XT,3~ȗ.&lSaz/;N坪JukTs;Ԗ箲Bh"-k]Dڐ~ҋa/Σ~[("7HjlԜEݝq1WuYwһgf05F[m ga/ΣD1u/5 i1?)+0,)7%ܧY`% x: FXQsq[Zq0{8?,ihr?SqWCR!'<իuGpHȿXw*♣6S|F {\nz3?;eAusy焇+2xl$2Ve>OYIޱ]ċm/ n)[B(Oj[^z_~R$>Rͽ1tBnc'0rDجiWH߸{6(h6K{iu3HIxb3OX,;l*])$cC wsñ Lh;ڐ~ҋ~ aDzK9-(MMI ,Yq=)瀈6V)o:KM&v(kS<>`E}ò-L~4FՒ Q}S_obj~R~Yʀz.)w7nJMC_ݫmHy9]*ȲΜSCւev`ha#o-!e"fߕ ~6k FXQ'cf(y~ld/A Fw*FDKop)1on $m$KHzrbc&|B'j#:F9Ol"H+|g)vl c6(#ժ-uuT$a(*57A*(2+<#ޫS35 }J'Wؠ~a/g.iG_3b(n<D'€6@x;xxWSݾ| E[g|iN_nK΂`6Oyz/uЖ {A3{eiOT޳ ϸۦwZvqN#[kElgjn =]ɆeD鎪~anK' c>ݒz/ &X.O2!W˴~EZ[mP=_5a/7nܲdqmgd35;-4 r0il꽾XfMYw.0YJdwߝFni׹"X /TQl]mP~? FXkɢzbnjvT}e$eGqK"ȣ"X \! ݛ6(c}VoKu=XPDКxz>=>DjW,JczҤZCXg,~aڲ"MGO}g#0uV*19)7SىiՆdgfz)?(? g sc`ͅ33?kgpN. F~)Q X>3H10¸V#w#yԠJf@j϶Be/ⲓ|hP7[AHe[iD"EL!GI,J%K7NO{S7EXzQDȼYʒY|m=\=^W! 8I7bEڛbIgOćqK) ZwP0J=&ܕ.]5{υf0S> =)*)GkrD¿h$m,@6@\ |qj:@u<⍢H%T+DMjm}S 0r] 6(t 2l ޵t=#kܻ3ރsePmZ٫/Hy1@l6(祥yԔZ&7T^wP Қ{g۾p]emK{/#2m`[* D8emKfziuސJcA81Ȗh2(з^l1`=WD}oTZM/+X:fUIP,⩰/E2mԄз^x4:=rWE09XxFY>  2jB XS4؛]mP]+/<":[Њ(Cm|<i+^唅RD]֏/G /͢2 90pQRWx_7~P}yM/?%O5"lirF4~f}"(`g\3^vg8OV \hLY8iL`0yvAYGY#yi@~&6c_<lȬ j`N"xߒ1GsLZ@s*dzڠ~ XgQW۲3U?vcC5>f#خM7GmEH +5; eqN `RX<Ǖ{[qݳoJi@U:ܽhp P#X Ck" RaN#I[W3"Q|j4"x @Dh:eGG#XI@Ll؎u%A"xUü&fl]}`pG/bC6EFXOq>#>o7myt=jp#g`_ P35-ήqu!AW~U- ZpLxKS `(#Y(_1fg`l)t;g7cj6=lܴbC&~#o!XN p:+h(;E.9؂i  gzyŀmno6$#rzWXĦoCPw vsڊ`6( b[[mPF O^x4:Mw[-@%:;lHa-KqCC>ZcW/ *G"-yWU5!!:#c"+,"@۱k[˺$:NU}_E~yeDR><&VR:BW㞷^ <׵/`L~C~*yJ,S`'j`D|t(5DQMڨqOz1GK#!X|Rw ֜'y!vN^E +2m耙Hj2^HjXgQ 3`rdT)AMsxHDQ r 8ʿh$$F9i'ULH~?DXgQȭ&SsnkZ"v*ֺ2yVɲ+2'Oz#y}g¢3"cӷ;5;,=FDZ"|!,a\MnNx: M< * Okc~&eԅ$8"]esiWX"`\TO:#mdkg(W&5E2KS1(yT J'+Bʴ~!1jCI/rD-uv Yw ّ;;#R.T\+R@:<Iܾz<(g.V!kO$=7"V~#.R$eП~{_m>I/<^aGN76߾ECr JrP;z.ji HS4 CBjC2V0"GBXQ'%c4V3|jnnx}L+Rh6S=t} Նd␚" R>꫹5dKBNzEx?SӹT(GCsX^wӘ- ĥH:Uu}uNBmrV%Ҽ>s|O,UU'Й4j΍uP PbN˴NnTL&(GIX_!F86C["MDEOn" "Q25,iMS8X-P~?H΢>خ97R  *[<".T˴+zZ U34:fT9Zx\(@@p̀pw%+hP X35}p^mP~? FXQ'̓"o"?{e ces%>#sE,ZE=q8' muB;Rsݐ{%c׿VDXX mpOqAZ-Pl[L B1|6LC> EFQ=\l*Ԙfj`/<^aGp}oz RN/*Bʴ~ ʰ~ aG9mcY4kA8w(>;QWE,#z_,>N~ pm1a)4 ]2Xo! =lw%=Xke+BfõFƋjCr\!/rLuuMV}0lH"gdn:&q Mi4BԧW-yuwB5r|􏺈Hsmc?A"=$/{2AjzPc,i i{MfA` ΢n/uqP)m~6HxS#ee!-먵hVY$7Kq߄yx§y ㎇VW{].01EE^ؖ%w"2uQ)b) |}}ۊU`Sd&&_) e]dX\,gKG? _m1!Y0E3:gE */^A&&qX] Oq@q EZ@"dj2GZLbMa/+| "GH|3<{ޔك+nEOj~>zyS|?x8E1Ջ3+̣wy^[4DG2TuD L%_Ѡ`9OɦfSBrMyJ^68W38*G@v1է# pmohX AL Bwl@'r}4:e3^.11,kڠ媼{iuu'Kh.h8ui 3A_q2b+0?56|zy,! d3e[ ЁE=VN`VF-eSY,IMnAiiC2`p"XggV{G"bM]ݒު*dFyqiWٽ)arڐm樚yyrfX_uaujnG7XyuF嗝[^h6E[Swc8(#!<aA=VQlku;_=؏t"}129^xD-u1>Qnf8c w)L](U?RFډjNx}4:Jȍ0n1]G@/+ WY:5BG#76&{)?г ):U $HfH4572$PK^`,r<-$J5b0ue8<"z4,9k t& VA=٧zw묽+Yw6TB\yޟdH ƴɆkjCI/rD- :`$8"΄<[i?bAO4O^fB;Kp&h-i^9O_ \=YN`Aæ)C/~˻+>/ ⨒6󷆉7YwkXv66ݥa/a]GH!'| 4=[<$у"԰?bCI/rL :"Gx)&FVx E>LŒyUCb˥dg1zjfv#5QEHp4Gs޹%FN_%GSWK"aA`LJᛁԠGKkXQ껞WǀtTVRXphk`-“^x-)7,<{EpFy5>ÂۉOͬ[$,lQ#̇ۏ j̞M ƛ&pbCz#ejXױlx9rդwr?Պ J+y+"wK#Pw^ؾq{&0kڑiR(ƹw >j?~1V,xQ4&I?ZѶ%i0Jtu&yur/a1M|?E5 ~ ^jn7qICwe`[0E} x,Vwqc.ƶ3(5sAL/<^Zú-x7C^c3୿oJj[q<8c&^$Y4ӆ(A0_"{#oiXQjzο0~d!EuZؗJ[4ӆ$4kAL/<^ZúU y.v[K\ӈ*BzgH;#xqGDLU49~Ju#ƽ&Ƿ``]E-O<\Fk`31t_!;Suk-e؂`b/cq}{ &c,iOG,IqG]t$sɤPpueWUCbХ$$'bSù6P$KizE< "[ N@/ISxbG*dQ`Lϔ[ƆjI'<>Z>Ʌ"% PEJDwe(Sxx-ɷ#M ƴLj|V#5zѝbtb]E^[W$.E'y[1.g`h m)qS!j}O¸.9"uɤ|]"c+] S 6T8!l/#j0 l,a[jPô Ha]GMؽ%wR0__3I7p2HZ.oKd ï69^Zú:ʚ @]RG` { _QFb`<$Y.I.I] ְcI#Å^%QdJE + R\ FsUa InIņ^m :j\?`L_urjokſwm3%#j0gJŻLxW$ ȤZiXס$SC΄8GklAC.p`7JSP^~?PGI)XWQ.5VV<.$yKw #0z}pc;e?1~t'wSfLG; +Y9HMLW3T?;hSXG.sV:ƒYC59x-+vջhxfJ93]Јw~&S Dq:Hdѝƌ_Oxо`j0nns;%*KXm {4[  OH9%ܫDh>g/FgQ0IRrjSQ ¿Ye'Gِ1iJ юmdtۯM&Iam`L&Sdaq̰~KúUGF:X$9MxW19Nliq>UAX6tf5D_jC8fȋaa]G=,]Hnd֟%ϩFh:zɋ(I1m`%C!9"u |-8XQv|름$Q̲+4i`J8EjH ϔ\MV#5qQ3h~ v-z }Ph7rԏ2E!-(+q /XNP2}ryC:wԜ*/ߔLV88Zbm3vU1m,I-h~ apy]Lܟܟxf*V A,;[k[_X3%W1c*^[úIRgvn)iŗ%J]P G3^Hph0 8BST! ^^xu@tT>d)7XWb%^b)QZb)Q_f'4]OE}3s;\$Zpj@X"%_ I,}LAL4g]#f+P"UNt!Xc?*5yL 3eĒ(;]ra/<^ZúQӉ} z Ezl&7.0!67g`Ss%o̜}scl|xΈ`ddgƇ;q_Mj lCh~ &?sz{I휧/ޗ@1?z~"N#΃?׽ xU1M(v ƾZ ֽae}uQO }',yY5 oJLJZ.i'\[Rņc/{i :8$V;TyuHN5jYQ"v~I"G 1U1m|?S2n5VEu;hՏwGA2H6T CHeg|Y5$ Q05{*6u/4bM ֱ3[{d GLjDҘΜ(=19COkHL"P$k81~#4YWi+uS {r%j%٤7*DY/sz$'g=yryp髂dy[$q~cM]Pi05`"+G[ f#ZVaa]E 3ޤdվju"Ixu>5o.O{ h0 EQ5"G԰ch $ΣlfJM&qD)t!.H@ܰhHQʒ{! 'u'ʄݳS{:Φ]HΨhHLOoj}AL/4bM Qu5hp$KoNs28h-< xs|sfӅc!4C .JnC/TJG+_/֑!K,]ʗ# j0ҵo3oWzu6W .A1J K"=A8c{׭J}_[v!Նc'ru|nӅPl3JPw@t ɦV1΂<Ey}9<Ǣ#M?OIfڸf˖.eۙ.AZ4$ E!Xm^x?Сo3Rc>v9; K:Exo'x'F / iI ZVt#5:r '9i,nFx/;nۘ`'h~襶h0!I$ߒ"۶^yu{ ICN@}w5H2hׂ"`5j>g>w`Lϔ40 M 6il Jw^0YU_ع|'oN5}]A}R7@ZowIJ;pO`=TK^52f$9y{AL/<^Zú$YJ2~-B| 8qQ?d(/iq[&5}A{i :?ed0}`?%ó /[$hhQd?i+ ۳ҟ^xu5|"DuX[{Wc#,g)#?2 sa֎[[|pi*í?+ _WwN$?_?z/x9KtcV$唪i}n0x ف93^{\(c}kbϵxÅH} $y*H,xHrBF< a‰`*+~63hpċH2.ї1?0~+b"4Ug SyZ0XLٜRI"sjzԸq}U j ƴLIL g:vR U- Eo,"ڰd\xq!i5IH /GW4$&$6Vd5FLw%ZƌttwR"WDօ#^5쯥Έ%Lۂ L9_>nUoU,nb>cw]˓"hțyK*6f#5?]Dl7HӞ@1zpn*L%Q(Oʿ)PȜI8]sm j$jIg8_l!G:I OQ$ ƴ!)Y԰1#oiXQ-,UN#a0nC7CS*7\֠gŅTnGAX68x%8PdZՆ0b][aa]G {˿; XD͜ Q8(zbD̺voywAgܥP} !/<^Zßuԭ>t߼i f{T2pW%;"rĮm5LioKSL_l? gtc`~; %OK5P=w2\?ˈ},&H\p>3{ H/:) Jr# [S!j!9t8#W60Ò]p'^[uoA7eZG{55~a ᴇy8L+&m`Lϔl7yYö6 Ԟ2^ZúZK8y%wAsX\,BшiISC\TظU2uK\v֗ynzHķwI׿V-ۘ#"jHLϔCH ~a/a]˝7/yxGvV.Dq~9kb)K^cU`Lϔ nb=ԋdh*C k%̷s ڢhts^~E"PfB2 j}_~?Ӽ>sx?*^Azv>XlG( ,|鉡)Եyz_L]^ ݑ'oK{Q0Q/P5ӆX7XXl?EH]62Il5-@[b*يc'O Yק O^xuu?E_ď޼$]G3ēA/4a|Ğ9]psb6.점R9]aӵ^k{HwvN(55vaGZv'օF 6_%ݑq_ at BWUMzH <%aY9bȂ<29W 7n nHCt6"GKkXQL}g$%bﱩ(&V )!N`L[M|~L8C*rՓ}ō4ȶ9'>z.NyiHL &WOFL: d+z|ȋKј?܆n'Vhee3$^.5^m :?xYYwq뵖$Y(zCY&+%zkyj[ 4" a]Gyȹy칃Bla {)XYFDj0 =f)C25DyATa]G _oā5)9TcA_օ ;ypzj~>"m5@h9IßseҼZpQ7eR=#ێ >y?L =E= Hw.I!'%QJ~;d`lfYzgGD^43%!JR gzu nmDУxN$'ۣ]2 f59 01m|?Edԩa ;1~º 'QCɔ4V30-,bFxsc~dGvlːgO*GrsŹ_\Үe?P0&%mRiQ`Lϔqj/"moNx}uOH.Q;֒m"9?,R#Haۣ(SSU`L:H^VVi>x}u׫YU_[mIRVI wIGa@aBѐ6Mdǣ c5A`t UԇspcKآ89IZlbse Xm"&meǾs?KVLm x8KWHe)lڢ6)ۭ`l g:vR Uh1YӂҠ"aqǕ8iAqW53%Q3g5Am;)*\rQx$L- 48M ƴE_E1m|?Edj8q̰~Kúdk2Njrs˅(m4kldt˅݄U SB>3k8b!H$4Ђek8L%P ȕomhPvQO['1"}9}V8A]Ei}}FoI_a..&.~H.Xؽ{`[`%EJBa H*lcK {#4YG}*CTE6^jgqgOe4>hYAb 9uV[YcQ qE8^֏%yz.|u4F,)i-& l%\zjƥ$ wgYs2߹H1D7 ";j02%5$Dd\Wq̰a/a]GVS`ql cɡ.q}W U,Oh"'K ( m%@3BRn}#GG@szKh75ͨm]^|(31 EFCJ<@%5!^J]d(<|܄"G԰FZEx\-[䇧rCW/Q_5eV n9Hdb ǵ ~a/a]ǒ`svErwyla_8UUClFF7mȤa/a]GMx:udXtzt<*V^JНu^`<2 9O^y \_iI_>laJN .ynϢ|eOD8 nQvj0e ً@e`ZIMURUgjF{Q̷=/T]7Y!^4&v}?p-:ě۪[߰[wT/II/r?먡 }ǐur۔|.2N}QLo.GDSՐ LJnAe.0GKiy%lhӴ%F^~k@Bb8sŋdxƪ6"!5߾ņp̐9"ufl$GCC$ * ,NLe"¢0%f>^gA3GKkXQwƸd0FtFNunɉ_mo0VNb\w<* Ƈj,d08l^xD- :F_B?7K7 OLg16|Ww(\Krzxaщaa]Ep<>m Ɏ0TJ :pɮHpnӆNv(cVEa]G}Fzte c;;iiQPB]޹Pl/z*GdX۶^F4$MpfIpf Xm3GKkXױ,YH\7EHjoH32ŷ&8tQb^s͏4t I~ ĕ}N .V`rFHmqoq1 .d:H*R{]:n'ǟT*a/]O_/YoiDBtz@{'6Ȏ:V 2ؔϝC?K9rJϪ0˾?{%T*uvDEI$a4sX t: A ǵ F笒5]Y{=v6s;X[$WGܘfܷC/(qi8I"UY<1S#5먧=uww^]rGM9)y.m;q;<-0NgvvӔq]&FL*K|>qڒh9t qЧ||tc~xǾj?=yΩŏ.M9SlhFZ}=qľ*0nN1H~P t;}h*Y/Ng ugJnFa сōA۪6|~d sgAL/<^Zú[=K0)_:1#*0 Qtgjض1K'<>Zm"1i㭻LJgڔD[4ؘ4w.I)9SC ̰dljK2 {!Iyz3@l؛uɕ|c#^%8-iCBH^?5m? ְc9EՑ3vpCG۪!K6I>V{f Ha]r`&M,jhID@>P yjh}_Ր6d'I5lcAK4"?{'ZPbEw^`2Eqh:H/OӹJ"E6D?)!}jP%m~Kú@Q(VˑmH΋_>s _fM#dJvrSX)G9I/<"u5lǭrl]?΢D :76zw* C޳g Q.^CϜE=!Ľ7O_|_ B 5m"E>S_XHz3A6 W]a]#5Zv/U?J"v (9_Ԑ8ySBVӆya/a]ڏ_ݦLOfA3%MRA8]- UpMX}28:Ȝo{yhX?ΏqFc`L1tI&cvR UpLcY=FU#!o7S_&ڑ(F-D>B݈:)q 7+jsz1^yzz>q#'S2c,:GՑ(8:%;srn Gp귇=_k؍TcB?k{N6 q5̹SU$q.D2{ dD;xQ֭eN՝$c{E2:h`Ôttڽhm ְC/TE$>QHEgJv%$H -q<)bzu`gJ62t1C^yu/ٗwmUGg;uJN4C:ztB8~I~U1m`w{&9~hASm {4Yު,OR pj4%ϵ?O#6c'cvUң`삆"ATi Ha]֋-b&otHCmϑw-/FdorB{ 9=zxO`Dc"Goު;}iiVa3-i0"u -2;T1|fY qȚDYvD_Kxiģ5$ E%9@65{1K/<^ZúqsoGf"EZ-HAc,3P>5"pگ~∟^xu:"3M|7mxֵ@%?dBleŬ90ٚu<ڼ?s,J+HɃxV&.nK8nbv&!OɅkA1QB#Ki[T;04| .A# e\9틆u5c$a/4"?Q#6w'S S?3:7:ٕ7"5? 2U砠Cs^T(X^ymxFe#R%Jl4 =;#2/ k^p+!B wR q/(`w5}^ϡlS<^Q"uJg@< ڊ;dptAx xrӷ{ѿ/\yt2L%4E׷Y)c̝-/Ɏ߅udDC*eYInD\ ZU҉a`]hʎSfownE~$?7"X{/SAj7M!3GgN|F8R{:EA?\4ą(Bn a[GB~o<!n (-OAÞįPw#*or@tA s#oؾ>wz/b,^l\FȲmY΍ N $[kE0b6z RZ" G7L2Mk{=UJ9 |iQuFbܱ=Uңe`ʒmǣºË#ejXw)cHi} |7e+C E{ı/ i!&X" bpGGkXW h:ϦjKߔ0'ϘmJpkQ5$ ݌0m Јt B] cl@Uƀ7-gHy=mqX ޢ7Ks-گm䝧/{pycV1v<6<D, ̨@ nO|629!{Ч Rx鑲W"Xwm[֓`&=fls)SGyV ƴ%Glѐ60Cզ^mlFg­q5pQω) r8Dc;L8}8ǪxDDD6a'<"ݦu 9 a@4&3f =d]L=h3 R}#9}CtT/{=}U*VjDD\$є6=;d1oXiU1M`%;uIA$V Hl;x-*'Σ\?d4pNiqFԋ#C0~L,Ĺu p "k,ڏm䝧/kAŻbTl5N^1[wθ,c rX%bwi;DIn..m a/<^ZúzgOg,i;iP )>`Df@2օU25`LH!J bGKkXסS+=[Y=$džZc6p<@G8&d%uw )xO0xj:Sw i^;^wޭLt:t;ACKzlu`@RBe ?LIk3{n[a`]-|r̉?šDrb p-J..ϛq^w'*0Hvc]2>nMLIG8V1vq#7ӆ}$DK 6}O?%Ki0LoS#gjDʡ'a$z6j54M m)p؝ы!/Sú?ϝUJճ$')J$16U(Uo; GY ?SA{V͙zGI* mQXΠ~ecc*%oEE33J VIR|rsiCUI00{i :t͠ ?NS攐Ǟa`1 A-|a#}`|rJHWۆ{i :ȻRUʒLh)hw6@(r'PHU ƽcIZm {u!"{,(apI(WG`#k`L!>a bU2uUmdv/"iShܔ[Erĵl qiqGI)XWQ8#S Ptޙ#52$Qtl A:]1ի9[mNL <}_VQ4{)9to^#t}>?GqczOI_jj{GKkXB«()2nPlʟcرGbNPe~aZXE{ab % ; ^xD- :gN>O5v&l!Q*Fʅw]p5$3I{ЮFl^xu>ty5u|JΝ%דWf刻ݦ%q M RQ+#RMvJlӂ5*6v(y\ƖS8**2RCb I"I 3V8 ְVyw܁tT4,xBB !A/@J&\mo6M؊,fWg[njz4%A؈@Lxgﵶ(07U<jblNhD( V*{aPp2w IIgp]06Kiscڈh15ljcKzuh+ K6 o+CMd6K Me@ 醛S$Q] *]N_7}piHE܊ыxJAQ\0:G6)QiOjj&wL/a]rG 6xP~f]Wgq*?uděN\OS5\VIba]exOzA["@Q`@ 1nۃ/v= gÞ{h mލa =8Ʒ6-GAX6"CXlV$oiXס_.١q_WFlh[${ՆfֳqN c`L1^*6cu8s͊q'B<,b.%AtvDwUTD( 8CY4$$h m_m4M/4"?H\S"&~D 8_0UhHL!=O$ m[mcGL/:h|+<"D F K_ln|3AJA_5'7$sjhj8f Ha]ryهʶE"5El\2b<coRTQe 6{Bc*XW#NAXs2`C?G!VI:ۛD s퉿,,| ͛K ؽ K/<^ZúWYRq-t).8\ K-o0 (XqP{ui3,\WA3GҰE uΣC 3j~FZŨhH  뺩 "l yFL5}]UB`~9||I||7 Yq5!2#\}.HS8oEy⽙r]D wWYamBYJ.])\p{.bYt<5${Joc qlCXuJrDgM-.R\Q05b,r"D8y+ 6sz( @|rEK1,ڱ[D {x?z9`U_S^iGG+XW?jg? ĒQBGw^uYҬ3Z5<ȑWei3(9cR afEa]GGN * h ߭ECA2P|A|>e Ջ,@=E;`䝧/{)YY˔ '#>gV0^J^i3$jx‹ bĨGKkX?%a1[$̙.@46=1I/ւxW M)A25m{/^xuK3.`,a[+dvTjY4L,)yg2" ۵ ~^Jßut-/%[*:S$2}c e&l/SYDoQx3k%tDS 2}hV:=o3OxmyDQXy8N篝yنЎ4࡜S9s;ozW3Gg)Jv^TKLqE,vKƍ^%kkXWQQј/ݺ7w {Mځ [0 &6vHFQ4fH؝!5}AÝ{i :b<%?,k"DIbo.z.t?bl*yj0 ̰O!8 bQ Jwux&d$jqH!Ow5Yg$"ĺLZqc@΍$yc[m? ְc6{9'BWqk7Q1^?nKz%֫h4g~Jpu'5vO?onJw=.XQKVr@Gx5w))_"PO\y}=5j>0,߲DwLv0~EJSUCb% Z F&`40K3 լlIc8%  #T?wJ M FHFzk`VȴA䜭J+:TnQ #eo5%#ڴSbF.LRsĻ_4wJ6~i#ϿGҰ\SOT8%</~d9BT`L>uH*&~t1kpHqq۝l,WE¨d`˦3e i0rdoT\mlm ְJ3mW{hɳ!Czm#6E&j0 IaWjiwM H:j_c}M15}&d\8_N*:Ӓ<|V ʼnS3d Xm4W'~Kú޻#XIs" zwABnEB,#z_uDjvgA ): U(beHEY2ڥsJsDX+Vqe;Eңt`Ll?SV ְ%n/9 %[-U1hP`|*M~JLL ^m {u8ZNrv ΃$WxfLB"gX R  ?s- ?_u<)53Ӄ$TIG»%Rp_'םEEqS-ޔٞao$] ְCیfqU0'oAy?%"!r3,zě,o_Ѝ9^Zúp="'~ْ3 `畠? jc#s`L!IC1EJְҕ8b Y$GqjH !`Я1B#Ki vjFu3LM?, :GD+7XCOIr~p{~鯦/;ІE"lWVɍ)~U,!ԐQҔtL \m {uTz{SY7sRptx(Cb'_9uRp"{93';?(s{ً2gZFx)%NU0$Yf867nD'G0{8kоxTm%"sWT&QJMݾj0q|JK>iط1GKkXסDd2z.v[S{)h&/=+J<B !- ˜ t3&0( V~`nq3!tG/﯄"<=싆Ĵ\LMO ѹ R^xucGX9D 5qBy H^~٣MEA<ڔ醻R!iسƠh߭yA<<܍__Ajf:θԏ{ .B'5L}JNO ǵ8ן^hDz) Q;Q?+SKFAS 2?G0L ioMJ":t^l y#ejXa~޲x ;%ꏈ_}N#S0J//oQ`,$Gu:ł E2?i7QC=L4r:T4T{h"P== iSJAzًz V~!D HPAGXIE < O0edUɋU1m`$qwз1β#5똷|J(]bRYpibrF4!ݰHF[4"hD.,6qG/rL :j]{?z``fs4'Ȃи F0/i Rޅ/6:&/<^ZúZHdFYf7@K R֎'A$;7MsDLU ƴxXmey7~KúPVuN@0[$lb0?$kqIJXg{j=%Ɵk߫c I6J q*6a/a]IyU<ԢJ\Q(h 6$6S54`\eR1ƊЮ.K{T͂tR5,HܪDN ,y6D",=0JR["2\4~?iٟ+M;2>hcO`Yqù5%r8"t$רq(%5F̰wjh(6c{i :/{KG2# CDzطDT{3bE~%ECbג=X#~Gm^xDM Q;JJ gņoHنRr:#m#RE2k_5$VPeJX?5lj#5[ `*{ACF yg6/dL؜q1g4-8i3|o㸝rG4Qh`jnxe3$Qkؙ6vk9~[ú72<3B&7^ Dm;I"qf戳_R2:I ^mt_ ְCwnK{Yo<ǡ'eڧ #Cm%{jH+?%k 3=m/6qi /<^ZúH+; :"Bǻ>_$#@ UC=%7lE!Ն^{i :|ZUŐ|j8%q"]+(˾xyZ*ĊM ;~6i#57I^.3GVdAͭYÙJнp`mJ6t+<0/<"ݦu&nfnUAji#fwb_mz^xD- :o3{-~ƒҤ~P‘8"C}_5ӆJ S_DAaVĸa/a]3$N=D[a k."#S!}Ga] Rj ƴ]Jtd QXm {ojFRV%$P(C R4&F Q1U1m c cSCbv#oiXסQ"){qgZJyyuTT֒g[5lf -6|( ְ\B~hF`I%8DQXqdAX6)ш35-6"GokXH ųEC<^S%PZ/K9<]P1(<;.v'{{m4(t@ Hxr%A A&ʓEX9EEHLK:W H/:|(0YNDu#amJH:N-(XAaqˈg[5${K kjj;^xu)Wf:pF}/I,xA?;gAiõ ְÜ+|={@p3/3qT#IƉƗ%c2hc֙Ʃ9],$n`GUFٸcƶLjTA]:Wv4MM]Ţ, V&fC='i8؃a(΂?u#Ԥc@$6R~ip"GKkXb[-ٟn]UzbTU{`< +SF3/pzuF6{>z{`/ "}G{?"Z$~e!#haa<=:Htr??Oo5}^ЈwS+ed?xAc \+oA𜉑89~j0v7)!Ԡ䴑9GKkXa ,~^C?y~RΆ@W<;>s{ًA<eXkIeŕZY 'ǵi#Dٳ7ۮIʌ!Ԉw(,GNOLH‡k'F[%?OWҽHOt 3"u1 #8X nv,("vՈ%ChT 8Qg(%Xy5?5>eWo}x/ud?<`;گjZ A;?!(A2 Lz 5[A^ӥ60CuKkҖ b3]U}ق7UI,B3D?%<1q H*鯮R1m&D KC blGKkQ2$H#i@ZB -a^6aĬ*V5,Dƫp\ bGKkQ/_Y@2p z X0xxI9.C\.E0Vp[k.E<&w`5h&z|$w<Gb2UޅMa~yKnT¦x‡ =_vlbz\v~Yh(_J8ⷑg4,LAI{- Q^m#VC/$I/:jۿ}c_슭v){$Ɨk\Ji0>eMIC&q8̚^x}u(̖7uEAq]Gb ,!?h\7(Xb9kvWwMd[;^;^H~'yRvvP9g*m1ԣ\&'h"hywøfƞ$Кս% Pzy>yμHi ϒ+K-Y|r{:~IE+n)/v ƗkS2eN ⤍M/k/7뾃ϩ1W, ds=e#~&vhsӰ0l)bߥa^ b=ߊdy) QrPA"/wI Jnh4z=w-9HB'WM~4(ԃLɉ A,ĉRkIx@ "N^m~ҋa/a_G%!; ݣ ~q-,B(GE9xU(Ǫ \ZHON x^]wZy3E%uT M{1ZJV1rT)Hږ &7Mּv"GGkWQM: bK4D *]g'_,.u[%c$-]mE^x}d>*FmPK"?Ȏn9~@d,xӄ?!io|BCcD-m 9 U'h:w/@_Hnp:AtZ)g='yDܪĴ!$3!tTğGKi̠Is|' dVo`s '"lH:T$qQ5fHB攥ݻvۆ{i :j`V.KGD+--y\88؉NcɈܦ60C5 ƅ>u8|忡6,Ũ$**yD_Z#k0{$Køw {uT 8-&KA%@BWj(( c ;,&Zaa_?X( rKnq>}IA'—YyvC]ϟmM7~]@o]i~!}}n<}߇ pX6w"/<^Zþq)du3hY!$7˳#kMC3HyoL AUCb$ZRC>1GKiQUyI?dI"Y!W6z0*\5$vDZPte${i  Ov-j jφ8U2g`<™N qjayACgm&|joh3)>~`U(4͘$[cA(VQXLN7kS"ncqЙLG'5[9!V6f5$&Aa[s4( Akqg9˾Ǡ>[$/O7Nh !k"n~6=$r&cvR UTN/] EXq)eP{brVIj0 ̐d^L(y6JZiM:`Ou)o0'4;$(ݳކV ()XHR2+ҐX6@yE\ݗ Aʋa:L)j<+/hZddD$QMAY_C#U1mR(Jj A/{i :`2U3q7E青Rܗ?(,. օ=" A6tg>jy/Fmm־HҰ FY9jqSrPƃ$0 }As9ֈ؄5$n9-9pԱtQ.6/{i :F7f%#)cDKb/f'mc t_0ss;ۓ )"!)N;Ђ?ll9_sǒiy!n,/a_GM>n/|&7wQx4N@n0(~҈xoVn|OX ʈ5ӆP(A֥{l# eTI[uP.C`AMH^JΓ5qblv*vh`L% "̠pZmC^{i :t{&z/zhOaK%y/S= V-J=?G^KMK}66TP#503'h@`7qIb^5FWbԷU¾E‡SBι8M^x?7&/WO4C mr FT=+s@w4 D X[??V6y`5K*^{w/RTpkHL8Ke 6 n!/:^\gd>HZ@-)8"nMjPHlkuo8x7 lbقx|hA4rM|9ɻ!! #r*ѽ?|5DNh"?4`g\#WjHz]mf=L/<^Jßu"1EgA5ҡYpg&nMCb,Sɶ:i;^yi  3;ݪb6Xb'u$j䪑&GCWq>DE]!'Ն0#5Y3;PN X@_ԏޓEח ?)uMO l 5@y}=wi7rSt9lӋ+ )n G@%g1ma3EJP0-߯f>x=} />G\θBc.HJE.ϩ]GG[ SgI[d0XC?vĈ ]Λxg}!HxdAdBٕsމ?Y$V4gIxdI Ѩ9^Zþz1OpSŮE|Q0}#^JFS>5gAK5LզEa_GmۥgH[$' i_3II$Jg:ݘTAN-k߿]!J_g5CInۥNz)9qZ1\T iC@HT^Ԓ/mdǾ#5PVOodq @HT`L8X@P !WIq5ꩉ^7} CKB¡w6*ŁJɦ!%ѱ ΐm y#ejס_/kɒkorp[$m&Ah4!V4HгjHL%x, 6u/4"?ЛLj}D!W$=n /X=6`t 4knd?g挎(D^<-6@4q6cd6hp |8L[^xD- : ͥ\eP$?w$#/Gw+05v4$ϒRp d9IVQ }HκHߋqŃ+c,VD=B#Rf)J mL7M/<^Zþ73+Ȫo*#upZl5Ǵ잙=@yR.`P}:Q%[085$ T`XҐm⨒4OĭNU^'Qd8lqD.Wۦ auINS\nlNx}}e OC^.Mf#45RD5UXV+0ZT9v ĊeQFRwANH^.X>z- OEѤ_b'Dԉt|tcW r\"D5`yٛL lώVz@-ۙ2uހh_7ky`BiIp4n>l^x}:LfCjHH,p}"w'~fEIX*H&.S9>Zþs53hĦCErr "=%\3)1E4v$B]jg!9>RUSM}bk>߷C'_sG7Ye ^ECb,Iܥ% "M^Jßuײ$W(@a-k_|z"'+b1&Y:GDonJ"4| b|G* ԃG$~$]xHV)AUc\?U׮AX60du a„9"}92H68W'd 'Э+ކ>Y1D< S Z9B>}5EWVNjʿKv{} kMV$G|wUl`$![Ն'[HM[06}1JL"W(;׵wS٧m~nNK~,<\Y!3EMǪU!#AGK N0".Kن>Ƃl OWկwܧoWfVI]=*3qB꒜`A0;Wä(!J+g*0 ̐$xT1Nh*rYM.RqGڑ`W UHXı0 ?_x)oR />o}_5W"p-H-ck3) rv v^&M}2"'0$G|$>L`Ɂr(N ^j@ox fמ6Jh4ɸx  0^ ~m "{'}.<}^?N|KOOo"4Y7O5d7ߒ#^ktkc%ӿ?YTA Úly!.YlW-9OQ?H1(_#:YiIOh 7Kӆ0.d*Y^Zþ4;F_PHcީE.#nAM_(s5ت!(YJNRˆ ְCO\J'9rDR\ 5SGN' @?lFGg`J$mi*{40{xϟI#0 G,4wx#/N75iK= AG,4{󾔰;؋l^ڥ=Ma,v9_14"n̫Ĵ[zKؾ75cA˧JҰC/ݾJBA\?*,"šdu_ X^>2UpLKU׎Uqi+Oݼ_vZ`ˎnDkȯcF`4tjWwBL_d/H)1GGkWQa_9j\w^͈xke3w ƴ+"IOQm# 謒5)>Q7ubc$q -̈́fSH0se#fXd25\AB,a_GjyG$q:8#g /i<Ȁ!'( *qBrDz-*7]{9jjdDsw <2%dI "vMSFҰc;"zd}[$, F0*c7 Ǚs v^j0~w ְ1m&FN#p.CA;{bZ|kH%9I = $eCX"GKkQ+Lc+ߠoTJF5ȋkQ%~, sgm YRB񼹽9^ZþxpץuvFW M|>Po4`Dl}PX{gP;M/gxcx &RxL2"i+ӣbGD {Ր6T rSy6SV$KkQY(]~Dc,IɅݑ)/ 78RkI:(~&iv#5ПGXE]r %\F35 $_~-Y󛳯kSO(,7A!3%NHGt?x@Ͷ<(fԎ;IͮV0X9vNhs2\Qfɨl@KܝY~t3˦-hh67mL˼ݖEU="B ǼJdS8 ʈ5p+bWM⭒6p*jYfD:b J\dqsX +EKu"zz?t7])7-ůeY{&ҳmՕxg6{@0wY1M]SF*:}nw5}3lD1oR) bUL g1Y՗&FI`Khcq+$W3ıU?U1mrRC>W*EGҰC';҅" ᑢfEIef~ϙVbD|k ̐aι5/6JA/r}D2FuȒdy:Ѹa&~]ˆɜUX6>?KrVjn<"?s@ѼE$|Dc5fca|=ϵ+HPJm|ɉ``_E>BL %Oők6BJiet @M'0R4"c'+Y٪_Se/"wݵ:/Kw] X~Sßu(Іų|&HJЗ\q[N%)A;-׈gӐ) `k8N;)*k;d˛i4λI#A=3A1eliG[}tc$ M0Ey潳 -|z =- ٚ"s*."WaQhبvo6SJziTkq)ЈR%|RQym8uFbe_{,,).*)9^RXܛ x g 9ZCwvP->*z= b΃@bYcA_["#5pmeyyoyE{ 8>kT,vl@4"ˆ,/<"}>ߕq=f?Ŵ@ahK1Ws*sc@$: ٚЎq̰a/a_ u_&w B4T_ҾϽ"G+IAt-Ajvay9_duS{Ա'z>job2!I{+ڐyv#qWofJr} .zp{7S|I2aߒrd0"`\Z"r#f뛆ĴmFqHJ m~~SßuQr6; ڇiAĊ _ "7G}א4͢% 4N#Ki3$=y+</iK|ð hѸm$V\Hp\5,xoV ePC?-WM7ՕE¿ dďfHhQT\Yy͂pl$G]0nm^gщ#o\J 6FSsjIdec$*AoՐ6ՔDrq5!t _(nGW/}lDHٸHw.Nq<, ƴ0qSl#$UG˥a_/k`}owt-mYrG:(T|ܧC?Xe$2UNE{'p"^T2.ɻ(u.V( n"otc^wKIi}%??`s"ÇAKZZV$|[%jpרGKk7'gf\_kɃoMUOݣbU2"vӐ9%߃4m0c#5vb(vcPՒY7,C?("K@ Ĵǎ$ Qw7 H/:*g묌X5lu캇vMW*#CfhsӐ83Swkp^m{ {ڊ}o ʪq.q[Қb 6 p83#ƳkH|:%%cN VmtUuԴ0᯴ECbE%AZIzn=7 i_iK} l6?? H:8*3lAAtO,݉@iUM) p޻ b|'GKkQK{ 7΋Ǿ"yq%uvXv#HKsrw dKA۰4DwAY^x} D#1A-",?6ghOwܧ;`zOVĨZ;d ef/Z&)|"i5ʉ &&fNaŊyM,]ļc/Ҧ0(mLjj1%; u9oGpr# !FKIuy6//<^Jßu2iÐV!iۓ1G'Pϫi"V_xﳍRA04')zB8z%  " q`N%jҩHڪZMCbP(0YxWmURc/`?\͸p ^6-Hp@|0C$"buGV’K  SB,'7pI/2{" j"3(T ƷP$[ 滛M RB{E>lc~3(O()|D*ʌbR\{ ue iNZa[,U\UFGl[·hٮKr9@fØVa:QsUi`nH q?; z'yE~}oD0P7l~a/a_GU-s G&0rS2?oF>c& + qՊ`yٛ5f["oT)HCC;D4$ @r/p b] Rr:Ų"+'(Fo-AD"p x2|A&5|pڶ~By?,RwWż-y\!w}I:{]8jnֈ5fXAjU! /z#oia_r+AMpD\_ .`5S1ܿO5FH >SCV1C^[uTr]Ee.JC W?o'4P5,Kyi8Ʃ g#Uߣo*HKɠٮy)#E1]qIjDYec% H{64q*oFiQ n콜W7ԽbFH, G)`PN[KVBHa[@>ˏ4ziz!—h8-if&Ԟ8u!C{~=~rk8=lmԂ48GeJ&:Av<#<]1m|~nimAY^x}00sf%t(r#|V¡2mnPػ4mA,>"Y^JßuC7v {oDhr|flT+1*r`|nH]lih}Ѻm Ha_P8 *.=HOh,L(w- ؜5.^05 g[.l>'W-y,JA%pt_a{t^#1U5ӆ⤐()L wt(*6UV$KkP=`tlK k" ?`iK;]M~>m!~fANR/Ve^9O߼ד :YOn\'I#­ZÞ=fJ"i4$۶ѽL/<^ZþCK-?#tv ئ%mzω<ɴ%ad*wאXhKrtҦKC'WY.K/r}5ۚE:a?|ڒ`dDlUYrKi0ϒ\ga޻yۆ{i :|ی7N4qk>E8 v:JqP 浳x]Cƫ%a~n6ua/a_Gm^Ա>$%r/ɃQ*?7Vlj>ArDpU Ѱf?pe#5pK]ۤCoD,y Eh6CB`݈Ɉ!1lFDh[mF^x}zu$2mHܢ K|Ps r2b]C)L qVm~a/a_Udp3hH>+b{%9jH ۺLa>dˈ~Sr}j`#ep:{i :t6ۙ 6I!'_ . t/; a'<>Zþʽ})/WA"ӣtGܼS;AP5fHhVM#gTr Mqۉ%q Qt rSF\ɀ]l6_R_Ǧ଩S'p|xIB#Wݟ` 3Gw1Ǯ"A wȲw#oia!tԱzy=jܠ 4H8. iS$7O s6A%/<"}-KSR>PvF)anԑ+1`3N{4*,T {&Yr6?? g5p(9_>.IdJ̨Q;S~J#CZ )aWTnd:4;Ռ$I8qX[$jl7n^QP$=.7 ƴM%(^Xl\^xD- :*M)Yӯ"]4dr}Oڞ #v/5X$|[mMO a=΋dm :j=ZmT/ICK^lixF1_Q`]xS`f*1^G,a_ ߅*5ieJ.@Stt+LP|j0ϒ\7pK#5xW]nk \׈@oD>l'C oVqa? v(G(35fH2N bI a/a_G͢;q@Pi^Il:P4@[<"vuU1m(N [k[c'$ aD*Y^JßuԨ3]C󒱘 xR8?. &̘~D$Y[ K aZHz weeo66$4e+8#)ߣZհA΃%(fHC UHoU?ЂI GޏW%OcpXC+O=G\/[rd75w1_۰a/a_O{hW=PeV9K2D{H-8شwqiCoJX" @^xD- :^fn#ѰQWͧf\-b31ܳJf~#/ Ne8fR:ɂVeq{0;c ؘ}!^p~}TC,P79̍VWק4+OݼVj£q0:=ėT1}*l'QX 2=DȄW,8yw|͜+~F"yE"*vWű?eyl nNLy}d(VL_kƼEKb'F;.搣Ϫp҂^svt#kiWQQ ◸a"e}ȟ$yÏ1S#O7g$ih4|͛ bg}5u?ChSyglmDhZw'عwP׻rm&GҌUc/Pnifu"`tRCvNV E n[#vWK  cP|FS bŇGҰT'Jz]8-#f0!fcΎ4h6meN /'1wwz3cy婛։Nw ƴI05A_5먗u{z~%R|"$FrY%8;niS$M$$ƥ1#oi?w#6݌D@ ҈i;[QDNT.ؔܡ9;RzBexs9ٛn1U rYcFpI0EfI^$DBz/WK/1tA7Ȥ^K^{i :La>!Uohg>pZ«#7!de^[ZN?'{SN|VY9ٛlr[#{#I~$ Czڠb+iH`q%5沑q#oiס*0w[$ '70%Q#0Ĵ[rJv!6Ea_IwQ"KoRX2(MFH~60CSC af,/a_G岻y;U;W$#}Yׁhg8ouye@K*KC0TH- :jAh:55.T^O=X6,l #!1m 5sA V%Kis"- Fg4t`SJST2TWߒx5zx]xϊ?Y4G(gI.4^sqB#Ki=wK 8>*OR.K'k)cL_#Tip|B'8T6`: m4pΥ~X,=lY9P5ϭ-Z>%.5VYа*c$_j ,/<^ZþR)XW3嶖+c97K1m`$ۘm ְ4W8d3ǭ]?KOm=x SЖ ޗߚޯM}g2휦;ksҥSf-c{*< -pԫ;v ~/I䀲 +a/a_2gm“M{Ct_H$Zꎮ&Uѐ6e bp< #kװCZciEܞ.oJ[E2CqV%q8k ̰Tii0VH-="}W^u"Xw[$AKfVW/W" Q$=nG6 Ʈv^1|- ׹ WZ^x}VIUwE\cTxIX^`z1Z]#⎣j02fmL"a/a_~çg&|D=HvA* #5Bְ!Ơܨ] ,/4"?t,-j~KWwYj yMB"on-9S;m~l8uwbOoB?<3U/ "/TcF/b* ᖭdN Tm 9 Uhk[V6-/ZD>e {0|Ĉ_UwհZJUcHh^x}^pfL#ދI)$!p= gba IX:҆0{"GokסW"MQwF3$QxxF[5c@(VU[A|T xV+!fr-y|w/?ܓD9dcא6_$KCOUq+-of7 ƇncRNMhˍnwzڎ.Js`[J.:K7('VO֐+vR(Ki C,'<"ݦ}΀*PKda/& .HmD8j??l^$_GpIX4(62Z^x}iN 5V1Hwa7ƩWI.㣻$QݐUL l6'r|L*u&eÿ<%Zy^qUBŠuip?/>5$v Y6C]zuR'V뜈5Ã?mJ)g݉ 0Nr"¦ʒx. m6GKkMiyâ~6zHŐKs]M$x je\$lQk q6q9"}/ Aѳt[O58+K]Ucg)0nfIM2p#[a V0weQ1TΔ ^u|~.=ax#\i$pP:4| #oiN*|jj[$A7dN|JCfH"J J$o M䪒6쫨s\]qA{[m%";!(Fcc|;*IƮ6JIn褆56c25o1~^ҝ-ɋś936:H(>CZKPޝ {n&Q87x- *j tYIRcLD:gI_j^El`$gRr !/r}Z0.$MriԔ0#lj }?Va,I0ŬQM9#p]A^)&/we%̊b\w#'`o.$V|UAbP1$SA?w ıѰ>JUԍď7OwexKFJ{-Mf׈(#ifI& 6a/a_K;;/-.~'Ac?'Ad,G} , ىfRoF74p?۝H&ATJ.v}d"-ɿ_=\ y2]#w`L!I4aOkn8f ְC{Rqhf[F# ^Ki a1ˀgS nkz\L坧o.^^H}-^R4EK|_6zl4$ ̐d wim1̾ЈRɈ67oH)0^ eO?2K1m Kɩdnq;vR UT91!">iqI'] a{KU%=~Zć:--9w\ ְvFeboq՚d j(d0W*M )9Pԗ>FH^{i :j%O˓x)]JaE:I׍y.G 6FI MFJiߋMeCxuښK-ȁuEq2摼 |Ix*ϩjHLjDڱ ,/<^Zþ'(ѣ$–3ꗄ{I4Qf\0Ӑ#cѰSxI S41^xDz) QSH!9Y-DKiqws @ycVh0|׵k0Y-Apkcчm Ha_Iګ>~cp,Z_;@9ӣVg5}1-srl$rB1Ⱥ7O|sh k,5~{4 A&s8Gw`l%!+@eü ְ*tl)wkH^t/?| ~~ 4 ֈ/^5,WĒlCm 7_2ik(u83!}Wѐ1~I4 S5@} 1M|~ᬖ [q@Y>x}}.jLnnь_0x|]K$+*j8g=1O;d!rЃ$QB2uIy?ZtSF >89vL=fjUӫ&`'˼>@o<ءa52sq2}![ ۦ'>D}ISAz[Y<.ZþjWT$ ^ DLF$AvdZ߻c IO0[C+ #5-S^~:L$}Za? ƛn6dn4$Kˆ+Ӌa/a_G}>=f{ľ䋄$|:` @G|OO̤ i8d)5휧M//娜:H([$7{@ O0nV߃}oiC!,H/w7A 9vR U #g:;b%&AgS 1F|umi3,Andy4p :Zފ$q{XAQ2&H«T01bJVQnLMm~&@~ZgQk׏>m!c$a5ݱ ְ/MBɭYUowNIY: a`m`)yD*݋ki*{Xi{VE{,Z-WSI<8=~'*YF-)kiƒ4p82aiGm ,1ÒNj8g!3EְÝՆBVZ@[Dql!mgg/b])~cXEڳ ,/<^ZþW ?B(scJ2`*t$<>]ե!h۫ b+GKi<˻'\~=^W C PǓ{(oiS$5o6Q-/<">2i,:ҷ/t]{-Arʈ69m2a<֮Gp]AC]R+n!c U|nu 1XJ"!'ul&v|7gî;EvMtDvy4D5SAY^x}Nm,{)_\i<$>-(n-geMŹX)E2a`LQQr^"KƦ^yu02ܪq_; SH=Q7#K 0z*j6 ²BL ~6X!Z#ְEH‚GY4$ @`_C V?׈wӆ qK !Rm_e?p_i3>JJѦz$5I'V]hJeIkxb qGPm#F^x?먜=T nbIк?֎"w`L! cA}{i :y0 ICq|QNd%'nѾo*;vbki/$I4|| b䞟U}:N׊!M ]އRD}G>n2,O0Ǯ@X&/d P{[ UIZ UԘ R:q:ԏo/. ,b_ڎn48v^Y`#U~3%GC"} ;pMD "ulIH&[r\%jYjdBRIwvP|IϤq g5}HȊT<(7d鉢p .9"/9]1=W"27 ه1Dҋp=q#w "[As鞦k[L7w\c* % 3美G dw?T$`444eKC\^W~KþZm%l]8ɸY`p M@SJ]1m^ےp1n{a_i:}q[j&(@wTD |Aw Ta;̡QEMqWޒa Xj:?7{>K[Qɛ7Ysl z6rNwud f+ ͒%aJ;ձmkljԜDCa|+*v ƴl IRp01>MB'r}y ~DA۴E_"FtDUNR>aZ#q BJ:/ zV 1>x}}5\Aӥ ~ިZpJFcT4X%n~=T$M4ˇw="-ĴIN. <<->]-/4"?k ''.+jݔ\!_6a.ՈS$ p5O'. ajL/<"}[K^Iyc< }R/=95gI&rݯ6zdyi :Bԑ'?=pw})yxSB#ϿG8͡ %8fՐλ.5ܼKҋaa_~|At]V] Q{`gtbc0F6m;U.4lw"{i :" dh()<]-fF.e*7qOϱk0.H !Bq̰a/a_{h˯ b%8d!wD`$FDSհps\KNcNM ;vR U  MlrǥӿȔOwA"Y^ZþzasCoKY[$MTf3]}Va/54@!]6??b8]þ*߬e{?6/?=}.ka^>=v ƴKH-8v uh8J_;$/ *|}w88-]CbF2pGKkסG4)cf2v'TId2 ZA{bƻFjHLcA;oi81*Y^ZþZk2_S ْ]X*^q*S9:8nY_L- ovĠ|a/a_GuBE9mC)Ď ;"a\JzK6P1GacMcJUCߕ1Ia$X9pnkރi?Q+ Y$7nӍi@ɡO Q}Sm# 98VEYn7ZDzlakvI. Gko'# w!)7G6T`0bE?Ю=Κ}F'FvK(}ځމ"?Ī;:Ztt9Z Ѣyn4}^G<d}uK2b/=.M Pmm$M:&j60F#5?َ/٥"PK|LkS919ݘc| P gT\"(re_%xb_f/j }>bj"F x:*C DFFeO': U]Ar JUBnB6 ΉL`#}5E2"kS S2ݙƵnWh'<>Z g,Jdy%9j-ҫ6r`,# Ql441p3vd2LIvx_|[Xb)#{`h$MoijCX$bLt{i :sDn뼘x_:$E.a[bazHPڵiέ/vB"VhV<~[þ);%v>Ng1ތӨ Nm/GmӐ6=#di8qlFg>S%~GawC8::! RtRD(G8us3kRCj ڛ,疼lw0J Pdž[YW-tc=g 'ͤ a~}QX5N"7yg_c;;tK^5ido>vĺ+a/a_;]uyqoI]>M=O{#U[ՐP%_J^[C\oUŸ"GKk|;,N;ZnɋoND;bij:G0siH^vl!. al6[a_YŐVkm,t[T/5.+p%>9"JAZҟfv#5ůVyv_SY-y&‰džUV"J6CO5 ;%Qii1 Y[,/a_θEOΣ O#@,!%hYBЋja4Ys#(U~.rq-*3fׅr6mOWAtry!HoqT,zFd3y*0ϒյ$¸(9dh *tC[WN_|,@ &gd6\R{216'9yv ƴDHM Fᅼ{i :*? ae>^Jßuhz^:iE[$ Úؤ/+XEDՐ6,Kh bZ 'F!._a<#&lUwqMLŻPٕ5ˆʐ/5PC^xD- a@moրI'ho9y6 Ùl㱠xF| 91kbfB&kKvaǣ3ku\IIP+| 4 he}n i!&X* ƆZNx}}^nP,"\1UfF"W$D+ўwxSpJڋ{c!o1쫨1^-M|1" ?yެ6 ƴ$ ]Km)/<^Zþolô _CC~Dd0eF{}!I9c왷GDQm^9O߼7]|@:|}VhIlp 1]}gܻc I4|ޛ b<F,/a_Q/A}-b ]0 }g2P,3K]`û,y}tkvtLDۿU!G Uw*#T{i yAyuxG7  ybTtYo/| \0Q䀠8+w ϱ'TU>y/dHv O#߮)@w <KV]iygڥ8߯)B]L~M/<^ZþMz N΃4p2%;2w vP71Rwx{ *<$TntrN ְ: (%@]ܣ<-IL_f~ 9Q ymWs=3W|ۘ> -;[`q')a߁]ȂA$5q\$#nĴ|W͖ 7?[^x?v{OVK@_s.A6 /έbxv{i :L<މ|Aϓ)@>wFVICƬ9eTuI6f+??CVBɢ&aqmVɣc ׍dč cRr#`inryh*}3ܕ=q8mPn(rV`ߧAX6m/Ƀy!TՆ'um{I;XgJ5q\ihs<"έU1m~kzުaVU.rn_H?~/{aZG~9Tֈyi rijCG,/a_V-љ*dGNAD ٭!}YFO% `s& r[}Lpdld%L=7H}#a0*A'M1m|~R8vğGI)Wᶶ꧱j{ȥ݅%3^(TqڍJF| sD{6Ƈ+(yR@V3 vk)3 ״ȝ*yeDke=r"M ,=nRCbgH4sq85{i :C:WW)7wr~Bo#9ǿxdD'M1M`kIVW؄l8}b'< }6s1j3׍Z;.-P$xGI'`Gc`L]NKC0Vĸ)a/a_Gel[) a|*Y^ZþӫĿBk]PMoOp VTYh +f fk @Ӄ& |~x~lg5{} {8O"ku]e8r˟0#w`\(eGKk] AnJ6{H]}I\&U rՈtIFyAZe?Nd:bˇXKG82EFx#Ya*_5$\f&d9$Y˒hW#1%}Nrb85]lhJP9"}c:-%m:fi~5b^2 Xh4⻍4,T?/m7@/\ Os/逢ߧڍ ڔ|8>VᏨ82BR1m|~$ !RA&B'x,!FBp|Aж`c7 @r}} Kk;@ Kf9r-oFa;"A$*0\b _*xoOrۉ^Kþ zp٣?h9jMg%9ysh?qth?MX7mۗ@AOj@bCXݧ VV.qcECh97,9 Γ@[?*F!55 Kqɧ 5 E"GKkס";S&[%lvmܜSwR$#vě- {u. ׵ I^x}g{c;:˔<>G'|h\ޭyo t`Li֥gyuKf/L~QK:I#Z$]X_SFg`LAIq_jQXl~ҋ!/Sþmg] gbmU0 ݟ]bbեGDjXqӳ$q*yߛ a?KrOK[66GKkס#XpnGMv"}sJqx;c'2.$ yˈmyIZyRãmmF '-,lΨO|#ˡ3_|yJSqsF}Jç6gԧa/a_h/jL]AɃ K@+Q+@Md_Æ+ a)Vj8(uE,/a_L|ʏ6^P&-ɷ^n#Aćr ROAm-GKkQoq[m~7`K(d <9 ~$'9zw ƴQ^jhn a/a_GiPn#n&!%FכU G;#T Z_n&!%$_tO6&!{i :FLJ<떰rW)Q-XlxyBtDx3A@s$YE-Vҁ`<̧x]1m z- E^m#J$/<^ZþR!."fZE>j?ւxI z z E]f'i΂.[ʓhE܊դE%p LsDZNb6߬M1M|~V/*jAXE|?Y~3qIq>KBq ]\8Zэc h`a5Xc*81G,*jXxD]oDR> 'J#~Q?=qr74R5_-/ s6 {49(K&SٕrҒ@nv#[CJ5ҒܢnekH{uUM<=^/A-{Q2d r - ƴ0$%4sAlByu8yF#VV>,>=o+1J P#f5$nz(w2XCЕW ְ ضx*j\ &nG`はA^bĜU25q` `WRgeMߖ|Οij\,K]=Y,#QZzU$h0iμ%yﱆAd^m :`$Z~Op=64r~%m(meS$)Z|fC,z#oiQx˩Dm)OQnuqPadQUңܦʼ+K&-Kxw#3GKkס⎤Bnd/ ޮ<:Dŷޮqsi3$;;5gA!yu V 9|ֻ`^kDv D@5a^%Kkס3 Qn A^IXz`(,5/pV%_u ->d!3G,:_%"%_M|ix8܌juD"h ŝ5L-Ĩa/:6>FUMUYƘ+{Rs֖)JAgqFiGDZ;ᇄ.>?}.K 5yI2;޽\ŠɓyuU1v([#z5?ygɭ8kƕy#5yՂ x#êkv|=M BDHO^Uz[Ӄ߰D8}9A(CZȀ.&Q c ? d*PكC%ݬ&DOlAꑶ Kҙ}8yǍ_tua*c@$$$J1GKkႮ|t~ "dii-mGj72|(mӍٮ4ar}lo+Ӵ>g[vjޙxܬU]h#u* ՂdPC̾Mzm BHȻ,݊{GQVou|.<.J$*GMځЂ|]kDlU ڱ$ڱ4TAĮJgRG5:0aHt֋2QK|OY! RwĊ+ Ha_Qǰ±I&~ λblv'5"UCbfv%Zm~a/:\ sQOK%B?^ ?l`a.5_ B53{NVK1n2dWKN>f|mNK΋= %NU5x_㝨G35$zJǵۘRO/<^Zþ_sEߧiw!Q-~=/sDvm]b[^+?m@szʼ>sy_㞤q`y`$ihJ: &!y#lt#4%H78.U}n6SkI*MgѺr ,yz}Dnvݘ#z >?˸?ؕ OlI⟱jw#"᠋G$__ NO~ ӳc'T0'`<_@⍊YWQP̀-*&L *& K_)i"AM7oAt;GsP 0fo GWvD̰5_Vs1 3ܼ-$yLs2೦h^|^Bɰxr@Ҋ?%΄R. IFB~A 29))M$)IVWi1=#50qGy?$>>dvY_dX}׉q^x}5 /'K=,PCKW ަ f;; ԋγժڳ]y{ڿ$G{&ɷDCl5Gs`L>YD/ b"O˷ Ha_GI:ku2WZ7 ;` _},@1OO|]n @`T.,<}_V>}OjdzX"Sk6Lܞ sWorhG7Kry4nԷJְCcPaFFM(c%W#; mzDHbu#iUCb I Vje?p:!@SϱqBTԂ Qټ pi`F* -[N[W}#LtI$z$RҀ\ǣq^dB)p чc[ؾz8:kI'HO?/6|HyX+ZÆEM1m(kl~a/a_G"k\N& y韂Wr"cL%) 1QϹنЎU$MRQ9O߼?OZfL7$ 7F%e[.hmln-D7H1FKk^8z}$̤SA=xǻ6G^7+hm7ZU|m+C8 %3`D"案(SRl KNQچp̐9~[þHB *1 %/F\sRZqT*6>?EՆ0"GҰy pfl9=/4A7 BG\ǮMZ[3KC.Vga/a_Gea";K/YoFhҐ"%_]7J m {u/<3s 7_Z"Y~ - y{NP̝VE'C!EH td yR8ŚifI" / O:$YE$ \0ݫ%I"էm k^#7^_J$qjZ6F ְ}bˠ"<]S5:w($RkOE>U1m(mk/<^Zþ-V4ͤj:1oœ%t@)qEnMĺ؏˽JhI`[jnt$OyN"\}ĂÍI*U1m JP7Ga"YְCmuCs< 6jEn"w|zxyPr5E/3&>K5obղ΋Mɋq;0܉J6/HV EK;~"E9=w,8txU1\8J(⊒LЉbOJT W(Z(aJ4'mn#oiױGG.o0ؔ\̊ =H棎xۮxH*J c6ư {4П5*bSLhRr33=ac{A X5ӆ!ht4\A"Y^ZþZ4p(+36\%1MZC 6xXa?Ǯ6P!iҬ!Ӫ b\ ְCgDٸTk}DKt0V=bG8)G\s`L8J} 5 I8w1^x}Z0l쮗Jg.}EhDh/0LHEP`9f`htJRD!gA%5]^8=jpQzo0*"<q\cnx(˂0I~A"H<}^)>eVp[Qlau8$I.^%^4$>Lmu]4kA3GKkס)f U9-!92y`o&G +I4 6)jX#쫨m.*9gU$ꃛ ]=*wK2ۈўMJJIn"N.&t)_GKkzKRcnqƟlJ rT W)a[xz҆0޹"G԰l-Sھ{L-?0%=ҍ VB]\&>?K_*8zdh*]Ի$2p܈oS_!6ypMAbIKf*j_Q%G)JypzTM5'd-&, R3,n!as"f!qSBIJ؆pin{i :\ :-kuɍ?KBf8f ְCaej0{-V"aϤdN~-VL*d! lKY/ b./<^Zþ=+;uF{R6t|"An^ }55⚻#QJl!6 ְÙ~@<^IQWY<%`? ;,k1]1m`$:w/ X6~1dyi :s{|NDlCi<ן!i?lȇtwhsӐ6-KM1Fg547aM 3&?1;߉c30f4lD6C٭Fa/<^Zþm,"PR04/℠BvSB\EF:ݰ1Y<j5׽i'kJըb/OPHk31J*AƦ 엄Ks1~نЀQ ¡*,ʹ%^[D'Y$ɣ٩R$dEty#޾)0l$a:vĨnU|}>1 BҠ†QLJCHl>vN9@XR$77HZC\VxM Ha_UPuN)9qt{O,O@`Vc|["Qm y#5_ \ՁmՒ0, <8I08ͧJFPrn"}I :4}޻n<.cڱTnbÿn縸%jh(\FaGG]1m`$|KCGv +N^x}b[K+dVMNIh˼J#/6 U$CMx aEְCB}+*.Y˚=IN~_(b8^&R JUԒ_\LkKrSP0~?LQBBGD;M-9tmm ְq.$_iN7"@"#A1wӐ鄔1.F ְ5~M+ 'H $撰:(8py+Fֈg>Xr )H,YH*@GrY #DR1نЎ5=~E= d^9O߼ U<(J o#9O1 ˀ"-?|6Oj y}f7%}}"wC$=PP ?k'-ɡeB]?c]lra3)aUo=d:wd)[:Ȁe?m_Y‘ =[ W8e^9O߼y&'UCM:)),܎1Q.#ڻiHL!RSC46dy) Q;N@ϡ%")tcbSV0H8Ϲk0 (KCCT[umଌYe&W !,}*:cy焑>MZ]۪ TX@ul ѯe]FҰ9@b=;cI4o |=u[Xp/Ggא9)i^gmYN/<^Zþ*]\%M$MM48(#NZ¾L$Vjncj2{i :* -ɣ:RF@~FӮ}H&h~">=斚؋B#y^yQyU"2:jdtD?hh\sT7U1bg5"XUKBT<d9)*JI>%>N~5 <9Erd-)^f(NV%(4_bYIG+n9Sr#03n2-H sCU((Am}6uAvC3xzEz&LrdM uM.og%"둢1ϓyK7"g9Gc`|dRJ! aЋ~Kþo2R&o h6dwTBρrnrN1Tfcuu 8 *ʋ[8o8K89P'-/_#iҟG@6vFCpJqMM=ja^9O߼߂#_̱)>nܙ<&X=f.$ױk0 d0J1"1 㮒5T9k9 ,lc' ,~@8SɠJ.Z5ˆ(!5ΰƦ^xAl2?mU3 >H_sM"$p zح&%)+y-8 1~Of_Ќ)8TJy&N3 H*qi烸1dek{%ySw0 yrq"A׷MCb]1,ITKüv {uԧ]@&1ŒVAs݌u^/w ²f(5t aӋaa_kVe~.}iN=)3|,v*  iS$S\mzGg[G&D dDo4$ʜwf+X"G`LFC2&ZCv {uTZ(& 8u蠌8KpEqy g$?t~Gz[O5Y^gh\ ??iޟ]޼wn1FHa&IʾL ω{ȩ* rRS1m$a!s]%ejס'SnWϞx &A xJI{)%~;SP ^0_,vmgI?p b*Y^JßulfvӓTH :xcgFu|ѕ&|6MZPcj0>ga߃bߓQ #5>&Uz#:Ͱ$1AD"gG|]qCk@'㏧'lf*`2ؑǵ'}.4}vebe;6qy  Key7r. k6~6;dy) aMzY?(@ws; ilnU +HM7Abi>j}7 G{9A {R';PrÆǵ>macV4P"] Byzfvq|W9A.%&I5]q#5gI. ARm {u<]-.2#Lh-=2J@9T H6 ƴIIYh ALRmD/<^Zßu$4lbhƐtA{ؐYU'iom6>?K)M~a'`_ǓoNG׶Kv&1y4i;h0 7U%i0~t$ vAkhwl^{i :}򞺉dk,8jC`'b/[M؃ehܘ;MoM> b3{yz2''h>H@k "[f"Á&6ĸs|zJpS1-!,Iيx>Z6LNx\m Z&{,裕Ɍ"Gd{nQYv60CMX c\U}bu!˥uKIpL~ϊ׀,|i_xdVpfA JRgj;%~T2%$FF :^Ҵ!eDV ƴTwI bCG;܈S{x K[$E^Bqxx*J}MCb@P- s64~Kþ+u{"z·;Guѹ~\bdg7G<Ǯ6'&S6c{i :*d䉦Bx$DrhF)|E"2_ayA/}_ Z>;Y[͵ }҂Hf]~ZaȜ>MtH&~$v.(0!G@r a|Þ*A8w^K<й J=w^"GҰFAl~ZAe 7qcY/rk7ğGKkQj;x4 ȿf49)xXMQ+ \ydTLS *_N*u{}A# &Q)A$_b_ab, %ȕ T v#5쫨^ tsj2+ג`\*#?"϶Ga f8Ǧn06 MivB#gnsBN#Ƌq|yIɃZ_hlig?9O7l$X %Q>YBVdNɰ"ዓcl&r&(/xq>G}N&h&|7G`i*M=צ 7Awd=c{]vIFO^ wӝ=R@{4n#5?Qf3F$f^4_qۙ`0jrP0)5ԢaT̮R00szR+mGi=3񛋽S#x*Yf*Y؛H?nY-]{[@A UxR;8vդ4"Ez+ɂ=)1We*^b#ζiXз2%첖&ktyz4Yǖ}ʑU½L]M$ *:rܦ Rg R(rvvAq蜳 y_O%}Lг>=2qD{qTVZЮMAbc% Oq U- 4byMVQ˙H>Z`gGH#f+eɍO-2آ`x]w0m! `$49ܻb$I*YZ}ow)a~s/ejy܀6 /A`x*0LdLZXNGGkWQYdXI뮎MQn<)!vi.ʅ?d60C:@xw1^x}Bjpc{/ dlD'ӯe %HjO]VNmgQO0foR5.Ȼ㰫"ͥ({Z)zEڗن.M|Ťv0;q$3&{cBc7 D7suwH:=O=M5`yd^IgNؒ\ ' fԍDMԺ3ΫǮAX6:p!jUx+ыaa_$') x[$]xH154zn2G<Ǧ0J)>Y_D ְB[nX=mQ)HŦԩɼ:Oؕ?o4 4gAY^x}?ޥWgק{)Bp$ Cz_z8[=A\۱Uo39λa.:$7䓦8C4~B'M)xTd Q^}?Ej8JY3a1&x Lg <#.*l*)uLRJ~2-g1pp7v/̼A>Dh\) ^8&{@1d3$Mً?i!ՇpPmaGexɚuMnS,ňq5v/@̘ 虣d P>W/,75 ԏ3xܪ<%}3Tw=<cFc`LpK'F؂nqFF) ub0e\lb%{M`졗8jLJ9K6N G[}nQXQ:&b;oՌs<#)'R<#=)җіL\ V7j9NX+O$Ϛ\g߁eErd}Y57qtTɈޘcΒL LQX#㖅uU /VEGڻo85XQ0 .[#H%-q>>5-XOjNb;xwjl}<ϊvC7&kj>.Sϴ F5-Wk:"m)٦ю!`<)*8$qc0S|Zx_((maa摓+);uH΃#?}.zgQ%;V yg6 ƋJQXQ:ZM=mW sg [,I;_HoP \,x#i)FD=Fv7~>?gl9|f3i 'T`aEKbyiVd4x`v,YN|yf,ĉJ!Q%3n[XQiO{cN%A;7G5Ap,@FU (In0+bOFy[;ZɮAʵٺN3ʷ=cWCq_cIX<-DQXQ:s0#dNS;f7V0lL|$=Ĩ<U*ł1}1kd!ZT¨Ub(maShiݭto3Xuav q $O`%5xI:-$ā"L ?yR *o%IZoFm鉶ěR1 NhpQ|cwتdFi <t̘}pYxud qmՏ{Vh"=@~LJ]]ݏha̢m1؛h*?$77;yc+֗g؈c?MjkFa Gi <4a~l[N.dMT׸[A16g`S-$gJ }1*5,G_ܘW(Xl:BHgI=^! 8yYGJŸX0$$$ᣅV!d(:]DRd6%O^e`ŹՋd9\\]]N>ܜQXQ:>sX[7?[ޯi?~\eQގwFA,wYE˒oX-ZюYⲤjD_#'//>)ޥUUo/v9~ =1 #ߺ44wߕ. Xz17ul,Z,Zݱ%ɢTL>$b-Z%xdG 6 ?7ÿ+`7y_iWm£ ;2}ErG6yGb|?O~T aZ=bJO4~~[uJ#2db?>#m}(m#f6OWX{R>;g7O{ߋ~_qAc.H.´NvoEK" Oᑷ?0(>}3^|bm`L1"%I 2C8F(ȸeaG szڢwdaDC?H9gh5]Nc)~_Q%%jXgQI?T%L9NI~HQwbDJH<}Ga[y8 Ɏ{q=:({wJ"Y}o%mP}s{/Sj"L }>Ga[yh%Ir )/qŔ`CdC 45x1K򄱜}Ec$ԂWQ2b=%o:T4vHm&i\\s?qUNY FX-»G3u܃7?8#Mݐr׎H8 6ppCHީ9|?/\y}%,is{;VS910ic>Ov`L1~_2n/im`|ǑdUc g'eJMhw~W#FX'-DF!H m bDJpN"U"52nYXQGsQVmpyKdK<жQk9Gb0ޟ+6_bST14SrGVԹLpuqt}jj>b%dLȘ<}Ga Gi <4_^q!!}qu<%lF$}%+_Ղ1}`$q7~BU8`(e/a|*19 YQhW͝{JGF*1$(4IxT o$ i!6Շ06[(maGݻQh{wX<%W++:&{'5SCzhxqLm.{Ep΢!^6`v!薋Q\صb}%Z-Ӈ$AiӇKg(e佬%s:2XʓUң^`8SdiƙkZK޺nWqF;1855"ũZ0Jr"5-p-1Nxu`;%щĩՀ1Ղ|`c* {f=3Ӈ0sZ̸ma=--3wso\m o^ӏ{ qDS Oz8m`j'yZT Ey8)!!Ӷ[8jw!ת#F$X]ǿB;RIFEy - g@ʍɩՀ1] xIO  YTNW-nk1T ΋p{0uhL^-ZNA::a',`5S2YQ.Z;^XoUӳł1}耎4!X}+wQX#㖅u&!SM5H2vme[$d7A]pͰ)M qݫcKP ?-cAQ%%nYX硍mlك2A?iKVGS  Bb)@8n4fܴg&`B2=K[@5tuV)vIHٟQ=z%F6&҈&ՂNɅ/@Z؟5}\Qunơ۞X[g!H^ 'q|բ)8~iaSrƴplw o?xn PUr`䛏+K޽ >qPx.\-IܪQY FX}AdVȨe`EFv--"w@0tH.G^TcrxM) j8n!ru@ 2"*]F̥i衚`><8uuGoW{wβ)7\Τzcsqc/aI؝wZhy,*KTa}J1]~$yˢGCx[;7VF; ;KPYk_|cO0M 汰Wbspw|470 {x@LX-_@8%' ^}}8 k8J[X籔QT +N-Q`g f#5ߩ1j8wp)A24@!AXA: _y8=xt~(: 4`yVՂq&˥$ځ-0smlyԪq=676:w$ uM^Hj#<҈j!1}KX:[XwE2u*Sgx2+lJ" $ Ɠs$E۫10ᦜ M\]AH#c?0cĦWqd{ĂpӸ:fs ׻g_b q9]<+w ??wD3I!ӷGTQHXoYNП2qHA'ebnwdp9|݃ Ѕ7.f[?cJP4sv>)$ڵ FQu˽;v?{1Sr4vƐ҃ݯ`ݳG0 hvZ؇R geag号|-v)!,%;ҹ"f"ց88㳽hXHLߏ%8ŸF\xU(Ÿy˽u*zs[$$蹀EQV1{cAJT-ӻR;G ƛWIC_TVl%2/JMIE&iK=4xcw'gEң6p`US2P6->5-puL7w8y7 Sr"_[Er|^q|ӂѩv.FHDz>vW?f(e<*'L}[ 3Ju Y$~=_O !ǧ5,}v]qՂP) ڳ yh f,(Y)H{ހAܢ-M"1W5"ZHl)!9pZH>. g(maN\d@tc5klaiH* 蒐) ).c RQŸY8+IQyl, Ɇ$i}->qȩ(QŸy8Jǣ[$ 9gb| I?R#$ERSn Z}E2-п0Nә>tz(nb^(*xj4wO^=pAǯ0ׇ:G?F.{6OF×Ҋ%޻Q‚kM .xW-eRR2Еo)p ]jjvU×}~\;޼Wq$ |JnbG4l=XEUIK,S"fpQXQ:7Τf9]T1NdR9eȫ2ן(*v47L gdZr 3kǞY#/ Gi </fKIHšOlFܣWr'!z`|JwZ8,Ѓ:Xؐ;AYb2KV,Әc$[pkł1}`$hV:Fpõ-6sk]zZK1Rbh=lҽΉыum>5-7~#S|K3ĶJAHW;=*8k%Uܫc$ۃ[ZX"Da Gi <nDעr}Yؔܤ%-Ը2<& =: ~fp|Π)O\B?S˳UE#YR#jaQfVOFa[̣.rIgE&Ӌg sc35pBBΓ2ֿ)hL4m[~?ӽ>wpD?*xܧs.H,ؕߢNExs\۟2ZQ !.߃k'ī×M6Swճ}9C);q}H /gѰAT-FX+[8c!zeaG϶z&ϐ4\3\(<+ i^i`FbP05z3@Ҙ<кn()'R"%·zҷ_Ɉֈ-w`LW4|i!ҧgFa[y,\@l%]e3#/<gq 5X;ƾi@pQrzʺaVp%jW»ȽR#Ʋ`ܼOia;VW52nYXc}oڽE'~E&8N"Q8D=҂1}g ~>|PȸeaG-f[ӑDTK `|qu98W@bM/ƌV[I3 5 EMk<Sзo ك3l;ϸ8oUs8%c7-('}tMg(e<\6E5RݢFl~8wxj!qS{JS}TQXQ:ڄ4ʊ:MxM)Wi ,w`{mÖ4.^BCW" E%Sb6V t/dᦇ8x/i=N|S#V üSiG7onFa[yyx ÝyzJ2Z`Ӗl ҈9{T"H8Dm.0iuY$-n%4]3ha ( f4wEDyW:QMI\1̽DϖΦqF[RV4/b>0Bmy(-DCXE2?/>^DQt6%y<Ͱvf]rslkhZ0,(OS\ce- i,*}|U<^;>$!% uSY5ĸ@9Ղ1}`%ڱ Ɠmq:zAdqKRr3q5n{K~"1{xsz%꣧X}?3 k8J[Xvf1w ч6IRB>Y3:#*2X,oid{6Ő`J@"5eZXQYqmE꺩LsJnh]̍j X"9*I{/gb-g{I a>"5-кj[ pPPӽ]L>*yh ҂1} Y`TX*Q:m 9!)PFIab ` u6-J qY]-j{ڵY}밯HfiʇV9R"y@yE)*~7d`\HӼ@fx)V }J6B'QyI(R#㖅u"Tb',V 7rpK3&k`:r܊-DWCnECQuB3. HȹZaa|#FKMڃ>qcyZPQ F!cuZ=d tڽ4_я%j/yhdXM B,>}?Ej(ʴCdw$<#,Rv0)+ ~ٝ5VПeOu+`AbKg`K^i9:"A\)yY/vlkԸՂ1}K.»\|Ey&̑l~N 6 /hGZ{~ZK 9;-g ' 8foѣm,&9%jQߦ!lo[)XD>uzD9V%mC纣Jfg|秹+H9{z :=Y( |Q"n$DBX,m(p\NH@SA{=PWWF}"קp)Ὅ/Uhjp_Jv^q>s3 k8J[XQ k-zCUߔ0%fn A'X*yXxӉbJ{  Ga G) QyH$9toɥ7=ViCdXG"r1`L1"%Y WAX!uQ&]y+["-;fzd F.;Ĥiq6sGK5/7(ܪlJ5h/s["`аzu75S0!IpQ%  "cXg/ogK IZ=.+){b<\Em^-FP5CFa<Ej(ʴCǓGR:C$RtQb^GbXopK(ê#$wK.u>xű?y;IyuJ4u(5q<9]XQ@)w'zﮒ о*;q"Q ~G[b>ԘƔA[X\J#㖅u%[y<"7nYXP3iP@e R;![ 7'ޮV ~?>%Ԇ1NxcceL *8߹|O=lRCBM+ݔttB;Vĸw9dFi <|i :ڢ`}W챦-GZ8!@hY-3%\=~Ȧ>q((ma)y^zIjDZUm7&|Tɋŀ!=`$)0 K15- ٿ7yu$I! ~N&G]E< Odiavȗm{LV(Q+!oH~$v._͟N 8}QHcM X5{XfI=` ;u#reGbHЅjZhcц}8 kdܲCdʔZrcʒBws6C,83a 7tcΞ-seh>ZX9pܲgMVNJסl|t> 0R`pӽ0IJnZ,ӇVV`++Ea Gi <BFz@Dg|Mh#9{ׂ| wjc`LϔCdaWJ,-pס]|d^-7oXo|.W8~^cMqd|IIX_j d_>%u>cסKzV8 YWϚ|E!{pÍǦ)zsV*(A/kէϩ\N )}JA8oc_֓kjDH0qS>%qOZC(RCQŸyk au4JNIٜP3ZgJ#hB!3JfܶΣ}1QXQ:']m`cvH̊KI0'bl:'%I ZHL$Cx[CX$XlYCQŸy[R&~9q |&$q|w_`w/j ],S$ze T:5!142lXg68aFQ>+Mo)QggX8 vrAξ 7?Gbte]%zzvQ4)1io{`-55c`<ܢ;%!-\((maQK]a#ɋKELGV2H;*W[-ˇNi!ja%^4-S7CuGLīhJn!C΃K-i60<\E9V Ƈ RgZ)Ea Gi Wd 7LNQHcM dQi;2 LRܩ2 k8J[XQXYO'P$A׎fSOĺHZ0 W hK@ۗ@^|(1㦅?p39 ܻ)`< wt%j|.;bdѠZ0gJ,g5 ( uN$O"(3&~yLlj~8^85M &%JlE0Gdp2NB۸Pf>J*|ĝj۩ A= '1o.&fZ#Ra@$7W>M(Rq:3 o@ +wKt|%9w6YJ>yQӂEޥ5"'Z0gJ(L qT}k\$3J[X 8P{3])a]>hRNwX}/rbm[coIÅ=b\'U2㳅uzH]%L-_/:/JՃӬ/9Fj;l>e Ψ>q۪- <?r*}:[}(R]S)m7[N_皟VGOH6)vgb t38 _ex~:'-;`{Q/|щaDu< Ώ36^cI:(1Ϲ5.xnrDXr" uK0/ SS4Z0HPO:-cA(q:R +<|=%ֲqrv2>JkWڦW -%Gd +#>(RCQuԆ = 7\H82pM/r=1*yxc`)!NZp+c"5-󨷺DEL=:W(iq(QŸyU;6,xPc3!5-XI&eF:yG>iS㧄B$V[RV LɆOC(RQ:z+l9[j~\8rgO^>j9<J vOrѩ u RptFxؚwC7Q;)@h\,M ]54+>A(maG9TܪUTk $K8%OlAُ^1Ղp%(J =J2C8F(pܶC٠osr+>]x˭ d0ƹ o,Ӈ.!918obe9ɌRÏ'h=WDvMÃC _S=W8dVٺ<5-/}Ќ[PlcIԆ?8*FIGK8BbߤĶ}Z8aytOQ^2?'yUNuɝr<* vo+m$8H>d op(e3 kdܲC5w+-p{<>O$iC b(ma$*RKz.c#^JIk7z ,= ;qcul$i"{Hw.H$(Hq)9pgFa[yNB3NJyJlr쉿"W8sd$y2bӨEyV Ƨ$E~-pyԢ0]Hci֩ZW.` Vyo[ Άl^!i!*4aIFyg޴ik-A2x.Jms]}/D)#tZ V|Ga[yhgyO *{̜0ᨏ_Bh0GuZH ضՇQL @ ,I;޷,[ e`EmBh2yWhwbuQ V{/AQQ-+dXxwb̷UɌyxЍ}(- ÇD HǦ>5k`L!ɉ^NBPKW1QXQ:ڏetM["ylO7 ;.9bT=O[5v[O )$,.qeTI ̢X+czH-HzPb;> 「3::!C_ @;a#=8VPL6}`޴:JHkRxWs޶x7XBb~RդzFOFa Gi Qak}B/KS\/e\lr#JxT-g} 52nYXQ+^z4܅d :%ϐpl~?}p*lz㷱T%~lz(wFroL8'6W_!YZmxS.r|tR 5-,S~v<㴥{(_ u[:8A ++ l=Wl]sUX3"<|>Ovče*K R2Ys#o*?:^2 ?a 0ZQ{uCN?I1%cAI[pG1Gl@ӂq?}XhIӁ-  QXQ:YsEK%I˜ os%?>7,e< jV #Rm-Dg!xF,QIAO[,;/[EM =q6vƽ=ė}TɌy,);w"(Xz8pbsj,aGB8pe4i7l9{,r ӣK5zR-ӇMtrYC(R#㖅u5o*sC?_l[$|^T6;xjx7iJe/-gQXQ:J QO0Y#)4h<I.8A6˼.6kBU&I_|YHD/Z0p25ڽXHL!ɶXFY%3JY3ߋ s&MN7K:SvߤSG]Ty%G݋ .i!8ga\ U2uuӸL?B[# ^m'Y"_|>t0!-LcJn4OJ ">%Qu9Uwt\|8}JɽY7{*iA>N q[}#UɌy0LS~*LH:-Ҕ")Rr UQ9?W8?S!?sx$tF/kQHcM ߮PEpZVt9jHp_OSG$un|4kjAX>)W3~2pܶC?+,/e ѽ5RO;q ^HĻ$gZ}1t>FF) [<:vfF'K-?vq>00U^5ػ. $ ]CBiaVjeRe,jU]C$󣊉0Y}ne><[S279Bb.%Yg X}tWedȸeaEHNó7W<@bot/!%GFV 쓙mA"QŸy˼!6%T'Bg*qƕY$ d#6nR@8POL;4ccѸ%([{0?v#N8{զFU ƻoPv#-}1|QX#㖅uZLaǭ3ضrmJ:)o.RFW.64:vյ$(lBŇQuJ}V٫ΌzȘc#M3R[8(q:-%0Uv}MR3v-i ld@x{m5`L1"%M0AX!uRR.vH r0G2%8wnʈq$#HpUU L\oɉ<4p.A "C%b;͌lfZtŨكY1f@'9517xd :IWh!Շ0vwdiay/Wn@gIԯFo/"qZ8T}b+HxC?HL8S MfGJf6g׏ϧh,n6ىN}&vcNch'e^9VjiUZ;2-Q{{܆*")v''tYp\5; d R)\2^p7Qg oz4/ vvep(ZɃMjZ #LS].#$~! ƻ- ELܕC7u>4k Ƕ VY(ma)u|/7@jDƤW`H\,$5._,2>|U$3JY3:MŖ]ol.:>.70U{Ya] :d\XH%.:#dP6LBd=dg9l~S7c5 8XB<pB~Rp՘GV[/˿"p=|^{C; -ࢄ,hNQbӏ劤k:c?r$V(kc[}Ga Gi <**.݅~<%ѣQc#S1Hc_--o$BŇQu\Cvf/^MqzI~7<@Ҕc[-Ӈ y'q[cAcثJfûĿ 2Q9!8b]K1VƗy>N'9+d2…ֹjq?9E"Ʌf '=x]\ THZC-%ߠ>8Rpcy*gWޠ Ǚ`8:Zck<wV}LDg05F]7VPqfk-~/ u!ϯcn ˼sGKe/6Ui"HMb9G ^0ih~0Nl#J jQ>AX1:ʟKG'epݰ7JJVwĝy$Hz|^ E4GVOah,tY˕ZS[+p~WcaBd'#%VW`Lc1n,f}A/Da Gi <*1$nq@jBIK")"D9=f6;(/8}J 2IN Dn6G[^i1BQ㶅u1:a- юɛ.8S_RI jb@J6\w  Q: -qW>pK-@SrЯf,PVhd폢q_cI;-1GA#5-0, ߱\|}3mPjT0.O)ՂqWS)iHڶ k-=^7,N~[$iqﺍOɖ_X2w_;bab@ڛ$l0dFi < Ɨ3h9aD,)dk]f"ܸH0babЄ!;l!2bMQXQ:p+vl{t9%ﯾ:?S:ź׾ZHϔ#aaόyT}% !Iol/|P٣@Y4g`|7|J#dV1QXQ:==Ԩ&ͻ YU z6Psщ+ //\l rSrrZN\15-m#ݳ:+8dd>X1u.yX_Ղ|(5ֹŇzW]WȸeaXWzx }5^Hnf[iěUcoV-$űDZ8QXQ:z[TGudI0ŖgH-qUIJuH $9 k8J[XQ@\":?ךN [l1/?IξZH涖G|;C"5eZXQKQ GTцm%HH_Nqq8[$h,W $xJؙ|ZhX?߽(8FXga`Գ=X{(P#=eJZ Q="ISě6x)ٸ0>ڪdFi l<%fqu#:_N ,)6 FJȸeak'PƆ?67~RhO;f*Y O>>c)bƾzEQ:cR1q \˻[Jn4'K^/cګ{BMMiSsZV* k8J[Xa"=kK_^w흒[A,)(HZ0'` Z}GWɌϟ#KDvq߻{WY4n84lGbd}*ŀ1](O KGipmb3+8FXg5#N%H@:=Z`.swcQ'n:\&f7w0Jn=ni; ygFЬHw|&Dsbbf${7cV #RB?QX#㖅u6gݗ<;;H2ay{LT$ԸՂ5);[BVɌyԒ5&,yS?g6eZv=gs^+g5`Lϔ>mMA5 O.d\-2(Z/˸ZS s@W͍3kd4B$:t)g}!rIK,odG/΢Հ1]B D}i :UόY腃!:Nj*B9ՏHM8*[m8ҳ;.Eb!D-~>>5-XQ(q.P]$;:7oY' ac(h95`zGa Gi <NFG {s$܌X3}D'x}T/qX#9qd>0B8cu-D?YaG(maGGn`;d vf7e$YV\9U b=9>v?B={mIʌ!.KrWK(. &6+g>U\{A2|H~ؒ6̈́Np>1ۉ6HAՆ0$4]"d YpsG[UxGHޓ"EM1M &񪹁4|W ``_H0o8N_?>!_QKr۾MU4D]97Z TmUĴB=Ibs?~<1[,/:j ׵Xв~.Ryޅݚ:qk[$=oi3,9 ,/<"}B7q'mBRGC侊t}k>,j+̨e t#:!-yrnD,DHel?9zUf }_A,P:4(Oɥ5T} GO1j˭Ӽ;O߼wJ|C- JЗEpŭ>ѧbal!N1yDtՒjLjpsGE]ٝGP/ەefŕgm7enPi&UMCJ2R2Fv^Jßu((1W7{{&66%Pa7y-p{TUmҔD#.pICt6 %/<}nJL6I3O]]Of~Λ,_a`?KGS4ϖtAj{xuT}&< OqbQ̩('U}9Sr!d0Kq<+??˼>Oo5}DFpt WU%`EĸZl񺳻 =~ZUWoW2v0"Qv _( ޗ?p+oH@i0>DZ$O Tmґ^[uZ\jV+5L9:—FC>^_>=D57Eʼ>wyo"km.ցH8@ H Oo@ߓYf'v$Q|5=HSzBZ,o=}^]>+(M^KґݧWW[vX5FUoi$R> a\Ћa/a_GcCHDgc ^\&➱>'n %h*vl??˼>wy_ %9哠YBS61Mp$wĒ#6 i#fX~wǔa/:Xb3{qqfe(bn+~RĮLV"v5`pkjՀʴ>[^Sh{MY5ry:)總})4ӆBАwlfbv{uT2RUz<:#F_5⌋-wgJQ)-MAX6tƒdq95DqI!z#5r4NV M< _y+qfeD|cڈIokmAY^x} 7τK0b N0.k8Kƙc,] Y*yMcOYxJz" JNؒ~!0-j jưQy.UAb Is܊!qv(Vhs^5f~-y%(=%&OEM̯%i Oz#5p!~=r^xI&L`kjbk 26 Sbjn:m~;{i :J 2>l6wWR2UZ㻗ufK@`d`Ґ6$.SqF {m6z9^ZþӐ؛0`KPE(:I⏚. V iC eC2IoPPUl[FKkZgAp5n- <8CcאvJn ٮ6?? ְÙ1rl&>$fdGۻ)VHcKԘ2]1m`$8;1οW,/:\\wY%jgI^\ ޠJ u2YFgאj'%Ljn8f H/:j-*_2`!7.KaD[)GkHܔ撒ԩwĈ\U} w#hk}d*w pa0n*=v ƴ,IG6?? ְ+&'{HI%M1Xt!RhTJz6U%Ld&Φ9"}ι_v>הs$(~x4c/A.aG"q̢!rai؆{i :*1˰}1ǮHۉ3@ ,#`:rDW HICޥwT ְõY3O*x"QXYe@y2O']b/4 m,R ޴"mN=@y.gՍ#20X۾fzS'޻Jzli'^Iȷ4 ,/<^Zþ"ͼ6~Hs0|GC5UCN:Iٙb m %,/(Y^RuQj5f-1.11 ?tW0m`-ӧx? hr,3Ÿۚ&E&!fȧlӏގ SyI?.#gW`LAIQ\oj89/m#'r|L*tBRsDԸ-bI_}ዋqkh"flKMDI9$8Fְ/A)sN,J c70l-0Er9 r2@.ON⨖ dRʨĒq;6U]qlĴ5Ina6v-a/:ʅ:u$tw"\,hv`UcnFd=;Gb<;*eӐP$%7ꖆmO^hDz) Q.ZT)T( ` X\8 G7F Hܦ'v4| Y$tOw8*Jl!LDOC=m=G!1m`$ɚkpэm~^JßuK,SD #&󒄉؋=\R]1m`$ "F婒쫨 XYfnhENYZ&wyKiY ڲ6\epSY^F.⭦o[$7{Uxa)Q iѸ*-cW`L!O [MJ<"}^-]ЭU*%oBlMGukH%K@)?ۯ58(f1G ^jQ{=֡nr352foo$ bNε$z)zc`Ȣ(qXx!ٹRr[+5g1Ε^x}k.vnS2pba8]?jQ[5$> uFs!T1^x}Уu3:GA&%37*.+5%e\KCV¸o9^Zþ.c*LXr%y?poytەe/>R o]Y ! b=G+WarW}Pd074yؒ_.J/?COjc 7,\ש6-6bU #!FmIN2hrs@L:iXi#5N*t8. JfԨ>ArĸUUP#LĦRX= Ϗ UT:Pu2E['z:伙p5d U|UE#k0 ̰mKm ./<"}5_)3uL~IPgKA\ݴ'"E>$[DK˩|wk#5\#n8b&Roe& ag<I!1m h hƖmB^xD- :*u Tݣ5ښS[ʔ?Er ?'J X~Sßuo&}qF1'+ hxg&^0N&)0|kI *>v82*Y>ZþJ+kDC$jKI08F@*"  cD]1m`$KC?vݯ#5RdP$F;iYrפRG-_u:qlϻJzli#fX2[ !C^x}&yPquN-yjFBW/#k`<]a$;'I. Oz#oiQKd4_Nf@n2!q,K 'r@邗S,8w+N}.<}^9pp4K,iq1 |eG*sBN!_LV Ʋ)fXA޵!"Gg 0աΨg֒fJscdn_~I=b\cɁ2e1^uJҰ|;޾ϣ{߇7K"DNRp'wAnms[#H-NF^t)nX8p#C 'UzСD%)^5Y#d2-T8l(#f5$>twCl y#5X8_Sxq.&%dQHZ)䋟]CCi) r т\ aD3Eְ!g / $Q'ww4( Ye4!D- bhF,:B(w}pb9"=Yg~zhM1Nvg茻iHC7%? bGKkQySG4\_֎Œ(//ࣃAw5F⭒~~77aو[IHѫ a]9~[þtZL[22jaR~5{DwܯCZI?] w7AYNx}}$Ƌ^m$v_>#%@GG HT$a;$v6cGҰ:*}3_n?`<#wI٩$ xڮ8;~+6a/a_]ʓ{QEr=7o{>e7%c_p_6m|zu4#l1 Ek ;Qm4_o1np\#ciHܜsdI3b4{AY^x} ^1=c7F>k$ |튊`k>#%bw-iTqDxߥ\Q%Yj㼎F|ۆ#1HJ2V{ iO5?Ep>fCHa_T-KiGk4h<^E҃$l`)qzkp3{XGKk${O/ā})F$\ QD/BDZiHLJIHsq^xD- :*Vm Y>[p:zI1&]gx'>ݦ R=Spd#slOVҼ;O߼wgKW1GYei\W$!~nǂ}&eG3x]1mRKa1:7 ְ`ϯKM\7yoLOz}OW&ƌ'f݈2uuz@ɳl>Y ~{_86$2{A" qMYmsCE/<^ZþJC6֡ =$ŌkTg&45$v:IJ@i#56E (x& XkAq_q\ R5vhM?GNDkR R"컩A$bkQ5d]TY+TLjsr1~`bR~ֳDb˺rDCuJH쎢>a_ >~aW*5N("+F~kh}5cXChD=?Kr"oi;j{i :|MJ]w2=y?8aNm:o'JoӐ؉G)郉GОF#{uhx @tѿ"7ܐM[žA̸F癍-(ͫR%\rhp&ۇt9h 'Ѯl-%ٵFI*ќ''2d%X1m!Նg%{i :zYz?unf#4MdMl_u{֓Zu`W[Էk1C nӲ>_[7jFhq#>)&>0Q+1Gڦ&>?Kr ft"G+WQFH Os锼_h˩UT5Ms;k_1Us;lɍn)A"i9 VgRyc!M%5|7^ຳ blMBuK3I:%I',"\j>&hH%a*eu g iS]}׳љiu=αNGF䥥Tm~Kþ'?}{,<؊JW~Vjv}׳FR4$~tInlk6?? g-SJ^V)h,H!kh\'vHatS< R5M!KAYp|gt37kCAd*I+уpxIX"N5cFb%ihs4`~^6``_fŧIy#衛;-p?~Qy>7KcOYNC7iޟ9ڼiW5.ߒ}xo^ߟɺH[h\ Rg ȏsU؛|yo>G+YfZ:2֒UH,B˕צϊc8ew2=$[RiՂpL9^[ #boص nYnH%߽Yrރ)[/#MqָdS*gyuh焄[ǥ UA%z52l$ 3g/ ƴ 6 ! #oiס#˘m F^$!H^&0!xX0دkH-5 8o۰a/a_G!;iee$K2p6z=EnUA?vγ7ۓGXuL W$[OYS ARp kDoĴ3$m/ņpGKk}EᣆM#^bEDHhtT,vU ߮ZveY{AI-o_w6GDHH >Ĵ{80Y{2w ƴ$SC$Y{Vd =a/a_G)o>^]X=qJ #K6^4˹ Df95ҽj@:}?ŗ$]kzԹ."Xq}=?[ü#)9Q+Ţ>I+흯;hE҇I!0HJhw)hnx$Јt ½K2D{Œl'aKnj_Lwci÷wl m~a/a_M\$f &ύyh%%xb6Ԉ0{,ʏ8JVW5$>Lb!ݫ b=GKkQb8Pȍ>p@W$Ahh5壋ɨB(Ucڈnihs|^x}5)id{$‚a }n\~˧ nEȦ~Iy07qQOs{ٻ:]t]% %+FC^t#ΎZ`L($  an*I/Sþ-w$κwoBYQxוѺ*S'_ O,_EiVҊş}mS"e(b1v>TA` N$?hEp4啧n^_X|j?IQ×&!XeKl`$jCŧJְr ߻2^^eEKj7Ѕ&r"G?-_e ǡ{*AM1m|~DjC1z#5Я;X5R^MɋK->T#%X9b]CbROOon\ jO#Bh1~̛ٖ/ɢm?lkQ$hHXB ,/<"?먿ݎ󨧫ˠ2"Ҵ /BVI'kG̱k0 e@r?,bGKkסwM7qԖLUM:*AWq(sJRq^ťDSC 6?? ְ]yg7=>=% w^wzM 2|`j`L+{Dsk. QmX^xD- :^cŰD|ŽCDE76|34q=q.34s;M=B '2jIFPMtр6=cWX",ڮ6bFJyni8ᆹGҰ<^lPJ./L}q)X)(hqn fStKRNՄߊdh *X]6 kR-Q4c[O#߫G{MC>Җ4=yqW$~qя⸖i,>v ƴY`Tp< a/4"?먡r\0c:.|[r27>R3vǝ8lSqsi3$Q@+54m)!/<^ZþX0H30;ۆ#%J5Dq h0=nKsX!<1z#oiQ;F`vwd>B;2$$v>uwGJѣsn iS$l v#kiW"F ҌL=Kn،w a=Uyi#fXppKC"V1^x}.VzF>4zҹoIb{X`ŹM Z}q 4$v ^J.Ժ, 8]^x}uq羯ց)o;V,u}5ӆ)a~ b]I[ul+zE"jjA5S^  ~wTYG;]y#$kі!D xVaˈ5$>t#/ k7A]%I)WS<ɿeۉMe\c`;[hϵkH|(/%-LRCw͝ ְbvJc9ȴ"Il>12h+saЕ$O!*F Oz#5p1PyAяKW`)i^6_hU0R{Fj0>[ .r\}_NAߥ@RSz9fԞGV0ɽJzخ i$ypNO&??Dְv6e:rp_LvS&.}̞əo|q7ܸ^cA!yuԪ2/BWXQp"٢ r*5e9k ի < "M;a yykoŧ^b;!`GQH.j m$j`,HO/&??vbְ&pdx-Oͦt8ߧʹn2#܌0;WhsӐؤE @:e4yojF:,~f^QeKۿs_6&qk WjHLaIp b}Ggzg&am1[1Lɉ$Kp"5'3ƅq&;x=%5|f#5sG]T"1H-.+|[q|٢+S/#s`L1Ѭ6iU}Q`K4U6.ί(:Ҙ17ض"%b1Z<׈5fHr`x͆0"GKk|l= 1b%'UGUG_kc{w*AM1m`%QЯgy4pS57޻:whsyv*/bz!Rw R?(Ё"@acZ&` d.i䗂CDEܶ0mH^ʱ}[pwgKNOמFcfّWqE{,x2{)m ~r>ԳM/K KJw坧oox}KI oEWAuF UM@ODTp= O 5ԇ4]o{IEvicAzLAEU%M4B[z)Q )f9>E>ìDy7v>pm!Y%ejQS#PjGX "m.2D8d&D,اC?t䨭xv7QX@nbdVL 9 hXNk刻iC`pYCY afa_|sU"v:u$c42޷\T b ,ʲ$n~S=fBYt"Gm)W> KvoBJ&[u܌az(N<=]FY5Ӕ"=҆#bKH2B&AKW)>^1ONUxTd kt2$gIХ/ *Mx_U?އg~+ɋȞ{Q-ʈ_V)~JTgIYA\UŸt#Gi {b3kΒ - {n^luYiǮ4[ݒ4Yøv#GҰ6%R(U]ZUյؠu2>qoYoک]9>Z ǠpX'-Y9!<[skW枧E>Hm14~>I(bU(>Gy#ܕ5o/IG0*/%ɺH A䲱n.r{bqUI M1mDk61*GKkQJъ-Y2`ApYo6Ey潻*Y=gU'{d{z(?"CGgY%P5$+`'5DOjXG#oiBRw$nZy[U6{@=V,9bFwѰpS%- @t!t25vzWTDyJS`W/Ugw3w5К?.r66my5b޿fߒQhLܢw;\x yR ,K2/R3HC 658{m*<_7q Cn`I`E4nG9X#Σm45 /i* Oz#ejƲsʢpQ?p6."UCK߈%aSGKim֋ ktNc^XIEnUC+ySD, 8sXZNp77 Q"^kz(I-QІ:Ox xgAX6粤XҴ!Ha_kO˟qW ;]RJjwka7avPӍe;K"n7hWyJ6*kz`lDMO-$@~ZO&h"%Vx#˰+M;\oL{KFG>=N`ud,BD׈qi(IZ,gf/^%I)W os@[h Q ? c īr0]61\~QIY_)圧o Is1_{TjZc]GFQg'&nIA&}wF=ҼcoG-!nh)2ŒS|}ҝoc,Iǹ-D[j|h*궗#Gŭz9}ϥFy$B<FiBK|+n*2_v4_c'zzCј;YreϛKQlĸ:U:M1m8&@ׂ+l#U^x}^5*zhF w)yX9ӎN& +r5"BKUC۵w)7N m\K/<^ZþGH%}Y7B+J|I?gt/WR`L!2Ry6``_ŖF[è2H>R$Ȧ@]BŎ Fd&G\cWdIXT*e}}zL:D[lKWE"\sxK> %8lChp PT~~Ҽ?syP~r#MKAj,Ŏ܍.Jzl:M)y;n.r#50W(%mAQI_zQxN)JP{i ̰$fB8&ȉnS5oLjs*A"en| ͣl԰ XI\ קՆ02,*I/:m~VS1ڒf %Z`]'1k8FM i3,45ķFX^xs_E\$ո-yr ´b٫^#TiIůp1;Jg* o"Sfxfyحh\pimՐxLRы&-tIyje3H jkPML D\,bd葩#"FT, I4*N1ak}L Va.M߼phw7uVLtZ6=60CdKCU1^x}zXԮγѢ|ݲ%.`Y1vGQ}W ,%/ۼPYm~>{m*t f>)qx.A|padd"i0ax2FmfB#KiڋTĿJ͜t=zS|H˚,i`IΛp bGKkars=oyr[PZJЂ,&b\3X?EBRTЯ: Hn7jWtIH`Uqq#D6SFsאؼ)~=˼F1 .^ QYr[ɢ`1~|d}?,q7KK2ilGi>;&LE`d"nf.HoxK<yDTU HIm\m ְC+Dy*H"a!H|äG ]Huqj ƴ3R%K}&unS W<}#/;-tZ`:mLq+8t kDCZ,ɍRp7M\ZNhD( VPnܚٞSy|?Y1j?PF\}א&HVp5[m0JU}iyQۊ{b+іe;ïōLY  Rh7 vCywy_3ELw'] SDy`0zd7 L5fH%Jjb//gb7qI~ka#Ո?rT$Ѫ!1mGn ,! Oz#ojũ:@U="tLZ`E$J2#4$ ̰KC #oj]>!ċgB⢐uw\䍌 ]l^ vs{鳓Fs`|MJ#SAwm Rb8B>M7n- 2^ Cn҆!MK1ojb!I/rL :^MnVEБ2lI7^O<c Kxk WŸ"GҰ^lw5\$?s&XZ} ,1ÒОw!3EְC{7K#^yFD @AjbvYH!4ӆx8&5\n{i : Q_qgbUqc,IDfc5nXc{i :&o%UWn ΂k~Fbm;MuU[ PT]lk{u2~[þZ1GrHLy8eDM!?AW4F̰D kj8f ְ9t⎦ ^+ :HEajvF9X0Q$!"hk V8q]CC-)A]47_A˳V%KkסA N;& ݡIg z#v6h0v M=jRq65^^xD- :tkr(iB Kt H RlPGt@ 3Q%=īc IҠƴAY^x}552 D܉L_VӪ8rc }F/G"{`L!Ig;n{i :lBhph x$Ѵ%Z\F+T$vGk ,i>Q> a\Bы~KþX+ (W:ߧdd.T-d,O9yv ƏKrpi m~;~KþfS)su"7/#]6{a.d̸T^ >Kp϶'T,;M߽) ('өVcĔGЎV=_716dm!vՆ0g,/a_Ge_m#y<#4ԕ%XSoi2|R.OAk˳۹io~yy_m0Qkqh~]CbS- SM~҉!'`_D:Ʃi1EQZLbઢ9SKzHT+! tgߴ5i~>leEgqDJDotzz =;Gdh`< (d] zMt3åNRUD*\D6W$.~8wNHGcl:xn ]J:\,kIͫM'<>ZþBtc|=78s+yJ ֱ:QI+8]1mh %#UğGҰCwyr-nڊdFn <;E%%KC;v)*GKkס"R[i'Co1jsy_+I3Mz0S:'9-$NˢxiU5%s`jHLXr@m~~Kþ{:HM JQHH<7# M8Kh /uU\7YOts]c{@+aX1۠JlDɛ=K:Zߝo]88c MH]j0jiQAvĸ a/a_{; _owM # hR'g160C4xw1^x}C #kT-nA5FөNKA_I].{xl;{9=fBeg뷲:_bx"`~+Hȿ]5z4$KC?w=kRGҰCHԮG-(7%Q0쮣m^PHU$8uW&[DHkƽZ H`_Nճ~ݘ7O儥{d2Cw##+0K-a^*qL>JUԐbW̋trCɛUVw's*^% ėU[. :K,n[u與䷡>/z.y$wM_ѓ$x7:9}ӗ~B=ɗ`5TA qF [JکL<[pH=e} i Vj zYƿ }1pJ5>n0_"jlIh+)xT~UP2ݰgKQ< {S|Zz3; TLҢr7;'~c5$>_K}6c-5먍n\|Us&.$.E/a'( F]1M t% Z%T _$G+Wav_}/^ ;% ԅpQM#k0 %@\gyAކC8 %GMln3]]peߖc I. xCLV ְ[ei0q3nh;ڔ6 q:s-"D"Ѣ~`|!%'NKw H/:L_hqv|м_4+ĩ@ [Qob1I|M1mK{(5D^A!$Ea_W5bD\猴H"X6B/[g5k) ̈?Q(УV iQIiWhpt!I/<"?(zu>vWܸwS^TNhU0=JI ƴYf-4\lcc2dyi :\prgOU,|)!%/n.jz*C?j4ʈ(pYkzd%Vĸػdg hWO^1WoZr͠&[L㩒M1mDqb q'Pm;^x}usblb׆'](D既teiHܔjI7qݢ6a_Gkw?r!t^ Tq,Cº grR R1m|~95 Wa_Ge׷2J&-IͭY0VƩ 1M`%qՆ6 Vg^n[?NG#V5U(bU5$n rG )G@Ü-dN%]X^"!h'RVY+ #Y%ڮAX6bFJv%1?49tdmq3u"W?x|v ² Hf#ņ:ufڹiM"y bObK@n f K?V1Rq F׮AX6b%x~SZ҆p̐9~[þ>5 `3XtK2Pۃ0A[#%^#Di3$iLI 6Z {u j;/.s،-% 9>B0bqdR]1m I"gՆp̐9B^}[1nO;*&;Iru"`XNEiU&&iz V]Tgg#8m߻Ezi':9G#q߻M)yjPt .V9^ZþU{U4>!%ae^7mUFnD]-U U{hԊ tGKkQ| iED>/}dOjK>Ǧ 1M(DC4m6K'<>ZU+C{C mY"xãlL./In׹̮|Ce-A}~wjK?a``_ʿ. &1mdL:pg^!zs?  ~"]Gtn|5B~17Հ9<=;+=]rDrӈ`$G ZԸQߢf5lёKL='_ޟFcQ)YzĂs:V![sW`ܜBm ŪO#0$twN•hoIĂ jِ^[@O}e$q}fjC^xD- f:>NFÑ H%rk"NĊT׀G׮6OjX xuXA+R0*.zD3B\7!W*=s*Hպ A!W(HzdlJ/n`+OݼS*\hxj+>Ic:p^py_P HЋai8gy4p2|qq=>0\ "DBW7*?^zs @دn"Ji&~B=~yvٹx\d\@HnRF:k߻P45fHrƝR]fWW,'`_Wq0E ]dFvKm3särk @2A*ȩ.Hְc71ev+%FэҬɫ7z! q]1m K:7- m6GKkx݁a+QIh@+QYpN6`izin^xD- :j{Ӊl(HDOVa_<]o! !OD{24gI+50i #5_[r'^06KrU;SFX^}W`L8Kҧ(g,OKGG+W8:шm҈4-|HRU1g!"Ԑp}%C6m#50ouKqZ8f#/o|=/W\@hDtV>H[eȒ9^oG\m4qU|?k"_SY"jL%!8 =:!U}4,|(? D Fg.JZD7#4XG׽dˡ(7rO仯w ƴ%m]sAy4 _I3SFPUAJ:/74*=X *t2"(af%ATpì F,*t==syv_M$wv4yTX)EqɅTӥ 2GGkWQHǢFtzA0՟5P|>Wű_#&+R1m`$__d/q[pzuh;`݈8_JN4*j GW%9v ƴa8K r[,/a_Gm&{1 0i{=׿"aU 0 ¥`QFV4$F))}jxʨdyi :%ko5W$g# %RuVB wHcW- `CTĸa/a_6Ͽ&|ZԏKԢ?@(! VQǮ&}$Bhj5?ўbE|JV± 0_ \ǡo C9a\7 p|]%\~BVkFwoV>g_؜y(sG8 /(ƂwhUN}Fo}giD1( {}g$>%op0Ԉ6wY#5^0bs]m/TR/u!f6]DIb ȭ4$͔$ZnICcehYi/<"?p jX!dKG"H"Ysyl .Lt4_??@Þ_7woU(%֑ DhnjvV(heD7bKsj+B#gdDbko5D9XW$hi#ᤝVNn|c|+*AMCC,o Ն0~+#5Yc!"[-bq`7t}Idq"]H1V H6 gLY.) M}L ְC^&jm#nH="*K7*Y*I$SI}iy͆N UV;g=^@Nn->Tpzy Т#䉱Uā4gI jl!3Eְҵ?0 :F`+lFjl<a[xcc JsÌǻ9B^}[b'^rX Gk ӓ42b]]D4n4ZzuԪn3?dǚ^裡4.CF| l-įɺ bddR `H,'Zz(SwYdU<چllvYBLu}#abV%ْHGR-`~.!ZlD_+^6ۈFDPjYK_Ǻu,܏ ; ^u0T6ZpjͿGZ}EџYޚټީ5.U(A}R&QlD&tǦN&P#,vnq0hȪF@4gwY{弽,HN;لbe[Vɍ0@D;7{ٴ=a~l@B"6y AeEf/a1A4k sz=h"TӀVD[A'R3 C'1h?.>~IT0! ~ չ׺-~v$]7q?=ZK|"Jvak16t{jkO儵g2g| {ع14Ϻն XX ݼιuTpቃvKAn4t!'lEdb NJ<6wzڠeB[K{دceR1LXP]Ua"q!ʚu*+%̓m,ûڠ(%_!l/RH%?P u3w xHZa> ZLUb6PtƋP_۠5 ~~VCdT¿ B+hONc=?$.{==6PCHkcmFz<bZe@I 6QƒGC8j- Rfx az`4lf*1Mu|w0m+J.* $q`;cLϳ{6/$h0g%K{دc D>k4(ID !($& <>ɻybH=.\<R]j댮Dvja =ĖچqYMcRɲxuGT4(NLE^G.KdoKwyH;#\sm^{iu{Ubh6O1Da]X/3w"̱bPʵQDp ^*;*ϔsZfUH;"r.Yjȭ,ֆl,Hڊ~~ޓ1vh]PW rR?$ gjʬe}7P(*,bN3ypwU}Ǵk];lj E J!ԝ T=Sixm*^~-#yx"mt9)Dml0 ́m6!soE@U%G;دB,b$84k6Ak8CUsP%"z6@ lL۠5z<]a.w]QJ`u[/8e ֶ X('S*1;Lxces" a[k:,AF*VlJҰ0%`AAyH` DvcAi [Wf^ OF"+XopVH7tL5=fD8dyhuo3{Kys#)?Π~9#̣9A<=AըI]/SC}`m`3FHG Ԓ Q}߳"1uP.wD3H$RawR ?xW5sDgzeo{p pd]gftGW8㤻*(K_s9 ,}/·t\W  {)>=E~ #ϋzFW 8_W䵟b gVA!9!脀G:{0bx"+պ(<5fJFxHla!L,8FYq5~\i}?ٮNg΃7њ"{&T*HD iD0VjaftP ژ*(eg(Ԋ+#} o}$旹BֿMVz4ϮGRٰ Wx d0g\FN b}1K#*cEjkll tN:6h#PDp ЗWphdPij-@mFrk杦NѼ w~9&=#|lrOd9D!84 GSͿS,ۦpwNU?4q[_UrtM\$vXP#v_Ab뎃wd 0NޛcEfa oJp)dswE,'f_mU,D7iN'XmVT^~'՚E~p RՇ; #1OoW٬ocrM1UsQ-{[ "9&Ҙ}\DpRlۏ m+Rw% '-顴bIBwr_} FZJ{sMQ }2EK7HDvik71E])1EYlvK_Jk`d"*`lCؗ 2{)#v:XO@ f/ƒsqc<>Qmt~3gZ6Ul^w\}:qhNBBwhF/3?j_Ο3Ճm-9ḡґmЀuJdu8)&G-v##\s5 ";JLXL m3bV3;zm_ʹMa{ȭj-6b&]+}<,ae#cimC6סYN+ߤ+޶YEP'(-Pmҽ2e@YՊ1;U{ 80QF-޷2M;8-trb@V;miTMVusn/S{/#X`ΣNT"dcKiLw=fro㷵Ap XBi)6Zcܸ3Sdw)-e֖ϵ9PAHÂ{:gv%G{دBo'#l>֎?q*־ ptqB*V QLKŌ ߟsn[80lzh,abm t7)NhBaoP<=kHa5myH۪͉L߰!^d 0[xi3%}q6G@8>v׏ԘgISgEԟ)@P\b>5[@},[ڱ_L$"^e!+̵m3DzhP.aby/\c?W5̽:UPn)Ԕ= 1#Es({IvFRz/%{`mnOqf!Ep/au$ !W`.HNWvQ $l> \=6yYaԽ ڊG/T"{)c}iuѭ8uDb8mGgZ,6zJ|fzvZ"!f題 Jd/u)~{$JP$r6>GupH1$Dx/Ŭ1VeVi%ҙ<<=Śp >3usxk4-P$!6S(B)U."#%!AJd/uh.`xDyovcu8LI>adv7O0Иmc%_j%Xg9$Rޕ H,>w@5]b2uJl]%ڳ{6N!;jY:VFמ:eMq`J: ˰ @$Jβsfurn]f/^ˌl?{##$iV"zATPW6RۇCo'Bc{Oڐ {%_ǚ"c'y:L-m R aڇ'FY 3\C{Ӣ.^ßJR^E럎dVȍ>aC߱FjR#ƛ,q݃meø6hk}Af/a-~k~crbBw7#~[!k?!D&AQ, Yߦ Dfuq?P\L}F#[ fa/6,'H Rs<6y)P!3r6\'CC Ra21y NV]&c&I`<d64JyP\}~H0V{KAQ"7bn7Ȏ Pӳ+fl}pd"Hp}O oo׳Mqf'bB&xJ*Hj@K;&㕧Y"tVi9QLcmЎK_.sؽFOd]cul{ogpBK]؇la='Gdk6va p/a}W1ʰ@D,zS2LcO ô2yR\qmFzKys8F]i@$׺QfJFB4!V,@iZ]&cx%PoU.ib]@sMhsL!+SRNymmbhG~X{HauP.lCDtVn1gZ۠-Y-uɖ"mAVA*yT*0cYmsnm9 |Ӳz@[Ìj]v\{鴔7eluÒY 6Cа;m 2l0)]6h?.^~u-dJ~h~]ӸQq8V[RiKs%#2VCmָ Ku,\Px)d \xS QY$,_C) !Vm=>}oȵHsr3tH܅F,!sΝdV=Vmd lnTz5چlY {-Ur9+f| ?;fmޏR rX9M &ozI,q޻l5@+=چ쨡^dL1 R}% B񄭍nx6P NDZAaK_~Efb>T@U;9Ā(t8j"b.q=ۇ(94-mzezدChPGqO5Jm]ƍL3 ARA/"5b7i 1RsC,6hc^{iux1ąCPő "3xFځ) b30*J;)Zz{6ڝֆl,D/muQv:F3}&fU9/Պ>V[&|='[Wz*#te.fL}}|icЬ+Rrz6PCȀ0 J.^~Yo'x b]]‰9F %5 9|{ReVI59ݟ{Dj6ꝫo&VbX-el0oj8xA bp8@ lg"f=Y^{iu!\w~)Y2~')73d B 2w!+"56j!Ε ZنlEpaK!ˠ^{eL8S a Ɯf{#ȉlQi[/=C{`AsotJd/uD1&1R8u'eZOۧ@ 9ϬS^@yݽSI %h}"1BR5^\.Nƽ"u}`(pqt^D[03/` T$GRnZ VA #|Ⱦ~(jcx%{6 2W9 p/aU7c|Lx HFȊ4ĥLɬLj>H]AP_&de+tBDbNf౳^V+E)F\V C&RB!B 6h?.^~k:Cj/1VB}@ )iap-8W˵ֵY4: zN0iggX|S)Q˨ä$ z5T&-sc]'$*1݃m54CnmȎEP/~\9 KC]Ŕ&;B'y0 L:uϖsEj!m/EqamQ{%K{دcKHΡwfbSupg Sq059~er6FH<>=k yVd<ױ3OlȏJy0Ƭ3.À~;mly{HhN$R!f6h?.^~^#fȈ0'ey vDuNDxYJevP"[PvmC=ױ잓rw/ P:rڋחe꧍3xZ!mLD"׽ ء+2{4uFVNȋR WK2Id4o1$%{ݟ 5JHJ 5R/D[0+Yr.`7ahFS0/#f" ̓;\Zؼbڐd/{iuX m5csB'r+䜹 k(Ym&>rndTC?6hcS<К1{ @̉ ~"L4se^vنr35= 6dKcAa`8a}|>9`ޠsIW@BruSD|c'[ZJT%ۇB3\{fiC6^Q%fu801OZSyHs1hwv|ﯲ"56j98됇z ٚ\R"-uhTl%iajs'#ADt3LFxkV!({eX&VVG]ߨ418]ŭe Yf_kKwBtNC{_UWdXc*:@rDEgsNqVYxDJ Dnc T'fWSF7 haBc-!CJ"@ 1Áu6Vث%{6a{J6dG "Kda?׏(K34̵bz`\!1"w!Lc==Ap Xk05n΂ dLy] xA0K_=V)vf\ې9 {:t_j|:NᄠrɎ/(?Giٟ%α{6p|#D-!d$6hcOp XX?IJ`x+ӝ480y'S tY݃aFsKdak8$'rstB/]E{S-m)qxm|q[A8`/zMܮ CpA2D1!(5ߏY6f A̓ۋDޕm.^~NY:6ZwAj;+#8%BTXMPK=l"ǩ/4=T~MK"K_zܮ %vVfD x҈p6<9'Y9ӭ挈Ϭ];_7쿣Ow;ūJ]#U3DZQ,ܖ5VƦvqf"c-Ӄ4ɳњ p/ar v3D S( %d n=bjKm'?ZY}GQ[k}K3^7Uu0Egpc.S]kwU!ւ )OKbRs(ۙ1xe̩8$ p'`2gF΅QO|%Bt7G'y(l?+Qpu`-|?Rb6A;j.>~"@&EBW;4ؚh4SJڲ&TBJ6~&WC{ %K{دctQ!; R.*G螴%"8+R7Nn pˤoM`7δoH]wW&l' CIJ gvl'I)ⳍ4^{iu8'L=HG\ES~5Kf\L6$PNU}y;;vIS&]i݌LmdM/kk)1ūۙ;IAp-~f\}*KqqZ܌|7C ܜ5~> #@eڨ t=Jx(jzi~?ټι{-sAq^ҡԢ&Y`\[u-5 HRkW+ }Uޚ4YKZԒ!,RdD [{3c.Ba6@P{kCvP/{iuh\~-d~$:%CK=m[Ԃ@n6~&ҐyzҽAP</@'V{4zæt^%륐1 heEȾyݴ?hzmЎK_6Sfn~yB]K[:AjMD h82Wxq\u=>ek~[uB _FdƎZp)OD4]G !h3Ҏ+"pq؅ M۠M;vG;دB;sJG.nH1$NmH 3M3Քd KԱ{6) 1𶵵AP7KȾuw`M|?q᝞JdUxH] (S<09b9WClY1m.?ױ P[ 24 FS> 5fg_拚@2ۤ1Lx]s<(?- OEGMmAZ+I dF^e1GGǹVOhKѸgꡫ~]s[1N({Fhb3+vu ՗8'= -$t/m*@Apꖺ-~ݬ^5\*x U^fNV HQ$MS/ >ӔBuYj2u[WD[9prDb5S#i}2b4#2jۤg"Y?NhG %A{/A%c1%+IL(] d ,?*ή/.&bI!u.˪ՃmB˸Οm- p/aU>Yv>T#Į:qa=NUUett`8^9LJ^${Z=VDnL.[c}^d [\Ƕx wdz b@OF4Bdv@fF\QbxCڎH$$jOz׹!;jY½:|N04gS"VLߩΎX>Ō/)&~zJ*B$ks M.^eW k Ҋ"*|cxĺpڈ\%"J{&"@نef/\½:$Rہ gRHpQbۯŮA+PcG+R#w [mD #1LܔjB6hDp` }| tM+BW}?[yRJXsVoHjLp 8P/\"-uׇi[t ͋ED.V0cy -I,6Rx>!&k{=ױ Kr/kwrk(9pG,܉t\j;SBnC ::mu' 5vImPUWko)|} wif} eWC?66 p/aMܪG:F{t-)UR.@ b+P.]=f $ŊYې^:H3h ]β 1[rOƈ[(b^ 1<_g=&Ұ0]^۠5 p/a ))k. H,i wfwgƞ"O=aHfz`lÑ.^~+C;I[*xd(H>w}'µ`Z @=U`]\コm6BqOQ};mE-쟪5^AOI;*T_+g(ف/ :a96h3{OKz{(.DyGy?NJY=Fo_='ϵ.%K{دc=cvLUC']~=dҷxOEYI!$!8}p 4lC5)Co.C-<=s ;(9!y\P{o6 p/a WȉΨԮTOePu{4/%r!gmD"C6mcEux6@16hV/N%^p/O%fدcuEKh=zx.8*7sc ۘ /v$:w /p{ک^{iu8Pf2p%'Xg@ނ@t`{(A~졷 E/\"-uG`@UOő,D*%)oؖ8~LTBn&ּn^@⮍ζQc.8VPOzD: 'knl2ݐPi>0ط0m gıFl*B..Ty؍B;\6K"ZԿ;(t/<M~ D7'~y3XS $)\AVaWp@*׎L`ʡ_)~)K$FfrVe0~  9(nVKR 7ߩL^`gA3 ),^W) H׃U:a𱎩̷j hETEˡf=sD:C>ޗ UEXQW#G}GE!y 4xnv*~J#6_(G5GCy 0# ChmPEBr7U5mЌ5tq񻻮҃~hřJL~$S?̭пtE9~"*gʪuG*lݛ黥ʋt de/ DF0@i ÓXVpMC͚,"?LCȣ!?'߆99UՈ*3ӸADx"py棁!6!ok&4_Ŧ.XGO6xv 3 |ZQl^N{c1(؟_3AnpaT$U]nqM_@usX={XH|?1~F@x/2|."OLp0rrF.jU-Px4Hc b%ykKB&/6;$!rm9Zkj\DU\<~"v ъsdŷsNojsX躁oWhLr9p0 <t+l1W(\F6ugޯŭG/\]ݷAk8Գ?OhY)XUGED9Fp2gx"? `c ?S+XDך7b ;^88Z}`<ݝЯ{2h>Wbz+):M<%[rzeM($HQ'gi ĦpZ[i=ٱ64фVZ5?n 8 {0po( p"H`bJ)OOX>#sB$KӻX۵[~>ΊtCp \.<\0K4ZGHRȣsPu> rz,+6 b_Z55Q(Ds'eO\;2!Jz| xB@M);8_ e.y~ڹC?/R|ѫđ xz_l~\rx= @Z s"ztH}\x2[)?R/0xpT9FKr;im׶Caj!ѹG E3} < 1\H r!-!mc@p2"M?] (R@{R4Am|b SLGym[]D76lG5b5ȥj{DqU(V1BѸUr*En#ga<~NMܪ[ZDPl 9\원[}1:NE82+E[0ܨHҨwھZJ~ܭqEDPTkݕuS~Q@'b!H v-~"d0ó?p]s,+'* U}+@!8MӞX&h4 |G"J&?&@[@x'X]k8YL>{:@:ZZg"? @kˍ8}sxr7k3/"-V*̼k/N9xHh;V`jbQDCe}C3< @&D<#k/E^{G*|JCr4QJS C@pQш$r4#\fG'Gw Z>lV=$OL|r8fO1s=5BU\R懨-̇]Q?pc ;];Тpp7a0q[)VqmW0Ly.C_D*dt~Z<3R!.9Az*c\$/uQ:Ԏq2Wssp>^ג#r9%9u|uo%dzRP.[`-*)6I/ RK\y/{>5(Z3|Xyj09} cK+Ю2^ˣ5scy;o=l-ї|8b.?9l[v>ؠ(.;J^w2nT85>Ӫz/~"wM8hƈj=<^7׽ Vt04F#]MgFR!1s"9Bp#Z.jٗP|,.<͵. 1HLmR0=%5-8IwΛv_0\~x 7Zu3&rCp +K=r#(&spHaJ]2'-pkݛSRZSfhF>&jd"/r]߯74YkuN"VW98t-riYvN{9{=nE-7u~n>al'[zddn(BOڙYN!*g@S2mE_@({kPį"qpo"xҩ+Hq#\uAA89/S5KV-6/ʣ<|cU5<LAka'G:Ɵ1*r|` _뼤uIҜ,"9';ߚn ǣ@i=ߧSk ⬾85(i8FY`DEBs7Qp#)t5B'%vh:&d0Y| F>G^i*[Oi _R||]e J8Fт傚Yqo#$uv+H;~2\BB,>2>:S"iݥѴ"K#p !btEH O@V_{r>KbR)~O sgt^T"rON#|Þ<UBEȀj-Djpj#>.dXjYL$ d[s4r5 >@F_Bw \z?F:ȗv"hs}V~p@=T)Z=*_.H"JF#ɘϿF}2967̸'|۞-//ڝgċvTb4+-l-/UÊEy AFhwvZ T7 G~A{d>D xT^r԰vCV} u {߁4dQ6)y JA$fHGVM#t]$ -*:-de"`2r=#EvF8'̭ @&_ C2,$kΠޮ EV32c=GAVҨx+NTngTAzAv;'k qI Dxzxl9$Ι%@qN" $(˱9afvv<lg K{u9i6tb@J UQycѩy)´XcAnd;4>mXdaC>ɱC7q,&H1n;/`,rC x8 x4!yS=>L_Df4dFQ/@ uLs0д^DstZgb!POSuUH߁Y$.265MvurL8@F㑐 3G*MYz*8bg2b䊘LW[1V_1wnqp 8t>$~DPu#Eםȩ|3ԅ [ͦh +_E "US_. h"k2(׎x omDxZ] Zs! x<"ν%Zq+w"[]-5_ ŝH|L>v!)Xu9>05obaH t61ă% 淑a">݁ļDf$~ŽALEC|LH2VL2ea kRu _&Z_&JIMJX!v(yu c@\5u`O_ Po'1gyGHeۈPĨu,x 6 $޲$@ޡ4)` Ar@|x~DC< ӝ:-'!+c$xԓZ-x8_Lo/"Y-"`C{axF.8M)/ѽ[dx0ҤoIaGvxX< 5#u^|2EoNxL=9㸏,rr[<'3ކ? :e2gEgq_DJsM'Q8/Cq!3H&gKT39+qƑwUI̔2C$4rd9$syH8 g)93"Cc8露'M4Ͳ*?B⌿)CDq_kpg9X'gE c%IsWqEfH_TL+q_!e|(&x R_[JKR_ ]rcRƱ,W8VnlR!HyaLGSq WYYq,#+ 8rK[oW8.ƑUH["#x c ?)Ma#%28}"3Å~Ž8ꝏn0 _".SkJő{?(I_#=Wu⋿HRߑ⋷Pڿ_E$_ȇQ|qX|/"/)28b>/4aE0aVJJonAcCrW׊/ |_l\./8>"cN=<&_NO|q+bup1;$_E-8v!EJ$_L5{$בtqlo-=QǾ坷<:UeF- YQpq_4Zšs\`[{O;e8LU&_؊M']EG\JAˆ.AϺű^W8Wx~(~ˇ0o߈íd6BW'UEC*[}*#e ᜻3BLIvȓb;Sۿ$S 08'qLqL$@8Wx$#-$("%څgSY*8,Lqfc{2ELL1< LzIQT]Ir-덻^ϋbqqC8r'cljNGIdqLBQ^G.0 btv< 8\q$ճD8#%@xw"8a;Q'89E9xO﬉*ݶl$UUrZms1#y\z9\dq 8v!u( x"8Οϕ,yW$#q-FwW{<_U'>^[)%<&ὨY$дga)>?nd19Gxȁǒob=+RS0Tq$jVP+)>Af^3ŏ|a&G 8i"G:#x&Q|(!X(.cFDi 4S<%?LhixUꮛݑafgɣ%E3g⁈'xC1bGHɂ/"S# gc|*xFș)XE)>i@f?xn$EXdUe ?txUNx z W'ФSIA4qEjAx W/G'|PgI<@n!Ot##ŦmD 4JOuGH) Q0QnQN.Wܦ,@s'E<IlFnohU@Ee))j'G<=+Uqÿ IhK<YⳖX+@\# "I\,I6Kw>Ywr!L}Qb/_K|L.e %>+%-i&M<Ǜ"2M|&'~y ≟ xzO䉟W^x\n259Xcy4[Z<%O<{I?O+\(~0&OrkjBDq3%O<)'~N.xaxNk'O<ȭ;O|ueYV⇙'Ѳt`mRϤԚ*!޺ӏ-SgL_heS}Ny莚\9<Л*>;Sk䤊ǓC@*b)>I30S|)#RFL;0d6SL&/MJsDIZ^$O'\Ys[YmAk<I͓K=)~{&wJ(*~_f*~vJ~tgdXSş2?O̘*I ?p$1_g'l㠎gRş+ ݢ|Rş;?G^pQ#T{ʮym5Uګ~dC&8 x8Y0f6S-d0}dR6xh=SLqQK*u*#,9*iJI|Nr#dю%DHsyi=<Ҋ,>LZ]Kv6P%Mm:y" YLEőIE{Cx(xĥhY<*xD$z}XȐh qMٖFoS\2G֘b4%z4yr#Frd]ID`1^ NDk.^rDЄӣWtLDCmss[uMheO[b:@~WV1[<>/ylx ks~#7k+8u\rl3[yK6Bf8"$JI"[| -Jߓ$ Zotr,~]'_yuz-&S<񥖶ʤ'^2<ŏxXD<O<+YUHУyŗDqД1Ma/Z OIEOgo*vNf8q;H_>Kb3q[a^b:[d!9 RIb- ]wWvr]%itt3yr6PqY ңbaH@2U ⚎.s!*BNzV\~DʊŨtzIEϊ*9X\)(+. GBME w%22yB Nu ]ͦ V\gn΁pZ:)~g6:,fj`eFjPpT Heeb8>c3a~'&,IUܣdo,.b*>]+Sz~,!/e"cu[Tٶw}i@aBvml#%[u7 zF`%=ŒWqߺ3Bbn3V9Я hqYgNn$wb̌ ,zQ)equtLTHa +{P(G&Tp|\qcL% ]l dw:5TwpsRBW(д·eGu2MYqA58[._"=584 e0uc&HqH,ى@( .3L &.ft Z~ L;"&mA]5ˌ#7{׈PL}0JVJcgT|^mv93s}xH\CrY$"kN Ck8/y68q N,cKdI9өn>N\D-p3K8Kö1CkrِtT?9X}LJ* "*+.ц++jcfHsv'|sQhd]xb*[U|Zj)mYqK42[rV07OQ'UwTFј,Nnacf%EʊNŗf*K7亂 o-K#1th[XF%>Gy<' )ic\H!lQ&w)"dr [wD( gnl`'r1 #ȄĢ*D W N)-A-rx]EUd9ET ȩ0-Y%ŒE%RQ82& z0 j찉E EĻٯ*$X{f '&>RX45-;>`daFՋ b$DŽpXD d5FL' 0X)QcRq\fN pXA&Cá!N\i"+^p\}WwW0x5:!:-%X8&â t^4/`;g%Y˅Wя)v^>y-k6/Y@Ӽr̸ܵ2M3u?^9d鳰[ $TMr˄9ui^n y2m*v >%HtNf y2 ;Y25ɛ.-i^n yy{5K+S1ҧ,iv4/^{4EC+Sgz[Bu^nB.x3aB>_ϾXG^7O;/hY{eD b AץW~trcE}8&}c4*w ?(MDcTƒ/˨Ҳh˅Vڰc," 8+0JgehClo1H17_zRZJQ *ᡕQt3uWﮘJ+I󊆻QOgDާ݇J_ͯ_;9 :x1I?/|\=92O;@!y\.8 }ڝϜ;yLNj(i*\"v)jiHO6m dH9p9~1.ʓ26.'sYs.hCf-7-=U#ѩ|js_h#74[>dij>OPeOΐ:R?<$oxv8[^pK XrKxz "C_H75xՋm/vs)2?R{sBO(L链PXmuCWorڅwp;oEj͕ԋGk>+\{@mI0]oXWF᫏&YڣR]c.e/ hT5>>;/?TnFR>awێ=LKnmҪz ]exؤiG蹃l@D߱7Mh{!>Wf ͆oDHDF.ge=%%/^aͳHDG'ӞKO r]DZh27zfSӖ#QKO;Il6u=p"mZtиõeL^V1\ RGвqnM|*u`2)[R|endstream endobj 456 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 833 >> stream x}mLSgǟ}v1L\dD 8t*`Bqo}b%*`i7KȖc&.71Kf,ė-6 ^rΗ?IAʊJq+)VxY HgfB֓ly&TlMæ-:BHVZSOH!)"omLD-$$d Ӛ,_N25/n%gE7"V<Α.c,Ycz#ՑCCUPڪ>,^RF ,vAX/fL,TK!OdOf.[wZ*u52d. K=jmkl)q/8x3n乛M|U@م ԞG,$.;^ 2 uv4> stream xYK/$/ F0♜TveǪTÕ83%q>  5[j# ϯn[ .axp B,~yXhg4*^?Ż f-rs˥Ԓ{Y,1\i?|SWkBUmGlo`ycx |FsǪjD'!7fJ|sX)/${ZϠEIv+ W;w/$Y9|}~j-a6hzPk)y0Flݹק/uߞʲ(fVk)Tn+A,1Mۿi]d!,k?kQnV@8%tWU<0J!xMoN/hmo I/vڽ_1h⦝Wjn ofs[:9%n 䎀ڞnH Kڱ ~dfߴ``?܄B:8qSB9vAVO͡%!h˞ rl \*) @37 mݽA $%wlq=m=UmzhBZBnOMW`dX@*IYǃpAO2><ȐkCn#(2T/}D7޳=TewC)M>R4FJi\)(E4rgcu|f򏠹l3X'/)X f+PIk̰,d@$(Rf£p؎Xb_FKx@CzJ|C;mL}e}/d0)L)i H^@MR!o~Jyrb*F"q'OcU3 #bM,o-r T'j.,BYd8OB:㒒XʎrG:z<:`ɅbrGwJ @R ɭ={B<.̒-e@ID]>nFYM$ֹWyK3])$J((+hX,ßp!ɶ7PmQ@5-q0OY^JlvdsWX;ĝSi PE)ӊN 10Ftc"eWsQ STS(Jm.Q lrpfDNUhS(u?.$t Ϫfݩ>v5@fsq}Z)fPDi J10}'1w/CWW1aW%'7%ha3rD42>Vĸ(%."XIf񅋘6' \ hۜ|!NYi+3kq蚼}_\~b}ϧIѿ d4ΘPP3$tH9,aKc( : #Dz w00vt p6dt 7?tEcD;8PR?EJV_G(g5ͅ˶J 35GɣkWݕ@TqCO$1{UG i[ K_(b,`R6Ш*q)2d ȗxĀȁ9K&bҮ1ۜP_e-d4 Щ+u`KTJ5ڮ]"D #k*&XlvNriX[M-NR=y*RIM?\ CD3"XBDuav.) %_\th.pWS4q84+pb (Ό9|)2QĴasz2^$ӿAQm)dh0]xpWãS3<"{'=Ārs!Pҁ{ޏ>t#R?ۥ.`m]czXX`qݾ;jave_/}7QFNrdP{D9$IG_nH$<&84+i w²OlT1:4{/IqZendstream endobj 458 0 obj << /Filter /FlateDecode /Length 346 >> stream x]1n@E{76P$\eLR+=}:_c-el>g+vb.>/O♯TTf =ZYGգnSmnҾRaCMx4:1!n:9ZbĄ̎mb#z5w*1!B!R#FBFt%+]Hh%n%11(#.^$~`V N$>`D VV?N  An8WU:;+ A$NƯ'eϳ K8yD_){cendstream endobj 459 0 obj << /Filter /FlateDecode /Subtype /Type1C /Length 3799 >> stream xW tUU$h e?k_qf\DBl@tWuӷ;5(DDJ1"pa9:ۼn8gs;ݧtu{o"b hhSǍ1:'&] Êw莲Lo۬FU6Տ6 Ca[drJg5sk[?æѿ(1OTybNO,! fcăClKCx`X v /YNCo]ta3zkɭ);;|7_A>"n-|:\oɗi4_WTX=DFR,+Jv*jV4i 85g^z) 9z C* HCjuZJc41&0!yKns' *:m:{FXjJQ%Y&6U\᲻`L6[lE,*LvR t=^ &c.ЇOe٢cP@1r枑(HŢKAC!U=$P#ߊ%+DAtSg\O >4'KOS?d,:ΖHohbv3 *] }T\ԘagRڠ]V!ȿ|" _L"X)L]4u"f.;w,  EljCo]:0~ 69l̯]~aF.z%?jJ`i2K3镢 ⩤hϢ9#p#χ ,}ʏZIN {Żƌ[-`s8Bm\X[E*^&Y4 I}crv5F /vnX^*K-EbTv@ݬAxoΩ1ϑfVΝ ƛ6.}?3 [ލf% ]&;-x PjL6>z\T!M;<^Gј#&ݞt3aD$54DzTw~fּڥBC=姳(I#y7ۿA#ypVm+V X|)gϡns'92e3m̆HRCGރX;9gLcr!\RN=I}VZ(EHl_q2"tq_ndh| S1 |ӎRg/Ȇ.-(z9c!_\XW< zLdZp;8cMU*ՖTgQ6[~eUx%$b3 띊x}תæ?|bLJӪdK c2A2aq%L_5,ȴ-Qˤb/]8=^~t MΕJ-)WRoObaz>[}=r@<0 ۶_ M-# U+qbh6 6-{Z`UQu$S--,K~OfO/^Lc&O\Feˆ>e%5a:ZC.ޭ4Z6,亸Nc)'l D;{?HA [9J]IcHƊp%>F>( ,Ubl1c1bv%cr>`NꡦY\P<%ʹFjNVsWޯqC9 !A2^zٛDd}O!/n>_xƎ*eKŢBLl+SvQWmG gҚV]1"c}@3 *Y+ `P?|/PHhpꡞ9?ea>}ևtgԓ2C0æ9h n܁¶Eŷ*> mh@l.LG>$gtY=fۏr` MBӶc # Nc.?g6q٢%uNxˮ{uAj>!wߏE J<ǻ1*-:Red5ڵp"<]%?}O,XPy5cvAQ KN_.*M@kfk  Slq@ ;eQHÉN9>ph_ꕴŤ2~mTg,LOÓ~KkE}#9{{&2]ж!ʹR >[V8*|`a~.nR{l31>;^ ls5]Nj ]١om %@~̆#A65pK1eifO(:T R1 w::Wjm\KՔ@YVo rEA I?p8f9#A',Aa0j.Q֮gм7ְC/gQm50 yM,Sr }XB$N ~Z6y2Vov1m {=ܾ3ټO}V>x(xk?1#1 bP\>4mWbՒ p&a>=eqj"uWM2 ތ`x+>͗<*QVNt6ɣ4HZy>pmNVÛLxEi>-fb{LB qR~4o<.!VmbE^Cr2aHG;OX\V'0tlJZ\q?[F䏧S.Oy{$}}}mk4e!!eikk{Kf]Rۜ{:sz[qf&P`šղSJʖFϸGޞZ_%w-k%f`K|ZBNJEzc[ x8|VCIz]|6 aB:̯J` %&=Ae5~7X r("1EkҙRO+Df^UQ%fhw\AC#/bG咍fku1;js@%Dո> stream x-ohu/mWәZWHt J R;VQ 2lELfM&=55^\J[:_(7{+ay)H_ ^Zy>&3LoLڙl'ك tkPWg^VD~ԇuL`zܳ.0}<66:DqpO;Ĥt9=xSiHed$ ;:'|tIߌ306 a#Xv°u;<{#M}d~j 64T1o<\˹L2E\ExMgWA-KC鞼S0j!)!DaCb\ `% (T#"T4ɧMO},@uX:ZCMfA8ͅ,IͦzǪiX@6|Qm!Qn)PHa#fJ=NOmp)Eq[^᪜$dyp9cRU$\JԟXSp`kT˴=x\"\=_\7 4ct[kÚqq0ǒ)M_dF2jXIBEA^Q{y}DcEC@c߀glF;qTR@A1_)˹2 wM>n( U'Ƞ\>Z׬zIgQjvG)j_mmqx޶"2S.cyEA6BO+&zZX[D-@QX3jEpazө,KP,ST> stream xcd`ab`dddu 21H3a!#kc7s7G ~"Ș[_PYQ`hii`d``ZXX('gT*hdX뗗%i(gd(((%*"s JKR|SR Yt8۽ǒ3~t:{} 9w>$:ut=6t.Աk/Tvkp=ol-b>sd[yxTqQendstream endobj 462 0 obj << /Filter /FlateDecode /Length 4592 >> stream x[[ȕ~_A8ndcc] Zbw3)mwNْadUwNU~D!3ANW.x=ֺ"+ C7>"5 ;6g~`+"?Be\%^d&mj6s޸m?L:Pf< SդblEM0Gu9&WO\ژAv5y0y󏎖 XM$,$#wPZ\Hy4l#HEY85 6DBB|2 U2|㞜҉"Zn'A TtfnղG@'5\X;HYD|(P&KH? jvwćle&ꀱErf\f(׏.#]0>DuDrg?7{uԥƣjW6qI qU]f\8W) l`2*BY.\UzoDŝ b v@C^(]YU8TeU.-RVm utE,GG pH7:@C)cz?_Me Lw0@y??TllO|Wu߬:/y8l-3ep7 ]LatwP~@Gph ήKlPٛJ);D0nEQzm76:{n}=U!PAK :%V`A囻DB~=yPDSGۻkE 2PP6 VZd;1 MɵwXג  'M;t\VVn]Վ#-|XG?\^6_W6|{7!kidLėU}{GbpuU_J~zDipPI]zG֩wRd8P8i+,d8 JS)}ϿI|^/I]ݨzٲ t."\juSmnm;MĽ\c[d0xjQM.j&^*&Xr/;Z_r}WC/'퓦qSIc T$H m /՛܇Q${20l>rInf[\bo3zhRJ^" L(j>ky7Xb^OH2E*qP'@(VM5#T›-Omp{ju^A9,zSMVrz5Ϳ!W[c<ۻ0&+A81iʓ(a|MzaBtMar- UiIBC$Ȥv Jx{4tQ(sԑFxއ&ě֊nB&䚎5j(@';ߜ_`fr( IqZ"1Xq\ǰ-`e;ZoE9'ܱmta@:D*˹NTC@bΰBaÊlyV`LxVMCyE9ehz8n^&.t@`X*;6C޵+i4 c $T4ۃ(})Uv[bm>tpP.,Eɺ}?]}Tͧľ7Ē~>}jfU?!TZ3Bo`@- t *XOX oRp:ɧu3{-Z=J(Q9y־d4qaͿ }Mte;lg,NfٿÉh~MlDǹbzH,9]%W'9=NAExp6M!jiqgH\"FyFrF)Uxc˺͗noƲb)P/y?\&EZ¶G?K&$ݐjbMyJx:Tx}@R­i EvRZຳtWOTQۦLdF4Jw JeOAvF`<4K)׶a>ܙz񺚽ɳf5N PN.9>-qYe7JRXn8 BiΈ/(t<*aƈ,bG)FX5xS@єqFQ(Ō4*I.sQ{#"(r1FlA1wF g#}]R2@3jBETD|ZfLgL1j 4U Epsb3th5ƨZ #I$׹QJ'I* =#D\ÂO7`cĤ(F*'݆8JLp5"IL!JDI,]BTv"d^FƉP*:eP:;Ò(Y1bɎQ dqV{\.9t4S`q율FR# o{lsREOHt;FTc`M16St>YQ#OGjX` 5΁>xFTjRQ-]Ir8xFO,$:sRN@-XΈ괥(FYIp`S#ω'"SFա!ۉQK6 )yTիHaT}T%T8Dsʢq%Tb+:"kAOERqzNRiF G:`ϐ/N9AIB|E2B20$iڗJmDxt8"[Q;n'Nw$XZ1dxllOH#J[g~M U%=z#LtSUFFِtkϧR?7k:57q'wttKFxQ|S=v_"קşq\rUM{TbyIwu|ZVE$Up=|)r}'iQlmE)Y)BPIE4 |g~IOoɯ*\V_XZ6B5CasIm_ׯ;~r01UkB-= +/~-Td\rbIXc 9u>/tbH8*oF): 2,hWb kG|cOk,Iy6HۙUkSOBC7W42s|x;B@jr?]e匿e7 S4^<:߿t|OH?nCKEWts'N:-cD  (tBjy RpXmÃ<jjY|^vm;ie{ovYJ:;|Lj|O'~q=3?\+<}T/ՂI0 ut-/[${ǀkع(]]giOfQhH:푚^>7_? "*,H]PQ{([/A/Np>-C6 Li/0y&:Bf~t컛*~tO33`䆀 2gLv&(_nendstream endobj 463 0 obj << /Type /XRef /Length 336 /Filter /FlateDecode /DecodeParms << /Columns 5 /Predictor 12 >> /W [ 1 3 1 ] /Info 3 0 R /Root 2 0 R /Size 464 /ID [<6c14cf8161e1d4021994aeddb6565ab1>] >> stream x햿/CQϽ-m1a1I1t1 j5,!Z.Dbbb|wu>1Ƈ_U&C-+E%"jR6?gxVsm~,+Kd_)ɲS㉝,fzDʒغ,6|̓bI-JgX' >ԧ{<Ԫ6137nb,ksw)tn̙Awp'҂!nbTbL΋ۼ1=bnGSK'guS9y}`>E endstream endobj startxref 933973 %%EOF dimRed/inst/CITATION0000644000176200001440000000105313371631672013600 0ustar liggesusersbibentry(bibtype = "Article", author = c(person("Guido", "Kraemer"), person("Markus", "Reichstein"), person("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))