pax_global_header00006660000000000000000000000064142051430270014510gustar00rootroot0000000000000052 comment=f22536ce535656db61b8c46a1a580519550ed734 leidenalg-0.8.9/000077500000000000000000000000001420514302700134525ustar00rootroot00000000000000leidenalg-0.8.9/.gitattributes000066400000000000000000000000511420514302700163410ustar00rootroot00000000000000* text=auto src/_version.py export-subst leidenalg-0.8.9/.github/000077500000000000000000000000001420514302700150125ustar00rootroot00000000000000leidenalg-0.8.9/.github/workflows/000077500000000000000000000000001420514302700170475ustar00rootroot00000000000000leidenalg-0.8.9/.github/workflows/build.yml000066400000000000000000000117651420514302700207030ustar00rootroot00000000000000name: Build and test, upload to PyPI on release on: push: branches: - master tags: - '*' pull_request: branches: - master env: CIBW_TEST_REQUIRES: ddt CIBW_TEST_COMMAND: "cd {project} && python -m unittest -v" CIBW_SKIP: "cp27-* pp27-* cp35-*" jobs: build_wheel_linux: name: Build wheels on Linux (${{ matrix.wheel_arch }}) runs-on: ubuntu-20.04 strategy: matrix: wheel_arch: [x86_64, i686] steps: - uses: actions/checkout@v2 with: submodules: true fetch-depth: 0 - uses: actions/setup-python@v2 name: Install Python with: python-version: '3.8' - name: Build wheels uses: joerick/cibuildwheel@v1.10.0 env: CIBW_BEFORE_BUILD: "yum install -y flex bison && pip install cmake && python setup.py build_c_core" CIBW_BUILD: "*-manylinux_${{ matrix.wheel_arch }}" - uses: actions/upload-artifact@v2 with: path: ./wheelhouse/*.whl build_wheel_macos: name: Build wheels on macOS runs-on: macos-10.15 steps: - uses: actions/checkout@v2 with: submodules: true fetch-depth: 0 - name: Cache installed C core id: cache-c-core uses: actions/cache@v2 with: path: vendor/install key: C-core-${{ runner.os }}-${{ hashFiles('.gitmodules') }} - uses: actions/setup-python@v2 name: Install Python with: python-version: '3.8' - name: Install OS dependencies if: steps.cache-c-core.outputs.cache-hit != 'true' # Only needed when building the C core run: brew install autoconf automake libtool cmake - name: Build wheels uses: joerick/cibuildwheel@v1.10.0 env: CIBW_BEFORE_BUILD: "python setup.py build_c_core" - uses: actions/upload-artifact@v2 with: path: ./wheelhouse/*.whl build_wheel_win: name: Build wheels on Windows (${{ matrix.cmake_arch }}) runs-on: windows-2019 strategy: matrix: include: - cmake_arch: Win32 wheel_arch: win32 vcpkg_arch: x86 - cmake_arch: x64 wheel_arch: win_amd64 vcpkg_arch: x64 steps: - uses: actions/checkout@v2 with: submodules: true fetch-depth: 0 - uses: actions/setup-python@v2 name: Install Python with: python-version: '3.8' - name: Cache installed C core id: cache-c-core uses: actions/cache@v2 with: path: vendor/install key: C-core-build-${{ runner.os }}-${{ matrix.cmake_arch }}-${{ hashFiles('.gitmodules') }}- - name: Install build dependencies if: steps.cache-c-core.outputs.cache-hit != 'true' # Only needed when building the C core run: choco install winflexbison3 cmake - name: Build wheels uses: joerick/cibuildwheel@v1.10.0 env: CIBW_BEFORE_BUILD: "python setup.py build_c_core" CIBW_BUILD: "*-${{ matrix.wheel_arch }}" IGRAPH_CMAKE_EXTRA_ARGS: -DCMAKE_BUILD_TYPE=Release -A ${{ matrix.cmake_arch }} CIBW_TEST_COMMAND: "cd /d {project} && python -m unittest -v" - uses: actions/upload-artifact@v2 with: path: ./wheelhouse/*.whl build_sdist: name: Build sdist runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 with: submodules: true fetch-depth: 0 - name: Cache installed C core id: cache-c-core uses: actions/cache@v2 with: path: | vendor/build vendor/install key: C-core-${{ runner.os }}-${{ hashFiles('.gitmodules') }}-4 - name: Install OS dependencies if: steps.cache-c-core.outputs.cache-hit != 'true' # Only needed when building the C core run: sudo apt install cmake flex bison - uses: actions/setup-python@v2 name: Install Python with: python-version: '3.8' - name: Build sdist run: | pip install setuptools_scm python setup.py build_c_core python setup.py sdist python setup.py install - name: Test run: | pip install ddt python -m unittest -v - uses: actions/upload-artifact@v2 with: path: dist/*.tar.gz upload_pypi: needs: [build_wheel_linux, build_wheel_macos, build_wheel_win, build_sdist] runs-on: ubuntu-latest # upload to PyPI on every push from the master branch if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') steps: - uses: actions/download-artifact@v2 with: name: artifact path: dist # Upload tagged versions to production PyPI - name: Publish distribution 📦 to PyPI uses: pypa/gh-action-pypi-publish@master with: password: ${{ secrets.PYPI_API_TOKEN }}leidenalg-0.8.9/.gitignore000066400000000000000000000007261420514302700154470ustar00rootroot00000000000000MANIFEST build/ dist/ lib/ nbproject/ leidenalg.egg-info/ wlib/ bin/ obj/ Makefile *.log **/*.o **/*.so **/*.pyc files.txt files_py3.txt callgrind* main.cpp leiden-dists.zip leidenalg.cbp leidenalg.depend leidenalg.layout leiden.log igraphcore/ **/*.swp valgrind-python.supp test/ test_install.sh massif* .vscode/ *.code-workspace PACKAGE.txt vendor/source/igraph vendor/source/install vendor/install src/leidenalg/version.py pip-wheel-metadata .eggs/ doc/source/_build leidenalg-0.8.9/.gitmodules000066400000000000000000000001731420514302700156300ustar00rootroot00000000000000[submodule "vendor/source/igraph"] path = vendor/source/igraph url = https://github.com/igraph/igraph.git ignore = all leidenalg-0.8.9/.readthedocs.yml000066400000000000000000000011031420514302700165330ustar00rootroot00000000000000# .readthedocs.yml # Read the Docs configuration file # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details # Required version: 2 conda: environment: build-doc.yml # Optionally build your docs in additional formats such as PDF and ePub formats: all # Optionally set the version of Python and requirements required to build your docs python: version: 3.7 install: - method: pip path: . submodules: include: all recursive: true # Build documentation in the doc/source directory with Sphinx sphinx: configuration: doc/source/conf.pyleidenalg-0.8.9/CHANGELOG000066400000000000000000000043161420514302700146700ustar00rootroot000000000000000.8.9 - Fixed bug with renaming of python-igraph to igraph (issue #93) - Removed irrelevant node_sizes argument for RBConfigurationVertexPartition and ModularityVertexPartition - Improved documentation 0.8.8 - Corrected relabeling bug (PR #82) - Improved error handling, avoiding some crashses (issue #81) 0.8.7 - Improved numerical stability 0.8.6 - Removed accidentally left DEBUG statement 0.8.5 - Corrected iterating over nodes (PR #70). - Fixed segfault with move_nodes_constrained (issue #68) - Fixed problem with initial_membership (issue #66) 0.8.4 - Update C core to 0.9.1 - Fixed caching problem (issue #62) - Fixed missing node_sizes for modularity (issue #60) 0.8.3 - Fixed missing parameter in find_partition_multiplex by @TomKellyGenetics (PR #50) 0.8.2 - New option to constrain community size by @orenbenkiki (PR #46) - Great performance improvement by @ragibson (PR #40) - Minor improvements and clarifications 0.8.1 - Fixed performance problem (issue #35) - Improved documentation 0.8.0 - New option to keep some nodes "fixed" by @iosonofabio (PR #8, #9) - Corrected bipartite clustering - Corrected some documentation - Several minor bugfixes 0.6.1 - Minor corrections to documentation - Added doctest to examples in documentation - Removed trailing semicolons throughout code - Corrected some errors in CPMVertexPartition.Bipartite 0.6.0 - Major API changes, now exposing actual classes and optimisation routine. - Improved algorithm, now runs faster and finds better solutions. - Improved error handling, doing more type checking. - Improved documentation throughout, now done using Sphinx and available from readthedocs.org. - Now includes testing module, available through python setup.py test. 0.5.3 - Fixed bug concerning weights (were rounded to integers). - Improved documentation. - Included an HOWTO on extending the current package. - Fixed some minor bugs. 0.5.2 - Ensured that random neighbour selection works in O(1) rather than O(k), with k the average number of neighbours. - Optimized the calculation of weight from/to community. - Included some missing references. 0.5.1 Corrected some mistakes which prevented it from being properly used on PyPi. No serious changes were made. 0.5 Initial release leidenalg-0.8.9/LICENSE000066400000000000000000001045051420514302700144640ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 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. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. {one line to give the program's name and a brief idea of what it does.} Copyright (C) {year} {name of author} This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: {project} Copyright (C) {year} {fullname} This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . leidenalg-0.8.9/MANIFEST000066400000000000000000000014271420514302700146070ustar00rootroot00000000000000# file GENERATED by distutils, do NOT edit LICENSE README.md setup.py include/CPMVertexPartition.h include/GraphHelper.h include/LinearResolutionParameterVertexPartition.h include/ModularityVertexPartition.h include/MutableVertexPartition.h include/Optimiser.h include/RBConfigurationVertexPartition.h include/RBERVertexPartition.h include/SignificanceVertexPartition.h include/SurpriseVertexPartition.h include/pynterface.h src/CPMVertexPartition.cpp src/GraphHelper.cpp src/LinearResolutionParameterVertexPartition.cpp src/ModularityVertexPartition.cpp src/MutableVertexPartition.cpp src/Optimiser.cpp src/RBConfigurationVertexPartition.cpp src/RBERVertexPartition.cpp src/SignificanceVertexPartition.cpp src/SurpriseVertexPartition.cpp src/__init__.py src/functions.py src/pynterface.cpp leidenalg-0.8.9/MANIFEST.in000066400000000000000000000006601420514302700152120ustar00rootroot00000000000000include LICENSE include CHANGELOG include README.rst include pyproject.toml include include/ include MANIFEST.in include tests/*.py exclude .git* exclude *.yml exclude release* prune .github graft vendor/source/igraph prune vendor/source/igraph/etc/abstracts prune vendor/source/igraph/etc/papers prune vendor/source/igraph/etc/presentations prune vendor/source/igraph/interfaces prune vendor/source/igraph/vendor/simpleraytracer leidenalg-0.8.9/README.rst000066400000000000000000000214571420514302700151520ustar00rootroot00000000000000leidenalg ============== This package implements the Leiden algorithm in ``C++`` and exposes it to ``python``. It relies on ``(python-)igraph`` for it to function. Besides the relative flexibility of the implementation, it also scales well, and can be run on graphs of millions of nodes (as long as they can fit in memory). The core function is ``find_partition`` which finds the optimal partition using the Leiden algorithm [1]_, which is an extension of the Louvain algorithm [2]_ for a number of different methods. The methods currently implemented are (1) modularity [3]_, (2) Reichardt and Bornholdt's model using the configuration null model and the Erdös-Rényi null model [4]_, (3) the Constant Potts model (CPM) [5]_, (4) Significance [6]_, and finally (5) Surprise [7]_. In addition, it supports multiplex partition optimisation allowing community detection on for example negative links [8]_ or multiple time slices [9]_. There is the possibility of only partially optimising a partition, so that some community assignments remain fixed [10]_. It also provides some support for community detection on bipartite graphs. See the `documentation `_ for more information. .. image:: https://readthedocs.org/projects/leidenalg/badge :target: http://leidenalg.readthedocs.io/en/latest/ :alt: Leiden documentation status .. image:: https://github.com/vtraag/leidenalg/actions/workflows/build.yml/badge.svg?branch=master :target: https://github.com/vtraag/leidenalg/actions/workflows/build.yml :alt: Leiden build status (GitHub Actions) .. image:: https://zenodo.org/badge/146722095.svg :target: https://zenodo.org/badge/latestdoi/146722095 :alt: DOI .. image:: https://anaconda.org/conda-forge/leidenalg/badges/version.svg :target: https://anaconda.org/conda-forge/leidenalg :alt: Anaconda (conda-forge) Installation ------------ In short: ``pip install leidenalg``. All major platforms are supported on Python>=3.6, earlier versions of Python are no longer supported. Alternatively, you can install from Anaconda (channel ``conda-forge``). For Unix like systems it is possible to install from source. For Windows this is overly complicated, and you are recommended to use the binary wheels. The igraph ``C`` core library is provided within this package, and is automatically compiled. If you encounter any issue with compilation, please see http://igraph.org. Make sure you have all necessary tools for compilation. In Ubuntu this can be installed using ``sudo apt-get install build-essential autoconf automake flex bison``, please refer to the documentation for your specific system. Make sure that not only ``gcc`` is installed, but also ``g++``, as the ``leidenalg`` package is programmed in ``C++``. You can check if all went well by running a variety of tests using ``python setup.py test``. There are basically two installation modes, similar to the python-igraph package itself (from which most of the setup.py comes). 1. No ``C`` core library is installed yet. The ``C`` core library of igraph that is provided within the ``leidenalg`` package is compiled. 2. A ``C`` core library is already installed. In this case, you may link dynamically to the already installed version by specifying ``--no-pkg-config``. This is probably also the version that is used by the igraph package, but you may want to double check this. In case the ``python-igraph`` package is already installed before, make sure that both use the **same versions** (at least the same minor version, which should be API compatible). Troubleshooting --------------- In case of any problems, best to start over with a clean environment. Make sure you remove the ``python-igraph`` package completely, remove the ``C`` core library and remove the ``leidenalg`` package. Then, do a complete reinstall starting from ``pip install leidenalg``. In case you want a dynamic library be sure to then install the ``C`` core library from source before. Make sure you **install the same versions**. Usage ----- There is no standalone version of ``leidenalg``, and you will always need python to access it. There are no plans at the moment for developing a standalone version or R support. However, there have been various efforts to port the package to R. These typically do not offer all available functionality or have some other limitations, but nonetheless may be very useful. The available ports are: - https://github.com/cole-trapnell-lab/leidenbase - https://github.com/TomKellyGenetics/leiden - https://github.com/kharchenkolab/leidenAlg Please refer to the documentation for more details on function calls and parameters. This implementation is made for flexibility, but ``igraph`` nowadays also includes an implementation of the Leiden algorithm internally. That implementation is less flexible: the implementation only works on undirected graphs, and only CPM and modularity are supported. It is likely to be substantially faster though. Just to get you started, below the essential parts. To start, make sure to import the packages: >>> import leidenalg >>> import igraph as ig We'll create a random graph for testing purposes: >>> G = ig.Graph.Erdos_Renyi(100, 0.1); For simply finding a partition use: >>> part = leidenalg.find_partition(G, leidenalg.ModularityVertexPartition); Contribute ---------- Source code: https://github.com/vtraag/leidenalg Issue tracking: https://github.com/vtraag/leidenalg/issues See the documentation on `Implementation` for more details on how to contribute new methods. References ---------- Please cite the references appropriately in case they are used. .. [1] Traag, V.A., Waltman. L., Van Eck, N.-J. (2018). From Louvain to Leiden: guaranteeing well-connected communities. Scientific reports, 9(1), 5233. `10.1038/s41598-019-41695-z `_ .. [2] Blondel, V. D., Guillaume, J.-L., Lambiotte, R., & Lefebvre, E. (2008). Fast unfolding of communities in large networks. Journal of Statistical Mechanics: Theory and Experiment, 10008(10), 6. `10.1088/1742-5468/2008/10/P10008 `_ .. [3] Newman, M. E. J., & Girvan, M. (2004). Finding and evaluating community structure in networks. Physical Review E, 69(2), 026113. `10.1103/PhysRevE.69.026113 `_ .. [4] Reichardt, J., & Bornholdt, S. (2006). Statistical mechanics of community detection. Physical Review E, 74(1), 016110. `10.1103/PhysRevE.74.016110 `_ .. [5] Traag, V. A., Van Dooren, P., & Nesterov, Y. (2011). Narrow scope for resolution-limit-free community detection. Physical Review E, 84(1), 016114. `10.1103/PhysRevE.84.016114 `_ .. [6] Traag, V. A., Krings, G., & Van Dooren, P. (2013). Significant scales in community structure. Scientific Reports, 3, 2930. `10.1038/srep02930 `_ .. [7] Traag, V. A., Aldecoa, R., & Delvenne, J.-C. (2015). Detecting communities using asymptotical surprise. Physical Review E, 92(2), 022816. `10.1103/PhysRevE.92.022816 `_ .. [8] Traag, V. A., & Bruggeman, J. (2009). Community detection in networks with positive and negative links. Physical Review E, 80(3), 036115. `10.1103/PhysRevE.80.036115 `_ .. [9] Mucha, P. J., Richardson, T., Macon, K., Porter, M. A., & Onnela, J.-P. (2010). Community structure in time-dependent, multiscale, and multiplex networks. Science, 328(5980), 876–8. `10.1126/science.1184819 `_ .. [10] Zanini, F., Berghuis, B. A., Jones, R. C., Robilant, B. N. di, Nong, R. Y., Norton, J., Clarke, Michael F., Quake, S. R. (2019). northstar: leveraging cell atlases to identify healthy and neoplastic cells in transcriptomes from human tumors. BioRxiv, 820928. `10.1101/820928 `_ Licence ------- Copyright (C) 2020 V.A. Traag This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/. leidenalg-0.8.9/build-doc.yml000066400000000000000000000003121420514302700160330ustar00rootroot00000000000000name: build-doc channels: - conda-forge dependencies: - python=3.8 - python-igraph>=0.8.0 - ddt - sphinx - sphinx_rtd_theme - autoconf - automake - flex - bison - libtool - cmakeleidenalg-0.8.9/doc/000077500000000000000000000000001420514302700142175ustar00rootroot00000000000000leidenalg-0.8.9/doc/source/000077500000000000000000000000001420514302700155175ustar00rootroot00000000000000leidenalg-0.8.9/doc/source/advanced.rst000066400000000000000000000262631420514302700200270ustar00rootroot00000000000000Advanced ======== The basic interface explained in the :ref:`Introduction` should provide you enough to start detecting communities. However, perhaps you want to improve the partitions further or want to do some more advanced analysis. In this section, we will explain this in more detail. Optimiser --------- Although the package provides simple access to the function :func:`~leidenalg.find_partition`, there is actually an underlying :class:`~leidenalg.Optimiser` class that is doing the actual work. We can also explicitly construct an :class:`~leidenalg.Optimiser` object: >>> optimiser = la.Optimiser() The function :func:`~leidenalg.find_partition` then does nothing else then calling :func:`~leidenalg.Optimiser.optimise_partition` on the provided partition. .. testsetup:: G = ig.Graph.Erdos_Renyi(100, p=5./100) partition = la.CPMVertexPartition(G) >>> diff = optimiser.optimise_partition(partition) :func:`~leidenalg.Optimiser.optimise_partition` simply tries to improve any provided partition. We can thus try to repeatedly call :func:`~leidenalg.Optimiser.optimise_partition` to keep on improving the current partition: >>> G = ig.Graph.Erdos_Renyi(100, p=5./100) >>> partition = la.ModularityVertexPartition(G) >>> diff = 1 >>> while diff > 0: ... diff = optimiser.optimise_partition(partition) Even if a call to :func:`~leidenalg.Optimiser.optimise_partition` did not improve the current partition, it is still possible that a next call will improve the partition. Of course, if the current partition is already optimal, this will never happen, but it is not possible to decide whether a partition is optimal. This functionality of repeating multiple iterations is actually already built-in. You can simply call >>> diff = optimiser.optimise_partition(partition, n_iterations=10) If ``n_iterations < 0`` the optimiser continues iterating until it encounters an iterations that did not improve the partition. The :func:`~leidenalg.Optimiser.optimise_partition` itself is built on two other basic algorithms: :func:`~leidenalg.Optimiser.move_nodes` and :func:`~leidenalg.Optimiser.merge_nodes`. You can also call these functions yourself. For example: >>> diff = optimiser.move_nodes(partition) or >>> diff = optimiser.merge_nodes(partition) The simpler Louvain algorithm aggregates the partition and repeats the :func:`~leidenalg.Optimiser.move_nodes` on the aggregated partition. We can easily emulate that: >>> partition = la.ModularityVertexPartition(G) >>> while optimiser.move_nodes(partition) > 0: ... partition = partition.aggregate_partition() This summarises the whole Louvain algorithm in just three lines of code. Although this finds the final aggregate partition, it leaves unclear the actual partition on the level of the individual nodes. In order to do that, we need to update the membership based on the aggregate partition, for which we use the function :func:`~leidenalg.VertexPartition.MutableVertexPartition.from_coarse_partition`. >>> partition = la.ModularityVertexPartition(G) >>> partition_agg = partition.aggregate_partition() >>> while optimiser.move_nodes(partition_agg) > 0: ... partition.from_coarse_partition(partition_agg) ... partition_agg = partition_agg.aggregate_partition() Now ``partition_agg`` contains the aggregate partition and ``partition`` contains the actual partition of the original graph ``G``. Of course, ``partition_agg.quality() == partition.quality()`` (save some rounding). Instead of :func:`~leidenalg.Optimiser.move_nodes`, you could also use :func:`~leidenalg.Optimiser.merge_nodes`. These functions depend on choosing particular alternative communities: the documentation of the functions provides more detail. One possibility is that rather than aggregating the partition based on the current partition, you can first refine the partition and then aggregate it. This is what is done in the Leiden algorithm, and can be done using the functions :func:`~leidenalg.Optimiser.move_nodes_constrained` and :func:`~leidenalg.Optimiser.merge_nodes_constrained`. Implementing this, you end up with the following high-level implementation of the Leiden algorithm: >>> # Set initial partition >>> partition = la.ModularityVertexPartition(G) >>> refined_partition = la.ModularityVertexPartition(G) >>> partition_agg = refined_partition.aggregate_partition() >>> >>> while optimiser.move_nodes(partition_agg): ... ... # Get individual membership for partition ... partition.from_coarse_partition(partition_agg, refined_partition.membership) ... ... # Refine partition ... refined_partition = la.ModularityVertexPartition(G) ... optimiser.merge_nodes_constrained(refined_partition, partition) ... ... # Define aggregate partition on refined partition ... partition_agg = refined_partition.aggregate_partition() ... ... # But use membership of actual partition ... aggregate_membership = [None] * len(refined_partition) ... for i in range(G.vcount()): ... aggregate_membership[refined_partition.membership[i]] = partition.membership[i] ... partition_agg.set_membership(aggregate_membership) These functions in turn rely on two key functions of the partition: :func:`~leidenalg.VertexPartition.MutableVertexPartition.diff_move` and :func:`~leidenalg.VertexPartition.MutableVertexPartition.move_node`. The first calculates the difference when moving a node, and the latter actually moves the node, and updates all necessary internal administration. The :func:`~leidenalg.Optimiser.move_nodes` then does something as follows >>> for v in G.vs: ... best_comm = max(range(len(partition)), ... key=lambda c: partition.diff_move(v.index, c)) ... partition.move_node(v.index, best_comm) The actual implementation is more complicated, but this gives the general idea. This package builds on a previous implementation of the Louvain algorithm in `louvain-igraph `_. To illustrate the difference between ``louvain-igraph`` and ``leidenalg``, we ran both algorithms for 10 iterations on a `Youtube network `_ of more than 1 million nodes and almost 3 million edges. .. image:: figures/speed.png The results are quite clear: Leiden is able to achieve a higher modularity in less time. It also points out that it is usually a good idea to run Leiden for at least two iterations; this is also the default setting. Note that even if the Leiden algorithm did not find any improvement in this iteration, it is always possible that it will find some improvement in the next iteration. Resolution profile ------------------ Some methods accept so-called resolution parameters, such as :class:`~leidenalg.CPMVertexPartition` or :class:`~leidenalg.RBConfigurationVertexPartition`. Although some methods may seem to have some 'natural' resolution, in reality this is often quite arbitrary. However, the methods implemented here (which depend in a linear way on resolution parameters) allow for an effective scanning of a full range for the resolution parameter. In particular, these methods somehow can be formulated as :math:`Q = E - \gamma N` where :math:`E` and :math:`N` are some other quantities. In the case for :class:`~leidenalg.CPMVertexPartition` for example, :math:`E = \sum_c m_c` is the number of internal edges and :math:`N = \sum_c \binom{n_c}{2}` is the sum of the internal possible edges. The essential insight for these formulations [1]_ is that if there is an optimal partition for both :math:`\gamma_1` and :math:`\gamma_2` then the partition is also optimal for all :math:`\gamma_1 \leq \gamma \leq \gamma_2`. Such a resolution profile can be constructed using the :class:`~leidenalg.Optimiser` object. >>> G = ig.Graph.Famous('Zachary') >>> optimiser = la.Optimiser() >>> profile = optimiser.resolution_profile(G, la.CPMVertexPartition, ... resolution_range=(0,1)) Plotting the resolution parameter versus the total number of internal edges we thus obtain something as follows: .. image:: figures/resolution_profile.png Now ``profile`` contains a list of partitions of the specified type (:class:`~leidenalg.CPMVertexPartition` in this case) for resolution parameters at which there was a change. In particular, ``profile[i]`` should be better until ``profile[i+1]``, or stated otherwise for any resolution parameter between ``profile[i].resolution_parameter`` and ``profile[i+1].resolution_parameter`` the partition at position ``i`` should be better. Of course, there will be some variations because :func:`~leidenalg.Optimiser.optimise_partition` will find partitions of varying quality. The change points can then also vary for different runs. This function repeatedly calls :func:`~leidenalg.Optimiser.optimise_partition` and can therefore require a lot of time. Especially for resolution parameters right around a change point there may be many possible partitions, thus requiring a lot of runs. Fixed nodes ----------- For some purposes, it might be beneficial to only update part of a partition. For example, perhaps we previously already ran the Leiden algorithm on some dataset, and did some analysis on the resulting partition. If we then gather new data, and in particular new nodes, it might be useful to keep the previous community assignments fixed, while only updating the community assignments for the new nodes. This can be done using the ``is_membership_fixed`` argument of :func:`~leidenalg.Optimiser.find_partition`, see [2]_ for some details. For example, suppose we previously detected ``partition`` for graph ``G``, which was extended to graph ``G2``. Assuming that the previously exiting nodes are identical, we could create a new partition by doing >>> new_membership = list(range(G2.vcount())) ... new_membership[:G.vcount()] = partition.membership We can then only update the community assignments for the new nodes as follows >>> new_partition = la.CPMVertexPartition(G2, new_membership, ... resolution_parameter=partition.resolution_parameter) ... is_membership_fixed = [i < G.vcount() for i in range(G2.vcount())] >>> diff = optimiser.optimise_partition(new_partition, is_membership_fixed=is_membership_fixed) In this example we used :class:`~leidenalg.CPMVertexPartition`. but any other ``VertexPartition`` would work as well. Maximum community size ---------------------- In some cases, you may want to restrict the community sizes. It is possible to indicate this by setting the :attr:`~leidenalg.Optimiser.max_comm_size` parameter so that this constraint is taken into account during optimisation. In addition, it is possible to pass this parameter directly when using :func:`~leidenalg.find_partition`. For example >>> partition = la.find_partition(G, la.ModularityVertexPartition, max_comm_size=10) References ---------- .. [1] Traag, V. A., Krings, G., & Van Dooren, P. (2013). Significant scales in community structure. Scientific Reports, 3, 2930. `10.1038/srep02930 `_ .. [2] Zanini, F., Berghuis, B. A., Jones, R. C., Robilant, B. N. di, Nong, R. Y., Norton, J., Clarke, Michael F., Quake, S. R. (2019). northstar: leveraging cell atlases to identify healthy and neoplastic cells in transcriptomes from human tumors. BioRxiv, 820928. `10.1101/820928 `_ leidenalg-0.8.9/doc/source/conf.py000066400000000000000000000245341420514302700170260ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # leidenalg documentation build configuration file, created by # sphinx-quickstart on Fri Oct 21 11:26:44 2016. # # This file is execfile()d with the current directory set to its # containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # import os #import sys # #sys.path.insert(0, os.path.abspath('.')) # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. # # needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.coverage', 'sphinx.ext.mathjax', 'sphinx.ext.napoleon', 'sphinx.ext.autosectionlabel' ] # Add any paths that contain templates here, relative to this directory. templates_path = ['.templates'] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # # source_suffix = ['.rst', '.md'] source_suffix = '.rst' # The encoding of source files. # # source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'leidenalg' copyright = u'2016, V.A. Traag' author = u'V.A. Traag' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. from pkg_resources import get_distribution # The full version, including alpha/beta/rc tags. release = get_distribution('leidenalg').version del get_distribution # The short X.Y version. version = '.'.join(release.split('.')[:2]) # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: # # today = '' # # Else, today_fmt is used as the format for a strftime call. # # today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This patterns also effect to html_static_path and html_extra_path exclude_patterns = [] # The reST default role (used for this markup: `text`) to use for all # documents. # # default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. # # add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). # # add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. # # show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. # modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built documents. # keep_warnings = False # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = False # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # #html_theme = 'classic' # on_rtd is whether we are on readthedocs.org, this line of code grabbed from docs.readthedocs.org on_rtd = os.environ.get('READTHEDOCS', None) == 'True' if not on_rtd: # only import and set the theme if we're building docs locally import sphinx_rtd_theme html_theme = 'sphinx_rtd_theme' html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] # otherwise, readthedocs.org uses their theme by default, so no need to specify it # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. # # html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. # html_theme_path = [] # The name for this set of Sphinx documents. # " v documentation" by default. # # html_title = u'leidenalg v0.7.0' # A shorter title for the navigation bar. Default is the same as html_title. # # html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. # # html_logo = None # The name of an image file (relative to this directory) to use as a favicon of # the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. # # html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['.static'] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. # # html_extra_path = [] # If not None, a 'Last updated on:' timestamp is inserted at every page # bottom, using the given strftime format. # The empty string is equivalent to '%b %d, %Y'. # # html_last_updated_fmt = None # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. # # html_use_smartypants = True # Custom sidebar templates, maps document names to template names. # # html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. # # html_additional_pages = {} # If false, no module index is generated. # # html_domain_indices = True # If false, no index is generated. # # html_use_index = True # If true, the index is split into individual pages for each letter. # # html_split_index = False # If true, links to the reST sources are added to the pages. # # html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. # # html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. # # html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. # # html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). # html_file_suffix = None # Language to be used for generating the HTML full-text search index. # Sphinx supports the following languages: # 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' # 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr', 'zh' # # html_search_language = 'en' # A dictionary with options for the search language support, empty by default. # 'ja' uses this config value. # 'zh' user can custom change `jieba` dictionary path. # # html_search_options = {'type': 'default'} # The name of a javascript file (relative to the configuration directory) that # implements a search results scorer. If empty, the default will be used. # # html_search_scorer = 'scorer.js' # Output file base name for HTML help builder. htmlhelp_basename = 'leidendoc' # -- Options for LaTeX output --------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). # # 'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). # # 'pointsize': '10pt', # Additional stuff for the LaTeX preamble. # # 'preamble': '', # Latex figure (float) alignment # # 'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ (master_doc, 'leidenalg.tex', u'leidenalg Documentation', u'V.A. Traag', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. # # latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. # # latex_use_parts = False # If true, show page references after internal links. # # latex_show_pagerefs = False # If true, show URL addresses after external links. # # latex_show_urls = False # Documents to append as an appendix to all manuals. # # latex_appendices = [] # It false, will not define \strong, \code, itleref, \crossref ... but only # \sphinxstrong, ..., \sphinxtitleref, ... To help avoid clash with user added # packages. # # latex_keep_old_macro_names = True # If false, no module index is generated. # # latex_domain_indices = True # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ (master_doc, 'leidenalg', u'leidenalg Documentation', [author], 1) ] # If true, show URL addresses after external links. # # man_show_urls = False # -- Options for Texinfo output ------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ (master_doc, 'leidenalg', u'leidenalg Documentation', author, 'leidenalg', 'One line description of project.', 'Miscellaneous'), ] autoclass_content = 'both' # Documents to append as an appendix to all manuals. # # texinfo_appendices = [] # If false, no module index is generated. # # texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. # # texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. # # texinfo_no_detailmenu = False doctest_global_setup = """ import igraph as ig import leidenalg as la """ leidenalg-0.8.9/doc/source/figures/000077500000000000000000000000001420514302700171635ustar00rootroot00000000000000leidenalg-0.8.9/doc/source/figures/karate_CPM.png000066400000000000000000002263311420514302700216460ustar00rootroot00000000000000‰PNG  IHDRXX¾f˜ÜsBIT|dˆ pHYsÄÄ•+ IDATxœìÝw|Ž÷úÀñO$BbABì+!vÄUj×l(jÕ®£1ê 8ªŽ)ªv­ª"fì 3fìHbFdÿþèyò 2žq?#Éõ~½Îëuä¹ïï}EËõ½îëk–”””ŒB!„PL.c „B‘ÝH‚%„B¡0I°„B!& –B!„Â$ÁB!„P˜$XB!„ “K!„Ba’` !„B(ÌÂØ!ÒwãÆ ‚‚‚xúô)5kÖÄÅÅ…üùó;,!„™0“IîB˜–Ð7˜ùõ×l?z”Rff¸$$P#9™ý%%aocà¡Cÿý÷ÆU!D:$Á„üàíÍê•+ù-6–j@4®¹l·°`K±bl9tˆ U«8J!„™‘Kñ™‹ U/\`vR’ZןºåÉÃö¿ÿ¦¦»»~ƒB¡I°„0j׿Ӌ¢Å½µ¬¬øå¯¿p“$K!L†¼E(„‘­œ=›ÒW®h•\üC·O>Q4&!„º‘ –Fôüùs*•,ɳøxÖùp»W/­_¯L`B!t",!ŒèßS¦0CÇä `$°k÷n^¾|©{PB!t& –FtÆÏ ­U.6–sÁÁ ­&„B’` aDwïâªÐZ.ññùù)´šB]H‚%„‘ܸq;KK”šË^Ph5!„ºK!„Ba’` a$ŽŽŽDÄÇóZ¡õ‚—úõZM!„.$Áˆ\Ê–%H¡µ‚rçÆ¥U+…VB¡ I°„0¢­[sE¡µZYQ«vm…VB¡ 4*„½zõ ‡bÅx‘ Ó: ÍÌëÛ—kÖ(™B]H‚%„‘ùþûߟ:•UZ&Y÷fùós÷Õ+eB¡5Ù"ÂÈ~û-kÔàg-ïïheÅ–={I!„n$ÁÂüÌÑzõø6—ú¿%‡Ü¹©ß®õš6Õ_pB!4& –&bÓ™3ØŽI…>Þ¨‡=kãàÁƒ´lÙÒØa!„QI‚%„‰ÊjÕ+kkk6mÚD§NŒŠB$XB˜¨¬Ôõ¡’%K²`ÁúôécìP„Â($ÁÂDeÕ –Š££#£GfذaÆE! N,!LTV®`©¸ººòùçŸ3aÂc‡"„% –&*«W°TZ´hAƒ ˜={¶±CBƒ‘K•*X*]ºtÁÞÞžŸ~úÉØ¡!„AH‚%„‰Ê.,•þýû“œœÌÚµkŠBè$XB˜¨ì–`x{{ÆöíÛŠBè•$XB˜¨ì´E˜ÚäÉ“9}ú4‡2v(B¡7’` a¢²cKeîܹlÙ²…ÀÀ@c‡"„z! –&*»V°T–-[ÆÂ… ¹qㆱCBÅI‚%„‰ÊÎ,•õë×3vìX=zdìP„BQÆ@‘¶ì^ÁRÙ½{7îîîìÝ»kkë÷> á܉8À¹«WINJÂÅÙ—6m¨Õ NNNFŠZ!2& –Èö^¿~ͽ{ úóOƒ‚ 1‘· ¸Öª…k‡¸¹»S©R%c‡ù‘ØØX¬¬¬Œ†A6£FÑÅÞžQ¹r±ùßç·-ÀD`¨×>ý”ð7op¬QƒåË—³nÝ:üýýv­`Gœ½¬óçÏÓºukªU«ÆâÅ‹3L®âââXµjÆ Kùš*q²¶¶NI®ÚµkÇßÿ Àwß}Ç÷߯¿oB!4$ –Èq¬­­SþÆ 9uêTº×Î;þüóOC„–"»ô`-\¸¥K—²e˺¨1WlÑ¢E|óÍ7)?~òä ØØØ|tm³fÍ äíÛ·T¬X‘ °^Ý…&B,‘£e–`Ìœ9“   þ0`#µ)T°’““µ¾÷ÆtîÜ™%J°bÅ .œé=áááœ8q‚Ï?ÿ<åkW¯^¥ZµjéÞ“ºŠõÍ7ß°jÕ*^¿~­uÜB¡I°DŽÖ ANŸ>éuÓ§OçúõëlÞ¼ÙQ§‚†ï²e|Ý© Ë•£UÅŠÔ±·çËÖ­Y6>çÏŸWk_~ù…3f°lÙ2z÷î­öó?¬^\»vªU«¦{OÛ¶mßÛ•­B!„©Käx5âäÉ“™^7iÒ$îÝ»gm(CW°~þ׿Ò ǽ½©¾g‹îßçÀÝ»üA£ƒ¹›Ü9‚Ux¸"kÙEDpdçN­î]ºt)C‡ÅÂ"í»49ú¦D‰ØÙÙqîܹ÷¾>iÒ$æÍ›GBB‚V1 !„¶$ÁÈ“'NNNku÷îÝ©R¥ 3fÌP$}V°‚öìÁE¡„Ã:xPãû^¼xÁŽ;0`@šŸGDD`mmM¡B…Ô^óÃfw•iÓ¦áãã£qŒB¡ I°„øMÆ5¤å³Ï>ÃÅÅ…©S§ê‹>+XAÁÁ¸(´– ”ª¹\]éePÑd{P%½«C‡DFF qœB¡-I°„øMÇ5¤å“O>¡iÓ¦L˜0A§uôYÁ2ONV,Á* 8)³gÏÔ¾'44”k×®ñÉ'Ÿ¤{& î*ÖÖÖ¸ºº¦9dTªXBC“Kˆÿ©R¥ Ož<áùóç:­Ó¶m[Ú¶m˘1c´^CŸ¬D33‚Zëòü9E‹UûžŒÛU4é¿J-­· J•*E§Nô:»L!R“KˆTtivO­E‹téÒ…¯¿þZ«ûõYÁr©[W±+pÑ`¸èéÓ§133ÃÍÍ-Ãë´Ù"hÓ¦ ~~~$¥18ÕËË‹]»vñøñc×BMI‚%D*J%XM›6å‹/¾`èСß«Ï –KÇŽ¥ó枦‚—–-Õ¾^êUxx8ùóç§`Á‚ZÅ”ÖÈ™%„0I°„HE‰>¬ÔÜÜÜ:t(ƒ Òè>}V°š4oNŒ1g$¢T)šwî¬Öµ»wï¦zõêT¬X1Ãë´ÝTI¯Ù ~ýúØØØ¤û¹B(E,!R)X° ¥K—æÊ•+Š­Y·n]FÍ_|¡ö=úL°Š/N—aêck>P¬ys6l¨Öõ™½9¨¢Mƒ{j 4àÚµk¼xñ"ÍÏ¥Š%„0I°„ø€’Û„*ÎÎÎL™2…=zdzmrr2ñññz=ìÙkÂîUªÄ~-ï¿,+X¯_¯Öõ¾¾¾|öÙgj͵Ҷÿ*µŒ¶ sçÎÍØ±cùá‡tz†BdD,!>   jժ̙3‡®]»fx>û¯RÛÌìÒ¥9¢á}7€ÁÅŠqôµ®gÅŠ >\­ëuÝ"„ôß&TéÚµ+×®]#$$D§ç!Dz$ÁâµjÕâæÍ›¼}ûVñµ+T¨ÀÂ… ñôôL÷}ô¬’'o^þºz•ï+UÂÛÜ\­{f›™ÑÜ‚µ”.[V­{ÔÝ £páÂäÏŸ_­ëÓãääÄ«W¯xðàAº×ÈV¡BŸ$Á" ºNuψƒƒË—/§]»vi~n¨ €u¾|ºqƒªS§ÒÞÞžffü œ’€ Àj`¸™ýÊ”áíÀì8~œ9ÿþ·ZëGDDpìØ1µ¶FA™ê•JFÛ„ðO²Û¨Q#~ûí7Ež'„©I‚%DôµM¨RªT)Ö¯_OË4F2ÁR1}:, ªU+®|ò ß”-K«rå`gÇÁƹàì̘;™¹r%õë×§zõêüú믙®«ÎX†Ô®_¿N•*UtøNþ_fÛ„£FÂ××—W¯^)òL!„P‘Kˆ4(=®!-E‹eûöí4kÖ콯j‹ðCçÏŸÇ{Ü8~Úµ‹SwîpðÖ-Î……±ÞߟÂööØ¥í0bÄ>œáÛ–—.]"22’-Z¨ƒ’,òçϟ顲U(„ÐI°„Hƒ­­-ùóççöíÛz}NÁ‚Ù·o 6$990^‚uàÀZ·nòc33³”ÿŸÖ–é²eË6lXºëiZ½e,Èx&–Š»»;ÉÉÉiža(„Ú’Kˆtè{›PÅÊÊ ÜÜ܈‹‹3J‚µÿ~Ú´i“îçnnnœ9s潯Y[[óý÷ß3nܸ®?tèÅŠ£fÍšjÇpÿþ}Š+†µµµúgB `úôé̘1C±ç !„$XB¤ÃP €……gÏžÅÃ×/_¼ËÏÏV­Z¥ûyzMÿîîî”,Y’M›6½÷uMÞTQbþÕ‡Š)‚££ãGÉᇠ,È€øÏþ£èó…9—$XB¤ÃÍÍ€€€4Ö—'N0cÆ ÌÕ› „„„üýýñððH÷šŒ&Ü7Ž?þø#e;uóæÍ4iÒ佞-uè:Á==êV±¾øâ Nœ8¡÷ma!DÎ –Ð縆ôLœ8‘“'OòäɃ·ì«âãùsÉöoÞ¬‡ÈDfyúô)QQQz–º‡=ÏŸ?Ÿƒjõ¿¶Ûƒyòä¡ZµjüðÃxzzR¤H‘ ¯ïÝ»7<Àßß?ÍÏ ™`vU,ixÏ>ÏžÅ51Q‘µœë‘‘éΆ9›$XrãÚ5Öúú2S‡sí¶ÄÅñù_(•Є¡¶ Õ©`©Ì™3‡S§N±k×.µ×úô)< N:Ú†ˆ››üñ_ýµZ×ÿøãLš4‰Ø4¶e `iÚ‡ÿÆ=~üxæÌ™£§¨„¡;†‹‚狺äÉCPPbë‰ìC,™1dÛtÜó/,OH`ªš© e*ÁR·‚¥òý÷ßsá¶mÛ¦ÖõºlªÜ¹s‡%JhtOZýX·oߦtéÒZ­£­%J`ggǹsç4ºï³Ï>ãÆ\¾|YO‘ CxýêŽ ®ç’;·ÆƒuEÎ –$$$°åÄ œX«zr2Ê9iFaŠ,•iÓ¦qóæM6lØéµºl<~ü˜ mêÆ IDAT.ÍëׯվÏÙÙ™&Mš°,ÕøCŒgH‹6Û„ ïÙAggŽ(¸ÞîwïpqqQpE‘]H‚eA¸˜›+²VMàêãÇÄ«Ù$/”S°`AÊ”)CHHˆ^Ÿ£iKeâĉDDD°víÚt¯yôè‘‘‘8;;kŸª±=£ÃŸÓ3hÐ .^¼H`` `øíAm¬ *иqcÖÉq)Y–KãÆ)T1}¼13£lÙ²Š¬'²I° ðÄ \œ•R/O9ÂÃH QÅÒ6Á3f /_¾dÕªUi~®ëö`HH´jÕJ« þ31|øpÀ0Gä¤ÅÚÚWWWŽ;¦ñ½#GŽä×_åÕ«WzˆLè[5¸™˜ˆîC p5Â?DÖ –D>z„æÓ†ÒçaaÁ;w\Q¨ËÔ,oooâããY¾|ùGŸéº=˜z,ƒ¶ –™™?ýô#FŒ0Ú!h~tNjÓ§OgÆŒ G$ eh÷îlU`ÝùòÑoôhVÙ‘$XP¡jU)¸Þ®øxjÖ¬©àŠB]5kÖ$44”·oßêíö¬¯¾ú sss–,Y’òµ°°0^¿~­õ–Ü‘#G(\¸0µk×ÀÖÖ–|ùòi•ìׯ_ŸR¥JQ¨P!,,,´ŠGWmÚ´ÁÏÏ$-Þ(kÖ¬fff: {ƳhýzFZZò\‡5¶U«ÒKÞìéË\6$0wnEÖŠnÄÇëÔC#t£Ï¡£ºV¯RûòË/)T¨PÊO]·S謢KE¯fÍš$&&ê½§-#ÚŒlP‘ÙXYÛª•+iŸKû¿?73c‹\‘sH‚eÕ«WçvRïX+p-_^•„¶´ÝS‡6of¤_¿~”(Q‚¹sçê´=¸uëV4h@éÒ¥ßûzêcs4uíÚ5 Òe Ú6»Ã?/= 8Å‹+•зàà`–¯_ÏÄ%Khee¥Q?V0PÉÚš»×¯“K¡——Dö$ – êÒ…ƒ ¬s6ŒoV¬ p®\d>à¦äÊÅR¥8xñ"¥+UÒ{¬"k“Ë@~Ú¼™ÏråB—á §€•ffT«[W©°„lmm)P €FçÙ©Ké Vj...LŸ>]ãû–/_΀ÒŒ+W®\¸ººröìY×U5¸7kÖ ;;;6nܨñJÐe›d«0+Y²d W¯^}ïOz÷&&!¿Û¶¥˜¥%m-,˜ì~F--©gkKþ1c|ø²*çYŠ$X´Õ×—OuøË³›¥%{9pàÞÞÞ}úàååõÞTla8Y)Á ÅÜÜœòåËÓ¡C<<<7nœZ÷¦·5˜š6Û„i Më(CprrâÕ«WóÖ¬aÑúõ|=u* 5"_¾|ŠVd’`XßÉ“i3}:6jnX8ZZ2ëVj5ožòõ °{÷nòäÉCÛ¶mµ˜(´W¿~}µzÅ?#úH°8@ëÖ­S~ܺuk:uêôѺ{÷..\ sçÎ^çèèÈÓ§O‰ŠŠR;¦´,ÆŒÃÔ©SÕ^G)ºn‚lš¢ððp4hÀœ9spww7v8"‡‘˾œ8‘Û1ÛɉÚÖÖ| ,ÎG@ï\¹hS¼8Ÿ|ÂÓwïhÖ®]šk 4ˆ 6°sçNFÍÓ§O ÷äpú× ¬,wwwzôè‘á|êT¯T4­b¥wDNÛ¶mÉ›7/;wîT{-%è2tT¥]»vDEE¥Û¦ÏÙiâc§OŸfذaœ8q‚ Ò3%Œ@,#)lcƒß¥K,;p€ó•+sù“OW½:ÿªV¿*W¦úĉ,9vŒå»veº– , k×®|ñŬX±ÂßÐǸ¥¬k×®‘/_>Ê”)óÑg5bàÀxyy}ôY@@qqq4nÜX­ç(•`L:•Õ«W®özºrpp þü\¹rE§uRW±.^¼Èâ™3é׬N%JÐÅÉ ÇbÅèݨó§MÓÛ¨›7ofýúõìܹs¥ ŒD,#‹‹‹£y§N,ݵ ¿Ë—9Âg#GRºR%ªT©¢ÑZMš4aïÞ½$''Ó±cG½ ÃÿÐG–Ò[„iU¯R«W¯#FŒ ÿþï}=­¡¢Ñ$Áº~ý:ŽŽŽ˜™™¥{Mêó E‰*V‰%ðôô¤wóæÌéлß}G›ãÇÙɾ{÷ø+* ÏÓ§y2k+ºve|¯^ E/T,XÀ½{÷Þ;Å@cËÈ‚ƒƒ©ûÁØ…Ê•+sóæM­×2d¾¾¾lÚ´‰o¿ý–/^è¦Hƒƒƒ‰‰‰<|øP±5•®`e–`Ô®]› &ЧOöîÝK… 4Jð‹)‚­­-ׯ_ÏôZuδ··gÀ€Ìš5Kít¥DÖ³'OXúÝwT>vŒ áá,úªZ]% 'ðo`UD%7m¢BáÂÜ—9ZŠ5jöööŒ?ÞØ¡! –±¥•`9::rãÆ ÖµµµeñâÅ´oßžÏ?ÿ___ÖiSºKÉ ÖåË—)Z´(¥J•ÊôÚêÕ«3}útºwï®QïUjêV±®]»FÕªU3½îÓO?åíÛ·ìß¿_ãX´Q¤HµžLõô)ÝjÕâ·'OP÷è±À¡W¯èæÆ}=ÌUË)’““éÒ¥ =zô gÏžÆG@,£Š‰‰áÞ½{ýeS®\9>|¨È+ß8p€˜˜:wî¬Õ@H‘>¥û°”¬`©S½JÍÑÑ‘F‡ÆÏS÷ç"£þ«Íš5‹ùóçóü¹.ÇòªO—™XêÔaîãÇhzJh9`ųg´pqÑê¹9ݽ{÷psscÉ’%4jÔÈØá‘B,#J«z¥¢D+µádzlÙ2Ö¬YÃäÉ“‰ŽŽVlíœLé>,c&XÉÉÉüþûïüöÛotìØQã繺ºrîÜ93¼N“ Û¥í6á¼qãp§¾–Ï­ yõЉ}ûj¹BÎäïïÏØ±c9{öìGçd al’`ѹsç¨S§NšŸ)`ØÙÙ±téR<<<èØ±#ëÖ­Stýœ(wîÜÔªU‹ÀÀ@EÖSj‹ðüùóØÛÛS¼xqµïQm ÚÛÛãëëK›6m4~nf §¦É@¥J•ðôôäÇÔ8M™››ãá៟ŸÚ÷ܾ}›3[¶079Y§g <:|X±_KÙÝúõëÙ¾};[·n5v(B¤I,#ʨ‚U©R%BCCõòÜÖ­[säÈž?N×®] ÖËsr %· •J°4­^=yò???z÷î üÓ÷iÓ&<<<4znfÇæh“`ôêÕ‹‡d ®¦Û„'ÆZ¡‘E#"ðÿóOEÖÊÎ~øá"## ’t ¡-I°Œ$!!«W¯âìœvÇF•*UÔz#K#GŽdáÂ…,_¾œï¾ûŽØØX½>/»Rr›P©-BM¬´Æ2)R„Ý»w«= ôSÁRY°`S¦LáÝ»wZݯ.wwwΞ=KLLŒZ×ïÝKÝL¶EÕåiP=ˉ†NåÊ•µzCC’ËH2ª^î£ÔåààÀòåËiذ!-[¶dãÆzfvãèèȳgÏxöì™Îk)QÁ ¤bÅŠ)RD­ë¯\¹BXXXš[‚ùóççðáø¹¹eÚ[P¶lYbccÓ=ˆ\— ×¥I/VÐÅ‹(Õž^¸vM¡Õ²—¸¸8>ùäH×®]Ž™’ËH2ê¿°¶¶ÆÆÆ†°°0ƒÄÓ¾}{Ž?ÎÇéÙ³'/^4Ès³ ¥Æ5(QÁR¢z•š¥¥%§N¢qãÆjUÒ«b%%%qóæMè¦æììL“&Mô~ȹ&CG­rå"ý*i¦2P®`A9Vç¡¡¡xxx°jÕ*êÕ«ggš™™‘¬c_ÈÙ$Á2’Ì*X ŸF÷ÌŒ;–Y³f±xñb|||?Ì8»RªK‰ –& Ö±cÇÈŸ?¦¿såÊÅéÓ§iݺ5¯^½ÊðÚôú°Ô•™AƒqéÒ%t^+=uëÖ%,,Œ'Oždzm¼™J ?¹<ŒŽÆÚÚZ¡³¾C‡1mÚ4Nœ8A‰%ŒŽj“ËHÔI° µMø¡Š+²jÕ*jÕªEÆ å-5(Õ‡¥këôéÓ899Q @µ®×ôHºtéBTTTº×¤÷s¡Îwub«0½f÷¨¨(üýýY¾|9#GŽäÕóç(õÞ_PÏÉI¡Õ²>___öíÛdž ŒŠ“ËÔI®À8¬Ô<==9sæ ·nÝ¢oß¾\½zÕh±˜º P¶lY._¾¬Ó:ºV°4©^ýñǸººâàà Ñ3¬5jh½†®¬0nÜ8µ®]¼x±ÖgïíÛ·N:ñóÏ?S¦L™÷> äÅ­[ nÓ†[/^ÐØÆ†½á'nõêñìÉ~ù¥VÏM­~ýú±zõj ¤óz7nÜàòåË\¹r…nݺÅâÅ‹qqq¡eË–Œ9ò££‡µ¬êÍ›7´mÛoooI®D–g–””$¯IXÆ ñ÷÷ÇB?¿úê+¼¼¼p1¡sÊ’““™5k¡¡¡L™2…Ê•+;$“ѼysöìÙC¾|ù´º¿eË–lß¾‚ j|ïôéÓqss£C‡^÷öí[Ú·oÏÑ£GµŠñC=zô`üرôëØ‘ÞÏž1U{NÝrçfñ’%t2D§çÇÄÄжmÛ ‡>þœ”ÊÔåË—)P NNNïýïÃß“?fðàÁüù¿áŸÉÉÉüú믬Y³†öíÛÓ¿J–, @‡5yå í´øávvœ5Ð[æèÊ•+Œ1‚mÛ¶iu¦ÒžnÍ›sêîÝL¯ ¯ =$$„òåËãääDÏž=Y³f k×®¥bÅŠ:DôÏÄù5kÖpíÚ5zõêÅ7èׯ_¦÷YäÎÍžK—X=oí–,¡à£G¸&$à ¸Áü3Š!ÈÜœ{{šõíËо}1Wè-ĬfÚ´i888àããcìP„Pœô`X³fÍØ·oŸZÈðOχ››[†ÿr6%çÏŸgöìÙ4lØÑ£G;£èÕ«>>>TªTI£û^¾|I×®]ñÓâ,ºúõësæÌÌÌÌÒ½&((ˆ+Vh~(::š.5j°ÿÞ=ך•/%çÏgpª­Â/^¤ló]¾|™òåËG5¨^½zJ•*uÕ.**Š^½z©=…ýCgÏžeÍš5¼~ýšþýûÓ²eKàŸ¼;w¦Y³fj¯õôéSŽøùøçŸóæùsÞ%'ÓÊÝ—hìჃqqqܸqC§·O³¢þýûÓ«W/ÚµÓ%=×éÁºÊ™ÿl2’«W¯R®\9µ“+ø§ß©bÅŠ„††jü¶1Ô®]›Í›7óûï¿ãîîÎäÉ“i›Ãæú¨ú°4ýï¥mËÏÏ–-[f˜\Á?½WJn ž?wŽ˜ˆEÖ*Ín__òæÏŸ’P½}ûö½¾)''' *”á:666Œ3†©S§2sæLµŸðàAÖ¬YCèß¿?õë×ïsÕÑ9š$XÅŠ£[ÏžtëÙ€õë×ùQÑÒÒ’âÅ‹óðáCìííÕ^?«zþü9Ÿ}öK—.Ulð¬¦HÆ4ºã>d*ó°4Ñ»woöîÝ‹¿¿?Æ 3Ø™Š¦@Ûq ÚŽhPg{pß¾}888(:è3èÀ\ââYË•MŽŒŒÄÝÝeË–qàÀ-ZÄ!ChÔ¨Q¦É•JÛ¶m±²²bÇŽ™^»cǺté˜4iK—.ý(¹hÓ¦ ~~~:eeeELLLšŸ•(Q‚èèhÞ¼y£õúYÁ… èÑ£»wï–äJd{’`¦ î*Æ:2GWÖÖÖÌœ9“ÁƒãííÍ’%KŒ’A¨`&ªÑ䜚6 Vbb"G¥E‹^§tï@ðéÓŠrì<Žç«¯¾¢M›6Z7¥«L™2___ÂÃÃÓü|íÚµ´lÙ’–,YÂ?üiòÙ¾}{­³BÆ @… Þ›)–ÝìÞ½›%K–°ÿ~òçÏoìp„Ð;I° ('U°Rsuueûöí*Tˆ–-[rèÐ!c‡¤wªmBMh“`íß¿Ÿ6mÚdxÍúõëiÛ¶-ÅŠÓhíÌ$ÄÅ¡d â“%ý‡Ä²eË6lXÊ£££Y¶lnnn¼|ù’íÛ·3eÊJ—.­ÖzªmBmY[[óöíÛt?·°° T©R{¯R+W©EJ”à›L†œ¦ç6°(OJ¥1{*#ùòåÃÏÏ!C†ð÷ßS²dI7nLÉ’%‰ŠŠâÚµk\¾|ù½~®îÝ»®óv´¶oª»E˜Zùòå¹sçŽÆÏ2†E‹qýúu–-[fìP„BZ|Ò‚W´{áâíö· ÷γÏŽ*ëËΟ?OíÚµuZ£lÙ²DDD§Ð`GS6dÈ|}}Ù´iß~û­Öom›……uêÔ! @­ë5©`e´=xüøqòæÍ‹«««Ú±j# €¦M›Òý›oÈ÷ùçŒÓð<½Ã@w.Þ»GñâÅéׯ_¦žØØX~ùå5jÄãÇÙ°aß}÷åÊ•£`Á‚”,Y’ *àì쌣£ã{ý\/^dðàÁL™2…hœì¨888ÿç5‘'Oâãã5VZ¤HÌÌÌéÓ§±cÇR¼xqEO ÆÕkl/¢GGƒzSLÒ”°5¦Ýš*T# –(QÁ‚œQÅR±µµeñâÅ´oßž®]»âëëkì´¢É6¡º ÖË—/¹~ýzšÇAÿ½WÿùÏR†ÇŽ=šY7RÄË‹j––ÜRã~ossfV¬Èá[·(jkKŸ>}˜4imÛ¶åøñ‡?DFF²`Á‚”#Ž=ÊèÑ£3Üv·´´|¯Ÿ«víÚT¨P~ø‰'rÿþý÷ú¹¢¢¢ˆUëû×¶Š•7oÞ”ž1u•+WŽû÷ïë4E^ŸºuëFçÎéÓ§±C Áÿ?èzœl xäòˆÍ[6+WV# –ž…‡‡caa­­­Îkå¤KÅÃÃ???bbbèܹs–9ôZE“mBu·3ÚܱcuêÔ¡lٲũ Õ<³ýû÷¿—äMYº”Œ¨^šVV ~.[€ @Ëܹiçà@ÕéÓ9xó&RS­Z5Ž;ƶmÛR¦þß¾}›éÓ§Ó¿ìíí9~ü8^^^ï𬉼yóÒ¸qcZµjÅ¡C‡Þëçzõê¡¡¡\¸pÐÐP"""xùò%ñññ­£m–6Û„`š[…aaa¸¹¹±`ÁÎh¦ïÔùSDäQæœÑÅ_°;`·"ke5rسž)U½‚ìÝèž™áÇóé§Ÿ2kÖ,vìØÁ”)SÈ—/Ÿ±ÃÊTåÊ•yþü9OŸ>Ít’ºº,???†šæg‹-bÏž=ZÅš™{÷îѧO*W®ÌáÇӼ¦Jü}ù2—/_&ððaâÈ“'˜™›öèßÌœIë6m(\¸pºÏY¸p!sçÎ¥E‹+VŒ0cÆ E¿—2bÄΞ=Kýúõßûµ”˜˜Htt4ÑÑÑ<}ú”·oàhMI IDATßbffF¾|ù°¶¶ÆÚÚšB… áèèÈ™3gpssSû¹Ú&X… âåË—jý:2„“'O2oÞ>>|ýõ×Z¯“ѯ߿þú‹ž={²mÛ6FŒÁÊ•+éÛ·/ÇgÓ¦M,]ºTëçfDÝùX–––)R{{û”~®ž={rüøqÞ½{Çýû÷9wî7nÜȰŸKÛ –б· çÍ›ÇÇY¼x±Ñbúg‘×”ê2(…«β/+éB,=zòä ñññØÛÛ+²^Þ¼y±µµåþýœù¯5Š… ²|ùr¦OŸ®vƒ²¡©Û‡¥N+½·õ1–áíÛ·xzzrøða¶mÛ¦sŸM•*U¸~ýú{_Û¼y3;väÌ™3Ìš5‹… ~Tñ]¼x1ùòåcРAiöCé¢^½z8;;³zõjï-P Í›7çúõëT­Z•Úµkcgg÷^?×Å‹ßëç²²²Ò)Á*P VVV’?~Ê—/Ï¥K—2¼.³ ÖãÇyüø15kÖ|ïë<àìÙ³tíÚU‘xN:EëÖ­)^¼8GUä% U‚•ÀÊ•+iÖ¬÷îÝÃ××—3fP±bÅtï0`£GÆÝÝ3g”íç6lÇÏô¿OZRcffFþüù±µµ¥\¹r899Q½zõ”Ÿ»§OŸÇÍ›7¹sç?æÍ›7ŸwWºtiž (À£G4ŽW]Ge„ œ>};;;½=G˜wwwŠEõϪOWþ}ùñêë¥ûBY$XzÅ«W¯(W®œ¢ë¦ÕÇ"ÞW±bEV­ZE­Zµhذ![·n5vHÔ¨Qƒ»wïòæÍ›t¯É¨‚õðáC^¾|Iõêï—Ú•ª^…††Ò´iS.\¸ÀêÕ«3<†G]!!!|ûí·Œ=šZµj±ÿþ”ž%] 4ooo6l¨Øl´fÍšQºti~ÿýwîÓdèhzoZYYQ¬X1¨V­ZJ?—……/^¼HéçºuëVJ?—­­-QQQZ¿•˜‘uëÖ±{÷n6oΙ"s:3336ü¼Ë.º3j1Ø‚)㦘ÄhcKOô±=ÿL8÷î¯^½"$$Dñõ³OOOΜ9í[·èÛ·/W¯^5j<™U±2J°ÒÚÜ¿?¥K—þ(éÒÔüÁÈ‘#©T©'NœÀÁÁA§õN:ÅW_}żyóhß¾=Û¶mÃÓÓPv‹»V­Zœ9s†5kÖ°|ùrEÖ=z4»wï&44Tí{êÖ­KXX˜Zçêø¬êç*Q¢åË—OéçRýEõôéS®\¹Bbb"ׯ_׺Ÿ+-³gÏæùóçÌŸ?_çµDÖÕØ¥1Ý[wÇ|ª¹v l§'NŒ8NÙÀ²I°ôDÛƒöïglŸ>< ¤„ ³Ú·'W®\Ô/]š;³eÓ&EŸ—]L˜0iÓ¦1gÎæÌ™c´82ëÃÊ(ÁJk{P‰7¿ÿþ{6lØ€‡‡‡ÎÇíß¿Ÿ>}ú°aü¼¼øõ×_ñððxï}T`—.]й¹9C‡U$ÁЦ+u³{FtÓ`aaA¡B…Rú¹jÖ¬‰££# àÅ‹Z÷s¥öÕW_Q­Z5FŽ©UŒÿÇÞ™‡EU¶üÃ0ì   ‹+¤€k¨,®™™¢¹¥¹¤¼i.dfZ¹dfVüÊÌÌ%×Ü2÷}É-QÑQqTÙQÙ”eXøÎ¼ ÌrfÏuyuuæœçÜ£0ó=÷}?ß[î޽˚­köÅ0¼zÓq@G&}?‰ƒG’”$Œ›¸*èéé òóT›Ùøé›×ñt%=ÉW‚ËÂö…i&°Z‚N`i¡3X÷éÃÎ#h¸u+AOŸ’^\ÌŸññËi}à×&L ¿»;ù(Ôv\]]Ù¸q#®®®xyy±oß>­ÇP•]CE=X±±±H$\\\dÇþüóOÞzë-•w÷eee1xð`.]ºÄ¨Q£øòË/UZe¨‚ƒƒ™;w.K–,©Ðû­I“&$'' n©ñÑG1a¼½½ SïCÝÚÚš/¾ø‚Ù³g+|¢KÑ –¢áììLII 6T¨ŸKÞîü¼<úôéøqã8p `ñUFzf:íû¶Ç½¯;ãŽg»ãvB¿ åÒ˜K¬(\ÁÀ%éðA&|#jí°ç—=L´žˆ¸¹ªjÿ}FoÑûzo"ŽF¼òF´¯ö»×OŸ>%99™æÍ›«½VlTõMLh{ô(AiiLº¥ó@˜•ÅGׯSÇÜœ椽 4ˆ‹/rãÆ þóŸÿhuÀ ÖÖÖÞ³"%¯<¨NöêìÙ³ôïߟ‡ò믿ÊÊwÊPRR"ËPݽ{—   ˈÀŠÐTaûöí¹té«W¯fÕªUj­õöÛocffÆž={:¿yóæsÿ~壮…XRJï*¬ªŸ+**ªL?×Õ«WéÙ³'6l̹*毛Oý¦õ¹6ý¹‘¹°˜xïó èpÉ'“Yc¸›V6ÜŒº©•Øt”gɬ%xØ{àò± úúˆ‰à øøŒÝŒq{ÏÓwrh¹fÆuÕ6t³5€PåÁwï2ºS'nK$(Ú"ØÈ+.¦Ïûï3sëV|üüÔŽãeCOO¯¿þš[·n1wî\Úµk§VG¤Y¬Åwe;Oœ8Q¦´¹téR&Mš¤ÒÓáŠ+8wî 4PiÔPVV6l`Ó¦MøûûsàÀÌÍÍ•ZC*°^ôóŠ•+W²zõj&NœÈÊ•+U^端¾bÀ€xyy)d,ÍbÉ¿#E]'÷Š022ÂÆÆ†„„„r±Jû¹Jÿ;’ÍñãÇù믿øý÷ßIMM%;;[6oÑÌÌ ===Ác»~.óÿžOQz‘Bç—|]BÚà4: íÄ¿{þ¥•S+ÁcÒQ97ndøÐádffâ8Ü‹ºœºrФ?“°´°Ä·/]¿éªÐÖ«„N`i¡Êƒ}:ubwzºÂâª4‡Ÿ=CÔ¯ÅEE É—V­Zñ矲}ûv:wîÌìÙ³ñÓ° íÔ©k×®eôèÑeŽW$°îß¿žžÎÎÎÀóÝ©Tx×Zi&NœˆD"ÁÍÍ9sæ(umbb"6làĉøûû«µs¯yóæßp0nÜ8Ú·o——AAA*ÿ>._¾œ€€…Jʽ{÷fìØ±• ,Me°ìì숊ŠâÙ³gUŠ^±XÌ®]»¸{÷®l—­D"!;;›œœ222ÈÎÎÆÄÄ33³2ÿU‡•;VòóþŸÉߣ¤Ij Ⱦ–Mý6"ÒÓ_´EII Ë–-ãÒ¥KtîÜ™àà` 2`Hu‡VãÑý”j!2Xs>úˆ‘ii¸©±Æ`HçÎjÅñ*0tèP‚ƒƒ eܸq!00=z°oß> ¤ð}+ÃÍ͈ˆAÖª ===V­ZEQQQ¥™¥Êèß¿?‰D¡&öªšÝ5U"”b``€½½=qqqž3vìX<== ¨r=SSSlmmeý\mÛ¶ÅÞÞ¾L?×7dý\YYYÉ/ý½;þ]Jލ¹+o D5bßÔ[G‡B¤¥¥qèÐ!FÅ‘#GèÝ»wu‡T«Ð ,"{uåüy ‰§ÞãÇ\:|Xµ^ÜÝÝÙ±cvvvøúúrìØ1Áï!Ï®AžÀŠŒŒÄÄÄDæK¥löjΜ9œ;wŽ¢¢"Nž<©PÏÓ©S§ð÷÷gýúõŒ5ŠM›6É.­"‘''§*Â…d„ øûûÓ±cGÂÃÕ¾þûï¿gÑ¢E¤¥¥Uz^U®îšÎ`ØÚÚ"‘HÈÊÊ*s<++‹·Þz‹)S¦¨\ ‰DXXXÈü¹Z·n›››ÌŸ+55•›7orëÖ-ýôS²³³ lbÄ«‚N` ŒýWWŽ¥½@#@:açÎ ²Ö«Äˆ#8räÁÁÁ/À̈ÿ"/ƒ%¯«töêüùóˆÅb¼¼¼ª\?--þýûóìÙ3,,,عsg¥#xY†êï¿ÿfÆŒ,_¾ooo%ß™âTÇD///BBBXºt)ëÖ­Súú+VT™õ155ÅÃÃ3gÎÈ}] Ê— oÞ¼ÉÀÙµk—à› dþ\Íš5ãõ×_§Y³fÔ©S‡üü|âããÙ¼e3úT4¬|O¸ª3YÖ4ÑÑÑܹs???:¤ñþÔ—À!2X—¯_ÇC x<€ËZ û2bjjJ`` cÇŽeòäÉ,[¶Lu4h€H$*SÆ‘—Á*-°‰óÏ?ÿ0|øpêׯO»ví ¬ô|i†êÆ,^¼˜ùóç«í ¯Õ5òI__Ÿ5kÖ ‘H˜ 6$66–dzpáBNž<‰¥¥¥Æï eû¹\]]I~–L¡GaÕ*‚ê=”­Cs”Θ=z”wÞy§š#ª}è–€rûömµŸMÄb\ŠÉhamMff¦@+¾zxxx°gÏ,,,èÑ£§NR{ÍMG_Ì`ݺu kkkÙ¿?mÚ´ÁÉÉ©Ò5—.]ÊÞ½{)**â£>ª°=''‡+VàííMzz:»víâ믿¦Q£Fj¿/ErdŽ*0räH:wîÌ7¾nذa$%%\á9o¿ý6'Nœ;ˆÚÐÐÂÂB­ !¯W¯÷ïß'66Vm—~u¹÷àt¯ú|8S§NåçŸfÆ ;vŒëׯ+4ÄöU¡N:ÌŸ?ŸáÇ3nÜ8•,_ìÃz1ƒ%Xk×®eèСXXXÈ]çæÍ›x{{Ó¤I²²²8xð`9Át÷î]æÌ™Ãرcqrr"88˜1cÆTë ÌÍÍ«uÖ<ïZ·nOŸ>UjAUó +XÚ(Ž5 ___ÆŽKÓ¦M²nÐ$¾|… ôó&É] ­[·f=e8qâŽŽŽ²VÇ+µsYÇÿÐ È•+W˜0Aý¹YúôaÉš5 À¼¶+"í{õ¢~ýúÔ¯_¿Âòå³gÏHNN&99™¤¤$RRRˆŠŠ’{üø1ööörÿ888`oo_á â—‘N:qàÀÖ®]K¯^½˜={¶R;lD"²RÒ®;ÈÉË#22’¼¼<°²²bݺu„„ÈÏgþùçŸ?~œ®]»boo_ÎßêÊ•+lذG1zôh¾ÿþ{µÞ³ÐH³XÕ Ÿ|ò çÏŸ§k×®¬ZµªÊ>´V­Záëë[¡ÐêÔ©sæÌ!33³œàÕdëÉ“' 4ˆ   ÜÜž»èY[[“‘‘Azz:ÖÖÖ¹oUx{x£YŸb(†BSϦꯣC.K–,!((€ëׯËzét(^qqñ«=.\@<== U{ÂÂB:7iÂ?II˜©¹–­-›CCe[ýU¥¸¸X&¶^ü“””Drr2FFF2±åàà€]V·n]5ßMÍ$--ÀÀ@JJJ˜={6õêÕ«òšï>ÿœUAAääåá%ѳ°«zz„ð°°ßV­x½woÚwèÀ!å“gÍš…¥¥%!!!|ñÅøúúÊ^ fãÆˆÅbüýýé\CÍfW¯^MII ãǯîPdH$ÆO=2T4iþþþrww.\¸ 0lذ2ÇGÅìÙ³eH(®^½Ê¬Y³Ø½{7¦¦¦r_www×ÈøEp×뫯ƒzëè¯×gZÂ4æ=_˜À* !!±XŒš×"¶oßNll¬ltØÏ?ÿŒ“““ÜÏ U£XqõêUV¬X¡öY)Ç÷îå—aÃø[ §ä™¢¯O³Y³˜üÝw‚ÄT™™™2±%Í‚•`Ïž=+“ù’:_—΄‰Åµ7©zöìY¸x‘Í!!?~œÅ‹Ó·o_nܸÁ‰'€ç¥Â7Ò©S',XPkškB£{ELž<™sçÎáëëËÊ•++Ì -®X±¢ÌñV­Z‘••E\\\™šB——-[FFFF•w–––dddðäÉ…²¬BÓÓ§'o¿þ6–å2d 1bûŽíÂVzzz”¨ðÙ[[Y½z5£F’‰«3gÎàáá¡Wj Ë` Ä'Ÿ|¨Q£7gÙ¹3í.^ä %~Ñw¿5lÈÉÈHŒÕΪmžV­Záïï¯ð5ááá´nÝ}}Œ?•¤yæÜŸrÞUî:Ãq†Li;…ù“5[”’˜˜ˆH$’eˆ_fòòòèÙ³'gÏž•òçôUE'°¢ô”q¡™6d¡r@"ÁªŠs‡PÒ®Û^Åò²››[F€½X†LJJ*'º^Ì„ió‰ìŸþ!00OŸ&¹¸sש¯OJëÖLœ=›ØØXvïÞ¿¿?ÿùÏ0444fmRYSMâ·ß~#..®ÒræØ±c™2eJ™ÒìÇ™:u*»ví’ûî»ïh×®ýúõS+¦aÆ1aºwWÎ`êéÓ§$''Ó¼yeyTÍQXXH›^mˆtE&Þ<£÷Œ˜0x¿ÍúMÓáÉx•Ö‹½Vùùùtï޽ 6:CW"€7nàææ¦±)ã¿îØAÈ©S ùøcÒââðÈÍ¥=Ð ¸ \.aâèÈøÙ³úÂSôË„‰‰ ÎÎÎ8;;Wx΋¢ëîÝ»œ={VvL__¿Ò,˜­­­`ñvïÞ?ÿÌ(5ÄÀ–¢"Œ¯_Gõj>üð׿ƒOZ&¬éë³Ï>ãÌ™3¼ñƬZµ —rç,_¾œ=zp®ÔhªÆcnnÎíÛ·e;Õ-&''3hÐ 6mÚ¤R?•……]vLç}% :%Bù_UF—7ßäxDW¯^å¯U«øóäIÎ8:bhlLûÎöÖ[xy{W[Ú¿&agg‡¯¿þºÜן>}Z. );öäÉ“2%ÇòÎÅÇÇséüy„ðÑžä»»—Û•V›qqq©5bÑÇLJC‡1~üxúöíËðáÃ˼nddÄ?þÈ´iÓøµÔÆéè©ÀRÇëÒ¥K|ÿý÷jgË5jÄ7°²²Ò؃aE;v ‘HÄÆ_6’8-‘…«rråIî…Ýø±1Y7³°lb‰©•)ý¼ú1zÿh6lØ XbéÒ¥åÆF>|XË¡WÀ€+W®hmk»ví¸Ñ© [¶Tz–šŽçXXX`aa!7 Ï-)J—“““¹uë'Nœ333+'ÀJ—!¥~C×BCy-[˜O­KJXù÷ß0_;=(ÚÀÅÅ¥ÚǸ(ƒ™™[¶lá×_åË/¿dÁ‚e^ïÖ­—/_æÏ?ÿdĈôîÝ›÷ߟ©S§`llLž ½x;wîäŸþáÀ꿞ÏVŒŽŽÆÕU¨Á\USPPÀ·ß~+3ÙuttdáÜÿ•]ãââ¨W¯¦¦¦ìß¿Ÿððp¼¼¼Ø²e çÏŸ¯±–#µ•Û·o“˜˜X¦Ï*55•øøxA7m½ªè–\½z•ÿû¿ÿÓÚýâãã+ÝÕ¤C=D" 4 Aƒž“žž^F€¥¤¤.;–ƒƒ™‘‘thîœpùî]AÖª)8;;GAAÖ3)ê0mÚ4NŸ>M= ¢Y³f²×¦Nʈ#ðôô¤yóæX[[ãââÂÅ‹ñöö&33“7nàãã£ð`íE‹‘ŸŸÏï¿ÿ.Ø{033ÃÜÜœ””­YÈ¥¥)½ÛÒ××—%K–0gΦL™Â¬Y³tK`JÄ‘rèÐ!üüüª)¢— ÀR“ˆˆ7n¬ÕÆéøøxÙœ:Õƒµµ5ÖÖÖ Ýüü|’’’Û¯žÝÓ0ÖÓ#!!¡RñWÛ~nÕªUu‡¢o¼ñíÛ·g„ 0€÷ß_öÚòåË2dÇ $'‡‰ýúñ 3ÀO,fè¶m<((ÀÃÉ ¿#øòÛoåÞgêÔ©xzzÊ2bBÒ Anݺ…••U™QMš`ß¾}ØØØÐ¥K…η´´¤I“&\¿~¶mÛÒºuköïßÏ»ïAo½k IDAT*¹ýP‡\BBB066¦C‡eŽ=z”ü±š¢z¹Ð ,5ÚÿJâããu£ j8†††4iÒsss \7["aîܹ8::biiI:udþc¥ÿXYYÕÿi£{mXð|6åÖ­[ùå—_˜1cóÿ[¾µ²²âË/¿dÚ'Ÿpaß>=~Ì ‰À  €àò½{Üþ¿ÿÃméRv>L›RV/ƒfêÔ©tíÚUcïAZ*ÔdV<++‹%K–pòäI¥®ëÖ­gÏž¥mÛ¶L™2…ê–@,Y²¤œŠŒŒÄÀÀ ÒMD:G'°ÔäêÕ«ZM§‘ššZcüžt”§¸¸˜¨¨("##ééq¥-ä’è2fÌ233ÉÌÌ$++‹ØØXÙÿKÿdddŸŸ_Fp•`uêÔÁÊʪŒ@“ž£í5ÙpTQ¾øâ N:EÏž= ÂÙÙ™:ùùüÄž¢"*rÇ3|ŸÂBÞLOgÈo0oÑ"Ú÷éÃàÁƒÙµk—Úc®ªÂÄÄ+++’’’4ö¹2}út~þùg¥¯óññaÖ¬YLš4‰:uêðÞ{ï±nݺr~c:”ãàÁƒ´lÙ²œª-ƒ #77—:TÛt‚ªÐ ,5¹råJ¹!»šD—½ªY<{öŒ¨¨("""ˆŠŠ"**Šû÷ïãââ‚««+-ºt!ôâE ë2ÐÎÙ™6mÚ`aaQåù………e׋",66–¬¬¬rç+-ÊÌÌTŸšéââ"Xãvuòæ›oÊJ†­6äôÊ•$)|½ .‘0à³ÏX¼b¡ááš ö¸sçVVV˜lNü×_Ѽyór¥(EpvvF"‘ÈÊâtéÒ…>ø Vû¿U7K–,aÛ¶måŽ9rDîñšÀ­Û·˜öó4BއP W€¨ƒ=[=ŠgSò¸7/7¾ûô;úûõ¯îPeè–Ü¿[[[­ŽoÑ ¬ê#55µŒŠŒŒ$++ ÜÜÜðôôdäÈ‘e è»f dd¨}ÿ;úú´ëуäädîß¿/;VVVˆD¢rç‹ÅbêÕ«§´Ã{vv¶\Q&Í–ÉeyyyrEÙ‹íÅsÄbñK‘Á’beeŶ¿þÂH,橊cVöæçcÁ£¤$lµ˜©vvvæÞ½{‚–jSSSÙ´i‡Ry Μ9#³Å˜2e ‹/– $Ö¡›6m¢oß¾²ÎR.\¸€››[¹ã5ñßgó¶Íä-Ƀ-2áÆ•Œøu^»¼øgÝ?Õf9tNîjðâäqm°mÛ6âââøâ‹/´vÏW‘˜˜"##¹{÷®LTâææ†‹‹‹,CåèèXåZƒá¾w/êºÊˆx^~ä¿ÿÍÈÈ ++‹ŒŒ ÌÌÌdbKÓÍÊò(**ª0SVZ ½xŽ¡¡!VVVÑ,º –\»vMé1ê¢Ë` KAA,%ýodd$ 6ÄÕÕ•æÍ›ãïï‹‹ VVªý²þøcÞÛ·Á%%بçCCv,[&û‘HDݺu©[·.ðÜ<5++‹{÷î¡§§§u1¢¯¯_&EÉÉÉ!##ƒŸ~ú š7o.aqqqrEYNNŽÜLYe¢ÌÒÒR+6ÿþû/Ewî¨%®ºm=bïž= 8PˆÐÂÞÞžÈÈH²³³Õ*û¬_¿oooµÄ<Ó¦M#//O6ˆXšÅšÿyÂiy¦¢R>̼yó´Qå4öhLüôxªÄEÿ‚÷ ¨kY—ÂÂBDzå³ûÚB'°Ô ,,L뙤øøxÁJ¿*dffÊ”´Ì'ËF¹¸¸Ð·o_\]]û2þꫯ())aì¸qôX·ŽðBå÷êéaØ©ƒ?ú¨Âs¤æ© 4 //ÌÌLÉÍÍ-SJÔÓÓSç펩©)¦¦¦xzz’žžN¯^½ª¼Fš½“רŸ••EBB‚Ülš\Q&-_JÿŽJ¿®H¯[i®ž>M½'OTýë(ƒCFaGŽhU`ÁóRaDDmÚ´QyØØX:ÄÎ;‰IZ&|ûí·çýn[¶l‘Y8訚ŒŒ öïß/³)MMlnÿøÇIè• œ¸’bì¯!^\ÞyYèÐF'°Täáǘ››+ýÄ®.º –b$&&ÊJ|RQ•——‡««+®®®téÒ…?üPcÛ‘ÿùçfΜÉ?üÀ‘#GpqwçFÛ¶8ݸÁô±XL¡¯/•pþ666ÆØØ;;;ŠŠŠÈÈÈ ##ƒ`aa!5©IØÕÕ• 6(tî‹Ù;EÉÉÉ‘+Ê233IHHàÎ;åDYvv¶R¢ì‘#¼¡Âû—G`Éϵ‰vvvj}Ö¨ºk°"¤v RÿËb­]»V°û¼ÌÈ3•räÈFŽ©åˆ*&ênëÿXOI¤LƒàÖ®[¬ÛºŽ1ëgשN`©HXX˜J»bÔ%..®ŒÛ±¸wï^™_TT²_ÿþýquuÕš[õœ9sH$\¸p!C†Ð³gO8À¶ãÇIOIaÈ›o2ôñcú"¯8¸ 50`æ§Ÿòù‚äååáííMHHb±â¿¶úúúeݳ²²ÈÊÊ"** }}}™0P·¤.Úht—fË”±"(..®P”eee‘””TF”»t ¡:2=€Ë´šrÔ¯_Ÿ»wïòôéS¥³x+W®äí·ßôáÅÇǧœgSÛ¶m±±±áÔ©S¼ù曂Ýëe$&&†›7oòÍ7ß”{-==ÈÈH:vìX ‘Égêü©H~“¨½Žä ÿ÷þÿéVmãÚµkZ/Õ%''ckkûÊtÎËË+g‰‰³³³¬Äçãニ‹‹Ò_ BpæÌfΜÉ7ß|C‹-ðööæý÷ß'**J¶‹ÊÚÚš°ÄD†úù±úüyŸ>ÅC_Ÿ>EE\‰ÕÓC"3ðí·¹³j ‰‰allÌ… èÒ¥ 'OžTÙDTšuiذ!¹¹¹dffD")cÁ íR¢¥¥%ÆÆÆZÛ¢"‘HæÚ¯ÞMš`'Ƚ-k## •ÕBáììÌÍ›7+š.ˆˆBBBØ´i“ ±˜ššÒ¢E‹r¶S¦L! @#KOOw‚Ö4ªÊ^õîÝ[ËUι“ç@÷#ˆ»Ç“'O”ÞM-:¥"aaa|üñÇZ½ç«TLKK+'¤RSSe–mÚ´aðàÁ¸ººÊµ(Ð6ß~û-OŸ>%88˜ .ðùçŸóÆoP§N¹}zéùù\މÁØØ˜Ë—/sýúuFØÛ³ÈÓ³L†R_,æáÇ899!‰¸pá¾¾¾ìÝ»WííÔ&&&˜˜˜`ooOaa!¤¥¥S¦ü¥­Ò,VMXÊÒØÎŽóqq `­Ë€M:Õ"®àyö³Aƒ<|øPa³ÓéÓ§¤‘x¤eÂÒËÑÑ‘.]º°cdž ¢‘ûÖv®\¹BNNN…Ó>¬U/Ǫxôè¹9¹ÐD˜õŠ;V¦¼¬-tKÑ×××úÁË*°âââÊY"Ë,ºwïÎĉ5îh­ çÏŸgƌ̜9???6mÚDhh(ùùùøùùñÆo”»æôéÓ¸»»Ëv%víÚµÂ?kkkÒÒÒÈÌÌÄÒÒ€àà`Þ~ûm6mÚ$ØÏ X,ÆÆÆ›çû¥%°ˆˆˆ2Íáš¿#X>>>»‡¦éÐ¥ a—/ &°<Ú)Ú­§lll¸ÿ~™Ÿ¿ŠX´hÆ Ó˜¼S¦Lá³Ï>+sü³Ï>£{÷î:UK–,©ÐJ(::š‚‚\]]µUÅ\¾|±‡˜B†ŒyqöòYÀª-TÇüA¨ý«¤¤D®%‚¬_êý÷ßÇÅÅEöE_“ùþûïyüø1ÇÇØØ˜ÀÀ@²³³¹uë›7o®ð‹fß¾} ¬øWpãÆËíê:vì}ûöeùòåžRAÕ¨Q#YsøÃ‡)(((SJµ )kž}ûòSP(±)¡"®ò†ÇpU„³³3×®]£]%bïÚµkܾ}›©S§j,ŽF¡¯¯ÏƒhÚ´©ì¸áÇG­\¹’‰'jìþµ‘“'Oboo_¡ylM,J$ôê Ø¢P 󄜫8:¥W¯^­ôÃFSÄÇÇÓ³gO­ßW²³³ËY"ܽ{·Œ%Â[o½…«««à£94ÍÅ‹™1cÓ¦M“ ž0auëÖ%33³Ò¶Ož<áÎ;J ï500ÀÆÆ¦Ü¬¸ƒ2xð`æÏŸO³fÍTCUPº9¼  €ŒŒ ?~\ÎM^ÝR–‹‹ ‹-(êê¡G|neETr2.j¬“ Ô×g] ˜¹§§§G“&MÊ ›Ò|ùå—ìØ±Cã±Hí^ŒcìØ±¼ù曌9²Zú/k*K–,aÅŠ¾~øðaÖ¯_¯Åˆª¦C‡NN‰Î‹ðS=ÖF:¥W®\áÃ?Ôú}kj+55µŒŠŒŒ$##Cf‰Ð¡C†Ž‹‹:_95ƒü‘„„:„™™ÙÙÙ 4ˆfÍšaoo_n§Ó‹ìÙ³‡*ø988pëÖ-êÖ­[Æ©}×®] >œ9sæ¨mè¨ØÚÚbkk óžJLLÄÈÈH&¶TÍŽŽŽ<}úT¥k5‰-2¸sgnä竼Æ`V­\Yc|ˤéééåzÿ~üñGT6âU†nݺñûï¿3zôèr¯Im¾þúkÇQعs';w®Ðí>,,ŒFQ¿~}-GV95B_¢OAjš8LŒçïžê/¤Ê½«å®µ˜ÔÔTòóó«EèÔ‹†”³D000e¥zõêŧŸ~Jƒ ª5N¡¹|ù23fÌ`Ò¤IÌš5 €Û·o€ ýúõãwÞ©r}ûö±zõj•bhܸ1>,3ë`ëÖ­øûû3uêTÜÝÝUZ[U¬¬¬°²²¢qãÆdgg“••Ń(***3ƒPQ¤}XŒZ³´jßž÷üý™²~=‹U0–/Ñø­·hÛ¹3±±±4i"P·¯š899qõêÕ2†µ.\ ))Iö;¡iÜÝÝ‰ŽŽ&++«ÜÏUÿþýÙ²e 111899i%žšÌÒ¥K9räH…¯×Äò ”¶ÛréÊ%¨ú#µrRÁTßT£#•*C'°”¤ºÊƒéééi´É¸4………2K„ÒfŽŽŽ215jÔ(\\\jäpP!ùù矉‰‰aÏž=²õÇóÇPXXÈ/¿ü¢ÐúÅ‹iÒ¤‰Ê³Í,,,HKK“»åxÆ Œ7ŽqãÆáåå¥Òúêbff†™™äçç“™™Ijjj¹Rbe6#...DEEÕj07(ˆ ·e « ¾n–HDZ÷î¬úo/Ú“'OÇÙÙ¹Fdõœœœˆ‰‰‘y\MŸ>]®3¸&‘î&ô“ÓŸ&ÍbýöÛoZ©¦±zõjFŽYé÷Å‘#G˜>}º£RœÀÏé÷]?òÞQ¯—Qü‹˜ÉŸL®¶L°N`)ÉËØàž••U¦_*22’‡Ê,š7oNŸ>}puu­QîßšæêÕ«Ìœ9“>ú¨ÌQPPÿþû/æææ„„„(¼ÞÞ½{0`€Z15nܘk×®ÉõtY½z5“&MB"‘Э[7µî£.†††²RbII‰¬”‰‰‰LlIgËIquuåâŋյ°|½nANNÔÿáP™dŒú1rôè2;¾êÕ«‡••ÑÑÑdddT{ÛÊÊŠÌÌLžM‘ÂBºÿ¡úú\útìÈ÷kÖÐÜÕ•¤¤$€r»P=zDrr2NNNZâ]W®\a×®]jýÞøúúr¾‚1B‘‘‘|ÿý÷lÞ¼Y­ûTôïPÓY°`Mš4aèЊ‡ø}þùçôïß¿Æ[¢Ö3¤0¼TÈ-60$òb$MV_‰]—Á’ÃÑ}ûXòõ×üsç"ž……Ø‹D".–”ðÖÙ³|öùçLþê+­Å¤JÿÕýû÷ËõK™™™•!ãââ¢rÉêeäúõëÌœ9“Ñ£Góù矗ymäÈ‘dggãïï¯t£ºªÍíò°µµ%22’ììl¹#n~ýõWfΜ‰D"©q\ÌÍÍ177ÇÑщDBff&ÉÉɲR¢Ô›G[§šÆÆÖ–'N°Z"!ìòe.Ÿ9Ã¥ØXÌÌÍß®^ÞÞev:88È2V¥Çmmm±²²"&&33³jís\´hsçέ–{àááÁ… èÔ©S¹×¥ˆ5¹ÇHS$''sæÌ8Pá9ÙÙÙ„……±páB-F¦………¼ûî»ìÞ¼›n(^U #¼ø_0lÄÅ3«U\.ƒUŽq=zpþ<‹%šWpN ð›XÌõFØ‚Êܹsñöö–û…)‘Hd%>i¿TDDNNNe²R...J5¿jüöÛoܸqƒŸ~úI¶K %%…AƒQXXÈüA‹-”^{È!,X° ÂmîÊ’››Ëƒ*eîܹ´k×Ní²¤¶(..&##ƒ?þ˜áÇӲeKY)±ôÎÉ—…GñôéSŠŠŠÊm\¸yó&...rË8)))}:½{÷¦Y³f—ù]ÑÛ·o'66¶BÍ'Ož0räHŽ=ªò=jcköìÙøúúVjª¹cÇbbbjlÿU\\C‡eÇŽ >œ3gÏÐíƒn„å…=ŸOXQ6+ `bÏÙgiÜ ú©u¬ÿ’Ÿ—G£zõø¿Ü\ÆVq®°¸°à˜Z4i•ðp¹¹i4¾øøxLZZZ9³ÎäädY‰¯E‹ 077·1B¦6pëÖ-fΜɰaÃX»vm™×.]ºÄ¬Y³hܸ1[¶lQéï4<<KKKÁÄ<scaaAjjj…Û¬çÍ›G`` ùùù•– j "‘ˆºuëÒ¦MJJJ°··'++‹{÷î¡§§'+%VwyL(ŒŒŒÈÌÌäÙ³gr_wssãöíÛ´mÛ¶ÜkvvvX[[M:u´¶KêðáØ˜˜Ð½{wnܸ¡ÕqJR|}};vl…«^½zôîݛ͛7óÁh5¶êâÎ;ÄÅÅUéX~äȪåK—øé§Ÿd#ÁþþûoôÐãÜæslݽ•yþóˆ‹(ìPÖ ¡¦™‘S>™ÂÜóÕ“Y•‡.ƒõ_[ZrìéST‘Iv††„ß»‡½ÀMèñññ2!µiÓ&êÔ©CIII™Œ”««kÙÆ]Yºt)aaaüôÓOåJ¥;vì`ãÆxxx¨U™7o:t oß¾ê†[ŽððpZ·n]éμ `ooϨQ£¿¿&÷„——Gff&™™™äææ–q“¯­‰„{÷î!‹iذ¡Üroff&?æµ×^«päädÒÒÒprrÒ¨ionn.½zõâÌ™3²cÏž=#11±Z<îFŽÉܹs+½·§§'¡¡¡*­_Û2Xü1~øa¥ÍýñññLž<™={öh12ÅØ»w/Çç÷ßgðàÁ,Z´H¬¬,._¾Ìù°óHò%x»{ãÑÁ£F¶ºè0uà@šîÛǯ¿|Ѩ!±±*Ç Ï¡nݺ¸ººâääĦM›Ø³gOµ¤ã_F"""˜1cƒ–kZ¸páBNž<ɨQ£>|¸Ê÷)**¢K—.üûï¿ê„[!ééédddT¹ébÉ’%˜™™1vlUùÙêçúõë,^¼¸\6QJQQ‘lWbff&æææ²RbMÝUW®\ÁÎαX\á\IE¾èóòòˆ‰‰ÁÊÊJc‚`òäÉŒ9’Ž;–9žPiüš"((}}}>úè£ ÏÙ¼y3Ož}‹Å?~\æá}ûö1{ölµ×© yàå1qâDÖ­[ÇâÅ‹Uz¢×FFFØÛÛ+ìb^§NêÔ©CÆ ÉÍÍ%33“øøx$‰LlYZZÖ˜±3¥122B,W؇%ÅÙÙ™7n`ffVi¿“ƒƒVVVÜ»wA²Jiiiñ÷ßWxŽÔ€ÔMý¨¥iÙ²¥¬$„°cǸrá’Ü\ ŒŒèй3  Öõ£££>|8:uÌ:22’’’éT4 ZcÆŒaóæÍ,X° Â td޲ý…&&&˜˜˜`ooOaa!™™™¤¥¥#bÕÑ”]FFF`hhHnnn¥=Tnnn iZµjEBB‘‘‘8;;«õ~§OŸÎÏ?ÿ\é9¦¦¦XZZ*ô3($¾¾¾WjòÎ;ï°eË"""´*µÅâÅ‹ò«I¶ÅÅÅôë×ÀÀ@ÜÝÝY·nfff¼ÿþûÕš ¼Ò+11½‚„ú8ð,*âqJ #?ø—JŸª”!!!WWWAÖzYÙ»i‹¿ù†âäd:H$¼ x¡@Xp0—ÄbÄ zêÿóŸ2מ:uŠyóæ1qâDA‡x áÜ®( ƒ–Ç|ÀöíÛ ÔxvMU¤#sªÚUb±˜zõêÉ\ï333ÉÊÊ"""YfKÛ6¥144$??sssž={V©À200 qãÆÜ¿¿Êl@ƒ ÈÎÎ&"";;;•†únÙ²…Ö­[óúë¯Wy®ƒƒwîÜQyØ·*tíÚ•}ûöUé1'Íb­X±B+qi‹-[¶Ð»wo…¾k>Ì¡ÿŽ`ªN¤;â8@ýúõÙ·o‰‰‰/åîÚ¹ýF ÂÂÂè*à“l§’¬ŒŒèر£`â t¬ªíãÃÆ>âTl,Á ¿ÍyîM·8[XÈ?±±ü5a#»v•]ûûï¿3gÎ~üñGAÅhW`Áÿ†A+ÂСCiÕªUµ™EV…4ƒ%$–––4jÔˆ6mÚȲ˜>äÆ<|øÌÌLAï§FFFH$ÌÌÌÈÎήò|© ”öU…™™mÚ´!??Ÿ»wïR¨ÄðéÄÄD¶oßÎgŸ}¦ð5ÒR¡¶ðññ)³«±"<<<066V¸¯¯¶°dÉ>ýôÓ*Ï;sæ :t¨ö¾ÄK—.1yòd.^¼Hýúõ9wî§OŸ~)żâËÐÐÌázü³Q%ÛåUE÷W…·]\xûÜ9v H‡ÍŽ‚úž?Ï[Íšññdz}ûv8@çÎëСCôêÕ ±X{Ib yòä‰Bç0ooofΜ©áÈ”GšÁÒ¦¦¦888àææ†››¦¦¦<~ü˜+W®ÍãÇ)PbH³ªH–4ƒ¥äää(%6lˆ½½=·oßæñãÇ ]óå—_²`Á…ï`llLݺuILLTê:uPTdI³X/ ¿ÿþ; Ù”Ô„w)n IDATòàþýûÙ°aƒÌ"âÎ;¬ZµŠE‹Uk\šä•X\ðCô²H„‡ÀCv‹‹‹III©;Y´Í`OOÆß»‡²6‚ÃÉÑќ߶àà`A³R´½’¢L  OŸ>ôìÙ“iÓ¦i0*å©[·.úúú|¨”´°° mÛ¶äääpïÞ=Š‹‹+žà®+ÊçÏeË0 ç=¯ï¸?}ÊF <=ÅÆÆ’žžŽ»»»àkW…žž 6$..NákzôèÁÀ™4IÕ±õšAeBE°²²¢qãÆ´iÓFö»÷àÁnÞ¼I\\YYY‚ÝK__=== •ÊbÁÿšÞ•¥qãÆÔ¯_ŸëׯËÍvFGGsüøq&L˜ ôÚR´Y*T4ƒ/OK™À‡®Ö™¤sçÎE__Ÿ9sæÿkp¯ ý`šæ•XovëÆmÖIš::ªÔHZºò`yž={ÆoßÏf%úIäñGa!+æÏ'##C ÈžS]Ù+)¶¶¶äää(•AèÖ­þþþ5Ê€PÓeBE033ÃÁÁ-Zàâ₱±1©©©\½z•˜˜ž%99Y¡ó‡ ÂùóçIHHÐh\B£Lö ´_¼|ù2\¼x±Ì¹sçâç燗——Öb© èÖ¹Ç÷ 2O‰LÖÀJ_Ÿ'©©hhȬ®ëüõ×_øûûSׂŽUŸ®^€AI‰Ú}4)))ÄÄÄ”†[¨R*„ç_Ø‹/ÆÏÏOQ)ŽªÜÕ‰‘‘õë×§yóæ´mÛ+++²²²¸yó&wïÞ%%%¥LyJšÁöÃ’‡¼¿««WÐsLOì^·Ã´Ž)]&vÁÔΔÖ}ZóÉœOd àïïOóæÍqwwçñãÇĪ1¼¾4666hÜgìeÏb:u [[Û*ü¥DFFb``€³³³†#{ÎþýûY»v-ûöí+s|É’%4kÖ¬Zí« À*EØÃ‡ðᇸŠDó¼qýEr€3À ccŽvíJnAØæ/E—Áz> müøñ$$$pøða²KJê+7 x”›+ˆ_UMÊ^I±¶¶¦¸¸X¥/·F±~ýzzöì©È£&4º«ƒH$ÂÚÚš¦M›òúë¯ËFøÜ»wÛ·o“@QQ‘L`©šÁ‚ç™°† ÍõÈë8¼îÀ©_pÒç$6?¢8¯˜”c)äÝÌãö§·Yn¼œNc;1ò‹‘DGG3tèPàyùóµ×^ÃÜÜœððpAvMj£T¨L@÷îÝIKK#<<\ƒQ ÇÒ¥K™Íèèh.\(sm•Ñ ¬ÿ’’’Bpp°¬¡*Ì®]»4Ó«fÑÍ'ŸCú Ù¡†·Ó(¸˜y‘­û·Ê}Y,ãââ‚¡¡!7oÞTyw§³³³J樊 l ž?|øøø°mÛ6Ĥ¬]»–‰'*u&û¯ñôô$((ˆöíÛ—y-##ƒ &ÔÈ¿Ëê@'°þ‹² „íÚµ#33Scðj•÷ïߟŸ£FbÖ¬YUžÿë¶m,27GÕÎ$àGSS– ’÷ìÙÃÀÕ^GÓXXX```@ZZšZëœ={–jeN ¼«2«ìííquu¥eË–˜››“––Ƶk׸ÿ>=â‡_~ û“lh®^ùå3wÙÜJÏ©_¿>...<|øP¥¡ÎVVVèëë+<”\,,,xíµ×¸¦¤õм,–žžžÊ½pB¡li4+®Â 44Tî|ÜWÉ¥]t ˆŠŠ"&&†^½z)u¦³X¯B‰077—)S¦ÎéÓ§ñööVøÚãçÏãom²û㞣¬¬8¢ä•òÙ·oýû÷d-MÓ¤IA¶ßŸMSÖ+xÍFÀQ,æ÷þÁíõו¾ç‹„……aggWkþT]‡fÒ¤IÍâ«‘Á*]"Åí,--iÔ¨o=ùu¥‘xJ Vè\{{{š5kƃ”ÞD¡©R¡*}X~ø!»víÒjù»2TÉ^¥§§A§NeÕªU„……±råJ¹¯=š_~ùEðY¼µW^`…††RTT¤RŽH$bÀ€ìÞ½[ð¸222000Pª±±¶ŸŸÏ´iÓ ãÌ™3tîÜY嵚·iCºD¹=˜bk˯@0 }öÏ΋€©66œêÞ¬ü|\WPó›Ûå¡Ê0èŠØ»w/³fÍÒ¨è«(°”1MJJ¢ˆ"(_±Q¦˜À‚ç±·hÑ€;wî(¼‘¢N: ^jnÚ´)ÅÅÅ*õ~öÙgüö›ºÝêɃ”®ªh¢¹ý»ï¾COO¹så—Ž§NÊøñãe?:þÇ+/°äíT†AƒiD`½¬ýWGŽ¡{÷î 8°Â_XUX{ü8o¯[Gâðík¯a/ó~ãÆÔ‹ùÚɉø‘#ykÝ:þp;¶D"áŸþÑH:^Ó¨Ûð^šmÛ¶Èõë×YïELLL°±±$ëVS‰DèëëSPP(g8e/Ká‚iƒJ ì4mÚ”{÷î)<²¦Q£F$%% 2I¡4ª” úõëÇ­[·4ž•­ U²W ¼Àš8q"íÚµ+gà å‡~à7Þ k×®‚Ýóeâ•X'OžÄÁÁ–-[ª¼†««+ܼySÀÈ^¾ò`qq1_~ù%.\ $$„nݺ ~???~Ù¸‘îÞåi~>??γü|‚ïßgá¦Møõí+èýjcöJŠªÃ +bÓ¦M,^¼˜ÐÐPAÖ{‘W-‹%‹‹Å Ybxxxðxëcá9¨öpgbbB«V­(..&22R!ÓOM” U-BõÛ6üû￈D"¥çöEGG“ŸŸ/³R—þýû3nÜ8úõë'÷õ+VàèèXkúO«ƒWZ`©Ú{õ"šhv™Ö±cÇèÔ©~~~ÿÏÞ™ÇÕœ¶ü]Ú•e/Ldl¡’,e¬c cÔÛÊ6YƘãñ`È2d'ɾ„YÆ6e©$…Ê–ŠB¥’ÒvÎï¿Î£:ÕÙÚÏûõêõÌó=÷}¯“ê{kù\å*<ת•œ-U¥P•,}tqxzz²{÷nÔ<ð1­ZµâáÇ ?·2!k–¦¦&†f†p_1v¨ÞT¥Ÿ•|Úp7¦iÓ¦"ÁÔ’ÐÕÕ¥víÚ$$$ÈuÏéÒ¥ ‘‘‘2EâºwïNnnn…Б5z¥¨âö—/_ÒµkW¶mÛ†¥¥¥Ø5G%==ï¾ûNîûUgj¬ƒuüøqlll¢3õå—_âãã#³ˆ£8ª‹ƒõóÏ?ãççGppp¥×‰’†û÷©‰™YQõ몄"S…[·n娱c\¾|YagBÕú,-w‚tiÂ.V]>Œ%Pj7Ô°µ–¿HºvíÚ´oßžììl¢££KL6iÒ„W¯^I5æ¦4ìííñó“¼–ìc\\\ðôôT˜-’rîÜ9ÌÌÌdúpxæÌ¹‡³‡††2eÊ‚ƒƒi\Œ˜óÅ‹ eþüùrÝ«&Pc,yk¯ £èŽÂªî`]ºt kkkú÷ïÏòåË+Ú…SÕ£Wù——§ÐΩõë×sîÜ9…êáÔ´!Hç`Í9ýk ¨Ã Óv¦ÉÖÿÓ´iS7nLDDD‰íŠNöìÙ“«W¯Ê´·uëÖ4oÞœ+W®(ÌI5zJÓ¦Måêâ;sæ îîîœ>}±kÂÃÃñòòbåÊ•2ß§&Q#¬={ö0räHôôôv¦¢Ó„UÙÁZ¸p!.\àÆôíÛ·¢Í)ª‹ƒŠÓÆú˜Õ«WÀ©S§r^½zõ …r‹¤Vf ;XEu†|9„Î9a|6¨}©ÆøþãéÝ»7^^^òöºººtìØ‘÷ïßóèÑ#±úW:::èëëË<3³0òD°¾ûî;vï–TF~:Ä€dšg*¯¸¨‡‡7nÜÀÝݽØ5OŸ>eéÒ¥xxxÈ|ŸšFs°„B![·neÆŒ =·Y³f4jÔˆ¹ÏÊÌÌ$33CCCXV~øùùÑ­[7ìííYµjUE›SfT%aQIwtqüþûïܾ}[a‘Ýêž&,ì`tQ¬‹».¢öƒÚ%]P›¨FCÓ†|ùÅ—œ9s†çÏŸÓ¯_?…Fæ›5k†±±1wîÜ«äÞ¨Q#Þ¼y£y—šššXXXÈü7¹nݺôéÓ‡}ûöÉm‹$Ƚùº—-[†P(ä¿ÿýo±k222øöÛoˤc¾:Sã,E§?FQQ¬ª(ѰxñbNŸ>M``  ¨hsÊ”ê½ÊGÞaÐűhÑ"bbb8tèÜgU÷4¡šš @tG=,TˆŒˆD¿·>H7)u'u¦´ŸBìõX6mÚÄ‘#G˜7oýõ111|þùçx{{Kwh1Ô©S‡N:‘žžNlll‘q4ŠLÊ*×Ï„ زeK™(ÎÌÖ­[qrr¢V­ZRï½xñ"½zõE<¥aúôéXXX0uêÔ×}þùçœ?^êók:5ÊÁJMMåäÉ“Œ?¾LÎïÓ§ááár§1ªRzðêÕ«ôèÑþøã™þ@T%bbbÈÌ̤}ûömŠÂQtÁ{> , !!Aît‹²“°tZ6mI˜w ¾k€Êoâëh p4šk0·Í\¶ü¸555vîÜIVV3fÌ@__Ÿ pðàAe-Ûðöí[þüóO&Mš$Ó~YӃÆ cÒ¤I :´Ôu‡F[[[&ûª …?Ü(‚å`)J–¡$Qì^U¬¥K—ò×_qùòå2.ZÙ¨ŽÑ«|5 ZsæÌ!33“;vÈ|Fu`AQK[[›ììl©¤4š7k΋ÐÌÖ™MÓ/š¢>H~¼0`0 t:êÐþÇö<ð€ë×gL›6 &Э[7ÂÃéW¯¿þú+žžž„……1lØ0Î;'÷û­[·.;w&%%…ÿýWt½aƤ¥¥É$³ð17F[[›˜˜™Ïøæ›oðõõU˜f\aäI fddpóæMììì$Þ“€ [¶lÁÚںĵ“'OféÒ¥ 鶯ŒlÚ±‰SÒ¸KcÔ5ÔQ×P§±ec>Ÿú9›wl–ûüã`ÅÅÅVæµ3ŠH>þ¼Rÿ@aooOçÎqss“)4]U©Î”MÁ{>Ó§OGEE…M›6É´ßÄÄ„W¯^I=X¸*!oÖǬýu-ÁžÁœ˜}‚t~Àö€-¶+lñh[zoáú¡ëܹp‡&-ÄîïÚµ+lÙ²E$YРAþóŸÿ°eË‚‚‚9r$>>>Ò¿ÑB´hÑ‚ºuëFJJ  ¸TaeŽbÅÅÅ*óßi¥˜c,XÀرc騱£L¶UfN_9N}æGÏǧ«/w½D˜+D˜+äåΗüÓõ~|ô#º t9 û‰ã`•eíÕÇbaa!—PeŽ`-_¾œÃ‡sîܹb~«+.\ÀÞÞ--­Š6¥ÌPä0hqL™2}}}Ö®]+ÓþÖ­[­`«*…µ°@º:¬Â4jÔˆA±þ×õþHà±@þÜð'Ó&L“(Í]«V-<<<ÈÉÉ)ÐÔ¤I–.]Š››—/_f̘1rkŸЩS'’““yòä óìÙ3¹Î•G®!ŸðìÙ3"""ä:§0òD¯@:qѳgϲmÛ6þþûoTUK~ô¯^½+++úôé#³m••‘?ŒdÔÒQ¼~OöÙð=Ðé£ï!{u6÷2þÛpFÏ-Ó½j„ƒuïÞ=^½zÅgŸ}V.÷“7ŠU¬úôéC»víØ¸q#:::mR¹SÝ£WùñîÝ;¹Ó3Å1~üxš4i‚««ké‹ QÝÓ„â"Xzzz¼}û¶‚,ú€³³3&LÀÆÆ†ððÿUЛ˜˜°bÅ \]]9wîcÇŽ•+Z¤¢¢BË–-ÑÕÕ%<<---222dŠàåÓ±cGâââD‘1YQtëÎ;¼yó{{{™ö?{öŒääd‰"LžžžK”¢ß¹s'úúúŒ5J&»*3Ž¿9rJûÙ—²A’&}#ÈöËÆ[Í›qÿ'õýj„ƒUµWcccÃóçÏeúä%xùòe±*ºÁÊ•+Ù»w/'Ož¬†8ž?΋/°²²ªhSÊ…²L888`nn^bk¸8ª{KœƒU»vm222ŠtÛ•7]»v%((ˆ-[¶°sçίµlÙ’Õ«W³xñbNž<É„ ¸víšÌ÷ªW¯;v$11 ¹S…²¤ UTT |Ï»té‚®®®ÜéÆ|6lØ€‹‹‹Ìû%-nÿý÷ßÉÉÉaÉ’%¥®õöö&11'''™íª¬¬Ú³ŠãñÇÉ[%ýh°¼?ò8s·nRí«öV`` ÚÚÚtéÒ¥\ï+k«2E¯BCCéß¿?­ZµbË–- f­jT7í«ÒPô0hqŒ1kkk.\(ñžšÁÙë°ªª*äåå1}úô"¯·nÝšµkײ`ÁŽ9ÂäÉ“eÖ¡RUUÅÌÌ ]]]„B¡\…êòÊ5䣨(Ö•+W044”«¾Ií«3fСCœK=Ïßߟ«W¯ò믿ÊlSeåmú[~ûá7rvåÈ|FÎþæO/•F[µw°Ê;z•¬Ý„•ÅÁZ³f îîî;vŒ‘#GV´9Ž··7ǯh3ÊEƒÇàÁƒ±··çÇ”h}uw°@|Veq°òqrrbÒ¤IØØØVäõ¶mÛŠ"4{÷îÅÉɉÐÐP™îU¿~}Úµk'ÒÍ’EºÃ‡”¨•••Ü‚›ò>—îÞ½‹A‰ÏŠáÇ3a‰>FDDàéé)smdegÒ‚IäyËÿwLpRÀøù’ËÝ»wgïÞ½|õÕW,Y²„ H\_•/@Ú°aCÌÌÌxüø±D?›FFFÔ«WOaÃgÏžÍz)«l}õ IDAT~Þrssñðð(1Ò' âŠÛwíÚEPPP‘îÎ’3f Ô©SG.{*;Ïž=#¯‡âêH=ëVKËÃà &T …ñ#Fàíí-ñ§ëòôÁСC©W¯»víÂØØ¸ÌïYQ:XhÔ¨IIIE"+eAûöíY¼x1_ýõ‡ B!£¬¬ø{útÆÆ’–—Ç¡5ÀàB^I¹¹üýâ¡ 0°MÞ¦¦–¹eEUu°àCœ»»;B¡P¢Î5;;;<ÈÀùå—_X¸p¡D5ùN–¦¦&Ÿ~ú)<(µÃKQiBøð·ýÆ?lñ¡?''???úõë'º¶bÅ ²²²Xºt©ÄçLŸ>ü‘–-[ÊeOU M›6¨]PSØyjçÕD?s¥Qí¬¬¬,öîÝ[êtðòDҎ„„êÕ«‡ššâ~ıyófV­Z…»»;ß~ûm™Þ«*Œ©©) 6¬hS*å•*„ÿµû4ÕZµp å`v6¦%ì1¶çäðct4MŒŒH,ãâü²¢*;XùL:•)S¦`mm-Q÷`Ÿ>}8räöööÌ™3‡Å‹—XcU·n]TUUEs35jDóæÍ‰ååË—ÅîSdš$b½zõ ¹³…µ¯fΜɧŸ~*UTlÑ¢E :´Ô9„ÕKKK„7W> ¼)”X±Ú9X•%5ø1’¦ Ë:=ÍðáÃÑÓÓcïÞ½4jÔ¨ÌîUPF¯ R–àÅajbÂ%__ÞÒ…ôÒrsiñÉ'dT‡äcjÕª…ŠŠ ¹¹¹®«©©¡¦¦&•OEbiiÉ7pww—¸ |À€üõ×_ØØØ0mÚ4–.]Z¬[óæÍ‰‹‹C øP_£­­MÛ¶mDFFж¶iÓ†ääd…é»ÙÙÙñöí[±R£¨çÒÇéÁ‘#G2nÜ8©äcÜÜÜøôÓO%¯S• `Μ9d*TE|6Œ:†u000hyµr°Es±*Ÿ|ò zzzFLˆ£,¬mÛ¶±dÉ6mÚÄ„ ÊäÕ‰wïÞT ¯¤|£XìíÙž—‡¶ŒûÿÌËc”Bm*/ªC+wwwTTT¤Rÿâ‹/8yò$;wfÒ¤I¬X±B¬c/n tãÆ111!::Z¬#¥È4!”ÅŠŽŽ&&&¦TQÐÒHLLäéÓ§˜˜˜`kk‹››6Rü|ïÛ·55µj[k›’’©S§øþûïéÚµ+ ,àÙ³g¢Æ?¹ï¡ê¯ÊXÇ¢õ¡Å®—ûŽ•ˆŠ–e( I¢Xeá`ÅÄÄðõ×_£©©ÉÁƒ+…ˆiU@½OYƒÎçôñã¤Ü¼‰ôÓ¿þÇ  á£GìÞ²EQf•Å9X•QK¦L™‚““ÖÖÖܺuKâ}C† áÌ™3|úé§8::²zõjR?ª¯«S§¼~ýºÀ>Ú·oOvv6ÑÑÑ¢ŠN¶mÛ–&Mšàãã#öuEE¯Îž=‹••&L @*­3gÎ[é²;òËž={3f _~ù%«V­âÝ»wÌŸ?ŸsçÎqìØ1ÆÇŽÕ;ÐùU¤Sö(HÔ^R› K%×@«6Ö£Gxøð¡ÜŸÊŠÏ?ÿœ€€€ÿ8*ÚÁòðð`áÂ…¬]»–ï¾ûNaçÖ”Vñ”õ0h€‹ó³Ra rrؼr¥,*_ªS+Ÿ.]ºpãÆ <<Á‚ªÅÊgêÔ©899acc#Ó¿££#W®\ÁÀÀ€¾}û²oß>´´´JüylÖ¬ÆÆÆÜ»wÎ;sõêUyÞB ÐɸµnÝZ®s]]]¹ÿ>“'O–j_rr23gÎäСCrÝ¿"HHHàèѣ̚5‹Þ½{³uëVüýýiÓ¦ 'NÄÛÛ›={ö0zôh‰ Î&}>‰uß­CECNI°Á¨§nd|ÉgæS-¬ª½‚­Ä-Z´àÚµkE^KIIA]]½ˆ:¯¤<}ú”±cÇ’““ñcÇj„¾IY——ÇÙ³g2dHE›Ré)«aС¡¡ôPày=rs Và‰eOIVU­Ã*L—.] ÁÓÓSæ±3ãÆãêÕ«hkk3zôhbccKÔj«S§tèÐË—/+Tý¿V­ZL›6Í›7°qãF‰æk–ĬY³077'>>¾€<ƒ$|þùçœ?^®û—'<`ÇŽŒ;–ñãÇsâÄ """h×®cÆŒáøñãìܹ“Ñ£Gchh(ó}œÇ8ó>ã=Ö»¬Ñ·×‡ÉÀV äÿ¿¶ßAÝÏêÒí@7rssù~Ô÷2Ý«l—ÊË—/cddDûöí+Ú‰Èb޶ɓܳg§NbåÊ•rZªé(k¯¤#t‹-v¦ºº:i |ð½Œ*è°4hhh““ƒP(DE¥`÷“žž?®ÃÊ€üaÑNNNlÛ¶ UUé?÷Oš4‰I“&qøðaâããINNæûï‹(¶oßžfÍšñ×_ѧO±l©° &пj×®MŸ>}äp9r$óçÏ>Ìß”&R3hРΞ=[äg§²qíÚ5üýýñ÷÷§víÚèééñêÕ+LLLèׯýû÷/“ÑmêjêŸæöíÛ„àsˇûûîÐΪìÐkv/:vì(×}ª¼ƒµiÓ&¹&›—7vvv¬ZµŠÓ§OBh@¯““INKÃ@O£û÷ÓÉÆF"G)>>žŸþŽ?^ÖWNœ8ÁÂ… +ÚŒ*ƒIII¤¥¥)l䆕•¿)ðÁpCM ;SSÑÖÖFGGGâYmI~KK«`͈¶¶6ÙÙÙäååU‰÷! S¦LÁÒÒ[[[6oÞ,³¦££#ñññܼyS4Ûrâĉb×öîÝ›ÄÄDÒÒÒHMMU؇„Ù³g³téR™SIII :”ÇcbbÂâÅ‹¥jÞúöÛoY¿~=õë+bº±bIKKÃßߟ€€üüühÛ¶-ZZZ…BêÔ©#rªÊËv ,,,˜9©lÔª´ƒuâÄ ,--Ëe´Œ¢ âYH®¾¾tËÉaÐø¸Ÿ4‰caÖ¯®»w{ÎþýûùóÏ?Y¹r¥Ä²ýJJ&** ¡PH›6m*Ú”*…©©)‘‘‘tèÐA!ç}òÉ'¼RýÒKÀͼ<ºwïNvv6©©©dddP«V-tttÐÖÖ}ijj*ànŠ£8 þW‡U¸Sª*Ó¥K‚ƒƒ™>}:¡¡¡Réf}LãÆ133Ã××—={öгgOœ‹L­°··ç—_~aúôé¼yó†ÐÐPZ¶lYb¡´$ÄÅÅa``À“'O033“jïÝ»w™?>—/_z;{ö,K–,‘h¿‹‹ Ó§OÇÜÜ\j»ËŠ'OžàççG@@±±±tèÐUUUêÕ«‡ŠŠ ={öä¿ÿýoµצ"ªìú¾}ûâíí]e†U.š4‰³‡s";›Ò\ÂUÀN}}þö÷Çü£Wbb" , sçÎrç÷•dõêÕ´hÑ‚Q£FU´)UŽüa»Šš0ºW/f"oÛJ0«m[þ¹w¯Àõììl222ÈÌÌ}åääqºttt*,ÍòìÙ3444Ä>x^¾|‰@  qãÆ`YÙ³sçNBBBؾ}»L)Ã÷ïßKÛ¶mÉÊÊbûöíx{{ãì쌃ƒƒhÝW_}ŶmÛDßÇØØXjÕª…éÿG<³³³¥*Ýx÷îƒfÕªUìß¿_T% ÿüó^^^ìÚµKtíܹsI4gpÙ²eXXX0tèP‰ïYV„……‰¢T***´mÛ–¼¼EX¤q°\]]177gĈÌš5‹±cÇJ¤µgÏ>|ÈòåË \ÿá‡pttÄÖÖ¶Äý[·nE[[›I“&Il«"ÉÍÍÕRùûûcffFëÖ­ÉÊÊâúõëÔ¯__äT5hРBl¬ª¬ƒemmÍ7*Ú ‰XõÃ$nÛÆZº­r&LšDÛví˜3gŽâ T™3g¸qãFµã«Þ¾}ËË—/iÕª•BÎûiÌŒãG÷ïüííÙuù²\v¼ÿžŒŒ Ñÿfff" ‹D»´µ%,ñÔÔT^¿~Í'Ÿ|"öõÐÐPºté¢Ð{VFf̘A‡pvv–zodd$&&&èè舮¥¦¦âîîÎ¥K—8p =bK!µÿüy†***—`<{öŒY³fáíí |˜¢±páB¼¼¼JÜ·råJôôô˜1cFë)))Œ5ªX…ø|¼¼¼xþü9óæÍ“ÈNE‘˜˜(ª§ ÁÎÎ333ÒÒÒðóóÃÐо}ûÒ¿6lX®¶Uª¤ƒµyófôôôªÄL½G‘‘|Ñ©Ñ%´—Æà`ÇŽœ*e–¡Ù™2e 3fÌ S'EÈ[Ö\?~L:uäj£þ˜–††ìJI¡·”ûbN¤•Ñ`äÜÜÜ"Ñ®÷ïߋҊG»d-Dÿ8Í%Žèèh7nŒ®®®ûì3ѵ%K–`iiÉ—_~)v‹‹ vvvŒYtœù¡C‡HHH(ñCõ?ÿüƒŸŸ_‘ÈWY%ª§JNNÆÎÎSSS^½z…¯¯/uëÖ9UŠ*¨ÊT9+--áÇsñâÅŠ6E"†[Z²*, yùsê֥玌üúk…Ø¥ä]b³¤¢õôôt† Âe9k ?&..NTOvvv4jÔˆ+W®àããCíÚµE:UÅE•¤J9X ,`àÀôéÓ§¢M‘ˆ…“'£»{7¿(èeÇŽðîÝ;Z´hAÇÁ‰ã¤|§ÀÄÕ„ÇAyþü¹¨ž*""¢@=•¦¦&ÿþû¯¨¦  _¿~ôíÛ—–-[JyS%Š¢Rǃ=н½}•s®222X·nwïÞåÇŋٕ›‹‡¯/Sd<ïk ü¨yRÓIMM%44”Õ«WW´)5†FqïÞ=êÕ«W#Š®I~Vq–®®./_¾TȽ444ÐÐÐ@___tM pº’““ÉÌÌDCC£H]Wy Á–”Ž;ríÚ5f͚ŭ[·ŠÌú300 55•äädQm«þþþ 8ÐÐPRRRøâ‹/ ¤·7nÜÈb2 hii±råJ\]]iÚ´)ãÆcìÏc‰î-½s0ž>xŠ©) ;coo_ ÙëÉ“'ìß¿___ýúõÃÕÕUéTU*u«W¯^øøøˆį́¬xxxpàÀæÎ[ €º«V̈‰aX {Å1\G‡ï·neðÿ×(‘Ÿ½{÷òöíÛ*3 º èaÐ5…çÏŸ£¦¦VâÍ»wïÒ¦M›rupÞ¿_¤®K(ŠvU4{öìÁßߟíÛ·qðÃÂÂèÔ©ÉÉÉ8Ìràúëd<É@ËR‹Z jñþÊ{ôêaÙÕ’é#§sÄë‡.pÆþýû‰ˆˆ(Ð!xéÒ%Vÿ±šK1—ÈÊ•Ë~Í®š\Þr™nÖ݈‹‹ÃÇÇ___rrrèß¿?ýúõ«6ZpÕ‰Jë`yxx  ‹äž++§NÂÍÍ GGG±6çååñ¥…&QQ¸K.¼ŒRScç¶mŒ˜<¹ ,®¹ >œM›6)…ó*Eƒ® ”$™Ï¿ÿþKݺu100(GËŠ’››+¶¶K\£¬C°eåîÝ»8;;óÇÐLMMeѶE¸¯u'gS´ ‹ãG¡ æªFŸn}8ïþ¿ôàš5kÐÔÔÕê?¡?/‚¼Ò…·á—O°nlMVV–È©233“ó`%eI¥t°²³³ùì³Ï¬s!!!¸¹¹Ñ¶m[æÌ™Sê¸+ØüÇôKKÃJ À h¼ãC­Õ Q_Ÿ°F8@]) W•”Ì­[·ððð`ûöímJDÑàkiii$&&–ø0-© »2 ®‹±V­ZE¯ò(¨ÿá‡hݺµ(‚ÝqPG"L#l—¬øW0ÜkÈó;ÏùyÁÏØÚÚ2zôh±Kµëi“õ( äõ{sAE[…ȈHe¸ Q)¬uëÖѨQ#+Ú”b‰‹‹ÃÍÍììlæÌ™#Õ'‰ÄÄDîØÁÍó繉±†áIIX™˜`Ý­]‡åëQ£ÊÐúšËþólmm4H‘ûJ¤A’ˆŒ’ÿ‘••Å£Gh×®]±k222ˆ‹‹+v8pe$;;»ˆã•““#6Ú¥¢¢¢Ð{ïÝ»—+W®p'åaýÂ`Fé{ p Ô‡¨sñèEzöì)vÉ¿ÿþ˧ý>%;&[~ƒÎï ÆÂÂB!ç)){*]‘ûëׯñññáܹsmŠX²³³qss#$$„9sæûËUÆÆÆÌùí7øí7àÃ{Vj1•=YYY\ºt‰¥K—V´)5###"##ÉÈȨv‚—eAqb££££Ãû÷»/Ÿü‚úµ¨ÈéÊWªÏÈÈ@SS³H]—<õf&L &€0]œ+KÈY’Ã’ýKðéé#vÉõë×Éë,{÷xa²­³ ¹¢t°ª•ÎÁüa{K IDATÚ´i³fͪh3IJ{÷nvîÜÉœ9sX°`ÂÎU:WåÉ'ŠŒŸPR1˜šš–é0èêF¾“UR MWW—ôôô*-說ªŠ®®n‘R‹üz®÷ïß“˜˜Hff&@‘‚zI¢ž=ÆÝà©ÆN«Ç¯rêÂ)† |#ÉüôññA8B ¢ú6Uqç))s*•ƒKdd$K–,©hS pîÜ9ÜÜÜ6lX•¨ S"ž'N°lÙ²Š6C e? ºº!‰ƒU»vmÞ½{W¥¬âÐÒÒ*â<åääˆ"]Á×ÅX¸ ~ÖÒYdï”?u—åžÅüIó‰ÿ7ÒÓÓ±³³cذatîÜ™éÛ§#@ÂÚ®RP»¤F矕µ‹U‰Jå`U¶èUXXnnn4oÞœ#GŽTx‡ŽÙ¹ÿ>šššÊ®›JDÓ¦M §~ýúU&­UQH’&ÔÓÓ#>>¾Æˆ¹ª««£®®^À¡ …ºSRRÈÌÌDMM­@]×å.Ã/ 0Â?âQçG|úé§¼zõ .]º„¹¹9¹aòÉ3|Œ XP%Uõk2•ÆÁ ãÝ»w2Õ4)š/^àææFJJ ¿üò‹2Q Pv®œ(‡AK†ºº:999%®ÉOÖdTTTÐÑÑ)RÛ—••%*¤å]Ú;h® ›ZÁ‹—/hß¾=ýúõÃÜÜ\$Cr<à8OCŸB—RÎ(‡ c Ã¾}ûøí·ßèÙ³'=zô gÏžèééÉÿ”” •ÆÁÚ¼y3...jƒ@ ÀÍÍ ???æÌ™££Rðööæ×_­h3”ÂÀÀ€¤¤$ÒÒÒªejKQhjj’’’Rêº|'«4¹˜š†¦¦&šššÔ­[—»wï¢n­NŠ)@Ú1¯oÎĉ‹¼öãÔùéÀOdu)9úXê{ÕùiöOü6ç7Þ½{ÇÕ«W dÍš5´hÑ‚=zЫW/¥„C%£RÄåýüü000(qb|YsàÀlmmiÒ¤ §NR:WÕeôªr“ÅRR<’¤AÅ’„ÔÔTT[*ðÑ×223ľ4¨Ï 4|4@|£¡dAÃË ùm·®óÚµk3pà@–.]Ê¥K—pqq!++‹Å‹3xð`\]]ñ÷÷G PLí—Ù©VEÖ^ùúú2xð`’’’ÆÁÁ¡BìPRv(¬Êºº:õë× „VRI¬üBw%ÅciiIî?Š«R¹¢Y]àú¦M›X´hW\AíkÙ“E#5¸úçÕb_ïØ±#Ó¦MãСCìÞ½sssNž<‰­­-...=z”øøx™ï¯Dv*Uƒ.„†††D‚ººº<{ö¬,ªÜäüùóDEEÑ Aôõõùæ›o˜9s&æææÔ«WOz£‹¡C‡tèÐggg^½zÅÕ«W9}ú4 ,ÀÚÚZ$ѤI…ݳ&P!Vzz:ÇŽãòåËer~dd$nnnèéé±mÛ67n\&÷QRyyþü9ñññX[[W´)J¤D9 Z<ššš$%%•ºN]]UUÕRGëTW®]»†——ñññ888Tàu///N:…÷qo2r30m`JÎÑè'á B­Aµ˜0rΎθ¸¸`bb"Õ”ˆððp:uêTàZË–- fâĉ´mÛ¶ÀkqqqDEEqüøqV¯^Íû÷ï077§uëÖ´nÝsssLLL$¶¡8ŒŒŒ>|¸(Õyýúu™1cêêê¢è–••¤Õú5— Iºººbnn.êtP)))¸¹¹Ëœ9s”5˜­[·¢­­­Œ`UQ233•à ‘““Cdd¤D±Ož}ºÈ¡ÐÐPbbbøé§Ÿ˜ýýlž|ÈÞ½{‰ŒŒD[[»H´KšrMMMúöíKß¾´.îß¿O`` ®®®$$$PW—¡È­P®Öƒxþüy¯[®]»Æºuë°´´äâÅ‹5²Ö@‰xNž<)¶UZIÕC9 º ’:XZZZäææ–*LZÕ8yò$^^^èëëãààÀš5kJ\?wî\LLLŠM»ýúë¯Ì€ppp(µ <""ggg–/_N¯^½Ä®Y»v-Mš4;mæÌ™DEEqàÀQç!ÀôéÓIKK+µN `Ú´iØØØ½~ýzŒŒŒ;vl‘=îîîÔªU‹ï¿ÿ¾ÔóóéÖ­ ©³JOOÕså×vEGG‹­ë’¦%$$D$ˆ ååñd!''‡‡p+€«¡WÉËÍ£S»Nô¶ìµ•u©©wi)7+88˜ýû÷³yóf™ö¿{÷ŽuëÖqÿþ}æÎ[îÿ0Jªžžžäääàìì\Ѧ(QÒwWwÉÎΦiÓ¦¥®MHH 77·Ê¶Öß½{///n޼ɘ1cptt”H~ß¾}\¼x‘íÛ·»þÎ;lذOOÏ×ýüüX´h½{÷F[[›_~ù¥Àë·o߯ÙÙ™¿ÿþ[¢‚-[¶ðøñã‘¶‰'2þ|ÚµkWd½—/_fÅŠ¥žOrr2ŽŽŽ\¸pAâ=Ò"®®ËÀÀ H£$Ž\\œ¨P><<¼€æVY /Û¸Œ­{¶ò&û Ù–ÙÐ0‚@ý–:97søfÖ7X_ºó,)åæ`}ûí·,Z´H&•Ø;vpèÐ!æÎËСCËÀ:%Õ…!C†àááAÆ +Ú% DR‘ÍêNjj*¯_¿æ“O>)umFFqqq´iÓ¦,SçÏŸÇËË UUU¤šºáââ‚™™Y©u¾ƒ.0ƒ677—E‹‘““òeËðòò"33“éÓ§ÙÛ¿ú÷ï/ªÛ*+W®°jÕ*öìÙƒ¡¡!ööö\»vMìÚØØX~ùåŽ9"ÑÙùHÚ¨Hž?^¤‹1;;»Hбpjòc²³³EÎÖÕ«Wiذ¡Èá*,U!+‰I‰tÙ§ž’·:ïƒj~ql„ÚkjsòØIút“NÛLåâ`ýóÏ?øùù‰º,$åÔ©S¸¹¹ñÍ7ß0eÊ”2²NIuAÞ(©’Êͽ{÷hݺuýþý{bcc%~ø„‡‡Ó±cÇJß$‘‘ÁáÇñòò¢[·n888ˆðÇÝ»wqvvfÍš5tï޽ĵ6l ^½z|ûí·À‡çŒ««+Ë–-Õ^ó1;vì`ß¾}¢t—$¼~ýš‰'2dÈnß¾ÍÖ­[‹]ÛµkW‚ƒƒ¥NWàííͺuë¤Ú§HRRRФãââĦÅýGDDˆ®/^å÷>þu<Ÿtø„¬#Y`'á¦ç =T›cÛŽñEWù VýxëÖ-nݺ€••U ªÍ›7K%ñºuëh×®ØÎ%JÄqòäI¾ú꫊6CI‘_ð^“‡Aç¹KŠ®®.ééé•¶~-::š#GŽàëë‹£££LÒ*»wï& €Ë—/—ú¾ÿ>aaaìÙ³‡ääd-ZDÆ ‹H#¤¦¦yÉïôõõ•¸a«~ýúüý÷ߌ3¦ÔçYË–-‰•(Jù1½zõâÕ«W¸ººIm–uëÖ¥k×®Jxrss ¤Ïž=KTT5*’blÛ¶-mÛ¶eêÔ©¼yó†«W¯ráÂ-Z„………(•(Iíµ!Í5Cø^Ò”§5Ì[™|Ýñk.m§¢zj’"WËûÈ6-Y•ÈH,ÕÕ±ÌÍচ¡99ôùôSº„¾‘ ,(õ¼¸¸8Ö­[GNNsçΕúLIÍåÝ»w <˜+W®T´)JÊå0èÑš6mÚHÔú^YS«—.]âÈ‘#¤§§3fÌ™K?fΜIÛ¶mŦòÄñÕW_±mÛ6.]ºÄþýûY¶l™ØzÞyóæñÕW_ag'>ì1eÊÞ¾}‹———TöΘ1ƒ¦M›‹‡‡‡Ø5 .ÄÞÞ^ªÔèÇìØ±•JŸõyòäI‘£ªªªH§+_³+¿ëðÆ¢T¢@ ¥‹ëèìæÐ!0ZFc¡Î€:¤` ³yófrrr¸uëÖÖÖ¸¸¸»vòäɸ¸¸Ñ“ÊçêÕ«üúë¯ìÛ·æÍ›Klw=¸|ù2L›6={ö©KÞµkYYYL›6Mâs óûï¿Ó¡C‡*Ñýú5ÑÑÑ"Í®èèh^½zU¤®KGG‡k׮ȭ[·DÎV¯^½¨W¯‡Žb깩dìÊË•M*8½tbëòâSº%î—ÖÁÊxû–ú††xäåQ´ÉT<û€ijj¼NNF»Ð…Ý»w³sçNæÎËÈ‘#¥1E‰£GfÕªUJ½¤À«W¯xÿþ}-ÍœÊàºìàà —:ÿÎ; fûöíKDEEñÃ? ¯¯Ï²eËJm¶9r$nnn%j6åG™$Qn‡õE«V­bïÞ½À‡sâĉ >¼À³ÏÏÏÓ§OóÇHtnq¸¸¸0f̘RkÒ*;™™™E꺢¢¢hÙ²%­[·ÆÌÌŒììlâââÆÈȈ+®ðÜõ9ô—óæ) ÙR“ÌäL™¶KWƒ%RßÐø¼<¤É’åæb\¯oÿ¿~àìÙ³¬_¿žaÆ(•J”|ÌíÛ·©S§ŽÒ¹ª!ÔôaÐdggK´VEEÞ½{GíÚµËØ²‚”6tY¦OŸŽ……E±é5qäK+Œ=š9sæH´'55}}ý׌3†={öHì`𬦦ÆX¹r%K—.å?ÿùð¿,yÙ°aŽŽŽK5ˆº²¡­­……®?zô¨€ÃŽŽÚÚÚ¼|ô,póº ¬'$&&F¦’%©¬ñvvìÒ¹ÊÇØ”“Ãh++4?ý”–-[räÈ d8M‰’ÿ¡,n¯y˜ššÖØaÐššš¤¥¥I¼>¿Ð½¼¬‡.;::Šº,-¡¡¡8;;³eˬ­­%Þ·jÕ*üýýqpp(1%XI¬aÆqäȼ½½%šqûömXäúÏ?ÿÌéÓ§=z4»wï¦Y³f$$$-wÇìáÇéÛ·/ÞÞÞ•¶ÑAVÌÌÌ033+0{øåË—øûû³çžW Û*›ë7¯Ëä`IÜ»{òØ1ÞÞ¼IѦUÉ™¤Ý¾M/–,Y¢t®”ÈM^^gÏžeÈ!mŠ’rD[[==½j=o¯8¤í$ÔÑÑ!ðZ +·¬dòüÉÌ_>Ÿ³Î’œœ¬0›^¼xÁúõë±±±áÉ“'¸¹¹±aÃ…8W¸»»,±såïïOïÞ½©S§uêԑʹJKK“Èiܸ1Í›7gß¾}[8‚õ1C† aÕªU <˜àà`ÑÈEpîÜ9 ¤³*; 6DMM ÍÁ ×nÝ¿%ÓV‰¬Mÿý/K¥ø¥.Ž•yyü%…dƒ%%qâÄ † VÑf(©š6mJ||< ¢M)W$u°òy|1å êÕgÌÊ1üù+»»ífíûµ ]?”F­Ñex‚‹o@*›7oòã?âää„‘‘AAAÌŸ?_!óæNNN…BÜÝÝ%Ò…,\¸“'OræÌ©UÑზ“¤R¤§§s÷îÝ×ÅÅÅ¡««[b÷k‹-¸rå û÷ïG (ÌÁÒÐÐàÈ‘#5f>«¡¡!y‘yŠ;ð1èÕÖ“i«ÄÖ¥PÄ ŠÀ¥ˆœ¤D‰2=XÓÉׯªI¨©©! ÉË+þ!²õèV4448?ê<Â\!yÁy°  ,Á99¯sß΀Ù³`ŒT6œòдiS-Z„“““Âά¬XZZ’s+GaçÕºY ;+IUJ "ÑoChh(]$Ð\‘„Z@GuuÂÂÂrž’šKTT FÖá(ù€yyyRÕ$UJŠbý{÷˜ãÙ=pü›õ$‚”؉ E­’˜5ŠÚ$ˆðÒEPªŠZµÚ¢åÅO£fÕ±7)j¡¡v4!6‰ˆÌßÞhDÆ3îgäÉùü×<÷}Ý'¥ÍɹÎ}®q‹Ç1lÝ0RS »QJ¥àÕñWl(¼*žUHIÉü¥òÇãïïOÆ eÒ¤IøûûÓ¨Q#¾“wùûû³|ùr‚ƒƒÕãðäɾúê+BBB¦yóæÜ¼y“}ûö©œ¥¥I‚бcG‚‚‚xù2ó7ÍÎ;÷N“vV>ÿüsòåËGóæÍ‰ŒŒTû¾¬Ô¨QƒŽ;2nÜ8EÖ3Uùóçç½bïÁßʬgqÚ­îU+Á:}ú4ÿ"ªÄDNŸ>­Øz"w’ê•€ÜYÅÊ,ÁúqÁÌ<8“ø@õÞ2L•2"…‹/RÝóÝq¡¡¡Œ;–®]»bkkËž={7nœâo¦%&&Ò§Olmm™?¾Z÷¬^½š.]ºÐ½{w&Nœøæëß}÷Æ[ƒ©4M°<==ÉŸ??™^£I  lÙ²¤eÚT ‘ußÞæÍÆÆ†Â… ¿™Zžd”`E=Œbò„ÉįÔ,¹zãs¸èt‘¿Í^ºÜ«W/fÏžM£Fسg½{÷&Ož<º†ÿŽ'NРA† BïÞ½³½þöíÛôèу¨¨(öîÝûÖ°Ñ¥K—Ò°aC­@M¬òåËS @L§º?~ü˜˜˜úÒŠ)BLL *•Š-[¶pèÐ!ÅÎìÞ½;III¬^½Z‘õLÑüïçcÓK÷]7[_[~¢]¢j&Xœ¶VìØBN[[k]r`ÇŽ´hÑkÿ^Šœ«X±b!!Wu!t'Ûƒ"½Ü´U˜¾‚uáÂnܽ œ2–Ø;O<˜4i•*UÒ}ÁL¼zõŠ/¾ø‚¼yó2oÞ¼l¯?þ<íÛ·ÇÊÊŠ 6dØ{©ËÖ`*m,///>|H``à;Ÿ)‘`tíÚ•¡C‡R«V-.)ð¢ØÔ©SY³f çÏŸ×y-S4Îw¿ú ¿ìß>}Ç (<·0»ìÖ)µ·›T¬HÖ/¢ª'h¢Çÿh…ù»}û6?–$]¼%þüØØØ(:ßÉT¥O°…"Ö]·s×R¥ÔLá`èAEÖÊÌÑ£GiÚ´)ǧW¯^Ù^?cÆ æÌ™ÃüùóéÛ·o†×,_¾œ:uêd{ Nv´I°T*Íš5㯿þzg6›¶ VFÝ«T©Bpp0~~~Ù¾¹¨Ž%K–0nÜ8³Ý^?ðÛꜩƒuOõ+Y?XàìëÌ3wt~¾Ú Ö×?üÀx;;8ÎÎŽ!“&鼎Ƚ¤z%2ãââBxx¸±Ãлô VЙ ÐîÜäwyÀß§z+sçÎ% €#GŽP¹rå,¯=räMš4ÁÕÕ•%K–P¢D‰ ¯‹ŒŒdãÆ|õÕW:ǧM‚ÿ6»§­bÅÇÇsýúu­ÞtÎlب……Ë—/çöíÛo5ökkëÖ­tèÐ!˱9ÙÑuG™öé4¬òYÁrà~'=XöÕìù‚/¸z[•îÃJÕN°<;u¢@Íš¨7³6cK¢uëÒZ~8 ÈpQ‘KKKJ”(Á;ºÿöiêÒ&Yá7ÂÙÀlœl¯jÄÆÆÒ£G ,Èÿûß,¯MIIaܸq²eË:wîœåõcÆŒaêÔ©ŠÄ©É Ñ´<<Nˆ·Èö PGnhxO›`Õð¨J<N°Qh¸ôìٳߌÈj«ìÙ³g|ýõ×sòäÉ FNïþýû¬Y³F£³³£m ^ýàÁ6lØhß•J3 ]\\ bݺu,Z´Hëg•/_žþýû3lØ0­×ÈI>úè#êׯ­­‚禣q‚•'_>¢_½â`ÆxÙÙñÑI`IÀ_@[;;Ž5n̳¸8ì tš»0OQQQܸqC‘d…yË ‡A«Tª7c)ZÔhÕ+e>ÕjjWuI+::šÏ>ûŒ"EŠðóÏ?gyíÚµkñöö¦k×®üðÃj?CÉ­A€¸¸8,--Q©TZÝïèèHµjÕ¸{÷.7nÜÐi‹ÔK°RÍ™3‡””’Í P¿~}EÿæfZ]vð }W®äÛ?Dea»JEKKú[Zâ®RagaÁ¨Ê•¸fl EHõJhÂ܃N[Ár¯êŽSœ“"ëæ¹“¯ÚºýwvàÀ¼¼¼˜8q"ݺuËôºððpzõêEDDû÷ï×è—§5kÖP©R%µfg©K—íÁTžžž888°páBÊ—/¯Ó¬>M,€~ýúÑ¥Kš6mªõË;vÄÑёŋ•ëEÊ­tšäÞ®cGö_¸@bR‹ÇÃß?NBR{Ο—†v¡inš2ç­Â´ –››M+7…¬ EÙ»y×åå˾Úêœ9s&»víâ?þàƒ>ÈôºE‹1tèPFŒÁðáÃ5zÆ£GX¾|¹âÛYJ$X7æÞ½{üñÇ:’Ñ4Á¨W¯›6mbèСìܹS«çöïߟ»wï²uëV­î¯)vTNõêÕñõõÅ××Wæ Å=z”>ø''e~K¹ƒ9v‹`ÅŒäÿ¿ü C>©òQ±3@»ÊOŸ>å?ÿù¥J•búôé™^wáÂ:vìHJJ Z 3Ub hFté¿J«}ûöäÏŸ?Ë Õ‘Ñ,,u888Hpp03fÌÐêÙãÇgÿþý?~\«û…œE(rÙÚ2×ÙXVVVXXX˜øïPŸ}›÷‘×[»^WÕ*}>Êšc„S¦L¡K—.™^7sæL~þùgæÌ™C¿~ý´Š3 €²eËR£†Rƒ¿þ¥D ^oÆÄÄpæÌÖÉŸ??yòäѺ—ð‡~ÀÕÕ•ž={jµU>wî\æÌ™£qM¼& –0yÏž=ãÌ™34nÜØØ¡ˆH¥RQ¨P!³œV~àh­jµ8¸ê –y-a—š‹<ÛOlQ{?Ô|qúôéìÛ·}ûöQ¶lÙ ¯9vìM›6¥T©R,[¶ŒR¥Jiüx]aZ¸p!#GŽÔêþì(•`¥¤¤`ccƒ••çÎÓi-m¶ Óêܹ3£F¢nݺZ‹³víZúõëg–U`}“K˜<齺2×àÓ'Xù-òãÝΛJÿW‰¼còÂN }$8V¿[a÷¡?2i€f'l<~ü˜Î;ãææÆ´iÓ2½n„ ¬[·ŽM›6eYÝR‡¾¶S)•`ýõ×_TªT ‡7#´¥k‚ðá‡Ìœ9sX½zµÆ÷›û R}‘K˜<ÙJ0dž÷Œ¬Aƒñë‚_ Ýʬò³¨þKuòT̓ÊE…ã7Žä©šKKÜFº1ìÖ0bïÇÒº¡f?<÷îÝK×®]ñóóÃÇÇ'ÃkvïÞMÍš5©[·.sæÌÁÁÁAëï`ãÆ”*UŠš5kê´NVž?®sœð:Áòôô䯿þâðáüxñBëµÜÜܸyó¦Î1Áë³£¢¢;v¬F÷ÙÚÚ²fÍ:vì¨H¹…$X¤…„„àìì¬õ–‚©Ìñ0èôîcÇŽeĈoµ}{ù²=„÷^píØ5–5]Fðê`ã¹~ä:~ü4~æÔ©S9tè{öìÁÍÍíÏŸ?Î7ß|ÃÑ£G9uê­ZµÒþüŸ˜˜æÍ›Ç˜1ct^++J5¹§õòò¢Zµjh½V¹rå¸víšÎ1¥:t(5ÂËË‹'Ož¨}_©R¥7nýû÷W,s' –0iR½J2·†÷´¬-[¶'Oš7ožáµ%K–¤]»vÙ°œ™û÷ïãííMùòå™2eJ†×¬_¿ž:àããäIšm9fE颙Qb‹ðáǼzõŠ%JàééÉ£GtÚ&Tb‹0½æÍ›ãïïO—.]8|ø°Ú÷Õ¨Qƒ:0~üxEã1W’` “OPP"¿ æwtj‚uïÞ=/^̸qãôòœ;wòÅ_0{öì ·‰þùçz÷îÍíÛ· âã•:y¶nÝŠ³³3uêÔQlÍÌ(QÁJ;½½råÊ$&&R¢D Ž9¢Õz¶¶¶.\˜ˆˆâJ¯xñâìÝ»—M›6áïï¯ö}-[¶äý÷ßgÞ¼yŠÆcŽ$Á&kÓ¦MtèÐÁØa3cN‡AÛØØ˜˜È Aƒ˜?¾^ž1yòd‚ƒƒÙ±c...ï|¾hÑ"üfh¨’^¾|ÉÌ™3 V1Q¢‚•þ€çÔÉî¦VÅJ5kÖ,lmm4hÚ÷ôèу„„Ö¬Y£—˜Ì…$XÂdÉö ÐsÚ*\·n:uÊ0ùÑŽ{÷hß¾=UªTÉð|ÀK—.áííMJJ ›6m¢J•*Š>ôÿÖ`zJ$Xéxnß¾='OžäúõëÜ»wO«5õ™`ôîÝ›ž={Ò¨Q#µê‡ ƹsç’£ð2% –0I/^D¥Rñþûï;a†ìííÉ—/_Ž? úÀDGG+þ ýöíÛñõõeþüùþ’3kÖ,üüü˜={¶ÖC³³sçN¨_¿¾^ÖO/99™/^?~­×xùò%ááá”/_þÍ×ìíí©W¯}ô‘ÖU,m'ºk¢V­ZìÚµ‹Q£F±mÛ6µî™6m«W¯Öj¾Vn –0IR½ú–ÓƒŽåûï¿g̘1ïŒjÐÅ?ü@HHÛ¶m£D‰o}vâÄ š5kF±bÅX¾|¹âU³TñññL™2%ÃÊ™¾è£z•ÊËË‹Giý6¡¾+X©ìííY¿~=gÏžÍr¶YZK–,aìØ±ZWçÌ™$XÂ$ÉpQa9y6VjßUúQ ÚŠˆˆ ]»v¸»»3qâÄw>ÿþûïYµjtíÚUççeÅÐ[ƒ ß«N:ܾ}›Úµk³k—º#öÿe¨+Õ„ xÿý÷ùüóÏIHHÈöúmÛ¶áåå•cYÑI°„ÉÙ²e žžžXXX;aærêaÐþþþ4hЀʕ+g8lTS[¶laРA,Z´ˆ¶mÛ¾õÙÞ½{©]»65kÖdÞ¼yŠÌ‰ÊÊž={°³³£Q£Fz}NzúL°àß µÙ&´´´ÄÅÅ…[·néŸ&¼½½?~<5âìÙ³Ù^¿k×.yã;I°„É‘íAaH9­á=$$„sçÎÑ»wo ãi8q"¡¡¡lÞ¼™¢E‹¾ùzLL Æ ãСC?~œ6mÚè{v’““™0a“'OÖû³ÒÓw‚åééIpp0/_¾äêÕ«¯mè*@ùòå9vìþþþ¬X±"Ëk™3gÝ»w7Pt¦O,aR®_¿Nll¬^ÞH"#9í0èô#´M°ÂÃÃiÓ¦ µk×~g~V@@íÚµ£C‡L™2KKÃü¨0Ô@ÑŒè:ëüùóT®\9ÓWEŠÁÍÍ www­ªX†htÏÌÂ… yòä £GÎòº *àëëËðáà ™i“K˜©^ cÈ)‡A2„Y³faeeõækØØØhûÆ:t(Ë–-{ë ÄÈÈHúôéÃÍ›79pà 4P4þ¬ìß¿KKKš4ib°g¦¥k+«êUªÔÉî›6m"%%E£õ•>2GS_ý5Íš5£mÛ¶<|ø0Óë6lH½zõÔn’7g’` “"ÍíÂXL½á}ÕªU¸¹¹Q¯^½w>Ó¤Š5vìX®\¹B`` ÎÎÎo¾¾dɾüòK† ÂÈ‘#‹[]ÆhlOK׃žÓÍH³fÍ8zô(:tÐøBcV°R5mÚ”%K–н{w<˜éuÞÞÞ(P€%K–.8$ –0{öì¡aÆäÉ“ÇØ¡ˆ\È”ƒ¾zõ*;vìà›o¾Éðsu¬›7oÒ¢E 5jôÖ¡É—/_ÆÇLJ„„¶lÙBÕªU]cÇŽeòäÉF}±Å,x=²!þüj´~éÒ¥ 7ú›zEŠa×®]ìØ±#ËÓ @dd$[·n5`t¦E,a2d{P›©6¼gwŽM–¯Ó0jÔ(Ö¬YóÖaÐÿýï™2e 3fÌ`À€ŠÆ¬®é!Õ†¢KÖ7(\¸°Z0///Ž9B8sæŒFÏ1ö6aZ3fÌ oÞ¼Yþ½?~<ûöíãĉŒÌtH‚%LBDD‘‘‘Ô¬YÓØ¡ˆ\̃?~<Æ £`Á‚™^“UkôèÑܼy“õë×ãèèÀÉ“'iÑ¢NNN¬X±‚Ò¥Kë#tµ{k0•.,u«Wðúm@;;;j×®­qËof¥W¯^øúúR¿~ýL¿yóæ1{öl£ooƒ$XÂ$HõJ˜ S: zëÖ­¨T*Z¶l™åu%Xׯ_§Y³f4kÖì­žªü‘åË—³fÍ>ûì3½Ä­®‰'2~üx¬­­èVÁR§ÿ*-OOO¢¢¢8qâ„F3ØÜÜÜÔ>+ÐPÜÝÝ büøñlÞ¼9ÃkÖ­[Gß¾}‰ŽŽ6ptÆ% –0ŠôÛÒÜ.L‰)lFEE±páBÆŸíµé¬uëÖ1vìXhÚ´)ûöí£N:T¯^ùóç¿©fËáÇõrŽ¢¶t©`={–êÕ««}}ûöíÙ¼y3:uÒhdƒ©U°RÙÚÚ²fÍ.^¼È”)S2¼fçÎ&ógm(ÆÿµAä ûöíãôž=œ9tˆë×)boOŠ•Õª‘ÿý÷©P¡B–[ BRÚàӾigHÙõ]¥emmMJJ IIIŒ3gggÖ®] ¼>³püøñØÚÚrôèÑ·F<Ó˜1c 2voh›`Ý¿Ÿ¤¤$Š+¦ö=–––´iÓ†÷Þ{•+W¾›SêÁÊÈØ±cÙ¼y3]»vå·ß~ÃÖÖöÍgvvv¬Zµ ooo·Fs*©` ýJI᳆ ÙôùçÄÌšÅBBøãéSŽFF2÷Î>ܾ¨9sØ·|9«ÿïÿŒ­oó0è3fйsg\]]Õ¾'**ŠO?ý”V­Zñí·ßH«V­ðòòâ§Ÿ~2™äêÇdÔ¨Qoý6¦ØØXT*•V[•šô_¥åééɨX±"þù§Z÷/^œÇ§ñó ¥}ûöLš4‰¦M›rúôé·>sqqá»ï¾3Ú †& –Л?wìÀÖÆ†¶GŽð˃L¼Ò¼þ‹W ,MN&,:šÃ†Ñ©V-#F,ÄÛŒ1ëСCDEEѹsgµïY½z5‹-â÷ß§qãÆÜ»w___®^½Ê¡C‡hذ¡#Ö̱cÇxôèíÚµ3v(oèÒ¥m‚õÑGñøñc5jdÛ„i•+WŽ#GްdÉ~ûí··>swwÇËË‹ &'8’KèÅñÝ»ù©[7b’“éªæ=+éxú4m+WÖklB¨ËЇA¿|ù’ñãÇ3sæLµï>|8QQQÌ™3–-[†¯¯/ƒ Êöhc0•·Ó2Ô„éyyyqûömnß¾Mdd¤Z÷ä„+•¿¿?/^¼`Ĉo}½U«V”+WŽyóæ)2ÃK(.6&†fíÚ±;: ïí´¹t‰A8XVu²á]“¾«°°05j„——C‡åŸþaàÀ¼|ù’mÛ¶iýC_Ÿ¦L™Â7ß|CÞ¼yÊ[´M°bcc‰ˆˆàý÷ß×ê¹Ú4»›ÂDwM 4ˆ6mÚЪU+¢¢¢Þ|½GÄÇÇ¿é4G’` ÅùÔ­K@R’Ö÷ \ â;” J-ê0è_ý•zõê©uÐùŠ+˜:u*»ví¢aÆÌ;—Y³f1xð`¨×8µuòäI"##Mòmam,MßLÏÁÁ5jP¤Hµ¬œTÁJõÉ'Ÿ°bÅ úôéóÖ‹ ÇçìÙ³üñÇFŒN$ÁŠZµbîwîÐJÇu6ÇÇ3]Nd&B߇AŸ9s†3gÎзoßl¯ýæ›oxòä ¿ÿþ;/^¤eË–,Xßÿ'''½Ä§„1cÆ0uêTc‡‘!m,Mç_eÄÓÓ“Ý»wÓ¤Iv¨ñKeNL° .ÌöíÛÙ·osçÎ}óu???V®\Ihh¨£ÓI°„¢‚V®¤Œý*ù€Èðp.\¸ {PB(@Ÿ[…êl ^¸púõëãããÃ×_ͤI“X¶l«V­¢{÷î¨T*½%€ºòóóãË/¿Ôé0e}Ò¶É]× @ƒ ¸xñ"Í›7W«ŠåääD\\\ŽÚ9mÚ4 ,H¿~ýÞ|méÒ¥Œ3æ­-Ds –PTÈ_á®ÐZqqœ>p@¡Õ„ЃƒÖÖÖŠýÍ7ß0sæÌ,GüöÛoüüóÏÇÇLµjÕøå—_(T¨Ð›ëÔ9ôÙÐBBB¸yó&:u2v(™zþü¹VÉŸ. îiµoߞ˗/“À•+W²½>§V±RuïÞ/¿ü’ºuë¾ù~·oߎ§§g–cQ¢££9xð üñOŸ>5T¸Z“K(&>>ž+‘}‰z<€Ó*´šºSºŠµzõj\]]ùøã3½fðàÁ¼xñÆǾ}û8pàžžžï\kŠ –)¾5˜ž6,%¶Syzz²uëVµ›Ýsz‚P½zu>̤I“Þ ݵk­Z½Ý`ò÷Õ¿ñêçE¡ …p,éHÛÛâ5Ó ç2Î,W–=[rö¯³Æø²% –PLhh(]5˜fœZ@L-ƒ ó¤äaÐ×®]cÛ¶m :4ÃÏÏŸ?Oݺuùì³Ï(^¼8Íš5£M›6L›6 •J•á=¦–`Íœ9“Þ½{ýXžìhÓƒ¥Äö`ª%JP´hQJ•*ŶmÛHÊæ%¡œö&af¬­­Y¹r%W¯^åÇÄÑÑ‘9sæÐ½{wMÄGm?b[ëm<Ùú„¤gIÄþË‹/H|œÈ³½ÏØÛa/õ{×§çøžFþnÞ% –PLõêÕY¡æ,u Èñ9ÂÄ(utV}WK—.eΜ9²lÙ2ÂÂÂ8|ø0Ÿ|òI–kšRÖ¹sç¸|ù2]ºt1v(ÙÒ&ÁR²‚ÿV±|||ÈòZs¨`¥5zôhªW¯NçÎqqq¡oß¾8”s`AÌâ®ÄA{àƒ n,´‡—g^²Òn%ÎIHLÈàBãK(ÆÒÒ’ªÎÎü¥Ðz!€{ãÆ ­&„rtÝ*œ0aß|óM†•AƒñêÕ+6lˆ¯¯/ýû÷ç»ï¾Sk]Sª`™ò[ƒé»‚кuköïß——W¶Û„æ–`´k×???ZµjE—!]ˆù9†”))jߟ26…‡KR´bQ=F©I°„¢ÜkÔ D¡µNÛÙáѨ‘B« ¡œ´‡A§õàÁvíÚÅ‚ 8tè111ïÜ»}ûv¬¬¬Þé59sæ µk׿ÓO?åСCDGG³cÇjÔ¨¡v\¦’`Íž=›Ï?ÿܤÇF¤¥iÖµk×(V¬˜âS½¼¼8{ö,NNNïœã—V°´´Tü… csss£t£ÒÜït¼´X <òϯßíO4I°„¢ZôìÉ-œHë!àêæFÅŠuJ=H{t÷¡ÝyÏõ=JT.AûÿkÏ×Ï¿¦ù÷Í)X¼ Îúýë>«û÷ïãïïÏĉßZkáÂ…üúë¯|öÙg0eʾúê+c2…ëÂ… œ?žnݺ5u%&&½½½Ú÷(õö`zš4»—+WŽk×®)ƒ1=w–€m0N‡E¾‚ý¡û :”ýµz& –PT§Î¹õÁ¨tiÆÚÙÚ2Ñß_‘˜„З¡°¶¶fU³UD‰&1*‘„ $ŽL$á@IÏ“x¸ù!ó\æñ^é÷èòE—·ú®RRRèß¿?wïÞåŸþ¡@¬^½š²eËj¥¥%–––$&&*õ-j,'¼5˜–6ÛƒúJ°*T¨@rr2¥J•"$$$ËQæ¸M8lÆ0â~‰Óy¸ùqŒ™=Fˆt# –PÜú'è¬ÃýÓ-,hàåEí† ‹I¥ ž=˜1[Æ@2Ð(•É…å!¹w2ÑFsìÞ1^>ÀéÓ§©]»6yóæåîÝ»,[¶Œ=zè—1«XóæÍ£S§NSðmb}3¥ ^onÙ²%Ûfw777nÞ¼©—ŒåøŽãð¡ }§·f¾Åj(’` åYXpîØ1š¾÷4¼u¾…çkÕbº*r¾/Æ~Á¯ÿJü ÞØs„þw Ÿ üŒ™3g¢R©hذ! ,ÀÙÙY‘ØŒ•`………qêÔ)E’DCÒ´ÿêÞ½{XXXP¤H½Ä£îÐæVÁº~ý:)…S@÷Tî*BB”êÖŽ$XB/ªÔ©ÃŒ;¨lg‡:}ñ@[•гŸ~ÊÊãÇõžZ;zö(kv¯!Ñ_»m¸¸Ýq¬Y¼†’¥J¤øáÇÆJ°rÚÖ`*M+XJ¿=˜žJ¥¢I“&œ5Qy«8ºá¨‚iO,!„PS5j Ô€è3иFc…{›>¬ððpvíÚEÿþýõ²¾¡©›`ºz•*»*–¹mªlTÜúç6Ž6ð‡7ƒª„Š3'ÏPÔ©¨ÞâÓ„$XB¡¦víP]R)²–ûë'ÁÒ硹l ¦2õ+u&–§§'»wï~'q6·  ¤SI"®EPö§²X²†ÇY\ü ¬FZQâ›\ ¾Â‡¥•8kG’` !„šúÑë Ö¥ãBAàbáòzt‰è+ÁZ¶lü1| Ÿ­MC‹ŽŽ&oÞ¼XZfÿ£ÐF3RºtiÞ{ï=Î;—á…æÖ‡•ª°ca®î¿ÊäÊ“)Ú´(*7>àÌþªr* Ô(ÀhçÑÜ9~×’¦õ6«$XB¡€€T>ºU±¬}¬9pP™€2 +""‚-[¶0pà@E×5&SnpO+«ÉîæXÁJkä—#ù'䮼Âêÿ¬fÀÓ ¸?€Wpiï%^}Ȥo';Ì É Q!„Ð@«ú­ðt÷dÓ¨M$ù%i|¿­·-?LÿÇŽzˆî5 lllˆG¥RfK3§ž5˜u¬¿ÿþ›’%Kbooo€¨ÞåééÉäÉ“7nÅŠãäÉ“oª£²~ IDATŸæž`XZZâêꊫ«+]¼»;µIK!4´~öz|l|°ék£þMÏÁ®™“|&1²ïHý÷?JV±V¬X»»;~h:ý-J0õþ«´²Á<#Q`h‹ +G®äÛÿ|kø”J°îÝ»Çúõëùú믈ʴ¨;dÔXýWi¥&X7æÜ¹s<~üoçwê‘9´H‚%„ZÓg Q7¢h·¢6%m°(kÅgð XzYb]Òš¼å¥×ñ^¼zúŠŽÍ:,6¥F5˜ãÖ`*u+X†8à9;•+W&66–7n¼SÅrssãæÍ›FŒNdD,!„ÐAÁÙ²p 'ž “G'V¶]ÉÔØ© ý`(£¾EôÝh–Ì\b𸔨`­^½š*UªP¥J…¢2-ÏŸ?Ïö¼ºÈÈHlllprr2PT™Ël›07ôaåD’` !„¨S§]»veÔ·£èÔ©Ož<1Z<º&X>dÅŠ :TÁ¨L‹:[„¦Ð•*5Á*X° 5jÔ ((ËTI‚%„ ¸téÒ[MàÆÞ¶Ñu‹ÐÜŠfD-BSJ°òæÍK:u z«ŠåââÂÝ»wIHH0r„"-I°„BaaaT¬XñÍ?;;;Cll¬Qâ±¶¶&%%…¤$ÍGI¬_¿ž>øÀd }Éi ü[ÅòððàÁƒܾ}7 M‘$XB¡£˜˜?~Œ‹‹Ë[_/]º4·nÝ2NPh·MøäÉ/^̈#ô•éÈn‹ðÙ³g<~ü777F•µºuërýúuîß¿ÿVK¶ M$XB¡£ôÛƒ©rb‚eÎo ¦—]ËÔªW©2jv—ËôH‚%„:2—+00WWW<<<ô•éÈ.Á2…ùWI=:ÇÚÚš¶mÛ²yófI°L$XB¡£ôýW©Œ`iÒèþüùs~ùåF­ç¨LC||<ÉÉÉØÙÙez)Ì¿ÊHÑ¢Equu%88øMK,Ó# –Bè(³ËØojRÁÊM[ƒ}ÿURRaaaT®\Ù€Q©/µŠU¾|ylllxøð!ÏŸ?7ÚKâ]’` !„ž|ø½A{™³v ¼ÐȧC~®½»xðàÁ›ërÃ@ÑŒäÔ÷´R,ž?.³°Lˆµ±BˆœìòåËxyyeúyj‚Õ¸qcƒÅôù·Ÿ³cÏbŠÆä‘Ý>Ì/³~Á~ú)}ÚôÁÑÑ‘zõê,6S¡ÎáÌ™3 ‘æÊ•+‡J¥âÒ¥Kx{{Ó·o_ââ⌖ø©` !„²«`¹ºº¾™¶­oGBŽààæÀêâ«yúŒ¤}I0ðÚ“!iw/®¾`ËG[ðúÜ ÷Fî‰ÍÔdÕä~ùòeÜÜܰµµ5pTšK­b•(Q‚Ò¥Ksùòec‡$þG,!„ÐÒýû÷±²²¢P¡B™^c¨¬ã—Ó¼GsbÆÀ05nè)×Sè<ª3ÛŽoÓ{|¦&« VNè¿J•v›°k׮įÆòìÙ3#G%@,!„ÐZfFÓ2DVøÝp>iú qãÀUƒ A\p]úuáTè)½ÅgŠÌ%Á²²²¢U«Vlß¾† baaAHHˆ±ÃH‚%„ZËî B€ ´¾?nc-;µT0"Óg. ü;  |ùòlÞ¼ÙÈ K!´¦N ô»M8eÎuuXä}xþõs†}¯ÎÞ¢yÈ,ÁºsçöööYnûššêÕ«óèÑ#ÂÃÃiÚ´©T°L„$XB¡%u,}nú/÷'±m¢Îë$y&±lÙ2"Ê2K°rZõ*•§§'7n$)9‰û ÷©Ó®mzµáû¹ßsìø1y»ÐdLƒBh!""‚üùóãààíµ¥K—æêÕ«ŠÇ””ÄÝл D>P bãbyðàNNN ,hÚ2{‹0'Ì¿ÊÈ¡K‡X±|e,H¬“Èu÷ë` »Níâ§u?¡ WÑù³Î,¶ÔØ¡æRÁB-¨[½ýmž:u ëšÊýžœì‘ÌéÓ§[Ï”=þ<ÃäØÔÈI/äB…*b¹Ãr’î%‘x,æ=Ï€ÿBâÑDbïÄò›ão¼Wö=Žž9jä¨sI°„B —/_¦B… j]«¯-ÂóçÏ“Ò*E±õ’>Mâü¥óŠ­gª2Û|òä ÑÑѸ¸¸!*ͺrŠðdóRƪñ÷`$Dï¦Yf¾pXÿær’` !„²0š–££#‰‰‰<þ\ÑŠ)‚Å ÅÖ³8oA‘ÂE[ÏTe–`å¤êÕ»whиqÇAy ntƒ¸ q4oל¿oþ­·ø„$XB¡uF4¤¥mš5k‚‚ã«lBlðp÷PnAeýWõ;Õ'>0냼³òjã+>éô‰r‰wH‚%„ºuëÎÎÎØÛÛ«}>¬âÅ‹c“bwX,ÿN¤råÊ ,fÚrú„Sþ;…{ÍuÍQú>žk×®iüçj ó—Ì'¡“öƒeS%ú$²`ñ"‘K!4¤éö è¯Ñ}ÑäEXwÑýMBËN–´¨ÖBˆL_F[„9¥zõêÕ+î_»êµÿe­,<{øLÎ.ÔI°„BC¦TÁ*äXˆ±?Åj€•ÖkX޳¤ßþØ©ìhÓ¦ AAA Fhz2ÑS¬¬Üµÿ³NÏÂ]Î.ÔI°„BCÚ$X%K–äÞ½{$&ê>u=½‰ý&ÒÄ¢ S´x£p!|öó¿›Ï×_ͲeËØ·o}ûöåÒ%%öMOF[„9¥Áýܹs$5ORl½„æ œ5ÿÑÆ –BhàêÕ«¸¹¹am­ù¶œ>ÌÙ㿇úëcÓÙFí{¬{[S}[uNþ;\ÔÙÙ™iÓ¦1xð`üüü˜0aOŸ>ÕGÈF““· *„Å%Gs\²À± £bë‰I‚%„Цz•JŸ‡>Z}¯B^`–³-a'p?Í€½`1Ëkk~jø!Û2ÞªV­Ë—/§nݺøøøàïﯷ¸ -}ëÒ¥K”+W•JeĨÔãááåiå~tÛœ¶ÁÃÃüGsƒ$XB¡mÜS鳂pçΣIJLâÛßRå—*䩚;;ò–Ï‹];*ΪÈgCxù˜o{}›íš­Zµbß¾}ØÚÚÒ A6mÚ¤·ø %}‚•SªWeÊ”Áâ±(QTŒƒ¤I9âÍÉœH,!„Ѐ.,WWWnß¾­pDÿš1c#FŒÀ‚iã¦qnû9^Ü{ÁßÇþ&tO(±b¹¸û"³~˜E¾|ù4Z»wïÞìÛ·°°0ºtéBpp°ž¾ ýKŸ`å”þ«TŸx}—Xè4ðn ÀB"#’` !„t©`és‹ððáÃX[[S·î»Ó'K–,IéÒ¥u~†ß}÷S§NeÅŠ|óÍ7„‡‡ë¼®¡¥O°rÒ9«W¯æIج»ê>šÃ®‡sÇÌU *‘I°„BMºT¯@¿[„Ó§OgäÈ‘zY;½2eÊðÿ÷øøø0tèP¦OŸ®—·#õáåË—XYY½é· 'þü,XÐÈ‘emõêÕ|òÉ'DEEqà 0Ë1Úÿ·üÁ’Ï}>§ò‡æ?¹ßX$ÁB5éš`ÙØØàììLDD„‚QÁï¿ÿNóæÍ)Z´¨¢ëfçã?&007774hÀï¿ÿnÐçk#§U¯Ö®]K“&MˆŠŠbÇŽ :{{{掚KµËÕ`¡‹®„ Ç+°p¢67 uI‚%„jÒe{0•ÒU¬¸¸8-ZÄàÁƒ[SS>>>?~œgϞѺuköïßo´X²“Sú¯Ö­[GÓ¦M‰ˆˆ`Ë–- :”¼yó¾uMȦªnªŠu?õ· -YRà§„î U:d‘Ž$XB¡&]+X |Vjc»)}ú˜ä RSƒpýúõ|úé§Ü¹s‡M›61|øpòçÏŸéõíú‹jý€£ ü ^¦¹ 8 ü Ö…­Wi-ªµàúõëúýF„$XB¡Ž„„nß¾M¹råtZGÉ+,,Œ«W¯âéé©ÈzJprrbêÔ© 2???ÆÏ“'OŒÖi‡Œ>zôˆØØXJ•*eä¨ €æÍ›sûömùöÛoß9Î'3cúŽ!êFýoô§Ì¸2X¶Â¾’=ùªçÃÊÑ ·Ñnô½Þ—ª¥«2®ß8:uêĆ ôü Ý_CBˆ\@‰ê¼Þ"ܺu«™Võ*½ªU«²|ùrvïÞM—.]èС_~ù¥±Ãz+Á2…êU`` .¤iÓ¦¬[·Nëfû àï÷ï0ذ°0’““©TéßS¡,XÀòåËéÓ§5kÖdôèÑ:Ç/2',!„PƒR –R¬;wRªT)ªT©¢óZúÔ²eKöîÝk2ƒJÓn3ÁÚ¸q#-[¶äêÕ«¬Y³†‘#G*ú&cÅŠßJ®zôèñæE{žx—$XB¡%ܰ¶¶æñãÇ:­cÊÕ«Œ˜Ê ÒçÏŸ¿Ùz3F‚µiÓ&ZµjÅ•+WXµj£GÆÑÑ0gÚÛÛÓºuk6lØ€··7ynn% –B¨A© è^Åò÷÷§{÷îOc76STšZÁzõê7oÞ¤B… yî–-[hÓ¦ aaa¬X±‚1cÆP¨P!ƒ<;­Ô*VÙ²eqppàìÙ³!·K!²˃puuUd=]¬‡²uëVz÷î­H,Æ`ÌA¥© –¡æ_mݺ•6mÚʲeËøî»ï(\¸°ÞŸ›™bÅŠQ¹reöíÛ'Íîz& –BdCÉêè–`å´­Á¬cPij“»¾ç_mÛ¶víÚqîÜ9–-[ƸqãpvvÖÛó4‘ZÅjÞ¼9Ç'::ÚØ!™%I°„"J'XÚ=uêÑÑÑ4iÒD±XL!•¦V°ôÕµ}ûv¼¼¼8{ö,‹-büøñ&“X¥ªP¡œ•&''Ë­[·¨X±"VVV:¯¹sçN:tè@pp0þþþLœ8‘âÅ‹+­~Õ®]›'OžðôéS*T¨ÀŸþiìÌŽ Bˆ,<{öŒ/^(þC3µŠ¥nelÆŒœ:uJÑLYúA¥íÛ·gàÀ­‘œœÌ‘£GØszGÏåéÓ§Ü|~“ÁSSÖ¡,”(QB«øvïÞÍÂ… ©R¥ óæÍ£dÉ’Z­cL={ödùòåx{{³nÝ:6lhìÌŠT°„" /^|g`£4Ù&4÷­Á¬¤*Í“'õë×gãÆjÝ·ûÏÝ”iT†–ãZ2õŸ©üÙòOÎÏ;OôÌh•?Äòˆå|<ècFÏÔlšùž={ðööæèѣ̙3‡~ø!G&WÍ›7çܹs”-[–[·niìÌŠErrrбƒBSµdÉ0`€¢ë.]º”W¯^e{|Ì­[·1b„4"¯^½bÖ¬Yœ={–aÆQ§N ¯ë0¤»Îí"~s<ÈzMË‘–?\œÓÛNã\8ófô½{÷²páB*T¨@¿~ýpqqÑå[1ëׯçöíÛo¶­lì̆T°„" J7¸§RwTCn®^¥gkk˘1cðóócÕªU 2äA¥ z5`«ËVâfŸ\$OOæŸÿþCe¯ÊDF½[ÁÙ¿?;wæÐ¡CüüóÏLž<Ùl’+€Î;³mÛ6Ú´i#3±& –BdAé÷Têl8p€¼yóR«V-ÅŸŸ“¹¹¹1oÞ<ºtéÂСCñóó#!!NÃ:qìÃc¤ ×pc¦6<\õëþûçD—.] ÂÏÏ)S¦(6hÖÔtïÞÀÀ@>ùävîÜiìp̆4¹ !D&>|HJJ NNNН­NkÆŒ,_¾\ñg›‹zõêQ¯^=6lØÀGu?âªê*)Ç´ìz) Ï>§iϦ8½r¢téÒL:•2eÊ(³)êÙ³'7fÁ‚Ìž=›Ö­[;$³ ,!„È„¾ªW¸¸¸pûöí ?_ºt)íÚµÓKrgn:uêÄ«ü¯HÜ¡ãq;ßBðÓ`¼½½™6mZ®H®T*;väâÅ‹¼zõŠ¿ÿþÛØ!™I°„"úê¿J•Ù6á‹/øý÷ß³m€¯>Ad\$Ô}­Øº± Ò}¡&uð¨œO¨I°„"ú¬`AæÛ„Ó§OgäÈ‘z{®¹Ù²Ÿ8wõ‡¶fÉþ É}C7œœðððÀÎÎŽ-[¶œœlìr– 8ª\P9XÇŽ9|ø0*TààÁƒÆ'G’K!Ò1TÿÀ† °´”ÿ+!dsE¾/i~oþ¶ùÙ¼s3yóäU>°ª{÷îäÍ›WšÝµ$ÿU !D:†ª`­Y³†F‘˜˜HLLŒÞŸgîòØåáòîËØu´Ãb‚…z7m [ V~»’¶Úê7À¦gÏžìÛ·ˆˆþùçc‡“ãH‚%„é"ÁJJJbΜ9 6,Ó3 …æüñgÅŒ P ÀÙÓ&[ˆÿ]ðø˜G¤úâ꼌yI»OÚ-fSeiiI·nÝ(S¦ŒT±´ –B¤qýúuJ•*…J¥ÒësÒμ’K{öì!&&oooæ›ÏžI{n=œ–~D¾:ù(Ù¦$6Em(3¡ Ý"»ñ«Ç¯„l Ae£ß?뜬G„††J‚¥_¹Bóbˆñ ×®]ãüùóŒ3xý&áíÛ·õúLswÿþ}æÎËŽ;Þ|­ZµjT«VíÍ?GDDP¢Dî"ª‚ R¿~}îܹömÛh×N*}ê’ –B¤qùòe*T¨ ×g̘1ƒ#F¼ùçŒ}šñõõeÑ¢EY^#É•vzôèATT”ŒlÐ$XB‘†¾+Xû÷ïÇÑÑ‘5j¼ùšlêæûï¿§_¿~/^ÜØ¡˜¥Ò¥KóþûïóìÙ3ÂÂÂŒNŽ! –B¤¡ï 7XªT)"##IJJÒÛsÍÕæÍ›±±±¡M›6ÆŬõèÑ éÅÒ€$XBñ?aaaT¨P 5_ñ×ТE‹èÔ© |ç3Ù&Ô\xx8+V¬`ìØ±ÆÅìU«V‚ ²sçNŒNŽ –Bü>«WÏž=cݺuôë×/ÃÏe›Psêô] åôìÙ“¢E‹Êù„j’K!þGŸó¯2ÚLK,ÍŒ5ŠQ£FáèèhìPrÔãœÖ®]käHrI°„âôUÁú믿¸ÿ>Í›7ÏôÕ ¾µk×âììL“&MŒJ®óÅ_˜˜ÈÉ“'ŠÉ“K!€ÄÄDnܸÁ| øÚéÇ2dD*Xê¹rå Û·ogøðáÆ%Wòôô$66–5kÖ;“' –B ¿íÁM›6Q©R¥l7irWO¿~ýX¸p¡±ÃÈÕúôéÃéÓ§yüøñ›¯Ýºu‹ëׯ1*Ó# –B ¿íAuªW*•ŠÂ… ©x æbÈ!L:{{{c‡’«uïÞ¸¸8ºôë‡-?$Oᾚi_ä|h „Ç L<9‘j­ª‘’’b”xI,!D®÷òåKîÝ»‡›››bkf7–!#RÁʘ̻2 ¾hÄÉz'I\•¨ö=I “õ ¥FûÙ_lf$ÁBäzJW¯Ž9‚¥¥¥ÆÛY’`½«ÿþ,X°@oÓõ…z¾›÷ÇŽ‘2\‹JToý(”“(˜ “K‘ë)}À³ºíéÉáÛ,X@­ZµÞ:[^äÝHfM›EÒíÏÊLþ!™ß×þÎŰ‹ FfÚ$ÁBäz—/_¦B… ЬµbÅ š6mJñâÅ5¾÷½÷ÞÃÒÒ’'Ož(KNvâÄ .^¼HŸ>}ŒJ®7àûį‰×y¸Uq þi°å ’` !r=¥*Xñññ,X°€¯¿þZë5d›ðõ¿ÇáÇ3oÞ½sÏ\3I°„¹–®F•ˑܒ`EEE1þ|~üñGc‡"²0ö›±ÙY‚uXä 8ø;0sÂLÅâ2u’` !r-]Œ†„„ðìÙ3š4i¢pT¹g‹Pæ]å×ÄÖÇVëûótÊÃîõ»ŒÈôI‚%„ȵtyƒP©± É ¬‰'2`ÀŠ+fìP„Ê”*CЮ òTÍáÜøòÔÎú…ëð¨â¡·øL‘$XBˆ\éÞ½{¨T*5¾wÆ Ô¨QCoMÙæž`mÚ´ [[[Z·nmìP„êUªÇ®Å»È×0³ÔÝð+ØV°%À/€¶uÛê?@cmì„ÂtipŸ>}:ÁÁº4¤dÍÒÒ’’%KŽ‹‹‹Þžc ·nÝbõêÕ;¡…†µòüÖsz~Û“mU¶ñÂù  P°Nƒuˆ5v×íhÞ¬9l0vÈF# –"WÒv{pæÌ™ > å†/f$µŠen V¿~ýX·n±Ã:Z>s9G?ä|èyöžÞ˩ͧÀªW­N³o›á^ÝÂ… ;L£’K‘+]ºt‰ž={jtÏíÛ·9qâß~û­ž¢úWj£{Æ õþ,C5j£G¦`Á‚ÆE( páÂ4iÜ„&•ÑÃH–"WÒf‹PŸíé™[ÖêÕ«)Z´¨^ÞºÂI‚%„ÈuîܹCÁ‚É—/ŸÚ÷:tˆlìP„0 RÁBäW®\áý÷ßÇÒ2óÿõÝ¿Ÿ;wÒ«W/Ö…œ²M(}WB¼M,!D®¡NõÊØíéå„köìÙ´lÙR£á­B˜;I°„¹Fv îÁÁÁÄÅÅѨQ#F•5S“ð?þàÞ½{tëÖÍØ¡aR¤K‘k\ºt ooïL?Ÿ>}:³gÏ6`DÙ3å ÖÓ§O™:uªœ3(D¤‚%„È’““¹zõ*åË—Ïðóµk×R¯^=\\\ YÖ\\\øçŸHNN6v(ïðõõeÑ¢EÆC“$,!D®UÿUrr2³gÏ&88ØÀQ©'µŠU¦Lc‡òÆÔ©SéÚµ+¥K—6v(B˜$©` !r…¬,SklOÏÔú°vîÜI\\;v4v(B˜,©` !r…°°0ÜÝÝßùú78{ö,£G6BTê1¥>¬»wï²`Á¶nÝjìP„0iRÁBä ™U°L½z¦•`ɼ+!Ô# –Âì½zõŠˆˆˆwz˜‚‚‚(P @†•-Sb*[„&L`àÀ-ZÔØ¡aòd‹Paö²ª^­Y³ÆiÆ*X7n$Ož<´jÕʨq‘SH‚%„0{%X‹/¦cÇŽ8::)*õÙÚÚâèèÈÝ»w)V¬˜ÁŸóæMÖ®]Ëúõë þl!rªÿoïþc¢¾ï8Ž¿OjÌ)žEƒ£ÚÙ¦¢ÅÑU“Eކ`“Æ6sq)Ðtvíê°•fÉÚÕuw5­1.ØøGmc1SuVH#-+òÃzN ´Ä)E©Z ;<n¬6Óþ¸Ï÷Åçã÷ý¾ßoþ yñù|ïs,ã^ss³²³³¿ùþêÕ«Ú½{·ªªªÆpª‘¹¾M8«  @åååaï XÏ`÷n^Á²Âƒí7«mÂõë×ëÅ_T\\\Ø{VÆ €qc``@MÇ›TÕX¥Ú¦Z]ó]SÂÔî8­þþ~I’ÇãQWW—–/_>ÆÓŽÌìÙ³ÕÒÒÖžo¿ý¶’’’´téÒ°öÆ€qaë®­*ÝUª®Þ.ù>i±¤{%}(énisæÞ5W3m3Uú§Ò1žväRSSuèС°õknnÖ¡C‡´k×®°õÆK”#ß¡Óñ§å?âÿö‹þ÷¥_ýò|æÑ©§ôÆÞ7ä*v…wÐ …û¨†‚‚K=£DžÁ`Y_õ~¥äÌdy~å‘ÿ­ïW7K“?Ô¶ Û´jãªÐhP||¼€¾üòË÷zúé§µyófÅÆÆ†¼0^°XÖÜ칺XvQzxd÷ùKýzÏûžŠ^. Í`!ŽU¬²²2ÍŸ?_‹/i`¼#`°¤µX« _ŒîþÁ¿ ªlw™<ͳƒ…P¨VSS“êêêTXX²Àí‚g°XÎÉ“'U^[®ÀÁ@Pu|nŸ}òQ5¿ßlh²Ðš={¶Îœ9’Ú@@k×®Õ±cÇBR¸Ý°‚Àr¶ïÙ®/–||¡T©³§S'Nœ¾V„r‹qÌ"`°œ? }>³7Ó«ªzk¼[.T‡¾ùæ›ÊÊÊÒý÷ßo¼6p»"`°œöÆvcKޝ›$''«§§G>ŸÏXÍÚÚZµ´´hÍš5Æj `°˜öövŧÇKvC³¥ /*z&W±¼^¯Š‹‹årYëL0À X,%55U]ÿè2W°UŠŠ2W/ÄL>‡UPP ;v©àF,–“äH’ ke,2T,ôL½“°´´T999š7ož©ÜŒ€ÀrÒéÆV̱­ÈXa¦X˜XÁª®®Vww·V­²Öiö€•pËY™µRGÛŽªW½AךÜ7Y/m|IÇ+''G÷ÝwŸ C'Ø€uùòemÚ´I‡68€›±‚ÀrÖ¬^£Ä÷¥W'æ·1zjåSúè£4oÞ<¹\.­\¹R;wîTOO™a 6`ñÜQCCCÁ… càl×Y¥e¤iàÜÀè ÔJ³ÖÏRLJ7ü¸³³Sn·[JKK“ÓéÔòå˃Ø üü|¹\.¥¤¤Œè¾W^yE÷ÜsòòòB4€ëXÁ`I)I)zÝõº&=2iä7Ÿ“¦®›ª†ý ßziÖ¬Y***ÒÁƒõøã«¦¦FYYYzõÕWåñDÆçŽfëÀòù|„+ LXÁ`iÛ÷n׺߬“ï=Ÿ”9Œ^—&ÿy²Z[”lOVUTT¨²²RW®\‘ÓéTnn®ƒ~”¶nݪ¸¸8­^½zXן?^………Ú·o_ˆ'p €åµmÓC<¤Ëy—Õ—Ò'eHºûëý’ê%5H õ z0áAíýëÞQ÷Š„-Äýû÷ëĉ*))Öõ999Ú¹s§ìvS§³¸€qcÛß¶iÏÑ=ò4xtõìUM{xš>ßó¹R2Sô@Æ*È+в¥ËŒõûøãåv»U]]­ÜÜܰ½ ñäɓڲe‹ÊÊÊnymII‰–,Y¢+¬s0°ŒK}}}jmmUzzzÈ{…{ ±··WË–-SQQ‘¼^¯ÒÓÓåp8d³Ùn¸®¼¼\Ÿ~ú©Š‹‹C2€ïGÀƒB¹…X}´ZÅ[ŠÕt I´€´H زµÉßèWòO’õºT¸¦PmmmÚ°aƒÞ}÷]#½Œ  BÄäbÞ3y:üÉaõ»ú¥ù’lßq‘Gšèš¨».Ü¥;ûîÔþ¿ï×”)S‚úŒ Bìæ-ÄœœåææjÚ´i·¼×?è—}®]WÖ]‘~=̆•Rô#Ñê8Ó¡™ö™Á `TXFª¬¬TEE…æÌ™#§Óùƒ 'ÎMÔ¥·.IY#ï5!n‚º;»55nj Œ‘ºº:¹Ýn9rD¹¹¹r:7l!>¶á1½ÿŽô»Q6¨’Ò6¥©õýV36Œ1¿ß¯ŠŠ ¹Ýîo¶g¤ÌPþÆ|yë¼AÕ¶=eÓË÷¾¬ç Ÿ74-€á `@¹¾…XòF‰.m¾${|U·4ýçÓuî“sŠŽæÓÑ€p!`@š2kŠzk{%ϨÛfØÔÑС¤¤¤à‹þ€ÓÝÝ­k׌„+IÌÔ±†cfŠD˜ÆÆFMpL0VoÈ1¤šÆcõÜ À0D˜ŒŒ ùüÆêE7F+Û‘m¬€[#`@„±ÛíŠ+ýÛL½˜ú-Ê\d¦€a!`@ÊÌΔþe ÐçRâôDÙívÅ  "ÐkϽ¦I']Çö{›ž+|Ž3°€0ã/"c¡Cù+òõǨÑ9,Í阣gŸ|ÖÜ`†…ƒF ‚Ùï¶«g{ô³‘ß;aÊ])jb”ÚÛÚ WÀ!`@‹‰ŽQOkòÏç뎟Þ!5Iêÿž‹K±¿ŒÕ‚·¨ÿ?ýš‘8#œ£ø?l€EÔÔÖh}éz5hPÌcäÏô+0= Û6 Ôhæ‚™*y¦DOü≱¸í°À‚N:¥úúzy½^-\¸P™™™¼Sˆ ,ÃøwÀ0€a,ÃX†° #`FÀ0Œ€`ØôL?­v¬t.IEND®B`‚leidenalg-0.8.9/doc/source/figures/karate_modularity.png000066400000000000000000002234671420514302700234270ustar00rootroot00000000000000‰PNG  IHDRXX¾f˜ÜsBIT|dˆ pHYsÄÄ•+ IDATxœìÝ{|ÏuûÀñׯf˜™mffæ°ÍisÎù¬(D$”„RD¹%Ê-ÉOrK‘J%§¢æÊaŒÍÌ 3;›Ù÷û£û»{Øá{ø|Û®çãq?wÛçs}®im—ë}}Þo³ÂÂÂ"„B!„bÌ€B!DU#–B!„¤ÀB!„P˜XB!„ “K!„BaR` !„B(L ,!„B…I%„B¡0Kc' „([dd$ÁÁÁ¤¤¤Ð¶m[üüü°µµ5vZB!*`&;¹ aZ"£"yýƒ×ùs÷Ÿ˜56#ß/Ÿ"Ÿ",XR\ˆ½‹=S&Máýyï;U!„eK2ã£|¹éKr¾ËÖ@R.º –»-qØîÀáí‡iåÑÊÐi !„¨€XB˜¿§ý8ßê<…Ë Õ»á,Ô|¶&ìþƒÞm{ë79!„‘KÐ~X{BŸ …W5¿×º5¿ñ;½»H‘%„¦BÞ"ÂÈ–¹œp×p­Š+€û¿ßç‰gŸP6)!„:‘–FtçÎy6"ïvžnþÆDaë§[•IL!„N¤ƒ%„-ü÷Bò–èX\Ì„½{ör÷î]Ýc !„ЙXBQÀéðQ&VŽ{!gC” &„B'R` aD׃®ƒ¿2±òüòP&˜BH%„‘DFFbålJmÌÞC &„BR` !„B(L ,!ŒÄËË‹¼ø<ÈP(`0töë¬P0!„ºK#jêׂ•‰U#¸ü(L!„N¤ÀˆváÊIJ¾eMûví• &„B'²Ñ¨F”žžŽƒ›ùiù:Å1[mƸØqlYµE¡Ì„BèB ,!Œìß›ÿÍ¢‹ÈÿJË"+l{Ù’~=]ÙÄ„BhM–…0²·&¾…O¢|®ÝýÖ[óÛöß”MJ!„N¤À„üB§?;aþ–ÿIB · é<„žzê/9!„“KqzÛif:Τ¦GMøH+ãÂp¨ñA œ_w&üD8SžŸÂÂ… ™ªBˆ È –&æÚõkL{G~>×1Úå~K ƒ qpw`ꤩ¼7ç½â{vîÜÉ•+W˜?¾3B¡"–&,**ŠùóçãèèÈèÑ£ñ÷÷ÇÆÆ¦Ôk7mÚDNNS§N5p–B!&K„B˜0OOOš7oγÏ>K¯^½Ê,®&MšDnn.ß}÷3BQ)°„0qÙÙÙÔªUK­kg͚ŵkר³gž³BQ)°„0q999Ô¬YSíëß}÷]Ž;ÆŸþ©Ç¬„B”G ,!Lœ&,•?þ˜ï¿ÿž=e%„¢ôìÙ“¥K—*[!„XB˜4}X#FŒ Y³f¬Y³F/ñ…¢:“K¦%’Ƈ••›6mÒÛ3„¢:’K¦Ï–ÊÔ©SIJJbçÎz}ŽBT'R` aÂôÝÁR™?>!!!8p@ïÏBˆê@ ,!L˜¡ ,€eË–±gÏNŸ>mç !DU&–&ÌÀgŸ}ƺuë¸té’Áž)„U‘XB˜0CÌ`=ì›o¾aþüùÄÅÅô¹BQ•H%„ 3tKå—_~aìØ±dffüÙBQH%„ 3FKåðáÃôë×Ï(ÏBˆÊN ,!L˜±:Xfffaué`yxx`~Çî(, jäÖ–Âè¤ÀUÆÐŽC± Qèô§`èã×G™XZ(**"//+++£å`HƒŸ ¡ ºÞ¦@ !„ÐX¢ÊèÕ½.ù.ŠÄrJtbdoM·‚WNuYTÙüÑf,Gê^[ÚÁ°ÔaX ±‚,5‚¤e?K†g gë[õ›°Bh@ ,QåÔ¶©MøÞp\_wÅ|¾šßâëÀ¦£ A[‚8ôû!NŸ>­ß$+PÕ;X‹-âСCœ:uŠž={>ð¹=ë÷ðF¯70w4§Æ¢°ˆ(qÁ%à[°X`AMš4ÏlήÏv2}!„¨X¢JªW·1§c˜e? —‘.˜Ï2‡-@Ø/ˆ¶óÁyŠ3OE^>lذo¿ý–ãÇ-ÿªÚÁúûï¿éÑ£={öäÃ?,óº3g¸“p‡? ÅæÔV«úVXÔ¶ÀáYzìóNgî§Þgé[KY±b…¿ !„¨˜Bï´ ašV½µŠÉ“ùåà/ì?ºŸðéåT‹Œë¸·u'ãf_}òÕ#]”Ï>ûŒ9sæ——G¿~ý žwU,°–/_Nbb"GŽ)wû‰M›6ñÜsÏQ§NæÍœGܵ8žù×3tìØ333¬­­xçw8xð Ï>û,/½ôááá´iÓÆP_ŽB”K:X¢ÊkÕªoÏx›Ã›“p!ð=áÜŽºMð®`Ú7k_榔Ÿ|ò û÷ïgÿþýθjXçÎcàÀ´nÝš5kÖ”[\åææòÕW_1uêÔâ© '›ââ `È!üñǼ÷Þ{¼ÿþûúû"„BCR`‰jÇÆÆ¦øÿwëÖ“'O–yíŠ+8~ü8¿þú«!R+VUf°V¯^ͺuëØ¾};#GV¼¯Ø§Ÿ~Êo¼QüÏIIIXZZbooÿȵ½zõ"((ˆ{÷îѼysºvíÊÖ­2è.„0 R`‰j­¢ àƒ> 88˜]» 7Hm ¬¢¢"­ïŒŒäÉ'ŸÄÉɉ7bggWá=qqqüõ×_<÷ÜsÅ»té­[·.óž’]¬7Þxƒ¯¾úŠŒŒ ­óB¥H%ªµ®]»rêÔ© ¯[¼x1—/_æ§Ÿ~2@VÆé`ÅÆÆ²~óz†¿>÷nî4З. |e ¯ÿ˜sçΩç‹/¾`É’%¬_¿ž^xAíç?ܽˆˆˆ U«VeÞ3xðà–pe©Pa*¤ÀÕ^÷îÝùûï¿+¼nÁ‚ܸqà ËP†î`ýëóÑõÕ®Ì81ƒßÚüF̧1\?xø¯ã9Ôýo_|›ŸŒàåw_.3Fll,cÆŒÁÌÌŒ­[·âìì¬öóÏŸ?Ojj*}ûö}àã ®wìØ‘ØØX’’’èÓ§………;vLíg !„>H%ª=u»XóæÍ#99™Í›7ë5'Cu°²s²ñàÅá÷{…_Â4  ÿüthL‚¢uEÄ~Ë×µ¾ÆÁÛ›ñ7ˆóÍ7ß0cÆ –.]ÊäÉ“5ÎcÍš5Ìš5ë‘W´D0tèPöíÛWüÏÒÅB˜)°Dµ§nKå7Þàþýû|ñÅzË)77·Ü·íyF^.^ƒ½ˆz'ŠÂÏ Õº§ha©;RñëÇÍø›¤¦¦òòË/s÷î]vïÞ§§§Æy:tGGG|}}øxbb"VVVÔ¯_¿ÜûKÎaÔ«WñãdzvíZsB¥H%ª½¦M›’››K||¼Ú÷L›6 333>ÿüs½ädˆ%ÂOv v~,hºÍWkHÙ˜Bën­3f ³fÍbÆŒZçQÚìT¼<¨¢*ꢢ¢Š?6~üxŽ?εk×´ÎK!t!–¨÷6áÃ&OžŒµµ5kÖ¬Q<}X+¾\A¤k$ Ñ2@s¸7ýíhÛ¶­ÖylÛ¶Þ½{Ó¨Q£G>WÑ€{I»ƒ, !ŒK ,!ЮÀ˜8q" 4`åÊ•Šæ£Ï+99™õ»ÖSðEnæÁѤ£Zý¹©”Õ½õæ¯TžÃðññÁËËË Ûk!„ŠXB }0nÜ8š6mZîÙzšÒçûÑG‰³ŽS$V¼s<¿ýE«{×­[Ç”)S°´,ýÄ.M޾qrrÂÙÙ™³gÏ>ðñ °råJòóóµÊQ!´%–@Íš5ñöö&$$D«ûGEË–-Y²d‰"ù賃õ[ðoäû)TpøÁ¡àCß–––ÆÏ?ÿÌ„ Jý|||<666Ô«WO혻«¼ûî»,]ºTã…BR` ñ_šl×Pš§Ÿ~???-Z¤s.úì`…‡€ŸBÁü *8ªâëRÖ¶ *š,ª”U` 6Œääd5ÎS!´%–ÿ¥év ¥yâ‰'èÙ³'o¿ý¶NqôÙÁ*²(R®Àj õ½ësûömµo‰ŠŠ"""‚'žx¢Ìk4pW±±±Áßß¿ÔMF¥‹%„04)°„ø¯–-[’””Ä;wtŠ3xð`Ìœ9s´Ž¡Ï–Y+ìÜ »Cƒ Ô¾¥¼ÁvMæ¯J*ímB€Æ3|øp½î]&„%I%D º »—Ô¯_?FŽÉ믿®Õýúì`uôë¨\ ž~êo.zêÔ)ÌÌÌèÒ¥K¹×i³D0hÐ (,|tãÔÉ“'³gÏ5Ž+„š’Kˆ”*°zöìÉ‹/¾È”)S4¾WŸ¬ÇýÇ2¸ô7÷4 ýýú«}¹:Ý«¸¸8lmm©[·®V)•¶eƒŠì%„0)°„(A‰9¬’ºté”)S˜4i’F÷鳃Õç±>8ßWÿ æò4ŽoÌ“}žTëÚ½{÷Ò¦Mš7o^îuÚ.ª”5ìйsgìííËü¼B(E ,!J¨[·.®®®„‡‡+³cÇŽÌž=›_|Qí{ôY`5lØ©#§b9EÇ.ÖÇÐÇ¡ݺuSëòŠÞTÑfÀ½¤®]»AZZZ©Ÿ—.–¤Àâ!J.ªøúú²páBžþù ¯-**"//O¯‡=¿=ùm–~HSצjÝ£îÒ @ll,vvvØÚÚªu}Y¼½½IOOçæÍ›e^#K…B}’KˆR身{yÜÜÜØ°aC† )õó†ê`Ô¶©MäáHµZ„ËPÌ&˜ÁçÀi 8l³if4ß„‰÷&râçüûë?>>žcÇŽ©µ4 Êt¯TÊ[&„ŠÝîÝ»óÝwß)ò#GŽ”û¶å… HNN¦_¿~jç dËÍÍ [[Û ß•¥B!„>H%D)±µµ%::Z¯Ï©[·.û÷ï§[·nÆ+°<ÈÀ‹ÿÙÌ̬øÿ—¶dº~ýz¦NZfŒƒƒmÛ¶U;‡˜˜°±±Q?ñ ¨S`,^¼˜%K–(ö\!„Kˆ2ªÀ°´´äÌ™3ôíÛ—»wï|+ €”ùù²†þ{÷îM£FضmÛ×äÍA%ö¿zXýúõñòòz¤8|Xݺu™0aÿ÷ÿ§èó…Õ—XB”¡K—.–zp°¾üõ×_,Y² õ¶MPB~~>ǧoß¾e^SÞ÷o¾ù&»ví*^Nýé§Ÿxì±Ç˜ÙR‡®;¸—EÝ.Ö‹/¾È_ý¥÷ea!Dõ –åÐçv e™?>ÿý7IIIy^E˃*åýY”œÇÒ¦{ÊÏ_©T´]CIï¾û.K—.U<!Dõ#–å0ä2¡Jvv6#FŒ`âĉÄÅÅéýy-ª”W`ÙÛÛ3{ölFÍË/¿¬Õ1?úX"°°° _¿~Xßÿ=+V¬àüùóŠ='33“ .Э[7µï)ëÏ¢ä`»‹‹ /½ôË—/W;®¾æ¯JRç蜒¤‹UõuóðàãØX–«ùs× ø%7—üÁÜgŸÕor¢Ò“ËˆŠŠŠX½z9/¾Ø‹6mÒ¶­ ––øù93eÊ06n\oì¦Q`lÙ²…µk×*ÖUÑtyÀÕÕ•¢¢"nݺUü±3gΟŸO÷îÝ‹?6räH²²²8pà€Zqõ½DбcGbccÕ~;³Q£FŒ1‚/¾øB¯y ã˜:t(¯ÆÇÓ[‹{—ÿë¯ü¸nây‰ªC ,#Ù±ã ,--ˆ]Ì!'صë6×®eRP_~™€¿ÿ\¿>—æÍí9{Ö°CÖâAVVVøøøbç•·“û—_~ÉæÍ›¼×tyPåႳ¬#q–-[ÆÊ•+IKK+7Þµk×pvv6Èæªš,Lž<™½{÷’ Ç¬„¡üöWeŠ1¾ÏÍeüÌ™ò2„(“XF0fLO~úi°jUcÇBÉñ“`òdX¶,›€€4^y¥?K–h6Ó"”eÈ.–ê-²|þùçlÛ¶?ÿüSëg¤¥¥qåÊ:uê¤ñ½%ç°~ÿýwZ´hA‹-J½Vy,C,ªhò6¡ŠìUõ¬Y°€-99:Çù±¨ˆ¯½¦@F¢*’ËÀÆŒîÝÿæ§ŸòÔº¾Y3Î!&fŸ}6OÏÙ‰²r»†Š ,øgæiïÞ½hõ m–UJ›èìééÉðáÃY½zu™×²Àòôô¤¨¨ˆ«W¯ª}OçÎiРF/aºRSS9yù2ˆÕ8ðÛo DU‘X´|ù4ÜÜN1c†æƒì_}•ǯ¿®åÀŸô™¨ˆ——)))¤¦¦êýYêöüñÇsèÐ!­~ñk»<P³fMZ·nÍG}Ĉ#¨_¿~¹×¿ð ܼy“ãÇ—úyCX ]KÞ«Ž 3gð/(P$–/p99¹Ì½áDõ&–DFFðÍ7›ùàíϵ۾=—çž{QÁ¬„& µL¨NKåÃ?ääÉ“ìÙ³Gíø)))ܼy“:h›"]ºta×®]¼þúëj]ÿÉ'Ÿ°`ÁrJY–1t¥éüs÷¼yóøðÃõ”•0”àcÇðSð|Q¿š5 V,ž¨:¤À2%K^eçNÝÖüëÔ òY´H½_jBY†*°Ôí`©¼ÿþûœ?ž;wªu½.˃*×®]ÃÉÉI£{J›ÇŠŽŽÆÕÕU«£u´åä䄳³3gÏžÕè¾§Ÿ~šÈÈH.^¼¨§Ì„!d¤§ã¥`<¿ASî IDAT54ÞXWTR`@~~>Û·ÿ…··î±Ú´)â×_åœ4c0Å–Ê»ï¾Ë•+Wøá‡*¼V—åA€ÄÄDΟ?OVVjßçëëËc=ÆúõÿÛ~ÄÛ3”F›eB÷ª ¥¯/GŒ·7;???#ŠªB ,ÂÏÏB‘XmÛÂ¥K‰äå©7$/”S·n]š4iBXX˜^Ÿ£iKeþüùÄÇÇóÍ7ß”yMBBÉÉÉøúújŸj°½¼ÃŸË2iÒ$BCC  ¿<¨¢måááA=øVŽK©´üzô X¡Žém ÓÌŒ¦M›*OT-R`@PÐ_øû+·WJ§N5å#1DKÛ `Μ9ܽ{—¯¾úªÔÏëº<F||< ЪÀ‚¶™˜6m`˜#rJcccƒ¿¿?ÇŽÓøÞ™3gòõ×_“žž®‡Ì„¾ùøøp¥ Ý7i€ ÀßA•ƒXœœ€Û •©o_K®]»¦\@¡6S/°f̘A^^6lxäsº.–Ü–AÛËÌÌŒÏ>ûŒéÓ§m‰4?:§¤Å‹³dÉ…3†2eÔ(v(goíÚŒŸ=[H¢*’Ë<7Õµ{UÒ+¯¼B½zõŠ7ùÔuy°äÎ*ºtôÚ¶mKAAÞgÚʣ͖ *²7Våöã÷ß3B‡ã™ž33c»\Q}HemÚ´!:ºìlÝc¿3Ý ­i»4¦mÞ ,ÏøñãqrrbÅŠ:-îØ±ƒ®]»âêêúÀÇK›£©ˆˆ&L˜P>|˜£W¯²àßÿ6pÖ¢2“Ë€†‘1cÞeÔ(ÍŠ¬ÔTèÜÙ†ßÿWWwš5k†££#‘‘‘rDƒ‘T¦+** š5kưaÃèÛ·/o¾ù¦Z÷–µ4X’6Ë„¥m0ZÚQ:†àííMzz:7oÞÔ:ÆüùóYµj•ll¢ÂÃñ··¯ðx'{{{‚?fð‹/òê¢E¼¾hݺw§víÚÊVTR`ظqï0hÐbìí-ÕÚºaãFðò²âãwЮ]Ÿâ×­[BCCIKKÓSÆ¢4;w&((H«WüË£ëàÁƒ 8°øŸÈðáÃy#ðaׯ_çüùó<ùä“å^çååEJJ ©©©jçTZeooÏœ9sX´h‘Úq”¢ë2!ÈR¡)ÊÍÍåìÙ³xxx`gggìtD5#–¼òÊ|¢£X¾Ü›öímxåX¿΃?ÿ„U«à…Ì4¨!AAO’’M¯^CJÕ¸qcÚ´iCjj*W¯^•¿A>¶kÐÇ ÖÃ@ïÞ½yþùçË}ƒO¦]¬²ŽÈ}û>ÇsϽHË–-+Œeii‰‡‡wïÞ%""7nl€¯¢zS=ö˜b1•.°"""¨]»6Mš4yäsÝ»w§FLž<™7>ð¹ÀÀ@rsséÑ£‡ZÏéÚµ+'Oždذaj]_Þ„‹-âÉ'Ÿ¤S§N8;;«OWnnnØÚÚê¼³ü{ï½ÇË/¿Ì¯¿þJhh({Žìá@ð._ÆÆÕ†Œkxù{Ñ¿cìqºvíªàW!T’““¹{÷nq—_fff)˜•¨n¤À2²ÜÜ\úôÎÇ\ü±uëÖQ»vmµŠ«’êÕ«‡¯¯/ñññ\¸p777êÕ«§tÊ⿺uëÆO?ý¤hL¥—Kë^•Ô©S'jÔ¨ÁK/½Ä–-[Š?¾fÍÞ}÷]µŸÓµk×â M+rùòe¼¼¼033+óÕy…?ÿü³Ú9èJÕÅÒ¥ÀrrrbĈôy¡QEQÄ5ŠƒAÀ 5§‚Nq*ä›6n¢×Î^ü°R „ºbcc)**ÂS¶QF&K„FBÇŽøX‹-¸råŠÖ17nL«V­HII!::šü|åšÿãææFAA·nÝR,¦Ò¬Š ,€öíÛóöÛo3vìXöíÛ‡‡‡‡F~ýúõqttäòåË^«N—ÈÅÅ… &°lÙ2µsЕsXI·“xoÝ{kqŒ¸â`50ŽŠ+O`4ðoˆÿ*žm¶açaGtŒì£¥„«W¯beeUjÇVC“ËÈJ+°¼¼¼ˆŒŒÔ)n5hÞ¼9ööö„‡‡“ S7nÜxä—»»;·nÝRd`ÝÎÎŽ¶mÛRXXHXXééé:Çÿ£ô±9Jv°Ôé^•äååE÷îÝÉÍÍÅÞÞ^ãç©ûgQÞüÕÖ-[ÆÇÌ;ºË«>]öÄê0¬‰+AÓcBÝáöÆÛøõóÓê¹Õ]vv6!!!xzzÊH„0)R`QiÝ+%ºX%9;;ãééIRR×®]£  @±ØÕ™Òûa³À***âûï¿ç»ï¾ãñÇ×øyþþþœ={¶Âï-M ,øß<–!h»LøæÊ7‰ëµ|°¤¿šÎ¸ùã´ P=ݽ{—èèh:v쨷„ЖXFtöìY:tèPêç”.°jÖ¬‰§§'vvv\¼x‘ÄÄDEãWG5jÔ ]»v)O©%ÂsçÎáââBÆ Õ¾Gµ4èââÂæÍ›4hÆÏ­¨àÔ´¸ðôôdĈ|òÉ'ç£) úöíK@@€Ú÷DGG³ýôvŠV踜ôI8¢Ø÷RU—˜˜HJJŠN/%”G–…®¤À2¢ò:XžžžDEEéå¹õë×§]»väççNff¦^žS](¹L¨T¥i÷*))‰€€^xáàŸó·mÛFß¾}5znEÇæhS`Œ3†[·nqìØ1ïÕ”¦Ë„Gþ>BœMœ"ÏŽoϯÇU$VUvóæMòóóiÞ¼¹±S¢LR`I~~>—.]Â×·ô–-[ªõF–.\\\ððð ..Žëׯ+¾+yu¡ä2¡RK„šXkÖ¬ydg÷úõë³wï^µ÷Âýt°TV­ZÅÂ… ÉÎÎÖê~uõîÝ›3gÎpÿþ}µ®ß²‚Ž -¹ûA@°úݳêèÊ•+ÔªU c§"D¹¤À2’òºW ûV êªU«^^^Ô­[—ÐÐP’’’ôþ̪ÆËˋ۷osûömc)ÑÁ ¢yóæÔ¯__­ëÃÃÉ-uIÐÖÖ–#GŽÐ¥Kµæöš6mJNNN™o­êR`áæ±4™Å ¥æÓ;AD`„BÁª–ÂÂB.^¼H£F4ZúÂX¤À2’òæ¯lll°··'66Ö ùØÛÛÓ¾}{rss¹téYYYynU¡Ôv Jt°”è^•deeÅÉ“'éÑ£‡ZÝ£²ºX………\¹rEã tKòõõå±ÇcýúõZÇP‡&Gç˜[›CÙWÒL ¨ë^WŽÕyÈýû÷ ÅËË‹:uê;!Ô"–‘TÔÁý ºWÄÕÕwwwbcc¹qㆠyªI©9,%:XšXÇŽÃÖÖ¶ÂïEsssN:ÅÀ+Ü꣬9,u÷¿ªÈ¤I“¸pá:Ç*KÇŽ‰U«£k–g¥?¨¹pȺ•…B+¿;wîpýúuÚ·o•••±ÓBmR`‰:–¡– fmmMË–-±µµåܹs$''<‡ÊF©9,];X§NÂÛÛ[í¿åWÔ½zØñãÇ9r$©©©e^SÖŸ…®çü•dˆ¥Â²†ÝSSS9~ü86l`æÌ™ÜI¿J½øÞ¼ Vù%$$––¦Ó²²Æ"–¨S\q:X%5hЀ:MDD„,[”£N:4mÚ”‹/êG×–&Ý«]»váïï›››FÏ8tècÆŒ)sÎÊÆÆ†æÍ›sáÂàŸ¡ä‚‚ç¯¶nÝ:¦OŸ®X¼‡ 2„}ûö·ß~Ë‚ 1bcÆŒa÷îÝXXX0fÌ–N_Šeˆ2Ǻš›1Øo°"±*»7nPXXH³fÍŒò|Ù¦AèJ{6‚ÊR`©4iÒ„{÷îƒÆ¿« Õ–Ö1tí`rôÐÍ›7±ºjE>ºŸùÙ8®1ON{Rç8•]dd$ 4 AƒÆNE­IË*pWiÔ¨YYYddd «òÙØØÐªU+lll !%%ÅØ)™œŠö€R‡.¬'Nàç燵µu…×nܸ‘±cÇê4ë³wï^fÍšEtôÿ*žøÞD†.ÊñÎÇI\žHNTñ{â)Ê+"{g6ÇûgNìšuoFL\ŒÖÏV™:u*ÇתsxëÖ-8ÀêÕ«yå•WèÖ­K–,áòåËøúú²téR¦M›FçΙ9s& x ¸Ú±cÇçüùóL}z*–¯êö÷U³wÌxÎÿ9EæÔ*«‚‚BCCqvv–âJTzÒÁ2‚Ö¬Y£Öµª.–ŸŸiœSæàà€ƒƒ111\¾|777µ~¡WmÛ¶åêÕ«deeQ»vm­bèR`©»úè#µ¯7•7 +bffFÓ¦MÉÌÌ$::šzõêU˳Â6lH½zõˆŠŠÂÓÓS£{u¿úàƒʽ&88˜{÷îѳgO­žñ°¬¬,Öý´Žü:¾=×n?q› _m`ÊËÿ[*LKK+^æ»xñ"aaaÔ®]Ú´iÃôéÓñöö~ k׫W/ÆŒ£ö.ì;sæ [¶l!##ƒ—^z©ø¿Õ3gÎpìØ1zõê¥Vœy“æ1qÄDŽðkЯ„,áNæв‹è= 7ÞFß}qss#77—ÈÈHÞ>­Œ._¾LÆ ±··7v*Bè…XtéÒ%ÜÝÝ5 733£yóæZýÂ6[[[Ú´iCbb"çÎÃÍÍ­ÚýUÍaiúïKÛV@@ýû÷ÇÌ̬ÜëÖ¬Y£èÒàÙsg‰¿¯H¬,×,6ïÝŒm-Ûâ‚êÞ½{ÌMy{{S¯^½rãØÛÛ3gÎ-ZTaÁYÒ¡C‡Ø²e uêÔᥗ^¢sçÎ|^utŽºüóBÈègG3úÙÑlݺ•äääG:ˆVVV4lØ[·nU‹¿”äç熧§§Ö/ƒQÈ6 ¤îö «,]¬’œœœhÛ¶-ééé\¹r…œœc§d0Ún× mKåÁýû÷ãææ¦èFŸƒ’ë—«L0ÿMNNN¦wïÞ¬_¿žƒòé§Ÿòꫯҽ{÷ ‹+•ÁƒcmmÍÏ?ÿ\áµ?ÿü3#GŽäàÁƒ,X°€uëÖ=R\ 4ˆ€€ 5þÒT¬­­¹ÿ~©Ÿsrr"++‹ÌÌL­ãW™™™„‡‡ããã#Å•¨ò¤À2 MÜUŒudŽ®ÌÍÍqww§Q£FDEEgì” BµfAAÅCÎ%iS`ðçŸÒ¯_¿r¯Szö àTÈ)å9ö†¼Ä<^{í5 ¤õPºÊÂ… Ù¼ys™ßsß|ó ýû÷',,Œµk×òÑGUX|:TëY¡ü ÀÃÃã=ŪšÛ·oGÛ¶m±°°0v:’,¡+)° ¨:u°JRí7dnnÎùóç¹s玱SÒ;Õ2¡&´)°8À AƒÊ½fëÖ­ <bW$7?”9Z§'œý‹Äúõë™:ujñ?gee±~ýzºtéÂÝ»wÙ½{7 .T{‹Õ2¡¶lllÊ=nÊÒÒ’ÆsóæM­ŸaªâââÈÌÌÄËËËØ©a0R`HTTŽŽŽjí½ó°Ê^`©4jÔÒÒÒˆŠŠ"7W¡å%¤Ú®AÚÌ`0`À€r¯ÑG÷ ÀÉÑ N(ì>$þ–ˆ¯¯¯BÁÙÙ™I“&ñÎ;ï°bÅ üqjÖ¬ÉÉ“'™1c†Æÿ-vëÖððpîÞ½«U>u°àŸ—$rrrHOO×ê¦èÚµk˜››Ó´iSc§"”••űcÇHNN6v*&K ,ÑvyÀÎÎŽ5jT‰od š5k†££#‘‘‘ÄÇ+3$mjºuëÆÉ“'5ºGÓVNN§OŸ.wðZéMEKêÛ±ï?Û(!µmÄ… ˆŽŽ&!!ŒŒ —YKŠŒŒ$00ãÇ“››ËÑ£G™4iææÚÿØÓe™P ªÖRá¥K—°³³+Þí^TnÛ~øû÷§uƒ4²³ãÛçŸÇ§IšÖ­Ë3]ºðù§Ÿ;E“"–h»<¨RUºX*uëÖ-~-=44”´´4#g¤¬&MšPTTDll¬Ú÷hÚÁªhyðöíÛìÛ·qãÆ©S½ý{S+H¡ýΡ_~´jÕ {{{ IHH(ÞóêÆ$''“••Ua¨f͚Œ%KèÙ³'Ççĉ¤¦¦êœæ!Cøã?´º·¢%Bsssš4iÂ7´zŽ)ÈÍÍåܹs¸»»S¿~}c§#tTTXȳþþ½öCŽáç;wÈ((`cb"‰¹¹œÈÌd\` ÷.¤“«+7*á̰>È6 ¼yó´¾_U`õèÑCÁ¬Œ¯qãÆlRZÑnä•…jkÔ¨Qj]¯i+  ÜMkõµ4¨ÒªU+<Ý=¹utÜA¤ÁéL™5…5j`gg‡]ñç²³³ÉÊÊâÞ½{¤¦¦ŸõX»vm¬­­©]»6µjÕâèÑ£|óÍ7Ô¨Qƒ—^z‰îÝ»ÇøüóÏ™6m?þø£Nyz{{“žžÎÍ›7iÒ¤‰F÷ªÛÁhРwïÞ%--í?‹Ê ##ƒ7nжm[º…Â4\ §sg¶O—qM“ÿþû÷ésÿ>}|}Y÷Å ScsÞªL¾û àÆÔ©SG§ý *뛄갴´ÄÃÃ"""ªÌ²¡¦sXšt°²²²8þüEDI\¿~!CtØb] ?~ú#VOXéd% tXæ×R«V-4h@“&MhÙ²%;vÄÕÕ+++233 åÔ©SÜ¿Ÿ™3g²bÅ :uêô@ŒæÍ›óÔSO±jÕ*ÝrEûeBM ,¨œK…ÉÉÉ$$$àããSé‹+y‹ByuÀ (»¸z˜p-7—Ó¦±óË/õ˜é«ÜÿTÁÁÁ:Ö\Õ–KS¯^½â!ç‹/j=Ll*4ÃÒ¤ƒUÑò >g¯Jòt÷Ä©¾fo”¿Éi™¢¡æ§5éÜøÑ½§ÊS»vmxõÕWùã?hÔ¨=zô Q£F¤¦¦ÁÅ‹˜ç5jqqq;vL»\ÿKÛ· Õ]",©Y³f\»vMãgí[·ÈÎΦE‹ÆNE(ä‰~ýøAË.vß»ÇäiÓH»}[á¬*)° àܹs´oß^§M›6%>>¾J¿y§Ò¸qc¼¼¼HII!::šü|b1KKK:tè@`` Z×kÒÁ*ïíÁ'NP«V-üýýÕÎUôìÙ“7F½ÁsµŸÃòM 'Ž€ý({n„Þ aÆŒ?¾ÂONN_|ñÝ»w'11‘~ø÷Þ{wwwêÖ­K£FðððÀ××//¯æ¹BCCyùå—Y¸p!7oÞÔ¸ØQqssÃÖöŸç5Q³fMòòò4Ú¬´~ýú˜™™)2?¦OW¯^ÅÒÒRãeSaºæŽÃì¬,ÔÛĤt;òóyV¡£¹*#)° @‰T.–Š••Í›7ÇÞÞžððpŒ’V4Y&T·Àº{÷.—/_.uÇqÐÿìÀÿýßÿ1cÆ Ö®]ËìÙ³ùqÙL®?«ÖVpµâû-fXÐüƒæ\=rÇŽŒ;– 0xð`Nœxtï‡äädV­ZU|$ПþÉìÙ³Ë]v·²²ÂÎÎgggZ´hAûöíñððà£>bþüùÄÄÄÂåË—‰%55Uí´íbÕªU‹ììlîqww'&&F§]äõ)<<œœœŒŠPHXX7g¶Žqú~ lÿé'%Òªt¤ÀÒ³¸¸8,--qttÔ9Vu*°TìììhÛ¶-………„……‘‘‘aì”4¢É2¡ºK„å-þüóÏtèÐA¯{?žÝ»wsàÀмu ×ôsm¦·Áº­5L>.Û·¡Fÿ¸ qcq«Å\9t…zuþwüMëÖ­9vì;wîdíÚµDGG³xñb^zé%\\\8qâ“'OÖúEˆZµjÑ£G ÀáǘçJOO'**ŠóçÏE||2Õ›”Úîí'L[ÈþýtT¨¸ô>ÐâlÖª@ ,=SbþJÅËËK§³Ð*»š5k,/^¤Q£F•bYBµ]È#ʽNÖíÛ·¹qãF©¿Ø6nÜÈ /¼ —Ct÷ìÙêU«=z4¯¿þz…×ûøøàããÃŒ 3Š?ööÛoãÐÀ¡ÜâêĉlÙ²…¢¢"&MšÄþó½mS°nÝ::uêôÈŒœ……uëÖ}`§÷ÜÜÜâ­"ÈÊÊ¢]»vìØ±ââ«"Ú,ª¸¹¹Š––ÆûÑ””Dzz:ÞÞÞFËAèWPh(O)ËЉQ(Zå"K„z¦d«:.–¦~ýú´k׎üü|ÂÃÃÉÌÌ4vJåRwKVY˃÷ïßçÛo¿åÕW_Õ:ϲüë_ÿbåÊ•,]ºT­âª,å}ÿþþûïŒ=š;w2}út¾üòKÆlj'ضmëÖ­Óú¹åQíU+++êׯ‹‹Kñ<×èÑ£9qâÙÙÙÄÄÄpöìY"##ËçÒ¶ƒ¥bì¥ÂØØXrssñôÔqã³J :/Ö²´D©!ƒ:@k;»JÿV¸6¤ÀÒ£¤¤$òòòpqqQ$^­Zµptt$¦šþmàa...xxxÇõë×MvXÝ9,u:Xe½=¨mîݻLj#8rä;wî,÷Hu´lÙ’Ë—/?ð±Ÿ~ú‰ÇœÓ§O³lÙ2V¯^ýHÇwÍš5Ô®]›I“&•:¥‹N:áëë˦M›4¾·N:ôéӇ˗/ÓªU+Ú·o³³óó\¡¡¡ÌsY[[ëT`Õ©Skkk’’’´Ž¡­¨¨(¬¬¬Ô>[T^ööü¥P¬K@Faa•œÓ«ˆXz¤Ëùƒe©ÎsX¥©U«^^^Ô­[—ÐÐP£ü⩈­­-Íš5ãÂ… å^WQ+11‘ÄÄDÚ¶mûÀÇo޼ə3gxæ™gÉàäÉ“ 8† òçŸ*ò’†ªÀÊÏÏçË/¿¤W¯^ܸqƒÍ›7³dÉš7o^æ½&L`öìÙôîÝ›Ó ÏsL:•'NTøï§4%Î133ÃÖÖGGGÜÝÝñöö¦M›6Åv)))äææråÊ®]»Fbb"™™™wI\]]IJJ2Ø–-EEE„……áèè¨È÷0}{ôPì˜Ñ`À¯M…¢U.R`é‘®ç–F– KgooOûöíÉÍÍåÒ¥KjYgHê,VÔÁ*kyPém6nÜÈûï¿Ï˜1cøê«¯‹kiiIFF=öìß¿Ÿyóæ©ýKÛ××—¿ÿþ›o¿ý–õë×+–¨¿Tø°Þ½{sæÌ™2÷ï²´´¤nݺ4nܘæÍ›Ó¸qã⣀òó󉋋ãܹs\ºt©øuv{7ÔRavv6çÎÃÓÓó™´ê :/ú B°Çv•'ÄÂ‚Žƒ+«²‘K¤ƒex®®®¸»»Ë7Læ¤jн<u°J[<{ö,:/ß©L›6mÛ¶1{ölæ­JЉ‰aéÒ¥<ÿüó899ñé§Ÿ2eʬ­­µŠ÷ÙgŸQ³fM^yåÅ–…kժŲe˘;w®Æ÷j²eƒ 999Åó\^^^tèÐww÷âù¬ëׯÏsݺu‹;wî<2ÏU»vmêÔ©£×ýáÒÒÒˆŽŽ¦C‡B.*¿Þ½{“åà€úGÕ—m¿­-ã&OV Rå#–ž¤¦¦’žžŽ»»»¢qK›c²¶¶¦eË–ØÚÚrîÜ9’““>>>\¿~½Üüò:X·nÝâîÝ»´y¨Õ®T÷***Šž={rþüy6mÚTî1<ê ã­·ÞböìÙ´k׎Ï,éjÒ¤I̘1ƒnݺqæÌãôêÕ WWW¾ÿþ{îÓdÓѲÞ"´¶¶ÆÁÁ777Z·n]<ÏeiiIZZZñ<×Õ«W‹ç¹IMMÕú­Äò$&&’ššúÈ÷›¨ÌÌÌøü‡i¥Û9£/[ZòæÂ…&±µˆ1H¥'úXptt$;;›ôôtÂÂÂ_•4hЀ:MDD„NÃÅJ¨¨‹U^UÚòàpuuÕù—à®]»˜9s&žžžüõ×_¸¹¹éïäÉ“¼öÚk¬\¹’¡C‡²sçÎâ-*”\ân×®§OŸfË–-lذA‘˜³gÏfïÞ½DEE©}OÇŽ‰UkþOÝŸUó\NNN4kÖ¬xžKõ‹*%%…ððp ¸|ù²Öó\¥‰‰‰!??c‰Ê˯GŽÅ"-÷Ü$y{3ñÍ7•M¬‘KOô±p>:°ë֭Â)S¦(R`h3Urؽ<ÿÏÞy‡GUfü“É$“Þ;! Rh!@Mš¨¨4EŠÈŠXDÔµ,*âªü\EE@T@š®4AšŠ¨ E !¤ÒI#¤‘:™$¿?²3›2I¦Ü™$d>Ïã¹sï{O’ÉÌwÎ9ï÷hcÓ ‹±µµUôs€µµ5ÅÅÅ÷s5æúõëXXX¶óYÕ{~÷õ×¼2{6Ó‡ cÚðá¼·t)?=JŽ@nâ4ãÿvî¤ê¡‡xMMßµÍÀ׎ˆÐM`]ƒÀÒBg°þþ÷Ù¿.žžß±eËŠŠêøöÛ,êêà‹/²éßÿQQ‹˜:5©Tø’AWÇ‚   ,,,ˆŒŒ¤  @ï1´g×ÐZVzz:ÕÕÕ(Ž}ûí·Üwß}ïê*--eæÌ™\ºt‰ùóçóꫯj´ ÈP>}šU«V±~ýúV½ß¼½½ÉÍÍUy柪<óÌ3,Z´ˆaơ勺½½=¯¼ò o¾ù¦Êר*°TÍ`©ŠD"ÁÏÏúúz<==UêçR¶û°®®Žk×®áææ¦·rNIQ ÌC!!}î9<öîåË—Yxé²M›X?}:O ÂÛ­L-0 >þáì/Æ_,¦½îß2`’DBôðSB"Q÷–'wpçÎrssñ÷÷×z­ôô$†È»ïV³x±òsBCþA)GŽDcccÅ©SG5ê­ï·áää„““$&&âåå¥q³µ&÷¶··çúõëJŸ­ ,eåÁuëÖ©<ã°9þù'o¿ý6eeeìÙ³§‰pS•úúzvìØÁŽ;˜>>¼¶f ÷M™ÒÁw KULK»Î“OŽ .®U?T>ü0TUÕñàƒóÏ~ǘ1†'º2¼¼¼(//'-- kkk½™'ʳXÍV[;ýõW>øàÅ×6l`éÒ¥}:Ü´igÏž¥GìÞ½[íëKKKÙ±c»víbÁ‚9r+++µÖЕÀ’³yóf¾úê+/^ÌæÍ›5^ç7Þ`Ú´i„……©T2“g±–.]Úê9Ú:¹·†D"ÁÉɉ›7o¶ˆUÞÏÕø÷$“É(//WlƉD$%%5™·hii‰‘‘‘à±n_µŠŸ?ü¢ÚZ•Ϋ¾ž™……Ì1‚þú _=èéÎ6 ÍÙ¹s'³æÌ¡¤¤„98X[ùÛo|›“ƒµ­-ŽËÛ÷ܣчµ»ƒÀÒB•|p©,®süx"ÑÃÔÕÕ¿HÞ XZZÒ§Oòóó¹rå ^^^8::êôž#FŒ`ëÖ­<ùä“MŽ·&°nܸ‘‘‘¢á¸°°£Gª¼k­1‹/¦ººš   V®\©ÖµÙÙÙìØ±ƒ_ý• hµsÏßߟøøx¯W…gŸ}–ÁƒÆ–-[4þ{üâ‹/X²d ‡n÷Üx€§Ÿ~ºM¥« €««+III”••µ+zÅb±Bè 8hxÊç-S^^޹¹9–––Mþ« û6oæÇ>â5MRûQåå€L&è›—žôI}}=Ÿþ9—.]bäÈ‘œ>}¦=öXG‡Öé1x챑ZÅÑpqq!$$„²²2’’’t²í]Nhh(QQQÈd²&Ç[kp?yò$'NT|­Ic{BB£F¢¨¨ˆx@-q•ÀŠ+X²d œ:uª…8T}Y 2„‹/²iÓ&¾þúkÖððð`áÂ…¼ÿþûížëêꊻ»;QQQ­ž£Kª¦§§+Η#‘HpppÀÓÓSáÏååå…™™™¢Ÿ+**Šëׯ·ÙÏÕuµµÌYº”´è¿Û<:t¨Æ×PŸ 6°lÙ2~ýõWÆŽ«·2òÝ€A` LUU©©©ôéÓGã5âãã¹~ýÔè±UÊÌ™àéyƒ£Gh·P7ÀÈÈooo<<Úsu×u ÀÙÙ™êêjJKK›¯­­%::OOOKá"‘kkk…?Wÿþý Rì<ÌÏÏ'&&†ØØXÒÒÒÈÏϧ¼¼™LÆÎŸ~bb;ë«ÂØòrö~ñ…+hõë×ó /P^^NDD„`#º %0Bô_EFþÄàÁÂŒ2""Î ²VwÂÕÕ•àà`JKK¹~ýº ¶Ê2XÊz°g¯ÎŸ?X,&,,¬Ýõ ™:u*eeeX[[³ÿþvGÈ3T?ÿü3¯¿þ:_|ñÆ Só;SŽ˜HƹsçØ°aÛ¶mSûúM›6±dÉ’6ϱ°° 44”3gÎ(}\ Z– ËËˉ‰‰¡oß¾XZZ z/…?WïÞ½8p bv¡T*%++‹=»w3DCÃÊæ .L–uNJJ ñññL™2…cÇŽ1Ű3Pm K`„È`…‡Gÿ×vA{BC!<\÷CaïFD">>>¸¹¹‘œœLv¶0YÅ=z ‰š”q”e° ,UGâüþûïÌ™3 ÄêÕ«Û<_ž¡ºvíëÖ­ãÃ?ÔËx”ŽùdllÌ×_Muu5Ë–-SëZ???¦OŸÎ'Ÿ|ÒæymÎÑu‰Pޱ±1žžž¤§§SXXHVVD¬¦a¤¦4îç ¤,7—Ðf}‡šâýwP¶ÝÑ8cþÓO?qÿý÷wpD]ƒÀ™LF\\œÖÛÏÍÍÅ “³3ôíkOII‰0 vC¬­­éׯ"‘ˆ«W¯RTT¤õšÍMG›g°bcc±··ÇÃÃü‘4iHVƆ 8tèµµµ<óÌ3­6£WTT°iÓ&† FQQà­·Þ¢gÏžZ_ª"äÈMX²d óæÍcäÈ‘\»vMåëfÏžMNN§OŸnõœI“&ñ믿*DmjjŠL&lHu[8::RVVÆíÛ· êECÒ’“ßþi*3ÓÊŠÈÈHWlIwîÁŠˆˆ ººš‘#G’••EQQ èè°º% Bù_YZZrîœññ]Nff&III¤¥¥‘Í­[·())¡²²²Õ¦TMqss£ÿþŠá»êì jNsÕ<ƒ¥nöê™gž¡°°7npàÀ¥å½¼¼<>úè#xà$ .\à…^ÀÖÖVãïCS:ÃÐòáÇsúôiÖ®]Ë5š¦?þøcÞ~ûí63Qm5»ë«L˜––†½½}›Æõ…êw¾µÎï••øøø¸¢ÆÈ{¯Cs»–€å5xð0„úpÆ lll‰DTUUQPP@ZZ111\½z•øøxnܸAff&¹¹¹RVV¦•¸Û066Æ××’’’4ž•Ö¼«yK.°¶nÝʬY³°¶¶VºNLL Æ ÃÛÛ›ÒÒRŽ=ÚB0]¿~•+WòôÓOãëëËéÓ§Y¸pa‡Ž±°¶¶ÆÊʪÃgÍ™˜˜°mÛ6îܹ£Ö‚öæ¶%°ôQ&LHHÀÆÆ|||T²nÐ%CÆŽ%B ç[5p½ºšþWwð믿âáá¡h8~ü¸Z;— üƒÑ¨€DFF²H€¹YC†<Èúõ_ÓðR¢mL"žŒ©©)¦¦¦­žW[[‹T*Uü«©©¡´´´É1SSS$‰b-Åÿ›ššv«¹S666ôïߟœœ®]»FÏž=±³³Sùz‘HDhh¨¢”´ïÀ>ª*ªHLL¤ªª wwwìììØ¶mçZIg~ûí·œüP¸À (ذa'OžT|}ìØ±6}Ý ´A` „PÙ+9'NãÀ{Ù°ág–-S?M}æ \½ê˺uï S{ˆÅbÄb±¢4Ñœúúz…ت®®¦¦¦FÑã%ÿ'‹ÛÌ‚ék›¹&ØÚÚ2`Àrrrˆ‰‰ÁËË Åã‡ÏfÎ’9T­ÿ6² .³Ž ¯màâ9·û'Oždݺu<ôÐC\»v_ýh(îܹ“#F°fÍš.ÓüÛÝ[cÙ²eœ={–±cDzyóæ6'3ÈË„›6mjr¼_¿~”––’™™Ùd‡¦Ð+;;™LÖî ][[[Š‹‹¹}û¶Îgn*cÌĉ œ4‰ GŽ žAÆÿxL"aßÞ½‚Æe ¯¾úŠùóç+6Ûœ9s†ÐÐÐV_Ï ´Oç}·êb\¹r…ùóç ºææÍÇ™7o$ÕÕyåÕEÖ¾}ðÙgžœ:%ä¾í122B"‘ ‘HZmÚ®©©i"¸¤RiVWW×n¬£qwwÇÑÑ‘ŒŒ ðòòâÇß~ä‰=AU´zsk?ªå¯ á3Ò‡¹ãæ‚L&cíÚµ|õÕW|óÍ7<úè£ìÙ³§CÞ4µÁÕÕ•ªª*¥}J{'N°xñb&OžÌ¼yó”žÊåË—Ù¶m .lò˜¼ÙýÙgŸU²D˜’’‚………ÊYjooo®^½Š]‹2¢>Xwø0üýñ¾qƒGÔ¼öYSSf¾ðc †—‚SUUÅÎ;ùóÏ?Ç »µ§ût%ë¡3Xröì9Ovö F–P\Üþù³g›°çÎe`fÖz?UgÅÄÄKKKìííquuÅÓÓ???‚‚‚&88???\\\033£®®ŽÒÒR²³³IJJ"22’˜˜˜·¤055¥wïÞ888ÇìGgSõ³fC¤ë—ÕsÓ÷&'. $$©TÊøñ㩯¯ç÷ß祗^êrâJNgÎbAƒÚ¹s'·nÝâÿøG«ç-Y²„sçÎÝ串݄Be°âããqppP”ˆUE^*ì(~Žg]` ­ïÁlJ*‘à·x1Ë ¥AÐØ–úmÏœ9#ø˜¬î†!ƒ%×®]#((HgMÜŸ~ºsç~ã±ÇþNaa&¡¡•  #FÀ•+ ááÌÍ=xî¹7™5kaû‹vQD"fffJ#Ëiž«ªªj²#h‘õÒU3¾s^šƒlƒ ¬4_§vO-ÑfÑ|eüO=õT«; »r¥Ê ŽäÅ_äÌ™3Œ7Ž/¿üRi9î‹/¾`„ œ=û¿ÑT^^^XYY§Ø™¨­À’J¥ÄÆÆÔæ¦”Ö°¶¶¦¸¸˜[·náìì¬qš"‹ ›6š›7 YYY:iyénz°@¬ÆdeeŒßtˆ¼ßÚÚGGGÜÝÝñòò¢wïÞôíÛ—úöí‹——˜šš"•J),,$##ƒ¸¸8¢¢¢ˆ‹‹cÿïû©"ÐܹP¸~]˜µ: ~~~dffRSSÓÑ¡¨ÅË/¿Ì”)S˜0aÉÉÉM{饗8zô(ׯ7ü®ìíí àâÅ‹”””pñâEâââT¾_VVUUUôîÝ[°ïÁÒÒ+++òòò[³=”‰ÒÆôìÙS±kmìØ±Š™Ë—/gݺuz‰±;Ѽ÷ ¬¦6‚A`iIBB^^^zÝÊjXÜŽÂÎΗV›ñ““’a¨@7u#3#nÞ¼)ЂƒŽü¬)ãÆã‡~`åÊ•|ÿý÷Mkîð^Q_ÁËFb/aŦìµÝKè¬PL¬LÀ;kÞiõ>7nÜÀÔÔT'ø{ôèAAAÕZxS©ÊáÇqrrbÔ¨Q*okk‹··7ÑÑÑøùùÑ¿~üñGGù?îöá¹sç033cÈ!MŽÌE…ÃP"Ô]íl ƒÀêüÈ›ñ¶tD IDATA&ܺÕåÕ¬Zµ lmm±±±ÁÖÖ¶Å?;;».ã_#otïׯ_G‡¢6666|÷Ýw|üñǼþúë|øß]nvvv¼úê«<ÿòó¾p˜‚TϨ†PÀjøoÆ®’Óù¿¸ÿcCÐŽï;ΰÿÔ‹§§§Nm,ä¥Â¶¼¾´¥´´”õë×sêÔ)µ®=z4þù'ÁÁÁ,_¾œéÓ§óÈ#ê<PÆúõëùàƒšKLLT'ЃÀÒ’+W®è5Z[[K~~~§˜ßf u***¨¨¨À?П¿"ÿBmÓe䀩±) .¤¤¤„’’JKKIOOW|-ÿ'ïk,¸ 0ìììš4ù9úÞ(ÑÙ­Tá•W^á·ß~câĉlÙ²???¤6R¶üg µ?Ô°V.´Æ€lŒŒ¢{‹÷Ø8Öþk-O=ð±±±ôëׯÉp]`nnŽ999:{]yíµ×øè£Ô¾n̘1¬X±‚¥K—bccã>ªÔoÌ€z=z”¾}û¶R]e°svv6TVV2dÈ›NÐ¥%‘‘‘-†ìêCöªsQ[[KEE•••TVV*þßÂÂ î ¹owK-øo…ƒß ? ЪQkcd2YÁÕ\„¥§§SZZÚâ333µE™¥C38räˆÆ×wî½÷^Ì¢E‹ðìçÉæ?6S›­Æï=ª¯VóòŒ—IMJåÃ×ô·™ÁÝÝøøxììì4²~h‹ÿüç?øûû·(E©‚ŸŸÕÕÕܼy“=z°dÉFÅO<¡sSỹD¸~ýúemh°gPv¼3ËG/¿ÌÉsç0ª©aˆH„³‘oÖÕQP_OXP/¼û.S¦NíèP–ܸqggç&ãPtA`uR©´‰ˆª¬¬D&“aaa¹¹9VVV¸¸¸4yƒº×ø^¬?²¦\bÛÁ8Þ˜ ƒ&››Ë7bÇÎÎN©m„X,ÆÑÑQmÒòòr¥¢Lž-S&ʪªª”вæ­ù9b±ø®È`ɱ³³ã?ßÿ±DLýÍÞœ«Vñ™ëg¼øÔ‹¸;ë/SíççGrr² ¥Úüü|víÚűcÇ4^c̘1œ9sFa‹!oxõÕW… ³[±k×.zè!ìí훿páAAA-ŽwÞ{î9¾ß½›õUU|4ÿ«("¯]ãÓ¹s9ƶßï€([bXZ¡Ñ§2m0,ýPUUÕ"3%‰077ÇÂÂÌÍÍÛ-ßôèуqÃÇqhË!ÐÒV¦öŸµ|V÷uuu+|‘,--bKÛ’’¥¥%–––xxx¨[mm«™²’’222¬ñ9¦¦¦ øôÓOãîî®a666JE™••Ž­z`ì¼±ÔSZ$Xjö×0îÑq$žÖŸð”H$8::’­Öï¾-ÚÛ5¨ £Gfûöí 5kÖ,¦Nʼyó‹³;±~ýz._¾ÜâxgmnîãÃäÌLbÚÈ&Úãñ••|sú46 ÙyyXÙÙé-Ne–DEE1~üx½ÞÓ °„¥¾¾^Ñ/%UH$EfÊÅÅ Moý¿­÷?Žt¦œ4‹Óô1S>ß÷¹âk‘H„ƒƒܹs‡ÒÒR’““122Ò»166nªÈýÅþý¿¿B„eff*eJ3em‰2[[[½jþõ×_Ä×ÆÃœöÏm“ÑpkÀ-~8ôÓ§M$6Upss#11‘òòr­Ê¾Û·ogذa ƒUM:t(/¿ü2UUUŠ ò,Ö‡†Ñ9j¡ÌTTÎñãÇù׿þ¥çˆÚ&Ôˋײ²˜¥Æ5­©ÁÖÁ™L†‘Š¦ÐºÀ °´ ""‚W^yE¯÷ÌÊÊbذÖ:f ´…L&kR⫨¨ ººZÑ/eff†ƒƒZ¹d7&55€¿-øÛ&lCvUý-…F«a:‚gf>Óê9ÖÖÖX[[Ó£GÅåììl*++›”…ú¾„Bþ³:t(EEELž<¹ÝkäÙ;eý¥¥¥Ü¼ySi6ÍÄÄD©(“—/å?£Æ«ÒëÖ˜?®üÁmÇÛšþ8šPì^̉ˆzXÐP*LHH`À€¯‘žžÎ±cÇØ¿¿ 1ÉË„“&MúÝöìÙCtt4ÁÁÁ‚Ü£9w[Vqq1?þø#'OžlñXglnÿàïgòÍ›j‰+9VÀ>à±°0ö‡‡ ™ê–†ddd`ee¥ö'vm1d°TCî¾ÞXPÕÕÕ)J|666¸¹¹µ9ÓPŠ‹‹IIIÁ××—÷Þ{€‚¯sÍ÷5k@E_ZñßÅŒ•¥*Cuçoù¬FWWWjkk)..¦¸¸˜´´4¬­­BB×MÂêÈŽ;T:·yöNU***”в’’nÞ¼I||| QV^^®–(;qáŒÓà Œ!p~ýyS\]]µz­Ñt×`kÈíä þ—ÅÚºu«`÷¹›Qf**çĉÌ›7OϵÎõ¤$¾Ù¾D-î à@l,ßmÛÆœÚujXÒýWÐ0JB†ƒ]¹ˆj\â366V”øœœœ077×› HKK£®®ŽÁƒ3sæL&NœÈ‘#G8ùýIòŠò¸÷±{)˜U€ì!(ë'ÎbÁd– /üóÖüc UUU 6ŒsçΩUª466nÒè^ZZJii)III+„¶å mÑG£»<[¦ŽA]]]«¢¬´´”œœœ&¢ìÒÙK Tïu(¤…§ ´˜z¸¸¸pýúuîܹ£voóæÍLš4IP/¥1cÆ´ðl ÆÉɉß~û{ï½W°{ݤ¦¦ÃÛo¿Ýâ±¢¢">|xD¦œ_z‰Ï0¿ý¸ºšÇÿïÿ ««¥÷R]nn.ÎÎÎÝv s]]]‹ÆóŠŠ EVÊÌÌ 777,,,:ägTRRBJJ ÞÞÞܹs‡¡C‡òøã“””¤ØEeooOvD6SfMáüW繓}ãPcj¬E.Âè²âj1“¦OâËø/ɾ™Mmm-fff\¸pQ£FqêÔ)MDåYOOO*++)))!++‹êêê& ú.%ÚÚÚbffF^^®®®z½w[ˆD"ìííUÞYå=Ì›L§Lann { 2™Lãþ?mðóó#&&†ª|MBBçÎc×®]‚ÆbaaAŸ>}Z|°]¾|9K–,1¬vh/{õÀè9¢¶9uö,B˜¹ñ™™Ü¾}[íÝÔB`XÑd†>èNåÁššš–R©T‘•²°°ÀÉɩӸ•§§§#“É áÏ?ÿdýúõŒ7¥}zÒ")©á©˜™™Ntt4nsݺvh“ ¥ØXLFF¾¾¾ˆD".\¸Àرc9tèÖÛ©å¯ÝÜÜÉdSXXHjjj“ò—>šÃáY¬Î$°ÔÅÕË•Ìó™0S€ÅÂÁÆÉ¦CÄ4d?{ôèAFF^^^*]óÚk¯±eËÄ#/6XŒ5Š}ûöñØcéä¾]ÈÈH***¸çž{”>~üøq½z9¶Ç­[·¨¨¬Ä[ õ†ÔÕѤ¼¬/ K²³³166ÖûÁÝ*°ª««[d¦…²³³ÃÝÝ]gýRÚPRRBjj*={öÄÑÑ‘]»vqùòe¤R)S¦Laܸq-®ùã? Áî¿[ˆï¹çžV_üìíí),,¤¤¤D1.åôéÓLš4‰]»v ö‹Å899áä䤸¾JKKIHHhÒ®KA+XcÆŒÑÙ=tͨ!£L` Õßye899qãÆ&Ï¿ÖX»v-³gÏÖ™ü˜1cX¾|9/¾øb“ã/¾ø"ãÇ7¬VX¿~}«ža)))ÔÔÔ¨ç¨Z'<<œP±dÂÌ ­­%¼Yÿž¾0 {Ö€Ž˜?w‡Àª¨¨   €¬¬,’’’ˆŠŠ"99™ââbD"NNN1`Àz÷öööR\eddPPP@pp0ŽŽŽ¬^½šøøxbccÙ²e‹Rq Co§ªá6ìååEFFF“c¿üò O?ýt‹ãBakkKÏž=0`€"{‘‘‘Áµk×ÈÌ̤¤¤Dð{vÕ¡ÏyhèC˜]æ¹jiÊ”ÁúÃÕòY…mE\\sçÎÕY={öÄØØ˜´´´&ÇMMÆGmÞ¼YÐûÝ »O:…››[«æ±±qŸ×}Œ IzzºÀÑiޝ¯/iiiMÊf.\ ''‡3fè%†RRR”>¯¦NJtt´ÂÜ·»Ó–k;tÎò œáÁÁD °N>`laÑa#• KM:ªþøc•fx]¼xoooÜÜÜ4ŠÃÚÚSSSnßné¾cÇ6nÜÈ¥K—4Z[,--qww§OŸ>`ffF~~>W®\!55•Û·oS[[ÛæwC™`˪-<áü&ϪWî­1>e<Ǿú5þäää““£Ø(allŒ¿¿?·nÝâÚµkøúúêmˆ·2¼½½‰ŒŒ¤¶¶¶C2 £Gæ­·ÞjõñåË—óÞ{ï±{÷n=FÕyX·n]»í 'NœÐ¸UA_l8v GSS¦ÊdhòÎ7ÃÔ”‹­d:õ…A`)á§Ÿ³~ý[üþ{<¡¡"†•áì k׊¸x±žûîû“_üË–½¡·˜4é¿jo„ŒƒƒžžžöSLGP^^NJJ ®®®-í¼yó(//gÁ‚j7ªkÚÜ® ggg)//W:âæÓO?åŸÿü'ÕÕÕn‡€••VVVxxxP]]MII ¹¹¹Ü¸qC‘­©©©éô»IUÅÙÉ™_wþJõWÕ„G„s&ü é—Ò±²´bÐsƒ6ŒÞ½{+ÎwwwWd¬7Ž;;;cggGjj*–––ôèÑ£#¾ ÁójÕªUroBCC¹pá#FŒhñx`` ~~~Z—Àºb‰077—3gÎpäÈ‘VÏ)//'""‚O>ùD‘©‡L&ã‘Ga÷ÁƒM›Æ—uu¨jò0S"áÌÅ‹xz eWªÕŒgŸÀÍ›çY·®€:Åc+V4üjjŸ}öãÇoeß¾s89iÖS£7oÞlu4O]]]“Ÿü¿fffb„LWáæÍ›”••ÔäÍ=//3f “Éøæ›oèÓ§Úk>|XÐmì^^^¤¥¥µË¿ÿýoV­Z…T*Õº,©K$ ...¸¸¸PWWGqq1¾¾¾?~œ¾}û*J‰wC_ŸD"aÔÈQŒ9 hp¬¾sçŽÒ¾4ù˜ ‹&€LLL //˜˜üüüô>Íàµ×^cáÂ…H$nݺ…³³³^ï æ¼gÏžU*° !‹5oÞ¼NÛc¤+Úkl‡ÎiÍИÌÌLf͚ž}û˜3ge55<1z4#"ø¬ººÕlV6°ÖÄ„snn\úóOz¨8}@—šÜÿ‹TZ…««%ÇÿÎñãrq¥__X·NÆ;ï¤Ò§7™™ :O^"”Éd”––’››Kjj*qqqDGG“••¥è›òòò"$$„>}úàíí««+ÖÖÖqÕ åååÄÄÄ ‹ l"®.]ºÄܹsñòòâÂ… ‰««W¯bkk‹`1›››cmmM~~ë›™ÿõ¯ËÞ½{»¯.‰D8880`Àêëë#|’““‰‹‹S້DB]]]«ßSPP Ê_[\]]  ##ƒììl]†Ù„ãÇcnnÎøñãéÙ³'¹¹¹ÔÔÔèíþrÆŽËéÓ§[}ÜÑÑ‘x [• ãããÉÌÌl×±¼37·_ºt‰åË—sáÂæÍ›ÇÏ?ÿ FFì>{–¹Û¶± ;±˜ûÄb^þ <,áabÂ(;;ÜÞxƒóééB\!ƒ¥ woWNŸ®$(HõkÆŽ…[·jpu áêÕdÜÜ„mB—©ªª"==;w…E§!ÓU¿i´(•îÛ·;w2fÌ­Ê!B4·+ÃÓÓ“«W¯âèèØªx~óÍ7Y³f »víbþüù‚Ç  ä; §M›†µµ5=zô ªªŠ’’²³³©¬¬l2˜º«y©É‘H$TWWcaa¡´Ü+‹ñööæÆôêÕ«Åõ¦¦¦‘››K\\¾¾¾:í¬¬¬äßÿþw£Où®Â€€ÝW®®®ØÚÚ’””Ôê½—/_ÎСCyâ‰'4ºGW+ª’½ÊÊÊ¢¨¨ˆè)*Õ9tè'OžäàÁƒÌœ9“]»v5ÉÎΘ3‡sæPZZJxx8çÏ#­®fñ°a Õxw¶.1,ॗ¦óÜQK\5æÐ!)3gŽâÜ9Í=kš7žWVV"‹±°° ¾¾©TJXXØ]Ó—ÒÑTTTššŠ“““Ò9\Ÿ|ò §NbþüùÌ™3GãûÔÖÖrâÄ õ«È½±|}}[=çÕW_eýúõlݺ•§Ÿ~Z'qI`` ?ýôS“cfff˜™™áêêJmm-ÅÅÅ“žžŽ•••¢”Ø•ú åËÎÎŽ²²2¥ýt¶¶¶TTT4izoŽ›››¢7Kþ¡K(³d°²²ÂÒÒ’¼¼<½Ïf•»º·%îä¶ ªxÔueΟ?‰‰I»;';kypÓ¦M²qãFž{î9Þzë­VŒÛØØpï½÷rï½÷ê9JõéšýäÏ?Où Úüý£FåðñÇí¿‰6!“ !SVV¦!Ó¿Å™LFÏž= âJ ²³³ÉÈÈ wïÞJß-ZÄÁƒY½zµVâ „mnW†½½=uuuíÎ|á…¨©©aÓ¦M:‹E(Ú3566ÆÑÑ___BBBpqqA*•’””D||<ÙÙÙ”——ë1bÍ155ÅÌ̬ÍÒ§»»;•••·zŽ™™™¢|ßÂñ_[<ˆ‡‡ÇoñX=(((üžíÑ––œ'žx‚Ÿ~úIa„|·ÒÞH9±<øöÛo#‘HxóÍ7Y±b³fÍê¯I]ÐíÖºuo²b…f£=óúë26n\ß$¥Üx„LjjªÒ2^^^Š2ÞÞÞŠ2K>uDNW£²²’ØØXD"AAA-§e2“&M"33““'O òG®s»ª´æðޜŋ#‘H:ý8‰D‚›››Ê.æ666xzzÒ¿|||‰DdeeMzz:ÅÅŶÔ#‘H‹Åíö–ùùù‘™™Ùn¿“»»;>>>$''“——'HŒ………lÙ²…+V´zNsR}зo_rss),,ló¼»}„ÎñãÇ TZFn̵k×°··ïTï%Ï>û,#FŒ`áÂ…|üñÇ„„„pß}÷utX‚ÑíK„.D±aƒöë8:B]]áááØÛÛSQQ‘‘Q“~)vC–jÔÖÖrîü9~‰ø… ‘¨¬®Db"aä‘„ú„âïï¿¿¿ÒßAJJ sæÌaĈ|öÙg‚Ä“˜˜H}}=AšÖžU¤ñ0èöÊC .d÷îݬY³¦‰¡egCžÅòVs›µÜWÞ _RRBaa!©©©ØØØ(J‰%,‘H¨©©ÁÔÔ”ÊÊÊ6{¨äMïíõϘ››Ó¯_?nÞ¼Ibb"~~~Z}¿ª¸µ[XX`kk«ÒsPHäÍîme‰ï¿ÿ~öìÙCBB‚Z‹õõõ]ÂXyݺu|÷Ýwíž×™²Wuuu<üðì^½š¶mÛ†¥¥%?þxG‡&(Ý:ƒ•‘Q B½„†Ê¸v-Jé{{{·šß¼y³C=oº»í¢÷}½™üÖdþ/ãÿø}Òïüõþ_œ~ð4d}ÀœÏæðð²‡ùîhË¢ß~û§žzŠÅ‹ &®@wÍíÊhm´2žxâ ¼½½Y½zµ"Ó !FæˆÅbñóócРA899QUUEBB äääPQQ!PÄšajjªÈf·—Å211ÁËË‹7n¨´v=ðôô$!!¡Íݦm±gÏú÷ïÏÀÛ=×ÝÝââb‡}k‚Ü®¡=îÖ,Öž={xàppph÷ÜÎÒ•••ň#ؾ};!!!>|˜ììl–,YÒÑ¡ N·XÜspŸdGŒ¨'==›&îßÚbÈ`µÍ˜'ÇðÌÎgHÿ-êÓÕð)ðàÌ>éi)é¿§³è?‹¸gÞ=Šk7nÜÈÊ•+ùàƒxê©§KŸ T/Ìš5‹~ýúu˜Yd{èbè³­­-={ödÀ€ŠÚŒŒ ®]»FFFF»}lº@Þènii©Rߘ­­-ää䨴¾¥¥% @*•rýúud2™Ê±egg³wï^^|ñE•¯Ñw©PÞèÞ¡¡¡˜™™©$ƺªö^9s†!C†(ÝH¡O.]ºÄ²e˸xñ"...œ={–?þø£Mgþ®L·X¦¦¦””×›Q^"‘ð^Sš¸¸w&pvÒYjÖ€ Ùüš}5œè<½ïëÍßÿþwöîÝË‘#G9r¤ q;vŒÉ“' *´Û£­aÐʘ6mÆ ãŸÿü§Ž#S]}¶°°ÀÝÝ   ‚‚‚°°°   €ÈÈHRRR(((Ћ¿“\`©’Á’ãîîNEE…Z‚ÐÓÓ777âââTnø~õÕWÕ6Ç533ÃÁÁA¯Þ\ªŠ,u³XݦaãÆ,Y²D%›’ÎPüñÇÙ±c?üðаãË/¿díÚµ—.éÖ+44”ðpá^DÃÃE„† ;d·®®Ž¼¼<½ö5t†ÎJòsÉ Ù*u˜)ËRøþü÷œ>}Z¥ôººè;{%G,Àƒ>Èĉyùå—u•ú888`llÌ­[·t~/y[¯^½ÿös®š_…G5\`*Ü ¹ÃÚÂzJOO§¨¨ˆÁ×nÆÃ Ue„ LŸ>¥K5[¯tQ&T;;;¼¼¼0`€âo/--˜˜233)--ì^ÆÆÆ!“ÉÔÊbAÛNïmáåå…‹‹ ÑÑÑJ³)))œ0 ¬æÔÔÔpùÂeêÙPˆº%Ðb#{%ÇÓÓ“œœjkkÕº®oß¾¬^½š3fè(2ÕèÑ£EEEîU¥ VVVxxxзo_z÷î©©)¹¹¹DEE‘ššJaaa«¿y‰P¾ŽºY,hhzOOOoSœI¥Ò6ˉŸ}öï¾û.W®\̲B,ãáá¡v6U]üýý¹sç¹¹¹*ÿØcqþüynÞ¼©Ó¸„Fìè¿<Î’%K¸xñb“1d«V­bÊ”)„……é-–΀A`ý—+W2yï=Oþõ/Õ3Y{ö€1·oçcb¢›!³†¬ÿ‘ŸŸO||!Ð Â!(T˜YQ`æY,hhTÞ·ocÇŽ8*Õèê«9ÖÖÖôèу~ýúáçç‡X,&??©TJZZR©”ŠŠ 3'vvvü°y3SÃÂØ—Ç›••ü hœópîÞÎcüÝwD;FU3¯/GGGú÷ï¯h”Ö‘H„——iiiZ­ÓÇ'22Re/1è:½X$,,L­Ûú*¾óÎ;)lß?))Ie;‰»ƒÀjDee%{öìaÕªUìÜù ¹¹åœ={'ŸüŽÑ£¿æàÁ+”•I9{6ÄDÕæiCw.Êd2®_¿NUUÁÁÁMšÆ'™(¨Àšª}†æÜ¹sâää$@PÂÒx´&ØÙÙqâÄ FŒѦ9¥.èÌîÚbff†««+H$ÌÍÍ)..¦¾¾ž¤¤$òóóÕÞé¶ýƒˆÚ°©Õ Ið!°6+‹1½{·xÌØØ˜Þ½{cffFtt´ÆÙ5h°S¨¯¯§¨H˜ÀÊP7‹5`À\\\8uêT‹Ç:S‰PÝÞ«¿þú‹ÀÀ@ìííuUÃŽÌ¡C‡¶°w¹téGåÝwßÕéý;;ÕˆÏ?ÿœçŸ¾É±ž={2mÚ4æÎ«˜ÄneeŨQ£tîåÑ]˃ÄÅÅáææ¦T`ŽG…‡ ÷r¿ãÎ}aÚ;wÖì•u†A+Â?ÿü“#FhdE )w[«5ÌÌÌ033Ã××www$ R©”äädâããÉÎÎn·7+úâEÖ½û.»4ø–åä° •L¥³³3}ûö%;;[+o+]— ÕíÂΟÅÚºu+³gÏVkŽ >²W<ò‹-jѧ™’’Â'Ÿ|¢pmïÎÖÉËËãôéÓŠ>„ö˜9s&ÐiLÝÍ¢¡¶¶–ääd***ÆÚÚZéyC‡e”ý(øLË~Ã-‡kÝ”^RR•+W7nœ–émJ…а#ìâÅ‹Lœ8QP7óö¸›³Xr7º[YYQSSƒ§§'ýúõÃÇÇ‘HDVVÑÑѤ§§+2]yìÁÙ§…·Ó| äâE~üî;¥‹Åb055%&&FãÝ~~~™£ª‚º,høð1f̾ÿþ{Ĥ 555lݺ•Å‹«u.û¯²³³:t([¶laðàÁM+..fÑ¢EògÙÖQ·pРA”””èì…ºW‰°  €˜˜\\\T29üþÓï±Zkš¶†ä€ÅX¯½Hþᇘ>}ºÖëèkkkLLL(,,Ôj?ÿü“éÓ§ëeN tÕ–Uƒ¹¹9nnnÒ·o_¬¬¬(,,$**Š7npëÖ->~ÿ}ž//Ç_Ë8þ#•òùªUmžãââB@@ u¶³³ÃØØXå¡äê`mmM¯^½ˆŠRÏz¥³f±Ô- ‚nÅUDDK–,áòåËJçãv'—vU0, ))‰ÔÔT&Ož¬ÖuºÎbu‡a]]"k5pà@lllT¾öüÉóØ/°u7È•Ý|;Î:§æ…Ê9|ø0S§Nd-]ãíí-ÈöûS§N±`Á½øu‡2acedd„………Ò’ X,ÆÑÑ??? „““UUUüòí·ø¨ÑÜÝf4|°kOКšš„H$"66VíaØÞÞÞdffꤧO“,–‰‰ Ï>û,_|ñ…àñhJ~~>¿ýö›Ú¦¿?ýô÷ß¿àñ=z”¯¾úª… ƒœ)S¦päÈÁ§™te ? ÔÏ^ÉyôÑGÙ¿¿"jànX·oß&::Zå¬Usúôç-`âcÛU¼h'ˆ=Äü¾ñw TûžÍ‰ˆˆÀÕÕµËüž4ÝÇgéÒ¥:ÍâB÷È`5.‚êv ¶¶¶ôìÙ“ØŒ BŠehu5—OŸVé\777z÷îMZZšÚ›(tU*Ô¤ à©§žâÀz-·…&Ù«¢¢"1b„ ±|ùå—DDD°yóf¥?ùä“|üñÇ‚Ïâíêt{uùòejkk5êÉDL›6ƒ Wqq1&&&j56vêëë¹qãeee„„„¨•µjÎÿTU3á윗;çÀi@þá¿øX N/91þ·ñHK¥ Ô^\AçonW†&à[ãСC¬X±B§f ÝQ`©c8š““µµ´,ØhÆ BE ±÷éÓ€øøx•7RØØØ ‘H/5ûøøPWW§Q¿á‹/¾ÈgŸiÛÜ©=‰‰‰¤¥¥©]UÑEsû»ï¾‹‘‘«Z)¿ôÒK<÷ÜsŠç€ÿÑí–²ƒê0cÆ ¬»µÿJÞ;âää„···`ëžÜz’m“¶ñDöôz§b71^{!vãû–/󲿱í¾mœú¦åvlM©®®æ÷ß×I:^×hÛðÞ˜ï¿ÿžÕ«W-ÈzÍ177ÇÉÉI¬[gE$allLMM  žáhJJ “mm‹ehÔÀîîîŽÉÉÉ*¬éÙ³'999‚LRhŒ&eB€‡~˜ØØXRRR:Ô¦A“ì/°/^Ì AƒZØ0Èyÿý÷7n÷Üs`÷¼›èÖëÔ©S¸»»Ó·o_× ÄÄÄ„˜˜#»ûʃõõõ¤¤¤PZZÊ Aƒ°ð AΔ)SØùñN®ÿ~é)'ß?‰´LÊÓ7ØõÉ.šò ÷ëŠÙ+9šƒn]»v±nÝ:._¾,ÈzÍénY,±XŒX,VÉ#44”ï ‹ã ÐCÃwæææôë׺º:U2ýÔE©PÓ2!t|Ãû_ý…H$R{n_JJ R©Ta'¤-S§NåÙgŸåá‡Vúø¦M›ðððè2ý§A·Xšö^5GÍîw“À***"** |||ôv_m÷TµMWX ù0èÖØºu+Û·oçÜ9a64Æßߟëׯ ¾ngBÓ>,‰DBobŠ#\$"ô>í¼áä“䆩maee…¥¥%yyyZݳ1ƒ&!!A£LÜÈ‘#‘ÉdZù}iƒ¦Ù+¡šÛsss cÓ¦M 2Dé9{÷¬Œ… j}¿»™n+°<ȰaÃñ™z衇8yò¤Æ&ŽÊ¸[Vjj*ÅÅÅ 4;;»ŽG0bccÞØ”¸_w%„,|ñÅìÛ·ßÿ]°5¡k}V—Æ; A½2aèàÁ„ Çe±˜¡ÿÏÞyGEym}ø¡w쀈€ Ø¢‚QÔ˜DõcŒQcÁ’\‚‰1ÅÄhŠQ±ao±&b‰ƒ  `C@@DéEêC™ï?æ‚ 0>ÏZ,ךyÏ9{p˜wÏ.¿­„"iºwïŽP($""¢Ê4`»víHII‘iÌMu¸¸¸à'C-YYÜÝݹvíZ­§Ïž=‹\_OŸ>­ðpö   fÏžM`` mÛJs¾páAAA,Z´H¡³šMÖÁR´öêU”ÝQØÐ¬/^D‹-èØ±c]›£tzôªcccŠ‹‹•Ú9µvíZΞ=«T=œ¦–"Ù¬ pM i÷@ ›¥%fff ïUJûöíiÛ¶-¡¡¡U´+;U8xð`®^½*×Z[[[LMM‰Šªù‘he‘7zDûöíêâ;}ú4ÞÞÞœ:u 555‰×„„„pèÐ!V®\)÷9M‰&é`íÞ½› &Tª.ÊN6d+&&†ŒŒ úôéSã³°êŠÆâ`ò´±Êò믿âïïÏÉ“'•²Ÿ©©)"‘Ha‘ÔúÌ«–¶¶6€TQ·ÇŒ¡°wov+hÃÛššŒøè#†Ê¡C‡Üíâàà@~~>‘‘‘õ¯ôõõiÞ¼¹Ü33_E‘¼LÞ¾­¬¸`õ8p€‘#GÊ5ÏTQqÑmÛ¶qëÖ-¼½½+½æÙ³g,_¾œmÛ¶É}NS£É9X"‘ˆM›6±`Á¥îÛ¡CÚ´iÃÍ›7Þ+//¼¼{67¢£ñòòâðáÃ|þùçüõ×_DEEñÆoàãã#ã®’iÖ¬½zõ"''‡èèè uNÊLÊ+×PŠ££#7n¬Åù²lÚ´ 777444d^{ᆠ"ŽxÊÂüùóéÙ³'sæÌ©òº7ÞxƒþùGæý›:MÊÁÊÌÌäĉ|ôÑG5²ÿ°aà Q8ÑÒƒ™™™„„„ЬY3¬­­+ÍÝ7¢¢¢ÈËË£{÷îumŠÒQvÁ{)‹/&))‰]»¤•Û—Œª“°zÚ[[ãÌÇ­Z±DŠ¿Åû€•¶6ö òÅÆhjj²}ûv X°`Í›7gñâÅüñÇsùÔ)Zêë±hý|}Ù™˜H‘HD‘HÄöÄDúýû/‘_|A+CCüø"ÑdîŒ5Y{Uzöì©P}Ž`ÅÆÆ’œœŒƒƒ¦¦¦umN­rîÜ9\\\ÐÕÕ­kSj eƒ–ÄìÙ³iÞ¼9¿ÿþ»\ëmmm‰ˆˆP²Uõ‡Wµ°@Æ:¬WhÓ¦ £F曵kù+ €£¬ûóO¦Í›'Uš[CCƒmÛ¶QXXX®1¨]»v,_¾OOO.]ºÄ¤I“Ö>366¦W¯^¤§§óôéS´µµ177WXðS¹†RFŽÉóçÏ UhŸWQ$z²‰‹ž9s†Í›7ó÷ßWû¥ø×_ÅÉɉaÆÉm[}å¿&°|âD"òóùM(dЫÌó½YÀ¯B!–ŒÇgï½'×YMÂÁzðà)))¼þúëµrž¢Q¬úè`eggs÷î]ôõõ±±±iRQ«R{ôª333rssNÏTÆG}D»víXñJZJ{šPRËÈȈììì:²è%sçÎeÚ´iôïߟÿ•Ð[XXðË/¿°bŠΞ=Ë”)SªyRSSÃÚÚCCCBBBÐÕÕE ÈÁ+ÅÁÁØØXqdL^”źwï/^¼ÀÅÅE®õÏŸ?'==]ªÓŽ; ”*E¿}ûvš7oÎĉ岫>³dòdôNžä¢Pˆ4E-f€ŸPˆ¦?L*óyMâ.YµWeéß¿?qqqr}ó*))!11±RݺàÙ³g$&&Ò½{w¹4Zqqq$$$àääT×¦Ô 5™*xÿý÷±³³«²5\=‚%ÉÁ200@ ÔÙàáRúõëÇõë×Ù¸q#Û·o/÷œµµ5¿þú+K—.åĉL›6k×®É}–©©)$''£­­­pªPÅî}úôÁÐÐPá}JY·nîîîr¯—¶¸ý§Ÿ~¢°°eË–U{­ÉÉɸ¹¹ÉmW}e÷ªUÄ;Æ*9FƒýV\LÔ‘#ì÷ô”i]£w°ÐÓÓ£OŸ>µz®¼Q¬ú½ÊÎÎæÞ½{èêêÒ¹sg¹Zˆ Mûª:”= Zãǧoß¾|ûí·R¯iŠ,¿KÙ¨««³mÛ6Š‹‹™?~…çmmmùý÷ßY¼x1‡fæÌ™rëP©««cccƒ¡¡!"‘H¡BuEåJQVëòå˘˜˜(Tß$öÕ‚ èÑ£sçέv¿+W®põêU¾ùæ¹mª¯ädgóß%KØYX(÷û ™³h‘LmÞÁªíèU)òvÖëùóç$&&ÒµkW¥ŽÍh¨øøø0nܸº6£VQö0hI¼õÖ[¸¸¸ðÅ_Hu}cw°@rV}q°JqsscÆŒôïߟààà ÏwíÚU¡Ù³gnnnÉuVË–-éÖ­›X7K”Á‚—)Q'''…7½/Ý¿ccã*ïãÆcÚ´iR}1 eÇŽr×FÖwϘ>ÇN””°H™§Fí`9s;;;:uêTëgëêê2lØ0Μ9#Óººv°rrr¸ÿ>ÚÚÚtîÜMMÍ:³¥¾àççGÏž=Õ°ji©)m¬²Œ9’1cÆHU쫦¦†M£Öê,M(o¡{MÑ·o_®_¿ÎæÍ›+ŸâààÀÆqssÃÛÛ› pïÞ=™ÏÒÔÔ¤GdffòàÁ™êêê 8€€©×”í",‹¢Q,±°°{ªŠÛ“““0`^^^ôëׯڽ’’’øòË/Ù³gÜöÔwŽž9CO%ìãü)Ã=½Q;XµÕ9Xò¤ ëÒÁzþü9ñññØÛÛ+44´±ÑTŠÛ%Qà%áââÂäÉ“¥ªýhìQ,eJ5Ô4êêêlݺ‘Hļyó*½®OŸ>x{{3mÚ4qdKÖŽ‹~q1ʨnhJ]_Ýh¬C‡1|øð:Mo•7•¥(·.¬ÜÜ\š˜˜ ¦¦F«V­PWWçáÇRë¢)+M/åFöïß/³&ÛÎ;™8q"FFFrŸ}åÊ100(÷øÙ³gñòòâôéÓR×ËŽ5ŠsçÎÉmKCàöíÛ8)Q¡½oI ·nÝ’êÚFë`ÕUíÕ«ÈŪm«´ÛÑÖÖVµ’@SŽ^•RSà%ѧO>ÿüs¦L™Rá¹wb3؆9îsð~èÍ·‰ß²4g)oþö&­lZѾg{Ön][ã6Ö4õ½Ð½2œœœ ÄÛÛ»Ò”a)¯½ö{öìáwÞaÙ²e,^¼XêúªRÒÖ­[cccCLLŒTïM333LMM•60ü³Ï>cíZéßoEEElÛ¶­ÊHŸ4H*nß¹s'ׯ_¯ÐÝY“&MbÛ¶m4kÖL!{ê;ÏŸ?gëH—”H­Ø(¬mÛ¶1mÚ4¹†_*›ñãÇããã#õ·ëÚô,xðàšššØÙÙÕ‹ßU}Då`½¤M›6¤¥¥Uˆ¬ÔÝ»wgéÒ¥üç?ÿ@„§‰NÌÿ{>ÑDSœUŒè²VË ø\1EiE$üÀâ Åز'3;³Æí¬)ªƒ/ë–¼½½‰DRu®9;;óÇ0jÔ(¾þúk¾ýö[©jþJ,ºtéÀ£Gªíð’%MXY V)ãÇçÖ­[Rßl•ñ¥¿°°???\]]ÅýòË/°|ùrß5% IDAT©÷™?>_|ñÖÖÖ ÙÓ°··çœk‰ÿÑԿ窣Ñ9XìÙ³§Úé൉´…III˜ššÖxay||<±±±ØÚÚÒªU«=«!ˆ¥¥%­[·®kS굕*„ÿµû3 u ‚ÞBø‡,«Xd…[ ‰ø"³vfÄ&×lq~MѬRæÌ™ÃìÙ³éÛ·¯T݃Æ ãðáø¸¸àááÁÒ¥K«¬±jÑ¢êêêâ¹™mÚ´ÁÊÊŠèèh+]§Ì4!HÅJIIÁ××—>ø@¡ó^Õ¾úä“OèÒ¥‹LQ±ï¾ûޱcÇV;‡°±àèèÈm%–܉¤ÖCltV}I –EÚ4aM§>D]]{{{UÔªTÑ«òÔä0hIXXZpþâyÈ&ȰpeÑ©c'r Ã!)‹††jjj•{\SSMMM™txêGGGnݺ…···Ôá#GŽä¯¿þ¢ÿþÌ›7åË—WªÅfeeEll,%ÿ__£§§G×®])))!,,Lb´ÕÞÞžôôt¥é»9;;“-Qª¢,ʺ/•MN˜0©S§Ê$ãééI—.]¤¯Óñ÷÷ÇÃÃwÞy5@_ £“fÍ066–êúFå`%''‹çbÕ':uê„‘‘Q¹’¨I+!!ØØXlllT)ÈÍÍåúõëåBñ*j7Šå2Í…â-Å 'ßúâ?‹é?±¿rª%C«oooÔÔÔdRóÍ79qâ½{÷fÆŒüòË/{I¡Û¶m‹……)iÓ„Õ¥K©.ŠATTTµ¢ Õ‘œœÌ³gϰ°°`àÀxzzÒ¿¿ôïï½{÷¢©©©p­¾’‘‘ÁÉ“'™5kýúõcñâÅ<þ\Ü8㧦¦ðWÔÕ™,¡>´2•ƒUײ U!M«&¬¼¼êaIÃìÙ³qss£o߾ܹsGêucÆŒáôéÓtéÒ…É“'ó믿’™ù¿úºfÍš¡­­Mjjj¹uúúútïÞ¡PHDDD¹h ²Ó„]»v¥]»vøúúJ|^YÑ«3gÎàääÄ´iÓð÷÷—IGëôéÓDGG׻쎢DGG³{÷n&MšÄÛo¿ÍªU«ÈÍÍeÑ¢Eœ={–£G2uêT~ݺ•oôõ‘MØ£<±À2–Ë Öh¬ÈÈH?~¬ð·„šâ7ÞÀßß¿ÊGe;X ÄÄÄ`mmM›6m”¶oS@å`UNMƒXº~)ù_)ž +\\ÈÊ +•`QíÒ˜"X¥ôéÓ‡[·n±mÛ¶j» _eܸqœ;wŽŽ;2aÂÖ¬Y#þ,µ°° >>¾BJ^N#hÛ¶-¡¡¡¤¤¤/;oܸ!N-*ƒÊ¢X7oÞ¤¤¤„(|ÆÑ£G‰ŠŠâÌ™32ÕéÞ¸qƒþùG湟õ•;wîàééÉ›o¾Éœ9sرcZZZ¸»»súôi<ÈĉiÞ¼y¹u?Îx]]¹Ï «ËŸ§NÉ´¦Ñ8Xõ±öêUª+vW–ƒ•ŸŸÏ£GèÒ¥ º ¼©š"wïÞ¥yóæXYYÕµ)õ–šN†] ƒ^JØÈ'68§DKK‹B sÓttt())‘ø\CaË–-ˆD"ÜÜÜdÖ.›8q"çÏŸ§M›6¼õÖ[¬_¿ž‚‚‰©ÂR Åš„‘‘‘ãâ₟Ÿ_•gI›"077gøðáùä8 ÐùuARRGŽáÓO?eèСlÚ´‰+W®`ooÏôéÓññña÷îݼ÷Þ{Rœ¼1c¯Yƒ¶š'¥¸ÞÐæ¬_Ïf–Ò(¬†½‚—­Ä;väÚµkžËÈÈ@KK«‚:¯´ˆ£V]»vEOOIw§&Fqq1gΜa̘1umJ½§¦†AÁ åíW4¨ˆÀ @åmX Tå`5Ô:¬WéÓ§7oÞdÇŽr™:u*W¯^EOO÷Þ{èèè*µÚš5kFÏž=éÑ£—.]Rªú¿††óæÍcÆ ¬_¿^ªùšUñé§ŸbggG|||9yixã7øçŸ:¿6yôè[·neÊ”)|ôÑG?~œÐÐPºuëÆ¤I“8vìÛ·oç½÷ÞÃÄÄDîs&Í‹ ?Ÿ}ûâÒ¼93MÀÍÿÿÙ| ¼Þ¢û  ¨¨ˆ‰³fÉuVƒŸä{éÒ%ÌÌÌèÞ½{]›"¥Q¬W£mФIKKÃÚÚZåX)ˆªöJ6J‡AwìØQi{jii!ÊRâØ›lÐ6kX’$ÚÚÚ"‰P{¥ûÉÈȈ˜˜˜º1¬(íææÆæÍ›QW—ý{ÿŒ3˜1c$>>žôôtfUqSìÞ½;:t௿þbذa ݰË2mÚ4FŒÆ Sh:Æ„ X´hðrþ¦,‘šÑ£GsæÌ™ ïúƵk׸rå W®\ÁÀÀ###RRR°°°ÀÕÕ•#F`jjªôs5µ´8ÈÝ»w ò÷环/{>À©[7œGŽä³!CpppPìe[—xyy)4Ù¼¶qvvfÕªUœ:uЍ¨›ù“ššNzzÆÆF9²^½úKV …DGGÓ¬Y3ºuëV Ö7~Ž?ηß~[×f4ŒIKK#++Ki#7œœœP[¢¼ƒæ-M,-INNFOO}}}©gµÕ%¥Q¬Wk(õôô …7ˆ×! ³gÏÆÑÑ‘²aùE0'OžL||<·oß϶œ>}ºÄk‡Jrr2YYYdff*íKÂgŸ}ÆòåËåNA¦¥¥1vìX<ˆ……K—.•©yëÃ?díÚµ´l©ŒñÆÊ%++‹+W®àï]»vEWW‘HD³fÍÄNUmÙÞ³gOzöìÉŒRhÐÖñãÇqtt¬•Ñ2Ê"8ø:ÏŸßdÅŠó PÈÈ‘0hÎß_ÁÎî7.¡PÈ“'O044l0iц‚ª¸]>ʃVVcEß} xŠö­„C—.Äu…B!€¼¼<ÒÓÓÉËË£°°°‚Ó¥¯¯_giiê°“ƒUʦM›Ø¾};sæÌaË–-r¥ K» ,XÀ¬Y³Ø²e C‡eîܹ¼ÿþûâkòóó‰§mÛ¶Mff&––UÍdªœÜÜ\>̪U«X»v­¸Kþý÷_:T®nJÒ`çÊøñÇ>|x½hö G©ÔÔÔèÚµ+æææ$$$••…««+_}õU£tªÊÒ`‹Ü÷îÝË»ï¾Û`&õÕŠŠösçNEçJ‹Ã?ÿdòñÇÎDF>^*ùFDDо}{ÚµkWÃ7=|||d;¡â({ô¯ŸÿŠÞçŠ×ê~¡Ëî?Vx\[[›-ZЦM¬­­éÖ­´mÛ]]]ÏŸ?'$$„ÐÐPbbbHLL$++«Ö$´µµ+ý}6†Nª˜5kóæÍcàÀܼySæõººº“€ŽŽŽX#)..WWWŽ= PA®ÁÚÚCCCBBB …2Á—¶÷ïß555nܸ!պݻwãççÇÎ;Ë=.­ƒµiÓ&Ú·oÏØ±ce²WYqñâE~øá† ÆæÍ› …ôéÓ‡‚‚ž={F×®]Ù±c;wîäƒ>hô΀ZII‰«Ik¾}ûrëÖ­º6C*V­ú/ÉÉ›ùýwÙ»­ŠŠ@__BÑ×7¨ÑY…M™Ó§OsëÖ­F#ÆWdgg“˜˜HçΕ²ß¤/'qÔü(|!ç»ÁåŠ —v^RÈŽüü|øß¼¼>>\¸p¡®M‘ŠE‹¦ð÷ߊ¥M&M‚7"øë¯?™0á?J²LE)OŸ>åÅ‹*çJ XZZ¢4+5*s;sÒg¦Ãb)mýeúæÓ)MMMš5kV®DA$‘——'Žvedd——‡¦¦f…º®Ò檨ª þ—&l ÖÌ™3Å]†^^^ôë×OªuÚÚÚ˜™™W¡¬ÂÔÔ”o¾ù†´´4Î;ÇÞ½{qss§äÔÔÔÐÕÕ¥k×®jjjhjjVZóÕØë°^¥W¯^²gÏ6oÞ,õºV­Z‘››[éïjĈ˜››³qãF®_¿Î„ Ê¥å455éܹ3ÚÚÚÜ¿_¢Èkeb×Í›7gܸqìÞ½[üXzz:ƒ bõêÕ•:WOž<¡   ÒŽæ§OŸòË/¿Ôˆs•““Ù3gøê«¯xíµ×8xð ;vdÉ’% 8Ó§OóÇ`ddÄæÍ›Ù³g}ô‘ʹ’@ƒJ¾šã®ïøøbÿþ)üõ—â¿â‡áý÷͸?I –©(Ë믿ΩS§šD$ ¶Tû¢(7oÝäË5_róâMJôKPsRˆ ;ðóg?3bØ¥YS—‹v•¦uuuËE»h×®Ä÷fII ÷îÝk’‘×;wríÚ5¼½½¥JÁ*Q8R 0zôhq±{ll,[¶l!((ˆ.]ºàéé)¾¶°°èèh ű+W®pâÄ ~ÿý÷JÏ8p þþþ„‡‡³páBN:UesÓ¦Mèéé1cÆŒ Ïåää0fÌ.]R¬¶°,±±±âzªˆˆœqvv¦M›6\¾|___ Ä:Uª&+éhPÖâÅ‹5jÃ^êÔ{¾ýv&††»øúkåì§§§NFFn½ÓëiÈ\¸p___V®\Yצ4*òòòˆ‰‰¡K—.5²ÿÓ§O¹}û6EEE899UZÞÐ([Ó•——Gvv6êêꔫí*ÕÆª G¶¡p÷î]ÜÜÜX·nýû÷¯öú””òóó%ê&Î;W,vZʦM›ðõõE__777œË úMJJ"55kkk¦NÊï¿ÿ^¥´Ã¡C‡¸~ý:™™™å¢Y•ñöÛo³cÇZµjUá¹Aƒ•ÓÉ’—{÷îáççÇ•+W())ÁÙÙ™!C†`hh(þ\ÔÓÓ;Uª+Ùi05X¡¡¡$&&6ç ^vYÈ À[-“'·"((ˆ*oÓ&ÎñãÇ™2eJ]›Ñè(; º&Ú±---åÖ*ªÏ¼Ú˜@II FFF²²²HLL¤  }}}JJJHJJÂÌÌ }}}¹4£*={öäÆ|òÉ'1oÞ¼*¯733#22RâÔ!C†àïï_ÎÁ255eРAŒ;ooovìØ››¯½ö­Zµ¢E‹ìÚµ [[Ûjß‹B¡   þüóÏj_WPPíÚµ“è\½óÎ;=zT.窤¤¤œŠº¥¥%...¬^½šÂÂBΟ?ÏÏ?ÿŒ®®.Çgݺu JÄ»>Ò`"XóæÍcæÌ™899Õµ)RóÙgïcm}ç}ŠiÙR‹ˆˆ¥7u’’’˜9s&ÿýw]›Òh ÁÁÁ¡IÝø•Izz:YYYXYY•{\$!HKK#;;---ZZZºt4vîÜI@@ÞÞÞhjV7¨,­úìÙ3ÜÝÝ9vì˜ø±Ã‡óìÙ3¾øâ¥NHhh(ÞÞÞäääàææF¿~ý>|8[¶l¡°°kkk‰ªû«V­B__Ÿ.]ºpáÂV¬X!~N$qçΊ‹‹qttDSS“Ÿþ™nݺU˜‰úñÇãáá!ÓÄ„´´4q×ßµk×ÄQ*qçßùóçÑÖÖÆÕÕWWW,,,¤Þ_EÕ4ˆÖõë×ÑÒÒjP΀“ÓPþý÷ˆRözòš7×S9WJDUÜ^óXZZòôéS¥ƒnJTÖI¨¦¦†ÚÚÚdffŠg—ˆëºRSSÉËË£¸¸X¢B}câã?ÆÉɉ!C†°víÚJS†êêêtèЧOŸ–‹:uèÐ bbb*8³¥tíÚ•uëÖqïÞ=¼½½ùùçŸyíµ×èܹ³XRÃÄĤœæ“»»;C† á?ÿyÙý½ÿ~.^¼Èñ;¸|™„õõÑSWçzn.]ÍÍ)(*âØ•+åÎ^´h}ô‘TÎÕãÇÅ”“’’pqqa„ xzzÅùóç™5kššš¸ººV›ÞT!? ÂÁÚ°aƒÔboõ '§¡üò‹Py«µ´Ü¹ŽŽªÎÊÄÇLJ}ûöÕµššÝ”¨NªAKK uuu ÐÑÑÿ”¥¸¸X\DŸ““CJJ @¢fWUÑŸúŽƒƒׯ_ç“O>áÎ;ÌŸ?_âu¦¦¦dff’‘‘Qnî ³³3W®\;Xjjj•ÜðòòbÀ€´nÝš àææ†ƒƒñññ„……‰k³ÜÝÝËu ¶SWgʨQüV\Ì  7€@ ~þ^R÷€wœœ˜9k‹×­cåÊ• 0€¡C‡VúÚoÞ¼)vª qvvfñâÅtíÚ•èèh.\¸ÀúõëQWWÇÕÕ•Õ«WWêHªPõþ¯éܹstìØQü ­!aoo……99Q´A-&FŸ¡C')Ç0`ggW/'Î76”= º)¡©©‰H$¢¸¸¸Òn¹R¹†Êš_444022ª ”Y¶‹111‘¼¼<ÔÕÕ+8^ ­©fÆ ìÚµ‹™3g²eË´´´*\cmm]A È!lܸ‘>ú¨Ú3Ö¯_»»;S¦LáæÍ›¬[·CCCÜÜÜhÑ¢¯¿þ:k×®¥oß¾â5.vvô‰Š"¡¤¤Ò}þÿçü<¾Þ°nüû/¿T"åê©zö쉳³3ÞÞÞ´iÓ†èèhΟ?/=|øpV­Z¥Š$×2õ¾«ªnŠúNtt4‹BF†/¾¾²É)åöm˜?¿=7oÆ*Ѻ¦$Õe5GBB€JÝY=z„••U¥£xÒÒÒÈÉÉQJšG(V(,,”íªïuu÷îÝcîܹ¬Y³†TxþÅ‹ddd”s:† Ɖ'022âÈ‘#<}ú”E‹•[—––Æ”)SÊ e¸víëÖ­ãÙ³glݺcccrss騱#o9805<œ©2¾†“À ®ÇÄ'®§ -WO¥££Ã“'OÄ5U®®® >kkkOU¡,êuëÈ‘#¸¸¸48çJ °fÍîß¿Ï_,eçÎ"¶m;ÏìÙòí÷ŸÿhsåŠò4Oš:™™™ñ믿ֵ)M†6mÚðàÁLMM›Dѵ2)MVæ`’˜˜¨”³´µµÑÖÖ¦yóæâÇJJJÊ9]éééäåå¡­­]¡®KR´¨®pppàÚµk|úé§Ü¹s§Â¬?ccc233IOO×¶–¦ GÅãlj­Þ.èü*]]]V®\ÉŠ+hß¾=S§Nå«)S!³s0xôìΖ–˜ôî‹‹K¹f¯§OŸ²oß>Ο?OII ®®®¬X±BåTÕêukÈ!øúúJį̀¯lÛ¶ýû÷³páÂrÔ#FtfÁ‚(^i ©–qãô™5ko½U}ØZ…tìÙ³‡ììì3 ± ìaÐM…¸¸8455«ü¢yÿþ}ìííkÕÁÉÏÏ/§ÙUªF/)ÚU×ìÞ½›+W®°eË– ~pp0½zõ"==Oߟ[7nðT  —–fjjÓÚȈ~ŽŽL˜?ŸC‡sðàÁr{ìÛ·ÐÐÐr‚/^ä·_%êâE‹Š²¿ŸŽ/]¢ï€ÄÆÆâëëËùóç),,dĈ¸ºº6-¸ÆD½u°¶mÛ†H$bΜ9umŠTœ" +8^………£]jjjJ={Ïž=\¾|™Œ{÷p fAõKÊq£¥Å‘ ž+W®““ƒ³³3ï¾û.½{÷fËüù emWu\ÔÔä+Uíbƒ¢^9Xõ-zŒ§§'VVV>|¸Î;tTÈÏÇÑÑÑQuÝÔ#Ú·oOHH-[¶l0i­ºBš4¡‘‘ñññMFÌUKK --­r¥H$*×Ř‘‘A^^šššåêºþ½t‰¯•`ƒIïÈHºtéBJJ ¾¾¾\¼x;;;‚”g(K`IIƒSÕoêÔ+88˜ÜÜ\¹jš”MBBžžždddðõ×_«ÒÕ`çú‰j´thiiQXXXå5¥)¦Œššúúújû Ä…ôÑÑÑdåæb¥¤3€Ä„ºw«+vvvbÿcÇzöŒ>UoQ-c}}öîÝË’%KízõâDANRîû­®Î™ÿ¥”¢¼æææŒ?žñãÇpíÚ5øã?ÐÕÕ×nõé£hU˜ i¨s%÷‘#GÖj‡^JJ k×®%>>:MKª¨yÂT/Q ƒ®šððpÚ·oA•×=zô++«z1d¹¾2¼G¾yøá î“ô20 !;x9áãÅ‹ÄÅÅFxx8ááá4oÞœö­[ãwäc²³ù¡¤„Êú‹€ŸÕÕùËÄ„ƒçÎ1ç“O”"-®ÝzôèC† Ê«êk†:u°öïßOZZZ­·¯_¿žþù‡Ï>ûŒ‘#GÖÊ™*ê–!C†àëë+µ¡ŠºE5 ºr¤ýÝ<{ö ]]]ÌÌÌjɲ†CFF)))üó÷ß\_²„ÿ/X*/?kh úì3>ùö[bbbhß¾½DáèøøxÂÃɈˆàØŽÜ ÁPT„#  ·´´HÖÒbîÌ™,]·€çÏŸóé§Ÿâã㣭eÉËËÃßߟ€€®^½Š¥¥¥ØÙ²³³SÚ9M:u°ú÷ïÏõë×k\çðáìY³†O>ù„©S§ÖèY*êçÎÃßߟŸ~ú©®MQ!%ªaЕSZ£VÎÕ‹/ÈÈÈPI_ü?"‘ˆäädRRRÐ××ÇÌÌ ###¦ ÄÛׯ#olû>ð¡™ÇoÜ@$aee%õ½¬¨¨ˆ“'Or?0ÛW¯’••Ef~>źºôîÝ{{{:wîŒvvv<|øooo¼½½å´¶š×rÿ¾ØÙJOO/'ñªH« é©3kÓ¦Mèéé1cÆŒ;ÃÏÏ5kÖ0dÈ.\¨3lbÌŸ?Ÿ3fзoߺ6E… ¨†AK&--œœœjëU kòu‡ùùù¤¤¤ššŠ¹¹9fffâú¾¼¼<GDÐ×Ñ‘œ’ä™jh­­Ío»wóú¨Q2—¸Hà½aà éׯááá<~üXœblժ͛7'??ŸO>ù;;;LMMå°ºzRRRĩīW¯Ò·o_± D»víjäÌÆJ8X999Œ3†K—.ÕÈþaaaxzzbddÄÂ… iÛ¶mœ£¢þÇ‚ 8~üx]›¢B°°°P ƒ.CNNñññØÚÚV{íDZ±±i’Êß™™™¤¤¤  133«*MNN&--Î;“•šŠ¥%G q•rÿÇÀ¼öíäcGÜÝÝÙ½{·LS"$9ËgΜ!00Pâ¨¸ØØXÂÃÃ9vì äçç`gg‡­­-¶¶¶ØÙÙaaa!µ ÒrãÆ ð÷÷GKKKÝrr’¶\¿éR'ÖŠ+°³³w:(‹ŒŒ <==‰ŽŽÆÃÃCÕ)Ñ„©©Šš#//O5 úd‰L=}úCCËrÔGRRRHNNןI*ÜŽŽŽF[[›öíÛ‹ËÊÈ`LïÞtgua!•I´ ßÕÕÙa`ÀþS§àì ¼ŒFMŸ>I“&I=L>66}}ýrõZáááüøãìß¿¿Êµžžž´jÕŠQ£F‰ëº"""'))IœV,›bTVš/&&Fݺÿ>ƒÿ´h¡ŒžÌÆE­;XñññÌ›7'N(ußÍ›7sìØ1<<µê`=zôˆ+V°wï^…÷ºvíkÖ¬ÁÑÑ‘… 6ÉZ’Y¸p!ãÆcÈ!umŠ QuÄ•'**Š–-[Ò¼yój¯½wï]»v­R˜´¡‘ššJJJ ššš˜™™U¡ŽŠŠBWW·Òâìû÷ïcoo_ÁÈÎÎ&..Ž¢¢"Z¶lIëÖ­)))aÀ€xyyÑ¿ÿ*Ïœ>}:žžžë”222HOOÇÚÚºÂs_~ù%£G–zTÛØ±cñöö®¶³TIII¢]YYYâz®ÒÚ.ijþ^%==½œ DïÞ½ÅÎVcª–¥V¬ 0mÚ4úõë'÷QQQ¬Y³MMM.\Xë ð*ê7iiiL™2…þù§®MQ¡$"##177W‰!"[Ú4::“Ÿ&/**"99™äädLLL033«VD577—ÇÓ±cÇJѪ~—‘‘‘ìííËM˜?>YYYÕÖIÌ›7þýûW‡¦¦&­Zµª°ÆÛÛ fÍšUíþ¥ 0€€€¥ÔYåääˆë¹Jk»"""$ÖuÉÒ€róæM±³ˆ åñä¡°°ÇsÇߟ «W)*.¦[¯^8ŠSß¾Õ¦Þe¥Ö¬ÀÀ@öíÛdž äZŸ››Ëš5kxøð! .¬õÿ ƒ;vPXXÈܹsëÚJB%;ð?’““ …労+#))‰¢¢¢ÛZŸ››KJJ YYY˜››cnn.Uª811‘ÌÌL:wî\éõ•udfddCóæÍÑÐШm¹{÷.sçÎåï¿ÿ–ª`ãÆÄÄİzõjñcU)òûúúréÒ%~ùå—j÷.%==É“'sîÜ9©×ÈŠ¤º.ccã ]ŒÒ8þ±±±âBùrš[5)0¼þÇÙ½iÂ/p é˜ðr˜ö--nòé°V çYZjÍÁúðÃùî»ïäR‰Ýºu+`áÂ…Œ;¶¬SÑX3f Û¶m£uëÖumŠ %"­Èfc'33“ÔÔT:uêTíµ€ØØXìííkÁ2呞žNJJ fff2Ýt£¢¢ÐÓÓ«¶–èÁƒØÚÚŠ£S"‘ˆ˜˜±`hrr2%%%÷1b#FŒàË/¿”ʦ˗/³jÕ*vïÞ¹¹y•BºÑÑÑ|ýõ×>|Xª½K‘¶Q™ÄÅÅUèb …RŒ’R¡¥…Ârš[­[·;\ʪLKNf€ôzöŒ_‹‹©jÒéz`µGOœ`À°a Ÿ]+Ö¿ÿþ‹ŸŸŸ¸ËBZNž<‰§§'|ð³gÏ®!ëT4’ª¨ß¼zSlŠÈZ¼ÞPšŠ‹‹ÅjëÍš5ÃÌ̬ڙ‹e‘&%XÊ«)º´´4bcc±²² †V•ÆÛºu+{÷î§»¤!55•éÓ§³hÑ"Ú¶m[å¼Í~ýú(sºÊßßÖ¬Y#Ó:e’‘‘Q!Å+1Å(éï844Tìp%$$”“çï>5>ž:q¸ g)×ÄcõôØ|ô(ýT$PšƒuçÎîܹ€““S9 *Y ñn޼ɚ5kèÖ­V¦L¢BÅÿøæ›oxýõ×1bD]›¢¢P ƒ–}”P}¯_ËËË#99™ŒŒ ±Úº¬EùÒ¤KÉÍÍåùóçØÙÙQXXHLL ÚÚÚjy«ÒËÊÊâ7Þ`ùòå2wÃïÛ·##£*õ²Þÿ}~þùg©¢”¯rìØ1ÂÃÃùúë¯e^[SIL1¶iÓ¦Bбl´òÅ‹åd zöì)N%JU{-¡¥©I¾H„<Õiººì½p^ʱú% 9X>>‡ñòZÆåËa8:jáèXÀíÛš2lXúõMóæf,^¼¸ÚýbccY³f ………,\¸P®7˜Š¦Inn.o½õV•-Ô*>ªaЕw¾I¢¾¦V322HNN¦¸¸sss¹Q###Ñ××—Z^ 4 úâÅ ’““±²²ÂÈȨÂuÕukΞ=›ììl:$³½÷ïßçÌ™3lÛ¶Mâ5ß~û-...Œ9R¦½KÙºu+jjjõ>ëóôéÓ )Fuuu±NW©fWiÜ­[·Ä©Ä’’q*±²ŽÎ÷ `üÍ›¼'§}ÑÀÈf͈ÌÈs¹,S§A ¸ÃÒ¥T&Ãqÿ>,^¬Ž©é@öíó¯t7¡PÈš5k¸uë .dРA²›¤¢IóÇ’’ÂgŸ}Vצ¨¨ATà!""‚¶mÛJÙ¯OQ¿W‡.›››ËÈÉÉáñãÇtêÔIêè\||<%%%äää`ddTeñu¿ã«W¯òÍ7ß°wï^¬¬¬¤¶»4e{ïÞ=æÍ›ÇîÝ»+Ô%ïܹ“‚‚æÍ›'õ¾¯òÓO?Ñ£GÞyç¹÷¨ RSSÅ:]¥š])))êºôõõ¹víܹsGìl 2SSSŽ8ÀÙ9sØ)(d—š‰nnü¼i“\ëev°‚lZ¶4aÛ¶b¦L‘nÍÞ½0ož&©©éèé•ÃîÚµ‹íÛ·³páB&L˜ ‹)*Tˆyï½÷Xµj•J/© ÐÔ‡AË2§>8¤U ]–‡„„²³³éܹ³ÔuJ€¨¨(444°²²ªVb@A×Ò(“4Êí¥6”m:(**búôéŒ7®Ü½OYBÉîîîLš4‰×^{M¡}êš¼¼¼ u]áááX[[ckk‹ B¡ØØX133ãÑåˬˆ‹CÑb‘ ÀZG‡ô¼<¹Ö˨@'¢eKâã‹‘EZå£`ôè"ÌÍMÉÎ.^¶\»v-ï¾û.²™¡BEîÞ½K³fÍTÎUÁÌÌŒ°°0A“­­­P(”êZ555ôõõÉÍÍ•©h\¼:tYNÞãÇ144”Iü²4Úeff&•¼¼t~ª«›4i»wï–ÚÁÊÉÉ)ÓÔÔdÿþý¬\¹’åË—óý÷ß`mmMtt´T{Vźu똲²î2dH–-[¦r®T(Lqq1gΜa̘1umŠŠZDOO###’““ëÚ”ZGGG‡‚‚©¯×××' à+WndæÌE,Zô3gΜ#==]i6 …Bâââ&??™ê£ª"!!ÄÄDúôé#µs•™™ÉÝ»wÑÐÐ@CCCéÎ@Û¶m±²²’zô[vvv¥ö3†U«VñÖ[oH§NˆŠŠ’Úæª8{ö,£GVÊ^õÖ­[£©©É[J7xøÿ ²"µƒååõË—KÿG]+Wó×_Þ ï£B¼®ZUË³ŠÆKûöíÅ…ËM i¬ââÞ|s6-[š1iÒJ¾ù&Œ]»ðûïùŒ»–6mléÓgþþrÛ’Mtt4hjjÒ«W/:tè ´Ù°Ré‹D"žÕk®Hƒ†88h¬”ýT4]ÂÃÃ)))i’u8*^bllLqq±L5Iª¢XK–lgáÂÈDE@uZJ((¸ÎŸ¶¤G±ˆD•7•OHH+++:wî¬ôaÒeS‚ÒÈ8INN½{÷ÆØØ˜üü|^¼x!—þ—,Àøñã¹páyUtšÉÚdðá‡bhhÈÈ‘#‰—z]UôéÓ‡ñãdzdÉ¥ìW_122¢MóæD(i¿Ûjj899ɵV*ëöíÛ89Éu€$œœŠ¸}û¶ÒöSÑ4QE¯T@ÓŒbUæ`-_¾…ß~»ŒPø—Lû‰D‹xøð=z÷®8ë577—˜˜BCCQWWÇÁÁ ôôôä¶_² "™S‚ÉÉÉ„††bnn^NÝûÉ“'rwËê`;###Ž=Zé5¯vVG§Nxñâ‡fÞ¼yüûï¿R¯­ŠQ£FaggÇúõ땲_}eäˆJq°ž¯ÙÛW;~©2ê÷€**ª@Úî---Z¶l)V-o Hr°’’Rùé§ï åøû!š±zõnàåÐåððpž?N³fÍppp uëÖ52×0++‹©S‚ùùù„……! qpp(WLŸ@‹-äveu°ìììhÑ¢E¥ªî………”””ÈT—ÖªU+rrrÐÖֿĉøùù)mÆàÔ©S)..æÀJÙ¯>òÃÆL—bÒAuÌÖÑÁý—_ä^/Õ_Š““ÿÇÞ}Du¦m¿fd†¢" Ò!¨¨("؈%êkWPA]³Q£ Ö5Æ®±$Ù5æÓU×hŠ£Ñ5ö.‰Æ®±JG:Ã3Ã÷‡;ˆÔ)çÌ93sÿþ[˜yÎí»y³—÷óœû‰ˆPsdV""L4n¹§NÂ!CÔ¾·Œ¦Ö­[ãåË—*χÒw"‘5Ι ôOÈdG´ZW.߉O?]Žëׯ£°°ÎÎεîˆcZZZ²²²àçç§R—'==OŸ>…««k­·ËÊÊ››«ÕÕ@ …BíŠ&Mšàúõëµ~§n÷J©ú›„_}õZ·niÓ¦©½N]æÏŸ¸¸8\¼x‘‘õøÆÆÆkV­Â -þ÷áîýúaðÈ‘¯¡Ò?E]»vET3‡Æär 6¶Â¨¯º Ú£íAR“1mÖì`Ý»wOŸ¦Ðþš±²²©8yòÜÝÝY¥P(ªîŸSefII îß¿èСCCfµÙTR·ƒÁÁÁÈÉÉÁáõ·f5òZsTÃĉ1þ|tïÞññÚ¿(¶fÍìß¿±±±Z¯ÅGa+W¢ìí·±Nƒ/nØlk‹ígÏjUƒÊ1}À€öhäMT•ÄÅtÔ~!b´’““‘››K!¼¡yóæ‰DŒÎw⫚ëòåHH$LÌ®*+páB#kÕ§  ±±±pvv†ƒƒC£Ÿþü9^¼x//¯z»S°´´Ôzº¿&K,cРA¸{÷n­Ùlšv°êšèÞ©S'ܺu ëÖ­kôÍEUìØ±+W®4ØíõŸÿú Q={bŠÿ}~. ÌÞQÏŸký|•ÖG}ŽU«Ô{ݵ.+WšaÞ¼/´^‡/ê^‘ú¸ºº"%%…ë2XW3`…‡GèÊÐêxø½—RSS‘““ƒ.]º4ÚÙQ 533C»víê=ÇT^^Žœœ8::j]Ÿ& x}ؽzK¡P@*•júê6*°{÷n$''ãÓO?U{ÝšŽ?Ž1cÆ48öCŸ¸v ÿ·v-š5i‚ÝxÕªùÊ^€]|-,€©S—‘1³ÜTXAA¡°²ê‡ÖÖiçNÀÁ¡†§ÿq$š£á¢¤>B¡NNNxÎÀß>ù®zÈJIy &¶_q…HdÇxWC¡PàÁƒ011QéÚ‘¤¤¤ª¡vvv ~–‰­A%MV@@ärù%M»W@ýKiñâÅèÑ£BBB´Srúôé7®œ14“,@VAâðÀÕºZX ¨E ˜ …xÏÞWGŽÄÞë×ñéO?1ö\µþ)úùçËhÚTŒaÃdhäŸ÷ZRSùóÅ((Wï‹„TŽîÝ»«u1.Ær´2`™šš¢²R “±µóócakkËØzxöìÚ¶mÛè'¹¹¹HJJ‚»»»J‡ë333ѬY3ÆÎ‹i°`̘18wîΟ?Áƒkuɶ  òóóë56|øpøøø`̘1øâ‹/¨ñ³6oÞŒ÷Þ{{÷jú*¿YXX`Ý÷¯o‘¹{÷.Š‹‹q°[7Æn¨Ií÷msrráé)ÂîݪgçN C123_ªû8BÞ@ÛƒDÆpà½z«k×LmëÅÂή=D ¼æ¼¹%ØP¸R -,,D×®]U WåååÈÎΆ““#µê]•SÓèÑ£‘C‡Юƒ4ÞÅ^m‹‡‡‡ãÀøñÇ5~V»ví0cÆ ,X°@ã5ôI—.]лwoÖ AÀ27o†¢¢2\ºÔÁÁf¸{¨ë*0¹¸{9Ò ×¯÷GAffº¹Í¦ÌÌL<}ú½zõâºÂsÆp´X,®K1dHW4iÂÔÁô;ðõí¦õ*r¹\å-ÁêCÝÝÝU~†²ÓÅå½–šÎú²±±¯¯oÕ( ],¥M›6¡²²óæÍÓøy}úôAïÞ½±fÍ× ¯i<1n×®KøðýX´¨ÄbüýŘ1Cˆ3„ð÷ÃÌL€¥K}0{ö~üôm íQ÷ЍÃÐ/ƒ®ÞÁò÷ï ;;)#ëš›?Gpp­ÖÈÏÏǽ{÷àêêŠV­ZÕû¹²²2$&&Ö90´1YYY°°°Ð*ÀÔ¤Íö RPP,--±ÿ~XXXhu?£: ¦OŸŽ &`àÀ¿ì1vìXØØØà'Ï"+B¡¨ÿò)5DGGW]¥oH IDAT@¯ÐÆ >»wïnôÀ+!JyyyÈÏÏgì4Ÿ”––"))©ê.ÎI“ã×_,ÔbÕDØÚŽFVV‚Æ+¼xñåååðôôlðséééÈÍÍÕhÞVEE.EÓ¦!­'OÅœ9ï! ÀGíïæåå!>>îîî°··¯÷s/^¼ht`hc²³³annÎèÖ [„À«m¼¼<œ,,,ê•…{÷îÁÖÖ–Ñ lo *1±EXQQ…BSSSáåË—Zm2±EXÓàÁƒ±mÛ6L˜0W®\Qù{]»vŘ1c°jÕ*Fë1T°o•——#<<Æ ãºb í2heÀÊÈÈÀO?ý„•+W²òå– ——WwVêëë‹-Z0ö윜ˆÅbµ†jЉ€U}z»d2œœœpõêUÖ355…­­-RSSµª«&GGGœ?GŽÁ¶mÛTþÞСCѦMlÙ²…Ñz ,Â[GŽÁ˜1c¸.ƒ;;;”””@"‘p]ŠÖD"d2æÌ™ƒ­[·²òŒê[‚u½ý—žžŽÇÃÙÙÎÎÎŒ>[¡PàÅ‹¬o *1°j^ð¬œìη.–Ò† `jjŠ9sæ¨üÉ“'£¢¢û÷ïg¥&CA‹ðm¶ÒVáÊx)//opKP"‘ >>€æC£«­A%¦;XÀ«¡£·o߯“'O‘‘¡Ñšl,˜6m¦L™‚~ýú©| ~Á‚ˆ‰‰Ax8]…W X„—îß¿±XŒ6mÚp] 1@Ê;ìôý2è¿þú EEEŒ¿BÿòåK<|ø°Þ-Á/^ %%žžž U¥F·£í!w…B©T ‹ªŸYXX 00]ºtѸ‹¥éDwutïÞgΜÁÒ¥KqâÄ •¾³víZìÛ·O£ùZÆ€á%ê^¶éûeЉŸ}ö–/_^kTƒ6’““Q\\ ŸZ[‚Õ†z{{×ù!*++‘’’777VÖ¯ Ý+¥àà`¼|ùRã· Ùî`)YXXà÷ßGtt4Ö®]«ÒwvìØ+VhÜ3d°/ÑpQ¢ ú<Kyîªæ¨M•••áÞ½{hÖ¬YÁ&99™±¡ÑõÖ ÀÎù+¥ž={"99=zôÀ™3ªNØMWKiõêÕhÓ¦ Þ{ï=TTT4úù'N 88Xoÿ²Â X„wŽ;†   ®K!N_/ƒÞ¶múôéSÕeÒ¶ƒ•““ƒÇ£mÛ¶hÙ²å¿S mÖ¬#C“›› ¡PX5ËKWØì`¯Îb5oÞ\£mB¡PWWW$%%iUŸ:BBB°jÕ*ôë×ÑÑÑ~þÌ™3ôÆw °ïÐö Ñ%};ð‰˜˜L›6 @ÝÓÜÕ‘””‰D‚Ž;B,Wý¼æÀКÁ‹-IIIŒÎÐRÛ+((·nÝBii)=z¤öÚºîb@»vípýúulÛ¶ {öìið³666Ø´i&Mš¤£êøá•'Ož@"‘ S§N\—BŒ„¾]]s$ƒ¦«¬¬ qqq°´´¬õbvv6+CÃÅÖ ’¶ÜKJJ`aaQoç½U«Vððð€¿¿¿F],]t¯Ï?ü€¼¼<,[¶¬ÁÏy{{#,, .ÔQeüF‹ð u¯ôå2èyóæaÆ o@‘H¤VíÊ-Aooï7®²)//ÇÇ!•JÚåµ-ÖÖÖ:{fuÚv°ê^))'»9r•••j­Ïô•9êúè£0hÐ Œ9999õ~®oß¾ Tù¼!£€Ex…·®ðýÀû¯¿þ Öú:]¬ê[‚"‘¨êçéééxøð!9¹û“Ëî }K•€5hÐ \»v cÆŒQûB.;XJÄŽ;0iÒ$\ºt©ÞÏ…„„ÀÊÊ ;vìÐ]qþøã:¯JÀ’J¥un VêããÓhH`W箪ÓE x5²¡yóæ8|ø°Zë»»»#%%…ó7õZµj…3gÎàÔ©S Þ0sæL¤¥¥áøñã:¬Ž_(`Þ íAÂ5¾xoì*‘HÔàëôÙÙÙxúôi­-ÁÔÔTÖ†6&?? …⺸ MÀ’J¥‰D*uÀ‚ƒƒqõêUXYY!**J­çp½MXÝúõëÑ´iSÌœ9³ÞϬZµ .\ÀÍ›7uXPÀ"¼ššŠ´´4tëÖëRˆããeЫV­Â‚ <›ÔPëÙ³gJ¥èСCÕ– r`¨‰‰ «CUÁõÖ ’6«¨¨Í›7Wé³o½õÌÌÌУGµ»X\¼IØ÷ßaaaèÝ»w½ÁoË–-ظq#çÛ›\ €ExºW„/øtôñãÇ!‹1tèÐ?WWÀ*--Ell,¬¬¬Þ8SU}`h«V­X©[UIIIpssãÅÌ;mÎ`Õ7`´>AAAÈÌÌÄÍ›7ÕšÁæáá¡ò]ºâïïððp¬Zµ G­ó3À‡~ˆ¢¢"WÇ- X„5·3èp;á>lfffâ‡~ÀªU«ýlÍ€•••…¤¤$tèСªó•——‡èèh mLAAär9ç[ƒJÚt°T=¥4zôh=z¡¡¡jlà[KÉÔÔû÷ïÇýû÷ñÕW_Õù™Ó§O3~g&ßQÀ":qáÂ,Z³ÝÆuƒ§ <úzÀ­§‚þ„…ËÂÛÛ›³×³ ©‰—A7vîª:TVVB.—ãéÓ§(//Gûöíabb…B§OŸ"??]ºtÑÙÀÐÆðekPIÓ€¥Q}Hkc„B!FŒ-Z¨°øt«.+V¬@ÇŽ1qâÄZU333üúë¯ á¨:Ýãö¯0ÄàU¢ýþÙ‰-‘m üÀz ß5ˆžG<‡0Bˆ¦7š¢í¾¶ø×»ÿâºdB¼º úîÝ»°µµ…P¨Û¿‹®_¿ãÇWë²c‘H„¸¸8¸»»W]3“ÔÔÔ7~ÆÉÉÉpqqÑùÿ]ë#—Ë! 5ÚªT·{¥„­[·¢}ûöøûï¿Ñ·oßF¿ãèèˆÜÜ\H¥RNÏÍ5dôèÑðññÁÀñŸÿüU¿suuÅ'Ÿ|‚™3gbûöíV©üø§›¤SŸ‚ÈT„«#¯"û»là+!ÜñꟼîfŠ %aÁéèÚË’ y³±._¾ŒÌÌLŒ?^åïdffB&“ÁÅÅVVVo íÒ¥ ¯ÂUaa!***xÓIt{þJ©K—.ÈÍÍE¿~ý b›°:///\½z;vìÀÏ?ÿüÆïüýýŒÕ«WsSœQÀ"¬8{ã,Þýú](ŠÀDÕ¾#Û+CÄØøŒôa·8BT¤ëË KKK±jÕ*|ûí·*çÉ“'Éd°µµEEE2228Ú¾m º=U]pp0’““‘œœŒ´´4•¾£KiÛ¶m())Áâŋ߸ù°aÃàåå…-[¶pT™nPÀ"Œ+–cÔ Q(:[ˆÿüÞâGÄcÄœ¬ÔFˆºtyà]sW‰111°µµ…““€W,…BÁÙÀÐÆ¤¤¤ÀÉÉI«‰élÐ4`Éår”——k<Y“Ãî|˜è®Ž9sæ`Ĉ6l233«~>yòd”——ã·ß~ã°:vQÀ"Œë5®äåš/0 O Ç©?O1W!ÒÕeÐßÿ=Uºè<33)))ðññA‹-ššŠ¼¼<˜™™ÁÑÑ‘Õ:5UXXˆòòrØÚÚr]J-š,mºW`ii‰®]»¢U«V*,}ê`)½óÎ;سg>øà„‡‡Wý|áÂ…ˆŽŽÆŸþÉauì¡€Eµç×=xîÿ¦Ý:åG˱ðº‘ðÛ—AGEE!** ~øa£ŸUn z{{C"‘ ..&&&hÓ¦MƒÓܹƇëpê£iÀÒôüUuAAA8{ö, €S§ÿK¥>,°µµÅÉ“'qáÂlÞ¼¹êçëÖ­ÃÞ½{Çauì €Eµ7|/ =8¯Ò HIKÁ½{÷´_‹°¹U¨ÊÖ`IIIÕ[NNNHIIAFF¼½½ÑªU+ˆÅbÖ ¶ž?ŽÖ­[s>{«>šr×¶ƒ}úôÁýû÷1xð`•ºXvvvJ¥z;´síÚµ°¶¶ÆôéÓ«~¶sçN,_¾ü-DC@‹0ênä]ÀŸ™µ¤Rüñ3‹¢%KKK˜˜˜0~ôÇŒo¿ý¶Áð‘‘‘/^ sçÎP(ˆŽŽ†……Ú´iSuý  Ú¥ÏºVTT©T ;;;®K©— xuëÁƒ¨¨¨@bbb£Ÿ××.–Ò¤I“0kÖ,ôêÕ«êÏ{òäI5x™uQQ.]º„?ÿüùùùº*Wc°cÊËËñ2ñ%ÐøÕ—".1´!Úcº‹µoß>¸¹¹áí·ß®÷3?†B¡@›6m””T50´®³L| X||k°&M¶™ WÀ«mÂãÇ«|Ø]ßøùùáÊ•+øâ‹/ªîd|8.^¼ˆàààF· -`À¨Q£°nÝ: 6 ó&LÀÿ+.ÆW••*Ee%vää ½ƒ‹Uª‡aTWÿ®@$3k™E˜¡_@?f#„Aõ]3gÎ`ûöí¸|ù2Š‹‹k}÷äÉ“hÒ¤I­³&ÅÅÅˆŠŠ‚ òóó5Ê—€•šš {{û7à󙺇ÜKKK!‹˜ŒèèhØÙÙ!""¢ÞÏYYYA(2þÂ×<<<ÐÏÝ¡YYÖàûæååᣠ ¦KÓ,¨)C¦ Eb íÊ<Ü<о}{í×"„ÎÎÎHKKƒB¡À¤IóÑ¢…œœ|0zôñÑG…<ø3X[;ÂÞ¾=æÏÿ ••…mÛ¶áÓO?}c-å– ƒƒ²²²àîî®ÑÀP>¬’’£U«VœÖ¡ªÊÊJ( µÂÓÝ+%u»{yyáñãÇŒ×À¥˜èhœ8x+µXã_â.^ÄåjM¹B‹0j|èx´Mj ¨~wiLG™bÛ§Û˜)Š–üõ׫!Ÿ¿þ:EEW!“e¢¢âd²%¨¨ø ry!rrŽbËW´hᎠ¦Ö:wõèÑ#”••¡¬¬ B¡íÛ·×øê¡P¡P™LÆÄO#ú´5ðãü•’··7 \\\Ùà(CÜ&\¿`¾“Jµ^g«TŠË—3P‘v(`ÆÝüý&0^óï ¾ ¸O0úöèË\Q„0lîÜX¾ü€áê»X¹Ši(*úׯgàÒ¥^Íô‰ŠŠ‚P(DEE¼½½áÀÀù.»X©©©°³³ƒX,æäùšàÃù«ê‚ƒƒqìØ±F»{xxàÙ³g¬ÔÀ•S7n ëtp¼-V]¡€E'€×c®£ÅÀ@¶šßÝ*@÷Øîøíý”è¿©SWàû\V­+**"1{ö°ví6¼xñB¡-Z´¨50T\,‰D‚¢¢"½ÙTR÷ü•ò-M¶B¤ª@ZëÉ“'°­¬Lþb1"#:¬! X„=;õÄ©õ§`æc¨²ÓWˆGŠñÑÿ‡{o°^!šºv-û÷Ÿ…L¦Ù¶Tz+V| ¡° :wîÌøåÇ\,}ÛTR·ƒÅf÷ xÜ €Û·oÃ××ýU÷m†v+""j¼5ؘ€òrDÜ¹ÃØzš €EXØ5’L ‚ïÃqŠ#0À¼ãPà<€¯ÓPSØúÛâ—Ù¿àÜOç8­™ÆŒ5åå Ï)jLeåAL™²B!óÿ æbVZZZ¶l SSS>— ê,¶Î_U§Êaw XZZ"##ƒÕZt¥¸¸Î ®ç@RRÂàŠê£€EXwdëü1ç¬óY‡A7Áišö¼»©Q©?\‹ƒ[„èÀÎ{PZ:¯Fj#—ã ÃÖu«´´Œœãß:XЭ[7¤¦¦ÂÙÙéééõÞ`(ÝWƒªÿbð/—E"øúù1¶ž&ø}1Ý»wG÷îݱ‹¹.…?~eeuÍ”V_n® ®^½‹nݺ1²ž’®Ö³gÏàé©màäŽ\.W9`Éår”——kü–§:”‡Ý•]¬º®TRn²^ÛºvíŠèòrT¨û"(õDTV" €•4G,BQQtt¦þ¥í‹™?„+‰ —Ë¡P(_»¦ôôtX[[ÃÌÌŒõg±E–.ºWJ5V] ©ƒþnnŒÌ©~ ÀÞÊ ––– ¬¦9 X„¢¢/î`ªãäøxvÞrÒEK*•"//­[3xÁ;Ôy‹P篔Z¶l oooܹsC‡ÅñãÇk}ÆÐÞ$œóÉ'øžs|ߋŘ»`i‡!„¨ ²²B¡S×£ˆ °ó¯`],}}k°&¾v°€×]¬>|¸Öï ­ƒ5%, YmÛâ„k\pÛÉ s—-cª,QÀ"„88tÀÔÁô;hÛ¶3Ck½‰í7 ÓÓÓaee¥“³HlãsÀêß¿?"##áìüêýºøøø7~/‹ÑªU«zÁë£Cwî T‹Ãî!b1]»Æ`Eš£€E!*òõ ÀÔ„è(ôïß•¡µÞÄfÀ2”­A%U–®Ã•Rc],CÛ&‰Åx‘”‘ªñ½[œÄbÜŽŠ‚OÞh¥€E!*5*bq|ãT¥e"ú÷÷gd­šØÜ"LJJ‚»»;+ksïK9+((gÏž­œ -`€³3§¦âë·ÞÂä6ðÙKš4ÁÇNN¸•˜÷L\¶Ã X„¢¢3¦ÂÄä€L-W ‡««Ý»wg¢¬ZØ X°´´„……ãksAî\,www´hÑ111u¾Qhhç°”llmqñÑ#ø|ù%:8ÀC,Æ8ëlð^b1ºZYÁ~Ù2ÜxþÎnnWý& X„¢†ƒB,§Õ&&ãpé’vÓàÂFÀ*++ÃË—/áèèÈèº\âóù«êšìnˆ¬êf-Y‚È/p)1ÿØ·ù3g"kæLŒÝ³çããñ('‹¾ø‚ë2ëDƒF !D ÆõFP?ŽY ¹|Úß75 ÁçŸ+ª{E @$¡¼¼œ±K‰ å­ÁêT X¥¥¥055eåj#UáË/¿ÄÊ•+Ѻukܾ}»ªûiè „B!ÜÜÜàææ† ¸.GeÔÁ"„5ýþûFŒ'‚Hô¡ß*„™Ù |ñÅ8,Y¢Î÷4Ãd+33Í›77˜­A%UVQQš7o®ƒŠê×ÐàQCÝ&Ôw°!Dûö}‰Ï>뼚¾STÏ'3!†H䊽{—`Ñ¢è¤>¦Vyy9²³³áääÄ@Uü¢ê,]­2`õïß111ÈÍ}}ô[yeá X„¢¡åË?@fæSŒµ"‘3‚· üÀw ƒab⌦M»àý÷o ¬,cÇÒYmLj0Ä­A%¾¿AX$ ž>}Z«‹åáágÏžqX© ,BÑ‚µµŽû7o^Bhhöî‰5k$˜?¿-–.Š¢¢tìØñ­Îëb¢ƒ•••…¦M›rÞ½a‹*¬²²2…BˆD"UU¿ú¶ á–>¢€E! HHH@Ïž=1qâD,]º¡¡¡ÈËËã¬mVEE233«¦ˆ"U:X|è^))–µµ5ºvíŠððp°øŠ!„0 >>ª 9äzÛFÛ-BCÞTR%`ñáü•RÓ¦MѳgO„‡‡¿ÑÅruuEzz:***8®TG‹B€öíÛWýg{{{C"‘pR‰‰ *++!—ËÕþnVV,,,xÓ¹a‹¾u°€×]¬€€dgg#99½IÈG°!DKÅÅÅÈÍÍ…««ë?wwwGRR7EA³mB™L†ŒŒ ƒÞTjì –L&ƒL&ƒ™™™«jX¯^½ðäÉdee½ÑÅ¢mBþ¡€E!Zª¹=¨¤Ë¶•ë`ñ­{¥T×aw XüC‹B´d(+;;fffœÕÔ•ÆŸÎ_U§¼:ÇÄÄ#GŽÄÑ£G)`ñ,BÑRÍóWJ\,uºËår¤¥¥ÁÅÅ…åªøA¡P@ƒ×ßðµƒåàà777ܺu«ª‹E‹(`Bˆ–ê X\¿I¨N˘¶ÆÏ_UVVB"‘𲃼îbµk×"‘999(,,äì¥ R,BÑB^^¤R)Z·n]ëw\w°T X999‹Å°´´ÔAUü ¯ç¯”Œ+W® ´´”ºX®éë÷ê” Æ‡ÂÂBš…Å#°!D <€··w½¿ç"`½÷Þ"´iÓ#F¬Åž=MpíÚ»¸re2¶l‘ (h<=1fÌ,¼|ù&&&hÑ¢…NëãCè`yyyA,#>>!!!ˆ§PÀ"„-4ÖÁrss«š¶Í¶«W#aié}ûQP»çÕ­ IDAT¹ü€5BŒð%äò³()y„cǺÀѱââ¸;„Ï¥†¹K$˜™™5ø†!_(»XNNNpwwǃ¸.‰üÿÿé!„žÊÊÊB“&MвeËz?£«3X7n<ÀàÁ“Q\| À¾1‰?~)Nœ¸ÁruüÓPÀÒ‡î•Rõm‰'B"‘   €ãª@‹B4V߀Ñêt±E˜’’ŽwÞ©ô>75¾ÙRé-L˜0wîıU/5´E¨篔š4i‚aÆáäÉ“èÛ·/"##¹.‹€!„h¬±7ÀÜÜ–––ÈÌÌd­ŽÞ½CQQqHãïK¥`èÐP+⿆–>u°€×3± ]»v8zô(Ç€!„hL•Àî6áW_mBFÆ0½´X¥ ?‚Ÿ1TÿÕ°ÊÊÊ  !‰8¨J3~~~xùò%RRR0pà@ê`ñ,BѪ‹ÍmÂmÛvC&©õ:ryvíÚÅ@Eú¡¾€¥oÝ+¥   üñÇPÈå¨Èʨž=ñþˆØüÙg¸qý:¤R)×%úßQ%„R¯ÔÔT4oÞ\¥éçîîîxôèã5Èår¤§ÇèÂÀj.H¤ÈÎΆëñ[}‡ÜõéüUuñ—/c÷ž=ðÐS&ƒÿ“'0pçÌøúk¤ˆÅøçøñX»s'×¥ ê`BˆTí^ìmÞ¹s&&Ý[O¡@DDcëñ™¡t°îEF¢}Ë–°Ü½r9®ËdØ ` €ø€k2žK$°ùùg¼Õ¢¢®]ã¶h#A‹B4ÐØ€ÑêØÚ"ŒEeå0ÆÖ“Ëÿ±±ñŒ­ÇWõ…+™L™L333ªR_â;Û§ŽæåaEee£Ÿ_àbQ&„{W®°_ ‘£€E!hlÀhu666Éd(,,d´†V­ZA ˆbl= ­ZÙ2¶_B÷*ýùsôïÓ¥R´Sã{îI¥5x0ž=|ÈVy°!D#ªŒh¨ŽmÂnݺ¸ÃØz"Q$ü[¯ áüUhïÞ8ÜÈEÞ ù£¬ ¡ï¼Ã\A¤ X„¢¦¤¤$ØÛÛÃÂÂBåï°°!UHg`µrÈdáããÃÀZü¦ï¬ÿ|õgdh5˜ÃÀ¸œ¬[µŠ©²H °!DMêpWbë ûàÁÁ˜87uýúc`þ«+`UVVB"‘èEkÇÖ­­¨Ðzq2~Ú¾ŠH](`BˆšÔÝØ;èþã_ÂÄd‚Öë…¡2Ä—Šø¯®€¥/Ý«²²2<ÎÊ‚j§ÿö€œ‚º»%°!DM|ê`µliƒ+¾F“&35^C(\‰3>„™™#FŒ@xx8ƒòO]g°ô%`EFF¿žKª5áOw²†!„¨I“€åì쌌Œ Èd2ÆëùôÓé0@à+ ¾ýºtIÀÖ­Ÿà£>®]»páÂ|øá‡ˆ7Ì‘ úÜÁЉ‰Á`¹œ±õWT .6–±õÈk°!D =‚‡‡G½7„Í+sÎÛ†Þ½ïC$¯òwLL¦ÁÏï""WýÌÞÞk×®Åܹs±nÝ:¬^½ùùùl”Ì}î`µlÙñcëÅ °¶±al=ò,BQƒ&Ý+%6/}€Ë—÷!8¸%€& 78 «Ú'^8`LL,ñõ×}y¢Îµ|}}±{÷nôêÕ ãÆÃ¶mÛX«[×jv°JJJ`aaƒÁ…-ˆ2÷?Ý"[¼F‹BÔ Éw%6;XðüùsÈd™ËeX´¨:}sóÎ03sEÓ¦í`fæöí7`Þ¼俦aÑ¢÷]sذa¸páLMMѧO9r„µúu¥fÀÒ—îxzz"W =E)€§r¹Æa £€E!jЦƒåææ†ääd†+zmýúõX¼x1Ö®]‰˜˜“()ÉÀÇ×wI6îß?‹ >W;PL›6 .\@BB&L˜€[·n±ô§`_],}Ï üÎ;xÀÀ:ñBúôa`%R X„¢m:Xln^¹r&&&èÕ«öøIggg¸»»ký 333|òÉ'X³f öìÙƒ?þ)))Z¯«kúÜÁÊÌÌDèܹø§X¬õZ“Ḭ́|ófª"u¡€E!*Ò¦{°»EøÍ7ß`É’%¬¬]“§§'þûßÿbܸq˜?>¾ùæVÞŽdƒB¡€@ ¨:o%•Jabb¢ÑK º”••…˜˜Èd2 :Ó§OÇr-Îb}.bÜ{Lîç ,BQ‘¶K$ÁÞÞ©©© VüòË/ ôéÓ¿üò‹NŸ¯ }ë^)ƒUyy9|||àää„&Mš`éæÍxàë‹4Xs/€ÞÞøôM¾MTE‹BT¤Íö Ó],©TŠüsçÎelMu77nÜ@AA†Ž‹/rVKcôåüUVVbcc«‚•³³s­ÑG"#q¤sgLW£û6G(Ä×VV8Çtɤ X„¢"m;Xóç°”Ûù`îܹؽ{7ÂÃÃñÁðrP)ß;XÙÙÙUÁªC‡u«êÎܽ‹îŸ‘߸ ´Ú葉ø€­‰ :®\ ß!CðäÉVÿ„!„¨¤¢¢ÉÉÉðòòÒj&VBB=z„   FÖc‚Ö¬YƒyóæaݺuXµjòòò¸.«Jõ!£P(055帪×ÁJ*•V+UÏ…}¸|9žffâéŒXéé Û&MÐÑÂ~ÍšÁ¦I,óðÀ“?„{çΘ¾r%BCCqèÐ!–ÿD„ß§ú!„'˜è^¯¶?Î@Eüê^ÕÔ¹sgìÞ½gϞń 0fÌÌš5‹ë²Þè`ñ¡{•ôôtX[[£C‡¶·²²ÂºjÃ` P(бãëk¡·oߎݻwãƒ>@·nݰlÙ2­ë'õ£!„¨€©€ÅTëôéÓpqqA§N´^‹MC‡Åùóçy3¨´zÀâòüUNNâââª:V...Œ¾Éؾ}û7ÂLž<¹êE„qãÆáàÁƒŒ=ÔF‹BTÀÄw°´´„‰‰ rssµZ‡ÏÝ«ºðePiõ-B.:XÊ`%‘HàííÍx°jˆ……†ŽC‡!$$‡nüKDc°!DLu°í»XÛ¶mäI“8ßÞR•*;X …R©:ynÍ`åêê ‘H¤“gW§ìb½õÖ[°´´Dtt´Îk0°!¤‰ÙÙÙpsscd=mVNNŽ?ŽiÓ¦1R ¸Tª Xºê^åääàÞ½{œ+¥Ö­[ÃÇÇ.\ Ãî,£€E!`²{h°ômk°!\ *Un²}þêåË—UÁªmÛ¶œ«ê”]¬ÁƒãÆ(**âº$ƒD‹BÁtÀÒtØè;wPTT„0V èrP)Û,e°*..® Vbî d’··7,--qûöm:ìÎ" X„Ò¦¸+i° ©{U] *e+`½|ù÷ï߯ Vnnn¼ VÕ)»XtØ=°!¤Lw°Zµj…‚‚H¥R•¿óûï¿£[·nððð`¬>bsPieeå‡Û•>k#77·*Xyyyñ>X)õèÑyyyÈÏχ··7þþûo®K284h”BPPP€’’8::2º®²‹¥jglýúõ¸sç£5ðYÍA¥£GÆìÙ³ÕZC¡PàêÕk8w.×®E¡°°Ri1ºvõGÿþЬY3899iT_nn.ÒÓÓÑ´iSxyyñb¼º¦L™‚Ý»w#$$@ß¾}¹.É P‹BpÿþýZ™ Î6¡¡o 6D9¨ÔÜܽ{÷Æü¡Ò÷Ξýžžý0tèJ¬Yóÿ=wïþÌǾ}M1kÖa¼ýö,[ö­Zõäææ">>………ðòò‚»»»^†+தê¨cî^ÕdjjŠåË—cݺuøõ×_1oÞ¼ZƒJûôyÇ»¢¼ü W P|ƒ/þŸ`¤¥eÖú}^^âã㑟ŸOOO¸»»L¸€ñãÇãĉ1bÍÄb,BiÓÜ•TÙ"ü믿дiStïÞñçë3lÙ²&LÀüùó±nÝ:TTT 4t®_ï€ÊÊ…j®Ø99¿¢C‡^U?©¬<<< *XU7iÒ$>|ï¼óNŸ>Íu9ƒ!„Ô#''•••°³³c|mU:XÔ½jX`` >Œ·Þz ]ºôÂñã7QY¹DÃÕÜQX8¡¡#!!Á(‚•’ò°;Mvg,B©[Ý+puuErrr¿ß¹s'FÅJ¸34¡¡¡(+k™ì”–+-ÂåËÈÈÈ0Š`¥$‹1vìXÜ¿eeexøð!×% X„R¶Î_)Õ·MXRR‚_~ù¥Ñðä•›7o!-M ÀZëµ^¾ì‚.h_”žQ¥.s(`BH=Øì`õo~óÍ7X²DÓ­.ãsñb$¤R†VóÇßG2´–þ°³³C@@ÌÌÌpìØ1( ®KÒ{°!¤\¬{÷î!%%Çgí¹†æÊ•HL¬<{ÁÐZúEÙÅ¢û ™A‹Bê–– XY5þª¿¦êÚ"¤î•ú ‹2´š5ììÞÁãÇZOxyyÁÞÞžžžt?!(`BHØ>Ôî`8q^^^¬?×Ð4iq ­&CZÚ«ÿŒÑäÉ“qþüyØØØ 2Òø¶J™D‹BêÀöö XXX Y³fÈÊÊ@Ý+Mõèဩ0'§†ÖÒ?þþþ(--EÏž=é°»–(`BHtÑÁ^w±¶lÙ‚°°0£ À¤¡Cý!1°"ѽ;Sç¹ôÓ”)S€;wî   €ërô,B©[—<×äááØØXœ;w“'Ofýy†¨[·89™0²–µuBBz3²–¾0`1dÈ:ì® X„RCJJ lmmaaaÁú³ÜÜÜpâÄ ÚÔ‚••fΓZ®t..1øÇ?&0R—>›pWíï6o>GžFÓ¦æŒ×¥¯&Mš„¦M›Òaw ÑÿWBH ºê`íß¿ýúõƒL&Cqq1ëÏ3tææfxðà,ÌÌÆB X­â·N@ 0ÅÞ½‹0rd?VëÓ7S¦LÁ… ššŠ/^p]ŽÞ¡€E!5è"`ÉårlÚ´ ,¨÷NB¢¾m۾Þ=ë1s¦ööA>p@êÿ>Qào`m½ ~~?¡´´£F½ÃQÅü% ñî»ïÂÓÓ“ºX €E!Õ§úÌ+ XÌ8w‹‚­[Wâܹ/°p¡ ºtÙ‰fÍzÂÙyD"xz®Æ»ï¦áûïy b±ˆëÒykòäɈ‹‹£€¥fÞk%„¡‹ñ ?Fll,–/_àÕ›„ÉÉɬ>ÓÐeeeaóæÍ8uêTÕÏ|}}áëë[õŸSSSáääÄEyzËÚÚ½{÷ÆóçÏqâÄ Œ5Šë’ôu°!¤šÀÛÛ›Õg¬_¿‹/®úÏu]úLÔ†ü±ÁÏP¸ÒÌäÉ“‘™™I#ÔD‹Bªa»ƒuñâEØØØ k×®U?£-Bí|öÙg˜>}:¹.Å ¹»»£M›6(((@BB×åè X„R Û#êºoÐÅÅiiiËå¬=×P=z"‘#FŒàºƒ6yòd:‹¥ X„ò? ðöö†@ `eýü¡¡¡°¶¶®õ;Ú&T_JJ öìÙƒ+Vp]ŠÁóõõ…µµ5NŸ>ŠŠ ®ËÑ °!äØì^àÀ˜>}z¿§mBõ©rîŠ0gÊ”)ppp û UD‹Bþ‡ÍùWum VGK=K—.ÅÒ¥KaccÃu)FCyÓo¿ýÆq%ú!„ü[¬»wï"++ ƒ®÷34ªAu¿ýöìíí1`À®K1:S§N…L&ÃíÛ·¹.…÷(`B™L†§OŸ¢mÛ¶Œ¯]s,C]¨ƒ¥šÄÄDœøàDDD 77·êgIIIxòä ‡Uñ,B{Ûƒªt¯@,ÃÖÖiiiŒ×`(æÍ›‡5kÖÀ‚ëRŒÚ¤I“ •J1} íжææб#‚ºtµ©)þ¯];¬ø×¿ŸŸÏu©œ¢€E!`§ƒµqãFüë_ÿ‚H¤Ú]wÔŪ߮]»Ð®];r]ŠÑÛ¿e b¢¢Ð7< <Àò2<--Åý’$UTà“G`ÿÝwðlÕ ?}ý5×år†!„€ùVjj*._¾Œwß}WåïÐ9¬ºÅÄÄàÚµk˜={6×¥½^½práB”WVâ#ƒT³€æÈ­¨ÀíO?Å0__TVVrQ.§(`BŒ^ii)222àááÁØše¨ u°êFó®øaj¿~¼}¿Êd*ç¹ãââ0ºÚÕPÆ‚!Äè1ݽºzõ*„B¡ÚÛY°j›1c¶oßÎÚt}¢š-Ÿ|Ëë×±PƒNÔ4]ââðÅÌ™ÌÆc°!Fé žU=Ø^m¾iûöíèÞ½ûcÝKOKÃÚ °I‹»2?W(ðÛ/¿ áþ}+ã7 X„£÷àÁx{{3²Öž={0pà@8::ªýÝ-Z@("//‘ZôÙÍ›7qÿþ}|ðÁ\—bô>›9ûË˵^çW©_ÏË@Eú!Äè1ÕÁ*//ÇöíÛñÑGi¼m¾ú¿ãÂ… ±eË®K!Ž…‡ƒ‰¿~tpðï¿XI?PÀ"„µÂÂBÁÉÉIëµÖ­[‡¥K—jµmÒ¡v>yþü9Le2Ø3°–@;ÄÅÅ1°ÿQÀ"„5¦æ_%&&"11AAAZ­cìwnܸC† aíÒm¢žÈÈHø38bÁ¿¢‘Œ­Çg°!F©€¥ÉX†ºóá¥K—––¦Öì0®¬¬,tap½N••x™ÍàŠüE‹bÔ˜ÑpöìY8::¢sçÎZ×c¬[„øòË/±~ýz®K!ÕtîÜg‘qÁÄøÿ}@‹bÔ˜è`i:–¡.­[·Fnn.ÊÊÊYO_Ð%ÎüäïïH5‹6&R €¿¿?cëñ,BˆÑzùò%är9ìí5?»}ûv¼ûî»°´´d¬.cëb­Y³&L€§§'×¥D"Ú;8 –µR˜[XÀÎÎŽÕø!ÄhiÛ½ÊÍÍÅ‘#GŸÕdLç°Îœ9ƒÒÒRŒ;–ëRH=ÞŸ=ÇT¼°¼!GML0͈æšQÀ"„-mŒ21–¡.ư233±uëVüûßÿæºÒ€W¬ÀéV­pK‹5l³´Äêo¿eª,Þ£€E1ZÚ ŒŒDAA ÀpUƳEHó®ôÇï—.aœ©©Æß57ÇïgÏ2XÿQÀ"„-mÞ dj,C]Œ¡ƒõé§ŸbæÌ™hݺ5×¥¸xzâLx8:››#Eï½ÐÃÜ?8€Nl•ÇK°!F)##b±666j÷СCèÚµ+k‡² =`9r¦¦¦>|8×¥5t ÄOgΠo³fØ Âè†ïx›šbÝÁƒè5r$ûòŒ ×B´9àþÍ7ßàÖ-mN¤4L(ÂÙÙ)))puueí9\HJJ¾}ûpðàA®K!èÞ·/’ ±hÊt:qö%%¨¨@W""MLðÄÌ ƒFö¡CWÌ X„£¤éöà·ß~‹… BÀàðź(»X†°¦OŸŽp]ÑÒ·»wcYNâbcqþ<ŽÞ¹€Î~~X4hüüýakkËu™œ¢€E1Jñññ˜2eŠZßINNÆÍ›7±hÑ"–ªzMyнoß¾¬?KW–.]ŠeË–ÁÚÚšëRlmmÑÀôgáEC@g°!FI“-B6¶×dhç°öíÛVÞº$„(`BŒÎóçÏammfÍš©üË—/ÃÜÜÝ»wg±²× )`=xðgΜÁüùó¹.…¡-BBˆÑÑ´{µk×.–*ªÍfa………áÂ… \—AˆNQ‹btÔ=àþóÏ?cøðáZÝY¨®¦M›ÂÂÂÙÙÙ:{&æÍ›‡uëÖÁÌÌŒëRÑ) X„££NK"‘`×®]˜3gËUÕ¦ï]¬;wÂÛÛ\—BˆÎQÀ"„u–.¶×¤Ïç°¢££qóæMÌš5‹ëRá,BˆQyúô)œœœ`ªÂ½j÷ïßGRRFŒ¡ƒÊjsssCrr2'ÏÖÖôéÓñÃ?p]!œ¡€E1*úÒ½ôw‹Â!°!FFÕî'Ož„§§§Æ×é0A··mÛ†ž={ÂÏÏëRá,BˆQQµƒµ~ýz,^¼XÕÏÎΉ%%%œÖ¡ª7n !!Ó¦MãºB8Gs°!FE•€µuëVL::ªª~ÊmB®KiT*Å’%KpåÊ®K!„¨ƒE1‰‰‰hÓ¦ „ÂúÿÕ—••…Ó§Oãý÷ß×]a ЗmB:wEÈ›(`BŒ†*Ý+®¶×¤kãÆ:t¨ZÃ[ 1t°!F£±î·nÝ‚T*E¿~ýtXUÃøþ&áŸþ‰ŒŒ ¼ûî»\—B¯Ð,BˆÑˆGHHH½¿ÿæ›o°qãFVÔ8>w°òóó±fͺg:P‹b =z„víÚÕùûß~û puuÕqe suuÅ‹/ P(¸.¥–°°0üøã\—A/Q‹b:¥P(°qãFܺuKÇU©FÙÅòôô五*kÖ¬ÁĉáîîÎu)„ðu°!F¡¡€Å·ƒí5ñíÖéÓ§!•J1vìX®K!„·¨ƒE1 ð÷÷¯õó§OŸ"::Ë–-ã *ÕðéVzz:¶oߎãÇs] !¼F,BˆQ¨¯ƒÅ÷îÀ¯€Eó®Q ,BˆÁ+++Cjjj­3Lááá°²²ª³³Å'|Ù"\½z5fÏž ®K!„÷h‹bðê^íß¿ŸƒŠÔÇÖüsss 6ŒÓ:Ѱ!¯®€õÓO?aìØ±°±±á¨*Õ™ššÂÆÆéééhݺµÎŸÿìÙ3üöÛoøý÷ßuþlBô,BˆÁKHH@Ÿ>}ªþsaa!öïßððp«Rr›‹€†Ã‡ëü¹„è3:ƒE1x5;Xúp°½&®¶ —,Y‚+V E‹:6!úŒ:X„ƒQQQ¨¨h„‡Gâúõ(”••ÃÆÆññIJ¥€ØØX¤§§cÈ!W«777$&&êô™ûöíCëÖ­Ñ¿>—C@‹b¶lù6ü‚ôôb”—ûè ÀÀUÞðõ‰¶mÛÀÙY„ Öq[¬<<|••g´Z§¼ü$&L˜Ž„„ UÆ.777$''³²vee%fΜ‰Û·o³²>!Ɔ:X„½óý÷ñòåÛ ¬ä””ÄÄÄ0°ûØì`Ñ%΄0‹!Dï\º €™ šKK»!<ü#k±­a£ß}÷Ñ¥KÆ×&ÄXQÀ"„ègϘ X€ÿÿÿ9::"''åå匭yýúu$&&bêÔ©Œ­I¡€EÑ3Ïž=ƒ••{†V­C”mIDAT샬¬l†Öb“]¬ÒÒR,[¶ ›6mbd=BÈk°!zÅÃÃééç\ñ!ƒë±‹ÉsXaaaøñÇY‹ò& X„½Óºµ?¦¶õ"УGCk±©7 7lØ€#F ]»v TE©‰!Dïøù1°š4¹¡Cõ'`1ÑÁúóÏ?‘™™‰‰'2T!¤&šƒEÑ;!!øûï§(.Ö~­¦MK°zõJDGGbĈèܹ³ö‹²HÛ€•——‡µk×âüùó VE©‰:X„½3uêdØÚ^pC«uš4Y„9sBpíÚ5´k×›6mBHHvíÚ…œœfŠe˜¶‹Î]¢…BQÉu„¢®çÏÓá倊ŠT W¸W×%HJºúÆOSRRpòäIœ8q^^^9r$† ¢}Á ;v,6mÚµ¾÷ÕW_¡cÇŽ=z4K•B”¨ƒEÑK..­±yó&˜›‡jðíTX[ÏCDÄñZ¿quuÅìÙ³qæÌüóŸÿÄ•+Wˆ5kÖ 66Vû IëôéÓ(//§pEˆŽP‹¢×¾ÿþÌ›7åå‡tSá›Ñ´éz$&FÂÑQµYZ8qâN:…üü|Œ9£F‚­­­VµkjË–-hÑ¢&Ož¬ÒçÓÒÒ0kÖ,;vŒåÊ!J°!zïéÓçxçPäåFI‰ €Þÿû­ À°±¹ƒ¾}mðÇÿÑøY|ØB<~ü8bbb°jÕ*•>?bÄìÚµ ööL g%„4†!Ä`lÛöü±±(,|;» dd„‹K7ôꀰ°Ñ0 ?cÏ»yó&Nž<‰?ÿü£FÒÙ[ˆqqqظq#vîÜÙègW­Z…·ß~C‡e½.BÈk°!©¤¤>„ŸŸëÏÒõbqq1 €Ù³g£´´~~~ð÷÷‡H$zãs‡Æ£G°lÙ2Vê „Ô!„0ˆÍ-Ä?ÿüË–mDTÔiTVzèÊJ{ˆDC&‹„£c{|òÉ<Ìš5OŸ>ÅòåËqàÀFžMQ,Ba “[ˆ£GŒóçïB*Ý QŸŠ…X¼ mÚd¡eË?~–––Úü!¢€E!,«¹…8bÄŒ5 vvv~W&“ÃÞ¾-òóçøHÅ'ž‚PøÿÛ»Ÿ&ã8ŽãŸýszÈ¥Œ Ùê°$:Âþ DÒ)è0/£“],.¡h:H„„·ÝÑÊÊk#ó¨ Z¬V«)•J)Nÿ^B Î)‘˜Tµšm(Û座©©Ë14-€zP°ÀB~-!&“ÏT©<•ÔèþUeùý×µ¶öAv;_Gš…‚ÔÙy^[[‹’‚ g¹\‹yõôô4>€ºp;S.—µ³³+åJ’öö¢ZZÊÉP XL¡PÓ1–·¿Q&S0–àh,Ã(X`1ÑhTµš¹%=»½ sOÄ‚ãóùäv·Iúj$ÏáÈ©¿?f$ @}(X`A±Ø€¤’¾ËëõËçã“9@3Q°À‚¦§ÇÔÑ1ÙpŽËõHcc#ì4¿8° H$¬Dâ†l¶Ç ¤¼R(TÔèè]cs¨€…ù|—´¹ù\ÒµcŸëtvjccMÏóƒ8O°ÀÂÖ×?©»ûޤ™cœõB6[›VW?S®€¡`€…9vmn®(‘ø¦öö«’ÞIÚþÇÑïåvßV_߬¶·(ð6qRb‰N‰LfQ3Êç_ÊḠZ-¦ƒ¿\®·ÚÝÍ)ìS2y_Ã÷Z=*ðߣ`À)´¼¼¬\.§jµªp8¬X,Æ? ¡`Æí€a,Ã(X†Q° £`FÁ0Œ‚` À°ŸX Qx7ßßIEND®B`‚leidenalg-0.8.9/doc/source/figures/layers_separate.pdf000066400000000000000000000633751420514302700230570ustar00rootroot00000000000000%PDF-1.5 %ÐÔÅØ 6 0 obj << /Length 8634 /Filter /FlateDecode >> stream xÚ½]ËŽ%¹qÝ÷WÔrfQ©ä›\°eX‚ oÆž¬…ÐzØ@·`=Ãïˆ q˜™uKÓY×€4U7ÈàáÉ$™'ãî/xÙ_~ùiç§£ÿî/î%…mßóKðqs©¾|þúéO/äôËñü´o¡Õôò?/lîÿûþÛ·Ú¢ó/ûævײülõåÏø›\Ü[ŒüOûËWü³ú‚þD·ùûç—O¯Ç=xÅOò'ÔS=.]_¡•“Ã)Æ¡‘ÿäÏì3§ŸÏárÃÖ“°ß?}Y‡ý‡ù¿ãWW·©§³Gh˜©µmw%@nd©Ñ粌·ß·œëîÌÍ»-„²W –>äj°¡Ö8¯çöpè­_à8;Èa‚‹w‚aÌýáñÂü$lfüüOà„fÄЛ¹/£­ 7løOA^OM!Elìužã8ë@µb\µ4x‚yžPÿ¾¤}à>%›tس Ï1$æGÄô#樿Y85- ¡u fdUÆ©< ¿9Br“€§|L{ä¤Û=8G˜z—˜ó4Ûß?Šü½bú¦Ëk¨›k{ +¦j5ÈT3àÚ–k i4î[r; üÝæJ+B©iÁ­€ÍPÒV8{ßÀ ’¡Îy,-âC,Å-ÞÄry–:šÓÂÏ9š6ûuÈmF«i¡§9*°M-ÚêÂÎŽ…R ¬M5-ÔGÍ«Ç:çyä%À›¼ìNwyiQžÃËKµêè÷!1|Ô}rº›Ÿþ¦‘Ô²àhÖ>öÓÝÐQ÷Æî^šOsÎïÈÇÇ*ÝÃpòñm ïÜ/yèêé˜Ú–|sŽSkÝÊJé¸èÄ´‡8æofT¦…FGFn/Üx]N L³ÑþÑaÍ´ÃI1<%Z¦áò!hUMôYëZ- w‘lRQ8Ú݆SýV@_G‹ò‘€ökZuk*` ô‹] †T¿âÇO¹ÒÕ=—\ØÎ 0Á¸šU°h “6ŠpZßÔjh´‹T;œ–È#4Å+ÞFs„yš6cû¤¡òBO!ˆ›w:!€ÐÈ¦… æ¨ÄÓp`ší. íÍ• íª ÚUÓÂPµZî"ß#Cq Þdèøy“¡å9 ÅTÀ:A0(T:³Rc•ù)÷4˜`hͪX8EJ›ED­{jµ$4ÚE¶’>t’ô& #ÌsåMtr~ÍÄŒÞç%êö~ä§ìêcFÐeë „2 Œ©uì-–"4›D µc†÷ì¼MŠSŽzR°¿ËJvr·1ìQÞ†ðÎRÖfiŸ–¥¬œìœÐCš2ü-9Ô²pÒü”jm1õfNJkÍ%¥KÕUkU- %Õj9Ì`¹‰cpÍÈ€ûÃogdxyÎ.Sg+f‚Æ>ü:ñ£9Jc‘Z•j -:¦jœCo¡ŸÙ"¨ý2´gßuFœ2\ùøÂÁÇ›ö(Ï9Æ«ôo9'&q¢ñàLÐ\7hm÷B6×Jâ|\ÙR´Y*m 42Úh|JÝRÌuu-[-¥$ ‰¶Ù:|1×ò D$dRâ}=4®¶ÏÒ÷ÙO5¯iJÄ«Ì;´˜ŒÉ ]ñsÓ«|3¾#„ùH„û¾’ë£/÷k@Ðúº>Ö¾²!ákºò¶%íC¢ Æx5 QAƒÆ_è§š—$%àEÚ]LéºÝï>º#ΓеYÜ_¦é·…¾®¤m÷ØÛ _ÀizÛj80ÍvWâî40qo™K¶²·Ö¹j[™«f ©†¼HúÈ\7‰+Nñ.o-ÊGÞYuþb&fœ8-›à«Ì•†L0²ÀWÅ«XµV ¬šžñœñ‘°A|½ êóPeÝï|XSëÄA¶+5ûz|áå&–Ïn4³y¾ôŽÒ¶Ïõ&#˜©{rîi²÷x4{úéláSy”HVn­uË©%¾MJ3Ъ¹xê<\¢ñ«…0Êœ[$öñÕuç®Ú,ü(Ù˜yŒ½dýÈF{š¾‘P}ù2ga_9]Û5Æ—þÀóê_¥3:=¶öÄ&òßËO;Z°›b࢟%ÃùùŸ~ö  š1™æñ¿NÓçÇß¾üê»ýÍ÷¾~÷¿üŸßýù{Š¿ÛùGøî?ö´ÿóÿú»?ÿåË}þýå¾ÿõÿòéŸ~´ú¯_¾áÈ‹“zµ¬P øùeu[*Aôd]€©šuIÄ&;_}š^ßéÂRÕÂä¥lZà‡væ–6šx|9©aˆôÌðª.3Êë¹µWlnvÊü´ßlImœ;j´·DÝã†(ðu‰ð¡‡ÿ´ö |‚Ê8Í0Sæ%L㤠¯~ˆÙ~‹.Î{Û+x%¾ÌñnRÃÄJ :¼3Èë¹­*í“9j¿5Ø’ÚÀJý‰•xÜ üðV-Nµz9­ Èå·xùcä–•\ê6©c¡Œo é«>´sê.ž=Ê“¤´²ßj¥ÕÕ §Z ÞåÓàä#‚&+b€3ðâvùà–¶†Dï/H“¼1x´±Gí”9ZBîœãÀÑ‚>ÄQÜÊm G˜g!©³õqf¼&Î{bFOës¹.é„VRü&å,ššP¯VQ0åhÜä]AËLmUM 7ÍÑRÓhçlÜ|(¬º§Tn>GêióvAT­†ÒÀÒ©½ ªÄGážÅê/`“޽F1„´¹Jí—9ZNîœæ‘ž¡¼º‹å¤çÌ1£øRÆ™èdfÖ¾–˼k³rº.‹ùû .æ§¾.ëƒÙÀøh¿\ìè¼G³~Q¶ù¼úöq]=ûòÂK.ÏMŽƒ¦5wœŠkâ;>ßOg]¿1hKÃzûs,ôóëͶ¾ÌÝë‡(ºø¨*–£æR­ª¹ä§m´ï­ç§’e÷u‘]zWø¥tÌ[)IŽ,žÙ@ fKjDÐTjÛ‹úÒz ®3ˆxʺ“Sz$À¿\o+0gœçH0]ãI¿æbFÕÀò!>ýû¢§å“Ë’êAQËGf²õ2GYü»²Ä3ŠjÍ ªZ²Zm¡…^‚ëÈSž!Kè±²–ýÒHk{œg)¥çü]u˜jU¦ñA5y0ÇQ½,We#„4êÀ J :Km}QdZGÁuæO‰ŸˆûPϧĽ©è›qž$Ëœ³x‘eªQu±F ÙêD_…¶J4pUBBH³¡ÖÖÌ ¶Õ ¶ÕÖ]è(¸Žt à1ëwßÜîÞVÜö8O–W”Â]0+¥mÑÉã­/sš?à[øÁBKeq•½BZ"ª ÑU«aañ 1kz×zi®–…¼H|9Úiþ=€Å/ÜxÄyŽ W§ñ¢àãÐ'@«3}Uä*ÓÀU !Ñf¢\3›*W#‚,WGE'ô\G6ï˜ó‰ºï(suoKs{œ'Ø ^°]Ì #…AfÓ|Aר®“‘L†­Z gxYË ´ÖIsµd4âEÚ'â>†w÷CNeÓ”»ž<§½…Œ‹} 1=/w«+‹"×§²Ñ"&Õ»lw¡?ç¼ÅìZ\Âd–»21ªê6± ¨ñÄþ‚ó’ñˆz1 c‘…é=RzvÇp_ê9=Iëéù°WwÌ ÝC[hû¢Ðe£s!Õ¼žÏvh4δ­§;s^Âñ^íˆjB¼¡¿àŒùŽ ç!hcrÑÇmÏ@ÏBÛf6*äÐ<õ}ÀUÂìG½ °\•­Òl ÜCb«Æ™­b@d ‘Ùàl,†°ç81û¡xP‰}S=8ãhszÁÙ¬Š‰‘ݳi¿ÀläW%)„4 |6<€Ð†Ðn ÎÊ^ˆzÊþDèÇ O>ßyÄyÈrâe0+&r¸YLdØÉÁAûÛ,¿& Ž|°±Jÿц ›à°˜€Ûl}…Øú‰®š='!õä.Ä#γy "X0Nå.PC¾0ÙQ ”Wå&„4› sÁª^ˆ¨2_hÁÐOpé@ÄcÚ'þ>+}oª‚gœ Yp÷!ˆú/ÿöËO?ûï?üþïÿñ(È_^úŸÓÿAG.R7†nÈ÷ºe_¥Ð]`ɰ´iŽå!Ò½/°:Õñp‰|ÅÂüDĥк,(ä.s$Ëh£TD}ë}N¬L‘ ‹SÜâîÜ8àJ­åÂÜK¿w1‚O©krýNÛdš•…5¯yçM•÷‘&ìÞ××´¶Ø;™SŽãi ;Š| òX½9?=Qâ™U»&¾0ÑÕgßk9‡ù ­ ª(mÚžsðÂFs–ß䤫œ‹'y³&%ãúö‘.g£† ‡ùQXfjàKO­]#[éâ×x~qèÄ…Æö¸…Ì[ú—( º2Sóªæ§š‰.\/3`14Çóye³c-&o$¹ƒœcèY`ÚØàÎÓ Ï“?}îõˤ/yûH-Uy|3UÅž¦ ‹ÈèŠya•½hgÂbš€E²«²¸ùFÚÓLÙh®,âb¹ˆÄœÚA^,e¬úb3Kæ¹gS`ìs`”(ÿ§Ä˜;ëÝ=Pc, UY\."ã=ñŒªŒ Jú|ÝQfÌ=mÔ°êŒyN{—YTa ]!:æÆv“7&½(ÄUlÌwɺçpPËM|·êi<¹‡Ç”'JʧLÉ1_­J©¬e?hŽaút”¹*Sa™uî7”‡ÆUfÜgr.ñM»éòãË\É]&˜+×OM¹|›ú˜'Pç2|äÓµüxzM§·ôÇÎôǬ8þÙ/¼ëQŠˆ˜9MV:ÊÇÿÚ=–v˜bêðwß¿ôß¹+ýò±C«€ùu ̫̓ÌV?”ÏóP˜•¹íRÀR§|¾êc…^õO,š æ×‹`¯Í.ÕeÇ1¬wX¥TN]‰³áùçRcV­±®[e4׸(¤9â·—Ò„Ï)¥¹æ°Ømè­"%`dÕc<± §:cN ‹F„íŠ)†x-}h—›3¤¦a¯ÆáXÌï˜_­Bæ-°µZçS·‰Ü¤ýJZ9¯ëój£ò:°Ouýs%­š_/‚½ž[]9Ëçë´j\+ ïò*›íêŸ gÕzë²Q¥,¤ÉØ¡kþvÆZ€g1RXÌ6ì6ÿ›Ï –À,sZX4œhVšÏ]ve!uâ%Y 5mJ«+°Ôb¢qvà@ihÉ £f~Q%-EtÁx 48C^öjΜÆñy@jv£­òMR[”g‘zí ͤŠS±6ú©'ÐÔâ¡¡F»bbA òºYØÂ|è³Q—w=傯 ‚¼beõüUyqH^ðOQæ‹4E¢MGˆ§PY˪uQ­˜ÉˆwÎøPJ𨳒à]PGœ'jó¶?9n%kàGÏ>#WCÚœ§!C¨m媹gD4ͦW²ò"WùJ½óS$hZm+WÕ ¹ôx)ŸÈŠƒñ6]Åë6[5ʓȊ¹ yà`TP´l~#®À.ó4Îxh‚ñEsÇâ)XÖ2Âj]T+&ÒÃ]e|¤ëCX•°÷`|}¬\6$P5ëaËÉ­ j)NÄ”_†­-´îïÌ;áÐc‹æÄS¨´a„Ô:hZÑs²kÐÇxŽ: 7áìQÞFóÖÃk›²ýÝ„$uò0¹`)?„9”È–•£êgÄÓhh› ¯urh–RèÖñn®¦…¥jÅLfÀ«¤<ÅÑx›§CXp—¨æC±ÕÉ»@kVÅB™0³¢¹,kZ} m0¸hž8@DÅK[F\­ƒ†«¥¡°žó=õ!¨“¬71l=BªÊãy¹iýð×̲þ¬òêfŸ Y—wÅK—ûÂDWø…ø¢õ„øªÖˆí}Ár9/¸B{ݼ÷·B…Œµ½eœëÁYÙnÍ©WG3kG®Š¯E: ¯KcÃøeýü:jÚ˜¼F»•þlÖ§D…ÞϔǴ£ö¾¤}7ÕŠ’ÖPÕÔ Í™‹Q•µX©g[küµVºÔlK5VpÕ*«m³õ¥ kp¢ÆˆåCV.í–ÒÒú´-YÍŒ ÍW¹+².£òfIÖîåîÖd…0O©¥¼$Ö ‡S4جHâ‚°hW­ãh!ÑcŒæ †œ°aë€0vtš!Ÿñ"ñcåÇÇøÎÚwñqž„¯ÍcÏOF£‡jè¾ÑÕɇÕÐÙæbݱºÙƒ«ÓB¢m¶¾pØóÓHÞSbÄÆµ(kYŸ¶…ÂfÆ|FÄ«Ì ^ÆäM‹×·NC˜§Ôj]’ëÈa Ùd_ð5º«ÒÒB¢ ÆÍ Œ8AÃÆ_ìç4C:#àEÚGþ>Fwò÷.º#ΓеjÃK6hž`XcÍj/øZYdpÕ“-"˜`ŒÁ:°Àp1lÀÅNN3&3"^¥}¬²ü^=Gº ï3âEâ'úâ¼M_ñÊ·éka¾Me=ª1‹J'„}¨i:·Ü¿¤'ó;œ™Ë›¦\d‡h&dV2Ólß]h­¯î} {;Ve&²Ð¾b³.s©^¾Xäò(ë”»*9ša±ŸÒâ+Ž÷}Bn-aifyzM7âQ½¢¿¶*"‰@» –ÊFÚ‚8©ëÈ‚ñÚ\•¯æô½.§ìPhwµVhîOßcëUd­$³ï…ÌÚ˅ɱXYÔ¬æw¹´´jîA“ï5XˆKÓ¨÷+s9b¹Ú“C’Wüq®Ÿ¬…”GØäs;Њ5ËÄ=Ä ×~–™DXž]ÐZå÷­h¯›û—”“gdÞ*1ìó´ Hõ§¥j³<«Ü+kmGÝæºg©eXYZ_¸“ǨÇ4â–Ԉ彣/c›sèt¾%À–ãøÝ5WîèV:ïÍõç@És‘êæõàéW~§¹Beg^µ»˜B•és,_æ'<•ߥi3*W‰Zxfð³@š‹s·äéÊP}³êμæu ;uÕ³ì[6ßewãk]ø‰m`Yµ‘˜V•FÝy¡KáYÁ%Ÿ¬Â³ÜÑJm£ÆsJ®Œ£‚Ýsáó^ä¹I`–fmä»™šÔå÷•Ÿs°àÙª÷s _ú›à½Öz¿Ïó[¢Eîc|Štñ|f$ìçÚÊ;+[Ág¾¾ÇÄì;ÍA8Ë‹¢ôÁ@)øQèù±9Pç¢|7Ø—9Etm¶ VúøëúÏž˜Ï?Epï¾MƒM$¬q“XL)ÁNÓç-¶ÿv:(°ý•ûПCé>,0*Ï® ÝÅSG6˜§ÄvJªu5x^”»SþupîB±²†#¨f»*¨1¬*­± Ü]:¬Î™F½„cÜwt»PÁö–n÷Õ*ê>G¹‹b+í èª D«½"Žâ2s6q™E5â fc*‚Ø„{«Î˜—†½„c)Î÷zŸû€@ÏÜæ6jµÁ:ušHUt"Pý‰Dg£,„£é/³Š­!ª‰²¡ ¨ÿÄþš3$¦QÏCpf÷#¨‘ûžÔÈýY7ÎkÍ °Å„Ù¿  <g%,D5` VBzÐþ5 <ÕÓÒ°CpföC°•ØwÁžÄ~ŽÞ— ÕºÊÔË‹Yaa­_Wü´TílV ùzt.²øôkX0ÜhV` ªA]Xð†þš3f¦a/FáX‰÷¼µÄõ]¼gÉí'á 3…­‹}r 3ɇÍ/Ñ\•°Òl ¹EólCjï°y”übW͓ҰW#p&÷CÕ¯±ûžêרýy7Îëm´+4@…¦?¢ 44Wã+Ä#âvE¢†Ðƒpè­9c^öjÎì~ ¸Òû.à“ÞÏz[­U”/Föœ°Èì¨fĬ «×2³è¬Åc1ìb ÝÅ*o·³>ƒJ£èÖLãZj-/‹z€S­ÙGá.T)÷EÂ3ГTÂVÌÑ’Yl¬©ÀaÍHDëK‚³Õ¡„°‹qê¿Ñ:ñX‚Nà–ÊKwÍYÓ² ‡ìO…+ëÀGÝÊûBðèYò~›Ê‹¶Ì\ņ =¤ÜMm •¦íÀes5~BL0‚Üó`o¡æ¥Ü{¯„Ã(–LãÌàŒÙΨç8Óù¡æÔ}Ouª|~ŠŠØ&4&Ö 2d¢‡Ó€F晫Qb‚⫽C²DØ-= —Þš3ä:ƒžÒ?3ú©øäô]­ø ôs`†:­ ÐhWX Ð«â5aj(k®ZdBš ^Ì ©Ðaóˆ3vU×dGØ«8Õ¥}ëY˜ö.Ö#Îs¤ä6§Qf V©0F÷Rt~½AªñÀip6žZT°¡ írnu-,-Õ¬ö´va¥¥ÍYÓ² §üÏœ~GV>9}[W>Hýa9Îék´O\°z³ˆ•žm¬ mÎJV j&ÄÌŠ †Tô°}„;«Î˜•†½‚3­í´¾ ÷äõÛpßZ–É ŠÉõ¯‹õÖòÜ_Þ\,,·ü¨»å€5aÕ6ŠÊ†]jN‚«¼…™ÂŒ C]쬓’A€¨,B =çRoÚŒŸ{UÝÙ[sƼ4ìÕ œÊÒ>Ãj]Ú»jØèIrØñÆ@rGÀÑ®àôW¥Â¸Õ€\ï/sµÕU^ú’Œ8ÚˆjBÀ¡·æŒyiØ«A8•¸|ðYäò6à#г·É½è;‹Ô¹h$pÆ·¸åVŠ›qå8:+o1,A͸ØY+Ç÷r$ù¾o™•. ÉÕx ¹9cjöjN$,©T’ßÕTÎ@OUÂü^1G»‚c´+æFHtVêbX0"æhWp€ç#PqÁxnΘš†½‡ÏßÁ|òü6æ#г0/Q…Ò‹]Áé/Ö­(κÍ+àü²ŠßÃêÉïŽ[H0"ÞhW`4* 8Û_ÁÖž‚'¦¤!¯ò?T¤~éY’ú6Ò#Ðÿ»Q!¼ØY¬Øö•Ý%n•î Ë·F˜ñÀnp6ÂBX0‚~y±÷Cφìö´¶.µ.EîÕ¶rÛ\1/y5gj?TPµoJ¨•ÚG õx‹²ÍÙÜø"1W]×(E\{R!ëÚˆ_ú:™=Ë+”ý6R÷%ÎW³;l÷˧So !›9‰¤q¼€YÛÁ™–÷ìOî3Y®í.’í—.¯oiþ´BÞ¼1KòM‹È|ççoò0 ¤œùe£@ðå&2ëàù×’° 7/3²KnôŽQdɋΜKzÓÄØuæ´cäòÜEdΡ«OCt1`Mo{.¦æÎïɇ“Ô|§Æs”ú_,‰–)ê}Øh¾Kk½jssXÚ»—m®ÙÏGÄ{ˆþ(7ÇZÞ¦.¿4Z‰o>T£Þôïà‡zyñ¨9ç*ß¾Êk/Ò{/ßè¾Ó¨ä^…å²\þ }sàê÷¡†ã'›{ þ :w•_·‘ç‘9n!±²˜Ë}ïô”mKÅï^™ë·ûÓAwΕM‹Ô9Ó¬äï?ç Œ¿ååVÉCÝoîK“ã£*󔨙KsjÚE®M)qE÷ÚK×Påh‚’¥ÿ§þý)¾JájævÝC‡ÚßòX‰&ažÅ¿c­ý‚š¶yãBÃÍòp)ùçøþ(ß=Ë´.|©Q{Ûw—å¿™³q/9Íï´"—94h ¹þw¨R˜œntÔ ÏUè¿ÂÇ ¢8ýÎV-ÎW÷” ÂξÈŠ<'ùÖ>šìQ89®þ`KÒ]®>Vµì]Ú EÀ%nõ=.W§)$êøÌ r¦Ão‡´®:wÝR«¬X¿á.—1&w,γÁ¾tÉe/s­ð6jb4/_"Ì…À[’W-è×ÎîC¿ò $ŇëRà5´þdçƒ=Е‚6Ø4N³òwkœÇ[ö£"ýò#oÕR<þŽ$'VÌõMúôzO”ž Jo•Ç]”ç±¹Ò¥Óÿþ(ÿx¿õóÿ#)  endstream endobj 13 0 obj << /Length1 1662 /Length2 8008 /Length3 0 /Length 9082 /Filter /FlateDecode >> stream xÚ·Pl6ŒHIwÇÒ K7HJw÷ ,± ìÒ% ‚ )„RÒÒ "(%ÝÝ ~ø”ÏóþÿÌ÷Íΰ{sºïëÜ30ÓkëqËÚÁlÀJ0(‚›(×ÐÓã€@ “™Y‚pÿmÇd6{À!0¨ø¿ò`âÞ¦BÜ5`P€ª§ €OÀ',Î'"ø@±¿‰0q€È bÐà¨Â `8&³<ÌÍ×âàˆ¸¯ó÷O›-;€OLL„ëp€¬+Øb ‚4@G°ë}E[ @f #|ÿ“‚MÒpçåõööæ¹Ây`Òì\o  †ƒ=¼Àv€_#4A®à¿FãÁdè;Bà:ô`öopopØ‚¡ðûO¨Øp_ §¢ÐrCÿ$«ÿIàüu8>¾Òýý+úG0ÈÖæê‚úB {ˆ  ¥¤ÎƒðAp@P»_D vòA\@6÷„?Z”du û ÿšnëqCÀyà—_3òþJsÌŠP;y˜«+Š€cþêOâ¶½?w_Þ¿.× ó†úÿì!P;û_cØyºñ@!îž`…¿8÷&Ìß60 E°;ìcëÈû«€¾¯ø'ß/óý þn07€ýýà@ˆ=øþ Óòžà@ÿ;þ‹0ùøv[ÀìbþÎ~oÛÿ‰ïïßâ0ÞËüõùç—ŽÂì`Pßßô?®˜WßPAW[Ÿó¯‘ÿqÊÉÁ|þÜÂ|n~! @LL "$üomä¯6þªµ‡Äþìöþ˜þîØë/ °ýµì€ÿæÒ„Ý  `û­ss Ðöþßÿ³Úÿùÿù¯,ÿWÿoGJž..øÙþ$üü Wˆ‹ï_Œ{áz"î—@v¿ Ðÿ¥ÿÜ\ °ÄÓõ½*Ðý2ÈB\þ9H\ â¶Ó† lÿÔËŸvƒ_›æ‚µapȯ·ÀÍþï~½lïßø½(ÿpï·ç¿%¡¶0»_kÆ/$ yx€|1÷ZâøóÝï£Øçxy 0Ä}à~¼@€=Ìó׊xU~™þDÂ^õ˜€ô‰xmÿA|÷räÿ…!wÏû üMðBþE¼ÿòÞK”ú¼Ï}ÿNþÆ÷^·û· ê¶Gü¶òýeýSU¿s x=þï ÃÿïgúM¾× /ÂÑü»ÖýÉò"¼a¿øï)¾¿‹Þ÷íöøÓÿŸ£·õô¸ïñÇzÜßËßøç öÛbN}ƒÙJ„;Õ„·^TËRys¯~F›_l‹I4éB°|ÏówTGÏ|2æ.gmWA>˜¦=Yùå[ÇÞŰy竹Tå\’bï²ÜwþÀåq§˜ÖFé0"’³L°Ÿ¤Cƒgm†bÆšlôí&B¤K`½r­è¶ ¾n*¶ pŸáÓ§R!âesÚ¶‘cM號LÌñ=ÌÒ=õU Fn‘c! çr­q—¾Ëf Ÿ~üèÕ×›&pT Ö]%\IDAì§JŸ3øâ#IÒ+ÕF8‹œÐ™|Y²Àþx7RÞà'´±ì@îì4¯‡1ÑßÛ?¤Ü6lHÙ£SoŠÃ ‡)±{KÙðÜá;[PJû¦šjR †$»'iYÛôŠJmžÅŸ÷ñÏ¡*™"ígד"Q8V…*qI¯ñü¿¢a (^$-äÏ¥,±øáû‹8­´7|Z]Ç D“/J•ÿìÚQHËTšvZ6õ_ÞÞh]ƒeCÌè£bL˜¼`³!1ëÐÎ8Vƒ,2ðØhÇ8<·G§î;‹,N§©y‰MM¦@½Ñ.º·U–ï#6¬˜‚xè¿é€î&NÃ×åC‹í¬:ý€˜ú®.ÊB˜U)†í.¸ÍÍ1í€Æ\^ýc¿“ÖÔÏöµÏ޾衜٭îù?¸ß+Bpת%ß¿KÜüæ4¢!›Îyé6d8ɱ_ÛiýA/B:@ÁvÇ„tkÛ ç3ò³enÎ6數é ÏZ’^;3úÀ…¨ÆáeròN¢§X«Rq=RKØ›Æh'ÕÒº çÝ7¯íBÄõœ]êác9Á‚Š;®QACã†Ry}šQbÙ4œ5¥qÊÀëóó–9m-ÜîwÏž0#ÈRgQô“ÃCî˜3%ÒÜøudÔÂÝE΄‰ëœrí)¦e^¡sT û=ï7œ¸fî…KcH$WF¦¯R©;©lŸYØWt Z[–¦Šë”ŒSe°ìâKŸhê…S%!?«3Ïybb˜ÎuR˜' c¢yêœÅT>þr[èÿðÕë(Qc3„Õ*Íãø€u9ûì€òåJkî™M=…Qކ¡Þü¡×1ÔòŠ<ß×à@~G’;f®|WYK¦³r¿µŠ¡‹æ¦p7»ž²´‘tsÛR´çKA_Øê~üð’öØÁþf[MH]£sÇUkÚ}ýõf°¸k%«2-£±ùÅ pÙüºó… •Å×öûÒϲËj#ņӱ)iG‰–H­c2|âÀø¦ØwV}¹§xû~‘ÆJÝ“CVͪEÁ¡â›å„Q&ôĨsû7ã ?Ë#íÏO¹ôJ“˜ë¶t܉õŸ¼„™RtþPÓkL~SïVŒMÆ{&*ª¥õR\¦¸žcÛÜ 7ð1$–×+jИ¨5ëÐל┊)™lWüBl£ÏCG±”h²„C_"=½)«¨{óvõ£uÄÜÛy$gÕ-[2ü± ý—z$Ë/I‡‡IßÔʦX•gñл§¼qç×¾yÔáðzðªŠÓÜ\5–ã½ë\ìþÝIÞDæ¹eý„²ç™±l êx;…³­uRÉtHJ®Džš;mrú‰˜ÃÞO¡J i™ž¯©¡ÃK‡Ów"ü>82ËP~I!¶ÆM«ÂGÞ<ª y'ðG©iÁ¬—³” ûÉ’V"³ÀcYH&ù¶ÍáLmzÆë(ňÅL‡˜´vyzŽ]{ÕÅÛ:¹AUçÌï\·EAfŒ‹È²Ä ÐÝ+â‹ÓìçsǸ·¾th&ô~žo‰ó2‚Æ£·×¾‰²K~X•¦6)9¨ÅœÖ ©’ð“F¹ o…¢îÜ@¤éò–pÅ­³BÖƒÜhçj¥Oˆ‹ÝÛ»å} ºÔ‰dZûåÔöjLíYœ\G~>& t)ZÒO¢é¨¦¯WÙ7OP<ÛvÇ\] ûˆN5œ¥—cGN–‹˜¯$†ùÐwÅr–sU1£ammºö¥2hšàƒ3…³‚I#-gyކJ“cƒ¶ðºÎd±¢H’§…9;ÆÞnóR§Òž”ÝŸÏå‰AË›©Þä#Sš~fϧ!ê!Wˆ•¬à™¾Ü ô¼ÑÅÓ¼焽¾‰ÐJK"Ðô­út$˜End&ÜEK„©@Ù9ØzrNô3%âEÒk9ÃÏàg®ÖÒ¯OE© õ†ž‹ú‹P¿|h¸Ã=”÷ÈòüÂ+$ßc„&q'ŸI4aÜÌ7Q®§ýØp»/¸@ÅÌ•Cwoa#,cÞΜöÁÒn—Œq<êþz|t"œÊTÁä NÝWÙêÍA¦ÞšOE{“±ßp:æERÝËÜ‘oÙ“­47>ö/h±:)&¶Ûãi¾ÚBË(6/XJª|Ý?^Ò­ß™Té6em7{JáYãTîQe”öÕ’S–ƒmŸ—}Á ÚküÅfR]úxUÇ·ÿ’³ÊBÕT±´{Htİ f²IÙÀ‡„æÜi\„µ{Å*_›\!|âçS{~LèæûEé‡ÝHnD¼Ã€ã &Ëì×5õ·G…ጇ×=8¸„Õð{Ýe¾j‰'d6æáË甾b²ø&Ÿy' µhÛ²’o¾ÆƒÆ ϵøWXº¤94â¢({a24E»Ø“®VÉN‘ + AvŽ6)>¼kÙÁ´*€¢¾:ÈJ¨Ý©a~û ¨1 Ló5EÀ$½Ê‹æ™ÄuOsÖ9c'Ùó£Vãú¨#åв\•¯\ùߤÙvlÎùÉX‘{2ê¬Ê×w)ë%DT•0 $ÂOÏáBÓ¯Éngm¼ÜmE'Wi³5u^+'l8–…´¾¨ ¿r‹ÈâÚ,Ÿ°äwÑóý ÎãèIíÜ,9Âê9|Õ?¾f¢ûyH¡Hv&þíý²1î’à÷öQ&›îNʘÖU½r"İ9¼vª· ,ß°ÀŒ¨"RŸÞk ’TWhŽ$ :;…Ý¡´Ï´,{,B‰+ÃÏhÅXu\mýƒdÆ/Gu^¨Lg[¿rj #-Òέõ#8. þQLÜT$¿qñôfcO2F7Ã4›+©Ç™ºÞrÖ닃ӂè…¼¬Õåæ—£8öwí󞈧3\ 7ò ‚ìÚàÄCx_`ÖEüý®–2[­7YçØT ! Ž™âß²Ç:-9E4O?©±cC.Cé£á$&'äØ}eŸTƒKqë£å?< ®×?ÁB(d‡éËÜN)Ò[KZ86Ï£u¬¢£ÔéfâùŽï>÷A=dLhýhŸ³k²öØ*÷ƑżûœiÞÁ(£Ò*iÅ=OPbÄpw:‹|¼ú‹póÏŒ5¤÷½ï…È¢p?§c:eˆ-s¿]={X‘Êtþµß[@‡àÍ7œ²‹âì…C½ƒZÊ¡’ÜîL[ò¢µ±ü%N05U™àçë)Äú–/þàUàœ¹^obà'S(ˆs¢HÓ☾ºügŸy»¬iˆck‘4 …¢4H«)uo;™@ùHô®¥T4¢QèAGdL—}¨AñûÄ;œØUR1¯O,ã›—ýûLOÚ‚¯ë§–”¶k³ÒôÌãÕr[®Í .¹äñ[‹òß+[˜ÖQq¿]|á]ʱ¶d Â6¥6g QºcZäí!™H“¡Œ“Ê„¥uÕš‹¼BÞ1?Ôµ¼uõ{{b]ávUÕO*ºhgg€>¨_7l–.KkKú®@˜€º— öïâ ¢YÝX4Â1”¦=ÏHêˆ »ÀX\Œ?l°Dœ©K~ûÄ€êîvP³¤J¸‚ºE1}òÀJ{×ÍÌÁ3ýU ^1Š2ûð×®od$¶RõÈ¥ò+!â@hê©r ¾¼!^ ý Ê”qž†+|ÉûRÑGH&øíeƒ.è3…¤ß°XÝLYô.›óÁ4h« êéÿÂÝ<ÜüÕ{“¦!wŸí[—×ì!"óqéå_‡áÁ‡Â™/*“\ÉÀ×C¶<6ÅW9~»Þn„¡-¨ ­ë-¬9¤#ù}ÉT‹$±5ìíÀ Lõ¨½¼‡Ö€÷‚g9½ã¹)‡n¸®½qA><ŠDÝyçÃ×ÙÞ:²+ª6»QÍèì)#©:Ø¡#¯^Í]¤µˆÉ$Ràµùˈ`1 âg]1,¿{M ¿U²ò¤å­øžS tò®5Y¾#B}28R’^[Ë}Z2—-Ñ[ÎãFÿ.o•?3iÿ$ZšdBŠóØ: ¢å7ŠÜ‡0É¡üž¬<Âc‘g@HI·XÔÔ­Ò♪òNbèt<'Ý&Òb0©ßÎìüò{}hh1ñ‰©‹•?¹Qõa$ßh[f±‰ÚÔd5}@QZNaÂBf`[,+”NÝ¡6Í*gÑ%’m@”Â0~Wš.V=?ÞUfÏ ”þVçæVz )òUèŽ&”‚7´^BžÈ˜29d$]—([YÂÛœhåk{ý©‡ZÆùƒ£ÝW õæCiD'K€¼—yèŒC@¯àè±ïnp Ôœú™WNäNHª)ò: vN*9Õ½ËêÉõ˰Æ&lŒK¹Ù–$tšÚµˆ.Ó>ž:¯â}ÀÆN¡¶½–ÑïÆØEÜ~ ‡Æz«¸r»!×Á…ú$)K’ãÚ=¢Xu( «Ô(N´56¤t„èBì0¸«¾x{µÓ_ʬD` Q.9Hì·?9ºæš1›ãéšh‘ÞN+å­Âõ2N©‘—Ã0„ÿ;øŽNÂÉi~bU~…ÙGòLE|’ØëC#5¥>ÐÑë\ñ¸K÷Âþ)8[ÕS«ÍgǤgûeéÈÑùÈ¥\™£’ëÝÏ“®h  Nì#)± Ü¶ÊSžÃü»')I¸ƒg‚ÌÈ´”0ŽADùš7­UK3…v¦éÚO,_ƒ89Ç ²‡ÓttQ° šBÉ»‘¾¶³$9R=Ÿ4Jgš+J{‘ Ý2KïÈùé˜ùé–²(ÅüÂÄ^'…ùÒº_’¯'Ê`Ïl /® ½/‚6•=°T³£BQ®zH´¾‹ó/瘽ò s²LÚ÷Õ†’Š•XÞISÑ}ÈQ¬G‘#³ÝµŽ-æÎE_ÿw¦jºœ^A Ó@i/%wã<ÿfmmòšÇÞ²"Ì½ŠŽw;+ž‡ºIø9Lø éeÓwÀÌ{l«É"‚!á½BpǘBy²Ï³Ut6©ÓGG­ù£Tà@FÚ„˜ñô²l óÏ“ZMæÒ‚†ú ‘جÇÖ¸uØ'®gæ'Ëø@¥3/›¥ý®=*Àd…zëÅq(;Ûu¼ÿ¦Š)ìû8Ó¼›q ™¹" —æùK"ÏáæF–C ÛAcµë„o´ž«=ÃÅ¢8GIÕož½LÒ´ì_*2Sd,) œÖ@$ËŵJšõ*ãØó×f rr®*’'M¦(‹uWŸk» ”‚&O ©úäퟱZq¡`‰È …¡ÚúÈn°è?¡)ü@«Å³­Ñ‰)ÅÉnì¥Þãkp· <‹(™òŒ-éÞoLÅ^½ª¯…Å÷W®iuDOê-ªíwux‹gÕ´Û5•bÝÀM½$ô<ØN¢&¥XÚ˜˜2ºtì^¹_½jcÄ¥¬™ÌÛ[5W—&±'«²èL2“ë[Å~ ÕeP^ 3Á6ûÒýM¯LøvÚ2¾àÐzK>p‡›±Ö…Ï!~¨-ÇY zJü‘(Ë õEaÁ®ºèþmökE¡¼h]m¹\Ôµ¯'÷ÿa[dšÒ$O9¸øøuËÆÕLÙì,RÖ—m)ždÃäFüÁâvM5ÐNò·÷FO9FæYµ“übgjz«¬4zo§Þ%}Cû¾U~ˆ¾EÖ÷ÚÂÞKZž7€~ó }V—/æœB¶¼{‚ô÷Ñ}|ò%¶¬ð´ƒôw·݈èyÁ² r–³Ù!Ôϧ)–%ÄÏÉ&XŸ²Ó~Ñ#’ÑÚ4ŸÑm€Ç‘ú’µñ­J‹•®U#P´s’i'ù)¯pªáí{)6%I²áÓ?µ+}÷¥¸ç%a&;—Zè—›ÖË;énìÄŒwOÄ n5˜%//äÒ£¸Û—–û®°>Gš†wè[˜Ûxȯ^,.~ñ`Þ–>s…^s“É>%§þùŒê¶_Õ¥ ^Z¦Ä÷^S&@֭怊á°&Eê 7þN0Ã*ý1oðó|bGó¬·]Aù+ÞuŽç£A]Cå×½VÔÛ-zwU"Ô¦ã“W–ƒ*,¸OfD$_ñ7£›Ÿ-2Ù0Ò":ðÕ§½MðÖ{*0ŠP©I÷‡_5úÔ“Fä z‘ÚžDo˜™ID§Ê‰Ð¥Î1êk9cÞÆÓ¯|o§»œšåÎSìgw³uÞDXX¾ä§tçÓÂND£òõq­®éÿÐt–el15øöåTãc%üãç¼Ùrü‘u“= î¶!ìŒs‚%¦wCQ‘ñOÌ­ž’T›¿_ù´“ïÉ‚œ8Y}]<øCÞð0ˆ/'G¸•HZ¨$8#Ý®79§äœº•#üóŠKÔócÌH±ö–—7aA¶ž~Ú ¬êÍËâ”ÖjCØåÄÒtžà4.?øÐ§u‹°Þ9òûD¹†I˜°ËšÆ> ß k·7 …àLC!RV£Õ¨÷ˆp/_9’áÔš2¿;©€ËFùrµ_`Ñôùäù—³¢’,Ÿš«=Y>¥NZo•7’]ó=\e~ٌăºªÞÄIˆvµqz®[èò`ʼvƾš”œ]žÂ<ûaígbæ!ᮕ*UvtÙØVqtøèù‡ñ`ö1Ó3UÑéêļ¬ ºc$‘«BÅÔÜK~çìsº5Ëå²5O7ë>áw?MÔ(,c_–Gû1êãõ¦DãYLJÚÚFµŸ½y—ûÍá)·A?ÛNÅÒ`†=2²ÎܲÒi#Ågs"]]ð[[¼'“£ÅŽ˜æRLáÉö>Ìm€¡¸¶h4Fœ#áÌ‘ ÍzÝÌtÜâjøóæ٧Hã×Âbv??;DBŠ\‘„íÞL¨ ?‘Å<Ç”¹”Ï`‚¡êŠÍ,»Rùô0Ë¡Oð_¼|â–q2Äh¼Cg{‚†Bà<£gpŽK¦r¿•Ï÷é‡eZ-)X -Ç¿ÊÒ^ÒÎÇñÀîQbKퟟñÐé--à ŽëòbPd’CÆhäm9Õ¸F`0 OGµ˜DQ§0‹JoâïVFš~ Aõ’XžtY•lø˜GŒ ´hÃyK[⤈QÎÓá³2tswѹÖÒziÖêØMÿ¦Žç1ÖÄHÑâèÎG ÿ|34}Ê÷o/ÂX4®8bEx±'£Íxò‹ˆ ŽýaÅ+űåA×LCŠAvnŸ):áñÉÝj!ø1Q/R,Ø$x^¦Ñ¦¼ 8ì÷ƒO¸§ê >¯ÈCª.qpQü©"BÛmõÝy…È\ÛzàdÞá‘^£þ]ºšãª}»+¶K$_Oç³¾h–U9„±8á±âYP…ÐæêÔ°¿Ð`jR˜Ö$Þ¸„ äê©Ë­Óø5öaó–{6X/ˆ,­[NÏ›KNž"Âk(ìB”«vLJ…lÕ®å®<ã£gMù ^’gˆ%þ®®Â+ú˜°óH)Ãé¨Òàs÷äD"æAàQJ¿!§—;<žf­é‘²wò-£°@Ça‚Ï“ÔêR^‹#¶=r²œç—R,­3ÝóЛxË3ãt¬fc 2MÁºØÕÑK§dôv™ÊÓḌåi‡w{\ä£UÁ4gR¢yò2[´ß­©û»z}—êþ¨XÀÏLŽporºÑ q‹eQcµáz3XJûí ³åQ_àéà¾~Á øÂ¬^è‘|óþ‰Èãw¬³AÚ;jë<“=¿Ž[pK¶=¹Â’ïgÄ×>Õxù@†€Kÿ•ósã>óB—Çz6ˆ×'°…á[ÕÒEt‘ÌçoŸÈæ½Öy"óié\Q^åýøÑ1ŸåèÛr¦X•ý„a©¦‘ \‰¾Ä¸a"6sÍ+*†vAS™¡ö[¹ ´p®Èzb}ƒ²˜zÕ©ÐEÍýȨ 豂dŸÞBÍUЄ•ˆ–k@#Ó}üÆ…ã´4|27ÙIé\ës”fýOEõ<ðŸŒaë›hç¢Ï|¨¨Öa[aQÐúˆ-—Ÿ,û…ÎuG†¯DŠ³Ñ¸$?\¯cö¨h¦I1‰D?MfHFth®ùµŽ0í=ؘ˜û¤Ígô¬}ÖhEÄý$œÊÑOÁ7MõÝëÈþq£\õwb79á)fí– …TB䎪7ï ªÎÃS>ad˜ËÓ#O]Àong:BW}ó>Ø*d›ÓQYÎû9Š˜Jâ°º½³.Dí4‡}UQ‚:†â)=zl(]M“rF2;#³tJü4œî"gR‰BÛkôÙªZ͘2@ùy)Q—0ý§Ù#[æ…—™ú¿`:  ÀœÐ]ã—k^˜W #[é)Ðnð`¬ÏÒÇ09ŒåãÊ3†ãë¿Q^ƒyËñ³m&ð/-~·éÓzoÌÞN*&9¸îSä)ã¸ì2ÞÎ<]á4¿–¹åƒh`æÚù馨AÜèˆ6Ò1tÐ%0ç®ÑÍGùY—Dîד‘Á‰E$r»TÝKÍ™Wyé9Fd/ÿ;ÉÍj¿ÐköU¿"+ÕH]•ä°›v…”÷§’§‘Í‹©M[y;o:š[Èç1Èo™¬¨‚ÑÝÏÞžP{ M¨¯ò[+æ9ýlý¦³‘¿øEk"?ÏD7L|mJ!o˹f…DkHs3EòÑ êgZc}l¨åãRQaÕÑ4éJ_XjcÔ{â’÷Žbo,ÚdvÎôúRú²Ê¹ã†Ú ±÷|’®©&„gÐ#™·½‹ùñ-øk2G½Ž4(l–ý(C/[¥,G]窞ôB[S dÄ7?¥OUõÓ}ýeßXÇ Œ[´Ž^³øÔÛùÞÚŽa¹¨¤ð¡ÅêlÏüC%þîÒf¢µÃÜ!³ãeÉΙ^{eù”>øV щoˆCÚˆpö¼»†¢íÐþ#ÆÆ]ÌÐë~ü^>êÀËlï,àÝxB½t½É+Wd¦‘OžeG†û7ÇØ_÷Ô~Š£âz É­Æ® S/8)æÛ„nÎÈLc<Œ,Ãï‘u‘OŸ¢Hሿ&ÎÑVÏ´æNÎ!¢kõšÛlLÚµ®}BùQőőjJ£öÅ·Ò0<­?Óo*Ÿ¶n‡âæÖì!5¤FÇ3ç<Ôo1‹Š=ZêýÔ¤ðr8ä(O÷¼¶MÏlç¥;LŒxA%Lkä+ó+’‡oúcÝ;A-l'Ñ™‡ŸõရWÌ9Ï®sÂv…Z£æRHÄïöÆéœWæí¸ù–všu#^šš2"Ö{F»&”M#¯U¸xRQkE”n,K”9Ç Àc¨‘yæp¥á¯©é¤ŽcWõ¾ˆÔ/+Ð4@eÌ20Îø?º:£c endstream endobj 15 0 obj << /Length1 1382 /Length2 5941 /Length3 0 /Length 6888 /Filter /FlateDecode >> stream xÚwX“íÛ>!é Ò°‘"R£s´c Âc”tHˆHIŠ„ˆ ˆ ÒJIH#Ý!!tÇ7}ë÷þþÿãø¾cÇñ칯ë¼ê¾ÏóÙn=¨‚-ÚA£°B`a PI Uƒ€ ˜0$ àæ6Db;ÜÆŒ’ùˆÃâlÊ0,©F5Ü€`1 XR,%EA é¿€hŒ Pæ´j 5Ð(„€[ íâAÚ;`q…þºòÂù€`ii)Áßá@g ‡¡€Ú0¬ÂWsBÑp$ëý¯¼w°XOOOa˜³›0c—Oè‰Ä: nŒÂøkh Ìñ×lÂn ¡Òím‡õ„a@œÁ G Üp1î([ˆ+„ªku]¨?ÀZî, þ;ÝŸÑ¿!Q¿ƒap8ÚÙ†òF¢ìvH'P¢%Œõ a(Û_@˜“ó€!`68ÀïÞa@ˆ‚>†ñÏÝठÖMØ éôkH‘_ipû¬‚²UB;;#PX7À¯þ”‘·ñÞ"ïCÚåó÷Ò‰²µû5ˆ­»‹ˆ éêŽPWþ„3þ±Ù#°@ t…p"¼à"¿Jz» ~;Á¿Ì¸)ü|\Ð.@;Ü ?¤÷ðqƒy €XŒ;ÂÏç?ÿ^À` -ŽÚ ì‘(À?Ùqf„Ýk0H/à}Ž` è×çï; ÉlÑ('ïà¿OYD]ÕXKÑT௙ÿö**¢½€>BÒR@!Q  ’’JIHýþH†ü³‘ÿˆUGÙ¡Òô‹Û¨¿zöø“¼Š„øï\:h{@ÞÈþ$‚ã.àÿ3å‡üÿ˜þ+ËÿNöÿn âîäôÀû'âÿÀœ‘NÞBpôuÇâ¤ Æ õßPÄÖFØ"ÝÿÛ«Ž…á$¡€²ÇÑZ,ú‡éAz!lõX¸Ã¬ùÃnôKqNHBí†üõÁ…€@ÿåÃÉ þ÷ qÃQó· SÑ¿‹ª àhÛ_r•Â0˜7wÔ¸•Ќӥ-Âë7™"Â(4Ä è´Cc¿Î –Š`ÙÿÊ wÇ`p2û}þ¸¢­kðBÀcÃh¸l¨cièç£O¡Åž;D?SŽLE…z^[’`[Tú­¾ÇC_¦k@ÆšÁKÇzE×£Œé‘]Ÿ…ìeÞâBìe{v›ØáËüÁŸÃœÃ”UxÙ&IŠl2y˜<=Ö(ªRy[û(7¥/OiÓh‚ç-º|ˆ”ÆãÏ:u %ùéZ 7¤×ç °Õ6m†‹{×y2çœcBæŸ>ˆLÖIãÔ¼Sw ˆ÷,¦šýÚÑ6IÝÌڤἸu3 K­"ÛvCYüj±ñä+гÌ<µ4UÚ{k¶-…£ªÏÎòj_,º€ á3Ô1ÂÆ{Ÿª½kÌTA²¾í»Ú!o̸£M‡Iú RÕR^˜Æ€X\7@ªw®E ÌåÙˆ©{<¿8„®x²Ø’#7úBO¯/ûÁÅ¡]²ÿ®1—QåWwùPP‘˜r¸g¬a"Ì¥™5b§§óJœ3yáGÄ“Hý·53G&ãóg·¹RŒæ Ó5yjÇÊ–B-yoÉç]2®bÀŸs ö3·ÞIBöcÙ$w†xmœGâyF/m…ÕÂF÷õ©k˜ê÷Ú•¬M¬oCé‰Ò{Xð¯-IJE=jÔ̱50NFŽ’¾z´z?áp•—Ì©ôM.cÖÄÞcˆ}ie÷µ£AAÿgIOEßPªœ)cu˜,ßÞ%p‹fÜV6ºrÎ@xÐÍq‹E˜ÎéA—(x)¯f£¯º»:ƒ‚¬Çña—mÑßZF™K¬A—ú"HM(V–¯`Ž6µ­ˆ´4ìk§Û‡‡¼/ù›]H¢¥õJ7¬In¹‹:~—oO™ýÒl¹1fóºl74_qá%:P~‰E¸Ãе4¡w1ýæ|ñ€ÌM‰Ý•Å̃‡uÚ9÷oˆ@Už¡U´¦ô¯“g™Ða–wu0ä|ÍÇP ]O–ÓüÛÇЛcˆ7=õãD»|)¨WWì£WÏùm ¯Ö&þ8')‰X£Š’cbKé~lÿ(™è®u;!ºÿ0¢Èñ3‚ÝÐK@¯óõ·šmƒÄFóFr/‹ÐL:Ö[ ,³'W´’f= ’«kø¿R›*Ó¿ ŠÈ#ë’-µä5>-XaòŸj6¡ŸçÈqÐu|a1E×Gt•– QhŒ6ÿ4ÞÓ3/* =ÍÎmôcìKkNh0IÓÏ$Y9§®íû·dÁÝ»åÁMne½oâïã›=³Ï„(¦R$KÆÔºÙ¨§ÄÃ˦,áÑ}.,kØn!1áô—Э"8žLŽtûˆÅzjÆxšö§}¢0 õªÊÉ­v%[³ØÕ§}2­~†&Ú3a~5žKSrAúä߸⼲޽ŽÉ"äSh²ê¥‡¾K_/üÈ~Èð1Ø`!ÿÂ1€óè0’‹&ãšÊˆ\3£’Oe[Gëð=DOÌÐ}Vâ>D—ªù-îÆîï±2‹C$”ßß÷¶8x•¹ÁÎ@2ÖñÁ/d–¸‡3Ký6ævvÖòkäºúãA©žÃçq³4OG_¾TÙ zÒF%(ýZ‘wšöì6¹H·M1¹üÒÑì]}F×µ8@£‘0’ÑÖ^záô‡Þe´úãùqqïÙÁ¨/¹D“ˆ/õq=¹3š(†ÁeUemžŸZæó×-Ï*UÞñ¾î|ÎU…„GÜRO4g,ò>' Qʹ½½£{Y©W•ʪ¬âf&¶ÒŸ­*»Ù²-}!ðnÙôCÂUýáÛ÷ò8z´EŠ!Ò†&2whM^¿%¾à‰ñUèmrw×?zýô›Bd:xìÖè’2õ(Ä\…ÏCƒáóéççV,Ù^X9}ôÐÂIj6WyÝk2@ù‚RvL_Ü2/qD~9žŸJÊ«Ô,ŠbX—ú¼F×êá§…RbZãE{~¸·Ñt)¦p݇iíÁ ‹ÐIB 2`é@½Þ[ú±çŸ‰ jŸYɬ{Ðiaø4)OÂù¡•# ÚËÏöëC*ÇóΙnðT&}(Bžæ±g¹a$Ý+òpø‰žÒÝ{ÜÙ…g™Ö3ëAj=!#~ïaŸ ¥ëÔä}$ãºCï¢+·Ók{Ýš jirç>—ô(½h©Ðx,=ˆPÌöÞV¼—)Òî6ï:ª„—Jªt \å'öª63ô<³ÆŸwßñ{{ <þQt°]Z̯ }ÚB»ÙD%$Û×—õ3 ,ÆøŒE+(°mUªJúB$=^-eF—§B‰›{^IDñ C &§A‡ìë/°åu\õh¶û´/Ím¾—ò˜’L ¡¡ìDN‹ƒs”rŒpkð?³b¢:Ñ5˜ó•«·îË™2`_ŒCeê ð¼â˳ïlC“Æ&ÖÔž[û¤8ԮϞ¥1ÑkYû¦?ùÜ/¬;ôD‚ µ'È>?nÔ4ò칫À‘¥=³wAvs´åøfrnÝ÷xãÍêùwjH•ªž÷ ÖgÊH?'Ò>PVލot<:H!ÑQlîüz%‘l«2»Âfì¶¢^õ5ûdÙÛ™Dg=Q5÷54Þýð¦gvz{v}Íþ‡ÇEý¼X‰ÙZ}¦†þö`óúK°œ°ÄÚäé²´¸‰t×¢1>| ã.(š¢idœFE}VPªõ!%’;¬ŸØ4nS®€È~ƒ/=ë£ù÷w'PÌ+@)՗鿨byh€Œò\é¿ëTÄ3µðÁr3W@õ4EO’ÖÕ;ì†ìNÝü§´ãÌ;åߟ–QåW¼#ó']ccS˾µ³xž 4¸ýpnU’¸ÙÏ”Ù÷çûd—ŵÁ{'‰œ°ƒÎËIþh”1Ï%ý†õM þëàqA|q§Ä¯­_ýå?¡ð²*«Ìš¿0&’_1–XPõï¾Èõ™ò8«ü–¦’Öÿ­×ËÛïæÇ¢îbÏM•@ÝC’)þñꢜ٦ƀöeQ¼3ÑwGÓÃùY3‘ ù<Øõg)à8øÆL†á倉üK±+êU ¦6Tÿ{e)8HuÙg¦OKð1­²†Èâ&Çû4ÈKÚøta…£©¥…Iƒ§2G:ž£ñ%­%žU™eÞ¡vüÜ€Ä(ü·z›o-w°†iÉÓI{®Š_Î> *2?îÿy`Nž^î^.¤ tC†—sPŒÛAN‡'ž}íþ-“D©ÙŸoãÍ^usß+ã½±Þ \ÒǼYUÔLº‡Ÿ\xM‹ìÇÐýðËsv*Ýö© p«1Í¥ B¡P»yYkïB.k"ÝBÿÛK¦9×S™‡é©ßö`J NÉ¡êx‡{xµq9þH#ð#¦6øI,›¢«ôò¶i· JÖö=siq¥wví§¢}k9KC¬…«Ê€b—€X êÜNïT ör7­ÐnÏÓ‹Éß"£(çO;Y¤3nijrŠ—»´}襾ád¨—Û÷m_$É<ÞÍ»põò£Ú f«í†— OMÔA[\Þxqï#B&=B-åÕd…2‹FÅ>Í2]6Ža?rÛò“TÖES¼¾TÌ(@åç5†/•ul埓€ü²tX¹BÓ‡#3‚R$[¸F/9m8wó>ÆÁÁP“_Ì^&“± ©v’¦±ˆ¨\3ØNO‘àWo<œ®ÁjD ¹'ž”™ðYõêxû&Oe2†úäAvûB“x²gô¸ôØö¿=î:jš Z%‰’ºÒx®•Øúæý…:W¥ó.#ÏÐ ;£yT>lÁÛo^y4šBù²žÅAçľ:“š‹G›Þâ+y텞ǒV<ýµÎÆSTDÊÞ‚eƒµ\¨Jm®­Ð]„3¾qº`çež&T‡-1Zl6W.Zf„ú8‘óýØó#±|•Mo'²ãº' w­üd'øÝÇY"WbO¯@¢SæÅÞ >ù>Yâî?Tíµ]ØóÕ˜f{Ò©‚¤ü©#¤púá€{Às¯ÔNMDWßþÅÊOÀfE1½W‰Zm™tJ˜…l´fO#‡ïÏ£>fniSI’`·äxºŸZÇ÷<ž>‹”Ò§eÍSŒ»¦èlúfe`÷…”aè=pú2̆ÎÐj*â]]²jËÞPV_^ œC_¤êm=–9¿4·4½C$ÖØrF‚|,J»7÷FÑrÀßaùú¥5Í„«PÑÅÑgÿƒ<Ñ!èÚöžñæÉL‹¼ñèBŸn¸OµjæáésÊbÆëVT‚÷ŽÅ‚gy8ÎycBéΈ< ‹w°=HÁ|“Õ–œ~櫈«ˆkEž;Ÿ‡(\¯½dœ(7%–_‰L¾rG”^CAP{sO Åë=ú»°{ƒcË·<ùaO·Oꎣ’ñ¸u¥®v )‰S\ץר™xT¿«amÒlOr >ûù£#f£Õ\äixpK·W@±$Ú^YùH,/mC1T{ÃI'º“s25ÍçRÉfÊœûçîû#YþÆ=ÿ'¼ƒeNûjà7vÀï9ÆÌ‘¯#ñGÐ7nlàŽÎþ+0ü©’¤p;i®†x‰Ÿ"„mŠCÞÁB-É{‘ÎÚ÷ Úñ ¶µkoÒ„m»¸œªŽÃTrY>—%pÔS¤i°ëWQ¬/ø=Ø~ëòáÆ+Ó¶ä‹r»¥9ÀÑ ¤£ªË>šÊ7Ö\³í¨`×û>pºô“B ûÔJ Öé-ãˆ{ŸíiñÃå™tñ#‹÷¼”²i÷ÐûÂ?¿#ðƒñ·kmbïî¹õ.5˜ý)O„Ê5ØB«f…äf„HÕOÖ’ ZF…í,hü­:WçãI2ÃWä0`þÇÝU‹Ò'w%MOH)Ò`D|‘Ïuþú1µèîsËî×+§R|5Ñ¡}ŠÚ,YÚÜQñU¡Í¡Ÿüíý¥]iî›r)^¶–|à|õÑÕ»}eCb6a§¿f“¢Ò•W65ùJ¬ÐNæKR•¸¡ºAï©ðÅϲbxûÆÖµöO &CâÀ3ß7÷#­zLAWIOBèG·2lJŽz2( çìo\ÓÐ'D*LW™I|ýÙô“}þÍáB4ٵɬ—«%6㎃„·¿^t™SkT/7³®Æ~»(¥y#—Ò‹ˆ"²äìɦڗùZ†Ð~ñ å¹ïìöƒè:³dºÒ¯z k¹#'iùÆJ±?å\ù—cd'uf¯[Ùª0cÝçLG†Zé–ØùT!V]O˜Lï ãõ‰©ÞÕŒ<_²}7À/È6$L|Öç­éÝŸ$¯§ –¤ñ¢;.QC#fj+J·Ö•ˆ©HXqJˆ²WÅËí n4òʼ®[.O¸Äåà]4EøøÁ L‹®œ†{ŸBÅY÷]•»\ˆÏÒ@üYòÆ“ëêó=õÎ,½öqm>+ö‘*ú9‘b“g w¡I\›óæ¨ H³04lgÁ̺•ó·íh4ºs'ÑÜðžJ\WOvCiËè;À`Ob&J6  %ÑO„dÇ#ã:¯6¾%§«FÕ{u¿LíZk™ãØ e 7Zë:^®²Ù=cU4}TÄà|³-}têÙÎ&GŒ¡êõpKµÈØë³1a_:l—2ZG¥œieD÷_A&"¥¥w}CbBfX;®_Ú’’8P1Õ´K+é?%¾ ÉË´„í(æ\ Ç’°\ ·†1˜Çäëò'‘.1¥Å&¨œ¾0ì=xaríÔÚZ }dÌ~FKñí“è£l6L•§ƒ|²Mb"•¸p£ÓÛ~ ”¦oŒ~³a9ÝœŠZiÛjUˆ pÙŠ»¯–ÝÂ@s÷ÿiü¾îà”d)W ˈjþrDJ¯Á=Ͼi+äÈ÷7”bÞ.†<å>OrÞ>‹¿y Evyß„$E>^¡·Àœ8 X]HXœ`¤cS䯝k$Têê Œü¤¤mÚJBŒ‹\fú~¬½*Îòºt4ÙœH¨­©ÙŸ³ŸÞÉLÂܯ·*¸ÉU…¢ºþÝ×'¦„v%ŒøœÛĈÎióeàÝQÍS2Š{}Ê…´Ùw³y~£òBLíÕ"Ãsû£oÓÆ«W§ñÓs©§ê7.ëÂò³üÏŠ;ö· …^ϼßóöíÅ—z´2™6èu¿®êAÈ‚@+Þ2ÀL üÖ“„vF€š>Ãìr]÷ ÿˆôyŠT mÁ{Šh–἟è¼L©ÅYC«LµD¢óTšP]NæëœÆš.~ÝH{mZ’c¯Œp¶Võæûµêzçw…g¤øLœ»½'¤®~ÖäÓt!Ï÷j-uy/4š<üÒÑhjIÎûXÔ3tÑbyxbjâ…Ô~ÌøFn¨ß³z:“[ÃÃ7öGÄOºu Ùè2¶ŒW‰Š¬6}¸òIiÉCxZø»Ø$NÉw"™æâüƒËyß'Ã}‚k†:„×ü5—Í*'X>K%+‘y •BBRáOëâÆ+E?ÒÕÛõóÚ_#ý•Zܲ† ;ºž:Š2 ·â—‘ØÕ\-¼¦“³ëÂ1]¬CÕužH”( yå€h-ÙZw&<óë­Gd+{‘ß–’º7ÃŒñw+Ü„ø²ßߌÚ?|ŤÙÚ ÑË/©¹’K˜Èº|¨v zÐYÀpcÂeZïƒ\o endstream endobj 18 0 obj << /Producer (pdfTeX-1.40.16) /Creator (TeX) /CreationDate (D:20161028142046+02'00') /ModDate (D:20161028142046+02'00') /Trapped /False /PTEX.Fullbanner (This is pdfTeX, Version 3.14159265-2.6-1.40.16 (TeX Live 2015) kpathsea version 6.2.1) >> endobj 9 0 obj << /Type /ObjStm /N 13 /First 86 /Length 743 /Filter /FlateDecode >> stream xÚ¥TÛnÛ0 }÷WðqÃëbɲ X.K¬Š$è yP]51Å™­ní¾~”ä¤I»bö`š"ÅsHÚ¤ ò p&€O$(S`¨PŒC‚:•ÂÚ©` Ð.ÒãÅЄ~‚f)hÔíFdþ¸3@.õÊDdXm­ÙÚR¤›Fdjšê¾.LƒÜÞpanK=¨`AÑpS¼YK–-#„©1Þñ¸ë½žc„ÝTõl§ ƒ)£ÃÑYkê-ÖáìÙÌjk°¸ö͘¼Ö\…n0ªÔÿ´£Ãø¾!}µ!ö¤ùûbçþÆú£3²ˆ tcüžyñ}Ojw+Õ/¿qY7Ö±®Nr®Ûãˆõ¥¼µëÆ-á&ÑÏgìésvÆÒczwÚÓ³—ôn³7nµß»Å‘Oåm ߤåéÍ¡ÆÎW«(„-ñ_â ¿ endstream endobj 19 0 obj << /Type /XRef /Index [0 20] /Size 20 /W [1 2 1] /Root 17 0 R /Info 18 0 R /ID [<81B0B7D05021895A491A9F9BEF85DFB9> <81B0B7D05021895A491A9F9BEF85DFB9>] /Length 67 /Filter /FlateDecode >> stream xÚÇ» €@Qûø. ‘_1ôEÒÌOcKúŠ¢ A CÖ*˜|>¹gtè]·üƒ÷ÈŽX|Üòõê©ç7 endstream endobj startxref 26048 %%EOF leidenalg-0.8.9/doc/source/figures/layers_separate.png000066400000000000000000001201111420514302700230500ustar00rootroot00000000000000‰PNG  IHDRFSlæ $iCCPiccxÚ••gP“YÇïó<é…@B‡PC‘*%€”Z(Ò«¨@èPElˆ¸+Šˆ4EQ@ÁU)²VD±°((bA7È" ¬W”ôÑyßÙûŸ¹÷üæ?gî=÷œ‚8X¼´'&¥ ¼ì˜AÁLðƒÂøi)OO7ðz?  åxoø÷"DD¦ñ—âÂÒÊå§Ò€²—X3+=e™/1=<þ+Ÿ]fÁRK|c™£¿ñèלo,úšãëÍ]z )úÿÿ{ï²T8‚ôبÈl¦OrTzV˜ ’™¶Ü —Ëô$GÅ&DþPð¿Jþ¥Gf§/GnrÊAltL:óÿ5204ßgñÖëk!FÿÿÎgYß½äzس {¾{á•tî@úñwOm©¯”|:îð3™ß<Ôò†@t *кÀ˜K` € ð¾ ¬|d\° €"°ìU 4€&Ð NƒNp\×Ámp ƒ'@&À+ ïÁ<AXˆ Ñ H R‡t #ˆ YCä A¡P4”e@¹Ðv¨*…ª :¨ ú:]nBƒÐ#h š†þ†>ÁL‚é°¬ëÃl˜»Â¾ðZ8N…sà|x7\×Ã'àø |†…ð+xa ʈ.ÂF¸ˆŒD!d3Rˆ”#õH+Òô!÷!2ƒ|DaP4¥‹²D9£üP|T*j3ªU…:Žê@õ¢î¡ÆP"Ô4-ÖA[ yè@t4: ]€.G7¢ÛÑ×ÐÃè ô{ ÃÀ°0fgL&³SŒ9ˆiÃ\Æ bÆ1³X,V«ƒµÂz`ðéØl%ööv;ý€#â”pF8G\0. —‡+Ç5ã.â†p“¸y¼8^o÷ÀGà7àKð ønüü~ž A`¬¾„8Â6B¡•p0JxK$UˆæD/b,q+±‚xŠxƒ8FüH¢’´I\R)ƒ´›tŒt™ôˆô–L&kmÉÁätònrù*ùùƒMLOŒ'!¶E¬Z¬ClHì5OQ§p(ë(9”rÊÊÊŒ8^\Cœ+&¾Y¼Züœøˆø¬MÂPÂC"Q¢X¢Yâ¦ÄKÕ :P#¨ùÔ#Ô«ÔqBS¥qi|ÚvZím‚Ž¡³è@IR%%ý%³%«%/H CƒÁc$0J§Ÿ¤¤8R‘R»¤Z¥†¤æ¤å¤m¥#¥ ¥Û¤‡¥?É0edâeöÊtÊ<•EÉjËzÉfÉ’½&;#G—³”ãËÊ–{,ËkË{Ëo”?"ß/?« ¨à¤¢P©pUaF‘¡h«§X¦xQqZ‰¦d­«T¦tIé%S’Éa&0+˜½L‘²¼²³r†rò€ò¼ KÅO%O¥Må©*A•­¥Z¦Ú£*RSRsWËUkQ{¬ŽWg«Ç¨PïSŸÓ`ihìÔèÔ˜bI³x¬V kT“¬i£™ªY¯y_ £ÅÖŠ×:¨uWÖ6юѮ־£ë˜êÄêÔ\^a¾"iEýŠ]’.G7S·EwL¡ç¦—§×©÷Z_M?X¯~Ÿþƒƒƒ'†TCÃ<Ãnÿ´øFÕF÷W’W:®Ü²²kåcãHãCÆMh&î&;MzL>›š™ L[M§ÍÔÌBÍjÌFØt¶'»˜}Ãmng¾Åü¼ùG S‹t‹ÓYêZÆ[6[N­b­Š\Õ°jÜJÅ*̪ÎJhÍ´µ>l-´Q¶ ³©·yn«jaÛh;ÉÑâÄqNp^ÛØ ìÚíæ¸ÜMÜËöˆ½“}¡ý€ÕÁÏ¡ÊᙣŠc´c‹£ÈÉÄi£Óeg´³«ó^çžÏkâ‰\Ì\6¹ôº’\}\«\Ÿ»i» ܺÝaw÷}ÕW'­îô<}O=Yž©ž¿za¼<½ª½^xzçz÷ùÐ|Öû4û¼÷µó-ñ}â§é—á×ãOññoòŸ °( ên ¼$ÔŒ ön ž]ã°fÿš‰“‚kYk³×Þ\'».aÝ…õ”õaëÏ„¢CB›CÂ<ÂêÃfÃyá5á">—€ÿ*Â6¢,b:Ò*²4r2Ê*ª4j*Ú*z_ôtŒMLyÌL,7¶*öMœs\mÜ\¼Gü±øÅ„€„¶D\bhâ¹$jR|Ro²brvò`ŠNJAŠ0Õ"uªHà*hLƒÒÖ¦u¥Ó—>Åþ ÍŒc™Ö™Õ™²ü³ÎdKd'e÷oÐÞ°kÃdŽcÎѨü=¹Ê¹ÛrÇ6q6Õm†6‡oîÙ¢º%ËÄV§­Ç·¶Åoû-Ï ¯4ïÝö€íÝù ù[óÇw8íh)+Œì´ÜYûê§ØŸv­ÜU¹ëKaDá­"ƒ¢ò¢…b~ñ­Ÿ ®øyqwÔîÓ’C{0{’ö<Øk³÷x©DiNéø>÷}e̲²wû×ï¿Yn\^{€p 〰­¢«R­rOåBULÕpµ]u[|Í®š¹ƒ‡Ùj­U¨-ªýt8öðÃ:§ºŽzúò#˜#™G^4ø7ôemj”m,jü|,é˜ð¸÷ñÞ&³¦¦fùæ’¸%£eúDȉ»'íOvµê¶Öµ1ÚŠNS§^þú˃Ӯ§{ΰϴžU?[ÓNk/ì€:6tˆ:c:…]A]ƒç\Îõt[v·ÿª÷ë±óÊç«/H^(¹H¸˜qñRÎ¥ÙË)—g®D_ïYßóäjàÕû½^½×\¯Ý¸îxýj§ïÒ «çoZÜïþíáÕÃü< >Œx8õ(áћǙçŸlE>ZþLþYýïZ¿· M…ÆìÇúŸû<2ÎõGÚ ù/È/Ê'•&›¦Œ¦ÎO;Nß}¹æåÄ«”Wó3JüYóZóõÙ¿lÿêŠ&ÞÞ,þ]üVæí±wÆïzf=gŸ½O|??WøAæÃñì}Ÿ>MÎg-`*>k}îþâúet1qqñ?.¢¼r)Ô• cHRMz&€„ú€èu0ê`:˜pœºQ<{PLTEÿÿÿ7~¸äÿÿÿý~tr%tRNSÌfî3™"»wUˆDªÝ¨óàëÇß›ÍíïÄÀPäøi‰æ˜vÏ]ŽŒbKGDˆH pHYs,,sˆéRtIMEà $‚9ž@€IDATxÚí½é‚ë<¶X×ÅyÉvrÛí'q¥÷À©)qÄM`­Ýç;§ Ü”61ãÿËü| Šu¹¿L¢Ólï[]€O|É¢??¹N‹½ov9h@ZërïžøžÝ¾åk« QqHÓh¥uý¥KZç{ßîbÐ(€8¾¬ÑL¥ÍÛwÎ˵•ÖÍʲvˆãkm”jKsµ÷æ2?á I_ô×N_®¥ºûʽ[~&Ñ:Ù;†·DñÛAð†¯iTé+ï4Ú¸ig7×VÒŸ·WÐèGÄ[Ô¼×S<ê_ÔhWªìƒFË‘¶`3qíB®:*N£} cµV·?»ÎîÕ÷Þ ‚„ãóå¾Ñ÷ÍF´–Y« Ž\;>\ï(ý@–úkUŸz«þrÄ~y˜D”FÕÈ;Ú4Ñ*g×®7X¶F“65ùZ½›§'ÌÉÕhÔéîxÓí`QíFþÕÞk{äÚ¦ª›~ñî-²F³øÚÅNω«žÞÄr5ÚWhÖ{ƒ$fcO¤yL-½µÇ®m*7ÇZ°FMs]§¹Ræe;9†¥:¤Ë×4š”e¹0‘º§HáÐHÒh5‹½IIc×.­u|‰€5jꢗeg}ÕobZÜŸn¡Ù]n ~˽WTGýa<Ñ¢$ï.¿z§}êC¬M>ŸÿP¨¸ÿ¡{J›Wòõo›éËMk4ÿ›X~°Ývz¼ËàX£ájÔ´‚o½‰&QÚñêž+Y£Ñá:”`’ÑDë›OW.’iô°R^UÉíÇÔ£°Ÿ(79ô­FÿV £E-tŽ’[ û‘p5Ú=šò¦é>^½¿à¯HÖhío­{ÇŒkÔüe«T_×¼z´T‹ëk´o[ÅJµš?Eýït“ýDo}ø÷ ‚y`rÕóçg›r5³øs1¦ë|$X>æ­“¿íÑ=Þ4˜b<ÑnºInêI3:¯ýOæÍY£^Ä·ºAïU“ÅÛËÍ×èÏ¥B:Z\¢'‰çF7ó-VÆüT#âïTÑ=Þ4˜âC¢•·ä4©®-ªî¾ïqÔ]ë&£ü¼×èØ@}c1ÕF¯­6T¬FÛaEs"-Š¿±ˆÖèár&ùhÉ-_«{-/¹˜u8ï-¹VU{¾ïîy§Ñ±š¡šLXu«Í¼¿ÌQ4𩲠,¯ïÞì¹U_ó$ªú_̧¿tÉÔmWŽ\çÑŽÆ/šümŠ<²;;—ÜôÓ÷ãk9Ͱ sûñQÓ&ïôå_Ï»ëÄ­Ênå?®ô¸l÷÷ÞµÕ­˜—û¼Ý’ôÅÿ0½«­ïÕ¿øæºîÝÔêæJ}ÛùyöÔR¶g… QŒk4t±D·{ªLžß»õm*Fw«•õ tžeÿ’GéÓ5^‘{yé> 2—,£ö)¦1Žš–ןô$Ýë ƒŸ»r_%pŸßúzŸgl&7ìÊ\Þ§ݶóNFº¹ècet±FS‹–C£.×hÛo£T>tÖc®Çu„¨·Rwɼõ™l_b‚C3¦Ñ~Aç%wÎÓèîoœ“?Ö„ö©|RÍò{}¾Ü‚žnM…•Q ±k³ÃÓV&4z™p>ðÑ}/†[_áèïMgМUL›5úqÔ4i¯•ËäÏ¿¾ÕèÄ-¡QoЗ)mwúôèki«TÞýy}v:är_Sí·Ñ=gÖ­°É çâõu§‘Ñuò/ûöy÷óí¶ÎR~ºö0ÍÙot+ãíß¿±ª›'¯\Zó·¹DÝØn Óô4;hbªPº¹Q?# ¨9o]?ÿëÛFýÄ&ŒÔ{Ãß&Ç9ëîË0Òü)Ôs›«¹wût_ί<­¯’¾4Õn;å¥[×Ì=]{èäô`õÑh?HyuÇàËnú¹@Å­þ?ºKÓteÃÜ‹Çß~æþvrˆi^@ùµâúªÑö¥y“O¾©™7ê £ýéß·}_ú¹ùøáèoŽœ§—Æyý(lòB34:œaw-ß_æÉæÃ¦4z¼MvŽ¡Ñîiff3øÙ¨ºý÷ó¶ŸžºP÷øæ =^ÃÛ¨Ñù£¦·NûW&/w5zŸgÐh˜ŽënêÛ‹Œ·åã14ú¨9CO%å½òy¢úÇAJõÐQ9áŸ÷kê'4:P\÷~Ôôñ“Óí+ʃ²‰û<Úú0QŽßžcçÔ;…sê73U½ Rö«*q§óGßa¿l²¼V*ëò’Yo4u·ž‚¾§iôuþf‡§ ¦Wq6ç‚?Œš–÷f×í“öe\ƒFI§&îóöѱÃS€¤®¿öò»Z+¾­ííˆÔèpŒòH™?Uøû)øÃ®éÇ/_gb¾”݆4'·ŸÞý~B£÷ûkÚ½5=ëóiÐsL£Ãò®wõzŸ×k¬c,pß®Á!åäì7dïðæ¯q þD}ñ¼oqò4»Mýù~ûýû*Þ`滋‡4ÿî~<`ú,¦ ^¶xì¯ü~Ôôz`®‰ øû¯O?wž]:¸«×ûì9^Çzâ§uê#ì}ØÐ¤Ø£jô‹$òצ™*óñæÚøýŒxF1Ø4 ° 4 ° 4 ° 4 ° 4 ° 4 ° 4 ° 4 ° 4 aP¸BhW Q­ Q…÷gĬB( Qp…P@£àˆ^£‰pƒ¤ýÑ(8¢×h¹÷(x‹¤ãWÐ(8â¢Ñjï‘.ð4 !pÑ(g¡Ð(„‡ Q4 A£h‚F!Ð(8B Qp…@£à4 !€FÁ!hB‚CÐ(„‡ Q4 A£hrx6J©:²ET›"³½? ° ‡[£U{Û§JY2i¡âK‰i+i A؇Y£Yo¼ØTû$ÓÚFUÚ ÔÙ]{ ` 4 9°F•Ö]ýžiŒIÛÍÒ¢/¥¹”%©N«½?°‡V£‘©/ª«D{L=2ÝØ¡™™"êG‰Q+kSk؇ˆÅæºk~‡˜ªd¼éêQg*´OEÖ©V{&`…Õ-ë];McuHö稭uZü>c4¸Iz¹Žÿ”øÛhͽ¬Óh¤:­ugkü²§hÓ¾GßJO>Há R]ýÚ•Þˆ˜ÕÆ.a•F#Ñ®ìÿÇZo@?†—©ž|ÃA5šëò÷תôFż¹† BX£Ñ"Õqf’ ‹ÍÖN‰¾t›Jzð`#¢¾ÍùÕºø•Þêêh=*fSÃíöþTÀk4Zêöš­¥ÇĈ9¹öä›·öÞŸ Xã˜m^»1¯ÕÑÕ¹©Æ*£†N3{ÔVh´ÑémÄÑ4U¬4ëÕ]Ì¿µN÷þLÀÇÔ¨ÒjÔyõúÛ1ÙÑ"sj >°B£Ã$SvúvâA’mh94Ž©Qó@Œ:/Z¿¹‰NGKüMt»÷ÇÛY¡Ña’5vž­‡-'f±zÃQ5:î¼_½žr¼DKì‹Dþ³¦¿ÈDI‚#$6êû JöóQ’ QŽ2ÄtY×ú¿Ty|ÙK¬¢VzpŽ©Ñé!¦Õ΋'‡˜Ø0ÏÖLxjmMxzLN¾Mxj.3æ{>°‰cj” O°Œ55Ò‹ûVOcoú}­uÛÏxN¿’¼c6ȱ9¦FL¿53Óïý`ÕbÐìë{/;­ck˜—Å šÅ ~qP:X Úu°ÔÖmMÒéÿÝÍÖ$å›­IhýƒjtTzÛ¶&éÛª˜A«4š˜¦ˆƒò²÷åÅ)£÷Gã “ÞÖš£b£<Y¥Ñn—áÅ~Ì©cðþPU£Fz¶mÎâíÛ6—Ï=®lÛì k4šìÔ/žw9-zOÃa5úrˆˆy…[8D$Ôn9DÄÖMxÚm®[÷=¨9›;Q¢X~¤]riT—½T·^¿çíH»‚#í|b…F ­w¬FIx8s–Á5úç€e+ËLêó0ª)²ã€e¯X¡ÑjïIñEUÒ®?GÖ¨Éôóì‘Þx•¥„+ÎNSðˆ5mj˜Ç±5jÈþ©ÿÃnºGõ¿ôe€Þ/–k4c_e˜Ëá5úÓØMç@sïX®QK›:A ÑШw,ר´ÝéUNW½XÐèhÔ;–k46M#Õ‘JŽ€F½cÝšzIy¿¡É‘ïÀcÐèÇ~Þ`„ãk´ŸEbj¤å±ïÁSÐèGÞà4úó!R™ ÑŽÿ¼ÁüÐèM¤ô‘ ŽàÃóOø¢Ñ^¤¤gzÐè~âéÊ!ŸÝ‚FG@£Þ1[£‡<¤þ±NöÁoÐèhÔ;ÂÖh¢Éh§ ÑШw,Ш·œõõNA£# QïX Q/¿{<ê4:õŽÙõõ»ÙÔ!ht_¥€ ^£uÁ×G)`‚Üá鉨cF¬3Ðèa?o^‚FûsE8/Ôht„ÀŸ7A£gz8™Kht„П7A£?ý -'sIààjõoý¯<±Øy^$ùÓÿV6Ÿ¸¬*˲­˜q²h´‡íðqhf­¾×vB¨º{‘­¤‹Tz+1UŒ•î‡Y£Ê˜©¬š¦©ZcªÖ‚¢ŠÒ¸.OL‘ªÿSeážãåXÕMS+ó§Žé> QpÈq5šÅZ«è÷J•êtóCR›BêÓ•ÈTuË­ÒȨ>ÎnEžCvûÂ8hrXf¦j×ü>è+’;ÐU_¥==譺ѣ½7%žÌ%$}àá€FÁ!¢žê%uý>Qm”žsrz"*7~<ʴ⟋lRm£«²V£Y¥l ÖJ%vÇzŠD©šn÷9ªF þXô÷·Ýv3ñsÅñìÑmÒ3bnþYo®á Öi´¹ 8vk±ÕeÀÑFOþ•è:ÐJwÑ~T£½ þZôw›ôz1ŸìJoḐÓFÙÃ*ViTƒ*Õ ÚR”ißèX©<µ·áRfÊÊU?$ZR!Ý QÏô|–Zý¾Ro8c¼©9ž¥·~!r5&澆Ë$è¯3_£ñ= }Í2em×cuÃ,J“VJŒ:]çî¢%kæ™0b—cj4Òi4¢ÑßX¯ž>šè|Ä¢§hƒ™[]™°´ùûÌ×hwKB#¨Û»ZY’ž󭯼´TÃU:¾–X¤³³¿ÔxÔ*ÇÔh¢Û1‹þn8¢ý;¾t%^_Ñ:+±ÐÝ×?Ùà™¯ÑR_»qjÛx?ɽ<Ū•ϯ¤w1ŸªÙÕQ[¯¸rLæºÕh¦ãµ×Nu1ªÑõfnîõ„?tÔ¾Î^J ’¬²Ó‚&™éWÃ$[ÐrŠÙ4Ï*ÇÔ¨©1ŒjôWëf%SÎkô¿W–øÏ±¦‹™™¿ømVh´Œb6vž­mgA3L²xþ-ôV9ªF§4ºšrJ£ëA£b˜¯Quk¿·:¹çUb§ö6ìæi-i´}$–Öq^Í+5ál&›U£Ñ”FÕJ¦5ú¯•%þ•Ã^{qLCþžW¹EåcÐ1JµùÃÑÀÌõ­B0gÁ@Ι"9¦F[]ZtÃèͰ½5¤ZÝ7š + CX”ø}Vh´xÌM6M+k&Sà”¥'¯¼¿¬£NWYÒO =ï¯ó!à(fˆ=Ž©ÑaEaȆ¹Dåøì$ÓöZ;Fét´ÄÈÒ-,`¾Fëû{³_Ê{¹ìlÍ¿o»6TÚÒ8c¦uuI«ö:¾÷û˜¶ÙüùQð‰cj4ÓݨFÛõçj¢ nMk‹ŒG'ô›¶£¤_g¾F›Ç×Óo,Óü6ý.]–Âè—UET—öFõ»ÝÔQ‘tÃÞÎ"ù¼Útëðà˜ýéF[õņþ¦L§c³<« OoÕ—lNò}æktØ1¤nc…Öº‹òºƒ·½š`}Ý|ñ®Ž,K¶†¨Or¾F«ÑeL›º{Ê1é-XòJÿËcbNéÛÿ: ÖÔ§ƒöGöŸúÿ(•Õ1í$/ÿ¥ÿ»Íˆª¶,ówí°jÔ°‘­##à í¥7²†iËÚŒQém뇯Fj¸›Ä kY ÑvP­Û²xK³Pg“iÛ<® þrT%,šmÜ@¢ï+z™š´mÑÜk 7*é݃•ûºž9O“å}»¿åõ팣jÔHop„Èy½ÞæS¸K>­«ï7rÜ65)JGˆô4«™wa¥F7lÒðŽÎÎü©$íySîÝpXž7ƒ|¬Öë»î·ôÚœ"ÒŸ!²uÅ\Ö=­e:ŸÌäúS„Vjtýt·=Š}KTÅýÔlîì‚ãjô|¦]›ô‹ë£¤ß×BföæTuoÒ¬*-œhw9Ó®Sç‰OÍýa+5êhG9G•ÜO&Ù]ÌÖèu>JWÆöNe¸ÌG‰Ë~þ²•ó•¯Q¤å¹`ÎWÞ‹•u´RâÛcLƒ+ÓAê‚CkôÇTCÏ’j+k}MYu>Ú¦ËíÖ¨³ècÅÐÝX«Q7•·o1cŽ­QG8Xô.åÖBeå‘v®ï1KÐèhÔ;Öi´vµ}ÇcL¯ r[ ÑШw¬Ó¨³¡ õû†Y$JËó’ÑÙ´4:õ޵u´Gü~cLà R­»¤ß燩Ì‘ðu>‚â4êë45®#bÊF”t½Hc UãcƒFG@£Þ±H£QÌAE½Hµ¥M©Ž€F½c™FCš¤~iI³~ht4êËõÝú½ºHRjÙzÇ2ʘô=*Q8 ¢>?)®A£Þ±L£;­yߎS7FG@£Þ±L£"æ#}[ç”†Š¨OŠkШw,ÓhpkÞ£”êèÐèhÔ;Îë¥:º QŸž× QïX¨Q‹5¿Iô8È9¤ËA£# QïX¨Ñ"¤™£gê›=‡4ÛËht4êKƒvn¶½?‰µ ËŽ€F½c©FÏSžJ—GåjÛ“­ô'@”¡¾DV‚FG@£Þ±T£Y¶Ó/Mp÷kÍ¡a A£# QïX¼ÃSßUètړ乩ýAŒ1CMóõ]Jq õŽUå¹}8D§DÖY9j7ÐèhÔ;Öh´pûpÄ¢G±¢–†ý|ÐèhÔ;ÖhÔq³;—:Æt¥Ò ØÏŽ€F½C F1] st6ht4ê5*yŒ –!ê«”â4êë4궺(1'¨®Ž€F½C¢Få1]hk`-FG@£Þ±F£®7o8ÆÄöÍë@£# Qï¨QcLŠC™VFG@£Þ!Q£Y.n‚{1±pKQI} zǪULIxU³x´£¡f*þ{ÐèhÔ;Vi4ÀÝò’~K–WG0¿Ž€F½c•Fƒ; ´?…JnÚœàÑw ÑШw¬ÒhÜø??íÄÐ,Õ%»âOFG@£Þ±J£=…^SëxüŒGc<:zÇ:&VGS=±’)ëðèht4êë4âtô|²C8ŠuܘÛ<ÐèhÔ;Vj´õ||…lªUñ(õÑ1D¥‰× QïX©Ñ( oÎÓ›)jƒ›º04:õŽ•eu$ÌŽ€F½c­F ­Ù;>FG@£Þ±V£oF\lPçÁõx zÇf¥1hátæh€ë¤¼Ž€F½Cà!"=õøv8ht4ê«j£îŽ"Àùý>‚FG@£Þ±ªoô Gª™ˆéht4êë4š.ûù8Hµï·ÛÀ;ÐèhÔ;ÖiÔý—vÔ1¦B‡·kËÐèhÔ;¤jô°cLŠõõÐèhÔ;Vî~ï<®HæSý¹ª™ãÑht4ê«4Z~aü§¹JjNºæìSrŽ€F½c¥FÝÿ´ZÜñ 3ï<ŠÙôzÇV:ó…Ì1¦YQáÑ;ht4ê5ªœí—׈Ôh3½éè€(eÿ« ht4êëNínòT¢ž“/ gu gxô‚¨ôâ4ê«wxº`ê]aM“,çuÙf¡}. ÑШwlÔh¸]PÝ€Õ̾†Db—Ä÷A£ȪV:U[{l÷E–ê ëþ|`«FÍ/%ŒlVç(\A£ODe/¼¸ìÌÿ¦••"›sYå¥`&,ïÄffmƒÏž)K@£CêT§yN§¬2Þ+·?8‘êk¶)ñÔ(#Ô ª4‚جџ\Ô£â™óY¥"*7vÖhdšómïÐ ½S·öŸg½9ï%žÒØ®Ñ( J,s;G¡>(M;þ4 ×ê¶îLóèÅÙ°HÓÂk¨B Û5jÄÒW—uÏ”]@£w*§gÔÆ'§Õ埣˜™v{`A£?±• Z’—e[ÙrTµe™ÛžxTOðVÐèÂ4ÚNÙöä1GK,ÂjJÁ†F {qç¡F­S{IP§—"-ôäÃJÐèR·/=e[¤7*æSÅÆ8;`C£?Õæ~m“OiUDuio°±2­£¢êظn?Ðè•l¤æx–ÞúùsjĻS©í̤‚XÑèvâÛ¦‘ßCzÙ†÷j¦uuëÉßsªçŒJ=^QÃõóëf¬ÄÃnx~dÖj´°ÚrèG©îÝî÷'oÓ&Oå=o£nÇ÷s¡ÓûÐè•r¬nX?.Òéh‰ÑîÓcd¥F•Ý%ãƒ$‹óÛ› ¡I¦èñ~.£æÊ×¶o]xoÐèýÚ£Î;­Ÿ?—Œ·éûVýîËàX­Q«³'Î3ïç[4цH›a’é!_~°M]8à‰¦hôvírÜyþ—ZÇLt˜öý6+5º¥¢8ÅhÄëw3m†Ië²,s¥Êž¡Ô²®Tµã¨L<Þ®=©Ñõ Q1¬Ôha·©šêÇÌäA4ùú®ƒFǃޢ©Zm}­ æUãn–Hp÷(½];žÒè¿›uüÊaí“Ý”Ì)Q J®6,ÉHõ}™\5=v5*/.íœÕîE£W†…gç­íòi¦ÌÜ9;‘¦X«Ñ ííLÓæ&½r Î-»Ò©{–}^Ø‘%ªLݽã4ØîQ4z¥Õɨóâõi7PPÈ<šÜoÖj´µk¥ÓóX}Q>-3ÞøQ§Ës éæM¤‹æ7ë—¶Ñ›­{P4z%Ñù˜ó¶Œ¢¶ãs¨VÕŸµkŒ4Ýê>À~?ÛX©<}^r´eîF¿0*WªÕkŽé|[Õ.ï°ªB]¡‡F¯zt²|»a®ü`²õPÌ_³k5:vDf¾¥°º¬€oŸt³i^UÔ^4Wüj¿½îä¿®¨‰—æ6½¡Æ¤Wo}ŒÇ™ZQy(¬^ :²ŠmÛÉÿSÿK%’jã¶"Qëμ9o”2iÒr/´(}0"=Ssܲ¾.©án3¬dµFÇŽÈÜ4Erl=Ç–®£mUPSIzܾC"oã*û Qï6êÕêÞE2çàÐ4€C™Ð(„€FjîÄóD¯Ü8/?TÕ-ÕñgE†° >…°¢ÑFÏ>°¾^¹Rw¨ÎÓbÎñ) >µÃ‚F!ì4êËùÃ%™ñè #l¥å¬c¨ŽõjX…°£ÑdAÅ*Zµ§\-êœu—=ªü?jYÔ·†FÁ–†˜º³w¢vÍ^HG›f9ã8¿âý€>€F!,itIu´\Y>`t¸c–gC힃F!lMxê¡ZÞªÿtxž<>{´êÐè7ƒA£à[M\?0ÅñƵgçç3hBÀÚôûÔõþŽk'‡«AÛBXÓ¨rýÄ䂦<Í]R8ñÛBXÓh´­:š}‡—4åIP(²õA¡Qp„½5õ›6›qˆH$ç)hDÙA2¢>(9 žaO£ÑºBš²_}>ÇÁJI™9Úßç94 !°û¶ÍN«£ z¬h÷Bì®Ñ~MSYT‡ÓÁÎ1Ý4 !°»FÏ›>¥ÇÚ4î`Gžì… Ñs…ôP¼Ål¸l4 ! A£— ©˜¤Ï,›#U¶-‚F!dhô§1õÑTÎôú÷DËwVI'×4­Ïý¬hB@ˆF#Ý-ØúygVL­õÔRÖÆë“íÐ(„€þ™fåd²bGJñ¢Y1P_Luz=—BX×h·n#¦|¦KŽÛžêÍ|îE£ök£:µ :51ܤÜžêM=îE£öûF[ ûvZw£"=ÞQ"&ºGwÊÔÐ(„€}6öÁoÊ^¤¯µ´C¦™wk?e Q#õÊJg_Ýõ+D_LzèÃ4“Ñê¨Ï£hBÀÅ„§•£LIú¥öMzèVýÏx¯Ç£hBÀ…FíŒ2¢³IŸfºU?A{˜õ[‹A£N¦ßÛeº%:—µêëK£VM}OÒî¿üÁhô;4Ö3(²ŸçãD£VF™&¨æo©W—ý†'­ÍtP±)²;ÐfT;ƒF¿@ÓžóÜf¡:çyNžÏÄÍbÐé䛉æ®A”É„2¶¹sTÖ—V¦&Á¼­>Z:çœçq¯=k>вÏóŽ<Ÿ£5õ±›9º»e×o¦;V„5ûß•Rm©zzâ§@£Ž1λ'edg2`¢Û{‘É¡§i9]ÅS¦4\”Ö\æ85:¿çÂogåùiu}/±ÑC†s:êPºœÐ¨c]>ò<¶ò «G;î·õÊEŽFÕ–‘ ¡ÔÎ_¼–Oý—R¡îÝ=4§2¨êýš“œ¢nÎBé.DŽF7íБݕ¦Ús1ÎõSÁžg–ö“îÞŒƒEi(]N¢žB5J£^r4ºâ ¸wtº£¥EUÏCLoÖR5÷q°©ŸHl-—•uMl}ˆ©x 1™úm ïûÈÑhd§Îx#q2áé.æz(ÕNgõÜɯGºæ1ᩱ?á©ÿÓÞ7x\ktÁ·`ùˆÌëôû~Z²½é÷qŸ²Ùöé÷ÙóŽ+QíéK:§ŸvQžÅé÷çe&L¿Ÿcæ |cùˆÌ¨íW´Y]$—õëãV.’+ÔSFª'ÁX®‰Ë:ç²è¹´šçñõÑI¼¹ïWq¬ÑvÁ2ëGdÖçÑ›[6Dª[»5IÕÿÞ#”?½«~>áhô+ôGE“Ú|ˆÏyž²5É\kÔ´f»ÑÁ.ð‘ý ÄŠ•{ïçÌŒ«[í¼zÚ½¥ô´õ„F¿‚ <×}£ž_ø²]à÷¦ÌžL_0ù‘ÏFy…p>R¯æÏíiÄQt’ÐÙÔy?ê\ën†£LÖ;4„€F!ÜOx*gOš(T0»9ˆ1ée"Tž>î ötš3…p¯Ñ(v2ù¬:ðàö¥ >•L”oì!ê¶Ð(8â ÓïMÅÑEUËÒù£BðôG£ßXÅ”9ñ¨µóGE0{›ÀcF!¾²ÔxÔÁì ¯TÊXk4 !ð5õ‰‹µŽÅŸ#ìIÓ]>…F݃FÁ r¶&YŽõ®½}©§3žD}ChqdwÒÓ€¤;‹´hŽ_³BY£‡žôôà*R/A£‡Öè'&ë6:hBàØm¼°èÏE¤kö’…¦ÑYkúD¤.›’,Ø{à@ Qa ï­úÖ¿›‰ù,‚F!¾­ÑÓð ;‡ OúwÇA£_Ö¨úTÛì<ÝxsšÄþnÕr@£_Öh¢?x´ ®UoÞ>6ç/ Qo7êëT¿=á¥ðr¤å->,ÆšBÔ­¡QpÄׇ˜²ôýö£¥Ï]…£D©{L€F!¾?RÿÁ£‰n÷þL¾ÍK‡qÑù²•*…ØaÂSëxzÀ>ZµoSr䞀óVUÉ`ö}¥uéGBì1o4Šu:íÑ|Å®ö'È&×êùK¨SzQ!E£»L¿ëÑzÅ 7ûëL§Ñ󗵦Bzäö4 !°Ï*¦(³½æš­ò?N¤’M©“¿_‚©ÆÇoØ£Q½ƒ¾ŽW銱úc{4k^·¿/Þv}4 ! lM}Ϻ¶l}ìv½Ñèß—Gßõqô%]hB@ FWrðþѱSDr}ô¥±hBÀÜ£j̘*>ø0…ðH£Çö¨ŸGƒ¢QŸ4Ú{ô°+I½ùž@£^iô';î)Åþ| CÐ(„Àþ­òƒ÷ÿÙº‚ö×hún…}8”+ÈBì¯Ñ,ÖkæÛ{Çñ—,€F!ö×h¿2TÓ°ÿÄ1-‹F!hôç'¡ao¨ßé!§¢QiØWéÖ˜W}{» þ§C„‚F!dhôµa_m}ÕáÖ£¿ßh5ŠèQ4 ! D£—†ýà?£tcP­Öí±*¤6Z=¤GÑ(„€š†ýSßàæó2«T§êPÞùp´Ý=ŠF!ähôÏyњݛŸ(r}¬©TŸŽO)Ž·g…¤Ñ?X8_©)µŽ%ÞÛ8O9ÞÞ+hB@®F×ú‡¤;RéÇëçQ4 ! W£¦kC*=ÎÁ÷ŸEm´>Ôî+hB@°F ÕÑ~.•È»cÆ¡¨É±ÎgB£25å½@íTGARöƒa[õGBÈÔheÚ®‘©Ž¦G›à³šËQLŸ[õBÈÔh¤´îꟼô¬r6: ´Ž4AkhB@¦F~šØÉ{&ïN/Hü,€F!¤jôº Év¡¥Zßós×f4 A W£?QkZö–#S)³Øãêé#ŽF!kÔ´ìôJËÎë'ä§J\Ÿ«îöŽÀÍm¡QÑí'ÏÛû%¢¦m/ªJÚˆò=DÝG×èOä¢Þ˜©ÔTI%íGZ/ž"[ÄG˜T‹F!¤kÔI©%UGÕâ5žYªe–=F!BÕèß}ùvFéÅuãD`](…W£¢Xó´ØÅBI£…³Ý죽}”¯èbˆ:ù»=¡Qh4*¯ÏbålªR¥[IN3Éôò®€/ƒF!Ž Ñôf‹¦ÕZçz•)7ÍE8)«æ¿(*Š›û …8€F-º[“·?_Iwö«¤QŸ ÞÐ&_2ß~Þ t_Ð(„À4ú:‹~=§Ží׋«Iw®ßUK:<Åw¢QCh´yÞ¿ÉS7öÈzEï<«}Ùz&éÝ£hBà5-Ý?câªÎ˜©½?‹e{ÕíßñîfÐ(À14úeòŸØ§-óÐ(„À14:eòEcLÒA£ÑèÓ(Ó_Òv¢Õj[½kÿnUTª²\[l”^eÑ“tÐè7èóÜrk­H¬çyfò\øü¼ÕE£žlëfú<Â^ÿ­®ö:õóAןWô¿?4iŸ‹´ÙY§ç"ÛûE¼Ú3OÔ½øªÑKžÛ|ûå%Ï-zášçžž®vš\™B’üü•OÓ>³ÎÈI©xËÎÏQÒMš˜ÌÊU?œoíOS~¬T›êôþøô´£Qçñ9Ïø¬m±˜t¼ä¹55çç<7ÏiêQ—ÕƒÃh4z¿ž>«Î/ЇŒ¢NÇÙÉPo›50iÖûÜi^ÿ–>1¥Óº/Ѽþï‡Iw=íhÔ9å5Ï›N·vJ,RÓ8ºæ¹¥úBe…}‰Q+~áÝ*£ÑÔ¦êyÿŽ”ŽO²­Ò»˜43~S×"«‡ô6чv-²¼×¶KíO¢¡Q×(ÝE— Šlí@[êöš”µ%é1××"[Q)a Ÿ4ú3ÜD4ÕÙõ‹3/Õͯé(ÉÝÝJ4Ò³’±ù]̧Bß6yòèë@£Îéî/âSbgipfê§»ô¬TGÕ]̽ìý©%ÜñL£w²{eÔ|s:µQ¤z8ÏTG­,vê®7f¾¶fÌuŒ‡-tzÏ “¶r¢ƒÉí{‰µŽ‚òáú“WúnøªÑfà¼Slåùæ‚¥át­A.?Gäé~mŸ j4꓈§Á›ØÆƒ¬î ð¾bå ,­å¹PüÕhûøæì¢Êâ”–oF!©Ñ~˜iÆä娫Ðuçh>õ}Ò*›A£ÇÔh?mý³G]ÝWäøyt¥ÿ@£Õh¿³ÍÇŸ‰]mëxwöÀA£GÕèOóyÉÙcãØsóŠ6&?…8¬F?ãh¾Óó3çi4ïfL%Ý4 !à±FÊΙ ÏÌÓh§ujom¿#Ð(„€Çæ.F_Q´ÓÀÕ¼yMM)_¤hBÀc–|î÷!_¤hBÊcÁ÷Ñ‹TZÛ´#hBÊcÑ÷‘åF¤Ï­R1ß'…@£ò(—mLUäV"Ú0ON$?hœq|fÞÌU·E”ºZw°4 !p|ÎZ^JÌG‚F!ޝÑÄÓS²6Ph)ÕQ4 !p|þ4©Å£·ü —²*Bx Ñ~»'[žK-tþñ©ŽA£>h>è.ÇI—_>vo 4 !à…Fûíð»/.%?´¢Óº_ÖÔ¸]õ?4 !à‡F{¦<š´N‡Y*™[‘Ò:MúKDlýŒF!<ÑèOTþõèì•éë(¾~>èL²Rë²HdTGÑ(„€/5ÚüÓ=êú®\Ÿºž$Õi݉è-F£þhôçOÞõ] >ê#j¥Ì¥E£iô®ï*›uÈóNTZÆÜ4 !à³F{ÄÕÊõ¶´Ð[Ѩ ‚|Ö¨ã äŽÃí|‘ˆå hBÀ_:hÝ3ð/‚F!Ðèj"7WÝçº4 !à¥F‹Ë¹¾L9ïè¹…$BÙ­€F!|Ôh”–‘¹3çÓãÝ,drÕåº hBÀGf©N›/<Á™ÊÖ¿4 !à£FŠXëÿç O°‹)E‘ýZt³ß:4 !à¥Fû%FGÝʹ±ožT—{}hBÀSþÔé׷γƒÍ5¦Y{îuhöÛŽBøªÑsÃ^ÆÖÅ˰ùeÜv¡2ŸE¼Ï;Bx«Ñ£6ìS›kXoÃU#Û±~4 !à±Fû†ýñ¦`*›K£î={yBø¬ÑŸâ€µQ«dÍ›óó¦øßBx­Qè“Ps½Ã¼~4 !€F½f8“Å«oA£hÔk²á‘LÉ÷§=¡Q4ê7ݾKKÑ(„ÝH%{2ÀÎ'F¡Q`4ZunnÒÕQ"–Èö=hBø«Ñöù ޵Î]t æÂ×JíÛªG£þjôïYL*Õ©ãÕÂ7«¯“=ç΢QŸ5ú§V´ZÇöïTx«~_Ð(„€Ï}¹«ºÓZÙ®œIoÕï …J£?‘Ò:µÜʵت/Ú/;5|F!üÕh>zWE©m?Úöq¾6;©ûÖž-hBÀ_ª‰¥Miyi¹=ù}mT=K¿$l4 !à³F¿Tµ³65³ùÞÏúKû” Q4ºÎÒç÷ÍÁªä;E£hÔÆ•ìô4~uêT¥¿Ñƒ€F!üÕh3G£… q­•Ï/ù®sòoì‡F!|ÖèŒ:b®í(Ðí—·U6u^ûE£kT¥Z—2î>Ò6³›CìþÜe4 !à¯Fçõ"+g6UÎæræ.‹bmóü¼1Ð(„@轊T·;œ÷öLììˆnjè*r~z=…@£†º5"M¿~PÑ…N]Ý~ÿ ¦hBž‰’x皢ÄY}xÇðÑ(„½áïvwÍ~2C£hÔ"wýŸ@£htŒÈ¯¤Û­ÃB Ñ1Ýå£Û’ª,KeUJ)²u;ãj¿1&4zLŠª5ynuGvÎsO»ÎÐèU§ ±úû¹(}alÈ&[•!Q{)Ñé<ýƘÐè!©Òkž[{»Gù5Ïý<*Žc^ÇçTj«Á+¹Ô:¯O‘éë†÷ëfÏ©NU%¥viºýƘÐè1Êkëèœç–<u&Ï›¨ŸY¸Û¬— ÑiLs»7éý¿+6§žfd×ãB§+R®Ôqq.Òé†K5¹ª# ÑR›¶Ñ9)³Ø–ôÚ[ž×ÚKÙø­ÑÍ=1Q­î‰djŽ—ì2Õ¯ƒ6åŠEãÞk‘ÊáAÍÑ'›u®v:E£$ÕÕ5)3K/÷F§Å=Ï¿¶7ùñY£–Û²‰.O7FvXNVäG«“[‰Qª‹¨9c¿ZÚ}ø jWua4z<ßóÜR¯º)æ^dü­“r¾‰Ïì¾øò‡óLÛäuS›à§:˜yÈ—?*SGp2W¡ó2;_`©3Ûf–…Ï5–²Yšù˜î¹0VÑUË÷KÒú4H¯ÿ,Ë2/{º§ÀÛR%ŽßàQìf)4z<Ô½ïÊ`K£'4zXìÞ˜ºwNɈu¢å‡€tº¸9=¹óR?sÕ¸›]š¥N6F£Ç£ÔFk[}Ô@¾yâØ×ðZ£¹Õiçµîî¹0:ž”/~ÏæŒ-¦wmŽš*/¯ÓÉ'gŠ Ñã‘é.z¼Û-õæ÷1€ý–Ô9ÄkÚm?˜¸I¯Ý´|ÎS£ïFå§.¬V¦±ïjkç^éöÂG£$¾çyméœSGhî•Qw3RöÃk6vww7ÒS·Iž£ÕÜrq{E]§¢Fí<GîÞäý[Âz¡hô€dýò¥sž§¶àê:5R_8l¼ÖhayŽšÒºSЧ–bÔ‹¯•ýB©:O׬-ìÖ3mé=="IŸçuŸçÖ?eTO­:ýås¿„×µ¾µQÓ]z(§>¯xy}®ºtz–+Íu›Ø4ie¿½…FI[ßèáºLßù±5ûà·Fsëï¾ÿWÿÊî§Õ/”ªV%×y¦©M“ÚÛ‰â=(™RÊnÛd}ž¿5šØ’Ùqä±h’V‹8Žo4 !à·F­Ÿ·ãyã\LšæB¿AQGø­Ñe¹¢&q Æy›=¡SšÑ(„€çµÍŽg¿£ø´«ø^“õÐ(„]DyÐíiö2…@£‹8꓈FwüÀ{Ðè"D Ô/ F£hœF— n ~ŒjdXm¯ÎQŸG Ñ%4·±Fª»‘îõ£Q4º„Yó"ËË?–’túE¤‹¾âÊÞì)4 !€F—ÌY\ºæP&Ëa¾ˆ´\`LÛÛ‰B Qûtûïbsé R¼È ¹=ù¡Q4jŸý«£?‘¶÷­F$J­-2@£hÔˆµNUúX»´l¢VeíœP4 !à¿FU÷õ»KdØ£(ïw¾0 ØÖÖ2>ˆ[0hÜ€FwØMdÅ‘õN)ÊeŸA³øT© Ð(„€ÿmvØ–CHut=¥¥w¨Ï‚#ü×èOºÃ žôàici” B Ñ=ZõJ”?VÛ™´%êc@£àˆ4ší0ÿ(:zuÔÒ¤-4 !€Fw™¤„­¾Ï–ÖÈ»ÎÆR&4 !‚F«”í¾é™xéѶvÖƒ¢Q4ZØš¾s`ú“Çw8F B„ Qsƒvê†G~#¥—VH-€F!‚Ðh¢[+åû9l:~û‹F£Ah4²´õÛÁŸÃ(×ßÞ{ B¡ÑŸÄNkVÂÎM›Pßî E£ahÔ¢¤°„æVOôwg-ˆúÄÐ(8ÎçÚòHÆßœµ êC£à4:ŸÃj´ìÎ’}uî—¨O ‚#Ðè|«Ñd·%U¢>14 Ž@£ói–Ï›*v˜òþŠÒkÏú,6Žì£Q4:Ÿfù0w·Z`6YýGZoë@£ht>ÉrZÛF~ëýÑnœhŠF!Ðè|Öl\jkù-lèÓݺ?…@£óIÊåU³ÌÒª-TTžn B QÇäû›¤ßoµèf¬íÊ·uîîóÃ`Ð(¸! &»4¯£t÷Cë»ñe®ÓÏ‘m<” B¤ÑÎõHöeŠt:þ³v*é6ˆF!Òè^ÇÌí=ÊTONw5õÑŽÜv …H£{3Wè}?ߢž¼ü SuÙY Q€4º[uTÉÝ`o†Gã-}»hB $FgﬦËÌÁ§Ô݇Ø6ˆF!BÒ¨¸SÅúÃÎyxOP-Ì…—ÆgnB¥ÑŸœêè Qœº{· Q°4Jut„Ìá±ËhB ,šêèþ;…„…L£Å–¹G‡Ýý~?D}bh˜Fê Ã)™()QŸG„¦ÑMˆ’Â!õ‰¡Qp]À¦u‘û°ó¼4 !€F°õ9¬¾/µ|ÆfxA£htŸÃ|ùÉ¢›Ùkýë4 !€FÐm{‹tãqË©u<ÿ‡#ûKÿÑ(„]@¹ñ¸áD;\04Ê¢“=ßœw¢VÖ£Ñ(„]Àæªý²V–3¥“‹º•}hB.`óõFTNH–õÆ6“Lç+»#Ð(„]ÀöʈÊá ö–n¹¬¦ÎJVîé‚F!ÂÔh¤VÉLmÿ ÔÇm’-²ürÂ{kÑ¢Q05Z­{¼“|û±Y¿|›êÉ^‡•„¢Q05u_Ÿzt#Óß;·¾[þÅNuæºZ…S£?õ~‡ÇW_[Rš­i‰Ot.¬ºF!Õ螇ÇçßdªVÝãx÷èÊs–Ñ(„@¨-¾;d¾Ùšw”Ž®ˆW}^hB Tîvh½|²Ñ™öjU稨‚#‚Õ莣L‡¤^Õ9ŠF!‚Õ螣LG$Š×t´¢Qp5ºç(“[š6Õ:Í%œŠFÁÙ9Ï[ ck´Ð^Þw¤´ÖqglÕLO» QpÅ9Ïcó?jCkôGÅ*lÖïÊäUôû[´zÝŒy« QpDŸç…És%Á£!kÔKúÍO~Ï|wÓWÐ(¸¡_ xÉóZÀÜE4ºˆ"±g¦ÈIe1Öê÷J»r[&‹ QpCûÈsµÃá<@£‹PN†¸"Þ²ëwí¶LA£à­£[žGû±htµÅ ^ãb“’F—wþn;;ª°'4:~äy¼»ÀÐè"›^¨tj½SÇžF ‡Š¢QpÂSžï/04º «Û3å:¶½ xjÔo ÖÆyÐhÜ õC£û±htÝÆÃAŸˆbûã®]ï›z ¢t{^ QpC9bÚ=ËÐè2ì~VYj}0½ÖéuÂÓæsŸªíCTû'ø04ê‰}™€e4hÔ° PÙÝÐÄ$ƒí RZV—wôæ™Ýs Y²¸&ŽFÁ}~[Êóí QSKç«lí™ÓåÙ®Z­Ó²´±H®yžÀ¿"OÐ(8¢_ôlò<ííí ýéU6ÄÜú\Le¸¾îëÒ—Ú>õÝ®¨‰£QpFsÎóX‚¼ÐèϲóÎÂ4 ç‹ÛŸõôS4•7tñ4Ê´âP4 ‰,åùfÐèÏyÄ|vS}å™oØ}áûÔ°ò½bÒ,…@£=Y:»½ºòˆÌ£Ò Þ…Ž—þ:…@£gªÙ“ƒ¢Ýw“ù*Ͱ!¿ÜChB^È,Ìô‚á§R.žˆŠF!Ðè•\ÀîœÒi' …@£7bû Ü}cù6hBÞX2\(Ë· D£hôN”S}ÏòOhBŠ!°¨í=h` 4*»Ú¦a¤à4*†ÈÃA.4 !€Fåà¡GÑ(„„E£ht ®y4°-ð{òU¢Q4:JÔêô͇­«›™F§+nB Ñ rý®áÞZ?ØN<¥ù<µ0SÐ(„â­Gëå§»ZwË÷mF£ht¥ßT9WN:2N4 ð &ÑÝdwທC“è²Y:í B Ñ7ÔÓ£õ™ÄIòŽ©¢Åû6£Q4º’o´ésiû” Q€Ш\ qû=¡Q€Ш`²O«R¿ JFÚ>Îh`4*ãÑNÐF%ÍÒE°hBÊæã.)_…y£# ÑYDí^.åѼ‚Fg‘ët¯íë>ì’òUX 0E”kï5Øc®-eåi³04 !€Fg’¤:Þ«qvÅ…@£sÉâýör(ªEõQ4 !€FgóÚ°oÊÃV×’/ÛhB ÑümØr:-¿ÅÂVÑ(„]BÖétxDýÊó2̲VÑ(„]DÔ>HT¬: èÐ,kÕ£Q4ºçºXx»7/kÕ£Q4º‰uçen`ÿM‹ZõhBn£ünu4Ù¿3vQ«B Ñm|¹:š¤ºÜ¹7vQ«B Ñ”ú«sò³TÇ;O²ZÒªG£ht=U?÷©ÑÝW/ší¹ãSÙ[qI«B ÑÕZ·Åùøö¯^6*õ—¯øàlÅ%­z4 !€F×S¥:U?Iºhy¤”Þi éz†H7ÿêhBn _eßíðÙ%zŸ#šŸ!‚F!Ðè&šÎ´ì¿o´,ÕÝM‹wmF£ht#Ê´ì¿ÝªïÙ£Y¯wÊ¢Q4º•¢Ý¥e¿G£~y¢ Q4º:Öû¯Ñüñâ}Ñ(„µA]á!4 !€Fa.Ѳ-›{Ð(„…¹4Ë¥ˆF!Ð(Ì¥^¾›…@£¶)ó/Ï謿Õ3[¡Q€1Ш%Ôu>|¡µn¿ùyfÏÇCÉB QK´·…’…Jµ.¿g¶¨Õ_?É$ªgf …@£–(Òû§õ"Mó¯Í‚ªô·÷ =Ø„F!Ш-Ô`ãѨŠMÛ¾S_ZjÔŸûüÕ¯0Òé¼D£hÔÝSÛºPÝ\×l§ßƒô« ûnæz&4 !€F­ÑèôÙ-ÍwWVú«‡4µz^ç/…@£öhoÇi‘&ÕÝ÷Ö¤ÎÝ2B Q{ F™ö¸züÅvýÜ1&4 !€F-¢Þo—ÇÕDe1«Tm¥=þèC¨•²ü•‰ª]sǘÐ(Ü0yžXîwj¬çydò|E£Ú¤›®výÐ}þšGuª{,n¡©s‰67“.Ês‘ñ#ÁfŽ1¡Q¸ÐŸa7Ï.yn³ ÖÏÁÖk¶F£6i´žL“:?'Rüüþlû¿QýÎ϶:6³XëR©Øâ˜S’ê4W}ü÷”mçå …3ªŸÿ§ÚÔÞ̼â’ç¥ÅIÓ ¯Uª[®f4j•÷mŒ"iÓç÷§2•Æ_ƒ©îu–¤›Jc_¤©æZzOg}%ât:õÕÜÛýÌ1&4 =•Iúkž§–¤gž˜¦/ÒTs-%Y‘ê²0y~2y¾°)‡F¿LfÞŸwASÁ`k€H_JÌÒ™³’>aB;]¨tÝ.ƒFa.FPõ5Ï[K)ѧâ¥Ä(]*½ JÝ^ó¼^*{4ú}¢{½S]ÞÑgéYzÈ»»˜+;°#ækzÊÛ¡v …Ù(ÝÞ’ÒHÏJu4ÖÉ­ÈdùvâcFÌ·…Ÿ^£NóÜŽÀ†Õ…=ZGƒ·´ž§ôJ-i4A£°…R–5šéxX]°1Íe¨ÑˆvÐØ™»ÛÇ{¢™;}Fɽç½Ã\Øg„FáçÇTγb›ôaæÂNç•y\îy^Ý:¯f‚F÷¤º«ÿ¾[µ„ö1jeiðߘùÖªÏÒ…ï}4 ?ý›ø6¬þ[YÚ÷¬}ŒZÙÚË"½7»¢¥“\Ðè®Ä:¿äW­-} ™¾½ùs[SQá³KSg±˜Ñ(ô”º¼äyck^‘Þò¼²5µÖ饾•Kó:!š™+Fz]ý6é·Ìk~£:¶%æ^öZe§¢J‹B‘^š¿™IN[» ÕýQ=¦þQjKb>/)ìó¼_´·PÌhÔ ñܯ¶_ºiyüu•þŠ•ÁS\Wé¯XFáÌuW›+àëy~[¥¯Ë¥Õ[4ê„ ªMu¬lž¥õ ÛÊæn:êt—/ë£Q¸’ä}žÛÜ7ªLž—Vó4 Ž@£nˆ¬m rhÐ(„uD£­,z;8hBºBéô{g#}Ÿ¦ó–@£hÔ¹×mfuZ Q4êŽö¾;§‡Ì[]F!Ш;¢XÇÞzÜ@£‰b›õóöÀA£hÔ%…·5™3g+4 !€Fa³váC£hV‘Ѩ¸‚Fa 1Ü@£° 4 pÂ*˜~pÂ**4 pÂ*æn‡F!ÐèwPÞ.gz …@£_!÷xYè;Ð(„ý Y¬c›ç„4 !€F¿C{½mÞhB~‰0=ŠF!Ðè·ˆrÚ:Pû0 Q4ú=òðŽgB£hô‹„çQ4 !€F¿I¢uµw _B Ñ¯’VE£hô»6yB Qp…@£°†¬œÕ;F!Ð(¬!™µÁ… @£°5oÊ…@£°†XÏZÙŠF!Ðènzç¼™JB£ht/TwàJæh‡F! Ðè^ÄG^Ñ4ï4 a€FwCiݵaßêy›U¡Q4ºuªÚ°ïô¼åXhBîHqÔ†}¡»y?ˆF!Ðè®´a_ëvÞ¢Q4º/ÇlØÏœ|F! ÐèÎô ûÃÕG“r¦úÑ(„ÝuÈîÑy Q4 A£h‚F!Ð(8B Qp…@£à4 !€F%užÚ£Q4*‰JëØ«ïB QQÔÖêp³ñ§A£hT‘Ò:uèæ!@£hTE©õܵ–âA£hTuªu>o?Ï=È«ù½hB ¤oÙÏÜùû:ÿÃhBФÈ%ùç ¥óù?ŒF!Ð(,£›wBý4 !€FaÍÜóCΠQ4 ‹Èg­|B Ñ iúSºhì B Qù˜v´˜ ù‰Ž—ü8…@£òi:-F¤­^…@£G éEªÌ$ž¿‡F!Ðè1èEªã뇅1÷€ú+hB…,OI— “; Öõ¢ŸG£hô@ÔíÞ­¬`êA£hôPD{·ê‚F!Ð(8B Ñã"iVþhB–H§m2: *ÉËR- ú@QµeY-Ÿq…FÁµ²çQbò\-¯Ÿ ÑÃRÄZ÷ÓIë?ý¥Ùùïµ.íÍ3­ÒK‘‹¸Ð(¸â–ç±½VY}Ëó¥ChôÀDIÞI ¾ÀºŸ_Ú4*Õ©­üʵnë¦6ÿ·h%èg4©îLžWNméK™ºGb“ç =ŠFNVµ½IïK4£Ô¼KO†¨],½ jÖ}‰'“¹ ë£hÜu:¿äy®;;óW­«sž›zîңĎĚAû©¥oDÐ=ÚHËNYœ$ÓÝ}XaÙ‰chÔ;#˜Qºl§úI#˜µN© ¨»ô¢ÎÒH}|Ïóå3RШ_˜¤*£ëä7K3Iuɯ*]:… ‚#Lz}R¥­ùÑ™¾N¹®—ÏF£ž‘¥:Uu’kÝÙZ ªú5§Mk½p»Q4 ®èó–¸úÚÍÑZõhtÖEÇ4ZŲ½ËèݵK»É RÙA£F]ãAF« ­Õnú—kk73 á‡FkUž'O\¿Šö©MpïÚ¹LjÌõ-˾¬Âüíûö‰¯¾´uZý ý±ÃóµרuLh4Se×§ð5Ï«§J[ßr9§öß<7‰Þ'jÝvoª Y:UCIþ6ö«Až[édz½v|°¹}^h´»«—±?órL<+¯_I}û±.»v6Ó‡nžf"Y^ª†Ý ½,uý¹v"l-,8b\£ùŸ<žšÛ·wìKžÿôY“ÅïZrÑyçxPý­äƒ<·Žc×n6åÉ ¦:.•Rí=¿ÊÁ·P\MÔOjïÌO™tº®ÙíßÞ}r¥åÛ7_>Q|ië_ oUÏŸŒlÊIަ˟k7–Zƒ#Æ5Úê®Ïóüžçjø8t—†Ëkž÷í+|z"×ÊËb¢x¢]þUZr~ÔâsžÿmÙ«éDo\[¬¾à…F³kճϕó7ž Z;×iIÍ}²o}[³Ûf´÷¡§˜zMu™Æc@µžäÝúá¿×F£0®Ñâožƒ>ÄkßÕ#Ï›ûÚtó/©NÕÔÊ ýÖ¢¯ýy3ÂO'úh]eâÚhÔ)šêÖîßÚuîp÷\v”4ýå‰ô¼G–5÷rmÍP}|bºçù µÒ^re$Ïωþfפ¾ªøf-h:^]°3Â4qíæ`SûüÒhqÓLu¯å%—ždøMå—Ü›eÑ|êgÆj†µÝ—èëµ5똂àƒFïyžÝ†•n}Wcy~NôOiÓÄS›GŒü²åêÂëµÖìòK£÷¯üÑù~]÷nÞÕusC];§‡|Ò¢£ß´ÝÅÀ#×F£aði“¤÷%㮩7–çýOžàuÃHÎ5–ÛÜ/×F£N™«Ñû°åmyn÷§£æúßVM[tô›.m.b»6 ƒÙ½OTïî}W/y>'Ñ.ý÷É»k=°¾wÈßk£Q§¼Ñh“(¥î_yqmíÜ6—Óãý°×»hƾéÏ%ÎgôÚh4 Þhô9Ï{oöЬõ££jL£sÒrâáÉ9«Õ…±k£Q§L|Ó— Ç®_y~K¼mÛ=öµ|úª¢VÇÓó#ßt£­íÛ=qm4Éókß~ý‹Ñߛ餉‹ŽäœÍêÂèµÑ¨SÆ5ÚÏßUÝ ¿òKkþö’¾µyþöîZý©··ÓÔµ©ƒq£åù%³£?mûg¶iôu¤>³¿äýU£ŒÔ»cT£õcâÙ ½Î›„ä·¬ÊG&º½Ï®G'¿¾¥ÛÉžÔ…óF§®}´—4¬dÔhãy~žÂy?Ns,Ïçj´·ãë¼Ñ7Õ…7óFßvü¹6óF2ªÑÁx^ç­¼ÒÛ?¯½ÿðô•>@ÿªÑn²®¸lÓäµÑh Œjt<ÏÏ'Àµ·ìËó7‰>½C΂ULï®F2ªÑGOM1T[¬»æñ,Ÿ¾§ÉþÒûÄÛç¯Û-Y’ÜôµYS£Ès£œâaºç¾£Û/N\'¬ê¯9¶’éeMýèá9ËywmÖÔ;eª6z9A³ˆ‡éeœ“?Z ç]d®ßT}ÞÚéõfXôu‡§æš ѶQÌ7×f‡§@˜ªŽåyÑçù]B#yþN£&‡/?|>iT]/;<ýÜf'mÛ„éݵÙáÉ)ú²íƒþ/ûéi®T9ÁüéÓ.|9×Í.?öI£»xfí7Úk4îËßVc|smö „>GŸò¼÷ÍTžç&Ï)÷šço=ê·óéòëéœã¯è×±Ô>¥Út[Ûëݵ5ûºä¥ßºÿËè.ž<þ³sØp^ÆãTl]NO¿Î¬Ýïû¥Sg¶µGÞ\;e > ʱ$˜Êóæyüæ%Ïßv6%÷ ûéTÚ¾ Õß.°uvßäµÙýÞ-£ý‰T?Ð×VE¿‡×ã-ý}Ç5y×o‹§†ûλÎhWÐˈÒyBJžl|N_›³˜BaT£SyÞ<ýöŸ<ÿÐg_çç­H«ÉÕ—¥ì†…7úĵ×yu0.¢p\wûúqÚœ ctn»zj{«JfÂÉ ‚PއµÌB~çÔÃõÈ'«¤_î©äœzI¤®GûìLü˜Íñ² ¾Aëºòíf××›y›ñX£‰óŽÄæ»lu°Y ð\÷]ÇN¿ùþ6—s\½¶Ž¿:÷¯´ò›­/'3„Öý’Œï¾ÀWõT£ªnšXwÎ_iÙ7W)zFá™$išü “à¢î‹õÃ(ýöˆÖvüÔh<=KÉ.Õ÷†3†éáÊÂ4åYd_¬ ¶ïΊŸUýίTÝò©Ó½­óq«Ž~þz÷•umÉ×ê ÉGüÔè÷ø¼”%¾çk€Wò/Õ³#ZnåKMØÒŸøŽG3ç³€F6F6F6F6F6F6F6F6F6F6F6F6F6F6ñÀrv÷S{à/ÿÐîszT¹÷Gþò7nˆEi´Úûã?ÉF¿w´%„F)J£rb¯Ph"I]’b¯@£àIê’ x—HR—¤XÀ+Ð(¸D’º$Å^FÁ%’Ô%)ð 4 .‘¤.I±€W Qp‰$uIм‚K$©KR,àh\"I]’b¯@£àIê’ x—HR—¤XÀ+Ð(¸D’º$Å^FÁ%’Ô%)ð 4 .‘¤.I±€W Qp‰$uIм‚K$©KR,àk5Z$*)솒UªÞûãËHRךX"7yíýY€UÖi´¸kSZL°:=©H0¯8¶F¯y[<–¯éÎE¶ä¹O¬Òh’ê´U­ùßÄV­ÖR&k;9'IÂv­ÑKžçF|ÊV Êdx®L¶§r>ØÌfZçÑïïo”kmIzJ§•)ñ7‹uÇ{Ú#ެÑ"5•Æ>Ïû,u7UÆÈ}ž›jnJžûà Fñ% Ê’ôŒ˜›k‘±½7?ìÏ‘5Zêöš”•%é1××"Má{`­u÷{£³óšÎïbþ5FÝû3{X£™qçï]zVº¯Ô]̿ƨTG½a…F•®î­ìÔ;]Ü‹”t²9låÀ­ïößÄNÝ1¾7º~[;f ¬Ðh9È…ÆÎ¤S­ï%þ*AlåÀU÷¸©;ºÈsz¯¼a…FÛAzÕvÞÒÃôÊ=x°•CkôÑêÊìh4´ºÐ¨G¬Ðh¥óA.T6¢(f6©¶÷‡Ö8°FëGG¦-çå:t^1µÏVh4Ó:{ŒYÉ…JÇ„íöþLÀÖhô˜>R¤vn#yŒZU:Ýûók¬™7ªt|i›¶f'EÝe&jßK 蹃ÍX£&Ï»K}!ŠmÍN*/3Q›ÔÖTTÀé¥Uñ[T©µ¹ò¦ZÛÕÑoÖZ\08²FÍ/heò¼_Ìd)ÏMµ¶KLž+Í´QŸXµ4jµ¶¼28‹/%¦VúZA ‡Öh¿|ÉòæÅ5Ï©-xÅÊžê¼Ó]nµYR7ÇŠá%¿8´F~“çiku‚gÕš©bxÉ+Øo\rpÌ‚K$©KR,àh\"I]’b¯@£àIê’ x—HR—¤XÀ+Ð(¸D’º$Å^FÁ%’Ô%)ð 4 .‘¤.I±€W Qp‰$uIм‚K$©KR,àh\"I]’b¯@£àIê’ x—HR—¤XÀ+Ð(¸D’º$Å^FÁ%’Ô%)ð 4 .‘¤.I±€W Qp‰$uIм‚K$©KR,àh\"I]’b¯@£àIê’ x—HR—¤XÀ+Ð(¸D’º$Å^FÁ%’Ô%)ð 4 .‘¤.I±€W Qp‰$uIм‚K$©KR,àh\"I]’b¯@£àIê’ x—HR—¤XÀ+Ð(¸D’º$Å^FÁ%’Ô%)ð 4 .‘¤.I±€W Qp‰$uIм‚K$©KR,àh\"I]’b¯@£àIê’ x—HR—¤XÀ+Ð(¸D’º$Å^FÁ%’Ô%)ð 4 .‘¤.I±€W Qp‰$uIм‚K$©KR,àh\"I]’b¯@£àIê’ x—HR—¤XÀ+Ð(¸D’º$Å^FÁ%’Ô%)ð 4 .‘¤.I±€W Qp‰$uIм‚K$©KR,àh\"I]’b¯@£àIê’ x—HR—¤XÀ+Ð(¸D’º$Å^FÁ%’Ô%)ð 4 .‘¤.I±€W Qp‰$uIм‚K$©KR,àh\"I]’b¯@£àIê’ x—HR—¤XÀ+Ð(¸D’º$Å^FÁ%’Ô%)ð 4 .‘¤.I±€W Qp‰$uIм‚K$©KR,àh\"I]’b¯@£àIê’ xÅJU[¶Ua3’L•e^GKŒê¼,Uf3HXˆ$u­ˆ¥HÜäyb3ÏjS¤ªm–ËX§Ñ*Õ=ie-ލ=—¨;{O]_Šl­¦,,âØM.y®•µ"u)1µg½[ž—VmKX¥Q£¼¶nêþÿ,…Q¤:UMS™ŒH,™hWM£LÉä×nZ£¹Ið¤©ÍÿÅ–Bˆ:ãäºIJ­mUAS÷¸æ9 ¯½X£ÑʼK{êÔV2”:.N=Ê–ôŒ˜Õ¹Ä"¦ów?ެÑú–çMj«>Úê8;ge¥µéE©Î£¾DÓžëhwíÄ A]²ËxÔ’ôžSÁÐZ’^«Ûk‰&ÑlÕpa)GÖ¨©$\óÜÔø¬äycž—kV*K5Ü\—×O±ÅÎXÄ &ºý½ÑÚ1”)æôžwj¤õM̧šêènX£µŽïyžÛ1T~m!õtvª£©¾‰ùÔèÎÅÇŸY¡Ñ\'÷ôJtn#ŠôáY)²Òit3]F»±¿º$Å¥7éE±¥<¯ušÝż÷ý‹ ö+1ÎõѦ³6ª^ê´¾¼£™ï´û«KT,u¿|é’ç¥ÉÌ­NÏÃÿUJžï†ök1Ò¶_\ÚšB•ýBã6Å¢{"@]¢béW(·ý²úØV )jû<ï·hYe²R4úÓô ugSyU×ïÿìŒu‰Š¥_œlª 6ó¼>çyÇ’çý£QóZmÛ}˜YÓð†Þê’‹ƒ/޲·„×HR—¤XÀ+¼Ôhß]Ô ¦zö'3mœ˜µú²íÍu&Hkq_2Ÿ‘¤.I±€Wø©ÑŸ"6Òú\#-ª~àq»òúqKuqs£R«»äzŒ$uIмÂSžÏÕ:.ËþhùÎÊãÓ×@M´,SÆ0g#I]’b¯ðV£?EÕžg‚tyb«õO¨ïGEyg"I]’b¯ðW£=þ·í£¾þ©ÿIŸè|$©KR,à~kôÇþ½m8‹$D$©KR,àht!ht’Ô%)ð 4º4ºIê’ x]]„$uIм..B’º$Å^F‚F!I]’b¯@£ A£‹¤.I±€W Ñ… ÑEHR—¤XÀ+ÐèBÐè"$©KR,àht!ht’Ô%)ð 4º4ºIê’ x]]„$uIм..B’º$Å^F‚F!I]’b¯@£ A£‹¤.I±€W Ñ… ÑEHR—¤XÀ+ÐèBÐè"$©KR,àht!ht’Ô%)ð 4º4ºIê’ x]]„$uIм..B’º$Å^F‚F!I]’b¯@£ A£‹¤.I±€W Ñ… ÑEHR—¤XÀ+ÐèBÐè"$©KR,àht!ht’Ô%)ð 4º4ºIê’ x]]„$uIм..B’º$Å^F‚F!I]’b¯@£ A£‹¤.I±€W Ñ… ÑEHR—¤XÀ+ÐèBÐè"$©KR,àht!ht’Ô%)ð 4º4ºIê’ x]]„$uIм..B’º$Å^F‚F!I]’b¯@£ A£‹¤.I±€W Ñ… ÑEHR—¤XÀ+ÐèBÐè"$©KR,àht!ht’Ô%)ð 4º4ºIê’ x]]„$uIм..B’º$Å^F‚F!I]’b¯@£ A£‹¤.I±€W Ñ… ÑEHR—¤XÀ+ÐèBÐè"$©KR,àht!ht’Ô%)ð 4º4ºIê’ x]]„$uIм..B’º$Å^F‚F!I]’b¯@£ A£‹¤.I±€Wx¬Ñ¢jS­»¼Ž¬Ù¨Rk+{cT«Në´­²=>"÷HR—¤XÀ+¼Õhë;­‘Vé½Ä´²Rb¤Av^>ã’Ô%)ð _5ªúzhNY_'Mëí%å¹z:e]Û‹lLEÔÔCO§¨ÎÍ•½j³$©KR,à~j´¯Š*ãÐ ½7WH“^Æ·OMº½BÚWEãì^¤ò²B*I]’b¯ðR£QjŒt`šão²îM<(1jµÞèQS‚iÜŸZ¨âÊB’º$Å^á¥FËgåõÒt›ôŒ˜«çOÉFéÕ:ÍþÙúøUÈQ—¤XÀ+|Ôh¥Ó?=êmÒ3‚û[âFéˆùuÞͦ’¤.I±X¥Qeiqöˆ!Jò²­¬¶Šª-mΚ…‡55ÏúdWzcbÞ(½11Ÿ­=›ø$I]’b±HßõßSÚST}“bñ¥®|žâ£Fsݾ êdjë‡ëGÅÜKou‰Í˜˜ûq¦vïÏ.’Ô%){ô£ªi”ù?[¯`£¼²jê\ëØR‰Q¬u^7U¹yDA&j´ÓÙˆ NÕúwk¦»±OžKõ<¼t—½N÷þøì"I]’b±†i]¢Ö–ôLõàÒßd m©>ªnc¾ÆÐ~ j´˜pžqáÚ"«qç6, u3ZdìY«^’º$Åb ¥cÛ=ëÝ=Ý3KL}gÕý™Yý Æ?&:Ô©Ók»ÌÛÑ6}ߪ_ûþ´Ò·%û’Ô%)k¤¶×út|¢ÔC,¥ã°íÕyVQ¸Þ oU:7T©ÿ©Öñ/©õÊÿ96ÀÔS{ömHR—¤XlñÔß”®®( :¯±“Ž¥.3ñ°wÔGŽ7—O¥^Ïx‰§ %NhÔRÞŠA’º$Åb‹f˜HvnP Û^¶4êo{댥6*Iê’‹-¨ŠÀ?Nö®O²¯öú•d’Ô%)ktÖûF‡fέ÷Fô‚B§£‚’5R_2Rt,Öp:Rßh+õÛç‘z[sQ%áŸF¿8o4¶>o´`Þh±Xã>o´(-ν$§›y£~Õn÷çFÕh¿ã¦ULÝëú÷Óyþê3#E¶¬b #{\V1Õ–W1ÅU“äÚšΫ˜’¦êXÅtÆ6ýظ¦¾“^´iרÑ5õ7Pˆ$uIŠÅ"·5õ–Îxèé÷ﱨ<ÖÔ1éc‡§Ûù D’º$Åb•L•¥Ýü¢Z•ybw‡§¤-;<#¸?3”²ÿܼßèß¾LûûFì7L,à^jôe÷û¾E‘l*²îO_zVžíÝïMKÊ·&½,uIмÂKþ/g1ý¯ÍíO_zôX?‹éò_{pÖ‘¤.I±€Wø©ÑsvÚ&E2hyîØÎ·z´¯vª6r®mž Z*cÒ"ÉS«›äŠA’º$Å^á«F²Áú¼ïØÞìÑûžànΩ÷°*ú#K]’b¯ðV£ýÐ`_ŋÛ=ús®ÚöH{Qž«¶ÿ¥µ;**Iê’ x…Ç}Á‚GÏËlÇåóã-éÞ$Å^’F­xöÞ$Å^”FmxöÞ$Å^–F-xöÞ$Å^˜F·{öÞ$Å^šF7{öÞ$Å^œF·zöÞ$Å^žF7zöÞ$Å^ F·yöÞ$Å^¢F7yöÞ$Å^¤F·xöÞ$Å^¦F7xöÞ$Å^¨F×{öÞ$Å^ªFW{öÞ$Å^¬F×zöÞ$Å^®FWzöÞ$Å^°F×yöÞ$Å^²FWyöÞ$Å^´F×xöÞ$Å^¶FWxöÞ$Å^¸F—{öÞ$Å^ºF{öÞ$Å^¼F—zöÞ$Å^FzöÞ$Å^FzöÞ$Å^F–yöÞ$Å^F{xöÞ$Å^FÏÌ÷(=ì½Iм^˜íQ4zØ{“ x½2×£hô°÷&)ð 4zc¦GÑèaïMR,àhôÎ<¢ÑÃÞ›¤XÀ+ÐèƒYE£‡½7I±€W Ñs<ŠF{o’b¯@£CfxöÞ$Å^FŸøìQ4zØ{“ x}æ£GÑèaïMR,àhôŸ<ŠF{o’b¯@£ùàQ4zØ{“ x}á½GÑèaïMR,àhô•·E£‡½7I±€W ÑÞyöÞ$Å^FÇxãQ4zØ{“ xeÚ£hô°÷&)ð 4:ΤGÑèaïMR,àht‚)¢ÑÃÞ›¤XÀ+ÐèE£‡½7I±€W ÑIÆ=ŠF{o’b¯@£ÓŒzöÞ$Å^Fß0æQ4zØ{“ x}LjGÑèaïMR,àhô-¯E£‡½7I±€W Ñ÷¼xöÞ$Å^F?ð×£hô°÷&)ð 4ú‰?E£‡½7I±€W Ñå’Ô%)ð 4:‹¼¯.¶ÑéFÔš éÆÚcfª¢ê^â)‹µýѫݑ¤.I±€W Ñyü/ýŸõiHêvS‰Q§ãì©HS!µÕç*Iê’ xE£õ³òN§"Ý&=¥ã?%ž*úÖ?*I]’b¯@£s05Gu²+½1ŸN寮<$©KR,©ÛTër{÷ÿ€ªÔ:m=ýÐèFjŽ¥7*æÍ5\yHR—¤XDÓ÷üŸ‰­ÍÂËâk‘^ÎGA£³«9ž¥dVÝõ9IDAT·:'êQ1›®g_†$uIŠE4±N«âtª;ZZjb•®6OŒÒ¾%ø4:ƒF—cÎ;µÓÇÙ"×Õh‘z½™E"I]’b‘ŒÒ]q›bÉ ±Î/Ó\²T[í*k€ŸëŽùÚ"»ÑúmßQàW«^’º$Å"˜Hëæ6¯ÏR'S¢»ÛdÁZ§{ß Ðè Ê çº[Y¢ùÍÑ™ýš;*I]’bL­[…!¹NîEÆžUΠÑ”zÜy¦ ^®ãßݧƳoC’º$Å"5èoÊì¤c©‹{‘¶HÛ4:ƒ7]  :Á¨AÕ1²¥ÑÏðe:$ZÝϓԟN‰V”$©KR,‚1)8HG+™KýX¸a\V.htî!õú$Kïç!¹gI&I]’bL¡Ó{­¡´3®^=_Eª-ï×+4:ƒdÐéþì¼ÕIÖN˜Ù·$“¤.I±H¦½KÏÖêä(½÷·ú·P¯ÎÀ4ÞGëŽ^½Ê£´œžºF׎ý E’º$Å"#½¸¯FööÊ©ûåK§ó6fÞmуFçPŽNUœW<&ç ‰}ë—¤.I±ˆ¦ßÂ1Vý²zkSåU¿ ¾?<¢óò”4:‡lLzý_®/R=f$?‰Ù³wµ$uIŠE6}=´ŸMbQyYéñ’z4:éEkŽåk‡ë61‹D’º$Å"ž¦i,/2Eî}W®@£ó(/ÝE‹¶:ÞTb‘þí)h:ßšô²Ô%)ð 4:#½t8¶^›ÿÞØäIôóö÷ýÉL{ߦu$©KR,àht&ýŒíÍzEkãlÐþ\Puß²ÁË£˜D©KR,àht6¦ª»’5ÍÞ½EW$©KR,°ž(ÕÕï*F;†„Fý£JûñËNÄLIê’ ¬§Õåï ¥nw úFT…ª¼ë»öŽE–º$Å«1MúâU£Å®Íz4êåµãÈÔIÕÞ±ÈR—¤X`5ùk“þÒ¬ßq” zFßItÉ«L І$uIŠVÓébL£…îö‹ zF§ïƒ˜j×î¢ ’Ô%)XK¦»ßQ:íõ‹bd‘N÷G”º$Åk1÷qšÆþnA¡Q¿h†£˜±Þ;Qê’ ¬Ei5®QµãXõ‹'vhTj,°4 Î1 ù{^e{vº_‘¤.I±ÀZÝŽk´Õûíô„F=#~¼¬K3ž$©KR,°–aEá‰Tï7OzF£uskäìº>î‚$uIŠVëlÌ¢™Ž÷‹ ú†ÒZ™<ËJ½ïn $©KR,°5>TŸïÙöB£ÞQ]7OXT”º$Å«)îí­!¦¶ãnWñ~£¤¯@* ÕÇ$í«¶ÙïoÖW Ód{‰‘ê«¶It:+Îq¶ä—Ñ(¸D’º$ŽŸŒC¯( Ò¨Õºn%^þkc‘}UTnœÿkÑ-¢Qp‡$uIŠ% T_ÿü}Ð×MUõ^‰uZJü­So+1ë럧}ÝtGÑ(¸D’º$ÅÖÍï3ùFé)Ï%ñÒÞÌ?Ä:?=Óǽ "4º/EՖˇßÒ¨²­6¾ðŸ‰ê¼Ì“=ù’Ô%)–`ˆ:­þXô7Ú&=#¸ìo‘Ùé½bÄýÑèIénvOÝ—è:†¹¬Gû-·1ÌÍÝEL£©'­ÿ¦$uIŠ%Œ ~­JoLÌ}—ë|é½Ð‹ùôÂÙ£Ñ]1)¡óºQæÿ, 6ž1ÊKUS«Tw¶æèÕ—U“=·KU’º$Å ÅHÍñ,½õÒ©ÆÄüûëå/ùå`té‘ýÜ'îJkª¡çfŽÒ©éEéu ³ˆm}±µ©†žóÊziªJR—¤XB!Ñù˜ó~µ^]wlu=Vb½ü#Òú4F>»nƒF÷ÄêÖWÞZúr]Þz RK5\#Ïk^Õ‹e/I]’b …V'£-u½¶Hcà±£õ CG5šÌ63Ý“\W¿éYéËLõ}3±óÍÖ:¾'V»´:*I]’b …A:>Q­djÆÛô}«~í׫îõ„g Î.îÇ0ÉZ+uǧ$³³qƒt-n9IR—¤XBaÊyþ—ZÇŒ 0]ú[ÿce‘ÿÒͨFOñÜî‰ÖÃ,Ø6óíBsoÓŸ[N6‚Tƒ$k–&‹$uIŠ%†éø¬ÑõLjt=ý¡Ñ=9Hm´¢6 ë 6 Îyîµ2T¯f®í÷æôÂÒññ M}£Üõ_/}£Çf0RŸÛ©ï6̤=Fê›ù3é®HR—¤XBaj¤¾e¤¬q›7úksÞh~™7ZnÝ®áÆ}Þh“.®CHR—¤XBy£àž~“ª›*¶¸ŠIëN5Jm‰¹¯áê2i’þÿ–þª$uIŠ%&W1­Å;XųŠéØÜÖÔ[Ú¼§ßˆŒ5õÂc ÖÔÃ7Ȫ²TÏ“1ÔÊiw‡§$/[vx‚ÅŒJOâO/e‡'‚$uIŠ%F÷ÝPsü¹lk÷g|iã~£½ìÿX”ýFA ’Ô%)–€P&Ì÷9nû"Œô^v¿ß&æ^öe1(»ßƒ $©KR,!¡ôm>JO•nèMü|ÓæÃA›ô6å<ºsÈA’º$Ž”JeLÕýκ6Æ>«þdФ0uÛ¤?ÔÂé^Ʊª#ãPUr2(HB’º$ÅÑ`½{ºzÞýΩ¿ÎGáœz†$uIŠ%8êþðw]Z<"¬Hrã½tÕadU/gS']ú‹h\"I]’b+ØÙ|gÈâ=ÌΠQp‰$uIЬ€F!$©KR,`4 ! I]’b+ QIê’ XBHR—¤XÀ hB@’º$ÅV@£’Ô%)°…¤.I±€Ð(„€$uIЬ€F!$©KR,`4 ! I]’b+ QIê’ XBHR—¤XÀ hB@’º$ÅV@£’Ô%)°…¤.I±€Ð(„€$uIЬ€F!$©KR,`4 ! I]’b+ QIê’ XBHR—¤XÀ hB@’º$ÅV@£’Ô%)°…¤.I±€Ð(„€$uIЬ€F!$©KR,`4 ! I]’b+ QIê’ XBHR—¤XÀ hB@’º$ÅV@£’Ô%)°…¤.I±€Ð(„€$uIЬ€F!$©KR,`4 ! I]’b+ QIê’ XBHR—¤XÀ hB@’º$ÅV@£’Ô%)°…¤.I±€Ð(„€$uIЬ€F!$©KR,`4 ! I]’b+ QIê’ XBHR—¤XÀ hB@’º$ÅV@£’Ô%)°…¤.I±€Ð(„€$uIЬ€F!$©KR,`4 ! I]’b+ QIê’ XBHR—¤XÀ hB@’º$ÅV@£’Ô%)°A¦uf¹Èÿ©ÿ],ÿ-4 .‘¤.I±ÀVŠ$Oµ!Í“Þ%Se_¢ŽU½ð7Ñ(¸D’º$ÅIz‡Æe÷&Ml”©^¡eYžK^VËE£àIê’ l"jµn“âd(’þÏÑæ"›NkU÷%ž²ªÿó’_F£àIê’ l¡Nuz1Þ™ón,Rõ5Ð{‰}Í4^ÐW€FÁ%’Ô%)Ø@‘ê²8 (Jnë ­LõsXâÉTNx‚K$©KR,°R·§?´Û,fÄ\ÿ)1Ju5û÷Ѩ*îG·w=¨sÓnjWôäKR—¤X`=•N£Óé½2"æS½ †‹F½£:ÏѺ³&¾CÿL¹¸å$I]’bÕŒÔJï…11/ªá¢QßPZ·ÙéÔ”Zoív¿ë´*NQbj¤K«¸’Ô%)X©9ž¥·hlý‰nύ›=¹zF¦urɵ\zã(Ý]:ô£X· W’º$Å«‰u3¦ÑFÇkK,t7V¢y‚æšzFùq,7¼Ÿúž·¦=µpñ$uIŠÖétÔy§T¯­5$:-±ž­F4ê‘Ö÷^žLw6Š&Ùü÷óIê’ ¬¥oÓ÷­úµXí­÷—Ù;Ÿ Q¿ht9|?Û(R ’lñþ7’Ô%)X‹ú3ÁsðŠÿW¹Žÿ6ÞMзçf…F}âI£±%Öh¤ðF£ëA£0dØ[éÔF‘ü5 üe¿,I]’bµTÓý¯Í:þ=¥ÑÙÍ94êÝ#%ÔâqõQ²Á¤ºX/œ‚/I]’bµdÃê§ùÓ“þ2UÁ?¸€F=ã1“8Ó–´ñXâ¡t·p4T’º$Å«ét1æ¼bý€j£ãQVLx –Rwçúh•Ú™ïtÙ ¢Ws¿íÍRIR—¤X`5ùø¸úâþ¦鸙ËÙcÿhÔ7Šó‚ú¼³² ã…:5…©ÖüïâUõ’Ô%)XM¿ìs¤2šnX´—fïÔóׯ QÿPçEõ­¥ ?÷EõåòÎ'Iê’ ¬§“^¹e  ßØä¥Dó—³k hÔG2UY>ê+ªU²¦r+I]’bõŒI¯Ú¶òy¬†»DÌh\"I]’b ÔO{ߟÛß[šô=­Žÿx4_"f4 .‘¤.I±Àò¾ãÐünõ†ñ¥3¦†›«¸Y¼hƒ44 .‘¤.I±À&*c½ûx}¿ã–=›Ïô*.o‡1bZÒ-†FÁ%’Ô%)ØFÑŸ(ßVMSµ«¶¡ŸÒåIÓô‡Gèe‡G Qp‰$uIж’Ä·ñ±•cêM…´Ÿ%x&mf —HR—¤X`;Q­ µÍ3ÇŠ¤/ryš Qp‰$uIм‚K$©KR,àh\"I]’b¯@£àIê’ x—HR—¤XÀ+Ð(¸D’º$Å^ÑkÀrÔ…FÁhÜ"G]ha4ºw_‚#Ð(„G Q4 Ž@£ hF!J—èÐ(B¹÷¤ð—ÿÇ×nW›®ï%tEXtdate:create2016-11-10T23:04:35+01:00 ï2*%tEXtdate:modify2016-11-10T23:04:35+01:00}²Š–tEXtpdf:VersionPDF-1.5 \ 9IEND®B`‚leidenalg-0.8.9/doc/source/figures/layers_separate.synctex.gz000066400000000000000000000113601420514302700244050ustar00rootroot00000000000000‹í]]ãÆ±}ׯ°<Ì;+vó{Þ‚À$p|h%Jû’¨Ôd'÷¿ß¦H‰Õ¬Óuk<º@Œ5<Ò9¬S,²ŠÕl~èϯûåÅ_¾ù©¨›²Ú?‰Ùï÷‡cû$žæ»bU.æ/m½Xlæ?þðÛŸ¾ûþûï~˜7õr¾­Ž/‹rÿXnêÅáy¾ª–ó¦:ÖËb¾.7ǺhæŸæÛÅ«Òü{Sõ¢->µÅ×A[>ÍM­D–‹í\ÁÛò¥˜Ë@ÄÝ—ÝúqU6m÷QItÿoÚÅ~µØVû‚|ü´Ü6ƒ\x­Ü¦Øu¹œWŸ‹zU_æåz{ì\|jÚ×A,ºAì°Z¥ØU©\-ºïÃ_"•¸m°¯_Š×µäð—¥®ë4•wbæ/õrlËmC´r_-¶V"x“ÜZoÎzÂMïó¢)拺-—[š¢Â1åO2Mù¯BJ¥:«\é½Êa³ž¯ëjßûÕ©çmùå_$ÄÕÙ> ªUSÁÔÔW*vuÂb]"”m©Žê[½l¨ÜÕIN &Ø}y\V»]µ§)â\6áÇ­Zšæ²p. ,ÚHŸVÅú¬{u‘ô›w×Ì‹—¢~mžK²UåÕõa\»n7-«•v@w¬žG˪.èj:ÖË© •Ëæü<¥cÕLµhRJÇ‚¹hµu¹¡:޵rúÿ²Ú«î:®Öx”’Ž B5*õçQ%×ð‘ä™t.±î×ÿ\ÔE]ÓHËá"·m¿.w+mó;Ö@—gÍkÓ»K¢©¯D0ô* 9)ˆðê‚0–™jm\öê²°Ê®Ëm[ÔÅŠÉ;¤ÀÖ i:¦ðÖ}dI:® ÊÃA¼¹u¯ÖÃÕ›jÝí3ÛÎ^ˆëꪭ–Õ–é_]sÃxQiTõð‡V‡c¹Ñ£T¯5æBäUi ILb¼*m§öJ÷aöNäUdTQÙ-™ªWmQÕ®Œ™ªW…QUurÖ5Óõª/ª»>î—­:¡dǰȫ¸°ô)=˜¯êº¶]í«]¡>pG^#=ì¨VçÕŽyp>1²í†Ú×e£ÆÂ/±Wi÷+Ñøæ%Û©:îYߊo®ØÑÁ®lØŽŽo®ÝQ¿Tgc›¢V{¢}ViUòÁt|sM¯·Õ¢e²^%ÍÀ‡J…ÀWÚ«ªzwøTÛ©­K‚Wec'Çf±á™êUÑÜA³¬ßF^ÕÌÕÏ'm7«6ñ‘¼Q›mÕ©YWµJ'tO¼Jš»ùDZ\~aâ^åÌÅ«Ïÿ],yª&^ÕŒ³HÀ–EÓ”û óâUÅÜË¢®«òÞ¨˜›çÅŠçÐÕr¹%–¼Q _Õ)Ì~ÁFDÉ•p?{ÍÔߨ„Oå¥Úq±_¾N}¤oTÂ*?»MÄbHýÚqµ:nûSÈáãóãR¿V<?l+vôO=f?Oƒž¶üÜ¿öfwx|é¯u<IL'Ç=fCíģȨƒ[gH×ÚéYê:마Þí£hÒ"u<eçgd oOW.»}>´Û)SÕ7?)ͼêŠOþ÷W¦â^q[~ýF迼vuû¬Ne¶àØ™ùk§‡µuêò+÷jˆ`ûŒQu_‡°Úªkö<"ÇlÔAÿ´“ÏHjgW_¯Õ­Ýc¸ê68ýLëîtÍ©\·ÏÅžªx•ܵÍ”ä^%y­Ç=æ^Åz­?<~˽ÊUœA?|óË÷‹ãEüêB^vÛèk;\Î<§‰ÖÝ—²ûp­§q±G1.hë0ežÌ‡ÙÏбE$†ßb± [ì—qFY’Å’y9ã‘ Ã48ï.+Ù)†SîWôߢѻ¢ CJv¸‰ÃjÔ¿SnA? ¥‰eñÃÕ?a€üptôcäÜÕÞÖ¿û`‰wä\†&Î]­·"qN,&¨æß£ñNý;J4-6#ç®v…Ìe…)ô=g‹wäøqç¡ÄŸ‰sWë-P^Œ(ׇ£ñšó‚Jü™8wµÞ"K“P„ƒäѺS4Ö‰¯‘ŠáŠ3”x3qîj½J‰‰Tc–TóïÎÑxÍ)["G‰?KKtTë-@J\@­;Ec5¥D÷½9wµÞB ¼Ó(Ì&g4QgºwŽÆ;õ7rðèÍQâÏÒ Õz‹(Í¥Hò‰Ååñúp4Þ©¿‘ƒÇ{Ž–^à¨Ö[ ¼Ñ$‹"•ëšwŽÆkÎ x¼ç(ñgéŽj½Ê‹åñúp4^s^Àƒ>G‰?KCpT#yŽ,r¯ÇâÍѶ€}Ž–†à¨Ö[ ¼Ñ8ó J5ÿîלð̣ğåÌÏQXLòbDy¼>‹åE üý9wµÞ"Kƒ,ÉÄ⌠$qD‡ž$ yêräàÁŸ£Ä¡¥18ªõiÈ4N&gDìGÒ§.Gÿ9JZzƒ£Zo²cDE&È3m|H²9;` à(qhiŽj½ÊŽû‘4dsvÀ.ÀQâÐÒ!Õz‹Ó8(K'gDìGÒ§.G6އ–&á¨Ö[ ìÑ<Š#u®ùwçh¼ÆÔHàDò;£pzùQ^ãïòÂ2£<ëÞÍþ ùýQ~ë(¬¬wFae½3 +ëQX±ïŒÂŠ}_4ƒ{(ƒÛ  ûž‘sññVëÓ[H)ò<&g4 2§Z×S±ˆ¢8‹>F¹ˆeðQ$a³¯ý¢Y–gi2,:€¡HÃ,™‚‰1GÙâTæa ô%£îŒ<“ú’QÆê?}É4L¢8ŒÎàed¶ÇÈÁœÍpýR(ï'%{ÅÄaµs¬¼g< ”ø1qXmð“ÃSzŽŽ~Œœ»Zo¡R3Œ¤~!ÀÚøHÌÌçH“zŽ–~GµÞB„¹ÌML¦°¶>$™ùIxZÏQâÑrÊï¨Ö[À !0»2éIÒ˜-ò%- ÀQ­·€B`³Ic¶d<µç(ñh9íwTë-„Ld˜FÑÄäó˜ýH3ó9’ð䞣ģåÄßQ­·€B`våÖ“¤1[2vMŽ–®é¨Ö[À !0Ù¤1[2žþç¡Ý}Ï¿ÂS<棙ôlDšEQ–S£ Î.ô{³—€~ ‡¦^-ƒ gÁÁF$q˜'A05ºà xOV žù%,H˜zµ 3œœ5g—¾½Y-x[ÖÀ!€©WË€ÃYp°ÁYCp¼'«oË8¸0õjz8 6§ávŠ©ÑÁ{²ZðÌ/aá0ÀÔ«eâ,8Øà¬!8»gÀ›Õ‚·e œ0õj™ŸplpÖïÉjÁ[²Fà†ÂaâÕHú62ˆâ8ŠÓ©ÑçwÜ@kñ3ׄÅ=…ÃÔ­­á¸ 6"q ²tjtÁQøÞ´?sMXÜV8LÝÚzŽ«à`ƒs‡àüâú ´¿-wpgá0ukk;®‚ƒ ΂£ð½i-~[îàæÂaêÖÖy\›Ó0,ÙÔè‚£ð½i-~æš°¸¿p˜ºµ5WÁÁçÁÙÞ¬¼%q$¼’u^ß¹ ¯ý܆÷/a<Ér<&x/˜?r/^Ù¾ Œ ð0.À{À¸ïãâ¾l(î÷‡Áã'ïKü€I'µ=Þààç ×j°§É ÁŒ.xäy”ë¡8‘‘TêÜ&rZ8ˆÃlXx„Ã,Ž%‡³L*‹3|Ž!A'áté$’YElé$RHÊ–ÎÕÐ/¹hÿÃç¥S•ՉȦÚi˜dA°¥³4MC9]: âª-ðS¦Nm“Q®‚×Ùˆ8ÏD×ÕáZ8±ÖØ ‰››íq3é#8ØÀŒaº'«ÅnÉ<Ëd{pÄLú6ü‚¢À½H-nÓ“þjKál“UFÒGp°É2ª?§±2×׋Õb·$ n´¦NmÖUp°AÉrAQà^¤·1YÀ£7&.¤à`^@a)d e–êkáÅj±ß Àó@¦Nm}ÅUp°O~S…îÉj±àá§S§¶¾â*8ØÀŒa‘gyˆT_ /V‹Ý’1¸up˜:µõWÁÁfÌ£Ð=Y-vKÆàþÁaêÔÖ\\©MžC›‡îÉòØÑûxvíÂÔ©­¹¸ 60cFXdq.Ò(Ó׋Õb7gLŠOS9LœIAj3ɃÐ}Y;̘O~ÿgÃðéË_áÛa‚ƒ ÊKi"s}-¼X-vsÆà•ïãKH÷€ñ•¥{Àø ³Îñ]%÷€ñØò0ŒÝÆ·ÜÆxà=`\€÷€ Åýî°ÄÏü݆é#Á<øÂc#5“n~Þp­™(2¦6g¸»q$Èé«Uq*C¢ÿ~^>ÌÃ,O˜¾Z›Pf[>aˆ€-Ÿ„"â€/ŸD2 [†Ÿ—Ïò4ΉßË` ínBÂÃ…#ýÒ°€ï+0I;#iŠ ü$Õ/ÏeŸ‡Ïÿ†ï4~ž}Æy fÿ+f¿ßŽíS÷Òùù®X•‹ùK[/›ù?üö§ï¾ÿþ»æM½œo«ãË¢Ü?–›zqxž¯ªå¼©Žõ²˜¯Ëͱ.šù§ùvñZÔÍߛⰨmñiqü:ûVÑìOUÓ.vŸ·ÅÓìwÕq¯¼ei8ûV¦'æ›fY—‡ö¸{šýÔ/L °leidenalg-0.8.9/doc/source/figures/layers_separate.tex000066400000000000000000000251041420514302700230720ustar00rootroot00000000000000\documentclass[tikz]{standalone} \renewcommand{\familydefault}{\sfdefault} \usepackage{sansmath} \sansmath \usepackage{tikz} %TikZ is required for this to work. Make sure this exists before the next line \usepackage{tikz-3dplot} %requires 3dplot.sty to be in same directory, or in your LaTeX installation \usetikzlibrary{calc} \begin{document} \definecolor{c0}{RGB}{228,26,28} \definecolor{c1}{RGB}{55,126,184} \begin{tikzpicture}[scale=0.7, n/.style={circle,draw=black,outer sep=0pt,inner sep=0pt, minimum size=6pt}, nc0/.style={n,fill=c0}, nc1/.style={n,fill=c1}, n2c0/.style={nc0,minimum size=3pt}, n2c1/.style={nc1,minimum size=3pt}, e/.style={}] \begin{scope}[local bounding box=outer box] \coordinate (t1) at (2,-3); \coordinate (t2) at (4,-6); %Network t=0 \node[n2c0] (a0) at (-0,0) {}; \node[n2c0] (b0) at (-1,0) {}; \node[n2c0] (c0) at (-0,1) {}; \node[n2c0] (d0) at (-1,1) {}; \node[n2c1] (e0) at (-2,1) {}; \node[n2c1] (f0) at (-1,2) {}; \node[n2c1] (g0) at (-2,2) {}; %\draw[-] (d0) -- (b0) -- (a0) -- (c0) -- (d0) -- % (e0) -- (g0) -- (f0) -- (d0); %Network t=1 \node[n2c0] (a1) at ($(t1) + (-0,0)$) {}; \node[n2c0] (b1) at ($(t1) + (-1,0)$) {}; \node[n2c0] (c1) at ($(t1) + (-0,1)$) {}; \node[n2c0] (d1) at ($(t1) + (-1,1)$) {}; \node[n2c0] (e1) at ($(t1) + (-2,1)$) {}; \node[n2c1] (f1) at ($(t1) + (-1,2)$) {}; \node[n2c1] (g1) at ($(t1) + (-2,2)$) {}; %\draw[-] (d1) -- (b1) -- (a1) -- (c1) -- (d1) -- % (e1) -- (g1) -- (f1) -- (d1) (b1) -- (e1); %Network t=2 \node[n2c0] (a2) at ($(t2) + (-0,0)$) {}; \node[n2c0] (b2) at ($(t2) + (-1,0)$) {}; \node[n2c0] (c2) at ($(t2) + (-0,1)$) {}; \node[n2c1] (d2) at ($(t2) + (-1,1)$) {}; \node[n2c1] (e2) at ($(t2) + (-2,1)$) {}; \node[n2c1] (f2) at ($(t2) + (-1,2)$) {}; %\node[nc0] (g2) at (2,4,2) {g}; %\draw[-] (d2) -- (b2) -- (a2) -- (c2) -- (d2) -- (e2) % (f2) -- (d2); %interslice edge 0 - 1 \draw[-,dashed] (a0) to[bend left =60] (a1) (b0) to[bend right=45] (b1) (c0) to[bend left =45] (c1) (d0) .. controls ($(t1) + (-2.5,1.5)$) .. (d1) (e0) to[bend right=45] (e1) (f0) to[bend left =45] (f1) (g0) to[bend right=60] (g1); %interslice edge 1 - 2 \draw[-,dashed] (a1) to[bend left =60] (a2) (b1) to[bend right=45] (b2) (c1) to[bend left =45] (c2) (d1) to[bend right=20] (d2) (e1) to[bend right=45] (e2) (f1) to[bend left =60] (f2); %\draw[thick,->] (0,0,0) -- (1,0,0) node[anchor=north east]{$x$}; %\draw[thick,->] (0,0,0) -- (0,1,0) node[anchor=north west]{$y$}; %\draw[thick,->] (0,0,0) -- (0,0,1) node[anchor=south]{$z$}; \draw ($(outer box.north east)+(0,7pt)$) rectangle ($(outer box.south west)+(0,-5pt)$); \node[anchor=south] at (outer box.north) {Layer 0 (Interslice)}; \end{scope} \begin{scope}[xshift=9cm,local bounding box=outer box] \coordinate (t1) at (2,-3); \coordinate (t2) at (4,-6); %Network t=0 \node[nc0] (a0) at (-0,0) {}; \node[nc0] (b0) at (-1,0) {}; \node[nc0] (c0) at (-0,1) {}; \node[nc0] (d0) at (-1,1) {}; \node[nc1] (e0) at (-2,1) {}; \node[nc1] (f0) at (-1,2) {}; \node[nc1] (g0) at (-2,2) {}; \draw[-] (d0) -- (b0) -- (a0) -- (c0) -- (d0) -- (e0) -- (g0) -- (f0) -- (d0); %Network t=1 \node[n2c0] (a1) at ($(t1) + (-0,0)$) {}; \node[n2c0] (b1) at ($(t1) + (-1,0)$) {}; \node[n2c0] (c1) at ($(t1) + (-0,1)$) {}; \node[n2c0] (d1) at ($(t1) + (-1,1)$) {}; \node[n2c0] (e1) at ($(t1) + (-2,1)$) {}; \node[n2c1] (f1) at ($(t1) + (-1,2)$) {}; \node[n2c1] (g1) at ($(t1) + (-2,2)$) {}; %\draw[-] (d1) -- (b1) -- (a1) -- (c1) -- (d1) -- % (e1) -- (g1) -- (f1) -- (d1) (b1) -- (e1); %Network t=2 \node[n2c0] (a2) at ($(t2) + (-0,0)$) {}; \node[n2c0] (b2) at ($(t2) + (-1,0)$) {}; \node[n2c0] (c2) at ($(t2) + (-0,1)$) {}; \node[n2c1] (d2) at ($(t2) + (-1,1)$) {}; \node[n2c1] (e2) at ($(t2) + (-2,1)$) {}; \node[n2c1] (f2) at ($(t2) + (-1,2)$) {}; %\node[nc0] (g2) at (2,4,2) {g}; %\draw[-] (d2) -- (b2) -- (a2) -- (c2) -- (d2) -- (e2) % (f2) -- (d2); %%interslice edge 0 - 1 \draw[-,red,opacity=0] (a0) to[bend left =60] (a1) (b0) to[bend right=45] (b1) (c0) to[bend left =45] (c1) (d0) .. controls ($(t1) + (-2.5,1.5)$) .. (d1) (e0) to[bend right=45] (e1) (f0) to[bend left =45] (f1) (g0) to[bend right=60] (g1); %%interslice edge 1 - 2 \draw[-,red,opacity=0] (a1) to[bend left =60] (a2) (b1) to[bend right=45] (b2) (c1) to[bend left =45] (c2) (d1) to[bend right=20] (d2) (e1) to[bend right=45] (e2) (f1) to[bend left =60] (f2); %\draw[thick,->] (0,0,0) -- (1,0,0) node[anchor=north east]{$x$}; %\draw[thick,->] (0,0,0) -- (0,1,0) node[anchor=north west]{$y$}; %\draw[thick,->] (0,0,0) -- (0,0,1) node[anchor=south]{$z$}; \draw ($(outer box.north east)+(0,7pt)$) rectangle ($(outer box.south west)+(0,-5pt)$); \node[anchor=south] at (outer box.north) {Layer 1 ($t = 1$)}; \end{scope} \begin{scope}[yshift=-10cm,local bounding box=outer box] \coordinate (t1) at (2,-3); \coordinate (t2) at (4,-6); %Network t=0 \node[n2c0] (a0) at (-0,0) {}; \node[n2c0] (b0) at (-1,0) {}; \node[n2c0] (c0) at (-0,1) {}; \node[n2c0] (d0) at (-1,1) {}; \node[n2c1] (e0) at (-2,1) {}; \node[n2c1] (f0) at (-1,2) {}; \node[n2c1] (g0) at (-2,2) {}; %\draw[-] (d0) -- (b0) -- (a0) -- (c0) -- (d0) -- % (e0) -- (g0) -- (f0) -- (d0); %Network t=1 \node[nc0] (a1) at ($(t1) + (-0,0)$) {}; \node[nc0] (b1) at ($(t1) + (-1,0)$) {}; \node[nc0] (c1) at ($(t1) + (-0,1)$) {}; \node[nc0] (d1) at ($(t1) + (-1,1)$) {}; \node[nc0] (e1) at ($(t1) + (-2,1)$) {}; \node[nc1] (f1) at ($(t1) + (-1,2)$) {}; \node[nc1] (g1) at ($(t1) + (-2,2)$) {}; \draw[-] (d1) -- (b1) -- (a1) -- (c1) -- (d1) -- (e1) -- (g1) -- (f1) -- (d1) (b1) -- (e1); %Network t=2 \node[n2c0] (a2) at ($(t2) + (-0,0)$) {}; \node[n2c0] (b2) at ($(t2) + (-1,0)$) {}; \node[n2c0] (c2) at ($(t2) + (-0,1)$) {}; \node[n2c1] (d2) at ($(t2) + (-1,1)$) {}; \node[n2c1] (e2) at ($(t2) + (-2,1)$) {}; \node[n2c1] (f2) at ($(t2) + (-1,2)$) {}; %\node[nc0] (g2) at (2,4,2) {g}; %\draw[-] (d2) -- (b2) -- (a2) -- (c2) -- (d2) -- (e2) % (f2) -- (d2); %interslice edge 0 - 1 \draw[-,red,opacity=0] (a0) to[bend left =60] (a1) (b0) to[bend right=45] (b1) (c0) to[bend left =45] (c1) (d0) .. controls ($(t1) + (-2.5,1.5)$) .. (d1) (e0) to[bend right=45] (e1) (f0) to[bend left =45] (f1) (g0) to[bend right=60] (g1); %interslice edge 1 - 2 \draw[-,red,opacity=0] (a1) to[bend left =60] (a2) (b1) to[bend right=45] (b2) (c1) to[bend left =45] (c2) (d1) to[bend right=20] (d2) (e1) to[bend right=45] (e2) (f1) to[bend left =60] (f2); %\draw[thick,->] (0,0,0) -- (1,0,0) node[anchor=north east]{$x$}; %\draw[thick,->] (0,0,0) -- (0,1,0) node[anchor=north west]{$y$}; %\draw[thick,->] (0,0,0) -- (0,0,1) node[anchor=south]{$z$}; \draw ($(outer box.north east)+(0,7pt)$) rectangle ($(outer box.south west)+(0,-5pt)$); \node[anchor=south] at (outer box.north) {Layer 2 ($t = 2$)}; \end{scope} \begin{scope}[xshift=9cm,yshift=-10cm,local bounding box=outer box] \coordinate (t1) at (2,-3); \coordinate (t2) at (4,-6); %Network t=0 \node[n2c0] (a0) at (-0,0) {}; \node[n2c0] (b0) at (-1,0) {}; \node[n2c0] (c0) at (-0,1) {}; \node[n2c0] (d0) at (-1,1) {}; \node[n2c1] (e0) at (-2,1) {}; \node[n2c1] (f0) at (-1,2) {}; \node[n2c1] (g0) at (-2,2) {}; %\draw[-] (d0) -- (b0) -- (a0) -- (c0) -- (d0) -- % (e0) -- (g0) -- (f0) -- (d0); %Network t=1 \node[n2c0] (a1) at ($(t1) + (-0,0)$) {}; \node[n2c0] (b1) at ($(t1) + (-1,0)$) {}; \node[n2c0] (c1) at ($(t1) + (-0,1)$) {}; \node[n2c0] (d1) at ($(t1) + (-1,1)$) {}; \node[n2c0] (e1) at ($(t1) + (-2,1)$) {}; \node[n2c1] (f1) at ($(t1) + (-1,2)$) {}; \node[n2c1] (g1) at ($(t1) + (-2,2)$) {}; %\draw[-] (d1) -- (b1) -- (a1) -- (c1) -- (d1) -- % (e1) -- (g1) -- (f1) -- (d1) (b1) -- (e1); %Network t=2 \node[nc0] (a2) at ($(t2) + (-0,0)$) {}; \node[nc0] (b2) at ($(t2) + (-1,0)$) {}; \node[nc0] (c2) at ($(t2) + (-0,1)$) {}; \node[nc1] (d2) at ($(t2) + (-1,1)$) {}; \node[nc1] (e2) at ($(t2) + (-2,1)$) {}; \node[nc1] (f2) at ($(t2) + (-1,2)$) {}; %\node[nc0] (g2) at (2,4,2) {g}; \draw[-] (d2) -- (b2) -- (a2) -- (c2) -- (d2) -- (e2) (f2) -- (d2); %interslice edge 0 - 1 \draw[-,red,opacity=0] (a0) to[bend left =60] (a1) (b0) to[bend right=45] (b1) (c0) to[bend left =45] (c1) (d0) .. controls ($(t1) + (-2.5,1.5)$) .. (d1) (e0) to[bend right=45] (e1) (f0) to[bend left =45] (f1) (g0) to[bend right=60] (g1); %interslice edge 1 - 2 \draw[-,red,opacity=0] (a1) to[bend left =60] (a2) (b1) to[bend right=45] (b2) (c1) to[bend left =45] (c2) (d1) to[bend right=20] (d2) (e1) to[bend right=45] (e2) (f1) to[bend left =60] (f2); %\draw[thick,->] (0,0,0) -- (1,0,0) node[anchor=north east]{$x$}; %\draw[thick,->] (0,0,0) -- (0,1,0) node[anchor=north west]{$y$}; %\draw[thick,->] (0,0,0) -- (0,0,1) node[anchor=south]{$z$}; \draw ($(outer box.north east)+(0,7pt)$) rectangle ($(outer box.south west)+(0,-5pt)$); \node[anchor=south] at (outer box.north) {Layer 3 ($t = 3$)}; \end{scope} \end{tikzpicture} \end{document} leidenalg-0.8.9/doc/source/figures/resolution_profile.png000066400000000000000000000231601420514302700236160ustar00rootroot00000000000000‰PNG  IHDReƒjzg%sBIT|dˆ pHYs  ÒÝ~ü IDATxœíÝytTõýÿñ×MB‚²e¢2,A,´Œ,lÚÖN¨&­ ""‚¸vÖ=ž†j%t¡‚`k«"…V‹¡Ž :Xh1–àr"[ÀJB%J2÷÷_æGÉ„$wæ“ÌóqÎ3—;ŸÏ{€s}ñù|îçZ¶mÛ@HE„ºÊŒ@(0¡ À„2Ê àx(ûÃþ k®¹Fýû÷×wÞ©¯¾úJ{öìÑСCÕ§OÝqǪªªrº £9Ê<¨§žzJ………úðÃUUU¥_|QÙÙÙzøá‡UTT¤ØØX=÷ÜsN–`<ÇGʪ««uâÄ UUUéÔ©SêÖ­›Þ~ûm3F’”••¥•+W:]€Ñ eݺuÓÃ?¬+¯¼RÝ»wW§N”ššªØØXEDœé:>>^t² ã9ÊŽ=ªüü|íÝ»WÔ‰'ôÆo8Ù%@‹ådão¾ù¦zõꥸ¸8IÒ¨Q£´iÓ&=zT>ŸO*..V÷îÝ/øy˲œ, Y5å‘⎎”]yå•Ú¼y³*++eÛ¶Ö¯_¯ÄÄD¥§§ëå—_–$-Y²D#Gެ³ Û¶y5Óë—¿üeÈkhMß!˜µ8ÕWs¶ÛÔ¶ûùÆ|Τ¿G­áÕ~?Mú\[š·­`^[šÊÑP6xð`ÝvÛmJIIÑ€dÛ¶¦M›¦ÜÜ\Í›7O}úôQYY™¦L™âdø?'Ô%4™Iß!˜µ8ÕWs¶ÛÔ¶ûy“þN„«Öðg`ÒwàÚÒ¼mµ¤k‹e7G´sˆeYÍ’<à\999ÊÉÉ uZ™¦ævôvL€³)hŒ”´„2Ê @(0¡ À„2Ê @(0¡ À„2Ê @(0¡ À„2Ê @(0¡ À„2Ê ê±¬PW€`p¹¤²²PW@èÊl;Ô ߀pÇô%€e ”€P`B€e ”€P`B€ep4”)%%E©©©JIIQ§N´`Á•——+##C ÊÌÌTEE…“eϲíà<]Òçó)>>^ï¾û®.\¨Ë.»L3fÌÐܹsU^^®ÜÜÜÚÅY–‚TB̲xÎ) ekjn Úôå›o¾©Þ½{«GÊÏÏWVV–$)++K«V­ VF Z(ûÇ?þ¡ &H’JKKåv»%I]ºtÑ¡C‡‚U€‘‚ÊNŸ>­Õ«WkìØ±’Î ïëü÷á&*¼þúëJKKÓå—_.Ir»ÝþѲ’’uîܹÎÏæääøöx<òx<W ˜×ë•×ëm¶ö‚²ÐÿŽ;îÐ÷¾÷=ÿ:²ììlÅÅÅ);;›…þÄB@Ë×ÔÜâx(;yò¤zöì©Ï>ûL:t$•••iܸqÚ¿¿zöì©åË—+66¶vq„²°A(´tƇ²¦ ”…B ¥k1[b n„2Ê @(0@Pö)q¹Î,öoÍ\.©¬,ÔULÅÝ—@p‡)´nÜ} Ð Ê @(0¡ À„2Ê @(0¡ À„2Ê @(0¡ À„2Ê @(0@T¨ Â…Ë%YV¨«h=\.©¬,ÔU@ó±lÛ¶C]D],Ë’Áå!Ë’¸<0ISs Ó— ”€P E:»F/Ð+..Ô•@ð¦ @«ÆÚ3Áš2€V€P`B€e ”€P`ÇCYEE…ÆŽ«~ýú)11Qï¾û®ÊËË•‘‘¡„„effª¢¢Âé2Œæx(ûñ¬›nºIÛ¶mÓ| ¾}û*77W7ÜpƒvìØ¡aÆiΜ9N—`4G7=vì˜RRR´k×®Çûöí« 6Èív«¤¤DGÛ·o¯]›Çh"6,Fo»{÷n]~ùåš>}ºáDDÈëõjëÖ­*(($åææê†nÐŽ;4lØ0Í™3§ñß Êþñȶm=óÌ3êÚµ«Š‹‹5}úôw`Û¶|>_cùùùÊÊÊ’$eeeiÕªUY6@ëbÙ¶m:©¸¸X;wîTzzº*++U]]­víÚ5¨ƒ^½z)..N–eéÞ{ïÕÔ©Sår¹T^^î?'..Neeeµ‹³,5 <hõ,Kâr˜­©¹%*Ð Ï?ÿ¼.\¨ŠŠ íÚµKûöíÓ< 7ß|³AlÚ´I]»vÕáÇýëÈ,˪qÎùïÏ•““ãÿÙãñÈãñ4¨_hM\®3Á¬%q¹¤ ü{h5¼^¯¼^o³µp¤,99Y2dˆ¶nÝ*IJJJÒG}tÑÍž=[í۷׳Ï>+¯×+·Û­’’¥§§kÛ¶mµ‹c¤ Z,F÷nšš[®)kÛ¶­¢££ýï«««ÜøÉ“'uüøqIÒ‰'´víZ%%%iĈzá…$IK–,ÑÈ‘#/²l€Ö%àôå7¿ùMýæ7¿Qee¥Þ~ûm-Z´H·ÜrKƒ/--Õ¨Q£dY–ªªªtçw*##CÔ¸qãôüóÏ«gÏžZ¾|y“¿@Kpú²ººZþóŸµvíZÙ¶­ÌÌLÝ{jˆpþ ML_@ËÅô%ÂMSsKƒî¾ B´\„2„Çï¾LII©uwd§N4pà@Íœ9Sqqqîg e7Üpƒ$i„ ’¤—^zI_~ù¥\.—îºë.­^½ÚÙ Â@ÀéËÔÔTÖ8–––¦-[¶4zkŒÇô%´XL_"Ü8¾%Fuuµ¶lÙâ_XXèöeTTÀ64@ÀTõÌ3Ïhâĉ:}ú´lÛVtt´ž{î98qB3fÌF­^ƒï¾¨ŠŠ -^¼XºûQ@ØhÐÝ—¯¿þºÖ®]+Û¶•™™©ïÿûÁ¨5eЂ±¦ ᦩ¹¥Á$B´\„2„ÇúÀy„2Ê PçŽþ)))þm0ÎeÛ¶,ËRaa¡£…„“:úïÚµ«ÞöîÝÛ‘‚ÎÅBh¹XèpÃÝ—#ÅÅIååÍÛ¦Ë%••5o›@sqüîË÷Þ{OC‡U§NÔ¶m[ÅÄĨcÇŽîÊÊÎŒ”5竹C`’€¡ìÐ’%KÔ«W/}ñÅZ¸p¡~ô££6€°0”ù|>%$$¨ªªJmÚ´Ñ=÷Ü£W_}5µ„:ï¾<«]»vúꫯ4`ÀÍš5K]»vUuuu0jGÊ^xáù|>-\¸P‘‘‘Ú¹s§òòò‚Q@ØàîK@‹Á60YSsKÀéËÍ›7köìÙÚ»w¯ªªªüÇ‹ŠŠÝ)j 8RÖ¯_?ýæ7¿QZZš"##ýÇÝnwƒ;ñù|8p âããµzõjíÙ³GãÇWYY™ÒÒÒ´téREEÕ·Œ”ÎÅHLæø>e;vÔðáÃÕ­[7¹ÝnÿëbÌŸ?_W_}µÿ}vv¶~øa)66VÏ=÷ÜÅWЊ eÆ ÓÌ™3õÞ{ïéÃ?ô¿ª¸¸X¯½öš¦Nê?öÖ[oi̘1’¤¬¬,­\¹²¥´×”mܸ±Æ¥3Ãsï¼óNƒ:øéOªßþö·ª¨¨$9rD.—Kgò`||¼©Ï?ÿ\ÇŽó¿â‰'žÐ¾}ûôÙgŸé¥—^Ò°aôlÙ2¥§§ëå—_–$-Y²D#GŽlôh Ž”õèÑãÿŸü в,íÛ·ï¢:Ú°aƒ~ÿûßkõêÕÚ½{·Æ¯òòr¥¤¤hÙ²ejÓ¦Míâ)œƒ‘2˜¬©¹…ý-¡ &s|úòÔ©SÊÍÍÕý÷ß/IúôÓO/¸þ 0”Ý}÷Ýòù|ú׿þ%IêÖ­›fÍšåxaá$`(Û¹s§fÍšå_óu饗2¥Ð̆²èèhUVVʲ,IÒîÝ»íxaá$àŽþ>ú¨¾÷½ï©¸¸XYYYÚ°aƒž}öÙ`Ô6t÷åáÇõïÿ[¶mëºë®Sç΃Qw_jàîK˜Ìñ-1222´víڀǜ@(œ‹P“55·Ô9}ùÕW_©²²R¥¥¥úâ‹/ü;vì¢7Ž@ýê e‹-Ò¼yótèÐ!%&&úCYÇŽuß}÷­@€ppúòÉ'ŸÔO~ò“`ÕSÓ—€s1} “å1KÚ³gªªªüÇ&L˜ÐèNŠP8¡ &slMÙYwÝu—>ùä%''+22Òßi0B@¸8RÖ·o_}òÉ'Šˆ¸Ïl³c¤ p.FÊ`2ÇHž˜˜¨Ã‡7ºpú²¢¢BW_}µ†ª˜˜ÿñþóŸŽN†²™3g£€°Ö »/C…5e€s±¦ &sìîËï|ç;Ú°aƒ\.—,Ëò·m[–e©¬¬¬Ñ ¦:GÊ|>Ÿ"""T]]}ÁžÝÃIŒ”ÎÅHLæØHÙÙ-0‚¾Â]ð7@-„2Ê Pçš²óïº<‹»/š_w_Öu×åYÜ} 6É»ûòüÐUVV¦ÊÊJÿûnݺ5ºSÔpMÙ«¯¾ª>}ú(>>^C† Q||¼† ŒÚÂFÀPö‹_üB›6mRBB‚öï߯5kÖèÛßþv0jCYTT”®¸â ù|>Ù¶­o¼QÁ¨ lÔ¹¦ì¬N:éøñãúÖ·¾¥I“&©sçκä’K‚Q5¸\gû›Àå’ØˆÍ©Î»/Ïúâ‹/t饗Êçóé¯ý«***4iÒ$]~ùåÎÇÝ—Cq'(Î×ÔÜpúrΜ9ŠŒŒT›6m4eÊMŸ>]óæÍkt‡¨-`({ã7j{õÕWÔø—_~©!C†(%%EIIIš={¶$iÏž=:t¨úôé£;î¸CUUUY6@ëRg({æ™g”’’¢;v(55ÕÿúÆ7¾¡~ýú5¨ñ˜˜½ýöÛÚºu«Þÿ}½þúëz÷Ýw•­‡~XEEEŠÕsÏ=×l_ %ªsMYyy¹Ž9¢™3g*77×¼C‡êܹóEwtòäI]ýõzúé§uË-·¨¤¤DÚ¼y³rrr.8"Çš2€©XS†ó9¶¦Ìåréë_ÿº^~ùeUVVjݺuZ·n>|Qø|>¥¤¤¨K—.ºñÆÕ»woÅÆÆ*"âL×ñññ:xð`£¿@kpMÙ¢E‹4vìXíÛ·OûöíÓ¸qãôôÓO7¼ƒˆmݺUÅÅÅ*((ÐöíÛ›T0@kpŸ²gžyFjß¾½$iÖ¬YºîºëôÀ\TG;v”ÇãÑþó=zT>ŸO*..V÷îÝëü\NNŽÿgÇ#ÇsQý8ÁëõÊëõ6[{÷)KJJÒ–-[-éÌ•ÔG}°ñÿýïjÓ¦:uê¤S§N)33S<òˆ–,Y¢Ñ£GëöÛo×ý÷߯è¾ûî«]kʆbMÎ×ÔÜRçHYUU•¢¢¢4qâD 2DcÆŒ‘$­\¹RYYY jüóÏ?WVV–|>Ÿ|>Ÿn¿ývÝtÓMêׯŸÆ¯G}T)))š2eJ£¿@kPçHYjjª %IÚ¸q£$éÛßþ¶ œâ)Š‘2œ¯©¹¥ÎP–’’¢­[·6ºáæ@(˜ŠP†ó96}yøðáz§4}úôFw €šê eÕÕÕ:~ü8#UAР5e¡Âô%ÀTL_â|ŽíèOž:GÊÊÊÊìzj`¤ `*FÊp>Çî¾4¡ `*BÎçØô%‚‡P`B€e ”€P`B€e ”€P`B€e ”€P`€¨P@KärI–ê*ƒË%••…º çY¶mÛ¡.¢.–eÉàò@X–Ôâ@Ss Ó— ”€P`B€e ”€P`B€e ”ÀÑPV\\¬aÆ)11QIIIZ°`$©¼¼\JHHPff¦***œ,ÀxŽ>û²¤¤D%%%JNNÖñãÇ•––¦üü|-^¼X—]v™f̘¡¹s窼¼\¹¹¹µ‹ãÙ—„=ž}Ù ºté¢äädIRûöíÕ¯_?+??_YYY’¤¬¬,­ZµÊÉ2Œ´5e{öìÑû￯¡C‡ª´´Tn·[Ò™àvèС`•`¤ „²ãÇë¶ÛnÓüùóÕ¾}{Y–Uã×Ïn¢œî ªªJ·Ýv›&Nœ¨‘#GJ’Ün·´¬¤¤D;w®óó999þŸ=<Ãæõzåõz›­=GúKÒ¤I“tùå—kÞ¼yþcÙÙÙŠ‹‹Svv6 ý@½Âe¡¿£¡lÓ¦Mºþúë•””$˲dY–žxâ >>^E)aŤ‹Nc™ô¸p6o[-鉚ZßIßkKó¶Õ’®-–mÛv°;]±b…Ö¬Y£?ÿùÏ’¤eË–©  @ ,¨Yœe»4€FkJ¬ŠjÆ:¬{÷îÚ·oŸÿ}qq±ºwï^ë¼äE€Éôå Aƒôé§ŸjïÞ½úꫯôÒK/iĈ¡(À!)‹ŒŒÔÂ… •‘‘!ŸÏ§)S¦¨_¿~¡(À!YS€šØÑÀ-.”åççkÚ´iºãŽ;´nݺP— •ؽ{·¦NªqãÆ…º­ÄÉ“'u×]wéÞ{ïÕßÿþ÷€ç·ØéË£Gêç?ÿ¹þò—¿„º­È¸qã´|ùòP— X¶l™\.—n¾ùf?^/½ôR½ç‡l¤lÊ”)r»Ýêß¿ã }&æã?®|Ðé2´0M½¶@].öúR\\ìß,?222`û! e“'OÖš5kj«ï™˜K—.ÕôéÓuðàA=òÈ#ºé¦›”œœŠÒ¬±×–Ï?ÿ\û#¨ÛÅ^_zôè¡ââbI »¶„,”}ë[ß’Ëåªq¬¾gbNœ8QóæÍÓŠ+´~ýzåååùŸg5öÚ£ûï¿_ï¿ÿ>#i.èb¯/£FR^^ž|ðA ><`û!Ù§¬.z&fAAAs~øÃê‡?üa°KЂ5äÚ§?þñÁ. @ WßõåÒK/ÕóÏ?ßà¶ZÜÝ—­‘Q¡¬¡ÏÄ€‹Áµ€SšóúÒPfÛv…o<@sàÚÀ)N^_BÊ&L˜ ë®»NEEEºòÊ+µxñbEFFê©§žRFF†5~üxž‰ à¢pm৯/-vóX€ÖĨ5eáŠP`B€e ”€P`B€eê©ÔÔT%%%iäÈ‘:vìX³¶Ÿžž®ÂÂÂzÏÉÏÏ×öíÛýïùË_ê­·ÞjÖ:L3gΜP— ÈeêÕ®];w ®ÊIDATê£>’ËåÒ¢E‹‚^êU«ôñÇûßÏž=[Æ zçóù|޵ýÄO\ôgœ¬€óeìÚk¯Õüï÷»ßiðàÁJNNÖìÙ³%I'OžÔ-·Ü¢””õïß_/¿ü²$iýúõJMMÕ€4uêT>}ºVû:tðÿ¼bÅ Mžú¨ÿ¼¿ýío2dˆRSSuÿý÷ËçóiæÌ™:uê”RSS5qâÄ žwöa,ç× ³ íÛ··mÛ¶«ªªì±cÇÚkÖ¬±mÛ¶×®]kO›6ͶmÛöù|ö-·Übÿë_ÿ²W¬Xá?nÛ¶}ìØ1»²²ÒîÑ£‡ýé§ŸÚ¶mÛ“&M²çÏŸoÛ¶m{<{Ë–-¶mÛv‡üŸËË˳'OžlÛ¶mßu×]öŠ+ü¿vö}}í^uÕUö¢E‹lÛ¶í§Ÿ~Úž:uj­ïö /ØÝºu³ËËËíS§NÙ×\s¿–òòrÛ¶mÿñ²²2Û¶mÛ²,;//Ï߯ÙólÛ¶'Nœh¿òÊ+þïõÈ#ضmÛóçÏ·»uëf—––Ú_~ù¥o—••ÙÛ¶m³‡nWUUÙ¶mÛ<ð€½téÒZ¿õw~=Z.FÊÔëìˆM×®]uèÐ!Ýxã’¤µk×jݺuJMMUjjªvìØ¡;w*))IëÖ­ÓÌ™3µqãFuèÐA;vìP¯^½Ô»woIRVV–ÞyçZ}Ùù(Þ@íŽ5J’”––¦½{÷^°o¼Q±±±jÛ¶­F­7J’ž|òI%''kèС*..ÖÎ;%IQQQ=z´ÿóëׯ×СCÕ¿½ýöÛ5¦YGŒ!IJJJÒ5×\£Î;+::Z½{÷Öþýûµ~ýzjРAJIIÑ[o½¥Ý»w×ú½¨ï¼ÈÈÈõh¹¢B]³]zé¥*,,Tee¥233µhÑ"=ôÐC²m[3gÎÔ=÷ÜSë3………zíµ×ôè£ê»ßý®FŒÑ ÀeY–ÿçÊÊÊÕW_»111’Ηªªª€}ž}¿aýõÖ[z÷Ýw£ôôt=mÛ¶õæË/¿Ôƒ>¨ÂÂBuëÖM³gÏ®Q÷Ùþ#""ü?Ÿí£ªªJ¶m+++K¿þõ¯~Ǻλä’Kj}-#eêu6ô´mÛVóçÏ×ï~÷;ù|>effêùçŸ×‰'$IÔáÇõùçŸë’K.Ñ„ ô³ŸýL………JHHÐÞ½{õÙgŸI’–.]*ÇS«¯.]ºhÇŽòù|Z¹r¥ÿx‡.x×gCۭϺuëtôèQ:uJ«V­Ò7¿ùMUTTÈår)&&FÛ·o¯±VëÜXYY)˲tÙe—éøñãÊËË»¨¾¿ûÝï*//O‡–$•——kÿþý’¤èèhUWW<ïbG˜‹‘2õ:w&99Y Ћ/¾¨;ï¼SÛ¶mÓµ×^+éLpZ¶l™vîÜ©Ÿÿü犈ˆPtt´þøÇ?*&&F‹/Öm·Ý¦êêj 4H÷Þ{o­öçÌ™£›o¾Y;wÖÀuüøqIÒøñãuÏ=÷è©§žR^^žÿ3 m·>ƒÖèÑ£uàÀMœ8Q©©©ºæškô§?ýI‰‰‰JHHðÇóÛíÔ©“î¹ç%&&ªk×®> stream xÚÓÎP(Îàýð endstream endobj 7 0 obj << /Type /XObject /Subtype /Form /BBox [0 0 100 100] /FormType 1 /Matrix [1 0 0 1 0 0] /Resources 8 0 R /Length 15 /Filter /FlateDecode >> stream xÚÓÎP(Îàýð endstream endobj 11 0 obj << /Length 3535 /Filter /FlateDecode >> stream xÚí\ÉŽ$·½÷WäÑ>$‡ûr0`˶û6Ð>:-i,»J»¡ß÷ 2ƒÁ\ªf¦]0<hÔ]QÁ ./‚ÁÌÖÓÛIOŸ=èwü4ø¿žÌä²J6L)«èóôx~øi‚ÎgSU|ÐÊ•¦ß&Ó7*’¿úñí·üóŸ´*ÓÛ_–_ñÇ¢b ÎM³I*ؘÓtžf[”ÎqšƒS%§“ƒU!ëèHÆ­3¾²6›Q&ˆ~½b_f”×~š£U:zòÆ(|µüµvŠª$W¦7ßNMeÑxóõôÅï~ýý—oþþêS›VnZ&`V…?Òxøëøf^K7Ä |×þã.?­*9gW½:ËG£bЉŒJüû#†óõ¼i=íH¿+²Â‘â=›é/?<¼^Æúÿx`?çÅôÞÛãÚ œ£J:†i.˜ \Ýí,Kʇ’í4g¥½ø%*cM"íeO/‚:lF9ë^´ŒU1{l,A¬M»Ô€¥¢© pøV—âF³]D­{ïD‘=¸­Ÿm\qð½t÷*·ZÄ÷¹ÙϬþÕô4 g7Fx'[Û¨¢KÞŽÌb³²9Û¹˜6¹J.üad–Í;ˆyghdëñKLFØÂQø¥™âB3]´C8²³ÍèãžÊ¥ÁùücúÝr篟ºÔ)u€wF…UÈ2ì“”Bæ±Z `ÁŠyºV'A\1 *ƒ*â@<Æ«à21í’‘vD{ß¡¶.nHgtýB@¦7÷iI×bAÕIÏ ³€\Þ%8xm:³Âx¸ºcEˆø¦cÒíàƒÓGÁˆ|‡á†¨àt¦ã ªDƒNzƒÍ)ŠÖ*—Š/\±ÙÚ”…À"©1N$6á1Ê’:Ü9Qc:ÔÎÑeV:à0›Í²SyÁÍbW›å>;³³ß3U«ªW‰®ƒp_ðq0Ê’‘¿D;ß¡¶nøkôüBX‘¦·Ú)÷Y<¿UšÎ3£Š€¼GTqAáÔ“üš¸ùâ}ˆËÑØÄyËwÑŠ¸D±’À‰ˆí®˜Ë9tÀé0P—«E®2²|­ÈkPìnt¸½¿[þâRx‘Æ7/÷y:˜§K¦êøgFYæb—mžÇúÁRó š5²:Äi*z §9´â¶29GC‡?bʤ8ÖÏËG>̆68Ð…¬SK.pt2dº95FF©Ù²O¿¶J’²ÚR¬!uÆ4Ý]Úq^ /ÏÎiDp‰ª#~Y}l Ôgt MwÇšãèðàTçl]”N!é ŒîÉÕ•yAé úKÞ©(» ªÕžfj”#[Kà¸Öñ¹^ÍsÅ/Lsÿ?Ó­Y`Žla«æŒ%¥R~º©dî(W¼ÂÒ îÙ“5 ̯,²KkŸí–ÀHVt-FÿÿŒjJ1P†V.,W`ú¢RºUX‹Kõ¢‹2 ªÀ6ò©äº¥Ö(ÀÒzñWÀ2Nd/6YB ¥o]O<`¬½§m^rõnÙ«Üj·Üççx~vûæÅõ‹Ñ¥&Ú!¥Yºi£§Ÿ:cà \ Î8X0òXWb‚œ.as#a\2·(<†aÕ&²½.yLÔ¸çµspÃc£ã¢‹4½ut¹ÏÊ•èòrGÌ‹ñ¥­]Ñ8(øPœ°—©ç!:‘tÁÀ]¢ÄŒ$@]ÂöFâ*ÊR©ŠqpØÐy+ÛâÏ#euî3cì[³Õèïq0‘†·Ž%ó\\ /W Ùn q„qµâcݦ‹Ä)œkq@rAç1&^¥„„²ÕpbZ>Ã9‡ó´s $V©f °™Çztn2,0çJ­¿6”Ù($³f0Õ%ÔŽû#j­ÃgíQü58ºÞ;[m„xvËÿ…‹sãA+®µC‹2ø„ƒˆ.¬Á9‹÷r $JL.Ô%loä ŒkΦøÎB΃»\’î‚‘‡D«w¼íü[SÑèöqX†7º0ºO‰¸}):¼\EùBthõ`3r¬$;p“3Ê8Û÷y—Œü$j¡‰lld(ÁkÆ CÙbs6‰¹.JÔGgí׆¡w/ĈÞðF»â£Ÿ‡K‘â….<¶yßy<øs©âTw|Š™ uÈžçØ,8W<ÃX?ýùökî(G–2]þeRÊþÉOãÍ J¹âöDÑæÙN Ìá­*ÕR¼uí± ­K½-5Ú)méê”x'Û°ðMIª¯–D„ê6,˜ çC{n²¸Ð‚踦¨èb{BpiÏzDb„5”0Qû ¢/ [äPsy¤ÿ®ö4ƒ×\1…æÅ벤ç/¢snèèÂ6·^~þ´KLcÈ» Ûð¦²<:’’òð•žiKˆTtr¤ÈþœI®ò¨ $,]õŽa®1“Q:£©³ùi÷˜Ã*ÇÒÞË<¾Çd•ªñ~÷˜n{¹ÂØÜc.nˆ×.2 ˆž 2L™í‰ÀQl½²æÑ'ĺL5…:„¤Æ&íþŸeô*ˆÆF,t±<ª‚À£Îa…(26þØ–3‹½*†V°b.‘þÛ•m–ÕÆ½—¢)Î0ÞÞë–®Œ¨Ãx¬3Ç#¥[îö^¶K1ol÷VÁõŽH´…ö\Éz‚ŒêC(%« ƒ^žÂÏA/ÁŠžEü-8“j°þ¨Æ!ØNDl÷±5K=¢…Gz+pH]´T:ív»ˆÚöŠ¢¸Ñáöþ¶9@‡Xï©[m©û<]§ÝVzñ´÷rjY«1kÊ3<£×Õ™K@%p¿Ö発hÅwƒ"sØ€ÖElvEv ELäHv OtÈæÑ,‹Fªôºlçë–èÆA¸˜¤ñÍãÒ}Ž6st1½àYîb,¢Ã˜ iÅpb,<íô‘({!™åóÈl¬ÂlÕ1XÀ†FJ³”Gä$„f(ÙÀîï–X0’YWâþv˜­S|½lzÕþ>öi¸K^ªÐ°Û˜XŸ¨bE¥z?é< qè*ˆšSÎ*ë’èU. Ó[òµÀ@þ.“9`h²Õ<Žmt¾¨.a‹Ô° £ò%!L TRƒ•‹,¡†½c,”Î3ÔÞÇ68ø¾Þ{•›mŒûĬ'f·S^¸Pv1`ÔB—.eEUΪ@%£Nµ MR¥ïú.éJÔ˜‹:R°½cðœÆÑ®#Ù¦³&ŠÁ.IKÔ:ku¨‡Þ=¿?¤é­È}Z®Å“*òîâãy<4õ³Þ©N‰ö¶äzÜs&µÛ( uÑèöÄ©CžY¯kŽª2çU6ɹèiÄ WdLjï®t{‘`[]¹xc 9LN̵–šÑGŸêQR*¡û¹ýZRŒÃwaèR&P©±|à¶,uÿh4è¥Â^/5õ bizïƒ4LÄXÀ­ZýÛ÷¿~óó/§ï¿¡º(ý E Ë·?üçÇÓw߿ݽûQqº¡U&Ýü˜Å‘åoðzßYÝ£E[SœFŠ·º>èib2õÔ²—$Ÿ‰g=½IT#D¼£a5ÙÂÒ*˜¯åG—·¦QZÖ‘£5D÷x¿M_L_Öýýþ;þý‹b¨†#*__Ž‚H—SE§a\æè¯aä¸ü©µú‡Úø«Þnæ†|fôÇéóéõtp¿éu¦2E¬°ÜzÉ»¢PÙÄ×ûÒãÁZšŠ®&xMüüÕ~M„ö-Öÿ÷5ôFlkbqgÚšH0Zh)Æ R6íeÙHå–‚îÑZŠXdÓ^3Á{´D–¡ý™²¾*;¸º ,ÈoZ~tùAÛÿáuñºËáM¶K?ÿ ®—üu endstream endobj 19 0 obj << /Length1 1578 /Length2 7625 /Length3 0 /Length 8653 /Filter /FlateDecode >> stream xÚ·4œk6¬KôÞËèÑkˆDïÁ`”Æè½D'„¨ÑEI´(!ˆNˆ¢Dï½ù$çœ÷ä}ÿ­ï[ÏZó<×î{ß×¾×-]Y[˜5X Eððó%ò꺺ü@(È  `±°èAÎàäX,`¸;•øÃB!îe Ľ¡: Põpð øE$øE%€@€(þ! .PyBlê¼UìŽÅ"sõCì÷yþù°ÛpøÅÅE¹»d]Àpˆ  P!À.÷m@Î]˜ Œðù¯ìR„«Ÿ——/ÈÅ·—æàxA°;î ¶üj rÿÝ/ @Ïâþ—Bf‡ðÁÁ€{3Ä u¿wñ€Ú‚á€ûì]5€¦+ú—±Ú_Ü€¿‡àçåÿO¸¿½‚@;ƒll`.® ¨j°ƒ8ƒšJj¼o7µýerv‡ÝûƒÄð>¯Çoø_c²ñ€Ãïo‹ßT¾Ÿá?ø÷Õ{ƒm°f&a6’áŽ5á-—Õ²Ô^‚Z‚z.®M¹ÚÚ9¶J«kXοX£Äš‰ýFÎ i² ¾)Á›N§ú†T?YUϱO}'μœµj¿ÝR`9Í…:y¾8Ò±ái±wĪ,Xôî²!Ú2BpÝ—Má`±â éKò{á=hÜpÞ±KùØl3¯ÆÐ/®¶§‰‡¶fI]úÀfÜêêvHk&¯ö©ÏQsæg7Çúƒ&<”+»Å-ÿÏEÞzµÔ‡wi[“Ž#JÏdÓ¹®\ ¦9j;¬>ê>“öW°Ù5&ÛÞñÄB‰YáájõZž™Ýô¨%í±5eX цª]%'ï&zˆ·H"×#5‡½iˆrT-­ÛtÚ{ÃùÚ6DBH×ɹÞ},' HèaqûõCjhèIüÏPjÏÏsJ¬[óÆb´Žø½¾^2g-…ÛÀ€ƒÎ ùSyê<š^rxÈK¦dš«€¶¬áÓp7Ñs’:Ç\;ÊY…W˜œÕ"¾Ï;ÁïO]2÷Ã¥H&WF¤¯Q©9ªìœ›ÛUtXY”¦Jh—ŒSg°îHŸjè†S'£ÄÔŽ™å<16Hç>-Ì…1Ó;ç±Ô†OFú¡¾z)fod G<¢^£}ìïÞïIScBÁ9?¤z¹Ú’{n]Oi˜£n »xäyµ¸¦"pÀÓ?”ß•â‰^(ßSÖ”é¨ïÔýaêc:p;ÛÕ<Õû ˆÝÇd)KÑyà‰,$›žbǺŸh®6=ãõ{(åˆù\»¸´Ö3ŠôÛ¶ª1Ê·urªN™SÜ?ŠM™¾£È ’\.A÷®I.ϲŸÌâÞúÐc#ëþ¼Ø–àcEí¬OбH}\“¦6*Ù?>«T%÷ ‹tFÙEß½…ØKÓç-ãIXe…lºÒ-ÔJŸ’»µuÉû £;׉fXùæÔöhŸÎœšŸ^E 8-ë%ѶW3Ô«˜%(žï¸a­­†}¤žÎ3Èq $Ë=[¬$y3tÆr•sW± c`oo¹ô¦2j€3D²‚È",æyK“c·ñ;/d±#I“„fE¸ÚÇ>L ·zªQéNËŽïN.òÄÇ LåMÔoòQ¨LFE8òi‰»IÇb¥*xg¯6‰Ê¢04錤#Æ„T ín?wrAü3åÙ‹¤×¤ðþ9ƒ!pŒ‹\úõ™µî`ð‰˜Ÿ(ÍÛáTƒ]žÁ¼‡—ž!ùðÚÄÝ|f±„} SŸDaw]­Ç;½A*¦.œ:ûK›a‹¶ftÈË{2FñèñQ‰îÔ& Æopë¾ÊVo 0÷Ô|.ÚŸŽÄm_h<âìZ¹ä‰xË‘l©±ù©oI“ÍQ1±Í_ãÕ6FF±YÁrr€à`åë¾ñ’.½Ž¤J¯°+Ûù3J?¤rx•aÚW ~.YNö/|K†ØÐ£Qëi5é“5mŸn‚+®*sUÅÒ®A±ƒV˜ñ^UW?†S‡QE öÞ5›|mr…È©¯wíYø ‘«Ï¨Ò7Û;ÑÜgñöý¾X¬ó_×ÕÞ†3Þt#sr‹<%èqµO”ùª1(‘MÔG ^PúŠÅê“|îa”(ܬeÃFJ±õ=¼ÐìWaáœf߀‡¦ì‰ÅØøÌÈÙŽl­Jv†|XQ²{Ò¿Eùñ]ó.–eýÃàaVBín ËÛI$p€z¿í×Aãô*OÚɛ ¦òç †-Fõ‘ÇÊ¡e¹*_¹ó'¥Ùw­/ÈÙPº3ê,Ë7ö¨ê%EU•° $ÃÏ.Ü…g_“ÿ˜·öt³›^£ËÖÐ~­œ°éPÒò¢6üÊ)ìY÷Vù„…€³®ÏWpowjÇVÉ1v÷Ñ«¾ñuc¡A…"!عÄä‡#¼7¤Aì"·Ü‡+$±¬ªzäDIüýa ømÔoX'±ÁLè¢>#}P'  ­®ÐI9*pr »CkŸk^¢ðÐÿ%© ?§}(Æ®ãní 7zùEûeÊl¶Õ+Ç÷ädEZ¹µ¾„'eAߪQH‹ä7/ƒo7÷µ ‹çôsÌó¹Rº\©«àm7`½ž8(„Y¨ÎÇV]nvÕñ×î®mÑ<ÇýþVT]”xäÞ5ªHpÐÙ\fã§ù&ë™]ÅÂxé)1™=ÖaÁ%ªqŠøö'6ä*”!ÊÔø”§·lÈ_5¨¯>ªÁAþ#2I½Þ)6B!;LOæÇŒ"ƒ•”¹CÓ"Fû&ZN&~‘Ïør¸7úÙSBË'»œ=㥰ǖ¹·¬f]Ì‹ö†•–ÙH«nyB’#{³YãÕ£"M?3jž"}èé—ü L‰Ç4”F‚å˜!¾ÂóvíHµ"UàøâkŸ— 6á›IܲËâì…#ÝÃZ\ªÁ’Ü®Lk{Š¢î§cí~#J\`ê2¡¡›ÄƶÁÀuÀ‚™n·Ob#`’Ÿ‹ž9Ä5Q¤a~ÂP]þ³W›¢MÖ$Ä¡¥H†FY¨Ù˜º¿“Ì z(v×\*ö¬A93"ºÓ.Ô›°øCân외çgÖñ­«¾æ'­A7õ3ËJ;µÙýiº¦ñj¹m—¦ç\ŠøíïòS•ÍÌèx“—£|Ë9VŒÄ8&t"f¬!JwÌßùºI'Òd¨âe ÀÒ:kÍD_¡ìšéØEüpñ}{jUáz]ÕK*ºlcg„"×o4I—¥µ&M)% ïçÇ‚ý:ùiD×6¿âHÓ]d$µÇN| »|ðý{üÑ{ ĹšÔägFt7×Cÿâ±Zº7µã1L¿¼—•Q這§¨Ž}JQ·N÷Gl¨k1þhä˜î̹#¡†90d[-ëš×ȼü”Ò§¸÷ LÐbMü¬ ÆÀ}„OÛ›*L$àÖ‡“£b%áðÛ$ÑEÛF ç¯æ¡¤uïC”Å@›LŠ€Ì ‡J xè9ŠL{qö~²Î·­íÔ@ÊÔ°¤^4ò÷!cŒO㦃¢Mñfx¤“Žå³Ÿ¦Ê™µK2‹Î˜LŸ¸Q kóðL¤*H,æàÞ:ìå;ñ=C<@"†Q^Väg*”SH%®Ý¶ÚoC¤Cž+ÕòPí!…P…økN[--2-™r™[cL¬ù‘n?XˆW¶.ß¡‡ù¿¥’ùM(³xs#‚X’ß4©Ò]Aͼ˜!ùNpµ­s™vîpÔTo ¨[̉¦Ì1<ƽ瑉­T=v®üJ„8ž VŽ&7ÀfxA•2ŽËûþä¾ìu¥è-,œ|Ǩ¢”Åç篛+‹Úcw:œm÷``C=ü^¸ÙS„ÃÁ_½¶hßç°a¼`ïô¤†¡"±—^íò·~,œU™æN¾&´¹äµ.¾ÎñÝór% mFmßlc/ ËÀ¥RÍ“Ä×qµ6±Ô"÷óP­„ÎszÆsSŽ\9ñ\zâ½y‰»ò.ÌÕ‡o²½´e9W¨ZïE6ar¤Œ¤jㄎ¼zµp™Ö,>&“\H‰ßê'#ŠÍ"Du͸òî5¡ÞvÉê“æ·ûŽ)HÐé»–dùöJµé 5Hzm],ÏYÉB¶dO9¯+û¼5̤ƒÓ(iÒ‰G\—À–~Mß/(½ãª©då 4^ó<}"*úïE]*Í©OCÞI.O¤[E›õ§õÚXœ^NÕ‡†“œš8[ú±SV…Aò qd¾7Ò˜¯¥÷+JË)L˜Ëôïˆg… ,¨ÙצY&ã~wŽ`ï£4ˆß“¦UËw‘Ù7(¥¿Õ¾ý!ÝŸñ*tWƒö‘‚_´^RžÈ”2=h(]—([YÂ×”hécsõ¹›FÆõ³ÍçúíÇÒ ˆv– EËà9§ ~À¾”ï®ÿ¨13YTNàIHª)ò<rJ,9Ó¹ËêÎõ ˰Â!jˆK¹Ý‘"›vœÙ3*Ó:™¹¨âCfç |º³žÑçÊÔIÒvâ>òRq!âqE©sî•¢*IfŠks€G²i/QT=¥<ÕRß|¤-Lbû€§jÔ˳áJfõŽ0Õ’¾¡½äA[ÌÈñ ÷œéoçD³ôNZù+ûlî—qJ |œ!Sà;zIG¤Å‰5ùUo©s‰iÏ»ê©)õq€ö§ŠÇ:—vÁàlUÍV[Ü]ãî#´åc§cçrEÎJîw? O;£ µc>Ìm­<ã=Ê¿{Ò‘²™„7p.Ä‚BGã@”¯{ÑY67Qješ¬ÿÄöÑ“Cs,C5§§„¥< ÍóUBëï73¥ßy8 æL<Ì%Íb1¢w¬‰‹Á6bc×{ç*þ0-zZÚB=ÜõáUêäÊç hÈýzyáTnìÜulÓˆ ùÈα^ÔW<Ï· ­rø\Ç­¼²³ûóÛª½DRw#½­çIrdºÞiTN´×Tv¢:e¬^‹³Ñ‹³ÍÏCÈ#¿Uˆø“xžæKëŒ&_û M”Áblˆ.oý.·”áØªÙ‘¡h×ÝK¤šS+9¦¯à‚AcnOVÈz¿ZSQ³‘È;j(º ;ˆw+rf¾çp©c¾pçf¨7W5[Π „¥¯´Ÿ’»y‘»¾>}Ã…kgQæVEÏ·“ÏKÓ(òœ&rtˆ¶åÓoê5¶Ý‚džFɘðA!¨}L¡<Ù;f “¤@æøÉAsñ8ØŸ‘6!n4»"Íòót³Vƒ¥´ ™±¾B4™íäá:6ÇÄÍÜÒât?¨tîe“´¼”?iÈE5Ré ø.4ŽýzT¡‡g“ÿ 9°nw§V÷|cóõOº e65UɧXÆd™ÙŒS"„U Ûá6¹<³Õ/«úÐË ±Y6冨¿ûZœº}cÈ.3ɃR9n^´ŠðìFÎg‰Ëò¤¹5±ïhb‹A uJÄ}ÙŠX²ù|Ñ™¡ÛUX;—øEDõf½ñkበýuB´ÃÓ`îŠÓ[”ö†’Ÿôr‚ÕîƒøŠ(Y]ÏÏQ…<Á#O TJ¿åܪpù4Mi}d¶DÿáÉy$;ßyrð¦Š)|jœÞqß½‹©¿‰¥" öùKbá–Ö£6FOo&é<Ö't‹á'U¿9Œy‘¤aÑ· Td¡ÌXV6<«H•K4h–5êUÆqoLåä\T¤NMоwÔ]Õvê+NŸR÷&È;Ù=/b³äFÀQ– Cµô ¸š?Äf2ÄPø†Q‹oS£]Š :—ÝÜ>ú@ ÎÓÚó¬dQ\Ø#¶¤ë !gíº¾ê ,¾¯r]Ó°=jZ÷ûÓ]‘Îv/‰¬š6ÛÆRì[wOAI]8ûiäô#ÖVfæŒNmÛWn7E¯Z™ð¨j¦óöWaMÕ¥Iɪ¬ÚÓ,z–ÑBCýt:ŒÊKäÆ8¦£ï£&uËD~ÌZÄYmËìò0Õ:óÛÇ–bä8 VÏH<c½f¥¹,,ÐßS;ø¶Ãq£(œ¥£%·›‹¾þõôþ¶y¦ mòŒ½³·o—l\ÍŒõîwªú²mÅÓìa€ÂP H¶²ÚMžü`Ì9²È¦•ä;WÓSe©Þócæ]Ò$ÆÔvùæ6yïks¸·´<Ÿ?ÃÖ†¬2n¬…0y·é©/ËìYái‡éïÚ@tžE- •]R°žÏ¢8{§X”<'Ÿ` æ Õ%–ÑÜ2›ÓyïGæCÞÊ¿&i$^º^@ÓÊYJ¦›0¢r¸Æ­voÛO±î(I’ Ÿý©Ué³?ðˆ{€iQ öpºc¹™a¥q£¼ƒá$ᣭ¸ÑÞé¡„¾àu©«K¹ôHž¶å•Þkì¡“ðv=s3k¸üÚå÷ï£Þ‚,;Òç.ÐrÙ` šŸ1Ô?úTËPÜK Ôø?hȤÈ»žzû£?°_Df¯;þN(Ã2ý1_Ðó|?³¬·ù«^u_+Ú;Ëoz,iv›uïÌ«DiL:Ƨ7¯-TXñžÌ‰H¿lE995 Ä|g¶f¢C´¨Í:yãou#T`”¡¦ÝPíGÔ{Õ’Fä zì[ŸDlXŒXHÅfʉ‘03=¨#ªåŠ~ϰ:ÕFv>3Í]¤<È(îbï¸}fnñR€Ê_/'ƒÚÇwXLÔ¥º¦ïc;BÊmX–©)ÄDò9Ú™ú§J÷OCyß²å"ꦻ>Þí@8˜„JÚMî##⟘Y“V›}Xý¼›ïÁŠ’8]}S¼ðMÞ0 “#ÚN$+T‰Š–nÓ{†¯ä”º#òóš[ÌãSôH±Ö¶§QA¶®^Ú-¬êÃÓüŒÎrSÄùÔÂd‘ð,.?èÈ»}›¨^%âçT¹–Y„¨ÛŠÖ.À{¯/ ð\]!BVìA‹aÏ1Ñ~¾rã™U A/OR·µòÕZŸÀ¼)pèôùèyÑéÇvÖÏMÕ¬‡ŸÓ¾L[m–7ž‘ß𣮱¼lBâE ]Skä"¸Þ<»Ð)tFž1«³«&£à§4ËF­"aé\­ܬRåÀ”m‘Àtÿrñq<ˆcÌäÅ\AUTº Û’Îi„ùšp1 Ïr…ïÇB»NÍJ¹lMðfC]Âg‚®àDõÂ2ŽyŒÃ^>/*Ì7uü¸¡-­ÔÙ[w¹“öÁ¸¼(õòƒÒÆK ”¹¡óô…+›©±×y–Ë+X• þt í 3rU¦Õ·Px׿v1ÒÚ/Ò”2ô{Ýhôn ¨îä)x}°Ë ËÓŽH’|!ßÒìºä‰³¬þ.ôú9)MATZvâÐóîLq§& …g±#p™êi3ªÔ1ޏ­†ü ®n,4ߤÃiò³x¤aždñ‰DZP¨BvÈ›fÒÏc¢ºÍ–ëñÎx%>J«ÉÔ®iøD—¾ý¸QÀ‚1ïýñjœÒiÓV‹ë6ÿ›ŠFáéñ"¥ÅxÒí£n+Ñ*‚Â=Ù˜Ñz#uáâÇ6gT(LMåWæqOV™âá5€‹ :jO?TkfNŸÛŽÂRŸB‰«Åø0*Œz%X6Q*œ¦ìD·{Î:kÙ!ÇyÇ °b=‚3Qx-?ú*Ò<„­ÿðµëµ“ª«>’ÐŽësr…‡TYé݇ ²Z&r'N&TŠ)ŽÐ<¹$úüRÝóœö\å°£>¡|Ãx×ÁºrŽR²ˆzÜo730GTµ>é+4Dœœç±ñ¿¬ÛÙít¿‹ÏbTæ60%RúÌçBâÀu4Xÿv]ñsîg@ïæ§-§Çs±3õˆÔ-NœÓ™…¾›÷ 9>ÏiUˆ%ÍKÙÃÛ ƒDi˜Ý'mãMVE¶žö% Y=Ã^rô[ ˜¿¡%¯ïê¨Ðy.0ÂpX¤È(ë–ðç‹|¡ÕÔÝ ¿b¯¨®%Õ'ƒPÎX­¢é؃¾Þ·#Ù^ #ïZŽ[|ÔNá´{$q­)©î²¯l,NÏÙÎXkI„t¬{Kh!ç…žñŠ1MÌ*DÛƒffgõ«®ãqŸw´òY{zƒëy_ë«T,WÇ¥’iïÐ^ù:Gc –Ø—B2Â売T»Ëð°ù` J“½|Ê%¡ØªxM8f=Tp‡Ù!;WÝÒÇKfÔ@téXâ“ÉHnþ§×…˜ƒmÌß;¢SœTñaxMÇ¿ömO˜GöŒOÐĵ^G~Ú#¯5Y½@Ø®Üi-O—ž<cp˸@äòA—›H±ØuOâ–UÅ„v…&„ûK’9)„‹f~’tpäB}µgËøù ÿW…ºÂ/Ù`ºCvæ…Öª¤›gm[³èÔOÂû—ŒýDz¡s]2¾¦x"È"MK%ÄþO•7Ì&/² CQ‘uÁýúöuKagbɹ§SùùÊü*3?ú‹³= ºÛ^Ürh =/R$~žy~3¦iÑ´Ÿ‹ŽÂæzA¬Û?Ù·È€AsíKÊQFeÍ7¬ÛK1Ÿp7¼Ÿp´ymsŒ3² ¾îÔÔìm!LCHY²–ÅÀÓ'}áZ· Q4¦¾S!*œ¶÷€q2Ôx«ºZû#¡|eyïlübeÇæ‰x»'>¤˜£˜j½ŒB¶6ÓëY¶·<Фa¥Ý!ëÇ¥ÛŠ¡¹ùŒµ77šÁ-¤nÄF.êûÎpÜ}_?"d¬WN=ÕRJ=ÔÉ”ÀõŸ ¥SÊš§kÏ0y¤ÛX-')•²ÆõrÎud×¾~µ|JËhÝ׆QN yâõÞ%ùq»w?ûÕC„è>=fËÔT·'ÁÓÃÕ ¨Â 6]ú9Ši»„»ú®‰¥'­uòð<Ž8¶{8r¼égbüæ0ï ôªzÎWÅ™·y¼óŽ÷Í&™öÿ(žÏ endstream endobj 21 0 obj << /Length1 1417 /Length2 6522 /Length3 0 /Length 7486 /Filter /FlateDecode >> stream xÚwTTíÚ6­ô€€4¤»‘éîFr€b˜¡KJPºD‘¥C:¤%¤Q)‰oÔ÷¼ç¼çÿ×ú¾5kíÙ÷uÇsÇu?km6f=C>y„DGñ ñ JŠÚ††wAA~AAa66#ÊòLÀfñDÂp©ÿ0Pô„€QhL ŒBÛi#à€†—+ $‰K IH ‚‚’ÿ2DxJJ`o˜ Íh à$›"ÂÝÏæE¡ù×+ÀiÏIJJðþväÝ ž0{0У 7ô‰ö`WÀaƒ üþ‚SŠB¹K øøøðƒÝüO'Y.^À†‚$ÄÓâü*лAþTÆOÀAaÈ?¸!Âåö„hÀf#Ñ^pˆ'€>0T×tÝ!ð?ÆZ x¿zñ ýî/ï_`ðßÎ`{{„›;îƒ;Ž0W «¢ÅòEñ`¸Ã/C°+ö{ƒa®`;´ÁïÌÁ€Š¼>FøWyH{O˜; É„¹þ*QàWt—•áŠ77…$ø•ŸÌbn»ŸÀŸÉºÀ>ð€¿GÜÁñW^îÆp˜‡D]é/4DðoÌ ‚Äï âkøÞÈÏò[ùFWàŽpÑE@‚`ŽôAì Pž^ €ÿTüS"`ö(Àâƒü;:†8þ‘ÑÃ÷„ù‚hî ‚¿~¿Y¡é倀»úýÛü÷|äÌ”µåyþTü·NAá ð‰‹|Âb‚€ ¸0 !.ý3ŒöW‚ÿöU‡;"É?Ù¢Ûô¯Œ½ÿ"ç_ËÁü3–ÍZÀùo’[ Š Ú£Bÿgªÿvùÿ1üW”ÿäÿŠ—«ëo5çoýÿ£»Á\ýþ2@“Ö …^mz àÿmj ù³´Ú˜—ÛkÕQ`ô"ÈÃ\ÿn# ©ó…8èÁPöÐ?lùƒÿÚ2W¢‡@Â~]+Ÿ àéЫe:hJþVAЛóÏ#•áö‡_+&,&€==Á~è!£%1 @½‹ßß$øáÚ@—8"< ~MMˆ‡ºïhø7"*  ¯«¿eôÌPPOÈ ‚hÄñ[þG2ö^žžè}üMt¦ÿ’/?â ±'x?‹°—Žp®‹h=­•§óáÛÅû¸Úþ8Ѽ/Z Å>÷4ªu#[uÒCÁÖ¡šz8Co¾üÑ»Ù@:c¾–]¹¡ÒÕ PÊ}k |…ƒgß»œ ŒZ§q‰ŒÇkdûIú ¤¶8)¦³‘Ý"[5›Ï.Û‘[$?nÀócs:*N>¿ý3VŒ93ë*jÈÜOîi‘ée¤n<~‰‹?Qh¥9ó[³ˆÏZ^È}Û—!ò­H³ç…xõ£[4þÌùÃÉý4”I¹ÍH v±cÅòÄèŠÎ¹œª9O+ƒÜÆÀ´L»Ù•Üă’¯¶@ ÆŽpïÒÍÔ'KÁ9Ú‡²|* þ3åN3–7©Ü×÷µ0<Õ«ËÅ-™+mœõìå) :W¶sZV†â,''JÔ“Ši0Ê5 ê"A†îÚyÊb½²ók0Ðd8qs{°K²2¡”úó˜ëůOëWª«bjÀþ ¾ª%Úíd€é•LcG1³W’3Hb¯óûƒË©s¾´He¤ãòÒ.!+þÛ^¯ÞAª æ ¹Y©.ý€i§œTÍÍvQ½¢ÍT¨ƒIòÒånzàÇì7V“ÏæV ‹(Ó‡9ÞO•\°ÿ0?“Ãd) 8/—_£þöéÅz5#æ|±o){:Iqžž6ô§{¶crÛŸLõ%¢o6šW*Òo×ÜU¯ÿþÑa Ñw/Ð+_à—ÔmŠ+è’Ÿ»'JŽC[%iô·}æÕU¥Ù*LÕ®Xþqˆž•::+e@Cq7ÇþnÚK½…ü²©]”4—*/UwoMÔþN€N ¹šXÅ.Cb!¯ MŸ«4sIi{‰ 9ŸyÀXÄê Års$®’î3KÚÉ*S–!Ÿ—wºð™x d¥‘Ë‘l ÛÅÛwBL¦•>µ}ÃôŠæÉo°୺š¼ >–)¢˜’,Ëy”Í•ÞÿóX#QÊ]øú¤zWáË;ycãÛ¬ûÁä þKbiÙߎ+œjÞ‘é…þµ3V0§º£Üæ2gmí±4ÎÓ3f¿ ®6Ë5œ›î ¹G¯³-๠Ýw™ƪÐ[lY¦ÂÔ¹g­]}5jó½Þñ³Iœ¼ñãüÃF&­ë’Ç4Þšçþ iFUT‡\šõTÊr¥X$ûåÕ´“‡ÑyËß$&oÐ}¬)ýøA$kžD¥4Ûmw«QüIùÖ¥¶ª¿«Æ´Ÿb®|¢oȦ¾íd¦xæH>lSÞ$yT±LUG/ÜŽ`åo¯^¯`ü€!`ôu¨ùj‰¯ÝOÝC'€Ke·š:¦w‘^ÿÝgÞ¢áæ&¼f²£WÆ-ò)¸¸úà[ö)ÃÙ/…pgj‰ U¹Mëw$f©>tÝ›1Jמ¨Xœw|ûz[%‚ã`Vø8b.zqØ#Ðåq¶u~_ï½K>>ó‰ýþÚ›{ŒÇ)ŒlJU Þ3‹ôÉ6ÿÃüuXé×¢cóℲ‚ágr­j2A"ïp´¿® kzSÃÌ*†C»°€úZK1ŽE©š#¿2K W8¿ÛÍWß$@þ3Øœ,?k‹Ì ®Þy˜ò?¯̤Õîe¬®çw.LS` tÄØFï{!9%~Mjy,õ8b5. å´fªMÎþjÖ¨Y½"bL¾`çôe·ã’á•ÝŽƒØ¡ò­Ý3s+íFòÍ'ÒeÍQ2wÙ!5\iµGÌÖ¢$ëmÓˆ¢iíöY¯·‹ 2»M¦TM)úWo‚k–ዼ*ƒFêe¹±ö"ç³¼­-ArOøÉÎr×fr¾ša¶:êUðÌ4Ú0Òè=L=¢Å2Œ²8éSV²."‡©X¾ ’‹öàK4Ã3 NÌ€I=eˆÑ5'÷¹cTËr÷ì jï34‚…š§yrBј{F_±‰ÐÇ#«¥#Œ¬‰„Î|‹ú-}UÅù)#ùÖÓ2 <Ù#°ü-qùqZD±…w‘HS Tbßl*XŒÅ–È G%Ezcû²åÙÄàÞSpïÒÞ×QöñcJ/Ê76qÃÏ-Z,Âïd‘ (&'ªpT§r³ Æ©·g(l¬©‰»ª’i e #Aøá·m·´•;ë1DèêHþÌìwÃÙúæS¬)èQ‹è7&¬©DßÄIG­´yÓÄ)/¹“˜,úøs”Õ¶'vÝ`YòfØ´ŠjÞ,dI›W Híï”ÀæŸýt¯jún/âê{Hôq³-­ú˜>Û§¹k|g¨òG9½B *Z—86-ü\Uº8Ö³°_ä¡SeHyþùy¬&[¶á}kyÚ|Ñ-ßÚ YÂz¨Q…€·Ç05Ãã™÷¯bç88ÏÂ7ùC$o8<Ä ´§nl —³UBòöžxwo÷#­i_…çÜûÌ]T^ºÕK¨¬µú,w#^<¡EßD³ƒcž@ÁVL°bÊÉÒ3”SÉ`”=:Q¢ò‰æÃT{Åz‚Î[oNÃ%6¢ü}¦9–fûî¶úÇo*º«Ô½p´Á-Ur³!ê–âÛÌçã`ÒŽvj‰§þ—) 1ø‡²¢&wìꢄߓÒwÚ:£îüH¨•ÒÖR'÷,M(죗ð´¨á<—¥TÆÎn+ø ÒÊûÄ…“›‘ر-ùlÁœGó½³±A›™GÁ6¯],1$‚åhó…EÞ|š})À—È$ÆÀú Ï‘. TúõöëZ"ñH§äàmÑZ䑯ÛtK©­ï¸ûU'ñP×àUÏ·ûÍ´j´/ë7®¦ï‚ÏÉÔ–lîÛv¤;8bjdö› PÅbÌE×m|¸0±ÔHf<+ëÛ4Q†Rm¾»€Ê~¶ôPMPr™³M¼~·j"AÉüŠ4j¾™½ ¾}$›/Ã5SI_uþŠ\ìÄFWͨ•jÈ0|;ëòc2{¾×N6aÊ0›°S¦½§r½ šžáTm‡Á"wiÛ8:=â[4ÅS¡±û»Oê\ +—ä2Az}IVBORˆêžaá ¬œOØ3”dØøSØ8™µšú° Ú3 ‰e'Bóæ¡»a6}Ù`Bí²Òâ³' ®!®XõÆÕÙ «†›l”–ÝÌØ\‰Yî{&_CµŠ¥†"Ý&°®}‡Ÿ;~…ÄñõŠÔ×EOïòaž/„˜ÈŒÆrŽ—§Ô`ÞP/=ºÿÝx¾©É’¤ò~èŒÇ4–pá]×LXrœìlW“÷Ñ3½®'<ë÷ÚIlp+´Y°³ñ,ÅHv)Sø"¬‰Ì©¼rT€±½Éä,Gì(Çõ6?˜Ë')¾ù@Í´|_^’›sH‹‹Î(ƒ#IÔÄBßí]…Ý8(~rzû!´û+ H¦96cÞ.Ëq/:#Ý™7c»¶7Ô–2zºçŠk°d_LqÃC$ æñ;ÝpVÆrIœ-ªTÚBën™©‰[¡8î²ý¼—Ÿö+µÀR’â“øATt7Xù¥VZÛF¨_ÒX€m|˜¢«ŸôcY HE·¿‡%Zî¬ç¯ûÀ>³ÈÚ²pôæ;ŒL;lqœÇðNrø¤ ©û(øßCõ+4îåŠÛo6ÑM¡:(ñÚÒ.³z3sà5RJô€óelL8ùºy»™;/P7.–WFñ;yÇFœ1ÌÆDÒb&Œ³+vÉïd·¶Ÿá*qʶ±ã7ö˜Ú©5á.ji¯íäæRuWßz'ìÝU •^WÚ .•ˆAØ ¨nmÇ;:}”ßìì6 ¨º+)+{1Iß¾Ø ‹ýäžýmçÐNlÊäKê1÷ÑäIì®ê­Ü¥*M=t¾`•}lübËÆ–ªsrI. îº<•_ch–7kˆ/=G¾ <Ó,¦ ce¤Îé6¬)ŽY`’ì}Wó5Ûî,UÄ+ýÁ¸KV*Å“$ËDo›§ü±ÂoxµR8¸€1àÖ‹f›É²ôÄzÉSƒž´Uì/2+Ø+6Þ²3¬ª× ŒüY7„û·ÏÛêÌ&P½:úœRç½¥a:ãGw²ŠÕ‚cÓí&ÃT%M(N´œK&&&\«e¬FˆãXZ˜ë¼)kàœº¼Ây¢$Û]|ªñAu- ±cÌ);éa,ómk¥—ö/×Åh^BÛŒ u"d»ã¿GENiX šF ¼Ù3XêX·ªÈ{E_!Ù­Æ.匣ùq¨ìðF‹D¾F ›àGµ/©ÛõÆ­tš³§’qÒ‰â2ª#UNnØ÷gê ô7À é?]™4‹a~uœÆ”úÄto‹Éõ{ÏSm ¦q›:ú“Sêzy–&wó£ÐÕzñ%_¥ÚUƒ³tßµn)¨·´JÕ%8A&0‹#&,5Œ=Ò;eè,¡ãÕðÌ^ÇEn–( kzæJA`88Šþ±m!]°xb_•žš÷É׬X?q:ÚV‘Ö[;ĆÌ]s?™±6/ks~tÜÆ ]>¼™V„"I†F6„ Xu‘·xR;'˜hÏ/,*°HA j±ª;„Ë“ø‰AŒö¬‹*¸TŒÛ(—pî1_A1J;’tiEºYíã¿yU~÷ý¨)Û3êÙ}†wfUcàx m¤èäZWq%áˆ_vöaôé*}ΧÃnp´[yW_í~Ø!rݽŬ>°ÍGæºH>ùòi¥Àiä…ÊwleqøY¦¿Z6hÏ“,çGœÞÃ~ȉwC¯ÆmÑÊGÒï'ÜëLvÏíŒG¯Ý3ÇñS/ö~+Öå—áÆé¾y‰ä{eÿYó»l;¾ªfVÔ5²ôsú»˜†yø½²ÖÖ®Äô8FUý;çF´DDŒ¨›œ×WuI­¼ ë¬JæÞ²A_½ôB-„—¢ê„É4ètô¯ø /w¿Èœ-!èfõÕýfOŒÞfÆ“ –¶Ð…ú5ižw–9Ã7³S\Þ’VÊõÅ‹ºj-*®xÏÜOo<…Q›dÒw“!ÞÛö:ª]—ÄT|¾s*KÚLû0ø4íU®G½÷QNÑ-©"¶Ìëés}£ƒZú¯ó¡;st‹[SÉEfMƒZ _=Ž1âð>$]& M £ƒß“Á^Þ·"¦hB±q°Ê*Šœô@ÞV.ùáqb“åÏUÁoŠauw¼Kcô¡©SÒ¸öíþü“’/øÚ¸O±‚OS™.¥»£ ´¹SæÜ»Zìï¤-V¶~Ç_M { lê¶|s¸¹åb¾ye­{⊕*² ùÚf‘°Ý*úq7ëuï]ŸðýÕh8}‰ýUX+\š†(Ó&׬ØèO«]žåÔµE–~p¥0%Exܵ•°š Dµ½€@ìp„eÆC9HzÆò £®~ä=²se&Öy/²™·*ã°u¼£íª5fvv¤¬mï õsŽ0(à¤q”Fx89ÌúêžR–6]u}cø¾×Ž•në'*Ö¾e_ Ã¸ïIp^(’²/7£Ëß».YÏó'vн÷OÒ<ÒÙüBОnM+yßë0Ïñ65ÃõÍ5u& öO±3ôd‘ÜVLÀçGaó÷°ò]) üHf}Wõ¹¢’\Ç ó®§:"ØqÐ’äÀ2¶¯,è…#-n“¨–N§~º×RR¨ú‚cƒv!lðµädS>7&o[—¼e73e·çÄÎJI—eüƒdŽ„TŠ .dÿAwð×{a[Ä1e2”Ì%˜\S鋦æÏŽg9½¶t§ëD§-^¾õf\é'®øÒs}VQ8ª¤Ó†-Mù”¢”ãd»MŠ»¨›þ6ô€AªˆbŠ 6Ú|Zâ!ì–SP‰¡•¯i¥õj ÆŸk¡™7‰|{V1hðÉÓ™[gæ¹ÓÞ´§O¦áMyƒêõÜ7Ë#qEòæ: ¢ý ùÄ#õÁ0asC¼åb«íSë‘¡‚7Ó«Ï›gUèÌ–ŽòŻݽ_kfHRL÷ÿ”µj/%sy¤K:?ÃW0ªKâºÕ“A©‘©×®<œÔ[¸ÿT̆ÅÔ‹êVßEh„ô—QÛôàüÄg‹âí­¾ú´òŒ^÷ä„áÀÁ^ ÿâk‘¶³Ã@}øË4Bù¦FÙŒøþ‰á#ܬ·•]´‹*' ˜wÕùpóEO0åÙ…ÜŽwk@†Ø<ºËŠÊ<ãs¶gÕÞÕI 鿢ý@ŽQñ¶›Çç‘o›­¯£hñ«ò’><ô56®Úq6!on½·Ñлgžâ1— žäcàñ~7¡¦‚ýmVvüíRä|ÕΉâOŒ«æÛ-çRü±íš£ÅNÒ9÷Íܲҟ´Oðû±Í½xvFÜ!a˱LF. A‡'ð¢ŸU`¹Ìó!ŠÓ/ʧö.,C“hƒN¤SÃ_?â[¼¦ˆYWÍÞNx¤úŠ£`Ñ!ÿYšÀeÓü@-o³õ{v Ú£8ÄZ?hËÉGáOç¤<*F]Û ¯faDxÁ^¨ˆ …2¯°Šøáª=«]'É¿] &_ŽÂ3%?LVý"¢fÍyc¿,`ŽCRÊ/¢¨*™Ei|À§6#vwÖòÖGçÕñ`\úб˜zRÞ;M•JZ÷ȯßp>9à!òPiàU¼Üak”ïán ö<{÷‡%ˆfV7ÆPŠCõÓ¶Dïm+7Výœ÷Ó‰4².Ø2 þ öæe²«R-eiѹæòèúmÑ©Tî¹^FÙȬfõýà5QGÖ¸÷8“#¹•5á!<`±Ä6®Ö:VOÆy“¸Ç5êÚ¡G9%mS‰7Ëä»f—ËÈQ»Vø€ n¯Å^nB˜q<|[¡T¸ÒãmÞ#*àoe­7º bÈw3€PDyéF¢¸&î~Z›DˆÑý¤Ñ°£ .Qw^ý²Oa©Ì£”aÖ–ò üR8•æÌ!쉖é4<`öÑ ªÂ¯áØë‰{8Ž}s=iô"GJßÌdQ~‘lú¤‚ê¶qU pT±;ﵟ®]U…i2£ihærCCsGË Ýôà-ùš“À XɆeÚê‚‚dßÇalzÆr¼¼‡’ý·å Ãê$¯›5šÇ[З´Ü៽ˆÒ/tTp<É"½¼~£C£xw枌ÈòÃPq ÿ͵OêÌ­°]ÅËöLWÖ§­íøO怔K_ùÜ“ •–ü¤¾Ûid”é%ÊôíÒŒìÙK905µZ½Ïz·Óø'â™böÉŒN0¿_6`¼x "_a%¤ñ¦Q¹_>IÿQ½”Ûm|¬Ô%Ö÷|T™µy_¹³.×xjÇZ£›Ä¨¬D=mÚ¶®åy»ž)ù½ˆ›ÀûƱ¦Á¨àúþY‰$á·IkÐxg’ÎM={E¨Üâ3 ³$"¹`œ$ºô¾¨M› Üx\oÌXÏ<’ã+ ç µ·]é’N_Fµk.8¾‘ל€™»álÒ%I»ÊÓ>Æ ì_sòú34¶Ë*+Õˆ!Kk¸‡¶”Òóf?~9Gç‹ðhL é‡ëØÏ<ÇAU†t†l®¢%ÌL5)–:Çš@·Æ‡Šbó×¢§¾øêRkí÷²_;x(Ô½ µ¦¸±Ç/ýs„¬»ƒãx‹9è6-istøW ÆEt_¬P"WB34UçÇ)è…>K1LLTz¢æ3ÓNÒöÜ>Á Žûr¸tßyå-›#ðSîÅɬ~òÏV¥XËUoÓ‹¸ÔpÇ·oÞÏ%OSŒ+)]WØYú®K®7²Êÿˆ±.¢ÿ,ËWê::ð™Wü=ê v 柦 Ê#ÒùP\ÐÖ³œõꂆ‰.¶ámmÃg$tÆD‹Ù$æc©q÷¹Žý#’-xøž`×ÉÆÞ5Lè}zû=ÁÊn‹†±ÍN5øÈŒE³w™§" "sûaë]×sZôãSÅIÐL0/«è{I¯L•ëd›ìM ®½¢Óòöï,?A[ˆPóR¸uÜ<?{·«»¾Yu({DÃHÈ,”[ÁÁO dNõ®…±nj©o? ä†f¿dÑÅÏ…3vN`¿¨A ¦M˜÷IÐã™Ê”Ð+ç+7ÎaPö.¼9Þ s|«dñ—Á\l^ž¿d\F5bݭο£n9PüsP䤔бÞ!+ðĈ4õRV–T¡eô6¿õ¸˜&.ºxãÒµß\º¾¸GÎm&PQž1R®F±);ÂMö‡bùp‡ÖÂ[wìnîe}Í÷æöÆV˜üñÕ åNý-¦…WCø%‘íØA£–ñ„ï>HÜM½<™&ŽûnbœG<Ø×Mää3¾=ïK¾1M.9—%–Ôb³Å³|h2ûYþÒv²œ x”MÆbe:nÕ€mÞÆ—é†3_BÍs ñ#­:„‡ƒá^Ìÿ7{[k endstream endobj 23 0 obj << /Length1 1375 /Length2 5945 /Length3 0 /Length 6879 /Filter /FlateDecode >> stream xÚtTS[×-‚Jׄޤ÷Þ‘NHH!tŽHWzéMzAEéÒ¥#(Mš ôz¿ûßï½1Þãäìµæj{Íy8Ù M•`hG¸:… d=-)DH89MXwøßvNs8Æ FÉü/„ Áâlª,¨‡FÚÞîXKÈ€%e@ @’þˆÆÈª дÑ(¸ § ÚÃpvÁâêüý ð@y°´´¤Àïp@ Ç   ÁºÀ‘¸ŠPˆ;`‚†"àXÿ¥à‘sÁb=d„…}}}… H/!4ÆYžWðE`]c¸ã‡¿Fô!HøŸÑ„H8S„×_´Ö‚8ƒ; GyáB¼Q08ÀUL´t8ê/°î_àÏå`!ðÒý‰þ•ú BÑHÊrœîpÀ@]Wë‡ (Ø/ ÄÝ ‹‡ø@îGàwë@]É€à&ü3ŸƒðÀz y!ÜÍ(ü+ îšÕP04 Ga½H~õ§ŠÀÀ¡¸{÷þ³\7Úø÷É ‚9ýæí!l†BxzõTÿ`p&’lÎp, ¤@RÜ€ûA]„0õ÷€ÿv‚™q3z ='Üð`„÷GèñXŒ7<8ð;þ}"ƒŠáÎÉ?Ùqf¸Ó_gÜþ1?À„£ýúýçÍÇ0åîÿü÷Š…u5̵5ïðÿù?Nee´(ÆqTPD€Á¢â€¤þw"CâO# ‚µPNh@ú¯~qõwÏ>HÀóG!¼À¿sé£qÔ…<ÿ0Ý$‚âàÿo¾ÿù¿ÑüW–ÿ'Óÿ»#uow÷ß~ž¿ÿ‡‚D¸ûÿAà¨ëÅÉ@ê¿¡ð¿´«‡!¼‘ÿíÕÂBprPB9ã(-ùˈðRGøÁa†,Ôå/Îüe7û¥6w nˆöBüú¾¿÷ôoNbP7Ü7Ä GÌß.8NAÿ.ª†‚¢a¿¤&".@0ˆ? nѸ“8Æi÷ûMe@X…ÆâBÜ€Á€Còk«`° Œýe#ùW^¨7ƒ“ØïíãŠþ}þ­g8Ü%™ž@Ce#\k#ÚNª•˜}WßÊ]ùšqrGDðm±¶OíƒýRŠInÎGrõé—`u;×N}eÏ“¼ùɃÀ•º›õþbG‚7Õ7œo:&M\]K <¾Á>AÙŒWhñH™Uæ ¦Ïå>U±̹τ“2ˆ»¶w*Õ—‹®L]R;²M¿£«º,G—þ†´ùö'cì ÇÓUñCFîüOÈÄðåx›Øtý,v¹ŽS’ß*ªÅþÁYê—,Ý÷ô}î­îrDa©Õdn¨ŠV™ÏQüÈâó9‹&ÐQƒV…ÞD¯Ë>=Se"&j€ÄwöÝ ¡¤w’ØÛP ²3°+æÅ箃m«lžsÑ_ÉPB.Œ7®œ^»£Asœ;/ŽÊöþXÌH[åÁ΢¸ë@bÕLÆ=·óP§Õ¿™iæT¯g|~ÛQk¹9i~V‹Ïé)q¹|š$•s­éJ¾âLä)ûæ†QçxŒuzMeȧƒ&ÖæûÓGšYôÌ£‡=»w ŒA’@…Œû²J.œ·™@úÚ3N­®ÑÁA+ϲ½`ÛS½†"„ÞÚºÂ"9~ÚyÔ˜Q]Ù•‘ÈÃ] Ýlu—‚¯¥ŸÌ/)=VI88kÑà^`}òL6nA¿_ÄŒH¥VÓ»écMòƒÒÛ‚Ëõšu׿½;ñ”-*„HYÑÊ¿¾në#ïLÍŽì£ÌÞq4/ÏW.‚¾ï˜½¹"%g‚™V•ºÈ)…]©›.e.(íV¶cxš3§–š°kPpSÀG;Z³iQõ²žzÉ—*¯•2%4âx¬4‚FÌýX\K­šYYk*Úõžà}ô°Y´æ³{îês1viž,nËL`†–ÓæuR»¾{ü—ž‡–©é?å;úËAÙç%2 Àó¦ ÿ\jº€vÛ ×¢É®¯e«ï£xÁ8=9˜S®†»×Qî¡æ6QªöZƒ5iµ;æV´Á·B‘:~e”w´ãL\Ëo´‹cULæ}¿=w}ÌW™ T¸6z“õrgþLV–WÖLð”£ÐŸ†4–}-:)âÛˆ:[s þUøÌI°GažŸ5ymO-ràðU¡Mz&³­š ”²¿òüÔà¼ú‰HèhKÙgj`Ô“Q5ŠVŠåÛN1¶}›=Ë¿En ßFe)‚Ýpô¤ª6ž?(xÈѬ}ª©ºœ¶ÿÁ†ùÍŒ’±¢€Hè8w³H•ßèÿú¥)tæ` ~8·“|²w.]|˜9ÔæßNîz]ûÕ5‹ƒû¡2zãÚ¡Êüww6øðû‰Ü¶yÛeýn(T²Ø“|/„½ÒK2‰°¾Éq`pa€ÏýôÇNi­`^Rÿ{†Z^[ÛúTé µÖ×-cF:´ÝÇ Ò“>Õ;jÇ„+*&Ñh™€Òìò´Î·ëí“*é´cÜÁÖ C˵¾¯Ì·\¹Êõõ#—?SôO{Ï[¡ÍÿIù "‚ 8Ñì0tÓeãã’,_â¾îÍæåm“Ÿzí¶+ÖՔ˻ôö®™ãlÝÊ‘ÊÍGãÂdY¯˜¢ª³ä¿ÈÿàÝ[¢õ!¡¢ÎuäcÁ† »sO¹R¯z§3lE·ž®KT˜ vˆҪ«š Õoö…æ«u›ðOˆ§Á‡[Ÿ-r!•¦4n™®"gƒJ7ß9û&TÄö¹1WF¦í‘9A×x{ž4ðË0(]ûÙÊî2Ç^kWþò[¬kŒ SŠx©Çe¢@ÑkîrtÈ6X<ñ ”5wŽ&.ŸßA{TöÙ6Ü¥q’~婜9O…Ìð.Ôª?Qw¬Ž¬K?ÎûfS«|îxVq[±Õñ‰œðn›Ùz¦%i5zÐÉY‚—!·³ä»ÅÕÞP̼ÆËäq>)8zÚ~:ÍÆ51B4Žè#üö¥0 GGûNde5È¡LNïpº“'šJÙ/„Ò{7¹!–ò½¤|U™f¿ÊöŒŸ4«5+2w£ö¸½ã[yF–>¸ ­ Z'ñMÔÆÜH½ÌÉwó…˜eŸÀçI 4çýñç̰ˆ(®€XþŸÄkFñâæE?è¿Â*†”Ùè$`öKŽ?ËÌJY{`~c·9˜¤ç|Äšm;©JFí\dn…t©E²:œîjdÃ+bìÉ–1¶:Z4QbüK~>üªø0ÂCƒ£Ñ†ëuÎrl_}ÆÐwƒ=Ç/‹Ïé´˜–ÁûC ÑýÚ0×;çU0f’Ã¥R¦ê·y–ü¼ ¬}{%z“FÚ“ú ^Ð6{†Ù ’Vç0}/bg1;ŽN‡$Åúm–×ú„kί°[T v0qÇaŸ÷ºñN$"üÛb÷ãi`ñâ:x\¼ŒÌã6Vz²­«K#)^öô?og=”>SRyù|Ö>,\LÇSŒ’”'F"ÍA#9)rxv>›.–Å_Љ9¼çò" !šFOçý  6?ìcº+"Ì›eS×í¹5ò$àþ(Ò‘ÝuS*ù¥À“¦Ußu:wOŠÄ^ú3Çœ¾&udDv¿òTæ\…àñEcBœýî…˜+[2¶iRX>Ö+ë^“ñd¯!=!R/µ/dDÄ/çH$8 ‹oõ0·ÇðŠ(ÄÓÌh²[”ùÝD´™³6IîšE îøŒ†«ñÖ±r¨ø›ÐY“™[ÔóƒÓ<Þ•ž‹c7·‡V]Ú#œ:úîÒ7°É®(ÆG¹¤ËÀ£(Ä«°ñô>ç„]ä˜Û»üÊÍðoó;†ŠW¨C–*²Ÿ“MŠ[( 7]]¡Ô[NH^X‹~~I>bùÍè'¼X ¶¹›Ìð P÷­ ¥ç/ÝGûrç^¾&õ™£Ô¾Âl÷ ¬Jí@K˜z8¨Á „‘5Z„¾iéíVt€MÈ×2{H)Kr쟅˜sÉÅ !Î;¾éHQÚ>ËÞšFŠ%dá¾Jø1Êa&;I¿¹çö\ÿìjÛ‰§«À]2ç«Klèã8v˜¤àÑ,Z 0Ü{Á2 #¯TEö·ÞfL\ü@'”äšØò¸®#NnO9–à'/[‹ÑE7Ï»Y"i Ô›ÉMY!þã®];Œ™|zE¦3ÓZEðk•ަÙ2~]Ñ}ÁÙšŸ.&Ôs4§{?ͦ!@õ~;™Úûkc3‡§G·Ê¹¢j¯Ã;¾xñÜ4žBg6Ô Z„„s/–ü-ßé·`§»š Uöʦëß'ê¯XxÙ”Ë÷“ùq=QFH¬œËÆ«‚(»÷ìnà9RTKDÏ«3:pC«æ«~ÎI²É?"ñôZÑ”ç¢0‰:äÔgÀ÷ÏÌxÅg?1þ„õºÐ]êìr&÷:=–ÞîvÍÛÒªË)ñû–;1«nA2²ß…!š7Ëê=y“ˆ–ÇôÓÐv¬ÛW‰x…—,Ø:‚/‡÷SÏ’‡wš‘Ù°QxFT´ó§ãm¡Ó¯îófg®Èûúø¬Q*&G³ËØl$ÿ¾AžÇ>£@ËôÞ€—›;•[Ãê¹IsÒP›ÕƬ|Zòb'f³í`H9FX/,¡Ê·L^?gÞÿNÅn‡žðÀ­ 8íX»7ÿ=WÓM#¾ðزR‰p… §Ï;:%ïßVYý M¤ZÕÐküqÙ™²Ð.™„Né§ÅgC¾Ooy¤@w&Ø]zä3ß?•š³, 'È5X©e ‘ZßNVµå{1ô´³o<ülj/è7“# e8évÞ“!Ó³}ÐJ©Çl°ybàȺ³§9Ðecö£6'¢OæˆàØÛþ^Nú5w™}[ÿ»T¢é È«xâF0òrä2=/$wü¥ÿýÛ¹ÍÈÛõ©Aç{›z›'€ã5îëÇ1¾ÕiUÜT"ÝŸÏ© ¡DÇo)=®‘꓇ †ÓˆT#¨ F±?B6MÝÖžWWÜÖ9/¦ƒ;*ñ©k=ûjxÜö]ƒêT1è}Ih#É›>sçÛmìyù °)j¨+˜Î=a)Â?Z’GM’ï4À’¿™  ™5ÍfȾ÷“%'¹~"²£Ÿd}éÝÔÃé×Ý_²­PY'ô‘'ûsÝ)·eFSáVØ›/·ðšK«,éžd1Æ%}ë]"ïæ»|»Ûê8Ä€ƒb‡U»b¡”b¡ðê~6¯óö@ žÄìW¦%;t¯iw¶e}æô8–êJàM`^̧)·’‘©öOMúÏïZE6ÔÀ<ù¡·ta7ÇHï–ÏÇJ¾M9çšä¢ÒG3‹(”ѦKŒ$$xtòªž÷*¡s°¾ûchi¢=gõD[¤ã¼ù{–š+ËŸ1µ$¹Þ¶­ AÔ§wm¼ ÅV…WGcr,úÝN’_’…T‰"vnDk‰ÕÞß[¯P{ˆ¦yLëÜæxD)6³¼O‡føDü¤tRúÒ í†åÉž®õ‡ò–bÄQ#ÍË |‘ݱ-D·ˆmmç‹RRšÎìƒDú…¶¾þFÿÀ§Š€Í×ì«û&°Ôc$ÁóÁ0’ïˆÏºVcÇGOO\˜¥g”…jMîß2üw…ZýìÎë>øÆbé¸aõì0ô~š\|–±´ú­z‹øôãbçœ×;Ö¶í³,ĺÇ4À(É"*”ýÜM¥Ürß#º‹GôÍ5™Ån2•>ñ‡-­m`oi‰4Ó«•|7¦`Q!áÄëMBj„ªõ¥N]àQéí EÑ4ŠÆ°¹d¦·ÏMÌ{;ÐÙþưu=[mIºiü=åM¥šÝ]Ÿïgiëy¢¿h}u¡µpsæW'´Ì7˜%Ê2ô‹Å§¿xÊ,&1WÃ!§r*ÒÿÌÍXá;Úæ8Euþ•ÈW­*2ÖùR®kç†=¥ó¼Ãm¤´LrWµZX4GºÈ<ÁUíg‘‘Êñ6·[W‡­tÄ6PsMÛyÖQëû¯¯ÀM¶;@b””~òÂLþNgúMxdÊTî~£aöä¢7S WI…\·`ri•”`âšZéT}œ}¯ .%` ¢åjN;Ma€BÄçp™ü¶-k»RªR©§ »gŸUo? ’‘”L²Vvòaî½³‹—Ï[pÒëB“@#ü‡l ÙõE-1¹®Co¬Çj¯@”åÍâ-ñy¡1*±õPžmËP*’((Ū«{ûý³}á«¥é/¨ðòü¨:‘ó™< ™[³Ãžâ¤¶hWˆx"týÊF1í‚|‘=ù¤ql~Cé×^ªmìÛ©¨!‡Ù&𕙟RÆkí;G-e:þޱ`WxU/¡ˆëùÄAe£úèU-{ó4urä-9.OÞóŒœöÉu]¾Êõ2i„ª°µZ"ƒû ·šeñeý몧A&šCÅSooå+…™*Ñ>¼‹Ä|“›}¿¯vÉ6÷ lÙYYH&àØ›ÇÕ4þL®Á@q˜í)§ì{;¢ú8*œ¨"¿Ê1HÖ­•-üJ’qú¶Sb”­…­˜‰Æ”(Ò$ÚÝ•[×e÷ÑäÜT­­.· zÛKÿŒž¡Âþ@ýó‰à‹ vm›Ô]ßâMóÏŸøÑ2Kf³·8<ÙéåW6Wü^4û ¼Æ·~Tî|v¸ê8 §¾¾ÕùˆsÒXЃ¸°ÔlÐöAµXqðnÎl¯èL¸¤yf±¶ß¡%ïu«åümg:Ììƒò?¦_iìB]¼¹¾+¢w4ðÐ. åt% ׉˜7B;ȬžD1—]7q¹IB±9ÉRLSþ>íÛíúh¼³lM¢8]k»&ÔM&VöˆÎëôÀÜ¡ÏÃÓ©ÜVKšÐ¾-Œû~q®}X¶KöX¨¥š“fcV˜Jé6¹B  I©ä½¶6Ø·Çà)ZòZž‰>Dº¶w¥ð¾þ¡PŒŠL·3¸[ ¹J“oø’ÆÃÄú£JúÕéu7 3UO^Cã ÛwJWåß¹dOê5<îyè6—öŒí5%½|ÓÄýGí†(Ù—”é!ê×_ÿ eÉ%îs‡uo·é–j„ŠÐ–ÞÈ‘uE)Ž8Èìd«ª1é~|õÄè§IŽ miÈÏGólÃäÅzgÖäC ¹äâùEsθ¢‡¡r‹ËŒu´½áÒ.q‘`%DÅywÑ ƒôør²jÓ,s+Ò›éâ…kÊY] [n÷8Sfß³ ½-Dr­…õtòõÑx¤ÚOíJ¯›+ÉÞ‹K8Šf¹z©eÛ*9¯ÆI- Õ'ÐpGd˜?6( gÑH¶>(èØ€,„'éåÏwéÉW³\¥ÏhUª®Ö-¤Ímò;¼ÂLW9 Ë}}CMÌÄbF».S™œ,FÀ/ý¢ülêãKÆþâ._™G_çæa63eqÕšŒÖôá³®óÆaiû™¶¹7v>Ñn\F¦\ÊQ;Âv‹´w“±yýØË޲C”ٕ࿜—èdZ;¤¾W_À®ÔKh³¨î‡ª’‡í í9Nx‡‹€—¨¾\8Ó½S~0ÍÈäõ2R¥oÚõ?þ"=¾ endstream endobj 26 0 obj << /Producer (pdfTeX-1.40.16) /Creator (TeX) /CreationDate (D:20161110230320+01'00') /ModDate (D:20161110230320+01'00') /Trapped /False /PTEX.Fullbanner (This is pdfTeX, Version 3.14159265-2.6-1.40.16 (TeX Live 2015) kpathsea version 6.2.1) >> endobj 6 0 obj << /Type /ObjStm /N 18 /First 134 /Length 1091 /Filter /FlateDecode >> stream xÚåVMoÛF½óW̱Eaí÷èd[‰“85,#u!ø@S™­Lª$Õºÿ¾3KÊ’å…«K´;;»3oßð‘#<8m@p:U‚0©™ÐðBƒ¢ w,ÎÆáHAksš&’ƒ”¤VÖ`Nœ½ÅÄ dêq-A î”T¸I³sÉñqÂ&Ù¬(çp| h÷StÝüµ xvZ-ªz²Ìòì,üQäáúÝÍê1+J˜òƒçVßÑ骞50ÕÑe$Øh8 Û_:^•y[Te¼Äz±¾Å¸õ1D|&÷ß’“+õKÃÞ'«mЏ)9ÝYI«=ÍX9ƒ›ŸñœÀ¿ûv¾ÌJãSªÊÅÙz{Ú¾„œÖŽG¯á©³NAÛ“/‚¡ÒùVn4GÕª$‰@Ji8é™ )P˜d(‰‡Î˼šŠ4ô¿;ÊÂΟÚPÎ`ÚÖ«_³E¢ÿä$aWu•OB‹éÙÕÙîtþß…î=Š HƒàSã¥Þ¨AGOÏJnH3.Â$‡= ;8"!¯ÒD 7â´=ùz0î<1—½B•EÇAh{þ§´™°«lÔi‰ñm‚r^'ì:4ÕªÎCƒ=':.ìÈFÕSG@3›…³çÌ¢d5& îAÇ;ˆo‹¢ ÂkÛP—X¸Ä{¿›´Y"™kHدÒU;–è©»©µ›ÙDïö§û_CÞ‡< Ðý©G îùÐN ØMxjו¶œýñtˆŠIN‡$þXUÚȳõFžõ1¬‹g–õü¦ÏÔ6ßzÉ»èÀƒvr€ïªøšk1pàÇý@Sv À*é{[Œ1Xf Öó8ºk±àjýl÷£%=e0œo[½¿CÌdEho²e+NhÓye¼ŒùuÌ×y\º‰ÜœîF™)¯•²t§è¿K¦F ô½u”©!^qTX^ÚÆ|„y7J&ᜅ&¯‹e[Õ>g´s1úeøá‡ÓËÉDpÜXdótwb5}dIÃ!ůþ·BA›œ _lù>ó‡~I(´w$huÑf‹"–óEÌ>iÃãp•ÙÇ`u1ÅCV“¿c,c9 lÎ ö[°’UlÉjÖ°–­¾ïn5.0™H·Þ¥$9¼¹=¿F’~GÓqÜâ»aÅÁ$½ÛK2ü¾Ê¬*kê€ãŸÕ65)ÞBíÓ»/ÞßFj{¸ ÔaGN`;€Ü‘ÏôÒ½ôÚdÔ·É`žÕ}—ä eMˆß·W’|Á$ï>ºã¢nZBůBÂ>eý;gÂ~.fíCCûß ¾#•l¹‹­Ó-l+6Ðîíлr[ïb a_·tÿšYCÝlE­(a j«"Vs§ïføÐ«yÒÅlõ­¿˜f endstream endobj 27 0 obj << /Type /XRef /Index [0 28] /Size 28 /W [1 2 1] /Root 25 0 R /Info 26 0 R /ID [<8369981844BFC4885ECA1BE4BDD06248> <8369981844BFC4885ECA1BE4BDD06248>] /Length 85 /Filter /FlateDecode >> stream xÚÉË@@DѪfü›PD"’†…8DcGõâž×uÀ )%Ü2ˆÇoJ”@¾Mée”,•Ô´Ëÿ ç×Ûr9½L\#¸ßø‘Vš endstream endobj startxref 28856 %%EOF leidenalg-0.8.9/doc/source/figures/slices.png000066400000000000000000001746361420514302700211740ustar00rootroot00000000000000‰PNG  IHDR‡á-¹¥ )iCCPiccxÚ•‘gP”‡†Ï÷}Û m—¥ÃÒ›T) HYz•^E–ÞY–"bCÄDiŠ ¢€‚Q)+¢X ŠXÐ,”Œ"*(÷GîLœ{'?òüzæwÎ93€"€Š¤¤ ø~.öìÐ06|G$/3ëãã ÿÈÇQ@¬‚%:&“ËÏKç \Ðʤ £ÀŒJJ ç€É @n3î/fÔ_>L~€ŸŠ Ñâ¾ó¨ïü¿{T¸|ABlL.Û?-VÉagú¹Ø³ÝØ>ü´Ø„ä˜ïþWå@“+pHKßÄOˆ‹°ÿo¨±¡‘üý‹÷¾€ÂüßÿÀw½´Fζïï,ª {€ôÓ¿3µ£¢…]÷xYüì¿2( LEP-Ðc0+°'po€PØ<ˆ‡àCäÃ(‚Ø¡ê¡ Z ÎB7\„kpîÂ}…g „)xóð–!"t„È Jˆ:¢‹#ÄqB<?$‰@âT$ ÉGv"%H9Rƒ4 -ÈOÈärFž È,ò'òÅPÊDP Ôå \Ô @×£qhš‡¢{Ñ*´=…v¡×лè(*Dß  `TŒ…)czsÀ¼±0,ãc[±b¬kÄÚ±^l{€ ±9ì3Ž€càØ8=œÎˆãá2p[q¥¸ÜI\®÷7›Ç}ÃÓñòx]¼%Þ ‚Ãçà‹ð•øf|'þ~?…ÿH XM‚9Á•JH$l&”:W ÄI‘H”!ê­‰ÞÄH¢€XD¬&ž"^!ާˆŸHT’ɘäL #¥’ H•¤VÒeÒiš´D#«“-ÉÞähò&r¹‰ÜK¾Gž"/QÄ)škJ%‘²ƒREi§Ü ŒSÞS©TªÕ—š@ÝN­¢ž¡Þ¢NP?Ó$h:4Z8-‹¶—v‚v•ö„öžN§kÐíèat}/½…~þ‚þI„!¢/â&-²M¤V¤KdDä­(YT]”+ºA4O´Rôœè=Ñ91²˜†˜ƒX¤ØV±Z± bcb â q#qoññRñVñÛâ3D '‰h‰B‰c×%&C•áÀà1v2š7SLS“éÆLd–0O3‡˜ó’’&’A’¹’µ’—$…,Œ¥Árc%³ÊXgYX_¤¤¸R1R{¤Ú¥F¤¥å¤í¤c¤‹¥;¤G¥¿È°eœd’döËtË<—ÅÉêÈúÊæÈ‘½!;'Ç”³’ãÉË•{*ÊëÈûÉo–?&?(¿  ¨à¢®P­p]aN‘¥h§˜¨X¡xYqV‰¡d£” T¡tEé5[’Íe'³«ØýìyeyeWå,åå!å%M•@•••çªUŽj¬j…jŸê¼š’š—Z¾Z›ÚSu²:G=^ýú€ú¢†¦F°ÆnnMiM7Í<Í6Íq-º–­V†V£ÖCm‚6G;Iû°ö}TÇT'^§Vçž.ªk¦› {Xwx~•ŪÔU«Æôhz\½l½6½ }–¾§~~·þ[5ƒ0ƒýß M “ › ŸI¹õýi¬cÌ3®5~¸š¾Úyõ¶Õ=«ß™èšÄ˜1ylÊ0õ2ÝmÚgúÕÌÜŒoÖn6k®fa^g>Æar|8¥œ[x {‹m->[šY ,ÏZþa¥g•dÕj5³FsMÌš¦5“Ö*Ö‘Ö ÖB¶M„ÍQ¡­²m¤m£íK;U»h»f»i®67‘{ŠûÖÞОoßi¿è`é°Åáª#æèâXì8ä$áèTãôÂYÅ9ιÍyÞÅÔe³ËUW¼«‡ë~×177ž[‹Û¼»¹û÷~š‡¿GÇKOO¾g¯êåîuÀk|­úÚÔµÝÞàíæ}Àû¹¦O†ÏϾ_ßZßW~F~ù~þ ÿþ­þìÊžjfö‰…µ-;— C B¶„Ü • Mí #†…5‡-¬sZwpÝT¸ixQø£õšës×ßÞ »!yÃ¥¢#7ž‹ÀGG´F,GzG6F.D¹EÕEÍóx‡xo¢í¢+¢gc¬cÊc¦c­cËcgâ¬ãÄÍÆÛÆWÆÏ%8$Ô$¼KtM¬O\LòN:‘´’œÜ‘BJ‰H¹*‘š”ÚŸ¦˜–›6œ®›^”.̰Ì8˜1Ï÷à7g"™ë3{LAº`0K+kWÖD¶Mvmö§œ œs¹â¹©¹ƒ›t6íÙ4çœw|3n3os_¾rþŽü‰-Ü- [‘­Q[û¶©n+Ü6µÝeûÉ”I;~)0,(/ø°3xgo¡BáöÂÉ].»ÚŠDŠøEc»­v×ÿ€û!ᇡ=«÷TïùV]|§Ä°¤²d¹”WzçG£«~\Ù»w¨Ì¬ìÈ>¾Ô}öÛî?Y.^žW>yÀë@W»¢¸âÃÁoWšTÖ¢Ê:$¬ò¬ê©V«ÞW½\_3Zk_ÛQ'_·§nñpôá‘#vGÚëêKê¿M8ú¸Á¥¡«Q£±òáXö±WMAMÇ9Ç[še›Kš¿žH=!<éw²¿Å¼¥¥U¾µ¬ mËj›=~êþiÇÓ=ízí ¬Ž’3p&ëÌëŸ"~ztÖãlß9ιöóêçë:Å]Hצ®ùîønaOhÏð÷ }½V½?ëÿ|â¢òÅÚK’—Ê.S.^^¹’weájúÕ¹kq×&û6ö=»rýa¿oÿÐ ·n:ß¼>À¸rËúÖÅÛ–·/ÜáÜé¾kv·kÐt°óÓ_:‡Ì†ºî™ßë¹oq¿wxÍðåÛ‘kÜ|èöðîèÚÑáG… G?žy’üäÝÓì§K϶ãÇ‹Ÿ‹=¯|!ÿ¢ñWí_;„fÂKŽƒ/ý_>›äM¾ù-ó·å©ÂWôW•ÓJÓ-3Æ3ggï¿^÷zêMú›¥¹¢ßů{«õöüv ·ÌO½ã¿[ù³ô½ÌûL>ô-ø,¼ø˜òqi±ø“̧“Ÿ9Ÿ¾™^ÊY&.W}ÕþÚûÍãÛøJÊÊÊ.¢¼P§î± cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“ pHYs,,sˆéRtIMEà 1 ¥ìl€IDATxÚìÝy˜Tõ/þ÷ÙêTwWwu7È&"¶"¢„$ †iÇàMHbfòLÔ„ïoÂÀ@Œî¸ÜEÇààîïfrçf¦#d›„‘ˆ˜HL°cK;cP P¤Y»©îZÎöý~œsªNÕûRÛçõB!„R8(B!„4 ‡„B!$Â!!„BI£pH!„BÒ(B!„4 ‡„B!$Â!!„BI£pH!„BÒ(B!„4 ‡„B!$Â!!„BI£pH!„B2„#ºB†E./çûdÊPðõ'„@#‡„’ÛË I)C !„BH…CB!„’¦æû!¤@íË÷ BH^ІBò¢6¤×Ô•ZKH!} ieB!„’FáB!„¤Q8$„B!i !„BH…CB!„’Fá¶î®â—l||1€m:‘Ùuû&€ûû9ÖbôÞ¥»8ð9ÑÇe Þy½¸Ïa›½Ï $×s€[½çw¹wsû›ÝÅĶy¯Å`Ρ?CÝÕ\`ÎÿÚøçµÙû|Ý ŽsŽç÷²÷ñîO!ÃG¥lÉ‹Á–²Yœu»:¸ÁCôsy¹ÃÃâî7Ôp¸ ç ìˆŽ‘ý,@ï ™ëõÙ0„óß<ˆ×°_§Ü:ˆ×ÿtzϵ¯ãàþ‡û¹?!„ŒÁ&¤xÔÁ J °ÝûxÜàçÂpG—ȺÿOþ?8Êø†fCÖý÷Ø8Ÿ[³ãAÓ% ÛÝè]ŒúÖ~7ûXèãscazÑ.¸_Ÿ®ÀÇêÐûkµoÇ ~áÝwwœ—Ü*ÖMm4rHH^ g䰿Ѱôqëâ9 Å­Y³8Çm²Ï§¯éÝàhggà˜{ô3xÌþ¦ÐGë¹æv«²n7Ðh){Ô/øµîôŽ‹>nç¿VoŽà5 „Ü(’à ‡‡û¹í­Y·h½Ýpá?åÙßÔ(à†;ÿ¶}¦¡L·Žäœ‡{œnW‡ÞSÉ# ¬Á©ä¦Œn{+!d4Q8$$/† }m8趃%Ì™û¾Bmv8Ê9d³Éh…ÃàúÇþ¡¾®€;‚ÜߺJBZsHHq¯5t} †·}8ÌùkîàŽ²uõsÛçñü¶#3R¶ Àmp×ååKpÔn¨ë6ƒ†úº™×’6¦BF’Ã9ÊqÇbäp ]´ý]rOðóƒ™]€ówû¥s6 â9õ¹÷w»ŒÞHæH^WúEL] É‹b ‡# 0…ÃÁÖî nÈè«ÌËP¦ß‡{»¡~mÆêu¥_Ä„QEE° !ñ€4ÄË@SÆ]œÝ.…['×1ýÙźo¨¯«”ï&„”9$$/Šuäðð0î3Úç‹_Û1»£H_å` yZy¤]]!dDhäEÜžï“(Ù© Å>¸BnDï!«†w¸A9‚Þ£ƒ]ï˜Kp´^WBH9¢‘CBúðs/Œòq‹uä0XKñå!Üo4Ïa uƒ8îh•²ÙŒÑy=² `SïdBHþP8$¤O~0<ŽÒ‡C #Á)ÐÁ}îëøC ‡ƒ9Ïñ ‡ ^l¿•^PpJ|Û 3Ø×„BÂ!!9ƒa©†ÃBÍbä^ÿìÎámî+ ,@ftm ó ¿µ^ëò‚£y}…¬Ñ ‡ð^»ì×£/þf™\m³Ëô¼<Àó¼Õ»ÍhŒàBHš4Ò€'I´QŽ”œ‹áŒybpƒâk¾4ŠüÁÛ w­\.‹Ñûÿ@?pÁãÞˆþwoCïõmÏÁ]CW‡L0|¹‹;¯BïÝÀ]p Tûkðà†`¸Éuîb€Ï-@ï^Âû¼KpÝß­YÙ×k0ØÇìí6£÷úÆì×£Î;ÿ`Áê'¼×7û9¾ŒÞa{7z¯õ\€ÞÁ²¿ïB:9$¤—yÀ-ü9€Ï£tG³ë²y€û¦xóaŒ|×0à†¾—1ðã ´Sy(;”ó»ý×_Ì~]ûôâ`Žó2F¶†BÎGá´ì`p=J7n  ¼ÃpGïÇàKª¬òî Fo @í¼Ά”ïü¶áüpú&žvÊãgM¤_R'øz çu]콆ÁçØé{¨mÞP ögŽŒ-*Þ^ ( w0|@´¥¥å8Æ.BÆ…ÃÂ0˜pH_«øüQ±Õ}<î­Yç¿/ë¹úüãíÆøðG*}G¼Ç>Ïï² ÇkäËÒGlÏñZ5À}ýoD DIˆ¡ŒÚæ8€Duwl»÷˜}±:¸a¦¿s?zOGߨÇñÞD&ø=€á‡ÛÁ¼ƒ}²Ý@£ŸuÞ¥¿¯c—wŒ\£ž·zW罦Wó5(x´æ”’ypƒÜ¨CBñ¬Fî§Ýè’†²vo¸üÇX 7°ö7Bçö牬c¬êãv ²î“oþPßxZ¼ ¹¿ŽÁ€y#úžߎ̛ŠÜÆ¢Dá” ?FAÁ2z¶£ÿ€ V «1ºëù²§O2^ϳ?ÁÍ!Ù!}(VžÏ8LïCæµ7yAkI)ÃïXOÁ2J m]ÙnŒþFàhZ_›:¶#3R¶ ¹§ÙÇSpÔnû°Ò;àíÃàŸ¿žqÁ n[”(’bw;Ü^ÉQßkii¹™.(„2R…Çkp¶'à§:¸¡è0zoþÈÞŒ3–ü &¾‘Ó¾ìÐÜe]X{ …øºŒ ‡¤øÁ0à& †„”,=q©Ã`HË5íº£·î-8e¼}™U8ù¥kV¡ÿ@<ÎHjÆôa€çÑw™Â›9>÷2_›Upgúû:ÜêÝf¨¥oŠíV&…, waÜ`ø¥–––Ÿçû¤HÑ N§ZÍ:’Ühö6ÜŸûR³™)PWoÜÀåÑô-Î~,”l•÷¸»‘Ù€|Ì,@&\m†ûs´™@•ëXãQñ œ_NÇžýÛbœÿ{áF¸Ï¿ýaœ¿.sz¯o¯ºŽãŽÂ!)T ÉhÊNL’½*À ‡/äû¤ÆÀsè½>.×èáh>7Èø±¹×æuÁåëoÉ>¸¡Ò?·èMájŒ_pòû^ûëƒa1×s}¹ß$úq20W¹ßHZö< ‡¤Q0$¤|<ˆ¬f×\sÍ—ò}Rcd7ÜÍ!þ¨!à$n;F·%ÝÕÞcÝx¼®Àãùé`öwÞ—Â „·"ë²nã÷ï¶zOx›«þ¢ÿúîöžkÏÓˆ‹½çq ¾nõÛ.z’#«!IT3’Œª`0|n0Ì[ŸdïÔ ^Pª°ŠUð—ý"*N97šÑÏ!ùERH!™  !cŠ*R hZ™ ¿®Y )uÁ ´l„Cá‚`0| À* †„”$ZOLH ie’o×# ¿×ÒÒr}™Ã:¸»ì^Љó»yø‹Écܺ[‡Çðûª¶½TðñºÏb ¾…Ýœ_‡¬¡ç¾mç;ÔçÔŸ—Ÿ_÷ÍÀ1:‡yŽ‹½ûuöq—åfïJ­5 CBŠ’| –¯ø^KKËí#9Xò‹ÏöUT6¸ëîÜÝ‚}Ýn3r—ÀðÇ*¸»õü²ã-ؽà ïÿûêhp«wYñ©•æË{}}}ü’ ·zÏåÍ8¿¼Fð8ûÐwiìšlň‚!!E„Â!É—r†ÙaáznÜ`×74ôèü‘&_zº m] wìFä· Ã›Þó >ç\…j7#Sƒm¼m€^ýºhþ×%X7Þm‚í·r ~­ƒ¥>üà¬÷ÎÿÚ{ÉŒ‚ª@@…C’Á`øZZZîÉÁŠ?’çhô©¹GýÃàqžÀùu¼™ž®ƒ;ey5ò3‚èŸO_ÏÙeÁÿÏÍãá~¸¡ì6œÿ:-Fï©g¿#C.‹‘ùZïÆù¹Ÿƒ–ýpØ…â% ¢f„!ZsHÆÛÈÃûÊ0f7vOKváü€R‡Þ}=ýãä QGà†œíûnFþô÷œ³[‡5`ðk.G[_SðÙú[{|Ð×yðXùz®c‚!!EŠÂ!OOÂ톔o]3¿Å0²öKÃ9ÎjôžÍMC1Ð4éèÊò˜ê€Ýë¯ÝYð5îkz|{·/fÙ(RD(’ñBo]Á 3’µtÃ9Nöú½B¥ìÈÜX­u~u#?DÑ)÷ „= ‡d< Þ–s0ô7˜ø†»¶¬nÇ †žC¸ßxË~Nã}®£ƒÓü}=‡àÇ‹}óÉíè Ëm£!%Â!KQ¸kÛ‚Ê5çO?wCHvÈÊqŽôsœB’ke1 ŽÔ®êã6Á 8ż¥Ü+R2(’±â—¯ø<¨®)_Áéq¿n¢ÿ&!¸‹pG ‡»5ß²+P0$¤ˆQ8$c Þæ–=Ö0¬£ä.U3X ý§djò¹öçzOßL›ÃÈŒAï CŤÜ+Rr(’Ñ–«à-C×ôþã?ÜûFpœ`è*ä)ÌàsêBñ®Åó‹\ïîã9tÁ-¼ºHŸ#U ¤Q8$£É/_AÁ°o£µ[8xœûy¿#‡o¤áp¸#Ÿ©Ë:Ï|tH-~Èõ ·öÞÿ×£ïú”…Ž*R¢(’Ñ’+RùŠóe—hl°[ã8~ ð×® $XøÚoã6à ·t×åÅsm¤ñÛíãH¡*RÂ(’Ñ@ïzwÙ€þƒ]ÜP÷æÇ¹ß;N]Çx™PÖw}[.ƒ®ÞŒáO‹ßÜ¡¸n×—ìQÃBžþ¬ìÀ[¬¢è ˽!%‰z+“‘ ßÁE `Ø¿'Ð{Š÷~dúóúá¬nø ŠÅ蔞ó>à8«¼Ûø›_àüõ{«Ñ÷¨ÕndFï|,x·zÛ…á—˜ñwéúÇÎÕ&oú±Åb7Ü×lÜ (}ñ×UîÃÀÝYò…6šR&(’‘ø<ÜQ„`ÁÛÏçû¤Š„ß·×oƒ—½0¨ nÌð>îLÕ¡ïéÞÝÛ÷幬ûçåó7QìCïþ΃õ„÷ Ðw­ÅÝpûAãZ¼ íèÝê°/þ›©ÁnôÝÛ9(R>®§pH†‹ ÞŽÜpÃØ*œßëØ/²nÀè/$m÷.ÁãÔŽãc0Ó³»án–X…Þ!q_Ö±ºà†ÑáÔåóCj®óõÏs¤ë! Á¸ÓïÃ]] w)Á¥È@ή@p_‘Cø·”ï“)âs$¥íIKBˆE’èû· •M0¼æšk¾÷ãk¾”ïó)bÁ_47¢4ÖäMdFFý7}6x·õ³ï9äwj}ÜŸõqÝh6F?wƒ ^ÁÛøo”Æ…C’Oþzâ×hC ª`0\_ÊÁðënÀ{ýO;jz#zo4I¹£‘¢ „”`i*Ú­L†äAôî„ðàHFH n$ê(ipª>_=¥©!å! wùK¯ ‡d°ž„Û&  ºf„ $¸NpÁöt¼eW (§`¸¥Q‡’Áð×îF³õþ'hC  ê„@ÈÐ<‡Ì.e·w°py_nEïbåÃÙð3å^`¼×’/çU ð>€Â!X°àíª–––ò}B„.¸Aãedâ*¸ë ýè¾dê<§£ýM,ã¥l6šRærV ð6‚ pHú…û‡ézP]3B†cÜþÉ~0ÌîÝ¿ûÍx¶ ¤`HHyT ‡$*xKÈè8·M°ð·_¶Æ—ïî(Ùh£!¥iÐÍ(’l ÉX(÷šmG0þëãAÐF3BÊÁ*P8$AÙëV·´´¼žï“"„Œ ÚhVÜ‚mý––„ä’]à¾*P8$>ªkFHù `˜Û`;”¼ø·¿ÃÙßx´™e]È´ƒÍ®@›‘Y¿êo~"$—aU  pH †„”ª@0r‹³þ€ 8¿hyܵ¦·ÂÙ{`àC(W0¤šŒ$—ao4£pH(R¨ÁØØwİ îëëײ Ž Â»_`{¸(’ÁQ ‡å- ýo †„”Úh6vî‡ÐnÃùm£÷ô­~8Ü †dpF\€Ú畯Ûü½ƒ!!¤ôP0{«‘»ÕánôÞ(²xp‡;Ï*d:ín¥`Hry™`xßpKSQ8,OTð–ò]à& †£n Ú”Á‘ Ý*ôn©¸£»¹…”Ž'1J¥©hZ¹üP0$¤<Ðzâñ1–#xÙÁðŒoKER™DÈX¡(…¥,*P8;Áu%ùÍCŠFpÔÖŽ>ÚhFÆRpÄŸ–ƒäWÙT  p8úÊâ])*4j8v(’±TZR(æÁm‡W­niÍáè¢`H Žì  Éh»n@Ü zc—OþzⲆŽ& †¤Ñ¨áØ õÄd<k’ü(Ë 4r8:.Fïu )’P‡Ì.G5= ÉxXà]º@SÊùR¶häpäÊò]) ÷à ˆÛA£†£…‚!/´Ö0¿Êº…Ñ¡`H -d}T€Œ—à¨?ýüŽ¿²ßhFápø‚Áð5¸ms(’Báîö.døh=1o´%Ê>‡ëz¸ïæ‚ÃÍ I¡ŽÒZÑ¡`HòFýó#»AÙ.¡ )Cw; TËõ])hÁQ5¾`0ü ÉøX w#ÊÐ.åñô$(¦Q8n&ÅÀ/_C£†Ã—]à& †dœøk )ŽÚh–…¦•/ ÿOKKËù>!BrX·ðõШápÑF3’/´‘lüQ0ÌÂáàÜ wK;@ß<¤°ÑZÑ¡`Hò)Xôš6¢Œ=ª@Ð ‡£w¤X×*ѨÃÐQ’oÔe|ÐF³P8ìCRLüµ†ô‡eè¨É·ÅÈ, ¡Ÿá±CÁphCJß‚ÃÍ«)’·î—.ДòPQRh#ÊØ£ ƒD#‡ç‹Â †Ÿ½« Å#¸ˆ½+ß'SD¨)´eì] `32h=q?(öFÃͤ5€þ° U …Â_òh#ÊX fCDÓÊ I± CúÃ28w¢wÁ[ †$ŸhJyìP0 ‡®`0ô¿y(’b@ÓQC÷$¨4)·‚j“Ž•ì  ‰¦•Ýož'AëHq ¶ÊÛ—ï“)T€ÔÞÜ.ª@0åi¸™;*_3xÁ ÷µ´´lÎ÷ ‘²× ‡c6šP9‡C †¤Øë¢Ñ–¾QR¨¨ÊÀè£`8 ÊuÍa0~ Iq¢n ó×S0$…ˆÖ ®ì  ‡©Go‡»=¸¾H± NGQÑëܨ)d«à®ÞZ/<„[… õÄ#Vn#‡þ» ê„@ŠMGõ*BGk GÏ“ `8ªÊ)Ò:RJ¨.Zßüe# I¡j@¦Ý%ý U åƒÁp=CRä¨.ZßrCZOL üŽ`‚Õ GO9¬9¤u¤ÔÐtTnT€*\?rT`Œ•z8¤áfRjê@á0—ì ë)’,\Oí.‡Ž6šƒR‡ I) –¯¡é(U Å„JP ÃqRªkƒë¾DÁ”ÚˆÒU ÅdwéüU G¥6r…ûw=è])= Èüa¡pHHñ¡µ†Ã3îÏ:m4'¥i¸™”:5ÌÈ®@ð`¾OˆÐF”á¡fyP*á‚!)~8,÷ò5T€£àZCÚˆ28 ó¤Öf¯CXHÁ” šRvQ'R¬h#ÊÐdW  `8ŽŠ}äÞUrASÊT€¯ÅÈ®/çŸáÁ¢ yVÌá‚!)' ¼ë}ù>‘< V XÕÒÒòB¾Oˆ! 7wƒGÍ @±†C †¤Ü”ëZOLŠ]2SÊOäûd ÃQŒá°×:‚!)eÁ(åTøš‚!)ÔGyp¨A)¶ )·ø9¨à-)/å8¥LÁ”ŠrõŠ‘ †÷Q0Ì¿b9¤áfR®üpX.%lruB ÙRŒVÁVÞ‡òùù*ÚhV€Šeä0 ÿCRf{×åðÇe€fP0$¥Á5¤¢×¹Q0,PÅ0rx'Ü!g€¾yHù)·`HÍH©h€ûó[îµIû¬@@ËF L¡‡Cê„@ÊK}½!CRjî÷®i#Jo´ž¸z8œç]S0$åªÎ».åpHH©©M)çBÁ°HÅšC †¤Œù›QJµ+U ¥hÜ€¸¥û³;T ‹HQ„CBÊX)—±¡ ¤Tk’ó+,¤`XØ(R¸Ê%RRJ¨roT Q8$¤pùë KmZêNô.x{çHFH¡Qà ÚhV¤ }C !åÌß©\Jáêš‘RÖÚˆâ£`XÄ(RøJ¥ CRꨲëzï5  EЦ• )\¥´æ0Xð–‚!)U4¥ìþœg—¦"E†F )|Å<…[Ìž:!R,_S o膃*” ‡„®ïºXÿÐP]3RNüQÃrÝ¡œ]€6š1šV&¤p5ŒüyCÁ”“Þ¥ å9¥LJ …CB [1N)g¼¥`HJ]9¯5|îÒ€Ö— ‡„¦bRöËWP0$å¢å©A‰¢5‡„¦bœR¦ºf¤Ýï]?‡ÒªI:`‚õ K …CBÈh `HÊ•_ôº\6¢P‚2@áÂV #Á`ø3¸ÓK I9X…LåÝù>™q@ÍÊ…CB [¡oHù<Üé¥`ÁÛÏçû¤'þ¨áù>‘q@Á°ŒÐ†B Óâ‘bÌÝ`3¨)O‹½K9”¯¡ e†Â!!d8¨)wþ¨a©Cª@P†hZ™2TÔ ”»”GùÚhV¦hä2‚:! †Å°il8(–19,aíííʱcÇT˜>}º3cÆ –ïs"CVHE°©à-!åQôš*”9 ‡%$‹É{÷î 8p@{õÕW+:::”àçgÍše_}õÕæœ9sì¥K—ù>_2(…²[™‚!!®[áÄÝ(¬7o£…* ‡¥bçÎáG¿õ÷uÌJ¥?¦„* ×O„€ÑÙ¶¶6­­­M€¿{üI|û‰õf¾Ï¼`'„U---/äû„É#¿#J)½¦f…â‹Åä?[qÏäîöêfÌAô¢+Pwñ•¨˜p!lÛ†i°L‰“ Ñцî÷ÿ N²wß}wý²eËâ+V¬HD£QžïçBzYï€;rð€ëAuÍÜÒ5~ÑëR›R¦`HÒ(±;w†]ÿ÷uÌLA Wá²ë¿€+n¸Žã@–e/š0’I òÔèõÓP;ë8³ÿè>ÜŠ¦¦¦È¶ÿ4²åÙÿ}fîܹv¾Ÿ)Tð–óû(—’`0\ßÒÒò`¾Oˆä…Ã"ÕÞÞ®øÁð‚†yX¸l-&L› UQ pl¦åCMƒ¬($ ¶à˜pÕ ¨š|)Îþî°zÎbÅ_¯ž¸ëç/ž¤Äq7œ…í‹1¶­º(r¾”fÑëøUh=1@¥lŠÖWÖüÏIÌLaÚU„%w=KfÏÅ¥Ó&àâÉQ\<)Ššš.˜8U‘j„Ç訨D8\YQ!)*ôº©˜òG_„^7ܱpóm99ßÏ«ÌÔØ·ËÈËx*y1€ÃÞm7Œáy=‰LÁÛ›( ÷¨a¡l©'AÁä@á°mÙ²%Òóáï¡…«pÝŸß‹S/@UHÁ…u¸ ZÇ´º ÌœX… ªuÔÕF©®FeeÂá0t= MCV4ȪIQQwÅuՌαsçÎp¾Ÿ_ép)ܾ¬‹Ñ@Üà}¾Î»ýXör­õ®¿ÔÒÒòz¾_$B @)–¯¡ ¤O‹L{{»²åŸÿ¥>ö§_EtâdTê*æ\ÅÌ "¸ø‚*LކQWJß'Ò¡i´;½,Ë2dUd’¬@«ªE䢫üÝcu±XŒ¾/ÆO€¬†û(W@Ü wÔbÜ0ùÆaä‚êš’Ü¡\ E¯ƒ¾DÁd£Pd~ðƒT2+…IW\ƒK| •: :¬âÒÉÌœX…ÊŠ°¦ ¦BÃÕ:EªjP!MC(¤C–H’ H2$YFõÅs¡×Nwllß¾½2ßϳ =àjïß/мßwÄb;€Q:ÓY„“Ré£ì¯'C*MEÎCá°Èüèç¯F`æÂ›ÁCʰ6xÿtv¥`9 \Àéœ1pîî3‘$’H’äý¿Àýwåä@KKKhH'EFË>¸£‚u>î}ìsp7ŸÜ †„äÃ*¸›Qöal7‚5?Ri*2 Ú­\Db±˜lvu@Ñ+P3e&EAEØÍq±¤IlÆ!K¦ƒî”[™&=•,»ï$Igð¢›e„jÝý(­­­z¾Ÿk{î"kÜ`HÉR(_CÈÐÈay饗ÂP=mc`ÌAO<‰Ó=&NÄ œŠèI987q2–éŽÇÌ=䂃sY‘½ñBÈZ¡è$ÀÞ½{) æÏȬkZ 1$$_J¡èu0R2(4rXDŽ;¦€ZUÛ²J& éPU§sÜþt‰DÒ€a°,–åN1»A‘A! 2÷ѪjaÅNåû©’Ì4r),~'¤Xû¨á<¸Ú.† ¿DÍÈ`P8,B‚3˜¦‰d2-‚$Ë`¬â¼ÛÅãÉtë<Æ,Ë‚iš°m œ1ÎÎ!ƒà €@e%íG)ûò}„”¹Å(î¢×óàŽFAÁ …Ã"Ä9ƒa¤ iRÉ$À¶,˜¦EVÀ˜HdžmY0 ¦‘‚eš°, Œ9Bx#‡nHôG¹c㯖/‡$Iõ­­­L×uG×u¦ª*‡ÃÌ»8áp˜åûu „1TÌE¯)’¡pXD.\h555!yâ=Ø–…d2Y–Á9‡­Û°,3ýÿÀƒe»7 †áŽ":–n›Ž ÁÀÀ 8¬Ø)$½Àiš¦bš¦Ò×ù躞3<ªªÊ#‘õi&„«`«¼±,8?‚Áð{---· `H†„Âaill4eM‡yîÌžNuBÀ¶mèvª¢BVÎ!Écpl¶=tl ‚ÙÌàsÀ™!œT˜™Ä¿üë÷ñµ¯}­Î;§{×!H$twwë…GEQxUU•­ªªÐuÝQUUD"›Â#!¤Àë¨áíp \™`HÈQ8,2×7.4öìÙNoƒô¯¶¶Ö ^gë/<2Æäîîî>w=Sx$„ g«< †dÔP8,2W\q…½gÏžpç×P1iPQãZP’,§Ã!„pw&û£ƒÌI‡Báø#ˆ6g`–‰DG`Μ9ƒf !%&8jX,Õ(’QEá°È¬\¹2þOÿº½ÚŽw¢ëP3꯼²â@0LR9Óñ™É<…ceB¢7½Üý^+³1þ|ó¶ÛnKŽäƒ(<BŠHpÔ°XÖƒá}Ô'™Œ ‡Eè¹g¾}fùò廼…pÝ4TLº’¬@’U@’Ò­ñüÑÃôŽd?2wZY0Á’'Ãì<IÑðàƒÆÆó¹Px$„àtr1Œ> 7 É(¢pX„æÎkúÓŸN½òÊ+gþëeLøÈCxÂEÕ †~[<áþGp/zPÜÿgÌy®=Gß<ºî¡®3fT‰šÁ†Çx<®9Ž#™¦©:Ž#% Â#!dêP\k )’1Cá°mÛ¶­ò•W^©îX8ýÖK¨¾è*Ô\vu J€HO- îD!¸e þáA$;þX´h‘±téRc§•…G/4Êà ?þøÆ#GŽÔ†1ïÚk¯½nqê®5kÖP‘jBJËýpân~z?Ƭ§`HF…Ã"³m۶ʧžz* 7ß|s²ººš755Ez޾£ë8jg] -RwÝ¡ÛÏ^æéhž;î÷þÌt—.[¶,¾víÚž|?·±à7ýùM›6ù!Ñ¿î+<ú× ),uè]¾¦Q0$ãŠÂaxôÑG£;vì¨Î†¾h4Ê×®]Û³víÚžööve×®]ÔöìÙÜ5…×^{­¹páB³Ð6³ÀÚÜaŽÂ#!ï~¸?—»lÏ÷Éä †XMÁŒ5 ‡n0Á0ÛŒ3˜?å|Í5×L€§Ÿ~º˜Z@• åeïÞ½zsssÈÿÿšš±páB³œ—n¸B_kx1€ÍpƒáÛpG ©O2s ˜ #‘_¿~ý¹ÆÆFsäG%…„ÂcñÛ¹sgø•W^©xíõ߆¹uþ†ÿÍ›7WËšŽÏ~æÆä7ÞhÐÏqA îP.´Ÿ‰ypG £ `HƅËÅäû¶µµUD"ü™gžé¤‘‡ò4ˆðØ70ú—º¬ÿrx\·nÝä®.hH,“{챨¿t*'NGdÚ,pÆ g ñcïÂNİcÇŽÊ;vT.[¶,¾bÅŠD4åù~e®G )’¼¢pX`b±˜|ÇwÔ·µµi É@Ö¬YsýtrNxœ9s&c°, ²,› I’í][Ò/W;wî ?ºþï똙‚®Â¬n×/@¨²ŽmòlF ‰žLüèb˜çN¢çè;è:ð455E¶ýøg‘O¬ï¤Qļ*ÔQÃ`0| À* †d¼Q8,  ÉhNxL¥R*„˜@áœûEÂs —$É–$‰£ @Ȳl(É‘±à:à æáê[îBtÒt8Ž YQ`™&LÃ@HAÓ4$“ (êt¨Uµ¨˜pμ½V÷Ü}÷ÝõÁ’Td\{(?0’²ÏÃ-pð½–––ÛP0$ãŽÂaÃY³fÙÏ>ûl'M;‘±ÖGx¬p}(‚BB¨!„@ö?æ]kB LÂãÎ;Ã;vì¨ÔÂU˜»øËøèÒÿŽšêHúó)Âi0B)(ª Y’qΡh:§cê ]ニî÷߯æÍ›«¯¼òJ›FÇ?jø §Êípƒ! †„ä…ðÿ~í®»îªÇã2CRH$Ib’$õYú¨œÂc,“]ÿ÷u0wñ—qå§¿„©¢¨ÔUDÂ*â†Të8ÝB·¬À²Lèá0gpœ9`¶IRP{ùBÎÑÓ¾kïûFýKÿñï'ég~ÜG i­áç½k †$ï(æCRÌÊ)<>öØcQf¦pAÃ<|ä3 /¨ÃôúJ\P†é0LŽ†Ñ•°Ò·çŒ!ïclËQT´0ÀgˆÎºFçqØñNlݺµŠŠÒ›`Áë##9ÐX `H …Ã<¢`HJ]©„Ç;w†÷ìÙVÕøØî@m´•ºŠ jt|â² h?“@Êbà\ 3îDUÓ ªY,ËPU ¶¬€Ë $ïRwùBœj}MMM‘… Z4½<æ uÔ‚Bá0O‚Áðæ›oN®[·.–ïs"d¼ #< Œ²w=.áñ•W^©€™ oFýÔ‹]…is|p&°¦ –²a3š -}¿T2EUݨ($@’ I´ê ˆL¿ñcÑÜÜ¢p8æ6x×O G )G`ïÞ½é?HW]u•=ØQ¿mÛ¶U>õÔSQ `HHß dι@BhÀØ„Ç×^ÿm¦}ä“`ÌÄM“£a¤,†î” !Y〻9…qÁ9„àe RæqÝ <á"ÄÄö1BSËcj1€[tF é…Ã!Ø¿¿ÖÜܬ·´´„Z[[Ïûc3þ|söìÙö’%KŒ¾JÐP0$dTñ@ÍE#ÇçGEé9pà€É-•§#TY I’‘2, ZGWÂã% qÓAÂtpºÇ=%Y’ É2$Y†û8O’ehÕ «œd ±XL¦¥%cÆ5|n@$„ôÂá Äb1ùþáªýÚf¾ª©—Bpä©÷ÐÚÚª·¶¶êMMM‘E‹=ôP,ø‹ž‚!!ãnDáQ’$g×®]aˆL» ŽãÀ¶ÝÍ%§{ÜÊ 5½‚¡i°ÌqÀçB/$ºü…¢“`œýï¼óŽFSËcâ~¸-'€F …ÃìÝ»W¿÷›Woõœ…ªWbê¼E¨štêf\ ¡h°-†aÀ¶LÄBâÄaô|ð6öìÙ~í7¯‡yø›]K—.5¶lÙÙ¼ys5Ü{ï½±Ûn»-™ïçF0<€œqX–‰d2M AQÎÿõéÃîž8LË€mY°m¶cƒs·„;Õ !àÇCE¯Ê÷ëPÊêÙ¡ühÔQ8ìÇÆ«›šš"Ú€k—Ý‹ê‰S!Òå) Ã@(”B2™€|ÑTL¾µ—]“-?ƒqö~øáºgŸ}–utt(CBŠÜûyבJ%!Ë2˜ã@ …ÜifŒ18¶ Ó2`8ç°, ¶e² pμ5ˆ ‚3ÆÎ466€~îÜ9„Ãa'³‘œ/IÛ€L›¼íù>BŠ…Ã>ƒáìE_ĵö5„t²,ƒsîN-´PªªB–e j0很s‡šÑýÞ[ `HHñª©©à¤0’ª Yq×Ú¶UsËÕ0Î A‚¨kh†{mZàÌ]a"xfôP;~×]÷H’TuàÀô0¢®ëL×uG×u¦ª*‡ÃÌ»PxœÅÈ”®Yï“!¤XP8Ìaÿþýš ?}ÇL¹|>êꢸ :³fýt‰dH‡¢ª$ BpÎÁ˜ΘWäöjèuSpºu'¸c¡ººššRd.\hnÞ¼¹:uêlËD2é¶Äóß$ªª–~Ó(ËÇ=´¼€h)Ø– Ç2Àm ±À™ãŽ «û4:„}ìc Û¶UèîîÖMÓTLÓTú:7 ¢Ò5„ …þö·ßœ³>ùg˜rù|̘z¦ÔV`B$„„é¤ow€àÜJr†MÓÀ œÙd¡è$Df\…î#oá‘¿{¬®±±‘ÚdRDæÎk«Õ°1¤:; ê§BÆèzØ›9PÀ…»cÙý}À`šlÛ‚mYplܱÁ™íCæ@pà æ¹“€cÇŽ™—_~ywöãŸ;wN÷®CH$4€Âã Ð&B†‰Âa–7V§Î~ˆŠÚIøÈË0aB=&Gøxb%&Õ„a9gã–ÙqhÙTUE¸" ÇqG ü²¢¢ú¢«`v‡yî${ì±èÓO?M ¢ )"7}zQrÇŽ•ÝGZŠ|¦7K`š&4Mƒ,+e œ pμ€hƒÙ˜c;6³!˽öG9ƒqö`öìÙ9Ë_ÕÖÖšÁëls¢M(„Œ…Ã,Û~ø“Ìûü*D¢•ºŠê°† ë+½n2*tH¸÷Q5½{QQ·‚ä†CÈ dUGíåŸÀéÖŸcÏž=aªeFHq¹ñÆ;vTÆïCÕ´Y×O‡Í0Eƒm)$’,Â]SÈçÜ Ì÷‚!g¶¹ÁRgŽ"uúHІ[n¹eXë‘Ç2<*ŠÂ«ªªlUU…®ëŽªª"‰ØªªòH$b£pÑ&BF€ÂaÀÞ½{uf¥™4>Çë„À¹@Êb8z6 Îl& ÑŽqÎ$Àý#!É~ó·#‚$A W{µÌŽá¥—^ ÓÆBŠGcc£¹lÙ²xSSSäÌíÆÔë¾™iŠ .+€$§;ž@ˆt¹7:ÞT²Ad˜•B÷{ÿ Xµò¯zf̘1&#u# Œ1¹»»[ïëØi !#Dá0 ¹¹9ÑéW@–e(²»ðüt‰J]…ép˜6ó¢O–ÈŠd@’ÿék‘:gáÀÚàΈR(V¬X‘ØöãŸE¬î3èz÷5ÔÎþ#HŠ7C ÉéÎ'Bo²[¦&½ÆÐ[gè‡Åî#oA0Z¤+W®Œçëy•Xx¬°Ùû7mB!d˜(:tH€šé³Ý…ävæw×g˜X­Ã´$IBwÊN¼ul·L…ðÖÜ †B¤Û TL¸=üûöíÓ‡|r„¼ŠF£üšÍ5›››õîÞ†Õ3? E¯€”=rxk ¹wí¤ë2+…î#oÁì:IÑðýÿûü©|?·þä#<~ö³Ÿýâ‹/çt7h°îZCBÈ0P8Ì!zÑlX¦…T*‰®s1ÑónãÃXw,Ë‚e™°mŽãÀqœL'~:”Ãnù2¿î!!¤8ø-4›››õP($,Ë’zÚ÷#yê}ÔÎú¦oEºLð6Ÿ¤ÎE÷{ÿ ÁlHІ¿]{Ol¬¦“ÇËX„Ç›nºéù›nº –e}! ½ wCÉïz€®5kÖì˺ۭp§“»@ÓÉ„Œ…ÃâñH’„P(„”æî:Ñõ0Nn“L™°m·CŠi°,N°E–7b€t-3‘Q˜0aB¾Ÿ"!db±˜|ÇwÔ·µµi‘H„?óÌ3°êë3ÑNœÃÙß½‚Ê) O˜½nJ¦-ž·9‚#uö(Œ³Âì<Ð"õøþÿ}þT±ÃÁjx4MSmoo߯(ÊüŠŠŠÜ5„çÙ´ià…Å?üÐÚ¸qã§lÛFCCÃï¹ç¬Y³&ßO¢Eá0‡dç „B:’É$É-OaÛ6 #Y’!„[ÛжmX^oeÓ0HÄašnHt§‘¼QƒLÕÌž=wÞy'^ýõ©%\F‚’+Î;×€½¯¾ÜáwRJž8‚ä wy[¸þB(áJ@vâ¬îÌÛJIѰjå_õäsa¡Éo¿ýöµ^ðÚ¦M›ž„»–pwÝõÿ‹ò“ŸÀ¶m|üãÇòåËWX ÜÈ#!ÄCá0`Ú´i¬µµñ=z×pzX‡ªj^7€s·ðµmY0-F*åN+[„㜷Œ³Ç ¥’8{ö¬˜0a‚TÆ5È)xÁ`8uêTöøãwùÁзvíÚž[n¹%ùƒü òÍ7ßÔÛÚÚ4£óÃóŽ5þ|söìÙö-·Ü’,‡ÑÂÑq»s}~Ò¤Iß=uêÔ_jš–ú¾ð€iÈ ¹î×GxL?Κ5kr>!å€ÂaÀœ9sì;v qâ0j.$܇ŽãÀ²L¨šæŽB@p‡9½ÚdY¦émN±2ÁЯsæØ°{ÎâhÇQüþ÷¿O¬]»¶ ¶„¢öövå¨kkkÓfÍše?ûì³}Õ&1có~ž{b±˜üÎ;ïhwß}w=|ç;ßélll4‡ôàd(Ÿ:uê/À¶í?Y·nÝynÓ¦M~Hìsä1ë.÷{÷óÿß?f¯Já‘”2 ‡ŸùÌgŒ§žz*š:ýœd ðF-K‡¦…¼6Y2,ËrÛäy]lÛ‚cÛ`¶Û !SËÌNïR„`0cî¦Ä%K–þcŽu÷ƒ;ï¼gÏžÅûï¿_Má‘íß¿_»ë®»êãñ¸þ|³µµUï:ø:&̽¶``Ž[5!+*$I‚cÙPCš»ùÄqÀ9ë]äÖ±Á½nî´2GüÃCp’1HŠ†ì©©þŒ4<Ξ=ÐÑÑɾ¯?òX`l É›‘C2î6cÊÖPx,>íííÊúõ룭­­}–Iò?÷ðÃãæ›oNÞsÏ==ô³ùd4Ë7ß|srݺu±|ŸéÓ*dÚã݆òššš"‡Ò6oÞÜ™ïçUÈ(öá¹g6žYñ׫'¦N}€ŽÎÔ^¾•“/ñz%ÚdùSË‚§ ^ Î`v@÷{o™IÀƧ6åÚ% ¤”Q0,* †x.ß'4Ö¬Ysîèç_¸PQz¯ôñƒ"E¡(»ð¸uëÖ*«§Ñ© Xòõ§1õ¢€ ªõt·²DÒ †²,’;³Ç9óljg] ½n*Nï{­­­ú–-["To´oû0wî\{û M§–ýÕ“¬Ø)t¾û+$O½‡ÚY×BVC$x-2ÓË‚ƒY&Ç"Ùñ€ZQƒçÿñ;g†² ¥˜ 7<& Â#ɧ`0\¶lYÜ//E Ò/{ÿ~îîä² I“$©ÏêcmB–e@Þ4öîÝ«755E qÙÿÀe—^¸hB%L‡£>BgÜòž‹” …Žãµ´µÀm’¬ \7uW4âìþWñüÖª^²dIŠêŽæFá°3fÌ`¿Ùý[¶l‰<¿õŸª3GqâÌQhUuÕN‚VU YÑ „€;³û4œÄ¹ôýéÎÀá1kŽãÈÞµdš¦ê8ŽDᑌ%¿³ Ü{ï½±Ûn»-™ïs"}j€ ëàCê›0ÖáQ’$[’$žð‹Åäµ÷>PW-ùï˜Ôp*uÖU`jm ›A)nÊÓLÓD(¤C éÐ4²¬@…ÝAæ rò¥Hž<‚Ôév,[þÕI¿yåÅŽñýŠ ‡ƒ°råÊø’%KR›6mªùÕ¯÷†íDìDß›Ž-Zd|å+_‰—êháhòC…G2^}ôÑèŽ;* †E `Ü`¸ ‡l¤áQ¡ !€<„Ç­[·V1+…º‹¯ÄU7~Ñ·"[]UWN¢3nâlÜ‚a1DÂ*N÷˜PUŠ¢@’$¨ª UUaK2¸,Cò.µ—/„ÕsV÷ilÛ¶­’~œÂá ͘1ƒ=ýôÓ]€[òb×®]á_üâ'OžT&OžÌ>õ©O¥.\hQÑÛÑ5–ájjjL¨ªªòÇêïñHq£`XT47¨‚ oÌ÷ •¢Bo¾ù¦ Ÿ‡"gÖbÆMÇ»’°án<±↿Ë[‚¬(nÓ E¢¨¯ÒÜ=²ª£rò¥èùàm8p@Ë÷× Q8†¹sçÚþ¨`SSSäSŸúTªÜ§óe´Â£ÝÑÑ{†áñÇßxâĉúÎÎÎy×^{íPÛ¼iooWš››õcÇŽ¥ÿJLŸ>-\¸Ð̺!?F"¾~ýúsôF® ÍP@F&ŽjX28ù’$ÙÝÝÝ¢­­MSô ÔÏœ .29’qSÝ&l‡»›OÇS’$s!î6À†ÒЉ¡çƒ·±óå_TÒF´óQ8$%m¤á1‰\}Ùe—ÀÞ…ºŒ£X,&oݺµêG?5bvõ½4H­¨Æ­_¸9~Ë-·$³ƒb,“ï»ï¾ÚÖÖV=‰ðgžy¦“–|®mÛ¶UxÞûߣ `XÐFe/8žEéÙ»w¯5^ΘÃH¸ ZGgÜ‚íp8L@Q$$ŒLmHDZÝPȹ;V(I °¥ÌIÉ2”Šj(z˜™Àþýû5úÐ…CRÖ ëÖ­{øý÷ßbΜ9Ç-Z´Ô:kÜìܹ3üè·þ¾ŽY)€¢W æÂË¡VÕApÎ#ø±ƒpR=hjjм°ý‡‘¿^±¼Ç/Q‹Åä;¾­­M£`Xø‚…$¼ †Em ð@æœk$!„¸;¨8µªÖ-pm0N÷„ ³w±ðÓ=&R†Ër/¶cƒ ·” x°²Hæ>zô$O%ÐÝÝ-çûu*4 éÇ‹/¾x€ùî»ïüáx^ÿVê»:úb±˜üØcE÷ìÙ€ú™WáòO} 5S.c¶mÁ2MF ¦aÀ6 ¤N·ãÜï_G¢ãؼysõw_øIuÓ?={úþûﯥ`X‚ëA< à/ò}Nd\ð@ÍÅ`±0pÎaY&’É4Mƒ,+jÎ;Hʰ`¤R°LÓýa¹¿'‚µý’sð¦¨%5”ïç^°(2ÃhåHÿBá1 ½½]¹íÏoŸÄÌ´p._ôEÌ]üeÈŠÁ9Çe¹ÁPÓBP)Y.˜½vzÚ÷ãìþWaž;‰?ûâ/€˜5k–½aÆ.ªgV˜²§ýï¸ãŽž§žzê§ pHà†ÃT*MÓJ&!IlÇFH AVd@Œ38¶ ˲`)†-Ë‚m™îºCá¶¹gé®fbä'X¢(2†Û:+p)ëðø•»˜ÄÌ¢ÓpÃ_­ÃÓ/Eee8ýùdÊ€aÐ4Í+WávB\À‘éWB¯›†³û‰Ô©÷!É ž}öÙ¢ìNT¶mÛVùì³ÏVÇãq98ºûÔSOåûÔHžMŸ>€Ý}¶e"™LB–pÁ¡Û6Lo72gî{>ÆlÛöf ˜¦Ë2Áï=¡ðWðô¢Ñù! ¦¦†~?d¡pHHZgå4VáÀ¾5kÖÔZ®-[¶DzŽ·A WaÉOã²K/A¥®¢JW3닪uœî £K’ À‡eYp̱Á¹µ"‚ú+¯ÇÉî3pŒ8¶nÝZEÕ K{{»²~ýúhkk«óçÏ7|ðÁîßg>óã©§žŠ&O½Ëp+N¹ÝOlˆ¢ªPœsH’ Æœôè¡é-;±-Ì1Ám·KŠp,î@pfô€™IHŠZnr> ‡„°± Þ}74v!÷­[·nò¹sçdŒcë¬ööveË?ÿK5,øâ×Ó½S/ª¯D]UqÃÃ9Îzm²€(˜ãÀ±-TTVz£&¸cCÈ ”Pj/ÿμý ššš"K–,1è@aزeKä_ÿõ_«üÑÂûî»/¶téRcäG&¥$òY³fÙmmmZêt;pÁÅÂ]Z¢ëº[ÇPV O—­q–eö-8–æXŽí^˜ á­=œÁì: øÜÒÏP­Ó(’qµÿ~­¹¹Y?xð æo8ðUH>ý¹Ï%çÌ™c¶v]¹…ð¸À»©1sæL>|–e[ë¬õë×G™•Âä9ŸÀ¥×¸§2½¾SjØsaÇ»R8ÕmÀtxzQU5H² Å+x«(*lY$+zÝTD.¼ñâñÇþÛ¿ýÛ™|½ÊYöhá¢E‹Œ‡z(FSþ¤/W_}µÙÖÖ¦u¾³S¯» ¶ð{&›P7úý”ãàÜsÜ‹`8³! œYàŽ î…CfHt´æÌ™Cos pHÆEöTßLUE…$á4c8Ã9vìØQ¹cÇÔ›z4 '<¦R©?BL„[—lÌ[gÅb1¹µµUWõJ|ôOVCUT\P­Ãf)›¡3nÂrxº®™OVhšUQ!Ë2dY†$I€$’ Y !2c.Rg¢­­MkooWè ÇøókUþìg?«¤ÑB2+V¬H¼°ý‡‘Ô™£è:ø:j/ÿ8sÀ¶¬@–e·¨µ¿žP¸›Ms¼‹í…Boä;Œ!yü ˜™„ZQê’”…C2ævîÜ~â‘Gêœ#¢(ø\mf…ÃøXE%BœÃ²m$MÇ,o[Þµm¼mÛhjjмò¶È[·œ¡)Á±ÑGx¬p}(—ÖY/½ôRª/œ%$·fÙ„HBgãwC¡*Kc»;ý.²×7p›!¸m²BУ“‘4Ž`×®]~ýC2ö²C!@£…dh¢Ñ(äáov=üðÃu±#ûP1y&B‘zE…$+à’œîx!Ü&Þ´±8³Á+ý1ó\<ÿߡل>P8$c&{´ðÚš(ºì2̨¬¶ãÀ²l¤ šªB•eLVT\§sü—eᇩ$Nq†åË—O¤QÄüëÖY¡P¨ÃïmZ3åȲ Çq§ÏÆ-hŠŒ”Å`Ú B¸=U}îBt ’7j(ü²’¯W IÐk'#yò¢i˜¦Tc·i`¯i¢©©)2gΛ¦¢ ËÂcºûeÿÿ?®@tæ¹ä¦ÏN6»:pâ·?FÝì…O¸È›)Ü÷‚Âï‚â¶ÎËÔ4t/©3GÑýÞB0jE5h°¡ɘعsg؆ÿrõµ˜[SƒHm”)SÀNœ€2e Â'N ÔÓíÖ«ƒû³Í9ã̶•eÜ®@$áç†õëÖÕ566ž¤)©â‘û öR8‚D"UÓJ& INà ƒAÉ”[Ç̲L·‚cƒ1Œ9nÍ3Á½QD7 Ê^?°ÑÕÞÞ®üà?¨¤PHÆJ4å[Ÿß|fÕ×ÿf¢8‡3ÿµ‘éW"2ãJȪI’2?ó^@w× 2Ë@÷{oÁì<ÀýÞ|òÉ'Ïåû9: ‡dÔÅb1ù‰G©€åÓ/ÂÜšÔÏœ µáH55P/™ ÞÝ ÀíÄ…p‹—Ú,Û†n‡`3›sØBàšŽ#Ãïÿßg>3ùß››;òýÉès[^™H¥’P€ãØPU œ3Ȳæ8°l ¦a¸Ët?æ»õ¤gÚd‰Ìt35±XL~饗Â?ùÉO*ÛÚÚÒÓõ ÉX™;w®½÷Õ—;üþÛñcï"uæèÑÉÐk'#IÕ!ÀŒ8Ìs'aÇ»`t‡`6$Eê•ÕC뎇Â!u=öX4Á9®©©Áš+®@´~”éBmh€tɨjooWöìÙŽ( ¾lôPÊ”)ëë!××A½d&œö£âqHÕ ÇÍxª¢¸UqëÖÉ24¸ß Š$¡J’ð)=ŒF ?ýéO+)–ŽÙ³gÛ­­­z÷û¿CÅ„ée Âí£΄C^¡[¶åŽ2&qض Ç2å+œt¹ Ál˜]î@ó‚ h4kÚÛÛ•]»vUüô§?­ìèèPüÏŸ?ßüô§?mP)2ÞæÎkÿÛ¿ýÛÿ{óàÁƒÚ¾}ûBÙoX¨fîðQ8$£j×®]ðÉê\TYé¶5;qêÌà‰œÚ!R)Àq‚{Àƒ$ËÜ"$nÝ:I‚$üâ%³T¿‘dttt(T³®tøEhÍ®ãp,‰8à8 ºnòL¨šYòÛdŽã¸ÁÑ2a[lÛr[ç9–[¶Â‰œA³ûT¯Ç!ó‹Õÿâ¿§§NÊn¸á†Ô-·Ü’¤Ÿ?’o3fÌ`Á‚k®¹fêüùóÍÍ›7wæûÜŠ…C2ªür!—W„Á9‡âÕãÝ=Nž‚ˆ'æ€w÷@™ý Š¢¤§eY†iZéµbYrG“.Tt;ÍÍÍúŒ3hÄ¢,]ºÔxøá‡‘:ÝŽÔévTL¼œ¹­ñTMƒªª¤L©wó‰;½ì†B¿5V MwÎऺaÅNp{µæû¹W,“Çz#Öþýûµ]»v…_}õÕŠà¡? síµ×šT-€ò@ጪ–_ý* •UBÀ²mTà]€ã@ªªr7 ¤Rà±n°'`'°c`^QcMSaYn]€Q0I‘qÀÞxã ¦³JDzeËâMMM‘3ÿµ ~ò/Òå'lK¢¨€$ApI– 8÷>Ÿ%LZ^Xt?ß}Ä-]±hÑ"£˜w¹á _¸àŽ;îèíïù;w†ßxã =¸†ÈŒRù(BÊ…C2ª’B`¦ª"Ä8’)z(­;†JÿÝ™ÒRìÄ €Ã˜»¡€q8ÌÃÜšv½ªÕy£FÕ’û÷«§§GølH±X±bEbÛ±b§qvÿÔÏùcî¸]d@ðË-ÒuÌÜvXÞ:CÇï„à¼xV÷iHІ‡z(–ïç8\û÷ï×âñ¸ÜÝÝ=âR<þtqKKKÈïqì›5k–}õÕW›K–,1hc !åÂ!u’ä¸6M„R)wÊÈDLÀ´,¦ Ã4‘2 X– Ûv`swG`B€azIQŠF£|ãë;ï¾ûîúî÷ÞBÅC¯Ÿê®C•@’¼NÂí„Àý>ª¬×&¿‚“Œ!q¼ ð躇ºŠyÔp×®]aX¸pá7Ô´··+ÍÍÍú´ìÑAÀÝTrÍ5×XK–,IÑBBˆÂ!u8LÛB<™„ª( sÓ4¡ª*8çn›4Æ`Y Ë‚a˜H&LÛ‚åØ°†°½`èÀ ‡@cc#¾üå/ëo¼ñÆäªª*[UU¡ëº£ªªˆD"¶ªª<‰ÐÈG‘ill4ýéåÓ­/¢nv#*§4²âC¯Mé‚ì€éz"Ý aÑ¢EF1O‹Æb1ùg?ûYåÔ©SÙ`Fób±˜¼wïÞ{­zO766ZÅš !c‡Â!US§NeÊA#…+% ª¢€ ‡9y› dI­cç÷WöF Ó„å8°ôÅ[(›8Í4Žãrww·Þ×¹(ŠÂ)<—+V$:¤µ¶¶êgßyÉ“GP;{!dMGfj9» ‚;ÅÌ,Éã‘èøwT¬˜§“àþáªãñ¸¼~ýú>w_îÝ»Wonnù¯[ðsTÒƒ2ɨºá†RMMM‘·m—¨¶Û+™sØŽªASUwS`Œƒ1˶aÚîè¡áØ09‡åÚÑC&>d Ç÷îÅM7ÝtnéÒ¥F<×Ç‘½kÉ4MÕq)‘HhŒ1 E&òÍ›7wnÙ²%òüÖªNi‡yîª.¼zíhÕõéÞÉB@p8©g!uê}0Óݯ±lÙ²x±÷NÝ»w¯¾cÇŽÊùóç›ÁŽ#ý…A 3U¼páB“ÖB†ƒÂ!U~-¹¶%aaÛ`"Ýv;Ÿ¸eIÜ !lÇíŒbÙ6,Æ`yÁпØBÀÜÍ.Ç™;ðÑØØh€âjkks®Çix|üñÇ79r¤Î0Œy×^{íýöèZ³f;|¿Ö¥låÊ•ñ%K–¤Ö¯_mmmÕ{>x=¼ YÕ VÕÁ=˜™HBP+jðü?~çL±‡¢X,&oذ!êü™7n¬î/ Ξ=Û^¸p¡Emë!£Â!UVX’ðÇA³iâÚPŽmÃf ªlA•eH’˲¡iª»Ù„s·—2…&¾8pG ÿÓvKÛ ¥,ÉHÃc$¹zÞ¼yp€ þý6mÚäÿs·w½/øÿkÖ¬Ù 2"3fÌ`›7oîܹsgøÀÚ¶ý{„™IX±S½n§„*°tɧ“¥R‡/‹ÉwÜqG½¿^pãÆ5ÁÏS$„Œ5 ‡dTE£Qþ—«VõlÞ¼¹úG©$.UUDe6çP9G°(‰iYîndŽîÃ@8 N-À~g»ƒA_ùÊWF­uÞ@áqݺu¿ÿþûOÌ™3çØ¢E‹vhP`w½Ø»©}?@áq4-]ºÔXºt©±víÚžöövåÿïÿ]óË_þ2üßþÛ3¾þõ¯w—Ú:º—^z©WW’~ô£æ•W^Ia2n(’Q·råÊø‹[¶Te ÛSI,«¨„&IP% çW¬Ë„CH‡AÓû·¸øé-[¶,>žS†/¾øâ!æ»ï¾{ð‡?üáÙŸß´i“ýk chÆŒlÊ”)L™2Å)µ`¸\º»»åýèG•§OŸV>¬]yå•öUW]UÔSå„âAጉǶn=ýW_ùÊl¯È®×ÃP…€"¹Ý“%dŠ\ûu 2áÐãBàÓ@˜$+(´Mµ‡9Ã…G2TÑh”¯\¹2¾råÊø¶mÛ*_yå•pSSSäÕW_­xàb4zHkɨ‹ÅbòúõëkýE{Lï9>®@½,C IîŽe·v!ƒ[®ÆñþÍ„À￱LXB $Ixvû¶SÃ<¥¼¡ðHFâ¶ÛnKÞvÛmÉ-[¶D6oÞ\}÷Ýw×ß{ï½1jIKɨòÓ·µµi³fͲ?÷¹Ï%ŸýÎw¢íŒá_’ \­…pu(”n‡ༀ˜¿µLüÞqÛèM’<»}Û©RœBFxô¤¡ðXV®\_¸p¡y×]wÕ?õÔSÑêêj^ ›o!…‰Â!5û÷ï×¾ñoÔutt(³fͲŸ}öÙÎh4Êo¾ùfã±Ç‹îÙ³'üËÄ›¶…銂‰²Œ d%=½|Œ1œá,]®&$IX¾jUÏÊ•+GmJ±Dx EÔqDáqݺu“»ººòýÔI–¹sçÚÏ<óLç]wÝUÿÆoè !c…Â!û÷ï×îºë®úx<.ƒ!஡zúé§»vîÜþÿïÿEÚÚÚ´ÃŽƒÃýoÑ¢EÆš5kJn'êh[³fÍGúúüpÂãÌ™3Ýâä–Y–M$É\ Y–mP»ëq7wî\û'?ùÉé|Ÿ!¤´Q8$#Ö_0 òK’øý_ßxã ½¥¥E?yò¤rÙe—Ù×\sIå:F×pÂc*•úS!ÄD çÜ/ºœ³X¸$I¶$IœÂãø¡~È„±FáŒH0Þ|óÍÉuëÖ ØË6r?(nܸ±º©©)r×]wõP(}„ÇZׇB!!!„ @B(dÿcÞµ&Üõ£‹@{{»ÒÜܬ;vLñ?FoÈ!Ù(’aÛ¶m[åSO=€ÁCR\$Ib’$õ9µOá±ðµ··+?øÁ*÷nÛù€9ç}¾©© @¦'s9¯ñ%„¸(’a¡`H€ü„GI’è÷Ö mÙ²%ò½çŸ¯Np7gGdÑØ(Kà^ëÊ÷Ã!ÛFkk«ÞÚÚªÿäù-Õ¶n)úþÔ„á£_²dÈ(’Á‹ð(Ë2@Q”ˆmÛ:<ž¯½½]ydÙŸOúåÎß­Å_Lž‚Ùà‚Ã0-¦‰”iÀa '- oÛv¤R8É–/_>qÙ²eñB+:OɃ!ã%#5Px sÎ5’Âï7\@š¶>ßÞ½{õÿæoê㜣ZUñðe³ð¹©SÁƒ¢(°¦i"eš%5$RIL % ³T »Œ^3M455EÞ|óM½¯ f„ÒEá Ú£>ݱcG%@ÁŒî—Ó`së`FcñP(”È^`”½ë² ±XL~üüú8çXé8˜SU…gç_ú™3!E"¼¡Vaªª¦C!ãc°ǽ–$ÌÖ4|À?%hjjŠÐŽfBÊ …C2 †¤ˆVxÌÉ›w²Ãc>žèÞ½{õÉàáËg£vâD€zYäš(„mƒûoNœ@ç0, ª¢ ¤iÐC:,Æ 1MLWU\Òñ†eâ›÷üMý_Þu’¦— )I¿ü`‰Dø3Ï<ÓI;I‰ixô7ÒädÛö¤\áq,F¿µvm=üå´iX8e ”)S \t!Ô‹/†6gì?ü’,¦ûtõ'Pa°m¶cÃ0UÈ’$ ²¸A×ñ¾ãàg éeBÊ…C’S,“ï¸ãŽú¶¶6‚!)cà 𦩠}<5<îÝ»W?ͦjîžy 4ÕûÕn˜)¼§°lÛ‚p2µE,Ë鋦(9,Š?Öñýd?üþ÷# )KX{{»ü÷`ûS0$dÐú S  ÉÈã`Ãcsssþ¸ºŒsHÞ t` ìÃ!leHš–>>c œsp.`Ù$IJzGÀ$YÁ²ŒÓœcÿþýý. ¤ôQ8,!ÁžÅÍ/¾Xy†g–}ñ‹_œ4uêTvà 7¤æÌ™c766Z¹ÖƒáÔ©SÙã?ÞE ¶áŽ<‚s®eY6UUí|óÍ7uXP,Ip;q © ¤žJ€qðxìÔéàýÓ—°†iYB@È^Pœ®¨8Í-477ëôû€ÒGá°Dìܹ3üĺuu‰ÀâùIŠ‚‰²JSSS¢²Œ¿û_ÿ«3¸±½½]yàêÚÚÚ´Y³fÙTߌ17PxçÜŸ¢y×ZðãÐÖÖ¦UI2æê!ÄIDªªPé}Îy¿r´Æ=V¬ÀNœ€ïeÛpsà8N:@pÎD¯ðxKKKhåÊ•ù~Í!cŒÂa‘‹Åbòƒ7ß<ù·†ûwe~U>VY…‘fªÇAÊ4`X~o™xÛ¶±×4ÑÉ9î¾ûîúeË–ÅW¬X‘8zô¨r×]wÕÇãq™‚!!…#û-%s±ªÀ²m¤ ÝgQø¼?’V"Ó4ay#…Œq0Îáx³ ¿xo6uššR(±;w†Ÿx䑺ç¨V|å ±bÆÅpƒ"˰,†eB7BH¤’˜#˸XQ±XãÇ©$öx]~ú ‹d2)Q0$¤8 ¦e!e˜ÐÔ”Ûf°ó,B¡Ô÷’`œC–$ØŽËòÛç™H¦R0L–eÂá6[8BÀ[—G˜0aæÍ›§œ;wNWU•G"š^&¤DQ8,RíííŠ ¯Fñ÷s?‚YµµP½]жãx( hjÒë„ C aÛøÓŠJ\©…ðãT'’Ié£ý¨õío»‹‚!!Åç€mÃr$R)(Š; Ì9‡jšÐTœsȲ Çq`Û6 ? &LË„ÅlÎa ¿X#ƒÛ&Æ×]wæÏŸ¯8p ÞLEQxUU•­ªªÐuÝQUUD"›Â#!ÅÂa‘zäÏÿ|R‚sÜ8a"þqþÔNœeÊ”ôçµ'P @íê„à{a°ª¸XQ°ª*‚ÿ›Hàæ ûwB )>³fͲÛÚÚ´ÖT $ €ç¶ã@iP’,{SÈ ŽãÀ´m¦Ã[vb:Ž;jˆÌÈ!ÇÂÇ>ö1«¡¡A@ww·Î“»»»õ¾Î‹Â#!ʼnÂaÚ²eKäw¦‰jEņyóP?s&@½x„i@ é#Uàñªô"sÎyzJ‰YÜ?KÃaüs2÷;wî /]ºÔþÙBÆÛÕW_m¶µµi¿³m\iÛ€°lš¦ASÈ’9c–mò­t0´„€%l!Ò!ÑÀpœ9è9t—\rI÷UW]Õ+Ô;wN÷®CH$4`dáñ³Ÿýìì_|1ß/+!e‹Âa‘iooW¾÷üóÕðÍË.ÅÔšH‘ÔˠμÂ0æ²w[ié¡4MCHÓ È2Y†*ËPƒ `¢¢à-„_[&¾µn]]cc#µÉ"¤ˆ,\¸ÐjjjÂ[¶…Ï‹ pÇÓ°l šªBUTH²÷Í¢ÃÜ>ʆmƒ Ó †fàߎ`8Á9z„@•$!W›ÚÚZ3xm8áñ¦›nzþ¦›n‚eY_…B/èpĻޠkÍš5ûòýºRª(™üà• ÎqC´ŸŸv!´Ê*€\…vÅlðDìèQH•éòÊ{Iï„‚PHCH Áp(œC €Oè:>`Ž2†íÛ·W®\¹2žïçJœÆÆFs²¢à$cøI*‰?©¨ã¶eAu(² g’"»KL¼h  H‡CÑà¿4R€?ùò—‡õ;a ðÇ5ÇqdïZ2MSmoo߯(ÊüŠŠŠ€Å¹î·iÓ& Aá‘QCá°Èìݶ=1y²»v(•„@Øìß·¶a;w›'°'À8÷JTH’HRºû$I€W®âJ-„£,EµÌ)B¶l9³|ùò‰{L—¨æ¨*4I‚ÊÎÓ?óp88æm<ñ§‘ƒáÐñ>þ–m¡GÔÉ2ƪuž¿ö0o¿ýöµ^ðÚ¦M›žP`wÝõÿ e‹H{{»òsP%˘]Q EQ V¸¥nyg ðZdñžxºà­âu@¼B¶²$A°Ì Ù»\¤¸Z[[õ¡!$ßæÎk/[¶,ÞÔÔùI*‰IUTË2TŠ™–zp§–ýÝÈv Z^Pt„@;cøíÎ"oܺõL¾žW ÄíÎõùM›6ù!q8á1xÜ^³fÍšœGH9 pXDš››u˜§‡áx;žn„½Ï Ótû¦Ú6Ø™³éû9Œ1áõPåÂZ’œLÁ[ @…$áBEÁ‡ŒaïÞ½z°{ !¤ð-\¸Ðú~SÎqŽÿ›L`©Æ…ª €äõKö \û£‡~0dp7 8B ÍqðËýñ_¶lY¼[æbxô¯ï÷ãRx$eƒÂa9vì˜e –m#™2 ë:EÝ|ìÄ X‰8 Ài¹»9ç`Œ¥§”„½î3QvÃ!!¤¸lÛ¶­ò©§žŠ@N2†ï&øãŽOè:d W8pÃ!‡WÓP$„Àk–‰÷0þ|s¬¦“Ç …GB†ŽÂaâ\ ešPUwƒ‰,I¨àzV>4zºÝB·–‡1·cŠi´íô‚tjÉ;’¸!Å# o¾ùæä=÷ÜÓ³uëÖª¦¦¦È¯-0Wi!ÌPè’=àˆ Ž?8Þ¶mXB $IX¾jUO9lL£ðHÈù(!Gp¦¦"‘twZ¶ Ý4!ËîND n—˶a’† Ã2aÙç½Ö‹ÝBàË_þ2$Iªã7¨€-!. —-[÷GúÖ®]Û³páBëÞ{î©?ÊŽ2÷wÅDYÆ…Šû«ß­a˜A˜?¾ùàƒÆf̘AS¿ðøío{úÉ“'«9çЫ§6!ãŽÂañk™½kÛ0‰d ²$ƒ î¶Ã2M(Š’Þ™Ìƒe{mô¼6Y~Á[#PðÖo‘Žb·ÉdÒ¿?u? ¤€mܸ±º©©)÷Þ{oì¶ÛnK?ߨØh¾øòË'·oß^yðàAíõ_ý*|†sœqóGZD’pÃç>—œ3gŽ} Ò¿„Çï²êëëÑÕÕÇ›Ò÷ù!Q’$Û»¦ðHÆ…Ã"ÒØØh†% GÃ)ÛÆ$! „Û"ËÔuhªEVÜ '’ÆxfôÐ42M˜Œ¹5Í€^­²Ü©¥!°ý»ßÅ×¾öµ`lºPx$dä}ôÑèŽ;*ÜÁÐFypzxïÞ½úO~ò“Ê_þò—á¯~õ«=7ÞxcŠF ÇÎ Âc€†ŽŽŽ¿·,ë EQd!„"„P… çÜÿ›ów-…G2(™O|ò“Æž={¿³-ü‘$›æŽjª EQ IRºM–ã8°ms`1–î€`f:BàÞ;Ö>÷¹ô™±è~àS…_yå•bùòå$©òرc…GB6Ø`˜Kcc£ÙÜÜ€9sæØ ókÍš5GàÖ`ük*^I1Ÿ(BÀh…G™¥ædŒìß¿_knnÖ[ZZBÁO›6Í™3Ç^¸p¡Yˆ?ƒ‹ÌW\aïÙ³'¼#•Â媆Z¶e!ĘÛO’ÒáPp8wËÞxõË‚üpèH ·½šfsæÌt0jx4MSuGJ$cLŽF£øøÇ?á£G†ƒ÷¥‘GBÎçÃH$Âï»ï¾õB/m’$1I’ú # ’$Ù’$ñ@x´ #³qãÆêŸ~ÿû‘DVE_kk+vìØ˜5k–ýo|#VH%£(™•+WÆòü–ꓜa—‘ÂÍá Ø’‹1¨Œ¥ËU^© d6äj“å¼}Í2a E‹£¹æh ðøÜsÏEõ«_U~ík_KN›6g‡Gš¶&Ä‹ÅäÇ{,ºgÏžp$áÏ<óLg!ý1!ù1Òð(„м’fGA{{»²nÙ²Iû-w]ïez«¬Ä¥¡®T5hÌÁQÓÄÛ¦‰wl‡mmmÚòåË'7”å…Ã"ôÛ·úó[n™ôšib²¬à£¡4! JÒyá°¯6YÁ`Øj[xßq’$<ôÐC±ñ|.ñxœ:tŒ™3gš9>^ßÕá†G¨­­µ¼kZCŠF,“ï¸ãŽú¶¶6‚! ãgË–-‘}þùê8ç˜¦ëøŸ3/ÁÂÚZooƒeÛHôiš†OÚ6 !ð£T{LMMM‘W^Øybë–3ùþù¦pX„f̘Á®¹î:ã׿þux‡‘‚&—ªT!ÜieïvÁB·Á6YN ~ÀXz:ù›>ÚF ê‡9WßÕ ¡†ÇŽŽŽ^÷¯©©1 ªªÊ ¤ P0$c‰ÂãèV¸qâD<~ÕU˜PQ ‡1(Š; 5hI²¬É`ÛøBE%.U5ü(•Ä)ΰ|ùò‰ÿüÏÿœ×€Há°mÛ¶­ò׿þupë”5%“¸&¤ca(„JoôÈj“…LHt„@R¼e[éÞ©7ß|s²×.Vxô¯³Ããã?¾ñĉõó®½öÚ  ¶dƒá¬Y³ì 6tââuRº(<lÿþýš ›s¾<}:j'N<ïvñs]ÐTÕÝ€s.˜ã`ަaµÁÏ ÿe[¸wÅŠ‰;ûÛŽ¡žËh¡pXd²;!TWW󦦦H‹eâÇÁuºŽÝnÙ}T9€vÆðÓH¾-¤u£m¤á1‰\}Ùe—ÀÞ…ºq±ÿ~íßøF]GG‡2kÖ,ûÙgŸí,´‘}B†%!„æ}LBÈÞuчÇÇV­š˧OÇ—§OGýÌ™P¦N‰B€8 ˆÀ „Œs0ƽj"6lÆ` ¨,cq8Œ÷™ƒ3œcãÆÕùúÛLá°ˆƒa°|Å’%KŒ{W¬˜xŠ3ü8•D$cº¢`¢"£ZrÇc‚ã4ãx9°¼PX'ËØ¸ukÞ×6äÓ@áqݺu¿ÿþûOÌ™3çØ¢E‹v‚Zg‘q°ÿ~í®»îªÇã2CR̲Âc®Ù)™s®aô£Ì9×Ç+ aZ@ -¢¢(€W“X’$hŠ‚ãÀ–$( ®ÖÜpèÿ o Üp:!̘1ƒùí²®¹æš©°nݺq-QC\î9Qx,-{÷îÕýî#€[ÚbáÂ…æ`¦…¶mÛVùì³ÏVûÁ~f ”`xçÜQUµ3ðùFý49å Þh¤}àÀ .ÓuH²»„K™2$ðS§!UUAØ6sYÎ>.$H°l –åþzÈÞE—$\¨(ø1ìܹ3<ÞF)°`'*_Qšò÷è°oÍš5ã>UQжmÛVùÆoè-¿úU8™Õ aóæÍÕ›7o®K>ñÉOŸþô§S¹~Égo4£`HȨé´õyáQ–eSUÕÎ_üÇTÀÇ«"°, –mC?q½‘*+ÎÁ“IðÎ.°'ऒpŒ1pÁ¡‡tš ˲ÒHý8IvÃá4 ‡„êš‘´1Áû°è}xߺuë&Ÿ;wNFì,T±XL¾ï¾ûj[[[ÓÓU—†B˜«‡Á96ç8`Û8ÊöìÙÞ³gOø7Þè5]LÁ¼rxô%…ÀLUÅDIBÊ4aš&ôD!? 0ïc–mÃö¡ã0ØŽ“…þ[KÿúBEÁ[6pèÐ! ãŒÂa¡`H†bÂãï¦éð8sæL>|–eE‰|عsgø‰G©KpŽjEÁêiÓðÉê(¢šÛq`ÙR† Ã4´mc -¦‰_švìØQùÚ‹/VþÝÿú_ÇŽSrU „Œ~Ãc¥äN ;,Œ¤a@VD€œ1ÙCÊ0`˜& o¤Ñq0žùUÊQ¿X) †d´ '<¦R©?BL„[Ô¶èk¶à:àÅ&àﮘƒúpŽã@–e˜–Ã4¡‡ $’*äT Žƒ ²Œ¹š†ÿ—L ƒ1Ü}÷Ýé• )Nq.2Mè)ª¢¸;…€fYPUŒ1Ȳ Çq`Ù¶ M†é†C˶`1ÓkkëøÍ*ß_  Dv'*_AÆCá±Àõ¡PˆºdÙ¹sgxÇŽ•ÕŠ‚¯6\Н_~9*k¢½n“ˆC2•‚ª(½:£<G…$aš¢àë‘jì0RxÝt#n¹å–CBŠO…$¡9è²mh©$dY†€ã8Ð4 šª‚sî†CÆ`ÛLÛ‚a¸1eéØ6Ü@èw3ãNsw³ôìÙ³©Îa9¢ºf¤P uVÉt?ðÅb1ù‰G©€¯6\ŠU3/AdÚ…"È5ÕàÝnÙÐ*²$Á´,„õgp˜‡s¤8‡`‰Ào-/ýðGU_ýêWãô3OHq¹ö“Ÿ4öìÙ~Ë4q½,RœsØŽ‚¦º#‰B0Îá8 –mÁ0ÝÙÓ¶aúá0pa¸8íM7Ï™3‡Âa¹¡`HŠÙ@á£ßýÀ–$)/¿·{ì±h‚s\âk—]†šéA™y1”©S! Ê´iàgÏ*ÔrŽžxŒ1˜!†i¢‚1·}€Oé:Þsœâ [·n­¢¢ô„—+®¸ÂÞ³gOøÛÂÕ¡„a€1ÝÖÒ¬Ì43Æ癩dÇéM'›,6‡€÷½ÚˆÖx?7 ‡y †óçÏ7Ÿ|òÉs I‰Õî ûõÄ%bÛ¶žkäq4ºíܹ3¼gÏžpµ¢à¡Ëf!R[)2u ‹> çÈðD‚1àô€¦ªPUŠ¢@‘ehª Ŷ¡H’Û*K’pc8ŒM&ÐÔÔY¸p¡ÕØØhŽðT !ãdÉ’%©Í›7W¿íU$¸€cš°ƒjÊP¼¥%Š"§w(3Îaq›sX~0ôÖZBÀàßZY³fÙùÈódïÞ½úƒ>XKoI™N‰ Ào$0vÝ‚^yå• X=u.‹ºk åêDÊ€sø0¤pÐÙØäh @?(ÞÚCUUÒ!Qæ<]èvŠ¢`~(„VËBsssˆÂ!!ÅcÆŒlÑ¢EÆž={ÂÛ’ ¬®ŠÀ‘$8Ž€âu@QàHHÏ8@z ÙÜÑÃt88Á9~g»3É_ÿú×ó2£ üåëĉª‹ÅýZnÛ¶­òî»ï®§`HÈ€¸,˦,ˆ¢(=Š¢ô0ÆRÀ‹‡B¡“ªªvªªÚ¥(J\Q”¸,˦?’(„P8ç:c¬’1q'ê8N½mÛ“,ËšjÛö$ÇqêcQÆX5ç¼’s®g½mùÕ¯ÂðÉš8ÌÍ”¼'IQÀ °ŽãœŠxŸwRIpæÖ;B¤7§p[gyÿ¼Luߣ¿ô ‘|¿Ø„¡y衇bº$á°ã`—a !âB !œ#Áº9C’1$…@R¤8GJ¤„€á]üQC[¿6Ý÷ÉË–-‹çë #Áþýûµææf½¥¥%,|ûË_þ2üË_þ2<þ|söìÙvÓCTð–Q5êÝ‚E‰8pÀH †PQMƒ,IpRI(ØÙ³îT²mŠÞÝ O¤ ÞJ² I’ K2¸éÎ~0TL–è’„N΋ÅdZZBHñˆF£üÁGízøá‡ë^³LÌPU\¤(P½>ÉRà¶™ÝÈéÑC¸ÓÈ6o“ÚYÎQ%IX±bE"_Ï‹Âá Äb1ù±Ç‹f7À®šz)€Hžz­­­zkk«ÞÔÔ„\kƒÁpÙ²eqZ€NȘQx”$ÉÞµkW>Òa;,]«Lõ ?sÖJf¬W04L¶m§× ÁÓnEÖI\¨(8â8xçw4šZ&¤¸¼ñÆ:àNÿS"ŽkC:þ›®C‘¤ô›A¿ ÷6œ0 SÓPt Ž_™&:¼™‡Çÿáòº9•ÂáöîÝ«¯½ïzf¦ ê•˜úÑEˆ\p.¸üjض Ë2alËDüØ!$NFÏo£µµU_rÓg'?òð7»–.]jlÙ²%²yóæj€ ÞR@  ã¦e!‘L"¤iPá¬úÁ0ÙƒašÞÎD¶m»ë¸½:f~H¬–h…!ÅÈ/Š_UUů»î:c×®]•oX&Þw,ë˜,gÊÙ™ÑCÿ÷€à-ÛÂÛ¶ K„$ ß|ôÑ®|¿I¤pØ7V755E`bÃGðñ/| Õ§A@€9lÛ‚a…RH&gÌAÅäKP{ÙÕ8ýŸ»Ë:::€‚!!ÅŠ Ã0 ‡BH¤Ré¶!Mƒüž[Gœ1·WªßsÓ²aÚ6 Ërkå9@?wîÂá°‡Gm·5!dtõÕÑìsŸûœñÍ{þ¦þgø·d—ª*&É .UUTË„pƒáQÆð!cø98ëÕ3œ®(øîK/,„¥%û †soúK|ü³ÿB!²,»E.m ¦ UEõÊkxïD &]}3º¼…s¿oCBŠWMM€nÎГH¸åidBX¶í–¨Q0o:ˆ±ÌÔsÊ ‰¦e‚eø]¸8Ã>sÝu$©êÀUþcëºÎt]wt]gªªòp8̼ …GBò¤¿V·æ_ÞurëÖ­UMMM‘ÃŽƒÃpðºÕ÷@ ?Z¸téRcÐ'1Æ(æ°ÿ~͆Ÿ¾c¦\>uµQ\P©–qºÇD2¤Cñv wÚˆ9àŒAp†ê™©ÃéÖàŽ…êê꼿 „ ÍÂ… ÍÍ›7W°m8H¤Ü÷wî›D;9缪n›,Û ‡LÇá8鉶7ä¯A<Î:„}ìc Û¶UèîîÖMÓTLÓìoà ¯ªª²UUº®;ªªŠH$b«ªÊ#‘õe'd”õ }Ñh”¯]»¶gÅŠ‰—^z)|àÀmß¾}º?P¸õ ¯¾új³Pë›R8Ìákû͉0듆‹ç]‡ÉuL©­À„H ÓŸNn[Æà8LÓ„¦i`ŽÎlH²ŠPt"3®B÷‘·ðÈß=VרØXCÆ„Á™;w®]'Ë8Ë9Ú3àþÜ;Œ!¬‡ **E†à’$ym²¤LÓí„ÀLÇI×2óë›ùSÊG½ÇcÇŽ™—_~ywöãŸ;wN÷®CH$4À Œ1¹»»[ïëÜû ‘H„92c!)Ço9BH^E£Q>çÚkÍææfýuÓÀ…BˆÈ²Û&+Pª&{ôÐ \'„Àk¦™žN~vû¶Sù~ný(<ÆãqÍqÙ»–F#<~ö³Ÿýâ‹/æû©“2Vî­n)æ½h6,ÓD*•D×¹€èy·ñƒa¬»–eÁ²LضÇqà8n9pŽÌŸ @W‚ÛÙ !…Ïo¡ÙÜܬ‡B!aY–ô[ËÄAÇÆb=Œ™ª ûo°M–_ªÆÿà8øµe¦;!Üý·«éäñâŽfx¼é¦›ž¿é¦›`YÖB¡Ð˺ñ®÷Àš5kvçû¹“ÒTîÁ p˜SOO7$IB(¤#©¹»Nt=ŒÓÛ$S&lË‚a¦`š,ËtC!ç^0d¿öey#ˆ&LÈ÷S$„ R®ºfpïŠÏpަ’¸JÓp™ªa†¢¤Ã¡SBà(c8âm>€I²‚g·o;UìÁp0†ÛÛÛ÷+Š2¿¢¢"`q®ûy»­À‰û‚ÿOá‘ G0.[¶,¾víÚž|ŸS>P8Ì!ÕyºF2™$ ÂëˆbdIrg3Ƕ`š&LÓ€iH$â0MŽcCpÁ¹×1é`8{ölÜyçxýõ×§R÷B [owþö·~'¥wlïxËP.QUÔH2€3œá8Ëü(‡$ ËW­êÉçÃB“+<Þ~ûík¼àµM›6=  Àïº!ëÿýðè_ßPx$C·eË–ÈæÍ›«êhFá0`Ú´i¬µµñ㿇^;²ìþ‚gŽ]ס¨dÙm‘ǽB·¶åDÃHÁ¶m8–á8àÌ\À8{ Z*‰ŽŽ>uêTy î~x¤ÅÜ„Œ¿ì‚·ßøÆ7bÙÖ®]ÛsË-·$ðƒT¾ùæ›z[[›öžãœw¬ùóç›×\sµdÉ’T9Œަ5kÖô uÙ6mÚä‡D dØ}ôÑèŽ;* †…Ã^æÌ™cïØ±‰‡Qsé|$½^ÉŽí¤‹ÝJ²[ÍLp‡9pl–eÁ0 Ø–émN±zCÁpdžÝsG;Ž¢³³3ñgögq ÿ¶Ô:‹üØ¿¿öøãGÓ aƌ̛zê‰Åbò;ï¼£Ý}÷ÝõP Š…G2R ÏGá0à3ŸùŒñÔSOES§?€“ŒàœÁ én‘kU…,˰,Ëm“Çœôè¡ãØ`¶îØàŽ Á¼ w 8ƒs7%.\¸0ýÇb,ºøEáwÞy'’É$Þÿýj „ l$o£Ñ(†A †ùGá±tÅb1Ùï]|üøqÚÚÚ´Õ«W×Ïž=Ûž3gŽÝØØhõ÷óëÃH$Âï»ï¾ØÒ¥K|?¯B@á0 òùóç›­­­z×Á×1aî °sت YQ!IˆRÝÍ'óFsG…c;8³½‘CŽø‡‡à$cPBÈžšêÏHÃãìÙ³‘ìûÒÈ#!½•c'„r7„ðØ€Lpl\(<޳ööveýúõÑÖÖÖóGzzzäÖÖV=ø¹›o¾9yÏ=÷ô–ý {öì g¯'&Ïs×]wõ,_¾\Þ‡ð„ Q9¹BqÀ¯žWè–¥,@wÓ g½Ã!óGpîÀê9ƒøÑwŸÚÐ9šç;Px¼ýöÛ§À·¾õ­8@ÝéK0.Z´Èx衇b I <æ´iÓ¦`Pvxüö·¿=ýäɓ՜s dY¦Qç¶lÙÙòÝ©ff ª^‰ê g¡zÊLÔÎü(äŠX–øÉ8Þ†äÉ#HnÇŽ;*_üù®ÊGþf×Ò¥Kþ6š…Ã,sçεý6Yg÷Kh‘z(á$YñÖJ$ÉÝ|,„[ËP0æDÎÇN‡EÁº¼ÀÝ?ÞÓL‡Ìœ93çvü‘N[Sx$¥`Û¶m•Ï>ûlu9vB #³fÍš#pk0æ4ØðX__®®.8Yšü(I’¸²,ÛpËh–…ööveùšÿ9©ûÃߦÌù>ú'_…Ò!Ë2lˆe™0 áp%*'L‡=û`ÅNáô[/Á8{ ?üpÝK/½dž8qB>|ø0Ã~P8ÌaíÚµ=?øÙÏ#v¼ g÷KÔ_y=”P% Ën‹,IòJÓÁ!88çŽsÀ¬âíûÓÓÉ+V¬Häû¹eËG÷ ¤PÁ[2–;::þÞ²¬+E‘…ŠBB(œsÿwlÎßµ’$Ù’$ñR±XL^ö•U“¬ž³ÐÂU¸ú‹w¡ášOCUUض E–ax%å4-‰d2ιۺ¶æLm¼]‡^G÷‘·ð›ßüF€¾*…Ã><÷ÌÆ3+þzõÄÔéÐñ›Ô^¾•“/ñ¦•½fÉ™©eáDá$š]'ÐýÞ[`¦»éiãSŠríÒXt?ð)ŠÂ¯¼òJ±|ùrH’TyìØ1Â#O I¾Âã_¸PQz¨ðƒ"E¡è…šp[7–lxܺuk•ÕsÑi XrçÓ˜zÑ ÀÕzº[Y"i ¥%!Ë2 !]rŽ9î¦ÐÚY×¢bÒLœlþ1¸cáºë®3)öÂaæÎko¡éÔ²¿ºc’;…Îw…ä©÷½äcPÂ¸Ñ ‡B ˆÌ2‘8~ÉŽ?ÔŠ<ÿß9Sªß„# ÑhÿøÇ |ôèÑpöýkjjL¨ªªòÇêïñ¬`0\½z5¦&I’$&IRŸµ1K=<îܹ3ÜÔÔÑÂUhüòÿÀe—^¸hB%L‡cB$„³q zÕ!fsk;¸mB’„"õ¨»¢g÷¿ŠùÞ¿F-Zd”êßæ‘¢pØ3f°ßìþŽ-[¶DžßúOÕÆ™£0Î…VU‡Pí$h•µU BX±S0»OÃIœKß¿œ[ïø Ï=÷\ôW¿úUå×¾öµä´iÓx_#þuGGG¯ûSx$Ãáw6¨®)n¥c±˜üè·þ¾.ÿäŸarÃU¨ÔUL¯¯À”h Û}Úšâv6? À4M„B:´ MÓ Ë äPØÄa*'_ 3v ñ£ï⯿þ7_õåŽaŸ` £p8+W®Œ/Y²$µiÓ¦š_ýzoØNtÁNtå¼­¤høä7_ùÊWâôŽd`ñxœ{›fŒ™3gš9>?¨ik d°¨à-)'#²ó·nÝZŬê.¾WÝøeÔÔ¸Ùj«B¸rzqgãRC$ìÆ™xB…¢($ ªªºë%\–!y—ês‘:ýœÄ9lÛ¶­’~œÂá ͘1ƒ=ýôÓ]€[ò¢¹¹Yoii ùŸŸ={¶½páB‹ŠÞŽ®ÑZóHá‘ É6Px sÎ5’B/0Žyx|óÍ7uhhü<9³3n8ø°+ Ûà\À°â†ã­?” +ŠÛ´BQ (*$Å«4wC©¬ê¨œ|)z>xÐòý5(D‡aîܹöܹsí•+WæûTÊÞX‡ÇÇ|ã‰'ê;;;ç]{íµ@l󦽽]innÖßzë­¼õÖ[¡mÛ¶U.\¸ÐL¿â`'„õëן£7r„ Ô\ÌÕ=dÔã$Ivww·hkkÓ½õ3ç‚‹LŽd\àt· Ûq?&ÇS’$s!î6¿Ú€Š‰¡çƒ·±óå_TÒF´óQ8$%m¨áÑqÙëi­š¦©D"‘«/»ì2¸Â»P÷ƒq‹Åä­[·Ví~a[ä4ïÿ<:xð`jeüÙÏ&—/_ÏŠTð–15êáQQ”ž½{÷:PsáåàŒ9 ‰¤ ªutÆ-؇ÍTEBÂÈÔ†tÛ …œ»c…’I‘[ œ‘ ¥¢Š^f&°ÿ~~'ôFᔵÂãš5kþ&‹ýãÅ_|déÒ¥¯€Zg›;w†Ÿx䑺wG"²Œ?ª¬ÄLUÅH8nÛ8âØ8`Û8Ë9vìØQ¹û?þ£ò/W­Jï<¦`HHÞ 9<ʲl8p jU-lÛ†i0N÷¸E-fïbá§{L¤Œÿ¿½{“³.̆݇9ìîl&YbH lÂ!†H¤604.m5Åú|^)’ÊÓ“B©lžB}‹Sª ”†òÐhRµ¥.|° ¢>/dµ‰t9eÁìB’ÙÃ}ß¿ÓûÇ}ÏìdÙ$›dvggæú~œÏ°ç{ãîÎ5¿Ãõó‚À‡ÚèèxÛR£ˆ9l˜1‘~ ûò´ký4Ù0ÅÏ~ö³½üçž{î¥mÛ¶}väÛ«utF„GϬ^½zô]O ®òÌS¸°½מ6ó[[ ´F X,˶QôZÐ’ŒöIŠ^¯XDàûB„!Ñ÷¡”O.Óº\9‡è §åÆÇr}M‰áè$Tëè,ŒÑÇah<ˆáðX~¹Ãc__Ÿó§üÇ3òZ£ÝqñÉ3ÎÀ_œuÛ†6RJøA€¢ç#^ŒÁuØÅ"Þ`v[ O.ðªRXñ‰O¼Í < áÞ{ï­Ëz¢f§†çyˆÇã( °,+ü;àÇá8vtŠ­‚ÃÇçy^ƒ €~¸îP‡§—A«ò¡0æä/°A1£*„Ç ¢w}ÿ( 4XxüüŸ||F^k,hKážß]„ù§t ÞÚV~»(äQô<ÄbE8Nxœ¥1€6ZJ\cŽãàábÏKƒ!Qý™={¶1ø&Dà£PÈöm­‘\7ì0ÔÑZd¥„àû>|σï{J/A6щf¥DïÀoS¦Lá߇‰jˆáqئM›R¿ò=´;.þ=sΜ7V*»==^∠À:x0JkøA€¤ŒAj ¡Ò¶·´` ¯Õ›7onkö2z¢zsÉ%—xwÜqGº°ï^Ø8ŽjÀqcÑŒ‚†eYPRAÊp:Ù÷}x^ ¤-ÂSRŒ `t8Ŭ¼!(¿Ë‰ËMÞŠáh«Ex\»ví©‡²1GgíÚµ+vßW¿ÚŸŸ?sf͸gÎ}Êt@kèC‡ ÷ífÎD;©)ÑÖÒ¥|)Ó.€VËÂ’I´ìvŽ‚á&TexOOO¹ºàúë¯ïh±,üá‡>TX°`kw]³ð8wî\¼øâ‹‚`Žκûî»ÛóZãã§ÎÄGfÏ8sçÀ™=ñßùȾ>Àq`<Èå1×…mYp£Â[×¶á ü£·,t:.~7Ç/‚ÿkåÊéßòI“ETG.¼ðB¿··7và×Û1ëâ+ Œ†’Bøpœ0–ÎSVJ…•7JBI £$´02€V´ÑÆxÈ÷÷,XÀ'£`8¤ 1rjÉyñ8´1xC)ìêH¶nÝ €gSWÃq„Çiˆ‚b±Xü„ÖºÀ„•ÍfížžžDʶñÉÓO‡ëºpf΂¦P€zc?ŒÈáú ǶÅà¸á„m‡kmc`HZ–ÄxQHК]fDufåÊ•ùüVª¸ÿUüÍL}ûbh%¡¥€°ð8<ËŒ)¯'4F‡#„JÂ(…Š‘C¥PØû(¿·e xJÒèiÜUöÕ¥š: ó’-xWK âZCH‚çáÕÀdzA€—¥Ä“A€îîîÔØ’úâæMûù >>F„Ç£û3¼'ptÖ÷¿ÿý$œŸL¢ÕëÆÔÀœ·M´Þ÷:ŒRáÆBשüäPZG§ ¶eÃŽN?°¢Ìv<'5vîÜ™àÏQýH§Óúó·|îà-·Ü2-ûRZN=ñTŒã²À²£O¢þB£ËÓÆ¥€¨£€¾^Â?Ô|ÿ €¯þïÚ_ëïq²b8¤q3r´ð¢)iܱ`¦ÆbÐÆ@H‰ (ú\ÇÅ\ÛÆ©Ž‹‚Öxg,À·ŠìÓ +V¬˜ÎQÄš×£³âñxélÓù­m°m2Toìb1˜B¦è…#ƒÃ?Z‡klˆcÛ0Q»­5âv†ëâ9)ð›ßü†g¨Õ™eË–yßþö·ƒžžžø›¿úÿ0ýü÷ÃI´ÂrÂpŽ"üý*k`¢nÃÒC%a´„,d1øò/„3S|²xd ‡4nJÁ°Ýq°jάž.b±¤”pl(ú¥¾:¶mùLàüX §9íø¡ïa‡ï£»»;5{ölÅ)€Iç¤Â#ìÝ»×€ÅÉ$´Öð|-ùâS±[GƒBA@)©$¤”ÐzøœÕÊö²ÙN8ÚøÌ3ϰñ–¨ÎìÚµ+öüóÏ»àìÇÀ“cÚüÅHžr,ÛÆðAMxt^¹Ó0º÷¿ŠÁ— £æÍ›'8Øpt ‡4.¶mÛ–,ûð",œ2©©ÓàÌœNΜ‰äÀâCƒpmÂ*­5”ÖB mÛX–lÁË£ž‡ _úRšUêαÂcÙTm0”/ æºÈ‹áˆÀÀÔÀáï' yxž?à„JA*¡5ÂùêR@LDS͹\ŽGdÕ‘]»vÅ®»îºŽ|>owvvÊþýYW²Øÿ_?Djö;ê|l7õFO £€m`L¸ùdðå_À?°°dÉïæ›oÎÖú{›ì©ê²Ù¬ýÅÏ~¬˜}N™‚޹sáž}¬öv¸gÍ…ÎÏG2Æ „@BÄ!¢za 2ñ^’ ÿ-®»âŠÿ¹s'w6 @ øA€|уã8€1HH‰˜ëBi ǶÃúš €çûÑ-€¾ +‚¡FXŒm¢ûSN9_|1Z“ɤJ&“2™LòIÑ$U †¹\ξì²Ë k×®ÍÀwÞÙÞÝÝʽöŠû÷ ‘>±Ô4$O™ ˉ0P^þ¡×d÷ÁϾ£,'†¿^ó™,gŸÆ†áªîÖ[oMçµFfʬ>÷\¤;N3ût¸gž {ú)0¹<Ô¾}@˜‰¾åù¸ƒcû°´†mYpŒÁ%É$öä%ö*…M›6¥V­Z•;Ùë¤Éå¿=ïŒÇáØvXp­B æ„»Ku":BÏó}}ÏC „RÆ@eLy«ô Ñ˜>}:Þÿþ÷ãå—_NW~ÍD"¡‰„L$Êu]G†G¢Ú²eKëwÜ‘€Ê`kÖ¬Zºt©wÛm·¥{{{cï%àu ûâ3Gü|‹-òoºé¦,gƎ᪪¯¯ÏÙ¾}{2å8¸åœyHÄãpf΄ÝÑ»cܹs!û^…•ËÁjOÑZ2×qÊ7ÇqàÚ6b@ËB›eáIlóŠøÎw¾ÓÊpØ8æÏŸ/zzz;gyl+Ü\"”D2Ê}†ˆŠn|Àrù<„ð•B@D·À˜ð`RØ¿?^yåñîw¿ÛÏçó1Lø¾ïø¾ïéÚ‰&ÖÑ‚aÉÂ… Å7¿ùÍý}}}Îc=Öò›ßü&öÌ3ÏÄKKGfÍš¥.¸àŸ¹'Žáªê±Çk€÷¶OÁ­­RB ÀÓ ËCîÙS,†}u»”RagU´¸Ø¶ÃZ+꬀y®‹ŸZ6úûû¾¾>‡¿ð¡TBûŠT(* PJB ?ˆ».,Û‚ÖáÏ‚¬= ¤€/%­ËP@PÆà·JáÍ7ß„ã8…¹sç¾eJéСC‰è>Õ§œr Þ|óÍZÿÓÕ•Ê`8–†ŠÎÎNU9PÉdf-Z´È߸qãZ/õŽáªªTòö–pç©õÖé¡!XûöÁäs€RЃCaHŒ”Ö˜a0ôý Z`îE³£¢ÓÓƒQg]gg'׎4€eË–y·Ür z¥@¯”8€ò}R"æ¸á1Y–UUR+(¥(¡cà¸Ic 4{Uøâ’K.uCÌÔ©SýÊû‘N$<®]»ÐÓÓ3£2<º®kR©”p]W§R)ÖhE6mÚ”Ú¸qc;Üpà \Xc ‡TUOÿøÇIèjm+o4i ¤„ÕÖn(+¡³ƒP…<„ wœ–Jc1A`´Ìplì–ÀSO=•àƱ|ùò\wwwêBÕ>¥¼óØ•®ˆºÌ”l :ZS(+F ýÒ4rt“¤1ø‰ï#0K–,ñÒéô ÷w"áñé§ŸNÌŸ?ÇytG·µµ ×uM"‘ Ԍ֭[—Þºuk+À`8Y0RUŒÁ\×E\iŠñ8bƒY´–Þ¡¢ÄXE=vR)! ›¨³ÑW"¶[áHäÐÐuì«¡z±råÊü÷x µW)üg±€%[ 8ÆÀ­XZþL¨hd°K¡Ð^Æ Gث▅ñ¬®-<~⟘O?ýtÿÑF•Röàà`âHŸ›á‘ƒáäÄpHU×bY×Ű܈QÈÃ=EßGÑóá®eQQh\ '4ìCu!Në¿ûÇ·nÝÁ5¬†“™¶fx¤FV †©TJ_{íµC †“Ã!UÝ)ቹBŽ3\píû>ÜÊÎ:özAÏóPôüò&ƒ@JxÑ´¡BJýu]]]¸òÊ+O=õÔ©|`l]]]~izù? y\’Lâ¼XÂ%VÔ[XºÉŠŸ Y1’Ø+%~ O'/[¶Ì;ñ«µ©TŠ…àT3Ùl־뮻ÚKÁðî»ï>À£ì&†CªªY³f©þþ~çy¯ˆwX\Ç…1€P ‰X ®ë–ÛìKuáùÊ~¹Ø8²\IRÚuª£Ñ¢7´B €”Òà¨JƒY¹reþùçŸõôô$þ³XÄsBàÉ´XJi¦túIégB!Ã_Š¿ŠF -Zä7ÂIãßùÎwbÆ 0í׿þuÀßš(ÙlÖ¾öÚk;z{{c †“Ã!UÕûÞ÷¾bwwwêY!p¦+€|Zk)wÃphÛ¥p¨¡”‚/Dtê…OJøQ-‰¨¸•Ào•ÂÞ;p饗Z¶l™—ËåbRJ;º·|ßw¥”V>ŸkT¦L™â@[[›€©S§ѽÌo–ª.Në7Ø´iSêë_ùJ{¯”èËç°(Ç®ƒSm§¼¼@Ã@`ŸÖxUI~„ç$O·íòF¥!­1dÌa«,]º´xÜ_´Aö;òÝï~·½»»;õOÿôOÎ?ÿ|}¢O°i¬*ƒá¬Y³Ôm·ÝvÁpòb8¤ªêêê ’–…¤ÄNßÇEñ8dt´™kpí°–$b17Ül¢ux–2*vå[iãÁ/EXm³dÉ’1¯!;Ùð˜J¥.<çœsàÜèö7JSr@ùÉOæþáoošÖ§þ­Ç…±8.ŒÇËï_ÚgZ ˆÚŒÁW¢côfØî}p˾£M'Ö«Õ«W¿à¥#½}Âã3xfõêÕ »aãŠ+®(Üwß}©þþ~gÓ¦M©É6âLcw£ó#Ã#Ÿ`‡-[¶´Þ¹áž´ò ˆ%ÛðÎ_ÓvTt`ïyð¼"ì¹ç!5ël¨ÀÇ`߯ðæ³?‚hü±å3º_äýä'?Iƒaýb8¤ª9Òú’L&óú­·ÞšÞ¾}{ò§Ÿ‹³Ómo³òâkJá·JâÍè輸eaÅÕW7M_ÝhÆ!–Ýot|Nä±X,~Ä3€cŒ‰™°dzÔ.»É¯»îº¡+V$º»»S—_~yO6h¤ oÇ$ZÚñ§Ÿþ›Ê/à´…]8çÝD笷¡5ábÖÔ$¦´Ä`ÈÂm4´ O¶* ˆÅRÀh £%ÚÏ8Þ›¿Eñ=X¾â/füôGßë?¹«£Za8¤“R Ç:N§u)(Öúú›Ý§xO<‡1Æ1Ƹƒ¢À.½.ºŸÔáqáÂ…â²Ë.+lݺµõk_ûZªÙ§¹úúúœ;w&~ñ‹_Äàá‡nÉf³lˆÂâ—¿üåÙ¯¿þz»ÖzÂ~G6mÚ”Ê÷¿€X² ‹?öW8å”´&\œ{Úœ’ŠC(ƒƒù ç¡‡jݱåÁÔ%{Ûã?Þòøã·ÜrË-X´h‘ŸÉd>˜Ÿj…ÇŽŽµ‡Šð…B"f—?Æu]¸ÑQ¨®ë"™lZ†ÑŽ· =ï"Üý|eó¿¶óç©>1Ò a0$àØá€­µŽ°Œ11ˆã„…Çf.ÆÞ´iS꾯~µ=mòJÙ6Þ™Hbºm‡ÓƒZãe¥ð¼åîºouSû6oÚÏso«c¬á±¿¿ÿ‚ 8×qœ ßµkWLE´ÍèÄiïX Û¶ñÆö¤ ¥ ^Ïz*üp©†?e[°l °,X–)´–¥‹ ez'rmÓ òÁ“ŠêÃ!·Ê`¸|ùòúÓQhÛ¶K £M]ŽKx´,KV†Öf+Æîëës>ÿ'2ãW~øOÿ¾©SqÕŒ™x{k ´6ð|^àÃó<¥0$v>¶‹x]+¬X±b:·'FExüs§;ŽsØÛÇci‡mÛÞÎ;ž=¶ã@GO ,ËÂÁ¼€PÆä|‰Ês­¢¯Ë ÿÛuc°mʲÃég+eŒO‘?ˆ;wÆëÃ!—M›6¥6nÜØ7ÜpCöŠ+®(Ôúš¨®wxT–eÉT*¥®ºê*ù/ÿò/ñ{ï½7}饗ŠcŒxÖ­;v$nú«¿êÈiv×Å-çÌÃe§©\ÛF %|?@Ñ÷wcÈ PÆ`1€yn yE<áûèîîNýüç?OðȳÚ:¥Çü‰ÇãýO?ýt‹®…"(, ØPð]x2ü²rAùë)© µ†Ñ–eA) ctébJÄÔS‘ÿíóøùÏžÀ'u†áÆlݺué­[·¶ †4aN6<–0ÿçÿüŸøÎw¾ƒ½{÷Ú=ôÐŒ|ä#åð=øêè^y¬ÙlÖ¾íý¯ŽœÖxÿ)§à çÿNO§á¶´B p[Zá ¢èûˆ\8¶˲`L8 4 ÀeÉÌu\|Ç+¢··7Æ ÉíD–váxÐÞ¹B( ~Žu¨pøª‚7†|ä ‚À‡) ¥„”Z+Àèò¡HŸ èííêÃ! ƒ!MRǯ½öZ÷æ›oNÞ{ï½øƒ?ø´··—Ããhê-<þÓ}äÔץö6Ü»èBtÌ +•”¾É$×-„S€Æ@i ©¤’JAXæÇbø¨eá_ó9tww§X1U׎ú;"„@±XD"ž@¡Går¥¡\žçÁ¡”J)hC­­a̤ûµ ÀpHÇT †©TJ_{íµC †TG{`¼ôÒKñðÃwôôô$¾ñoäÖ¬Y“ëÈãhŽkñîØ±#ñH!¸åíó1uút€{ÎÙ°ÓS`„€>Õê  Ekx¾×qˆÇàqĤDL)ÄŒÁlÇÁEñž ||î3Õñð{ÓË'ð=~…B–mÃh)8n ¶m…/+ ð?—C>ŸC!ŸC±P@±X€ï{Aµ’a@TFkcd÷O¾ªõ÷JÇá°õõõ9£ý÷±”‚aoooŒÁQéÜ×­[·¶îÚµë¤ÌGáѯ ¥·)<–dµÂãÎ;ãð®Ö6(­‡O´H$¥ ^û-Œˆþv• wžjmˆð$ + …¥•giÛÆÛl18Ù+š</^ì@aßËÐÂC1ŸC.7„|>\ ‡†18˜ _ŸË!ŸÏ£PÈÃóо#Åð­bZÁÂáâÅ‹ƒ“ºPª N+7Ê3‹w~ï{­û+Ö||ô£1kÖ,õ¾÷½¯¸`ÁÑÕÕŒ¶~¨2Κ5KÝvÛm ©Ñtvvªå˗纻»Swß}wûÆœüg]ÅHâ¨ÓkZëcâÑ}¬ôú1¬y±XlT‚%SÒ°- R)¨pZÏrX­­€Vй<Ô¾7*¯­|K&’ðƒ`¸Ç€M/Ïv\¼¡ìܹ3Á¿aáÂ…Âvã²û0Ø· ígœ£5”Žã²,¸n Bh­ •„’ZÉp:Y h)ÂÑC)ÊÓÊÅý¯B²°œ¸‘©>16ˆmÛ¶%¿¸ví´¼.˜á8˜n;00Ø#%úûûîîîŽüÝ?þãÊ_Ü]»vÅn»í¶tooolÞ¼y‚ýfÔÈ*‹±kyŠÃÉ„G˲4Ö…´Y6æ:†ò¤ÚÚÐ}¼ÜÓ;=:;Xþœj`^nˆêHTXIbŒÊ·’év8ÉôôÓOÇW­ZU‹&¾rÅÐÆÛß|öGh9e6œd FK(á„g%[lËŽÖ†»’Œ ¢‘ZÑÈa8­¬ƒ/ÿpõªOrjb8¬sÙlÖ¾é²ËN}Ò ×Ò/jkûZÛpA*…3Ý„”ð|Å À>ž¿/H‰ë¯¿¾cùò幕+Wæ_}õUçºë®ëÈår6ƒ!5ƒt:­?þñç7nÜØþ…/|!ýï|g_­¯i4Ç %s\ Šž‡ÁobJÅÛK#‰äsð}A4R¨Tx”žŒfÊ1z²™°,PãYµjUîëüg»hûÿë‡xÛï^£%,k8ª¨òÆÀ”ÂaMiÄPIN)¾Ü£bíà¹Êõ‹á°ŽmÛ¶-ùÅÏ~Z^k´;>qúéXÙ9J)ض@x¾¢‡[,bmc®ãâý‰$.°=:á;<2ɤ) ƒ!5“U«Vå¾óï´ö÷÷;[¶li­çš&ÀŠž˜[„mÛÀ7Çá¾\(ÿ]Ñ®SÏ÷Qô}ŠEx¾?ð!µ† Œ4a/pÊ)§àüóÏw:”p]W§R)N/7€ï>tßëK/ýà©…×_¡ާ1å¬ß…e‡Ãð´äð(½RŸ¡1ªbŠ*‡ÃüÀKðì…åÄpÿ׿:)ŸlÑØ0Ö©¾¾>§ /Æmï<ó¦N…Ë)¤„(zbnŽž{iP€iiÅ;bq<\,`@) P°.¾øboݺuYCj&W]uUîŽ;îHß{ï½í—\r‰W¯?ÿ»…@ %òÅ"œhX+×u‹Å •‚í8a%‰ðKÑ ƒ¡P BkcP*kT4Ï\|ñÅX´h‘»{÷îŽÒ×tG·µµ ×uM"‘®ëšT*%ëG:ÖŸ¿åso¹å–iÙŽ`ð L;· v¼%ÚØ†Ãð¥²ë°Ç°4ŠN%÷À?°@8ÜÙÙÉ6ì:ÆpX§>ÿ'2#¯5–:ÎÿL>ÎÌ™å·ÇÐ À=x \d¬”ÒÐZ!®1˜ã8¸¦-…¯çóØ£$ö>ùd2N¬õ÷F4‘®¸âŠÂ~ô£dOOO¢^»üJuÏ‹¸Ð ̵1R"ÁuJÇäE'¢H ?ð‚žïÁ øR†£†9ÔÆ@Ãà5¥€çŸÇ»Þõ®àío»–RZù|>¦”²Gº.†Çú°lÙ2ÀÁÏÿÝßO+¾±þÁ~¤ç]„–·ubxߺ‰ÖèpzÙ Ú|2øò/a”€åÄpõªOq:¹þ1Ö¡M›6¥~åûhw\üý;ÞŽ¹sîÜNχÃnOAåД™k­!¤DK@‰°Çìk…<^–Û¶mKF(ˆšFe1öÊ•+óõ6z8þ|ÑÓÓ“Ø%Î"ZfXÌ ®í(†O!ˆ  caL9$JÊ{•ÄÐóÏãÌ3ÏÙ[—ËåbRJ;º·|ßwO6<~ðƒœÿ½ï}¯Öÿ¬MeÙ²eÞyç·oùŠ¿˜ ¾ƒ»‚\ß4ħžŠxj§œ^‡Å7_ƒÌ„ŸÝYÈb©Üÿ¯îãˆac`8¬3}}}Î}_ýj;|1kÊX©ÜsΆ{æ\Ϥl z(|ò–ˆÇ‹ÅÅàØ6Û†kÛp”‚`ºã ‹ã'¿_»vZWWÉ¢¦ÒÕÕå/Y²ÄÛ¾}{ò®»îj_»vm¶Ö×t</^twwã"Àê$:¤„ÐI!àº.\Ç…m[€´1PJ†KO¤„2þˆ[*cЧ†ŒA›ea´›ÒàÔ©SGÝ0s"áñÒK/ý꥗^Š þG<ÿAôêg¢ûÀêÕ«Xë÷FÓÙÙ©~ú£ïõoÚ´)õ•ÍÿÚ.ò!ò‘?ÊÇp´°11Ö™‡z¨5¯5Þ—žŠŸv:b­m{ÊÄæÏ‡Îç¡^}Vk+ìt¸WÑy¹€˜ëÂuÄã1ÄãqxRÂÑŽ1pü^"=JâU¥ðàƒ¶òšÍêÕ«·oߞܺukëŠ+rõ4ÒÕÕåŸê8x])<æñG-­ZC\)áØ6lZiÀ±¡µ†Š 0€ "Ñf”¼1ø©N$üÑ•WžÐß„ }}}»ÇYÔÒÒðþè]K÷6l(}ŠRHdx¬’U«VåV­Z•ÛµkWì±ÇK>ÿü󱞞žrˆ_´h‘?þ|±téR½—‰á°ÎìØò` >~ê©PJA p˜ €øï^@0B*|\SPZCG¥Æ¥U$V©¦À;bq¼ªŠì2£¦TYŒ½~ýúôxc‡/lÚ´ÅŠÓ·û>ÎtcXຖW)8Z¯“Ã!D%Âu‡¿†ŒÁ4ÛÆx­Å-<^uÕUk<à‰ 6Ü`€ ¢û³F¼Ìð8N.\(þšÃaéëësö(‰6ÛÆÛ[Zá8Ü–°êV8X Àv ‡råÒ[':ÁŠv0Ú–£†,l€s\ßPù ‘¨™L–bì±páBQ ·ß.0£-…vÛÏI6føH=„ëK»‘Ëk +ÖÊh:ùW"ÌwnÞ¼¿Vß×êÕ« u#mذ¡‰ª„á°Žìܹ3ç'’ᨡ”ðrCHFݶ&ðaÅâ0B@ï³üqR)(Vhm µ†åذäpá-†ÄÓ¿U õöÀHT étZøÃ.tww§þùŸÿ¹½Þ~,X ,‡´Æ7 y,K$qºëÂ`S*% 7¨! ¥€XÚ &A¯øi‰»|ùòÜd=bx$ª>†Ã:òÚk¯90ݶ|ÑC"ušUœ~P¢äsð^‘°dɯ«}*Dx<+º1ó™Ï mÞ¼¹­»»;õt`@)œ‹£Óq¦—Àh  5/H‰g…@` â–…W_Ý;PÇK!±t›6âe†Gj8 ‡uH Ïów]ä EcàGGå9¶ ¥,Ë*“UŒNAð|¾ ´.¯9*M#•Ên=cpå•W²¬Ž§žzŠ¶Ô”ê©»2._¾ÓñªRxUÓm§;nxÜž1a‡aŠ¢E‹ü›nº)[O»µÇÓêÕ«_ðÒ‘Þ^­ðøå/yö믿ޮµ€ÃÎÔ&šp ‡u¤Ôeöœð•D¾X€mÛårkß÷á8Nyg²R ˆŽÑ‹ÎQõ£ÂÛbe—JSLaÙm¡P(}cÙ Âp(…>& ËѳFcÈ<øõ¯ã/ÿò/ûàСC‰è>Õ8ý€á‘êAWW—_:–n2c¯[·.½uëÖV`ô`X’N§uåôðŽ;û={¶ä(áøkxìïïÿ‡ ÎuÇ6Æ8Æ7ºEkÃGý[ËðHãá°ÎüÞ{ßëmß¾=ù+àÝ–å{* €1×…sت BHH)ÂP¨Ô[NA(ïR4/DÏXß÷¡•dJÝcÕ<ý „á‘&»›nº)ûÑ~tÆd+Æk0M½íÀntáñÏœî8Îao/EŽ1&ÚxÎðX/*‹Ä{{{cp÷Ýw·ÿà?H.X°@,^¼ØŸ,W*1Ö™sÏ=Wlß¾=¹µXÄÛݦA€˜Rá‘x–U‡aÔº\t[yB)J‡ŒÆ³Q§ÙE]4æñ8:«ddxŒ¾Np´¯GTMê²Ë.+lݺµuÆ S¾ô¥/¬õ5•‚a*•Òëׯ?İר,ËR–e1<0Ù¼×R- ‡ulãÆJÏVž|Ùçw¶o½ÿþÔ ÑxNêðl¼QÌ›7O\xá…þdÙ5™ýìg?Û Àî¹ç^Ú¶mÛgG¾}¼Î]ðÌêÕ«k^›B‡«,Ưcõ ©ÉT5<Ú¶íJ);J/çÈc__ŸSšN¾ùœs‹ÅàÌœ »=ûÔS;çlÈ—_†)¡“I —‡ÛÒ §P@ÌushšÙ*N ÀYŽ‹ âq<øú׿žªE…ÃaY³fÍК5k†úúúœ;w&žzê©ÄÐЧvššÌ…›õj¼Î]>CãA ‡ÇòË µqÝu× ­X±"ÑÝݺüòË Õü}ª †—]vYa²ÊBTc¦c”mÛòG+<îܹ3œ: ïH¥à:ÔÀœo¤„xáEÀ?*ŽEtˆ:‰-ËBÌq—"j1¸0†ÃíÛ·'kñÎpØ€:;;Uggga"wTÒèª/ˆÞõý£|,Àð8á.\(JÅØ_ûÚ×R•nÇŽ‰;wÆK/ßyçícÚ²eKëwÜ‘ b †DcR¡µ–®ë¨x{5§­uô²°,K<õÔS 8'‘€e‡K¸œ™3Ë‚~ã Xm­0BÀH ØöÈÏ  Â?;º%, §;~«¶mÛ–œè £ ‡D5ÄðXŸV¬X‘{üñÇ“[·nmM&“æ7ÞpF{†ßÝÝêîîN%- ¿÷Þ÷zø‡Xí<ƒ!Ѹ9ÖÈ#´Ö 0ÆÄ£ûXéõ£…GÛ¶}×u<ýã'àwÛR‚H ”>)¬¶V@èBúÀA¨ÈbRJ(¥ F"ž€óAyi)$ΰÃp¸{÷îÃ!•Õ"<®]»öÔC‡Ùh ²jëììT¿ÿû¿ï=òÈ#­=ôP[éõgÇãX˜HBkm „ÖØ-^U Û·oOnß¾=ù£ýÈ»ù曳¥u„ †DµUGݘ82<–ŒÁ\×ÅtË‚çð|‰|ñR@|cø}Uôº@)ãm¥‚² K‡W”îOwüBÏ?ÿ|l¢ÿM‰êØx„ǹsçâÅ_DMS`{¼¶lÙÒú£ï~·Úלv:–L™‚´ƒ¾(z<ßCAÐÛ}ÿŸçaûöíÉ?þqòö»î:ðÚk¯9¥`xà 7d¹„hò9ZxlµÂ©a¡$ŠžÇq†b…Â`6ú»àÃF¥”PzøO©ÆäøÃÊpHÔÀŽ#ñòv±€¸”¸Ô²ðN7†‹¼$%®¿þúòŽJC¢ú”ÓEßG¼èÁuX–c âA×u¡”‚mÛÑñyžïG·0"@ üèX[õKÔö(Ã!QŒîÏðžx<ðè¬ÃlÛ¶-¹uëÖÖvÇÁúóâœqZ¦¤{Ÿ|öâÅ"\Ç…õŒê|-–…YŽƒ•m)üÈóðýp Ñå—_žg0$ª?-–…>%qP¸ÅÛ†1€ñX 1×…Ö: ‡JA_xž¢ç¡è{¢l0*„GÜjoèp³ôüùóÙsHD“ÊD5)O?¨”Ífí/~þóÓà/Î:ËN‰¶ÓN‡•JÁžÒ=V¶°- ~ %‘€Ò RIH­QÔ€÷$ȃ'ßÿÖÿiû‹¿ø‹» ‰êËEï}¯·}ûöä/|ï±mXÈCi !âñ\×…$*¥!•‚/øÑúD_ˆápXq+höF4ݼ`Á†C"ª+Õ £šLGgÝzë­é¼Ö¸(Æ_žs¦Ì>ÎÜ9pN›Sôàœ~:ôþý€SµÆP.©$üxžï£E©ðø,Hàe)±O+ŒW¡6ŸsÏ=Wlß¾=ùkàÂxÆ÷ ´B ˆ±áifZ)(­‡§’¥„M'ûÆ €r8”^‰º»ºº‚‰þÞ‰h­ðÍBg».fØf»¦G%ÙÀ«Já·Já·JâͨÏp¶ãàëßÿþë“ai Ã!ÑQL™2ÅÀ Vðù‚ Çv`Œ±hQEÓAJ©0 ú~x‚ïÃ|¨hCJ庣ÒèÁ~­pÉÅò¬ÖÝ»w·–¾¶ã8º­­M¸®k‰„t]פR)ÁðHT;G †ÐÕÕå?üƒÇ^ß¼ys[wwwêE)ñ"$p”¦ÂÒhá²e˼±^Ãxc8$":ŠÅ‹û7nlß-ûÙÏNëííÍ›7OÜ{ï½GÝ4’N§õ²e˼É4"8V ‡DDÇpñ?Xغukë}ÿÝ ZÂhäÐe[0Ú„ë •„T B)Z—Ç*ÝP> awTv;þüQÃÚÔ©SýÊû‘Žóù|Œá‘¨:víÚ»îºë:r¹œ=–`XŽáø€·uëÖÖÇ}çÇâ8Óu!¤D %\!`Ûöp]EiTPëòY©AK稖F_¯(‰¸eáòË//œÈµ+<ær¹˜”ÒŽî-ß÷])¥ÅðH46Í †C"¢cêêêò—/_žëîîN=X,àÓ©v„7®Ö°µ.[„›MF“U ‡"*¼ÍƒŸDç§®¸úê¡ÎÎΪ]©â&2<íëÕ“Ê`¸dÉïæ›oÎ6z0‰Ž(“É,ð@ôâ³µ¾ª­•+Wæ¿÷À©~¥°Õ+bi" ײà€eYaY´ ¹´#¹4z8|ž„ð„ï#03l«V­ÊÕêûÏðS¦Lñ ­­­ôu‚£}=¢ÉbÛ¶mÉÛo¿=ËåìË.»¬°víÚl­¯i¢0¢"ž0þs­¯‰j+Në¿ûÇ3T³Ù¬}ë­·¦·oßžL¥Rúî»ï>°páBžúa8¤¦”ÉdÖc8ÞˆpÔˆè0UDïzÔðøå/yö믿ޮµŒmÛaUØ´iS꾯~µ=¯5R¶ƒwµ¶àœDïnmE‡¼ÀÇ{ž¯H‰ÿ¶nÝÚúÃï~·õo×­;¸lÙ2/›ÍÚ×^{mGoooŒÁpt ‡Ôt2™Ì}nŠ^d0$¢V­ðØÑуBJyØÇ[–%,ËÒ–e‰ÒËhÂðØ××ç¬ûøU3žõŠ€?˜Ö›Î: ­–Û¶!„€(z>Þ•Lâ¬BE¥ðšRx Ç‹Râ–[n™öýïß°_|ñEã`8¤¦ë¢ ‰h\5<ö÷÷ÿCç:ŽcccŒÝÇLxúΨS¨Í³Ù¬ý—û،ץD»ëbÝüùø£ÓgÃu])áØ6<ßGÑó‘/¡µåq:€¿Hµã±bO>~úÓŸ&`Þ¼yâ _øÂA¶ŒŽášFE0Ì"\_È`HD5UÿÀéŽãööRPàcMo½õÖôëRâܶ6Ü—ù=Ì™5 àÌœ 50Häsˆ¹.lÛ† Æh­!¼"¤1øƒdóc1lÊçàƒ‹/¾Øg0<2†CjxÑ9É7a8~ aÉ5ѤfY–²,ëh!ÆÖZÇXƘDÑŽîë:i´–º ÙlÖþâç?? VÌ>g§§ÀJ¥àÎí„3{6L±žS™ˆ‡00€x #‹#æzpl-–m €³Ý.ŒÇñó À_¯\9ýÑ'ŸìŸàÿ¿êÃ!5,C"¢qʲ,nêè¾òu'lóæÍmy­qA*…kÏ>­SÒáŸr âïzÔþýÐûöÁ 0SÚNnŽãÀ²,ÄÜ\×…-Ë‚c \¿O࿥ěZcË–-­,½~+†CjH#‚á×€Áˆh¤“ ¥µ£:™ðøóŸÿ<?u&lÛ¾àÁ!È={`£L±=850 €cÛp]'¼wÂ{KkX–Ë$- ‹bq<î{ؽ{w ô ‡Ôp2™Ì»1 ŸE8b˜­õuÕ¡ –eùƒƒƒ¦··7–²mdÚ§@ëŠl)¡ú`‚– âmŽãÀ°- Zkc`Tøv+ºÀÑÆŸÇ¿ûÝÖµk×òña†Cj(™LæR„ç$§Á`HD4ÞªÇÚ±c‡€ó“I(­ ”BÏ¡€|ù8Aˆpc0CCåRB+m `Yáh¡cÃ’ÃÒ0Õ¶ÑnÙ2»víŠqcÊá©aDÁð0MÇmÛöwïÞ€é¶@ÈáÃ°Âæ·{û$j`¢Gð…€"ÚµE Z;Yvºãà7RcppІáˆ`ø‚kC"¢ÉíHá1 „µ4žï#W(D=†ÐR,Àmi=ì“ÈbE߇BÀü €R Rk(c ( o±NXÖ±®­i1RÝËd2×`8Þ‡0QSÚÀó=Äã1ä‹,Û†”1߇ã8€1PZCH ?ày ž?ˆ”ÐÁPPÆ@ÂÀœäµ52†Cªk™LæF£ ‰ˆÀìÙ³¼®[ëë"¢ê¥à‘Z_ÕÞÍ7ßœÝùã'÷(‰Mù>LâÇ…mYåó’Mt+—]‰°×PƒàY!ƒyóæ‰5kÖ Ä%5<ŽÒ¤Ã¼ †D m”VS€pzù_þõ_÷O·mdµÆC…~à{8XšNÖ:1¬-ôŽiÇ|?Æ`É’%Þ½÷Þ{ ÖßÓdÇ‘Cš”*‚áù`0$jhl  cY¸p¡Øöä“ýwÞyg{wwwê™ @¯˜í:˜a;8ݱÑnÙ0; _”oh½J!ˆú ?·nÝÁeË–y'}1M€á&ÁðYרSëë"¢êc5kÖ -]ºÔ»í¶ÛÒ½½½±ç„Æs8úÒÁE‹ù·ß~û¡t:Í“Pƈá&•L&s)€GÌA ?†päˆ èD,\¸P|ó›ßÜß××çìܹ3ñÔSO%žyæ™x.—³`Ö¬Yê‚ .ð,X .¹ä¡ðø1ҤäÁ`HÔÐF4\ à‰Z_Õ—ÎÎNÕÙÙY`Waõ1Ò¤À`HÔØ@@4ùq·2Õ܈`x ‰ˆêG©¦¢úŠG£ïë+ˆˆêG©fF)¼e0$j@£4\ C¢I‹#‡T †DÍ Dõ‡á&܈`Èú ¢ÅfDõ‰ÓÊ4¡¢ú C¢Ç`HT¿i°ð–¨9°€¨¾qZ™&ƒ!Qsˆ–TC®'&ª3 ‡4îFœ„Àú ¢ÅfDáÆME}ƒ!Qƒc0$j ‡4.XxKÔ<Ø@@ÔX¸!…ªnD0ÜC¢†Å¢ÆÃ‘CªªL&ón~w)5(n4#jL ‡T5'!°×Œ¨Á15.†Cª Þ5656†C:i#‚ᮃ!QÃaQsà†:)™LæcàID D̓áNOB jl j.œV¦ÂÂ[¢æÀ¢æÃpHÇmD0¼ÀúZ_UˆšÊ‡£û= ‡t\2™Ì=`á-QÃcQóÑ@pÃ!YôÃó©èEC¢Å¢æp¤nH¡1aá-Qs`Qs8ZÃ!ÓˆáækÀ`HÔØ@@ÔŽÕ@Àie:¢è‡çv°ð–¨á±€¨9Œ¥€áFÅÂ[¢æÁ¢æ0Ö†Cz C¢æÁ¢æp< \sH‡ K?< †D ˆ DÍa”‚£n4ãÈ!•Uüðð$¢Ç¢æ0JÁ1×3Þ5“ 7x¤Ö×DDÕWÑ@ÇF3†Cb0$jl j'Ó@À5‡MnD0dá-QƒªXOüa05´QŽ«šŠ#‡MŒ…·DÍ DÍ£ 9lRÏ* ‰ˆšGµ8rØ„xQs`Qó¨fÃa“ ×#\‹@D †͈šGµ›OB j †DÍa¼¸æ°Ið$¢æÀ¢æ0ž 9l< ¨9°€¨9ŒwÃaƒ±»‰7š5‡QnD•ÛTŃ!Qƒc0$jѲ‘GÌÁ8®'f8l@,¼%jl j¹ÑŒá°Á0565‡‰n ànå2Ê:„Å`0$jHl jµh àÈaƒˆ~xv‚½fD DÍ¡V  ‡ €…·D̓ DÍ¡–Íëƒ!Qs`Qó¨u×Ö±QÖ!\ C¢†ÃfDÍc”‚ ¯¦âÈaŠ~x^d¯Qƒb0$j“¥€#‡u¨ÖÃÍD41Ø@@Ô<&SGë̈`xÂ!g"j0l j“­€á°Žd2™õ˜ÃÍD4¾¸ÑŒ¨yLƆÃ:ýðܽÈ`HÔ  ‰šÃdn àšÃ:0Ù†›‰h|d2™ D o²o4ãÈá$7b¸y= ‰RÅI7š5¬É †ÃI+úá¹ “p¸™ˆª‹ DÍa”‚I¹l„ápª‡gDTl jõÔ@Àp8É0565‡zÛhÆ )“Ȇ› ‰ˆšÃˆ`ø&y08r8iTüðLêuDtòØ@@ÔFi ¨‹õÄ ‡“@½ 7щcQs¨ç†Ãc0$jl jõÞ@ÀpXC#‚á#x ‰ 7š5Fh `8¬‘L&s êpC¢æÑ( Ü­\ѳŠ`0$jhl jÔ@À‘à VïëˆhlØ@@Ô<­€áp5Â:":6n4#jØ@Àp8A2™Ì=h€uDtt †DÍ¡‘'@ô¬âSÑ‹ †D Š DÍ¡Ñ7šqCÊ8k´uD4ºQ®ƒ!QÃiô`0Ž«ë>C¢†Ä¢æÐ, œVÑÏWЀëˆèpl jÍÔ@ÀpXeÍ0ÜLD¡Áp=Â"j0Ͷьᰊ ‰šˆšC³C€k«f”u—‚Á¨!±€¨9ŒÒ@ÐðÁàÈaUD?<˜ƒ&yVAÔ¬Ø@@ÔFi hšõÄ ‡'©‡›‰šÕˆ‚«š"f2™{Àáf¢†Ç¢æÀ‚ñÕðá0zVñ©èEC¢Å¢æÀf㯡7¤pQsÈd2×àðf1$j@ †£aÃáˆu×€Á¨!Eë‰7‚ D §á¦•£žÛÁuD DÍ «¡Â!‡›‰šˆš&^ÄCC¢æÁ¢æÀ‚Úhˆ5‡#‚á³.ƒ!QCbQs ƒá„©û‘Êáæ9à³ ¢†Æ¢æ0J×O º‡n&j#nD8’@D ¦¢`0¬‰º ‡ †DÍ D̓ “C]®9 YxKÔ *Ö †D m”黑Ã臇눈š&—º9¬xVÁ`HÔÀØ@@Ô<Ø@0ùÔÍÈ!×!5656LNuGÃõ×"QƒáF3¢æÁ‚É«.Â!¸¨á15‡hÙÈWÀ‚I«žÖ25(65‡ŠõÄïƒá¤U/#‡ †D Š DÍ õc²‡ÃCà.E¢†ÅfDÍa”‚kì©õuÑè&{8¼œZ"jH †DÍ õg²‡Cþð5 ÁËFˆ7šÕ§zÚBD ª¯`0$jp †õ‹áˆ& o‰šêÛdŸV&¢Á`HÔØ@Pÿ‰hÜ8 õD ŠÍÃ!›Šú C¢Ç`Ø8‰h\°ð–¨y° ±pC Uƒ!Qó`Aãa8$¢ªå$„Å`0$jHÜhÖ˜8­LDUÕWì{͈ƒaãb8$¢ª`á-Qó`Acc8$¢“6">àj0564‡fXsx>€÷¸ ÀÏ¢{"ª’L&ó1ð$¢†ÇfÍ£QG߃ð˜ˆÆQÅI{͈Öˆ`¸À5`0lXã1rx;€½ÞÖ^KY„S\÷ÔúBˆ o‰šC&“y7o ¸ † mÊû݇ê>¸p Ñ8`á-Qó`Uªf8|oÅí¤Ô=HD“ƒ!Q`TÍÝÊ•6Í#ª¥Â[C¢ÅM5GÙoHÔXØkFÔÀØ@@GRÍ‘ÃÒ®e†C¢úÇ`HÔÀF4\CªP­‘ÃÊòëc…CîV&šÜžðÏ`0$j8l  ±¨E8äne¢É»‰h¬ªçTüwiû„SÍ#‡ª¹[™ˆˆh1Òñ¨V80Òqªæ )DDDTC™LæF o¬õ5Qýa8$""jQ0¼=z‘ÁN§•‰ˆˆêƒ!UG‰ˆˆê؈`¸À=µ¾&ªo ‡DDDu*“É܃á`x#Þz*Ñqã´2QÊd2÷aøÄ/CªŽQ5¥\àÃOd #,§çƒQDÁðªèECª*†C"ª–ól0gÄëÓÃbév5عFtÂ*‚aáï©¥ªâ´2Qc¸À^ ¯=šhéèkÏAø@u Â#,Op)†G5Þƒ°ƒˆŽS&“YÉdžÅp0ü i05†Òîž}ý«¢kxáÖ#o{á´×úŠk½ê¸>;Q“Ëd2 >±:ÃÁðÙZ_5&†C¢ÆP ‡µz°(M­[í ‡W†C¢1b0¤‰ÆpHTÿίøïZM1•Îo=ÖÈåÖQ®™ˆŽ`D0|Àb0Ò8ㆢúµw ¯»÷@µODU”Éd.°ášÞg>ãf.w9$ªOïãûM¶†Îèþ‘“ú,D . †€Áj€#‡Dõé „;àgw ߃áM#} ÀMUüúY Žócæ ¬²†§—‰hCª5†C¢ú–Æp¯àò~÷¡º£ˆÇû@•FØXºŽbD0¼GßäE4>Œ1'u#¢šú0Âu†{>˜LFiF×XÍÑK¢Fò†—kÙYJÄ‘C¢:WYa3§Òôæ€G|G ©¦¸!…¨¾ÕºßðX×¶3úïÁh,îƒ!Õ§•‰êZi j²•J_`7Âu†“uº›h2y“ï÷˜š§•‰êWe‘ô±F'r·òMÑ×;Úîi":ÜzLÎjB ‡DõëxÂáDíV¾áè×Cš4‰êלŠÿ.­5aAöÈ`–Åøž`’ð•èk¯GxŒÞ±Šºy¢ Ñ$ÄpHT¿Uü÷£#Þ¶¾>á08ÖéëÓÆø~DD4‰ê×}Þ‹áPöÂÑÃgÁQ9"":AÖÉî8¶,«ÖßU {‰ˆˆˆ¨ŒáˆˆˆˆÊ‰ˆˆˆ¨ŒáˆˆˆˆÊ‰ˆˆˆ¨ŒáˆˆˆˆÊ‰ˆˆˆ¨Œáˆˆ¨þ]à{+nD¯':.,Á&""ª_ç؈á³ÖŸEx–zgÅëžpuôz¢c3ƜԈˆ¨IÝŽp„îö}ý4€ÝÑ5ܽ\éSE¬Õ5R=b8$"":!" ^Ÿªá5ÜŽ£O—®qo ¯‘ê Ã!Ñ )…®÷ÔúBŽâ¦Šëœs’Ÿ‹š7¤¿ó+þû‰Z_ÌQ”‚kÀžZ_ Õ·Ö@DDTGöŽáu—"ÜRkWa8ÄÞWë‹¡úÁpHDD46c>®u0Lø4†×BÞ`}¯‰ê«lˆˆˆŽßÏ®á»G^ŸB¸æ¯Z²åíâðénD×vOþ¨Nqäˆˆèø¤1¼¹ãÇGy¿ûPÝQÄcõž?Êë> `*8rHǃ»•‰ˆˆŽË‡1¼8}’Ÿk¼ÌÁá;•ÙsHcÇpHDDt\J¡ëÑZ_Èq\k©(›è˜XeCDDt|JÓ·µÞx2•»”/«õÅP}`8$"":>¥]Ëõ+» Y‚Mc )DDDcW¹éãXáp¢w+¦2²›Æ„ለhìŽ'Ž÷nåRð<ÚNäÊs—·Žï? 5 nH!""³Ê ¥ 8‡‡°‰¾–Ÿ!¥¬,é¹[ùQLÞÕ4Ép䈈hìUü÷ÈÝÊ{0±ç,—F ¯Âѧ¯Ÿð1»'‘OH!"":i_Áð(ÝÃ׳©á5]à½8|ôð‰èšx®2—“‡DDDDÔ8XeCDDDDe ‡DDDDTÆpHDDDDe ‡DDDDTÆpHDDDDe ‡DDDDTÆpHDDDDe ‡DDDDTÆpHDDDDe ‡DDDDTÆpHDDDDe ‡DDDDTÆpHDDDDeÿ?>‹×(?ã%tEXtdate:create2016-11-10T23:03:49+01:00#VJ>%tEXtdate:modify2016-11-10T23:03:49+01:00R ò‚tEXtpdf:VersionPDF-1.5 \ 9IEND®B`‚leidenalg-0.8.9/doc/source/figures/slices.synctex.gz000066400000000000000000000070021420514302700225020ustar00rootroot00000000000000‹í]QÛ6~÷¯h€/ë|±¬š"ÛÂ%Ž!ßÑÔÅï9 KÙ³XGú‰å°Y/ÖU¹oòýj»|Ë«ES<ÿÂXG»$]Æulâ#$³xIÖBÑbšŸª¬†tÖAß…BØ~˜gånWîaˆ8'‰x¾­a,çÄÀé»Aú´Ê×=¯u’œ†wW/ò—¼z«Ÿ 0ª¡u~h{׺)+W9œÐ³D£¬¬rØMÇ|éVŸ"«û7pò ³f̃2tL˜ WSÈã˜+ÝßY¹‹ªì–œ¥BÇB,Tâe.‚ëüÄYèœrܯ[VyUAKÓáB·m^³Ýj0üŽ9ÐÆYýV7ùîhâ# ¤^é€PŽ‚Z'„6ÍÄÒ¦ÒZ§…‘v]l›¼ÊW ½óN  –Ôy3…î\ Rê¼¹Ò0Ÿ'ñvçؽ–•½.×ÍaÙ<)ã쵩ü‡ªlʬÜ*üÖ9wÞ/ ޲:¿ÀìpL78K¸d,D^™†,#[#¯LÛ ¯´ovˆw"¯$ƒŒâ¹LaõÊ-ÈÚ¦±Âê•aõ°¬ê¼Rx½ò ò®û¬u¤2‡E^É…Swá¡(ðÊ.\A»l—ûr—‹7ª"¯®¨µG¹S48F&7섯‹Zì…GZ˜Wjj=¢¤(»9EÁ8•ǽ²n±›3V*صâhvsîJþBTc›¼žhžDXêfšÝœÓëm¹lZ¯”V'àC)LP;í•Õ{;}Šqjªc¦šà•Ù¸’c½Ü¨‘ê•Ѫ‚:+¹:F^Ù¬²÷@#–Û±Žx¢e¶R½.+NØ${¥´ªæ¿Ç"{VȽÒY%/?ÿ'ÏÔP½²"±Ëòº.öE‹W«Z–UUþ¦Ú0Q2×OË•Cår±CR,ž(‡óWQÂì—ÊŽ(ž(…»ê¸O”Â]z‰å8ßgoc|¢ñÙ‘b÷[ŽËÕq{*!ÏoŸ–ÈÇý–â1ùa[*³?÷8ýì6=Mñ¹-€ßN³;Ì_NWó`3x8îqjV@æ$ n=!]Ê3îzêƒ1¾ÛF±C îX*õèáÍûáqç’ÛÏC[§ŒY'/J¯¼RÿO7cr¯q[|n·±§A8}xkóöI”2[dîLüöµã©AŒNU¼*ä^ "2>ÒªöãÙ¬¦l{Õ"ǬŤß9¹B;±N¾WÛ»9]µßCFǼëuó”ï!‹WÊÙ,vR’z¥¤­FªT©W²ÚêÃ÷o©W:c§á§SÝÚ/NëüÍÚ¡ymη˜Çá;_Ý=EO圭—KÓQðè^ uLÄ [~¨En¯ÖóîÜ:fã…pS­…åÉÿþãùe•¯‹}>Z¦SÇSYÀWNÕ¸e œ³ ðÕy3ê œ³I:Cu, /áôŹÝÍz3ûáØ´¤šým¹Ùë"ëÊÛv‚Ù?÷…P8ûå›ÖkaØc0û—|ûm—íÍãì]’¦éì2{ Cþ|ŒOˆØŠ_ûσٿG- ûuöÜIGOõŸgfïHÀfÓtZ0žºLɵ.Z(]Rc—éÄ]jCt.^H&Lïai=‰¾=\šEœ ´í¹ø3Ûœð3Ø {X6·Ô$›Í‰l ú0– Bñ(H-=G,Jiô8B\(Ãp,ûŠ^E™ß„>`¨t­Vv»f÷þœŸ I¦ãN ˜)c24ÀA–PB™˜2´è{¬ÕìµCiEQœÿ| K¯ËL~’²í‹‚}:ÙTl&&¨KÚ´ƒ>4[JÒ £qOz”, G–ºË ŸÆú¤,EG]A>l*6“SÔ‡©¥mÚAÞbiă‹Ýf©½Ìä§‹Œ*{”nomØÖheS±|(Z#>¨Ñ‡V퀯XŠä!@[Iè'/ô“6E%ƒº‚}:ÙTl&Ô‡ÄÒ‡6í Í–’“„‡£žô(KB~ò‘A?õI™ºã}ÀP O'›ŠÍäÃõahéC›vЇfK±<”( ØY,u—A?éó¢£® @ŸN6›É‡õ!µô¡M;èC³¥XJ4"Q üä#ƒ~Òça„Ud_Ñÿ[­™TÄŸ¡CØî…^ïI0‘ñè‰ š¤„ð``—»L敪OÊÐêME>C…„°Ý ½Þ&¦ ¢<Ñ£\LOÑ`}dpÇú¤ ­9Tè3T0Û½Ðë=ÁâX¢ŒÐ$¥ñÀ.wGmGhõ£¢RŸV†³Ý ½Þ$ŽÊ8MB8Ž^28ŽÚ8ŽÐêDE>C€°Ý ½Þ“ˆó˜÷±¥”³Á8úÈà8ŽõIZ=¨(ÐgØ¡#l÷B¯÷‹c‰Ò4‰ƒ Øå.ƒã¨ctw¯¢@Ÿa°Ý ½Þ,Ž%±¤=âØå.ƒã¨côve݃M€¢ûŽ Pt­½eèú2ŠÎ©wCÑÙåFôÓ&ãZ+û²Ö_ï #ʃtôDR³¸ûbˆ´Ë]vÉWDŸ”¡·¼ÍZkôC†{Ø5»÷çôåa˜¤|ôD’ û¬”Lp"÷¿H³öª·…“TԀю‹Â(‘ð{–.W “2´àUQ`–¡ž„ÍpÔÆÐ+`fylÕµ]±)—˜¡´÷’A?iË%†Ô* ôŠíIØL>D¯€™å°U;èC³¥È6–޼dÐOÚm,C vú Åü$l&¢WÀÌò تô¡ÙR, G^2è'mÆè€ŠJ}ZÙTlÆèplylÕøðŠ¥HƆ£/ô“6cts§¢@Ÿaã7 ›É‡èplylÕúÐl)R®Æ†£/ô“¶\Ñ2BE>ÃaÇ$l&¢WÀ±å°U;èC³¥XŽn¼dÐOú4[Šå¡áhÈKý¤ÏCô"ð+ú èу5ú€ñ‚Öɾ¬×{‚ͼ’8$$Øå.ƒ™©ŸyÑúOE>C…°Ý ½Þ“”11SE£'z”ÓP<ìr—Áqë“2´>SQ ÏP!l÷B¯÷$II†Õ@yÆ|0Ž>28Žc}Gë'•ú´2œí^èõž q PÆ8#<Øå.ƒã¨cŽÖ7* ôj„í^èõž q Q"6jƒqô‘ÁqÔÇ1Z¨(ÐgØã#l÷B¯÷$ “ Qž¸ œS>GDZ>)Cëú {p„í^èõž`q,Ñ( Ã&»ÜepõqŒ^ÓL€¢WÀ è¾c]koGt}™EçÔ P4Æ5(ºÏ¶F0TƵVv»f÷þœžàaÈiÌFOô(i·î„Ò nBä"iÖÞ8¶pPš„c8 XÂI,á÷8|™ä -íT˜¥“MÅf8ð­‘€|¬ÚŸ+–"ÛA€*¥‹— úI»LÐ;wú ÷ñ“°™|£>Œ-}hÓúÐl)²LT)¼dÐOÚe:A¯ðUè3\“OÂfò!ú…€Äò Ví Í–byÈõ¥—— úIŸ‡èሊ}†ƒ“IØL>D¿X~!Àªô¡ÙR,}iç%ƒ~Òç!zø¢¢@Ÿá`f6“Ñ/$–_°j}h¶)+!:.½dÐOÚ²2EwTTêÓʦb3ø0E¿Z~!ÀªðáK‘<¨RšzÉ Ÿ´y˜¢ÅËWÔEŽœPtW¯¢À÷†3Âv/ôzOÄ:Ðá7OJ"–¦p^r”…I)§‰xâö•G´û%5ûÆCæ˜SÖþS§sÛˆ1BˆjM×ÊòQ»V¯]+–°”ó Wðá¬×6ÒY×Ùî ÖÖ‰áÜeN˜Ø±]ž]ëHD”ž÷µ?'§&5l¤ =+ûÂ(ºùWQº† 6Âv/ôzOâ”Ò€’Ñ=J’4ƒd`—‹,Œ"DÁ%»Ÿ´j7âk¿ ÞžšžÛ ²Tifû°e³×®™H‡8àRLJ³n{Üõ•§#,¸<ü<ìÑùañ ‰ÚãóSÃUCEÊÐãáÛQäçO qÁ)<ýh#IåO3D†g~mÇ]ûË™mÜ?]‘·¿ÎÞ…$JÒÙŸ—ÿw8˜ô7Œß¥lö÷²n–»ÏÛüqömyÜ·ÿ»k”Åq'ù¦ÎªâÐw³ÿ¾ yleidenalg-0.8.9/doc/source/figures/slices.tex000066400000000000000000000061671420514302700212010ustar00rootroot00000000000000\documentclass[tikz]{standalone} \renewcommand{\familydefault}{\sfdefault} \usepackage{sansmath} \sansmath \usepackage{tikz} %TikZ is required for this to work. Make sure this exists before the next line \usepackage{tikz-3dplot} %requires 3dplot.sty to be in same directory, or in your LaTeX installation \begin{document} \tdplotsetmaincoords{70}{110} \definecolor{c0}{RGB}{228,26,28} \definecolor{c1}{RGB}{55,126,184} \begin{tikzpicture}[tdplot_main_coords, n/.style={circle,draw=black,shading=ball,outer sep=0pt,inner sep=0pt, minimum size=6pt}, nc0/.style={n,ball color=c0}, nc1/.style={n,ball color=c1}, e/.style={}] %Network t=1 \draw[fill=lightgray,opacity=0.9] (-1,0,-1) -- (3,0,-1) node[below] {$\scriptstyle t=1$} -- (3,0,3) -- (-1,0,3) -- (-1,0,-1); \node[nc0] (a0) at (0,0,0) {}; \node[nc0] (b0) at (1,0,0) {}; \node[nc0] (c0) at (0,0,1) {}; \node[nc0] (d0) at (1,0,1) {}; \node[nc1] (e0) at (2,0,1) {}; \node[nc1] (f0) at (1,0,2) {}; \node[nc1] (g0) at (2,0,2) {}; \draw[-] (d0) -- (b0) -- (a0) -- (c0) -- (d0) -- (e0) -- (g0) -- (f0) -- (d0); %ghost nodes for interslice links \node[e] (a1) at (0,2,0) {}; \node[e] (b1) at (1,2,0) {}; \node[e] (c1) at (0,2,1) {}; \node[e] (d1) at (1,2,1) {}; \node[e] (e1) at (2,2,1) {}; \node[e] (f1) at (1,2,2) {}; \node[e] (g1) at (2,2,2) {}; %interslice edge 0 - 1 \draw[-,gray] (a0) -- (a1) (b0) -- (b1) (c0) -- (c1) (d0) -- (d1) (e0) -- (e1) (f0) -- node[] (f01) {} (f1) (g0) -- (g1); %Network t=2 \draw[fill=lightgray,opacity=0.9] (-1,2,-1) -- (3,2,-1) node[below] {$\scriptstyle t=2$} -- (3,2,3) -- (-1,2,3) -- (-1,2,-1); \node[nc0] (a1) at (0,2,0) {}; \node[nc0] (b1) at (1,2,0) {}; \node[nc0] (c1) at (0,2,1) {}; \node[nc0] (d1) at (1,2,1) {}; \node[nc0] (e1) at (2,2,1) {}; \node[nc1] (f1) at (1,2,2) {}; \node[nc1] (g1) at (2,2,2) {}; \draw[-] (d1) -- (b1) -- (a1) -- (c1) -- (d1) -- (e1) -- (g1) -- (f1) -- node (fd1) {}(d1) (b1) -- (e1); %ghost nodes for interslice links \node[e] (a2) at (0,4,0) {}; \node[e] (b2) at (1,4,0) {}; \node[e] (c2) at (0,4,1) {}; \node[e] (d2) at (1,4,1) {}; \node[e] (e2) at (2,4,1) {}; \node[e] (f2) at (1,4,2) {}; %interslice edge 1 - 2 \draw[-,gray] (a1) -- (a2) (b1) -- (b2) (c1) -- (c2) (d1) -- (d2) (e1) -- (e2) (f1) -- (f2); %Network t=3 \draw[fill=lightgray,opacity=0.9] (-1,4,-1) -- (3,4,-1) node[below] {$\scriptstyle t=3$} -- (3,4,3) -- (-1,4,3) -- (-1,4,-1); \node[nc0] (a2) at (0,4,0) {}; \node[nc0] (b2) at (1,4,0) {}; \node[nc0] (c2) at (0,4,1) {}; \node[nc1] (d2) at (1,4,1) {}; \node[nc1] (e2) at (2,4,1) {}; \node[nc1] (f2) at (1,4,2) {}; \draw[-] (d2) -- (b2) -- (a2) -- (c2) -- (d2) -- (e2) (f2) -- (d2); %Create equations \node[anchor=base,align=left] (S_irs) at (0,1.2,3) {Interslice\\ coupling}; \draw[->] (S_irs) .. controls (1,1,2.5) .. (f01); \node[anchor=base,align=left] (A_ijs) at (0,3.2,3) {Intraslice\\ link}; \draw[->] (A_ijs) .. controls (1.5,3,2) .. (fd1); \end{tikzpicture} \end{document} leidenalg-0.8.9/doc/source/figures/speed.png000066400000000000000000002221111420514302700207700ustar00rootroot00000000000000‰PNG  IHDR°ïâsBIT|dˆ pHYs.#.#x¥?v9tEXtSoftwarematplotlib version 2.2.2, http://matplotlib.org/†ŸÔ IDATxœìÝ{tÝU7þÏ9'9IÓ+é ÁR°X±mZ  Ë%ƒãÃ`¦àÐÂðxÔFe–¢ˆƒèˆ: Ïp±ÃEu„G)ryä²@F >³¼Tl @[Ê¥wJÛ¤Íåœóû#iÚ“æÚ&ç¤ù¾^kuõìýÝßýýä@WÞÙ{§ …B!€DH—» t„ BH!$ˆ€D@ " €@‚ A„ BH!$ˆ€D@ " €@‚ A„ BH!$ˆ€D@ " €@‚ A„ BH!$ˆ€D@ " €@‚ A„ BH!$ˆ€D@ " €@‚ A„ BH!$ˆ€D@ " €@‚ A„ BH!$ˆ€D@ " €@‚ A„ BH!$ˆ€D@ " €@‚ A„ BH!$ˆ€D@ " €@‚ A„ BH!$ˆ€D@ " €@‚ A„ BH!$ˆ€D@ " €@‚ A„ BH!$ˆ€D@ " €@‚ A„ BH!$ˆ€D@ " €@‚ A„ BH!$ˆ€D@ " €@‚ A„ BH!$ˆ€D@ " €@‚ A„ BH!$ˆ€D@ " €@‚ A„ BH!$ˆ€D@ " €@‚ A„ BH!$HE¹ €$Êår±qãÆ½ú'L˜™L¦ I! „2ظqcœxâ‰{õ/^¼8&Ož\†Š€¤°Å($ˆ€D@ " €@‚ A„ BH!$ˆ€D@ " €@‚ A„ BH!$ˆ€D@ " €@‚ A„ BH!$ˆ€D@ " €@‚ A„ BH!$ˆ€¤¢ÜÀpÓ\_?½3Zž]ùƆH׌ŒÊ™3¢æ¼‘­«+wy@ †ÔÐмtil¹òªhùã÷¾¶dI4üèÇ‘;7Æ^sudçÌ)C…©B¡P(w4ëÖ­‹Oið èD@e d©¡C 5t4/]æÝ·ïÅ.ÕU1ñžEþ=JN@e €}gÕZy ¤†ÔвþŒ³z Í»“;7&Þï TÐ=!”€úϪµòH -ûHU}tLøÏG!ŸÈç#r¹ˆ|¾S»…|[[_> …=Ææò…ÝcÛîÏí›ÏGtnÚ>·ÝŸë¢]èx~G-]µ;Õº÷ØÂµu®uïÚ»¬5ß~mWù=jm¿¶ûÙ¹(ìlŠüºuûü½œøðƒ~Á(©Šr½é몵æ%Kbü³­Z$[®¼ªá`DÄΦxë+_ݯR…B[¹\[`ÓÕç|>¢µµ=àÉíõ¹k}r¹(´æÚ?ç£ÐÚÚõçnŸ“‹hÝ㙹\û}]}Îí~f.‘kíô¹‹Z{­¯mîüÎQØ´iŸÞgËŸþoÌF %wÞ% JJ@жµ,Ÿæ¥Kû¾¥eDÄΦØ|ñÅôªµŽ@¬µµ-œÚãïhÍE!×Z|­µ½Ýšk ž:Æ´VûŠ®åöž+·÷µÜºuû´Z-¢-¸]÷gˆÈV¶­ÂÚ+h˵×վЫµµ=,Û½ê †³–g——» a„=èi[Ëæ%K¢áG?¶­å Û×Uko^öÙûÕ¯ôšuàz ÍÚæØ=WO×ö#œÛærƒó2˨õå—Ë] Yù†íå.H!@7lkÙ¦ËE¡¹9bçÎ(47G¡©©íïMÍÍQhÚ£¿£¯}LÓΈ¦=ÛMQhoGsS{{Ͼ]cÛû£°mÛ>ÕݺbElú»ÿ5Ào`à¥GŽ*w @º0¶µìæv…híáÙîÀmwÀ¶w×Ôv_§@¯(˜+ ùvz…¦æ¢{£µu@¾ºV9sF¹KF@Ð…}ÝÖró'/Ž‘çŸ·{e\G×´×*ºâ¯}õ`8¥RétD&‘NE*ik·ÿIuu­«±™t¤R»¯E:Ó~oûõT:R»®e2ííôîùRéHíº–N·ß¿»Ú£¦H·??“é¢ÎtDjk™L§v{-í×Z_-¶_÷¿÷ùõÕ,˜?€ß €Þ €a­°sgä·m‹üÖmQضµýïm‘ß¶5 [·µ_ÛÚÞ·- [·EnÝÚh]ñâ>=/÷꫱õ[ßà¯P©TDEE[•δ}N·O™LÇß‘IG*S±ûs:QÑ>f×çô®ñéˆLE[X•ÉNg"Õ~_ñçögVT즊ž¿Ççt:RŸso¼Û¾ó¯ûü ºéƨ|×ô=‚³=B·ô®nwð–Jíºíj殮R©ü˜šžx²Ëój{“;7²uuƒP@÷„0Ä5××GãOg—G¾±!Ò5#£r挨9oÁ°þb¡PˆèîµxE¡Þ^×ö ·E47—ûKò¨¨ˆ¨È´\»ƒ¨ö¿#“i œ:Æ´‡Z_Ëooˆæ§žÚçrF}òÂȼýíÝ`»ÂµöÏéöÚ:>ï®eÒíZûØ=?w®eÚW¡íúº‡I˜µóWïs Uó×g BEÉ6îë_‹ óÎîßêóêª{ÍÕƒW@7R…B¡Pî" iÖ­['žxâ^ý‹/ŽÉ“'—¡"`(j^º4¶\yU?üÍÎc¯¹zÀμ(…B! ;wFakqp×õн­{„€Å㢥¥Ü_ ºt:RÕÕ••û_ën®¾q{ôõTCEEG_××vÍßEß ­èZÆYûHM¼ÿÞ¯'éš—.ݧ@j ÏJ¥ØŽGëûùµÕUQ»paŒ8ù¤Á/  !”€èM9ÀX(¢°cÇ^á^×[sv¿m§óó¦²2RÙl¤ªª"²ÙHUWE*[©ªªHe³UUí}Ù=úª#Uµ»]toUu¤²ÙÈ­[[¿ñ/û\ÖćÖ+mKM 5ô¤†žæ¥Kã­¯|5š—,évÌPý 9„PB 'ûóøÊÙ³£ÐØØiU^ñ–›{]ë¼mçöí½IEÅîp­ªª=p«î"¬ÛÕníö ëÚû÷ ë:æÛöEç@o×çLfоD«Ö†ÔÐ#ššëë£ñλڶoØé‘£Ú¶_0ß/.e' „2=Ù×0$v4¹ÜÀD¿¥'LˆŠw¾³hu\_VËu襲U]¯¾«®ô`n¨°jmèH M)úJ@e €d) QhlŒü¦M‘߸)r›6E~sÛçü¦M‘Û´9ò›6¶}~cmä7l(wÉÃ^jôèH©1£#=zL[{Ì®¾1Qhhˆ†þÇ>Ïo[ËgÕÚÐ$€SE¹ €M¿ü¦Í‘Û´±+Ÿè^*Õ)Ü©ÑcŠÂ½¶¾]ߘÝãv]5*Rét¯j^V¿ÏÛZ FÞˆ“OЉ÷,²jmˆÉÖÕùç@BOàW"éôîp¯«oôèHï ñöºÖ¦FŽìS¸7Æ}ýkû´­åØk®¼¢.;gNL¼ÿ^«Öö“€€"ÍõõÑøÓ;Û~ðÞØéš‘m?x?oÁóƒwß H§;B»®Vïuîu S#GF*•*÷WÒgÙ9s¢váÂ~okiåÚà³j `ÿ8ƒÊÀ„ EÍK—Æ–+¯êqKÅrmÝ'ðÛO™L^Ï[sv¾–ª©9 Â½Ô¼t©m-V„PB†š>ÖïUR#N>iŸŸ'ðO=ñá…U@œAp[®¼ªÿaÝΦØ8ÿ¼¨8|ªÀ/¢ÇÀ/=~|¤'Œtm{{ÂøHÝ㊾¦§žêq«×îdçν$Xó²eûDED¶n–eõ\Ñ1À_ûú×öiUçØk®°€áK@0¹ÍoFË3õѲ¬>þó§å.§4ÊøõWvΜ¨]¸°ßçBîÚò 'B€a,·iS´,[-õÏDs}[(˜{õÕr—µÿ°Ào_Œ8ù¤˜xÏ¢xë+_æ%Kº—;7Æ^sµpè3!À0‘[¿¾-\¶,Zê룥þ™È½þz¹Ëê›]_m{¸7¾=àÛõy|m¤ÇOhk#5fÌøí‹ìœ91ñþ{£¹¾>ï¼+Zž]ù†í‘9**gΈšó9ô›€àS("¿n]4/«o룹¾>òkו»´Ý~*[W'Œ€`+ ‘{ýh©oß&´=ÌoØPîÒ""¢ò˜cbä‚ù?€ˆ€`ˆ( ‘{õÕ½¶ ÍoÚTîÒº5î›ß°² à# (ƒB¡¹W^‰–eõÑüÌ3Ѳ¬m…`þÍ7KVCzâĨ¬«‹–åË#¿vm¿ïÏÎ+8 Y!ŸÜªÕÑÜ~^à®P°ðÖ[%«!}ðäÈÖÕEeûŸììºHOž©T*š—. óÎŽØÙÔ÷ ««bì5W^Á !À*äóÑúòʶ3—Õ·…‚Ï<…mÛJVCæmo‹ÊÙ»‚ÀÙQY7+2“&u;>;gNÔ.\›/¾¸o!auUÔ.\Ù9s°jJE@° ¹\´¾ôÒî pWØÐP²2o{Tήk_8+*ëê"3aB¿çqòI1ñžEñÖW¾ÍK–t;.;wnŒ½æjá ÀL@Ð…ÖÖh]±"šëŸéØ&´åÙg£°cGÉjÈL=,*gµmZ9».*gÕE¦ö ›?;gNL¼ÿÞh®¯Æ;g—G¾a{¤GŽŠÊ™3¢fÁ|g B€N --ÑúŠhîØ&ô™h]¾< ;w–¬†Ìᇷ³£rÖ¬ÈÖÍŠô¸q%yv¶®N0Œ €D+47GËóÏ·­¬oß*ôž‹hêÃY|!•ŠŠw¼£}Eଶ3gÍŒô˜1¥y>‰# †Œæúúhüém[[66DºfdÛÖ–ç-m…;£å¹ç¢¥þ™¶ pY}´<÷\DKËTßétTyd{ؾMèÌ™‘5ª4Ï€C@óÒ¥±åÊ«¢åÜûÚ’%Ñð£GvîÜ{ÍÕ‘3§Osv숖ÿy.š—-‹–gži Ÿ>¢µu ËïZ:ÓßÙºömBëfµ…55¥y>tC@”ÕŽG‹Í_±³ç-=›—,‰ óÎŽÚ… cÄÉ']ËïØ-Ï<Û.‹æúúh}aED.7˜¥ïVQ•Ó§·­¬›ÙºÙQ1ãÝ‘1¢4Ï€~eÓ¼tiŸÂÁ;›bóEÇØ¯-¢qG4/«–gê£uÅ‹ùüà»KeeT¾ë]Q9»®}u`]TuT¤ª«Kó|ØOB l¶\yUßÃÁ]ššâ­úÂàÔY6•ï>**ëfG¶nV[ø®wEªªª4Ï€A Ê¢yÙ².Ï,›êª¨|÷Œö pvTÖÕE廦Gª²²Ü•À€eÑxç]e{vªº:*gÎl?3°m«ÐŠw)  „@Y´<»¼$ÏIÕÔD嬙EÛ„Vyd¤2™’<†!PùƆŸ35jTTÖÍŠÊY³";{v[xÄÂ@؃€(‹Ôˆû7A&Ù÷¾7²³ëÚ¶ UG©tz@ê€áJ@”\î7"÷Êšýš£æï΃þåT$‡_±Jªé¿ÿ;Öÿ§E~ãÆýšgä‚ùT$‹€(‰B¡Ûo¹56ž»`¿ÃÁìܹ‘­« Ê Yl1 º|ccl¹üŸbÇ}÷ïÿdÕU1öš«÷H(!0¨ZW®ŒMŸ¸0ZŸ{~ÿ'«®ŠÚ… #;gÎþÏ e‹Q`Ðìxô±XÚ_õV̘•³g÷8&;wnL¼gQŒ8ù¤,Ç B`ÀòùØvÝõ±í{×õ:väÇ>c¯úJ¤²Ùh®¯Æ;g—G¾a{¤GŽŠÊ™3¢fÁ|gÀ*¿eKl¾ä²hzüñžVWÅA×^5>§£+[W'€A& LËòÿ‰MŸøDäV¿Òã¸Ì”)Q{Û-‘5«D•»8ƒ¿øEl8ãÌ^ÃÁª?ÿ@L|ð—ÂA(+€ýRhi‰·®ùF4Ü~{¯cG_zIŒ¾üó‘ÊdJPÐ!°Ïrë×Çæ‹?Í¿ý]ãR£FÅAÿv}Œ8å”UtG@쓦?,‰Í]ùµëzW1}zÔÞzKT9­D•=q!Ð/…B!¶ÿÇbã9î5¬>ýô˜øÀ}ÂAB¬ ú¬°cGlùÒ—£ñg?ïy`:c¾|EŒºè¢H¥R¥)è!Ð'­kÖÄæ /Š–úúÇ¥kk£öû7GÕ ï/Qe@€^í\¼86ê3Qز¥Çq•GωÚ[þ=*=´D•ýå B […B!¶ÝxSl:ÿ‚^ÃÁšóÄÄEw `ˆ³‚èR~Û¶x󳟋=ÜóÀl6Æ}ýšyþy¥) Ø/B`/-+VÄæ¿¿0Z_z©Çq郎ñ·ÞÙc)QeÀþ²Å(PdÇ/Œ §ŸÑk8˜}ßûbÒ# àc!…ÖÖØúíïÄö›nîu쨋>c¾tE¤*ü_ 8Ðø©¹Í›ãÍO}&šžzªÇq©šš÷¯ß‰š³Î,QeÀ@@Â5/]›/¼(r¯½Öã¸ÌGÄøÛn‰Ê£Ž*QeÀ`p!$XÃ]wņ¿9»×p°ú/OŽIþ_á V@ššbËUÿ?ùIÏS©}ùçcô¥—D*í÷Š`8@Âä^#6}ò¢hyúéÇ¥ÆÚnˆê¿ø`‰*JA@ Òôÿþ;6êӑ߸±Çq•3fDím·DÅÔ©%ª ({…@ …Ø~Ë­±qþ‚^ÃÁóæÅ„ûïÀ0e! sùÆÆØrù?ÅŽûîïy`EEŒýç¯ÆÈ~$R©TiŠJN@ÃXëÊ•±éFësÏ÷8.=iRÔþû÷£ê=ï)Qe@¹Øb†©>ëOû«^ÃÁìqÇŤ‡~)€„À0SÈçcëw¿›?ú±(lÝÚãØ‘ýHLøùÿ‰ÌÁ—¨: Ül1 ÃH~Ë–Ø|ÉeÑôøã=¬®Šƒ®½6j>|Ni † ! -Ëÿ'6}â‘[ýJã2S¦Dím·DvÖ¬U %¶€a ñ¿ˆ gœÙk8Xõ爉þR8 f!À --ñÖ5߈†ÛoïuìèK/‰Ñ—>R™L *†*! rë×Çæ‹?Í¿ý]ãR£FÅAÿv}Œ8å”U eB85ýaIl¾è¢È¯]×㸊éÓ£öÖ[¢òÈi%ª êœAB¡ÛÿãG±ñœ÷VŸ~zL|à>á PÄ B8@vìˆ-W|)~wÏÓéóå+bÔEE*•*MqÀC@€Ö5kbó'>-Ï<Óã¸tmmÔ~ÿæ¨:áý%ª 8Ð`ˆÛùıùÓÿ…-[zW9gvÔÞzKTzh‰*DÎ €!ªP(ĶnŒMç_Ðk8X³`~L¼g‘pè•„0å·m‹7ÿñ³±óáGz˜ÍƸ¯_#Ï?¯4…<! 1-+VÄæ¿¿0Z_z©Çq郎ñ·ÞÙc)QeÀp`‹QBvüòÁØpú½†ƒÙ÷½/&=òpè7+`(´¶ÆÖo'¶ßts¯cG]ôÉó¥+"UáÆ€þó“E(³ÜæÍñæ§>MO=Õã¸TMMŒû×ïDÍYg–¨2`8@5/]›/¼(r¯½Öã¸ÌGÄøÛn‰Ê£Ž*QeÀpå B(“†»îŠ sv¯á`õ_ž“ü¿ÂA`@XA%VhjŠ-Wýs4þä'=L¥bôåŸÑ—^©´ß醀J(÷ú±é“EËÓO÷8.5nlÔÞpCTÿÅKTB(‘¦ÿ÷ß±ùSŸŽüÆ=Ž«œ1#jo»%*¦N-Qe@’د Y¡Pˆí·Üç/è51o^L¸ÿ^á 0h¬ €A”olŒ-Ÿ¿bÒ¤IqÈ!‡Ä1Ç•••å.oÐ6ŸÜÞ IDAT477ÇÊ•+ãõ×_µk×FCCC477GMMMŒ;6¦M›GuTd³Ù}î³Ï>«W¯ŽuëÖEDÄäÉ“ãðÃ3f ès€á-¿eKl¾ä²hzüñžVWÅA×^5>§4…ìA@8Ä<üðÃñÃþ0ž~úé.¯7.N=õÔ¸ôÒK£¶¶vÐêø‹¿ø‹xíµ×d®¿ù›¿‰k¯½¶Ûë=öXü×ýW,[¶,^~ùåhmmíq¾l6úЇâüóÏã?~Ÿëjii‰;î¸#~þóŸÇ+¯¼Ò嘩S§Æ9çœûØÇ†u0 ì¿–g—Ǧ /ŒÜê®ÿ{²KfÊ”¨½í–ÈΚU¢ÊŠÙbtˆhhhˆÏ}îsqÙe—uFDlÙ²%î¼óÎ8ãŒ3âÉ'Ÿ,a…û®ªªªÇë·ß~{Ü}÷Ýñ /ôF´­2|衇âïþîïâòË/†††~×´jÕª8÷Üsã»ßýn·á`DÄêÕ«ã»ßýnœ{î¹±zõê~?H†Æ{~Î<«×p°êÏ?ü¥p(++‡€\.Ÿýìgã‰'ž(꯭­3fĨQ£bÍš5±|ùò( ±qãÆøô§?wÜqGwÜqå(»ÏN9å”~Ïf³1eÊ”8ôÐCcÔ¨Q‘N§cëÖ­ñÒK/íµªñˆW_}5n¿ýö9rdŸæß°aC|üãßk®©S§Æ‘G…B!^|ñÅ¢àðÙgŸüãñ³Ÿý,Æ߯¯¾ --ñÖ5߈†ÛoïuìèK/‰Ñ—>R™L *è^ª°+q¢l¾õ­oÅ~ðƒŽveee|ñ‹_Œ¿ýÛ¿-:kïÅ_Œ+¯¼²h…á¸qãâˆI“& hMk×®íÓj¾Îþó?ÿ³èk9ôÐCãW¿úU¤R©nïùÈG>ét:>ðıÇ3fÌˆŠŠ®³ë+VÄM7Ý=ôPQÿyç_ýêW{­/ŸÏÇüùócéÒ¥}'NŒk¯½6N8á„¢±‹/Ž/}éK±aÃ†Ž¾cŽ9&î¼óοž¾X·n]œxâ‰{õ/^¼8&Ož¼_s¥‘[¿>6_ü©hþíïz—5*ú·ëcD?Y`°ËlÍš5qê©§FKKKGßM7Ý'tR—ãwîÜýèG‹BÂsÏ=7¾öµ¯ z­}qê©§ÆË/¿ÜѾôÒKã3ŸùL÷´´´ôû|¿ë®»..\ØÑN§ÓñÄOô”Þ{ï½ñ…/|¡£=nܸX´hQ¼ýíoïrüš5kâì³ÏŽ·Þz«£ï{ßû^œ~úéýª·3!Øšþ°$6_tQä×®ëq\ÅôéQ{ë-Qyä´UÐ;g–Ù7ÞXΛ7¯Ûp0"¢ºº:¾ùÍoj‹-Š5kÖ j}±dÉ’¢p0NǼyóz½¯¿á`D[ð¸g¨—ÏçãW¿úU÷är¹¸á†Šú¾øÅ/vFDL™2%¾øÅ/õ]ýõ‘Ïçû]3pà+ ±ý?~Ïùp¯á`õé§ÇÄîCŽ€°ŒvîÜ<òHQß'>ñ‰^ï;âˆ#ŠBÄÖÖÖx༾þZ´hQQûýï¼ímo”ge2™xÿûß_Ô·ç™]Y²dI¼úê«íÉ“'Ç™gžÙë³Î:묢U}¯¼òJüñìgÅÀ®°cGlùìçâ­/}9b_ìØK:c¾òå¨ý÷ïGzÔ¨ÒÐGÂ2zê©§bÇŽícŽ9&¦MëÛJ“Î+ó}ôÑ­­¿ö:ðœsÎÔgŽ7n¯zÒùýõ_ÿud2™^Ÿ“Édö Ëý¾Òj]³&6üõ¼hüùÝ=ŽK×ÖÆ„;£/¾x¿Ï*,å. É/^\Ô~Ï{ÞÓç{;¨¨ˆÖÖÖˆˆX¾|ylܸ1&L˜0 5öÕƒ>íÚÚÚøÐ‡>4¨Ï|íµ×ŠÚ½?øä“Oµûó¾ßóž÷Ä­·ÞÚÑ^¼xq\qÅ}¾úšëë£ñ§wF˳Ë#ߨéš‘Q9sFT¼kzlýÎw£°eK÷WΙµ·Þ‡Z¢Šö€°ŒV¬XQÔ>úè£û|oMMMLŸ>=–/_^4_¹ÂÎÛ‹žuÖYût¶`_½ùæ›{¬ï}ï{»ßÜܼפýyßÇ{lQ{õêÕÑÜÜÙl¶ÏsCSóÒ¥±åÊ«¢¥‹­ƒ›—,éÓ5 æÇ¸¯_©êê.`ÀÙb´Œ^~ùå¢öÔ©Sûuÿ”)SŠÚ/½ôÒ~×´/^zé¥xúé§‹ús{ÑíÛ·Çg?ûÙØºukG_]]]üñÝÞóòË/G.—ëh?>Fõãl°Q£FÅAÔÑÎår±jÕªþ 9;},6Ì;»Ëp°O²Ù÷íoÅAÿúá pÀ°‚°L¶lÙ[:mW÷¶·½­_srÈ!EírVwß]|&×ÑGGyä€ÍŸËåbûöí±råÊxê©§â®»îŠ 6t\7n\|ë[ßêqŽÎ«ûû®#ÚÞ÷›o¾ÙÑ^½zuLŸ>½ßóCCóÒ¥±ùâ‹#v6íÓý郎ñ·ÞÙcàÊ—€°L¶mÛVÔ1bDÔÔÔôkŽÚÚÚ¢ööíÛ÷»®þjmmûï¿¿¨oWþð‡?Œo~ó›}{ÔQGÅ÷¾÷½˜6mZãö\mѶ‚°¿:¿ïÎßCàÀ²åÊ«ö9̾ï}Q»ðæÈ”i[g€ý! ,“†††¢vUUU¿ç¨î´]ç9Ká׿þulܸ±£]SS§vÚ ?÷øã .¸ N>ùäH§{ß)·±±±¨ÝùÝõÅPxßÀÀh^¶lß·ˆ1_þ’p8` ˤs`5aç9K¡óö¢§žzjŒ9rП»dÉ’ˆˆÈd2qÒI'õ:¾ó»Éf³ý~fçïQ9Þ700ï¼k¿îßñóŸGÕ1GP5¥% "R©TIîHëׯ'Ÿ|²¨o·Ý5Çž¡_KKK¼õÖ[ñüóÏÇO<¿þõ¯#—ËÅïÿûøýï§œrJ|ûÛßîתÀñ}§åÙåe½ œ„eÒù¼Á;wö{ŽÎ÷ô÷ Ãýuï½÷FkkkG{Ú´iqì±Çî÷¼£FŠQ£FíÕôÑGǹçž/¼ðB\~ùåñüóÏGDÄ#<Û·oÛn»­ÛíF;¿›¦¦þŸ;ÖùžR¿o`àä÷o‹à|CéÏ|(½ÞÆ è¼ ç¾Vå-ZTÔˆÕƒ}1}úôøÑ~S§NíèûÍo~?þñ»½g8²ÀÀI×ìßVÈé‘{ÿÀB@X&WÈíØ±£ßgÚmÞ¼¹¨=zôèý®«¯þð‡?ĪU«:Ú•••qÖYg•ìùãÆ‹/|á E}·ß~{ ….Çw~7ß]_lÚ´©¨=f̘~Ï •3g”õ~€r–ÉAcÇŽ-ê{ã7ú5Çk¯½VÔ>üðÃ÷·¬>»ûÚüàcüøñ%{~DÄ>ð¢ uݺuñ /t9vÏÕ†¯¿þz¿Ÿ×ùžÎsŽšóìßý æP%¥' ,£w¼ãEíÕ«W÷ëþW_}µ¨=mÚ´ý®©/¶oß?üpQ_©¶ÝSEEEvØaE}¯¼òJ—cßñŽwD&“éhoÚ´)¶oïûbÛ·o7ß|³£ÉdJÈ+[W•ûxfjvîÜÈÖÕ pE¥# ,£éÓ§µÿô§?õùÞÆÆÆxþùç‹úÞùÎwH]½yðÁcÇŽíÉ“'Ç 'œP’gwVQQQÔnnnîr\6›)S¦õõç}ÿñ,jO:5²ÙlŸï†žq_ÿZDuUÿnª®Š±×\=8”ˆ€°ŒþìÏþ¬¨ý»ßý®Ï÷þáˆÖÖÖŽöŒ3b„ V[O:o/:oÞ¼¢Õy¥´víÚ¢vOÛœîÏûî<öÄOìó½ÀД3'j.ŒèkØ_]µ FvΜÁ- ` Ëè„NˆêêêŽöÓO?/½ôRŸîýÅ/~QÔ>餓´¶î¼øâ‹±téÒŽv*•гÏ>»$ÏîlÅŠ±~ýú¢¾ž¶ý<ùä“‹Ú÷Ýw_är¹^Ÿ“Ëåâþûïïq.àÀ4âä“bôe—ö:.;wnL¼gQŒ8¹4ÿ­LÂ21bDœrÊ)E}·Ýv[¯÷­\¹2}ôÑŽvEEEœqÆ^_W:¯|ï{ß»×Ö¥rà 7µgΜ|p·ã;î¸xûÛßÞÑ^»ví^Á_Wî¿ÿþX·n]Gû°Ã‹c÷ñì2`Êç»î1"F~äÅćŒ‰÷ßkå 0lËì’K.‰ÊÊÊŽö=÷Ü¿úÕ¯ºßÔÔW\qE´´´tô}öÙqØa‡õøœw½ë]E~ûÛßö»Ö–––¸ï¾ûŠúÎ9çœ~ϳ§»ï¾;V¯^ݯ{ …B\ýõñÈ#õŸþù=Þ—Édâ’K.)ê»öÚkãÕW_íöžW_}5¾ùÍoõýã?þc¤ÓþÕá¢uåª.û«?øç1î_¾ÙººÒ0Ȥe6eÊ”¸à‚ Šú.»ì²øÉO~ÍÍÍEý/½ôR|ä#‰§Ÿ~º£oܸqñÿð%©õñÇÍ›7w´ÇŽù—¹ßsžvÚiñ™Ï|&~ùË_Æ–-[ºÛÒÒ?þx,X° ¾ÿýï];þøãcÞ¼y½>ïÌ3ÏŒ9{¬Ú²eKÌŸ??žzꩽÆ>ùä“1þüxë­·:úŽ9æ˜8í´Óúò¥ˆÖU«ºì¯èaËb€YE¹ âòË/_|1/^mAØ5×\7ß|s̘1#FŽkÖ¬‰åË—G¡P踯²²2nºé¦˜4iRIê\´hQQûŒ3Έªªªýž·µµ5{ì±xì±Ç""âC‰©S§Æ˜1c¢ªª*býúõ±bŊعsç^÷×ÕÕÅÍ7ß©Tª×g¥Óé¸ñÆãÜsÏ×_=""6lØÿ÷‡~xyä‘Q(âÅ_Üke㡇7ÞxcŸž8rB a„C@&“‰ë¯¿>®¼òÊxðÁ;ú7mÚO>ùd—÷Œ?>®½öÚ8î¸ãJRãºuëöZe·¿Û‹vçõ×_ïïz’Édâ‚ .ˆË.»,jjjú<ÿ¤I“â?øA|îsŸ‹åË—wô¯Zµ*VuÌœ93®»îº˜0aBŸŸ }ù·ÞŠü+£÷$ †+á1räȸîºëâ”SN‰;î¸#þô§?u9nܸqqê©§Æ¥—^µµµ%«ïž{î‰\.×Ñž9sf¼ûÝïÞïy?ÿùÏÇìÙ³ã7¿ùM<óÌ3ÑØØØë=‡zhœvÚiqöÙgÇG±OÏ=âˆ#âg?ûYÜqÇñ³Ÿý,Ö¬YÓå¸Ã;,>üáÇÇ>ö±¢³"ᡵ‡3P3B`˜Jöܳ’!c×–¢ëׯ;vÄ„ âC‰c=6²Ùl¹Ëù|>V®\¯¼òJ¬]»6¶oßÍÍÍQSS£FŠÉ“'ÇŒ3eß3Ï<«V­Šõë×GDÛ*ÃÃ?÷ç)ŸÙKÃdÞsß7U)1 ¬¯K³ €Ô ¨:ÍëÖEóÂEEkÙºÑ)w.!U'?gNb-[_Ÿb'éPu’–l6jGŒHµ€´ ¨:¹Æâ3kGŒˆL6›r7éPur Edzõui¶PBªN>a‰Ñl]]ª}”‚€€ª“´¡€¨BªJaÆÈÏŸ_´& ª€€ª’{õÕˆB¡h­V@T!U%iyѨ©‰ìÈ©öP BªJ®¡±èxíðá‘éÖ-ÝfJ@@@UÉ'Ì ÌÖ×¥Ù@ɨ*IKŒfí?T !U%×8§èx­€¨BªFaÓ¦È75­Yb¨BªFnnSDssÑš%F€j!  jäŠ2™ÈŽ•n3%"  j䋎יîÝÓm D„TÄ€Ðò¢@P5’Âl}]šm””€€ª‘kh,:ž­¯O·€P ›7G¾©©h-[7:ånJG@@UÈÏ›‘Ë­eíAT!U!iÿÁˆˆÚÑfÕC@@UH k† Žšž=Óm „„T…Ü+EÇ-/ T!U!i¡€¨6BªB^@Bª@!ŸÜ«¯­ €j#  âåçÏØ¼¹h­¶¾>ånJK@@ÅË54&Ö²u£Ók Pñ’ö¬Ùe—¨éÝ;ÝfJL@@ÅË%„öª‘€€Š—Z^¨>B*^R@Xk!P…„T´BssäæÌ)ZËÖ×¥Ú @g  ¢å,ŒØ°±hÍ„@5PÑò Ë‹FDdGÛƒ¨>B*ZÒþƒ5DMÿþé6Ð ¨hIam}}ºtB*ZR@hÿA Z ¨h¹†Æ¢ãÙúº4Ûè4„T¬B¡y3ZP±š/ŽÂúõEkB Z ¨X¹††ÄZ­€¨RB*V.ayÑL¿~Q3 ºÍtB*V®¡±èx¶ntd2™t›è$„T¬|㜢ãöª™€€Š•´Äh¶¾>ÝF:!©P($„fUL@@Ej^¶, kÖ­Õ €*&  "åkÙúº´Úèt„T¤|Âò¢™Þ½£f§Òm P‘r Edzuu‘ÉdRî óP‘r 3³öªœ€€Š”ÖÖN·€NF@@Å) ‘kh,ZËÖ×¥Ù @§#  â4/_…U«ŠÖ²õõ)wй¨8ù„åE#ìA  â$í?˜éÑ#j J·€NF@@ÅI këê"“É¤Û @'#  â䋎gëëÒl SPqr EÇí?  å–¨0Í+VDóòåEkB€ˆl©€ö”›3'±V+ x[/Ì_w<Ù//\ë6å¢g×lŒÒ'>¼ÿˆØcXßR·W2iþ^*õYi?Ïk+¿géÉ …B©›€j³hÑ¢8øàƒ·衇bðàÁ%è*ǺÛoåŸ?wËB÷n1ìå—"Scò<@1ÏÏ[?¸ûùx¦ieâ9ãGö ŽÙ#öÞ/ÅÎJ+ÍßK¥>+íçymå÷, }B(!tœU?úq¬þþ[ŒgÇ탘V‚Ž:¿G^\_½iflÌ5¿í¹Ý²5qù¤}ãÀqƒR謴Òü½Tê³Ò~ž×V~ÏJÃ4 *J¾±±è¸ýŠ{~ÞÊm""6æšã«7ÍŒçç%Ï*ªiþ^*õYi?Ïk+¿g¥c!”€„Ðq–œpRlúç?·ï}Ö™Ñïk—• #€Îí³×þ}«K&6 G|âßê[Ž“þQ‘ôÏÄ„$ E Iÿ’i{ßð·9±p冤;%Ú¿{Lzïè6]sãß+óYi?Ïk+í³Æì×~ö½m¾( !”€€:΂ ûGó’%[Œ÷ŸüÝèõÉO” #€Îë…ù+ãÓ?ý{©Û*įÎ: öÖ·ÔmÛÀ£TŒæ5kІƒµ–ØÂOÎ+u @¹óɦR·l#!#—°ÿ`DD¶¾.­6ÊÆË W—º ‚¼äï(B*F¾¡±x¡K—¨6,Õ^ÊÁºM¹R·T§@ùP1’ffGŠLmmºÍ”ž]³¥n¨ þN€òáÝ;#) ´ÿ @qc‡ô‰§ç®Øîë{wËÆÀÞ][e2™6Ý#éôbÃI÷N|b‘BÒ¹o¾÷â•båúÍIw}[ýzv‰Á}»oÓ¹‹*ôYi?ÏkëÏÚ}HŸí¾H—€€Š‘8ƒ°¾.Í6ÊÆá{‰[þ9w»¯¿úÓïŽ=†õmÇŽ:‡毊OÿôoÛ}ý?ñ®mþ½Tê³Ò~ž×Ö9žuüþ#¶ûZ ]– b¶]ss!~ûhÃv_?~dÿŠ #"öÖ7Þ1¢ßv]ÛÖßK¥>+íçymå÷, ´„T„æuë¢yᢢµ¬%F¶ð‹¿ÌŽ¿¾¼t»®í–­‰ ŽÙ£;ê\.ë7åâ³?,f/ZS´Þ³[m\vÂøxü•eñÒÂÕ±nS.zvÍÆîCúÄñû¨êýÅ^˜¿*î|²)•ßK¥>+íçymå÷, =B(!´¿å_þJ¬ûíõ[Œw;ô±óo®+AGK¡Pˆ¯O}:þôô‚Äs¦œ:!>°§÷"PéìA@EÈ54·ÿ ÀënzìÕ­†ƒŸ:¨^8UB@@EÈ76D̘³<®º÷ÅÄú{Æìg66ÅŽ€RPö ë×G~þü¢µl}}ÊÝt.KVmˆKnšùæâ; é×=¾5qŸ¨­É¤ÜP*BÊ^nîÜÄZ­„@ÛœkŽKnš¯­ÙT´Þ5[SNý{uM¹3 ”„”½\Âò¢QSÙ‘#Rí 3ùñ½/ÄÓsW$Ö¿|Ü^±Ç°~)vtBÊ^®¡±èx툑éjV Pî™9?nþGò ëß52ŽÛoxŠ…€€²—O˜A˜­n#Ä‹ VÅ”;žM¬ï=¢_|é˜=RìèL„”½¤„YûUhåºMqñ3bc®¹h}@¯®1yÒ„èšõO¨V> ì%íAX+ ªL¾¹_ŸúTÌ_¾¾h½¶&ß9yßÔ¯{ʉ€€²Vظ1òóæ­eëëRí Ô~þçYñ÷YËëç|p÷xgýÀ;:#!e-7·)¢¹ø2z–ªÉC/,Ž_>ôJbýˆw ‰Ó°7+  Ìå–L&²£F¥Ú @©¼ºlm|ó–§ë»ê—|xïÈd2)vtVBÊZâþƒÃ†E¦»=¶€Ê·nc..ºaF¬Ý˜+ZïÕ-SN=»eSî 謄”µ¤€Ðò¢@5( ñÝ;žW¯I<çë'Q;õJ±+ ³PÖg *pÃßæÄýÏ,L¬æà]ãà=¥ØP„”µ\CcÑñl}]šm¤î‰†×âêû^J¬¿o·â³‡î–bG@¹P¶ ›7G¾©©h-[7efIº IDAT:ånÒ³x冸ô÷3#ß\(Z6 G|sâ>Q[“I¹3 ([ù¦¦ˆ\®hÍ„@¥Ú”kŽ‹ošË×n*Zï–­‰É§Lˆ~=»¦ÜP.„”­¤ý#"jG›AT¦ÞóB<Û´2±þ•ã÷ŠqCû¦ØPn„”­\㜢ã5CGMÏž)wÐñîš>/n}|nbý£ïÇNžbG@9P¶r EÇ-/ T¢毌ÿºë¹Äúø‘ýã Gí‘bG@¹P¶’–ÍÖ×§Û@[±vS\tãŒØ”k.ZØ»k|wÒ¾Ñ%ëí=ðö|‚@ÙÊ'„f$ß\ˆËn~*®ØP´^[“‰ïNš»ôížrg@¹P– ù|ä^}µhM@T’Ÿ=ðrüó•e‰õóFH±# Ü (Kùùó#6o.Z«âÁçůnH¬9~hLzߨ;*€€²”khL¬eëF§×@i\²&¾uëÓ‰õ1ƒ{ÇÅÞ+2™LŠ]•@@@YÊ5ŸQS³Ë.QÓ»wÊÝ´¯µsqÑ3bÝÆ|ÑzŸîÙøÞ©ûE®Ù”;*€€²”ol,:nÿA Ü …¸ü¶g¢qÉÚÄs¾1qŸ1°gŠ]•D@@YÊ%„–ÊÛomŒž[”Xÿ÷Œ‰Û}—;*€€²”kœSt¼Ö B Œ=þʲøŸû_J¬¿ìÎñI±#  (;…ææÈÍ)fëëSî },\±>.ýýÌh.¯Ð#¾1qŸ¨©É¤ÛPq„”ü‚…7­eëëRí =lÜœKnš+Öm.ZïÖ¥&¦œº_ôíÑ%å΀J$  ìäöŒˆÈ޶!P~®¼ç…xnÞªÄúÅÞ;Æé“bG@%Pvr aÍÀQÓ¯_ºÍì ÛŸhŠÛŸhJ¬Ozï¨8zŸa)vT:!e') ¬­«Kµ€õlÓŠ¸âÏ%Ö'Œç5.ÅŽ€j  ì䊎g„@Y¾vS\rÓÌØœ/­ïܧ[\~ò¾‘­õ–h_>m ì$Í ÌÖ×¥ÙÀvËå›ã²ßÏŒE+7­×Öd⻓öútK¹3 (+…B!ò Ekfåâ§½7¼–XÿÒÑ{Ä>£¤ØPM„”•æE‹¢°¡øŒ!PxvaüæÑÆÄú1û‹‰ï™^C@ÕPV’–°Ä(Ðù5,Yß¹í™ÄúØ!}â+Çí™L&Å®€j#  ¬$„™þý¢f€åø€Îkí†\\tÃŒX·)_´Þ·G6¦œ2!ºw­M¹3 Ú(+9ûe¨P(Ä·n{:æ,][´žÉD|sâ>1|`Ï”;ª‘€€²’oœSt\@tf×=Òy~qbýŒCw‹Æî’bG@5PV’–Õc³—ÆÿN{9±~à¸]âÓíšbG@µP6 …‚€(+ V¬¯ÝüT4Š×G ì_?q|ÔÔdÒm ¨jBÊFóÒ¥QX³¦h­V@t26çã¢fÄÊu›‹Ö»w©ï:!úôè’rg@µP6’fFDdëëÒjàm …¸âÏÇ‹ V%žóÕöŽ1ƒû¤ØÀë„”\CcÑñLïÞQ³ÓNé6°·=ÞwMŸ—X?õ€ÑñÁw M±#€P6ò[Ù0“±Ð9<3wEüàžçëûÕ ˆs?¸{Š´&  l$-1jyQ ³X¶fc\|ÓŒÈå Eë»ôíß9yßÈÖz”ŽO&(Iam]]ª}“Ë7Ç¥¿ŸKVm,ZÏÖfbò¤ ±Sïn)wК€€²P(÷ 4ƒè ®¹ï¥˜Þ¸<±~Á1{Æ;FöO±#€â„”…æå+¢°jUÑZÖ B Äî{fAüîosëš0,N|׈;H&  ,ä–¥5{Ñê¸ü¶gëã†öÿq¡àtÍ_¾.¾>õ©(Š×GíÔ3¾vâxË–€€N¯yÅŠh^¾¼hÍ B M6åã¢fĪõ¹¢õ]kã{§î½ºgSî `Û èôrsæ$Ö„@Z …B|ï®ç⥅«Ϲô„wDý Þ)vÐvB:½\Âò¢Ñ½[Ô œj/@õšú¹qÏÌù‰õÓÿ­.ß{HŠl!^®¡±èxvôèÈÔøOÐñžzuyüð/$ÖßY?0Î>|lŠl?ŸªÐé%„–R°lõƸ䦙‘o.­î×=¾sò¾‘­õÖ(>Å ÓË',1* :Z.ß_ýýÌXºzcÑz—ÚLL>eB èÕ5åζ_¶Ô PÜܹsã…^ˆÅ‹ÇÚµkcРA1lذØo¿ý¢K—.¥n¯Ã …hjjŠY³fÅ‚ bõêÕQ[[ýúõ‹¡C‡Æ>ûì}ûö-u›@Ê’ö í¿ÿôb̘³<±~á±{Æ^Ãû¥ØÀŽv2üããW¿úULŸ>½h½ÿþqÌ1ÇÄùçŸì°>;ì°˜7o^»ÜëÄOŒ)S¦$Ö—-[÷ß<úè£ñØcÅŠ+ÏÍd2±ß~ûÅÇ>ö±øÐ‡>5mÜ{lܸqm:ÿ­¦M›#FŒØ¡{mÓ¼zu4/]Z´V+ :нOÍÿþjbýÃûÞ52ÅŽÚ‡€°“X»vm\vÙeñ‡?üa«ç­X±"~÷»ßÅ}÷ÝS¦L‰ƒ:(¥·_·nÝkßÿþ÷ã—¿üeäóùmºW¡Pˆ'Ÿ|2ž|òÉøíoßûÞ÷bôèÑíÕ*Ð åæÌI¬ew­O± š¼¼pu|÷Žgë{ë»gŠ´{vù|>¾ô¥/m80<ðÀ8úè£cï½÷ŽL&ÓR[ºti|þóŸÇ<ívÛ쨣ŽJ¬Í;·h88`À€x÷»ßGuT}ôÑ1a„-–V>}zœvÚi1{öìvïè<ò Å ]»FíС©öT‡Uë7ÇÅ7N››‹Öû÷ì“O™ݺԦÜ@û0ƒ°¸âŠ+â/ùKËq—.]⢋.ŠI“&E×®][ÆgÍš—^ziËò£›6mŠsÎ9'î¼óÎ4hP»ötýõ×G.—kóu¿ýíoã¿øEËñðáÃã€ئkëêêbâĉq衇Æn»íÖ*x}öä/~ñ‹øùÏÞ*.[¶,>÷¹ÏÅ]wݵՙŠÅì»ï¾qå•W¶éš!C†´é|`Ç%î?8jTdj}8´¯ææB|cêSÑôÚú¢õšLÄ·OÞ7†ôï‘rgíG@XbsçÎë®»®ÕØ~ô£8âˆ#¶8w·Ýv‹_ýêWñéOº%$\±bE\}õÕñ­o}«]ûÚÞ ìÁlu}Z-^¼¸Ãž”FóºuѼpQÑš%Fö²~S.¾rÃôX½¡øþË=»ÕÆ”S&D¯nVç*ƒ€°„zè¡VÇïyÏ{¶ùÚw½ë]‘ÍþëCªçž{.–.MÞ/§£Ý}÷ݱnݺ–ãÆá‡ޡϬ­­muüæ¥ZÊoœ“Xí¡P(Ää;ž‹Ù‹Ö$žóµÇGÝ.½Sì  c Kèå—_nu9¾ð…/D¯^½v¸w m’Âì®õé6Tœ%«6Ä%7͈|s¡h}H¿îñíîµ5m{P,1Z"«W¯nuÜ£GèÙ³g›î1pàÀVÇkÖ$ïÓQr¹\ÜqÇ­Æ:zöà¯~õ«xñÅ}Û?›ÍƧ>õ©yÖºuëâ׿þuœtÒI%]ªU®¡±è¸ý±9×—Ü43^[³©h½k¶&¦œ:!ú÷êšrgé0ƒ°DÖ®]Ûê¸[·nm¾G÷îÝ·zÏ4<øàƒ±téÒ–ãž={ƱÇÛaÏ{ê©§âÊ+¯l5ö©O}*êë·}6Q6›ý÷ß?Þÿþ÷ǸqãbÈ!Ñ«W¯X·n]ÌŸ??üñ¸ýöÛcÙ²e-×466Æg>ó™¸ñÆcøðáíöz€­Ë'Í ;àÇ÷¾OÏ]‘Xÿòq{ÅÃú¥Ø@º„%²nݺVÇí¾õžixëò¢ÇsL‡-ŹpáÂ8çœsbóæÍ-c»ï¾{|á _Øæ{|ñ‹_ŒI“&ÅN;íT´¾çž{Æá‡_üâãꫯŽk¯½6 …×—[²dIœwÞy1uêÔ6/g ´]aýúÈÏŸ_´& ¶×=3çÇÍÿ˜›X?ñ]#â¸ý|¨le½Äè_þò—R·Ðn¶'p*uHµxñâxøá‡[uÔò¢«V­Š3Î8#/^Ü2Ö·o߸ꪫÚ®ž}öÙ‰áà›uëÖ-.¼ð¸ì²ËZ?ûì³q×]wm{ãÀvËÍMþ¿V@l‡¬Š)w<›Xß{D¿øÒ1{¦Ø@i”u@xÖYgÅG?ûÙÏâµ×^+u;mòÖý7lØÐæ{¼õš¶îa¸£n»í¶Èår-ÇcÆŒ‰ý÷߿ݟ³nݺ8óÌ3㥗^jëÙ³güìg?kÓÒ¢ÛãôÓOÃ;¬ÕØõ×_ß¡Ï^—kh(^¨©‰ìÈé6”½•ë6ÅÅ7Έ¹æ¢õ½ºÆäI¢k¶¬ßl“²ÿdÞ¼yñÃþ09ä¸ð ãŸÿüg©[Ú&o]†sãÆm¾G©©S§¶:îˆÙƒ7nŒÏþó1}úô–±îÝ»ÇO~ò“Øo¿ýÚýyÅœuÖY­ŽgΜ«V­JåÙPÍr EÇkGŒˆL×®é6”µ|s!¾>õ阿|}ÑzmM&¾sò¾1¨_÷¢u€JSöaDD¡PˆÍ›7ÇÝwߟüä'ãCúPüæ7¿‰5kÖ”ºµD½{÷nu¼~ýú6ï!øÖY“}úôÙá¾¶Õã?-Ç]ºt‰|ä#íúŒM›6ÅyçûÛßZƺví×\sM¼ï}ïk×gmÍ>ûìýúõk9Îçó1kÖ¬ÔžÕ*ÿ¦¿cÞ,[7:ÝF€²÷Ί¿ÏZšX?烻Ç;ë¦Ø@i•u@xä‘GFmmmDük?¾B¡³gÏŽË/¿<:è ¸ôÒKãé§Ÿ.e›E 0 Uè±`Á‚6ÝcÞ¼y­ŽëRÜ“ëæ›onu|衇nÓÞ~Û*—ËÅ¿øÅVûLvéÒ%~üãÇØnÏÙ5551tèÐVc嶤-”£\㜢ãYûmðÐ ‹ãy%±~Ä;†ÄiøâP]Ê: ¼êª«âÁŒóÏ??†…B!"^ …B¬_¿>¦N“&MЉ'ÆÍ7ß¼]{ýu”]wݵÕñœ9Å? OÒÔÔÔêx̘1;ÜÓ¶X³fMüñl5֞ˋæóù¸à‚ bÚ´i-cÙl6®¼òÊ-öLK÷î­—Ûž%a¶É%Í ìà½GÊñê²µñÍ[’¿(¶ë Þqɇ÷nù¢@µ(ë€0"bçwŽÏþó1mÚ´øÉO~‡rHˇ²Ã÷ßwß}w4¿)¨ØyçS[ΪU>ayÑÈd";rdª½å熿͉ûŸY˜XÿôÁ»ÆÁ{ø²P½*2 |Cmmm}ôÑñË_þ2î½÷ÞøÌg>ýúõk™Uñz0õÚk¯Åµ×^Gydœyæ™ñÀ´:§£ôèÑ#Ž:ê¨Vc?ÿùÏßöº†††¸ï¾ûZ޳ÙlüñíÞ_1o=øÞ÷¾7F¶Ã‡õßúÖ·â÷¿ÿ}«±o|ãíº·áöXºtiüä'?i5v衇ګ:XÒþƒµÃ†Eæ-{‚¼Ù ¯ÅÕ÷½”Xßn;Ňî–bGOE„o6jÔ¨øÊW¾=ôP|ï{ß‹ýöÛo‹åG›››ãᇎsÎ9';ì°øÉO~¯½öZ‡öuÞyçE—.]ZŽo¹å–˜6mZâù7nŒ‹/¾¸Õ²¨'NŒQ£Fmõ9ãÆkõç±Çks¯›7oŽÛo¿½ÕX{xS¦L‰ë¯¿¾ÕØe—]§žzêßû ¯¼òJ<ðÀmºfÉ’%qÖYgÅÒ¥K[ƺtéguV»õ—kh(:žµÿ °‹WnˆK?3òÍÅ¿è5´øæÄ}¢¶Æ}€êV5áºvíùÈGâw¿û]ÜtÓM1lذˆx=$|óò£ ,ˆ«®º*>ðÄW¿úÕ˜7o^‡ô3räÈøÄ'>Ñjì _øBüæ7¿‰M›6µŸ={v|êSŸŠéÓ§·Œõïß?Î=÷Üéí­xàVi¿~ýâÈ#Ü¡{^uÕUñË_þ²ÕØ'>ñ‰øÀ>MMMmú³víÚÄç,Y²$Î>ûì8þøããÚk¯Æ¤å #bÍš5ñ›ßü&N8á„xæ™gZÕÎ>ûìv™1 l]â B!`S®9.¾iF,_»©h½[¶&¦œ:!úõìšrgO¶Ô ”ÂìÙ³ãw¿û]ÜqDZzõêVµ·Î*Ü´iSÜrË-qçwƹçžgžyf»÷óÿñ1kÖ¬x衇"âõ™zßþö·ãþçb¯½öŠ^½zÅܹsã¹çžkµôi—.]âšk®‰AƒÒÙCgêÔ©­Ž?þøèÖ­ÛÝóÍ{¾áºë®‹ë®»®Í÷šùdD¼¾yÖ`MMMrÈ!Ñ»wïøÓŸþ›6mj©oÚ´)~øÃÆ+¯¼S¦Li×ÞjkkãG?úQ\zé¥q÷Ýw·Œ/[¶,~øá¢×ì´ÓN1eÊ”x×»ÞÕ®½$Y´hQ<òÈ#­ÆJ½?àŽZ½zuËÿ¶¦gÏžqñÅǤI“Rè (lÞù¹MEkÙºÑ)w”ƒ»¦Ï‹[Ÿ›XŸøî‘qì„á)vйU|@8gΜ¸ñÆãÖ[o+VDÄ–Á`ÿþýcâĉqÚi§Åˆ#""båÊ•1uêÔ¸îºëbÁ‚-3 o¿ýö8âˆ#âˆ#Žh×>{õê?üáã¨£ŽŠ_þò—1cÆŒ¢çõïß?Ž9æ˜8ÿüócàÀíÚÃÖÜrË-‘Ïç[Ž÷Þ{ïØsÏ=S{þŽ3fL|îsŸ‹üãñÜsÏņ Þöšººº8餓âä“ONõw Õ.ßÔñ¦¿oÞ,[_Ÿr7@g÷Âü•ñ_w=—X?²|ñè=Rì óËÞ¼fe…Èçóqÿý÷Ç 7Ü=öX …-–ˆ?~|œ~úéqì±ÇF×®Å÷£Ù¼ysüô§?k®¹¦eìàƒŽŸþô§úÞXRtñâű~ýúØyçcذa±ÿþû'öʶinnŽÆÆÆ˜;wn,Z´(V­Z7nŒîÝ»Gß¾}cРA1~üø -Z|ðã=ôP <¸Ãž å`ßÿË>þÉ¢µ¡³^Šš=Rîè¬V¬ÝŸþÙßbáŠâ_üØ»küú¬b—¾ÝSî  s«¨„óçÏo¼1¦NË–-‹ˆÍ|#ìÚµk{ì±ñ±},Æÿ¶÷ìÒ¥Kœ{î¹±xñâ¸é¦›""â™gžéÐ×1räÈ9rd‡?§ÕÔÔÄ®»î»îºk©[ŠÈ5Î):^3dˆph‘o.Äe7?•ÖÖdâò“÷Qöa¡Pˆ?ÿùÏqã7Æ#<ÍÍÍ­f ¾qΈ#â´ÓN‹‰'FÿþýÛüœøÃ-áK•Ðþr Edzõui¶tr?{àåøç+Ëëç9.ö«³D8@1e^sÍ5qóÍ7ÇÂ… #bËÙ‚™L&:è 8ýôÓãàƒn ·Ç›—}lnnÞáÞ(.רXt<[W—j@çõàó‹â×7$Ö?4&½oTŠ”—²ÿû¿ÿ»UøÆÏýúõ‹‰'Æi§ÖnËtÖÔÔ´Ë}غ|Cñý„@DDã’5ñ­[ŸN¬Ü;.þð^;ôÅ0€JWÖá› …Ø{ï½ãôÓOãŽ;.ºvíÚ®÷ïÙ³gœxâ‰ízOZ+är‘›;·hM@¬Ý˜‹‹nœë6æ‹Ö{wÏÆ”S&D®ó C”ý§']ºt‰c=6>ö±Å>ûìÓaÏ0`@Lž<¹Ãî@D~þüˆÍ›‹Öj„PÕ …B\~Û3Ѹdmâ9ß8i|ŒÜ©WŠ]”§²/¼ðÂøèG? (u+´ƒ¤ý#"²u£Ókèt~ûhc<ðÜ¢Äú¿`L8nPŠ”¯²Ï8ãŒR·@;Ê54¯Ùe—¨éÝ;Ýf€NãñW–ÅÿÜÿRbýýcwŽ?dLŠ”·²çÏŸßòó!C¢¦¦f»î“ÏçcÑ¢}#}ذa;Üm—O˜A˜­¯K³  Y¸b}þyë IDAT\úû™Ñ\(^> G|câ>QS“I·1€2VÖáa‡™L&2™LÜÿýÛì-\¸0Ž8∈ˆÈd2ñÜsϵg›l£¤%F³ö„ª´qs>.¹iF¬XW|oÒn]jbÊ©¢o.)wPÞÊ: Œˆ(¾N^¢û°ýrsŠŽ ¡:]yÏ ñܼU‰õ‹?¼wŒÒ7ÅŽ*Ãö­ÉÙ‰d2–“¨…ææÈÍ)Ö ¡êÜþDSÜþDSb}Ò{GÅÑûX`{”}@hæ@eÈ/X±qcÑš=¡º<Û´"®øCò’ïûŽêç5.ÅŽ*KÙ„íaÓ¦M-?wëÖ­„T¯|CCb-;ztŠ¥´|í¦¸ä¦™±9_üK`;õî—OšÙZoc¶—OV"¢©é_ËWõîÝ»„T¯\ccÑñš£¦_¿t›J"—oŽË~?3­ÜP´^[“‰ïž2!vîã ];B@·ß~{D¼¾ŸáÈ‘#KÜ @uJ í?Õã§½7¼–XÿâÑãbßQRì 2eKÝÀÛ¹í¶Û¶é¼{ï½7 ØöŒ6mÚ‹/ŽG}4f̘Ñ2¾Ï>û´¹Gv\R@˜BUxàÙ…ñ›GëÇì;,>úžQé5PÁ:}@xÑEE&“Ùê9…B!þë¿þk»ŸQ(ük›ãŽ;n»ïÀöK w­O· u KÖÄwn{&±>vHŸøÊq{½í{B¶M§ßðæo{êżõC¦SO=5Æßæû°c …Bä‹Ö²u£ÓmHÕÚ ¹¸è†±nS¾h½olL9eBtïZ›rg•«,Âí ÿÚrß‘#GƧ?ýé8ýôÓ;ä9l]ó¢EQذ¡hÍ£P¹ …B|ë¶§cÎÒµEë™LÄ7&îÃöL¹3€ÊÖéÂÉ“'/ qÉ%—DÄë3ÿó?ÿs›÷ Ìd2ѵk×èÓ§OŒ3&† ÖnýÐvIË‹F¡’]÷HCüåùʼnõ3>°[¼ì.)vP:}@xâ‰'&Ö.¹ä’–eB>úhA@™J 3ýûEÍ6~ù(/Í^ÿ;íåÄúãv‰O¼kŠTšR7°£:jùQÒ“Kܰ.Õ>€t,X±>¾vóSÑœð6nÄÀžñõÇGMM¦ø ìN?ƒpk¦M›ÖòóàÁƒKØ ;B@ÕcÃæ|\tÃŒX¹nsÑz÷.µñ½S'DŸ]Rî  z”u@8|øðR·@;È',1* „ÊR(âŠ?</.X•xÎW?²wŒÜ'Å®ªOÙ/1 @y+ ‰{ ¡²ÜöxSÜ5}^býÔFÇÇM±#€ê$  ¤š—.ÂÚµEkµõõ)wt”g殈Üó|b}¿ÑâÜîžbGÕK@@I%ÍŒˆÈÖ×¥ÕЖ­Ùß4#rùBÑú.}ºÅw&íÙZoMÒÐi÷ <üðÃ[g2™¸ÿþû·zN{(ö:N®¡±èx¦OŸ¨80Ýf€v—Ë7Ç¥¿ŸKVm,ZÏÖfbò)b§ÞÝRî  zuÚ€pÞ¼y‘Éd¢Pxý›æ™LæmÏiÅž@ÇÉoeÿA'Cù»æ¾—bzãòÄú—ŽÞ#Þ1²ŠÐiÂ7lKØ^ ·gÐÀ¶IZb4[7:ÝF€vwß3 âw›“XÿЄaqÒ»G¦Ø8 6lX»œ@ç–kh(:^[W—n#@»š½hu|÷ögëã†öÿ1l@”;à BJ&ßИXByúÕïÄÃ/.I¬ŸuØØxïn;§ØoÕi—};kÖ¬‰¦¦¦–ãQ£FEÏž=KØm•kl,:žéÙ3j J·`‡ýíå%qíŸg%ÖÙcP|òÀú; ˜² ÿð‡?Ä7¾ñˆˆÈf³ñðà ÊLR@˜­«‹L&“n3À™¿|]|}êSQ(¯Ú©g|íÄñQSãÿÛ¥V¶áòåË£ðÿ>?~|ôïß¿ÄÐVIa­åE¡¬lØ”‹n˜«ÖçŠÖ{t­ïº_ôê^¶o=*JÙîAاOŸˆˆÈd21dÈwÀöÈ%ìA˜­¯K³ ` …øÞ]ÏÅK W'žsé ïˆúA½Sì €­)Û€p—]viùyóæÍ%ì€í•ßÊ£@y˜ú¹qÏÌù‰õÓß_‡ïíË\IÙ„cÇŽmù¹©©©„°=šW¬ˆæåˋքPžzuyüð/$ÖßY?0Î>blb€Ò(Û€°¾¾>Æ…B!^|ñÅX´hQ©[  ’öŒB9X¶zc\rÓÌÈ7ŠÖõíßþè>‘­-Û·›«¬?±ùøÇ?¯ï}óãÿ¸ÄÝЉa÷nQ3dpª½m“Ë7ÇW?3–®ÞX´Þ¥6“OÙ7öî–rgl‹l©Ø'Ÿ|rL›6-|ðÁ¸õÖ[£¾¾>Î8ãŒR·À6È54ÏŽ™š²þþ Tœ毊;žlŠ—®Žu›r±bí¦X¶fSâù»gì=¢ŠÐeFDüà?ˆ‹.º(î»ï¾¸òÊ+ãïÿ{œqÆñ¾÷½¯Ô­°¹Æ9EÇ-/ ÇóóVÆî~>žiZ¹Í׿ÿð8á]#;°+vTY„_|qDDôîÝ;zõêk×®¿þõ¯ñ׿þ5zõê{ì±G 80zõêµÍ÷Ìd2ñÝï~·£ZàÿÉ',1š­¯O· ¨G^\_½iflÌ5oó5{ëÿqìžØí¡¬Â[o½52™LËq&“‰B¡kÖ¬‰'žx¢M÷+ B€”$íAh!”ÞóóV¶9Œˆø÷CÆD·.µÔí¥â6yÊd2-蜚W¯Žæ¥K‹Öj„Pr?¸ûù6‡ƒ¿~¤¡º ½•}@X(ÚíéÈÍ)¾ÿ`DD¶¾.µ>€-½0e›ö|³§ç®ˆæ¯jçŽhoe½Äè´iÓJÝÛ!ßÐX¼ÐµkÔšj/@kw<9o‡®¿óɦØcØ^íÔ ¡¬ÂáÇ—º¶C®¡ø2„ÙQ£"Skÿ2(¥—®Þ¡ë_ÚÁëèxe¿Ä(å'רXtån€·úðþ#vèúãwðz:ž€€Tåç$ÖìA¥·Ç°¾ñŽý¶ëÚñ#ûÇÃú¶sG´·ŠÜ$fùòå1{öìXµjU¬^½: …B›®?á„:¨3’–l6j‡Oµ ¸ Ý3>÷‹ÄÆ\ó6_Ó-[³Gv@{©˜€ðµ×^‹ë¯¿>î¼óÎxõÕWwè^B€Ž“ÖŽ™lÅüg ÊÚžÃûÅå“ö¯Þ4s›BÂnÙš¸|Ò¾±çðí›y@º*â“Ø?ýéOqÉ%—ÄÚµkÛ<[ð ™L& …Bd2™vî€7K ³õui¶¼Ç ŠÿýÿÞWÞóB<=wEâyãGö ŽÙC8PFÊ> ¼ãŽ;â+_ùJÑ`ðÍaß[ëo­mo°@Ûä^i(:nÿAè|öÞ/®ýì{ã…ù«âÎ'›â¥…«cݦ\ôìšÝ‡ô‰ã÷aÏA€2TÖáܹsãk_ûZËÌ¿B¡ãÆ‹~ðƒÑ­[·øÁ~¯‡“'OŽ5kÖÄâÅ‹cúôéñä“OFsssd2™Øi§âì³ÏŽ^½z•øT¾|Ò B!tZ{ ë{ Û«ÔmÐNÊ: üÅ/~6lh™ xî¹çÆ9眙L&æÍ›×FDœx≭®3gN|ÿûßûï¿?^{íµ¸ñÆãÿþïÿbРA©¾€jRX¿>ò ­ ÒQSê¶WsssÜqÇ-áàÑGçž{î6ï!8zôè¸úê«ãóŸÿ| …˜5kV|îsŸ‹Í›7wdÛU-÷꫉µZ!@*Ê6 |ñÅcíÚµ-{žsÎ9ÛuŸóÏ??Ž8âˆ( ñüóÏÇu×]מmð&¹„åE£¦&²#G¤Ú @µ*Û€ð¥—^Šˆ×÷:thì¶Ûn[=ÿ ±˜ .¸ åç›o¾¹}` ¹†Æ¢ãµ#GD¦k×t›¨Re®\¹²åç±cÇnQëR£7nL¼×®»îcÆŒ‰B¡ ñòË/·_£´È'Ì ´ÿ @zÊ6 \»vmËÏ}ûöÝ¢Þ£GÄó‹©{Ó‡Ó³gÏÞ±æ(*×8§è¸€ =e¾9Ìår[Ô{õêÕêxÑ¢E[½_Ïž=[~^ºtév@1I{ Òóÿ³wçQvÖõýÀ?ÏÜ;Y! ! I˜äމ ;AD6Ù*‚ ­¶n­+•ZÅ_¥Z´ZD©ÖöØhQ‚l"ÈŽµ#)KâLHd!d!û½óüþÀ\3ɽI&3óܹ÷¾^çäœy¾ßçù>Ÿ{à çäÏ÷[·á~ûíWþùå—_Þi~РAÝîÙvfa5+V¬(ÿ¼aÆ>¨€í¥›7GiéÒŠs9!@fê6 loo/ÿ¼hQå-ë¦M›Vþù—¿üeÕµ6lØ=öXùºÒ–¥ôNqñ∮®ŠsùöB¦µ4³º §N¹\.Ò4%K–ÄÆwºç裎ˆˆ4MãÎ;U:W¾÷½ïuëÜ>X o;:+O$IäÛÚ2­ ™Õm@8|øð8øàƒ#â•ð¿øÅN÷œqÆ‘$IlÚ´)>ò‘Äÿþïÿ–ç×­[W^ye|÷»ß$I""bäÈ‘qÄGdð šK©Êùƒ¹‰#2$ÛbšX¾ÖôƱÇ?þxDDÜwß}qâ‰'v›õ«_'tRÜ{q$I,Z´(>ðÄСCcŸ}ö‰U«VE©TŠˆWBÆ$IâÏþìÏ¢µµ5óÏÐèŠU¼ó2U·„ìLÓ4~üãǺuëvºçoÿöoc̘1ñJ'aš¦±aÆX¾|y‹År0q衇ÆÇ?þñì>@©æ¶;S€þWׄ¯~õ«ã¦›nŠ®®®ˆˆhiÙ9ïœ8qb|ÿûßÏ|æ3ñôÓO—Ç·…‚išFš¦qÜqÇÅ׿þu݃ý¤jaû”l hruFDùÂ]™:ujüèG?ŠŸþô§qï½÷Æ¢E‹bíÚµ1räÈxÝë^§Ÿ~z¼ùÍoΠZ€æ”nÝ¥ÅK*ÎÙb [uî©\.§Ÿ~zœ~úéµ. é”–,‰øÃ™¯;d«®Ï  >TÛ^4""7Å£YÐïŠÇ[8 Z†Ͷ€&'  ßUë Ì·²,€j„ÎÈž€€~WªÖA( È\¾ÖTó| &ïM’$¾ÿýï×äÝ(-£¸xqŹ|{{ÆÕ0`ÂÿùŸÿ‰$I2}gš¦™¿ Ñ•ž{.bëÖŠs:²g‹QúU±Êö¢¹Â”ì  "paÄ+}Ô·bGgÅñ–qã¢eøðl‹`à„O>ùd­K ”ªtæuÔ„-FèWÅŽŽŠãΨ !ýªØ¹¨â¸€ 6„ô›´TŠâ¢ÊaN@PBúMé…"¶l©8—o/dZ ¯ÐoJUçl1 PBúM±³³âxËþûGˈÙ@DDäk]@oÜ|óÍý²îÙgŸÝ/ë4›j¡îA€Ú©ë€ðâ‹/Ž$Iú|]!@ߨæ„5S×á6išöz$I"MÓ~ šUÕÂöB–e°º÷6Ü>LÓ´OBFþ(MÓ(utVœË¦d[ eu^vÙe=º¿T*ÅÚµkã™gž‰‡~8–-[I’ÄÈ‘#ãÓŸþtì³Ï>ýT)@óézá…H7mª8ç B€Ú©ë€ðÝï~÷^?[,ãÆoŒ+®¸"Ö®]?øÁâÚk¯±cÇöa…Í«Úö¢B€Zj©uµ’Ïçã½ï}oÌš5+  ,ˆO~ò“±uëÖZ—Њ‹*Ž'£FFË~ûe\ Û4m@¸Í‘GŸþô§#MÓøÝï~³fͪuI ¡Z¡îA€Újú€0"âýï 4(""þë¿þ«ÆÕ4†bGgÅñ|{{¶…Ѐ0"† ‡vX¤iÏ?ÿ|üö·¿­uIu¯¤ƒ`@þÁøñãË?/ZTùÜ,öL𦶠„P*•Ê?¯X±¢†•Ô¿®•+#]¿¾â\N@PSÂ?øýï_þ¹µµµ†•Ô¿j݃ùöBVeP€0"üñxæ™gÊ×cÇŽ­a5õ¯øûŽŠãɾûFËèÑWÀöš> \¶lY|ö³Ÿ$IÊcG}t +¨¥]œ?¸ýŸ·d/_ë²ÖÕÕk×® Äý÷ß7ÜpC¬_¿>Ò4$Iâ oxCŒ7®ÖeÔµj[Œæ S²-€Ôu@xÐAõzmÁ`DD>Ÿ¿ù›¿éõšÍ®Z@˜+2­€Õu@˜¦i¯žO’$’$‰4M#ŸÏÇe—]‡vXUМÒ4b碊sùööŒ«`GuaoβJÓ4Ò4cŽ9&n¼ñÆxç;ßÙ‡•4§®—^ŠtíÚŠsùöB¦µ°³ºî |ÃÞÐãgòù|ì³Ï>1zôè8äCâMozSLž<¹ªhN¥ŽÎªsy[ŒÔ\]„sæÌ©u ì ÚùƒÉ°aÑ2vl¶Å°“ºßb€¥Z@˜/zµ-4}C@@Ÿ*vtTÏÙ^`@Чªv¶²,€*„ô©bGgÅñ¼B€A@@Ÿézé¥HW¯®8' „ô™â¢EUç„C¾ÖTsÐAÕä½I’ÄO]tQüö·¿ÿüÏÿŒ5kÖÄ׿þõ «h]ëÖE×Ê•çrB€£®Ûån»í¶¸õÖ[#"â ƒŠY³fí2ÜÑĉcöìÙqðÁGš¦qÇwÄ-·ÜÒ_å4´j݃ùöBVe°uΚ5«üó—¿üå2dH×2dH|ùË_._Ïž=»*h>ÅŽÎʃE®ÿx€þU·áÂ… ã‰'žˆ$I¢P(Äᇾ×k~øáQ("MÓxòÉ'cáÂ…}X)@s(U;pòäHv8€Ú©Û€ð™gž)ÿøàˆx¥‹ðÖ[o+¯¼²Çë\yå•që­·F’$‘$I|ðÁ1yòä¾. ¡;:*Oäó‘›4)ÛbØ¥º #"þú¯ÿ:Ò4$I"MÓøÞ÷¾ïyÏ{âg?ûÙ.ÏìêêŠ|0Î=÷ÜøÞ÷¾W~~ÛšôLµósmm‘äóÙÀ.ÕõßÚ¾õ­o÷¿ÿýqÝuוC¾G}4>ö±ÅÈ‘#ãC‰B¡ûì³ODD¼üòËÑÙÙ¿ûÝïbÍš5å€1"â}ï{_¼å-o©Ùç¨WÕBç :@ÍŸ}¶êœ€`àiØ”,ŸÏÇë^÷ºZ—ÐðŠU¶\.rNÊ´v¯!Î  vŠÇsNŠdРl‹`·„ôJµ€Ðö¢SÃn1ºM©TŠ5kÖDDÄÈ‘##—ËÕ¸"€ÆRª²Å¨€``j¸€péÒ¥qË-·Ä#<óçϵk×v›1bDzè¡ñú׿>Þõ®wÅX£JCµ3„SÄ+V¬ˆø‡ˆ»ï¾;ººº"""MÓî[³fM<üðÃñðÃÇ5×\ïxÇ;âÿý¿ÿãÆËºd€º—nÞ¥¥K+Îå„RCœAø‹_ü"Î:문뮻¢T*•ƒÁ$I*þŠx%<,•Jq×]wÅ»Þõ®øïÿþïZ~€ºT\¼8¢Â?ƈˆÈ·2­€=S÷ác=Ÿüä'cÕªU‘¦i·0MÓ5jT´µµE[[[Œ5ª<å{W¯^çw^<úè£5ûõ¨ØÑYy"I"?yr¦µ°gêz‹Ñ7Æyç›6mŠ$IÊá)§œgŸ}vLŸ>=FÕí™5kÖļyóâæ›o.oGš$IlÚ´)Î?ÿü¸ë®»bèС5úDõ¥TåüÁܤI‘ œm1ì‘ºî œ={v¬X±¢N™2%n¸á†øæ7¿'œpÂNá`DÄÈ‘#ãøã«®º*n¸á†˜¼]‡ËŠ+böìÙ~€úV¬æ?0`Õu@øÃþ°Nš4)®»îº8ì°ÃöøùC=4®»îº˜4iRyüàýX1@c©æ„VÝ„ .Œçž{®¼­èßýÝßŘ1cz¼Î˜1câ’K.)ŸKøÂ /Ä‚ úº\€†Tìè¨8žoŸ’q%쩺 Ÿ|òÉòÏãÇ·¿ýí{½ÖÛßþö8à€Ê×O=õT¯jhé–-QZ¼¤âœ-F®º W­ZI’Äë^÷º^¯·ýÛÖ ºÒ’¥]]ç„WÝ„7n,ÿ<|øð^¯·ýÛ¯ @eÕÎŒˆÈM±Å(À@U·á¨Q£Ê?¯X±¢×ëm¿ÆÈ‘#{½@£«¶p@´ šm1챺 ÇŒišÆ£>6lØëµ6lØ>úhùzìØ±½® ÑU óííÙ@Ôm@øú׿>ZZZ"I’زeK\{íµ{½Ö¬Y³bóæÍÑÒÒGuTÿ IDAT_• аŠÇóí…,Ë ‡ê6 9rdqÄñJá¿þë¿Æ½÷ÞÛãuî¿ÿþøîw¿I’D’$qøá‡wÛ¾€ÊJÕ: …Lë gòµ. 7>ñ‰OÄÇ?þñH’$¶nÝ^xa|ðƒŒO~ò“±Ï>ûìòÙõë×Çw¿ûݘ5kV”J¥HÓ4’$‰üãU¿k‹/Ž'Ÿ|2–/_ëׯqãÆÅĉcúôéÑÚÚZëòúMš¦±dÉ’X°`A<ÿüó±nݺÈår1räȘ0aB~øá1bĈ>}çÖ­[ã7¿ùM<ÿüó±|ùò>|xŒ7.:è 8ðÀûô]Ð(Òb1Š‹Wœ lu¾ýíoãŽ;.zè¡H’$ŠÅb\{íµqýõ×ÇñÇÓ§OB¡ûî»o$IëÖ­‹ÎÎΘ7o^Üÿý±iÓ¦r0˜$I{ì±qüñÇ×ô3Ýyç1{öì˜7o^ÅùQ£FÅé§Ÿ\pAŒ=ºßê8ñÄcéÒ¥}²Ö»ßýî¸üò˫οøâ‹qÏ=÷Äÿ÷ǯ~õ«X½zuÕ{“$‰éÓ§ÇûÞ÷¾ø“?ù“hiÙû&ØU«VÅÕW_?ùÉOª¾súôéñá8N=õÔ½~4¢ÒsÏElÝZqN@0°%iš¦µ.¢7Ö¯_ïÿûãÉ'ŸŒ$IbÛÇI’d—Ïm_š¦ñÚ×¾6®¿þú>|x¿×\Éúõëã’K.‰ÿøÇ{tÿ˜1câòË/·½ímýRO_„ï}ï{ãïÿþï+Îýó?ÿs¹‹³§¦OŸW\qEL™2¥ÇÏ>øàƒñ…/|!^|ñÅ=ºÿÌ3ÏŒK/½4† ÖãwU²lÙ²8î¸ãv衇büøñ}òèO›|0^|ߟUœ›ðô“ÑR£?Kؽº=ƒp›áÇǜ9sâÔSOíÖ ñJXéWDt»ç”SN‰9sæÔ,,•Jñ™Ï|f§ppôèÑqì±ÇÆi§‡rH·ÐsåÊ•ñ©O}*~ýë_g]níªûnñâÅÃÁýöÛ/Þð†7Ä©§ž§vZyä‘;m­:oÞ¼øÓ?ýÓX¸paêùÕ¯~çw^·p0I’8äCâ´ÓN‹·¾õ­±ß~ûu{æ¶Ûn‹‹.º(ºººzô.hTŎΊã-ãÆ ¸ºÞbt›}÷Ý7¾ùÍoƽ÷Þ³fÍÚmh¶-$<úè£ãÃþpœtÒIY”YÕ×¾öµxðÁË×­­­qñÅǹ瞃 */X° ¾øÅ/–·ݲeKœwÞyqÛm·Å¸qãú´¦ë¯¿>ŠÅbŸ»îºëâÚk¯-_Oš4)Þüæ7ïѳ…B!fΜ'œpBL›6m§.ÐÕ«Wǵ×^ÿþïÿ^_|ñÅøÄ'>·ß~{ T W¯^ßþö·ãÒK/íÓº8à€½zîèv=sæÌÝn÷úú׿>Î?ÿü݉£FŠ‹.º(Ž8âˆ8ÿüóË!á³Ï>ßÿþ÷ãcûØnë»úê«cÍš5åëéÓ§ÇìÙ³w  øÀbâĉqÞyç•ÇgÍšïyÏ{Ä;PK¥ªa!Ó:蹺?ƒ°Þ}þóŸ›o¾¹|=cÆŒ¸ì²ËvùLGGGœyæ™åζ|>wÞyg´µµõk­»óÈ#ÄûÞ÷¾òuKKKÜwß}1a„ªÏ,Y²$<ðÀ¿ëŠ+®èÖ©8mÚ´ÝžßØÙÙgœqF9XlmmÛo¿= » 4.¾øâøÑ~T¾Þ“ߣÝq!õnÙñ'Fñ™gvñùÏžœ_ƒŠØSua=Û´iSÜu×]ÝÆþò/ÿr·Ïµ··wë0,‹qÛm·õy}=5wîÜn×o}ë[wFÄ^…ƒÑ-ˆŒxeûÕíϬäöÛoïvÞá)§œ²Ûp0"â£ýh·ë;ï¼36oÞ¼çÅBƒIK¥(.ZTq.§ƒ`ÀÖÐÏþóظqcùzúôéÝÎÁÛ•3ft»¾ûî»û´¶žZ¿~}üä'?é6vÎ9çôÛûÚÚÚbß}÷í6¶|ùò]>³ãw´ãwXÍÔ©Sãˆ#Ž(_oذ!~þóŸïa¥ÐxJ/¼±eKŹ|{!ÓZè9a =ôÐCÝ®ßøÆ7îñ³G}täóY¾ÎçóqÔQGíñ»vü½Ùñ÷šI©£³ê\~Ê”ì `¯kè™Îï:òÈ#÷øÙaÆÅk^óš]®—¥·=묳¢µµµßÞ·víÚX½zu·±±cÇV½Çïæµ¯}m 6lß7}úôn× ,Øãg¡Ñ;;+Ž·ì¿´Œ‘m1ôX~÷·ÔNw U’$IÜsÏ=™¼ë÷¿ÿ}·ë)=ì¼ikk‹'žx¢|½páÂxó›ßÜ'µõÄÂ… cÞ¼yÝÆús{шØéìÆ±cÇÆPõþ½É“'÷è};Þ/ ¤™;:*Žç?Pt@¸téÒH’$Ò4ÍìI’dòžÕ«WïÔ7a„­1qâÄn×UºzúÛ7ÞØíúÈ#ŒiÓ¦õÛûºººbΜ9ÝÆN>ùä]þÞ=ûì³Ý®{û]¯^½:Ö¬Y#GŽìÑ:Ъuæ„ua@„ÛdÚeD®[·®ÛõСC{´åeÄ+çümïå—_îu]=U,ãÖ[oí6Öß݃³gÏŽ§žzª|Ïçãƒüà.ŸY»vm·ëý÷ß¿Gï>|x <86oÞ\[·n€¦T- Ì·²,€½TaD¶á]Ö¯_ßízðàÁ=^cÈ!»\3 <ð@¬\¹²|=lذ8ãŒ3úí}=öX|ãßè6öÁ~0ÚÛÛwù܆ º]ïøÝí‰!C†t kñ}C­¥]]Qê\Tq._èÙ6ÉÔF]„išFkkkœp 1sæÌ8üðÃk]R¯íXõE@¸ãšYØq{ÑÓO?=†Þ/ïzá…â¼ó΋­[·–Ç^óš×Ä…^¸ÛgûâûÞñ™Z|ßPk]Ë–EºiSÅ9gÔ‡º“$‰b±wß}wÜ}÷Ý1mÚ´˜9sf¼ë]ïÚi›Ízµ7Û¨fµõj5Ë—/ŸýìgÝÆúk{ѵkׯG?úÑX¾|yylĈqõÕWïUØ·7jý}Ã@Pm{шˆün:yZj]À®|õ«_éÓ§Gš¦Ý~=óÌ3qÅWÄqÇçw^Üwß}Q*•j]nìxÞà¦*9»²ã3==ð·n¾ùæ(‹åë©S§ÆQGÕçïÙ°aC|ìc‹§Ÿ~º<6lذøÞ÷¾·Û­E·¿{Ûoº§v|&ëï‚b•íE“Q£¢eÔ¨Œ«`o èÂsÎ9'Î9çœèììŒo¼1n¹å–X±bEy¾X,Æ}÷Ý÷Ýw_ì¿ÿþqÖYgÅŒ3bêÔ©5¬zÏì¸ çÞVµçÎÛíº?º7oÞŸúÔ§bÞ¼yå±!C†Äw¾ó˜>}ú¯Ó, Õ:óí…,Ë tá6…B!>ûÙÏÆƒ>ßýîwãïxGär¹ˆˆrWáÊ•+ãÚk¯w¾óñž÷¼'~ðƒÄË/¿\ãÊ«ÛgŸ}º]oܸ±ÇgÚ­ZµªÛõ¾ûîÛëºöÔ¯ýëèÜ.(hmm³Î:«Oß±eË–8ÿüóã¿øEylРAqÍ5×Ä›Þô¦­µãw³ãw·;ëׯß) 1bDÖ€FPìè¬8îüA€úQá6---qüñÇÇ·¾õ­x衇âsŸû\¼úÕ¯îvOš¦ñØcÅ—¾ô¥xÛÛÞŸÿüçã—¿üe*®n¿ýö‹‘#Gv{þùç{´ÆÒ¥K»]2ü úo¼±Ûõ 'œû￟­_,ã¯þê¯âÁ,µ¶¶Æ7¿ùÍ8öØc{¼Þ”)Sº]?÷Üs=z~ÇûGµÓï4ƒRGGÅq!@ý¨«€p{£GŽ|ä#qÛm·Å~ðƒ8÷ÜsË]yišFÄ+]y·Þzk|øÃŽ“N:)®¹æšCýéU¯zU·ëE‹*ŸíUÍ’%Kº]gµµêË/¿wÞyg·±¾Ü^´T*ÅE]÷Þ{oy,ŸÏÇ7¾ñ8ñÄ÷jÍ¿›gŸ}¶GÏ/^¼x—ëA3HÓ´ú£B€ºQ·áö?üð¸ôÒKãç?ÿy\~ùåñÆ7¾±<·m Ò¥K—Æ·¿ýí8ùä“ãÃþpüøÇ?Ž­[·Ö°êˆ×¼æ5Ý®ûÛßîñ³6lˆ§žzªÛØŽÝ”ýåŽ;îˆ7–¯Ç¿W]}•tuuÅç>÷¹¸ë®»Êc¹\.þùŸÿ9N9唽^wÇïæ©§žêövç7¿ùÍ.׃fеbE¤U¶BÎ êFC„Û <8Î>ûìøÿøøéOÿøÇc„ åù4M£««+~ñ‹_Äg?ûÙxüñÇkXmÄÛÞö¶n×ÿó?ÿ³ÇÏþú׿Žb±X¾>øàƒc̘1}Vۮ츽èŒ3ÊgBöFWWW|á _ˆÛo¿½<ÖÒÒ—]vYœqƽZ{ܸqñÚ×¾¶|],ã‘GÙãçwü½9î¸ãzUÔ£j݃ùöBVeÐK n¯­­->ó™ÏÄ}÷Ýÿöoÿ§vZ 4(’$©uieÇ{l 2¤|=oÞ¼X¸pá=û£ý¨ÛõÉ'ŸÜ§µU³`Á‚xôÑGË×I’ÄÌ™3{½nš¦ñw÷wqóÍ7w[û+_ùJœuÖY½^?"âïxG·ë›nºiž[¸pa·Ï똄zRìè¬8žì»o´Œm1쵆 ·I’$† C† é“.·¾4tèÐ8õÔS»ýû¿ÿûnŸëè舻ᄏ|ÏçãÌ3Ïìóú*Ù±{ð˜cމ¶¶¶^¯{饗ÆøÃnc_þò—ûôlÃ3Ï<³Û?ýéO£sQÛìø{rÚi§ÅàÁƒû¬.¨¥jç¶Ô?¾`×6 |á…â;ßùNœrÊ)ñ| n¹å–Ø´iS­ËÚÉù短­­åë›nº)î½÷Þª÷oÞ¼9¾ð…/t;?qæÌ™1yòä]¾çµ¯}m·_¿úÕ¯z\ëÖ­[ã–[né6ÖÞå—_×_}·±K.¹$ÞûÞ÷özíí …8ûì³Ë×[·n‹/¾86oÞ\õ™{î¹§[§akkk|úÓŸîÓº ^TÛb4ïüA€º’¯u}iË–-qÏ=÷Äܹsã—¿üetuuEš¦Ýîiii‰·¼å-1sæÌ8üðÃkTéµµµÅŸÿùŸÇµ×^[»ð ãâ‹/ŽsÏ=7 T_¸paüíßþmÌ›7¯<6jԨ̫ûî»/V­ZU¾9rdœrÊ)½ZóꫯŽY³fuûó?ÿó8þøãcÉ’%=Zk¿ýö‹áÇïòž .¸ î¹çžX³fMD¼²­ë‡>ô¡øêW¿S§N-ß·eË–¸á†âŠ+®èöüG>ò‘˜4iRê‚F! h Ο??æÎwÜqG¬]»6"^9Ónû-ï<ðÀx÷»ß3f̈ &ÔªÔŠ>ûÙÏÆ‚ ⡇ŠˆW:Û¾ò•¯Ä¿üË¿ÄÁÇÅ‹ÇO<Ñ-ðlmmk®¹&Æ—IsçÎív}æ™göz«ÍíÏÜfΜ91gΜ¯uÙe—ÅŒ3vyÏßúÖ·â/þâ/Ê]˜¿ùÍoâOþäOâC‰¶¶¶X·n]<ñÄÝÂЈˆN8!.¼ðÂ× MÓ(v.ª8—Ô•º W­Z·ÞzkÌ;7,X ·…hƒŽSN9%fΜÇsL-ËÝ¥\.W]uU|ñ‹_Œ;<þâ‹/ÆÏ~ö³ŠÏì¿ÿþqùå—ÇÑGIË–-‹ŸÿüçÝÆúò|À,sÌ1qÍ5×ÄÅ_\Ó4ùóçÇüùó+>óÎw¾3¾ò•¯ ¸s,!+]/½éþÆŽòí…Lk wê* ìêêŠx nºé¦xà¢T*ED÷nÁ4Mãˆ#Žˆ™3gÆgœûì³O-KÞcÇ+¯¼2N=õÔ˜5kVüö·¿­xߨQ£âôÓO .¸ FY}7ÝtSùûŽˆ8äCâ ƒÊìý}íío{Ü~ûíqõÕWÇO~ò“ò–£;:òÈ#ã#ùHœzê©WKñ÷Uçl1 P_’tÇCú … ÆÜ¹sãÖ[o_|1"vî3fLœyæ™qÎ9çt;K®^mÛRtùòå±qãÆ3fLLœ81Ž:ê¨nçÒ{[¶l‰ßüæ7ñÜsÏÅÊ•+cèС1~üø8è ƒ¢­­­_Þ¹lÙ²8î¸ãv衇büøñýòNè 7Η.ü«Æ“aÃbÂÓOvÛÒ€m@wÞpà qÓM7Åc=;f™¹\.Ž;9sfüñ µýc[[[¿…St7hРxÓ›ÞTë2`@+vvVÏ ÂA€:3 Â/}éKݺ·™:uj̘1#Î>ûìØÿýkT@ó¨æl/ Pwt@¸½ÖÖÖ8á„bæÌ™qÄG”ÇW¯^Ýçï5jTŸ¯ PϪv¾ª=ÛB赺 ‹ÅbÜ}÷Ýq÷Ýw÷ë{’$‰'žx¢_ßPoŠÇó:êN]„ÛηÚq«Qú_×K/EZ¥[;_˜’q5ôV]„Ûl û‹`gÅE‹ªÎé ¨?: œ8qb­KhzÕÎL† ‰–ñã³-€^Ðá}÷ÝWëš^µós…)‘´´d[ ½æovØ¥j¡íEê“€€]*UÙbT@PŸ„ìRµ3„õI@@U]k×F׋/VœË ê’€€ªŠ‹UË¿ª=ÃJè+Bª*vtVž<8r&dZ }C@@U¥jçNžI‹ÿ…Ô#» @UÅjaaJ¶…Ðg„TUìè¨8ž+²-€>#  ªb碊ãy!@ÝPQ×úõѵ|yŹ|{!ÓZè;B**UéŒÐAPÏ„TTìì¬<‘ÏGnÒ¤Lk ï¨¨Z@˜Ÿ<9’|>Ûbè3B*ªæl/ PׄTTìè¬8žo/dY}L@@E¥j[Œê ¨kBv’nܥ矯8' ¨oBvR\´¨êœ€ ¾ ØI±Êö¢‘ËEîÀI™Ö@ß°“jaîÀI‘ ”m1ô)!;)vTÞbÔö¢õO@ÀNJU:óííÙ@Ÿ°“j[Œê ¨BºI7oŽÒÒ¥çrB€º'  ›ââÅiZq.ß^È´úž€€nŠ•'’$òmm™Ö@ßÐM©££âxnÒ¤Hθúš€€nŠÇóÎhBº©æ„ A@@7U;Û§d[ýB@@YºeK”/©8g‹Q€Æ  ¬´diDWWŹ|{{ÆÕЄ”UÛ^4""?yrv…Ðo„”U s&D2th¶ÅÐ/„”U ?Ð0„”;:*ŽçÛ ™Ö@ÿPVìè¬8ž×AÐ0„DDDZ,FiñâŠsB€Æ!  ""JK—F‹ç„C@@DD;;«Îå S²+€~%  "ªŸ?Ø2~\´ žm1ô!Q½ƒÐö¢E@@DD”„MA@@DD;U4!‘–JQ\T9 Ì Š€€(=ÿ|Ä–-çòí…Lk  ˆbGgÕ¹ü”)Ù@¿¥ÎΊã-ûï-#Fd[ ýJ@@«„yç4!UÂ\{{¶…Ðï„좃ÐùƒF@ÐäÒ®®(u.ª8—o/dZ ýO@Ð亖-‹tÓ¦ŠsÎ h<B€&Wm{Ñ!@#4¹bGgÅñdÔ¨h5*ÛbèwB€&W­ƒÐùƒI@ÐäªuÚ^ 1 š\©Z¡€ ! šXš¦Õ·4$!@ëZ±"Ò *ÎåÛÛ3®€,šXµîÁˆˆ\{!«2È€ ‰;:+Ž'#FDË~ûe[ ™4±RÕó§D’$Ù@&„M¬ØÑQq<_(d[™4±b碊ãB€Æ% hRišF±Ê£9!@Ã4©®U«"]·®â\¾½i-dG@ФŠUçl1 и„MªTe{Ñdøðh;6ÛbÈŒ€ IU;0_(D’$Ù@f„MªZ@˜³½(@C4©ª„í…,Ë cB€&Uìè¨8ž×AÐЄM¨ë¥—"]½¦â\¾0%ãjÈ’€  UÛ^4B!@£4¡ja2dH´ŒŸm1dJ@Ð„Š‹*Žç S"iñ¿€FæošP±£³âx¾½=ÛBÈœ€  •ªl1êüA€Æ' hBÕÎ 4>!@“éZ»6º^|±âœ€ ñ šLqÑ¢ªs¹öBfuPB€&Sü}Gå‰Áƒ#7aB¶Å9!@“)U;pòäHZüo Ñù›`€&S¬¦d[5! h2ÕÂ\¡iÔ†€ É;UÏ š‚€ ‰t­_]Ë—WœË¿ª=ãj¨!@)UéŒÐAÐ,„M¤ÚùƒÑÚ¹‰3­€Ú4‘ja¾­-’|>Ûb¨ !@)vtTÏÙ^ išHÕÂöB–ePCB€&Rìè¬8ž×AÐ4„M¢kãÆèzá…ŠsB€æ! h¥E‹ªÎ š‡€ IT;0r¹Èµ˜i-ÔŽ€ IT smFÒÚšm1ÔŒ€ I;*o1j{Q€æ" h¥*„B€æ" hÅŽŽŠãB€æ" hé¦MQzs9!@S4ââÅiZq.ß^È´jK@Њ•'’$òmm™Ö@m š@©³³âxnÒ¤HζjJ@ЊUÂ|{{¶…PsB€&P5 ,LɶjN@Ъ„¹B!Ó:¨=!@ƒK·l‰Òâ%çòí…Lk ö„ ®´diDWWʼB€¦# hpÅŽŽªsùÉ“3¬€@@Ðઞ?8aB$C‡f[ 5' hpUBÛ‹4%!@ƒ«æÛ Y–À! hpŎΊãy„MI@ÐÀÒb1J‹WœË··g\ € •–.(+Îé hNB€VíüÁˆˆ\aJv…0`Xµó[Æ‹–aò-€A@ÐÀŠÇm/ м„ ¬Ô¹¨â¸€ y Xµ3„ÍK@РÒR)ŠÏ>[q.' hZB€Uzþùˆ-[*ÎåÛ ™ÖÀÀeŽ¢ IDAT! hPŎΪs¶h^B€Uªrþ`˘1Ѳï¾ÙÀ€! hPÅ*¡îA€æ& hPÕœ€ © T±££âx¾0%ãJH„ (íêŠâ¢Eçòí…Lk``4 ®–ElÚ\q΄ÍM@Ѐª?! hvB€T- LFŠ–Q£²-€E@Ѐª„ùööl `À4 bGgÅñ|{!Ë2€„ ¨T­ƒÐùƒMO@Ð`Ò4­¾Å¨€ é L׊‘nØPqN@€€ Á;:ªÎåÚ ™ÕÀÀ$ h0Õ¶MFŒˆ–ýö˶!@ƒ)vtVϦD’$ÙÀ€# h0¥*„Î B@ÐpŠ‹*Ž ˆ4”4M«žA˜ko϶$!@éZµ*Òuë*ÎåÛ ™ÖÀÀ$ h ŎΪs¶ B@ÐPJU¶M†–1c²-€I@Ð@ŠÇó…B$I’q5 DB€R¬ÒA˜³½( h ÕÂ|{!Ë2À„ ¤j@¨ƒ€?È׺*[¼xq<ù䓱|ùòX¿~}Œ7.&NœÓ§OÖÖÖZ— @]/½éê5çò…)WÀ@% `î¼óΘ={vÌ›7¯âü¨Q£âôÓO .¸ FÝouœx≱téÒ>YëÝï~w\~ùå{tï²eËâñÇÇ<æÏŸóçÏÕ«Ww»ç©§žÚëZzû¹þã?þ#Ž9昽~úSµîÁˆˆ|{{v…0  ˆõë×Ç%—\?þñwyßêÕ«ã?ÿó?ãî»ïŽË/¿<Þö¶·eTáÞô¡rH¸zõêøö·¿—^ziŸÖuÀìÕs<ð@·ë™3gîQçRKKK´··Ça‡‡zhzè¡qðÁÇŠ+⤓NÚ«Zv'ŸÏÇØ/kC-«„éB¶' ¬±oûÛ±uëÖòõŒ3*†ƒÛ 2$.»ì²8óÌ3ËÏÍ;7>úÑF[[[¿×»+<òHüþ÷¿/_·´´ÄŒÿŸ½û²ÊÛ8~'3éBH" ÁÐT@WXAÁem¬ 6Ćè«bCAeW\ÙEE_)‚i ¬ÒYª %$‚i¤g&yÿàe6“Ì™”™Iø~®‹Ëœç9ç9¿&*Ü9çÜR㸾}ûjûöí jÈò€&Ïlç BB@eœAèFÅÅÅZµj•ÕµñãÇ×8...Î*D4™Lúꫯê½>g-]ºÔª}õÕW«uëÖ5Ž &ê¨<7WåYY6ï*# t£M›6©¨¨ÈÒîÑ£‡:tèàÐØª+óV¯^]¯µ9«  @ß}÷յѣG»©àÂc:~Üî=C\¬Ëêx>B7Ú°aƒUûŠ+®pxlïÞ½e4þw‡ØèôéÓõV›³¾ýö[ZÚááá vv €êL‰I¶oøùÉàÀJ^À…ƒ€Ð>lÕîÞ½»ÃcuÉ%—œ÷y®Tu{Ñ#FÈÇÇÇMÕ»çÆÄÈË›ÕþËXs4”cÇŽYµcbbœ­XÚGÕ•W^Y/µ9ãèÑ£Úµk—յư½h~~¾¦M›¦Ý»w+--M Rhh¨:uê¤Þ½{kÈ!ŠŒŒtw©@LöÂXçþ½húÝ$''G999V×Z;¹ `›6m¬ÚIv‚†¶dÉ«v÷îÝuñÅ»¥gäææêóÏ?·ºvî÷%))I«V­Ò믿®áÇkòäÉjÑ¢…›*jf? ŒuiÏǾsnræÌ«v@@€zFxx¸U;??¿Îu9Ëd2iåÊ•V×ÃêAG•••iÙ²e1b„¶mÛæîr»LIÇm^7ª`¡›Xµýüüœ~†¿¿ÿyŸé ?þø£NŸ>miê†npyÎðööV||¼úõë§Î;«mÛ¶ VQQ‘222´k×.­X±B©©©–1™™™ºÿþûõñÇ«k×®n¬¨®¼ @å6ïãb]Z ÀóºIaa¡U»>ªÏt…ªÛ‹:TAAA.¯ÃQcÇŽÕ AƒÔ¶m[›÷;wî¬hâĉZ´h‘fÍš¥²²2Igß߇zH«V­R@@€+ËÎË”˜d÷[Œªb‹Qáååå’1õ)##C7n´ºæéÛ‹Þ}÷ÝvÃÁÊ ƒî¾ûn½ýöÛòöþï·Izzº>üðÆ,pšÙÞù£>>2T9«B7©zÞ`qq±ÓϨ:ÆÙ3 ëêË/¿”Éd²´;tè ž={º´††6pà@ÝqÇV×>ýôS7UØf²££åed¡8À¡›T݆³¤¤Äég¸; \ºt©UÛÓWÖÖý÷ßoµZ3--M¿ýö›+¬Ù  l/ °€ÐM‚ƒƒ­ÚEEENŸ!˜••eÕnÖ¬YërÔöíÛ•T)”ðññш#\6¿+µjÕJ:u²ºvèÐ!7UTgwa\œk 4 „n¦«k§Nrê©©©VíX®Z²d‰UûøƒZ´há²ù]-**ʪ]5œÜÉ”˜dóº1.Ö•e B7jß¾½UûøñãNOII±jwèСÎ59"??_ßÿ½Õµ¦º½è9þþþVíÚl 4„ò¢"•§¥Ù¼gŒqq5€Æ€€Ð.¹ä«öþó‡ÇVÛæ²cÇŽõRWM¾ýö[YÚ‘‘‘êׯŸKæv—ììl«vXX˜›*¬™ÏóƒFÎ Ø@@èFýû÷·joݺÕá±Û·o—Éd²´/½ôREDDÔ[mçSu{Ñ[n¹EƒÁ%s»ƒÙlÖþýû­®µjÕÊMÕÖì?(ƒA†¶m]Z  q t£~ýúYm]¹k×.=zÔ¡±Ë—/·j4¨^k³çÈ‘#Ú½{·¥íåå¥Q£F¹dnwÙ°aƒrss-m£Ñ¨^½z¹±"à¿ì?hˆn+/×hÝ( @C† ±ºöÞ{ïÕ8.11Q«W¯¶´F£†^ïõÙRuõ`Ÿ>}풹ݡ°°PûÛ߬®]qÅ vSE€5{!Û‹ì! t³GyD>•Vù,[¶Lk×®µÛ¿¤¤DS§NUYY™åÚ¨Q£Ô®]»óÎÓ©S'«_[¶lqºÖ²²2­X±ÂêÚèÑ£~Ž;deeéË/¿”ÙlvxL~~¾{ì1>|ØêúÃ?\ßåµf¶³Å(!ÀB7‹ŽŽÖ]wÝeuí±ÇÓǬÒÒR«ëGÕ_þòíÚµËr-44T'NtI­ëÖ­SVV–¥¢Áƒ×˳333•’’RíWZZZµ¾¶ú¥¤¤(33Óîó õ׿þUC† Ñœ9stðàA•——Ûì[RR¢/¿üR#GŽÔ† ¬î5J½{÷®Û‹ꑽ3 öÝ]¤É“'ëÈ‘#–0ª¬¬L/¿ü²þñèÒK/UPP’““uàÀUTTXÆùøøèwÞQ«V­\RçÒ¥K­ÚÇ—ŸŸ_½<{Ò¤IÚºu«C}hóúW\¡E‹wlrr²æÎ«¹sç*00P;vTxx¸‚ƒƒURR¢ÌÌLíß¿¿Z8+I×^{­^zé%‡j\¡¢¸Xæ“'mÞ3ì ôƒAo½õ–ž}öY}ûí·–ë¿ÿþ»6nÜhsL‹-4sæL—­fKOOצM›¬®5–íEí),,ÔîÝ»kìçã㣇~X÷ß¿ ƒ *cJN–*ýÐ@eƸ8Wh,=DPPÞ|óM 2D|ðþóŸÿØìª¡C‡êÑGUxx¸Ëê[¶l™Õù}]»vU—.]\6]…‡‡ëÑGÕ¶mÛ´gÏÔ8¦uëÖ>|¸n»í6µiÓÆUÎ1%&Ù¾áí-ct[—Öh<¼**ì,?[ÛR4##CEEEŠˆˆP›6mÔ³gOùúúº»¼F­¢¢B)))JJJRzzºòòòT\\,…„„(<<\ݺuSdddƒÕžž®T»¾aÆMKþ¿æ+÷ÅêÛÞ¢£uÑæŸÝP 1`¡‡ŠŽŽVtt´»Ëh’¼¼¼xÑ$˜’’l^7rþ à<¼Ý] vL‰‰6¯cc\\  1! €FÊ”tÜæu+çA@PEi©Ì))6ïãb]Z  q! €FÈ”œ"•—ۼDŽ€ó! €FÈœ”d÷ž±];×ht 2Ù  mÚÈ+ ÀµÅBh„ì„l/ ¨!4BöBc\¬+Ë4B„Й“l^7²‚PBhd*L&™““mÞ# Ô„€sJŠd2Ù¼G@¨ !42öΔ$ClŒë 4J„ÐÈØ ½#[É;0еÅBhdL‰I6¯³½(À„ÐȘ“ŽÛ¼nŒ‹sq%€Æˆ€{[Œ²‚àBhD*Ìf™Nœ°y€àBhḐNI¥¥6ïâb]Z  q" €FÄ”˜d÷ž1&Æu…š„””uêÔÉòkÊ”)î.ɪž»îº«Áæ™3gŽÕ\[¶li°¹.TS¦L±zSRRÜ]àÿ@#bNL´yÝ;"BÞÍš¹¸@cD@ˆ))ÉæuÎ8Š€{¡€à BhDì¯ äüA€cŒî.à˜Šòr™Ž·yÏëÒZh(‡rw 4y¬ €F¢<-]*.±yÏçâj!4ö¶•$c [ŒÃ£ÐHØ ½ÃÂäêÚbÀÍJ÷îUáÿ~ª²ýT^X ïÀ ùt½T·ß&ßnÝÜ]Þ¥  @;wîTFF†²²²d0®:¨k×®òöví…ììlmÛ¶Mééé*..V«V­­îÝ»7H-GŽÑo¿ý¦¬¬,åçç+$$D-[¶T¯^½V¯s•””hÇŽJMMUVV–‚ƒƒÕ¦M]~ùå ®õsËËË•˜˜¨ÄÄD¥¥¥©  @ƒA!!!jݺµÔ¬Y³z|%Ž)++ÓöíÛ•’’¢¬¬,…††*22R=zôPHHˆË뀦„€ {¡!6Ö¥u€;•îÞ­œg§©lçÎê÷vìPÁG‹äÛ«—B^~Q¾ n¨ð±qãFÍŸ?_;wîTYY™Í>aaa=z´î»ï>‡N:Y¾¾âŠ+´hÑ"‡Æ%%%éµ×^Ó† d2™ªÝoݺµn½õV?^~~~=Óžììl-X°@+W®TzzºÍ>ÞÞÞêÑ£‡&Nœ¨«®ºÊ¡çN™2EË—/·´×®]«¶mÛ*//Oo¿ý¶V®\©¼¼¼jãŒF£n¼ñFMš4I‘‘‘Í•››«Õ«WkíÚµÚ¾}»ÍçV~-½zõÒ¸qãô‡?üÁ¡ç×E~~¾Þyç-Y²Äf]¾¾¾ºîºë4yòdEGG+%%E´Ü¿ùæ›5sæÌ¯3¶€F”˜hóº1.Ö¥u€»­^£Ì[FÙ ++ݱC™·ŒRÑê5.ªìÂ’••¥{î¹GãÇ×–-[솃ÒÙ mþüù|¸Ö­[g3”¤S§NiöìÙ3fŒ233ë4× Aƒ4þ|»á tvUÞŽ;tÏ=÷è©§žRiii­æÛ³gFŽ©?þØnˆg2™ôå—_jÔ¨Q:xð CϽóÎ;õÌ3Ïhݺuç ¥³¯eÛ¶mzðÁ5iÒ$:ý:uøðaÝpà zÿý÷íÖUZZªï¿ÿ^7ß|³Ö¯_ß`µ@SÆ Bh$L‰I6¯YAàPº{·²|P*.ql@q‰²|P-—-e%a=:~ü¸Æ§ääd«ëAAAêÚµ«"""d6›•ššª¨¼¼\’”““£{î¹Gï¾û®ú÷ï_¯5}ýõך:uªe®sâââÔ¾}{ùøø(55UûöíSEE…~ýõW=ðÀºú꫞ëí·ßÖ?þñ«k^^^Š‹‹SLLŒ‚‚‚”——§}ûö)++ËÒgåÊ•ÊÌÌÔ{ï½'£Ññ¿’MJJÒ“O>©œœIRHHˆâãã¦ÂÂBíÛ·O–þ™™™š8q¢V®\©ÀÀÀó>»¢¢Âªª:(,,L***Rjjª>lóÍ7*,,Ô»ï¾+///‡_‹#Ž;¦»îºKÙÙÙÕj‹Whh¨rrr´oß>åääèÌ™3züñÇõ÷¿ÿ½^ë€ !42ÛÙb”€@C¨(.–¹«¬ê[ÎÓu<<§¸D9¢ðùÿj˜¢œdhÙR^þþî.£ÖŠŠŠ4qâD«p0..NO<ñ„ $ƒÁ`Õ?##CsæÌÑâÅ‹%=Oî©§žÒŠ+Þ³&)))zî¹ç¬ÂÁnݺéùçŸW·*gQ¦¥¥iæÌ™úî»ï´ÿ~¥¤¤85×òåË­ÂAoooÝqǺ÷Þ{Õ¦M«¾Z»v­^yåéðœ“'OVNNŽ¢¢¢ôôÓOëü£Õû\QQ¡¯¾úJÓ¦MSQQ‘$)99Y|ð~øáó>ÛËËK½zõÒ°aÃ4`ÀEGGÛì—››«%K–èwÞQAA$iýúõúì³ÏtÛm·9üZjb6›õôÓO[…ƒáááš2eІ f¬šL&}ýõך9s¦²³³õÌ3ÏÔ[p¡ €F <#Cÿÿ?úU¨OåEEÊ™ô¤Š~øÁù@Εíݧô¾ŽÿÖàüý0x°Bÿþ7y¸»§½þúëúí·ß,íhΜ9ò·z¶jÕJ/¿ü²Ú·oo9.;;[o½õ–f̘Q/5MŸ>Ýj»Ë+®¸Bï½÷žÍ3/ºè"½õÖ[jÙ²¥>úè#åææ:úè#…‡‡Ûœç¦›nR`` U ¸dÉM˜0á¼+üÞ}÷]µmÛ¶ÆBBB4nÜ8]}õÕºóÎ;uæÌËk3fŒ¼½ëç«Å‹kïÞ½–vxx¸>ùäµoß¾Z_£Ñ¨‘#G*>>^wÞygµ‡€šq!4&;«%Éëª2\r&=©¢•_5‰pÐã—¨håWÊ™äø 2O‘žž®/¾øÂÒŽŠŠÒìٳ톃•ÝsÏ=ºæšk,í¯¾úªNgžsâÄ ýøã–vPPfÍše3¬lÊ”)êÒ¥‹Ss-X°@ÅÅÅ–öÔ©S톃•µhÑB³fͲ´Íf³>üðC‡ç5zûí·m†ƒ• 4Hñññ–öÉ“'-¡¤=Ž„ƒ•uîÜY&L°´“““µk×.§žq>Ÿ|ò‰Uû¹çž³Vvñųzj‰€{¡WHˆ¼ÃÂ\[ €&«¢¸øìÊA4¨¢~PE¥°©1øì³Ï¬Î¡›8q¢œXyÏ=÷X¾.++ÓÆë\ÓŠ+¬ÎÑûóŸÿìÐÖ¥ƒA'NtxžÂÂB-]ºÔÒŽŽŽÖŸÿüg‡Ç_vÙeêÝ»·¥½nÝ:‡Ç>>VíäädµiÓ¦Æq_|±Ãs„„„XµÏX“ÜÜ\­^½Z?ýô“:¤äääjA =yyy×w>´jwëÖÍ©ñÎö@£`J²}n!€úú÷¿I:» &çÖ3? ly‹ÌÌL«íESSS5pàÀ:=3''§NãKKK­°¶mÛÊ`08õŒØØX‡´´4«ö«¯¾ªW_}Õ©¹ªÊÍÍu¨_ÕÐï|*¯Ð”$“ÉtÞþf³Y ,лᆱÂÂB‡ç©ÌѲ&UÃfGÂÓÊZ·n]/uÀ…„€<\EE…L‰‰6ïÔ3¿ûUËœ™éîr$Ie)ëî{jîhGøÂäÓÙñÕe Åвe£Z9xN]Ã<[ ê4¾jÀìô3š5kæP?w¾þ†:VÄd2iÒ¤IZµjUžSù Ⱥ¨495¾6¿ÿp¡# WþûïªÈÏ·yÏëÒZ\8¼üýeŒŽvw’$ct´|zöTÙÎNõíÕKÔU]8*¯ôT ¤I óúë+X«­… V »wï®Áƒ+>>^­[·Vxx¸|}}åëëkÕÏ™­\UugßóÆðOC@Δ˜d÷[Œ¸P„NI™·ŒrnÛS?…¼übÃu ³j÷ë×O ,pS5gÕö¼½ÚŒ µjöÙgêÑ£‡ÓóyŠÒÒRÍ›7ÏÒöòòÒŒ3tóÍ7×86ßÎ0×UóæÍ­ÚŽnÁZÛþÉÛÝÎÏœ”dóºWP¼#"\[ ¸‰oB‚ÂçÍ“üýàï§ðyóä›Ð°…]"ªüÙ3ÑÎ1®äëëkµEhJJŠÌf³SÏH²óçíªª¾~GÇyªmÛ¶Y…£#FŒp(”¤ôôô©©ê™ƒ¿ýö›Sã:TŸåÀ€<œÉÎ<Œ±± º… xš€?RËeKåÛ«×yûùö꥖˖²µh= VÇŽ-íÔÔTÉâãã-_ëàÁƒ-++Óê[uµà¦M›žÇUý½»öÚk»k×®ú-æÿuïÞݪ½e˧Æ;Û@@Ïn@çÚBÀø&$¨åÊ/Õòûoô—±òíÝ[Æ.åÛ»·‚þ2V-¿ÿV-W~ÉÊÁzÖ¯_?«öâÅ‹ÝTÉõªýõ×ýé§Ÿ”——çPß+¯¼RƒÁÒ^·n~ÿýw‡çò4U·V­¼³&Ë—/¯ïr$ý½ôóûïêàµk×:ügffjݺu R4e„àá섆Ø×Ä·[7…¾úŠZ®X®È5«ÕrÅr…¾úŠ|»uswiMÒm·Ý&£ÑhiüñÇ:|ø°+:»5fåu>ÿüs‡¶À4›Íš;w®Ãó„„„høðá–vaaЉ¡y IDAT¡^{í5çŠõ UÏû;vì˜CãÖ¬Y£íÛ·7DIjÞ¼¹n¸áK»´´T¯¾úªCc§OŸ®²²²© š2BðpöWƺ² À,&&F·Ür‹¥]RR¢ûï¿_GŽqê9¥¥¥Z¶lY½ÔÔ®];«í1 4yòd•””œwÜk¯½¦_ýÕ©¹&Nœ(___K{ÅŠzã7œ>÷ðÈ‘#Ú¶m›Scê[çέڟ|ò‰ Ï;fïÞ½úŸÿùŸ†,KãÇ—¥ýõ×_kÆŒ2™L6û—••iúôéúþûï´.hªÀƒ•gg«"'׿=cl¬k‹\ЦL™¢N:YÚ'OžÔ¨Q£ôæ›oêÔ©SvÇëçŸÖôéÓuÍ5×hêÔ©õVÓ3Ï<£ÀÀ@K{ëÖ­ºóÎ;µoß¾j}ÓÒÒôÄOèÃ?”tve £¢££õòË/[]{ï½÷tûí·kݺuvC,IJIIÑ'Ÿ|¢±cÇjذaÚ¼y³Ãó6„„„EEEYÚIIIº÷Þ{uôèÑj} 4þ|;V¹¹¹ o°º.¾øb=úè£V×.\¨#FháÂ…Ú½{·’’’´{÷nËõE‹I’† Ö`u@Se¬¹ À]ì­”®¤þóŸº÷Þ{-ÛRkÞ¼yš7ož¢££Õ¾}{5kÖLf³YgΜQjjªNœ8áôJ;GEGG륗^ÒÓO?­òòrIÒž={4jÔ(µoß^íÛ·—RSSµoß>KŸ.]º¨ÿþú׿þåð\#GŽTff¦þþ÷¿[žóŸÿüG=ôÔ¥KEDDÈÏÏOÊÎÎÖÑ£G>ëÐU ƒ&Ož¬'žxÂrm×®]6l˜:uꤸ¸8yyy)##C{öìQii©$Éh4êµ×^Ó}÷Ý×`µÝwß}:yò¤>ýôS˵#GŽhÆŒvÇôíÛW?þ¸¾ùæ˵Ê[Ïl# fJL²yÝËß_Þ‘‘®-pÁkݺµ–,Y¢çŸ^_}õ•Õ½ääd%''×øŒªgàÕÕðáÃe6›õÜsÏYÂ,éìÙz¶Î×»ä’KôÏþS‹/vz®ûî»O:uÒÿüÏÿ(33Ór½¨¨H;wîtèõýúkã†nPRR’fÏž­ŠŠ IREE…<¨ƒVëïïï¯×^{M hк¼¼¼ô /(&&F³gÏ®qëÓ;ï¼Sýë_«}î‚‚‚²LhÀƒÙ[Ahˆ‹å§án¤Y³fiüøñZ°`~úé'åæÚ>ãœV­Z©OŸ>4h®»îºz¯iäÈ‘JHHÐk¯½¦7ÚÜò322R£GÖ}÷ݧ€€€ZÏ5`À­]»VK–,Ñ_|¡ƒZB6[|||¯~ýúéÆoT¬‡ì4aÂÅÇÇë­·ÞÒþýûmö ÖÿøGM˜0AíÚµsYm÷Üs† ¦+Vhýúõ:qâ„rrrªV­Z©oß¾ºùæ›Õ±cGIª¶J388Øeµ@cåUq¾ÿzhééé6âjÆ ŠdU*Ézä1Ù8¼ÝèõjñÞ|7T€µòòr:tHGŽQnn®òòòäçç§àà`EEE©C‡jݺµËêÉÊÊÒ¶mÛ”žž®ââbµjÕJmÛ¶UÏž=åíí]ïóåääh÷îÝÊÈÈPnn®L&“Õ¢E ÅÆÆª}ûöu $]!11Q»wïÖéÓ§UQQ¡ˆˆ]tÑEêÙ³§üüüÜ]^¾øâ =ûì³–ö´iÓtÇw¸±"ð|¬ fo!ç<…···ºté¢.]º¸»IRxx¸† â²ùBCCuÍ5׸l¾†§¸¸8w—QkÛ·o·jwíÚÕM•@ãQÿ?2¨7fB»²³³õý÷ß[Ú~~~V€'# Už›«ò¬,›÷Œø§úêË‹/¾¨ââbK{èСb[Tp7BðP¦ãÇíÞ3°‚4AãÇ×þóŸûåççëé§ŸÖwß}g¹æíí­»îº«!Ë€&ƒ3ÀC™“lßðó“¡õE.­À6nܨ7ªcÇŽ8p ºu릨¨(ª  @'OžÔÖ­[µbÅ åääX7nœâããÝT94.„à¡ìž?#/o€€¦ëðáÃ:|ø°Ãýo¼ñF=öØc X4-„à¡L‰‰6¯cc\\ €k„††V[x>-Z´Ðƒ>¨±cÇ6`UÐô€‡2%Ù>ƒÐÈùƒ ‰ú÷¿ÿ­íÛ·kÛ¶mÚ·oŸNœ8¡Ó§O«¨¨H’¢ððpuëÖM}úôÑ!Cäïïïæª ñ! e²³Å¨€4QF£Q}ûöUß¾}Ý] 4ib¨€1%'K6ïõ€€<ˆ)1Ñö oo£Ûº¶@“D@Ä”˜dóº!*J^~~®-Ð$€1'%Ù¼Îùƒ€úbtw€ÿ2Ù c\[à‚’’¢ZÚ7ß|³fÎœéÆŠà¬»îºK[·nµ´:äÆjêÇu×]§ÔÔTIRTT”Ö­[çæŠ`O§N,__qÅZ´h‘«à V€1%·yÝÀ B@=! QQZ*sJŠÍ{Æöq.®ÐT€‡0%§Håå6ïq! ¾€‡0Û9P^^2¶kçÒZM—ÑÝÎ2Ù  ­[ËËßߵŀFaÑ¢Eî.¡Þ­[·ÎÝ%@“Ç Bð¦ÄD›× l/ ¨G„à!ì­ 4ÆÅº² @Ç£à!L‰I6¯YAðPÚ¿¿Ž;¦¬¬,•––*,,L‘‘‘êÕ«—‚‚‚Ü]¢Ç(++ÓÑ£G•˜˜¨ÌÌLÈÏÏOÍ›7Wtt´.»ì2¸µÆŠŠ íÙ³GIIIÊÈÈZ¶l©^½z颋.rkmÎ8s挶nݪ´´4¨eË–jݺµzõê%Ÿ›÷رc:|ø°233uæÌ………iذajÖ¬™Ý1§NÒÑ£G•œœ¬üü|•——«yóæjÑ¢…YïukûöíJKKSVV–š7o®6mÚ¨OŸ>òóó«×¹N:¥½{÷*--MÅÅÅ S§N/ooÖ/îD@ ¢¬Læ”›÷ ºƒ'ó´rgЧQa©I¾Fu¼¨™nêÙVÛ4wwyM^VV–þùÏjåÊ•ÊÊʲÙÇÇÇG}ûöÕ#<¢„„‡ž;eÊ-_¾ÜÒ^»v­Ú¶mëÐØ-[¶hìØ±–öĉõÈ#XõYµj•}ôQK{øðáš5k–Cϯlîܹš3gŽ¥=iÒ$=ðÀÕúeddhÕªUZ¿~½víÚ¥ÂÂB»Ï4êß¿¿Æ¯Þ½{;\Ë]wÝ¥­[·ZÚ‡²ÛwÙ²eš:uª¥=cÆ ÝrË-*//ׇ~¨?þX)vþ~¢wïÞzúé§þ½¬‹ë®»N©©©’¤¨¨(‡Ï$LNNÖ믿®õë׫¬¬¬Úý°°09R>ú¨í¾¶¤¤¤hàÀ–öÍ7߬™3gJ’¾øâ -Z´Èæ{Ÿ .]ºXÚ¥¥¥Ú´i“~øámÞ¼Y§N:ïkŠÕرc5zôh‡Ã»9sæhîܹ–öG}¤>}ú(==]sçÎÕ7ß|£‚‚‚jãuÓM7é‰'žPhh¨CsÙ³sçNÍ™3G›7oVyyyµûzðÁuÇwnB@Àœš*™L6ïÀýšš«¿}û«ö¥äV»·79G˶%«[t¨& í¬.Q!n¨°é[³fž~úi›CeeeeÚ¸q£6nܨ1cÆhÚ´i2Ýûב×]wZ´h¡ßÿ]’ôÃ?(//OÍ›;*WTTX…˜ƒA#GŽ´Ù÷ú믯ñ}:Çd2iýúõZ¿~½î¾ûn=õÔS.y¿~ÿýw=þøãV!£-Û·o×wÜ¡3fhøðá ^—³¾ùæM:U%%%vûdggëƒ>І ôÎ;ïÔyÎüü|Mžûì3ýðÚ7o^­ÃàyóæiöìÙ2›Ívûœ>}ZÓ§O×–-[ô÷¿ÿ]¾¾¾µš @퀰wþ $bc\Wx°M‡2ôÌâÝ*1U_RÙÞä=øþV½ò§õëÔÊEÕ]–,Y¢çž{®ÚŠ víÚ©C‡ ЩS§´gÏ«pàóÏ?×É“'5oÞ<·†„>>>1b„Þÿ}IRII‰¾úê+ÝqÇ?cóæÍV«ì `wÈŠŠ «vDD„Ú·o¯ÐÐPùûû«  @'NœÐ±cǬޯ… ª¬¬LÓ¦Msæå9­¸¸X<ð€öîÝ+IòõõU||¼"##U^^®£GêÈ‘#–þeeeš:uª:vì¨Î;7hmÎøöÛoõÔSOU ¤¢££uñÅ+ @Ú³gJKKuôèQ=ôÐCNý¾WUQQ¡)S¦XÂA///uêÔImÛ¶•ÒÒÒ´oß¾jãª~ï¨}ûöjÕª•‚‚‚TVV¦Ó§OëàÁƒVáòÁƒ5vìX-_¾ÜéÕ}'NœÐ믿®¼¼øàÝvÛmo'  ~€0%&Ù¼Îö¢Ü¥¤Ì¬ßóKÝ]†ÅŒ•ûÏ)1•kæW4cL÷ªÊ9-‚}åçcpwµöÌ3ÏXëÖ«W/-X°@Õú†‡‡ë¥—^RLLŒ^ýuËõùóçkذaêÔ©“Kj¶¥C‡êÑ£‡víÚ%IÚ¿¿<èЊ¸¼¼<­^½ÚÒnÙ²¥®½öZ»ýW®\éPèѪU+=ñÄêÓ§î»ï>™þÿ’ùóç7h@˜­ÀÀ@}øá‡ºì²Ëlö¹ì²Ë´páBÝxã–@lË–-:~ü¸bbÜ¿ëÑ믿®üü|K»GZ°`‚‚‚ªõ ÖO<¡N:iÒ¤IÊÎήõ¼çÞ {çOJg¿ª?~¼ž}öÙÏÝóññÑСCuÕUWé/ù‹~ýõWIÒ÷߯I“&9µÕhnn® ƒÞzë- 4¨Ú}ƒÁ n¸A—^z©î¸ãKH˜””¤yóæéñÇwhžsÛ—Ž?ÞîŠÀ͘1C¹¹¹Z»v­¤³å’%Kž@ý `N:nó:!W+.5kúŠ}Úx0Ãé@Î:•§[ÞÚàî2$I~FoõïÜJÏŽˆ—¿oã 7oÞ¬ýû÷[ÚÁÁÁzóÍ7m†ƒ•7NÛ¶m³lÃX^^®… jÆŒ ZoMn½õVK@(]øì³ÏÖ8¾²ÚqäÈ‘çÝ2ÕÙQW]u•þüç?ëã?–$mݺUééév·0­S§NµžÓ¦M3Ʋò²¢¢B[¶lq{@˜žž®~øÁÒЬY³l†ƒ•Ýpà úå—_´xñâ:Íå•WÚ íiÓ¦SýCBB4}út5JÒÙ¿þZ=ôSϹóÎ;m†ƒ•ÅÆÆê…^Ðĉ-×>ûì3M˜0Áá3{õê¥'Ÿ|²Æ~O<ñ„% ”Îþ;€kÿÇ.aJL´y€€«M_±Okö¥5‰pÐÓ”˜Êµf_𦝍~.™§ûòË/­ÚwÜq‡Ã¡UÕ°à›o¾Qi©{W§:Ô*Dúꫯª©êö¢çB›ú4xð`«öÎ;ë}Žs"##uË-·8Ô÷øƒUûÀ Q’SV­ZeYm)IÇw8”}衇j\ÅW“ûï¿¿N㯨¨(K»r¸í‡Å?þñêÚµ«¥­üÑá¹|ðA‡Þ׎;Z½¦ƒ:<€úA@nVa6Ëtâ„Í{„\©¤Ì¬3Ü]F“·ñ`†JÊÌ5wô ;vì°jßtÓMíØ±£UàPRR¢}ûÜ’jذa–vNNŽÕÖ¡¶8pÀ*»üòËW«ùM&“òòòtêÔ)¥¤¤Xýòòò²ê{ôèÑZÍáˆ~ýúwdeUÏ’ËÊÊjˆ’œR5(:t¨ÃcÛ´i£„„„ZϤ¾}ûÖz|U*((PFFFµÏDJJŠÂÂÂ,}ýLôë×Ïj|Mn¼ñF«vÕï{üýýzO*¦ŠŠŠ,Û¶p ¶73Ÿ<)U:á2C\¬Kk ªÜÜ\¨ôƒ­Í›7¯Õ¤GV[”îÝ»W={ö¬·kcôèÑV[L.Y²Ä*4¬ªêêÁÑ£G;ÓtÉ%—è·ß~“$ýòË/JMMµÚöðœÒÒR}ýõ×–v³fÍtýõ××8GQQ‘æÌ™£>úHev~8¸&ö‚¸úP5 9«vå­=+›4i’¶nÝêÐ3?úè#õéÓÇáªÊÎζ|ìÔ둜?°²-ZÔzìš5k4cÆ ¥¤¤Ôj¼³Ÿ‰X'w¨ªÚÿ÷ßwhœ³ïÕÏTm¿GÔ[Œ€›™“’l^÷Žˆw³f®-ÀïÙñ‘üŒüµQ}ó3zkPüEzv„s«œÜ­êj¥fµø³jpp°U;''§N5Õ—ÊgVTThÙ²e6ûýðÃÊÍ͵´‡ &ÿó>»  @ãÇׂ ê|TTTÔzlMêzŸ»UÊj³ò¬êçÒµ]é¶páB=üðõ%ç?ξΪßã•?ûçÓØ?OÀ…†„àf&;¡±–ç@]øû4ýÖ•”™õ{¾cÛÝ5´£gôÔÿÖn@IzãöêÐÊý?€Ù"Ø·Q­<§jáìêA[êãõaĈš5k–%À[¶l™~øájAGÕíEo½õÖŸ=kÖ,mß¾ÝÒöòòÒUW]¥k¯½V]»vÕE]¤ÐÐPùúúZ­¤JIIÑÀëò².¾¾¾–•Œµ a]½bm÷îÝzíµ×¬®EEEiøðáêÑ£‡¢££!ùúúZ}ŸÜu×]¯Ì¬ÊÙï·ªý=åû@ý" 7³Ʋ½(÷ñó1¨MX€»Ë$µ P|ÛíKqlKeÝ¢CÕ¿S«¨êÂbծ͖—ùùùç}f}(//wzLXX˜ ¤ï¾ûN’tòäIýüóÏêׯŸ¥OJJŠ6oÞliwîܹƳî222ôÙgŸYÚ~~~úÇ?þaõ\{ª¾WÍ¢E‹\6WóæÍUXX(éìç²¼¼Ü©Ul®^É:wî\«Ïé˜1c4mÚ45ÿ5}]>Î~ÏV]5ììÖ¡Öü€›Ù  NîMÙ“7tqzÛS?£·& íÜ@]8ÂÃíÚIvþ{>‰‰‰ç}æ9ƒõ K³ÙìðŽnƒXÕèÑ£­ÚK—.µj/[¶ÌjeÕþ¶üøãVAÐøñã ¥³á"Sù Á²²²jŸ³šœ;Ò õË/¿XÚÑÑчƒ’”™™Yë¹ýž­Ú¿.ç-ð\„àFåå2?nóž1.Ö¥µ€'ë¢Wþ”àpHègôÖ+JP—¨ú_©v¡ Q»ví,í¼¼<=zÔ©gìܹӪݭ[7›ýªž•Vu%Óù9rÄ©šÎ¹úê«ei¯Y³Æ²²¬¼¼\Ë—/·ÜóõõÕM7ÝTã3«,×^{­ÃõìÚUûít/4Ý»w·joÙ²Åá±f³Y;vì¨ï’ì:yò¤Õ–¦ýû÷w8LNN®S@¸{÷n§úïٳǪmïû@ãF@nTž–.—ؼgd!Xéש•æÝ{…ºE‡ž·_·èPÍ»÷ õckÑzÓ«W/«öÊ•+{ôèQíß¿ßÒöóó³»EgÕ•JΑ?ýô“Ã}+óòòÒ-·Übi—––Z^ß¿ÿýotè6mÚdPFGG«oß¾=¯sgë³/ßÿýÏSüé§Ÿ4kÖ,'ª†···|ðA«k/¿ü²¾ùæ»c²²²tÿý÷»<ˆŽŽV`` ¥ýã?ÖxbVV–yä‘j+Rkãã?Öš5kÎÛçøñãzñÅ­®3Æn  q# 7²Ø^àa^yåùøøXÚ[·nÕí·ßnó|³¬¬,½øâ‹š1c†ÕõñãÇW Ï* ÖСC-m³Ù¬x@›6mªÖ·´´T‹/Ö˜1ctúôi‡¶þ<Ÿ[o½ÕªýÔSO©´´ÔÒ5j”¼¼¼zÖ€dioß¾]?ü°N:U­ovv¶fÍš¥ &¨´´Táááµ|¦[o½Uýúõ³´ËÊÊ4iÒ$7N+V¬ÐtìØ1mÙ²Eo¾ù¦†ªíÛ·ËËËËê³ÖÐ|}}5hÐ «:ǧ 6Tëk6›µjÕ*=Zû÷ï————Bëðƒä!!!2›ÍzüñÇõî»ÆˆXû IDAT練°°Ú|ß~û­n¿ýv«•Á111ÕXM‡c§ „½€ÐëÊ2¨Q×®]5mÚ4=ÿüó*//—tvKÇ?ýéOЉ‰ÑÅ_,???:uJ{÷î•Éd²õÕWë±Ç«qžÇ\kÖ¬±œÙöûï¿kܸqЉ‰Q§Näëë«Ó§OkÏž=– £eË–šËêÂÀÀ@½üòËzøá‡ký:.Do¾ù¦ÆoVoÚ´Éf°|΄ Ô¶m[}÷Ýw–kŽÀµõÈ#hÍš5–ÏmFF†î»ï>EEE©K—.ò÷÷WNNŽöîÝ«ÜÜ\˸x@;wîÔÖ­[k5ï“O>©7ÞxCgΜÑ[o½¥þóŸJHHPDD„Μ9£ýû÷ëôéÓVc‚ƒƒ5kÖ,«½šBp“Ò½{Uòó/6ïYAð@úÓŸÔ¼ysM:ÕjÒñãÇuüøq»ãF¥_|Ñj¢=‘‘‘š={¶~øaÔ8GÛ¶mõ¯ý«ZÀá,___1B|ðAµ{ýû÷Wdd¤SÏ»ï¾ûtâÄ «3ñÌf³öìÙcó¼ÄÐÐPÍ;W­[·v¾ø \óæÍõþûïkæÌ™Z²d‰***ìöõ÷÷׳Ï>«[o½Uÿû¿ÿku¯òªÏ†Ð®];Íž=[>ú¨Õ÷OjjªRSSmŽ7nœžxâ Ýu×]µž766VóæÍÓC=¤¼¼<ióæÍvû‡‡‡ëÝwßÕe—]Vë9x>¶+ݽ[ÃG(óúT‘“c³Oáòå*µ±E îvýõ×kÍš5;v¬ÂÂÂìöóññQ¿~ýôé§ŸêÕW_u(<çÊ+¯Ô_|¡Ú]ÕnÙF²C‡N¿[FíÔõš¼üòËzã7{ž×wÞ©o¾ùF—_~y­æÁÙoÓ§O×—_~©{ï½W;wVhh¨|}}¥Ë/¿\S¦LÑÚµk-ÛÉV=Û¯Y³f ^gÿþýµtéÒó~¶F£úõë§… êé§Ÿ®—y{÷î­•+Wê–[n±: ±²ÀÀ@3Fß}÷ºwï^/óð\^çûq "==] ¨v}Æ Nÿ4—¢Õk”õàƒRqIÍýý>ožþ8¨æ¾¸Ayy¹öíÛ§cÇŽ);;[¥¥¥ Sdd¤zõê¥ààà:Ï‘••¥mÛ¶)--MÅÅÅjÑ¢…Ú¶m«Þ½{Ëhl¤UTTèСCÚ·oŸ²²²d0¡¨¨(uïÞ½Ñ¼Ž¦æ©§žÒÊ•+-í¯¿þZ;vtÙü§OŸÖŽ;têÔ)+<<\-[¶TBBB΢œ3gŽæÎkiôÑGêÓ§¥]XX¨;v(--MYYYjÞ¼¹Ú´i£>}úÈßß¿N¯ @ãÁyÀEJwïv<”¤âe=ø Z.[*ß„„†-€ZðööÖe—]Ö [†‡‡kÈ! ö|WðòòRçÎÕ¹sgw—‚ÿWQQ¡;vXÚjß¾½KkˆˆˆpËg;00Pýû÷wù¼< [Œ€‹ä<;Íñpðœâå>÷|ÃpÚ°aƒÕ¹ñññ2 n¬\‹€\ tÏ•íÜY»±;v¨tïÞz®à”ŸŸ¯éÓ§[]9r¤›ª÷ (üô3·ŽhªvíÚ¥^xA'Ož¬±orr²ÆŽ«'NX®EDDhذa Y"xÎ (ÛÀ­ãšªÒÒR}úé§úüóÏuÅW¨_¿~êÚµ«"""äçç§ÜÜ\;vL7nÔªU«TVVf5þÕW_•¿¿¿›ª÷ (/,¨Ûø‚üzª i*//×æÍ›µyóf‡ú M™2E×\sMWž‡€\À;0¨nヂë©€¦%00P¾¾¾*--uxÌ%—\¢)S¦èꫯnÀÊÀs€ øt½T¥;vÔi<ªëÖ­›~ùåýüóÏÚ¾}»<¨ÔÔTeee©¤¤D¾¾¾jÞ¼¹.ºè"õìÙSW_}µúõë'///w—nãUQQQáî"€ Mzzº Píú† 醊ÐÐJ÷îUæõ7Ôz|Ëï¿•o·nõXàBåíîàBàÛ­›|zö¬ÝØ^½õ†€\$túK’¿Ÿsƒüýòò‹ Sà‚D@.â› ðyó ýý>ož|¶0À…€ðÿÚ»ï說üÿÿ¯JH‡„@¨¢ôÞQ)"Ž2QP”®ˆAu¾ŽGDPgº†¤|PQ‚@D Ô@€P!¤ !¿?\¹¿œ›vor É}>Öš5Ù;gŸý뺳sÞûì TñÁž ]µR^mÚyW›6 ]µRìé È®ÂÃÙ€«ñjÑB¡ÿY£Ìýû•±d©²Æêvzš*Tò“g“Æò}ú)ÎØ Bp¯fÍHŽ-FB‚p!$B‚p!$B‚p!$B‚p!$B‚p!$B‚p!$B‚p!$B‚p!$B‚p!$B‚p!$B‚p!$B‚p!$B‚p!$B‚p!ÎpEÙÙÙÖ'&&:8€µªT©"wwwg‡” BÀ ’’’ ¬ïׯŸƒ#XëÇTÕªUPbl1 ¸„€ !A¸„€ qËÉÉÉqv€«ÉÌÌÔÑ£GóÕ‡„„ÈÝÝÝ ,U¥Jžå¢L#A¸¶\ BÀ… \ BÀ… \ BÀ… \ BÀ… \ˆ‡³\Ñ™3gtøða]ºtIééé SõêÕÕªU+yzz:;<”SÙÙÙ:uê”âââtéÒ%¥¦¦ÊËËKªU«–š6m*___g‡ 8UVV–öîÝ«óçÏëÒ¥KªT©’ÂÂÂÔ¨Q#Õ¨QÃÙáÀË‘ã'siØÂµk×tìØ1:uJ×®]ÓÍ›7 àà`5mÚTµjÕrvˆÀ1ÀÄ϶®_¿®½{÷êÂ… ºråŠüýýUµjU5kÖL¡¡¡6í+..NÇŽÓÅ‹•••¥°°0Õ¬YS-Z´P… ¼ëÛ#A8І ´`ÁÅÄÄøý   =üðÃzå•WâàèP;wN›6mÒ¯¿þªÝ»w+--­ÐkÝÝÝuï½÷ê™gžÑ<`U? êÑ£G©b=räH©Ú£üøüóÏ5kÖ¬·ŒŒTTT”Um’’’4sæLýïÿSrrr×´jÕJC† ÑC=TâØÀQΜ9£ýû÷kÿþý:pà€<¨ôôtÓ÷#""´uëÖR÷ãÈñ“¹´k°×g7++K;wîÔ¶mÛ´k×.;v¬ÈëÃÂÂôÄOhàÀV?ü›8q¢V¯^muŒ¹ÆŒ£—_~¹Äíáxös4hPªØ¶lÙR¢…Œ¹îŽz¶eîÌ™3š9s¦6oÞ¬ŒŒŒûêØ±£FŽ©Ž;–¸Ÿœœ-_¾\‹-*ôÙXXX˜üq½øâ‹,î‡M¹åäää8; ¼KOO×ßþö7ý÷¿ÿµèú*Uª(**J÷ß¿#Cy6nÜ8­[·®Dm»uë¦)S¦¨J•*]O‚¶äèáöíÛ5iÒ$]¹rÅ¢ëûôé£É“'3)‡AiçUÔCDÆ[%::ZsçÎÕ MÖå²E‚ÐQã'séòÏÞŸÝ}ûöiĈºvíšÕ±èwÞÑc=fq„®ÁQc®£„Œ¹®Ã‰m[ÌUóúðÃÕ·oßB¿Ïx[þ9òÙV^«V­Òûï¿_`bМ›››ž{î9M˜0AîîîVõsùòe½ñÆúå—_,º¾V­Zš6mšš5kfU?@axƒ°³ììl;VÛ·o7Ô‡„„¨qãÆòóóÓ™3g«Ü|ýåË—5zôhÍŸ?_mÛ¶uFØ(Nž­aÆiéÒ¥ºë®»,î ( BÀÎ>ùäÃäÚÓÓS'NÔ“O>)///SýñãÇõÎ;ïÈÌÌÔK/½¤µk×*,,Ìáq£|iܸ±úõë§.]ºxžÊÅ‹5{öl-[¶ÌT¯W_}U‹-’›››Uý=ôÐCš0aB©ã$iÚ´ijÑ¢…Å×[úfÊ… ôòË/n·nÝZS¦LQ½zõLu™™™Zºt©þñ˜®Ý¶m›f̘¡×_Ýâ¸KõêÕËÙ! œñòòRxx¸NŸ>m“û9rüd.íÚlýÙ•þœ'<üðÃêÓ§Zµj•ïásNNŽ6oÞ¬>ø@çÎ3ÕGEE©~ýúºï¾û¬îsÑ¢E ·øú€€«ûÀßÛ\-Z´Ð´iÓ¬jcÍg1·ü+K‰íŠ+ªK—.ÎwG<Û:xð &MšdHöèÑCûÛßT­Z5S]ZZšæÍ›§9sæ˜ê/^¬† jÀ€ý<'N4$+Uª¤É“'ë/ù‹a1ݾ}ûôæ›oš’¥×®]Ó¨Q£´víZ’è(5„€9sFß~û­¡nÆŒêÙ³g¾kï¾ûn-X°@Ï?ÿ¼i’œœ¬Y³fiòäɉ勛››xà3¦Ø­ªV­ªÉ“'«Aƒ†ÏÛž={´~ýz=òÈ#Võíëë[¢s.€‚T©RÅ.Ÿ§™3gÞ&hÕª•,Xïí-/// KŒ¹®ÍV‰íððpmÙ²¥Dmßxã íÝ»×TîÝ»·üüü¬º 2ÊG?Ûúøã ‹àzè!͘1#ßî~~~;v¬BBBôÁ˜êg̘¡Gy¤ØÏîîÝ»µqãFSÙÓÓS .,ðglÑ¢…–,Y¢'Ÿ|ÒôßèéÓ§õÍ7ßhäÈ‘ÅþL@QHv4kÖ,Ã/•¾}û8¹Îåãã£?üP}úô1µ[¹r¥FŒ¡š5kÚ=^”/Ÿ}ö™Õ<4HÑÑцIÊ÷ßou‚¸ÓÅÇÇkÍš5¦²§§§¢¢¢ŠÜÚ±gÏžŠŒŒ4q‘™™©Y³féÃ?´{¼¸ó…„„($$ÄêvsçÎ5”;tè`Õï|d ¯ÈÈH=ýôÓvݦ֑ã'si×aïÏn‹-´yóf«Î¿ Ö´iÓiÚ®ìĉÚ¿¿š7on—8Q¶8bÌu$Æ\×aÏ͇‡G‰æ¦/^Ô¾}û uÖ,šËÅ‚ŒòǑ϶vîÜ©_ýÕTÖ{ï½WäÖøƒÖæÍ›µk×.Ink¾`Á‚bΘ1ÃP~á…ŠL€kÊ”)†ÿFçÍ›§ZHòâàÀNnܸaøE$IÇ/¶]ݺu “ð[·niíÚµ6å_I'Å4”£££mpGY·n²³³Må^½z©N:Ŷ1b„¡¼aÃݼyÓÖáÁEܸqCëׯ7Ô•äA+00Ðîª5~2—v-öþ솄„X•ÌÕ°aCµiÓÆPÇܹ1æ: c®ëˆŒŒÔž={´fÍM™2E P“&MäéééÔ¸V­Ze˜_Ô©S‡3-!ɱ϶¾ÿþ{C¹ÿþ .²››[¾ñÒü>æÎž=«ß~ûÍTöññѳÏ>[l|:t0,RJII)ñ»@.„€üüóϺ~ýº©ÜªU+Ù,EéÛ·¯¡üÃ?Ø46 (76”oܸ¡””'E؇ù¸j>î¦^½z†ó322Ê̸ólذA©©©¦r@@çâŽç¨ñ“¹4î52”/]ºä¤HûaÌuwbb;''G«V­2Ôõë×ÏIÑ ¼°öÙVvv¶¶nÝj¨³tž{ÿý÷+44ÔT>}ú´>\èõæãdÏž=hQ_Œ¹°5„€üøã†rûöí-nÛ¶m[yxüÿ;ÇÆÆêòåË6‹ (Š»»{¾º¼[Íe]bb¢a²îáá¡Ö­[[ÜÞ|<7ïK­\¹ÒPîÓ§Ï÷ÀÈË‘ã'siÜ)ò~–$æÅ(ŸsáL»ví2œ}èáá¡ÈÈH'F„òÀÚg[û÷ïWrr²©ªºuëZÔW… Ô®];C]QóÜŸ~úÉP¶fÌ5¿vÇŽ¦­Ð’ AØÉ±cÇ å–-[ZÜÖ××Wõë×/ò~€½˜JîááQì– @Yb>ž6hÐÀªmÇZµje(?~Ü&qÁµœ>}Ú°­Œôç6ÀÌ‘ã'siÜ)N:e(ç}C(/sáLß}÷¡ÜµkWÆZ”šµÏ¶ÌÇ-óykq5Ï­W¯ž‚‚‚L匌 ={Öâö€9â/P'Nœ0”k×®mUûš5k*66ÖTŽ‹‹S§NlP” 6ÊM›6-ò@æ‚>|XãÆÓtùòeݼySAAA Q³fÍÔ®];õêÕ«DgÁÀõ,[¶L_~ù¥ââ├œlšØW¯^]mÚ´Ñý÷ßoÕùæõZµjYùõ$Q+W®TNNީܤI“|ÛØwGŽŸÌ¥q'HKKÓ/¿üb¨Ë{ö¥æÌ™£¸¸89sFÉÉÉòññQ`` j×®­6mÚ¨[·nù¶B rîÜ9Mš4Iüñ‡.]º¤ëׯ+ @ÁÁÁjÔ¨‘Úµk§‡zÈððØŒ¹p–ÔÔTmÚ´ÉPǙܰkŸm9jž›––¦‹/–ª¯5jÞv<~ü¸jÖ¬iÕ=€\$;HNN6 Ô’T­Z5«îQ½zuC9>>¾´aÅJOOÏ·å]ÞCç-uèÐ!:tÈP—˜˜¨ÄÄD9rDß}÷>üðC +V¬0”³²²”ššª„„íØ±C3gÎTÇŽõÆo¨iÓ¦¥ŽåWBB‚ uW®\Ñ•+Wtüøq­]»VQQQêß¿¿^}õUUªT©Ø{2æÂ™Ö­[§7n˜Ê¡¡¡êÒ¥K‰ïÇ‚ H%{¶e¾c€ù¸VóqÓü~…Õ«bÅŠVõU½zu8p Ø¾K°Å(`©©©†rÅŠ­~0b(§¥¥•:. 8Ó¦MSbb¢©`·-ï’““5sæL 4H.\°KpÐСC5}útÃ[Y1?˜¼råÊVõU©R¥|çÄ™û@Q~úé'êQõéÓ§D÷:tèÖ­[§øøx¥¥¥)++˰ãÍ7ßT·nÝ4{ölÎÍB©9jüd.;ABB‚¾øâ CÝàÁƒåååe—þvîÜ©§žzJ‹-²Ëýá:222´páBõíÛ×¢­>sáLæÛ‹FFFæ;ûÕ+V¬ÐÞ½{•˜˜XàbŒÈÈH=÷Üs†ä ÊŸ’<Û2 Íǵâ˜Ï‹ÓÓÓ <°´óé‚bãyJƒ7;HOO7”Í„XÂÇǧÈ{¶öÃ?èßÿþ·¡îµ×^³j{ooouèÐA;vÔ=÷Ü£°°0U¬XÑ4)ŽŽÖþóÃŒûöíÓСCµtéRØìçAÙWµjUuíÚUÍ›7×]wÝ¥   ¹¹¹)99Y±±±Ú¶m›~þùgÓõ999š3gŽnß¾­qãÆzߌŒ CÙ|¼µ„nÞ¼i*3FÃæ«Y{õêe×ñ/wAÆöíÛ5sæL…‡‡Û­/”oŽ?™KÃÙ2335vìXÃç&""BÇ·ê>µk×V—.]Ô´iSÕ­[W~~~’¤¤¤$íß¿_›6mRLLŒéú¬¬,Mžú¨Å×ÞÿýZºt© `zû+;;[Ÿ~ú©a® ×õâ‹/Zt···Æ§ððpMž<ÙTðàA­[·ÎâíÌsá™™™úÏþc¨+É™Ü,È@.[<ÛÊËÚ6%?álœAØùÊÒ¼.[ʼµg–¸r劆 b8 +44Tÿú׿¬ÞoÝZ&LP£F uK–,±kŸ(Ÿ‚‚‚4mÚ4ÃÄúĉŠŽŽ.ðzóñ4ïVw–2oà K­ZµÊPîׯŸUæ.È(,9˜W¡C‡êsdÖrÔøÉ\β`Á}ùå—†º!C†X½µ¨µjÖ¬©÷Þ{ÏP·cÇ:uÊ®ý¢|4hºwïn¨[¼xq¡×3æÂ¶lÙ¢äädSÙßß_½{÷¶ú>>úh¡ÉAs¹ 2ò¾›» e›-žm•v,,èz{Ísy["AØA¥J• å’<7.l.§yóæ 4•³³³uüøñ¯eÌ…£?^¿üò‹¡®ÿþëŸå‡-Ÿm•vž›»Mx.???U¨?õRÚ~ jÃó” BÀ‚ƒƒ “qéÏ 5Ξ=k(;â.¸†´´4 >\4Õùùùé믿Î÷†‰½æ›]½zÕ¡1 ü¨Q£†¡\ØDÛüàûsçÎYÕùõAAAùÆ|À\FF†Ö¯_o¨{â‰'Ö? 2` Ž?™KÑþûßÿê­·ÞÒíÛ·Mu}úôÑÔ©S~.PDD„¡\’‡†€$U¨PAÕªU3ÔöybÌ…£­ZµÊ0æ6lØPM›6uh ,È(ûlýlËÖó\óûå2“’’týúu«ú2s ë ° BÀNÌW#Y»]ABB‚¡\¯^½RÇdddhäÈ‘úý÷ßMu¾¾¾š7ožš7o̷)Éve€$y{{Ê…}–ÌÇÓÓ§O[ÕÏ™3gмP 6(==ÝT®R¥Šxà‡õÏ‚ Ø‚#ÇOæÒp„7j„ ÊÎÎ6ÕõîÝ[}ôQ«þíy1lÉüóTÔ6vŒ¹p”œœœ|gr;rÑ\.d”möx¶å¨y®ŸŸŸÂÂÂJÕc.l‰!`'õë×7”óþÒ*NFFF¾ÕKŽÜöåÓ74jÔ(íÙ³ÇTW±bEÍ;W­[·vJL999†ƒÉ¥?W°%ažì(ì³d>ž9rĪ{{÷î-ò~@AÌ·}ì±ÇäáááÐxðŒÒräøÉ\ö¶eË7N·nÝ2ÕõìÙSŸ~ú©ÜÝÝ“¥sÀÖ|žsá(;wî4$7¼¼¼Ô§O‡ÇÁ¼¸ì²×³-óq+&&ƪöŽšçÆÅÅž£U¬X1ßnJ€5Hvb~Ö®]»,n»{÷nê7V•*Ul\ÏÍ›7õâ‹/>‡ÞÞÞúòË/Õ®];§Å«¬¬,S¹B… |ÖQbüñ‡¡l¾*/o}ƒ Lå[·nþ¸(ŽùxÞ¥K+¢„+:yòd¾Ï˜£WJ³ ¶àÈñ“¹4ìiûöízõÕW óÐx@Ó§Owøâ¼öíÛg(6—Š“”””ïm–¢>OŒ¹póEs½zõRPPÃã`AFÙdÏg[Íš53|uòäI‹ÚÞ¾}[»wï6ÔÙkžk~mçβëÊ>=€tîÜÙ°")&&Fqqqµ]½zµ¡Ü³gO›Æ×’™™©1cÆ÷òòÒìÙ³Õ©S''F&­[·ÎPnÒ¤‰*Uªä¤hP–ݼyS›6m2Ôµoß¾Ðë|ðACÙ|››ÂÄÅÅÞùúúæ;¿0·råJC¹M›6ù¶ò²7dÀV5~2—†½ìرC/¿ü²aLìܹ³>ÿüsyyy9-®+W®hçΆº:8)”uëׯ7œñV¥J•"· cÌ…#¤¤¤è‡~0Ô9c{Q‰e‘½Ÿmyxx¨[·n†:Kç¹?ÿü³á|÷Zµj©aÆ…^o>NnÞ¼Y)))õŘ [#AØIÅŠõÐCê¾þúëbÛùäÖ½~~~E.v sùòe}ùå—†ºnݺÉÍÍ­Ð6Œ¹p„µk×ÆßˆˆuìØÑáq° £ìqÔ³­Ç{ÌP^±b…Eç¶›—æ÷1W£F µmÛÖT¾qㆾùæ›bûÙµk—!¹Às4” BÀŽ^~ùeyzzšÊ«V­Ò–-[ ½þæÍ›š4i’a5k¿~ýT«V-»Æ‰ò);;[ãÇ7|æ<<<4}úô|«¢Jcß¾}ù¶R(ÎÉ“'5räHÃ>ÿAAAzæ™glʦ5kÖèòåËVµY¾|¹fÍše¨‹ŒŒÌwð|^uêÔÑã?n*geeiâĉ†?XÍmÞ¼Ù°‚ÐÓÓScÆŒ±*V¸žíÛ·+11ÑT®T©’z÷îíÐX[räøÉ\¶£Q£FæŸíÚµÓœ9sòEUË–-SjjªÅ×çääè³Ï>Ë÷–°aÃT±bE›Å…²çĉÚºu«Um5jÔ(Ã|ÚÓÓS£F*¶-c.ìÍ|W~ýú™¸¶d”-Žz¶%I:u2$­¯^½ªwß}×ðF¶¹o¾ùFÑÑѦrpp°žþùbû;v¬¡½Ø±³I“&Z½zµé¡ö… ­V­Z)$$Ät]ff¦/^¬¿ýío†? FŒ‘o¥5`îã?6œ]YâÏ;}û” êÕ«[ÜæäÉ“1b„’’’LuAAAúä“Oxûµœºpá‚’““óý.?yò¤6nÜhºÎ××W>ø`¿÷oݺUdbÂQã'si×bÏÏnll¬†ªôôtS]ݺu¥[·nY5/¾yóf‘Ÿ©W^yEóæÍÓ¹sçäã㣰°0Ãg5WNNŽ¢££õÖ[oå{Ó¼~ýúúàƒ áÎaÏÏíÑ£G5|øpmÚ´Iéééª\¹r¡gµ¥¥¥iùòå?~|¾·ºÇŒcÑtŒ¹8{ö¬aû€€=÷Üs6¹÷¡C‡ôù矛Ê*TPTTT©’Ë–-SíÚµ-žÓæäähæÌ™ùÞÔzñÅuï½÷–8Ø—£žmåª_¿¾V­Zeš»ÆÅÅéÈ‘#jݺµáóš––¦/¾øBÓ§O7´ë­·Ôºuëb®êÕ«ëØ±c¦íœoß¾­õë׫Fºûî» Éó}ûöé…^ЩS§LuµjÕRTTs”š[NNN޳ƒÊ³ììl½ð †×à%©råÊjܸ±*Uª¤3gÎ(66VyÿsôôôÔ‚ ¯œÖhРÍîõÍ7ߺåƪU«4iÒ$C]HHˆî¾ûnªbÅŠJKKSBB‚Ž;¦‚~í¼þúë­jEù÷ì³ÏÝ®P¡‚j×®­ˆˆùûûËÝÝ]ÉÉÉ:|øpoéÛo¿Uýúõ-ê/::ZÆ 3¬|vssS“&MT³fM¥¦¦*66Ö\‘þܦiöìÙ>ðr]¾|Y]»vÕ­[·Lu+V¬PóæÍKt¿Üñ¶U«VêÓ§ºwï®jÕªxmRR’–-[¦yóæˆKÒG}dx åK÷îÝuöìÙRÝ#22RQQQE^ã¨ñ“¹´ë°çg÷óÏ?Ï·Û@Iµoß^ß~ûm¡ß7ÿ9<<½þúë¦rÕªUóíB‘Ë×××°(¨8ï¿ÿ¾þýï›Ê]ºtѼyó¬ˆ:¿îÝ»+55U<òˆz÷î­Ö­[¸]tٳgþÖ”þL-_¾œ7¶ï`Žz¶•×þó½ñƆ:5kÖLÕªUÓÕ«Wµÿ~¥¥¥®yúé§eÍ»X4hbcc õÕªUSÆ åé驸øx=zÔðýÀÀ@-]ºÔáçÚ£|*:e ÔÜÝÝ5cÆ ½óÎ;Z¿~½©þÊ•+úé§Ÿ lS¹reEEE1¹F™•”””oâ]M™2…­îP¨Û·oëäÉ“†7° Ó©S'EEE)<<ÜâûwèÐA³gÏÖĉM±srrtàÀ8p À6>ú¨Þÿ}’ƒ(Öš5k _êׯ_âä`^111Љ‰ÑäÉ“K´ ƒä lÁQã'si”u·nÝÒÑ£Gó=Ü+È_þòýýïW`` "CY”ššª½{÷{¯¯¯&Mš¤'Ÿ|Òªû3溆Z”ؾxñb¡«[²˜(Wfff¾7Àlu&wJJŠ–,Y¢%K–”hAÆ×_Mrùüõ¯UVV–¦L™¢ŒŒ Iþ>Ïý;Ìœ›››ž}öYMœ8Ѫ~|}}5wî\½ñÆúõ×_MõçÏŸ×ùóç lS«V-}úé§$a3$¨T©’¦OŸ®‡zHóçÏ×ï¿ÿ^àuAAAzøá‡õÊ+¯Xµ p¦6mÚhÈ!úí·ßtäÈÛqssSƒ Ô¿=þøãòóósP¤( ¬°°0ÅÄÄXôG«¯¯¯î»ï> 4H:u*QŸ]»vÕºuë4sæLýïÿ+ðGIjÙ²¥†ʶ¢°XAç¬Ø 2àLŽ?™K£,=z´¶oß®˜˜Ã´…ñ÷÷W=4hÐ ›,"AùQ¯^=½ð ڵk—bcc çg¦N:êÛ·¯ú÷ï_âq1¶öÃ?(99ÙT Q÷îÝmÞ 2`KýúõSûöíõÙgŸiË–-¦Da^*TPÇŽ5jÔ(ÃÙ…Ö ÕüùóµlÙ2-Z´¨ÐÏohh¨üq=Z¾¾¾%ê ([ŒN»%Ç¥K—týúuU©REÕ«W/t; ¬ÈÊÊÒ‰'” K—.)--M™™™òõõU@@€ªU«¦fÍšqˆ2,’’’¢cÇŽéÂ… º|ù²nܸ¡Û·o+ @ªW¯ž4h`Ó7ù233µwï^;wN—/_VÅŠUµjU5jÔH5kÖ´Y?(ÿöìÙ£šÊžžžúñÇKõíÔ©SZ²d 2pGräøÉ\eÅ•+W§ .())I7nÜ›››üýý¤úõë«^½z†s†€‚ܾ}[ñññ:sæŒ.^¼h:ÓÇÇG S³fÍì’¨cÌ-µy®!C†è—_~1”­}Óª ß}÷ 2àÚ³gé÷¹¿¿¿ÂÂÂÔ¼ys………Ù´¯ãÇëèÑ£ºté’²²²¦š5kªeË–ªP¡‚Mû$„@™Ã‚ àO,È€’!A¸ÞK\ BÀ… \ BÀ… \ BÀ… \ BÀ… \ BÀ… \ BÀ… \ BÀ… \ BÀ… \ BÀ… \ BÀ… \ BÀ… \ BÀ… ?~¼4h`úß… œ’Kùõ×_MÿömÛ¶URR’CûOIIQ‡L1lݺաý€‡³gJHHP=ìÞOdd¤¢¢¢ìÞŠ–™™©÷Þ{ÏT5j”BBBC@@€^|ñE}øá‡’¤©S§êÞ{ï•Cãàºxƒà2.\¨“'OJ’ÂÂÂôÜsÏ9%ŽAƒ)""BÒŸI꯿þÚ)qpM$.áÚµkš;w®©ùÄêv(¹´´4-^¼ØTîÛ·¯*V¬èĈ$///=ñÄš3gŽ$iùòå=z´€ò-FåÞ²eË”––f*;ûíÁ\O>ù¤*TøóOóŒŒ -Y²ÄÉp$åÞÒ¥KM_·hÑBuêÔq^0yDDD¨uëÖ¦ò²eË”““ãĈ¸¶€2,''GûöíÓ©S§téÒ%U¨PAµk×V»víŠÝª2##C{öìÑÉ“'•žž®ÀÀ@Õ­[WmÛ¶•§§g©cKKKSLLŒ.^¼¨¤¤$yzz*88Xwß}·š4i"77·R÷a‰Ý»wëôéÓ¦rïÞ½K|¯S§Néðáúté’ÒÓÓåææ&…††ªFºçž{¬Þºôá‡ÖîÝ»%IçÎÓÎ;Õ©S§ÇÅ!A6~üx­]»ÖTÞ¾}»ÂÃà ¼ö—_~Ñ!CLåW_}U£GVff¦æÏŸ¯eË–éìÙ³ùÚy{{kÀ€;v¬|}} ßKJJÒgŸ}¦ï¿ÿ^ׯ_Ï×6((HcƌѠAƒLÛ_Zcûöíúú믣¬¬¬¯ Qÿþý5|øpX݇5Ö­[g(wëÖͪö™™™Z¸p¡V¬X¡S§Ny­‡‡‡6l¨ž={jÈ!òññ)öþÝ»w×ûï¿o*¯]»–!»"AeLRR’FŽ©ýû÷zÍÍ›7õÍ7ßhÏž=úæ›oäçç'IÚ¿¿^|ñE%&&Ú699YS¦LQll¬¦Njq’ðÊ•+;v¬¢££-ú¾úê+-_¾\³gÏV›6m,ê£$~üñGÓ×aaaª[·®ÅmÏž=«aÆéäÉ“]ëÖ-8p@PŸ>}T£FbÛT¯^]5kÖÔ™3gLñæää8ì K®‡!”!™™™1b„8 IòññQóæÍªëׯkÿþý†äßÁƒõÖ[oiæÌ™Š‹‹Ó!C”šš*I VÓ¦M¨äädíÝ»W¦¶«V­R“&MôÌ3Ï×É“'5lذ|o3úùù©qãÆªR¥Š²³³• C‡éöíÛ’¤«W¯êùçŸ×W_}¥{ï½·Ôÿ>æâââ 1µmÛÖâ¶™™™>|x¾ä`PPêׯ¯Ê•+ËÃÃCéééºté’Nœ8aø÷³F»víL ÂÄÄD:tH7.ѽ 8$  Y¼x±®]»&ooo½úê«4haËÛ·okÉ’%š:uª²³³%I7nÔÎ;5uêT¥¦¦ªzõêš4i’zöìix;0==]QQQZ¾|¹©núôéêÛ·o¾mJóJOO×K/½dHÄÕ«WOcÇŽU÷îÝåîîn¸þâÅ‹úì³Ï´råJI&âÆ¯5kÖ(,,¬tÿ@f~ÿýwC¹Q£F·]±b…Nœ8a*׬YSÿïÿý?uîܹÀ·*srr´ÿ~ýßÿýŸ¾ûî;«âlذ¡¡C‚€ÝX˜Ài®]»&OOOýóŸÿÔ°aÃòqW¡B 4H¯¼òŠ¡þ•W^ÑÑ£GU«V--[¶L½zõÊ—äªT©’Þÿ}uîÜÙT—––¦7ÓG}¤¸¸8S¹[·nZµj•|ðÁ|ÉAIªZµª>øà?ÞTwåÊ}þùçÅÿX)÷MË\õë×·¸í–-[L_{zzjþüùêÒ¥K¡[®º¹¹©yóæzå•W´uëÖBÏ•,Hƒ 墶€Ò"AeÌK/½¤víÚyÍàÁƒU±bESùÚµk’¤?þ¸Ø·ô†n(ÿú믅^{þüy­ZµÊT®U«–f̘‘/qY#F’‘k֬ѕ+WŠmg óíA«W¯nqÛ¼oD6nÜX5kÖ´¸­‡‡‡<<,ß´'""ÂPŽ·¸-X‹!”!¾¾¾zöÙg-º®eË–†ºöíÛç«+H»víäååe*:t¨Ðk—,Y¢¬¬,Sy̘1%s 2Äôuff¦~þùg‹ÛZÂüLDkÞêËËÖ‰KsU«V•›››©œ`×þ¸6„P†´nÝZ~~~][»vmCùþûï·¨‡‡‡jÔ¨a*•Û±c‡ékOOOõêÕË¢>rµk×ΰeçž={¬j_œ¼±»¹¹) Àâ¶wÝu—éë„„-\¸Ð¦±ååååeH¬^½zÕn}€åûœ®^½z_ëïïo“¶iii^“‘‘ax»°Zµj%zÓÎÏÏO)))’¤Ó§O[ݾ(7nÜ0}ííímUÛ>}úhëÖ­¦ò| M›6)22R]»vUhh¨Íâ”$]¿~]’tëÖ-effÞä[!Aeˆ5oÀ¹»»Û¤í­[· ¼&11QÙÙÙ¦òéÓ§Õ£G‹û(HîY‰¶““cˆÏüߣ8?ü°Ö®]kHîÞ½[»wï–$Õ©SG­ZµRëÖ­Õ¦M«°1?³0++‹!» AeHÞí8­•÷Œ;[HNN¶éý$)==Ýf÷rss“···nÞ¼)I¦ÿ·¦ýÌ™35sæL-\¸0_ûøøxÅÇÇkõêÕ’þLþõ¯Õ3Ï<£ÀÀ@«ãÍû¶£$U¬XÑê{€%8ƒP"YYY6¿gNNŽMï—÷¼ÆÜm;­áéé©qãÆiË–-zã7Ô¦Myzzxm||¼fΜ©ž={jÆ VÇš7Aèëë[ªd0…7%l(wíÚUsçÎuR4 7œ‹˜˜˜¨ˆˆ«ïªáÇkøðáºyó¦<¨˜˜ýöÛoŠŽŽVFF†éÚ””;V^^^êÞ½»E÷OJJ2$\«U«fuŒ`)–#J¤råʆr||¼s)BÍš5 å .”úžÞÞÞjݺµ† ¦9sæ(::ZÓ¦MSíÚµM×ܾ}[S¦L±øÈ‹/Ê5jÔ(uœP„€ RݺuMåS§NéÌ™3NŒ(¿† Ê'Nœ°y^^^zä‘G´|ùr…††šêÏž=«C‡Yt¸¸8C¹Q£F6ò"A(±Î;Ê+V¬pR$kÖ¬™¡|äÈ»õ¤ž={ê,jk—yÜ`K$%öôÓOËÝÝÝT^¸pa¾·áœ©eË–òôô4•ÿøã»öçááa({yyYÔ.o\îîîjÛ¶­M〼HJ¬^½zzì±ÇLå7nhĈV' oÞ¼©Õ«WÛ:<ùùù©M›6¦òÁƒ•––Vl»´´4-Z´Hééé÷•––¦Í›7êêÕ«Wl»ÌÌLýþûï¦r‹-dq¿`-„€Ryûí·U¿~}SùìÙ³êׯŸf̘¡ .ÚîÆÚ±c‡&Ož¬®]»êí·ß¶K|>ø éë[·n)::ºØ6™™™¦¸Þzë-mÛ¶­ÈÄâï¿ÿ®çž{NçÏŸ7ÕµiÓF5kÖ,¶¯={öèÆ¦²ù6¥`kÅ_@áüüü4gÎ :Tñññ’¤ëׯëË/¿Ô—_~©Zµj©nݺò÷÷×­[·”––¦„„>}Z·oß6Ý'ïV¥¶ô—¿üEQQQÊÊÊ’$mÚ´I=zô°¨mjjªV®\©•+WÊÍÍMµk×V5(777]»vMGÕÅ‹ í|}}5yòd‹úظq£ékwwwõéÓÇŸ J†! Ô"""´råJ½ûî»Z·ná{§OŸÖéÓ§‹½G@@€]b Q÷îÝM‰¸­[·*33Óâósåää(>>Þ”-LµjÕ4kÖ,Ý}÷ÝÅÞ3;;[?üðƒ©Ü¥K………YX‹-F6áçç§O?ýTk֬ѣ>jQ¯jÕªúë_ÿªÏ?ÿ\?þø£Ýb{î¹çL_§¤¤ÞÚ+Hpp°¾ýö[ 6LMš4‘‡GñëkëÕ«§qãÆiÆ jÚ´©EqmÛ¶M—/_.0N°·œœœg(nß¾­Ã‡+..N×®]SJJм½½åçç§5jè®»îRµjÕÏSO=¥˜˜IRÛ¶mµhÑ"‹Û^¿~]ÇŽÓ™3gtùòeeddÈÝÝ]•*URµjÕÔ AEDDXÓðáÃõÓO?I’7n¬·ÄûÕ:IDATÕ«W[}° B€KøùçŸ5lØ0Sù»ï¾S³fÍœϱcÇÔ§OåþYþÅ_X|6"”[Œ\BçÎÕ±cGSù«¯¾rb4Òœ9sLÉÁV­Z‘à0$.ãÍ7ß”»»»$ióæÍŠuJÇ×ÿþ÷?I’›››&Nœè”8¸&„—Ѹqc 8P’”““£>úÈ)qüãÿPvv¶$é‰'žPË–-×äáìp¤×^{MAAA¦í=“’’â°þSRRÔ¼ysÓù‡Ï<óŒÃúIrËÉý‹@¹Ç£€ !A¸„€ !A¸„€ !A¸„€ !A¸„€ !A¸„€ !A¸„€ !A¸„€ !A¸„€ !A¸„€ !A¸„€ !A¸„€ !A¸„€ !A¸„€ !A¸„€ !A¸„€ !A¸„€ !A¸„€ !A¸„€ !A¸„€ !A¸ÿrø5ÚôëpFIEND®B`‚leidenalg-0.8.9/doc/source/implement.rst000066400000000000000000000074071420514302700202530ustar00rootroot00000000000000Implementation ============== If you have a cool new idea for a better method, and you want to optimise it, you can easily plug it in the current tool. This section explains how the package is setup internally, and how you can extend it. Most of this concerns ``C++``, and ``python`` only comes in when exposing the resulting classes. Method ------ All methods in the end derive from :class:`MutableVertexPartition`, which implements almost all necessary details, such as moving actual nodes while maintaining the internal administration. Similarly, it provides all the necessary functionality for initialising a partition. Additionally, there are two abstract classes that derive from this base class: :class:`ResolutionParameterVertexPartition` and :class:`LinearResolutionParameterVertexPartition` (which in turn derives from the former class). If you want a method with a resolution parameter, you should derive from one of these two classes, otherwise, simply from the base class :class:`MutableVertexPartition`. There are two functions that you need to implement yourself: :func:`diff_move` and :func:`quality`. Note that they should always be consistent, so that we can double check the internal consistency. You should also ensure that the diff_move function can be correctly used on any aggregate graph (i.e. moving a node in the aggregate graph indeed corresponds to moving a set of nodes in the individual graph). That's it. In principle, you could now use and test the method in ``C++``. Python ------ Exposing the method to ``python`` takes a bit more effort. There are various places in which you need to change/add things. In the following, we assume you created a new class called ``CoolVertexPartition``. In order of dependencies, it goes as follows: 1. Your own new VertexPartition class should add some specific methods. In particular, you need to ensure you create a method .. code-block:: c++ CoolVertexPartition* CoolVertexPartition::create(Graph* graph) { return new CoolVertexPartition(graph); } and .. code-block:: c++ CoolVertexPartition* CoolVertexPartition::create(Graph* graph, vector const& membership) { return new CoolVertexPartition(graph, membership); } These methods ensure that based on a current partition, we can create a new partition (without knowing its type). 2. In ``python_partition_interface.cpp`` some methods need to be added. In particular .. code-block:: c++ PyObject* _new_CoolVertexPartition(PyObject *self, PyObject *args, PyObject *keywds) You should be able to simply copy an existing method, and adapt it to your own needs. 3. These methods need to be exposed in ``pynterface.h``. In particular, you need to add the method you created in step (2) to ``leiden_funcs[]``. Again, you should be able to simply copy an existing line. 4. You can then finally create the Python class in ``VertexPartition.py``. The base class derives from the :class:`VertexClustering` from :mod:`igraph`, so that it is compatible with all operations in :mod:`igraph`. You should add the method as follows:: class CoolVertexPartition(MutableVertexPartition): def __init__(self, ... ): ... Again, you should be able to copy the outline for another class and adapt it to your own needs. Don't forget to change to ``docstring`` to update the documentation so that everybody knows how your new cool method works. 5. Expose your newly created ``python`` class directly in ``__init__.py`` by importing it:: from .VertexPartition import CoolVertexPartition That's it! You're done and should now be able to find communities using your new :class:`CoolVertexPartition`: >>> la.find_partition(G, la.CoolVertexPartition); # doctest: +SKIP leidenalg-0.8.9/doc/source/index.rst000066400000000000000000000006711420514302700173640ustar00rootroot00000000000000.. la documentation master file, created by sphinx-quickstart on Fri Oct 21 11:26:44 2016. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. leidenalg documentation ===================== .. toctree:: :maxdepth: 2 install intro advanced multiplex implement Reference ========= .. toctree:: :maxdepth: 2 reference * :ref:`genindex` * :ref:`search` leidenalg-0.8.9/doc/source/install.rst000066400000000000000000000033201420514302700177150ustar00rootroot00000000000000Installation ============ In short: ``pip install leidenalg``. Alternatively, use `Anaconda `_ and get the conda packages from the `conda-forge channel `_, which supports both Unix, Mac OS and Windows. For Unix like systems it is possible to install from source. For Windows this is overly complicated, and you are recommended to use the binary wheels. There are two things that are needed by this package: the igraph ``C`` core library and the python-igraph python package. For both, please see http://igraph.org. Make sure you have all necessary tools for compilation. In Ubuntu this can be installed using ``sudo apt-get install build-essential``, please refer to the documentation for your specific system. Make sure that not only ``gcc`` is installed, but also ``g++``, as the ``leidenalg`` package is programmed in ``C++``. You can check if all went well by running a variety of tests using ``python setup.py test``. There are basically two installation modes, similar to the python-igraph package itself (from which most of the ``setup.py`` comes). 1. No ``C`` core library is installed yet. The ``C`` core library of igraph that is provided within the ``leidenalg`` package is compiled. 2. A ``C`` core library is already installed. In this case, you may link dynamically to the already installed version by specifying ``--no-pkg-config``. This is probably also the version that is used by the igraph package, but you may want to double check this. In case the ``python-igraph`` package is already installed before, make sure that both use the **same versions** (at least the same minor version, which should be API compatible).leidenalg-0.8.9/doc/source/intro.rst000066400000000000000000000113011420514302700174000ustar00rootroot00000000000000Introduction ============ The :mod:`leidenalg` package facilitates community detection of networks and builds on the package :mod:`igraph`. We abbreviate the :mod:`leidenalg` package as ``la`` and the ``igraph`` package as ``ig`` in all ``Python`` code throughout this documentation. Although the options in the :mod:`leidenalg` community detection package are extensive, most people are presumably simply interested in detecting communities with a robust method that works well. This introduction explains how to do that. For those without patience (and some prior experience), if you simply want to detect communities given a graph ``G`` using modularity, you simply use .. testsetup:: G = ig.Graph.Erdos_Renyi(100, p=5./100); >>> partition = la.find_partition(G, la.ModularityVertexPartition); That's it. The result ``partition`` is in this case a :class:`~leidenalg.ModularityVertexPartition` which is derived from the :mod:`igraph` type :class:`ig.VertexClustering`, see the `documentation `_ for more details. Why then should you use this package rather than for example the Louvain algorithm :func:`community_multilevel` built into :mod:`igraph`? If you want to use modularity, and you work with a simple undirected, unweighted graph, then indeed you may use the built-in method. For anything else, the functionality is not built-in and this package is for you. Moreover, the Leiden algorithm is typically faster than the Louvain algorithm and returns partitions of a higher quality. For those less familiar with :mod:`igraph`, let us work out an example more fully. First, we need to import the relevant packages: >>> import igraph as ig >>> import leidenalg as la Let us then look at one of the most famous examples of network science: the Zachary karate club (it even has a prize named after it): >>> G = ig.Graph.Famous('Zachary') Now detecting communities with modularity is straightforward, as demonstrated earlier: >>> partition = la.find_partition(G, la.ModularityVertexPartition) You can simply plot the results as follows: >>> ig.plot(partition) # doctest: +SKIP .. image:: figures/karate_modularity.png In this case, the algorithm actually finds the optimal partition (for small graphs like these you can check this using :func:`~ig.Graph.community_optimal_modularity` in the :mod:`igraph` package), but this is generally not the case (although the algorithm should do well). Although this is the optimal partition, it does not correspond to the split in two factions that was observed for this particular network. We can uncover that split in two using a different method, :class:`~leidenalg.CPMVertexPartition`: >>> partition = la.find_partition(G, la.CPMVertexPartition, ... resolution_parameter = 0.05); >>> ig.plot(partition) # doctest: +SKIP .. image:: figures/karate_CPM.png Note that any additional ``**kwargs`` passed to :func:`~leidenalg.find_partition` is passed on to the constructor of the given ``partition_type``. In this case, we can pass the ``resolution_parameter``, but we could also pass ``weights`` or ``node_sizes``. This is the real benefit of using this package: it provides implementations for six different methods (see :ref:`Reference`), and works also on directed and weighted graphs. In addition, it also provides flexible functionality for customizing to some extent the optimisation routines (see :ref:`Advanced`). Finally, it also allows to work with more complex multiplex graphs (see :ref:`Multiplex`). The Leiden algorithm [1] extends the Louvain algorithm [2], which is widely seen as one of the best algorithms for detecting communities. However, the Louvain algorithm can lead to arbitrarily badly connected communities, whereas the Leiden algorithm guarantees communities are well-connected. In fact, it converges towards a partition in which all subsets of all communities are locally optimally assigned. Finally, the Leiden algorithm is also much faster, because it relies on a fast local move routine. The `"canonical" `_ Leiden algorithm is implemented in ``Java`` and is faster than this implementation, but less extensive. References ---------- .. [1] Traag, V.A., Waltman. L., Van Eck, N.-J. (2018). From Louvain to Leiden: guaranteeing well-connected communities. `arXiv:1810.08473 `_ .. [2] Blondel, V. D., Guillaume, J.-L., Lambiotte, R., & Lefebvre, E. (2008). Fast unfolding of communities in large networks. Journal of Statistical Mechanics: Theory and Experiment, 10008(10), 6. `10.1088/1742-5468/2008/10/P10008 `_ leidenalg-0.8.9/doc/source/multiplex.rst000066400000000000000000000450441420514302700203030ustar00rootroot00000000000000Multiplex ========= The implementation of multiplex community detection builds on ideas in [1]_. The most basic form simply considers two or more graphs which are defined on the same vertex set, but which have differing edge sets. In this context, each node is identified with a single community, and cannot have different communities for different graphs. We call this *layers* of graphs in this context. This format is actually more flexible than it looks, but you have to construct the layer graphs in a smart way. Instead of having layers of graphs which are always identified on the same vertex set, you could define *slices* of graphs which do not necessarily have the same vertex set. Using slices we would like to assign a node to a community for each slice, so that the community for a node can be different for different slices, rather than always being the same for all layers. We can translate *slices* into *layers* but it is not an easy transformation to grasp fully. But by doing so, we can again rely on the same machinery we developed for dealing with layers. Throughout the remained of this section, we assume an optimiser has been created: >>> optimiser = la.Optimiser() Layer multiplex --------------- If we have two graphs which are identified on exactly the same vertex set, we say we have two *layers*. For example, suppose graph ``G_telephone`` contains the communication between friends over the telephone and that the graph ``G_email`` contains the communication between friends via mail. The exact same vertex set then means that ``G_telephone.vs[i]`` is identical to the node ``G_email.vs[i]``. For each layer we can separately specify the type of partition that we look for. In principle they could be different for each layer, but for now we will assume the type of partition is the same for all layers. The quality of all partitions combined is simply the sum of the individual qualities for the various partitions, weighted by the ``layer_weight``. If we denote by :math:`q_k` the quality of layer :math:`k` and the weight by :math:`w_k`, the overall quality is then .. math:: q = \sum_k w_k q_k. The optimisation algorithm is no different from the standard algorithm. We simply calculate the overall difference of moving a node to another community as the sum of the individual differences in all partitions. The rest (aggregating and repeating on the aggregate partition) simple proceeds as usual. The most straightforward way to use this is then to use :func:`~leidenalg.find_partition_multiplex`: .. testsetup:: G_telephone = ig.Graph.Erdos_Renyi(100, 0.1); G_email = ig.Graph.Erdos_Renyi(100, 0.1); >>> membership, improv = la.find_partition_multiplex( ... [G_telephone, G_email], ... la.ModularityVertexPartition); .. note:: You may need to carefully reflect how you want to weigh the importance of an individual layer. Since the :class:`~leidenalg.ModularityVertexPartition` is normalised by the number of links, you essentially weigh layers the same, independent of the number of links. This may be undesirable, in which case it may be better to use :class:`RBConfigurationVertexPartition`, which is unnormalised. Alternatively, you may specify different ``layer_weights``. Similar to the simpler function :func:`~leidenalg.find_partition`, it is a simple helper function. The function returns a membership vector, because the membership for all layers is identical. You can also control the partitions and optimisation in more detail. Perhaps it is better to use :class:`~leidenalg.CPMVertexPartition` with different resolution parameter for example for different layers of the graph. For example, using email creates a more connected structure because multiple people can be involved in a single mail, which may require a higher resolution parameter for the email graph. >>> part_telephone = la.CPMVertexPartition( ... G_telephone, resolution_parameter=0.01); >>> part_email = la.CPMVertexPartition( ... G_email, resolution_parameter=0.3); >>> diff = optimiser.optimise_partition_multiplex( ... [part_telephone, part_email]); Note that ``part_telephone`` and ``part_email`` contain exactly the same partition, in the sense that ``part_telephone.membership == part_email.membership``. The underlying graph is of course different, and hence the individual quality will also be different. Some layers may have a more important role in the partition and this can be indicated by the ``layer_weight``. Using half the weight for the email layer for example would be possible as follows: >>> diff = optimiser.optimise_partition_multiplex( ... [part_telephone, part_email], ... layer_weights=[1,0.5]); Negative links ^^^^^^^^^^^^^^ The layer weights are especially useful when negative links are present, representing for example conflict or animosity. Most methods (except CPM) only accept positive weights. In order to deal with graphs that do have negative links, a solution is to separate the graph into two layers: one layer with positive links, the other with only negative links [2]_. In general, we would like to have relatively many positive links within communities, while for negative links the opposite holds: we want many negative links between communities. We can easily do this within the multiplex layer framework by passing in a negative layer weight. For example, suppose we have a graph ``G`` with possibly negative weights. We can then separate it into a positive and negative graph as follows: .. testsetup:: import numpy as np G = ig.Graph.Erdos_Renyi(100, 0.1) G.es['weight'] = np.random.randn(G.ecount()); >>> G_pos = G.subgraph_edges(G.es.select(weight_gt = 0), delete_vertices=False); >>> G_neg = G.subgraph_edges(G.es.select(weight_lt = 0), delete_vertices=False); >>> G_neg.es['weight'] = [-w for w in G_neg.es['weight']]; We can then simply detect communities using; >>> part_pos = la.ModularityVertexPartition(G_pos, weights='weight'); >>> part_neg = la.ModularityVertexPartition(G_neg, weights='weight'); >>> diff = optimiser.optimise_partition_multiplex( ... [part_pos, part_neg], ... layer_weights=[1,-1]); Bipartite ^^^^^^^^^ For some methods it may be possible to to community detection in bipartite networks. Bipartite networks are special in the sense that they have only links between the two different classes, and no links within a class are allowed. For example, there might be products and customers, and there is a link between :math:`i` and :math:`j` if a product :math:`i` is bought by a customer :math:`j`. In this case, there are no links among products, nor among customers. One possible approach is simply project this bipartite network into the one or the other class and then detect communities. But then the correspondence between the communities in the two different projections is lost. Detecting communities in the bipartite network can therefore be useful. Setting this up requires a bit of a creative approach, which is why it is also explicitly explained here. We will explain it for the CPM method, and then show how this works the same for some related measures. In the case of CPM you would like to be able to set three different resolution parameters: one for within each class :math:`\gamma_0, \gamma_1`, and one for the links between classes, :math:`\gamma_{01}`. Then the formulation would be .. math:: Q = \sum_{ij} [A_{ij} - (\gamma_0\delta(s_i,0) + \gamma_1\delta(s_i,1)) \delta(s_i,s_j) - \gamma_{01}(1 - \delta(s_i, s_j)) ]\delta(\sigma_i, \sigma_j) where :math:`s_i` denotes the bipartite class of a node and :math:`\sigma_i` the community of the node as elsewhere in the documentation. Rewriting as a sum over communities gives a bit more insight .. math:: Q = \sum_c (e_c - \gamma_{01} 2 n_c(0) n_c(1) - \gamma_0 n^2_c(0) - \gamma_1 n^2_c(1)) where :math:`n_c(0)` is the number of nodes in community :math:`c` of class 0 (and similarly for 1) and :math:`e_c` is the number of edges within community :math:`c`. We denote by :math:`n_c = n_c(0) + n_c(1)` the total number of nodes in community :math:`c`. Note that .. math:: n_c^2 &= (n_c(0) + n_c(1))^2 \\ &= n_c(0)^2 + 2 n_c(0) n_c(1) + n_c(1)^2 We then create three different layers: (1) all nodes have ``node_size = 1`` and all relevant links; (2) only nodes of class 0 have ``node_size = 1`` and no links; (3) only nodes of class 1 have ``node_size = 1`` and no links. If we add the first with resolution parameter :math:`\gamma_{01}`, and the others with resolution parameters :math:`\gamma_{01} - \gamma_0` and :math:`\gamma_{01} - \gamma_1`, but the latter two with a layer weight of -1 while the first layer has layer weight 1, we obtain the following: .. math:: Q &= \sum_c (e_c - \gamma_{01} n_c^2) -\sum_c (- (\gamma_{01} - \gamma_0) n_c(0)^2) -\sum_c (- (\gamma_{01} - \gamma_1) n_c(0)^2) \\ &= \sum_c [e_c - \gamma_{01} 2 n_c(0) n_c(1) - \gamma_{01} n_c(0)^2 - \gamma_{01} n_c(1)^2) + ( \gamma_{01} - \gamma_0) n_c(0)^2 + ( \gamma_{01} - \gamma_1) n_c(1)^2 ] \\ &= \sum_c (e_c - \gamma_{01} 2 n_c(0) n_c(1) - \gamma_{0} n_c(0)^2 - \gamma_{1} n_c(1)^2) \\ Hence detecting communities with these three layers corresponds to detecting communities in bipartite networks. Although we worked out this example for directed network including self-loops (since it is easiest), it works out similarly for undirected networks (with or without self-loops). This only corresponds to the CPM method. However, using a little additional trick, we can also make this work for modularity. Essentially, modularity is nothing else than CPM with the ``node_size`` set to the degree, and the resolution parameter set to :math:`\gamma = \frac{1}{2m}`. In particular, in general (i.e. not specifically for bipartite graph) if ``node_sizes=G.degree()`` we then obtain .. math:: Q = \sum_{ij} A_{ij} - \gamma k_i k_j In the case of bipartite graphs something similar is obtained, but then correctly adapted (as long as the resolution parameter is also appropriately rescaled). Note that this is only possible for modularity for undirected graphs. Hence, we can also detect communities in bipartite networks using modularity by using this little trick. The definition of modularity for bipartite graphs is identical to the formulation of bipartite modularity provided in [3]_. All of this has been implemented in the constructor :func:`~leidenalg.CPMVertexPartition.Bipartite`. You can simply pass in a bipartite network with the classes appropriately defined in ``G.vs['type']`` or equivalent. This function assumes the two classes are coded by ``0`` and ``1``, and if this is not the case it will try to convert it into such categories by :func:`ig.UniqueIdGenerator`. An explicit example of this: .. testsetup:: import numpy as np G.vs['type'] = np.random.randint(0, 2, G.vcount()) >>> p_01, p_0, p_1 = la.CPMVertexPartition.Bipartite(G, ... resolution_parameter_01=0.1); >>> diff = optimiser.optimise_partition_multiplex([p_01, p_0, p_1], ... layer_weights=[1, -1, -1]); Slices to layers ---------------- The multiplex formulation as layers has two limitations: (1) each graph needs to have an identical vertex set; (2) each node is only in a single community. Ideally, one would like to relax both these requirements, so that you can work with graphs that do not need to have identical nodes and where nodes can be in different communities in different layers. For example, a person could be in one community when looking at his professional relations, but in another community looking at his personal relations. Perhaps more commonly: a person could be in one community at time 1 and in another community at time 2. Fortunately, this is also possible with this package. We call the more general formulation *slices* in contrast to the *layers* required by the earlier functions. Slices are then just different graphs, which do not need to have the same vertex set in any way. The idea is to build one big graph out of all the slices and then decompose it again in layers that correspond with slices. The key element is that some slices are coupled: for example two consecutive time windows, or simply two different slices of types of relations. Because any two slices can be coupled in theory, we represent the coupling itself again with a graph. The nodes of this *coupling graph* thus are slices, and the (possibly weighted) links in the coupling graph represent the (possibly weighted) couplings between slices. Below an example with three different time slices, where slice 1 is coupled to slice 2, which in turn is coupled to slice 3: .. image:: figures/slices.png The coupling graph thus consists of three nodes and a simple line structure: ``1 -- 2 -- 3``. We convert this into layers by putting all nodes of all slices in one big network. Each node is thus represented by a tuple ``(node, slice)`` in a certain sense. Out of this big network, we then only take those edges that are defined between nodes of the same slice, which then constitutes a single layer. Finally, we need one more layer for the couplings. In addition, for methods such as :class:`~leidenalg.CPMVertexPartition`, so-called ``node_sizes`` are required, and for them to properly function, they should be set to 0 (which is handled appropriately by the package). We thus obtain equally many layers as we have slices, and we need one more layer for representing the interslice couplings. For the example provided above, we thus obtain the following: .. image:: figures/layers_separate.png To transform slices into layers using a coupling graph, this package provides :func:`~leidenalg.layers_to_slices`. For the example above, this would function as follows. First create the coupling graph assuming we have three slices ``G_1``, ``G_2`` and ``G_3``: .. testsetup:: G_1 = ig.Graph.Erdos_Renyi(100, 0.1) G_2 = ig.Graph.Erdos_Renyi(100, 0.1) G_3 = ig.Graph.Erdos_Renyi(100, 0.1) G_1.vs['id'] = range(100) G_2.vs['id'] = range(100) G_3.vs['id'] = range(100) >>> G_coupling = ig.Graph.Formula('1 -- 2 -- 3'); >>> G_coupling.es['weight'] = 0.1; # Interslice coupling strength >>> G_coupling.vs['slice'] = [G_1, G_2, G_3] Then we convert them to layers >>> layers, interslice_layer, G_full = la.slices_to_layers(G_coupling); Now we still have to create partitions for all the layers. We can freely choose here to use the same partition types for all partitions, or to use different types for different layers. .. warning:: The interslice layer should usually be of type :class:`~leidenalg.CPMVertexPartition` with a ``resolution_parameter=0`` and ``node_sizes`` set to 0. The ``G.vs[node_size]`` is automatically set to 0 for all nodes in the interslice layer in :func:`~leidenalg.slices_to_layers`, so you can simply pass in the attribute ``node_size``. Unless you know what you are doing, simply use these settings. .. warning:: When using methods that accept a node_size argument, this should always be used. This is the case for :class:`~leidenalg.CPMVertexPartition`, :class:`~leidenalg.RBERVertexPartition`, :class:`~leidenalg.SurpriseVertexPartition` and :class:`~leidenalg.SignificanceVertexPartition`. .. testsetup:: gamma = 0.5; >>> partitions = [la.CPMVertexPartition(H, node_sizes='node_size', ... weights='weight', resolution_parameter=gamma) ... for H in layers]; >>> interslice_partition = la.CPMVertexPartition(interslice_layer, resolution_parameter=0, ... node_sizes='node_size', weights='weight'); You can then simply optimise these partitions as before using :func:`~leidenalg.Optimiser.optimise_partition_multiplex`: >>> diff = optimiser.optimise_partition_multiplex(partitions + [interslice_partition]); Temporal community detection ---------------------------- One of the most common tasks for converting slices to layers is that we have slices at different points in time. We call this temporal community detection. Because it is such a common task, we provide several helper functions to simplify the above process. Let us assume again that we have three slices ``G_1``, ``G_2`` and ``G_3`` as in the example above. The most straightforward function is :func:`~leidenalg.find_partition_temporal`: >>> membership, improvement = la.find_partition_temporal( ... [G_1, G_2, G_3], ... la.CPMVertexPartition, ... interslice_weight=0.1, ... resolution_parameter=gamma) This function only returns the membership vectors for the different time slices, rather than actual partitions. Rather than directly detecting communities, you can also obtain the actual partitions in a slightly more convenient way using :func:`~leidenalg.time_slices_to_layers`: >>> layers, interslice_layer, G_full = \ ... la.time_slices_to_layers([G_1, G_2, G_3], ... interslice_weight=0.1); >>> partitions = [la.CPMVertexPartition(H, node_sizes='node_size', ... weights='weight', ... resolution_parameter=gamma) ... for H in layers]; >>> interslice_partition = \ ... la.CPMVertexPartition(interslice_layer, resolution_parameter=0, ... node_sizes='node_size', weights='weight'); >>> diff = optimiser.optimise_partition_multiplex(partitions + [interslice_partition]); Both these functions assume that the interslice coupling is always identical for all slices. If you want more finegrained control, you will have to use the earlier explained functions. References ---------- .. [1] Mucha, P. J., Richardson, T., Macon, K., Porter, M. A., & Onnela, J.-P. (2010). Community structure in time-dependent, multiscale, and multiplex networks. Science, 328(5980), 876–8. `10.1126/science.1184819 `_ .. [2] Traag, V. A., & Bruggeman, J. (2009). Community detection in networks with positive and negative links. Physical Review E, 80(3), 036115. `10.1103/PhysRevE.80.036115 `_ .. [3] Barber, M. J. (2007). Modularity and community detection in bipartite networks. Physical Review E, 76(6), 066102. `10.1103/PhysRevE.76.066102 `_leidenalg-0.8.9/doc/source/reference.rst000066400000000000000000000027321420514302700202130ustar00rootroot00000000000000Reference =============== Module functions ---------------- .. automodule:: leidenalg :members: find_partition, find_partition_multiplex, find_partition_temporal, slices_to_layers, time_slices_to_layers, :undoc-members: :show-inheritance: Optimiser --------- .. autoclass:: Optimiser :members: :undoc-members: :show-inheritance: MutableVertexPartition ---------------------- .. autoclass:: leidenalg.VertexPartition.MutableVertexPartition :members: :undoc-members: :show-inheritance: ModularityVertexPartition ------------------------- .. autoclass:: ModularityVertexPartition :members: :undoc-members: :show-inheritance: RBConfigurationVertexPartition ------------------------------ .. autoclass:: RBConfigurationVertexPartition :members: resolution_parameter :undoc-members: :show-inheritance: RBERVertexPartition ------------------- .. autoclass:: RBERVertexPartition :members: :undoc-members: :show-inheritance: CPMVertexPartition ------------------ .. autoclass:: CPMVertexPartition :members: :undoc-members: :show-inheritance: SignificanceVertexPartition --------------------------- .. autoclass:: SignificanceVertexPartition :members: :undoc-members: :show-inheritance: SurpriseVertexPartition ----------------------- .. autoclass:: SurpriseVertexPartition :members: :undoc-members: :show-inheritance: leidenalg-0.8.9/include/000077500000000000000000000000001420514302700150755ustar00rootroot00000000000000leidenalg-0.8.9/include/CPMVertexPartition.h000066400000000000000000000015131420514302700207550ustar00rootroot00000000000000#ifndef CPMVERTEXPARTITION_H #define CPMVERTEXPARTITION_H #include class CPMVertexPartition : public LinearResolutionParameterVertexPartition { public: CPMVertexPartition(Graph* graph, vector membership, double resolution_parameter); CPMVertexPartition(Graph* graph, vector membership); CPMVertexPartition(Graph* graph, double resolution_parameter); CPMVertexPartition(Graph* graph); virtual ~CPMVertexPartition(); virtual CPMVertexPartition* create(Graph* graph); virtual CPMVertexPartition* create(Graph* graph, vector const& membership); virtual double diff_move(size_t v, size_t new_comm); virtual double quality(double resolution_parameter); protected: private: }; #endif // CPMVERTEXPARTITION_H leidenalg-0.8.9/include/GraphHelper.h000066400000000000000000000144621420514302700174560ustar00rootroot00000000000000#ifndef GRAPHHELPER_INCLUDED #define GRAPHHELPER_INCLUDED #include #include #include #include #include //#ifdef DEBUG #include using std::cerr; using std::endl; //#endif class MutableVertexPartition; using std::vector; using std::pair; using std::set; using std::deque; using std::make_pair; vector range(size_t n); bool orderCSize(const size_t* A, const size_t* B); double KL(double q, double p); double KLL(double q, double p); template T sum(vector vec) { T sum_of_elems = T(); for (T x : vec) sum_of_elems += x; return sum_of_elems; }; class Exception : public std::exception { public: Exception(const char* str) { this->str = str; } virtual const char* what() const throw() { return this->str; } private: const char* str; }; inline size_t get_random_int(size_t from, size_t to, igraph_rng_t* rng) { return igraph_rng_get_integer(rng, from, to); }; void shuffle(vector& v, igraph_rng_t* rng); class Graph { public: Graph(igraph_t* graph, vector const& edge_weights, vector const& node_sizes, vector const& node_self_weights, int correct_self_loops); Graph(igraph_t* graph, vector const& edge_weights, vector const& node_sizes, vector const& node_self_weights); Graph(igraph_t* graph, vector const& edge_weights, vector const& node_sizes, int correct_self_loops); Graph(igraph_t* graph, vector const& edge_weights, vector const& node_sizes); Graph(igraph_t* graph, vector const& edge_weights, int correct_self_loops); Graph(igraph_t* graph, vector const& edge_weights); Graph(igraph_t* graph, vector const& node_sizes, int correct_self_loops); Graph(igraph_t* graph, vector const& node_sizes); Graph(igraph_t* graph, int correct_self_loops); Graph(igraph_t* graph); Graph(); ~Graph(); int has_self_loops(); size_t possible_edges(); size_t possible_edges(size_t n); Graph* collapse_graph(MutableVertexPartition* partition); vector const& get_neighbour_edges(size_t v, igraph_neimode_t mode); vector const& get_neighbours(size_t v, igraph_neimode_t mode); size_t get_random_neighbour(size_t v, igraph_neimode_t mode, igraph_rng_t* rng); inline size_t get_random_node(igraph_rng_t* rng) { return get_random_int(0, this->vcount() - 1, rng); }; inline igraph_t* get_igraph() { return this->_graph; }; inline size_t vcount() { return igraph_vcount(this->_graph); }; inline size_t ecount() { return igraph_ecount(this->_graph); }; inline double total_weight() { return this->_total_weight; }; inline size_t total_size() { return this->_total_size; }; inline int is_directed() { return this->_is_directed; }; inline double density() { return this->_density; }; inline int correct_self_loops() { return this->_correct_self_loops; }; inline int is_weighted() { return this->_is_weighted; }; // Get weight of edge based on attribute (or 1.0 if there is none). inline double edge_weight(size_t e) { #ifdef DEBUG if (e > this->_edge_weights.size()) throw Exception("Edges outside of range of edge weights."); #endif return this->_edge_weights[e]; }; inline void edge(size_t eid, size_t &from, size_t &to) { from = IGRAPH_FROM(this->get_igraph(), eid); to = IGRAPH_TO(this->get_igraph(), eid); } inline vector edge(size_t e) { vector edge(2); this->edge(e, edge[0], edge[1]); return edge; } // Get size of node based on attribute (or 1.0 if there is none). inline size_t node_size(size_t v) { return this->_node_sizes[v]; }; // Get self weight of node based on attribute (or set to 0.0 if there is none) inline double node_self_weight(size_t v) { return this->_node_self_weights[v]; }; inline size_t degree(size_t v, igraph_neimode_t mode) { if (mode == IGRAPH_IN || !this->is_directed()) return this->_degree_in[v]; else if (mode == IGRAPH_OUT) return this->_degree_out[v]; else if (mode == IGRAPH_ALL) return this->_degree_all[v]; else throw Exception("Incorrect mode specified."); }; inline double strength(size_t v, igraph_neimode_t mode) { if (mode == IGRAPH_IN || !this->is_directed()) return this->_strength_in[v]; else if (mode == IGRAPH_OUT) return this->_strength_out[v]; else throw Exception("Incorrect mode specified."); }; protected: int _remove_graph; private: igraph_t* _graph; igraph_vector_t _temp_igraph_vector; // Utility variables to easily access the strength of each node vector _strength_in; vector _strength_out; vector _degree_in; vector _degree_out; vector _degree_all; vector _edge_weights; // Used for the weight of the edges. vector _node_sizes; // Used for the size of the nodes. vector _node_self_weights; // Used for the self weight of the nodes. void cache_neighbours(size_t v, igraph_neimode_t mode); vector _cached_neighs_from; size_t _current_node_cache_neigh_from; vector _cached_neighs_to; size_t _current_node_cache_neigh_to; vector _cached_neighs_all; size_t _current_node_cache_neigh_all; void cache_neighbour_edges(size_t v, igraph_neimode_t mode); vector _cached_neigh_edges_from; size_t _current_node_cache_neigh_edges_from; vector _cached_neigh_edges_to; size_t _current_node_cache_neigh_edges_to; vector _cached_neigh_edges_all; size_t _current_node_cache_neigh_edges_all; double _total_weight; size_t _total_size; int _is_weighted; bool _is_directed; int _correct_self_loops; double _density; void init_admin(); void set_defaults(); void set_default_edge_weight(); void set_default_node_size(); void set_self_weights(); }; // We need this ugly way to include the MutableVertexPartition // to overcome a circular linkage problem. #include "MutableVertexPartition.h" #endif // GRAPHHELPER_INCLUDED leidenalg-0.8.9/include/LinearResolutionParameterVertexPartition.h000066400000000000000000000013541420514302700255000ustar00rootroot00000000000000#ifndef LINEARRESOLUTIONPARAMETERVERTEXPARTITION_H #define LINEARRESOLUTIONPARAMETERVERTEXPARTITION_H #include class LinearResolutionParameterVertexPartition : public ResolutionParameterVertexPartition { public: LinearResolutionParameterVertexPartition(Graph* graph, vector membership, double resolution_parameter); LinearResolutionParameterVertexPartition(Graph* graph, vector membership); LinearResolutionParameterVertexPartition(Graph* graph, double resolution_parameter); LinearResolutionParameterVertexPartition(Graph* graph); virtual ~LinearResolutionParameterVertexPartition(); private: }; #endif // RESOLUTIONPARAMETERVERTEXPARTITION_H leidenalg-0.8.9/include/ModularityVertexPartition.h000066400000000000000000000012371420514302700224720ustar00rootroot00000000000000#ifndef MODULARITYVERTEXPARTITION_H #define MODULARITYVERTEXPARTITION_H #include class ModularityVertexPartition : public MutableVertexPartition { public: ModularityVertexPartition(Graph* graph, vector const& membership); ModularityVertexPartition(Graph* graph); virtual ~ModularityVertexPartition(); virtual ModularityVertexPartition* create(Graph* graph); virtual ModularityVertexPartition* create(Graph* graph, vector const& membership); virtual double diff_move(size_t v, size_t new_comm); virtual double quality(); protected: private: }; #endif // MODULARITYVERTEXPARTITION_H leidenalg-0.8.9/include/MutableVertexPartition.h000066400000000000000000000160361420514302700217350ustar00rootroot00000000000000#ifndef MUTABLEVERTEXPARTITION_H #define MUTABLEVERTEXPARTITION_H #include #include "GraphHelper.h" #include #include #include #include using std::string; using std::map; using std::make_pair; using std::pair; using std::sort; using std::reverse; using std::priority_queue; /**************************************************************************** Contains a partition of graph. This class contains the basic implementation for optimising a partition. Specifically, it implements all the administration necessary to keep track of the partition from various points of view. Internally, it keeps track of the number of internal edges (or total weight), the size of the communities, the total incoming degree (or weight) for a community, etc... When deriving from this class, one can easily use this administration to provide their own implementation. In order to keep the administration up-to-date, all changes in partition should be done through move_node. This function moves a node from one community to another, and updates all the administration. It is possible to manually update the membership vector, and then call __init_admin() which completely refreshes all the administration. This is only possible by updating the membership vector, not by changing some of the other variables. The basic idea is that diff_move computes the difference in the quality function if we call move_node for the same move. Using this framework, the Leiden method in the optimisation class can call these general functions in order to optimise the quality function. *****************************************************************************/ class MutableVertexPartition { public: MutableVertexPartition(Graph* graph, vector const& membership); MutableVertexPartition(Graph* graph); virtual MutableVertexPartition* create(Graph* graph); virtual MutableVertexPartition* create(Graph* graph, vector const& membership); virtual ~MutableVertexPartition(); inline size_t membership(size_t v) { return this->_membership[v]; }; inline vector const& membership() const { return this->_membership; }; size_t csize(size_t comm); size_t cnodes(size_t comm); vector get_community(size_t comm); vector< vector > get_communities(); size_t n_communities(); void move_node(size_t v,size_t new_comm); virtual double diff_move(size_t v, size_t new_comm) { throw Exception("Function not implemented. This should be implented in a derived class, since the base class does not implement a specific method."); }; virtual double quality() { throw Exception("Function not implemented. This should be implented in a derived class, since the base class does not implement a specific method."); }; inline Graph* get_graph() { return this->graph; }; void renumber_communities(); void renumber_communities(vector const& fixed_nodes, vector const& fixed_membership); void renumber_communities(vector const& new_membership); void set_membership(vector const& new_membership); void relabel_communities(vector const& new_comm_id); vector static rank_order_communities(vector partitions); size_t get_empty_community(); size_t add_empty_community(); void from_coarse_partition(vector const& coarse_partition_membership); void from_coarse_partition(MutableVertexPartition* partition); void from_coarse_partition(MutableVertexPartition* partition, vector const& coarser_membership); void from_coarse_partition(vector const& coarse_partition_membership, vector const& coarse_node); void from_partition(MutableVertexPartition* partition); inline double total_weight_in_comm(size_t comm) { return comm < _n_communities ? this->_total_weight_in_comm[comm] : 0.0; }; inline double total_weight_from_comm(size_t comm) { return comm < _n_communities ? this->_total_weight_from_comm[comm] : 0.0; }; inline double total_weight_to_comm(size_t comm) { return comm < _n_communities ? this->_total_weight_to_comm[comm] : 0.0; }; inline double total_weight_in_all_comms() { return this->_total_weight_in_all_comms; }; inline size_t total_possible_edges_in_all_comms() { return this->_total_possible_edges_in_all_comms; }; inline double weight_to_comm(size_t v, size_t comm) { if (this->_current_node_cache_community_to != v) { this->cache_neigh_communities(v, IGRAPH_OUT); this->_current_node_cache_community_to = v; } if (comm < this->_cached_weight_to_community.size()) return this->_cached_weight_to_community[comm]; else return 0.0; } inline double weight_from_comm(size_t v, size_t comm) { if (!this->graph->is_directed()) return weight_to_comm(v, comm); if (this->_current_node_cache_community_from != v) { this->cache_neigh_communities(v, IGRAPH_IN); this->_current_node_cache_community_from = v; } if (comm < this->_cached_weight_from_community.size()) return this->_cached_weight_from_community[comm]; else return 0.0; } vector const& get_neigh_comms(size_t v, igraph_neimode_t); vector get_neigh_comms(size_t v, igraph_neimode_t mode, vector const& constrained_membership); // By delegating the responsibility for deleting the graph to the partition, // we no longer have to worry about deleting this graph. int destructor_delete_graph; protected: void init_admin(); vector _membership; // Membership vector, i.e. \sigma_i = c means that node i is in community c Graph* graph; // Community size vector< size_t > _csize; // Number of nodes in community vector< size_t > _cnodes; double weight_vertex_tofrom_comm(size_t v, size_t comm, igraph_neimode_t mode); void set_default_attrs(); private: // Keep track of the internal weight of each community vector _total_weight_in_comm; // Keep track of the total weight to a community vector _total_weight_to_comm; // Keep track of the total weight from a community vector _total_weight_from_comm; // Keep track of the total internal weight double _total_weight_in_all_comms; size_t _total_possible_edges_in_all_comms; size_t _n_communities; vector _empty_communities; void cache_neigh_communities(size_t v, igraph_neimode_t mode); size_t _current_node_cache_community_from; vector _cached_weight_from_community; vector _cached_neigh_comms_from; size_t _current_node_cache_community_to; vector _cached_weight_to_community; vector _cached_neigh_comms_to; size_t _current_node_cache_community_all; vector _cached_weight_all_community; vector _cached_neigh_comms_all; void clean_mem(); void init_graph_admin(); void update_n_communities(); }; #endif // MUTABLEVERTEXPARTITION_H leidenalg-0.8.9/include/Optimiser.h000066400000000000000000000175351420514302700172340ustar00rootroot00000000000000#ifndef OPTIMISER_H #define OPTIMISER_H #include "GraphHelper.h" #include "MutableVertexPartition.h" #include #include #include #include using std::cerr; using std::endl; using std::set; using std::map; /**************************************************************************** Class for doing community detection using the Leiden algorithm. Given a certain partition type is calls diff_move for trying to move a node to another community. It moves the node to the community that *maximises* this diff_move. If no further improvement is possible, the graph is aggregated (collapse_graph) and the method is reiterated on that graph. ****************************************************************************/ class Optimiser { public: Optimiser(); double optimise_partition(MutableVertexPartition* partition); double optimise_partition(MutableVertexPartition* partition, vector const& is_membership_fixed); double optimise_partition(MutableVertexPartition* partition, vector const& is_membership_fixed, size_t max_comm_size); template T* find_partition(Graph* graph); template T* find_partition(Graph* graph, double resolution_parameter); // The multiplex functions that simultaneously optimise multiple graphs and partitions (i.e. methods) // Each node will be in the same community in all graphs, and the graphs are expected to have identical nodes // Optionally we can loop over all possible communities instead of only the neighbours. In the case of negative // layer weights this may be necessary. double optimise_partition(vector partitions, vector layer_weights, vector const& is_membership_fixed); double optimise_partition(vector partitions, vector layer_weights, vector const& is_membership_fixed, size_t max_comm_size); double move_nodes(MutableVertexPartition* partition); double move_nodes(MutableVertexPartition* partition, int consider_comms); double move_nodes(MutableVertexPartition* partition, vector const& is_membership_fixed, int consider_comms, bool renumber_fixed_nodes); double move_nodes(MutableVertexPartition* partition, vector const& is_membership_fixed, int consider_comms, bool renumber_fixed_nodes, size_t max_comm_size); double move_nodes(vector partitions, vector layer_weights, vector const& is_membership_fixed, bool renumber_fixed_nodes); double move_nodes(vector partitions, vector layer_weights, vector const& is_membership_fixed, int consider_comms, int consider_empty_community); double move_nodes(vector partitions, vector layer_weights, vector const& is_membership_fixed, int consider_comms, int consider_empty_community, bool renumber_fixed_nodes); double move_nodes(vector partitions, vector layer_weights, vector const& is_membership_fixed, int consider_comms, int consider_empty_community, bool renumber_fixed_nodes, size_t max_comm_size); double merge_nodes(MutableVertexPartition* partition); double merge_nodes(MutableVertexPartition* partition, int consider_comms); double merge_nodes(MutableVertexPartition* partition, vector const& is_membership_fixed, int consider_comms, bool renumber_fixed_nodes); double merge_nodes(MutableVertexPartition* partition, vector const& is_membership_fixed, int consider_comms, bool renumber_fixed_nodes, size_t max_comm_size); double merge_nodes(vector partitions, vector layer_weights, vector const& is_membership_fixed, bool renumber_fixed_nodes); double merge_nodes(vector partitions, vector layer_weights, vector const& is_membership_fixed, int consider_comms, bool renumber_fixed_nodes); double merge_nodes(vector partitions, vector layer_weights, vector const& is_membership_fixed, int consider_comms, bool renumber_fixed_nodes, size_t max_comm_size); double move_nodes_constrained(MutableVertexPartition* partition, MutableVertexPartition* constrained_partition); double move_nodes_constrained(MutableVertexPartition* partition, int consider_comms, MutableVertexPartition* constrained_partition); double move_nodes_constrained(MutableVertexPartition* partition, int consider_comms, MutableVertexPartition* constrained_partition, size_t max_comm_size); double move_nodes_constrained(vector partitions, vector layer_weights, MutableVertexPartition* constrained_partition); double move_nodes_constrained(vector partitions, vector layer_weights, int consider_comms, MutableVertexPartition* constrained_partition); double move_nodes_constrained(vector partitions, vector layer_weights, int consider_comms, MutableVertexPartition* constrained_partition, size_t max_comm_size); double merge_nodes_constrained(MutableVertexPartition* partition, MutableVertexPartition* constrained_partition); double merge_nodes_constrained(MutableVertexPartition* partition, int consider_comms, MutableVertexPartition* constrained_partition); double merge_nodes_constrained(MutableVertexPartition* partition, int consider_comms, MutableVertexPartition* constrained_partition, size_t max_comm_size); double merge_nodes_constrained(vector partitions, vector layer_weights, MutableVertexPartition* constrained_partition); double merge_nodes_constrained(vector partitions, vector layer_weights, int consider_comms, MutableVertexPartition* constrained_partition); double merge_nodes_constrained(vector partitions, vector layer_weights, int consider_comms, MutableVertexPartition* constrained_partition, size_t max_comm_size); inline void set_rng_seed(size_t seed) { igraph_rng_seed(&rng, seed); }; virtual ~Optimiser(); int consider_comms; // Indicates how communities will be considered for improvement. Should be one of the parameters below int refine_partition; // Refine partition before aggregating int refine_consider_comms; // Indicates how communities will be considered for improvement within the refinement. Should be one of the parameters below int optimise_routine; // What routine to use for optimisation int refine_routine; // What routine to use for optimisation int consider_empty_community; // Determine whether to consider moving nodes to an empty community size_t max_comm_size; // Constrain the maximal community size. static const int ALL_COMMS = 1; // Consider all communities for improvement. static const int ALL_NEIGH_COMMS = 2; // Consider all neighbour communities for improvement. static const int RAND_COMM = 3; // Consider a random commmunity for improvement. static const int RAND_NEIGH_COMM = 4; // Consider a random community among the neighbours for improvement. static const int MOVE_NODES = 10; // Use move node routine static const int MERGE_NODES = 11; // Use merge node routine protected: private: void print_settings(); igraph_rng_t rng; }; template T* Optimiser::find_partition(Graph* graph) { T* partition = new T(graph); #ifdef DEBUG cerr << "Use default partition (all nodes in own community)" << endl; #endif this->optimise_partition(partition); return partition; } template T* Optimiser::find_partition(Graph* graph, double resolution_parameter) { T* partition = new T(graph, resolution_parameter); #ifdef DEBUG cerr << "Use default partition (all nodes in own community)" << endl; #endif this->optimise_partition(partition); return partition; } #endif // OPTIMISER_H leidenalg-0.8.9/include/RBConfigurationVertexPartition.h000066400000000000000000000017351420514302700233770ustar00rootroot00000000000000#ifndef RBCONFIGURATIONVERTEXPARTITION_H #define RBCONFIGURATIONVERTEXPARTITION_H #include "LinearResolutionParameterVertexPartition.h" class RBConfigurationVertexPartition : public LinearResolutionParameterVertexPartition { public: RBConfigurationVertexPartition(Graph* graph, vector const& membership, double resolution_parameter); RBConfigurationVertexPartition(Graph* graph, vector const& membership); RBConfigurationVertexPartition(Graph* graph, double resolution_parameter); RBConfigurationVertexPartition(Graph* graph); virtual ~RBConfigurationVertexPartition(); virtual RBConfigurationVertexPartition* create(Graph* graph); virtual RBConfigurationVertexPartition* create(Graph* graph, vector const& membership); virtual double diff_move(size_t v, size_t new_comm); virtual double quality(double resolution_parameter); protected: private: }; #endif // RBCONFIGURATIONVERTEXPARTITION_H leidenalg-0.8.9/include/RBERVertexPartition.h000066400000000000000000000015451420514302700210750ustar00rootroot00000000000000#ifndef RBERVERTEXPARTITION_H #define RBERVERTEXPARTITION_H #include class RBERVertexPartition : public LinearResolutionParameterVertexPartition { public: RBERVertexPartition(Graph* graph, vector const& membership, double resolution_parameter); RBERVertexPartition(Graph* graph, vector const& membership); RBERVertexPartition(Graph* graph, double resolution_parameter); RBERVertexPartition(Graph* graph); virtual ~RBERVertexPartition(); virtual RBERVertexPartition* create(Graph* graph); virtual RBERVertexPartition* create(Graph* graph, vector const& membership); virtual double diff_move(size_t v, size_t new_comm); virtual double quality(double resolution_parameter); protected: private: }; #endif // RBERVERTEXPARTITION_H leidenalg-0.8.9/include/ResolutionParameterVertexPartition.h000066400000000000000000000020131420514302700243360ustar00rootroot00000000000000#ifndef RESOLUTIONPARAMETERVERTEXPARTITION_H #define RESOLUTIONPARAMETERVERTEXPARTITION_H #include class ResolutionParameterVertexPartition : public MutableVertexPartition { public: ResolutionParameterVertexPartition(Graph* graph, vector membership, double resolution_parameter); ResolutionParameterVertexPartition(Graph* graph, vector membership); ResolutionParameterVertexPartition(Graph* graph, double resolution_parameter); ResolutionParameterVertexPartition(Graph* graph); virtual ~ResolutionParameterVertexPartition(); double resolution_parameter; virtual double quality() { return this->quality(this->resolution_parameter); }; virtual double quality(double resolution_parameter) { throw Exception("Function not implemented. This should be implented in a derived class, since the base class does not implement a specific method."); }; private: }; #endif // RESOLUTIONPARAMETERVERTEXPARTITION_H leidenalg-0.8.9/include/SignificanceVertexPartition.h000066400000000000000000000012511420514302700227170ustar00rootroot00000000000000#ifndef SIGNIFICANCEVERTEXPARTITION_H #define SIGNIFICANCEVERTEXPARTITION_H #include class SignificanceVertexPartition : public MutableVertexPartition { public: SignificanceVertexPartition(Graph* graph, vector const& membership); SignificanceVertexPartition(Graph* graph); virtual ~SignificanceVertexPartition(); virtual SignificanceVertexPartition* create(Graph* graph); virtual SignificanceVertexPartition* create(Graph* graph, vector const& membership); virtual double diff_move(size_t v, size_t new_comm); virtual double quality(); protected: private: }; #endif // SIGNIFICANCEVERTEXPARTITION_H leidenalg-0.8.9/include/SurpriseVertexPartition.h000066400000000000000000000014141420514302700221520ustar00rootroot00000000000000#ifndef SURPRISEVERTEXPARTITION_H #define SURPRISEVERTEXPARTITION_H #include "MutableVertexPartition.h" #include using std::cerr; using std::endl; class SurpriseVertexPartition: public MutableVertexPartition { public: SurpriseVertexPartition(Graph* graph, vector const& membership); SurpriseVertexPartition(Graph* graph, SurpriseVertexPartition* partition); SurpriseVertexPartition(Graph* graph); virtual ~SurpriseVertexPartition(); virtual SurpriseVertexPartition* create(Graph* graph); virtual SurpriseVertexPartition* create(Graph* graph, vector const& membership); virtual double diff_move(size_t v, size_t new_comm); virtual double quality(); protected: private: }; #endif // SURPRISEVERTEXPARTITION_H leidenalg-0.8.9/include/pynterface.h000066400000000000000000000227761420514302700174240ustar00rootroot00000000000000#ifndef PYNTERFACE_H_INCLUDED #define PYNTERFACE_H_INCLUDED #include #include #include "GraphHelper.h" #include "ModularityVertexPartition.h" #include "SignificanceVertexPartition.h" #include "SurpriseVertexPartition.h" #include "RBConfigurationVertexPartition.h" #include "RBERVertexPartition.h" #include "CPMVertexPartition.h" #include "Optimiser.h" #include "python_partition_interface.h" #include "python_optimiser_interface.h" #ifdef __cplusplus extern "C" { #endif PyObject* _set_rng_seed(PyObject *self, PyObject *args, PyObject *keywds); static PyMethodDef leiden_funcs[] = { {"_new_ModularityVertexPartition", (PyCFunction)_new_ModularityVertexPartition, METH_VARARGS | METH_KEYWORDS, ""}, {"_new_SignificanceVertexPartition", (PyCFunction)_new_SignificanceVertexPartition, METH_VARARGS | METH_KEYWORDS, ""}, {"_new_SurpriseVertexPartition", (PyCFunction)_new_SurpriseVertexPartition, METH_VARARGS | METH_KEYWORDS, ""}, {"_new_CPMVertexPartition", (PyCFunction)_new_CPMVertexPartition, METH_VARARGS | METH_KEYWORDS, ""}, {"_new_RBERVertexPartition", (PyCFunction)_new_RBERVertexPartition, METH_VARARGS | METH_KEYWORDS, ""}, {"_new_RBConfigurationVertexPartition", (PyCFunction)_new_RBConfigurationVertexPartition, METH_VARARGS | METH_KEYWORDS, ""}, {"_MutableVertexPartition_diff_move", (PyCFunction)_MutableVertexPartition_diff_move, METH_VARARGS | METH_KEYWORDS, ""}, {"_MutableVertexPartition_move_node", (PyCFunction)_MutableVertexPartition_move_node, METH_VARARGS | METH_KEYWORDS, ""}, {"_MutableVertexPartition_get_py_igraph", (PyCFunction)_MutableVertexPartition_get_py_igraph, METH_VARARGS | METH_KEYWORDS, ""}, {"_MutableVertexPartition_aggregate_partition", (PyCFunction)_MutableVertexPartition_aggregate_partition, METH_VARARGS | METH_KEYWORDS, ""}, {"_MutableVertexPartition_from_coarse_partition", (PyCFunction)_MutableVertexPartition_from_coarse_partition, METH_VARARGS | METH_KEYWORDS, ""}, {"_MutableVertexPartition_renumber_communities", (PyCFunction)_MutableVertexPartition_renumber_communities, METH_VARARGS | METH_KEYWORDS, ""}, {"_MutableVertexPartition_quality", (PyCFunction)_MutableVertexPartition_quality, METH_VARARGS | METH_KEYWORDS, ""}, {"_MutableVertexPartition_total_weight_in_comm", (PyCFunction)_MutableVertexPartition_total_weight_in_comm, METH_VARARGS | METH_KEYWORDS, ""}, {"_MutableVertexPartition_total_weight_from_comm", (PyCFunction)_MutableVertexPartition_total_weight_from_comm, METH_VARARGS | METH_KEYWORDS, ""}, {"_MutableVertexPartition_total_weight_to_comm", (PyCFunction)_MutableVertexPartition_total_weight_to_comm, METH_VARARGS | METH_KEYWORDS, ""}, {"_MutableVertexPartition_total_weight_in_all_comms", (PyCFunction)_MutableVertexPartition_total_weight_in_all_comms, METH_VARARGS | METH_KEYWORDS, ""}, {"_MutableVertexPartition_total_possible_edges_in_all_comms", (PyCFunction)_MutableVertexPartition_total_possible_edges_in_all_comms, METH_VARARGS | METH_KEYWORDS, ""}, {"_MutableVertexPartition_weight_to_comm", (PyCFunction)_MutableVertexPartition_weight_to_comm, METH_VARARGS | METH_KEYWORDS, ""}, {"_MutableVertexPartition_weight_from_comm", (PyCFunction)_MutableVertexPartition_weight_from_comm, METH_VARARGS | METH_KEYWORDS, ""}, {"_MutableVertexPartition_get_membership", (PyCFunction)_MutableVertexPartition_get_membership, METH_VARARGS | METH_KEYWORDS, ""}, {"_MutableVertexPartition_set_membership", (PyCFunction)_MutableVertexPartition_set_membership, METH_VARARGS | METH_KEYWORDS, ""}, {"_ResolutionParameterVertexPartition_get_resolution", (PyCFunction)_ResolutionParameterVertexPartition_get_resolution, METH_VARARGS | METH_KEYWORDS, ""}, {"_ResolutionParameterVertexPartition_set_resolution", (PyCFunction)_ResolutionParameterVertexPartition_set_resolution, METH_VARARGS | METH_KEYWORDS, ""}, {"_ResolutionParameterVertexPartition_quality", (PyCFunction)_ResolutionParameterVertexPartition_quality, METH_VARARGS | METH_KEYWORDS, ""}, {"_new_Optimiser", (PyCFunction)_new_Optimiser, METH_NOARGS, ""}, {"_Optimiser_optimise_partition", (PyCFunction)_Optimiser_optimise_partition, METH_VARARGS | METH_KEYWORDS, ""}, {"_Optimiser_optimise_partition_multiplex", (PyCFunction)_Optimiser_optimise_partition_multiplex, METH_VARARGS | METH_KEYWORDS, ""}, {"_Optimiser_move_nodes", (PyCFunction)_Optimiser_move_nodes, METH_VARARGS | METH_KEYWORDS, ""}, {"_Optimiser_move_nodes_constrained", (PyCFunction)_Optimiser_move_nodes_constrained, METH_VARARGS | METH_KEYWORDS, ""}, {"_Optimiser_merge_nodes", (PyCFunction)_Optimiser_merge_nodes, METH_VARARGS | METH_KEYWORDS, ""}, {"_Optimiser_merge_nodes_constrained", (PyCFunction)_Optimiser_merge_nodes_constrained, METH_VARARGS | METH_KEYWORDS, ""}, {"_Optimiser_set_consider_comms", (PyCFunction)_Optimiser_set_consider_comms, METH_VARARGS | METH_KEYWORDS, ""}, {"_Optimiser_set_refine_consider_comms", (PyCFunction)_Optimiser_set_refine_consider_comms, METH_VARARGS | METH_KEYWORDS, ""}, {"_Optimiser_set_optimise_routine", (PyCFunction)_Optimiser_set_optimise_routine, METH_VARARGS | METH_KEYWORDS, ""}, {"_Optimiser_set_refine_routine", (PyCFunction)_Optimiser_set_refine_routine, METH_VARARGS | METH_KEYWORDS, ""}, {"_Optimiser_set_consider_empty_community", (PyCFunction)_Optimiser_set_consider_empty_community, METH_VARARGS | METH_KEYWORDS, ""}, {"_Optimiser_set_refine_partition", (PyCFunction)_Optimiser_set_refine_partition, METH_VARARGS | METH_KEYWORDS, ""}, {"_Optimiser_set_max_comm_size", (PyCFunction)_Optimiser_set_max_comm_size, METH_VARARGS | METH_KEYWORDS, ""}, {"_Optimiser_get_consider_comms", (PyCFunction)_Optimiser_get_consider_comms, METH_VARARGS | METH_KEYWORDS, ""}, {"_Optimiser_get_refine_consider_comms", (PyCFunction)_Optimiser_get_refine_consider_comms, METH_VARARGS | METH_KEYWORDS, ""}, {"_Optimiser_get_optimise_routine", (PyCFunction)_Optimiser_get_optimise_routine, METH_VARARGS | METH_KEYWORDS, ""}, {"_Optimiser_get_refine_routine", (PyCFunction)_Optimiser_get_refine_routine, METH_VARARGS | METH_KEYWORDS, ""}, {"_Optimiser_get_consider_empty_community", (PyCFunction)_Optimiser_get_consider_empty_community, METH_VARARGS | METH_KEYWORDS, ""}, {"_Optimiser_get_refine_partition", (PyCFunction)_Optimiser_get_refine_partition, METH_VARARGS | METH_KEYWORDS, ""}, {"_Optimiser_get_max_comm_size", (PyCFunction)_Optimiser_get_max_comm_size, METH_VARARGS | METH_KEYWORDS, ""}, {"_Optimiser_set_rng_seed", (PyCFunction)_Optimiser_set_rng_seed, METH_VARARGS | METH_KEYWORDS, ""}, {NULL} }; struct module_state { PyObject *error; }; #define GETSTATE(m) ((struct module_state*)PyModule_GetState(m)) static int leiden_traverse(PyObject *m, visitproc visit, void *arg) { Py_VISIT(GETSTATE(m)->error); return 0; } static int leiden_clear(PyObject *m) { Py_CLEAR(GETSTATE(m)->error); return 0; } static struct PyModuleDef leidendef = { PyModuleDef_HEAD_INIT, "_c_leiden", NULL, sizeof(struct module_state), leiden_funcs, NULL, leiden_traverse, leiden_clear, NULL }; #define INITERROR return NULL PyObject * PyInit__c_leiden(void) { PyObject* module = PyModule_Create(&leidendef); PyModule_AddIntConstant(module, "ALL_COMMS", Optimiser::ALL_COMMS); PyModule_AddIntConstant(module, "ALL_NEIGH_COMMS", Optimiser::ALL_NEIGH_COMMS); PyModule_AddIntConstant(module, "RAND_COMM", Optimiser::RAND_COMM); PyModule_AddIntConstant(module, "RAND_NEIGH_COMM", Optimiser::RAND_NEIGH_COMM); PyModule_AddIntConstant(module, "MOVE_NODES", Optimiser::MOVE_NODES); PyModule_AddIntConstant(module, "MERGE_NODES", Optimiser::MERGE_NODES); if (module == NULL) INITERROR; struct module_state *st = GETSTATE(module); st->error = PyErr_NewException("leidenalg.Error", NULL, NULL); if (st->error == NULL) { Py_DECREF(module); INITERROR; } return module; } #ifdef __cplusplus } #endif #endif // PYNTERFACE_H_INCLUDED leidenalg-0.8.9/include/python_optimiser_interface.h000066400000000000000000000054161420514302700227100ustar00rootroot00000000000000#ifndef PYNTERFACE_OPTIMISER_H_INCLUDED #define PYNTERFACE_OPTIMISER_H_INCLUDED #include #include #include "GraphHelper.h" #include "ModularityVertexPartition.h" #include "SignificanceVertexPartition.h" #include "SurpriseVertexPartition.h" #include "RBConfigurationVertexPartition.h" #include "RBERVertexPartition.h" #include "CPMVertexPartition.h" #include "Optimiser.h" #include "python_partition_interface.h" #ifdef DEBUG #include using std::cerr; using std::endl; #endif PyObject* capsule_Optimiser(Optimiser* optimiser); Optimiser* decapsule_Optimiser(PyObject* py_optimiser); void del_Optimiser(PyObject* py_optimiser); #ifdef __cplusplus extern "C" { #endif PyObject* _new_Optimiser(PyObject *self, PyObject *args); PyObject* _Optimiser_optimise_partition(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _Optimiser_optimise_partition_multiplex(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _Optimiser_move_nodes(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _Optimiser_move_nodes_constrained(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _Optimiser_merge_nodes(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _Optimiser_merge_nodes_constrained(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _Optimiser_set_consider_comms(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _Optimiser_set_refine_consider_comms(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _Optimiser_set_optimise_routine(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _Optimiser_set_refine_routine(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _Optimiser_set_consider_empty_community(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _Optimiser_set_refine_partition(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _Optimiser_set_max_comm_size(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _Optimiser_set_rng_seed(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _Optimiser_get_consider_comms(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _Optimiser_get_refine_consider_comms(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _Optimiser_get_optimise_routine(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _Optimiser_get_refine_routine(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _Optimiser_get_consider_empty_community(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _Optimiser_get_refine_partition(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _Optimiser_get_max_comm_size(PyObject *self, PyObject *args, PyObject *keywds); #ifdef __cplusplus } #endif #endif // PYNTERFACE_OPTIMISER_H_INCLUDED leidenalg-0.8.9/include/python_partition_interface.h000066400000000000000000000077751420514302700227200ustar00rootroot00000000000000#ifndef PYNTERFACE_PARTITION_H_INCLUDED #define PYNTERFACE_PARTITION_H_INCLUDED #include #include #include "GraphHelper.h" #include "ModularityVertexPartition.h" #include "SignificanceVertexPartition.h" #include "SurpriseVertexPartition.h" #include "RBConfigurationVertexPartition.h" #include "RBERVertexPartition.h" #include "CPMVertexPartition.h" #include "Optimiser.h" #include #ifdef DEBUG #include using std::cerr; using std::endl; #endif MutableVertexPartition* create_partition(Graph* graph, char* method, vector* initial_membership, double resolution_parameter); MutableVertexPartition* create_partition_from_py(PyObject* py_obj_graph, char* method, PyObject* py_initial_membership, PyObject* py_weights, PyObject* py_node_sizes, double resolution_parameter); Graph* create_graph_from_py(PyObject* py_obj_graph, PyObject* py_node_sizes); Graph* create_graph_from_py(PyObject* py_obj_graph, PyObject* py_node_sizes, PyObject* py_weights); Graph* create_graph_from_py(PyObject* py_obj_graph, PyObject* py_node_sizes, PyObject* py_weights, int check_positive_weight); vector create_size_t_vector(PyObject* py_list); PyObject* capsule_MutableVertexPartition(MutableVertexPartition* partition); MutableVertexPartition* decapsule_MutableVertexPartition(PyObject* py_partition); void del_MutableVertexPartition(PyObject *self); #ifdef __cplusplus extern "C" { #endif PyObject* _new_ModularityVertexPartition(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _new_SignificanceVertexPartition(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _new_SurpriseVertexPartition(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _new_CPMVertexPartition(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _new_RBERVertexPartition(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _new_RBConfigurationVertexPartition(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _MutableVertexPartition_diff_move(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _MutableVertexPartition_move_node(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _MutableVertexPartition_aggregate_partition(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _MutableVertexPartition_get_py_igraph(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _MutableVertexPartition_from_coarse_partition(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _MutableVertexPartition_renumber_communities(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _MutableVertexPartition_quality(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _MutableVertexPartition_total_weight_in_comm(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _MutableVertexPartition_total_weight_from_comm(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _MutableVertexPartition_total_weight_to_comm(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _MutableVertexPartition_total_weight_in_all_comms(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _MutableVertexPartition_total_possible_edges_in_all_comms(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _MutableVertexPartition_weight_to_comm(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _MutableVertexPartition_weight_from_comm(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _MutableVertexPartition_get_membership(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _MutableVertexPartition_set_membership(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _ResolutionParameterVertexPartition_get_resolution(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _ResolutionParameterVertexPartition_set_resolution(PyObject *self, PyObject *args, PyObject *keywds); PyObject* _ResolutionParameterVertexPartition_quality(PyObject *self, PyObject *args, PyObject *keywds); #ifdef __cplusplus } #endif #endif // PYNTERFACE_PARTITION_H_INCLUDED leidenalg-0.8.9/setup.cfg000066400000000000000000000001721420514302700152730ustar00rootroot00000000000000[build_sphinx] source-dir = doc/source build-dir = doc/build all_files = 1 [upload_sphinx] upload-dir = doc/build/html leidenalg-0.8.9/setup.py000066400000000000000000000736151420514302700152000ustar00rootroot00000000000000#!usr/bin/env python import os import platform import sys ########################################################################### # Check Python's version info and exit early if it is too old if sys.version_info < (3, 6): print("This module requires Python >= 3.6") sys.exit(0) # Check whether we are compiling for PyPy. Headers will not be installed # for PyPy. SKIP_HEADER_INSTALL = (platform.python_implementation() == "PyPy") or ( "SKIP_HEADER_INSTALL" in os.environ ) ########################################################################### from setuptools import setup, Command, Extension import glob import shlex import shutil import subprocess import sys import sysconfig from pathlib import Path from select import select from shutil import which from time import sleep ########################################################################### is_windows = platform.system() == "windows" def building_on_windows_msvc(): """Returns True when using the non-MinGW CPython interpreter on Windows""" return platform.system() == "Windows" and sysconfig.get_platform() != "mingw" def exclude_from_list(items, items_to_exclude): """Excludes certain items from a list, keeping the original order of the remaining items.""" itemset = set(items_to_exclude) return [item for item in items if item not in itemset] def find_static_library(library_name, library_path): """Given the raw name of a library in `library_name`, tries to find a static library with this name in the given `library_path`. `library_path` is automatically extended with common library directories on Linux and Mac OS X.""" variants = ["lib{0}.a", "{0}.a", "{0}.lib", "lib{0}.lib"] if is_unix_like(): extra_libdirs = [ "/usr/local/lib64", "/usr/local/lib", "/usr/lib/x86_64-linux-gnu", "/usr/lib64", "/usr/lib", "/lib64", "/lib", ] else: extra_libdirs = [] for path in extra_libdirs: if path not in library_path and os.path.isdir(path): library_path.append(path) for path in library_path: for variant in variants: full_path = os.path.join(path, variant.format(library_name)) if os.path.isfile(full_path): return full_path def first(iterable): """Returns the first element from the given iterable.""" for item in iterable: return item raise ValueError("iterable is empty") def get_output(args, encoding="utf-8"): """Returns the output of a command returning a single line of output.""" PIPE = subprocess.PIPE try: p = subprocess.Popen(args, shell=False, stdin=PIPE, stdout=PIPE, stderr=PIPE) stdout, stderr = p.communicate() returncode = p.returncode except OSError: stdout, stderr = None, None returncode = 77 if encoding and type(stdout).__name__ == "bytes": stdout = str(stdout, encoding=encoding) if encoding and type(stderr).__name__ == "bytes": stderr = str(stderr, encoding=encoding) return stdout, returncode def get_output_single_line(args, encoding="utf-8"): """Returns the output of a command returning a single line of output, stripped from any trailing newlines.""" stdout, returncode = get_output(args, encoding=encoding) if stdout is not None: line, _, _ = stdout.partition("\n") else: line = None return line, returncode def is_unix_like(platform=None): """Returns whether the given platform is a Unix-like platform with the usual Unix filesystem. When the parameter is omitted, it defaults to ``sys.platform`` """ platform = platform or sys.platform platform = platform.lower() return ( platform.startswith("linux") or platform.startswith("darwin") or platform.startswith("cygwin") ) def wait_for_keypress(seconds): """Wait for a keypress or until the given number of seconds have passed, whichever happens first. """ global is_windows while seconds > 0: if seconds > 1: plural = "s" else: plural = "" sys.stdout.write( "\rContinuing in %2d second%s; press Enter to continue " "immediately. " % (seconds, plural) ) sys.stdout.flush() if is_windows: from msvcrt import kbhit for i in range(10): if kbhit(): seconds = 0 break sleep(0.1) else: rlist, _, _ = select([sys.stdin], [], [], 1) if rlist: sys.stdin.readline() seconds = 0 break seconds -= 1 sys.stdout.write("\r" + " " * 65 + "\r") ########################################################################### class IgraphCCoreBuilder(object): """Superclass for classes responsible for downloading and building the C core of igraph if it is not installed yet. """ def create_build_config_file(self, install_folder, libraries): with (install_folder / "build.cfg").open("w") as fp: fp.write(repr(libraries)) def parse_pkgconfig_file(self, filename): building_on_windows = building_on_windows_msvc() if building_on_windows: libraries = ["igraph"] else: libraries = [] with filename.open("r") as fp: for line in fp: if line.startswith("Libs: ") or line.startswith("Libs.private: "): words = line.strip().split() libraries.extend( word[2:] for word in words if word.startswith("-l") ) if not libraries: # Educated guess libraries = ["igraph"] return libraries ########################################################################### class IgraphCCoreCMakeBuilder(IgraphCCoreBuilder): """Class responsible for downloading and building the C core of igraph if it is not installed yet, assuming that the C core uses CMake as the build tool. This is the case from igraph 0.9. Returns: False if the build failed or the list of libraries to link to when linking the Python interface to igraph """ def compile_in(self, source_folder, build_folder, install_folder): """Compiles igraph from its source code in the given folder. source_folder is the name of the folder that contains igraph's source files. build_folder is the name of the folder where the build should be executed. Both must be absolute paths. """ global is_windows cmake = which("cmake") if not cmake: print( "igraph uses CMake as the build system. You need to install CMake " "before compiling igraph." ) return False build_to_source_folder = os.path.relpath(source_folder, build_folder) os.chdir(build_folder) print("Configuring build...") args = [cmake] # Build the Python interface with vendored libraries for deps in "ARPACK BLAS CXSPARSE GLPK GMP LAPACK".split(): args.append("-DIGRAPH_USE_INTERNAL_" + deps + "=ON") # -fPIC is needed on Linux so we can link to a static igraph lib from a # Python shared library args.append("-DCMAKE_POSITION_INDEPENDENT_CODE=ON") # Add any extra CMake args from environment variables if "IGRAPH_CMAKE_EXTRA_ARGS" in os.environ: args.extend(shlex.split(os.environ["IGRAPH_CMAKE_EXTRA_ARGS"])) # Finally, add the source folder path args.append(str(build_to_source_folder)) retcode = subprocess.call(args) if retcode: return False print("Running build...") retcode = subprocess.call( [cmake, "--build", ".", "--config", "Release"] ) if retcode: return False print("Installing build...") retcode = subprocess.call([cmake, "--install", ".", "--prefix", str(install_folder), "--config", "Release"]) if retcode: return False pkgconfig_candidates = [ install_folder / "lib" / "pkgconfig" / "igraph.pc", install_folder / "lib64" / "pkgconfig" / "igraph.pc" ] for candidate in pkgconfig_candidates: if candidate.exists(): return self.parse_pkgconfig_file(candidate) raise RuntimeError("no igraph.pc was found in the installation folder of igraph") ########################################################################### class BuildConfiguration(object): def __init__(self): self.include_dirs = [] self.library_dirs = [] self.runtime_library_dirs = [] self.libraries = [] self.extra_compile_args = [] self.extra_link_args = [] self.define_macros = [] self.extra_objects = [] self.static_extension = False self.external = False self.use_pkgconfig = False self._has_pkgconfig = None self.excluded_include_dirs = [] self.excluded_library_dirs = [] self.wait = platform.system() != "Windows" @property def has_pkgconfig(self): """Returns whether ``pkg-config`` is available on the current system and it knows about igraph or not.""" if self._has_pkgconfig is None: if self.use_pkgconfig: line, exit_code = get_output_single_line(["pkg-config", "igraph"]) self._has_pkgconfig = exit_code == 0 else: self._has_pkgconfig = False return self._has_pkgconfig @property def build_c_core(self): """Returns a class representing a custom setup.py command that builds the C core of igraph. This is used in CI environments where we want to build the C core of igraph once and then build the Python interface for various Python versions without having to recompile the C core all the time. If is also used as a custom building block of `build_ext`. """ buildcfg = self class build_c_core(Command): description = "Compile the C core of igraph only" user_options = [] def initialize_options(self): pass def finalize_options(self): pass def run(self): buildcfg.c_core_built = buildcfg.compile_igraph_from_vendor_source() return build_c_core @property def build_ext(self): """Returns a class that can be used as a replacement for the ``build_ext`` command in ``setuptools`` and that will compile the C core of igraph before compiling the Python extension. """ from setuptools.command.build_ext import build_ext from distutils.sysconfig import get_python_inc buildcfg = self class custom_build_ext(build_ext): def run(self): # Bail out if we don't have the Python include files include_dir = get_python_inc() if not os.path.isfile(os.path.join(include_dir, "Python.h")): print("You will need the Python headers to compile this extension.") sys.exit(1) # Check whether the user asked us to discover a pre-built igraph # with pkg-config detected = False if buildcfg.external: if buildcfg.use_pkgconfig: detected = buildcfg.detect_from_pkgconfig() if not detected: print( "Cannot find the C core of igraph on this system using pkg-config." ) sys.exit(1) else: buildcfg.use_educated_guess() else: # Build the C core from the vendored igraph source self.run_command("build_c_core") if not buildcfg.c_core_built: # Fall back to an educated guess if everything else failed if not detected: buildcfg.use_educated_guess() # Add any extra include paths if needed; this is needed for the # Appveyor CI build if "IGRAPH_EXTRA_INCLUDE_PATH" in os.environ: buildcfg.include_dirs = ( list(os.environ["IGRAPH_EXTRA_INCLUDE_PATH"].split(os.pathsep)) + buildcfg.include_dirs ) # Add any extra library paths if needed; this is needed for the # Appveyor CI build if "IGRAPH_EXTRA_LIBRARY_PATH" in os.environ: buildcfg.library_dirs = ( list(os.environ["IGRAPH_EXTRA_LIBRARY_PATH"].split(os.pathsep)) + buildcfg.library_dirs ) # Add extra libraries that may have been specified if "IGRAPH_EXTRA_LIBRARIES" in os.environ: extra_libraries = os.environ["IGRAPH_EXTRA_LIBRARIES"].split(',') buildcfg.libraries.extend(extra_libraries) # Override static specification based on environment variable if "IGRAPH_STATIC_EXTENSION" in os.environ: if os.environ["IGRAPH_STATIC_EXTENSION"].lower() in ['true', '1', 'on']: buildcfg.static_extension = True else: buildcfg.static_extension = False # Replaces library names with full paths to static libraries # where possible. libm.a is excluded because it caused problems # on Sabayon Linux where libm.a is probably not compiled with # -fPIC if buildcfg.static_extension: if buildcfg.static_extension == "only_igraph": buildcfg.replace_static_libraries(only=["igraph"]) else: buildcfg.replace_static_libraries(exclusions=["m"]) # Add extra libraries that may have been specified if "IGRAPH_EXTRA_DYNAMIC_LIBRARIES" in os.environ: extra_libraries = os.environ["IGRAPH_EXTRA_DYNAMIC_LIBRARIES"].split(',') buildcfg.libraries.extend(extra_libraries) # Prints basic build information buildcfg.print_build_info() # Find the igraph extension and configure it with the settings # of this build configuration ext = first( extension for extension in self.extensions if extension.name == "leidenalg._c_leiden" ) ext.include_dirs += buildcfg.include_dirs buildcfg.configure(ext) # Run the original build_ext command build_ext.run(self) return custom_build_ext @property def sdist(self): """Returns a class that can be used as a replacement for the ``sdist`` command in ``setuptools`` and that will clean up ``vendor/source/igraph`` before running the original ``sdist`` command. """ from setuptools.command.sdist import sdist def is_git_repo(folder): return os.path.exists(os.path.join(folder, ".git")) def cleanup_git_repo(folder): folder = str(folder) cwd = os.getcwd() try: os.chdir(folder) if os.path.exists(".git"): retcode = subprocess.call("git clean -dfx", shell=True) if retcode: raise RuntimeError(f"Failed to clean {folder} with git") finally: os.chdir(cwd) class custom_sdist(sdist): def run(self): igraph_source_repo = os.path.join("vendor", "source", "igraph") igraph_build_dir = os.path.join("vendor", "build", "igraph") version_file = os.path.join(igraph_source_repo, "IGRAPH_VERSION") version = None # Check whether the source repo contains an IGRAPH_VERSION file, # and extract the version number from that if os.path.exists(version_file): with open(version_file, "r") as fp: version = fp.read().strip().split("\n")[0] # If no IGRAPH_VERSION file exists, but we have a git repo, try # git describe if not version and is_git_repo(igraph_source_repo): cwd = os.getcwd() try: os.chdir(igraph_source_repo) version = subprocess.check_output("git describe", shell=True).decode("utf-8").strip() finally: os.chdir(cwd) # If we still don't have a version number, try to parse it from # include/igraph_version.h if not version: version_header = os.path.join(igraph_build_dir, "include", "igraph_version.h") if not os.path.exists(version_header): raise RuntimeError("You need to build the C core of igraph first before generating a source tarball of python-igraph") with open(version_header, "r") as fp: lines = [line.strip() for line in fp if line.startswith("#define IGRAPH_VERSION ")] if len(lines) == 1: version = lines[0].split('"')[1] if not isinstance(version, str) or len(version) < 5: raise RuntimeError(f"Cannot determine the version number of the C core in {igraph_source_repo}") if not is_git_repo(igraph_source_repo): # python-igraph was extracted from an official tarball so # there is no need to tweak anything return sdist.run(self) else: # Clean up vendor/source/igraph with git cleanup_git_repo(igraph_source_repo) # Copy the generated parser sources from the build folder parser_dir = os.path.join(igraph_build_dir, "src", "io", "parsers") if os.path.isdir(parser_dir): shutil.copytree(parser_dir, os.path.join(igraph_source_repo, "src", "io", "parsers")) else: raise RuntimeError(f"You need to build the C core of igraph first before generating a source tarball of python-igraph") # Add a version file to the tarball with open(version_file, "w") as fp: fp.write(version) # Run the original sdist command retval = sdist.run(self) # Clean up vendor/source/igraph with git again cleanup_git_repo(igraph_source_repo) return retval return custom_sdist def compile_igraph_from_vendor_source(self): """Compiles igraph from the vendored source code inside `vendor/source/igraph`. This folder typically comes from a git submodule. """ vendor_folder = Path("vendor") source_folder = vendor_folder / "source" / "igraph" build_folder = vendor_folder / "build" / "igraph" install_folder = vendor_folder / "install" / "igraph" if install_folder.exists(): # Vendored igraph already compiled and installed, just use it self.use_vendored_igraph() return True if (source_folder / "CMakeLists.txt").exists(): igraph_builder = IgraphCCoreCMakeBuilder() else: print("Cannot find vendored igraph source in {0}".format(source_folder)) print("") return False print("We are going to build the C core of igraph.") print(" Source folder: {0}".format(source_folder)) print(" Build folder: {0}".format(build_folder)) print(" Install folder: {0}".format(install_folder)) print("") source_folder = source_folder.resolve() build_folder = build_folder.resolve() install_folder = install_folder.resolve() Path(build_folder).mkdir(parents=True, exist_ok=True) cwd = os.getcwd() try: libraries = igraph_builder.compile_in( source_folder=source_folder, build_folder=build_folder, install_folder=install_folder, ) finally: os.chdir(cwd) igraph_builder.create_build_config_file(install_folder, libraries) self.use_vendored_igraph() return True def configure(self, ext): """Configures the given Extension object using this build configuration.""" ext.include_dirs = exclude_from_list( ext.include_dirs, self.excluded_include_dirs ) ext.library_dirs = exclude_from_list( self.library_dirs, self.excluded_library_dirs ) ext.runtime_library_dirs = self.runtime_library_dirs ext.libraries = self.libraries ext.extra_compile_args = self.extra_compile_args ext.extra_link_args = self.extra_link_args ext.extra_objects = self.extra_objects ext.define_macros = self.define_macros def detect_from_pkgconfig(self): """Detects the igraph include directory, library directory and the list of libraries to link to using ``pkg-config``.""" if not buildcfg.has_pkgconfig: return False cmd = ["pkg-config", "igraph", "--cflags", "--libs"] if self.static_extension: cmd += ["--static"] line, exit_code = get_output_single_line(cmd) if exit_code > 0 or len(line) == 0: return False opts = line.strip().split() self.libraries = [opt[2:] for opt in opts if opt.startswith("-l")] self.library_dirs = [opt[2:] for opt in opts if opt.startswith("-L")] self.include_dirs = [opt[2:] for opt in opts if opt.startswith("-I")] return True def print_build_info(self): """Prints the include and library path being used for debugging purposes.""" if self.static_extension == "only_igraph": build_type = "dynamic extension with vendored igraph source" elif self.static_extension: build_type = "static extension" else: build_type = "dynamic extension" print("Build type: %s" % build_type) print("Include path: %s" % " ".join(self.include_dirs)) if self.excluded_include_dirs: print(" - excluding: %s" % " ".join(self.excluded_include_dirs)) print("Library path: %s" % " ".join(self.library_dirs)) if self.excluded_library_dirs: print(" - excluding: %s" % " ".join(self.excluded_library_dirs)) print("Runtime library path: %s" % " ".join(self.runtime_library_dirs)) print("Linked dynamic libraries: %s" % " ".join(self.libraries)) print("Linked static libraries: %s" % " ".join(self.extra_objects)) print("Extra compiler options: %s" % " ".join(self.extra_compile_args)) print("Extra linker options: %s" % " ".join(self.extra_link_args)) def process_args_from_command_line(self): """Preprocesses the command line options before they are passed to setup.py and sets up the build configuration.""" # Yes, this is ugly, but we don't want to interfere with setup.py's own # option handling opts_to_remove = [] for idx, option in enumerate(sys.argv): if not option.startswith("--"): continue if option == "--static": opts_to_remove.append(idx) self.static_extension = True elif option == "--no-pkg-config": opts_to_remove.append(idx) self.use_pkgconfig = False elif option == "--no-wait": opts_to_remove.append(idx) self.wait = False elif option == "--external": opts_to_remove.append(idx) self.external = True elif option == "--use-pkg-config": opts_to_remove.append(idx) self.use_pkgconfig = True for idx in reversed(opts_to_remove): sys.argv[idx : (idx + 1)] = [] def replace_static_libraries(self, only=None, exclusions=None): """Replaces references to libraries with full paths to their static versions if the static version is to be found on the library path.""" building_on_windows = building_on_windows_msvc() if not building_on_windows and "stdc++" not in self.libraries: self.libraries.append("stdc++") if exclusions is None: exclusions = [] print(f"Libraries: {self.libraries}") print(f"Exclusions: {exclusions}") for library_name in set(self.libraries) - set(exclusions): if only is not None and library_name not in only: continue static_lib = find_static_library(library_name, self.library_dirs) if static_lib: print(f"Found {library_name} as static library in {static_lib}.") self.libraries.remove(library_name) self.extra_objects.append(static_lib) else: print(f"Warning: could not find static library of {library_name}.") def use_vendored_igraph(self): """Assumes that igraph is installed already in ``vendor/install/igraph`` and sets up the include and library paths and the library names accordingly.""" building_on_windows = building_on_windows_msvc() vendor_dir = Path("vendor") / "install" / "igraph" buildcfg.include_dirs = [str(vendor_dir / "include" / "igraph")] buildcfg.library_dirs = [] for candidate in ("lib", "lib64"): candidate = vendor_dir / candidate if candidate.exists(): buildcfg.library_dirs.append(str(candidate)) break else: raise RuntimeError("cannot detect igraph library dir within " + str(vendor_dir)) if not buildcfg.static_extension: buildcfg.static_extension = "only_igraph" if building_on_windows: buildcfg.define_macros.append(("IGRAPH_STATIC", "1")) buildcfg_file = vendor_dir / "build.cfg" if buildcfg_file.exists(): buildcfg.libraries = eval(buildcfg_file.open("r").read()) def use_educated_guess(self): """Tries to guess the proper library names, include and library paths.""" print("""WARNING: You are trying to install with an external igraph library. No include dirs or library dirs are specified, so they need to be set externally. If compilation fails you may adjust the following environment variables to adjust the required paths. - IGRAPH_EXTRA_INCLUDE_PATH - IGRAPH_EXTRA_LIBRARY_PATH - IGRAPH_EXTRA_LIBRARIES - IGRAPH_EXTRA_DYNAMIC_LIBRARIES If a static build extension is used, we try to statically link to igraph. The extra libraries that are specified are then also assumed to be statically linked. If, in addition, some libraries need to be explicitly dynamically linked, you can specify this. """) self.libraries = ['igraph'] self.include_dirs = [] self.library_dirs = [] ########################################################################### # Process command line options buildcfg = BuildConfiguration() buildcfg.process_args_from_command_line() # Define the extension leiden_ext = Extension('leidenalg._c_leiden', sources = glob.glob(os.path.join('src', 'leidenalg', '*.cpp')), include_dirs=['include']); options = dict( name = 'leidenalg', description = 'Leiden is a general algorithm for methods of community detection in large networks.', long_description= """ Leiden is a general algorithm for methods of community detection in large networks. Please refer to the `documentation `_ for more details. The source code of this package is hosted at `GitHub `_. Issues and bug reports are welcome at https://github.com/vtraag/leidenalg/issues. """, license = 'GPLv3+', url = 'https://github.com/vtraag/leidenalg', use_scm_version={ 'write_to': 'src/leidenalg/version.py', }, setup_requires=['setuptools_scm'], author = 'V.A. Traag', author_email = 'vincent@traag.net', test_suite = 'tests', provides = ['leidenalg'], package_dir = {'leidenalg': os.path.join('src', 'leidenalg')}, packages = ['leidenalg'], ext_modules = [leiden_ext], install_requires = ['igraph >= 0.9.0,< 0.10'], platforms="ALL", keywords=[ 'graph', 'network', 'community detection', 'clustering' ], classifiers=[ 'Development Status :: 4 - Beta', 'Environment :: Console', 'Intended Audience :: End Users/Desktop', 'Intended Audience :: Developers', 'Intended Audience :: Science/Research', 'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)', 'Operating System :: MacOS :: MacOS X', 'Operating System :: Microsoft :: Windows', 'Operating System :: POSIX', 'Programming Language :: Python', 'Programming Language :: C++', 'Topic :: Scientific/Engineering :: Mathematics', 'Topic :: Scientific/Engineering :: Information Analysis', 'Topic :: Sociology' ], cmdclass={ "build_c_core": buildcfg.build_c_core, # used by CI "build_ext": buildcfg.build_ext, "sdist": buildcfg.sdist }, ) setup(**options)leidenalg-0.8.9/src/000077500000000000000000000000001420514302700142415ustar00rootroot00000000000000leidenalg-0.8.9/src/leidenalg/000077500000000000000000000000001420514302700161655ustar00rootroot00000000000000leidenalg-0.8.9/src/leidenalg/CPMVertexPartition.cpp000066400000000000000000000120341420514302700224000ustar00rootroot00000000000000#include "CPMVertexPartition.h" CPMVertexPartition::CPMVertexPartition(Graph* graph, vector membership, double resolution_parameter) : LinearResolutionParameterVertexPartition(graph, membership, resolution_parameter) { } CPMVertexPartition::CPMVertexPartition(Graph* graph, vector membership) : LinearResolutionParameterVertexPartition(graph, membership) { } CPMVertexPartition::CPMVertexPartition(Graph* graph, double resolution_parameter) : LinearResolutionParameterVertexPartition(graph, resolution_parameter) { } CPMVertexPartition::CPMVertexPartition(Graph* graph) : LinearResolutionParameterVertexPartition(graph) { } CPMVertexPartition::~CPMVertexPartition() { } CPMVertexPartition* CPMVertexPartition::create(Graph* graph) { return new CPMVertexPartition(graph, this->resolution_parameter); } CPMVertexPartition* CPMVertexPartition::create(Graph* graph, vector const& membership) { return new CPMVertexPartition(graph, membership, this->resolution_parameter); } /******************************************************************************** RBER implementation of a vertex partition (which includes a resolution parameter). ********************************************************************************/ double CPMVertexPartition::diff_move(size_t v, size_t new_comm) { #ifdef DEBUG cerr << "double CPMVertexPartition::diff_move(" << v << ", " << new_comm << ")" << endl; cerr << "Using resolution parameter: " << this->resolution_parameter << "." << endl; #endif size_t old_comm = this->membership(v); double diff = 0.0; if (new_comm != old_comm) { double w_to_old = this->weight_to_comm(v, old_comm); #ifdef DEBUG cerr << "\t" << "w_to_old: " << w_to_old << endl; #endif double w_to_new = this->weight_to_comm(v, new_comm); #ifdef DEBUG cerr << "\t" << "w_to_new: " << w_to_new << endl; #endif double w_from_old = this->weight_from_comm(v, old_comm); #ifdef DEBUG cerr << "\t" << "w_from_old: " << w_from_old << endl; #endif double w_from_new = this->weight_from_comm(v, new_comm); #ifdef DEBUG cerr << "\t" << "w_from_new: " << w_from_new << endl; #endif size_t nsize = this->graph->node_size(v); #ifdef DEBUG cerr << "\t" << "nsize: " << nsize << endl; #endif size_t csize_old = this->csize(old_comm); #ifdef DEBUG cerr << "\t" << "csize_old: " << csize_old << endl; #endif size_t csize_new = this->csize(new_comm); #ifdef DEBUG cerr << "\t" << "csize_new: " << csize_new << endl; #endif double self_weight = this->graph->node_self_weight(v); #ifdef DEBUG cerr << "\t" << "self_weight: " << self_weight << endl; cerr << "\t" << "density: " << this->graph->density() << endl; #endif double possible_edge_difference_old = 0.0; if (this->graph->correct_self_loops()) possible_edge_difference_old = nsize*(2.0*csize_old - nsize); else possible_edge_difference_old = nsize*(2.0*csize_old - nsize - 1.0); #ifdef DEBUG cerr << "\t" << "possible_edge_difference_old: " << possible_edge_difference_old << endl; #endif double diff_old = w_to_old + w_from_old - self_weight - this->resolution_parameter*possible_edge_difference_old; #ifdef DEBUG cerr << "\t" << "diff_old: " << diff_old << endl; #endif double possible_edge_difference_new = 0.0; if (this->graph->correct_self_loops()) possible_edge_difference_new = nsize*(2.0*csize_new + nsize); else possible_edge_difference_new = nsize*(2.0*csize_new + nsize - 1.0); #ifdef DEBUG cerr << "\t" << "possible_edge_difference_new: " << possible_edge_difference_new << endl; #endif double diff_new = w_to_new + w_from_new + self_weight - this->resolution_parameter*possible_edge_difference_new; #ifdef DEBUG cerr << "\t" << "diff_new: " << diff_new << endl; #endif diff = diff_new - diff_old; #ifdef DEBUG cerr << "\t" << "diff: " << diff << endl;; #endif } #ifdef DEBUG cerr << "exit CPMVertexPartition::diff_move(" << v << ", " << new_comm << ")" << endl; cerr << "return " << diff << endl << endl; #endif return diff; } double CPMVertexPartition::quality(double resolution_parameter) { #ifdef DEBUG cerr << "double CPMVertexPartition::quality()" << endl; #endif double mod = 0.0; for (size_t c = 0; c < this->n_communities(); c++) { size_t csize = this->csize(c); double w = this->total_weight_in_comm(c); size_t comm_possible_edges = this->graph->possible_edges(csize); #ifdef DEBUG cerr << "\t" << "Comm: " << c << ", w_c=" << w << ", n_c=" << csize << ", comm_possible_edges=" << comm_possible_edges << ", p=" << this->graph->density() << "." << endl; #endif mod += w - resolution_parameter*comm_possible_edges; } #ifdef DEBUG cerr << "exit double CPMVertexPartition::quality()" << endl; cerr << "return " << mod << endl << endl; #endif return (2.0 - this->graph->is_directed())*mod; } leidenalg-0.8.9/src/leidenalg/GraphHelper.cpp000066400000000000000000000562051420514302700211020ustar00rootroot00000000000000#include "GraphHelper.h" #ifdef DEBUG using std::cerr; using std::endl; #endif vector range(size_t n) { vector range_vec(n); for(size_t i = 0; i < n; i++) range_vec[i] = i; return range_vec; } bool orderCSize(const size_t* A, const size_t* B) { if (A[1] == B[1]) { if (A[2] == B[2]) return A[0] < B[0]; else return A[2] > B[2]; } else return A[1] > B[1]; } void shuffle(vector& v, igraph_rng_t* rng) { size_t n = v.size(); if (n > 0) { for (size_t idx = n - 1; idx > 0; idx--) { size_t rand_idx = get_random_int(0, idx, rng); size_t tmp = v[idx]; v[idx] = v[rand_idx]; v[rand_idx] = tmp; } } } /**************************************************************************** The binary Kullback-Leibler divergence. ****************************************************************************/ double KL(double q, double p) { double KL = 0.0; if (q > 0.0 && p > 0.0) KL += q*log(q/p); if (q < 1.0 && p < 1.0) KL += (1.0-q)*log((1.0-q)/(1.0-p)); return KL; } double KLL(double q, double p) { double KL = 0.0; if (q > 0.0 && p > 0.0) KL += q*log(q/p); if (q < 1.0 && p < 1.0) KL += (1.0-q)*log((1.0-q)/(1.0-p)); if (q < p) KL *= -1; return KL; } Graph::Graph(igraph_t* graph, vector const& edge_weights, vector const& node_sizes, vector const& node_self_weights, int correct_self_loops) { this->_graph = graph; this->_remove_graph = false; if (edge_weights.size() != this->ecount()) throw Exception("Edge weights vector inconsistent length with the edge count of the graph."); this->_edge_weights = edge_weights; this->_is_weighted = true; if (node_sizes.size() != this->vcount()) throw Exception("Node size vector inconsistent length with the vertex count of the graph."); this->_node_sizes = node_sizes; if (node_self_weights.size() != this->vcount()) throw Exception("Node self weights vector inconsistent length with the vertex count of the graph."); this->_node_self_weights = node_self_weights; this->_correct_self_loops = correct_self_loops; igraph_vector_init(&this->_temp_igraph_vector, this->vcount()); this->init_admin(); } Graph::Graph(igraph_t* graph, vector const& edge_weights, vector const& node_sizes, vector const& node_self_weights) { this->_graph = graph; this->_remove_graph = false; if (edge_weights.size() != this->ecount()) throw Exception("Edge weights vector inconsistent length with the edge count of the graph."); this->_edge_weights = edge_weights; this->_is_weighted = true; if (node_sizes.size() != this->vcount()) throw Exception("Node size vector inconsistent length with the vertex count of the graph."); this->_node_sizes = node_sizes; this->_correct_self_loops = this->has_self_loops(); this->_node_self_weights = node_self_weights; igraph_vector_init(&this->_temp_igraph_vector, this->vcount()); this->init_admin(); } Graph::Graph(igraph_t* graph, vector const& edge_weights, vector const& node_sizes, int correct_self_loops) { this->_graph = graph; this->_remove_graph = false; if (edge_weights.size() != this->ecount()) throw Exception("Edge weights vector inconsistent length with the edge count of the graph."); this->_edge_weights = edge_weights; this->_is_weighted = true; if (node_sizes.size() != this->vcount()) throw Exception("Node size vector inconsistent length with the vertex count of the graph."); this->_node_sizes = node_sizes; this->_correct_self_loops = correct_self_loops; igraph_vector_init(&this->_temp_igraph_vector, this->vcount()); this->init_admin(); this->set_self_weights(); } Graph::Graph(igraph_t* graph, vector const& edge_weights, vector const& node_sizes) { this->_graph = graph; this->_remove_graph = false; if (edge_weights.size() != this->ecount()) throw Exception("Edge weights vector inconsistent length with the edge count of the graph."); this->_edge_weights = edge_weights; this->_is_weighted = true; if (node_sizes.size() != this->vcount()) throw Exception("Node size vector inconsistent length with the vertex count of the graph."); this->_node_sizes = node_sizes; this->_correct_self_loops = this->has_self_loops(); igraph_vector_init(&this->_temp_igraph_vector, this->vcount()); this->init_admin(); this->set_self_weights(); } Graph::Graph(igraph_t* graph, vector const& edge_weights, int correct_self_loops) { this->_graph = graph; this->_remove_graph = false; this->_correct_self_loops = correct_self_loops; if (edge_weights.size() != this->ecount()) throw Exception("Edge weights vector inconsistent length with the edge count of the graph."); this->_edge_weights = edge_weights; this->_is_weighted = true; this->set_default_node_size(); igraph_vector_init(&this->_temp_igraph_vector, this->vcount()); this->init_admin(); this->set_self_weights(); } Graph::Graph(igraph_t* graph, vector const& edge_weights) { this->_graph = graph; this->_remove_graph = false; if (edge_weights.size() != this->ecount()) throw Exception("Edge weights vector inconsistent length with the edge count of the graph."); this->_edge_weights = edge_weights; this->_is_weighted = true; this->_correct_self_loops = this->has_self_loops(); this->set_default_node_size(); igraph_vector_init(&this->_temp_igraph_vector, this->vcount()); this->init_admin(); this->set_self_weights(); } Graph::Graph(igraph_t* graph, vector const& node_sizes, int correct_self_loops) { this->_graph = graph; this->_remove_graph = false; this->_correct_self_loops = correct_self_loops; if (node_sizes.size() != this->vcount()) throw Exception("Node size vector inconsistent length with the vertex count of the graph."); this->_node_sizes = node_sizes; this->set_default_edge_weight(); this->_is_weighted = false; igraph_vector_init(&this->_temp_igraph_vector, this->vcount()); this->init_admin(); this->set_self_weights(); } Graph::Graph(igraph_t* graph, vector const& node_sizes) { this->_graph = graph; this->_remove_graph = false; this->set_defaults(); this->_is_weighted = false; if (node_sizes.size() != this->vcount()) throw Exception("Node size vector inconsistent length with the vertex count of the graph."); this->_node_sizes = node_sizes; this->_correct_self_loops = this->has_self_loops(); igraph_vector_init(&this->_temp_igraph_vector, this->vcount()); this->init_admin(); this->set_self_weights(); } Graph::Graph(igraph_t* graph, int correct_self_loops) { this->_graph = graph; this->_remove_graph = false; this->_correct_self_loops = correct_self_loops; this->set_defaults(); this->_is_weighted = false; igraph_vector_init(&this->_temp_igraph_vector, this->vcount()); this->init_admin(); this->set_self_weights(); } Graph::Graph(igraph_t* graph) { this->_graph = graph; this->_remove_graph = false; this->set_defaults(); this->_is_weighted = false; this->_correct_self_loops = this->has_self_loops(); igraph_vector_init(&this->_temp_igraph_vector, this->vcount()); this->init_admin(); this->set_self_weights(); } Graph::Graph() { this->_graph = new igraph_t(); this->_remove_graph = true; this->set_defaults(); this->_is_weighted = false; this->_correct_self_loops = false; igraph_vector_init(&this->_temp_igraph_vector, this->vcount()); this->init_admin(); this->set_self_weights(); } Graph::~Graph() { if (this->_remove_graph) { igraph_destroy(this->_graph); delete this->_graph; } igraph_vector_destroy(&this->_temp_igraph_vector); } int Graph::has_self_loops() { size_t m = this->ecount(); igraph_vector_bool_t loop; igraph_vector_bool_init(&loop, m); igraph_is_loop(this->_graph, &loop, igraph_ess_all(IGRAPH_EDGEORDER_ID)); int has_self_loops = false; for (size_t idx = 0; idx < m; idx++) { if (VECTOR(loop)[idx]) { has_self_loops = true; break; } } igraph_vector_bool_destroy(&loop); return has_self_loops; } size_t Graph::possible_edges() { return this->possible_edges(this->vcount()); } size_t Graph::possible_edges(size_t n) { size_t possible_edges = n*(n-1); if (!this->is_directed()) possible_edges /= 2; if (this->correct_self_loops()) possible_edges += n; return possible_edges; } void Graph::set_defaults() { this->set_default_edge_weight(); this->set_default_node_size(); } void Graph::set_default_edge_weight() { size_t m = this->ecount(); // Set default edge weight of 1.0 this->_edge_weights.clear(); this->_edge_weights.resize(m); fill(this->_edge_weights.begin(), this->_edge_weights.end(), 1.0); this->_is_weighted = false; } void Graph::set_default_node_size() { size_t n = this->vcount(); // Set default node size of 1 this->_node_sizes.clear(); this->_node_sizes.resize(n); fill(this->_node_sizes.begin(), this->_node_sizes.end(), 1); } void Graph::set_self_weights() { size_t n = this->vcount(); // Set default self_weights of the total weight of any possible self-loops this->_node_self_weights.clear(); this->_node_self_weights.resize(n); for (size_t v = 0; v < n; v++) { #ifdef DEBUG cerr << "\t" << "Size node " << v << ": " << this->node_size(v) << endl; #endif double self_weight = 0.0; // There should be only one self loop igraph_integer_t eid; // Get edge id for self loop igraph_get_eid(this->_graph, &eid, v, v, this->is_directed(), false); if (eid >= 0) self_weight = this->edge_weight(eid); this->_node_self_weights[v] = self_weight; #ifdef DEBUG cerr << "\t" << "Self weight node " << v << ": " << self_weight << endl; #endif } } void Graph::init_admin() { size_t m = this->ecount(); size_t n = this->vcount(); this->_is_directed = igraph_is_directed(this->_graph); this->_strength_in.clear(); this->_strength_in.resize(n, 0.0); this->_degree_in.clear(); this->_degree_in.resize(n, 0.0); if (this->_is_directed) { this->_strength_out.clear(); this->_strength_out.resize(n, 0.0); this->_degree_out.clear(); this->_degree_out.resize(n, 0); this->_degree_all.clear(); this->_degree_all.resize(n, 0); } // Determine total weight in the graph. this->_total_weight = 0.0; for (size_t e = 0; e < m; e++) { double w = this->edge_weight(e); this->_total_weight += w; size_t from, to; this->edge(e, from, to); if (this->is_directed()) { this->_strength_in[to] += w; this->_strength_out[from] += w; this->_degree_in[to]++; this->_degree_out[from]++; this->_degree_all[to]++; this->_degree_all[from]++; } else { // we only compute strength_in and degree_in for undirected graphs this->_strength_in[to] += w; this->_strength_in[from] += w; // recall that igraph ignores the mode for undirected graphs this->_degree_in[to]++; this->_degree_in[from]++; } } // Make sure to multiply by 2 for undirected graphs //if (!this->is_directed()) // this->_total_weight *= 2.0; this->_total_size = 0; for (size_t v = 0; v < n; v++) this->_total_size += this->node_size(v); // Calculate density; double w = this->total_weight(); size_t n_size = this->total_size(); // For now we default to not correcting self loops. // this->_correct_self_loops = false; (remove this as this is set in the constructor) double normalise = 0.0; if (this->_correct_self_loops) normalise = n_size*n_size; else normalise = n_size*(n_size - 1); if (this->is_directed()) this->_density = w/normalise; else this->_density = 2*w/normalise; this->_current_node_cache_neigh_edges_from = n + 1; this->_current_node_cache_neigh_edges_to = n + 1; this->_current_node_cache_neigh_edges_all = n + 1; this->_current_node_cache_neigh_from = n + 1; this->_current_node_cache_neigh_to = n + 1; this->_current_node_cache_neigh_all = n + 1; } void Graph::cache_neighbour_edges(size_t v, igraph_neimode_t mode) { #ifdef DEBUG cerr << "void Graph::cache_neighbour_edges(" << v << ", " << mode << ");" << endl; #endif size_t degree = this->degree(v, mode); #ifdef DEBUG cerr << "Degree: " << degree << endl; #endif igraph_vector_t *incident_edges = &this->_temp_igraph_vector; igraph_incident(this->_graph, incident_edges, v, mode); vector* _cached_neigh_edges = NULL; switch (mode) { case IGRAPH_IN: this->_current_node_cache_neigh_edges_from = v; _cached_neigh_edges = &(this->_cached_neigh_edges_from); break; case IGRAPH_OUT: this->_current_node_cache_neigh_edges_to = v; _cached_neigh_edges = &(this->_cached_neigh_edges_to); break; case IGRAPH_ALL: this->_current_node_cache_neigh_edges_all = v; _cached_neigh_edges = &(this->_cached_neigh_edges_all); break; } _cached_neigh_edges->assign(igraph_vector_e_ptr(incident_edges, 0), igraph_vector_e_ptr(incident_edges, degree)); #ifdef DEBUG cerr << "Number of edges: " << _cached_neigh_edges->size() << endl; #endif #ifdef DEBUG cerr << "exit void Graph::cache_neighbour_edges(" << v << ", " << mode << ");" << endl; #endif } vector const& Graph::get_neighbour_edges(size_t v, igraph_neimode_t mode) { if (!this->is_directed()) mode = IGRAPH_ALL; // igraph ignores mode for undirected graphs switch (mode) { case IGRAPH_IN: if (this->_current_node_cache_neigh_edges_from != v) { cache_neighbour_edges(v, mode); this->_current_node_cache_neigh_edges_from = v; } return this->_cached_neigh_edges_from; case IGRAPH_OUT: if (this->_current_node_cache_neigh_edges_to != v) { cache_neighbour_edges(v, mode); this->_current_node_cache_neigh_edges_to = v; } return this->_cached_neigh_edges_to; case IGRAPH_ALL: if (this->_current_node_cache_neigh_edges_all != v) { cache_neighbour_edges(v, mode); this->_current_node_cache_neigh_edges_all = v; } return this->_cached_neigh_edges_all; } throw Exception("Incorrect model for getting neighbour edges."); } void Graph::cache_neighbours(size_t v, igraph_neimode_t mode) { #ifdef DEBUG cerr << "void Graph::cache_neighbours(" << v << ", " << mode << ");" << endl; #endif size_t degree = this->degree(v, mode); #ifdef DEBUG cerr << "Degree: " << degree << endl; #endif igraph_vector_t *neighbours = &this->_temp_igraph_vector; igraph_neighbors(this->_graph, neighbours, v, mode); vector* _cached_neighs = NULL; switch (mode) { case IGRAPH_IN: this->_current_node_cache_neigh_from = v; _cached_neighs = &(this->_cached_neighs_from); break; case IGRAPH_OUT: this->_current_node_cache_neigh_to = v; _cached_neighs = &(this->_cached_neighs_to); break; case IGRAPH_ALL: this->_current_node_cache_neigh_all = v; _cached_neighs = &(this->_cached_neighs_all); break; } _cached_neighs->assign(igraph_vector_e_ptr(neighbours, 0),igraph_vector_e_ptr(neighbours, degree)); #ifdef DEBUG cerr << "Number of edges: " << _cached_neighs->size() << endl; #endif #ifdef DEBUG cerr << "exit void Graph::cache_neighbours(" << v << ", " << mode << ");" << endl; #endif } vector< size_t > const& Graph::get_neighbours(size_t v, igraph_neimode_t mode) { if (!this->is_directed()) mode = IGRAPH_ALL; // igraph ignores mode for undirected graphs switch (mode) { case IGRAPH_IN: if (this->_current_node_cache_neigh_from != v) { cache_neighbours(v, mode); this -> _current_node_cache_neigh_from = v; } #ifdef DEBUG cerr << "Returning " << this->_cached_neighs_from.size() << " incoming neighbours" << endl; #endif return this->_cached_neighs_from; case IGRAPH_OUT: if (this->_current_node_cache_neigh_to != v) { cache_neighbours(v, mode); this -> _current_node_cache_neigh_to = v; } #ifdef DEBUG cerr << "Returning " << this->_cached_neighs_to.size() << " incoming neighbours" << endl; #endif return this->_cached_neighs_to; case IGRAPH_ALL: if (this->_current_node_cache_neigh_all != v) { cache_neighbours(v, mode); this->_current_node_cache_neigh_all = v; } #ifdef DEBUG cerr << "Returning " << this->_cached_neighs_all.size() << " incoming neighbours" << endl; #endif return this->_cached_neighs_all; } throw Exception("Invalid mode for getting neighbours."); } /******************************************************************************** * This should return a random neighbour in O(1) ********************************************************************************/ size_t Graph::get_random_neighbour(size_t v, igraph_neimode_t mode, igraph_rng_t* rng) { size_t node=v; size_t rand_neigh = -1; if (this->degree(v, mode) <= 0) throw Exception("Cannot select a random neighbour for an isolated node."); if (this->is_directed() && mode != IGRAPH_ALL) { if (mode == IGRAPH_OUT) { // Get indices of where neighbours are size_t cum_degree_this_node = (size_t) VECTOR(this->_graph->os)[node]; size_t cum_degree_next_node = (size_t) VECTOR(this->_graph->os)[node+1]; // Get a random index from them size_t rand_neigh_idx = get_random_int(cum_degree_this_node, cum_degree_next_node - 1, rng); // Return the neighbour at that index #ifdef DEBUG cerr << "Degree: " << this->degree(node, mode) << " diff in cumulative: " << cum_degree_next_node - cum_degree_this_node << endl; #endif rand_neigh = VECTOR(this->_graph->to)[ (size_t)VECTOR(this->_graph->oi)[rand_neigh_idx] ]; } else if (mode == IGRAPH_IN) { // Get indices of where neighbours are size_t cum_degree_this_node = (size_t) VECTOR(this->_graph->is)[node]; size_t cum_degree_next_node = (size_t) VECTOR(this->_graph->is)[node+1]; // Get a random index from them size_t rand_neigh_idx = get_random_int(cum_degree_this_node, cum_degree_next_node - 1, rng); #ifdef DEBUG cerr << "Degree: " << this->degree(node, mode) << " diff in cumulative: " << cum_degree_next_node - cum_degree_this_node << endl; #endif // Return the neighbour at that index rand_neigh = VECTOR(this->_graph->from)[ (size_t)VECTOR(this->_graph->ii)[rand_neigh_idx] ]; } } else { // both in- and out- neighbors in a directed graph. size_t cum_outdegree_this_node = (size_t)VECTOR(this->_graph->os)[node]; size_t cum_indegree_this_node = (size_t)VECTOR(this->_graph->is)[node]; size_t cum_outdegree_next_node = (size_t)VECTOR(this->_graph->os)[node+1]; size_t cum_indegree_next_node = (size_t)VECTOR(this->_graph->is)[node+1]; size_t total_outdegree = cum_outdegree_next_node - cum_outdegree_this_node; size_t total_indegree = cum_indegree_next_node - cum_indegree_this_node; size_t rand_idx = get_random_int(0, total_outdegree + total_indegree - 1, rng); #ifdef DEBUG cerr << "Degree: " << this->degree(node, mode) << " diff in cumulative: " << total_outdegree + total_indegree << endl; #endif // From among in or out neighbours? if (rand_idx < total_outdegree) { // From among outgoing neighbours size_t rand_neigh_idx = cum_outdegree_this_node + rand_idx; rand_neigh = VECTOR(this->_graph->to)[ (size_t)VECTOR(this->_graph->oi)[rand_neigh_idx] ]; } else { // From among incoming neighbours size_t rand_neigh_idx = cum_indegree_this_node + rand_idx - total_outdegree; rand_neigh = VECTOR(this->_graph->from)[ (size_t)VECTOR(this->_graph->ii)[rand_neigh_idx] ]; } } return rand_neigh; } /**************************************************************************** Creates a graph with communities as node and links as weights between communities. The weight of the edges in the new graph is simply the sum of the weight of the edges between the communities. The self weight of a node (i.e. the weight of its self loop) is the internal weight of a community. The size of a node in the new graph is simply the size of the community in the old graph. *****************************************************************************/ Graph* Graph::collapse_graph(MutableVertexPartition* partition) { #ifdef DEBUG cerr << "Graph* Graph::collapse_graph(vector membership)" << endl; #endif #ifdef DEBUG cerr << "Current graph has " << this->vcount() << " nodes and " << this->ecount() << " edges." << endl; cerr << "Collapsing to graph with " << partition->n_communities() << " nodes." << endl; #endif size_t n_collapsed = partition->n_communities(); vector > community_memberships = partition->get_communities(); vector collapsed_weights; double total_collapsed_weight = 0.0; vector edge_weight_to_community(n_collapsed, 0.0); vector neighbour_comm_added(n_collapsed, false); // collapsed edges for new graph igraph_vector_t edges; igraph_vector_init(&edges, 0); for (size_t v_comm = 0; v_comm < n_collapsed; v_comm++) { vector neighbour_communities; for (size_t v : community_memberships[v_comm]) { for (size_t e : this->get_neighbour_edges(v, IGRAPH_OUT)) { size_t from, to; this->edge(e, from, to); if ((size_t) from != v) { // need to skip because IGRAPH_OUT is ignored for undirected graphs continue; } size_t u_comm = partition->membership(to); double w = this->edge_weight(e); // Self loops appear twice here if the graph is undirected, so divide by 2.0 in that case. if (from == to && !this->is_directed()) w /= 2.0; if (!neighbour_comm_added[u_comm]) { neighbour_comm_added[u_comm] = true; neighbour_communities.push_back(u_comm); } edge_weight_to_community[u_comm] += w; } } for (size_t u_comm : neighbour_communities) { igraph_vector_push_back(&edges, v_comm); igraph_vector_push_back(&edges, u_comm); collapsed_weights.push_back(edge_weight_to_community[u_comm]); total_collapsed_weight += edge_weight_to_community[u_comm]; // reset edge_weight_to_community to all 0.0 and neighbour_comm_added to all false edge_weight_to_community[u_comm] = 0.0; neighbour_comm_added[u_comm] = false; } } // Create graph based on edges igraph_t* graph = new igraph_t(); igraph_create(graph, &edges, n_collapsed, this->is_directed()); igraph_vector_destroy(&edges); if ((size_t) igraph_vcount(graph) != partition->n_communities()) throw Exception("Something went wrong with collapsing the graph."); // Calculate new node sizes vector csizes(n_collapsed, 0); for (size_t c = 0; c < partition->n_communities(); c++) csizes[c] = partition->csize(c); Graph* G = new Graph(graph, collapsed_weights, csizes, this->_correct_self_loops); G->_remove_graph = true; #ifdef DEBUG cerr << "exit Graph::collapse_graph(vector membership)" << endl << endl; #endif return G; } leidenalg-0.8.9/src/leidenalg/LinearResolutionParameterVertexPartition.cpp000066400000000000000000000017131420514302700271220ustar00rootroot00000000000000#include "LinearResolutionParameterVertexPartition.h" LinearResolutionParameterVertexPartition::LinearResolutionParameterVertexPartition(Graph* graph, vector membership, double resolution_parameter) : ResolutionParameterVertexPartition(graph, membership, resolution_parameter) { } LinearResolutionParameterVertexPartition::LinearResolutionParameterVertexPartition(Graph* graph, vector membership) : ResolutionParameterVertexPartition(graph, membership) { } LinearResolutionParameterVertexPartition::LinearResolutionParameterVertexPartition(Graph* graph, double resolution_parameter) : ResolutionParameterVertexPartition(graph, resolution_parameter) { } LinearResolutionParameterVertexPartition::LinearResolutionParameterVertexPartition(Graph* graph) : ResolutionParameterVertexPartition(graph) { } LinearResolutionParameterVertexPartition::~LinearResolutionParameterVertexPartition() { } leidenalg-0.8.9/src/leidenalg/ModularityVertexPartition.cpp000066400000000000000000000124211420514302700241120ustar00rootroot00000000000000#include "ModularityVertexPartition.h" #ifdef DEBUG #include using std::cerr; using std::endl; #endif ModularityVertexPartition::ModularityVertexPartition(Graph* graph, vector const& membership) : MutableVertexPartition(graph, membership) { } ModularityVertexPartition::ModularityVertexPartition(Graph* graph) : MutableVertexPartition(graph) { } ModularityVertexPartition::~ModularityVertexPartition() { } ModularityVertexPartition* ModularityVertexPartition::create(Graph* graph) { return new ModularityVertexPartition(graph); } ModularityVertexPartition* ModularityVertexPartition::create(Graph* graph, vector const& membership) { return new ModularityVertexPartition(graph, membership); } /***************************************************************************** Returns the difference in modularity if we move a node to a new community *****************************************************************************/ double ModularityVertexPartition::diff_move(size_t v, size_t new_comm) { #ifdef DEBUG cerr << "double ModularityVertexPartition::diff_move(" << v << ", " << new_comm << ")" << endl; #endif size_t old_comm = this->_membership[v]; double diff = 0.0; double total_weight = this->graph->total_weight()*(2.0 - this->graph->is_directed()); if (total_weight == 0.0) return 0.0; if (new_comm != old_comm) { #ifdef DEBUG cerr << "\t" << "old_comm: " << old_comm << endl; #endif double w_to_old = this->weight_to_comm(v, old_comm); #ifdef DEBUG cerr << "\t" << "w_to_old: " << w_to_old << endl; #endif double w_from_old = this->weight_from_comm(v, old_comm); #ifdef DEBUG cerr << "\t" << "w_from_old: " << w_from_old << endl; #endif double w_to_new = this->weight_to_comm(v, new_comm); #ifdef DEBUG cerr << "\t" << "w_to_new: " << w_to_new << endl; #endif double w_from_new = this->weight_from_comm(v, new_comm); #ifdef DEBUG cerr << "\t" << "w_from_new: " << w_from_new << endl; #endif double k_out = this->graph->strength(v, IGRAPH_OUT); #ifdef DEBUG cerr << "\t" << "k_out: " << k_out << endl; #endif double k_in = this->graph->strength(v, IGRAPH_IN); #ifdef DEBUG cerr << "\t" << "k_in: " << k_in << endl; #endif double self_weight = this->graph->node_self_weight(v); #ifdef DEBUG cerr << "\t" << "self_weight: " << self_weight << endl; #endif double K_out_old = this->total_weight_from_comm(old_comm); #ifdef DEBUG cerr << "\t" << "K_out_old: " << K_out_old << endl; #endif double K_in_old = this->total_weight_to_comm(old_comm); #ifdef DEBUG cerr << "\t" << "K_in_old: " << K_in_old << endl; #endif double K_out_new = this->total_weight_from_comm(new_comm) + k_out; #ifdef DEBUG cerr << "\t" << "K_out_new: " << K_out_new << endl; #endif double K_in_new = this->total_weight_to_comm(new_comm) + k_in; #ifdef DEBUG cerr << "\t" << "K_in_new: " << K_in_new << endl; cerr << "\t" << "total_weight: " << total_weight << endl; #endif double diff_old = (w_to_old - k_out*K_in_old/total_weight) + \ (w_from_old - k_in*K_out_old/total_weight); #ifdef DEBUG cerr << "\t" << "diff_old: " << diff_old << endl; #endif double diff_new = (w_to_new + self_weight - k_out*K_in_new/total_weight) + \ (w_from_new + self_weight - k_in*K_out_new/total_weight); #ifdef DEBUG cerr << "\t" << "diff_new: " << diff_new << endl; #endif diff = diff_new - diff_old; #ifdef DEBUG cerr << "\t" << "diff: " << diff << endl; #endif } #ifdef DEBUG cerr << "exit double ModularityVertexPartition::diff_move((" << v << ", " << new_comm << ")" << endl; cerr << "return " << diff << endl << endl; #endif double m; if (this->graph->is_directed()) m = this->graph->total_weight(); else m = 2*this->graph->total_weight(); return diff/m; } /***************************************************************************** Give the modularity of the partition. We here use the unscaled version of modularity, in other words, we don"t normalise by the number of edges. ******************************************************************************/ double ModularityVertexPartition::quality() { #ifdef DEBUG cerr << "double ModularityVertexPartition::quality()" << endl; #endif double mod = 0.0; double m; if (this->graph->is_directed()) m = this->graph->total_weight(); else m = 2*this->graph->total_weight(); if (m == 0) return 0.0; for (size_t c = 0; c < this->n_communities(); c++) { double w = this->total_weight_in_comm(c); double w_out = this->total_weight_from_comm(c); double w_in = this->total_weight_to_comm(c); #ifdef DEBUG size_t csize = this->csize(c); cerr << "\t" << "Comm: " << c << ", size=" << csize << ", w=" << w << ", w_out=" << w_out << ", w_in=" << w_in << "." << endl; #endif mod += w - w_out*w_in/((this->graph->is_directed() ? 1.0 : 4.0)*this->graph->total_weight()); } double q = (2.0 - this->graph->is_directed())*mod; #ifdef DEBUG cerr << "exit double ModularityVertexPartition::quality()" << endl; cerr << "return " << q/m << endl << endl; #endif return q/m; } leidenalg-0.8.9/src/leidenalg/MutableVertexPartition.cpp000066400000000000000000001020031420514302700233460ustar00rootroot00000000000000#include "MutableVertexPartition.h" #ifdef DEBUG using std::cerr; using std::endl; #endif /**************************************************************************** Create a new vertex partition. Parameters: graph -- The igraph.Graph on which this partition is defined. membership=None -- The membership vector of this partition, i.e. an community number for each node. So membership[i] = c implies that node i is in community c. If None, it is initialised with each node in its own community. weight_attr=None -- What edge attribute should be used as a weight for the edges? If None, the weight defaults to 1. size_attr=None -- What node attribute should be used for keeping track of the size of the node? In some methods (e.g. CPM or Significance), we need to keep track of the total size of the community. So when we aggregate/collapse the graph, we should know how many nodes were in a community. If None, the size of a node defaults to 1. self_weight_attr=None -- What node attribute should be used for the self weight? If None, the self_weight is recalculated each time.""" *****************************************************************************/ MutableVertexPartition::MutableVertexPartition(Graph* graph, vector const& membership) { this->destructor_delete_graph = false; this->graph = graph; if (membership.size() != graph->vcount()) { throw Exception("Membership vector has incorrect size."); } this->_membership = membership; this->init_admin(); } MutableVertexPartition::MutableVertexPartition(Graph* graph) { this->destructor_delete_graph = false; this->graph = graph; this->_membership = range(graph->vcount()); this->init_admin(); } MutableVertexPartition* MutableVertexPartition::create(Graph* graph) { return new MutableVertexPartition(graph); } MutableVertexPartition* MutableVertexPartition::create(Graph* graph, vector const& membership) { return new MutableVertexPartition(graph, membership); } MutableVertexPartition::~MutableVertexPartition() { this->clean_mem(); if (this->destructor_delete_graph) delete this->graph; } void MutableVertexPartition::clean_mem() { } size_t MutableVertexPartition::csize(size_t comm) { if (comm < this->_csize.size()) return this->_csize[comm]; else return 0; } size_t MutableVertexPartition::cnodes(size_t comm) { if (comm < this->_cnodes.size()) return this->_cnodes[comm]; else return 0; } vector MutableVertexPartition::get_community(size_t comm) { vector community; community.reserve(this->_cnodes[comm]); for (size_t i = 0; i < this->graph->vcount(); i++) if (this->_membership[i] == comm) community.push_back(i); return community; } vector< vector > MutableVertexPartition::get_communities() { vector< vector > communities(this->_n_communities); for (size_t c = 0; c < this->_n_communities; c++) { size_t cn = this->_cnodes[c]; communities[c].reserve(cn); } for (size_t i = 0; i < this->graph->vcount(); i++) communities[this->_membership[i]].push_back(i); return communities; } size_t MutableVertexPartition::n_communities() { return this->_n_communities; } /**************************************************************************** Initialise all the administration based on the membership vector. *****************************************************************************/ void MutableVertexPartition::init_admin() { #ifdef DEBUG cerr << "void MutableVertexPartition::init_admin()" << endl; #endif size_t n = this->graph->vcount(); // First determine number of communities (assuming they are consecutively numbered this->update_n_communities(); // Reset administration this->_total_weight_in_comm.clear(); this->_total_weight_in_comm.resize(this->_n_communities); this->_total_weight_from_comm.clear(); this->_total_weight_from_comm.resize(this->_n_communities); this->_total_weight_to_comm.clear(); this->_total_weight_to_comm.resize(this->_n_communities); this->_csize.clear(); this->_csize.resize(this->_n_communities); this->_cnodes.clear(); this->_cnodes.resize(this->_n_communities); this->_current_node_cache_community_from = n + 1; this->_cached_weight_from_community.resize(this->_n_communities, 0); this->_current_node_cache_community_to = n + 1; this->_cached_weight_to_community.resize(this->_n_communities, 0); this->_current_node_cache_community_all = n + 1; this->_cached_weight_all_community.resize(this->_n_communities, 0); this->_cached_neigh_comms_all.resize(n); if (this->get_graph()->is_directed()) { this->_cached_neigh_comms_from.resize(n); this->_cached_neigh_comms_to.resize(n); } this->_empty_communities.clear(); this->_total_weight_in_all_comms = 0.0; for (size_t v = 0; v < n; v++) { size_t v_comm = this->_membership[v]; // Update the community size this->_csize[v_comm] += this->graph->node_size(v); // Update the community size this->_cnodes[v_comm] += 1; } size_t m = graph->ecount(); for (size_t e = 0; e < m; e++) { size_t v, u; this->graph->edge(e, v, u); size_t v_comm = this->_membership[v]; size_t u_comm = this->_membership[u]; // Get the weight of the edge double w = this->graph->edge_weight(e); // Add weight to the outgoing weight of community of v this->_total_weight_from_comm[v_comm] += w; #ifdef DEBUG cerr << "\t" << "Add (" << v << ", " << u << ") weight " << w << " to from_comm " << v_comm << "." << endl; #endif // Add weight to the incoming weight of community of u this->_total_weight_to_comm[u_comm] += w; #ifdef DEBUG cerr << "\t" << "Add (" << v << ", " << u << ") weight " << w << " to to_comm " << u_comm << "." << endl; #endif if (!this->graph->is_directed()) { #ifdef DEBUG cerr << "\t" << "Add (" << u << ", " << v << ") weight " << w << " to from_comm " << u_comm << "." << endl; #endif this->_total_weight_from_comm[u_comm] += w; #ifdef DEBUG cerr << "\t" << "Add (" << u << ", " << v << ") weight " << w << " to to_comm " << v_comm << "." << endl; #endif this->_total_weight_to_comm[v_comm] += w; } // If it is an edge within a community if (v_comm == u_comm) { this->_total_weight_in_comm[v_comm] += w; this->_total_weight_in_all_comms += w; #ifdef DEBUG cerr << "\t" << "Add (" << v << ", " << u << ") weight " << w << " to in_comm " << v_comm << "." << endl; #endif } } this->_total_possible_edges_in_all_comms = 0; for (size_t c = 0; c < this->_n_communities; c++) { size_t n_c = this->csize(c); size_t possible_edges = this->graph->possible_edges(n_c); #ifdef DEBUG cerr << "\t" << "c=" << c << ", n_c=" << n_c << ", possible_edges=" << possible_edges << endl; #endif this->_total_possible_edges_in_all_comms += possible_edges; // It is possible that some community have a zero size (if the order // is for example not consecutive. We add those communities to the empty // communities vector for consistency. if (this->_cnodes[c] == 0) this->_empty_communities.push_back(c); } #ifdef DEBUG cerr << "exit MutableVertexPartition::init_admin()" << endl << endl; #endif } void MutableVertexPartition::update_n_communities() { this->_n_communities = 0; for (size_t i = 0; i < this->graph->vcount(); i++) if (this->_membership[i] >= this->_n_communities) this->_n_communities = this->_membership[i] + 1; } /**************************************************************************** Renumber the communities so that they are numbered 0,...,q-1 where q is the number of communities. This also removes any empty communities, as they will not be given a new number. *****************************************************************************/ void MutableVertexPartition::renumber_communities() { vector partitions(1); partitions[0] = this; vector new_comm_id = MutableVertexPartition::rank_order_communities(partitions); this->relabel_communities(new_comm_id); } /**************************************************************************** Renumber the communities according to the new labels in new_comm_id. This adjusts the internal bookkeeping as required, avoiding the more costly setup required in init_admin(). In particular, this avoids recomputation of weights in/from/to each community by simply assigning the previously computed values to the new, relabeled communities. For instance, a new_comm_id of <1, 2, 0> will change the labels such that community 0 becomes 1, community 1 becomes 2, and community 2 becomes 0. *****************************************************************************/ void MutableVertexPartition::relabel_communities(vector const& new_comm_id) { if (this->_n_communities != new_comm_id.size()) { throw Exception("Problem swapping community labels. Mismatch between n_communities and new_comm_id vector."); } size_t n = this->graph->vcount(); for (size_t i = 0; i < n; i++) this->_membership[i] = new_comm_id[this->_membership[i]]; this->update_n_communities(); size_t nbcomms = this->n_communities(); vector new_total_weight_in_comm(nbcomms, 0.0); vector new_total_weight_from_comm(nbcomms, 0.0); vector new_total_weight_to_comm(nbcomms, 0.0); vector new_csize(nbcomms, 0); vector new_cnodes(nbcomms, 0); // Relabel community admin for (size_t c = 0; c < new_comm_id.size(); c++) { size_t new_c = new_comm_id[c]; if (this->_cnodes[c] > 0) { new_total_weight_in_comm[new_c] = this->_total_weight_in_comm[c]; new_total_weight_from_comm[new_c] = this->_total_weight_from_comm[c]; new_total_weight_to_comm[new_c] = this->_total_weight_to_comm[c]; new_csize[new_c] = this->_csize[c]; new_cnodes[new_c] = this->_cnodes[c]; } } this->_total_weight_in_comm = new_total_weight_in_comm; this->_total_weight_from_comm = new_total_weight_from_comm; this->_total_weight_to_comm = new_total_weight_to_comm; this->_csize = new_csize; this->_cnodes = new_cnodes; this->_empty_communities.clear(); for (size_t c = 0; c < nbcomms; c++) { if (this->_cnodes[c] == 0) { this->_empty_communities.push_back(c); } } // invalidate cached weight vectors for (size_t c : this->_cached_neigh_comms_from) this->_cached_weight_from_community[c] = 0; this->_cached_neigh_comms_from.clear(); this->_cached_weight_from_community.resize(nbcomms, 0); this->_current_node_cache_community_from = n + 1; for (size_t c : this->_cached_neigh_comms_to) this->_cached_weight_to_community[c] = 0; this->_cached_neigh_comms_to.clear(); this->_cached_weight_to_community.resize(nbcomms, 0); this->_current_node_cache_community_to = n + 1; for (size_t c : this->_cached_neigh_comms_all) this->_cached_weight_all_community[c] = 0; this->_cached_neigh_comms_all.clear(); this->_cached_weight_all_community.resize(nbcomms, 0); this->_current_node_cache_community_all = n + 1; #ifdef DEBUG if (this->_csize.size() < this->_n_communities || this->_cnodes.size() < this->_n_communities || this->_total_weight_in_comm.size() < this->_n_communities || this->_total_weight_to_comm.size() < this->_n_communities || this->_total_weight_from_comm.size() < this->_n_communities || this->_cached_weight_from_community.size() < this->_n_communities || this->_cached_weight_to_community.size() < this->_n_communities || this->_cached_weight_all_community.size() < this->_n_communities) { cerr << "ERROR: MutableVertexPartition bookkeeping is too small after rearrange_community_labels." << endl; } this->init_admin(); for (size_t c = 0; c < this->_n_communities; c++) { if (fabs(new_total_weight_in_comm[c] - this->_total_weight_in_comm[c]) > 1e-6 || fabs(new_total_weight_from_comm[c] - this->_total_weight_from_comm[c]) > 1e-6 || fabs(new_total_weight_to_comm[c] - this->_total_weight_to_comm[c]) > 1e-6 || new_csize[c] != this->_csize[c] || new_cnodes[c] != this->_cnodes[c]) { cerr << "ERROR: MutableVertexPartition bookkeeping is incorrect after rearrange_community_labels." << endl; cerr << "Community c has " << endl << "total_weight_in_comm=" << new_total_weight_in_comm[c] << " (should be " << this->_total_weight_in_comm[c] << ")" << endl << "total_weight_from_comm=" << new_total_weight_from_comm[c] << " (should be " << this->_total_weight_from_comm[c] << ")" << endl << "total_weight_to_comm=" << new_total_weight_to_comm[c] << " (should be " << this->_total_weight_to_comm[c] << ")" << endl << "csize=" << new_csize[c] << " (should be " << this->_csize[c] << ")" << endl << "cnodes=" << new_cnodes[c] << " (should be " << this->_cnodes[c] << ")" << endl; } } #endif } vector MutableVertexPartition::rank_order_communities(vector partitions) { size_t nb_layers = partitions.size(); size_t nb_comms = partitions[0]->n_communities(); #ifdef DEBUG size_t n = partitions[0]->graph->vcount(); for (size_t layer = 0; layer < nb_layers; layer++) { for (size_t v = 0; v < n; v++) { if (partitions[0]->membership(v) != partitions[layer]->membership(v)) cerr << "Membership of all partitions are not equal"; } } #endif // First sort the communities by size // Csizes // first - community // second - csize // third - number of nodes (may be aggregate nodes), to account for communities with zero weight. vector csizes; for (size_t i = 0; i < nb_comms; i++) { size_t csize = 0; for (size_t layer = 0; layer < nb_layers; layer++) csize += partitions[layer]->csize(i); size_t* row = new size_t[3]; row[0] = i; row[1] = csize; row[2] = partitions[0]->cnodes(i); csizes.push_back(row); } sort(csizes.begin(), csizes.end(), orderCSize); // Then use the sort order to assign new communities, // such that the largest community gets the lowest index. vector new_comm_id(nb_comms, 0); for (size_t i = 0; i < nb_comms; i++) { size_t comm = csizes[i][0]; new_comm_id[comm] = i; delete[] csizes[i]; } return new_comm_id; } /**************************************************************************** Renumber the communities using the original fixed membership vector. Notice that this doesn't ensure any property of the community numbers. *****************************************************************************/ void MutableVertexPartition::renumber_communities(vector const& fixed_nodes, vector const& fixed_membership) { #ifdef DEBUG cerr << "void MutableVertexPartition::renumber_communities(" << &fixed_nodes << ", " << &fixed_membership << ")" << endl; #endif // Skip whole thing if there are no fixed nodes for efficiency if (fixed_nodes.size() == 0) return; // The number of communities does not depend on whether some are fixed size_t nb_comms = n_communities(); // Fill the community map with the original communities vector new_comm_id(nb_comms); vector comm_assigned_bool(nb_comms); priority_queue, std::greater > new_comm_assigned; for (size_t v : fixed_nodes) { if (!comm_assigned_bool[_membership[v]]) { size_t fixed_comm_v = fixed_membership[v]; #ifdef DEBUG cerr << "Setting map for fixed community " << fixed_comm_v << endl; #endif new_comm_id[_membership[v]] = fixed_comm_v; comm_assigned_bool[_membership[v]] = true; new_comm_assigned.push(fixed_comm_v); } } // Index of the most recently added community size_t cc = 0; for (size_t c = 0; c != nb_comms; c++) { if(!comm_assigned_bool[c]) { // Look for the first free integer while (!new_comm_assigned.empty() && cc == new_comm_assigned.top()) { new_comm_assigned.pop(); cc++; } // Assign the community #ifdef DEBUG cerr << "Setting map for free community " << cc << endl; #endif new_comm_id[c] = cc++; } } this->relabel_communities(new_comm_id); } void MutableVertexPartition::renumber_communities(vector const& membership) { cerr << "This function is deprecated, use MutableVertexPartition::set_membership(vector const& membership)" << endl; this->set_membership(membership); } size_t MutableVertexPartition::get_empty_community() { if (this->_empty_communities.empty()) { // If there was no empty community yet, // we will create a new one. add_empty_community(); } return this->_empty_communities.back(); } void MutableVertexPartition::set_membership(vector const& membership) { #ifdef DEBUG cerr << "void MutableVertexPartition::set_membership(" << &membership << ")" << endl; #endif this->_membership = membership; this->clean_mem(); this->init_admin(); #ifdef DEBUG cerr << "exit MutableVertexPartition::set_membership(" << &membership << ")" << endl; #endif } size_t MutableVertexPartition::add_empty_community() { this->_n_communities = this->_n_communities + 1; if (this->_n_communities > this->graph->vcount()) throw Exception("There cannot be more communities than nodes, so there must already be an empty community."); size_t new_comm = this->_n_communities - 1; this->_csize.resize(this->_n_communities); this->_csize[new_comm] = 0; this->_cnodes.resize(this->_n_communities); this->_cnodes[new_comm] = 0; this->_total_weight_in_comm.resize(this->_n_communities); this->_total_weight_in_comm[new_comm] = 0; this->_total_weight_from_comm.resize(this->_n_communities); this->_total_weight_from_comm[new_comm] = 0; this->_total_weight_to_comm.resize(this->_n_communities); this->_total_weight_to_comm[new_comm] = 0; this->_cached_weight_all_community.resize(this->_n_communities); this->_cached_weight_from_community.resize(this->_n_communities); this->_cached_weight_to_community.resize(this->_n_communities); this->_empty_communities.push_back(new_comm); #ifdef DEBUG cerr << "Added empty community " << new_comm << endl; #endif return new_comm; } /**************************************************************************** Move a node to a new community and update the administration. Parameters: v -- Node to move. new_comm -- To which community should it move. *****************************************************************************/ void MutableVertexPartition::move_node(size_t v,size_t new_comm) { #ifdef DEBUG cerr << "void MutableVertexPartition::move_node(" << v << ", " << new_comm << ")" << endl; if (new_comm >= this->n_communities()) cerr << "ERROR: New community (" << new_comm << ") larger than total number of communities (" << this->n_communities() << ")." << endl; #endif // Move node and update internal administration if (new_comm >= this->_n_communities) { if (new_comm < this->graph->vcount()) { while (new_comm >= this->_n_communities) this->add_empty_community(); } else { throw Exception("Cannot add new communities beyond the number of nodes."); } } // Keep track of all possible edges in all communities; size_t node_size = this->graph->node_size(v); size_t old_comm = this->_membership[v]; #ifdef DEBUG cerr << "Node size: " << node_size << ", old comm: " << old_comm << ", new comm: " << new_comm << endl; #endif // Incidentally, this is independent of whether we take into account self-loops or not // (i.e. whether we count as n_c^2 or as n_c(n_c - 1). Be careful to do this before the // adaptation of the community sizes, otherwise the calculations are incorrect. if (new_comm != old_comm) { double delta_possible_edges_in_comms = 2.0*node_size*(ptrdiff_t)(this->_csize[new_comm] - this->_csize[old_comm] + node_size)/(2.0 - this->graph->is_directed()); _total_possible_edges_in_all_comms += delta_possible_edges_in_comms; #ifdef DEBUG cerr << "Change in possible edges in all comms: " << delta_possible_edges_in_comms << endl; #endif } // Remove from old community #ifdef DEBUG cerr << "Removing from old community " << old_comm << ", community size: " << this->_csize[old_comm] << endl; #endif this->_cnodes[old_comm] -= 1; this->_csize[old_comm] -= node_size; #ifdef DEBUG cerr << "Removed from old community." << endl; #endif // We have to use the size of the set of nodes rather than the csize // to account for nodes that have a zero size (i.e. community may not be empty, but // may have zero size). if (this->_cnodes[old_comm] == 0) { #ifdef DEBUG cerr << "Adding community " << old_comm << " to empty communities." << endl; #endif this->_empty_communities.push_back(old_comm); #ifdef DEBUG cerr << "Added community " << old_comm << " to empty communities." << endl; #endif } if (this->_cnodes[new_comm] == 0) { #ifdef DEBUG cerr << "Removing from empty communities (number of empty communities is " << this->_empty_communities.size() << ")." << endl; #endif vector::reverse_iterator it_comm = this->_empty_communities.rbegin(); while (it_comm != this->_empty_communities.rend() && *it_comm != new_comm) { #ifdef DEBUG cerr << "Empty community " << *it_comm << " != new community " << new_comm << endl; #endif it_comm++; } #ifdef DEBUG cerr << "Erasing empty community " << *it_comm << endl; if (it_comm == this->_empty_communities.rend()) cerr << "ERROR: empty community does not exist." << endl; #endif if (it_comm != this->_empty_communities.rend()) this->_empty_communities.erase( (++it_comm).base() ); } #ifdef DEBUG cerr << "Adding to new community " << new_comm << ", community size: " << this->_csize[new_comm] << endl; #endif // Add to new community this->_cnodes[new_comm] += 1; this->_csize[new_comm] += this->graph->node_size(v); // Switch outgoing links #ifdef DEBUG cerr << "Added to new community." << endl; #endif // Use set for incident edges, because self loop appears twice igraph_neimode_t modes[2] = {IGRAPH_OUT, IGRAPH_IN}; for (size_t mode_i = 0; mode_i < 2; mode_i++) { igraph_neimode_t mode = modes[mode_i]; // Loop over all incident edges vector const& neighbours = this->graph->get_neighbours(v, mode); vector const& neighbour_edges = this->graph->get_neighbour_edges(v, mode); size_t degree = neighbours.size(); #ifdef DEBUG if (mode == IGRAPH_OUT) cerr << "\t" << "Looping over outgoing links." << endl; else if (mode == IGRAPH_IN) cerr << "\t" << "Looping over incoming links." << endl; else cerr << "\t" << "Looping over unknown mode." << endl; #endif for (size_t idx = 0; idx < degree; idx++) { size_t u = neighbours[idx]; size_t e = neighbour_edges[idx]; size_t u_comm = this->_membership[u]; // Get the weight of the edge double w = this->graph->edge_weight(e); if (mode == IGRAPH_OUT) { // Remove the weight from the outgoing weights of the old community this->_total_weight_from_comm[old_comm] -= w; // Add the weight to the outgoing weights of the new community this->_total_weight_from_comm[new_comm] += w; #ifdef DEBUG cerr << "\t" << "Moving link (" << v << "-" << u << ") " << "outgoing weight " << w << " from " << old_comm << " to " << new_comm << "." << endl; #endif } else if (mode == IGRAPH_IN) { // Remove the weight from the outgoing weights of the old community this->_total_weight_to_comm[old_comm] -= w; // Add the weight to the outgoing weights of the new community this->_total_weight_to_comm[new_comm] += w; #ifdef DEBUG cerr << "\t" << "Moving link (" << v << "-" << u << ") " << "incoming weight " << w << " from " << old_comm << " to " << new_comm << "." << endl; #endif } else throw Exception("Incorrect mode for updating the admin."); // Get internal weight (if it is an internal edge) double int_weight = w/(this->graph->is_directed() ? 1.0 : 2.0)/( u == v ? 2.0 : 1.0); // If it is an internal edge in the old community if (old_comm == u_comm) { // Remove the internal weight this->_total_weight_in_comm[old_comm] -= int_weight; this->_total_weight_in_all_comms -= int_weight; #ifdef DEBUG cerr << "\t" << "From link (" << v << "-" << u << ") " << "remove internal weight " << int_weight << " from " << old_comm << "." << endl; #endif } // If it is an internal edge in the new community // i.e. if u is in the new community, or if it is a self loop if ((new_comm == u_comm) || (u == v)) { // Add the internal weight this->_total_weight_in_comm[new_comm] += int_weight; this->_total_weight_in_all_comms += int_weight; #ifdef DEBUG cerr << "\t" << "From link (" << v << "-" << u << ") " << "add internal weight " << int_weight << " to " << new_comm << "." << endl; #endif } } } #ifdef DEBUG // Check this->_total_weight_in_all_comms double check_total_weight_in_all_comms = 0.0; for (size_t c = 0; c < this->n_communities(); c++) check_total_weight_in_all_comms += this->total_weight_in_comm(c); cerr << "Internal _total_weight_in_all_comms=" << this->_total_weight_in_all_comms << ", calculated check_total_weight_in_all_comms=" << check_total_weight_in_all_comms << endl; #endif // Update the membership vector this->_membership[v] = new_comm; #ifdef DEBUG cerr << "exit MutableVertexPartition::move_node(" << v << ", " << new_comm << ")" << endl << endl; #endif } /**************************************************************************** Read new communities from coarser partition assuming that the community represents a node in the coarser partition (with the same index as the community number). ****************************************************************************/ void MutableVertexPartition::from_coarse_partition(vector const& coarse_partition_membership) { this->from_coarse_partition(coarse_partition_membership, this->_membership); } void MutableVertexPartition::from_coarse_partition(MutableVertexPartition* coarse_partition) { this->from_coarse_partition(coarse_partition, this->_membership); } void MutableVertexPartition::from_coarse_partition(MutableVertexPartition* coarse_partition, vector const& coarse_node) { this->from_coarse_partition(coarse_partition->membership(), coarse_node); } /**************************************************************************** Set the current community of all nodes to the community specified in the partition assuming that the coarser partition is created using the membership as specified by coarser_membership. In other words node i becomes node coarse_node[i] in the coarser partition and thus has community coarse_partition_membership[coarse_node[i]]. ****************************************************************************/ void MutableVertexPartition::from_coarse_partition(vector const& coarse_partition_membership, vector const& coarse_node) { // Read the coarser partition for (size_t v = 0; v < this->graph->vcount(); v++) { // In the coarser partition, the node should have the community id // as represented by the coarser_membership vector size_t v_level2 = coarse_node[v]; // In the coarser partition, this node is represented by v_level2 size_t v_comm_level2 = coarse_partition_membership[v_level2]; // Set local membership to community found for node at second level this->_membership[v] = v_comm_level2; } this->clean_mem(); this->init_admin(); } /**************************************************************************** Read new partition from another partition. ****************************************************************************/ void MutableVertexPartition::from_partition(MutableVertexPartition* partition) { // Assign the membership of every node in the supplied partition // to the one in this partition for (size_t v = 0; v < this->graph->vcount(); v++) this->_membership[v] = partition->membership(v); this->clean_mem(); this->init_admin(); } void MutableVertexPartition::cache_neigh_communities(size_t v, igraph_neimode_t mode) { // TODO: We can probably calculate at once the IN, OUT and ALL // rather than this being called multiple times. // Weight between vertex and community #ifdef DEBUG cerr << "double MutableVertexPartition::cache_neigh_communities(" << v << ", " << mode << ")." << endl; #endif vector* _cached_weight_tofrom_community = NULL; vector* _cached_neighs_comms = NULL; switch (mode) { case IGRAPH_IN: _cached_weight_tofrom_community = &(this->_cached_weight_from_community); _cached_neighs_comms = &(this->_cached_neigh_comms_from); break; case IGRAPH_OUT: _cached_weight_tofrom_community = &(this->_cached_weight_to_community); _cached_neighs_comms = &(this->_cached_neigh_comms_to); break; case IGRAPH_ALL: _cached_weight_tofrom_community = &(this->_cached_weight_all_community); _cached_neighs_comms = &(this->_cached_neigh_comms_all); break; } // Reset cached communities for (size_t c : *_cached_neighs_comms) (*_cached_weight_tofrom_community)[c] = 0; // Loop over all incident edges vector const& neighbours = this->graph->get_neighbours(v, mode); vector const& neighbour_edges = this->graph->get_neighbour_edges(v, mode); size_t degree = neighbours.size(); // Reset cached neighbours _cached_neighs_comms->clear(); for (size_t idx = 0; idx < degree; idx++) { size_t u = neighbours[idx]; size_t e = neighbour_edges[idx]; // If it is an edge to the requested community #ifdef DEBUG size_t v_comm = this->_membership[v]; #endif size_t comm = this->_membership[u]; // Get the weight of the edge double w = this->graph->edge_weight(e); // Self loops appear twice here if the graph is undirected, so divide by 2.0 in that case. if (u == v && !this->graph->is_directed()) w /= 2.0; #ifdef DEBUG cerr << "\t" << "Edge (" << v << "-" << u << "), Comm (" << v_comm << "-" << comm << ") weight: " << w << "." << endl; #endif (*_cached_weight_tofrom_community)[comm] += w; // REMARK: Notice in the rare case of negative weights, being exactly equal // for a certain community, that this community may then potentially be added multiple // times to the _cached_neighs. However, I don' believe this causes any further issue, // so that's why I leave this here as is. if ((*_cached_weight_tofrom_community)[comm] != 0) _cached_neighs_comms->push_back(comm); } #ifdef DEBUG cerr << "exit Graph::cache_neigh_communities(" << v << ", " << mode << ")." << endl; #endif } vector const& MutableVertexPartition::get_neigh_comms(size_t v, igraph_neimode_t mode) { if (!this->get_graph()->is_directed()) mode = IGRAPH_ALL; // igraph ignores mode for undirected graphs switch (mode) { case IGRAPH_IN: if (this->_current_node_cache_community_from != v) { cache_neigh_communities(v, mode); this->_current_node_cache_community_from = v; } return this->_cached_neigh_comms_from; case IGRAPH_OUT: if (this->_current_node_cache_community_to != v) { cache_neigh_communities(v, mode); this->_current_node_cache_community_to = v; } return this->_cached_neigh_comms_to; case IGRAPH_ALL: if (this->_current_node_cache_community_all != v) { cache_neigh_communities(v, mode); this->_current_node_cache_community_all = v; } return this->_cached_neigh_comms_all; } throw Exception("Problem obtaining neighbour communities, invalid mode."); } vector MutableVertexPartition::get_neigh_comms(size_t v, igraph_neimode_t mode, vector const& constrained_membership) { vector neigh_comms; vector comm_added(this->n_communities(), false); for (size_t u : this->graph->get_neighbours(v, mode)) { if (constrained_membership[v] == constrained_membership[u]) { size_t comm = this->membership(u); if (!comm_added[comm]) { neigh_comms.push_back(comm); comm_added[comm]; } } } return neigh_comms; } leidenalg-0.8.9/src/leidenalg/Optimiser.cpp000066400000000000000000001614661420514302700206620ustar00rootroot00000000000000#include "Optimiser.h" /**************************************************************************** Create a new Optimiser object Be sure to call igraph_i_set_attribute_table(&igraph_cattribute_table); before using this package, otherwise the attribute handling will not be dealt with correctly. Parameters: consider_comms -- Consider communities in a specific manner: ALL_COMMS -- Consider all communities for improvement. ALL_NEIGH_COMMS -- Consider all neighbour communities for improvement. RAND_COMM -- Consider a random commmunity for improvement. RAND_NEIGH_COMM -- Consider a random community among the neighbours for improvement. ****************************************************************************/ Optimiser::Optimiser() { this->consider_comms = Optimiser::ALL_NEIGH_COMMS; this->optimise_routine = Optimiser::MOVE_NODES; this->refine_consider_comms = Optimiser::ALL_NEIGH_COMMS; this->refine_routine = Optimiser::MERGE_NODES; this->refine_partition = true; this->consider_empty_community = true; this->max_comm_size = 0; igraph_rng_init(&rng, &igraph_rngtype_mt19937); igraph_rng_seed(&rng, time(NULL)); } Optimiser::~Optimiser() { igraph_rng_destroy(&rng); } void Optimiser::print_settings() { cerr << "Consider communities method:\t" << this->consider_comms << endl; cerr << "Refine partition:\t" << this->refine_partition << endl; } /***************************************************************************** optimise the provided partition. *****************************************************************************/ double Optimiser::optimise_partition(MutableVertexPartition* partition) { size_t n = partition->get_graph()->vcount(); vector is_membership_fixed(n, false); return this->optimise_partition(partition, is_membership_fixed); } double Optimiser::optimise_partition(MutableVertexPartition* partition, vector const& is_membership_fixed) { return this->optimise_partition(partition, is_membership_fixed, this->max_comm_size); } double Optimiser::optimise_partition(MutableVertexPartition* partition, vector const& is_membership_fixed, size_t max_comm_size) { vector partitions(1); partitions[0] = partition; vector layer_weights(1, 1.0); return this->optimise_partition(partitions, layer_weights, is_membership_fixed, max_comm_size); } double Optimiser::optimise_partition(vector partitions, vector layer_weights, vector const& is_membership_fixed) { return this->optimise_partition(partitions, layer_weights, is_membership_fixed, this->max_comm_size); } /***************************************************************************** optimise the providede partitions simultaneously. We here use the sum of the difference of the moves as the overall quality function, each partition weighted by the layer weight. *****************************************************************************/ /***************************************************************************** optimise the provided partition. *****************************************************************************/ double Optimiser::optimise_partition(vector partitions, vector layer_weights, vector const& is_membership_fixed, size_t max_comm_size) { #ifdef DEBUG cerr << "void Optimiser::optimise_partition(vector partitions, vector layer_weights, vector const& is_membership_fixed, size_t max_comm_size)" << endl; #endif double q = 0.0; // Number of multiplex layers size_t nb_layers = partitions.size(); if (nb_layers == 0) throw Exception("No partitions provided."); // Get graphs for all layers vector graphs(nb_layers); for (size_t layer = 0; layer < nb_layers; layer++) graphs[layer] = partitions[layer]->get_graph(); // Number of nodes in the graphs. Should be the same across // all graphs, so we only take the first one. size_t n = graphs[0]->vcount(); // Make sure that all graphs contain the exact same number of nodes. // We assume the index of each vertex in the graph points to the // same node (but then in a different layer). for (Graph* graph : graphs) if (graph->vcount() != n) throw Exception("Number of nodes are not equal for all graphs."); // Get the fixed membership for fixed nodes vector fixed_nodes; vector fixed_membership(n); for (size_t v = 0; v < n; v++) { if (is_membership_fixed[v]) { fixed_nodes.push_back(v); fixed_membership[v] = partitions[0]->membership(v); } } // Initialize the vector of the collapsed graphs for all layers vector collapsed_graphs(nb_layers); vector collapsed_partitions(nb_layers); // Declare the collapsed_graph variable which will contain the graph // collapsed by its communities. We will use this variables at each // further iteration, so we don't keep a collapsed graph at each pass. for (size_t layer = 0; layer < nb_layers; layer++) { collapsed_graphs[layer] = graphs[layer]; collapsed_partitions[layer] = partitions[layer]; } // Declare which nodes in the collapsed graph are fixed, which to start is // simply equal to is_membership_fixed vector is_collapsed_membership_fixed(is_membership_fixed); // This reflects the aggregate node, which to start with is simply equal to the graph. vector aggregate_node_per_individual_node = range(n); bool aggregate_further = true; // As long as there remains improvement iterate double improv = 0.0; do { // Optimise partition for collapsed graph #ifdef DEBUG q = 0.0; for (size_t layer = 0; layer < nb_layers; layer++) q += partitions[layer]->quality()*layer_weights[layer]; cerr << "Quality before moving " << q << endl; #endif if (this->optimise_routine == Optimiser::MOVE_NODES) improv += this->move_nodes(collapsed_partitions, layer_weights, is_collapsed_membership_fixed, this->consider_comms, this->consider_empty_community, false, max_comm_size); else if (this->optimise_routine == Optimiser::MERGE_NODES) improv += this->merge_nodes(collapsed_partitions, layer_weights, is_collapsed_membership_fixed, this->consider_comms, false, max_comm_size); #ifdef DEBUG cerr << "Found " << collapsed_partitions[0]->n_communities() << " communities, improved " << improv << endl; q = 0.0; for (size_t layer = 0; layer < nb_layers; layer++) q += partitions[layer]->quality()*layer_weights[layer]; cerr << "Quality after moving " << q << endl; #endif // DEBUG // Make sure improvement on coarser scale is reflected on the // scale of the graph as a whole. for (size_t layer = 0; layer < nb_layers; layer++) { if (collapsed_partitions[layer] != partitions[layer]) { if (this->refine_partition) partitions[layer]->from_coarse_partition(collapsed_partitions[layer], aggregate_node_per_individual_node); else partitions[layer]->from_coarse_partition(collapsed_partitions[layer]); } } #ifdef DEBUG q = 0.0; for (size_t layer = 0; layer < nb_layers; layer++) q += partitions[layer]->quality()*layer_weights[layer]; cerr << "Quality on finer partition " << q << endl; #endif // DEBUG #ifdef DEBUG cerr << "Number of communities: " << partitions[0]->n_communities() << endl; #endif // Collapse graph (i.e. community graph) // If we do refine the partition, we separate communities in slightly more // fine-grained parts for which we collapse the graph. vector sub_collapsed_partitions(nb_layers); vector new_collapsed_graphs(nb_layers); vector new_collapsed_partitions(nb_layers); if (this->refine_partition) { // First create a new partition, which should be a sub partition // of the collapsed partition, i.e. such that all clusters of // the partition are strictly partitioned in the subpartition. #ifdef DEBUG cerr << "\tBefore SLM " << collapsed_partitions[0]->n_communities() << " communities." << endl; #endif for (size_t layer = 0; layer < nb_layers; layer++) { sub_collapsed_partitions[layer] = collapsed_partitions[layer]->create(collapsed_graphs[layer]); } // Then move around nodes but restrict movement to within original communities. #ifdef DEBUG cerr << "\tStarting refinement with " << sub_collapsed_partitions[0]->n_communities() << " communities." << endl; #endif if (this->refine_routine == Optimiser::MOVE_NODES) this->move_nodes_constrained(sub_collapsed_partitions, layer_weights, refine_consider_comms, collapsed_partitions[0], max_comm_size); else if (this->refine_routine == Optimiser::MERGE_NODES) this->merge_nodes_constrained(sub_collapsed_partitions, layer_weights, refine_consider_comms, collapsed_partitions[0], max_comm_size); #ifdef DEBUG cerr << "\tAfter applying refinement found " << sub_collapsed_partitions[0]->n_communities() << " communities." << endl; #endif // Determine new aggregate node per individual node for (size_t v = 0; v < n; v++) { size_t aggregate_node = aggregate_node_per_individual_node[v]; aggregate_node_per_individual_node[v] = sub_collapsed_partitions[0]->membership(aggregate_node); } // Collapse graph based on sub collapsed partition for (size_t layer = 0; layer < nb_layers; layer++) { new_collapsed_graphs[layer] = collapsed_graphs[layer]->collapse_graph(sub_collapsed_partitions[layer]); } // Determine the membership for the collapsed graph vector new_collapsed_membership(new_collapsed_graphs[0]->vcount()); // Every node within the collapsed graph should be assigned // to the community of the original partition before the refinement. // We thus check for each node what the community is in the refined partition // and set the membership equal to the original partition (i.e. // even though the aggregation may be slightly different, the // membership of the aggregated nodes is as indicated by the original partition.) #ifdef DEBUG //cerr << "Refinement\tOrig" << endl; #endif // DEBUG for (size_t v = 0; v < collapsed_graphs[0]->vcount(); v++) { size_t new_aggregate_node = sub_collapsed_partitions[0]->membership(v); new_collapsed_membership[new_aggregate_node] = collapsed_partitions[0]->membership(v); #ifdef DEBUG //cerr << sub_collapsed_partition->membership(v) << "\t" << sub_collapsed_partition->membership(v) << endl; #endif // DEBUG } // Determine which collapsed nodes are fixed is_collapsed_membership_fixed.clear(); is_collapsed_membership_fixed.resize(new_collapsed_graphs[0]->vcount(), false); for (size_t v = 0; v < n; v++) if (is_membership_fixed[v]) is_collapsed_membership_fixed[aggregate_node_per_individual_node[v]] = true; // Create new collapsed partition for (size_t layer = 0; layer < nb_layers; layer++) { delete sub_collapsed_partitions[layer]; new_collapsed_partitions[layer] = collapsed_partitions[layer]->create(new_collapsed_graphs[layer], new_collapsed_membership); } } else { for (size_t layer = 0; layer < nb_layers; layer++) { new_collapsed_graphs[layer] = collapsed_graphs[layer]->collapse_graph(collapsed_partitions[layer]); // Create collapsed partition (i.e. default partition of each node in its own community). new_collapsed_partitions[layer] = collapsed_partitions[layer]->create(new_collapsed_graphs[layer]); #ifdef DEBUG cerr << "Layer " << layer << endl; cerr << "Old collapsed graph " << collapsed_graphs[layer] << ", vcount is " << collapsed_graphs[layer]->vcount() << endl; cerr << "New collapsed graph " << new_collapsed_graphs[layer] << ", vcount is " << new_collapsed_graphs[layer]->vcount() << endl; #endif } } // Determine whether to aggregate further // If all is fixed, no need to aggregate aggregate_further = false; for (const bool& membership_fixed : is_collapsed_membership_fixed) { if(!membership_fixed) { aggregate_further = true; break; } } // else, check whether anything has stirred since last time aggregate_further &= (new_collapsed_graphs[0]->vcount() < collapsed_graphs[0]->vcount()) && (collapsed_graphs[0]->vcount() > collapsed_partitions[0]->n_communities()); #ifdef DEBUG cerr << "Aggregate further " << aggregate_further << endl; #endif // Delete the previous collapsed partition and graph for (size_t layer = 0; layer < nb_layers; layer++) { if (collapsed_partitions[layer] != partitions[layer]) delete collapsed_partitions[layer]; if (collapsed_graphs[layer] != graphs[layer]) delete collapsed_graphs[layer]; } // and set them to the new one. collapsed_partitions = new_collapsed_partitions; collapsed_graphs = new_collapsed_graphs; #ifdef DEBUG for (size_t layer = 0; layer < nb_layers; layer++) { cerr << "Calculate partition " << layer << " quality." << endl; q = partitions[layer]->quality()*layer_weights[layer]; cerr << "Calculate collapsed partition quality." << endl; double q_collapsed = 0.0; q_collapsed += collapsed_partitions[layer]->quality()*layer_weights[layer]; if (fabs(q - q_collapsed) > 1e-6) { cerr << "ERROR: Quality of original partition and collapsed partition are not equal." << endl; } cerr << "partition->quality()=" << q << ", collapsed_partition->quality()=" << q_collapsed << endl; cerr << "graph->total_weight()=" << graphs[layer]->total_weight() << ", collapsed_graph->total_weight()=" << collapsed_graphs[layer]->total_weight() << endl; cerr << "graph->vcount()=" << graphs[layer]->vcount() << ", collapsed_graph->vcount()=" << collapsed_graphs[layer]->vcount() << endl; cerr << "graph->ecount()=" << graphs[layer]->ecount() << ", collapsed_graph->ecount()=" << collapsed_graphs[layer]->ecount() << endl; cerr << "graph->is_directed()=" << graphs[layer]->is_directed() << ", collapsed_graph->is_directed()=" << collapsed_graphs[layer]->is_directed() << endl; cerr << "graph->correct_self_loops()=" << graphs[layer]->correct_self_loops() << ", collapsed_graph->correct_self_loops()=" << collapsed_graphs[layer]->correct_self_loops() << endl << endl; } #endif // DEBUG } while (aggregate_further); // Clean up memory after use. for (size_t layer = 0; layer < nb_layers; layer++) { if (collapsed_partitions[layer] != partitions[layer]) delete collapsed_partitions[layer]; if (collapsed_graphs[layer] != graphs[layer]) delete collapsed_graphs[layer]; } // Make sure the resulting communities are called 0,...,r-1 // where r is the number of communities. The exception is fixed // nodes which should keep the numbers of the original communities q = 0.0; partitions[0]->renumber_communities(); partitions[0]->renumber_communities(fixed_nodes, fixed_membership); vector const& membership = partitions[0]->membership(); // We only renumber the communities for the first graph, // since the communities for the other graphs should just be equal // to the membership of the first graph. for (size_t layer = 1; layer < nb_layers; layer++) { partitions[layer]->set_membership(membership); q += partitions[layer]->quality()*layer_weights[layer]; } return improv; } /***************************************************************************** Move nodes to other communities depending on how other communities are considered, see consider_comms parameter of the class. Parameters: partition -- The partition to optimise. ******************************************************************************/ double Optimiser::move_nodes(MutableVertexPartition* partition) { return this->move_nodes(partition, this->consider_comms); } double Optimiser::move_nodes(MutableVertexPartition* partition, int consider_comms) { vector is_membership_fixed(partition->get_graph()->vcount()); return this->move_nodes(partition, is_membership_fixed, consider_comms, false); } double Optimiser::move_nodes(MutableVertexPartition* partition, vector const& is_membership_fixed, int consider_comms, bool renumber_fixed_nodes) { return this->move_nodes(partition, is_membership_fixed, consider_comms, renumber_fixed_nodes, this->max_comm_size); } double Optimiser::move_nodes(MutableVertexPartition* partition, vector const& is_membership_fixed, int consider_comms, bool renumber_fixed_nodes, size_t max_comm_size) { vector partitions(1); partitions[0] = partition; vector layer_weights(1, 1.0); return this->move_nodes(partitions, layer_weights, is_membership_fixed, consider_comms, this->consider_empty_community, renumber_fixed_nodes, max_comm_size); } double Optimiser::merge_nodes(MutableVertexPartition* partition) { return this->merge_nodes(partition, this->consider_comms); } double Optimiser::merge_nodes(MutableVertexPartition* partition, int consider_comms) { vector is_membership_fixed(partition->get_graph()->vcount()); return this->merge_nodes(partition, is_membership_fixed, consider_comms, false); } double Optimiser::merge_nodes(MutableVertexPartition* partition, vector const& is_membership_fixed, int consider_comms, bool renumber_fixed_nodes) { return this->merge_nodes(partition, is_membership_fixed, consider_comms, renumber_fixed_nodes, this->max_comm_size); } double Optimiser::merge_nodes(MutableVertexPartition* partition, vector const& is_membership_fixed, int consider_comms, bool renumber_fixed_nodes, size_t max_comm_size) { vector partitions(1); partitions[0] = partition; vector layer_weights(1, 1.0); return this->merge_nodes(partitions, layer_weights, is_membership_fixed, consider_comms, renumber_fixed_nodes, max_comm_size); } double Optimiser::move_nodes_constrained(MutableVertexPartition* partition, MutableVertexPartition* constrained_partition) { return this->move_nodes_constrained(partition, this->refine_consider_comms, constrained_partition); } double Optimiser::move_nodes_constrained(MutableVertexPartition* partition, int consider_comms, MutableVertexPartition* constrained_partition) { return this->move_nodes_constrained(partition, consider_comms, constrained_partition, this->max_comm_size); } double Optimiser::move_nodes_constrained(MutableVertexPartition* partition, int consider_comms, MutableVertexPartition* constrained_partition, size_t max_comm_size) { vector partitions(1); partitions[0] = partition; vector layer_weights(1, 1.0); return this->move_nodes_constrained(partitions, layer_weights, consider_comms, constrained_partition, max_comm_size); } double Optimiser::merge_nodes_constrained(MutableVertexPartition* partition, MutableVertexPartition* constrained_partition) { return this->merge_nodes_constrained(partition, this->refine_consider_comms, constrained_partition); } double Optimiser::merge_nodes_constrained(MutableVertexPartition* partition, int consider_comms, MutableVertexPartition* constrained_partition) { return this->merge_nodes_constrained(partition, consider_comms, constrained_partition, this->max_comm_size); } double Optimiser::merge_nodes_constrained(MutableVertexPartition* partition, int consider_comms, MutableVertexPartition* constrained_partition, size_t max_comm_size) { vector partitions(1); partitions[0] = partition; vector layer_weights(1, 1.0); return this->merge_nodes_constrained(partitions, layer_weights, consider_comms, constrained_partition, max_comm_size); } /***************************************************************************** Move nodes to neighbouring communities such that each move improves the given quality function maximally (i.e. greedily) for multiple layers, i.e. for multiplex networks. Each node will be in the same community in each layer, but the method may be different, or the weighting may be different for different layers. Notably, this can be used in the case of negative links, where you would like to weigh the negative links with a negative weight. Parameters: partitions -- The partitions to optimise. layer_weights -- The weights used for the different layers. ******************************************************************************/ double Optimiser::move_nodes(vector partitions, vector layer_weights, vector const& is_membership_fixed, bool renumber_fixed_nodes) { return this->move_nodes(partitions, layer_weights, is_membership_fixed, this->consider_comms, this->consider_empty_community, renumber_fixed_nodes); } double Optimiser::move_nodes(vector partitions, vector layer_weights, vector const& is_membership_fixed, int consider_comms, int consider_empty_community) { return this->move_nodes(partitions, layer_weights, is_membership_fixed, consider_comms, consider_empty_community, true); } double Optimiser::move_nodes(vector partitions, vector layer_weights, vector const& is_membership_fixed, int consider_comms, int consider_empty_community, bool renumber_fixed_nodes) { return this->move_nodes(partitions, layer_weights, is_membership_fixed, consider_comms, consider_empty_community, renumber_fixed_nodes, this->max_comm_size); } double Optimiser::move_nodes(vector partitions, vector layer_weights, vector const& is_membership_fixed, int consider_comms, int consider_empty_community, bool renumber_fixed_nodes, size_t max_comm_size) { #ifdef DEBUG cerr << "double Optimiser::move_nodes(vector partitions, vector layer_weights, vector const& is_membership_fixed, int consider_comms, int consider_empty_community, bool renumber_fixed_nodes, size_t max_comm_size)" << endl; #endif // Number of multiplex layers size_t nb_layers = partitions.size(); if (nb_layers == 0) return -1.0; // Get graphs vector graphs(nb_layers); for (size_t layer = 0; layer < nb_layers; layer++) graphs[layer] = partitions[layer]->get_graph(); // Number of nodes in the graph size_t n = graphs[0]->vcount(); // Get the fixed membership for fixed nodes vector fixed_nodes; vector fixed_membership(n); if (renumber_fixed_nodes) { for (size_t v = 0; v < n; v++) { if (is_membership_fixed[v]) { fixed_nodes.push_back(v); fixed_membership[v] = partitions[0]->membership(v); } } } // Total improvement while moving nodes double total_improv = 0.0; for (Graph* graph : graphs) if (graph->vcount() != n) throw Exception("Number of nodes are not equal for all graphs."); // Number of moved nodes during one loop size_t nb_moves = 0; // Fixed nodes are also stable nodes vector is_node_stable(is_membership_fixed); // Establish vertex order // We normally initialize the normal vertex order // of considering node 0,1,... // But if we use a random order, we shuffle this order. // Also, we skip fixed nodes from the queue for efficiency reasons vector nodes; for (size_t v = 0; v != is_membership_fixed.size(); v++) { if (!is_membership_fixed[v]) nodes.push_back(v); } shuffle(nodes, &rng); deque vertex_order(nodes.begin(), nodes.end()); // Initialize the degree vector // If we want to debug the function, we will calculate some additional values. // In particular, the following consistencies could be checked: // (1) - The difference in the quality function after a move should match // the reported difference when calling diff_move. // (2) - The quality function should be exactly the same value after // aggregating/collapsing the graph. vector comm_added(partitions[0]->n_communities(), false); vector comms; // As long as the queue is not empty while(!vertex_order.empty()) { size_t v = vertex_order.front(); vertex_order.pop_front(); // What is the current community of the node (this should be the same for all layers) size_t v_comm = partitions[0]->membership(v); if (consider_comms == ALL_COMMS) { for(size_t comm = 0; comm < partitions[0]->n_communities(); comm++) { for (size_t layer = 0; layer < nb_layers; layer++) { if (partitions[layer]->cnodes(comm) > 0 && !comm_added[comm]) { comms.push_back(comm); comm_added[comm] = true; break; // Break from for loop in layer } } } } else if (consider_comms == ALL_NEIGH_COMMS) { /****************************ALL NEIGH COMMS*****************************/ for (size_t layer = 0; layer < nb_layers; layer++) { for (size_t comm : partitions[layer]->get_neigh_comms(v, IGRAPH_ALL)) { if (!comm_added[comm]) { comms.push_back(comm); comm_added[comm] = true; } } } } else if (consider_comms == RAND_COMM) { /****************************RAND COMM***********************************/ size_t rand_comm = partitions[0]->membership(graphs[0]->get_random_node(&rng)); // No need to check if random_comm is already added, we only add one comm comms.push_back(rand_comm); comm_added[rand_comm] = true; } else if (consider_comms == RAND_NEIGH_COMM) { /****************************RAND NEIGH COMM*****************************/ size_t rand_layer = get_random_int(0, nb_layers - 1, &rng); if (graphs[rand_layer]->degree(v, IGRAPH_ALL) > 0) { size_t rand_comm = partitions[0]->membership(graphs[rand_layer]->get_random_neighbour(v, IGRAPH_ALL, &rng)); // No need to check if random_comm is already added, we only add one comm comms.push_back(rand_comm); comm_added[rand_comm] = true; } } // Check if we should move to an empty community if (consider_empty_community) { if ( partitions[0]->cnodes(v_comm) > 1 ) // We should not move a node when it is already in its own empty community (this may otherwise create more empty communities than nodes) { size_t n_comms = partitions[0]->n_communities(); size_t comm = partitions[0]->get_empty_community(); #ifdef DEBUG cerr << "Checking empty community (" << comm << ") for partition " << partitions[0] << endl; #endif comms.push_back(comm); if (partitions[0]->n_communities() > n_comms) { // If the empty community has just been added, we need to make sure // that is has also been added to the other layers for (size_t layer = 1; layer < nb_layers; layer++) partitions[layer]->add_empty_community(); comm_added.push_back(true); } } } #ifdef DEBUG cerr << "Consider " << comms.size() << " communities for moving." << endl; #endif size_t max_comm = v_comm; double max_improv = (0 < max_comm_size && max_comm_size < partitions[0]->csize(v_comm)) ? -INFINITY : 10*DBL_EPSILON; size_t v_size = graphs[0]->node_size(v); for (size_t comm : comms) { // reset comm_added to all false comm_added[comm] = false; // Do not create too-large communities. if (0 < max_comm_size && max_comm_size < partitions[0]->csize(comm) + v_size) { continue; } double possible_improv = 0.0; // Consider the improvement of moving to a community for all layers for (size_t layer = 0; layer < nb_layers; layer++) { // Make sure to multiply it by the weight per layer possible_improv += layer_weights[layer]*partitions[layer]->diff_move(v, comm); } if (possible_improv > max_improv) { max_comm = comm; max_improv = possible_improv; } } // Clear comms comms.clear(); is_node_stable[v] = true; // If we actually plan to move the node if (max_comm != v_comm) { // Keep track of improvement total_improv += max_improv; #ifdef DEBUG // If we are debugging, calculate quality function double q_improv = 0; #endif for (size_t layer = 0; layer < nb_layers; layer++) { MutableVertexPartition* partition = partitions[layer]; #ifdef DEBUG // If we are debugging, calculate quality function double q1 = partition->quality(); #endif // Actually move the node partition->move_node(v, max_comm); #ifdef DEBUG // If we are debugging, calculate quality function // and report difference double q2 = partition->quality(); double q_delta = layer_weights[layer]*(q2 - q1); q_improv += q_delta; cerr << "Move node " << v << " from " << v_comm << " to " << max_comm << " for layer " << layer << " (diff_move=" << max_improv << ", q2 - q1=" << q_delta << ")" << endl; #endif } #ifdef DEBUG if (fabs(q_improv - max_improv) > 1e-6) { cerr << "ERROR: Inconsistency while moving nodes, improvement as measured by quality function did not equal the improvement measured by the diff_move function." << endl << " (diff_move=" << max_improv << ", q2 - q1=" << q_improv << ")" << endl; } #endif // Mark neighbours as unstable (if not in new community and not fixed) for (Graph* graph : graphs) { for (size_t u : graph->get_neighbours(v, IGRAPH_ALL)) { // If the neighbour was stable and is not in the new community, we // should mark it as unstable, and add it to the queue, skipping // fixed nodes if (is_node_stable[u] && partitions[0]->membership(u) != max_comm && !is_membership_fixed[u]) { vertex_order.push_back(u); is_node_stable[u] = false; } } } // Keep track of number of moves nb_moves += 1; } } partitions[0]->renumber_communities(); if (renumber_fixed_nodes) partitions[0]->renumber_communities(fixed_nodes, fixed_membership); vector const& membership = partitions[0]->membership(); for (size_t layer = 1; layer < nb_layers; layer++) { partitions[layer]->set_membership(membership); #ifdef DEBUG cerr << "Renumbered communities for layer " << layer << " for " << partitions[layer]->n_communities() << " communities." << endl; #endif //DEBUG } return total_improv; } double Optimiser::merge_nodes(vector partitions, vector layer_weights, vector const& is_membership_fixed, bool renumber_fixed_nodes) { return this->merge_nodes(partitions, layer_weights, is_membership_fixed, this->consider_comms, renumber_fixed_nodes); } double Optimiser::merge_nodes(vector partitions, vector layer_weights, vector const& is_membership_fixed, int consider_comms, bool renumber_fixed_nodes) { return this->merge_nodes(partitions, layer_weights, is_membership_fixed, consider_comms, renumber_fixed_nodes, this->max_comm_size); } double Optimiser::merge_nodes(vector partitions, vector layer_weights, vector const& is_membership_fixed, int consider_comms, bool renumber_fixed_nodes, size_t max_comm_size) { #ifdef DEBUG cerr << "double Optimiser::merge_nodes(vector partitions, vector layer_weights, vector const& is_membership_fixed, int consider_comms, bool renumber_fixed_nodes, size_t max_comm)" << std::endl; #endif // Number of multiplex layers size_t nb_layers = partitions.size(); if (nb_layers == 0) return -1.0; // Get graphs vector graphs(nb_layers); for (size_t layer = 0; layer < nb_layers; layer++) graphs[layer] = partitions[layer]->get_graph(); // Number of nodes in the graph size_t n = graphs[0]->vcount(); // Get the fixed membership for fixed nodes vector fixed_nodes; vector fixed_membership(n); if (renumber_fixed_nodes) { for (size_t v = 0; v < n; v++) { if (is_membership_fixed[v]) { fixed_nodes.push_back(v); fixed_membership[v] = partitions[0]->membership(v); } } } // Total improvement while merging nodes double total_improv = 0.0; for (Graph* graph : graphs) if (graph->vcount() != n) throw Exception("Number of nodes are not equal for all graphs."); // Establish vertex order, skipping fixed nodes // We normally initialize the normal vertex order // of considering node 0,1,... vector vertex_order; for (size_t v = 0; v != n; v++) if (!is_membership_fixed[v]) vertex_order.push_back(v); // But if we use a random order, we shuffle this order. shuffle(vertex_order, &rng); vector comm_added(partitions[0]->n_communities(), false); vector comms; // Iterate over all nodes for (size_t v : vertex_order) { // What is the current community of the node (this should be the same for all layers) size_t v_comm = partitions[0]->membership(v); // Clear comms for (size_t comm : comms) comm_added[comm] = false; comms.clear(); #ifdef DEBUG cerr << "Consider moving node " << v << " from " << v_comm << "." << endl; #endif if (partitions[0]->cnodes(v_comm) == 1) { if (consider_comms == ALL_COMMS) { for(size_t comm = 0; comm < partitions[0]->n_communities(); comm++) { for (size_t layer = 0; layer < nb_layers; layer++) { if (partitions[layer]->cnodes(comm) > 0 && !comm_added[comm]) { comms.push_back(comm); comm_added[comm] = true; break; // Break from for loop in layer } } } } else if (consider_comms == ALL_NEIGH_COMMS) { /****************************ALL NEIGH COMMS*****************************/ for (size_t layer = 0; layer < nb_layers; layer++) { for (size_t comm : partitions[layer]->get_neigh_comms(v, IGRAPH_ALL)) { if (!comm_added[comm]) { comms.push_back(comm); comm_added[comm] = true; } } } } else if (consider_comms == RAND_COMM) { /****************************RAND COMM***********************************/ size_t rand_comm = partitions[0]->membership(graphs[0]->get_random_node(&rng)); // No need to check if random_comm is already added, we only add one comm comms.push_back(rand_comm); comm_added[rand_comm] = true; } else if (consider_comms == RAND_NEIGH_COMM) { /****************************RAND NEIGH COMM*****************************/ size_t rand_layer = get_random_int(0, nb_layers - 1, &rng); size_t k = graphs[rand_layer]->degree(v, IGRAPH_ALL); if (k > 0) { // Make sure there is also a probability not to move the node if (get_random_int(0, k, &rng) > 0) { size_t rand_comm = partitions[0]->membership(graphs[rand_layer]->get_random_neighbour(v, IGRAPH_ALL, &rng)); // No need to check if random_comm is already added, we only add one comm comms.push_back(rand_comm); comm_added[rand_comm] = true; } } } #ifdef DEBUG cerr << "Consider " << comms.size() << " communities for moving node " << v << "." << endl; #endif size_t max_comm = v_comm; double max_improv = (0 < max_comm_size && max_comm_size < partitions[0]->csize(v_comm)) ? -INFINITY : 0; size_t v_size = graphs[0]->node_size(v); for (size_t comm : comms) { // Do not create too-large communities. if (0 < max_comm_size && max_comm_size < partitions[0]->csize(comm) + v_size) { continue; } double possible_improv = 0.0; // Consider the improvement of moving to a community for all layers for (size_t layer = 0; layer < nb_layers; layer++) { // Make sure to multiply it by the weight per layer possible_improv += layer_weights[layer]*partitions[layer]->diff_move(v, comm); } #ifdef DEBUG cerr << "Improvement of " << possible_improv << " when move to " << comm << "." << endl; #endif if (possible_improv >= max_improv) { max_comm = comm; max_improv = possible_improv; } } // If we actually plan to move the node if (max_comm != v_comm) { // Keep track of improvement total_improv += max_improv; #ifdef DEBUG // If we are debugging, calculate quality function double q_improv = 0; #endif for (size_t layer = 0; layer < nb_layers; layer++) { MutableVertexPartition* partition = partitions[layer]; #ifdef DEBUG // If we are debugging, calculate quality function double q1 = partition->quality(); #endif // Actually move the node partition->move_node(v, max_comm); #ifdef DEBUG // If we are debugging, calculate quality function // and report difference double q2 = partition->quality(); double q_delta = layer_weights[layer]*(q2 - q1); q_improv += q_delta; cerr << "Move node " << v << " from " << v_comm << " to " << max_comm << " for layer " << layer << " (diff_move=" << max_improv << ", q2 - q1=" << q_delta << ")" << endl; #endif } #ifdef DEBUG if (fabs(q_improv - max_improv) > 1e-6) { cerr << "ERROR: Inconsistency while moving nodes, improvement as measured by quality function did not equal the improvement measured by the diff_move function." << endl << " (diff_move=" << max_improv << ", q2 - q1=" << q_improv << ")" << endl; } #endif } } } partitions[0]->renumber_communities(); if (renumber_fixed_nodes) partitions[0]->renumber_communities(fixed_nodes, fixed_membership); vector const& membership = partitions[0]->membership(); for (size_t layer = 1; layer < nb_layers; layer++) { partitions[layer]->set_membership(membership); #ifdef DEBUG cerr << "Renumbered communities for layer " << layer << " for " << partitions[layer]->n_communities() << " communities." << endl; #endif //DEBUG } return total_improv; } double Optimiser::move_nodes_constrained(vector partitions, vector layer_weights, MutableVertexPartition* constrained_partition) { return this->move_nodes_constrained(partitions, layer_weights, this->refine_consider_comms, constrained_partition); } double Optimiser::move_nodes_constrained(vector partitions, vector layer_weights, int consider_comms, MutableVertexPartition* constrained_partition) { return this->move_nodes_constrained(partitions, layer_weights, refine_consider_comms, constrained_partition, this->max_comm_size); } double Optimiser::move_nodes_constrained(vector partitions, vector layer_weights, int consider_comms, MutableVertexPartition* constrained_partition, size_t max_comm_size) { #ifdef DEBUG cerr << "double Optimiser::move_nodes_constrained(vector partitions, vector layer_weights, int consider_comms, MutableVertexPartition* constrained_partition, size_t max_comm_size)" << std::endl; #endif // Number of multiplex layers size_t nb_layers = partitions.size(); if (nb_layers == 0) return -1.0; // Get graphs vector graphs(nb_layers); for (size_t layer = 0; layer < nb_layers; layer++) graphs[layer] = partitions[layer]->get_graph(); // Number of nodes in the graph size_t n = graphs[0]->vcount(); // Total improvement while moving nodes double total_improv = 0.0; for (size_t layer = 0; layer < nb_layers; layer++) if (graphs[layer]->vcount() != n) throw Exception("Number of nodes are not equal for all graphs."); // Number of moved nodes during one loop size_t nb_moves = 0; // Establish vertex order // We normally initialize the normal vertex order // of considering node 0,1,... vector is_node_stable(n, false); // But if we use a random order, we shuffle this order. vector nodes = range(n); shuffle(nodes, &rng); deque vertex_order(nodes.begin(), nodes.end()); vector< vector > constrained_comms = constrained_partition->get_communities(); // Initialize the degree vector // If we want to debug the function, we will calculate some additional values. // In particular, the following consistencies could be checked: // (1) - The difference in the quality function after a move should match // the reported difference when calling diff_move. // (2) - The quality function should be exactly the same value after // aggregating/collapsing the graph. vector comm_added(partitions[0]->n_communities(), false); vector comms; // As long as the queue is not empty while(!vertex_order.empty()) { size_t v = vertex_order.front(); vertex_order.pop_front(); // Clear comms for (size_t comm : comms) comm_added[comm] = false; comms.clear(); // What is the current community of the node (this should be the same for all layers) size_t v_comm = partitions[0]->membership(v); if (consider_comms == ALL_COMMS) { // Add all communities to the set comms that are within the constrained community. size_t v_constrained_comm = constrained_partition->membership(v); for (size_t u : constrained_comms[v_constrained_comm]) { size_t u_comm = partitions[0]->membership(u); if (!comm_added[u_comm]) { comms.push_back(u_comm); comm_added[u_comm] = true; } } } else if (consider_comms == ALL_NEIGH_COMMS) { /****************************ALL NEIGH COMMS*****************************/ for (size_t layer = 0; layer < nb_layers; layer++) { for (size_t comm : partitions[layer]->get_neigh_comms(v, IGRAPH_ALL, constrained_partition->membership())) { if (!comm_added[comm]) { comms.push_back(comm); comm_added[comm] = true; } } } } else if (consider_comms == RAND_COMM) { /****************************RAND COMM***********************************/ size_t v_constrained_comm = constrained_partition->membership(v); size_t random_idx = get_random_int(0, constrained_comms[v_constrained_comm].size() - 1, &rng); size_t rand_comm = constrained_comms[v_constrained_comm][random_idx]; // No need to check if random_comm is already added, we only add one comm comms.push_back(rand_comm); comm_added[rand_comm] = true; } else if (consider_comms == RAND_NEIGH_COMM) { /****************************RAND NEIGH COMM*****************************/ // Draw a random community among the neighbours, proportional to the // frequency of the communities among the neighbours. Notice this is no // longer vector all_neigh_comms_incl_dupes; for (size_t layer = 0; layer < nb_layers; layer++) { vector neigh_comm_layer = partitions[layer]->get_neigh_comms(v, IGRAPH_ALL, constrained_partition->membership()); all_neigh_comms_incl_dupes.insert(all_neigh_comms_incl_dupes.end(), neigh_comm_layer.begin(), neigh_comm_layer.end()); } if (all_neigh_comms_incl_dupes.size() > 0) { size_t random_idx = get_random_int(0, all_neigh_comms_incl_dupes.size() - 1, &rng); size_t rand_comm = all_neigh_comms_incl_dupes[random_idx]; // No need to check if random_comm is already added, we only add one comm comms.push_back(rand_comm); comm_added[rand_comm] = true; } } #ifdef DEBUG cerr << "Consider " << comms.size() << " communities for moving." << endl; #endif size_t max_comm = v_comm; double max_improv = (0 < max_comm_size && max_comm_size < partitions[0]->csize(v_comm)) ? -INFINITY : 10*DBL_EPSILON; size_t v_size = graphs[0]->node_size(v); for (size_t comm : comms) { // Do not create too-large communities. if (0 < max_comm_size && max_comm_size < partitions[0]->csize(comm) + v_size) { continue; } double possible_improv = 0.0; // Consider the improvement of moving to a community for all layers for (size_t layer = 0; layer < nb_layers; layer++) { // Make sure to multiply it by the weight per layer possible_improv += layer_weights[layer]*partitions[layer]->diff_move(v, comm); } // Check if improvement is best if (possible_improv > max_improv) { max_comm = comm; max_improv = possible_improv; } } is_node_stable[v] = true; // If we actually plan to move the nove if (max_comm != v_comm) { // Keep track of improvement total_improv += max_improv; #ifdef DEBUG // If we are debugging, calculate quality function double q_improv = 0; #endif for (size_t layer = 0; layer < nb_layers; layer++) { MutableVertexPartition* partition = partitions[layer]; #ifdef DEBUG // If we are debugging, calculate quality function double q1 = partition->quality(); #endif // Actually move the node partition->move_node(v, max_comm); #ifdef DEBUG // If we are debugging, calculate quality function // and report difference double q2 = partition->quality(); double q_delta = layer_weights[layer]*(q2 - q1); q_improv += q_delta; cerr << "Move node " << v << " from " << v_comm << " to " << max_comm << " for layer " << layer << " (diff_move=" << max_improv << ", q2 - q1=" << q_delta << ")" << endl; #endif } #ifdef DEBUG if (fabs(q_improv - max_improv) > 1e-6) { cerr << "ERROR: Inconsistency while moving nodes, improvement as measured by quality function did not equal the improvement measured by the diff_move function." << endl << " (diff_move=" << max_improv << ", q2 - q1=" << q_improv << ")" << endl; } #endif // Mark neighbours as unstable (if not in new community and not fixed) for (Graph* graph : graphs) { for (size_t u : graph->get_neighbours(v, IGRAPH_ALL)) { // If the neighbour was stable and is not in the new community, we // should mark it as unstable, and add it to the queue, skipping // fixed nodes if (is_node_stable[u] && partitions[0]->membership(u) != max_comm && constrained_partition->membership(u) == constrained_partition->membership(v)) { vertex_order.push_back(u); is_node_stable[u] = false; } } } // Keep track of number of moves nb_moves += 1; } #ifdef DEBUG cerr << "Moved " << nb_moves << " nodes." << endl; #endif } partitions[0]->renumber_communities(); vector const& membership = partitions[0]->membership(); for (size_t layer = 1; layer < nb_layers; layer++) { partitions[layer]->set_membership(membership); #ifdef DEBUG cerr << "Renumbered communities for layer " << layer << " for " << partitions[layer]->n_communities() << " communities." << endl; #endif //DEBUG } return total_improv; } double Optimiser::merge_nodes_constrained(vector partitions, vector layer_weights, MutableVertexPartition* constrained_partition) { return this->merge_nodes_constrained(partitions, layer_weights, this->refine_consider_comms, constrained_partition); } double Optimiser::merge_nodes_constrained(vector partitions, vector layer_weights, int consider_comms, MutableVertexPartition* constrained_partition) { return this->merge_nodes_constrained(partitions, layer_weights, refine_consider_comms, constrained_partition, this->max_comm_size); } double Optimiser::merge_nodes_constrained(vector partitions, vector layer_weights, int consider_comms, MutableVertexPartition* constrained_partition, size_t max_comm_size) { #ifdef DEBUG cerr << "double Optimiser::merge_nodes_constrained(vector partitions, vector layer_weights, int consider_comms, MutableVertexPartition* constrained_partition, size_t max_comm_size)" << std::endl; #endif // Number of multiplex layers size_t nb_layers = partitions.size(); if (nb_layers == 0) return -1.0; // Get graphs vector graphs(nb_layers); for (size_t layer = 0; layer < nb_layers; layer++) graphs[layer] = partitions[layer]->get_graph(); // Number of nodes in the graph size_t n = graphs[0]->vcount(); // Total improvement while merging nodes double total_improv = 0.0; for (size_t layer = 0; layer < nb_layers; layer++) if (graphs[layer]->vcount() != n) throw Exception("Number of nodes are not equal for all graphs."); // Establish vertex order // We normally initialize the normal vertex order // of considering node 0,1,... vector vertex_order = range(n); // But if we use a random order, we shuffle this order. shuffle(vertex_order, &rng); vector< vector > constrained_comms = constrained_partition->get_communities(); vector comm_added(partitions[0]->n_communities(), false); vector comms; // For each node for (size_t v : vertex_order) { // What is the current community of the node (this should be the same for all layers) size_t v_comm = partitions[0]->membership(v); if (partitions[0]->cnodes(v_comm) == 1) { // Clear comms for (size_t comm : comms) comm_added[comm] = false; comms.clear(); if (consider_comms == ALL_COMMS) { // Add all communities to the set comms that are within the constrained community. size_t v_constrained_comm = constrained_partition->membership(v); for (size_t u : constrained_comms[v_constrained_comm]) { size_t u_comm = partitions[0]->membership(u); if (!comm_added[u_comm]) { comms.push_back(u_comm); comm_added[u_comm] = true; } } } else if (consider_comms == ALL_NEIGH_COMMS) { /****************************ALL NEIGH COMMS*****************************/ for (size_t layer = 0; layer < nb_layers; layer++) { for (size_t u : partitions[layer]->get_graph()->get_neighbours(v, IGRAPH_ALL)) { if (constrained_partition->membership(v) == constrained_partition->membership(u)) { size_t comm = partitions[layer]->membership(u); if (!comm_added[comm]) { comms.push_back(comm); comm_added[comm] = true; } } } } } else if (consider_comms == RAND_COMM) { /****************************RAND COMM***********************************/ size_t v_constrained_comm = constrained_partition->membership(v); size_t random_idx = get_random_int(0, constrained_comms[v_constrained_comm].size() - 1, &rng); size_t rand_comm = constrained_comms[v_constrained_comm][random_idx]; // No need to check if random_comm is already added, we only add one comm comms.push_back(rand_comm); comm_added[rand_comm] = true; } else if (consider_comms == RAND_NEIGH_COMM) { /****************************RAND NEIGH COMM*****************************/ // Draw a random community among the neighbours, proportional to the // frequency of the communities among the neighbours. Notice this is no // longer vector all_neigh_comms_incl_dupes; for (size_t layer = 0; layer < nb_layers; layer++) { vector neigh_comm_layer = partitions[layer]->get_neigh_comms(v, IGRAPH_ALL, constrained_partition->membership()); all_neigh_comms_incl_dupes.insert(all_neigh_comms_incl_dupes.end(), neigh_comm_layer.begin(), neigh_comm_layer.end()); } size_t k = all_neigh_comms_incl_dupes.size(); if (k > 0) { // Make sure there is also a probability not to move the node if (get_random_int(0, k, &rng) > 0) { size_t random_idx = get_random_int(0, k - 1, &rng); size_t rand_comm = all_neigh_comms_incl_dupes[random_idx]; // No need to check if random_comm is already added, we only add one comm comms.push_back(rand_comm); comm_added[rand_comm] = true; } } } #ifdef DEBUG cerr << "Consider " << comms.size() << " communities for moving." << endl; #endif size_t max_comm = v_comm; double max_improv = (0 < max_comm_size && max_comm_size < partitions[0]->csize(v_comm)) ? -INFINITY : 0; size_t v_size = graphs[0]->node_size(v); for (size_t comm : comms) { // reset comm_added to all false comm_added[comm] = false; // Do not create too-large communities. if (0 < max_comm_size && max_comm_size < partitions[0]->csize(comm) + v_size) { continue; } double possible_improv = 0.0; // Consider the improvement of moving to a community for all layers for (size_t layer = 0; layer < nb_layers; layer++) { // Make sure to multiply it by the weight per layer possible_improv += layer_weights[layer]*partitions[layer]->diff_move(v, comm); } if (possible_improv >= max_improv) { max_comm = comm; max_improv = possible_improv; } } // If we actually plan to move the node if (max_comm != v_comm) { // Keep track of improvement total_improv += max_improv; #ifdef DEBUG // If we are debugging, calculate quality function double q_improv = 0; #endif for (size_t layer = 0; layer < nb_layers; layer++) { MutableVertexPartition* partition = partitions[layer]; #ifdef DEBUG // If we are debugging, calculate quality function double q1 = partition->quality(); #endif // Actually move the node partition->move_node(v, max_comm); #ifdef DEBUG // If we are debugging, calculate quality function // and report difference double q2 = partition->quality(); double q_delta = layer_weights[layer]*(q2 - q1); q_improv += q_delta; cerr << "Move node " << v << " from " << v_comm << " to " << max_comm << " for layer " << layer << " (diff_move=" << max_improv << ", q2 - q1=" << q_delta << ")" << endl; #endif } #ifdef DEBUG if (fabs(q_improv - max_improv) > 1e-6) { cerr << "ERROR: Inconsistency while moving nodes, improvement as measured by quality function did not equal the improvement measured by the diff_move function." << endl << " (diff_move=" << max_improv << ", q2 - q1=" << q_improv << ")" << endl; } #endif } } } partitions[0]->renumber_communities(); vector const& membership = partitions[0]->membership(); for (size_t layer = 1; layer < nb_layers; layer++) { partitions[layer]->set_membership(membership); #ifdef DEBUG cerr << "Renumbered communities for layer " << layer << " for " << partitions[layer]->n_communities() << " communities." << endl; #endif //DEBUG } return total_improv; } leidenalg-0.8.9/src/leidenalg/Optimiser.py000066400000000000000000000732261420514302700205240ustar00rootroot00000000000000from . import _c_leiden from .VertexPartition import LinearResolutionParameterVertexPartition from collections import namedtuple from math import log, sqrt class Optimiser(object): """ Class for doing community detection using the Leiden algorithm. The Leiden algorithm [1] derives from the Louvain algorithm [2]. The Louvain algorithm has an elegant formulation. It consists of two phases: (1) move nodes between communities; (2) aggregate the graph. It then repeats these phases on the aggregate graph. The Leiden algorithm consists of three phases: (1) move nodes; (2) refine communities; (3) aggregate the graph based on the refinement. The Louvain algorithm can lead to arbitrarily badly connected communities, whereas the Leiden algorithm guarantees communities are well-connected. In fact, it converges towards a partition in which all subsets of all communities are locally optimally assigned. Finally, the Leiden algorithm is also much faster, because it relies on a fast local move routine. There is one, rather technical, difference with the original Leiden algorithm. This implementation provides a general optimisation routine for any quality function. There is one aspect of the original Leiden algorithm that cannot be translated well in this framework: when merging subcommunities in the refinement procedure, it does not consider whether they are sufficiently well connected to the rest of the community. This implementation therefore does not guarantee subpartition :math:`\gamma`-density. However, all other guarantees still hold: After each iteration 1. :math:`\gamma`-separation 2. :math:`\gamma`-connectivity After a stable iteration 3. Node optimality 4. Some subsets are locally optimally assigned Asymptotically 5. Uniform :math:`\gamma`-density 6. Subset optimality The optimiser class provides a number of different methods for optimising a given partition. The overall optimisation procedure :func:`optimise_partition` calls either :func:`move_nodes` or :func:`merge_nodes` (which is controlled by :attr:`optimise_routine`) then aggregates the graph and repeats the same procedure. Possible, indicated by :attr:`refine_partition` the partition is refined before aggregating, meaning that subsets of communities are considered for moving around. Which routine is used for the refinement is indicated by :attr:`refine_routine`. For calculating the actual improvement of moving a node (corresponding a subset of nodes in the aggregate graph), the code relies on :func:`~VertexPartition.MutableVertexPartition.diff_move` which provides different values for different methods (e.g. modularity or CPM). The default settings are consistent with the Leiden algorithm. By not doing the refinement, you essentially get the Louvain algorithm with a fast local move. Finally, the Optimiser class provides a routine to construct a :func:`resolution_profile` on a resolution parameter. References ---------- .. [1] Traag, V.A., Waltman. L., Van Eck, N.-J. (2018). From Louvain to Leiden: guaranteeing well-connected communities. `arXiv:1810.08473 `_ .. [2] Blondel, V. D., Guillaume, J.-L., Lambiotte, R., & Lefebvre, E. (2008). Fast unfolding of communities in large networks. Journal of Statistical Mechanics: Theory and Experiment, 10008(10), 6. `10.1088/1742-5468/2008/10/P10008 `_ """ def __init__(self): """ Create a new Optimiser object """ self._optimiser = _c_leiden._new_Optimiser() #########################################################3 # consider_comms @property def consider_comms(self): """ Determine how alternative communities are considered for moving a node for *optimising* a partition. Nodes will only move to alternative communities that improve the given quality function. Notes ------- This attribute should be set to one of the following values * :attr:`leidenalg.ALL_NEIGH_COMMS` Consider all neighbouring communities for moving. * :attr:`leidenalg.ALL_COMMS` Consider all communities for moving. This is especially useful in the case of negative links, in which case it may be better to move a node to a non-neighbouring community. * :attr:`leidenalg.RAND_NEIGH_COMM` Consider a random neighbour community for moving. The probability to choose a community is proportional to the number of neighbours a node has in that community. * :attr:`leidenalg.RAND_COMM` Consider a random community for moving. The probability to choose a community is proportional to the number of nodes in that community. """ return _c_leiden._Optimiser_get_consider_comms(self._optimiser) @consider_comms.setter def consider_comms(self, value): _c_leiden._Optimiser_set_consider_comms(self._optimiser, value) #########################################################3 # refine consider_comms @property def refine_consider_comms(self): """ Determine how alternative communities are considered for moving a node when *refining* a partition. Nodes will only move to alternative communities that improve the given quality function. Notes ------- This attribute should be set to one of the following values * :attr:`leidenalg.ALL_NEIGH_COMMS` Consider all neighbouring communities for moving. * :attr:`leidenalg.ALL_COMMS` Consider all communities for moving. This is especially useful in the case of negative links, in which case it may be better to move a node to a non-neighbouring community. * :attr:`leidenalg.RAND_NEIGH_COMM` Consider a random neighbour community for moving. The probability to choose a community is proportional to the number of neighbours a node has in that community. * :attr:`leidenalg.RAND_COMM` Consider a random community for moving. The probability to choose a community is proportional to the number of nodes in that community. """ return _c_leiden._Optimiser_get_refine_consider_comms(self._optimiser) @refine_consider_comms.setter def refine_consider_comms(self, value): _c_leiden._Optimiser_set_refine_consider_comms(self._optimiser, value) #########################################################3 # optimise routine @property def optimise_routine(self): """ Determine the routine to use for *optimising* a partition. Notes ------- This attribute should be set to one of the following values * :attr:`leidenalg.MOVE_NODES` Use :func:`move_nodes`. * :attr:`leidenalg.MERGE_NODES` Use :func:`merge_nodes`. """ return _c_leiden._Optimiser_get_optimise_routine(self._optimiser) @optimise_routine.setter def optimise_routine(self, value): _c_leiden._Optimiser_set_optimise_routine(self._optimiser, value) #########################################################3 # optimise routine @property def refine_routine(self): """ Determine the routine to use for *refining* a partition. Notes ------- This attribute should be set to one of the following values * :attr:`leidenalg.MOVE_NODES` Use :func:`move_nodes`. * :attr:`leidenalg.MERGE_NODES` Use :func:`merge_nodes`. """ return _c_leiden._Optimiser_get_refine_routine(self._optimiser) @refine_routine.setter def refine_routine(self, value): _c_leiden._Optimiser_set_refine_routine(self._optimiser, value) #########################################################3 # refine_partition @property def refine_partition(self): """ boolean: if ``True`` refine partition before aggregation. """ return _c_leiden._Optimiser_get_refine_partition(self._optimiser) @refine_partition.setter def refine_partition(self, value): _c_leiden._Optimiser_set_refine_partition(self._optimiser, value) #########################################################3 # consider_empty_community @property def consider_empty_community(self): """ boolean: if ``True`` consider also moving nodes to an empty community (default). """ return _c_leiden._Optimiser_get_consider_empty_community(self._optimiser) @consider_empty_community.setter def consider_empty_community(self, value): _c_leiden._Optimiser_set_consider_empty_community(self._optimiser, value) #########################################################3 # max_comm_size @property def max_comm_size(self): """ Constrain the maximal community size. By default (zero), communities can be of any size. If this is set to a positive integer value, then communities will be constrained to be at most this total size. """ return _c_leiden._Optimiser_get_max_comm_size(self._optimiser) @max_comm_size.setter def max_comm_size(self, value): if value < 0: raise ValueError("negative max_comm_size: %s" % value) _c_leiden._Optimiser_set_max_comm_size(self._optimiser, value) ########################################################## # Set rng seed def set_rng_seed(self, value): """ Set the random seed for the random number generator. Parameters ---------- value The integer seed used in the random number generator """ _c_leiden._Optimiser_set_rng_seed(self._optimiser, value) def optimise_partition(self, partition, n_iterations=2, is_membership_fixed=None): """ Optimise the given partition. Parameters ---------- partition The :class:`~VertexPartition.MutableVertexPartition` to optimise. n_iterations : int Number of iterations to run the Leiden algorithm. By default, 2 iterations are run. If the number of iterations is negative, the Leiden algorithm is run until an iteration in which there was no improvement. is_membership_fixed: list of bools or None Boolean list of nodes that are not allowed to change community. The length of this list must be equal to the number of nodes. By default (None) all nodes can change community during the optimization. Returns ------- float Improvement in quality function. Examples -------- >>> G = ig.Graph.Famous('Zachary') >>> optimiser = la.Optimiser() >>> partition = la.ModularityVertexPartition(G) >>> diff = optimiser.optimise_partition(partition) or, fixing the membership of some nodes: >>> is_membership_fixed = [False for v in G.vs] >>> is_membership_fixed[4] = True >>> is_membership_fixed[6] = True >>> diff = optimiser.optimise_partition(partition, is_membership_fixed=is_membership_fixed) """ itr = 0 diff = 0 continue_iteration = itr < n_iterations or n_iterations < 0 while continue_iteration: diff_inc = _c_leiden._Optimiser_optimise_partition( self._optimiser, partition._partition, is_membership_fixed=is_membership_fixed, ) diff += diff_inc itr += 1 if n_iterations < 0: continue_iteration = (diff_inc > 0) else: continue_iteration = itr < n_iterations partition._update_internal_membership() return diff def optimise_partition_multiplex(self, partitions, layer_weights=None, n_iterations=2, is_membership_fixed=None): """ Optimise the given partitions simultaneously. Parameters ---------- partitions List of :class:`~VertexPartition.MutableVertexPartition` layers to optimise. layer_weights List of weights of layers. is_membership_fixed: list of bools or None Boolean list of nodes that are not allowed to change community. The length of this list must be equal to the number of nodes. By default (None) all nodes can change community during the optimization. n_iterations : int Number of iterations to run the Leiden algorithm. By default, 2 iterations are run. If the number of iterations is negative, the Leiden algorithm is run until an iteration in which there was no improvement. Returns ------- float Improvement in quality of combined partitions, see `Notes <#notes-multiplex>`_. .. _notes-multiplex: Notes ----- This method assumes that the partitions are defined for graphs with the same vertices. The connections between the vertices may be different, but the vertices themselves should be identical. In other words, all vertices should have identical indices in all graphs (i.e. node `i` is assumed to be the same node in all graphs). The quality of the overall partition is simply the sum of the individual qualities for the various partitions, weighted by the layer_weight. If we denote by :math:`Q_k` the quality of layer :math:`k` and the weight by :math:`\\lambda_k`, the overall quality is then .. math:: Q = \sum_k \\lambda_k Q_k. This is particularly useful for graphs containing negative links. When separating the graph in two graphs, the one containing only the positive links, and the other only the negative link, by supplying a negative weight to the latter layer, we try to find relatively many positive links within a community and relatively many negative links between communities. Note that in this case it may be better to assign a node to a community to which it is not connected so that :attr:`consider_comms` may be better set to :attr:`leidenalg.ALL_COMMS`. Besides multiplex graphs where each node is assumed to have a single community, it is also useful in the case of for example multiple time slices, or in situations where nodes can have different communities in different slices. The package includes some special helper functions for using :func:`optimise_partition_multiplex` in such cases, where there is a conversion required from (time) slices to layers suitable for use in this function. See Also -------- :func:`slices_to_layers` :func:`time_slices_to_layers` :func:`find_partition_multiplex` :func:`find_partition_temporal` Examples -------- >>> G_pos = ig.Graph.SBM(100, pref_matrix=[[0.5, 0.1], [0.1, 0.5]], block_sizes=[50, 50]) >>> G_neg = ig.Graph.SBM(100, pref_matrix=[[0.1, 0.5], [0.5, 0.1]], block_sizes=[50, 50]) >>> optimiser = la.Optimiser() >>> partition_pos = la.ModularityVertexPartition(G_pos) >>> partition_neg = la.ModularityVertexPartition(G_neg) >>> diff = optimiser.optimise_partition_multiplex( ... partitions=[partition_pos, partition_neg], ... layer_weights=[1,-1]) """ if not layer_weights: layer_weights = [1]*len(partitions) itr = 0 diff = 0 continue_iteration = itr < n_iterations or n_iterations < 0 while continue_iteration: diff_inc = _c_leiden._Optimiser_optimise_partition_multiplex( self._optimiser, [partition._partition for partition in partitions], layer_weights, is_membership_fixed) diff += diff_inc itr += 1 if n_iterations < 0: continue_iteration = (diff_inc > 0) else: continue_iteration = itr < n_iterations for partition in partitions: partition._update_internal_membership() return diff def move_nodes(self, partition, is_membership_fixed=None, consider_comms=None): """ Move nodes to alternative communities for *optimising* the partition. Parameters ---------- partition The partition for which to move nodes. is_membership_fixed: list of bools or None Boolean list of nodes that are not allowed to change community. The length of this list must be equal to the number of nodes. By default (None) all nodes can change community during the optimization. consider_comms If ``None`` uses :attr:`consider_comms`, but can be set to something else. Returns ------- float Improvement in quality function. Notes ----- When moving nodes, the function loops over nodes and considers moving the node to an alternative community. Which community depends on ``consider_comms``. The function terminates when no more nodes can be moved to an alternative community. See Also -------- :func:`Optimiser.move_nodes_constrained` :func:`Optimiser.merge_nodes` Examples -------- >>> G = ig.Graph.Famous('Zachary') >>> optimiser = la.Optimiser() >>> partition = la.ModularityVertexPartition(G) >>> diff = optimiser.move_nodes(partition) """ if (consider_comms is None): consider_comms = self.consider_comms diff = _c_leiden._Optimiser_move_nodes( self._optimiser, partition._partition, is_membership_fixed, consider_comms) partition._update_internal_membership() return diff def move_nodes_constrained(self, partition, constrained_partition, consider_comms=None): """ Move nodes to alternative communities for *refining* the partition. Parameters ---------- partition The partition for which to move nodes. constrained_partition The partition within which we may move nodes. consider_comms If ``None`` uses :attr:`refine_consider_comms`, but can be set to something else. Returns ------- float Improvement in quality function. Notes ----- The idea is constrain the movement of nodes to alternative communities to another partition. In other words, if there is a partition ``P`` which we want to refine, we can then initialize a new singleton partition, and move nodes in that partition constrained to ``P``. See Also -------- :func:`Optimiser.move_nodes` :func:`Optimiser.merge_nodes_constrained` Examples -------- >>> G = ig.Graph.Famous('Zachary') >>> optimiser = la.Optimiser() >>> partition = la.ModularityVertexPartition(G) >>> diff = optimiser.optimise_partition(partition) >>> refine_partition = la.ModularityVertexPartition(G) >>> diff = optimiser.move_nodes_constrained(refine_partition, partition) """ if (consider_comms is None): consider_comms = self.refine_consider_comms diff = _c_leiden._Optimiser_move_nodes_constrained(self._optimiser, partition._partition, constrained_partition._partition, consider_comms) partition._update_internal_membership() return diff def merge_nodes(self, partition, is_membership_fixed=None, consider_comms=None): """ Merge nodes for *optimising* the partition. Parameters ---------- partition The partition for which to merge nodes. is_membership_fixed: list of bools or None Boolean list of nodes that are not allowed to change community. The length of this list must be equal to the number of nodes. By default (None) all nodes can change community during the optimization. consider_comms If ``None`` uses :attr:`consider_comms`, but can be set to something else. Returns ------- float Improvement in quality function. Notes ----- This function loop over all nodes once and tries to merge them with another community. Merging in this case implies that a node will never be removed from a community, only merged with other communities. See Also -------- :func:`Optimiser.move_nodes` :func:`Optimiser.merge_nodes_constrained` Examples -------- >>> G = ig.Graph.Famous('Zachary') >>> optimiser = la.Optimiser() >>> partition = la.ModularityVertexPartition(G) >>> diff = optimiser.merge_nodes(partition) """ if (consider_comms is None): consider_comms = self.consider_comms diff = _c_leiden._Optimiser_merge_nodes( self._optimiser, partition._partition, is_membership_fixed, consider_comms) partition._update_internal_membership() return diff def merge_nodes_constrained(self, partition, constrained_partition, consider_comms=None): """ Merge nodes for *refining* the partition. Parameters ---------- partition The partition for which to merge nodes. constrained_partition The partition within which we may merge nodes. consider_comms If ``None`` uses :attr:`refine_consider_comms`, but can be set to something else. Returns ------- float Improvement in quality function. Notes ----- The idea is constrain the merging of nodes to another partition. In other words, if there is a partition ``P`` which we want to refine, we can then initialize a new singleton partition, and move nodes in that partition constrained to ``P``. See Also -------- :func:`Optimiser.move_nodes_constrained` :func:`Optimiser.merge_nodes` Examples -------- >>> G = ig.Graph.Famous('Zachary') >>> optimiser = la.Optimiser() >>> partition = la.ModularityVertexPartition(G) >>> diff = optimiser.optimise_partition(partition) >>> refine_partition = la.ModularityVertexPartition(G) >>> diff = optimiser.move_nodes_constrained(refine_partition, partition) """ if (consider_comms is None): consider_comms = self.refine_consider_comms diff = _c_leiden._Optimiser_merge_nodes_constrained(self._optimiser, partition._partition, constrained_partition._partition, consider_comms) partition._update_internal_membership() return diff def resolution_profile(self, graph, partition_type, resolution_range, weights=None, bisect_func=lambda p: p.bisect_value(), min_diff_bisect_value=1, min_diff_resolution=1e-3, linear_bisection=False, number_iterations=1, **kwargs ): """ Use bisectioning on the resolution parameter in order to construct a resolution profile. Parameters ---------- graph The graph for which to construct a resolution profile. partition_type The type of :class:`~VertexPartition.MutableVertexPartition` used to find a partition (must support resolution parameters obviously). resolution_range The range of resolution values that we would like to scan. weights If provided, indicates the edge attribute to use as a weight. Returns ------- list of :class:`~VertexPartition.MutableVertexPartition` A list of partitions for different resolutions. Other Parameters ---------------- bisect_func The function used for bisectioning. For the methods currently implemented, this should usually not be altered. min_diff_bisect_value The difference in the value returned by the bisect_func below which the bisectioning stops (i.e. by default, a difference of a single edge does not trigger further bisectioning). min_diff_resolution The difference in resolution below which the bisectioning stops. For positive differences, the logarithmic difference is used by default, i.e. ``diff = log(res_1) - log(res_2) = log(res_1/res_2)``, for which ``diff > min_diff_resolution`` to continue bisectioning. Set the linear_bisection to true in order to use only linear bisectioning (in the case of negative resolution parameters for example, which can happen with negative weights). linear_bisection Whether the bisectioning will be done on a linear or on a logarithmic basis (if possible). number_iterations Indicates the number of iterations of the algorithm to run. If negative (or zero) the algorithm is run until a stable iteration. Examples -------- >>> G = ig.Graph.Famous('Zachary') >>> optimiser = la.Optimiser() >>> profile = optimiser.resolution_profile(G, la.CPMVertexPartition, ... resolution_range=(0,1)) """ # Helper function for cleaning values to be a stepwise function def clean_stepwise(bisect_values): # Check best partition for each resolution parameter for res, bisect in bisect_values.items(): best_bisect = bisect best_quality = bisect.partition.quality(res) for res2, bisect2 in bisect_values.items(): if bisect2.partition.quality(res) > best_quality: best_bisect = bisect2 best_quality = bisect2.partition.quality(res) if best_bisect != bisect: bisect_values[res] = best_bisect # We only need to keep the changes in the bisection values bisect_list = sorted([(res, part.bisect_value) for res, part in bisect_values.items()], key=lambda x: x[0]) for (res1, v1), (res2, v2) \ in zip(bisect_list, bisect_list[1:]): # If two consecutive bisection values are the same, remove the second # resolution parameter if v1 == v2: del bisect_values[res2] for res, bisect in bisect_values.items(): bisect.partition.resolution_parameter = res # We assume here that the bisection values are # monotonically decreasing with increasing resolution # parameter values. def ensure_monotonicity(bisect_values, new_res): # First check if this partition improves on any other partition for res, bisect_part in bisect_values.items(): if bisect_values[new_res].partition.quality(res) > bisect_part.partition.quality(res): bisect_values[res] = bisect_values[new_res] # Then check what is best partition for the new_res current_quality = bisect_values[new_res].partition.quality(new_res) best_res = new_res for res, bisect_part in bisect_values.items(): if bisect_part.partition.quality(new_res) > current_quality: best_res = new_res bisect_values[new_res] = bisect_values[best_res] def find_partition(self, graph, partition_type, weights=None, **kwargs): partition = partition_type(graph, weights=weights, **kwargs) n_itr = 0 while self.optimise_partition(partition) > 0 and \ (n_itr < number_iterations or number_iterations <= 0): n_itr += 1 return partition assert issubclass(partition_type, LinearResolutionParameterVertexPartition), "Bisectioning only works on partitions with a linear resolution parameter." # Start actual bisectioning bisect_values = {} stack_res_range = [] # Push first range onto the stack stack_res_range.append(resolution_range) # Make sure the bisection values are calculated # The namedtuple we will use in the bisection function BisectPartition = namedtuple('BisectPartition', ['partition', 'bisect_value']) partition = find_partition(self, graph=graph, partition_type=partition_type, weights=weights,resolution_parameter=resolution_range[0], **kwargs) bisect_values[resolution_range[0]] = BisectPartition(partition=partition, bisect_value=bisect_func(partition)) partition = find_partition(self, graph=graph, partition_type=partition_type, weights=weights, resolution_parameter=resolution_range[1], **kwargs) bisect_values[resolution_range[1]] = BisectPartition(partition=partition, bisect_value=bisect_func(partition)) # While stack of ranges not yet empty try: from tqdm import tqdm progress = tqdm(total=float('inf')) except: progress = None while stack_res_range: # Get the current range from the stack current_range = stack_res_range.pop() # Get the difference in bisection values diff_bisect_value = abs(bisect_values[current_range[0]].bisect_value - bisect_values[current_range[1]].bisect_value) # Get the difference in resolution parameter (in log space if 0 is not in # the interval (assuming only non-negative resolution parameters). if current_range[0] > 0 and current_range[1] > 0 and not linear_bisection: diff_resolution = log(current_range[1]/current_range[0]) else: diff_resolution = abs(current_range[1] - current_range[0]) # Check if we still want to scan a smaller interval # If we would like to bisect this interval if diff_bisect_value > min_diff_bisect_value and \ diff_resolution > min_diff_resolution: # Determine new resolution value if current_range[0] > 0 and current_range[1] > 0 and not linear_bisection: new_res = sqrt(current_range[1]*current_range[0]) else: new_res = sum(current_range)/2.0 # Bisect left (push on stack) stack_res_range.append((current_range[0], new_res)) # Bisect right (push on stack) stack_res_range.append((new_res, current_range[1])) # If we haven't scanned this resolution value yet, # do so now if not new_res in bisect_values: partition = find_partition(self, graph, partition_type=partition_type, weights=weights, resolution_parameter=new_res, **kwargs) bisect_values[new_res] = BisectPartition(partition=partition, bisect_value=bisect_func(partition)) if progress is not None: progress.update(1) progress.set_postfix(resolution_parameter=new_res, refresh=False) # Because of stochastic differences in different runs, the monotonicity # of the bisection values might be violated, so check for any # inconsistencies ensure_monotonicity(bisect_values, new_res) if progress is not None: progress.close() # Ensure we only keep those resolution values for which # the bisection values actually changed, instead of all of them clean_stepwise(bisect_values) # Use an ordered dict so that when iterating over it, the results appear in # increasing order based on the resolution value. return sorted((bisect.partition for res, bisect in bisect_values.items()), key=lambda x: x.resolution_parameter) leidenalg-0.8.9/src/leidenalg/RBConfigurationVertexPartition.cpp000066400000000000000000000135101420514302700250140ustar00rootroot00000000000000#include "RBConfigurationVertexPartition.h" RBConfigurationVertexPartition::RBConfigurationVertexPartition(Graph* graph, vector const& membership, double resolution_parameter) : LinearResolutionParameterVertexPartition(graph, membership, resolution_parameter) { } RBConfigurationVertexPartition::RBConfigurationVertexPartition(Graph* graph, vector const& membership) : LinearResolutionParameterVertexPartition(graph, membership) { } RBConfigurationVertexPartition::RBConfigurationVertexPartition(Graph* graph, double resolution_parameter) : LinearResolutionParameterVertexPartition(graph, resolution_parameter) { } RBConfigurationVertexPartition::RBConfigurationVertexPartition(Graph* graph) : LinearResolutionParameterVertexPartition(graph) { } RBConfigurationVertexPartition::~RBConfigurationVertexPartition() { } RBConfigurationVertexPartition* RBConfigurationVertexPartition::create(Graph* graph) { return new RBConfigurationVertexPartition(graph, this->resolution_parameter); } RBConfigurationVertexPartition* RBConfigurationVertexPartition::create(Graph* graph, vector const& membership) { return new RBConfigurationVertexPartition(graph, membership, this->resolution_parameter); } /***************************************************************************** Returns the difference in modularity if we move a node to a new community *****************************************************************************/ double RBConfigurationVertexPartition::diff_move(size_t v, size_t new_comm) { #ifdef DEBUG cerr << "double RBConfigurationVertexPartition::diff_move(" << v << ", " << new_comm << ")" << endl; #endif size_t old_comm = this->_membership[v]; double diff = 0.0; double total_weight = this->graph->total_weight()*(2.0 - this->graph->is_directed()); if (total_weight == 0.0) return 0.0; if (new_comm != old_comm) { #ifdef DEBUG cerr << "\t" << "old_comm: " << old_comm << endl; #endif double w_to_old = this->weight_to_comm(v, old_comm); #ifdef DEBUG cerr << "\t" << "w_to_old: " << w_to_old << endl; #endif double w_from_old = this->weight_from_comm(v, old_comm); #ifdef DEBUG cerr << "\t" << "w_from_old: " << w_from_old << endl; #endif double w_to_new = this->weight_to_comm(v, new_comm); #ifdef DEBUG cerr << "\t" << "w_to_new: " << w_to_new << endl; #endif double w_from_new = this->weight_from_comm(v, new_comm); #ifdef DEBUG cerr << "\t" << "w_from_new: " << w_from_new << endl; #endif double k_out = this->graph->strength(v, IGRAPH_OUT); #ifdef DEBUG cerr << "\t" << "k_out: " << k_out << endl; #endif double k_in = this->graph->strength(v, IGRAPH_IN); #ifdef DEBUG cerr << "\t" << "k_in: " << k_in << endl; #endif double self_weight = this->graph->node_self_weight(v); #ifdef DEBUG cerr << "\t" << "self_weight: " << self_weight << endl; #endif double K_out_old = this->total_weight_from_comm(old_comm); #ifdef DEBUG cerr << "\t" << "K_out_old: " << K_out_old << endl; #endif double K_in_old = this->total_weight_to_comm(old_comm); #ifdef DEBUG cerr << "\t" << "K_in_old: " << K_in_old << endl; #endif double K_out_new = this->total_weight_from_comm(new_comm) + k_out; #ifdef DEBUG cerr << "\t" << "K_out_new: " << K_out_new << endl; #endif double K_in_new = this->total_weight_to_comm(new_comm) + k_in; #ifdef DEBUG cerr << "\t" << "K_in_new: " << K_in_new << endl; cerr << "\t" << "total_weight: " << total_weight << endl; #endif double diff_old = (w_to_old - this->resolution_parameter*k_out*K_in_old/total_weight) + \ (w_from_old - this->resolution_parameter*k_in*K_out_old/total_weight); #ifdef DEBUG cerr << "\t" << "diff_old: " << diff_old << endl; #endif double diff_new = (w_to_new + self_weight - this->resolution_parameter*k_out*K_in_new/total_weight) + \ (w_from_new + self_weight - this->resolution_parameter*k_in*K_out_new/total_weight); #ifdef DEBUG cerr << "\t" << "diff_new: " << diff_new << endl; #endif diff = diff_new - diff_old; #ifdef DEBUG cerr << "\t" << "diff: " << diff << endl; #endif } #ifdef DEBUG cerr << "exit RBConfigurationVertexPartition::diff_move(" << v << ", " << new_comm << ")" << endl; cerr << "return " << diff << endl << endl; #endif return diff; } /***************************************************************************** Give the modularity of the partition. We here use the unscaled version of modularity, in other words, we don"t normalise by the number of edges. ******************************************************************************/ double RBConfigurationVertexPartition::quality(double resolution_parameter) { #ifdef DEBUG cerr << "double ModularityVertexPartition::quality()" << endl; #endif double mod = 0.0; double m; if (this->graph->is_directed()) m = this->graph->total_weight(); else m = 2*this->graph->total_weight(); if (m == 0) return 0.0; for (size_t c = 0; c < this->n_communities(); c++) { double w = this->total_weight_in_comm(c); double w_out = this->total_weight_from_comm(c); double w_in = this->total_weight_to_comm(c); #ifdef DEBUG size_t csize = this->csize(c); cerr << "\t" << "Comm: " << c << ", size=" << csize << ", w=" << w << ", w_out=" << w_out << ", w_in=" << w_in << "." << endl; #endif mod += w - resolution_parameter*w_out*w_in/((this->graph->is_directed() ? 1.0 : 4.0)*this->graph->total_weight()); } double q = (2.0 - this->graph->is_directed())*mod; #ifdef DEBUG cerr << "exit double RBConfigurationVertexPartition::quality()" << endl; cerr << "return " << q << endl << endl; #endif return q; } leidenalg-0.8.9/src/leidenalg/RBERVertexPartition.cpp000066400000000000000000000121301420514302700225100ustar00rootroot00000000000000#include "RBERVertexPartition.h" RBERVertexPartition::RBERVertexPartition(Graph* graph, vector const& membership, double resolution_parameter) : LinearResolutionParameterVertexPartition(graph, membership, resolution_parameter) { } RBERVertexPartition::RBERVertexPartition(Graph* graph, vector const& membership) : LinearResolutionParameterVertexPartition(graph, membership) { } RBERVertexPartition::RBERVertexPartition(Graph* graph, double resolution_parameter) : LinearResolutionParameterVertexPartition(graph, resolution_parameter) { } RBERVertexPartition::RBERVertexPartition(Graph* graph) : LinearResolutionParameterVertexPartition(graph) { } RBERVertexPartition* RBERVertexPartition::create(Graph* graph) { return new RBERVertexPartition(graph, this->resolution_parameter); } RBERVertexPartition* RBERVertexPartition::create(Graph* graph, vector const& membership) { return new RBERVertexPartition(graph, membership, this->resolution_parameter); } RBERVertexPartition::~RBERVertexPartition() { } /******************************************************************************** RBER implementation of a vertex partition (which includes a resolution parameter). ********************************************************************************/ double RBERVertexPartition::diff_move(size_t v, size_t new_comm) { #ifdef DEBUG cerr << "double RBERVertexPartition::diff_move(" << v << ", " << new_comm << ")" << endl; #endif size_t old_comm = this->membership(v); double diff = 0.0; if (new_comm != old_comm) { double w_to_old = this->weight_to_comm(v, old_comm); #ifdef DEBUG cerr << "\t" << "w_to_old: " << w_to_old << endl; #endif double w_to_new = this->weight_to_comm(v, new_comm); #ifdef DEBUG cerr << "\t" << "w_to_new: " << w_to_new << endl; #endif double w_from_old = this->weight_from_comm(v, old_comm); #ifdef DEBUG cerr << "\t" << "w_from_old: " << w_from_old << endl; #endif double w_from_new = this->weight_from_comm(v, new_comm); #ifdef DEBUG cerr << "\t" << "w_from_new: " << w_from_new << endl; #endif size_t nsize = this->graph->node_size(v); #ifdef DEBUG cerr << "\t" << "nsize: " << nsize << endl; #endif size_t csize_old = this->csize(old_comm); #ifdef DEBUG cerr << "\t" << "csize_old: " << csize_old << endl; #endif size_t csize_new = this->csize(new_comm); #ifdef DEBUG cerr << "\t" << "csize_new: " << csize_new << endl; #endif double self_weight = this->graph->node_self_weight(v); #ifdef DEBUG cerr << "\t" << "self_weight: " << self_weight << endl; cerr << "\t" << "density: " << this->graph->density() << endl; #endif double possible_edge_difference_old = 0.0; if (this->graph->correct_self_loops()) possible_edge_difference_old = nsize*(ptrdiff_t)(2.0*csize_old - nsize); else possible_edge_difference_old = nsize*(ptrdiff_t)(2.0*csize_old - nsize - 1.0); #ifdef DEBUG cerr << "\t" << "possible_edge_difference_old: " << possible_edge_difference_old << endl; #endif double diff_old = w_to_old + w_from_old - self_weight - this->resolution_parameter*this->graph->density()*possible_edge_difference_old; #ifdef DEBUG cerr << "\t" << "diff_old: " << diff_old << endl; #endif double possible_edge_difference_new = 0.0; if (this->graph->correct_self_loops()) possible_edge_difference_new = nsize*(ptrdiff_t)(2.0*csize_new + nsize); else possible_edge_difference_new = nsize*(ptrdiff_t)(2.0*csize_new + nsize - 1.0); #ifdef DEBUG cerr << "\t" << "possible_edge_difference_new: " << possible_edge_difference_new << endl; #endif double diff_new = w_to_new + w_from_new + self_weight - this->resolution_parameter*this->graph->density()*possible_edge_difference_new; #ifdef DEBUG cerr << "\t" << "diff_new: " << diff_new << endl; #endif diff = diff_new - diff_old; #ifdef DEBUG cerr << "\t" << "diff: " << diff << endl;; #endif } #ifdef DEBUG cerr << "exit RBERVertexPartition::diff_move(" << v << ", " << new_comm << ")" << endl; cerr << "return " << diff << endl << endl; #endif return diff; } double RBERVertexPartition::quality(double resolution_parameter) { #ifdef DEBUG cerr << "double RBERVertexPartition::quality()" << endl; #endif double mod = 0.0; for (size_t c = 0; c < this->n_communities(); c++) { size_t csize = this->csize(c); double w = this->total_weight_in_comm(c); size_t comm_possible_edges = this->graph->possible_edges(csize); #ifdef DEBUG cerr << "\t" << "Comm: " << c << ", w_c=" << w << ", n_c=" << csize << ", comm_possible_edges=" << comm_possible_edges << ", p=" << this->graph->density() << "." << endl; #endif mod += w - resolution_parameter*this->graph->density()*comm_possible_edges; } #ifdef DEBUG cerr << "exit double RBERVertexPartition::quality()" << endl; cerr << "return " << mod << endl << endl; #endif return (2.0 - this->graph->is_directed())*mod; } leidenalg-0.8.9/src/leidenalg/ResolutionParameterVertexPartition.cpp000066400000000000000000000017311420514302700257670ustar00rootroot00000000000000#include "ResolutionParameterVertexPartition.h" ResolutionParameterVertexPartition::ResolutionParameterVertexPartition(Graph* graph, vector membership, double resolution_parameter) : MutableVertexPartition(graph, membership) { this->resolution_parameter = resolution_parameter; } ResolutionParameterVertexPartition::ResolutionParameterVertexPartition(Graph* graph, vector membership) : MutableVertexPartition(graph, membership) { this->resolution_parameter = 1.0; } ResolutionParameterVertexPartition::ResolutionParameterVertexPartition(Graph* graph, double resolution_parameter) : MutableVertexPartition(graph) { this->resolution_parameter = resolution_parameter; } ResolutionParameterVertexPartition::ResolutionParameterVertexPartition(Graph* graph) : MutableVertexPartition(graph) { this->resolution_parameter = 1.0; } ResolutionParameterVertexPartition::~ResolutionParameterVertexPartition() { } leidenalg-0.8.9/src/leidenalg/SignificanceVertexPartition.cpp000066400000000000000000000132501420514302700243440ustar00rootroot00000000000000#include "SignificanceVertexPartition.h" #ifdef DEBUG #include using std::cerr; using std::endl; #endif SignificanceVertexPartition::SignificanceVertexPartition(Graph* graph, vector const& membership) : MutableVertexPartition(graph, membership) { } SignificanceVertexPartition::SignificanceVertexPartition(Graph* graph) : MutableVertexPartition(graph) { } SignificanceVertexPartition* SignificanceVertexPartition::create(Graph* graph) { return new SignificanceVertexPartition(graph); } SignificanceVertexPartition* SignificanceVertexPartition::create(Graph* graph, vector const& membership) { return new SignificanceVertexPartition(graph, membership); } SignificanceVertexPartition::~SignificanceVertexPartition() { } double SignificanceVertexPartition::diff_move(size_t v, size_t new_comm) { #ifdef DEBUG cerr << "virtual double SignificanceVertexPartition::diff_move(" << v << ", " << new_comm << ")" << endl; #endif size_t old_comm = this->membership(v); size_t nsize = this->graph->node_size(v); double diff = 0.0; if (new_comm != old_comm) { double normalise = (2.0 - this->graph->is_directed()); double p = this->graph->density(); #ifdef DEBUG size_t n = this->graph->total_size(); cerr << "\t" << "Community: " << old_comm << " => " << new_comm << "." << endl; cerr << "\t" << "n: " << n << ", m: " << this->graph->total_weight() << ", p: " << p << "." << endl; #endif //Old comm size_t n_old = this->csize(old_comm); size_t N_old = this->graph->possible_edges(n_old); double m_old = this->total_weight_in_comm(old_comm); double q_old = 0.0; if (N_old > 0) q_old = m_old/N_old; #ifdef DEBUG cerr << "\t" << "n_old: " << n_old << ", N_old: " << N_old << ", m_old: " << m_old << ", q_old: " << q_old << ", KL: " << KL(q_old, p) << "." << endl; #endif // Old comm after move size_t n_oldx = n_old - nsize; // It should not be possible that this becomes negative, so no need for ptrdiff_t here. size_t N_oldx = this->graph->possible_edges(n_oldx); double sw = this->graph->node_self_weight(v); // Be careful to exclude the self weight here, because this is include in the weight_to_comm function. double wtc = this->weight_to_comm(v, old_comm) - sw; double wfc = this->weight_from_comm(v, old_comm) - sw; #ifdef DEBUG cerr << "\t" << "wtc: " << wtc << ", wfc: " << wfc << ", sw: " << sw << "." << endl; #endif double m_oldx = m_old - wtc/normalise - wfc/normalise - sw; double q_oldx = 0.0; if (N_oldx > 0) q_oldx = m_oldx/N_oldx; #ifdef DEBUG cerr << "\t" << "n_oldx: " << n_oldx << ", N_oldx: " << N_oldx << ", m_oldx: " << m_oldx << ", q_oldx: " << q_oldx << ", KL: " << KL(q_oldx, p) << "." << endl; #endif // New comm size_t n_new = this->csize(new_comm); size_t N_new = this->graph->possible_edges(n_new); double m_new = this->total_weight_in_comm(new_comm); double q_new = 0.0; if (N_new > 0) q_new = m_new/N_new; #ifdef DEBUG cerr << "\t" << "n_new: " << n_new << ", N_new: " << N_new << ", m_new: " << m_new << ", q_new: " << q_new << ", KL: " << KL(q_new, p) << "." << endl; #endif // New comm after move size_t n_newx = n_new + nsize; size_t N_newx = this->graph->possible_edges(n_newx); wtc = this->weight_to_comm(v, new_comm); wfc = this->weight_from_comm(v, new_comm); sw = this->graph->node_self_weight(v); #ifdef DEBUG cerr << "\t" << "wtc: " << wtc << ", wfc: " << wfc << ", sw: " << sw << "." << endl; #endif double m_newx = m_new + wtc/normalise + wfc/normalise + sw; double q_newx = 0.0; if (N_newx > 0) q_newx = m_newx/N_newx; #ifdef DEBUG cerr << "\t" << "n_newx: " << n_newx << ", N_newx: " << N_newx << ", m_newx: " << m_newx << ", q_newx: " << q_newx << ", KL: " << KL(q_newx, p) << "." << endl; #endif // Calculate actual diff if (N_oldx != N_new || q_oldx != q_new) diff += (double)N_oldx*KLL(q_oldx, p) - (double)N_new*KLL(q_new, p); if (N_newx != N_old || q_newx != q_old) diff += (double)N_newx*KLL(q_newx, p) - (double)N_old*KLL(q_old, p); #ifdef DEBUG cerr << "\t" << "diff: " << diff << "." << endl; #endif } #ifdef DEBUG cerr << "exit double SignificanceVertexPartition::diff_move(" << v << ", " << new_comm << ")" << endl; cerr << "return " << diff << endl << endl; #endif return diff; } /******************************************************************************** Calculate the significance of the partition. *********************************************************************************/ double SignificanceVertexPartition::quality() { #ifdef DEBUG cerr << "double SignificanceVertexPartition::quality()"; size_t n = this->graph->total_size(); #endif double S = 0.0; double p = this->graph->density(); #ifdef DEBUG cerr << "\t" << "n=" << n << ", m=" << this->graph->total_weight() << ", p=" << p << "." << endl; #endif for (size_t c = 0; c < this->n_communities(); c++) { size_t n_c = this->csize(c); double m_c = this->total_weight_in_comm(c); double p_c = 0.0; size_t N_c = this->graph->possible_edges(n_c); if (N_c > 0) p_c = m_c/N_c; #ifdef DEBUG cerr << "\t" << "c=" << c << ", n_c=" << n_c << ", m_c=" << m_c << ", N_c=" << N_c << ", p_c=" << p_c << ", p=" << p << ", KLL=" << KL(p_c, p) << "." << endl; #endif S += N_c*KLL(p_c, p); } #ifdef DEBUG cerr << "exit SignificanceVertexPartition::quality()" << endl; cerr << "return " << S << endl << endl; #endif return S; } leidenalg-0.8.9/src/leidenalg/SurpriseVertexPartition.cpp000066400000000000000000000105761420514302700236060ustar00rootroot00000000000000#include "SurpriseVertexPartition.h" SurpriseVertexPartition::SurpriseVertexPartition(Graph* graph, vector const& membership) : MutableVertexPartition(graph, membership) { } SurpriseVertexPartition::SurpriseVertexPartition(Graph* graph) : MutableVertexPartition(graph) { } SurpriseVertexPartition* SurpriseVertexPartition::create(Graph* graph) { return new SurpriseVertexPartition(graph); } SurpriseVertexPartition* SurpriseVertexPartition::create(Graph* graph, vector const& membership) { return new SurpriseVertexPartition(graph, membership); } SurpriseVertexPartition::~SurpriseVertexPartition() { } double SurpriseVertexPartition::diff_move(size_t v, size_t new_comm) { #ifdef DEBUG cerr << "virtual double SurpriseVertexPartition::diff_move(" << v << ", " << new_comm << ")" << endl; #endif size_t old_comm = this->membership(v); size_t nsize = this->graph->node_size(v); #ifdef DEBUG cerr << "\t" << "nsize: " << nsize << endl; #endif double diff = 0.0; double m = this->graph->total_weight(); if (m == 0) return 0.0; if (new_comm != old_comm) { double normalise = (2.0 - this->graph->is_directed()); size_t n = this->graph->total_size(); size_t n2 = this->graph->possible_edges(n); #ifdef DEBUG cerr << "\t" << "Community: " << old_comm << " => " << new_comm << "." << endl; cerr << "\t" << "m: " << m << ", n2: " << n2 << "." << endl; #endif // Before move double mc = this->total_weight_in_all_comms(); size_t nc2 = this->total_possible_edges_in_all_comms(); #ifdef DEBUG cerr << "\t" << "mc: " << mc << ", nc2: " << nc2 << "." << endl; #endif // To old comm size_t n_old = this->csize(old_comm); double sw = this->graph->node_self_weight(v); double wtc = this->weight_to_comm(v, old_comm) - sw; double wfc = this->weight_from_comm(v, old_comm) - sw; #ifdef DEBUG cerr << "\t" << "wtc: " << wtc << ", wfc: " << wfc << ", sw: " << sw << "." << endl; #endif double m_old = wtc/normalise + wfc/normalise + sw; #ifdef DEBUG cerr << "\t" << "m_old: " << m_old << ", n_old: " << n_old << "." << endl; #endif // To new comm size_t n_new = this->csize(new_comm); wtc = this->weight_to_comm(v, new_comm); wfc = this->weight_from_comm(v, new_comm); sw = this->graph->node_self_weight(v); #ifdef DEBUG cerr << "\t" << "wtc: " << wtc << ", wfc: " << wfc << ", sw: " << sw << "." << endl; #endif double m_new = wtc/normalise + wfc/normalise + sw; #ifdef DEBUG cerr << "\t" << "m_new: " << m_new << ", n_new: " << n_new << "." << endl; #endif double q = mc/m; double s = (double)nc2/(double)n2; double q_new = (mc - m_old + m_new)/m; #ifdef DEBUG cerr << "\t" << "mc - m_old + m_new=" << (mc - m_old + m_new) << endl; #endif double delta_nc2 = 2.0*nsize*(ptrdiff_t)(n_new - n_old + nsize)/normalise; double s_new = (double)(nc2 + delta_nc2)/(double)n2; #ifdef DEBUG cerr << "\t" << "delta_nc2=" << delta_nc2 << endl; #endif #ifdef DEBUG cerr << "\t" << "q:\t" << q << ", s:\t" << s << "." << endl; cerr << "\t" << "q_new:\t" << q_new << ", s_new:\t" << s_new << "." << endl; #endif diff = m*(KLL(q_new, s_new) - KLL(q, s)); #ifdef DEBUG cerr << "\t" << "diff: " << diff << "." << endl; #endif } #ifdef DEBUG cerr << "exit double SurpriseVertexPartition::diff_move(" << v << ", " << new_comm << ")" << endl; cerr << "return " << diff << endl << endl; #endif return diff; } double SurpriseVertexPartition::quality() { #ifdef DEBUG cerr << "double SurpriseVertexPartition::quality()" << endl; #endif double mc = this->total_weight_in_all_comms(); size_t nc2 = this->total_possible_edges_in_all_comms(); double m = this->graph->total_weight(); size_t n = this->graph->total_size(); if (m == 0) return 0.0; size_t n2 = this->graph->possible_edges(n); #ifdef DEBUG cerr << "\t" << "mc=" << mc << ", m=" << m << ", nc2=" << nc2 << ", n2=" << n2 << "." << endl; #endif double q = mc/m; double s = (double)nc2/(double)n2; #ifdef DEBUG cerr << "\t" << "q:\t" << q << ", s:\t" << s << "." << endl; #endif double S = m*KLL(q,s); #ifdef DEBUG cerr << "exit SurpriseVertexPartition::quality()" << endl; cerr << "return " << S << endl << endl; #endif return S; } leidenalg-0.8.9/src/leidenalg/VertexPartition.py000066400000000000000000001216261420514302700217160ustar00rootroot00000000000000import igraph as _ig from . import _c_leiden from .functions import _get_py_capsule class MutableVertexPartition(_ig.VertexClustering): """ Contains a partition of a graph, derives from :class:`ig.VertexClustering`. Please see the `documentation `_ of :class:`ig.VertexClustering` for more details about its functionality. This class contains the basic implementation for optimising a partition. Specifically, it implements all the administration necessary to keep track of the partition from various points of view. Internally, it keeps track of the number of internal edges (or total weight), the size of the communities, the total incoming degree (or weight) for a community, et cetera. In order to keep the administration up-to-date, all changes in a partition should be done through :func:`~VertexPartition.MutableVertexPartition.move_node` or :func:`~VertexPartition.MutableVertexPartition.set_membership`. The first moves a node from one community to another, and updates the administration. The latter simply updates the membership vector and updates the administration. The basic idea is that :func:`~VertexPartition.MutableVertexPartition.diff_move` computes the difference in the quality function if we would call :func:`~VertexPartition.MutableVertexPartition.move_node` for the same move. These functions are overridden in any derived classes to provide an actual implementation. These functions are used by :class:`Optimiser` to optimise the partition. .. warning:: This base class should never be used in practice, since only derived classes provide an actual implementation. """ # Init def __init__(self, graph, initial_membership=None): """ Parameters ---------- graph The :class:`ig.Graph` on which this partition is defined. membership The membership vector of this partition. ``Membership[i] = c`` implies that node ``i`` is in community ``c``. If ``None``, it is initialised with a singleton partition community, i.e. ``membership[i] = i``. """ if initial_membership is not None: initial_membership = list(initial_membership) super(MutableVertexPartition, self).__init__(graph, initial_membership) @classmethod def _FromCPartition(cls, partition): n, directed, edges, weights, node_sizes = _c_leiden._MutableVertexPartition_get_py_igraph(partition) graph = _ig.Graph(n=n, directed=directed, edges=edges, edge_attrs={'weight': weights}, vertex_attrs={'node_size': node_sizes}) new_partition = cls(graph) new_partition._partition = partition new_partition._update_internal_membership() return new_partition @classmethod def FromPartition(cls, partition, **kwargs): """ Create a new partition from an existing partition. Parameters ---------- partition The :class:`~VertexPartition.MutableVertexPartition` to replicate. **kwargs Any remaining keyword arguments will be passed on to the constructor of the new partition. Notes ----- This may for example come in handy when determining the quality of a partition using a different method. Suppose that we already have a partition ``p`` and that we want to determine the Significance of that partition. We can then simply use >>> p = la.find_partition(ig.Graph.Famous('Zachary'), ... la.ModularityVertexPartition) >>> sig = la.SignificanceVertexPartition.FromPartition(p).quality() """ new_partition = cls(partition.graph, partition.membership, **kwargs) return new_partition def _update_internal_membership(self): self._membership = _c_leiden._MutableVertexPartition_get_membership(self._partition) # Reset the length of the object, i.e. the number of communities if len(self._membership)>0: self._len = max(m for m in self._membership if m is not None)+1 else: self._len = 0 def set_membership(self, membership): """ Set membership. """ _c_leiden._MutableVertexPartition_set_membership(self._partition, list(membership)) self._update_internal_membership() # Calculate improvement *if* we move this node def diff_move(self,v,new_comm): """ Calculate the difference in the quality function if node ``v`` is moved to community ``new_comm``. Parameters ---------- v The node to move. new_comm The community to move to. Returns ------- float Difference in quality function. Notes ----- The difference returned by diff_move should be equivalent to first determining the quality of the partition, then calling move_node, and then determining again the quality of the partition and looking at the difference. In other words >>> partition = la.find_partition(ig.Graph.Famous('Zachary'), ... la.ModularityVertexPartition) >>> diff = partition.diff_move(v=0, new_comm=0) >>> q1 = partition.quality() >>> partition.move_node(v=0, new_comm=0) >>> q2 = partition.quality() >>> round(diff, 10) == round(q2 - q1, 10) True .. warning:: Only derived classes provide actual implementations, the base class provides no implementation for this function. """ return _c_leiden._MutableVertexPartition_diff_move(self._partition, v, new_comm) def aggregate_partition(self, membership_partition=None): """ Aggregate the graph according to the current partition and provide a default partition for it. The aggregated graph can then be found as a parameter of the partition ``partition.graph``. Notes ----- This function contrasts to the function ``cluster_graph`` in igraph itself, which also provides the aggregate graph, but we may require setting the appropriate ``resolution_parameter``, ``weights`` and ``node_sizes``. In particular, this function also ensures that the quality defined on the aggregate partition is identical to the quality defined on the original partition. Examples -------- >>> G = ig.Graph.Famous('Zachary') >>> partition = la.find_partition(G, la.ModularityVertexPartition) >>> aggregate_partition = partition.aggregate_partition(partition) >>> aggregate_graph = aggregate_partition.graph >>> aggregate_partition.quality() == partition.quality() True """ partition_agg = self._FromCPartition(_c_leiden._MutableVertexPartition_aggregate_partition(self._partition)) if (not membership_partition is None): membership = partition_agg.membership for v in self.graph.vs: membership[self.membership[v.index]] = membership_partition.membership[v.index] partition_agg.set_membership(membership) return partition_agg def move_node(self,v,new_comm): """ Move node ``v`` to community ``new_comm``. Parameters ---------- v Node to move. new_comm Community to move to. Examples -------- >>> G = ig.Graph.Famous('Zachary') >>> partition = la.ModularityVertexPartition(G) >>> partition.move_node(0, 1) """ _c_leiden._MutableVertexPartition_move_node(self._partition, v, new_comm) # Make sure this move is also reflected in the membership vector of the python object self._membership[v] = new_comm self._modularity_dirty = True def from_coarse_partition(self, partition, coarse_node=None): """ Update current partition according to coarser partition. Parameters ---------- partition : :class:`~VertexPartition.MutableVertexPartition` The coarser partition used to update the current partition. coarse_node : list of int The coarser node which represent the current node in the partition. Notes ----- This function is to be used to determine the correct partition for an aggregated graph. In particular, suppose we move nodes and then get an aggregate graph. >>> diff = optimiser.move_nodes(partition) >>> aggregate_partition = partition.aggregate_partition() Now we also move nodes in the aggregate partition >>> diff = optimiser.move_nodes(aggregate_partition) Now we improved the quality function of ``aggregate_partition``, but this is not yet reflected in the original ``partition``. We can thus call >>> partition.from_coarse_partition(aggregate_partition) so that ``partition`` now reflects the changes made to ``aggregate_partition``. The ``coarse_node`` can be used it the ``aggregate_partition`` is not defined based on the membership of this partition. In particular the membership of this partition is defined as follows: >>> for v in G.vs: ... partition.membership[v] = aggregate_partition.membership[coarse_node[v]] # doctest: +SKIP If ``coarse_node`` is :obj:`None` it is assumed the coarse node was defined based on the membership of the current partition, so that >>> for v in G.vs: ... partition.membership[v] = aggregate_partition.membership[partition.membership[v]] # doctest: +SKIP This can be useful when the aggregate partition is defined on a more refined partition. """ # Read the coarser partition _c_leiden._MutableVertexPartition_from_coarse_partition(self._partition, partition.membership, coarse_node) self._update_internal_membership() def renumber_communities(self): """ Renumber the communities so that they are numbered in decreasing size. Notes ----- The sort is not necessarily stable. """ _c_leiden._MutableVertexPartition_renumber_communities(self._partition) self._update_internal_membership() def quality(self): """ The current quality of the partition. """ return _c_leiden._MutableVertexPartition_quality(self._partition) def total_weight_in_comm(self, comm): """ The total weight (i.e. number of edges) within a community. Parameters ---------- comm Community See Also -------- :func:`~VertexPartition.MutableVertexPartition.total_weight_to_comm` :func:`~VertexPartition.MutableVertexPartition.total_weight_from_comm` :func:`~VertexPartition.MutableVertexPartition.total_weight_in_all_comms` """ return _c_leiden._MutableVertexPartition_total_weight_in_comm(self._partition, comm) def total_weight_from_comm(self, comm): """ The total weight (i.e. number of edges) from a community. Parameters ---------- comm Community Notes ----- This includes all edges, also the ones that are internal to a community. Sometimes this is also referred to as the community (out)degree. See Also -------- :func:`~VertexPartition.MutableVertexPartition.total_weight_to_comm` :func:`~VertexPartition.MutableVertexPartition.total_weight_in_comm` :func:`~VertexPartition.MutableVertexPartition.total_weight_in_all_comms` """ return _c_leiden._MutableVertexPartition_total_weight_from_comm(self._partition, comm) def total_weight_to_comm(self, comm): """ The total weight (i.e. number of edges) to a community. Parameters ---------- comm Community Notes ----- This includes all edges, also the ones that are internal to a community. Sometimes this is also referred to as the community (in)degree. See Also -------- :func:`~VertexPartition.MutableVertexPartition.total_weight_from_comm` :func:`~VertexPartition.MutableVertexPartition.total_weight_in_comm` :func:`~VertexPartition.MutableVertexPartition.total_weight_in_all_comms` """ return _c_leiden._MutableVertexPartition_total_weight_to_comm(self._partition, comm) def total_weight_in_all_comms(self): """ The total weight (i.e. number of edges) within all communities. Notes ----- This should be equal to simply the sum of ``total_weight_in_comm`` for all communities. See Also -------- :func:`~VertexPartition.MutableVertexPartition.total_weight_to_comm` :func:`~VertexPartition.MutableVertexPartition.total_weight_from_comm` :func:`~VertexPartition.MutableVertexPartition.total_weight_in_comm` """ return _c_leiden._MutableVertexPartition_total_weight_in_all_comms(self._partition) def total_possible_edges_in_all_comms(self): """ The total possible number of edges in all communities. Notes ----- If we denote by :math:`n_c` the number of nodes in community :math:`c`, this is simply .. math :: \\sum_c \\binom{n_c}{2} """ return _c_leiden._MutableVertexPartition_total_possible_edges_in_all_comms(self._partition) def weight_to_comm(self, v, comm): """ The total number of edges (or sum of weights) from node ``v`` to community ``comm``. See Also -------- :func:`~VertexPartition.MutableVertexPartition.weight_from_comm` """ return _c_leiden._MutableVertexPartition_weight_to_comm(self._partition, v, comm) def weight_from_comm(self, v, comm): """ The total number of edges (or sum of weights) to node ``v`` from community ``comm``. See Also -------- :func:`~VertexPartition.MutableVertexPartition.weight_to_comm` """ return _c_leiden._MutableVertexPartition_weight_from_comm(self._partition, v, comm) class ModularityVertexPartition(MutableVertexPartition): """ Implements modularity. This quality function is well-defined only for positive edge weights. Notes ----- The quality function is .. math:: Q = \\frac{1}{2m} \\sum_{ij} \\left(A_{ij} - \\frac{k_i k_j}{2m} \\right)\\delta(\\sigma_i, \\sigma_j) where :math:`A` is the adjacency matrix, :math:`k_i` is the (weighted) degree of node :math:`i`, :math:`m` is the total number of edges (or total edge weight), :math:`\\sigma_i` denotes the community of node :math:`i` and :math:`\\delta(\\sigma_i, \\sigma_j) = 1` if :math:`\\sigma_i = \\sigma_j` and `0` otherwise. This can alternatively be formulated as a sum over communities: .. math:: Q = \\frac{1}{2m} \\sum_{c} \\left(m_c - \\frac{K_c^2}{4m} \\right) where :math:`m_c` is the number of internal edges (or total internal edge weight) of community :math:`c` and :math:`K_c = \\sum_{i \\mid \\sigma_i = c} k_i` is the total (weighted) degree of nodes in community :math:`c`. Note that for directed graphs a slightly different formulation is used, as proposed by Leicht and Newman [2]: .. math:: Q = \\frac{1}{m} \\sum_{ij} \\left(A_{ij} - \\frac{k_i^\mathrm{out} k_j^\mathrm{in}}{m} \\right)\\delta(\\sigma_i, \\sigma_j), where :math:`k_i^\\mathrm{out}` and :math:`k_i^\\mathrm{in}` refers to respectively the outdegree and indegree of node :math:`i`, and :math:`A_{ij}` refers to an edge from :math:`i` to :math:`j`. References ---------- .. [1] Newman, M. E. J., & Girvan, M. (2004). Finding and evaluating community structure in networks. Physical Review E, 69(2), 026113. `10.1103/PhysRevE.69.026113 `_ .. [2] Leicht, E. A., & Newman, M. E. J. (2008). Community Structure in Directed Networks. Physical Review Letters, 100(11), 118703. `10.1103/PhysRevLett.100.118703 `_ """ def __init__(self, graph, initial_membership=None, weights=None): """ Parameters ---------- graph : :class:`ig.Graph` Graph to define the partition on. initial_membership : list of int Initial membership for the partition. If :obj:`None` then defaults to a singleton partition. weights : list of double, or edge attribute Weights of edges. Can be either an iterable or an edge attribute. """ if initial_membership is not None: initial_membership = list(initial_membership) super(ModularityVertexPartition, self).__init__(graph, initial_membership) pygraph_t = _get_py_capsule(graph) if weights is not None: if isinstance(weights, str): weights = graph.es[weights] else: # Make sure it is a list weights = list(weights) self._partition = _c_leiden._new_ModularityVertexPartition(pygraph_t, initial_membership, weights) self._update_internal_membership() def __deepcopy__(self, memo): n, directed, edges, weights, node_sizes = _c_leiden._MutableVertexPartition_get_py_igraph(self._partition) new_partition = ModularityVertexPartition(self.graph, self.membership, weights) return new_partition class SurpriseVertexPartition(MutableVertexPartition): """ Implements (asymptotic) Surprise. This quality function is well-defined only for positive edge weights. Notes ----- The quality function is .. math:: Q = m D(q \\parallel \\langle q \\rangle) where :math:`m` is the number of edges, .. math:: q = \\frac{\\sum_c m_c}{m}, is the fraction of internal edges, .. math:: \\langle q \\rangle = \\frac{\\sum_c \\binom{n_c}{2}}{\\binom{n}{2}} is the expected fraction of internal edges, and finally .. math:: D(x \\parallel y) = x \\ln \\frac{x}{y} + (1 - x) \\ln \\frac{1 - x}{1 - y} is the binary Kullback-Leibler divergence. For directed graphs we can multiplying the binomials by 2, and this leaves :math:`\\langle q \\rangle` unchanged, so that we can simply use the same formulation. For weighted graphs we can simply count the total internal weight instead of the total number of edges for :math:`q`, while :math:`\\langle q \\rangle` remains unchanged. References ---------- .. [1] Traag, V. A., Aldecoa, R., & Delvenne, J.-C. (2015). Detecting communities using asymptotical surprise. Physical Review E, 92(2), 022816. `10.1103/PhysRevE.92.022816 `_ """ def __init__(self, graph, initial_membership=None, weights=None, node_sizes=None): """ Parameters ---------- graph : :class:`ig.Graph` Graph to define the partition on. initial_membership : list of int Initial membership for the partition. If :obj:`None` then defaults to a singleton partition. weights : list of double, or edge attribute Weights of edges. Can be either an iterable or an edge attribute. node_sizes : list of int, or vertex attribute The quality function takes into account the size of a community, which is defined as the sum over the sizes of each individual node. By default, the node sizes are set to 1, meaning that the size of a community equals the number of nodes of a community. If a node already represents an aggregation, this could be reflect in its node size. """ if initial_membership is not None: initial_membership = list(initial_membership) super(SurpriseVertexPartition, self).__init__(graph, initial_membership) pygraph_t = _get_py_capsule(graph) if weights is not None: if isinstance(weights, str): weights = graph.es[weights] else: # Make sure it is a list weights = list(weights) if node_sizes is not None: if isinstance(node_sizes, str): node_sizes = graph.vs[node_sizes] else: # Make sure it is a list node_sizes = list(node_sizes) self._partition = _c_leiden._new_SurpriseVertexPartition(pygraph_t, initial_membership, weights, node_sizes) self._update_internal_membership() def __deepcopy__(self, memo): n, directed, edges, weights, node_sizes = _c_leiden._MutableVertexPartition_get_py_igraph(self._partition) new_partition = SurpriseVertexPartition(self.graph, self.membership, weights, node_sizes) return new_partition class SignificanceVertexPartition(MutableVertexPartition): """ Implements Significance. This quality function is well-defined only for unweighted graphs. Notes ----- The quality function is .. math:: Q = \\sum_c \\binom{n_c}{2} D(p_c \\parallel p) where :math:`n_c` is the number of nodes in community :math:`c`, .. math:: p_c = \\frac{m_c}{\\binom{n_c}{2}}, is the density of community :math:`c`, .. math:: p = \\frac{m}{\\binom{n}{2}} is the overall density of the graph, and finally .. math:: D(x \\parallel y) = x \\ln \\frac{x}{y} + (1 - x) \\ln \\frac{1 - x}{1 - y} is the binary Kullback-Leibler divergence. For directed graphs simply multiply the binomials by 2. The expected Significance in Erdos-Renyi graphs behaves roughly as :math:`\\frac{1}{2} n \\ln n` for both directed and undirected graphs in this formulation. .. warning:: This method is not suitable for weighted graphs. References ---------- .. [1] Traag, V. A., Krings, G., & Van Dooren, P. (2013). Significant scales in community structure. Scientific Reports, 3, 2930. `10.1038/srep02930 `_ """ def __init__(self, graph, initial_membership=None, node_sizes=None): """ Parameters ---------- graph : :class:`ig.Graph` Graph to define the partition on. initial_membership : list of int Initial membership for the partition. If :obj:`None` then defaults to a singleton partition. node_sizes : list of int, or vertex attribute The quality function takes into account the size of a community, which is defined as the sum over the sizes of each individual node. By default, the node sizes are set to 1, meaning that the size of a community equals the number of nodes of a community. If a node already represents an aggregation, this could be reflect in its node size. """ if initial_membership is not None: initial_membership = list(initial_membership) super(SignificanceVertexPartition, self).__init__(graph, initial_membership) pygraph_t = _get_py_capsule(graph) if node_sizes is not None: if isinstance(node_sizes, str): node_sizes = graph.vs[node_sizes] else: # Make sure it is a list node_sizes = list(node_sizes) self._partition = _c_leiden._new_SignificanceVertexPartition(pygraph_t, initial_membership, node_sizes) self._update_internal_membership() def __deepcopy__(self, memo): n, directed, edges, weights, node_sizes = _c_leiden._MutableVertexPartition_get_py_igraph(self._partition) new_partition = SignificanceVertexPartition(self.graph, self.membership, node_sizes) return new_partition class LinearResolutionParameterVertexPartition(MutableVertexPartition): """ Some quality functions have a linear resolution parameter, for which the basis is implemented here. With a linear resolution parameter, we mean that the objective function has the form: .. math:: Q = E - \\gamma F where :math:`\\gamma` is some resolution parameter and :math:`E` and :math:`F` arbitrary other functions of the partition. One thing that can be easily done on these type of quality functions, is bisectioning on the gamma function (also assuming that :math:`E` is a stepwise decreasing monotonic function, e.g. as for :class:`CPMVertexPartition`). """ def __init__(self, graph, initial_membership=None): if initial_membership is not None: initial_membership = list(initial_membership) super(LinearResolutionParameterVertexPartition, self).__init__(graph, initial_membership) #########################################################3 # resolution parameter @property def resolution_parameter(self): """ Resolution parameter. """ return _c_leiden._ResolutionParameterVertexPartition_get_resolution(self._partition) @resolution_parameter.setter def resolution_parameter(self, value): return _c_leiden._ResolutionParameterVertexPartition_set_resolution(self._partition, value) def bisect_value(self): """ Give the value on which we can perform bisectioning. If p1 and p2 are two different optimal partitions for two different resolution parameters g1 and g2, then if p1.bisect_value() == p2.bisect_value() the two partitions should be optimal for both g1 and g2. """ return self.total_weight_in_all_comms() def quality(self, resolution_parameter=None): return _c_leiden._ResolutionParameterVertexPartition_quality(self._partition, resolution_parameter) class RBERVertexPartition(LinearResolutionParameterVertexPartition): """ Implements Reichardt and Bornholdt’s Potts model with an ErdÅ‘s-Rényi null model. This quality function is well-defined only for positive edge weights. This quality function uses a linear resolution parameter. Notes ----- The quality function is .. math:: Q = \\sum_{ij} \\left(A_{ij} - \\gamma p \\right)\\delta(\\sigma_i, \\sigma_j) where :math:`A` is the adjacency matrix, .. math:: p = \\frac{m}{\\binom{n}{2}} is the overall density of the graph, :math:`\\sigma_i` denotes the community of node :math:`i`, :math:`\\delta(\\sigma_i, \\sigma_j) = 1` if :math:`\\sigma_i = \\sigma_j` and `0` otherwise, and, finally :math:`\\gamma` is a resolution parameter. This can alternatively be formulated as a sum over communities: .. math:: Q = \\sum_{c} \\left[m_c - \\gamma p \\binom{n_c}{2} \\right] where :math:`m_c` is the number of internal edges of community :math:`c` and :math:`n_c` the number of nodes in community :math:`c`. References ---------- .. [1] Reichardt, J., & Bornholdt, S. (2006). Statistical mechanics of community detection. Physical Review E, 74(1), 016110. `10.1103/PhysRevE.74.016110 `_ """ def __init__(self, graph, initial_membership=None, weights=None, node_sizes=None, resolution_parameter=1.0): """ Parameters ---------- graph : :class:`ig.Graph` Graph to define the partition on. initial_membership : list of int Initial membership for the partition. If :obj:`None` then defaults to a singleton partition. weights : list of double, or edge attribute Weights of edges. Can be either an iterable or an edge attribute. node_sizes : list of int, or vertex attribute The quality function takes into account the size of a community, which is defined as the sum over the sizes of each individual node. By default, the node sizes are set to 1, meaning that the size of a community equals the number of nodes of a community. If a node already represents an aggregation, this could be reflect in its node size. resolution_parameter : double Resolution parameter. """ if initial_membership is not None: initial_membership = list(initial_membership) super(RBERVertexPartition, self).__init__(graph, initial_membership) pygraph_t = _get_py_capsule(graph) if weights is not None: if isinstance(weights, str): weights = graph.es[weights] else: # Make sure it is a list weights = list(weights) if node_sizes is not None: if isinstance(node_sizes, str): node_sizes = graph.vs[node_sizes] else: # Make sure it is a list node_sizes = list(node_sizes) self._partition = _c_leiden._new_RBERVertexPartition(pygraph_t, initial_membership, weights, node_sizes, resolution_parameter) self._update_internal_membership() def __deepcopy__(self, memo): n, directed, edges, weights, node_sizes = _c_leiden._MutableVertexPartition_get_py_igraph(self._partition) new_partition = RBERVertexPartition(self.graph, self.membership, weights, node_sizes, self.resolution_parameter) return new_partition class RBConfigurationVertexPartition(LinearResolutionParameterVertexPartition): """ Implements Reichardt and Bornholdt's Potts model with a configuration null model. This quality function is well-defined only for positive edge weights. This quality function uses a linear resolution parameter. Notes ----- The quality function is .. math:: Q = \\sum_{ij} \\left(A_{ij} - \\gamma \\frac{k_i k_j}{2m} \\right)\\delta(\\sigma_i, \\sigma_j) where :math:`A` is the adjacency matrix, :math:`k_i` is the (weighted) degree of node :math:`i`, :math:`m` is the total number of edges (or total edge weight), :math:`\\sigma_i` denotes the community of node :math:`i` and :math:`\\delta(\\sigma_i, \\sigma_j) = 1` if :math:`\\sigma_i = \\sigma_j` and `0` otherwise. This can alternatively be formulated as a sum over communities: .. math:: Q = \\sum_{c} \\left(m_c - \\gamma \\frac{K_c^2}{4m} \\right) where :math:`m_c` is the number of internal edges (or total internal edge weight) of community :math:`c` and :math:`K_c = \\sum_{i \\mid \\sigma_i = c} k_i` is the total (weighted) degree of nodes in community :math:`c`. Note that for directed graphs a slightly different formulation is used, as proposed by Leicht and Newman [2]: .. math:: Q = \\sum_{ij} \\left(A_{ij} - \\gamma \\frac{k_i^\mathrm{out} k_j^\mathrm{in}}{m} \\right)\\delta(\\sigma_i, \\sigma_j), where :math:`k_i^\\mathrm{out}` and :math:`k_i^\\mathrm{in}` refers to respectively the outdegree and indegree of node :math:`i`, and :math:`A_{ij}` refers to an edge from :math:`i` to :math:`j`. Note that this is the same as :class:`ModularityVertexPartition` when setting :math:`\\gamma=1` and normalising by :math:`2m`, or :math:`m` for directed graphs. References ---------- .. [1] Reichardt, J., & Bornholdt, S. (2006). Statistical mechanics of community detection. Physical Review E, 74(1), 016110. `10.1103/PhysRevE.74.016110 `_ .. [2] Leicht, E. A., & Newman, M. E. J. (2008). Community Structure in Directed Networks. Physical Review Letters, 100(11), 118703. `10.1103/PhysRevLett.100.118703 `_ """ def __init__(self, graph, initial_membership=None, weights=None, resolution_parameter=1.0): """ Parameters ---------- graph : :class:`ig.Graph` Graph to define the partition on. initial_membership : list of int Initial membership for the partition. If :obj:`None` then defaults to a singleton partition. weights : list of double, or edge attribute Weights of edges. Can be either an iterable or an edge attribute. resolution_parameter : double Resolution parameter. """ if initial_membership is not None: initial_membership = list(initial_membership) super(RBConfigurationVertexPartition, self).__init__(graph, initial_membership) pygraph_t = _get_py_capsule(graph) if weights is not None: if isinstance(weights, str): weights = graph.es[weights] else: # Make sure it is a list weights = list(weights) self._partition = _c_leiden._new_RBConfigurationVertexPartition(pygraph_t, initial_membership, weights, resolution_parameter) self._update_internal_membership() def __deepcopy__(self, memo): n, directed, edges, weights, node_sizes = _c_leiden._MutableVertexPartition_get_py_igraph(self._partition) new_partition = RBConfigurationVertexPartition(self.graph, self.membership, weights, self.resolution_parameter) return new_partition class CPMVertexPartition(LinearResolutionParameterVertexPartition): """ Implements the Constant Potts Model (CPM). This quality function is well-defined for both positive and negative edge weights. This quality function uses a linear resolution parameter. Notes ----- The Constant Potts Model (CPM) quality function is .. math:: Q = \\sum_{ij} \\left(A_{ij} - \\gamma \\right)\\delta(\\sigma_i, \\sigma_j) where :math:`A` is the adjacency matrix, :math:`\\sigma_i` denotes the community of node :math:`i`, :math:`\\delta(\\sigma_i, \\sigma_j) = 1` if :math:`\\sigma_i = \\sigma_j` and `0` otherwise, and, finally :math:`\\gamma` is a resolution parameter. This can alternatively be formulated as a sum over communities: .. math:: Q = \\sum_{c} \\left[m_c - \\gamma \\binom{n_c}{2} \\right] where :math:`m_c` is the number of internal edges of community :math:`c` and :math:`n_c` the number of nodes in community :math:`c`. The resolution parameter :math:`\\gamma` for this functions has a particularly simple interpretation. The internal density of communities .. math:: p_c = \\frac{m_c}{\\binom{n_c}{2}} \\geq \\gamma is higher than :math:`\\gamma`, while the external density .. math:: p_{cd} = \\frac{m_{cd}}{n_c n_d} \\leq \\gamma is lower than :math:`\\gamma`. In other words, choosing a particular :math:`\\gamma` corresponds to choosing to find communities of a particular density, and as such defines communities. Finally, the definition of a community is in a sense independent of the actual graph, which is not the case for any of the other methods (see the reference for more detail). References ---------- .. [1] Traag, V. A., Van Dooren, P., & Nesterov, Y. (2011). Narrow scope for resolution-limit-free community detection. Physical Review E, 84(1), 016114. `10.1103/PhysRevE.84.016114 `_ """ def __init__(self, graph, initial_membership=None, weights=None, node_sizes=None, resolution_parameter=1.0): """ Parameters ---------- graph : :class:`ig.Graph` Graph to define the partition on. initial_membership : list of int Initial membership for the partition. If :obj:`None` then defaults to a singleton partition. weights : list of double, or edge attribute Weights of edges. Can be either an iterable or an edge attribute. node_sizes : list of int, or vertex attribute The quality function takes into account the size of a community, which is defined as the sum over the sizes of each individual node. By default, the node sizes are set to 1, meaning that the size of a community equals the number of nodes of a community. If a node already represents an aggregation, this could be reflect in its node size. resolution_parameter : double Resolution parameter. """ if initial_membership is not None: initial_membership = list(initial_membership) super(CPMVertexPartition, self).__init__(graph, initial_membership) pygraph_t = _get_py_capsule(graph) if weights is not None: if isinstance(weights, str): weights = graph.es[weights] else: # Make sure it is a list weights = list(weights) if node_sizes is not None: if isinstance(node_sizes, str): node_sizes = graph.vs[node_sizes] else: # Make sure it is a list node_sizes = list(node_sizes) self._partition = _c_leiden._new_CPMVertexPartition(pygraph_t, initial_membership, weights, node_sizes, resolution_parameter) self._update_internal_membership() def __deepcopy__(self, memo): n, directed, edges, weights, node_sizes = _c_leiden._MutableVertexPartition_get_py_igraph(self._partition) new_partition = CPMVertexPartition(self.graph, self.membership, weights, node_sizes, self.resolution_parameter) return new_partition @classmethod def Bipartite(cls, graph, resolution_parameter_01, resolution_parameter_0 = 0, resolution_parameter_1 = 0, degree_as_node_size=False, types='type', **kwargs): """ Create three layers for bipartite partitions. This creates three layers for bipartite partition necessary for detecting communities in bipartite networks. These three layers should be passed to :func:`Optimiser.optimise_partition_multiplex` with ``layer_weights=[1,-1,-1]``. See `Notes <#notes-bipartite>`_ for more details. Parameters ---------- graph : :class:`ig.Graph` Graph to define the bipartite partitions on. resolution_parameter_01 : double Resolution parameter for in between two classes. resolution_parameter_0 : double Resolution parameter for class 0. resolution_parameter_1 : double Resolution parameter for class 1. degree_as_node_size : boolean If ``True`` use degree as node size instead of 1, to mimic modularity, see `Notes <#notes-bipartite>`_. types : vertex attribute or list Indicator of the class for each vertex. If not 0, 1, it is automatically converted. **kwargs Additional arguments passed on to default constructor of :class:`CPMVertexPartition`. Returns ------- :class:`ig.CPMVertexPartition` partition containing the bipartite graph and correct node sizes. :class:`ig.CPMVertexPartition` partition for type 0, containing the correct node sizes for type 0. :class:`ig.CPMVertexPartition` partition for type 1, containing the correct node sizes for type 1. .. _notes-bipartite: Notes ----- For bipartite networks, we would like to be able to set three different resolution parameters: one for within each class :math:`\\gamma_0, \\gamma_1`, and one for the links between classes, :math:`\\gamma_{01}`. Then the formulation would be .. math:: Q = \\sum_{ij} [A_{ij} - (\\gamma_0\\delta(s_i,0) + \\gamma_1\\delta(s_i,1)) \\delta(s_i,s_j) - \\gamma_{01}(1 - \\delta(s_i, s_j)) ]\\delta(\\sigma_i, \\sigma_j) In terms of communities this is .. math:: Q = \\sum_c (e_c - \\gamma_{01} 2 n_c(0) n_c(1) - \\gamma_0 n^2_c(0) - \\gamma_1 n^2_c(1)) where :math:`n_c(0)` is the number of nodes in community :math:`c` of class 0 (and similarly for 1) and :math:`e_c` is the number of edges within community :math:`c`. We denote by :math:`n_c = n_c(0) + n_c(1)` the total number of nodes in community :math:`c`. We achieve this by creating three layers : (1) all nodes have ``node_size = 1`` and all relevant links; (2) only nodes of class 0 have ``node_size = 1`` and no links; (3) only nodes of class 1 have ``node_size = 1`` and no links. If we add the first with resolution parameter :math:`\\gamma_{01}`, and the others with resolution parameters :math:`\\gamma_{01} - \\gamma_0` and :math:`\\gamma_{01} - \\gamma_1`, but the latter two with a layer weight of -1 while the first layer has layer weight 1, we obtain the following: .. math:: Q &= \\sum_c (e_c - \\gamma_{01} n_c^2) -\\sum_c (- (\\gamma_{01} - \\gamma_0) n_c(0)^2) -\\sum_c (- (\\gamma_{01} - \\gamma_1) n_c(1)^2) \\\\ &= \\sum_c [e_c - \\gamma_{01} 2 n_c(0) n_c(1) - \\gamma_{01} n_c(0)^2 - \\gamma_{01} n_c(1)^2) + ( \\gamma_{01} - \\gamma_0) n_c(0)^2 + ( \\gamma_{01} - \\gamma_1) n_c(1)^2 ] \\\\ &= \\sum_c [e_c - \\gamma_{01} 2 n_c(0) n_c(1) - \\gamma_{0} n_c(0)^2 - \\gamma_{1} n_c(1)^2] Although the derivation above is using :math:`n_c^2`, implicitly assuming a direct graph with self-loops, similar derivations can be made for undirected graphs using :math:`\\binom{n_c}{2}`, but the notation is then somewhat more convoluted. If we set node sizes equal to the degree, we get something similar to modularity, except that the resolution parameter should still be divided by :math:`2m`. In particular, in general (i.e. not specifically for bipartite graph) if ``node_sizes=G.degree()`` we then obtain .. math:: Q = \\sum_{ij} A_{ij} - \\gamma k_i k_j In the case of bipartite graphs something similar is obtained, but then correctly adapted (as long as the resolution parameter is also appropriately rescaled). .. note:: This function is not suited for directed graphs in the case of using the degree as node sizes. """ if types is not None: if isinstance(types, str): types = graph.vs[types] else: # Make sure it is a list types = list(types) if set(types) != set([0, 1]): new_type = _ig.UniqueIdGenerator() types = [new_type[t] for t in types] if set(types) != set([0, 1]): raise ValueError("More than one type specified.") if degree_as_node_size: if (graph.is_directed()): raise ValueError("This method is not suitable for directed graphs " + "when using degree as node sizes.") node_sizes = graph.degree() else: node_sizes = [1]*graph.vcount() partition_01 = cls(graph, node_sizes=node_sizes, resolution_parameter=resolution_parameter_01, **kwargs) H_0 = graph.subgraph_edges([], delete_vertices=False) partition_0 = cls(H_0, weights=None, node_sizes=[s if t == 0 else 0 for v, s, t in zip(graph.vs,node_sizes,types)], resolution_parameter=resolution_parameter_01 - resolution_parameter_0) H_1 = graph.subgraph_edges([], delete_vertices=False) partition_1 = cls(H_1, weights=None, node_sizes=[s if t == 1 else 0 for v, s, t in zip(graph.vs,node_sizes,types)], resolution_parameter=resolution_parameter_01 - resolution_parameter_1) return partition_01, partition_0, partition_1 leidenalg-0.8.9/src/leidenalg/__init__.py000066400000000000000000000045101420514302700202760ustar00rootroot00000000000000# -*- coding: utf-8 -*- r""" This package implements the Leiden algorithm in ``C++`` and exposes it to python. It relies on ``(python-)igraph`` for it to function. Besides the relative flexibility of the implementation, it also scales well, and can be run on graphs of millions of nodes (as long as they can fit in memory). Each method is represented by a different class, all of whom derive from :class:`~leidenalg.VertexPartition.MutableVertexPartition`. In addition, multiplex graphs are supported as layers, which also supports multislice representations. Examples -------- The simplest example just finds a partition using modularity >>> G = ig.Graph.Tree(100, 3) >>> partition = la.find_partition(G, la.ModularityVertexPartition) Alternatively, one can access the different optimisation routines individually and construct partitions oneself. These partitions can then be optimised by constructing an :class:`Optimiser` object and running :func:`~Optimiser.optimise_partition`. >>> G = ig.Graph.Tree(100, 3) >>> partition = la.CPMVertexPartition(G, resolution_parameter = 0.1) >>> optimiser = la.Optimiser() >>> diff = optimiser.optimise_partition(partition) The :class:`Optimiser` class contains also the different subroutines that are used internally by :func:`~Optimiser.optimise_partition`. In addition, through the Optimiser class there are various options available for changing some of the optimisation procedure which can affect both speed and quality, which are not immediately available in :func:`leidenalg.find_partition`. """ from .functions import ALL_COMMS from .functions import ALL_NEIGH_COMMS from .functions import RAND_COMM from .functions import RAND_NEIGH_COMM from .functions import MOVE_NODES from .functions import MERGE_NODES from .functions import find_partition from .functions import find_partition_multiplex from .functions import find_partition_temporal from .functions import slices_to_layers from .functions import time_slices_to_layers from .Optimiser import Optimiser from .VertexPartition import ModularityVertexPartition from .VertexPartition import SurpriseVertexPartition from .VertexPartition import SignificanceVertexPartition from .VertexPartition import RBERVertexPartition from .VertexPartition import RBConfigurationVertexPartition from .VertexPartition import CPMVertexPartition from .version import * leidenalg-0.8.9/src/leidenalg/functions.py000066400000000000000000000471361420514302700205620ustar00rootroot00000000000000import sys import igraph as _ig from . import _c_leiden from ._c_leiden import ALL_COMMS from ._c_leiden import ALL_NEIGH_COMMS from ._c_leiden import RAND_COMM from ._c_leiden import RAND_NEIGH_COMM from ._c_leiden import MOVE_NODES from ._c_leiden import MERGE_NODES from collections import Counter def _get_py_capsule(graph): return graph.__graph_as_capsule() from .VertexPartition import * from .Optimiser import * def find_partition(graph, partition_type, initial_membership=None, weights=None, n_iterations=2, max_comm_size=0, seed=None, **kwargs): """ Detect communities using the default settings. This function detects communities given the specified method in the ``partition_type``. This should be type derived from :class:`VertexPartition.MutableVertexPartition`, e.g. :class:`ModularityVertexPartition` or :class:`CPMVertexPartition`. Optionally an initial membership and edge weights can be provided. Remaining ``**kwargs`` are passed on to the constructor of the ``partition_type``, including for example a ``resolution_parameter``. Parameters ---------- graph : :class:`ig.Graph` The graph for which to detect communities. partition_type : type of :class:` The type of partition to use for optimisation. initial_membership : list of int Initial membership for the partition. If :obj:`None` then defaults to a singleton partition. weights : list of double, or edge attribute Weights of edges. Can be either an iterable or an edge attribute. n_iterations : int Number of iterations to run the Leiden algorithm. By default, 2 iterations are run. If the number of iterations is negative, the Leiden algorithm is run until an iteration in which there was no improvement. max_comm_size : non-negative int Maximal total size of nodes in a community. If zero (the default), then communities can be of any size. seed : int Seed for the random number generator. By default uses a random seed if nothing is specified. **kwargs Remaining keyword arguments, passed on to constructor of ``partition_type``. Returns ------- partition The optimised partition. See Also -------- :func:`Optimiser.optimise_partition` Examples -------- >>> G = ig.Graph.Famous('Zachary') >>> partition = la.find_partition(G, la.ModularityVertexPartition) """ if not weights is None: kwargs['weights'] = weights partition = partition_type(graph, initial_membership=initial_membership, **kwargs) optimiser = Optimiser() optimiser.max_comm_size = max_comm_size if (not seed is None): optimiser.set_rng_seed(seed) optimiser.optimise_partition(partition, n_iterations) return partition def find_partition_multiplex(graphs, partition_type, n_iterations=2, max_comm_size=0, seed=None, **kwargs): """ Detect communities for multiplex graphs. Each graph should be defined on the same set of vertices, only the edges may differ for different graphs. See :func:`Optimiser.optimise_partition_multiplex` for a more detailed explanation. Parameters ---------- graphs : list of :class:`ig.Graph` List of :class:`ig.Graph` graphs to optimise. partition_type : type of :class:`MutableVertexPartition` The type of partition to use for optimisation (identical for all graphs). n_iterations : int Number of iterations to run the Leiden algorithm. By default, 2 iterations are run. If the number of iterations is negative, the Leiden algorithm is run until an iteration in which there was no improvement. max_comm_size : non-negative int Maximal total size of nodes in a community. If zero (the default), then communities can be of any size. seed : int Seed for the random number generator. By default uses a random seed if nothing is specified. **kwargs Remaining keyword arguments, passed on to constructor of ``partition_type``. Returns ------- list of int membership of nodes. float Improvement in quality of combined partitions, see :func:`Optimiser.optimise_partition_multiplex`. Notes ----- We don't return a partition in this case because a partition is always defined on a single graph. We therefore simply return the membership (which is the same for all layers). See Also -------- :func:`Optimiser.optimise_partition_multiplex` :func:`slices_to_layers` Examples -------- >>> n = 100 >>> G_1 = ig.Graph.Lattice([n], 1) >>> G_2 = ig.Graph.Lattice([n], 1) >>> membership, improvement = la.find_partition_multiplex([G_1, G_2], ... la.ModularityVertexPartition) """ n_layers = len(graphs) partitions = [] layer_weights = [1]*n_layers for graph in graphs: partitions.append(partition_type(graph, **kwargs)) optimiser = Optimiser() optimiser.max_comm_size = max_comm_size; if (not seed is None): optimiser.set_rng_seed(seed) improvement = optimiser.optimise_partition_multiplex(partitions, layer_weights, n_iterations) return partitions[0].membership, improvement def find_partition_temporal(graphs, partition_type, interslice_weight=1, slice_attr='slice', vertex_id_attr='id', edge_type_attr='type', weight_attr='weight', n_iterations=2, max_comm_size=0, seed=None, **kwargs): """ Detect communities for temporal graphs. Each graph is considered to represent a time slice and does not necessarily need to be defined on the same set of vertices. Nodes in two consecutive slices are identified on the basis of the ``vertex_id_attr``, i.e. if two nodes in two consecutive slices have an identical value of the ``vertex_id_attr`` they are coupled. The ``vertex_id_attr`` should hence be unique in each slice. The nodes are then coupled with a weight of ``interslice_weight`` which is set in the edge attribute ``weight_attr``. No weight is set if the ``interslice_weight`` is None (i.e. corresponding in practice with a weight of 1). See :func:`time_slices_to_layers` for a more detailed explanation. Parameters ---------- graphs : list of :class:`ig.Graph` List of :class:`leidenalg.VertexPartition` layers to optimise. partition_type : type of :class:`VertexPartition.MutableVertexPartition` The type of partition to use for optimisation (identical for all graphs). interslice_weight : float The weight of the coupling between two consecutive time slices. slice_attr : string The vertex attribute to use for indicating the slice of a node. vertex_id_attr : string The vertex to use to identify nodes. edge_type_attr : string The edge attribute to use for indicating the type of link (`interslice` or `intraslice`). weight_attr : string The edge attribute used to indicate the weight. n_iterations : int Number of iterations to run the Leiden algorithm. By default, 2 iterations are run. If the number of iterations is negative, the Leiden algorithm is run until an iteration in which there was no improvement. max_comm_size : non-negative int Maximal total size of nodes in a community. If zero (the default), then communities can be of any size. seed : int Seed for the random number generator. By default uses a random seed if nothing is specified. **kwargs Remaining keyword arguments, passed on to constructor of ``partition_type``. Returns ------- list of membership list containing for each slice the membership vector. float Improvement in quality of combined partitions, see :func:`Optimiser.optimise_partition_multiplex`. See Also -------- :func:`time_slices_to_layers` :func:`slices_to_layers` Examples -------- >>> n = 100 >>> G_1 = ig.Graph.Lattice([n], 1) >>> G_1.vs['id'] = range(n) >>> G_2 = ig.Graph.Lattice([n], 1) >>> G_2.vs['id'] = range(n) >>> membership, improvement = la.find_partition_temporal([G_1, G_2], ... la.ModularityVertexPartition, ... interslice_weight=1) """ # Create layers G_layers, G_interslice, G = time_slices_to_layers(graphs, interslice_weight, slice_attr=slice_attr, vertex_id_attr=vertex_id_attr, edge_type_attr=edge_type_attr, weight_attr=weight_attr) # Optimise partitions arg_dict = {} if 'node_sizes' in partition_type.__init__.__code__.co_varnames: arg_dict['node_sizes'] = 'node_size' if 'weights' in partition_type.__init__.__code__.co_varnames: arg_dict['weights'] = 'weight' arg_dict.update(kwargs) partitions = [] for H in G_layers: arg_dict['graph'] = H partitions.append(partition_type(**arg_dict)) # We can always take the same interslice partition, as this should have no # cost in the optimisation. partition_interslice = CPMVertexPartition(G_interslice, resolution_parameter=0, node_sizes='node_size', weights=weight_attr) optimiser = Optimiser() optimiser.max_comm_size = max_comm_size if (not seed is None): optimiser.set_rng_seed(seed) improvement = optimiser.optimise_partition_multiplex(partitions + [partition_interslice], n_iterations=n_iterations) # Transform results back into original form. membership = {(v[slice_attr], v[vertex_id_attr]): m for v, m in zip(G.vs, partitions[0].membership)} membership_time_slices = [] for slice_idx, H in enumerate(graphs): membership_slice = [membership[(slice_idx, v[vertex_id_attr])] for v in H.vs] membership_time_slices.append(list(membership_slice)) return membership_time_slices, improvement #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # These are helper functions to create a proper # disjoint union in python. The igraph implementation # currently does not keep the attributes when creating # a disjoint_union. def get_attrs_or_nones(seq, attr_name): try: return seq[attr_name] except KeyError: return [None] * len(seq) def disjoint_union_attrs(graphs): G = _ig.Graph.disjoint_union(graphs[0], graphs[1:]) vertex_attributes = set(sum([H.vertex_attributes() for H in graphs], [])) edge_attributes = set(sum([H.edge_attributes() for H in graphs], [])) for attr in vertex_attributes: attr_value = sum([get_attrs_or_nones(H.vs, attr) for H in graphs], []) G.vs[attr] = attr_value for attr in edge_attributes: attr_value = sum([get_attrs_or_nones(H.es, attr) for H in graphs], []) G.es[attr] = attr_value return G #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # Conversion to layer graphs def time_slices_to_layers(graphs, interslice_weight=1, slice_attr='slice', vertex_id_attr='id', edge_type_attr='type', weight_attr='weight'): """ Convert time slices to layer graphs. Each graph is considered to represent a time slice. This function simply connects all the consecutive slices (i.e. the slice graph) with an ``interslice_weight``. The further conversion is then delegated to :func:`slices_to_layers`, which also provides further details. See Also -------- :func:`find_partition_temporal` :func:`slices_to_layers` """ G_slices = _ig.Graph.Tree(len(graphs), 1, mode=_ig.TREE_UNDIRECTED) G_slices.es[weight_attr] = interslice_weight G_slices.vs[slice_attr] = graphs return slices_to_layers(G_slices, slice_attr, vertex_id_attr, edge_type_attr, weight_attr) def slices_to_layers(G_coupling, slice_attr='slice', vertex_id_attr='id', edge_type_attr='type', weight_attr='weight'): """ Convert a coupling graph of slices to layers of graphs. This function converts a graph of slices to layers so that they can be used with this package. This function assumes that the slices are represented by nodes in ``G_coupling``, and stored in the attribute ``slice_attr``. In other words, ``G_coupling.vs[slice_attr]`` should contain :class:`ig.Graph` s . The slices will be converted to layers, and nodes in different slices will be coupled if the two slices are connected in ``G_coupling``. Nodes in two connected slices are identified on the basis of the ``vertex_id_attr``, i.e. if two nodes in two connected slices have an identical value of the ``vertex_id_attr`` they will be coupled. The ``vertex_id_attr`` should hence be unique in each slice. Each node in the resulting layer graphs will contain two vertex attributes with the name of ``slice_attr`` and ``vertex_id_attr`` that refer respectively to the slice and id of the node. The weight of the coupling is determined by the weight of this link in ``G_coupling``, as determined by the ``weight_attr``. Parameters ---------- G_coupling : :class:`ig.Graph` The graph connecting the different slices. slice_attr : string The vertex attribute which contains the slices. vertex_id_attr : string The vertex attribute which is used to identify whether two nodes in two slices represent the same node, and hence, should be coupled. edge_type_attr : string The edge attribute to use for indicating the type of link (``interslice`` or ``intraslice``). weight_attr : string The edge attribute used to indicate the (coupling) weight. Returns ------- G_layers : list of :class:`ig.Graph` A list of slices converted to layers. G_interslice : :class:`ig.Graph` The interslice coupling layer. G : :class:`ig.Graph` The complete graph containing all layers and interslice couplings. Notes ----- The distinction between slices and layers is not easy to grasp. Slices in this context refer to graphs that somehow represents different aspects of a network. The simplest example is probably slices that represents time: there are different snapshots network across time, and each snapshot is considered a slice. Some nodes may drop out of the network over time, while others enter the network. Edges may change over time, or the weight of the links may change over time. This is just the simplest example of a slice, and there may be different, more complex possibilities. Below an example with three time slices: .. image:: figures/slices.png Now in order to optimise partitions across these different slices, we represent them slightly differently, namely as layers. The idea of layers is that all graphs always are defined on the same set of nodes, and that only the links differ for different layers. We thus create new nodes as combinations of original nodes and slices. For example, if node 1 existed in both slice 1 and in slice 2, we will thus create two nodes to build the layers: a node 1-1 and a node 1-2. Additionally, if the slices are connected in the slice graph, the two nodes would also be connected, so there would be a linke between node 1-1 and 1-2. Different slices will then correspond to different layers: each layer only contains the link for that particular slice. In addition, for methods such as :class:`CPMVertexPartition`, so-called ``node_sizes`` are required, and for them to properly function, they should be set to 1 only for nodes of a layer that represent nodes of the corresponding slice and 0 for the other nodes (which is handled appropriately in this function, and stored in the vertex attribute ``node_size``). Additionally, ``node_sizes`` should be set to 0 for the interslice coupling layer. We thus obtain equally many layers as we have slices, and we need one more layer for representing the interslice couplings. For the example provided above, we thus obtain the following: .. image:: figures/layers_separate.png The idea of doing community detection with slices is further detailed in [1]. References ---------- .. [1] Mucha, P. J., Richardson, T., Macon, K., Porter, M. A., & Onnela, J.-P. (2010). Community structure in time-dependent, multiscale, and multiplex networks. Science, 328(5980), 876-8. `10.1126/science.1184819 `_ See Also -------- :func:`find_partition_temporal` :func:`time_slices_to_layers` """ if not slice_attr in G_coupling.vertex_attributes(): raise ValueError("Could not find the vertex attribute {0} in the coupling graph.".format(slice_attr)) if not weight_attr in G_coupling.edge_attributes(): raise ValueError("Could not find the edge attribute {0} in the coupling graph.".format(weight_attr)) # Create disjoint union of the time graphs for v_slice in G_coupling.vs: H = v_slice[slice_attr] H.vs[slice_attr] = v_slice.index if not vertex_id_attr in H.vertex_attributes(): raise ValueError("Could not find the vertex attribute {0} to identify nodes in different slices.".format(vertex_id_attr )) if not weight_attr in H.edge_attributes(): H.es[weight_attr] = 1 G = disjoint_union_attrs(G_coupling.vs[slice_attr]) G.es[edge_type_attr] = 'intraslice' for v_slice in G_coupling.vs: for u_slice in v_slice.neighbors(mode=_ig.OUT): if v_slice.index < u_slice.index or G_coupling.is_directed(): nodes_v = G.vs.select(lambda v: v[slice_attr]==v_slice.index)[vertex_id_attr] if len(set(nodes_v)) != len(nodes_v): err = '\n'.join( ['\t{0} {1} times'.format(item, count) for item, count in Counter(nodes_v).items() if count > 1] ) raise ValueError('No unique IDs for slice {0}, require unique IDs:\n{1}'.format(v_slice.index, err)) nodes_u = G.vs.select(lambda v: v[slice_attr]==u_slice.index)[vertex_id_attr] if len(set(nodes_u)) != len(nodes_u): err = '\n'.join( ['\t{0} {1} times'.format(item, count) for item, count in Counter(nodes_u).items() if count > 1] ) raise ValueError('No unique IDs for slice {0}, require unique IDs:\n{1}'.format(u_slice.index, err)) common_nodes = set(nodes_v).intersection(set(nodes_u)) nodes_v = sorted([v for v in G.vs if v[slice_attr] == v_slice.index and v[vertex_id_attr] in common_nodes], key=lambda v: v[vertex_id_attr]) nodes_u = sorted([v for v in G.vs if v[slice_attr] == u_slice.index and v[vertex_id_attr] in common_nodes], key=lambda v: v[vertex_id_attr]) edges = zip(nodes_v, nodes_u) e_start = G.ecount() G.add_edges(edges) e_end = G.ecount() e_idx = range(e_start, e_end) interslice_weight = G_coupling.es[G_coupling.get_eid(v_slice, u_slice)][weight_attr] if not interslice_weight is None: G.es[e_idx][weight_attr] = interslice_weight G.es[e_idx][edge_type_attr] = 'interslice' # Convert aggregate graph to individual layers for each time slice. G_layers = [None]*G_coupling.vcount() for v_slice in G_coupling.vs: H = G.subgraph_edges(G.es.select(_within=[v.index for v in G.vs if v[slice_attr] == v_slice.index]), delete_vertices=False) H.vs['node_size'] = [1 if v[slice_attr] == v_slice.index else 0 for v in H.vs] G_layers[v_slice.index] = H # Create one graph for the interslice links. G_interslice = G.subgraph_edges(G.es.select(type_eq='interslice'), delete_vertices=False) G_interslice.vs['node_size'] = 0 return G_layers, G_interslice, G leidenalg-0.8.9/src/leidenalg/pynterface.cpp000066400000000000000000000000301420514302700210220ustar00rootroot00000000000000#include "pynterface.h" leidenalg-0.8.9/src/leidenalg/python_optimiser_interface.cpp000066400000000000000000000706221420514302700243340ustar00rootroot00000000000000#include "python_optimiser_interface.h" PyObject* capsule_Optimiser(Optimiser* optimiser) { PyObject* py_optimiser = PyCapsule_New(optimiser, "leidenalg.Optimiser", del_Optimiser); return py_optimiser; } Optimiser* decapsule_Optimiser(PyObject* py_optimiser) { Optimiser* optimiser = (Optimiser*) PyCapsule_GetPointer(py_optimiser, "leidenalg.Optimiser"); return optimiser; } void del_Optimiser(PyObject* py_optimiser) { Optimiser* optimiser = decapsule_Optimiser(py_optimiser); delete optimiser; } #ifdef __cplusplus extern "C" { #endif PyObject* _new_Optimiser(PyObject *self, PyObject *args) { if (args != NULL) { PyErr_BadArgument(); return NULL; } Optimiser* optimiser = new Optimiser(); PyObject* py_optimiser = capsule_Optimiser(optimiser); return py_optimiser; } PyObject* _Optimiser_optimise_partition(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_optimiser = NULL; PyObject* py_partition = NULL; PyObject* py_is_membership_fixed = NULL; static const char* kwlist[] = {"optimiser", "partition", "is_membership_fixed", NULL}; #ifdef DEBUG cerr << "Parsing arguments..." << endl; #endif if (!PyArg_ParseTupleAndKeywords(args, keywds, "OO|O", (char**) kwlist, &py_optimiser, &py_partition, &py_is_membership_fixed)) return NULL; #ifdef DEBUG cerr << "optimise_partition(" << py_partition << ", is_membership_fixed=" << py_is_membership_fixed << ");" << endl; #endif #ifdef DEBUG cerr << "Capsule optimiser at address " << py_optimiser << endl; #endif Optimiser* optimiser = decapsule_Optimiser(py_optimiser); #ifdef DEBUG cerr << "Using optimiser at address " << optimiser << endl; #endif #ifdef DEBUG cerr << "Capsule partition at address " << py_partition << endl; #endif MutableVertexPartition* partition = decapsule_MutableVertexPartition(py_partition); #ifdef DEBUG cerr << "Using partition at address " << partition << endl; #endif size_t n = partition->get_graph()->vcount(); vector is_membership_fixed(n, false); if (py_is_membership_fixed != NULL && py_is_membership_fixed != Py_None) { #ifdef DEBUG cerr << "Reading is_membership_fixed." << endl; #endif size_t nb_is_membership_fixed = PyList_Size(py_is_membership_fixed); if (nb_is_membership_fixed != n) { PyErr_SetString(PyExc_ValueError, "Node size vector not the same size as the number of nodes."); return NULL; } for (size_t v = 0; v < n; v++) { PyObject* py_item = PyList_GetItem(py_is_membership_fixed, v); is_membership_fixed[v] = PyObject_IsTrue(py_item); } } double q = 0.0; try { q = optimiser->optimise_partition(partition, is_membership_fixed); } catch (std::exception& e) { PyErr_SetString(PyExc_ValueError, e.what()); return NULL; } return PyFloat_FromDouble(q); } PyObject* _Optimiser_optimise_partition_multiplex(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_optimiser = NULL; PyObject* py_partitions = NULL; PyObject* py_layer_weights = NULL; PyObject* py_is_membership_fixed = NULL; static const char* kwlist[] = {"optimiser", "partitions", "layer_weights", "is_membership_fixed", NULL}; #ifdef DEBUG cerr << "Parsing arguments..." << endl; #endif if (!PyArg_ParseTupleAndKeywords(args, keywds, "OOO|O", (char**) kwlist, &py_optimiser, &py_partitions, &py_layer_weights, &py_is_membership_fixed)) return NULL; size_t nb_partitions = (size_t)PyList_Size(py_partitions); if (nb_partitions != (size_t)PyList_Size(py_layer_weights)) { PyErr_SetString(PyExc_ValueError, "Number of layer weights does not equal the number of partitions"); return NULL; } #ifdef DEBUG cerr << "Parsing " << nb_partitions << " partitions." << endl; #endif // This is all done per layer. vector partitions(nb_partitions); vector layer_weights(nb_partitions, 1.0); for (size_t layer = 0; layer < nb_partitions; layer++) { PyObject* py_partition = PyList_GetItem(py_partitions, layer); #ifdef DEBUG cerr << "Capsule partition at address " << py_partition << endl; #endif MutableVertexPartition* partition = decapsule_MutableVertexPartition(py_partition); #ifdef DEBUG cerr << "Using partition at address " << partition << endl; #endif PyObject* layer_weight = PyList_GetItem(py_layer_weights, layer); partitions[layer] = partition; if (PyNumber_Check(layer_weight)) { layer_weights[layer] = PyFloat_AsDouble(layer_weight); } else { PyErr_SetString(PyExc_TypeError, "Expected floating value for layer weight."); return NULL; } if (isnan(layer_weights[layer])) { PyErr_SetString(PyExc_TypeError, "Cannot accept NaN weights."); return NULL; } } if (nb_partitions == 0) return NULL; size_t n = partitions[0]->get_graph()->vcount(); vector is_membership_fixed(n, false); if (py_is_membership_fixed != NULL && py_is_membership_fixed != Py_None) { #ifdef DEBUG cerr << "Reading is_membership_fixed." << endl; #endif size_t nb_is_membership_fixed = PyList_Size(py_is_membership_fixed); if (nb_is_membership_fixed != n) { PyErr_SetString(PyExc_TypeError, "Node size vector not the same size as the number of nodes."); return NULL; } for (size_t v = 0; v < n; v++) { PyObject* py_item = PyList_GetItem(py_is_membership_fixed, v); is_membership_fixed[v] = PyObject_IsTrue(py_item); } } #ifdef DEBUG cerr << "Capsule optimiser at address " << py_optimiser << endl; #endif Optimiser* optimiser = decapsule_Optimiser(py_optimiser); #ifdef DEBUG cerr << "Using optimiser at address " << optimiser << endl; #endif double q = 0.0; try { q = optimiser->optimise_partition(partitions, layer_weights, is_membership_fixed); } catch (std::exception& e) { PyErr_SetString(PyExc_ValueError, e.what()); return NULL; } return PyFloat_FromDouble(q); } PyObject* _Optimiser_move_nodes(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_optimiser = NULL; PyObject* py_partition = NULL; PyObject* py_is_membership_fixed = NULL; int consider_comms = -1; static const char* kwlist[] = {"optimiser", "partition", "is_membership_fixed", "consider_comms", NULL}; #ifdef DEBUG cerr << "Parsing arguments..." << endl; #endif if (!PyArg_ParseTupleAndKeywords(args, keywds, "OO|Oi", (char**) kwlist, &py_optimiser, &py_partition, &py_is_membership_fixed, &consider_comms)) return NULL; #ifdef DEBUG cerr << "optimise_partition(" << py_partition << ");" << endl; #endif #ifdef DEBUG cerr << "Capsule optimiser at address " << py_optimiser << endl; #endif Optimiser* optimiser = decapsule_Optimiser(py_optimiser); #ifdef DEBUG cerr << "Using optimiser at address " << optimiser << endl; #endif #ifdef DEBUG cerr << "Capsule partition at address " << py_partition << endl; #endif MutableVertexPartition* partition = decapsule_MutableVertexPartition(py_partition); #ifdef DEBUG cerr << "Using partition at address " << partition << endl; #endif size_t n = partition->get_graph()->vcount(); vector is_membership_fixed(n, false); if (py_is_membership_fixed != NULL && py_is_membership_fixed != Py_None) { #ifdef DEBUG cerr << "Reading is_membership_fixed." << endl; #endif size_t nb_is_membership_fixed = PyList_Size(py_is_membership_fixed); if (nb_is_membership_fixed != n) { PyErr_SetString(PyExc_TypeError, "Node size vector not the same size as the number of nodes."); return NULL; } for (size_t v = 0; v < n; v++) { PyObject* py_item = PyList_GetItem(py_is_membership_fixed, v); is_membership_fixed[v] = PyObject_IsTrue(py_item); } } if (consider_comms < 0) consider_comms = optimiser->consider_comms; double q = 0.0; try { q = optimiser->move_nodes(partition, is_membership_fixed, consider_comms, true); } catch (std::exception& e) { PyErr_SetString(PyExc_ValueError, e.what()); return NULL; } return PyFloat_FromDouble(q); } PyObject* _Optimiser_merge_nodes(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_optimiser = NULL; PyObject* py_partition = NULL; PyObject* py_is_membership_fixed = NULL; int consider_comms = -1; static const char* kwlist[] = {"optimiser", "partition", "is_membership_fixed", "consider_comms", NULL}; #ifdef DEBUG cerr << "Parsing arguments..." << endl; #endif if (!PyArg_ParseTupleAndKeywords(args, keywds, "OO|Oi", (char**) kwlist, &py_optimiser, &py_partition, &py_is_membership_fixed, &consider_comms)) return NULL; #ifdef DEBUG cerr << "optimise_partition(" << py_partition << ");" << endl; #endif #ifdef DEBUG cerr << "Capsule optimiser at address " << py_optimiser << endl; #endif Optimiser* optimiser = decapsule_Optimiser(py_optimiser); #ifdef DEBUG cerr << "Using optimiser at address " << optimiser << endl; #endif #ifdef DEBUG cerr << "Capsule partition at address " << py_partition << endl; #endif MutableVertexPartition* partition = decapsule_MutableVertexPartition(py_partition); #ifdef DEBUG cerr << "Using partition at address " << partition << endl; #endif size_t n = partition->get_graph()->vcount(); vector is_membership_fixed(n, false); if (py_is_membership_fixed != NULL && py_is_membership_fixed != Py_None) { #ifdef DEBUG cerr << "Reading is_membership_fixed." << endl; #endif size_t nb_is_membership_fixed = PyList_Size(py_is_membership_fixed); if (nb_is_membership_fixed != n) { PyErr_SetString(PyExc_TypeError, "Node size vector not the same size as the number of nodes."); return NULL; } for (size_t v = 0; v < n; v++) { PyObject* py_item = PyList_GetItem(py_is_membership_fixed, v); is_membership_fixed[v] = PyObject_IsTrue(py_item); } } if (consider_comms < 0) consider_comms = optimiser->consider_comms; double q = 0.0; try { q = optimiser->merge_nodes(partition, is_membership_fixed, consider_comms, true); } catch (std::exception& e) { PyErr_SetString(PyExc_ValueError, e.what()); return NULL; } return PyFloat_FromDouble(q); } PyObject* _Optimiser_move_nodes_constrained(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_optimiser = NULL; PyObject* py_partition = NULL; PyObject* py_constrained_partition = NULL; int consider_comms = -1; static const char* kwlist[] = {"optimiser", "partition", "constrained_partition", "consider_comms", NULL}; #ifdef DEBUG cerr << "Parsing arguments..." << endl; #endif if (!PyArg_ParseTupleAndKeywords(args, keywds, "OOO|i", (char**) kwlist, &py_optimiser, &py_partition, &py_constrained_partition, &consider_comms)) return NULL; #ifdef DEBUG cerr << "optimise_partition(" << py_partition << ");" << endl; #endif #ifdef DEBUG cerr << "Capsule optimiser at address " << py_optimiser << endl; #endif Optimiser* optimiser = decapsule_Optimiser(py_optimiser); #ifdef DEBUG cerr << "Using optimiser at address " << optimiser << endl; #endif #ifdef DEBUG cerr << "Capsule partition at address " << py_partition << endl; #endif MutableVertexPartition* partition = decapsule_MutableVertexPartition(py_partition); #ifdef DEBUG cerr << "Using partition at address " << partition << endl; #endif #ifdef DEBUG cerr << "Capsule constrained partition at address " << py_constrained_partition << endl; #endif MutableVertexPartition* constrained_partition = decapsule_MutableVertexPartition(py_constrained_partition); #ifdef DEBUG cerr << "Using constrained partition at address " << constrained_partition << endl; #endif if (consider_comms < 0) consider_comms = optimiser->refine_consider_comms; double q = 0.0; try { q = optimiser->move_nodes_constrained(partition, consider_comms, constrained_partition); } catch (std::exception& e) { PyErr_SetString(PyExc_ValueError, e.what()); return NULL; } return PyFloat_FromDouble(q); } PyObject* _Optimiser_merge_nodes_constrained(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_optimiser = NULL; PyObject* py_partition = NULL; PyObject* py_constrained_partition = NULL; int consider_comms = -1; static const char* kwlist[] = {"optimiser", "partition", "constrained_partition", "consider_comms", NULL}; #ifdef DEBUG cerr << "Parsing arguments..." << endl; #endif if (!PyArg_ParseTupleAndKeywords(args, keywds, "OOO|i", (char**) kwlist, &py_optimiser, &py_partition, &py_constrained_partition, &consider_comms)) return NULL; #ifdef DEBUG cerr << "optimise_partition(" << py_partition << ");" << endl; #endif #ifdef DEBUG cerr << "Capsule optimiser at address " << py_optimiser << endl; #endif Optimiser* optimiser = decapsule_Optimiser(py_optimiser); #ifdef DEBUG cerr << "Using optimiser at address " << optimiser << endl; #endif #ifdef DEBUG cerr << "Capsule partition at address " << py_partition << endl; #endif MutableVertexPartition* partition = decapsule_MutableVertexPartition(py_partition); #ifdef DEBUG cerr << "Using partition at address " << partition << endl; #endif #ifdef DEBUG cerr << "Capsule constrained partition at address " << py_partition << endl; #endif MutableVertexPartition* constrained_partition = decapsule_MutableVertexPartition(py_constrained_partition); #ifdef DEBUG cerr << "Using constrained partition at address " << partition << endl; #endif if (consider_comms < 0) consider_comms = optimiser->refine_consider_comms; double q = 0.0; try { q = optimiser->merge_nodes_constrained(partition, consider_comms, constrained_partition); } catch (std::exception& e) { PyErr_SetString(PyExc_ValueError, e.what()); return NULL; } return PyFloat_FromDouble(q); } PyObject* _Optimiser_set_consider_comms(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_optimiser = NULL; int consider_comms = Optimiser::ALL_NEIGH_COMMS; static const char* kwlist[] = {"optimiser", "consider_comms", NULL}; #ifdef DEBUG cerr << "Parsing arguments..." << endl; #endif if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oi", (char**) kwlist, &py_optimiser, &consider_comms)) return NULL; #ifdef DEBUG cerr << "set_consider_comms(" << consider_comms << ");" << endl; #endif #ifdef DEBUG cerr << "Capsule optimiser at address " << py_optimiser << endl; #endif Optimiser* optimiser = decapsule_Optimiser(py_optimiser); #ifdef DEBUG cerr << "Using optimiser at address " << optimiser << endl; #endif optimiser->consider_comms = consider_comms; Py_INCREF(Py_None); return Py_None; } PyObject* _Optimiser_get_consider_comms(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_optimiser = NULL; static const char* kwlist[] = {"optimiser", NULL}; #ifdef DEBUG cerr << "Parsing arguments..." << endl; #endif if (!PyArg_ParseTupleAndKeywords(args, keywds, "O", (char**) kwlist, &py_optimiser)) return NULL; #ifdef DEBUG cerr << "get_consider_comms();" << endl; #endif #ifdef DEBUG cerr << "Capsule optimiser at address " << py_optimiser << endl; #endif Optimiser* optimiser = decapsule_Optimiser(py_optimiser); #ifdef DEBUG cerr << "Using optimiser at address " << optimiser << endl; #endif return PyLong_FromLong(optimiser->consider_comms); } PyObject* _Optimiser_set_refine_consider_comms(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_optimiser = NULL; int refine_consider_comms = Optimiser::ALL_NEIGH_COMMS; static const char* kwlist[] = {"optimiser", "refine_consider_comms", NULL}; #ifdef DEBUG cerr << "Parsing arguments..." << endl; #endif if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oi", (char**) kwlist, &py_optimiser, &refine_consider_comms)) return NULL; #ifdef DEBUG cerr << "set_refine_consider_comms(" << refine_consider_comms << ");" << endl; #endif #ifdef DEBUG cerr << "Capsule optimiser at address " << py_optimiser << endl; #endif Optimiser* optimiser = decapsule_Optimiser(py_optimiser); #ifdef DEBUG cerr << "Using optimiser at address " << optimiser << endl; #endif optimiser->refine_consider_comms = refine_consider_comms; Py_INCREF(Py_None); return Py_None; } PyObject* _Optimiser_get_refine_consider_comms(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_optimiser = NULL; static const char* kwlist[] = {"optimiser", NULL}; #ifdef DEBUG cerr << "Parsing arguments..." << endl; #endif if (!PyArg_ParseTupleAndKeywords(args, keywds, "O", (char**) kwlist, &py_optimiser)) return NULL; #ifdef DEBUG cerr << "get_refine_consider_comms();" << endl; #endif #ifdef DEBUG cerr << "Capsule optimiser at address " << py_optimiser << endl; #endif Optimiser* optimiser = decapsule_Optimiser(py_optimiser); #ifdef DEBUG cerr << "Using optimiser at address " << optimiser << endl; #endif return PyLong_FromLong(optimiser->refine_consider_comms); } PyObject* _Optimiser_set_optimise_routine(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_optimiser = NULL; int optimise_routine = Optimiser::ALL_NEIGH_COMMS; static const char* kwlist[] = {"optimiser", "optimise_routine", NULL}; #ifdef DEBUG cerr << "Parsing arguments..." << endl; #endif if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oi", (char**) kwlist, &py_optimiser, &optimise_routine)) return NULL; #ifdef DEBUG cerr << "set_optimise_routine(" << optimise_routine << ");" << endl; #endif #ifdef DEBUG cerr << "Capsule optimiser at address " << py_optimiser << endl; #endif Optimiser* optimiser = decapsule_Optimiser(py_optimiser); #ifdef DEBUG cerr << "Using optimiser at address " << optimiser << endl; #endif optimiser->optimise_routine = optimise_routine; Py_INCREF(Py_None); return Py_None; } PyObject* _Optimiser_get_optimise_routine(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_optimiser = NULL; static const char* kwlist[] = {"optimiser", NULL}; #ifdef DEBUG cerr << "Parsing arguments..." << endl; #endif if (!PyArg_ParseTupleAndKeywords(args, keywds, "O", (char**) kwlist, &py_optimiser)) return NULL; #ifdef DEBUG cerr << "get_optimise_routine();" << endl; #endif #ifdef DEBUG cerr << "Capsule optimiser at address " << py_optimiser << endl; #endif Optimiser* optimiser = decapsule_Optimiser(py_optimiser); #ifdef DEBUG cerr << "Using optimiser at address " << optimiser << endl; #endif return PyLong_FromLong(optimiser->optimise_routine); } PyObject* _Optimiser_set_refine_routine(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_optimiser = NULL; int refine_routine = Optimiser::ALL_NEIGH_COMMS; static const char* kwlist[] = {"optimiser", "refine_routine", NULL}; #ifdef DEBUG cerr << "Parsing arguments..." << endl; #endif if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oi", (char**) kwlist, &py_optimiser, &refine_routine)) return NULL; #ifdef DEBUG cerr << "set_refine_routine(" << refine_routine << ");" << endl; #endif #ifdef DEBUG cerr << "Capsule optimiser at address " << py_optimiser << endl; #endif Optimiser* optimiser = decapsule_Optimiser(py_optimiser); #ifdef DEBUG cerr << "Using optimiser at address " << optimiser << endl; #endif optimiser->refine_routine = refine_routine; Py_INCREF(Py_None); return Py_None; } PyObject* _Optimiser_get_refine_routine(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_optimiser = NULL; static const char* kwlist[] = {"optimiser", NULL}; #ifdef DEBUG cerr << "Parsing arguments..." << endl; #endif if (!PyArg_ParseTupleAndKeywords(args, keywds, "O", (char**) kwlist, &py_optimiser)) return NULL; #ifdef DEBUG cerr << "get_refine_routine();" << endl; #endif #ifdef DEBUG cerr << "Capsule optimiser at address " << py_optimiser << endl; #endif Optimiser* optimiser = decapsule_Optimiser(py_optimiser); #ifdef DEBUG cerr << "Using optimiser at address " << optimiser << endl; #endif return PyLong_FromLong(optimiser->refine_routine); } PyObject* _Optimiser_set_consider_empty_community(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_optimiser = NULL; int consider_empty_community = true; static const char* kwlist[] = {"optimiser", "consider_empty_community", NULL}; #ifdef DEBUG cerr << "Parsing arguments..." << endl; #endif if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oi", (char**) kwlist, &py_optimiser, &consider_empty_community)) return NULL; #ifdef DEBUG cerr << "set_consider_empty_community(" << consider_empty_community << ");" << endl; #endif #ifdef DEBUG cerr << "Capsule optimiser at address " << py_optimiser << endl; #endif Optimiser* optimiser = decapsule_Optimiser(py_optimiser); #ifdef DEBUG cerr << "Using optimiser at address " << optimiser << endl; #endif #ifdef DEBUG cerr << "Setting consider_empty_community to " << consider_empty_community << endl; #endif optimiser->consider_empty_community = consider_empty_community; #ifdef DEBUG cerr << "Set consider_empty_community to " << optimiser->consider_empty_community << endl; #endif Py_INCREF(Py_None); return Py_None; } PyObject* _Optimiser_get_consider_empty_community(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_optimiser = NULL; static const char* kwlist[] = {"optimiser", NULL}; #ifdef DEBUG cerr << "Parsing arguments..." << endl; #endif if (!PyArg_ParseTupleAndKeywords(args, keywds, "O", (char**) kwlist, &py_optimiser)) return NULL; #ifdef DEBUG cerr << "get_consider_empty_community();" << endl; #endif #ifdef DEBUG cerr << "Capsule optimiser at address " << py_optimiser << endl; #endif Optimiser* optimiser = decapsule_Optimiser(py_optimiser); #ifdef DEBUG cerr << "Using optimiser at address " << optimiser << endl; cerr << "Returning " << optimiser->consider_empty_community << endl; #endif return PyBool_FromLong(optimiser->consider_empty_community); } PyObject* _Optimiser_set_refine_partition(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_optimiser = NULL; int refine_partition = false; static const char* kwlist[] = {"optimiser", "refine_partition", NULL}; #ifdef DEBUG cerr << "Parsing arguments..." << endl; #endif if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oi", (char**) kwlist, &py_optimiser, &refine_partition)) return NULL; #ifdef DEBUG cerr << "set_refine_partition(" << refine_partition << ");" << endl; #endif #ifdef DEBUG cerr << "Capsule optimiser at address " << py_optimiser << endl; #endif Optimiser* optimiser = decapsule_Optimiser(py_optimiser); #ifdef DEBUG cerr << "Using optimiser at address " << optimiser << endl; #endif optimiser->refine_partition = refine_partition; Py_INCREF(Py_None); return Py_None; } PyObject* _Optimiser_get_refine_partition(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_optimiser = NULL; static const char* kwlist[] = {"optimiser", NULL}; #ifdef DEBUG cerr << "Parsing arguments..." << endl; #endif if (!PyArg_ParseTupleAndKeywords(args, keywds, "O", (char**) kwlist, &py_optimiser)) return NULL; #ifdef DEBUG cerr << "get_refine_partition();" << endl; #endif #ifdef DEBUG cerr << "Capsule optimiser at address " << py_optimiser << endl; #endif Optimiser* optimiser = decapsule_Optimiser(py_optimiser); #ifdef DEBUG cerr << "Using optimiser at address " << optimiser << endl; #endif return PyBool_FromLong(optimiser->refine_partition); } PyObject* _Optimiser_set_max_comm_size(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_optimiser = NULL; size_t max_comm_size = 0; static const char* kwlist[] = {"optimiser", "max_comm_size", NULL}; #ifdef DEBUG cerr << "Parsing arguments..." << endl; #endif if (!PyArg_ParseTupleAndKeywords(args, keywds, "On", (char**) kwlist, &py_optimiser, &max_comm_size)) return NULL; #ifdef DEBUG cerr << "set_max_comm_size(" << max_comm_size << ");" << endl; #endif #ifdef DEBUG cerr << "Capsule optimiser at address " << py_optimiser << endl; #endif Optimiser* optimiser = decapsule_Optimiser(py_optimiser); #ifdef DEBUG cerr << "Using optimiser at address " << optimiser << endl; #endif optimiser->max_comm_size = max_comm_size; Py_INCREF(Py_None); return Py_None; } PyObject* _Optimiser_get_max_comm_size(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_optimiser = NULL; static const char* kwlist[] = {"optimiser", NULL}; #ifdef DEBUG cerr << "Parsing arguments..." << endl; #endif if (!PyArg_ParseTupleAndKeywords(args, keywds, "O", (char**) kwlist, &py_optimiser)) return NULL; #ifdef DEBUG cerr << "get_max_comm_size();" << endl; #endif #ifdef DEBUG cerr << "Capsule optimiser at address " << py_optimiser << endl; #endif Optimiser* optimiser = decapsule_Optimiser(py_optimiser); #ifdef DEBUG cerr << "Using optimiser at address " << optimiser << endl; #endif return PyLong_FromSize_t(optimiser->max_comm_size); } PyObject* _Optimiser_set_rng_seed(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_optimiser = NULL; int seed = 0; static const char* kwlist[] = {"optimiser", "seed", NULL}; #ifdef DEBUG cerr << "Parsing arguments..." << endl; #endif if (!PyArg_ParseTupleAndKeywords(args, keywds, "Oi", (char**) kwlist, &py_optimiser, &seed)) return NULL; #ifdef DEBUG cerr << "set_rng_seed(" << seed << ");" << endl; #endif #ifdef DEBUG cerr << "Capsule optimiser at address " << py_optimiser << endl; #endif Optimiser* optimiser = decapsule_Optimiser(py_optimiser); #ifdef DEBUG cerr << "Using optimiser at address " << optimiser << endl; #endif #ifdef DEBUG cerr << "Setting seed to " << seed << endl; #endif optimiser->set_rng_seed(seed); Py_INCREF(Py_None); return Py_None; } #ifdef __cplusplus } #endif leidenalg-0.8.9/src/leidenalg/python_partition_interface.cpp000066400000000000000000001102501420514302700243220ustar00rootroot00000000000000#include "python_partition_interface.h" Graph* create_graph_from_py(PyObject* py_obj_graph, PyObject* py_node_sizes) { return create_graph_from_py(py_obj_graph, py_node_sizes, NULL, true); } Graph* create_graph_from_py(PyObject* py_obj_graph, PyObject* py_node_sizes, PyObject* py_weights) { return create_graph_from_py(py_obj_graph, py_node_sizes, py_weights, true); } Graph* create_graph_from_py(PyObject* py_obj_graph, PyObject* py_node_sizes, PyObject* py_weights, int check_positive_weight) { #ifdef DEBUG cerr << "create_graph_from_py" << endl; #endif igraph_t* py_graph = (igraph_t*) PyCapsule_GetPointer(py_obj_graph, NULL); #ifdef DEBUG cerr << "Got igraph_t " << py_graph << endl; #endif // If necessary create a weighted graph Graph* graph = NULL; #ifdef DEBUG cerr << "Creating graph."<< endl; #endif size_t n = igraph_vcount(py_graph); size_t m = igraph_ecount(py_graph); vector node_sizes; vector weights; if (py_node_sizes != NULL && py_node_sizes != Py_None) { #ifdef DEBUG cerr << "Reading node_sizes." << endl; #endif size_t nb_node_size = PyList_Size(py_node_sizes); if (nb_node_size != n) { throw Exception("Node size vector not the same size as the number of nodes."); } node_sizes.resize(n); for (size_t v = 0; v < n; v++) { PyObject* py_item = PyList_GetItem(py_node_sizes, v); if (PyNumber_Check(py_item) && PyIndex_Check(py_item)) { size_t e = PyLong_AsSize_t(PyNumber_Long(py_item)); node_sizes[v] = e; } else { throw Exception("Expected integer value for node sizes vector."); } } } if (py_weights != NULL && py_weights != Py_None) { #ifdef DEBUG cerr << "Reading weights." << endl; #endif size_t nb_weights = PyList_Size(py_weights); if (nb_weights != m) throw Exception("Weight vector not the same size as the number of edges."); weights.resize(m); for (size_t e = 0; e < m; e++) { PyObject* py_item = PyList_GetItem(py_weights, e); #ifdef DEBUG //PyObject* py_item_repr = PyObject_Repr(py_item); //const char* s = PyUnicode_AsUTF8(py_item_repr); //cerr << "Got item " << e << ": " << s << endl; #endif if (PyNumber_Check(py_item)) { weights[e] = PyFloat_AsDouble(py_item); } else { throw Exception("Expected floating point value for weight vector."); } if (check_positive_weight) if (weights[e] < 0 ) throw Exception("Cannot accept negative weights."); if (isnan(weights[e])) throw Exception("Cannot accept NaN weights."); if (!isfinite(weights[e])) throw Exception("Cannot accept infinite weights."); } } // TODO: Pass correct_for_self_loops as parameter int correct_self_loops = false; if (node_sizes.size() == n) { if (weights.size() == m) graph = new Graph(py_graph, weights, node_sizes, correct_self_loops); else graph = new Graph(py_graph, node_sizes, correct_self_loops); } else { if (weights.size() == m) graph = new Graph(py_graph, weights, correct_self_loops); else graph = new Graph(py_graph, correct_self_loops); } #ifdef DEBUG cerr << "Created graph " << graph << endl; cerr << "Number of nodes " << graph->vcount() << endl; cerr << "Number of edges " << graph->ecount() << endl; cerr << "Total weight " << graph->total_weight() << endl; #endif return graph; } vector create_size_t_vector(PyObject* py_list) { size_t n = PyList_Size(py_list); vector result(n); for (size_t i = 0; i < n; i++) { PyObject* py_item = PyList_GetItem(py_list, i); if (PyNumber_Check(py_item) && PyIndex_Check(py_item)) { size_t e = PyLong_AsSize_t(PyNumber_Long(py_item)); if (e >= n) throw Exception("Value cannot exceed length of list."); else result[i] = e; } else throw Exception("Value cannot exceed length of list."); } return result; } PyObject* capsule_MutableVertexPartition(MutableVertexPartition* partition) { PyObject* py_partition = PyCapsule_New(partition, "leidenalg.VertexPartition.MutableVertexPartition", del_MutableVertexPartition); return py_partition; } MutableVertexPartition* decapsule_MutableVertexPartition(PyObject* py_partition) { MutableVertexPartition* partition = (MutableVertexPartition*) PyCapsule_GetPointer(py_partition, "leidenalg.VertexPartition.MutableVertexPartition"); return partition; } void del_MutableVertexPartition(PyObject* py_partition) { MutableVertexPartition* partition = decapsule_MutableVertexPartition(py_partition); delete partition; } #ifdef __cplusplus extern "C" { #endif PyObject* _new_ModularityVertexPartition(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_obj_graph = NULL; PyObject* py_initial_membership = NULL; PyObject* py_weights = NULL; static const char* kwlist[] = {"graph", "initial_membership", "weights", NULL}; if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|OO", (char**) kwlist, &py_obj_graph, &py_initial_membership, &py_weights)) return NULL; try { Graph* graph = create_graph_from_py(py_obj_graph, NULL, py_weights); ModularityVertexPartition* partition = NULL; // If necessary create an initial partition if (py_initial_membership != NULL && py_initial_membership != Py_None) { vector initial_membership = create_size_t_vector(py_initial_membership); partition = new ModularityVertexPartition(graph, initial_membership); } else partition = new ModularityVertexPartition(graph); // Do *NOT* forget to remove the graph upon deletion partition->destructor_delete_graph = true; PyObject* py_partition = capsule_MutableVertexPartition(partition); #ifdef DEBUG cerr << "Created capsule partition at address " << py_partition << endl; #endif return py_partition; } catch (std::exception& e ) { string s = "Could not construct partition: " + string(e.what()); PyErr_SetString(PyExc_BaseException, s.c_str()); return NULL; } } PyObject* _new_SignificanceVertexPartition(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_obj_graph = NULL; PyObject* py_initial_membership = NULL; PyObject* py_node_sizes = NULL; static const char* kwlist[] = {"graph", "initial_membership", "node_sizes", NULL}; if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|OO", (char**) kwlist, &py_obj_graph, &py_initial_membership, &py_node_sizes)) return NULL; try { Graph* graph = create_graph_from_py(py_obj_graph, py_node_sizes); SignificanceVertexPartition* partition = NULL; // If necessary create an initial partition if (py_initial_membership != NULL && py_initial_membership != Py_None) { vector initial_membership = create_size_t_vector(py_initial_membership); partition = new SignificanceVertexPartition(graph, initial_membership); } else partition = new SignificanceVertexPartition(graph); // Do *NOT* forget to remove the graph upon deletion partition->destructor_delete_graph = true; PyObject* py_partition = capsule_MutableVertexPartition(partition); #ifdef DEBUG cerr << "Created capsule partition at address " << py_partition << endl; #endif return py_partition; } catch (std::exception const & e ) { string s = "Could not construct partition: " + string(e.what()); PyErr_SetString(PyExc_BaseException, s.c_str()); return NULL; } } PyObject* _new_SurpriseVertexPartition(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_obj_graph = NULL; PyObject* py_initial_membership = NULL; PyObject* py_weights = NULL; PyObject* py_node_sizes = NULL; static const char* kwlist[] = {"graph", "initial_membership", "weights", "node_sizes", NULL}; if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|OOO", (char**) kwlist, &py_obj_graph, &py_initial_membership, &py_weights, &py_node_sizes)) return NULL; try { Graph* graph = create_graph_from_py(py_obj_graph, py_node_sizes, py_weights); SurpriseVertexPartition* partition = NULL; // If necessary create an initial partition if (py_initial_membership != NULL && py_initial_membership != Py_None) { vector initial_membership = create_size_t_vector(py_initial_membership); partition = new SurpriseVertexPartition(graph, initial_membership); } else partition = new SurpriseVertexPartition(graph); // Do *NOT* forget to remove the graph upon deletion partition->destructor_delete_graph = true; PyObject* py_partition = capsule_MutableVertexPartition(partition); #ifdef DEBUG cerr << "Created capsule partition at address " << py_partition << endl; #endif return py_partition; } catch (std::exception const & e ) { string s = "Could not construct partition: " + string(e.what()); PyErr_SetString(PyExc_BaseException, s.c_str()); return NULL; } } PyObject* _new_CPMVertexPartition(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_obj_graph = NULL; PyObject* py_initial_membership = NULL; PyObject* py_weights = NULL; PyObject* py_node_sizes = NULL; double resolution_parameter = 1.0; static const char* kwlist[] = {"graph", "initial_membership", "weights", "node_sizes", "resolution_parameter", NULL}; if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|OOOd", (char**) kwlist, &py_obj_graph, &py_initial_membership, &py_weights, &py_node_sizes, &resolution_parameter)) return NULL; try { Graph* graph = create_graph_from_py(py_obj_graph, py_node_sizes, py_weights, false); CPMVertexPartition* partition = NULL; // If necessary create an initial partition if (py_initial_membership != NULL && py_initial_membership != Py_None) { vector initial_membership = create_size_t_vector(py_initial_membership); partition = new CPMVertexPartition(graph, initial_membership, resolution_parameter); } else partition = new CPMVertexPartition(graph, resolution_parameter); // Do *NOT* forget to remove the graph upon deletion partition->destructor_delete_graph = true; PyObject* py_partition = capsule_MutableVertexPartition(partition); #ifdef DEBUG cerr << "Created capsule partition at address " << py_partition << endl; #endif return py_partition; } catch (std::exception const & e ) { string s = "Could not construct partition: " + string(e.what()); PyErr_SetString(PyExc_BaseException, s.c_str()); return NULL; } } PyObject* _new_RBERVertexPartition(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_obj_graph = NULL; PyObject* py_initial_membership = NULL; PyObject* py_weights = NULL; PyObject* py_node_sizes = NULL; double resolution_parameter = 1.0; static const char* kwlist[] = {"graph", "initial_membership", "weights", "node_sizes", "resolution_parameter", NULL}; if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|OOOd", (char**) kwlist, &py_obj_graph, &py_initial_membership, &py_weights, &py_node_sizes, &resolution_parameter)) return NULL; try { Graph* graph = create_graph_from_py(py_obj_graph, py_node_sizes, py_weights); RBERVertexPartition* partition = NULL; // If necessary create an initial partition if (py_initial_membership != NULL && py_initial_membership != Py_None) { vector initial_membership = create_size_t_vector(py_initial_membership); partition = new RBERVertexPartition(graph, initial_membership, resolution_parameter); } else partition = new RBERVertexPartition(graph, resolution_parameter); // Do *NOT* forget to remove the graph upon deletion partition->destructor_delete_graph = true; PyObject* py_partition = capsule_MutableVertexPartition(partition); #ifdef DEBUG cerr << "Created capsule partition at address " << py_partition << endl; #endif return py_partition; } catch (std::exception const & e ) { string s = "Could not construct partition: " + string(e.what()); PyErr_SetString(PyExc_BaseException, s.c_str()); return NULL; } } PyObject* _new_RBConfigurationVertexPartition(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_obj_graph = NULL; PyObject* py_initial_membership = NULL; PyObject* py_weights = NULL; double resolution_parameter = 1.0; static const char* kwlist[] = {"graph", "initial_membership", "weights", "resolution_parameter", NULL}; if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|OOd", (char**) kwlist, &py_obj_graph, &py_initial_membership, &py_weights, &resolution_parameter)) return NULL; try { Graph* graph = create_graph_from_py(py_obj_graph, NULL, py_weights); RBConfigurationVertexPartition* partition = NULL; // If necessary create an initial partition if (py_initial_membership != NULL && py_initial_membership != Py_None) { vector initial_membership = create_size_t_vector(py_initial_membership); partition = new RBConfigurationVertexPartition(graph, initial_membership, resolution_parameter); } else partition = new RBConfigurationVertexPartition(graph, resolution_parameter); // Do *NOT* forget to remove the graph upon deletion partition->destructor_delete_graph = true; PyObject* py_partition = capsule_MutableVertexPartition(partition); #ifdef DEBUG cerr << "Created capsule partition at address " << py_partition << endl; #endif return py_partition; } catch (std::exception const & e ) { string s = "Could not construct partition: " + string(e.what()); PyErr_SetString(PyExc_BaseException, s.c_str()); return NULL; } } PyObject* _MutableVertexPartition_get_py_igraph(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_partition = NULL; static const char* kwlist[] = {"partition", NULL}; #ifdef DEBUG cerr << "Parsing arguments..." << endl; #endif if (!PyArg_ParseTupleAndKeywords(args, keywds, "O", (char**) kwlist, &py_partition)) return NULL; #ifdef DEBUG cerr << "get_py_igraph();" << endl; #endif #ifdef DEBUG cerr << "Capsule partition at address " << py_partition << endl; #endif MutableVertexPartition* partition = decapsule_MutableVertexPartition(py_partition); #ifdef DEBUG cerr << "Using partition at address " << partition << endl; #endif Graph* graph = partition->get_graph(); size_t n = graph->vcount(); size_t m = graph->ecount(); PyObject* edges = PyList_New(m); for (size_t e = 0; e < m; e++) { vector edge = graph->edge(e); PyList_SetItem(edges, e, Py_BuildValue("(nn)", edge[0], edge[1])); } PyObject* weights = PyList_New(m); for (size_t e = 0; e < m; e++) { PyObject* item = PyFloat_FromDouble(graph->edge_weight(e)); PyList_SetItem(weights, e, item); } PyObject* node_sizes = PyList_New(n); for (size_t v = 0; v < n; v++) { PyObject* item = PyLong_FromSize_t(graph->node_size(v)); PyList_SetItem(node_sizes, v, item); } return Py_BuildValue("lOOOO", n, graph->is_directed() ? Py_True : Py_False, edges, weights, node_sizes); } PyObject* _MutableVertexPartition_from_coarse_partition(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_partition = NULL; PyObject* py_membership = NULL; PyObject* py_coarse_node = NULL; static const char* kwlist[] = {"partition", "membership", "coarse_node", NULL}; #ifdef DEBUG cerr << "Parsing arguments..." << endl; #endif // TODO : Instead of simply returning NULL, we should also set an error. if (!PyArg_ParseTupleAndKeywords(args, keywds, "OO|O", (char**) kwlist, &py_partition, &py_membership, &py_coarse_node)) return NULL; #ifdef DEBUG cerr << "from_coarse_partition();" << endl; #endif vector membership; try { membership = create_size_t_vector(py_membership); } catch (std::exception& e ) { string s = "Could not create membership vector: " + string(e.what()); PyErr_SetString(PyExc_BaseException, s.c_str()); return NULL; } #ifdef DEBUG cerr << "Capsule partition at address " << py_partition << endl; #endif MutableVertexPartition* partition = decapsule_MutableVertexPartition(py_partition); #ifdef DEBUG cerr << "Using partition at address " << partition << endl; #endif if (py_coarse_node != NULL && py_coarse_node != Py_None) { vector coarse_node; try { coarse_node = create_size_t_vector(py_coarse_node); } catch (std::exception& e ) { string s = "Could not create coarse node vector: " + string(e.what()); PyErr_SetString(PyExc_BaseException, s.c_str()); return NULL; } partition->from_coarse_partition(membership, coarse_node); } else partition->from_coarse_partition(membership); Py_INCREF(Py_None); return Py_None; } PyObject* _MutableVertexPartition_renumber_communities(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_partition = NULL; static const char* kwlist[] = {"partition", NULL}; #ifdef DEBUG cerr << "Parsing arguments..." << endl; #endif if (!PyArg_ParseTupleAndKeywords(args, keywds, "O", (char**) kwlist, &py_partition)) return NULL; #ifdef DEBUG cerr << "renumber_communities();" << endl; #endif #ifdef DEBUG cerr << "Capsule partition at address " << py_partition << endl; #endif MutableVertexPartition* partition = decapsule_MutableVertexPartition(py_partition); #ifdef DEBUG cerr << "Using partition at address " << partition << endl; #endif partition->renumber_communities(); Py_INCREF(Py_None); return Py_None; } PyObject* _MutableVertexPartition_diff_move(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_partition = NULL; size_t v; size_t new_comm; static const char* kwlist[] = {"partition", "v", "new_comm", NULL}; #ifdef DEBUG cerr << "Parsing arguments..." << endl; #endif if (!PyArg_ParseTupleAndKeywords(args, keywds, "Onn", (char**) kwlist, &py_partition, &v, &new_comm)) return NULL; #ifdef DEBUG cerr << "diff_move(" << v << ", " << new_comm << ");" << endl; #endif #ifdef DEBUG cerr << "Capsule partition at address " << py_partition << endl; #endif MutableVertexPartition* partition = decapsule_MutableVertexPartition(py_partition); #ifdef DEBUG cerr << "Using partition at address " << partition << endl; #endif double diff = partition->diff_move(v, new_comm); return PyFloat_FromDouble(diff); } PyObject* _MutableVertexPartition_move_node(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_partition = NULL; size_t v; size_t new_comm; static const char* kwlist[] = {"partition", "v", "new_comm", NULL}; #ifdef DEBUG cerr << "Parsing arguments..." << endl; #endif if (!PyArg_ParseTupleAndKeywords(args, keywds, "Onn", (char**) kwlist, &py_partition, &v, &new_comm)) return NULL; #ifdef DEBUG cerr << "move_node(" << v << ", " << new_comm << ");" << endl; #endif #ifdef DEBUG cerr << "Capsule partition at address " << py_partition << endl; #endif MutableVertexPartition* partition = decapsule_MutableVertexPartition(py_partition); #ifdef DEBUG cerr << "Using partition at address " << partition << endl; #endif if (new_comm >= partition->get_graph()->vcount()) { PyErr_SetString(PyExc_TypeError, "Community membership cannot exceed number of nodes."); return NULL; } else if (new_comm < 0) { PyErr_SetString(PyExc_TypeError, "Community membership cannot be negative"); return NULL; } partition->move_node(v, new_comm); Py_INCREF(Py_None); return Py_None; } PyObject* _MutableVertexPartition_quality(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_partition = NULL; static const char* kwlist[] = {"partition", NULL}; #ifdef DEBUG cerr << "Parsing arguments..." << endl; #endif if (!PyArg_ParseTupleAndKeywords(args, keywds, "O", (char**) kwlist, &py_partition)) return NULL; #ifdef DEBUG cerr << "quality();" << endl; #endif #ifdef DEBUG cerr << "Capsule partition at address " << py_partition << endl; #endif MutableVertexPartition* partition = decapsule_MutableVertexPartition(py_partition); #ifdef DEBUG cerr << "Using partition at address " << partition << endl; #endif double q = partition->quality(); return PyFloat_FromDouble(q); } PyObject* _MutableVertexPartition_aggregate_partition(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_partition = NULL; static const char* kwlist[] = {"partition", NULL}; #ifdef DEBUG cerr << "Parsing arguments..." << endl; #endif if (!PyArg_ParseTupleAndKeywords(args, keywds, "O", (char**) kwlist, &py_partition)) return NULL; #ifdef DEBUG cerr << "aggregate_partition();" << endl; #endif #ifdef DEBUG cerr << "Capsule partition at address " << py_partition << endl; #endif MutableVertexPartition* partition = decapsule_MutableVertexPartition(py_partition); #ifdef DEBUG cerr << "Using partition at address " << partition << endl; #endif // First collapse graph (i.e. community graph) Graph* collapsed_graph = partition->get_graph()->collapse_graph(partition); // Create collapsed partition (i.e. default partition of each node in its own community). MutableVertexPartition* collapsed_partition = partition->create(collapsed_graph); collapsed_partition->destructor_delete_graph = true; PyObject* py_collapsed_partition = capsule_MutableVertexPartition(collapsed_partition); return py_collapsed_partition; } PyObject* _MutableVertexPartition_total_weight_in_comm(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_partition = NULL; size_t comm; static const char* kwlist[] = {"partition", "comm", NULL}; #ifdef DEBUG cerr << "Parsing arguments..." << endl; #endif if (!PyArg_ParseTupleAndKeywords(args, keywds, "On", (char**) kwlist, &py_partition, &comm)) return NULL; #ifdef DEBUG cerr << "total_weight_in_comm(" << comm << ");" << endl; #endif #ifdef DEBUG cerr << "Capsule partition at address " << py_partition << endl; #endif MutableVertexPartition* partition = decapsule_MutableVertexPartition(py_partition); #ifdef DEBUG cerr << "Using partition at address " << partition << endl; #endif if (comm >= partition->n_communities()) { PyErr_SetString(PyExc_IndexError, "Try to index beyond the number of communities."); return NULL; } double w = partition->total_weight_in_comm(comm); return PyFloat_FromDouble(w); } PyObject* _MutableVertexPartition_total_weight_from_comm(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_partition = NULL; size_t comm; static const char* kwlist[] = {"partition", "comm", NULL}; #ifdef DEBUG cerr << "Parsing arguments..." << endl; #endif if (!PyArg_ParseTupleAndKeywords(args, keywds, "On", (char**) kwlist, &py_partition, &comm)) return NULL; #ifdef DEBUG cerr << "total_weight_from_comm(" << comm << ");" << endl; #endif #ifdef DEBUG cerr << "Capsule partition at address " << py_partition << endl; #endif MutableVertexPartition* partition = decapsule_MutableVertexPartition(py_partition); if (comm >= partition->n_communities()) { PyErr_SetString(PyExc_IndexError, "Try to index beyond the number of communities."); return NULL; } #ifdef DEBUG cerr << "Using partition at address " << partition << endl; #endif double w = partition->total_weight_from_comm(comm); return PyFloat_FromDouble(w); } PyObject* _MutableVertexPartition_total_weight_to_comm(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_partition = NULL; size_t comm; static const char* kwlist[] = {"partition", "comm", NULL}; #ifdef DEBUG cerr << "Parsing arguments..." << endl; #endif if (!PyArg_ParseTupleAndKeywords(args, keywds, "On", (char**) kwlist, &py_partition, &comm)) return NULL; #ifdef DEBUG cerr << "total_weight_to_comm(" << comm << ");" << endl; #endif #ifdef DEBUG cerr << "Capsule partition at address " << py_partition << endl; #endif MutableVertexPartition* partition = decapsule_MutableVertexPartition(py_partition); if (comm >= partition->n_communities()) { PyErr_SetString(PyExc_IndexError, "Try to index beyond the number of communities."); return NULL; } #ifdef DEBUG cerr << "Using partition at address " << partition << endl; #endif double w = partition->total_weight_to_comm(comm); return PyFloat_FromDouble(w); } PyObject* _MutableVertexPartition_total_weight_in_all_comms(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_partition = NULL; static const char* kwlist[] = {"partition", NULL}; #ifdef DEBUG cerr << "Parsing arguments..." << endl; #endif if (!PyArg_ParseTupleAndKeywords(args, keywds, "O", (char**) kwlist, &py_partition)) return NULL; #ifdef DEBUG cerr << "total_weight_in_all_comms();" << endl; #endif #ifdef DEBUG cerr << "Capsule partition at address " << py_partition << endl; #endif MutableVertexPartition* partition = decapsule_MutableVertexPartition(py_partition); #ifdef DEBUG cerr << "Using partition at address " << partition << endl; #endif double w = partition->total_weight_in_all_comms(); return PyFloat_FromDouble(w); } PyObject* _MutableVertexPartition_total_possible_edges_in_all_comms(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_partition = NULL; static const char* kwlist[] = {"partition", NULL}; #ifdef DEBUG cerr << "Parsing arguments..." << endl; #endif if (!PyArg_ParseTupleAndKeywords(args, keywds, "O", (char**) kwlist, &py_partition)) return NULL; #ifdef DEBUG cerr << "total_possible_edges_in_all_comms();" << endl; #endif #ifdef DEBUG cerr << "Capsule partition at address " << py_partition << endl; #endif MutableVertexPartition* partition = decapsule_MutableVertexPartition(py_partition); #ifdef DEBUG cerr << "Using partition at address " << partition << endl; #endif size_t e = partition->total_possible_edges_in_all_comms(); return PyLong_FromSize_t(e); } PyObject* _MutableVertexPartition_weight_to_comm(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_partition = NULL; size_t v; size_t comm; static const char* kwlist[] = {"partition", "v", "comm", NULL}; #ifdef DEBUG cerr << "Parsing arguments..." << endl; #endif if (!PyArg_ParseTupleAndKeywords(args, keywds, "Onn", (char**) kwlist, &py_partition, &v, &comm)) return NULL; #ifdef DEBUG cerr << "weight_to_comm(" << v << ", " << comm << ");" << endl; #endif #ifdef DEBUG cerr << "Capsule partition at address " << py_partition << endl; #endif MutableVertexPartition* partition = decapsule_MutableVertexPartition(py_partition); if (comm >= partition->n_communities()) { PyErr_SetString(PyExc_IndexError, "Try to index beyond the number of communities."); return NULL; } if (v >= partition->get_graph()->vcount()) { PyErr_SetString(PyExc_IndexError, "Try to index beyond the number of nodes."); return NULL; } #ifdef DEBUG cerr << "Using partition at address " << partition << endl; #endif double diff = partition->weight_to_comm(v, comm); return PyFloat_FromDouble(diff); } PyObject* _MutableVertexPartition_weight_from_comm(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_partition = NULL; size_t v; size_t comm; static const char* kwlist[] = {"partition", "v", "comm", NULL}; #ifdef DEBUG cerr << "Parsing arguments..." << endl; #endif if (!PyArg_ParseTupleAndKeywords(args, keywds, "Onn", (char**) kwlist, &py_partition, &v, &comm)) return NULL; #ifdef DEBUG cerr << "weight_to_comm(" << v << ", " << comm << ");" << endl; #endif #ifdef DEBUG cerr << "Capsule partition at address " << py_partition << endl; #endif MutableVertexPartition* partition = decapsule_MutableVertexPartition(py_partition); if (comm >= partition->n_communities()) { PyErr_SetString(PyExc_IndexError, "Try to index beyond the number of communities."); return NULL; } if (v >= partition->get_graph()->vcount()) { PyErr_SetString(PyExc_IndexError, "Try to index beyond the number of nodes."); return NULL; } #ifdef DEBUG cerr << "Using partition at address " << partition << endl; #endif double diff = partition->weight_to_comm(v, comm); return PyFloat_FromDouble(diff); } PyObject* _MutableVertexPartition_get_membership(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_partition = NULL; static const char* kwlist[] = {"partition", NULL}; #ifdef DEBUG cerr << "Parsing arguments..." << endl; #endif if (!PyArg_ParseTupleAndKeywords(args, keywds, "O", (char**) kwlist, &py_partition)) return NULL; #ifdef DEBUG cerr << "get_membership();" << endl; #endif #ifdef DEBUG cerr << "Capsule partition at address " << py_partition << endl; #endif MutableVertexPartition* partition = decapsule_MutableVertexPartition(py_partition); #ifdef DEBUG cerr << "Using partition at address " << partition << endl; #endif size_t n = partition->get_graph()->vcount(); PyObject* py_membership = PyList_New(n); for (size_t v = 0; v < n; v++) { PyObject* item = PyLong_FromSize_t(partition->membership(v)); PyList_SetItem(py_membership, v, item); } return py_membership; } PyObject* _MutableVertexPartition_set_membership(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_partition = NULL; PyObject* py_membership = NULL; static const char* kwlist[] = {"partition", "membership", NULL}; #ifdef DEBUG cerr << "Parsing arguments..." << endl; #endif if (!PyArg_ParseTupleAndKeywords(args, keywds, "OO", (char**) kwlist, &py_partition, &py_membership)) return NULL; #ifdef DEBUG cerr << "set_membership();" << endl; #endif #ifdef DEBUG cerr << "Capsule partition at address " << py_partition << endl; #endif MutableVertexPartition* partition = decapsule_MutableVertexPartition(py_partition); #ifdef DEBUG cerr << "Using partition at address " << partition << endl; #endif try { partition->set_membership(create_size_t_vector(py_membership)); } catch (std::exception& e ) { string s = "Could not set membership: " + string(e.what()); PyErr_SetString(PyExc_BaseException, s.c_str()); return NULL; } #ifdef DEBUG cerr << "Exiting set_membership();" << endl; #endif Py_INCREF(Py_None); return Py_None; } PyObject* _ResolutionParameterVertexPartition_get_resolution(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_partition = NULL; static const char* kwlist[] = {"partition", NULL}; #ifdef DEBUG cerr << "Parsing arguments..." << endl; #endif if (!PyArg_ParseTupleAndKeywords(args, keywds, "O", (char**) kwlist, &py_partition)) return NULL; #ifdef DEBUG cerr << "get_resolution();" << endl; #endif #ifdef DEBUG cerr << "Capsule ResolutionParameterVertexPartition at address " << py_partition << endl; #endif ResolutionParameterVertexPartition* partition = (ResolutionParameterVertexPartition*)decapsule_MutableVertexPartition(py_partition); #ifdef DEBUG cerr << "Using ResolutionParameterVertexPartition at address " << partition << endl; #endif return PyFloat_FromDouble(partition->resolution_parameter); } PyObject* _ResolutionParameterVertexPartition_set_resolution(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_partition = NULL; double resolution_parameter = 1.0; static const char* kwlist[] = {"partition", "resolution_parameter", NULL}; #ifdef DEBUG cerr << "Parsing arguments..." << endl; #endif if (!PyArg_ParseTupleAndKeywords(args, keywds, "Od", (char**) kwlist, &py_partition, &resolution_parameter)) return NULL; #ifdef DEBUG cerr << "set_resolution(" << resolution_parameter << ");" << endl; #endif #ifdef DEBUG cerr << "Capsule ResolutionParameterVertexPartition at address " << py_partition << endl; #endif ResolutionParameterVertexPartition* partition = (ResolutionParameterVertexPartition*)decapsule_MutableVertexPartition(py_partition); #ifdef DEBUG cerr << "Using ResolutionParameterVertexPartition at address " << partition << endl; #endif partition->resolution_parameter = resolution_parameter; Py_INCREF(Py_None); return Py_None; } PyObject* _ResolutionParameterVertexPartition_quality(PyObject *self, PyObject *args, PyObject *keywds) { PyObject* py_partition = NULL; PyObject* py_res = NULL; double resolution_parameter = 0.0; static const char* kwlist[] = {"partition", "resolution_parameter", NULL}; #ifdef DEBUG cerr << "Parsing arguments..." << endl; #endif if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|O", (char**) kwlist, &py_partition, &py_res)) return NULL; #ifdef DEBUG cerr << "quality();" << endl; #endif #ifdef DEBUG cerr << "Capsule partition at address " << py_partition << endl; #endif ResolutionParameterVertexPartition* partition = (ResolutionParameterVertexPartition*)decapsule_MutableVertexPartition(py_partition); if (py_res != NULL && py_res != Py_None) { if (PyNumber_Check(py_res)) { resolution_parameter = PyFloat_AsDouble(py_res); } else { PyErr_SetString(PyExc_TypeError, "Expected floating point value for resolution parameter."); return NULL; } if (isnan(resolution_parameter)) { PyErr_SetString(PyExc_TypeError, "Cannot accept NaN resolution parameter."); return NULL; } } else resolution_parameter = partition->resolution_parameter; #ifdef DEBUG cerr << "Using partition at address " << partition << endl; #endif double q = partition->quality(resolution_parameter); return PyFloat_FromDouble(q); } #ifdef __cplusplus } #endif leidenalg-0.8.9/tests/000077500000000000000000000000001420514302700146145ustar00rootroot00000000000000leidenalg-0.8.9/tests/__init__.py000066400000000000000000000000001420514302700167130ustar00rootroot00000000000000leidenalg-0.8.9/tests/test_Optimiser.py000066400000000000000000000200161420514302700201770ustar00rootroot00000000000000import unittest import igraph as ig import leidenalg from functools import reduce class OptimiserTest(unittest.TestCase): def setUp(self): self.optimiser = leidenalg.Optimiser() def test_move_nodes(self): G = ig.Graph.Full(100) partition = leidenalg.CPMVertexPartition(G, resolution_parameter=0.5) self.optimiser.move_nodes(partition, consider_comms=leidenalg.ALL_NEIGH_COMMS) self.assertListEqual( partition.sizes(), [100], msg="CPMVertexPartition(resolution_parameter=0.5) of complete graph after move nodes incorrect.") def test_move_nodes_with_max_comm_size(self): G = ig.Graph.Full(100) partition = leidenalg.CPMVertexPartition(G, resolution_parameter=0.5) self.optimiser.max_comm_size = 17 self.optimiser.move_nodes(partition, consider_comms=leidenalg.ALL_NEIGH_COMMS) self.assertListEqual( partition.sizes(), [17, 17, 17, 17, 17, 15], msg="CPMVertexPartition(resolution_parameter=0.5) of complete graph after move nodes (max_comm_size=17) incorrect.") def test_move_nodes_with_fixed(self): # One edge plus singleton, but the two connected nodes are fixed G = ig.Graph([(0, 2)]) is_membership_fixed = [True, False, True] partition = leidenalg.CPMVertexPartition( G, resolution_parameter=0.1) self.optimiser.move_nodes(partition, is_membership_fixed=is_membership_fixed, consider_comms=leidenalg.ALL_NEIGH_COMMS) self.assertListEqual( partition.sizes(), [1, 1, 1], msg="CPMVertexPartition(resolution_parameter=0.1) of one edge plus singleton after move nodes with fixed nodes is incorrect.") def test_merge_nodes(self): G = ig.Graph.Full(100) partition = leidenalg.CPMVertexPartition(G, resolution_parameter=0.5) self.optimiser.merge_nodes(partition, consider_comms=leidenalg.ALL_NEIGH_COMMS) self.assertListEqual( partition.sizes(), [100], msg="CPMVertexPartition(resolution_parameter=0.5) of complete graph after merge nodes incorrect.") self.assertEqual( partition.total_weight_in_all_comms(), G.ecount(), msg="total_weight_in_all_comms not equal to ecount of graph.") def test_merge_nodes_with_max_comm_size(self): G = ig.Graph.Full(100) partition = leidenalg.CPMVertexPartition(G, resolution_parameter=0.5) self.optimiser.max_comm_size = 17 self.optimiser.merge_nodes(partition, consider_comms=leidenalg.ALL_NEIGH_COMMS) self.assertListEqual( partition.sizes(), [17, 17, 17, 17, 17, 15], msg="CPMVertexPartition(resolution_parameter=0.5) of complete graph after merge nodes (max_comm_size=17) incorrect.") def test_diff_move_node_optimality(self): G = ig.Graph.Erdos_Renyi(100, p=5./100, directed=False, loops=False) partition = leidenalg.CPMVertexPartition(G, resolution_parameter=0.1) while 0 < self.optimiser.move_nodes(partition, consider_comms=leidenalg.ALL_NEIGH_COMMS): pass for v in G.vs: neigh_comms = set(partition.membership[u.index] for u in v.neighbors()) for c in neigh_comms: self.assertLessEqual( partition.diff_move(v.index, c), 1e-10, # Allow for a small difference up to rounding error. msg="Was able to move a node to a better community, violating node optimality.") def test_optimiser(self): G = reduce(ig.Graph.disjoint_union, (ig.Graph.Tree(10, 3, mode=ig.TREE_UNDIRECTED) for i in range(10))) partition = leidenalg.CPMVertexPartition(G, resolution_parameter=0) self.optimiser.consider_comms=leidenalg.ALL_NEIGH_COMMS self.optimiser.optimise_partition(partition) self.assertListEqual( partition.sizes(), 10*[10], msg="After optimising partition failed to find different components with CPMVertexPartition(resolution_parameter=0)") def test_optimiser_with_max_comm_size(self): G = ig.Graph.Full(100) partition = leidenalg.CPMVertexPartition(G, resolution_parameter=0) self.optimiser.consider_comms=leidenalg.ALL_NEIGH_COMMS self.optimiser.max_comm_size = 10 self.optimiser.optimise_partition(partition) self.assertListEqual( partition.sizes(), 10*[10], msg="After optimising partition (max_comm_size=10) failed to find different components with CPMVertexPartition(resolution_parameter=0)") def test_optimiser_split_with_max_comm_size(self): G = ig.Graph.Full(100) partition = leidenalg.CPMVertexPartition(G, resolution_parameter=0.5) self.optimiser.merge_nodes(partition, consider_comms=leidenalg.ALL_NEIGH_COMMS) self.assertListEqual( partition.sizes(), [100], msg="CPMVertexPartition(resolution_parameter=0.5) of complete graph after merge nodes incorrect.") self.optimiser.max_comm_size = 10 self.optimiser.optimise_partition(partition) self.assertListEqual( partition.sizes(), 10*[10], msg="After optimising partition (max_comm_size=10) failed to find different components with CPMVertexPartition(resolution_parameter=0.5)") def test_optimiser_with_is_membership_fixed(self): G = ig.Graph.Full(3) partition = leidenalg.CPMVertexPartition( G, resolution_parameter=0.01, initial_membership=[2, 1, 0]) # Equivalent to setting initial membership #partition.set_membership([2, 1, 2]) is_membership_fixed = [True, False, False] original_quality = partition.quality() diff = self.optimiser.optimise_partition(partition, is_membership_fixed=is_membership_fixed) self.assertAlmostEqual(partition.quality() - original_quality, diff, places=10, msg="Optimisation with fixed nodes returns inconsistent quality") self.assertListEqual( partition.membership, [2, 2, 2], msg="After optimising partition with fixed nodes failed to recover initial fixed memberships" ) def test_optimiser_is_membership_fixed_large_labels(self): G = ig.Graph.Erdos_Renyi(n=100, p=5./100, directed=True, loops=True) membership = list(range(G.vcount())) partition = leidenalg.RBConfigurationVertexPartition(G, initial_membership=membership) # large enough to force nonconsecutive labels in the final partition fixed_node_idx = 90 is_membership_fixed = [False] * G.vcount() is_membership_fixed[fixed_node_idx] = True original_quality = partition.quality() diff = self.optimiser.optimise_partition(partition, is_membership_fixed=is_membership_fixed) self.assertLess(len(set(partition.membership)), len(partition), msg="Optimisation with fixed nodes yielded too many communities") self.assertAlmostEqual(partition.quality() - original_quality, diff, places=10, msg="Optimisation with fixed nodes returned inconsistent quality") self.assertEqual(partition.membership[fixed_node_idx], fixed_node_idx, msg="Optimisation with fixed nodes failed to keep the associated community labels fixed") def test_neg_weight_bipartite(self): G = ig.Graph.Full_Bipartite(50, 50) G.es['weight'] = -0.1 partition = leidenalg.CPMVertexPartition(G, resolution_parameter=-0.1, weights='weight') self.optimiser.consider_comms=leidenalg.ALL_COMMS self.optimiser.optimise_partition(partition) self.assertListEqual( partition.sizes(), 2*[50], msg="After optimising partition failed to find bipartite structure with CPMVertexPartition(resolution_parameter=-0.1)") def test_resolution_profile(self): G = ig.Graph.Famous('Zachary') profile = self.optimiser.resolution_profile(G, leidenalg.CPMVertexPartition, resolution_range=(0,1)) self.assertListEqual( profile[0].sizes(), [G.vcount()], msg="Resolution profile incorrect: at resolution 0, not equal to a single community for CPM.") self.assertListEqual( profile[-1].sizes(), [1]*G.vcount(), msg="Resolution profile incorrect: at resolution 1, not equal to a singleton partition for CPM.") #%% if __name__ == '__main__': #%% unittest.main(verbosity=3) suite = unittest.TestLoader().discover('.') unittest.TextTestRunner(verbosity=1).run(suite) leidenalg-0.8.9/tests/test_VertexPartition.py000066400000000000000000000204531420514302700214000ustar00rootroot00000000000000import unittest import igraph as ig import leidenalg import random from copy import deepcopy from ddt import ddt, data, unpack #%% def name_object(obj, name): obj.__name__ = name return obj graphs = [ ########################################################################### # Zachary karate network name_object(ig.Graph.Famous('Zachary'), 'Zachary'), ########################################################################### # ER Networks # Undirected no loop name_object(ig.Graph.Erdos_Renyi(100, p=1./100, directed=False, loops=False), 'ER_k1_undirected_no_loops'), name_object(ig.Graph.Erdos_Renyi(100, p=5./100, directed=False, loops=False), 'ER_k5_undirected_no_loops'), # Directed no loop name_object(ig.Graph.Erdos_Renyi(100, p=1./100, directed=True, loops=False), 'ER_k1_directed_no_loops'), name_object(ig.Graph.Erdos_Renyi(100, p=5./100, directed=True, loops=False), 'ER_k5_directed_no_loops'), # Undirected loops name_object(ig.Graph.Erdos_Renyi(100, p=1./100, directed=False, loops=True), 'ER_k1_undirected_loops'), name_object(ig.Graph.Erdos_Renyi(100, p=5./100, directed=False, loops=True), 'ER_k5_undirected_loops'), # Directed loops name_object(ig.Graph.Erdos_Renyi(100, p=1./100, directed=True, loops=True), 'ER_k1_directed_loops'), name_object(ig.Graph.Erdos_Renyi(100, p=5./100, directed=True, loops=True), 'ER_k5_directed_loops'), ########################################################################### # Tree name_object(ig.Graph.Tree(100, 3, type=ig.TREE_UNDIRECTED), 'Tree_undirected'), name_object(ig.Graph.Tree(100, 3, type=ig.TREE_OUT), 'Tree_directed_out'), name_object(ig.Graph.Tree(100, 3, type=ig.TREE_IN), 'Tree_directed_in'), ########################################################################### # Lattice name_object(ig.Graph.Lattice([100], nei=3, directed=False, mutual=True, circular=True), 'Lattice_undirected'), name_object(ig.Graph.Lattice([100], nei=3, directed=True, mutual=False, circular=True), 'Lattice_directed') ] bipartite_graph = name_object( ig.Graph.Bipartite([0, 0, 0, 0, 1, 1, 1, 1], [[0, 4], [0, 5], [0, 6], [1, 4], [1, 5], [2, 6], [2, 7], [3, 6], [3, 7], [3, 5]]), 'bipartite_example') def make_weighted(G): m = G.ecount() G.es['weight'] = [random.random() for i in range(G.ecount())] G.__name__ += '_weighted' return G graphs += [make_weighted(H) for H in graphs] class BaseTest: @ddt class MutableVertexPartitionTest(unittest.TestCase): def setUp(self): self.optimiser = leidenalg.Optimiser() @data(*graphs) def test_move_nodes(self, graph): if 'weight' in graph.es.attributes() and self.partition_type == leidenalg.SignificanceVertexPartition: raise unittest.SkipTest('Significance doesn\'t handle weighted graphs') if 'weight' in graph.es.attributes(): partition = self.partition_type(graph, weights='weight') else: partition = self.partition_type(graph) for v in range(graph.vcount()): if graph.degree(v) >= 1: u = graph.neighbors(v)[0] diff = partition.diff_move(v, partition.membership[u]) q1 = partition.quality() partition.move_node(v, partition.membership[u]) q2 = partition.quality() self.assertAlmostEqual( q2 - q1, diff, places=5, msg="Difference in quality ({0}) not equal to calculated difference ({1})".format( q2 - q1, diff)) @data(*graphs) def test_aggregate_partition(self, graph): if 'weight' in graph.es.attributes() and self.partition_type != leidenalg.SignificanceVertexPartition: partition = self.partition_type(graph, weights='weight') else: partition = self.partition_type(graph) self.optimiser.move_nodes(partition) aggregate_partition = partition.aggregate_partition() self.assertAlmostEqual( partition.quality(), aggregate_partition.quality(), places=5, msg='Quality not equal for aggregate partition.') self.optimiser.move_nodes(aggregate_partition) partition.from_coarse_partition(aggregate_partition) self.assertAlmostEqual( partition.quality(), aggregate_partition.quality(), places=5, msg='Quality not equal from coarser partition.') @data(*graphs) def test_total_weight_in_all_comms(self, graph): if 'weight' in graph.es.attributes() and self.partition_type != leidenalg.SignificanceVertexPartition: partition = self.partition_type(graph, weights='weight') else: partition = self.partition_type(graph) self.optimiser.optimise_partition(partition) s = sum([partition.total_weight_in_comm(c) for c,_ in enumerate(partition)]) self.assertAlmostEqual( s, partition.total_weight_in_all_comms(), places=5, msg='Total weight in all communities ({0}) not equal to the sum of the weight in all communities ({1}).'.format( s, partition.total_weight_in_all_comms()) ) @data(*graphs) def test_copy(self, graph): if 'weight' in graph.es.attributes() and self.partition_type != leidenalg.SignificanceVertexPartition: partition = self.partition_type(graph, weights='weight') else: partition = self.partition_type(graph) self.optimiser.optimise_partition(partition) partition2 = deepcopy(partition) self.assertAlmostEqual( partition.quality(), partition2.quality(), places=5, msg='Quality of deepcopy ({0}) not equal to quality of original partition ({1}).'.format( partition.quality(), partition2.quality()) ) if (partition2.membership[0] == 0): partition2.move_node(0, 1) else: partition2.move_node(0, 0) self.assertNotEqual( partition.membership[0], partition2.membership[0], msg='Moving node 0 in the deepcopy to community {0} results in community membership {1} for node 0 also in original partition.'.format( partition.membership[0], partition2.membership[0]) ) class ModularityVertexPartitionTest(BaseTest.MutableVertexPartitionTest): def setUp(self): super(ModularityVertexPartitionTest, self).setUp() self.partition_type = leidenalg.ModularityVertexPartition class RBERVertexPartitionTest(BaseTest.MutableVertexPartitionTest): def setUp(self): super(RBERVertexPartitionTest, self).setUp() self.partition_type = leidenalg.RBERVertexPartition class RBConfigurationVertexPartitionTest(BaseTest.MutableVertexPartitionTest): def setUp(self): super(RBConfigurationVertexPartitionTest, self).setUp() self.partition_type = leidenalg.RBConfigurationVertexPartition class CPMVertexPartitionTest(BaseTest.MutableVertexPartitionTest): def setUp(self): super(CPMVertexPartitionTest, self).setUp() self.partition_type = leidenalg.CPMVertexPartition def test_Bipartite(self): graph = bipartite_graph partition, partition_0, partition_1 = \ leidenalg.CPMVertexPartition.Bipartite(graph, resolution_parameter_01=0.2) self.optimiser.optimise_partition_multiplex( [partition, partition_0, partition_1], layer_weights=[1, -1, -1]) self.assertEqual(len(partition), 1) class SurpriseVertexPartitionTest(BaseTest.MutableVertexPartitionTest): def setUp(self): super(SurpriseVertexPartitionTest, self).setUp() self.partition_type = leidenalg.SurpriseVertexPartition class SignificanceVertexPartitionTest(BaseTest.MutableVertexPartitionTest): def setUp(self): super(SignificanceVertexPartitionTest, self).setUp() self.partition_type = leidenalg.SignificanceVertexPartition #%% if __name__ == '__main__': #%% unittest.main(verbosity=3) suite = unittest.TestLoader().discover('.') unittest.TextTestRunner(verbosity=1).run(suite) leidenalg-0.8.9/vendor/000077500000000000000000000000001420514302700147475ustar00rootroot00000000000000leidenalg-0.8.9/vendor/source/000077500000000000000000000000001420514302700162475ustar00rootroot00000000000000leidenalg-0.8.9/vendor/source/igraph/000077500000000000000000000000001420514302700175215ustar00rootroot00000000000000